From 3196b7c4ca935df3313ce86ce19110be3573861b Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Fri, 29 Nov 2019 15:17:13 -0500 Subject: [PATCH 001/529] Merge PR #5294: Upgrade Module Spec --- x/upgrade/abci.go | 5 +- x/upgrade/handler.go | 1 + x/upgrade/internal/keeper/keeper.go | 8 ++- x/upgrade/spec/01_concepts.md | 84 +++++++++++++++++++++++++++++ x/upgrade/spec/02_state.md | 7 +++ x/upgrade/spec/03_events.md | 4 ++ x/upgrade/spec/README.md | 20 +++++++ 7 files changed, 126 insertions(+), 3 deletions(-) create mode 100644 x/upgrade/spec/01_concepts.md create mode 100644 x/upgrade/spec/02_state.md create mode 100644 x/upgrade/spec/03_events.md create mode 100644 x/upgrade/spec/README.md diff --git a/x/upgrade/abci.go b/x/upgrade/abci.go index c0c7a8ae10fd..01b0aae6a003 100644 --- a/x/upgrade/abci.go +++ b/x/upgrade/abci.go @@ -12,13 +12,14 @@ import ( // If it is ready, it will execute it if the handler is installed, and panic/abort otherwise. // If the plan is not ready, it will ensure the handler is not registered too early (and abort otherwise). // -// The prupose is to ensure the binary is switch EXACTLY at the desired block, and to allow +// The purpose is to ensure the binary is switch EXACTLY at the desired block, and to allow // a migration to be executed if needed upon this switch (migration defined in the new binary) func BeginBlocker(k Keeper, ctx sdk.Context, _ abci.RequestBeginBlock) { plan, found := k.GetUpgradePlan(ctx) if !found { return } + if plan.ShouldExecute(ctx) { if !k.HasHandler(plan.Name) { upgradeMsg := fmt.Sprintf("UPGRADE \"%s\" NEEDED at %s: %s", plan.Name, plan.DueAt(), plan.Info) @@ -26,10 +27,12 @@ func BeginBlocker(k Keeper, ctx sdk.Context, _ abci.RequestBeginBlock) { ctx.Logger().Error(upgradeMsg) panic(upgradeMsg) } + // We have an upgrade handler for this upgrade name, so apply the upgrade ctx.Logger().Info(fmt.Sprintf("applying upgrade \"%s\" at %s", plan.Name, plan.DueAt())) ctx = ctx.WithBlockGasMeter(sdk.NewInfiniteGasMeter()) k.ApplyUpgrade(ctx, plan) + return } diff --git a/x/upgrade/handler.go b/x/upgrade/handler.go index 2ae2cb09976a..925d4e875c9d 100644 --- a/x/upgrade/handler.go +++ b/x/upgrade/handler.go @@ -15,6 +15,7 @@ func NewSoftwareUpgradeProposalHandler(k Keeper) govtypes.Handler { switch c := content.(type) { case SoftwareUpgradeProposal: return handleSoftwareUpgradeProposal(ctx, k, c) + case CancelSoftwareUpgradeProposal: return handleCancelSoftwareUpgradeProposal(ctx, k, c) diff --git a/x/upgrade/internal/keeper/keeper.go b/x/upgrade/internal/keeper/keeper.go index 11c50a0e5abd..bb95ec6eafdb 100644 --- a/x/upgrade/internal/keeper/keeper.go +++ b/x/upgrade/internal/keeper/keeper.go @@ -37,10 +37,10 @@ func (k Keeper) SetUpgradeHandler(name string, upgradeHandler types.UpgradeHandl // If there is another Plan already scheduled, it will overwrite it // (implicitly cancelling the current plan) func (k Keeper) ScheduleUpgrade(ctx sdk.Context, plan types.Plan) sdk.Error { - err := plan.ValidateBasic() - if err != nil { + if err := plan.ValidateBasic(); err != nil { return err } + if !plan.Time.IsZero() { if !plan.Time.After(ctx.BlockHeader().Time) { return sdk.ErrUnknownRequest("upgrade cannot be scheduled in the past") @@ -65,6 +65,7 @@ func (k Keeper) getDoneHeight(ctx sdk.Context, name string) int64 { if len(bz) == 0 { return 0 } + return int64(binary.BigEndian.Uint64(bz)) } @@ -87,6 +88,7 @@ func (k Keeper) GetUpgradePlan(ctx sdk.Context) (plan types.Plan, havePlan bool) if bz == nil { return plan, false } + k.cdc.MustUnmarshalBinaryBare(bz, &plan) return plan, true } @@ -111,7 +113,9 @@ func (k Keeper) ApplyUpgrade(ctx sdk.Context, plan types.Plan) { if handler == nil { panic("ApplyUpgrade should never be called without first checking HasHandler") } + handler(ctx, plan) + k.ClearUpgradePlan(ctx) k.setDone(ctx, plan.Name) } diff --git a/x/upgrade/spec/01_concepts.md b/x/upgrade/spec/01_concepts.md new file mode 100644 index 000000000000..2b93738f65af --- /dev/null +++ b/x/upgrade/spec/01_concepts.md @@ -0,0 +1,84 @@ +# Concepts + +## Plan + +The `x/upgrade` module defines a `Plan` type in which a live upgrade is scheduled +to occur. A `Plan` can be scheduled at a specific block height or time, but not both. +A `Plan` is created once a (frozen) release candidate along with an appropriate upgrade +`Handler` (see below) is agreed upon, where the `Name` of a `Plan` corresponds to a +specific `Handler`. Typically, a `Plan` is created through a governance proposal +process, where if voted upon and passed, will be scheduled. The `Info` of a `Plan` +may contain various metadata about the upgrade, typically application specific +upgrade info to be included on-chain such as a git commit that validators could +automatically upgrade to. + +### Sidecar Process + +If an operator running the application binary also runs a sidecar process to assist +in the automatic download and upgrade of a binary, the `Info` allows this process to +be seamless. Namely, the `x/upgrade` module fulfills the +[cosmosd Upgradeable Binary Specification](https://github.com/regen-network/cosmosd#upgradeable-binary-specification) +specification and `cosmosd` can optionally be used to fully automate the upgrade +process for node operators. By populating the `Info` field with the necessary information, +binaries can automatically be downloaded. See [here](https://github.com/regen-network/cosmosd#auto-download) +for more info. + +```go +type Plan struct { + Name string + Time Time + Height int64 + Info string +} +``` + +## Handler + +The `x/upgrade` module facilitates upgrading from major version X to major version Y. To +accomplish this, node operators must first upgrade their current binary to a new +binary that has a corresponding `Handler` for the new version Y. It is assumed that +this version has fully been tested and approved by the community at large. This +`Handler` defines what state migrations need to occur before the new binary Y +can successfully run the chain. Naturally, this `Handler` is application specific +and not defined on a per-module basis. Registering a `Handler` is done via +`Keeper#SetUpgradeHandler` in the application. + +```go +type UpgradeHandler func(Context, Plan) +``` + +During each `EndBlock` execution, the `x/upgrade` module checks if there exists a +`Plan` that should execute (is scheduled at that time or height). If so, the corresponding +`Handler` is executed. If the `Plan` is expected to execute but no `Handler` is registered +or if the binary was upgraded too early, the node will gracefully panic and exit. + +## Proposal + +Typically, a `Plan` is proposed and submitted through governance via a `SoftwareUpgradeProposal`. +This proposal prescribes to the standard governance process. If the proposal passes, +the `Plan`, which targets a specific `Handler`, is persisted and scheduled. The +upgrade can be delayed or hastened by updating the `Plan.Time` in a new proposal. + +```go +type SoftwareUpgradeProposal struct { + Title string + Description string + Plan Plan +} +``` + +### Cancelling Upgrade Proposals + +Upgrade proposals can be cancelled. There exists a `CancelSoftwareUpgrade` proposal +type, which can be voted on and passed and will remove the scheduled upgrade `Plan`. +Of course this requires that the upgrade was known to be a bad idea well before the +upgrade itself, to allow time for a vote. + +If such a possibility is desired, the upgrade height is to be +`2 * (VotingPeriod + DepositPeriod) + (SafetyDelta)` from the beginning of the +upgrade proposal. The `SafetyDelta` is the time available from the success of an +upgrade proposal and the realization it was a bad idea (due to external social consensus). + +A `CancelSoftwareUpgrade` proposal can also be made while the original +`SoftwareUpgradeProposal` is still being voted upon, as long as the `VotingPeriod` +ends after the `SoftwareUpgradeProposal`. diff --git a/x/upgrade/spec/02_state.md b/x/upgrade/spec/02_state.md new file mode 100644 index 000000000000..ad2650053854 --- /dev/null +++ b/x/upgrade/spec/02_state.md @@ -0,0 +1,7 @@ +# State + +The internal state of the `x/upgrade` module is relatively minimal and simple. The +state only contains the currently active upgrade `Plan` (if one exists) by key +`0x0` and if a `Plan` is marked as "done" by key `0x1`. + +The `x/upgrade` module contains no genesis state. diff --git a/x/upgrade/spec/03_events.md b/x/upgrade/spec/03_events.md new file mode 100644 index 000000000000..bbfcdddfa69e --- /dev/null +++ b/x/upgrade/spec/03_events.md @@ -0,0 +1,4 @@ +# Events + +The `x/upgrade` does not emit any events by itself. Any and all proposal related +events are emitted through the `x/gov` module. diff --git a/x/upgrade/spec/README.md b/x/upgrade/spec/README.md new file mode 100644 index 000000000000..cbe7b5a3bc35 --- /dev/null +++ b/x/upgrade/spec/README.md @@ -0,0 +1,20 @@ +# Upgrade Module Specification + +## Abstract + +`x/upgrade` is an implementation of a Cosmos SDK module that facilitates smoothly +upgrading a live Cosmos chain to a new (breaking) software version. It accomplishes this by +providing a `BeginBlocker` hook that prevents the blockchain state machine from +proceeding once a pre-defined upgrade block time or height has been reached. + +The module does not prescribe anything regarding how governance decides to do an +upgrade, but just the mechanism for coordinating the upgrade safely. Without software +support for upgrades, upgrading a live chain is risky because all of the validators +need to pause their state machines at exactly the same point in the process. If +this is not done correctly, there can be state inconsistencies which are hard to +recover from. + + +1. **[Concepts](01_concepts.md)** +2. **[State](02_state.md)** +3. **[Events](03_events.md)** From b9cb3e105dbafa92806a873b5327ab5970da3ffd Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Sat, 30 Nov 2019 14:32:08 +0000 Subject: [PATCH 002/529] Merge PR #5345: Add dev docs for COSMOS_SDK_TEST_KEYRING --- client/keys/utils.go | 4 +++- crypto/keys/keyring.go | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/client/keys/utils.go b/client/keys/utils.go index 95beb8ffe09f..2b2ca06f0e5b 100644 --- a/client/keys/utils.go +++ b/client/keys/utils.go @@ -46,7 +46,9 @@ func NewKeyringFromHomeFlag(input io.Reader) (keys.Keybase, error) { return NewKeyringFromDir(viper.GetString(flags.FlagHome), input) } -// NewKeyBaseFromDir initializes a keybase at a particular dir. +// NewKeyBaseFromDir initializes a keyring at a particular dir. +// If the COSMOS_SDK_TEST_KEYRING environment variable is set and not empty it will +// return an on-disk, password-less keyring that could be used for testing purposes. func NewKeyringFromDir(rootDir string, input io.Reader) (keys.Keybase, error) { if os.Getenv("COSMOS_SDK_TEST_KEYRING") != "" { return keys.NewTestKeyring(sdk.GetConfig().GetKeyringServiceName(), rootDir) diff --git a/crypto/keys/keyring.go b/crypto/keys/keyring.go index d2673a68b3f9..839e15912f2e 100644 --- a/crypto/keys/keyring.go +++ b/crypto/keys/keyring.go @@ -47,8 +47,8 @@ func NewKeyring(name string, dir string, userInput io.Reader) (Keybase, error) { return newKeyringKeybase(db), nil } -// NewTestKeyring creates a new instance of a keyring for -// testing purposes that does not prompt users for password. +// NewTestKeyring creates a new instance of an on-disk keyring for +// testing purposes that does not prompt users for password. func NewTestKeyring(name string, dir string) (Keybase, error) { db, err := keyring.Open(lkbToKeyringConfig(name, dir, nil, true)) if err != nil { From 82a5238a465378b6698ac9e634c48d3baf1479f9 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Sun, 1 Dec 2019 10:06:34 -0500 Subject: [PATCH 003/529] Merge PR #5348: Fix Ignored Error During Tx Generate Only Mode --- CHANGELOG.md | 1 + x/auth/client/utils/tx.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cc3a700d4213..cd0ee7cee95a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -185,6 +185,7 @@ to detail this new feature and how state transitions occur. ### Bug Fixes +* (client) [\#5303](https://github.com/cosmos/cosmos-sdk/issues/5303) Fix ignored error in tx generate only mode. * (iavl) [\#5276](https://github.com/cosmos/cosmos-sdk/issues/5276) Fix potential race condition in `iavlIterator#Close`. * (cli) [\#4763](https://github.com/cosmos/cosmos-sdk/issues/4763) Fix flag `--min-self-delegation` for staking `EditValidator` * (keys) Fix ledger custom coin type support bug diff --git a/x/auth/client/utils/tx.go b/x/auth/client/utils/tx.go index 4837639e45fe..265d9031bc43 100644 --- a/x/auth/client/utils/tx.go +++ b/x/auth/client/utils/tx.go @@ -331,7 +331,7 @@ func buildUnsignedStdTxOffline(txBldr authtypes.TxBuilder, cliCtx context.CLICon stdSignMsg, err := txBldr.BuildSignMsg(msgs) if err != nil { - return stdTx, nil + return stdTx, err } return authtypes.NewStdTx(stdSignMsg.Msgs, stdSignMsg.Fee, nil, stdSignMsg.Memo), nil From 5be87e40cef3f58419d76b236c246d3e4032a7a3 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sun, 1 Dec 2019 18:14:44 -0500 Subject: [PATCH 004/529] Bump github.com/tendermint/tendermint from 0.32.7 to 0.32.8 (#5330) * Bump github.com/tendermint/tendermint from 0.32.7 to 0.32.8 Bumps [github.com/tendermint/tendermint](https://github.com/tendermint/tendermint) from 0.32.7 to 0.32.8. - [Release notes](https://github.com/tendermint/tendermint/releases) - [Changelog](https://github.com/tendermint/tendermint/blob/master/CHANGELOG.md) - [Commits](https://github.com/tendermint/tendermint/compare/v0.32.7...v0.32.8) Signed-off-by: dependabot-preview[bot] * Update go.{mod,sum} --- go.mod | 3 +-- go.sum | 29 +++++++++++++++++++---------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index 6017aa69779d..dc54f5cf4423 100644 --- a/go.mod +++ b/go.mod @@ -21,12 +21,11 @@ require ( github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.5.0 github.com/stretchr/testify v1.4.0 - github.com/stumble/gorocksdb v0.0.3 // indirect github.com/tendermint/btcd v0.1.1 github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 github.com/tendermint/go-amino v0.15.1 github.com/tendermint/iavl v0.12.4 - github.com/tendermint/tendermint v0.32.7 + github.com/tendermint/tendermint v0.32.8 github.com/tendermint/tm-db v0.2.0 gopkg.in/yaml.v2 v2.2.7 ) diff --git a/go.sum b/go.sum index 27d7a591d642..7b6a998a73be 100644 --- a/go.sum +++ b/go.sum @@ -29,6 +29,7 @@ github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVa github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= @@ -54,6 +55,8 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dvsekhvalnov/jose2go v0.0.0-20180829124132-7f401d37b68a h1:mq+R6XEM6lJX5VlLyZIrUSP8tSuJp82xTK89hvBwJbU= github.com/dvsekhvalnov/jose2go v0.0.0-20180829124132-7f401d37b68a/go.mod h1:7BvyPhdbLxMXIYTFPLsyJRFMsKmOZnQmzh6Gb+uquuM= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/etcd-io/bbolt v1.3.2/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= github.com/etcd-io/bbolt v1.3.3 h1:gSJmxrs37LgTqR/oyJBWok6k6SvXEUerFTbltIhXkBM= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= @@ -84,8 +87,6 @@ github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+ github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/gogo/protobuf v1.3.0 h1:G8O7TerXerS4F6sx9OV7/nRfJdnXgHZu/S/7F2SN+UE= -github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= @@ -180,6 +181,8 @@ github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDf github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20181020173914-7e9e6cabbd39/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.0 h1:7etb9YClo3a6HjLzfl6rIQaU+FDfi0VSX39io3aQ+DM= @@ -220,8 +223,6 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/spf13/viper v1.0.0/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= github.com/spf13/viper v1.3.2 h1:VUFqw5KcqRf7i70GOzW7N+Q7+gxVBkSSqiXB12+JQ4M= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU= -github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.5.0 h1:GpsTwfsQ27oS/Aha/6d1oD7tpKIqWnOA6tgOX9HHkt4= github.com/spf13/viper v1.5.0/go.mod h1:AkYRkVJF8TkSG/xet6PzXX+l39KhhXa2pdqVSxnTcn4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -248,8 +249,8 @@ github.com/tendermint/go-amino v0.15.1/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoM github.com/tendermint/iavl v0.12.4 h1:hd1woxUGISKkfUWBA4mmmTwOua6PQZTJM/F0FDrmMV8= github.com/tendermint/iavl v0.12.4/go.mod h1:8LHakzt8/0G3/I8FUU0ReNx98S/EP6eyPJkAUvEXT/o= github.com/tendermint/tendermint v0.32.1/go.mod h1:jmPDAKuNkev9793/ivn/fTBnfpA9mGBww8MPRNPNxnU= -github.com/tendermint/tendermint v0.32.7 h1:Szu5Fm1L3pvn3t4uQxPAcP+7ndZEQKgLie/yokM56rU= -github.com/tendermint/tendermint v0.32.7/go.mod h1:D2+A3pNjY+Po72X0mTfaXorFhiVI8dh/Zg640FGyGtE= +github.com/tendermint/tendermint v0.32.8 h1:eOaLJGRi5x/Rb23fiVsxq9c5fZ/6O5QplExlGjNPDVI= +github.com/tendermint/tendermint v0.32.8/go.mod h1:5/B1XZjNYtVBso8o1l/Eg4A0Mhu42lDcmftoQl95j/E= github.com/tendermint/tm-db v0.1.1 h1:G3Xezy3sOk9+ekhjZ/kjArYIs1SmwV+1OUgNkj7RgV0= github.com/tendermint/tm-db v0.1.1/go.mod h1:0cPKWu2Mou3IlxecH+MEUSYc1Ch537alLe6CpFrKzgw= github.com/tendermint/tm-db v0.2.0 h1:rJxgdqn6fIiVJZy4zLpY1qVlyD0TU6vhkT4kEf71TQQ= @@ -276,12 +277,16 @@ golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a h1:YX8ljsm6wXlHZO+aRz9Exq golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= @@ -302,6 +307,7 @@ golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be h1:QAcqgptGM8IQBC9K/RC4o+O9YmqEm0diQn9QmZw/0mU= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= @@ -310,21 +316,26 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2 h1:67iHsV9djwGdZpdZNbLuQj6FOzCaZe3w+vhLjn5AcFA= google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/grpc v1.13.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.22.0 h1:J0UbZOIrCAl+fpTOf8YLs4dJo8L/owV4LYVtAXQoPkw= google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.23.1 h1:q4XQuHFC6I28BKZpo6IYyb3mNO+l7lSOxRuYTCiDfXk= -google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1 h1:wdKvqQk7IttEw92GoRyKG2IDrUIpgpj6H6m81yfeMW0= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -341,8 +352,6 @@ gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo= gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= From 7953b525d81da0b583dc670d03e41913e2e45c7c Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Mon, 2 Dec 2019 20:58:14 -0500 Subject: [PATCH 005/529] Merge PR #5299: Migrate Equivocation Handling to x/evidence --- CHANGELOG.md | 5 + simapp/app.go | 3 +- x/evidence/abci.go | 25 ++++ x/evidence/alias.go | 25 ++-- x/evidence/client/cli/query.go | 33 ++++- x/evidence/client/rest/query.go | 24 ++++ x/evidence/genesis.go | 3 + x/evidence/genesis_test.go | 6 +- x/evidence/handler_test.go | 2 +- x/evidence/internal/keeper/infraction.go | 109 ++++++++++++++++ x/evidence/internal/keeper/infraction_test.go | 117 ++++++++++++++++++ x/evidence/internal/keeper/keeper.go | 28 +++-- x/evidence/internal/keeper/keeper_test.go | 48 ++++++- x/evidence/internal/keeper/params.go | 25 ++++ x/evidence/internal/keeper/params_test.go | 11 ++ x/evidence/internal/keeper/querier.go | 22 +++- x/evidence/internal/keeper/querier_test.go | 9 ++ x/evidence/internal/types/codec.go | 1 + x/evidence/internal/types/evidence.go | 101 +++++++++++++++ x/evidence/internal/types/evidence_test.go | 55 ++++++++ x/evidence/internal/types/expected_keepers.go | 31 +++++ x/evidence/internal/types/genesis.go | 25 +++- x/evidence/internal/types/genesis_test.go | 4 +- x/evidence/internal/types/keys.go | 3 - x/evidence/internal/types/params.go | 60 +++++++++ x/evidence/internal/types/querier.go | 1 + x/evidence/module.go | 4 +- x/evidence/spec/05_params.md | 7 ++ x/evidence/spec/06_begin_block.md | 96 ++++++++++++++ x/evidence/spec/README.md | 16 ++- x/params/keeper_test.go | 5 +- x/params/subspace/subspace.go | 5 + x/slashing/abci.go | 15 --- x/slashing/alias.go | 3 - x/slashing/internal/keeper/infractions.go | 102 --------------- x/slashing/internal/keeper/keeper.go | 28 +++++ x/slashing/internal/keeper/keeper_test.go | 99 --------------- x/slashing/internal/keeper/params.go | 6 - x/slashing/internal/keeper/signing_info.go | 47 +++++++ .../internal/keeper/signing_info_test.go | 41 ++++++ x/slashing/internal/types/genesis.go | 5 - x/slashing/internal/types/params.go | 21 ++-- x/slashing/simulation/genesis.go | 4 +- x/slashing/spec/04_begin_block.md | 83 +------------ x/slashing/spec/06_events.md | 8 +- x/slashing/spec/08_params.md | 3 +- x/slashing/spec/README.md | 2 +- 47 files changed, 995 insertions(+), 381 deletions(-) create mode 100644 x/evidence/abci.go create mode 100644 x/evidence/internal/keeper/infraction.go create mode 100644 x/evidence/internal/keeper/infraction_test.go create mode 100644 x/evidence/internal/keeper/params.go create mode 100644 x/evidence/internal/keeper/params_test.go create mode 100644 x/evidence/internal/types/evidence.go create mode 100644 x/evidence/internal/types/evidence_test.go create mode 100644 x/evidence/internal/types/expected_keepers.go create mode 100644 x/evidence/internal/types/params.go create mode 100644 x/evidence/spec/05_params.md create mode 100644 x/evidence/spec/06_begin_block.md diff --git a/CHANGELOG.md b/CHANGELOG.md index cd0ee7cee95a..d5ed05db7416 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,9 @@ deprecated and all components removed except the `legacy/` package. This require genesis state. Namely, `accounts` now exist under `app_state.auth.accounts`. The corresponding migration logic has been implemented for v0.38 target version. Applications can migrate via: `$ {appd} migrate v0.38 genesis.json`. +* (modules) [\#5299](https://github.com/cosmos/cosmos-sdk/pull/5299) Handling of `ABCIEvidenceTypeDuplicateVote` + during `BeginBlock` along with the corresponding parameters (`MaxEvidenceAge`) have moved from the + `x/slashing` module to the `x/evidence` module. ### API Breaking Changes @@ -71,6 +74,8 @@ if the provided arguments are invalid. * `StdTx#GetSignatures` will return an array of just signature byte slices `[][]byte` instead of returning an array of `StdSignature` structs. To replicate the old behavior, use the public field `StdTx.Signatures` to get back the array of StdSignatures `[]StdSignature`. +* (modules) [\#5299](https://github.com/cosmos/cosmos-sdk/pull/5299) `HandleDoubleSign` along with params `MaxEvidenceAge` + and `DoubleSignJailEndTime` have moved from the `x/slashing` module to the `x/evidence` module. ### Client Breaking Changes diff --git a/simapp/app.go b/simapp/app.go index 87e08e0c6858..4ed1a244dda1 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -194,6 +194,7 @@ func NewSimApp( // create evidence keeper with router evidenceKeeper := evidence.NewKeeper( app.cdc, keys[evidence.StoreKey], app.subspaces[evidence.ModuleName], evidence.DefaultCodespace, + &app.StakingKeeper, app.SlashingKeeper, ) evidenceRouter := evidence.NewRouter() // TODO: Register evidence routes. @@ -237,7 +238,7 @@ func NewSimApp( // During begin block slashing happens after distr.BeginBlocker so that // there is nothing left over in the validator fee pool, so as to keep the // CanWithdrawInvariant invariant. - app.mm.SetOrderBeginBlockers(upgrade.ModuleName, mint.ModuleName, distr.ModuleName, slashing.ModuleName) + app.mm.SetOrderBeginBlockers(upgrade.ModuleName, mint.ModuleName, distr.ModuleName, slashing.ModuleName, evidence.ModuleName) app.mm.SetOrderEndBlockers(crisis.ModuleName, gov.ModuleName, staking.ModuleName) // NOTE: The genutils moodule must occur after staking so that pools are diff --git a/x/evidence/abci.go b/x/evidence/abci.go new file mode 100644 index 000000000000..e12ed7065f9b --- /dev/null +++ b/x/evidence/abci.go @@ -0,0 +1,25 @@ +package evidence + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + + abci "github.com/tendermint/tendermint/abci/types" + tmtypes "github.com/tendermint/tendermint/types" +) + +// BeginBlocker iterates through and handles any newly discovered evidence of +// misbehavior submitted by Tendermint. Currently, only equivocation is handled. +func BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock, k Keeper) { + for _, tmEvidence := range req.ByzantineValidators { + switch tmEvidence.Type { + case tmtypes.ABCIEvidenceTypeDuplicateVote: + evidence := ConvertDuplicateVoteEvidence(tmEvidence) + k.HandleDoubleSign(ctx, evidence.(Equivocation)) + + default: + k.Logger(ctx).Error(fmt.Sprintf("ignored unknown evidence type: %s", tmEvidence.Type)) + } + } +} diff --git a/x/evidence/alias.go b/x/evidence/alias.go index 5eca5a074f1f..411f39751578 100644 --- a/x/evidence/alias.go +++ b/x/evidence/alias.go @@ -15,6 +15,7 @@ const ( DefaultParamspace = types.DefaultParamspace QueryEvidence = types.QueryEvidence QueryAllEvidence = types.QueryAllEvidence + QueryParameters = types.QueryParameters CodeNoEvidenceHandlerExists = types.CodeNoEvidenceHandlerExists CodeInvalidEvidence = types.CodeInvalidEvidence CodeNoEvidenceExists = types.CodeNoEvidenceExists @@ -23,21 +24,26 @@ const ( EventTypeSubmitEvidence = types.EventTypeSubmitEvidence AttributeValueCategory = types.AttributeValueCategory AttributeKeyEvidenceHash = types.AttributeKeyEvidenceHash + DefaultMaxEvidenceAge = types.DefaultMaxEvidenceAge ) var ( NewKeeper = keeper.NewKeeper NewQuerier = keeper.NewQuerier - NewMsgSubmitEvidence = types.NewMsgSubmitEvidence - NewRouter = types.NewRouter - NewQueryEvidenceParams = types.NewQueryEvidenceParams - NewQueryAllEvidenceParams = types.NewQueryAllEvidenceParams - RegisterCodec = types.RegisterCodec - RegisterEvidenceTypeCodec = types.RegisterEvidenceTypeCodec - ModuleCdc = types.ModuleCdc - NewGenesisState = types.NewGenesisState - DefaultGenesisState = types.DefaultGenesisState + NewMsgSubmitEvidence = types.NewMsgSubmitEvidence + NewRouter = types.NewRouter + NewQueryEvidenceParams = types.NewQueryEvidenceParams + NewQueryAllEvidenceParams = types.NewQueryAllEvidenceParams + RegisterCodec = types.RegisterCodec + RegisterEvidenceTypeCodec = types.RegisterEvidenceTypeCodec + ModuleCdc = types.ModuleCdc + NewGenesisState = types.NewGenesisState + DefaultGenesisState = types.DefaultGenesisState + ConvertDuplicateVoteEvidence = types.ConvertDuplicateVoteEvidence + KeyMaxEvidenceAge = types.KeyMaxEvidenceAge + DoubleSignJailEndTime = types.DoubleSignJailEndTime + ParamKeyTable = types.ParamKeyTable ) type ( @@ -47,4 +53,5 @@ type ( MsgSubmitEvidence = types.MsgSubmitEvidence Handler = types.Handler Router = types.Router + Equivocation = types.Equivocation ) diff --git a/x/evidence/client/cli/query.go b/x/evidence/client/cli/query.go index 0529af859411..4c5eb13abaf1 100644 --- a/x/evidence/client/cli/query.go +++ b/x/evidence/client/cli/query.go @@ -46,7 +46,38 @@ $ %s query %s --page=2 --limit=50 cmd.Flags().Int(flagPage, 1, "pagination page of evidence to to query for") cmd.Flags().Int(flagLimit, 100, "pagination limit of evidence to query for") - return cmd + cmd.AddCommand(client.GetCommands(QueryParamsCmd(cdc))...) + + return client.GetCommands(cmd)[0] +} + +// QueryParamsCmd returns the command handler for evidence parameter querying. +func QueryParamsCmd(cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "params", + Short: "Query the current evidence parameters", + Args: cobra.NoArgs, + Long: strings.TrimSpace(`Query the current evidence parameters: + +$ query evidence params +`), + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + + route := fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryParameters) + res, _, err := cliCtx.QueryWithData(route, nil) + if err != nil { + return err + } + + var params types.Params + if err := cdc.UnmarshalJSON(res, ¶ms); err != nil { + return fmt.Errorf("failed to unmarshal params: %w", err) + } + + return cliCtx.PrintOutput(params) + }, + } } // QueryEvidenceCmd returns the command handler for evidence querying. Evidence diff --git a/x/evidence/client/rest/query.go b/x/evidence/client/rest/query.go index 84a894487a99..45b66660ac73 100644 --- a/x/evidence/client/rest/query.go +++ b/x/evidence/client/rest/query.go @@ -22,6 +22,11 @@ func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router) { "/evidence", queryAllEvidenceHandler(cliCtx), ).Methods(MethodGet) + + r.HandleFunc( + "/evidence/params", + queryParamsHandler(cliCtx), + ).Methods(MethodGet) } func queryEvidenceHandler(cliCtx context.CLIContext) http.HandlerFunc { @@ -89,3 +94,22 @@ func queryAllEvidenceHandler(cliCtx context.CLIContext) http.HandlerFunc { rest.PostProcessResponse(w, cliCtx, res) } } + +func queryParamsHandler(cliCtx context.CLIContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) + if !ok { + return + } + + route := fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryParameters) + res, height, err := cliCtx.QueryWithData(route, nil) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + + cliCtx = cliCtx.WithHeight(height) + rest.PostProcessResponse(w, cliCtx, res) + } +} diff --git a/x/evidence/genesis.go b/x/evidence/genesis.go index b06c7ce96783..2ec9e954202e 100644 --- a/x/evidence/genesis.go +++ b/x/evidence/genesis.go @@ -20,11 +20,14 @@ func InitGenesis(ctx sdk.Context, k Keeper, gs GenesisState) { k.SetEvidence(ctx, e) } + + k.SetParams(ctx, gs.Params) } // ExportGenesis returns the evidence module's exported genesis. func ExportGenesis(ctx sdk.Context, k Keeper) GenesisState { return GenesisState{ + Params: k.GetParams(ctx), Evidence: k.GetAllEvidence(ctx), } } diff --git a/x/evidence/genesis_test.go b/x/evidence/genesis_test.go index 3f3e3abac48b..a77b847db177 100644 --- a/x/evidence/genesis_test.go +++ b/x/evidence/genesis_test.go @@ -33,7 +33,7 @@ func (suite *GenesisTestSuite) SetupTest() { // recreate keeper in order to use custom testing types evidenceKeeper := evidence.NewKeeper( cdc, app.GetKey(evidence.StoreKey), app.GetSubspace(evidence.ModuleName), - evidence.DefaultCodespace, + evidence.DefaultCodespace, app.StakingKeeper, app.SlashingKeeper, ) router := evidence.NewRouter() router = router.AddRoute(types.TestEvidenceRouteEquivocation, types.TestEquivocationHandler(*evidenceKeeper)) @@ -67,7 +67,7 @@ func (suite *GenesisTestSuite) TestInitGenesis_Valid() { } suite.NotPanics(func() { - evidence.InitGenesis(suite.ctx, suite.keeper, evidence.NewGenesisState(testEvidence)) + evidence.InitGenesis(suite.ctx, suite.keeper, evidence.NewGenesisState(types.DefaultParams(), testEvidence)) }) for _, e := range testEvidence { @@ -100,7 +100,7 @@ func (suite *GenesisTestSuite) TestInitGenesis_Invalid() { } suite.Panics(func() { - evidence.InitGenesis(suite.ctx, suite.keeper, evidence.NewGenesisState(testEvidence)) + evidence.InitGenesis(suite.ctx, suite.keeper, evidence.NewGenesisState(types.DefaultParams(), testEvidence)) }) suite.Empty(suite.keeper.GetAllEvidence(suite.ctx)) diff --git a/x/evidence/handler_test.go b/x/evidence/handler_test.go index 0b286817ee2c..1957778950ad 100644 --- a/x/evidence/handler_test.go +++ b/x/evidence/handler_test.go @@ -32,7 +32,7 @@ func (suite *HandlerTestSuite) SetupTest() { // recreate keeper in order to use custom testing types evidenceKeeper := evidence.NewKeeper( cdc, app.GetKey(evidence.StoreKey), app.GetSubspace(evidence.ModuleName), - evidence.DefaultCodespace, + evidence.DefaultCodespace, app.StakingKeeper, app.SlashingKeeper, ) router := evidence.NewRouter() router = router.AddRoute(types.TestEvidenceRouteEquivocation, types.TestEquivocationHandler(*evidenceKeeper)) diff --git a/x/evidence/internal/keeper/infraction.go b/x/evidence/internal/keeper/infraction.go new file mode 100644 index 000000000000..fab16c833e74 --- /dev/null +++ b/x/evidence/internal/keeper/infraction.go @@ -0,0 +1,109 @@ +package keeper + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/cosmos-sdk/x/evidence/internal/types" +) + +// HandleDoubleSign implements an equivocation evidence handler. Assuming the +// evidence is valid, the validator committing the misbehavior will be slashed, +// jailed and tombstoned. Once tombstoned, the validator will not be able to +// recover. Note, the evidence contains the block time and height at the time of +// the equivocation. +// +// The evidence is considered invalid if: +// - the evidence is too old +// - the validator is unbonded or does not exist +// - the signing info does not exist (will panic) +// - is already tombstoned +// +// TODO: Some of the invalid constraints listed above may need to be reconsidered +// in the case of a lunatic attack. +func (k Keeper) HandleDoubleSign(ctx sdk.Context, evidence types.Equivocation) { + logger := k.Logger(ctx) + consAddr := evidence.GetConsensusAddress() + infractionHeight := evidence.GetHeight() + + // calculate the age of the evidence + blockTime := ctx.BlockHeader().Time + age := blockTime.Sub(evidence.GetTime()) + + if _, err := k.slashingKeeper.GetPubkey(ctx, consAddr.Bytes()); err != nil { + // Ignore evidence that cannot be handled. + // + // NOTE: We used to panic with: + // `panic(fmt.Sprintf("Validator consensus-address %v not found", consAddr))`, + // but this couples the expectations of the app to both Tendermint and + // the simulator. Both are expected to provide the full range of + // allowable but none of the disallowed evidence types. Instead of + // getting this coordination right, it is easier to relax the + // constraints and ignore evidence that cannot be handled. + return + } + + // reject evidence if the double-sign is too old + if age > k.MaxEvidenceAge(ctx) { + logger.Info( + fmt.Sprintf( + "ignored double sign from %s at height %d, age of %d past max age of %d", + consAddr, infractionHeight, age, k.MaxEvidenceAge(ctx), + ), + ) + return + } + + validator := k.stakingKeeper.ValidatorByConsAddr(ctx, consAddr) + if validator == nil || validator.IsUnbonded() { + // Defensive: Simulation doesn't take unbonding periods into account, and + // Tendermint might break this assumption at some point. + return + } + + if ok := k.slashingKeeper.HasValidatorSigningInfo(ctx, consAddr); !ok { + panic(fmt.Sprintf("expected signing info for validator %s but not found", consAddr)) + } + + // ignore if the validator is already tombstoned + if k.slashingKeeper.IsTombstoned(ctx, consAddr) { + logger.Info( + fmt.Sprintf( + "ignored double sign from %s at height %d, validator already tombstoned", + consAddr, infractionHeight, + ), + ) + return + } + + logger.Info(fmt.Sprintf("confirmed double sign from %s at height %d, age of %d", consAddr, infractionHeight, age)) + + // We need to retrieve the stake distribution which signed the block, so we + // subtract ValidatorUpdateDelay from the evidence height. + // Note, that this *can* result in a negative "distributionHeight", up to + // -ValidatorUpdateDelay, i.e. at the end of the + // pre-genesis block (none) = at the beginning of the genesis block. + // That's fine since this is just used to filter unbonding delegations & redelegations. + distributionHeight := infractionHeight - sdk.ValidatorUpdateDelay + + // Slash validator. The `power` is the int64 power of the validator as provided + // to/by Tendermint. This value is validator.Tokens as sent to Tendermint via + // ABCI, and now received as evidence. The fraction is passed in to separately + // to slash unbonding and rebonding delegations. + k.slashingKeeper.Slash( + ctx, + consAddr, + k.slashingKeeper.SlashFractionDoubleSign(ctx), + evidence.GetValidatorPower(), distributionHeight, + ) + + // Jail the validator if not already jailed. This will begin unbonding the + // validator if not already unbonding (tombstoned). + if !validator.IsJailed() { + k.slashingKeeper.Jail(ctx, consAddr) + } + + k.slashingKeeper.JailUntil(ctx, consAddr, types.DoubleSignJailEndTime) + k.slashingKeeper.Tombstone(ctx, consAddr) +} diff --git a/x/evidence/internal/keeper/infraction_test.go b/x/evidence/internal/keeper/infraction_test.go new file mode 100644 index 000000000000..ca68948f5eb1 --- /dev/null +++ b/x/evidence/internal/keeper/infraction_test.go @@ -0,0 +1,117 @@ +package keeper_test + +import ( + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/evidence/internal/types" + "github.com/cosmos/cosmos-sdk/x/staking" + + "github.com/tendermint/tendermint/crypto" +) + +func newTestMsgCreateValidator(address sdk.ValAddress, pubKey crypto.PubKey, amt sdk.Int) staking.MsgCreateValidator { + commission := staking.NewCommissionRates(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()) + return staking.NewMsgCreateValidator( + address, pubKey, sdk.NewCoin(sdk.DefaultBondDenom, amt), + staking.Description{}, commission, sdk.OneInt(), + ) +} + +func (suite *KeeperTestSuite) TestHandleDoubleSign() { + ctx := suite.ctx.WithIsCheckTx(false).WithBlockHeight(1) + suite.populateValidators(ctx) + + power := int64(100) + stakingParams := suite.app.StakingKeeper.GetParams(ctx) + amt := sdk.TokensFromConsensusPower(power) + operatorAddr, val := valAddresses[0], pubkeys[0] + + // create validator + res := staking.NewHandler(suite.app.StakingKeeper)(ctx, newTestMsgCreateValidator(operatorAddr, val, amt)) + suite.True(res.IsOK(), res.Log) + + // execute end-blocker and verify validator attributes + staking.EndBlocker(ctx, suite.app.StakingKeeper) + suite.Equal( + suite.app.BankKeeper.GetCoins(ctx, sdk.AccAddress(operatorAddr)), + sdk.NewCoins(sdk.NewCoin(stakingParams.BondDenom, initAmt.Sub(amt))), + ) + suite.Equal(amt, suite.app.StakingKeeper.Validator(ctx, operatorAddr).GetBondedTokens()) + + // handle a signature to set signing info + suite.app.SlashingKeeper.HandleValidatorSignature(ctx, val.Address(), amt.Int64(), true) + + // double sign less than max age + oldTokens := suite.app.StakingKeeper.Validator(ctx, operatorAddr).GetTokens() + evidence := types.Equivocation{ + Height: 0, + Time: time.Unix(0, 0), + Power: power, + ConsensusAddress: sdk.ConsAddress(val.Address()), + } + suite.keeper.HandleDoubleSign(ctx, evidence) + + // should be jailed and tombstoned + suite.True(suite.app.StakingKeeper.Validator(ctx, operatorAddr).IsJailed()) + suite.True(suite.app.SlashingKeeper.IsTombstoned(ctx, sdk.ConsAddress(val.Address()))) + + // tokens should be decreased + newTokens := suite.app.StakingKeeper.Validator(ctx, operatorAddr).GetTokens() + suite.True(newTokens.LT(oldTokens)) + + // submit duplicate evidence + suite.keeper.HandleDoubleSign(ctx, evidence) + + // tokens should be the same (capped slash) + suite.True(suite.app.StakingKeeper.Validator(ctx, operatorAddr).GetTokens().Equal(newTokens)) + + // jump to past the unbonding period + ctx = ctx.WithBlockTime(time.Unix(1, 0).Add(stakingParams.UnbondingTime)) + + // require we cannot unjail + suite.Error(suite.app.SlashingKeeper.Unjail(ctx, operatorAddr)) + + // require we be able to unbond now + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + del, _ := suite.app.StakingKeeper.GetDelegation(ctx, sdk.AccAddress(operatorAddr), operatorAddr) + validator, _ := suite.app.StakingKeeper.GetValidator(ctx, operatorAddr) + totalBond := validator.TokensFromShares(del.GetShares()).TruncateInt() + msgUnbond := staking.NewMsgUndelegate(sdk.AccAddress(operatorAddr), operatorAddr, sdk.NewCoin(stakingParams.BondDenom, totalBond)) + res = staking.NewHandler(suite.app.StakingKeeper)(ctx, msgUnbond) + suite.True(res.IsOK()) +} + +func (suite *KeeperTestSuite) TestHandleDoubleSign_TooOld() { + ctx := suite.ctx.WithIsCheckTx(false).WithBlockHeight(1).WithBlockTime(time.Now()) + suite.populateValidators(ctx) + + power := int64(100) + stakingParams := suite.app.StakingKeeper.GetParams(ctx) + amt := sdk.TokensFromConsensusPower(power) + operatorAddr, val := valAddresses[0], pubkeys[0] + + // create validator + res := staking.NewHandler(suite.app.StakingKeeper)(ctx, newTestMsgCreateValidator(operatorAddr, val, amt)) + suite.True(res.IsOK(), res.Log) + + // execute end-blocker and verify validator attributes + staking.EndBlocker(ctx, suite.app.StakingKeeper) + suite.Equal( + suite.app.BankKeeper.GetCoins(ctx, sdk.AccAddress(operatorAddr)), + sdk.NewCoins(sdk.NewCoin(stakingParams.BondDenom, initAmt.Sub(amt))), + ) + suite.Equal(amt, suite.app.StakingKeeper.Validator(ctx, operatorAddr).GetBondedTokens()) + + evidence := types.Equivocation{ + Height: 0, + Time: ctx.BlockTime(), + Power: power, + ConsensusAddress: sdk.ConsAddress(val.Address()), + } + ctx = ctx.WithBlockTime(ctx.BlockTime().Add(suite.app.EvidenceKeeper.MaxEvidenceAge(ctx) + 1)) + suite.keeper.HandleDoubleSign(ctx, evidence) + + suite.False(suite.app.StakingKeeper.Validator(ctx, operatorAddr).IsJailed()) + suite.False(suite.app.SlashingKeeper.IsTombstoned(ctx, sdk.ConsAddress(val.Address()))) +} diff --git a/x/evidence/internal/keeper/keeper.go b/x/evidence/internal/keeper/keeper.go index fa79aac7be08..26b45db7d69d 100644 --- a/x/evidence/internal/keeper/keeper.go +++ b/x/evidence/internal/keeper/keeper.go @@ -18,22 +18,32 @@ import ( // managing persistence, state transitions and query handling for the evidence // module. type Keeper struct { - cdc *codec.Codec - storeKey sdk.StoreKey - paramSpace params.Subspace - router types.Router - codespace sdk.CodespaceType + cdc *codec.Codec + storeKey sdk.StoreKey + paramSpace params.Subspace + router types.Router + stakingKeeper types.StakingKeeper + slashingKeeper types.SlashingKeeper + codespace sdk.CodespaceType } func NewKeeper( cdc *codec.Codec, storeKey sdk.StoreKey, paramSpace params.Subspace, codespace sdk.CodespaceType, + stakingKeeper types.StakingKeeper, slashingKeeper types.SlashingKeeper, ) *Keeper { + // set KeyTable if it has not already been set + if !paramSpace.HasKeyTable() { + paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable()) + } + return &Keeper{ - cdc: cdc, - storeKey: storeKey, - paramSpace: paramSpace, - codespace: codespace, + cdc: cdc, + storeKey: storeKey, + paramSpace: paramSpace, + stakingKeeper: stakingKeeper, + slashingKeeper: slashingKeeper, + codespace: codespace, } } diff --git a/x/evidence/internal/keeper/keeper_test.go b/x/evidence/internal/keeper/keeper_test.go index 2f7862283ae8..bde9f08f02ce 100644 --- a/x/evidence/internal/keeper/keeper_test.go +++ b/x/evidence/internal/keeper/keeper_test.go @@ -1,6 +1,7 @@ package keeper_test import ( + "encoding/hex" "testing" "github.com/cosmos/cosmos-sdk/simapp" @@ -9,18 +10,50 @@ import ( "github.com/cosmos/cosmos-sdk/x/evidence/exported" "github.com/cosmos/cosmos-sdk/x/evidence/internal/keeper" "github.com/cosmos/cosmos-sdk/x/evidence/internal/types" + "github.com/cosmos/cosmos-sdk/x/supply" "github.com/stretchr/testify/suite" abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/ed25519" ) +var ( + pubkeys = []crypto.PubKey{ + newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB50"), + newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB51"), + newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB52"), + } + + valAddresses = []sdk.ValAddress{ + sdk.ValAddress(pubkeys[0].Address()), + sdk.ValAddress(pubkeys[1].Address()), + sdk.ValAddress(pubkeys[2].Address()), + } + + initAmt = sdk.TokensFromConsensusPower(200) + initCoins = sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initAmt)) +) + +func newPubKey(pk string) (res crypto.PubKey) { + pkBytes, err := hex.DecodeString(pk) + if err != nil { + panic(err) + } + + var pubkey ed25519.PubKeyEd25519 + copy(pubkey[:], pkBytes) + + return pubkey +} + type KeeperTestSuite struct { suite.Suite ctx sdk.Context querier sdk.Querier keeper keeper.Keeper + app *simapp.SimApp } func (suite *KeeperTestSuite) SetupTest() { @@ -34,7 +67,7 @@ func (suite *KeeperTestSuite) SetupTest() { // recreate keeper in order to use custom testing types evidenceKeeper := evidence.NewKeeper( cdc, app.GetKey(evidence.StoreKey), app.GetSubspace(evidence.ModuleName), - evidence.DefaultCodespace, + evidence.DefaultCodespace, app.StakingKeeper, app.SlashingKeeper, ) router := evidence.NewRouter() router = router.AddRoute(types.TestEvidenceRouteEquivocation, types.TestEquivocationHandler(*evidenceKeeper)) @@ -43,6 +76,7 @@ func (suite *KeeperTestSuite) SetupTest() { suite.ctx = app.BaseApp.NewContext(checkTx, abci.Header{Height: 1}) suite.querier = keeper.NewQuerier(*evidenceKeeper) suite.keeper = *evidenceKeeper + suite.app = app } func (suite *KeeperTestSuite) populateEvidence(ctx sdk.Context, numEvidence int) []exported.Evidence { @@ -74,6 +108,18 @@ func (suite *KeeperTestSuite) populateEvidence(ctx sdk.Context, numEvidence int) return evidence } +func (suite *KeeperTestSuite) populateValidators(ctx sdk.Context) { + // add accounts and set total supply + totalSupplyAmt := initAmt.MulRaw(int64(len(valAddresses))) + totalSupply := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, totalSupplyAmt)) + suite.app.SupplyKeeper.SetSupply(ctx, supply.NewSupply(totalSupply)) + + for _, addr := range valAddresses { + _, err := suite.app.BankKeeper.AddCoins(ctx, sdk.AccAddress(addr), initCoins) + suite.NoError(err) + } +} + func (suite *KeeperTestSuite) TestSubmitValidEvidence() { ctx := suite.ctx.WithIsCheckTx(false) pk := ed25519.GenPrivKey() diff --git a/x/evidence/internal/keeper/params.go b/x/evidence/internal/keeper/params.go new file mode 100644 index 000000000000..8db4867781e7 --- /dev/null +++ b/x/evidence/internal/keeper/params.go @@ -0,0 +1,25 @@ +package keeper + +import ( + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/evidence/internal/types" +) + +// MaxEvidenceAge returns the maximum age for submitted evidence. +func (k Keeper) MaxEvidenceAge(ctx sdk.Context) (res time.Duration) { + k.paramSpace.Get(ctx, types.KeyMaxEvidenceAge, &res) + return +} + +// GetParams returns the total set of evidence parameters. +func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) { + k.paramSpace.GetParamSet(ctx, ¶ms) + return params +} + +// SetParams sets the evidence parameters to the param space. +func (k Keeper) SetParams(ctx sdk.Context, params types.Params) { + k.paramSpace.SetParamSet(ctx, ¶ms) +} diff --git a/x/evidence/internal/keeper/params_test.go b/x/evidence/internal/keeper/params_test.go new file mode 100644 index 000000000000..58d25230eec7 --- /dev/null +++ b/x/evidence/internal/keeper/params_test.go @@ -0,0 +1,11 @@ +package keeper_test + +import ( + "github.com/cosmos/cosmos-sdk/x/evidence/internal/types" +) + +func (suite *KeeperTestSuite) TestParams() { + ctx := suite.ctx.WithIsCheckTx(false) + suite.Equal(types.DefaultParams(), suite.keeper.GetParams(ctx)) + suite.Equal(types.DefaultMaxEvidenceAge, suite.keeper.MaxEvidenceAge(ctx)) +} diff --git a/x/evidence/internal/keeper/querier.go b/x/evidence/internal/keeper/querier.go index fa6ef17c0f31..dfbda68f66d6 100644 --- a/x/evidence/internal/keeper/querier.go +++ b/x/evidence/internal/keeper/querier.go @@ -21,11 +21,14 @@ func NewQuerier(k Keeper) sdk.Querier { ) switch path[0] { + case types.QueryParameters: + res, err = queryParams(ctx, k) + case types.QueryEvidence: - res, err = queryEvidence(ctx, path[1:], req, k) + res, err = queryEvidence(ctx, req, k) case types.QueryAllEvidence: - res, err = queryAllEvidence(ctx, path[1:], req, k) + res, err = queryAllEvidence(ctx, req, k) default: err = sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown %s query endpoint", types.ModuleName) @@ -35,7 +38,18 @@ func NewQuerier(k Keeper) sdk.Querier { } } -func queryEvidence(ctx sdk.Context, _ []string, req abci.RequestQuery, k Keeper) ([]byte, error) { +func queryParams(ctx sdk.Context, k Keeper) ([]byte, error) { + params := k.GetParams(ctx) + + res, err := codec.MarshalJSONIndent(k.cdc, params) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) + } + + return res, nil +} + +func queryEvidence(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryEvidenceParams err := k.cdc.UnmarshalJSON(req.Data, ¶ms) @@ -61,7 +75,7 @@ func queryEvidence(ctx sdk.Context, _ []string, req abci.RequestQuery, k Keeper) return res, nil } -func queryAllEvidence(ctx sdk.Context, _ []string, req abci.RequestQuery, k Keeper) ([]byte, error) { +func queryAllEvidence(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryAllEvidenceParams err := k.cdc.UnmarshalJSON(req.Data, ¶ms) diff --git a/x/evidence/internal/keeper/querier_test.go b/x/evidence/internal/keeper/querier_test.go index b656019edd8a..68af96640ab4 100644 --- a/x/evidence/internal/keeper/querier_test.go +++ b/x/evidence/internal/keeper/querier_test.go @@ -84,3 +84,12 @@ func (suite *KeeperTestSuite) TestQueryAllEvidence_InvalidPagination() { suite.Nil(types.TestingCdc.UnmarshalJSON(bz, &e)) suite.Len(e, 0) } + +func (suite *KeeperTestSuite) TestQueryParams() { + ctx := suite.ctx.WithIsCheckTx(false) + + bz, err := suite.querier(ctx, []string{types.QueryParameters}, abci.RequestQuery{}) + suite.Nil(err) + suite.NotNil(bz) + suite.Equal("{\n \"max_evidence_age\": \"120000000000\"\n}", string(bz)) +} diff --git a/x/evidence/internal/types/codec.go b/x/evidence/internal/types/codec.go index 72fb044e9d55..7c57bc4a71f8 100644 --- a/x/evidence/internal/types/codec.go +++ b/x/evidence/internal/types/codec.go @@ -14,6 +14,7 @@ var ModuleCdc = codec.New() func RegisterCodec(cdc *codec.Codec) { cdc.RegisterInterface((*exported.Evidence)(nil), nil) cdc.RegisterConcrete(MsgSubmitEvidence{}, "cosmos-sdk/MsgSubmitEvidence", nil) + cdc.RegisterConcrete(Equivocation{}, "cosmos-sdk/Equivocation", nil) } // RegisterEvidenceTypeCodec registers an external concrete Evidence type defined diff --git a/x/evidence/internal/types/evidence.go b/x/evidence/internal/types/evidence.go new file mode 100644 index 000000000000..d4dbfc1eafef --- /dev/null +++ b/x/evidence/internal/types/evidence.go @@ -0,0 +1,101 @@ +package types + +import ( + "fmt" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/evidence/exported" + + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto/tmhash" + cmn "github.com/tendermint/tendermint/libs/common" + "gopkg.in/yaml.v2" +) + +// Evidence type constants +const ( + RouteEquivocation = "equivocation" + TypeEquivocation = "equivocation" +) + +var _ exported.Evidence = (*Equivocation)(nil) + +// Equivocation implements the Evidence interface and defines evidence of double +// signing misbehavior. +type Equivocation struct { + Height int64 `json:"height" yaml:"height"` + Time time.Time `json:"time" yaml:"time"` + Power int64 `json:"power" yaml:"power"` + ConsensusAddress sdk.ConsAddress `json:"consensus_address" yaml:"consensus_address"` +} + +// Route returns the Evidence Handler route for an Equivocation type. +func (e Equivocation) Route() string { return RouteEquivocation } + +// Type returns the Evidence Handler type for an Equivocation type. +func (e Equivocation) Type() string { return TypeEquivocation } + +func (e Equivocation) String() string { + bz, _ := yaml.Marshal(e) + return string(bz) +} + +// Hash returns the hash of an Equivocation object. +func (e Equivocation) Hash() cmn.HexBytes { + return tmhash.Sum(ModuleCdc.MustMarshalBinaryBare(e)) +} + +// ValidateBasic performs basic stateless validation checks on an Equivocation object. +func (e Equivocation) ValidateBasic() error { + if e.Time.IsZero() { + return fmt.Errorf("invalid equivocation time: %s", e.Time) + } + if e.Height < 1 { + return fmt.Errorf("invalid equivocation height: %d", e.Height) + } + if e.Power < 1 { + return fmt.Errorf("invalid equivocation validator power: %d", e.Power) + } + if e.ConsensusAddress.Empty() { + return fmt.Errorf("invalid equivocation validator consensus address: %s", e.ConsensusAddress) + } + + return nil +} + +// GetConsensusAddress returns the validator's consensus address at time of the +// Equivocation infraction. +func (e Equivocation) GetConsensusAddress() sdk.ConsAddress { + return e.ConsensusAddress +} + +// GetHeight returns the height at time of the Equivocation infraction. +func (e Equivocation) GetHeight() int64 { + return e.Height +} + +// GetTime returns the time at time of the Equivocation infraction. +func (e Equivocation) GetTime() time.Time { + return e.Time +} + +// GetValidatorPower returns the validator's power at time of the Equivocation +// infraction. +func (e Equivocation) GetValidatorPower() int64 { + return e.Power +} + +// GetTotalPower is a no-op for the Equivocation type. +func (e Equivocation) GetTotalPower() int64 { return 0 } + +// ConvertDuplicateVoteEvidence converts a Tendermint concrete Evidence type to +// SDK Evidence using Equivocation as the concrete type. +func ConvertDuplicateVoteEvidence(dupVote abci.Evidence) exported.Evidence { + return Equivocation{ + Height: dupVote.Height, + Power: dupVote.Validator.Power, + ConsensusAddress: sdk.ConsAddress(dupVote.Validator.Address), + Time: dupVote.Time, + } +} diff --git a/x/evidence/internal/types/evidence_test.go b/x/evidence/internal/types/evidence_test.go new file mode 100644 index 000000000000..ad2107b8fa41 --- /dev/null +++ b/x/evidence/internal/types/evidence_test.go @@ -0,0 +1,55 @@ +package types_test + +import ( + "testing" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/evidence/internal/types" + "github.com/stretchr/testify/require" +) + +func TestEquivocation_Valid(t *testing.T) { + n, _ := time.Parse(time.RFC3339, "2006-01-02T15:04:05Z") + e := types.Equivocation{ + Height: 100, + Time: n, + Power: 1000000, + ConsensusAddress: sdk.ConsAddress("foo"), + } + + require.Equal(t, e.GetTotalPower(), int64(0)) + require.Equal(t, e.GetValidatorPower(), e.Power) + require.Equal(t, e.GetTime(), e.Time) + require.Equal(t, e.GetConsensusAddress(), e.ConsensusAddress) + require.Equal(t, e.GetHeight(), e.Height) + require.Equal(t, e.Type(), types.TypeEquivocation) + require.Equal(t, e.Route(), types.RouteEquivocation) + require.Equal(t, e.Hash().String(), "808DA679674C9C0599965D02EBC5D4DCFD5E700D03035BBCD2DECCBBF44386F7") + require.Equal(t, e.String(), "height: 100\ntime: 2006-01-02T15:04:05Z\npower: 1000000\nconsensus_address: cosmosvalcons1vehk7pqt5u4\n") + require.NoError(t, e.ValidateBasic()) +} + +func TestEquivocationValidateBasic(t *testing.T) { + var zeroTime time.Time + + n, _ := time.Parse(time.RFC3339, "2006-01-02T15:04:05Z") + testCases := []struct { + name string + e types.Equivocation + expectErr bool + }{ + {"valid", types.Equivocation{100, n, 1000000, sdk.ConsAddress("foo")}, false}, + {"invalid time", types.Equivocation{100, zeroTime, 1000000, sdk.ConsAddress("foo")}, true}, + {"invalid height", types.Equivocation{0, n, 1000000, sdk.ConsAddress("foo")}, true}, + {"invalid power", types.Equivocation{100, n, 0, sdk.ConsAddress("foo")}, true}, + {"invalid address", types.Equivocation{100, n, 1000000, nil}, true}, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + require.Equal(t, tc.expectErr, tc.e.ValidateBasic() != nil) + }) + } +} diff --git a/x/evidence/internal/types/expected_keepers.go b/x/evidence/internal/types/expected_keepers.go new file mode 100644 index 000000000000..fc4b12247639 --- /dev/null +++ b/x/evidence/internal/types/expected_keepers.go @@ -0,0 +1,31 @@ +package types + +import ( + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + stakingexported "github.com/cosmos/cosmos-sdk/x/staking/exported" + + "github.com/tendermint/tendermint/crypto" +) + +type ( + // StakingKeeper defines the staking module interface contract needed by the + // evidence module. + StakingKeeper interface { + ValidatorByConsAddr(sdk.Context, sdk.ConsAddress) stakingexported.ValidatorI + } + + // SlashingKeeper defines the slashing module interface contract needed by the + // evidence module. + SlashingKeeper interface { + GetPubkey(sdk.Context, crypto.Address) (crypto.PubKey, error) + IsTombstoned(sdk.Context, sdk.ConsAddress) bool + HasValidatorSigningInfo(sdk.Context, sdk.ConsAddress) bool + Tombstone(sdk.Context, sdk.ConsAddress) + Slash(sdk.Context, sdk.ConsAddress, sdk.Dec, int64, int64) + SlashFractionDoubleSign(sdk.Context) sdk.Dec + Jail(sdk.Context, sdk.ConsAddress) + JailUntil(sdk.Context, sdk.ConsAddress, time.Time) + } +) diff --git a/x/evidence/internal/types/genesis.go b/x/evidence/internal/types/genesis.go index 4013b573fc9f..83c5a0f10a58 100644 --- a/x/evidence/internal/types/genesis.go +++ b/x/evidence/internal/types/genesis.go @@ -1,21 +1,33 @@ package types -import "github.com/cosmos/cosmos-sdk/x/evidence/exported" +import ( + "fmt" + "time" + + "github.com/cosmos/cosmos-sdk/x/evidence/exported" +) // DONTCOVER // GenesisState defines the evidence module's genesis state. type GenesisState struct { + Params Params `json:"params" yaml:"params"` Evidence []exported.Evidence `json:"evidence" yaml:"evidence"` } -func NewGenesisState(e []exported.Evidence) GenesisState { - return GenesisState{Evidence: e} +func NewGenesisState(p Params, e []exported.Evidence) GenesisState { + return GenesisState{ + Params: p, + Evidence: e, + } } // DefaultGenesisState returns the evidence module's default genesis state. func DefaultGenesisState() GenesisState { - return GenesisState{Evidence: []exported.Evidence{}} + return GenesisState{ + Params: DefaultParams(), + Evidence: []exported.Evidence{}, + } } // Validate performs basic gensis state validation returning an error upon any @@ -27,5 +39,10 @@ func (gs GenesisState) Validate() error { } } + maxEvidence := gs.Params.MaxEvidenceAge + if maxEvidence < 1*time.Minute { + return fmt.Errorf("max evidence age must be at least 1 minute, is %s", maxEvidence.String()) + } + return nil } diff --git a/x/evidence/internal/types/genesis_test.go b/x/evidence/internal/types/genesis_test.go index 936877ad3c2a..f7ef8027b25c 100644 --- a/x/evidence/internal/types/genesis_test.go +++ b/x/evidence/internal/types/genesis_test.go @@ -39,7 +39,7 @@ func TestGenesisStateValidate_Valid(t *testing.T) { } } - gs := types.NewGenesisState(evidence) + gs := types.NewGenesisState(types.DefaultParams(), evidence) require.NoError(t, gs.Validate()) } @@ -66,6 +66,6 @@ func TestGenesisStateValidate_Invalid(t *testing.T) { } } - gs := types.NewGenesisState(evidence) + gs := types.NewGenesisState(types.DefaultParams(), evidence) require.Error(t, gs.Validate()) } diff --git a/x/evidence/internal/types/keys.go b/x/evidence/internal/types/keys.go index 702f76d9b64a..775fa2c021a1 100644 --- a/x/evidence/internal/types/keys.go +++ b/x/evidence/internal/types/keys.go @@ -12,9 +12,6 @@ const ( // QuerierRoute defines the module's query routing key QuerierRoute = ModuleName - - // DefaultParamspace defines the module's default paramspace name - DefaultParamspace = ModuleName ) // KVStore key prefixes diff --git a/x/evidence/internal/types/params.go b/x/evidence/internal/types/params.go new file mode 100644 index 000000000000..5684786b73f7 --- /dev/null +++ b/x/evidence/internal/types/params.go @@ -0,0 +1,60 @@ +package types + +import ( + "time" + + "github.com/cosmos/cosmos-sdk/x/params" + + "gopkg.in/yaml.v2" +) + +// DONTCOVER + +// Default parameter values +const ( + DefaultParamspace = ModuleName + DefaultMaxEvidenceAge = 60 * 2 * time.Second +) + +// Parameter store keys +var ( + KeyMaxEvidenceAge = []byte("MaxEvidenceAge") + + // The Double Sign Jail period ends at Max Time supported by Amino + // (Dec 31, 9999 - 23:59:59 GMT). + DoubleSignJailEndTime = time.Unix(253402300799, 0) +) + +// Params defines the total set of parameters for the evidence module +type Params struct { + MaxEvidenceAge time.Duration `json:"max_evidence_age" yaml:"max_evidence_age"` +} + +// ParamKeyTable returns the parameter key table. +func ParamKeyTable() params.KeyTable { + return params.NewKeyTable().RegisterParamSet(&Params{}) +} + +func (p Params) MarshalYAML() (interface{}, error) { + bz, err := yaml.Marshal(p) + return string(bz), err +} + +func (p Params) String() string { + out, _ := p.MarshalYAML() + return out.(string) +} + +// ParamSetPairs returns the parameter set pairs. +func (p *Params) ParamSetPairs() params.ParamSetPairs { + return params.ParamSetPairs{ + params.NewParamSetPair(KeyMaxEvidenceAge, &p.MaxEvidenceAge), + } +} + +// DefaultParams returns the default parameters for the evidence module. +func DefaultParams() Params { + return Params{ + MaxEvidenceAge: DefaultMaxEvidenceAge, + } +} diff --git a/x/evidence/internal/types/querier.go b/x/evidence/internal/types/querier.go index af643ee7c276..130d0699de45 100644 --- a/x/evidence/internal/types/querier.go +++ b/x/evidence/internal/types/querier.go @@ -2,6 +2,7 @@ package types // Querier routes for the evidence module const ( + QueryParameters = "parameters" QueryEvidence = "evidence" QueryAllEvidence = "all_evidence" ) diff --git a/x/evidence/module.go b/x/evidence/module.go index a66a35adf36c..aa4129469dab 100644 --- a/x/evidence/module.go +++ b/x/evidence/module.go @@ -158,7 +158,9 @@ func (am AppModule) ExportGenesis(ctx sdk.Context) json.RawMessage { } // BeginBlock executes all ABCI BeginBlock logic respective to the evidence module. -func (AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {} +func (am AppModule) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) { + BeginBlocker(ctx, req, am.keeper) +} // EndBlock executes all ABCI EndBlock logic respective to the evidence module. It // returns no validator updates. diff --git a/x/evidence/spec/05_params.md b/x/evidence/spec/05_params.md new file mode 100644 index 000000000000..ff30153725c1 --- /dev/null +++ b/x/evidence/spec/05_params.md @@ -0,0 +1,7 @@ +# Parameters + +The evidence module contains the following parameters: + +| Key | Type | Example | +| -------------- | ---------------- | -------------- | +| MaxEvidenceAge | string (time ns) | "120000000000" | diff --git a/x/evidence/spec/06_begin_block.md b/x/evidence/spec/06_begin_block.md new file mode 100644 index 000000000000..312e2b0e6d3d --- /dev/null +++ b/x/evidence/spec/06_begin_block.md @@ -0,0 +1,96 @@ +# BeginBlock + +## Evidence Handling + +Tendermint blocks can include +[Evidence](https://github.com/tendermint/tendermint/blob/master/docs/spec/blockchain/blockchain.md#evidence), +which indicates that a validator committed malicious behavior. The relevant information is +forwarded to the application as ABCI Evidence in `abci.RequestBeginBlock` so that +the validator an be accordingly punished. + +### Equivocation + +Currently, the evidence module only handles evidence of type `Equivocation` which is derived from +Tendermint's `ABCIEvidenceTypeDuplicateVote` during `BeginBlock`. + +For some `Equivocation` submitted in `block` to be valid, it must satisfy: + +`Evidence.Timestamp >= block.Timestamp - MaxEvidenceAge` + +Where `Evidence.Timestamp` is the timestamp in the block at height `Evidence.Height` and +`block.Timestamp` is the current block timestamp. + +If valid `Equivocation` evidence is included in a block, the validator's stake is +reduced (slashed) by `SlashFractionDoubleSign`, which is defined by the `x/slashing` module, +of what their stake was when the infraction occurred (rather than when the evidence was discovered). +We want to "follow the stake", i.e. the stake which contributed to the infraction +should be slashed, even if it has since been redelegated or started unbonding. + +In addition, the validator is permanently jailed and tombstoned making it impossible for that +validator to ever re-enter the validator set. + +The `Equivocation` evidence is handled as follows: + +```go +func (k Keeper) HandleDoubleSign(ctx Context, evidence Equivocation) { + consAddr := evidence.GetConsensusAddress() + infractionHeight := evidence.GetHeight() + + // calculate the age of the evidence + blockTime := ctx.BlockHeader().Time + age := blockTime.Sub(evidence.GetTime()) + + // reject evidence we cannot handle + if _, err := k.slashingKeeper.GetPubkey(ctx, consAddr.Bytes()); err != nil { + return + } + + // reject evidence if it is too old + if age > k.MaxEvidenceAge(ctx) { + return + } + + // reject evidence if the validator is already unbonded + validator := k.stakingKeeper.ValidatorByConsAddr(ctx, consAddr) + if validator == nil || validator.IsUnbonded() { + return + } + + // verify the validator has signing info in order to be slashed and tombstoned + if ok := k.slashingKeeper.HasValidatorSigningInfo(ctx, consAddr); !ok { + panic(...) + } + + // reject evidence if the validator is already tombstoned + if k.slashingKeeper.IsTombstoned(ctx, consAddr) { + return + } + + // We need to retrieve the stake distribution which signed the block, so we + // subtract ValidatorUpdateDelay from the evidence height. + // Note, that this *can* result in a negative "distributionHeight", up to + // -ValidatorUpdateDelay, i.e. at the end of the + // pre-genesis block (none) = at the beginning of the genesis block. + // That's fine since this is just used to filter unbonding delegations & redelegations. + distributionHeight := infractionHeight - sdk.ValidatorUpdateDelay + + // Slash validator. The `power` is the int64 power of the validator as provided + // to/by Tendermint. This value is validator.Tokens as sent to Tendermint via + // ABCI, and now received as evidence. The fraction is passed in to separately + // to slash unbonding and rebonding delegations. + k.slashingKeeper.Slash(ctx, consAddr, evidence.GetValidatorPower(), distributionHeight) + + // Jail the validator if not already jailed. This will begin unbonding the + // validator if not already unbonding (tombstoned). + if !validator.IsJailed() { + k.slashingKeeper.Jail(ctx, consAddr) + } + + k.slashingKeeper.JailUntil(ctx, consAddr, types.DoubleSignJailEndTime) + k.slashingKeeper.Tombstone(ctx, consAddr) +} +``` + +Note, the slashing, jailing, and tombstoning calls are delegated through the `x/slashing` module +which emit informative events and finally delegate calls to the `x/staking` module. Documentation +on slashing and jailing can be found in the [x/staking spec](/.././cosmos-sdk/x/staking/spec/02_state_transitions.md) diff --git a/x/evidence/spec/README.md b/x/evidence/spec/README.md index 1f8667b1b7f0..9313dc7616ad 100644 --- a/x/evidence/spec/README.md +++ b/x/evidence/spec/README.md @@ -1,5 +1,15 @@ # Evidence Module Specification +## Table of Contents + + +1. **[Concepts](01_concepts.md)** +2. **[State](02_state.md)** +3. **[Messages](03_messages.md)** +4. **[Events](04_events.md)** +5. **[Params](05_params.md)** +6. **[BeginBlock](06_begin_block.md)** + ## Abstract `x/evidence` is an implementation of a Cosmos SDK module, per [ADR 009](./../../../docs/architecture/adr-009-evidence-module.md), @@ -20,9 +30,3 @@ keeper in order for it to be successfully routed and executed. Each corresponding handler must also fulfill the `Handler` interface contract. The `Handler` for a given `Evidence` type can perform any arbitrary state transitions such as slashing, jailing, and tombstoning. - - -1. **[Concepts](01_concepts.md)** -2. **[State](02_state.md)** -3. **[Messages](03_messages.md)** -4. **[Events](04_events.md)** diff --git a/x/params/keeper_test.go b/x/params/keeper_test.go index 6f66e7fe8e14..7b94204a6207 100644 --- a/x/params/keeper_test.go +++ b/x/params/keeper_test.go @@ -39,7 +39,10 @@ func TestKeeper(t *testing.T) { cdc, ctx, skey, _, keeper := testComponents() store := prefix.NewStore(ctx.KVStore(skey), []byte("test/")) - space := keeper.Subspace("test").WithKeyTable(table) + space := keeper.Subspace("test") + require.False(t, space.HasKeyTable()) + space = space.WithKeyTable(table) + require.True(t, space.HasKeyTable()) // Set params for i, kv := range kvs { diff --git a/x/params/subspace/subspace.go b/x/params/subspace/subspace.go index 673e27e71055..aee65842035b 100644 --- a/x/params/subspace/subspace.go +++ b/x/params/subspace/subspace.go @@ -46,6 +46,11 @@ func NewSubspace(cdc *codec.Codec, key sdk.StoreKey, tkey sdk.StoreKey, name str return } +// HasKeyTable returns if the Subspace has a KeyTable registered. +func (s Subspace) HasKeyTable() bool { + return len(s.table.m) > 0 +} + // WithKeyTable initializes KeyTable and returns modified Subspace func (s Subspace) WithKeyTable(table KeyTable) Subspace { if table.m == nil { diff --git a/x/slashing/abci.go b/x/slashing/abci.go index 74931763f850..c6caeec9b5fd 100644 --- a/x/slashing/abci.go +++ b/x/slashing/abci.go @@ -1,10 +1,7 @@ package slashing import ( - "fmt" - abci "github.com/tendermint/tendermint/abci/types" - tmtypes "github.com/tendermint/tendermint/types" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -18,16 +15,4 @@ func BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock, k Keeper) { for _, voteInfo := range req.LastCommitInfo.GetVotes() { k.HandleValidatorSignature(ctx, voteInfo.Validator.Address, voteInfo.Validator.Power, voteInfo.SignedLastBlock) } - - // Iterate through any newly discovered evidence of infraction - // Slash any validators (and since-unbonded stake within the unbonding period) - // who contributed to valid infractions - for _, evidence := range req.ByzantineValidators { - switch evidence.Type { - case tmtypes.ABCIEvidenceTypeDuplicateVote: - k.HandleDoubleSign(ctx, evidence.Validator.Address, evidence.Height, evidence.Time, evidence.Validator.Power) - default: - k.Logger(ctx).Error(fmt.Sprintf("ignored unknown evidence type: %s", evidence.Type)) - } - } } diff --git a/x/slashing/alias.go b/x/slashing/alias.go index c0107510336e..677228182c0d 100644 --- a/x/slashing/alias.go +++ b/x/slashing/alias.go @@ -23,7 +23,6 @@ const ( RouterKey = types.RouterKey QuerierRoute = types.QuerierRoute DefaultParamspace = types.DefaultParamspace - DefaultMaxEvidenceAge = types.DefaultMaxEvidenceAge DefaultSignedBlocksWindow = types.DefaultSignedBlocksWindow DefaultDowntimeJailDuration = types.DefaultDowntimeJailDuration QueryParameters = types.QueryParameters @@ -77,11 +76,9 @@ var ( ValidatorSigningInfoKey = types.ValidatorSigningInfoKey ValidatorMissedBlockBitArrayKey = types.ValidatorMissedBlockBitArrayKey AddrPubkeyRelationKey = types.AddrPubkeyRelationKey - DoubleSignJailEndTime = types.DoubleSignJailEndTime DefaultMinSignedPerWindow = types.DefaultMinSignedPerWindow DefaultSlashFractionDoubleSign = types.DefaultSlashFractionDoubleSign DefaultSlashFractionDowntime = types.DefaultSlashFractionDowntime - KeyMaxEvidenceAge = types.KeyMaxEvidenceAge KeySignedBlocksWindow = types.KeySignedBlocksWindow KeyMinSignedPerWindow = types.KeyMinSignedPerWindow KeyDowntimeJailDuration = types.KeyDowntimeJailDuration diff --git a/x/slashing/internal/keeper/infractions.go b/x/slashing/internal/keeper/infractions.go index e71ccb7142a8..a10b6f945b3a 100644 --- a/x/slashing/internal/keeper/infractions.go +++ b/x/slashing/internal/keeper/infractions.go @@ -2,7 +2,6 @@ package keeper import ( "fmt" - "time" "github.com/tendermint/tendermint/crypto" @@ -10,107 +9,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/slashing/internal/types" ) -// HandleDoubleSign handles a validator signing two blocks at the same height. -// power: power of the double-signing validator at the height of infraction -func (k Keeper) HandleDoubleSign(ctx sdk.Context, addr crypto.Address, infractionHeight int64, timestamp time.Time, power int64) { - logger := k.Logger(ctx) - - // calculate the age of the evidence - time := ctx.BlockHeader().Time - age := time.Sub(timestamp) - - // fetch the validator public key - consAddr := sdk.ConsAddress(addr) - if _, err := k.GetPubkey(ctx, addr); err != nil { - // Ignore evidence that cannot be handled. - // NOTE: - // We used to panic with: - // `panic(fmt.Sprintf("Validator consensus-address %v not found", consAddr))`, - // but this couples the expectations of the app to both Tendermint and - // the simulator. Both are expected to provide the full range of - // allowable but none of the disallowed evidence types. Instead of - // getting this coordination right, it is easier to relax the - // constraints and ignore evidence that cannot be handled. - return - } - - // Reject evidence if the double-sign is too old - if age > k.MaxEvidenceAge(ctx) { - logger.Info(fmt.Sprintf("Ignored double sign from %s at height %d, age of %d past max age of %d", - consAddr, infractionHeight, age, k.MaxEvidenceAge(ctx))) - return - } - - // Get validator and signing info - validator := k.sk.ValidatorByConsAddr(ctx, consAddr) - if validator == nil || validator.IsUnbonded() { - // Defensive. - // Simulation doesn't take unbonding periods into account, and - // Tendermint might break this assumption at some point. - return - } - - // fetch the validator signing info - signInfo, found := k.GetValidatorSigningInfo(ctx, consAddr) - if !found { - panic(fmt.Sprintf("Expected signing info for validator %s but not found", consAddr)) - } - - // validator is already tombstoned - if signInfo.Tombstoned { - logger.Info(fmt.Sprintf("Ignored double sign from %s at height %d, validator already tombstoned", consAddr, infractionHeight)) - return - } - - // double sign confirmed - logger.Info(fmt.Sprintf("Confirmed double sign from %s at height %d, age of %d", consAddr, infractionHeight, age)) - - // We need to retrieve the stake distribution which signed the block, so we subtract ValidatorUpdateDelay from the evidence height. - // Note that this *can* result in a negative "distributionHeight", up to -ValidatorUpdateDelay, - // i.e. at the end of the pre-genesis block (none) = at the beginning of the genesis block. - // That's fine since this is just used to filter unbonding delegations & redelegations. - distributionHeight := infractionHeight - sdk.ValidatorUpdateDelay - - // get the percentage slash penalty fraction - fraction := k.SlashFractionDoubleSign(ctx) - - // Slash validator - // `power` is the int64 power of the validator as provided to/by - // Tendermint. This value is validator.Tokens as sent to Tendermint via - // ABCI, and now received as evidence. - // The fraction is passed in to separately to slash unbonding and rebonding delegations. - ctx.EventManager().EmitEvent( - sdk.NewEvent( - types.EventTypeSlash, - sdk.NewAttribute(types.AttributeKeyAddress, consAddr.String()), - sdk.NewAttribute(types.AttributeKeyPower, fmt.Sprintf("%d", power)), - sdk.NewAttribute(types.AttributeKeyReason, types.AttributeValueDoubleSign), - ), - ) - k.sk.Slash(ctx, consAddr, distributionHeight, power, fraction) - - // Jail validator if not already jailed - // begin unbonding validator if not already unbonding (tombstone) - if !validator.IsJailed() { - ctx.EventManager().EmitEvent( - sdk.NewEvent( - types.EventTypeSlash, - sdk.NewAttribute(types.AttributeKeyJailed, consAddr.String()), - ), - ) - k.sk.Jail(ctx, consAddr) - } - - // Set tombstoned to be true - signInfo.Tombstoned = true - - // Set jailed until to be forever (max time) - signInfo.JailedUntil = types.DoubleSignJailEndTime - - // Set validator signing info - k.SetValidatorSigningInfo(ctx, consAddr, signInfo) -} - // HandleValidatorSignature handles a validator signature, must be called once per validator per block. func (k Keeper) HandleValidatorSignature(ctx sdk.Context, addr crypto.Address, power int64, signed bool) { logger := k.Logger(ctx) diff --git a/x/slashing/internal/keeper/keeper.go b/x/slashing/internal/keeper/keeper.go index 4b4d28900308..b7a3706369f9 100644 --- a/x/slashing/internal/keeper/keeper.go +++ b/x/slashing/internal/keeper/keeper.go @@ -54,6 +54,34 @@ func (k Keeper) GetPubkey(ctx sdk.Context, address crypto.Address) (crypto.PubKe return pubkey, nil } +// Slash attempts to slash a validator. The slash is delegated to the staking +// module to make the necessary validator changes. +func (k Keeper) Slash(ctx sdk.Context, consAddr sdk.ConsAddress, fraction sdk.Dec, power, distributionHeight int64) { + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeSlash, + sdk.NewAttribute(types.AttributeKeyAddress, consAddr.String()), + sdk.NewAttribute(types.AttributeKeyPower, fmt.Sprintf("%d", power)), + sdk.NewAttribute(types.AttributeKeyReason, types.AttributeValueDoubleSign), + ), + ) + + k.sk.Slash(ctx, consAddr, distributionHeight, power, fraction) +} + +// Jail attempts to jail a validator. The slash is delegated to the staking module +// to make the necessary validator changes. +func (k Keeper) Jail(ctx sdk.Context, consAddr sdk.ConsAddress) { + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeSlash, + sdk.NewAttribute(types.AttributeKeyJailed, consAddr.String()), + ), + ) + + k.sk.Jail(ctx, consAddr) +} + func (k Keeper) setAddrPubkeyRelation(ctx sdk.Context, addr crypto.Address, pubkey crypto.PubKey) { store := ctx.KVStore(k.storeKey) bz := k.cdc.MustMarshalBinaryLengthPrefixed(pubkey) diff --git a/x/slashing/internal/keeper/keeper_test.go b/x/slashing/internal/keeper/keeper_test.go index 36b67c7bbd6c..54b77848a043 100644 --- a/x/slashing/internal/keeper/keeper_test.go +++ b/x/slashing/internal/keeper/keeper_test.go @@ -5,111 +5,12 @@ import ( "time" "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/slashing/internal/types" "github.com/cosmos/cosmos-sdk/x/staking" ) -// ______________________________________________________________ - -// Test that a validator is slashed correctly -// when we discover evidence of infraction -func TestHandleDoubleSign(t *testing.T) { - - // initial setup - ctx, ck, sk, _, keeper := CreateTestInput(t, TestParams()) - // validator added pre-genesis - ctx = ctx.WithBlockHeight(-1) - power := int64(100) - amt := sdk.TokensFromConsensusPower(power) - operatorAddr, val := Addrs[0], Pks[0] - got := staking.NewHandler(sk)(ctx, NewTestMsgCreateValidator(operatorAddr, val, amt)) - require.True(t, got.IsOK()) - staking.EndBlocker(ctx, sk) - require.Equal( - t, ck.GetCoins(ctx, sdk.AccAddress(operatorAddr)), - sdk.NewCoins(sdk.NewCoin(sk.GetParams(ctx).BondDenom, InitTokens.Sub(amt))), - ) - require.Equal(t, amt, sk.Validator(ctx, operatorAddr).GetBondedTokens()) - - // handle a signature to set signing info - keeper.HandleValidatorSignature(ctx, val.Address(), amt.Int64(), true) - - oldTokens := sk.Validator(ctx, operatorAddr).GetTokens() - - // double sign less than max age - keeper.HandleDoubleSign(ctx, val.Address(), 0, time.Unix(0, 0), power) - - // should be jailed - require.True(t, sk.Validator(ctx, operatorAddr).IsJailed()) - - // tokens should be decreased - newTokens := sk.Validator(ctx, operatorAddr).GetTokens() - require.True(t, newTokens.LT(oldTokens)) - - // New evidence - keeper.HandleDoubleSign(ctx, val.Address(), 0, time.Unix(0, 0), power) - - // tokens should be the same (capped slash) - require.True(t, sk.Validator(ctx, operatorAddr).GetTokens().Equal(newTokens)) - - // Jump to past the unbonding period - ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(1, 0).Add(sk.GetParams(ctx).UnbondingTime)}) - - // Still shouldn't be able to unjail - require.Error(t, keeper.Unjail(ctx, operatorAddr)) - - // Should be able to unbond now - del, _ := sk.GetDelegation(ctx, sdk.AccAddress(operatorAddr), operatorAddr) - validator, _ := sk.GetValidator(ctx, operatorAddr) - - totalBond := validator.TokensFromShares(del.GetShares()).TruncateInt() - msgUnbond := staking.NewMsgUndelegate(sdk.AccAddress(operatorAddr), operatorAddr, sdk.NewCoin(sk.GetParams(ctx).BondDenom, totalBond)) - res := staking.NewHandler(sk)(ctx, msgUnbond) - require.True(t, res.IsOK()) -} - -// ______________________________________________________________ - -// Test that a validator is slashed correctly -// when we discover evidence of infraction -func TestPastMaxEvidenceAge(t *testing.T) { - - // initial setup - ctx, ck, sk, _, keeper := CreateTestInput(t, TestParams()) - // validator added pre-genesis - ctx = ctx.WithBlockHeight(-1) - power := int64(100) - amt := sdk.TokensFromConsensusPower(power) - operatorAddr, val := Addrs[0], Pks[0] - got := staking.NewHandler(sk)(ctx, NewTestMsgCreateValidator(operatorAddr, val, amt)) - require.True(t, got.IsOK()) - staking.EndBlocker(ctx, sk) - require.Equal( - t, ck.GetCoins(ctx, sdk.AccAddress(operatorAddr)), - sdk.NewCoins(sdk.NewCoin(sk.GetParams(ctx).BondDenom, InitTokens.Sub(amt))), - ) - require.Equal(t, amt, sk.Validator(ctx, operatorAddr).GetBondedTokens()) - - // handle a signature to set signing info - keeper.HandleValidatorSignature(ctx, val.Address(), power, true) - - ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(1, 0).Add(keeper.MaxEvidenceAge(ctx))}) - - oldPower := sk.Validator(ctx, operatorAddr).GetConsensusPower() - - // double sign past max age - keeper.HandleDoubleSign(ctx, val.Address(), 0, time.Unix(0, 0), power) - - // should still be bonded - require.True(t, sk.Validator(ctx, operatorAddr).IsBonded()) - - // should still have same power - require.Equal(t, oldPower, sk.Validator(ctx, operatorAddr).GetConsensusPower()) -} - // Test a new validator entering the validator set // Ensure that SigningInfo.StartHeight is set correctly // and that they are not immediately jailed diff --git a/x/slashing/internal/keeper/params.go b/x/slashing/internal/keeper/params.go index 124588dc7f6c..82fe991cccc1 100644 --- a/x/slashing/internal/keeper/params.go +++ b/x/slashing/internal/keeper/params.go @@ -7,12 +7,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/slashing/internal/types" ) -// MaxEvidenceAge - max age for evidence -func (k Keeper) MaxEvidenceAge(ctx sdk.Context) (res time.Duration) { - k.paramspace.Get(ctx, types.KeyMaxEvidenceAge, &res) - return -} - // SignedBlocksWindow - sliding window for downtime slashing func (k Keeper) SignedBlocksWindow(ctx sdk.Context) (res int64) { k.paramspace.Get(ctx, types.KeySignedBlocksWindow, &res) diff --git a/x/slashing/internal/keeper/signing_info.go b/x/slashing/internal/keeper/signing_info.go index ebb61e732880..1162c258f35a 100644 --- a/x/slashing/internal/keeper/signing_info.go +++ b/x/slashing/internal/keeper/signing_info.go @@ -1,6 +1,8 @@ package keeper import ( + "time" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/slashing/internal/types" ) @@ -19,6 +21,13 @@ func (k Keeper) GetValidatorSigningInfo(ctx sdk.Context, address sdk.ConsAddress return } +// HasValidatorSigningInfo returns if a given validator has signing information +// persited. +func (k Keeper) HasValidatorSigningInfo(ctx sdk.Context, consAddr sdk.ConsAddress) bool { + _, ok := k.GetValidatorSigningInfo(ctx, consAddr) + return ok +} + // SetValidatorSigningInfo sets the validator signing info to a consensus address key func (k Keeper) SetValidatorSigningInfo(ctx sdk.Context, address sdk.ConsAddress, info types.ValidatorSigningInfo) { store := ctx.KVStore(k.storeKey) @@ -77,6 +86,44 @@ func (k Keeper) IterateValidatorMissedBlockBitArray(ctx sdk.Context, } } +// JailUntil attempts to set a validator's JailedUntil attribute in its signing +// info. It will panic if the signing info does not exist for the validator. +func (k Keeper) JailUntil(ctx sdk.Context, consAddr sdk.ConsAddress, jailTime time.Time) { + signInfo, ok := k.GetValidatorSigningInfo(ctx, consAddr) + if !ok { + panic("cannot jail validator that does not have any signing information") + } + + signInfo.JailedUntil = jailTime + k.SetValidatorSigningInfo(ctx, consAddr, signInfo) +} + +// Tombstone attempts to tombstone a validator. It will panic if signing info for +// the given validator does not exist. +func (k Keeper) Tombstone(ctx sdk.Context, consAddr sdk.ConsAddress) { + signInfo, ok := k.GetValidatorSigningInfo(ctx, consAddr) + if !ok { + panic("cannot tombstone validator that does not have any signing information") + } + + if signInfo.Tombstoned { + panic("cannot tombstone validator that is already tombstoned") + } + + signInfo.Tombstoned = true + k.SetValidatorSigningInfo(ctx, consAddr, signInfo) +} + +// IsTombstoned returns if a given validator by consensus address is tombstoned. +func (k Keeper) IsTombstoned(ctx sdk.Context, consAddr sdk.ConsAddress) bool { + signInfo, ok := k.GetValidatorSigningInfo(ctx, consAddr) + if !ok { + return false + } + + return signInfo.Tombstoned +} + // SetValidatorMissedBlockBitArray sets the bit that checks if the validator has // missed a block in the current window func (k Keeper) SetValidatorMissedBlockBitArray(ctx sdk.Context, address sdk.ConsAddress, index int64, missed bool) { diff --git a/x/slashing/internal/keeper/signing_info_test.go b/x/slashing/internal/keeper/signing_info_test.go index e7d302f48194..7d9e7c56e526 100644 --- a/x/slashing/internal/keeper/signing_info_test.go +++ b/x/slashing/internal/keeper/signing_info_test.go @@ -39,3 +39,44 @@ func TestGetSetValidatorMissedBlockBitArray(t *testing.T) { missed = keeper.GetValidatorMissedBlockBitArray(ctx, sdk.ConsAddress(Addrs[0]), 0) require.True(t, missed) // now should be missed } + +func TestTombstoned(t *testing.T) { + ctx, _, _, _, keeper := CreateTestInput(t, types.DefaultParams()) + require.Panics(t, func() { keeper.Tombstone(ctx, sdk.ConsAddress(Addrs[0])) }) + require.False(t, keeper.IsTombstoned(ctx, sdk.ConsAddress(Addrs[0]))) + + newInfo := types.NewValidatorSigningInfo( + sdk.ConsAddress(Addrs[0]), + int64(4), + int64(3), + time.Unix(2, 0), + false, + int64(10), + ) + keeper.SetValidatorSigningInfo(ctx, sdk.ConsAddress(Addrs[0]), newInfo) + + require.False(t, keeper.IsTombstoned(ctx, sdk.ConsAddress(Addrs[0]))) + keeper.Tombstone(ctx, sdk.ConsAddress(Addrs[0])) + require.True(t, keeper.IsTombstoned(ctx, sdk.ConsAddress(Addrs[0]))) + require.Panics(t, func() { keeper.Tombstone(ctx, sdk.ConsAddress(Addrs[0])) }) +} + +func TestJailUntil(t *testing.T) { + ctx, _, _, _, keeper := CreateTestInput(t, types.DefaultParams()) + require.Panics(t, func() { keeper.JailUntil(ctx, sdk.ConsAddress(Addrs[0]), time.Now()) }) + + newInfo := types.NewValidatorSigningInfo( + sdk.ConsAddress(Addrs[0]), + int64(4), + int64(3), + time.Unix(2, 0), + false, + int64(10), + ) + keeper.SetValidatorSigningInfo(ctx, sdk.ConsAddress(Addrs[0]), newInfo) + keeper.JailUntil(ctx, sdk.ConsAddress(Addrs[0]), time.Unix(253402300799, 0).UTC()) + + info, ok := keeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(Addrs[0])) + require.True(t, ok) + require.Equal(t, time.Unix(253402300799, 0).UTC(), info.JailedUntil) +} diff --git a/x/slashing/internal/types/genesis.go b/x/slashing/internal/types/genesis.go index 4aadb9aaaf6d..42089eea5191 100644 --- a/x/slashing/internal/types/genesis.go +++ b/x/slashing/internal/types/genesis.go @@ -66,11 +66,6 @@ func ValidateGenesis(data GenesisState) error { return fmt.Errorf("min signed per window should be less than or equal to one and greater than zero, is %s", minSign.String()) } - maxEvidence := data.Params.MaxEvidenceAge - if maxEvidence < 1*time.Minute { - return fmt.Errorf("max evidence age must be at least 1 minute, is %s", maxEvidence.String()) - } - downtimeJail := data.Params.DowntimeJailDuration if downtimeJail < 1*time.Minute { return fmt.Errorf("downtime unblond duration must be at least 1 minute, is %s", downtimeJail.String()) diff --git a/x/slashing/internal/types/params.go b/x/slashing/internal/types/params.go index 20892dd8224f..4817ac5ee3ef 100644 --- a/x/slashing/internal/types/params.go +++ b/x/slashing/internal/types/params.go @@ -11,14 +11,11 @@ import ( // Default parameter namespace const ( DefaultParamspace = ModuleName - DefaultMaxEvidenceAge = 60 * 2 * time.Second DefaultSignedBlocksWindow = int64(100) DefaultDowntimeJailDuration = 60 * 10 * time.Second ) -// The Double Sign Jail period ends at Max Time supported by Amino (Dec 31, 9999 - 23:59:59 GMT) var ( - DoubleSignJailEndTime = time.Unix(253402300799, 0) DefaultMinSignedPerWindow = sdk.NewDecWithPrec(5, 1) DefaultSlashFractionDoubleSign = sdk.NewDec(1).Quo(sdk.NewDec(20)) DefaultSlashFractionDowntime = sdk.NewDec(1).Quo(sdk.NewDec(100)) @@ -26,7 +23,6 @@ var ( // Parameter store keys var ( - KeyMaxEvidenceAge = []byte("MaxEvidenceAge") KeySignedBlocksWindow = []byte("SignedBlocksWindow") KeyMinSignedPerWindow = []byte("MinSignedPerWindow") KeyDowntimeJailDuration = []byte("DowntimeJailDuration") @@ -41,7 +37,6 @@ func ParamKeyTable() params.KeyTable { // Params - used for initializing default parameter for slashing at genesis type Params struct { - MaxEvidenceAge time.Duration `json:"max_evidence_age" yaml:"max_evidence_age"` SignedBlocksWindow int64 `json:"signed_blocks_window" yaml:"signed_blocks_window"` MinSignedPerWindow sdk.Dec `json:"min_signed_per_window" yaml:"min_signed_per_window"` DowntimeJailDuration time.Duration `json:"downtime_jail_duration" yaml:"downtime_jail_duration"` @@ -50,12 +45,12 @@ type Params struct { } // NewParams creates a new Params object -func NewParams(maxEvidenceAge time.Duration, signedBlocksWindow int64, - minSignedPerWindow sdk.Dec, downtimeJailDuration time.Duration, - slashFractionDoubleSign, slashFractionDowntime sdk.Dec) Params { +func NewParams( + signedBlocksWindow int64, minSignedPerWindow sdk.Dec, downtimeJailDuration time.Duration, + slashFractionDoubleSign, slashFractionDowntime sdk.Dec, +) Params { return Params{ - MaxEvidenceAge: maxEvidenceAge, SignedBlocksWindow: signedBlocksWindow, MinSignedPerWindow: minSignedPerWindow, DowntimeJailDuration: downtimeJailDuration, @@ -67,12 +62,11 @@ func NewParams(maxEvidenceAge time.Duration, signedBlocksWindow int64, // String implements the stringer interface for Params func (p Params) String() string { return fmt.Sprintf(`Slashing Params: - MaxEvidenceAge: %s SignedBlocksWindow: %d MinSignedPerWindow: %s DowntimeJailDuration: %s SlashFractionDoubleSign: %s - SlashFractionDowntime: %s`, p.MaxEvidenceAge, + SlashFractionDowntime: %s`, p.SignedBlocksWindow, p.MinSignedPerWindow, p.DowntimeJailDuration, p.SlashFractionDoubleSign, p.SlashFractionDowntime) @@ -81,7 +75,6 @@ func (p Params) String() string { // ParamSetPairs - Implements params.ParamSet func (p *Params) ParamSetPairs() params.ParamSetPairs { return params.ParamSetPairs{ - params.NewParamSetPair(KeyMaxEvidenceAge, &p.MaxEvidenceAge), params.NewParamSetPair(KeySignedBlocksWindow, &p.SignedBlocksWindow), params.NewParamSetPair(KeyMinSignedPerWindow, &p.MinSignedPerWindow), params.NewParamSetPair(KeyDowntimeJailDuration, &p.DowntimeJailDuration), @@ -93,7 +86,7 @@ func (p *Params) ParamSetPairs() params.ParamSetPairs { // DefaultParams defines the parameters for this module func DefaultParams() Params { return NewParams( - DefaultMaxEvidenceAge, DefaultSignedBlocksWindow, DefaultMinSignedPerWindow, - DefaultDowntimeJailDuration, DefaultSlashFractionDoubleSign, DefaultSlashFractionDowntime, + DefaultSignedBlocksWindow, DefaultMinSignedPerWindow, DefaultDowntimeJailDuration, + DefaultSlashFractionDoubleSign, DefaultSlashFractionDowntime, ) } diff --git a/x/slashing/simulation/genesis.go b/x/slashing/simulation/genesis.go index dfe9e813fe16..a26a626642b7 100644 --- a/x/slashing/simulation/genesis.go +++ b/x/slashing/simulation/genesis.go @@ -82,8 +82,8 @@ func RandomizedGenState(simState *module.SimulationState) { ) params := types.NewParams( - simState.UnbondTime, signedBlocksWindow, minSignedPerWindow, - downtimeJailDuration, slashFractionDoubleSign, slashFractionDowntime, + signedBlocksWindow, minSignedPerWindow, downtimeJailDuration, + slashFractionDoubleSign, slashFractionDowntime, ) slashingGenesis := types.NewGenesisState(params, nil, nil) diff --git a/x/slashing/spec/04_begin_block.md b/x/slashing/spec/04_begin_block.md index 18d6cbcc42f6..f99aa0d8a50f 100644 --- a/x/slashing/spec/04_begin_block.md +++ b/x/slashing/spec/04_begin_block.md @@ -1,93 +1,12 @@ # BeginBlock -## Evidence Handling - -Tendermint blocks can include -[Evidence](https://github.com/tendermint/tendermint/blob/master/docs/spec/blockchain/blockchain.md#evidence), which indicates that a validator committed malicious -behavior. The relevant information is forwarded to the application as ABCI Evidence -in `abci.RequestBeginBlock` so that the validator an be accordingly punished. - -For some `Evidence` submitted in `block` to be valid, it must satisfy: - -`Evidence.Timestamp >= block.Timestamp - MaxEvidenceAge` - -Where `Evidence.Timestamp` is the timestamp in the block at height -`Evidence.Height` and `block.Timestamp` is the current block timestamp. - -If valid evidence is included in a block, the validator's stake is reduced by -some penalty (`SlashFractionDoubleSign` for equivocation) of what their stake was -when the infraction occurred (rather than when the evidence was discovered). We -want to "follow the stake", i.e. the stake which contributed to the infraction -should be slashed, even if it has since been redelegated or started unbonding. - -We first need to loop through the unbondings and redelegations from the slashed -validator and track how much stake has since moved: - -```go -slashAmountUnbondings := 0 -slashAmountRedelegations := 0 - -unbondings := getUnbondings(validator.Address) -for unbond in unbondings { - - if was not bonded before evidence.Height or started unbonding before unbonding period ago { - continue - } - - burn := unbond.InitialTokens * SLASH_PROPORTION - slashAmountUnbondings += burn - - unbond.Tokens = max(0, unbond.Tokens - burn) -} - -// only care if source gets slashed because we're already bonded to destination -// so if destination validator gets slashed our delegation just has same shares -// of smaller pool. -redels := getRedelegationsBySource(validator.Address) -for redel in redels { - - if was not bonded before evidence.Height or started redelegating before unbonding period ago { - continue - } - - burn := redel.InitialTokens * SLASH_PROPORTION - slashAmountRedelegations += burn - - amount := unbondFromValidator(redel.Destination, burn) - destroy(amount) -} -``` - -We then slash the validator and tombstone them: - -``` -curVal := validator -oldVal := loadValidator(evidence.Height, evidence.Address) - -slashAmount := SLASH_PROPORTION * oldVal.Shares -slashAmount -= slashAmountUnbondings -slashAmount -= slashAmountRedelegations - -curVal.Shares = max(0, curVal.Shares - slashAmount) - -signInfo = SigningInfo.Get(val.Address) -signInfo.JailedUntil = MAX_TIME -signInfo.Tombstoned = true -SigningInfo.Set(val.Address, signInfo) -``` - -This ensures that offending validators are punished the same amount whether they -act as a single validator with X stake or as N validators with collectively X -stake. The amount slashed for all double signature infractions committed within a -single slashing period is capped as described in [overview.md](overview.md) under Tombstone Caps. - ## Liveness Tracking At the beginning of each block, we update the `ValidatorSigningInfo` for each validator and check if they've crossed below the liveness threshold over a sliding window. This sliding window is defined by `SignedBlocksWindow` and the index in this window is determined by `IndexOffset` found in the validator's -`ValidatorSigningInfo`. For each block processed, the `IndexOffset` is incrimented +`ValidatorSigningInfo`. For each block processed, the `IndexOffset` is incremented regardless if the validator signed or not. Once the index is determined, the `MissedBlocksBitArray` and `MissedBlocksCounter` are updated accordingly. diff --git a/x/slashing/spec/06_events.md b/x/slashing/spec/06_events.md index 7891ebfe5a39..8d4e616c76cd 100644 --- a/x/slashing/spec/06_events.md +++ b/x/slashing/spec/06_events.md @@ -5,16 +5,16 @@ The slashing module emits the following events/tags: ## BeginBlocker | Type | Attribute Key | Attribute Value | -|-------|---------------|-----------------------------| +| ----- | ------------- | --------------------------- | | slash | address | {validatorConsensusAddress} | | slash | power | {validatorPower} | | slash | reason | {slashReason} | | slash | jailed [0] | {validatorConsensusAddress} | -- [0] Only included if the validator is jailed. +- [0] Only included if the validator is jailed. | Type | Attribute Key | Attribute Value | -|----------|---------------|-----------------------------| +| -------- | ------------- | --------------------------- | | liveness | address | {validatorConsensusAddress} | | liveness | missed_blocks | {missedBlocksCounter} | | liveness | height | {blockHeight} | @@ -24,7 +24,7 @@ The slashing module emits the following events/tags: ### MsgUnjail | Type | Attribute Key | Attribute Value | -|---------|---------------|-----------------| +| ------- | ------------- | --------------- | | message | module | slashing | | message | action | unjail | | message | sender | {senderAddress} | diff --git a/x/slashing/spec/08_params.md b/x/slashing/spec/08_params.md index b9dfca051628..c68188eb4b7c 100644 --- a/x/slashing/spec/08_params.md +++ b/x/slashing/spec/08_params.md @@ -3,8 +3,7 @@ The slashing module contains the following parameters: | Key | Type | Example | -|-------------------------|------------------|------------------------| -| MaxEvidenceAge | string (time ns) | "120000000000" | +| ----------------------- | ---------------- | ---------------------- | | SignedBlocksWindow | string (int64) | "100" | | MinSignedPerWindow | string (dec) | "0.500000000000000000" | | DowntimeJailDuration | string (time ns) | "600000000000" | diff --git a/x/slashing/spec/README.md b/x/slashing/spec/README.md index fbcb704fff6f..0f0111433c31 100644 --- a/x/slashing/spec/README.md +++ b/x/slashing/spec/README.md @@ -9,6 +9,7 @@ The slashing module enables Cosmos SDK-based blockchains to disincentivize any a by a protocol-recognized actor with value at stake by penalizing them ("slashing"). Penalties may include, but are not limited to: + - Burning some amount of their stake - Removing their ability to vote on future blocks for a period of time. @@ -35,4 +36,3 @@ This module will be used by the Cosmos Hub, the first hub in the Cosmos ecosyste 7. **[Staking Tombstone](07_tombstone.md)** - [Abstract](07_tombstone.md#abstract) 8. **[Parameters](08_params.md)** - From b862e271a12b07907e9d804d78739d60222a1f4d Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Tue, 3 Dec 2019 04:24:12 -0500 Subject: [PATCH 006/529] Allow node to restart after halt config trigger (#5352) * Allow node to restart after halt config trigger * Update godoc * Update documentation on halt config --- CHANGELOG.md | 2 ++ baseapp/abci.go | 36 ++++++++++++++++++------------------ server/config/config.go | 6 ++---- server/config/toml.go | 6 ++---- 4 files changed, 24 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d5ed05db7416..c7783efc23de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -196,6 +196,8 @@ to detail this new feature and how state transitions occur. * (keys) Fix ledger custom coin type support bug * (x/gov) [\#5107](https://github.com/cosmos/cosmos-sdk/pull/5107) Sum validator operator's all voting power when tally votes * (rest) [\#5212](https://github.com/cosmos/cosmos-sdk/issues/5212) Fix pagination in the `/gov/proposals` handler. +* (baseapp) [\#5350](https://github.com/cosmos/cosmos-sdk/issues/5350) Allow a node to restart successfully after a `halt-height` or `halt-time` + has been triggered. ## [v0.37.4] - 2019-11-04 diff --git a/baseapp/abci.go b/baseapp/abci.go index ef8c71d4222a..e93b7c56c2c9 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -215,24 +215,6 @@ func (app *BaseApp) DeliverTx(req abci.RequestDeliverTx) (res abci.ResponseDeliv func (app *BaseApp) Commit() (res abci.ResponseCommit) { header := app.deliverState.ctx.BlockHeader() - var halt bool - - switch { - case app.haltHeight > 0 && uint64(header.Height) >= app.haltHeight: - halt = true - - case app.haltTime > 0 && header.Time.Unix() >= int64(app.haltTime): - halt = true - } - - if halt { - app.halt() - - // Note: State is not actually committed when halted. Logs from Tendermint - // can be ignored. - return abci.ResponseCommit{} - } - // Write the DeliverTx state which is cache-wrapped and commit the MultiStore. // The write to the DeliverTx state writes all state transitions to the root // MultiStore (app.cms) so when Commit() is called is persists those values. @@ -249,6 +231,24 @@ func (app *BaseApp) Commit() (res abci.ResponseCommit) { // empty/reset the deliver state app.deliverState = nil + var halt bool + + switch { + case app.haltHeight > 0 && uint64(header.Height) >= app.haltHeight: + halt = true + + case app.haltTime > 0 && header.Time.Unix() >= int64(app.haltTime): + halt = true + } + + if halt { + // Halt the binary and allow Tendermint to receive the ResponseCommit + // response with the commit ID hash. This will allow the node to successfully + // restart and process blocks assuming the halt configuration has been + // reset or moved to a more distant value. + app.halt() + } + return abci.ResponseCommit{ Data: commitID.Hash, } diff --git a/server/config/config.go b/server/config/config.go index fc9ead54b466..9752ae85273a 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -22,16 +22,14 @@ type BaseConfig struct { // HaltHeight contains a non-zero block height at which a node will gracefully // halt and shutdown that can be used to assist upgrades and testing. // - // Note: State will not be committed on the corresponding height and any logs - // indicating such can be safely ignored. + // Note: Commitment of state will be attempted on the corresponding block. HaltHeight uint64 `mapstructure:"halt-height"` // HaltTime contains a non-zero minimum block time (in Unix seconds) at which // a node will gracefully halt and shutdown that can be used to assist // upgrades and testing. // - // Note: State will not be committed on the corresponding height and any logs - // indicating such can be safely ignored. + // Note: Commitment of state will be attempted on the corresponding block. HaltTime uint64 `mapstructure:"halt-time"` // InterBlockCache enables inter-block caching. diff --git a/server/config/toml.go b/server/config/toml.go index c0e27c69c809..0463d26a93fb 100644 --- a/server/config/toml.go +++ b/server/config/toml.go @@ -21,16 +21,14 @@ minimum-gas-prices = "{{ .BaseConfig.MinGasPrices }}" # HaltHeight contains a non-zero block height at which a node will gracefully # halt and shutdown that can be used to assist upgrades and testing. # -# Note: State will not be committed on the corresponding height and any logs -# indicating such can be safely ignored. +# Note: Commitment of state will be attempted on the corresponding block. halt-height = {{ .BaseConfig.HaltHeight }} # HaltTime contains a non-zero minimum block time (in Unix seconds) at which # a node will gracefully halt and shutdown that can be used to assist upgrades # and testing. # -# Note: State will not be committed on the corresponding height and any logs -# indicating such can be safely ignored. +# Note: Commitment of state will be attempted on the corresponding block. halt-time = {{ .BaseConfig.HaltTime }} # InterBlockCache enables inter-block caching. From b9c40ea2b6c6113f940993d1c3251baa5dc14b16 Mon Sep 17 00:00:00 2001 From: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Date: Tue, 3 Dec 2019 12:14:18 +0100 Subject: [PATCH 007/529] fix MsgEditValidator JSON tag (#5342) * add json tag to MsgEditValidator; closes #5336 * changelog * Apply suggestions from code review Co-Authored-By: Alessio Treglia * format * changelog minor fix --- CHANGELOG.md | 1 + x/staking/legacy/v0_36/types.go | 3 +- x/staking/legacy/v0_38/types.go | 2 +- x/staking/types/msg.go | 84 +++++++++++++++++++++------------ 4 files changed, 58 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c7783efc23de..7148e122122b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -83,6 +83,7 @@ if the provided arguments are invalid. * (rest) [\#4783](https://github.com/cosmos/cosmos-sdk/issues/4783) The balance field in the DelegationResponse type is now sdk.Coin instead of sdk.Int * (x/auth) [\#5006](https://github.com/cosmos/cosmos-sdk/pull/5006) The gas required to pass the `AnteHandler` has increased significantly due to modular `AnteHandler` support. Increase GasLimit accordingly. +* (rest) [\#5336](https://github.com/cosmos/cosmos-sdk/issues/5336) `MsgEditValidator` uses `description` instead of `Description` as a JSON key. ### Features diff --git a/x/staking/legacy/v0_36/types.go b/x/staking/legacy/v0_36/types.go index b5edcc04864c..1e0ff71bd8f8 100644 --- a/x/staking/legacy/v0_36/types.go +++ b/x/staking/legacy/v0_36/types.go @@ -5,10 +5,11 @@ package v0_36 import ( "time" + "github.com/tendermint/tendermint/crypto" + "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" v034staking "github.com/cosmos/cosmos-sdk/x/staking/legacy/v0_34" - "github.com/tendermint/tendermint/crypto" ) const ( diff --git a/x/staking/legacy/v0_38/types.go b/x/staking/legacy/v0_38/types.go index 3b21d8f9cc0b..88bce2c5c505 100644 --- a/x/staking/legacy/v0_38/types.go +++ b/x/staking/legacy/v0_38/types.go @@ -5,9 +5,9 @@ package v0_38 import ( "time" - "github.com/cosmos/cosmos-sdk/codec" "github.com/tendermint/tendermint/crypto" + "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" v034staking "github.com/cosmos/cosmos-sdk/x/staking/legacy/v0_34" v036staking "github.com/cosmos/cosmos-sdk/x/staking/legacy/v0_36" diff --git a/x/staking/types/msg.go b/x/staking/types/msg.go index 6be3587865da..1efe19530de9 100644 --- a/x/staking/types/msg.go +++ b/x/staking/types/msg.go @@ -42,7 +42,8 @@ type msgCreateValidatorJSON struct { Value sdk.Coin `json:"value" yaml:"value"` } -// Default way to create validator. Delegator address and validator address are the same +// NewMsgCreateValidator creates a new MsgCreateValidator instance. +// Delegator address and validator address are the same. func NewMsgCreateValidator( valAddr sdk.ValAddress, pubKey crypto.PubKey, selfDelegation sdk.Coin, description Description, commission CommissionRates, minSelfDelegation sdk.Int, @@ -59,18 +60,21 @@ func NewMsgCreateValidator( } } -//nolint +// Route implements the sdk.Msg interface. func (msg MsgCreateValidator) Route() string { return RouterKey } -func (msg MsgCreateValidator) Type() string { return "create_validator" } -// Return address(es) that must sign over msg.GetSignBytes() +// Type implements the sdk.Msg interface. +func (msg MsgCreateValidator) Type() string { return "create_validator" } + +// GetSigners implements the sdk.Msg interface. It returns the address(es) that +// must sign over msg.GetSignBytes(). +// If the validator address is not same as delegator's, then the validator must +// sign the msg as well. func (msg MsgCreateValidator) GetSigners() []sdk.AccAddress { // delegator is first signer so delegator pays fees addrs := []sdk.AccAddress{msg.DelegatorAddress} if !bytes.Equal(msg.DelegatorAddress.Bytes(), msg.ValidatorAddress.Bytes()) { - // if validator addr is not same as delegator addr, validator must sign - // msg as well addrs = append(addrs, sdk.AccAddress(msg.ValidatorAddress)) } return addrs @@ -113,7 +117,7 @@ func (msg *MsgCreateValidator) UnmarshalJSON(bz []byte) error { return nil } -// custom marshal yaml function due to consensus pubkey +// MarshalYAML implements a custom marshal yaml function due to consensus pubkey. func (msg MsgCreateValidator) MarshalYAML() (interface{}, error) { bs, err := yaml.Marshal(struct { Description Description @@ -146,7 +150,7 @@ func (msg MsgCreateValidator) GetSignBytes() []byte { return sdk.MustSortJSON(bz) } -// quick validity check +// ValidateBasic implements the sdk.Msg interface. func (msg MsgCreateValidator) ValidateBasic() sdk.Error { // note that unmarshaling from bech32 ensures either empty or valid if msg.DelegatorAddress.Empty() { @@ -182,7 +186,7 @@ func (msg MsgCreateValidator) ValidateBasic() sdk.Error { // MsgEditValidator - struct for editing a validator type MsgEditValidator struct { - Description + Description Description `json:"description" yaml:"description"` ValidatorAddress sdk.ValAddress `json:"address" yaml:"address"` // We pass a reference to the new commission rate and min self delegation as it's not mandatory to @@ -194,6 +198,7 @@ type MsgEditValidator struct { MinSelfDelegation *sdk.Int `json:"min_self_delegation" yaml:"min_self_delegation"` } +// NewMsgEditValidator creates a new MsgEditValidator instance func NewMsgEditValidator(valAddr sdk.ValAddress, description Description, newRate *sdk.Dec, newMinSelfDelegation *sdk.Int) MsgEditValidator { return MsgEditValidator{ Description: description, @@ -203,20 +208,24 @@ func NewMsgEditValidator(valAddr sdk.ValAddress, description Description, newRat } } -//nolint +// Route implements the sdk.Msg interface. func (msg MsgEditValidator) Route() string { return RouterKey } -func (msg MsgEditValidator) Type() string { return "edit_validator" } + +// Type implements the sdk.Msg interface. +func (msg MsgEditValidator) Type() string { return "edit_validator" } + +// GetSigners implements the sdk.Msg interface. func (msg MsgEditValidator) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{sdk.AccAddress(msg.ValidatorAddress)} } -// get the bytes for the message signer to sign on +// GetSignBytes implements the sdk.Msg interface. func (msg MsgEditValidator) GetSignBytes() []byte { bz := ModuleCdc.MustMarshalJSON(msg) return sdk.MustSortJSON(bz) } -// quick validity check +// ValidateBasic implements the sdk.Msg interface. func (msg MsgEditValidator) ValidateBasic() sdk.Error { if msg.ValidatorAddress.Empty() { return sdk.NewError(DefaultCodespace, CodeInvalidInput, "nil validator address") @@ -246,6 +255,7 @@ type MsgDelegate struct { Amount sdk.Coin `json:"amount" yaml:"amount"` } +// NewMsgDelegate creates a new MsgDelegate instance. func NewMsgDelegate(delAddr sdk.AccAddress, valAddr sdk.ValAddress, amount sdk.Coin) MsgDelegate { return MsgDelegate{ DelegatorAddress: delAddr, @@ -254,20 +264,24 @@ func NewMsgDelegate(delAddr sdk.AccAddress, valAddr sdk.ValAddress, amount sdk.C } } -//nolint +// Route implements the sdk.Msg interface. func (msg MsgDelegate) Route() string { return RouterKey } -func (msg MsgDelegate) Type() string { return "delegate" } + +// Type implements the sdk.Msg interface. +func (msg MsgDelegate) Type() string { return "delegate" } + +// GetSigners implements the sdk.Msg interface. func (msg MsgDelegate) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.DelegatorAddress} } -// get the bytes for the message signer to sign on +// GetSignBytes implements the sdk.Msg interface. func (msg MsgDelegate) GetSignBytes() []byte { bz := ModuleCdc.MustMarshalJSON(msg) return sdk.MustSortJSON(bz) } -// quick validity check +// ValidateBasic implements the sdk.Msg interface. func (msg MsgDelegate) ValidateBasic() sdk.Error { if msg.DelegatorAddress.Empty() { return ErrNilDelegatorAddr(DefaultCodespace) @@ -283,7 +297,7 @@ func (msg MsgDelegate) ValidateBasic() sdk.Error { //______________________________________________________________________ -// MsgDelegate - struct for bonding transactions +// MsgBeginRedelegate defines the attributes of a bonding transaction. type MsgBeginRedelegate struct { DelegatorAddress sdk.AccAddress `json:"delegator_address" yaml:"delegator_address"` ValidatorSrcAddress sdk.ValAddress `json:"validator_src_address" yaml:"validator_src_address"` @@ -291,9 +305,10 @@ type MsgBeginRedelegate struct { Amount sdk.Coin `json:"amount" yaml:"amount"` } -func NewMsgBeginRedelegate(delAddr sdk.AccAddress, valSrcAddr, - valDstAddr sdk.ValAddress, amount sdk.Coin) MsgBeginRedelegate { - +// NewMsgBeginRedelegate creates a new MsgBeginRedelegate instance. +func NewMsgBeginRedelegate( + delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress, amount sdk.Coin, +) MsgBeginRedelegate { return MsgBeginRedelegate{ DelegatorAddress: delAddr, ValidatorSrcAddress: valSrcAddr, @@ -302,20 +317,24 @@ func NewMsgBeginRedelegate(delAddr sdk.AccAddress, valSrcAddr, } } -//nolint +// Route implements the sdk.Msg interface. func (msg MsgBeginRedelegate) Route() string { return RouterKey } -func (msg MsgBeginRedelegate) Type() string { return "begin_redelegate" } + +// Type implements the sdk.Msg interface +func (msg MsgBeginRedelegate) Type() string { return "begin_redelegate" } + +// GetSigners implements the sdk.Msg interface func (msg MsgBeginRedelegate) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.DelegatorAddress} } -// get the bytes for the message signer to sign on +// GetSignBytes implements the sdk.Msg interface. func (msg MsgBeginRedelegate) GetSignBytes() []byte { bz := ModuleCdc.MustMarshalJSON(msg) return sdk.MustSortJSON(bz) } -// quick validity check +// ValidateBasic implements the sdk.Msg interface. func (msg MsgBeginRedelegate) ValidateBasic() sdk.Error { if msg.DelegatorAddress.Empty() { return ErrNilDelegatorAddr(DefaultCodespace) @@ -339,6 +358,7 @@ type MsgUndelegate struct { Amount sdk.Coin `json:"amount" yaml:"amount"` } +// NewMsgUndelegate creates a new MsgUndelegate instance. func NewMsgUndelegate(delAddr sdk.AccAddress, valAddr sdk.ValAddress, amount sdk.Coin) MsgUndelegate { return MsgUndelegate{ DelegatorAddress: delAddr, @@ -347,18 +367,22 @@ func NewMsgUndelegate(delAddr sdk.AccAddress, valAddr sdk.ValAddress, amount sdk } } -//nolint -func (msg MsgUndelegate) Route() string { return RouterKey } -func (msg MsgUndelegate) Type() string { return "begin_unbonding" } +// Route implements the sdk.Msg interface. +func (msg MsgUndelegate) Route() string { return RouterKey } + +// Type implements the sdk.Msg interface. +func (msg MsgUndelegate) Type() string { return "begin_unbonding" } + +// GetSigners implements the sdk.Msg interface. func (msg MsgUndelegate) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.DelegatorAddress} } -// get the bytes for the message signer to sign on +// GetSignBytes implements the sdk.Msg interface. func (msg MsgUndelegate) GetSignBytes() []byte { bz := ModuleCdc.MustMarshalJSON(msg) return sdk.MustSortJSON(bz) } -// quick validity check +// ValidateBasic implements the sdk.Msg interface. func (msg MsgUndelegate) ValidateBasic() sdk.Error { if msg.DelegatorAddress.Empty() { return ErrNilDelegatorAddr(DefaultCodespace) From 202cb9be0bc37570741ab0484840a8acf84c29e9 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Wed, 4 Dec 2019 16:18:02 +0100 Subject: [PATCH 008/529] Merge PR #5340: ADR 17: Historical header module --- docs/architecture/README.MD | 1 + .../adr-017-historical-header-module.md | 61 +++++++++++++++++++ .../{adt-template.md => adr-template.md} | 0 3 files changed, 62 insertions(+) create mode 100644 docs/architecture/adr-017-historical-header-module.md rename docs/architecture/{adt-template.md => adr-template.md} (100%) diff --git a/docs/architecture/README.MD b/docs/architecture/README.MD index 99d8204b213f..6b64c9c99402 100644 --- a/docs/architecture/README.MD +++ b/docs/architecture/README.MD @@ -31,3 +31,4 @@ Please add a entry below in your Pull Request for an ADR. - [ADR 010: Modular AnteHandler](./adr-010-modular-antehandler.md) - [ADR 011: Generalize Genesis Accounts](./adr-011-generalize-genesis-accounts.md) - [ADR 012: State Accessors](./adr-012-state-accessors.md) +- [ADR 017: Historical Header Module](./adr-017-historical-header-module.md) diff --git a/docs/architecture/adr-017-historical-header-module.md b/docs/architecture/adr-017-historical-header-module.md new file mode 100644 index 000000000000..0077ebb72a8c --- /dev/null +++ b/docs/architecture/adr-017-historical-header-module.md @@ -0,0 +1,61 @@ +# ADR 17: Historical Header Module + +## Changelog + +- 26 November 2019: Start of first version +- 2 December 2019: Final draft of first version + +## Context + +In order for the Cosmos SDK to implement the [IBC specification](https://github.com/cosmos/ics), modules within the SDK must have the ability to introspect recent consensus states (validator sets & commitment roots) as proofs of these values on other chains must be checked during the handshakes. + +## Decision + +The application MUST store the most recent `n` headers in a persistent store. At first, this store MAY be the current Merklised store. A non-Merklised store MAY be used later as no proofs are necessary. + +The application MUST store this information by storing new headers immediately when handling `abci.RequestBeginBlock`: + +```golang +func BeginBlock(ctx sdk.Context, keeper HistoricalHeaderKeeper, req abci.RequestBeginBlock) abci.ResponseBeginBlock { + info := HistoricalInfo{ + Header: ctx.BlockHeader(), + ValSet: keeper.StakingKeeper.GetAllValidators(ctx), // note that this must be stored in a canonical order + } + keeper.SetHistoricalInfo(ctx, ctx.BlockHeight(), info) + n := keeper.GetParamRecentHeadersToStore() + keeper.PruneHistoricalInfo(ctx, ctx.BlockHeight() - n) + // continue handling request +} +``` + +Alternatively, the application MAY store only the hash of the validator set. + +The application MUST make these past `n` committed headers available for querying by SDK modules through the `Keeper`'s `GetHistoricalInfo` function. This MAY be implemented in a new module, or it MAY also be integrated into an existing one (likely `x/staking` or `x/ibc`). + +`n` MAY be configured as a parameter store parameter, in which case it could be changed by `ParameterChangeProposal`s, although it will take some blocks for the stored information to catch up if `n` is increased. + +## Status + +Proposed. + +## Consequences + +Implementation of this ADR will require changes to the Cosmos SDK. It will not require changes to Tendermint. + +### Positive + +- Easy retrieval of headers & state roots for recent past heights by modules anywhere in the SDK. +- No RPC calls to Tendermint required. +- No ABCI alterations required. + +### Negative + +- Duplicates `n` headers data in Tendermint & the application (additional disk usage) - in the long term, an approach such as [this](https://github.com/tendermint/tendermint/issues/4210) might be preferable. + +### Neutral + +(none known) + +## References + +- [ICS 2: "Consensus state introspection"](https://github.com/cosmos/ics/tree/master/spec/ics-024-host-requirements#consensus-state-introspection) diff --git a/docs/architecture/adt-template.md b/docs/architecture/adr-template.md similarity index 100% rename from docs/architecture/adt-template.md rename to docs/architecture/adr-template.md From 12ff486a5730a41fa2ab8a1d9543766e22561a29 Mon Sep 17 00:00:00 2001 From: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Date: Wed, 4 Dec 2019 18:11:37 +0100 Subject: [PATCH 009/529] Updated PR template, stale and codecov settings (#5362) * updated PR template, stale and codecov settings * remove extra line * address @alexanderbez comments * Update .codecov.yml --- .codecov.yml | 34 +++++++++++++++++++++++++++----- .github/PULL_REQUEST_TEMPLATE.md | 32 +++++++++++++++++++++--------- .github/stale.yml | 4 ++-- 3 files changed, 54 insertions(+), 16 deletions(-) diff --git a/.codecov.yml b/.codecov.yml index a751662cd1a1..80b53809f8bc 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -1,4 +1,3 @@ - # # This codecov.yml is the default configuration for # all repositories on Codecov. You may adjust the settings @@ -10,18 +9,43 @@ coverage: range: 70...100 status: - # Learn more at https://codecov.io/docs#yaml_default_commit_status - project: + # Learn more at https://docs.codecov.io/docs/commit-status + project: default: threshold: 1% # allow this much decrease on project + app: + target: 70% + flags: app + modules: + target: 70% + flags: modules + client: + flags: client changes: false comment: - layout: "header, diff" - behavior: default # update if exists else create new + layout: "reach, diff, files" + behavior: default # update if exists else create new + require_changes: true + +flags: + app: + paths: + - "app/" + - "baseapp/" + modules: + paths: + - "x/" + - "!x/**/client/" # ignore client package + client: + paths: + - "client/" + - "x/**/client/" ignore: - "docs" - "*.md" - "*.rst" - "x/**/test_common.go" + - "scripts/" + - "contrib" diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index b7ffdc2b3934..6dd37f7f28e3 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -4,17 +4,31 @@ v Before smashing the submit button please review the checkboxes. v If a checkbox is n/a - please still include it but + a little note why ☺ > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > --> -- Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/cosmos-sdk/blob/develop/CONTRIBUTING.md#pr-targeting)) +Closes: #XXX -- [ ] Linked to github-issue with discussion and accepted design OR link to spec that describes this work. -- [ ] Wrote tests -- [ ] Updated relevant documentation (`docs/`) +## Description + + + +______ + +For contributor use: + +- [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#pr-targeting)) +- [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. +- [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). +- [ ] Wrote unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#testing) +- [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) +- [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` -- [ ] Re-reviewed `Files changed` in the github PR explorer +- [ ] Re-reviewed `Files changed` in the Github PR explorer ______ -For Admin Use: -- Added appropriate labels to PR (ex. wip, ready-for-review, docs) -- Reviewers Assigned -- Squashed all commits, uses message "Merge pull request #XYZ: [title]" ([coding standards](https://github.com/tendermint/coding/blob/master/README.md#merging-a-pr)) +For admin use: + +- [ ] Added appropriate labels to PR (ex. `WIP`, `R4R`, `docs`, etc) +- [ ] Reviewers assigned +- [ ] Squashed all commits, uses message "Merge pull request #XYZ: [title]" ([coding standards](https://github.com/tendermint/coding/blob/master/README.md#merging-a-pr)) diff --git a/.github/stale.yml b/.github/stale.yml index 6b9680042587..044feb3843d4 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -1,11 +1,11 @@ # Configuration for probot-stale - https://github.com/probot/stale # Number of days of inactivity before an Issue or Pull Request becomes stale -daysUntilStale: 60 +daysUntilStale: 10 # Number of days of inactivity before an Issue or Pull Request with the stale label is closed. # Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. -daysUntilClose: 9 +daysUntilClose: 4 # Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled) onlyLabels: [] From 722a633f5478fed1d26e745a018370f2aa32be4f Mon Sep 17 00:00:00 2001 From: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Date: Thu, 5 Dec 2019 10:29:54 +0100 Subject: [PATCH 010/529] Sim refactor 3: move weighted operations to modules (#4869) * move GenesisState generators to modules * minor change on slashing genState generator * move simulation params back to modules (#4839) move simulation params back to modules (#4839) * cleanup params * various fixes * move store decoders to modules * fix * module pattern * split generators for param change * param changes * revert util pkg * banksim * compile * update Decoders params * fix * address @colin-axner comments * move weighted operations to modules * cleanup * cleanup * Update cmd_test.go * simulation manager * mino fixes * cleanup * add GenerateGenesisState to simulation manager * Apply suggestions from code review Co-Authored-By: frog power 4000 * address @rigelrozanski comments * changelog * Apply suggestions from code review Co-Authored-By: colin axner * restructure modules simulation pkgs * remove cycle deps * rename funcs and add missing params * modularize simulator param changes * build * fix params keys * make format * various fixes * fix tests * minor updates to sim_test * cleanup * more cleanup * modularize genesis generators * minor cleanup * remove cdc from generators * remove cdc * add get or generate * fix non-determinism in simulation * changelog and x/simulation godoc * cleanup operations * update operations to use baseapp * updates and cleanup operations * update operations * restructure sim ops params * rename sim /operations/msg.go to /operations.go * move GenTx to a helper pkg to avoid circle deps * rm msg.ValidateBasic * changelog * random fees; delete auth's DeductFees sim operation * add chain-id for sig verification * Update x/simulation/account.go Co-Authored-By: colin axner * fix bank, gov and distr errors * fix staking and slashing errors; increase prob for send enabled * increase gas x10 * make format * fix some distr and staking edge cases * fix all edge cases * golang ci * rename acc vars; default no fees to 0stake * cleanup; check for exchange rate and skip invalid ops * fixes * check for max entries * add pubkey to genaccounts * fix gov bug * update staking sim ops * fix small redelegation error * fix small self delegation on unjail * rm inf loop on random val/accs * copy array * add ok boolean to RandomValidator return values * format * build * add WeightedOperations to AppModuleSimulation * define each module proposals content as part of the module pattern * Update x/bank/simulation/operations.go Co-Authored-By: colin axner * Update simapp/helpers/test_helpers.go Co-Authored-By: colin axner * address @colin-axner comments * add genaccount pubkey validation * fix test * update operations and move RandomFees to x/simulation * update gov ops * address @alexanderbez comments * avoid modifications to config * reorder params * modularized sim operations working * changelog * Update types/module/simulation.go Co-Authored-By: frog power 4000 * Update x/simulation/params.go Co-Authored-By: frog power 4000 * Update x/simulation/params.go Co-Authored-By: frog power 4000 * update /types/module * Update x/distribution/simulation/genesis.go Co-Authored-By: Alexander Bezobchuk * remove named return values * ensure all operations are simulated * golangci * add nolint * disable whitespace and funlen linter * disable godox * add TODO on unjail * update ops weights * remove dup * update godoc * remove unused func * build fixes * move weights to the same file * scopelint * changelog * address @AdityaSripal comments * address @alexanderbez comments --- CHANGELOG.md | 9 +- simapp/app.go | 13 +- simapp/params.go | 21 +-- simapp/params/doc.go | 19 +++ simapp/params/weights.go | 22 +++ simapp/sim_bench_test.go | 6 +- simapp/sim_test.go | 217 ++---------------------- simapp/state.go | 1 + simapp/utils.go | 23 +++ types/module/simulation.go | 56 ++++-- x/auth/module.go | 57 ++++--- x/bank/module.go | 57 ++++--- x/bank/simulation/operations.go | 51 +++++- x/distribution/module.go | 73 ++++---- x/distribution/simulation/operations.go | 85 ++++++---- x/distribution/simulation/proposals.go | 52 ++++++ x/gov/module.go | 70 ++++---- x/gov/simulation/operations.go | 76 +++++++-- x/gov/simulation/proposals.go | 32 ++++ x/mint/module.go | 57 ++++--- x/params/module.go | 48 +++++- x/params/simulation/operations.go | 11 +- x/params/simulation/proposals.go | 20 +++ x/simulation/operation.go | 8 + x/simulation/params.go | 22 ++- x/slashing/module.go | 67 +++++--- x/slashing/simulation/operations.go | 28 +++ x/staking/module.go | 62 ++++--- x/staking/simulation/operations.go | 79 +++++++++ x/supply/module.go | 57 ++++--- 30 files changed, 880 insertions(+), 519 deletions(-) create mode 100644 simapp/params/doc.go create mode 100644 simapp/params/weights.go create mode 100644 x/distribution/simulation/proposals.go create mode 100644 x/gov/simulation/proposals.go create mode 100644 x/params/simulation/proposals.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 7148e122122b..79947cba3ce3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -172,12 +172,15 @@ generalized genesis accounts through the `GenesisAccount` interface. * (simulation) [\#4824](https://github.com/cosmos/cosmos-sdk/issues/4824) PrintAllInvariants flag will print all failed invariants * (simulation) [\#4490](https://github.com/cosmos/cosmos-sdk/issues/4490) add `InitialBlockHeight` flag to resume a simulation from a given block * Support exporting the simulation stats to a given JSON file -* (simulation) [\#4847](https://github.com/cosmos/cosmos-sdk/issues/4847), [\#4838](https://github.com/cosmos/cosmos-sdk/pull/4838) `SimApp` and simulation refactors +* (simulation) [\#4847](https://github.com/cosmos/cosmos-sdk/issues/4847), [\#4838](https://github.com/cosmos/cosmos-sdk/pull/4838) and [\#4869](https://github.com/cosmos/cosmos-sdk/pull/4869) `SimApp` and simulation refactors: * Implement `SimulationManager` for executing modules' simulation functionalities in a modularized way * Add `RegisterStoreDecoders` to the `SimulationManager` for decoding each module's types * Add `GenerateGenesisStates` to the `SimulationManager` to generate a randomized `GenState` for each module - * Add `RandomizedParams` to the `SimulationManager` that registers each modules' parameters `Content` to simulate - `ParamChangeProposal`s + * Add `RandomizedParams` to the `SimulationManager` that registers each modules' parameters in order to + simulate `ParamChangeProposal`s' `Content`s + * Add `WeightedOperations` to the `SimulationManager` that define simulation operations (modules' `Msg`s) with their + respective weights (i.e chance of being simulated). + * Add `ProposalContents` to the `SimulationManager` to register each module's governance proposal `Content`s. * (simulation) [\#4893](https://github.com/cosmos/cosmos-sdk/issues/4893) Change SimApp keepers to be public and add getter functions for keys and codec * (simulation) [\#4906](https://github.com/cosmos/cosmos-sdk/issues/4906) Add simulation `Config` struct that wraps simulation flags * (simulation) [\#4935](https://github.com/cosmos/cosmos-sdk/issues/4935) Update simulation to reflect a proper `ABCI` application without bypassing `BaseApp` semantics diff --git a/simapp/app.go b/simapp/app.go index 4ed1a244dda1..84a1197713c4 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -226,10 +226,10 @@ func NewSimApp( bank.NewAppModule(app.BankKeeper, app.AccountKeeper), crisis.NewAppModule(&app.CrisisKeeper), supply.NewAppModule(app.SupplyKeeper, app.AccountKeeper), - gov.NewAppModule(app.GovKeeper, app.SupplyKeeper), + gov.NewAppModule(app.GovKeeper, app.AccountKeeper, app.SupplyKeeper), mint.NewAppModule(app.MintKeeper), - distr.NewAppModule(app.DistrKeeper, app.SupplyKeeper), - slashing.NewAppModule(app.SlashingKeeper, app.StakingKeeper), + slashing.NewAppModule(app.SlashingKeeper, app.AccountKeeper, app.StakingKeeper), + distr.NewAppModule(app.DistrKeeper, app.AccountKeeper, app.SupplyKeeper, app.StakingKeeper), staking.NewAppModule(app.StakingKeeper, app.AccountKeeper, app.SupplyKeeper), upgrade.NewAppModule(app.UpgradeKeeper), evidence.NewAppModule(app.EvidenceKeeper), @@ -260,11 +260,12 @@ func NewSimApp( auth.NewAppModule(app.AccountKeeper), bank.NewAppModule(app.BankKeeper, app.AccountKeeper), supply.NewAppModule(app.SupplyKeeper, app.AccountKeeper), - gov.NewAppModule(app.GovKeeper, app.SupplyKeeper), + gov.NewAppModule(app.GovKeeper, app.AccountKeeper, app.SupplyKeeper), mint.NewAppModule(app.MintKeeper), - distr.NewAppModule(app.DistrKeeper, app.SupplyKeeper), staking.NewAppModule(app.StakingKeeper, app.AccountKeeper, app.SupplyKeeper), - slashing.NewAppModule(app.SlashingKeeper, app.StakingKeeper), + distr.NewAppModule(app.DistrKeeper, app.AccountKeeper, app.SupplyKeeper, app.StakingKeeper), + slashing.NewAppModule(app.SlashingKeeper, app.AccountKeeper, app.StakingKeeper), + params.NewAppModule(), // NOTE: only used for simulation to generate randomized param change proposals ) app.sm.RegisterStoreDecoders() diff --git a/simapp/params.go b/simapp/params.go index e0416761a8b3..7bb425b5f46f 100644 --- a/simapp/params.go +++ b/simapp/params.go @@ -2,23 +2,6 @@ package simapp // Simulation parameter constants const ( - StakePerAccount = "stake_per_account" - InitiallyBondedValidators = "initially_bonded_validators" - OpWeightDeductFee = "op_weight_deduct_fee" - OpWeightMsgSend = "op_weight_msg_send" - OpWeightMsgMultiSend = "op_weight_msg_multisend" - OpWeightMsgSetWithdrawAddress = "op_weight_msg_set_withdraw_address" - OpWeightMsgWithdrawDelegationReward = "op_weight_msg_withdraw_delegation_reward" - OpWeightMsgWithdrawValidatorCommission = "op_weight_msg_withdraw_validator_commission" - OpWeightSubmitTextProposal = "op_weight_submit_text_proposal" - OpWeightSubmitCommunitySpendProposal = "op_weight_submit_community_spend_proposal" - OpWeightSubmitParamChangeProposal = "op_weight_submit_param_change_proposal" - OpWeightMsgDeposit = "op_weight_msg_deposit" - OpWeightMsgVote = "op_weight_msg_vote" - OpWeightMsgCreateValidator = "op_weight_msg_create_validator" - OpWeightMsgEditValidator = "op_weight_msg_edit_validator" - OpWeightMsgDelegate = "op_weight_msg_delegate" - OpWeightMsgUndelegate = "op_weight_msg_undelegate" - OpWeightMsgBeginRedelegate = "op_weight_msg_begin_redelegate" - OpWeightMsgUnjail = "op_weight_msg_unjail" + StakePerAccount = "stake_per_account" + InitiallyBondedValidators = "initially_bonded_validators" ) diff --git a/simapp/params/doc.go b/simapp/params/doc.go new file mode 100644 index 000000000000..1c721342a9c9 --- /dev/null +++ b/simapp/params/doc.go @@ -0,0 +1,19 @@ +/* +Package params defines the simulation parameters in the simapp. + +It contains the default weights used for each transaction used on the module's +simulation. These weights define the chance for a transaction to be simulated at +any gived operation. + +You can repace the default values for the weights by providing a params.json +file with the weights defined for each of the transaction operations: + + { + "op_weight_msg_send": 60, + "op_weight_msg_delegate": 100, + } + +In the example above, the `MsgSend` has 60% chance to be simulated, while the +`MsgDelegate` will always be simulated. +*/ +package params diff --git a/simapp/params/weights.go b/simapp/params/weights.go new file mode 100644 index 000000000000..adff26b8a288 --- /dev/null +++ b/simapp/params/weights.go @@ -0,0 +1,22 @@ +package params + +// Default simulation operation weights for messages and gov proposals +const ( + DefaultWeightMsgSend int = 100 + DefaultWeightMsgMultiSend int = 10 + DefaultWeightMsgSetWithdrawAddress int = 50 + DefaultWeightMsgWithdrawDelegationReward int = 50 + DefaultWeightMsgWithdrawValidatorCommission int = 50 + DefaultWeightMsgDeposit int = 100 + DefaultWeightMsgVote int = 67 + DefaultWeightMsgUnjail int = 100 + DefaultWeightMsgCreateValidator int = 100 + DefaultWeightMsgEditValidator int = 5 + DefaultWeightMsgDelegate int = 100 + DefaultWeightMsgUndelegate int = 100 + DefaultWeightMsgBeginRedelegate int = 100 + + DefaultWeightCommunitySpendProposal int = 5 + DefaultWeightTextProposal int = 5 + DefaultWeightParamChangeProposal int = 5 +) diff --git a/simapp/sim_bench_test.go b/simapp/sim_bench_test.go index e9d5d7d87d2c..994e9803247a 100644 --- a/simapp/sim_bench_test.go +++ b/simapp/sim_bench_test.go @@ -36,7 +36,8 @@ func BenchmarkFullAppSimulation(b *testing.B) { // TODO: parameterize numbers, save for a later PR _, simParams, simErr := simulation.SimulateFromSeed( b, os.Stdout, app.BaseApp, AppStateFn(app.Codec(), app.sm), - testAndRunTxs(app, config), app.ModuleAccountAddrs(), config, + SimulationOperations(app, app.Codec(), config), + app.ModuleAccountAddrs(), config, ) // export state and params before the simulation error is checked @@ -86,7 +87,8 @@ func BenchmarkInvariants(b *testing.B) { // 2. Run parameterized simulation (w/o invariants) _, simParams, simErr := simulation.SimulateFromSeed( b, ioutil.Discard, app.BaseApp, AppStateFn(app.Codec(), app.sm), - testAndRunTxs(app, config), app.ModuleAccountAddrs(), config, + SimulationOperations(app, app.Codec(), config), + app.ModuleAccountAddrs(), config, ) // export state and params before the simulation error is checked diff --git a/simapp/sim_test.go b/simapp/sim_test.go index 17bcf9d57010..100e685836fc 100644 --- a/simapp/sim_test.go +++ b/simapp/sim_test.go @@ -18,19 +18,13 @@ import ( "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" - banksim "github.com/cosmos/cosmos-sdk/x/bank/simulation" distr "github.com/cosmos/cosmos-sdk/x/distribution" - distrsim "github.com/cosmos/cosmos-sdk/x/distribution/simulation" "github.com/cosmos/cosmos-sdk/x/gov" - govsim "github.com/cosmos/cosmos-sdk/x/gov/simulation" "github.com/cosmos/cosmos-sdk/x/mint" "github.com/cosmos/cosmos-sdk/x/params" - paramsim "github.com/cosmos/cosmos-sdk/x/params/simulation" "github.com/cosmos/cosmos-sdk/x/simulation" "github.com/cosmos/cosmos-sdk/x/slashing" - slashingsim "github.com/cosmos/cosmos-sdk/x/slashing/simulation" "github.com/cosmos/cosmos-sdk/x/staking" - stakingsim "github.com/cosmos/cosmos-sdk/x/staking/simulation" "github.com/cosmos/cosmos-sdk/x/supply" ) @@ -39,201 +33,6 @@ func init() { GetSimulatorFlags() } -func testAndRunTxs(app *SimApp, config simulation.Config) []simulation.WeightedOperation { - ap := make(simulation.AppParams) - - paramChanges := app.sm.GenerateParamChanges(config.Seed) - - if config.ParamsFile != "" { - bz, err := ioutil.ReadFile(config.ParamsFile) - if err != nil { - panic(err) - } - - app.cdc.MustUnmarshalJSON(bz, &ap) - } - - // nolint: govet - return []simulation.WeightedOperation{ - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightMsgSend, &v, nil, - func(_ *rand.Rand) { - v = 100 - }) - return v - }(nil), - banksim.SimulateMsgSend(app.AccountKeeper, app.BankKeeper), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightMsgMultiSend, &v, nil, - func(_ *rand.Rand) { - v = 40 - }) - return v - }(nil), - banksim.SimulateMsgMultiSend(app.AccountKeeper, app.BankKeeper), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightMsgSetWithdrawAddress, &v, nil, - func(_ *rand.Rand) { - v = 50 - }) - return v - }(nil), - distrsim.SimulateMsgSetWithdrawAddress(app.AccountKeeper, app.DistrKeeper), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightMsgWithdrawDelegationReward, &v, nil, - func(_ *rand.Rand) { - v = 50 - }) - return v - }(nil), - distrsim.SimulateMsgWithdrawDelegatorReward(app.AccountKeeper, app.DistrKeeper, app.StakingKeeper), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightMsgWithdrawValidatorCommission, &v, nil, - func(_ *rand.Rand) { - v = 50 - }) - return v - }(nil), - distrsim.SimulateMsgWithdrawValidatorCommission(app.AccountKeeper, app.DistrKeeper, app.StakingKeeper), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightSubmitTextProposal, &v, nil, - func(_ *rand.Rand) { - v = 20 - }) - return v - }(nil), - govsim.SimulateSubmitProposal(app.AccountKeeper, app.GovKeeper, govsim.SimulateTextProposalContent), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightSubmitCommunitySpendProposal, &v, nil, - func(_ *rand.Rand) { - v = 20 - }) - return v - }(nil), - govsim.SimulateSubmitProposal(app.AccountKeeper, app.GovKeeper, distrsim.SimulateCommunityPoolSpendProposalContent(app.DistrKeeper)), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightSubmitParamChangeProposal, &v, nil, - func(_ *rand.Rand) { - v = 20 - }) - return v - }(nil), - govsim.SimulateSubmitProposal(app.AccountKeeper, app.GovKeeper, paramsim.SimulateParamChangeProposalContent(paramChanges)), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightMsgDeposit, &v, nil, - func(_ *rand.Rand) { - v = 100 - }) - return v - }(nil), - govsim.SimulateMsgDeposit(app.AccountKeeper, app.GovKeeper), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightMsgVote, &v, nil, - func(_ *rand.Rand) { - v = 100 - }) - return v - }(nil), - govsim.SimulateMsgVote(app.AccountKeeper, app.GovKeeper), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightMsgCreateValidator, &v, nil, - func(_ *rand.Rand) { - v = 100 - }) - return v - }(nil), - stakingsim.SimulateMsgCreateValidator(app.AccountKeeper, app.StakingKeeper), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightMsgEditValidator, &v, nil, - func(_ *rand.Rand) { - v = 20 - }) - return v - }(nil), - stakingsim.SimulateMsgEditValidator(app.AccountKeeper, app.StakingKeeper), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightMsgDelegate, &v, nil, - func(_ *rand.Rand) { - v = 100 - }) - return v - }(nil), - stakingsim.SimulateMsgDelegate(app.AccountKeeper, app.StakingKeeper), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightMsgUndelegate, &v, nil, - func(_ *rand.Rand) { - v = 100 - }) - return v - }(nil), - stakingsim.SimulateMsgUndelegate(app.AccountKeeper, app.StakingKeeper), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightMsgBeginRedelegate, &v, nil, - func(_ *rand.Rand) { - v = 100 - }) - return v - }(nil), - stakingsim.SimulateMsgBeginRedelegate(app.AccountKeeper, app.StakingKeeper), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightMsgUnjail, &v, nil, - func(_ *rand.Rand) { - v = 100 - }) - return v - }(nil), - slashingsim.SimulateMsgUnjail(app.AccountKeeper, app.SlashingKeeper, app.StakingKeeper), - }, - } -} - // fauxMerkleModeOpt returns a BaseApp option to use a dbStoreAdapter instead of // an IAVLStore for faster simulation speed. func fauxMerkleModeOpt(bapp *baseapp.BaseApp) { @@ -276,7 +75,8 @@ func TestFullAppSimulation(t *testing.T) { // Run randomized simulation _, simParams, simErr := simulation.SimulateFromSeed( t, os.Stdout, app.BaseApp, AppStateFn(app.Codec(), app.sm), - testAndRunTxs(app, config), app.ModuleAccountAddrs(), config, + SimulationOperations(app, app.Codec(), config), + app.ModuleAccountAddrs(), config, ) // export state and params before the simulation error is checked @@ -331,7 +131,8 @@ func TestAppImportExport(t *testing.T) { // Run randomized simulation _, simParams, simErr := simulation.SimulateFromSeed( t, os.Stdout, app.BaseApp, AppStateFn(app.Codec(), app.sm), - testAndRunTxs(app, config), app.ModuleAccountAddrs(), config, + SimulationOperations(app, app.Codec(), config), + app.ModuleAccountAddrs(), config, ) // export state and simParams before the simulation error is checked @@ -417,7 +218,6 @@ func TestAppImportExport(t *testing.T) { fmt.Printf("compared %d key/value pairs between %s and %s\n", len(failedKVAs), storeKeyA, storeKeyB) require.Equal(t, len(failedKVAs), 0, GetSimulationLog(storeKeyA.Name(), app.sm.StoreDecoders, app.cdc, failedKVAs, failedKVBs)) } - } func TestAppSimulationAfterImport(t *testing.T) { @@ -449,7 +249,8 @@ func TestAppSimulationAfterImport(t *testing.T) { // Run randomized simulation stopEarly, simParams, simErr := simulation.SimulateFromSeed( t, os.Stdout, app.BaseApp, AppStateFn(app.Codec(), app.sm), - testAndRunTxs(app, config), app.ModuleAccountAddrs(), config, + SimulationOperations(app, app.Codec(), config), + app.ModuleAccountAddrs(), config, ) // export state and params before the simulation error is checked @@ -504,7 +305,8 @@ func TestAppSimulationAfterImport(t *testing.T) { // Run randomized simulation on imported app _, _, err = simulation.SimulateFromSeed( t, os.Stdout, newApp.BaseApp, AppStateFn(app.Codec(), app.sm), - testAndRunTxs(newApp, config), newApp.ModuleAccountAddrs(), config, + SimulationOperations(newApp, newApp.Codec(), config), + newApp.ModuleAccountAddrs(), config, ) require.NoError(t, err) @@ -550,7 +352,8 @@ func TestAppStateDeterminism(t *testing.T) { _, _, err := simulation.SimulateFromSeed( t, os.Stdout, app.BaseApp, AppStateFn(app.Codec(), app.sm), - testAndRunTxs(app, config), app.ModuleAccountAddrs(), config, + SimulationOperations(app, app.Codec(), config), + app.ModuleAccountAddrs(), config, ) require.NoError(t, err) diff --git a/simapp/state.go b/simapp/state.go index 679bce803b20..22a4e53a63f0 100644 --- a/simapp/state.go +++ b/simapp/state.go @@ -30,6 +30,7 @@ func AppStateFn(cdc *codec.Codec, simManager *module.SimulationManager) simulati genesisTimestamp = time.Unix(FlagGenesisTimeValue, 0) } + chainID = config.ChainID switch { case config.ParamsFile != "" && config.GenesisFile != "": panic("cannot provide both a genesis file and a params file") diff --git a/simapp/utils.go b/simapp/utils.go index 4f9ff37dc21b..959988d0b1c0 100644 --- a/simapp/utils.go +++ b/simapp/utils.go @@ -10,6 +10,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/x/simulation" ) @@ -84,6 +85,28 @@ func NewConfigFromFlags() simulation.Config { } } +// SimulationOperations retrieves the simulation params from the provided file path +// and returns all the modules weighted operations +func SimulationOperations(app *SimApp, cdc *codec.Codec, config simulation.Config) []simulation.WeightedOperation { + simState := module.SimulationState{ + AppParams: make(simulation.AppParams), + Cdc: cdc, + } + + if config.ParamsFile != "" { + bz, err := ioutil.ReadFile(config.ParamsFile) + if err != nil { + panic(err) + } + + app.cdc.MustUnmarshalJSON(bz, &simState.AppParams) + } + + simState.ParamChanges = app.sm.GenerateParamChanges(config.Seed) + simState.Contents = app.sm.GetProposalContents(simState) + return app.sm.WeightedOperations(simState) +} + //--------------------------------------------------------------------- // Simulation Utils diff --git a/types/module/simulation.go b/types/module/simulation.go index 1d359888646b..fab432c8a57e 100644 --- a/types/module/simulation.go +++ b/types/module/simulation.go @@ -2,6 +2,7 @@ package module import ( "encoding/json" + "math/rand" "time" @@ -13,14 +14,20 @@ import ( // AppModuleSimulation defines the standard functions that every module should expose // for the SDK blockchain simulator type AppModuleSimulation interface { - // register a func to decode the each module's defined types from their corresponding store key - RegisterStoreDecoder(sdk.StoreDecoderRegistry) - // randomized genesis states GenerateGenesisState(input *SimulationState) + // content functions used to simulate governance proposals + ProposalContents(simState SimulationState) []simulation.WeightedProposalContent + // randomized module parameters for param change proposals RandomizedParams(r *rand.Rand) []simulation.ParamChange + + // register a func to decode the each module's defined types from their corresponding store key + RegisterStoreDecoder(sdk.StoreDecoderRegistry) + + // simulation operations (i.e msgs) with their respective weight + WeightedOperations(simState SimulationState) []simulation.WeightedOperation } // SimulationManager defines a simulation manager that provides the high level utility @@ -40,6 +47,17 @@ func NewSimulationManager(modules ...AppModuleSimulation) *SimulationManager { } } +// GetProposalContents returns each module's proposal content generator function +// with their default operation weight and key. +func (sm *SimulationManager) GetProposalContents(simState SimulationState) []simulation.WeightedProposalContent { + var wContents []simulation.WeightedProposalContent + for _, module := range sm.Modules { + wContents = append(wContents, module.ProposalContents(simState)...) + } + + return wContents +} + // RegisterStoreDecoders registers each of the modules' store decoders into a map func (sm *SimulationManager) RegisterStoreDecoders() { for _, module := range sm.Modules { @@ -49,9 +67,9 @@ func (sm *SimulationManager) RegisterStoreDecoders() { // GenerateGenesisStates generates a randomized GenesisState for each of the // registered modules -func (sm *SimulationManager) GenerateGenesisStates(input *SimulationState) { +func (sm *SimulationManager) GenerateGenesisStates(simState *SimulationState) { for _, module := range sm.Modules { - module.GenerateGenesisState(input) + module.GenerateGenesisState(simState) } } @@ -67,16 +85,28 @@ func (sm *SimulationManager) GenerateParamChanges(seed int64) (paramChanges []si return } +// WeightedOperations returns all the modules' weighted operations of an application +func (sm *SimulationManager) WeightedOperations(simState SimulationState) []simulation.WeightedOperation { + var wOps []simulation.WeightedOperation + for _, module := range sm.Modules { + wOps = append(wOps, module.WeightedOperations(simState)...) + } + + return wOps +} + // SimulationState is the input parameters used on each of the module's randomized // GenesisState generator function type SimulationState struct { AppParams simulation.AppParams - Cdc *codec.Codec // application codec - Rand *rand.Rand // random number - GenState map[string]json.RawMessage // genesis state - Accounts []simulation.Account // simulation accounts - InitialStake int64 // initial coins per account - NumBonded int64 // number of initially bonded acconts - GenTimestamp time.Time // genesis timestamp - UnbondTime time.Duration // staking unbond time stored to use it as the slashing maximum evidence duration + Cdc *codec.Codec // application codec + Rand *rand.Rand // random number + GenState map[string]json.RawMessage // genesis state + Accounts []simulation.Account // simulation accounts + InitialStake int64 // initial coins per account + NumBonded int64 // number of initially bonded accounts + GenTimestamp time.Time // genesis timestamp + UnbondTime time.Duration // staking unbond time stored to use it as the slashing maximum evidence duration + ParamChanges []simulation.ParamChange // simulated parameter changes from modules + Contents []simulation.WeightedProposalContent // proposal content generator functions with their default weight and app sim key } diff --git a/x/auth/module.go b/x/auth/module.go index 676a54b61990..510f4304d7c5 100644 --- a/x/auth/module.go +++ b/x/auth/module.go @@ -22,7 +22,7 @@ import ( var ( _ module.AppModule = AppModule{} _ module.AppModuleBasic = AppModuleBasic{} - _ module.AppModuleSimulation = AppModuleSimulation{} + _ module.AppModuleSimulation = AppModule{} ) // AppModuleBasic defines the basic application module used by the auth module. @@ -71,30 +71,9 @@ func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command { //____________________________________________________________________________ -// AppModuleSimulation defines the module simulation functions used by the auth module. -type AppModuleSimulation struct{} - -// RegisterStoreDecoder registers a decoder for auth module's types -func (AppModuleSimulation) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { - sdr[StoreKey] = simulation.DecodeStore -} - -// GenerateGenesisState creates a randomized GenState of the auth module -func (AppModuleSimulation) GenerateGenesisState(simState *module.SimulationState) { - simulation.RandomizedGenState(simState) -} - -// RandomizedParams creates randomized auth param changes for the simulator. -func (AppModuleSimulation) RandomizedParams(r *rand.Rand) []sim.ParamChange { - return simulation.ParamChanges(r) -} - -//____________________________________________________________________________ - // AppModule implements an application module for the auth module. type AppModule struct { AppModuleBasic - AppModuleSimulation accountKeeper AccountKeeper } @@ -102,9 +81,8 @@ type AppModule struct { // NewAppModule creates a new AppModule object func NewAppModule(accountKeeper AccountKeeper) AppModule { return AppModule{ - AppModuleBasic: AppModuleBasic{}, - AppModuleSimulation: AppModuleSimulation{}, - accountKeeper: accountKeeper, + AppModuleBasic: AppModuleBasic{}, + accountKeeper: accountKeeper, } } @@ -156,3 +134,32 @@ func (AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {} func (AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { return []abci.ValidatorUpdate{} } + +//____________________________________________________________________________ + +// AppModuleSimulation functions + +// GenerateGenesisState creates a randomized GenState of the auth module +func (AppModule) GenerateGenesisState(simState *module.SimulationState) { + simulation.RandomizedGenState(simState) +} + +// ProposalContents doesn't return any content functions for governance proposals. +func (AppModule) ProposalContents(_ module.SimulationState) []sim.WeightedProposalContent { + return nil +} + +// RandomizedParams creates randomized auth param changes for the simulator. +func (AppModule) RandomizedParams(r *rand.Rand) []sim.ParamChange { + return simulation.ParamChanges(r) +} + +// RegisterStoreDecoder registers a decoder for auth module's types +func (AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { + sdr[StoreKey] = simulation.DecodeStore +} + +// WeightedOperations doesn't return any auth module operation. +func (AppModule) WeightedOperations(_ module.SimulationState) []sim.WeightedOperation { + return nil +} diff --git a/x/bank/module.go b/x/bank/module.go index 2539f052cd3b..0430d18f1550 100644 --- a/x/bank/module.go +++ b/x/bank/module.go @@ -24,7 +24,7 @@ import ( var ( _ module.AppModule = AppModule{} _ module.AppModuleBasic = AppModuleBasic{} - _ module.AppModuleSimulation = AppModuleSimulation{} + _ module.AppModuleSimulation = AppModule{} ) // AppModuleBasic defines the basic application module used by the bank module. @@ -67,28 +67,9 @@ func (AppModuleBasic) GetQueryCmd(_ *codec.Codec) *cobra.Command { return nil } //____________________________________________________________________________ -// AppModuleSimulation defines the module simulation functions used by the bank module. -type AppModuleSimulation struct{} - -// RegisterStoreDecoder performs a no-op. -func (AppModuleSimulation) RegisterStoreDecoder(_ sdk.StoreDecoderRegistry) {} - -// GenerateGenesisState creates a randomized GenState of the bank module. -func (AppModuleSimulation) GenerateGenesisState(simState *module.SimulationState) { - simulation.RandomizedGenState(simState) -} - -// RandomizedParams creates randomized bank param changes for the simulator. -func (AppModuleSimulation) RandomizedParams(r *rand.Rand) []sim.ParamChange { - return simulation.ParamChanges(r) -} - -//____________________________________________________________________________ - // AppModule implements an application module for the bank module. type AppModule struct { AppModuleBasic - AppModuleSimulation keeper Keeper accountKeeper types.AccountKeeper @@ -97,10 +78,9 @@ type AppModule struct { // NewAppModule creates a new AppModule object func NewAppModule(keeper Keeper, accountKeeper types.AccountKeeper) AppModule { return AppModule{ - AppModuleBasic: AppModuleBasic{}, - AppModuleSimulation: AppModuleSimulation{}, - keeper: keeper, - accountKeeper: accountKeeper, + AppModuleBasic: AppModuleBasic{}, + keeper: keeper, + accountKeeper: accountKeeper, } } @@ -150,3 +130,32 @@ func (AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {} func (AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { return []abci.ValidatorUpdate{} } + +//____________________________________________________________________________ + +// AppModuleSimulation functions + +// GenerateGenesisState creates a randomized GenState of the bank module. +func (AppModule) GenerateGenesisState(simState *module.SimulationState) { + simulation.RandomizedGenState(simState) +} + +// ProposalContents doesn't return any content functions for governance proposals. +func (AppModule) ProposalContents(_ module.SimulationState) []sim.WeightedProposalContent { + return nil +} + +// RandomizedParams creates randomized bank param changes for the simulator. +func (AppModule) RandomizedParams(r *rand.Rand) []sim.ParamChange { + return simulation.ParamChanges(r) +} + +// RegisterStoreDecoder performs a no-op. +func (AppModule) RegisterStoreDecoder(_ sdk.StoreDecoderRegistry) {} + +// WeightedOperations returns the all the gov module operations with their respective weights. +func (am AppModule) WeightedOperations(simState module.SimulationState) []sim.WeightedOperation { + return simulation.WeightedOperations( + simState.AppParams, simState.Cdc, am.accountKeeper, am.keeper, + ) +} diff --git a/x/bank/simulation/operations.go b/x/bank/simulation/operations.go index 9d46d1fff946..9e89174e9433 100644 --- a/x/bank/simulation/operations.go +++ b/x/bank/simulation/operations.go @@ -7,13 +7,50 @@ import ( "github.com/tendermint/tendermint/crypto" "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/simapp/helpers" + simappparams "github.com/cosmos/cosmos-sdk/simapp/params" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/bank/internal/keeper" "github.com/cosmos/cosmos-sdk/x/bank/internal/types" "github.com/cosmos/cosmos-sdk/x/simulation" ) +// Simulation operation weights constants +const ( + OpWeightMsgSend = "op_weight_msg_send" + OpWeightMsgMultiSend = "op_weight_msg_multisend" +) + +// WeightedOperations returns all the operations from the module with their respective weights +func WeightedOperations(appParams simulation.AppParams, cdc *codec.Codec, ak types.AccountKeeper, + bk keeper.Keeper) simulation.WeightedOperations { + + var weightMsgSend, weightMsgMultiSend int + appParams.GetOrGenerate(cdc, OpWeightMsgSend, &weightMsgSend, nil, + func(_ *rand.Rand) { + weightMsgSend = simappparams.DefaultWeightMsgSend + }, + ) + + appParams.GetOrGenerate(cdc, OpWeightMsgMultiSend, &weightMsgMultiSend, nil, + func(_ *rand.Rand) { + weightMsgMultiSend = simappparams.DefaultWeightMsgMultiSend + }, + ) + + return simulation.WeightedOperations{ + simulation.NewWeightedOperation( + weightMsgSend, + SimulateMsgSend(ak, bk), + ), + simulation.NewWeightedOperation( + weightMsgMultiSend, + SimulateMsgMultiSend(ak, bk), + ), + } +} + // SimulateMsgSend tests and runs a single msg send where both // accounts already exist. // nolint: funlen @@ -51,12 +88,15 @@ func SimulateMsgSend(ak types.AccountKeeper, bk keeper.Keeper) simulation.Operat func sendMsgSend( r *rand.Rand, app *baseapp.BaseApp, ak types.AccountKeeper, msg types.MsgSend, ctx sdk.Context, chainID string, privkeys []crypto.PrivKey, -) (err error) { +) error { account := ak.GetAccount(ctx, msg.FromAddress) coins := account.SpendableCoins(ctx.BlockTime()) - var fees sdk.Coins + var ( + fees sdk.Coins + err error + ) coins, hasNeg := coins.SafeSub(msg.Amount) if !hasNeg { fees, err = simulation.RandomFees(r, ctx, coins) @@ -181,7 +221,7 @@ func SimulateMsgMultiSend(ak types.AccountKeeper, bk keeper.Keeper) simulation.O func sendMsgMultiSend( r *rand.Rand, app *baseapp.BaseApp, ak types.AccountKeeper, msg types.MsgMultiSend, ctx sdk.Context, chainID string, privkeys []crypto.PrivKey, -) (err error) { +) error { accountNumbers := make([]uint64, len(msg.Inputs)) sequenceNumbers := make([]uint64, len(msg.Inputs)) @@ -196,7 +236,10 @@ func sendMsgMultiSend( feePayer := ak.GetAccount(ctx, msg.Inputs[0].Address) coins := feePayer.SpendableCoins(ctx.BlockTime()) - var fees sdk.Coins + var ( + fees sdk.Coins + err error + ) coins, hasNeg := coins.SafeSub(msg.Inputs[0].Coins) if !hasNeg { fees, err = simulation.RandomFees(r, ctx, coins) diff --git a/x/distribution/module.go b/x/distribution/module.go index 2b42e0b68c51..c0452ebb3c6b 100644 --- a/x/distribution/module.go +++ b/x/distribution/module.go @@ -18,12 +18,13 @@ import ( "github.com/cosmos/cosmos-sdk/x/distribution/simulation" "github.com/cosmos/cosmos-sdk/x/distribution/types" sim "github.com/cosmos/cosmos-sdk/x/simulation" + stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" ) var ( _ module.AppModule = AppModule{} _ module.AppModuleBasic = AppModuleBasic{} - _ module.AppModuleSimulation = AppModuleSimulation{} + _ module.AppModuleSimulation = AppModule{} ) // AppModuleBasic defines the basic application module used by the distribution module. @@ -72,42 +73,25 @@ func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command { //____________________________________________________________________________ -// AppModuleSimulation defines the module simulation functions used by the distribution module. -type AppModuleSimulation struct{} - -// RegisterStoreDecoder registers a decoder for distribution module's types -func (AppModuleSimulation) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { - sdr[StoreKey] = simulation.DecodeStore -} - -// GenerateGenesisState creates a randomized GenState of the distribution module. -func (AppModuleSimulation) GenerateGenesisState(simState *module.SimulationState) { - simulation.RandomizedGenState(simState) -} - -// RandomizedParams creates randomized distribution param changes for the simulator. -func (AppModuleSimulation) RandomizedParams(r *rand.Rand) []sim.ParamChange { - return simulation.ParamChanges(r) -} - -//____________________________________________________________________________ - // AppModule implements an application module for the distribution module. type AppModule struct { AppModuleBasic - AppModuleSimulation - keeper Keeper - supplyKeeper types.SupplyKeeper + keeper Keeper + accountKeeper types.AccountKeeper + stakingKeeper stakingkeeper.Keeper + supplyKeeper types.SupplyKeeper } // NewAppModule creates a new AppModule object -func NewAppModule(keeper Keeper, supplyKeeper types.SupplyKeeper) AppModule { +func NewAppModule(keeper Keeper, accountKeeper types.AccountKeeper, + supplyKeeper types.SupplyKeeper, stakingKeeper stakingkeeper.Keeper) AppModule { return AppModule{ - AppModuleBasic: AppModuleBasic{}, - AppModuleSimulation: AppModuleSimulation{}, - keeper: keeper, - supplyKeeper: supplyKeeper, + AppModuleBasic: AppModuleBasic{}, + keeper: keeper, + accountKeeper: accountKeeper, + supplyKeeper: supplyKeeper, + stakingKeeper: stakingKeeper, } } @@ -167,3 +151,34 @@ func (am AppModule) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) { func (AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { return []abci.ValidatorUpdate{} } + +//____________________________________________________________________________ + +// AppModuleSimulation functions + +// GenerateGenesisState creates a randomized GenState of the distribution module. +func (AppModule) GenerateGenesisState(simState *module.SimulationState) { + simulation.RandomizedGenState(simState) +} + +// ProposalContents returns all the distribution content functions used to +// simulate governance proposals. +func (am AppModule) ProposalContents(_ module.SimulationState) []sim.WeightedProposalContent { + return simulation.ProposalContents(am.keeper) +} + +// RandomizedParams creates randomized distribution param changes for the simulator. +func (AppModule) RandomizedParams(r *rand.Rand) []sim.ParamChange { + return simulation.ParamChanges(r) +} + +// RegisterStoreDecoder registers a decoder for distribution module's types +func (AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { + sdr[StoreKey] = simulation.DecodeStore +} + +// WeightedOperations returns the all the gov module operations with their respective weights. +func (am AppModule) WeightedOperations(simState module.SimulationState) []sim.WeightedOperation { + return simulation.WeightedOperations(simState.AppParams, simState.Cdc, + am.accountKeeper, am.keeper, am.stakingKeeper) +} diff --git a/x/distribution/simulation/operations.go b/x/distribution/simulation/operations.go index c8bab36d496b..f3875e2560b0 100644 --- a/x/distribution/simulation/operations.go +++ b/x/distribution/simulation/operations.go @@ -6,23 +6,72 @@ import ( "math/rand" "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/simapp/helpers" + simappparams "github.com/cosmos/cosmos-sdk/simapp/params" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/distribution/keeper" "github.com/cosmos/cosmos-sdk/x/distribution/types" - govsim "github.com/cosmos/cosmos-sdk/x/gov/simulation" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/cosmos/cosmos-sdk/x/simulation" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" ) +// Simulation operation weights constants +const ( + OpWeightMsgSetWithdrawAddress = "op_weight_msg_set_withdraw_address" + OpWeightMsgWithdrawDelegationReward = "op_weight_msg_withdraw_delegation_reward" + OpWeightMsgWithdrawValidatorCommission = "op_weight_msg_withdraw_validator_commission" +) + +// WeightedOperations returns all the operations from the module with their respective weights +func WeightedOperations( + appParams simulation.AppParams, cdc *codec.Codec, ak types.AccountKeeper, + k keeper.Keeper, sk stakingkeeper.Keeper, +) simulation.WeightedOperations { + + var weightMsgSetWithdrawAddress int + appParams.GetOrGenerate(cdc, OpWeightMsgSetWithdrawAddress, &weightMsgSetWithdrawAddress, nil, + func(_ *rand.Rand) { + weightMsgSetWithdrawAddress = simappparams.DefaultWeightMsgSetWithdrawAddress + }, + ) + + var weightMsgWithdrawDelegationReward int + appParams.GetOrGenerate(cdc, OpWeightMsgWithdrawDelegationReward, &weightMsgWithdrawDelegationReward, nil, + func(_ *rand.Rand) { + weightMsgWithdrawDelegationReward = simappparams.DefaultWeightMsgWithdrawDelegationReward + }, + ) + + var weightMsgWithdrawValidatorCommission int + appParams.GetOrGenerate(cdc, OpWeightMsgWithdrawValidatorCommission, &weightMsgWithdrawValidatorCommission, nil, + func(_ *rand.Rand) { + weightMsgWithdrawValidatorCommission = simappparams.DefaultWeightMsgWithdrawValidatorCommission + }, + ) + + return simulation.WeightedOperations{ + simulation.NewWeightedOperation( + weightMsgSetWithdrawAddress, + SimulateMsgSetWithdrawAddress(ak, k), + ), + simulation.NewWeightedOperation( + weightMsgWithdrawDelegationReward, + SimulateMsgWithdrawDelegatorReward(ak, k, sk), + ), + simulation.NewWeightedOperation( + weightMsgWithdrawValidatorCommission, + SimulateMsgWithdrawValidatorCommission(ak, k, sk), + ), + } +} + // SimulateMsgSetWithdrawAddress generates a MsgSetWithdrawAddress with random values. // nolint: funlen func SimulateMsgSetWithdrawAddress(ak types.AccountKeeper, k keeper.Keeper) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, ) (simulation.OperationMsg, []simulation.FutureOperation, error) { - if !k.GetWithdrawAddrEnabled(ctx) { return simulation.NoOpMsg(types.ModuleName), nil, nil } @@ -59,9 +108,9 @@ func SimulateMsgSetWithdrawAddress(ak types.AccountKeeper, k keeper.Keeper) simu // SimulateMsgWithdrawDelegatorReward generates a MsgWithdrawDelegatorReward with random values. // nolint: funlen func SimulateMsgWithdrawDelegatorReward(ak types.AccountKeeper, k keeper.Keeper, sk stakingkeeper.Keeper) simulation.Operation { - return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, + return func( + r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, ) (simulation.OperationMsg, []simulation.FutureOperation, error) { - simAccount, _ := simulation.RandomAcc(r, accs) delegations := sk.GetAllDelegatorDelegations(ctx, simAccount.Address) if len(delegations) == 0 { @@ -148,29 +197,3 @@ func SimulateMsgWithdrawValidatorCommission(ak types.AccountKeeper, k keeper.Kee return simulation.NewOperationMsg(msg, true, ""), nil, nil } } - -// SimulateCommunityPoolSpendProposalContent generates random community-pool-spend proposal content -// nolint: funlen -func SimulateCommunityPoolSpendProposalContent(k keeper.Keeper) govsim.ContentSimulator { - return func(r *rand.Rand, ctx sdk.Context, accs []simulation.Account) govtypes.Content { - simAccount, _ := simulation.RandomAcc(r, accs) - - balance := k.GetFeePool(ctx).CommunityPool - if balance.Empty() { - return nil - } - - denomIndex := r.Intn(len(balance)) - amount, err := simulation.RandPositiveInt(r, balance[denomIndex].Amount.TruncateInt()) - if err != nil { - return nil - } - - return types.NewCommunityPoolSpendProposal( - simulation.RandStringOfLength(r, 10), - simulation.RandStringOfLength(r, 100), - simAccount.Address, - sdk.NewCoins(sdk.NewCoin(balance[denomIndex].Denom, amount)), - ) - } -} diff --git a/x/distribution/simulation/proposals.go b/x/distribution/simulation/proposals.go new file mode 100644 index 000000000000..cd6fcb1b7506 --- /dev/null +++ b/x/distribution/simulation/proposals.go @@ -0,0 +1,52 @@ +package simulation + +import ( + "math/rand" + + simappparams "github.com/cosmos/cosmos-sdk/simapp/params" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/distribution/keeper" + "github.com/cosmos/cosmos-sdk/x/distribution/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/cosmos/cosmos-sdk/x/simulation" +) + +// OpWeightSubmitCommunitySpendProposal app params key for community spend proposal +const OpWeightSubmitCommunitySpendProposal = "op_weight_submit_community_spend_proposal" + +// ProposalContents defines the module weighted proposals' contents +func ProposalContents(k keeper.Keeper) []simulation.WeightedProposalContent { + return []simulation.WeightedProposalContent{ + { + AppParamsKey: OpWeightSubmitCommunitySpendProposal, + DefaultWeight: simappparams.DefaultWeightCommunitySpendProposal, + ContentSimulatorFn: SimulateCommunityPoolSpendProposalContent(k), + }, + } +} + +// SimulateCommunityPoolSpendProposalContent generates random community-pool-spend proposal content +// nolint: funlen +func SimulateCommunityPoolSpendProposalContent(k keeper.Keeper) simulation.ContentSimulatorFn { + return func(r *rand.Rand, ctx sdk.Context, accs []simulation.Account) govtypes.Content { + simAccount, _ := simulation.RandomAcc(r, accs) + + balance := k.GetFeePool(ctx).CommunityPool + if balance.Empty() { + return nil + } + + denomIndex := r.Intn(len(balance)) + amount, err := simulation.RandPositiveInt(r, balance[denomIndex].Amount.TruncateInt()) + if err != nil { + return nil + } + + return types.NewCommunityPoolSpendProposal( + simulation.RandStringOfLength(r, 10), + simulation.RandStringOfLength(r, 100), + simAccount.Address, + sdk.NewCoins(sdk.NewCoin(balance[denomIndex].Denom, amount)), + ) + } +} diff --git a/x/gov/module.go b/x/gov/module.go index 26b238f1e9df..1ef3a8c0f5cf 100644 --- a/x/gov/module.go +++ b/x/gov/module.go @@ -26,7 +26,7 @@ import ( var ( _ module.AppModule = AppModule{} _ module.AppModuleBasic = AppModuleBasic{} - _ module.AppModuleSimulation = AppModuleSimulation{} + _ module.AppModuleSimulation = AppModule{} ) // AppModuleBasic defines the basic application module used by the gov module. @@ -95,42 +95,22 @@ func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command { //____________________________________________________________________________ -// AppModuleSimulation defines the module simulation functions used by the gov module. -type AppModuleSimulation struct{} - -// RegisterStoreDecoder registers a decoder for gov module's types -func (AppModuleSimulation) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { - sdr[StoreKey] = simulation.DecodeStore -} - -// GenerateGenesisState creates a randomized GenState of the gov module. -func (AppModuleSimulation) GenerateGenesisState(simState *module.SimulationState) { - simulation.RandomizedGenState(simState) -} - -// RandomizedParams creates randomized gov param changes for the simulator. -func (AppModuleSimulation) RandomizedParams(r *rand.Rand) []sim.ParamChange { - return simulation.ParamChanges(r) -} - -//____________________________________________________________________________ - // AppModule implements an application module for the gov module. type AppModule struct { AppModuleBasic - AppModuleSimulation - keeper Keeper - supplyKeeper types.SupplyKeeper + keeper Keeper + accountKeeper types.AccountKeeper + supplyKeeper types.SupplyKeeper } // NewAppModule creates a new AppModule object -func NewAppModule(keeper Keeper, supplyKeeper types.SupplyKeeper) AppModule { +func NewAppModule(keeper Keeper, accountKeeper types.AccountKeeper, supplyKeeper types.SupplyKeeper) AppModule { return AppModule{ - AppModuleBasic: AppModuleBasic{}, - AppModuleSimulation: AppModuleSimulation{}, - keeper: keeper, - supplyKeeper: supplyKeeper, + AppModuleBasic: AppModuleBasic{}, + keeper: keeper, + accountKeeper: accountKeeper, + supplyKeeper: supplyKeeper, } } @@ -189,3 +169,35 @@ func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.Val EndBlocker(ctx, am.keeper) return []abci.ValidatorUpdate{} } + +//____________________________________________________________________________ + +// AppModuleSimulation functions + +// GenerateGenesisState creates a randomized GenState of the gov module. +func (AppModule) GenerateGenesisState(simState *module.SimulationState) { + simulation.RandomizedGenState(simState) +} + +// ProposalContents returns all the gov content functions used to +// simulate governance proposals. +func (AppModule) ProposalContents(_ module.SimulationState) []sim.WeightedProposalContent { + return simulation.ProposalContents() +} + +// RandomizedParams creates randomized gov param changes for the simulator. +func (AppModule) RandomizedParams(r *rand.Rand) []sim.ParamChange { + return simulation.ParamChanges(r) +} + +// RegisterStoreDecoder registers a decoder for gov module's types +func (AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { + sdr[StoreKey] = simulation.DecodeStore +} + +// WeightedOperations returns the all the gov module operations with their respective weights. +func (am AppModule) WeightedOperations(simState module.SimulationState) []sim.WeightedOperation { + return simulation.WeightedOperations( + simState.AppParams, simState.Cdc, + am.accountKeeper, am.keeper, simState.Contents) +} diff --git a/x/gov/simulation/operations.go b/x/gov/simulation/operations.go index ddabe9c238b9..4d33d82bc86c 100644 --- a/x/gov/simulation/operations.go +++ b/x/gov/simulation/operations.go @@ -7,7 +7,9 @@ import ( "time" "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/simapp/helpers" + simappparams "github.com/cosmos/cosmos-sdk/simapp/params" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/gov/keeper" "github.com/cosmos/cosmos-sdk/x/gov/types" @@ -16,16 +18,72 @@ import ( var initialProposalID = uint64(100000000000000) -// ContentSimulator defines a function type alias for generating random proposal -// content. -type ContentSimulator func(r *rand.Rand, ctx sdk.Context, accs []simulation.Account) types.Content +// Simulation operation weights constants +const ( + OpWeightMsgDeposit = "op_weight_msg_deposit" + OpWeightMsgVote = "op_weight_msg_vote" +) + +// WeightedOperations returns all the operations from the module with their respective weights +func WeightedOperations(appParams simulation.AppParams, cdc *codec.Codec, ak types.AccountKeeper, + k keeper.Keeper, wContents []simulation.WeightedProposalContent) simulation.WeightedOperations { + + var ( + weightMsgDeposit int + weightMsgVote int + ) + + appParams.GetOrGenerate(cdc, OpWeightMsgDeposit, &weightMsgDeposit, nil, + func(_ *rand.Rand) { + weightMsgDeposit = simappparams.DefaultWeightMsgDeposit + }, + ) + + appParams.GetOrGenerate(cdc, OpWeightMsgVote, &weightMsgVote, nil, + func(_ *rand.Rand) { + weightMsgVote = simappparams.DefaultWeightMsgVote + }, + ) + + // generate the weighted operations for the proposal contents + var wProposalOps simulation.WeightedOperations + + for _, wContent := range wContents { + wContent := wContent // pin variable + var weight int + appParams.GetOrGenerate(cdc, wContent.AppParamsKey, &weight, nil, + func(_ *rand.Rand) { weight = wContent.DefaultWeight }) + + wProposalOps = append( + wProposalOps, + simulation.NewWeightedOperation( + weight, + SimulateSubmitProposal(ak, k, wContent.ContentSimulatorFn), + ), + ) + } + + wGovOps := simulation.WeightedOperations{ + simulation.NewWeightedOperation( + weightMsgDeposit, + SimulateMsgDeposit(ak, k), + ), + simulation.NewWeightedOperation( + weightMsgVote, + SimulateMsgVote(ak, k), + ), + } + + return append(wProposalOps, wGovOps...) +} // SimulateSubmitProposal simulates creating a msg Submit Proposal // voting on the proposal, and subsequently slashing the proposal. It is implemented using // future operations. // nolint: funlen -func SimulateSubmitProposal(ak types.AccountKeeper, k keeper.Keeper, - contentSim ContentSimulator) simulation.Operation { +func SimulateSubmitProposal( + ak types.AccountKeeper, k keeper.Keeper, contentSim simulation.ContentSimulatorFn, +) simulation.Operation { // The states are: // column 1: All validators vote // column 2: 90% vote @@ -127,14 +185,6 @@ func SimulateSubmitProposal(ak types.AccountKeeper, k keeper.Keeper, } } -// SimulateTextProposalContent returns random text proposal content. -func SimulateTextProposalContent(r *rand.Rand, _ sdk.Context, _ []simulation.Account) types.Content { - return types.NewTextProposal( - simulation.RandStringOfLength(r, 140), - simulation.RandStringOfLength(r, 5000), - ) -} - // SimulateMsgDeposit generates a MsgDeposit with random values. // nolint: funlen func SimulateMsgDeposit(ak types.AccountKeeper, k keeper.Keeper) simulation.Operation { diff --git a/x/gov/simulation/proposals.go b/x/gov/simulation/proposals.go new file mode 100644 index 000000000000..b3d73d15c349 --- /dev/null +++ b/x/gov/simulation/proposals.go @@ -0,0 +1,32 @@ +package simulation + +import ( + "math/rand" + + simappparams "github.com/cosmos/cosmos-sdk/simapp/params" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/cosmos/cosmos-sdk/x/simulation" +) + +// OpWeightSubmitTextProposal app params key for text proposal +const OpWeightSubmitTextProposal = "op_weight_submit_text_proposal" + +// ProposalContents defines the module weighted proposals' contents +func ProposalContents() []simulation.WeightedProposalContent { + return []simulation.WeightedProposalContent{ + { + AppParamsKey: OpWeightSubmitTextProposal, + DefaultWeight: simappparams.DefaultWeightTextProposal, + ContentSimulatorFn: SimulateTextProposalContent, + }, + } +} + +// SimulateTextProposalContent returns a random text proposal content. +func SimulateTextProposalContent(r *rand.Rand, _ sdk.Context, _ []simulation.Account) types.Content { + return types.NewTextProposal( + simulation.RandStringOfLength(r, 140), + simulation.RandStringOfLength(r, 5000), + ) +} diff --git a/x/mint/module.go b/x/mint/module.go index 115150dc9eaa..f0e36e1693d7 100644 --- a/x/mint/module.go +++ b/x/mint/module.go @@ -22,7 +22,7 @@ import ( var ( _ module.AppModule = AppModule{} _ module.AppModuleBasic = AppModuleBasic{} - _ module.AppModuleSimulation = AppModuleSimulation{} + _ module.AppModuleSimulation = AppModule{} ) // AppModuleBasic defines the basic application module used by the mint module. @@ -69,30 +69,9 @@ func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command { //____________________________________________________________________________ -// AppModuleSimulation defines the module simulation functions used by the mint module. -type AppModuleSimulation struct{} - -// RegisterStoreDecoder registers a decoder for mint module's types. -func (AppModuleSimulation) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { - sdr[StoreKey] = simulation.DecodeStore -} - -// GenerateGenesisState creates a randomized GenState of the mint module. -func (AppModuleSimulation) GenerateGenesisState(simState *module.SimulationState) { - simulation.RandomizedGenState(simState) -} - -// RandomizedParams creates randomized mint param changes for the simulator. -func (AppModuleSimulation) RandomizedParams(r *rand.Rand) []sim.ParamChange { - return simulation.ParamChanges(r) -} - -//____________________________________________________________________________ - // AppModule implements an application module for the mint module. type AppModule struct { AppModuleBasic - AppModuleSimulation keeper Keeper } @@ -100,9 +79,8 @@ type AppModule struct { // NewAppModule creates a new AppModule object func NewAppModule(keeper Keeper) AppModule { return AppModule{ - AppModuleBasic: AppModuleBasic{}, - AppModuleSimulation: AppModuleSimulation{}, - keeper: keeper, + AppModuleBasic: AppModuleBasic{}, + keeper: keeper, } } @@ -156,3 +134,32 @@ func (am AppModule) BeginBlock(ctx sdk.Context, _ abci.RequestBeginBlock) { func (AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { return []abci.ValidatorUpdate{} } + +//____________________________________________________________________________ + +// AppModuleSimulation functions + +// GenerateGenesisState creates a randomized GenState of the mint module. +func (AppModule) GenerateGenesisState(simState *module.SimulationState) { + simulation.RandomizedGenState(simState) +} + +// ProposalContents doesn't return any content functions for governance proposals. +func (AppModule) ProposalContents(_ module.SimulationState) []sim.WeightedProposalContent { + return nil +} + +// RandomizedParams creates randomized mint param changes for the simulator. +func (AppModule) RandomizedParams(r *rand.Rand) []sim.ParamChange { + return simulation.ParamChanges(r) +} + +// RegisterStoreDecoder registers a decoder for mint module's types. +func (AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { + sdr[StoreKey] = simulation.DecodeStore +} + +// WeightedOperations doesn't return any mint module operation. +func (AppModule) WeightedOperations(_ module.SimulationState) []sim.WeightedOperation { + return nil +} diff --git a/x/params/module.go b/x/params/module.go index 38b93bd5f00c..5817b482b3b8 100644 --- a/x/params/module.go +++ b/x/params/module.go @@ -2,18 +2,23 @@ package params import ( "encoding/json" + "math/rand" "github.com/gorilla/mux" "github.com/spf13/cobra" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" + "github.com/cosmos/cosmos-sdk/x/params/simulation" "github.com/cosmos/cosmos-sdk/x/params/types" + sim "github.com/cosmos/cosmos-sdk/x/simulation" ) var ( - _ module.AppModuleBasic = AppModuleBasic{} + _ module.AppModuleBasic = AppModuleBasic{} + _ module.AppModuleSimulation = AppModule{} ) // AppModuleBasic defines the basic application module used by the params module. @@ -44,3 +49,44 @@ func (AppModuleBasic) GetTxCmd(_ *codec.Codec) *cobra.Command { return nil } // GetQueryCmd returns no root query command for the params module. func (AppModuleBasic) GetQueryCmd(_ *codec.Codec) *cobra.Command { return nil } + +//____________________________________________________________________________ + +// AppModule implements an application module for the distribution module. +type AppModule struct { + AppModuleBasic +} + +// NewAppModule creates a new AppModule object +func NewAppModule() AppModule { + return AppModule{ + AppModuleBasic: AppModuleBasic{}, + } +} + +//____________________________________________________________________________ + +// AppModuleSimulation functions + +// GenerateGenesisState performs a no-op. +func (AppModule) GenerateGenesisState(simState *module.SimulationState) { +} + +// ProposalContents returns all the params content functions used to +// simulate governance proposals. +func (am AppModule) ProposalContents(simState module.SimulationState) []sim.WeightedProposalContent { + return simulation.ProposalContents(simState.ParamChanges) +} + +// RandomizedParams creates randomized distribution param changes for the simulator. +func (AppModule) RandomizedParams(r *rand.Rand) []sim.ParamChange { + return nil +} + +// RegisterStoreDecoder doesn't register any type. +func (AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) {} + +// WeightedOperations returns the all the gov module operations with their respective weights. +func (am AppModule) WeightedOperations(_ module.SimulationState) []sim.WeightedOperation { + return nil +} diff --git a/x/params/simulation/operations.go b/x/params/simulation/operations.go index 0e2516c5fbe4..ab514e06fec0 100644 --- a/x/params/simulation/operations.go +++ b/x/params/simulation/operations.go @@ -4,16 +4,15 @@ import ( "math/rand" sdk "github.com/cosmos/cosmos-sdk/types" - govsim "github.com/cosmos/cosmos-sdk/x/gov/simulation" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" - "github.com/cosmos/cosmos-sdk/x/params" + "github.com/cosmos/cosmos-sdk/x/params/types" "github.com/cosmos/cosmos-sdk/x/simulation" ) // SimulateParamChangeProposalContent returns random parameter change content. // It will generate a ParameterChangeProposal object with anywhere between 1 and // the total amount of defined parameters changes, all of which have random valid values. -func SimulateParamChangeProposalContent(paramChangePool []simulation.ParamChange) govsim.ContentSimulator { +func SimulateParamChangeProposalContent(paramChangePool []simulation.ParamChange) simulation.ContentSimulatorFn { return func(r *rand.Rand, _ sdk.Context, _ []simulation.Account) govtypes.Content { lenParamChange := len(paramChangePool) @@ -22,7 +21,7 @@ func SimulateParamChangeProposalContent(paramChangePool []simulation.ParamChange } numChanges := simulation.RandIntBetween(r, 1, lenParamChange) - paramChanges := make([]params.ParamChange, numChanges) + paramChanges := make([]types.ParamChange, numChanges) // map from key to empty struct; used only for look-up of the keys of the // parameters that are already in the random set of changes. @@ -41,10 +40,10 @@ func SimulateParamChangeProposalContent(paramChangePool []simulation.ParamChange // add a new distinct parameter to the set of changes and register the key // to avoid further duplicates paramChangesKeys[spc.ComposedKey()] = struct{}{} - paramChanges[i] = params.NewParamChangeWithSubkey(spc.Subspace, spc.Key, spc.Subkey, spc.SimValue(r)) + paramChanges[i] = types.NewParamChangeWithSubkey(spc.Subspace, spc.Key, spc.Subkey, spc.SimValue(r)) } - return params.NewParameterChangeProposal( + return types.NewParameterChangeProposal( simulation.RandStringOfLength(r, 140), // title simulation.RandStringOfLength(r, 5000), // description paramChanges, // set of changes diff --git a/x/params/simulation/proposals.go b/x/params/simulation/proposals.go new file mode 100644 index 000000000000..ad1c37dd88b7 --- /dev/null +++ b/x/params/simulation/proposals.go @@ -0,0 +1,20 @@ +package simulation + +import ( + simappparams "github.com/cosmos/cosmos-sdk/simapp/params" + "github.com/cosmos/cosmos-sdk/x/simulation" +) + +// OpWeightSubmitParamChangeProposal app params key for param change proposal +const OpWeightSubmitParamChangeProposal = "op_weight_submit_param_change_proposal" + +// ProposalContents defines the module weighted proposals' contents +func ProposalContents(paramChanges []simulation.ParamChange) []simulation.WeightedProposalContent { + return []simulation.WeightedProposalContent{ + { + AppParamsKey: OpWeightSubmitParamChangeProposal, + DefaultWeight: simappparams.DefaultWeightParamChangeProposal, + ContentSimulatorFn: SimulateParamChangeProposalContent(paramChanges), + }, + } +} diff --git a/x/simulation/operation.go b/x/simulation/operation.go index d7eaf9cfe9b5..8565b42961d7 100644 --- a/x/simulation/operation.go +++ b/x/simulation/operation.go @@ -199,6 +199,14 @@ type WeightedOperation struct { Op Operation } +// NewWeightedOperation creates a new WeightedOperation instance +func NewWeightedOperation(weight int, op Operation) WeightedOperation { + return WeightedOperation{ + Weight: weight, + Op: op, + } +} + // WeightedOperations is the group of all weighted operations to simulate. type WeightedOperations []WeightedOperation diff --git a/x/simulation/params.go b/x/simulation/params.go index e2bbcfcca055..d3e2af44f15c 100644 --- a/x/simulation/params.go +++ b/x/simulation/params.go @@ -6,6 +6,8 @@ import ( "math/rand" "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" ) const ( @@ -45,7 +47,8 @@ type ParamSimulator func(r *rand.Rand) // GetOrGenerate attempts to get a given parameter by key from the AppParams // object. If it exists, it'll be decoded and returned. Otherwise, the provided -// ParamSimulator is used to generate a random value. +// ParamSimulator is used to generate a random value or default value (eg: in the +// case of operation weights where Rand is not used). func (sp AppParams) GetOrGenerate(cdc *codec.Codec, key string, ptr interface{}, r *rand.Rand, ps ParamSimulator) { if v, ok := sp[key]; ok && v != nil { cdc.MustUnmarshalJSON(v, ptr) @@ -55,6 +58,10 @@ func (sp AppParams) GetOrGenerate(cdc *codec.Codec, key string, ptr interface{}, ps(r) } +// ContentSimulatorFn defines a function type alias for generating random proposal +// content. +type ContentSimulatorFn func(r *rand.Rand, ctx sdk.Context, accs []Account) govtypes.Content + // Params define the parameters necessary for running the simulations type Params struct { PastEvidenceFraction float64 @@ -65,7 +72,7 @@ type Params struct { BlockSizeTransitionMatrix TransitionMatrix } -// RandomParams for simulation +// RandomParams returns random simulation parameters func RandomParams(r *rand.Rand) Params { return Params{ PastEvidenceFraction: r.Float64(), @@ -105,3 +112,14 @@ func NewSimParamChange(subspace, key, subkey string, simVal SimValFn) ParamChang func (spc ParamChange) ComposedKey() string { return fmt.Sprintf("%s/%s/%s", spc.Subspace, spc.Key, spc.Subkey) } + +//----------------------------------------------------------------------------- +// Proposal Contents + +// WeightedProposalContent defines a common struct for proposal contents defined by +// external modules (i.e outside gov) +type WeightedProposalContent struct { + AppParamsKey string // key used to retrieve the value of the weight from the simulation application params + DefaultWeight int // default weight + ContentSimulatorFn ContentSimulatorFn // content simulator function +} diff --git a/x/slashing/module.go b/x/slashing/module.go index 9a179b67d931..47d15cf89937 100644 --- a/x/slashing/module.go +++ b/x/slashing/module.go @@ -18,12 +18,13 @@ import ( "github.com/cosmos/cosmos-sdk/x/slashing/client/rest" "github.com/cosmos/cosmos-sdk/x/slashing/internal/types" "github.com/cosmos/cosmos-sdk/x/slashing/simulation" + stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" ) var ( _ module.AppModule = AppModule{} _ module.AppModuleBasic = AppModuleBasic{} - _ module.AppModuleSimulation = AppModuleSimulation{} + _ module.AppModuleSimulation = AppModule{} ) // AppModuleBasic defines the basic application module used by the slashing module. @@ -74,42 +75,22 @@ func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command { //____________________________________________________________________________ -// AppModuleSimulation defines the module simulation functions used by the slashing module. -type AppModuleSimulation struct{} - -// RegisterStoreDecoder registers a decoder for slashing module's types -func (AppModuleSimulation) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { - sdr[StoreKey] = simulation.DecodeStore -} - -// GenerateGenesisState creates a randomized GenState of the slashing module. -func (AppModuleSimulation) GenerateGenesisState(simState *module.SimulationState) { - simulation.RandomizedGenState(simState) -} - -// RandomizedParams creates randomized slashing param changes for the simulator. -func (AppModuleSimulation) RandomizedParams(r *rand.Rand) []sim.ParamChange { - return simulation.ParamChanges(r) -} - -//____________________________________________________________________________ - // AppModule implements an application module for the slashing module. type AppModule struct { AppModuleBasic - AppModuleSimulation keeper Keeper - stakingKeeper types.StakingKeeper + accountKeeper types.AccountKeeper + stakingKeeper stakingkeeper.Keeper } // NewAppModule creates a new AppModule object -func NewAppModule(keeper Keeper, stakingKeeper types.StakingKeeper) AppModule { +func NewAppModule(keeper Keeper, accountKeeper types.AccountKeeper, stakingKeeper stakingkeeper.Keeper) AppModule { return AppModule{ - AppModuleBasic: AppModuleBasic{}, - AppModuleSimulation: AppModuleSimulation{}, - keeper: keeper, - stakingKeeper: stakingKeeper, + AppModuleBasic: AppModuleBasic{}, + keeper: keeper, + accountKeeper: accountKeeper, + stakingKeeper: stakingKeeper, } } @@ -167,3 +148,33 @@ func (am AppModule) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) { func (AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { return []abci.ValidatorUpdate{} } + +//____________________________________________________________________________ + +// AppModuleSimulation functions + +// GenerateGenesisState creates a randomized GenState of the slashing module. +func (AppModule) GenerateGenesisState(simState *module.SimulationState) { + simulation.RandomizedGenState(simState) +} + +// ProposalContents doesn't return any content functions for governance proposals. +func (AppModule) ProposalContents(_ module.SimulationState) []sim.WeightedProposalContent { + return nil +} + +// RandomizedParams creates randomized slashing param changes for the simulator. +func (AppModule) RandomizedParams(r *rand.Rand) []sim.ParamChange { + return simulation.ParamChanges(r) +} + +// RegisterStoreDecoder registers a decoder for slashing module's types +func (AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { + sdr[StoreKey] = simulation.DecodeStore +} + +// WeightedOperations returns the all the slashing module operations with their respective weights. +func (am AppModule) WeightedOperations(simState module.SimulationState) []sim.WeightedOperation { + return simulation.WeightedOperations(simState.AppParams, simState.Cdc, + am.accountKeeper, am.keeper, am.stakingKeeper) +} diff --git a/x/slashing/simulation/operations.go b/x/slashing/simulation/operations.go index e7b4c6870ac2..992513c924d8 100644 --- a/x/slashing/simulation/operations.go +++ b/x/slashing/simulation/operations.go @@ -5,7 +5,9 @@ import ( "math/rand" "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/simapp/helpers" + simappparams "github.com/cosmos/cosmos-sdk/simapp/params" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/simulation" "github.com/cosmos/cosmos-sdk/x/slashing/internal/keeper" @@ -13,6 +15,32 @@ import ( stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" ) +// Simulation operation weights constants +const ( + OpWeightMsgUnjail = "op_weight_msg_unjail" +) + +// WeightedOperations returns all the operations from the module with their respective weights +func WeightedOperations( + appParams simulation.AppParams, cdc *codec.Codec, ak types.AccountKeeper, + k keeper.Keeper, sk stakingkeeper.Keeper, +) simulation.WeightedOperations { + + var weightMsgUnjail int + appParams.GetOrGenerate(cdc, OpWeightMsgUnjail, &weightMsgUnjail, nil, + func(_ *rand.Rand) { + weightMsgUnjail = simappparams.DefaultWeightMsgUnjail + }, + ) + + return simulation.WeightedOperations{ + simulation.NewWeightedOperation( + weightMsgUnjail, + SimulateMsgUnjail(ak, k, sk), + ), + } +} + // SimulateMsgUnjail generates a MsgUnjail with random values // nolint: funlen func SimulateMsgUnjail(ak types.AccountKeeper, k keeper.Keeper, sk stakingkeeper.Keeper) simulation.Operation { diff --git a/x/staking/module.go b/x/staking/module.go index 75833037d76b..45a06e67244a 100644 --- a/x/staking/module.go +++ b/x/staking/module.go @@ -27,7 +27,7 @@ import ( var ( _ module.AppModule = AppModule{} _ module.AppModuleBasic = AppModuleBasic{} - _ module.AppModuleSimulation = AppModuleSimulation{} + _ module.AppModuleSimulation = AppModule{} ) // AppModuleBasic defines the basic application module used by the staking module. @@ -99,30 +99,9 @@ func (AppModuleBasic) BuildCreateValidatorMsg(cliCtx context.CLIContext, //____________________________________________________________________________ -// AppModuleSimulation defines the module simulation functions used by the staking module. -type AppModuleSimulation struct{} - -// RegisterStoreDecoder registers a decoder for staking module's types -func (AppModuleSimulation) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { - sdr[StoreKey] = simulation.DecodeStore -} - -// GenerateGenesisState creates a randomized GenState of the staking module. -func (AppModuleSimulation) GenerateGenesisState(simState *module.SimulationState) { - simulation.RandomizedGenState(simState) -} - -// RandomizedParams creates randomized staking param changes for the simulator. -func (AppModuleSimulation) RandomizedParams(r *rand.Rand) []sim.ParamChange { - return simulation.ParamChanges(r) -} - -//____________________________________________________________________________ - // AppModule implements an application module for the staking module. type AppModule struct { AppModuleBasic - AppModuleSimulation keeper Keeper accountKeeper types.AccountKeeper @@ -133,11 +112,10 @@ type AppModule struct { func NewAppModule(keeper Keeper, accountKeeper types.AccountKeeper, supplyKeeper types.SupplyKeeper) AppModule { return AppModule{ - AppModuleBasic: AppModuleBasic{}, - AppModuleSimulation: AppModuleSimulation{}, - keeper: keeper, - accountKeeper: accountKeeper, - supplyKeeper: supplyKeeper, + AppModuleBasic: AppModuleBasic{}, + keeper: keeper, + accountKeeper: accountKeeper, + supplyKeeper: supplyKeeper, } } @@ -194,3 +172,33 @@ func (AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {} func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { return EndBlocker(ctx, am.keeper) } + +//____________________________________________________________________________ + +// AppModuleSimulation functions + +// GenerateGenesisState creates a randomized GenState of the staking module. +func (AppModule) GenerateGenesisState(simState *module.SimulationState) { + simulation.RandomizedGenState(simState) +} + +// ProposalContents doesn't return any content functions for governance proposals. +func (AppModule) ProposalContents(_ module.SimulationState) []sim.WeightedProposalContent { + return nil +} + +// RandomizedParams creates randomized staking param changes for the simulator. +func (AppModule) RandomizedParams(r *rand.Rand) []sim.ParamChange { + return simulation.ParamChanges(r) +} + +// RegisterStoreDecoder registers a decoder for staking module's types +func (AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { + sdr[StoreKey] = simulation.DecodeStore +} + +// WeightedOperations returns the all the staking module operations with their respective weights. +func (am AppModule) WeightedOperations(simState module.SimulationState) []sim.WeightedOperation { + return simulation.WeightedOperations(simState.AppParams, simState.Cdc, + am.accountKeeper, am.keeper) +} diff --git a/x/staking/simulation/operations.go b/x/staking/simulation/operations.go index 71513bb19bd3..d2b2cab87d04 100644 --- a/x/staking/simulation/operations.go +++ b/x/staking/simulation/operations.go @@ -6,13 +6,92 @@ import ( "math/rand" "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/simapp/helpers" + simappparams "github.com/cosmos/cosmos-sdk/simapp/params" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/simulation" "github.com/cosmos/cosmos-sdk/x/staking/keeper" "github.com/cosmos/cosmos-sdk/x/staking/types" ) +// Simulation operation weights constants +const ( + OpWeightMsgCreateValidator = "op_weight_msg_create_validator" + OpWeightMsgEditValidator = "op_weight_msg_edit_validator" + OpWeightMsgDelegate = "op_weight_msg_delegate" + OpWeightMsgUndelegate = "op_weight_msg_undelegate" + OpWeightMsgBeginRedelegate = "op_weight_msg_begin_redelegate" +) + +// WeightedOperations returns all the operations from the module with their respective weights +func WeightedOperations( + appParams simulation.AppParams, cdc *codec.Codec, ak types.AccountKeeper, + k keeper.Keeper, +) simulation.WeightedOperations { + + var ( + weightMsgCreateValidator int + weightMsgEditValidator int + weightMsgDelegate int + weightMsgUndelegate int + weightMsgBeginRedelegate int + ) + + appParams.GetOrGenerate(cdc, OpWeightMsgCreateValidator, &weightMsgCreateValidator, nil, + func(_ *rand.Rand) { + weightMsgCreateValidator = simappparams.DefaultWeightMsgCreateValidator + }, + ) + + appParams.GetOrGenerate(cdc, OpWeightMsgEditValidator, &weightMsgEditValidator, nil, + func(_ *rand.Rand) { + weightMsgEditValidator = simappparams.DefaultWeightMsgEditValidator + }, + ) + + appParams.GetOrGenerate(cdc, OpWeightMsgDelegate, &weightMsgDelegate, nil, + func(_ *rand.Rand) { + weightMsgDelegate = simappparams.DefaultWeightMsgDelegate + }, + ) + + appParams.GetOrGenerate(cdc, OpWeightMsgUndelegate, &weightMsgUndelegate, nil, + func(_ *rand.Rand) { + weightMsgUndelegate = simappparams.DefaultWeightMsgUndelegate + }, + ) + + appParams.GetOrGenerate(cdc, OpWeightMsgBeginRedelegate, &weightMsgBeginRedelegate, nil, + func(_ *rand.Rand) { + weightMsgBeginRedelegate = simappparams.DefaultWeightMsgBeginRedelegate + }, + ) + + return simulation.WeightedOperations{ + simulation.NewWeightedOperation( + weightMsgCreateValidator, + SimulateMsgCreateValidator(ak, k), + ), + simulation.NewWeightedOperation( + weightMsgEditValidator, + SimulateMsgEditValidator(ak, k), + ), + simulation.NewWeightedOperation( + weightMsgDelegate, + SimulateMsgDelegate(ak, k), + ), + simulation.NewWeightedOperation( + weightMsgUndelegate, + SimulateMsgUndelegate(ak, k), + ), + simulation.NewWeightedOperation( + weightMsgBeginRedelegate, + SimulateMsgBeginRedelegate(ak, k), + ), + } +} + // SimulateMsgCreateValidator generates a MsgCreateValidator with random values // nolint: funlen func SimulateMsgCreateValidator(ak types.AccountKeeper, k keeper.Keeper) simulation.Operation { diff --git a/x/supply/module.go b/x/supply/module.go index 6c14e8d892cd..307b77865b36 100644 --- a/x/supply/module.go +++ b/x/supply/module.go @@ -70,30 +70,9 @@ func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command { //____________________________________________________________________________ -// AppModuleSimulation defines the module simulation functions used by the supply module. -type AppModuleSimulation struct{} - -// RegisterStoreDecoder registers a decoder for supply module's types -func (AppModuleSimulation) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { - sdr[StoreKey] = simulation.DecodeStore -} - -// GenerateGenesisState creates a randomized GenState of the supply module. -func (AppModuleSimulation) GenerateGenesisState(simState *module.SimulationState) { - simulation.RandomizedGenState(simState) -} - -// RandomizedParams doesn't create any randomized supply param changes for the simulator. -func (AppModuleSimulation) RandomizedParams(_ *rand.Rand) []sim.ParamChange { - return nil -} - -//____________________________________________________________________________ - // AppModule implements an application module for the supply module. type AppModule struct { AppModuleBasic - AppModuleSimulation keeper Keeper ak types.AccountKeeper @@ -102,10 +81,9 @@ type AppModule struct { // NewAppModule creates a new AppModule object func NewAppModule(keeper Keeper, ak types.AccountKeeper) AppModule { return AppModule{ - AppModuleBasic: AppModuleBasic{}, - AppModuleSimulation: AppModuleSimulation{}, - keeper: keeper, - ak: ak, + AppModuleBasic: AppModuleBasic{}, + keeper: keeper, + ak: ak, } } @@ -161,3 +139,32 @@ func (am AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {} func (AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { return []abci.ValidatorUpdate{} } + +//____________________________________________________________________________ + +// AppModuleSimulation functions + +// GenerateGenesisState creates a randomized GenState of the supply module. +func (AppModule) GenerateGenesisState(simState *module.SimulationState) { + simulation.RandomizedGenState(simState) +} + +// ProposalContents doesn't return any content functions for governance proposals. +func (AppModule) ProposalContents(_ module.SimulationState) []sim.WeightedProposalContent { + return nil +} + +// RandomizedParams doesn't create any randomized supply param changes for the simulator. +func (AppModule) RandomizedParams(_ *rand.Rand) []sim.ParamChange { + return nil +} + +// RegisterStoreDecoder registers a decoder for supply module's types +func (AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { + sdr[StoreKey] = simulation.DecodeStore +} + +// WeightedOperations doesn't return any operation for the nft module. +func (AppModule) WeightedOperations(_ module.SimulationState) []sim.WeightedOperation { + return nil +} From 0300a6f6d7a7bb0daeb9d487c9e8931a745aec4f Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Thu, 5 Dec 2019 16:07:29 +0100 Subject: [PATCH 011/529] Small non-breaking UX changes to keys {list,delete} commands (#5366) Add --list-names flag to keys command for short listing. Make keys delete accept multiple key names at once. Usage example: gaiacli keys list -n | xargs gaiacli keys delete --- CHANGELOG.md | 3 +++ client/keys/delete.go | 44 +++++++++++++++++++++------------------- client/keys/list.go | 21 ++++++++++++++++--- client/keys/list_test.go | 9 ++++++++ 4 files changed, 53 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 79947cba3ce3..10436fa612b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -106,6 +106,9 @@ upgrade via: `sudo rm -rf /Library/Developer/CommandLineTools; xcode-select --in correct version via: `pkgutil --pkg-info=com.apple.pkg.CLTools_Executables`. * (keys) [\#5097](https://github.com/cosmos/cosmos-sdk/pull/5097) New `keys migrate` command to assist users migrate their keys to the new keyring. +* (keys) [\#5366](https://github.com/cosmos/cosmos-sdk/pull/5366) `keys list` now accepts a `--list-names` option to list key names only, whilst the `keys delete` +command can delete multiple keys by passing their names as arguments. The aforementioned commands can then be piped together, e.g. +`appcli keys list -n | xargs appcli keys delete` * (modules) [\#4233](https://github.com/cosmos/cosmos-sdk/pull/4233) Add upgrade module that coordinates software upgrades of live chains. * [\#4486](https://github.com/cosmos/cosmos-sdk/issues/4486) Introduce new `PeriodicVestingAccount` vesting account type that allows for arbitrary vesting periods. diff --git a/client/keys/delete.go b/client/keys/delete.go index d2e535105a19..aadc831fe129 100644 --- a/client/keys/delete.go +++ b/client/keys/delete.go @@ -18,27 +18,26 @@ const ( func deleteKeyCommand() *cobra.Command { cmd := &cobra.Command{ - Use: "delete ", - Short: "Delete the given key", - Long: `Delete a key from the store. + Use: "delete ...", + Short: "Delete the given keys", + Long: `Delete keys from the Keybase backend. Note that removing offline or ledger keys will remove only the public key references stored locally, i.e. private keys stored in a ledger device cannot be deleted with the CLI. `, RunE: runDeleteCmd, - Args: cobra.ExactArgs(1), + Args: cobra.MinimumNArgs(1), } cmd.Flags().BoolP(flagYes, "y", false, "Skip confirmation prompt when deleting offline or ledger key references") cmd.Flags().BoolP(flagForce, "f", false, - "Remove the key unconditionally without asking for the passphrase") + "Remove the key unconditionally without asking for the passphrase. Deprecated.") return cmd } func runDeleteCmd(cmd *cobra.Command, args []string) error { - name := args[0] buf := bufio.NewReader(cmd.InOrStdin()) kb, err := NewKeyringFromHomeFlag(buf) @@ -46,31 +45,34 @@ func runDeleteCmd(cmd *cobra.Command, args []string) error { return err } - info, err := kb.Get(name) - if err != nil { - return err - } + for _, name := range args { + info, err := kb.Get(name) + if err != nil { + return err + } - if info.GetType() == keys.TypeLedger || info.GetType() == keys.TypeOffline { - // confirm deletion, unless -y is passed - if !viper.GetBool(flagYes) { - if err := confirmDeletion(buf); err != nil { + if info.GetType() == keys.TypeLedger || info.GetType() == keys.TypeOffline { + // confirm deletion, unless -y is passed + if !viper.GetBool(flagYes) { + if err := confirmDeletion(buf); err != nil { + return err + } + } + + if err := kb.Delete(name, "", true); err != nil { return err } + cmd.PrintErrln("Public key reference deleted") + return nil } + // old password and skip flag arguments are ignored if err := kb.Delete(name, "", true); err != nil { return err } - cmd.PrintErrln("Public key reference deleted") - return nil + cmd.PrintErrln("Key deleted forever (uh oh!)") } - // old password and skip flag arguments are ignored - if err := kb.Delete(name, "", true); err != nil { - return err - } - cmd.PrintErrln("Key deleted forever (uh oh!)") return nil } diff --git a/client/keys/list.go b/client/keys/list.go index da4d4b22240f..45d29a942699 100644 --- a/client/keys/list.go +++ b/client/keys/list.go @@ -2,10 +2,13 @@ package keys import ( "github.com/spf13/cobra" + "github.com/spf13/viper" "github.com/cosmos/cosmos-sdk/client/flags" ) +const flagListNames = "list-names" + func listKeysCmd() *cobra.Command { cmd := &cobra.Command{ Use: "list", @@ -15,18 +18,30 @@ along with their associated name and address.`, RunE: runListCmd, } cmd.Flags().Bool(flags.FlagIndentResponse, false, "Add indent to JSON response") + cmd.Flags().BoolP(flagListNames, "n", false, "List names only") return cmd } -func runListCmd(cmd *cobra.Command, args []string) error { +func runListCmd(cmd *cobra.Command, _ []string) error { kb, err := NewKeyringFromHomeFlag(cmd.InOrStdin()) if err != nil { return err } infos, err := kb.List() - if err == nil { + if err != nil { + return err + } + + if !viper.GetBool(flagListNames) { printInfos(infos) + return nil + } + + cmd.SetOut(cmd.OutOrStdout()) + for _, info := range infos { + cmd.Println(info.GetName()) } - return err + + return nil } diff --git a/client/keys/list_test.go b/client/keys/list_test.go index b8cfb223caef..8f4a5b6411b6 100644 --- a/client/keys/list_test.go +++ b/client/keys/list_test.go @@ -57,10 +57,19 @@ func Test_runListCmd(t *testing.T) { if runningUnattended { mockIn.Reset("testpass1\ntestpass1\n") } + viper.Set(flagListNames, false) viper.Set(flags.FlagHome, tt.kbDir) if err := runListCmd(tt.args.cmd, tt.args.args); (err != nil) != tt.wantErr { t.Errorf("runListCmd() error = %v, wantErr %v", err, tt.wantErr) } + + if runningUnattended { + mockIn.Reset("testpass1\ntestpass1\n") + } + viper.Set(flagListNames, true) + if err := runListCmd(tt.args.cmd, tt.args.args); (err != nil) != tt.wantErr { + t.Errorf("runListCmd() error = %v, wantErr %v", err, tt.wantErr) + } }) } } From 3c2ace95100d47f7fc4f68241fa91c2158ee368a Mon Sep 17 00:00:00 2001 From: Sunny Aggarwal Date: Thu, 5 Dec 2019 12:55:43 -0500 Subject: [PATCH 012/529] Merge PR #5360: Sortable Decimal Bytes --- types/decimal.go | 36 ++++++++++++++++++++++++++++++++++++ types/decimal_test.go | 25 +++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/types/decimal.go b/types/decimal.go index 03934e2145ab..b066c3e43374 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -551,6 +551,42 @@ func (d Dec) Ceil() Dec { //___________________________________________________________________________________ +// MaxSortableDec is the largest Dec that can be passed into SortableDecBytes() +// Its negative form is the least Dec that can be passed in. +var MaxSortableDec = OneDec().Quo(SmallestDec()) + +// ValidSortableDec ensures that a Dec is within the sortable bounds, +// a Dec can't have a precision of less than 10^-18. +// Max sortable decimal was set to the reciprocal of SmallestDec. +func ValidSortableDec(dec Dec) bool { + return dec.Abs().LTE(MaxSortableDec) +} + +// SortableDecBytes returns a byte slice representation of a Dec that can be sorted. +// Left and right pads with 0s so there are 18 digits to left and right of the decimal point. +// For this reason, there is a maximum and minimum value for this, enforced by ValidSortableDec. +func SortableDecBytes(dec Dec) []byte { + if !ValidSortableDec(dec) { + panic("dec must be within bounds") + } + // Instead of adding an extra byte to all sortable decs in order to handle max sortable, we just + // makes its bytes be "max" which comes after all numbers in ASCIIbetical order + if dec.Equal(MaxSortableDec) { + return []byte("max") + } + // For the same reason, we make the bytes of minimum sortable dec be --, which comes before all numbers. + if dec.Equal(MaxSortableDec.Neg()) { + return []byte("--") + } + // We move the negative sign to the front of all the left padded 0s, to make negative numbers come before positive numbers + if dec.IsNegative() { + return append([]byte("-"), []byte(fmt.Sprintf(fmt.Sprintf("%%0%ds", Precision*2+1), dec.Abs().String()))...) + } + return []byte(fmt.Sprintf(fmt.Sprintf("%%0%ds", Precision*2+1), dec.String())) +} + +//___________________________________________________________________________________ + // reuse nil values var ( nilAmino string diff --git a/types/decimal_test.go b/types/decimal_test.go index e51c48fc7fee..ea97a1029a5a 100644 --- a/types/decimal_test.go +++ b/types/decimal_test.go @@ -443,3 +443,28 @@ func TestApproxSqrt(t *testing.T) { require.Equal(t, tc.expected, res, "unexpected result for test case %d, input: %v", i, tc.input) } } + +func TestDecSortableBytes(t *testing.T) { + tests := []struct { + d Dec + want []byte + }{ + {NewDec(0), []byte("000000000000000000.000000000000000000")}, + {NewDec(1), []byte("000000000000000001.000000000000000000")}, + {NewDec(10), []byte("000000000000000010.000000000000000000")}, + {NewDec(12340), []byte("000000000000012340.000000000000000000")}, + {NewDecWithPrec(12340, 4), []byte("000000000000000001.234000000000000000")}, + {NewDecWithPrec(12340, 5), []byte("000000000000000000.123400000000000000")}, + {NewDecWithPrec(12340, 8), []byte("000000000000000000.000123400000000000")}, + {NewDecWithPrec(1009009009009009009, 17), []byte("000000000000000010.090090090090090090")}, + {NewDecWithPrec(-1009009009009009009, 17), []byte("-000000000000000010.090090090090090090")}, + {NewDec(1000000000000000000), []byte("max")}, + {NewDec(-1000000000000000000), []byte("--")}, + } + for tcIndex, tc := range tests { + assert.Equal(t, tc.want, SortableDecBytes(tc.d), "bad String(), index: %v", tcIndex) + } + + assert.Panics(t, func() { SortableDecBytes(NewDec(1000000000000000001)) }) + assert.Panics(t, func() { SortableDecBytes(NewDec(-1000000000000000001)) }) +} From 72ff13eb9722ca08ae3c633622ae7dfe10bdd2fc Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Fri, 6 Dec 2019 16:25:25 +0100 Subject: [PATCH 013/529] [x/simulation] RandSubsetCoins() should return sorted coinset (#5373) Closes: #5372 --- x/simulation/rand_util.go | 2 +- x/simulation/rand_util_test.go | 40 ++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 x/simulation/rand_util_test.go diff --git a/x/simulation/rand_util.go b/x/simulation/rand_util.go index b0c403cf76d1..b494b0fb8aab 100644 --- a/x/simulation/rand_util.go +++ b/x/simulation/rand_util.go @@ -122,7 +122,7 @@ func RandSubsetCoins(r *rand.Rand, coins sdk.Coins) sdk.Coins { } subset = append(subset, sdk.NewCoin(c.Denom, amt)) } - return subset + return subset.Sort() } // DeriveRand derives a new Rand deterministically from another random source. diff --git a/x/simulation/rand_util_test.go b/x/simulation/rand_util_test.go new file mode 100644 index 000000000000..e212fed0ab3d --- /dev/null +++ b/x/simulation/rand_util_test.go @@ -0,0 +1,40 @@ +package simulation_test + +import ( + "math/rand" + "testing" + + "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/simulation" +) + +func TestRandSubsetCoins(t *testing.T) { + tests := []struct { + name string + r *rand.Rand + coins sdk.Coins + }{ + {"seed=1", rand.New(rand.NewSource(1)), mustParseCoins("100stake,2testtoken")}, + {"seed=50", rand.New(rand.NewSource(50)), mustParseCoins("100stake,2testtoken")}, + {"seed=99", rand.New(rand.NewSource(99)), mustParseCoins("100stake,2testtoken")}, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + got := simulation.RandSubsetCoins(tt.r, tt.coins) + gotStringRep := got.String() + sortedStringRep := got.Sort().String() + require.Equal(t, gotStringRep, sortedStringRep) + }) + } +} + +func mustParseCoins(s string) sdk.Coins { + coins, err := sdk.ParseCoins(s) + if err != nil { + panic(err) + } + return coins +} From e648f6c672d6eccb9a53466025bcfcb84b9403ab Mon Sep 17 00:00:00 2001 From: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Date: Fri, 6 Dec 2019 19:18:00 +0100 Subject: [PATCH 014/529] Merge PR #5356: isPositive and minor linter changes --- x/staking/types/commission.go | 2 +- x/staking/types/delegation.go | 57 ++++++++++++++++++++++------------- x/staking/types/genesis.go | 5 +-- x/staking/types/msg.go | 8 ++--- 4 files changed, 44 insertions(+), 28 deletions(-) diff --git a/x/staking/types/commission.go b/x/staking/types/commission.go index 83b3460419c4..f447c452822f 100644 --- a/x/staking/types/commission.go +++ b/x/staking/types/commission.go @@ -40,7 +40,7 @@ func NewCommission(rate, maxRate, maxChangeRate sdk.Dec) Commission { } } -// NewCommission returns an initialized validator commission with a specified +// NewCommissionWithTime returns an initialized validator commission with a specified // update time which should be the current block BFT time. func NewCommissionWithTime(rate, maxRate, maxChangeRate sdk.Dec, updatedAt time.Time) Commission { return Commission{ diff --git a/x/staking/types/delegation.go b/x/staking/types/delegation.go index a3e1fab1bc9b..672edd5a90ed 100644 --- a/x/staking/types/delegation.go +++ b/x/staking/types/delegation.go @@ -52,12 +52,13 @@ func NewDelegation(delegatorAddr sdk.AccAddress, validatorAddr sdk.ValAddress, } } -// return the delegation +// MustMarshalDelegation returns the delegation bytes. Panics if fails func MustMarshalDelegation(cdc *codec.Codec, delegation Delegation) []byte { return cdc.MustMarshalBinaryLengthPrefixed(delegation) } -// return the delegation +// MustUnmarshalDelegation return the unmarshaled delegation from bytes. +// Panics if fails. func MustUnmarshalDelegation(cdc *codec.Codec, value []byte) Delegation { delegation, err := UnmarshalDelegation(cdc, value) if err != nil { @@ -137,7 +138,7 @@ func NewUnbondingDelegation(delegatorAddr sdk.AccAddress, } } -// NewUnbondingDelegation - create a new unbonding delegation object +// NewUnbondingDelegationEntry - create a new unbonding delegation object func NewUnbondingDelegationEntry(creationHeight int64, completionTime time.Time, balance sdk.Int) UnbondingDelegationEntry { @@ -251,7 +252,7 @@ func NewRedelegation(delegatorAddr sdk.AccAddress, validatorSrcAddr, } } -// NewRedelegation - create a new redelegation object +// NewRedelegationEntry - create a new redelegation object func NewRedelegationEntry(creationHeight int64, completionTime time.Time, balance sdk.Int, sharesDst sdk.Dec) RedelegationEntry { @@ -283,12 +284,12 @@ func (d *Redelegation) RemoveEntry(i int64) { d.Entries = append(d.Entries[:i], d.Entries[i+1:]...) } -// return the redelegation +// MustMarshalRED returns the Redelegation bytes. Panics if fails. func MustMarshalRED(cdc *codec.Codec, red Redelegation) []byte { return cdc.MustMarshalBinaryLengthPrefixed(red) } -// unmarshal a redelegation from a store value +// MustUnmarshalRED unmarshals a redelegation from a store value. Panics if fails. func MustUnmarshalRED(cdc *codec.Codec, value []byte) Redelegation { red, err := UnmarshalRED(cdc, value) if err != nil { @@ -297,7 +298,7 @@ func MustUnmarshalRED(cdc *codec.Codec, value []byte) Redelegation { return red } -// unmarshal a redelegation from a store value +// UnmarshalRED unmarshals a redelegation from a store value func UnmarshalRED(cdc *codec.Codec, value []byte) (red Redelegation, err error) { err = cdc.UnmarshalBinaryLengthPrefixed(value, &red) return red, err @@ -355,8 +356,14 @@ type DelegationResponse struct { Balance sdk.Coin `json:"balance" yaml:"balance"` } -func NewDelegationResp(d sdk.AccAddress, v sdk.ValAddress, s sdk.Dec, b sdk.Coin) DelegationResponse { - return DelegationResponse{NewDelegation(d, v, s), b} +// NewDelegationResp creates a new DelegationResponse instance +func NewDelegationResp( + delegatorAddr sdk.AccAddress, validatorAddr sdk.ValAddress, shares sdk.Dec, balance sdk.Coin, +) DelegationResponse { + return DelegationResponse{ + Delegation: NewDelegation(delegatorAddr, validatorAddr, shares), + Balance: balance, + } } // String implements the Stringer interface for DelegationResponse. @@ -397,6 +404,20 @@ type RedelegationResponse struct { Entries []RedelegationEntryResponse `json:"entries" yaml:"entries"` } +// NewRedelegationResponse crates a new RedelegationEntryResponse instance. +func NewRedelegationResponse( + delegatorAddr sdk.AccAddress, validatorSrc, validatorDst sdk.ValAddress, entries []RedelegationEntryResponse, +) RedelegationResponse { + return RedelegationResponse{ + Redelegation: Redelegation{ + DelegatorAddress: delegatorAddr, + ValidatorSrcAddress: validatorSrc, + ValidatorDstAddress: validatorDst, + }, + Entries: entries, + } +} + // RedelegationEntryResponse is equivalent to a RedelegationEntry except that it // contains a balance in addition to shares which is more suitable for client // responses. @@ -405,21 +426,15 @@ type RedelegationEntryResponse struct { Balance sdk.Int `json:"balance"` } -func NewRedelegationResponse(d sdk.AccAddress, vSrc, vDst sdk.ValAddress, entries []RedelegationEntryResponse) RedelegationResponse { - return RedelegationResponse{ - Redelegation{ - DelegatorAddress: d, - ValidatorSrcAddress: vSrc, - ValidatorDstAddress: vDst, - }, - entries, +// NewRedelegationEntryResponse creates a new RedelegationEntryResponse instance. +func NewRedelegationEntryResponse( + creationHeight int64, completionTime time.Time, sharesDst sdk.Dec, initialBalance, balance sdk.Int) RedelegationEntryResponse { + return RedelegationEntryResponse{ + RedelegationEntry: NewRedelegationEntry(creationHeight, completionTime, initialBalance, sharesDst), + Balance: balance, } } -func NewRedelegationEntryResponse(ch int64, ct time.Time, s sdk.Dec, ib, b sdk.Int) RedelegationEntryResponse { - return RedelegationEntryResponse{NewRedelegationEntry(ch, ct, ib, s), b} -} - // String implements the Stringer interface for RedelegationResp. func (r RedelegationResponse) String() string { out := fmt.Sprintf(`Redelegations between: diff --git a/x/staking/types/genesis.go b/x/staking/types/genesis.go index 52e4fdef87af..943ab4fb31f0 100644 --- a/x/staking/types/genesis.go +++ b/x/staking/types/genesis.go @@ -16,12 +16,13 @@ type GenesisState struct { Exported bool `json:"exported" yaml:"exported"` } -// Last validator power, needed for validator set update logic +// LastValidatorPower required for validator set update logic type LastValidatorPower struct { Address sdk.ValAddress Power int64 } +// NewGenesisState creates a new GenesisState instanc e func NewGenesisState(params Params, validators []Validator, delegations []Delegation) GenesisState { return GenesisState{ Params: params, @@ -30,7 +31,7 @@ func NewGenesisState(params Params, validators []Validator, delegations []Delega } } -// get raw genesis raw message for testing +// DefaultGenesisState gets the raw genesis raw message for testing func DefaultGenesisState() GenesisState { return GenesisState{ Params: DefaultParams(), diff --git a/x/staking/types/msg.go b/x/staking/types/msg.go index 1efe19530de9..fa44090ac747 100644 --- a/x/staking/types/msg.go +++ b/x/staking/types/msg.go @@ -162,7 +162,7 @@ func (msg MsgCreateValidator) ValidateBasic() sdk.Error { if !sdk.AccAddress(msg.ValidatorAddress).Equals(msg.DelegatorAddress) { return ErrBadValidatorAddr(DefaultCodespace) } - if msg.Value.Amount.LTE(sdk.ZeroInt()) { + if !msg.Value.Amount.IsPositive() { return ErrBadDelegationAmount(DefaultCodespace) } if msg.Description == (Description{}) { @@ -289,7 +289,7 @@ func (msg MsgDelegate) ValidateBasic() sdk.Error { if msg.ValidatorAddress.Empty() { return ErrNilValidatorAddr(DefaultCodespace) } - if msg.Amount.Amount.LTE(sdk.ZeroInt()) { + if !msg.Amount.Amount.IsPositive() { return ErrBadDelegationAmount(DefaultCodespace) } return nil @@ -345,7 +345,7 @@ func (msg MsgBeginRedelegate) ValidateBasic() sdk.Error { if msg.ValidatorDstAddress.Empty() { return ErrNilValidatorAddr(DefaultCodespace) } - if msg.Amount.Amount.LTE(sdk.ZeroInt()) { + if !msg.Amount.Amount.IsPositive() { return ErrBadSharesAmount(DefaultCodespace) } return nil @@ -390,7 +390,7 @@ func (msg MsgUndelegate) ValidateBasic() sdk.Error { if msg.ValidatorAddress.Empty() { return ErrNilValidatorAddr(DefaultCodespace) } - if msg.Amount.Amount.LTE(sdk.ZeroInt()) { + if !msg.Amount.Amount.IsPositive() { return ErrBadSharesAmount(DefaultCodespace) } return nil From 18e2848d4eb4b6471bcb70e72bb7d48a04ef6f41 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 9 Dec 2019 10:30:00 +0100 Subject: [PATCH 015/529] Bump github.com/spf13/viper from 1.5.0 to 1.6.1 (#5375) Bumps [github.com/spf13/viper](https://github.com/spf13/viper) from 1.5.0 to 1.6.1. - [Release notes](https://github.com/spf13/viper/releases) - [Commits](https://github.com/spf13/viper/compare/v1.5.0...v1.6.1) Signed-off-by: dependabot-preview[bot] --- go.mod | 2 +- go.sum | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index dc54f5cf4423..9a659ce9dd40 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/spf13/cobra v0.0.5 github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 - github.com/spf13/viper v1.5.0 + github.com/spf13/viper v1.6.1 github.com/stretchr/testify v1.4.0 github.com/tendermint/btcd v0.1.1 github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 diff --git a/go.sum b/go.sum index 7b6a998a73be..bc31fcd7f750 100644 --- a/go.sum +++ b/go.sum @@ -107,6 +107,7 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= @@ -131,6 +132,7 @@ github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d h1:Z+RDyXzjKE0i2sTjZ/b1uxiGtPhFy34Ou/Tk0qwN0kM= github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d/go.mod h1:JJNrCn9otv/2QP4D7SMJBgaleKpOf66PnW6F5WGNRIc= @@ -202,6 +204,8 @@ github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/snikch/goodman v0.0.0-20171125024755-10e37e294daa/go.mod h1:oJyF+mSPHbB5mVY2iO9KV3pTt/QbIkGaO8gQ2WrDbP4= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= @@ -225,6 +229,8 @@ github.com/spf13/viper v1.3.2 h1:VUFqw5KcqRf7i70GOzW7N+Q7+gxVBkSSqiXB12+JQ4M= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.5.0 h1:GpsTwfsQ27oS/Aha/6d1oD7tpKIqWnOA6tgOX9HHkt4= github.com/spf13/viper v1.5.0/go.mod h1:AkYRkVJF8TkSG/xet6PzXX+l39KhhXa2pdqVSxnTcn4= +github.com/spf13/viper v1.6.1 h1:VPZzIkznI1YhVMRi6vNFLHSwhnhReBfgTxIPccpfdZk= +github.com/spf13/viper v1.6.1/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= @@ -318,6 +324,7 @@ golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= @@ -343,6 +350,8 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= From 7d7821b9af132b0f6131640195326aa02b6751db Mon Sep 17 00:00:00 2001 From: Marko Date: Mon, 9 Dec 2019 12:32:53 +0100 Subject: [PATCH 016/529] Add Scaffolding tooling to README (#5376) - added scaffolding tool to README - removed unnecessary docs Signed-off-by: Marko Baricevic --- README.md | 4 ++++ docs/core/ocap.md | 14 -------------- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 3d3e8ffd9d54..54338119ab2b 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,10 @@ For more, please go to the [Cosmos SDK Docs](./docs/README.md) The Cosmos Hub application, `gaia`, has moved to its [own repository](https://github.com/cosmos/gaia). Go there to join the Cosmos Hub mainnet and more. +## Scaffolding + +If you are starting a new app or a new module we provide a [scaffolding tool](https://github.com/cosmos/scaffold) to help you get started and speed up development. If you have any questions or find a bug, feel free to open an issue in the repo. + ## Disambiguation This Cosmos-SDK project is not related to the [React-Cosmos](https://github.com/react-cosmos/react-cosmos) project (yet). Many thanks to Evan Coury and Ovidiu (@skidding) for this Github organization name. As per our agreement, this disambiguation notice will stay here. diff --git a/docs/core/ocap.md b/docs/core/ocap.md index ff0fa78cd684..8322ce4ec5dc 100644 --- a/docs/core/ocap.md +++ b/docs/core/ocap.md @@ -42,20 +42,6 @@ foundation of an object capability system. For an introduction to object-capabilities, see [this article](https://en.wikipedia.org/wiki/Object-capability_model). -Strictly speaking, Golang does not implement object capabilities -completely, because of several issues: - -- pervasive ability to import primitive modules (e.g. "unsafe", "os") -- pervasive ability to [override module vars](https://github.com/golang/go/issues/23161) -- data-race vulnerability where 2+ goroutines can create illegal interface values - -The first is easy to catch by auditing imports and using a proper -dependency version control system like Dep. The second and third are -unfortunate but it can be audited with some cost. - -Perhaps [Go2 will implement the object capability -model](https://github.com/golang/go/issues/23157). - ## Ocaps in practice The idea is to only reveal what is necessary to get the work done. From b18bd06a364e6ac15f22423e6b66a9feb3eeae93 Mon Sep 17 00:00:00 2001 From: gamarin2 Date: Tue, 10 Dec 2019 15:29:46 +0100 Subject: [PATCH 017/529] Merge PR #5379: New docs V1 (merge master-docs to master) --- CHANGELOG.md | 10 + CONTRIBUTING.md | 7 +- README.md | 11 +- docs/.vuepress/components/PageHistory.vue | 18 - docs/.vuepress/config.js | 222 +- docs/.vuepress/enhanceApp.js | 8 - docs/.vuepress/public/logo-bw.svg | 8 + docs/.vuepress/public/logo.svg | 18 + docs/.vuepress/styles/index.styl | 3 + docs/DOCS_README.md | 38 +- docs/README.md | 84 +- docs/Screen Shot 2019-10-17 at 15.07.22.png | Bin 0 -> 45486 bytes docs/architecture/{README.MD => README.md} | 6 + .../architecture/readme.md~origin_master-docs | 5 + docs/basics/README.md | 16 + docs/basics/accounts.md | 134 + docs/basics/app-anatomy.md | 227 +- docs/basics/gas-fees.md | 88 + docs/basics/tx-lifecycle.md | 92 +- docs/building-modules/README.md | 95 +- docs/building-modules/beginblock-endblock.md | 38 + docs/building-modules/genesis.md | 59 + docs/building-modules/handler.md | 76 + docs/building-modules/intro.md | 93 + docs/building-modules/invariants.md | 88 + docs/building-modules/keeper.md | 78 + docs/building-modules/messages-and-queries.md | 75 + docs/building-modules/module-interfaces.md | 167 + docs/building-modules/module-manager.md | 142 + docs/building-modules/querier.md | 53 + docs/building-modules/structure.md | 13 +- docs/cn/README.md | 5 + docs/core/README.md | 20 + docs/core/baseapp.md | 225 +- docs/core/context.md | 117 + docs/core/encoding.md | 44 + docs/core/events.md | 91 + docs/core/node.md | 70 + docs/core/ocap.md | 21 +- docs/core/store.md | 237 + docs/core/transactions.md | 91 + docs/interfaces/README.md | 15 + docs/interfaces/cli.md | 137 + docs/interfaces/clients.md | 26 - docs/interfaces/interfaces-intro.md | 43 + docs/interfaces/lite/readme.md | 5 + docs/interfaces/lite/specification.md | 2 +- docs/interfaces/query-lifecycle.md | 161 + docs/interfaces/rest.md | 60 + docs/interfaces/service-providers.md | 196 - docs/intro/README.md | 16 + docs/intro/{intro.md => overview.md} | 18 +- docs/intro/sdk-app-architecture.md | 30 +- docs/intro/sdk-design.md | 22 +- docs/intro/why-app-specific.md | 21 +- docs/kr/README.md | 5 + docs/package-lock.json | 5432 ++++++++--------- docs/package.json | 17 +- docs/post.sh | 3 + docs/pre.sh | 12 + docs/ru/readme.md | 7 +- docs/spec/README.md | 19 +- docs/using-the-sdk/README.md | 10 + .../using-the-sdk/simulation.md | 0 x/README.md | 22 + x/auth/spec/README.md | 2 +- x/bank/spec/README.md | 2 +- x/crisis/spec/README.md | 2 +- x/distribution/spec/README.md | 2 +- x/gov/spec/README.md | 2 +- x/mint/spec/README.md | 2 +- x/params/spec/README.md | 2 +- x/slashing/spec/README.md | 2 +- x/staking/spec/README.md | 2 +- x/supply/spec/README.md | 2 +- 75 files changed, 5561 insertions(+), 3631 deletions(-) delete mode 100644 docs/.vuepress/components/PageHistory.vue delete mode 100644 docs/.vuepress/enhanceApp.js create mode 100644 docs/.vuepress/public/logo-bw.svg create mode 100644 docs/.vuepress/public/logo.svg create mode 100644 docs/.vuepress/styles/index.styl create mode 100644 docs/Screen Shot 2019-10-17 at 15.07.22.png rename docs/architecture/{README.MD => README.md} (97%) create mode 100644 docs/architecture/readme.md~origin_master-docs create mode 100644 docs/basics/README.md create mode 100644 docs/basics/accounts.md create mode 100644 docs/basics/gas-fees.md create mode 100644 docs/building-modules/beginblock-endblock.md create mode 100644 docs/building-modules/genesis.md create mode 100644 docs/building-modules/handler.md create mode 100644 docs/building-modules/intro.md create mode 100644 docs/building-modules/invariants.md create mode 100644 docs/building-modules/keeper.md create mode 100644 docs/building-modules/messages-and-queries.md create mode 100644 docs/building-modules/module-interfaces.md create mode 100644 docs/building-modules/module-manager.md create mode 100644 docs/building-modules/querier.md create mode 100644 docs/core/README.md create mode 100644 docs/core/context.md create mode 100644 docs/core/encoding.md create mode 100644 docs/core/events.md create mode 100644 docs/core/node.md create mode 100644 docs/core/store.md create mode 100644 docs/core/transactions.md create mode 100644 docs/interfaces/README.md create mode 100644 docs/interfaces/cli.md delete mode 100644 docs/interfaces/clients.md create mode 100644 docs/interfaces/interfaces-intro.md create mode 100644 docs/interfaces/query-lifecycle.md create mode 100644 docs/interfaces/rest.md delete mode 100644 docs/interfaces/service-providers.md create mode 100644 docs/intro/README.md rename docs/intro/{intro.md => overview.md} (69%) create mode 100755 docs/post.sh create mode 100755 docs/pre.sh create mode 100644 docs/using-the-sdk/README.md rename docs/{concepts => }/using-the-sdk/simulation.md (100%) create mode 100644 x/README.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 10436fa612b2..44fcf198b728 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -194,6 +194,14 @@ caching through `CommitKVStoreCacheManager`. Any application wishing to utilize must set it in their app via a `BaseApp` option. The `BaseApp` docs have been drastically improved to detail this new feature and how state transitions occur. * (docs/spec) All module specs moved into their respective module dir in x/ (i.e. docs/spec/staking -->> x/staking/spec) +* (docs/) [\#5379](https://github.com/cosmos/cosmos-sdk/pull/5379) Major documentation refactor, including: + * (docs/intro/) Add and improve introduction material for newcomers. + * (docs/basics/) Add documentation about basic concepts of the cosmos sdk such as the anatomy of an SDK application, the transaction lifecycle or accounts. + * (docs/core/) Add documentation about core conepts of the cosmos sdk such as `baseapp`, `server`, `store`s, `context` and more. + * (docs/building-modules/) Add reference documentation on concepts relevant for module developers (`keeper`, `handler`, `messages`, `queries`,...). + * (docs/interfaces/) Add documentation on building interfaces for the Cosmos SDK. + * Redesigned user interface that features new dynamically generated sidebar, build-time code embedding from GitHub, new homepage as well as many other improvements. + ### Bug Fixes @@ -206,6 +214,8 @@ to detail this new feature and how state transitions occur. * (baseapp) [\#5350](https://github.com/cosmos/cosmos-sdk/issues/5350) Allow a node to restart successfully after a `halt-height` or `halt-time` has been triggered. + + ## [v0.37.4] - 2019-11-04 ### Improvements diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 07b8b3d94055..139c9a4576ec 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -92,10 +92,9 @@ All PRs require two Reviews before merge (except docs changes, or variable name- If you open a PR on the Cosmos SDK, it is mandatory to update the relevant documentation in /docs. -- If your change relates to the core SDK (baseapp, store, ...), please update the docs/cosmos-hub folder and possibly the docs/spec folder. -- If your changes relate specifically to the gaia application (not including modules), please modify the docs/cosmos-hub folder. -- If your changes relate to a module, please update the module's spec in docs/spec. If the module is used by gaia, you might also need to modify docs/cosmos-hub. -- If your changes relate to the core of the CLI or Light-client (not specifically to module's CLI/Rest), please modify the docs/clients folder. +- If your change relates to the core SDK (baseapp, store, ...), please update the `docs/basics/`, `docs/core/` and/or `docs/building-modules/` folders. +- If your changes relate to the core of the CLI or Light-client (not specifically to module's CLI/Rest), please modify the `docs/interfaces/` folder. +- If your changes relate to a module, please update the module's spec in `x/moduleName/docs/spec/`. ## Forking diff --git a/README.md b/README.md index 54338119ab2b..25dae82fdf76 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,8 @@ +--- +parent: + order: false +--- + # Cosmos SDK ![banner](docs/cosmos-sdk-image.jpg) @@ -12,7 +17,7 @@ [![riot.im](https://img.shields.io/badge/riot.im-JOIN%20CHAT-green.svg)](https://riot.im/app/#/room/#cosmos-sdk:matrix.org) The Cosmos-SDK is a framework for building blockchain applications in Golang. -It is being used to build `Gaia`, the first implementation of the Cosmos Hub. +It is being used to build [`Gaia`](https://github.com/cosmos/gaia), the first implementation of the Cosmos Hub. **WARNING**: The SDK has mostly stabilized, but we are still making some breaking changes. @@ -23,9 +28,9 @@ breaking changes. To learn how the SDK works from a high-level perspective, go to the [SDK Intro](./docs/intro/intro.md). -If you want to get started quickly and learn how to build on top of the SDK, please follow the [SDK Application Tutorial](https://github.com/cosmos/sdk-application-tutorial). You can also fork the tutorial's repo to get started building your own Cosmos SDK application. +If you want to get started quickly and learn how to build on top of the SDK, please follow the [SDK Application Tutorial](https://github.com/cosmos/sdk-application-tutorial). You can also fork the tutorial's repository to get started building your own Cosmos SDK application. -For more, please go to the [Cosmos SDK Docs](./docs/README.md) +For more, please go to the [Cosmos SDK Docs](./docs/). ## Cosmos Hub Mainnet diff --git a/docs/.vuepress/components/PageHistory.vue b/docs/.vuepress/components/PageHistory.vue deleted file mode 100644 index 22f2a7bd50ce..000000000000 --- a/docs/.vuepress/components/PageHistory.vue +++ /dev/null @@ -1,18 +0,0 @@ - - - diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index 84b4407653e5..4502495d68f3 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -1,95 +1,161 @@ -const glob = require("glob"); -const markdownIt = require("markdown-it"); -const meta = require("markdown-it-meta"); -const fs = require("fs"); -const _ = require("lodash"); - -const sidebar = (directory, array) => { - return array.map(i => { - const children = _.sortBy( - glob - .sync(`./${directory}/${i[1]}/*.md`) - .map(path => { - const md = new markdownIt(); - const file = fs.readFileSync(path, "utf8"); - md.use(meta); - md.render(file); - const order = md.meta.order; - return { path, order }; - }) - .filter(f => f.order !== false), - ["order", "path"] - ) - .map(f => f.path) - .filter(f => !f.match("readme")); - return { - title: i[0], - children - }; - }); -}; - module.exports = { + theme: "cosmos", title: "Cosmos SDK", - base: process.env.VUEPRESS_BASE || "/", + markdown: { + anchor: { + permalinkSymbol: "" + } + }, locales: { - "/": { - lang: "en-US" + '/': { + lang: 'en-US' + }, + 'kr': { + lang: "kr" }, - "/ru/": { - lang: "ru" + 'cn': { + lang: 'cn' }, + 'ru': { + lang: 'ru' + } }, + base: process.env.VUEPRESS_BASE || "/", themeConfig: { repo: "cosmos/cosmos-sdk", + docsRepo: "cosmos/cosmos-sdk", docsDir: "docs", editLinks: true, - docsBranch: "master", - locales: { - "/": { - label: "English", - sidebar: sidebar("", [ - ["Intro", "intro"], - ["Basics", "basics"], - ["SDK Core", "core"], - ["About Modules", "modules"], - ["Using the SDK", "sdk"], - ["Interfaces", "interfaces"] - ]) + label: "sdk", + sidebar: [ + { + title: "Using the SDK", + children: [ + { + title: "Modules", + directory: true, + path: "/modules" + }, + ] }, - "/ru/": { - label: "Русский", - sidebar: sidebar("ru", [ - ["Введение", "intro"], - ["Основы", "basics"], - ["SDK Core", "core"], - ["Модули", "modules"], - ["Используем SDK", "sdk"], - ["Интерфейсы", "interfaces"] - ]) + { + title: "Resources", + children: [ + { + title: "Tutorials", + path: "https://github.com/cosmos/sdk-application-tutorial" + }, + { + title: "SDK API Reference", + path: "https://godoc.org/github.com/cosmos/cosmos-sdk" + }, + { + title: "REST API Spec", + path: "https://cosmos.network/rpc/" + } + ] + } + ], + gutter: { + title: "Help & Support", + editLink: true, + chat: { + title: "Riot Chat", + text: "Chat with Cosmos developers on Riot Chat.", + url: "https://riot.im/app/#/room/#cosmos-sdk:matrix.org", + bg: "linear-gradient(225.11deg, #2E3148 0%, #161931 95.68%)" }, - '/kr/': { - label: '한국어', - sidebar: sidebar('kr', [ - ['소개', 'intro'], - ['기초', 'basics'], - ['SDK Core', 'core'], - ['모듈들', 'modules'], - ['프로그램 사용', 'sdk'], - ['인터페이스', 'interfaces'], - ]), + forum: { + title: "Cosmos SDK Forum", + text: "Join the SDK Developer Forum to learn more.", + url: "https://forum.cosmos.network/", + bg: "linear-gradient(225deg, #46509F -1.08%, #2F3564 95.88%)", + logo: "cosmos" }, - '/cn/': { - label: '中文', - sidebar: sidebar('cn', [ - ['介绍', 'intro'], - ['基本', 'basics'], - ['SDK Core', 'core'], - ['模块', 'modules'], - ['使用该程序', 'sdk'], - ['接口', 'interfaces'], - ]), + github: { + title: "Found an Issue?", + text: "Help us improve this page by suggesting edits on GitHub." + } + }, + footer: { + logo: "/logo-bw.svg", + textLink: { + text: "cosmos.network", + url: "https://cosmos.network" }, + services: [ + { + service: "medium", + url: "https://blog.cosmos.network/" + }, + { + service: "twitter", + url: "https://twitter.com/cosmos" + }, + { + service: "linkedin", + url: "https://www.linkedin.com/company/tendermint/" + }, + { + service: "reddit", + url: "https://reddit.com/r/cosmosnetwork" + }, + { + service: "telegram", + url: "https://t.me/cosmosproject" + }, + { + service: "youtube", + url: "https://www.youtube.com/c/CosmosProject" + } + ], + smallprint: + "The development of the Cosmos project is led primarily by Tendermint Inc., the for-profit entity which also maintains this website. Funding for this development comes primarily from the Interchain Foundation, a Swiss non-profit.", + links: [ + { + title: "Documentation", + children: [ + { + title: "Cosmos SDK", + url: "https://cosmos.network/docs" + }, + { + title: "Cosmos Hub", + url: "https://hub.cosmos.network/" + } + ] + }, + { + title: "Community", + children: [ + { + title: "Cosmos blog", + url: "https://blog.cosmos.network/" + }, + { + title: "Forum", + url: "https://forum.cosmos.network/" + }, + { + title: "Chat", + url: "https://riot.im/app/#/room/#cosmos-sdk:matrix.org" + } + ] + }, + { + title: "Contributing", + children: [ + { + title: "Contributing to the docs", + url: "https://github.com/cosmos/cosmos-sdk/tree/master/docs" + }, + { + title: "Source code on GitHub", + url: "https://github.com/cosmos/cosmos-sdk/" + } + ] + } + ] } }, plugins: [ diff --git a/docs/.vuepress/enhanceApp.js b/docs/.vuepress/enhanceApp.js deleted file mode 100644 index 6deeedeb0558..000000000000 --- a/docs/.vuepress/enhanceApp.js +++ /dev/null @@ -1,8 +0,0 @@ -import axios from 'axios' -import Vue from 'vue' - -Vue.use({ - install (Vue) { - Vue.prototype.$axios = axios.create() - } -}) \ No newline at end of file diff --git a/docs/.vuepress/public/logo-bw.svg b/docs/.vuepress/public/logo-bw.svg new file mode 100644 index 000000000000..f2575260a761 --- /dev/null +++ b/docs/.vuepress/public/logo-bw.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/docs/.vuepress/public/logo.svg b/docs/.vuepress/public/logo.svg new file mode 100644 index 000000000000..95ca6d30da5b --- /dev/null +++ b/docs/.vuepress/public/logo.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/docs/.vuepress/styles/index.styl b/docs/.vuepress/styles/index.styl new file mode 100644 index 000000000000..66affa704b7b --- /dev/null +++ b/docs/.vuepress/styles/index.styl @@ -0,0 +1,3 @@ +:root + --accent-color #5064fb + --background #161931 \ No newline at end of file diff --git a/docs/DOCS_README.md b/docs/DOCS_README.md index 609044c5192f..96986bef8030 100644 --- a/docs/DOCS_README.md +++ b/docs/DOCS_README.md @@ -1,6 +1,13 @@ # Updating the docs -If you want to open a PR on the Cosmos SDK to update the documentation, please follow the guidelines in the [`CONTRIBUTING.md`](https://github.com/cosmos/cosmos-sdk/tree/master/CONTRIBUTING.md) +If you want to open a PR on the Cosmos SDK to update the documentation, please follow the guidelines in the [`CONTRIBUTING.md`](https://github.com/cosmos/cosmos-sdk/tree/master/CONTRIBUTING.md#updating-documentation) + +## Translating + +- Docs translations live in a `docs/country-code/` folder, where `country-code` stands for the country code of the language used (`cn` for Chinese, `kr` for Korea, `fr` for France, ...). +- Always translate content living on `master`. +- Only content under `/docs/intro/`, `/docs/basics/`, `/docs/core/`, `/docs/building-modules/` and `docs/interfaces` needs to be translated, as well as `docs/README.md`. It is also nice (but not mandatory) to translate `/docs/spec/`. +- Specify the release/tag of the translation in the README of your translation folder. Update the release/tag each time you update the translation. ## Docs Build Workflow @@ -59,34 +66,27 @@ to send users to the GitHub. ## Building Locally -To build and serve the documentation locally, run: +Make sure you are in the `docs` directory and run the following commands: -```bash -npm install -g vuepress +```sh +rm -rf node_modules ``` -then change the following line in the `config.js`: +This command will remove old version of the visual theme and required packages. This step is optional. -```js -base: "/docs/", +```sh +npm install ``` -to: +Install the theme and all dependencies. -```js -base: "/", +```sh +npm run serve ``` -Finally, go up one directory to the root of the repo and run: - -```bash -# from root of repo -vuepress build docs -cd dist/docs -python -m SimpleHTTPServer 8080 -``` +Run `pre` and `post` hooks and start a hot-reloading web-server. See output of this command for the URL (it is often https://localhost:8080). -then navigate to localhost:8080 in your browser. +To build documentation as a static website run `npm run build`. You will find the website in `.vuepress/dist` directory. ## Build RPC Docs diff --git a/docs/README.md b/docs/README.md index aa68d54a99f9..56df7df3c43b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,22 +1,82 @@ +--- +layout: index +title: Documentation +description: The Cosmos-SDK is a framework for building blockchain applications in Golang. It is being used to build Gaia, the first implementation of the Cosmos Hub. +features: + - cta: Read + title: Introduction to Cosmos SDK + desc: Learn about all the parts of the Cosmos SDK. + label: 5 min + url: /intro/ + image: spaceship + - cta: Learn + title: SDK Tutorial + desc: Build a complete blockchain application from scratch. + label: 30-40 min + special: dark + h3: View tutorials + url: https://tutorials.cosmos.network/ + image: window +sections: + - title: Introduction + desc: High-level overview of the Cosmos SDK. + url: /intro + icon: introduction + - title: Basics + desc: Anatomy of a blockchain, transaction lifecycle, accounts and more. + icon: basics + url: /basics + - title: SDK Core + desc: Read about the core concepts like `baseapp`, the store, or the server. + icon: core + url: /core + - title: Building Modules + desc: Discover how to build modules for the Cosmos SDK. + icon: modules + url: /building-modules + - title: Interfaces + desc: Build interfaces for Cosmos SDK applications. + icon: interfaces + url: /interfaces + - title: Modules + desc: Explore existing modules to build your application with. + icon: specifications + url: /modules +stack: + - title: Cosmos Hub + desc: Short description about Cosmos Hub, no longer than a few of lines. + color: "#BA3FD9" + label: hub + url: http://hub.cosmos.network + - title: Tendermint + desc: Short description about Tendermint, no longer than a few of lines. + color: "#00BB00" + label: core + url: http://docs.tendermint.com +footer: + newsletter: false +--- + # Cosmos SDK Documentation ## Get Started -- **[SDK Intro](./intro/intro.md)**: High-level overview of the Cosmos SDK. -- **[SDK application tutorial](https://github.com/cosmos/sdk-application-tutorial)**: A tutorial to learn the SDK. It showcases how to build an SDK-based blockchain from scratch, and explains the basic principles of the SDK in the process. - -## Resources +- **[SDK Intro](./intro/overview.md)**: High-level overview of the Cosmos SDK. +- **[SDK Application Tutorial](https://github.com/cosmos/sdk-application-tutorial)**: A tutorial that showcases how to build an SDK-based blockchain from scratch and explains the basic principles of the SDK in the process. -- [Specifications](./spec/README.md): Specifications of modules and other parts of the Cosmos SDK. -- [SDK API Reference](https://godoc.org/github.com/cosmos/cosmos-sdk): Godocs of the Cosmos SDK. -- [REST API spec](https://cosmos.network/rpc/): List of endpoints to interact with a `gaia` full-node through REST. +## Reference -## Creating a new SDK project +- **[Basics](./basics/)**: Documentation on the basic concepts of the Cosmos SDK, like the standard anatomy of an application, the transaction lifecycle and accounts management. +- **[Core](./core/)**: Documentation on the core concepts of the Cosmos SDK, like `baseapp`, the `store` or the `server`. +- **[Building Modules](./building-modules/)**: Important concepts for module developers like `message`s, `keeper`s, `handler`s and `querier`s. +- **[Interfaces](./interfaces/)**: Documentation on building interfaces for Cosmos SDK applications. -To create a new project, you can either: +## Other Resources -- Fork [this repo](https://github.com/cosmos/sdk-application-tutorial/). Do not forget to remove the `nameservice` module from the various files if you don't need it. -- Use community tools like [chainkit](https://github.com/blocklayerhq/chainkit). +- **[Module Directory](../x/)**: Module implementations and their respective documentation. +- **[Specifications](./spec/)**: Specifications of modules and other parts of the Cosmos SDK. +- **[SDK API Reference](https://godoc.org/github.com/cosmos/cosmos-sdk)**: Godocs of the Cosmos SDK. +- **[REST API spec](https://cosmos.network/rpc/)**: List of endpoints to interact with a `gaia` full-node through REST. ## Cosmos Hub @@ -33,6 +93,4 @@ Contact us for information about funding an implementation in another language. See [this file](https://github.com/cosmos/cosmos-sdk/blob/master/docs/DOCS_README.md) for details of the build process and considerations when making changes. -## Version -This documentation is built from the following commit: diff --git a/docs/Screen Shot 2019-10-17 at 15.07.22.png b/docs/Screen Shot 2019-10-17 at 15.07.22.png new file mode 100644 index 0000000000000000000000000000000000000000..fc823b91ed22ddbb8cecc7e0b596457bebf5a2d6 GIT binary patch literal 45486 zcma%i1yCH#+BF&iB)GdvaCZpq?(XjH?(Vi&f)m``f-bfMg1fuB|Gf8pa;yHTe3|Om zneBPHdmfqY(`R}j739P}!{NYzfq{LNln_w@1A`%ZKezk%;r-X_z7QD<>=U}Bu&{!p zurQH=lf9XxjVTzIL}aQuj7l;PBe%OyNC=jQi2RyDB9Wf$njYUKgzPI7IBHN7zOIS` zU1@}osJaN6ZYoLi=k_|P`6FRuXj5I6fe#~DXp=XMSEpPYS347(?p-`@W7*hXDK-n9 zo(rYSU|c~yhA!V2SeU3YB@aJPVIiUg(0`rBQ_PiDQNapeUVPPEUHcGG*l9=yys3V9 zQ&nlc2PvC+ z1pTID2SC?yfSHK0YiA&U>Hf^p?2!!j+((IPf}qz2yHJbZOvFQgR~5tS(D9omyovr}rSdoeL|8^GQhdpOXfRB6$^!=BZ%lK_LA>@U2TIM<+Wh9o?>9m-Cw)$5gEXO*!fKSaezD$2Fxy zW~@ytg!GIHyaw_t3&e_-wX1tO;sYZs8&n@5Y1d&gzJ6ju-wu-Lu|Kmv4u3P@0}uEd zLWF-F(74QulSp)e+_Q$I@bNVu0!GBxv1>|?fGXgY!B}mfnoT147DIxxuE#mT*}--h z)qSXMy_!SCdl}jtKi2q5Y@F0Jj)=pAPD5-C zwg$2CL8!lLmctF79h%ZTn;s?vIs4 zN2t%NpYOAp?E^G3*x4ONzno^d%;Z03-DL`f#>;}0@z&;12O~3YKiE%)ydRoR&6WfozD02<(eOP`eQPJ~*iX z!ci@ZTo1knq(2e_i6E^61j~Aic>vz9Cwm5BT7Z!P+-y*+0sK6;Td?ms5hnzWAUr1| zeL(p-cMCK@kLxc;y+H7Df=|RBg@i0VLjDrEMn>(2s}#b9RV%_KHc+)(RvKp*f3FpIV}vfHdF&vEl$)$zkbf91yFr=MF62>kH+5!FAN*PqTmJmdL6`UfGd>%+1JA@oMA zi+!XZLz#lDhaCuU`l%^UJ$k{)+xAF2rK=f!tw)#Ee#;4D^&SyRuQC3sPv|!puni&pqi22 zqpne*@ZCXUBk3nQ~W%Uow`f4JKOrwrrJQZfUm} zw}}(qmL`J_bRJ2($U6g9CH*T!6qyw-6#?H>N>!>{R1N@2-OQp3Dw#!NYI>zQWj;C& zahKoVga_ovmB__SQ%C$#N56FbAX8OV^;fMrWS&|1VXoSajnx;?Yvh0>jqQ!Khs|dt z!p72Q&?wWW)EI1aVg-5l<1qR6*34e1`j0$?v#B0d8MYv{I<{F0yk9Mq7oORtoOzBN zjx<9vu}64!g3cYq%@p$WB3B8!bmJf`89M(;+DccgSgrU5M_cI=>c#rTX6wAUQ^IQY zRbO6nAK*Rd*4fcF?lkUS+*dAcM-2y`4i67L9PS?2&GMBmRhN9d|w!0clp!sf&z#jl`!B zRL@*%Aku2lFwwNBZ?TKi;?^?LP}9<@7plyzxK~@M;HE&LXpuvbDFrwTY5iIpYU^p6 zeT<9^lg*G#lr0!PiX22urmV{HaNJba7GJVi;%h=YRyh$mjyeXMtS)LVIv>-V*mFf2&N*u-Z53&)aBAI_ za=3BT-Co>$1dapg)=nap@=j+@HBX;byeYF}cV$;uT9^7JgHLKl3r3Rqkd> zqEA$JZhkKfXB~CUJ%z@H$`^yc^X9smx`fue)(~kqW+7%R1;!XAtNW{0^k)Pn{G;Et z!1@BN0~P}UzYg_y29^YW6#OoD6m$x8^uamEItWH6TNooG8(#HOEbI!(BkLHm4Av}O zTv&KWHKIS3AqsJXMGRD8Z{iUtp=hS)c+{gUoTJq5lo4uB!Abs}xPFXb|5(fd;T8WZ zhnwtiFy|GgqmFfl(sRQ-;2sgy57rb`Hxd;UlT1%`N^X;qjXXJNEBTHBQSK(M&Cv?P zI%GL8Z70u>#c%$&gT2U7XP%u=#+uA`WdTP_PHgHw!pM`PJ3t`wS#AZu-DBv;?x^S3 z*^1lZ%ZsRoeI^PJ*V5FoZxerfyzcr`9djAu#~Roqc z5tmw)xSPH0tCzmF7q|@Va;S(9DXt$BLLz30R9cYG)^tG->G>eT-M zJ)`@Sf0tA4SXH)AUGFbTr$tkB!ozsda}(?blXX~e|~aGC+Et-OhOO!`o0XxI1ESj<>mSxI^5B4Mj?{B-=Ld*NAa#b{E=Q|P51ko-G& zR4y+23on}o_nFIE<~7SoC5tv;wk)sr)pCmS$(}GszYWP@<5)B=x`f_S$Ex+%?cp9h zohDX2r;5FSt7+!#^xoUIUD>;jZO>YEPPdxFUFMW?;b6vdH*75yo+H>^uM^#|e9LY5 zq}{!E<)Ce}bIF_GX*KH!`YxP+)=$Di<5J>5@xeG}NcFAee&{=WNfoO6b8Z7)tmosm ztm&7-%>4xiP~Bd`-VVdH{_pF>yQXXCYh8b?8&gnuhq~~~fPd+8?M>suk+Hwm+X8z6 z=j4^xz1jB3kM4%oAATGMx<>}T*SGGt&cgXqe11Q+oF$KzMCYOMcVhwgWN@nPjV_8F ztoP@_Nx4W#J#C1!z0iBUARFEBp6(0<43CrZX5A2Khfb zxTF%sf!_zhpmmBGq(pH z$-gAH-_QTaW*{N@mxzlsABl#n0+F!2lPM7!Ju5vU2|pYW5fQJGi5a(&h}eG>fB(lv zV&UTAz|Fwm?(R_cV(39<=S=$VO8&bZ5mRSl zCrbwxOM5$_f9f?fvUhdiBO&>xq5s+beV?WtmjBz5o%4UG^{ybpKUWx-=ouOQr|$Qn zy#M5KD_DA%+GvPa+M3!qzqi59#L3Lb`>z83-=+U;@;{1d{zp+J#{Vq&A6NdXBrn51 z8vKVw|2EgZa^LO6568>!Kep$GYwh4~d3Oh%rHH)B`w`+F-@I=e?>p6h9pBISnpkG< zl;4j*k|KgC9^l70?mi~2ov(QZzRYD=<7V|aC$z^?$bw&?(a;jU_EpGfaq{rpjDIDMlGFzCSAO{lRU8`-vfc1~CQ$Tm{P-1$jLa4BuVN(NqYN%M zEYMQ895VXvydxoTNbpyt21m|dhd@c14pW1{_#4-NzdL=KPvJ{yf{b~>gh?WBCt(~t zVRTQC7Jaj)U`pS^YsA%HOq6N_3u&o+QSL z5ZjL|UCacKQs7xMpi$((DH|qi$JcRls0~3$e;7fDlOv^g__5B63s%*ksoxM%w00B- z+6wY?^plc|+JmnH&yWbk+SFee zKM)f?5HmD^m0VLf6Yti=&Dg*LN)FY3`ntB8 zdvfv|F>bGw(s&ip?Msq0xo7ej108(A%r~CrV7AjIwaKs>;Gdiw~tJV!; zO?4VyOMF$tzl!+tO``K4j3hA;vjzC6;Q_qSTDP0e-~0`b5Ge3vC1-qcJ4rO#*pkN! zy1Ec#T~%wiboU8k@;l2h5pF}r%<9t$8>QBe-; z$F6m;E`@xku>ysBmu;u0(O}`e{lf#%GKH_wqdGAZ;a@B+rp{)y1m(CZ z!NT+P)t}v(F-3*L1w@m-xj>HYvFG>h4N-~iZrSGS<4V?sl;aQ4*$I`Y^!sLM(IvLl z6(O+oB1L`Did($2I6C=xS&X5=#CG7OY^UUA^;b`E4}4A!yqrW_5edA6ve2%R=5|KH z80O`^ahcj6VPZrH6H2rZFlj)-Y-+yI95G2ofnKWysXPlu!KoEFHa?#NCpdQWTLkTt z6ooYXytE{3>1QMMBBP|CwN;J~IRb{EtqM&AkYA$Qv#&C)j*LDIu_o@P093(2)4r-I zUk#>qY}Hk;$4y136+2cj5-DkZ`L&v%MI*Ek#||4&I)HTtXqwjS)^cFK^~LAIre>NC z0S!7|^(qYF6X^fauLnM`2VP17$1$VWN5qYu;J#W@AR_AmL}ia z15Fx$6X^4S=LuB;J&{c?hmC#MVhPhk6iM zsEG^I2`T%h+KMCUSOgJ`A2)ODFp2J*4v!U#p@rdf(}R!kVhCQvYu;uPJOq% zta@*$H)>~-VKp%BI{wGbQ)~4}C;dm2pW8hB?+seULoR%nyy&a=KyQ?*xy4}zEPTuzGc5hCa31i7)pMyVq{yzpS4{#)p-j6_^?-7a=_{Ow-i?hFCS1NPR zqC_inJCh{)agI;$zxLV*^Fi-e5R~4wDUOv)Cc2Plj*%KU8#{J}n`)j!6kSG8WY(CJ zsk#M(M4x@GuREbK-OCSvaSr0&*35MsnnZF#L}$!~imR?SmXrPHezGqb6m&JVtMxmS zmlg)zqr>v}fMB4)0Usa??PBU#VFKs;0)AT$6v5-brd^I7wGPm2Gkc`^sL!q<8}(Z79S?2*V!%c^HF?LY~JA( zCS9*)`Qf0xfId7*5(v{XNBxhm#h?wggDAu#jk%5?_p7}M zy@0SERxY2!7UWSZ;-C^k;Rz_nm1QK{;?nN9VFZ>n^o|0jk3_!Yi2IX7(>}>_XB1p< zQ<1@Q#hlN>2kZTY_EED3o|=5B3@)IB$?B{7z@TOIqo$EE(l9MbR|)m2uj)r^ILT&? zc;6Q$sY#?=v1P0=bmYEKi?Vscx1BWH)Y+?{y zdpub~h;KfyKu&@7EB>nlws;oJxEs`J9xETYRCxbo)_~91S6tSIwO)3mmz9>4=M(i>4jUJ-DVrdW2mibI)E^Uh+}0ViVTR;gFO#f%cB4$Us`IL$VS#(m9TPNv z>_r(@pyE7;GmYYh<6eocuMzXByAeNs{*2~>7EvH6O+QgqEow^?ak^n>atY0<9=`6- zW=La3jU~MwSEM<}7A`X(CpfGZ#1DfP3Zc{rvDpymnv$s(4qs4_DM0#Hbltew7>jlp6)n79>?&g*52fGlzX7_ys;L164!Wk^MI?p zdwJdV_&*@4gn1vopU@L~T0A#2{}IggjFCHtzyoQaw{lPY8t!g;#mdqR8HN@mGJNkL zBpAmtXwKP`qZ)g`J{ZBKS;-o^sRq1k@}`7ZHq@>eW+yokC`a?O8xPks8?WmA{Mlxu zqKt>2Xf;u09T46-puyZbr^z}aGKotl66cGt$38>M4;UPb(@XQfA541m!eenKxV*;U zL;L2<^Ozuot}xKB-4TWp)1OqM$h$}-lbn)!MJ3+H->ixr# zt*Q9>(4>2gN~o^mg~gM;&Zc_h z_Sjq-csq2a8NHC4Vlu9%!C`DhdRaC|;TmzbD*a=gJvXD&o{a9`{Vd4sliqN@}!gCX#TJvZUye0*UEUbERh7Z4(CLpsb z(Jvm76o^O9TZPP#-Ms#7`e9;?`y%$ux?sPtZwu$B*OQUhQmTFR;wwi}ZON_yuQ;}K zy~z@6G)c>216M>%$yWbGeYn?o`_NP6OkSrGR~vQGnNJ}i;tBTd9-udUts#os{^b6W z@Qx``tAFserLmH0Ht2VAqk$9|zxKnwnq4C8ga zzlwZ(BHw%M!3!w+bu_Sipp@qT(&@Ol50-g<)2bYXoLr#Kz4@4jS--MFs{Yj^JHV#RuHJ&A#T zM1Ww}0Q)T1zQgrK5X6|cRNu+qSN|O(g<^jsrLlHrycg;?c!`tUd-+otIY}FMD1PT^ ztZx5PY6hUPm#^s;y-*%!=`r;jyY4qvnN@MapsN;4BX9W=v9UN3$)V) z>hX~+bX|$MY7^hdc(Ny%x)-vaXl}ddyG!9>zqqqS3f7{Pv&z?qOz6CdG!cd9Y zhVsUhfBwdi`I9{@-BpoOEmT-TReyYkL^)9uszWbICC!ZvBjcF1S3J^_>Y&8jTRN>s zbAGSinwq5hsu|&a0d$VZQ4xG#&FP3`=y-rRSCDRWzRdP{UhbEL$-Ifsr5Riw;W7tB zCI!Jz2Rrk_k-ctcn${Y)z5k88?L9wvB=+0WuIl|HViR$i(aO@xRJji%}DAh3*bO-6az3YTvPsb0AAU0VtYzl+Hb#iQ-?8s)>kzvVlb zWzTE5r;^sl#7v!YXG|00&t%e#8DsN(OmDx~8;6|rq~O=_zU7rx@xQq9u57mR9m0`r zlU+W|>|(#$C)fA*EtT7~6VsaZttus8&3}$bzU^*guXOv?<}?~l^x^Hf4P8t^j(ydC zRS2$!)$VO*{%&i@UI0fL2NK4{YV~O_ZwWzyMBUE7*2|h z(Vn-#WAz+lPm+&Rh~}!{we^kokffR|LWZdpgMnhfsDTjF z@6SX(p0pK@*P;t610J0B`Z7Uv@}`7g1x#p}T{?av(nzI0j34Ww>W1TNFBFesDHMj3 zY8Wib!q!sz3})keX)mmF)JW2MFK+my#!v{pV>K#Eus;fM{+Ja8LY3#~4)26z6=^yD zCMPGD>2-?KgZsKfobu6^{mwuWfKBWPFPebNDaP%$t_p7$GT3i8CG&RKXFGdX&0=_~ zk0zT83w$&72gcWd3bA8pRlRx_H8r?-41irvZU|eiy27*G(&jK1vQb?liqyeY!FD3R zn?mv#jsEKbNw}`Z`41Fi_$}r~-^kCqw5qZ!T%#=I}4j|}x z{V-6y_@%L4j(Z72G^^%frqky(lhg6o{KiVOsp{F5_;M0hm!4S$j(mBBT2!Q3*Z61S zh)B3J06bWjm_nMCMmmjy|p-Ia-pZ067%ZD$Ve_~zbzV$&yqPZtoxdt zh7vomYwevxog(nCHW&)Xu*@DyQCQ9B>4T!aUWDA zwwc^oexdFdYiZb@kyxVmdIV|`ECt5Zad*b|gyZ-DWb?Hl8G86`5UAlhWH4HItqMw+ z2u@=xTZS@7sVulJVzBgKUc0VnwwF1_Sz%}_604#+%6H{t-g*KaV8 zw;Xx$sV9nhTugDw7sRKOFW0{Z`k7GU?Lqyh{WdZHMd_{2OpNWKAmPLp-FwN4z=@sR zp!gxfsT#CHCCx(m#qXte>!MmyZx%V~C^^I0{mc->J0m8< z*RPU?{JGdYPf|EF+)~wiD!>%mI3%1}RFfc;dH7=@Zl;CK46mA6Lx=2x=MO%z5|Sk= zDhInAHuZ^t!sDvvkq^=&xS4Ku;qnX$ zuUf;c4vz&%#rx^Y6MpN8La89~P*? z4^pb&GDC?TR@(fmEQT5PqrwkzSb*drPNXv$fh@W4(t^j%er&Lb`3ZBN|UCFSCJw)<%L1 zevtvBGPY9$u}tvdV(MOe_&sJT$ly&pNR5v+6#R1h#hM3pON92-4srBAJ5>_Z>&jMytg$x83{gZ)n82`e=*cRl^;B4yhqx;ErWHf zmu%Wv*1ZpB=ytn46JdG|tM?}L`5En&mYkieC~X>|f|<3RylHnHbFAm|nO5b>nxh)L zOnm3%eLu)84!$B!ryHX_!;1!ylxehx!M?+40Q~YOvnD$#!KXOJ@5X|V-+9i?`UlLB zEVq!OJ9ToaSO>t7Go(;58t}Um8}*Dhx%B0<)0jNazRL_h z4BJ-*uNaPY`q0IQDtX{5ZRjWH4catE-R1ocxY9=6F;g`u!m=)u?5}J37jrOY0~36e zSSI!(zibdRi6dt}@`?fhX`!4K4a$zQR%TyOse)b~S4DhlyyY&)Y_MJ8rgd>j>J3z%6Qh-PE#`lRv9&EZ^T;BIN z6gHY{;ZRP?fK(4=>sV>vfg{(OBE$-5ti-p<&s?J6;a5HsLQ})(B4O03#WJy_kH21w zU#?#FMt0N|#DsfdE- zL)Q9jY4p<<0Iu&yKGl@pp3@#YriUi}Nps>dxH&#@^Deg@3^VV%-}~%g0;6J$$EfJQ z?{U>t?Mq|F8jB$pI`M-Hw(6}-HkI_KGb?Dvq)IcFicCPV)m(~>&_+iD0~NJF|FKUm z#hdbVePyT)>I}70!2O28aeQvDaL(l5t8=cD9q1ZBBmMhzZfBI@q}O6X(Q`cYUAHMG zY@_5V)*@X>1X6;vVW`sYO4MjHp(du?!;w$%WLF;exZ z_P!=8E~t)!JEp6*G?lTU67GB1cLGhj{`?Y$R6L38X&J0G#-B-57alklG6;52UBv+~ z28 z#QPtw!l|o5*|$7PRd_w@V9{>Z7Se|#EJd#b7o4+5E}+3)U_N7u_#CqxP}LP0@!$l3 z6O8uqd-gdnA#=5-b)Vn0Z#Z*piU6YXEvH|^eRg@1}8bq@ca66 z&LJbLeDd`_9Z>GbYm8U~fz7kwR=^D8tWPsdcw)2I2Y^cn^|%gKvA5kWKSy3OHYHuv zpm{a#{WHy8k?9}l=Ds{xA`_$ zSv>){jP8U;iCrQ-auJQ&Mu0D6d8@6hFB^^(?#6DLfh*RX?P>_&$_>nKHoBjpZ!VBl zYB>QP)WPXCkZx;2%170{8cznI?J2%@Gfuk~9w0^twCMV0w`05*Qr#LwF|YYEIw(rt zf|b)kMptKjIEj*2t(gfI?Z~9Yj~t`4{Fu~0U`XMCulcrm75C~-HW(X6s<~&TH0>9b(JFxBQ+wRNvep^+5Pf&4OuQN#aO6eyOm#Z^vMdZaBCpM+ ztP#k9oMaZx?gw*bQZ1pJG=D8!iMLyUna7Abm&fAobK?S%6>`FB#P|~zu^vI;Ao3CD z@nw`%cQ#4iZI)$RNzCQuy0-$PsOFVHZ&O-XoM4!#mZmDpxU%osHaWW%d^$n@n~mLo ze6;oUv*<5m{J=R(Gi)INvzf4qy`}CD2ESJt2hZi>z!tPMDFz9=r-<~zAXbe1aVA{868%7corHA7b zNy+%=(@e$9=3Wd)RZ|@wVRa`6)C$n zoK#f4c4>f|U8c+g){^JnIqlT#j}=PkVqd$SX2(4`=mvl5LHsh~i8N6}rkSMdr2 zdvuvjCku3FVr(!e;}yr=RK&1#v0J*$aW_!cS7G-j;c}ecu77}cb@Bu@`x#d-Y`)LZ zYiEo>5^LSI@ml$ykKK{RUyLd{KrSDF_RP9oORp{m=2aRK+q#85ZIHPF9#8Dc-J?D* zc{+7B0iR3G^O?VMhK@UOn{HE5lhX{TwBXD9R6FHiI?(cri+^#UeC_b;(Nd)*qw&_^ zPwlVdRr7qvgacms?Y4Sz1`plizmX;dDg97Wi`5J-wbtnA>u0LFWDBl^PW##%-JaTDL!_ zQ;nR&71CiBl99WdOvMDN(a#$-O#nBW5)G7{C<+9!b4WL&%|A_zuBOYC+mjVhBr90j zrJLo6@(h^vpXJ=9Z1;w2&sHgRyky~4w!bXa@AVe8j@_dTj9a2x)&WCIia2?kMd|o2 z+6pRsX$ZeayAZsy{EwGfK9@<9d866x+$P#PH!@8+X4b3TKM0aMSN-SwyiuDHTe0m0 z>Y?pDfOyuPn|-Pr_C5Toze^O){f;-uJ#Neijf7evnma3?)$?w*eZTC?o4}5YY{|or zDq~y=_;pQlk7v>xox@IeZZZNpXu3KKd1ZN+h`Ah}O1x|}vOy?K#T=VKUIJaWX|+nl z$tTWi-i){B%k+M8eh;s%AL}@*JY_FB7Ruw4#L46naL>QS@ihzJ6WiEYUC}=CQiU<&YgY z>Q9h%zw6Yu9B2pp;z%=;b>qXnU^->8icv9%U(!<`X+kvmlJfh!w9|P$Jl4wz7XCos zry$Rv=aBBJJN^=%4l2gV7|YKX|4x%Bk_5q|BY?S4Y{m+z8t}b)hRq^e3f@|~Fk@w_ z{Fxo_86j${g72d@eeA0V#LO$>C~$ESebg|elLGVMWq-Hh>KZ>VDaTa1^O(z0ssSS- z#3ks2V&l8YP7x8X!HgY*(jcRZvthN%kyAiBF7p7=_dmafl)GVv1J;qT*t3T4wQM~a zBT^A_WhVI8=zluvvaNTmNLQ42?S>Vay8hm=YaMS)#7|+2AS!_aesd`=V31SJe>@0U zZJ*G}y=TO)v)$yP=%TM@J3^!&(_YY?CVOCJ33okf=yPs zy7YUUe26xX$_GpVcJEQ8I{+soB(q~~W-{;bb9-0!vN@hY@KSnk*CJqRK4JM71@MbQ zJi}&UsC1+fs#6O1hja9pmd+Xt_no>LPdOI27f)||4X)OUfS;YfSu^{xj6gv~16?lJ zzUp>@Q=Yza-`lG2iZ^=nCA9EC4@=Ox&`P=zvAGVhDB84?Cj22d@a(yATFcZUx3fEZ zS0%I%IT|-3jCBhx%_LXNV%vxp zs8p@_-1)x5AoA0$sFeb$+jqwaxNPrVq4!&PuK`7rdEjrGTkAK4H5IMU;9^|vH+P28 zdyLcZGW>1uUninlQ!?nyVS`f~>V^1=d%*J2Bc*SPX?GUt$91gBhS7?H({+S+6PpUl z6KlEPe$9*`(2{$$*mu{lX30prnh6u~zl^SImG~Tu?rz4G;8S`0GsrOK++~Ji@tP`X z`Nf@ane*$7i0B98B~!~jrV5<)=|#0%a-tDi#$Di~g~y)C1F$`fpk#H2eFMH_AuOon zzV+sg+KfL@Tv%Xb85T;5vqF-Ry4QTNZUq(3?bLXI6Li;%EZWtLMvpOeXjddDj?dFE|cFPq54Cw_csO)PudhKf+)X-_;gtFVOK8nxH5q{|8~b9iR}SfAGJm(-q*zZ29C z7uLg{ah5~V>_T}~dX~$S8={ z)<4GhZMau%kth0}pBhh!B-#$Dgl?}K!&;j(VHd;fba$FDrLjX-&S`URwd~{~@J?}4 zL<)?*rW9{GdCKhlGtQ;_-{Tw|8N5wDRxArXaND3YFgK^R*Qhoi@E4~NEeODn(lY*0 zh~OWFCg{5m+KH(2`2ZDddw$$Kd4U#*{ z43?G1c%-=!m`QEZcLG7g8fycncm>AR6RwsV>=tLg3X3=*b5Mam;?M|yF)R~Hx=_g& zD5ICol3w6Z`J=lBv&X{tFu%E;C` zCnd>=4?bO9?pfqzqkAkMii3x>bcR0P_OOe-m%NR7^d!ZRHh6oVe(s^9!2t4yFCeys zOH+NV_^R*M$x6k_8@DP#Q-uKn=P$O$Ph4tY?whT$P9Er@m+5}pb6(c@39P`i_~lyT zj_TrtVH2|02zo@)r+5BE6eh(b=SKqT=2?NjLSVODbQ z-Lqvtk(@P&>T**6Z*l@Z1=-fK=;Qi2QZqxogfdr272pN0bAO*uOk5uk52(2OOh`Cb zS8SDim!w?lyT-rlf9880793GaW`iHE2r|y~Ul5(2TZ%vP*-FwaIsiuQX9|4p$8?Q>s-#i=7q43ijRL-0j&EfVjhFn>6fK1hyB~e#%bbY@Dt|Y1t5Lr=#$TD9VIBhxTYUKhM zoU4$aR|I)SHn?Z5+_D913Hpcp+xob>6Sa#AcN6*fUH9ysZ)^FFnEh_MTuaS?E0|M^ zLcgy2*nH*k#u-f$?ruven5&D`OC{3?stjK}3?dGcNXhY^gV^<_ik|H!dsctV*~B(P2~jl4!yfUFwhX_;UxOO%+q-58jlv1Q3K2?{G3xTwjd9UPwy z4Zs}f-D{Q)4FseSy;d|@9hiLh8Mq64HCV0LrDN)v$xPRYrqkWB5WBl}qUXIp)ebA# zRRg5{Z#1{ID{&R&{eEr*87Bzq{jNjCCkrKgb9G3qadO8?HPC``Ki71kja;GhiW#Jf zSiRgEm9QXkrB}mo?2!`#a3O&xud{h#As1t5Rv5W-i%4eJA{?W&O_XpMJ4F&TriojP zobwD*6Db+4wP;CkN%+uq=33jQh z!0cgG=|wim8sqAOT+506?v6FvYbGZ6I18vdNdKKo%a^u9x@JGJr z-OPd1NEx+4%;MDPj5}I)`XP$W>=aRWDoJBVN@{UNE-B>N3*C+>d{`_O88gDneYUp^ zrvnzep%T8IF<9Aq<(U@pBEB1v)NJIp0$Ez9AhMVb4L- z$*AGLVjprnb5-4t zgy3<4UAT#0ldtlbldts3L?J)Hh2__Q(O5lCs(8i})3(`~MD8e1q>!4%T52+_j(tS@ z*0uo4l{*`)+A=LS_R?!>m>gB3$p{^=%j^39r1p7T-2O;zFp~4m2sz#rgO?wdwZ@pr z3i@nSmYYALcb;V7YTmk6q;HZ_P7FR+<1)qJTicC=#eX!#2i$^AXOnparo~cUt3w?i-H- zz~1E^SNg8-4T+8s+A^dN_x-&$!DAqX5!hoIykazMIh`Efm67ae}x4&?~X{DYA77zMNDcxn3&o|#`3NPJW ztibU`#d|)F!MP%8qJ;f>mc!`aN2-U(3n|v=nYgns-|_}g8oh2*@?16)!*tTE=J@^z zj-We5+?Q^`@flYv!!{;)pvFLM8f-C7bPhkf|Koa2%Kg2@^D0HIZcz5!KPp=ABi>I4RyS+9M2fn3lbmM z$C28CdE5VaMnG8edj8F6b(~F4=OxLk!$~&hrnA&Xe)Rub_b*Nmh)qK#u30sM;vDly zYlSp6h4n&0tQ53EEAjdjQ5Gnc zypq{-UUQc%m4^7tnaF+5c7Mr>5bs8s8l!x2t|^*a+t^}dE(}oYX`xs15nnfF-_|yi zPG5*fB~-DP?C#o)c*uAnZzW{Cg3()q-C$+2@tjUSuFZH(F{+qpggu9-q}o=4r}R1v0Dm8COS3TJDvKX?iqTuxkPkC`x2DWTv1kw1y9o8lm&d9kN) z-LRDH!$W7p;N=s!e52U@u5sOqf6`B?|H5j+6$MK3++S^np-xj?S>Xz3y}}?)#}TDx z3Sk8uxOpcS_)8KhXK+bLP9UhVA*+aLV9a6;)-rIR)~8j9jb}g5if0NYZ8Cu_s|6>R zfP1-tel4x~u4E#LQpA$A0J{0a3C2!fVM&(KOdMg8wKjB(5uMgn~ zrkbM)i~*wzoOjU9sE0y-B9Q<4yC%Jsf4VW7qZ8pTnS<-=M4P02wB{q(WTH9Pq9a3i z-ZExzTxe8;(mwVnk;C7=6H9M$ozTSLq%ipE)+1ZSWpRCb zXEJyylerOinn*#+H7lCrlrm>Bl~nr+`Pll*066!_TXOdydz%fz@r6xYi}w2Oz7b=| z?1@27TDm%lu{!{`A|3Av! zDlD$3YZAuY-5Y`jcW*4XM{sw7ySpWLaCb?9ySqCy3GVLh(mkE``~R6|Zf3r@I=AQ9 z=j_^5wQB8!Yc2hoK(5Y;qb_+P0?D zPI{{%juZ(wBS7IQf6jQJ#r-=Ln$b=e2CDiv3Q_u~k7x>vZ-o~0LMp^8bwn9qtjiPx zaoPUg>8)dfc>6_fmLChWrRoNF_vD3R&wN*AL~x|JGy1K$2Z5=;j)&N^n6o0e{~K-k z4?#`u{kJhzn|zzUbp1)zkClC4BF6vu>sJ|t`Lujmo(u0Fy^ zGa6QEgE&gf2oMwp^Vlc|%bhH;lG)B{!=<2`nIHh(9pqZ2LPLWMY|#|@CPa%B11YVU8r6JC&n_*p4Aoq@&158xVu zb?;yNGG6m)!%Z5wF&&VoD!%++H_+ex#1oaFk^05mS?@l}T$g)lJ*j^d_9R_VQd^vRlM74qDJ}EH*jAcoQ$2eqt0aFV4617(J9u4)r+CiR|F_m*LK}`p zQ~umiihJ0l5-TapO{6tjRyZqSfjnYCk)H^M@>ot!j^%fGA3+M=YX-CiD)l~TQw;+g zM9l6R)XAvh!j~mkkPQDuUAII57YwsnN?`kyAmfzDg|+>wRp6Mi2ZB9$Q-ReS(Qf+Z ziDJ8NWpW8t@N$eraUSN%QN`Id8Nw=oW? zQ+4~WvnVZOV@A3FdD@QUxi19`{C5tF5BbWQ5O^3E2t=t}?*|Nw1kAr~>@$C4FRH=D zd-=LOv=-y9*1_a1pRAc5N@19H*PU8_y#~|K7307K>!XCF$Nee|RpI&@R2$pd^002- zI@U?tI-=5Kq1WUi1o2LzuxMDnKMVMJIC0~*{P+Ac+0$}rBAcIdpqIC|#(7*;nvY34 zwIGJ9tD3t~ubH2eA?rd(#lqtIQj0~W%^d%@+u8CG0U=@5j<5%xfpCsPTq;49v>aCY zd}W>T3qR%Kn?h+_)Z9n~7wO->`x0Bgxh^xgxQ(UJqPpv!%;l{7B^J=yi%r4k?ik^sw&6*51dJOUIdQeiS`P(2L z74$A2g$eGz^N=t=;LiLl;qo#?$%<0J{r5{mxLZnTTit}YMGXmOJ>Nq9ka@F>1qS*X zx6X*RrlDQa-UV0XvKwz%o(~Z^CXX^vchy$>O0D`#%?Mvoc!2#%qgAkFDl@bAh}1Y9 zkrUOh)Ob^A#BU*~6lOLyuD|qhDlb#R8GYV2lT{tD`|3L3zjkkFI9V;WXll)C8A9<7 z)P5^Qt9USEd=hTrW^{jvVHSFM=X%~8V7%-;#+&nd)ZD_twc)+A{uC=w9MS2z{rdUb zFzckj*EWxnufGK+6^UFt1kVKn@m5+l*lPg zB$u>Wg0EBdkvCp)TW_Y?kDH3YW&h1Z`?tKjk_ed<5-yNl_|k-Mr$PF?(nIU-%%Tl> zh|%V%!bj$F?Cm+Dmfy|VS^N7&-nkY(eq&~R&tg@Gn>AndN?69iBVt1IeogC;;4G+5qGq_=SK9kE}uuFpMX-xbU8IGVu zBDX{dlUzPCDv>ts&fLbCnbE-P_mh@}Ole0;*xXJ>UHv2}vEQ&;=k_o|(Hm;1yJh&3 z@`@%a34K#(1wS8O%8*kR@&jRdZNFT)yX`_cyFq*A7#cesUEG4x`|c6>v0fe^iwn^bF1jcHVGA& z5jTa|S;g6I{0L7aEiFC$w!@!7A7U4tJ_$Eb#NhdtwZ7aqP3Y}*IwMfz0?#93Ih74i zKDm|XU&^A#ms*2UPaT-@OQ$n8uOF{|h=T1sAH7_Bx@l8l#ZM+P&vL%fj%+r8=;(>> z5a$wTYqeG;WwQO0rR1TIl?U{XG?BE>%=pDrZQA?w$LN%Uyro^$Tq(sZWl)C&cEDvX2P4K@uR@!RF8}EAZcyy4z|&NYhzcJd#|5Oo=>PRT{7$2+ z*sU2jmJD9cXO5t8x;@nRq^)he++bs-3VhnFIaIlRD=WZK!CNHKW;#=1tC^Mlt-s-# zbKjbPG_w#TL55>p2dAJd=CIh55uYHsPGOEdTKQxfYYo{!Jc46ky?+@stO70!$Z9WDCvVu6lRfdObE)`%k9Dhw#01c;8?=(jX!tVsXHG zLv|U(g&62>Ee2xAYB*Z9qgV=M1**HjZBOGy;B6*hq&*({W!^H1a?MI^iwT~-TuM>W zONDI&&ra}5H$2+)aSf2{8WK^66i;8#Yo4Z5Zs(FFalqv zO*#g?=;2$!gaVI;lj?86@hC2PvALt`r-a9k9!Sa!mdq^vQ15WYtV?-tnGT?oiOn?S zBO5*TLHmqe0wL2nY6yG8C8{`y)%vZVqq(0e2fzm*S5)7H)0qNkb&$#nS7ky+zMl91^xK`>dOVe_A)udO%%C-He($W* z-S>Vrmd`+nx?H+W$7T(~~&rc?1!`r!h!9^wvHq)*7N*kLa z7Wy22E(cKa%G=+cD%26$IqHuy*U9rA=Yn~ey0Oy`}J_jBR z%&7*Dsh@mtd=M~Q(7J~SlHOa7^dBfU6l*( z9%0N_d6M3+UCCEHH~jC?KQ$CLJFFcWk7Jx!1N_j;!tZLCzGzYu<=<8d5)u*)L>KD{ z4`|Z5ZG{uh%eH`@PjWmdMLg)5QY-wc1fXZbB`O>s@U@mlR-1Y$KY>@X3sZO0XQZOF z^2;%72vN>1ardK)RY#pfoy>N=8|~ZVl%}C-o@uc8GrnUn!JI*v+ss;v#n)4RSf2au z;c=>ftL2-(1Cb3HO=Vzd31mkc-2Xsc?FM|k>^B4Tz-zYMsYGVn59Ed%`w0ZRdTl%! zKGhjFPCb}FI_{TkRi9Y}FJs2gc5mzR-X@wcSmo*O6}O)3XQYWF<`wY$f?8-Qu;c~4 ztnQ?i{PIg{=wb~kwyo}LYKrYaw?*wO=lJ_Tg3<4OdpL^_5ES!3uap|*pLp%78BnES zbbZwZMY$CLd(C2oOU90__Oqsy#}9Rx!W*UV3(tjW9+IK^ZIYo#f9Hw)l=+(qpsTw8 z7QJ0BpAHX5mI^CwfN{lR$^SDy=U{YiC#5EO73OF|R_OoAZ8b0(~& zUddiPgG*XVT`SQ97@v%O{G?+!VZ)d=bd+a3_I@SPS(-5uO9qjlJ<*`T@+u=)C&dy{ z;BTq*glY*<(8`Q`iOU@45TAZsXr8uet}(}=+i%gDd6=vNP%f?PDh84kf_VFIyC9G|*|hDOfMdaG%V z2J!+O%F;dc18FdFrmVc@a2#dC_mrpk<}Qo;SugO@fe2Cd3|t1M2^@e$asP2AUSI@0 zQ&NSdXEMo}xyOR7LTHT!mH)hfY#Sovx-aODW52Xm)!ycL;gIWpuj9JrzK{V6kHq`o zE=!+E<5^p~fN+>I?6@m3m6F9y5ZfDm+xqJbTr)pj!)NiwP57Hh$ACF~w^^CS={s5I zDG8L!uVsxRW7$xXZWm~794mvpDgB7tm|#Z{eO?Lz-)Y2g+D1H&)OXEQ#0%4xv^$Ug zNq>Q}e(v|dng6k9weE9L8TXgi3#R6)*HK9t1}i-HZ3D8lNrHR&M*n)|7|3J0P?Zws zU!BCL=JANMY0#q=im;2x!T9#_AW)%vrY&7}Ik#od1A?8;oM3gU5J>QZB1N_u@eP;g zgmJRDU-jjA7@&gA7#EKZLFZr-g+?>V4TLDWxze-DEF!W}J8?Ky7H`IeYKyO}Rmb`6 zW7Fj=9Ba?81QiNvf}3dH2gM#j=AT&3&Yl*tc3>4bf0I3UFmi{MLJ;5SPmQA84Yjks z|JjkZ@c5}CkjG*136|=PkBn&Obdd?7_BmmJ-CUZR3k0`bp95;adNcs`suUK#axwQSqVOOZ- zS_l;3$nm)O(j>zq{V3I4&%ayuQuVT5Ebq#gqt$gtWE}4Ta{^p%8gJtn0j0iq=Q3i@ z_n1lN;`O=yoLO%TtTgOS<=?k2yjy9SYkSRU_+Ckq=CG>F(sWup*^Xu{z3#ExWY2Oo zvLWj&(xg6ho$;srV(s?y#B){za90*gyM%UCwD5DIM!@FrQIhxTF-~TqU?dx5GYA_Z z9Cq&Q@m}n8m+3g*&GB%Fyt>rNp*;ia;mgtXoJw=sPYx^vta1iX1^NrC=yc^VuuhgK z`1yO@T9WZI=9Siz>}K;tTCcbD^VbIll<4WcPJJo7}Jk&Xw-s68C-Xot^RWtEIeaVwCT7|?+N z8B_IapEMclsYL6<-_GE68F*s@I4 z6@E_NPS*_;f7(q_?XItU_en|8j0KL3Jb0*1@N0#io`p;XGmy+8~&Pv zgJJs&H8*G7YbVw$(R9eMvMgU5@-#i%f$a-(qL`euHXbfhc>^2~KBx|SD^FrT$3oq6 zMc$-;qyFtl>v1H1YB;5!wG6*k#eqKhJhT?8U|y+fryE44 zA+G7|RB@&}3*@~fpj;icM1n11|pcRo87ZFvTbT_Sdz zYcHpBw-1bMpNu^4g-!biGPyi~mD-J&{PxRIS=yH^4&(ep%IAeCoyZ zr_+(dP$zLc_@FiWZOPaAw!@y+xtC!~Cq=Ei2~g_Z9ybG;M7G9)bbG3ct0x1qfmAepnD1-52VNbMW!7sIn&zGsEyx#ivznzJ1{|u}eW;NS0&Q zQuC8T%N7#j)Lxp=Ir;F#pjOv4;ej59VQ`CI=iB|t8<4RV2~MOXIGSt|gsVKjZqPv8nXZJfTf|*Ofb`u8t6?*PneX)`)~-C@1c%+lUgU z4CvfEKJ)oJ=}%f^M0S()S{q+&8j~D#FOl;U51~9#vr{71VG8#U_Yk5r8V2^`s=z^@ zs8X{;B3pM(!;*BimWEW`DD=?zsQ1kzaK!4puy@a!>-%2pe}vA^;wI|^)XOLxAbC4p zE~=47Uw}9wt$*By$zGVKsndv_}4NM<`S?mLsvj*{P9%!#AZ#eN!RU}?l5P; zkLAWW!8wWv^O2G=vX;el^?Gmogg{~}9j%iPmP;>SUO@?LQm$>vV!)`zF<6!_tl(?5 z9%<|E8KjZ=$KrIc_IyDF3}IkPK=7$2W-kdYVweqUMYmZj{>3Ump_W9%RO!y_T=_&`OD131*PPg zQM!`&+g0A-Go&N^yyM9Ec}FbiFs->mZDH+F)Zi{U@^E~kEwZZp4D(pTQVcVDBxJe~ zF-~ST(*Su1t}cxKl)0pY91B$F9^PPgL!;YOlE8n;c3?zbxjfc4dKTWWCxJN3R(98p z{pn)i1#~Cgp6Kv;^l&(vRaG#2(efjrhU4@Z>xe+UZXA2q@di|)L`&@Za(@;U&VxkA zi&_}ge%?0z{X%YW@ifb!?TEo@3q9}8%r|3C!~uq>+|hn1d~oR%3oGkwOg}Qp!VsG<%;C=Mh?0WCkqVPfXuZL;fuk?8w&-+{f>m@;6@vpU< zA^A;m@l;TshT^Q?^Rfh}zIqYioxKOV`imgDY9s0;CJ~03_#3Z3*Kg<(Djjxto^nEU-Oyqi4us3^uA$tADtU7AX~MxNPBw=nfPt`YCEpb z`~^lhp503UOw-WfnrNMZAXmQUtq19YX7Bwc*z^1W$Z{TL9~Scs{jLTFkV{2KM6X9^ z-7YsJMUIj$xYjk)tj~IvGq5c@oHBs^KE}G~F&AAg4hJHe;WuA6hn8aNFFa=wq*qLS z1jE?3L7=7ut;d}*iIKHlcI_sX=c;q$O^#N#G$|dmW3i)nlBb6ra;%C76;YybcFTi_0!fft<@$j(DGfY--d0AO00>6n+QVT=_}0dSGqs;MJ@YyoR??~Vq&^hzCt`WsF8pFt4I9@ zsQ*S~6mX5=KAb+_ZEjqeGw8}UgjnIe>h8uEavvE4=MR74;jy$k@#$W8`AuaJ@(biE zuqGdFsGvjk)t>2T6dFp6n%kf=^3ahH^SyVwm&~u!o(^pq%Up@~X4>#ISmWhCUY^X+ zT=izR$=TjKlJhK4RT!r`8fj!cMPKCmU4OAh`?XkmSijb=2Tb0zbY zZiTJOQa~9j63`Nlhl95eA!Q3m4-*e70#fCbY8KUJ-QF13ibx1@V=1#(jIA5EH7F zEsR#xVjB4LvH@8qEl)?U0U{cq`S#@FlyM-I5L;lBwnaqrBHZr^-eA)Fmf)W9F@~DM zQ!NNaOsdAjDN_&HYEOuIi(C7SPyYB}w!%lBe!Eh(|M8fg4d~G32(V5B5=TbRl^|N< zYs-gLL7@KSwe7nDq5H-j_2>6grS<*^hQG}y;iQr&UtqhbL%at19}{s>7>BDiazrov zXAHFw`ZsBoX}_U*R6FnegvV@e2Q-YL?)k~m3KE!n#n1|`pO%*1f{TOU=J@VdT|^Sq5F=S;|?uMHwPNm|{EGYvY8RV8aaY3r-s znW1iHQF?gNUcaDTiNpq5i&)+q^RMYHMk{HXHaNx9-a~6^@4Y)A1$9Y>b zB-!rblM?5#fPtI`!H(5)E9YmDvG-@;-<9+Y<-sn9uB7a4bj6_IUGfJ$LWAN{&+>YL`WbN8_5~u1EtuDAJga+)=!3 z)8iL{Cyqz!sV}DjJ<3^K-l&MpNlh*D6}1;q==v1;!;I7J4NmqIHd6JA7&u;-NS)s~ z3zju3P9bA2N`?853$)LpxLfNQJ4d8&6tNbE^L~j$BA<|N;4DyK=)-SbZ1>s|+xGd| z6U<;%xWm*p{qx?0YnP+HGw!vdug0&zsfwg$Ec@bi*QYQHl-mfcN}e&x`( z0jJYKGjM!QFFmjeihklA%;&jrHaYsPdUi<$0dPI*C3FrXh6Fm})_ zr^4;hQ6L>DY!kZft-~k=dA-?Pe;G@MmHwkfJ$hgybR-ol!iqwP)rTR9Nt(sPBlS7h zd{wv@{XwvS@-AA0e`m^G;RKx~q#auZSAM9M(SZ_Ci%C;K+{4J3ZZ2EM73VG;+U`M_ zlyFCFhcTohExl-hJi+x*tszP4TRT-y2oU;(9Xk^-{TWVBNf!(O63&wMxEc#uk}ajt zz`=|Y>X;u*mu+p{AO-0ClVpj>L_q=!C#KqXrDUMLz@LHHwe0@LFBaOiK8V2aMH{(_ z@Kb8nR;`ugR{^Fz8Z0jxNy$ffb&5J^eIMJht*%HX?V+N|O+cgS`RyrWkX~#a-$W5` z@2RraHHuExi_v*K<_KEg5YA$MTRu1fL0Z0bz1&3~y==4uowpqclYyUEcpD+@y#6yQ zycRQhynCSnHf|6qUXPI?)(XFzp@5m_Aq=m~{n!(wo3dLo*uC;wmkYf^z*==7r2P!p zZO*7$sd)p!LMH5u#HJmX?$Qh>_%+@HYO#1Zyu&3wEJcn0IfC!0+yfnO#dwWr-7k3J ztImMA0ReC0w@GlNSUL3V<{roASvJ{7jWA<-4r8P+b2lM%Kf#!5ZksZ zqZ|gQYSFs)9ZC1b-RyTVJ?hcOb76#Cy^Uwh?c?vQ0w{Rt>Dm%OUQr&EI6QVvXE&Pc5BDr1gUoTyRZa!Wp-njz*W2+CZssy?M=!lRUErFgyHK- z{dUibbH9`MuwLI=TpI!F+jjVduB-KV?&y`_gr){!21)Hh$;D6=7+&ug4;RfS`@0lH zfNPo&SPfBbwnAFRDBuZ-PJo63bxquJQ|S)-6@CREh%gJcmn;S+M&S=7x{3DA7}AUtZa>oY+mplJL_*55tJ-mPn=Ss3MUP~En@bk(Aa?ro%*kDf6aa%PqL!o7(d>L z=p}JRNpRcQDdq*;3#8Nbpf18e-_jV#0zQUvGaek-g)L08?D8%2ihxhPjici-U5Cw! zoFV+iNl43Bne-TrC}K071>Pw8Li;q@@4g3NC}N+_%(&wsi4))&&-$D-F5nS}%`j4D zw_FX8+aAG*A}rES!YS;&EKLW@L+8J7n}4GXi^Rc=5x<&%DKLL8xr}_EZ@i8;rM}wR z62>61EP>z{kXhk;;5WloP=uo>eT2GB?u6Ln6$v)6{iC!NHXk-i*WDQ9mpArG@4XV@ z&ZI7pkGRj+5V5C^KdbAGen^MeZ3~6NhVB1?LpyMANm?T2HE}7|KCZ|gtJYJ$j&npM z?el!c9c8WxHBK$F*UfB#TP~EW(>pd$-)p$1wutE&nj}{M)YpCJAG+EeCX`4sV?aq|z(a%r%qHl)|!eewTiwmVS95v%R?%2X1SMly~ zm76Do3jqwgB~V9r7{v_-`$e*t1r1J}y%!AQDm;&v{|RRwQO9BVX;ciMV4EAu5Pwzj z5dFFfS{Ti~6TRn2M=sF*evseU(sm%Z(ucJ1hMH3+sJ;6Ra2Z7R0au>km$a}` zywZxsaElqw`D$w1v*OAKpE5NmabAo2ht`?2*)&d%8lzq^a^J5gDCVNZ;x-p~R|bh) zVHcfJizLc*5luJf`0@-o*f7$YsNwt-zBRH)VlWZ;8u@xXi!41g@Eh9)?(EfXu@w&? z9W(N;oceQ;dD~O&P`T#r#Sf*2mt^#GXRgjR@*j0!GC9toTFKo*uF*uVjVt52V5eQR zBVpw{<>g+eCtJ)YsV;Y4WiJKK_$Avmk@Km3(jHqx{uC8zF&cirNk>9Ff*;{v4Vzu5 zxfqTi-AP8ZCCPH6Y*Y<63Kc+Kr#?nky4@$q?2y3AzrT3k_kXb^23c&hg>^yJ#t+9> z0wlVhM+4_vvDYPcUOFY`kUQk?k-8KB_x`a+HA)4U z@Ej^-#7GsTa_ia>*j@GC9nM-40{nK6-R?L5r5oTYo3^(&Nw*7W>7%Q((vKTIY;6{^ z{mA%SSuitda)Bh>;YezW0}tefpUNFdYMwGOf0DtJ;sch@OXfdEf9HaY=E8O z4zzdVlU0TbXC)cq9-u!@$kz0F+EwcY%IL%#WgU&~{^ScW4J)7=4s7c%tlG;Dm18~f}5XJ4nv|-ga zXs}m(f)i-$n=LXqhp0yewwZEh*5DL2Lxd%Qb}dk&G3i#PyzfG(0V^i%L<_{mb}jJV zgczJTE1Yqf^lXvgIFpz7)8e5Z+T1`~@nKCj-isqzy`g!<-#!@_!5bn)5@*VVww1rI z53qQI3WsB3xMp_^c%r&%%7&a?J2zyZN75L%+1uViMSXzD>|Wyt-VpqA%8Eq@XX8vn z&pf3%fHciX?gY!k3(5~7VpWdtjaOSqJ4_3rucecgD$QX`8ab()upIwTBZsz=QeBJb z2fR~TskBXOl28O2+EkP4Srv+rCTQOUc{yMO$E;O~b(z7S`1H$4rVma#X7atAU=`#)z=b2G+1Kb2`GFH#F!Qyr~SqN&L zhLVt?ZWIV?pJ03y=7#Mn^cs{Y_iJ4M4doSF=p7vba(@2^dV|U#Ie54W2aQl8 zl&R1QRjRfO-$H^@dCgaJm&VrhS91=>eauJx6;NMXsP9pzeE)?u`HVvc@&@dLJ*o-Z zXtBF|lrP>gdrR?{tpay5ePwk+v_Gb4!tfxY0%fg-tWgLa)qTZzkaO%+kl;O#&&J5* zfEI!rE4i6uj>+b|8Rb);`sl6m54A>WKjQ?LZ3+}myTT$PR^3@a$+BktaARuvC1WX>ZaD4K$f#orD(a5-x?Ti(z=2|=%eYFqb z)}Xdp8~03WEEZoRqi%R>dx=Zq7U?3ED|tjw74{~zsEg=}2)z#0Ho>i6HP$O#ZOu>M zJM99s4~z3_)#A$cnHe>9TusL624~UGQ;vcW-_0J_YHJm+PCbr%;oSQ3!^`2b9z;3N zH=ofx@R|_ldB{cfx*W}GwFr|bZpk@GCK4kXnlKkAg@I4ye*f?|JyVn zIhcek=LwfBk1yV(w5D-uGxC>K^~R@Z!!?`p-)s$0Yd@bA`xRe#k#{B+N@X&9u5NBPK;haV%Yv4#BwuK)w)F^4G-JXpD~~u z+v=>~sP)B$2q89laXT_R4iL8@dlA1Xae<*D=l`_OZp1DIabQQM7MP1P@f@WqWztP!1`{PhPhwV4)23uK$gmEQ}8%M~+#4VgV zM1z_r^cM=*?N7=N=7PO0#eLM)j? zb9ik;V+ZB#YTjr4_?3d?{{Qa~N6 zM!m#;ep%u_zbq+rbPanA5?Se*w0Sheau~Q0BE8S4T@dPh*c|YnsFuEbNdS8RYbd#I zdFn1PUBLOBk3GHVaSP01^b|GMU8^cf+6TAKsZ%XobBLw>Q=+rx{=U9r0Epr)D_ZT1 zV~Bf+wbQ4B0%w8E=|1=ZPe8f`>n$&2qGA@w8Eg&`rW+JPwO8Zjw~twcju?e{XKgoq z5J`+{x<{`)`st8k6bqW$QEGY%rU)}f$h@ATLSkHq2IxvXYf;>>Z^#(L*N|hBE&+-= zaR)R|1(^bCda)G|)8%?af`VCpg=fshC2%fbu*TS_6{uig}4s z?k0Y9#kVY|mtEif;nR`1e(GQ<@{^ z&)ygPD<-V3n~tq$eaN~e_;j91%PY*7horWm2v8d>if6Dd7Fc|~;=oob@y#WZ_7vsL z_7UYz%Jnt_ioHzfAHS`?^Rbvg^RXT9IiBtt?@d~mS@h1bzR&Dz2&-gIvu7(LT!{lE zsvz44>;1deF2%B9QAy|oYjyzfiPw1xHnYoAJXUW&YLq_wcKzqw?fuLiuLl^bX?0aD zT!zpv;m3J+pFVJ|=bpjfR8rya&z@3BTGA))A4sRFNEKPXxN|w1$CGiDJ!~ zHcCJGyc=GRGD4|w1ibj_3K?rU@72VanSPh2QU5c^wvulvaY7;yDB=51r430*yn=AR z0w+a@|0;&Gh?t$Sd2i^Te=@Z)bBlul{fMUnBAh3gAT5%8_+a5bs3F@S-qqtsLpJeJ zc(McBC&o9pFD_z4Gol-dKl~Q+xpg`QL!(&Ab#ZQl&E)59dlUkkrDxRc|8cp>8)!+) zoI{eu{(>Vr5@Wu%@N!gi)%`;HG{#{px@o0%0Hr!%z1T`_-7pI=Oe`dU|Die);+&hW zeeI_VMBZj^_)vtAxZz?7f(>n0Bkyl=-ePz3gW+!{W78>x+#P615nPO1^rct=n7)QO5)gc#;gN^M+=$$I?@d?o zKZ#6Q*gsQ#yNlv1D$h5E+MZf7=3A&oy)@|lyU4r-(ya#Ww?aEX7bIWvOVh0@xsF4L zrcF--jYVCVM~iR71e>s`PPb%6_sx>G^Kn)iW-&?z!8*B0LW^%mwer=N20G4;cN!Ktha!EPYCvtUo}$y`v_+fL>j*&% zdg8VEtJ(IHJAC-tHgF8IFLJcje37qZ)E4*L8Hn6@eZOHn@F$oxOtfb{A#&+`T>`Y? zZeg-ZquYK$y;s4O&&7)J>ZD8MFY1qsncJ2Up}Hb@5x*hdEZ!Mpxas=N$f9>A+HUXh zxn}Qnzvjyy&qW3wM>ncFE8Afco@<-2M0j4`zciWc`$4WqyJ#NB?eDPJO&(^syV$pG z-W}B3?PRAsCAT*Q5!taD2k*j?_01>uFZSV8=^2r=gdrA^+c3As%UC)5q=r)vQleos zs`fx4x(iIf*QYtgT0(dOl!E7pI>1MrqO# zv%rO0fWhneEZrRx&c>_LvpT%37D5qc*G}@o6Kb$`#exh2ocoA$KQ`st;>39vxy3Vk zX8wyZ&pFoO#^E`!GcB*2Q2fci*z;Sexp;oKxG2VcF!sRd4Nj}k*hU;g?L*%f-{+90 zCgtaUTh<$6B(rhoE$E16Ng$Y5RmPs37%15AkOvV#0TZdQ$UyVKe-)e-$AufYk9eo> zN2MYE6RteJCKNp`a$V2(6DKA8QRqzAa0muU1ojs>?M)TrmKl{fzui1YJV2A`6i|~#RUb~8gY)4 zbdUed;pYsZ{K8ftP4fX%Y(|At?B7`@L*> zO*4BH*^E2WT~f7Z2X9e@^j`EHL6LAX<`uZcKaR2fKS|WS3ut0=TNpndb{=8?Mf3cF zj&`a?@o$n;#DG!8zrxG6%rQWDDwmWx21@Ki!(^^>H>e!iB9oye^%R5A@6D=1jP+P= zi5x7B@n1P1=};KGp_W7e;Y4#+H&U$Ae(1eRO3!_Bz^q&!PH)|MNB#%-HF1ymq+KAIk$xFFHp*BKhlhRnYok$%*2 za18OXLau!`)FrMw%k*u1*=G4c%Blu{buw<^UN@IQ`luR_0Av5k`IkTOS#AF4Q((N$8p481z^Aw+p3Zs2H_IM@+6sPy5$oAStgYUDVGw4ZIrg+Q`7Re-V@7(IlExZgR?QHN{3JMbF-- z*z>gpq6@g{Jhot1Njh+t+D@42Hsg2W5vdc+ery`Z?ywfnGj=EoFl(CA>(`na@m{gs zEatmC&L8A8h7M?p!!UFzYlr7=lK5DGQm9*40CsV}`Bq=K2BUg4aHw*5UL#{g8ys%wWRS_gU_ZHnHd) z_E*oQ?zpsfC6e#kD{7%5YOdU_B80-L^2TBC&sZkb+z^Bt z9r~?=ht%CbjzAFrTNT4~|1VWK|NY(5b4~%>k3nI4o1h_CR1na?GVf&tn&lRywG#efq8$%>k{E6S7LqC#9Z1rogfM(p{z;=TXSAI+<;U`DH;e*pB#9lE1w7m)ZW{Hp2 zk%PYv8B`Q9*x>ogG5LfvQpY@0(0#ex%>!DyDs5vj`7 z!yL-Zd&k-pT=)C*6ZC92RxP~`WU_i^#I*X{`YG*c<*c-w|3~2ZNY^`Sst*}kzhLI$ zjQje?2yW%llegJlhsYf(l0@%6G93WGmyyELdw}-tVCOR|g_8t=hn9x5Dy{5VQcnjZ zT_XYTqtU&oq0~~#BlVh~d&7gruk4$s*Tj4JVw1?vL)2b~b*flxZ3{CV0sQv2cr$c5 z*o#jHYv|qhXhV2C8+|0hj$3`<*NZn%?pWLZ!ehA?SDa{7=kYr;jJ`2LIVXLO<_gc* z23>-@bj)l)#!Ab7Pfpd_F`W=dwhOZjX;fe6NKYcM0aZEup+f{=p)LqXzUNY6P;Btx zkW$k&LP9*13{p$);|4)Bi=p>7F7#b&jrk5JGTgL4Lo?Yf{ryX2G`uXqbTELKZh!&g z#0ZKF9%ZvdI@Ch8WR=FAmC;tJ#iaEI>Qle%d0qE3pN)^-kqNsJspJBq*IMHWR&4;F zpET2R#fbIR?(4W?YYp+5=bQEKv@R^i2Sk0W2GD#QCv?e#%|zN&*2bkK4U+2vu-Vr2 z4_ma(#KYOB%l4ty>+U^YQ4q;bEh&FWJu@w!)dM<+$e(xs3MXH%L8YB`Hls)T4#LXO z3zYfcC)hKlM2hTdE7!TYt*0rHfqay>8 zzrdYmd(RgI_=7*7uP4pZB#C<4+a5X_Y)YVk@9;`gQ9hiDh+a%YHC=)mOV#7K1=+!g zC9)oQ0F9u}%u_zxxV<|CQqYN3sm{sHrI1hQdwipePR- zPLNH$zmCR-3KOBXDiguNt{(bBb(>;JzT9N#)u^rP)X#9M&xN9f{(Y*$9Jwf1c9=dd zBCE)QsQpSL$TNPf$lV^we1`ry@`V&G{FT~9QRUbi9j}}o3&SjiAD_wo$ezD;g5#li zB+WlvRD6a6{~J>H<0;8bca>w`XcR$bG$KK!Xk3SqN7Qx%|L7y$(W2K2N-?;rrUw9$t(&yi-C1kVj66Z*rGJ>kL-SCJLtkzDPagxNWob zVp>D1sb~2?jH_f6$^KJ;t6I+An+`^SDyilX#$UTN<@6QOjMm8koOXhW)!T#wPx-yu z&jL+@iv;15a;YIH zNML9_S~K=2d#ziT}6)e(i4mT{P8U)M|-l3)8Yc?m(xN3 zl2C~)S{b|!G|;2R^(R?9?>4`tMXtHuT+Mw#Lt~ry?FAt4J*@E`z|wpdh=T$I0)gvH ztgNc75n9?1wcBN{f0Bg_G{dh!T`oF4CtWx>?J>gHD@;ys=6$Gd$F|m;Uolu#NYmIx zg$wZUA){)id@huM#C8C-7CAQ*PxOLt-DouT!BW7o({Wag{Kq5;-wD}E!Eb&S3g1t9 z&_(Qqt&L^5J+7cLcz z>rWZ^j17A2L|ooo^;dZUAZ~i9wr<+)OzXEF4y&0f@#RmmZzcSV&?Q2?LTMxk1r%_p?<)eAd)TtvSWtzX>ehX5#`IU@T6^oO(2#tw}hIb7x`2fT_584 z52*1_$Ve)0tZCCNqltr}{mUS%j7SI3fsDFMLCv8RRrmR0D|D`wXu8_eva(w$yKi$_ z02h9j8N`Rh8x%^|SHCadV&30 z@@s=ql5B)WAtKG3mc}=QMGLowWS6*LwfgG`NMZmBc5?3aVf`DO7r^4enqku`3S+(jmx&(cd0#Nul4DwgfzVx2L=b#0q_bu^e{Fbj0uEtkES5F+uu^ z6Z*$Z$3M}ka$NoyiTLXHh|yW@cZxRxi-GqVrr2^Pd#i0NGjeSrU8nR4)TU+>WL`eww3O%B{bw z1@PpNMR4#%_2M72_jUPJbm1`O-E?a7EuW-ZP^3v1UF3 zGN7OIlRZ}`Kkk^qIxbjtO$TG>FIpJ3EQMpVUKKOxW5u(afOIaqGO3X*1k|5zni;p1 zC7&=yb&!%9q}=E7SEPpQN@aao@8i%|+})fep5>!M$dA7ul0Mf>8LPobO^pAICT!4~ z?$C+{8Vqw7EL>TwY!E^n$xm2s`@?eHQVL)-algG*xX|BRmvZ|&xVW_uA|r`hTbHfS zI=ap)`30mm>H0AbQe)!EFASUTI*479QX9lhR9c)IId!7IFxfdZ<8ZM2QiR9*0UVjA z9rLN;9c)XkgsaEA7!{*Gt>;xMW!HmF-Qh!%N7NLoGO?hLOmVy+%y2bx1Bjk24rS}j zc=Mk+jY$Od1W+f}rbdh{E8cRr6r(3!n+_S7Tsx@(pO9L0^CJ-}wUI%{3KX}~sGD|> z&*t>BDd39Z$jIPOVz7Hq(Q9USKG`>Z($#azph_&)h%Mv$kIeZdDJ0%~vh?~`bx$-cb( z2Z@LTWe0%{iO1j5pXpcq5TxyEqvcJw6`TJ!8O~ELxVHZU+exM9m(q_!cQ#HlQ zBkj{qIe@;P{tJEa_neOz{bc4|iFiX1%5dx&K-({CFZv}56 z>T!B{QU`))cxQkye1vI%vPqO}YaB%xT8KJm&_Ykfq>-wiaD9OTq(8tM7R=S}%gZGE z1_=ZWd!>$mhA@fL!@5cn#%+w)1*am0U^sRK#7Hu8&Q-z%j6_ad%Cql$) z`poKo0~lcgw#!WfNDg?_N`MX?dh-G}yqXXy*0gE^_p6RJ?i zr^zIaN(F#=-ACs{N2^-41!W6a;y5yl zJTa|+Z77cjFyaMV}BJ8BbNg_}dJE%H3O4UxuW-`MmU-E){$M5@04b!)Q-< z!ZCznaH8QVb_nbUG=f=!)`o1`lNXftM;(&wSCI)0Ltz^tzP!Im9u;8Ka?B)Qx!cbr zy+rs;JsQrDe*1QmS{a1Q*|!F=9C}Jf-Qr3Um(dUkCk5HlgP18^$jWPo9TgX6T}iq; zO*^GZ5Po}9_!{IrjeLm`vH$KuE#t@$XWAHpt+gY}FaY<$%w)0KoeD!?iNx`7?ZSET z$)(rh>k?J8))bEk7UW+LnyFUdo2pa=BC@gLm(&=v7rQ&)BKFJrUxi)S2r>s-rw=YkD8cX<*?!#?G#T0^^V@J$fhz z?ea7AlP;924D;|N^}X4T(4g(I#$hb;oZc97Q}kn<#_7ncweiU zo}%H{$3m@Ap9cjI+$#AUwNN3|w82WGIQTE5Sr4tChvBUun`&~W`&M2?ZAU$>Ve&Vz z!sD)s=mE>ln(R*fzkWAt)^E&y&~5v8;vXT5H`#8;*z>f~sia0wWi93Bjw}axES_Iv z-<|%Dl}p2m7>x!EfwqhER-03@$PeMY-C(@J2VcB~qF#h9k{q*z^_6RG5Xr2s z^F%KFI`ZyFE~InUoCd@8u<=NW=@Pgq_7wmq()v+v@k{8pIG#kO*ydiFlXocnN>d~0 zD}{6`VNBRKp9rVT)^^Eml0ZL&Jz*F%@<1(!oy{~Vq+Z_es1%>|^spR3M8+h@p^(mg zfq&YGPb?K(TjQJ=eg)a_gAHLRlr4qRR!A0UnH|;i*b@v#tT*VtK5H|l16EQLhd)>!{m4_ULfz)U*G82NKWZY? zf8Cwm`*IS=1L#9M7v!$FUNv@f{pwD~91EG8%k8O|uTHhT88^H~0VA#`JnRXXgv5d> zN)NwpUXyZ$Mo&%ym8d!5;I9n7_{!L6X1fsh-72 z(nak(5RwQkR_F%!C$mYi&5FxHgz4P*Xo06INsF;Qci zHyQ&>8l)ZbSdp@=k6L-UcVW!%-Sut0;3nbYudHi>3zO@225(gEl3T8ih0W{NA1_=tKVWsf`Z!^E~nnD9B5>9N?vY=W>+)>L-%MV0i zCW5jD)&MfU5_*m#-;aNi*=8x%c796wYIED+V$wYsU}j2m6LNL;x^k1>4+!h-O;OlA znJ{qs@iG<=*B^XUBTh}U_%S`5LDQ%q1sUY zq6Xtjz#wJ*EzxPsYm6DakTu(T$8YKdpSkXkht(3ht($$thgL|3-S1}f*VU{&N+o+?p_o)t|SbEfK1dT`jv~WU&t=qn)y==EBBC26f>)`2Oy~UnX>2Y!0pXj!`0` z^Xxqkk3IcX;7w{)$40RXy6C=fa zK(fKVB0uyF@h*@+?&ZCPUmN?4R?Pfkpz;@{!PZu@Z2Y0WlJ!|af=s`2fN%4a(?=8{ z1uOer^=LD`L~W-@=VA#CSg>F+l?ZAl@?-iQNot*4wk#g9VEB(}=i7-r!$>9tW1BG@ zWhW36R4nKOjD{0`UO*|r`eNv@$N0RcZs)llw-ZI*2~NUIEY^he857)MMyp@1#gI6r zO|&OS_a~|>i{X~NdnWe7Y#I74U~-)R52!falACy}AP|VoM##b7LLpWg*5iBJb~WE@ z;00nWc*eUg9jhA)6J+mwh3615MMzCA+FJ}@9#8*TZW?b1oP*Du4(gcZEs^3-qA&(B z>=U`g>H^FpPJ?AhX*$p7m{NunP1TIV2y^>UfAlX6oQ3%b7F9$%+=lFmL&Ux?naK4e zM=hnChn>VvIqkO?)!z@^iS-?YBh!X|QUKbHE%MF-@(Bh7eTK^h9j&fR%)QOXTl~vT z#r+e)3zFlT9fg|3hqR+PI>xOBA4i^}u$Y(Y&f{J&C^KfnOR;u6;CIHshV|PfHEFtP zKQV_WRYLL4B(7QEEMaRx;7Ng+{~$ZM*>}WHYvl)zQA?MgarTtMQS(^Qw9o ze31X1=qD%seJ9g`Wjmhdo6>i6-VgZ2iU?AK)(53wtkUELdv#(V45C8Ii;`1h*^G35 z3vGeLkA0Lys3RbAwJ|m_2%Wde4PxWlAwdW)f_-foA>Z)+y8h{o#npYRf~)n|g>tkr zN{tM5GJcq&^_AqQ4-OHg8jjrPJ~A-)1?T=|~qhKEfcB)8kCp>c+Ato}HS0uO~|NuA`3{o%m}#H(@Z zOi6!wf{eDflB&fK{Ul%en{K*;lDeR`ry21)_2koMt^NqFPb6S&`T`>!5K_pE!i0aP zwq+iEF_ofuar8x0#6zFnB{NalL zMC>Zna0gS<`0YMJ1whAaPp)Wd7A`SRL4Nr>$A55kX5D;RiSE&pqqNsv$}v-zxOanwnRUd4wdk4}ky+rFOAcy?S(}Y6HcCL5aBVA#;=bPdYkwvGy|P?lKr}WLNvYisu_=k z%E8BBQBg_XbQ9IIsniVnVQA>fbeJyz^~Ya}4Cj zJK(7;3U#wkVm`+ab3=~y)IBfjT9I{~!pOvC;u^--z*{a^*xmNoCb1h&^Z0(Tw0RL-@?KJ-;2ujR^XP0ni58q4rxf7)PH*;wKJYPek#w=|{nXD$T=bQAmdkk&|Lf_Vb3ys#jJ^l#~rj{~a^ z8;59)QoaGI%e51-S(Bfp`eBM?7qVP!&nxPfsv$!4n-}5^MA=g@!au|6E#bHcpm(YX zUWFnN@}yJ)IlCv$K#S3DSfx+~7cz1I;a&}-aW_X(VdJIQ_Q5VlZVaJc1{@sPeeVe7 zheJ3#`dcD?YTvhQOOHl^EaCeUy*A8?W6r=EXbEzaa6tk(t^z!s;TSlSeea3J3%lJb zM%pmij{%1>_~!efV4h1gLxz5W$CycK0HBhnV!C|Fr&xx#O|IG;LqT@LhQuBG*>VK2 zn|d|K^NKvf!tY_46`Bg%k~-r3@L}W1GfloIZnPqPIbfuukpUyPr^c+c{0*%gYl86T zr;Qo03@qG|;gYVCpEEx;t(I}Rtr8<)_7FCv#c{V1P@Tedn>jHcv%-+Po-5dnw;u-+ z7ay7&jryx2FXgq)8cGGW;<2P`^jZWcF-R>W8ulF}kHXQRgMwjEYg}bc-urDkj;jC?ltO&*ddRSz(KtnV;9T&9T? zxYVwMlbo}%h*MWrnPq!YM z9U61#2BQWge{inm6#?i1UmywJM4h@`LZtOHDuu0CLZE`c(O+`yR7G;yoAfnYl)#aK z%C>~kR(5D>(7-l@+UyY}_{+neD$IokS>i9mTD$J^ri)hWF;_il|5)8G_*iW8%l%fy zM|-|z)s$djDzQLuzr>Hb4G`DOyKw_ugg7kVuoEAr!;HuuOs>i;7)$Th8fVl709B6R zv=Hl_)u1$YeCvr2FRp0olqSz=tKj_u?%tD-E+nu{bKwx zJAE_PY4itMaStmzd}>{MtgHQrWZ_6R%J zZc~w`dPpgQA!Oup8h@_%PCJ?v*=;1BJpPX8L5I;4hqDOd`_<7R(F(GS3WDk?Yi}Pd zxyoY{nXiR@eN(JWLm!?2K}agi0IR1O&JoPPH@hao+U1VR-uo(=U)8^K z`#2ov9@9^noH!t#Ojn;O8j=8H?w&^7>mncBHODUiU@?hPPv~vW!ZRi%{MNGM8peyS45Vo`~cBOln?PT#ujfsG)VC#wK9G-Ke*h;Y>2XkpikCA7BZhts2< z-p$;%ABfd3VsC$(j}~PdXCC@SKl;R9niZYNt;A~)rc<3FUJL)&@w_?5yGb(H#t>d> zoZ;nce1E1TsiWdP+_=FmSi6`@%J?fUHl3$PKypTgjj@ewdOTgcurk}+jvz>8sqTeU z8TXSd@!*bf!r7HR_tqr1ON$C4LFNkHA*WUnRCktBZgu5&#(`+bHEG%jiQ)%2fR= z1a+3yL5nhpdk;91j^Utt?L(1IMoFyY*IBmOQM2+IWw;`|7yy0{!KZvaM3AK@8@UAS zSBM%pa+3i~RPK((QVHXm^is>(A%){*^)ShT1DW!z_RS5y$4N?OghN23#|1exZaMBu`N4UDUYjwECnI?A@Xn zS--H;AlH>Wp`9%FD_}%UbJfd*VlG+ zNZF<<{V>AFcxoAcJUa0R45ED*Pu)-rkKhupqERoi zpfERbqRMcHfBUvpur@k8dEutHe-9gu+_nH`X-C)DV3!&UcMrl%ysG8hJ5Uob6ZZ{n zKcyi_*_wF-IH0%haC_y0CbVIujWxes-YKw5>D-N)ZMF*sY04TRPf&D^W#=RSXT!-y z#6i>O>FGN1@M>?WWxI}@=N$VDz={*9Hr#$BY4F2L z&*6aEWv8;7;_+(Rm~+F*&hkD35G7ny`2l?i6>6n_h}U1kM$Hhcog@E*ai!@+){v28 zaCnfY?acJ;PKAIeRH!A}wiz)Ym?MP{1x#y21%4%RZJo2VcszeGF4Gq3u+$v)!4{pp zChMu88aOTGW6a$1nTUx58DrDui=Km);&A5$(j?_nxZ&&|Y~xj3(ipc%LwAOqU{x4y z(y?K+(bFMCZP|U?T^)KT&&YI=oBP+HXQSKZzbYiRAJ#>C1Wn5kgrND2%K_dZ@x@)w zyjRG%CW_rEh>|ARoop85xnqaQj6yp5Z%SKAKem^xloX ztQ#xEHh!X?1qHG7BY#$CL9;R#eym`wN+nH)lf$aF&G!j^rR=9v*Jg%^)dQ>urWcyH6%+ zINa{EDVf;p`Tr!sUkBEh9RqOV!ltJ^*#~eX$sY%`bOvy~dj#-0=0sUc52s=x4Nb@& zZfrWHv(%W8ODDBP$JPBOeeJe|Z>{4MQ?2!aR&vfWXa1)AEYumQv}W$z{qS&Aq|GyM z%X9cf9u&$to-!IlQpBP+YQHj!a9kS)tf)6@nM|^%wQ4iNlb$-=;x<%EI10r~Bsi^P zPQ+UC4C4=5?2kU#U7(O#S};99B};0{sy+$*Lw)?$-tUtk#P%c@5QhnFu#n4=iKT3I zx}Cn0>5HE?SuZk#rSj|vDd>bE6ZEt209(ljIMYIP5+C!1TV2228IgWs@7pBNr&Kqs zNm%Jdw&q>vGbNrT^AUbTqf!r%-Rvn;-jQiB*{i4j zx90rs3iM|`853ggsWUo=?-#Ia+m4kyDA8!Bw3Rba1(Vy=F3qv{y()r*MZ--_e?4`g z&**Y7TA)6&XLDJ~cm$Szn@WC~k;qo^Y>ALJv0|Mfqr`b>eg}~(m9E=dFK(ATyNcNT zCHk+!^GDl!KDuBqPa=Y*JwlV3h=ETyGMf9*)Rdd9p7BPb)7a>+NQQ(`Qkf>~B^bms zqPcW1ztgy7oH085dNq+MN%29p=l&L@dlRrNwAEPRdmBiN$ z;zaxN6aMt0XY%O(oD_ebEB8roRg@{|C*Tp{Z;1o zu>eC1Uc(|o`)~g0CovHBTWC2K&wuo4h`$a5A3ZR{_1FCQX#Y*te2WC)zE5PLY4nG3 z`L74U{`B_{_j#jZ{o@+t--kk;jaccVb$^Wpy{N&bIo{ZF+1UsJ2|7mhzUx}Qq* SsR|nK1yR;|SgB|c@_zs#uux(E literal 0 HcmV?d00001 diff --git a/docs/architecture/README.MD b/docs/architecture/README.md similarity index 97% rename from docs/architecture/README.MD rename to docs/architecture/README.md index 6b64c9c99402..f5b6a553305d 100644 --- a/docs/architecture/README.MD +++ b/docs/architecture/README.md @@ -1,3 +1,9 @@ +--- +order: false +parent: + order: false +--- + # Architecture Decision Records (ADR) This is a location to record all high-level architecture decisions in the Cosmos-SDK. diff --git a/docs/architecture/readme.md~origin_master-docs b/docs/architecture/readme.md~origin_master-docs new file mode 100644 index 000000000000..f0c07cb68565 --- /dev/null +++ b/docs/architecture/readme.md~origin_master-docs @@ -0,0 +1,5 @@ +--- +order: false +parent: + order: false +--- diff --git a/docs/basics/README.md b/docs/basics/README.md new file mode 100644 index 000000000000..c2e3e519fe76 --- /dev/null +++ b/docs/basics/README.md @@ -0,0 +1,16 @@ +--- +order: false +parent: + order: 2 +--- + +# Basics + +This repository contains reference documentation on the basic concepts of the Cosmos SDK. + +1. [Anatomy of an SDK Application](./app-anatomy.md) +2. [Lifecycle of a transaction](./tx-lifecycle.md) +3. [Accounts](./accounts.md) +4. [Gas and Fees](./gas-fees.md) + +After reading the basics, head on to the [Core Reference](../core/README.md) for more advanced material. \ No newline at end of file diff --git a/docs/basics/accounts.md b/docs/basics/accounts.md new file mode 100644 index 000000000000..ae69c081f549 --- /dev/null +++ b/docs/basics/accounts.md @@ -0,0 +1,134 @@ +--- +order: 3 +synopsis: This document describes the in-built accounts system of the Cosmos SDK. +--- + +# Accounts + +## Pre-requisite Readings {hide} + +- [Anatomy of an SDK Application](./app-anatomy.md) {prereq} + +## Account Definition + +In the Cosmos SDK, an *account* designates a pair of *public key* `PubKey` and *private key* `PrivKey`. The `PubKey` can be derived to generate various `Addresses`, which are used to identify users (among other parties) in the application. `Addresses` are also associated with [`message`s](../building-modules/messages-and-queries.md#messages) to identify the sender of the `message`. The `PrivKey` is used to generate [digital signatures](#signatures) to prove that an `Address` associated with the `PrivKey` approved of a given `message`. + +To derive `PubKey`s and `PrivKey`s, the Cosmos SDK uses a standard called [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki). This standard defines how to build an HD wallet, where a wallet is a set of accounts. At the core of every account, there is a seed, which takes the form of a 12 or 24-words mnemonic. From this mnemonic, it is possible to derive any number of `PrivKey`s using one-way cryptographic function. Then, a `PubKey` can be derived from the `PrivKey`. Naturally, the mnemonic is the most sensitive information, as private keys can always be re-generated if the mnemonic is preserved. + +``` + Account 0 Account 1 Account 2 + ++------------------+ +------------------+ +------------------+ +| | | | | | +| Address 0 | | Address 1 | | Address 2 | +| ^ | | ^ | | ^ | +| | | | | | | | | +| | | | | | | | | +| | | | | | | | | +| + | | + | | + | +| Public key 0 | | Public key 1 | | Public key 2 | +| ^ | | ^ | | ^ | +| | | | | | | | | +| | | | | | | | | +| | | | | | | | | +| + | | + | | + | +| Private key 0 | | Private key 1 | | Private key 2 | +| ^ | | ^ | | ^ | ++------------------+ +------------------+ +------------------+ + | | | + | | | + | | | + +--------------------------------------------------------------------+ + | + | + +---------+---------+ + | | + | Master PrivKey | + | | + +-------------------+ + | + | + +---------+---------+ + | | + | Mnemonic (Seed) | + | | + +-------------------+ +``` + +In the Cosmos SDK, accounts are stored and managed via an object called a [`Keybase`](#keybase). + +## Keybase + +A `Keybase` is an object that stores and manages accounts. In the Cosmos SDK, a `Keybase` implementation follows the `Keybase` interface: + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/crypto/keys/types.go#L13-L86 + +The default implementation of `Keybase` of the Cosmos SDK is `dbKeybase`. + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/crypto/keys/keybase.go + +A few notes on the `Keybase` methods as implemented in `dbKeybase`: + +- `Sign(name, passphrase string, msg []byte) ([]byte, crypto.PubKey, error)` strictly deals with the signature of the `message` bytes. Some preliminary work should be done beforehand to prepare and encode the `message` into a canonical `[]byte` form. See an example of `message` preparation from the `auth` module. Note that signature verification is not implemented in the SDK by default. It is deferred to the [`anteHandler`](#antehandler). + +++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/x/auth/types/txbuilder.go#L176-L209 +- `CreateMnemonic(name string, language Language, passwd string, algo SigningAlgo) (info Info, seed string, err error)` creates a new mnemonic and prints it in the logs, but it **does not persist it on disk**. +- `CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd string, account uint32, index uint32) (Info, error)` creates a new account based on the [`bip44 path`](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki) and persists it on disk (note that the `PrivKey` is [encrypted with a passphrase before being persisted](https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/crypto/keys/mintkey/mintkey.go), it is **never stored unencrypted**). In the context of this method, the `account` and `address` parameters refer to the segment of the BIP44 derivation path (e.g. `0`, `1`, `2`, ...) used to derive the `PrivKey` and `PubKey` from the mnemonic (note that given the same mnemonic and `account`, the same `PrivKey` will be generated, and given the same `account` and `address`, the same `PubKey` and `Address` will be generated). Finally, note that the `CreateAccount` method derives keys and addresses using `secp256k1` as implemented in the [Tendermint library](https://github.com/tendermint/tendermint/tree/bc572217c07b90ad9cee851f193aaa8e9557cbc7/crypto/secp256k1). As a result, it only works for creating account keys and addresses, not consensus keys. See [`Addresses`](#addresses) for more. + +The current implementation of `dbKeybase` is basic and does not offer on-demand locking. If an instance of `dbKeybase` is created, the underlying `db` is locked meaning no other process can access it besides the one in which it was instantiated. This is the reason why the default SDK client uses another implementation of the `Keybase` interface called `lazyKeybase`: + + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/crypto/keys/lazy_keybase.go + +`lazyKeybase` is simple wrapper around `dbKeybase` which locks the database only when operations are to be performed and unlocks it immediately after. With the `lazyKeybase`, it is possible for the [command-line interface](../interfaces/cli.md) to create a new account while the [rest server](../interfaces/rest.md) is running. It is also possible to pipe multiple CLI commands. + +## Addresses and PubKeys + +`Addresses` and `PubKey`s are both public information that identify actors in the application. There are 3 main types of `Addresses`/`PubKeys` available by default in the Cosmos SDK: + +- Addresses and Keys for **accounts**, which identify users (e.g. the sender of a `message`). They are derived using the **`secp256k1`** curve. +- Addresses and Keys for **validator operators**, which identify the operators of validators. They are derived using the **`secp256k1`** curve. +- Addresses and Keys for **consensus nodes**, which identify the validator nodes participating in consensus. They are derived using the **`ed25519`** curve. + +| | Address bech32 Prefix | Pubkey bech32 Prefix | Curve | Address byte length | Pubkey byte length | +|--------------------|-----------------------|----------------------|-------------|---------------------|--------------------| +| Accounts | cosmos | cosmospub | `secp256k1` | `20` | `33` | +| Validator Operator | cosmosvaloper | cosmosvaloperpub | `secp256k1` | `20` | `33` | +| Consensus Nodes | cosmosvalcons | cosmosvalconspub | `ed25519` | `20` | `32` | + +### PubKeys + +`PubKey`s used in the Cosmos SDK follow the `Pubkey` interface defined in tendermint's `crypto` package: + ++++ https://github.com/tendermint/tendermint/blob/bc572217c07b90ad9cee851f193aaa8e9557cbc7/crypto/crypto.go#L22-L27 + +For `secp256k1` keys, the actual implementation can be found [here](https://github.com/tendermint/tendermint/blob/bc572217c07b90ad9cee851f193aaa8e9557cbc7/crypto/secp256k1/secp256k1.go#L140). For `ed25519` keys, it can be found [here](https://github.com/tendermint/tendermint/blob/bc572217c07b90ad9cee851f193aaa8e9557cbc7/crypto/ed25519/ed25519.go#L135). + +Note that in the Cosmos SDK, `Pubkeys` are not manipulated in their raw form. Instead, they are double encoded using [`Amino`](../core/encoding.md#amino) and [`bech32`](https://en.bitcoin.it/wiki/Bech32). In the SDK is done by first calling the `Bytes()` method on the raw `Pubkey` (which applies amino encoding), and then the `ConvertAndEncode` method of `bech32`. + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/address.go#L579-L729 + +### Addresses + +The Cosmos SDK comes by default with 3 types of addresses: + +- `AccAddress` for accounts. +- `ValAddress` for validator operators. +- `ConsAddress` for validator nodes. + +Each of these address types are an alias for an hex-encoded `[]byte` array of length 20. Here is the standard way to obtain an address `aa` from a `Pubkey pub`: + +```go +aa := sdk.AccAddress(pub.Address().Bytes()) +``` + +These addresses implement the `Address` interface: + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/address.go#L71-L80 + +Of note, the `Marhsal()` and `Bytes()` method both return the same raw `[]byte` form of the address, the former being needed for Protobuff compatibility. Also, the `String()` method is used to return the `bech32` encoded form of the address, which should be the only address format with which end-user interract. Next is an example: + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/address.go#L229-L243 + +## Next {hide} + +Learn about [gas and fees](./gas-fees.md) {hide} \ No newline at end of file diff --git a/docs/basics/app-anatomy.md b/docs/basics/app-anatomy.md index 2f15fe626f43..e982306f342d 100644 --- a/docs/basics/app-anatomy.md +++ b/docs/basics/app-anatomy.md @@ -1,39 +1,15 @@ -# Anatomy of an SDK Application +--- +order: 1 +synopsis: "This document describes the core parts of a Cosmos SDK application. Throughout the document, a placeholder application named `app` will be used." +--- -## Pre-requisite reading +# Anatomy of an SDK Application -- [High-level overview of the architecture of an SDK application](../intro/sdk-app-architecture.md) -- [Cosmos SDK design overview](../intro/sdk-design.md) -## Synopsis - -This document describes the core parts of a Cosmos SDK application. The placeholder name for this application will be `app`. - -- [Node Client](#node-client) -- [Core Application File](#core-application-file) -- [Modules](#modules) -- [Interfaces](#interfaces) -- [Dependencies and Makefile](#dependencies-and-makefile) - -The core parts listed above will generally translate to the following directory tree: - -``` -./app -├── cmd/ -│ ├── appd -│ └── appcli -├── app.go -├── x/ -│ ├── auth -│ ├── ... -│ └── bank -├── go.mod -└── Makefile -``` ## Node Client -The Daemon, or Full-Node Client, is the core process of an SDK-based blockchain. Participants in the network run this process to initialize their state-machine, connect with other full-nodes and update their state-machine as new blocks come in. +The Daemon, or [Full-Node Client](../core/node.md), is the core process of an SDK-based blockchain. Participants in the network run this process to initialize their state-machine, connect with other full-nodes and update their state-machine as new blocks come in. ``` ^ +-------------------------------+ ^ @@ -53,15 +29,11 @@ Blockchain Node | | Consensus | | v +-------------------------------+ v ``` -The blockchain full-node presents itself as a binary, generally suffixed by `-d` for "daemon" (e.g. `appd` for `app` or `gaiad` for `gaia`). This binary is built by running a simple `main.go` function placed in `cmd/appd/`. This operation usually happens through the [Makefile](#dependencies-and-makefile). - -To learn more about the `main.go` function, [click here](./node.md#main-function). +The blockchain full-node presents itself as a binary, generally suffixed by `-d` for "daemon" (e.g. `appd` for `app` or `gaiad` for `gaia`). This binary is built by running a simple [`main.go`](../core/node.md#main-function) function placed in `./cmd/appd/`. This operation usually happens through the [Makefile](#dependencies-and-makefile). -Once the main binary is built, the node can be started by running the `start` command. The core logic behind the `start` command is implemented in the SDK itself in the [`/server/start.go`](https://github.com/cosmos/cosmos-sdk/blob/master/server/start.go) file. The main [`start` command function](https://github.com/cosmos/cosmos-sdk/blob/master/server/start.go#L31) takes a [`context`](https://godoc.org/github.com/cosmos/cosmos-sdk/client/context) and [`appCreator`](<#constructor-function-(`appCreator`)>) as arguments. The `appCreator` is a constructor function for the SDK application, and is used in the starting process of the full-node. +Once the main binary is built, the node can be started by running the [`start` command](../core/node.md#start-command). This command function primarily does three things: -The `start` command function primarily does three things: - -1. Create an instance of the state-machine defined in [`app.go`](#core-application-file) using the `appCreator`. +1. Create an instance of the state-machine defined in [`app.go`](#core-application-file). 2. Initialize the state-machine with the latest known state, extracted from the `db` stored in the `~/.appd/data` folder. At this point, the state-machine is at height `appBlockHeight`. 3. Create and start a new Tendermint instance. Among other things, the node will perform a handshake with its peers. It will get the latest `blockHeight` from them, and replay blocks to sync to this height if it is greater than the local `appBlockHeight`. If `appBlockHeight` is `0`, the node is starting from genesis and Tendermint sends an `InitChain` message via the ABCI to the `app`, which triggers the [`InitChainer`](#initchainer). @@ -73,104 +45,135 @@ In general, the core of the state-machine is defined in a file called `app.go`. The first thing defined in `app.go` is the `type` of the application. It is generally comprised of the following parts: -- **A reference to [`baseapp`](./baseapp.md).** The custom application defined in `app.go` is an extension of the `baseapp` type. `baseapp` implements most of the core logic for the application, including all the [ABCI methods](https://tendermint.com/docs/spec/abci/abci.html#overview) and the routing logic. When a transaction is relayed by Tendermint to the application, the latter uses `baseapp`'s methods to route them to the appropriate module. -- **A list of store keys**. The [store](./store.md), which contains the entire state, is implemented as a multistore (i.e. a store of stores) in the Cosmos SDK. Each module uses one or multiple stores in the multistore to persist their part of the state. These stores can be accessed with specific keys that are declared in the `app` type. These keys, along with the `keepers`, are at the heart of the [object-capabilities model](../intro/ocap.md) of the Cosmos SDK. -- **A list of module's `keepers`.** Each module defines an abstraction called `keeper`, which handles reads and writes for this module's store(s). The `keeper`'s methods of one module can be called from other modules (if authorized), which is why they are declared in the application's type and exported as interfaces to other modules so that they are only allowed to access the authorized functions. -- **A reference to a `codec`.** The Cosmos SDK gives developers the freedom to choose the encoding framework for their application. The application's `codec` is used to serialize and deserialize data structures in order to store them, as stores can only persist `[]bytes`. The `codec` must be deterministic. The default codec is [amino](./amino.md). -- **A reference to a [module manager](./modules.md#module-manager)**. The module manager is an object that contains a list of the application's module. It facilitates operations related to these modules, like registering [`routes`](./baseapp.md#routing), [query routes](#./baseapp.md#query-routing) or setting the order of execution between modules for various functions like [`InitChainer`](#initchainer), [`BeginBlocker` and `EndBlocker`](#beginblocker-and-endblocker). +- **A reference to [`baseapp`](../core/baseapp.md).** The custom application defined in `app.go` is an extension of `baseapp`. When a transaction is relayed by Tendermint to the application, `app` uses `baseapp`'s methods to route them to the appropriate module. `baseapp` implements most of the core logic for the application, including all the [ABCI methods](https://tendermint.com/docs/spec/abci/abci.html#overview) and the [routing logic](../core/baseapp.md#routing). +- **A list of store keys**. The [store](../core/store.md), which contains the entire state, is implemented as a [`multistore`](../core/store.md#multistore) (i.e. a store of stores) in the Cosmos SDK. Each module uses one or multiple stores in the multistore to persist their part of the state. These stores can be accessed with specific keys that are declared in the `app` type. These keys, along with the `keepers`, are at the heart of the [object-capabilities model](../core/ocap.md) of the Cosmos SDK. +- **A list of module's `keeper`s.** Each module defines an abstraction called [`keeper`](../building-modules/keeper.md), which handles reads and writes for this module's store(s). The `keeper`'s methods of one module can be called from other modules (if authorized), which is why they are declared in the application's type and exported as interfaces to other modules so that the latter can only access the authorized functions. +- **A reference to a [`codec`](../core/encoding.md).** The application's `codec` is used to serialize and deserialize data structures in order to store them, as stores can only persist `[]bytes`. The `codec` must be deterministic. The default codec is [amino](../core/encoding.md). +- **A reference to a [module manager](../building-modules/module-manager.md#manager)** and a [basic module manager](../building-modules/module-manager.md#basicmanager). The module manager is an object that contains a list of the application's module. It facilitates operations related to these modules, like registering [`routes`](../core/baseapp.md#routing), [query routes](../core/baseapp.md#query-routing) or setting the order of execution between modules for various functions like [`InitChainer`](#initchainer), [`BeginBlocker` and `EndBlocker`](#beginblocker-and-endblocker). + +See an example of application type definition from [`gaia`](https://github.com/cosmos/gaia) -You can see an example of application type definition [here](https://github.com/cosmos/gaia/blob/master/app/app.go#L73-L107). ++++ https://github.com/cosmos/gaia/blob/5bc422e6868d04747e50b467e8eeb31ae2fe98a3/app/app.go#L87-L115 ### Constructor Function -This function constructs a new application of the type defined above. It is called every time the full-node is started with the [`start`](https://github.com/cosmos/cosmos-sdk/blob/master/server/start.go#L117) command. Here are the main actions performed by this function: +This function constructs a new application of the type defined in the section above. It must fulfill the `AppCreator` signature in order to be used in the [`start` command](../core/node.md#start-command) of the application's daemon command. ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/server/constructors.go#L20 + +Here are the main actions performed by this function: + +- Instantiate a new [`codec`](../core/encoding.md) and initialize the `codec` of each of the application's module using the [basic manager](../building-modules/module-manager.md#basicmanager) - Instantiate a new application with a reference to a `baseapp` instance, a codec and all the appropriate store keys. -- Instantiate all the [`keeper`s](#keeper) defined in the application's `type` using the `NewKeeper` function of each of the application's modules. Note that `keepers` must be instantiated in the correct order, as the `NewKeeper` of one module might require a reference to another module's `keeper`. -- Instantiate the application's [module manager](./module-manager.md) with the [`AppModule`](#application-module-interface) object of each of the application's modules. -- With the module manager, initialize the application's [`routes`](./baseapp.md#routing) and [query routes](./baseapp.md#query-routing). When a transaction is relayed to the application by Tendermint via the ABCI, it is routed to the appropriate module's [`handler`](#handler) using the routes defined here. Likewise, when a query is received by the application, it is routed to the appropriate module's [`querier`](#querier) using the query routes defined here. -- With the module manager, register the [application's modules' invariants](./invariants.md). Invariants are variables (e.g. total supply of a token) that are evaluated at the end of each block. The process of checking invariants is done via a special module called the [`InvariantsRegistry`](./invariants.md#invariant-registry). The value of the invariant should be equal to a predicted value defined in the module. Should the value be different than the predicted one, special logic defined in the invariant registry will be triggered (usually the chain is halted). This is useful to make sure no critical bug goes unnoticed and produces long-lasting effects that would be hard to fix. -- With the module manager, set the order of execution between the `InitGenesis`, `BegingBlocker` and `EndBlocker` functions of each of the [application's modules](#application-module-interface). Note that not all modules implement these functions. +- Instantiate all the [`keeper`s](#keeper) defined in the application's `type` using the `NewKeeper` function of each of the application's modules. Note that `keepers` must be instantiated in the correct order, as the `NewKeeper` of one module might require a reference to another module's `keeper`. +- Instantiate the application's [module manager](../building-modules/module-manager.md#manager) with the [`AppModule`](#application-module-interface) object of each of the application's modules. +- With the module manager, initialize the application's [`routes`](../core/baseapp.md#routing) and [query routes](../core/baseapp.md#query-routing). When a transaction is relayed to the application by Tendermint via the ABCI, it is routed to the appropriate module's [`handler`](#handler) using the routes defined here. Likewise, when a query is received by the application, it is routed to the appropriate module's [`querier`](#querier) using the query routes defined here. +- With the module manager, register the [application's modules' invariants](../building-modules/invariants.md). Invariants are variables (e.g. total supply of a token) that are evaluated at the end of each block. The process of checking invariants is done via a special module called the [`InvariantsRegistry`](../building-modules/invariants.md#invariant-registry). The value of the invariant should be equal to a predicted value defined in the module. Should the value be different than the predicted one, special logic defined in the invariant registry will be triggered (usually the chain is halted). This is useful to make sure no critical bug goes unnoticed and produces long-lasting effects that would be hard to fix. +- With the module manager, set the order of execution between the `InitGenesis`, `BegingBlocker` and `EndBlocker` functions of each of the [application's modules](#application-module-interface). Note that not all modules implement these functions. - Set the remainer of application's parameters: - - [`InitChainer`](#initchainer): used to initialize the application when it is first started. - - [`BeginBlocker`, `EndBlocker`](#beginblocker-and-endlbocker): called at the beginning and the end of every block). - - [`anteHandler`](#baseapp.md#antehandler): used to handle fees and signature verification. -- Mount the stores. -- Return the application. + + [`InitChainer`](#initchainer): used to initialize the application when it is first started. + + [`BeginBlocker`, `EndBlocker`](#beginblocker-and-endlbocker): called at the beginning and the end of every block). + + [`anteHandler`](../core/baseapp.md#antehandler): used to handle fees and signature verification. +- Mount the stores. +- Return the application. Note that this function only creates an instance of the app, while the actual state is either carried over from the `~/.appd/data` folder if the node is restarted, or generated from the genesis file if the node is started for the first time. -You can see an example of application constructor [here](https://github.com/cosmos/gaia/blob/master/app/app.go#L110-L222). +See an example of application constructor from [`gaia`](https://github.com/cosmos/gaia): + ++++ https://github.com/cosmos/gaia/blob/f41a660cdd5bea173139965ade55bd25d1ee3429/app/app.go#L110-L222 ### InitChainer -The `InitChainer` is a function that initializes the state of the application from a [genesis file](./genesis.md) (i.e. token balances of genesis accounts). It is called when the application receives the `InitChain` message from the Tendermint engine, which happens when the node is started at `appBlockHeight == 0` (i.e. on genesis). The application must set the `InitChainer` in its constructor via the [`SetInitChainer`](https://godoc.org/github.com/cosmos/cosmos-sdk/baseapp#BaseApp.SetInitChainer) method. +The `InitChainer` is a function that initializes the state of the application from a genesis file (i.e. token balances of genesis accounts). It is called when the application receives the `InitChain` message from the Tendermint engine, which happens when the node is started at `appBlockHeight == 0` (i.e. on genesis). The application must set the `InitChainer` in its [constructor](#constructor-function) via the [`SetInitChainer`](https://godoc.org/github.com/cosmos/cosmos-sdk/baseapp#BaseApp.SetInitChainer) method. -In general, the `InitChainer` is mostly composed of the `InitGenesis` function of each of the application's modules. This is done by calling the `InitGenesis` function of the module manager, which in turn will call the `InitGenesis` function of each of the modules it contains. Note that the order in which the modules' `InitGenesis` functions must be called has to be set in the module manager using the `SetOrderInitGenesis` method. This is done in the [application's constructor](#application-constructor), and the `SetOrderInitGenesis` has to be called before the `SetInitChainer`. +In general, the `InitChainer` is mostly composed of the [`InitGenesis`](../building-modules/genesis.md#initgenesis) function of each of the application's modules. This is done by calling the `InitGenesis` function of the module manager, which in turn will call the `InitGenesis` function of each of the modules it contains. Note that the order in which the modules' `InitGenesis` functions must be called has to be set in the module manager using the [module manager's](../building-modules/module-manager.md) `SetOrderInitGenesis` method. This is done in the [application's constructor](#application-constructor), and the `SetOrderInitGenesis` has to be called before the `SetInitChainer`. -You can see an example of an `InitChainer` [here](https://github.com/cosmos/gaia/blob/master/app/app.go#L235-L239). +See an example of an `InitChainer` from [`gaia`](https://github.com/cosmos/gaia): + ++++ https://github.com/cosmos/gaia/blob/f41a660cdd5bea173139965ade55bd25d1ee3429/app/app.go#L235-L239 ### BeginBlocker and EndBlocker -The SDK offers developers the possibility to implement automatic execution of code as part of their application. This is implemented through two function called `BeginBlocker` and `EndBlocker`. They are called when the application receives respectively the `BeginBlock` and `EndBlock` messages from the Tendermint engine, which happens at the beginning and at the end of each block. The application must set the `BeginBlocker` and `EndBlocker` in its constructor via the [`SetBeginBlocker`](https://godoc.org/github.com/cosmos/cosmos-sdk/baseapp#BaseApp.SetBeginBlocker) and [`SetEndBlocker`](https://godoc.org/github.com/cosmos/cosmos-sdk/baseapp#BaseApp.SetEndBlocker) methods. +The SDK offers developers the possibility to implement automatic execution of code as part of their application. This is implemented through two function called `BeginBlocker` and `EndBlocker`. They are called when the application receives respectively the `BeginBlock` and `EndBlock` messages from the Tendermint engine, which happens at the beginning and at the end of each block. The application must set the `BeginBlocker` and `EndBlocker` in its [constructor](#constructor-function) via the [`SetBeginBlocker`](https://godoc.org/github.com/cosmos/cosmos-sdk/baseapp#BaseApp.SetBeginBlocker) and [`SetEndBlocker`](https://godoc.org/github.com/cosmos/cosmos-sdk/baseapp#BaseApp.SetEndBlocker) methods. -In general, the `BeginBlocker` and `EndBlocker` functions are mostly composed of the `BeginBlock` and `EndBlock` functions of each of the application's modules. This is done by calling the `BeginBlock` and `EndBlock` functions of the module manager, which in turn will call the `BeginBLock` and `EndBlock` functions of each of the modules it contains. Note that the order in which the modules' `BegingBlock` and `EndBlock` functions must be called has to be set in the module manager using the `SetOrderBeginBlock` and `SetOrderEndBlock` methods respectively. This is done in the [application's constructor](#application-constructor), and the `SetOrderBeginBlock` and `SetOrderEndBlock` methods have to be called before the `SetBeginBlocker` and `SetEndBlocker` functions. +In general, the `BeginBlocker` and `EndBlocker` functions are mostly composed of the [`BeginBlock` and `EndBlock`](../building-modules/beginblock-endblock.md) functions of each of the application's modules. This is done by calling the `BeginBlock` and `EndBlock` functions of the module manager, which in turn will call the `BeginBLock` and `EndBlock` functions of each of the modules it contains. Note that the order in which the modules' `BegingBlock` and `EndBlock` functions must be called has to be set in the module manager using the `SetOrderBeginBlock` and `SetOrderEndBlock` methods respectively. This is done via the [module manager](../building-modules/module-manager.md) in the [application's constructor](#application-constructor), and the `SetOrderBeginBlock` and `SetOrderEndBlock` methods have to be called before the `SetBeginBlocker` and `SetEndBlocker` functions. -As a sidenote, it is important to remember that application-specific blockchains are deterministic. Developers must be careful not to introduce non-determinism in `BeginBlocker` or `EndBlocker`, and must also be careful not to make them too computationally expensive, as gas does not constrain the cost of `BeginBlocker` and `EndBlocker` execution. +As a sidenote, it is important to remember that application-specific blockchains are deterministic. Developers must be careful not to introduce non-determinism in `BeginBlocker` or `EndBlocker`, and must also be careful not to make them too computationally expensive, as [gas](./gas-fees.md) does not constrain the cost of `BeginBlocker` and `EndBlocker` execution. -You can see an example of `BeginBlocker` and `EndBlocker` functions [here](https://github.com/cosmos/gaia/blob/master/app/app.go#L224-L232). +See an example of `BeginBlocker` and `EndBlocker` functions from [`gaia`](https://github.com/cosmos/gaia) + ++++ https://github.com/cosmos/gaia/blob/f41a660cdd5bea173139965ade55bd25d1ee3429/app/app.go#L224-L232 ### Register Codec -The `MakeCodec` function is the last important function of the `app.go` file. The goal of this function is to instantiate a codec `cdc` (e.g. amino) initialize the codec of the SDK and each of the application's modules using the `RegisterCodec` function. +The `MakeCodec` function is the last important function of the `app.go` file. The goal of this function is to instantiate a [codec `cdc`](../core/encoding.md) (e.g. amino) initialize the codec of the SDK and each of the application's modules using the `RegisterCodec` function. -To register the application's modules, the `MakeCodec` function calls `RegisterCodec` on `ModuleBasics`. `ModuleBasics` is a basic manager which lists all of the application's modules. It is instantiated in the `init()` function, and only serves to easily register non-dependent elements of application's modules (such as codec). To learn more about the basic module manager,. +To register the application's modules, the `MakeCodec` function calls `RegisterCodec` on `ModuleBasics`. `ModuleBasics` is a [basic manager](../building-modules/module-manager.md#basicmanager) which lists all of the application's modules. It is instanciated in the `init()` function, and only serves to easily register non-dependant elements of application's modules (such as codec). To learn more about the basic module manager, click [here](../building-modules/module-manager.md#basicmanager). -You can see an example of a `MakeCodec` [here](https://github.com/cosmos/gaia/blob/master/app/app.go#L64-L70) +See an example of a `MakeCodec` from [`gaia`](https://github.com/cosmos/gaia): + ++++ https://github.com/cosmos/gaia/blob/f41a660cdd5bea173139965ade55bd25d1ee3429/app/app.go#L64-L70 ## Modules -Modules are the heart and soul of an SDK application. They can be considered as state-machines within the state-machine. When a transaction is relayed from the underlying Tendermint engine via the ABCI to the application, it is routed by `baseapp` to the appropriate module in order to be processed. This paradigm enables developers to easily build complex state-machines, as most of the modules they need often already exist. For developers, most of the work involved in building an SDK application revolves around building custom modules required by their application that do not exist, and integrating them with modules that do already exist into one coherent application. In the application directory, the standard practice is to store modules in the `x/` folder (not to be confused with the SDK's `x/` folder, which contains already-built modules). +[Modules](../building-modules/intro.md) are the heart and soul of SDK applications. They can be considered as state-machines within the state-machine. When a transaction is relayed from the underlying Tendermint engine via the ABCI to the application, it is routed by [`baseapp`](../core/baseapp.md) to the appropriate module in order to be processed. This paradigm enables developers to easily build complex state-machines, as most of the modules they need often already exist. For developers, most of the work involved in building an SDK application revolves around building custom modules required by their application that do not exist yet, and integrating them with modules that do already exist into one coherent application. In the application directory, the standard practice is to store modules in the `x/` folder (not to be confused with the SDK's `x/` folder, which contains already-built modules). ### Application Module Interface -Modules implement two interfaces defined in the Cosmos SDK, [`AppModuleBasic`](https://github.com/cosmos/cosmos-sdk/blob/master/types/module/module.go#L44-L57) and [`AppModule`](https://github.com/cosmos/cosmos-sdk/blob/master/types/module/module.go#L44-L57). The former implements basic non-dependant elements of the module, such as the `codec`, while the latter handles the bulk of the module methods (including methods that require references to other modules' `keeper`s). Both the `AppModule` and `AppModuleBasic` types are defined in a file called `./module.go`. - -`AppModule` exposes a collection of useful methods on the module that facilitates the composition of modules into a coherent application. Important methods include: +Modules must implement [interfaces](../building-modules/module-manager.md#application-module-interfaces) defined in the Cosmos SDK, [`AppModuleBasic`](../building-modules/module-manager.md#appmodulebasic) and [`AppModule`](../building-modules/module-manager.md#appmodule). The former implements basic non-dependant elements of the module, such as the `codec`, while the latter handles the bulk of the module methods (including methods that require references to other modules' `keeper`s). Both the `AppModule` and `AppModuleBasic` types are defined in a file called `./module.go`. -- `Route()` and `QueryRoute()`: These methods the name of the route and querier route for the module, for [messages](#message-types) to be routed to the module's [`handler`](#handler) and queries to be routes to the module's [`querier`](#querier). -- `NewHandler()` and `NewQuerierHandler()`: These methods return a `handler` and `querierHandler` respectively, in order to process a message or a query once they are routed. -- `BeginBlock()`, `EndBlock()` and `InitGenesis()`: These methods are executed respectively at the beginning of each block, at the end of each block and at the start of the chain. They implement special logic the module requires to be triggered during those events. For example, the `EndBlock` function is frequently used by modules where voting occurs to tally the result of the votes. -- `RegisterInvariants()`: This method registers the [invariants](./invariants.md) for the module. Invariants are checked at the end of every block to make sure no unpredicted behaviour is occuring. -- `AppModule`'s methods are called from the `module manager`, which manages the application's collection of modules. +`AppModule` exposes a collection of useful methods on the module that facilitates the composition of modules into a coherent application. These methods are are called from the `module manager`(../building-modules/module-manager.md#manager), which manages the application's collection of modules. ### Message Types -A message is a custom type defined by each module that implements the [`message`](https://github.com/cosmos/cosmos-sdk/blob/master/types/tx_msg.go#L8-L29) interface. Each `transaction` contains one or multiple `messages`. When a valid block of transactions is received by the full-node, Tendermint relays each one to the application via [`DeliverTx`](https://tendermint.com/docs/app-dev/abci-spec.html#delivertx). Then, the application handles the transaction: +[`Message`s](../building-modules/messages-and-queries.md#messages) are objects defined by each module that implement the [`message`](../building-modules/messages-and-queries.md#messages) interface. Each [`transaction`](../core/transactions.md) contains one or multiple `messages`. -1. Upon receiving the transaction, the application first unmarshals it from `[]bytes`. -2. Then, it verifies a few things about the transaction like [fee payment and signatures](#accounts-fees-gas.md) before extracting the message(s) contained in the transaction. -3. With the [`Type()`](https://github.com/cosmos/cosmos-sdk/blob/master/types/tx_msg.go#L16) method, `baseapp` is able to know which modules defines the message. It is then able to route it to the appropriate module's [handler](#handler) in order for the message to be processed. -4. If the message is successfully processed, the state is updated. +When a valid block of transactions is received by the full-node, Tendermint relays each one to the application via [`DeliverTx`](https://tendermint.com/docs/app-dev/abci-spec.html#delivertx). Then, the application handles the transaction: + +1. Upon receiving the transaction, the application first unmarshalls it from `[]bytes`. +2. Then, it verifies a few things about the transaction like [fee payment and signatures](#gas-fees.md#antehandler) before extracting the message(s) contained in the transaction. +3. With the `Type()` method of the `message`, `baseapp` is able to route it to the appropriate module's [`handler`](#handler) in order for it to be processed. +4. If the message is successfully processed, the state is updated. For a more detailed look at a transaction lifecycle, click [here](./tx-lifecycle.md). -Module developers create custom message types when they build their own module. The general practice is to prefix the type declaration of the message with `Msg`. For example, the message type [`MsgSend`](https://github.com/cosmos/cosmos-sdk/blob/master/x/bank/types/msgs.go#L10-L15) allows users to transfer tokens. It is processed by the handler of the `bank` module, which ultimately calls the `keeper` of the `auth` module in order to update the state. +Module developers create custom message types when they build their own module. The general practice is to prefix the type declaration of the message with `Msg`. For example, the message type `MsgSend` allows users to transfer tokens: + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/x/bank/internal/types/msgs.go#L10-L15 + +It is processed by the `handler` of the `bank` module, which ultimately calls the `keeper` of the `auth` module in order to update the state. ### Handler -The `handler` refers to the part of the module responsible for processing the message after it is routed by `baseapp`. `handler` functions of modules (except those of the `auth` module) are only executed if the transaction is relayed from Tendermint by the `DeliverTx` ABCI message. If the transaction is relayed by `CheckTx`, only stateless checks and fee-related (i.e. `auth` module-related) stateful checks are performed. To better understand the difference between `DeliverTx`and `CheckTx`, as well as the difference between stateful and stateless checks, click [here](./tx-lifecycle.md). +The [`handler`](../building-modules/handler.md) refers to the part of the module responsible for processing the `message` after it is routed by `baseapp`. `handler` functions of modules are only executed if the transaction is relayed from Tendermint by the `DeliverTx` ABCI message. If the transaction is relayed by `CheckTx`, only stateless checks and fee-related stateful checks are performed. To better understand the difference between `DeliverTx`and `CheckTx`, as well as the difference between stateful and stateless checks, click [here](./tx-lifecycle.md). + +The `handler` of a module is generally defined in a file called `handler.go` and consists of: -The handler of a module is generally defined in a file called `handler.go` and consists of: +- A **switch function** `NewHandler` to route the message to the appropriate `handler` function. This function returns a `handler` function, and is registered in the [`AppModule`](#application-module-interface) to be used in the application's module manager to initialize the [application's router](../core/baseapp.md#routing). Next is an example of such a switch from the [nameservice tutorial](https://github.com/cosmos/sdk-tutorials/tree/master/nameservice) + +++ https://github.com/cosmos/sdk-tutorials/blob/master/nameservice/x/nameservice/handler.go#L12-L26 +- **One handler function for each message type defined by the module**. Developers write the message processing logic in these functions. This generally involves doing stateful checks to ensure the message is valid and calling [`keeper`](#keeper)'s methods to update the state. -- A **switch function** `NewHandler` to route the message to the appropriate handler function. This function returns a `handler` function, and is registered in the [`AppModule`](#application-module-interface) to be used in the application's module manager to initialize the application's router. See an example of such a switch [here](https://github.com/cosmos/sdk-application-tutorial/blob/master/x/nameservice/handler.go#L10-L22). -- **One handler function for each message type defined by the module**. Developers write the message processing logic in these functions. This generally involves doing stateful checks to ensure the message is valid and calling [`keeper`](#keeper)'s methods to update the state. +Handler functions return a result of type `sdk.Result`, which informs the application on whether the message was successfully processed: + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/result.go#L15-L40 + +### Querier + +[`Queriers`](../building-modules/querier.md) are very similar to `handlers`, except they serve user queries to the state as opposed to processing transactions. A [query](../building-modules/messages-and-queries.md#queries) is initiated from an [interface](#interfaces) by an end-user who provides a `queryRoute` and some `data`. The query is then routed to the correct application's `querier` by `baseapp`'s `handleQueryCustom` method using `queryRoute`: + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/baseapp/abci.go#L395-L453 + +The `Querier` of a module is defined in a file called `querier.go`, and consists of: + +- A **switch function** `NewQuerier` to route the query to the appropriate `querier` function. This function returns a `querier` function, and is is registered in the [`AppModule`](#application-module-interface) to be used in the application's module manager to initialize the [application's query router](../core/baseapp.md#query-routing). See an example of such a switch from the [nameservice tutorial](https://github.com/cosmos/sdk-tutorials/tree/master/nameservice): + +++ https://github.com/cosmos/sdk-tutorials/blob/86a27321cf89cc637581762e953d0c07f8c78ece/nameservice/x/nameservice/internal/keeper/querier.go#L19-L32 +- **One querier function for each data type defined by the module that needs to be queryable**. Developers write the query processing logic in these functions. This generally involves calling [`keeper`](#keeper)'s methods to query the state and marshalling it to JSON. -Handler functions return a result of type [`sdk.Result`](https://github.com/cosmos/cosmos-sdk/blob/master/types/result.go#L14-L37), which informs the application on whether the message was successfully processed. ### Keeper -`Keepers` are the gatekeepers of their module's store(s). To read or write in a module's store, it is mandatory to go through one of its `keeper`'s methods. This is ensured by the [object-capabilities](./ocap.md) model of the Cosmos SDK. Only objects that hold the key to a store can access it, and only the module's `keeper` should hold the key(s) to the module's store(s). +[`Keepers`](../building-modules/keeper.md) are the gatekeepers of their module's store(s). To read or write in a module's store, it is mandatory to go through one of its `keeper`'s methods. This is ensured by the [object-capabilities](../core/ocap.md) model of the Cosmos SDK. Only objects that hold the key to a store can access it, and only the module's `keeper` should hold the key(s) to the module's store(s). `Keepers` are generally defined in a file called `keeper.go`. It contains the `keeper`'s type definition and methods. @@ -180,18 +183,7 @@ The `keeper` type definition generally consists of: - Reference to **other module's `keepers`**. Only needed if the `keeper` needs to access other module's store(s) (either to read or write from them). - A reference to the application's **codec**. The `keeper` needs it to marshal structs before storing them, or to unmarshal them when it retrieves them, because stores only accept `[]bytes` as value. -Along with the type definition, the next important component of the `keeper.go` file is the `keeper`'s constructor function, `NewKeeper`. This function instantiates a new `keeper` of the type defined above, with a `codec`, store `keys` and potentially references to other modules' `keeper`s as parameters. The `NewKeeper` function is called from the [application's constructor](#constructor-function). - -The rest of the file defines the `keeper`'s methods, primarily getters and setters. You can check an example of a `keeper` implementation [here](https://github.com/cosmos/sdk-application-tutorial/blob/master/x/nameservice/keeper.go). - -### Querier - -`Queriers` are very similar to `handlers`, except they serve user queries to the state as opposed to processing transactions. A query is initiated from an [interface](#intefaces) by an end-user who provides a `queryRoute` and some `data`. The query is then routed to the correct application's `querier` by `baseapp`'s [`handleQueryCustom`](https://github.com/cosmos/cosmos-sdk/blob/master/baseapp/baseapp.go#L519-L556) method using `queryRoute`. - -The `Querier` of a module is defined in a file called `querier.go`, and consists of: - -- A **switch function** `NewQuerier` to route the query to the appropriate `querier` function. This function returns a `querier` function, and is is registered in the [`AppModule`](#application-module-interface) to be used in the application's module manager to initialize the application's query router. See an example of such a switch [here](https://github.com/cosmos/sdk-application-tutorial/blob/master/x/nameservice/querier.go#L21-L34). -- - **One querier function for each data type defined by the module that needs to be queryable**. Developers write the query processing logic in these functions. This generally involves calling [`keeper`](#keeper)'s methods to query the state and marshaling it to JSON. See an example of `querier` functions [here](https://github.com/cosmos/sdk-application-tutorial/blob/master/x/nameservice/querier.go#L37-L101). +Along with the type definition, the next important component of the `keeper.go` file is the `keeper`'s constructor function, `NewKeeper`. This function instantiates a new `keeper` of the type defined above, with a `codec`, store `keys` and potentially references to other modules' `keeper`s as parameters. The `NewKeeper` function is called from the [application's constructor](#constructor-function). The rest of the file defines the `keeper`'s methods, primarily getters and setters. ### Command-Line and REST Interfaces @@ -199,40 +191,45 @@ Each module defines command-line commands and REST routes to be exposed to end-u #### CLI -Generally, the commands related to a module are defined in a folder called `client/cli` in the module's folder. The CLI divides commands in two category, transactions and queries, defined in `client/cli/tx.go` and `client/cli/query.go` respectively. Both commands are built on top of the [Cobra Library](https://github.com/spf13/cobra): +Generally, the [commands related to a module](../building-modules/module-interfaces.md#cli) are defined in a folder called `client/cli` in the module's folder. The CLI divides commands in two category, transactions and queries, defined in `client/cli/tx.go` and `client/cli/query.go` respectively. Both commands are built on top of the [Cobra Library](https://github.com/spf13/cobra): -- Transactions commands let users generate new transactions so that they can be included in a block and eventually update the state. One command should be created for each [message type](#message-types) defined in the module. The command calls the constructor of the message with the parameters provided by the end-user, and wraps it into a transaction. The SDK handles signing and the addition of other transaction metadata. See examples of transactions commands [here](https://github.com/cosmos/sdk-application-tutorial/blob/master/x/nameservice/client/cli/tx.go). -- Queries let users query the subset of the state defined by the module. Query commands forward queries to the [application's query router](./baseapp.md#query-routing), which routes them to the appropriate [querier](#querier) the `queryRoute` parameter supplied. See examples of query commands [here](https://github.com/cosmos/sdk-application-tutorial/blob/master/x/nameservice/client/cli/query.go). +- Transactions commands let users generate new transactions so that they can be included in a block and eventually update the state. One command should be created for each [message type](#message-types) defined in the module. The command calls the constructor of the message with the parameters provided by the end-user, and wraps it into a transaction. The SDK handles signing and the addition of other transaction metadata. +- Queries let users query the subset of the state defined by the module. Query commands forward queries to the [application's query router](../core/baseapp.md#query-routing), which routes them to the appropriate [querier](#querier) the `queryRoute` parameter supplied. #### REST -The module's REST interface lets users generate transactions and query the state through REST calls to the application's light client daemon (LCD). REST routes are defined in a file `client/rest/rest.go`, which is composed of: +The [module's REST interface](../building-modules/module-interfaces.md#rest) lets users generate transactions and query the state through REST calls to the application's [light client daemon](../core/node.md#lcd) (LCD). REST routes are defined in a file `client/rest/rest.go`, which is composed of: - A `RegisterRoutes` function, which registers each route defined in the file. This function is called from the [main application's interface](#application-interfaces) for each module used within the application. The router used in the SDK is [Gorilla's mux](https://github.com/gorilla/mux). -- Custom request type definitions for each query or transaction creation function that needs to be exposed. These custom request types build on the [base `request` type](https://github.com/cosmos/cosmos-sdk/blob/master/types/rest/rest.go#L32-L43) of the Cosmos SDK. +- Custom request type definitions for each query or transaction creation function that needs to be exposed. These custom request types build on the base `request` type of the Cosmos SDK: + +++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/rest/rest.go#L47-L60 - One handler function for each request that can be routed to the given module. These functions implement the core logic necessary to serve the request. -See an example of a module's `rest.go` file [here](https://github.com/cosmos/sdk-application-tutorial/blob/master/x/nameservice/client/rest/rest.go). - ## Application Interface -Interfaces let end-users interact with full-node clients. This means querying data from the full-node or creating and sending new transactions to be relayed by the full-node and eventually included in a block. +[Interfaces](../interfaces/interfaces-intro.md) let end-users interact with full-node clients. This means querying data from the full-node or creating and sending new transactions to be relayed by the full-node and eventually included in a block. -The main interface is the Command-Line Interface. The CLI of an SDK application is built by aggregating [CLI commands](#cli) defined in each of the modules used by the application. The CLI of an application generally has the `-cli` suffix (e.g. `appcli`), and defined in a file called `cmd/appcli/main.go`. The file contains: +The main interface is the [Command-Line Interface](../interfaces/cli.md). The CLI of an SDK application is built by aggregating [CLI commands](#cli) defined in each of the modules used by the application. The CLI of an application generally has the `-cli` suffix (e.g. `appcli`), and defined in a file called `cmd/appcli/main.go`. The file contains: - **A `main()` function**, which is executed to build the `appcli` interface client. This function prepares each command and adds them to the `rootCmd` before building them. At the root of `appCli`, the function adds generic commands like `status`, `keys` and `config`, query commands, tx commands and `rest-server`. -- **Query commands** are added by calling the `queryCmd` function, also defined in `appcli/main.go`. This function returns a Cobra command that contains the query commands defined in each of the application's modules (passed as an array of `sdk.ModuleClients` from the `main()` function), as well as some other lower level query commands such as block or validator queries. Query command are called by using the command `appcli query [query]` of the CLI. -- **Transaction commands** are added by calling the `txCmd` function. Similar to `queryCmd`, the function returns a Cobra command that contains the tx commands defined in each of the application's modules, as well as lower level tx commands like transaction signing or broadcasting. Tx commands are called by using the command `appcli tx [tx]` of the CLI. -- **A `registerRoutes` function**, which is called from the `main()` function when initializing the [application's light-client daemon (LCD)](./node.md#lcd) (i.e. `rest-server`). `registerRoutes` calls the `RegisterRoutes` function of each of the application's module, thereby registering the routes of the module to the lcd's router. The LCD can be started by running the following command `appcli rest-server`. +- **Query commands** are added by calling the `queryCmd` function, also defined in `appcli/main.go`. This function returns a Cobra command that contains the query commands defined in each of the application's modules (passed as an array of `sdk.ModuleClients` from the `main()` function), as well as some other lower level query commands such as block or validator queries. Query command are called by using the command `appcli query [query]` of the CLI. +- **Transaction commands** are added by calling the `txCmd` function. Similar to `queryCmd`, the function returns a Cobra command that contains the tx commands defined in each of the application's modules, as well as lower level tx commands like transaction signing or broadcasting. Tx commands are called by using the command `appcli tx [tx]` of the CLI. +- **A `registerRoutes` function**, which is called from the `main()` function when initializing the [application's light-client daemon (LCD)](../core/node.md#lcd) (i.e. `rest-server`). `registerRoutes` calls the `RegisterRoutes` function of each of the application's module, thereby registering the routes of the module to the lcd's router. The LCD can be started by running the following command `appcli rest-server`. + +See an example of an application's main command-line file from the [nameservice tutorial](https://github.com/cosmos/sdk-tutorials/tree/master/nameservice) -See an example of an application's main command-line file [here](https://github.com/cosmos/sdk-application-tutorial/blob/master/cmd/nscli/main.go). ++++ https://github.com/cosmos/sdk-tutorials/blob/86a27321cf89cc637581762e953d0c07f8c78ece/nameservice/cmd/nscli/main.go ## Dependencies and Makefile -This section is optional, as developers are free to choose their dependency manager and project building method. That said, the current most used framework for versioning control is [`go.mod`](https://github.com/golang/go/wiki/Modules). It ensures each of the libraries used throughout the application are imported with the correct version. An example can be found [here](https://github.com/cosmos/sdk-application-tutorial/blob/master/go.mod). +This section is optional, as developers are free to choose their dependency manager and project building method. That said, the current most used framework for versioning control is [`go.mod`](https://github.com/golang/go/wiki/Modules). It ensures each of the libraries used throughout the application are imported with the correct version. See an example from the [nameservice tutorial](https://github.com/cosmos/sdk-tutorials/tree/master/nameservice): + ++++ https://github.com/cosmos/sdk-tutorials/blob/c6754a1e313eb1ed973c5c91dcc606f2fd288811/go.mod#L1-L18 + +For building the application, a [Makefile](https://en.wikipedia.org/wiki/Makefile) is generally used. The Makefile primarily ensures that the `go.mod` is run before building the two entrypoints to the application, [`appd`](#node-client) and [`appcli`](#application-interface). See an example of Makefile from the [nameservice tutorial]() -For building the application, a [Makefile](https://en.wikipedia.org/wiki/Makefile) is generally used. The Makefile primarily ensures that the `go.mod` is run before building the two entrypoints to the application, [`appd`](#node-client) and [`appcli`](#application-interface). An example of Makefile can be found [here](https://github.com/cosmos/sdk-application-tutorial/blob/master/Makefile). ++++ https://github.com/cosmos/sdk-tutorials/blob/86a27321cf89cc637581762e953d0c07f8c78ece/nameservice/Makefile -## Next +## Next {hide} -Learn more about the [Lifecycle of a transaction](./tx-lifecycle.md). +Learn more about the [Lifecycle of a transaction](./tx-lifecycle.md) {hide} diff --git a/docs/basics/gas-fees.md b/docs/basics/gas-fees.md new file mode 100644 index 000000000000..b54a7f19be60 --- /dev/null +++ b/docs/basics/gas-fees.md @@ -0,0 +1,88 @@ +--- +order: 4 +synopsis: This document describes the default strategies to handle gas and fees within a Cosmos SDK application. +--- + +# Gas and Fees + +## Pre-requisite Readings {hide} + +- [Anatomy of an SDK Application](./app-anatomy.md) {prereq} + +## Introduction to `Gas` and `Fees` + +In the Cosmos SDK, `gas` is a special unit that is used to track the consumption of resources during execution. `gas` is typically consumed whenever read and writes are made to the store, but it can also be consumed if expensive computation needs to be done. It serves two main purposes: + +- Make sure blocks are not consuming too many resources and will be finalized. This is implemented by default in the SDK via the [block gas meter](#block-gas-meter). +- Prevent spam and abuse from end-user. To this end, `gas` consumed during [`message`](../building-modules/messages-and-queries.md#messages) execution is typically priced, resulting in a `fee` (`fees = gas * gas-prices`). `fees` generally have to be paid by the sender of the `message`. Note that the SDK does not enforce `gas` pricing by default, as there may be other ways to prevent spam (e.g. bandwidth schemes). Still, most applications will implement `fee` mechanisms to prevent spam. This is done via the [`AnteHandler`](#antehandler). + +## Gas Meter + +In the Cosmos SDK, `gas` is a simple alias for `uint64`, and is managed by an object called a *gas meter*. Gas meters implement the `GasMeter` interface + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/store/types/gas.go#L31-L39 + +where: + +- `GasConsumed()` returns the amount of gas that was consumed by the gas meter instance. +- `GasConsumedToLimit()` returns the amount of gas that was consumed by gas meter instance, or the limit if it is reached. +- `Limit()` returns the limit of the gas meter instance. `0` if the gas meter is infinite. +- `ConsumeGas(amount Gas, descriptor string)` consumes the amount of `gas` provided. If the `gas` overflows, it panics with the `descriptor` message. If the gas meter is not infinite, it panics if `gas` consumed goes above the limit. +- `IsPastLimit()` returns `true` if the amount of gas consumed by the gas meter instance is strictly above the limit, `false` otherwise. +- `IsOutOfGas()` returns `true` if the amount of gas consumed by the gas meter instance is above or equal to the limit, `false` otherwise. + +The gas meter is generally held in [`ctx`](../core/context.md), and consuming gas is done with the following pattern: + +```go +ctx.GasMeter().ConsumeGas(amount, "description") +``` + +By default, the Cosmos SDK makes use of two different gas meters, the [main gas meter](#main-gas-metter[) and the [block gas meter](#block-gas-meter). + +### Main Gas Meter + +`ctx.GasMeter()` is the main gas meter of the application. The main gas meter is initialized in `BeginBlock` via `setDeliverState`, and then tracks gas consumption during execution sequences that lead to state-transitions, i.e. those originally triggered by [`BeginBlock`](../core/baseapp.md#beginblock), [`DeliverTx`](../core/baseapp.md#delivertx) and [`EndBlock`](../core/baseapp.md#endblock). At the beginning of each `DeliverTx`, the main gas meter **must be set to 0** in the [`AnteHandler`](#antehandler), so that it can track gas comsumption per-transaction. + +Gas comsumption can be done manually, generally by the module developer in the [`BeginBlocker`, `EndBlocker`](../building-modules/beginblock-endblock.md) or [`handler`](../building-modules/handler.md), but most of the time it is done automatically whenever there is a read or write to the store. This automatic gas consumption logic is implemented in a special store called [`GasKv`](../core/store.md#gaskv-store). + +### Block Gas Meter + +`ctx.BlockGasMeter()` is the gas meter used to track gas consumption per block and make sure it does not go above a certain limit. A new instance of the `BlockGasMeter` is created each time [`BeginBlock`](../core/baseapp.md#beginblock) is called. The `BlockGasMeter` is finite, and the limit of gas per block is defined in the application's consensus parameters. By default Cosmos SDK applications use the default consensus parameters provided by Tendermint: + ++++ https://github.com/tendermint/tendermint/blob/f323c80cb3b78e123ea6238c8e136a30ff749ccc/types/params.go#L65-L72 + +When a new [transaction](../core/transactions.md) is being processed via `DeliverTx`, the current value of `BlockGasMeter` is checked to see if it is above the limit. If it is, `DeliverTx` returns immediately. This can happen even with the first transaction in a block, as `BeginBlock` itself can consume gas. If not, the transaction is processed normally. At the end of `DeliverTx`, the gas tracked by `ctx.BlockGasMeter()` is increased by the amount consumed to process the transaction: + +```go +ctx.BlockGasMeter().ConsumeGas( + ctx.GasMeter().GasConsumedToLimit(), + "block gas meter", +) +``` + +## AnteHandler + +The `AnteHandler` is a special `handler` that is run for every transaction during `CheckTx` and `DeliverTx`, before the `handler` of each `message` in the transaction. `AnteHandler`s have a different signature than `handler`s: + +```go +// AnteHandler authenticates transactions, before their internal messages are handled. +// If newCtx.IsZero(), ctx is used instead. +type AnteHandler func(ctx Context, tx Tx, simulate bool) (newCtx Context, result Result, abort bool) +``` + +The `anteHandler` is not implemented in the core SDK but in a module. This gives the possibility to developers to choose which version of `AnteHandler` fits their application's needs. That said, most applications today use the default implementation defined in the [`auth` module](https://github.com/cosmos/cosmos-sdk/tree/master/x/auth). Here is what the `anteHandler` is intended to do in a normal Cosmos SDK application: + +- Verify that the transaction are of the correct type. Transaction types are defined in the module that implements the `anteHandler`, and they follow the transaction interface: + +++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/tx_msg.go#L33-L41 +This enables developers to play with various types for the transaction of their application. In the default `auth` module, the standard transaction type is `StdTx`: + +++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/x/auth/types/stdtx.go#L22-L29 +- Verify signatures for each [`message`](../building-modules/messages-and-queries.md#messages) contained in the transaction. Each `message` should be signed by one or multiple sender(s), and these signatures must be verified in the `anteHandler`. +- During `CheckTx`, verify that the gas prices provided with the transaction is greater than the local `min-gas-prices` (as a reminder, gas-prices can be deducted from the following equation: `fees = gas * gas-prices`). `min-gas-prices` is a parameter local to each full-node and used during `CheckTx` to discard transactions that do not provide a minimum amount of fees. This ensure that the mempool cannot be spammed with garbage transactions. +- Verify that the sender of the transaction has enough funds to cover for the `fees`. When the end-user generates a transaction, they must indicate 2 of the 3 following parameters (the third one being implicit): `fees`, `gas` and `gas-prices`. This signals how much they are willing to pay for nodes to execute their transaction. The provided `gas` value is stored in a parameter called `GasWanted` for later use. +- Set `newCtx.GasMeter` to 0, with a limit of `GasWanted`. **This step is extremely important**, as it not only makes sure the transaction cannot consume infinite gas, but also that `ctx.GasMeter` is reset in-between each `DeliverTx` (`ctx` is set to `newCtx` after `anteHandler` is run, and the `anteHandler` is run each time `DeliverTx` is called). + +As explained above, the `anteHandler` returns a maximum limit of `gas` the transaction can consume during execution called `GasWanted`. The actual amount consumed in the end is denominated `GasUsed`, and we must therefore have `GasUsed =< GasWanted`. Both `GasWanted` and `GasUsed` are relayed to the underlying consensus engine when [`DeliverTx`](../core/baseapp.md#delivertx) returns. + +## Next {hide} + +Learn about [baseapp](../core/baseapp.md) {hide} \ No newline at end of file diff --git a/docs/basics/tx-lifecycle.md b/docs/basics/tx-lifecycle.md index 01bf4848d5ff..af138706b543 100644 --- a/docs/basics/tx-lifecycle.md +++ b/docs/basics/tx-lifecycle.md @@ -1,18 +1,13 @@ -# Transaction Lifecycle - -## Prerequisite Reading +--- +order: 2 +synopsis: "This document describes the lifecycle of a transaction from creation to committed state changes. Transaction definition is described in a [different doc](../core/transactions.md). The transaction will be referred to as `Tx`." +--- -* [Anatomy of an SDK Application](./app-anatomy.md) - -## Synopsis +# Transaction Lifecycle -This document describes the lifecycle of a transaction from creation to committed state changes. Transaction definition is described in a [different doc](../core/tx-msgs.md#transactions). The transaction will be referred to as `Tx`. +## Pre-requisite Readings {hide} -1. [Creation](#creation) -2. [Addition to Mempool](#addition-to-mempool) -3. [Inclusion in a Block](#inclusion-in-a-block) -4. [State Changes](#state-changes) -5. [Consensus and Commit](#consensus-and-commit) +- [Anatomy of an SDK Application](./app-anatomy.md) {prereq} ## Creation @@ -26,13 +21,13 @@ One of the main application interfaces is the command-line interface. The transa This command will automatically **create** the transaction, **sign** it using the account's private key, and **broadcast** it to the specified peer node. -There are several required and optional flags for transaction creation. The `--from` flag specifies which [account](./accounts-fees-gas.md#accounts) the transaction is originating from. For example, if the transaction is sending coins, the funds will be drawn from the specified `from` address. +There are several required and optional flags for transaction creation. The `--from` flag specifies which [account](./accounts.md) the transaction is originating from. For example, if the transaction is sending coins, the funds will be drawn from the specified `from` address. #### Gas and Fees -Additionally, there are several [flags](../interfaces/cli.md) users can use to indicate how much they are willing to pay in [fees](./accounts-fees-gas.md#fees): +Additionally, there are several [flags](../interfaces/cli.md) users can use to indicate how much they are willing to pay in [fees](./gas-fees.md): -* `--gas` refers to how much [gas](./accounts-fees-gas.md#gas), which represents computational resources, `Tx` consumes. Gas is dependent on the transaction and is not precisely calculated until execution, but can be estimated by providing `auto` as the value for `--gas`. +* `--gas` refers to how much [gas](./gas-fees.md), which represents computational resources, `Tx` consumes. Gas is dependent on the transaction and is not precisely calculated until execution, but can be estimated by providing `auto` as the value for `--gas`. * `--gas-adjustment` (optional) can be used to scale `gas` up in order to avoid underestimating. For example, users can specify their gas adjustment as 1.5 to use 1.5 times the estimated gas. * `--gas-prices` specifies how much the user is willing pay per unit of gas, which can be one or multiple denominations of tokens. For example, `--gas-prices=0.025uatom, 0.025upho` means the user is willing to pay 0.025uatom AND 0.025upho per unit of gas. * `--fees` specifies how much in fees the user is willing to pay in total. @@ -56,12 +51,8 @@ The command-line is an easy way to interact with an application, but `Tx` can al ## Addition to Mempool Each full-node (running Tendermint) that receives a `Tx` sends an [ABCI message](https://tendermint.com/docs/spec/abci/abci.html#messages), -`CheckTx`, to the application layer to check for validity, and receives an -`abci.ResponseCheckTx`. If the `Tx` passes the checks, it is held in the nodes' -[**Mempool**](https://tendermint.com/docs/tendermint-core/mempool.html#mempool) -(an in-memory pool of transactions unique to each node) pending inclusion in a -block - honest nodes will discard `Tx` if it is found to be invalid. Prior to -consensus, nodes continuously check incoming transactions and gossip them to their peers. +`CheckTx`, to the application layer to check for validity, and receives an `abci.ResponseCheckTx`. If the `Tx` passes the checks, it is held in the nodes' +[**Mempool**](https://tendermint.com/docs/tendermint-core/mempool.html#mempool), an in-memory pool of transactions unique to each node) pending inclusion in a block - honest nodes will discard `Tx` if it is found to be invalid. Prior to consensus, nodes continuously check incoming transactions and gossip them to their peers. ### Types of Checks @@ -86,21 +77,21 @@ through several steps, beginning with decoding `Tx`. ### Decoding -When `Tx` is received by the application from the underlying consensus engine (e.g. Tendermint), it is still in its encoded (i.e. using [Amino](https://tendermint.com/docs/spec/blockchain/encoding.html#amino)) `[]byte` form and needs to be unmarshaled in order to be processed. Then, the [`runTx`](../core/baseapp.md#runtx-and-runmsgs) function is called to run in `runTxModeCheck` mode, meaning the function will run all checks but exit before executing messages and writing state changes. +When `Tx` is received by the application from the underlying consensus engine (e.g. Tendermint), it is still in its [encoded](../core/encoding.md) `[]byte` form and needs to be unmarshaled in order to be processed. Then, the [`runTx`](../core/baseapp.md#runtx-and-runmsgs) function is called to run in `runTxModeCheck` mode, meaning the function will run all checks but exit before executing messages and writing state changes. ### ValidateBasic -[Messages](../core/tx-msgs.md#messages) are extracted from `Tx` and `ValidateBasic`, a function defined by the module developer for every message, is run for each one. It should include basic stateless sanity checks. For example, if the message is to send coins from one address to another, `ValidateBasic` likely checks for nonempty addresses and a nonnegative coin amount, but does not require knowledge of state such as account balance of an address. +[`Message`s](../core/transactions.md#messages) are extracted from `Tx` and `ValidateBasic`, a method of the `Msg` interface implemented by the module developer, is run for each one. It should include basic **stateless** sanity checks. For example, if the message is to send coins from one address to another, `ValidateBasic` likely checks for nonempty addresses and a nonnegative coin amount, but does not require knowledge of state such as account balance of an address. ### AnteHandler -The [`AnteHandler`](../core/baseapp.md#antehandler), which is technically optional but should be defined for each application, is run. A deep copy of the internal state, `checkState`, is made and the defined `AnteHandler` performs limited checks specified for the transaction type. Using a copy allows the handler to do stateful checks for `Tx` without modifying the last committed state, and revert back to the original if the execution fails. +The [`AnteHandler`](../basics/gas-fees.md#antehandler), which is technically optional but should be defined for each application, is run. A deep copy of the internal state, `checkState`, is made and the defined `AnteHandler` performs limited checks specified for the transaction type. Using a copy allows the handler to do stateful checks for `Tx` without modifying the last committed state, and revert back to the original if the execution fails. -For example, the [`auth`](https://github.com/cosmos/cosmos-sdk/tree/master/docs/spec/auth) module `AnteHandler` checks and increments sequence numbers, checks signatures and account numbers, and deducts fees from the first signer of the transaction - all state changes are made using the `checkState`. +For example, the [`auth`](https://github.com/cosmos/cosmos-sdk/tree/master/x/auth/spec) module `AnteHandler` checks and increments sequence numbers, checks signatures and account numbers, and deducts fees from the first signer of the transaction - all state changes are made using the `checkState`. ### Gas -The [`Context`](../core/context.md) used to keep track of important data while `AnteHandler` is executing `Tx` keeps a `GasMeter` which tracks how much gas has been used. The user-provided amount for gas is known as the value `GasWanted`. If `GasConsumed`, the amount of gas consumed so far, ever exceeds `GasWanted`, execution stops. Otherwise, `CheckTx` sets `GasUsed` equal to `GasConsumed` and returns it in the result. After calculating the gas and fee values, validator-nodes check that the user-specified `gas-prices` is less than their locally defined `min-gas-prices`. +The [`Context`](../core/context.md), which keeps a `GasMeter` that will track how much gas has been used during the execution of `Tx`, is initialized. The user-provided amount of gas for `Tx` is known as `GasWanted`. If `GasConsumed`, the amount of gas consumed so during execution, ever exceeds `GasWanted`, the execution will stop and the changes made to the cacehd copy of the state won't be committed. Otherwise, `CheckTx` sets `GasUsed` equal to `GasConsumed` and returns it in the result. After calculating the gas and fee values, validator-nodes check that the user-specified `gas-prices` is less than their locally defined `min-gas-prices`. ### Discard or Addition to Mempool @@ -109,8 +100,7 @@ there. Otherwise, if it passes `CheckTx` successfully, the default protocol is t nodes and add it to the Mempool so that the `Tx` becomes a candidate to be included in the next block. The **mempool** serves the purpose of keeping track of transactions seen by all full-nodes. -Full-nodes that are not validators (and thus do not participate in creating blocks) keep a -**mempool cache** of the last `mempool.cache_size` transactions they have seen, as a first line of +Full-nodes keep a **mempool cache** of the last `mempool.cache_size` transactions they have seen, as a first line of defense to prevent replay attacks. Ideally, `mempool.cache_size` is large enough to encompass all of the transactions in the full mempool. If the the mempool cache is too small to keep track of all the transactions, `CheckTx` is responsible for identifying and rejecting replayed transactions. @@ -142,11 +132,11 @@ must be in this proposer's mempool. ## State Changes The next step of consensus is to execute the transactions to fully validate them. All full-nodes -that receive a block proposal execute the transactions by calling the ABCI functions +that receive a block proposal from the correct proposer execute the transactions by calling the ABCI functions [`BeginBlock`](./app-anatomy.md#beginblocker-and-endblocker), `DeliverTx` for each transaction, -and [`EndBlock`](./app-anatomy.md#beginblocker-and-endblocker). While full-nodes each run everything -individually, since the messages' state transitions are deterministic and transactions are -explicitly ordered in the block proposal, this process yields a single, unambiguous result. +and [`EndBlock`](./app-anatomy.md#beginblocker-and-endblocker). While each full-node runs everything +locally, this process yields a single, unambiguous result, since the messages' state transitions are deterministic and transactions are +explicitly ordered in the block proposal. ``` ----------------------- @@ -190,7 +180,7 @@ explicitly ordered in the block proposal, this process yields a single, unambigu The `DeliverTx` ABCI function defined in [`baseapp`](../core/baseapp.md) does the bulk of the state transitions: it is run for each transaction in the block in sequential order as committed to during consensus. Under the hood, `DeliverTx` is almost identical to `CheckTx` but calls the -[`runTx`](../core/baseapp.md#runtx-and-runmsgs) function in deliver mode instead of check mode. +[`runTx`](../core/baseapp.md#runtx) function in deliver mode instead of check mode. Instead of using their `checkState`, full-nodes use `deliverState`: * **Decoding:** Since `DeliverTx` is an ABCI call, `Tx` is received in the encoded `[]byte` form. @@ -206,16 +196,16 @@ to each node - differing values across nodes would yield nondeterministic result * **Route and Handler:** While `CheckTx` would have exited, `DeliverTx` continues to run [`runMsgs`](../core/baseapp.md#runtx-and-runmsgs) to fully execute each `Msg` within the transaction. Since the transaction may have messages from different modules, `baseapp` needs to know which module -to find the appropriate Handler. Thus, the [`Route`](../core/tx-msgs.md#route) function is called to -retrieve the route name and find the `Handler` within the module. +to find the appropriate Handler. Thus, the `route` function is called via the [module manager](../building-modules/module-manager.md) to +retrieve the route name and find the [`Handler`](../building-modules/handler.md) within the module. -* **Handler:** The `Handler`, a step up from `AnteHandler`, is responsible for executing each +* **Handler:** The `handler`, a step up from `AnteHandler`, is responsible for executing each message in the `Tx` and causes state transitions to persist in `deliverTxState`. It is defined within a `Msg`'s module and writes to the appropriate stores within the module. -* **Gas:** While a `Tx` is being delivered, a block `GasMeter` is used to keep track of how much -gas is left for each transaction; if execution completes, `GasUsed` is set and returned in the -`abci.ResponseDeliverTx`. If execution halts because `GasMeter` has run out or something else goes +* **Gas:** While a `Tx` is being delivered, a `GasMeter` is used to keep track of how much +gas is being used; if execution completes, `GasUsed` is set and returned in the +`abci.ResponseDeliverTx`. If execution halts because `BlockGasMeter` or `GasMeter` has run out or something else goes wrong, a deferred function at the end appropriately errors or panics. If there are any failed state changes resulting from a `Tx` being invalid or `GasMeter` running out, @@ -224,25 +214,15 @@ block proposal cause validator nodes to reject the block and vote for a `nil` bl `Tx` is delivered successfully, any leftover gas is returned to the user and the transaction is validated. -### Consensus and Commit +### Commit -The final step is for validator nodes to commit the block and state changes. Validator nodes +The final step is for nodes to commit the block and state changes. Validator nodes perform the previous step of executing state transitions in order to validate the transactions, -then sign the block to confirm and vote for them. Full nodes that are not validators do not +then sign the block to confirm it. Full nodes that are not validators do not participate in consensus - i.e. they cannot vote - but listen for votes to understand whether or -not they should commit the state changes. - -#### Consensus - -The consensus layer may technically run any consensus algorithm to come to agreement on which block -to accept. In [Tendermint BFT](https://tendermint.com/docs/spec/consensus/consensus.html), validator -nodes go through a Prevote stage and a Precommit stage, and the block requires +2/3 Precommits from -the validator-nodes to move into the commit stage. Note that this phase is purely in the consensus -layer; a `Tx` is represented as a `[]byte`. - -#### Commit +not they should commit the state changes. -In the **Commit** stage, full nodes commit to a new block to be added to the blockchain and +When they receive enough validator votes (2/3+ *precommits* weighted by voting power), full nodes commit to a new block to be added to the blockchain and finalize the state transitions in the application layer. A new state root is generated to serve as a merkle proof for the state transitions. Applications use the [`Commit`](../core/baseapp.md#commit) ABCI method inherited from [Baseapp](../core/baseapp.md); it syncs all the state transitions by @@ -260,6 +240,6 @@ At this point, the transaction lifecycle of a `Tx` is over: nodes have verified delivered it by executing its state changes, and committed those changes. The `Tx` itself, in `[]byte` form, is stored in a block and appended to the blockchain. -## Next +## Next {hide} -Learn about [Baseapp](../core/baseapp.md). +Learn about [accounts](./accounts.md) {hide} diff --git a/docs/building-modules/README.md b/docs/building-modules/README.md index 145e6e501dfa..732485c74477 100644 --- a/docs/building-modules/README.md +++ b/docs/building-modules/README.md @@ -1,75 +1,22 @@ -# Modules +--- +order: false +parent: + order: 4 +--- + +# Building Modules + +This repository contains documentation on concepts developers need to know in order to build modules for Cosmos SDK applications. + +1. [Introduction to Cosmos SDK Modules](./intro.md) +2. [`AppModule` Interface and Module Manager](./module-manager.md) +3. [Messages and Queries](./messages-and-queries.md) +4. [`Handler`s - Processing Messages](./handler.md) +5. [`Querier`s - Processing Queries](./querier.md) +6. [BeginBlocker and EndBlocker](./beginblock-endblock.md) +7. [`Keeper`s](./keeper.md) +8. [Invariants](./invariants.md) +9. [Genesis](./genesis.md) +10. [Module Interfaces](./module-interfaces.md) +11. [Standard Module Structure](./structure.md) -## Auth - -The `x/auth` modules is used for accounts - -- [API docs](https://godoc.org/github.com/cosmos/cosmos-sdk/x/auth) -- [Specification](https://github.com/cosmos/cosmos-sdk/tree/master/docs/spec/auth) - -## Bank - -The `x/bank` module is for transferring coins between accounts. - -- [API docs](https://godoc.org/github.com/cosmos/cosmos-sdk/x/bank) -- [Specification](https://github.com/cosmos/cosmos-sdk/tree/master/docs/spec/bank) - -## Staking - -The `x/staking` module is for Cosmos Delegated-Proof-of-Stake. - -- [API docs](https://godoc.org/github.com/cosmos/cosmos-sdk/x/staking) -- [Specification](https://github.com/cosmos/cosmos-sdk/tree/master/docs/spec/staking) - -## Slashing - -The `x/slashing` module is for Cosmos Delegated-Proof-of-Stake. - -- [API docs](https://godoc.org/github.com/cosmos/cosmos-sdk/x/slashing) -- [Specification](https://github.com/cosmos/cosmos-sdk/tree/master/docs/spec/slashing) - -## Distribution - -The `x/distribution` module is for distributing fees and inflation across bonded -stakeholders. - -- [API docs](https://godoc.org/github.com/cosmos/cosmos-sdk/x/distribution) -- [Specification](https://github.com/cosmos/cosmos-sdk/tree/master/docs/spec/distribution) - -## Governance - -The `x/gov` module is for bonded stakeholders to make proposals and vote on them. - -- [API docs](https://godoc.org/github.com/cosmos/cosmos-sdk/x/gov) -- [Specification](https://github.com/cosmos/cosmos-sdk/tree/master/docs/spec/governance) - -To keep up with the current status of IBC, follow and contribute to [ICS](https://github.com/cosmos/ics) - -## Crisis - -The `x/crisis` module is for halting the blockchain under certain circumstances. - -- [API Docs](https://godoc.org/github.com/cosmos/cosmos-sdk/x/crisis) -- [Specification](https://github.com/cosmos/cosmos-sdk/blob/master/docs/spec/crisis) - -## Mint - -The `x/mint` module is for flexible inflation rates and effect a balance between market liquidity and staked supply. - -- [API Docs](https://godoc.org/github.com/cosmos/cosmos-sdk/x/mint) -- [Specification](https://github.com/cosmos/cosmos-sdk/blob/master/docs/spec/mint) - -## Params - -The `x/params` module provides a globally available parameter store. - -- [API Docs](https://godoc.org/github.com/cosmos/cosmos-sdk/x/params) -- [Specification](https://github.com/cosmos/cosmos-sdk/blob/master/docs/spec/params) - -## Evidence - -The `x/evidence` modules provides a mechanism for defining and submitting arbitrary -events of misbehavior and a means to execute custom business logic for such misbehavior. - -- [API Docs](https://godoc.org/github.com/cosmos/cosmos-sdk/x/evidence) -- [Specification](https://github.com/cosmos/cosmos-sdk/blob/master/docs/spec/evidence) diff --git a/docs/building-modules/beginblock-endblock.md b/docs/building-modules/beginblock-endblock.md new file mode 100644 index 000000000000..fe3aeedceb92 --- /dev/null +++ b/docs/building-modules/beginblock-endblock.md @@ -0,0 +1,38 @@ +--- +order: 6 +synopsis: "`BeginBlocker` and `EndBlocker` are optional methods module developers can implement in their module. They will be triggered at the beginning and at the end of each block respectively, when the [`BeginBlock`](../core/baseapp.md#beginblock) and [`EndBlock`](../core/baseapp.md#endblock) ABCI messages are received from the underlying consensus engine." +--- + +# BeginBlocker and EndBlocker + +## Pre-requisite Readings {hide} + +- [Module Manager](./module-manager.md) {prereq} + +## BeginBlocker and EndBlocker + +`BeginBlocker` and `EndBlocker` are a way for module developers to add automatic execution of logic to their module. This is a powerful tool that should be used carefully, as complex automatic functions can slow down or even halt the chain. + +When needed, `BeginBlocker` and `EndBlocker` are implemented as part of the [`AppModule` interface](./module-manager.md#appmodule). The `BeginBlock` and `EndBlock` methods of the interface implemented in `module.go` generally defer to `BeginBlocker` and `EndBlocker` methods respectively, which are usually implemented in a **`abci.go`** file. + +The actual implementation of `BeginBlocker` and `EndBlocker` in `./abci.go` are very similar to that of a [`handler`](./handler.md): + +- They generally use the [`keeper`](./keeper.md) and [`ctx`](../core/context.md) to retrieve information about the latest state. +- If needed, they use the `keeper` and `ctx` to trigger state-transitions. +- If needed, they can emit [`events`](../core/events.md) via the `ctx`'s `EventManager`. + +A specificity of the `EndBlocker` is that it can return validator updates to the underlying consensus engine in the form of an [`[]abci.ValidatorUpdates`](https://tendermint.com/docs/app-dev/abci-spec.html#validatorupdate). This is the preferred way to implement custom validator changes. + +It is possible for developers to defined the order of execution between the `BeginBlocker`/`EndBlocker` functions of each of their application's modules via the module's manager `SetOrderBeginBlocker`/`SetOrderEndBlocker` methods. For more on the module manager, click [here](./module-manager.md#manager). + +See an example implementation of `BeginBlocker` from the `distr` module: + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/x/distribution/abci.go#L10-L32 + +and an example implementation of `EndBlocker` from the `staking` module: + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/x/staking/handler.go#L44-L96 + +## Next {hide} + +Learn about [`keeper`s](./keeper.md) {hide} diff --git a/docs/building-modules/genesis.md b/docs/building-modules/genesis.md new file mode 100644 index 000000000000..0d4ddec93e77 --- /dev/null +++ b/docs/building-modules/genesis.md @@ -0,0 +1,59 @@ +--- +order: 9 +synopsis: Modules generally handle a subset of the state and, as such, they need to define the related subset of the genesis file as well as methods to initialize, verify and export it. +--- + +# Module Genesis + +## Pre-requisite Readings {hide} + +- [Module Manager](./module-manager.md) {prereq} +- [Keepers](./keeper.md) {prereq} + +## Type Definition + +The subset of the genesis state defined from a given module is generally defined in a `./internal/types/genesis.go` file, along with the `DefaultGenesis` and `ValidateGenesis` methods. The struct defining the module's subset of the genesis state is usually called `GenesisState` and contains all the module-related values that need to be initialized during the genesis process. + +See an example of `GenesisState` type definition from the nameservice tutorial + ++++ https://github.com/cosmos/sdk-tutorials/blob/86a27321cf89cc637581762e953d0c07f8c78ece/nameservice/x/nameservice/genesis.go#L10-L12 + +Next we present the main genesis-related methods that need to be implemented by module developers in order for their module to be used in Cosmos SDK applications. + +### `DefaultGenesis` + +The `DefaultGenesis()` method is a simple method that calls the constructor function for `GenesisState` with the default value for each parameter. See an example from the `nameservice` module: + ++++ https://github.com/cosmos/sdk-tutorials/blob/86a27321cf89cc637581762e953d0c07f8c78ece/nameservice/x/nameservice/genesis.go#L33-L37 + +### `ValidateGenesis` + +The `ValidateGenesis(genesisState GenesisState)` method is called to verify that the provided `genesisState` is correct. It should perform validity checks on each of the parameter listed in `GenesisState`. See an example from the `nameservice` module: + ++++ https://github.com/cosmos/sdk-tutorials/blob/86a27321cf89cc637581762e953d0c07f8c78ece/nameservice/x/nameservice/genesis.go#L18-L31 + +## Other Genesis Methods + +Other than the methods related directly to `GenesisState`, module developers are expected to implement two other methods as part of the [`AppModuleGenesis` interface](./module-manager.md#appmodulegenesis) (only if the module needs to initialize a subset of state in genesis). These methods are [`InitGenesis`](#initgenesis) and [`ExportGenesis`](#exportgenesis). + +### `InitGenesis` + +The `InitGenesis` method is executed during [`InitChain`](../core/baseapp.md#initchain) when the application is first started. Given a `GenesisState`, it initializes the subset of the state managed by the module by using the module's [`keeper`](./keeper.md) setter function on each parameter within the `GenesisState`. + +The [module manager](./module-manager.md#manager) of the application is responsible for calling the `InitGenesis` method of each of the application's modules, in order. This order is set by the application developer via the manager's `SetOrderGenesisMethod`, which is called in the [application's constructor function](../basics/app-anatomy.md#constructor-function) + +See an example of `InitGenesis` from the nameservice tutorial + ++++ https://github.com/cosmos/sdk-tutorials/blob/86a27321cf89cc637581762e953d0c07f8c78ece/nameservice/x/nameservice/genesis.go#L39-L44 + +### `ExportGenesis` + +The `ExportGenesis` method is executed whenever an export of the state is made. It takes the latest known version of the subset of the state managed by the module and creates a new `GenesisState` out of it. This is mainly used when the chain needs to be upgraded via a hard fork. + +See an example of `ExportGenesis` from the nameservice tutorial. + ++++ https://github.com/cosmos/sdk-tutorials/blob/86a27321cf89cc637581762e953d0c07f8c78ece/nameservice/x/nameservice/genesis.go#L46-L57 + +## Next {hide} + +Learn about [modules interfaces](#module-interfaces.md) {hide} \ No newline at end of file diff --git a/docs/building-modules/handler.md b/docs/building-modules/handler.md new file mode 100644 index 000000000000..b42d591c0867 --- /dev/null +++ b/docs/building-modules/handler.md @@ -0,0 +1,76 @@ +--- +order: 4 +synopsis: "A `Handler` designates a function that processes [`message`s](./messages-and-queries.md#messages). `Handler`s are specific to the module in which they are defined, and only process `message`s defined within the said module. They are called from `baseapp` during [`DeliverTx`](../core/baseapp.md#delivertx)." +--- + +# Handlers + +## Pre-requisite Readings {hide} + +- [Module Manager](./module-manager.md) {prereq} +- [Messages and Queries](./messages-and-queries.md) {prereq} + +## `handler` type + +The `handler` type defined in the Cosmos SDK specifies the typical structure of a `handler` function. + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/handler.go#L4 + +Let us break it down: + +- The [`Msg`](./messages-and-queries.md#messages) is the actual object being processed. +- The [`Context`](../core/context.md) contains all the necessary information needed to process the `msg`, as well as a cache-wrapped copy of the latest state. If the `msg` is succesfully processed, the modified version of the temporary state contained in the `ctx` will be written to the main state. +- The [`Result`] returned to `baseapp`, which contains (among other things) information on the execution of the `handler`, [`gas`](../basics/gas-fees.md) consumption and [`events`](../core/events.md). + +++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/result.go#L15-L40 + +## Implementation of a module `handler`s + +Module `handler`s are typically implemented in a `./handler.go` file inside the module's folder. The [module manager](./module-manager.md) is used to add the module's `handler`s to the [application's `router`](../core/baseapp.md#message-routing) via the `NewHandler()` method. Typically, the manager's `NewHandler()` method simply calls a `NewHandler()` method defined in `handler.go`, which looks like the following: + +```go +func NewHandler(keeper Keeper) sdk.Handler { + return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + switch msg := msg.(type) { + case MsgType1: + return handleMsgType1(ctx, keeper, msg) + case MsgType2: + return handleMsgType2(ctx, keeper, msg) + default: + errMsg := fmt.Sprintf("Unrecognized nameservice Msg type: %v", msg.Type()) + return sdk.ErrUnknownRequest(errMsg).Result() + } + } +} +``` + +This simple switch returns a `handler` function specific to the type of the received `message`. These `handler` functions are the ones that actually process `message`s, and usually follow the following 2 steps: + +- First, they perform *stateful* checks to make sure the `message` is valid. At this stage, the `message`'s `ValidateBasic()` method has already been called, meaning *stateless* checks on the message (like making sure parameters are correctly formatted) have already been performed. Checks performed in the `handler` can be more expensive and require access to the state. For example, a `handler` for a `transfer` message might check that the sending account has enough funds to actually perform the transfer. To access the state, the `handler` needs to call the [`keeper`'s](./keeper.md) getter functions. +- Then, if the checks are successfull, the `handler` calls the [`keeper`'s](./keeper.md) setter functions to actually perform the state transition. + +Before returning, `handler` functions generally emit one or multiple [`events`](../core/events.md) via the `EventManager` held in the `ctx`: + +```go +ctx.EventManager().EmitEvent( + sdk.NewEvent( + eventType, // e.g. sdk.EventTypeMessage for a message, types.CustomEventType for a custom event defined in the module + sdk.NewAttribute(attributeKey, attributeValue), + ), + ) +``` + +These `events` are relayed back to the underlying consensus engine and can be used by service providers to implement services around the application. Click [here](../core/events.md) to learn more about `events`. + +Finally, the `handler` function returns a `sdk.Result` which contains the aforementioned `events` and an optional `Data` field. + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/result.go#L15-L40 + +Next is an example of how to return a `Result` from the `gov` module: + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/x/gov/handler.go#L59-L62 + +For a deeper look at `handler`s, see this [example implementation of a `handler` function](https://github.com/cosmos/sdk-application-tutorial/blob/c6754a1e313eb1ed973c5c91dcc606f2fd288811/x/nameservice/handler.go) from the nameservice tutorial. + +## Next {hide} + +Learn about [queriers](./querier.md) {hide} diff --git a/docs/building-modules/intro.md b/docs/building-modules/intro.md new file mode 100644 index 000000000000..8ad43da48ece --- /dev/null +++ b/docs/building-modules/intro.md @@ -0,0 +1,93 @@ +--- +order: 1 +synopsis: Modules define most of the logic of SDK applications. Developers compose module together using the Cosmos SDK to build their custom application-specific blockchains. This document outlines the basic concepts behind SDK modules and how to approach module management. +--- + +# Introduction to SDK Modules + +## Pre-requisite Readings {hide} + +- [Anatomy of an SDK application](../basics/app-anatomy.md) {prereq} +- [Lifecycle of an SDK transaction](../basics/tx-lifecycle.md) {prereq} + +## Role of Modules in an SDK Application + +The Cosmos SDK can be thought as the Ruby-on-Rails of blockchain development. It comes with a core that provides the basic functionalities every blockchain application needs, like a [boilerplate implementation of the ABCI](../core/baseapp.md) to communicate with the underlying consensus engine, a [`multistore`](../core/store.md#multistore) to persist state, a [server](../core/node.md) to form a full-node and [interfaces](../interfaces/interfaces-intro.md) to handle queries. + +On top of this core, the Cosmos SDK enables developers to build modules that implement the business logic of their application. In other words, SDK modules implement the bulk of the logic of applications, while the core does the wiring and enables modules to be composed together. The end goal is to build a robust ecosystem of open-source SDK modules, making it increasingly easier to build complex blockchain applications. + +SDK Modules can be seen as little state-machines within the state-machine. They generally define a subset of the state using one ore multiple `KVStore` in the [main multistore](../core/store.md), as well as a subset of [`message` types](./messages-and-queries.md#messages). These `message`s are routed by one of the main component of SDK core, [`baseapp`](../core/baseapp.md), to the [`handler`](./handler.md) of the module that define them. + +``` + + + | + | Transaction relayed from the full-node's consensus engine + | to the node's application via DeliverTx + | + | + | + +---------------------v--------------------------+ + | APPLICATION | + | | + | Using baseapp's methods: Decode the Tx, | + | extract and route the message(s) | + | | + +---------------------+--------------------------+ + | + | + | + +---------------------------+ + | + | + | + | Message routed to the correct + | module to be processed + | + | ++----------------+ +---------------+ +----------------+ +------v----------+ +| | | | | | | | +| AUTH MODULE | | BANK MODULE | | STAKING MODULE | | GOV MODULE | +| | | | | | | | +| | | | | | | Handles message,| +| | | | | | | Updates state | +| | | | | | | | ++----------------+ +---------------+ +----------------+ +------+----------+ + | + | + | + | + +--------------------------+ + | + | Return result to the underlying consensus engine (e.g. Tendermint) + | (0=Ok, 1=Err) + v +``` + +As a result of this architecture, building an SDK application usually revolves around writing modules to implement the specialized logic of the application, and composing them with existing modules to complete the application. Developers will generally work on modules that implement logic needed for their specific use case that do not exist yet, and will use existing modules for more generic functionalities like staking, accounts or token management. + +## How to Approach Building Modules as a Developer + +While there is no definitive guidelines for writing modules, here are some important design principles developers should keep in mind when building them: + +- **Composability**: SDK applications are almost always composed of multiple modules. This means developers need to carefully consider the integration of their module not only with the core of the Cosmos SDK, but also with other modules. The former is achieved by following standard design patterns outlined [here](#main-components-of-sdk-modules), while the latter is achieved by properly exposing the store(s) of the module via the [`keeper`](./keeper.md). +- **Specialization**: A direct consequence of the **composability** feature is that modules should be **specialized**. Developers should carefully establish the scope of their module and not batch multiple functionalities into the same module. This separation of concern enables modules to be re-used in other projects and improves the upgradability of the application. **Specialization** also plays an important role in the [object-capabilities model](../core/ocap.md) of the Cosmos SDK. +- **Capabilities**: Most modules need to read and/or write to the store(s) of other modules. However, in an open-source environment, it is possible for some module to be malicious. That is why module developers need to carefully think not only about how their module interracts with other modules, but also about how to give access to the module's store(s). The Cosmos SDK takes a capabilities-oriented approach to inter-module security. This means that each store defined by a module is accessed by a `key`, which is held by the module's [`keeper`](./keeper.md). This `keeper` defines how to access the store(s) and under what conditions. Access to the module's store(s) is done by passing a reference to the module's `keeper`. + +## Main Components of SDK Modules + +Modules are by convention defined in the `.x/` subfolder (e.g. the `bank` module will be defined in the `./x/bank` folder). They generally share the same core components: + +- Custom [`message` types](./messages-and-queries.md#messages) to trigger state-transitions. +- A [`handler`](./handler.md) used to process messages when they are routed to the module by [`baseapp`](../core/baseapp.md#message-routing). +- A [`keeper`](./keeper.md), used to access the module's store(s) and update the state. +- A [`querier`](./querier.md), used to process user queries when they are routed to the module by [`baseapp`](../core/baseapp.md#query-routing). +- Interfaces, for end users to query the subset of the state defined by the module and create `message`s of the custom types defined in the module. + +In addition to these components, modules implement the `AppModule` interface in order to be managed by the [`module manager`](./module-manager.md). + +Please refer to the [structure document](./structure.md) to learn about the recommended structure of a module's directory. + +## Next {hide} + +Read more on the [`AppModule` interface and the `module manager`](./module-manager.md) {hide} + diff --git a/docs/building-modules/invariants.md b/docs/building-modules/invariants.md new file mode 100644 index 000000000000..2e18551914d4 --- /dev/null +++ b/docs/building-modules/invariants.md @@ -0,0 +1,88 @@ +--- +order: 8 +synopsis: "An invariant is a property of the application that should always be true. In the context of the Cosmos SDK, an `Invariant` is a function that checks for a particular invariant. These functions are useful to detect bugs early on and act upon them to limit their potential consequences (e.g. by halting the chain). They are also useful in the development process of the application to detect bugs via simulations." +--- + +# Invariants + +## Pre-requisite Readings {hide} + +- [Keepers](./keeper.md) {prereq} + +## Implementing `Invariant`s + +An `Invariant` is a function that checks for a particular invariant within a module. Module `Invariant`s must follow the `Invariant`s type: + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/invariant.go#L9 + +where the `string` return value is the invariant message, which can be used when printing logs, and the `bool` return value is the actual result of the invariant check. + +In practice, each module implements `Invariant`s in a `./internal/keeper/invariants.go` file within the module's folder. The standard is to implement one `Invariant` function per logical grouping of invariants with the following model: + +```go +// Example for an Invariant that checks balance-related invariants + +func BalanceInvariants(k Keeper) sdk.Invariant { + return func(ctx sdk.Context) (string, bool) { + // Implement checks for balance-related invariants + } +} +``` + +Additionally, module developers should generally implement an `AllInvariants` function that runs all the `Invariant`s functions of the module: + +```go +// AllInvariants runs all invariants of the module. +// In this example, the module implements two Invariants: BalanceInvariants and DepositsInvariants + +func AllInvariants(k Keeper) sdk.Invariant { + + return func(ctx sdk.Context) (string, bool) { + res, stop := BalanceInvariants(k)(ctx) + if stop { + return res, stop + } + + return DepositsInvariant(k)(ctx) + } +} +``` + +Finally, module developers need to implement the `RegisterInvariants` method as part of the [`AppModule` interface](./module-manager.md#appmodule). Indeed, the `RegisterInvariants` method of the module, implemented in the `module.go` file, typically only defers the call to a `RegisterInvariants` method implemented in `internal/keeper/invariants.go`. The `RegisterInvariants` method registers a route for each `Invariant` function in the [`InvariantRegistry`](#invariant-registry): + + +```go +// RegisterInvariants registers all staking invariants +func RegisterInvariants(ir sdk.InvariantRegistry, k Keeper) { + ir.RegisterRoute(types.ModuleName, "module-accounts", + BalanceInvariants(k)) + ir.RegisterRoute(types.ModuleName, "nonnegative-power", + DepositsInvariant(k)) +} +``` + +For more, see an example of [`Invariant`s implementation from the `staking` module](https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/x/staking/keeper/invariants.go). + +## Invariant Registry + +The `InvariantRegistry` is a registry where the `Invariant`s of all the modules of an application are registered. There is only one `InvariantRegistry` per **application**, meaning module developers need not implement their own `InvariantRegistry` when building a module. **All module developers need to do is to register their modules' invariants in the `InvariantRegistry`, as explained in the section above**. The rest of this section gives more information on the `InvariantRegistry` itself, and does not contain anything directly relevant to module developers. + +At its core, the `InvariantRegistry` is defined in the SDK as an interface: + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/invariant.go#L14-L17 + +Typically, this interface is implemented in the `keeper` of a specific module. The most used implementation of an `InvariantRegistry` can be found in the `crisis` module: + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/x/crisis/internal/keeper/keeper.go#L45-L49 + + The `InvariantRegistry` is therefore typically instantiated by instantiating the `keeper` of the `crisis` module in the [application's constructor function](../basics/app-anatomy.md#constructor-function). + +`Invariant`s can be checked manually via [`message`s](./messages-and-queries.md), but most often they are checked automatically at the end of each block. Here is an example from the `crisis` module: + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/x/crisis/abci.go#L7-L14 + +In both cases, if one of the `Invariant`s returns false, the `InvariantRegistry` can trigger special logic (e.g. have the application panic and print the `Invariant`s message in the log). + +## Next {hide} + +Learn about [genesis functionalities](./genesis.md) {hide} diff --git a/docs/building-modules/keeper.md b/docs/building-modules/keeper.md new file mode 100644 index 000000000000..e76b0bb008d0 --- /dev/null +++ b/docs/building-modules/keeper.md @@ -0,0 +1,78 @@ +--- +order: 7 +synopsis: "`Keeper`s refer to a Cosmos SDK abstraction whose role is to manage access to the subset of the state defined by various modules. `Keeper`s are module-specific, i.e. the subset of state defined by a module can only be accessed by a `keeper` defined in said module. If a module needs to access the subset of state defined by another module, a reference to the second module's internal `keeper` needs to be passed to the first one. This is done in `app.go` during the instantiation of module keepers." +--- + +# Keepers + +## Pre-requisite Readings {hide} + +- [Introduction to SDK Modules](./intro.md) {prereq} + +## Motivation + +The Cosmos SDK is a framework that makes it easy for developers to build complex decentralised applications from scratch, mainly by composing modules together. As the ecosystem of open source modules for the Cosmos SDK expands, it will become increasingly likely that some of these modules contain vulnerabilities, as a result of the negligence or malice of their developer. + +The Cosmos SDK adopts an [object-capabilities-based approach](../core/ocap.md) to help developers better protect their application from unwanted inter-module interactions, and `keeper`s are at the core of this approach. A `keeper` can be thought of quite literally as the gatekeeper of a module's store(s). Each store (typically an [`IAVL` Store](../core/store.md#iavl-store)) defined within a module comes with a `storeKey`, which grants unlimited access to it. The module's `keeper` holds this `storeKey` (which should otherwise remain unexposed), and defines [methods](#implementing-methods) for reading and writing to the store(s). + +The core idea behind the object-capabilities approach is to only reveal what is necessary to get the work done. In practice, this means that instead of handling permissions of modules through access-control lists, module `keeper`s are passed a reference to the specific instance of the other modules' `keeper`s that they need to access (this is done in the [application's constructor function](../basics/app-anatomy.md#constructor-function)). As a consequence, a module can only interact with the subset of state defined in another module via the methods exposed by the instance of the other module's `keeper`. This is a great way for developers to control the interactions that their own module can have with modules developed by external developers. + +## Type Definition + +`keeper`s are generally implemented in a `internal/keeper/keeper.go` file located in the module's folder. By convention, the type `keeper` of a module is simply named `Keeper` and usually follows the following structure: + +```go +type Keeper struct { + // External keepers, if any + + // Store key(s) + + // codec +} +``` + +For example, here is the [type definition of the `keeper` from the nameservice tutorial: + ++++ https://github.com/cosmos/sdk-tutorials/blob/86a27321cf89cc637581762e953d0c07f8c78ece/nameservice/x/nameservice/internal/keeper/keeper.go#L10-L17 + +Let us go through the different parameters: + +- An expected `keeper` is a `keeper` external to a module that is required by the internal `keeper` of said module. External `keeper`s are listed in the internal `keeper`'s type definition as interfaces. These interfaces are themselves defined in a `internal/types/expected_keepers.go` file within the module's folder. In this context, interfaces are used to reduce the number of dependencies, as well as to facilitate the maintenance of the module itself. +- `storeKey`s grant access to the store(s) of the [multistore](../core/store.md) managed by the module. They should always remain unexposed to external modules. +- A [codec `cdc`](../core/encoding.md), used to marshall and unmarshall struct to/from `[]byte`. + +Of course, it is possible to define different types of internal `keeper`s for the same module (e.g. a read-only `keeper`). Each type of `keeper` comes with its own constructor function, which is called from the [application's constructor function](../basics/app-anatomy.md). This is where `keeper`s are instantiated, and where developers make sure to pass correct instances of modules' `keeper`s to other modules that require it. + +## Implementing Methods + +`Keeper`s primarily expose getter and setter methods for the store(s) managed by their module. These methods should remain as simple as possible and strictly be limited to getting or setting the requested value, as validity checks should have already been performed via the `ValidateBasic()` method of the [`message`](./messages-and-queries.md#messages) and the [`handler`](./handler.md) when `keeper`s' methods are called. + +Typically, a *getter* method will present with the following signature + +```go +func (k Keeper) Get(ctx sdk.Context, key string) returnType +``` + +and go through the following steps: + +1. Retrieve the appropriate store from the `ctx` using the `storeKey`. This is done through the `KVStore(storeKey sdk.StoreKey` method of the `ctx`. +2. If it exists, get the `[]byte` value stored at location `[]byte(key)` using the `Get(key []byte)` method of the store. +3. Unmarshall the retrieved value from `[]byte` to `returnType` using the codec `cdc`. Return the value. + +Similarly, a *setter* method will present with the following signature + +```go +func (k Keeper) Set(ctx sdk.Context, key string, value valueType) +``` + +and go through the following steps: + +1. Retrieve the appropriate store from the `ctx` using the `storeKey`. This is done through the `KVStore(storeKey sdk.StoreKey` method of the `ctx`. +2. Marhsall `value` to `[]byte` using the codec `cdc`. +3. Set the encoded value in the store at location `key` using the `Set(key []byte, value []byte)` method of the store. + +For more, see an example of `keeper`'s [methods implementation from the nameservice tutorial](https://github.com/cosmos/sdk-application-tutorial/blob/c6754a1e313eb1ed973c5c91dcc606f2fd288811/x/nameservice/internal/keeper/keeper.go). + +## Next {hide} + +Learn about [invariants](./invariants.md) {hide} diff --git a/docs/building-modules/messages-and-queries.md b/docs/building-modules/messages-and-queries.md new file mode 100644 index 000000000000..bb0665483b36 --- /dev/null +++ b/docs/building-modules/messages-and-queries.md @@ -0,0 +1,75 @@ +--- +order: 3 +synopsis: "`Message`s and `Queries` are the two primary objects handled by modules. Most of the core components defined in a module, like `handler`s, `keeper`s and `querier`s, exist to process `message`s and `queries`." +--- + +# Messages and Queries + +## Pre-requisite Readings {hide} + +- [Introduction to SDK Modules](./intro.md) {prereq} + +## Messages + +`Message`s are objects whose end-goal is to trigger state-transitions. They are wrapped in [transactions](../core/transactions.md), which may contain one or multiple of them. + +When a transaction is relayed from the underlying consensus engine to the SDK application, it is first decoded by [`baseapp`](../core/baseapp.md). Then, each `message` contained in the transaction is extracted and routed to the appropriate module via `baseapp`'s `router` so that it can be processed by the module's [`handler`](./handler.md). For a more detailed explanation of the lifecycle of a transaction, click [here](../basics/tx-lifecycle.md). + +Defining `message`s is the responsibility of module developers. Typically, they are defined in a `./internal/types/msgs.go` file inside the module's folder. The `message`'s type definition usually includes a list of parameters needed to process the message that will be provided by end-users when they want to create a new transaction containing said `message`. + +```go +// Example of a message type definition + +type MsgSubmitProposal struct { + Content Content `json:"content" yaml:"content"` + InitialDeposit sdk.Coins `json:"initial_deposit" yaml:"initial_deposit"` + Proposer sdk.AccAddress `json:"proposer" yaml:"proposer"` +} +``` + +The `Msg` is typically accompanied by a standard constructor function, that is called from one of the [module's interface](./module-interfaces.md). `message`s also need to implement the [`Msg`] interface: + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/tx_msg.go#L7-L29 + +It contains the following methods: + +- `Route() string`: Name of the route for this message. Typically all `message`s in a module have the same route, which is most often the module's name. +- `Type() string`: Type of the message, used primarly in [events](../core/events.md). This should return a message-specific `string`, typically the denomination of the message itself. +- `ValidateBasic() Error`: This method is called by `baseapp` very early in the processing of the `message` (in both [`CheckTx`](../core/baseapp.md#checktx) and [`DeliverTx`](../core/baseapp.md#delivertx)), in order to discard obviously invalid messages. `ValidateBasic` should only include *stateless* checks, i.e. checks that do not require access to the state. This usually consists in checking that the message's parameters are correctly formatted and valid (i.e. that the `amount` is strictly positive for a transfer). +- `GetSignBytes() []byte`: Return the canonical byte representation of the message. Used to generate a signature. +- `GetSigners() []AccAddress`: Return the list of signers. The SDK will make sure that each `message` contained in a transaction is signed by all the signers listed in the list returned by this method. + +See an example implementation of a `message` from the `nameservice` module: + ++++ https://github.com/cosmos/sdk-tutorials/blob/86a27321cf89cc637581762e953d0c07f8c78ece/nameservice/x/nameservice/internal/types/msgs.go#L10-L51 + +## Queries + +A `query` is a request for information made by end-users of applications through an interface and processed by a full-node. A `query` is received by a full-node through its consensus engine and relayed to the application via the ABCI. It is then routed to the appropriate module via `baseapp`'s `queryrouter` so that it can be processed by the module's [`querier`](./querier.md). For a deeper look at the lifecycle of a `query`, click [here](../interfaces/query-lifecycle.md). + +Contrary to `message`s, there is usually no specific `query` object defined by module developers. Instead, the SDK takes the simpler approach of using a simple `path` to define each `query`. The `path` contains the `query` type and all the arguments needed in order to process it. For most module queries, the `path` should look like the following: + +``` +queryCategory/queryRoute/queryType/arg1/arg2/... +``` + +where: + +- `queryCategory` is the category of the `query`, typically `custom` for module queries. It is used to differentiate between different kinds of queries within `baseapp`'s [`Query` method](../core/baseapp.md#query). +- `queryRoute` is used by `baseapp`'s [`queryRouter`](../core/baseapp.md#query-routing) to map the `query` to its module. Usually, `queryRoute` should be the name of the module. +- `queryType` is used by the module's [`querier`](./querier.md) to map the `query` to the appropriate `querier function` within the module. +- `args` are the actual arguments needed to process the `query`. They are filled out by the end-user. Note that for bigger queries, you might prefer passing arguments in the `Data` field of the request `req` instead of the `path`. + +The `path` for each `query` must be defined by the module developer in the module's [command-line interface file](./module-interfaces.md#query-commands).Overall, there are 3 mains components module developers need to implement in order to make the subset of the state defined by their module queryable: + +- A [`querier`](./querier.md), to process the `query` once it has been [routed to the module](../core/baseapp.md#query-routing). +- [Query commands](./module-interfaces.md#query-commands) in the module's CLI file, where the `path` for each `query` is specified. +- `query` return types. Typically defined in a file `internal/types/querier.go`, they specify the result type of each of the module's `queries`. These custom types must implement the `String()` method of [`fmt.Stringer`](https://golang.org/pkg/fmt/#Stringer). + +See an example of `query` return types from the `nameservice` module: + ++++ https://github.com/cosmos/sdk-tutorials/blob/c6754a1e313eb1ed973c5c91dcc606f2fd288811/x/nameservice/internal/types/querier.go#L5-L21 + +## Next {hide} + +Learn about [`handler`s](./handler.md) {hide} \ No newline at end of file diff --git a/docs/building-modules/module-interfaces.md b/docs/building-modules/module-interfaces.md new file mode 100644 index 000000000000..5b1352621a42 --- /dev/null +++ b/docs/building-modules/module-interfaces.md @@ -0,0 +1,167 @@ +--- +order: 11 +synopsis: This document details how to build CLI and REST interfaces for a module. Examples from various SDK modules are included. +--- + +# Module Interfaces + +## Pre-requisite Readings {hide} + +* [Building Modules Intro](./intro.md) {prereq} + +## CLI + +One of the main interfaces for an application is the [command-line interface](../interfaces/cli.md). This entrypoint adds commands from the application's modules to let end-users create [**messages**](./messages-and-queries.md#messages) and [**queries**](./messages-and-queries.md#queries). The CLI files are typically found in the `./x/moduleName/client/cli` folder. + +### Transaction Commands + +[Transactions](../core/transactions.md) are created by users to wrap messages that trigger state changes when they get included in a valid block. Transaction commands typically have their own `tx.go` file in the module `./x/moduleName/client/cli` folder. The commands are specified in getter functions prefixed with `GetCmd` and include the name of the command. + +Here is an example from the `nameservice` module: + ++++ https://github.com/cosmos/sdk-tutorials/blob/86a27321cf89cc637581762e953d0c07f8c78ece/nameservice/x/nameservice/client/cli/tx.go#L33-L58 + +This getter function creates the command for the Buy Name transaction. It does the following: + +- **Construct the command:** Read the [Cobra Documentation](https://github.com/spf13/cobra) for details on how to create commands. + + **Use:** Specifies the format of a command-line entry users should type in order to invoke this command. In this case, the user uses `buy-name` as the name of the transaction command and provides the `name` the user wishes to buy and the `amount` the user is willing to pay. + + **Args:** The number of arguments the user provides, in this case exactly two: `name` and `amount`. + + **Short and Long:** A description for the function is provided here. A `Short` description is expected, and `Long` can be used to provide a more detailed description when a user uses the `--help` flag to ask for more information. + + **RunE:** Defines a function that can return an error, called when the command is executed. Using `Run` would do the same thing, but would not allow for errors to be returned. +- **`RunE` Function Body:** The function should be specified as a `RunE` to allow for errors to be returned. This function encapsulates all of the logic to create a new transaction that is ready to be relayed to nodes. + + The function should first initialize a [`TxBuilder`](../core/transactions.md#txbuilder) with the application `codec`'s `TxEncoder`, as well as a new [`CLIContext`](../interfaces/query-lifecycle.md#clicontext) with the `codec` and `AccountDecoder`. These contexts contain all the information provided by the user and will be used to transfer this user-specific information between processes. To learn more about how contexts are used in a transaction, click [here](../core/transactions.md#transaction-generation). + + If applicable, the command's arguments are parsed. Here, the `amount` given by the user is parsed into a denomination of `coins`. + + If applicable, the `CLIContext` is used to retrieve any parameters such as the transaction originator's address to be used in the transaction. Here, the `from` address is retrieved by calling `cliCtx.getFromAddress()`. + + A [message](./messages-and-queries.md) is created using all parameters parsed from the command arguments and `CLIContext`. The constructor function of the specific message type is called directly. It is good practice to call `ValidateBasic()` on the newly created message to run a sanity check and check for invalid arguments. + + Depending on what the user wants, the transaction is either generated offline or signed and broadcasted to the preconfigured node using `GenerateOrBroadcastMsgs()`. +- **Flags.** Add any [flags](#flags) to the command. No flags were specified here, but all transaction commands have flags to provide additional information from the user (e.g. amount of fees they are willing to pay). These *persistent* [transaction flags](../interfaces/cli.md#flags) can be added to a higher-level command so that they apply to all transaction commands. + +Finally, the module needs to have a `GetTxCmd()`, which aggregates all of the transaction commands of the module. Often, each command getter function has its own file in the module's `cli` folder, and a separate `tx.go` file contains `GetTxCmd()`. Application developers wishing to include the module's transactions will call this function to add them as subcommands in their CLI. Here is the `auth` `GetTxCmd()` function, which adds the `Sign` and `MultiSign` commands. + ++++ https://github.com/cosmos/cosmos-sdk/blob/67f6b021180c7ef0bcf25b6597a629aca27766b8/x/auth/client/cli/tx.go#L11-L25 + +An application using this module likely adds `auth` module commands to its root `TxCmd` command by calling `txCmd.AddCommand(authModuleClient.GetTxCmd())`. + +### Query Commands + +[Queries](./messages-and-queries.md#queries) allow users to gather information about the application or network state; they are routed by the application and processed by the module in which they are defined. Query commands typically have their own `query.go` file in the module `x/moduleName/client/cli` folder. Like transaction commands, they are specified in getter functions and have the prefix `GetCmdQuery`. Here is an example of a query command from the `nameservice` module: + ++++ https://github.com/cosmos/sdk-tutorials/blob/86a27321cf89cc637581762e953d0c07f8c78ece/nameservice/x/nameservice/client/cli/query.go#L52-L73 + +This query returns the address that owns a particular name. The getter function does the following: + +- **`codec` and `queryRoute`.** In addition to taking in the application `codec`, query command getters also take a `queryRoute` used to construct a path [Baseapp](../core/baseapp.md#query-routing) uses to route the query in the application. +- **Construct the command.** Read the [Cobra Documentation](https://github.com/spf13/cobra) and the [transaction command](#transaction-commands) example above for more information. The user must type `whois` and provide the `name` they are querying for as the only argument. +- **`RunE`.** The function should be specified as a `RunE` to allow for errors to be returned. This function encapsulates all of the logic to create a new query that is ready to be relayed to nodes. + + The function should first initialize a new [`CLIContext`](../interfaces/query-lifecycle.md#clicontext) with the application `codec`. + + If applicable, the `CLIContext` is used to retrieve any parameters (e.g. the query originator's address to be used in the query) and marshal them with the query parameter type, in preparation to be relayed to a node. There are no `CLIContext` parameters in this case because the query does not involve any information about the user. + + The `queryRoute` is used to construct a `path` [`baseapp`](../core/baseapp.md) will use to route the query to the appropriate [querier](./querier.md). The expected format for a query `path` is "queryCategory/queryRoute/queryType/arg1/arg2/...", where `queryCategory` can be `p2p`, `store`, `app`, or `custom`, `queryRoute` is the name of the module, and `queryType` is the name of the query type defined within the module. [`baseapp`](../core/baseapp.md) can handle each type of `queryCategory` by routing it to a module querier or retrieving results directly from stores and functions for querying peer nodes. Module queries are `custom` type queries (some SDK modules have exceptions, such as `auth` and `gov` module queries). + + The `CLIContext` `QueryWithData()` function is used to relay the query to a node and retrieve the response. It requires the `path`. It returns the result and height of the query upon success or an error if the query fails. In addition, it will verify the returned proof if `TrustNode` is disabled. If proof verification fails or the query height is invalid, an error will be returned. + + The `codec` is used to nmarshal the response and the `CLIContext` is used to print the output back to the user. +- **Flags.** Add any [flags](#flags) to the command. + + +Finally, the module also needs a `GetQueryCmd`, which aggregates all of the query commands of the module. Application developers wishing to include the module's queries will call this function to add them as subcommands in their CLI. Its structure is identical to the `GetTxCmd` command shown above. + +### Flags + +[Flags](../interfaces/cli.md#flags) are entered by the user and allow for command customizations. Examples include the [fees](../basics/gas-fees.md) or gas prices users are willing to pay for their transactions. + +The flags for a module are typically found in a `flags.go` file in the `./x/moduleName/client/cli` folder. Module developers can create a list of possible flags including the value type, default value, and a description displayed if the user uses a `help` command. In each transaction getter function, they can add flags to the commands and, optionally, mark flags as *required* so that an error is thrown if the user does not provide values for them. + +For full details on flags, visit the [Cobra Documentation](https://github.com/spf13/cobra). + +For example, the SDK `./client/flags` package includes a `PostCommands()` function that adds necessary flags to transaction commands, such as the `from` flag to indicate which address the transaction originates from. + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/client/flags/flags.go#L85-L116 + +Here is an example of how to add a flag using the `from` flag from this function. + +```go +cmd.Flags().String(FlagFrom, "", "Name or address of private key with which to sign") +``` + +The input provided for this flag - called `FlagFrom` is a string with the default value of `""` if none is provided. If the user asks for a description of this flag, the description will be printed. + +A flag can be marked as *required* so that an error is automatically thrown if the user does not provide a value: + +```go +cmd.MarkFlagRequired(FlagFrom) +``` + +Since `PostCommands()` includes all of the basic flags required for a transaction command, module developers may choose not to add any of their own (specifying arguments instead may often be more appropriate). For a full list of what flags are included in the `PostCommands()` function, including which are required inputs from users, see the CLI documentation [here](../interfaces/cli.md#transaction-flags). + +## REST + +Applications typically support web services that use HTTP requests (e.g. a web wallet like [Lunie.io](https://lunie.io). Thus, application developers will also use REST Routes to route HTTP requests to the application's modules; these routes will be used by service providers. The module developer's responsibility is to define the REST client by defining [routes](#register-routes) for all possible [requests](#request-types) and [handlers](#request-handlers) for each of them. It's up to the module developer how to organize the REST interface files; there is typically a `rest.go` file found in the module's `./x/moduleName/client/rest` folder. + +To support HTTP requests, the module developer needs to define possible request types, how to handle them, and provide a way to register them with a provided router. + +### Request Types + +Request types, which define structured interactions from users, must be defined for all *transaction* requests. Users using this method to interact with an application will send HTTP Requests with the required fields in order to trigger state changes in the application. Conventionally, each request is named with the suffix `Req`, e.g. `SendReq` for a Send transaction. Each struct should include a base request [`baseReq`](../interfaces/rest.md#basereq), the name of the transaction, and all the arguments the user must provide for the transaction. + +Here is an example of a request to buy a name from the `nameservice` module: + ++++ https://github.com/cosmos/sdk-tutorials/blob/master/nameservice/x/nameservice/client/rest/tx.go#L14-L19 + +The `BaseReq` includes basic information that every request needs to have, similar to required flags in a CLI. All of these values, including `GasPrices` and `AccountNumber`, will be provided in the request body. The user will also need to specify the arguments `Name` and `Amount` fields in the body and `Buyer` will be provided by the user's address. + +#### BaseReq + +`BaseReq` is a type defined in the SDK that encapsulates much of the transaction configurations similar to CLI command flags. Users must provide the information in the body of their requests. + +* `From` indicates which [account](../basics/accounts.md) the transaction originates from. This account is used to sign the transaction. +* `Memo` sends a memo along with the transaction. +* `ChainID` specifies the unique identifier of the blockchain the transaction pertains to. +* `AccountNumber` is an identifier for the account. +* `Sequence`is the value of a counter measuring how many transactions have been sent from the account. It is used to prevent replay attacks. +* `Gas` refers to how much [gas](../basics/gas-fees.md), which represents computational resources, Tx consumes. Gas is dependent on the transaction and is not precisely calculated until execution, but can be estimated by providing auto as the value for `Gas`. +* `GasAdjustment` can be used to scale gas up in order to avoid underestimating. For example, users can specify their gas adjustment as 1.5 to use 1.5 times the estimated gas. +* `GasPrices` specifies how much the user is willing pay per unit of gas, which can be one or multiple denominations of tokens. For example, --gas-prices=0.025uatom, 0.025upho means the user is willing to pay 0.025uatom AND 0.025upho per unit of gas. +* `Fees` specifies how much in [fees](../basics/gas-fees.md) the user is willing to pay in total. Note that the user only needs to provide either `gas-prices` or `fees`, but not both, because they can be derived from each other. +* `Simulate` instructs the application to ignore gas and simulate the transaction running without broadcasting. + +### Request Handlers + +Request handlers must be defined for both transaction and query requests. Handlers' arguments include a reference to the application's `codec` and the [`CLIContext`](../interfaces/query-lifecycle.md#clicontext) created in the user interaction. + +Here is an example of a request handler for the nameservice module `buyNameReq` request (the same one shown above): + ++++ https://github.com/cosmos/sdk-tutorials/blob/master/nameservice/x/nameservice/client/rest/tx.go#L21-L57 + +The request handler can be broken down as follows: + +* **Parse Request:** The request handler first attempts to parse the request, and then run `Sanitize` and `ValidateBasic` on the underlying `BaseReq` to check the validity of the request. Next, it attempts to parse the arguments `Buyer` and `Amount` to the types `AccountAddress` and `Coins` respectively. +* **Message:** Then, a [message](./messages-and-queries.md) of the type `MsgBuyName` (defined by the module developer to trigger the state changes for this transaction) is created from the values and another sanity check, `ValidateBasic` is run on it. +* **Generate Transaction:** Finally, the HTTP `ResponseWriter`, application [`codec`](../core/encoding.md), [`CLIContext`](../interfaces/query-lifecycle.md#clicontext), request [`BaseReq`](../interfaces/rest.md#basereq), and message is passed to `WriteGenerateStdTxResponse` to further process the request. + +To read more about how a transaction is generated, visit the transactions documentation [here](../core/transactions.md#transaction-generation). + + +### Register Routes + +The application CLI entrypoint will have a `RegisterRoutes` function in its `main.go` file, which calls the `registerRoutes` functions of each module utilized by the application. Module developers need to implement `registerRoutes` for their modules so that applications are able to route messages and queries to their corresponding handlers and queriers. + +The router used by the SDK is [Gorilla Mux](https://github.com/gorilla/mux). The router is initialized with the Gorilla Mux `NewRouter()` function. Then, the router's `HandleFunc` function can then be used to route urls with the defined request handlers and the HTTP method (e.g. "POST", "GET") as a route matcher. It is recommended to prefix every route with the name of the module to avoid collisions with other modules that have the same query or transaction names. + +Here is a `registerRoutes` function with one query route example from the [nameservice tutorial](https://cosmos.network/docs/tutorial/rest.html): + +``` go +func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Codec, storeName string) { + // ResolveName Query + r.HandleFunc(fmt.Sprintf("/%s/names/{%s}", storeName, restName), resolveNameHandler(cdc, cliCtx, storeName)).Methods("GET") +} +``` + +A few things to note: + +* The router `r` has already been initialized by the application and is passed in here as an argument - this function is able to add on the nameservice module's routes onto any application's router. The application must also provide a [`CLIContext`](../interfaces/query-lifecycle.md#clicontext) that the querier will need to process user requests and the application [`codec`](../core/encoding.md) for encoding and decoding application-specific types. +* `"/%s/names/{%s}", storeName, restName` is the url for the HTTP request. `storeName` is the name of the module, `restName` is a variable provided by the user to specify what kind of query they are making. +* `resolveNameHandler` is the query request handler defined by the module developer. It also takes the application `codec` and `CLIContext` passed in from the user side, as well as the `storeName`. +* `"GET"` is the HTTP Request method. As to be expected, queries are typically GET requests. Transactions are typically POST and PUT requests. + + +## Next {hide} + +Read about the recommended [module structure](./structure.md) {hide} diff --git a/docs/building-modules/module-manager.md b/docs/building-modules/module-manager.md new file mode 100644 index 000000000000..2ad4bc9006a4 --- /dev/null +++ b/docs/building-modules/module-manager.md @@ -0,0 +1,142 @@ +--- +order: 2 +synopsis: "Cosmos SDK modules need to implement the [`AppModule` interfaces](#application-module-interfaces), in order to be managed by the application's [module manager](#module-manager). The module manager plays an important role in [`message` and `query` routing](../core/baseapp.md#routing), and allows application developers to set the order of execution of a variety of functions like [`BeginBlocker` and `EndBlocker`](../basics/app-anatomy.md#begingblocker-and-endblocker)." +--- + + +# Module Manager + +## Pre-requisite Readings {hide} + +- [Introduction to SDK Modules](./intro.md) {prereq} + +## Application Module Interfaces + +Application module interfaces exist to facilitate the composition of modules together to form a functional SDK application. There are 3 main application module interfaces: + +- [`AppModuleBasic`](#appmodulebasic) for independent module functionalities. +- [`AppModule`](#appmodule) for inter-dependent module functionalities (except genesis-related functionalities). +- [`AppModuleGenesis`](#appmodulegenesis) for inter-dependent genesis-related module functionalities. + +The `AppModuleBasic` interface exists to define independent methods of the module, i.e. those that do not depend on other modules in the application. This allows for the construction of the basic application structure early in the application definition, generally in the `init()` function of the [main application file](../basics/app-anatomy.md#core-application-file). + +The `AppModule` interface exists to define inter-dependent module methods. Many modules need to interract with other modules, typically through [`keeper`s](./keeper.md), which means there is a need for an interface where modules list their `keeper`s and other methods that require a reference to another module's object. `AppModule` interface also enables the module manager to set the order of execution between module's methods like `BeginBlock` and `EndBlock`, which is important in cases where the order of execution between modules matters in the context of the application. + +Lastly the interface for genesis functionality `AppModuleGenesis` is separated out from full module functionality `AppModule` so that modules which +are only used for genesis can take advantage of the `Module` patterns without having to define many placeholder functions. + +### `AppModuleBasic` + +The `AppModuleBasic` interface defines the independent methods modules need to implement. + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/module/module.go#L46-L59 + +Let us go through the methods: + +- `Name()`: Returns the name of the module as a `string`. +- `RegisterCodec(*codec.Codec)`: Registers the `codec` for the module, which is used to marhsal and unmarshal structs to/from `[]byte` in order to persist them in the moduel's `KVStore`. +- `DefaultGenesis()`: Returns a default [`GenesisState`](./genesis.md#genesisstate) for the module, marshalled to `json.RawMessage`. The default `GenesisState` need to be defined by the module developer and is primarily used for testing. +- `ValidateGenesis(json.RawMessage)`: Used to validate the `GenesisState` defined by a module, given in its `json.RawMessage` form. It will usually unmarshall the `json` before running a custom [`ValidateGenesis`](./genesis.md#validategenesis) function defined by the module developer. +- `RegisterRESTRoutes(context.CLIContext, *mux.Router)`: Registers the REST routes for the module. These routes will be used to map REST request to the module in order to process them. See [../interfaces/rest.md] for more. +- `GetTxCmd(*codec.Codec)`: Returns the root [`Tx` command](./module-interfaces.md#tx) for the module. The subcommands of this root command are used by end-users to generate new transactions containing [`message`s](./messages-and-queries.md#queries) defined in the module. +- `GetQueryCmd(*codec.Codec)`: Return the root [`query` command](./module-interfaces.md#query) for the module. The subcommands of this root command are used by end-users to generate new queries to the subset of the state defined by the module. + +All the `AppModuleBasic` of an application are managed by the [`BasicManager`](#basicmanager). + +### `AppModuleGenesis` + +The `AppModuleGenesis` interface is a simple embedding of the `AppModuleBasic` interface with two added methods. + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/module/module.go#L126-L131 + +Let us go through the two added methods: + +- `InitGenesis(sdk.Context, json.RawMessage)`: Initializes the subset of the state managed by the module. It is called at genesis (i.e. when the chain is first started). +- `ExportGenesis(sdk.Context)`: Exports the latest subset of the state managed by the module to be used in a new genesis file. `ExportGenesis` is called for each module when a new chain is started from the state of an existing chain. + +It does not have its own manager, and exists separately from [`AppModule`](#appmodule) only for modules that exist only to implement genesis functionalities, so that they can be managed without having to implement all of `AppModule`'s methods. If the module is not only used during genesis, `InitGenesis(sdk.Context, json.RawMessage)` and `ExportGenesis(sdk.Context)` will generally be defined as methods of the concrete type implementing hte `AppModule` interface. + +### `AppModule` + +The `AppModule` interface defines the inter-dependent methods modules need to implement. + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/module/module.go#L133-L149 + +`AppModule`s are managed by the [module manager](#manager). This interface embeds the `AppModuleGenesis` interface so that the manager can access all the independent and genesis inter-dependent methods of the module. This means that a concrete type implementing the `AppModule` interface must either implement all the methods of `AppModuleGenesis` (and by extension `AppModuleBasic`), or include a concrete type that does as parameter. + +Let us go through the methods of `AppModule`: + +- `RegisterInvariants(sdk.InvariantRegistry)`: Registers the [`invariants`](./invariants.md) of the module. If the invariants deviates from its predicted value, the [`InvariantRegistry`](./invariants.md#registry) triggers appropriate logic (most often the chain will be halted). +- `Route()`: Returns the name of the module's route, for [`message`s](./messages-and-queries.md#messages) to be routed to the module by [`baseapp`](../core/baseapp.md#message-routing). +- `NewHandler()`: Returns a [`handler`](./handler.md) given the `Type()` of the `message`, in order to process the `message`. +- `QuerierRoute()`: Returns the name of the module's query route, for [`queries`](./messages-and-queries.md#queries) to be routes to the module by [`baseapp`](../core/baseapp.md#query-routing). +- `NewQuerierHandler()`: Returns a [`querier`](./querier.md) given the query `path`, in order to process the `query`. +- `BeginBlock(sdk.Context, abci.RequestBeginBlock)`: This method gives module developers the option to implement logic that is automatically triggered at the beginning of each block. Implement empty if no logic needs to be triggered at the beginning of each block for this module. +- `EndBlock(sdk.Context, abci.RequestEndBlock)`: This method gives module developers the option to implement logic that is automatically triggered at the beginning of each block. This is also where the module can inform the underlying consensus engine of validator set changes (e.g. the `staking` module). Implement empty if no logic needs to be triggered at the beginning of each block for this module. + +### Implementing the Application Module Interfaces + +Typically, the various application module interfaces are implemented in a file called `module.go`, located in the module's folder (e.g. `./x/module/module.go`). + +Almost every module need to implement the `AppModuleBasic` and `AppModule` interfaces. If the module is only used for genesis, it will implement `AppModuleGenesis` instead of `AppModule`. The concrete type that implements the interface can add parameters that are required for the implementation of the various methods of the interface. For example, the `NewHandler()` function often calls a `NewHandler(k keeper)` function defined in [`handler.go`](./handler.md) and therefore needs to pass the module's [`keeper`](./keeper.md) as parameter. + +```go +// example +type AppModule struct { + AppModuleBasic + keeper Keeper +} +``` + +In the example above, you can see that the `AppModule` concrete type references an `AppModuleBasic`, and not an `AppModuleGenesis`. That is because `AppModuleGenesis` only needs to be implemented in modules that focus on genesis-related functionalities. In most modules, the concrete `AppModule` type will have a reference to an `AppModuleBasic` and implement the two added methods of `AppModuleGenesis` directly in the `AppModule` type. + +If no parameter is required (which is often the case for `AppModuleBasic`), just declare an empty concrete type like so: + +```go +type AppModuleBasic struct{} +``` + +## Module Managers + +Module managers are used to manage collections of `AppModuleBasic` and `AppModule`. + +### `BasicManager` + +The `BasicManager` is a structure that lists all the `AppModuleBasic` of an application: + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/module/module.go#L61-L63 + +It implements the following methods: + +- `NewBasicManager(modules ...AppModuleBasic)`: Constructor function. It takes a list of the application's `AppModuleBasic` and builds a new `BasicManager`. This function is generally called in the `init()` function of [`app.go`](../basics/app-anatomy.md#core-application-file) to quickly initialize the independent elements of the application's modules (click [here](https://github.com/cosmos/gaia/blob/master/app/app.go#L59-L74) to see an example). +- `RegisterCodec(cdc *codec.Codec)`: Registers the [`codec`s](../core/encoding.md) of each of the application's `AppModuleBasic`. This function is usually called early on in the [application's construction](../basics/app-anatomy.md#constructor). +- `DefaultGenesis()`: Provides default genesis information for modules in the application by calling the [`DefaultGenesis()`](./genesis.md#defaultgenesis) function of each module. It is used to construct a default genesis file for the application. +- `ValidateGenesis(genesis map[string]json.RawMessage)`: Validates the genesis information modules by calling the [`ValidateGenesis()`](./genesis.md#validategenesis) function of each module. +- `RegisterRESTRoutes(ctx context.CLIContext, rtr *mux.Router)`: Registers REST routes for modules by calling the [`RegisterRESTRoutes`](./module-interfaces.md#register-routes) function of each module. This function is usually called function from the `main.go` function of the [application's command-line interface](../interfaces/cli.md). +- `AddTxCommands(rootTxCmd *cobra.Command, cdc *codec.Codec)`: Adds modules' transaction commands to the application's [`rootTxCommand`](../interfaces/cli.md#transaction-commands). This function is usually called function from the `main.go` function of the [application's command-line interface](../interfaces/cli.md). +- `AddQueryCommands(rootQueryCmd *cobra.Command, cdc *codec.Codec)`: Adds modules' query commands to the application's [`rootQueryCommand`](../interfaces/cli.md#query-commands). This function is usually called function from the `main.go` function of the [application's command-line interface](../interfaces/cli.md). + + +### `Manager` + +The `Manager` is a structure that holds all the `AppModule` of an application, and defines the order of execution between several key components of these modules: + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/module/module.go#L190-L198 + +The module manager is used throughout the application whenever an action on a collection of modules is required. It implements the following methods: + +- `NewManager(modules ...AppModule)`: Constructor function. It takes a list of the application's `AppModule`s and builds a new `Manager`. It is generally called from the application's main [constructor function](../basics/app-anatomy.md#constructor-function). +- `SetOrderInitGenesis(moduleNames ...string)`: Sets the order in which the [`InitGenesis`](./genesis.md#initgenesis) function of each module will be called when the application is first started. This function is generally called from the application's main [constructor function](../basics/app-anatomy.md#constructor-function). +- `SetOrderExportGenesis(moduleNames ...string)`: Sets the order in which the [`ExportGenesis`](./genesis.md#exportgenesis) function of each module will be called in case of an export. This function is generally called from the application's main [constructor function](../basics/app-anatomy.md#constructor-function). +- `SetOrderBeginBlockers(moduleNames ...string)`: Sets the order in which the `BeginBlock()` function of each module will be called at the beginning of each block. This function is generally called from the application's main [constructor function](../basics/app-anatomy.md#constructor-function). +- `SetOrderEndBlockers(moduleNames ...string)`: Sets the order in which the `EndBlock()` function of each module will be called at the beginning of each block. This function is generally called from the application's main [constructor function](../basics/app-anatomy.md#constructor-function). +- `RegisterInvariants(ir sdk.InvariantRegistry)`: Registers the [invariants](./invariants.md) of each module. +- `RegisterRoutes(router sdk.Router, queryRouter sdk.QueryRouter)`: Registers module routes to the application's `router`, in order to route [`message`s](./messages-and-queries.md#messages) to the appropriate [`handler`](./handler.md), and module query routes to the application's `queryRouter`, in order to route [`queries`](./messages-and-queries.md#queries) to the appropriate [`querier`](./querier.md). +- `InitGenesis(ctx sdk.Context, genesisData map[string]json.RawMessage)`: Calls the [`InitGenesis`](./genesis.md#initgenesis) function of each module when the application is first started, in the order defined in `OrderInitGenesis`. Returns an `abci.ResponseInitChain` to the underlying consensus engine, which can contain validator updates. +- `ExportGenesis(ctx sdk.Context)`: Calls the [`ExportGenesis`](./genesis.md#exportgenesis) function of each module, in the order defined in `OrderExportGenesis`. The export constructs a genesis file from a previously existing state, and is mainly used when a hard-fork upgrade of the chain is required. +- `BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock)`: At the beginning of each block, this function is called from [`baseapp`](../core/baseapp.md#beginblock) and, in turn, calls the [`BeginBlock`](./beginblock-endblock.md) function of each module, in the order defined in `OrderBeginBlockers`. It creates a child [context](../core/context.md) with an event manager to aggregate [events](../core/events.md) emitted from all modules. The function returns an `abci.ResponseBeginBlock` which contains the aforementioned events. +- `EndBlock(ctx sdk.Context, req abci.RequestEndBlock)`: At the end of each block, this function is called from [`baseapp`](../core/baseapp.md#endblock) and, in turn, calls the [`EndBlock`](./beginblock-endblock.md) function of each module, in the order defined in `OrderEndBlockers`. It creates a child [context](../core/context.md) with an event manager to aggregate [events](../core/events.md) emitted from all modules. The function returns an `abci.ResponseEndBlock` which contains the aforementioned events, as well as validator set updates (if any). + +## Next {hide} + +Learn more about [`message`s and `queries`](./messages-and-queries.md) {hide} diff --git a/docs/building-modules/querier.md b/docs/building-modules/querier.md new file mode 100644 index 000000000000..f839a2bef266 --- /dev/null +++ b/docs/building-modules/querier.md @@ -0,0 +1,53 @@ +--- +order: 5 +synopsis: "A `Querier` designates a function that processes [`queries`](./messages-and-queries.md#queries). `querier`s are specific to the module in which they are defined, and only process `queries` defined within said module. They are called from `baseapp`'s [`Query` method](../core/baseapp.md#query)." +--- + +# Queriers + +## Pre-requisite Readings {hide} + +- [Module Manager](./module-manager.md) {prereq} +- [Messages and Queries](./messages-and-queries.md) {prereq} + +## `Querier` type + +The `querier` type defined in the Cosmos SDK specifies the typical structure of a `querier` function: + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/queryable.go#L6 + +Let us break it down: + +- The `path` is an array of `string`s that contains the type of the query, and that can also contain `query` arguments. See [`queries`](./messages-and-queries.md#queries) for more information. +- The `req` itself is primarily used to retrieve arguments if they are too large to fit in the `path`. This is done using the `Data` field of `req`. +- The [`Context`](../core/context.md) contains all the necessary information needed to process the `query`, as well as a cache-wrapped copy of the latest state. It is primarily used by the [`keeper`](./keeper.md) to access the state. +- The result `res` returned to `baseapp`, marhsalled using the application's [`codec`](../core/encoding.md). + +## Implementation of a module `querier`s + +Module `querier`s are typically implemented in a `./internal/keeper/querier.go` file inside the module's folder. The [module manager](./module-manager.md) is used to add the module's `querier`s to the [application's `queryRouter`](../core/baseapp.md#query-routing) via the `NewQuerier()` method. Typically, the manager's `NewQuerier()` method simply calls a `NewQuerier()` method defined in `keeper/querier.go`, which looks like the following: + +```go +func NewQuerier(keeper Keeper) sdk.Querier { + return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err sdk.Error) { + switch path[0] { + case QueryType1: + return queryType1(ctx, path[1:], req, keeper) + case QueryType2: + return queryType2(ctx, path[1:], req, keeper) + default: + return nil, sdk.ErrUnknownRequest("unknown nameservice query endpoint") + } + } +} +``` + +This simple switch returns a `querier` function specific to the type of the received `query`. At this point of the [query lifecycle](../interfaces/query-lifecycle.md), the first element of the `path` (`path[0]`) contains the type of the query. The following elements are either empty or contain arguments needed to process the query. + +The `querier` functions themselves are pretty straighforward. They generally fetch a value or values from the state using the [`keeper`](./keeper.md). Then, they marshall the value(s) using the [`codec`](../core/encoding.md) and return the `[]byte` obtained as result. + +For a deeper look at `querier`s, see this [example implementation of a `querier` function](https://github.com/cosmos/sdk-application-tutorial/blob/c6754a1e313eb1ed973c5c91dcc606f2fd288811/x/nameservice/internal/keeper/querier.go) from the nameservice tutorial. + +## Next {hide} + +Learn about [`BeginBlocker` and `EndBlocker`](./beginblock-endblock.md) {hide} diff --git a/docs/building-modules/structure.md b/docs/building-modules/structure.md index 8b0f62c0e825..7ae32f2dde82 100644 --- a/docs/building-modules/structure.md +++ b/docs/building-modules/structure.md @@ -1,8 +1,9 @@ -# Module Specification +--- +order: 12 +synopsis: This document outlines the recommended structure of Cosmos SDK modules. These ideas are meant to be applied as suggestions. Application developers are encouraged to improve upon and contribute to module structure and development design. +--- -This document outlines the recommended structure of Cosmos SDK modules. These -ideas are meant to be applied as suggestions. Application developers are encouraged -to improve upon and contribute to module structure and development design. +# Recommended Folder Structure ## Structure @@ -79,3 +80,7 @@ allows for greater freedom of development while maintaining API stability. - `module.go`: The module's implementation of the `AppModule` and `AppModuleBasic` interfaces. - `simulation.go`: The module's simulation messages and related types (if any). + +## Next {hide} + +Learn about [interfaces](../interfaces/interfaces-intro.md) {hide} \ No newline at end of file diff --git a/docs/cn/README.md b/docs/cn/README.md index e3bd9ce98876..bbd14a3109f3 100644 --- a/docs/cn/README.md +++ b/docs/cn/README.md @@ -1,3 +1,8 @@ +--- +parent: + order: false +--- + # Cosmos SDK 文档 ## 开始 diff --git a/docs/core/README.md b/docs/core/README.md new file mode 100644 index 000000000000..6d865e79a8ff --- /dev/null +++ b/docs/core/README.md @@ -0,0 +1,20 @@ +--- +order: false +parent: + order: 3 +--- + +# Core Concepts + +This repository contains reference documentation on the core conepts of the Cosmos SDK. + +1. [`Baseapp`](./baseapp.md) +2. [Transaction](./transactions.md) +3. [Context](./context.md) +4. [Node Client](./node.md) +5. [Store](./store.md) +6. [Encoding](./encoding.md) +7. [Events](./events.md) +8. [Object-Capabilities](./ocap.md) + +After reading about the core concepts, head on to the [Building Modules documentation](../building-modules/README.md) to learn more about the process of building modules. \ No newline at end of file diff --git a/docs/core/baseapp.md b/docs/core/baseapp.md index 2a0a06a4a836..add0b049caf5 100644 --- a/docs/core/baseapp.md +++ b/docs/core/baseapp.md @@ -1,45 +1,14 @@ -# BaseApp - -## Pre-requisite Reading - -- [Anatomy of an SDK application](../basics/app-anatomy.md) -- [Lifecycle of an SDK transaction](../basics/tx-lifecycle.md) - -## Synopsis - -This document describes `BaseApp`, the abstraction that implements the core -functionalities of an SDK application. - -- [BaseApp](#baseapp) - - [Pre-requisite Reading](#pre-requisite-reading) - - [Synopsis](#synopsis) - - [Introduction](#introduction) - - [Type Definition](#type-definition) - - [Constructor](#constructor) - - [States](#states) - - [InitChain](#initchain) - - [CheckTx](#checktx) - - [BeginBlock](#beginblock) - - [DeliverTx](#delivertx) - - [Commit](#commit) - - [Routing](#routing) - - [Message Routing](#message-routing) - - [Query Routing](#query-routing) - - [Main ABCI Messages](#main-abci-messages) - - [CheckTx](#checktx-1) - - [RecheckTx](#rechecktx) - - [DeliverTx](#delivertx-1) - - [RunTx, AnteHandler and RunMsgs](#runtx-antehandler-and-runmsgs) - - [RunTx](#runtx) - - [AnteHandler](#antehandler) - - [RunMsgs](#runmsgs) - - [Other ABCI Messages](#other-abci-messages) - - [InitChain](#initchain-1) - - [BeginBlock](#beginblock-1) - - [EndBlock](#endblock) - - [Commit](#commit-1) - - [Info](#info) - - [Query](#query) +--- +order: 1 +synopsis: This document describes `BaseApp`, the abstraction that implements the core functionalities of an SDK application. +--- + +# Baseapp + +## Pre-requisite Readings {hide} + +- [Anatomy of an SDK application](../basics/app-anatomy.md) {prereq} +- [Lifecycle of an SDK transaction](../basics/tx-lifecycle.md) {prereq} ## Introduction @@ -75,18 +44,19 @@ management logic. ## Type Definition -The [`BaseApp` type](https://github.com/cosmos/cosmos-sdk/blob/master/baseapp/baseapp.go#L53) holds -many important parameters for any Cosmos SDK based application. Let us go through the most -important components. +The `BaseApp` type holds many important parameters for any Cosmos SDK based application. + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/baseapp/baseapp.go#L54-L108 + +Let us go through the most important components. > __Note__: Not all parameters are described, only the most important ones. Refer to the -[type definition](https://github.com/cosmos/cosmos-sdk/blob/master/baseapp/baseapp.go#L53) for the -full list. +type definition for the full list. First, the important parameters that are initialized during the bootstrapping of the application: -- [`CommitMultiStore`](./store.md#commit-multi-store): This is the main store of the application, -which holds the canonical state that is committed at the [end of each block](#commit-1). This store +- [`CommitMultiStore`](./store.md#commitmultistore): This is the main store of the application, +which holds the canonical state that is committed at the [end of each block](#commit). This store is **not** cached, meaning it is not used to update the application's volatile (un-committed) states. The `CommitMultiStore` is a multi-store, meaning a store of stores. Each module of the application uses one or multiple `KVStores` in the multi-store to persist their subset of the state. @@ -104,7 +74,7 @@ raw transaction bytes relayed by the underlying Tendermint engine. used to persist data related to the core of the application, like consensus parameters. - [`AnteHandler`](#antehandler): This handler is used to handle signature verification, fee payment, and other pre-message execution checks when a transaction is received. It's executed during -[`CheckTx/RecheckTx`](#checktx-1) and [`DeliverTx`](#delivertx-1). +[`CheckTx/RecheckTx`](#checktx) and [`DeliverTx`](#delivertx). - [`InitChainer`](../basics/app-anatomy.md#initchainer), [`BeginBlocker` and `EndBlocker`](../basics/app-anatomy.md#beginblocker-and-endblocker): These are the functions executed when the application receives the `InitChain`, `BeginBlock` and `EndBlock` @@ -112,11 +82,11 @@ ABCI messages from the underlying Tendermint engine. Then, parameters used to define [volatile states](#volatile-states) (i.e. cached states): -- `checkState`: This state is updated during [`CheckTx`](#checktx-1), and reset on [`Commit`](#commit-1). -- `deliverState`: This state is updated during [`DeliverTx`](#delivertx-1), and set to `nil` on -[`Commit`](#commit-1) and gets re-initialized on BeginBlock. +- `checkState`: This state is updated during [`CheckTx`](#checktx), and reset on [`Commit`](#commit). +- `deliverState`: This state is updated during [`DeliverTx`](#delivertx), and set to `nil` on +[`Commit`](#commit) and gets re-initialized on BeginBlock. -Finally, a few more important parameters: +Finally, a few more important parameterd: - `voteInfos`: This parameter carries the list of validators whose precommit is missing, either because they did not vote or because the proposer did not include their vote. This information is @@ -124,7 +94,7 @@ carried by the [Context](#context) and can be used by the application for variou punishing absent validators. - `minGasPrices`: This parameter defines the minimum gas prices accepted by the node. This is a **local** parameter, meaning each full-node can set a different `minGasPrices`. It is used in the -`AnteHandler` during [`CheckTx`](#checktx-1), mainly as a spam protection mechanism. The transaction +`AnteHandler` during [`CheckTx`](#checktx), mainly as a spam protection mechanism. The transaction enters the [mempool](https://tendermint.com/docs/tendermint-core/mempool.html#transaction-ordering) only if the gas prices of the transaction are greater than one of the minimum gas price in `minGasPrices` (e.g. if `minGasPrices == 1uatom,1photon`, the `gas-price` of the transaction must be @@ -144,20 +114,18 @@ func NewBaseApp( ``` The `BaseApp` constructor function is pretty straightforward. The only thing worth noting is the -possibility to provide additional [`options`](https://github.com/cosmos/cosmos-sdk/blob/master/baseapp/options.go) +possibility to provide additional [`options`](https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/baseapp/options.go) to the `BaseApp`, which will execute them in order. The `options` are generally `setter` functions for important parameters, like `SetPruning()` to set pruning options or `SetMinGasPrices()` to set the node's `min-gas-prices`. -A list of `options` examples can be found -[here](https://github.com/cosmos/cosmos-sdk/blob/master/baseapp/options.go). Naturally, developers -can add additional `options` based on their application's needs. +Naturally, developers can add additional `options` based on their application's needs. -## States +## State Updates The `BaseApp` maintains two primary volatile states and a root or main state. The main state is the canonical state of the application and the volatile states, `checkState` and `deliverState`, -are used to handle state transitions in-between the main state made during [`Commit`](#commit-1). +are used to handle state transitions in-between the main state made during [`Commit`](#commit). Internally, there is only a single `CommitMultiStore` which we refer to as the main or root state. From this root state, we derive two volatile state through a mechanism called cache-wrapping. The @@ -165,14 +133,14 @@ types can be illustrated as follows: ![Types](./baseapp_state_types.png) -### InitChain +### InitChain State Updates During `InitChain`, the two volatile states, `checkState` and `deliverState` are set by cache-wrapping the root `CommitMultiStore`. Any subsequent reads and writes happen on cached versions of the `CommitMultiStore`. ![InitChain](./baseapp_state-initchain.png) -### CheckTx +### CheckTx State Updates During `CheckTx`, the `checkState`, which is based off of the last committed state from the root store, is used for any reads and writes. Here we only execute the `AnteHandler` and verify a router @@ -183,15 +151,15 @@ success. ![CheckTx](./baseapp_state-checktx.png) -### BeginBlock +### BeginBlock State Updates During `BeginBlock`, the `deliverState` is set for use in subsequent `DeliverTx` ABCI messages. The `deliverState` is based off of the last committed state from the root store and is cache-wrapped. -Note, the `deliverState` is set to `nil` on [`Commit`](#commit-1). +Note, the `deliverState` is set to `nil` on [`Commit`](#commit). ![BeginBlock](./baseapp_state-begin_block.png) -### DeliverTx +### DeliverTx State Updates The state flow for `DeliverTx` is nearly identical to `CheckTx` except state transitions occur on the `deliverState` and messages in a transaction are executed. Similarly to `CheckTx`, state transitions @@ -201,7 +169,7 @@ the AnteHandler are persisted. ![DeliverTx](./baseapp_state-deliver_tx.png) -### Commit +### Commit State Updates During `Commit` all the state transitions that occurred in the `deliverState` are finally written to the root `CommitMultiStore` which in turn is committed to disk and results in a new application @@ -216,28 +184,30 @@ When messages and queries are received by the application, they must be routed t ### Message Routing -`Message`s need to be routed after they are extracted from transactions, which are sent from the underlying Tendermint engine via the [`CheckTx`](#checktx) and [`DeliverTx`](#delivertx) ABCI messages. To do so, `baseapp` holds a [`router`](https://github.com/cosmos/cosmos-sdk/blob/master/baseapp/router.go) which maps `paths` (`string`) to the appropriate module `handler`. Usually, the `path` is the name of the module. +[`Message`s](#../building-modules/messages-and-queries.md#messages) need to be routed after they are extracted from transactions, which are sent from the underlying Tendermint engine via the [`CheckTx`](#checktx) and [`DeliverTx`](#delivertx) ABCI messages. To do so, `baseapp` holds a `router` which maps `paths` (`string`) to the appropriate module [`handler`](../building-modules/handler.md). Usually, the `path` is the name of the module. -The application's `router` is initialized with all the routes using the application's module manager, which itself is initialized with all the application's modules in the application's [constructor](../basics/app-anatomy.md#app-constructor). ++++ https://github.com/cosmos/cosmos-sdk/blob/master/baseapp/router.go + +The application's `router` is initilalized with all the routes using the application's [module manager](../building-modules/module-manager.md#manager), which itself is initialized with all the application's modules in the application's [constructor](../basics/app-anatomy.md#app-constructor). ### Query Routing -Similar to messages, queries need to be routed to the appropriate module's querier. To do so, `baseapp` holds a [`query router`](https://github.com/cosmos/cosmos-sdk/blob/master/baseapp/queryrouter.go), which maps `paths` (`string`) to the appropriate module `querier`. Usually, the `path` is the name of the module. +Similar to `message`s, [`queries`](../building-modules/messages-and-queries.md#queries) need to be routed to the appropriate module's [querier](../building-modules/querier.md). To do so, `baseapp` holds a `query router`, which maps module names to module `querier`s. The `queryRouter` is called during the initial stages of `query` processing, which is done via the [`Query` ABCI message](#query). -Just like the `router`, the `query router` is initialized with all the query routes using the application's module manager, which itself is initialized with all the application's modules in the application's [constructor](../basics/app-anatomy.md#app-constructor). +Just like the `router`, the `query router` is initilalized with all the query routes using the application's [module manager](../building-modules/module-manager.md), which itself is initialized with all the application's modules in the application's [constructor](../basics/app-anatomy.md#app-constructor). ## Main ABCI Messages -The [Application-Blockchain Interface](https://tendermint.com/docs/spec/abci/) (ABCI) is a generic interface that connects a state-machine with a consensus engine to form a functional full-node. It can be wrapped in any language, and needs to be implemented by each application-specific blockchain built on top of an ABCI-compatible consensus engine like Tendermint. +The [Application-Blockchain Interface](https://tendermint.com/docs/spec/abci/) (ABCI) is a generic interface that connects a state-machine with a consensus engine to form a functional full-node. It can be wrapped in any language, and needs to be implemented by each application-specific blockchain built on top of an ABCI-compatible consensus engine like Tendermint. The consensus engine handles two main tasks: - The networking logic, which mainly consists in gossiping block parts, transactions and consensus votes. -- The consensus logic, which results in the deterministic ordering of transactions in the form of blocks. +- The consensus logic, which results in the deterministic ordering of transactions in the form of blocks. -It is **not** the role of the consensus engine to define the state or the validity of transactions. Generally, transactions are handled by the consensus engine in the form of `[]bytes`, and relayed to the application via the ABCI to be decoded and processed. At keys moments in the networking and consensus processes (e.g. beginning of a block, commit of a block, reception of an unconfirmed transaction, ...), the consensus engine emits ABCI messages for the state-machine to act on. +It is **not** the role of the consensus engine to define the state or the validity of transactions. Generally, transactions are handled by the consensus engine in the form of `[]bytes`, and relayed to the application via the ABCI to be decoded and processed. At keys moments in the networking and consensus processes (e.g. beginning of a block, commit of a block, reception of an unconfirmed transaction, ...), the consensus engine emits ABCI messages for the state-machine to act on. -Developers building on top of the Cosmos SDK need not implement the ABCI themselves, as all the ABCI messages are implemented as a set of `baseapp`'s methods in the Cosmos SDK. Let us go through the main ABCI messages that `baseapp` handles: [`CheckTx`](#checktx) and [`DeliverTx`](#delivertx). Note that these ABCI messages are different from the `message`s contained in `transactions`, the purpose of which is to trigger state-transitions. +Developers building on top of the Cosmos SDK need not implement the ABCI themselves, as `baseapp` comes with a built-in implementation of the interface. Let us go through the main ABCI messages that `baseapp` implements: [`CheckTx`](#checktx) and [`DeliverTx`](#delivertx) ### CheckTx @@ -247,24 +217,24 @@ transaction is received by a full-node. The role of `CheckTx` is to guard the fu Unconfirmed transactions are relayed to peers only if they pass `CheckTx`. `CheckTx()` can perform both _stateful_ and _stateless_ checks, but developers should strive to -make them lightweight. In the Cosmos SDK, after decoding transactions, `CheckTx()` is implemented +make them lightweight. In the Cosmos SDK, after [decoding transactions](./encoding.md), `CheckTx()` is implemented to do the following checks: 1. Extract the `message`s from the transaction. 2. Perform _stateless_ checks by calling `ValidateBasic()` on each of the `messages`. This is done first, as _stateless_ checks are less computationally expensive than _stateful_ checks. If `ValidateBasic()` fail, `CheckTx` returns before running _stateful_ checks, which saves resources. -3. Perform non-module related _stateful_ checks on the account. This step is mainly about checking +3. Perform non-module related _stateful_ checks on the [account](../basics/accounts.md). This step is mainly about checking that the `message` signatures are valid, that enough fees are provided and that the sending account - has enough funds to pay for said fees. Note that no precise `gas` counting occurs here, - as `message`s are not processed. Usually, the `AnteHandler` will check that the `gas` provided + has enough funds to pay for said fees. Note that no precise [`gas`](../basics/gas-fees.md) counting occurs here, + as `message`s are not processed. Usually, the [`AnteHandler`](../basics/gas-fees.md#antehandler) will check that the `gas` provided with the transaction is superior to a minimum reference gas amount based on the raw transaction size, in order to avoid spam with transactions that provide 0 gas. 4. Ensure that a [`Route`](#message-routing) exists for each `message`, but do **not** actually process `message`s. `Message`s only need to be processed when the canonical state need to be updated, which happens during `DeliverTx`. -Steps 2. and 3. are performed by the `AnteHandler` in the [`RunTx()`](<#runtx()-,antehandler-and-runmsgs()>) +Steps 2. and 3. are performed by the [`AnteHandler`](../basics/gas-fees.md#antehandler) in the [`RunTx()`](#runtx-antehandler-and-runmsgs) function, which `CheckTx()` calls with the `runTxModeCheck` mode. During each step of `CheckTx()`, a special [volatile state](#volatile-states) called `checkState` is updated. This state is used to keep track of the temporary changes triggered by the `CheckTx()` calls of each transaction without modifying @@ -279,13 +249,14 @@ is actually included in a block, because `checkState` never gets committed to th `CheckTx` returns a response to the underlying consensus engine of type [`abci.ResponseCheckTx`](https://tendermint.com/docs/spec/abci/abci.html#messages). The response contains: -- `Code (uint32)`: Response Code. `0` if successful. +- `Code (uint32)`: Response Code. `0` if successful. - `Data ([]byte)`: Result bytes, if any. - `Log (string):` The output of the application's logger. May be non-deterministic. - `Info (string):` Additional information. May be non-deterministic. -- `GasWanted (int64)`: Amount of gas requested for transaction. It is provided by users when they generate the transaction. -- `GasUsed (int64)`: Amount of gas consumed by transaction. During `CheckTx`, this value is computed by multiplying the standard cost of a transaction byte by the size of the raw transaction (click [here](https://github.com/cosmos/cosmos-sdk/blob/master/x/auth/ante.go#L101) for an example). -- `Events ([]Event)`: Key-Value events for filtering and indexing transactions (eg. by account or message type). +- `GasWanted (int64)`: Amount of gas requested for transaction. It is provided by users when they generate the transaction. +- `GasUsed (int64)`: Amount of gas consumed by transaction. During `CheckTx`, this value is computed by multiplying the standard cost of a transaction byte by the size of the raw transaction. Next is an example: + +++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/x/auth/ante/basic.go#L104 +- `Events ([]cmn.KVPair)`: Key-Value tags for filtering and indexing transactions (eg. by account). See [`event`s](./events.md) for more. - `Codespace (string)`: Namespace for the Code. #### RecheckTx @@ -301,57 +272,69 @@ This allows certain checks like signature verification can be skipped during `Ch When the underlying consensus engine receives a block proposal, each transaction in the block needs to be processed by the application. To that end, the underlying consensus engine sends a `DeliverTx` message to the application for each transaction in a sequential order. -Before the first transaction of a given block is processed, a [volatile state](#volatile-states) called `deliverState` is initialized during [`BeginBlock`](#beginblock). This state is updated each time a transaction is processed via `DeliverTx()`, and committed to the [main state](#main-state) when the block is [committed](#commit), after what is is set to `nil`. +Before the first transaction of a given block is processed, a [volatile state](#volatile-states) called `deliverState` is intialized during [`BeginBlock`](#beginblock). This state is updated each time a transaction is processed via `DeliverTx`, and committed to the [main state](#main-state) when the block is [committed](#commit), after what is is set to `nil`. `DeliverTx` performs the **exact same steps as `CheckTx`**, with a little caveat at step 3 and the addition of a fifth step: 1. The `AnteHandler` does **not** check that the transaction's `gas-prices` is sufficient. That is because the `min-gas-prices` value `gas-prices` is checked against is local to the node, and therefore what is enough for one full-node might not be for another. This means that the proposer can potentially include transactions for free, although they are not incentivised to do so, as they earn a bonus on the total fee of the block they propose. -2. For each `message` in the transaction, route to the appropriate module's `handler`. Additional _stateful_ checks are performed, and the cache-wrapped multistore held in `deliverState`'s `context` is updated by the module's `keeper`. If the `handler` returns successfully, the cache-wrapped multistore held in `context` is written to `deliverState` `CacheMultiStore`. +2. For each `message` in the transaction, route to the appropriate module's [`handler`](../building-modules/handler.md). Additional _stateful_ checks are performed, and the cache-wrapped multistore held in `deliverState`'s `context` is updated by the module's `keeper`. If the `handler` returns successfully, the cache-wrapped multistore held in `context` is written to `deliverState` `CacheMultiStore`. + +During step 5., each read/write to the store increases the value of `GasConsumed`. You can find the default cost of each operation: + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/store/types/gas.go#L142-L150 -During step 5., each read/write to the store increases the value of `GasConsumed`. You can find the default cost of each operation [here](https://github.com/cosmos/cosmos-sdk/blob/master/store/types/gas.go#L142-L150). At any point, if `GasConsumed > GasWanted`, the function returns with `Code != 0` and `DeliverTx()` fails. +At any point, if `GasConsumed > GasWanted`, the function returns with `Code != 0` and `DeliverTx` fails. -`DeliverTx` returns a response to the underlying consensus engine of type [`abci.ResponseCheckTx`](https://tendermint.com/docs/spec/abci/abci.html#messages). The response contains: +`DeliverTx` returns a response to the underlying consensus engine of type [`abci.ResponseDeliverTx`](https://tendermint.com/docs/spec/abci/abci.html#delivertx). The response contains: -- `Code (uint32)`: Response Code. `0` if successful. +- `Code (uint32)`: Response Code. `0` if successful. - `Data ([]byte)`: Result bytes, if any. - `Log (string):` The output of the application's logger. May be non-deterministic. - `Info (string):` Additional information. May be non-deterministic. -- `GasWanted (int64)`: Amount of gas requested for transaction. It is provided by users when they generate the transaction. -- `GasUsed (int64)`: Amount of gas consumed by transaction. During `DeliverTx`, this value is computed by multiplying the standard cost of a transaction byte by the size of the raw transaction (click [here](https://github.com/cosmos/cosmos-sdk/blob/master/x/auth/ante.go#L101) for an example), and by adding gas each time a read/write to the store occurs. -- `Tags ([]cmn.KVPair)`: Key-Value tags for filtering and indexing transactions (eg. by account). +- `GasWanted (int64)`: Amount of gas requested for transaction. It is provided by users when they generate the transaction. +- `GasUsed (int64)`: Amount of gas consumed by transaction. During `DeliverTx`, this value is computed by multiplying the standard cost of a transaction byte by the size of the raw transaction, and by adding gas each time a read/write to the store occurs. +- `Events ([]cmn.KVPair)`: Key-Value tags for filtering and indexing transactions (eg. by account). See [`event`s](./events.md) for more. - `Codespace (string)`: Namespace for the Code. ## RunTx, AnteHandler and RunMsgs ### RunTx -`RunTx()` is called from `CheckTx()`/`DeliverTx()` to handle the transaction, with `runTxModeCheck` or `runTxModeDeliver` as parameter to differentiate between the two modes of execution. Note that when `RunTx()` receives a transaction, it has already been decoded. +`RunTx` is called from `CheckTx`/`DeliverTx` to handle the transaction, with `runTxModeCheck` or `runTxModeDeliver` as parameter to differentiate between the two modes of execution. Note that when `RunTx` receives a transaction, it has already been decoded. -The first thing `RunTx()` does upon being called is to retrieve the `context`'s `CacheMultiStore` by calling the `getContextForTx()` function with the appropriate mode (either `runTxModeCheck` or `runTxModeDeliver`). This `CacheMultiStore` is a cached version of the main store instantiated during `BeginBlock` for `DeliverTx` and during the `Commit` of the previous block for `CheckTx`. After that, two `defer func()` are called for `gas` management. They are executed when `RunTx()` returns and make sure `gas` is actually consumed, and will throw errors, if any. +The first thing `RunTx` does upon being called is to retrieve the `context`'s `CacheMultiStore` by calling the `getContextForTx()` function with the appropriate mode (either `runTxModeCheck` or `runTxModeDeliver`). This `CacheMultiStore` is a cached version of the main store instantiated during `BeginBlock` for `DeliverTx` and during the `Commit` of the previous block for `CheckTx`. After that, two `defer func()` are called for [`gas`](../basics/gas-fees.md) management. They are executed when `runTx` returns and make sure `gas` is actually consumed, and will throw errors, if any. After that, `RunTx()` calls `ValidateBasic()` on each `message`in the `Tx`, which runs preliminary _stateless_ validity checks. If any `message` fails to pass `ValidateBasic()`, `RunTx()` returns with an error. -Then, the [`anteHandler`](#antehandler) of the application is run (if it exists). In preparation of this step, both the `checkState`/`deliverState`'s `context` and `context`'s `CacheMultiStore` are cached-wrapped using the [`cacheTxContext()`](https://github.com/cosmos/cosmos-sdk/blob/master/baseapp/baseapp.go#L781-L798) function. This allows `RunTx()` not to commit the changes made to the state during the execution of `anteHandler` if it ends up failing. It also prevents the module implementing the `anteHandler` from writing to state, which is an important part of the [object-capabilities](./ocap.md) of the Cosmos SDK. +Then, the [`anteHandler`](#antehandler) of the application is run (if it exists). In preparation of this step, both the `checkState`/`deliverState`'s `context` and `context`'s `CacheMultiStore` are cached-wrapped using the `cacheTxContext()` function. + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/baseapp/baseapp.go#L587 + +This allows `RunTx` not to commit the changes made to the state during the execution of `anteHandler` if it ends up failing. It also prevents the module implementing the `anteHandler` from writing to state, which is an important part of the [object-capabilities](./ocap.md) of the Cosmos SDK. Finally, the [`RunMsgs()`](#runmsgs) function is called to process the `messages`s in the `Tx`. In preparation of this step, just like with the `anteHandler`, both the `checkState`/`deliverState`'s `context` and `context`'s `CacheMultiStore` are cached-wrapped using the `cacheTxContext()` function. ### AnteHandler -The `AnteHandler` is a special handler that implements the [`anteHandler` interface](https://github.com/cosmos/cosmos-sdk/blob/master/types/handler.go#L8) and is used to authenticate the transaction before the transaction's internal messages are processed. +The `AnteHandler` is a special handler that implements the `anteHandler` interface and is used to authenticate the transaction before the transaction's internal messages are processed. + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/handler.go#L8 The `AnteHandler` is theoretically optional, but still a very important component of public blockchain networks. It serves 3 primary purposes: -- Be a primary line of defense against spam and second line of defense (the first one being the mempool) against transaction replay with fees deduction and `sequence`checking. -- Perform preliminary _stateful_ validity checks like ensuring signatures are valid or that the sender has enough funds to pay for fees. -- Play a role in the incentivisation of stakeholders via the collection of transaction fees. +- Be a primary line of defense against spam and second line of defense (the first one being the mempool) against transaction replay with fees deduction and [`sequence`](./transactions.md#transaction-generation) checking. +- Perform preliminary *stateful* validity checks like ensuring signatures are valid or that the sender has enough funds to pay for fees. +- Play a role in the incentivisation of stakeholders via the collection of transaction fees. + +`baseapp` holds an `anteHandler` as paraemter, which is initialized in the [application's constructor](../basics/app-anatomy.md#application-constructor). The most widely used `anteHandler` today is that of the [`auth` module](https://github.com/cosmos/cosmos-sdk/blob/master/x/auth/ante/ante.go). -`baseapp` holds an `anteHandler` as parameter, which is initialized in the [application's constructor](../basics/app-anatomy.md#application-constructor). The most widely used `anteHandler` today is that of the [`auth` module](https://github.com/cosmos/cosmos-sdk/blob/master/x/auth/ante.go). +Click [here](../basics/gas-fees.md#antehandler) for more on the `anteHandler`. ### RunMsgs -`RunMsgs()` is called from `RunTx()` with `runTxModeCheck` as parameter to check the existence of a route for each message contained in the transaction, and with `runTxModeDeliver` to actually process the `message`s. +`RunMsgs` is called from `RunTx` with `runTxModeCheck` as parameter to check the existence of a route for each message the transaction, and with `runTxModeDeliver` to actually process the `message`s. -First, it retrieves the `message`'s `route` using the `Msg.Route()` method. Then, using the application's [`router`](#routing) and the `route`, it checks for the existence of a `handler`. At this point, if `mode == runTxModeCheck`, `RunMsgs()` returns. If instead `mode == runTxModeDeliver`, the `handler` function for the message is executed, before `RunMsgs()` returns. +First, it retreives the `message`'s `route` using the `Msg.Route()` method. Then, using the application's [`router`](#routing) and the `route`, it checks for the existence of a `handler`. At this point, if `mode == runTxModeCheck`, `RunMsgs` returns. If instead `mode == runTxModeDeliver`, the [`handler`](../building-modules/handler.md) function for the message is executed, before `RunMsgs` returns. ## Other ABCI Messages @@ -359,44 +342,50 @@ First, it retrieves the `message`'s `route` using the `Msg.Route()` method. Then The [`InitChain` ABCI message](https://tendermint.com/docs/app-dev/abci-spec.html#initchain) is sent from the underlying Tendermint engine when the chain is first started. It is mainly used to **initialize** parameters and state like: -- [Consensus Parameters](https://tendermint.com/docs/spec/abci/apps.html#consensus-parameters) via `setConsensusParams`. +- [Consensus Parameters](https://tendermint.com/docs/spec/abci/apps.html#consensus-parameters) via `setConsensusParams`. - [`checkState` and `deliverState`](#volatile-states) via `setCheckState` and `setDeliverState`. -- The block gas meter, with infinite gas to process genesis transactions. +- The [block gas meter](../basics/gas-fees.md#block-gas-meter), with infinite gas to process genesis transactions. -Finally, the `InitChain(req abci.RequestInitChain)` method of `baseapp` calls the [`initChainer()`](../basics/app-anatomy.md#initchainer) of the application in order to initialize the main state of the application from the [`genesis file`](./genesis.md) and, if defined, call the `InitGenesis` function of each of the application's modules. +Finally, the `InitChain(req abci.RequestInitChain)` method of `baseapp` calls the [`initChainer()`](../basics/app-anatomy.md#initchainer) of the application in order to initialize the main state of the application from the `genesis file` and, if defined, call the [`InitGenesis`](../building-modules/genesis.md#initgenesis) function of each of the application's modules. ### BeginBlock The [`BeginBlock` ABCI message](#https://tendermint.com/docs/app-dev/abci-spec.html#beginblock) is sent from the underlying Tendermint engine when a block proposal created by the correct proposer is received, before [`DeliverTx`](#delivertx) is run for each transaction in the block. It allows developers to have logic be executed at the beginning of each block. In the Cosmos SDK, the `BeginBlock(req abci.RequestBeginBlock)` method does the following: -- Initialize [`deliverState`](#volatile-states) with the latest header using the `req abci.RequestBeginBlock` passed as parameter via the [`setDeliverState`](https://github.com/cosmos/cosmos-sdk/blob/master/baseapp/baseapp.go#L283-L289) function. -- Initialize the block gas meter with the `maxGas` limit. The `gas` consumed within the block cannot go above `maxGas`. This parameter is defined in the application's consensus parameters. -- Run the application's [`begingBlocker()`](../basics/app-anatomy.md#beginblocker-and-endblock), which mainly runs the `BeginBlocker()` method of each of the application's modules. -- Set the [`VoteInfos`](https://tendermint.com/docs/app-dev/abci-spec.html#voteinfo) of the application, i.e. the list of validators whose _precommit_ for the previous block was included by the proposer of the current block. This information is carried into the [`Context`](./context.md) so that it can be used during `DeliverTx` and `EndBlock`. +- Initialize [`deliverState`](#volatile-states) with the latest header using the `req abci.RequestBeginBlock` passed as parameter via the `setDeliverState` function. + +++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/baseapp/baseapp.go#L387-L397 +This function also resets the [main gas meter](../basics/gas-fees.md#main-gas-meter). +- Initialize the [block gas meter](../basics/gas-fees.md#block-gas-meter) with the `maxGas` limit. The `gas` consumed within the block cannot go above `maxGas`. This parameter is defined in the application's consensus parameters. +- Run the application's [`beginBlocker()`](../basics/app-anatomy.md#beginblocker-and-endblock), which mainly runs the [`BeginBlocker()`](../building-modules/beginblock-endblock.md#beginblock) method of each of the application's modules. +- Set the [`VoteInfos`](https://tendermint.com/docs/app-dev/abci-spec.html#voteinfo) of the application, i.e. the list of validators whose *precommit* for the previous block was included by the proposer of the current block. This information is carried into the [`Context`](./context.md) so that it can be used during `DeliverTx` and `EndBlock`. ### EndBlock -The [`EndBlock` ABCI message](#https://tendermint.com/docs/app-dev/abci-spec.html#endblock) is sent from the underlying Tendermint engine after [`DeliverTx`](#delivertx) as been run for each transaction n the block. It allows developers to have logic be executed at the end of each block. In the Cosmos SDK, the bulk `EndBlock(req abci.RequestEndBlock)` method is to run the application's [`endBlocker()`](../basics/app-anatomy.md#beginblocker-and-endblock), which mainly runs the `EndBlocker()` method of each of the application's modules. +The [`EndBlock` ABCI message](#https://tendermint.com/docs/app-dev/abci-spec.html#endblock) is sent from the underlying Tendermint engine after [`DeliverTx`](#delivertx) as been run for each transaction in the block. It allows developers to have logic be executed at the end of each block. In the Cosmos SDK, the bulk `EndBlock(req abci.RequestEndBlock)` method is to run the application's [`EndBlocker()`](../basics/app-anatomy.md#beginblocker-and-endblock), which mainly runs the [`EndBlocker()`](../building-modules/beginblock-endblock.md#beginblock) method of each of the application's modules. ### Commit -The [`Commit` ABCI message](https://tendermint.com/docs/app-dev/abci-spec.html#commit) is sent from the underlying Tendermint engine after the full-node has received _precommits_ from 2/3+ of validators (weighted by voting power). On the `baseapp` end, the `Commit(res abci.ResponseCommit)` function is implemented to commit all the valid state transitions that occured during `BeginBlock()`, `DeliverTx()` and `EndBlock()` and to reset state for the next block. +The [`Commit` ABCI message](https://tendermint.com/docs/app-dev/abci-spec.html#commit) is sent from the underlying Tendermint engine after the full-node has received *precommits* from 2/3+ of validators (weighted by voting power). On the `baseapp` end, the `Commit(res abci.ResponseCommit)` function is implemented to commit all the valid state transitions that occured during `BeginBlock`, `DeliverTx` and `EndBlock` and to reset state for the next block. -To commit state-transitions, the `Commit` function calls the `Write()` function on `deliverState.ms`, where `deliverState.ms` is a cached multistore of the main store `app.cms`. Then, the `Commit` function sets `checkState` to the latest header (obtained from `deliverState.ctx.BlockHeader`) and `deliverState` to `nil`. +To commit state-transitions, the `Commit` function calls the `Write()` function on `deliverState.ms`, where `deliverState.ms` is a cached multistore of the main store `app.cms`. Then, the `Commit` function sets `checkState` to the latest header (obtbained from `deliverState.ctx.BlockHeader`) and `deliverState` to `nil`. -Finally, `Commit` returns the hash of the commitment of `app.cms` back to the underlying consensus engine. This hash is used as a reference in the header of the next block. +Finally, `Commit` returns the hash of the commitment of `app.cms` back to the underlying consensus engine. This hash is used as a reference in the header of the next block. ### Info -The [`Info` ABCI message](https://tendermint.com/docs/app-dev/abci-spec.html#info) is a simple query from the underlying consensus engine, notably used to sync the latter with the application during a handshake that happens on startup. When called, the `Info(res abci.ResponseInfo)` function from `baseapp` will return the application's name, version and the hash of the last commit of `app.cms`. +The [`Info` ABCI message](https://tendermint.com/docs/app-dev/abci-spec.html#info) is a simple query from the underlying consensus engine, notably used to sync the latter with the application during a handshake that happens on startup. When called, the `Info(res abci.ResponseInfo)` function from `baseapp` will return the application's name, version and the hash of the last commit of `app.cms`. -### Query +### Query -The [`Query` ABCI message](https://tendermint.com/docs/app-dev/abci-spec.html#query) is used to serve queries received from the underlying consensus engine, including queries received via RPC like Tendermint RPC. It is the main entrypoint to build interfaces with the application. The application must respect a few rules when implementing the `Query` method, which are outlined [here](https://tendermint.com/docs/app-dev/abci-spec.html#query). +The [`Query` ABCI message](https://tendermint.com/docs/app-dev/abci-spec.html#query) is used to serve queries received from the underlying consensus engine, including queries received via RPC like Tendermint RPC. It is the main entrypoint to build interfaces with the application. The application must respect a few rules when implementing the `Query` method, which are outlined [here](https://tendermint.com/docs/app-dev/abci-spec.html#query). -The `baseapp` implementation of the `Query(req abci.RequestQuery)` method is a simple dispatcher serving 4 main categories of queries: +Each `query` comes with a `path`, which contains multiple `string`s. By convention, the first element of the `path` (`path[0]`) contains the category of `query` (`app`, `p2p`, `store` or `custom`). The `baseapp` implementation of the `Query(req abci.RequestQuery)` method is a simple dispatcher serving these 4 main categories of queries: - Application-related queries like querying the application's version, which are served via the `handleQueryApp` method. -- Direct queries to the multistore, which are served by the `handlerQueryStore` method. These direct queries are different from custom queries which go through `app.queryRouter`, and are mainly used by third-party service provider like block explorers. +- Direct queries to the multistore, which are served by the `handlerQueryStore` method. These direct queryeis are different from custom queries which go through `app.queryRouter`, and are mainly used by third-party service provider like block explorers. - P2P queries, which are served via the `handleQueryP2P` method. These queries return either `app.addrPeerFilter` or `app.ipPeerFilter` that contain the list of peers filtered by address or IP respectively. These lists are first initialized via `options` in `baseapp`'s [constructor](#constructor). - Custom queries, which encompass most queries, are served via the `handleQueryCustom` method. The `handleQueryCustom` cache-wraps the multistore before using the `queryRoute` obtained from [`app.queryRouter`](#query-routing) to map the query to the appropriate module's `querier`. + +## Next {hide} + +Learn more about [transactions](./transactions.md) {hide} \ No newline at end of file diff --git a/docs/core/context.md b/docs/core/context.md new file mode 100644 index 000000000000..e501834a911f --- /dev/null +++ b/docs/core/context.md @@ -0,0 +1,117 @@ +--- +order: 3 +synopsis: The `context` is a data structure intended to be passed from function to function that carries information about the current state of the application. It holds a cached copy of the entire state as well as useful objects and information like `gasMeter`, `block height`, `consensus parameters` and more. +--- + +# Context + +## Pre-requisites Readings {hide} + +- [Anatomy of an SDK Application](../basics/app-anatomy.md) {prereq} +- [Lifecycle of a Transaction](../basics/tx-lifecycle.md) {prereq} + +## Context Definition + +The SDK `Context` is a custom data structure that contains Go's stdlib [`context`](https://golang.org/pkg/context) as its base, and has many additional types within its definition that are specific to the Cosmos SDK. he `Context` is integral to transaction processing in that it allows modules to easily access their respective [store](./store.md#base-layer-kvstores) in the [`multistore`](./store.md#multistore) and retrieve transactional context such as the block header and gas meter. + +```go +type Context struct { + ctx context.Context + ms MultiStore + header abci.Header + chainID string + txBytes []byte + logger log.Logger + voteInfo []abci.VoteInfo + gasMeter GasMeter + blockGasMeter GasMeter + checkTx bool + minGasPrice DecCoins + consParams *abci.ConsensusParams + eventManager *EventManager +} +``` + +- **Context:** The base type is a Go [Context](https://golang.org/pkg/context), which is explained further in the [Go Context Package](#go-context-package) section below. +- **Multistore:** Every application's `BaseApp` contains a [`CommitMultiStore`](./store.md#multistore) which is provided when a `Context` is created. Calling the `KVStore()` and `TransientStore()` methods allows modules to fetch their respective [`KVStore`](./store.md#base-layer-kvstores) using their unique `StoreKey`. +- **ABCI Header:** The [header](https://tendermint.com/docs/spec/abci/abci.html#header) is an ABCI type. It carries important information about the state of the blockchain, such as block height and proposer of the current block. +- **Chain ID:** The unique identification number of the blockchain a block pertains to. +- **Transaction Bytes:** The `[]byte` representation of a transaction being processed using the context. Every transaction is processed by various parts of the SDK and consensus engine (e.g. Tendermint) throughout its [lifecycle](../basics/tx-lifecycle.md), some of which to not have any understanding of transaction types. Thus, transactions are marshaled into the generic `[]byte` type using some kind of [encoding format](./encoding.md) such as [Amino](./encoding.md). +- **Logger:** A `logger` from the Tendermint libraries. Learn more about logs [here](https://tendermint.com/docs/tendermint-core/how-to-read-logs.html#how-to-read-logs). Modules call this method to create their own unique module-specific logger. +- **VoteInfo:** A list of the ABCI type [`VoteInfo`](https://tendermint.com/docs/spec/abci/abci.html#voteinfo), which includes the name of a validator and a boolean indicating whether they have signed the block. +- **Gas Meters:** Specifically, a [`gasMeter`](../basics/gas-fees.md#main-gas-meter) for the transaction currently being processed using the context and a [`blockGasMeter`](../basics/gas-fees.md#block-gas-meter) for the entire block it belongs to. Users specify how much in fees they wish to pay for the execution of their transaction; these gas meters keep track of how much [gas](../basics/gas-fees.md) has been used in the transaction or block so far. If the gas meter runs out, execution halts. +- **CheckTx Mode:** A boolean value indicating whether a transaction should be processed in `CheckTx` or `DeliverTx` mode. +- **Min Gas Price:** The minimum [gas](../basics/gas-fees.md) price a node is willing to take in order to include a transaction in its block. This price is a local value configured by each node individually, and should therefore **not be used in any functions used in sequences leading to state-transitions**. +- **Consensus Params:** The ABCI type [Consensus Parameters](https://tendermint.com/docs/spec/abci/apps.html#consensus-parameters), which specify certain limits for the blockchain, such as maximum gas for a block. +- **Event Manager:** The event manager allows any caller with access to a `Context` to emit [`Events`](./events.md). Modules may define module specific +`Events` by defining various `Types` and `Attributes` or use the common definitions found in `types/`. Clients can subscribe or query for these `Events`. These `Events` are collected throughout `DeliverTx`, `BeginBlock`, and `EndBlock` and are returned to Tendermint for indexing. For example: + +```go +ctx.EventManager().EmitEvent(sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory)), +) +``` + +## Go Context Package + +A basic `Context` is defined in the [Golang Context Package](https://golang.org/pkg/context). A `Context` +is an immutable data structure that carries request-scoped data across APIs and processes. Contexts +are also designed to enable concurrency and to be used in goroutines. + +Contexts are intended to be **immutable**; they should never be edited. Instead, the convention is +to create a child context from its parent using a `With` function. For example: + +``` go +childCtx = parentCtx.WithBlockHeader(header) +``` + +The [Golang Context Package](https://golang.org/pkg/context) documentation instructs developers to +explicitly pass a context `ctx` as the first argument of a process. + +## Cache Wrapping + +The `Context` contains a `MultiStore`, which allows for cache-wrapping functionality: a `CacheMultiStore` +where each `KVStore` is is wrapped with an ephemeral cache. Processes are free to write changes to +the `CacheMultiStore`, then write the changes back to the original state or disregard them if something +goes wrong. The pattern of usage for a Context is as follows: + +1. A process receives a Context `ctx` from its parent process, which provides information needed to + perform the process. +2. The `ctx.ms` is **cache wrapped**, i.e. a cached copy of the [multistore](./store.md#multistore) is made so that the process can make changes to the state as it executes, without changing the original`ctx.ms`. This is useful to protect the underlying multistore in case the changes need to be reverted at some point in the execution. +3. The process may read and write from `ctx` as it is executing. It may call a subprocess and pass +`ctx` to it as needed. +4. When a subprocess returns, it checks if the result is a success or failure. If a failure, nothing +needs to be done - the cache wrapped `ctx` is simply discarded. If successful, the changes made to +the cache-wrapped `MultiStore` can be committed to the original `ctx.ms` via `Write()`. + +For example, here is a snippet from the [`runTx`](./baseapp.md#runtx-and-runmsgs) function in +[`baseapp`](./baseapp.md): + +```go +runMsgCtx, msCache := app.cacheTxContext(ctx, txBytes) +result = app.runMsgs(runMsgCtx, msgs, mode) +result.GasWanted = gasWanted + +if mode != runTxModeDeliver { + return result +} + +if result.IsOK() { + msCache.Write() +} +``` + +Here is the process: + +1. Prior to calling `runMsgs` on the message(s) in the transaction, it uses `app.cacheTxContext()` +to cache-wrap the context and multistore. +2. The cache-wrapped context, `runMsgCtx`, is used in `runMsgs` to return a result. +3. If the process is running in [`checkTxMode`](./baseapp.md#checktx), there is no need to write the +changes - the result is returned immediately. +4. If the process is running in [`deliverTxMode`](./baseapp.md#delivertx) and the result indicates +a successful run over all the messages, the cached multistore is written back to the original. + +## Next {hide} + +Learn about the [node client](./node.md) {hide} diff --git a/docs/core/encoding.md b/docs/core/encoding.md new file mode 100644 index 000000000000..caf445511799 --- /dev/null +++ b/docs/core/encoding.md @@ -0,0 +1,44 @@ +--- +order: 6 +synopsis: The `codec` is used everywhere in the Cosmos SDK to encode and decode structs and interfaces. The specific codec used in the Cosmos SDK is called `go-amino` +--- + +# Encoding + +## Pre-requisite Readings {hide} + +- [Anatomy of an SDK application](../basics/app-anatomy.md) {prereq} + +## Encoding + +Every Cosmos SDK application exposes a global `codec` to marshal/unmarshal structs and interfaces in order to store and/or transfer them. As of now, the `codec` used in the Cosmos SDK is [go-amino](https://github.com/tendermint/go-amino), which possesses the following important properties: + +- Interface support. +- Deterministic encoding of value (which is required considering that blockchains are deterministic replicated state-machines). +- Upgradeable schemas. + +The application's `codec` is typically initialized in the [application's constructor function](../basics/app-anatomy.md#constructor-function), where it is also passed to each of the application's modules via the [basic manager](../building-modules/module-manager.md#basic-manager). + +Among other things, the `codec` is used by module's [`keeper`s](../building-modules/keeper.md) to marshal objects into `[]byte` before storing them in the module's [`KVStore`](./store.md#kvstore), or to unmarshal them from `[]byte` when retrieving them: + +```go +// typical pattern to marshal an object to []byte before storing it +bz := keeper.cdc.MustMarshalBinaryBare(object) + +//typical pattern to unmarshal an object from []byte when retrieving it +keeper.cdc.MustUnmarshalBinaryBare(bz, &object) +``` + +Alternatively, it is possible to use `MustMarshalBinaryLengthPrefixed`/`MustUnmarshalBinaryLengthPrefixed` instead of `MustMarshalBinaryBare`/`MustUnmarshalBinaryBare` for the same encoding prefixed by a `uvarint` encoding of the object to encode. + +Another important use of the `codec` is the encoding and decoding of [transactions](./transactions.md). Transactions are defined at the Cosmos SDK level, but passed to the underlying consensus engine in order to be relayed to other peers. Since the underlying consensus engine is agnostic to the application, it only accepts transactions in the form of `[]byte`. The encoding is done by an object called `TxEncoder` and the decoding by an object called `TxDecoder`. + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/tx_msg.go#L45-L49 + +A standard implementation of both these objects can be found in the [`auth` module](https://github.com/cosmos/cosmos-sdk/blob/master/x/auth): + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/x/auth/types/stdtx.go#L241-L266 + +## Next {hide} + +Learn about [events](./events.md) {hide} \ No newline at end of file diff --git a/docs/core/events.md b/docs/core/events.md new file mode 100644 index 000000000000..b9eabb3161ae --- /dev/null +++ b/docs/core/events.md @@ -0,0 +1,91 @@ +--- +order: 7 +synopsis: "`Event`s are objects that contain information about the execution of the application. They are mainly used by service providers like block explorers and wallet to track the execution of various messages and index transactions." +--- + +# Events + +## Pre-Requisite Readings {hide} + +- [Anatomy of an SDK application](../basics/app-anatomy.md) {prereq} + +## Events + +`Event`s are implemented in the Cosmos SDK as an alias of the ABCI `event` type. + ++++ https://github.com/tendermint/tendermint/blob/bc572217c07b90ad9cee851f193aaa8e9557cbc7/abci/types/types.pb.go#L2661-L2667 + +They contain: + +- A **`type`** of type `string`, which can refer to the type of action that led to the `event`'s emission (e.g. a certain value going above a threshold), or to the type of `message` if the event is triggered at the end of that `message` processing. +- A list of `attributes`, which are key-value pairs that give more information about the `event`. + +++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/events.go#L51-L56 + +`Event`s are returned to the underlying consensus engine in the response of the following ABCI messages: [`CheckTx`](./baseapp.md#checktx), [`DeliverTx`](./baseapp.md#delivertx), [`BeginBlock`](./baseapp.md#beginblock) and [`EndBlock`](./baseapp.md#endblock). + +Typically, `event` `type`s and `attributes` are defined on a **per-module basis** in the module's `/internal/types/events.go` file, and triggered from the module's [`handler`](../building-modules/handler.md) via the [`EventManager`](#eventmanager). + +## EventManager + +In Cosmos SDK applications, `event`s are generally managed by an object called the `EventManager`. It is implemented as a simple wrapper around a slice of `event`s: + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/events.go#L16-L20 + +The `EventManager` comes with a set of useful methods to manage `event`s. Among them, the one that is used the most by module and application developers is the `EmitEvent` method, which registers an `event` in the `EventManager`. + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/events.go#L29-L31 + +Typically, module developers will implement event emission via the `EventManager` in the [`handler`](../building-modules/handler.md) of modules, as well as in the [`BeginBlocker` and/or`EndBlocker` functions](../building-modules/beginblock-endblock.md). The `EventManager` is accessed via the context [`ctx`](./context.md), and event emission generally follows this pattern: + +```go +ctx.EventManager().EmitEvent( + sdk.NewEvent( + eventType, // e.g. sdk.EventTypeMessage for a message, types.CustomEventType for a custom event defined in the module + sdk.NewAttribute(attributeKey, attributeValue), + ), + ) +``` + +See the [`handler` concept doc](../building-modules/handler.md) for a more detailed view on how to typically implement `events` and use the `EventManager` in modules. + +## Subscribing to `events` + +It is possible to subscribe to `events` via [Tendermint's Websocket](https://tendermint.com/docs/app-dev/subscribing-to-events-via-websocket.html#subscribing-to-events-via-websocket). This is done by calling the `subscribe` RPC method via Websocket: + +``` +{ + "jsonrpc": "2.0", + "method": "subscribe", + "id": "0", + "params": { + "query": "tm.event='eventCategory' AND type.attribute='attributeValue'" + } +} +``` + +The main `eventCategory` you can subscribe to are: + +- `NewBlock`: Contains `events` triggered during `BeginBlock` and `EndBlock`. +- `Tx`: Contains `events` triggered during `DeliverTx` (i.e. transaction processing). +- `ValidatorSetUpdates`: Contains validator set updates for the block. + +These events are triggered from the `state` package after a block is committed. You can get the full list of `event` categories [here](https://godoc.org/github.com/tendermint/tendermint/types#pkg-constants). + +The `type` and `attribute` value of the `query` allow you to filter the specific `event` you are looking for. For example, a `transfer` transaction triggers an `event` of type `Transfer` and has `Recipient` and `Sender` as `attributes` (as defined in the [`events` file of the `bank` module](https://github.com/cosmos/cosmos-sdk/blob/master/x/bank/internal/types/events.go)). Subscribing to this `event` would be done like so: + +``` +{ + "jsonrpc": "2.0", + "method": "subscribe", + "id": "0", + "params": { + "query": "tm.event='Tx' AND transfer.sender='senderAddress'" + } +} +``` + +where `senderAddress` is an address following the [`AccAddress`](../basics/accounts.md#addresses) format. + +## Next {hide} + +Learn about [object-capabilities](./ocap.md) {hide} \ No newline at end of file diff --git a/docs/core/node.md b/docs/core/node.md new file mode 100644 index 000000000000..5da50d6080a4 --- /dev/null +++ b/docs/core/node.md @@ -0,0 +1,70 @@ +--- +order: 4 +synopsis: The main endpoint of an SDK application is the daemon client, otherwise known as the full-node client. The full-node runs the state-machine, starting from a genesis file. It connects to peers running the same client in order to receive and relay transactions, block proposals and signatures. The full-node is constituted of the application, defined with the Cosmos SDK, and of a consensus engine connected to the application via the ABCI. +--- + +# Node Client (Daemon) + +## Pre-requisite Readings {hide} + +- [Anatomy of an SDK application](../basics/app-anatomy.md) {prereq} + +## `main` function + +The full-node client of any SDK application is built by running a `main` function. The client is generally named by appending the `-d` suffix to the application name (e.g. `appd` for an application named `app`), and the `main` function is defined in a `./cmd/appd/main.go` file. Running this function creates an executable `.appd` that comes with a set of commands. For an app named `app`, the main command is [`appd start`](#start-command), which starts the full-node. + +In general, developers will implement the `main.go` function with the following structure: + +- First, a [`codec`](./encoding.md) is instanciated for the application. +- Then, the `config` is retrieved and config parameters are set. This mainly involves setting the bech32 prefixes for [addresses and pubkeys](../basics/accounts.md#addresses-and-pubkeys). + +++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/config.go#L10-L21 +- Using [cobra](https://github.com/spf13/cobra), the root command of the full-node client is created. After that, all the custom commands of the application are added using the `AddCommand()` method of `rootCmd`. +- Add default server commands to `rootCmd` using the `server.AddCommands(ctx, cdc, rootCmd, newApp, exportAppStateAndTMValidators)` method. These commands are separated from the ones added above since they are standard and defined at SDK level. They should be shared by all SDK-based applications. They include the most important command: the [`start` command](#start-command). +- Prepare and execute the `executor`. + +++ https://github.com/tendermint/tendermint/blob/bc572217c07b90ad9cee851f193aaa8e9557cbc7/libs/cli/setup.go#L75-L78 + +See an example of `main` function from the [`gaia`](https://github.com/cosmos/gaia) application: + ++++ https://github.com/cosmos/gaia/blob/f41a660cdd5bea173139965ade55bd25d1ee3429/cmd/gaiad/main.go + +## `start` command + +The `start` command is defined in the `/server` folder of the Cosmos SDK. It is added to the root command of the full-node client in the [`main` function](#main-function) and called by the end-user to start their node: + +```go +// For an example app named "app", the following command starts the full-node + +appd start +``` + +As a reminder, the full-node is composed of three conceptual layers: the networking layer, the consensus layer and the application layer. The first two are generally bundled together in an entity called the consensus engine (Tendermint Core by default), while the third is the state-machine defined with the help of the Cosmos SDK. Currently, the Cosmos SDK uses Tendermint as the default consensus engine, meaning the start command is implemented to boot up a Tendermint node. + +The flow of the `start` command is pretty straightforward. First, it retrieves the `config` from the `context` in order to open the `db` (a [`leveldb`](https://github.com/syndtr/goleveldb) instance by default). This `db` contains the latest known state of the application (empty if the application is started from the first time. + +With the `db`, the `start` command creates a new instance of the application using an `appCreator` function: + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/server/start.go#L144 + +Note that an `appCreator` is a function that fulfills the `AppCreator` signature. In practice, the [constructor the application](../basics/app-anatomy.md#constructor-function) is passed as the `appCreator`. + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/server/constructors.go#L17-L25 + +Then, the instance of `app` is used to instanciate a new Tendermint node: + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/server/start.go#L153-L163 + +The Tendermint node can be created with `app` because the latter satisfies the [`abci.Application` interface](https://github.com/tendermint/tendermint/blob/bc572217c07b90ad9cee851f193aaa8e9557cbc7/abci/types/application.go#L11-L26) (given that `app` extends [`baseapp`](./baseapp.md)). As part of the `NewNode` method, Tendermint makes sure that the height of the application (i.e. number of blocks since genesis) is equal to the height of the Tendermint node. The difference between these two heights should always be negative or null. If it is strictly negative, `NewNode` will replay blocks until the height of the application reaches the height of the Tendermint node. Finally, if the height of the application is `0`, the Tendermint node will call [`InitChain`](./baseapp.md#initchain) on the application to initialize the state from the genesis file. + +Once the Tendermint node is instanciated and in sync with the application, the node can be started: + +```go +if err := tmNode.Start(); err != nil { + return nil, err +} +``` + +Upon starting, the node will bootstrap its RPC and P2P server and start dialing peers. During handshake with its peers, if the node realizes they are ahead, it will query all the blocks sequentially in order to catch up. Then, it will wait for new block proposals and block signatures from validators in order to make progress. + +## Next {hide} + +Learn about the [store](./store.md) {hide} \ No newline at end of file diff --git a/docs/core/ocap.md b/docs/core/ocap.md index 8322ce4ec5dc..27e7be4a3f4e 100644 --- a/docs/core/ocap.md +++ b/docs/core/ocap.md @@ -1,13 +1,12 @@ --- -order: false +order: 8 --- # Object-Capability Model ## Intro -When thinking about security, it is good to start with a specific threat -model. Our threat model is the following: +When thinking about security, it is good to start with a specific threat model. Our threat model is the following: > We assume that a thriving ecosystem of Cosmos-SDK modules that are easy to compose into a blockchain application will contain faulty or malicious modules. @@ -67,14 +66,10 @@ var sumValue := externalModule.ComputeSumValue(*account) ``` In the Cosmos SDK, you can see the application of this principle in the -[gaia app](../gaia/app/app.go). +gaia app. -```go -// register message routes -app.Router(). - AddRoute(bank.RouterKey, bank.NewHandler(app.bankKeeper)). - AddRoute(staking.RouterKey, staking.NewHandler(app.stakingKeeper)). - AddRoute(distr.RouterKey, distr.NewHandler(app.distrKeeper)). - AddRoute(slashing.RouterKey, slashing.NewHandler(app.slashingKeeper)). - AddRoute(gov.RouterKey, gov.NewHandler(app.govKeeper)) -``` ++++ https://github.com/cosmos/gaia/blob/master/app/app.go#L197-L209 + +## Next + +Learn about [building modules](../building-modules/intro.md) {hide} \ No newline at end of file diff --git a/docs/core/store.md b/docs/core/store.md new file mode 100644 index 000000000000..9eb5e886c0bf --- /dev/null +++ b/docs/core/store.md @@ -0,0 +1,237 @@ +--- +order: 5 +synopsis: A store is a data structure that holds the state of the application. +--- + +# Store + +## Pre-requisite Readings {hide} + +- [Anatomy of an SDK application](../basics/app-anatomy.md) {prereq} + +## Introduction to SDK Stores + +The Cosmos SDK comes with a large set of stores to persist the state of applications. By default, the main store of SDK applications is a `multistore`, i.e. a store of stores. Developers can add any number of key-value stores to the multistore, depending on their application needs. The multistore exists to support the modularity of the Cosmos SDK, as it lets each module declare and manage their own subset of the state. Key-value stores in the multistore can only be accessed with a specific capability `key`, which is typically held in the [`keeper`](../building-modules/keeper.md) of the module that declared the store. + +``` ++-----------------------------------------------------+ +| | +| +--------------------------------------------+ | +| | | | +| | KVStore 1 - Manage by keeper of Module 1 | +| | | | +| +--------------------------------------------+ | +| | +| +--------------------------------------------+ | +| | | | +| | KVStore 2 - Manage by keeper of Module 2 | | +| | | | +| +--------------------------------------------+ | +| | +| +--------------------------------------------+ | +| | | | +| | KVStore 3 - Manage by keeper of Module 2 | | +| | | | +| +--------------------------------------------+ | +| | +| +--------------------------------------------+ | +| | | | +| | KVStore 4 - Manage by keeper of Module 3 | | +| | | | +| +--------------------------------------------+ | +| | +| +--------------------------------------------+ | +| | | | +| | KVStore 5 - Manage by keeper of Module 4 | | +| | | | +| +--------------------------------------------+ | +| | +| Main Multistore | +| | ++-----------------------------------------------------+ + + Application's State +``` + +### Store Interface + +At its very core, a Cosmos SDK `store` is an object that holds a `CacheWrapper` and implements a `GetStoreType()` method: + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/store/types/store.go#L12-L15 + +The `GetStoreType` is a simple method that returns the type of store, whereas a `CacheWrapper` is a simple interface that specifies cache-wrapping and `Write` methods: + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/store/types/store.go#L217-L238 + +Cache-wrapping is used ubiquitously in the Cosmos SDK and required to be implemented on every store type. A cache-wrapper creates a light snapshot of a store that can be passed around and updated without affecting the main underlying store. This is used to trigger temporary state-transitions that may be reverted later should an error occur. If a state-transition sequence is performed without issue, the cached store can be comitted to the underlying store at the end of the sequence. + +### Commit Store + +A commit store is a store that has the ability to commit changes made to the underlying tree or db. The Cosmos SDK differentiates simple stores from commit stores by extending the basic store interfaces with a `Committer`: + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/store/types/store.go#L24-L28 + +The `Committer` is an interface that defines methods to persist changes to disk: + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/store/types/store.go#L17-L22 + +The `CommitID` is a deterministic commit of the state tree. Its hash is returned to the underlying consensus engine and stored in the block header. Note that commit store interfaces exist for various purposes, one of which is to make sure not every object can commit the store. As part of the [object-capabilities model](./ocap.md) of the Cosmos SDK, only `baseapp` should have the ability to commit stores. For example, this is the reason why the `ctx.KVStore()` method by which modules typically access stores returns a `KVStore` and not a `CommitKVStore`. + +The Cosmos SDK comes with many types of stores, the most used being [`CommitMultiStore`](#multistore), [`KVStore`](#kvstore) and [`GasKv` store](#gaskv-store). [Other types of stores](#other-stores) include `Transient` and `TraceKV` stores. + +## Multistore + +### Multistore Interface + +Each Cosmos SDK application holds a multistore at its root to persist its state. The multistore is a store of `KVStores` that follows the `Multistore` interface: + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/store/types/store.go#L83-L112 + +If tracing is enabled, then cache-wrapping the multistore will wrap all the underlying `KVStore` in [`TraceKv.Store`](#tracekv-store) before caching them. + +### CommitMultiStore + +The main type of `Multistore` used in the Cosmos SDK is `CommitMultiStore`, which is an extension of the `Multistore` interface: + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/store/types/store.go#L120-L158 + +As for concrete implementation, the [`rootMulti.Store`] is the go-to implementation of the `CommitMultiStore` interface. + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/store/rootmulti/store.go#L27-L43 + +The `rootMulti.Store` is a base-layer multistore built around a `db` on top of which multiple `KVStores` can be mounted, and is the default multistore store used in [`baseapp`](./baseapp.md). + +### CacheMultiStore + +Whenever the `rootMulti.Store` needs to be cached-wrapped, a [`cachemulti.Store`](https://github.com/cosmos/cosmos-sdk/blob/master/store/cachemulti/store.go) is used. + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/store/cachemulti/store.go#L17-L28 + +`cachemulti.Store` cache wraps all substores in its constructor and hold them in `Store.stores`. `Store.GetKVStore()` returns the store from `Store.stores`, and `Store.Write()` recursively calls `CacheWrap.Write()` on all the substores. + +## Base-layer KVStores + +### `KVStore` and `CommitKVStore` Interfaces + +A `KVStore` is a simple key-value store used to store and retrieve data. A `CommitKVStore` is a `KVStore` that also implements a `Committer`. By default, stores mounted in `baseapp`'s main `CommitMultiStore` are `CommitKVStore`s. The `KVStore` interface is primarily used to restrict modules from accessing the committer. + +Individual `KVStore`s are used by modules to manage a subset of the global state. `KVStores` can be accessed by objects that hold a specific key. This `key` should only be exposed to the [`keeper`](../building-modules/keeper.md) of the module that defines the store. + +`CommitKVStore`s are declared by proxy of their respective `key` and mounted on the application's [multistore](#multistore) in the [main application file](../basics/app-anatomy.md#core-application-file). In the same file, the `key` is also passed to the module's `keeper` that is responsible for managing the store. + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/store/types/store.go#L163-L193 + +Apart from the traditional `Get` and `Set` methods, a `KVStore` is expected to implement an `Iterator()` method which returns an `Iterator` object. The `Iterator()` method is used to iterate over a domain of keys, typically keys that share a common prefix. Here is a common pattern of using an `Iterator` that might be found in a module's `keeper`: + +```go +store := ctx.KVStore(keeper.storeKey) +iterator := sdk.KVStorePrefixIterator(store, prefix) // proxy for store.Iterator + +defer iterator.Close() +for ; iterator.Valid(); iterator.Next() { + var object types.Object + keeper.cdc.MustUnmarshalBinaryLengthPrefixed(iterator.Value(), &object) + + if cb(object) { + break + } +} +``` + +### `IAVL` Store + +The default implementation of `KVStore` and `CommitKVStore` used in `baseapp` is the `iavl.Store`. + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/store/iavl/store.go#L32-L47 + + `iavl` stores are based around an [IAVL Tree](https://github.com/tendermint/iavl), a self-balancing binary tree which guarantees that: + +- `Get` and `Set` operations are O(log n), where n is the number of elements in the tree. +- Iteration efficiently returns the sorted elements within the range. +- Each tree version is immutable and can be retrieved even after a commit (depending on the pruning settings). + +### `DbAdapter` Store + +`dbadapter.Store` is a adapter for `dbm.DB` making it fulfilling the `KVStore` interface. + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/store/dbadapter/store.go#L13-L16 + +`dbadapter.Store` embeds `dbm.DB`, meaning most of the `KVStore` interface functions are implemented. The other functions (mostly miscellaneous) are manually implemented. This store is primarily used within [Transient Stores](#transient-stores) + +### `Transient` Store + +`Transient.Store` is a base-layer `KVStore` which is automatically discarded at the end of the block. + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/store/transient/store.go#L14-L17 + +`Transient.Store` is a `dbadapter.Store` with a `dbm.NewMemDB()`. All `KVStore` methods are reused. When `Store.Commit()` is called, a new `dbadapter.Store` is assigned, discarding previous reference and making it garbage collected. + +This type of store is useful to persist information that is only relevant per-block. One example would be to store parameter changes (i.e. a bool set to `true` if a parameter changed in a block). + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/x/params/subspace/subspace.go#L24-L32 + +Transient stores are typically accessed via the [`context`](./context.md) via the `TransientStore()` method: + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/context.go#L215-L218 + +## KVStore Wrappers + +### CacheKVStore + +`cachekv.Store` is a wrapper `KVStore` which provides buffered writing / cached reading functionalities over the underlying `KVStore`. + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/store/cachekv/store.go#L26-L33 + +This is the type used whenever an IAVL Store needs to be cache-wrapped (typically when setting value that might be reverted later). + +#### `Get` + +`Store.Get()` checks `Store.cache` first in order to find if there is any cached value associated with the key. If the value exists, the function returns it. If not, the function calls `Store.parent.Get()`, sets the key-value pair to the `Store.cache`, and returns it. + +#### `Set` + +`Store.Set()` sets the key-value pair to the `Store.cache`. `cValue` has the field dirty bool which indicates whether the cached value is different from the underlying value. When `Store.Set()` cache new pair, the `cValue.dirty` is set `true` so when `Store.Write()` is called it can be written to the underlying store. + +#### `Iterator` + +`Store.Iterator()` have to traverse on both caches items and the original items. In `Store.iterator()`, two iterators are generated for each of them, and merged. `memIterator` is essentially a slice of the `KVPairs`, used for cached items. `mergeIterator` is a combination of two iterators, where traverse happens ordered on both iterators. + +### `GasKv` Store + +Cosmos SDK applications use [`gas`](../basics/gas-fees.md) to track resources usage and prevent spam. [`GasKv.Store`](https://github.com/cosmos/cosmos-sdk/blob/master/store/gaskv/store.go) is a `KVStore` wrapper that enables automatic gas consumption each time a read or write to the store is made. It is the solution of choice to track storage usage in Cosmos SDK applications. + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/store/gaskv/store.go#L11-L17 + +When methods of the parent `KVStore` are called, `GasKv.Store` automatically consumes appropriate amount of gas depending on the `Store.gasConfig`: + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/store/types/gas.go#L141-L150 + +By default, all `KVStores` are wrapped in `GasKv.Stores` when retrieved. This is done in the `KVStore()` method of the [`context`](./context.md): + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/context.go#L210-L213 + +In this case, the default gas configuration is used: + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/store/types/gas.go#L152-L163 + +### `TraceKv` Store + +`tracekv.Store` is a wrapper `KVStore` which provides operation tracing functionalities over the underlying `KVStore`. It is applied automatically by the Cosmos SDK on all `KVStore` if tracing is enabled on the parent `MultiStore`. + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/store/tracekv/store.go#L20-L43 + +When each `KVStore` methods are called, `tracekv.Store` automatically logs `traceOperation` to the `Store.writer`. `traceOperation.Metadata` is filled with `Store.context` when it is not nil. `TraceContext` is a `map[string]interface{}`. + +### `Prefix` Store + +`prefix.Store` is a wrapper `KVStore` which provides automatic key-prefixing functionalities over the underlying `KVStore`. + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/store/prefix/store.go#L17-L20 + +When `Store.{Get, Set}()` is called, the store forwards the call to its parent, with the key prefixed with the `Store.prefix`. + +When `Store.Iterator()` is called, it does not simply prefix the `Store.prefix`, since it does not work as intended. In that case, some of the elements are traversed even they are not starting with the prefix. + +## Next {hide} + +Learn about [encoding](./encoding.md) {hide} \ No newline at end of file diff --git a/docs/core/transactions.md b/docs/core/transactions.md new file mode 100644 index 000000000000..d49cd853a797 --- /dev/null +++ b/docs/core/transactions.md @@ -0,0 +1,91 @@ +--- +order: 2 +synopsis: "`Transactions` are objects created by end-users to trigger state changes in the application." +--- + +# Transactions + +## Pre-requisite Readings {hide} + +* [Anatomy of an SDK Application](../basics/app-anatomy.md) {prereq} + +## Transactions + +Transactions are comprised of metadata held in [contexts](./context.md) and [messages](../building-modules/messages-and-queries.md) that trigger state changes within a module through the module's [Handler](../building-modules/handler.md). + +When users want to interact with an application and make state changes (e.g. sending coins), they create transactions. Each of a transaction's `message`s must be signed using the private key associated with the appropriate account(s), before the transaction is broadcasted to the network. A transaction must then be included in a block, validated, and approved by the network through the consensus process. To read more about the lifecycle of a transaction, click [here](../basics/tx-lifecycle.md). + +## Type Definition + +Transaction objects are SDK types that implement the `Tx` interface + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/tx_msg.go#L34-L41 + +It contains the following methods: + +* **GetMsgs:** unwraps the transaction and returns a list of its message(s) - one transaction may have one or multiple [messages](../building-modules/messages-and-queries.md#messages), which are defined by module developers. +* **ValidateBasic:** includes lightweight, [*stateless*](../basics/tx-lifecycle.md#types-of-checks) checks used by ABCI messages [`CheckTx`](./baseapp.md#checktx) and [`DeliverTx`](./baseapp.md#delivertx) to make sure transactions are not invalid. For example, the [`auth`](https://github.com/cosmos/cosmos-sdk/tree/master/x/auth) module's `StdTx` `ValidateBasic` function checks that its transactions are signed by the correct number of signers and that the fees do not exceed what the user's maximum. Note that this function is to be distinct from the `ValidateBasic` functions for *`messages`*, which perform basic validity checks on messages only. For example, when [`runTx`](./baseapp.md#runtx) is checking a transaction created from the [`auth`](https://github.com/cosmos/cosmos-sdk/tree/master/x/auth/spec) module, it first runs `ValidateBasic` on each message, then runs the `auth` module AnteHandler which calls `ValidateBasic` for the transaction itself. +* **TxEncoder:** Nodes running the consensus engine (e.g. Tendermint Core) are responsible for gossiping transactions and ordering them into blocks, but only handle them in the generic `[]byte` form. Transactions are always [marshaled](./encoding.md) (encoded) before they are relayed to nodes, which compacts them to facilitate gossiping and helps maintain the consensus engine's separation from from application logic. The Cosmos SDK allows developers to specify any deterministic encoding format for their applications; the default is Amino. +* **TxDecoder:** [ABCI](https://tendermint.com/docs/spec/abci/) calls from the consensus engine to the application, such as `CheckTx` and `DeliverTx`, are used to process transaction data to determine validity and state changes. Since transactions are passed in as `txBytes []byte`, they need to first be unmarshaled (decoded) using `TxDecoder` before any logic is applied. + +The most used implementation of the `Tx` interface is [`StdTx` from the `auth` module](https://github.com/cosmos/cosmos-sdk/blob/master/x/auth/types/stdtx.go). As a developer, using `StdTx` as your transaction format is as simple as importing the `auth` module in your application (which can be done in the [constructor of the application](../basics/app-anatomy.md#constructor-function)) + +## Transaction Process + +A transaction is created by an end-user through one of the possible [interfaces](#interfaces). In the process, two contexts and an array of [messages](#messages) are created, which are then used to [generate](#transaction-generation) the transaction itself. The actual state changes triggered by transactions are enabled by the [handlers](#handlers). The rest of the document will describe each of these components, in this order. + +### CLI and REST Interfaces + +Application developers create entrypoints to the application by creating a [command-line interface](../interfaces/cli.md) and/or [REST interface](../interfaces/rest.md), typically found in the application's `./cmd` folder. These interfaces allow users to interact with the application through command-line or through HTTP requests. + +For the [command-line interface](../building-modules/module-interfaces.md#cli), module developers create subcommands to add as children to the application top-level transaction command `TxCmd`. For [HTTP requests](../building-modules/module-interfaces.md#rest), module developers specify acceptable request types, register REST routes, and create HTTP Request Handlers. + +When users interact with the application's interfaces, they invoke the underlying modules' handlers or command functions, directly creating messages. + +### Messages + +**`Message`s** are module-specific objects that trigger state transitions within the scope of the module they belong to. Module developers define the `message`s for their module by implementing the `Msg` interface, and also define a [`Handler`](../building-modules/handler.md) to process them. + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/tx_msg.go#L8-L29 + +`Message`s in a module are typically defined in a `msgs.go` file (though not always), and one handler with multiple functions to handle each of the module's `message`s is defined in a `handler.go` file. + +Note: module `messages` are not to be confused with [ABCI Messages](https://tendermint.com/docs/spec/abci/abci.html#messages) which define interactions between the Tendermint and application layers. + +To learn more about `message`s, click [here](../building-modules/messages-and-queries.md#messages). + +While messages contain the information for state transition logic, a transaction's other metadata and relevant information are stored in the `TxBuilder` and `CLIContext`. + +### Transaction Generation + +Transactions are first created by end-users through an `appcli tx` command through the command-line or a POST request to an HTTPS server. For details about transaction creation, click [here](../basics/tx-lifecycle.md#transaction-creation). + +[`Contexts`](https://godoc.org/context) are immutable objects that contain all the information needed to process a request. In the process of creating a transaction through the `auth` module (though it is not mandatory to create transactions this way), two contexts are created: the [`CLIContext`](../interfaces/query-lifecycle.md#clicontext) and `TxBuilder`. Both are automatically generated and do not need to be defined by application developers, but do require input from the transaction creator (e.g. using flags through the CLI). + +The `TxBuilder` contains data closely related with the processing of transactions. + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/x/auth/types/txbuilder.go#L18-L31 + +- `TxEncoder` defined by the developer for this type of transaction. Used to encode messages before being processed by nodes running Tendermint. +- `Keybase` that manages the user's keys and is used to perform signing operations. +- `AccountNumber` from which this transaction originated. +- `Sequence`, the number of transactions that the user has sent out, used to prevent replay attacks. +- `Gas` option chosen by the users for how to calculate how much gas they will need to pay. A common option is "auto" which generates an automatic estimate. +- `GasAdjustment` to adjust the estimate of gas by a scalar value, used to avoid underestimating the amount of gas required. +- `SimulateAndExecute` option to simply simulate the transaction execution without broadcasting. +- `ChainID` representing which blockchain this transaction pertains to. +- `Memo` to send with the transaction. +- `Fees`, the maximum amount the user is willing to pay in fees. Alternative to specifying gas prices. +- `GasPrices`, the amount per unit of gas the user is willing to pay in fees. Alternative to specifying fees. + +The `CLIContext` is initialized using the application's `codec` and data more closely related to the user interaction with the interface, holding data such as the output to the user and the broadcast mode. Read more about `CLIContext` [here](../interfaces/query-lifecycle.md#clicontext). + +Every message in a transaction must be signed by the addresses specified by `GetSigners`. The signing process must be handled by a module, and the most widely used one is the [`auth`](https://github.com/cosmos/cosmos-sdk/tree/master/x/auth/spec) module. Signing is automatically performed when the transaction is created, unless the user choses to generate and sign separately. The `TxBuilder` (namely, the `KeyBase`) is used to perform the signing operations, and the `CLIContext` is used to broadcast transactions. + +### Handlers + +Since `message`s are module-specific types, each module needs a [`handler`](../building-modules/handler.md) to process all of its `message` types and trigger state changes within the module's scope. This design puts more responsibility on module developers, allowing application developers to reuse common functionalities without having to implement state transition logic repetitively. To read more about `handler`s, click [here](../building-modules/handler.md). + +## Next {hide} + +Learn about the [context](./context.md) {hide} \ No newline at end of file diff --git a/docs/interfaces/README.md b/docs/interfaces/README.md new file mode 100644 index 000000000000..0e23c0478ae7 --- /dev/null +++ b/docs/interfaces/README.md @@ -0,0 +1,15 @@ +--- +order: false +parent: + order: 5 +--- + +# Interfaces + +This repository contains documentation on interfaces for Cosmos SDK applications. + +1. [Introduction to Interaces](./interfaces-intro.md) +2. [Lifecycle of a Query](./query-lifecycle.md) +3. [Command-Line Interface](./cli.md) +4. [Rest Interface](./rest.md) + diff --git a/docs/interfaces/cli.md b/docs/interfaces/cli.md new file mode 100644 index 000000000000..9cc907ee7126 --- /dev/null +++ b/docs/interfaces/cli.md @@ -0,0 +1,137 @@ +--- +order: 3 +synopsis: "This document describes how to create a commmand-line interface (CLI) for an [**application**](../basics/app-anatomy.md). A separate document for implementing a CLI for an SDK [**module**](../building-modules/intro.md) can be found [here](#../building-modules/module-interfaces.md#cli)." +--- + +# Command-Line Interface + +## Pre-requisite Readings {hide} + +* [Lifecycle of a Query](./query-lifecycle.md) {prereq} + +## Command-Line Interface + +One of the main entrypoints of an application is the command-line interface. This entrypoint is created via a `main.go` file which compiles to a binary, conventionally placed in the application's `./cmd/cli` folder. The CLI for an application is typically be referred to as the name of the application suffixed with `-cli`, e.g. `appcli`. Here is where the interfaces docs lie in the directory from the [nameservice tutorial](https://cosmos.network/docs/tutorial). + +### Example Command + +There is no set way to create a CLI, but SDK modules typically use the [Cobra Library](https://github.com/spf13/cobra). Building a CLI with Cobra entails defining commands, arguments, and flags. [**Commands**](#commands) understand the actions users wish to take, such as `tx` for creating a transaction and `query` for querying the application. Each command can also have nested subcommands, necessary for naming the specific transaction type. Users also supply **Arguments**, such as account numbers to send coins to, and [**Flags**](#flags) to modify various aspects of the commands, such as gas prices or which node to broadcast to. + +Here is an example of a command a user might enter to interact with the nameservice CLI `nscli` in order to buy a name: + +```bash +nscli tx nameservice buy-name --gas auto --gas-prices +``` + +The first four strings specify the command: + +- The root command for the entire application `nscli`. +- The subcommand `tx`, which contains all commands that let users create transactions. +- The subcommand `nameservice` to indicate which module to route the command to (`nameservice` module in this case). +- The type of transaction `buy-name`. + +The next two strings are arguments: the `name` the user wishes to buy and the `amount` they want to pay for it. Finally, the last few strings of the command are flags to indicate how much the user is willing to pay in fees (calculated using the amount of gas used to execute the transaction and the gas prices provided by the user). + +The CLI interacts with a [node](../core/node.md) (running `nsd`) to handle this command. The interface itself is defined in a `main.go` file. + +### Building the CLI + +The `main.go` file needs to have a `main()` function that does the following to run the command-line interface: + +* **Instantiate the `codec`** by calling the application's `MakeCodec()` function. The [`codec`](../core/encoding.md) is used to code and encode data structures for the application - stores can only persist `[]byte`s so the developer must define a serialization format for their data structures or use the default, [Amino](../core/encoding.md#amino). +* **Configurations** are set by reading in configuration files (e.g. the sdk config file). +* **Create the root command** to which all the application commands will be added as subcommands and add any required flags to it, such as `--chain-id`. +* **Add subcommands** for all the possible user interactions, including [transaction commands](#transaction-commands) and [query commands](#query-commands). +* **Create an Executor** and [execute](https://godoc.org/github.com/spf13/cobra#Command.Execute) the root command. + +See an example of `main()` function from the `nameservice` application: + ++++ https://github.com/cosmos/sdk-tutorials/blob/86a27321cf89cc637581762e953d0c07f8c78ece/nameservice/cmd/nscli/main.go#L23-L66 + +The rest of the document will detail what needs to be implemented for each step and include smaller portions of code from the nameservice CLI `main.go` file. + +## Adding Commands to the CLI + +Every application CLI first constructs a root command, then adds functionality by aggregating subcommands (often with further nested subcommands) using `rootCmd.AddCommand()`. The bulk of an application's unique capabilities lies in its transaction and query commands, called `TxCmd` and `QueryCmd` respectively. + +### Root Command + +The root command (called `rootCmd`) is what the user first types into the command line to indicate which application they wish to interact with. The string used to invoke the command (the "Use" field) is typically the name of the application suffixed with `-cli`, e.g. `appcli`. The root command typically includes the following commands to support basic functionality in the application. + +* **Status** command from the SDK rpc client tools, which prints information about the status of the connected [`Node`](../core/node.md). The Status of a node includes `NodeInfo`,`SyncInfo` and `ValidatorInfo`. +* **Config** [command](https://github.com/cosmos/cosmos-sdk/blob/master/client/config.go) from the SDK client tools, which allows the user to edit a `config.toml` file that sets values for [flags](#flags) such as `--chain-id` and which `--node` they wish to connect to. +The `config` command can be invoked by typing `appcli config` with optional arguments ` [value]` and a `--get` flag to query configurations or `--home` flag to create a new configuration. +* **Keys** [commands](https://github.com/cosmos/cosmos-sdk/blob/master/client/keys) from the SDK client tools, which includes a collection of subcommands for using the key functions in the SDK crypto tools, including adding a new key and saving it to disk, listing all public keys stored in the key manager, and deleting a key. +For example, users can type `appcli keys add ` to add a new key and save an encrypted copy to disk, using the flag `--recover` to recover a private key from a seed phrase or the flag `--multisig` to group multiple keys together to create a multisig key. For full details on the `add` key command, see the code [here](https://github.com/cosmos/cosmos-sdk/blob/master/client/keys/add.go). +* [**Transaction**](#transaction-commands) commands. +* [**Query**](#query-commands) commands. + +Next is an example `main()` function from the `nameservice` application. It instantiates the root command, adds a [*persistent* flag](#flags) and `PreRun` function to be run before every execution, and adds all of the necessary subcommands. + ++++ https://github.com/cosmos/sdk-tutorials/blob/86a27321cf89cc637581762e953d0c07f8c78ece/nameservice/cmd/nscli/main.go#L23-L66 + +The root-level `status`, `config`, and `keys` subcommands are common across most applications and do not interact with application state. The bulk of an application's functionality - what users can actually *do* with it - is enabled by its transaction commands. + +### Transaction Commands + +[Transactions](#./transactions.md) are objects wrapping [messages](../building-modules/messages-and-queries.md#messages) that trigger state changes. To enable the creation of transactions using the CLI interface, a function `txCmd` is generally added to the `rootCmd`: + ++++ https://github.com/cosmos/sdk-tutorials/blob/86a27321cf89cc637581762e953d0c07f8c78ece/nameservice/cmd/nscli/main.go#L51 + +This `txCmd` function adds all the transaction available to end-users for the application. This typically includes: + +* **Sign command** from the [`auth`](https://github.com/cosmos/cosmos-sdk/tree/master/x/auth/spec) module that signs messages in a transaction. To enable multisig, add the `auth` module's `MultiSign` command. Since every transaction requires some sort of signature in order to be valid, thithe signing command is necessary for every application. +* **Broadcast command** from the SDK client tools, to broadcast transactions. +* **Send command** from the [`bank`](https://github.com/cosmos/cosmos-sdk/tree/master/x/bank/spec) module, which is a transaction that allows accounts to send coins to one another, including gas and fees for transactions. +* **All [module transaction commands](../building-modules/module-interfaces.md#transaction-commands)** the application is dependent on, retrieved by using the [basic module manager's](../building-modules/module-manager.md#basic-manager) `AddTxCommands()` function. + +Here is an example of a `txCmd` aggregating these subcommands from the `nameservice` application: + ++++ https://github.com/cosmos/sdk-tutorials/blob/86a27321cf89cc637581762e953d0c07f8c78ece/nameservice/cmd/nscli/main.go#L97-L118 + + +### Query Commands + +[**Queries**](../building-modules/messages-and-queries.md#queries) are objects that allow users to retrieve information about the application's state. To enable the creation of transactions using the CLI interface, a function `txCmd` is generally added to the `rootCmd`: + ++++ https://github.com/cosmos/sdk-tutorials/blob/86a27321cf89cc637581762e953d0c07f8c78ece/nameservice/cmd/nscli/main.go#L50 + +This `queryCmd` function adds all the queries available to end-users for the application. This typically includes: + +* **QueryTx** and/or other transaction query commands] from the `auth` module which allow the user to search for a transaction by inputting its hash, a list of tags, or a block height. These queries allow users to see if transactions have been included in a block. +* **Account command** from the `auth` module, which displays the state (e.g. account balance) of an account given an address. +* **Validator command** from the SDK rpc client tools, which displays the validator set of a given height. +* **Block command** from the SDK rpc client tools, which displays the block data for a given height. +* **All [module query commands](../building-modules/module-interfaces.md#query-commands)** the application is dependent on, retrieved by using the [basic module manager's](../building-modules/module-manager.md#basic-manager) `AddQueryCommands()` function. + +Here is an example of a `queryCmd` aggregating subcommands from the `nameservice` application: + ++++ https://github.com/cosmos/sdk-tutorials/blob/86a27321cf89cc637581762e953d0c07f8c78ece/nameservice/cmd/nscli/main.go#L74-L95 + +## Flags + +Flags are used to modify commands; developers can include them in a `flags.go` file with their CLI. Users can explicitly include them in commands or pre-configure them by entering a command in the format `appcli config ` into their command line. Commonly pre-configured flags include the `--node` to connect to and `--chain-id` of the blockchain the user wishes to interact with. + +A *persistent* flag (as opposed to a _local_ flag) added to a command transcends all of its children: subcommands will inherit the configured values for these flags. Additionally, all flags have default values when they are added to commands; some toggle an option off but others are empty values that the user needs to override to create valid commands. A flag can be explicitly marked as _required_ so that an error is automatically thrown if the user does not provide a value, but it is also acceptable to handle unexpected missing flags differently. + +Flags are added to commands directly (generally in the [module's CLI file](../building-modules/module-interfaces.md#flags) where module commands are defined) and no flag except for the `rootCmd` persistent flags has to be added at application level. It is common to add a _persistent_ flag for `--chain-id`, the unique identifier of the blockchain the application pertains to, to the root command. Adding this flag can be done in the `main()` function. Adding this flag makes sense as the chain ID should not be changing across commands in this application CLI. Here is an example from the `nameservice` application: + ++++ https://github.com/cosmos/sdk-tutorials/blob/86a27321cf89cc637581762e953d0c07f8c78ece/nameservice/cmd/nscli/main.go#L41 + + +## Configurations + +The last function to define in `main.go` is `initConfig`, which does exactly what it sounds like - initialize configurations. To call this function, set it as a `PersistentPreRunE` function for the root command, so that it always executes before the main execution of the root command and any of its subcommands. `initConfig()` does the following: + +1. Read in the `config.toml` file. This same file is edited through `config` commands. +2. Use the [Viper](https://github.com/spf13/viper) to read in configurations from the file and set them. +3. Set any persistent flags defined by the user: `--chain-id`, `--encoding`, `--output`, etc. + +Here is an example of an `initConfig()` function from the [nameservice tutorial CLI](https://cosmos.network/docs/tutorial/entrypoint.html#nscli): + ++++ https://github.com/cosmos/sdk-tutorials/blob/86a27321cf89cc637581762e953d0c07f8c78ece/nameservice/cmd/nscli/main.go#L120-L141 + +And an example of how to add `initConfig` as a `PersistentPreRunE` to the root command: + ++++ https://github.com/cosmos/sdk-tutorials/blob/86a27321cf89cc637581762e953d0c07f8c78ece/nameservice/cmd/nscli/main.go#L42-L44 + diff --git a/docs/interfaces/clients.md b/docs/interfaces/clients.md deleted file mode 100644 index ee972577c121..000000000000 --- a/docs/interfaces/clients.md +++ /dev/null @@ -1,26 +0,0 @@ -# Clients - -This section explains contains information on clients for SDK based blockchain. - ->*NOTE*: This section is a WIP. - -## Light-client - -Light-clients enable users to interact with your application without having to download the entire state history but with a good level of security. - -- [Overview of light clients](./lite/README.md) -- [Starting a light-client server](./lite/getting_started.md) -- [Light-client specification](./lite/specification.md) - -## Other clients - -- [Command-Line interface for SDK-based blockchain](./cli.md) -- [Service provider doc](./service-providers.md) - -## Genesis upgrade - -If you need to upgrade your node you could export the genesis and migrate it to the new version through this script: - -```bash - migrate v0.36 genesis_0_34.json [--time "2019-04-22T17:00:11Z"] [--chain-id test] > ~/.gaiad/genesis.json -``` diff --git a/docs/interfaces/interfaces-intro.md b/docs/interfaces/interfaces-intro.md new file mode 100644 index 000000000000..eb807d0025e8 --- /dev/null +++ b/docs/interfaces/interfaces-intro.md @@ -0,0 +1,43 @@ +--- +order: 1 +synopsis: Typically, SDK applications include interfaces to let end-users interact with the application. This document introduces the different types of interfaces for SDK applications. +--- + +# Interfaces + +## Pre-requisite Readings {hide} + +* [Anatomy of an SDK Application](../basics/app-anatomy.md) {prereq} +* [Lifecycle of a Transaction](../basics/tx-lifecycle.md) {prereq} + +## Types of Application Interfaces + +SDK applications generally have a Command-Line Interface (CLI) and REST Interface to support interactions with a [full-node](../core/node.md). The SDK is opinionated about how to create these two interfaces; all modules specify [Cobra commands](https://github.com/spf13/cobra) and register routes using [Gorilla Mux routers](https://github.com/gorilla/mux). The CLI and REST Interface are conventionally defined in the application `./app/cmd/cli` folder. + +## Module vs Application Interfaces + +The process of creating an application interface is distinct from creating a [module interface](../building-modules/module-interfaces.md), though the two are closely intertwined. As expected, module interfaces handle the bulk of the underlying logic, defining ways for end-users to create [messages](../building-modules/messages-and-queries.md#messages) and [queries](../building-modules/messages-and-queries.md#queries) to the subset of application state within their scope. On the other hand, application interfaces aggregate module-level interfaces in order to route `messages` and `queries` to the appropriate modules. Application interfaces also handle root-level responsibilities such as signing and broadcasting [transactions](../core/transactions.md) that wrap messages. + +### Module Developer Responsibilities + +With regards to interfaces, module developers need to include the following definitions: + +* **CLI commands:** Specifically, [Transaction commands](../building-modules/module-interfaces.md#transaction-commands) and [Query commands](../building-modules/module-interfaces.md#query-commands). These are commands that users will invoke when interacting with the application to create transactions and queries. For example, if an application enables sending coins through the [`auth`](https://github.com/cosmos/cosmos-sdk/tree/master/x/auth/spec) module, users will create `tx auth send` transactions. +* **Request Handlers:** Also categorized into Transaction and Query requests. Transactions will require HTTP [Request Types](../building-modules/module-interfaces.md#request-types) in addition to [Request Handlers](../building-modules/module-interfaces.md#request-handlers) in order to encapsulate all of the user's options (e.g. gas prices). +* **REST Routes:** Given a router, the module interface registers paths with the aforementioned [Request Handlers](../building-modules/module-interfaces.md#request-handlers) for each type of request. + +Module interfaces are designed to be generic. Both commands and request types include required user input (through flags or request body) which are different for each application. This section of documents will only detail application interfaces; to read about how to build module interfaces, click [here](../building-modules/module-interfaces.md). + +### Application Developer Responsibilities + +With regards to interfaces, application developers need to include: + +* **CLI Root Command:** The [root command](./cli.md#root-command) adds subcommands to include all of the functionality for the application, mainly module [transaction](./cli.md#transaction-commands) and [query](./cli.md#query-commands) commands from the application's module(s). +* **App Configurations:** All application-specific values are the responsibility of the application developer, including the [`codec`](../core/encoding.md) used to marshal requests before relaying them to a node. +* **User Configurations:** Some values are specific to the user, such as the user's address and which node they are connected to. The CLI has a [configurations](./cli.md#configurations) function to set these values. +* **RegisterRoutes Function:** [Routes](./rest.md#registerroutes) must be registered and passed to an instantiated [REST server](./rest.md#rest-server) so that it knows how to route requests for this particular application. + + +## Next {hide} + +Read about the [Lifecycle of a Query](./query-lifecycle.md) {hide} diff --git a/docs/interfaces/lite/readme.md b/docs/interfaces/lite/readme.md index 23bcb2f93b26..e31ccd0752e5 100644 --- a/docs/interfaces/lite/readme.md +++ b/docs/interfaces/lite/readme.md @@ -1,3 +1,8 @@ +--- +parent: + order: false +--- + # Light Client Overview **See the Cosmos SDK Light Client RPC documentation [here](https://cosmos.network/rpc/)** diff --git a/docs/interfaces/lite/specification.md b/docs/interfaces/lite/specification.md index e252403731a2..4ce849acaa1d 100644 --- a/docs/interfaces/lite/specification.md +++ b/docs/interfaces/lite/specification.md @@ -14,7 +14,7 @@ tree is the AppHash which will be included in block header. ![Simple Merkle Tree](./pics/simpleMerkleTree.png) -As we have discussed in [LCD trust-propagation](https://github.com/irisnet/cosmos-sdk/tree/bianjie/lcd_spec/docs/spec/lcd#trust-propagation), +As we have discussed in LCD trust-propagation, the AppHash can be verified by checking voting power against a trusted validator set. Here we just need to build proof from ABCI state to AppHash. The proof contains two parts: diff --git a/docs/interfaces/query-lifecycle.md b/docs/interfaces/query-lifecycle.md new file mode 100644 index 000000000000..748ebb8225dc --- /dev/null +++ b/docs/interfaces/query-lifecycle.md @@ -0,0 +1,161 @@ +--- +order: 2 +synopsis: "This document describes the lifecycle of a query in a SDK application, from the user interface to application stores and back. The query will be referred to as `Query`." +--- + +# Query Lifecycle + +## Pre-requisite Readings {hide} + +* [Introduction to Interfaces](./interfaces-intro.md) {prereq} + +## Query Creation + +A [**query**](../building-modules/messages-and-queries.md#queries) is a request for information made by end-users of applications through an interface and processed by a full-node. Users can query information about the network, the application itself, and application state directly from the application's stores or modules. Note that queries are different from [transactions](../core/transactions.md) (view the lifecycle [here](../basics/tx-lifecycle.md)), particularly in that they do not require consensus to be processed (as they do not trigger state-transitions); they can be fully handled by one full-node. + +For the purpose of explaining the query lifecycle, let's say `Query` is requesting a list of delegations made by a certain delegator address in the application called `app`. As to be expected, the [`staking`](https://github.com/cosmos/cosmos-sdk/tree/master/x/staking/spec) module handles this query. But first, there are a few ways `Query` can be created by users. + +### CLI + +The main interface for an application is the command-line interface. Users connect to a full-node and run the CLI directly from their machines - the CLI interacts directly with the full-node. To create `Query` from their terminal, users type the following command: + +```bash +appcli query staking delegations +``` + +This query command was defined by the [`staking`](https://github.com/cosmos/cosmos-sdk/tree/master/x/staking/spec) module developer and added to the list of subcommands by the application developer when creating the CLI. The code for this particular command is the following: + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/x/staking/client/cli/query.go#L250-L293 + +Note that the general format is as follows: + +```bash +appcli query [moduleName] [command] --flag +``` + +To provide values such as `--node` (the full-node the CLI connects to), the user can use the `config` command to set themn or provide them as flags. + +The CLI understands a specific set of commands, defined in a hierarchical structure by the application developer: from the [root command](./cli.md#root-command) (`appcli`), the type of command (`query`), the module that contains the command (`staking`), and command itself (`delegations`). Thus, the CLI knows exactly which module handles this command and directly passes the call there. + +### REST + +Another interface through which users can make queries is through HTTP Requests to a [REST server](./rest.md#rest-server). The REST server contains, among other things, a [`CLIContext`](#clicontext) and [mux](./rest.md#gorilla-mux) router. The request looks like this: + +```bash +GET http://localhost:{PORT}/staking/delegators/{delegatorAddr}/delegations +``` + +To provide values such as `--node` (the full-node the CLI connects to) that are required by [`baseReq`](../building-modules/module-interfaces.md#basereq), the user must configure their local REST server with the values or provide them in the request body. + +The router automatically routes the `Query` HTTP request to the staking module `delegatorDelegationsHandlerFn()` function. + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/x/staking/client/rest/query.go#L103-L106 + +Since this function is defined within the module and thus has no inherent knowledge of the application `Query` belongs to, it takes in the application `codec` and `CLIContext` as parameters. + +To summarize, when users interact with the interfaces, they create a CLI command or HTTP request. `Query` now exists in one of these two forms, but needs to be transformed into an object understood by a full-node. + +## Query Preparation + +The interactions from the users' perspective are a bit different, but the underlying functions are almost identical because they are implementations of the same command defined by the module developer. This step of processing happens within the CLI or REST server and heavily involves a `CLIContext`. + +### CLIContext + +The first thing that is created in the execution of a CLI command is a `CLIContext`, while the REST Server directly provides a `CLIContext` for the REST Request handler. A [Context](../core/context.md) is an immutable object that stores all the data needed to process a request on the user side. In particular, a `CLIContext` stores the following: + +* **Codec**: The [encoder/decoder](../core/encoding.md) used by the application, used to marshal the parameters and query before making the Tendermint RPC request and unmarshal the returned response into a JSON object. +* **Account Decoder**: The account decoder from the [`auth`](https://github.com/cosmos/cosmos-sdk/tree/master/x/auth/spec) module, which translates `[]byte`s into accounts. +* **RPC Client**: The Tendermint RPC Client, or node, to which the request will be relayed to. +* **Keybase**: A [Key Manager](../basics/accounts.md#keybase) used to sign transactions and handle other operations with keys. +* **Output Writer**: A [Writer](https://golang.org/pkg/io/#Writer) used to output the response. +* **Configurations**: The flags configured by the user for this command, including `--height`, specifying the height of the blockchain to query and `--indent`, which indicates to add an indent to the JSON response. + +The `CLIContext` also contains various functions such as `Query()` which retrieves the RPC Client and makes an ABCI call to relay a query to a full-node. + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/client/context/context.go#L23-L47 + +The `CLIContext`'s primary role is to store data used during interactions with the end-user and provide methods to interact with this data - it is used before and after the query is processed by the full-node. Specifically, in handling `Query`, the `CLIContext` is utilized to encode the query parameters, retrieve the full-node, and write the output. Prior to being relayed to a full-node, the query needs to be encoded into a `[]byte` form, as full-nodes are application-agnostic and do not understand specific types. The full-node (RPC Client) itself is retrieved using the `CLIContext`, which knows which node the user CLI is connected to. The query is relayed to this full-node to be processed. Finally, the `CLIContext` contains a `Writer` to write output when the response is returned. These steps are further described in later sections. + +### Arguments and Route Creation + +At this point in the lifecycle, the user has created a CLI command or HTTP Request with all of the data they wish to include in their `Query`. A `CLIContext` exists to assist in the rest of the `Query`'s journey. Now, the next step is to parse the command or request, extract the arguments, create a `queryRoute`, and encode everything. These steps all happen on the user side within the interface they are interacting with. + +#### Encoding + +In this case, `Query` contains an [address](../basics/accounts.md#addresses) `delegatorAddress` as its only argument. However, the request can only contain `[]byte`s, as it will be relayed to a consensus engine (e.g. Tendermint Core) of a full-node that has no inherent knowledge of the application types. Thus, the `codec` of `CLIContext` is used to marshal the address. + +Here is what the code looks like for the CLI command: + +```go +delAddr, err := sdk.AccAddressFromBech32(args[0]) +bz, err := cdc.MarshalJSON(types.NewQueryDelegatorParams(delAddr)) +``` + +Here is what the code looks like for the HTTP Request: + +```go +vars := mux.Vars(r) +bech32delegator := vars["delegatorAddr"] +delegatorAddr, err := sdk.AccAddressFromBech32(bech32delegator) +cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) +if !ok { + return +} +params := types.NewQueryDelegatorParams(delegatorAddr) +``` + +#### Query Route Creation + +Important to note is that there will never be a "query" object created for `Query`; the SDK actually takes a simpler approach. Instead of an object, all the full-node needs to process a query is its `route` which specifies exactly which module to route the query to and the name of this query type. The `route` will be passed to the application `baseapp`, then module, then [querier](../building-modules/querier.md), and each will understand the `route` and pass it to the appropriate next step. [`baseapp`](../core/baseapp.md#query-routing) will understand this query to be a `custom` query in the module `staking`, and the `staking` module querier supports the type `QueryDelegatorDelegations`. Thus, the route will be `"custom/staking/delegatorDelegations"`. + +Here is what the code looks like: + +```go +route := fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryDelegatorDelegations) +``` + +Now, `Query` exists as a set of encoded arguments and a route to a specific module and its query type. It is ready to be relayed to a full-node. + +#### ABCI Query Call + +The `CLIContext` has a `Query()` function used to retrieve the pre-configured node and relay a query to it; the function takes the query `route` and arguments as parameters. It first retrieves the RPC Client (called the [**node**](../core/node.md)) configured by the user to relay this query to, and creates the `ABCIQueryOptions` (parameters formatted for the ABCI call). The node is then used to make the ABCI call, `ABCIQueryWithOptions()`. + +Here is what the code looks like: + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/client/context/query.go#L75-L112 + +## RPC + +With a call to `ABCIQueryWithOptions()`, `Query` is received by a [full-node](../core/encoding.md) which will then process the request. Note that, while the RPC is made to the consensus engine (e.g. Tendermint Core) of a full-node, queries are not part of consensus and will not be broadcasted to the rest of the network, as they do not require anything the network needs to agree upon. + +Read more about ABCI Clients and Tendermint RPC in the Tendermint documentation [here](https://tendermint.com/rpc). + +## Application Query Handling + +When a query is received by the full-node after it has been relayed from the underlying consensus engine, it is now being handled within an environment that understands application-specific types and has a copy of the state. [`baseapp`](../core/baseapp.md) implements the ABCI [`Query()`](../core/baseapp.md#query) function and handles four different types of queries: `app`, `store`, `p2p`, and `custom`. The `queryRoute` is parsed such that the first string must be one of the four options, then the rest of the path is parsed within the subroutines handling each type of query. The first three types (`app`, `store`, `p2p`) are purely application-level and thus directly handled by `baseapp` or the stores, but the `custom` query type requires `baseapp` to route the query to a module's [querier](../building-modules/querier.md). + +Since `Query` is a custom query type from the `staking` module, `baseapp` first parses the path, then uses the `QueryRouter` to retrieve the corresponding querier, and routes the query to the module. The querier is responsible for recognizing this query, retrieving the appropriate values from the application's stores, and returning a response. Read more about queriers [here](../building-modules/querier.md). + +Once a result is received from the querier, `baseapp` begins the process of returning a response to the user. + +## Response + +Since `Query()` is an ABCI function, `baseapp` returns the response as an [`abci.ResponseQuery`](https://tendermint.com/docs/spec/abci/abci.html#messages) type. The `CLIContext` `Query()` routine receives the response and, if `--trust-node` is toggled to `false` and a proof needs to be verified, the response is verified with the `CLIContext` `verifyProof()` function before the response is returned. + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/client/context/query.go#L127-L165 + +### CLI Response + +The application [`codec`](../core/encoding.md) is used to unmarshal the response to a JSON and the `CLIContext` prints the output to the command line, applying any configurations such as `--indent`. + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/x/staking/client/cli/query.go#L252-L293 + +### REST Response + +The [REST server](./rest.md#rest-server) uses the `CLIContext` to format the response properly, then uses the HTTP package to write the appropriate response or error. + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/x/staking/client/rest/utils.go#L115-L148 + +## Next {hide} + +Read about how to build a [Command-Line Interface](./cli.md), or a [REST Interface](./rest.md) {hide} diff --git a/docs/interfaces/rest.md b/docs/interfaces/rest.md new file mode 100644 index 000000000000..ceb2ce63999e --- /dev/null +++ b/docs/interfaces/rest.md @@ -0,0 +1,60 @@ +--- +order: 4 +synopsis: "This document describes how to create a REST interface for an SDK **application**. A separate document for creating a [**module**](../building-modules/intro.md) REST interface can be found [here](#../module-interfaces.md#rest)." +--- + +# REST Interface + +## Prerequisites {hide} + +* [Query Lifecycle](./query-lifecycle.md) {prereq} +* [Application CLI](./cli.md) {prereq} + +## Application REST Interface + +Building the REST Interface for an application is done by [aggregating REST Routes](#registering-routes) defined in the application's modules. This interface is served by a REST Server [REST server](#rest-server), which route requests and output responses in the application itself. The SDK comes with its own REST Server by default. To enable it, the `rest.ServeCommand` command needs to be added as a subcommand of the `rootCmd` in the `main()` function of the [CLI interface](./cli.md): + +```go +rootCmd.AddCommand(rest.ServeCommand(cdc, registerRoutes)) +``` + +Users will then be able to use the application CLI to start a new REST server, a local server through which they can securely interact with the application without downloading the entire state. The command entered by users would look something like this: + +```bash +appcli rest-server --chain-id --trust-node +``` + +Note that if `trust-node` is set to `false`, the REST server will verify the query proof against the merkle root (contained in the block header). + +## REST Server + +A REST Server is used to receive and route HTTP Requests, obtain the results from the application, and return a response to the user. The REST Server defined by the SDK `rest` package contains the following: + +* **Router:** A router for HTTP requests. A new router can be instantiated for an application and used to match routes based on path, request method, headers, etc. The SDK uses the [Gorilla Mux Router](https://github.com/gorilla/mux). +* **CLIContext:** A [`CLIContext`](./query-lifecycle.md#clicontext) created for a user interaction. +* **Keybase:** A [Keybase](../basics/accounts.md#keybase) is a key manager. +* **Logger:** A logger from Tendermint `Log`, a log package structured around key-value pairs that allows logging level to be set differently for different keys. The logger takes `Debug()`, `Info()`, and `Error()`s. +* **Listener:** A [listener](https://golang.org/pkg/net/#Listener) from the net package. + +Of the five, the only attribute that application developers need interact with is the `router`: they need to add routes to it so that the REST server can properly handle queries. See the next section for more information on registering routes. + +In order to enable the REST Server in an SDK application, the `rest.ServeCommand` needs to be added to the application's command-line interface. See the [above section](#application-rest-interface) for more information. + +## Registering Routes + +To include routes for each module in an application, the CLI must have some kind of function to register routes in its REST Server. This function is called `RegisterRoutes()`, and is utilized by the `ServeCommand` and must include routes for each of the application's modules. Since each module used by an SDK application implements a [`RegisterRESTRoutes`](../building-modules/module-interfaces.md#rest) function, application developers simply use the [Module Manager](../building-modules/module-manager.md) to call this function for each module (this is done in the [application's constructor](../basics/app-anatomy.md#constructor-function)). + +At the bare minimum, a `RegisterRoutes()` function should use the SDK client package `RegisterRoutes()` function to be able to route RPC calls, and instruct the application Module Manager to call `RegisterRESTRoutes()` for all of its modules. This is done in the `main.go` file of the CLI (typically located in `./cmd/appcli/main.go`). + +```go +func registerRoutes(rs *rest.RestServer) { + client.RegisterRoutes(rs.CliCtx, rs.Mux) + app.ModuleBasics.RegisterRESTRoutes(rs.CliCtx, rs.Mux) +} +``` + +This function is specific to the application and passed in to the `ServeCommand`, which should be added to the `rootCmd` as such: + +```go +rootCmd.AddCommand(rest.ServeCommand(cdc, registerRoutes)) +``` diff --git a/docs/interfaces/service-providers.md b/docs/interfaces/service-providers.md deleted file mode 100644 index ad8019930dba..000000000000 --- a/docs/interfaces/service-providers.md +++ /dev/null @@ -1,196 +0,0 @@ -# Service Providers - -We define 'service providers' as entities providing services for end-users that involve some form of interaction with a Cosmos-SDK based blockchain (this includes the Cosmos Hub). More specifically, this document will be focused around interactions with tokens. - -This section does not concern wallet builders that want to provide [Light-Client](https://github.com/cosmos/cosmos-sdk/tree/master/docs/interfaces/lite) functionalities. Service providers are expected to act as trusted point of contact to the blockchain for their end-users. - -## High-level description of the architecture - -There are three main pieces to consider: - -- Full-nodes: To interact with the blockchain. -- Rest Server: This acts as a relayer for HTTP calls. -- Rest API: Define available endpoints for the Rest Server. - -## Running a Full-Node - -### Installation and configuration - -We will describe the steps to run and interact with a full-node for the Cosmos Hub. For other SDK-based blockchain, the process should be similar. - -First, you need to [install the software](../cosmos-hub/installation.md). - -Then, you can start [running a full-node](../cosmos-hub/join-testnet.md). - -### Command-Line interface - -Next you will find a few useful CLI commands to interact with the Full-Node. - -#### Creating a key-pair - -To generate a new key (default secp256k1 elliptic curve): - -```bash -gaiacli keys add -``` - -The key-pair will be created in your system's password store. This will return the information listed below: - -- `NAME`: Name of your key -- `TYPE`: Type of your key, always `local`. -- `ADDRESS`: Your address. Used to receive funds. -- `PUBKEY`: Your public key. Useful for validators. -- `MNEMONIC`: 24-words phrase. **Save this mnemonic somewhere safe**. It is used to recover your -private key in case you forget the password to unlock your system's credentials store. - -You can see all your available keys by typing: - -```bash -gaiacli keys list -``` - -#### Checking your balance - -After receiving tokens to your address, you can view your account's balance by typing: - -```bash -gaiacli account -``` - -*Note: When you query an account balance with zero tokens, you will get this error: No account with address was found in the state. This is expected! We're working on improving our error messages.* - -#### Sending coins via the CLI - -Here is the command to send coins via the CLI: - -```bash -gaiacli tx send \ - --chain-id= -``` - -Parameters: - -- ``: Key name or address of sending account. -- ``: Address of the recipient. -- ``: This parameter accepts the format ``, such as `10faucetToken`. - -Flags: - -- `--chain-id`: This flag allows you to specify the id of the chain. There will be different ids for different testnet chains and main chain. - -#### Help - -If you need to do something else, the best command you can run is: - -```bash -gaiacli -``` - -It will display all the available commands. For each command, you can use the `--help` flag to get further information. - -## Setting up the Rest Server - -The Rest Server acts as an intermediary between the front-end and the full-node. You don't need to run the Rest Server on the same machine as the full-node. - -To start the Rest server: - -```bash -gaiacli rest-server --node= -``` - -Flags: -- `--trust-node`: A boolean. If `true`, light-client verification is disabled. If `false`, it is disabled. For service providers, this should be set to `true`. By default, it set to `true`. -- `--node`: This is where you indicate the address and the port of your full-node. The format is ``. If the full-node is on the same machine, the address should be `tcp://localhost:26657`. -- `--laddr`: This flag allows you to specify the address and port for the Rest Server (default `1317`). You will mostly use this flag only to specify the port, in which case just input "localhost" for the address. The format is . - - -### Listening for incoming transaction - -The recommended way to listen for incoming transaction is to periodically query the blockchain through the following endpoint of the LCD: - -[`/bank/balance/{address}`](https://cosmos.network/rpc/#/ICS20/get_bank_balances__address_) - -## Rest API - -The Rest API documents all the available endpoints that you can use to interact -with your full node. It can be found [here](https://cosmos.network/rpc/). - -The API is divided into ICS standards for each category of endpoints. For -example, the [ICS20](https://cosmos.network/rpc/#/ICS20/) describes the API to -interact with tokens. - -To give more flexibility to developers, we have included the ability to -generate unsigned transactions, [sign](https://cosmos.network/rpc/#/ICS20/post_tx_sign) -and [broadcast](https://cosmos.network/rpc/#/ICS20/post_tx_broadcast) them with -different API endpoints. This allows service providers to use their own signing -mechanism for instance. - -In order to generate an unsigned transaction (example with -[coin transfer](https://cosmos.network/rpc/#/ICS20/post_bank_accounts__address__transfers)), -you need to use the field `generate_only` in the body of `base_req`. - -## Cosmos SDK Transaction Signing - -Cosmos SDK transaction signing is a fairly simple process. - -Every Cosmos SDK transaction has a canonical JSON representation. The `gaiacli` -and Stargate REST interfaces provide canonical JSON representations of transactions -and their "broadcast" functions will provide compact Amino (a protobuf-like wire format) -encoding translations. - -Things to know when signing messages: - -The format is as follows - -```json -{ - "account_number": XXX, - "chain_id": XXX, - "fee": XXX, - "sequence": XXX, - "memo": XXX, - "msgs": XXX -} -``` - -The signer must supply `"chain_id"`, `"account number"` and `"sequence number"`. - -The `"fee"`, `"msgs"` and `"memo"` fields will be supplied by the transaction -composer interface. - -The `"account_number"` and `"sequence"` fields can be queried directly from the -blockchain or cached locally. Getting these numbers wrong, along with the chainID, -is a common cause of invalid signature error. You can load the mempool of a full -node or validator with a sequence of uncommitted transactions with incrementing -sequence numbers and it will mostly do the correct thing. - -Before signing, all keys are lexicographically sorted and all white space is -removed from the JSON output. - -The signature encoding is the 64-byte concatenation of ECDSArands (i.e. `r || s`), -where `s` is lexicographically less than its inverse in order to prevent malleability. -This is like Ethereum, but without the extra byte for PubKey recovery, since -Tendermint assumes the PubKey is always provided anyway. - -Signatures and public key examples in a signed transaction: - -``` json -{ - "type": "cosmos-sdk/StdTx", - "value": { - "msg": [...], - "signatures": [ - { - "pub_key": { - "type": "tendermint/PubKeySecp256k1", - "value": XXX - }, - "signature": XXX - } - ], - } -} -``` - -Once signatures are properly generated, insert the JSON into into the generated -transaction and then use the broadcast endpoint. diff --git a/docs/intro/README.md b/docs/intro/README.md new file mode 100644 index 000000000000..22ade6bf00a7 --- /dev/null +++ b/docs/intro/README.md @@ -0,0 +1,16 @@ +--- +order: false +parent: + order: 1 +--- + +# Introduction + +This folder contains introduction material on the Cosmos SDK. + +1. [Overview](./overview.md) +2. [Application-Specific Blockchains](./why-app-specific.md) +3. [Architecture of an SDK Application](./sdk-app-architecture.md) +4. [Cosmos SDK Design Overview](./sdk-design.md) + +After reading the introduction material, head over to the [basics](../basics/README.md) to learn more. \ No newline at end of file diff --git a/docs/intro/intro.md b/docs/intro/overview.md similarity index 69% rename from docs/intro/intro.md rename to docs/intro/overview.md index 1b1a6ff7ddd6..94e6d3d6df40 100644 --- a/docs/intro/intro.md +++ b/docs/intro/overview.md @@ -2,13 +2,13 @@ order: 1 --- -# SDK Intro +# High-level Overview ## What is the SDK? -The [Cosmos-SDK](https://github.com/cosmos/cosmos-sdk) is an open-source framework for building multi-asset public Proof-of-Stake (PoS) blockchains, like the Cosmos Hub, as well as permissioned Proof-Of-Authority (PoA) blockchains. Blockchains built with the Cosmos SDK are generally referred to as **application-specific blockchains**. +The [Cosmos-SDK](https://github.com/cosmos/cosmos-sdk) is an open-source framework for building multi-asset public Proof-of-Stake (PoS) blockchains, like the Cosmos Hub, as well as permissioned Proof-Of-Authority (PoA) blockchains. Blockchains built with the Cosmos SDK are generally referred to as **application-specific blockchains**. -The goal of the Cosmos SDK is to allow developers to easily create custom blockchains from scratch that can natively interoperate with other blockchains. We envision the SDK as the npm-like framework to build secure blockchain applications on top of [Tendermint](https://github.com/tendermint/tendermint). SDK-based blockchains are built out of composable modules, most of which are open source and readily available for any developers to use. Anyone can create a module for the Cosmos-SDK, and integrating already-built modules is as simple as importing them into your blockchain application. What's more, the Cosmos SDK is a capabilities-based system, which allows developers to better reason about the security of interactions between modules. For a deeper look at capabilities, jump to [this section](./ocap.md). +The goal of the Cosmos SDK is to allow developers to easily create custom blockchains from scratch that can natively interoperate with other blockchains. We envision the SDK as the npm-like framework to build secure blockchain applications on top of [Tendermint](https://github.com/tendermint/tendermint). SDK-based blockchains are built out of composable [modules](../building-modules/intro.md), most of which are open source and readily available for any developers to use. Anyone can create a module for the Cosmos-SDK, and integrating already-built modules is as simple as importing them into your blockchain application. What's more, the Cosmos SDK is a capabilities-based system, which allows developers to better reason about the security of interactions between modules. For a deeper look at capabilities, jump to [this section](../core/ocap.md). ## What are Application-Specific Blockchains? @@ -16,18 +16,22 @@ One development paradigm in the blockchain world today is that of virtual-machin Application-specific blockchains offer a radically different development paradigm than virtual-machine blockchains. An application-specific blockchain is a blockchain customized to operate a single application: developers have all the freedom to make the design decisions required for the application to run optimally. They can also provide better sovereignty, security and performance. -To learn more about application-specific blockchains, [click here](./why-app-specific.md). +Learn more about [application-specific blockchains](./why-app-specific.md). ## Why the Cosmos SDK? The Cosmos SDK is the most advanced framework for building custom application-specific blockchains today. Here are a few reasons why you might want to consider building your decentralised application with the Cosmos SDK: - The default consensus engine available within the SDK is [Tendermint Core](https://github.com/tendermint/tendermint). Tendermint is the most (and only) mature BFT consensus engine in existence. It is widely used across the industry and is considered the gold standard consensus engine for building Proof-of-Stake systems. -- The SDK is open source and designed to make it easy to build blockchains out of composable modules. As the ecosystem of open source SDK modules grow, it will become increasingly easier to build complex decentralised platforms with it. +- The SDK is open source and designed to make it easy to build blockchains out of composable [modules](../../x/). As the ecosystem of open source SDK modules grows, it will become increasingly easier to build complex decentralised platforms with it. - The SDK is inspired by capabilities-based security, and informed by years of wrestling with blockchain state-machines. This makes the Cosmos SDK a very secure environment to build blockchains. -- Most importantly, the Cosmos SDK has already been used to build many application-specific blockchains that are already in production. Among others, we can cite [Cosmos Hub](https://hub.cosmos.network), [IRIS Hub](https://irisnet.org), [Binance Chain](https://docs.binance.org/), [Terra](https://terra.money/) or [Lino](https://lino.network/). Many more are building on the Cosmos SDK. You can get a view of the ecosystem [here](https://cosmos.network/ecosystem). +- Most importantly, the Cosmos SDK has already been used to build many application-specific blockchains that are already in production. Among others, we can cite [Cosmos Hub](https://hub.cosmos.network), [IRIS Hub](https://irisnet.org), [Binance Chain](https://docs.binance.org/), [Terra](https://terra.money/) or [Lino](https://lino.network/). [Many more](https://cosmos.network/ecosystem) are building on the Cosmos SDK. ## Getting started with the Cosmos SDK - Learn more about the [architecture of an SDK application](./sdk-app-architecture.md) -- Learn how to build an application-specific blockchain from scratch with the [SDK Tutorial](https://cosmos.network/docs/tutorial) \ No newline at end of file +- Learn how to build an application-specific blockchain from scratch with the [SDK Tutorial](https://cosmos.network/docs/tutorial) + +## Next {hide} + +Learn about [application-specific blockchains](./why-app-specific.md) {hide} \ No newline at end of file diff --git a/docs/intro/sdk-app-architecture.md b/docs/intro/sdk-app-architecture.md index ccf84fc48dbe..4f4f0f3e9051 100644 --- a/docs/intro/sdk-app-architecture.md +++ b/docs/intro/sdk-app-architecture.md @@ -2,7 +2,7 @@ order: 3 --- -# SDK Application Architecture +# Blockchain Architecture ## State machine @@ -30,13 +30,13 @@ In practice, the transactions are bundled in blocks to make the process more eff +--------+ +--------+ ``` -In a blockchain context, the state machine is deterministic. This means that if you start at a given state and replay the same sequence of transactions, you will always end up with the same final state. +In a blockchain context, the state machine is deterministic. This means that if a node is started at a given state and replays the same sequence of transactions, it will always end up with the same final state. -The Cosmos SDK gives you maximum flexibility to define the state of your application, transaction types and state transition functions. The process of building the state-machine with the SDK will be described more in depth in the following sections. But first, let us see how it is replicated using **Tendermint**. +The Cosmos SDK gives developers maximum flexibility to define the state of their application, transaction types and state transition functions. The process of building state-machines with the SDK will be described more in depth in the following sections. But first, let us see how the state-machine is replicated using **Tendermint**. -### Tendermint +## Tendermint -As a developer, you just have to define the state machine using the Cosmos-SDK, and [*Tendermint*](https://tendermint.com/docs/introduction/what-is-tendermint.html) will handle replication over the network for you. +Thanks to the Cosmos SDK, develepers just have to define the state machine, and [*Tendermint*](https://tendermint.com/docs/introduction/what-is-tendermint.html) will handle replication over the network for them. ``` @@ -56,16 +56,13 @@ Blockchain node | | Consensus | | ``` -Tendermint is an application-agnostic engine that is responsible for handling the *networking* and *consensus* layers of your blockchain. In practice, this means that Tendermint is responsible for propagating and ordering transaction bytes. Tendermint Core relies on an eponymous Byzantine-Fault-Tolerant (BFT) algorithm to reach consensus on the order of transactions. For more on Tendermint, click [here](https://tendermint.com/docs/introduction/what-is-tendermint.html). +[Tendermint](https://tendermint.com/docs/introduction/what-is-tendermint.html) is an application-agnostic engine that is responsible for handling the *networking* and *consensus* layers of a blockchain. In practice, this means that Tendermint is responsible for propagating and ordering transaction bytes. Tendermint Core relies on an eponymous Byzantine-Fault-Tolerant (BFT) algorithm to reach consensus on the order of transactions. -The Tendermint consensus algorithm works with a set of special nodes called *Validators*. Validators are responsible for adding blocks of transactions to the blockchain. At any given block, there is a validator set V. A validator in V is chosen by the algorithm to be the proposer of the next block. This block is considered valid if more than two thirds of V signed a *[prevote](https://tendermint.com/docs/spec/consensus/consensus.html#prevote-step-height-h-round-r)* and a *[precommit](https://tendermint.com/docs/spec/consensus/consensus.html#precommit-step-height-h-round-r)* on it, and if all the transactions that it contains are valid. The validator set can be changed by rules written in the state-machine. For a deeper look at the algorithm, click [here](https://tendermint.com/docs/introduction/what-is-tendermint.html#consensus-overview). - - -The main part of a Cosmos SDK application is a blockchain daemon that is run by each node in the network locally. If less than one third of the *validator set* is byzantine (i.e. malicious), then each node should obtain the same result when querying the state at the same time. +The Tendermint [consensus algorithm](https://tendermint.com/docs/introduction/what-is-tendermint.html#consensus-overview) works with a set of special nodes called *Validators*. Validators are responsible for adding blocks of transactions to the blockchain. At any given block, there is a validator set V. A validator in V is chosen by the algorithm to be the proposer of the next block. This block is considered valid if more than two thirds of V signed a *[prevote](https://tendermint.com/docs/spec/consensus/consensus.html#prevote-step-height-h-round-r)* and a *[precommit](https://tendermint.com/docs/spec/consensus/consensus.html#precommit-step-height-h-round-r)* on it, and if all the transactions that it contains are valid. The validator set can be changed by rules written in the state-machine. ## ABCI -Tendermint passes transactions from the network to the application through an interface called the [ABCI](https://github.com/tendermint/tendermint/tree/master/abci), which the application must implement. +Tendermint passes transactions to the application through an interface called the [ABCI](https://tendermint.com/docs/spec/abci/), which the application must implement. ``` +---------------------+ @@ -89,12 +86,15 @@ Note that **Tendermint only handles transaction bytes**. It has no knowledge of Here are the most important messages of the ABCI: -- `CheckTx`: When a transaction is received by Tendermint Core, it is passed to the application to check if a few basic requirements are met. `CheckTx` is used to protect the mempool of full-nodes against spam. A special handler called the "Ante Handler" is used to execute a series of validation steps such as checking for sufficient fees and validating the signatures. If the check is valid, the transaction is added to the [mempool](https://tendermint.com/docs/spec/reactors/mempool/functionality.html#mempool-functionality) and relayed to peer nodes. Note that transactions are not processed (i.e. no modification of the state occurs) with `CheckTx` since they have not been included in a block yet. -- `DeliverTx`: When a [valid block](https://tendermint.com/docs/spec/blockchain/blockchain.html#validation) is received by Tendermint Core, each transaction in the given block is passed to the application via `DeliverTx` to be processed. It is during this stage that the state transitions occur. The "Ante Handler" executes again along with the actual handlers for each message in the transaction. +- `CheckTx`: When a transaction is received by Tendermint Core, it is passed to the application to check if a few basic requirements are met. `CheckTx` is used to protect the mempool of full-nodes against spam transactions. A special handler called the [`AnteHandler`](../basics/gas-fees.md#antehandler) is used to execute a series of validation steps such as checking for sufficient fees and validating the signatures. If the checks are valid, the transaction is added to the [mempool](https://tendermint.com/docs/spec/reactors/mempool/functionality.html#mempool-functionality) and relayed to peer nodes. Note that transactions are not processed (i.e. no modification of the state occurs) with `CheckTx` since they have not been included in a block yet. +- `DeliverTx`: When a [valid block](https://tendermint.com/docs/spec/blockchain/blockchain.html#validation) is received by Tendermint Core, each transaction in the block is passed to the application via `DeliverTx` in order to be processed. It is during this stage that the state transitions occur. The `AnteHandler` executes again along with the actual [`handler`s](../building-modules/handler.md) for each message in the transaction. - `BeginBlock`/`EndBlock`: These messages are executed at the beginning and the end of each block, whether the block contains transaction or not. It is useful to trigger automatic execution of logic. Proceed with caution though, as computationally expensive loops could slow down your blockchain, or even freeze it if the loop is infinite. -For a more detailed view of the ABCI methods and types, click [here](https://tendermint.com/docs/spec/abci/abci.html#overview). +Find a more detailed view of the ABCI methods from the [Tendermint docs](https://tendermint.com/docs/spec/abci/abci.html#overview). Any application built on Tendermint needs to implement the ABCI interface in order to communicate with the underlying local Tendermint engine. Fortunately, you do not have to implement the ABCI interface. The Cosmos SDK provides a boilerplate implementation of it in the form of [baseapp](./sdk-design.md#baseapp). -### Next, let us go into the [high-level design principles of the SDK](./sdk-design.md) \ No newline at end of file + +## Next {hide} + +Read about the [high-level design principles of the SDK](./sdk-design.md) {hide} \ No newline at end of file diff --git a/docs/intro/sdk-design.md b/docs/intro/sdk-design.md index 2462bf07a6bc..0b4f9689f6ed 100644 --- a/docs/intro/sdk-design.md +++ b/docs/intro/sdk-design.md @@ -2,9 +2,9 @@ order: 4 --- -# Cosmos SDK design overview +# Main Components of the Cosmos SDK -The Cosmos SDK is a framework that facilitates the development of secure state-machines on top of Tendermint. At its core, the SDK is a boilerplate implementation of the ABCI in Golang. It comes with a `multistore` to persist data and a `router` to handle transactions. +The Cosmos SDK is a framework that facilitates the development of secure state-machines on top of Tendermint. At its core, the SDK is a boilerplate implementation of the [ABCI](./sdk-app-architecture.md#abci) in Golang. It comes with a [`multistore`](../core/store.md#multistore) to persist data and a [`router`](../core/baseapp.md#routing) to handle transactions. Here is a simplified view of how transactions are handled by an application built on top of the Cosmos SDK when transferred from Tendermint via `DeliverTx`: @@ -13,21 +13,21 @@ Here is a simplified view of how transactions are handled by an application buil 3. Route each message to the appropriate module so that it can be processed. 4. Commit state changes. -The application also enables you to generate transactions, encode them and pass them to the underlying Tendermint engine to broadcast them. - ## `baseapp` -`baseApp` is the boilerplate implementation of the ABCI of the Cosmos SDK. It comes with a `router` to route transactions to their respective module. The main `app.go` file of your application will define your custom `app` type that will embed `baseapp`. This way, your custom `app` type will automatically inherit all the ABCI methods of `baseapp`. See an example of this in the [SDK application tutorial](https://github.com/cosmos/sdk-application-tutorial/blob/c6754a1e313eb1ed973c5c91dcc606f2fd288811/app.go#L73). +`baseapp` is the boilerplate implementation of a Cosmos SDK application. It comes with an implementation of the ABCI to handle the connexion with the underlying consensus engine. Typically, a Cosmos SDK application extends `baseapp` by embedding it in [`app.go`](../basics/app-anatomy.md#core-application-file). See an example of this from the SDK application tutorial: + ++++ https://github.com/cosmos/sdk-tutorials/blob/c6754a1e313eb1ed973c5c91dcc606f2fd288811/app.go#L72-L92 The goal of `baseapp` is to provide a secure interface between the store and the extensible state machine while defining as little about the state machine as possible (staying true to the ABCI). -For more on `baseapp`, please click [here](../concepts/baseapp.md). +For more on `baseapp`, please click [here](../core/baseapp.md). ## Multistore - The Cosmos SDK provides a multistore for persisting state. The multistore allows developers to declare any number of [`KVStores`](https://github.com/blocklayerhq/chainkit). These `KVStores` only accept the `[]byte` type as value and therefore any custom structure needs to be marshalled using [go-amino](https://github.com/tendermint/go-amino) before being stored. + The Cosmos SDK provides a [`multistore`](../core/store.md#multisotre) for persisting state. The multistore allows developers to declare any number of [`KVStores`](../core/store.md#base-layer-kvstores). These `KVStores` only accept the `[]byte` type as value and therefore any custom structure needs to be marshalled using [a codec](../core/encoding.md) before being stored. -The multistore abstraction is used to divide the state in distinct compartments, each managed by its own module. For more on the multistore, click [here](../concepts/store.md) +The multistore abstraction is used to divide the state in distinct compartments, each managed by its own module. For more on the multistore, click [here](../core/store.md#multistore) ## Modules @@ -80,7 +80,7 @@ Here is a simplified view of how a transaction is processed by the application o v ``` -Each module can be seen as a little state-machine. Developers need to define the subset of the state handled by the module, as well as custom message types that modify the state (*Note:* `messages` are extracted from `transactions` using `baseapp`). In general, each module declares its own `KVStore` in the multistore to persist the subset of the state it defines. Most developers will need to access other 3rd party modules when building their own modules. Given that the Cosmos-SDK is an open framework, some of the modules may be malicious, which means there is a need for security principles to reason about inter-module interactions. These principles are based on [object-capabilities](../core/ocap.md). In practice, this means that instead of having each module keep an access control list for other modules, each module implements special objects called `keepers` that can be passed to other modules to grant a pre-defined set of capabilities. +Each module can be seen as a little state-machine. Developers need to define the subset of the state handled by the module, as well as custom message types that modify the state (*Note:* `messages` are extracted from `transactions` by `baseapp`). In general, each module declares its own `KVStore` in the `multistore` to persist the subset of the state it defines. Most developers will need to access other 3rd party modules when building their own modules. Given that the Cosmos-SDK is an open framework, some of the modules may be malicious, which means there is a need for security principles to reason about inter-module interactions. These principles are based on [object-capabilities](../core/ocap.md). In practice, this means that instead of having each module keep an access control list for other modules, each module implements special objects called `keepers` that can be passed to other modules to grant a pre-defined set of capabilities. SDK modules are defined in the `x/` folder of the SDK. Some core modules include: @@ -90,5 +90,7 @@ SDK modules are defined in the `x/` folder of the SDK. Some core modules include In addition to the already existing modules in `x/`, that anyone can use in their app, the SDK lets you build your own custom modules. You can check an [example of that in the tutorial](https://cosmos.network/docs/tutorial/keeper.html). +## Next {hide} + +Learn more about the [anatomy of an SDK application](../basics/app-anatomy.md) {hide} -### Next, learn more about the security model of the Cosmos SDK, [ocap](../core/ocap.md) diff --git a/docs/intro/why-app-specific.md b/docs/intro/why-app-specific.md index 54f1169d0071..cd37b562126c 100644 --- a/docs/intro/why-app-specific.md +++ b/docs/intro/why-app-specific.md @@ -30,11 +30,11 @@ Blockchain node | | Consensus | | Virtual-machine blockchains like Ethereum addressed the demand for more programmability back in 2014. At the time, the options available for building decentralised applications were quite limited. Most developers would build on top of the complex and limited Bitcoin scripting language, or fork the Bitcoin codebase which was hard to work with and customize. -Virtual-machine blockchains came in with a new value proposition. Their state-machine incorporates a virtual-machine that is able to interpret turing-complete programs called Smart Contracts. These Smart Contracts are very good for use cases like one-time events (e.g. ICOs), but they can fall short for building complex decentralised platforms: +Virtual-machine blockchains came in with a new value proposition. Their state-machine incorporates a virtual-machine that is able to interpret turing-complete programs called Smart Contracts. These Smart Contracts are very good for use cases like one-time events (e.g. ICOs), but they can fall short for building complex decentralised platforms. Here is why: -- Smart Contracts are generally developed with specific programming languages that can be interpreted by the underlying virtual-machine. These programming languages are often immature and inherently limited by the constraints of the virtual-machine. For example, the Ethereum Virtual Machine does not allow developers to implement automatic execution of code. Developers are also limited to the account-based system of the EVM, and they can only choose from a limited set of functions for their cryptographic operations. These are examples, but they hint at the lack of **flexibility** a smart contract environment often entails. +- Smart Contracts are generally developed with specific programming languages that can be interpreted by the underlying virtual-machine. These programming languages are often immature and inherently limited by the constraints of the virtual-machine itself. For example, the Ethereum Virtual Machine does not allow developers to implement automatic execution of code. Developers are also limited to the account-based system of the EVM, and they can only choose from a limited set of functions for their cryptographic operations. These are examples, but they hint at the lack of **flexibility** that a smart contract environment often entails. - Smart Contracts are all run by the same virtual machine. This means that they compete for resources, which can severly restrain **performance**. And even if the state-machine were to be split in multiple subsets (e.g. via sharding), Smart Contracts would still need to be interpeted by a virtual machine, which would limit performance compared to a native application implemented at state-machine level (our benchmarks show an improvement on the order of x10 in performance when the virtual-machine is removed). -- Another issue with the fact that Smart Contracts share the same underlying environment is the resulting limitation in **sovereignty**. A decentralised application is an ecosystem that involves multiple players. If the application is built on a general-purpose virtual-machine blockchain, these players have very limited sovereignty over it, and are ultimately superseded by the governance of the underlying blockchain. If there is a bug in the application, very little can be done about it. +- Another issue with the fact that Smart Contracts share the same underlying environment is the resulting limitation in **sovereignty**. A decentralised application is an ecosystem that involves multiple players. If the application is built on a general-purpose virtual-machine blockchain, stakeholders have very limited sovereignty over their application, and are ultimately superseded by the governance of the underlying blockchain. If there is a bug in the application, very little can be done about it. Application-Specific Blockchains are designed to address these shortcomings. @@ -46,7 +46,7 @@ Application-specific blockchains give maximum flexibility to developers: - In Cosmos blockchains, the state-machine is typically connected to the underlying consensus engine via an interface called the [ABCI](https://tendermint.com/docs/spec/abci/). This interface can be wrapped in any programming language, meaning developers can build their state-machine in the programming language of their choice. - Developers can choose among multiple frameworks to build their state-machine. The most widely used today is the Cosmos SDK, but others exist (e.g. [Lotion](https://github.com/nomic-io/lotion), [Weave](https://github.com/iov-one/weave), ...). The choice will most of the time be done based on the programming language they want to use (Cosmos SDK and Weave are in Golang, Lotion is in Javascript, ...). -- The ABCI also allows developers to swap the consensus engine of their application-specific blockchain. Today, only Tendermint is production-ready, but in the future other engines are expected to emerge. +- The ABCI also allows developers to swap the consensus engine of their application-specific blockchain. Today, only Tendermint is production-ready, but in the future other consensus engines are expected to emerge. - Even when they settle for a framework and consensus engine, developers still have the freedom to tweak them if they don't perfectly match their requirements in their pristine forms. - Developers are free to explore the full spectrum of tradeoffs (e.g. number of validators vs transaction throughput, safety vs availability in asynchrony, ...) and design choices (DB or IAVL tree for storage, UTXO or account model, ...). - Developers can implement automatic execution of code. In the Cosmos SDK, logic can be automatically triggered at the beginning and the end of each block. They are also free to choose the cryptographic library used in their application, as opposed to being constrained by what is made available by the underlying environment in the case of virtual-machine blockchains. @@ -55,7 +55,7 @@ The list above contains a few examples that show how much flexibility applicatio ### Performance -Decentralised applications built with Smart Contracts are inherently capped in performance by the underlying environment. For a decentralised application to optimise performance, it needs to be built as an application-specific blockchains. Here are the benefits of an application-specific blockchains with regards to performance: +Decentralised applications built with Smart Contracts are inherently capped in performance by the underlying environment. For a decentralised application to optimise performance, it needs to be built as an application-specific blockchains. Next are some of the benefits an application-specific blockchains brings in terms of performance: - Developers of application-specific blockchains can choose to operate with novel consensus engine such as Tendermint BFT. Compared to Proof-of-Work (used by most virtual-machine blockchains today), it offers significant gains in throuhgput. - An application-specific blockchain only operates a single application, so that the application does not compete with others for computation and storage. This is the opposite of most non-sharded virtual-machine blockchains today, where smart contracts all compete for computation and storage. @@ -71,13 +71,10 @@ Security is hard to quantify, and greatly varies from platform to platform. That ### Sovereignty -One of the major benefits of application-specific blockchains is sovereignty. A decentralised application is an ecosystem that involves many actors: users, developers, third-party services, and more. When developers build on virtual-machine blockchain where many decentralised applications coexist, the community of the application is different than the community of the underlying blockchain, and the latter supersedes the former. If there is a bug or if a new feature is needed, the community of the application has very little sovereignty to upgrade the code. If the community of the underlying blockchain refuses to act, nothing can happen. +One of the major benefits of application-specific blockchains is sovereignty. A decentralised application is an ecosystem that involves many actors: users, developers, third-party services, and more. When developers build on virtual-machine blockchain where many decentralised applications coexist, the community of the application is different than the community of the underlying blockchain, and the latter supersedes the former in the governance process. If there is a bug or if a new feature is needed, stakeholders of the application have very little leeway to upgrade the code. If the community of the underlying blockchain refuses to act, nothing can happen. -The fundamental issue here is that the governance of the application and the governance of the network are not aligned. This issue is solved by application-specific blockchains. Because application-specific blockchains specialize to operate a single application, the community of the application has full control over the entire chain. This ensures the community will not be stuck if a bug is discovered, and that it has the entire freedom to choose how it is going to evolve. +The fundamental issue here is that the governance of the application and the governance of the network are not aligned. This issue is solved by application-specific blockchains. Because application-specific blockchains specialize to operate a single application, stakeholders the application has full control over the entire chain. This ensures the community will not be stuck if a bug is discovered, and that it has the entire freedom to choose how it is going to evolve. -## Start Building Your Application-Specific Blockchain Today +## Next {hide} -Clearly, application-specific blockchains are awesome. The Cosmos SDK makes it easier than ever to build them. What are you waiting for? - -- Learn more about the [high-level architecture](./sdk-app-architecture) of an SDK application. -- Learn how to build an application-specific blockchain from scratch with the [SDK tutorial](https://cosmos.network/docs/tutorial) +Learn more about the [high-level architecture](./sdk-app-architecture.md) of an SDK application {hide} diff --git a/docs/kr/README.md b/docs/kr/README.md index 5ac84b1455ee..86c60314bd7a 100755 --- a/docs/kr/README.md +++ b/docs/kr/README.md @@ -1,3 +1,8 @@ +--- +parent: + order: false +--- + # 코스모스 SDK 문서에 오신 걸 환영합니다! ::: warning diff --git a/docs/package-lock.json b/docs/package-lock.json index 52587236f7bc..1100a982c2a5 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -5,271 +5,289 @@ "requires": true, "dependencies": { "@babel/code-frame": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", - "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", - "dev": true, + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", + "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", "requires": { "@babel/highlight": "^7.0.0" } }, "@babel/core": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.4.5.tgz", - "integrity": "sha512-OvjIh6aqXtlsA8ujtGKfC7LYWksYSX8yQcM8Ay3LuvVeQ63lcOKgoZWVqcpFwkd29aYU9rVx7jxhfhiEDV9MZA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.4.4", - "@babel/helpers": "^7.4.4", - "@babel/parser": "^7.4.5", - "@babel/template": "^7.4.4", - "@babel/traverse": "^7.4.5", - "@babel/types": "^7.4.4", - "convert-source-map": "^1.1.0", + "version": "7.7.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.7.5.tgz", + "integrity": "sha512-M42+ScN4+1S9iB6f+TL7QBpoQETxbclx+KNoKJABghnKYE+fMzSGqst0BZJc8CpI625bwPwYgUyRvxZ+0mZzpw==", + "requires": { + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.7.4", + "@babel/helpers": "^7.7.4", + "@babel/parser": "^7.7.5", + "@babel/template": "^7.7.4", + "@babel/traverse": "^7.7.4", + "@babel/types": "^7.7.4", + "convert-source-map": "^1.7.0", "debug": "^4.1.0", "json5": "^2.1.0", - "lodash": "^4.17.11", + "lodash": "^4.17.13", "resolve": "^1.3.2", "semver": "^5.4.1", "source-map": "^0.5.0" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "json5": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.1.tgz", + "integrity": "sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==", + "requires": { + "minimist": "^1.2.0" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + } } }, "@babel/generator": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.4.4.tgz", - "integrity": "sha512-53UOLK6TVNqKxf7RUh8NE851EHRxOOeVXKbK2bivdb+iziMyk03Sr4eaE9OELCbyZAAafAKPDwF2TPUES5QbxQ==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.7.4.tgz", + "integrity": "sha512-m5qo2WgdOJeyYngKImbkyQrnUN1mPceaG5BV+G0E3gWsa4l/jCSryWJdM2x8OuGAOyh+3d5pVYfZWCiNFtynxg==", "requires": { - "@babel/types": "^7.4.4", + "@babel/types": "^7.7.4", "jsesc": "^2.5.1", - "lodash": "^4.17.11", - "source-map": "^0.5.0", - "trim-right": "^1.0.1" + "lodash": "^4.17.13", + "source-map": "^0.5.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + } } }, "@babel/helper-annotate-as-pure": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz", - "integrity": "sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.7.4.tgz", + "integrity": "sha512-2BQmQgECKzYKFPpiycoF9tlb5HA4lrVyAmLLVK177EcQAqjVLciUb2/R+n1boQ9y5ENV3uz2ZqiNw7QMBBw1Og==", "requires": { - "@babel/types": "^7.0.0" + "@babel/types": "^7.7.4" } }, "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz", - "integrity": "sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.7.4.tgz", + "integrity": "sha512-Biq/d/WtvfftWZ9Uf39hbPBYDUo986m5Bb4zhkeYDGUllF43D+nUe5M6Vuo6/8JDK/0YX/uBdeoQpyaNhNugZQ==", "requires": { - "@babel/helper-explode-assignable-expression": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/helper-explode-assignable-expression": "^7.7.4", + "@babel/types": "^7.7.4" } }, "@babel/helper-call-delegate": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.4.4.tgz", - "integrity": "sha512-l79boDFJ8S1c5hvQvG+rc+wHw6IuH7YldmRKsYtpbawsxURu/paVy57FZMomGK22/JckepaikOkY0MoAmdyOlQ==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.7.4.tgz", + "integrity": "sha512-8JH9/B7J7tCYJ2PpWVpw9JhPuEVHztagNVuQAFBVFYluRMlpG7F1CgKEgGeL6KFqcsIa92ZYVj6DSc0XwmN1ZA==", "requires": { - "@babel/helper-hoist-variables": "^7.4.4", - "@babel/traverse": "^7.4.4", - "@babel/types": "^7.4.4" + "@babel/helper-hoist-variables": "^7.7.4", + "@babel/traverse": "^7.7.4", + "@babel/types": "^7.7.4" } }, "@babel/helper-create-class-features-plugin": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.4.4.tgz", - "integrity": "sha512-UbBHIa2qeAGgyiNR9RszVF7bUHEdgS4JAUNT8SiqrAN6YJVxlOxeLr5pBzb5kan302dejJ9nla4RyKcR1XT6XA==", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-member-expression-to-functions": "^7.0.0", - "@babel/helper-optimise-call-expression": "^7.0.0", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.7.4.tgz", + "integrity": "sha512-l+OnKACG4uiDHQ/aJT8dwpR+LhCJALxL0mJ6nzjB25e5IPwqV1VOsY7ah6UB1DG+VOXAIMtuC54rFJGiHkxjgA==", + "requires": { + "@babel/helper-function-name": "^7.7.4", + "@babel/helper-member-expression-to-functions": "^7.7.4", + "@babel/helper-optimise-call-expression": "^7.7.4", "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.4.4", - "@babel/helper-split-export-declaration": "^7.4.4" + "@babel/helper-replace-supers": "^7.7.4", + "@babel/helper-split-export-declaration": "^7.7.4" + } + }, + "@babel/helper-create-regexp-features-plugin": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.7.4.tgz", + "integrity": "sha512-Mt+jBKaxL0zfOIWrfQpnfYCN7/rS6GKx6CCCfuoqVVd+17R8zNDlzVYmIi9qyb2wOk002NsmSTDymkIygDUH7A==", + "requires": { + "@babel/helper-regex": "^7.4.4", + "regexpu-core": "^4.6.0" } }, "@babel/helper-define-map": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.4.4.tgz", - "integrity": "sha512-IX3Ln8gLhZpSuqHJSnTNBWGDE9kdkTEWl21A/K7PQ00tseBwbqCHTvNLHSBd9M0R5rER4h5Rsvj9vw0R5SieBg==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.7.4.tgz", + "integrity": "sha512-v5LorqOa0nVQUvAUTUF3KPastvUt/HzByXNamKQ6RdJRTV7j8rLL+WB5C/MzzWAwOomxDhYFb1wLLxHqox86lg==", "requires": { - "@babel/helper-function-name": "^7.1.0", - "@babel/types": "^7.4.4", - "lodash": "^4.17.11" + "@babel/helper-function-name": "^7.7.4", + "@babel/types": "^7.7.4", + "lodash": "^4.17.13" } }, "@babel/helper-explode-assignable-expression": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz", - "integrity": "sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.7.4.tgz", + "integrity": "sha512-2/SicuFrNSXsZNBxe5UGdLr+HZg+raWBLE9vC98bdYOKX/U6PY0mdGlYUJdtTDPSU0Lw0PNbKKDpwYHJLn2jLg==", "requires": { - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/traverse": "^7.7.4", + "@babel/types": "^7.7.4" } }, "@babel/helper-function-name": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", - "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.7.4.tgz", + "integrity": "sha512-AnkGIdiBhEuiwdoMnKm7jfPfqItZhgRaZfMg1XX3bS25INOnLPjPG1Ppnajh8eqgt5kPJnfqrRHqFqmjKDZLzQ==", "requires": { - "@babel/helper-get-function-arity": "^7.0.0", - "@babel/template": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/helper-get-function-arity": "^7.7.4", + "@babel/template": "^7.7.4", + "@babel/types": "^7.7.4" } }, "@babel/helper-get-function-arity": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", - "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.7.4.tgz", + "integrity": "sha512-QTGKEdCkjgzgfJ3bAyRwF4yyT3pg+vDgan8DSivq1eS0gwi+KGKE5x8kRcbeFTb/673mkO5SN1IZfmCfA5o+EA==", "requires": { - "@babel/types": "^7.0.0" + "@babel/types": "^7.7.4" } }, "@babel/helper-hoist-variables": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.4.4.tgz", - "integrity": "sha512-VYk2/H/BnYbZDDg39hr3t2kKyifAm1W6zHRfhx8jGjIHpQEBv9dry7oQ2f3+J703TLu69nYdxsovl0XYfcnK4w==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.7.4.tgz", + "integrity": "sha512-wQC4xyvc1Jo/FnLirL6CEgPgPCa8M74tOdjWpRhQYapz5JC7u3NYU1zCVoVAGCE3EaIP9T1A3iW0WLJ+reZlpQ==", "requires": { - "@babel/types": "^7.4.4" + "@babel/types": "^7.7.4" } }, "@babel/helper-member-expression-to-functions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.0.0.tgz", - "integrity": "sha512-avo+lm/QmZlv27Zsi0xEor2fKcqWG56D5ae9dzklpIaY7cQMK5N8VSpaNVPPagiqmy7LrEjK1IWdGMOqPu5csg==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.7.4.tgz", + "integrity": "sha512-9KcA1X2E3OjXl/ykfMMInBK+uVdfIVakVe7W7Lg3wfXUNyS3Q1HWLFRwZIjhqiCGbslummPDnmb7vIekS0C1vw==", "requires": { - "@babel/types": "^7.0.0" + "@babel/types": "^7.7.4" } }, "@babel/helper-module-imports": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz", - "integrity": "sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.7.4.tgz", + "integrity": "sha512-dGcrX6K9l8258WFjyDLJwuVKxR4XZfU0/vTUgOQYWEnRD8mgr+p4d6fCUMq/ys0h4CCt/S5JhbvtyErjWouAUQ==", "requires": { - "@babel/types": "^7.0.0" + "@babel/types": "^7.7.4" } }, "@babel/helper-module-transforms": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.4.4.tgz", - "integrity": "sha512-3Z1yp8TVQf+B4ynN7WoHPKS8EkdTbgAEy0nU0rs/1Kw4pDgmvYH3rz3aI11KgxKCba2cn7N+tqzV1mY2HMN96w==", - "dev": true, + "version": "7.7.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.7.5.tgz", + "integrity": "sha512-A7pSxyJf1gN5qXVcidwLWydjftUN878VkalhXX5iQDuGyiGK3sOrrKKHF4/A4fwHtnsotv/NipwAeLzY4KQPvw==", "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/helper-simple-access": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.4.4", - "@babel/template": "^7.4.4", - "@babel/types": "^7.4.4", - "lodash": "^4.17.11" + "@babel/helper-module-imports": "^7.7.4", + "@babel/helper-simple-access": "^7.7.4", + "@babel/helper-split-export-declaration": "^7.7.4", + "@babel/template": "^7.7.4", + "@babel/types": "^7.7.4", + "lodash": "^4.17.13" } }, "@babel/helper-optimise-call-expression": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz", - "integrity": "sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.7.4.tgz", + "integrity": "sha512-VB7gWZ2fDkSuqW6b1AKXkJWO5NyNI3bFL/kK79/30moK57blr6NbH8xcl2XcKCwOmJosftWunZqfO84IGq3ZZg==", "requires": { - "@babel/types": "^7.0.0" + "@babel/types": "^7.7.4" } }, "@babel/helper-plugin-utils": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz", - "integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==", - "dev": true + "integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==" }, "@babel/helper-regex": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.4.4.tgz", - "integrity": "sha512-Y5nuB/kESmR3tKjU8Nkn1wMGEx1tjJX076HBMeL3XLQCu6vA/YRzuTW0bbb+qRnXvQGn+d6Rx953yffl8vEy7Q==", - "dev": true, + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.5.5.tgz", + "integrity": "sha512-CkCYQLkfkiugbRDO8eZn6lRuR8kzZoGXCg3149iTk5se7g6qykSpy3+hELSwquhu+TgHn8nkLiBwHvNX8Hofcw==", "requires": { - "lodash": "^4.17.11" + "lodash": "^4.17.13" } }, "@babel/helper-remap-async-to-generator": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz", - "integrity": "sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.7.4.tgz", + "integrity": "sha512-Sk4xmtVdM9sA/jCI80f+KS+Md+ZHIpjuqmYPk1M7F/upHou5e4ReYmExAiu6PVe65BhJPZA2CY9x9k4BqE5klw==", "requires": { - "@babel/helper-annotate-as-pure": "^7.0.0", - "@babel/helper-wrap-function": "^7.1.0", - "@babel/template": "^7.1.0", - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/helper-annotate-as-pure": "^7.7.4", + "@babel/helper-wrap-function": "^7.7.4", + "@babel/template": "^7.7.4", + "@babel/traverse": "^7.7.4", + "@babel/types": "^7.7.4" } }, "@babel/helper-replace-supers": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.4.4.tgz", - "integrity": "sha512-04xGEnd+s01nY1l15EuMS1rfKktNF+1CkKmHoErDppjAAZL+IUBZpzT748x262HF7fibaQPhbvWUl5HeSt1EXg==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.7.4.tgz", + "integrity": "sha512-pP0tfgg9hsZWo5ZboYGuBn/bbYT/hdLPVSS4NMmiRJdwWhP0IznPwN9AE1JwyGsjSPLC364I0Qh5p+EPkGPNpg==", "requires": { - "@babel/helper-member-expression-to-functions": "^7.0.0", - "@babel/helper-optimise-call-expression": "^7.0.0", - "@babel/traverse": "^7.4.4", - "@babel/types": "^7.4.4" + "@babel/helper-member-expression-to-functions": "^7.7.4", + "@babel/helper-optimise-call-expression": "^7.7.4", + "@babel/traverse": "^7.7.4", + "@babel/types": "^7.7.4" } }, "@babel/helper-simple-access": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz", - "integrity": "sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.7.4.tgz", + "integrity": "sha512-zK7THeEXfan7UlWsG2A6CI/L9jVnI5+xxKZOdej39Y0YtDYKx9raHk5F2EtK9K8DHRTihYwg20ADt9S36GR78A==", "requires": { - "@babel/template": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/template": "^7.7.4", + "@babel/types": "^7.7.4" } }, "@babel/helper-split-export-declaration": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz", - "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.7.4.tgz", + "integrity": "sha512-guAg1SXFcVr04Guk9eq0S4/rWS++sbmyqosJzVs8+1fH5NI+ZcmkaSkc7dmtAFbHFva6yRJnjW3yAcGxjueDug==", "requires": { - "@babel/types": "^7.4.4" + "@babel/types": "^7.7.4" } }, "@babel/helper-wrap-function": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz", - "integrity": "sha512-o9fP1BZLLSrYlxYEYyl2aS+Flun5gtjTIG8iln+XuEzQTs0PLagAGSXUcqruJwD5fM48jzIEggCKpIfWTcR7pQ==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.7.4.tgz", + "integrity": "sha512-VsfzZt6wmsocOaVU0OokwrIytHND55yvyT4BPB9AIIgwr8+x7617hetdJTsuGwygN5RC6mxA9EJztTjuwm2ofg==", "requires": { - "@babel/helper-function-name": "^7.1.0", - "@babel/template": "^7.1.0", - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.2.0" + "@babel/helper-function-name": "^7.7.4", + "@babel/template": "^7.7.4", + "@babel/traverse": "^7.7.4", + "@babel/types": "^7.7.4" } }, "@babel/helpers": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.4.4.tgz", - "integrity": "sha512-igczbR/0SeuPR8RFfC7tGrbdTbFL3QTvH6D+Z6zNxnTe//GyqmtHmDkzrqDmyZ3eSwPqB/LhyKoU5DXsp+Vp2A==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.7.4.tgz", + "integrity": "sha512-ak5NGZGJ6LV85Q1Zc9gn2n+ayXOizryhjSUBTdu5ih1tlVCJeuQENzc4ItyCVhINVXvIT/ZQ4mheGIsfBkpskg==", "requires": { - "@babel/template": "^7.4.4", - "@babel/traverse": "^7.4.4", - "@babel/types": "^7.4.4" + "@babel/template": "^7.7.4", + "@babel/traverse": "^7.7.4", + "@babel/types": "^7.7.4" } }, "@babel/highlight": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", - "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", - "dev": true, + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", + "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", "requires": { "chalk": "^2.0.0", "esutils": "^2.0.2", @@ -277,442 +295,397 @@ } }, "@babel/parser": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.4.5.tgz", - "integrity": "sha512-9mUqkL1FF5T7f0WDFfAoDdiMVPWsdD1gZYzSnaXsxUCUqzuch/8of9G3VUSNiZmMBoRxT3neyVsqeiL/ZPcjew==", - "dev": true + "version": "7.7.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.5.tgz", + "integrity": "sha512-KNlOe9+/nk4i29g0VXgl8PEXIRms5xKLJeuZ6UptN0fHv+jDiriG+y94X6qAgWTR0h3KaoM1wK5G5h7MHFRSig==" }, "@babel/plugin-proposal-async-generator-functions": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz", - "integrity": "sha512-+Dfo/SCQqrwx48ptLVGLdE39YtWRuKc/Y9I5Fy0P1DDBB9lsAHpjcEJQt+4IifuSOSTLBKJObJqMvaO1pIE8LQ==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.7.4.tgz", + "integrity": "sha512-1ypyZvGRXriY/QP668+s8sFr2mqinhkRDMPSQLNghCQE+GAkFtp+wkHVvg2+Hdki8gwP+NFzJBJ/N1BfzCCDEw==", "requires": { "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-remap-async-to-generator": "^7.1.0", - "@babel/plugin-syntax-async-generators": "^7.2.0" + "@babel/helper-remap-async-to-generator": "^7.7.4", + "@babel/plugin-syntax-async-generators": "^7.7.4" } }, "@babel/plugin-proposal-class-properties": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.4.4.tgz", - "integrity": "sha512-WjKTI8g8d5w1Bc9zgwSz2nfrsNQsXcCf9J9cdCvrJV6RF56yztwm4TmJC0MgJ9tvwO9gUA/mcYe89bLdGfiXFg==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.7.4.tgz", + "integrity": "sha512-EcuXeV4Hv1X3+Q1TsuOmyyxeTRiSqurGJ26+I/FW1WbymmRRapVORm6x1Zl3iDIHyRxEs+VXWp6qnlcfcJSbbw==", "requires": { - "@babel/helper-create-class-features-plugin": "^7.4.4", + "@babel/helper-create-class-features-plugin": "^7.7.4", "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-proposal-decorators": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.4.4.tgz", - "integrity": "sha512-z7MpQz3XC/iQJWXH9y+MaWcLPNSMY9RQSthrLzak8R8hCj0fuyNk+Dzi9kfNe/JxxlWQ2g7wkABbgWjW36MTcw==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.7.4.tgz", + "integrity": "sha512-GftcVDcLCwVdzKmwOBDjATd548+IE+mBo7ttgatqNDR7VG7GqIuZPtRWlMLHbhTXhcnFZiGER8iIYl1n/imtsg==", "requires": { - "@babel/helper-create-class-features-plugin": "^7.4.4", + "@babel/helper-create-class-features-plugin": "^7.7.4", "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-decorators": "^7.2.0" + "@babel/plugin-syntax-decorators": "^7.7.4" } }, "@babel/plugin-proposal-json-strings": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.2.0.tgz", - "integrity": "sha512-MAFV1CA/YVmYwZG0fBQyXhmj0BHCB5egZHCKWIFVv/XCxAeVGIHfos3SwDck4LvCllENIAg7xMKOG5kH0dzyUg==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.7.4.tgz", + "integrity": "sha512-wQvt3akcBTfLU/wYoqm/ws7YOAQKu8EVJEvHip/mzkNtjaclQoCCIqKXFP5/eyfnfbQCDV3OLRIK3mIVyXuZlw==", "requires": { "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-json-strings": "^7.2.0" + "@babel/plugin-syntax-json-strings": "^7.7.4" } }, "@babel/plugin-proposal-object-rest-spread": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.4.4.tgz", - "integrity": "sha512-dMBG6cSPBbHeEBdFXeQ2QLc5gUpg4Vkaz8octD4aoW/ISO+jBOcsuxYL7bsb5WSu8RLP6boxrBIALEHgoHtO9g==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.7.4.tgz", + "integrity": "sha512-rnpnZR3/iWKmiQyJ3LKJpSwLDcX/nSXhdLk4Aq/tXOApIvyu7qoabrige0ylsAJffaUC51WiBu209Q0U+86OWQ==", "requires": { "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-object-rest-spread": "^7.2.0" + "@babel/plugin-syntax-object-rest-spread": "^7.7.4" } }, "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.2.0.tgz", - "integrity": "sha512-mgYj3jCcxug6KUcX4OBoOJz3CMrwRfQELPQ5560F70YQUBZB7uac9fqaWamKR1iWUzGiK2t0ygzjTScZnVz75g==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.7.4.tgz", + "integrity": "sha512-DyM7U2bnsQerCQ+sejcTNZh8KQEUuC3ufzdnVnSiUv/qoGJp2Z3hanKL18KDhsBT5Wj6a7CMT5mdyCNJsEaA9w==", "requires": { "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-optional-catch-binding": "^7.2.0" + "@babel/plugin-syntax-optional-catch-binding": "^7.7.4" } }, "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.4.4.tgz", - "integrity": "sha512-j1NwnOqMG9mFUOH58JTFsA/+ZYzQLUZ/drqWUqxCYLGeu2JFZL8YrNC9hBxKmWtAuOCHPcRpgv7fhap09Fb4kA==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.7.4.tgz", + "integrity": "sha512-cHgqHgYvffluZk85dJ02vloErm3Y6xtH+2noOBOJ2kXOJH3aVCDnj5eR/lVNlTnYu4hndAPJD3rTFjW3qee0PA==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-regex": "^7.4.4", - "regexpu-core": "^4.5.4" + "@babel/helper-create-regexp-features-plugin": "^7.7.4", + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-syntax-async-generators": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.2.0.tgz", - "integrity": "sha512-1ZrIRBv2t0GSlcwVoQ6VgSLpLgiN/FVQUzt9znxo7v2Ov4jJrs8RY8tv0wvDmFN3qIdMKWrmMMW6yZ0G19MfGg==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.7.4.tgz", + "integrity": "sha512-Li4+EjSpBgxcsmeEF8IFcfV/+yJGxHXDirDkEoyFjumuwbmfCVHUt0HuowD/iGM7OhIRyXJH9YXxqiH6N815+g==", "requires": { "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-syntax-decorators": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.2.0.tgz", - "integrity": "sha512-38QdqVoXdHUQfTpZo3rQwqQdWtCn5tMv4uV6r2RMfTqNBuv4ZBhz79SfaQWKTVmxHjeFv/DnXVC/+agHCklYWA==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.7.4.tgz", + "integrity": "sha512-0oNLWNH4k5ZbBVfAwiTU53rKFWIeTh6ZlaWOXWJc4ywxs0tjz5fc3uZ6jKAnZSxN98eXVgg7bJIuzjX+3SXY+A==", "requires": { "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-syntax-dynamic-import": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.2.0.tgz", - "integrity": "sha512-mVxuJ0YroI/h/tbFTPGZR8cv6ai+STMKNBq0f8hFxsxWjl94qqhsb+wXbpNMDPU3cfR1TIsVFzU3nXyZMqyK4w==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.7.4.tgz", + "integrity": "sha512-jHQW0vbRGvwQNgyVxwDh4yuXu4bH1f5/EICJLAhl1SblLs2CDhrsmCk+v5XLdE9wxtAFRyxx+P//Iw+a5L/tTg==", "requires": { "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-syntax-json-strings": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.2.0.tgz", - "integrity": "sha512-5UGYnMSLRE1dqqZwug+1LISpA403HzlSfsg6P9VXU6TBjcSHeNlw4DxDx7LgpF+iKZoOG/+uzqoRHTdcUpiZNg==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.7.4.tgz", + "integrity": "sha512-QpGupahTQW1mHRXddMG5srgpHWqRLwJnJZKXTigB9RPFCCGbDGCgBeM/iC82ICXp414WeYx/tD54w7M2qRqTMg==", "requires": { "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-syntax-jsx": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.2.0.tgz", - "integrity": "sha512-VyN4QANJkRW6lDBmENzRszvZf3/4AXaj9YR7GwrWeeN9tEBPuXbmDYVU9bYBN0D70zCWVwUy0HWq2553VCb6Hw==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.7.4.tgz", + "integrity": "sha512-wuy6fiMe9y7HeZBWXYCGt2RGxZOj0BImZ9EyXJVnVGBKO/Br592rbR3rtIQn0eQhAk9vqaKP5n8tVqEFBQMfLg==", "requires": { "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-syntax-object-rest-spread": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz", - "integrity": "sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.7.4.tgz", + "integrity": "sha512-mObR+r+KZq0XhRVS2BrBKBpr5jqrqzlPvS9C9vuOf5ilSwzloAl7RPWLrgKdWS6IreaVrjHxTjtyqFiOisaCwg==", "requires": { "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.2.0.tgz", - "integrity": "sha512-bDe4xKNhb0LI7IvZHiA13kff0KEfaGX/Hv4lMA9+7TEc63hMNvfKo6ZFpXhKuEp+II/q35Gc4NoMeDZyaUbj9w==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.7.4.tgz", + "integrity": "sha512-4ZSuzWgFxqHRE31Glu+fEr/MirNZOMYmD/0BhBWyLyOOQz/gTAl7QmWm2hX1QxEIXsr2vkdlwxIzTyiYRC4xcQ==", "requires": { "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-arrow-functions": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.2.0.tgz", - "integrity": "sha512-ER77Cax1+8/8jCB9fo4Ud161OZzWN5qawi4GusDuRLcDbDG+bIGYY20zb2dfAFdTRGzrfq2xZPvF0R64EHnimg==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.7.4.tgz", + "integrity": "sha512-zUXy3e8jBNPiffmqkHRNDdZM2r8DWhCB7HhcoyZjiK1TxYEluLHAvQuYnTT+ARqRpabWqy/NHkO6e3MsYB5YfA==", "requires": { "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-async-to-generator": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.4.4.tgz", - "integrity": "sha512-YiqW2Li8TXmzgbXw+STsSqPBPFnGviiaSp6CYOq55X8GQ2SGVLrXB6pNid8HkqkZAzOH6knbai3snhP7v0fNwA==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.7.4.tgz", + "integrity": "sha512-zpUTZphp5nHokuy8yLlyafxCJ0rSlFoSHypTUWgpdwoDXWQcseaect7cJ8Ppk6nunOM6+5rPMkod4OYKPR5MUg==", "requires": { - "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-module-imports": "^7.7.4", "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-remap-async-to-generator": "^7.1.0" + "@babel/helper-remap-async-to-generator": "^7.7.4" } }, "@babel/plugin-transform-block-scoped-functions": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.2.0.tgz", - "integrity": "sha512-ntQPR6q1/NKuphly49+QiQiTN0O63uOwjdD6dhIjSWBI5xlrbUFh720TIpzBhpnrLfv2tNH/BXvLIab1+BAI0w==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.7.4.tgz", + "integrity": "sha512-kqtQzwtKcpPclHYjLK//3lH8OFsCDuDJBaFhVwf8kqdnF6MN4l618UDlcA7TfRs3FayrHj+svYnSX8MC9zmUyQ==", "requires": { "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-block-scoping": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.4.4.tgz", - "integrity": "sha512-jkTUyWZcTrwxu5DD4rWz6rDB5Cjdmgz6z7M7RLXOJyCUkFBawssDGcGh8M/0FTSB87avyJI1HsTwUXp9nKA1PA==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.7.4.tgz", + "integrity": "sha512-2VBe9u0G+fDt9B5OV5DQH4KBf5DoiNkwFKOz0TCvBWvdAN2rOykCTkrL+jTLxfCAm76l9Qo5OqL7HBOx2dWggg==", "requires": { "@babel/helper-plugin-utils": "^7.0.0", - "lodash": "^4.17.11" + "lodash": "^4.17.13" } }, "@babel/plugin-transform-classes": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.4.4.tgz", - "integrity": "sha512-/e44eFLImEGIpL9qPxSRat13I5QNRgBLu2hOQJCF7VLy/otSM/sypV1+XaIw5+502RX/+6YaSAPmldk+nhHDPw==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.0.0", - "@babel/helper-define-map": "^7.4.4", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-optimise-call-expression": "^7.0.0", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.7.4.tgz", + "integrity": "sha512-sK1mjWat7K+buWRuImEzjNf68qrKcrddtpQo3swi9j7dUcG6y6R6+Di039QN2bD1dykeswlagupEmpOatFHHUg==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.7.4", + "@babel/helper-define-map": "^7.7.4", + "@babel/helper-function-name": "^7.7.4", + "@babel/helper-optimise-call-expression": "^7.7.4", "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.4.4", - "@babel/helper-split-export-declaration": "^7.4.4", + "@babel/helper-replace-supers": "^7.7.4", + "@babel/helper-split-export-declaration": "^7.7.4", "globals": "^11.1.0" } }, "@babel/plugin-transform-computed-properties": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.2.0.tgz", - "integrity": "sha512-kP/drqTxY6Xt3NNpKiMomfgkNn4o7+vKxK2DDKcBG9sHj51vHqMBGy8wbDS/J4lMxnqs153/T3+DmCEAkC5cpA==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.7.4.tgz", + "integrity": "sha512-bSNsOsZnlpLLyQew35rl4Fma3yKWqK3ImWMSC/Nc+6nGjC9s5NFWAer1YQ899/6s9HxO2zQC1WoFNfkOqRkqRQ==", "requires": { "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-destructuring": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.4.4.tgz", - "integrity": "sha512-/aOx+nW0w8eHiEHm+BTERB2oJn5D127iye/SUQl7NjHy0lf+j7h4MKMMSOwdazGq9OxgiNADncE+SRJkCxjZpQ==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.7.4.tgz", + "integrity": "sha512-4jFMXI1Cu2aXbcXXl8Lr6YubCn6Oc7k9lLsu8v61TZh+1jny2BWmdtvY9zSUlLdGUvcy9DMAWyZEOqjsbeg/wA==", "requires": { "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-dotall-regex": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.4.4.tgz", - "integrity": "sha512-P05YEhRc2h53lZDjRPk/OektxCVevFzZs2Gfjd545Wde3k+yFDbXORgl2e0xpbq8mLcKJ7Idss4fAg0zORN/zg==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.7.4.tgz", + "integrity": "sha512-mk0cH1zyMa/XHeb6LOTXTbG7uIJ8Rrjlzu91pUx/KS3JpcgaTDwMS8kM+ar8SLOvlL2Lofi4CGBAjCo3a2x+lw==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-regex": "^7.4.4", - "regexpu-core": "^4.5.4" + "@babel/helper-create-regexp-features-plugin": "^7.7.4", + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-duplicate-keys": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.2.0.tgz", - "integrity": "sha512-q+yuxW4DsTjNceUiTzK0L+AfQ0zD9rWaTLiUqHA8p0gxx7lu1EylenfzjeIWNkPy6e/0VG/Wjw9uf9LueQwLOw==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.7.4.tgz", + "integrity": "sha512-g1y4/G6xGWMD85Tlft5XedGaZBCIVN+/P0bs6eabmcPP9egFleMAo65OOjlhcz1njpwagyY3t0nsQC9oTFegJA==", "requires": { "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-exponentiation-operator": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.2.0.tgz", - "integrity": "sha512-umh4hR6N7mu4Elq9GG8TOu9M0bakvlsREEC+ialrQN6ABS4oDQ69qJv1VtR3uxlKMCQMCvzk7vr17RHKcjx68A==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.7.4.tgz", + "integrity": "sha512-MCqiLfCKm6KEA1dglf6Uqq1ElDIZwFuzz1WH5mTf8k2uQSxEJMbOIEh7IZv7uichr7PMfi5YVSrr1vz+ipp7AQ==", "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.1.0", + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.7.4", "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-for-of": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.4.4.tgz", - "integrity": "sha512-9T/5Dlr14Z9TIEXLXkt8T1DU7F24cbhwhMNUziN3hB1AXoZcdzPcTiKGRn/6iOymDqtTKWnr/BtRKN9JwbKtdQ==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.7.4.tgz", + "integrity": "sha512-zZ1fD1B8keYtEcKF+M1TROfeHTKnijcVQm0yO/Yu1f7qoDoxEIc/+GX6Go430Bg84eM/xwPFp0+h4EbZg7epAA==", "requires": { "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-function-name": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.4.4.tgz", - "integrity": "sha512-iU9pv7U+2jC9ANQkKeNF6DrPy4GBa4NWQtl6dHB4Pb3izX2JOEvDTFarlNsBj/63ZEzNNIAMs3Qw4fNCcSOXJA==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.7.4.tgz", + "integrity": "sha512-E/x09TvjHNhsULs2IusN+aJNRV5zKwxu1cpirZyRPw+FyyIKEHPXTsadj48bVpc1R5Qq1B5ZkzumuFLytnbT6g==", "requires": { - "@babel/helper-function-name": "^7.1.0", + "@babel/helper-function-name": "^7.7.4", "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-literals": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.2.0.tgz", - "integrity": "sha512-2ThDhm4lI4oV7fVQ6pNNK+sx+c/GM5/SaML0w/r4ZB7sAneD/piDJtwdKlNckXeyGK7wlwg2E2w33C/Hh+VFCg==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.7.4.tgz", + "integrity": "sha512-X2MSV7LfJFm4aZfxd0yLVFrEXAgPqYoDG53Br/tCKiKYfX0MjVjQeWPIhPHHsCqzwQANq+FLN786fF5rgLS+gw==", "requires": { "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-modules-amd": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.2.0.tgz", - "integrity": "sha512-mK2A8ucqz1qhrdqjS9VMIDfIvvT2thrEsIQzbaTdc5QFzhDjQv2CkJJ5f6BXIkgbmaoax3zBr2RyvV/8zeoUZw==", - "dev": true, + "version": "7.7.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.7.5.tgz", + "integrity": "sha512-CT57FG4A2ZUNU1v+HdvDSDrjNWBrtCmSH6YbbgN3Lrf0Di/q/lWRxZrE72p3+HCCz9UjfZOEBdphgC0nzOS6DQ==", "requires": { - "@babel/helper-module-transforms": "^7.1.0", - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-module-transforms": "^7.7.5", + "@babel/helper-plugin-utils": "^7.0.0", + "babel-plugin-dynamic-import-node": "^2.3.0" } }, "@babel/plugin-transform-modules-commonjs": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.4.4.tgz", - "integrity": "sha512-4sfBOJt58sEo9a2BQXnZq+Q3ZTSAUXyK3E30o36BOGnJ+tvJ6YSxF0PG6kERvbeISgProodWuI9UVG3/FMY6iw==", - "dev": true, + "version": "7.7.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.7.5.tgz", + "integrity": "sha512-9Cq4zTFExwFhQI6MT1aFxgqhIsMWQWDVwOgLzl7PTWJHsNaqFvklAU+Oz6AQLAS0dJKTwZSOCo20INwktxpi3Q==", "requires": { - "@babel/helper-module-transforms": "^7.4.4", + "@babel/helper-module-transforms": "^7.7.5", "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-simple-access": "^7.1.0" + "@babel/helper-simple-access": "^7.7.4", + "babel-plugin-dynamic-import-node": "^2.3.0" } }, "@babel/plugin-transform-modules-systemjs": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.4.4.tgz", - "integrity": "sha512-MSiModfILQc3/oqnG7NrP1jHaSPryO6tA2kOMmAQApz5dayPxWiHqmq4sWH2xF5LcQK56LlbKByCd8Aah/OIkQ==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.7.4.tgz", + "integrity": "sha512-y2c96hmcsUi6LrMqvmNDPBBiGCiQu0aYqpHatVVu6kD4mFEXKjyNxd/drc18XXAf9dv7UXjrZwBVmTTGaGP8iw==", "requires": { - "@babel/helper-hoist-variables": "^7.4.4", - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-hoist-variables": "^7.7.4", + "@babel/helper-plugin-utils": "^7.0.0", + "babel-plugin-dynamic-import-node": "^2.3.0" } }, "@babel/plugin-transform-modules-umd": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.2.0.tgz", - "integrity": "sha512-BV3bw6MyUH1iIsGhXlOK6sXhmSarZjtJ/vMiD9dNmpY8QXFFQTj+6v92pcfy1iqa8DeAfJFwoxcrS/TUZda6sw==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.7.4.tgz", + "integrity": "sha512-u2B8TIi0qZI4j8q4C51ktfO7E3cQ0qnaXFI1/OXITordD40tt17g/sXqgNNCcMTcBFKrUPcGDx+TBJuZxLx7tw==", "requires": { - "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-module-transforms": "^7.7.4", "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.4.5.tgz", - "integrity": "sha512-z7+2IsWafTBbjNsOxU/Iv5CvTJlr5w4+HGu1HovKYTtgJ362f7kBcQglkfmlspKKZ3bgrbSGvLfNx++ZJgCWsg==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.7.4.tgz", + "integrity": "sha512-jBUkiqLKvUWpv9GLSuHUFYdmHg0ujC1JEYoZUfeOOfNydZXp1sXObgyPatpcwjWgsdBGsagWW0cdJpX/DO2jMw==", "requires": { - "regexp-tree": "^0.1.6" + "@babel/helper-create-regexp-features-plugin": "^7.7.4" } }, "@babel/plugin-transform-new-target": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.4.4.tgz", - "integrity": "sha512-r1z3T2DNGQwwe2vPGZMBNjioT2scgWzK9BCnDEh+46z8EEwXBq24uRzd65I7pjtugzPSj921aM15RpESgzsSuA==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.7.4.tgz", + "integrity": "sha512-CnPRiNtOG1vRodnsyGX37bHQleHE14B9dnnlgSeEs3ek3fHN1A1SScglTCg1sfbe7sRQ2BUcpgpTpWSfMKz3gg==", "requires": { "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-object-super": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.2.0.tgz", - "integrity": "sha512-VMyhPYZISFZAqAPVkiYb7dUe2AsVi2/wCT5+wZdsNO31FojQJa9ns40hzZ6U9f50Jlq4w6qwzdBB2uwqZ00ebg==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.7.4.tgz", + "integrity": "sha512-ho+dAEhC2aRnff2JCA0SAK7V2R62zJd/7dmtoe7MHcso4C2mS+vZjn1Pb1pCVZvJs1mgsvv5+7sT+m3Bysb6eg==", "requires": { "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.1.0" + "@babel/helper-replace-supers": "^7.7.4" } }, "@babel/plugin-transform-parameters": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.4.4.tgz", - "integrity": "sha512-oMh5DUO1V63nZcu/ZVLQFqiihBGo4OpxJxR1otF50GMeCLiRx5nUdtokd+u9SuVJrvvuIh9OosRFPP4pIPnwmw==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.7.4.tgz", + "integrity": "sha512-VJwhVePWPa0DqE9vcfptaJSzNDKrWU/4FbYCjZERtmqEs05g3UMXnYMZoXja7JAJ7Y7sPZipwm/pGApZt7wHlw==", "requires": { - "@babel/helper-call-delegate": "^7.4.4", - "@babel/helper-get-function-arity": "^7.0.0", + "@babel/helper-call-delegate": "^7.7.4", + "@babel/helper-get-function-arity": "^7.7.4", "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-regenerator": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.4.5.tgz", - "integrity": "sha512-gBKRh5qAaCWntnd09S8QC7r3auLCqq5DI6O0DlfoyDjslSBVqBibrMdsqO+Uhmx3+BlOmE/Kw1HFxmGbv0N9dA==", - "dev": true, + "version": "7.7.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.7.5.tgz", + "integrity": "sha512-/8I8tPvX2FkuEyWbjRCt4qTAgZK0DVy8QRguhA524UH48RfGJy94On2ri+dCuwOpcerPRl9O4ebQkRcVzIaGBw==", "requires": { "regenerator-transform": "^0.14.0" } }, "@babel/plugin-transform-runtime": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.4.4.tgz", - "integrity": "sha512-aMVojEjPszvau3NRg+TIH14ynZLvPewH4xhlCW1w6A3rkxTS1m4uwzRclYR9oS+rl/dr+kT+pzbfHuAWP/lc7Q==", - "dev": true, + "version": "7.7.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.7.6.tgz", + "integrity": "sha512-tajQY+YmXR7JjTwRvwL4HePqoL3DYxpYXIHKVvrOIvJmeHe2y1w4tz5qz9ObUDC9m76rCzIMPyn4eERuwA4a4A==", "requires": { - "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-module-imports": "^7.7.4", "@babel/helper-plugin-utils": "^7.0.0", "resolve": "^1.8.1", "semver": "^5.5.1" } }, "@babel/plugin-transform-shorthand-properties": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.2.0.tgz", - "integrity": "sha512-QP4eUM83ha9zmYtpbnyjTLAGKQritA5XW/iG9cjtuOI8s1RuL/3V6a3DeSHfKutJQ+ayUfeZJPcnCYEQzaPQqg==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.7.4.tgz", + "integrity": "sha512-q+suddWRfIcnyG5YiDP58sT65AJDZSUhXQDZE3r04AuqD6d/XLaQPPXSBzP2zGerkgBivqtQm9XKGLuHqBID6Q==", "requires": { "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-spread": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.2.2.tgz", - "integrity": "sha512-KWfky/58vubwtS0hLqEnrWJjsMGaOeSBn90Ezn5Jeg9Z8KKHmELbP1yGylMlm5N6TPKeY9A2+UaSYLdxahg01w==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.7.4.tgz", + "integrity": "sha512-8OSs0FLe5/80cndziPlg4R0K6HcWSM0zyNhHhLsmw/Nc5MaA49cAsnoJ/t/YZf8qkG7fD+UjTRaApVDB526d7Q==", "requires": { "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-sticky-regex": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.2.0.tgz", - "integrity": "sha512-KKYCoGaRAf+ckH8gEL3JHUaFVyNHKe3ASNsZ+AlktgHevvxGigoIttrEJb8iKN03Q7Eazlv1s6cx2B2cQ3Jabw==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.7.4.tgz", + "integrity": "sha512-Ls2NASyL6qtVe1H1hXts9yuEeONV2TJZmplLONkMPUG158CtmnrzW5Q5teibM5UVOFjG0D3IC5mzXR6pPpUY7A==", "requires": { "@babel/helper-plugin-utils": "^7.0.0", "@babel/helper-regex": "^7.0.0" } }, "@babel/plugin-transform-template-literals": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.4.4.tgz", - "integrity": "sha512-mQrEC4TWkhLN0z8ygIvEL9ZEToPhG5K7KDW3pzGqOfIGZ28Jb0POUkeWcoz8HnHvhFy6dwAT1j8OzqN8s804+g==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.7.4.tgz", + "integrity": "sha512-sA+KxLwF3QwGj5abMHkHgshp9+rRz+oY9uoRil4CyLtgEuE/88dpkeWgNk5qKVsJE9iSfly3nvHapdRiIS2wnQ==", "requires": { - "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-annotate-as-pure": "^7.7.4", "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-typeof-symbol": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.2.0.tgz", - "integrity": "sha512-2LNhETWYxiYysBtrBTqL8+La0jIoQQnIScUJc74OYvUGRmkskNY4EzLCnjHBzdmb38wqtTaixpo1NctEcvMDZw==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.7.4.tgz", + "integrity": "sha512-KQPUQ/7mqe2m0B8VecdyaW5XcQYaePyl9R7IsKd+irzj6jvbhoGnRE+M0aNkyAzI07VfUQ9266L5xMARitV3wg==", "requires": { "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-unicode-regex": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.4.4.tgz", - "integrity": "sha512-il+/XdNw01i93+M9J9u4T7/e/Ue/vWfNZE4IRUQjplu2Mqb/AFTDimkw2tdEdSH50wuQXZAbXSql0UphQke+vA==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.7.4.tgz", + "integrity": "sha512-N77UUIV+WCvE+5yHw+oks3m18/umd7y392Zv7mYTpFqHtkpcc+QUz+gLJNTWVlWROIWeLqY0f3OjZxV5TcXnRw==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-regex": "^7.4.4", - "regexpu-core": "^4.5.4" + "@babel/helper-create-regexp-features-plugin": "^7.7.4", + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/preset-env": { "version": "7.3.4", "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.3.4.tgz", "integrity": "sha512-2mwqfYMK8weA0g0uBKOt4FE3iEodiHy9/CW0b+nWXcbL+pGzLx8ESYc+j9IIxr6LTDHWKgPm71i9smo02bw+gA==", - "dev": true, "requires": { "@babel/helper-module-imports": "^7.0.0", "@babel/helper-plugin-utils": "^7.0.0", @@ -760,68 +733,106 @@ } }, "@babel/runtime": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.4.5.tgz", - "integrity": "sha512-TuI4qpWZP6lGOGIuGWtp9sPluqYICmbk8T/1vpSysqJxRPkudh/ofFWyqdcMsDf2s7KvDL4/YHgKyvcS3g9CJQ==", - "dev": true, + "version": "7.7.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.7.6.tgz", + "integrity": "sha512-BWAJxpNVa0QlE5gZdWjSxXtemZyZ9RmrmVozxt3NUXeZhVIJ5ANyqmMc0JDrivBZyxUuQvFxlvH4OWWOogGfUw==", "requires": { "regenerator-runtime": "^0.13.2" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz", + "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==" + } } }, "@babel/runtime-corejs2": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs2/-/runtime-corejs2-7.4.5.tgz", - "integrity": "sha512-5yLuwzvIDecKwYMzJtiarky4Fb5643H3Ao5jwX0HrMR5oM5mn2iHH9wSZonxwNK0oAjAFUQAiOd4jT7/9Y2jMQ==", - "dev": true, + "version": "7.7.6", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs2/-/runtime-corejs2-7.7.6.tgz", + "integrity": "sha512-QYp/8xdH8iMin3pH5gtT/rUuttVfIcOhWBC3wh9Eh/qs4jEe39+3DpCDLgWXhMQgiCTOH8mrLSvQ0OHOCcox9g==", "requires": { "core-js": "^2.6.5", "regenerator-runtime": "^0.13.2" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz", + "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==" + } } }, "@babel/template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.4.tgz", - "integrity": "sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.7.4.tgz", + "integrity": "sha512-qUzihgVPguAzXCK7WXw8pqs6cEwi54s3E+HrejlkuWO6ivMKx9hZl3Y2fSXp9i5HgyWmj7RKP+ulaYnKM4yYxw==", "requires": { "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.4.4", - "@babel/types": "^7.4.4" + "@babel/parser": "^7.7.4", + "@babel/types": "^7.7.4" } }, "@babel/traverse": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.4.5.tgz", - "integrity": "sha512-Vc+qjynwkjRmIFGxy0KYoPj4FdVDxLej89kMHFsWScq999uX+pwcX4v9mWRjW0KcAYTPAuVQl2LKP1wEVLsp+A==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.4.4", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.4.4", - "@babel/parser": "^7.4.5", - "@babel/types": "^7.4.4", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.7.4.tgz", + "integrity": "sha512-P1L58hQyupn8+ezVA2z5KBm4/Zr4lCC8dwKCMYzsa5jFMDMQAzaBNy9W5VjB+KAmBjb40U7a/H6ao+Xo+9saIw==", + "requires": { + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.7.4", + "@babel/helper-function-name": "^7.7.4", + "@babel/helper-split-export-declaration": "^7.7.4", + "@babel/parser": "^7.7.4", + "@babel/types": "^7.7.4", "debug": "^4.1.0", "globals": "^11.1.0", - "lodash": "^4.17.11" + "lodash": "^4.17.13" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } } }, "@babel/types": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.4.4.tgz", - "integrity": "sha512-dOllgYdnEFOebhkKCjzSVFqw/PmmB8pH6RGOWkY4GsboQNd47b1fBThBSwlHAq9alF9vc1M3+6oqR47R50L0tQ==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.7.4.tgz", + "integrity": "sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA==", "requires": { "esutils": "^2.0.2", - "lodash": "^4.17.11", + "lodash": "^4.17.13", "to-fast-properties": "^2.0.0" + }, + "dependencies": { + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" + } + } + }, + "@cosmos-ui/vue": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/@cosmos-ui/vue/-/vue-0.5.16.tgz", + "integrity": "sha512-Z4byEoZLkIbumm3SlnrzwuyvDi6vzWv2GfT36QuaPFWusCShGgc47ehXp2S55tKrNajOIiF9bfgasHRL6mfHFA==", + "requires": { + "vue": "^2.6.10" } }, "@mrmlnc/readdir-enhanced": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", - "dev": true, "requires": { "call-me-maybe": "^1.0.1", "glob-to-regexp": "^0.3.0" @@ -830,20 +841,30 @@ "@nodelib/fs.stat": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", - "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", - "dev": true + "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==" + }, + "@types/babel-types": { + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/@types/babel-types/-/babel-types-7.0.7.tgz", + "integrity": "sha512-dBtBbrc+qTHy1WdfHYjBwRln4+LWqASWakLHsWHR2NWHIFkv4W3O070IGoGLEBrJBvct3r0L1BUPuvURi7kYUQ==" + }, + "@types/babylon": { + "version": "6.16.5", + "resolved": "https://registry.npmjs.org/@types/babylon/-/babylon-6.16.5.tgz", + "integrity": "sha512-xH2e58elpj1X4ynnKp9qSnWlsRTIs6n3tgLGNfwAGHwePw0mulHQllV34n0T25uYSu1k0hRKkWXF890B1yS47w==", + "requires": { + "@types/babel-types": "*" + } }, "@types/events": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", - "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", - "dev": true + "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==" }, "@types/glob": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==", - "dev": true, "requires": { "@types/events": "*", "@types/minimatch": "*", @@ -853,32 +874,27 @@ "@types/minimatch": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", - "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", - "dev": true + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==" }, "@types/node": { - "version": "12.0.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.0.10.tgz", - "integrity": "sha512-LcsGbPomWsad6wmMNv7nBLw7YYYyfdYcz6xryKYQhx89c3XXan+8Q6AJ43G5XDIaklaVkK3mE4fCb0SBvMiPSQ==", - "dev": true + "version": "12.12.15", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.15.tgz", + "integrity": "sha512-Pv+vWicyFd07Hw/SmNnTUguqrHgDfMtjabvD9sQyxeqbpCEg8CmViLBaVPHtNsoBgZECrRf5/pgV6FJIBrGSjw==" }, "@types/q": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.2.tgz", - "integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==", - "dev": true + "integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==" }, "@vue/babel-helper-vue-jsx-merge-props": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-1.0.0.tgz", - "integrity": "sha512-6tyf5Cqm4m6v7buITuwS+jHzPlIPxbFzEhXR5JGZpbrvOcp1hiQKckd305/3C7C36wFekNTQSxAtgeM0j0yoUw==", - "dev": true + "integrity": "sha512-6tyf5Cqm4m6v7buITuwS+jHzPlIPxbFzEhXR5JGZpbrvOcp1hiQKckd305/3C7C36wFekNTQSxAtgeM0j0yoUw==" }, "@vue/babel-plugin-transform-vue-jsx": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@vue/babel-plugin-transform-vue-jsx/-/babel-plugin-transform-vue-jsx-1.0.0.tgz", - "integrity": "sha512-U+JNwVQSmaLKjO3lzCUC3cNXxprgezV1N+jOdqbP4xWNaqtWUCJnkjTVcgECM18A/AinDKPcUUeoyhU7yxUxXQ==", - "dev": true, + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@vue/babel-plugin-transform-vue-jsx/-/babel-plugin-transform-vue-jsx-1.1.2.tgz", + "integrity": "sha512-YfdaoSMvD1nj7+DsrwfTvTnhDXI7bsuh+Y5qWwvQXlD24uLgnsoww3qbiZvWf/EoviZMrvqkqN4CBw0W3BWUTQ==", "requires": { "@babel/helper-module-imports": "^7.0.0", "@babel/plugin-syntax-jsx": "^7.2.0", @@ -889,10 +905,9 @@ } }, "@vue/babel-preset-app": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/@vue/babel-preset-app/-/babel-preset-app-3.8.0.tgz", - "integrity": "sha512-A2NBzIVdtNq52foc+P+yQ/7rSm2q2oPpn2FJVW4hFgaWVOL+HaOLCjWDEQyEeMbRZvyOVHMuom097u3p2H2Rfw==", - "dev": true, + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/@vue/babel-preset-app/-/babel-preset-app-3.12.1.tgz", + "integrity": "sha512-Zjy5jQaikV1Pz+ri0YgXFS7q4/5wCxB5tRkDOEIt5+4105u0Feb/pvH20nVL6nx9GyXrECFfcm7Yxr/z++OaPQ==", "requires": { "@babel/helper-module-imports": "^7.0.0", "@babel/plugin-proposal-class-properties": "^7.0.0", @@ -910,67 +925,75 @@ } }, "@vue/babel-preset-jsx": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@vue/babel-preset-jsx/-/babel-preset-jsx-1.0.0.tgz", - "integrity": "sha512-5CbDu/QHS+TtQNw5aYAffiMxBBB2Eo9+RJpS8X+6FJbdG5Rvc4TVipEqkrg0pJviWadNg7TEy0Uz4o7VNXeIZw==", - "dev": true, + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@vue/babel-preset-jsx/-/babel-preset-jsx-1.1.2.tgz", + "integrity": "sha512-zDpVnFpeC9YXmvGIDSsKNdL7qCG2rA3gjywLYHPCKDT10erjxF4U+6ay9X6TW5fl4GsDlJp9bVfAVQAAVzxxvQ==", "requires": { "@vue/babel-helper-vue-jsx-merge-props": "^1.0.0", - "@vue/babel-plugin-transform-vue-jsx": "^1.0.0", - "@vue/babel-sugar-functional-vue": "^1.0.0", - "@vue/babel-sugar-inject-h": "^1.0.0", - "@vue/babel-sugar-v-model": "^1.0.0", - "@vue/babel-sugar-v-on": "^1.0.0" + "@vue/babel-plugin-transform-vue-jsx": "^1.1.2", + "@vue/babel-sugar-functional-vue": "^1.1.2", + "@vue/babel-sugar-inject-h": "^1.1.2", + "@vue/babel-sugar-v-model": "^1.1.2", + "@vue/babel-sugar-v-on": "^1.1.2" } }, "@vue/babel-sugar-functional-vue": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@vue/babel-sugar-functional-vue/-/babel-sugar-functional-vue-1.0.0.tgz", - "integrity": "sha512-XE/jNaaorTuhWayCz+QClk5AB9OV5HzrwbzEC6sIUY0J60A28ONQKeTwxfidW42egOkqNH/UU6eE3KLfmiDj0Q==", - "dev": true, + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-functional-vue/-/babel-sugar-functional-vue-1.1.2.tgz", + "integrity": "sha512-YhmdJQSVEFF5ETJXzrMpj0nkCXEa39TvVxJTuVjzvP2rgKhdMmQzlJuMv/HpadhZaRVMCCF3AEjjJcK5q/cYzQ==", "requires": { "@babel/plugin-syntax-jsx": "^7.2.0" } }, "@vue/babel-sugar-inject-h": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@vue/babel-sugar-inject-h/-/babel-sugar-inject-h-1.0.0.tgz", - "integrity": "sha512-NxWU+DqtbZgfGvd25GPoFMj+rvyQ8ZA1pHj8vIeqRij+vx3sXoKkObjA9ulZunvWw5F6uG9xYy4ytpxab/X+Hg==", - "dev": true, + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-inject-h/-/babel-sugar-inject-h-1.1.2.tgz", + "integrity": "sha512-VRSENdTvD5htpnVp7i7DNuChR5rVMcORdXjvv5HVvpdKHzDZAYiLSD+GhnhxLm3/dMuk8pSzV+k28ECkiN5m8w==", "requires": { "@babel/plugin-syntax-jsx": "^7.2.0" } }, "@vue/babel-sugar-v-model": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@vue/babel-sugar-v-model/-/babel-sugar-v-model-1.0.0.tgz", - "integrity": "sha512-Pfg2Al0io66P1eO6zUbRIgpyKCU2qTnumiE0lao/wA/uNdb7Dx5Tfd1W6tO5SsByETPnEs8i8+gawRIXX40rFw==", - "dev": true, + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-v-model/-/babel-sugar-v-model-1.1.2.tgz", + "integrity": "sha512-vLXPvNq8vDtt0u9LqFdpGM9W9IWDmCmCyJXuozlq4F4UYVleXJ2Fa+3JsnTZNJcG+pLjjfnEGHci2339Kj5sGg==", "requires": { "@babel/plugin-syntax-jsx": "^7.2.0", "@vue/babel-helper-vue-jsx-merge-props": "^1.0.0", - "@vue/babel-plugin-transform-vue-jsx": "^1.0.0", + "@vue/babel-plugin-transform-vue-jsx": "^1.1.2", "camelcase": "^5.0.0", "html-tags": "^2.0.0", "svg-tags": "^1.0.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + } } }, "@vue/babel-sugar-v-on": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@vue/babel-sugar-v-on/-/babel-sugar-v-on-1.0.0.tgz", - "integrity": "sha512-2aqJaDLKdSSGlxZU+GjFERaSNUaa6DQreV+V/K4W/6Lxj8520/r1lChWEa/zuAoPD2Vhy0D2QrqqO+I0D6CkKw==", - "dev": true, + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-v-on/-/babel-sugar-v-on-1.1.2.tgz", + "integrity": "sha512-T8ZCwC8Jp2uRtcZ88YwZtZXe7eQrJcfRq0uTFy6ShbwYJyz5qWskRFoVsdTi9o0WEhmQXxhQUewodOSCUPVmsQ==", "requires": { "@babel/plugin-syntax-jsx": "^7.2.0", - "@vue/babel-plugin-transform-vue-jsx": "^1.0.0", + "@vue/babel-plugin-transform-vue-jsx": "^1.1.2", "camelcase": "^5.0.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + } } }, "@vue/component-compiler-utils": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-2.6.0.tgz", - "integrity": "sha512-IHjxt7LsOFYc0DkTncB7OXJL7UzwOLPPQCfEUNyxL2qt+tF12THV+EO33O1G2Uk4feMSWua3iD39Itszx0f0bw==", - "dev": true, + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-3.1.0.tgz", + "integrity": "sha512-OJ7swvl8LtKtX5aYP8jHhO6fQBIRIGkU6rvWzK+CGJiNOnvg16nzcBkd9qMZzW8trI2AsqAKx263nv7kb5rhZw==", "requires": { "consolidate": "^0.15.1", "hash-sum": "^1.0.2", @@ -978,7 +1001,7 @@ "merge-source-map": "^1.1.0", "postcss": "^7.0.14", "postcss-selector-parser": "^5.0.0", - "prettier": "1.16.3", + "prettier": "^1.18.2", "source-map": "~0.6.1", "vue-template-es2015-compiler": "^1.9.0" }, @@ -986,14 +1009,12 @@ "cssesc": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", - "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==", - "dev": true + "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==" }, "lru-cache": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dev": true, "requires": { "pseudomap": "^1.0.2", "yallist": "^2.1.2" @@ -1003,40 +1024,31 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", - "dev": true, "requires": { "cssesc": "^2.0.0", "indexes-of": "^1.0.1", "uniq": "^1.0.1" } }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, "yallist": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" } } }, "@vuepress/core": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@vuepress/core/-/core-1.0.2.tgz", - "integrity": "sha512-PUMaxq44wEuqXHutcmxj6q9cCRS4kZ1nyBvvHr9AIuxJflgYDw/k8wxhYuZjsxVWhpJjsPywLGNRyLN88vJcqQ==", - "dev": true, + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@vuepress/core/-/core-1.2.0.tgz", + "integrity": "sha512-ZIsUkQIF+h4Yk6q4okoRnRwRhcYePu/kNiL0WWPDGycjai8cFqFjLDP/tJjfTKXmn9A62j2ETjSwaiMxCtDkyw==", "requires": { "@babel/core": "^7.0.0", "@vue/babel-preset-app": "^3.1.1", - "@vuepress/markdown": "^1.0.2", - "@vuepress/markdown-loader": "^1.0.2", - "@vuepress/plugin-last-updated": "^1.0.2", - "@vuepress/plugin-register-components": "^1.0.2", - "@vuepress/shared-utils": "^1.0.2", + "@vuepress/markdown": "^1.2.0", + "@vuepress/markdown-loader": "^1.2.0", + "@vuepress/plugin-last-updated": "^1.2.0", + "@vuepress/plugin-register-components": "^1.2.0", + "@vuepress/shared-utils": "^1.2.0", "autoprefixer": "^9.5.1", "babel-loader": "^8.0.4", "cache-loader": "^3.0.0", @@ -1046,7 +1058,7 @@ "cross-spawn": "^6.0.5", "css-loader": "^2.1.1", "file-loader": "^3.0.1", - "js-yaml": "^3.11.0", + "js-yaml": "^3.13.1", "lru-cache": "^5.1.1", "mini-css-extract-plugin": "0.6.0", "optimize-css-assets-webpack-plugin": "^5.0.1", @@ -1055,13 +1067,13 @@ "postcss-safe-parser": "^4.0.1", "toml": "^3.0.0", "url-loader": "^1.0.1", - "vue": "^2.5.16", - "vue-loader": "^15.2.4", - "vue-router": "^3.0.2", - "vue-server-renderer": "^2.5.16", - "vue-template-compiler": "^2.5.16", + "vue": "^2.6.10", + "vue-loader": "^15.7.1", + "vue-router": "^3.1.3", + "vue-server-renderer": "^2.6.10", + "vue-template-compiler": "^2.6.10", "vuepress-html-webpack-plugin": "^3.2.0", - "vuepress-plugin-container": "^2.0.0", + "vuepress-plugin-container": "^2.0.2", "webpack": "^4.8.1", "webpack-chain": "^4.6.0", "webpack-dev-server": "^3.5.1", @@ -1070,38 +1082,54 @@ } }, "@vuepress/markdown": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@vuepress/markdown/-/markdown-1.0.2.tgz", - "integrity": "sha512-ddl0FG11aeidjcFYYNU53xZ1WLEYb3g5/hijfSCEQKyMv+gDXy7Z3/uc4I4oH2UNtB2Wpo3pQoeKGY56edcBuA==", - "dev": true, + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@vuepress/markdown/-/markdown-1.2.0.tgz", + "integrity": "sha512-RLRQmTu5wJbCO4Qv+J0K53o5Ew7nAGItLwWyzCbIUB6pRsya3kqSCViWQVlKlS53zFTmRHuAC9tJMRdzly3mCA==", "requires": { - "@vuepress/shared-utils": "^1.0.2", + "@vuepress/shared-utils": "^1.2.0", "markdown-it": "^8.4.1", "markdown-it-anchor": "^5.0.2", "markdown-it-chain": "^1.3.0", "markdown-it-emoji": "^1.4.0", "markdown-it-table-of-contents": "^0.4.0", "prismjs": "^1.13.0" + }, + "dependencies": { + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" + }, + "markdown-it": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.2.tgz", + "integrity": "sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ==", + "requires": { + "argparse": "^1.0.7", + "entities": "~1.1.1", + "linkify-it": "^2.0.0", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + } + } } }, "@vuepress/markdown-loader": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@vuepress/markdown-loader/-/markdown-loader-1.0.2.tgz", - "integrity": "sha512-ljD2mVDpeq0VvCHMHfemGW+0fhLmOMldtWIAYQ/I8LjLuV2qknAwjzZ4tEAqveaVIFMUBRP3V6d8YGIK9dr6kg==", - "dev": true, + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@vuepress/markdown-loader/-/markdown-loader-1.2.0.tgz", + "integrity": "sha512-gOZzoHjfp/W6t+qKBRdbHS/9TwRnNuhY7V+yFzxofNONFHQULofIN/arG+ptYc2SuqJ541jqudNQW+ldHNMC2w==", "requires": { - "@vuepress/markdown": "^1.0.2", + "@vuepress/markdown": "^1.2.0", "loader-utils": "^1.1.0", "lru-cache": "^5.1.1" } }, "@vuepress/plugin-active-header-links": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@vuepress/plugin-active-header-links/-/plugin-active-header-links-1.0.2.tgz", - "integrity": "sha512-Wo9NP55OOJ/vGFnYwStZcDBJMnf1gNDL159K7oiiEltuz8kjZBqmtsIjQXOzXFjA8voYh/RVL48Sr4eGCDd7LQ==", - "dev": true, + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@vuepress/plugin-active-header-links/-/plugin-active-header-links-1.2.0.tgz", + "integrity": "sha512-vdi7l96pElJvEmcx6t9DWJNH25TIurS8acjN3+b7o4NzdaszFn5j6klN6WtI4Z+5BVDrxHP5W1F3Ebw8SZyupA==", "requires": { - "lodash.throttle": "^4.1.1" + "lodash.debounce": "^4.0.8" } }, "@vuepress/plugin-google-analytics": { @@ -1111,43 +1139,38 @@ "dev": true }, "@vuepress/plugin-last-updated": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@vuepress/plugin-last-updated/-/plugin-last-updated-1.0.2.tgz", - "integrity": "sha512-SwugVHcllUwy9WPqtWWM+hUEvH6SDPFJAHnpIs0kXJmaxIIipqF/9+CokT5QzxzGVHeYPU4YKtLadEIXdRcXsw==", - "dev": true, + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@vuepress/plugin-last-updated/-/plugin-last-updated-1.2.0.tgz", + "integrity": "sha512-j4uZb/MXDyG+v9QCG3T/rkiaOhC/ib7NKCt1cjn3GOwvWTDmB5UZm9EBhUpbDNrBgxW+SaHOe3kMVNO8bGOTGw==", "requires": { "cross-spawn": "^6.0.5" } }, "@vuepress/plugin-nprogress": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@vuepress/plugin-nprogress/-/plugin-nprogress-1.0.2.tgz", - "integrity": "sha512-degCJe2Z0eHbYblUGQXuDMIZSwH7twQcbWtkuH8goxXNilvtVxtWvBkUJouJ9RN3RuSk7EfPT171mrwq9yqbUg==", - "dev": true, + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@vuepress/plugin-nprogress/-/plugin-nprogress-1.2.0.tgz", + "integrity": "sha512-0apt3Dp6XVCOkLViX6seKSEJgARihi+pX3/r8j8ndFp9Y+vmgLFZnQnGE5iKNi1ty+A6PZOK0RQcBjwTAU4pAw==", "requires": { "nprogress": "^0.2.0" } }, "@vuepress/plugin-register-components": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@vuepress/plugin-register-components/-/plugin-register-components-1.0.2.tgz", - "integrity": "sha512-iqUq4kgNdVHba0cZJLv81DfB9ZsTdJY7gynN0NYHFwDEjsdOh1cRMgteuWa/mmK9XfopMO5oysD9WDhzCiIjfQ==", - "dev": true, + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@vuepress/plugin-register-components/-/plugin-register-components-1.2.0.tgz", + "integrity": "sha512-C32b8sbGtDEX8I3SUUKS/w2rThiRFiKxmzNcJD996me7VY/4rgmZ8CxGtb6G9wByVoK0UdG1SOkrgOPdSCm80A==", "requires": { - "@vuepress/shared-utils": "^1.0.2" + "@vuepress/shared-utils": "^1.2.0" } }, "@vuepress/plugin-search": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@vuepress/plugin-search/-/plugin-search-1.0.2.tgz", - "integrity": "sha512-LCFZLp+adppdHETIEARwQhczj+mdpa+D25qL9RNmYxzU9mF6qItYNLl57P6omGU2Vr8frAc+rWgjbi4cjkbCvQ==", - "dev": true + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@vuepress/plugin-search/-/plugin-search-1.2.0.tgz", + "integrity": "sha512-QU3JfnMfImDAArbJOVH1q1iCDE5QrT99GLpNGo6KQYZWqY1TWAbgyf8C2hQdaI03co1lkU2Wn/iqzHJ5WHlueg==" }, "@vuepress/shared-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@vuepress/shared-utils/-/shared-utils-1.0.2.tgz", - "integrity": "sha512-QyNV76Dn0u2ooXbC3AXJZrQLuTNS4i8xSmJqZWsel2ooJKknXP3UIMIENcK1QFHnlIACznyV53u9hRAYBaZEWQ==", - "dev": true, + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@vuepress/shared-utils/-/shared-utils-1.2.0.tgz", + "integrity": "sha512-wo5Ng2/xzsmIYCzvWxgLFlDBp7FkmJp2shAkbSurLNAh1vixhs0+LyDxsk01+m34ktJSp9rTUUsm6khw/Fvo0w==", "requires": { "chalk": "^2.3.2", "diacritics": "^1.3.0", @@ -1161,33 +1184,32 @@ }, "dependencies": { "semver": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.1.2.tgz", - "integrity": "sha512-z4PqiCpomGtWj8633oeAdXm1Kn1W++3T8epkZYnwiVgIYIJ0QHszhInYSJTYxebByQH7KVCEAn8R9duzZW2PhQ==", - "dev": true + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" } } }, "@vuepress/theme-default": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@vuepress/theme-default/-/theme-default-1.0.2.tgz", - "integrity": "sha512-fawiYshvQWXyaEgMXcyqj7j0atHLysIA2AzFt4K6y29WaMfiIAPE9lsxymTzT4zkc/T6nRP/TqwiuUaOK12wkw==", - "dev": true, + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@vuepress/theme-default/-/theme-default-1.2.0.tgz", + "integrity": "sha512-mJxAMYQQv4OrGFsArMlONu8RpCzPUVx81dumkyTT4ay5PXAWTj+WDeFQLOT3j0g9QrDJGnHhbiw2aS+R/0WUyQ==", "requires": { - "@vuepress/plugin-active-header-links": "^1.0.2", - "@vuepress/plugin-nprogress": "^1.0.2", - "@vuepress/plugin-search": "^1.0.2", + "@vuepress/plugin-active-header-links": "^1.2.0", + "@vuepress/plugin-nprogress": "^1.2.0", + "@vuepress/plugin-search": "^1.2.0", "docsearch.js": "^2.5.2", + "lodash": "^4.17.15", "stylus": "^0.54.5", "stylus-loader": "^3.0.2", - "vuepress-plugin-container": "^2.0.0" + "vuepress-plugin-container": "^2.0.2", + "vuepress-plugin-smooth-scroll": "^0.0.3" } }, "@webassemblyjs/ast": { "version": "1.8.5", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz", "integrity": "sha512-aJMfngIZ65+t71C3y2nBBg5FFG0Okt9m0XEgWZ7Ywgn1oMAT8cNwx00Uv1cQyHtidq0Xn94R4TAywO+LCQ+ZAQ==", - "dev": true, "requires": { "@webassemblyjs/helper-module-context": "1.8.5", "@webassemblyjs/helper-wasm-bytecode": "1.8.5", @@ -1197,26 +1219,22 @@ "@webassemblyjs/floating-point-hex-parser": { "version": "1.8.5", "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.5.tgz", - "integrity": "sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ==", - "dev": true + "integrity": "sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ==" }, "@webassemblyjs/helper-api-error": { "version": "1.8.5", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.5.tgz", - "integrity": "sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA==", - "dev": true + "integrity": "sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA==" }, "@webassemblyjs/helper-buffer": { "version": "1.8.5", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.5.tgz", - "integrity": "sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q==", - "dev": true + "integrity": "sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q==" }, "@webassemblyjs/helper-code-frame": { "version": "1.8.5", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.5.tgz", "integrity": "sha512-VQAadSubZIhNpH46IR3yWO4kZZjMxN1opDrzePLdVKAZ+DFjkGD/rf4v1jap744uPVU6yjL/smZbRIIJTOUnKQ==", - "dev": true, "requires": { "@webassemblyjs/wast-printer": "1.8.5" } @@ -1224,14 +1242,12 @@ "@webassemblyjs/helper-fsm": { "version": "1.8.5", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.5.tgz", - "integrity": "sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow==", - "dev": true + "integrity": "sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow==" }, "@webassemblyjs/helper-module-context": { "version": "1.8.5", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.5.tgz", "integrity": "sha512-/O1B236mN7UNEU4t9X7Pj38i4VoU8CcMHyy3l2cV/kIF4U5KoHXDVqcDuOs1ltkac90IM4vZdHc52t1x8Yfs3g==", - "dev": true, "requires": { "@webassemblyjs/ast": "1.8.5", "mamacro": "^0.0.3" @@ -1240,14 +1256,12 @@ "@webassemblyjs/helper-wasm-bytecode": { "version": "1.8.5", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.5.tgz", - "integrity": "sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ==", - "dev": true + "integrity": "sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ==" }, "@webassemblyjs/helper-wasm-section": { "version": "1.8.5", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.5.tgz", "integrity": "sha512-VV083zwR+VTrIWWtgIUpqfvVdK4ff38loRmrdDBgBT8ADXYsEZ5mPQ4Nde90N3UYatHdYoDIFb7oHzMncI02tA==", - "dev": true, "requires": { "@webassemblyjs/ast": "1.8.5", "@webassemblyjs/helper-buffer": "1.8.5", @@ -1259,7 +1273,6 @@ "version": "1.8.5", "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.8.5.tgz", "integrity": "sha512-aaCvQYrvKbY/n6wKHb/ylAJr27GglahUO89CcGXMItrOBqRarUMxWLJgxm9PJNuKULwN5n1csT9bYoMeZOGF3g==", - "dev": true, "requires": { "@xtuc/ieee754": "^1.2.0" } @@ -1268,7 +1281,6 @@ "version": "1.8.5", "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.8.5.tgz", "integrity": "sha512-plYUuUwleLIziknvlP8VpTgO4kqNaH57Y3JnNa6DLpu/sGcP6hbVdfdX5aHAV716pQBKrfuU26BJK29qY37J7A==", - "dev": true, "requires": { "@xtuc/long": "4.2.2" } @@ -1276,14 +1288,12 @@ "@webassemblyjs/utf8": { "version": "1.8.5", "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.8.5.tgz", - "integrity": "sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw==", - "dev": true + "integrity": "sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw==" }, "@webassemblyjs/wasm-edit": { "version": "1.8.5", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.8.5.tgz", "integrity": "sha512-A41EMy8MWw5yvqj7MQzkDjU29K7UJq1VrX2vWLzfpRHt3ISftOXqrtojn7nlPsZ9Ijhp5NwuODuycSvfAO/26Q==", - "dev": true, "requires": { "@webassemblyjs/ast": "1.8.5", "@webassemblyjs/helper-buffer": "1.8.5", @@ -1299,7 +1309,6 @@ "version": "1.8.5", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.8.5.tgz", "integrity": "sha512-BCZBT0LURC0CXDzj5FXSc2FPTsxwp3nWcqXQdOZE4U7h7i8FqtFK5Egia6f9raQLpEKT1VL7zr4r3+QX6zArWg==", - "dev": true, "requires": { "@webassemblyjs/ast": "1.8.5", "@webassemblyjs/helper-wasm-bytecode": "1.8.5", @@ -1312,7 +1321,6 @@ "version": "1.8.5", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.8.5.tgz", "integrity": "sha512-HKo2mO/Uh9A6ojzu7cjslGaHaUU14LdLbGEKqTR7PBKwT6LdPtLLh9fPY33rmr5wcOMrsWDbbdCHq4hQUdd37Q==", - "dev": true, "requires": { "@webassemblyjs/ast": "1.8.5", "@webassemblyjs/helper-buffer": "1.8.5", @@ -1324,7 +1332,6 @@ "version": "1.8.5", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.8.5.tgz", "integrity": "sha512-pi0SYE9T6tfcMkthwcgCpL0cM9nRYr6/6fjgDtL6q/ZqKHdMWvxitRi5JcZ7RI4SNJJYnYNaWy5UUrHQy998lw==", - "dev": true, "requires": { "@webassemblyjs/ast": "1.8.5", "@webassemblyjs/helper-api-error": "1.8.5", @@ -1338,7 +1345,6 @@ "version": "1.8.5", "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.8.5.tgz", "integrity": "sha512-daXC1FyKWHF1i11obK086QRlsMsY4+tIOKgBqI1lxAnkp9xe9YMcgOxm9kLe+ttjs5aWV2KKE1TWJCN57/Btsg==", - "dev": true, "requires": { "@webassemblyjs/ast": "1.8.5", "@webassemblyjs/floating-point-hex-parser": "1.8.5", @@ -1352,7 +1358,6 @@ "version": "1.8.5", "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.8.5.tgz", "integrity": "sha512-w0U0pD4EhlnvRyeJzBqaVSJAo9w/ce7/WPogeXLzGkO6hzhr4GnQIZ4W4uUt5b9ooAaXPtnXlj0gzsXEOUNYMg==", - "dev": true, "requires": { "@webassemblyjs/ast": "1.8.5", "@webassemblyjs/wast-parser": "1.8.5", @@ -1362,54 +1367,56 @@ "@xtuc/ieee754": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" }, "@xtuc/long": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, "accepts": { "version": "1.3.7", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", - "dev": true, "requires": { "mime-types": "~2.1.24", "negotiator": "0.6.2" } }, "acorn": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz", - "integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==", - "dev": true + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=" }, - "acorn-dynamic-import": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz", - "integrity": "sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw==", - "dev": true + "acorn-globals": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-3.1.0.tgz", + "integrity": "sha1-/YJw9x+7SZawBPqIDuXUZXOnMb8=", + "requires": { + "acorn": "^4.0.4" + }, + "dependencies": { + "acorn": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", + "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=" + } + } }, "agentkeepalive": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-2.2.0.tgz", - "integrity": "sha1-xdG9SxKQCPEWPyNvhuX66iAm4u8=", - "dev": true + "integrity": "sha1-xdG9SxKQCPEWPyNvhuX66iAm4u8=" }, "ajv": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", - "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", - "dev": true, + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", + "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", "requires": { "fast-deep-equal": "^2.0.1", "fast-json-stable-stringify": "^2.0.0", @@ -1420,20 +1427,17 @@ "ajv-errors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", - "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", - "dev": true + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==" }, "ajv-keywords": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.0.tgz", - "integrity": "sha512-aUjdRFISbuFOl0EIZc+9e4FfZp0bDZgAdOOf30bJmw8VM9v84SHyVyxDfbWxpGYbdZD/9XoKxfHVNmxPkhwyGw==", - "dev": true + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz", + "integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==" }, "algoliasearch": { - "version": "3.33.0", - "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-3.33.0.tgz", - "integrity": "sha512-9DaVmOd7cvcZeYyV0BWAeJHVWJmgOL2DNUEBY/DTR4MzD1wCWs4Djl7LAlfvkGwGBdRHZCG+l0HA1572w3T8zg==", - "dev": true, + "version": "3.35.1", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-3.35.1.tgz", + "integrity": "sha512-K4yKVhaHkXfJ/xcUnil04xiSrB8B8yHZoFEhWNpXg23eiCnqvTZw1tn/SqvdsANlYHLJlKl0qi3I/Q2Sqo7LwQ==", "requires": { "agentkeepalive": "^2.2.0", "debug": "^2.6.9", @@ -1450,81 +1454,50 @@ "reduce": "^1.0.1", "semver": "^5.1.0", "tunnel-agent": "^0.6.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "events": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", - "dev": true - }, - "isarray": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.4.tgz", - "integrity": "sha512-GMxXOiUirWg1xTKRipM0Ek07rX+ubx4nNVElTJdNLYmNO/2YrDkgJGw9CljXn+r4EWiDQg/8lsRdHyg2PJuUaA==", - "dev": true - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } + } + }, + "align-text": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "requires": { + "kind-of": "^3.0.2", + "longest": "^1.0.1", + "repeat-string": "^1.5.2" } }, "alphanum-sort": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", - "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=", - "dev": true - }, - "amdefine": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", - "dev": true + "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=" }, "ansi-colors": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", - "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", - "dev": true + "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==" }, "ansi-escapes": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.2.0.tgz", - "integrity": "sha512-0+VX4uhi8m3aNbzoqKmkAVOEj6uQzcUHXoFPkKjhZPTpGRUBqVh930KbB6PS4zIyDZccphlLIYlu8nsjFzkXwg==", - "dev": true, + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.0.tgz", + "integrity": "sha512-EiYhwo0v255HUL6eDyuLrXEkTi7WwVCLAw+SeOQ7M7qdun1z1pum4DEm/nuqIVbPvi9RPPc9k9LbyBv6H0DwVg==", "requires": { - "type-fest": "^0.5.2" + "type-fest": "^0.8.1" } }, "ansi-html": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz", - "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=", - "dev": true + "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=" }, "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" }, "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, "requires": { "color-convert": "^1.9.0" } @@ -1533,7 +1506,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "dev": true, "requires": { "micromatch": "^3.1.4", "normalize-path": "^2.1.1" @@ -1543,7 +1515,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, "requires": { "remove-trailing-separator": "^1.0.1" } @@ -1553,14 +1524,12 @@ "aproba": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", - "dev": true + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, "requires": { "sprintf-js": "~1.0.2" } @@ -1568,32 +1537,27 @@ "arr-diff": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" }, "arr-flatten": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" }, "arr-union": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=" }, "array-flatten": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", - "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", - "dev": true + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" }, "array-union": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", - "dev": true, "requires": { "array-uniq": "^1.0.1" } @@ -1601,20 +1565,22 @@ "array-uniq": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", - "dev": true + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=" }, "array-unique": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" }, "asn1": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "dev": true, "requires": { "safer-buffer": "~2.1.0" } @@ -1623,7 +1589,6 @@ "version": "4.10.1", "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", - "dev": true, "requires": { "bn.js": "^4.0.0", "inherits": "^2.0.1", @@ -1634,7 +1599,6 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", - "dev": true, "requires": { "object-assign": "^4.1.1", "util": "0.10.3" @@ -1643,14 +1607,12 @@ "inherits": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", - "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", - "dev": true + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=" }, "util": { "version": "0.10.3", "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", - "dev": true, "requires": { "inherits": "2.0.1" } @@ -1660,74 +1622,72 @@ "assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" }, "assign-symbols": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" }, "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", - "dev": true + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "requires": { + "lodash": "^4.17.14" + } }, "async-each": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", - "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", - "dev": true + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==" + }, + "async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, "atob": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "dev": true + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" }, "autocomplete.js": { "version": "0.36.0", "resolved": "https://registry.npmjs.org/autocomplete.js/-/autocomplete.js-0.36.0.tgz", "integrity": "sha512-jEwUXnVMeCHHutUt10i/8ZiRaCb0Wo+ZyKxeGsYwBDtw6EJHqEeDrq4UwZRD8YBSvp3g6klP678il2eeiVXN2Q==", - "dev": true, "requires": { "immediate": "^3.2.3" } }, "autoprefixer": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.6.0.tgz", - "integrity": "sha512-kuip9YilBqhirhHEGHaBTZKXL//xxGnzvsD0FtBQa6z+A69qZD6s/BAX9VzDF1i9VKDquTJDQaPLSEhOnL6FvQ==", - "dev": true, + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.7.3.tgz", + "integrity": "sha512-8T5Y1C5Iyj6PgkPSFd0ODvK9DIleuPKUPYniNxybS47g2k2wFgLZ46lGQHlBuGKIAEV8fbCDfKCCRS1tvOgc3Q==", "requires": { - "browserslist": "^4.6.1", - "caniuse-lite": "^1.0.30000971", + "browserslist": "^4.8.0", + "caniuse-lite": "^1.0.30001012", "chalk": "^2.4.2", "normalize-range": "^0.1.2", "num2fraction": "^1.2.2", - "postcss": "^7.0.16", - "postcss-value-parser": "^3.3.1" + "postcss": "^7.0.23", + "postcss-value-parser": "^4.0.2" } }, "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "dev": true + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" }, "aws4": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", - "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", - "dev": true + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.0.tgz", + "integrity": "sha512-Uvq6hVe90D0B2WEnUqtdgY1bATGz3mw33nH9Y+dmA+w5DHvUmBgkr5rM/KCHpCsiFNRUfokW/szpPPgMK2hm4A==" }, "axios": { "version": "0.19.0", @@ -1736,53 +1696,38 @@ "requires": { "follow-redirects": "1.5.10", "is-buffer": "^2.0.2" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - }, - "follow-redirects": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", - "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", - "requires": { - "debug": "=3.1.0" - } - }, - "is-buffer": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz", - "integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==" - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } } }, "babel-loader": { "version": "8.0.6", "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.0.6.tgz", "integrity": "sha512-4BmWKtBOBm13uoUwd08UwjZlaw3O9GWf456R9j+5YykFZ6LUIjIKLc0zEZf+hauxPOJs96C8k6FvYD09vWzhYw==", - "dev": true, "requires": { "find-cache-dir": "^2.0.0", "loader-utils": "^1.0.2", "mkdirp": "^0.5.1", "pify": "^4.0.1" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + } + } } }, "babel-plugin-dynamic-import-node": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz", "integrity": "sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ==", - "dev": true, "requires": { "object.assign": "^4.1.0" } @@ -1791,7 +1736,6 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/babel-plugin-module-resolver/-/babel-plugin-module-resolver-3.2.0.tgz", "integrity": "sha512-tjR0GvSndzPew/Iayf4uICWZqjBwnlMWjSx6brryfQ81F9rxBVqwDJtFCV8oOs0+vJeefK9TmdZtkIFdFe1UnA==", - "dev": true, "requires": { "find-babel-config": "^1.1.0", "glob": "^7.1.2", @@ -1800,17 +1744,40 @@ "resolve": "^1.4.0" } }, - "balanced-match": { - "version": "1.0.0", + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "requires": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + } + }, + "babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "requires": { + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==" + }, + "balanced-match": { + "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, "base": { "version": "0.11.2", "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, "requires": { "cache-base": "^1.0.1", "class-utils": "^0.3.5", @@ -1825,7 +1792,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, "requires": { "is-descriptor": "^1.0.0" } @@ -1834,7 +1800,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, "requires": { "kind-of": "^6.0.0" } @@ -1843,7 +1808,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, "requires": { "kind-of": "^6.0.0" } @@ -1852,32 +1816,33 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", "is-data-descriptor": "^1.0.0", "kind-of": "^6.0.2" } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" } } }, "base64-js": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", - "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==", - "dev": true + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" }, "batch": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", - "dev": true + "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=" }, "bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "dev": true, "requires": { "tweetnacl": "^0.14.3" } @@ -1885,32 +1850,27 @@ "big.js": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "dev": true + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==" }, "binary-extensions": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", - "dev": true + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==" }, "bluebird": { - "version": "3.5.5", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz", - "integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==", - "dev": true + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" }, "bn.js": { "version": "4.11.8", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", - "dev": true + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" }, "body-parser": { "version": "1.19.0", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", - "dev": true, "requires": { "bytes": "3.1.0", "content-type": "~1.0.4", @@ -1927,23 +1887,12 @@ "bytes": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", - "dev": true - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" } } }, @@ -1951,7 +1900,6 @@ "version": "3.5.0", "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", - "dev": true, "requires": { "array-flatten": "^2.1.0", "deep-equal": "^1.0.1", @@ -1964,14 +1912,12 @@ "boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", - "dev": true + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1981,7 +1927,6 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, "requires": { "arr-flatten": "^1.1.0", "array-unique": "^0.3.2", @@ -1999,7 +1944,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, "requires": { "is-extendable": "^0.1.0" } @@ -2009,14 +1953,12 @@ "brorand": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", - "dev": true + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" }, "browserify-aes": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", - "dev": true, "requires": { "buffer-xor": "^1.0.3", "cipher-base": "^1.0.0", @@ -2030,7 +1972,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", - "dev": true, "requires": { "browserify-aes": "^1.0.4", "browserify-des": "^1.0.0", @@ -2041,7 +1982,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", - "dev": true, "requires": { "cipher-base": "^1.0.1", "des.js": "^1.0.0", @@ -2053,7 +1993,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", - "dev": true, "requires": { "bn.js": "^4.1.0", "randombytes": "^2.0.1" @@ -2063,7 +2002,6 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", - "dev": true, "requires": { "bn.js": "^4.1.1", "browserify-rsa": "^4.0.0", @@ -2078,86 +2016,83 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", - "dev": true, "requires": { "pako": "~1.0.5" } }, "browserslist": { - "version": "4.6.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.6.3.tgz", - "integrity": "sha512-CNBqTCq22RKM8wKJNowcqihHJ4SkI8CGeK7KOR9tPboXUuS5Zk5lQgzzTbs4oxD8x+6HUshZUa2OyNI9lR93bQ==", - "dev": true, + "version": "4.8.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.8.2.tgz", + "integrity": "sha512-+M4oeaTplPm/f1pXDw84YohEv7B1i/2Aisei8s4s6k3QsoSHa7i5sz8u/cGQkkatCPxMASKxPualR4wwYgVboA==", "requires": { - "caniuse-lite": "^1.0.30000975", - "electron-to-chromium": "^1.3.164", - "node-releases": "^1.1.23" + "caniuse-lite": "^1.0.30001015", + "electron-to-chromium": "^1.3.322", + "node-releases": "^1.1.42" } }, "buffer": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", - "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", - "dev": true, + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", "requires": { "base64-js": "^1.0.2", "ieee754": "^1.1.4", "isarray": "^1.0.0" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + } } }, "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "dev": true + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" }, "buffer-indexof": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", - "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==", - "dev": true + "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==" }, "buffer-json": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/buffer-json/-/buffer-json-2.0.0.tgz", - "integrity": "sha512-+jjPFVqyfF1esi9fvfUs3NqM0pH1ziZ36VP4hmA/y/Ssfo/5w5xHKfTw9BwQjoJ1w/oVtpLomqwUHKdefGyuHw==", - "dev": true + "integrity": "sha512-+jjPFVqyfF1esi9fvfUs3NqM0pH1ziZ36VP4hmA/y/Ssfo/5w5xHKfTw9BwQjoJ1w/oVtpLomqwUHKdefGyuHw==" }, "buffer-xor": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", - "dev": true + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" }, "builtin-status-codes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", - "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", - "dev": true + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=" }, "bytes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", - "dev": true + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" }, "cac": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/cac/-/cac-6.5.2.tgz", - "integrity": "sha512-8JdiD9/ZLsG418j/chyZQ3VWuhFELSGlH4EUxzNKgIH8wK8dO0j5Pqu6Pk7B/RP3kX9aasyQhPrrUjYO5e0w7w==", - "dev": true + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.5.3.tgz", + "integrity": "sha512-wZfzSWVXuue1H3J7TDNjbzg4KTqPXCmh7F3QIzEYXfnhMCcOUrx99M7rpO2UDVJA9dqv3butGj2nHvCV47CmPg==" }, "cacache": { - "version": "11.3.3", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.3.tgz", - "integrity": "sha512-p8WcneCytvzPxhDvYp31PD039vi77I12W+/KfR9S8AZbaiARFBCpsPJS+9uhWfeBfeAtW7o/4vt3MUqLkbY6nA==", - "dev": true, + "version": "12.0.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.3.tgz", + "integrity": "sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw==", "requires": { "bluebird": "^3.5.5", "chownr": "^1.1.1", "figgy-pudding": "^3.5.1", "glob": "^7.1.4", "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", "lru-cache": "^5.1.1", "mississippi": "^3.0.0", "mkdirp": "^0.5.1", @@ -2167,13 +2102,27 @@ "ssri": "^6.0.1", "unique-filename": "^1.1.1", "y18n": "^4.0.0" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + } + } } }, "cache-base": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, "requires": { "collection-visit": "^1.0.0", "component-emitter": "^1.2.1", @@ -2190,7 +2139,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/cache-loader/-/cache-loader-3.0.1.tgz", "integrity": "sha512-HzJIvGiGqYsFUrMjAJNDbVZoG7qQA+vy9AIoKs7s9DscNfki0I589mf2w6/tW+kkFH3zyiknoWV5Jdynu6b/zw==", - "dev": true, "requires": { "buffer-json": "^2.0.0", "find-cache-dir": "^2.1.0", @@ -2198,19 +2146,32 @@ "mkdirp": "^0.5.1", "neo-async": "^2.6.1", "schema-utils": "^1.0.0" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + } + } } }, "call-me-maybe": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", - "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=", - "dev": true + "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=" }, "caller-callsite": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", - "dev": true, "requires": { "callsites": "^2.0.0" } @@ -2219,7 +2180,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", - "dev": true, "requires": { "caller-callsite": "^2.0.0" } @@ -2227,30 +2187,26 @@ "callsites": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", - "dev": true + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=" }, "camel-case": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", - "dev": true, "requires": { "no-case": "^2.2.0", "upper-case": "^1.1.1" } }, "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=" }, "caniuse-api": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", - "dev": true, "requires": { "browserslist": "^4.0.0", "caniuse-lite": "^1.0.0", @@ -2259,33 +2215,46 @@ } }, "caniuse-lite": { - "version": "1.0.30000978", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000978.tgz", - "integrity": "sha512-H6gK6kxUzG6oAwg/Jal279z8pHw0BzrpZfwo/CA9FFm/vA0l8IhDfkZtepyJNE2Y4V6Dp3P3ubz6czby1/Mgsw==", - "dev": true + "version": "1.0.30001015", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001015.tgz", + "integrity": "sha512-/xL2AbW/XWHNu1gnIrO8UitBGoFthcsDgU9VLK1/dpsoxbaD5LscHozKze05R6WLsBvLhqv78dAPozMFQBYLbQ==" }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "center-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", + "requires": { + "align-text": "^0.1.3", + "lazy-cache": "^1.0.3" + } }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } }, + "character-parser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz", + "integrity": "sha1-x84o821LzZdE5f/CxfzeHHMmH8A=", + "requires": { + "is-regex": "^1.0.3" + } + }, "chokidar": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.6.tgz", - "integrity": "sha512-V2jUo67OKkc6ySiRpJrjlpJKl9kDuG+Xb8VgsGzb+aEouhgS1D0weyPU4lEzdAcsCAvrih2J2BqyXqHWvVLw5g==", - "dev": true, + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", "requires": { "anymatch": "^2.0.0", "async-each": "^1.0.1", @@ -2302,16 +2271,14 @@ } }, "chownr": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz", - "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==", - "dev": true + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.3.tgz", + "integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==" }, "chrome-trace-event": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz", "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==", - "dev": true, "requires": { "tslib": "^1.9.0" } @@ -2319,14 +2286,12 @@ "ci-info": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", - "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==", - "dev": true + "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==" }, "cipher-base": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", - "dev": true, "requires": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -2336,7 +2301,6 @@ "version": "0.3.6", "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dev": true, "requires": { "arr-union": "^3.1.0", "define-property": "^0.2.5", @@ -2348,7 +2312,6 @@ "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, "requires": { "is-descriptor": "^0.1.0" } @@ -2359,24 +2322,14 @@ "version": "4.2.1", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz", "integrity": "sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g==", - "dev": true, "requires": { "source-map": "~0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } } }, "clipboard": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.4.tgz", "integrity": "sha512-Vw26VSLRpJfBofiVaFb/I8PVfdI1OxKcYShe6fm0sP/DtmiWQNCjhM/okTvdCo0G+lMMm1rMYbk4IK4x1X+kgQ==", - "dev": true, "optional": true, "requires": { "good-listener": "^1.2.2", @@ -2384,39 +2337,25 @@ "tiny-emitter": "^2.0.0" } }, + "clipboard-copy": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/clipboard-copy/-/clipboard-copy-3.1.0.tgz", + "integrity": "sha512-Xsu1NddBXB89IUauda5BIq3Zq73UWkjkaQlPQbLNvNsd5WBMnTWPNKYR6HGaySOxGYZ+BKxP2E9X4ElnI3yiPA==" + }, "cliui": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", - "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", - "dev": true, + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } + "center-align": "^0.1.1", + "right-align": "^0.1.1", + "wordwrap": "0.0.2" } }, "coa": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", - "dev": true, "requires": { "@types/q": "^1.5.1", "chalk": "^2.4.1", @@ -2426,14 +2365,12 @@ "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, "collection-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, "requires": { "map-visit": "^1.0.0", "object-visit": "^1.0.0" @@ -2443,7 +2380,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/color/-/color-3.1.2.tgz", "integrity": "sha512-vXTJhHebByxZn3lDvDJYw4lR5+uB3vuoHsuYA5AKuxRVn5wzzIfQKGLBmgdVRHKTJYeK5rvJcHnrd0Li49CFpg==", - "dev": true, "requires": { "color-convert": "^1.9.1", "color-string": "^1.5.2" @@ -2453,7 +2389,6 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "requires": { "color-name": "1.1.3" } @@ -2461,14 +2396,12 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, "color-string": { "version": "1.5.3", "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz", "integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==", - "dev": true, "requires": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" @@ -2478,7 +2411,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, "requires": { "delayed-stream": "~1.0.0" } @@ -2486,26 +2418,22 @@ "commander": { "version": "2.17.1", "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", - "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", - "dev": true + "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==" }, "commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=" }, "component-emitter": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" }, "compressible": { "version": "2.0.17", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.17.tgz", "integrity": "sha512-BGHeLCK1GV7j1bSmQQAi26X+GgWcTjLr/0tzSvMCl3LH1w1IJ4PFSPoV5316b30cneTziC+B1a+3OjoSUcQYmw==", - "dev": true, "requires": { "mime-db": ">= 1.40.0 < 2" } @@ -2514,7 +2442,6 @@ "version": "1.7.4", "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", - "dev": true, "requires": { "accepts": "~1.3.5", "bytes": "3.0.0", @@ -2525,34 +2452,22 @@ "vary": "~1.1.2" }, "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" } } }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "concat-stream": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, "requires": { "buffer-from": "^1.0.0", "inherits": "^2.0.3", @@ -2563,80 +2478,91 @@ "connect-history-api-fallback": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", - "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", - "dev": true + "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==" }, "consola": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/consola/-/consola-2.9.0.tgz", - "integrity": "sha512-34Iue+LRcWbndFIfZc5boNizWlsrRjqIBJZTe591vImgbnq7nx2EzlrLtANj9TH2Fxm7puFJBJAOk5BhvZOddQ==", - "dev": true + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/consola/-/consola-2.11.0.tgz", + "integrity": "sha512-2bcAqHastlPSCvZ+ur8bgHInGAWvUnysWz3h3xRX+/XZoCY7avolJJnVXOPGoVoyCcg1b231XixonoArmgxaoA==" }, "console-browserify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", - "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", - "dev": true, - "requires": { - "date-now": "^0.1.4" - } + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==" }, "consolidate": { "version": "0.15.1", "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.15.1.tgz", "integrity": "sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw==", - "dev": true, "requires": { "bluebird": "^3.1.1" } }, + "constantinople": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-3.1.2.tgz", + "integrity": "sha512-yePcBqEFhLOqSBtwYOGGS1exHo/s1xjekXiinh4itpNQGCu4KA1euPh1fg07N2wMITZXQkBz75Ntdt1ctGZouw==", + "requires": { + "@types/babel-types": "^7.0.0", + "@types/babylon": "^6.16.2", + "babel-types": "^6.26.0", + "babylon": "^6.18.0" + } + }, "constants-browserify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", - "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", - "dev": true + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=" }, "content-disposition": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", - "dev": true, "requires": { "safe-buffer": "5.1.2" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } } }, "content-type": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", - "dev": true + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" }, "convert-source-map": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", - "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", - "dev": true, + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", "requires": { "safe-buffer": "~5.1.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } } }, "cookie": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", - "dev": true + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" }, "cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", - "dev": true + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" }, "copy-concurrently": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", - "dev": true, "requires": { "aproba": "^1.1.1", "fs-write-stream-atomic": "^1.0.8", @@ -2644,21 +2570,34 @@ "mkdirp": "^0.5.1", "rimraf": "^2.5.4", "run-queue": "^1.0.0" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + } + } } }, "copy-descriptor": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" }, "copy-webpack-plugin": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-5.0.3.tgz", - "integrity": "sha512-PlZRs9CUMnAVylZq+vg2Juew662jWtwOXOqH4lbQD9ZFhRG9R7tVStOgHt21CBGVq7k5yIJaz8TXDLSjV+Lj8Q==", - "dev": true, + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-5.0.5.tgz", + "integrity": "sha512-7N68eIoQTyudAuxkfPT7HzGoQ+TsmArN/I3HFwG+lVE3FNzqvZKIiaxtYh4o3BIznioxUvx9j26+Rtsc9htQUQ==", "requires": { - "cacache": "^11.3.2", + "cacache": "^12.0.3", "find-cache-dir": "^2.1.0", "glob-parent": "^3.1.0", "globby": "^7.1.1", @@ -2666,9 +2605,9 @@ "loader-utils": "^1.2.3", "minimatch": "^3.0.4", "normalize-path": "^3.0.0", - "p-limit": "^2.2.0", + "p-limit": "^2.2.1", "schema-utils": "^1.0.0", - "serialize-javascript": "^1.7.0", + "serialize-javascript": "^2.1.0", "webpack-log": "^2.0.0" }, "dependencies": { @@ -2676,7 +2615,6 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/globby/-/globby-7.1.1.tgz", "integrity": "sha1-+yzP+UAfhgCUXfral0QMypcrhoA=", - "dev": true, "requires": { "array-union": "^1.0.1", "dir-glob": "^2.0.0", @@ -2689,14 +2627,12 @@ "ignore": { "version": "3.3.10", "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", - "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", - "dev": true + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==" }, "p-limit": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", - "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", - "dev": true, + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", + "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", "requires": { "p-try": "^2.0.0" } @@ -2704,40 +2640,34 @@ "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" }, "pify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" }, "slash": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", - "dev": true + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=" } } }, "core-js": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.9.tgz", - "integrity": "sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==", - "dev": true + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz", + "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==" }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "cosmiconfig": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", - "dev": true, "requires": { "import-fresh": "^2.0.0", "is-directory": "^0.3.1", @@ -2749,7 +2679,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", - "dev": true, "requires": { "bn.js": "^4.1.0", "elliptic": "^6.0.0" @@ -2759,7 +2688,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", - "dev": true, "requires": { "cipher-base": "^1.0.1", "inherits": "^2.0.1", @@ -2772,7 +2700,6 @@ "version": "1.1.7", "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", - "dev": true, "requires": { "cipher-base": "^1.0.3", "create-hash": "^1.1.0", @@ -2786,7 +2713,6 @@ "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, "requires": { "nice-try": "^1.0.4", "path-key": "^2.0.1", @@ -2799,7 +2725,6 @@ "version": "3.12.0", "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", - "dev": true, "requires": { "browserify-cipher": "^1.0.0", "browserify-sign": "^4.0.0", @@ -2814,17 +2739,26 @@ "randomfill": "^1.0.3" } }, + "css": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz", + "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==", + "requires": { + "inherits": "^2.0.3", + "source-map": "^0.6.1", + "source-map-resolve": "^0.5.2", + "urix": "^0.1.0" + } + }, "css-color-names": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", - "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=", - "dev": true + "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=" }, "css-declaration-sorter": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz", "integrity": "sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA==", - "dev": true, "requires": { "postcss": "^7.0.1", "timsort": "^0.3.0" @@ -2834,7 +2768,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-2.1.1.tgz", "integrity": "sha512-OcKJU/lt232vl1P9EEDamhoO9iKY3tIjY5GU+XDLblAykTdgs6Ux9P1hTHve8nFKy5KPpOXOsVI/hIwi3841+w==", - "dev": true, "requires": { "camelcase": "^5.2.0", "icss-utils": "^4.1.0", @@ -2847,22 +2780,35 @@ "postcss-modules-values": "^2.0.0", "postcss-value-parser": "^3.3.0", "schema-utils": "^1.0.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } } }, "css-parse": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-1.7.0.tgz", - "integrity": "sha1-Mh9s9zeCpv91ERE5D8BeLGV9jJs=", - "dev": true + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-2.0.0.tgz", + "integrity": "sha1-pGjuZnwW2BzPBcWMONKpfHgNv9Q=", + "requires": { + "css": "^2.0.0" + } }, "css-select": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.0.2.tgz", - "integrity": "sha512-dSpYaDVoWaELjvZ3mS6IKZM/y2PMPa/XYoEfYNZePL4U/XgyxZNroHEHReDx/d+VgXh9VbCTtFqLkFbmeqeaRQ==", - "dev": true, + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", + "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", "requires": { "boolbase": "^1.0.0", - "css-what": "^2.1.2", + "css-what": "^3.2.1", "domutils": "^1.7.0", "nth-check": "^1.0.2" } @@ -2870,48 +2816,36 @@ "css-select-base-adapter": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", - "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==", - "dev": true + "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==" }, "css-tree": { - "version": "1.0.0-alpha.28", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.28.tgz", - "integrity": "sha512-joNNW1gCp3qFFzj4St6zk+Wh/NBv0vM5YbEreZk0SD4S23S+1xBKb6cLDg2uj4P4k/GUMlIm6cKIDqIG+vdt0w==", - "dev": true, + "version": "1.0.0-alpha.37", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", + "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==", "requires": { - "mdn-data": "~1.1.0", - "source-map": "^0.5.3" + "mdn-data": "2.0.4", + "source-map": "^0.6.1" } }, "css-unit-converter": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.1.tgz", - "integrity": "sha1-2bkoGtz9jO2TW9urqDeGiX9k6ZY=", - "dev": true - }, - "css-url-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/css-url-regex/-/css-url-regex-1.1.0.tgz", - "integrity": "sha1-g4NCMMyfdMRX3lnuvRVD/uuDt+w=", - "dev": true + "integrity": "sha1-2bkoGtz9jO2TW9urqDeGiX9k6ZY=" }, "css-what": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", - "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==", - "dev": true + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.2.1.tgz", + "integrity": "sha512-WwOrosiQTvyms+Ti5ZC5vGEK0Vod3FTt1ca+payZqvKuGJF+dq7bG63DstxtN0dpm6FxY27a/zS3Wten+gEtGw==" }, "cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==" }, "cssnano": { "version": "4.1.10", "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.10.tgz", "integrity": "sha512-5wny+F6H4/8RgNlaqab4ktc3e0/blKutmq8yNlBFXA//nSFFAqAngjNVRzUvCgYROULmZZUoosL/KSoZo5aUaQ==", - "dev": true, "requires": { "cosmiconfig": "^5.0.0", "cssnano-preset-default": "^4.0.7", @@ -2923,7 +2857,6 @@ "version": "4.0.7", "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-4.0.7.tgz", "integrity": "sha512-x0YHHx2h6p0fCl1zY9L9roD7rnlltugGu7zXSKQx6k2rYw0Hi3IqxcoAGF7u9Q5w1nt7vK0ulxV8Lo+EvllGsA==", - "dev": true, "requires": { "css-declaration-sorter": "^4.0.1", "cssnano-util-raw-cache": "^4.0.1", @@ -2960,20 +2893,17 @@ "cssnano-util-get-arguments": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz", - "integrity": "sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8=", - "dev": true + "integrity": "sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8=" }, "cssnano-util-get-match": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz", - "integrity": "sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0=", - "dev": true + "integrity": "sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0=" }, "cssnano-util-raw-cache": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz", "integrity": "sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA==", - "dev": true, "requires": { "postcss": "^7.0.0" } @@ -2981,95 +2911,74 @@ "cssnano-util-same-parent": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz", - "integrity": "sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q==", - "dev": true + "integrity": "sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q==" }, "csso": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/csso/-/csso-3.5.1.tgz", - "integrity": "sha512-vrqULLffYU1Q2tLdJvaCYbONStnfkfimRxXNaGjxMldI0C7JPBC4rB1RyjhfdZ4m1frm8pM9uRPKH3d2knZ8gg==", - "dev": true, + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.0.2.tgz", + "integrity": "sha512-kS7/oeNVXkHWxby5tHVxlhjizRCSv8QdU7hB2FpdAibDU8FjTAolhNjKNTiLzXtUrKT6HwClE81yXwEk1309wg==", "requires": { - "css-tree": "1.0.0-alpha.29" - }, - "dependencies": { - "css-tree": { - "version": "1.0.0-alpha.29", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.29.tgz", - "integrity": "sha512-sRNb1XydwkW9IOci6iB2xmy8IGCj6r/fr+JWitvJ2JxQRPzN3T4AGGVWCMlVmVwM1gtgALJRmGIlWv5ppnGGkg==", - "dev": true, - "requires": { - "mdn-data": "~1.1.0", - "source-map": "^0.5.3" - } - } + "css-tree": "1.0.0-alpha.37" } }, "cyclist": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz", - "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=", - "dev": true + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", + "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=" }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, "requires": { "assert-plus": "^1.0.0" } }, - "date-now": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", - "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", - "dev": true - }, "de-indent": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", - "integrity": "sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0=", - "dev": true + "integrity": "sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0=" }, "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "requires": { - "ms": "^2.1.1" + "ms": "2.0.0" } }, "decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" }, "decode-uri-component": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", - "dev": true + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" }, "deep-equal": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", - "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=", - "dev": true + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", + "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", + "requires": { + "is-arguments": "^1.0.4", + "is-date-object": "^1.0.1", + "is-regex": "^1.0.4", + "object-is": "^1.0.1", + "object-keys": "^1.1.1", + "regexp.prototype.flags": "^1.2.0" + } }, "deepmerge": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-1.5.2.tgz", - "integrity": "sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ==", - "dev": true + "integrity": "sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ==" }, "default-gateway": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz", "integrity": "sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==", - "dev": true, "requires": { "execa": "^1.0.0", "ip-regex": "^2.1.0" @@ -3079,7 +2988,6 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, "requires": { "object-keys": "^1.0.12" } @@ -3088,7 +2996,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, "requires": { "is-descriptor": "^1.0.2", "isobject": "^3.0.1" @@ -3098,7 +3005,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, "requires": { "kind-of": "^6.0.0" } @@ -3107,7 +3013,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, "requires": { "kind-of": "^6.0.0" } @@ -3116,12 +3021,16 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", "is-data-descriptor": "^1.0.0", "kind-of": "^6.0.2" } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" } } }, @@ -3129,7 +3038,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==", - "dev": true, "requires": { "@types/glob": "^7.1.1", "globby": "^6.1.0", @@ -3144,7 +3052,6 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", - "dev": true, "requires": { "array-union": "^1.0.1", "glob": "^7.0.3", @@ -3156,8 +3063,7 @@ "pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" } } } @@ -3166,27 +3072,23 @@ "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, "delegate": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==", - "dev": true, "optional": true }, "depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "dev": true + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" }, "des.js": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", - "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", - "dev": true, + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", "requires": { "inherits": "^2.0.1", "minimalistic-assert": "^1.0.0" @@ -3195,26 +3097,22 @@ "destroy": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", - "dev": true + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" }, "detect-node": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz", - "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==", - "dev": true + "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==" }, "diacritics": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/diacritics/-/diacritics-1.3.0.tgz", - "integrity": "sha1-PvqHMj67hj5mls67AILUj/PW96E=", - "dev": true + "integrity": "sha1-PvqHMj67hj5mls67AILUj/PW96E=" }, "diffie-hellman": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", - "dev": true, "requires": { "bn.js": "^4.1.0", "miller-rabin": "^4.0.0", @@ -3225,7 +3123,6 @@ "version": "2.2.2", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", - "dev": true, "requires": { "path-type": "^3.0.0" } @@ -3233,14 +3130,12 @@ "dns-equal": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", - "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=", - "dev": true + "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=" }, "dns-packet": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz", "integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==", - "dev": true, "requires": { "ip": "^1.1.0", "safe-buffer": "^5.0.1" @@ -3250,7 +3145,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", - "dev": true, "requires": { "buffer-indexof": "^1.0.0" } @@ -3259,7 +3153,6 @@ "version": "2.6.3", "resolved": "https://registry.npmjs.org/docsearch.js/-/docsearch.js-2.6.3.tgz", "integrity": "sha512-GN+MBozuyz664ycpZY0ecdQE0ND/LSgJKhTLA0/v3arIS3S1Rpf2OJz6A35ReMsm91V5apcmzr5/kM84cvUg+A==", - "dev": true, "requires": { "algoliasearch": "^3.24.5", "autocomplete.js": "0.36.0", @@ -3270,48 +3163,54 @@ "zepto": "^1.2.0" } }, + "doctypes": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz", + "integrity": "sha1-6oCxBqh1OHdOijpKWv4pPeSJ4Kk=" + }, "dom-converter": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", - "dev": true, "requires": { "utila": "~0.4" } }, "dom-serializer": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", - "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", - "dev": true, + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", + "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", "requires": { - "domelementtype": "^1.3.0", - "entities": "^1.1.1" + "domelementtype": "^2.0.1", + "entities": "^2.0.0" + }, + "dependencies": { + "domelementtype": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.1.tgz", + "integrity": "sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ==" + } } }, "dom-walk": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.1.tgz", - "integrity": "sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg=", - "dev": true + "integrity": "sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg=" }, "domain-browser": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", - "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", - "dev": true + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==" }, "domelementtype": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", - "dev": true + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" }, "domhandler": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", - "dev": true, "requires": { "domelementtype": "1" } @@ -3320,7 +3219,6 @@ "version": "1.7.0", "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", - "dev": true, "requires": { "dom-serializer": "0", "domelementtype": "1" @@ -3330,7 +3228,6 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", - "dev": true, "requires": { "is-obj": "^1.0.0" } @@ -3339,7 +3236,6 @@ "version": "3.7.1", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", - "dev": true, "requires": { "end-of-stream": "^1.0.0", "inherits": "^2.0.1", @@ -3351,7 +3247,6 @@ "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "dev": true, "requires": { "jsbn": "~0.1.0", "safer-buffer": "^2.1.0" @@ -3360,20 +3255,17 @@ "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", - "dev": true + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, "electron-to-chromium": { - "version": "1.3.175", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.175.tgz", - "integrity": "sha512-cQ0o7phcPA0EYkN4juZy/rq4XVxl/1ywQnytDT9hZTC0cHfaOBqWK2XlWp9Mk8xRGntgnmxlHTOux4HLb2ZNnA==", - "dev": true + "version": "1.3.322", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.322.tgz", + "integrity": "sha512-Tc8JQEfGQ1MzfSzI/bTlSr7btJv/FFO7Yh6tanqVmIWOuNCu6/D1MilIEgLtmWqIrsv+o4IjpLAhgMBr/ncNAA==" }, "elliptic": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.0.tgz", - "integrity": "sha512-eFOJTMyCYb7xtE/caJ6JJu+bhi67WCYNbkGSknu20pmM8Ke/bqOfdnZWxyoGN26JgfxTbXrsCkEw4KheCT/KGg==", - "dev": true, + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.2.tgz", + "integrity": "sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==", "requires": { "bn.js": "^4.4.0", "brorand": "^1.0.1", @@ -3387,68 +3279,70 @@ "emoji-regex": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" }, "emojis-list": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", - "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", - "dev": true + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=" }, "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", - "dev": true + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" }, "end-of-stream": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", - "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", - "dev": true, + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "requires": { "once": "^1.4.0" } }, "enhanced-resolve": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz", - "integrity": "sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng==", - "dev": true, + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.1.tgz", + "integrity": "sha512-98p2zE+rL7/g/DzMHMTF4zZlCgeVdJ7yr6xzEpJRYwFYrGi9ANdn5DnJURg6RpBkyk60XYDnWIv51VfIhfNGuA==", "requires": { "graceful-fs": "^4.1.2", - "memory-fs": "^0.4.0", + "memory-fs": "^0.5.0", "tapable": "^1.0.0" + }, + "dependencies": { + "memory-fs": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", + "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + } } }, "entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", - "dev": true + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz", + "integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw==" }, "envify": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/envify/-/envify-4.1.0.tgz", "integrity": "sha512-IKRVVoAYr4pIx4yIWNsz9mOsboxlNXiu7TNBnem/K/uTHdkyzXWDzHCK7UTolqBbgaBz0tQHsD3YNls0uIIjiw==", - "dev": true, "requires": { "esprima": "^4.0.0", "through": "~2.3.4" } }, "envinfo": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.3.1.tgz", - "integrity": "sha512-GvXiDTqLYrORVSCuJCsWHPXF5BFvoWMQA9xX4YVjPT1jyS3aZEHUBwjzxU/6LTPF9ReHgVEbX7IEN5UvSXHw/A==", - "dev": true + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.5.0.tgz", + "integrity": "sha512-jDgnJaF/Btomk+m3PZDTTCb5XIIIX3zYItnCRfF73zVgvinLoRomuhi75Y4su0PtQxWz4v66XnLLckyvyJTOIQ==" }, "errno": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", - "dev": true, "requires": { "prr": "~1.0.1" } @@ -3457,30 +3351,31 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, "requires": { "is-arrayish": "^0.2.1" } }, "es-abstract": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", - "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", - "dev": true, + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.16.3.tgz", + "integrity": "sha512-WtY7Fx5LiOnSYgF5eg/1T+GONaGmpvpPdCpSnYij+U2gDTL0UPfWrhDw7b2IYb+9NQJsYpCA0wOQvZfsd6YwRw==", "requires": { - "es-to-primitive": "^1.2.0", + "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", "has": "^1.0.3", + "has-symbols": "^1.0.1", "is-callable": "^1.1.4", "is-regex": "^1.0.4", - "object-keys": "^1.0.12" + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "string.prototype.trimleft": "^2.1.0", + "string.prototype.trimright": "^2.1.0" } }, "es-to-primitive": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", - "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", - "dev": true, + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", "requires": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", @@ -3490,26 +3385,22 @@ "es6-promise": { "version": "4.2.8", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", - "dev": true + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", - "dev": true + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, "eslint-scope": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", - "dev": true, "requires": { "esrecurse": "^4.1.0", "estraverse": "^4.1.1" @@ -3518,53 +3409,45 @@ "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" }, "esrecurse": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", - "dev": true, "requires": { "estraverse": "^4.1.0" } }, "estraverse": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", - "dev": true + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" }, "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", - "dev": true + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" }, "etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", - "dev": true + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" }, "eventemitter3": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", - "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==", - "dev": true + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.0.tgz", + "integrity": "sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==" }, "events": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz", - "integrity": "sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA==", - "dev": true + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" }, "eventsource": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.0.7.tgz", "integrity": "sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ==", - "dev": true, "requires": { "original": "^1.0.0" } @@ -3573,7 +3456,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", - "dev": true, "requires": { "md5.js": "^1.3.4", "safe-buffer": "^5.1.1" @@ -3583,7 +3465,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, "requires": { "cross-spawn": "^6.0.0", "get-stream": "^4.0.0", @@ -3598,7 +3479,6 @@ "version": "2.1.4", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, "requires": { "debug": "^2.3.3", "define-property": "^0.2.5", @@ -3609,20 +3489,10 @@ "to-regex": "^3.0.1" }, "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, "requires": { "is-descriptor": "^0.1.0" } @@ -3631,16 +3501,9 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, "requires": { "is-extendable": "^0.1.0" } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true } } }, @@ -3648,7 +3511,6 @@ "version": "4.17.1", "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", - "dev": true, "requires": { "accepts": "~1.3.7", "array-flatten": "1.1.1", @@ -3685,37 +3547,29 @@ "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", - "dev": true + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" } } }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, "extend-shallow": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, "requires": { "assign-symbols": "^1.0.0", "is-extendable": "^1.0.1" @@ -3725,7 +3579,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, "requires": { "is-plain-object": "^2.0.4" } @@ -3736,7 +3589,6 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, "requires": { "array-unique": "^0.3.2", "define-property": "^1.0.0", @@ -3752,7 +3604,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, "requires": { "is-descriptor": "^1.0.0" } @@ -3761,7 +3612,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, "requires": { "is-extendable": "^0.1.0" } @@ -3770,7 +3620,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, "requires": { "kind-of": "^6.0.0" } @@ -3779,7 +3628,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, "requires": { "kind-of": "^6.0.0" } @@ -3788,32 +3636,33 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", "is-data-descriptor": "^1.0.0", "kind-of": "^6.0.2" } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" } } }, "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" }, "fast-deep-equal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", - "dev": true + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" }, "fast-glob": { "version": "2.2.7", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz", "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", - "dev": true, "requires": { "@mrmlnc/readdir-enhanced": "^2.2.1", "@nodelib/fs.stat": "^1.1.2", @@ -3826,14 +3675,12 @@ "fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", - "dev": true + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" }, "faye-websocket": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", - "dev": true, "requires": { "websocket-driver": ">=0.5.1" } @@ -3841,14 +3688,12 @@ "figgy-pudding": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz", - "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==", - "dev": true + "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==" }, "figures": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.0.0.tgz", - "integrity": "sha512-HKri+WoWoUgr83pehn/SIgLOMZ9nAWC6dcGj26RY2R4F50u4+RTUz0RCrUlOV3nKRAICW1UGzyb+kcX2qK1S/g==", - "dev": true, + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.1.0.tgz", + "integrity": "sha512-ravh8VRXqHuMvZt/d8GblBeqDMkdJMBdv/2KntFH+ra5MXkO7nxNKpzQ3n6QD/2da1kH0aWmNISdvhM7gl2gVg==", "requires": { "escape-string-regexp": "^1.0.5" } @@ -3857,7 +3702,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-3.0.1.tgz", "integrity": "sha512-4sNIOXgtH/9WZq4NvlfU3Opn5ynUsqBwSLyM+I7UOwdGigTBYfVVQEwe/msZNX/j4pCJTIM14Fsw66Svo1oVrw==", - "dev": true, "requires": { "loader-utils": "^1.0.2", "schema-utils": "^1.0.0" @@ -3867,7 +3711,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, "requires": { "extend-shallow": "^2.0.1", "is-number": "^3.0.0", @@ -3879,7 +3722,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, "requires": { "is-extendable": "^0.1.0" } @@ -3890,7 +3732,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", - "dev": true, "requires": { "debug": "2.6.9", "encodeurl": "~1.0.2", @@ -3899,30 +3740,12 @@ "parseurl": "~1.3.3", "statuses": "~1.5.0", "unpipe": "~1.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } } }, "find-babel-config": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/find-babel-config/-/find-babel-config-1.2.0.tgz", "integrity": "sha512-jB2CHJeqy6a820ssiqwrKMeyC6nNdmrcgkKWJWmpoxpE8RKciYJXCcXRq1h2AzCo5I5BJeN2tkGEO3hLTuePRA==", - "dev": true, "requires": { "json5": "^0.5.1", "path-exists": "^3.0.0" @@ -3931,8 +3754,7 @@ "json5": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", - "dev": true + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" } } }, @@ -3940,7 +3762,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", - "dev": true, "requires": { "commondir": "^1.0.1", "make-dir": "^2.0.0", @@ -3951,7 +3772,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, "requires": { "locate-path": "^2.0.0" } @@ -3960,28 +3780,25 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", - "dev": true, "requires": { "inherits": "^2.0.3", "readable-stream": "^2.3.6" } }, "follow-redirects": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.7.0.tgz", - "integrity": "sha512-m/pZQy4Gj287eNy94nivy5wchN3Kp+Q5WgUPNy5lJSZ3sgkVKSYV/ZChMAQVIgx1SqfZ2zBZtPA2YlXIWxxJOQ==", - "dev": true, + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", "requires": { - "debug": "^3.2.6" + "debug": "=3.1.0" }, "dependencies": { "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "requires": { - "ms": "^2.1.1" + "ms": "2.0.0" } } } @@ -3989,26 +3806,22 @@ "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" }, "foreach": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", - "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", - "dev": true + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=" }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" }, "form-data": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, "requires": { "asynckit": "^0.4.0", "combined-stream": "^1.0.6", @@ -4018,14 +3831,12 @@ "forwarded": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", - "dev": true + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" }, "fragment-cache": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, "requires": { "map-cache": "^0.2.2" } @@ -4033,14 +3844,12 @@ "fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", - "dev": true + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" }, "from2": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", - "dev": true, "requires": { "inherits": "^2.0.1", "readable-stream": "^2.0.0" @@ -4050,7 +3859,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", - "dev": true, "requires": { "graceful-fs": "^4.1.2", "jsonfile": "^4.0.0", @@ -4061,7 +3869,6 @@ "version": "1.0.10", "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", - "dev": true, "requires": { "graceful-fs": "^4.1.2", "iferr": "^0.1.5", @@ -4072,14 +3879,12 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "fsevents": { "version": "1.2.9", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", - "dev": true, "optional": true, "requires": { "nan": "^2.12.1", @@ -4089,25 +3894,21 @@ "abbrev": { "version": "1.1.1", "bundled": true, - "dev": true, "optional": true }, "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true, "optional": true }, "aproba": { "version": "1.2.0", "bundled": true, - "dev": true, "optional": true }, "are-we-there-yet": { "version": "1.1.5", "bundled": true, - "dev": true, "optional": true, "requires": { "delegates": "^1.0.0", @@ -4117,13 +3918,11 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, - "dev": true, "optional": true, "requires": { "balanced-match": "^1.0.0", @@ -4133,37 +3932,31 @@ "chownr": { "version": "1.1.1", "bundled": true, - "dev": true, "optional": true }, "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, "optional": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, "optional": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, "optional": true }, "core-util-is": { "version": "1.0.2", "bundled": true, - "dev": true, "optional": true }, "debug": { "version": "4.1.1", "bundled": true, - "dev": true, "optional": true, "requires": { "ms": "^2.1.1" @@ -4172,25 +3965,21 @@ "deep-extend": { "version": "0.6.0", "bundled": true, - "dev": true, "optional": true }, "delegates": { "version": "1.0.0", "bundled": true, - "dev": true, "optional": true }, "detect-libc": { "version": "1.0.3", "bundled": true, - "dev": true, "optional": true }, "fs-minipass": { "version": "1.2.5", "bundled": true, - "dev": true, "optional": true, "requires": { "minipass": "^2.2.1" @@ -4199,13 +3988,11 @@ "fs.realpath": { "version": "1.0.0", "bundled": true, - "dev": true, "optional": true }, "gauge": { "version": "2.7.4", "bundled": true, - "dev": true, "optional": true, "requires": { "aproba": "^1.0.3", @@ -4221,7 +4008,6 @@ "glob": { "version": "7.1.3", "bundled": true, - "dev": true, "optional": true, "requires": { "fs.realpath": "^1.0.0", @@ -4235,13 +4021,11 @@ "has-unicode": { "version": "2.0.1", "bundled": true, - "dev": true, "optional": true }, "iconv-lite": { "version": "0.4.24", "bundled": true, - "dev": true, "optional": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" @@ -4250,7 +4034,6 @@ "ignore-walk": { "version": "3.0.1", "bundled": true, - "dev": true, "optional": true, "requires": { "minimatch": "^3.0.4" @@ -4259,7 +4042,6 @@ "inflight": { "version": "1.0.6", "bundled": true, - "dev": true, "optional": true, "requires": { "once": "^1.3.0", @@ -4269,19 +4051,16 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, "optional": true }, "ini": { "version": "1.3.5", "bundled": true, - "dev": true, "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, - "dev": true, "optional": true, "requires": { "number-is-nan": "^1.0.0" @@ -4290,13 +4069,11 @@ "isarray": { "version": "1.0.0", "bundled": true, - "dev": true, "optional": true }, "minimatch": { "version": "3.0.4", "bundled": true, - "dev": true, "optional": true, "requires": { "brace-expansion": "^1.1.7" @@ -4305,13 +4082,11 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, "optional": true }, "minipass": { "version": "2.3.5", "bundled": true, - "dev": true, "optional": true, "requires": { "safe-buffer": "^5.1.2", @@ -4321,7 +4096,6 @@ "minizlib": { "version": "1.2.1", "bundled": true, - "dev": true, "optional": true, "requires": { "minipass": "^2.2.1" @@ -4330,7 +4104,6 @@ "mkdirp": { "version": "0.5.1", "bundled": true, - "dev": true, "optional": true, "requires": { "minimist": "0.0.8" @@ -4339,13 +4112,11 @@ "ms": { "version": "2.1.1", "bundled": true, - "dev": true, "optional": true }, "needle": { "version": "2.3.0", "bundled": true, - "dev": true, "optional": true, "requires": { "debug": "^4.1.0", @@ -4356,7 +4127,6 @@ "node-pre-gyp": { "version": "0.12.0", "bundled": true, - "dev": true, "optional": true, "requires": { "detect-libc": "^1.0.2", @@ -4374,7 +4144,6 @@ "nopt": { "version": "4.0.1", "bundled": true, - "dev": true, "optional": true, "requires": { "abbrev": "1", @@ -4384,13 +4153,11 @@ "npm-bundled": { "version": "1.0.6", "bundled": true, - "dev": true, "optional": true }, "npm-packlist": { "version": "1.4.1", "bundled": true, - "dev": true, "optional": true, "requires": { "ignore-walk": "^3.0.1", @@ -4400,7 +4167,6 @@ "npmlog": { "version": "4.1.2", "bundled": true, - "dev": true, "optional": true, "requires": { "are-we-there-yet": "~1.1.2", @@ -4412,19 +4178,16 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, "optional": true }, "object-assign": { "version": "4.1.1", "bundled": true, - "dev": true, "optional": true }, "once": { "version": "1.4.0", "bundled": true, - "dev": true, "optional": true, "requires": { "wrappy": "1" @@ -4433,19 +4196,16 @@ "os-homedir": { "version": "1.0.2", "bundled": true, - "dev": true, "optional": true }, "os-tmpdir": { "version": "1.0.2", "bundled": true, - "dev": true, "optional": true }, "osenv": { "version": "0.1.5", "bundled": true, - "dev": true, "optional": true, "requires": { "os-homedir": "^1.0.0", @@ -4455,19 +4215,16 @@ "path-is-absolute": { "version": "1.0.1", "bundled": true, - "dev": true, "optional": true }, "process-nextick-args": { "version": "2.0.0", "bundled": true, - "dev": true, "optional": true }, "rc": { "version": "1.2.8", "bundled": true, - "dev": true, "optional": true, "requires": { "deep-extend": "^0.6.0", @@ -4479,7 +4236,6 @@ "minimist": { "version": "1.2.0", "bundled": true, - "dev": true, "optional": true } } @@ -4487,7 +4243,6 @@ "readable-stream": { "version": "2.3.6", "bundled": true, - "dev": true, "optional": true, "requires": { "core-util-is": "~1.0.0", @@ -4502,7 +4257,6 @@ "rimraf": { "version": "2.6.3", "bundled": true, - "dev": true, "optional": true, "requires": { "glob": "^7.1.3" @@ -4511,43 +4265,36 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true, "optional": true }, "safer-buffer": { "version": "2.1.2", "bundled": true, - "dev": true, "optional": true }, "sax": { "version": "1.2.4", "bundled": true, - "dev": true, "optional": true }, "semver": { "version": "5.7.0", "bundled": true, - "dev": true, "optional": true }, "set-blocking": { "version": "2.0.0", "bundled": true, - "dev": true, "optional": true }, "signal-exit": { "version": "3.0.2", "bundled": true, - "dev": true, "optional": true }, "string-width": { "version": "1.0.2", "bundled": true, - "dev": true, "optional": true, "requires": { "code-point-at": "^1.0.0", @@ -4558,7 +4305,6 @@ "string_decoder": { "version": "1.1.1", "bundled": true, - "dev": true, "optional": true, "requires": { "safe-buffer": "~5.1.0" @@ -4567,7 +4313,6 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, - "dev": true, "optional": true, "requires": { "ansi-regex": "^2.0.0" @@ -4576,13 +4321,11 @@ "strip-json-comments": { "version": "2.0.1", "bundled": true, - "dev": true, "optional": true }, "tar": { "version": "4.4.8", "bundled": true, - "dev": true, "optional": true, "requires": { "chownr": "^1.1.1", @@ -4597,13 +4340,11 @@ "util-deprecate": { "version": "1.0.2", "bundled": true, - "dev": true, "optional": true }, "wide-align": { "version": "1.1.3", "bundled": true, - "dev": true, "optional": true, "requires": { "string-width": "^1.0.2 || 2" @@ -4612,13 +4353,11 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true, "optional": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true, "optional": true } } @@ -4626,20 +4365,22 @@ "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "fuse.js": { + "version": "3.4.6", + "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-3.4.6.tgz", + "integrity": "sha512-H6aJY4UpLFwxj1+5nAvufom5b2BT2v45P1MkPvdGIK8fWjQx/7o6tTT1+ALV0yawQvbmvCF0ufl2et8eJ7v7Cg==" }, "get-caller-file": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", - "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", - "dev": true + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==" }, "get-stream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, "requires": { "pump": "^3.0.0" } @@ -4647,23 +4388,20 @@ "get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=" }, "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dev": true, "requires": { "assert-plus": "^1.0.0" } }, "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "dev": true, + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -4677,7 +4415,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, "requires": { "is-glob": "^3.1.0", "path-dirname": "^1.0.0" @@ -4687,7 +4424,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, "requires": { "is-extglob": "^2.1.0" } @@ -4697,14 +4433,12 @@ "glob-to-regexp": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz", - "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=", - "dev": true + "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=" }, "global": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", - "dev": true, "requires": { "min-document": "^2.19.0", "process": "^0.11.10" @@ -4713,14 +4447,12 @@ "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" }, "globby": { "version": "9.2.0", "resolved": "https://registry.npmjs.org/globby/-/globby-9.2.0.tgz", "integrity": "sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==", - "dev": true, "requires": { "@types/glob": "^7.1.1", "array-union": "^1.0.2", @@ -4736,47 +4468,48 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz", "integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=", - "dev": true, "optional": true, "requires": { "delegate": "^3.1.2" } }, "graceful-fs": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.0.tgz", - "integrity": "sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg==", - "dev": true + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" }, "gray-matter": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.2.tgz", "integrity": "sha512-7hB/+LxrOjq/dd8APlK0r24uL/67w7SkYnfwhNFwg/VDIGWGmduTDYf3WNstLW2fbbmRwrDGCVSJ2isuf2+4Hw==", - "dev": true, "requires": { "js-yaml": "^3.11.0", "kind-of": "^6.0.2", "section-matter": "^1.0.0", "strip-bom-string": "^1.0.0" + }, + "dependencies": { + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + } } }, "handle-thing": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.0.tgz", - "integrity": "sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ==", - "dev": true + "integrity": "sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ==" }, "har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" }, "har-validator": { "version": "5.1.3", "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", - "dev": true, "requires": { "ajv": "^6.5.5", "har-schema": "^2.0.0" @@ -4786,7 +4519,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, "requires": { "function-bind": "^1.1.1" } @@ -4795,7 +4527,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, "requires": { "ansi-regex": "^2.0.0" } @@ -4803,20 +4534,17 @@ "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, "has-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", - "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", - "dev": true + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" }, "has-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dev": true, "requires": { "get-value": "^2.0.6", "has-values": "^1.0.0", @@ -4827,17 +4555,20 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, "requires": { "is-number": "^3.0.0", "kind-of": "^4.0.0" }, "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, "kind-of": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, "requires": { "is-buffer": "^1.1.5" } @@ -4848,7 +4579,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", - "dev": true, "requires": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -4857,14 +4587,12 @@ "hash-sum": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz", - "integrity": "sha1-M7QHd3VMZDJXPBIMw4CLvRDUfwQ=", - "dev": true + "integrity": "sha1-M7QHd3VMZDJXPBIMw4CLvRDUfwQ=" }, "hash.js": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "dev": true, "requires": { "inherits": "^2.0.3", "minimalistic-assert": "^1.0.1" @@ -4873,20 +4601,17 @@ "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" }, "hex-color-regex": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", - "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==", - "dev": true + "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==" }, "hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", - "dev": true, "requires": { "hash.js": "^1.0.3", "minimalistic-assert": "^1.0.0", @@ -4897,25 +4622,20 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/hogan.js/-/hogan.js-3.0.2.tgz", "integrity": "sha1-TNnhq9QpQUbnZ55B14mHMrAse/0=", - "dev": true, "requires": { "mkdirp": "0.3.0", "nopt": "1.0.10" - }, - "dependencies": { - "mkdirp": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", - "integrity": "sha1-G79asbqCevI1dRQ0kEJkVfSB/h4=", - "dev": true - } } }, + "hotkeys-js": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/hotkeys-js/-/hotkeys-js-3.7.3.tgz", + "integrity": "sha512-CSaeVPAKEEYNexYR35znMJnCqoofk7oqG/AOOqWow1qDT0Yxy+g+Y8Hs/LhGlsZaSJ7973YN6/N41LAr3t30QQ==" + }, "hpack.js": { "version": "2.1.6", "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", - "dev": true, "requires": { "inherits": "^2.0.1", "obuf": "^1.0.0", @@ -4926,32 +4646,27 @@ "hsl-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz", - "integrity": "sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4=", - "dev": true + "integrity": "sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4=" }, "hsla-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz", - "integrity": "sha1-wc56MWjIxmFAM6S194d/OyJfnDg=", - "dev": true + "integrity": "sha1-wc56MWjIxmFAM6S194d/OyJfnDg=" }, "html-comment-regex": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz", - "integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==", - "dev": true + "integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==" }, "html-entities": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz", - "integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8=", - "dev": true + "integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8=" }, "html-minifier": { "version": "3.5.21", "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.21.tgz", "integrity": "sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA==", - "dev": true, "requires": { "camel-case": "3.0.x", "clean-css": "4.2.x", @@ -4960,19 +4675,35 @@ "param-case": "2.1.x", "relateurl": "0.2.x", "uglify-js": "3.4.x" + }, + "dependencies": { + "uglify-js": { + "version": "3.4.10", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz", + "integrity": "sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==", + "requires": { + "commander": "~2.19.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "commander": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", + "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==" + } + } + } } }, "html-tags": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-2.0.0.tgz", - "integrity": "sha1-ELMKOGCF9Dzt41PMj6fLDe7qZos=", - "dev": true + "integrity": "sha1-ELMKOGCF9Dzt41PMj6fLDe7qZos=" }, "htmlparser2": { "version": "3.10.1", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", - "dev": true, "requires": { "domelementtype": "^1.3.1", "domhandler": "^2.3.0", @@ -4982,11 +4713,15 @@ "readable-stream": "^3.1.1" }, "dependencies": { + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" + }, "readable-stream": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", - "dev": true, "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -4998,14 +4733,12 @@ "http-deceiver": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=", - "dev": true + "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=" }, "http-errors": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", - "dev": true, "requires": { "depd": "~1.1.2", "inherits": "2.0.3", @@ -5017,24 +4750,21 @@ "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" } } }, "http-parser-js": { "version": "0.4.10", "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.10.tgz", - "integrity": "sha1-ksnBN0w1CF912zWexWzCV8u5P6Q=", - "dev": true + "integrity": "sha1-ksnBN0w1CF912zWexWzCV8u5P6Q=" }, "http-proxy": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz", - "integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==", - "dev": true, + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.0.tgz", + "integrity": "sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ==", "requires": { - "eventemitter3": "^3.0.0", + "eventemitter3": "^4.0.0", "follow-redirects": "^1.0.0", "requires-port": "^1.0.0" } @@ -5043,7 +4773,6 @@ "version": "0.19.1", "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz", "integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==", - "dev": true, "requires": { "http-proxy": "^1.17.0", "is-glob": "^4.0.0", @@ -5055,7 +4784,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dev": true, "requires": { "assert-plus": "^1.0.0", "jsprim": "^1.2.2", @@ -5065,14 +4793,12 @@ "https-browserify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", - "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", - "dev": true + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=" }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" } @@ -5080,14 +4806,12 @@ "icss-replace-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz", - "integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=", - "dev": true + "integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=" }, "icss-utils": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-4.1.1.tgz", "integrity": "sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==", - "dev": true, "requires": { "postcss": "^7.0.14" } @@ -5095,32 +4819,27 @@ "ieee754": { "version": "1.1.13", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", - "dev": true + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" }, "iferr": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", - "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", - "dev": true + "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=" }, "ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==" }, "immediate": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.2.3.tgz", - "integrity": "sha1-0UD6j2FGWb1lQSMwl92qwlzdmRw=", - "dev": true + "integrity": "sha1-0UD6j2FGWb1lQSMwl92qwlzdmRw=" }, "import-cwd": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=", - "dev": true, "requires": { "import-from": "^2.1.0" } @@ -5129,7 +4848,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", - "dev": true, "requires": { "caller-path": "^2.0.0", "resolve-from": "^3.0.0" @@ -5139,7 +4857,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/import-from/-/import-from-2.1.0.tgz", "integrity": "sha1-M1238qev/VOqpHHUuAId7ja387E=", - "dev": true, "requires": { "resolve-from": "^3.0.0" } @@ -5148,7 +4865,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", - "dev": true, "requires": { "pkg-dir": "^3.0.0", "resolve-cwd": "^2.0.0" @@ -5157,20 +4873,22 @@ "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" }, "indexes-of": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", - "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", - "dev": true + "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=" + }, + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==" }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -5179,24 +4897,26 @@ "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "internal-ip": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz", "integrity": "sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==", - "dev": true, "requires": { "default-gateway": "^4.2.0", "ipaddr.js": "^1.9.0" } }, + "intersection-observer": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/intersection-observer/-/intersection-observer-0.7.0.tgz", + "integrity": "sha512-Id0Fij0HsB/vKWGeBe9PxeY45ttRiBmhFyyt/geBdDHBYNctMRTE3dC1U3ujzz3lap+hVXlEcVaB56kZP/eEUg==" + }, "invariant": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "dev": true, "requires": { "loose-envify": "^1.0.0" } @@ -5204,85 +4924,68 @@ "invert-kv": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", - "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", - "dev": true + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==" }, "ip": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", - "dev": true + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" }, "ip-regex": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", - "dev": true + "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=" }, "ipaddr.js": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz", - "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==", - "dev": true + "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==" }, "is-absolute-url": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", - "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=", - "dev": true + "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=" }, "is-accessor-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, "requires": { "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } } }, + "is-arguments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", + "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==" + }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" }, "is-binary-path": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", - "dev": true, "requires": { "binary-extensions": "^1.0.0" } }, "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", + "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==" }, "is-callable": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", - "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", - "dev": true + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==" }, "is-color-stop": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz", "integrity": "sha1-z/9HGu5N1cnhWFmPvhKWe1za00U=", - "dev": true, "requires": { "css-color-names": "^0.0.4", "hex-color-regex": "^1.1.0", @@ -5296,33 +4999,19 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, "requires": { "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } } }, "is-date-object": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", - "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", - "dev": true + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=" }, "is-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, "requires": { "is-accessor-descriptor": "^0.1.6", "is-data-descriptor": "^0.1.4", @@ -5332,40 +5021,50 @@ "kind-of": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" } } }, "is-directory": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", - "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", - "dev": true + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=" + }, + "is-expression": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-expression/-/is-expression-3.0.0.tgz", + "integrity": "sha1-Oayqa+f9HzRx3ELHQW5hwkMXrJ8=", + "requires": { + "acorn": "~4.0.2", + "object-assign": "^4.0.1" + }, + "dependencies": { + "acorn": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", + "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=" + } + } }, "is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" }, "is-glob": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, "requires": { "is-extglob": "^2.1.1" } @@ -5374,39 +5073,24 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, "requires": { "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } } }, "is-obj": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", - "dev": true + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=" }, "is-path-cwd": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.1.0.tgz", - "integrity": "sha512-Sc5j3/YnM8tDeyCsVeKlm/0p95075DyLmDEIkSgQ7mXkrOX+uTCtmQFm0CYzVyJwcCCmO3k8qfJt17SxQwB5Zw==", - "dev": true + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==" }, "is-path-in-cwd": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz", "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==", - "dev": true, "requires": { "is-path-inside": "^2.1.0" } @@ -5415,7 +5099,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz", "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==", - "dev": true, "requires": { "path-is-inside": "^1.0.2" } @@ -5423,23 +5106,25 @@ "is-plain-obj": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", - "dev": true + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=" }, "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, "requires": { "isobject": "^3.0.1" } }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" + }, "is-regex": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", - "dev": true, "requires": { "has": "^1.0.1" } @@ -5447,98 +5132,88 @@ "is-resolvable": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", - "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", - "dev": true + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==" }, "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" }, "is-svg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-3.0.0.tgz", "integrity": "sha512-gi4iHK53LR2ujhLVVj+37Ykh9GLqYHX6JOVXbLAucaG/Cqw9xwdFOjDM2qeifLs1sF1npXXFvDu0r5HNgCMrzQ==", - "dev": true, "requires": { "html-comment-regex": "^1.1.0" } }, "is-symbol": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", - "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", - "dev": true, + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", "requires": { - "has-symbols": "^1.0.0" + "has-symbols": "^1.0.1" } }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" }, "is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" }, "is-wsl": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", - "dev": true + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=" }, "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" }, "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" }, "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" }, "javascript-stringify": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/javascript-stringify/-/javascript-stringify-1.6.0.tgz", - "integrity": "sha1-FC0RHzpuPa6PSpr9d9RYVbWpzOM=", - "dev": true + "integrity": "sha1-FC0RHzpuPa6PSpr9d9RYVbWpzOM=" }, "js-levenshtein": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", - "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", - "dev": true + "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==" + }, + "js-stringify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz", + "integrity": "sha1-Fzb939lyTyijaCrcYjCufk6Weds=" }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "js-yaml": { "version": "3.13.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, "requires": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -5547,50 +5222,42 @@ "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" }, "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" }, "json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" }, "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", - "dev": true + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" }, "json3": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz", - "integrity": "sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==", - "dev": true + "integrity": "sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==" }, "json5": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz", - "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==", - "dev": true, + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", "requires": { "minimist": "^1.2.0" } @@ -5599,7 +5266,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "dev": true, "requires": { "graceful-fs": "^4.1.6" } @@ -5608,7 +5274,6 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "dev": true, "requires": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", @@ -5616,42 +5281,61 @@ "verror": "1.10.0" } }, + "jstransformer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-1.0.0.tgz", + "integrity": "sha1-7Yvwkh4vPx7U1cGkT2hwntJHIsM=", + "requires": { + "is-promise": "^2.0.0", + "promise": "^7.0.1" + } + }, "killable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", - "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==", - "dev": true + "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==" }, "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + } + } }, "last-call-webpack-plugin": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/last-call-webpack-plugin/-/last-call-webpack-plugin-3.0.0.tgz", "integrity": "sha512-7KI2l2GIZa9p2spzPIVZBYyNKkN+e/SQPpnjlTiPhdbDW3F86tdKKELxKpzJ5sgU19wQWsACULZmpTPYHeWO5w==", - "dev": true, "requires": { "lodash": "^4.17.5", "webpack-sources": "^1.1.0" } }, + "lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=" + }, "lcid": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", - "dev": true, "requires": { "invert-kv": "^2.0.0" } }, "linkify-it": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.1.0.tgz", - "integrity": "sha512-4REs8/062kV2DSHxNfq5183zrqXMl7WP0WzABH9IeJI+NLm429FgE1PDecltYfnOoFDFlZGh2T8PfZn0r+GTRg==", - "dev": true, + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", + "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", "requires": { "uc.micro": "^1.0.1" } @@ -5659,119 +5343,113 @@ "load-script": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/load-script/-/load-script-1.0.0.tgz", - "integrity": "sha1-BJGTngvuVkPuSUp+PaPSuscMbKQ=", - "dev": true + "integrity": "sha1-BJGTngvuVkPuSUp+PaPSuscMbKQ=" }, "loader-runner": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", - "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", - "dev": true + "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==" }, "loader-utils": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", - "dev": true, "requires": { "big.js": "^5.2.2", "emojis-list": "^2.0.0", "json5": "^1.0.1" - }, - "dependencies": { - "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "requires": { - "minimist": "^1.2.0" - } - } } }, "locate-path": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, "requires": { "p-locate": "^2.0.0", "path-exists": "^3.0.0" } }, "lodash": { - "version": "4.17.13", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.13.tgz", - "integrity": "sha512-vm3/XWXfWtRua0FkUyEHBZy8kCPjErNBT9fJx8Zvs+U6zjqPbTUOpkaoum3O5uiA8sm+yNMHXfYkTUHFoMxFNA==", - "dev": true + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" }, "lodash._reinterpolate": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", - "dev": true + "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=" + }, + "lodash.chunk": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.chunk/-/lodash.chunk-4.2.0.tgz", + "integrity": "sha1-ZuXOH3btJ7QwPYxlEujRIW6BBrw=" }, "lodash.clonedeep": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", - "dev": true + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=" + }, + "lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" }, "lodash.kebabcase": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz", - "integrity": "sha1-hImxyw0p/4gZXM7KRI/21swpXDY=", - "dev": true + "integrity": "sha1-hImxyw0p/4gZXM7KRI/21swpXDY=" }, "lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", - "dev": true + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=" + }, + "lodash.padstart": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.padstart/-/lodash.padstart-4.6.1.tgz", + "integrity": "sha1-0uPuv/DZ05rVD1y9G1KnvOa7YRs=" + }, + "lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=" }, "lodash.template": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", - "dev": true, "requires": { "lodash._reinterpolate": "^3.0.0", "lodash.templatesettings": "^4.0.0" } }, "lodash.templatesettings": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz", - "integrity": "sha1-K01OlbpEDZFf8IvImeRVNmZxMxY=", - "dev": true, + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", + "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", "requires": { - "lodash._reinterpolate": "~3.0.0" + "lodash._reinterpolate": "^3.0.0" } }, - "lodash.throttle": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", - "integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=", - "dev": true - }, "lodash.uniq": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", - "dev": true + "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=" }, "loglevel": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.3.tgz", - "integrity": "sha512-LoEDv5pgpvWgPF4kNYuIp0qqSJVWak/dML0RY74xlzMZiT9w77teNAwKYKWBTYjlokMirg+o3jBwp+vlLrcfAA==", - "dev": true + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.6.tgz", + "integrity": "sha512-Sgr5lbboAUBo3eXCSPL4/KoVz3ROKquOjcctxmHIt+vol2DrqTQe3SwkKKuYhEiWB5kYa13YyopJ69deJ1irzQ==" + }, + "longest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=" }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, "requires": { "js-tokens": "^3.0.0 || ^4.0.0" } @@ -5779,23 +5457,25 @@ "lower-case": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", - "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=", - "dev": true + "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=" }, "lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, "requires": { "yallist": "^3.0.2" } }, + "lunr": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.8.tgz", + "integrity": "sha512-oxMeX/Y35PNFuZoHp+jUj5OSEmLCaIH4KTFJh7a93cHBoFmpw2IoPs22VIz7vyO2YUnx2Tn9dzIwO2P/4quIRg==" + }, "make-dir": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, "requires": { "pify": "^4.0.1", "semver": "^5.6.0" @@ -5804,14 +5484,12 @@ "mamacro": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/mamacro/-/mamacro-0.0.3.tgz", - "integrity": "sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA==", - "dev": true + "integrity": "sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA==" }, "map-age-cleaner": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", - "dev": true, "requires": { "p-defer": "^1.0.0" } @@ -5819,42 +5497,42 @@ "map-cache": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=" }, "map-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, "requires": { "object-visit": "^1.0.0" } }, "markdown-it": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.2.tgz", - "integrity": "sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ==", - "dev": true, + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz", + "integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==", "requires": { "argparse": "^1.0.7", - "entities": "~1.1.1", + "entities": "~2.0.0", "linkify-it": "^2.0.0", "mdurl": "^1.0.1", "uc.micro": "^1.0.5" } }, "markdown-it-anchor": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-5.2.4.tgz", - "integrity": "sha512-n8zCGjxA3T+Mx1pG8HEgbJbkB8JFUuRkeTZQuIM8iPY6oQ8sWOPRZJDFC9a/pNg2QkHEjjGkhBEl/RSyzaDZ3A==", - "dev": true + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-5.2.5.tgz", + "integrity": "sha512-xLIjLQmtym3QpoY9llBgApknl7pxAcN3WDRc2d3rwpl+/YvDZHPmKscGs+L6E05xf2KrCXPBvosWt7MZukwSpQ==" + }, + "markdown-it-attrs": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/markdown-it-attrs/-/markdown-it-attrs-3.0.1.tgz", + "integrity": "sha512-fcpdmxdEsctDVJEunPyrirVtU/6zcTMxPxAu4Ofz51PKAa8vRMpmGQXsmXx1HTdIdUPoDonm/RhS/+jTNywj/Q==" }, "markdown-it-chain": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/markdown-it-chain/-/markdown-it-chain-1.3.0.tgz", "integrity": "sha512-XClV8I1TKy8L2qsT9iX3qiV+50ZtcInGXI80CA+DP62sMs7hXlyV/RM3hfwy5O3Ad0sJm9xIwQELgANfESo8mQ==", - "dev": true, "requires": { "webpack-chain": "^4.9.0" } @@ -5862,35 +5540,27 @@ "markdown-it-container": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/markdown-it-container/-/markdown-it-container-2.0.0.tgz", - "integrity": "sha1-ABm0P9Au7+zi8ZYKKJX7qBpARpU=", - "dev": true + "integrity": "sha1-ABm0P9Au7+zi8ZYKKJX7qBpARpU=" }, "markdown-it-emoji": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/markdown-it-emoji/-/markdown-it-emoji-1.4.0.tgz", - "integrity": "sha1-m+4OmpkKljupbfaYDE/dsF37Tcw=", - "dev": true + "integrity": "sha1-m+4OmpkKljupbfaYDE/dsF37Tcw=" }, - "markdown-it-meta": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/markdown-it-meta/-/markdown-it-meta-0.0.1.tgz", - "integrity": "sha1-11to8RVlnK9WjkrUPLRgpHEkjDk=", - "dev": true, - "requires": { - "js-yaml": "^3.8.1" - } + "markdown-it-ins": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-ins/-/markdown-it-ins-3.0.0.tgz", + "integrity": "sha512-+vyAdBuMGwmT2yMlAFJSx2VR/0QZ1onQ/Mkkmr4l9tDFOh5sVoAgRbkgbuSsk+sxJ9vaMH/IQ323ydfvQrPO/Q==" }, "markdown-it-table-of-contents": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/markdown-it-table-of-contents/-/markdown-it-table-of-contents-0.4.4.tgz", - "integrity": "sha512-TAIHTHPwa9+ltKvKPWulm/beozQU41Ab+FIefRaQV1NRnpzwcV9QOe6wXQS5WLivm5Q/nlo0rl6laGkMDZE7Gw==", - "dev": true + "integrity": "sha512-TAIHTHPwa9+ltKvKPWulm/beozQU41Ab+FIefRaQV1NRnpzwcV9QOe6wXQS5WLivm5Q/nlo0rl6laGkMDZE7Gw==" }, "md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", - "dev": true, "requires": { "hash-base": "^3.0.0", "inherits": "^2.0.1", @@ -5898,28 +5568,24 @@ } }, "mdn-data": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-1.1.4.tgz", - "integrity": "sha512-FSYbp3lyKjyj3E7fMl6rYvUdX0FBXaluGqlFoYESWQlyUTq8R+wp0rkFxoYFqZlHCvsUXGjyJmLQSnXToYhOSA==", - "dev": true + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", + "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==" }, "mdurl": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=", - "dev": true + "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=" }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", - "dev": true + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" }, "mem": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", - "dev": true, "requires": { "map-age-cleaner": "^0.1.1", "mimic-fn": "^2.0.0", @@ -5930,7 +5596,6 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", - "dev": true, "requires": { "errno": "^0.1.3", "readable-stream": "^2.0.1" @@ -5939,43 +5604,30 @@ "merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", - "dev": true + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" }, "merge-source-map": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", - "dev": true, "requires": { "source-map": "^0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } } }, "merge2": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.2.3.tgz", - "integrity": "sha512-gdUU1Fwj5ep4kplwcmftruWofEFt6lfpkkr3h860CXbAB9c3hGb55EOL2ali0Td5oebvW0E1+3Sr+Ur7XfKpRA==", - "dev": true + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.3.0.tgz", + "integrity": "sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw==" }, "methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", - "dev": true + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" }, "micromatch": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, "requires": { "arr-diff": "^4.0.0", "array-unique": "^0.3.2", @@ -5990,13 +5642,19 @@ "regex-not": "^1.0.0", "snapdragon": "^0.8.1", "to-regex": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + } } }, "miller-rabin": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", - "dev": true, "requires": { "bn.js": "^4.0.0", "brorand": "^1.0.1" @@ -6005,35 +5663,30 @@ "mime": { "version": "2.4.4", "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", - "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==", - "dev": true + "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==" }, "mime-db": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", - "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==", - "dev": true + "version": "1.42.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.42.0.tgz", + "integrity": "sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ==" }, "mime-types": { - "version": "2.1.24", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", - "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", - "dev": true, + "version": "2.1.25", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.25.tgz", + "integrity": "sha512-5KhStqB5xpTAeGqKBAMgwaYMnQik7teQN4IAzC7npDv6kzeU6prfkR67bc87J1kWMPGkoaZSq1npmexMgkmEVg==", "requires": { - "mime-db": "1.40.0" + "mime-db": "1.42.0" } }, "mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" }, "min-document": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=", - "dev": true, "requires": { "dom-walk": "^0.1.0" } @@ -6042,7 +5695,6 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.6.0.tgz", "integrity": "sha512-79q5P7YGI6rdnVyIAV4NXpBQJFWdkzJxCim3Kog4078fM0piAaFlwocqbejdWtLW1cEzCexPrh6EdyFsPgVdAw==", - "dev": true, "requires": { "loader-utils": "^1.1.0", "normalize-url": "^2.0.1", @@ -6053,20 +5705,17 @@ "minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" }, "minimalistic-crypto-utils": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", - "dev": true + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -6074,14 +5723,12 @@ "minimist": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" }, "mississippi": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", - "dev": true, "requires": { "concat-stream": "^1.5.0", "duplexify": "^3.4.2", @@ -6099,7 +5746,6 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "dev": true, "requires": { "for-in": "^1.0.2", "is-extendable": "^1.0.1" @@ -6109,7 +5755,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, "requires": { "is-plain-object": "^2.0.4" } @@ -6117,27 +5762,14 @@ } }, "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, - "requires": { - "minimist": "0.0.8" - }, - "dependencies": { - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true - } - } + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", + "integrity": "sha1-G79asbqCevI1dRQ0kEJkVfSB/h4=" }, "move-concurrently": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", - "dev": true, "requires": { "aproba": "^1.1.1", "copy-concurrently": "^1.0.0", @@ -6145,19 +5777,32 @@ "mkdirp": "^0.5.1", "rimraf": "^2.5.4", "run-queue": "^1.0.3" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + } + } } }, "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "multicast-dns": { "version": "6.2.3", "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", - "dev": true, "requires": { "dns-packet": "^1.3.1", "thunky": "^1.0.2" @@ -6166,21 +5811,18 @@ "multicast-dns-service-types": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", - "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", - "dev": true + "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=" }, "nan": { "version": "2.14.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", - "dev": true, "optional": true }, "nanomatch": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dev": true, "requires": { "arr-diff": "^4.0.0", "array-unique": "^0.3.2", @@ -6193,46 +5835,47 @@ "regex-not": "^1.0.0", "snapdragon": "^0.8.1", "to-regex": "^3.0.1" + }, + "dependencies": { + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + } } }, "negotiator": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", - "dev": true + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" }, "neo-async": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", - "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", - "dev": true + "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==" }, "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" }, "no-case": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", - "dev": true, "requires": { "lower-case": "^1.1.1" } }, "node-forge": { - "version": "0.7.5", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.5.tgz", - "integrity": "sha512-MmbQJ2MTESTjt3Gi/3yG1wGpIMhUfcIypUCGtTizFR9IiccFwxSpfp0vtIZlkFclEqERemxfnSdZEMR9VqqEFQ==", - "dev": true + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.0.tgz", + "integrity": "sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ==" }, "node-libs-browser": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", - "dev": true, "requires": { "assert": "^1.1.1", "browserify-zlib": "^0.2.0", @@ -6259,28 +5902,37 @@ "vm-browserify": "^1.0.1" }, "dependencies": { + "events": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz", + "integrity": "sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA==" + }, "punycode": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" } } }, "node-releases": { - "version": "1.1.23", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.23.tgz", - "integrity": "sha512-uq1iL79YjfYC0WXoHbC/z28q/9pOl8kSHaXdWmAAc8No+bDwqkZbzIJz55g/MUsPgSGm9LZ7QSUbzTcH5tz47w==", - "dev": true, + "version": "1.1.42", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.42.tgz", + "integrity": "sha512-OQ/ESmUqGawI2PRX+XIRao44qWYBBfN54ImQYdWVTQqUckuejOg76ysSqDBK8NG3zwySRVnX36JwDQ6x+9GxzA==", "requires": { - "semver": "^5.3.0" + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } } }, "nopt": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", - "dev": true, "requires": { "abbrev": "1" } @@ -6288,20 +5940,17 @@ "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" }, "normalize-range": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", - "dev": true + "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=" }, "normalize-url": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-2.0.1.tgz", "integrity": "sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw==", - "dev": true, "requires": { "prepend-http": "^2.0.0", "query-string": "^5.0.1", @@ -6312,7 +5961,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "dev": true, "requires": { "path-key": "^2.0.0" } @@ -6320,14 +5968,12 @@ "nprogress": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz", - "integrity": "sha1-y480xTIT2JVyP8urkH6UIq28r7E=", - "dev": true + "integrity": "sha1-y480xTIT2JVyP8urkH6UIq28r7E=" }, "nth-check": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", - "dev": true, "requires": { "boolbase": "~1.0.0" } @@ -6335,32 +5981,27 @@ "num2fraction": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", - "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=", - "dev": true + "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=" }, "number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, "oauth-sign": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, "object-copy": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, "requires": { "copy-descriptor": "^0.1.0", "define-property": "^0.2.5", @@ -6371,33 +6012,31 @@ "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, "requires": { "is-descriptor": "^0.1.0" } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } } } }, + "object-inspect": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==" + }, + "object-is": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.0.1.tgz", + "integrity": "sha1-CqYOyZiaCz7Xlc9NBvYs8a1lObY=" + }, "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" }, "object-visit": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dev": true, "requires": { "isobject": "^3.0.0" } @@ -6406,7 +6045,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", - "dev": true, "requires": { "define-properties": "^1.1.2", "function-bind": "^1.1.1", @@ -6418,7 +6056,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", - "dev": true, "requires": { "define-properties": "^1.1.2", "es-abstract": "^1.5.1" @@ -6428,7 +6065,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "dev": true, "requires": { "isobject": "^3.0.1" } @@ -6437,7 +6073,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.0.tgz", "integrity": "sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg==", - "dev": true, "requires": { "define-properties": "^1.1.3", "es-abstract": "^1.12.0", @@ -6448,14 +6083,12 @@ "obuf": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", - "dev": true + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" }, "on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "dev": true, "requires": { "ee-first": "1.1.1" } @@ -6463,34 +6096,35 @@ "on-headers": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", - "dev": true + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, "requires": { "wrappy": "1" } }, + "opencollective-postinstall": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.2.tgz", + "integrity": "sha512-pVOEP16TrAO2/fjej1IdOyupJY8KDUM1CvsaScRbw6oddvpQoOfGk4ywha0HKKVAD6RkW4x6Q+tNBwhf3Bgpuw==" + }, "opn": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==", - "dev": true, "requires": { "is-wsl": "^1.1.0" } }, "optimize-css-assets-webpack-plugin": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-5.0.1.tgz", - "integrity": "sha512-Rqm6sSjWtx9FchdP0uzTQDc7GXDKnwVEGoSxjezPkzMewx7gEWE9IMUYKmigTRC4U3RaNSwYVnUDLuIdtTpm0A==", - "dev": true, + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-5.0.3.tgz", + "integrity": "sha512-q9fbvCRS6EYtUKKSwI87qm2IxlyJK5b4dygW1rKUBT6mMDhdG5e5bZT63v6tnJR9F9FB/H5a0HTmtw+laUBxKA==", "requires": { - "cssnano": "^4.1.0", + "cssnano": "^4.1.10", "last-call-webpack-plugin": "^3.0.0" } }, @@ -6498,7 +6132,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==", - "dev": true, "requires": { "url-parse": "^1.4.3" } @@ -6506,14 +6139,12 @@ "os-browserify": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", - "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", - "dev": true + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=" }, "os-locale": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", - "dev": true, "requires": { "execa": "^1.0.0", "lcid": "^2.0.0", @@ -6523,26 +6154,22 @@ "p-defer": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", - "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", - "dev": true + "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=" }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" }, "p-is-promise": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", - "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", - "dev": true + "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==" }, "p-limit": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, "requires": { "p-try": "^1.0.0" } @@ -6551,7 +6178,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, "requires": { "p-limit": "^1.1.0" } @@ -6559,14 +6185,12 @@ "p-map": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", - "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", - "dev": true + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==" }, "p-retry": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-3.0.1.tgz", "integrity": "sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w==", - "dev": true, "requires": { "retry": "^0.12.0" } @@ -6574,22 +6198,19 @@ "p-try": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" }, "pako": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz", - "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==", - "dev": true + "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==" }, "parallel-transform": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.1.0.tgz", - "integrity": "sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=", - "dev": true, + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", + "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", "requires": { - "cyclist": "~0.2.2", + "cyclist": "^1.0.1", "inherits": "^2.0.3", "readable-stream": "^2.1.5" } @@ -6598,16 +6219,14 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", - "dev": true, "requires": { "no-case": "^2.2.0" } }, "parse-asn1": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.4.tgz", - "integrity": "sha512-Qs5duJcuvNExRfFZ99HDD3z4mAi3r9Wl/FOjEOijlxwCZs7E7mW2vjTpgQ4J8LpTF8x5v+1Vn5UQFejmWT11aw==", - "dev": true, + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz", + "integrity": "sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==", "requires": { "asn1.js": "^4.0.0", "browserify-aes": "^1.0.0", @@ -6621,7 +6240,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, "requires": { "error-ex": "^1.3.1", "json-parse-better-errors": "^1.0.1" @@ -6630,68 +6248,57 @@ "parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "dev": true + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" }, "pascalcase": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" }, "path-browserify": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", - "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", - "dev": true + "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==" }, "path-dirname": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", - "dev": true + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=" }, "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "path-is-inside": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", - "dev": true + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=" }, "path-key": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" }, "path-parse": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", - "dev": true + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" }, "path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", - "dev": true + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, "path-type": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, "requires": { "pify": "^3.0.0" }, @@ -6699,8 +6306,7 @@ "pify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" } } }, @@ -6708,7 +6314,6 @@ "version": "3.0.17", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", - "dev": true, "requires": { "create-hash": "^1.1.2", "create-hmac": "^1.1.4", @@ -6720,26 +6325,22 @@ "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, "pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" }, "pinkie": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "dev": true + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" }, "pinkie-promise": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dev": true, "requires": { "pinkie": "^2.0.0" } @@ -6748,7 +6349,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "dev": true, "requires": { "find-up": "^3.0.0" }, @@ -6757,7 +6357,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, "requires": { "locate-path": "^3.0.0" } @@ -6766,17 +6365,15 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, "requires": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" } }, "p-limit": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", - "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", - "dev": true, + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", + "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", "requires": { "p-try": "^2.0.0" } @@ -6785,7 +6382,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, "requires": { "p-limit": "^2.0.0" } @@ -6793,8 +6389,7 @@ "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" } } }, @@ -6802,67 +6397,67 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", - "dev": true, "requires": { "find-up": "^2.1.0" } }, "portfinder": { - "version": "1.0.20", - "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.20.tgz", - "integrity": "sha512-Yxe4mTyDzTd59PZJY4ojZR8F+E5e97iq2ZOHPz3HDgSvYC5siNad2tLooQ5y5QHyQhc3xVqvyk/eNA3wuoa7Sw==", - "dev": true, + "version": "1.0.25", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.25.tgz", + "integrity": "sha512-6ElJnHBbxVA1XSLgBp7G1FiCkQdlqGzuF7DswL5tcea+E8UpuvPU7beVAjjRwCioTS9ZluNbu+ZyRvgTsmqEBg==", "requires": { - "async": "^1.5.2", - "debug": "^2.2.0", - "mkdirp": "0.5.x" + "async": "^2.6.2", + "debug": "^3.1.1", + "mkdirp": "^0.5.1" }, "dependencies": { "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" } }, "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" } } }, "posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" }, "postcss": { - "version": "7.0.17", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.17.tgz", - "integrity": "sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==", - "dev": true, + "version": "7.0.24", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.24.tgz", + "integrity": "sha512-Xl0XvdNWg+CblAXzNvbSOUvgJXwSjmbAKORqyw9V2AlHrm1js2gFw9y3jibBAhpKZi8b5JzJCVh/FyzPsTtgTA==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", "supports-color": "^6.1.0" }, "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, "supports-color": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, "requires": { "has-flag": "^3.0.0" } @@ -6873,7 +6468,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-7.0.1.tgz", "integrity": "sha512-oXqx0m6tb4N3JGdmeMSc/i91KppbYsFZKdH0xMOqK8V1rJlzrKlTdokz8ozUXLVejydRN6u2IddxpcijRj2FqQ==", - "dev": true, "requires": { "css-unit-converter": "^1.1.1", "postcss": "^7.0.5", @@ -6884,19 +6478,22 @@ "cssesc": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", - "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==", - "dev": true + "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==" }, "postcss-selector-parser": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", - "dev": true, "requires": { "cssesc": "^2.0.0", "indexes-of": "^1.0.1", "uniq": "^1.0.1" } + }, + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" } } }, @@ -6904,30 +6501,41 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-4.0.3.tgz", "integrity": "sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw==", - "dev": true, "requires": { "browserslist": "^4.0.0", "color": "^3.0.0", "has": "^1.0.0", "postcss": "^7.0.0", "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } } }, "postcss-convert-values": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz", "integrity": "sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ==", - "dev": true, "requires": { "postcss": "^7.0.0", "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } } }, "postcss-discard-comments": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz", "integrity": "sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg==", - "dev": true, "requires": { "postcss": "^7.0.0" } @@ -6936,7 +6544,6 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz", "integrity": "sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ==", - "dev": true, "requires": { "postcss": "^7.0.0" } @@ -6945,7 +6552,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz", "integrity": "sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w==", - "dev": true, "requires": { "postcss": "^7.0.0" } @@ -6954,7 +6560,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz", "integrity": "sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg==", - "dev": true, "requires": { "postcss": "^7.0.0" } @@ -6963,7 +6568,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.1.0.tgz", "integrity": "sha512-4pV3JJVPLd5+RueiVVB+gFOAa7GWc25XQcMp86Zexzke69mKf6Nx9LRcQywdz7yZI9n1udOxmLuAwTBypypF8Q==", - "dev": true, "requires": { "cosmiconfig": "^5.0.0", "import-cwd": "^2.0.0" @@ -6973,7 +6577,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-3.0.0.tgz", "integrity": "sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA==", - "dev": true, "requires": { "loader-utils": "^1.1.0", "postcss": "^7.0.0", @@ -6985,19 +6588,24 @@ "version": "4.0.11", "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz", "integrity": "sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw==", - "dev": true, "requires": { "css-color-names": "0.0.4", "postcss": "^7.0.0", "postcss-value-parser": "^3.0.0", "stylehacks": "^4.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } } }, "postcss-merge-rules": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz", "integrity": "sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ==", - "dev": true, "requires": { "browserslist": "^4.0.0", "caniuse-api": "^3.0.0", @@ -7011,7 +6619,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz", "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", - "dev": true, "requires": { "dot-prop": "^4.1.1", "indexes-of": "^1.0.1", @@ -7024,29 +6631,40 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz", "integrity": "sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg==", - "dev": true, "requires": { "postcss": "^7.0.0", "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } } }, "postcss-minify-gradients": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz", "integrity": "sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q==", - "dev": true, "requires": { "cssnano-util-get-arguments": "^4.0.0", "is-color-stop": "^1.0.0", "postcss": "^7.0.0", "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } } }, "postcss-minify-params": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz", "integrity": "sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg==", - "dev": true, "requires": { "alphanum-sort": "^1.0.0", "browserslist": "^4.0.0", @@ -7054,13 +6672,19 @@ "postcss": "^7.0.0", "postcss-value-parser": "^3.0.0", "uniqs": "^2.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } } }, "postcss-minify-selectors": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz", "integrity": "sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g==", - "dev": true, "requires": { "alphanum-sort": "^1.0.0", "has": "^1.0.0", @@ -7072,7 +6696,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz", "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", - "dev": true, "requires": { "dot-prop": "^4.1.1", "indexes-of": "^1.0.1", @@ -7085,7 +6708,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz", "integrity": "sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==", - "dev": true, "requires": { "postcss": "^7.0.5" } @@ -7094,18 +6716,23 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-2.0.6.tgz", "integrity": "sha512-oLUV5YNkeIBa0yQl7EYnxMgy4N6noxmiwZStaEJUSe2xPMcdNc8WmBQuQCx18H5psYbVxz8zoHk0RAAYZXP9gA==", - "dev": true, "requires": { "postcss": "^7.0.6", "postcss-selector-parser": "^6.0.0", "postcss-value-parser": "^3.3.1" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } } }, "postcss-modules-scope": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.1.0.tgz", - "integrity": "sha512-91Rjps0JnmtUB0cujlc8KIKCsJXWjzuxGeT/+Q2i2HXKZ7nBUeF9YQTZZTNvHVoNYj1AthsjnGLtqDUE0Op79A==", - "dev": true, + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.1.1.tgz", + "integrity": "sha512-OXRUPecnHCg8b9xWvldG/jUpRIGPNRka0r4D4j0ESUU2/5IOnpsjfPPmDprM3Ih8CgZ8FXjWqaniK5v4rWt3oQ==", "requires": { "postcss": "^7.0.6", "postcss-selector-parser": "^6.0.0" @@ -7115,7 +6742,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-2.0.0.tgz", "integrity": "sha512-Ki7JZa7ff1N3EIMlPnGTZfUMe69FFwiQPnVSXC9mnn3jozCRBYIxiZd44yJOV2AmabOo4qFf8s0dC/+lweG7+w==", - "dev": true, "requires": { "icss-replace-symbols": "^1.1.0", "postcss": "^7.0.6" @@ -7125,7 +6751,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz", "integrity": "sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g==", - "dev": true, "requires": { "postcss": "^7.0.0" } @@ -7134,75 +6759,110 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz", "integrity": "sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ==", - "dev": true, "requires": { "cssnano-util-get-match": "^4.0.0", "postcss": "^7.0.0", "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } } }, "postcss-normalize-positions": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz", "integrity": "sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA==", - "dev": true, "requires": { "cssnano-util-get-arguments": "^4.0.0", "has": "^1.0.0", "postcss": "^7.0.0", "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } } }, "postcss-normalize-repeat-style": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz", "integrity": "sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q==", - "dev": true, "requires": { "cssnano-util-get-arguments": "^4.0.0", "cssnano-util-get-match": "^4.0.0", "postcss": "^7.0.0", "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } } }, "postcss-normalize-string": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz", "integrity": "sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA==", - "dev": true, "requires": { "has": "^1.0.0", "postcss": "^7.0.0", "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } } }, "postcss-normalize-timing-functions": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz", "integrity": "sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A==", - "dev": true, "requires": { "cssnano-util-get-match": "^4.0.0", "postcss": "^7.0.0", "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } } }, "postcss-normalize-unicode": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz", "integrity": "sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg==", - "dev": true, "requires": { "browserslist": "^4.0.0", "postcss": "^7.0.0", "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } } }, "postcss-normalize-url": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz", "integrity": "sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA==", - "dev": true, "requires": { "is-absolute-url": "^2.0.0", "normalize-url": "^3.0.0", @@ -7213,8 +6873,12 @@ "normalize-url": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz", - "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==", - "dev": true + "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==" + }, + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" } } }, @@ -7222,28 +6886,39 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz", "integrity": "sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA==", - "dev": true, "requires": { "postcss": "^7.0.0", "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } } }, "postcss-ordered-values": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz", "integrity": "sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw==", - "dev": true, "requires": { "cssnano-util-get-arguments": "^4.0.0", "postcss": "^7.0.0", "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } } }, "postcss-reduce-initial": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz", "integrity": "sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA==", - "dev": true, "requires": { "browserslist": "^4.0.0", "caniuse-api": "^3.0.0", @@ -7255,19 +6930,24 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz", "integrity": "sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg==", - "dev": true, "requires": { "cssnano-util-get-match": "^4.0.0", "has": "^1.0.0", "postcss": "^7.0.0", "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } } }, "postcss-safe-parser": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-4.0.1.tgz", "integrity": "sha512-xZsFA3uX8MO3yAda03QrG3/Eg1LN3EPfjjf07vke/46HERLZyHrTsQ9E1r1w1W//fWEhtYNndo2hQplN2cVpCQ==", - "dev": true, "requires": { "postcss": "^7.0.0" } @@ -7276,7 +6956,6 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.2.tgz", "integrity": "sha512-36P2QR59jDTOAiIkqEprfJDsoNrvwFei3eCqKd1Y0tUsBimsq39BLp7RD+JWny3WgB1zGhJX8XVePwm9k4wdBg==", - "dev": true, "requires": { "cssesc": "^3.0.0", "indexes-of": "^1.0.1", @@ -7287,19 +6966,24 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-4.0.2.tgz", "integrity": "sha512-C6wyjo3VwFm0QgBy+Fu7gCYOkCmgmClghO+pjcxvrcBKtiKt0uCF+hvbMO1fyv5BMImRK90SMb+dwUnfbGd+jw==", - "dev": true, "requires": { "is-svg": "^3.0.0", "postcss": "^7.0.0", "postcss-value-parser": "^3.0.0", "svgo": "^1.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } } }, "postcss-unique-selectors": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz", "integrity": "sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg==", - "dev": true, "requires": { "alphanum-sort": "^1.0.0", "postcss": "^7.0.0", @@ -7307,28 +6991,24 @@ } }, "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.0.2.tgz", + "integrity": "sha512-LmeoohTpp/K4UiyQCwuGWlONxXamGzCMtFxLq4W1nZVGIQLYvMCJx3yAF9qyyuFpflABI9yVdtJAqbihOsCsJQ==" }, "prepend-http": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", - "dev": true + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=" }, "prettier": { - "version": "1.16.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.16.3.tgz", - "integrity": "sha512-kn/GU6SMRYPxUakNXhpP0EedT/KmaPzr0H5lIsDogrykbaxOpOfAFfk5XA7DZrJyMAv1wlMV3CPcZruGXVVUZw==", - "dev": true + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", + "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==" }, "pretty-error": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.1.tgz", "integrity": "sha1-X0+HyPkeWuPzuoerTPXgOxoX8aM=", - "dev": true, "requires": { "renderkid": "^2.0.1", "utila": "~0.4" @@ -7337,14 +7017,12 @@ "pretty-time": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/pretty-time/-/pretty-time-1.1.0.tgz", - "integrity": "sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA==", - "dev": true + "integrity": "sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA==" }, "prismjs": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.16.0.tgz", - "integrity": "sha512-OA4MKxjFZHSvZcisLGe14THYsug/nF6O1f0pAJc0KN0wTyAcLqmsbE+lTGKSpyh+9pEW57+k6pg2AfYR+coyHA==", - "dev": true, + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.17.1.tgz", + "integrity": "sha512-PrEDJAFdUGbOP6xK/UsfkC5ghJsPJviKgnQOoxaDbBjwc8op68Quupwt1DeAFoG8GImPhiKXAvvsH7wDSLsu1Q==", "requires": { "clipboard": "^2.0.0" } @@ -7352,32 +7030,35 @@ "private": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", - "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", - "dev": true + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==" }, "process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", - "dev": true + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "requires": { + "asap": "~2.0.3" + } }, "promise-inflight": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", - "dev": true + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=" }, "proxy-addr": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz", "integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==", - "dev": true, "requires": { "forwarded": "~0.1.2", "ipaddr.js": "1.9.0" @@ -7386,26 +7067,22 @@ "prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", - "dev": true + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=" }, "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", - "dev": true + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" }, "psl": { - "version": "1.1.33", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.33.tgz", - "integrity": "sha512-LTDP2uSrsc7XCb5lO7A8BI1qYxRe/8EqlRvMeEl6rsnYAqDOl8xHR+8lSAIVfrNaSAlTPTNOCgNjWcoUL3AZsw==", - "dev": true + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.6.0.tgz", + "integrity": "sha512-SYKKmVel98NCOYXpkwUqZqh0ahZeeKfmisiLIcEZdsb+WbLv02g/dI5BUmZnIyOe7RzZtLax81nnb2HbvC2tzA==" }, "public-encrypt": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", - "dev": true, "requires": { "bn.js": "^4.1.0", "browserify-rsa": "^4.0.0", @@ -7415,35 +7092,154 @@ "safe-buffer": "^5.1.2" } }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, + "pug": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pug/-/pug-2.0.4.tgz", + "integrity": "sha512-XhoaDlvi6NIzL49nu094R2NA6P37ijtgMDuWE+ofekDChvfKnzFal60bhSdiy8y2PBO6fmz3oMEIcfpBVRUdvw==", "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "pug-code-gen": "^2.0.2", + "pug-filters": "^3.1.1", + "pug-lexer": "^4.1.0", + "pug-linker": "^3.0.6", + "pug-load": "^2.0.12", + "pug-parser": "^5.0.1", + "pug-runtime": "^2.0.5", + "pug-strip-comments": "^1.0.4" } }, - "pumpify": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", - "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", - "dev": true, + "pug-attrs": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pug-attrs/-/pug-attrs-2.0.4.tgz", + "integrity": "sha512-TaZ4Z2TWUPDJcV3wjU3RtUXMrd3kM4Wzjbe3EWnSsZPsJ3LDI0F3yCnf2/W7PPFF+edUFQ0HgDL1IoxSz5K8EQ==", "requires": { - "duplexify": "^3.6.0", - "inherits": "^2.0.3", - "pump": "^2.0.0" - }, - "dependencies": { - "pump": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "constantinople": "^3.0.1", + "js-stringify": "^1.0.1", + "pug-runtime": "^2.0.5" + } + }, + "pug-code-gen": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/pug-code-gen/-/pug-code-gen-2.0.2.tgz", + "integrity": "sha512-kROFWv/AHx/9CRgoGJeRSm+4mLWchbgpRzTEn8XCiwwOy6Vh0gAClS8Vh5TEJ9DBjaP8wCjS3J6HKsEsYdvaCw==", + "requires": { + "constantinople": "^3.1.2", + "doctypes": "^1.1.0", + "js-stringify": "^1.0.1", + "pug-attrs": "^2.0.4", + "pug-error": "^1.3.3", + "pug-runtime": "^2.0.5", + "void-elements": "^2.0.1", + "with": "^5.0.0" + } + }, + "pug-error": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/pug-error/-/pug-error-1.3.3.tgz", + "integrity": "sha512-qE3YhESP2mRAWMFJgKdtT5D7ckThRScXRwkfo+Erqga7dyJdY3ZquspprMCj/9sJ2ijm5hXFWQE/A3l4poMWiQ==" + }, + "pug-filters": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/pug-filters/-/pug-filters-3.1.1.tgz", + "integrity": "sha512-lFfjNyGEyVWC4BwX0WyvkoWLapI5xHSM3xZJFUhx4JM4XyyRdO8Aucc6pCygnqV2uSgJFaJWW3Ft1wCWSoQkQg==", + "requires": { + "clean-css": "^4.1.11", + "constantinople": "^3.0.1", + "jstransformer": "1.0.0", + "pug-error": "^1.3.3", + "pug-walk": "^1.1.8", + "resolve": "^1.1.6", + "uglify-js": "^2.6.1" + } + }, + "pug-lexer": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/pug-lexer/-/pug-lexer-4.1.0.tgz", + "integrity": "sha512-i55yzEBtjm0mlplW4LoANq7k3S8gDdfC6+LThGEvsK4FuobcKfDAwt6V4jKPH9RtiE3a2Akfg5UpafZ1OksaPA==", + "requires": { + "character-parser": "^2.1.1", + "is-expression": "^3.0.0", + "pug-error": "^1.3.3" + } + }, + "pug-linker": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/pug-linker/-/pug-linker-3.0.6.tgz", + "integrity": "sha512-bagfuHttfQOpANGy1Y6NJ+0mNb7dD2MswFG2ZKj22s8g0wVsojpRlqveEQHmgXXcfROB2RT6oqbPYr9EN2ZWzg==", + "requires": { + "pug-error": "^1.3.3", + "pug-walk": "^1.1.8" + } + }, + "pug-load": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/pug-load/-/pug-load-2.0.12.tgz", + "integrity": "sha512-UqpgGpyyXRYgJs/X60sE6SIf8UBsmcHYKNaOccyVLEuT6OPBIMo6xMPhoJnqtB3Q3BbO4Z3Bjz5qDsUWh4rXsg==", + "requires": { + "object-assign": "^4.1.0", + "pug-walk": "^1.1.8" + } + }, + "pug-parser": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pug-parser/-/pug-parser-5.0.1.tgz", + "integrity": "sha512-nGHqK+w07p5/PsPIyzkTQfzlYfuqoiGjaoqHv1LjOv2ZLXmGX1O+4Vcvps+P4LhxZ3drYSljjq4b+Naid126wA==", + "requires": { + "pug-error": "^1.3.3", + "token-stream": "0.0.1" + } + }, + "pug-plain-loader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pug-plain-loader/-/pug-plain-loader-1.0.0.tgz", + "integrity": "sha512-mDfq/qvJJ0xdug38mZ1ObW0BQTx9kAHnKqotXC+C00XQkKmsWaMe90JUg/kN4lS6MU7tpVsMZ+rmcnBSPfDtHA==", + "requires": { + "loader-utils": "^1.1.0" + } + }, + "pug-runtime": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/pug-runtime/-/pug-runtime-2.0.5.tgz", + "integrity": "sha512-P+rXKn9un4fQY77wtpcuFyvFaBww7/91f3jHa154qU26qFAnOe6SW1CbIDcxiG5lLK9HazYrMCCuDvNgDQNptw==" + }, + "pug-strip-comments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/pug-strip-comments/-/pug-strip-comments-1.0.4.tgz", + "integrity": "sha512-i5j/9CS4yFhSxHp5iKPHwigaig/VV9g+FgReLJWWHEHbvKsbqL0oP/K5ubuLco6Wu3Kan5p7u7qk8A4oLLh6vw==", + "requires": { + "pug-error": "^1.3.3" + } + }, + "pug-walk": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pug-walk/-/pug-walk-1.1.8.tgz", + "integrity": "sha512-GMu3M5nUL3fju4/egXwZO0XLi6fW/K3T3VTgFQ14GxNi8btlxgT5qZL//JwZFm/2Fa64J/PNS8AZeys3wiMkVA==" + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } } } @@ -7451,26 +7247,22 @@ "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, "q": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", - "dev": true + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=" }, "qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", - "dev": true + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" }, "query-string": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", - "dev": true, "requires": { "decode-uri-component": "^0.2.0", "object-assign": "^4.1.0", @@ -7480,26 +7272,22 @@ "querystring": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", - "dev": true + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" }, "querystring-es3": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", - "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", - "dev": true + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=" }, "querystringify": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz", - "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==", - "dev": true + "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==" }, "randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, "requires": { "safe-buffer": "^5.1.0" } @@ -7508,7 +7296,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", - "dev": true, "requires": { "randombytes": "^2.0.5", "safe-buffer": "^5.1.0" @@ -7517,14 +7304,12 @@ "range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "dev": true + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" }, "raw-body": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", - "dev": true, "requires": { "bytes": "3.1.0", "http-errors": "1.7.2", @@ -7535,8 +7320,7 @@ "bytes": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", - "dev": true + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" } } }, @@ -7544,7 +7328,6 @@ "version": "2.3.6", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -7553,13 +7336,24 @@ "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } } }, "readdirp": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", - "dev": true, "requires": { "graceful-fs": "^4.1.11", "micromatch": "^3.1.10", @@ -7570,7 +7364,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/reduce/-/reduce-1.0.2.tgz", "integrity": "sha512-xX7Fxke/oHO5IfZSk77lvPa/7bjMh9BuCk4OOoX5XTXrM7s0Z+MkPfSDfz0q7r91BhhGSs8gii/VEN/7zhCPpQ==", - "dev": true, "requires": { "object-keys": "^1.1.0" } @@ -7578,29 +7371,25 @@ "regenerate": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", - "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==", - "dev": true + "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==" }, "regenerate-unicode-properties": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz", "integrity": "sha512-LGZzkgtLY79GeXLm8Dp0BVLdQlWICzBnJz/ipWUgo59qBaZ+BHtq51P2q1uVZlppMuUAT37SDk39qUbjTWB7bA==", - "dev": true, "requires": { "regenerate": "^1.4.0" } }, "regenerator-runtime": { - "version": "0.13.2", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz", - "integrity": "sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA==", - "dev": true + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" }, "regenerator-transform": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.0.tgz", - "integrity": "sha512-rtOelq4Cawlbmq9xuMR5gdFmv7ku/sFoB7sRiywx7aq53bc52b4j6zvH7Te1Vt/X2YveDKnCGUbioieU7FEL3w==", - "dev": true, + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.1.tgz", + "integrity": "sha512-flVuee02C3FKRISbxhXl9mGzdbWUVHubl1SMaknjxkFB1/iqpJhArQUvRxOOPEc/9tAiX0BaQ28FJH10E4isSQ==", "requires": { "private": "^0.1.6" } @@ -7609,26 +7398,26 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dev": true, "requires": { "extend-shallow": "^3.0.2", "safe-regex": "^1.1.0" } }, - "regexp-tree": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.10.tgz", - "integrity": "sha512-K1qVSbcedffwuIslMwpe6vGlj+ZXRnGkvjAtFHfDZZZuEdA/h0dxljAPu9vhUo6Rrx2U2AwJ+nSQ6hK+lrP5MQ==", - "dev": true + "regexp.prototype.flags": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.2.0.tgz", + "integrity": "sha512-ztaw4M1VqgMwl9HlPpOuiYgItcHlunW0He2fE6eNfT6E/CF2FtYi9ofOYe4mKntstYk0Fyh/rDRBdS3AnxjlrA==", + "requires": { + "define-properties": "^1.1.2" + } }, "regexpu-core": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.5.4.tgz", - "integrity": "sha512-BtizvGtFQKGPUcTy56o3nk1bGRp4SZOTYrDtGNlqCQufptV5IkkLN6Emw+yunAJjzf+C9FQFtvq7IoA3+oMYHQ==", - "dev": true, + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.6.0.tgz", + "integrity": "sha512-YlVaefl8P5BnFYOITTNzDvan1ulLOiXJzCNZxduTIosN17b87h3bvG9yHMoHaRuo88H4mQ06Aodj5VtYGGGiTg==", "requires": { "regenerate": "^1.4.0", - "regenerate-unicode-properties": "^8.0.2", + "regenerate-unicode-properties": "^8.1.0", "regjsgen": "^0.5.0", "regjsparser": "^0.6.0", "unicode-match-property-ecmascript": "^1.0.4", @@ -7636,16 +7425,14 @@ } }, "regjsgen": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.0.tgz", - "integrity": "sha512-RnIrLhrXCX5ow/E5/Mh2O4e/oa1/jW0eaBKTSy3LaCj+M3Bqvm97GWDp2yUtzIs4LEn65zR2yiYGFqb2ApnzDA==", - "dev": true + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.1.tgz", + "integrity": "sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg==" }, "regjsparser": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.0.tgz", "integrity": "sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ==", - "dev": true, "requires": { "jsesc": "~0.5.0" }, @@ -7653,28 +7440,24 @@ "jsesc": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", - "dev": true + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" } } }, "relateurl": { "version": "0.2.7", "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", - "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", - "dev": true + "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=" }, "remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" }, "renderkid": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.3.tgz", "integrity": "sha512-z8CLQp7EZBPCwCnncgf9C4XAi3WR0dv+uWu/PjIyhhAb5d6IJ/QZqlHFprHeKT+59//V6BNUsLbvN8+2LarxGA==", - "dev": true, "requires": { "css-select": "^1.1.0", "dom-converter": "^0.2", @@ -7687,7 +7470,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", - "dev": true, "requires": { "boolbase": "~1.0.0", "css-what": "2.1", @@ -7695,11 +7477,15 @@ "nth-check": "~1.0.1" } }, + "css-what": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", + "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==" + }, "domutils": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", - "dev": true, "requires": { "dom-serializer": "0", "domelementtype": "1" @@ -7710,20 +7496,17 @@ "repeat-element": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", - "dev": true + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==" }, "repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" }, "request": { "version": "2.88.0", "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", - "dev": true, "requires": { "aws-sign2": "~0.7.0", "aws4": "^1.8.0", @@ -7745,45 +7528,32 @@ "tough-cookie": "~2.4.3", "tunnel-agent": "^0.6.0", "uuid": "^3.3.2" - }, - "dependencies": { - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", - "dev": true - } } }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" }, "require-main-filename": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", - "dev": true + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" }, "requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", - "dev": true + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" }, "reselect": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/reselect/-/reselect-3.0.1.tgz", - "integrity": "sha1-79qpjqdFEyTQkrKyFjpqHXqaIUc=", - "dev": true + "integrity": "sha1-79qpjqdFEyTQkrKyFjpqHXqaIUc=" }, "resolve": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.1.tgz", - "integrity": "sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw==", - "dev": true, + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.13.1.tgz", + "integrity": "sha512-CxqObCX8K8YtAhOBRg+lrcdn+LK+WYOS8tSjqSFbjtrI5PnS63QPhZl4+yKfrU9tdsbMu9Anr/amegT87M9Z6w==", "requires": { "path-parse": "^1.0.6" } @@ -7792,7 +7562,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", - "dev": true, "requires": { "resolve-from": "^3.0.0" } @@ -7800,44 +7569,45 @@ "resolve-from": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", - "dev": true + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=" }, "resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "dev": true + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" }, "ret": { "version": "0.1.15", "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" }, "retry": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", - "dev": true + "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=" }, "rgb-regex": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz", - "integrity": "sha1-wODWiC3w4jviVKR16O3UGRX+rrE=", - "dev": true + "integrity": "sha1-wODWiC3w4jviVKR16O3UGRX+rrE=" }, "rgba-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz", - "integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=", - "dev": true + "integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=" + }, + "right-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", + "requires": { + "align-text": "^0.1.1" + } }, "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "dev": true, + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "requires": { "glob": "^7.1.3" } @@ -7846,7 +7616,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "dev": true, "requires": { "hash-base": "^3.0.0", "inherits": "^2.0.1" @@ -7856,22 +7625,19 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", - "dev": true, "requires": { "aproba": "^1.1.1" } }, "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" }, "safe-regex": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, "requires": { "ret": "~0.1.10" } @@ -7879,20 +7645,17 @@ "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" }, "schema-utils": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", - "dev": true, "requires": { "ajv": "^6.1.0", "ajv-errors": "^1.0.0", @@ -7903,7 +7666,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", - "dev": true, "requires": { "extend-shallow": "^2.0.1", "kind-of": "^6.0.0" @@ -7913,10 +7675,14 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, "requires": { "is-extendable": "^0.1.0" } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" } } }, @@ -7924,35 +7690,30 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz", "integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=", - "dev": true, "optional": true }, "select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", - "dev": true + "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=" }, "selfsigned": { - "version": "1.10.4", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.4.tgz", - "integrity": "sha512-9AukTiDmHXGXWtWjembZ5NDmVvP2695EtpgbCsxCa68w3c88B+alqbmZ4O3hZ4VWGXeGWzEVdvqgAJD8DQPCDw==", - "dev": true, + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.7.tgz", + "integrity": "sha512-8M3wBCzeWIJnQfl43IKwOmC4H/RAp50S8DF60znzjW5GVqTcSe2vWclt7hmYVPkKPlHWOu5EaWOMZ2Y6W8ZXTA==", "requires": { - "node-forge": "0.7.5" + "node-forge": "0.9.0" } }, "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", - "dev": true + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" }, "send": { "version": "0.17.1", "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", - "dev": true, "requires": { "debug": "2.6.9", "depd": "~1.1.2", @@ -7969,48 +7730,27 @@ "statuses": "~1.5.0" }, "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, "mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" }, "ms": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "dev": true + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" } } }, "serialize-javascript": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.7.0.tgz", - "integrity": "sha512-ke8UG8ulpFOxO8f8gRYabHQe/ZntKlcig2Mp+8+URDP1D8vJZ0KUt7LYo07q25Z/+JVSgpr/cui9PIp5H6/+nA==", - "dev": true + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz", + "integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==" }, "serve-index": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", - "dev": true, "requires": { "accepts": "~1.3.4", "batch": "0.6.1", @@ -8021,20 +7761,10 @@ "parseurl": "~1.3.2" }, "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, "http-errors": { "version": "1.6.3", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", - "dev": true, "requires": { "depd": "~1.1.2", "inherits": "2.0.3", @@ -8045,20 +7775,12 @@ "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, "setprototypeof": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", - "dev": true + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" } } }, @@ -8066,7 +7788,6 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", - "dev": true, "requires": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", @@ -8077,14 +7798,12 @@ "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, "set-value": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "dev": true, "requires": { "extend-shallow": "^2.0.1", "is-extendable": "^0.1.1", @@ -8096,7 +7815,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, "requires": { "is-extendable": "^0.1.0" } @@ -8106,20 +7824,17 @@ "setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", - "dev": true + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" }, "setprototypeof": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", - "dev": true + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" }, "sha.js": { "version": "2.4.11", "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "dev": true, "requires": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -8129,7 +7844,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, "requires": { "shebang-regex": "^1.0.0" } @@ -8137,20 +7851,17 @@ "shebang-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "dev": true + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" }, "simple-swizzle": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", - "dev": true, "requires": { "is-arrayish": "^0.3.1" }, @@ -8158,22 +7869,35 @@ "is-arrayish": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", - "dev": true + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" } } }, + "sitemap": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/sitemap/-/sitemap-3.2.2.tgz", + "integrity": "sha512-TModL/WU4m2q/mQcrDgNANn0P4LwprM9MMvG4hu5zP4c6IIKs2YLTu6nXXnNr8ODW/WFtxKggiJ1EGn2W0GNmg==", + "requires": { + "lodash.chunk": "^4.2.0", + "lodash.padstart": "^4.6.1", + "whatwg-url": "^7.0.0", + "xmlbuilder": "^13.0.0" + } + }, "slash": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", - "dev": true + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==" + }, + "smoothscroll-polyfill": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/smoothscroll-polyfill/-/smoothscroll-polyfill-0.4.4.tgz", + "integrity": "sha512-TK5ZA9U5RqCwMpfoMq/l1mrH0JAR7y7KRvOBx0n2869aLxch+gT9GhN3yUfjiw+d/DiF1mKo14+hd62JyMmoBg==" }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "dev": true, "requires": { "base": "^0.11.1", "debug": "^2.2.0", @@ -8185,20 +7909,10 @@ "use": "^3.1.0" }, "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, "requires": { "is-descriptor": "^0.1.0" } @@ -8207,16 +7921,14 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, "requires": { "is-extendable": "^0.1.0" } }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" } } }, @@ -8224,7 +7936,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, "requires": { "define-property": "^1.0.0", "isobject": "^3.0.0", @@ -8235,7 +7946,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, "requires": { "is-descriptor": "^1.0.0" } @@ -8244,7 +7954,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, "requires": { "kind-of": "^6.0.0" } @@ -8253,7 +7962,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, "requires": { "kind-of": "^6.0.0" } @@ -8262,12 +7970,16 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", "is-data-descriptor": "^1.0.0", "kind-of": "^6.0.2" } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" } } }, @@ -8275,37 +7987,23 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "dev": true, "requires": { "kind-of": "^3.2.0" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } } }, "sockjs": { "version": "0.3.19", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.19.tgz", "integrity": "sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw==", - "dev": true, "requires": { "faye-websocket": "^0.10.0", "uuid": "^3.0.1" } }, "sockjs-client": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.3.0.tgz", - "integrity": "sha512-R9jxEzhnnrdxLCNln0xg5uGHqMnkhPSTzUZH2eXcR03S/On9Yvoq2wyUZILRUhZCNVu2PmwWVoyuiPz8th8zbg==", - "dev": true, + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.4.0.tgz", + "integrity": "sha512-5zaLyO8/nri5cua0VtOrFXBPK1jbL4+1cebT/mmKA1E1ZXOvJrII75bPu0l0k843G/+iAbhEqzyKr0w/eCCj7g==", "requires": { "debug": "^3.2.5", "eventsource": "^1.0.7", @@ -8319,7 +8017,6 @@ "version": "3.2.6", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, "requires": { "ms": "^2.1.1" } @@ -8328,10 +8025,14 @@ "version": "0.11.3", "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.3.tgz", "integrity": "sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA==", - "dev": true, "requires": { "websocket-driver": ">=0.5.1" } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" } } }, @@ -8339,7 +8040,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz", "integrity": "sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=", - "dev": true, "requires": { "is-plain-obj": "^1.0.0" } @@ -8347,20 +8047,17 @@ "source-list-map": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", - "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", - "dev": true + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==" }, "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" }, "source-map-resolve": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", - "dev": true, "requires": { "atob": "^2.1.1", "decode-uri-component": "^0.2.0", @@ -8370,47 +8067,50 @@ } }, "source-map-support": { - "version": "0.5.12", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.12.tgz", - "integrity": "sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ==", - "dev": true, + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz", + "integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==", "requires": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } } }, "source-map-url": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", - "dev": true + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=" }, "spdy": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.0.tgz", - "integrity": "sha512-ot0oEGT/PGUpzf/6uk4AWLqkq+irlqHXkrdbk51oWONh3bxQmBuljxPNl66zlRRcIJStWq0QkLUCPOPjgjvU0Q==", - "dev": true, + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.1.tgz", + "integrity": "sha512-HeZS3PBdMA+sZSu0qwpCxl3DeALD5ASx8pAX0jZdKXSpPWbQ6SYGnlg3BBmYLx5LtiZrmkAZfErCm2oECBcioA==", "requires": { "debug": "^4.1.0", "handle-thing": "^2.0.0", "http-deceiver": "^1.2.7", "select-hose": "^2.0.0", "spdy-transport": "^3.0.0" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } } }, "spdy-transport": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", - "dev": true, "requires": { "debug": "^4.1.0", "detect-node": "^2.0.4", @@ -8420,11 +8120,23 @@ "wbuf": "^1.7.3" }, "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, "readable-stream": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", - "dev": true, "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -8437,7 +8149,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dev": true, "requires": { "extend-shallow": "^3.0.0" } @@ -8445,14 +8156,12 @@ "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" }, "sshpk": { "version": "1.16.1", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "dev": true, "requires": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", @@ -8469,7 +8178,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", - "dev": true, "requires": { "figgy-pudding": "^3.5.1" } @@ -8477,20 +8185,17 @@ "stable": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", - "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", - "dev": true + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==" }, "stack-utils": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz", - "integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA==", - "dev": true + "integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA==" }, "static-extend": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, "requires": { "define-property": "^0.2.5", "object-copy": "^0.1.0" @@ -8500,7 +8205,6 @@ "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, "requires": { "is-descriptor": "^0.1.0" } @@ -8510,14 +8214,12 @@ "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", - "dev": true + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" }, "std-env": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/std-env/-/std-env-2.2.1.tgz", "integrity": "sha512-IjYQUinA3lg5re/YMlwlfhqNRTzMZMqE+pezevdcTaHceqx8ngEi1alX9nNCk9Sc81fy1fLDeQoaCzeiW1yBOQ==", - "dev": true, "requires": { "ci-info": "^1.6.0" } @@ -8526,7 +8228,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", - "dev": true, "requires": { "inherits": "~2.0.1", "readable-stream": "^2.0.2" @@ -8536,7 +8237,6 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", - "dev": true, "requires": { "end-of-stream": "^1.1.0", "stream-shift": "^1.0.0" @@ -8546,7 +8246,6 @@ "version": "2.8.3", "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", - "dev": true, "requires": { "builtin-status-codes": "^3.0.0", "inherits": "^2.0.1", @@ -8558,20 +8257,17 @@ "stream-shift": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", - "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=", - "dev": true + "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=" }, "strict-uri-encode": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", - "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", - "dev": true + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=" }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, "requires": { "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^4.0.0" @@ -8580,34 +8276,55 @@ "ansi-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" }, "strip-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, "requires": { "ansi-regex": "^3.0.0" } } } }, + "string.prototype.trimleft": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz", + "integrity": "sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw==", + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "string.prototype.trimright": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz", + "integrity": "sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg==", + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, "requires": { "safe-buffer": "~5.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } } }, "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, "requires": { "ansi-regex": "^2.0.0" } @@ -8615,20 +8332,17 @@ "strip-bom-string": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", - "integrity": "sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI=", - "dev": true + "integrity": "sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI=" }, "strip-eof": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" }, "stylehacks": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz", "integrity": "sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g==", - "dev": true, "requires": { "browserslist": "^4.0.0", "postcss": "^7.0.0", @@ -8639,7 +8353,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz", "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", - "dev": true, "requires": { "dot-prop": "^4.1.1", "indexes-of": "^1.0.1", @@ -8649,47 +8362,50 @@ } }, "stylus": { - "version": "0.54.5", - "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.54.5.tgz", - "integrity": "sha1-QrlWCTHKcJDOhRWnmLqeaqPW3Hk=", - "dev": true, - "requires": { - "css-parse": "1.7.x", - "debug": "*", - "glob": "7.0.x", - "mkdirp": "0.5.x", - "sax": "0.5.x", - "source-map": "0.1.x" + "version": "0.54.7", + "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.54.7.tgz", + "integrity": "sha512-Yw3WMTzVwevT6ZTrLCYNHAFmanMxdylelL3hkWNgPMeTCpMwpV3nXjpOHuBXtFv7aiO2xRuQS6OoAdgkNcSNug==", + "requires": { + "css-parse": "~2.0.0", + "debug": "~3.1.0", + "glob": "^7.1.3", + "mkdirp": "~0.5.x", + "safer-buffer": "^2.1.2", + "sax": "~1.2.4", + "semver": "^6.0.0", + "source-map": "^0.7.3" }, "dependencies": { - "glob": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz", - "integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=", - "dev": true, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.2", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "ms": "2.0.0" } }, - "sax": { - "version": "0.5.8", - "resolved": "https://registry.npmjs.org/sax/-/sax-0.5.8.tgz", - "integrity": "sha1-1HLbIo6zMcJQaw6MFVJK25OdEsE=", - "dev": true + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" }, - "source-map": { - "version": "0.1.43", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", - "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", - "dev": true, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "requires": { - "amdefine": ">=0.0.4" + "minimist": "0.0.8" } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + }, + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" } } }, @@ -8697,7 +8413,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/stylus-loader/-/stylus-loader-3.0.2.tgz", "integrity": "sha512-+VomPdZ6a0razP+zinir61yZgpw2NfljeSsdUF5kJuEzlo3khXhY19Fn6l8QQz1GRJGtMCo8nG5C04ePyV7SUA==", - "dev": true, "requires": { "loader-utils": "^1.0.2", "lodash.clonedeep": "^4.5.0", @@ -8708,7 +8423,6 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, "requires": { "has-flag": "^3.0.0" } @@ -8716,22 +8430,19 @@ "svg-tags": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz", - "integrity": "sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=", - "dev": true + "integrity": "sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=" }, "svgo": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.2.2.tgz", - "integrity": "sha512-rAfulcwp2D9jjdGu+0CuqlrAUin6bBWrpoqXWwKDZZZJfXcUXQSxLJOFJCQCSA0x0pP2U0TxSlJu2ROq5Bq6qA==", - "dev": true, + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", + "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==", "requires": { "chalk": "^2.4.1", "coa": "^2.0.2", "css-select": "^2.0.0", "css-select-base-adapter": "^0.1.1", - "css-tree": "1.0.0-alpha.28", - "css-url-regex": "^1.1.0", - "csso": "^3.5.1", + "css-tree": "1.0.0-alpha.37", + "csso": "^4.0.2", "js-yaml": "^3.13.1", "mkdirp": "~0.5.1", "object.values": "^1.1.0", @@ -8739,98 +8450,89 @@ "stable": "^0.1.8", "unquote": "~1.1.1", "util.promisify": "~1.0.0" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + } + } } }, "tapable": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", - "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", - "dev": true + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==" }, "terser": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-4.0.0.tgz", - "integrity": "sha512-dOapGTU0hETFl1tCo4t56FN+2jffoKyER9qBGoUFyZ6y7WLoKT0bF+lAYi6B6YsILcGF3q1C2FBh8QcKSCgkgA==", - "dev": true, + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.4.2.tgz", + "integrity": "sha512-Uufrsvhj9O1ikwgITGsZ5EZS6qPokUOkCegS7fYOdGTv+OA90vndUbU6PEjr5ePqHfNUbGyMO7xyIZv2MhsALQ==", "requires": { - "commander": "^2.19.0", + "commander": "^2.20.0", "source-map": "~0.6.1", - "source-map-support": "~0.5.10" + "source-map-support": "~0.5.12" }, "dependencies": { "commander": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", - "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" } } }, "terser-webpack-plugin": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.3.0.tgz", - "integrity": "sha512-W2YWmxPjjkUcOWa4pBEv4OP4er1aeQJlSo2UhtCFQCuRXEHjOFscO8VyWHj9JLlA0RzQb8Y2/Ta78XZvT54uGg==", - "dev": true, + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.2.tgz", + "integrity": "sha512-fdEb91kR2l+BVgES77N/NTXWZlpX6vX+pYPjnX5grcDYBF2CMnzJiXX4NNlna4l04lvCW39lZ+O/jSvUhHH/ew==", "requires": { - "cacache": "^11.3.2", - "find-cache-dir": "^2.0.0", + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", "is-wsl": "^1.1.0", - "loader-utils": "^1.2.3", "schema-utils": "^1.0.0", - "serialize-javascript": "^1.7.0", + "serialize-javascript": "^2.1.1", "source-map": "^0.6.1", - "terser": "^4.0.0", - "webpack-sources": "^1.3.0", + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", "worker-farm": "^1.7.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } } }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" }, "through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, "requires": { "readable-stream": "~2.3.6", "xtend": "~4.0.1" } }, "thunky": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.0.3.tgz", - "integrity": "sha512-YwT8pjmNcAXBZqrubu22P4FYsh2D4dxRmnWBOL8Jk8bUcRUtc5326kx32tuTmFDAZtLOGEVNl8POAR8j896Iow==", - "dev": true + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" }, "timers-browserify": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.10.tgz", - "integrity": "sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg==", - "dev": true, + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.11.tgz", + "integrity": "sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ==", "requires": { "setimmediate": "^1.0.4" } @@ -8838,59 +8540,68 @@ "timsort": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", - "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=", - "dev": true + "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=" }, "tiny-emitter": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==", - "dev": true, "optional": true }, + "tm-tooltip": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/tm-tooltip/-/tm-tooltip-0.0.10.tgz", + "integrity": "sha512-ud+LicFlyhwLwO/nfGvtASg3TyUCjaEQC5GCZaE/JzXQmwK0ndb+4F0/ek8xr07rOENFUIT9N+1tmUDqCAtv1g==", + "requires": { + "markdown-it": "^9.1.0" + }, + "dependencies": { + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" + }, + "markdown-it": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-9.1.0.tgz", + "integrity": "sha512-xHKG4C8iPriyfu/jc2hsCC045fKrMQ0VexX2F1FGYiRxDxqMB2aAhF8WauJ3fltn2kb90moGBkiiEdooGIg55w==", + "requires": { + "argparse": "^1.0.7", + "entities": "~1.1.1", + "linkify-it": "^2.0.0", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + } + } + } + }, "to-arraybuffer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", - "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", - "dev": true + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=" }, "to-factory": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/to-factory/-/to-factory-1.0.0.tgz", - "integrity": "sha1-hzivi9lxIK0dQEeXKtpVY7+UebE=", - "dev": true + "integrity": "sha1-hzivi9lxIK0dQEeXKtpVY7+UebE=" }, "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=" }, "to-object-path": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, "requires": { "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } } }, "to-regex": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dev": true, "requires": { "define-property": "^2.0.2", "extend-shallow": "^3.0.2", @@ -8902,7 +8613,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, "requires": { "is-number": "^3.0.0", "repeat-string": "^1.6.1" @@ -8911,26 +8621,27 @@ "toidentifier": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", - "dev": true + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + }, + "token-stream": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/token-stream/-/token-stream-0.0.1.tgz", + "integrity": "sha1-zu78cXp2xDFvEm0LnbqlXX598Bo=" }, "toml": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz", - "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==", - "dev": true + "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==" }, "toposort": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/toposort/-/toposort-1.0.7.tgz", - "integrity": "sha1-LmhELZ9k7HILjMieZEOsbKqVACk=", - "dev": true + "integrity": "sha1-LmhELZ9k7HILjMieZEOsbKqVACk=" }, "tough-cookie": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", - "dev": true, "requires": { "psl": "^1.1.24", "punycode": "^1.4.1" @@ -8939,34 +8650,32 @@ "punycode": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" } } }, - "trim-right": { + "tr46": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", - "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", - "dev": true + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", + "requires": { + "punycode": "^2.1.0" + } }, "tslib": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", - "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", - "dev": true + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" }, "tty-browserify": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", - "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", - "dev": true + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=" }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, "requires": { "safe-buffer": "^5.0.1" } @@ -8974,20 +8683,17 @@ "tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "dev": true + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" }, "type-fest": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.5.2.tgz", - "integrity": "sha512-DWkS49EQKVX//Tbupb9TFa19c7+MK1XmzkrZUR8TAktmE/DizXoaoJV6TZ/tSIPXipqNiRI6CyAe7x69Jb6RSw==", - "dev": true + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==" }, "type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "dev": true, "requires": { "media-typer": "0.3.0", "mime-types": "~2.1.24" @@ -8996,50 +8702,45 @@ "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", - "dev": true + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" }, "uc.micro": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", - "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", - "dev": true + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" }, "uglify-js": { - "version": "3.4.10", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz", - "integrity": "sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==", - "dev": true, + "version": "2.8.29", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", + "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", "requires": { - "commander": "~2.19.0", - "source-map": "~0.6.1" + "source-map": "~0.5.1", + "uglify-to-browserify": "~1.0.0", + "yargs": "~3.10.0" }, "dependencies": { - "commander": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", - "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==", - "dev": true - }, "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" } } }, + "uglify-to-browserify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", + "optional": true + }, "unicode-canonical-property-names-ecmascript": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", - "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", - "dev": true + "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==" }, "unicode-match-property-ecmascript": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", - "dev": true, "requires": { "unicode-canonical-property-names-ecmascript": "^1.0.4", "unicode-property-aliases-ecmascript": "^1.0.4" @@ -9048,20 +8749,17 @@ "unicode-match-property-value-ecmascript": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.1.0.tgz", - "integrity": "sha512-hDTHvaBk3RmFzvSl0UVrUmC3PuW9wKVnpoUDYH0JDkSIovzw+J5viQmeYHxVSBptubnr7PbH2e0fnpDRQnQl5g==", - "dev": true + "integrity": "sha512-hDTHvaBk3RmFzvSl0UVrUmC3PuW9wKVnpoUDYH0JDkSIovzw+J5viQmeYHxVSBptubnr7PbH2e0fnpDRQnQl5g==" }, "unicode-property-aliases-ecmascript": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz", - "integrity": "sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw==", - "dev": true + "integrity": "sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw==" }, "union-value": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "dev": true, "requires": { "arr-union": "^3.1.0", "get-value": "^2.0.6", @@ -9072,20 +8770,17 @@ "uniq": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", - "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", - "dev": true + "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=" }, "uniqs": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz", - "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=", - "dev": true + "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=" }, "unique-filename": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", - "dev": true, "requires": { "unique-slug": "^2.0.0" } @@ -9094,7 +8789,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", - "dev": true, "requires": { "imurmurhash": "^0.1.4" } @@ -9102,26 +8796,22 @@ "universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", - "dev": true + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" }, "unquote": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", - "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=", - "dev": true + "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=" }, "unset-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, "requires": { "has-value": "^0.3.1", "isobject": "^3.0.0" @@ -9131,7 +8821,6 @@ "version": "0.3.1", "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, "requires": { "get-value": "^2.0.3", "has-values": "^0.1.4", @@ -9142,7 +8831,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, "requires": { "isarray": "1.0.0" } @@ -9152,28 +8840,29 @@ "has-values": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" } } }, "upath": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.2.tgz", - "integrity": "sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==", - "dev": true + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==" }, "upper-case": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", - "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=", - "dev": true + "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=" }, "uri-js": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "dev": true, "requires": { "punycode": "^2.1.0" } @@ -9181,14 +8870,12 @@ "urix": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "dev": true + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" }, "url": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", - "dev": true, "requires": { "punycode": "1.3.2", "querystring": "0.2.0" @@ -9197,8 +8884,7 @@ "punycode": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", - "dev": true + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" } } }, @@ -9206,7 +8892,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-1.1.2.tgz", "integrity": "sha512-dXHkKmw8FhPqu8asTc1puBfe3TehOCo2+RmOOev5suNCIYBcT626kxiWg1NBVkwc4rO8BGa7gP70W7VXuqHrjg==", - "dev": true, "requires": { "loader-utils": "^1.1.0", "mime": "^2.0.3", @@ -9217,7 +8902,6 @@ "version": "1.4.7", "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.7.tgz", "integrity": "sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==", - "dev": true, "requires": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" @@ -9226,14 +8910,12 @@ "use": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" }, "util": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", - "dev": true, "requires": { "inherits": "2.0.3" }, @@ -9241,22 +8923,19 @@ "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" } } }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "util.promisify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", - "dev": true, "requires": { "define-properties": "^1.1.2", "object.getownpropertydescriptors": "^2.0.3" @@ -9265,38 +8944,37 @@ "utila": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", - "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=", - "dev": true + "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=" }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", - "dev": true + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", - "dev": true + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", + "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==" + }, + "v-runtime-template": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/v-runtime-template/-/v-runtime-template-1.10.0.tgz", + "integrity": "sha512-WLlq9jUepSfUrMEenw3mn7FDXX6hhbl11JjC1OKhwLzifHzVrY5a696TUHDPyj9jke3GGnR7b+2T3od/RL5cww==" }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", - "dev": true + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" }, "vendors": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.3.tgz", - "integrity": "sha512-fOi47nsJP5Wqefa43kyWSg80qF+Q3XA6MUkgi7Hp1HQaKDQW4cQrK2D0P7mmbFtsV1N89am55Yru/nyEwRubcw==", - "dev": true + "integrity": "sha512-fOi47nsJP5Wqefa43kyWSg80qF+Q3XA6MUkgi7Hp1HQaKDQW4cQrK2D0P7mmbFtsV1N89am55Yru/nyEwRubcw==" }, "verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, "requires": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", @@ -9304,30 +8982,31 @@ } }, "vm-browserify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.0.tgz", - "integrity": "sha512-iq+S7vZJE60yejDYM0ek6zg308+UZsdtPExWP9VZoCFCz1zkJoXFnAX7aZfd/ZwrkidzdUZL0C/ryW+JwAiIGw==", - "dev": true + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==" + }, + "void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=" }, "vue": { "version": "2.6.10", "resolved": "https://registry.npmjs.org/vue/-/vue-2.6.10.tgz", - "integrity": "sha512-ImThpeNU9HbdZL3utgMCq0oiMzAkt1mcgy3/E6zWC/G6AaQoeuFdsl9nDhTDU3X1R6FK7nsIUuRACVcjI+A2GQ==", - "dev": true + "integrity": "sha512-ImThpeNU9HbdZL3utgMCq0oiMzAkt1mcgy3/E6zWC/G6AaQoeuFdsl9nDhTDU3X1R6FK7nsIUuRACVcjI+A2GQ==" }, "vue-hot-reload-api": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.3.tgz", - "integrity": "sha512-KmvZVtmM26BQOMK1rwUZsrqxEGeKiYSZGA7SNWE6uExx8UX/cj9hq2MRV/wWC3Cq6AoeDGk57rL9YMFRel/q+g==", - "dev": true + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz", + "integrity": "sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==" }, "vue-loader": { - "version": "15.7.0", - "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.7.0.tgz", - "integrity": "sha512-x+NZ4RIthQOxcFclEcs8sXGEWqnZHodL2J9Vq+hUz+TDZzBaDIh1j3d9M2IUlTjtrHTZy4uMuRdTi8BGws7jLA==", - "dev": true, + "version": "15.7.2", + "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.7.2.tgz", + "integrity": "sha512-H/P9xt/nkocyu4hZKg5TzPqyCT1oKOaCSk9zs0JCbJuy0Q8KtR0bjJpnT/5R5x/Ckd1GFkkLQnQ1C4x6xXeLZg==", "requires": { - "@vue/component-compiler-utils": "^2.5.1", + "@vue/component-compiler-utils": "^3.0.0", "hash-sum": "^1.0.2", "loader-utils": "^1.1.0", "vue-hot-reload-api": "^2.3.0", @@ -9335,16 +9014,14 @@ } }, "vue-router": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.0.6.tgz", - "integrity": "sha512-Ox0ciFLswtSGRTHYhGvx2L44sVbTPNS+uD2kRISuo8B39Y79rOo0Kw0hzupTmiVtftQYCZl87mwldhh2L9Aquw==", - "dev": true + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.1.3.tgz", + "integrity": "sha512-8iSa4mGNXBjyuSZFCCO4fiKfvzqk+mhL0lnKuGcQtO1eoj8nq3CmbEG8FwK5QqoqwDgsjsf1GDuisDX4cdb/aQ==" }, "vue-server-renderer": { "version": "2.6.10", "resolved": "https://registry.npmjs.org/vue-server-renderer/-/vue-server-renderer-2.6.10.tgz", "integrity": "sha512-UYoCEutBpKzL2fKCwx8zlRtRtwxbPZXKTqbl2iIF4yRZUNO/ovrHyDAJDljft0kd+K0tZhN53XRHkgvCZoIhug==", - "dev": true, "requires": { "chalk": "^1.1.3", "hash-sum": "^1.0.2", @@ -9359,14 +9036,12 @@ "ansi-styles": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" }, "chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, "requires": { "ansi-styles": "^2.2.1", "escape-string-regexp": "^1.0.2", @@ -9375,17 +9050,20 @@ "supports-color": "^2.0.0" } }, + "serialize-javascript": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.9.1.tgz", + "integrity": "sha512-0Vb/54WJ6k5v8sSWN09S0ora+Hnr+cX40r9F170nT+mSkaxltoE/7R3OrIdBSUv1OoiobH1QoWQbCnAO+e8J1A==" + }, "source-map": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", - "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=", - "dev": true + "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=" }, "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" } } }, @@ -9393,7 +9071,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.2.tgz", "integrity": "sha512-0ip8ge6Gzz/Bk0iHovU9XAUQaFt/G2B61bnWa2tCcqqdgfHs1lF9xXorFbE55Gmy92okFT+8bfmySuUOu13vxQ==", - "dev": true, "requires": { "hash-sum": "^1.0.2", "loader-utils": "^1.0.2" @@ -9403,7 +9080,6 @@ "version": "2.6.10", "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.6.10.tgz", "integrity": "sha512-jVZkw4/I/HT5ZMvRnhv78okGusqe0+qH2A0Em0Cp8aq78+NK9TII263CDVz2QXZsIT+yyV/gZc/j/vlwa+Epyg==", - "dev": true, "requires": { "de-indent": "^1.0.2", "he": "^1.1.0" @@ -9412,26 +9088,24 @@ "vue-template-es2015-compiler": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz", - "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==", - "dev": true + "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==" }, "vuepress": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/vuepress/-/vuepress-1.0.2.tgz", - "integrity": "sha512-HPRWxrq6D+S9uCR3oJ8/OTCy8GcYm9l1HxHb44rvaN2gyySVXIiqSkCwzd9r2PY8+pwvrfYE4rcY1RsTTpJ25g==", - "dev": true, + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/vuepress/-/vuepress-1.2.0.tgz", + "integrity": "sha512-EfHo8Cc73qo+1Pm18hM0qOGynmDr8q5fu2664obynsdCJ1zpvoShVnA0Msraw4SI2xDc0iAoIb3dTwxUIM8DAw==", "requires": { - "@vuepress/core": "^1.0.2", - "@vuepress/theme-default": "^1.0.2", + "@vuepress/core": "^1.2.0", + "@vuepress/theme-default": "^1.2.0", "cac": "^6.3.9", - "envinfo": "^7.2.0" + "envinfo": "^7.2.0", + "opencollective-postinstall": "^2.0.2" } }, "vuepress-html-webpack-plugin": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/vuepress-html-webpack-plugin/-/vuepress-html-webpack-plugin-3.2.0.tgz", "integrity": "sha512-BebAEl1BmWlro3+VyDhIOCY6Gef2MCBllEVAP3NUAtMguiyOwo/dClbwJ167WYmcxHJKLl7b0Chr9H7fpn1d0A==", - "dev": true, "requires": { "html-minifier": "^3.2.3", "loader-utils": "^0.2.16", @@ -9445,20 +9119,17 @@ "big.js": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", - "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==", - "dev": true + "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==" }, "json5": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", - "dev": true + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" }, "loader-utils": { "version": "0.2.17", "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", - "dev": true, "requires": { "big.js": "^3.1.3", "emojis-list": "^2.0.0", @@ -9469,19 +9140,63 @@ } }, "vuepress-plugin-container": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/vuepress-plugin-container/-/vuepress-plugin-container-2.0.1.tgz", - "integrity": "sha512-SMlWJl0uZYkqAxD2RUZmIrANZWKgiZdM64K7WmdyHyQPYI+NUj3ugi5D+zDn62BoO9NfQTiskEIa2u619SRweA==", - "dev": true, + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/vuepress-plugin-container/-/vuepress-plugin-container-2.1.2.tgz", + "integrity": "sha512-Df5KoIDMYiFg45GTfFw2hIiLGSsjhms4f3ppl2UIBf5nWMxi2lfifcoo8MooMSfxboxRZjoDccqQfu0fypaKrQ==", "requires": { "markdown-it-container": "^2.0.0" } }, + "vuepress-plugin-sitemap": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/vuepress-plugin-sitemap/-/vuepress-plugin-sitemap-2.3.1.tgz", + "integrity": "sha512-n+8lbukhrKrsI9H/EX0EBgkE1pn85LAQFvQ5dIvrZP4Kz6JxPOPPNTQmZMhahQV1tXbLZQCEN7A1WZH4x+arJQ==", + "requires": { + "sitemap": "^3.0.0" + } + }, + "vuepress-plugin-smooth-scroll": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/vuepress-plugin-smooth-scroll/-/vuepress-plugin-smooth-scroll-0.0.3.tgz", + "integrity": "sha512-qsQkDftLVFLe8BiviIHaLV0Ea38YLZKKonDGsNQy1IE0wllFpFIEldWD8frWZtDFdx6b/O3KDMgVQ0qp5NjJCg==", + "requires": { + "smoothscroll-polyfill": "^0.4.3" + } + }, + "vuepress-theme-cosmos": { + "version": "1.0.93", + "resolved": "https://registry.npmjs.org/vuepress-theme-cosmos/-/vuepress-theme-cosmos-1.0.93.tgz", + "integrity": "sha512-P8I8RSydfW/cetx0ruYegeDPuX3PkD/M9I8F7LX54rnA9wPrTM4fLo3fl2MYJmY9jh9uStVLGx95IlHqxtwsOA==", + "requires": { + "@cosmos-ui/vue": "^0.5.16", + "@vuepress/plugin-last-updated": "^1.2.0", + "@vuepress/plugin-search": "^1.1.0", + "algoliasearch": "^3.35.1", + "axios": "^0.19.0", + "clipboard-copy": "^3.1.0", + "docsearch.js": "^2.6.3", + "fuse.js": "^3.4.6", + "hotkeys-js": "^3.7.3", + "intersection-observer": "^0.7.0", + "lunr": "^2.3.8", + "markdown-it": "^10.0.0", + "markdown-it-attrs": "^3.0.1", + "markdown-it-ins": "^3.0.0", + "prismjs": "^1.17.1", + "pug": "^2.0.4", + "pug-plain-loader": "^1.0.0", + "stylus": "^0.54.7", + "stylus-loader": "^3.0.2", + "tm-tooltip": "0.0.10", + "v-runtime-template": "^1.10.0", + "vuepress": "^1.2.0", + "vuepress-plugin-sitemap": "^2.3.1" + } + }, "watchpack": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz", "integrity": "sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA==", - "dev": true, "requires": { "chokidar": "^2.0.2", "graceful-fs": "^4.1.2", @@ -9492,118 +9207,253 @@ "version": "1.7.3", "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", - "dev": true, "requires": { "minimalistic-assert": "^1.0.0" } }, + "webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" + }, "webpack": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.35.0.tgz", - "integrity": "sha512-M5hL3qpVvtr8d4YaJANbAQBc4uT01G33eDpl/psRTBCfjxFTihdhin1NtAKB1ruDwzeVdcsHHV3NX+QsAgOosw==", - "dev": true, + "version": "4.41.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.41.2.tgz", + "integrity": "sha512-Zhw69edTGfbz9/8JJoyRQ/pq8FYUoY0diOXqW0T6yhgdhCv6wr0hra5DwwWexNRns2Z2+gsnrNcbe9hbGBgk/A==", "requires": { "@webassemblyjs/ast": "1.8.5", "@webassemblyjs/helper-module-context": "1.8.5", "@webassemblyjs/wasm-edit": "1.8.5", "@webassemblyjs/wasm-parser": "1.8.5", - "acorn": "^6.0.5", - "acorn-dynamic-import": "^4.0.0", - "ajv": "^6.1.0", - "ajv-keywords": "^3.1.0", - "chrome-trace-event": "^1.0.0", + "acorn": "^6.2.1", + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1", + "chrome-trace-event": "^1.0.2", "enhanced-resolve": "^4.1.0", - "eslint-scope": "^4.0.0", + "eslint-scope": "^4.0.3", "json-parse-better-errors": "^1.0.2", - "loader-runner": "^2.3.0", - "loader-utils": "^1.1.0", - "memory-fs": "~0.4.1", - "micromatch": "^3.1.8", - "mkdirp": "~0.5.0", - "neo-async": "^2.5.0", - "node-libs-browser": "^2.0.0", + "loader-runner": "^2.4.0", + "loader-utils": "^1.2.3", + "memory-fs": "^0.4.1", + "micromatch": "^3.1.10", + "mkdirp": "^0.5.1", + "neo-async": "^2.6.1", + "node-libs-browser": "^2.2.1", "schema-utils": "^1.0.0", - "tapable": "^1.1.0", - "terser-webpack-plugin": "^1.1.0", - "watchpack": "^1.5.0", - "webpack-sources": "^1.3.0" + "tapable": "^1.1.3", + "terser-webpack-plugin": "^1.4.1", + "watchpack": "^1.6.0", + "webpack-sources": "^1.4.1" + }, + "dependencies": { + "acorn": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.0.tgz", + "integrity": "sha512-gac8OEcQ2Li1dxIEWGZzsp2BitJxwkwcOm0zHAJLcPJaVvm58FRnk6RkuLRpU1EujipU2ZFODv2P9DLMfnV8mw==" + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + } + } } }, "webpack-chain": { "version": "4.12.1", "resolved": "https://registry.npmjs.org/webpack-chain/-/webpack-chain-4.12.1.tgz", "integrity": "sha512-BCfKo2YkDe2ByqkEWe1Rw+zko4LsyS75LVr29C6xIrxAg9JHJ4pl8kaIZ396SUSNp6b4815dRZPSTAS8LlURRQ==", - "dev": true, "requires": { "deepmerge": "^1.5.2", "javascript-stringify": "^1.6.0" } }, "webpack-dev-middleware": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.0.tgz", - "integrity": "sha512-qvDesR1QZRIAZHOE3iQ4CXLZZSQ1lAUsSpnQmlB1PBfoN/xdRjmge3Dok0W4IdaVLJOGJy3sGI4sZHwjRU0PCA==", - "dev": true, + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.2.tgz", + "integrity": "sha512-1xC42LxbYoqLNAhV6YzTYacicgMZQTqRd27Sim9wn5hJrX3I5nxYy1SxSd4+gjUFsz1dQFj+yEe6zEVmSkeJjw==", "requires": { "memory-fs": "^0.4.1", - "mime": "^2.4.2", + "mime": "^2.4.4", + "mkdirp": "^0.5.1", "range-parser": "^1.2.1", "webpack-log": "^2.0.0" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + } + } } }, "webpack-dev-server": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.7.2.tgz", - "integrity": "sha512-mjWtrKJW2T9SsjJ4/dxDC2fkFVUw8jlpemDERqV0ZJIkjjjamR2AbQlr3oz+j4JLhYCHImHnXZK5H06P2wvUew==", - "dev": true, + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.9.0.tgz", + "integrity": "sha512-E6uQ4kRrTX9URN9s/lIbqTAztwEPdvzVrcmHE8EQ9YnuT9J8Es5Wrd8n9BKg1a0oZ5EgEke/EQFgUsp18dSTBw==", "requires": { "ansi-html": "0.0.7", "bonjour": "^3.5.0", - "chokidar": "^2.1.6", + "chokidar": "^2.1.8", "compression": "^1.7.4", "connect-history-api-fallback": "^1.6.0", "debug": "^4.1.1", "del": "^4.1.1", "express": "^4.17.1", "html-entities": "^1.2.1", - "http-proxy-middleware": "^0.19.1", + "http-proxy-middleware": "0.19.1", "import-local": "^2.0.0", "internal-ip": "^4.3.0", "ip": "^1.1.5", + "is-absolute-url": "^3.0.3", "killable": "^1.0.1", - "loglevel": "^1.6.3", + "loglevel": "^1.6.4", "opn": "^5.5.0", "p-retry": "^3.0.1", - "portfinder": "^1.0.20", + "portfinder": "^1.0.25", "schema-utils": "^1.0.0", - "selfsigned": "^1.10.4", - "semver": "^6.1.1", + "selfsigned": "^1.10.7", + "semver": "^6.3.0", "serve-index": "^1.9.1", "sockjs": "0.3.19", - "sockjs-client": "1.3.0", - "spdy": "^4.0.0", + "sockjs-client": "1.4.0", + "spdy": "^4.0.1", "strip-ansi": "^3.0.1", "supports-color": "^6.1.0", "url": "^0.11.0", - "webpack-dev-middleware": "^3.7.0", + "webpack-dev-middleware": "^3.7.2", "webpack-log": "^2.0.0", + "ws": "^6.2.1", "yargs": "12.0.5" }, "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + }, + "cliui": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "requires": { + "locate-path": "^3.0.0" + } + }, + "is-absolute-url": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.3.tgz", + "integrity": "sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==" + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "p-limit": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", + "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + }, "semver": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.1.2.tgz", - "integrity": "sha512-z4PqiCpomGtWj8633oeAdXm1Kn1W++3T8epkZYnwiVgIYIJ0QHszhInYSJTYxebByQH7KVCEAn8R9duzZW2PhQ==", - "dev": true + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" }, "supports-color": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, "requires": { "has-flag": "^3.0.0" } + }, + "yargs": { + "version": "12.0.5", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", + "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", + "requires": { + "cliui": "^4.0.0", + "decamelize": "^1.2.0", + "find-up": "^3.0.0", + "get-caller-file": "^1.0.1", + "os-locale": "^3.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1 || ^4.0.0", + "yargs-parser": "^11.1.1" + } } } }, @@ -9611,44 +9461,32 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz", "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==", - "dev": true, "requires": { "ansi-colors": "^3.0.0", "uuid": "^3.3.2" } }, "webpack-merge": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.1.tgz", - "integrity": "sha512-4p8WQyS98bUJcCvFMbdGZyZmsKuWjWVnVHnAS3FFg0HDaRVrPbkivx2RYCre8UiemD67RsiFFLfn4JhLAin8Vw==", - "dev": true, + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.2.tgz", + "integrity": "sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g==", "requires": { - "lodash": "^4.17.5" + "lodash": "^4.17.15" } }, "webpack-sources": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.3.0.tgz", - "integrity": "sha512-OiVgSrbGu7NEnEvQJJgdSFPl2qWKkWq5lHMhgiToIiN9w34EBnjYzSYs+VbL5KoYiLNtFFa7BZIKxRED3I32pA==", - "dev": true, + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", "requires": { "source-list-map": "^2.0.0", "source-map": "~0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } } }, "webpackbar": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/webpackbar/-/webpackbar-3.2.0.tgz", "integrity": "sha512-PC4o+1c8gWWileUfwabe0gqptlXUDJd5E0zbpr2xHP1VSOVlZVPBZ8j6NCR8zM5zbKdxPhctHXahgpNK1qFDPw==", - "dev": true, "requires": { "ansi-escapes": "^4.1.0", "chalk": "^2.4.1", @@ -9663,14 +9501,12 @@ "ansi-regex": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, "requires": { "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", @@ -9681,7 +9517,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, "requires": { "ansi-regex": "^4.1.0" } @@ -9690,7 +9525,6 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "dev": true, "requires": { "ansi-styles": "^3.2.0", "string-width": "^3.0.0", @@ -9703,7 +9537,6 @@ "version": "0.7.3", "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.3.tgz", "integrity": "sha512-bpxWlvbbB459Mlipc5GBzzZwhoZgGEZLuqPaR0INBGnPAY1vdBX6hPnoFXiw+3yWxDuHyQjO2oXTMyS8A5haFg==", - "dev": true, "requires": { "http-parser-js": ">=0.4.0 <0.4.11", "safe-buffer": ">=5.1.0", @@ -9713,20 +9546,27 @@ "websocket-extensions": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz", - "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==", - "dev": true + "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==" + }, + "whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } }, "when": { "version": "3.6.4", "resolved": "https://registry.npmjs.org/when/-/when-3.6.4.tgz", - "integrity": "sha1-RztRfsFZ4rhQBUl6E5g/CVQS404=", - "dev": true + "integrity": "sha1-RztRfsFZ4rhQBUl6E5g/CVQS404=" }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, "requires": { "isexe": "^2.0.0" } @@ -9734,14 +9574,31 @@ "which-module": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + }, + "window-size": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=" + }, + "with": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/with/-/with-5.1.1.tgz", + "integrity": "sha1-+k2qktrzLE6pTtRTyB8EaGtXXf4=", + "requires": { + "acorn": "^3.1.0", + "acorn-globals": "^3.0.0" + } + }, + "wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=" }, "worker-farm": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", - "dev": true, "requires": { "errno": "~0.1.7" } @@ -9750,7 +9607,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", - "dev": true, "requires": { "string-width": "^1.0.1", "strip-ansi": "^3.0.1" @@ -9760,7 +9616,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, "requires": { "number-is-nan": "^1.0.0" } @@ -9769,7 +9624,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -9781,107 +9635,67 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "ws": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", + "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", + "requires": { + "async-limiter": "~1.0.0" + } + }, + "xmlbuilder": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-13.0.2.tgz", + "integrity": "sha512-Eux0i2QdDYKbdbA6AM6xE4m6ZTZr4G4xF9kahI2ukSEMCzwce2eX9WlTI5J3s+NU7hpasFsr8hWIONae7LluAQ==" }, "xtend": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", - "dev": true + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" }, "y18n": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", - "dev": true + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" }, "yallist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", - "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", - "dev": true + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" }, "yargs": { - "version": "12.0.5", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", - "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", - "dev": true, - "requires": { - "cliui": "^4.0.0", - "decamelize": "^1.2.0", - "find-up": "^3.0.0", - "get-caller-file": "^1.0.1", - "os-locale": "^3.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1 || ^4.0.0", - "yargs-parser": "^11.1.1" - }, - "dependencies": { - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", - "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - } + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "requires": { + "camelcase": "^1.0.2", + "cliui": "^2.1.0", + "decamelize": "^1.0.0", + "window-size": "0.1.0" } }, "yargs-parser": { "version": "11.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", - "dev": true, "requires": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + } } }, "zepto": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/zepto/-/zepto-1.2.0.tgz", - "integrity": "sha1-4Se9nmb9hGvl6rSME5SIL3wOT5g=", - "dev": true + "integrity": "sha1-4Se9nmb9hGvl6rSME5SIL3wOT5g=" } } } diff --git a/docs/package.json b/docs/package.json index 0ad5ffc2bc54..a8d32367076f 100644 --- a/docs/package.json +++ b/docs/package.json @@ -4,19 +4,16 @@ "description": "## Get Started", "main": "index.js", "scripts": { - "serve": "vuepress dev", - "build": "vuepress build" + "preserve": "./pre.sh", + "serve": "trap 'exit 0' SIGINT; vuepress dev", + "postserve": "./post.sh", + "prebuild": "./pre.sh", + "build": "trap 'exit 0' SIGINT; vuepress build --no-cache", + "postbuild": "./post.sh" }, "author": "", "license": "ISC", - "devDependencies": { - "@vuepress/plugin-google-analytics": "^1.2.0", - "lodash": "^4.17.13", - "markdown-it": "^8.4.2", - "markdown-it-meta": "0.0.1", - "vuepress": "^1.0.2" - }, "dependencies": { - "axios": "^0.19.0" + "vuepress-theme-cosmos": "^1.0.93" } } diff --git a/docs/post.sh b/docs/post.sh new file mode 100755 index 000000000000..5d8c7ed48737 --- /dev/null +++ b/docs/post.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +rm -rf modules \ No newline at end of file diff --git a/docs/pre.sh b/docs/pre.sh new file mode 100755 index 000000000000..a71ac0b65d5e --- /dev/null +++ b/docs/pre.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +mkdir -p modules + +for D in ../x/*; do + if [ -d "${D}" ]; then + rm -rf "modules/$(echo $D | awk -F/ '{print $NF}')" + mkdir -p "modules/$(echo $D | awk -F/ '{print $NF}')" && cp -r $D/spec/* "$_" + fi +done + +cp ../x/README.md modules/ \ No newline at end of file diff --git a/docs/ru/readme.md b/docs/ru/readme.md index 6f9cc8f33199..c8872c30fa41 100644 --- a/docs/ru/readme.md +++ b/docs/ru/readme.md @@ -1 +1,6 @@ -# RU \ No newline at end of file +--- +parent: + order: false +--- + +# RU diff --git a/docs/spec/README.md b/docs/spec/README.md index f287a9601e3f..2dd2321be23c 100644 --- a/docs/spec/README.md +++ b/docs/spec/README.md @@ -1,3 +1,8 @@ +--- +parent: + order: false +--- + # Specifications This directory contains specifications for the modules of the Cosmos SDK as well as Interchain Standards (ICS) and other specifications. @@ -13,17 +18,9 @@ block. ## Modules specifications -- [Auth](../../x/auth/spec) - The structure and authentication of accounts and transactions. -- [Bank](../../x/bank/spec) - Sending tokens. -- [Governance](../../x/gov/spec) - Proposals and voting. -- [Staking](../../x/staking/spec) - Proof-of-stake bonding, delegation, etc. -- [Slashing](../../x/slashing/spec) - Validator punishment mechanisms. -- [Distribution](../../x/distribution/spec) - Fee distribution, and staking token provision distribution. -- [Crisis](.../../x/crisis/spec) - Halting the blockchain under certain circumstances. -- [Mint](../../x/mint/spec) - Staking token provision creation. -- [Params](../../x/params/spec) - Globally available parameter store. -- [Supply](../../x/supply/spec) - Total supply of the chain. -- [NFT](https://github.com/cosmos/modules/tree/master/incubator/nft/docs/spec) - Non-fungible tokens. +Go the [module directory](../../x/README.md) + +## Tendermint For details on the underlying blockchain and p2p protocols, see the [Tendermint specification](https://github.com/tendermint/tendermint/tree/master/docs/spec). diff --git a/docs/using-the-sdk/README.md b/docs/using-the-sdk/README.md new file mode 100644 index 000000000000..ef0f84c16fb2 --- /dev/null +++ b/docs/using-the-sdk/README.md @@ -0,0 +1,10 @@ +--- +parent: + order: false +--- + +# Using the SDK + +- [Modules](../../x/README.md) +- [Simulation](./simulation.md) + diff --git a/docs/concepts/using-the-sdk/simulation.md b/docs/using-the-sdk/simulation.md similarity index 100% rename from docs/concepts/using-the-sdk/simulation.md rename to docs/using-the-sdk/simulation.md diff --git a/x/README.md b/x/README.md new file mode 100644 index 000000000000..a38c7ab3dd31 --- /dev/null +++ b/x/README.md @@ -0,0 +1,22 @@ +--- +parent: + order: false +--- + +# List of Modules + +Here are some production-grade modules that can be used in Cosmos SDK applications, along with their respective documentation: + +- [Auth](./x/auth/spec/README.md) - Authentication of accounts and transactions for Cosmos SDK application. +- [Bank](./x/bank/spec/README.md) - Token transfer functionalities. +- [Governance](./x/gov/spec/README.md) - On-chain proposals and voting. +- [Staking](./x/staking/spec/README.md) - Proof-of-stake layer for public blockchains. +- [Slashing](.x/slashing/spec/README.md) - Validator punishment mechanisms. +- [Distribution](.x/distribution/spec/README.md) - Fee distribution, and staking token provision distribution. +- [Crisis](./x/crisis/spec/README.md) - Halting the blockchain under certain circumstances (e.g. if an invariant is broken). +- [Mint](./x/mint/spec/README.md) - Creation of new units of staking token. +- [Params](./x/params/spec/README.md) - Globally available parameter store. +- [Supply](./x/supply/spec/README.md) - Total token supply of the chain. + +To learn more about the process of building modules, visit the [building modules reference documentation](../docs/building-modules/README.md). + diff --git a/x/auth/spec/README.md b/x/auth/spec/README.md index 1e57a39c095e..8dd0a2dd2209 100644 --- a/x/auth/spec/README.md +++ b/x/auth/spec/README.md @@ -1,4 +1,4 @@ -# Auth module specification +# `auth` ## Abstract diff --git a/x/bank/spec/README.md b/x/bank/spec/README.md index f4c583af98b6..1f5ad958a915 100644 --- a/x/bank/spec/README.md +++ b/x/bank/spec/README.md @@ -1,4 +1,4 @@ -# Bank module specification +# `bank` ## Abstract diff --git a/x/crisis/spec/README.md b/x/crisis/spec/README.md index 6fae6fe52e0f..48847155135a 100644 --- a/x/crisis/spec/README.md +++ b/x/crisis/spec/README.md @@ -1,4 +1,4 @@ -# Crisis +# `crisis` ## Overview diff --git a/x/distribution/spec/README.md b/x/distribution/spec/README.md index cf306c4e45e5..7540bcd8997f 100644 --- a/x/distribution/spec/README.md +++ b/x/distribution/spec/README.md @@ -1,4 +1,4 @@ -# Distribution +# `distribution` ## Overview diff --git a/x/gov/spec/README.md b/x/gov/spec/README.md index 5f9ebc31ca35..8276fa72ba2a 100644 --- a/x/gov/spec/README.md +++ b/x/gov/spec/README.md @@ -1,4 +1,4 @@ -# Governance module specification +# `gov` ## Abstract diff --git a/x/mint/spec/README.md b/x/mint/spec/README.md index b7e0ef9e065d..b4d9a1ddc86b 100644 --- a/x/mint/spec/README.md +++ b/x/mint/spec/README.md @@ -1,4 +1,4 @@ -# Mint Specification +# `mint` ## Contents diff --git a/x/params/spec/README.md b/x/params/spec/README.md index a7728e8680e8..503e6b51d24d 100644 --- a/x/params/spec/README.md +++ b/x/params/spec/README.md @@ -1,4 +1,4 @@ -# Params module specification +# `params` ## Abstract diff --git a/x/slashing/spec/README.md b/x/slashing/spec/README.md index 0f0111433c31..c70dc220f16d 100644 --- a/x/slashing/spec/README.md +++ b/x/slashing/spec/README.md @@ -1,4 +1,4 @@ -# Slashing module specification +# `slashing` ## Abstract diff --git a/x/staking/spec/README.md b/x/staking/spec/README.md index a34274b7a112..9e4a9a99e677 100644 --- a/x/staking/spec/README.md +++ b/x/staking/spec/README.md @@ -1,4 +1,4 @@ -# Staking module specification +# `staking` ## Abstract diff --git a/x/supply/spec/README.md b/x/supply/spec/README.md index e637bc013187..d9ef2b1075d9 100644 --- a/x/supply/spec/README.md +++ b/x/supply/spec/README.md @@ -1,4 +1,4 @@ -# Supply Specification +# `supply` ## Contents From 9f03b57fe3ce223d6233a47e555536e671be27c9 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Tue, 10 Dec 2019 11:48:57 -0500 Subject: [PATCH 018/529] Merge PR #5359: Params Validation --- types/coin.go | 12 +- types/dec_coin.go | 4 +- types/denom.go | 6 +- x/auth/ante/ante_test.go | 3 +- x/auth/simulation/genesis.go | 2 +- x/auth/simulation/params.go | 6 +- x/auth/types/params.go | 97 +++++++++++-- x/bank/internal/types/params.go | 13 +- x/bank/simulation/params.go | 2 +- x/crisis/internal/types/params.go | 17 ++- x/distribution/keeper/params.go | 67 ++++++++- x/distribution/simulation/params.go | 6 +- x/evidence/internal/types/params.go | 16 ++- x/gov/simulation/params.go | 6 +- x/gov/types/params.go | 63 ++++++++- x/mint/alias.go | 1 - x/mint/internal/types/genesis.go | 3 +- x/mint/internal/types/params.go | 144 +++++++++++++++++--- x/mint/simulation/params.go | 8 +- x/params/alias.go | 6 +- x/params/client/utils/utils.go | 7 +- x/params/client/utils/utils_test.go | 9 +- x/params/doc.go | 137 +++++++++---------- x/params/keeper.go | 6 +- x/params/keeper_test.go | 46 ++++--- x/params/proposal_handler.go | 20 +-- x/params/proposal_handler_test.go | 6 +- x/params/simulation/operations.go | 2 +- x/params/subspace/common_test.go | 72 ++++++++++ x/params/subspace/doc.go | 21 ++- x/params/subspace/paramset.go | 22 +-- x/params/subspace/subspace.go | 195 +++++++++++--------------- x/params/subspace/subspace_test.go | 203 ++++++++++++++++++++++++++++ x/params/subspace/table.go | 61 ++++----- x/params/subspace/table_test.go | 62 +++++---- x/params/subspace/test_common.go | 40 ------ x/params/types/errors.go | 4 +- x/params/types/proposal.go | 13 +- x/params/types/proposal_test.go | 10 +- x/simulation/params.go | 6 +- x/slashing/handler_test.go | 1 - x/slashing/internal/types/params.go | 84 +++++++++++- x/slashing/simulation/params.go | 6 +- x/staking/handler_test.go | 49 +++---- x/staking/simulation/params.go | 4 +- x/staking/types/params.go | 83 ++++++++++-- 46 files changed, 1141 insertions(+), 510 deletions(-) create mode 100644 x/params/subspace/common_test.go create mode 100644 x/params/subspace/subspace_test.go delete mode 100644 x/params/subspace/test_common.go diff --git a/types/coin.go b/types/coin.go index c64ba0dca500..94b9dc901c77 100644 --- a/types/coin.go +++ b/types/coin.go @@ -52,7 +52,7 @@ func (coin Coin) String() string { // validate returns an error if the Coin has a negative amount or if // the denom is invalid. func validate(denom string, amount Int) error { - if err := validateDenom(denom); err != nil { + if err := ValidateDenom(denom); err != nil { return err } @@ -203,7 +203,7 @@ func (coins Coins) IsValid() bool { case 0: return true case 1: - if err := validateDenom(coins[0].Denom); err != nil { + if err := ValidateDenom(coins[0].Denom); err != nil { return false } return coins[0].IsPositive() @@ -599,7 +599,9 @@ var ( reDecCoin = regexp.MustCompile(fmt.Sprintf(`^(%s)%s(%s)$`, reDecAmt, reSpc, reDnmString)) ) -func validateDenom(denom string) error { +// ValidateDenom validates a denomination string returning an error if it is +// invalid. +func ValidateDenom(denom string) error { if !reDnm.MatchString(denom) { return fmt.Errorf("invalid denom: %s", denom) } @@ -607,7 +609,7 @@ func validateDenom(denom string) error { } func mustValidateDenom(denom string) { - if err := validateDenom(denom); err != nil { + if err := ValidateDenom(denom); err != nil { panic(err) } } @@ -629,7 +631,7 @@ func ParseCoin(coinStr string) (coin Coin, err error) { return Coin{}, fmt.Errorf("failed to parse coin amount: %s", amountStr) } - if err := validateDenom(denomStr); err != nil { + if err := ValidateDenom(denomStr); err != nil { return Coin{}, fmt.Errorf("invalid denom cannot contain upper case characters or spaces: %s", err) } diff --git a/types/dec_coin.go b/types/dec_coin.go index ca50468383c0..0c11d3135341 100644 --- a/types/dec_coin.go +++ b/types/dec_coin.go @@ -470,7 +470,7 @@ func (coins DecCoins) IsValid() bool { return true case 1: - if err := validateDenom(coins[0].Denom); err != nil { + if err := ValidateDenom(coins[0].Denom); err != nil { return false } return coins[0].IsPositive() @@ -570,7 +570,7 @@ func ParseDecCoin(coinStr string) (coin DecCoin, err error) { return DecCoin{}, errors.Wrap(err, fmt.Sprintf("failed to parse decimal coin amount: %s", amountStr)) } - if err := validateDenom(denomStr); err != nil { + if err := ValidateDenom(denomStr); err != nil { return DecCoin{}, fmt.Errorf("invalid denom cannot contain upper case characters or spaces: %s", err) } diff --git a/types/denom.go b/types/denom.go index 73d396644523..f79bef8b9459 100644 --- a/types/denom.go +++ b/types/denom.go @@ -11,7 +11,7 @@ var denomUnits = map[string]Dec{} // RegisterDenom registers a denomination with a corresponding unit. If the // denomination is already registered, an error will be returned. func RegisterDenom(denom string, unit Dec) error { - if err := validateDenom(denom); err != nil { + if err := ValidateDenom(denom); err != nil { return err } @@ -26,7 +26,7 @@ func RegisterDenom(denom string, unit Dec) error { // GetDenomUnit returns a unit for a given denomination if it exists. A boolean // is returned if the denomination is registered. func GetDenomUnit(denom string) (Dec, bool) { - if err := validateDenom(denom); err != nil { + if err := ValidateDenom(denom); err != nil { return ZeroDec(), false } @@ -42,7 +42,7 @@ func GetDenomUnit(denom string) (Dec, bool) { // denomination is invalid or if neither denomination is registered, an error // is returned. func ConvertCoin(coin Coin, denom string) (Coin, error) { - if err := validateDenom(denom); err != nil { + if err := ValidateDenom(denom); err != nil { return Coin{}, err } diff --git a/x/auth/ante/ante_test.go b/x/auth/ante/ante_test.go index b6803c174189..5ac42a6dc855 100644 --- a/x/auth/ante/ante_test.go +++ b/x/auth/ante/ante_test.go @@ -781,8 +781,7 @@ func TestAnteHandlerReCheck(t *testing.T) { name string params types.Params }{ - {"memo size check", types.NewParams(0, types.DefaultTxSigLimit, types.DefaultTxSizeCostPerByte, types.DefaultSigVerifyCostED25519, types.DefaultSigVerifyCostSecp256k1)}, - {"tx sig limit check", types.NewParams(types.DefaultMaxMemoCharacters, 0, types.DefaultTxSizeCostPerByte, types.DefaultSigVerifyCostED25519, types.DefaultSigVerifyCostSecp256k1)}, + {"memo size check", types.NewParams(1, types.DefaultTxSigLimit, types.DefaultTxSizeCostPerByte, types.DefaultSigVerifyCostED25519, types.DefaultSigVerifyCostSecp256k1)}, {"txsize check", types.NewParams(types.DefaultMaxMemoCharacters, types.DefaultTxSigLimit, 10000000, types.DefaultSigVerifyCostED25519, types.DefaultSigVerifyCostSecp256k1)}, {"sig verify cost check", types.NewParams(types.DefaultMaxMemoCharacters, types.DefaultTxSigLimit, types.DefaultTxSizeCostPerByte, types.DefaultSigVerifyCostED25519, 100000000)}, } diff --git a/x/auth/simulation/genesis.go b/x/auth/simulation/genesis.go index 61b248472312..808d81ac296f 100644 --- a/x/auth/simulation/genesis.go +++ b/x/auth/simulation/genesis.go @@ -81,7 +81,7 @@ func RandomizedGenState(simState *module.SimulationState) { var sigVerifyCostSECP256K1 uint64 simState.AppParams.GetOrGenerate( simState.Cdc, SigVerifyCostSECP256K1, &sigVerifyCostSECP256K1, simState.Rand, - func(r *rand.Rand) { sigVerifyCostED25519 = GenSigVerifyCostSECP256K1(r) }, + func(r *rand.Rand) { sigVerifyCostSECP256K1 = GenSigVerifyCostSECP256K1(r) }, ) params := types.NewParams(maxMemoChars, txSigLimit, txSizeCostPerByte, diff --git a/x/auth/simulation/params.go b/x/auth/simulation/params.go index 045124a4a4a3..afca0348d3a5 100644 --- a/x/auth/simulation/params.go +++ b/x/auth/simulation/params.go @@ -20,17 +20,17 @@ const ( // on the simulation func ParamChanges(r *rand.Rand) []simulation.ParamChange { return []simulation.ParamChange{ - simulation.NewSimParamChange(types.ModuleName, keyMaxMemoCharacters, "", + simulation.NewSimParamChange(types.ModuleName, keyMaxMemoCharacters, func(r *rand.Rand) string { return fmt.Sprintf("\"%d\"", GenMaxMemoChars(r)) }, ), - simulation.NewSimParamChange(types.ModuleName, keyTxSigLimit, "", + simulation.NewSimParamChange(types.ModuleName, keyTxSigLimit, func(r *rand.Rand) string { return fmt.Sprintf("\"%d\"", GenTxSigLimit(r)) }, ), - simulation.NewSimParamChange(types.ModuleName, keyTxSizeCostPerByte, "", + simulation.NewSimParamChange(types.ModuleName, keyTxSizeCostPerByte, func(r *rand.Rand) string { return fmt.Sprintf("\"%d\"", GenTxSizeCostPerByte(r)) }, diff --git a/x/auth/types/params.go b/x/auth/types/params.go index 288ed334341e..2f994ef7eecf 100644 --- a/x/auth/types/params.go +++ b/x/auth/types/params.go @@ -5,6 +5,7 @@ import ( "fmt" "strings" + "github.com/cosmos/cosmos-sdk/x/params" "github.com/cosmos/cosmos-sdk/x/params/subspace" ) @@ -63,11 +64,11 @@ func ParamKeyTable() subspace.KeyTable { // nolint func (p *Params) ParamSetPairs() subspace.ParamSetPairs { return subspace.ParamSetPairs{ - {KeyMaxMemoCharacters, &p.MaxMemoCharacters}, - {KeyTxSigLimit, &p.TxSigLimit}, - {KeyTxSizeCostPerByte, &p.TxSizeCostPerByte}, - {KeySigVerifyCostED25519, &p.SigVerifyCostED25519}, - {KeySigVerifyCostSecp256k1, &p.SigVerifyCostSecp256k1}, + params.NewParamSetPair(KeyMaxMemoCharacters, &p.MaxMemoCharacters, validateMaxMemoCharacters), + params.NewParamSetPair(KeyTxSigLimit, &p.TxSigLimit, validateTxSigLimit), + params.NewParamSetPair(KeyTxSizeCostPerByte, &p.TxSizeCostPerByte, validateTxSizeCostPerByte), + params.NewParamSetPair(KeySigVerifyCostED25519, &p.SigVerifyCostED25519, validateSigVerifyCostED25519), + params.NewParamSetPair(KeySigVerifyCostSecp256k1, &p.SigVerifyCostSecp256k1, validateSigVerifyCostSecp256k1), } } @@ -101,22 +102,88 @@ func (p Params) String() string { return sb.String() } +func validateTxSigLimit(i interface{}) error { + v, ok := i.(uint64) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v == 0 { + return fmt.Errorf("invalid tx signature limit: %d", v) + } + + return nil +} + +func validateSigVerifyCostED25519(i interface{}) error { + v, ok := i.(uint64) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v == 0 { + return fmt.Errorf("invalid ED25519 signature verification cost: %d", v) + } + + return nil +} + +func validateSigVerifyCostSecp256k1(i interface{}) error { + v, ok := i.(uint64) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v == 0 { + return fmt.Errorf("invalid SECK256k1 signature verification cost: %d", v) + } + + return nil +} + +func validateMaxMemoCharacters(i interface{}) error { + v, ok := i.(uint64) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v == 0 { + return fmt.Errorf("invalid max memo characters: %d", v) + } + + return nil +} + +func validateTxSizeCostPerByte(i interface{}) error { + v, ok := i.(uint64) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v == 0 { + return fmt.Errorf("invalid tx size cost per byte: %d", v) + } + + return nil +} + // Validate checks that the parameters have valid values. func (p Params) Validate() error { - if p.TxSigLimit == 0 { - return fmt.Errorf("invalid tx signature limit: %d", p.TxSigLimit) + if err := validateTxSigLimit(p.TxSigLimit); err != nil { + return err } - if p.SigVerifyCostED25519 == 0 { - return fmt.Errorf("invalid ED25519 signature verification cost: %d", p.SigVerifyCostED25519) + if err := validateSigVerifyCostED25519(p.SigVerifyCostED25519); err != nil { + return err } - if p.SigVerifyCostSecp256k1 == 0 { - return fmt.Errorf("invalid SECK256k1 signature verification cost: %d", p.SigVerifyCostSecp256k1) + if err := validateSigVerifyCostSecp256k1(p.SigVerifyCostSecp256k1); err != nil { + return err } - if p.MaxMemoCharacters == 0 { - return fmt.Errorf("invalid max memo characters: %d", p.MaxMemoCharacters) + if err := validateSigVerifyCostSecp256k1(p.MaxMemoCharacters); err != nil { + return err } - if p.TxSizeCostPerByte == 0 { - return fmt.Errorf("invalid tx size cost per byte: %d", p.TxSizeCostPerByte) + if err := validateTxSizeCostPerByte(p.TxSizeCostPerByte); err != nil { + return err } + return nil } diff --git a/x/bank/internal/types/params.go b/x/bank/internal/types/params.go index d232a975f0cb..cdd6aff84f81 100644 --- a/x/bank/internal/types/params.go +++ b/x/bank/internal/types/params.go @@ -1,6 +1,8 @@ package types import ( + "fmt" + "github.com/cosmos/cosmos-sdk/x/params" ) @@ -17,6 +19,15 @@ var ParamStoreKeySendEnabled = []byte("sendenabled") // ParamKeyTable type declaration for parameters func ParamKeyTable() params.KeyTable { return params.NewKeyTable( - ParamStoreKeySendEnabled, false, + params.NewParamSetPair(ParamStoreKeySendEnabled, false, validateSendEnabled), ) } + +func validateSendEnabled(i interface{}) error { + _, ok := i.(bool) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + return nil +} diff --git a/x/bank/simulation/params.go b/x/bank/simulation/params.go index f0dfec04b0b2..f5aa25bf6a0c 100644 --- a/x/bank/simulation/params.go +++ b/x/bank/simulation/params.go @@ -16,7 +16,7 @@ const keySendEnabled = "sendenabled" // on the simulation func ParamChanges(r *rand.Rand) []simulation.ParamChange { return []simulation.ParamChange{ - simulation.NewSimParamChange(types.ModuleName, keySendEnabled, "", + simulation.NewSimParamChange(types.ModuleName, keySendEnabled, func(r *rand.Rand) string { return fmt.Sprintf("%v", GenSendEnabled(r)) }, diff --git a/x/crisis/internal/types/params.go b/x/crisis/internal/types/params.go index a0dbdf726783..5749c9192e34 100644 --- a/x/crisis/internal/types/params.go +++ b/x/crisis/internal/types/params.go @@ -1,6 +1,8 @@ package types import ( + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/params" ) @@ -18,6 +20,19 @@ var ( // type declaration for parameters func ParamKeyTable() params.KeyTable { return params.NewKeyTable( - ParamStoreKeyConstantFee, sdk.Coin{}, + params.NewParamSetPair(ParamStoreKeyConstantFee, sdk.Coin{}, validateConstantFee), ) } + +func validateConstantFee(i interface{}) error { + v, ok := i.(sdk.Coin) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if !v.IsValid() { + return fmt.Errorf("invalid constant fee: %s", v) + } + + return nil +} diff --git a/x/distribution/keeper/params.go b/x/distribution/keeper/params.go index b95a6efb27c9..764dfdc21731 100644 --- a/x/distribution/keeper/params.go +++ b/x/distribution/keeper/params.go @@ -1,6 +1,8 @@ package keeper import ( + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/params" ) @@ -8,13 +10,70 @@ import ( // type declaration for parameters func ParamKeyTable() params.KeyTable { return params.NewKeyTable( - ParamStoreKeyCommunityTax, sdk.Dec{}, - ParamStoreKeyBaseProposerReward, sdk.Dec{}, - ParamStoreKeyBonusProposerReward, sdk.Dec{}, - ParamStoreKeyWithdrawAddrEnabled, false, + params.NewParamSetPair(ParamStoreKeyCommunityTax, sdk.Dec{}, validateCommunityTax), + params.NewParamSetPair(ParamStoreKeyBaseProposerReward, sdk.Dec{}, validateBaseProposerReward), + params.NewParamSetPair(ParamStoreKeyBonusProposerReward, sdk.Dec{}, validateBonusProposerReward), + params.NewParamSetPair(ParamStoreKeyWithdrawAddrEnabled, false, validateWithdrawAddrEnabled), ) } +func validateCommunityTax(i interface{}) error { + v, ok := i.(sdk.Dec) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v.IsNegative() { + return fmt.Errorf("community tax must be positive: %s", v) + } + if v.GT(sdk.OneDec()) { + return fmt.Errorf("community tax too large: %s", v) + } + + return nil +} + +func validateBaseProposerReward(i interface{}) error { + v, ok := i.(sdk.Dec) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v.IsNegative() { + return fmt.Errorf("base proposer reward must be positive: %s", v) + } + if v.GT(sdk.OneDec()) { + return fmt.Errorf("base proposer reward too large: %s", v) + } + + return nil +} + +func validateBonusProposerReward(i interface{}) error { + v, ok := i.(sdk.Dec) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v.IsNegative() { + return fmt.Errorf("bonus proposer reward must be positive: %s", v) + } + if v.GT(sdk.OneDec()) { + return fmt.Errorf("bonus proposer reward too large: %s", v) + } + + return nil +} + +func validateWithdrawAddrEnabled(i interface{}) error { + _, ok := i.(bool) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + return nil +} + // returns the current CommunityTax rate from the global param store // nolint: errcheck func (k Keeper) GetCommunityTax(ctx sdk.Context) sdk.Dec { diff --git a/x/distribution/simulation/params.go b/x/distribution/simulation/params.go index 710243e6d033..60c591a6dc3b 100644 --- a/x/distribution/simulation/params.go +++ b/x/distribution/simulation/params.go @@ -20,17 +20,17 @@ const ( // on the simulation func ParamChanges(r *rand.Rand) []simulation.ParamChange { return []simulation.ParamChange{ - simulation.NewSimParamChange(types.ModuleName, keyCommunityTax, "", + simulation.NewSimParamChange(types.ModuleName, keyCommunityTax, func(r *rand.Rand) string { return fmt.Sprintf("\"%s\"", GenCommunityTax(r)) }, ), - simulation.NewSimParamChange(types.ModuleName, keyBaseProposerReward, "", + simulation.NewSimParamChange(types.ModuleName, keyBaseProposerReward, func(r *rand.Rand) string { return fmt.Sprintf("\"%s\"", GenBaseProposerReward(r)) }, ), - simulation.NewSimParamChange(types.ModuleName, keyBonusProposerReward, "", + simulation.NewSimParamChange(types.ModuleName, keyBonusProposerReward, func(r *rand.Rand) string { return fmt.Sprintf("\"%s\"", GenBonusProposerReward(r)) }, diff --git a/x/evidence/internal/types/params.go b/x/evidence/internal/types/params.go index 5684786b73f7..6865eb2825ab 100644 --- a/x/evidence/internal/types/params.go +++ b/x/evidence/internal/types/params.go @@ -1,6 +1,7 @@ package types import ( + "fmt" "time" "github.com/cosmos/cosmos-sdk/x/params" @@ -48,7 +49,7 @@ func (p Params) String() string { // ParamSetPairs returns the parameter set pairs. func (p *Params) ParamSetPairs() params.ParamSetPairs { return params.ParamSetPairs{ - params.NewParamSetPair(KeyMaxEvidenceAge, &p.MaxEvidenceAge), + params.NewParamSetPair(KeyMaxEvidenceAge, &p.MaxEvidenceAge, validateMaxEvidenceAge), } } @@ -58,3 +59,16 @@ func DefaultParams() Params { MaxEvidenceAge: DefaultMaxEvidenceAge, } } + +func validateMaxEvidenceAge(i interface{}) error { + v, ok := i.(time.Duration) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v <= 0 { + return fmt.Errorf("max evidence age must be positive: %s", v) + } + + return nil +} diff --git a/x/gov/simulation/params.go b/x/gov/simulation/params.go index c43f3952e15f..420b5a8eec78 100644 --- a/x/gov/simulation/params.go +++ b/x/gov/simulation/params.go @@ -25,17 +25,17 @@ const ( // on the simulation func ParamChanges(r *rand.Rand) []simulation.ParamChange { return []simulation.ParamChange{ - simulation.NewSimParamChange(types.ModuleName, keyVotingParams, "", + simulation.NewSimParamChange(types.ModuleName, keyVotingParams, func(r *rand.Rand) string { return fmt.Sprintf(`{"voting_period": "%d"}`, GenVotingParamsVotingPeriod(r)) }, ), - simulation.NewSimParamChange(types.ModuleName, keyDepositParams, "", + simulation.NewSimParamChange(types.ModuleName, keyDepositParams, func(r *rand.Rand) string { return fmt.Sprintf(`{"max_deposit_period": "%d"}`, GenDepositParamsDepositPeriod(r)) }, ), - simulation.NewSimParamChange(types.ModuleName, keyTallyParams, "", + simulation.NewSimParamChange(types.ModuleName, keyTallyParams, func(r *rand.Rand) string { changes := []struct { key string diff --git a/x/gov/types/params.go b/x/gov/types/params.go index a7fe1da7b5b3..ff671d493169 100644 --- a/x/gov/types/params.go +++ b/x/gov/types/params.go @@ -31,9 +31,9 @@ var ( // ParamKeyTable - Key declaration for parameters func ParamKeyTable() params.KeyTable { return params.NewKeyTable( - ParamStoreKeyDepositParams, DepositParams{}, - ParamStoreKeyVotingParams, VotingParams{}, - ParamStoreKeyTallyParams, TallyParams{}, + params.NewParamSetPair(ParamStoreKeyDepositParams, DepositParams{}, validateDepositParams), + params.NewParamSetPair(ParamStoreKeyVotingParams, VotingParams{}, validateVotingParams), + params.NewParamSetPair(ParamStoreKeyTallyParams, TallyParams{}, validateTallyParams), ) } @@ -71,6 +71,22 @@ func (dp DepositParams) Equal(dp2 DepositParams) bool { return dp.MinDeposit.IsEqual(dp2.MinDeposit) && dp.MaxDepositPeriod == dp2.MaxDepositPeriod } +func validateDepositParams(i interface{}) error { + v, ok := i.(DepositParams) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if !v.MinDeposit.IsValid() { + return fmt.Errorf("invalid minimum deposit: %s", v.MinDeposit) + } + if v.MaxDepositPeriod <= 0 { + return fmt.Errorf("maximum deposit period must be positive: %d", v.MaxDepositPeriod) + } + + return nil +} + // TallyParams defines the params around Tallying votes in governance type TallyParams struct { Quorum sdk.Dec `json:"quorum,omitempty" yaml:"quorum,omitempty"` // Minimum percentage of total stake needed to vote for a result to be considered valid @@ -101,6 +117,34 @@ func (tp TallyParams) String() string { tp.Quorum, tp.Threshold, tp.Veto) } +func validateTallyParams(i interface{}) error { + v, ok := i.(TallyParams) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v.Quorum.IsNegative() { + return fmt.Errorf("quorom cannot be negative: %s", v.Quorum) + } + if v.Quorum.GT(sdk.OneDec()) { + return fmt.Errorf("quorom too large: %s", v) + } + if !v.Threshold.IsPositive() { + return fmt.Errorf("vote threshold must be positive: %s", v.Threshold) + } + if v.Threshold.GT(sdk.OneDec()) { + return fmt.Errorf("vote threshold too large: %s", v) + } + if !v.Veto.IsPositive() { + return fmt.Errorf("veto threshold must be positive: %s", v.Threshold) + } + if v.Veto.GT(sdk.OneDec()) { + return fmt.Errorf("veto threshold too large: %s", v) + } + + return nil +} + // VotingParams defines the params around Voting in governance type VotingParams struct { VotingPeriod time.Duration `json:"voting_period,omitempty" yaml:"voting_period,omitempty"` // Length of the voting period. @@ -124,6 +168,19 @@ func (vp VotingParams) String() string { Voting Period: %s`, vp.VotingPeriod) } +func validateVotingParams(i interface{}) error { + v, ok := i.(VotingParams) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v.VotingPeriod <= 0 { + return fmt.Errorf("voting period must be positive: %s", v.VotingPeriod) + } + + return nil +} + // Params returns all of the governance params type Params struct { VotingParams VotingParams `json:"voting_params" yaml:"voting_params"` diff --git a/x/mint/alias.go b/x/mint/alias.go index 4d31e826bcf0..9572d077b458 100644 --- a/x/mint/alias.go +++ b/x/mint/alias.go @@ -34,7 +34,6 @@ var ( ParamKeyTable = types.ParamKeyTable NewParams = types.NewParams DefaultParams = types.DefaultParams - ValidateParams = types.ValidateParams // variable aliases ModuleCdc = types.ModuleCdc diff --git a/x/mint/internal/types/genesis.go b/x/mint/internal/types/genesis.go index 43ee15f1e0d6..acb3a8efe80f 100644 --- a/x/mint/internal/types/genesis.go +++ b/x/mint/internal/types/genesis.go @@ -25,8 +25,7 @@ func DefaultGenesisState() GenesisState { // ValidateGenesis validates the provided genesis state to ensure the // expected invariants holds. func ValidateGenesis(data GenesisState) error { - err := ValidateParams(data.Params) - if err != nil { + if err := data.Params.Validate(); err != nil { return err } diff --git a/x/mint/internal/types/params.go b/x/mint/internal/types/params.go index 122f88bfef01..082c9ff22599 100644 --- a/x/mint/internal/types/params.go +++ b/x/mint/internal/types/params.go @@ -1,7 +1,9 @@ package types import ( + "errors" "fmt" + "strings" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/params" @@ -32,8 +34,9 @@ func ParamKeyTable() params.KeyTable { return params.NewKeyTable().RegisterParamSet(&Params{}) } -func NewParams(mintDenom string, inflationRateChange, inflationMax, - inflationMin, goalBonded sdk.Dec, blocksPerYear uint64) Params { +func NewParams( + mintDenom string, inflationRateChange, inflationMax, inflationMin, goalBonded sdk.Dec, blocksPerYear uint64, +) Params { return Params{ MintDenom: mintDenom, @@ -58,20 +61,34 @@ func DefaultParams() Params { } // validate params -func ValidateParams(params Params) error { - if params.GoalBonded.IsNegative() { - return fmt.Errorf("mint parameter GoalBonded should be positive, is %s ", params.GoalBonded.String()) +func (p Params) Validate() error { + if err := validateMintDenom(p.MintDenom); err != nil { + return err } - if params.GoalBonded.GT(sdk.OneDec()) { - return fmt.Errorf("mint parameter GoalBonded must be <= 1, is %s", params.GoalBonded.String()) + if err := validateInflationRateChange(p.InflationRateChange); err != nil { + return err } - if params.InflationMax.LT(params.InflationMin) { - return fmt.Errorf("mint parameter Max inflation must be greater than or equal to min inflation") + if err := validateInflationMax(p.InflationMax); err != nil { + return err } - if params.MintDenom == "" { - return fmt.Errorf("mint parameter MintDenom can't be an empty string") + if err := validateInflationMin(p.InflationMin); err != nil { + return err } + if err := validateGoalBonded(p.GoalBonded); err != nil { + return err + } + if err := validateBlocksPerYear(p.BlocksPerYear); err != nil { + return err + } + if p.InflationMax.LT(p.InflationMin) { + return fmt.Errorf( + "max inflation (%s) must be greater than or equal to min inflation (%s)", + p.InflationMax, p.InflationMin, + ) + } + return nil + } func (p Params) String() string { @@ -91,11 +108,104 @@ func (p Params) String() string { // Implements params.ParamSet func (p *Params) ParamSetPairs() params.ParamSetPairs { return params.ParamSetPairs{ - {Key: KeyMintDenom, Value: &p.MintDenom}, - {Key: KeyInflationRateChange, Value: &p.InflationRateChange}, - {Key: KeyInflationMax, Value: &p.InflationMax}, - {Key: KeyInflationMin, Value: &p.InflationMin}, - {Key: KeyGoalBonded, Value: &p.GoalBonded}, - {Key: KeyBlocksPerYear, Value: &p.BlocksPerYear}, + params.NewParamSetPair(KeyMintDenom, &p.MintDenom, validateMintDenom), + params.NewParamSetPair(KeyInflationRateChange, &p.InflationRateChange, validateInflationRateChange), + params.NewParamSetPair(KeyInflationMax, &p.InflationMax, validateInflationMax), + params.NewParamSetPair(KeyInflationMin, &p.InflationMin, validateInflationMin), + params.NewParamSetPair(KeyGoalBonded, &p.GoalBonded, validateGoalBonded), + params.NewParamSetPair(KeyBlocksPerYear, &p.BlocksPerYear, validateBlocksPerYear), + } +} + +func validateMintDenom(i interface{}) error { + v, ok := i.(string) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if strings.TrimSpace(v) == "" { + return errors.New("mint denom cannot be blank") + } + if err := sdk.ValidateDenom(v); err != nil { + return err + } + + return nil +} + +func validateInflationRateChange(i interface{}) error { + v, ok := i.(sdk.Dec) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v.IsNegative() { + return fmt.Errorf("inflation rate change cannot be negative: %s", v) + } + if v.GT(sdk.OneDec()) { + return fmt.Errorf("inflation rate change too large: %s", v) + } + + return nil +} + +func validateInflationMax(i interface{}) error { + v, ok := i.(sdk.Dec) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v.IsNegative() { + return fmt.Errorf("max inflation cannot be negative: %s", v) } + if v.GT(sdk.OneDec()) { + return fmt.Errorf("max inflation too large: %s", v) + } + + return nil +} + +func validateInflationMin(i interface{}) error { + v, ok := i.(sdk.Dec) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v.IsNegative() { + return fmt.Errorf("min inflation cannot be negative: %s", v) + } + if v.GT(sdk.OneDec()) { + return fmt.Errorf("min inflation too large: %s", v) + } + + return nil +} + +func validateGoalBonded(i interface{}) error { + v, ok := i.(sdk.Dec) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v.IsNegative() { + return fmt.Errorf("goal bonded cannot be negative: %s", v) + } + if v.GT(sdk.OneDec()) { + return fmt.Errorf("goal bonded too large: %s", v) + } + + return nil +} + +func validateBlocksPerYear(i interface{}) error { + v, ok := i.(uint64) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v == 0 { + return fmt.Errorf("blocks per year must be positive: %d", v) + } + + return nil } diff --git a/x/mint/simulation/params.go b/x/mint/simulation/params.go index 506b3bf45dc5..4f73183f058a 100644 --- a/x/mint/simulation/params.go +++ b/x/mint/simulation/params.go @@ -21,22 +21,22 @@ const ( // on the simulation func ParamChanges(r *rand.Rand) []simulation.ParamChange { return []simulation.ParamChange{ - simulation.NewSimParamChange(types.ModuleName, keyInflationRateChange, "", + simulation.NewSimParamChange(types.ModuleName, keyInflationRateChange, func(r *rand.Rand) string { return fmt.Sprintf("\"%s\"", GenInflationRateChange(r)) }, ), - simulation.NewSimParamChange(types.ModuleName, keyInflationMax, "", + simulation.NewSimParamChange(types.ModuleName, keyInflationMax, func(r *rand.Rand) string { return fmt.Sprintf("\"%s\"", GenInflationMax(r)) }, ), - simulation.NewSimParamChange(types.ModuleName, keyInflationMin, "", + simulation.NewSimParamChange(types.ModuleName, keyInflationMin, func(r *rand.Rand) string { return fmt.Sprintf("\"%s\"", GenInflationMin(r)) }, ), - simulation.NewSimParamChange(types.ModuleName, keyGoalBonded, "", + simulation.NewSimParamChange(types.ModuleName, keyGoalBonded, func(r *rand.Rand) string { return fmt.Sprintf("\"%s\"", GenGoalBonded(r)) }, diff --git a/x/params/alias.go b/x/params/alias.go index 47b89296de93..ace601c219dc 100644 --- a/x/params/alias.go +++ b/x/params/alias.go @@ -1,9 +1,10 @@ +package params + // nolint // autogenerated code using github.com/rigelrozanski/multitool // aliases generated for the following subdirectories: // ALIASGEN: github.com/cosmos/cosmos-sdk/x/params/subspace // ALIASGEN: github.com/cosmos/cosmos-sdk/x/params/types -package params import ( "github.com/cosmos/cosmos-sdk/x/params/subspace" @@ -13,7 +14,6 @@ import ( const ( StoreKey = subspace.StoreKey TStoreKey = subspace.TStoreKey - TestParamStore = subspace.TestParamStore DefaultCodespace = types.DefaultCodespace CodeUnknownSubspace = types.CodeUnknownSubspace CodeSettingParameter = types.CodeSettingParameter @@ -28,7 +28,6 @@ var ( NewParamSetPair = subspace.NewParamSetPair NewSubspace = subspace.NewSubspace NewKeyTable = subspace.NewKeyTable - DefaultTestComponents = subspace.DefaultTestComponents RegisterCodec = types.RegisterCodec ErrUnknownSubspace = types.ErrUnknownSubspace ErrSettingParameter = types.ErrSettingParameter @@ -38,7 +37,6 @@ var ( ErrEmptyValue = types.ErrEmptyValue NewParameterChangeProposal = types.NewParameterChangeProposal NewParamChange = types.NewParamChange - NewParamChangeWithSubkey = types.NewParamChangeWithSubkey ValidateChanges = types.ValidateChanges // variable aliases diff --git a/x/params/client/utils/utils.go b/x/params/client/utils/utils.go index 6bcbeb43a520..748d98502dc3 100644 --- a/x/params/client/utils/utils.go +++ b/x/params/client/utils/utils.go @@ -20,7 +20,6 @@ type ( ParamChangeJSON struct { Subspace string `json:"subspace" yaml:"subspace"` Key string `json:"key" yaml:"key"` - Subkey string `json:"subkey,omitempty" yaml:"subkey,omitempty"` Value json.RawMessage `json:"value" yaml:"value"` } @@ -45,13 +44,13 @@ type ( } ) -func NewParamChangeJSON(subspace, key, subkey string, value json.RawMessage) ParamChangeJSON { - return ParamChangeJSON{subspace, key, subkey, value} +func NewParamChangeJSON(subspace, key string, value json.RawMessage) ParamChangeJSON { + return ParamChangeJSON{subspace, key, value} } // ToParamChange converts a ParamChangeJSON object to ParamChange. func (pcj ParamChangeJSON) ToParamChange() params.ParamChange { - return params.NewParamChangeWithSubkey(pcj.Subspace, pcj.Key, pcj.Subkey, string(pcj.Value)) + return params.NewParamChange(pcj.Subspace, pcj.Key, string(pcj.Value)) } // ToParamChanges converts a slice of ParamChangeJSON objects to a slice of diff --git a/x/params/client/utils/utils_test.go b/x/params/client/utils/utils_test.go index 1953d11ffe74..c19857339b42 100644 --- a/x/params/client/utils/utils_test.go +++ b/x/params/client/utils/utils_test.go @@ -8,16 +8,15 @@ import ( ) func TestNewParamChangeJSON(t *testing.T) { - pcj := NewParamChangeJSON("subspace", "key", "subkey", json.RawMessage(`{}`)) + pcj := NewParamChangeJSON("subspace", "key", json.RawMessage(`{}`)) require.Equal(t, "subspace", pcj.Subspace) require.Equal(t, "key", pcj.Key) - require.Equal(t, "subkey", pcj.Subkey) require.Equal(t, json.RawMessage(`{}`), pcj.Value) } func TestToParamChanges(t *testing.T) { - pcj1 := NewParamChangeJSON("subspace", "key1", "", json.RawMessage(`{}`)) - pcj2 := NewParamChangeJSON("subspace", "key2", "", json.RawMessage(`{}`)) + pcj1 := NewParamChangeJSON("subspace", "key1", json.RawMessage(`{}`)) + pcj2 := NewParamChangeJSON("subspace", "key2", json.RawMessage(`{}`)) pcjs := ParamChangesJSON{pcj1, pcj2} paramChanges := pcjs.ToParamChanges() @@ -25,11 +24,9 @@ func TestToParamChanges(t *testing.T) { require.Equal(t, paramChanges[0].Subspace, pcj1.Subspace) require.Equal(t, paramChanges[0].Key, pcj1.Key) - require.Equal(t, paramChanges[0].Subkey, pcj1.Subkey) require.Equal(t, paramChanges[0].Value, string(pcj1.Value)) require.Equal(t, paramChanges[1].Subspace, pcj2.Subspace) require.Equal(t, paramChanges[1].Key, pcj2.Key) - require.Equal(t, paramChanges[1].Subkey, pcj2.Subkey) require.Equal(t, paramChanges[1].Value, string(pcj2.Value)) } diff --git a/x/params/doc.go b/x/params/doc.go index 1591507b465c..68ab4dee0e1f 100644 --- a/x/params/doc.go +++ b/x/params/doc.go @@ -1,11 +1,10 @@ -package params - /* -Package params provides a globally available parameter store. +Package params provides a namespaced module parameter store. -There are two main types, Keeper and Subspace. Subspace is an isolated namespace for a -paramstore, where keys are prefixed by preconfigured spacename. Keeper has a -permission to access all existing spaces. +There are two core components, Keeper and Subspace. Subspace is an isolated +namespace for a parameter store, where keys are prefixed by pre-configured +subspace names which modules provide. The Keeper has a permission to access all +existing subspaces. Subspace can be used by the individual keepers, who needs a private parameter store that the other keeper cannot modify. Keeper can be used by the Governance keeper, @@ -13,12 +12,10 @@ who need to modify any parameter in case of the proposal passes. Basic Usage: -First, declare parameter space and parameter keys for the module. Then include -params.Subspace in the keeper. Since we prefix the keys with the spacename, it is -recommended to use the same name with the module's. +1. Declare constant module parameter keys and the globally unique Subspace name: const ( - DefaultParamspace = "mymodule" + ModuleSubspace = "mymodule" ) const ( @@ -26,93 +23,89 @@ recommended to use the same name with the module's. KeyParameter2 = "myparameter2" ) - type Keeper struct { - cdc *codec.Codec - key sdk.StoreKey - - ps params.Subspace - } +2. Create a concrete parameter struct and define the validation functions: - func ParamKeyTable() params.KeyTable { - return params.NewKeyTable( - KeyParameter1, MyStruct{}, - KeyParameter2, MyStruct{}, - ) + type MyParams struct { + MyParam1 int64 `json:"my_param1" yaml:"my_param1"` + MyParam2 bool `json:"my_param2" yaml:"my_param2"` } - func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, ps params.Subspace) Keeper { - return Keeper { - cdc: cdc, - key: key, - ps: ps.WithKeyTable(ParamKeyTable()), + func validateMyParam1(i interface{}) error { + _, ok := i.(int64) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) } - } - -Pass a params.Subspace to NewKeeper with DefaultParamspace (or another) - app.myKeeper = mymodule.NewKeeper(app.paramStore.SubStore(mymodule.DefaultParamspace)) + // validate (if necessary)... -Now we can access to the paramstore using Paramstore Keys + return nil + } - var param MyStruct - k.ps.Get(ctx, KeyParameter1, ¶m) - k.ps.Set(ctx, KeyParameter2, param) + func validateMyParam2(i interface{}) error { + _, ok := i.(bool) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } -If you want to store an unknown number of parameters, or want to store a mapping, -you can use subkeys. Subkeys can be used with a main key, where the subkeys are -inheriting the key properties. + // validate (if necessary)... - func ParamKeyTable() params.KeyTable { - return params.NewKeyTable( - KeyParamMain, MyStruct{}, - ) + return nil } +3. Implement the params.ParamSet interface: - func (k Keeper) GetDynamicParameter(ctx sdk.Context, subkey []byte) (res MyStruct) { - k.ps.GetWithSubkey(ctx, KeyParamMain, subkey, &res) + func (p *MyParams) ParamSetPairs() params.ParamSetPairs { + return params.ParamSetPairs{ + {KeyParameter1, &p.MyParam1, validateMyParam1}, + {KeyParameter2, &p.MyParam2, validateMyParam2}, + } } -Genesis Usage: + func paramKeyTable() params.KeyTable { + return params.NewKeyTable().RegisterParamSet(&MyParams{}) + } -Declare a struct for parameters and make it implement params.ParamSet. It will then -be able to be passed to SetParamSet. +4. Have the module accept a Subspace in the constructor and set the KeyTable (if necessary): - type MyParams struct { - Parameter1 uint64 - Parameter2 string - } + func NewKeeper(..., paramSpace params.Subspace, ...) Keeper { + // set KeyTable if it has not already been set + if !paramSpace.HasKeyTable() { + paramSpace = paramSpace.WithKeyTable(paramKeyTable()) + } - // Implements params.ParamSet - // KeyValuePairs must return the list of (ParamKey, PointerToTheField) - func (p *MyParams) KeyValuePairs() params.KeyValuePairs { - return params.KeyFieldPairs { - {KeyParameter1, &p.Parameter1}, - {KeyParameter2, &p.Parameter2}, + return Keeper { + // ... + paramSpace: paramSpace, } } - func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) { - k.ps.SetParamSet(ctx, &data.params) - } +Now we have access to the module's parameters that are namespaced using the keys defined: -The method is pointer receiver because there could be a case that we read from -the store and set the result to the struct. + func InitGenesis(ctx sdk.Context, k Keeper, gs GenesisState) { + // ... + k.SetParams(ctx, gs.Params) + } -Master Keeper Usage: + func (k Keeper) SetParams(ctx sdk.Context, params Params) { + k.paramSpace.SetParamSet(ctx, ¶ms) + } -Keepers that require master permission to the paramstore, such as gov, can take -params.Keeper itself to access all subspace(using GetSubspace) + func (k Keeper) GetParams(ctx sdk.Context) (params Params) { + k.paramSpace.GetParamSet(ctx, ¶ms) + return params + } - type MasterKeeper struct { - pk params.Keeper + func (k Keeper) MyParam1(ctx sdk.Context) (res int64) { + k.paramSpace.Get(ctx, KeyParameter1, &res) + return res } - func (k MasterKeeper) SetParam(ctx sdk.Context, space string, key string, param interface{}) { - space, ok := k.pk.GetSubspace(space) - if !ok { - return - } - space.Set(ctx, key, param) + func (k Keeper) MyParam2(ctx sdk.Context) (res bool) { + k.paramSpace.Get(ctx, KeyParameter2, &res) + return res } + +NOTE: Any call to SetParamSet will panic or any call to Update will error if any +given parameter value is invalid based on the registered value validation function. */ +package params diff --git a/x/params/keeper.go b/x/params/keeper.go index d5fc3ea539bb..9e91259df656 100644 --- a/x/params/keeper.go +++ b/x/params/keeper.go @@ -21,16 +21,14 @@ type Keeper struct { } // NewKeeper constructs a params keeper -func NewKeeper(cdc *codec.Codec, key, tkey sdk.StoreKey, codespace sdk.CodespaceType) (k Keeper) { - k = Keeper{ +func NewKeeper(cdc *codec.Codec, key, tkey sdk.StoreKey, codespace sdk.CodespaceType) Keeper { + return Keeper{ cdc: cdc, key: key, tkey: tkey, codespace: codespace, spaces: make(map[string]*Subspace), } - - return k } // Logger returns a module-specific logger. diff --git a/x/params/keeper_test.go b/x/params/keeper_test.go index 7b94204a6207..3f2f1a4b2bf4 100644 --- a/x/params/keeper_test.go +++ b/x/params/keeper_test.go @@ -10,6 +10,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) +func validateNoOp(_ interface{}) error { return nil } + func TestKeeper(t *testing.T) { kvs := []struct { key string @@ -25,15 +27,15 @@ func TestKeeper(t *testing.T) { } table := NewKeyTable( - []byte("key1"), int64(0), - []byte("key2"), int64(0), - []byte("key3"), int64(0), - []byte("key4"), int64(0), - []byte("key5"), int64(0), - []byte("key6"), int64(0), - []byte("key7"), int64(0), - []byte("extra1"), bool(false), - []byte("extra2"), string(""), + NewParamSetPair([]byte("key1"), int64(0), validateNoOp), + NewParamSetPair([]byte("key2"), int64(0), validateNoOp), + NewParamSetPair([]byte("key3"), int64(0), validateNoOp), + NewParamSetPair([]byte("key4"), int64(0), validateNoOp), + NewParamSetPair([]byte("key5"), int64(0), validateNoOp), + NewParamSetPair([]byte("key6"), int64(0), validateNoOp), + NewParamSetPair([]byte("key7"), int64(0), validateNoOp), + NewParamSetPair([]byte("extra1"), bool(false), validateNoOp), + NewParamSetPair([]byte("extra2"), string(""), validateNoOp), ) cdc, ctx, skey, _, keeper := testComponents() @@ -135,18 +137,18 @@ func TestSubspace(t *testing.T) { } table := NewKeyTable( - []byte("string"), string(""), - []byte("bool"), bool(false), - []byte("int16"), int16(0), - []byte("int32"), int32(0), - []byte("int64"), int64(0), - []byte("uint16"), uint16(0), - []byte("uint32"), uint32(0), - []byte("uint64"), uint64(0), - []byte("int"), sdk.Int{}, - []byte("uint"), sdk.Uint{}, - []byte("dec"), sdk.Dec{}, - []byte("struct"), s{}, + NewParamSetPair([]byte("string"), string(""), validateNoOp), + NewParamSetPair([]byte("bool"), bool(false), validateNoOp), + NewParamSetPair([]byte("int16"), int16(0), validateNoOp), + NewParamSetPair([]byte("int32"), int32(0), validateNoOp), + NewParamSetPair([]byte("int64"), int64(0), validateNoOp), + NewParamSetPair([]byte("uint16"), uint16(0), validateNoOp), + NewParamSetPair([]byte("uint32"), uint32(0), validateNoOp), + NewParamSetPair([]byte("uint64"), uint64(0), validateNoOp), + NewParamSetPair([]byte("int"), sdk.Int{}, validateNoOp), + NewParamSetPair([]byte("uint"), sdk.Uint{}, validateNoOp), + NewParamSetPair([]byte("dec"), sdk.Dec{}, validateNoOp), + NewParamSetPair([]byte("struct"), s{}, validateNoOp), ) store := prefix.NewStore(ctx.KVStore(key), []byte("test/")) @@ -200,7 +202,7 @@ func TestJSONUpdate(t *testing.T) { key := []byte("key") - space := keeper.Subspace("test").WithKeyTable(NewKeyTable(key, paramJSON{})) + space := keeper.Subspace("test").WithKeyTable(NewKeyTable(NewParamSetPair(key, paramJSON{}, validateNoOp))) var param paramJSON diff --git a/x/params/proposal_handler.go b/x/params/proposal_handler.go index 97efd3e91226..e2e976454275 100644 --- a/x/params/proposal_handler.go +++ b/x/params/proposal_handler.go @@ -28,22 +28,12 @@ func handleParameterChangeProposal(ctx sdk.Context, k Keeper, p ParameterChangeP return ErrUnknownSubspace(k.codespace, c.Subspace) } - var err error - if len(c.Subkey) == 0 { - k.Logger(ctx).Info( - fmt.Sprintf("setting new parameter; key: %s, value: %s", c.Key, c.Value), - ) - - err = ss.Update(ctx, []byte(c.Key), []byte(c.Value)) - } else { - k.Logger(ctx).Info( - fmt.Sprintf("setting new parameter; key: %s, subkey: %s, value: %s", c.Key, c.Subspace, c.Value), - ) - err = ss.UpdateWithSubkey(ctx, []byte(c.Key), []byte(c.Subkey), []byte(c.Value)) - } + k.Logger(ctx).Info( + fmt.Sprintf("attempt to set new parameter value; key: %s, value: %s", c.Key, c.Value), + ) - if err != nil { - return ErrSettingParameter(k.codespace, c.Key, c.Subkey, c.Value, err.Error()) + if err := ss.Update(ctx, []byte(c.Key), []byte(c.Value)); err != nil { + return ErrSettingParameter(k.codespace, c.Key, c.Value, err.Error()) } } diff --git a/x/params/proposal_handler_test.go b/x/params/proposal_handler_test.go index 934211356d14..841f832160c5 100644 --- a/x/params/proposal_handler_test.go +++ b/x/params/proposal_handler_test.go @@ -17,6 +17,8 @@ import ( "github.com/cosmos/cosmos-sdk/x/params/types" ) +func validateNoOp(_ interface{}) error { return nil } + type testInput struct { ctx sdk.Context cdc *codec.Codec @@ -43,8 +45,8 @@ type testParams struct { func (tp *testParams) ParamSetPairs() subspace.ParamSetPairs { return subspace.ParamSetPairs{ - {Key: []byte(keyMaxValidators), Value: &tp.MaxValidators}, - {Key: []byte(keySlashingRate), Value: &tp.SlashingRate}, + params.NewParamSetPair([]byte(keyMaxValidators), &tp.MaxValidators, validateNoOp), + params.NewParamSetPair([]byte(keySlashingRate), &tp.SlashingRate, validateNoOp), } } diff --git a/x/params/simulation/operations.go b/x/params/simulation/operations.go index ab514e06fec0..c9415a68e1df 100644 --- a/x/params/simulation/operations.go +++ b/x/params/simulation/operations.go @@ -40,7 +40,7 @@ func SimulateParamChangeProposalContent(paramChangePool []simulation.ParamChange // add a new distinct parameter to the set of changes and register the key // to avoid further duplicates paramChangesKeys[spc.ComposedKey()] = struct{}{} - paramChanges[i] = types.NewParamChangeWithSubkey(spc.Subspace, spc.Key, spc.Subkey, spc.SimValue(r)) + paramChanges[i] = types.NewParamChange(spc.Subspace, spc.Key, spc.SimValue(r)) } return types.NewParameterChangeProposal( diff --git a/x/params/subspace/common_test.go b/x/params/subspace/common_test.go new file mode 100644 index 000000000000..69c41478dbcc --- /dev/null +++ b/x/params/subspace/common_test.go @@ -0,0 +1,72 @@ +package subspace_test + +import ( + "errors" + "fmt" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/params/subspace" +) + +var ( + keyUnbondingTime = []byte("UnbondingTime") + keyMaxValidators = []byte("MaxValidators") + keyBondDenom = []byte("BondDenom") + + key = sdk.NewKVStoreKey("storekey") + tkey = sdk.NewTransientStoreKey("transientstorekey") +) + +type params struct { + UnbondingTime time.Duration `json:"unbonding_time" yaml:"unbonding_time"` + MaxValidators uint16 `json:"max_validators" yaml:"max_validators"` + BondDenom string `json:"bond_denom" yaml:"bond_denom"` +} + +func validateUnbondingTime(i interface{}) error { + v, ok := i.(time.Duration) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v < (24 * time.Hour) { + return fmt.Errorf("unbonding time must be at least one day") + } + + return nil +} + +func validateMaxValidators(i interface{}) error { + _, ok := i.(uint16) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + return nil +} + +func validateBondDenom(i interface{}) error { + v, ok := i.(string) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if len(v) == 0 { + return errors.New("denom cannot be empty") + } + + return nil +} + +func (p *params) ParamSetPairs() subspace.ParamSetPairs { + return subspace.ParamSetPairs{ + {keyUnbondingTime, &p.UnbondingTime, validateUnbondingTime}, + {keyMaxValidators, &p.MaxValidators, validateMaxValidators}, + {keyBondDenom, &p.BondDenom, validateBondDenom}, + } +} + +func paramKeyTable() subspace.KeyTable { + return subspace.NewKeyTable().RegisterParamSet(¶ms{}) +} diff --git a/x/params/subspace/doc.go b/x/params/subspace/doc.go index 1ab87ac01958..0bde2ebe62d4 100644 --- a/x/params/subspace/doc.go +++ b/x/params/subspace/doc.go @@ -1,14 +1,13 @@ -package subspace - /* -To prevent namespace collision between consumer modules, we define type -"space". A Space can only be generated by the keeper, and the keeper checks -the existence of the space having the same name before generating the -space. +To prevent namespace collision between consumer modules, we define a type +Subspace. A Subspace can only be generated by the keeper, and the keeper checks +the existence of the Subspace having the same name before generating the +Subspace. -Consumer modules must take a space (via Keeper.Subspace), not the keeper -itself. This isolates each modules from the others and make them modify the -parameters safely. Keeper can be treated as master permission for all -subspaces (via Keeper.GetSubspace), so should be passed to proper modules -(ex. gov) +Consumer modules must take a Subspace (via Keeper.Subspace), not the keeper +itself. This isolates each modules from the others and make them modify their +respective parameters safely. Keeper can be treated as master permission for all +Subspaces (via Keeper.GetSubspace), so should be passed to proper modules +(ex. x/governance). */ +package subspace diff --git a/x/params/subspace/paramset.go b/x/params/subspace/paramset.go index 8f2206217b8e..195944d8c9c4 100644 --- a/x/params/subspace/paramset.go +++ b/x/params/subspace/paramset.go @@ -1,14 +1,20 @@ package subspace -// ParamSetPair is used for associating paramsubspace key and field of param structs -type ParamSetPair struct { - Key []byte - Value interface{} -} +type ( + ValueValidatorFn func(value interface{}) error + + // ParamSetPair is used for associating paramsubspace key and field of param + // structs. + ParamSetPair struct { + Key []byte + Value interface{} + ValidatorFn ValueValidatorFn + } +) -// NewParamSetPair creates a new ParamSetPair instance -func NewParamSetPair(key []byte, value interface{}) ParamSetPair { - return ParamSetPair{key, value} +// NewParamSetPair creates a new ParamSetPair instance. +func NewParamSetPair(key []byte, value interface{}, vfn ValueValidatorFn) ParamSetPair { + return ParamSetPair{key, value, vfn} } // ParamSetPairs Slice of KeyFieldPair diff --git a/x/params/subspace/subspace.go b/x/params/subspace/subspace.go index aee65842035b..94533f9451f1 100644 --- a/x/params/subspace/subspace.go +++ b/x/params/subspace/subspace.go @@ -22,28 +22,22 @@ const ( // Transient store persists for a block, so we use it for // recording whether the parameter has been changed or not type Subspace struct { - cdc *codec.Codec - key sdk.StoreKey // []byte -> []byte, stores parameter - tkey sdk.StoreKey // []byte -> bool, stores parameter change - - name []byte - + cdc *codec.Codec + key sdk.StoreKey // []byte -> []byte, stores parameter + tkey sdk.StoreKey // []byte -> bool, stores parameter change + name []byte table KeyTable } // NewSubspace constructs a store with namestore -func NewSubspace(cdc *codec.Codec, key sdk.StoreKey, tkey sdk.StoreKey, name string) (res Subspace) { - res = Subspace{ - cdc: cdc, - key: key, - tkey: tkey, - name: []byte(name), - table: KeyTable{ - m: make(map[string]attribute), - }, +func NewSubspace(cdc *codec.Codec, key sdk.StoreKey, tkey sdk.StoreKey, name string) Subspace { + return Subspace{ + cdc: cdc, + key: key, + tkey: tkey, + name: []byte(name), + table: NewKeyTable(), } - - return } // HasKeyTable returns if the Subspace has a KeyTable registered. @@ -64,7 +58,7 @@ func (s Subspace) WithKeyTable(table KeyTable) Subspace { s.table.m[k] = v } - // Allocate additional capicity for Subspace.name + // Allocate additional capacity for Subspace.name // So we don't have to allocate extra space each time appending to the key name := s.name s.name = make([]byte, len(name), len(name)+table.maxKeyLength()) @@ -87,105 +81,110 @@ func (s Subspace) transientStore(ctx sdk.Context) sdk.KVStore { return prefix.NewStore(ctx.TransientStore(s.tkey), append(s.name, '/')) } -func concatKeys(key, subkey []byte) (res []byte) { - res = make([]byte, len(key)+1+len(subkey)) - copy(res, key) - res[len(key)] = '/' - copy(res[len(key)+1:], subkey) - return +// Validate attempts to validate a parameter value by its key. If the key is not +// registered or if the validation of the value fails, an error is returned. +func (s Subspace) Validate(ctx sdk.Context, key []byte, value interface{}) error { + attr, ok := s.table.m[string(key)] + if !ok { + return fmt.Errorf("parameter %s not registered", string(key)) + } + + if err := attr.vfn(value); err != nil { + return fmt.Errorf("invalid parameter value: %s", err) + } + + return nil } -// Get parameter from store +// Get queries for a parameter by key from the Subspace's KVStore and sets the +// value to the provided pointer. If the value does not exist, it will panic. func (s Subspace) Get(ctx sdk.Context, key []byte, ptr interface{}) { store := s.kvStore(ctx) bz := store.Get(key) - err := s.cdc.UnmarshalJSON(bz, ptr) - if err != nil { + + if err := s.cdc.UnmarshalJSON(bz, ptr); err != nil { panic(err) } } -// GetIfExists do not modify ptr if the stored parameter is nil +// GetIfExists queries for a parameter by key from the Subspace's KVStore and +// sets the value to the provided pointer. If the value does not exist, it will +// perform a no-op. func (s Subspace) GetIfExists(ctx sdk.Context, key []byte, ptr interface{}) { store := s.kvStore(ctx) bz := store.Get(key) if bz == nil { return } - err := s.cdc.UnmarshalJSON(bz, ptr) - if err != nil { + + if err := s.cdc.UnmarshalJSON(bz, ptr); err != nil { panic(err) } } -// GetWithSubkey returns a parameter with a given key and a subkey. -func (s Subspace) GetWithSubkey(ctx sdk.Context, key, subkey []byte, ptr interface{}) { - s.Get(ctx, concatKeys(key, subkey), ptr) -} - -// GetWithSubkeyIfExists returns a parameter with a given key and a subkey but does not -// modify ptr if the stored parameter is nil. -func (s Subspace) GetWithSubkeyIfExists(ctx sdk.Context, key, subkey []byte, ptr interface{}) { - s.GetIfExists(ctx, concatKeys(key, subkey), ptr) -} - -// Get raw bytes of parameter from store +// GetRaw queries for the raw values bytes for a parameter by key. func (s Subspace) GetRaw(ctx sdk.Context, key []byte) []byte { store := s.kvStore(ctx) return store.Get(key) } -// Check if the parameter is set in the store +// Has returns if a parameter key exists or not in the Subspace's KVStore. func (s Subspace) Has(ctx sdk.Context, key []byte) bool { store := s.kvStore(ctx) return store.Has(key) } -// Returns true if the parameter is set in the block +// Modified returns true if the parameter key is set in the Subspace's transient +// KVStore. func (s Subspace) Modified(ctx sdk.Context, key []byte) bool { tstore := s.transientStore(ctx) return tstore.Has(key) } -func (s Subspace) checkType(store sdk.KVStore, key []byte, param interface{}) { +// checkType verifies that the provided key and value are comptable and registered. +func (s Subspace) checkType(key []byte, value interface{}) { attr, ok := s.table.m[string(key)] if !ok { panic(fmt.Sprintf("parameter %s not registered", string(key))) } ty := attr.ty - pty := reflect.TypeOf(param) + pty := reflect.TypeOf(value) if pty.Kind() == reflect.Ptr { pty = pty.Elem() } if pty != ty { - panic("Type mismatch with registered table") + panic("type mismatch with registered table") } } -// Set stores the parameter. It returns error if stored parameter has different type from input. -// It also set to the transient store to record change. -func (s Subspace) Set(ctx sdk.Context, key []byte, param interface{}) { +// Set stores a value for given a parameter key assuming the parameter type has +// been registered. It will panic if the parameter type has not been registered +// or if the value cannot be encoded. A change record is also set in the Subspace's +// transient KVStore to mark the parameter as modified. +func (s Subspace) Set(ctx sdk.Context, key []byte, value interface{}) { + s.checkType(key, value) store := s.kvStore(ctx) - s.checkType(store, key, param) - - bz, err := s.cdc.MarshalJSON(param) + bz, err := s.cdc.MarshalJSON(value) if err != nil { panic(err) } + store.Set(key, bz) tstore := s.transientStore(ctx) tstore.Set(key, []byte{}) - } -// Update stores raw parameter bytes. It returns error if the stored parameter -// has a different type from the input. It also sets to the transient store to -// record change. -func (s Subspace) Update(ctx sdk.Context, key []byte, param []byte) error { +// Update stores an updated raw value for a given parameter key assuming the +// parameter type has been registered. It will panic if the parameter type has +// not been registered or if the value cannot be encoded. An error is returned +// if the raw value is not compatible with the registered type for the parameter +// key or if the new value is invalid as determined by the registered type's +// validation function. +func (s Subspace) Update(ctx sdk.Context, key, value []byte) error { attr, ok := s.table.m[string(key)] if !ok { panic(fmt.Sprintf("parameter %s not registered", string(key))) @@ -194,72 +193,33 @@ func (s Subspace) Update(ctx sdk.Context, key []byte, param []byte) error { ty := attr.ty dest := reflect.New(ty).Interface() s.GetIfExists(ctx, key, dest) - err := s.cdc.UnmarshalJSON(param, dest) - if err != nil { - return err - } - - s.Set(ctx, key, dest) - // TODO: Remove; seems redundant as Set already does this. - tStore := s.transientStore(ctx) - tStore.Set(key, []byte{}) - - return nil -} - -// SetWithSubkey set a parameter with a key and subkey -// Checks parameter type only over the key -func (s Subspace) SetWithSubkey(ctx sdk.Context, key []byte, subkey []byte, param interface{}) { - store := s.kvStore(ctx) - - s.checkType(store, key, param) - - newkey := concatKeys(key, subkey) - - bz, err := s.cdc.MarshalJSON(param) - if err != nil { - panic(err) - } - store.Set(newkey, bz) - - tstore := s.transientStore(ctx) - tstore.Set(newkey, []byte{}) -} - -// UpdateWithSubkey stores raw parameter bytes with a key and subkey. It checks -// the parameter type only over the key. -func (s Subspace) UpdateWithSubkey(ctx sdk.Context, key []byte, subkey []byte, param []byte) error { - concatkey := concatKeys(key, subkey) - - attr, ok := s.table.m[string(concatkey)] - if !ok { - return fmt.Errorf("parameter %s not registered", string(key)) + if err := s.cdc.UnmarshalJSON(value, dest); err != nil { + return err } - ty := attr.ty - dest := reflect.New(ty).Interface() - s.GetWithSubkeyIfExists(ctx, key, subkey, dest) - err := s.cdc.UnmarshalJSON(param, dest) - if err != nil { + // destValue contains the dereferenced value of dest so validation function do + // not have to operate on pointers. + destValue := reflect.Indirect(reflect.ValueOf(dest)).Interface() + if err := s.Validate(ctx, key, destValue); err != nil { return err } - s.SetWithSubkey(ctx, key, subkey, dest) - tStore := s.transientStore(ctx) - tStore.Set(concatkey, []byte{}) - + s.Set(ctx, key, dest) return nil } -// Get to ParamSet +// GetParamSet iterates through each ParamSetPair where for each pair, it will +// retrieve the value and set it to the corresponding value pointer provided +// in the ParamSetPair by calling Subspace#Get. func (s Subspace) GetParamSet(ctx sdk.Context, ps ParamSet) { for _, pair := range ps.ParamSetPairs() { s.Get(ctx, pair.Key, pair.Value) } } -// Set from ParamSet +// SetParamSet iterates through each ParamSetPair and sets the value with the +// corresponding parameter key in the Subspace's KVStore. func (s Subspace) SetParamSet(ctx sdk.Context, ps ParamSet) { for _, pair := range ps.ParamSetPairs() { // pair.Field is a pointer to the field, so indirecting the ptr. @@ -267,11 +227,16 @@ func (s Subspace) SetParamSet(ctx sdk.Context, ps ParamSet) { // since SetStruct is meant to be used in InitGenesis // so this method will not be called frequently v := reflect.Indirect(reflect.ValueOf(pair.Value)).Interface() + + if err := pair.ValidatorFn(v); err != nil { + panic(fmt.Sprintf("value from ParamSetPair is invalid: %s", err)) + } + s.Set(ctx, pair.Key, v) } } -// Returns name of Subspace +// Name returns the name of the Subspace. func (s Subspace) Name() string { return string(s.name) } @@ -281,27 +246,27 @@ type ReadOnlySubspace struct { s Subspace } -// Exposes Get +// Get delegates a read-only Get call to the Subspace. func (ros ReadOnlySubspace) Get(ctx sdk.Context, key []byte, ptr interface{}) { ros.s.Get(ctx, key, ptr) } -// Exposes GetRaw +// GetRaw delegates a read-only GetRaw call to the Subspace. func (ros ReadOnlySubspace) GetRaw(ctx sdk.Context, key []byte) []byte { return ros.s.GetRaw(ctx, key) } -// Exposes Has +// Has delegates a read-only Has call to the Subspace. func (ros ReadOnlySubspace) Has(ctx sdk.Context, key []byte) bool { return ros.s.Has(ctx, key) } -// Exposes Modified +// Modified delegates a read-only Modified call to the Subspace. func (ros ReadOnlySubspace) Modified(ctx sdk.Context, key []byte) bool { return ros.s.Modified(ctx, key) } -// Exposes Space +// Name delegates a read-only Name call to the Subspace. func (ros ReadOnlySubspace) Name() string { return ros.s.Name() } diff --git a/x/params/subspace/subspace_test.go b/x/params/subspace/subspace_test.go new file mode 100644 index 000000000000..31a5d7635126 --- /dev/null +++ b/x/params/subspace/subspace_test.go @@ -0,0 +1,203 @@ +package subspace_test + +import ( + "fmt" + "testing" + "time" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/params/subspace" + "github.com/stretchr/testify/suite" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/libs/log" + dbm "github.com/tendermint/tm-db" +) + +type SubspaceTestSuite struct { + suite.Suite + + cdc *codec.Codec + ctx sdk.Context + ss subspace.Subspace +} + +func (suite *SubspaceTestSuite) SetupTest() { + cdc := codec.New() + db := dbm.NewMemDB() + + ms := store.NewCommitMultiStore(db) + ms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db) + ms.MountStoreWithDB(tkey, sdk.StoreTypeTransient, db) + suite.NoError(ms.LoadLatestVersion()) + + ss := subspace.NewSubspace(cdc, key, tkey, "testsubspace") + + suite.cdc = cdc + suite.ctx = sdk.NewContext(ms, abci.Header{}, false, log.NewNopLogger()) + suite.ss = ss.WithKeyTable(paramKeyTable()) +} + +func (suite *SubspaceTestSuite) TestKeyTable() { + suite.Require().True(suite.ss.HasKeyTable()) + suite.Require().Panics(func() { + suite.ss.WithKeyTable(paramKeyTable()) + }) + suite.Require().NotPanics(func() { + ss := subspace.NewSubspace(codec.New(), key, tkey, "testsubspace2") + ss = ss.WithKeyTable(paramKeyTable()) + }) +} + +func (suite *SubspaceTestSuite) TestGetSet() { + var v time.Duration + t := time.Hour * 48 + + suite.Require().Panics(func() { + suite.ss.Get(suite.ctx, keyUnbondingTime, &v) + }) + suite.Require().NotEqual(t, v) + suite.Require().NotPanics(func() { + suite.ss.Set(suite.ctx, keyUnbondingTime, t) + }) + suite.Require().NotPanics(func() { + suite.ss.Get(suite.ctx, keyUnbondingTime, &v) + }) + suite.Require().Equal(t, v) +} + +func (suite *SubspaceTestSuite) TestGetIfExists() { + var v time.Duration + + suite.Require().NotPanics(func() { + suite.ss.GetIfExists(suite.ctx, keyUnbondingTime, &v) + }) + suite.Require().Equal(time.Duration(0), v) +} + +func (suite *SubspaceTestSuite) TestGetRaw() { + t := time.Hour * 48 + + suite.Require().NotPanics(func() { + suite.ss.Set(suite.ctx, keyUnbondingTime, t) + }) + suite.Require().NotPanics(func() { + res := suite.ss.GetRaw(suite.ctx, keyUnbondingTime) + suite.Require().Equal("2231373238303030303030303030303022", fmt.Sprintf("%X", res)) + }) +} + +func (suite *SubspaceTestSuite) TestHas() { + t := time.Hour * 48 + + suite.Require().False(suite.ss.Has(suite.ctx, keyUnbondingTime)) + suite.Require().NotPanics(func() { + suite.ss.Set(suite.ctx, keyUnbondingTime, t) + }) + suite.Require().True(suite.ss.Has(suite.ctx, keyUnbondingTime)) +} + +func (suite *SubspaceTestSuite) TestModified() { + t := time.Hour * 48 + + suite.Require().False(suite.ss.Modified(suite.ctx, keyUnbondingTime)) + suite.Require().NotPanics(func() { + suite.ss.Set(suite.ctx, keyUnbondingTime, t) + }) + suite.Require().True(suite.ss.Modified(suite.ctx, keyUnbondingTime)) +} + +func (suite *SubspaceTestSuite) TestUpdate() { + suite.Require().Panics(func() { + suite.ss.Update(suite.ctx, []byte("invalid_key"), nil) + }) + + t := time.Hour * 48 + suite.Require().NotPanics(func() { + suite.ss.Set(suite.ctx, keyUnbondingTime, t) + }) + + bad := time.Minute * 5 + + bz, err := suite.cdc.MarshalJSON(bad) + suite.Require().NoError(err) + suite.Require().Error(suite.ss.Update(suite.ctx, keyUnbondingTime, bz)) + + good := time.Hour * 360 + bz, err = suite.cdc.MarshalJSON(good) + suite.Require().NoError(err) + suite.Require().NoError(suite.ss.Update(suite.ctx, keyUnbondingTime, bz)) + + var v time.Duration + + suite.Require().NotPanics(func() { + suite.ss.Get(suite.ctx, keyUnbondingTime, &v) + }) + suite.Require().Equal(good, v) +} + +func (suite *SubspaceTestSuite) TestGetParamSet() { + a := params{ + UnbondingTime: time.Hour * 48, + MaxValidators: 100, + BondDenom: "stake", + } + suite.Require().NotPanics(func() { + suite.ss.Set(suite.ctx, keyUnbondingTime, a.UnbondingTime) + suite.ss.Set(suite.ctx, keyMaxValidators, a.MaxValidators) + suite.ss.Set(suite.ctx, keyBondDenom, a.BondDenom) + }) + + b := params{} + suite.Require().NotPanics(func() { + suite.ss.GetParamSet(suite.ctx, &b) + }) + suite.Require().Equal(a.UnbondingTime, b.UnbondingTime) + suite.Require().Equal(a.MaxValidators, b.MaxValidators) + suite.Require().Equal(a.BondDenom, b.BondDenom) +} + +func (suite *SubspaceTestSuite) TestSetParamSet() { + testCases := []struct { + name string + ps subspace.ParamSet + }{ + {"invalid unbonding time", ¶ms{time.Hour * 1, 100, "stake"}}, + {"invalid bond denom", ¶ms{time.Hour * 48, 100, ""}}, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.Require().Panics(func() { + suite.ss.SetParamSet(suite.ctx, tc.ps) + }) + }) + } + + a := params{ + UnbondingTime: time.Hour * 48, + MaxValidators: 100, + BondDenom: "stake", + } + suite.Require().NotPanics(func() { + suite.ss.SetParamSet(suite.ctx, &a) + }) + + b := params{} + suite.Require().NotPanics(func() { + suite.ss.GetParamSet(suite.ctx, &b) + }) + suite.Require().Equal(a.UnbondingTime, b.UnbondingTime) + suite.Require().Equal(a.MaxValidators, b.MaxValidators) + suite.Require().Equal(a.BondDenom, b.BondDenom) +} + +func (suite *SubspaceTestSuite) TestName() { + suite.Require().Equal("testsubspace", suite.ss.Name()) +} + +func TestKeeperTestSuite(t *testing.T) { + suite.Run(t, new(SubspaceTestSuite)) +} diff --git a/x/params/subspace/table.go b/x/params/subspace/table.go index 75269cc06ef8..92e72242b967 100644 --- a/x/params/subspace/table.go +++ b/x/params/subspace/table.go @@ -2,10 +2,13 @@ package subspace import ( "reflect" + + sdk "github.com/cosmos/cosmos-sdk/types" ) type attribute struct { - ty reflect.Type + ty reflect.Type + vfn ValueValidatorFn } // KeyTable subspaces appropriate type for each parameter key @@ -13,65 +16,54 @@ type KeyTable struct { m map[string]attribute } -// Constructs new table -func NewKeyTable(keytypes ...interface{}) (res KeyTable) { - if len(keytypes)%2 != 0 { - panic("odd number arguments in NewTypeKeyTable") - } - - res = KeyTable{ +func NewKeyTable(pairs ...ParamSetPair) KeyTable { + keyTable := KeyTable{ m: make(map[string]attribute), } - for i := 0; i < len(keytypes); i += 2 { - res = res.RegisterType(keytypes[i].([]byte), keytypes[i+1]) + for _, psp := range pairs { + keyTable = keyTable.RegisterType(psp) } - return + return keyTable } -func isAlphaNumeric(key []byte) bool { - for _, b := range key { - if !((48 <= b && b <= 57) || // numeric - (65 <= b && b <= 90) || // upper case - (97 <= b && b <= 122)) { // lower case - return false - } +// RegisterType registers a single ParamSetPair (key-type pair) in a KeyTable. +func (t KeyTable) RegisterType(psp ParamSetPair) KeyTable { + if len(psp.Key) == 0 { + panic("cannot register ParamSetPair with an parameter empty key") } - return true -} - -// Register single key-type pair -func (t KeyTable) RegisterType(key []byte, ty interface{}) KeyTable { - if len(key) == 0 { - panic("cannot register empty key") + if !sdk.IsAlphaNumeric(string(psp.Key)) { + panic("cannot register ParamSetPair with a non-alphanumeric parameter key") } - if !isAlphaNumeric(key) { - panic("non alphanumeric parameter key") + if psp.ValidatorFn == nil { + panic("cannot register ParamSetPair without a value validation function") } - keystr := string(key) + + keystr := string(psp.Key) if _, ok := t.m[keystr]; ok { panic("duplicate parameter key") } - rty := reflect.TypeOf(ty) + rty := reflect.TypeOf(psp.Value) - // Indirect rty if it is ptr + // indirect rty if it is a pointer if rty.Kind() == reflect.Ptr { rty = rty.Elem() } t.m[keystr] = attribute{ - ty: rty, + vfn: psp.ValidatorFn, + ty: rty, } return t } -// Register multiple pairs from ParamSet +// RegisterParamSet registers multiple ParamSetPairs from a ParamSet in a KeyTable. func (t KeyTable) RegisterParamSet(ps ParamSet) KeyTable { - for _, kvp := range ps.ParamSetPairs() { - t = t.RegisterType(kvp.Key, kvp.Value) + for _, psp := range ps.ParamSetPairs() { + t = t.RegisterType(psp) } return t } @@ -83,5 +75,6 @@ func (t KeyTable) maxKeyLength() (res int) { res = l } } + return } diff --git a/x/params/subspace/table_test.go b/x/params/subspace/table_test.go index f1485b6e2653..fc47481a3bea 100644 --- a/x/params/subspace/table_test.go +++ b/x/params/subspace/table_test.go @@ -1,35 +1,45 @@ -package subspace +package subspace_test import ( "testing" + "time" + "github.com/cosmos/cosmos-sdk/x/params/subspace" "github.com/stretchr/testify/require" ) -type testparams struct { - i int64 - b bool -} - -func (tp *testparams) ParamSetPairs() ParamSetPairs { - return ParamSetPairs{ - {[]byte("i"), &tp.i}, - {[]byte("b"), &tp.b}, - } -} - func TestKeyTable(t *testing.T) { - table := NewKeyTable() - - require.Panics(t, func() { table.RegisterType([]byte(""), nil) }) - require.Panics(t, func() { table.RegisterType([]byte("!@#$%"), nil) }) - require.Panics(t, func() { table.RegisterType([]byte("hello,"), nil) }) - require.Panics(t, func() { table.RegisterType([]byte("hello"), nil) }) - - require.NotPanics(t, func() { table.RegisterType([]byte("hello"), bool(false)) }) - require.NotPanics(t, func() { table.RegisterType([]byte("world"), int64(0)) }) - require.Panics(t, func() { table.RegisterType([]byte("hello"), bool(false)) }) - - require.NotPanics(t, func() { table.RegisterParamSet(&testparams{}) }) - require.Panics(t, func() { table.RegisterParamSet(&testparams{}) }) + table := subspace.NewKeyTable() + + require.Panics(t, func() { table.RegisterType(subspace.ParamSetPair{[]byte(""), nil, nil}) }) + require.Panics(t, func() { table.RegisterType(subspace.ParamSetPair{[]byte("!@#$%"), nil, nil}) }) + require.Panics(t, func() { table.RegisterType(subspace.ParamSetPair{[]byte("hello,"), nil, nil}) }) + require.Panics(t, func() { table.RegisterType(subspace.ParamSetPair{[]byte("hello"), nil, nil}) }) + + require.NotPanics(t, func() { + table.RegisterType(subspace.ParamSetPair{keyBondDenom, string("stake"), validateBondDenom}) + }) + require.NotPanics(t, func() { + table.RegisterType(subspace.ParamSetPair{keyMaxValidators, uint16(100), validateMaxValidators}) + }) + require.Panics(t, func() { + table.RegisterType(subspace.ParamSetPair{keyUnbondingTime, time.Duration(1), nil}) + }) + require.NotPanics(t, func() { + table.RegisterType(subspace.ParamSetPair{keyUnbondingTime, time.Duration(1), validateMaxValidators}) + }) + require.NotPanics(t, func() { + newTable := subspace.NewKeyTable() + newTable.RegisterParamSet(¶ms{}) + }) + + require.Panics(t, func() { table.RegisterParamSet(¶ms{}) }) + require.Panics(t, func() { subspace.NewKeyTable(subspace.ParamSetPair{[]byte(""), nil, nil}) }) + + require.NotPanics(t, func() { + subspace.NewKeyTable( + subspace.ParamSetPair{[]byte("test"), string("stake"), validateBondDenom}, + subspace.ParamSetPair{[]byte("test2"), uint16(100), validateMaxValidators}, + ) + }) } diff --git a/x/params/subspace/test_common.go b/x/params/subspace/test_common.go deleted file mode 100644 index 2b1d817beaa9..000000000000 --- a/x/params/subspace/test_common.go +++ /dev/null @@ -1,40 +0,0 @@ -package subspace - -import ( - "os" - "testing" - - "github.com/stretchr/testify/require" - - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/libs/log" - dbm "github.com/tendermint/tm-db" - - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/store" - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// Keys for parameter access -const ( - TestParamStore = "ParamsTest" -) - -// Returns components for testing -func DefaultTestComponents(t *testing.T) (sdk.Context, Subspace, func() sdk.CommitID) { - cdc := codec.New() - key := sdk.NewKVStoreKey(StoreKey) - tkey := sdk.NewTransientStoreKey(TStoreKey) - db := dbm.NewMemDB() - ms := store.NewCommitMultiStore(db) - ms.SetTracer(os.Stdout) - ms.SetTracingContext(sdk.TraceContext{}) - ms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(tkey, sdk.StoreTypeTransient, db) - err := ms.LoadLatestVersion() - require.Nil(t, err) - ctx := sdk.NewContext(ms, abci.Header{}, false, log.NewTMLogger(os.Stdout)) - subspace := NewSubspace(cdc, key, tkey, TestParamStore) - - return ctx, subspace, ms.Commit -} diff --git a/x/params/types/errors.go b/x/params/types/errors.go index bbf8f5a2b4d6..12726b0322f5 100644 --- a/x/params/types/errors.go +++ b/x/params/types/errors.go @@ -21,8 +21,8 @@ func ErrUnknownSubspace(codespace sdk.CodespaceType, space string) sdk.Error { } // ErrSettingParameter returns an error for failing to set a parameter. -func ErrSettingParameter(codespace sdk.CodespaceType, key, subkey, value, msg string) sdk.Error { - return sdk.NewError(codespace, CodeSettingParameter, fmt.Sprintf("error setting parameter %s on %s (%s): %s", value, key, subkey, msg)) +func ErrSettingParameter(codespace sdk.CodespaceType, key, value, msg string) sdk.Error { + return sdk.NewError(codespace, CodeSettingParameter, fmt.Sprintf("error setting parameter %s on %s: %s", value, key, msg)) } // ErrEmptyChanges returns an error for empty parameter changes. diff --git a/x/params/types/proposal.go b/x/params/types/proposal.go index 58d559615723..a4bcefab2df6 100644 --- a/x/params/types/proposal.go +++ b/x/params/types/proposal.go @@ -69,9 +69,8 @@ func (pcp ParameterChangeProposal) String() string { b.WriteString(fmt.Sprintf(` Param Change: Subspace: %s Key: %s - Subkey: %X Value: %X -`, pc.Subspace, pc.Key, pc.Subkey, pc.Value)) +`, pc.Subspace, pc.Key, pc.Value)) } return b.String() @@ -81,16 +80,11 @@ func (pcp ParameterChangeProposal) String() string { type ParamChange struct { Subspace string `json:"subspace" yaml:"subspace"` Key string `json:"key" yaml:"key"` - Subkey string `json:"subkey,omitempty" yaml:"subkey,omitempty"` Value string `json:"value" yaml:"value"` } func NewParamChange(subspace, key, value string) ParamChange { - return ParamChange{subspace, key, "", value} -} - -func NewParamChangeWithSubkey(subspace, key, subkey, value string) ParamChange { - return ParamChange{subspace, key, subkey, value} + return ParamChange{subspace, key, value} } // String implements the Stringer interface. @@ -98,9 +92,8 @@ func (pc ParamChange) String() string { return fmt.Sprintf(`Param Change: Subspace: %s Key: %s - Subkey: %X Value: %X -`, pc.Subspace, pc.Key, pc.Subkey, pc.Value) +`, pc.Subspace, pc.Key, pc.Value) } // ValidateChanges performs basic validation checks over a set of ParamChange. It diff --git a/x/params/types/proposal_test.go b/x/params/types/proposal_test.go index e4865aad7ad8..aa891c82031d 100644 --- a/x/params/types/proposal_test.go +++ b/x/params/types/proposal_test.go @@ -8,7 +8,7 @@ import ( func TestParameterChangeProposal(t *testing.T) { pc1 := NewParamChange("sub", "foo", "baz") - pc2 := NewParamChangeWithSubkey("sub", "bar", "cat", "dog") + pc2 := NewParamChange("sub", "bar", "cat") pcp := NewParameterChangeProposal("test title", "test description", []ParamChange{pc1, pc2}) require.Equal(t, "test title", pcp.GetTitle()) @@ -17,15 +17,11 @@ func TestParameterChangeProposal(t *testing.T) { require.Equal(t, ProposalTypeChange, pcp.ProposalType()) require.Nil(t, pcp.ValidateBasic()) - pc3 := NewParamChangeWithSubkey("", "bar", "cat", "dog") + pc3 := NewParamChange("", "bar", "cat") pcp = NewParameterChangeProposal("test title", "test description", []ParamChange{pc3}) require.Error(t, pcp.ValidateBasic()) - pc4 := NewParamChangeWithSubkey("sub", "", "cat", "dog") + pc4 := NewParamChange("sub", "", "cat") pcp = NewParameterChangeProposal("test title", "test description", []ParamChange{pc4}) require.Error(t, pcp.ValidateBasic()) - - pc5 := NewParamChangeWithSubkey("sub", "foo", "cat", "") - pcp = NewParameterChangeProposal("test title", "test description", []ParamChange{pc5}) - require.Error(t, pcp.ValidateBasic()) } diff --git a/x/simulation/params.go b/x/simulation/params.go index d3e2af44f15c..2673822d8f43 100644 --- a/x/simulation/params.go +++ b/x/simulation/params.go @@ -94,23 +94,21 @@ type SimValFn func(r *rand.Rand) string type ParamChange struct { Subspace string Key string - Subkey string SimValue SimValFn } // NewSimParamChange creates a new ParamChange instance -func NewSimParamChange(subspace, key, subkey string, simVal SimValFn) ParamChange { +func NewSimParamChange(subspace, key string, simVal SimValFn) ParamChange { return ParamChange{ Subspace: subspace, Key: key, - Subkey: subkey, SimValue: simVal, } } // ComposedKey creates a new composed key for the param change proposal func (spc ParamChange) ComposedKey() string { - return fmt.Sprintf("%s/%s/%s", spc.Subspace, spc.Key, spc.Subkey) + return fmt.Sprintf("%s/%s", spc.Subspace, spc.Key) } //----------------------------------------------------------------------------- diff --git a/x/slashing/handler_test.go b/x/slashing/handler_test.go index 077ea009f3a9..e0d5228326da 100644 --- a/x/slashing/handler_test.go +++ b/x/slashing/handler_test.go @@ -72,7 +72,6 @@ func TestJailedValidatorDelegations(t *testing.T) { ctx, _, stakingKeeper, _, slashingKeeper := slashingkeeper.CreateTestInput(t, DefaultParams()) stakingParams := stakingKeeper.GetParams(ctx) - stakingParams.UnbondingTime = 0 stakingKeeper.SetParams(ctx, stakingParams) // create a validator diff --git a/x/slashing/internal/types/params.go b/x/slashing/internal/types/params.go index 4817ac5ee3ef..15dd6cca6238 100644 --- a/x/slashing/internal/types/params.go +++ b/x/slashing/internal/types/params.go @@ -75,11 +75,11 @@ func (p Params) String() string { // ParamSetPairs - Implements params.ParamSet func (p *Params) ParamSetPairs() params.ParamSetPairs { return params.ParamSetPairs{ - params.NewParamSetPair(KeySignedBlocksWindow, &p.SignedBlocksWindow), - params.NewParamSetPair(KeyMinSignedPerWindow, &p.MinSignedPerWindow), - params.NewParamSetPair(KeyDowntimeJailDuration, &p.DowntimeJailDuration), - params.NewParamSetPair(KeySlashFractionDoubleSign, &p.SlashFractionDoubleSign), - params.NewParamSetPair(KeySlashFractionDowntime, &p.SlashFractionDowntime), + params.NewParamSetPair(KeySignedBlocksWindow, &p.SignedBlocksWindow, validateSignedBlocksWindow), + params.NewParamSetPair(KeyMinSignedPerWindow, &p.MinSignedPerWindow, validateMinSignedPerWindow), + params.NewParamSetPair(KeyDowntimeJailDuration, &p.DowntimeJailDuration, validateDowntimeJailDuration), + params.NewParamSetPair(KeySlashFractionDoubleSign, &p.SlashFractionDoubleSign, validateSlashFractionDoubleSign), + params.NewParamSetPair(KeySlashFractionDowntime, &p.SlashFractionDowntime, validateSlashFractionDowntime), } } @@ -90,3 +90,77 @@ func DefaultParams() Params { DefaultSlashFractionDoubleSign, DefaultSlashFractionDowntime, ) } + +func validateSignedBlocksWindow(i interface{}) error { + v, ok := i.(int64) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v <= 0 { + return fmt.Errorf("signed blocks window must be positive: %d", v) + } + + return nil +} + +func validateMinSignedPerWindow(i interface{}) error { + v, ok := i.(sdk.Dec) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v.IsNegative() { + return fmt.Errorf("min signed per window cannot be negative: %s", v) + } + if v.GT(sdk.OneDec()) { + return fmt.Errorf("min signed per window too large: %s", v) + } + + return nil +} + +func validateDowntimeJailDuration(i interface{}) error { + v, ok := i.(time.Duration) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v <= 0 { + return fmt.Errorf("downtime jail duration must be positive: %s", v) + } + + return nil +} + +func validateSlashFractionDoubleSign(i interface{}) error { + v, ok := i.(sdk.Dec) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v.IsNegative() { + return fmt.Errorf("double sign slash fraction cannot be negative: %s", v) + } + if v.GT(sdk.OneDec()) { + return fmt.Errorf("double sign slash fraction too large: %s", v) + } + + return nil +} + +func validateSlashFractionDowntime(i interface{}) error { + v, ok := i.(sdk.Dec) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v.IsNegative() { + return fmt.Errorf("downtime slash fraction cannot be negative: %s", v) + } + if v.GT(sdk.OneDec()) { + return fmt.Errorf("downtime slash fraction too large: %s", v) + } + + return nil +} diff --git a/x/slashing/simulation/params.go b/x/slashing/simulation/params.go index 447073912c1a..6679928d8fc4 100644 --- a/x/slashing/simulation/params.go +++ b/x/slashing/simulation/params.go @@ -20,17 +20,17 @@ const ( // on the simulation func ParamChanges(r *rand.Rand) []simulation.ParamChange { return []simulation.ParamChange{ - simulation.NewSimParamChange(types.ModuleName, keySignedBlocksWindow, "", + simulation.NewSimParamChange(types.ModuleName, keySignedBlocksWindow, func(r *rand.Rand) string { return fmt.Sprintf("\"%d\"", GenSignedBlocksWindow(r)) }, ), - simulation.NewSimParamChange(types.ModuleName, keyMinSignedPerWindow, "", + simulation.NewSimParamChange(types.ModuleName, keyMinSignedPerWindow, func(r *rand.Rand) string { return fmt.Sprintf("\"%s\"", GenMinSignedPerWindow(r)) }, ), - simulation.NewSimParamChange(types.ModuleName, keySlashFractionDowntime, "", + simulation.NewSimParamChange(types.ModuleName, keySlashFractionDowntime, func(r *rand.Rand) string { return fmt.Sprintf("\"%s\"", GenSlashFractionDowntime(r)) }, diff --git a/x/staking/handler_test.go b/x/staking/handler_test.go index 6a822603a88e..0e999ba9b43b 100644 --- a/x/staking/handler_test.go +++ b/x/staking/handler_test.go @@ -17,25 +17,12 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking/types" ) -//______________________________________________________________________ - -// retrieve params which are instant -func setInstantUnbondPeriod(keeper keep.Keeper, ctx sdk.Context) types.Params { - params := keeper.GetParams(ctx) - params.UnbondingTime = 0 - keeper.SetParams(ctx, params) - return params -} - -//______________________________________________________________________ - func TestValidatorByPowerIndex(t *testing.T) { validatorAddr, validatorAddr3 := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1]) initPower := int64(1000000) initBond := sdk.TokensFromConsensusPower(initPower) ctx, _, keeper, _ := keep.CreateTestInput(t, false, initPower) - _ = setInstantUnbondPeriod(keeper, ctx) // create validator msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], initBond) @@ -186,7 +173,6 @@ func TestInvalidPubKeyTypeMsgCreateValidator(t *testing.T) { func TestLegacyValidatorDelegations(t *testing.T) { ctx, _, keeper, _ := keep.CreateTestInput(t, false, int64(1000)) - setInstantUnbondPeriod(keeper, ctx) bondAmount := sdk.TokensFromConsensusPower(10) valAddr := sdk.ValAddress(keep.Addrs[0]) @@ -350,7 +336,6 @@ func TestEditValidatorDecreaseMinSelfDelegation(t *testing.T) { initPower := int64(100) initBond := sdk.TokensFromConsensusPower(100) ctx, _, keeper, _ := keep.CreateTestInput(t, false, initPower) - _ = setInstantUnbondPeriod(keeper, ctx) // create validator msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], initBond) @@ -382,7 +367,6 @@ func TestEditValidatorIncreaseMinSelfDelegationBeyondCurrentBond(t *testing.T) { initPower := int64(100) initBond := sdk.TokensFromConsensusPower(100) ctx, _, keeper, _ := keep.CreateTestInput(t, false, initPower) - _ = setInstantUnbondPeriod(keeper, ctx) // create validator msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], initBond) @@ -412,7 +396,8 @@ func TestIncrementsMsgUnbond(t *testing.T) { initPower := int64(1000) initBond := sdk.TokensFromConsensusPower(initPower) ctx, accMapper, keeper, _ := keep.CreateTestInput(t, false, initPower) - params := setInstantUnbondPeriod(keeper, ctx) + + params := keeper.GetParams(ctx) denom := params.BondDenom // create validator, delegate @@ -510,7 +495,10 @@ func TestMultipleMsgCreateValidator(t *testing.T) { initPower := int64(1000) initTokens := sdk.TokensFromConsensusPower(initPower) ctx, accMapper, keeper, _ := keep.CreateTestInput(t, false, initPower) - params := setInstantUnbondPeriod(keeper, ctx) + + params := keeper.GetParams(ctx) + blockTime := time.Now().UTC() + ctx = ctx.WithBlockTime(blockTime) validatorAddrs := []sdk.ValAddress{ sdk.ValAddress(keep.Addrs[0]), @@ -544,6 +532,8 @@ func TestMultipleMsgCreateValidator(t *testing.T) { require.Equal(t, balanceExpd, balanceGot, "expected account to have %d, got %d", balanceExpd, balanceGot) } + EndBlocker(ctx, keeper) + // unbond them all by removing delegation for i, validatorAddr := range validatorAddrs { _, found := keeper.GetValidator(ctx, validatorAddr) @@ -552,16 +542,17 @@ func TestMultipleMsgCreateValidator(t *testing.T) { unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(10)) msgUndelegate := NewMsgUndelegate(delegatorAddrs[i], validatorAddr, unbondAmt) // remove delegation got := handleMsgUndelegate(ctx, msgUndelegate, keeper) - require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got) - var finishTime time.Time - // Jump to finishTime for unbonding period and remove from unbonding queue + var finishTime time.Time types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime) - ctx = ctx.WithBlockTime(finishTime) + // adds validator into unbonding queue EndBlocker(ctx, keeper) + // removes validator from queue and set + EndBlocker(ctx.WithBlockTime(blockTime.Add(params.UnbondingTime)), keeper) + // Check that the validator is deleted from state validators := keeper.GetValidators(ctx, 100) require.Equal(t, len(validatorAddrs)-(i+1), len(validators), @@ -578,7 +569,6 @@ func TestMultipleMsgCreateValidator(t *testing.T) { func TestMultipleMsgDelegate(t *testing.T) { ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000) validatorAddr, delegatorAddrs := sdk.ValAddress(keep.Addrs[0]), keep.Addrs[1:] - _ = setInstantUnbondPeriod(keeper, ctx) // first make a validator msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], sdk.NewInt(10)) @@ -620,7 +610,6 @@ func TestMultipleMsgDelegate(t *testing.T) { func TestJailValidator(t *testing.T) { ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000) validatorAddr, delegatorAddr := sdk.ValAddress(keep.Addrs[0]), keep.Addrs[1] - _ = setInstantUnbondPeriod(keeper, ctx) // create the validator msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], sdk.NewInt(10)) @@ -873,10 +862,8 @@ func TestTransitiveRedelegation(t *testing.T) { validatorAddr2 := sdk.ValAddress(keep.Addrs[1]) validatorAddr3 := sdk.ValAddress(keep.Addrs[2]) - // set the unbonding time - params := keeper.GetParams(ctx) - params.UnbondingTime = 0 - keeper.SetParams(ctx, params) + blockTime := time.Now().UTC() + ctx = ctx.WithBlockTime(blockTime) // create the validators msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], sdk.NewInt(10)) @@ -902,12 +889,15 @@ func TestTransitiveRedelegation(t *testing.T) { got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) require.True(t, !got.IsOK(), "expected an error, msg: %v", msgBeginRedelegate) + params := keeper.GetParams(ctx) + ctx = ctx.WithBlockTime(blockTime.Add(params.UnbondingTime)) + // complete first redelegation EndBlocker(ctx, keeper) // now should be able to redelegate from the second validator to the third got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) - require.True(t, got.IsOK(), "expected no error") + require.True(t, got.IsOK(), "expected no error", got.Log) } func TestMultipleRedelegationAtSameTime(t *testing.T) { @@ -1125,7 +1115,6 @@ func TestUnbondingWhenExcessValidators(t *testing.T) { // set the unbonding time params := keeper.GetParams(ctx) - params.UnbondingTime = 0 params.MaxValidators = 2 keeper.SetParams(ctx, params) diff --git a/x/staking/simulation/params.go b/x/staking/simulation/params.go index f4c292cae674..97938fb91e2d 100644 --- a/x/staking/simulation/params.go +++ b/x/staking/simulation/params.go @@ -19,12 +19,12 @@ const ( // on the simulation func ParamChanges(r *rand.Rand) []simulation.ParamChange { return []simulation.ParamChange{ - simulation.NewSimParamChange(types.ModuleName, keyMaxValidators, "", + simulation.NewSimParamChange(types.ModuleName, keyMaxValidators, func(r *rand.Rand) string { return fmt.Sprintf("%d", GenMaxValidators(r)) }, ), - simulation.NewSimParamChange(types.ModuleName, keyUnbondingTime, "", + simulation.NewSimParamChange(types.ModuleName, keyUnbondingTime, func(r *rand.Rand) string { return fmt.Sprintf("\"%d\"", GenUnbondingTime(r)) }, diff --git a/x/staking/types/params.go b/x/staking/types/params.go index 8be8cff4f24b..00d7aed07fb7 100644 --- a/x/staking/types/params.go +++ b/x/staking/types/params.go @@ -2,7 +2,9 @@ package types import ( "bytes" + "errors" "fmt" + "strings" "time" "github.com/cosmos/cosmos-sdk/codec" @@ -39,8 +41,7 @@ type Params struct { UnbondingTime time.Duration `json:"unbonding_time" yaml:"unbonding_time"` // time duration of unbonding MaxValidators uint16 `json:"max_validators" yaml:"max_validators"` // maximum number of validators (max uint16 = 65535) MaxEntries uint16 `json:"max_entries" yaml:"max_entries"` // max entries for either unbonding delegation or redelegation (per pair/trio) - // note: we need to be a bit careful about potential overflow here, since this is user-determined - BondDenom string `json:"bond_denom" yaml:"bond_denom"` // bondable coin denomination + BondDenom string `json:"bond_denom" yaml:"bond_denom"` // bondable coin denomination } // NewParams creates a new Params instance @@ -58,10 +59,10 @@ func NewParams(unbondingTime time.Duration, maxValidators, maxEntries uint16, // Implements params.ParamSet func (p *Params) ParamSetPairs() params.ParamSetPairs { return params.ParamSetPairs{ - {Key: KeyUnbondingTime, Value: &p.UnbondingTime}, - {Key: KeyMaxValidators, Value: &p.MaxValidators}, - {Key: KeyMaxEntries, Value: &p.MaxEntries}, - {Key: KeyBondDenom, Value: &p.BondDenom}, + params.NewParamSetPair(KeyUnbondingTime, &p.UnbondingTime, validateUnbondingTime), + params.NewParamSetPair(KeyMaxValidators, &p.MaxValidators, validateMaxValidators), + params.NewParamSetPair(KeyMaxEntries, &p.MaxEntries, validateMaxEntries), + params.NewParamSetPair(KeyBondDenom, &p.BondDenom, validateBondDenom), } } @@ -108,11 +109,73 @@ func UnmarshalParams(cdc *codec.Codec, value []byte) (params Params, err error) // validate a set of params func (p Params) Validate() error { - if p.BondDenom == "" { - return fmt.Errorf("staking parameter BondDenom can't be an empty string") + if err := validateUnbondingTime(p.UnbondingTime); err != nil { + return err } - if p.MaxValidators == 0 { - return fmt.Errorf("staking parameter MaxValidators must be a positive integer") + if err := validateMaxValidators(p.MaxValidators); err != nil { + return err } + if err := validateMaxEntries(p.MaxEntries); err != nil { + return err + } + if err := validateBondDenom(p.BondDenom); err != nil { + return err + } + + return nil +} + +func validateUnbondingTime(i interface{}) error { + v, ok := i.(time.Duration) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v <= 0 { + return fmt.Errorf("unbonding time must be positive: %d", v) + } + + return nil +} + +func validateMaxValidators(i interface{}) error { + v, ok := i.(uint16) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v == 0 { + return fmt.Errorf("max validators must be positive: %d", v) + } + + return nil +} + +func validateMaxEntries(i interface{}) error { + v, ok := i.(uint16) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v == 0 { + return fmt.Errorf("max entries must be positive: %d", v) + } + + return nil +} + +func validateBondDenom(i interface{}) error { + v, ok := i.(string) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if strings.TrimSpace(v) == "" { + return errors.New("bond denom cannot be blank") + } + if err := sdk.ValidateDenom(v); err != nil { + return err + } + return nil } From 09bd174a490c02d90b10b587cda03fc88f037048 Mon Sep 17 00:00:00 2001 From: Riccardo Montagnin Date: Tue, 10 Dec 2019 20:09:22 +0100 Subject: [PATCH 019/529] Merge PR #5249: Support for sending funds to the community pool - Part I --- CHANGELOG.md | 1 + simapp/app.go | 17 +++++- simapp/app_test.go | 2 +- simapp/test_helpers.go | 2 +- x/bank/app_test.go | 76 ++++++++++++++++++++------- x/bank/internal/keeper/keeper_test.go | 4 +- x/distribution/client/cli/tx.go | 33 ++++++++++++ x/distribution/client/rest/tx.go | 35 ++++++++++++ x/distribution/handler.go | 19 +++++++ x/distribution/keeper/keeper.go | 13 +++++ x/distribution/keeper/keeper_test.go | 19 +++++++ x/distribution/types/msg.go | 38 ++++++++++++++ x/distribution/types/msg_test.go | 21 ++++++++ 13 files changed, 256 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 44fcf198b728..da4abf38ce45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -139,6 +139,7 @@ that allows for arbitrary vesting periods. * `ValidateSigCountDecorator`: Validate the number of signatures in tx based on app-parameters. * `IncrementSequenceDecorator`: Increments the account sequence for each signer to prevent replay attacks. * (cli) [\#5223](https://github.com/cosmos/cosmos-sdk/issues/5223) Cosmos Ledger App v2.0.0 is now supported. The changes are backwards compatible and App v1.5.x is still supported. +* (modules) [\#5249](https://github.com/cosmos/cosmos-sdk/pull/5249) Funds are now allowed to be directly sent to the community pool (via the distribution module account). ### Improvements diff --git a/simapp/app.go b/simapp/app.go index 84a1197713c4..1f10c7674bd9 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -72,6 +72,11 @@ var ( staking.NotBondedPoolName: {supply.Burner, supply.Staking}, gov.ModuleName: {supply.Burner}, } + + // module accounts that are allowed to receive tokens + allowedReceivingModAcc = map[string]bool{ + distr.ModuleName: true, + } ) // MakeCodec - custom tx codec @@ -167,7 +172,7 @@ func NewSimApp( ) app.BankKeeper = bank.NewBaseKeeper( app.AccountKeeper, app.subspaces[bank.ModuleName], bank.DefaultCodespace, - app.ModuleAccountAddrs(), + app.BlacklistedAccAddrs(), ) app.SupplyKeeper = supply.NewKeeper( app.cdc, keys[supply.StoreKey], app.AccountKeeper, app.BankKeeper, maccPerms, @@ -322,6 +327,16 @@ func (app *SimApp) ModuleAccountAddrs() map[string]bool { return modAccAddrs } +// BlacklistedAccAddrs returns all the app's module account addresses black listed for receiving tokens. +func (app *SimApp) BlacklistedAccAddrs() map[string]bool { + blacklistedAddrs := make(map[string]bool) + for acc := range maccPerms { + blacklistedAddrs[supply.NewModuleAddress(acc).String()] = !allowedReceivingModAcc[acc] + } + + return blacklistedAddrs +} + // Codec returns SimApp's codec. // // NOTE: This is solely to be used for testing purposes as it may be desirable diff --git a/simapp/app_test.go b/simapp/app_test.go index 4cddce7b6786..2be73cdfbf0e 100644 --- a/simapp/app_test.go +++ b/simapp/app_test.go @@ -42,7 +42,7 @@ func TestBlackListedAddrs(t *testing.T) { app := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, 0) for acc := range maccPerms { - require.True(t, app.BankKeeper.BlacklistedAddr(app.SupplyKeeper.GetModuleAddress(acc))) + require.Equal(t, !allowedReceivingModAcc[acc], app.BankKeeper.BlacklistedAddr(app.SupplyKeeper.GetModuleAddress(acc))) } } diff --git a/simapp/test_helpers.go b/simapp/test_helpers.go index 7d91a610893a..c7874bc0b7c9 100644 --- a/simapp/test_helpers.go +++ b/simapp/test_helpers.go @@ -105,7 +105,7 @@ func CheckBalance(t *testing.T, app *SimApp, addr sdk.AccAddress, exp sdk.Coins) ctxCheck := app.BaseApp.NewContext(true, abci.Header{}) res := app.AccountKeeper.GetAccount(ctxCheck, addr) - require.Equal(t, exp, res.GetCoins()) + require.True(t, exp.IsEqual(res.GetCoins())) } // SignCheckDeliver checks a generated signed transaction and simulates a diff --git a/x/bank/app_test.go b/x/bank/app_test.go index 35a42d8d601b..9ec1bdfaa3f3 100644 --- a/x/bank/app_test.go +++ b/x/bank/app_test.go @@ -3,6 +3,8 @@ package bank_test import ( "testing" + "github.com/cosmos/cosmos-sdk/x/distribution" + "github.com/cosmos/cosmos-sdk/x/supply" "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" @@ -118,36 +120,70 @@ func TestSendNotEnoughBalance(t *testing.T) { require.Equal(t, res2.GetSequence(), origSeq+1) } -// A module account cannot be the recipient of bank sends +// A module account cannot be the recipient of bank sends unless it has been marked as such func TestSendToModuleAcc(t *testing.T) { - acc := &auth.BaseAccount{ - Address: addr1, - Coins: coins, + tests := []struct { + name string + fromBalance sdk.Coins + msg types.MsgSend + expSimPass bool + expPass bool + expFromBalance sdk.Coins + expToBalance sdk.Coins + }{ + { + name: "Normal module account cannot be the recipient of bank sends", + fromBalance: coins, + msg: types.NewMsgSend(addr1, moduleAccAddr, coins), + expSimPass: false, + expPass: false, + expFromBalance: coins, + expToBalance: sdk.NewCoins(), + }, + { + name: "Allowed module account can be the recipient of bank sends", + fromBalance: coins, + msg: types.NewMsgSend(addr1, supply.NewModuleAddress(distribution.ModuleName), coins), + expPass: true, + expSimPass: true, + expFromBalance: sdk.NewCoins(), + expToBalance: coins, + }, } - genAccs := []authexported.GenesisAccount{acc} - app := simapp.SetupWithGenesisAccounts(genAccs) + for _, test := range tests { + test := test + t.Run(test.name, func(t *testing.T) { + acc := &auth.BaseAccount{ + Address: test.msg.FromAddress, + Coins: test.fromBalance, + } - ctxCheck := app.BaseApp.NewContext(true, abci.Header{}) + genAccs := []authexported.GenesisAccount{acc} + app := simapp.SetupWithGenesisAccounts(genAccs) - res1 := app.AccountKeeper.GetAccount(ctxCheck, addr1) - require.NotNil(t, res1) - require.Equal(t, acc, res1.(*auth.BaseAccount)) + ctxCheck := app.BaseApp.NewContext(true, abci.Header{}) - origAccNum := res1.GetAccountNumber() - origSeq := res1.GetSequence() + res1 := app.AccountKeeper.GetAccount(ctxCheck, test.msg.FromAddress) + require.NotNil(t, res1) + require.Equal(t, acc, res1.(*auth.BaseAccount)) - header := abci.Header{Height: app.LastBlockHeight() + 1} - simapp.SignCheckDeliver(t, app.Codec(), app.BaseApp, header, []sdk.Msg{sendMsg2}, []uint64{origAccNum}, []uint64{origSeq}, false, false, priv1) + origAccNum := res1.GetAccountNumber() + origSeq := res1.GetSequence() - simapp.CheckBalance(t, app, addr1, coins) - simapp.CheckBalance(t, app, moduleAccAddr, sdk.Coins(nil)) + header := abci.Header{Height: app.LastBlockHeight() + 1} + simapp.SignCheckDeliver(t, app.Codec(), app.BaseApp, header, []sdk.Msg{test.msg}, []uint64{origAccNum}, []uint64{origSeq}, test.expSimPass, test.expPass, priv1) - res2 := app.AccountKeeper.GetAccount(app.NewContext(true, abci.Header{}), addr1) - require.NotNil(t, res2) + simapp.CheckBalance(t, app, test.msg.FromAddress, test.expFromBalance) + simapp.CheckBalance(t, app, test.msg.ToAddress, test.expToBalance) - require.Equal(t, res2.GetAccountNumber(), origAccNum) - require.Equal(t, res2.GetSequence(), origSeq+1) + res2 := app.AccountKeeper.GetAccount(app.NewContext(true, abci.Header{}), addr1) + require.NotNil(t, res2) + + require.Equal(t, res2.GetAccountNumber(), origAccNum) + require.Equal(t, res2.GetSequence(), origSeq+1) + }) + } } func TestMsgMultiSendWithAccounts(t *testing.T) { diff --git a/x/bank/internal/keeper/keeper_test.go b/x/bank/internal/keeper/keeper_test.go index e136da5c1cbb..ba6c3f56c440 100644 --- a/x/bank/internal/keeper/keeper_test.go +++ b/x/bank/internal/keeper/keeper_test.go @@ -4,6 +4,7 @@ import ( "testing" "time" + "github.com/cosmos/cosmos-sdk/x/supply" "github.com/tendermint/tendermint/libs/common" "github.com/stretchr/testify/require" @@ -97,7 +98,8 @@ func TestKeeper(t *testing.T) { // Test retrieving black listed accounts for acc := range simapp.GetMaccPerms() { - require.True(t, app.BankKeeper.BlacklistedAddr(app.SupplyKeeper.GetModuleAddress(acc))) + addr := supply.NewModuleAddress(acc) + require.Equal(t, app.BlacklistedAccAddrs()[addr.String()], app.BankKeeper.BlacklistedAddr(addr)) } } diff --git a/x/distribution/client/cli/tx.go b/x/distribution/client/cli/tx.go index 22140eccd21e..b73244d61c08 100644 --- a/x/distribution/client/cli/tx.go +++ b/x/distribution/client/cli/tx.go @@ -47,6 +47,7 @@ func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { GetCmdWithdrawRewards(cdc), GetCmdSetWithdrawAddr(cdc), GetCmdWithdrawAllRewards(cdc, storeKey), + GetCmdFundCommunityPool(cdc), )...) return distTxCmd @@ -259,3 +260,35 @@ Where proposal.json contains: return cmd } + +// command to fund the community pool +func GetCmdFundCommunityPool(cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "fund-community-pool [amount]", + Args: cobra.ExactArgs(1), + Short: "funds the community pool with the specified amount", + Long: strings.TrimSpace( + fmt.Sprintf(`Funds the community pool with the specified amount + +Example: +$ %s tx fund-community-pool 100uatom --from mykey +`, + version.ClientName, + ), + ), + RunE: func(cmd *cobra.Command, args []string) error { + inBuf := bufio.NewReader(cmd.InOrStdin()) + txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc)) + cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) + + depositorAddr := cliCtx.GetFromAddress() + amount, err := sdk.ParseCoins(args[0]) + if err != nil { + return err + } + + msg := types.NewMsgDepositIntoCommunityPool(amount, depositorAddr) + return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } +} diff --git a/x/distribution/client/rest/tx.go b/x/distribution/client/rest/tx.go index 6dbb6f26ea6d..6044e150ed11 100644 --- a/x/distribution/client/rest/tx.go +++ b/x/distribution/client/rest/tx.go @@ -39,6 +39,12 @@ func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router, queryRoute strin withdrawValidatorRewardsHandlerFn(cliCtx), ).Methods("POST") + // Fund the community pool + r.HandleFunc( + "/distribution/community_pool", + fundCommunityPoolHandlerFn(cliCtx), + ).Methods("POST") + } type ( @@ -50,6 +56,11 @@ type ( BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` WithdrawAddress sdk.AccAddress `json:"withdraw_address" yaml:"withdraw_address"` } + + fundCommunityPoolReq struct { + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + Amount sdk.Coins `json:"amount" yaml:"amount"` + } ) // Withdraw delegator rewards @@ -177,6 +188,30 @@ func withdrawValidatorRewardsHandlerFn(cliCtx context.CLIContext) http.HandlerFu } } +// Fund the community pool +func fundCommunityPoolHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req fundCommunityPoolReq + if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) { + return + } + + req.BaseReq = req.BaseReq.Sanitize() + if !req.BaseReq.ValidateBasic(w) { + return + } + + fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + msg := types.NewMsgDepositIntoCommunityPool(req.Amount, fromAddr) + utils.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) + } +} + // Auxiliary func checkDelegatorAddressVar(w http.ResponseWriter, r *http.Request) (sdk.AccAddress, bool) { diff --git a/x/distribution/handler.go b/x/distribution/handler.go index ca047cec3672..d2561241160d 100644 --- a/x/distribution/handler.go +++ b/x/distribution/handler.go @@ -23,6 +23,9 @@ func NewHandler(k keeper.Keeper) sdk.Handler { case types.MsgWithdrawValidatorCommission: return handleMsgWithdrawValidatorCommission(ctx, msg, k) + case types.MsgDepositIntoCommunityPool: + return handleMsgDepositIntoCommunityPool(ctx, msg, k) + default: errMsg := fmt.Sprintf("unrecognized distribution message type: %T", msg) return sdk.ErrUnknownRequest(errMsg).Result() @@ -83,6 +86,22 @@ func handleMsgWithdrawValidatorCommission(ctx sdk.Context, msg types.MsgWithdraw return sdk.Result{Events: ctx.EventManager().Events()} } +func handleMsgDepositIntoCommunityPool(ctx sdk.Context, msg types.MsgDepositIntoCommunityPool, k keeper.Keeper) sdk.Result { + if err := k.DepositCommunityPoolFunds(ctx, msg.Amount, msg.Depositor); err != nil { + return sdk.ResultFromError(err) + } + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Depositor.String()), + ), + ) + + return sdk.Result{Events: ctx.EventManager().Events()} +} + func NewCommunityPoolSpendProposalHandler(k Keeper) govtypes.Handler { return func(ctx sdk.Context, content govtypes.Content) sdk.Error { switch c := content.(type) { diff --git a/x/distribution/keeper/keeper.go b/x/distribution/keeper/keeper.go index 0f9b56199063..a36834fb7c75 100644 --- a/x/distribution/keeper/keeper.go +++ b/x/distribution/keeper/keeper.go @@ -149,3 +149,16 @@ func (k Keeper) GetTotalRewards(ctx sdk.Context) (totalRewards sdk.DecCoins) { ) return totalRewards } + +// DepositCommunityPoolFunds allows to transfer the specified amount from the sender into the community pool +func (k Keeper) DepositCommunityPoolFunds(ctx sdk.Context, amount sdk.Coins, sender sdk.AccAddress) error { + if err := k.supplyKeeper.SendCoinsFromAccountToModule(ctx, sender, types.ModuleName, amount); err != nil { + return err + } + + feePool := k.GetFeePool(ctx) + feePool.CommunityPool = feePool.CommunityPool.Add(sdk.NewDecCoins(amount)) + k.SetFeePool(ctx, feePool) + + return nil +} diff --git a/x/distribution/keeper/keeper_test.go b/x/distribution/keeper/keeper_test.go index 49d4e3c18302..a493e4fea6dd 100644 --- a/x/distribution/keeper/keeper_test.go +++ b/x/distribution/keeper/keeper_test.go @@ -3,6 +3,8 @@ package keeper import ( "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" sdk "github.com/cosmos/cosmos-sdk/types" @@ -89,3 +91,20 @@ func TestGetTotalRewards(t *testing.T) { require.Equal(t, expectedRewards, totalRewards) } + +func TestDepositCommunityPoolFunds(t *testing.T) { + // nolint dogsled + ctx, _, bk, keeper, _, _, _ := CreateTestInputAdvanced(t, false, 1000, sdk.NewDecWithPrec(2, 2)) + + amount := sdk.NewCoins(sdk.NewInt64Coin("stake", 100)) + _ = bk.SetCoins(ctx, delAddr1, amount) + + initPool := keeper.GetFeePool(ctx) + assert.Empty(t, initPool.CommunityPool) + + err := keeper.DepositCommunityPoolFunds(ctx, amount, delAddr1) + assert.Nil(t, err) + + assert.Equal(t, initPool.CommunityPool.Add(sdk.NewDecCoins(amount)), keeper.GetFeePool(ctx).CommunityPool) + assert.Empty(t, bk.GetCoins(ctx, delAddr1)) +} diff --git a/x/distribution/types/msg.go b/x/distribution/types/msg.go index a5eb8422be97..8bc8b1a0dd52 100644 --- a/x/distribution/types/msg.go +++ b/x/distribution/types/msg.go @@ -116,3 +116,41 @@ func (msg MsgWithdrawValidatorCommission) ValidateBasic() sdk.Error { } return nil } + +// msg struct for delegation withdraw from a single validator +type MsgDepositIntoCommunityPool struct { + Amount sdk.Coins `json:"amount" yaml:"amount"` + Depositor sdk.AccAddress `json:"depositor" yaml:"depositor"` +} + +func NewMsgDepositIntoCommunityPool(amount sdk.Coins, depositor sdk.AccAddress) MsgDepositIntoCommunityPool { + return MsgDepositIntoCommunityPool{ + Amount: amount, + Depositor: depositor, + } +} + +func (msg MsgDepositIntoCommunityPool) Route() string { return ModuleName } +func (msg MsgDepositIntoCommunityPool) Type() string { return "deposit_into_community_pool" } + +// Return address that must sign over msg.GetSignBytes() +func (msg MsgDepositIntoCommunityPool) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Depositor} +} + +// get the bytes for the message signer to sign on +func (msg MsgDepositIntoCommunityPool) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(msg) + return sdk.MustSortJSON(bz) +} + +// quick validity check +func (msg MsgDepositIntoCommunityPool) ValidateBasic() sdk.Error { + if !msg.Amount.IsValid() { + return sdk.ErrInvalidCoins(msg.Amount.String()) + } + if msg.Depositor.Empty() { + return sdk.ErrInvalidAddress(msg.Depositor.String()) + } + return nil +} diff --git a/x/distribution/types/msg_test.go b/x/distribution/types/msg_test.go index 4fe6125a2cb8..c78931191527 100644 --- a/x/distribution/types/msg_test.go +++ b/x/distribution/types/msg_test.go @@ -72,3 +72,24 @@ func TestMsgWithdrawValidatorCommission(t *testing.T) { } } } + +// test ValidateBasic for MsgDepositIntoCommunityPool +func TestMsgDepositIntoCommunityPool(t *testing.T) { + tests := []struct { + amount sdk.Coins + depositor sdk.AccAddress + expectPass bool + }{ + {sdk.NewCoins(sdk.NewInt64Coin("uatom", 10000)), sdk.AccAddress{}, false}, + {sdk.Coins{sdk.NewInt64Coin("uatom", 10), sdk.NewInt64Coin("uatom", 10)}, delAddr1, false}, + {sdk.NewCoins(sdk.NewInt64Coin("uatom", 1000)), delAddr1, true}, + } + for i, tc := range tests { + msg := NewMsgDepositIntoCommunityPool(tc.amount, tc.depositor) + if tc.expectPass { + require.Nil(t, msg.ValidateBasic(), "test index: %v", i) + } else { + require.NotNil(t, msg.ValidateBasic(), "test index: %v", i) + } + } +} From bcca045caf49e9d6dc2b586415422b217ee686e0 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Tue, 10 Dec 2019 23:02:15 -0500 Subject: [PATCH 020/529] Merge PR #5384: Fund Community Pool -- Part II --- simapp/params/weights.go | 1 + x/distribution/alias.go | 2 + x/distribution/client/cli/tx.go | 11 +++-- x/distribution/client/rest/tx.go | 8 +++- x/distribution/handler.go | 8 ++-- x/distribution/keeper/keeper.go | 7 ++- x/distribution/keeper/keeper_test.go | 4 +- x/distribution/simulation/operations.go | 61 +++++++++++++++++++++++++ x/distribution/types/msg.go | 35 +++++++++----- x/distribution/types/msg_test.go | 2 +- 10 files changed, 113 insertions(+), 26 deletions(-) diff --git a/simapp/params/weights.go b/simapp/params/weights.go index adff26b8a288..0ba377b009b1 100644 --- a/simapp/params/weights.go +++ b/simapp/params/weights.go @@ -7,6 +7,7 @@ const ( DefaultWeightMsgSetWithdrawAddress int = 50 DefaultWeightMsgWithdrawDelegationReward int = 50 DefaultWeightMsgWithdrawValidatorCommission int = 50 + DefaultWeightMsgFundCommunityPool int = 50 DefaultWeightMsgDeposit int = 100 DefaultWeightMsgVote int = 67 DefaultWeightMsgUnjail int = 100 diff --git a/x/distribution/alias.go b/x/distribution/alias.go index 466674a492dd..d55d88dd3eed 100644 --- a/x/distribution/alias.go +++ b/x/distribution/alias.go @@ -37,6 +37,7 @@ const ( ParamBaseProposerReward = types.ParamBaseProposerReward ParamBonusProposerReward = types.ParamBonusProposerReward ParamWithdrawAddrEnabled = types.ParamWithdrawAddrEnabled + TypeMsgFundCommunityPool = types.TypeMsgFundCommunityPool ) var ( @@ -90,6 +91,7 @@ var ( NewMsgSetWithdrawAddress = types.NewMsgSetWithdrawAddress NewMsgWithdrawDelegatorReward = types.NewMsgWithdrawDelegatorReward NewMsgWithdrawValidatorCommission = types.NewMsgWithdrawValidatorCommission + MsgFundCommunityPool = types.NewMsgFundCommunityPool NewCommunityPoolSpendProposal = types.NewCommunityPoolSpendProposal NewQueryValidatorOutstandingRewardsParams = types.NewQueryValidatorOutstandingRewardsParams NewQueryValidatorCommissionParams = types.NewQueryValidatorCommissionParams diff --git a/x/distribution/client/cli/tx.go b/x/distribution/client/cli/tx.go index b73244d61c08..29d0c17fc263 100644 --- a/x/distribution/client/cli/tx.go +++ b/x/distribution/client/cli/tx.go @@ -261,12 +261,13 @@ Where proposal.json contains: return cmd } -// command to fund the community pool +// GetCmdFundCommunityPool returns a command implementation that supports directly +// funding the community pool. func GetCmdFundCommunityPool(cdc *codec.Codec) *cobra.Command { return &cobra.Command{ Use: "fund-community-pool [amount]", Args: cobra.ExactArgs(1), - Short: "funds the community pool with the specified amount", + Short: "Funds the community pool with the specified amount", Long: strings.TrimSpace( fmt.Sprintf(`Funds the community pool with the specified amount @@ -287,7 +288,11 @@ $ %s tx fund-community-pool 100uatom --from mykey return err } - msg := types.NewMsgDepositIntoCommunityPool(amount, depositorAddr) + msg := types.NewMsgFundCommunityPool(amount, depositorAddr) + if err := msg.ValidateBasic(); err != nil { + return err + } + return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) }, } diff --git a/x/distribution/client/rest/tx.go b/x/distribution/client/rest/tx.go index 6044e150ed11..ace2c11a7aba 100644 --- a/x/distribution/client/rest/tx.go +++ b/x/distribution/client/rest/tx.go @@ -188,7 +188,6 @@ func withdrawValidatorRewardsHandlerFn(cliCtx context.CLIContext) http.HandlerFu } } -// Fund the community pool func fundCommunityPoolHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req fundCommunityPoolReq @@ -207,7 +206,12 @@ func fundCommunityPoolHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return } - msg := types.NewMsgDepositIntoCommunityPool(req.Amount, fromAddr) + msg := types.NewMsgFundCommunityPool(req.Amount, fromAddr) + if err := msg.ValidateBasic(); err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + utils.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) } } diff --git a/x/distribution/handler.go b/x/distribution/handler.go index d2561241160d..90c4bc14de93 100644 --- a/x/distribution/handler.go +++ b/x/distribution/handler.go @@ -23,8 +23,8 @@ func NewHandler(k keeper.Keeper) sdk.Handler { case types.MsgWithdrawValidatorCommission: return handleMsgWithdrawValidatorCommission(ctx, msg, k) - case types.MsgDepositIntoCommunityPool: - return handleMsgDepositIntoCommunityPool(ctx, msg, k) + case types.MsgFundCommunityPool: + return handleMsgFundCommunityPool(ctx, msg, k) default: errMsg := fmt.Sprintf("unrecognized distribution message type: %T", msg) @@ -86,8 +86,8 @@ func handleMsgWithdrawValidatorCommission(ctx sdk.Context, msg types.MsgWithdraw return sdk.Result{Events: ctx.EventManager().Events()} } -func handleMsgDepositIntoCommunityPool(ctx sdk.Context, msg types.MsgDepositIntoCommunityPool, k keeper.Keeper) sdk.Result { - if err := k.DepositCommunityPoolFunds(ctx, msg.Amount, msg.Depositor); err != nil { +func handleMsgFundCommunityPool(ctx sdk.Context, msg types.MsgFundCommunityPool, k keeper.Keeper) sdk.Result { + if err := k.FundCommunityPool(ctx, msg.Amount, msg.Depositor); err != nil { return sdk.ResultFromError(err) } diff --git a/x/distribution/keeper/keeper.go b/x/distribution/keeper/keeper.go index a36834fb7c75..6aca0d86fa10 100644 --- a/x/distribution/keeper/keeper.go +++ b/x/distribution/keeper/keeper.go @@ -150,8 +150,11 @@ func (k Keeper) GetTotalRewards(ctx sdk.Context) (totalRewards sdk.DecCoins) { return totalRewards } -// DepositCommunityPoolFunds allows to transfer the specified amount from the sender into the community pool -func (k Keeper) DepositCommunityPoolFunds(ctx sdk.Context, amount sdk.Coins, sender sdk.AccAddress) error { +// FundCommunityPool allows an account to directly fund the community fund pool. +// The amount is first added to the distribution module account and then directly +// added to the pool. An error is returned if the amount cannot be sent to the +// module account. +func (k Keeper) FundCommunityPool(ctx sdk.Context, amount sdk.Coins, sender sdk.AccAddress) error { if err := k.supplyKeeper.SendCoinsFromAccountToModule(ctx, sender, types.ModuleName, amount); err != nil { return err } diff --git a/x/distribution/keeper/keeper_test.go b/x/distribution/keeper/keeper_test.go index a493e4fea6dd..f0421d80ee5a 100644 --- a/x/distribution/keeper/keeper_test.go +++ b/x/distribution/keeper/keeper_test.go @@ -92,7 +92,7 @@ func TestGetTotalRewards(t *testing.T) { require.Equal(t, expectedRewards, totalRewards) } -func TestDepositCommunityPoolFunds(t *testing.T) { +func TestFundCommunityPool(t *testing.T) { // nolint dogsled ctx, _, bk, keeper, _, _, _ := CreateTestInputAdvanced(t, false, 1000, sdk.NewDecWithPrec(2, 2)) @@ -102,7 +102,7 @@ func TestDepositCommunityPoolFunds(t *testing.T) { initPool := keeper.GetFeePool(ctx) assert.Empty(t, initPool.CommunityPool) - err := keeper.DepositCommunityPoolFunds(ctx, amount, delAddr1) + err := keeper.FundCommunityPool(ctx, amount, delAddr1) assert.Nil(t, err) assert.Equal(t, initPool.CommunityPool.Add(sdk.NewDecCoins(amount)), keeper.GetFeePool(ctx).CommunityPool) diff --git a/x/distribution/simulation/operations.go b/x/distribution/simulation/operations.go index f3875e2560b0..2ec483cbc1ba 100644 --- a/x/distribution/simulation/operations.go +++ b/x/distribution/simulation/operations.go @@ -21,6 +21,7 @@ const ( OpWeightMsgSetWithdrawAddress = "op_weight_msg_set_withdraw_address" OpWeightMsgWithdrawDelegationReward = "op_weight_msg_withdraw_delegation_reward" OpWeightMsgWithdrawValidatorCommission = "op_weight_msg_withdraw_validator_commission" + OpWeightMsgFundCommunityPool = "op_weight_msg_fund_community_pool" ) // WeightedOperations returns all the operations from the module with their respective weights @@ -50,6 +51,13 @@ func WeightedOperations( }, ) + var weightMsgFundCommunityPool int + appParams.GetOrGenerate(cdc, OpWeightMsgFundCommunityPool, &weightMsgFundCommunityPool, nil, + func(_ *rand.Rand) { + weightMsgFundCommunityPool = simappparams.DefaultWeightMsgFundCommunityPool + }, + ) + return simulation.WeightedOperations{ simulation.NewWeightedOperation( weightMsgSetWithdrawAddress, @@ -63,6 +71,10 @@ func WeightedOperations( weightMsgWithdrawValidatorCommission, SimulateMsgWithdrawValidatorCommission(ak, k, sk), ), + simulation.NewWeightedOperation( + weightMsgFundCommunityPool, + SimulateMsgFundCommunityPool(ak, k, sk), + ), } } @@ -197,3 +209,52 @@ func SimulateMsgWithdrawValidatorCommission(ak types.AccountKeeper, k keeper.Kee return simulation.NewOperationMsg(msg, true, ""), nil, nil } } + +// SimulateMsgFundCommunityPool simulates MsgFundCommunityPool execution where +// a random account sends a random amount of its funds to the community pool. +func SimulateMsgFundCommunityPool(ak types.AccountKeeper, k keeper.Keeper, sk stakingkeeper.Keeper) simulation.Operation { + return func( + r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, + ) (simulation.OperationMsg, []simulation.FutureOperation, error) { + + funder, _ := simulation.RandomAcc(r, accs) + + account := ak.GetAccount(ctx, funder.Address) + coins := account.SpendableCoins(ctx.BlockTime()) + + fundAmount := simulation.RandSubsetCoins(r, coins) + if fundAmount.Empty() { + return simulation.NoOpMsg(types.ModuleName), nil, nil + } + + var ( + fees sdk.Coins + err error + ) + + coins, hasNeg := coins.SafeSub(fundAmount) + if !hasNeg { + fees, err = simulation.RandomFees(r, ctx, coins) + if err != nil { + return simulation.NoOpMsg(types.ModuleName), nil, err + } + } + + msg := types.NewMsgFundCommunityPool(fundAmount, funder.Address) + tx := helpers.GenTx( + []sdk.Msg{msg}, + fees, + chainID, + []uint64{account.GetAccountNumber()}, + []uint64{account.GetSequence()}, + funder.PrivKey, + ) + + res := app.Deliver(tx) + if !res.IsOK() { + return simulation.NoOpMsg(types.ModuleName), nil, errors.New(res.Log) + } + + return simulation.NewOperationMsg(msg, true, ""), nil, nil + } +} diff --git a/x/distribution/types/msg.go b/x/distribution/types/msg.go index 8bc8b1a0dd52..408983cb0ff2 100644 --- a/x/distribution/types/msg.go +++ b/x/distribution/types/msg.go @@ -117,40 +117,51 @@ func (msg MsgWithdrawValidatorCommission) ValidateBasic() sdk.Error { return nil } -// msg struct for delegation withdraw from a single validator -type MsgDepositIntoCommunityPool struct { +const TypeMsgFundCommunityPool = "fund_community_pool" + +// MsgFundCommunityPool defines a Msg type that allows an account to directly +// fund the community pool. +type MsgFundCommunityPool struct { Amount sdk.Coins `json:"amount" yaml:"amount"` Depositor sdk.AccAddress `json:"depositor" yaml:"depositor"` } -func NewMsgDepositIntoCommunityPool(amount sdk.Coins, depositor sdk.AccAddress) MsgDepositIntoCommunityPool { - return MsgDepositIntoCommunityPool{ +// NewMsgFundCommunityPool returns a new MsgFundCommunityPool with a sender and +// a funding amount. +func NewMsgFundCommunityPool(amount sdk.Coins, depositor sdk.AccAddress) MsgFundCommunityPool { + return MsgFundCommunityPool{ Amount: amount, Depositor: depositor, } } -func (msg MsgDepositIntoCommunityPool) Route() string { return ModuleName } -func (msg MsgDepositIntoCommunityPool) Type() string { return "deposit_into_community_pool" } +// Route returns the MsgFundCommunityPool message route. +func (msg MsgFundCommunityPool) Route() string { return ModuleName } -// Return address that must sign over msg.GetSignBytes() -func (msg MsgDepositIntoCommunityPool) GetSigners() []sdk.AccAddress { +// Type returns the MsgFundCommunityPool message type. +func (msg MsgFundCommunityPool) Type() string { return TypeMsgFundCommunityPool } + +// GetSigners returns the signer addresses that are expected to sign the result +// of GetSignBytes. +func (msg MsgFundCommunityPool) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.Depositor} } -// get the bytes for the message signer to sign on -func (msg MsgDepositIntoCommunityPool) GetSignBytes() []byte { +// GetSignBytes returns the raw bytes for a MsgFundCommunityPool message that +// the expected signer needs to sign. +func (msg MsgFundCommunityPool) GetSignBytes() []byte { bz := ModuleCdc.MustMarshalJSON(msg) return sdk.MustSortJSON(bz) } -// quick validity check -func (msg MsgDepositIntoCommunityPool) ValidateBasic() sdk.Error { +// ValidateBasic performs basic MsgFundCommunityPool message validation. +func (msg MsgFundCommunityPool) ValidateBasic() sdk.Error { if !msg.Amount.IsValid() { return sdk.ErrInvalidCoins(msg.Amount.String()) } if msg.Depositor.Empty() { return sdk.ErrInvalidAddress(msg.Depositor.String()) } + return nil } diff --git a/x/distribution/types/msg_test.go b/x/distribution/types/msg_test.go index c78931191527..324626178d04 100644 --- a/x/distribution/types/msg_test.go +++ b/x/distribution/types/msg_test.go @@ -85,7 +85,7 @@ func TestMsgDepositIntoCommunityPool(t *testing.T) { {sdk.NewCoins(sdk.NewInt64Coin("uatom", 1000)), delAddr1, true}, } for i, tc := range tests { - msg := NewMsgDepositIntoCommunityPool(tc.amount, tc.depositor) + msg := NewMsgFundCommunityPool(tc.amount, tc.depositor) if tc.expectPass { require.Nil(t, msg.ValidateBasic(), "test index: %v", i) } else { From 891e3604bf69541784aee639cda3ed58c84e705d Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 11 Dec 2019 10:35:11 +0100 Subject: [PATCH 021/529] Bump github.com/mattn/go-isatty from 0.0.10 to 0.0.11 (#5387) Bumps [github.com/mattn/go-isatty](https://github.com/mattn/go-isatty) from 0.0.10 to 0.0.11. - [Release notes](https://github.com/mattn/go-isatty/releases) - [Commits](https://github.com/mattn/go-isatty/compare/v0.0.10...v0.0.11) Signed-off-by: dependabot-preview[bot] --- go.mod | 2 +- go.sum | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 9a659ce9dd40..93c6f3b209e9 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/golang/mock v1.3.1-0.20190508161146-9fa652df1129 github.com/gorilla/mux v1.7.3 github.com/hashicorp/golang-lru v0.5.3 - github.com/mattn/go-isatty v0.0.10 + github.com/mattn/go-isatty v0.0.11 github.com/pelletier/go-toml v1.6.0 github.com/pkg/errors v0.8.1 github.com/rakyll/statik v0.1.6 diff --git a/go.sum b/go.sum index bc31fcd7f750..e83a49d31f82 100644 --- a/go.sum +++ b/go.sum @@ -156,6 +156,8 @@ github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzR github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= @@ -316,6 +318,8 @@ golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be h1:QAcqgptGM8IQBC9K/RC4o+O9YmqEm0diQn9QmZw/0mU= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= From 394860068db0ffb04a57b96288426e00637f7b27 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Wed, 11 Dec 2019 09:45:26 +0000 Subject: [PATCH 022/529] keyring's encrypted file backend integration (#5355) Client commands accept a new `--keyring-backend` option through which users can specify which backend should be used by the new key store: - os: use OS default credentials storage (default). - file: use encrypted file-based store. - test: use password-less key store (highly insecure). --- CHANGELOG.md | 6 +++++ Makefile | 1 - client/alias.go | 5 ++++ client/config.go | 11 ++++---- client/flags/flags.go | 10 +++++++- client/keys/export.go | 3 +-- client/keys/import.go | 3 +-- client/keys/root.go | 3 +++ client/keys/root_test.go | 9 +++++++ client/keys/utils.go | 18 +++++++++----- client/keys/utils_test.go | 25 +++++++++++++++++++ crypto/keys/README.md | 47 +++++++++++++++++++++++++++++++++++ crypto/keys/keyring.go | 43 ++++++++++++++++++++++++++------ crypto/keys/keyring_test.go | 9 +++++++ x/genutil/client/cli/gentx.go | 3 +++ 15 files changed, 171 insertions(+), 25 deletions(-) create mode 100644 client/keys/utils_test.go create mode 100644 crypto/keys/README.md diff --git a/CHANGELOG.md b/CHANGELOG.md index da4abf38ce45..c98332bea017 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -84,6 +84,7 @@ if the provided arguments are invalid. * (x/auth) [\#5006](https://github.com/cosmos/cosmos-sdk/pull/5006) The gas required to pass the `AnteHandler` has increased significantly due to modular `AnteHandler` support. Increase GasLimit accordingly. * (rest) [\#5336](https://github.com/cosmos/cosmos-sdk/issues/5336) `MsgEditValidator` uses `description` instead of `Description` as a JSON key. +* (keys) [\#5097](https://github.com/cosmos/cosmos-sdk/pull/5097) Due to the keybase -> keyring transition, keys need to be migrated. See `keys migrate` command for more info. ### Features @@ -104,6 +105,11 @@ the following [issue](https://github.com/keybase/go-keychain/issues/47) with the you encounter this issue, you must upgrade your xcode command line tools to version >= `10.2`. You can upgrade via: `sudo rm -rf /Library/Developer/CommandLineTools; xcode-select --install`. Verify the correct version via: `pkgutil --pkg-info=com.apple.pkg.CLTools_Executables`. +* [\#5355](https://github.com/cosmos/cosmos-sdk/pull/5355) Client commands accept a new `--keyring-backend` option through which users can specify which backend should be used +by the new key store: + - `os`: use OS default credentials storage (default). + - `file`: use encrypted file-based store. + - `test`: use password-less key store. *For testing purposes only. Use it at your own risk.* * (keys) [\#5097](https://github.com/cosmos/cosmos-sdk/pull/5097) New `keys migrate` command to assist users migrate their keys to the new keyring. * (keys) [\#5366](https://github.com/cosmos/cosmos-sdk/pull/5366) `keys list` now accepts a `--list-names` option to list key names only, whilst the `keys delete` diff --git a/Makefile b/Makefile index f02d60c893f9..8d947640f75a 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,6 @@ SIMAPP = ./simapp MOCKS_DIR = $(CURDIR)/tests/mocks export GO111MODULE = on -export COSMOS_SDK_TEST_KEYRING = y all: tools build lint test diff --git a/client/alias.go b/client/alias.go index e2a1caf167a4..eed043c54401 100644 --- a/client/alias.go +++ b/client/alias.go @@ -24,6 +24,7 @@ import ( const ( DefaultGasAdjustment = flags.DefaultGasAdjustment DefaultGasLimit = flags.DefaultGasLimit + DefaultKeyringBackend = flags.DefaultKeyringBackend GasFlagAuto = flags.GasFlagAuto BroadcastBlock = flags.BroadcastBlock BroadcastSync = flags.BroadcastSync @@ -46,12 +47,16 @@ const ( FlagDryRun = flags.FlagDryRun FlagGenerateOnly = flags.FlagGenerateOnly FlagIndentResponse = flags.FlagIndentResponse + FlagKeyringBackend = flags.FlagKeyringBackend FlagListenAddr = flags.FlagListenAddr FlagMaxOpenConnections = flags.FlagMaxOpenConnections FlagRPCReadTimeout = flags.FlagRPCReadTimeout FlagRPCWriteTimeout = flags.FlagRPCWriteTimeout FlagOutputDocument = flags.FlagOutputDocument FlagSkipConfirmation = flags.FlagSkipConfirmation + KeyringBackendFile = flags.KeyringBackendFile + KeyringBackendOS = flags.KeyringBackendOS + KeyringBackendTest = flags.KeyringBackendTest DefaultKeyPass = keys.DefaultKeyPass FlagAddress = keys.FlagAddress FlagPublicKey = keys.FlagPublicKey diff --git a/client/config.go b/client/config.go index 61258d96fe97..226d056fea06 100644 --- a/client/config.go +++ b/client/config.go @@ -20,10 +20,11 @@ const ( ) var configDefaults = map[string]string{ - "chain-id": "", - "output": "text", - "node": "tcp://localhost:26657", - "broadcast-mode": "sync", + "chain-id": "", + "keyring-backend": "os", + "output": "text", + "node": "tcp://localhost:26657", + "broadcast-mode": "sync", } // ConfigCmd returns a CLI command to interactively create an application CLI @@ -98,7 +99,7 @@ func runConfigCmd(cmd *cobra.Command, args []string) error { // set config value for a given key switch key { - case "chain-id", "output", "node", "broadcast-mode": + case "chain-id", "output", "node", "broadcast-mode", "keyring-backend": tree.Set(key, value) case "trace", "trust-node", "indent": diff --git a/client/flags/flags.go b/client/flags/flags.go index 62f2a8d012f9..9451500bfc21 100644 --- a/client/flags/flags.go +++ b/client/flags/flags.go @@ -20,6 +20,12 @@ const ( DefaultGasLimit = 200000 GasFlagAuto = "auto" + // DefaultKeyringBackend + DefaultKeyringBackend = KeyringBackendOS + KeyringBackendFile = "file" + KeyringBackendOS = "os" + KeyringBackendTest = "test" + // BroadcastBlock defines a tx broadcasting mode where the client waits for // the tx to be committed in a block. BroadcastBlock = "block" @@ -54,6 +60,7 @@ const ( FlagRPCWriteTimeout = "write-timeout" FlagOutputDocument = "output-document" // inspired by wget -O FlagSkipConfirmation = "yes" + FlagKeyringBackend = "keyring-backend" ) // LineBreak can be included in a command list to provide a blank line @@ -99,16 +106,17 @@ func PostCommands(cmds ...*cobra.Command) []*cobra.Command { c.Flags().Bool(FlagDryRun, false, "ignore the --gas flag and perform a simulation of a transaction, but don't broadcast it") c.Flags().Bool(FlagGenerateOnly, false, "Build an unsigned transaction and write it to STDOUT (when enabled, the local Keybase is not accessible and the node operates offline)") c.Flags().BoolP(FlagSkipConfirmation, "y", false, "Skip tx broadcasting prompt confirmation") + c.Flags().String(FlagKeyringBackend, DefaultKeyringBackend, "Select keyring's backend (os|file|test)") // --gas can accept integers and "simulate" c.Flags().Var(&GasFlagVar, "gas", fmt.Sprintf( "gas limit to set per-transaction; set to %q to calculate required gas automatically (default %d)", GasFlagAuto, DefaultGasLimit, )) - viper.BindPFlag(FlagTrustNode, c.Flags().Lookup(FlagTrustNode)) viper.BindPFlag(FlagUseLedger, c.Flags().Lookup(FlagUseLedger)) viper.BindPFlag(FlagNode, c.Flags().Lookup(FlagNode)) + viper.BindPFlag(FlagKeyringBackend, c.Flags().Lookup(FlagKeyringBackend)) c.MarkFlagRequired(FlagChainID) } diff --git a/client/keys/export.go b/client/keys/export.go index 393785501b45..dc6be244beec 100644 --- a/client/keys/export.go +++ b/client/keys/export.go @@ -9,14 +9,13 @@ import ( ) func exportKeyCommand() *cobra.Command { - cmd := &cobra.Command{ + return &cobra.Command{ Use: "export ", Short: "Export private keys", Long: `Export a private key from the local keybase in ASCII-armored encrypted format.`, Args: cobra.ExactArgs(1), RunE: runExportCmd, } - return cmd } func runExportCmd(cmd *cobra.Command, args []string) error { diff --git a/client/keys/import.go b/client/keys/import.go index 127479ce994c..1e754b7852f9 100644 --- a/client/keys/import.go +++ b/client/keys/import.go @@ -10,14 +10,13 @@ import ( ) func importKeyCommand() *cobra.Command { - cmd := &cobra.Command{ + return &cobra.Command{ Use: "import ", Short: "Import private keys into the local keybase", Long: "Import a ASCII armored private key into the local keybase.", Args: cobra.ExactArgs(2), RunE: runImportCmd, } - return cmd } func runImportCmd(cmd *cobra.Command, args []string) error { diff --git a/client/keys/root.go b/client/keys/root.go index b95740a2c036..5e54a5263ed4 100644 --- a/client/keys/root.go +++ b/client/keys/root.go @@ -2,6 +2,7 @@ package keys import ( "github.com/spf13/cobra" + "github.com/spf13/viper" "github.com/cosmos/cosmos-sdk/client/flags" ) @@ -31,5 +32,7 @@ func Commands() *cobra.Command { parseKeyStringCommand(), migrateCommand(), ) + cmd.PersistentFlags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|test)") + viper.BindPFlag(flags.FlagKeyringBackend, cmd.Flags().Lookup(flags.FlagKeyringBackend)) return cmd } diff --git a/client/keys/root_test.go b/client/keys/root_test.go index 6794d725e6f0..49681b17e95f 100644 --- a/client/keys/root_test.go +++ b/client/keys/root_test.go @@ -1,9 +1,13 @@ package keys import ( + "os" "testing" + "github.com/spf13/viper" "github.com/stretchr/testify/assert" + + "github.com/cosmos/cosmos-sdk/client/flags" ) func TestCommands(t *testing.T) { @@ -13,3 +17,8 @@ func TestCommands(t *testing.T) { // Commands are registered assert.Equal(t, 11, len(rootCommands.Commands())) } + +func TestMain(m *testing.M) { + viper.Set(flags.FlagKeyringBackend, flags.KeyringBackendTest) + os.Exit(m.Run()) +} diff --git a/client/keys/utils.go b/client/keys/utils.go index 2b2ca06f0e5b..1096ae6e0790 100644 --- a/client/keys/utils.go +++ b/client/keys/utils.go @@ -3,7 +3,6 @@ package keys import ( "fmt" "io" - "os" "path/filepath" "github.com/99designs/keyring" @@ -46,14 +45,21 @@ func NewKeyringFromHomeFlag(input io.Reader) (keys.Keybase, error) { return NewKeyringFromDir(viper.GetString(flags.FlagHome), input) } -// NewKeyBaseFromDir initializes a keyring at a particular dir. -// If the COSMOS_SDK_TEST_KEYRING environment variable is set and not empty it will -// return an on-disk, password-less keyring that could be used for testing purposes. +// NewKeyBaseFromDir initializes a keyring at the given directory. +// If the viper flag flags.FlagKeyringBackend is set to file, it returns an on-disk keyring with +// CLI prompt support only. If flags.FlagKeyringBackend is set to test it will return an on-disk, +// password-less keyring that could be used for testing purposes. func NewKeyringFromDir(rootDir string, input io.Reader) (keys.Keybase, error) { - if os.Getenv("COSMOS_SDK_TEST_KEYRING") != "" { + keyringBackend := viper.GetString(flags.FlagKeyringBackend) + switch keyringBackend { + case flags.KeyringBackendTest: return keys.NewTestKeyring(sdk.GetConfig().GetKeyringServiceName(), rootDir) + case flags.KeyringBackendFile: + return keys.NewKeyringFile(sdk.GetConfig().GetKeyringServiceName(), rootDir, input) + case flags.KeyringBackendOS: + return keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), rootDir, input) } - return keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), rootDir, input) + return nil, fmt.Errorf("unknown keyring backend %q", keyringBackend) } func getLazyKeyBaseFromDir(rootDir string) (keys.Keybase, error) { diff --git a/client/keys/utils_test.go b/client/keys/utils_test.go new file mode 100644 index 000000000000..85fb7b63a116 --- /dev/null +++ b/client/keys/utils_test.go @@ -0,0 +1,25 @@ +package keys + +import ( + "path/filepath" + "strings" + "testing" + + "github.com/spf13/viper" + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/tests" +) + +func TestNewKeyringFromDir(t *testing.T) { + dir, cleanup := tests.NewTestCaseDir(t) + defer cleanup() + viper.Set(flags.FlagKeyringBackend, flags.KeyringBackendTest) + _, err := NewKeyringFromDir(filepath.Join(dir, "test"), nil) + require.NoError(t, err) + viper.Set(flags.FlagKeyringBackend, flags.KeyringBackendFile) + buf := strings.NewReader("password\npassword\n") + _, err = NewKeyringFromDir(filepath.Join(dir, "test"), buf) + require.NoError(t, err) +} diff --git a/crypto/keys/README.md b/crypto/keys/README.md new file mode 100644 index 000000000000..df690636bc2a --- /dev/null +++ b/crypto/keys/README.md @@ -0,0 +1,47 @@ +# Keys API + +[![API Reference](https://godoc.org/github.com/cosmos/cosmos-sdk/crypto/keys?status.svg)](https://godoc.org/github.com/cosmos/cosmos-sdk/crypto/keys) + + +## The Keybase interface + +The [Keybase](https://godoc.org/github.com/cosmos/cosmos-sdk/crypto/keys#Keybase) interface defines +the methods that a type needs to implement to be used as key storage backend. This package provides +few implementations out-of-the-box. + +## Constructors + +### New + +The [New](https://godoc.org/github.com/cosmos/cosmos-sdk/crypto/keys#New) constructor returns +an on-disk implementation backed by LevelDB storage that has been the default implementation used by the SDK until v0.38.0. +Due to [security concerns](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-006-secret-store-replacement.md), we recommend to drop +it in favor of the `NewKeyring` or `NewKeyringFile` constructors. We strongly advise to migrate away from this function as **it may be removed in a future +release**. + +### NewInMemory + +The [NewInMemory](https://godoc.org/github.com/cosmos/cosmos-sdk/crypto/keys#NewInMemory) constructor returns +an implementation backed by an in-memory, goroutine-safe map that we've historically used for testing purposes or on-the-fly +key generation and we consider safe for the aforementioned use cases since the generated keys are discarded when the process +terminates or the type instance is garbage collected. + +### NewKeyring + +The [NewKeyring](https://godoc.org/github.com/cosmos/cosmos-sdk/crypto/keys#NewKeyring) constructor returns +an implementation backed by the [Keyring](https://github.com/99designs/keyring) library, whose aim is to provide a common +abstraction and uniform interface between secret stores available for Windows, macOS, and most GNU/Linux distributions. +The instance returned by this constructor will use the operating system's default credentials store, which will then handle +keys storage operations securely. + +### NewKeyringFile, NewTestKeyring + +Both [NewKeyringFile](https://godoc.org/github.com/cosmos/cosmos-sdk/crypto/keys#NewKeyringFile) and +[NewTestKeyring](https://godoc.org/github.com/cosmos/cosmos-sdk/crypto/keys#NewTestKeyring) constructors return +on-disk implementations backed by the [Keyring](https://github.com/99designs/keyring) `file` backend. +Whilst `NewKeyringFile` returns a secure, encrypted file-based type that requires user's password in order to +function correctly, the implementation returned by `NewTestKeyring` stores keys information in clear text and **must be used +only for testing purposes**. + +`NewKeyringFile` and `NewTestKeyring` store key files in the client home directory's `keyring` +and `keyring-test` subdirectories respectively. diff --git a/crypto/keys/keyring.go b/crypto/keys/keyring.go index 839e15912f2e..28d9aaec8ff1 100644 --- a/crypto/keys/keyring.go +++ b/crypto/keys/keyring.go @@ -26,6 +26,11 @@ import ( "github.com/cosmos/cosmos-sdk/types" ) +const ( + keyringDirName = "keyring" + testKeyringDirName = "keyring-test" +) + var _ Keybase = keyringKeybase{} // keyringKeybase implements the Keybase interface by using the Keyring library @@ -47,6 +52,16 @@ func NewKeyring(name string, dir string, userInput io.Reader) (Keybase, error) { return newKeyringKeybase(db), nil } +// NewKeyringFile creates a new instance of an encrypted file-backed keyring. +func NewKeyringFile(name string, dir string, userInput io.Reader) (Keybase, error) { + db, err := keyring.Open(newFileBackendKeyringConfig(name, dir, userInput)) + if err != nil { + return nil, err + } + + return newKeyringKeybase(db), nil +} + // NewTestKeyring creates a new instance of an on-disk keyring for // testing purposes that does not prompt users for password. func NewTestKeyring(name string, dir string) (Keybase, error) { @@ -458,12 +473,30 @@ func lkbToKeyringConfig(name, dir string, buf io.Reader, test bool) keyring.Conf return keyring.Config{ AllowedBackends: []keyring.BackendType{"file"}, ServiceName: name, - FileDir: dir, + FileDir: filepath.Join(dir, testKeyringDirName), FilePasswordFunc: fakePrompt, } } - realPrompt := func(prompt string) (string, error) { + return keyring.Config{ + ServiceName: name, + FileDir: dir, + FilePasswordFunc: newRealPrompt(dir, buf), + } +} + +func newFileBackendKeyringConfig(name, dir string, buf io.Reader) keyring.Config { + fileDir := filepath.Join(dir, keyringDirName) + return keyring.Config{ + AllowedBackends: []keyring.BackendType{"file"}, + ServiceName: name, + FileDir: fileDir, + FilePasswordFunc: newRealPrompt(fileDir, buf), + } +} + +func newRealPrompt(dir string, buf io.Reader) func(string) (string, error) { + return func(prompt string) (string, error) { keyhashStored := false keyhashFilePath := filepath.Join(dir, "keyhash") @@ -532,12 +565,6 @@ func lkbToKeyringConfig(name, dir string, buf io.Reader, test bool) keyring.Conf return pass, nil } } - - return keyring.Config{ - ServiceName: name, - FileDir: dir, - FilePasswordFunc: realPrompt, - } } func fakePrompt(prompt string) (string, error) { diff --git a/crypto/keys/keyring_test.go b/crypto/keys/keyring_test.go index 0916e0f46e9e..84cfe3816f34 100644 --- a/crypto/keys/keyring_test.go +++ b/crypto/keys/keyring_test.go @@ -2,6 +2,7 @@ package keys import ( + "strings" "testing" "github.com/stretchr/testify/assert" @@ -323,3 +324,11 @@ func TestLazySeedPhraseKeyRing(t *testing.T) { require.Equal(t, info.GetPubKey().Address(), newInfo.GetPubKey().Address()) require.Equal(t, info.GetPubKey(), newInfo.GetPubKey()) } + +func TestNewKeyringFile(t *testing.T) { + dir, cleanup := tests.NewTestCaseDir(t) + defer cleanup() + buf := strings.NewReader("password\npassword\n") + _, err := NewKeyringFile("test", dir, buf) + require.NoError(t, err) +} diff --git a/x/genutil/client/cli/gentx.go b/x/genutil/client/cli/gentx.go index f6a2a334c71b..462969e52ee7 100644 --- a/x/genutil/client/cli/gentx.go +++ b/x/genutil/client/cli/gentx.go @@ -23,6 +23,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" kbkeys "github.com/cosmos/cosmos-sdk/crypto/keys" "github.com/cosmos/cosmos-sdk/server" @@ -194,6 +195,8 @@ func GenTxCmd(ctx *server.Context, cdc *codec.Codec, mbm module.BasicManager, sm cmd.Flags().String(client.FlagOutputDocument, "", "write the genesis transaction JSON document to the given file instead of the default location") cmd.Flags().AddFlagSet(fsCreateValidator) + cmd.Flags().String(client.FlagKeyringBackend, client.DefaultKeyringBackend, "Select keyring's backend (os|file|test)") + viper.BindPFlag(flags.FlagKeyringBackend, cmd.Flags().Lookup(flags.FlagKeyringBackend)) cmd.MarkFlagRequired(client.FlagName) return cmd From 7c9164cdc826fcf8fa682884376ab6e4d9ef4c1e Mon Sep 17 00:00:00 2001 From: gamarin2 Date: Wed, 11 Dec 2019 18:35:27 +0100 Subject: [PATCH 023/529] Final updates for new docs website (#5388) * consolidate intro * start anatomy of sdk app * wokring * working * querier * working * workiiiing * finish * add dep and makefile * Apply suggestions from code review Co-Authored-By: Alessio Treglia * typo * typo * Apply suggestions from code review Co-Authored-By: Alexander Bezobchuk Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Co-Authored-By: Alessio Treglia Co-Authored-By: frog power 4000 * refactor for new module interface * karoly review * Apply suggestions from code review Co-Authored-By: Karoly Albert Szabo Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * encoding * working on baseapp doc * baseapp work * reorg * almost there * finish first draft * remove old files * module doc start * finish intro * working * workinnn * add transactions into core * hans comments * add transactions into core * working * gautier comments * clean * working * consolidate intro * querier * workiiiing * refactor for new module interface * karoly review * working on baseapp doc * baseapp work * reorg * almost there * finish first draft * remove old files * finish intro * workinnn * initial commit after rebase * query-lifecycle and started modules-interfaces * query-lifecycle first draft done * module interfaces first draft * rest and intro skeletons * rest and intro done * small edits and links * comments * revisions * cli.md comments * comments * minor edits * better flow for query lifecycle * add transactions into core * hans comments * add transactions into core * checkout master-docs files * deleted some * remove modules readme * cli.md comments * comments * module-interfaces comments * Merge PR #4857: Add Context concept doc * working * working * finish messages and queries * handler * querier * last comments! * punctuation * querier2 * consolidate intro * querier * workiiiing * refactor for new module interface * karoly review * working on baseapp doc * baseapp work * reorg * almost there * finish first draft * remove old files * finish intro * workinnn * initial commit after rebase * query-lifecycle and started modules-interfaces * query-lifecycle first draft done * module interfaces first draft * rest and intro skeletons * rest and intro done * small edits and links * comments * revisions * cli.md comments * comments * minor edits * better flow for query lifecycle * checkout master-docs files * deleted some * remove modules readme * cli.md comments * comments * module-interfaces comments * keeper * genesis * finish * Apply suggestions from code review Co-Authored-By: Hans Schoenburg * hans review * Update docs/core/baseapp.md Co-Authored-By: Hans Schoenburg * working * last comment * workin * Apply suggestions from code review * encoding and node * almost finish store * finish docs * fixes * fede comments + permalinks * hans review * add more permalinks * update docs theme version (#5239) * R4R: Docs Cleanup (#5246) * start * work * work * work * remove table of content * links intro * fix links * remove junk * cleanup * cleanup * work * finish cleanup * addback readmes * remove nft * fix links * remove dup * remove dup * remove dup * remove dup * remove dup * fix links * add subscribe events * refine rest * index page * sidebar * theme version * theme version * testing netlify * theme version * tooltip example * version * testing code embedding * reverting back * theme version * version * version * version * readme and version * cleanup * redo app anatomy * modules readme, theme version * theme version * fix modules list * theme version * new snippets * modules readme * update docs readme * modify synopsis * version * fix yaml * version * version * version * version * version * version * version * version * version * version * add hide banner * version * version * version * small fixes * modules readme, version * remove hotkeys dep, version * version * version * version * version * version * version * version * slight notice * fix links and hide * permalinks * small clean * version * resolve conflicts, add google analytics * fix merge remants * version * changelog 1/2 * Changelog: docs UI * version * remove merge conflicts * Code: Update link for Contributing to the docs to docs_readme * HTML/CSS: Update layout of homepage footer to match new layout in Figma * version * final modifs * modules, version * modules readme * link to module list from homepage * version * building modules link * version * version * fonts * version * Update post.sh --- docs/.vuepress/config.js | 42 ++++++++++++++++++------- docs/README.md | 24 +++++++------- docs/building-modules/README.md | 3 +- docs/intro/sdk-design.md | 15 +++++---- docs/intro/why-app-specific.md | 3 +- docs/package-lock.json | 31 +++++++++--------- docs/package.json | 3 +- docs/post.sh | 2 +- docs/pre.sh | 2 +- x/README.md | 5 ++- x/auth/spec/01_concepts.md | 4 +++ x/auth/spec/02_state.md | 4 +++ x/auth/spec/03_messages.md | 4 +++ x/auth/spec/03_types.md | 4 +++ x/auth/spec/04_keepers.md | 4 +++ x/auth/spec/05_vesting.md | 4 +++ x/auth/spec/07_params.md | 4 +++ x/auth/spec/README.md | 7 +++++ x/bank/spec/01_state.md | 4 +++ x/bank/spec/02_keepers.md | 4 +++ x/bank/spec/03_messages.md | 4 +++ x/bank/spec/04_events.md | 4 +++ x/bank/spec/05_params.md | 4 +++ x/bank/spec/README.md | 7 +++++ x/crisis/spec/01_state.md | 4 +++ x/crisis/spec/02_messages.md | 4 +++ x/crisis/spec/03_events.md | 4 +++ x/crisis/spec/04_params.md | 4 +++ x/crisis/spec/README.md | 7 +++++ x/distribution/spec/01_concepts.md | 4 +++ x/distribution/spec/02_state.md | 4 +++ x/distribution/spec/03_end_block.md | 4 +++ x/distribution/spec/04_messages.md | 4 +++ x/distribution/spec/05_hooks.md | 4 +++ x/distribution/spec/06_events.md | 4 +++ x/distribution/spec/07_params.md | 4 +++ x/distribution/spec/README.md | 7 +++++ x/evidence/spec/01_concepts.md | 4 +++ x/evidence/spec/02_state.md | 4 +++ x/evidence/spec/03_messages.md | 4 +++ x/evidence/spec/04_events.md | 4 +++ x/evidence/spec/05_params.md | 4 +++ x/evidence/spec/06_begin_block.md | 4 +++ x/evidence/spec/README.md | 9 +++++- x/gov/spec/01_concepts.md | 4 +++ x/gov/spec/02_state.md | 4 +++ x/gov/spec/03_messages.md | 4 +++ x/gov/spec/04_events.md | 4 +++ x/gov/spec/05_future_improvements.md | 4 +++ x/gov/spec/06_params.md | 4 +++ x/gov/spec/README.md | 7 +++++ x/mint/spec/01_concepts.md | 5 +++ x/mint/spec/02_state.md | 4 +++ x/mint/spec/03_begin_block.md | 4 +++ x/mint/spec/04_params.md | 4 +++ x/mint/spec/05_events.md | 4 +++ x/mint/spec/README.md | 7 +++++ x/params/spec/01_keeper.md | 4 +++ x/params/spec/02_subspace.md | 4 +++ x/params/spec/README.md | 7 +++++ x/slashing/spec/01_concepts.md | 4 +++ x/slashing/spec/02_state.md | 4 +++ x/slashing/spec/03_messages.md | 4 +++ x/slashing/spec/04_begin_block.md | 4 +++ x/slashing/spec/05_hooks.md | 8 +++-- x/slashing/spec/06_events.md | 4 +++ x/slashing/spec/07_tombstone.md | 4 +++ x/slashing/spec/08_params.md | 4 +++ x/slashing/spec/README.md | 7 +++++ x/staking/spec/01_state.md | 4 +++ x/staking/spec/02_state_transitions.md | 4 +++ x/staking/spec/03_messages.md | 4 +++ x/staking/spec/04_end_block.md | 4 +++ x/staking/spec/05_hooks.md | 4 +++ x/staking/spec/06_events.md | 4 +++ x/staking/spec/07_params.md | 4 +++ x/staking/spec/README.md | 7 +++++ x/supply/spec/01_concepts.md | 4 +++ x/supply/spec/02_state.md | 4 +++ x/supply/spec/03_future_improvements.md | 4 +++ x/supply/spec/README.md | 7 +++++ x/upgrade/spec/01_concepts.md | 4 +++ x/upgrade/spec/02_state.md | 4 +++ x/upgrade/spec/03_events.md | 4 +++ x/upgrade/spec/README.md | 9 +++++- 85 files changed, 413 insertions(+), 62 deletions(-) diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index 4502495d68f3..5a3d148ec652 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -6,18 +6,31 @@ module.exports = { permalinkSymbol: "" } }, + head: [ + [ + "link", + { + rel: "stylesheet", + type: "text/css", + href: "https://cloud.typography.com/6138116/7255612/css/fonts.css" + } + ], + ], locales: { - '/': { - lang: 'en-US' + "/": { + lang: "en-US" + }, + kr: { + lang: "kr" }, - 'kr': { + kr: { lang: "kr" }, - 'cn': { - lang: 'cn' + cn: { + lang: "cn" }, - 'ru': { - lang: 'ru' + ru: { + lang: "ru" } }, base: process.env.VUEPRESS_BASE || "/", @@ -35,7 +48,7 @@ module.exports = { title: "Modules", directory: true, path: "/modules" - }, + } ] }, { @@ -81,7 +94,7 @@ module.exports = { logo: "/logo-bw.svg", textLink: { text: "cosmos.network", - url: "https://cosmos.network" + url: "/" }, services: [ { @@ -147,7 +160,8 @@ module.exports = { children: [ { title: "Contributing to the docs", - url: "https://github.com/cosmos/cosmos-sdk/tree/master/docs" + url: + "https://github.com/cosmos/cosmos-sdk/blob/master/docs/DOCS_README.md" }, { title: "Source code on GitHub", @@ -164,6 +178,12 @@ module.exports = { { ga: "UA-51029217-12" } + ], + [ + "sitemap", + { + hostname: "https://docs.cosmos.network" + } ] - ], + ] }; diff --git a/docs/README.md b/docs/README.md index 56df7df3c43b..e3346e2013e9 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,7 +1,7 @@ --- layout: index -title: Documentation -description: The Cosmos-SDK is a framework for building blockchain applications in Golang. It is being used to build Gaia, the first implementation of the Cosmos Hub. +title: Cosmos SDK Documentation +description: Cosmos SDK is the world’s most popular framework for building application-specific blockchains. features: - cta: Read title: Introduction to Cosmos SDK @@ -27,7 +27,7 @@ sections: icon: basics url: /basics - title: SDK Core - desc: Read about the core concepts like `baseapp`, the store, or the server. + desc: Read about the core concepts like `baseapp`, the store, or the server. icon: core url: /core - title: Building Modules @@ -41,15 +41,15 @@ sections: - title: Modules desc: Explore existing modules to build your application with. icon: specifications - url: /modules + url: /modules/ stack: - title: Cosmos Hub - desc: Short description about Cosmos Hub, no longer than a few of lines. + desc: The first of thousands of interconnected blockchains on the Cosmos Network. color: "#BA3FD9" label: hub url: http://hub.cosmos.network - title: Tendermint - desc: Short description about Tendermint, no longer than a few of lines. + desc: The leading BFT engine for building blockchains, powering Cosmos SDK. color: "#00BB00" label: core url: http://docs.tendermint.com @@ -66,14 +66,14 @@ footer: ## Reference -- **[Basics](./basics/)**: Documentation on the basic concepts of the Cosmos SDK, like the standard anatomy of an application, the transaction lifecycle and accounts management. -- **[Core](./core/)**: Documentation on the core concepts of the Cosmos SDK, like `baseapp`, the `store` or the `server`. -- **[Building Modules](./building-modules/)**: Important concepts for module developers like `message`s, `keeper`s, `handler`s and `querier`s. -- **[Interfaces](./interfaces/)**: Documentation on building interfaces for Cosmos SDK applications. +- **[Basics](./basics/)**: Documentation on the basic concepts of the Cosmos SDK, like the standard anatomy of an application, the transaction lifecycle and accounts management. +- **[Core](./core/)**: Documentation on the core concepts of the Cosmos SDK, like `baseapp`, the `store` or the `server`. +- **[Building Modules](./building-modules/)**: Important concepts for module developers like `message`s, `keeper`s, `handler`s and `querier`s. +- **[Interfaces](./interfaces/)**: Documentation on building interfaces for Cosmos SDK applications. ## Other Resources -- **[Module Directory](../x/)**: Module implementations and their respective documentation. +- **[Module Directory](../x/)**: Module implementations and their respective documentation. - **[Specifications](./spec/)**: Specifications of modules and other parts of the Cosmos SDK. - **[SDK API Reference](https://godoc.org/github.com/cosmos/cosmos-sdk)**: Godocs of the Cosmos SDK. - **[REST API spec](https://cosmos.network/rpc/)**: List of endpoints to interact with a `gaia` full-node through REST. @@ -92,5 +92,3 @@ Contact us for information about funding an implementation in another language. See [this file](https://github.com/cosmos/cosmos-sdk/blob/master/docs/DOCS_README.md) for details of the build process and considerations when making changes. - - diff --git a/docs/building-modules/README.md b/docs/building-modules/README.md index 732485c74477..5257e5aa2080 100644 --- a/docs/building-modules/README.md +++ b/docs/building-modules/README.md @@ -6,7 +6,7 @@ parent: # Building Modules -This repository contains documentation on concepts developers need to know in order to build modules for Cosmos SDK applications. +This repository contains documentation on concepts developers need to know in order to build modules for Cosmos SDK applications. 1. [Introduction to Cosmos SDK Modules](./intro.md) 2. [`AppModule` Interface and Module Manager](./module-manager.md) @@ -19,4 +19,3 @@ This repository contains documentation on concepts developers need to know in or 9. [Genesis](./genesis.md) 10. [Module Interfaces](./module-interfaces.md) 11. [Standard Module Structure](./structure.md) - diff --git a/docs/intro/sdk-design.md b/docs/intro/sdk-design.md index 0b4f9689f6ed..51cab8c1b336 100644 --- a/docs/intro/sdk-design.md +++ b/docs/intro/sdk-design.md @@ -4,13 +4,13 @@ order: 4 # Main Components of the Cosmos SDK -The Cosmos SDK is a framework that facilitates the development of secure state-machines on top of Tendermint. At its core, the SDK is a boilerplate implementation of the [ABCI](./sdk-app-architecture.md#abci) in Golang. It comes with a [`multistore`](../core/store.md#multistore) to persist data and a [`router`](../core/baseapp.md#routing) to handle transactions. +The Cosmos SDK is a framework that facilitates the development of secure state-machines on top of Tendermint. At its core, the SDK is a boilerplate implementation of the [ABCI](./sdk-app-architecture.md#abci) in Golang. It comes with a [`multistore`](../core/store.md#multistore) to persist data and a [`router`](../core/baseapp.md#routing) to handle transactions. Here is a simplified view of how transactions are handled by an application built on top of the Cosmos SDK when transferred from Tendermint via `DeliverTx`: -1. Decode `transactions` received from the Tendermint consensus engine (remember that Tendermint only deals with `[]bytes`). +1. Decode `transactions` received from the Tendermint consensus engine (remember that Tendermint only deals with `[]bytes`). 2. Extract `messages` from `transactions` and do basic sanity checks. -3. Route each message to the appropriate module so that it can be processed. +3. Route each message to the appropriate module so that it can be processed. 4. Commit state changes. ## `baseapp` @@ -25,7 +25,7 @@ For more on `baseapp`, please click [here](../core/baseapp.md). ## Multistore - The Cosmos SDK provides a [`multistore`](../core/store.md#multisotre) for persisting state. The multistore allows developers to declare any number of [`KVStores`](../core/store.md#base-layer-kvstores). These `KVStores` only accept the `[]byte` type as value and therefore any custom structure needs to be marshalled using [a codec](../core/encoding.md) before being stored. +The Cosmos SDK provides a [`multistore`](../core/store.md#multisotre) for persisting state. The multistore allows developers to declare any number of [`KVStores`](../core/store.md#base-layer-kvstores). These `KVStores` only accept the `[]byte` type as value and therefore any custom structure needs to be marshalled using [a codec](../core/encoding.md) before being stored. The multistore abstraction is used to divide the state in distinct compartments, each managed by its own module. For more on the multistore, click [here](../core/store.md#multistore) @@ -38,9 +38,9 @@ Here is a simplified view of how a transaction is processed by the application o ``` + | - | Transaction relayed from the full-node's Tendermint engine + | Transaction relayed from the full-node's Tendermint engine | to the node's application via DeliverTx - | + | | | +---------------------v--------------------------+ @@ -88,9 +88,8 @@ SDK modules are defined in the `x/` folder of the SDK. Some core modules include - `x/bank`: Used to enable tokens and token transfers. - `x/staking` + `x/slashing`: Used to build Proof-Of-Stake blockchains. -In addition to the already existing modules in `x/`, that anyone can use in their app, the SDK lets you build your own custom modules. You can check an [example of that in the tutorial](https://cosmos.network/docs/tutorial/keeper.html). +In addition to the already existing modules in `x/`, that anyone can use in their app, the SDK lets you build your own custom modules. You can check an [example of that in the tutorial](https://cosmos.network/docs/tutorial/keeper.html). ## Next {hide} Learn more about the [anatomy of an SDK application](../basics/app-anatomy.md) {hide} - diff --git a/docs/intro/why-app-specific.md b/docs/intro/why-app-specific.md index cd37b562126c..b6d88f1176a2 100644 --- a/docs/intro/why-app-specific.md +++ b/docs/intro/why-app-specific.md @@ -1,11 +1,10 @@ --- order: 2 +synopsis: This document explains what application-specific blockchains are, and why developers would want to build one as opposed to writing Smart Contracts. --- # Application-Specific Blockchains -This document explains what application-specific blockchains are, and why developers would want to build one as opposed to writing Smart Contracts. - ## What are application-specific blockchains? Application-specific blockchains are blockchains customized to operate a single application. Instead of building a decentralised application on top of an underlying blockchain like Ethereum, developers build their own blockchain from the ground up. This means building a full-node client, a light-client, and all the necessary interfaces (CLI, REST, ...) to interract with the nodes. diff --git a/docs/package-lock.json b/docs/package-lock.json index 1100a982c2a5..f6c622dc2111 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -877,9 +877,9 @@ "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==" }, "@types/node": { - "version": "12.12.15", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.15.tgz", - "integrity": "sha512-Pv+vWicyFd07Hw/SmNnTUguqrHgDfMtjabvD9sQyxeqbpCEg8CmViLBaVPHtNsoBgZECrRf5/pgV6FJIBrGSjw==" + "version": "12.12.17", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.17.tgz", + "integrity": "sha512-Is+l3mcHvs47sKy+afn2O1rV4ldZFU7W8101cNlOd+MRbjM4Onida8jSZnJdTe/0Pcf25g9BNIUsuugmE6puHA==" }, "@types/q": { "version": "1.5.2", @@ -1135,8 +1135,7 @@ "@vuepress/plugin-google-analytics": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@vuepress/plugin-google-analytics/-/plugin-google-analytics-1.2.0.tgz", - "integrity": "sha512-0zol5D4Efb5GKel7ADO/s65MLtKSLnOEGkeWzuipkWomSQPzP7TJ3+/RcYBnGdyBFHd1BSpTUHGK0b/IGwM3UA==", - "dev": true + "integrity": "sha512-0zol5D4Efb5GKel7ADO/s65MLtKSLnOEGkeWzuipkWomSQPzP7TJ3+/RcYBnGdyBFHd1BSpTUHGK0b/IGwM3UA==" }, "@vuepress/plugin-last-updated": { "version": "1.2.0", @@ -2593,9 +2592,9 @@ "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" }, "copy-webpack-plugin": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-5.0.5.tgz", - "integrity": "sha512-7N68eIoQTyudAuxkfPT7HzGoQ+TsmArN/I3HFwG+lVE3FNzqvZKIiaxtYh4o3BIznioxUvx9j26+Rtsc9htQUQ==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-5.1.0.tgz", + "integrity": "sha512-0sNrj/Sx7/cWA0k7CVQa0sdA/dzCybqSb0+GbhKuQdOlAvnAwgC2osmbAFOAfha7ZXnreoQmCq5oDjG3gP4VHw==", "requires": { "cacache": "^12.0.3", "find-cache-dir": "^2.1.0", @@ -2607,7 +2606,7 @@ "normalize-path": "^3.0.0", "p-limit": "^2.2.1", "schema-utils": "^1.0.0", - "serialize-javascript": "^2.1.0", + "serialize-javascript": "^2.1.2", "webpack-log": "^2.0.0" }, "dependencies": { @@ -8490,15 +8489,15 @@ } }, "terser-webpack-plugin": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.2.tgz", - "integrity": "sha512-fdEb91kR2l+BVgES77N/NTXWZlpX6vX+pYPjnX5grcDYBF2CMnzJiXX4NNlna4l04lvCW39lZ+O/jSvUhHH/ew==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz", + "integrity": "sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA==", "requires": { "cacache": "^12.0.2", "find-cache-dir": "^2.1.0", "is-wsl": "^1.1.0", "schema-utils": "^1.0.0", - "serialize-javascript": "^2.1.1", + "serialize-javascript": "^2.1.2", "source-map": "^0.6.1", "terser": "^4.1.2", "webpack-sources": "^1.4.0", @@ -9164,9 +9163,9 @@ } }, "vuepress-theme-cosmos": { - "version": "1.0.93", - "resolved": "https://registry.npmjs.org/vuepress-theme-cosmos/-/vuepress-theme-cosmos-1.0.93.tgz", - "integrity": "sha512-P8I8RSydfW/cetx0ruYegeDPuX3PkD/M9I8F7LX54rnA9wPrTM4fLo3fl2MYJmY9jh9uStVLGx95IlHqxtwsOA==", + "version": "1.0.103", + "resolved": "https://registry.npmjs.org/vuepress-theme-cosmos/-/vuepress-theme-cosmos-1.0.103.tgz", + "integrity": "sha512-vp/5gTySDgjIaO9xLFeTrj241slW1aNG8GhUHtWPOir07SYQ6iOVSncMvHgUlNs4uSha+/EMIpn8Pg4FF8VSLQ==", "requires": { "@cosmos-ui/vue": "^0.5.16", "@vuepress/plugin-last-updated": "^1.2.0", diff --git a/docs/package.json b/docs/package.json index a8d32367076f..d9ea55727e9d 100644 --- a/docs/package.json +++ b/docs/package.json @@ -14,6 +14,7 @@ "author": "", "license": "ISC", "dependencies": { - "vuepress-theme-cosmos": "^1.0.93" + "@vuepress/plugin-google-analytics": "^1.2.0", + "vuepress-theme-cosmos": "^1.0.103" } } diff --git a/docs/post.sh b/docs/post.sh index 5d8c7ed48737..2662dd1a31f1 100755 --- a/docs/post.sh +++ b/docs/post.sh @@ -1,3 +1,3 @@ #!/usr/bin/env bash -rm -rf modules \ No newline at end of file +rm -rf modules diff --git a/docs/pre.sh b/docs/pre.sh index a71ac0b65d5e..47e4329fbf5c 100755 --- a/docs/pre.sh +++ b/docs/pre.sh @@ -9,4 +9,4 @@ for D in ../x/*; do fi done -cp ../x/README.md modules/ \ No newline at end of file +cat ../x/README.md | sed 's/\.\/x/\/modules/g' | sed 's/spec\/README.md//g' | sed 's/\.\.\/docs\/building-modules\/README\.md/\/building-modules\/intro\.html/g' > ./modules/README.md \ No newline at end of file diff --git a/x/README.md b/x/README.md index a38c7ab3dd31..117075d62a54 100644 --- a/x/README.md +++ b/x/README.md @@ -11,12 +11,11 @@ Here are some production-grade modules that can be used in Cosmos SDK applicatio - [Bank](./x/bank/spec/README.md) - Token transfer functionalities. - [Governance](./x/gov/spec/README.md) - On-chain proposals and voting. - [Staking](./x/staking/spec/README.md) - Proof-of-stake layer for public blockchains. -- [Slashing](.x/slashing/spec/README.md) - Validator punishment mechanisms. -- [Distribution](.x/distribution/spec/README.md) - Fee distribution, and staking token provision distribution. +- [Slashing](./x/slashing/spec/README.md) - Validator punishment mechanisms. +- [Distribution](./x/distribution/spec/README.md) - Fee distribution, and staking token provision distribution. - [Crisis](./x/crisis/spec/README.md) - Halting the blockchain under certain circumstances (e.g. if an invariant is broken). - [Mint](./x/mint/spec/README.md) - Creation of new units of staking token. - [Params](./x/params/spec/README.md) - Globally available parameter store. - [Supply](./x/supply/spec/README.md) - Total token supply of the chain. To learn more about the process of building modules, visit the [building modules reference documentation](../docs/building-modules/README.md). - diff --git a/x/auth/spec/01_concepts.md b/x/auth/spec/01_concepts.md index 6d428d5b079c..1794b1d4fa6e 100644 --- a/x/auth/spec/01_concepts.md +++ b/x/auth/spec/01_concepts.md @@ -1,3 +1,7 @@ +--- +order: 1 +--- + # Concepts ## Gas & Fees diff --git a/x/auth/spec/02_state.md b/x/auth/spec/02_state.md index 203192ac669c..92c030e3f6d2 100644 --- a/x/auth/spec/02_state.md +++ b/x/auth/spec/02_state.md @@ -1,3 +1,7 @@ +--- +order: 2 +--- + # State ## Accounts diff --git a/x/auth/spec/03_messages.md b/x/auth/spec/03_messages.md index 878f9192d613..b4b64ef07e31 100644 --- a/x/auth/spec/03_messages.md +++ b/x/auth/spec/03_messages.md @@ -1,3 +1,7 @@ +--- +order: 3 +--- + # Messages TODO make this file conform to typical messages spec diff --git a/x/auth/spec/03_types.md b/x/auth/spec/03_types.md index 106e1412c1e7..efd0637dbc6b 100644 --- a/x/auth/spec/03_types.md +++ b/x/auth/spec/03_types.md @@ -1,3 +1,7 @@ +--- +order: 4 +--- + # Types Besides accounts (specified in [State](state.md)), the types exposed by the auth module diff --git a/x/auth/spec/04_keepers.md b/x/auth/spec/04_keepers.md index 3eeb0a2530b9..b56dbe0fd0ed 100644 --- a/x/auth/spec/04_keepers.md +++ b/x/auth/spec/04_keepers.md @@ -1,3 +1,7 @@ +--- +order: 5 +--- + # Keepers The auth module only exposes one keeper, the account keeper, which can be used to read and write accounts. diff --git a/x/auth/spec/05_vesting.md b/x/auth/spec/05_vesting.md index 26974ada5c6e..81de8fff3868 100644 --- a/x/auth/spec/05_vesting.md +++ b/x/auth/spec/05_vesting.md @@ -1,3 +1,7 @@ +--- +order: 6 +--- + # Vesting - [Vesting](#vesting) diff --git a/x/auth/spec/07_params.md b/x/auth/spec/07_params.md index b5d9ad9c20dc..a3983eb657d6 100644 --- a/x/auth/spec/07_params.md +++ b/x/auth/spec/07_params.md @@ -1,3 +1,7 @@ +--- +order: 7 +--- + # Parameters The auth module contains the following parameters: diff --git a/x/auth/spec/README.md b/x/auth/spec/README.md index 8dd0a2dd2209..b6627bfe9561 100644 --- a/x/auth/spec/README.md +++ b/x/auth/spec/README.md @@ -1,3 +1,10 @@ +--- +order: 0 +title: "Auth Overview" +parent: + title: "auth" +--- + # `auth` ## Abstract diff --git a/x/bank/spec/01_state.md b/x/bank/spec/01_state.md index b3421b607b30..67050c46112d 100644 --- a/x/bank/spec/01_state.md +++ b/x/bank/spec/01_state.md @@ -1,3 +1,7 @@ +--- +order: 1 +--- + # State Presently, the bank module has no inherent state — it simply reads and writes accounts using the `AccountKeeper` from the `auth` module. diff --git a/x/bank/spec/02_keepers.md b/x/bank/spec/02_keepers.md index 7624c70a5555..45a42e618eb7 100644 --- a/x/bank/spec/02_keepers.md +++ b/x/bank/spec/02_keepers.md @@ -1,3 +1,7 @@ +--- +order: 2 +--- + # Keepers The bank module provides three different exported keeper interfaces which can be passed to other modules which need to read or update account balances. Modules should use the least-permissive interface which provides the functionality they require. diff --git a/x/bank/spec/03_messages.md b/x/bank/spec/03_messages.md index 30c3db2b6c0b..dbdb8e7df0cd 100644 --- a/x/bank/spec/03_messages.md +++ b/x/bank/spec/03_messages.md @@ -1,3 +1,7 @@ +--- +order: 3 +--- + # Messages ## MsgSend diff --git a/x/bank/spec/04_events.md b/x/bank/spec/04_events.md index a7fac11947c8..c5794b7daa06 100644 --- a/x/bank/spec/04_events.md +++ b/x/bank/spec/04_events.md @@ -1,3 +1,7 @@ +--- +order: 4 +--- + # Events The bank module emits the following events: diff --git a/x/bank/spec/05_params.md b/x/bank/spec/05_params.md index d68fad95e987..cd99570fe629 100644 --- a/x/bank/spec/05_params.md +++ b/x/bank/spec/05_params.md @@ -1,3 +1,7 @@ +--- +order: 5 +--- + # Parameters The bank module contains the following parameters: diff --git a/x/bank/spec/README.md b/x/bank/spec/README.md index 1f5ad958a915..9ddad6ea6e9c 100644 --- a/x/bank/spec/README.md +++ b/x/bank/spec/README.md @@ -1,3 +1,10 @@ +--- +order: 0 +title: Bank Overview +parent: + title: "bank" +--- + # `bank` ## Abstract diff --git a/x/crisis/spec/01_state.md b/x/crisis/spec/01_state.md index 1b454ff5afde..9163934cad90 100644 --- a/x/crisis/spec/01_state.md +++ b/x/crisis/spec/01_state.md @@ -1,3 +1,7 @@ +--- +order: 1 +--- + # State ## ConstantFee diff --git a/x/crisis/spec/02_messages.md b/x/crisis/spec/02_messages.md index f6169d2b7cc5..916fba3a24ba 100644 --- a/x/crisis/spec/02_messages.md +++ b/x/crisis/spec/02_messages.md @@ -1,3 +1,7 @@ +--- +order: 2 +--- + # Messages In this section we describe the processing of the crisis messages and the diff --git a/x/crisis/spec/03_events.md b/x/crisis/spec/03_events.md index f645e823b715..92f231c83f66 100644 --- a/x/crisis/spec/03_events.md +++ b/x/crisis/spec/03_events.md @@ -1,3 +1,7 @@ +--- +order: 3 +--- + # Events The crisis module emits the following events: diff --git a/x/crisis/spec/04_params.md b/x/crisis/spec/04_params.md index 19ccc364829c..663ba62d0da7 100644 --- a/x/crisis/spec/04_params.md +++ b/x/crisis/spec/04_params.md @@ -1,3 +1,7 @@ +--- +order: 4 +--- + # Parameters The crisis module contains the following parameters: diff --git a/x/crisis/spec/README.md b/x/crisis/spec/README.md index 48847155135a..73bba46b4eb5 100644 --- a/x/crisis/spec/README.md +++ b/x/crisis/spec/README.md @@ -1,3 +1,10 @@ +--- +order: 0 +title: Crisis Overview +parent: + title: "crisis" +--- + # `crisis` ## Overview diff --git a/x/distribution/spec/01_concepts.md b/x/distribution/spec/01_concepts.md index 38485dcdaf72..720821bb1f62 100644 --- a/x/distribution/spec/01_concepts.md +++ b/x/distribution/spec/01_concepts.md @@ -1,3 +1,7 @@ +--- +order: 1 +--- + # Concepts ## Reference Counting in F1 Fee Distribution diff --git a/x/distribution/spec/02_state.md b/x/distribution/spec/02_state.md index 46832a27b579..2f9629c98b2b 100644 --- a/x/distribution/spec/02_state.md +++ b/x/distribution/spec/02_state.md @@ -1,3 +1,7 @@ +--- +order: 2 +--- + # State ## FeePool diff --git a/x/distribution/spec/03_end_block.md b/x/distribution/spec/03_end_block.md index f5e62a5d8bfc..ffc315b000ce 100644 --- a/x/distribution/spec/03_end_block.md +++ b/x/distribution/spec/03_end_block.md @@ -1,3 +1,7 @@ +--- +order: 3 +--- + # End Block At each `EndBlock`, the fees received are transferred to the distribution `ModuleAccount`, as it's the account the one who keeps track of the flow of coins in (as in this case) and out the module. The fees are also allocated to the proposer, community fund and global pool. When the validator is the proposer of the round, that validator (and their delegators) receives between 1% and 5% of fee rewards, the reserve community tax is then charged, then the remainder is distributed proportionally by voting power to all bonded validators independent of whether they voted (social distribution). Note the social distribution is applied to proposer validator in addition to the proposer reward. diff --git a/x/distribution/spec/04_messages.md b/x/distribution/spec/04_messages.md index 54650fffe78c..45b0877f1f8b 100644 --- a/x/distribution/spec/04_messages.md +++ b/x/distribution/spec/04_messages.md @@ -1,3 +1,7 @@ +--- +order: 4 +--- + # Messages ## MsgWithdrawDelegationRewardsAll diff --git a/x/distribution/spec/05_hooks.md b/x/distribution/spec/05_hooks.md index fac39fb89db9..cf066872cd61 100644 --- a/x/distribution/spec/05_hooks.md +++ b/x/distribution/spec/05_hooks.md @@ -1,3 +1,7 @@ +--- +order: 5 +--- + # Hooks ## Create or modify delegation distribution diff --git a/x/distribution/spec/06_events.md b/x/distribution/spec/06_events.md index 08a22b660f56..303283b32ce1 100644 --- a/x/distribution/spec/06_events.md +++ b/x/distribution/spec/06_events.md @@ -1,3 +1,7 @@ +--- +order: 6 +--- + # Events The distribution module emits the following events: diff --git a/x/distribution/spec/07_params.md b/x/distribution/spec/07_params.md index 563c2c4270c0..4daa7e0cacb9 100644 --- a/x/distribution/spec/07_params.md +++ b/x/distribution/spec/07_params.md @@ -1,3 +1,7 @@ +--- +order: 7 +--- + # Parameters The distribution module contains the following parameters: diff --git a/x/distribution/spec/README.md b/x/distribution/spec/README.md index 7540bcd8997f..c710934bb78b 100644 --- a/x/distribution/spec/README.md +++ b/x/distribution/spec/README.md @@ -1,3 +1,10 @@ +--- +order: 0 +title: Distribution Overview +parent: + title: "distribution" +--- + # `distribution` ## Overview diff --git a/x/evidence/spec/01_concepts.md b/x/evidence/spec/01_concepts.md index b71f493f2dde..d1cb158f1e0b 100644 --- a/x/evidence/spec/01_concepts.md +++ b/x/evidence/spec/01_concepts.md @@ -1,3 +1,7 @@ +--- +order: 1 +--- + # Concepts ## Evidence diff --git a/x/evidence/spec/02_state.md b/x/evidence/spec/02_state.md index 163743a7c829..7541d1d21cfa 100644 --- a/x/evidence/spec/02_state.md +++ b/x/evidence/spec/02_state.md @@ -1,3 +1,7 @@ +--- +order: 2 +--- + # State Currently the `x/evidence` module only stores valid submitted `Evidence` in state. diff --git a/x/evidence/spec/03_messages.md b/x/evidence/spec/03_messages.md index 84b8a844e951..9be381e65b87 100644 --- a/x/evidence/spec/03_messages.md +++ b/x/evidence/spec/03_messages.md @@ -1,3 +1,7 @@ +--- +order: 3 +--- + # Messages ## MsgSubmitEvidence diff --git a/x/evidence/spec/04_events.md b/x/evidence/spec/04_events.md index 1994f2398f6a..d1c701b21e32 100644 --- a/x/evidence/spec/04_events.md +++ b/x/evidence/spec/04_events.md @@ -1,3 +1,7 @@ +--- +order: 4 +--- + # Events The `x/evidence` module emits the following events: diff --git a/x/evidence/spec/05_params.md b/x/evidence/spec/05_params.md index ff30153725c1..d33005e5c474 100644 --- a/x/evidence/spec/05_params.md +++ b/x/evidence/spec/05_params.md @@ -1,3 +1,7 @@ +--- +order: 5 +--- + # Parameters The evidence module contains the following parameters: diff --git a/x/evidence/spec/06_begin_block.md b/x/evidence/spec/06_begin_block.md index 312e2b0e6d3d..b9a53d116d8c 100644 --- a/x/evidence/spec/06_begin_block.md +++ b/x/evidence/spec/06_begin_block.md @@ -1,3 +1,7 @@ +--- +order: 6 +--- + # BeginBlock ## Evidence Handling diff --git a/x/evidence/spec/README.md b/x/evidence/spec/README.md index 9313dc7616ad..b04f704caa95 100644 --- a/x/evidence/spec/README.md +++ b/x/evidence/spec/README.md @@ -1,4 +1,11 @@ -# Evidence Module Specification +--- +order: 0 +title: Evidence Overview +parent: + title: "evidence" +--- + +# `evidence` ## Table of Contents diff --git a/x/gov/spec/01_concepts.md b/x/gov/spec/01_concepts.md index 71b0bb87c71e..cb6210e2786e 100644 --- a/x/gov/spec/01_concepts.md +++ b/x/gov/spec/01_concepts.md @@ -1,3 +1,7 @@ +--- +order: 1 +--- + # Concepts *Disclaimer: This is work in progress. Mechanisms are susceptible to change.* diff --git a/x/gov/spec/02_state.md b/x/gov/spec/02_state.md index d9e44dbba3ee..d647929816aa 100644 --- a/x/gov/spec/02_state.md +++ b/x/gov/spec/02_state.md @@ -1,3 +1,7 @@ +--- +order: 2 +--- + # State ## Parameters and base types diff --git a/x/gov/spec/03_messages.md b/x/gov/spec/03_messages.md index cf6c405e3d65..1df329807934 100644 --- a/x/gov/spec/03_messages.md +++ b/x/gov/spec/03_messages.md @@ -1,3 +1,7 @@ +--- +order: 3 +--- + # Messages ## Proposal Submission diff --git a/x/gov/spec/04_events.md b/x/gov/spec/04_events.md index b2dd73490d94..b2f749db1b19 100644 --- a/x/gov/spec/04_events.md +++ b/x/gov/spec/04_events.md @@ -1,3 +1,7 @@ +--- +order: 4 +--- + # Events The governance module emits the following events: diff --git a/x/gov/spec/05_future_improvements.md b/x/gov/spec/05_future_improvements.md index 51ae179254d9..96af61e84168 100644 --- a/x/gov/spec/05_future_improvements.md +++ b/x/gov/spec/05_future_improvements.md @@ -1,3 +1,7 @@ +--- +order: 5 +--- + # Future Improvements The current documentation only describes the minimum viable product for the diff --git a/x/gov/spec/06_params.md b/x/gov/spec/06_params.md index 4d24d03dfadf..db146b9a854a 100644 --- a/x/gov/spec/06_params.md +++ b/x/gov/spec/06_params.md @@ -1,3 +1,7 @@ +--- +order: 6 +--- + # Parameters The governance module contains the following parameters: diff --git a/x/gov/spec/README.md b/x/gov/spec/README.md index 8276fa72ba2a..846158540858 100644 --- a/x/gov/spec/README.md +++ b/x/gov/spec/README.md @@ -1,3 +1,10 @@ +--- +order: 0 +title: Gov Overview +parent: + title: "gov" +--- + # `gov` ## Abstract diff --git a/x/mint/spec/01_concepts.md b/x/mint/spec/01_concepts.md index 14b2c6abd499..6d952b3d183a 100644 --- a/x/mint/spec/01_concepts.md +++ b/x/mint/spec/01_concepts.md @@ -1,3 +1,8 @@ +--- +order: 0 +title: Overview +--- + # Concepts ## The Minting Mechanism diff --git a/x/mint/spec/02_state.md b/x/mint/spec/02_state.md index 19e6f38ea8c2..f59a146d78d0 100644 --- a/x/mint/spec/02_state.md +++ b/x/mint/spec/02_state.md @@ -1,3 +1,7 @@ +--- +order: 2 +--- + # State ## Minter diff --git a/x/mint/spec/03_begin_block.md b/x/mint/spec/03_begin_block.md index 427c0142ef9e..c2e27ec2a453 100644 --- a/x/mint/spec/03_begin_block.md +++ b/x/mint/spec/03_begin_block.md @@ -1,3 +1,7 @@ +--- +order: 3 +--- + # Begin-Block Minting parameters are recalculated and inflation diff --git a/x/mint/spec/04_params.md b/x/mint/spec/04_params.md index c743045e3846..f87766c4e908 100644 --- a/x/mint/spec/04_params.md +++ b/x/mint/spec/04_params.md @@ -1,3 +1,7 @@ +--- +order: 4 +--- + # Parameters The minting module contains the following parameters: diff --git a/x/mint/spec/05_events.md b/x/mint/spec/05_events.md index a98d8db73d01..c7191eebb132 100644 --- a/x/mint/spec/05_events.md +++ b/x/mint/spec/05_events.md @@ -1,3 +1,7 @@ +--- +order: 5 +--- + # Events The minting module emits the following events: diff --git a/x/mint/spec/README.md b/x/mint/spec/README.md index b4d9a1ddc86b..f8fda23588fb 100644 --- a/x/mint/spec/README.md +++ b/x/mint/spec/README.md @@ -1,3 +1,10 @@ +--- +order: 0 +title: Mint Overview +parent: + title: "mint" +--- + # `mint` ## Contents diff --git a/x/params/spec/01_keeper.md b/x/params/spec/01_keeper.md index 5cfd42caff99..5a257b568188 100644 --- a/x/params/spec/01_keeper.md +++ b/x/params/spec/01_keeper.md @@ -1,3 +1,7 @@ +--- +order: 1 +--- + # Keeper In the app initialization stage, `Keeper.Subspace(Paramspace)` is passed to the user modules, and the subspaces are stored in `Keeper.spaces`. Later it can be retrieved with `Keeper.GetSubspace`, so the keepers holding `Keeper` can access to any subspace. For example, Gov module can take `Keeper` as its argument and modify parameter of any subspace when a `ParameterChangeProposal` is accepted. diff --git a/x/params/spec/02_subspace.md b/x/params/spec/02_subspace.md index 9c2245e0f872..feb395430c80 100644 --- a/x/params/spec/02_subspace.md +++ b/x/params/spec/02_subspace.md @@ -1,3 +1,7 @@ +--- +order: 2 +--- + # Subspace `Subspace` is a prefixed subspace of the parameter store. Each module who use the parameter store will take a `Subspace`, not the `Keeper`, to isolate permission to access. diff --git a/x/params/spec/README.md b/x/params/spec/README.md index 503e6b51d24d..6d8934aa9b0d 100644 --- a/x/params/spec/README.md +++ b/x/params/spec/README.md @@ -1,3 +1,10 @@ +--- +order: 0 +title: Params Overview +parent: + title: "params" +--- + # `params` ## Abstract diff --git a/x/slashing/spec/01_concepts.md b/x/slashing/spec/01_concepts.md index b453cd0452fd..62eca44d8e2b 100644 --- a/x/slashing/spec/01_concepts.md +++ b/x/slashing/spec/01_concepts.md @@ -1,3 +1,7 @@ +--- +order: 1 +--- + # Concepts ## States diff --git a/x/slashing/spec/02_state.md b/x/slashing/spec/02_state.md index 3ef5d108ea43..dbe7055e70d0 100644 --- a/x/slashing/spec/02_state.md +++ b/x/slashing/spec/02_state.md @@ -1,3 +1,7 @@ +--- +order: 2 +--- + # State ## Signing Info (Liveness) diff --git a/x/slashing/spec/03_messages.md b/x/slashing/spec/03_messages.md index ca19c892a901..160c2a332338 100644 --- a/x/slashing/spec/03_messages.md +++ b/x/slashing/spec/03_messages.md @@ -1,3 +1,7 @@ +--- +order: 3 +--- + # Messages In this section we describe the processing of messages for the `slashing` module. diff --git a/x/slashing/spec/04_begin_block.md b/x/slashing/spec/04_begin_block.md index f99aa0d8a50f..17e6d39525fb 100644 --- a/x/slashing/spec/04_begin_block.md +++ b/x/slashing/spec/04_begin_block.md @@ -1,3 +1,7 @@ +--- +order: 4 +--- + # BeginBlock ## Liveness Tracking diff --git a/x/slashing/spec/05_hooks.md b/x/slashing/spec/05_hooks.md index 4963142eefbf..cfb8eabf8658 100644 --- a/x/slashing/spec/05_hooks.md +++ b/x/slashing/spec/05_hooks.md @@ -1,8 +1,12 @@ -## Hooks +--- +order: 5 +--- + +# Hooks In this section we describe the "hooks" - slashing module code that runs when other events happen. -### Validator Bonded +## Validator Bonded Upon successful first-time bonding of a new validator, we create a new `ValidatorSigningInfo` structure for the now-bonded validator, which `StartHeight` of the current block. diff --git a/x/slashing/spec/06_events.md b/x/slashing/spec/06_events.md index 8d4e616c76cd..a56b70c06091 100644 --- a/x/slashing/spec/06_events.md +++ b/x/slashing/spec/06_events.md @@ -1,3 +1,7 @@ +--- +order: 6 +--- + # Tags The slashing module emits the following events/tags: diff --git a/x/slashing/spec/07_tombstone.md b/x/slashing/spec/07_tombstone.md index d6ba47d5f62f..23d4babeeca7 100644 --- a/x/slashing/spec/07_tombstone.md +++ b/x/slashing/spec/07_tombstone.md @@ -1,3 +1,7 @@ +--- +order: 7 +--- + # Staking Tombstone ## Abstract diff --git a/x/slashing/spec/08_params.md b/x/slashing/spec/08_params.md index c68188eb4b7c..1ecb815013a4 100644 --- a/x/slashing/spec/08_params.md +++ b/x/slashing/spec/08_params.md @@ -1,3 +1,7 @@ +--- +order: 8 +--- + # Parameters The slashing module contains the following parameters: diff --git a/x/slashing/spec/README.md b/x/slashing/spec/README.md index c70dc220f16d..07e36acfc185 100644 --- a/x/slashing/spec/README.md +++ b/x/slashing/spec/README.md @@ -1,3 +1,10 @@ +--- +order: 20 +title: Slashing Overview +parent: + title: "slashing" +--- + # `slashing` ## Abstract diff --git a/x/staking/spec/01_state.md b/x/staking/spec/01_state.md index dbf9410ceb2f..890d6925118d 100644 --- a/x/staking/spec/01_state.md +++ b/x/staking/spec/01_state.md @@ -1,3 +1,7 @@ +--- +order: 1 +--- + # State ## LastTotalPower diff --git a/x/staking/spec/02_state_transitions.md b/x/staking/spec/02_state_transitions.md index 76f086f5ebb5..634f5ac85308 100644 --- a/x/staking/spec/02_state_transitions.md +++ b/x/staking/spec/02_state_transitions.md @@ -1,3 +1,7 @@ +--- +order: 2 +--- + # State Transitions This document describes the state transition operations pertaining to: diff --git a/x/staking/spec/03_messages.md b/x/staking/spec/03_messages.md index f20e386f9743..2f9a71521f14 100644 --- a/x/staking/spec/03_messages.md +++ b/x/staking/spec/03_messages.md @@ -1,3 +1,7 @@ +--- +order: 3 +--- + # Messages In this section we describe the processing of the staking messages and the corresponding updates to the state. All created/modified state objects specified by each message are defined within the [state](./02_state.md) section. diff --git a/x/staking/spec/04_end_block.md b/x/staking/spec/04_end_block.md index 9508d9d57591..d42b26704e9e 100644 --- a/x/staking/spec/04_end_block.md +++ b/x/staking/spec/04_end_block.md @@ -1,3 +1,7 @@ +--- +order: 4 +--- + # End-Block Each abci end block call, the operations to update queues and validator set diff --git a/x/staking/spec/05_hooks.md b/x/staking/spec/05_hooks.md index e3c87d7c57fc..10e084e2a5f0 100644 --- a/x/staking/spec/05_hooks.md +++ b/x/staking/spec/05_hooks.md @@ -1,3 +1,7 @@ +--- +order: 5 +--- + # Hooks Other modules may register operations to execute when a certain event has diff --git a/x/staking/spec/06_events.md b/x/staking/spec/06_events.md index 85b498bc372e..5994af5fa3a6 100644 --- a/x/staking/spec/06_events.md +++ b/x/staking/spec/06_events.md @@ -1,3 +1,7 @@ +--- +order: 6 +--- + # Events The staking module emits the following events: diff --git a/x/staking/spec/07_params.md b/x/staking/spec/07_params.md index df44952b49fe..4fdd5ca124e4 100644 --- a/x/staking/spec/07_params.md +++ b/x/staking/spec/07_params.md @@ -1,3 +1,7 @@ +--- +order: 7 +--- + # Parameters The staking module contains the following parameters: diff --git a/x/staking/spec/README.md b/x/staking/spec/README.md index 9e4a9a99e677..c889d06841be 100644 --- a/x/staking/spec/README.md +++ b/x/staking/spec/README.md @@ -1,3 +1,10 @@ +--- +order: 0 +title: Staking Overview +parent: + title: "staking" +--- + # `staking` ## Abstract diff --git a/x/supply/spec/01_concepts.md b/x/supply/spec/01_concepts.md index 69ab038afefd..4cd86bce2dc7 100644 --- a/x/supply/spec/01_concepts.md +++ b/x/supply/spec/01_concepts.md @@ -1,3 +1,7 @@ +--- +order: 1 +--- + # Concepts ## Supply diff --git a/x/supply/spec/02_state.md b/x/supply/spec/02_state.md index d414d5c9414c..65ca6b57aa5f 100644 --- a/x/supply/spec/02_state.md +++ b/x/supply/spec/02_state.md @@ -1,3 +1,7 @@ +--- +order: 2 +--- + # State ## Supply diff --git a/x/supply/spec/03_future_improvements.md b/x/supply/spec/03_future_improvements.md index 5582740f38b8..b4fc078b1ba7 100644 --- a/x/supply/spec/03_future_improvements.md +++ b/x/supply/spec/03_future_improvements.md @@ -1,3 +1,7 @@ +--- +order: 3 +--- + # Future improvements The current supply module only keeps track of the total supply of coins held in the network. diff --git a/x/supply/spec/README.md b/x/supply/spec/README.md index d9ef2b1075d9..833ac1529017 100644 --- a/x/supply/spec/README.md +++ b/x/supply/spec/README.md @@ -1,3 +1,10 @@ +--- +order: 0 +title: Supply Overview +parent: + title: "supply" +--- + # `supply` ## Contents diff --git a/x/upgrade/spec/01_concepts.md b/x/upgrade/spec/01_concepts.md index 2b93738f65af..b5e5c2208c27 100644 --- a/x/upgrade/spec/01_concepts.md +++ b/x/upgrade/spec/01_concepts.md @@ -1,3 +1,7 @@ +--- +order: 1 +--- + # Concepts ## Plan diff --git a/x/upgrade/spec/02_state.md b/x/upgrade/spec/02_state.md index ad2650053854..585e6f0c4c33 100644 --- a/x/upgrade/spec/02_state.md +++ b/x/upgrade/spec/02_state.md @@ -1,3 +1,7 @@ +--- +order: 2 +--- + # State The internal state of the `x/upgrade` module is relatively minimal and simple. The diff --git a/x/upgrade/spec/03_events.md b/x/upgrade/spec/03_events.md index bbfcdddfa69e..7e86d08dae40 100644 --- a/x/upgrade/spec/03_events.md +++ b/x/upgrade/spec/03_events.md @@ -1,3 +1,7 @@ +--- +order: 3 +--- + # Events The `x/upgrade` does not emit any events by itself. Any and all proposal related diff --git a/x/upgrade/spec/README.md b/x/upgrade/spec/README.md index cbe7b5a3bc35..94d352a25bb3 100644 --- a/x/upgrade/spec/README.md +++ b/x/upgrade/spec/README.md @@ -1,4 +1,11 @@ -# Upgrade Module Specification +--- +order: 0 +title: Upgrade Overview +parent: + title: "upgrade" +--- + +# `upgrade` ## Abstract From 5ce4bebf17fe74ed1c3354efca9e489b809c48ad Mon Sep 17 00:00:00 2001 From: Joon Date: Wed, 11 Dec 2019 21:06:45 +0100 Subject: [PATCH 024/529] Merge PR #5230: [ADR: 015] IBC Packet Receiver --- docs/architecture/README.md | 1 + .../adr-015-ibc-packet-receiver.md | 312 ++++++++++++++++++ 2 files changed, 313 insertions(+) create mode 100644 docs/architecture/adr-015-ibc-packet-receiver.md diff --git a/docs/architecture/README.md b/docs/architecture/README.md index f5b6a553305d..f7d2dafeb502 100644 --- a/docs/architecture/README.md +++ b/docs/architecture/README.md @@ -37,4 +37,5 @@ Please add a entry below in your Pull Request for an ADR. - [ADR 010: Modular AnteHandler](./adr-010-modular-antehandler.md) - [ADR 011: Generalize Genesis Accounts](./adr-011-generalize-genesis-accounts.md) - [ADR 012: State Accessors](./adr-012-state-accessors.md) +- [ADR 015: IBC Packet Receiver](./adr-015-ibc-packet-receiver.md) - [ADR 017: Historical Header Module](./adr-017-historical-header-module.md) diff --git a/docs/architecture/adr-015-ibc-packet-receiver.md b/docs/architecture/adr-015-ibc-packet-receiver.md new file mode 100644 index 000000000000..e772c3234c47 --- /dev/null +++ b/docs/architecture/adr-015-ibc-packet-receiver.md @@ -0,0 +1,312 @@ +# ADR 015: IBC Packet Receiver + +## Changelog + +- 2019 Oct 22: Initial Draft + +## Context + +[ICS 26 - Routing Module](https://github.com/cosmos/ics/tree/master/spec/ics-026-routing-module) defines a function [`handlePacketRecv`](https://github.com/cosmos/ics/tree/master/spec/ics-026-routing-module#packet-relay). + +In ICS 26, the routing module is defined as a layer above each application module +which verifies and routes messages to the destination modules. It is possible to +implement it as a separate module, however, we already have functionality to route +messages upon the destination identifiers in the baseapp. This ADR suggests +to utilize existing `baseapp.router` to route packets to application modules. + +Generally, routing module callbacks have two separate steps in them, +verification and execution. This corresponds to the `AnteHandler`-`Handler` +model inside the SDK. We can do the verification inside the `AnteHandler` +in order to increase developer ergonomics by reducing boilerplate +verification code. + +For atomic multi-message transaction, we want to keep the IBC related +state modification to be preserved even the application side state change +reverts. One of the example might be IBC token sending message following with +stake delegation which uses the tokens received by the previous packet message. +If the token receiving fails for any reason, we might not want to keep +executing the transaction, but we also don't want to abort the transaction +or the sequence and commitment will be reverted and the channel will be stuck. +This ADR suggests new `CodeType`, `CodeTxBreak`, to fix this problem. + +## Decision + +`PortKeeper` will have the capability key that is able to access only the +channels bound to the port. Entities that hold a `PortKeeper` will be +able to call the methods on it which are corresponding with the methods with +the same names on the `ChannelKeeper`, but only with the +allowed port. `ChannelKeeper.Port(string, ChannelChecker)` will be defined to +easily construct a capability-safe `PortKeeper`. This will be addressed in +another ADR and we will use insecure `ChannelKeeper` for now. + +`baseapp.runMsgs` will break the loop over the messages if one of the handlers +returns `!Result.IsOK()`. However, the outer logic will write the cached +store if `Result.IsOK() || Result.Code.IsBreak()`. `Result.Code.IsBreak()` if +`Result.Code == CodeTxBreak`. + +```go +func (app *BaseApp) runTx(tx Tx) (result Result) { + msgs := tx.GetMsgs() + + // AnteHandler + if app.anteHandler != nil { + anteCtx, msCache := app.cacheTxContext(ctx) + newCtx, err := app.anteHandler(anteCtx, tx) + if !newCtx.IsZero() { + ctx = newCtx.WithMultiStore(ms) + } + + if err != nil { + // error handling logic + return res + } + + msCache.Write() + } + + // Main Handler + runMsgCtx, msCache := app.cacheTxContext(ctx) + result = app.runMsgs(runMsgCtx, msgs) + // BEGIN modification made in this ADR + if result.IsOK() || result.IsBreak() { + // END + msCache.Write() + } + + return result +} +``` + +The Cosmos SDK will define an `AnteDecorator` for IBC packet receiving. The +`AnteDecorator` will iterate over the messages included in the transaction, type +`switch` to check whether the message contains an incoming IBC packet, and if so +verify the Merkle proof. + +```go +type ProofVerificationDecorator struct { + clientKeeper ClientKeeper + channelKeeper ChannelKeeper +} + +func (pvr ProofVerificationDecorator) AnteHandle(ctx Context, tx Tx, simulate bool, next AnteHandler) (Context, error) { + for _, msg := range tx.GetMsgs() { + var err error + switch msg := msg.(type) { + case client.MsgUpdateClient: + err = pvr.clientKeeper.UpdateClient(msg.ClientID, msg.Header) + case channel.MsgPacket: + err = pvr.channelKeeper.RecvPacket(msg.Packet, msg.Proofs, msg.ProofHeight) + case chanel.MsgAcknowledgement: + err = pvr.channelKeeper.AcknowledgementPacket(msg.Acknowledgement, msg.Proof, msg.ProofHeight) + case channel.MsgTimeoutPacket: + err = pvr.channelKeeper.TimeoutPacket(msg.Packet, msg.Proof, msg.ProofHeight, msg.NextSequenceRecv) + case channel.MsgChannelOpenInit; + err = pvr.channelKeeper.CheckOpen(msg.PortID, msg.ChannelID, msg.Channel) + default: + continue + } + + if err != nil { + return ctx, err + } + } + + return next(ctx, tx, simulate) +} +``` + +Where `MsgUpdateClient`, `MsgPacket`, `MsgAcknowledgement`, `MsgTimeoutPacket` +are `sdk.Msg` types correspond to `handleUpdateClient`, `handleRecvPacket`, +`handleAcknowledgementPacket`, `handleTimeoutPacket` of the routing module, +respectively. + +The side effects of `RecvPacket`, `VerifyAcknowledgement`, +`VerifyTimeout` will be extracted out into separated functions, +`WriteAcknowledgement`, `DeleteCommitment`, `DeleteCommitmentTimeout`, respectively, +which will be called by the application handlers after the execution. + +`WriteAcknowledgement` writes the acknowledgement to the state that can be +verified by the counter-party chain and increments the sequence to prevent +double execution. `DeleteCommitment` will delete the commitment stored, +`DeleteCommitmentTimeout` will delete the commitment and close channel in case +of ordered channel. + +```go +func (keeper ChannelKeeper) WriteAcknowledgement(ctx Context, packet Packet, ack []byte) { + keeper.SetPacketAcknowledgement(ctx, packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence(), ack) + keeper.SetNextSequenceRecv(ctx, packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) +} + +func (keeper ChannelKeeper) DeleteCommitment(ctx Context, packet Packet) { + keeper.deletePacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) +} + +func (keeper ChannelKeeper) DeleteCommitmentTimeout(ctx Context, packet Packet) { + k.deletePacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) + + if channel.Ordering == types.ORDERED [ + channel.State = types.CLOSED + k.SetChannel(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), channel) + } +} +``` + +Each application handler should call respective finalization methods on the `PortKeeper` +in order to increase sequence (in case of packet) or remove the commitment +(in case of acknowledgement and timeout). +Calling those functions implies that the application logic has successfully executed. +However, the handlers can return `Result` with `CodeTxBreak` after calling those methods +which will persist the state changes that has been already done but prevent any further +messages to be executed in case of semantically invalid packet. This will keep the sequence +increased in the previous IBC packets(thus preventing double execution) without +proceeding to the following messages. +In any case the application modules should never return state reverting result, +which will make the channel unable to proceed. + +`ChannelKeeper.CheckOpen` method will be introduced. This will replace `onChanOpen*` defined +under the routing module specification. Instead of define each channel handshake callback +functions, application modules can provide `ChannelChecker` function with the `AppModule` +which will be injected to `ChannelKeeper.Port()` at the top level application. +`CheckOpen` will find the correct `ChennelChecker` using the +`PortID` and call it, which will return an error if it is unacceptable by the application. + +The `ProofVerificationDecorator` will be inserted to the top level application. +It is not safe to make each module responsible to call proof verification +logic, whereas application can misbehave(in terms of IBC protocol) by +mistake. + +The `ProofVerificationDecorator` should come right after the default sybil attack +resistent layer from the current `auth.NewAnteHandler`: + +```go +// add IBC ProofVerificationDecorator to the Chain of +func NewAnteHandler( + ak keeper.AccountKeeper, supplyKeeper types.SupplyKeeper, ibcKeeper ibc.Keeper, + sigGasConsumer SignatureVerificationGasConsumer) sdk.AnteHandler { + return sdk.ChainAnteDecorators( + NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first + ... + NewIncrementSequenceDecorator(ak), + ibcante.ProofVerificationDecorator(ibcKeeper.ClientKeeper, ibcKeeper.ChannelKeeper), // innermost AnteDecorator + ) +} +``` + +The implementation of this ADR will also change the `Data` field of the `Packet` type from `[]byte` (i.e. arbitrary data) to `PacketDataI`. We want to make application modules be able to register custom packet data type which is automatically unmarshaled at `TxDecoder` time and can be simply type switched inside the application handler. Also, by having `GetCommitment()` method instead of manually generate the commitment inside the IBC keeper, the applications can define their own commitment method, including bare bytes, hashing, etc. + +This also removes the `Timeout` field from the `Packet` struct. This is because the `PacketDataI` interface now contains this information. You can see details about this in [ICS04](https://github.com/cosmos/ics/tree/master/spec/ics-004-channel-and-packet-semantics#definitions). + +The `PacketDataI` is the application specific interface that provides information for the execution of the application packet. In the case of ICS20 this would be `denom`, `amount` and `address` + +```go +// PacketDataI defines the standard interface for IBC packet data +type PacketDataI interface { + GetCommitment() []byte // Commitment form that will be stored in the state. + GetTimeoutHeight() uint64 + + ValidateBasic() sdk.Error + Type() string +} +``` + +Example application-side usage: + +```go +type AppModule struct {} + +// CheckChannel will be provided to the ChannelKeeper as ChannelKeeper.Port(module.CheckChannel) +func (module AppModule) CheckChannel(portID, channelID string, channel Channel) error { + if channel.Ordering != UNORDERED { + return ErrUncompatibleOrdering() + } + if channel.CounterpartyPort != "bank" { + return ErrUncompatiblePort() + } + if channel.Version != "" { + return ErrUncompatibleVersion() + } + return nil +} + +func NewHandler(k Keeper) Handler { + return func(ctx Context, msg Msg) Result { + switch msg := msg.(type) { + case MsgTransfer: + return handleMsgTransfer(ctx, k, msg) + case ibc.MsgPacket: + switch data := msg.Packet.Data.(type) { + case PacketDataTransfer: // i.e fulfills the PacketDataI interface + return handlePacketDataTransfer(ctx, k, msg.Packet, data) + } + case ibc.MsgTimeoutPacket: + switch packet := msg.Packet.Data.(type) { + case PacketDataTransfer: // i.e fulfills the PacketDataI interface + return handleTimeoutPacketDataTransfer(ctx, k, msg.Packet) + } + // interface { PortID() string; ChannelID() string; Channel() ibc.Channel } + // MsgChanInit, MsgChanTry implements ibc.MsgChannelOpen + case ibc.MsgChannelOpen: + return handleMsgChannelOpen(ctx, k, msg) + } + } +} + +func handleMsgTransfer(ctx Context, k Keeper, msg MsgTransfer) Result { + err := k.SendTransfer(ctx,msg.PortID, msg.ChannelID, msg.Amount, msg.Sender, msg.Receiver) + if err != nil { + return sdk.ResultFromError(err) + } + + return sdk.Result{} +} + +func handlePacketDataTransfer(ctx Context, k Keeper, packet Packet, data PacketDataTransfer) Result { + err := k.ReceiveTransfer(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetDestinationPort(), packet.GetDestinationChannel(), data) + if err != nil { + // TODO: Source chain sent invalid packet, shutdown channel + } + k.ChannelKeeper.WriteAcknowledgement([]byte{0x00}) // WriteAcknowledgement increases the sequence, preventing double spending + return sdk.Result{} +} + +func handleCustomTimeoutPacket(ctx Context, k Keeper, packet CustomPacket) Result { + err := k.RecoverTransfer(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetDestinationPort(), packet.GetDestinationChannel(), data) + if err != nil { + // This chain sent invalid packet or cannot recover the funds + panic(err) + } + k.ChannelKeeper.DeleteCommitmentTimeout(ctx, packet) + // packet timeout should not fail + return sdk.Result{} +} + +func handleMsgChannelOpen(sdk.Context, k Keeper, msg MsgOpenChannel) Result { + k.AllocateEscrowAddress(ctx, msg.ChannelID()) + return sdk.Result{} +} +``` + +## Status + +Proposed + +## Consequences + +### Positive + +- Intuitive interface for developers - IBC handlers do not need to care about IBC authentication +- State change commitment logic is embedded into `baseapp.runTx` logic + +### Negative + +- Cannot support dynamic ports, routing is tied to the baseapp router + +### Neutral + +- Introduces new `AnteHandler` decorator. +- Dynamic ports can be supported using hierarchical port identifier, see #5290 for detail + +## References + +- Relevant comment: [cosmos/ics#289](https://github.com/cosmos/ics/issues/289#issuecomment-544533583) +- [ICS26 - Routing Module](https://github.com/cosmos/ics/blob/master/spec/ics-026-routing-module) From 5e89009e561d8c251690263996421e1cb2b61636 Mon Sep 17 00:00:00 2001 From: gamarin2 Date: Wed, 11 Dec 2019 23:58:22 +0100 Subject: [PATCH 025/529] Bump font weight docs website and fix link (#5391) --- README.md | 4 ++-- docs/README.md | 12 ++++++------ docs/package-lock.json | 8 ++++---- docs/package.json | 4 ++-- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 25dae82fdf76..10090dd2dace 100644 --- a/README.md +++ b/README.md @@ -26,9 +26,9 @@ breaking changes. ## Quick Start -To learn how the SDK works from a high-level perspective, go to the [SDK Intro](./docs/intro/intro.md). +To learn how the SDK works from a high-level perspective, go to the [SDK Intro](./docs/intro/overview.md). -If you want to get started quickly and learn how to build on top of the SDK, please follow the [SDK Application Tutorial](https://github.com/cosmos/sdk-application-tutorial). You can also fork the tutorial's repository to get started building your own Cosmos SDK application. +If you want to get started quickly and learn how to build on top of the SDK, please follow the [SDK Application Tutorial](https://tutorials.cosmos.network/nameservice/tutorial/00-intro.html). You can also fork the tutorial's repository to get started building your own Cosmos SDK application. For more, please go to the [Cosmos SDK Docs](./docs/). diff --git a/docs/README.md b/docs/README.md index e3346e2013e9..801178b70ce1 100644 --- a/docs/README.md +++ b/docs/README.md @@ -20,24 +20,24 @@ features: sections: - title: Introduction desc: High-level overview of the Cosmos SDK. - url: /intro + url: /intro/overview.html icon: introduction - title: Basics desc: Anatomy of a blockchain, transaction lifecycle, accounts and more. icon: basics - url: /basics - - title: SDK Core + url: /basics/app-anatomy.html + - title: Core Concepts desc: Read about the core concepts like `baseapp`, the store, or the server. icon: core - url: /core + url: /core/baseapp.html - title: Building Modules desc: Discover how to build modules for the Cosmos SDK. icon: modules - url: /building-modules + url: /building-modules/intro.html - title: Interfaces desc: Build interfaces for Cosmos SDK applications. icon: interfaces - url: /interfaces + url: /interfaces/interfaces-intro.html - title: Modules desc: Explore existing modules to build your application with. icon: specifications diff --git a/docs/package-lock.json b/docs/package-lock.json index f6c622dc2111..a6ed27d90813 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -9163,9 +9163,9 @@ } }, "vuepress-theme-cosmos": { - "version": "1.0.103", - "resolved": "https://registry.npmjs.org/vuepress-theme-cosmos/-/vuepress-theme-cosmos-1.0.103.tgz", - "integrity": "sha512-vp/5gTySDgjIaO9xLFeTrj241slW1aNG8GhUHtWPOir07SYQ6iOVSncMvHgUlNs4uSha+/EMIpn8Pg4FF8VSLQ==", + "version": "1.0.104", + "resolved": "https://registry.npmjs.org/vuepress-theme-cosmos/-/vuepress-theme-cosmos-1.0.104.tgz", + "integrity": "sha512-vq7s+eteIqMEbkT1euRjzWRTSbSt1SBljHx5M0mplF3+RwJxtKbqKeN/pGewxz+3+myq+dctttFWbHCGaKmacA==", "requires": { "@cosmos-ui/vue": "^0.5.16", "@vuepress/plugin-last-updated": "^1.2.0", @@ -9697,4 +9697,4 @@ "integrity": "sha1-4Se9nmb9hGvl6rSME5SIL3wOT5g=" } } -} +} \ No newline at end of file diff --git a/docs/package.json b/docs/package.json index d9ea55727e9d..b09d03f7d46f 100644 --- a/docs/package.json +++ b/docs/package.json @@ -15,6 +15,6 @@ "license": "ISC", "dependencies": { "@vuepress/plugin-google-analytics": "^1.2.0", - "vuepress-theme-cosmos": "^1.0.103" + "vuepress-theme-cosmos": "^1.0.104" } -} +} \ No newline at end of file From b8f5b09831a2cda4e5b02c216c587e54818fc260 Mon Sep 17 00:00:00 2001 From: gamarin2 Date: Thu, 12 Dec 2019 01:50:23 +0100 Subject: [PATCH 026/529] One more quickfix to docs (#5394) --- docs/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/README.md b/docs/README.md index 801178b70ce1..4a2a02e78484 100644 --- a/docs/README.md +++ b/docs/README.md @@ -7,10 +7,10 @@ features: title: Introduction to Cosmos SDK desc: Learn about all the parts of the Cosmos SDK. label: 5 min - url: /intro/ + url: /intro/overview.html image: spaceship - cta: Learn - title: SDK Tutorial + title: SDK Tutorials desc: Build a complete blockchain application from scratch. label: 30-40 min special: dark From 96b384b269957d2cdeee5ee266c6505d4c6cf0af Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Thu, 12 Dec 2019 16:58:22 +0500 Subject: [PATCH 027/529] Fix links on homepage, reduce font weight in cards (#5396) --- docs/package-lock.json | 8 ++++---- docs/package.json | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/package-lock.json b/docs/package-lock.json index a6ed27d90813..5ac336064d73 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -9163,9 +9163,9 @@ } }, "vuepress-theme-cosmos": { - "version": "1.0.104", - "resolved": "https://registry.npmjs.org/vuepress-theme-cosmos/-/vuepress-theme-cosmos-1.0.104.tgz", - "integrity": "sha512-vq7s+eteIqMEbkT1euRjzWRTSbSt1SBljHx5M0mplF3+RwJxtKbqKeN/pGewxz+3+myq+dctttFWbHCGaKmacA==", + "version": "1.0.105", + "resolved": "https://registry.npmjs.org/vuepress-theme-cosmos/-/vuepress-theme-cosmos-1.0.105.tgz", + "integrity": "sha512-UZOPEnNuz5r6cB/o75Qj81/n5BOlpDkf+lGpNxo70C1Eqqg/pjzgj3phhxzSvgXbY5bpdCyeXWySQ8zZnnYtPA==", "requires": { "@cosmos-ui/vue": "^0.5.16", "@vuepress/plugin-last-updated": "^1.2.0", @@ -9697,4 +9697,4 @@ "integrity": "sha1-4Se9nmb9hGvl6rSME5SIL3wOT5g=" } } -} \ No newline at end of file +} diff --git a/docs/package.json b/docs/package.json index b09d03f7d46f..f0bdcede3481 100644 --- a/docs/package.json +++ b/docs/package.json @@ -15,6 +15,6 @@ "license": "ISC", "dependencies": { "@vuepress/plugin-google-analytics": "^1.2.0", - "vuepress-theme-cosmos": "^1.0.104" + "vuepress-theme-cosmos": "^1.0.105" } -} \ No newline at end of file +} From d58bf903f41bff183fe8fad262f51840e2d71d28 Mon Sep 17 00:00:00 2001 From: Andrea Giacobino Date: Thu, 12 Dec 2019 16:20:30 +0100 Subject: [PATCH 028/529] Merge PR #5385: fix int overflow error for rand.Intn --- simapp/state.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simapp/state.go b/simapp/state.go index 22a4e53a63f0..8815784b0a60 100644 --- a/simapp/state.go +++ b/simapp/state.go @@ -81,7 +81,7 @@ func AppStateRandomizedFn( var initialStake, numInitiallyBonded int64 appParams.GetOrGenerate( cdc, StakePerAccount, &initialStake, r, - func(r *rand.Rand) { initialStake = int64(r.Intn(1e12)) }, + func(r *rand.Rand) { initialStake = r.Int63n(1e12) }, ) appParams.GetOrGenerate( cdc, InitiallyBondedValidators, &numInitiallyBonded, r, From a7e28dec6a871a062a7fff4cdf69a1d38ecc67a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arda=20G=C3=BC=C3=A7l=C3=BC?= Date: Thu, 12 Dec 2019 18:46:14 +0300 Subject: [PATCH 029/529] Merge PR #5392: Fix typos in the CONTRIBUTING.md --- CONTRIBUTING.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 139c9a4576ec..34789be8e24a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -26,10 +26,10 @@ contributors, the general procedure for contributing has been established: [find](https://github.com/cosmos/cosmos-sdk/issues) an issue you'd like to help with 2. Participate in thoughtful discussion on that issue 3. If you would like to contribute: - 1. If a the issue is a proposal, ensure that the proposal has been accepted - 2. Ensure that nobody else has already begun working on this issue, if they have + 1. If the issue is a proposal, ensure that the proposal has been accepted + 2. Ensure that nobody else has already begun working on this issue. If they have, make sure to contact them to collaborate - 3. If nobody has been assigned the issue and you would like to work on it + 3. If nobody has been assigned for the issue and you would like to work on it, make a comment on the issue to inform the community of your intentions to begin work 4. Follow standard Github best practices: fork the repo, branch from the @@ -120,7 +120,7 @@ To pull in updates from the origin repo, run - `git fetch upstream` - `git rebase upstream/master` (or whatever branch you want) -Please don't make Pull Requests to `master`. +Please don't make Pull Requests from `master`. ## Dependencies @@ -128,7 +128,7 @@ We use [Go 1.11 Modules](https://github.com/golang/go/wiki/Modules) to manage dependency versions. The master branch of every Cosmos repository should just build with `go get`, -which means they should be kept up-to-date with their dependencies so we can +which means they should be kept up-to-date with their dependencies, so we can get away with telling people they can just `go get` our software. Since some dependencies are not under our control, a third party may break our From aa28dca517d8fa6b376bac84ddf2a24d69b6cd60 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Thu, 12 Dec 2019 11:44:54 -0500 Subject: [PATCH 030/529] Merge PR #5399: Fix Uint#LTE --- CHANGELOG.md | 4 +--- types/uint.go | 2 +- types/uint_test.go | 4 +++- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c98332bea017..22a49edab308 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -209,9 +209,9 @@ to detail this new feature and how state transitions occur. * (docs/interfaces/) Add documentation on building interfaces for the Cosmos SDK. * Redesigned user interface that features new dynamically generated sidebar, build-time code embedding from GitHub, new homepage as well as many other improvements. - ### Bug Fixes +* (types) [\#5395](https://github.com/cosmos/cosmos-sdk/issues/5395) Fix `Uint#LTE` * (client) [\#5303](https://github.com/cosmos/cosmos-sdk/issues/5303) Fix ignored error in tx generate only mode. * (iavl) [\#5276](https://github.com/cosmos/cosmos-sdk/issues/5276) Fix potential race condition in `iavlIterator#Close`. * (cli) [\#4763](https://github.com/cosmos/cosmos-sdk/issues/4763) Fix flag `--min-self-delegation` for staking `EditValidator` @@ -221,8 +221,6 @@ to detail this new feature and how state transitions occur. * (baseapp) [\#5350](https://github.com/cosmos/cosmos-sdk/issues/5350) Allow a node to restart successfully after a `halt-height` or `halt-time` has been triggered. - - ## [v0.37.4] - 2019-11-04 ### Improvements diff --git a/types/uint.go b/types/uint.go index a6c4a0abf978..da43f5fb9094 100644 --- a/types/uint.go +++ b/types/uint.go @@ -74,7 +74,7 @@ func (u Uint) GTE(u2 Uint) bool { return u.GT(u2) || u.Equal(u2) } func (u Uint) LT(u2 Uint) bool { return lt(u.i, u2.i) } // LTE returns true if first Uint is lesser than or equal to the second -func (u Uint) LTE(u2 Uint) bool { return !u.GTE(u2) } +func (u Uint) LTE(u2 Uint) bool { return !u.GT(u2) } // Add adds Uint from another func (u Uint) Add(u2 Uint) Uint { return NewUintFromBigInt(new(big.Int).Add(u.i, u2.i)) } diff --git a/types/uint_test.go b/types/uint_test.go index 34fc1780bacc..d371c81369a0 100644 --- a/types/uint_test.go +++ b/types/uint_test.go @@ -141,7 +141,7 @@ func TestArithUint(t *testing.T) { } func TestCompUint(t *testing.T) { - for d := 0; d < 1000; d++ { + for d := 0; d < 10000; d++ { n1 := rand.Uint64() i1 := NewUint(n1) n2 := rand.Uint64() @@ -156,6 +156,8 @@ func TestCompUint(t *testing.T) { {i1.LT(i2), n1 < n2}, {i1.GTE(i2), !i1.LT(i2)}, {!i1.GTE(i2), i1.LT(i2)}, + {i1.LTE(i2), n1 <= n2}, + {i2.LTE(i1), n2 <= n1}, } for tcnum, tc := range cases { From efcd5fd315da956cd37e347067a3e4b4c4c472a5 Mon Sep 17 00:00:00 2001 From: gamarin2 Date: Thu, 12 Dec 2019 20:36:37 +0100 Subject: [PATCH 031/529] Fix module docs ordering (#5400) * add dep and makefile * Apply suggestions from code review Co-Authored-By: Alessio Treglia * typo * typo * Apply suggestions from code review Co-Authored-By: Alexander Bezobchuk Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Co-Authored-By: Alessio Treglia Co-Authored-By: frog power 4000 * refactor for new module interface * karoly review * Apply suggestions from code review Co-Authored-By: Karoly Albert Szabo Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * encoding * working on baseapp doc * baseapp work * reorg * almost there * finish first draft * remove old files * module doc start * finish intro * working * workinnn * add transactions into core * hans comments * add transactions into core * working * gautier comments * clean * working * consolidate intro * querier * workiiiing * refactor for new module interface * karoly review * working on baseapp doc * baseapp work * reorg * almost there * finish first draft * remove old files * finish intro * workinnn * initial commit after rebase * query-lifecycle and started modules-interfaces * query-lifecycle first draft done * module interfaces first draft * rest and intro skeletons * rest and intro done * small edits and links * comments * revisions * cli.md comments * comments * minor edits * better flow for query lifecycle * add transactions into core * hans comments * add transactions into core * checkout master-docs files * deleted some * remove modules readme * cli.md comments * comments * module-interfaces comments * Merge PR #4857: Add Context concept doc * working * working * finish messages and queries * handler * querier * last comments! * punctuation * querier2 * consolidate intro * querier * workiiiing * refactor for new module interface * karoly review * working on baseapp doc * baseapp work * reorg * almost there * finish first draft * remove old files * finish intro * workinnn * initial commit after rebase * query-lifecycle and started modules-interfaces * query-lifecycle first draft done * module interfaces first draft * rest and intro skeletons * rest and intro done * small edits and links * comments * revisions * cli.md comments * comments * minor edits * better flow for query lifecycle * checkout master-docs files * deleted some * remove modules readme * cli.md comments * comments * module-interfaces comments * keeper * genesis * finish * Apply suggestions from code review Co-Authored-By: Hans Schoenburg * hans review * Update docs/core/baseapp.md Co-Authored-By: Hans Schoenburg * working * last comment * workin * Apply suggestions from code review * encoding and node * almost finish store * finish docs * fixes * fede comments + permalinks * hans review * add more permalinks * update docs theme version (#5239) * R4R: Docs Cleanup (#5246) * start * work * work * work * remove table of content * links intro * fix links * remove junk * cleanup * cleanup * work * finish cleanup * addback readmes * remove nft * fix links * remove dup * remove dup * remove dup * remove dup * remove dup * fix links * add subscribe events * refine rest * index page * sidebar * theme version * theme version * testing netlify * theme version * tooltip example * version * testing code embedding * reverting back * theme version * version * version * version * readme and version * cleanup * redo app anatomy * modules readme, theme version * theme version * fix modules list * theme version * new snippets * modules readme * update docs readme * modify synopsis * version * fix yaml * version * version * version * version * version * version * version * version * version * version * add hide banner * version * version * version * small fixes * modules readme, version * remove hotkeys dep, version * version * version * version * version * version * version * version * slight notice * fix links and hide * permalinks * small clean * version * resolve conflicts, add google analytics * fix merge remants * version * changelog 1/2 * Changelog: docs UI * version * remove merge conflicts * Code: Update link for Contributing to the docs to docs_readme * HTML/CSS: Update layout of homepage footer to match new layout in Figma * version * final modifs * modules, version * modules readme * link to module list from homepage * version * building modules link * version * version * fonts * version * version * fix link * fix package.json * links in explore sdk section * core concepts * version * fix order * fix --- x/README.md | 1 + x/mint/spec/01_concepts.md | 3 +-- x/slashing/spec/README.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/x/README.md b/x/README.md index 117075d62a54..8e86008c0ac0 100644 --- a/x/README.md +++ b/x/README.md @@ -1,4 +1,5 @@ --- +order: 0 parent: order: false --- diff --git a/x/mint/spec/01_concepts.md b/x/mint/spec/01_concepts.md index 6d952b3d183a..e4a4884e27ff 100644 --- a/x/mint/spec/01_concepts.md +++ b/x/mint/spec/01_concepts.md @@ -1,6 +1,5 @@ --- -order: 0 -title: Overview +order: 1 --- # Concepts diff --git a/x/slashing/spec/README.md b/x/slashing/spec/README.md index 07e36acfc185..57fc11b941cb 100644 --- a/x/slashing/spec/README.md +++ b/x/slashing/spec/README.md @@ -1,5 +1,5 @@ --- -order: 20 +order: 0 title: Slashing Overview parent: title: "slashing" From 0e28da23e7f0a33dcc9e75166f1c05d3eea161c4 Mon Sep 17 00:00:00 2001 From: Austin Abell Date: Thu, 12 Dec 2019 16:52:24 -0500 Subject: [PATCH 032/529] Interchangable PrivKey implementations in keybase (#5278) Allow for the keybase to be configured to override the implementation of the key that is saved to the keybase. Closes: #4941 --- CHANGELOG.md | 3 ++ client/keys/add.go | 41 ++++++++++------- client/keys/add_ledger_test.go | 4 +- client/keys/add_test.go | 2 +- client/keys/codec.go | 13 +++--- client/keys/delete.go | 3 +- client/keys/delete_test.go | 2 +- client/keys/export.go | 3 +- client/keys/export_test.go | 2 +- client/keys/import.go | 3 +- client/keys/import_test.go | 2 +- client/keys/list.go | 3 +- client/keys/list_test.go | 2 +- client/keys/migrate.go | 3 +- client/keys/migrate_test.go | 4 +- client/keys/mnemonic.go | 3 +- client/keys/mnemonic_test.go | 4 +- client/keys/parse.go | 7 +-- client/keys/root.go | 20 ++++----- client/keys/show.go | 3 +- client/keys/show_test.go | 4 +- client/keys/update.go | 4 +- client/keys/update_test.go | 4 +- client/keys/utils.go | 35 ++++++++------- crypto/keys/codec.go | 14 ++++-- crypto/keys/keybase.go | 7 +-- crypto/keys/keybase_base.go | 38 ++++++++++++++-- crypto/keys/keybase_test.go | 4 +- crypto/keys/keyring.go | 17 ++++--- crypto/keys/lazy_keybase.go | 48 ++++++++++---------- crypto/keys/lazy_keybase_test.go | 77 ++++++++++++++++++++++++++++++++ crypto/keys/types.go | 12 ++++- 32 files changed, 273 insertions(+), 118 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 22a49edab308..5c59ec9a9418 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -76,6 +76,8 @@ if the provided arguments are invalid. `StdTx.Signatures` to get back the array of StdSignatures `[]StdSignature`. * (modules) [\#5299](https://github.com/cosmos/cosmos-sdk/pull/5299) `HandleDoubleSign` along with params `MaxEvidenceAge` and `DoubleSignJailEndTime` have moved from the `x/slashing` module to the `x/evidence` module. +* (keys) [\#4941](https://github.com/cosmos/cosmos-sdk/issues/4941) Initializing a new keybase through `NewKeyringFromHomeFlag`, `NewKeyringFromDir`, `NewKeyBaseFromHomeFlag`, `NewKeyBaseFromDir`, or `NewInMemory` functions now accept optional parameters of type `KeybaseOption`. These optional parameters are also added on the keys subcommands functions, which are now public, and allows these options to be set on the commands or ignored to default to previous behavior. + * The option introduced in this PR is `WithKeygenFunc` which allows a custom bytes to key implementation to be defined when keys are created. ### Client Breaking Changes @@ -146,6 +148,7 @@ that allows for arbitrary vesting periods. * `IncrementSequenceDecorator`: Increments the account sequence for each signer to prevent replay attacks. * (cli) [\#5223](https://github.com/cosmos/cosmos-sdk/issues/5223) Cosmos Ledger App v2.0.0 is now supported. The changes are backwards compatible and App v1.5.x is still supported. * (modules) [\#5249](https://github.com/cosmos/cosmos-sdk/pull/5249) Funds are now allowed to be directly sent to the community pool (via the distribution module account). +* (keys) [\#4941](https://github.com/cosmos/cosmos-sdk/issues/4941) Introduce keybase option to allow overriding the default private key implementation of a key generated through the `keys add` cli command. ### Improvements diff --git a/client/keys/add.go b/client/keys/add.go index f55572887b12..791ba6bc8b3a 100644 --- a/client/keys/add.go +++ b/client/keys/add.go @@ -5,6 +5,7 @@ import ( "bytes" "errors" "fmt" + "io" "sort" bip39 "github.com/bartekn/go-bip39" @@ -36,7 +37,8 @@ const ( DefaultKeyPass = "12345678" ) -func addKeyCommand() *cobra.Command { +// AddKeyCommand defines a keys command to add a generated or recovered private key to keybase. +func AddKeyCommand() *cobra.Command { cmd := &cobra.Command{ Use: "add ", Short: "Add an encrypted private key (either newly generated or recovered), encrypt it, and save to disk", @@ -75,6 +77,24 @@ the flag --nosort is set. return cmd } +func getKeybase(transient bool, buf io.Reader) (keys.Keybase, error) { + if transient { + return keys.NewInMemory(), nil + } + + return NewKeyringFromHomeFlag(buf) +} + +func runAddCmd(cmd *cobra.Command, args []string) error { + inBuf := bufio.NewReader(cmd.InOrStdin()) + kb, err := getKeybase(viper.GetBool(flagDryRun), inBuf) + if err != nil { + return err + } + + return RunAddCmd(cmd, args, kb, inBuf) +} + /* input - bip39 mnemonic @@ -84,26 +104,15 @@ input output - armor encrypted private key (saved to file) */ -func runAddCmd(cmd *cobra.Command, args []string) error { - var kb keys.Keybase +func RunAddCmd(cmd *cobra.Command, args []string, kb keys.Keybase, inBuf *bufio.Reader) error { var err error - inBuf := bufio.NewReader(cmd.InOrStdin()) name := args[0] interactive := viper.GetBool(flagInteractive) showMnemonic := !viper.GetBool(flagNoBackup) - if viper.GetBool(flagDryRun) { - // we throw this away, so don't enforce args, - // we want to get a new random seed phrase quickly - kb = keys.NewInMemory() - } else { - kb, err = NewKeyringFromHomeFlag(cmd.InOrStdin()) - if err != nil { - return err - } - + if !viper.GetBool(flagDryRun) { _, err = kb.Get(name) if err == nil { // account exists, ask for user confirmation @@ -273,9 +282,9 @@ func printCreate(cmd *cobra.Command, info keys.Info, showMnemonic bool, mnemonic var jsonString []byte if viper.GetBool(flags.FlagIndentResponse) { - jsonString, err = cdc.MarshalJSONIndent(out, "", " ") + jsonString, err = KeysCdc.MarshalJSONIndent(out, "", " ") } else { - jsonString, err = cdc.MarshalJSON(out) + jsonString, err = KeysCdc.MarshalJSON(out) } if err != nil { diff --git a/client/keys/add_ledger_test.go b/client/keys/add_ledger_test.go index d33fd4a814d6..184e99597137 100644 --- a/client/keys/add_ledger_test.go +++ b/client/keys/add_ledger_test.go @@ -33,7 +33,7 @@ func Test_runAddCmdLedgerWithCustomCoinType(t *testing.T) { config.SetBech32PrefixForValidator(bech32PrefixValAddr, bech32PrefixValPub) config.SetBech32PrefixForConsensusNode(bech32PrefixConsAddr, bech32PrefixConsPub) - cmd := addKeyCommand() + cmd := AddKeyCommand() require.NotNil(t, cmd) // Prepare a keybase @@ -80,7 +80,7 @@ func Test_runAddCmdLedgerWithCustomCoinType(t *testing.T) { func Test_runAddCmdLedger(t *testing.T) { runningUnattended := isRunningUnattended() - cmd := addKeyCommand() + cmd := AddKeyCommand() require.NotNil(t, cmd) mockIn, _, _ := tests.ApplyMockIO(cmd) diff --git a/client/keys/add_test.go b/client/keys/add_test.go index 3f332a393e4a..d1a7dd04b3e0 100644 --- a/client/keys/add_test.go +++ b/client/keys/add_test.go @@ -15,7 +15,7 @@ import ( func Test_runAddCmdBasic(t *testing.T) { runningUnattended := isRunningUnattended() - cmd := addKeyCommand() + cmd := AddKeyCommand() assert.NotNil(t, cmd) mockIn, _, _ := tests.ApplyMockIO(cmd) diff --git a/client/keys/codec.go b/client/keys/codec.go index eae45446e784..e47d3b231afc 100644 --- a/client/keys/codec.go +++ b/client/keys/codec.go @@ -4,20 +4,21 @@ import ( "github.com/cosmos/cosmos-sdk/codec" ) -var cdc *codec.Codec +// KeysCdc defines codec to be used with key operations +var KeysCdc *codec.Codec func init() { - cdc = codec.New() - codec.RegisterCrypto(cdc) - cdc.Seal() + KeysCdc = codec.New() + codec.RegisterCrypto(KeysCdc) + KeysCdc.Seal() } // marshal keys func MarshalJSON(o interface{}) ([]byte, error) { - return cdc.MarshalJSON(o) + return KeysCdc.MarshalJSON(o) } // unmarshal json func UnmarshalJSON(bz []byte, ptr interface{}) error { - return cdc.UnmarshalJSON(bz, ptr) + return KeysCdc.UnmarshalJSON(bz, ptr) } diff --git a/client/keys/delete.go b/client/keys/delete.go index aadc831fe129..8e607a319ba4 100644 --- a/client/keys/delete.go +++ b/client/keys/delete.go @@ -16,7 +16,8 @@ const ( flagForce = "force" ) -func deleteKeyCommand() *cobra.Command { +// DeleteKeyCommand deletes a key from the key store. +func DeleteKeyCommand() *cobra.Command { cmd := &cobra.Command{ Use: "delete ...", Short: "Delete the given keys", diff --git a/client/keys/delete_test.go b/client/keys/delete_test.go index 537c8073f88a..7593b7f010a3 100644 --- a/client/keys/delete_test.go +++ b/client/keys/delete_test.go @@ -14,7 +14,7 @@ import ( func Test_runDeleteCmd(t *testing.T) { runningUnattended := isRunningUnattended() - deleteKeyCommand := deleteKeyCommand() + deleteKeyCommand := DeleteKeyCommand() mockIn, _, _ := tests.ApplyMockIO(deleteKeyCommand) yesF, _ := deleteKeyCommand.Flags().GetBool(flagYes) diff --git a/client/keys/export.go b/client/keys/export.go index dc6be244beec..761cdc561c37 100644 --- a/client/keys/export.go +++ b/client/keys/export.go @@ -8,7 +8,8 @@ import ( "github.com/cosmos/cosmos-sdk/client/input" ) -func exportKeyCommand() *cobra.Command { +// ExportKeyCommand exports private keys from the key store. +func ExportKeyCommand() *cobra.Command { return &cobra.Command{ Use: "export ", Short: "Export private keys", diff --git a/client/keys/export_test.go b/client/keys/export_test.go index 8132f06a6d55..1279ae537a74 100644 --- a/client/keys/export_test.go +++ b/client/keys/export_test.go @@ -12,7 +12,7 @@ import ( func Test_runExportCmd(t *testing.T) { runningUnattended := isRunningUnattended() - exportKeyCommand := exportKeyCommand() + exportKeyCommand := ExportKeyCommand() mockIn, _, _ := tests.ApplyMockIO(exportKeyCommand) // Now add a temporary keybase diff --git a/client/keys/import.go b/client/keys/import.go index 1e754b7852f9..7fb323c77478 100644 --- a/client/keys/import.go +++ b/client/keys/import.go @@ -9,7 +9,8 @@ import ( "github.com/cosmos/cosmos-sdk/client/input" ) -func importKeyCommand() *cobra.Command { +// ImportKeyCommand imports private keys from a keyfile. +func ImportKeyCommand() *cobra.Command { return &cobra.Command{ Use: "import ", Short: "Import private keys into the local keybase", diff --git a/client/keys/import_test.go b/client/keys/import_test.go index 3579f968634a..aad96b83e8fe 100644 --- a/client/keys/import_test.go +++ b/client/keys/import_test.go @@ -14,7 +14,7 @@ import ( func Test_runImportCmd(t *testing.T) { runningUnattended := isRunningUnattended() - importKeyCommand := importKeyCommand() + importKeyCommand := ImportKeyCommand() mockIn, _, _ := tests.ApplyMockIO(importKeyCommand) // Now add a temporary keybase diff --git a/client/keys/list.go b/client/keys/list.go index 45d29a942699..1954a46de35c 100644 --- a/client/keys/list.go +++ b/client/keys/list.go @@ -9,7 +9,8 @@ import ( const flagListNames = "list-names" -func listKeysCmd() *cobra.Command { +// ListKeysCmd lists all keys in the key store. +func ListKeysCmd() *cobra.Command { cmd := &cobra.Command{ Use: "list", Short: "List all keys", diff --git a/client/keys/list_test.go b/client/keys/list_test.go index 8f4a5b6411b6..129255fd541b 100644 --- a/client/keys/list_test.go +++ b/client/keys/list_test.go @@ -18,7 +18,7 @@ func Test_runListCmd(t *testing.T) { args []string } - cmdBasic := listKeysCmd() + cmdBasic := ListKeysCmd() // Prepare some keybases kbHome1, cleanUp1 := tests.NewTestCaseDir(t) diff --git a/client/keys/migrate.go b/client/keys/migrate.go index 63f4e33b0262..1b7c19f24c24 100644 --- a/client/keys/migrate.go +++ b/client/keys/migrate.go @@ -18,7 +18,8 @@ import ( // is not needed for importing into the Keyring keystore. const migratePassphrase = "NOOP_PASSPHRASE" -func migrateCommand() *cobra.Command { +// MigrateCommand migrates key information from legacy keybase to OS secret store. +func MigrateCommand() *cobra.Command { cmd := &cobra.Command{ Use: "migrate", Short: "Migrate key information from the lagacy key database to the OS secret store, or encrypted file store as a fall-back and save it", diff --git a/client/keys/migrate_test.go b/client/keys/migrate_test.go index 61a55ef90804..0ad9226d309d 100644 --- a/client/keys/migrate_test.go +++ b/client/keys/migrate_test.go @@ -13,7 +13,7 @@ import ( ) func Test_runMigrateCmd(t *testing.T) { - cmd := addKeyCommand() + cmd := AddKeyCommand() assert.NotNil(t, cmd) mockIn, _, _ := tests.ApplyMockIO(cmd) @@ -29,7 +29,7 @@ func Test_runMigrateCmd(t *testing.T) { assert.NoError(t, err) viper.Set(flags.FlagDryRun, true) - cmd = migrateCommand() + cmd = MigrateCommand() mockIn, _, _ = tests.ApplyMockIO(cmd) mockIn.Reset("test1234\n") assert.NoError(t, runMigrateCmd(cmd, []string{})) diff --git a/client/keys/mnemonic.go b/client/keys/mnemonic.go index c5b7f9a08b4e..01d7416f0536 100644 --- a/client/keys/mnemonic.go +++ b/client/keys/mnemonic.go @@ -17,7 +17,8 @@ const ( mnemonicEntropySize = 256 ) -func mnemonicKeyCommand() *cobra.Command { +// MnemonicKeyCommand computes the bip39 memonic for input entropy. +func MnemonicKeyCommand() *cobra.Command { cmd := &cobra.Command{ Use: "mnemonic", Short: "Compute the bip39 mnemonic for some input entropy", diff --git a/client/keys/mnemonic_test.go b/client/keys/mnemonic_test.go index e532c42ddccb..7097ef0a3ca5 100644 --- a/client/keys/mnemonic_test.go +++ b/client/keys/mnemonic_test.go @@ -11,13 +11,13 @@ import ( ) func Test_RunMnemonicCmdNormal(t *testing.T) { - cmdBasic := mnemonicKeyCommand() + cmdBasic := MnemonicKeyCommand() err := runMnemonicCmd(cmdBasic, []string{}) require.NoError(t, err) } func Test_RunMnemonicCmdUser(t *testing.T) { - cmdUser := mnemonicKeyCommand() + cmdUser := MnemonicKeyCommand() err := cmdUser.Flags().Set(flagUserEntropy, "1") assert.NoError(t, err) diff --git a/client/keys/parse.go b/client/keys/parse.go index b76b530ab6cd..79ccca739f0a 100644 --- a/client/keys/parse.go +++ b/client/keys/parse.go @@ -67,7 +67,8 @@ func (bo bech32Output) String() string { return fmt.Sprintf("Bech32 Formats:\n%s", strings.Join(out, "\n")) } -func parseKeyStringCommand() *cobra.Command { +// ParseKeyStringCommand parses an address from hex to bech32 and vice versa. +func ParseKeyStringCommand() *cobra.Command { cmd := &cobra.Command{ Use: "parse ", Short: "Parse address from hex to bech32 and vice versa", @@ -124,9 +125,9 @@ func displayParseKeyInfo(stringer fmt.Stringer) { case OutputFormatJSON: if viper.GetBool(flags.FlagIndentResponse) { - out, err = cdc.MarshalJSONIndent(stringer, "", " ") + out, err = KeysCdc.MarshalJSONIndent(stringer, "", " ") } else { - out = cdc.MustMarshalJSON(stringer) + out = KeysCdc.MustMarshalJSON(stringer) } } diff --git a/client/keys/root.go b/client/keys/root.go index 5e54a5263ed4..b7f70059c015 100644 --- a/client/keys/root.go +++ b/client/keys/root.go @@ -20,17 +20,17 @@ func Commands() *cobra.Command { needs to sign with a private key.`, } cmd.AddCommand( - mnemonicKeyCommand(), - addKeyCommand(), - exportKeyCommand(), - importKeyCommand(), - listKeysCmd(), - showKeysCmd(), + MnemonicKeyCommand(), + AddKeyCommand(), + ExportKeyCommand(), + ImportKeyCommand(), + ListKeysCmd(), + ShowKeysCmd(), flags.LineBreak, - deleteKeyCommand(), - updateKeyCommand(), - parseKeyStringCommand(), - migrateCommand(), + DeleteKeyCommand(), + UpdateKeyCommand(), + ParseKeyStringCommand(), + MigrateCommand(), ) cmd.PersistentFlags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|test)") viper.BindPFlag(flags.FlagKeyringBackend, cmd.Flags().Lookup(flags.FlagKeyringBackend)) diff --git a/client/keys/show.go b/client/keys/show.go index fa37f372f90a..e848a2208bb3 100644 --- a/client/keys/show.go +++ b/client/keys/show.go @@ -32,7 +32,8 @@ const ( defaultMultiSigKeyName = "multi" ) -func showKeysCmd() *cobra.Command { +// ShowKeysCmd shows key information for a given key name. +func ShowKeysCmd() *cobra.Command { cmd := &cobra.Command{ Use: "show [name [name...]]", Short: "Show key info for the given name", diff --git a/client/keys/show_test.go b/client/keys/show_test.go index 6fb97d97f441..0483e06d1de3 100644 --- a/client/keys/show_test.go +++ b/client/keys/show_test.go @@ -28,7 +28,7 @@ func Test_multiSigKey_Properties(t *testing.T) { } func Test_showKeysCmd(t *testing.T) { - cmd := showKeysCmd() + cmd := ShowKeysCmd() require.NotNil(t, cmd) require.Equal(t, "false", cmd.Flag(FlagAddress).DefValue) require.Equal(t, "false", cmd.Flag(FlagPublicKey).DefValue) @@ -36,7 +36,7 @@ func Test_showKeysCmd(t *testing.T) { func Test_runShowCmd(t *testing.T) { runningUnattended := isRunningUnattended() - cmd := showKeysCmd() + cmd := ShowKeysCmd() mockIn, _, _ := tests.ApplyMockIO(cmd) require.EqualError(t, runShowCmd(cmd, []string{"invalid"}), "The specified item could not be found in the keyring") require.EqualError(t, runShowCmd(cmd, []string{"invalid1", "invalid2"}), "The specified item could not be found in the keyring") diff --git a/client/keys/update.go b/client/keys/update.go index 64fdbe7e5f91..79b3ad4498ae 100644 --- a/client/keys/update.go +++ b/client/keys/update.go @@ -8,7 +8,9 @@ import ( "github.com/cosmos/cosmos-sdk/client/input" ) -func updateKeyCommand() *cobra.Command { +// UpdateKeyCommand changes the password of a key in the keybase. +// It takes no effect on keys managed by new the keyring-based keybase implementation. +func UpdateKeyCommand() *cobra.Command { cmd := &cobra.Command{ Use: "update ", Short: "Change the password used to protect private key", diff --git a/client/keys/update_test.go b/client/keys/update_test.go index 43e5dc98f0e2..6cfd46d92f38 100644 --- a/client/keys/update_test.go +++ b/client/keys/update_test.go @@ -11,7 +11,7 @@ import ( ) func Test_updateKeyCommand(t *testing.T) { - cmd := updateKeyCommand() + cmd := UpdateKeyCommand() assert.NotNil(t, cmd) // No flags or defaults to validate } @@ -20,7 +20,7 @@ func Test_runUpdateCmd(t *testing.T) { fakeKeyName1 := "runUpdateCmd_Key1" fakeKeyName2 := "runUpdateCmd_Key2" - cmd := updateKeyCommand() + cmd := UpdateKeyCommand() // fails because it requests a password assert.EqualError(t, runUpdateCmd(cmd, []string{fakeKeyName1}), "EOF") diff --git a/client/keys/utils.go b/client/keys/utils.go index 1096ae6e0790..498758d2c7bb 100644 --- a/client/keys/utils.go +++ b/client/keys/utils.go @@ -26,30 +26,33 @@ const ( type bechKeyOutFn func(keyInfo keys.Info) (keys.KeyOutput, error) -// NewKeyBaseFromHomeFlag initializes a Keybase based on the configuration. -func NewKeyBaseFromHomeFlag() (keys.Keybase, error) { +// NewKeyBaseFromHomeFlag initializes a Keybase based on the configuration. Keybase +// options can be applied when generating this new Keybase. +func NewKeyBaseFromHomeFlag(opts ...keys.KeybaseOption) (keys.Keybase, error) { rootDir := viper.GetString(flags.FlagHome) - return NewKeyBaseFromDir(rootDir) + return NewKeyBaseFromDir(rootDir, opts...) } -// NewKeyBaseFromDir initializes a keybase at a particular dir. -func NewKeyBaseFromDir(rootDir string) (keys.Keybase, error) { - return getLazyKeyBaseFromDir(rootDir) +// NewKeyBaseFromDir initializes a keybase at the rootDir directory. Keybase +// options can be applied when generating this new Keybase. +func NewKeyBaseFromDir(rootDir string, opts ...keys.KeybaseOption) (keys.Keybase, error) { + return getLazyKeyBaseFromDir(rootDir, opts...) } // NewInMemoryKeyBase returns a storage-less keybase. func NewInMemoryKeyBase() keys.Keybase { return keys.NewInMemory() } -// NewKeyBaseFromHomeFlag initializes a keyring based on configuration. -func NewKeyringFromHomeFlag(input io.Reader) (keys.Keybase, error) { - return NewKeyringFromDir(viper.GetString(flags.FlagHome), input) +// NewKeyBaseFromHomeFlag initializes a keyring based on configuration. Keybase +// options can be applied when generating this new Keybase. +func NewKeyringFromHomeFlag(input io.Reader, opts ...keys.KeybaseOption) (keys.Keybase, error) { + return NewKeyringFromDir(viper.GetString(flags.FlagHome), input, opts...) } // NewKeyBaseFromDir initializes a keyring at the given directory. // If the viper flag flags.FlagKeyringBackend is set to file, it returns an on-disk keyring with // CLI prompt support only. If flags.FlagKeyringBackend is set to test it will return an on-disk, // password-less keyring that could be used for testing purposes. -func NewKeyringFromDir(rootDir string, input io.Reader) (keys.Keybase, error) { +func NewKeyringFromDir(rootDir string, input io.Reader, opts ...keys.KeybaseOption) (keys.Keybase, error) { keyringBackend := viper.GetString(flags.FlagKeyringBackend) switch keyringBackend { case flags.KeyringBackendTest: @@ -62,8 +65,8 @@ func NewKeyringFromDir(rootDir string, input io.Reader) (keys.Keybase, error) { return nil, fmt.Errorf("unknown keyring backend %q", keyringBackend) } -func getLazyKeyBaseFromDir(rootDir string) (keys.Keybase, error) { - return keys.New(defaultKeyDBName, filepath.Join(rootDir, "keys")), nil +func getLazyKeyBaseFromDir(rootDir string, opts ...keys.KeybaseOption) (keys.Keybase, error) { + return keys.New(defaultKeyDBName, filepath.Join(rootDir, "keys"), opts...), nil } func printKeyInfo(keyInfo keys.Info, bechKeyOut bechKeyOutFn) { @@ -80,9 +83,9 @@ func printKeyInfo(keyInfo keys.Info, bechKeyOut bechKeyOutFn) { var out []byte var err error if viper.GetBool(flags.FlagIndentResponse) { - out, err = cdc.MarshalJSONIndent(ko, "", " ") + out, err = KeysCdc.MarshalJSONIndent(ko, "", " ") } else { - out, err = cdc.MarshalJSON(ko) + out, err = KeysCdc.MarshalJSON(ko) } if err != nil { panic(err) @@ -107,9 +110,9 @@ func printInfos(infos []keys.Info) { var err error if viper.GetBool(flags.FlagIndentResponse) { - out, err = cdc.MarshalJSONIndent(kos, "", " ") + out, err = KeysCdc.MarshalJSONIndent(kos, "", " ") } else { - out, err = cdc.MarshalJSON(kos) + out, err = KeysCdc.MarshalJSON(kos) } if err != nil { diff --git a/crypto/keys/codec.go b/crypto/keys/codec.go index 3181a9ef3e60..c3b3e76a3a8b 100644 --- a/crypto/keys/codec.go +++ b/crypto/keys/codec.go @@ -7,16 +7,22 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/keys/hd" ) -var cdc *codec.Codec +// CryptoCdc defines the codec required for keys and info +var CryptoCdc *codec.Codec func init() { - cdc = codec.New() - cryptoAmino.RegisterAmino(cdc) + CryptoCdc = codec.New() + cryptoAmino.RegisterAmino(CryptoCdc) + RegisterCodec(CryptoCdc) + CryptoCdc.Seal() +} + +// RegisterCodec registers concrete types and interfaces on the given codec. +func RegisterCodec(cdc *codec.Codec) { cdc.RegisterInterface((*Info)(nil), nil) cdc.RegisterConcrete(hd.BIP44Params{}, "crypto/keys/hd/BIP44Params", nil) cdc.RegisterConcrete(localInfo{}, "crypto/keys/localInfo", nil) cdc.RegisterConcrete(ledgerInfo{}, "crypto/keys/ledgerInfo", nil) cdc.RegisterConcrete(offlineInfo{}, "crypto/keys/offlineInfo", nil) cdc.RegisterConcrete(multiInfo{}, "crypto/keys/multiInfo", nil) - cdc.Seal() } diff --git a/crypto/keys/keybase.go b/crypto/keys/keybase.go index 00ac5c2373b5..d1b67e914248 100644 --- a/crypto/keys/keybase.go +++ b/crypto/keys/keybase.go @@ -75,16 +75,17 @@ type dbKeybase struct { // newDBKeybase creates a new dbKeybase instance using the provided DB for // reading and writing keys. -func newDBKeybase(db dbm.DB) Keybase { +func newDBKeybase(db dbm.DB, opts ...KeybaseOption) Keybase { return dbKeybase{ - base: baseKeybase{}, + base: newBaseKeybase(opts...), db: db, } } // NewInMemory creates a transient keybase on top of in-memory storage // instance useful for testing purposes and on-the-fly key generation. -func NewInMemory() Keybase { return newDBKeybase(dbm.NewMemDB()) } +// Keybase options can be applied when generating this new Keybase. +func NewInMemory(opts ...KeybaseOption) Keybase { return newDBKeybase(dbm.NewMemDB(), opts...) } // CreateMnemonic generates a new key and persists it to storage, encrypted // using the provided password. It returns the generated mnemonic and the key Info. diff --git a/crypto/keys/keybase_base.go b/crypto/keys/keybase_base.go index 55dd9bbffece..ea3a60bb9b75 100644 --- a/crypto/keys/keybase_base.go +++ b/crypto/keys/keybase_base.go @@ -16,9 +16,15 @@ import ( ) type ( + kbOptions struct { + keygenFunc PrivKeyGenFunc + } + // baseKeybase is an auxiliary type that groups Keybase storage agnostic features // together. - baseKeybase struct{} + baseKeybase struct { + options kbOptions + } keyWriter interface { writeLocalKeyer @@ -34,6 +40,30 @@ type ( } ) +// WithKeygenFunc applies an overridden key generation function to generate the private key. +func WithKeygenFunc(f PrivKeyGenFunc) KeybaseOption { + return func(o *kbOptions) { + o.keygenFunc = f + } +} + +// newBaseKeybase generates the base keybase with defaulting to tendermint SECP256K1 key type +func newBaseKeybase(optionsFns ...KeybaseOption) baseKeybase { + // Default options for keybase + options := kbOptions{keygenFunc: baseSecpPrivKeyGen} + + for _, optionFn := range optionsFns { + optionFn(&options) + } + + return baseKeybase{options: options} +} + +// baseSecpPrivKeyGen generates a secp256k1 private key from the given bytes +func baseSecpPrivKeyGen(bz [32]byte) tmcrypto.PrivKey { + return secp256k1.PrivKeySecp256k1(bz) +} + // SignWithLedger signs a binary message with the ledger device referenced by an Info object // and returns the signed bytes and the public key. It returns an error if the device could // not be queried or it returned an error. @@ -72,7 +102,7 @@ func (kb baseKeybase) DecodeSignature(info Info, msg []byte) (sig []byte, pub tm return nil, nil, err } - if err := cdc.UnmarshalBinaryLengthPrefixed([]byte(signed), sig); err != nil { + if err := CryptoCdc.UnmarshalBinaryLengthPrefixed([]byte(signed), sig); err != nil { return nil, nil, errors.Wrap(err, "failed to decode signature") } @@ -101,9 +131,9 @@ func (kb baseKeybase) persistDerivedKey( var info Info if passwd != "" { - info = keyWriter.writeLocalKey(name, secp256k1.PrivKeySecp256k1(derivedPriv), passwd) + info = keyWriter.writeLocalKey(name, kb.options.keygenFunc(derivedPriv), passwd) } else { - info = kb.writeOfflineKey(keyWriter, name, secp256k1.PrivKeySecp256k1(derivedPriv).PubKey()) + info = kb.writeOfflineKey(keyWriter, name, kb.options.keygenFunc(derivedPriv).PubKey()) } return info, nil diff --git a/crypto/keys/keybase_test.go b/crypto/keys/keybase_test.go index 2d4752fe3c31..f74d7c0c5785 100644 --- a/crypto/keys/keybase_test.go +++ b/crypto/keys/keybase_test.go @@ -10,6 +10,7 @@ import ( "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/ed25519" + "github.com/tendermint/tendermint/crypto/secp256k1" "github.com/cosmos/cosmos-sdk/crypto/keys/hd" "github.com/cosmos/cosmos-sdk/crypto/keys/mintkey" @@ -401,7 +402,8 @@ func TestSeedPhrase(t *testing.T) { func ExampleNew() { // Select the encryption and storage for your cryptostore - cstore := NewInMemory() + customKeyGenFunc := func(bz [32]byte) crypto.PrivKey { return secp256k1.PrivKeySecp256k1(bz) } + cstore := NewInMemory(WithKeygenFunc(customKeyGenFunc)) sec := Secp256k1 diff --git a/crypto/keys/keyring.go b/crypto/keys/keyring.go index 28d9aaec8ff1..b7c7aa0daa84 100644 --- a/crypto/keys/keyring.go +++ b/crypto/keys/keyring.go @@ -42,14 +42,17 @@ type keyringKeybase struct { var maxPassphraseEntryAttempts = 3 -// NewKeyring creates a new instance of a keyring. -func NewKeyring(name string, dir string, userInput io.Reader) (Keybase, error) { +// NewKeyring creates a new instance of a keyring. Keybase +// options can be applied when generating this new Keybase. +func NewKeyring( + name string, dir string, userInput io.Reader, opts ...KeybaseOption, +) (Keybase, error) { db, err := keyring.Open(lkbToKeyringConfig(name, dir, userInput, false)) if err != nil { return nil, err } - return newKeyringKeybase(db), nil + return newKeyringKeybase(db, opts...), nil } // NewKeyringFile creates a new instance of an encrypted file-backed keyring. @@ -64,13 +67,13 @@ func NewKeyringFile(name string, dir string, userInput io.Reader) (Keybase, erro // NewTestKeyring creates a new instance of an on-disk keyring for // testing purposes that does not prompt users for password. -func NewTestKeyring(name string, dir string) (Keybase, error) { +func NewTestKeyring(name string, dir string, opts ...KeybaseOption) (Keybase, error) { db, err := keyring.Open(lkbToKeyringConfig(name, dir, nil, true)) if err != nil { return nil, err } - return newKeyringKeybase(db), nil + return newKeyringKeybase(db, opts...), nil } // CreateMnemonic generates a new key and persists it to storage, encrypted @@ -572,9 +575,9 @@ func fakePrompt(prompt string) (string, error) { return "test", nil } -func newKeyringKeybase(db keyring.Keyring) Keybase { +func newKeyringKeybase(db keyring.Keyring, opts ...KeybaseOption) Keybase { return keyringKeybase{ db: db, - base: baseKeybase{}, + base: newBaseKeybase(opts...), } } diff --git a/crypto/keys/lazy_keybase.go b/crypto/keys/lazy_keybase.go index f362c9a1a61e..0c9b61c8588d 100644 --- a/crypto/keys/lazy_keybase.go +++ b/crypto/keys/lazy_keybase.go @@ -14,17 +14,18 @@ var _ Keybase = lazyKeybase{} // NOTE: lazyKeybase will be deprecated in favor of lazyKeybaseKeyring. type lazyKeybase struct { - name string - dir string + name string + dir string + options []KeybaseOption } // New creates a new instance of a lazy keybase. -func New(name, dir string) Keybase { +func New(name, dir string, opts ...KeybaseOption) Keybase { if err := cmn.EnsureDir(dir, 0700); err != nil { panic(fmt.Sprintf("failed to create Keybase directory: %s", err)) } - return lazyKeybase{name: name, dir: dir} + return lazyKeybase{name: name, dir: dir, options: opts} } func (lkb lazyKeybase) List() ([]Info, error) { @@ -34,7 +35,7 @@ func (lkb lazyKeybase) List() ([]Info, error) { } defer db.Close() - return newDBKeybase(db).List() + return newDBKeybase(db, lkb.options...).List() } func (lkb lazyKeybase) Get(name string) (Info, error) { @@ -44,7 +45,7 @@ func (lkb lazyKeybase) Get(name string) (Info, error) { } defer db.Close() - return newDBKeybase(db).Get(name) + return newDBKeybase(db, lkb.options...).Get(name) } func (lkb lazyKeybase) GetByAddress(address sdk.AccAddress) (Info, error) { @@ -54,7 +55,7 @@ func (lkb lazyKeybase) GetByAddress(address sdk.AccAddress) (Info, error) { } defer db.Close() - return newDBKeybase(db).GetByAddress(address) + return newDBKeybase(db, lkb.options...).GetByAddress(address) } func (lkb lazyKeybase) Delete(name, passphrase string, skipPass bool) error { @@ -64,7 +65,7 @@ func (lkb lazyKeybase) Delete(name, passphrase string, skipPass bool) error { } defer db.Close() - return newDBKeybase(db).Delete(name, passphrase, skipPass) + return newDBKeybase(db, lkb.options...).Delete(name, passphrase, skipPass) } func (lkb lazyKeybase) Sign(name, passphrase string, msg []byte) ([]byte, crypto.PubKey, error) { @@ -74,7 +75,7 @@ func (lkb lazyKeybase) Sign(name, passphrase string, msg []byte) ([]byte, crypto } defer db.Close() - return newDBKeybase(db).Sign(name, passphrase, msg) + return newDBKeybase(db, lkb.options...).Sign(name, passphrase, msg) } func (lkb lazyKeybase) CreateMnemonic(name string, language Language, passwd string, algo SigningAlgo) (info Info, seed string, err error) { @@ -84,7 +85,7 @@ func (lkb lazyKeybase) CreateMnemonic(name string, language Language, passwd str } defer db.Close() - return newDBKeybase(db).CreateMnemonic(name, language, passwd, algo) + return newDBKeybase(db, lkb.options...).CreateMnemonic(name, language, passwd, algo) } func (lkb lazyKeybase) CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd string, account uint32, index uint32) (Info, error) { @@ -94,7 +95,8 @@ func (lkb lazyKeybase) CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd } defer db.Close() - return newDBKeybase(db).CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd, account, index) + return newDBKeybase(db, + lkb.options...).CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd, account, index) } func (lkb lazyKeybase) Derive(name, mnemonic, bip39Passwd, encryptPasswd string, params hd.BIP44Params) (Info, error) { @@ -104,7 +106,7 @@ func (lkb lazyKeybase) Derive(name, mnemonic, bip39Passwd, encryptPasswd string, } defer db.Close() - return newDBKeybase(db).Derive(name, mnemonic, bip39Passwd, encryptPasswd, params) + return newDBKeybase(db, lkb.options...).Derive(name, mnemonic, bip39Passwd, encryptPasswd, params) } func (lkb lazyKeybase) CreateLedger(name string, algo SigningAlgo, hrp string, account, index uint32) (info Info, err error) { @@ -114,7 +116,7 @@ func (lkb lazyKeybase) CreateLedger(name string, algo SigningAlgo, hrp string, a } defer db.Close() - return newDBKeybase(db).CreateLedger(name, algo, hrp, account, index) + return newDBKeybase(db, lkb.options...).CreateLedger(name, algo, hrp, account, index) } func (lkb lazyKeybase) CreateOffline(name string, pubkey crypto.PubKey) (info Info, err error) { @@ -124,7 +126,7 @@ func (lkb lazyKeybase) CreateOffline(name string, pubkey crypto.PubKey) (info In } defer db.Close() - return newDBKeybase(db).CreateOffline(name, pubkey) + return newDBKeybase(db, lkb.options...).CreateOffline(name, pubkey) } func (lkb lazyKeybase) CreateMulti(name string, pubkey crypto.PubKey) (info Info, err error) { @@ -134,7 +136,7 @@ func (lkb lazyKeybase) CreateMulti(name string, pubkey crypto.PubKey) (info Info } defer db.Close() - return newDBKeybase(db).CreateMulti(name, pubkey) + return newDBKeybase(db, lkb.options...).CreateMulti(name, pubkey) } func (lkb lazyKeybase) Update(name, oldpass string, getNewpass func() (string, error)) error { @@ -144,7 +146,7 @@ func (lkb lazyKeybase) Update(name, oldpass string, getNewpass func() (string, e } defer db.Close() - return newDBKeybase(db).Update(name, oldpass, getNewpass) + return newDBKeybase(db, lkb.options...).Update(name, oldpass, getNewpass) } func (lkb lazyKeybase) Import(name string, armor string) (err error) { @@ -154,7 +156,7 @@ func (lkb lazyKeybase) Import(name string, armor string) (err error) { } defer db.Close() - return newDBKeybase(db).Import(name, armor) + return newDBKeybase(db, lkb.options...).Import(name, armor) } func (lkb lazyKeybase) ImportPrivKey(name string, armor string, passphrase string) error { @@ -164,7 +166,7 @@ func (lkb lazyKeybase) ImportPrivKey(name string, armor string, passphrase strin } defer db.Close() - return newDBKeybase(db).ImportPrivKey(name, armor, passphrase) + return newDBKeybase(db, lkb.options...).ImportPrivKey(name, armor, passphrase) } func (lkb lazyKeybase) ImportPubKey(name string, armor string) (err error) { @@ -174,7 +176,7 @@ func (lkb lazyKeybase) ImportPubKey(name string, armor string) (err error) { } defer db.Close() - return newDBKeybase(db).ImportPubKey(name, armor) + return newDBKeybase(db, lkb.options...).ImportPubKey(name, armor) } func (lkb lazyKeybase) Export(name string) (armor string, err error) { @@ -184,7 +186,7 @@ func (lkb lazyKeybase) Export(name string) (armor string, err error) { } defer db.Close() - return newDBKeybase(db).Export(name) + return newDBKeybase(db, lkb.options...).Export(name) } func (lkb lazyKeybase) ExportPubKey(name string) (armor string, err error) { @@ -194,7 +196,7 @@ func (lkb lazyKeybase) ExportPubKey(name string) (armor string, err error) { } defer db.Close() - return newDBKeybase(db).ExportPubKey(name) + return newDBKeybase(db, lkb.options...).ExportPubKey(name) } func (lkb lazyKeybase) ExportPrivateKeyObject(name string, passphrase string) (crypto.PrivKey, error) { @@ -204,7 +206,7 @@ func (lkb lazyKeybase) ExportPrivateKeyObject(name string, passphrase string) (c } defer db.Close() - return newDBKeybase(db).ExportPrivateKeyObject(name, passphrase) + return newDBKeybase(db, lkb.options...).ExportPrivateKeyObject(name, passphrase) } func (lkb lazyKeybase) ExportPrivKey(name string, decryptPassphrase string, @@ -216,7 +218,7 @@ func (lkb lazyKeybase) ExportPrivKey(name string, decryptPassphrase string, } defer db.Close() - return newDBKeybase(db).ExportPrivKey(name, decryptPassphrase, encryptPassphrase) + return newDBKeybase(db, lkb.options...).ExportPrivKey(name, decryptPassphrase, encryptPassphrase) } func (lkb lazyKeybase) CloseDB() {} diff --git a/crypto/keys/lazy_keybase_test.go b/crypto/keys/lazy_keybase_test.go index 1dabc9b8ebe8..31a9cf242f72 100644 --- a/crypto/keys/lazy_keybase_test.go +++ b/crypto/keys/lazy_keybase_test.go @@ -5,9 +5,12 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + amino "github.com/tendermint/go-amino" "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/ed25519" + tmamino "github.com/tendermint/tendermint/crypto/encoding/amino" + "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/crypto/keys/hd" "github.com/cosmos/cosmos-sdk/tests" sdk "github.com/cosmos/cosmos-sdk/types" @@ -371,3 +374,77 @@ func TestLazySeedPhrase(t *testing.T) { require.Equal(t, info.GetPubKey().Address(), newInfo.GetPubKey().Address()) require.Equal(t, info.GetPubKey(), newInfo.GetPubKey()) } + +var _ crypto.PrivKey = testPriv{} +var _ crypto.PubKey = testPub{} +var testCdc *amino.Codec + +type testPriv []byte + +func (privkey testPriv) PubKey() crypto.PubKey { return testPub{} } +func (privkey testPriv) Bytes() []byte { + return testCdc.MustMarshalBinaryBare(privkey) +} +func (privkey testPriv) Sign(msg []byte) ([]byte, error) { return []byte{}, nil } +func (privkey testPriv) Equals(other crypto.PrivKey) bool { return true } + +type testPub []byte + +func (key testPub) Address() crypto.Address { return crypto.Address{} } +func (key testPub) Bytes() []byte { + return testCdc.MustMarshalBinaryBare(key) +} +func (key testPub) VerifyBytes(msg []byte, sig []byte) bool { return true } +func (key testPub) Equals(other crypto.PubKey) bool { return true } + +func TestKeygenOverride(t *testing.T) { + dir, cleanup := tests.NewTestCaseDir(t) + defer cleanup() + + // Save existing codec and reset after test + cryptoCdc := CryptoCdc + defer func() { + CryptoCdc = cryptoCdc + }() + + // Setup testCdc encoding and decoding new key type + testCdc = codec.New() + RegisterCodec(testCdc) + tmamino.RegisterAmino(testCdc) + + // Set up codecs for using new key types + privName, pubName := "test/priv_name", "test/pub_name" + tmamino.RegisterKeyType(testPriv{}, privName) + tmamino.RegisterKeyType(testPub{}, pubName) + testCdc.RegisterConcrete(testPriv{}, privName, nil) + testCdc.RegisterConcrete(testPub{}, pubName, nil) + CryptoCdc = testCdc + + overrideCalled := false + dummyFunc := func(bz [32]byte) crypto.PrivKey { + overrideCalled = true + return testPriv(bz[:]) + } + + kb := New("keybasename", dir, WithKeygenFunc(dummyFunc)) + + testName, pw := "name", "testPassword" + + // create new key which will generate with + info, _, err := kb.CreateMnemonic(testName, English, pw, Secp256k1) + require.NoError(t, err) + require.Equal(t, info.GetName(), testName) + + // Assert overridden function was called + require.True(t, overrideCalled) + + // export private key object + exported, err := kb.ExportPrivateKeyObject(testName, pw) + require.Nil(t, err, "%+v", err) + + // require that the key type is the new key + _, ok := exported.(testPriv) + require.True(t, ok) + + require.True(t, exported.PubKey().Equals(info.GetPubKey())) +} diff --git a/crypto/keys/types.go b/crypto/keys/types.go index d968dce59716..739250f98ef8 100644 --- a/crypto/keys/types.go +++ b/crypto/keys/types.go @@ -306,11 +306,19 @@ func (i multiInfo) GetPath() (*hd.BIP44Params, error) { // encoding info func marshalInfo(i Info) []byte { - return cdc.MustMarshalBinaryLengthPrefixed(i) + return CryptoCdc.MustMarshalBinaryLengthPrefixed(i) } // decoding info func unmarshalInfo(bz []byte) (info Info, err error) { - err = cdc.UnmarshalBinaryLengthPrefixed(bz, &info) + err = CryptoCdc.UnmarshalBinaryLengthPrefixed(bz, &info) return } + +type ( + // PrivKeyGenFunc defines the function to convert derived key bytes to a tendermint private key + PrivKeyGenFunc func(bz [32]byte) crypto.PrivKey + + // KeybaseOption overrides options for the db + KeybaseOption func(*kbOptions) +) From d7b0f4b9b4fbdbe1dcb036475e71a026baf4b475 Mon Sep 17 00:00:00 2001 From: Austin Abell Date: Fri, 13 Dec 2019 06:21:49 -0500 Subject: [PATCH 033/529] apply options on newly added keyring types (#5404) --- client/keys/utils.go | 6 +++--- crypto/keys/keyring.go | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/client/keys/utils.go b/client/keys/utils.go index 498758d2c7bb..f6cf20e818df 100644 --- a/client/keys/utils.go +++ b/client/keys/utils.go @@ -56,11 +56,11 @@ func NewKeyringFromDir(rootDir string, input io.Reader, opts ...keys.KeybaseOpti keyringBackend := viper.GetString(flags.FlagKeyringBackend) switch keyringBackend { case flags.KeyringBackendTest: - return keys.NewTestKeyring(sdk.GetConfig().GetKeyringServiceName(), rootDir) + return keys.NewTestKeyring(sdk.GetConfig().GetKeyringServiceName(), rootDir, opts...) case flags.KeyringBackendFile: - return keys.NewKeyringFile(sdk.GetConfig().GetKeyringServiceName(), rootDir, input) + return keys.NewKeyringFile(sdk.GetConfig().GetKeyringServiceName(), rootDir, input, opts...) case flags.KeyringBackendOS: - return keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), rootDir, input) + return keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), rootDir, input, opts...) } return nil, fmt.Errorf("unknown keyring backend %q", keyringBackend) } diff --git a/crypto/keys/keyring.go b/crypto/keys/keyring.go index b7c7aa0daa84..842db588c30f 100644 --- a/crypto/keys/keyring.go +++ b/crypto/keys/keyring.go @@ -56,13 +56,13 @@ func NewKeyring( } // NewKeyringFile creates a new instance of an encrypted file-backed keyring. -func NewKeyringFile(name string, dir string, userInput io.Reader) (Keybase, error) { +func NewKeyringFile(name string, dir string, userInput io.Reader, opts ...KeybaseOption) (Keybase, error) { db, err := keyring.Open(newFileBackendKeyringConfig(name, dir, userInput)) if err != nil { return nil, err } - return newKeyringKeybase(db), nil + return newKeyringKeybase(db, opts...), nil } // NewTestKeyring creates a new instance of an on-disk keyring for From bc7c8c7c6b34d19b1b0d91db99465d09a1c658a0 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Fri, 13 Dec 2019 17:46:27 +0000 Subject: [PATCH 034/529] Bump x/simulation coverage (#5407) --- x/simulation/account_test.go | 77 ++++++++++++++++++++++++++++++++++ x/simulation/rand_util_test.go | 22 ++++++++++ 2 files changed, 99 insertions(+) create mode 100644 x/simulation/account_test.go diff --git a/x/simulation/account_test.go b/x/simulation/account_test.go new file mode 100644 index 000000000000..adb28dcf984f --- /dev/null +++ b/x/simulation/account_test.go @@ -0,0 +1,77 @@ +package simulation_test + +import ( + "math/rand" + "testing" + "time" + + "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/simulation" +) + +func TestRandomAccounts(t *testing.T) { + t.Parallel() + r := rand.New(rand.NewSource(time.Now().Unix())) + tests := []struct { + name string + n int + want int + }{ + {"0-accounts", 0, 0}, + {"0-accounts", 1, 1}, + {"0-accounts", 1_000, 1_000}, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + got := simulation.RandomAccounts(r, tt.n) + require.Equal(t, tt.want, len(got)) + if tt.n == 0 { + return + } + acc, i := simulation.RandomAcc(r, got) + require.True(t, acc.Equals(got[i])) + accFound, found := simulation.FindAccount(got, acc.Address) + require.True(t, found) + require.True(t, accFound.Equals(acc)) + }) + } +} + +func TestFindAccountEmptySlice(t *testing.T) { + t.Parallel() + r := rand.New(rand.NewSource(time.Now().Unix())) + accs := simulation.RandomAccounts(r, 1) + require.Equal(t, 1, len(accs)) + acc, found := simulation.FindAccount(nil, accs[0].Address) + require.False(t, found) + require.Nil(t, acc.Address) + require.Nil(t, acc.PrivKey) + require.Nil(t, acc.PubKey) +} + +func TestRandomFees(t *testing.T) { + t.Parallel() + r := rand.New(rand.NewSource(time.Now().Unix())) + tests := []struct { + name string + spendableCoins sdk.Coins + wantEmpty bool + wantErr bool + }{ + {"0 coins", sdk.Coins{}, true, false}, + {"0 coins", sdk.NewCoins(sdk.NewInt64Coin("aaa", 10), sdk.NewInt64Coin("bbb", 5)), false, false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := simulation.RandomFees(r, sdk.Context{}, tt.spendableCoins) + if (err != nil) != tt.wantErr { + t.Errorf("RandomFees() error = %v, wantErr %v", err, tt.wantErr) + return + } + require.Equal(t, tt.wantEmpty, got.Empty()) + }) + } +} diff --git a/x/simulation/rand_util_test.go b/x/simulation/rand_util_test.go index e212fed0ab3d..2128de4050aa 100644 --- a/x/simulation/rand_util_test.go +++ b/x/simulation/rand_util_test.go @@ -3,6 +3,7 @@ package simulation_test import ( "math/rand" "testing" + "time" "github.com/stretchr/testify/require" @@ -11,6 +12,7 @@ import ( ) func TestRandSubsetCoins(t *testing.T) { + t.Parallel() tests := []struct { name string r *rand.Rand @@ -31,6 +33,26 @@ func TestRandSubsetCoins(t *testing.T) { } } +func TestRandStringOfLength(t *testing.T) { + t.Parallel() + r := rand.New(rand.NewSource(time.Now().Unix())) + tests := []struct { + name string + n int + want int + }{ + {"0-size", 0, 0}, + {"10-size", 10, 10}, + {"10-size", 1_000_000_000, 1_000_000_000}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := simulation.RandStringOfLength(r, tt.n) + require.Equal(t, tt.want, len(got)) + }) + } +} + func mustParseCoins(s string) sdk.Coins { coins, err := sdk.ParseCoins(s) if err != nil { From b04dcf2be0db0cf0d19a2b15a49f9e11704b0709 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Mon, 16 Dec 2019 15:17:35 +0100 Subject: [PATCH 035/529] Merged PR #5397: ADR 003: Dynamic Capability Store --- docs/architecture/README.md | 1 + .../adr-003-dynamic-capability-store.md | 271 ++++++++++++++++++ 2 files changed, 272 insertions(+) create mode 100644 docs/architecture/adr-003-dynamic-capability-store.md diff --git a/docs/architecture/README.md b/docs/architecture/README.md index f7d2dafeb502..a63e13fefc93 100644 --- a/docs/architecture/README.md +++ b/docs/architecture/README.md @@ -32,6 +32,7 @@ Please add a entry below in your Pull Request for an ADR. ## ADR Table of Contents - [ADR 002: SDK Documentation Structure](./adr-002-docs-structure.md) +- [ADR 003: Dynamic Capability Store](./adr-003-dynamic-capability-store.md) - [ADR 006: Secret Store Replacement](./adr-006-secret-store-replacement.md) - [ADR 009: Evidence Module](./adr-009-evidence-module.md) - [ADR 010: Modular AnteHandler](./adr-010-modular-antehandler.md) diff --git a/docs/architecture/adr-003-dynamic-capability-store.md b/docs/architecture/adr-003-dynamic-capability-store.md new file mode 100644 index 000000000000..7272c138f816 --- /dev/null +++ b/docs/architecture/adr-003-dynamic-capability-store.md @@ -0,0 +1,271 @@ +# ADR 3: Dynamic Capability Store + +## Changelog + +- 12 December 2019: Initial version + +## Context + +Full implementation of the [IBC specification](https://github.com/cosmos/ics) requires the ability to create and authenticate object-capability keys at runtime (i.e., during transaction execution), +as described in [ICS 5](https://github.com/cosmos/ics/tree/master/spec/ics-005-port-allocation#technical-specification). In the IBC specification, capability keys are created for each newly initialised +port & channel, and are used to authenticate future usage of the port or channel. Since channels and potentially ports can be initialised during transaction execution, the state machine must be able to create +object-capability keys at this time. + +At present, the Cosmos SDK does not have the ability to do this. Object-capability keys are currently pointers (memory addresses) of `StoreKey` structs created at application initialisation in `app.go` ([example](https://github.com/cosmos/gaia/blob/dcbddd9f04b3086c0ad07ee65de16e7adedc7da4/app/app.go#L132)) +and passed to Keepers as fixed arguments ([example](https://github.com/cosmos/gaia/blob/dcbddd9f04b3086c0ad07ee65de16e7adedc7da4/app/app.go#L160)). Keepers cannot create or store capability keys during transaction execution — although they could call `NewKVStoreKey` and take the memory address +of the returned struct, storing this in the Merklised store would result in a consensus fault, since the memory address will be different on each machine (this is intentional — were this not the case, the keys would be predictable and couldn't serve as object capabilities). + +Keepers need a way to keep a private map of store keys which can be altered during transacton execution, along with a suitable mechanism for regenerating the unique memory addresses (capability keys) in this map whenever the application is started or restarted. +This ADR proposes such an interface & mechanism. + +## Decision + +The SDK will include a new `CapabilityKeeper` abstraction, which is responsible for provisioning, tracking, and authenticating capabilities at runtime. During application initialisation in `app.go`, the `CapabilityKeeper` will +be hooked up to modules through unique function references (by calling `ScopeToModule`, defined below) so that it can identify the calling module when later invoked. When the initial state is loaded from disk, the `CapabilityKeeper`'s `Initialise` function will create new capability keys +for all previously allocated capability identifiers (allocated during execution of past transactions and assigned to particular modes), and keep them in a memory-only store while the chain is running. The SDK will include a new `MemoryStore` store type, similar +to the existing `TransientStore` but without erasure on `Commit()`, which this `CapabilityKeeper` will use to privately store capability keys. + +The `CapabilityKeeper` will use two stores: a regular, persistent `KVStore`, which will track what capabilities have been created by each module, and an in-memory `MemoryStore` (described below), which will +store the actual capabilities. The `CapabilityKeeper` will define the following types & functions: + +The `Capability` interface, similar to `StoreKey`, provides `Name()` and `String()` methods. + +```golang +type Capability interface { + Name() string + String() string +} +``` + +A `CapabilityKey` is simply a struct, the address of which is taken for the actual capability. + +```golang +type CapabilityKey struct { + name string +} +``` + +A `CapabilityKeeper` contains a persistent store key, memory store key, and mapping of allocated module names. + +```golang +type CapabilityKeeper struct { + persistentKey StoreKey + memoryKey MemoryStoreKey + moduleNames map[string]interface{} + sealed bool +} +``` + +The `CapabilityKeeper` provides the ability to create *scoped* sub-keepers which are tied to a particular module name. These `ScopedCapabilityKeeper`s must be created at application +initialisation and passed to modules, which can then use them to claim capabilities they receive and retrieve capabilities which they own by name, in addition +to creating new capabilities & authenticating capabilities passed by other modules. + +```golang +type ScopedCapabilityKeeper struct { + persistentKey StoreKey + memoryKey MemoryStoreKey + moduleName string +} +``` + +`ScopeToModule` is used to create a scoped sub-keeper with a particular name, which must be unique. It MUST be called before `InitialiseAndSeal`. + +```golang +func (ck CapabilityKeeper) ScopeToModule(moduleName string) ScopedCapabilityKeeper { + if ck.sealed { + panic("capability keeper is sealed") + } + if _, present := ck.moduleNames[moduleName]; present { + panic("cannot create multiple scoped capability keepers for the same module name") + } + ck.moduleNames[moduleName] = struct{}{} + return ScopedCapabilityKeeper{ + persistentKey: ck.persistentKey, + memoryKey: ck.memoryKey, + moduleName: moduleName + } +} +``` + +`InitialiseAndSeal` MUST be called exactly once, after loading the initial state and creating all necessary `ScopedCapabilityKeeper`s, +in order to populate the memory store with newly-created capability keys in accordance with the keys previously claimed by particular modules +and prevent the creation of any new `ScopedCapabilityKeeper`s. + +```golang +func (ck CapabilityKeeper) InitialiseAndSeal(ctx Context) { + if ck.sealed { + panic("capability keeper is sealed") + } + persistentStore := ctx.KVStore(ck.persistentKey) + memoryStore := ctx.KVStore(ck.memoryKey) + // initialise memory store for all names in persistent store + for _, key := range persistentStore.Iter() { + capability = &CapabilityKey{name: key} + memoryStore.Set("fwd/" + capability, name) + memoryStore.Set("rev/" + name, capability) + } + ck.sealed = true +} +``` + +`NewCapability` can be called by any module to create a new unique, unforgeable object-capability +reference. The newly created capability is *not* automatically persisted, `ClaimCapability` must be +called on the `ScopedCapabilityKeeper` in order to persist it. + +```golang +func (sck ScopedCapabilityKeeper) NewCapability(ctx Context, name string) (Capability, error) { + memoryStore := ctx.KVStore(sck.memoryKey) + // check name not taken in memory store + if memoryStore.Get("rev/" + name) != nil { + return nil, errors.New("name already taken") + } + // create a new capability + capability := &CapabilityKey{name: name} + // set forward mapping in memory store from capability to name + memoryStore.Set("fwd/" + capability, name) + // set reverse mapping in memory store from name to capability + memoryStore.Set("rev/" + name, capability) + // return the newly created capability + return capability +} +``` + +`AuthenticateCapability` can be called by any module to check that a capability +does in fact correspond to a particular name (the name can be untrusted user input). + +```golang +func (sck ScopedCapabilityKeeper) AuthenticateCapability(name string, capability Capability) bool { + memoryStore := ctx.KVStore(sck.memoryKey) + // return whether forward mapping in memory store matches name + return memoryStore.Get("fwd/" + capability) === name +} +``` + +`ClaimCapability` allows a module to claim a capability key which it has received (perhaps by calling `NewCapability`, or from another module), so that future `GetCapability` calls will succeed. + +`ClaimCapability` MUST be called, even if `NewCapability` was called by the same module. Capabilities are single-owner, so if multiple modules have a single `Capability` reference, the last module +to call `ClaimCapability` will own it. To avoid confusion, a module which calls `NewCapability` SHOULD either call `ClaimCapability` or pass the capability to another module which will then claim it. + +```golang +func (sck ScopedCapabilityKeeper) ClaimCapability(ctx Context, capability Capability) error { + persistentStore := ctx.KVStore(sck.persistentKey) + memoryStore := ctx.KVStore(sck.memoryKey) + // fetch name from memory store + name := memoryStore.Get("fwd/" + capability) + if name === nil { + return errors.New("capability not found") + } + // set name to module in persistent store + persistentStore.Set(name, sck.moduleName) +} +``` + +`GetCapability` allows a module to fetch a capability which it has previously claimed by name. The module is not allowed to retrieve capabilities which it does not own. If another module +claims a capability, the previously owning module will no longer be able to claim it. + +```golang +func (sck ScopedCapabilityKeeper) GetCapability(ctx Context, name string) (Capability, error) { + persistentStore := ctx.KVStore(sck.persistentKey) + memoryStore := ctx.KVStore(sck.memoryKey) + // check that this module owns the capability with this name + res := persistentStore.Get(name) + if res != sck.moduleName { + return errors.New("capability of this name not owned by module") + } + // fetch capability from memory store, return it + capability := memoryStore.Get("rev/" + name) + return capability +} +``` + +### Memory store + +A new store key type, `MemoryStoreKey`, will be added to the `store` package. The `MemoryStoreKey`s work just like `StoreKey`s. + +The memory store will work just like the current transient store, except that it will not create a new `dbadapter.Store` when `Commit()` is called, but instead retain the current one (so that state will persist across blocks). + +Initially the memory store will only be used by the `CapabilityKeeper`, but it could be used by other modules in the future. + +### Usage patterns + +#### Initialisation + +Any modules which use dynamic capabilities must be provided a `ScopedCapabilityKeeper` in `app.go`: + +```golang +ck := NewCapabilityKeeper(persistentKey, memoryKey) +mod1Keeper := NewMod1Keeper(ck.ScopeToModule("mod1"), ....) +mod2Keeper := NewMod2Keeper(ck.ScopeToModule("mod2"), ....) + +// other initialisation logic ... + +// load initial state... + +ck.InitialiseAndSeal(initialContext) +``` + +#### Creating, passing, claiming and using capabilities + +Consider the case where `mod1` wants to create a capability, associate it with a resource (e.g. an IBC channel) by name, then pass it to `mod2` which will use it later: + +Module 1 would have the following code: + +```golang +capability := scopedCapabilityKeeper.NewCapability(ctx, "resourceABC") +mod2Keeper.SomeFunction(ctx, capability, args...) +``` + +`SomeFunction`, running in module 2, could then claim the capability: + +```golang +func (k Mod2Keeper) SomeFunction(ctx Context, capability Capability) { + k.sck.ClaimCapability(ctx, capability) + // other logic... +} +``` + +Later on, module 2 can retrieve that capability by name and pass it to module 1, which will authenticate it against the resource: + +```golang +func (k Mod2Keeper) SomeOtherFunction(ctx Context, name string) { + capability := k.sck.GetCapability(ctx, name) + mod1.UseResource(ctx, capability, "resourceABC") +} +``` + +Module 1 will then check that this capability key is authenticated to use the resource before allowing module 2 to use it: + +```golang +func (k Mod1Keeper) UseResource(ctx Context, capability Capability, resource string) { + if !k.sck.AuthenticateCapability(name, capability) { + return errors.New("unauthenticated") + } + // do something with the resource +} +``` + +If module 2 passed the capability key to module 3, module 3 could then claim it and call module 1 just like module 2 did +(in which case module 2 could no longer call `GetCapability`, since it would then be owned uniquely by module 3). + +## Status + +Proposed. + +## Consequences + +### Positive + +- Dynamic capability support. + +### Negative + +- Requires an additional keeper. +- Some overlap with existing `StoreKey` system (in the future they could be combined, since this is a superset functionality-wise). + +### Neutral + +(none known) + +## References + +- [Original discussion](https://github.com/cosmos/cosmos-sdk/pull/5230#discussion_r343978513) From b7ec16951f0f22bb9df27b458904f6df7584b8e2 Mon Sep 17 00:00:00 2001 From: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Date: Mon, 16 Dec 2019 16:24:37 -0300 Subject: [PATCH 036/529] update SECURITY.md (#5377) * update SECURITY.md * add comment on bug report * format --- .github/ISSUE_TEMPLATE/bug-report.md | 12 ++++-- SECURITY.md | 61 +++++++++++++++++++--------- 2 files changed, 51 insertions(+), 22 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md index 346969aef117..369cd676cbaa 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -10,21 +10,27 @@ v Before smashing the submit button please review the template. v Please also ensure that this is not a duplicate issue :) ☺ > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > --> + + ## Summary of Bug ## Version - + ## Steps to Reproduce - + ____ -#### For Admin Use +## For Admin Use - [ ] Not duplicate issue - [ ] Appropriate labels applied diff --git a/SECURITY.md b/SECURITY.md index 4eddc8c4fbda..8d3322dbd080 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,29 +1,52 @@ # Security -As part of our [Coordinated Vulnerability Disclosure -Policy](https://tendermint.com/security), we operate a bug bounty. -See the policy for more details on submissions and rewards. +> **IMPORTANT**: If you find a security issue, you can contact our team directly at +security@tendermint.com, or report it to our [bug bounty program](https://hackerone.com/tendermint) on HackerOne. *DO NOT* open a public issue on the repository. -The following is a list of examples of the kinds of bugs we're most interested in for -the Cosmos SDK. See [here](https://github.com/tendermint/tendermint/blob/master/SECURITY.md) for vulnerabilities we are interested in for Tendermint, and lower-level libraries, e.g. IAVL. +## Bug Bounty -## Modules -- x/staking -- x/slashing -- x/types -- x/gov +As part of our [Coordinated Vulnerability Disclosure Policy](https://tendermint.com/security), we operate a +[bug bounty program](https://hackerone.com/tendermint) with Hacker One. -We are interested in bugs in other modules, however the above are most likely to have -significant vulnerabilities, due to the complexity / nuance involved +See the policy linked above for more details on submissions and rewards and read +this [blog post](https://blog.cosmos.network/bug-bounty-program-for-tendermint-cosmos-833c67693586) for the program scope. -## How we process Tx parameters -- Integer operations on tx parameters, especially sdk.Int / sdk.Uint -- Gas calculation & parameter choices -- Tx signature verification (code in x/auth/ante.go) -- Possible Node DoS vectors. (Perhaps due to Gas weighting / non constant timing) +The following is a list of examples of the kinds of bugs we're most interested +in for the Cosmos SDK. See [here](https://github.com/tendermint/tendermint/blob/master/SECURITY.md) for vulnerabilities we are interested +in for Tendermint and other lower-level libraries (eg. [IAVL](https://github.com/tendermint/iavl)). + +### Core packages + +- [`/baseapp`](https://github.com/cosmos/cosmos-sdk/tree/master/baseapp) +- [`/crypto`](https://github.com/cosmos/cosmos-sdk/tree/master/crypto) +- [`/types`](https://github.com/cosmos/cosmos-sdk/tree/master/types) +- [`/store`](https://github.com/cosmos/cosmos-sdk/tree/master/store) + +### Modules + +- [`x/auth`](https://github.com/cosmos/cosmos-sdk/tree/master/x/auth) +- [`x/bank`](https://github.com/cosmos/cosmos-sdk/tree/master/x/bank) +- [`x/staking`](https://github.com/cosmos/cosmos-sdk/tree/master/x/staking) +- [`x/slashing`](https://github.com/cosmos/cosmos-sdk/tree/master/x/slashing) +- [`x/evidence`](https://github.com/cosmos/cosmos-sdk/tree/master/x/evidence) +- [`x/distribution`](https://github.com/cosmos/cosmos-sdk/tree/master/x/distribution) +- [`x/supply`](https://github.com/cosmos/cosmos-sdk/tree/master/x/supply) +- [`x/ibc`](https://github.com/cosmos/cosmos-sdk/tree/ibc-alpha/x/ibc) (currently in alpha mode) + +We are interested in bugs in other modules, however the above are most likely to +have significant vulnerabilities, due to the complexity / nuance involved. We +also recommend you to read the [specification](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/README.md) of each module before digging into +the code. + +### How we process Tx parameters + +- Integer operations on tx parameters, especially `sdk.Int` / `sdk.Dec` +- Gas calculation & parameter choices +- Tx signature verification (see [`x/auth/ante`](https://github.com/cosmos/cosmos-sdk/tree/master/x/auth/ante)) +- Possible Node DoS vectors (perhaps due to gas weighting / non constant timing) + +### Handling private keys -## Handling private keys - HD key derivation, local and Ledger, and all key-management functionality - Side-channel attack vectors with our implementations - e.g. key exfiltration based on time or memory-access patterns when decrypting privkey - From fb0a2c46d3bd99c0d7b66effcabbc4f247435a2a Mon Sep 17 00:00:00 2001 From: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Date: Mon, 16 Dec 2019 19:10:18 -0300 Subject: [PATCH 037/529] fix DecCoins constructor (#5410) * fix decCoins * minor changes for standardization * changelog * add test cases --- CHANGELOG.md | 1 + types/dec_coin.go | 58 ++++++++++++++--------- types/dec_coin_test.go | 105 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 142 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c59ec9a9418..15b78b68bf43 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -223,6 +223,7 @@ to detail this new feature and how state transitions occur. * (rest) [\#5212](https://github.com/cosmos/cosmos-sdk/issues/5212) Fix pagination in the `/gov/proposals` handler. * (baseapp) [\#5350](https://github.com/cosmos/cosmos-sdk/issues/5350) Allow a node to restart successfully after a `halt-height` or `halt-time` has been triggered. +* (types) [\#5408](https://github.com/cosmos/cosmos-sdk/issues/5408) `NewDecCoins` constructor now sorts the coins. ## [v0.37.4] - 2019-11-04 diff --git a/types/dec_coin.go b/types/dec_coin.go index 0c11d3135341..e26a88f8755e 100644 --- a/types/dec_coin.go +++ b/types/dec_coin.go @@ -11,17 +11,16 @@ import ( // ---------------------------------------------------------------------------- // Decimal Coin -// Coins which can have additional decimal points +// DecCoin defines a coin which can have additional decimal points type DecCoin struct { Denom string `json:"denom"` Amount Dec `json:"amount"` } +// NewDecCoin creates a new DecCoin instance from an Int. func NewDecCoin(denom string, amount Int) DecCoin { - mustValidateDenom(denom) - - if amount.IsNegative() { - panic(fmt.Sprintf("negative coin amount: %v\n", amount)) + if err := validate(denom, amount); err != nil { + panic(err) } return DecCoin{ @@ -30,6 +29,7 @@ func NewDecCoin(denom string, amount Int) DecCoin { } } +// NewDecCoinFromDec creates a new DecCoin instance from a Dec. func NewDecCoinFromDec(denom string, amount Dec) DecCoin { mustValidateDenom(denom) @@ -43,12 +43,10 @@ func NewDecCoinFromDec(denom string, amount Dec) DecCoin { } } +// NewDecCoinFromCoin creates a new DecCoin from a Coin. func NewDecCoinFromCoin(coin Coin) DecCoin { - if coin.Amount.IsNegative() { - panic(fmt.Sprintf("negative decimal coin amount: %v\n", coin.Amount)) - } - if strings.ToLower(coin.Denom) != coin.Denom { - panic(fmt.Sprintf("denom cannot contain upper case characters: %s\n", coin.Denom)) + if err := validate(coin.Denom, coin.Amount); err != nil { + panic(err) } return DecCoin{ @@ -97,7 +95,7 @@ func (coin DecCoin) IsEqual(other DecCoin) bool { return coin.Amount.Equal(other.Amount) } -// Adds amounts of two coins with same denom +// Add adds amounts of two decimal coins with same denom. func (coin DecCoin) Add(coinB DecCoin) DecCoin { if coin.Denom != coinB.Denom { panic(fmt.Sprintf("coin denom different: %v %v\n", coin.Denom, coinB.Denom)) @@ -105,12 +103,16 @@ func (coin DecCoin) Add(coinB DecCoin) DecCoin { return DecCoin{coin.Denom, coin.Amount.Add(coinB.Amount)} } -// Subtracts amounts of two coins with same denom +// Sub subtracts amounts of two decimal coins with same denom. func (coin DecCoin) Sub(coinB DecCoin) DecCoin { if coin.Denom != coinB.Denom { panic(fmt.Sprintf("coin denom different: %v %v\n", coin.Denom, coinB.Denom)) } - return DecCoin{coin.Denom, coin.Amount.Sub(coinB.Amount)} + res := DecCoin{coin.Denom, coin.Amount.Sub(coinB.Amount)} + if res.IsNegative() { + panic("negative decimal coin amount") + } + return res } // TruncateDecimal returns a Coin with a truncated decimal and a DecCoin for the @@ -118,7 +120,7 @@ func (coin DecCoin) Sub(coinB DecCoin) DecCoin { func (coin DecCoin) TruncateDecimal() (Coin, DecCoin) { truncated := coin.Amount.TruncateInt() change := coin.Amount.Sub(truncated.ToDec()) - return NewCoin(coin.Denom, truncated), DecCoin{coin.Denom, change} + return NewCoin(coin.Denom, truncated), NewDecCoinFromDec(coin.Denom, change) } // IsPositive returns true if coin amount is positive. @@ -141,18 +143,30 @@ func (coin DecCoin) String() string { return fmt.Sprintf("%v%v", coin.Amount, coin.Denom) } +// IsValid returns true if the DecCoin has a non-negative amount and the denom is vaild. +func (coin DecCoin) IsValid() bool { + if err := ValidateDenom(coin.Denom); err != nil { + return false + } + return !coin.IsNegative() +} + // ---------------------------------------------------------------------------- // Decimal Coins -// coins with decimal +// DecCoins defines a slice of coins with decimal values type DecCoins []DecCoin +// NewDecCoins constructs a new coin set with decimal values +// from regular Coins. func NewDecCoins(coins Coins) DecCoins { - dcs := make(DecCoins, len(coins)) - for i, coin := range coins { - dcs[i] = NewDecCoinFromCoin(coin) + decCoins := make(DecCoins, len(coins)) + newCoins := NewCoins(coins...) + for i, coin := range newCoins { + decCoins[i] = NewDecCoinFromCoin(coin) } - return dcs + + return decCoins } // String implements the Stringer interface for DecCoins. It returns a @@ -177,7 +191,7 @@ func (coins DecCoins) TruncateDecimal() (truncatedCoins Coins, changeCoins DecCo for _, coin := range coins { truncated, change := coin.TruncateDecimal() if !truncated.IsZero() { - truncatedCoins = truncatedCoins.Add(Coins{truncated}) + truncatedCoins = truncatedCoins.Add(NewCoins(truncated)) } if !change.IsZero() { changeCoins = changeCoins.Add(DecCoins{change}) @@ -404,7 +418,7 @@ func (coins DecCoins) Empty() bool { return len(coins) == 0 } -// returns the amount of a denom from deccoins +// AmountOf returns the amount of a denom from deccoins func (coins DecCoins) AmountOf(denom string) Dec { mustValidateDenom(denom) @@ -452,7 +466,7 @@ func (coins DecCoins) IsEqual(coinsB DecCoins) bool { return true } -// return whether all coins are zero +// IsZero returns whether all coins are zero func (coins DecCoins) IsZero() bool { for _, coin := range coins { if !coin.Amount.IsZero() { diff --git a/types/dec_coin_test.go b/types/dec_coin_test.go index 3c8df657287f..65408a0b3ab3 100644 --- a/types/dec_coin_test.go +++ b/types/dec_coin_test.go @@ -96,6 +96,111 @@ func TestAddDecCoins(t *testing.T) { } } +func TestIsValid(t *testing.T) { + tests := []struct { + coin DecCoin + expectPass bool + msg string + }{ + { + NewDecCoin("mytoken", NewInt(10)), + true, + "valid coins should have passed", + }, + { + DecCoin{Denom: "BTC", Amount: NewDec(10)}, + false, + "invalid denoms", + }, + { + DecCoin{Denom: "BTC", Amount: NewDec(-10)}, + false, + "negative amount", + }, + } + + for _, tc := range tests { + tc := tc + if tc.expectPass { + require.True(t, tc.coin.IsValid(), tc.msg) + } else { + require.False(t, tc.coin.IsValid(), tc.msg) + } + } +} + +func TestSubDecCoin(t *testing.T) { + tests := []struct { + coin DecCoin + expectPass bool + msg string + }{ + { + NewDecCoin("mytoken", NewInt(20)), + true, + "valid coins should have passed", + }, + { + NewDecCoin("othertoken", NewInt(20)), + false, + "denom mismatch", + }, + { + NewDecCoin("mytoken", NewInt(9)), + false, + "negative amount", + }, + } + + decCoin := NewDecCoin("mytoken", NewInt(10)) + + for _, tc := range tests { + tc := tc + if tc.expectPass { + equal := tc.coin.Sub(decCoin) + require.Equal(t, equal, decCoin, tc.msg) + } else { + require.Panics(t, func() { tc.coin.Sub(decCoin) }, tc.msg) + } + } +} + +func TestSubDecCoins(t *testing.T) { + tests := []struct { + coins DecCoins + expectPass bool + msg string + }{ + { + NewDecCoins(Coins{NewCoin("mytoken", NewInt(10)), NewCoin("btc", NewInt(20)), NewCoin("eth", NewInt(30))}), + true, + "sorted coins should have passed", + }, + { + DecCoins{NewDecCoin("mytoken", NewInt(10)), NewDecCoin("btc", NewInt(20)), NewDecCoin("eth", NewInt(30))}, + false, + "unorted coins should panic", + }, + { + DecCoins{DecCoin{Denom: "BTC", Amount: NewDec(10)}, NewDecCoin("eth", NewInt(15)), NewDecCoin("mytoken", NewInt(5))}, + false, + "invalid denoms", + }, + } + + decCoins := NewDecCoins(Coins{NewCoin("btc", NewInt(10)), NewCoin("eth", NewInt(15)), NewCoin("mytoken", NewInt(5))}) + + for _, tc := range tests { + tc := tc + if tc.expectPass { + equal := tc.coins.Sub(decCoins) + require.Equal(t, equal, decCoins, tc.msg) + } else { + require.Panics(t, func() { tc.coins.Sub(decCoins) }, tc.msg) + } + } +} + func TestSortDecCoins(t *testing.T) { good := DecCoins{ NewInt64DecCoin("gas", 1), From 98acd941e705951bde6bcbdb55336dd46ff6363e Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Tue, 17 Dec 2019 03:48:52 +0100 Subject: [PATCH 038/529] Reduce password prompt duplication when using keyring's file backend (#5406) Workaround for #5403, users are still prompted for password twice. --- x/genutil/client/cli/gentx.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/x/genutil/client/cli/gentx.go b/x/genutil/client/cli/gentx.go index 462969e52ee7..ebfdded23a96 100644 --- a/x/genutil/client/cli/gentx.go +++ b/x/genutil/client/cli/gentx.go @@ -140,12 +140,7 @@ func GenTxCmd(ctx *server.Context, cdc *codec.Codec, mbm module.BasicManager, sm return errors.Wrap(err, "failed to build create-validator message") } - info, err := txBldr.Keybase().Get(name) - if err != nil { - return errors.Wrap(err, "failed to read from tx builder keybase") - } - - if info.GetType() == kbkeys.TypeOffline || info.GetType() == kbkeys.TypeMulti { + if key.GetType() == kbkeys.TypeOffline || key.GetType() == kbkeys.TypeMulti { fmt.Println("Offline key passed in. Use `tx sign` command to sign:") return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}) } From 13378bd2cfb9695da6477494e449b0a3bca9bc94 Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Tue, 17 Dec 2019 16:44:44 +0500 Subject: [PATCH 039/529] Docs: hide frontmatter, bugfixes (#5413) * encoding * working on baseapp doc * baseapp work * reorg * almost there * finish first draft * remove old files * module doc start * finish intro * working * workinnn * add transactions into core * hans comments * add transactions into core * working * gautier comments * clean * working * consolidate intro * querier * workiiiing * refactor for new module interface * karoly review * working on baseapp doc * baseapp work * reorg * almost there * finish first draft * remove old files * finish intro * workinnn * initial commit after rebase * query-lifecycle and started modules-interfaces * query-lifecycle first draft done * module interfaces first draft * rest and intro skeletons * rest and intro done * small edits and links * comments * revisions * cli.md comments * comments * minor edits * better flow for query lifecycle * add transactions into core * hans comments * add transactions into core * checkout master-docs files * deleted some * remove modules readme * cli.md comments * comments * module-interfaces comments * Merge PR #4857: Add Context concept doc * working * working * finish messages and queries * handler * querier * last comments! * punctuation * querier2 * consolidate intro * querier * workiiiing * refactor for new module interface * karoly review * working on baseapp doc * baseapp work * reorg * almost there * finish first draft * remove old files * finish intro * workinnn * initial commit after rebase * query-lifecycle and started modules-interfaces * query-lifecycle first draft done * module interfaces first draft * rest and intro skeletons * rest and intro done * small edits and links * comments * revisions * cli.md comments * comments * minor edits * better flow for query lifecycle * checkout master-docs files * deleted some * remove modules readme * cli.md comments * comments * module-interfaces comments * keeper * genesis * finish * Apply suggestions from code review Co-Authored-By: Hans Schoenburg * hans review * Update docs/core/baseapp.md Co-Authored-By: Hans Schoenburg * working * last comment * workin * Apply suggestions from code review * encoding and node * almost finish store * finish docs * fixes * fede comments + permalinks * hans review * add more permalinks * update docs theme version (#5239) * R4R: Docs Cleanup (#5246) * start * work * work * work * remove table of content * links intro * fix links * remove junk * cleanup * cleanup * work * finish cleanup * addback readmes * remove nft * fix links * remove dup * remove dup * remove dup * remove dup * remove dup * fix links * add subscribe events * refine rest * index page * sidebar * theme version * theme version * testing netlify * theme version * tooltip example * version * testing code embedding * reverting back * theme version * version * version * version * readme and version * cleanup * redo app anatomy * modules readme, theme version * theme version * fix modules list * theme version * new snippets * modules readme * update docs readme * modify synopsis * version * fix yaml * version * version * version * version * version * version * version * version * version * version * add hide banner * version * version * version * small fixes * modules readme, version * remove hotkeys dep, version * version * version * version * version * version * version * version * slight notice * fix links and hide * permalinks * small clean * version * resolve conflicts, add google analytics * fix merge remants * version * changelog 1/2 * Changelog: docs UI * version * remove merge conflicts * Code: Update link for Contributing to the docs to docs_readme * HTML/CSS: Update layout of homepage footer to match new layout in Figma * version * final modifs * modules, version * modules readme * link to module list from homepage * version * building modules link * version * version * fonts * version * version * fix link * fix package.json * links in explore sdk section * core concepts * version * change delimeters for frontmatter * frontmatter in comments * version * temp add tiny-cookie * fixed link issues * fixed styling issues, copy * hide frontmatter * hide frontmatter * layout fixes, padded ascii diagram * fira sans font for code --- README.md | 4 +- docs/.vuepress/config.js | 6 +- docs/README.md | 9 +- docs/basics/README.md | 4 +- docs/basics/accounts.md | 4 +- docs/basics/app-anatomy.md | 4 +- docs/basics/gas-fees.md | 4 +- docs/basics/tx-lifecycle.md | 4 +- docs/building-modules/README.md | 4 +- docs/building-modules/beginblock-endblock.md | 4 +- docs/building-modules/genesis.md | 4 +- docs/building-modules/handler.md | 4 +- docs/building-modules/intro.md | 4 +- docs/building-modules/invariants.md | 4 +- docs/building-modules/keeper.md | 4 +- docs/building-modules/messages-and-queries.md | 4 +- docs/building-modules/module-interfaces.md | 4 +- docs/building-modules/module-manager.md | 5 +- docs/building-modules/querier.md | 4 +- docs/building-modules/structure.md | 4 +- docs/core/README.md | 4 +- docs/core/baseapp.md | 4 +- docs/core/context.md | 4 +- docs/core/encoding.md | 4 +- docs/core/events.md | 4 +- docs/core/node.md | 4 +- docs/core/ocap.md | 4 +- docs/core/store.md | 4 +- docs/core/transactions.md | 4 +- docs/interfaces/README.md | 4 +- docs/interfaces/cli.md | 4 +- docs/interfaces/interfaces-intro.md | 4 +- docs/interfaces/query-lifecycle.md | 4 +- docs/interfaces/rest.md | 4 +- docs/intro/README.md | 4 +- docs/intro/overview.md | 4 +- docs/intro/sdk-app-architecture.md | 34 +- docs/intro/sdk-design.md | 4 +- docs/intro/why-app-specific.md | 4 +- docs/package-lock.json | 579 +++++++++++------- docs/package.json | 8 +- docs/using-the-sdk/README.md | 4 +- x/README.md | 5 +- x/auth/spec/01_concepts.md | 4 +- x/auth/spec/02_state.md | 4 +- x/auth/spec/03_messages.md | 4 +- x/auth/spec/03_types.md | 4 +- x/auth/spec/04_keepers.md | 4 +- x/auth/spec/05_vesting.md | 4 +- x/auth/spec/07_params.md | 4 +- x/auth/spec/README.md | 4 +- x/bank/spec/01_state.md | 4 +- x/bank/spec/02_keepers.md | 4 +- x/bank/spec/03_messages.md | 4 +- x/bank/spec/04_events.md | 4 +- x/bank/spec/05_params.md | 4 +- x/bank/spec/README.md | 4 +- x/crisis/spec/01_state.md | 4 +- x/crisis/spec/02_messages.md | 4 +- x/crisis/spec/03_events.md | 4 +- x/crisis/spec/04_params.md | 4 +- x/crisis/spec/README.md | 4 +- x/distribution/spec/01_concepts.md | 4 +- x/distribution/spec/02_state.md | 4 +- x/distribution/spec/03_end_block.md | 4 +- x/distribution/spec/04_messages.md | 4 +- x/distribution/spec/05_hooks.md | 4 +- x/distribution/spec/06_events.md | 4 +- x/distribution/spec/07_params.md | 4 +- x/distribution/spec/README.md | 4 +- x/evidence/spec/01_concepts.md | 4 +- x/evidence/spec/02_state.md | 4 +- x/evidence/spec/03_messages.md | 4 +- x/evidence/spec/04_events.md | 4 +- x/evidence/spec/05_params.md | 4 +- x/evidence/spec/06_begin_block.md | 4 +- x/evidence/spec/README.md | 4 +- x/gov/spec/01_concepts.md | 4 +- x/gov/spec/02_state.md | 4 +- x/gov/spec/03_messages.md | 4 +- x/gov/spec/04_events.md | 4 +- x/gov/spec/05_future_improvements.md | 4 +- x/gov/spec/06_params.md | 4 +- x/gov/spec/README.md | 4 +- x/mint/spec/01_concepts.md | 6 +- x/mint/spec/02_state.md | 4 +- x/mint/spec/03_begin_block.md | 4 +- x/mint/spec/04_params.md | 4 +- x/mint/spec/05_events.md | 4 +- x/mint/spec/README.md | 4 +- x/params/spec/01_keeper.md | 4 +- x/params/spec/02_subspace.md | 4 +- x/params/spec/README.md | 4 +- x/slashing/spec/01_concepts.md | 4 +- x/slashing/spec/02_state.md | 4 +- x/slashing/spec/03_messages.md | 4 +- x/slashing/spec/04_begin_block.md | 4 +- x/slashing/spec/05_hooks.md | 4 +- x/slashing/spec/06_events.md | 4 +- x/slashing/spec/07_tombstone.md | 4 +- x/slashing/spec/08_params.md | 4 +- x/slashing/spec/README.md | 6 +- x/staking/spec/01_state.md | 4 +- x/staking/spec/02_state_transitions.md | 4 +- x/staking/spec/03_messages.md | 4 +- x/staking/spec/04_end_block.md | 4 +- x/staking/spec/05_hooks.md | 4 +- x/staking/spec/06_events.md | 4 +- x/staking/spec/07_params.md | 4 +- x/staking/spec/README.md | 4 +- x/supply/spec/01_concepts.md | 4 +- x/supply/spec/02_state.md | 4 +- x/supply/spec/03_future_improvements.md | 4 +- x/supply/spec/README.md | 4 +- x/upgrade/spec/01_concepts.md | 4 +- x/upgrade/spec/02_state.md | 4 +- x/upgrade/spec/03_events.md | 4 +- x/upgrade/spec/README.md | 4 +- 118 files changed, 605 insertions(+), 489 deletions(-) diff --git a/README.md b/README.md index 10090dd2dace..d1ee3d585a01 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ---- + # Cosmos SDK diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index 5a3d148ec652..9295d711284f 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -123,7 +123,7 @@ module.exports = { } ], smallprint: - "The development of the Cosmos project is led primarily by Tendermint Inc., the for-profit entity which also maintains this website. Funding for this development comes primarily from the Interchain Foundation, a Swiss non-profit.", + "This website is maintained by Tendermint Inc. The contents and opinions of this website are those of Tendermint Inc.", links: [ { title: "Documentation", @@ -135,6 +135,10 @@ module.exports = { { title: "Cosmos Hub", url: "https://hub.cosmos.network/" + }, + { + title: "Tendermint Core", + url: "https://docs.tendermint.com/" } ] }, diff --git a/docs/README.md b/docs/README.md index 4a2a02e78484..7eb27fdea435 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,5 +1,5 @@ ---- -layout: index + # Cosmos SDK Documentation diff --git a/docs/basics/README.md b/docs/basics/README.md index c2e3e519fe76..131ee1ba452f 100644 --- a/docs/basics/README.md +++ b/docs/basics/README.md @@ -1,8 +1,8 @@ ---- + # Basics diff --git a/docs/basics/accounts.md b/docs/basics/accounts.md index ae69c081f549..f5667a26009e 100644 --- a/docs/basics/accounts.md +++ b/docs/basics/accounts.md @@ -1,7 +1,7 @@ ---- + # Accounts diff --git a/docs/basics/app-anatomy.md b/docs/basics/app-anatomy.md index e982306f342d..0c7e084cea8b 100644 --- a/docs/basics/app-anatomy.md +++ b/docs/basics/app-anatomy.md @@ -1,7 +1,7 @@ ---- + # Anatomy of an SDK Application diff --git a/docs/basics/gas-fees.md b/docs/basics/gas-fees.md index b54a7f19be60..5bb4d779f5c0 100644 --- a/docs/basics/gas-fees.md +++ b/docs/basics/gas-fees.md @@ -1,7 +1,7 @@ ---- + # Gas and Fees diff --git a/docs/basics/tx-lifecycle.md b/docs/basics/tx-lifecycle.md index af138706b543..5d99c290e376 100644 --- a/docs/basics/tx-lifecycle.md +++ b/docs/basics/tx-lifecycle.md @@ -1,7 +1,7 @@ ---- + # Transaction Lifecycle diff --git a/docs/building-modules/README.md b/docs/building-modules/README.md index 5257e5aa2080..f23a129e7bb4 100644 --- a/docs/building-modules/README.md +++ b/docs/building-modules/README.md @@ -1,8 +1,8 @@ ---- + # Building Modules diff --git a/docs/building-modules/beginblock-endblock.md b/docs/building-modules/beginblock-endblock.md index fe3aeedceb92..578a0f733828 100644 --- a/docs/building-modules/beginblock-endblock.md +++ b/docs/building-modules/beginblock-endblock.md @@ -1,7 +1,7 @@ ---- + # BeginBlocker and EndBlocker diff --git a/docs/building-modules/genesis.md b/docs/building-modules/genesis.md index 0d4ddec93e77..8cb8815b7ce8 100644 --- a/docs/building-modules/genesis.md +++ b/docs/building-modules/genesis.md @@ -1,7 +1,7 @@ ---- + # Module Genesis diff --git a/docs/building-modules/handler.md b/docs/building-modules/handler.md index b42d591c0867..3b19bf9603a9 100644 --- a/docs/building-modules/handler.md +++ b/docs/building-modules/handler.md @@ -1,7 +1,7 @@ ---- + # Handlers diff --git a/docs/building-modules/intro.md b/docs/building-modules/intro.md index 8ad43da48ece..1d125b51b8a7 100644 --- a/docs/building-modules/intro.md +++ b/docs/building-modules/intro.md @@ -1,7 +1,7 @@ ---- + # Introduction to SDK Modules diff --git a/docs/building-modules/invariants.md b/docs/building-modules/invariants.md index 2e18551914d4..64b8e4696dc9 100644 --- a/docs/building-modules/invariants.md +++ b/docs/building-modules/invariants.md @@ -1,7 +1,7 @@ ---- + # Invariants diff --git a/docs/building-modules/keeper.md b/docs/building-modules/keeper.md index e76b0bb008d0..a9132bae041c 100644 --- a/docs/building-modules/keeper.md +++ b/docs/building-modules/keeper.md @@ -1,7 +1,7 @@ ---- + # Keepers diff --git a/docs/building-modules/messages-and-queries.md b/docs/building-modules/messages-and-queries.md index bb0665483b36..3c87cc84eeab 100644 --- a/docs/building-modules/messages-and-queries.md +++ b/docs/building-modules/messages-and-queries.md @@ -1,7 +1,7 @@ ---- + # Messages and Queries diff --git a/docs/building-modules/module-interfaces.md b/docs/building-modules/module-interfaces.md index 5b1352621a42..bfb820d75e40 100644 --- a/docs/building-modules/module-interfaces.md +++ b/docs/building-modules/module-interfaces.md @@ -1,7 +1,7 @@ ---- + # Module Interfaces diff --git a/docs/building-modules/module-manager.md b/docs/building-modules/module-manager.md index 2ad4bc9006a4..bbafacca29c7 100644 --- a/docs/building-modules/module-manager.md +++ b/docs/building-modules/module-manager.md @@ -1,8 +1,7 @@ ---- + # Module Manager diff --git a/docs/building-modules/querier.md b/docs/building-modules/querier.md index f839a2bef266..02c334fc3843 100644 --- a/docs/building-modules/querier.md +++ b/docs/building-modules/querier.md @@ -1,7 +1,7 @@ ---- + # Queriers diff --git a/docs/building-modules/structure.md b/docs/building-modules/structure.md index 7ae32f2dde82..6b6d2f889a14 100644 --- a/docs/building-modules/structure.md +++ b/docs/building-modules/structure.md @@ -1,7 +1,7 @@ ---- + # Recommended Folder Structure diff --git a/docs/core/README.md b/docs/core/README.md index 6d865e79a8ff..6bfd2feb3fb7 100644 --- a/docs/core/README.md +++ b/docs/core/README.md @@ -1,8 +1,8 @@ ---- + # Core Concepts diff --git a/docs/core/baseapp.md b/docs/core/baseapp.md index add0b049caf5..8ef2dbcdfdcc 100644 --- a/docs/core/baseapp.md +++ b/docs/core/baseapp.md @@ -1,7 +1,7 @@ ---- + # Baseapp diff --git a/docs/core/context.md b/docs/core/context.md index e501834a911f..f54c9d036d93 100644 --- a/docs/core/context.md +++ b/docs/core/context.md @@ -1,7 +1,7 @@ ---- + # Context diff --git a/docs/core/encoding.md b/docs/core/encoding.md index caf445511799..6629612a3a24 100644 --- a/docs/core/encoding.md +++ b/docs/core/encoding.md @@ -1,7 +1,7 @@ ---- + # Encoding diff --git a/docs/core/events.md b/docs/core/events.md index b9eabb3161ae..11b6ad1e59b0 100644 --- a/docs/core/events.md +++ b/docs/core/events.md @@ -1,7 +1,7 @@ ---- + # Events diff --git a/docs/core/node.md b/docs/core/node.md index 5da50d6080a4..8ca558609504 100644 --- a/docs/core/node.md +++ b/docs/core/node.md @@ -1,7 +1,7 @@ ---- + # Node Client (Daemon) diff --git a/docs/core/ocap.md b/docs/core/ocap.md index 27e7be4a3f4e..c3a6cf08ee53 100644 --- a/docs/core/ocap.md +++ b/docs/core/ocap.md @@ -1,6 +1,6 @@ ---- + # Object-Capability Model diff --git a/docs/core/store.md b/docs/core/store.md index 9eb5e886c0bf..ee93f49e9332 100644 --- a/docs/core/store.md +++ b/docs/core/store.md @@ -1,7 +1,7 @@ ---- + # Store diff --git a/docs/core/transactions.md b/docs/core/transactions.md index d49cd853a797..3023d6fce8dd 100644 --- a/docs/core/transactions.md +++ b/docs/core/transactions.md @@ -1,7 +1,7 @@ ---- + # Transactions diff --git a/docs/interfaces/README.md b/docs/interfaces/README.md index 0e23c0478ae7..ea94cb9a6fc3 100644 --- a/docs/interfaces/README.md +++ b/docs/interfaces/README.md @@ -1,8 +1,8 @@ ---- + # Interfaces diff --git a/docs/interfaces/cli.md b/docs/interfaces/cli.md index 9cc907ee7126..0e7c786ed1f9 100644 --- a/docs/interfaces/cli.md +++ b/docs/interfaces/cli.md @@ -1,7 +1,7 @@ ---- + # Command-Line Interface diff --git a/docs/interfaces/interfaces-intro.md b/docs/interfaces/interfaces-intro.md index eb807d0025e8..029ed39accb5 100644 --- a/docs/interfaces/interfaces-intro.md +++ b/docs/interfaces/interfaces-intro.md @@ -1,7 +1,7 @@ ---- + # Interfaces diff --git a/docs/interfaces/query-lifecycle.md b/docs/interfaces/query-lifecycle.md index 748ebb8225dc..5d1eab955af2 100644 --- a/docs/interfaces/query-lifecycle.md +++ b/docs/interfaces/query-lifecycle.md @@ -1,7 +1,7 @@ ---- + # Query Lifecycle diff --git a/docs/interfaces/rest.md b/docs/interfaces/rest.md index ceb2ce63999e..75e5a78dc3d8 100644 --- a/docs/interfaces/rest.md +++ b/docs/interfaces/rest.md @@ -1,7 +1,7 @@ ---- + # REST Interface diff --git a/docs/intro/README.md b/docs/intro/README.md index 22ade6bf00a7..454ce66955e7 100644 --- a/docs/intro/README.md +++ b/docs/intro/README.md @@ -1,8 +1,8 @@ ---- + # Introduction diff --git a/docs/intro/overview.md b/docs/intro/overview.md index 94e6d3d6df40..f7e2242afcfa 100644 --- a/docs/intro/overview.md +++ b/docs/intro/overview.md @@ -1,6 +1,6 @@ ---- + # High-level Overview diff --git a/docs/intro/sdk-app-architecture.md b/docs/intro/sdk-app-architecture.md index 4f4f0f3e9051..68785906eff2 100644 --- a/docs/intro/sdk-app-architecture.md +++ b/docs/intro/sdk-app-architecture.md @@ -1,6 +1,6 @@ ---- + # Blockchain Architecture @@ -65,21 +65,21 @@ The Tendermint [consensus algorithm](https://tendermint.com/docs/introduction/wh Tendermint passes transactions to the application through an interface called the [ABCI](https://tendermint.com/docs/spec/abci/), which the application must implement. ``` -+---------------------+ -| | -| Application | -| | -+--------+---+--------+ - ^ | - | | ABCI - | v -+--------+---+--------+ -| | -| | -| Tendermint | -| | -| | -+---------------------+ + +---------------------+ + | | + | Application | + | | + +--------+---+--------+ + ^ | + | | ABCI + | v + +--------+---+--------+ + | | + | | + | Tendermint | + | | + | | + +---------------------+ ``` Note that **Tendermint only handles transaction bytes**. It has no knowledge of what these bytes mean. All Tendermint does is order these transaction bytes deterministically. Tendermint passes the bytes to the application via the ABCI, and expects a return code to inform it if the messages contained in the transactions were successfully processed or not. diff --git a/docs/intro/sdk-design.md b/docs/intro/sdk-design.md index 51cab8c1b336..00a5f2a4b875 100644 --- a/docs/intro/sdk-design.md +++ b/docs/intro/sdk-design.md @@ -1,6 +1,6 @@ ---- + # Main Components of the Cosmos SDK diff --git a/docs/intro/why-app-specific.md b/docs/intro/why-app-specific.md index b6d88f1176a2..a3645f9e3095 100644 --- a/docs/intro/why-app-specific.md +++ b/docs/intro/why-app-specific.md @@ -1,7 +1,7 @@ ---- + # Application-Specific Blockchains diff --git a/docs/package-lock.json b/docs/package-lock.json index 5ac336064d73..3eee6f418b9a 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -822,9 +822,9 @@ } }, "@cosmos-ui/vue": { - "version": "0.5.16", - "resolved": "https://registry.npmjs.org/@cosmos-ui/vue/-/vue-0.5.16.tgz", - "integrity": "sha512-Z4byEoZLkIbumm3SlnrzwuyvDi6vzWv2GfT36QuaPFWusCShGgc47ehXp2S55tKrNajOIiF9bfgasHRL6mfHFA==", + "version": "0.5.17", + "resolved": "https://registry.npmjs.org/@cosmos-ui/vue/-/vue-0.5.17.tgz", + "integrity": "sha512-x9ruudnnUCDxFQZRRMBzmVYM1s7ukmGuyCd0M+fMo3kAwg/IePlyq3aA4aZXD411NvBFNG1A2BxWQAWd09hT0g==", "requires": { "vue": "^2.6.10" } @@ -877,9 +877,9 @@ "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==" }, "@types/node": { - "version": "12.12.17", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.17.tgz", - "integrity": "sha512-Is+l3mcHvs47sKy+afn2O1rV4ldZFU7W8101cNlOd+MRbjM4Onida8jSZnJdTe/0Pcf25g9BNIUsuugmE6puHA==" + "version": "12.12.18", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.18.tgz", + "integrity": "sha512-DBkZuIMFuAfjJHiunyRc+aNvmXYNwV1IPMgGKGlwCp6zh6MKrVtmvjSWK/axWcD25KJffkXgkfvFra8ndenXAw==" }, "@types/q": { "version": "1.5.2", @@ -1203,6 +1203,16 @@ "stylus-loader": "^3.0.2", "vuepress-plugin-container": "^2.0.2", "vuepress-plugin-smooth-scroll": "^0.0.3" + }, + "dependencies": { + "vuepress-plugin-smooth-scroll": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/vuepress-plugin-smooth-scroll/-/vuepress-plugin-smooth-scroll-0.0.3.tgz", + "integrity": "sha512-qsQkDftLVFLe8BiviIHaLV0Ea38YLZKKonDGsNQy1IE0wllFpFIEldWD8frWZtDFdx6b/O3KDMgVQ0qp5NjJCg==", + "requires": { + "smoothscroll-polyfill": "^0.4.3" + } + } } }, "@webassemblyjs/ast": { @@ -1463,6 +1473,21 @@ "kind-of": "^3.0.2", "longest": "^1.0.1", "repeat-string": "^1.5.2" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } } }, "alphanum-sort": { @@ -1820,11 +1845,6 @@ "is-data-descriptor": "^1.0.0", "kind-of": "^6.0.2" } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" } } }, @@ -1856,6 +1876,15 @@ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==" }, + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "optional": true, + "requires": { + "file-uri-to-path": "1.0.0" + } + }, "bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", @@ -1937,16 +1966,6 @@ "snapdragon-node": "^2.0.1", "split-string": "^3.0.2", "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } } }, "brorand": { @@ -2214,9 +2233,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001015", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001015.tgz", - "integrity": "sha512-/xL2AbW/XWHNu1gnIrO8UitBGoFthcsDgU9VLK1/dpsoxbaD5LscHozKze05R6WLsBvLhqv78dAPozMFQBYLbQ==" + "version": "1.0.30001016", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001016.tgz", + "integrity": "sha512-yYQ2QfotceRiH4U+h1Us86WJXtVHDmy3nEKIdYPsZCYnOV5/tMgGbmoIlrMzmh2VXlproqYtVaKeGDBkMZifFA==" }, "caseless": { "version": "0.12.0", @@ -2592,9 +2611,9 @@ "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" }, "copy-webpack-plugin": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-5.1.0.tgz", - "integrity": "sha512-0sNrj/Sx7/cWA0k7CVQa0sdA/dzCybqSb0+GbhKuQdOlAvnAwgC2osmbAFOAfha7ZXnreoQmCq5oDjG3gP4VHw==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-5.1.1.tgz", + "integrity": "sha512-P15M5ZC8dyCjQHWwd4Ia/dm0SgVvZJMYeykVIVYXbGyqO4dWB5oyPHp9i7wjwo5LhtlhKbiBCdS2NvM07Wlybg==", "requires": { "cacache": "^12.0.3", "find-cache-dir": "^2.1.0", @@ -3025,11 +3044,6 @@ "is-data-descriptor": "^1.0.0", "kind-of": "^6.0.2" } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" } } }, @@ -3355,9 +3369,9 @@ } }, "es-abstract": { - "version": "1.16.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.16.3.tgz", - "integrity": "sha512-WtY7Fx5LiOnSYgF5eg/1T+GONaGmpvpPdCpSnYij+U2gDTL0UPfWrhDw7b2IYb+9NQJsYpCA0wOQvZfsd6YwRw==", + "version": "1.17.0-next.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.0-next.1.tgz", + "integrity": "sha512-7MmGr03N7Rnuid6+wyhD9sHNE2n4tFSwExnU2lQl3lIo2ShXWGePY80zYaoMOmILWv57H0amMjZGHNzzGG70Rw==", "requires": { "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", @@ -3367,6 +3381,7 @@ "is-regex": "^1.0.4", "object-inspect": "^1.7.0", "object-keys": "^1.1.1", + "object.assign": "^4.1.0", "string.prototype.trimleft": "^2.1.0", "string.prototype.trimright": "^2.1.0" } @@ -3495,14 +3510,6 @@ "requires": { "is-descriptor": "^0.1.0" } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } } } }, @@ -3566,22 +3573,11 @@ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "requires": { - "is-plain-object": "^2.0.4" - } - } + "is-extendable": "^0.1.0" } }, "extglob": { @@ -3607,14 +3603,6 @@ "is-descriptor": "^1.0.0" } }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - }, "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", @@ -3640,11 +3628,6 @@ "is-data-descriptor": "^1.0.0", "kind-of": "^6.0.2" } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" } } }, @@ -3672,9 +3655,9 @@ } }, "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, "faye-websocket": { "version": "0.10.0", @@ -3706,6 +3689,12 @@ "schema-utils": "^1.0.0" } }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "optional": true + }, "fill-range": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", @@ -3715,16 +3704,6 @@ "is-number": "^3.0.0", "repeat-string": "^1.6.1", "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } } }, "finalhandler": { @@ -3881,13 +3860,14 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "fsevents": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", - "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.11.tgz", + "integrity": "sha512-+ux3lx6peh0BpvY0JebGyZoiR4D+oYzdPZMKJwkZ+sFkNJzpL7tXc/wehS49gUAxg3tmMHPHZkA8JU2rhhgDHw==", "optional": true, "requires": { + "bindings": "^1.5.0", "nan": "^2.12.1", - "node-pre-gyp": "^0.12.0" + "node-pre-gyp": "*" }, "dependencies": { "abbrev": { @@ -3929,7 +3909,7 @@ } }, "chownr": { - "version": "1.1.1", + "version": "1.1.3", "bundled": true, "optional": true }, @@ -3954,7 +3934,7 @@ "optional": true }, "debug": { - "version": "4.1.1", + "version": "3.2.6", "bundled": true, "optional": true, "requires": { @@ -3977,11 +3957,11 @@ "optional": true }, "fs-minipass": { - "version": "1.2.5", + "version": "1.2.7", "bundled": true, "optional": true, "requires": { - "minipass": "^2.2.1" + "minipass": "^2.6.0" } }, "fs.realpath": { @@ -4005,7 +3985,7 @@ } }, "glob": { - "version": "7.1.3", + "version": "7.1.6", "bundled": true, "optional": true, "requires": { @@ -4031,7 +4011,7 @@ } }, "ignore-walk": { - "version": "3.0.1", + "version": "3.0.3", "bundled": true, "optional": true, "requires": { @@ -4048,7 +4028,7 @@ } }, "inherits": { - "version": "2.0.3", + "version": "2.0.4", "bundled": true, "optional": true }, @@ -4084,7 +4064,7 @@ "optional": true }, "minipass": { - "version": "2.3.5", + "version": "2.9.0", "bundled": true, "optional": true, "requires": { @@ -4093,11 +4073,11 @@ } }, "minizlib": { - "version": "1.2.1", + "version": "1.3.3", "bundled": true, "optional": true, "requires": { - "minipass": "^2.2.1" + "minipass": "^2.9.0" } }, "mkdirp": { @@ -4109,22 +4089,22 @@ } }, "ms": { - "version": "2.1.1", + "version": "2.1.2", "bundled": true, "optional": true }, "needle": { - "version": "2.3.0", + "version": "2.4.0", "bundled": true, "optional": true, "requires": { - "debug": "^4.1.0", + "debug": "^3.2.6", "iconv-lite": "^0.4.4", "sax": "^1.2.4" } }, "node-pre-gyp": { - "version": "0.12.0", + "version": "0.14.0", "bundled": true, "optional": true, "requires": { @@ -4137,7 +4117,7 @@ "rc": "^1.2.7", "rimraf": "^2.6.1", "semver": "^5.3.0", - "tar": "^4" + "tar": "^4.4.2" } }, "nopt": { @@ -4150,12 +4130,20 @@ } }, "npm-bundled": { - "version": "1.0.6", + "version": "1.1.1", + "bundled": true, + "optional": true, + "requires": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-normalize-package-bin": { + "version": "1.0.1", "bundled": true, "optional": true }, "npm-packlist": { - "version": "1.4.1", + "version": "1.4.7", "bundled": true, "optional": true, "requires": { @@ -4217,7 +4205,7 @@ "optional": true }, "process-nextick-args": { - "version": "2.0.0", + "version": "2.0.1", "bundled": true, "optional": true }, @@ -4254,7 +4242,7 @@ } }, "rimraf": { - "version": "2.6.3", + "version": "2.7.1", "bundled": true, "optional": true, "requires": { @@ -4277,7 +4265,7 @@ "optional": true }, "semver": { - "version": "5.7.0", + "version": "5.7.1", "bundled": true, "optional": true }, @@ -4323,17 +4311,17 @@ "optional": true }, "tar": { - "version": "4.4.8", + "version": "4.4.13", "bundled": true, "optional": true, "requires": { "chownr": "^1.1.1", "fs-minipass": "^1.2.5", - "minipass": "^2.3.4", - "minizlib": "^1.1.1", + "minipass": "^2.8.6", + "minizlib": "^1.2.1", "mkdirp": "^0.5.0", "safe-buffer": "^5.1.2", - "yallist": "^3.0.2" + "yallist": "^3.0.3" } }, "util-deprecate": { @@ -4355,7 +4343,7 @@ "optional": true }, "yallist": { - "version": "3.0.3", + "version": "3.1.1", "bundled": true, "optional": true } @@ -4486,13 +4474,6 @@ "kind-of": "^6.0.2", "section-matter": "^1.0.0", "strip-bom-string": "^1.0.0" - }, - "dependencies": { - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" - } } }, "handle-thing": { @@ -4951,6 +4932,21 @@ "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "requires": { "kind-of": "^3.0.2" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } } }, "is-arguments": { @@ -5000,6 +4996,21 @@ "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "requires": { "kind-of": "^3.0.2" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } } }, "is-date-object": { @@ -5074,6 +5085,21 @@ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "requires": { "kind-of": "^3.0.2" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } } }, "is-obj": { @@ -5121,11 +5147,11 @@ "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" }, "is-regex": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", - "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", "requires": { - "has": "^1.0.1" + "has": "^1.0.3" } }, "is-resolvable": { @@ -5295,19 +5321,9 @@ "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==" }, "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - } - } + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" }, "last-call-webpack-plugin": { "version": "3.0.0", @@ -5643,10 +5659,22 @@ "to-regex": "^3.0.2" }, "dependencies": { - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } } } }, @@ -5836,10 +5864,22 @@ "to-regex": "^3.0.1" }, "dependencies": { - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } } } }, @@ -6014,6 +6054,19 @@ "requires": { "is-descriptor": "^0.1.0" } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } } } }, @@ -6023,9 +6076,9 @@ "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==" }, "object-is": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.0.1.tgz", - "integrity": "sha1-CqYOyZiaCz7Xlc9NBvYs8a1lObY=" + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.0.2.tgz", + "integrity": "sha512-Epah+btZd5wrrfjkJZq1AOB9O6OxUQto45hzFd7lXGrpHPGE0W1k+426yrZV+k6NJOzLNNW/nVsmZdIWsAqoOQ==" }, "object-keys": { "version": "1.1.1", @@ -6052,12 +6105,12 @@ } }, "object.getownpropertydescriptors": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", - "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz", + "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==", "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.5.1" + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" } }, "object.pick": { @@ -6069,12 +6122,12 @@ } }, "object.values": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.0.tgz", - "integrity": "sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", + "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", "requires": { "define-properties": "^1.1.3", - "es-abstract": "^1.12.0", + "es-abstract": "^1.17.0-next.1", "function-bind": "^1.1.1", "has": "^1.0.3" } @@ -7400,14 +7453,34 @@ "requires": { "extend-shallow": "^3.0.2", "safe-regex": "^1.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } } }, "regexp.prototype.flags": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.2.0.tgz", - "integrity": "sha512-ztaw4M1VqgMwl9HlPpOuiYgItcHlunW0He2fE6eNfT6E/CF2FtYi9ofOYe4mKntstYk0Fyh/rDRBdS3AnxjlrA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz", + "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==", "requires": { - "define-properties": "^1.1.2" + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" } }, "regexpu-core": { @@ -7429,9 +7502,9 @@ "integrity": "sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg==" }, "regjsparser": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.0.tgz", - "integrity": "sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ==", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.1.tgz", + "integrity": "sha512-7LutE94sz/NKSYegK+/4E77+8DipxF+Qn2Tmu362AcmsF2NYq/wx3+ObvU90TKEhjf7hQoFXo23ajjrXP7eUgg==", "requires": { "jsesc": "~0.5.0" }, @@ -7668,21 +7741,6 @@ "requires": { "extend-shallow": "^2.0.1", "kind-of": "^6.0.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" - } } }, "select": { @@ -7808,16 +7866,6 @@ "is-extendable": "^0.1.1", "is-plain-object": "^2.0.3", "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } } }, "setimmediate": { @@ -7916,14 +7964,6 @@ "is-descriptor": "^0.1.0" } }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -7974,11 +8014,6 @@ "is-data-descriptor": "^1.0.0", "kind-of": "^6.0.2" } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" } } }, @@ -7988,6 +8023,21 @@ "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", "requires": { "kind-of": "^3.2.0" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } } }, "sockjs": { @@ -8150,6 +8200,25 @@ "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", "requires": { "extend-shallow": "^3.0.0" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } } }, "sprintf-js": { @@ -8254,9 +8323,9 @@ } }, "stream-shift": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", - "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" }, "strict-uri-encode": { "version": "1.1.0", @@ -8541,6 +8610,11 @@ "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=" }, + "tiny-cookie": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tiny-cookie/-/tiny-cookie-2.3.1.tgz", + "integrity": "sha512-C4x1e8dHfKf03ewuN9aIZzzOfN2a6QKhYlnHdzJxmmjMTLqcskI20F+EplszjODQ4SHmIGFJrvUUnBMS/bJbOA==" + }, "tiny-emitter": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", @@ -8595,6 +8669,21 @@ "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", "requires": { "kind-of": "^3.0.2" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } } }, "to-regex": { @@ -8606,6 +8695,25 @@ "extend-shallow": "^3.0.2", "regex-not": "^1.0.2", "safe-regex": "^1.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } } }, "to-regex-range": { @@ -8991,9 +9099,9 @@ "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=" }, "vue": { - "version": "2.6.10", - "resolved": "https://registry.npmjs.org/vue/-/vue-2.6.10.tgz", - "integrity": "sha512-ImThpeNU9HbdZL3utgMCq0oiMzAkt1mcgy3/E6zWC/G6AaQoeuFdsl9nDhTDU3X1R6FK7nsIUuRACVcjI+A2GQ==" + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/vue/-/vue-2.6.11.tgz", + "integrity": "sha512-VfPwgcGABbGAue9+sfrD4PuwFar7gPb1yl1UK1MwXoQPAw0BKSqWfoYCT/ThFrdEVWoI51dBuyCoiNU9bZDZxQ==" }, "vue-hot-reload-api": { "version": "2.3.4", @@ -9001,11 +9109,11 @@ "integrity": "sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==" }, "vue-loader": { - "version": "15.7.2", - "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.7.2.tgz", - "integrity": "sha512-H/P9xt/nkocyu4hZKg5TzPqyCT1oKOaCSk9zs0JCbJuy0Q8KtR0bjJpnT/5R5x/Ckd1GFkkLQnQ1C4x6xXeLZg==", + "version": "15.8.3", + "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.8.3.tgz", + "integrity": "sha512-yFksTFbhp+lxlm92DrKdpVIWMpranXnTEuGSc0oW+Gk43M9LWaAmBTnfj5+FCdve715mTHvo78IdaXf5TbiTJg==", "requires": { - "@vue/component-compiler-utils": "^3.0.0", + "@vue/component-compiler-utils": "^3.1.0", "hash-sum": "^1.0.2", "loader-utils": "^1.1.0", "vue-hot-reload-api": "^2.3.0", @@ -9018,17 +9126,17 @@ "integrity": "sha512-8iSa4mGNXBjyuSZFCCO4fiKfvzqk+mhL0lnKuGcQtO1eoj8nq3CmbEG8FwK5QqoqwDgsjsf1GDuisDX4cdb/aQ==" }, "vue-server-renderer": { - "version": "2.6.10", - "resolved": "https://registry.npmjs.org/vue-server-renderer/-/vue-server-renderer-2.6.10.tgz", - "integrity": "sha512-UYoCEutBpKzL2fKCwx8zlRtRtwxbPZXKTqbl2iIF4yRZUNO/ovrHyDAJDljft0kd+K0tZhN53XRHkgvCZoIhug==", + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/vue-server-renderer/-/vue-server-renderer-2.6.11.tgz", + "integrity": "sha512-V3faFJHr2KYfdSIalL+JjinZSHYUhlrvJ9pzCIjjwSh77+pkrsXpK4PucdPcng57+N77pd1LrKqwbqjQdktU1A==", "requires": { "chalk": "^1.1.3", "hash-sum": "^1.0.2", "he": "^1.1.0", - "lodash.template": "^4.4.0", + "lodash.template": "^4.5.0", "lodash.uniq": "^4.5.0", "resolve": "^1.2.0", - "serialize-javascript": "^1.3.0", + "serialize-javascript": "^2.1.2", "source-map": "0.5.6" }, "dependencies": { @@ -9049,11 +9157,6 @@ "supports-color": "^2.0.0" } }, - "serialize-javascript": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.9.1.tgz", - "integrity": "sha512-0Vb/54WJ6k5v8sSWN09S0ora+Hnr+cX40r9F170nT+mSkaxltoE/7R3OrIdBSUv1OoiobH1QoWQbCnAO+e8J1A==" - }, "source-map": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", @@ -9076,9 +9179,9 @@ } }, "vue-template-compiler": { - "version": "2.6.10", - "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.6.10.tgz", - "integrity": "sha512-jVZkw4/I/HT5ZMvRnhv78okGusqe0+qH2A0Em0Cp8aq78+NK9TII263CDVz2QXZsIT+yyV/gZc/j/vlwa+Epyg==", + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.6.11.tgz", + "integrity": "sha512-KIq15bvQDrcCjpGjrAhx4mUlyyHfdmTaoNfeoATHLAiWB+MU3cx4lOzMwrnUh9cCxy0Lt1T11hAFY6TQgroUAA==", "requires": { "de-indent": "^1.0.2", "he": "^1.1.0" @@ -9155,17 +9258,23 @@ } }, "vuepress-plugin-smooth-scroll": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/vuepress-plugin-smooth-scroll/-/vuepress-plugin-smooth-scroll-0.0.3.tgz", - "integrity": "sha512-qsQkDftLVFLe8BiviIHaLV0Ea38YLZKKonDGsNQy1IE0wllFpFIEldWD8frWZtDFdx6b/O3KDMgVQ0qp5NjJCg==", + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/vuepress-plugin-smooth-scroll/-/vuepress-plugin-smooth-scroll-0.0.9.tgz", + "integrity": "sha512-UXX+HLZO1NKVwyiOJlj0smh8F9dKnwybjEi7w/Mj9EYLhKrNYr5uXs+N+OTt8VwKCn3f0vZ1XAwFIjsPlD7GJA==", "requires": { - "smoothscroll-polyfill": "^0.4.3" + "smoothscroll-polyfill": "^0.4.4" } }, "vuepress-theme-cosmos": { +<<<<<<< HEAD + "version": "1.0.113", + "resolved": "https://registry.npmjs.org/vuepress-theme-cosmos/-/vuepress-theme-cosmos-1.0.113.tgz", + "integrity": "sha512-gSr9Hqp42Ursw7G9N7UG5KQMEVxEsFlPnfb5VlDo3k/s1mruSsZvXczfGEkno0U+lATGROWWU+No4xpOqMADiA==", +======= "version": "1.0.105", "resolved": "https://registry.npmjs.org/vuepress-theme-cosmos/-/vuepress-theme-cosmos-1.0.105.tgz", "integrity": "sha512-UZOPEnNuz5r6cB/o75Qj81/n5BOlpDkf+lGpNxo70C1Eqqg/pjzgj3phhxzSvgXbY5bpdCyeXWySQ8zZnnYtPA==", +>>>>>>> master "requires": { "@cosmos-ui/vue": "^0.5.16", "@vuepress/plugin-last-updated": "^1.2.0", @@ -9175,6 +9284,7 @@ "clipboard-copy": "^3.1.0", "docsearch.js": "^2.6.3", "fuse.js": "^3.4.6", + "gray-matter": "^4.0.2", "hotkeys-js": "^3.7.3", "intersection-observer": "^0.7.0", "lunr": "^2.3.8", @@ -9189,7 +9299,8 @@ "tm-tooltip": "0.0.10", "v-runtime-template": "^1.10.0", "vuepress": "^1.2.0", - "vuepress-plugin-sitemap": "^2.3.1" + "vuepress-plugin-sitemap": "^2.3.1", + "vuepress-plugin-smooth-scroll": "0.0.9" } }, "watchpack": { @@ -9216,9 +9327,9 @@ "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" }, "webpack": { - "version": "4.41.2", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.41.2.tgz", - "integrity": "sha512-Zhw69edTGfbz9/8JJoyRQ/pq8FYUoY0diOXqW0T6yhgdhCv6wr0hra5DwwWexNRns2Z2+gsnrNcbe9hbGBgk/A==", + "version": "4.41.3", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.41.3.tgz", + "integrity": "sha512-EcNzP9jGoxpQAXq1VOoTet0ik7/VVU1MovIfcUSAjLowc7GhcQku/sOXALvq5nPpSei2HF6VRhibeJSC3i/Law==", "requires": { "@webassemblyjs/ast": "1.8.5", "@webassemblyjs/helper-module-context": "1.8.5", @@ -9240,7 +9351,7 @@ "node-libs-browser": "^2.2.1", "schema-utils": "^1.0.0", "tapable": "^1.1.3", - "terser-webpack-plugin": "^1.4.1", + "terser-webpack-plugin": "^1.4.3", "watchpack": "^1.6.0", "webpack-sources": "^1.4.1" }, diff --git a/docs/package.json b/docs/package.json index f0bdcede3481..06255f68eb6a 100644 --- a/docs/package.json +++ b/docs/package.json @@ -5,7 +5,7 @@ "main": "index.js", "scripts": { "preserve": "./pre.sh", - "serve": "trap 'exit 0' SIGINT; vuepress dev", + "serve": "trap 'exit 0' SIGINT; vuepress dev --no-cache", "postserve": "./post.sh", "prebuild": "./pre.sh", "build": "trap 'exit 0' SIGINT; vuepress build --no-cache", @@ -15,6 +15,8 @@ "license": "ISC", "dependencies": { "@vuepress/plugin-google-analytics": "^1.2.0", - "vuepress-theme-cosmos": "^1.0.105" + "tiny-cookie": "^2.3.1", + "vuepress-plugin-smooth-scroll": "0.0.9", + "vuepress-theme-cosmos": "^1.0.113" } -} +} \ No newline at end of file diff --git a/docs/using-the-sdk/README.md b/docs/using-the-sdk/README.md index ef0f84c16fb2..5254bf991ae5 100644 --- a/docs/using-the-sdk/README.md +++ b/docs/using-the-sdk/README.md @@ -1,7 +1,7 @@ ---- + # Using the SDK diff --git a/x/README.md b/x/README.md index 8e86008c0ac0..a37fcfc31cf5 100644 --- a/x/README.md +++ b/x/README.md @@ -1,8 +1,7 @@ ---- -order: 0 + # List of Modules diff --git a/x/auth/spec/01_concepts.md b/x/auth/spec/01_concepts.md index 1794b1d4fa6e..47316b4cbbf6 100644 --- a/x/auth/spec/01_concepts.md +++ b/x/auth/spec/01_concepts.md @@ -1,6 +1,6 @@ ---- + # Concepts diff --git a/x/auth/spec/02_state.md b/x/auth/spec/02_state.md index 92c030e3f6d2..0d1c29d90d77 100644 --- a/x/auth/spec/02_state.md +++ b/x/auth/spec/02_state.md @@ -1,6 +1,6 @@ ---- + # State diff --git a/x/auth/spec/03_messages.md b/x/auth/spec/03_messages.md index b4b64ef07e31..37834d8d1627 100644 --- a/x/auth/spec/03_messages.md +++ b/x/auth/spec/03_messages.md @@ -1,6 +1,6 @@ ---- + # Messages diff --git a/x/auth/spec/03_types.md b/x/auth/spec/03_types.md index efd0637dbc6b..62c1d186c4e1 100644 --- a/x/auth/spec/03_types.md +++ b/x/auth/spec/03_types.md @@ -1,6 +1,6 @@ ---- + # Types diff --git a/x/auth/spec/04_keepers.md b/x/auth/spec/04_keepers.md index b56dbe0fd0ed..e154e5383042 100644 --- a/x/auth/spec/04_keepers.md +++ b/x/auth/spec/04_keepers.md @@ -1,6 +1,6 @@ ---- + # Keepers diff --git a/x/auth/spec/05_vesting.md b/x/auth/spec/05_vesting.md index 81de8fff3868..7cddc26e7c67 100644 --- a/x/auth/spec/05_vesting.md +++ b/x/auth/spec/05_vesting.md @@ -1,6 +1,6 @@ ---- + # Vesting diff --git a/x/auth/spec/07_params.md b/x/auth/spec/07_params.md index a3983eb657d6..6ef63ed1215b 100644 --- a/x/auth/spec/07_params.md +++ b/x/auth/spec/07_params.md @@ -1,6 +1,6 @@ ---- + # Parameters diff --git a/x/auth/spec/README.md b/x/auth/spec/README.md index b6627bfe9561..ea49a9736efe 100644 --- a/x/auth/spec/README.md +++ b/x/auth/spec/README.md @@ -1,9 +1,9 @@ ---- + # `auth` diff --git a/x/bank/spec/01_state.md b/x/bank/spec/01_state.md index 67050c46112d..ba0e25b899b0 100644 --- a/x/bank/spec/01_state.md +++ b/x/bank/spec/01_state.md @@ -1,6 +1,6 @@ ---- + # State diff --git a/x/bank/spec/02_keepers.md b/x/bank/spec/02_keepers.md index 45a42e618eb7..d20b42fe3dea 100644 --- a/x/bank/spec/02_keepers.md +++ b/x/bank/spec/02_keepers.md @@ -1,6 +1,6 @@ ---- + # Keepers diff --git a/x/bank/spec/03_messages.md b/x/bank/spec/03_messages.md index dbdb8e7df0cd..f9cde522837a 100644 --- a/x/bank/spec/03_messages.md +++ b/x/bank/spec/03_messages.md @@ -1,6 +1,6 @@ ---- + # Messages diff --git a/x/bank/spec/04_events.md b/x/bank/spec/04_events.md index c5794b7daa06..481ee9f0d2c5 100644 --- a/x/bank/spec/04_events.md +++ b/x/bank/spec/04_events.md @@ -1,6 +1,6 @@ ---- + # Events diff --git a/x/bank/spec/05_params.md b/x/bank/spec/05_params.md index cd99570fe629..fe59bed244ec 100644 --- a/x/bank/spec/05_params.md +++ b/x/bank/spec/05_params.md @@ -1,6 +1,6 @@ ---- + # Parameters diff --git a/x/bank/spec/README.md b/x/bank/spec/README.md index 9ddad6ea6e9c..28902554f49f 100644 --- a/x/bank/spec/README.md +++ b/x/bank/spec/README.md @@ -1,9 +1,9 @@ ---- + # `bank` diff --git a/x/crisis/spec/01_state.md b/x/crisis/spec/01_state.md index 9163934cad90..cbb949b0e327 100644 --- a/x/crisis/spec/01_state.md +++ b/x/crisis/spec/01_state.md @@ -1,6 +1,6 @@ ---- + # State diff --git a/x/crisis/spec/02_messages.md b/x/crisis/spec/02_messages.md index 916fba3a24ba..93a01aec2677 100644 --- a/x/crisis/spec/02_messages.md +++ b/x/crisis/spec/02_messages.md @@ -1,6 +1,6 @@ ---- + # Messages diff --git a/x/crisis/spec/03_events.md b/x/crisis/spec/03_events.md index 92f231c83f66..5aef2078ebf9 100644 --- a/x/crisis/spec/03_events.md +++ b/x/crisis/spec/03_events.md @@ -1,6 +1,6 @@ ---- + # Events diff --git a/x/crisis/spec/04_params.md b/x/crisis/spec/04_params.md index 663ba62d0da7..0d046adaa5e3 100644 --- a/x/crisis/spec/04_params.md +++ b/x/crisis/spec/04_params.md @@ -1,6 +1,6 @@ ---- + # Parameters diff --git a/x/crisis/spec/README.md b/x/crisis/spec/README.md index 73bba46b4eb5..de75381bf1ae 100644 --- a/x/crisis/spec/README.md +++ b/x/crisis/spec/README.md @@ -1,9 +1,9 @@ ---- + # `crisis` diff --git a/x/distribution/spec/01_concepts.md b/x/distribution/spec/01_concepts.md index 720821bb1f62..70c684690c98 100644 --- a/x/distribution/spec/01_concepts.md +++ b/x/distribution/spec/01_concepts.md @@ -1,6 +1,6 @@ ---- + # Concepts diff --git a/x/distribution/spec/02_state.md b/x/distribution/spec/02_state.md index 2f9629c98b2b..624fb9f0ff61 100644 --- a/x/distribution/spec/02_state.md +++ b/x/distribution/spec/02_state.md @@ -1,6 +1,6 @@ ---- + # State diff --git a/x/distribution/spec/03_end_block.md b/x/distribution/spec/03_end_block.md index ffc315b000ce..c5f8d655a5fb 100644 --- a/x/distribution/spec/03_end_block.md +++ b/x/distribution/spec/03_end_block.md @@ -1,6 +1,6 @@ ---- + # End Block diff --git a/x/distribution/spec/04_messages.md b/x/distribution/spec/04_messages.md index 45b0877f1f8b..ef57cb4c3106 100644 --- a/x/distribution/spec/04_messages.md +++ b/x/distribution/spec/04_messages.md @@ -1,6 +1,6 @@ ---- + # Messages diff --git a/x/distribution/spec/05_hooks.md b/x/distribution/spec/05_hooks.md index cf066872cd61..dfedf31831d4 100644 --- a/x/distribution/spec/05_hooks.md +++ b/x/distribution/spec/05_hooks.md @@ -1,6 +1,6 @@ ---- + # Hooks diff --git a/x/distribution/spec/06_events.md b/x/distribution/spec/06_events.md index 303283b32ce1..7e70f0beb4c5 100644 --- a/x/distribution/spec/06_events.md +++ b/x/distribution/spec/06_events.md @@ -1,6 +1,6 @@ ---- + # Events diff --git a/x/distribution/spec/07_params.md b/x/distribution/spec/07_params.md index 4daa7e0cacb9..5a933e923a6b 100644 --- a/x/distribution/spec/07_params.md +++ b/x/distribution/spec/07_params.md @@ -1,6 +1,6 @@ ---- + # Parameters diff --git a/x/distribution/spec/README.md b/x/distribution/spec/README.md index c710934bb78b..6eac14be46ba 100644 --- a/x/distribution/spec/README.md +++ b/x/distribution/spec/README.md @@ -1,9 +1,9 @@ ---- + # `distribution` diff --git a/x/evidence/spec/01_concepts.md b/x/evidence/spec/01_concepts.md index d1cb158f1e0b..3b50ccecfb76 100644 --- a/x/evidence/spec/01_concepts.md +++ b/x/evidence/spec/01_concepts.md @@ -1,6 +1,6 @@ ---- + # Concepts diff --git a/x/evidence/spec/02_state.md b/x/evidence/spec/02_state.md index 7541d1d21cfa..f65876837ae2 100644 --- a/x/evidence/spec/02_state.md +++ b/x/evidence/spec/02_state.md @@ -1,6 +1,6 @@ ---- + # State diff --git a/x/evidence/spec/03_messages.md b/x/evidence/spec/03_messages.md index 9be381e65b87..a39052dab986 100644 --- a/x/evidence/spec/03_messages.md +++ b/x/evidence/spec/03_messages.md @@ -1,6 +1,6 @@ ---- + # Messages diff --git a/x/evidence/spec/04_events.md b/x/evidence/spec/04_events.md index d1c701b21e32..35fd77b3f5ac 100644 --- a/x/evidence/spec/04_events.md +++ b/x/evidence/spec/04_events.md @@ -1,6 +1,6 @@ ---- + # Events diff --git a/x/evidence/spec/05_params.md b/x/evidence/spec/05_params.md index d33005e5c474..15a444ecde9e 100644 --- a/x/evidence/spec/05_params.md +++ b/x/evidence/spec/05_params.md @@ -1,6 +1,6 @@ ---- + # Parameters diff --git a/x/evidence/spec/06_begin_block.md b/x/evidence/spec/06_begin_block.md index b9a53d116d8c..e90543862e71 100644 --- a/x/evidence/spec/06_begin_block.md +++ b/x/evidence/spec/06_begin_block.md @@ -1,6 +1,6 @@ ---- + # BeginBlock diff --git a/x/evidence/spec/README.md b/x/evidence/spec/README.md index b04f704caa95..ff0754133ce6 100644 --- a/x/evidence/spec/README.md +++ b/x/evidence/spec/README.md @@ -1,9 +1,9 @@ ---- + # `evidence` diff --git a/x/gov/spec/01_concepts.md b/x/gov/spec/01_concepts.md index cb6210e2786e..deed64b36c95 100644 --- a/x/gov/spec/01_concepts.md +++ b/x/gov/spec/01_concepts.md @@ -1,6 +1,6 @@ ---- + # Concepts diff --git a/x/gov/spec/02_state.md b/x/gov/spec/02_state.md index d647929816aa..e180c2839461 100644 --- a/x/gov/spec/02_state.md +++ b/x/gov/spec/02_state.md @@ -1,6 +1,6 @@ ---- + # State diff --git a/x/gov/spec/03_messages.md b/x/gov/spec/03_messages.md index 1df329807934..f0e8dc9161c5 100644 --- a/x/gov/spec/03_messages.md +++ b/x/gov/spec/03_messages.md @@ -1,6 +1,6 @@ ---- + # Messages diff --git a/x/gov/spec/04_events.md b/x/gov/spec/04_events.md index b2f749db1b19..918b3754ed19 100644 --- a/x/gov/spec/04_events.md +++ b/x/gov/spec/04_events.md @@ -1,6 +1,6 @@ ---- + # Events diff --git a/x/gov/spec/05_future_improvements.md b/x/gov/spec/05_future_improvements.md index 96af61e84168..6a8350f569b8 100644 --- a/x/gov/spec/05_future_improvements.md +++ b/x/gov/spec/05_future_improvements.md @@ -1,6 +1,6 @@ ---- + # Future Improvements diff --git a/x/gov/spec/06_params.md b/x/gov/spec/06_params.md index db146b9a854a..f8dbe5edc91a 100644 --- a/x/gov/spec/06_params.md +++ b/x/gov/spec/06_params.md @@ -1,6 +1,6 @@ ---- + # Parameters diff --git a/x/gov/spec/README.md b/x/gov/spec/README.md index 846158540858..38f516a955f4 100644 --- a/x/gov/spec/README.md +++ b/x/gov/spec/README.md @@ -1,9 +1,9 @@ ---- + # `gov` diff --git a/x/mint/spec/01_concepts.md b/x/mint/spec/01_concepts.md index e4a4884e27ff..1dd137b97b97 100644 --- a/x/mint/spec/01_concepts.md +++ b/x/mint/spec/01_concepts.md @@ -1,6 +1,6 @@ ---- -order: 1 ---- + # Concepts diff --git a/x/mint/spec/02_state.md b/x/mint/spec/02_state.md index f59a146d78d0..c4d7a3eff185 100644 --- a/x/mint/spec/02_state.md +++ b/x/mint/spec/02_state.md @@ -1,6 +1,6 @@ ---- + # State diff --git a/x/mint/spec/03_begin_block.md b/x/mint/spec/03_begin_block.md index c2e27ec2a453..33eeffa52961 100644 --- a/x/mint/spec/03_begin_block.md +++ b/x/mint/spec/03_begin_block.md @@ -1,6 +1,6 @@ ---- + # Begin-Block diff --git a/x/mint/spec/04_params.md b/x/mint/spec/04_params.md index f87766c4e908..ed18e5557ebb 100644 --- a/x/mint/spec/04_params.md +++ b/x/mint/spec/04_params.md @@ -1,6 +1,6 @@ ---- + # Parameters diff --git a/x/mint/spec/05_events.md b/x/mint/spec/05_events.md index c7191eebb132..f6130a3b999a 100644 --- a/x/mint/spec/05_events.md +++ b/x/mint/spec/05_events.md @@ -1,6 +1,6 @@ ---- + # Events diff --git a/x/mint/spec/README.md b/x/mint/spec/README.md index f8fda23588fb..950cadbb1c89 100644 --- a/x/mint/spec/README.md +++ b/x/mint/spec/README.md @@ -1,9 +1,9 @@ ---- + # `mint` diff --git a/x/params/spec/01_keeper.md b/x/params/spec/01_keeper.md index 5a257b568188..b2256919a4b1 100644 --- a/x/params/spec/01_keeper.md +++ b/x/params/spec/01_keeper.md @@ -1,6 +1,6 @@ ---- + # Keeper diff --git a/x/params/spec/02_subspace.md b/x/params/spec/02_subspace.md index feb395430c80..98102791fd70 100644 --- a/x/params/spec/02_subspace.md +++ b/x/params/spec/02_subspace.md @@ -1,6 +1,6 @@ ---- + # Subspace diff --git a/x/params/spec/README.md b/x/params/spec/README.md index 6d8934aa9b0d..c84ad6e5bc9a 100644 --- a/x/params/spec/README.md +++ b/x/params/spec/README.md @@ -1,9 +1,9 @@ ---- + # `params` diff --git a/x/slashing/spec/01_concepts.md b/x/slashing/spec/01_concepts.md index 62eca44d8e2b..b38a6edbed8c 100644 --- a/x/slashing/spec/01_concepts.md +++ b/x/slashing/spec/01_concepts.md @@ -1,6 +1,6 @@ ---- + # Concepts diff --git a/x/slashing/spec/02_state.md b/x/slashing/spec/02_state.md index dbe7055e70d0..867fa7998374 100644 --- a/x/slashing/spec/02_state.md +++ b/x/slashing/spec/02_state.md @@ -1,6 +1,6 @@ ---- + # State diff --git a/x/slashing/spec/03_messages.md b/x/slashing/spec/03_messages.md index 160c2a332338..d7825bfd0b8f 100644 --- a/x/slashing/spec/03_messages.md +++ b/x/slashing/spec/03_messages.md @@ -1,6 +1,6 @@ ---- + # Messages diff --git a/x/slashing/spec/04_begin_block.md b/x/slashing/spec/04_begin_block.md index 17e6d39525fb..96d1217f1945 100644 --- a/x/slashing/spec/04_begin_block.md +++ b/x/slashing/spec/04_begin_block.md @@ -1,6 +1,6 @@ ---- + # BeginBlock diff --git a/x/slashing/spec/05_hooks.md b/x/slashing/spec/05_hooks.md index cfb8eabf8658..adb8da39b01f 100644 --- a/x/slashing/spec/05_hooks.md +++ b/x/slashing/spec/05_hooks.md @@ -1,6 +1,6 @@ ---- + # Hooks diff --git a/x/slashing/spec/06_events.md b/x/slashing/spec/06_events.md index a56b70c06091..c5fceda51981 100644 --- a/x/slashing/spec/06_events.md +++ b/x/slashing/spec/06_events.md @@ -1,6 +1,6 @@ ---- + # Tags diff --git a/x/slashing/spec/07_tombstone.md b/x/slashing/spec/07_tombstone.md index 23d4babeeca7..a062278cec9d 100644 --- a/x/slashing/spec/07_tombstone.md +++ b/x/slashing/spec/07_tombstone.md @@ -1,6 +1,6 @@ ---- + # Staking Tombstone diff --git a/x/slashing/spec/08_params.md b/x/slashing/spec/08_params.md index 1ecb815013a4..0ebfb9e27ef2 100644 --- a/x/slashing/spec/08_params.md +++ b/x/slashing/spec/08_params.md @@ -1,6 +1,6 @@ ---- + # Parameters diff --git a/x/slashing/spec/README.md b/x/slashing/spec/README.md index 57fc11b941cb..7f694d03d36f 100644 --- a/x/slashing/spec/README.md +++ b/x/slashing/spec/README.md @@ -1,9 +1,9 @@ ---- -order: 0 + # `slashing` diff --git a/x/staking/spec/01_state.md b/x/staking/spec/01_state.md index 890d6925118d..bf388a143615 100644 --- a/x/staking/spec/01_state.md +++ b/x/staking/spec/01_state.md @@ -1,6 +1,6 @@ ---- + # State diff --git a/x/staking/spec/02_state_transitions.md b/x/staking/spec/02_state_transitions.md index 634f5ac85308..8aaa9c36443a 100644 --- a/x/staking/spec/02_state_transitions.md +++ b/x/staking/spec/02_state_transitions.md @@ -1,6 +1,6 @@ ---- + # State Transitions diff --git a/x/staking/spec/03_messages.md b/x/staking/spec/03_messages.md index 2f9a71521f14..d7b98b1aabab 100644 --- a/x/staking/spec/03_messages.md +++ b/x/staking/spec/03_messages.md @@ -1,6 +1,6 @@ ---- + # Messages diff --git a/x/staking/spec/04_end_block.md b/x/staking/spec/04_end_block.md index d42b26704e9e..3207c078cd30 100644 --- a/x/staking/spec/04_end_block.md +++ b/x/staking/spec/04_end_block.md @@ -1,6 +1,6 @@ ---- + # End-Block diff --git a/x/staking/spec/05_hooks.md b/x/staking/spec/05_hooks.md index 10e084e2a5f0..2eac2d4a1708 100644 --- a/x/staking/spec/05_hooks.md +++ b/x/staking/spec/05_hooks.md @@ -1,6 +1,6 @@ ---- + # Hooks diff --git a/x/staking/spec/06_events.md b/x/staking/spec/06_events.md index 5994af5fa3a6..48162355cf97 100644 --- a/x/staking/spec/06_events.md +++ b/x/staking/spec/06_events.md @@ -1,6 +1,6 @@ ---- + # Events diff --git a/x/staking/spec/07_params.md b/x/staking/spec/07_params.md index 4fdd5ca124e4..6df38579dc81 100644 --- a/x/staking/spec/07_params.md +++ b/x/staking/spec/07_params.md @@ -1,6 +1,6 @@ ---- + # Parameters diff --git a/x/staking/spec/README.md b/x/staking/spec/README.md index c889d06841be..7f61b900cd92 100644 --- a/x/staking/spec/README.md +++ b/x/staking/spec/README.md @@ -1,9 +1,9 @@ ---- + # `staking` diff --git a/x/supply/spec/01_concepts.md b/x/supply/spec/01_concepts.md index 4cd86bce2dc7..89af77fe68bd 100644 --- a/x/supply/spec/01_concepts.md +++ b/x/supply/spec/01_concepts.md @@ -1,6 +1,6 @@ ---- + # Concepts diff --git a/x/supply/spec/02_state.md b/x/supply/spec/02_state.md index 65ca6b57aa5f..5f232d740a86 100644 --- a/x/supply/spec/02_state.md +++ b/x/supply/spec/02_state.md @@ -1,6 +1,6 @@ ---- + # State diff --git a/x/supply/spec/03_future_improvements.md b/x/supply/spec/03_future_improvements.md index b4fc078b1ba7..11011b6ff7a3 100644 --- a/x/supply/spec/03_future_improvements.md +++ b/x/supply/spec/03_future_improvements.md @@ -1,6 +1,6 @@ ---- + # Future improvements diff --git a/x/supply/spec/README.md b/x/supply/spec/README.md index 833ac1529017..25f2e3b8afee 100644 --- a/x/supply/spec/README.md +++ b/x/supply/spec/README.md @@ -1,9 +1,9 @@ ---- + # `supply` diff --git a/x/upgrade/spec/01_concepts.md b/x/upgrade/spec/01_concepts.md index b5e5c2208c27..19205591fc15 100644 --- a/x/upgrade/spec/01_concepts.md +++ b/x/upgrade/spec/01_concepts.md @@ -1,6 +1,6 @@ ---- + # Concepts diff --git a/x/upgrade/spec/02_state.md b/x/upgrade/spec/02_state.md index 585e6f0c4c33..f069b4f96797 100644 --- a/x/upgrade/spec/02_state.md +++ b/x/upgrade/spec/02_state.md @@ -1,6 +1,6 @@ ---- + # State diff --git a/x/upgrade/spec/03_events.md b/x/upgrade/spec/03_events.md index 7e86d08dae40..e4e0e6d5fc26 100644 --- a/x/upgrade/spec/03_events.md +++ b/x/upgrade/spec/03_events.md @@ -1,6 +1,6 @@ ---- + # Events diff --git a/x/upgrade/spec/README.md b/x/upgrade/spec/README.md index 94d352a25bb3..eb34357071e6 100644 --- a/x/upgrade/spec/README.md +++ b/x/upgrade/spec/README.md @@ -1,9 +1,9 @@ ---- + # `upgrade` From 347125678557557a29895f4baa9750cef8c9f360 Mon Sep 17 00:00:00 2001 From: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Date: Tue, 17 Dec 2019 15:28:52 -0300 Subject: [PATCH 040/529] Merge PR #5378: application interfaces for simulation --- CHANGELOG.md | 7 +- simapp/app.go | 11 ++ simapp/app_test.go | 2 +- simapp/config.go | 75 ++++++++++++++ simapp/{ => params}/params.go | 2 +- simapp/sim_bench_test.go | 97 +++++++----------- simapp/sim_test.go | 184 ++++++++++------------------------ simapp/state.go | 5 +- simapp/test_helpers.go | 6 +- simapp/types.go | 46 +++++++++ simapp/utils.go | 153 ++++++++++++---------------- 11 files changed, 301 insertions(+), 287 deletions(-) create mode 100644 simapp/config.go rename simapp/{ => params}/params.go (91%) create mode 100644 simapp/types.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 15b78b68bf43..591b6e4c65d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -182,7 +182,7 @@ generalized genesis accounts through the `GenesisAccount` interface. * (sdk) [\#4640](https://github.com/cosmos/cosmos-sdk/issues/4640) improve import/export simulation errors by extending `DiffKVStores` to return an array of `KVPairs` that are then compared to check for inconsistencies. * (sdk) [\#4717](https://github.com/cosmos/cosmos-sdk/issues/4717) refactor `x/slashing` to match the new module spec * (sdk) [\#4758](https://github.com/cosmos/cosmos-sdk/issues/4758) update `x/genaccounts` to match module spec -* (simulation) [\#4824](https://github.com/cosmos/cosmos-sdk/issues/4824) PrintAllInvariants flag will print all failed invariants +* (simulation) [\#4824](https://github.com/cosmos/cosmos-sdk/issues/4824) `PrintAllInvariants` flag will print all failed invariants * (simulation) [\#4490](https://github.com/cosmos/cosmos-sdk/issues/4490) add `InitialBlockHeight` flag to resume a simulation from a given block * Support exporting the simulation stats to a given JSON file * (simulation) [\#4847](https://github.com/cosmos/cosmos-sdk/issues/4847), [\#4838](https://github.com/cosmos/cosmos-sdk/pull/4838) and [\#4869](https://github.com/cosmos/cosmos-sdk/pull/4869) `SimApp` and simulation refactors: @@ -194,9 +194,12 @@ generalized genesis accounts through the `GenesisAccount` interface. * Add `WeightedOperations` to the `SimulationManager` that define simulation operations (modules' `Msg`s) with their respective weights (i.e chance of being simulated). * Add `ProposalContents` to the `SimulationManager` to register each module's governance proposal `Content`s. -* (simulation) [\#4893](https://github.com/cosmos/cosmos-sdk/issues/4893) Change SimApp keepers to be public and add getter functions for keys and codec +* (simulation) [\#4893](https://github.com/cosmos/cosmos-sdk/issues/4893) Change `SimApp` keepers to be public and add getter functions for keys and codec * (simulation) [\#4906](https://github.com/cosmos/cosmos-sdk/issues/4906) Add simulation `Config` struct that wraps simulation flags * (simulation) [\#4935](https://github.com/cosmos/cosmos-sdk/issues/4935) Update simulation to reflect a proper `ABCI` application without bypassing `BaseApp` semantics +* (simulation) [\#5378](https://github.com/cosmos/cosmos-sdk/pull/5378) Simulation tests refactor: + * Add `App` interface for general SDK-based app's methods. + * Refactor and cleanup simulation tests into util functions to simplify their implementation for other SDK apps. * (store) [\#4792](https://github.com/cosmos/cosmos-sdk/issues/4792) panic on non-registered store * (types) [\#4821](https://github.com/cosmos/cosmos-sdk/issues/4821) types/errors package added with support for stacktraces. It is meant as a more feature-rich replacement for sdk.Errors in the mid-term. * (store) [\#1947](https://github.com/cosmos/cosmos-sdk/issues/1947) Implement inter-block (persistent) diff --git a/simapp/app.go b/simapp/app.go index 1f10c7674bd9..2bd4ed3543f5 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -89,6 +89,9 @@ func MakeCodec() *codec.Codec { return cdc } +// Verify app interface at compile time +var _ App = (*SimApp)(nil) + // SimApp extends an ABCI application, but with most of its parameters exported. // They are exported for convenience in creating helper functions, as object // capabilities aren't needed for testing. @@ -295,6 +298,9 @@ func NewSimApp( return app } +// Name returns the name of the App +func (app *SimApp) Name() string { return app.BaseApp.Name() } + // BeginBlocker application updates every begin block func (app *SimApp) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) abci.ResponseBeginBlock { return app.mm.BeginBlock(ctx, req) @@ -366,6 +372,11 @@ func (app *SimApp) GetSubspace(moduleName string) params.Subspace { return app.subspaces[moduleName] } +// SimulationManager implements the SimulationApp interface +func (app *SimApp) SimulationManager() *module.SimulationManager { + return app.sm +} + // GetMaccPerms returns a copy of the module account permissions func GetMaccPerms() map[string][]string { dupMaccPerms := make(map[string][]string) diff --git a/simapp/app_test.go b/simapp/app_test.go index 2be73cdfbf0e..1f152976f1e9 100644 --- a/simapp/app_test.go +++ b/simapp/app_test.go @@ -18,7 +18,7 @@ func TestSimAppExport(t *testing.T) { app := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, 0) genesisState := NewDefaultGenesisState() - stateBytes, err := codec.MarshalJSONIndent(app.cdc, genesisState) + stateBytes, err := codec.MarshalJSONIndent(app.Codec(), genesisState) require.NoError(t, err) // Initialize the chain diff --git a/simapp/config.go b/simapp/config.go new file mode 100644 index 000000000000..d42527d3dc6f --- /dev/null +++ b/simapp/config.go @@ -0,0 +1,75 @@ +package simapp + +import ( + "flag" + + "github.com/cosmos/cosmos-sdk/x/simulation" +) + +// List of available flags for the simulator +var ( + FlagGenesisFileValue string + FlagParamsFileValue string + FlagExportParamsPathValue string + FlagExportParamsHeightValue int + FlagExportStatePathValue string + FlagExportStatsPathValue string + FlagSeedValue int64 + FlagInitialBlockHeightValue int + FlagNumBlocksValue int + FlagBlockSizeValue int + FlagLeanValue bool + FlagCommitValue bool + FlagOnOperationValue bool // TODO: Remove in favor of binary search for invariant violation + FlagAllInvariantsValue bool + + FlagEnabledValue bool + FlagVerboseValue bool + FlagPeriodValue uint + FlagGenesisTimeValue int64 +) + +// GetSimulatorFlags gets the values of all the available simulation flags +func GetSimulatorFlags() { + // config fields + flag.StringVar(&FlagGenesisFileValue, "Genesis", "", "custom simulation genesis file; cannot be used with params file") + flag.StringVar(&FlagParamsFileValue, "Params", "", "custom simulation params file which overrides any random params; cannot be used with genesis") + flag.StringVar(&FlagExportParamsPathValue, "ExportParamsPath", "", "custom file path to save the exported params JSON") + flag.IntVar(&FlagExportParamsHeightValue, "ExportParamsHeight", 0, "height to which export the randomly generated params") + flag.StringVar(&FlagExportStatePathValue, "ExportStatePath", "", "custom file path to save the exported app state JSON") + flag.StringVar(&FlagExportStatsPathValue, "ExportStatsPath", "", "custom file path to save the exported simulation statistics JSON") + flag.Int64Var(&FlagSeedValue, "Seed", 42, "simulation random seed") + flag.IntVar(&FlagInitialBlockHeightValue, "InitialBlockHeight", 1, "initial block to start the simulation") + flag.IntVar(&FlagNumBlocksValue, "NumBlocks", 500, "number of new blocks to simulate from the initial block height") + flag.IntVar(&FlagBlockSizeValue, "BlockSize", 200, "operations per block") + flag.BoolVar(&FlagLeanValue, "Lean", false, "lean simulation log output") + flag.BoolVar(&FlagCommitValue, "Commit", false, "have the simulation commit") + flag.BoolVar(&FlagOnOperationValue, "SimulateEveryOperation", false, "run slow invariants every operation") + flag.BoolVar(&FlagAllInvariantsValue, "PrintAllInvariants", false, "print all invariants if a broken invariant is found") + + // simulation flags + flag.BoolVar(&FlagEnabledValue, "Enabled", false, "enable the simulation") + flag.BoolVar(&FlagVerboseValue, "Verbose", false, "verbose log output") + flag.UintVar(&FlagPeriodValue, "Period", 0, "run slow invariants only once every period assertions") + flag.Int64Var(&FlagGenesisTimeValue, "GenesisTime", 0, "override genesis UNIX time instead of using a random UNIX time") +} + +// NewConfigFromFlags creates a simulation from the retrieved values of the flags. +func NewConfigFromFlags() simulation.Config { + return simulation.Config{ + GenesisFile: FlagGenesisFileValue, + ParamsFile: FlagParamsFileValue, + ExportParamsPath: FlagExportParamsPathValue, + ExportParamsHeight: FlagExportParamsHeightValue, + ExportStatePath: FlagExportStatePathValue, + ExportStatsPath: FlagExportStatsPathValue, + Seed: FlagSeedValue, + InitialBlockHeight: FlagInitialBlockHeightValue, + NumBlocks: FlagNumBlocksValue, + BlockSize: FlagBlockSizeValue, + Lean: FlagLeanValue, + Commit: FlagCommitValue, + OnOperation: FlagOnOperationValue, + AllInvariants: FlagAllInvariantsValue, + } +} diff --git a/simapp/params.go b/simapp/params/params.go similarity index 91% rename from simapp/params.go rename to simapp/params/params.go index 7bb425b5f46f..b6aa5fb55e0f 100644 --- a/simapp/params.go +++ b/simapp/params/params.go @@ -1,4 +1,4 @@ -package simapp +package params // Simulation parameter constants const ( diff --git a/simapp/sim_bench_test.go b/simapp/sim_bench_test.go index 994e9803247a..2b6c486bf9b8 100644 --- a/simapp/sim_bench_test.go +++ b/simapp/sim_bench_test.go @@ -2,113 +2,88 @@ package simapp import ( "fmt" - "io/ioutil" "os" "testing" - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/libs/log" - dbm "github.com/tendermint/tm-db" - - "github.com/cosmos/cosmos-sdk/simapp/helpers" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/simulation" + abci "github.com/tendermint/tendermint/abci/types" ) // Profile with: // /usr/local/go/bin/go test -benchmem -run=^$ github.com/cosmos/cosmos-sdk/simapp -bench ^BenchmarkFullAppSimulation$ -Commit=true -cpuprofile cpu.out func BenchmarkFullAppSimulation(b *testing.B) { - logger := log.NewNopLogger() - config := NewConfigFromFlags() - config.ChainID = helpers.SimAppChainID + config, db, dir, logger, _, err := SetupSimulation("goleveldb-app-sim", "Simulation") + if err != nil { + b.Fatalf("simulation setup failed: %s", err.Error()) + } - var db dbm.DB - dir, _ := ioutil.TempDir("", "goleveldb-app-sim") - db, _ = sdk.NewLevelDB("Simulation", dir) defer func() { db.Close() - os.RemoveAll(dir) + err = os.RemoveAll(dir) + if err != nil { + b.Fatal(err) + } }() app := NewSimApp(logger, db, nil, true, FlagPeriodValue, interBlockCacheOpt()) - // Run randomized simulation - // TODO: parameterize numbers, save for a later PR + // run randomized simulation _, simParams, simErr := simulation.SimulateFromSeed( - b, os.Stdout, app.BaseApp, AppStateFn(app.Codec(), app.sm), + b, os.Stdout, app.BaseApp, AppStateFn(app.Codec(), app.SimulationManager()), SimulationOperations(app, app.Codec(), config), app.ModuleAccountAddrs(), config, ) - // export state and params before the simulation error is checked - if config.ExportStatePath != "" { - if err := ExportStateToJSON(app, config.ExportStatePath); err != nil { - fmt.Println(err) - b.Fail() - } - } - - if config.ExportParamsPath != "" { - if err := ExportParamsToJSON(simParams, config.ExportParamsPath); err != nil { - fmt.Println(err) - b.Fail() - } + // export state and simParams before the simulation error is checked + if err = CheckExportSimulation(app, config, simParams); err != nil { + b.Fatal(err) } if simErr != nil { - fmt.Println(simErr) - b.FailNow() + b.Fatal(simErr) } if config.Commit { - fmt.Println("\nGoLevelDB Stats") - fmt.Println(db.Stats()["leveldb.stats"]) - fmt.Println("GoLevelDB cached block size", db.Stats()["leveldb.cachedblock"]) + PrintStats(db) } } func BenchmarkInvariants(b *testing.B) { - logger := log.NewNopLogger() + config, db, dir, logger, _, err := SetupSimulation("leveldb-app-invariant-bench", "Simulation") + if err != nil { + b.Fatalf("simulation setup failed: %s", err.Error()) + } - config := NewConfigFromFlags() config.AllInvariants = false - config.ChainID = helpers.SimAppChainID - - dir, _ := ioutil.TempDir("", "goleveldb-app-invariant-bench") - db, _ := sdk.NewLevelDB("simulation", dir) defer func() { db.Close() - os.RemoveAll(dir) + err = os.RemoveAll(dir) + if err != nil { + b.Fatal(err) + } }() app := NewSimApp(logger, db, nil, true, FlagPeriodValue, interBlockCacheOpt()) - // 2. Run parameterized simulation (w/o invariants) + // run randomized simulation _, simParams, simErr := simulation.SimulateFromSeed( - b, ioutil.Discard, app.BaseApp, AppStateFn(app.Codec(), app.sm), + b, os.Stdout, app.BaseApp, AppStateFn(app.Codec(), app.SimulationManager()), SimulationOperations(app, app.Codec(), config), app.ModuleAccountAddrs(), config, ) - // export state and params before the simulation error is checked - if config.ExportStatePath != "" { - if err := ExportStateToJSON(app, config.ExportStatePath); err != nil { - fmt.Println(err) - b.Fail() - } + // export state and simParams before the simulation error is checked + if err = CheckExportSimulation(app, config, simParams); err != nil { + b.Fatal(err) } - if config.ExportParamsPath != "" { - if err := ExportParamsToJSON(simParams, config.ExportParamsPath); err != nil { - fmt.Println(err) - b.Fail() - } + if simErr != nil { + b.Fatal(simErr) } - if simErr != nil { - fmt.Println(simErr) - b.FailNow() + if config.Commit { + PrintStats(db) } ctx := app.NewContext(true, abci.Header{Height: app.LastBlockHeight() + 1}) @@ -121,8 +96,10 @@ func BenchmarkInvariants(b *testing.B) { cr := cr b.Run(fmt.Sprintf("%s/%s", cr.ModuleName, cr.Route), func(b *testing.B) { if res, stop := cr.Invar(ctx); stop { - fmt.Printf("broken invariant at block %d of %d\n%s", ctx.BlockHeight()-1, config.NumBlocks, res) - b.FailNow() + b.Fatalf( + "broken invariant at block %d of %d\n%s", + ctx.BlockHeight()-1, config.NumBlocks, res, + ) } }) } diff --git a/simapp/sim_test.go b/simapp/sim_test.go index 100e685836fc..7738b29a4263 100644 --- a/simapp/sim_test.go +++ b/simapp/sim_test.go @@ -3,7 +3,6 @@ package simapp import ( "encoding/json" "fmt" - "io/ioutil" "math/rand" "os" "testing" @@ -33,6 +32,12 @@ func init() { GetSimulatorFlags() } +type StoreKeysPrefixes struct { + A sdk.StoreKey + B sdk.StoreKey + Prefixes [][]byte +} + // fauxMerkleModeOpt returns a BaseApp option to use a dbStoreAdapter instead of // an IAVLStore for faster simulation speed. func fauxMerkleModeOpt(bapp *baseapp.BaseApp) { @@ -46,83 +51,47 @@ func interBlockCacheOpt() func(*baseapp.BaseApp) { } func TestFullAppSimulation(t *testing.T) { - if !FlagEnabledValue { + config, db, dir, logger, skip, err := SetupSimulation("leveldb-app-sim", "Simulation") + if skip { t.Skip("skipping application simulation") } - - var logger log.Logger - config := NewConfigFromFlags() - config.ChainID = helpers.SimAppChainID - - if FlagVerboseValue { - logger = log.TestingLogger() - } else { - logger = log.NewNopLogger() - } - - var db dbm.DB - dir, _ := ioutil.TempDir("", "goleveldb-app-sim") - db, _ = sdk.NewLevelDB("Simulation", dir) + require.NoError(t, err, "simulation setup failed") defer func() { db.Close() - os.RemoveAll(dir) + require.NoError(t, os.RemoveAll(dir)) }() app := NewSimApp(logger, db, nil, true, FlagPeriodValue, fauxMerkleModeOpt) require.Equal(t, "SimApp", app.Name()) - // Run randomized simulation + // run randomized simulation _, simParams, simErr := simulation.SimulateFromSeed( - t, os.Stdout, app.BaseApp, AppStateFn(app.Codec(), app.sm), + t, os.Stdout, app.BaseApp, AppStateFn(app.Codec(), app.SimulationManager()), SimulationOperations(app, app.Codec(), config), app.ModuleAccountAddrs(), config, ) - // export state and params before the simulation error is checked - if config.ExportStatePath != "" { - err := ExportStateToJSON(app, config.ExportStatePath) - require.NoError(t, err) - } - - if config.ExportParamsPath != "" { - err := ExportParamsToJSON(simParams, config.ExportParamsPath) - require.NoError(t, err) - } - + // export state and simParams before the simulation error is checked + err = CheckExportSimulation(app, config, simParams) + require.NoError(t, err) require.NoError(t, simErr) if config.Commit { - // for memdb: - // fmt.Println("Database Size", db.Stats()["database.size"]) - fmt.Println("\nGoLevelDB Stats") - fmt.Println(db.Stats()["leveldb.stats"]) - fmt.Println("GoLevelDB cached block size", db.Stats()["leveldb.cachedblock"]) + PrintStats(db) } } func TestAppImportExport(t *testing.T) { - if !FlagEnabledValue { + config, db, dir, logger, skip, err := SetupSimulation("leveldb-app-sim", "Simulation") + if skip { t.Skip("skipping application import/export simulation") } - - var logger log.Logger - config := NewConfigFromFlags() - config.ChainID = helpers.SimAppChainID - - if FlagVerboseValue { - logger = log.TestingLogger() - } else { - logger = log.NewNopLogger() - } - - var db dbm.DB - dir, _ := ioutil.TempDir("", "goleveldb-app-sim") - db, _ = sdk.NewLevelDB("Simulation", dir) + require.NoError(t, err, "simulation setup failed") defer func() { db.Close() - os.RemoveAll(dir) + require.NoError(t, os.RemoveAll(dir)) }() app := NewSimApp(logger, db, nil, true, FlagPeriodValue, fauxMerkleModeOpt) @@ -130,64 +99,47 @@ func TestAppImportExport(t *testing.T) { // Run randomized simulation _, simParams, simErr := simulation.SimulateFromSeed( - t, os.Stdout, app.BaseApp, AppStateFn(app.Codec(), app.sm), + t, os.Stdout, app.BaseApp, AppStateFn(app.Codec(), app.SimulationManager()), SimulationOperations(app, app.Codec(), config), app.ModuleAccountAddrs(), config, ) // export state and simParams before the simulation error is checked - if config.ExportStatePath != "" { - err := ExportStateToJSON(app, config.ExportStatePath) - require.NoError(t, err) - } - - if config.ExportParamsPath != "" { - err := ExportParamsToJSON(simParams, config.ExportParamsPath) - require.NoError(t, err) - } - + err = CheckExportSimulation(app, config, simParams) + require.NoError(t, err) require.NoError(t, simErr) if config.Commit { - // for memdb: - // fmt.Println("Database Size", db.Stats()["database.size"]) - fmt.Println("\nGoLevelDB Stats") - fmt.Println(db.Stats()["leveldb.stats"]) - fmt.Println("GoLevelDB cached block size", db.Stats()["leveldb.cachedblock"]) + PrintStats(db) } fmt.Printf("exporting genesis...\n") appState, _, err := app.ExportAppStateAndValidators(false, []string{}) require.NoError(t, err) + fmt.Printf("importing genesis...\n") - newDir, _ := ioutil.TempDir("", "goleveldb-app-sim-2") - newDB, _ := sdk.NewLevelDB("Simulation-2", dir) + _, newDB, newDir, _, _, err := SetupSimulation("leveldb-app-sim-2", "Simulation-2") + require.NoError(t, err, "simulation setup failed") defer func() { newDB.Close() - _ = os.RemoveAll(newDir) + require.NoError(t, os.RemoveAll(newDir)) }() newApp := NewSimApp(log.NewNopLogger(), newDB, nil, true, FlagPeriodValue, fauxMerkleModeOpt) require.Equal(t, "SimApp", newApp.Name()) var genesisState GenesisState - err = app.cdc.UnmarshalJSON(appState, &genesisState) + err = app.Codec().UnmarshalJSON(appState, &genesisState) require.NoError(t, err) + ctxA := app.NewContext(true, abci.Header{Height: app.LastBlockHeight()}) ctxB := newApp.NewContext(true, abci.Header{Height: app.LastBlockHeight()}) newApp.mm.InitGenesis(ctxB, genesisState) fmt.Printf("comparing stores...\n") - ctxA := app.NewContext(true, abci.Header{Height: app.LastBlockHeight()}) - - type StoreKeysPrefixes struct { - A sdk.StoreKey - B sdk.StoreKey - Prefixes [][]byte - } storeKeysPrefixes := []StoreKeysPrefixes{ {app.keys[baseapp.MainStoreKey], newApp.keys[baseapp.MainStoreKey], [][]byte{}}, @@ -204,43 +156,28 @@ func TestAppImportExport(t *testing.T) { {app.keys[gov.StoreKey], newApp.keys[gov.StoreKey], [][]byte{}}, } - for _, storeKeysPrefix := range storeKeysPrefixes { - storeKeyA := storeKeysPrefix.A - storeKeyB := storeKeysPrefix.B - prefixes := storeKeysPrefix.Prefixes - - storeA := ctxA.KVStore(storeKeyA) - storeB := ctxB.KVStore(storeKeyB) + for _, skp := range storeKeysPrefixes { + storeA := ctxA.KVStore(skp.A) + storeB := ctxB.KVStore(skp.B) - failedKVAs, failedKVBs := sdk.DiffKVStores(storeA, storeB, prefixes) + failedKVAs, failedKVBs := sdk.DiffKVStores(storeA, storeB, skp.Prefixes) require.Equal(t, len(failedKVAs), len(failedKVBs), "unequal sets of key-values to compare") - fmt.Printf("compared %d key/value pairs between %s and %s\n", len(failedKVAs), storeKeyA, storeKeyB) - require.Equal(t, len(failedKVAs), 0, GetSimulationLog(storeKeyA.Name(), app.sm.StoreDecoders, app.cdc, failedKVAs, failedKVBs)) + fmt.Printf("compared %d key/value pairs between %s and %s\n", len(failedKVAs), skp.A, skp.B) + require.Equal(t, len(failedKVAs), 0, GetSimulationLog(skp.A.Name(), app.SimulationManager().StoreDecoders, app.Codec(), failedKVAs, failedKVBs)) } } func TestAppSimulationAfterImport(t *testing.T) { - if !FlagEnabledValue { + config, db, dir, logger, skip, err := SetupSimulation("leveldb-app-sim", "Simulation") + if skip { t.Skip("skipping application simulation after import") } - - var logger log.Logger - config := NewConfigFromFlags() - config.ChainID = helpers.SimAppChainID - - if FlagVerboseValue { - logger = log.TestingLogger() - } else { - logger = log.NewNopLogger() - } - - dir, _ := ioutil.TempDir("", "goleveldb-app-sim") - db, _ := sdk.NewLevelDB("Simulation", dir) + require.NoError(t, err, "simulation setup failed") defer func() { db.Close() - os.RemoveAll(dir) + require.NoError(t, os.RemoveAll(dir)) }() app := NewSimApp(logger, db, nil, true, FlagPeriodValue, fauxMerkleModeOpt) @@ -248,35 +185,22 @@ func TestAppSimulationAfterImport(t *testing.T) { // Run randomized simulation stopEarly, simParams, simErr := simulation.SimulateFromSeed( - t, os.Stdout, app.BaseApp, AppStateFn(app.Codec(), app.sm), + t, os.Stdout, app.BaseApp, AppStateFn(app.Codec(), app.SimulationManager()), SimulationOperations(app, app.Codec(), config), app.ModuleAccountAddrs(), config, ) - // export state and params before the simulation error is checked - if config.ExportStatePath != "" { - err := ExportStateToJSON(app, config.ExportStatePath) - require.NoError(t, err) - } - - if config.ExportParamsPath != "" { - err := ExportParamsToJSON(simParams, config.ExportParamsPath) - require.NoError(t, err) - } - + // export state and simParams before the simulation error is checked + err = CheckExportSimulation(app, config, simParams) + require.NoError(t, err) require.NoError(t, simErr) if config.Commit { - // for memdb: - // fmt.Println("Database Size", db.Stats()["database.size"]) - fmt.Println("\nGoLevelDB Stats") - fmt.Println(db.Stats()["leveldb.stats"]) - fmt.Println("GoLevelDB cached block size", db.Stats()["leveldb.cachedblock"]) + PrintStats(db) } if stopEarly { - // we can't export or import a zero-validator genesis - fmt.Printf("we can't export or import a zero-validator genesis, exiting test...\n") + fmt.Println("can't export or import a zero-validator genesis, exiting test...") return } @@ -287,12 +211,12 @@ func TestAppSimulationAfterImport(t *testing.T) { fmt.Printf("importing genesis...\n") - newDir, _ := ioutil.TempDir("", "goleveldb-app-sim-2") - newDB, _ := sdk.NewLevelDB("Simulation-2", dir) + _, newDB, newDir, _, _, err := SetupSimulation("leveldb-app-sim-2", "Simulation-2") + require.NoError(t, err, "simulation setup failed") defer func() { newDB.Close() - _ = os.RemoveAll(newDir) + require.NoError(t, os.RemoveAll(newDir)) }() newApp := NewSimApp(log.NewNopLogger(), newDB, nil, true, FlagPeriodValue, fauxMerkleModeOpt) @@ -302,13 +226,11 @@ func TestAppSimulationAfterImport(t *testing.T) { AppStateBytes: appState, }) - // Run randomized simulation on imported app _, _, err = simulation.SimulateFromSeed( - t, os.Stdout, newApp.BaseApp, AppStateFn(app.Codec(), app.sm), + t, os.Stdout, newApp.BaseApp, AppStateFn(app.Codec(), app.SimulationManager()), SimulationOperations(newApp, newApp.Codec(), config), newApp.ModuleAccountAddrs(), config, ) - require.NoError(t, err) } @@ -351,12 +273,16 @@ func TestAppStateDeterminism(t *testing.T) { ) _, _, err := simulation.SimulateFromSeed( - t, os.Stdout, app.BaseApp, AppStateFn(app.Codec(), app.sm), + t, os.Stdout, app.BaseApp, AppStateFn(app.Codec(), app.SimulationManager()), SimulationOperations(app, app.Codec(), config), app.ModuleAccountAddrs(), config, ) require.NoError(t, err) + if config.Commit { + PrintStats(db) + } + appHash := app.LastCommitID().Hash appHashList[j] = appHash diff --git a/simapp/state.go b/simapp/state.go index 8815784b0a60..942ec784681d 100644 --- a/simapp/state.go +++ b/simapp/state.go @@ -12,6 +12,7 @@ import ( tmtypes "github.com/tendermint/tendermint/types" "github.com/cosmos/cosmos-sdk/codec" + simapparams "github.com/cosmos/cosmos-sdk/simapp/params" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/simulation" @@ -80,11 +81,11 @@ func AppStateRandomizedFn( // number of bonded accounts var initialStake, numInitiallyBonded int64 appParams.GetOrGenerate( - cdc, StakePerAccount, &initialStake, r, + cdc, simapparams.StakePerAccount, &initialStake, r, func(r *rand.Rand) { initialStake = r.Int63n(1e12) }, ) appParams.GetOrGenerate( - cdc, InitiallyBondedValidators, &numInitiallyBonded, r, + cdc, simapparams.InitiallyBondedValidators, &numInitiallyBonded, r, func(r *rand.Rand) { numInitiallyBonded = int64(r.Intn(300)) }, ) diff --git a/simapp/test_helpers.go b/simapp/test_helpers.go index c7874bc0b7c9..306b4259fb2d 100644 --- a/simapp/test_helpers.go +++ b/simapp/test_helpers.go @@ -27,7 +27,7 @@ func Setup(isCheckTx bool) *SimApp { if !isCheckTx { // init chain must be called to stop deliverState from being nil genesisState := NewDefaultGenesisState() - stateBytes, err := codec.MarshalJSONIndent(app.cdc, genesisState) + stateBytes, err := codec.MarshalJSONIndent(app.Codec(), genesisState) if err != nil { panic(err) } @@ -54,10 +54,10 @@ func SetupWithGenesisAccounts(genAccs []authexported.GenesisAccount) *SimApp { genesisState := NewDefaultGenesisState() authGenesis := auth.NewGenesisState(auth.DefaultParams(), genAccs) - genesisStateBz := app.cdc.MustMarshalJSON(authGenesis) + genesisStateBz := app.Codec().MustMarshalJSON(authGenesis) genesisState[auth.ModuleName] = genesisStateBz - stateBytes, err := codec.MarshalJSONIndent(app.cdc, genesisState) + stateBytes, err := codec.MarshalJSONIndent(app.Codec(), genesisState) if err != nil { panic(err) } diff --git a/simapp/types.go b/simapp/types.go new file mode 100644 index 000000000000..a3f146f67ceb --- /dev/null +++ b/simapp/types.go @@ -0,0 +1,46 @@ +package simapp + +import ( + "encoding/json" + + abci "github.com/tendermint/tendermint/abci/types" + tmtypes "github.com/tendermint/tendermint/types" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" +) + +// App implements the common methods for a Cosmos SDK-based application +// specific blockchain. +type App interface { + // The assigned name of the app. + Name() string + + // The application types codec. + // NOTE: This shoult be sealed before being returned. + Codec() *codec.Codec + + // Application updates every begin block. + BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) abci.ResponseBeginBlock + + // Application updates every end block. + EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock + + // Application update at chain (i.e app) initialization. + InitChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain + + // Loads the app at a given height. + LoadHeight(height int64) error + + // Exports the state of the application for a genesis file. + ExportAppStateAndValidators( + forZeroHeight bool, jailWhiteList []string, + ) (json.RawMessage, []tmtypes.GenesisValidator, error) + + // All the registered module account addreses. + ModuleAccountAddrs() map[string]bool + + // Helper for the simulation framework. + SimulationManager() *module.SimulationManager +} diff --git a/simapp/utils.go b/simapp/utils.go index 959988d0b1c0..63a07afc9de4 100644 --- a/simapp/utils.go +++ b/simapp/utils.go @@ -2,92 +2,54 @@ package simapp import ( "encoding/json" - "flag" "fmt" "io/ioutil" cmn "github.com/tendermint/tendermint/libs/common" + "github.com/tendermint/tendermint/libs/log" + dbm "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/simapp/helpers" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/x/simulation" ) -//--------------------------------------------------------------------- -// Flags - -// List of available flags for the simulator -var ( - FlagGenesisFileValue string - FlagParamsFileValue string - FlagExportParamsPathValue string - FlagExportParamsHeightValue int - FlagExportStatePathValue string - FlagExportStatsPathValue string - FlagSeedValue int64 - FlagInitialBlockHeightValue int - FlagNumBlocksValue int - FlagBlockSizeValue int - FlagLeanValue bool - FlagCommitValue bool - FlagOnOperationValue bool // TODO: Remove in favor of binary search for invariant violation - FlagAllInvariantsValue bool - - FlagEnabledValue bool - FlagVerboseValue bool - FlagPeriodValue uint - FlagGenesisTimeValue int64 -) +// SetupSimulation creates the config, db (levelDB), temporary directory and logger for +// the simulation tests. If `FlagEnabledValue` is false it skips the current test. +// Returns error on an invalid db intantiation or temp dir creation. +func SetupSimulation(dirPrefix, dbName string) (simulation.Config, dbm.DB, string, log.Logger, bool, error) { + if !FlagEnabledValue { + return simulation.Config{}, nil, "", nil, true, nil + } -// GetSimulatorFlags gets the values of all the available simulation flags -func GetSimulatorFlags() { - // config fields - flag.StringVar(&FlagGenesisFileValue, "Genesis", "", "custom simulation genesis file; cannot be used with params file") - flag.StringVar(&FlagParamsFileValue, "Params", "", "custom simulation params file which overrides any random params; cannot be used with genesis") - flag.StringVar(&FlagExportParamsPathValue, "ExportParamsPath", "", "custom file path to save the exported params JSON") - flag.IntVar(&FlagExportParamsHeightValue, "ExportParamsHeight", 0, "height to which export the randomly generated params") - flag.StringVar(&FlagExportStatePathValue, "ExportStatePath", "", "custom file path to save the exported app state JSON") - flag.StringVar(&FlagExportStatsPathValue, "ExportStatsPath", "", "custom file path to save the exported simulation statistics JSON") - flag.Int64Var(&FlagSeedValue, "Seed", 42, "simulation random seed") - flag.IntVar(&FlagInitialBlockHeightValue, "InitialBlockHeight", 1, "initial block to start the simulation") - flag.IntVar(&FlagNumBlocksValue, "NumBlocks", 500, "number of new blocks to simulate from the initial block height") - flag.IntVar(&FlagBlockSizeValue, "BlockSize", 200, "operations per block") - flag.BoolVar(&FlagLeanValue, "Lean", false, "lean simulation log output") - flag.BoolVar(&FlagCommitValue, "Commit", false, "have the simulation commit") - flag.BoolVar(&FlagOnOperationValue, "SimulateEveryOperation", false, "run slow invariants every operation") - flag.BoolVar(&FlagAllInvariantsValue, "PrintAllInvariants", false, "print all invariants if a broken invariant is found") - - // simulation flags - flag.BoolVar(&FlagEnabledValue, "Enabled", false, "enable the simulation") - flag.BoolVar(&FlagVerboseValue, "Verbose", false, "verbose log output") - flag.UintVar(&FlagPeriodValue, "Period", 0, "run slow invariants only once every period assertions") - flag.Int64Var(&FlagGenesisTimeValue, "GenesisTime", 0, "override genesis UNIX time instead of using a random UNIX time") -} + config := NewConfigFromFlags() + config.ChainID = helpers.SimAppChainID + + var logger log.Logger + if FlagVerboseValue { + logger = log.TestingLogger() + } else { + logger = log.NewNopLogger() + } -// NewConfigFromFlags creates a simulation from the retrieved values of the flags. -func NewConfigFromFlags() simulation.Config { - return simulation.Config{ - GenesisFile: FlagGenesisFileValue, - ParamsFile: FlagParamsFileValue, - ExportParamsPath: FlagExportParamsPathValue, - ExportParamsHeight: FlagExportParamsHeightValue, - ExportStatePath: FlagExportStatePathValue, - ExportStatsPath: FlagExportStatsPathValue, - Seed: FlagSeedValue, - InitialBlockHeight: FlagInitialBlockHeightValue, - NumBlocks: FlagNumBlocksValue, - BlockSize: FlagBlockSizeValue, - Lean: FlagLeanValue, - Commit: FlagCommitValue, - OnOperation: FlagOnOperationValue, - AllInvariants: FlagAllInvariantsValue, + dir, err := ioutil.TempDir("", dirPrefix) + if err != nil { + return simulation.Config{}, nil, "", nil, false, err } + + db, err := sdk.NewLevelDB(dbName, dir) + if err != nil { + return simulation.Config{}, nil, "", nil, false, err + } + + return config, db, dir, logger, false, nil } // SimulationOperations retrieves the simulation params from the provided file path // and returns all the modules weighted operations -func SimulationOperations(app *SimApp, cdc *codec.Codec, config simulation.Config) []simulation.WeightedOperation { +func SimulationOperations(app App, cdc *codec.Codec, config simulation.Config) []simulation.WeightedOperation { simState := module.SimulationState{ AppParams: make(simulation.AppParams), Cdc: cdc, @@ -99,37 +61,50 @@ func SimulationOperations(app *SimApp, cdc *codec.Codec, config simulation.Confi panic(err) } - app.cdc.MustUnmarshalJSON(bz, &simState.AppParams) + app.Codec().MustUnmarshalJSON(bz, &simState.AppParams) } - simState.ParamChanges = app.sm.GenerateParamChanges(config.Seed) - simState.Contents = app.sm.GetProposalContents(simState) - return app.sm.WeightedOperations(simState) + simState.ParamChanges = app.SimulationManager().GenerateParamChanges(config.Seed) + simState.Contents = app.SimulationManager().GetProposalContents(simState) + return app.SimulationManager().WeightedOperations(simState) } -//--------------------------------------------------------------------- -// Simulation Utils +// CheckExportSimulation exports the app state and simulation parameters to JSON +// if the export paths are defined. +func CheckExportSimulation( + app App, config simulation.Config, params simulation.Params, +) error { + if config.ExportStatePath != "" { + fmt.Println("exporting app state...") + appState, _, err := app.ExportAppStateAndValidators(false, nil) + if err != nil { + return err + } -// ExportStateToJSON util function to export the app state to JSON -func ExportStateToJSON(app *SimApp, path string) error { - fmt.Println("exporting app state...") - appState, _, err := app.ExportAppStateAndValidators(false, nil) - if err != nil { - return err + if err := ioutil.WriteFile(config.ExportStatePath, []byte(appState), 0644); err != nil { + return err + } } - return ioutil.WriteFile(path, []byte(appState), 0644) -} + if config.ExportParamsPath != "" { + fmt.Println("exporting simulation params...") + paramsBz, err := json.MarshalIndent(params, "", " ") + if err != nil { + return err + } -// ExportParamsToJSON util function to export the simulation parameters to JSON -func ExportParamsToJSON(params simulation.Params, path string) error { - fmt.Println("exporting simulation params...") - paramsBz, err := json.MarshalIndent(params, "", " ") - if err != nil { - return err + if err := ioutil.WriteFile(config.ExportParamsPath, paramsBz, 0644); err != nil { + return err + } } + return nil +} - return ioutil.WriteFile(path, paramsBz, 0644) +// PrintStats prints the corresponding statistics from the app DB. +func PrintStats(db dbm.DB) { + fmt.Println("\nLevelDB Stats") + fmt.Println(db.Stats()["leveldb.stats"]) + fmt.Println("LevelDB cached block size", db.Stats()["leveldb.cachedblock"]) } // GetSimulationLog unmarshals the KVPair's Value to the corresponding type based on the From 908fd2ba78504e3a72b99653ae8e8ef7e40486c8 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Tue, 17 Dec 2019 13:59:16 -0500 Subject: [PATCH 041/529] Merge PR #5417: Update distribution module doc --- x/distribution/alias.go | 8 ++------ x/distribution/doc.go | 6 ++++++ 2 files changed, 8 insertions(+), 6 deletions(-) create mode 100644 x/distribution/doc.go diff --git a/x/distribution/alias.go b/x/distribution/alias.go index d55d88dd3eed..de6f269e6a1c 100644 --- a/x/distribution/alias.go +++ b/x/distribution/alias.go @@ -1,9 +1,3 @@ -// nolint -// autogenerated code using github.com/rigelrozanski/multitool -// aliases generated for the following subdirectories: -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/distribution/keeper -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/distribution/types -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/distribution/client package distribution import ( @@ -12,6 +6,8 @@ import ( "github.com/cosmos/cosmos-sdk/x/distribution/types" ) +// nolint + const ( DefaultParamspace = keeper.DefaultParamspace DefaultCodespace = types.DefaultCodespace diff --git a/x/distribution/doc.go b/x/distribution/doc.go new file mode 100644 index 000000000000..8b9966c05903 --- /dev/null +++ b/x/distribution/doc.go @@ -0,0 +1,6 @@ +/* +Package distribution implements a Cosmos SDK module, that provides an implementation +of the F1 fee distribution algorithm. It handles reward tracking, allocation, and +distribution. Please refer to the specification under /spec for further information. +*/ +package distribution From fca4cbef88284af662d79bb47aa34131b28b5485 Mon Sep 17 00:00:00 2001 From: Aditya Date: Wed, 18 Dec 2019 05:20:02 -0800 Subject: [PATCH 042/529] Merge PR #5380: ADR 17 Implementation: Historical Module --- CHANGELOG.md | 3 + x/staking/abci.go | 18 ++ x/staking/alias.go | 13 ++ x/staking/client/cli/query.go | 46 +++++ x/staking/client/rest/query.go | 37 ++++ x/staking/handler.go | 56 ------ x/staking/keeper/historical_info.go | 71 +++++++ x/staking/keeper/historical_info_test.go | 106 ++++++++++ x/staking/keeper/params.go | 8 + x/staking/keeper/querier.go | 23 +++ x/staking/keeper/querier_test.go | 189 ++++++++++++------ x/staking/keeper/val_state_change.go | 56 ++++++ x/staking/module.go | 4 +- x/staking/simulation/genesis.go | 2 +- x/staking/spec/01_state.md | 18 ++ x/staking/spec/04_begin_block.md | 16 ++ .../spec/{04_end_block.md => 05_end_block.md} | 2 +- x/staking/spec/{05_hooks.md => 06_hooks.md} | 2 +- x/staking/spec/{06_events.md => 07_events.md} | 2 +- x/staking/spec/07_params.md | 14 -- x/staking/spec/08_params.md | 15 ++ x/staking/spec/README.md | 19 +- x/staking/types/errors.go | 25 ++- x/staking/types/historical_info.go | 57 ++++++ x/staking/types/historical_info_test.go | 67 +++++++ x/staking/types/keys.go | 10 + x/staking/types/params.go | 56 ++++-- x/staking/types/querier.go | 12 ++ x/staking/types/validator.go | 23 +++ x/staking/types/validator_test.go | 32 +++ 30 files changed, 827 insertions(+), 175 deletions(-) create mode 100644 x/staking/abci.go create mode 100644 x/staking/keeper/historical_info.go create mode 100644 x/staking/keeper/historical_info_test.go create mode 100644 x/staking/spec/04_begin_block.md rename x/staking/spec/{04_end_block.md => 05_end_block.md} (99%) rename x/staking/spec/{05_hooks.md => 06_hooks.md} (99%) rename x/staking/spec/{06_events.md => 07_events.md} (99%) delete mode 100644 x/staking/spec/07_params.md create mode 100644 x/staking/spec/08_params.md create mode 100644 x/staking/types/historical_info.go create mode 100644 x/staking/types/historical_info_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 591b6e4c65d0..7516d35b4157 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -147,6 +147,9 @@ that allows for arbitrary vesting periods. * `ValidateSigCountDecorator`: Validate the number of signatures in tx based on app-parameters. * `IncrementSequenceDecorator`: Increments the account sequence for each signer to prevent replay attacks. * (cli) [\#5223](https://github.com/cosmos/cosmos-sdk/issues/5223) Cosmos Ledger App v2.0.0 is now supported. The changes are backwards compatible and App v1.5.x is still supported. +* (x/staking) [\#5380](https://github.com/cosmos/cosmos-sdk/pull/5380) Introduced ability to store historical info entries in staking keeper, allows applications to introspect specified number of past headers and validator sets + * Introduces new parameter `HistoricalEntries` which allows applications to determine how many recent historical info entries they want to persist in store. Default value is 0. + * Introduces cli commands and rest routes to query historical information at a given height * (modules) [\#5249](https://github.com/cosmos/cosmos-sdk/pull/5249) Funds are now allowed to be directly sent to the community pool (via the distribution module account). * (keys) [\#4941](https://github.com/cosmos/cosmos-sdk/issues/4941) Introduce keybase option to allow overriding the default private key implementation of a key generated through the `keys add` cli command. diff --git a/x/staking/abci.go b/x/staking/abci.go new file mode 100644 index 000000000000..39755c24440c --- /dev/null +++ b/x/staking/abci.go @@ -0,0 +1,18 @@ +package staking + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/staking/keeper" + abci "github.com/tendermint/tendermint/abci/types" +) + +// BeginBlocker will persist the current header and validator set as a historical entry +// and prune the oldest entry based on the HistoricalEntries parameter +func BeginBlocker(ctx sdk.Context, k keeper.Keeper) { + k.TrackHistoricalInfo(ctx) +} + +// Called every block, update validator set +func EndBlocker(ctx sdk.Context, k keeper.Keeper) []abci.ValidatorUpdate { + return k.BlockValidatorUpdates(ctx) +} diff --git a/x/staking/alias.go b/x/staking/alias.go index 019fa0298532..887b9b7bf690 100644 --- a/x/staking/alias.go +++ b/x/staking/alias.go @@ -19,6 +19,7 @@ const ( CodeInvalidDelegation = types.CodeInvalidDelegation CodeInvalidInput = types.CodeInvalidInput CodeValidatorJailed = types.CodeValidatorJailed + CodeInvalidHistoricalInfo = types.CodeInvalidHistoricalInfo CodeInvalidAddress = types.CodeInvalidAddress CodeUnauthorized = types.CodeUnauthorized CodeInternal = types.CodeInternal @@ -47,6 +48,7 @@ const ( QueryDelegatorValidator = types.QueryDelegatorValidator QueryPool = types.QueryPool QueryParameters = types.QueryParameters + QueryHistoricalInfo = types.QueryHistoricalInfo MaxMonikerLength = types.MaxMonikerLength MaxIdentityLength = types.MaxIdentityLength MaxWebsiteLength = types.MaxWebsiteLength @@ -86,6 +88,10 @@ var ( NewDelegationResp = types.NewDelegationResp NewRedelegationResponse = types.NewRedelegationResponse NewRedelegationEntryResponse = types.NewRedelegationEntryResponse + NewHistoricalInfo = types.NewHistoricalInfo + MustMarshalHistoricalInfo = types.MustMarshalHistoricalInfo + MustUnmarshalHistoricalInfo = types.MustUnmarshalHistoricalInfo + UnmarshalHistoricalInfo = types.UnmarshalHistoricalInfo ErrNilValidatorAddr = types.ErrNilValidatorAddr ErrBadValidatorAddr = types.ErrBadValidatorAddr ErrNoValidatorFound = types.ErrNoValidatorFound @@ -131,6 +137,8 @@ var ( ErrBothShareMsgsGiven = types.ErrBothShareMsgsGiven ErrNeitherShareMsgsGiven = types.ErrNeitherShareMsgsGiven ErrMissingSignature = types.ErrMissingSignature + ErrInvalidHistoricalInfo = types.ErrInvalidHistoricalInfo + ErrNoHistoricalInfo = types.ErrNoHistoricalInfo NewGenesisState = types.NewGenesisState DefaultGenesisState = types.DefaultGenesisState NewMultiStakingHooks = types.NewMultiStakingHooks @@ -159,6 +167,7 @@ var ( GetREDsFromValSrcIndexKey = types.GetREDsFromValSrcIndexKey GetREDsToValDstIndexKey = types.GetREDsToValDstIndexKey GetREDsByDelToValDstIndexKey = types.GetREDsByDelToValDstIndexKey + GetHistoricalInfoKey = types.GetHistoricalInfoKey NewMsgCreateValidator = types.NewMsgCreateValidator NewMsgEditValidator = types.NewMsgEditValidator NewMsgDelegate = types.NewMsgDelegate @@ -174,6 +183,7 @@ var ( NewQueryBondsParams = types.NewQueryBondsParams NewQueryRedelegationParams = types.NewQueryRedelegationParams NewQueryValidatorsParams = types.NewQueryValidatorsParams + NewQueryHistoricalInfoParams = types.NewQueryHistoricalInfoParams NewValidator = types.NewValidator MustMarshalValidator = types.MustMarshalValidator MustUnmarshalValidator = types.MustUnmarshalValidator @@ -196,6 +206,7 @@ var ( UnbondingQueueKey = types.UnbondingQueueKey RedelegationQueueKey = types.RedelegationQueueKey ValidatorQueueKey = types.ValidatorQueueKey + HistoricalInfoKey = types.HistoricalInfoKey KeyUnbondingTime = types.KeyUnbondingTime KeyMaxValidators = types.KeyMaxValidators KeyMaxEntries = types.KeyMaxEntries @@ -216,6 +227,7 @@ type ( Redelegation = types.Redelegation RedelegationEntry = types.RedelegationEntry Redelegations = types.Redelegations + HistoricalInfo = types.HistoricalInfo DelegationResponse = types.DelegationResponse DelegationResponses = types.DelegationResponses RedelegationResponse = types.RedelegationResponse @@ -237,6 +249,7 @@ type ( QueryBondsParams = types.QueryBondsParams QueryRedelegationParams = types.QueryRedelegationParams QueryValidatorsParams = types.QueryValidatorsParams + QueryHistoricalInfoParams = types.QueryHistoricalInfoParams Validator = types.Validator Validators = types.Validators Description = types.Description diff --git a/x/staking/client/cli/query.go b/x/staking/client/cli/query.go index ce7ca6e55be7..632237c1d915 100644 --- a/x/staking/client/cli/query.go +++ b/x/staking/client/cli/query.go @@ -2,6 +2,7 @@ package cli import ( "fmt" + "strconv" "strings" "github.com/spf13/cobra" @@ -35,6 +36,7 @@ func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { GetCmdQueryValidatorDelegations(queryRoute, cdc), GetCmdQueryValidatorUnbondingDelegations(queryRoute, cdc), GetCmdQueryValidatorRedelegations(queryRoute, cdc), + GetCmdQueryHistoricalInfo(queryRoute, cdc), GetCmdQueryParams(queryRoute, cdc), GetCmdQueryPool(queryRoute, cdc))...) @@ -527,6 +529,50 @@ $ %s query staking redelegation cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p } } +// GetCmdQueryHistoricalInfo implements the historical info query command +func GetCmdQueryHistoricalInfo(queryRoute string, cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "historical-info [height]", + Args: cobra.ExactArgs(1), + Short: "Query historical info at given height", + Long: strings.TrimSpace( + fmt.Sprintf(`Query historical info at given height. + +Example: +$ %s query staking historical-info 5 +`, + version.ClientName, + ), + ), + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + + height, err := strconv.ParseInt(args[0], 10, 64) + if err != nil || height < 0 { + return fmt.Errorf("height argument provided must be a non-negative-integer: %v", err) + } + + bz, err := cdc.MarshalJSON(types.QueryHistoricalInfoParams{Height: height}) + if err != nil { + return err + } + + route := fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryHistoricalInfo) + res, _, err := cliCtx.QueryWithData(route, bz) + if err != nil { + return err + } + + var resp types.HistoricalInfo + if err := cdc.UnmarshalJSON(res, &resp); err != nil { + return err + } + + return cliCtx.PrintOutput(resp) + }, + } +} + // GetCmdQueryPool implements the pool query command. func GetCmdQueryPool(storeName string, cdc *codec.Codec) *cobra.Command { return &cobra.Command{ diff --git a/x/staking/client/rest/query.go b/x/staking/client/rest/query.go index e0eabd870e93..ddd6c03c7c6b 100644 --- a/x/staking/client/rest/query.go +++ b/x/staking/client/rest/query.go @@ -3,6 +3,7 @@ package rest import ( "fmt" "net/http" + "strconv" "strings" "github.com/gorilla/mux" @@ -86,6 +87,12 @@ func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router) { validatorUnbondingDelegationsHandlerFn(cliCtx), ).Methods("GET") + // Get HistoricalInfo at a given height + r.HandleFunc( + "/staking/historical_info/{height}", + historicalInfoHandlerFn(cliCtx), + ).Methods("GET") + // Get the current state of the staking pool r.HandleFunc( "/staking/pool", @@ -313,6 +320,36 @@ func validatorUnbondingDelegationsHandlerFn(cliCtx context.CLIContext) http.Hand return queryValidator(cliCtx, "custom/staking/validatorUnbondingDelegations") } +// HTTP request handler to query historical info at a given height +func historicalInfoHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + heightStr := vars["height"] + height, err := strconv.ParseInt(heightStr, 10, 64) + if err != nil || height < 0 { + rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("Must provide non-negative integer for height: %v", err)) + return + } + + params := types.NewQueryHistoricalInfoParams(height) + bz, err := cliCtx.Codec.MarshalJSON(params) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + + route := fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryHistoricalInfo) + res, height, err := cliCtx.QueryWithData(route, bz) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + cliCtx = cliCtx.WithHeight(height) + rest.PostProcessResponse(w, cliCtx, res) + } +} + // HTTP request handler to query the pool information func poolHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { diff --git a/x/staking/handler.go b/x/staking/handler.go index 1d7ba1e84762..376da255ea1c 100644 --- a/x/staking/handler.go +++ b/x/staking/handler.go @@ -4,7 +4,6 @@ import ( "fmt" "time" - abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/common" tmtypes "github.com/tendermint/tendermint/types" @@ -40,61 +39,6 @@ func NewHandler(k keeper.Keeper) sdk.Handler { } } -// Called every block, update validator set -func EndBlocker(ctx sdk.Context, k keeper.Keeper) []abci.ValidatorUpdate { - // Calculate validator set changes. - // - // NOTE: ApplyAndReturnValidatorSetUpdates has to come before - // UnbondAllMatureValidatorQueue. - // This fixes a bug when the unbonding period is instant (is the case in - // some of the tests). The test expected the validator to be completely - // unbonded after the Endblocker (go from Bonded -> Unbonding during - // ApplyAndReturnValidatorSetUpdates and then Unbonding -> Unbonded during - // UnbondAllMatureValidatorQueue). - validatorUpdates := k.ApplyAndReturnValidatorSetUpdates(ctx) - - // Unbond all mature validators from the unbonding queue. - k.UnbondAllMatureValidatorQueue(ctx) - - // Remove all mature unbonding delegations from the ubd queue. - matureUnbonds := k.DequeueAllMatureUBDQueue(ctx, ctx.BlockHeader().Time) - for _, dvPair := range matureUnbonds { - err := k.CompleteUnbonding(ctx, dvPair.DelegatorAddress, dvPair.ValidatorAddress) - if err != nil { - continue - } - - ctx.EventManager().EmitEvent( - sdk.NewEvent( - types.EventTypeCompleteUnbonding, - sdk.NewAttribute(types.AttributeKeyValidator, dvPair.ValidatorAddress.String()), - sdk.NewAttribute(types.AttributeKeyDelegator, dvPair.DelegatorAddress.String()), - ), - ) - } - - // Remove all mature redelegations from the red queue. - matureRedelegations := k.DequeueAllMatureRedelegationQueue(ctx, ctx.BlockHeader().Time) - for _, dvvTriplet := range matureRedelegations { - err := k.CompleteRedelegation(ctx, dvvTriplet.DelegatorAddress, - dvvTriplet.ValidatorSrcAddress, dvvTriplet.ValidatorDstAddress) - if err != nil { - continue - } - - ctx.EventManager().EmitEvent( - sdk.NewEvent( - types.EventTypeCompleteRedelegation, - sdk.NewAttribute(types.AttributeKeyDelegator, dvvTriplet.DelegatorAddress.String()), - sdk.NewAttribute(types.AttributeKeySrcValidator, dvvTriplet.ValidatorSrcAddress.String()), - sdk.NewAttribute(types.AttributeKeyDstValidator, dvvTriplet.ValidatorDstAddress.String()), - ), - ) - } - - return validatorUpdates -} - // These functions assume everything has been authenticated, // now we just perform action and save diff --git a/x/staking/keeper/historical_info.go b/x/staking/keeper/historical_info.go new file mode 100644 index 000000000000..2ce0aee7dbcc --- /dev/null +++ b/x/staking/keeper/historical_info.go @@ -0,0 +1,71 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/staking/types" +) + +// GetHistoricalInfo gets the historical info at a given height +func (k Keeper) GetHistoricalInfo(ctx sdk.Context, height int64) (types.HistoricalInfo, bool) { + store := ctx.KVStore(k.storeKey) + key := types.GetHistoricalInfoKey(height) + + value := store.Get(key) + if value == nil { + return types.HistoricalInfo{}, false + } + + hi := types.MustUnmarshalHistoricalInfo(k.cdc, value) + return hi, true +} + +// SetHistoricalInfo sets the historical info at a given height +func (k Keeper) SetHistoricalInfo(ctx sdk.Context, height int64, hi types.HistoricalInfo) { + store := ctx.KVStore(k.storeKey) + key := types.GetHistoricalInfoKey(height) + + value := types.MustMarshalHistoricalInfo(k.cdc, hi) + store.Set(key, value) +} + +// DeleteHistoricalInfo deletes the historical info at a given height +func (k Keeper) DeleteHistoricalInfo(ctx sdk.Context, height int64) { + store := ctx.KVStore(k.storeKey) + key := types.GetHistoricalInfoKey(height) + + store.Delete(key) +} + +// TrackHistoricalInfo saves the latest historical-info and deletes the oldest +// heights that are below pruning height +func (k Keeper) TrackHistoricalInfo(ctx sdk.Context) { + entryNum := k.HistoricalEntries(ctx) + + // Prune store to ensure we only have parameter-defined historical entries. + // In most cases, this will involve removing a single historical entry. + // In the rare scenario when the historical entries gets reduced to a lower value k' + // from the original value k. k - k' entries must be deleted from the store. + // Since the entries to be deleted are always in a continuous range, we can iterate + // over the historical entries starting from the most recent version to be pruned + // and then return at the first empty entry. + for i := ctx.BlockHeight() - int64(entryNum); i >= 0; i-- { + _, found := k.GetHistoricalInfo(ctx, i) + if found { + k.DeleteHistoricalInfo(ctx, i) + } else { + break + } + } + + // if there is no need to persist historicalInfo, return + if entryNum == 0 { + return + } + + // Create HistoricalInfo struct + lastVals := k.GetLastValidators(ctx) + historicalEntry := types.NewHistoricalInfo(ctx.BlockHeader(), lastVals) + + // Set latest HistoricalInfo at current height + k.SetHistoricalInfo(ctx, ctx.BlockHeight(), historicalEntry) +} diff --git a/x/staking/keeper/historical_info_test.go b/x/staking/keeper/historical_info_test.go new file mode 100644 index 000000000000..fa1fa2356cd9 --- /dev/null +++ b/x/staking/keeper/historical_info_test.go @@ -0,0 +1,106 @@ +package keeper + +import ( + "sort" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/staking/types" + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/stretchr/testify/require" +) + +func TestHistoricalInfo(t *testing.T) { + ctx, _, keeper, _ := CreateTestInput(t, false, 10) + validators := make([]types.Validator, len(addrVals)) + + for i, valAddr := range addrVals { + validators[i] = types.NewValidator(valAddr, PKs[i], types.Description{}) + } + + hi := types.NewHistoricalInfo(ctx.BlockHeader(), validators) + + keeper.SetHistoricalInfo(ctx, 2, hi) + + recv, found := keeper.GetHistoricalInfo(ctx, 2) + require.True(t, found, "HistoricalInfo not found after set") + require.Equal(t, hi, recv, "HistoricalInfo not equal") + require.True(t, sort.IsSorted(types.Validators(recv.ValSet)), "HistoricalInfo validators is not sorted") + + keeper.DeleteHistoricalInfo(ctx, 2) + + recv, found = keeper.GetHistoricalInfo(ctx, 2) + require.False(t, found, "HistoricalInfo found after delete") + require.Equal(t, types.HistoricalInfo{}, recv, "HistoricalInfo is not empty") +} + +func TestTrackHistoricalInfo(t *testing.T) { + ctx, _, k, _ := CreateTestInput(t, false, 10) + + // set historical entries in params to 5 + params := types.DefaultParams() + params.HistoricalEntries = 5 + k.SetParams(ctx, params) + + // set historical info at 5, 4 which should be pruned + // and check that it has been stored + h4 := abci.Header{ + ChainID: "HelloChain", + Height: 4, + } + h5 := abci.Header{ + ChainID: "HelloChain", + Height: 5, + } + valSet := []types.Validator{ + types.NewValidator(sdk.ValAddress(Addrs[0]), PKs[0], types.Description{}), + types.NewValidator(sdk.ValAddress(Addrs[1]), PKs[1], types.Description{}), + } + hi4 := types.NewHistoricalInfo(h4, valSet) + hi5 := types.NewHistoricalInfo(h5, valSet) + k.SetHistoricalInfo(ctx, 4, hi4) + k.SetHistoricalInfo(ctx, 5, hi5) + recv, found := k.GetHistoricalInfo(ctx, 4) + require.True(t, found) + require.Equal(t, hi4, recv) + recv, found = k.GetHistoricalInfo(ctx, 5) + require.True(t, found) + require.Equal(t, hi5, recv) + + // Set last validators in keeper + val1 := types.NewValidator(sdk.ValAddress(Addrs[2]), PKs[2], types.Description{}) + k.SetValidator(ctx, val1) + k.SetLastValidatorPower(ctx, val1.OperatorAddress, 10) + val2 := types.NewValidator(sdk.ValAddress(Addrs[3]), PKs[3], types.Description{}) + vals := []types.Validator{val1, val2} + sort.Sort(types.Validators(vals)) + k.SetValidator(ctx, val2) + k.SetLastValidatorPower(ctx, val2.OperatorAddress, 8) + + // Set Header for BeginBlock context + header := abci.Header{ + ChainID: "HelloChain", + Height: 10, + } + ctx = ctx.WithBlockHeader(header) + + k.TrackHistoricalInfo(ctx) + + // Check HistoricalInfo at height 10 is persisted + expected := types.HistoricalInfo{ + Header: header, + ValSet: vals, + } + recv, found = k.GetHistoricalInfo(ctx, 10) + require.True(t, found, "GetHistoricalInfo failed after BeginBlock") + require.Equal(t, expected, recv, "GetHistoricalInfo returned eunexpected result") + + // Check HistoricalInfo at height 5, 4 is pruned + recv, found = k.GetHistoricalInfo(ctx, 4) + require.False(t, found, "GetHistoricalInfo did not prune earlier height") + require.Equal(t, types.HistoricalInfo{}, recv, "GetHistoricalInfo at height 4 is not empty after prune") + recv, found = k.GetHistoricalInfo(ctx, 5) + require.False(t, found, "GetHistoricalInfo did not prune first prune height") + require.Equal(t, types.HistoricalInfo{}, recv, "GetHistoricalInfo at height 5 is not empty after prune") +} diff --git a/x/staking/keeper/params.go b/x/staking/keeper/params.go index dede56b2c19d..11f4b57bc55b 100644 --- a/x/staking/keeper/params.go +++ b/x/staking/keeper/params.go @@ -37,6 +37,13 @@ func (k Keeper) MaxEntries(ctx sdk.Context) (res uint16) { return } +// HistoricalEntries = number of historical info entries +// to persist in store +func (k Keeper) HistoricalEntries(ctx sdk.Context) (res uint16) { + k.paramstore.Get(ctx, types.KeyHistoricalEntries, &res) + return +} + // BondDenom - Bondable coin denomination func (k Keeper) BondDenom(ctx sdk.Context) (res string) { k.paramstore.Get(ctx, types.KeyBondDenom, &res) @@ -49,6 +56,7 @@ func (k Keeper) GetParams(ctx sdk.Context) types.Params { k.UnbondingTime(ctx), k.MaxValidators(ctx), k.MaxEntries(ctx), + k.HistoricalEntries(ctx), k.BondDenom(ctx), ) } diff --git a/x/staking/keeper/querier.go b/x/staking/keeper/querier.go index d97bb07b10ef..15bc59ee5ff6 100644 --- a/x/staking/keeper/querier.go +++ b/x/staking/keeper/querier.go @@ -38,6 +38,8 @@ func NewQuerier(k Keeper) sdk.Querier { return queryDelegatorValidators(ctx, req, k) case types.QueryDelegatorValidator: return queryDelegatorValidator(ctx, req, k) + case types.QueryHistoricalInfo: + return queryHistoricalInfo(ctx, req, k) case types.QueryPool: return queryPool(ctx, k) case types.QueryParameters: @@ -327,6 +329,27 @@ func queryRedelegations(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byt return res, nil } +func queryHistoricalInfo(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { + var params types.QueryHistoricalInfoParams + + err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) + if err != nil { + return nil, sdk.ErrUnknownRequest(string(req.Data)) + } + + hi, found := k.GetHistoricalInfo(ctx, params.Height) + if !found { + return nil, types.ErrNoHistoricalInfo(types.DefaultCodespace) + } + + res, err := codec.MarshalJSONIndent(types.ModuleCdc, hi) + if err != nil { + return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + } + + return res, nil +} + func queryPool(ctx sdk.Context, k Keeper) ([]byte, sdk.Error) { bondDenom := k.BondDenom(ctx) bondedPool := k.GetBondedPool(ctx) diff --git a/x/staking/keeper/querier_test.go b/x/staking/keeper/querier_test.go index 2dac9b6f99ab..320266ca1a28 100644 --- a/x/staking/keeper/querier_test.go +++ b/x/staking/keeper/querier_test.go @@ -31,6 +31,13 @@ func TestNewQuerier(t *testing.T) { keeper.SetValidatorByPowerIndex(ctx, validators[i]) } + header := abci.Header{ + ChainID: "HelloChain", + Height: 5, + } + hi := types.NewHistoricalInfo(header, validators[:]) + keeper.SetHistoricalInfo(ctx, 5, hi) + query := abci.RequestQuery{ Path: "", Data: []byte{}, @@ -39,53 +46,63 @@ func TestNewQuerier(t *testing.T) { querier := NewQuerier(keeper) bz, err := querier(ctx, []string{"other"}, query) - require.NotNil(t, err) + require.Error(t, err) require.Nil(t, bz) _, err = querier(ctx, []string{"pool"}, query) - require.Nil(t, err) + require.NoError(t, err) _, err = querier(ctx, []string{"parameters"}, query) - require.Nil(t, err) + require.NoError(t, err) queryValParams := types.NewQueryValidatorParams(addrVal1) bz, errRes := cdc.MarshalJSON(queryValParams) - require.Nil(t, errRes) + require.NoError(t, errRes) query.Path = "/custom/staking/validator" query.Data = bz _, err = querier(ctx, []string{"validator"}, query) - require.Nil(t, err) + require.NoError(t, err) _, err = querier(ctx, []string{"validatorDelegations"}, query) - require.Nil(t, err) + require.NoError(t, err) _, err = querier(ctx, []string{"validatorUnbondingDelegations"}, query) - require.Nil(t, err) + require.NoError(t, err) queryDelParams := types.NewQueryDelegatorParams(addrAcc2) bz, errRes = cdc.MarshalJSON(queryDelParams) - require.Nil(t, errRes) + require.NoError(t, errRes) query.Path = "/custom/staking/validator" query.Data = bz _, err = querier(ctx, []string{"delegatorDelegations"}, query) - require.Nil(t, err) + require.NoError(t, err) _, err = querier(ctx, []string{"delegatorUnbondingDelegations"}, query) - require.Nil(t, err) + require.NoError(t, err) _, err = querier(ctx, []string{"delegatorValidators"}, query) - require.Nil(t, err) + require.NoError(t, err) bz, errRes = cdc.MarshalJSON(types.NewQueryRedelegationParams(nil, nil, nil)) - require.Nil(t, errRes) + require.NoError(t, errRes) query.Data = bz _, err = querier(ctx, []string{"redelegations"}, query) - require.Nil(t, err) + require.NoError(t, err) + + queryHisParams := types.NewQueryHistoricalInfoParams(5) + bz, errRes = cdc.MarshalJSON(queryHisParams) + require.NoError(t, errRes) + + query.Path = "/custom/staking/historicalInfo" + query.Data = bz + + _, err = querier(ctx, []string{"historicalInfo"}, query) + require.NoError(t, err) } func TestQueryParametersPool(t *testing.T) { @@ -94,21 +111,21 @@ func TestQueryParametersPool(t *testing.T) { bondDenom := sdk.DefaultBondDenom res, err := queryParameters(ctx, keeper) - require.Nil(t, err) + require.NoError(t, err) var params types.Params errRes := cdc.UnmarshalJSON(res, ¶ms) - require.Nil(t, errRes) + require.NoError(t, errRes) require.Equal(t, keeper.GetParams(ctx), params) res, err = queryPool(ctx, keeper) - require.Nil(t, err) + require.NoError(t, err) var pool types.Pool bondedPool := keeper.GetBondedPool(ctx) notBondedPool := keeper.GetNotBondedPool(ctx) errRes = cdc.UnmarshalJSON(res, &pool) - require.Nil(t, errRes) + require.NoError(t, errRes) require.Equal(t, bondedPool.GetCoins().AmountOf(bondDenom), pool.BondedTokens) require.Equal(t, notBondedPool.GetCoins().AmountOf(bondDenom), pool.NotBondedTokens) } @@ -138,7 +155,7 @@ func TestQueryValidators(t *testing.T) { for i, s := range status { queryValsParams := types.NewQueryValidatorsParams(1, int(params.MaxValidators), s.String()) bz, err := cdc.MarshalJSON(queryValsParams) - require.Nil(t, err) + require.NoError(t, err) req := abci.RequestQuery{ Path: fmt.Sprintf("/custom/%s/%s", types.QuerierRoute, types.QueryValidators), @@ -146,11 +163,11 @@ func TestQueryValidators(t *testing.T) { } res, err := queryValidators(ctx, req, keeper) - require.Nil(t, err) + require.NoError(t, err) var validatorsResp []types.Validator err = cdc.UnmarshalJSON(res, &validatorsResp) - require.Nil(t, err) + require.NoError(t, err) require.Equal(t, 1, len(validatorsResp)) require.ElementsMatch(t, validators[i].OperatorAddress, validatorsResp[0].OperatorAddress) @@ -160,18 +177,18 @@ func TestQueryValidators(t *testing.T) { // Query each validator queryParams := types.NewQueryValidatorParams(addrVal1) bz, err := cdc.MarshalJSON(queryParams) - require.Nil(t, err) + require.NoError(t, err) query := abci.RequestQuery{ Path: "/custom/staking/validator", Data: bz, } res, err := queryValidator(ctx, query, keeper) - require.Nil(t, err) + require.NoError(t, err) var validator types.Validator err = cdc.UnmarshalJSON(res, &validator) - require.Nil(t, err) + require.NoError(t, err) require.Equal(t, queriedValidators[0], validator) } @@ -199,7 +216,7 @@ func TestQueryDelegation(t *testing.T) { // Query Delegator bonded validators queryParams := types.NewQueryDelegatorParams(addrAcc2) bz, errRes := cdc.MarshalJSON(queryParams) - require.Nil(t, errRes) + require.NoError(t, errRes) query := abci.RequestQuery{ Path: "/custom/staking/delegatorValidators", @@ -209,11 +226,11 @@ func TestQueryDelegation(t *testing.T) { delValidators := keeper.GetDelegatorValidators(ctx, addrAcc2, params.MaxValidators) res, err := queryDelegatorValidators(ctx, query, keeper) - require.Nil(t, err) + require.NoError(t, err) var validatorsResp []types.Validator errRes = cdc.UnmarshalJSON(res, &validatorsResp) - require.Nil(t, errRes) + require.NoError(t, errRes) require.Equal(t, len(delValidators), len(validatorsResp)) require.ElementsMatch(t, delValidators, validatorsResp) @@ -222,12 +239,12 @@ func TestQueryDelegation(t *testing.T) { query.Data = bz[:len(bz)-1] _, err = queryDelegatorValidators(ctx, query, keeper) - require.NotNil(t, err) + require.Error(t, err) // Query bonded validator queryBondParams := types.NewQueryBondsParams(addrAcc2, addrVal1) bz, errRes = cdc.MarshalJSON(queryBondParams) - require.Nil(t, errRes) + require.NoError(t, errRes) query = abci.RequestQuery{ Path: "/custom/staking/delegatorValidator", @@ -235,11 +252,11 @@ func TestQueryDelegation(t *testing.T) { } res, err = queryDelegatorValidator(ctx, query, keeper) - require.Nil(t, err) + require.NoError(t, err) var validator types.Validator errRes = cdc.UnmarshalJSON(res, &validator) - require.Nil(t, errRes) + require.NoError(t, errRes) require.Equal(t, delValidators[0], validator) @@ -247,7 +264,7 @@ func TestQueryDelegation(t *testing.T) { query.Data = bz[:len(bz)-1] _, err = queryDelegatorValidator(ctx, query, keeper) - require.NotNil(t, err) + require.Error(t, err) // Query delegation @@ -260,11 +277,11 @@ func TestQueryDelegation(t *testing.T) { require.True(t, found) res, err = queryDelegation(ctx, query, keeper) - require.Nil(t, err) + require.NoError(t, err) var delegationRes types.DelegationResponse errRes = cdc.UnmarshalJSON(res, &delegationRes) - require.Nil(t, errRes) + require.NoError(t, errRes) require.Equal(t, delegation.ValidatorAddress, delegationRes.ValidatorAddress) require.Equal(t, delegation.DelegatorAddress, delegationRes.DelegatorAddress) @@ -277,11 +294,11 @@ func TestQueryDelegation(t *testing.T) { } res, err = queryDelegatorDelegations(ctx, query, keeper) - require.Nil(t, err) + require.NoError(t, err) var delegatorDelegations types.DelegationResponses errRes = cdc.UnmarshalJSON(res, &delegatorDelegations) - require.Nil(t, errRes) + require.NoError(t, errRes) require.Len(t, delegatorDelegations, 1) require.Equal(t, delegation.ValidatorAddress, delegatorDelegations[0].ValidatorAddress) require.Equal(t, delegation.DelegatorAddress, delegatorDelegations[0].DelegatorAddress) @@ -291,12 +308,12 @@ func TestQueryDelegation(t *testing.T) { query.Data = bz[:len(bz)-1] _, err = queryDelegation(ctx, query, keeper) - require.NotNil(t, err) + require.Error(t, err) // Query validator delegations bz, errRes = cdc.MarshalJSON(types.NewQueryValidatorParams(addrVal1)) - require.Nil(t, errRes) + require.NoError(t, errRes) query = abci.RequestQuery{ Path: "custom/staking/validatorDelegations", @@ -304,11 +321,11 @@ func TestQueryDelegation(t *testing.T) { } res, err = queryValidatorDelegations(ctx, query, keeper) - require.Nil(t, err) + require.NoError(t, err) var delegationsRes types.DelegationResponses errRes = cdc.UnmarshalJSON(res, &delegationsRes) - require.Nil(t, errRes) + require.NoError(t, errRes) require.Len(t, delegatorDelegations, 1) require.Equal(t, delegation.ValidatorAddress, delegationsRes[0].ValidatorAddress) require.Equal(t, delegation.DelegatorAddress, delegationsRes[0].DelegatorAddress) @@ -317,11 +334,11 @@ func TestQueryDelegation(t *testing.T) { // Query unbonging delegation unbondingTokens := sdk.TokensFromConsensusPower(10) _, err = keeper.Undelegate(ctx, addrAcc2, val1.OperatorAddress, unbondingTokens.ToDec()) - require.Nil(t, err) + require.NoError(t, err) queryBondParams = types.NewQueryBondsParams(addrAcc2, addrVal1) bz, errRes = cdc.MarshalJSON(queryBondParams) - require.Nil(t, errRes) + require.NoError(t, errRes) query = abci.RequestQuery{ Path: "/custom/staking/unbondingDelegation", @@ -332,11 +349,11 @@ func TestQueryDelegation(t *testing.T) { require.True(t, found) res, err = queryUnbondingDelegation(ctx, query, keeper) - require.Nil(t, err) + require.NoError(t, err) var unbondRes types.UnbondingDelegation errRes = cdc.UnmarshalJSON(res, &unbondRes) - require.Nil(t, errRes) + require.NoError(t, errRes) require.Equal(t, unbond, unbondRes) @@ -344,7 +361,7 @@ func TestQueryDelegation(t *testing.T) { query.Data = bz[:len(bz)-1] _, err = queryUnbondingDelegation(ctx, query, keeper) - require.NotNil(t, err) + require.Error(t, err) // Query Delegator Delegations @@ -354,29 +371,29 @@ func TestQueryDelegation(t *testing.T) { } res, err = queryDelegatorUnbondingDelegations(ctx, query, keeper) - require.Nil(t, err) + require.NoError(t, err) var delegatorUbds []types.UnbondingDelegation errRes = cdc.UnmarshalJSON(res, &delegatorUbds) - require.Nil(t, errRes) + require.NoError(t, errRes) require.Equal(t, unbond, delegatorUbds[0]) // error unknown request query.Data = bz[:len(bz)-1] _, err = queryDelegatorUnbondingDelegations(ctx, query, keeper) - require.NotNil(t, err) + require.Error(t, err) // Query redelegation redelegationTokens := sdk.TokensFromConsensusPower(10) _, err = keeper.BeginRedelegation(ctx, addrAcc2, val1.OperatorAddress, val2.OperatorAddress, redelegationTokens.ToDec()) - require.Nil(t, err) + require.NoError(t, err) redel, found := keeper.GetRedelegation(ctx, addrAcc2, val1.OperatorAddress, val2.OperatorAddress) require.True(t, found) bz, errRes = cdc.MarshalJSON(types.NewQueryRedelegationParams(addrAcc2, val1.OperatorAddress, val2.OperatorAddress)) - require.Nil(t, errRes) + require.NoError(t, errRes) query = abci.RequestQuery{ Path: "/custom/staking/redelegations", @@ -384,11 +401,11 @@ func TestQueryDelegation(t *testing.T) { } res, err = queryRedelegations(ctx, query, keeper) - require.Nil(t, err) + require.NoError(t, err) var redelRes types.RedelegationResponses errRes = cdc.UnmarshalJSON(res, &redelRes) - require.Nil(t, errRes) + require.NoError(t, errRes) require.Len(t, redelRes, 1) require.Equal(t, redel.DelegatorAddress, redelRes[0].DelegatorAddress) require.Equal(t, redel.ValidatorSrcAddress, redelRes[0].ValidatorSrcAddress) @@ -420,7 +437,7 @@ func TestQueryRedelegations(t *testing.T) { // delegator redelegations queryDelegatorParams := types.NewQueryDelegatorParams(addrAcc2) bz, errRes := cdc.MarshalJSON(queryDelegatorParams) - require.Nil(t, errRes) + require.NoError(t, errRes) query := abci.RequestQuery{ Path: "/custom/staking/redelegations", @@ -428,11 +445,11 @@ func TestQueryRedelegations(t *testing.T) { } res, err := queryRedelegations(ctx, query, keeper) - require.Nil(t, err) + require.NoError(t, err) var redelRes types.RedelegationResponses errRes = cdc.UnmarshalJSON(res, &redelRes) - require.Nil(t, errRes) + require.NoError(t, errRes) require.Len(t, redelRes, 1) require.Equal(t, redel.DelegatorAddress, redelRes[0].DelegatorAddress) require.Equal(t, redel.ValidatorSrcAddress, redelRes[0].ValidatorSrcAddress) @@ -442,7 +459,7 @@ func TestQueryRedelegations(t *testing.T) { // validator redelegations queryValidatorParams := types.NewQueryValidatorParams(val1.GetOperator()) bz, errRes = cdc.MarshalJSON(queryValidatorParams) - require.Nil(t, errRes) + require.NoError(t, errRes) query = abci.RequestQuery{ Path: "/custom/staking/redelegations", @@ -450,10 +467,10 @@ func TestQueryRedelegations(t *testing.T) { } res, err = queryRedelegations(ctx, query, keeper) - require.Nil(t, err) + require.NoError(t, err) errRes = cdc.UnmarshalJSON(res, &redelRes) - require.Nil(t, errRes) + require.NoError(t, errRes) require.Len(t, redelRes, 1) require.Equal(t, redel.DelegatorAddress, redelRes[0].DelegatorAddress) require.Equal(t, redel.ValidatorSrcAddress, redelRes[0].ValidatorSrcAddress) @@ -489,13 +506,13 @@ func TestQueryUnbondingDelegation(t *testing.T) { // queryValidatorParams := types.NewQueryBondsParams(addrAcc1, val1.GetOperator()) bz, errRes := cdc.MarshalJSON(queryValidatorParams) - require.Nil(t, errRes) + require.NoError(t, errRes) query := abci.RequestQuery{ Path: "/custom/staking/unbondingDelegation", Data: bz, } res, err := queryUnbondingDelegation(ctx, query, keeper) - require.Nil(t, err) + require.NoError(t, err) require.NotNil(t, res) var ubDel types.UnbondingDelegation require.NoError(t, cdc.UnmarshalJSON(res, &ubDel)) @@ -508,26 +525,26 @@ func TestQueryUnbondingDelegation(t *testing.T) { // queryValidatorParams = types.NewQueryBondsParams(addrAcc2, val1.GetOperator()) bz, errRes = cdc.MarshalJSON(queryValidatorParams) - require.Nil(t, errRes) + require.NoError(t, errRes) query = abci.RequestQuery{ Path: "/custom/staking/unbondingDelegation", Data: bz, } _, err = queryUnbondingDelegation(ctx, query, keeper) - require.NotNil(t, err) + require.Error(t, err) // // found: query unbonding delegation by delegator and validator // queryDelegatorParams := types.NewQueryDelegatorParams(addrAcc1) bz, errRes = cdc.MarshalJSON(queryDelegatorParams) - require.Nil(t, errRes) + require.NoError(t, errRes) query = abci.RequestQuery{ Path: "/custom/staking/delegatorUnbondingDelegations", Data: bz, } res, err = queryDelegatorUnbondingDelegations(ctx, query, keeper) - require.Nil(t, err) + require.NoError(t, err) require.NotNil(t, res) var ubDels []types.UnbondingDelegation require.NoError(t, cdc.UnmarshalJSON(res, &ubDels)) @@ -540,14 +557,56 @@ func TestQueryUnbondingDelegation(t *testing.T) { // queryDelegatorParams = types.NewQueryDelegatorParams(addrAcc2) bz, errRes = cdc.MarshalJSON(queryDelegatorParams) - require.Nil(t, errRes) + require.NoError(t, errRes) query = abci.RequestQuery{ Path: "/custom/staking/delegatorUnbondingDelegations", Data: bz, } res, err = queryDelegatorUnbondingDelegations(ctx, query, keeper) - require.Nil(t, err) + require.NoError(t, err) require.NotNil(t, res) require.NoError(t, cdc.UnmarshalJSON(res, &ubDels)) require.Equal(t, 0, len(ubDels)) } + +func TestQueryHistoricalInfo(t *testing.T) { + cdc := codec.New() + ctx, _, keeper, _ := CreateTestInput(t, false, 10000) + + // Create Validators and Delegation + val1 := types.NewValidator(addrVal1, pk1, types.Description{}) + val2 := types.NewValidator(addrVal2, pk2, types.Description{}) + vals := []types.Validator{val1, val2} + keeper.SetValidator(ctx, val1) + keeper.SetValidator(ctx, val2) + + header := abci.Header{ + ChainID: "HelloChain", + Height: 5, + } + hi := types.NewHistoricalInfo(header, vals) + keeper.SetHistoricalInfo(ctx, 5, hi) + + queryHistoricalParams := types.NewQueryHistoricalInfoParams(4) + bz, errRes := cdc.MarshalJSON(queryHistoricalParams) + require.NoError(t, errRes) + query := abci.RequestQuery{ + Path: "/custom/staking/historicalInfo", + Data: bz, + } + res, err := queryHistoricalInfo(ctx, query, keeper) + require.Error(t, err, "Invalid query passed") + require.Nil(t, res, "Invalid query returned non-nil result") + + queryHistoricalParams = types.NewQueryHistoricalInfoParams(5) + bz, errRes = cdc.MarshalJSON(queryHistoricalParams) + require.NoError(t, errRes) + query.Data = bz + res, err = queryHistoricalInfo(ctx, query, keeper) + require.NoError(t, err, "Valid query passed") + require.NotNil(t, res, "Valid query returned nil result") + + var recv types.HistoricalInfo + require.NoError(t, cdc.UnmarshalJSON(res, &recv)) + require.Equal(t, hi, recv, "HistoricalInfo query returned wrong result") +} diff --git a/x/staking/keeper/val_state_change.go b/x/staking/keeper/val_state_change.go index 724ebaff0590..f43a8f9da5a7 100644 --- a/x/staking/keeper/val_state_change.go +++ b/x/staking/keeper/val_state_change.go @@ -11,6 +11,62 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking/types" ) +// Calculate the ValidatorUpdates for the current block +// Called in each EndBlock +func (k Keeper) BlockValidatorUpdates(ctx sdk.Context) []abci.ValidatorUpdate { + // Calculate validator set changes. + // + // NOTE: ApplyAndReturnValidatorSetUpdates has to come before + // UnbondAllMatureValidatorQueue. + // This fixes a bug when the unbonding period is instant (is the case in + // some of the tests). The test expected the validator to be completely + // unbonded after the Endblocker (go from Bonded -> Unbonding during + // ApplyAndReturnValidatorSetUpdates and then Unbonding -> Unbonded during + // UnbondAllMatureValidatorQueue). + validatorUpdates := k.ApplyAndReturnValidatorSetUpdates(ctx) + + // Unbond all mature validators from the unbonding queue. + k.UnbondAllMatureValidatorQueue(ctx) + + // Remove all mature unbonding delegations from the ubd queue. + matureUnbonds := k.DequeueAllMatureUBDQueue(ctx, ctx.BlockHeader().Time) + for _, dvPair := range matureUnbonds { + err := k.CompleteUnbonding(ctx, dvPair.DelegatorAddress, dvPair.ValidatorAddress) + if err != nil { + continue + } + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeCompleteUnbonding, + sdk.NewAttribute(types.AttributeKeyValidator, dvPair.ValidatorAddress.String()), + sdk.NewAttribute(types.AttributeKeyDelegator, dvPair.DelegatorAddress.String()), + ), + ) + } + + // Remove all mature redelegations from the red queue. + matureRedelegations := k.DequeueAllMatureRedelegationQueue(ctx, ctx.BlockHeader().Time) + for _, dvvTriplet := range matureRedelegations { + err := k.CompleteRedelegation(ctx, dvvTriplet.DelegatorAddress, + dvvTriplet.ValidatorSrcAddress, dvvTriplet.ValidatorDstAddress) + if err != nil { + continue + } + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeCompleteRedelegation, + sdk.NewAttribute(types.AttributeKeyDelegator, dvvTriplet.DelegatorAddress.String()), + sdk.NewAttribute(types.AttributeKeySrcValidator, dvvTriplet.ValidatorSrcAddress.String()), + sdk.NewAttribute(types.AttributeKeyDstValidator, dvvTriplet.ValidatorDstAddress.String()), + ), + ) + } + + return validatorUpdates +} + // Apply and return accumulated updates to the bonded validator set. Also, // * Updates the active valset as keyed by LastValidatorPowerKey. // * Updates the total power as keyed by LastTotalPowerKey. diff --git a/x/staking/module.go b/x/staking/module.go index 45a06e67244a..69a8cb940504 100644 --- a/x/staking/module.go +++ b/x/staking/module.go @@ -165,7 +165,9 @@ func (am AppModule) ExportGenesis(ctx sdk.Context) json.RawMessage { } // BeginBlock returns the begin blocker for the staking module. -func (AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {} +func (am AppModule) BeginBlock(ctx sdk.Context, _ abci.RequestBeginBlock) { + BeginBlocker(ctx, am.keeper) +} // EndBlock returns the end blocker for the staking module. It returns no validator // updates. diff --git a/x/staking/simulation/genesis.go b/x/staking/simulation/genesis.go index d0455386298c..cca02bee8cc9 100644 --- a/x/staking/simulation/genesis.go +++ b/x/staking/simulation/genesis.go @@ -50,7 +50,7 @@ func RandomizedGenState(simState *module.SimulationState) { // NewSimulationManager constructor for this to work simState.UnbondTime = unbondTime - params := types.NewParams(simState.UnbondTime, maxValidators, 7, sdk.DefaultBondDenom) + params := types.NewParams(simState.UnbondTime, maxValidators, 7, 3, sdk.DefaultBondDenom) // validators & delegations var ( diff --git a/x/staking/spec/01_state.md b/x/staking/spec/01_state.md index bf388a143615..11b63d8dfc32 100644 --- a/x/staking/spec/01_state.md +++ b/x/staking/spec/01_state.md @@ -282,3 +282,21 @@ The stored object as each key is an array of validator operator addresses from which the validator object can be accessed. Typically it is expected that only a single validator record will be associated with a given timestamp however it is possible that multiple validators exist in the queue at the same location. + +## HistoricalInfo + +HistoricalInfo objects are stored and pruned at each block such that the staking keeper persists +the `n` most recent historical info defined by staking module parameter: `HistoricalEntries`. + +```go +type HistoricalInfo struct { + Header abci.Header + ValSet []types.Validator +} +``` + +At each BeginBlock, the staking keeper will persist the current Header and the Validators that committed +the current block in a `HistoricalInfo` object. The Validators are sorted on their address to ensure that +they are in a determisnistic order. +The oldest HistoricalEntries will be pruned to ensure that there only exist the parameter-defined number of +historical entries. diff --git a/x/staking/spec/04_begin_block.md b/x/staking/spec/04_begin_block.md new file mode 100644 index 000000000000..3ba615b5de4a --- /dev/null +++ b/x/staking/spec/04_begin_block.md @@ -0,0 +1,16 @@ + + +# Begin-Block + +Each abci begin block call, the historical info will get stored and pruned +according to the `HistoricalEntries` parameter. + +## Historical Info Tracking + +If the `HistoricalEntries` parameter is 0, then the `BeginBlock` performs a no-op. + +Otherwise, the latest historical info is stored under the key `historicalInfoKey|height`, while any entries older than `height - HistoricalEntries` is deleted. +In most cases, this results in a single entry being pruned per block. +However, if the parameter `HistoricalEntries` has changed to a lower value there will be multiple entries in the store that must be pruned. diff --git a/x/staking/spec/04_end_block.md b/x/staking/spec/05_end_block.md similarity index 99% rename from x/staking/spec/04_end_block.md rename to x/staking/spec/05_end_block.md index 3207c078cd30..16444134f424 100644 --- a/x/staking/spec/04_end_block.md +++ b/x/staking/spec/05_end_block.md @@ -1,5 +1,5 @@ # End-Block diff --git a/x/staking/spec/05_hooks.md b/x/staking/spec/06_hooks.md similarity index 99% rename from x/staking/spec/05_hooks.md rename to x/staking/spec/06_hooks.md index 2eac2d4a1708..c2c372b624d8 100644 --- a/x/staking/spec/05_hooks.md +++ b/x/staking/spec/06_hooks.md @@ -1,5 +1,5 @@ # Hooks diff --git a/x/staking/spec/06_events.md b/x/staking/spec/07_events.md similarity index 99% rename from x/staking/spec/06_events.md rename to x/staking/spec/07_events.md index 48162355cf97..e16cf009570d 100644 --- a/x/staking/spec/06_events.md +++ b/x/staking/spec/07_events.md @@ -1,5 +1,5 @@ # Events diff --git a/x/staking/spec/07_params.md b/x/staking/spec/07_params.md deleted file mode 100644 index 6df38579dc81..000000000000 --- a/x/staking/spec/07_params.md +++ /dev/null @@ -1,14 +0,0 @@ - - -# Parameters - -The staking module contains the following parameters: - -| Key | Type | Example | -|---------------|------------------|-------------------| -| UnbondingTime | string (time ns) | "259200000000000" | -| MaxValidators | uint16 | 100 | -| KeyMaxEntries | uint16 | 7 | -| BondDenom | string | "uatom" | diff --git a/x/staking/spec/08_params.md b/x/staking/spec/08_params.md new file mode 100644 index 000000000000..3d87879e18a0 --- /dev/null +++ b/x/staking/spec/08_params.md @@ -0,0 +1,15 @@ + + +# Parameters + +The staking module contains the following parameters: + +| Key | Type | Example | +|-------------------|------------------|-------------------| +| UnbondingTime | string (time ns) | "259200000000000" | +| MaxValidators | uint16 | 100 | +| KeyMaxEntries | uint16 | 7 | +| HistoricalEntries | uint16 | 3 | +| BondDenom | string | "uatom" | diff --git a/x/staking/spec/README.md b/x/staking/spec/README.md index 7f61b900cd92..437790ce74e2 100644 --- a/x/staking/spec/README.md +++ b/x/staking/spec/README.md @@ -32,6 +32,7 @@ network. - [UnbondingDelegation](01_state.md#unbondingdelegation) - [Redelegation](01_state.md#redelegation) - [Queues](01_state.md#queues) + - [HistoricalInfo](01_state.md#historicalinfo) 2. **[State Transitions](02_state_transitions.md)** - [Validators](02_state_transitions.md#validators) - [Delegations](02_state_transitions.md#delegations) @@ -42,11 +43,13 @@ network. - [MsgDelegate](03_messages.md#msgdelegate) - [MsgBeginUnbonding](03_messages.md#msgbeginunbonding) - [MsgBeginRedelegate](03_messages.md#msgbeginredelegate) -4. **[End-Block ](04_end_block.md)** - - [Validator Set Changes](04_end_block.md#validator-set-changes) - - [Queues ](04_end_block.md#queues-) -5. **[Hooks](05_hooks.md)** -6. **[Events](06_events.md)** - - [EndBlocker](06_events.md#endblocker) - - [Handlers](06_events.md#handlers) -7. **[Parameters](07_params.md)** +4. **[Begin-Block](04_begin_block.md)** + - [Historical Info Tracking](04_begin_block.md#historical-info-tracking) +4. **[End-Block ](05_end_block.md)** + - [Validator Set Changes](05_end_block.md#validator-set-changes) + - [Queues ](05_end_block.md#queues-) +5. **[Hooks](06_hooks.md)** +6. **[Events](07_events.md)** + - [EndBlocker](07_events.md#endblocker) + - [Handlers](07_events.md#handlers) +7. **[Parameters](08_params.md)** diff --git a/x/staking/types/errors.go b/x/staking/types/errors.go index 012f9421f8ee..523e720e2d98 100644 --- a/x/staking/types/errors.go +++ b/x/staking/types/errors.go @@ -14,14 +14,15 @@ type CodeType = sdk.CodeType const ( DefaultCodespace sdk.CodespaceType = ModuleName - CodeInvalidValidator CodeType = 101 - CodeInvalidDelegation CodeType = 102 - CodeInvalidInput CodeType = 103 - CodeValidatorJailed CodeType = 104 - CodeInvalidAddress CodeType = sdk.CodeInvalidAddress - CodeUnauthorized CodeType = sdk.CodeUnauthorized - CodeInternal CodeType = sdk.CodeInternal - CodeUnknownRequest CodeType = sdk.CodeUnknownRequest + CodeInvalidValidator CodeType = 101 + CodeInvalidDelegation CodeType = 102 + CodeInvalidInput CodeType = 103 + CodeValidatorJailed CodeType = 104 + CodeInvalidHistoricalInfo CodeType = 105 + CodeInvalidAddress CodeType = sdk.CodeInvalidAddress + CodeUnauthorized CodeType = sdk.CodeUnauthorized + CodeInternal CodeType = sdk.CodeInternal + CodeUnknownRequest CodeType = sdk.CodeUnknownRequest ) //validator @@ -212,3 +213,11 @@ func ErrNeitherShareMsgsGiven(codespace sdk.CodespaceType) sdk.Error { func ErrMissingSignature(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidValidator, "missing signature") } + +func ErrInvalidHistoricalInfo(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodeInvalidHistoricalInfo, "invalid historical info") +} + +func ErrNoHistoricalInfo(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodeInvalidHistoricalInfo, "no historical info found") +} diff --git a/x/staking/types/historical_info.go b/x/staking/types/historical_info.go new file mode 100644 index 000000000000..8fae88f07f4e --- /dev/null +++ b/x/staking/types/historical_info.go @@ -0,0 +1,57 @@ +package types + +import ( + "sort" + + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/codec" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +// HistoricalInfo contains the historical information that gets stored at each height +type HistoricalInfo struct { + Header abci.Header `json:"header" yaml:"header"` + ValSet []Validator `json:"valset" yaml:"valset"` +} + +// NewHistoricalInfo will create a historical information struct from header and valset +// it will first sort valset before inclusion into historical info +func NewHistoricalInfo(header abci.Header, valSet []Validator) HistoricalInfo { + sort.Sort(Validators(valSet)) + return HistoricalInfo{ + Header: header, + ValSet: valSet, + } +} + +// MustMarshalHistoricalInfo wll marshal historical info and panic on error +func MustMarshalHistoricalInfo(cdc *codec.Codec, hi HistoricalInfo) []byte { + return cdc.MustMarshalBinaryLengthPrefixed(hi) +} + +// MustUnmarshalHistoricalInfo wll unmarshal historical info and panic on error +func MustUnmarshalHistoricalInfo(cdc *codec.Codec, value []byte) HistoricalInfo { + hi, err := UnmarshalHistoricalInfo(cdc, value) + if err != nil { + panic(err) + } + return hi +} + +// UnmarshalHistoricalInfo will unmarshal historical info and return any error +func UnmarshalHistoricalInfo(cdc *codec.Codec, value []byte) (hi HistoricalInfo, err error) { + err = cdc.UnmarshalBinaryLengthPrefixed(value, &hi) + return hi, err +} + +// ValidateBasic will ensure HistoricalInfo is not nil and sorted +func ValidateBasic(hi HistoricalInfo) error { + if len(hi.ValSet) == 0 { + return sdkerrors.Wrap(ErrInvalidHistoricalInfo(DefaultCodespace), "ValidatorSer is nil") + } + if !sort.IsSorted(Validators(hi.ValSet)) { + return sdkerrors.Wrap(ErrInvalidHistoricalInfo(DefaultCodespace), "ValidatorSet is not sorted by address") + } + return nil +} diff --git a/x/staking/types/historical_info_test.go b/x/staking/types/historical_info_test.go new file mode 100644 index 000000000000..f607ba15031c --- /dev/null +++ b/x/staking/types/historical_info_test.go @@ -0,0 +1,67 @@ +package types + +import ( + "math/rand" + "sort" + "testing" + + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" +) + +var ( + validators = []Validator{ + NewValidator(valAddr1, pk1, Description{}), + NewValidator(valAddr2, pk2, Description{}), + NewValidator(valAddr3, pk3, Description{}), + } + header = abci.Header{ + ChainID: "hello", + Height: 5, + } +) + +func TestHistoricalInfo(t *testing.T) { + hi := NewHistoricalInfo(header, validators) + require.True(t, sort.IsSorted(Validators(hi.ValSet)), "Validators are not sorted") + + var value []byte + require.NotPanics(t, func() { + value = MustMarshalHistoricalInfo(ModuleCdc, hi) + }) + + require.NotNil(t, value, "Marshalled HistoricalInfo is nil") + + recv, err := UnmarshalHistoricalInfo(ModuleCdc, value) + require.Nil(t, err, "Unmarshalling HistoricalInfo failed") + require.Equal(t, hi, recv, "Unmarshalled HistoricalInfo is different from original") + require.True(t, sort.IsSorted(Validators(hi.ValSet)), "Validators are not sorted") +} + +func TestValidateBasic(t *testing.T) { + hi := HistoricalInfo{ + Header: header, + } + err := ValidateBasic(hi) + require.Error(t, err, "ValidateBasic passed on nil ValSet") + + // Ensure validators are not sorted + for sort.IsSorted(Validators(validators)) { + rand.Shuffle(len(validators), func(i, j int) { + it := validators[i] + validators[i] = validators[j] + validators[j] = it + }) + } + + hi = HistoricalInfo{ + Header: header, + ValSet: validators, + } + err = ValidateBasic(hi) + require.Error(t, err, "ValidateBasic passed on unsorted ValSet") + + hi = NewHistoricalInfo(header, validators) + err = ValidateBasic(hi) + require.NoError(t, err, "ValidateBasic failed on valid HistoricalInfo") +} diff --git a/x/staking/types/keys.go b/x/staking/types/keys.go index 372b0b924294..d278b50db3e7 100644 --- a/x/staking/types/keys.go +++ b/x/staking/types/keys.go @@ -2,6 +2,7 @@ package types import ( "encoding/binary" + "strconv" "time" sdk "github.com/cosmos/cosmos-sdk/types" @@ -45,6 +46,8 @@ var ( UnbondingQueueKey = []byte{0x41} // prefix for the timestamps in unbonding queue RedelegationQueueKey = []byte{0x42} // prefix for the timestamps in redelegations queue ValidatorQueueKey = []byte{0x43} // prefix for the timestamps in validator queue + + HistoricalInfoKey = []byte{0x50} // prefix for the historical info ) // gets the key for the validator with address @@ -278,3 +281,10 @@ func GetREDsByDelToValDstIndexKey(delAddr sdk.AccAddress, valDstAddr sdk.ValAddr GetREDsToValDstIndexKey(valDstAddr), delAddr.Bytes()...) } + +//________________________________________________________________________________ + +// GetHistoricalInfoKey gets the key for the historical info +func GetHistoricalInfoKey(height int64) []byte { + return append(HistoricalInfoKey, []byte(strconv.FormatInt(height, 10))...) +} diff --git a/x/staking/types/params.go b/x/staking/types/params.go index 00d7aed07fb7..f3aefb404899 100644 --- a/x/staking/types/params.go +++ b/x/staking/types/params.go @@ -24,35 +24,42 @@ const ( // Default maximum entries in a UBD/RED pair DefaultMaxEntries uint16 = 7 + + // DefaultHistorical entries is 0 since it must only be non-zero for + // IBC connected chains + DefaultHistoricalEntries uint16 = 0 ) // nolint - Keys for parameter access var ( - KeyUnbondingTime = []byte("UnbondingTime") - KeyMaxValidators = []byte("MaxValidators") - KeyMaxEntries = []byte("KeyMaxEntries") - KeyBondDenom = []byte("BondDenom") + KeyUnbondingTime = []byte("UnbondingTime") + KeyMaxValidators = []byte("MaxValidators") + KeyMaxEntries = []byte("KeyMaxEntries") + KeyBondDenom = []byte("BondDenom") + KeyHistoricalEntries = []byte("HistoricalEntries") ) var _ params.ParamSet = (*Params)(nil) // Params defines the high level settings for staking type Params struct { - UnbondingTime time.Duration `json:"unbonding_time" yaml:"unbonding_time"` // time duration of unbonding - MaxValidators uint16 `json:"max_validators" yaml:"max_validators"` // maximum number of validators (max uint16 = 65535) - MaxEntries uint16 `json:"max_entries" yaml:"max_entries"` // max entries for either unbonding delegation or redelegation (per pair/trio) - BondDenom string `json:"bond_denom" yaml:"bond_denom"` // bondable coin denomination + UnbondingTime time.Duration `json:"unbonding_time" yaml:"unbonding_time"` // time duration of unbonding + MaxValidators uint16 `json:"max_validators" yaml:"max_validators"` // maximum number of validators (max uint16 = 65535) + MaxEntries uint16 `json:"max_entries" yaml:"max_entries"` // max entries for either unbonding delegation or redelegation (per pair/trio) + HistoricalEntries uint16 `json:"historical_entries" yaml:"historical_entries"` // number of historical entries to persist + BondDenom string `json:"bond_denom" yaml:"bond_denom"` // bondable coin denomination } // NewParams creates a new Params instance -func NewParams(unbondingTime time.Duration, maxValidators, maxEntries uint16, +func NewParams(unbondingTime time.Duration, maxValidators, maxEntries, historicalEntries uint16, bondDenom string) Params { return Params{ - UnbondingTime: unbondingTime, - MaxValidators: maxValidators, - MaxEntries: maxEntries, - BondDenom: bondDenom, + UnbondingTime: unbondingTime, + MaxValidators: maxValidators, + MaxEntries: maxEntries, + HistoricalEntries: historicalEntries, + BondDenom: bondDenom, } } @@ -62,6 +69,7 @@ func (p *Params) ParamSetPairs() params.ParamSetPairs { params.NewParamSetPair(KeyUnbondingTime, &p.UnbondingTime, validateUnbondingTime), params.NewParamSetPair(KeyMaxValidators, &p.MaxValidators, validateMaxValidators), params.NewParamSetPair(KeyMaxEntries, &p.MaxEntries, validateMaxEntries), + params.NewParamSetPair(KeyHistoricalEntries, &p.HistoricalEntries, validateHistoricalEntries), params.NewParamSetPair(KeyBondDenom, &p.BondDenom, validateBondDenom), } } @@ -76,17 +84,18 @@ func (p Params) Equal(p2 Params) bool { // DefaultParams returns a default set of parameters. func DefaultParams() Params { - return NewParams(DefaultUnbondingTime, DefaultMaxValidators, DefaultMaxEntries, sdk.DefaultBondDenom) + return NewParams(DefaultUnbondingTime, DefaultMaxValidators, DefaultMaxEntries, DefaultHistoricalEntries, sdk.DefaultBondDenom) } // String returns a human readable string representation of the parameters. func (p Params) String() string { return fmt.Sprintf(`Params: - Unbonding Time: %s - Max Validators: %d - Max Entries: %d - Bonded Coin Denom: %s`, p.UnbondingTime, - p.MaxValidators, p.MaxEntries, p.BondDenom) + Unbonding Time: %s + Max Validators: %d + Max Entries: %d + Historical Entries: %d + Bonded Coin Denom: %s`, p.UnbondingTime, + p.MaxValidators, p.MaxEntries, p.HistoricalEntries, p.BondDenom) } // unmarshal the current staking params value from store key or panic @@ -164,6 +173,15 @@ func validateMaxEntries(i interface{}) error { return nil } +func validateHistoricalEntries(i interface{}) error { + _, ok := i.(uint16) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + return nil +} + func validateBondDenom(i interface{}) error { v, ok := i.(string) if !ok { diff --git a/x/staking/types/querier.go b/x/staking/types/querier.go index ba38a55742f5..adc387354ea9 100644 --- a/x/staking/types/querier.go +++ b/x/staking/types/querier.go @@ -20,6 +20,7 @@ const ( QueryDelegatorValidator = "delegatorValidator" QueryPool = "pool" QueryParameters = "parameters" + QueryHistoricalInfo = "historicalInfo" ) // defines the params for the following queries: @@ -96,3 +97,14 @@ type QueryValidatorsParams struct { func NewQueryValidatorsParams(page, limit int, status string) QueryValidatorsParams { return QueryValidatorsParams{page, limit, status} } + +// QueryHistoricalInfoParams defines the params for the following queries: +// - 'custom/staking/historicalInfo' +type QueryHistoricalInfoParams struct { + Height int64 +} + +// NewQueryHistoricalInfoParams creates a new QueryHistoricalInfoParams instance +func NewQueryHistoricalInfoParams(height int64) QueryHistoricalInfoParams { + return QueryHistoricalInfoParams{height} +} diff --git a/x/staking/types/validator.go b/x/staking/types/validator.go index df68c177e930..37e6cbc02575 100644 --- a/x/staking/types/validator.go +++ b/x/staking/types/validator.go @@ -3,6 +3,7 @@ package types import ( "bytes" "fmt" + "sort" "strings" "time" @@ -102,6 +103,28 @@ func (v Validators) ToSDKValidators() (validators []exported.ValidatorI) { return validators } +// Sort Validators sorts validator array in ascending operator address order +func (v Validators) Sort() { + sort.Sort(v) +} + +// Implements sort interface +func (v Validators) Len() int { + return len(v) +} + +// Implements sort interface +func (v Validators) Less(i, j int) bool { + return bytes.Compare(v[i].OperatorAddress, v[j].OperatorAddress) == -1 +} + +// Implements sort interface +func (v Validators) Swap(i, j int) { + it := v[i] + v[i] = v[j] + v[j] = it +} + // NewValidator - initialize a new validator func NewValidator(operator sdk.ValAddress, pubKey crypto.PubKey, description Description) Validator { return Validator{ diff --git a/x/staking/types/validator_test.go b/x/staking/types/validator_test.go index 6f8243efab4b..f705d0d8df99 100644 --- a/x/staking/types/validator_test.go +++ b/x/staking/types/validator_test.go @@ -2,10 +2,14 @@ package types import ( "fmt" + "math/rand" + "reflect" + "sort" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/crypto/ed25519" tmtypes "github.com/tendermint/tendermint/types" yaml "gopkg.in/yaml.v2" @@ -303,3 +307,31 @@ func TestValidatorMarshalYAML(t *testing.T) { `, validator.OperatorAddress.String(), bechifiedPub) require.Equal(t, want, string(bs)) } + +// Check that sort will create deterministic ordering of validators +func TestValidatorsSortDeterminism(t *testing.T) { + vals := make([]Validator, 10) + sortedVals := make([]Validator, 10) + + // Create random validator slice + for i := range vals { + pk := ed25519.GenPrivKey().PubKey() + vals[i] = NewValidator(sdk.ValAddress(pk.Address()), pk, Description{}) + } + + // Save sorted copy + sort.Sort(Validators(vals)) + copy(sortedVals, vals) + + // Randomly shuffle validators, sort, and check it is equal to original sort + for i := 0; i < 10; i++ { + rand.Shuffle(10, func(i, j int) { + it := vals[i] + vals[i] = vals[j] + vals[j] = it + }) + + Validators(vals).Sort() + require.True(t, reflect.DeepEqual(sortedVals, vals), "Validator sort returned different slices") + } +} From eae10b0cff46eecf8c7d4210d8131028d01be24f Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Wed, 18 Dec 2019 15:48:22 +0100 Subject: [PATCH 043/529] Merge PR #5419: Parametrise simulation gas value --- CHANGELOG.md | 3 ++- simapp/helpers/test_helpers.go | 9 ++++++--- simapp/test_helpers.go | 2 ++ x/bank/simulation/operations.go | 2 ++ x/distribution/simulation/operations.go | 4 ++++ x/gov/simulation/operations.go | 3 +++ x/slashing/simulation/operations.go | 1 + x/staking/simulation/operations.go | 5 +++++ 8 files changed, 25 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7516d35b4157..8507b6b1f2ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -77,7 +77,8 @@ if the provided arguments are invalid. * (modules) [\#5299](https://github.com/cosmos/cosmos-sdk/pull/5299) `HandleDoubleSign` along with params `MaxEvidenceAge` and `DoubleSignJailEndTime` have moved from the `x/slashing` module to the `x/evidence` module. * (keys) [\#4941](https://github.com/cosmos/cosmos-sdk/issues/4941) Initializing a new keybase through `NewKeyringFromHomeFlag`, `NewKeyringFromDir`, `NewKeyBaseFromHomeFlag`, `NewKeyBaseFromDir`, or `NewInMemory` functions now accept optional parameters of type `KeybaseOption`. These optional parameters are also added on the keys subcommands functions, which are now public, and allows these options to be set on the commands or ignored to default to previous behavior. - * The option introduced in this PR is `WithKeygenFunc` which allows a custom bytes to key implementation to be defined when keys are created. + * The option introduced in this PR is `WithKeygenFunc` which allows a custom bytes to key implementation to be defined when keys are created. +* (simapp) [\#5419](https://github.com/cosmos/cosmos-sdk/pull/5419) simapp/helpers.GenTx() now accepts a gas argument. ### Client Breaking Changes diff --git a/simapp/helpers/test_helpers.go b/simapp/helpers/test_helpers.go index a9127a6fbd45..2341635eeea8 100644 --- a/simapp/helpers/test_helpers.go +++ b/simapp/helpers/test_helpers.go @@ -12,13 +12,16 @@ import ( ) // SimAppChainID hardcoded chainID for simulation -const SimAppChainID = "simulation-app" +const ( + DefaultGenTxGas = 1000000 + SimAppChainID = "simulation-app" +) // GenTx generates a signed mock transaction. -func GenTx(msgs []sdk.Msg, feeAmt sdk.Coins, chainID string, accnums []uint64, seq []uint64, priv ...crypto.PrivKey) auth.StdTx { +func GenTx(msgs []sdk.Msg, feeAmt sdk.Coins, gas uint64, chainID string, accnums []uint64, seq []uint64, priv ...crypto.PrivKey) auth.StdTx { fee := auth.StdFee{ Amount: feeAmt, - Gas: 1000000, // TODO: this should be a param + Gas: gas, } sigs := make([]auth.StdSignature, len(priv)) diff --git a/simapp/test_helpers.go b/simapp/test_helpers.go index 306b4259fb2d..0e6d22150255 100644 --- a/simapp/test_helpers.go +++ b/simapp/test_helpers.go @@ -120,6 +120,7 @@ func SignCheckDeliver( tx := helpers.GenTx( msgs, sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 0)}, + helpers.DefaultGenTxGas, "", accNums, seq, @@ -163,6 +164,7 @@ func GenSequenceOfTxs(msgs []sdk.Msg, accNums []uint64, initSeqNums []uint64, nu txs[i] = helpers.GenTx( msgs, sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 0)}, + helpers.DefaultGenTxGas, "", accNums, initSeqNums, diff --git a/x/bank/simulation/operations.go b/x/bank/simulation/operations.go index 9e89174e9433..71a88386c960 100644 --- a/x/bank/simulation/operations.go +++ b/x/bank/simulation/operations.go @@ -108,6 +108,7 @@ func sendMsgSend( tx := helpers.GenTx( []sdk.Msg{msg}, fees, + helpers.DefaultGenTxGas, chainID, []uint64{account.GetAccountNumber()}, []uint64{account.GetSequence()}, @@ -251,6 +252,7 @@ func sendMsgMultiSend( tx := helpers.GenTx( []sdk.Msg{msg}, fees, + helpers.DefaultGenTxGas, chainID, accountNumbers, sequenceNumbers, diff --git a/x/distribution/simulation/operations.go b/x/distribution/simulation/operations.go index 2ec483cbc1ba..9a9dea6b8d4b 100644 --- a/x/distribution/simulation/operations.go +++ b/x/distribution/simulation/operations.go @@ -102,6 +102,7 @@ func SimulateMsgSetWithdrawAddress(ak types.AccountKeeper, k keeper.Keeper) simu tx := helpers.GenTx( []sdk.Msg{msg}, fees, + helpers.DefaultGenTxGas, chainID, []uint64{account.GetAccountNumber()}, []uint64{account.GetSequence()}, @@ -147,6 +148,7 @@ func SimulateMsgWithdrawDelegatorReward(ak types.AccountKeeper, k keeper.Keeper, tx := helpers.GenTx( []sdk.Msg{msg}, fees, + helpers.DefaultGenTxGas, chainID, []uint64{account.GetAccountNumber()}, []uint64{account.GetSequence()}, @@ -195,6 +197,7 @@ func SimulateMsgWithdrawValidatorCommission(ak types.AccountKeeper, k keeper.Kee tx := helpers.GenTx( []sdk.Msg{msg}, fees, + helpers.DefaultGenTxGas, chainID, []uint64{account.GetAccountNumber()}, []uint64{account.GetSequence()}, @@ -244,6 +247,7 @@ func SimulateMsgFundCommunityPool(ak types.AccountKeeper, k keeper.Keeper, sk st tx := helpers.GenTx( []sdk.Msg{msg}, fees, + helpers.DefaultGenTxGas, chainID, []uint64{account.GetAccountNumber()}, []uint64{account.GetSequence()}, diff --git a/x/gov/simulation/operations.go b/x/gov/simulation/operations.go index 4d33d82bc86c..0e0bcd06f600 100644 --- a/x/gov/simulation/operations.go +++ b/x/gov/simulation/operations.go @@ -141,6 +141,7 @@ func SimulateSubmitProposal( tx := helpers.GenTx( []sdk.Msg{msg}, fees, + helpers.DefaultGenTxGas, chainID, []uint64{account.GetAccountNumber()}, []uint64{account.GetSequence()}, @@ -223,6 +224,7 @@ func SimulateMsgDeposit(ak types.AccountKeeper, k keeper.Keeper) simulation.Oper tx := helpers.GenTx( []sdk.Msg{msg}, fees, + helpers.DefaultGenTxGas, chainID, []uint64{account.GetAccountNumber()}, []uint64{account.GetSequence()}, @@ -280,6 +282,7 @@ func operationSimulateMsgVote(ak types.AccountKeeper, k keeper.Keeper, tx := helpers.GenTx( []sdk.Msg{msg}, fees, + helpers.DefaultGenTxGas, chainID, []uint64{account.GetAccountNumber()}, []uint64{account.GetSequence()}, diff --git a/x/slashing/simulation/operations.go b/x/slashing/simulation/operations.go index 992513c924d8..3e2a3bc78bad 100644 --- a/x/slashing/simulation/operations.go +++ b/x/slashing/simulation/operations.go @@ -86,6 +86,7 @@ func SimulateMsgUnjail(ak types.AccountKeeper, k keeper.Keeper, sk stakingkeeper tx := helpers.GenTx( []sdk.Msg{msg}, fees, + helpers.DefaultGenTxGas, chainID, []uint64{account.GetAccountNumber()}, []uint64{account.GetSequence()}, diff --git a/x/staking/simulation/operations.go b/x/staking/simulation/operations.go index d2b2cab87d04..8ddea88aa7c6 100644 --- a/x/staking/simulation/operations.go +++ b/x/staking/simulation/operations.go @@ -154,6 +154,7 @@ func SimulateMsgCreateValidator(ak types.AccountKeeper, k keeper.Keeper) simulat tx := helpers.GenTx( []sdk.Msg{msg}, fees, + helpers.DefaultGenTxGas, chainID, []uint64{account.GetAccountNumber()}, []uint64{account.GetSequence()}, @@ -218,6 +219,7 @@ func SimulateMsgEditValidator(ak types.AccountKeeper, k keeper.Keeper) simulatio tx := helpers.GenTx( []sdk.Msg{msg}, fees, + helpers.DefaultGenTxGas, chainID, []uint64{account.GetAccountNumber()}, []uint64{account.GetSequence()}, @@ -284,6 +286,7 @@ func SimulateMsgDelegate(ak types.AccountKeeper, k keeper.Keeper) simulation.Ope tx := helpers.GenTx( []sdk.Msg{msg}, fees, + helpers.DefaultGenTxGas, chainID, []uint64{account.GetAccountNumber()}, []uint64{account.GetSequence()}, @@ -363,6 +366,7 @@ func SimulateMsgUndelegate(ak types.AccountKeeper, k keeper.Keeper) simulation.O tx := helpers.GenTx( []sdk.Msg{msg}, fees, + helpers.DefaultGenTxGas, chainID, []uint64{account.GetAccountNumber()}, []uint64{account.GetSequence()}, @@ -468,6 +472,7 @@ func SimulateMsgBeginRedelegate(ak types.AccountKeeper, k keeper.Keeper) simulat tx := helpers.GenTx( []sdk.Msg{msg}, fees, + helpers.DefaultGenTxGas, chainID, []uint64{account.GetAccountNumber()}, []uint64{account.GetSequence()}, From cf4645213d4135bbaad0cbf2bac0517b401a4e20 Mon Sep 17 00:00:00 2001 From: Dmitry Shulyak Date: Wed, 18 Dec 2019 20:15:37 +0200 Subject: [PATCH 044/529] Merge PR #5405: Queries to /gov/proposals/{proposalID}/votes support pagination --- x/gov/client/cli/query.go | 15 +++- x/gov/client/rest/query.go | 11 ++- x/gov/client/utils/query.go | 78 +++++++++++-------- x/gov/client/utils/query_test.go | 129 +++++++++++++++++++++++++++++++ x/gov/keeper/querier.go | 10 ++- x/gov/keeper/querier_test.go | 80 ++++++++++++++++++- x/gov/types/querier.go | 17 +++- 7 files changed, 295 insertions(+), 45 deletions(-) create mode 100644 x/gov/client/utils/query_test.go diff --git a/x/gov/client/cli/query.go b/x/gov/client/cli/query.go index 47a0c223d0ca..69f89e7a7d05 100644 --- a/x/gov/client/cli/query.go +++ b/x/gov/client/cli/query.go @@ -13,6 +13,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" + "github.com/cosmos/cosmos-sdk/x/auth/client/utils" gcutils "github.com/cosmos/cosmos-sdk/x/gov/client/utils" "github.com/cosmos/cosmos-sdk/x/gov/types" ) @@ -242,7 +243,7 @@ $ %s query gov vote 1 cosmos1skjwj5whet0lpe65qaq4rpq03hjxlwd9nf39lk // GetCmdQueryVotes implements the command to query for proposal votes. func GetCmdQueryVotes(queryRoute string, cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ + cmd := &cobra.Command{ Use: "votes [proposal-id]", Args: cobra.ExactArgs(1), Short: "Query votes on a proposal", @@ -250,7 +251,8 @@ func GetCmdQueryVotes(queryRoute string, cdc *codec.Codec) *cobra.Command { fmt.Sprintf(`Query vote details for a single proposal by its identifier. Example: -$ %s query gov votes 1 +$ %[1]s query gov votes 1 +$ %[1]s query gov votes 1 --page=2 --limit=100 `, version.ClientName, ), @@ -263,8 +265,10 @@ $ %s query gov votes 1 if err != nil { return fmt.Errorf("proposal-id %s not a valid int, please input a valid proposal-id", args[0]) } + page := viper.GetInt(flagPage) + limit := viper.GetInt(flagNumLimit) - params := types.NewQueryProposalParams(proposalID) + params := types.NewQueryProposalVotesParams(proposalID, page, limit) bz, err := cdc.MarshalJSON(params) if err != nil { return err @@ -281,7 +285,7 @@ $ %s query gov votes 1 propStatus := proposal.Status if !(propStatus == types.StatusVotingPeriod || propStatus == types.StatusDepositPeriod) { - res, err = gcutils.QueryVotesByTxQuery(cliCtx, params) + res, err = gcutils.QueryVotesByTxQuery(cliCtx, params, utils.QueryTxsByEvents) } else { res, _, err = cliCtx.QueryWithData(fmt.Sprintf("custom/%s/votes", queryRoute), bz) } @@ -295,6 +299,9 @@ $ %s query gov votes 1 return cliCtx.PrintOutput(votes) }, } + cmd.Flags().Int(flagPage, 1, "pagination page of votes to to query for") + cmd.Flags().Int(flagNumLimit, 100, "pagination limit of votes to query for") + return cmd } // Command to Get a specific Deposit Information diff --git a/x/gov/client/rest/query.go b/x/gov/client/rest/query.go index a3ccb926cf29..de9ccf379dd5 100644 --- a/x/gov/client/rest/query.go +++ b/x/gov/client/rest/query.go @@ -10,6 +10,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/rest" + "github.com/cosmos/cosmos-sdk/x/auth/client/utils" gcutils "github.com/cosmos/cosmos-sdk/x/gov/client/utils" "github.com/cosmos/cosmos-sdk/x/gov/types" ) @@ -332,6 +333,12 @@ func queryVoteHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { // todo: Split this functionality into helper functions to remove the above func queryVotesOnProposalHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { + _, page, limit, err := rest.ParseHTTPArgsWithLimit(r, 0) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + vars := mux.Vars(r) strProposalID := vars[RestProposalID] @@ -351,7 +358,7 @@ func queryVotesOnProposalHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return } - params := types.NewQueryProposalParams(proposalID) + params := types.NewQueryProposalVotesParams(proposalID, page, limit) bz, err := cliCtx.Codec.MarshalJSON(params) if err != nil { @@ -375,7 +382,7 @@ func queryVotesOnProposalHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { // as they're no longer in state. propStatus := proposal.Status if !(propStatus == types.StatusVotingPeriod || propStatus == types.StatusDepositPeriod) { - res, err = gcutils.QueryVotesByTxQuery(cliCtx, params) + res, err = gcutils.QueryVotesByTxQuery(cliCtx, params, utils.QueryTxsByEvents) } else { res, _, err = cliCtx.QueryWithData("custom/gov/votes", bz) } diff --git a/x/gov/client/utils/query.go b/x/gov/client/utils/query.go index 0e29b6f4fb41..2eaf2c5a7a78 100644 --- a/x/gov/client/utils/query.go +++ b/x/gov/client/utils/query.go @@ -3,6 +3,7 @@ package utils import ( "fmt" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth/client/utils" @@ -72,45 +73,57 @@ func QueryDepositsByTxQuery(cliCtx context.CLIContext, params types.QueryProposa return cliCtx.Codec.MarshalJSON(deposits) } -// QueryVotesByTxQuery will query for votes via a direct txs tags query. It -// will fetch and build votes directly from the returned txs and return a JSON -// marshalled result or any error that occurred. -// -// NOTE: SearchTxs is used to facilitate the txs query which does not currently -// support configurable pagination. -func QueryVotesByTxQuery(cliCtx context.CLIContext, params types.QueryProposalParams) ([]byte, error) { - events := []string{ - fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, types.TypeMsgVote), - fmt.Sprintf("%s.%s='%s'", types.EventTypeProposalVote, types.AttributeKeyProposalID, []byte(fmt.Sprintf("%d", params.ProposalID))), - } - - // NOTE: SearchTxs is used to facilitate the txs query which does not currently - // support configurable pagination. - searchResult, err := utils.QueryTxsByEvents(cliCtx, events, defaultPage, defaultLimit) - if err != nil { - return nil, err - } - - var votes []types.Vote - - for _, info := range searchResult.Txs { - for _, msg := range info.Tx.GetMsgs() { - if msg.Type() == types.TypeMsgVote { - voteMsg := msg.(types.MsgVote) +// TxQuerier is a type that accepts query parameters (target events and pagination options) and returns sdk.SearchTxsResult. +// Mainly used for easier mocking of utils.QueryTxsByEvents in tests. +type TxQuerier func(cliCtx context.CLIContext, events []string, page, limit int) (*sdk.SearchTxsResult, error) - votes = append(votes, types.Vote{ - Voter: voteMsg.Voter, - ProposalID: params.ProposalID, - Option: voteMsg.Option, - }) +// QueryVotesByTxQuery will query for votes using provided TxQuerier implementation. +// In general utils.QueryTxsByEvents should be used that will do a direct tx query to a tendermint node. +// It will fetch and build votes directly from the returned txs and return a JSON +// marshalled result or any error that occurred. +func QueryVotesByTxQuery(cliCtx context.CLIContext, params types.QueryProposalVotesParams, querier TxQuerier) ([]byte, error) { + var ( + events = []string{ + fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, types.TypeMsgVote), + fmt.Sprintf("%s.%s='%s'", types.EventTypeProposalVote, types.AttributeKeyProposalID, []byte(fmt.Sprintf("%d", params.ProposalID))), + } + votes []types.Vote + nextTxPage = defaultPage + totalLimit = params.Limit * params.Page + ) + // query interrupted either if we collected enough votes or tx indexer run out of relevant txs + for len(votes) < totalLimit { + searchResult, err := querier(cliCtx, events, nextTxPage, defaultLimit) + if err != nil { + return nil, err + } + nextTxPage++ + for _, info := range searchResult.Txs { + for _, msg := range info.Tx.GetMsgs() { + if msg.Type() == types.TypeMsgVote { + voteMsg := msg.(types.MsgVote) + + votes = append(votes, types.Vote{ + Voter: voteMsg.Voter, + ProposalID: params.ProposalID, + Option: voteMsg.Option, + }) + } } } + if len(searchResult.Txs) != defaultLimit { + break + } + } + start, end := client.Paginate(len(votes), params.Page, params.Limit, 100) + if start < 0 || end < 0 { + votes = []types.Vote{} + } else { + votes = votes[start:end] } - if cliCtx.Indent { return cliCtx.Codec.MarshalJSONIndent(votes, "", " ") } - return cliCtx.Codec.MarshalJSON(votes) } @@ -128,7 +141,6 @@ func QueryVoteByTxQuery(cliCtx context.CLIContext, params types.QueryVoteParams) if err != nil { return nil, err } - for _, info := range searchResult.Txs { for _, msg := range info.Tx.GetMsgs() { // there should only be a single vote under the given conditions diff --git a/x/gov/client/utils/query_test.go b/x/gov/client/utils/query_test.go new file mode 100644 index 000000000000..ce9b548b93bb --- /dev/null +++ b/x/gov/client/utils/query_test.go @@ -0,0 +1,129 @@ +package utils + +import ( + "testing" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/stretchr/testify/require" +) + +type txMock struct { + address sdk.AccAddress + msgNum int +} + +func (tx txMock) ValidateBasic() sdk.Error { + return nil +} + +func (tx txMock) GetMsgs() (msgs []sdk.Msg) { + for i := 0; i < tx.msgNum; i++ { + msgs = append(msgs, types.NewMsgVote(tx.address, 0, types.OptionYes)) + } + return +} + +func makeQuerier(txs []sdk.Tx) TxQuerier { + return func(cliCtx context.CLIContext, events []string, page, limit int) (*sdk.SearchTxsResult, error) { + start, end := client.Paginate(len(txs), page, limit, 100) + if start < 0 || end < 0 { + return nil, nil + } + rst := &sdk.SearchTxsResult{ + TotalCount: len(txs), + PageNumber: page, + PageTotal: len(txs) / limit, + Limit: limit, + Count: end - start, + } + for _, tx := range txs[start:end] { + rst.Txs = append(rst.Txs, sdk.TxResponse{Tx: tx}) + } + return rst, nil + } +} + +func TestGetPaginatedVotes(t *testing.T) { + type testCase struct { + description string + page, limit int + txs []sdk.Tx + votes []types.Vote + } + acc1 := make(sdk.AccAddress, 20) + acc1[0] = 1 + acc2 := make(sdk.AccAddress, 20) + acc2[0] = 2 + for _, tc := range []testCase{ + { + description: "1MsgPerTxAll", + page: 1, + limit: 2, + txs: []sdk.Tx{txMock{acc1, 1}, txMock{acc2, 1}}, + votes: []types.Vote{ + types.NewVote(0, acc1, types.OptionYes), + types.NewVote(0, acc2, types.OptionYes)}, + }, + { + description: "2MsgPerTx1Chunk", + page: 1, + limit: 2, + txs: []sdk.Tx{txMock{acc1, 2}, txMock{acc2, 2}}, + votes: []types.Vote{ + types.NewVote(0, acc1, types.OptionYes), + types.NewVote(0, acc1, types.OptionYes)}, + }, + { + description: "2MsgPerTx2Chunk", + page: 2, + limit: 2, + txs: []sdk.Tx{txMock{acc1, 2}, txMock{acc2, 2}}, + votes: []types.Vote{ + types.NewVote(0, acc2, types.OptionYes), + types.NewVote(0, acc2, types.OptionYes)}, + }, + { + description: "IncompleteSearchTx", + page: 1, + limit: 2, + txs: []sdk.Tx{txMock{acc1, 1}}, + votes: []types.Vote{types.NewVote(0, acc1, types.OptionYes)}, + }, + { + description: "IncompleteSearchTx", + page: 1, + limit: 2, + txs: []sdk.Tx{txMock{acc1, 1}}, + votes: []types.Vote{types.NewVote(0, acc1, types.OptionYes)}, + }, + { + description: "InvalidPage", + page: -1, + txs: []sdk.Tx{txMock{acc1, 1}}, + }, + { + description: "OutOfBounds", + page: 2, + limit: 10, + txs: []sdk.Tx{txMock{acc1, 1}}, + }, + } { + tc := tc + t.Run(tc.description, func(t *testing.T) { + ctx := context.CLIContext{}.WithCodec(codec.New()) + params := types.NewQueryProposalVotesParams(0, tc.page, tc.limit) + votesData, err := QueryVotesByTxQuery(ctx, params, makeQuerier(tc.txs)) + require.NoError(t, err) + votes := []types.Vote{} + require.NoError(t, ctx.Codec.UnmarshalJSON(votesData, &votes)) + require.Equal(t, len(tc.votes), len(votes)) + for i := range votes { + require.Equal(t, tc.votes[i], votes[i]) + } + }) + } +} diff --git a/x/gov/keeper/querier.go b/x/gov/keeper/querier.go index b27f8fa54e5b..b5efc7619b05 100644 --- a/x/gov/keeper/querier.go +++ b/x/gov/keeper/querier.go @@ -5,6 +5,7 @@ import ( abci "github.com/tendermint/tendermint/abci/types" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/gov/types" @@ -177,7 +178,7 @@ func queryTally(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Ke // nolint: unparam func queryVotes(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) ([]byte, sdk.Error) { - var params types.QueryProposalParams + var params types.QueryProposalVotesParams err := keeper.cdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { @@ -187,6 +188,13 @@ func queryVotes(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Ke votes := keeper.GetVotes(ctx, params.ProposalID) if votes == nil { votes = types.Votes{} + } else { + start, end := client.Paginate(len(votes), params.Page, params.Limit, 100) + if start < 0 || end < 0 { + votes = types.Votes{} + } else { + votes = votes[start:end] + } } bz, err := codec.MarshalJSONIndent(keeper.cdc, votes) diff --git a/x/gov/keeper/querier_test.go b/x/gov/keeper/querier_test.go index 827741bea38e..a5f781da1807 100644 --- a/x/gov/keeper/querier_test.go +++ b/x/gov/keeper/querier_test.go @@ -1,8 +1,10 @@ package keeper import ( + "math/rand" "strings" "testing" + "time" "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" @@ -122,10 +124,11 @@ func getQueriedVote(t *testing.T, ctx sdk.Context, cdc *codec.Codec, querier sdk return vote } -func getQueriedVotes(t *testing.T, ctx sdk.Context, cdc *codec.Codec, querier sdk.Querier, proposalID uint64) []types.Vote { +func getQueriedVotes(t *testing.T, ctx sdk.Context, cdc *codec.Codec, querier sdk.Querier, + proposalID uint64, page, limit int) []types.Vote { query := abci.RequestQuery{ Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryVote}, "/"), - Data: cdc.MustMarshalJSON(types.NewQueryProposalParams(proposalID)), + Data: cdc.MustMarshalJSON(types.NewQueryProposalVotesParams(proposalID, page, limit)), } bz, err := querier(ctx, []string{types.QueryVotes}, query) @@ -244,7 +247,7 @@ func TestQueries(t *testing.T) { require.Equal(t, proposal3, proposals[1]) // Test query votes on types.Proposal 2 - votes := getQueriedVotes(t, ctx, keeper.cdc, querier, proposal2.ProposalID) + votes := getQueriedVotes(t, ctx, keeper.cdc, querier, proposal2.ProposalID, 1, 0) require.Len(t, votes, 1) require.Equal(t, vote1, votes[0]) @@ -252,7 +255,7 @@ func TestQueries(t *testing.T) { require.Equal(t, vote1, vote) // Test query votes on types.Proposal 3 - votes = getQueriedVotes(t, ctx, keeper.cdc, querier, proposal3.ProposalID) + votes = getQueriedVotes(t, ctx, keeper.cdc, querier, proposal3.ProposalID, 1, 0) require.Len(t, votes, 2) require.Equal(t, vote2, votes[0]) require.Equal(t, vote3, votes[1]) @@ -280,3 +283,72 @@ func TestQueries(t *testing.T) { proposals = getQueriedProposals(t, ctx, keeper.cdc, querier, TestAddrs[0], TestAddrs[0], types.StatusNil, 1, 0) require.Equal(t, proposal2.ProposalID, proposals[0].ProposalID) } + +func TestPaginatedVotesQuery(t *testing.T) { + ctx, _, keeper, _, _ := createTestInput(t, false, 1000) + + proposal := types.Proposal{ + ProposalID: 100, + Status: types.StatusVotingPeriod, + } + keeper.SetProposal(ctx, proposal) + + votes := make([]types.Vote, 20) + rand := rand.New(rand.NewSource(time.Now().UnixNano())) + addr := make(sdk.AccAddress, 20) + for i := range votes { + rand.Read(addr) + vote := types.Vote{ + ProposalID: proposal.ProposalID, + Voter: addr, + Option: types.OptionYes, + } + votes[i] = vote + keeper.SetVote(ctx, vote) + } + + querier := NewQuerier(keeper) + + // keeper preserves consistent order for each query, but this is not the insertion order + all := getQueriedVotes(t, ctx, keeper.cdc, querier, proposal.ProposalID, 1, 0) + require.Equal(t, len(all), len(votes)) + + type testCase struct { + description string + page int + limit int + votes []types.Vote + } + for _, tc := range []testCase{ + { + description: "SkipAll", + page: 2, + limit: len(all), + }, + { + description: "GetFirstChunk", + page: 1, + limit: 10, + votes: all[:10], + }, + { + description: "GetSecondsChunk", + page: 2, + limit: 10, + votes: all[10:], + }, + { + description: "InvalidPage", + page: -1, + }, + } { + tc := tc + t.Run(tc.description, func(t *testing.T) { + votes := getQueriedVotes(t, ctx, keeper.cdc, querier, proposal.ProposalID, tc.page, tc.limit) + require.Equal(t, len(tc.votes), len(votes)) + for i := range votes { + require.Equal(t, tc.votes[i], votes[i]) + } + }) + } +} diff --git a/x/gov/types/querier.go b/x/gov/types/querier.go index fe97356b5cc2..fe9b5e0f15cb 100644 --- a/x/gov/types/querier.go +++ b/x/gov/types/querier.go @@ -26,7 +26,6 @@ const ( // - 'custom/gov/proposal' // - 'custom/gov/deposits' // - 'custom/gov/tally' -// - 'custom/gov/votes' type QueryProposalParams struct { ProposalID uint64 } @@ -38,6 +37,22 @@ func NewQueryProposalParams(proposalID uint64) QueryProposalParams { } } +// QueryProposalVotesParams used for queries to 'custom/gov/votes'. +type QueryProposalVotesParams struct { + ProposalID uint64 + Page int + Limit int +} + +// NewQueryProposalVotesParams creates new instance of the QueryProposalVotesParams. +func NewQueryProposalVotesParams(proposalID uint64, page, limit int) QueryProposalVotesParams { + return QueryProposalVotesParams{ + ProposalID: proposalID, + Page: page, + Limit: limit, + } +} + // QueryDepositParams params for query 'custom/gov/deposit' type QueryDepositParams struct { ProposalID uint64 From 876beef6341b7da161f5b283e9d0a2836fd379d6 Mon Sep 17 00:00:00 2001 From: Kevin Davis Date: Thu, 19 Dec 2019 16:46:43 -0500 Subject: [PATCH 045/529] Merge PR #5428: Add mod, exponentiation for uint --- CHANGELOG.md | 7 ++++--- types/uint.go | 44 ++++++++++++++++++++++++++++++++++++++++++++ types/uint_test.go | 19 +++++++++++++++++++ 3 files changed, 67 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8507b6b1f2ec..5bcb6ee207f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -76,7 +76,7 @@ if the provided arguments are invalid. `StdTx.Signatures` to get back the array of StdSignatures `[]StdSignature`. * (modules) [\#5299](https://github.com/cosmos/cosmos-sdk/pull/5299) `HandleDoubleSign` along with params `MaxEvidenceAge` and `DoubleSignJailEndTime` have moved from the `x/slashing` module to the `x/evidence` module. -* (keys) [\#4941](https://github.com/cosmos/cosmos-sdk/issues/4941) Initializing a new keybase through `NewKeyringFromHomeFlag`, `NewKeyringFromDir`, `NewKeyBaseFromHomeFlag`, `NewKeyBaseFromDir`, or `NewInMemory` functions now accept optional parameters of type `KeybaseOption`. These optional parameters are also added on the keys subcommands functions, which are now public, and allows these options to be set on the commands or ignored to default to previous behavior. +* (keys) [\#4941](https://github.com/cosmos/cosmos-sdk/issues/4941) Initializing a new keybase through `NewKeyringFromHomeFlag`, `NewKeyringFromDir`, `NewKeyBaseFromHomeFlag`, `NewKeyBaseFromDir`, or `NewInMemory` functions now accept optional parameters of type `KeybaseOption`. These optional parameters are also added on the keys subcommands functions, which are now public, and allows these options to be set on the commands or ignored to default to previous behavior. * The option introduced in this PR is `WithKeygenFunc` which allows a custom bytes to key implementation to be defined when keys are created. * (simapp) [\#5419](https://github.com/cosmos/cosmos-sdk/pull/5419) simapp/helpers.GenTx() now accepts a gas argument. @@ -213,11 +213,12 @@ to detail this new feature and how state transitions occur. * (docs/spec) All module specs moved into their respective module dir in x/ (i.e. docs/spec/staking -->> x/staking/spec) * (docs/) [\#5379](https://github.com/cosmos/cosmos-sdk/pull/5379) Major documentation refactor, including: * (docs/intro/) Add and improve introduction material for newcomers. - * (docs/basics/) Add documentation about basic concepts of the cosmos sdk such as the anatomy of an SDK application, the transaction lifecycle or accounts. - * (docs/core/) Add documentation about core conepts of the cosmos sdk such as `baseapp`, `server`, `store`s, `context` and more. + * (docs/basics/) Add documentation about basic concepts of the cosmos sdk such as the anatomy of an SDK application, the transaction lifecycle or accounts. + * (docs/core/) Add documentation about core conepts of the cosmos sdk such as `baseapp`, `server`, `store`s, `context` and more. * (docs/building-modules/) Add reference documentation on concepts relevant for module developers (`keeper`, `handler`, `messages`, `queries`,...). * (docs/interfaces/) Add documentation on building interfaces for the Cosmos SDK. * Redesigned user interface that features new dynamically generated sidebar, build-time code embedding from GitHub, new homepage as well as many other improvements. +* (types) [\#5428](https://github.com/cosmos/cosmos-sdk/pull/5428) Add `Mod` (modulo) method and `RelativePow` (exponentation) function for `Uint`. ### Bug Fixes diff --git a/types/uint.go b/types/uint.go index da43f5fb9094..1cc289b900dc 100644 --- a/types/uint.go +++ b/types/uint.go @@ -99,6 +99,14 @@ func (u Uint) MulUint64(u2 uint64) (res Uint) { return u.Mul(NewUint(u2)) } // Quo divides Uint with Uint func (u Uint) Quo(u2 Uint) (res Uint) { return NewUintFromBigInt(div(u.i, u2.i)) } +// Mod returns remainder after dividing with Uint +func (u Uint) Mod(u2 Uint) Uint { + if u2.IsZero() { + panic("division-by-zero") + } + return Uint{mod(u.i, u2.i)} +} + // Quo divides Uint with uint64 func (u Uint) QuoUint64(u2 uint64) Uint { return u.Quo(NewUint(u2)) } @@ -172,3 +180,39 @@ func checkNewUint(i *big.Int) (Uint, error) { } return Uint{i}, nil } + +// RelativePow raises x to the power of n, where x (and the result, z) are scaled by factor b +// for example, RelativePow(210, 2, 100) = 441 (2.1^2 = 4.41) +func RelativePow(x Uint, n Uint, b Uint) (z Uint) { + if x.IsZero() { + if n.IsZero() { + z = b // 0^0 = 1 + return + } + z = ZeroUint() // otherwise 0^a = 0 + return + } + + z = x + if n.Mod(NewUint(2)).Equal(ZeroUint()) { + z = b + } + + halfOfB := b.Quo(NewUint(2)) + n = n.Quo(NewUint(2)) + + for n.GT(ZeroUint()) { + xSquared := x.Mul(x) + xSquaredRounded := xSquared.Add(halfOfB) + + x = xSquaredRounded.Quo(b) + + if n.Mod(NewUint(2)).Equal(OneUint()) { + zx := z.Mul(x) + zxRounded := zx.Add(halfOfB) + z = zxRounded.Quo(b) + } + n = n.Quo(NewUint(2)) + } + return z +} diff --git a/types/uint_test.go b/types/uint_test.go index d371c81369a0..e90fbf7f509c 100644 --- a/types/uint_test.go +++ b/types/uint_test.go @@ -256,3 +256,22 @@ func TestParseUint(t *testing.T) { func randuint() Uint { return NewUint(rand.Uint64()) } + +func TestRelativePow(t *testing.T) { + tests := []struct { + args []Uint + want Uint + }{ + {[]Uint{ZeroUint(), ZeroUint(), OneUint()}, OneUint()}, + {[]Uint{ZeroUint(), ZeroUint(), NewUint(10)}, NewUint(10)}, + {[]Uint{ZeroUint(), OneUint(), NewUint(10)}, ZeroUint()}, + {[]Uint{NewUint(10), NewUint(2), OneUint()}, NewUint(100)}, + {[]Uint{NewUint(210), NewUint(2), NewUint(100)}, NewUint(441)}, + {[]Uint{NewUint(2100), NewUint(2), NewUint(1000)}, NewUint(4410)}, + {[]Uint{NewUint(1000000001547125958), NewUint(600), NewUint(1000000000000000000)}, NewUint(1000000928276004850)}, + } + for i, tc := range tests { + res := RelativePow(tc.args[0], tc.args[1], tc.args[2]) + require.Equal(t, tc.want, res, "unexpected result for test case %d, input: %v, got: %v", i, tc.args, res) + } +} From d12919987a44d7159a4a52aba41991f7e02b6eeb Mon Sep 17 00:00:00 2001 From: kaustubhkapatral <54210167+kaustubhkapatral@users.noreply.github.com> Date: Sun, 22 Dec 2019 00:10:03 +0530 Subject: [PATCH 046/529] Modified examples in distribution module (#5441) --- x/distribution/client/cli/query.go | 12 ++++++------ x/distribution/client/cli/tx.go | 10 +++++----- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/x/distribution/client/cli/query.go b/x/distribution/client/cli/query.go index 36d12e57fb1d..6b8457a3d730 100644 --- a/x/distribution/client/cli/query.go +++ b/x/distribution/client/cli/query.go @@ -66,7 +66,7 @@ func GetCmdQueryValidatorOutstandingRewards(queryRoute string, cdc *codec.Codec) for a validator and all their delegations. Example: -$ %s query distr validator-outstanding-rewards cosmosvaloper1lwjmdnks33xwnmfayc64ycprww49n33mtm92ne +$ %s query distribution validator-outstanding-rewards cosmosvaloper1lwjmdnks33xwnmfayc64ycprww49n33mtm92ne `, version.ClientName, ), @@ -113,7 +113,7 @@ func GetCmdQueryValidatorCommission(queryRoute string, cdc *codec.Codec) *cobra. fmt.Sprintf(`Query validator commission rewards from delegators to that validator. Example: -$ %s query distr commission cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj +$ %s query distribution commission cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj `, version.ClientName, ), @@ -148,7 +148,7 @@ func GetCmdQueryValidatorSlashes(queryRoute string, cdc *codec.Codec) *cobra.Com fmt.Sprintf(`Query all slashes of a validator for a given block range. Example: -$ %s query distr slashes cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj 0 100 +$ %s query distribution slashes cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj 0 100 `, version.ClientName, ), @@ -199,8 +199,8 @@ func GetCmdQueryDelegatorRewards(queryRoute string, cdc *codec.Codec) *cobra.Com fmt.Sprintf(`Query all rewards earned by a delegator, optionally restrict to rewards from a single validator. Example: -$ %s query distr rewards cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p -$ %s query distr rewards cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj +$ %s query distribution rewards cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p +$ %s query distribution rewards cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj `, version.ClientName, version.ClientName, ), @@ -243,7 +243,7 @@ func GetCmdQueryCommunityPool(queryRoute string, cdc *codec.Codec) *cobra.Comman fmt.Sprintf(`Query all coins in the community pool which is under Governance control. Example: -$ %s query distr community-pool +$ %s query distribution community-pool `, version.ClientName, ), diff --git a/x/distribution/client/cli/tx.go b/x/distribution/client/cli/tx.go index 29d0c17fc263..281373267fa5 100644 --- a/x/distribution/client/cli/tx.go +++ b/x/distribution/client/cli/tx.go @@ -95,8 +95,8 @@ func GetCmdWithdrawRewards(cdc *codec.Codec) *cobra.Command { and optionally withdraw validator commission if the delegation address given is a validator operator. Example: -$ %s tx distr withdraw-rewards cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj --from mykey -$ %s tx distr withdraw-rewards cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj --from mykey --commission +$ %s tx distribution withdraw-rewards cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj --from mykey +$ %s tx distribution withdraw-rewards cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj --from mykey --commission `, version.ClientName, version.ClientName, ), @@ -134,7 +134,7 @@ func GetCmdWithdrawAllRewards(cdc *codec.Codec, queryRoute string) *cobra.Comman fmt.Sprintf(`Withdraw all rewards for a single delegator. Example: -$ %s tx distr withdraw-all-rewards --from mykey +$ %s tx distribution withdraw-all-rewards --from mykey `, version.ClientName, ), @@ -176,7 +176,7 @@ func GetCmdSetWithdrawAddr(cdc *codec.Codec) *cobra.Command { fmt.Sprintf(`Set the withdraw address for rewards associated with a delegator address. Example: -$ %s tx set-withdraw-addr cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p --from mykey +$ %s tx distribution set-withdraw-addr cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p --from mykey `, version.ClientName, ), @@ -272,7 +272,7 @@ func GetCmdFundCommunityPool(cdc *codec.Codec) *cobra.Command { fmt.Sprintf(`Funds the community pool with the specified amount Example: -$ %s tx fund-community-pool 100uatom --from mykey +$ %s tx distribution fund-community-pool 100uatom --from mykey `, version.ClientName, ), From 8353680115d02e723cca30068aa8032d80451e45 Mon Sep 17 00:00:00 2001 From: Ferenc Fabian Date: Mon, 23 Dec 2019 17:05:47 +0100 Subject: [PATCH 047/529] Merge PR #5442: Remove of the client/alias.go --- CHANGELOG.md | 2 + client/alias.go | 129 --------------------------- client/routes.go | 3 +- x/auth/client/cli/decode.go | 4 +- x/auth/client/utils/tx.go | 8 +- x/bank/client/cli/tx.go | 3 +- x/crisis/client/cli/tx.go | 3 +- x/distribution/client/cli/query.go | 3 +- x/distribution/client/cli/tx.go | 5 +- x/evidence/client/cli/query.go | 5 +- x/evidence/client/cli/tx.go | 3 +- x/genutil/client/cli/collect.go | 4 +- x/genutil/client/cli/gentx.go | 26 +++--- x/genutil/client/cli/init.go | 6 +- x/genutil/client/cli/init_test.go | 4 +- x/genutil/client/cli/migrate_test.go | 4 +- x/gov/client/cli/query.go | 3 +- x/gov/client/cli/tx.go | 5 +- x/mint/client/cli/query.go | 3 +- x/slashing/client/cli/query.go | 3 +- x/slashing/client/cli/tx.go | 3 +- x/staking/client/cli/query.go | 3 +- x/staking/client/cli/tx.go | 15 ++-- x/supply/client/cli/query.go | 3 +- x/upgrade/module.go | 6 +- 25 files changed, 72 insertions(+), 184 deletions(-) delete mode 100644 client/alias.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 5bcb6ee207f5..e7b2bd071eb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,8 @@ logic has been implemented for v0.38 target version. Applications can migrate vi ### API Breaking Changes +* (client) [\#5442](https://github.com/cosmos/cosmos-sdk/pull/5442) Remove client/alias.go as it's not necessary and +components can be imported directly from the packages. * (store) [\#4748](https://github.com/cosmos/cosmos-sdk/pull/4748) The `CommitMultiStore` interface now requires a `SetInterBlockCache` method. Applications that do not wish to support this can simply have this method perform a no-op. diff --git a/client/alias.go b/client/alias.go deleted file mode 100644 index eed043c54401..000000000000 --- a/client/alias.go +++ /dev/null @@ -1,129 +0,0 @@ -// nolint -// autogenerated code using github.com/rigelrozanski/multitool -// aliases generated for the following subdirectories: -// ALIASGEN: github.com/cosmos/cosmos-sdk/client/context -// ALIASGEN: github.com/cosmos/cosmos-sdk/client/flags -// ALIASGEN: github.com/cosmos/cosmos-sdk/client/keys -// ALIASGEN: github.com/cosmos/cosmos-sdk/client/lcd -// ALIASGEN: github.com/cosmos/cosmos-sdk/client/rest -// ALIASGEN: github.com/cosmos/cosmos-sdk/client/rpc -// ALIASGEN: github.com/cosmos/cosmos-sdk/client/tx -// ALIASGEN: github.com/cosmos/cosmos-sdk/client/utils -// ALIASGEN: github.com/cosmos/cosmos-sdk/client/input -package client - -import ( - "github.com/cosmos/cosmos-sdk/client/context" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/client/input" - "github.com/cosmos/cosmos-sdk/client/keys" - "github.com/cosmos/cosmos-sdk/client/lcd" - "github.com/cosmos/cosmos-sdk/client/rpc" -) - -const ( - DefaultGasAdjustment = flags.DefaultGasAdjustment - DefaultGasLimit = flags.DefaultGasLimit - DefaultKeyringBackend = flags.DefaultKeyringBackend - GasFlagAuto = flags.GasFlagAuto - BroadcastBlock = flags.BroadcastBlock - BroadcastSync = flags.BroadcastSync - BroadcastAsync = flags.BroadcastAsync - FlagHome = flags.FlagHome - FlagUseLedger = flags.FlagUseLedger - FlagChainID = flags.FlagChainID - FlagNode = flags.FlagNode - FlagHeight = flags.FlagHeight - FlagGasAdjustment = flags.FlagGasAdjustment - FlagTrustNode = flags.FlagTrustNode - FlagFrom = flags.FlagFrom - FlagName = flags.FlagName - FlagAccountNumber = flags.FlagAccountNumber - FlagSequence = flags.FlagSequence - FlagMemo = flags.FlagMemo - FlagFees = flags.FlagFees - FlagGasPrices = flags.FlagGasPrices - FlagBroadcastMode = flags.FlagBroadcastMode - FlagDryRun = flags.FlagDryRun - FlagGenerateOnly = flags.FlagGenerateOnly - FlagIndentResponse = flags.FlagIndentResponse - FlagKeyringBackend = flags.FlagKeyringBackend - FlagListenAddr = flags.FlagListenAddr - FlagMaxOpenConnections = flags.FlagMaxOpenConnections - FlagRPCReadTimeout = flags.FlagRPCReadTimeout - FlagRPCWriteTimeout = flags.FlagRPCWriteTimeout - FlagOutputDocument = flags.FlagOutputDocument - FlagSkipConfirmation = flags.FlagSkipConfirmation - KeyringBackendFile = flags.KeyringBackendFile - KeyringBackendOS = flags.KeyringBackendOS - KeyringBackendTest = flags.KeyringBackendTest - DefaultKeyPass = keys.DefaultKeyPass - FlagAddress = keys.FlagAddress - FlagPublicKey = keys.FlagPublicKey - FlagBechPrefix = keys.FlagBechPrefix - FlagDevice = keys.FlagDevice - OutputFormatText = keys.OutputFormatText - OutputFormatJSON = keys.OutputFormatJSON - MinPassLength = input.MinPassLength -) - -var ( - // functions aliases - NewCLIContextWithFrom = context.NewCLIContextWithFrom - NewCLIContextWithInput = context.NewCLIContextWithInput - NewCLIContextWithInputAndFrom = context.NewCLIContextWithInputAndFrom - NewCLIContext = context.NewCLIContext - GetFromFields = context.GetFromFields - ErrInvalidAccount = context.ErrInvalidAccount - ErrVerifyCommit = context.ErrVerifyCommit - GetCommands = flags.GetCommands - PostCommands = flags.PostCommands - RegisterRestServerFlags = flags.RegisterRestServerFlags - ParseGas = flags.ParseGas - NewCompletionCmd = flags.NewCompletionCmd - MarshalJSON = keys.MarshalJSON - UnmarshalJSON = keys.UnmarshalJSON - Commands = keys.Commands - NewAddNewKey = keys.NewAddNewKey - NewRecoverKey = keys.NewRecoverKey - NewUpdateKeyReq = keys.NewUpdateKeyReq - NewDeleteKeyReq = keys.NewDeleteKeyReq - NewKeyringFromDir = keys.NewKeyringFromDir - NewKeyringFromHomeFlag = keys.NewKeyringFromHomeFlag - NewInMemoryKeyBase = keys.NewInMemoryKeyBase - NewRestServer = lcd.NewRestServer - ServeCommand = lcd.ServeCommand - BlockCommand = rpc.BlockCommand - GetChainHeight = rpc.GetChainHeight - BlockRequestHandlerFn = rpc.BlockRequestHandlerFn - LatestBlockRequestHandlerFn = rpc.LatestBlockRequestHandlerFn - RegisterRPCRoutes = rpc.RegisterRPCRoutes - StatusCommand = rpc.StatusCommand - NodeInfoRequestHandlerFn = rpc.NodeInfoRequestHandlerFn - NodeSyncingRequestHandlerFn = rpc.NodeSyncingRequestHandlerFn - ValidatorCommand = rpc.ValidatorCommand - GetValidators = rpc.GetValidators - ValidatorSetRequestHandlerFn = rpc.ValidatorSetRequestHandlerFn - LatestValidatorSetRequestHandlerFn = rpc.LatestValidatorSetRequestHandlerFn - GetPassword = input.GetPassword - GetCheckPassword = input.GetCheckPassword - GetConfirmation = input.GetConfirmation - GetString = input.GetString - PrintPrefixed = input.PrintPrefixed - - // variable aliases - LineBreak = flags.LineBreak - GasFlagVar = flags.GasFlagVar -) - -type ( - CLIContext = context.CLIContext - GasSetting = flags.GasSetting - AddNewKey = keys.AddNewKey - RecoverKey = keys.RecoverKey - UpdateKeyReq = keys.UpdateKeyReq - DeleteKeyReq = keys.DeleteKeyReq - RestServer = lcd.RestServer - ValidatorOutput = rpc.ValidatorOutput - ResultValidatorsOutput = rpc.ResultValidatorsOutput -) diff --git a/client/routes.go b/client/routes.go index ded91ca897b0..9eac8fa0d828 100644 --- a/client/routes.go +++ b/client/routes.go @@ -4,9 +4,10 @@ import ( "github.com/gorilla/mux" "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/rpc" ) // Register routes func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router) { - RegisterRPCRoutes(cliCtx, r) + rpc.RegisterRPCRoutes(cliCtx, r) } diff --git a/x/auth/client/cli/decode.go b/x/auth/client/cli/decode.go index 370f4fe72d7f..b27bbaa1c4ee 100644 --- a/x/auth/client/cli/decode.go +++ b/x/auth/client/cli/decode.go @@ -10,8 +10,8 @@ import ( "github.com/spf13/cobra" "github.com/tendermint/go-amino" - "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -43,7 +43,7 @@ func GetDecodeCommand(codec *amino.Codec) *cobra.Command { }, } - return client.PostCommands(cmd)[0] + return flags.PostCommands(cmd)[0] } // GetDecodeTxCmd - returns the command to decode a tx from hex or base64 diff --git a/x/auth/client/utils/tx.go b/x/auth/client/utils/tx.go index 265d9031bc43..7bdde2306518 100644 --- a/x/auth/client/utils/tx.go +++ b/x/auth/client/utils/tx.go @@ -10,10 +10,10 @@ import ( "github.com/pkg/errors" "github.com/spf13/viper" - "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/input" + "github.com/cosmos/cosmos-sdk/client/keys" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -94,7 +94,7 @@ func CompleteAndBroadcastTxCLI(txBldr authtypes.TxBuilder, cliCtx context.CLICon } // build and sign the transaction - txBytes, err := txBldr.BuildAndSign(fromName, client.DefaultKeyPass, msgs) + txBytes, err := txBldr.BuildAndSign(fromName, keys.DefaultKeyPass, msgs) if err != nil { return err } @@ -192,7 +192,7 @@ func SignStdTx( } } - return txBldr.SignStdTx(name, client.DefaultKeyPass, stdTx, appendSig) + return txBldr.SignStdTx(name, keys.DefaultKeyPass, stdTx, appendSig) } // SignStdTxWithSignerAddress attaches a signature to a StdTx and returns a copy of a it. @@ -214,7 +214,7 @@ func SignStdTxWithSignerAddress(txBldr authtypes.TxBuilder, cliCtx context.CLICo } } - return txBldr.SignStdTx(name, client.DefaultKeyPass, stdTx, false) + return txBldr.SignStdTx(name, keys.DefaultKeyPass, stdTx, false) } // Read and decode a StdTx from the given filename. Can pass "-" to read from stdin. diff --git a/x/bank/client/cli/tx.go b/x/bank/client/cli/tx.go index 71e1392b968a..58bce19eba6f 100644 --- a/x/bank/client/cli/tx.go +++ b/x/bank/client/cli/tx.go @@ -7,6 +7,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" @@ -57,7 +58,7 @@ func SendTxCmd(cdc *codec.Codec) *cobra.Command { }, } - cmd = client.PostCommands(cmd)[0] + cmd = flags.PostCommands(cmd)[0] return cmd } diff --git a/x/crisis/client/cli/tx.go b/x/crisis/client/cli/tx.go index cdea9206fbe6..e2df844db639 100644 --- a/x/crisis/client/cli/tx.go +++ b/x/crisis/client/cli/tx.go @@ -8,6 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" @@ -46,7 +47,7 @@ func GetTxCmd(cdc *codec.Codec) *cobra.Command { RunE: client.ValidateCmd, } - txCmd.AddCommand(client.PostCommands( + txCmd.AddCommand(flags.PostCommands( GetCmdInvariantBroken(cdc), )...) return txCmd diff --git a/x/distribution/client/cli/query.go b/x/distribution/client/cli/query.go index 6b8457a3d730..dff8e5e06a5d 100644 --- a/x/distribution/client/cli/query.go +++ b/x/distribution/client/cli/query.go @@ -9,6 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" @@ -26,7 +27,7 @@ func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { RunE: client.ValidateCmd, } - distQueryCmd.AddCommand(client.GetCommands( + distQueryCmd.AddCommand(flags.GetCommands( GetCmdQueryParams(queryRoute, cdc), GetCmdQueryValidatorOutstandingRewards(queryRoute, cdc), GetCmdQueryValidatorCommission(queryRoute, cdc), diff --git a/x/distribution/client/cli/tx.go b/x/distribution/client/cli/tx.go index 281373267fa5..6eaee60992b6 100644 --- a/x/distribution/client/cli/tx.go +++ b/x/distribution/client/cli/tx.go @@ -11,6 +11,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" @@ -43,7 +44,7 @@ func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { RunE: client.ValidateCmd, } - distTxCmd.AddCommand(client.PostCommands( + distTxCmd.AddCommand(flags.PostCommands( GetCmdWithdrawRewards(cdc), GetCmdSetWithdrawAddr(cdc), GetCmdWithdrawAllRewards(cdc, storeKey), @@ -150,7 +151,7 @@ $ %s tx distribution withdraw-all-rewards --from mykey // The transaction cannot be generated offline since it requires a query // to get all the validators. if cliCtx.GenerateOnly { - return fmt.Errorf("command disabled with the provided flag: %s", client.FlagGenerateOnly) + return fmt.Errorf("command disabled with the provided flag: %s", flags.FlagGenerateOnly) } msgs, err := common.WithdrawAllDelegatorRewards(cliCtx, queryRoute, delAddr) diff --git a/x/evidence/client/cli/query.go b/x/evidence/client/cli/query.go index 4c5eb13abaf1..b4a1dffd0af5 100644 --- a/x/evidence/client/cli/query.go +++ b/x/evidence/client/cli/query.go @@ -10,6 +10,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/x/evidence/exported" @@ -46,9 +47,9 @@ $ %s query %s --page=2 --limit=50 cmd.Flags().Int(flagPage, 1, "pagination page of evidence to to query for") cmd.Flags().Int(flagLimit, 100, "pagination limit of evidence to query for") - cmd.AddCommand(client.GetCommands(QueryParamsCmd(cdc))...) + cmd.AddCommand(flags.GetCommands(QueryParamsCmd(cdc))...) - return client.GetCommands(cmd)[0] + return flags.GetCommands(cmd)[0] } // QueryParamsCmd returns the command handler for evidence parameter querying. diff --git a/x/evidence/client/cli/tx.go b/x/evidence/client/cli/tx.go index 7cf6c5f6eadb..b97b56c0a23d 100644 --- a/x/evidence/client/cli/tx.go +++ b/x/evidence/client/cli/tx.go @@ -2,6 +2,7 @@ package cli import ( "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/x/evidence/internal/types" @@ -24,7 +25,7 @@ func GetTxCmd(storeKey string, cdc *codec.Codec, childCmds []*cobra.Command) *co submitEvidenceCmd := SubmitEvidenceCmd(cdc) for _, childCmd := range childCmds { - submitEvidenceCmd.AddCommand(client.PostCommands(childCmd)[0]) + submitEvidenceCmd.AddCommand(flags.PostCommands(childCmd)[0]) } // TODO: Add tx commands. diff --git a/x/genutil/client/cli/collect.go b/x/genutil/client/cli/collect.go index fe1c864eca9f..bc38ab74d287 100644 --- a/x/genutil/client/cli/collect.go +++ b/x/genutil/client/cli/collect.go @@ -10,7 +10,7 @@ import ( "github.com/tendermint/tendermint/libs/cli" tmtypes "github.com/tendermint/tendermint/types" - "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/server" "github.com/cosmos/cosmos-sdk/x/genutil" @@ -29,7 +29,7 @@ func CollectGenTxsCmd(ctx *server.Context, cdc *codec.Codec, RunE: func(_ *cobra.Command, _ []string) error { config := ctx.Config config.SetRoot(viper.GetString(cli.HomeFlag)) - name := viper.GetString(client.FlagName) + name := viper.GetString(flags.FlagName) nodeID, valPubKey, err := genutil.InitializeNodeValidatorFiles(config) if err != nil { return errors.Wrap(err, "failed to initialize node validator files") diff --git a/x/genutil/client/cli/gentx.go b/x/genutil/client/cli/gentx.go index ebfdded23a96..aae33d6b8b7c 100644 --- a/x/genutil/client/cli/gentx.go +++ b/x/genutil/client/cli/gentx.go @@ -21,9 +21,9 @@ import ( "github.com/tendermint/tendermint/libs/common" tmtypes "github.com/tendermint/tendermint/types" - "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/keys" "github.com/cosmos/cosmos-sdk/codec" kbkeys "github.com/cosmos/cosmos-sdk/crypto/keys" "github.com/cosmos/cosmos-sdk/server" @@ -64,7 +64,7 @@ func GenTxCmd(ctx *server.Context, cdc *codec.Codec, mbm module.BasicManager, sm RunE: func(cmd *cobra.Command, args []string) error { config := ctx.Config - config.SetRoot(viper.GetString(client.FlagHome)) + config.SetRoot(viper.GetString(flags.FlagHome)) nodeID, valPubKey, err := genutil.InitializeNodeValidatorFiles(ctx.Config) if err != nil { return errors.Wrap(err, "failed to initialize node validator files") @@ -97,19 +97,19 @@ func GenTxCmd(ctx *server.Context, cdc *codec.Codec, mbm module.BasicManager, sm } inBuf := bufio.NewReader(cmd.InOrStdin()) - kb, err := client.NewKeyringFromDir(viper.GetString(flagClientHome), inBuf) + kb, err := keys.NewKeyringFromDir(viper.GetString(flagClientHome), inBuf) if err != nil { return errors.Wrap(err, "failed to initialize keybase") } - name := viper.GetString(client.FlagName) + name := viper.GetString(flags.FlagName) key, err := kb.Get(name) if err != nil { return errors.Wrap(err, "failed to read from keybase") } // Set flags for creating gentx - viper.Set(client.FlagHome, viper.GetString(flagClientHome)) + viper.Set(flags.FlagHome, viper.GetString(flagClientHome)) smbh.PrepareFlagsForTxCreateValidator(config, nodeID, genDoc.ChainID, valPubKey) // Fetch the amount of coins staked @@ -125,14 +125,14 @@ func GenTxCmd(ctx *server.Context, cdc *codec.Codec, mbm module.BasicManager, sm } txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc)) - cliCtx := client.NewCLIContextWithInput(inBuf).WithCodec(cdc) + cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) // Set the generate-only flag here after the CLI context has // been created. This allows the from name/key to be correctly populated. // // TODO: Consider removing the manual setting of generate-only in // favor of a 'gentx' flag in the create-validator command. - viper.Set(client.FlagGenerateOnly, true) + viper.Set(flags.FlagGenerateOnly, true) // create a 'create-validator' message txBldr, msg, err := smbh.BuildCreateValidatorMsg(cliCtx, txBldr) @@ -166,7 +166,7 @@ func GenTxCmd(ctx *server.Context, cdc *codec.Codec, mbm module.BasicManager, sm } // Fetch output file name - outputDocument := viper.GetString(client.FlagOutputDocument) + outputDocument := viper.GetString(flags.FlagOutputDocument) if outputDocument == "" { outputDocument, err = makeOutputFilepath(config.RootDir, nodeID) if err != nil { @@ -184,16 +184,16 @@ func GenTxCmd(ctx *server.Context, cdc *codec.Codec, mbm module.BasicManager, sm }, } - cmd.Flags().String(client.FlagHome, defaultNodeHome, "node's home directory") + cmd.Flags().String(flags.FlagHome, defaultNodeHome, "node's home directory") cmd.Flags().String(flagClientHome, defaultCLIHome, "client's home directory") - cmd.Flags().String(client.FlagName, "", "name of private key with which to sign the gentx") - cmd.Flags().String(client.FlagOutputDocument, "", + cmd.Flags().String(flags.FlagName, "", "name of private key with which to sign the gentx") + cmd.Flags().String(flags.FlagOutputDocument, "", "write the genesis transaction JSON document to the given file instead of the default location") cmd.Flags().AddFlagSet(fsCreateValidator) - cmd.Flags().String(client.FlagKeyringBackend, client.DefaultKeyringBackend, "Select keyring's backend (os|file|test)") + cmd.Flags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|test)") viper.BindPFlag(flags.FlagKeyringBackend, cmd.Flags().Lookup(flags.FlagKeyringBackend)) - cmd.MarkFlagRequired(client.FlagName) + cmd.MarkFlagRequired(flags.FlagName) return cmd } diff --git a/x/genutil/client/cli/init.go b/x/genutil/client/cli/init.go index aed60d17f839..c611556ae8f1 100644 --- a/x/genutil/client/cli/init.go +++ b/x/genutil/client/cli/init.go @@ -14,7 +14,7 @@ import ( "github.com/tendermint/tendermint/libs/common" "github.com/tendermint/tendermint/types" - "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/server" sdk "github.com/cosmos/cosmos-sdk/types" @@ -70,7 +70,7 @@ func InitCmd(ctx *server.Context, cdc *codec.Codec, mbm module.BasicManager, config := ctx.Config config.SetRoot(viper.GetString(cli.HomeFlag)) - chainID := viper.GetString(client.FlagChainID) + chainID := viper.GetString(flags.FlagChainID) if chainID == "" { chainID = fmt.Sprintf("test-chain-%v", common.RandStr(6)) } @@ -119,7 +119,7 @@ func InitCmd(ctx *server.Context, cdc *codec.Codec, mbm module.BasicManager, cmd.Flags().String(cli.HomeFlag, defaultNodeHome, "node's home directory") cmd.Flags().BoolP(flagOverwrite, "o", false, "overwrite the genesis.json file") - cmd.Flags().String(client.FlagChainID, "", "genesis file chain-id, if left blank will be randomly created") + cmd.Flags().String(flags.FlagChainID, "", "genesis file chain-id, if left blank will be randomly created") return cmd } diff --git a/x/genutil/client/cli/init_test.go b/x/genutil/client/cli/init_test.go index 540e57cfb5f2..6ab1ef208abe 100644 --- a/x/genutil/client/cli/init_test.go +++ b/x/genutil/client/cli/init_test.go @@ -14,7 +14,7 @@ import ( "github.com/tendermint/tendermint/libs/cli" "github.com/tendermint/tendermint/libs/log" - "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/server" "github.com/cosmos/cosmos-sdk/server/mock" @@ -126,7 +126,7 @@ func TestInitNodeValidatorFiles(t *testing.T) { home, cleanup := tests.NewTestCaseDir(t) defer cleanup() viper.Set(cli.HomeFlag, home) - viper.Set(client.FlagName, "moniker") + viper.Set(flags.FlagName, "moniker") cfg, err := tcmd.ParseConfig() require.Nil(t, err) nodeID, valPubKey, err := genutil.InitializeNodeValidatorFiles(cfg) diff --git a/x/genutil/client/cli/migrate_test.go b/x/genutil/client/cli/migrate_test.go index fca36a4dfc28..423629efcb13 100644 --- a/x/genutil/client/cli/migrate_test.go +++ b/x/genutil/client/cli/migrate_test.go @@ -12,7 +12,7 @@ import ( "github.com/tendermint/tendermint/libs/cli" "github.com/tendermint/tendermint/libs/log" - "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/server" "github.com/cosmos/cosmos-sdk/tests" ) @@ -39,7 +39,7 @@ func TestGetMigrationCallback(t *testing.T) { func TestMigrateGenesis(t *testing.T) { home, cleanup := tests.NewTestCaseDir(t) viper.Set(cli.HomeFlag, home) - viper.Set(client.FlagName, "moniker") + viper.Set(flags.FlagName, "moniker") logger := log.NewNopLogger() cfg, err := tcmd.ParseConfig() require.Nil(t, err) diff --git a/x/gov/client/cli/query.go b/x/gov/client/cli/query.go index 69f89e7a7d05..332fe0d89cd3 100644 --- a/x/gov/client/cli/query.go +++ b/x/gov/client/cli/query.go @@ -10,6 +10,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" @@ -29,7 +30,7 @@ func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { RunE: client.ValidateCmd, } - govQueryCmd.AddCommand(client.GetCommands( + govQueryCmd.AddCommand(flags.GetCommands( GetCmdQueryProposal(queryRoute, cdc), GetCmdQueryProposals(queryRoute, cdc), GetCmdQueryVote(queryRoute, cdc), diff --git a/x/gov/client/cli/tx.go b/x/gov/client/cli/tx.go index 4bd49a610e95..8c6c1109c9d4 100644 --- a/x/gov/client/cli/tx.go +++ b/x/gov/client/cli/tx.go @@ -10,6 +10,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" @@ -66,10 +67,10 @@ func GetTxCmd(storeKey string, cdc *codec.Codec, pcmds []*cobra.Command) *cobra. cmdSubmitProp := GetCmdSubmitProposal(cdc) for _, pcmd := range pcmds { - cmdSubmitProp.AddCommand(client.PostCommands(pcmd)[0]) + cmdSubmitProp.AddCommand(flags.PostCommands(pcmd)[0]) } - govTxCmd.AddCommand(client.PostCommands( + govTxCmd.AddCommand(flags.PostCommands( GetCmdDeposit(cdc), GetCmdVote(cdc), cmdSubmitProp, diff --git a/x/mint/client/cli/query.go b/x/mint/client/cli/query.go index 3350706362f3..ec37cde40cf6 100644 --- a/x/mint/client/cli/query.go +++ b/x/mint/client/cli/query.go @@ -7,6 +7,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/mint/internal/types" @@ -23,7 +24,7 @@ func GetQueryCmd(cdc *codec.Codec) *cobra.Command { } mintingQueryCmd.AddCommand( - client.GetCommands( + flags.GetCommands( GetCmdQueryParams(cdc), GetCmdQueryInflation(cdc), GetCmdQueryAnnualProvisions(cdc), diff --git a/x/slashing/client/cli/query.go b/x/slashing/client/cli/query.go index 836d2bcb1f3d..a5b0cd1be524 100644 --- a/x/slashing/client/cli/query.go +++ b/x/slashing/client/cli/query.go @@ -8,6 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" @@ -26,7 +27,7 @@ func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { } slashingQueryCmd.AddCommand( - client.GetCommands( + flags.GetCommands( GetCmdQuerySigningInfo(queryRoute, cdc), GetCmdQueryParams(cdc), )..., diff --git a/x/slashing/client/cli/tx.go b/x/slashing/client/cli/tx.go index e6bb0b44e9b8..5aa262568d54 100644 --- a/x/slashing/client/cli/tx.go +++ b/x/slashing/client/cli/tx.go @@ -7,6 +7,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" @@ -24,7 +25,7 @@ func GetTxCmd(cdc *codec.Codec) *cobra.Command { RunE: client.ValidateCmd, } - slashingTxCmd.AddCommand(client.PostCommands( + slashingTxCmd.AddCommand(flags.PostCommands( GetCmdUnjail(cdc), )...) diff --git a/x/staking/client/cli/query.go b/x/staking/client/cli/query.go index 632237c1d915..14a60c49bc04 100644 --- a/x/staking/client/cli/query.go +++ b/x/staking/client/cli/query.go @@ -9,6 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" @@ -24,7 +25,7 @@ func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { SuggestionsMinimumDistance: 2, RunE: client.ValidateCmd, } - stakingQueryCmd.AddCommand(client.GetCommands( + stakingQueryCmd.AddCommand(flags.GetCommands( GetCmdQueryDelegation(queryRoute, cdc), GetCmdQueryDelegations(queryRoute, cdc), GetCmdQueryUnbondingDelegation(queryRoute, cdc), diff --git a/x/staking/client/cli/tx.go b/x/staking/client/cli/tx.go index 5898a25933f1..34ed0abce3c7 100644 --- a/x/staking/client/cli/tx.go +++ b/x/staking/client/cli/tx.go @@ -15,6 +15,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" @@ -33,7 +34,7 @@ func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { RunE: client.ValidateCmd, } - stakingTxCmd.AddCommand(client.PostCommands( + stakingTxCmd.AddCommand(flags.PostCommands( GetCmdCreateValidator(cdc), GetCmdEditValidator(cdc), GetCmdDelegate(cdc), @@ -69,10 +70,10 @@ func GetCmdCreateValidator(cdc *codec.Codec) *cobra.Command { cmd.Flags().AddFlagSet(FsCommissionCreate) cmd.Flags().AddFlagSet(FsMinSelfDelegation) - cmd.Flags().String(FlagIP, "", fmt.Sprintf("The node's public IP. It takes effect only when used in combination with --%s", client.FlagGenerateOnly)) + cmd.Flags().String(FlagIP, "", fmt.Sprintf("The node's public IP. It takes effect only when used in combination with --%s", flags.FlagGenerateOnly)) cmd.Flags().String(FlagNodeID, "", "The node's ID") - cmd.MarkFlagRequired(client.FlagFrom) + cmd.MarkFlagRequired(flags.FlagFrom) cmd.MarkFlagRequired(FlagAmount) cmd.MarkFlagRequired(FlagPubKey) cmd.MarkFlagRequired(FlagMoniker) @@ -309,8 +310,8 @@ func PrepareFlagsForTxCreateValidator( details := viper.GetString(FlagDetails) identity := viper.GetString(FlagIdentity) - viper.Set(client.FlagChainID, chainID) - viper.Set(client.FlagFrom, viper.GetString(client.FlagName)) + viper.Set(flags.FlagChainID, chainID) + viper.Set(flags.FlagFrom, viper.GetString(flags.FlagName)) viper.Set(FlagNodeID, nodeID) viper.Set(FlagIP, ip) viper.Set(FlagPubKey, sdk.MustBech32ifyConsPub(valPubKey)) @@ -321,7 +322,7 @@ func PrepareFlagsForTxCreateValidator( viper.Set(FlagIdentity, identity) if config.Moniker == "" { - viper.Set(FlagMoniker, viper.GetString(client.FlagName)) + viper.Set(FlagMoniker, viper.GetString(flags.FlagName)) } if viper.GetString(FlagAmount) == "" { viper.Set(FlagAmount, defaultAmount) @@ -384,7 +385,7 @@ func BuildCreateValidatorMsg(cliCtx context.CLIContext, txBldr auth.TxBuilder) ( sdk.ValAddress(valAddr), pk, amount, description, commissionRates, minSelfDelegation, ) - if viper.GetBool(client.FlagGenerateOnly) { + if viper.GetBool(flags.FlagGenerateOnly) { ip := viper.GetString(FlagIP) nodeID := viper.GetString(FlagNodeID) if nodeID != "" && ip != "" { diff --git a/x/supply/client/cli/query.go b/x/supply/client/cli/query.go index 009f2f7df983..26c4a77cd506 100644 --- a/x/supply/client/cli/query.go +++ b/x/supply/client/cli/query.go @@ -8,6 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" @@ -25,7 +26,7 @@ func GetQueryCmd(cdc *codec.Codec) *cobra.Command { RunE: client.ValidateCmd, } - supplyQueryCmd.AddCommand(client.GetCommands( + supplyQueryCmd.AddCommand(flags.GetCommands( GetCmdQueryTotalSupply(cdc), )...) diff --git a/x/upgrade/module.go b/x/upgrade/module.go index a365cd1a36c2..129cc904bf10 100644 --- a/x/upgrade/module.go +++ b/x/upgrade/module.go @@ -6,8 +6,8 @@ import ( "github.com/gorilla/mux" "github.com/spf13/cobra" - "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" @@ -52,7 +52,7 @@ func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command { Use: "upgrade", Short: "Querying commands for the upgrade module", } - queryCmd.AddCommand(client.GetCommands( + queryCmd.AddCommand(flags.GetCommands( cli.GetPlanCmd(StoreKey, cdc), cli.GetAppliedHeightCmd(StoreKey, cdc), )...) @@ -66,7 +66,7 @@ func (AppModuleBasic) GetTxCmd(cdc *codec.Codec) *cobra.Command { Use: "upgrade", Short: "Upgrade transaction subcommands", } - txCmd.AddCommand(client.PostCommands()...) + txCmd.AddCommand(flags.PostCommands()...) return txCmd } From 5188c3565ba6c70238eddd8a5c84a0bed73bd1ee Mon Sep 17 00:00:00 2001 From: Dmitry Shulyak Date: Tue, 24 Dec 2019 19:04:36 +0200 Subject: [PATCH 048/529] Merge PR #5445: Mock rpcclient in tests for votes pagination --- x/gov/client/cli/query.go | 3 +- x/gov/client/rest/query.go | 3 +- x/gov/client/utils/query.go | 13 ++-- x/gov/client/utils/query_test.go | 118 +++++++++++++++++++------------ 4 files changed, 79 insertions(+), 58 deletions(-) diff --git a/x/gov/client/cli/query.go b/x/gov/client/cli/query.go index 332fe0d89cd3..1a0c0a179ef7 100644 --- a/x/gov/client/cli/query.go +++ b/x/gov/client/cli/query.go @@ -14,7 +14,6 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" - "github.com/cosmos/cosmos-sdk/x/auth/client/utils" gcutils "github.com/cosmos/cosmos-sdk/x/gov/client/utils" "github.com/cosmos/cosmos-sdk/x/gov/types" ) @@ -286,7 +285,7 @@ $ %[1]s query gov votes 1 --page=2 --limit=100 propStatus := proposal.Status if !(propStatus == types.StatusVotingPeriod || propStatus == types.StatusDepositPeriod) { - res, err = gcutils.QueryVotesByTxQuery(cliCtx, params, utils.QueryTxsByEvents) + res, err = gcutils.QueryVotesByTxQuery(cliCtx, params) } else { res, _, err = cliCtx.QueryWithData(fmt.Sprintf("custom/%s/votes", queryRoute), bz) } diff --git a/x/gov/client/rest/query.go b/x/gov/client/rest/query.go index de9ccf379dd5..3eb5800d7a99 100644 --- a/x/gov/client/rest/query.go +++ b/x/gov/client/rest/query.go @@ -10,7 +10,6 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/rest" - "github.com/cosmos/cosmos-sdk/x/auth/client/utils" gcutils "github.com/cosmos/cosmos-sdk/x/gov/client/utils" "github.com/cosmos/cosmos-sdk/x/gov/types" ) @@ -382,7 +381,7 @@ func queryVotesOnProposalHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { // as they're no longer in state. propStatus := proposal.Status if !(propStatus == types.StatusVotingPeriod || propStatus == types.StatusDepositPeriod) { - res, err = gcutils.QueryVotesByTxQuery(cliCtx, params, utils.QueryTxsByEvents) + res, err = gcutils.QueryVotesByTxQuery(cliCtx, params) } else { res, _, err = cliCtx.QueryWithData("custom/gov/votes", bz) } diff --git a/x/gov/client/utils/query.go b/x/gov/client/utils/query.go index 2eaf2c5a7a78..d4be3c010f93 100644 --- a/x/gov/client/utils/query.go +++ b/x/gov/client/utils/query.go @@ -73,15 +73,10 @@ func QueryDepositsByTxQuery(cliCtx context.CLIContext, params types.QueryProposa return cliCtx.Codec.MarshalJSON(deposits) } -// TxQuerier is a type that accepts query parameters (target events and pagination options) and returns sdk.SearchTxsResult. -// Mainly used for easier mocking of utils.QueryTxsByEvents in tests. -type TxQuerier func(cliCtx context.CLIContext, events []string, page, limit int) (*sdk.SearchTxsResult, error) - -// QueryVotesByTxQuery will query for votes using provided TxQuerier implementation. -// In general utils.QueryTxsByEvents should be used that will do a direct tx query to a tendermint node. -// It will fetch and build votes directly from the returned txs and return a JSON +// QueryVotesByTxQuery will query for votes via a direct txs tags query. It +// will fetch and build votes directly from the returned txs and return a JSON // marshalled result or any error that occurred. -func QueryVotesByTxQuery(cliCtx context.CLIContext, params types.QueryProposalVotesParams, querier TxQuerier) ([]byte, error) { +func QueryVotesByTxQuery(cliCtx context.CLIContext, params types.QueryProposalVotesParams) ([]byte, error) { var ( events = []string{ fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, types.TypeMsgVote), @@ -93,7 +88,7 @@ func QueryVotesByTxQuery(cliCtx context.CLIContext, params types.QueryProposalVo ) // query interrupted either if we collected enough votes or tx indexer run out of relevant txs for len(votes) < totalLimit { - searchResult, err := querier(cliCtx, events, nextTxPage, defaultLimit) + searchResult, err := utils.QueryTxsByEvents(cliCtx, events, nextTxPage, defaultLimit) if err != nil { return nil, err } diff --git a/x/gov/client/utils/query_test.go b/x/gov/client/utils/query_test.go index ce9b548b93bb..68762b248066 100644 --- a/x/gov/client/utils/query_test.go +++ b/x/gov/client/utils/query_test.go @@ -7,72 +7,87 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/rpc/client/mock" + ctypes "github.com/tendermint/tendermint/rpc/core/types" + tmtypes "github.com/tendermint/tendermint/types" ) -type txMock struct { - address sdk.AccAddress - msgNum int +type TxSearchMock struct { + mock.Client + txs []tmtypes.Tx } -func (tx txMock) ValidateBasic() sdk.Error { - return nil +func (mock TxSearchMock) TxSearch(query string, prove bool, page, perPage int) (*ctypes.ResultTxSearch, error) { + start, end := client.Paginate(len(mock.txs), page, perPage, 100) + if start < 0 || end < 0 { + // nil result with nil error crashes utils.QueryTxsByEvents + return &ctypes.ResultTxSearch{}, nil + } + txs := mock.txs[start:end] + rst := &ctypes.ResultTxSearch{Txs: make([]*ctypes.ResultTx, len(txs)), TotalCount: len(txs)} + for i := range txs { + rst.Txs[i] = &ctypes.ResultTx{Tx: txs[i]} + } + return rst, nil } -func (tx txMock) GetMsgs() (msgs []sdk.Msg) { - for i := 0; i < tx.msgNum; i++ { - msgs = append(msgs, types.NewMsgVote(tx.address, 0, types.OptionYes)) - } - return +func (mock TxSearchMock) Block(height *int64) (*ctypes.ResultBlock, error) { + // any non nil Block needs to be returned. used to get time value + return &ctypes.ResultBlock{Block: &tmtypes.Block{}}, nil } -func makeQuerier(txs []sdk.Tx) TxQuerier { - return func(cliCtx context.CLIContext, events []string, page, limit int) (*sdk.SearchTxsResult, error) { - start, end := client.Paginate(len(txs), page, limit, 100) - if start < 0 || end < 0 { - return nil, nil - } - rst := &sdk.SearchTxsResult{ - TotalCount: len(txs), - PageNumber: page, - PageTotal: len(txs) / limit, - Limit: limit, - Count: end - start, - } - for _, tx := range txs[start:end] { - rst.Txs = append(rst.Txs, sdk.TxResponse{Tx: tx}) - } - return rst, nil - } +func newTestCodec() *codec.Codec { + cdc := codec.New() + sdk.RegisterCodec(cdc) + types.RegisterCodec(cdc) + authtypes.RegisterCodec(cdc) + return cdc } func TestGetPaginatedVotes(t *testing.T) { type testCase struct { description string page, limit int - txs []sdk.Tx + txs []authtypes.StdTx votes []types.Vote } acc1 := make(sdk.AccAddress, 20) acc1[0] = 1 acc2 := make(sdk.AccAddress, 20) acc2[0] = 2 + acc1Msgs := []sdk.Msg{ + types.NewMsgVote(acc1, 0, types.OptionYes), + types.NewMsgVote(acc1, 0, types.OptionYes), + } + acc2Msgs := []sdk.Msg{ + types.NewMsgVote(acc2, 0, types.OptionYes), + types.NewMsgVote(acc2, 0, types.OptionYes), + } for _, tc := range []testCase{ { description: "1MsgPerTxAll", page: 1, limit: 2, - txs: []sdk.Tx{txMock{acc1, 1}, txMock{acc2, 1}}, + txs: []authtypes.StdTx{ + {Msgs: acc1Msgs[:1]}, + {Msgs: acc2Msgs[:1]}, + }, votes: []types.Vote{ types.NewVote(0, acc1, types.OptionYes), types.NewVote(0, acc2, types.OptionYes)}, }, + { description: "2MsgPerTx1Chunk", page: 1, limit: 2, - txs: []sdk.Tx{txMock{acc1, 2}, txMock{acc2, 2}}, + txs: []authtypes.StdTx{ + {Msgs: acc1Msgs}, + {Msgs: acc2Msgs}, + }, votes: []types.Vote{ types.NewVote(0, acc1, types.OptionYes), types.NewVote(0, acc1, types.OptionYes)}, @@ -81,7 +96,10 @@ func TestGetPaginatedVotes(t *testing.T) { description: "2MsgPerTx2Chunk", page: 2, limit: 2, - txs: []sdk.Tx{txMock{acc1, 2}, txMock{acc2, 2}}, + txs: []authtypes.StdTx{ + {Msgs: acc1Msgs}, + {Msgs: acc2Msgs}, + }, votes: []types.Vote{ types.NewVote(0, acc2, types.OptionYes), types.NewVote(0, acc2, types.OptionYes)}, @@ -90,33 +108,43 @@ func TestGetPaginatedVotes(t *testing.T) { description: "IncompleteSearchTx", page: 1, limit: 2, - txs: []sdk.Tx{txMock{acc1, 1}}, - votes: []types.Vote{types.NewVote(0, acc1, types.OptionYes)}, - }, - { - description: "IncompleteSearchTx", - page: 1, - limit: 2, - txs: []sdk.Tx{txMock{acc1, 1}}, - votes: []types.Vote{types.NewVote(0, acc1, types.OptionYes)}, + txs: []authtypes.StdTx{ + {Msgs: acc1Msgs[:1]}, + }, + votes: []types.Vote{types.NewVote(0, acc1, types.OptionYes)}, }, { description: "InvalidPage", page: -1, - txs: []sdk.Tx{txMock{acc1, 1}}, + txs: []authtypes.StdTx{ + {Msgs: acc1Msgs[:1]}, + }, }, { description: "OutOfBounds", page: 2, limit: 10, - txs: []sdk.Tx{txMock{acc1, 1}}, + txs: []authtypes.StdTx{ + {Msgs: acc1Msgs[:1]}, + }, }, } { tc := tc t.Run(tc.description, func(t *testing.T) { - ctx := context.CLIContext{}.WithCodec(codec.New()) + var ( + marshalled = make([]tmtypes.Tx, len(tc.txs)) + cdc = newTestCodec() + ) + for i := range tc.txs { + tx, err := cdc.MarshalBinaryLengthPrefixed(&tc.txs[i]) + require.NoError(t, err) + marshalled[i] = tmtypes.Tx(tx) + } + client := TxSearchMock{txs: marshalled} + ctx := context.CLIContext{}.WithCodec(cdc).WithTrustNode(true).WithClient(client) + params := types.NewQueryProposalVotesParams(0, tc.page, tc.limit) - votesData, err := QueryVotesByTxQuery(ctx, params, makeQuerier(tc.txs)) + votesData, err := QueryVotesByTxQuery(ctx, params) require.NoError(t, err) votes := []types.Vote{} require.NoError(t, ctx.Codec.UnmarshalJSON(votesData, &votes)) From b314b851e4300e30a22c9e3fd9b5e2602e7c4e92 Mon Sep 17 00:00:00 2001 From: Dmitry Shulyak Date: Thu, 26 Dec 2019 17:33:34 +0200 Subject: [PATCH 049/529] Merge PR #5435: Added iterator that allows to read only requested values --- CHANGELOG.md | 3 + store/types/iterator.go | 61 ++++++++++++++++++ store/types/iterator_test.go | 119 +++++++++++++++++++++++++++++++++++ types/store.go | 12 ++++ 4 files changed, 195 insertions(+) create mode 100644 store/types/iterator.go create mode 100644 store/types/iterator_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index e7b2bd071eb8..ef0b35e5206d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -93,6 +93,7 @@ increased significantly due to modular `AnteHandler` support. Increase GasLimit ### Features +* (store) [\#5435](https://github.com/cosmos/cosmos-sdk/pull/5435) New iterator for paginated requests. Iterator limits DB reads to the range of the requested page. * (x/evidence) [\#5240](https://github.com/cosmos/cosmos-sdk/pull/5240) Initial implementation of the `x/evidence` module. * (cli) [\#5212](https://github.com/cosmos/cosmos-sdk/issues/5212) The `q gov proposals` command now supports pagination. * (store) [\#4724](https://github.com/cosmos/cosmos-sdk/issues/4724) Multistore supports substore migrations upon load. New `rootmulti.Store.LoadLatestVersionAndUpgrade` method in @@ -2804,3 +2805,5 @@ BUG FIXES: [v0.37.1]: https://github.com/cosmos/cosmos-sdk/releases/tag/v0.37.1 [v0.37.0]: https://github.com/cosmos/cosmos-sdk/releases/tag/v0.37.0 [v0.36.0]: https://github.com/cosmos/cosmos-sdk/releases/tag/v0.36.0 + + diff --git a/store/types/iterator.go b/store/types/iterator.go new file mode 100644 index 000000000000..cfce4124e397 --- /dev/null +++ b/store/types/iterator.go @@ -0,0 +1,61 @@ +package types + +import ( + "fmt" +) + +// KVStorePrefixIteratorPaginated returns iterator over items in the selected page. +// Items iterated and skipped in ascending order. +func KVStorePrefixIteratorPaginated(kvs KVStore, prefix []byte, page, limit uint) Iterator { + pi := &PaginatedIterator{ + Iterator: KVStorePrefixIterator(kvs, prefix), + page: page, + limit: limit, + } + pi.skip() + return pi +} + +// KVStoreReversePrefixIteratorPaginated returns iterator over items in the selected page. +// Items iterated and skipped in descending order. +func KVStoreReversePrefixIteratorPaginated(kvs KVStore, prefix []byte, page, limit uint) Iterator { + pi := &PaginatedIterator{ + Iterator: KVStoreReversePrefixIterator(kvs, prefix), + page: page, + limit: limit, + } + pi.skip() + return pi +} + +// PaginatedIterator is a wrapper around Iterator that iterates over values starting for given page and limit. +type PaginatedIterator struct { + Iterator + + page, limit uint // provided during initialization + iterated uint // incremented in a call to Next + +} + +func (pi *PaginatedIterator) skip() { + for i := (pi.page - 1) * pi.limit; i > 0 && pi.Iterator.Valid(); i-- { + pi.Iterator.Next() + } +} + +// Next will panic after limit is reached. +func (pi *PaginatedIterator) Next() { + if !pi.Valid() { + panic(fmt.Sprintf("PaginatedIterator reached limit %d", pi.limit)) + } + pi.Iterator.Next() + pi.iterated++ +} + +// Valid if below limit and underlying iterator is valid. +func (pi *PaginatedIterator) Valid() bool { + if pi.iterated >= pi.limit { + return false + } + return pi.Iterator.Valid() +} diff --git a/store/types/iterator_test.go b/store/types/iterator_test.go new file mode 100644 index 000000000000..e081de80a3d5 --- /dev/null +++ b/store/types/iterator_test.go @@ -0,0 +1,119 @@ +package types_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + dbm "github.com/tendermint/tm-db" + + "github.com/cosmos/cosmos-sdk/store/iavl" + "github.com/cosmos/cosmos-sdk/store/types" +) + +func newMemTestKVStore(t *testing.T) types.KVStore { + db := dbm.NewMemDB() + store, err := iavl.LoadStore(db, types.CommitID{}, types.PruneNothing, false) + require.NoError(t, err) + return store +} + +func TestPaginatedIterator(t *testing.T) { + kvs := newMemTestKVStore(t) + total := 10 + lth := total - 1 + asc := make([][]byte, total) + desc := make([][]byte, total) + // store returns values in lexicographic order (or reverse lex order) + for i := 0; i < total; i++ { + key := []byte{byte(i)} + kvs.Set(key, key) + asc[i] = key + desc[lth-i] = key + } + type testCase struct { + desc string + page, limit uint + result [][]byte + reverse bool + } + for _, tc := range []testCase{ + { + desc: "FirstChunk", + page: 1, + limit: 4, + result: asc[:4], + }, + { + desc: "SecondChunk", + page: 2, + limit: 4, + result: asc[4:8], + }, + { + desc: "ThirdChunkHalf", + page: 3, + limit: 4, + result: asc[8:], + }, + { + desc: "OverLimit", + page: 10, + limit: 10, + result: [][]byte{}, + }, + { + desc: "ZeroLimit", + page: 1, + result: [][]byte{}, + }, + { + desc: "ReverseFirstChunk", + page: 1, + limit: 6, + result: desc[:6], + reverse: true, + }, + { + desc: "ReverseSecondChunk", + page: 2, + limit: 6, + result: desc[6:], + reverse: true, + }, + } { + tc := tc + t.Run(tc.desc, func(t *testing.T) { + var iter types.Iterator + if tc.reverse { + iter = types.KVStoreReversePrefixIteratorPaginated(kvs, nil, tc.page, tc.limit) + } else { + iter = types.KVStorePrefixIteratorPaginated(kvs, nil, tc.page, tc.limit) + } + defer iter.Close() + + result := [][]byte{} + for ; iter.Valid(); iter.Next() { + result = append(result, iter.Key()) + } + + require.Equal(t, tc.result, result) + require.False(t, iter.Valid()) + }) + } +} + +func TestPaginatedIteratorPanicIfInvalid(t *testing.T) { + kvs := newMemTestKVStore(t) + + iter := types.KVStorePrefixIteratorPaginated(kvs, nil, 1, 1) + defer iter.Close() + require.False(t, iter.Valid()) + require.Panics(t, func() { iter.Next() }) // "iterator is empty" + + kvs.Set([]byte{1}, []byte{}) + + iter = types.KVStorePrefixIteratorPaginated(kvs, nil, 1, 0) + defer iter.Close() + require.False(t, iter.Valid()) + require.Panics(t, func() { iter.Next() }) // "not empty but limit is zero" +} diff --git a/types/store.go b/types/store.go index c34b6d437d09..1c50444c0efd 100644 --- a/types/store.go +++ b/types/store.go @@ -40,6 +40,18 @@ func KVStoreReversePrefixIterator(kvs KVStore, prefix []byte) Iterator { return types.KVStoreReversePrefixIterator(kvs, prefix) } +// KVStorePrefixIteratorPaginated returns iterator over items in the selected page. +// Items iterated and skipped in ascending order. +func KVStorePrefixIteratorPaginated(kvs KVStore, prefix []byte, page, limit uint) Iterator { + return types.KVStorePrefixIteratorPaginated(kvs, prefix, page, limit) +} + +// KVStoreReversePrefixIteratorPaginated returns iterator over items in the selected page. +// Items iterated and skipped in descending order. +func KVStoreReversePrefixIteratorPaginated(kvs KVStore, prefix []byte, page, limit uint) Iterator { + return types.KVStorePrefixIteratorPaginated(kvs, prefix, page, limit) +} + // DiffKVStores compares two KVstores and returns all the key/value pairs // that differ from one another. It also skips value comparison for a set of provided prefixes func DiffKVStores(a KVStore, b KVStore, prefixesToSkip [][]byte) (kvAs, kvBs []cmn.KVPair) { From 3c82b663476006f772c238d65a11b1fa48e2beeb Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Fri, 27 Dec 2019 16:23:18 +0100 Subject: [PATCH 050/529] Merge PR #5427: Remove code duplication in x/auth/client/cli --- CHANGELOG.md | 1 + client/flags/flags.go | 4 ++ x/auth/client/cli/decode.go | 98 ++++++++++--------------------------- 3 files changed, 32 insertions(+), 71 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ef0b35e5206d..dac02cb50f66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -90,6 +90,7 @@ if the provided arguments are invalid. increased significantly due to modular `AnteHandler` support. Increase GasLimit accordingly. * (rest) [\#5336](https://github.com/cosmos/cosmos-sdk/issues/5336) `MsgEditValidator` uses `description` instead of `Description` as a JSON key. * (keys) [\#5097](https://github.com/cosmos/cosmos-sdk/pull/5097) Due to the keybase -> keyring transition, keys need to be migrated. See `keys migrate` command for more info. +* (x/auth) [\#5424](https://github.com/cosmos/cosmos-sdk/issues/5424) Drop `decode-tx` command from x/auth/client/cli, duplicate of the `decode` command. ### Features diff --git a/client/flags/flags.go b/client/flags/flags.go index 9451500bfc21..d609e26729f6 100644 --- a/client/flags/flags.go +++ b/client/flags/flags.go @@ -84,6 +84,8 @@ func GetCommands(cmds ...*cobra.Command) []*cobra.Command { viper.BindPFlag(FlagNode, c.Flags().Lookup(FlagNode)) c.MarkFlagRequired(FlagChainID) + + c.SetErr(c.ErrOrStderr()) } return cmds } @@ -119,6 +121,8 @@ func PostCommands(cmds ...*cobra.Command) []*cobra.Command { viper.BindPFlag(FlagKeyringBackend, c.Flags().Lookup(FlagKeyringBackend)) c.MarkFlagRequired(FlagChainID) + + c.SetErr(c.ErrOrStderr()) } return cmds } diff --git a/x/auth/client/cli/decode.go b/x/auth/client/cli/decode.go index b27bbaa1c4ee..c9253d8fb4a3 100644 --- a/x/auth/client/cli/decode.go +++ b/x/auth/client/cli/decode.go @@ -1,98 +1,54 @@ package cli import ( - "bytes" "encoding/base64" "encoding/hex" - "encoding/json" - "fmt" "github.com/spf13/cobra" + "github.com/spf13/viper" "github.com/tendermint/go-amino" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/version" - "github.com/cosmos/cosmos-sdk/x/auth/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" ) +const flagHex = "hex" + // GetDecodeCommand returns the decode command to take Amino-serialized bytes // and turn it into a JSONified transaction. func GetDecodeCommand(codec *amino.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "decode [amino-byte-string]", - Short: "Decode an amino-encoded transaction string", + Short: "Decode an amino-encoded transaction string.", Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) (err error) { - cliCtx := context.NewCLIContext().WithCodec(codec) - - txBytes, err := base64.StdEncoding.DecodeString(args[0]) - if err != nil { - return err - } - - var stdTx authtypes.StdTx - err = cliCtx.Codec.UnmarshalBinaryLengthPrefixed(txBytes, &stdTx) - if err != nil { - return err - } - - return cliCtx.PrintOutput(stdTx) - }, + RunE: runDecodeTxString(codec), } + cmd.Flags().BoolP(flagHex, "x", false, "Treat input as hexadecimal instead of base64") return flags.PostCommands(cmd)[0] } -// GetDecodeTxCmd - returns the command to decode a tx from hex or base64 -func GetDecodeTxCmd(cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ - Use: "decode-tx [tx]", - Short: "Decode a tx from hex or base64", - Long: fmt.Sprintf(`Decode a tx from hex, base64. - -Example: - $ %s tx decode-tx TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz - `, version.ClientName), - Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - - txString := args[0] - - // try hex, then base64 - txBytes, err := hex.DecodeString(txString) - if err != nil { - var err2 error - txBytes, err2 = base64.StdEncoding.DecodeString(txString) - if err2 != nil { - return fmt.Errorf(`expected hex or base64. Got errors: - hex: %v, - base64: %v - `, err, err2) - } - } - - var tx = types.StdTx{} - - err = cdc.UnmarshalBinaryLengthPrefixed(txBytes, &tx) - if err != nil { - return err - } - - bz, err := cdc.MarshalJSON(tx) - if err != nil { - return err - } - - buf := bytes.NewBuffer([]byte{}) - if err = json.Indent(buf, bz, "", " "); err != nil { - return err - } - - fmt.Println(buf.String()) - return nil - }, +func runDecodeTxString(codec *amino.Codec) func(cmd *cobra.Command, args []string) (err error) { + return func(cmd *cobra.Command, args []string) (err error) { + cliCtx := context.NewCLIContext().WithCodec(codec).WithOutput(cmd.OutOrStdout()) + var txBytes []byte + + if viper.GetBool(flagHex) { + txBytes, err = hex.DecodeString(args[0]) + } else { + txBytes, err = base64.StdEncoding.DecodeString(args[0]) + } + if err != nil { + return err + } + + var stdTx authtypes.StdTx + err = cliCtx.Codec.UnmarshalBinaryLengthPrefixed(txBytes, &stdTx) + if err != nil { + return err + } + + return cliCtx.PrintOutput(stdTx) } } From 9a183ffbcc0163c8deb71c7fd5f8089a83e58f05 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Fri, 27 Dec 2019 12:57:54 -0500 Subject: [PATCH 051/529] Merge PR #5421: Refactor Error Handling --- CHANGELOG.md | 15 +- baseapp/abci.go | 176 ++++--- baseapp/baseapp.go | 161 +++--- baseapp/baseapp_test.go | 203 +++++--- baseapp/helpers.go | 6 +- baseapp/queryrouter_test.go | 2 +- baseapp/router_test.go | 4 +- client/context/broadcast.go | 7 +- client/context/broadcast_test.go | 11 +- .../adr-015-ibc-packet-receiver.md | 2 +- docs/building-modules/handler.md | 13 +- docs/building-modules/querier.md | 6 +- server/mock/app.go | 12 +- server/mock/tx.go | 7 +- simapp/app.go | 16 +- simapp/test_helpers.go | 20 +- store/errors/errors.go | 26 - store/iavl/store.go | 9 +- store/iavl/store_test.go | 21 +- store/rootmulti/store.go | 21 +- store/rootmulti/store_test.go | 20 +- types/decimal.go | 24 +- types/errors.go | 361 -------------- types/errors/abci.go | 39 ++ types/errors/abci_test.go | 26 +- types/errors/errors.go | 43 +- types/errors/stacktrace_test.go | 8 +- types/errors_test.go | 138 ------ types/handler.go | 2 +- types/queryable.go | 9 +- types/result.go | 48 +- types/result_test.go | 14 +- types/tx_msg.go | 8 +- x/auth/ante/ante_test.go | 71 ++- x/auth/client/rest/query.go | 6 +- x/auth/client/utils/tx.go | 6 +- x/auth/client/utils/tx_test.go | 7 +- x/auth/keeper/keeper.go | 9 +- x/auth/keeper/querier.go | 15 +- x/auth/types/expected_keepers.go | 2 +- x/auth/types/stdtx.go | 26 +- x/auth/types/stdtx_test.go | 13 +- x/bank/alias.go | 29 +- x/bank/bench_test.go | 10 +- x/bank/handler.go | 28 +- x/bank/handler_test.go | 13 +- x/bank/internal/keeper/keeper.go | 101 ++-- x/bank/internal/keeper/keeper_test.go | 12 +- x/bank/internal/keeper/querier.go | 13 +- x/bank/internal/types/errors.go | 34 +- x/bank/internal/types/msgs.go | 43 +- x/bank/simulation/operations.go | 13 +- x/crisis/alias.go | 34 +- x/crisis/handler.go | 17 +- x/crisis/handler_test.go | 24 +- x/crisis/internal/keeper/keeper.go | 2 +- x/crisis/internal/types/errors.go | 22 +- x/crisis/internal/types/expected_keepers.go | 2 +- x/crisis/internal/types/msgs.go | 4 +- x/distribution/alias.go | 16 +- x/distribution/handler.go | 37 +- x/distribution/keeper/allocation_test.go | 38 +- x/distribution/keeper/delegation.go | 4 +- x/distribution/keeper/delegation_test.go | 64 ++- x/distribution/keeper/fee_pool.go | 5 +- x/distribution/keeper/keeper.go | 29 +- x/distribution/keeper/proposal_handler.go | 5 +- x/distribution/keeper/querier.go | 88 ++-- x/distribution/keeper/querier_test.go | 12 +- x/distribution/keeper/test_common.go | 8 +- x/distribution/simulation/operations.go | 25 +- x/distribution/types/errors.go | 56 +-- x/distribution/types/expected_keepers.go | 6 +- x/distribution/types/msg.go | 24 +- x/distribution/types/proposal.go | 9 +- x/evidence/alias.go | 30 +- x/evidence/genesis_test.go | 3 +- x/evidence/handler.go | 15 +- x/evidence/handler_test.go | 13 +- x/evidence/internal/keeper/infraction_test.go | 15 +- x/evidence/internal/keeper/keeper.go | 13 +- x/evidence/internal/keeper/keeper_test.go | 3 +- x/evidence/internal/keeper/querier.go | 8 +- x/evidence/internal/types/errors.go | 56 +-- x/evidence/internal/types/msgs.go | 8 +- x/genutil/client/rest/query.go | 19 +- x/gov/abci.go | 2 +- x/gov/abci_test.go | 51 +- x/gov/alias.go | 87 ++-- x/gov/genesis_test.go | 2 +- x/gov/handler.go | 33 +- x/gov/handler_test.go | 7 +- x/gov/keeper/deposit.go | 11 +- x/gov/keeper/deposit_test.go | 6 +- x/gov/keeper/keeper.go | 6 +- x/gov/keeper/proposal.go | 12 +- x/gov/keeper/proposal_test.go | 25 +- x/gov/keeper/querier.go | 76 +-- x/gov/keeper/querier_test.go | 10 +- x/gov/keeper/test_common.go | 8 +- x/gov/keeper/vote.go | 9 +- x/gov/legacy/v0_36/types.go | 30 +- x/gov/simulation/operations.go | 19 +- x/gov/test_common.go | 28 +- x/gov/types/content.go | 16 +- x/gov/types/errors.go | 71 +-- x/gov/types/expected_keepers.go | 18 +- x/gov/types/msgs.go | 27 +- x/gov/types/proposal.go | 8 +- x/mint/alias.go | 7 +- x/mint/internal/keeper/keeper.go | 8 +- x/mint/internal/keeper/querier.go | 19 +- x/mint/internal/types/expected_keepers.go | 6 +- x/mock/app.go | 2 +- x/mock/app_test.go | 16 +- x/mock/test_utils.go | 33 +- x/mock/types.go | 11 +- x/params/alias.go | 18 +- x/params/commmon_test.go | 2 +- x/params/keeper.go | 20 +- x/params/proposal_handler.go | 12 +- x/params/proposal_handler_test.go | 2 +- x/params/types/errors.go | 49 +- x/params/types/proposal.go | 15 +- x/slashing/abci_test.go | 6 +- x/slashing/alias.go | 15 +- x/slashing/app_test.go | 14 +- x/slashing/handler.go | 15 +- x/slashing/handler_test.go | 91 ++-- x/slashing/internal/keeper/keeper.go | 7 +- x/slashing/internal/keeper/keeper_test.go | 30 +- x/slashing/internal/keeper/querier.go | 28 +- x/slashing/internal/keeper/test_common.go | 8 +- x/slashing/internal/keeper/unjail.go | 16 +- x/slashing/internal/types/errors.go | 57 +-- x/slashing/internal/types/msg.go | 4 +- x/slashing/simulation/operations.go | 6 +- x/staking/alias.go | 27 +- x/staking/app_test.go | 4 +- x/staking/client/cli/tx.go | 5 +- x/staking/exported/exported.go | 40 +- x/staking/handler.go | 75 +-- x/staking/handler_test.go | 467 +++++++++++------- x/staking/keeper/delegation.go | 71 +-- x/staking/keeper/keeper.go | 14 +- x/staking/keeper/pool.go | 4 +- x/staking/keeper/querier.go | 134 ++--- x/staking/keeper/query_utils.go | 8 +- x/staking/keeper/test_common.go | 5 +- x/staking/keeper/validator.go | 2 +- x/staking/simulation/operations.go | 31 +- x/staking/types/commission.go | 24 +- x/staking/types/errors.go | 270 ++-------- x/staking/types/expected_keepers.go | 8 +- x/staking/types/historical_info.go | 4 +- x/staking/types/msg.go | 58 ++- x/staking/types/validator.go | 25 +- x/supply/alias.go | 3 +- x/supply/internal/keeper/bank.go | 85 ++-- x/supply/internal/keeper/bank_test.go | 24 +- x/supply/internal/keeper/key.go | 8 - x/supply/internal/keeper/querier.go | 19 +- x/supply/internal/types/expected_keepers.go | 10 +- x/upgrade/abci_test.go | 12 +- x/upgrade/alias.go | 8 +- x/upgrade/handler.go | 12 +- x/upgrade/internal/keeper/keeper.go | 10 +- x/upgrade/internal/keeper/querier.go | 20 +- x/upgrade/internal/types/plan.go | 12 +- x/upgrade/internal/types/proposal.go | 14 +- 170 files changed, 2309 insertions(+), 2926 deletions(-) delete mode 100644 store/errors/errors.go delete mode 100644 types/errors.go delete mode 100644 types/errors_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index dac02cb50f66..be6b7cec3274 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,7 +50,20 @@ logic has been implemented for v0.38 target version. Applications can migrate vi ### API Breaking Changes -* (client) [\#5442](https://github.com/cosmos/cosmos-sdk/pull/5442) Remove client/alias.go as it's not necessary and +* (baseapp/types) [\#5421](https://github.com/cosmos/cosmos-sdk/pull/5421) The `Error` interface (`types/errors.go`) + has been removed in favor of the concrete type defined in `types/errors/` which implements the standard `error` + interface. As a result, the `Handler` and `Querier` implementations now return a standard `error`. + Within `BaseApp`, `runTx` now returns a `(GasInfo, *Result, error)` tuple and `runMsgs` returns a + `(*Result, error)` tuple. A reference to a `Result` is now used to indicate success whereas an error + signals an invalid message or failed message execution. As a result, the fields `Code`, `Codespace`, + `GasWanted`, and `GasUsed` have been removed the `Result` type. The latter two fields are now found + in the `GasInfo` type which is always returned regardless of execution outcome. + + Note to developers: Since all handlers and queriers must now return a standard `error`, the `types/errors/` + package contains all the relevant and pre-registered errors that you typically work with. A typical + error returned will look like `sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "...")`. You can retrieve + relevant ABCI information from the error via `ABCIInfo`. +* (client) [\#5442](https://github.com/cosmos/cosmos-sdk/pull/5442) Remove client/alias.go as it's not necessary and components can be imported directly from the packages. * (store) [\#4748](https://github.com/cosmos/cosmos-sdk/pull/4748) The `CommitMultiStore` interface now requires a `SetInterBlockCache` method. Applications that do not wish to support this can simply diff --git a/baseapp/abci.go b/baseapp/abci.go index e93b7c56c2c9..57bcec661eff 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -11,6 +11,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) // InitChain implements the ABCI interface. It runs the initialization logic @@ -153,54 +154,66 @@ func (app *BaseApp) EndBlock(req abci.RequestEndBlock) (res abci.ResponseEndBloc return } -// CheckTx implements the ABCI interface. It runs the "basic checks" to see -// whether or not a transaction can possibly be executed, first decoding and then -// the ante handler (which checks signatures/fees/ValidateBasic). -// -// NOTE:CheckTx does not run the actual Msg handler function(s). -func (app *BaseApp) CheckTx(req abci.RequestCheckTx) (res abci.ResponseCheckTx) { - var result sdk.Result - +// CheckTx implements the ABCI interface and executes a tx in CheckTx mode. In +// CheckTx mode, messages are not executed. This means messages are only validated +// and only the AnteHandler is executed. State is persisted to the BaseApp's +// internal CheckTx state if the AnteHandler passes. Otherwise, the ResponseCheckTx +// will contain releveant error information. Regardless of tx execution outcome, +// the ResponseCheckTx will contain relevant gas execution context. +func (app *BaseApp) CheckTx(req abci.RequestCheckTx) abci.ResponseCheckTx { tx, err := app.txDecoder(req.Tx) + if err != nil { + return sdkerrors.ResponseCheckTx(err, 0, 0) + } + + var mode runTxMode + switch { - case err != nil: - result = err.Result() case req.Type == abci.CheckTxType_New: - result = app.runTx(runTxModeCheck, req.Tx, tx) + mode = runTxModeCheck + case req.Type == abci.CheckTxType_Recheck: - result = app.runTx(runTxModeReCheck, req.Tx, tx) + mode = runTxModeReCheck + default: - panic(fmt.Sprintf("Unknown RequestCheckTx Type: %v", req.Type)) + panic(fmt.Sprintf("unknown RequestCheckTx type: %s", req.Type)) + } + + gInfo, result, err := app.runTx(mode, req.Tx, tx) + if err != nil { + return sdkerrors.ResponseCheckTx(err, gInfo.GasWanted, gInfo.GasUsed) } return abci.ResponseCheckTx{ - Code: uint32(result.Code), - Data: result.Data, + GasWanted: int64(gInfo.GasWanted), // TODO: Should type accept unsigned ints? + GasUsed: int64(gInfo.GasUsed), // TODO: Should type accept unsigned ints? Log: result.Log, - GasWanted: int64(result.GasWanted), // TODO: Should type accept unsigned ints? - GasUsed: int64(result.GasUsed), // TODO: Should type accept unsigned ints? + Data: result.Data, Events: result.Events.ToABCIEvents(), } } -// DeliverTx implements the ABCI interface. -func (app *BaseApp) DeliverTx(req abci.RequestDeliverTx) (res abci.ResponseDeliverTx) { - var result sdk.Result - +// DeliverTx implements the ABCI interface and executes a tx in DeliverTx mode. +// State only gets persisted if all messages are valid and get executed successfully. +// Otherwise, the ResponseDeliverTx will contain releveant error information. +// Regardless of tx execution outcome, the ResponseDeliverTx will contain relevant +// gas execution context. +func (app *BaseApp) DeliverTx(req abci.RequestDeliverTx) abci.ResponseDeliverTx { tx, err := app.txDecoder(req.Tx) if err != nil { - result = err.Result() - } else { - result = app.runTx(runTxModeDeliver, req.Tx, tx) + return sdkerrors.ResponseDeliverTx(err, 0, 0) + } + + gInfo, result, err := app.runTx(runTxModeDeliver, req.Tx, tx) + if err != nil { + return sdkerrors.ResponseDeliverTx(err, gInfo.GasWanted, gInfo.GasUsed) } return abci.ResponseDeliverTx{ - Code: uint32(result.Code), - Codespace: string(result.Codespace), - Data: result.Data, + GasWanted: int64(gInfo.GasWanted), // TODO: Should type accept unsigned ints? + GasUsed: int64(gInfo.GasUsed), // TODO: Should type accept unsigned ints? Log: result.Log, - GasWanted: int64(result.GasWanted), // TODO: Should type accept unsigned ints? - GasUsed: int64(result.GasUsed), // TODO: Should type accept unsigned ints? + Data: result.Data, Events: result.Events.ToABCIEvents(), } } @@ -278,11 +291,10 @@ func (app *BaseApp) halt() { // Query implements the ABCI interface. It delegates to CommitMultiStore if it // implements Queryable. -func (app *BaseApp) Query(req abci.RequestQuery) (res abci.ResponseQuery) { +func (app *BaseApp) Query(req abci.RequestQuery) abci.ResponseQuery { path := splitPath(req.Path) if len(path) == 0 { - msg := "no query path provided" - return sdk.ErrUnknownRequest(msg).QueryResult() + sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "no query path provided")) } switch path[0] { @@ -294,61 +306,59 @@ func (app *BaseApp) Query(req abci.RequestQuery) (res abci.ResponseQuery) { return handleQueryStore(app, path, req) case "p2p": - return handleQueryP2P(app, path, req) + return handleQueryP2P(app, path) case "custom": return handleQueryCustom(app, path, req) } - msg := "unknown query path" - return sdk.ErrUnknownRequest(msg).QueryResult() + return sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "unknown query path")) } -func handleQueryApp(app *BaseApp, path []string, req abci.RequestQuery) (res abci.ResponseQuery) { +func handleQueryApp(app *BaseApp, path []string, req abci.RequestQuery) abci.ResponseQuery { if len(path) >= 2 { - var result sdk.Result - switch path[1] { case "simulate": txBytes := req.Data + tx, err := app.txDecoder(txBytes) if err != nil { - result = err.Result() - } else { - result = app.Simulate(txBytes, tx) + return sdkerrors.QueryResult(sdkerrors.Wrap(err, "failed to decode tx")) + } + + gInfo, _, _ := app.Simulate(txBytes, tx) + + return abci.ResponseQuery{ + Codespace: sdkerrors.RootCodespace, + Height: req.Height, + Value: codec.Cdc.MustMarshalBinaryLengthPrefixed(gInfo.GasUsed), } case "version": return abci.ResponseQuery{ - Code: uint32(sdk.CodeOK), - Codespace: string(sdk.CodespaceRoot), + Codespace: sdkerrors.RootCodespace, Height: req.Height, Value: []byte(app.appVersion), } default: - result = sdk.ErrUnknownRequest(fmt.Sprintf("unknown query: %s", path)).Result() - } - - value := codec.Cdc.MustMarshalBinaryLengthPrefixed(result) - return abci.ResponseQuery{ - Code: uint32(sdk.CodeOK), - Codespace: string(sdk.CodespaceRoot), - Height: req.Height, - Value: value, + return sdkerrors.QueryResult(sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown query: %s", path)) } } - msg := "expected second parameter to be either 'simulate' or 'version', neither was present" - return sdk.ErrUnknownRequest(msg).QueryResult() + return sdkerrors.QueryResult( + sdkerrors.Wrap( + sdkerrors.ErrUnknownRequest, + "expected second parameter to be either 'simulate' or 'version', neither was present", + ), + ) } func handleQueryStore(app *BaseApp, path []string, req abci.RequestQuery) abci.ResponseQuery { // "/store" prefix for store queries queryable, ok := app.cms.(sdk.Queryable) if !ok { - msg := "multistore doesn't support queries" - return sdk.ErrUnknownRequest(msg).QueryResult() + return sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "multistore doesn't support queries")) } req.Path = "/" + strings.Join(path[1:], "/") @@ -359,7 +369,12 @@ func handleQueryStore(app *BaseApp, path []string, req abci.RequestQuery) abci.R } if req.Height <= 1 && req.Prove { - return sdk.ErrInternal("cannot query with proof when height <= 1; please provide a valid height").QueryResult() + return sdkerrors.QueryResult( + sdkerrors.Wrap( + sdkerrors.ErrInvalidRequest, + "cannot query with proof when height <= 1; please provide a valid height", + ), + ) } resp := queryable.Query(req) @@ -368,7 +383,7 @@ func handleQueryStore(app *BaseApp, path []string, req abci.RequestQuery) abci.R return resp } -func handleQueryP2P(app *BaseApp, path []string, _ abci.RequestQuery) (res abci.ResponseQuery) { +func handleQueryP2P(app *BaseApp, path []string) abci.ResponseQuery { // "/p2p" prefix for p2p queries if len(path) >= 4 { cmd, typ, arg := path[1], path[2], path[3] @@ -383,28 +398,30 @@ func handleQueryP2P(app *BaseApp, path []string, _ abci.RequestQuery) (res abci. } default: - msg := "expected second parameter to be 'filter'" - return sdk.ErrUnknownRequest(msg).QueryResult() + return sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "expected second parameter to be 'filter'")) } } - msg := "Expected path is p2p filter " - return sdk.ErrUnknownRequest(msg).QueryResult() + return sdkerrors.QueryResult( + sdkerrors.Wrap( + sdkerrors.ErrUnknownRequest, "expected path is p2p filter ", + ), + ) } -func handleQueryCustom(app *BaseApp, path []string, req abci.RequestQuery) (res abci.ResponseQuery) { +func handleQueryCustom(app *BaseApp, path []string, req abci.RequestQuery) abci.ResponseQuery { // path[0] should be "custom" because "/custom" prefix is required for keeper // queries. // // The QueryRouter routes using path[1]. For example, in the path // "custom/gov/proposal", QueryRouter routes using "gov". if len(path) < 2 || path[1] == "" { - return sdk.ErrUnknownRequest("No route for custom query specified").QueryResult() + return sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "no route for custom query specified")) } querier := app.queryRouter.Route(path[1]) if querier == nil { - return sdk.ErrUnknownRequest(fmt.Sprintf("no custom querier found for route %s", path[1])).QueryResult() + return sdkerrors.QueryResult(sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "no custom querier found for route %s", path[1])) } // when a client did not provide a query height, manually inject the latest @@ -413,17 +430,22 @@ func handleQueryCustom(app *BaseApp, path []string, req abci.RequestQuery) (res } if req.Height <= 1 && req.Prove { - return sdk.ErrInternal("cannot query with proof when height <= 1; please provide a valid height").QueryResult() + return sdkerrors.QueryResult( + sdkerrors.Wrap( + sdkerrors.ErrInvalidRequest, + "cannot query with proof when height <= 1; please provide a valid height", + ), + ) } cacheMS, err := app.cms.CacheMultiStoreWithVersion(req.Height) if err != nil { - return sdk.ErrInternal( - fmt.Sprintf( - "failed to load state at height %d; %s (latest height: %d)", - req.Height, err, app.LastBlockHeight(), + return sdkerrors.QueryResult( + sdkerrors.Wrapf( + sdkerrors.ErrInvalidRequest, + "failed to load state at height %d; %s (latest height: %d)", req.Height, err, app.LastBlockHeight(), ), - ).QueryResult() + ) } // cache wrap the commit-multistore for safety @@ -435,18 +457,18 @@ func handleQueryCustom(app *BaseApp, path []string, req abci.RequestQuery) (res // // For example, in the path "custom/gov/proposal/test", the gov querier gets // []string{"proposal", "test"} as the path. - resBytes, queryErr := querier(ctx, path[2:], req) - if queryErr != nil { + resBytes, err := querier(ctx, path[2:], req) + if err != nil { + space, code, log := sdkerrors.ABCIInfo(err, false) return abci.ResponseQuery{ - Code: uint32(queryErr.Code()), - Codespace: string(queryErr.Codespace()), + Code: code, + Codespace: space, + Log: log, Height: req.Height, - Log: queryErr.ABCILog(), } } return abci.ResponseQuery{ - Code: uint32(sdk.CodeOK), Height: req.Height, Value: resBytes, } diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index ae1ca19db7f7..46f3e2649907 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -19,6 +19,7 @@ import ( "github.com/cosmos/cosmos-sdk/store" storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) const ( @@ -446,13 +447,12 @@ func (app *BaseApp) validateHeight(req abci.RequestBeginBlock) error { } // validateBasicTxMsgs executes basic validator calls for messages. -func validateBasicTxMsgs(msgs []sdk.Msg) sdk.Error { +func validateBasicTxMsgs(msgs []sdk.Msg) error { if len(msgs) == 0 { - return sdk.ErrUnknownRequest("Tx.GetMsgs() must return at least one message in list") + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "must contain at least one message") } for _, msg := range msgs { - // Validate the Msg. err := msg.ValidateBasic() if err != nil { return err @@ -508,11 +508,14 @@ func (app *BaseApp) cacheTxContext(ctx sdk.Context, txBytes []byte) (sdk.Context return ctx.WithMultiStore(msCache), msCache } -// runTx processes a transaction. The transactions is processed via an -// anteHandler. The provided txBytes may be nil in some cases, eg. in tests. For -// further details on transaction execution, reference the BaseApp SDK -// documentation. -func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (result sdk.Result) { +// runTx processes a transaction within a given execution mode, encoded transaction +// bytes, and the decoded transaction itself. All state transitions occur through +// a cached Context depending on the mode provided. State only gets persisted +// if all messages get executed successfully and the execution mode is DeliverTx. +// Note, gas execution info is always returned. A reference to a Result is +// returned if the tx does not run out of gas and if all the messages are valid +// and execute successfully. An error is returned otherwise. +func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (gInfo sdk.GasInfo, result *sdk.Result, err error) { // NOTE: GasWanted should be returned by the AnteHandler. GasUsed is // determined by the GasMeter. We need access to the context to get the gas // meter so we initialize upfront. @@ -523,7 +526,8 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (result sdk // only run the tx if there is block gas remaining if mode == runTxModeDeliver && ctx.BlockGasMeter().IsOutOfGas() { - return sdk.ErrOutOfGas("no block gas left to run tx").Result() + gInfo = sdk.GasInfo{GasUsed: ctx.BlockGasMeter().GasConsumed()} + return gInfo, nil, sdkerrors.Wrap(sdkerrors.ErrOutOfGas, "no block gas left to run tx") } var startingGas uint64 @@ -534,20 +538,28 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (result sdk defer func() { if r := recover(); r != nil { switch rType := r.(type) { + // TODO: Use ErrOutOfGas instead of ErrorOutOfGas which would allow us + // to keep the stracktrace. case sdk.ErrorOutOfGas: - log := fmt.Sprintf( - "out of gas in location: %v; gasWanted: %d, gasUsed: %d", - rType.Descriptor, gasWanted, ctx.GasMeter().GasConsumed(), + err = sdkerrors.Wrap( + sdkerrors.ErrOutOfGas, fmt.Sprintf( + "out of gas in location: %v; gasWanted: %d, gasUsed: %d", + rType.Descriptor, gasWanted, ctx.GasMeter().GasConsumed(), + ), ) - result = sdk.ErrOutOfGas(log).Result() + default: - log := fmt.Sprintf("recovered: %v\nstack:\n%v", r, string(debug.Stack())) - result = sdk.ErrInternal(log).Result() + err = sdkerrors.Wrap( + sdkerrors.ErrPanic, fmt.Sprintf( + "recovered: %v\nstack:\n%v", r, string(debug.Stack()), + ), + ) } + + result = nil } - result.GasWanted = gasWanted - result.GasUsed = ctx.GasMeter().GasConsumed() + gInfo = sdk.GasInfo{GasWanted: gasWanted, GasUsed: ctx.GasMeter().GasConsumed()} }() // If BlockGasMeter() panics it will be caught by the above recover and will @@ -558,8 +570,7 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (result sdk defer func() { if mode == runTxModeDeliver { ctx.BlockGasMeter().ConsumeGas( - ctx.GasMeter().GasConsumedToLimit(), - "block gas meter", + ctx.GasMeter().GasConsumedToLimit(), "block gas meter", ) if ctx.BlockGasMeter().GasConsumed() < startingGas { @@ -568,20 +579,21 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (result sdk } }() - var msgs = tx.GetMsgs() + msgs := tx.GetMsgs() if err := validateBasicTxMsgs(msgs); err != nil { - return err.Result() + gInfo = sdk.GasInfo{GasUsed: ctx.BlockGasMeter().GasConsumed()} + return gInfo, nil, err } if app.anteHandler != nil { var anteCtx sdk.Context var msCache sdk.CacheMultiStore - // Cache wrap context before anteHandler call in case it aborts. + // Cache wrap context before AnteHandler call in case it aborts. // This is required for both CheckTx and DeliverTx. // Ref: https://github.com/cosmos/cosmos-sdk/issues/2772 // - // NOTE: Alternatively, we could require that anteHandler ensures that + // NOTE: Alternatively, we could require that AnteHandler ensures that // writes do not happen if aborted/failed. This may have some // performance benefits, but it'll be more difficult to get right. anteCtx, msCache = app.cacheTxContext(ctx, txBytes) @@ -589,11 +601,11 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (result sdk newCtx, err := app.anteHandler(anteCtx, tx, mode == runTxModeSimulate) if !newCtx.IsZero() { // At this point, newCtx.MultiStore() is cache-wrapped, or something else - // replaced by the ante handler. We want the original multistore, not one - // which was cache-wrapped for the ante handler. + // replaced by the AnteHandler. We want the original multistore, not one + // which was cache-wrapped for the AnteHandler. // // Also, in the case of the tx aborting, we need to track gas consumed via - // the instantiated gas meter in the ante handler, so we update the context + // the instantiated gas meter in the AnteHandler, so we update the context // prior to returning. ctx = newCtx.WithMultiStore(ms) } @@ -602,10 +614,7 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (result sdk gasWanted = ctx.GasMeter().Limit() if err != nil { - res := sdk.ResultFromError(err) - res.GasWanted = gasWanted - res.GasUsed = ctx.GasMeter().GasConsumed() - return res + return gInfo, nil, err } msCache.Write() @@ -615,83 +624,63 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (result sdk // MultiStore in case message processing fails. At this point, the MultiStore // is doubly cached-wrapped. runMsgCtx, msCache := app.cacheTxContext(ctx, txBytes) - result = app.runMsgs(runMsgCtx, msgs, mode) - result.GasWanted = gasWanted - // Safety check: don't write the cache state unless we're in DeliverTx. - if mode != runTxModeDeliver { - return result - } - - // only update state if all messages pass - if result.IsOK() { + // Attempt to execute all messages and only update state if all messages pass + // and we're in DeliverTx. Note, runMsgs will never return a reference to a + // Result if any single message fails or does not have a registered Handler. + result, err = app.runMsgs(runMsgCtx, msgs, mode) + if err == nil && mode == runTxModeDeliver { msCache.Write() } - return result + return gInfo, result, err } -// runMsgs iterates through all the messages and executes them. -func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode runTxMode) (result sdk.Result) { +// runMsgs iterates through a list of messages and executes them with the provided +// Context and execution mode. Messages will only be executed during simulation +// and DeliverTx. An error is returned if any single message fails or if a +// Handler does not exist for a given message route. Otherwise, a reference to a +// Result is returned. The caller must not commit state if an error is returned. +func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode runTxMode) (*sdk.Result, error) { msgLogs := make(sdk.ABCIMessageLogs, 0, len(msgs)) - data := make([]byte, 0, len(msgs)) - var ( - code sdk.CodeType - codespace sdk.CodespaceType - ) - events := sdk.EmptyEvents() - // NOTE: GasWanted is determined by ante handler and GasUsed by the GasMeter. + // NOTE: GasWanted is determined by the AnteHandler and GasUsed by the GasMeter. for i, msg := range msgs { - // match message route + // skip actual execution for (Re)CheckTx mode + if mode == runTxModeCheck || mode == runTxModeReCheck { + break + } + msgRoute := msg.Route() handler := app.router.Route(msgRoute) if handler == nil { - return sdk.ErrUnknownRequest("unrecognized message type: " + msgRoute).Result() + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized message route: %s; message index: %d", msgRoute, i) } - var msgResult sdk.Result - - // skip actual execution for CheckTx and ReCheckTx mode - if mode != runTxModeCheck && mode != runTxModeReCheck { - msgResult = handler(ctx, msg) + msgResult, err := handler(ctx, msg) + if err != nil { + return nil, sdkerrors.Wrapf(err, "failed to execute message; message index: %d", i) } - // Each message result's Data must be length prefixed in order to separate - // each result. - data = append(data, msgResult.Data...) - - msgEvents := msgResult.Events - - // append events from the message's execution and a message action event - msgEvents = msgEvents.AppendEvent( + msgEvents := sdk.Events{ sdk.NewEvent(sdk.EventTypeMessage, sdk.NewAttribute(sdk.AttributeKeyAction, msg.Type())), - ) - - events = events.AppendEvents(msgEvents) - - // stop execution and return on first failed message - if !msgResult.IsOK() { - msgLogs = append(msgLogs, sdk.NewABCIMessageLog(uint16(i), false, msgResult.Log, msgEvents)) - - code = msgResult.Code - codespace = msgResult.Codespace - break } + msgEvents = msgEvents.AppendEvents(msgResult.Events) - msgLogs = append(msgLogs, sdk.NewABCIMessageLog(uint16(i), true, msgResult.Log, msgEvents)) - } - - result = sdk.Result{ - Code: code, - Codespace: codespace, - Data: data, - Log: strings.TrimSpace(msgLogs.String()), - GasUsed: ctx.GasMeter().GasConsumed(), - Events: events, + // append message events, data and logs + // + // Note: Each message result's data must be length-prefixed in order to + // separate each result. + events = events.AppendEvents(msgEvents) + data = append(data, msgResult.Data...) + msgLogs = append(msgLogs, sdk.NewABCIMessageLog(uint16(i), msgResult.Log, msgEvents)) } - return result + return &sdk.Result{ + Data: data, + Log: strings.TrimSpace(msgLogs.String()), + Events: events, + }, nil } diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index 52df9bbef0ed..01996e27ef40 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -514,8 +514,8 @@ func (tx *txTest) setFailOnHandler(fail bool) { } // Implements Tx -func (tx txTest) GetMsgs() []sdk.Msg { return tx.Msgs } -func (tx txTest) ValidateBasic() sdk.Error { return nil } +func (tx txTest) GetMsgs() []sdk.Msg { return tx.Msgs } +func (tx txTest) ValidateBasic() error { return nil } const ( routeMsgCounter = "msgCounter" @@ -534,19 +534,20 @@ func (msg msgCounter) Route() string { return routeMsgCounter } func (msg msgCounter) Type() string { return "counter1" } func (msg msgCounter) GetSignBytes() []byte { return nil } func (msg msgCounter) GetSigners() []sdk.AccAddress { return nil } -func (msg msgCounter) ValidateBasic() sdk.Error { +func (msg msgCounter) ValidateBasic() error { if msg.Counter >= 0 { return nil } - return sdk.ErrInvalidSequence("counter should be a non-negative integer.") + return sdkerrors.Wrap(sdkerrors.ErrInvalidSequence, "counter should be a non-negative integer") } -func newTxCounter(txInt int64, msgInts ...int64) *txTest { - msgs := make([]sdk.Msg, 0, len(msgInts)) - for _, msgInt := range msgInts { - msgs = append(msgs, msgCounter{msgInt, false}) +func newTxCounter(counter int64, msgCounters ...int64) *txTest { + msgs := make([]sdk.Msg, 0, len(msgCounters)) + for _, c := range msgCounters { + msgs = append(msgs, msgCounter{c, false}) } - return &txTest{msgs, txInt, false} + + return &txTest{msgs, counter, false} } // a msg we dont know how to route @@ -573,24 +574,26 @@ func (msg msgCounter2) Route() string { return routeMsgCounter2 } func (msg msgCounter2) Type() string { return "counter2" } func (msg msgCounter2) GetSignBytes() []byte { return nil } func (msg msgCounter2) GetSigners() []sdk.AccAddress { return nil } -func (msg msgCounter2) ValidateBasic() sdk.Error { +func (msg msgCounter2) ValidateBasic() error { if msg.Counter >= 0 { return nil } - return sdk.ErrInvalidSequence("counter should be a non-negative integer.") + return sdkerrors.Wrap(sdkerrors.ErrInvalidSequence, "counter should be a non-negative integer") } // amino decode func testTxDecoder(cdc *codec.Codec) sdk.TxDecoder { - return func(txBytes []byte) (sdk.Tx, sdk.Error) { + return func(txBytes []byte) (sdk.Tx, error) { var tx txTest if len(txBytes) == 0 { - return nil, sdk.ErrTxDecode("txBytes are empty") + return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "tx bytes are empty") } + err := cdc.UnmarshalBinaryLengthPrefixed(txBytes, &tx) if err != nil { - return nil, sdk.ErrTxDecode("").TraceSDK(err.Error()) + return nil, sdkerrors.ErrTxDecode } + return tx, nil } } @@ -604,25 +607,28 @@ func anteHandlerTxTest(t *testing.T, capKey sdk.StoreKey, storeKey []byte) sdk.A return newCtx, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "ante handler failure") } - res := incrementingCounter(t, store, storeKey, txTest.Counter) - if !res.IsOK() { - err = sdkerrors.ABCIError(string(res.Codespace), uint32(res.Code), res.Log) + _, err = incrementingCounter(t, store, storeKey, txTest.Counter) + if err != nil { + return newCtx, err } - return + + return newCtx, nil } } func handlerMsgCounter(t *testing.T, capKey sdk.StoreKey, deliverKey []byte) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { store := ctx.KVStore(capKey) var msgCount int64 + switch m := msg.(type) { case *msgCounter: if m.FailOnHandler { - return sdk.ErrInternal("message handler failure").Result() + return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "message handler failure") } msgCount = m.Counter + case *msgCounter2: msgCount = m.Counter } @@ -651,11 +657,11 @@ func setIntOnStore(store sdk.KVStore, key []byte, i int64) { // check counter matches what's in store. // increment and store -func incrementingCounter(t *testing.T, store sdk.KVStore, counterKey []byte, counter int64) (res sdk.Result) { +func incrementingCounter(t *testing.T, store sdk.KVStore, counterKey []byte, counter int64) (*sdk.Result, error) { storedCounter := getIntFromStore(store, counterKey) require.Equal(t, storedCounter, counter) setIntOnStore(store, counterKey, counter+1) - return + return &sdk.Result{}, nil } //--------------------------------------------------------------------- @@ -675,7 +681,9 @@ func TestCheckTx(t *testing.T) { anteOpt := func(bapp *BaseApp) { bapp.SetAnteHandler(anteHandlerTxTest(t, capKey1, counterKey)) } routerOpt := func(bapp *BaseApp) { // TODO: can remove this once CheckTx doesnt process msgs. - bapp.Router().AddRoute(routeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) sdk.Result { return sdk.Result{} }) + bapp.Router().AddRoute(routeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { + return &sdk.Result{}, nil + }) } app := setupBaseApp(t, anteOpt, routerOpt) @@ -847,9 +855,9 @@ func TestSimulateTx(t *testing.T) { } routerOpt := func(bapp *BaseApp) { - bapp.Router().AddRoute(routeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + bapp.Router().AddRoute(routeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { ctx.GasMeter().ConsumeGas(gasConsumed, "test") - return sdk.Result{GasUsed: ctx.GasMeter().GasConsumed()} + return &sdk.Result{}, nil }) } @@ -872,14 +880,16 @@ func TestSimulateTx(t *testing.T) { require.Nil(t, err) // simulate a message, check gas reported - result := app.Simulate(txBytes, tx) - require.True(t, result.IsOK(), result.Log) - require.Equal(t, gasConsumed, result.GasUsed) + gInfo, result, err := app.Simulate(txBytes, tx) + require.NoError(t, err) + require.NotNil(t, result) + require.Equal(t, gasConsumed, gInfo.GasUsed) // simulate again, same result - result = app.Simulate(txBytes, tx) - require.True(t, result.IsOK(), result.Log) - require.Equal(t, gasConsumed, result.GasUsed) + gInfo, result, err = app.Simulate(txBytes, tx) + require.NoError(t, err) + require.NotNil(t, result) + require.Equal(t, gasConsumed, gInfo.GasUsed) // simulate by calling Query with encoded tx query := abci.RequestQuery{ @@ -889,11 +899,10 @@ func TestSimulateTx(t *testing.T) { queryResult := app.Query(query) require.True(t, queryResult.IsOK(), queryResult.Log) - var res sdk.Result - codec.Cdc.MustUnmarshalBinaryLengthPrefixed(queryResult.Value, &res) - require.Nil(t, err, "Result unmarshalling failed") - require.True(t, res.IsOK(), res.Log) - require.Equal(t, gasConsumed, res.GasUsed, res.Log) + var res uint64 + err = codec.Cdc.UnmarshalBinaryLengthPrefixed(queryResult.Value, &res) + require.NoError(t, err) + require.Equal(t, gasConsumed, res) app.EndBlock(abci.RequestEndBlock{}) app.Commit() } @@ -906,7 +915,9 @@ func TestRunInvalidTransaction(t *testing.T) { }) } routerOpt := func(bapp *BaseApp) { - bapp.Router().AddRoute(routeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) (res sdk.Result) { return }) + bapp.Router().AddRoute(routeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { + return &sdk.Result{}, nil + }) } app := setupBaseApp(t, anteOpt, routerOpt) @@ -914,15 +925,19 @@ func TestRunInvalidTransaction(t *testing.T) { header := abci.Header{Height: 1} app.BeginBlock(abci.RequestBeginBlock{Header: header}) - // Transaction with no messages + // transaction with no messages { emptyTx := &txTest{} - err := app.Deliver(emptyTx) - require.EqualValues(t, sdk.CodeUnknownRequest, err.Code) - require.EqualValues(t, sdk.CodespaceRoot, err.Codespace) + _, result, err := app.Deliver(emptyTx) + require.Error(t, err) + require.Nil(t, result) + + space, code, _ := sdkerrors.ABCIInfo(err, false) + require.EqualValues(t, sdkerrors.ErrInvalidRequest.Codespace(), space, err) + require.EqualValues(t, sdkerrors.ErrInvalidRequest.ABCICode(), code, err) } - // Transaction where ValidateBasic fails + // transaction where ValidateBasic fails { testCases := []struct { tx *txTest @@ -940,27 +955,39 @@ func TestRunInvalidTransaction(t *testing.T) { for _, testCase := range testCases { tx := testCase.tx - res := app.Deliver(tx) + _, result, err := app.Deliver(tx) + if testCase.fail { - require.EqualValues(t, sdk.CodeInvalidSequence, res.Code) - require.EqualValues(t, sdk.CodespaceRoot, res.Codespace) + require.Error(t, err) + + space, code, _ := sdkerrors.ABCIInfo(err, false) + require.EqualValues(t, sdkerrors.ErrInvalidSequence.Codespace(), space, err) + require.EqualValues(t, sdkerrors.ErrInvalidSequence.ABCICode(), code, err) } else { - require.True(t, res.IsOK(), fmt.Sprintf("%v", res)) + require.NotNil(t, result) } } } - // Transaction with no known route + // transaction with no known route { unknownRouteTx := txTest{[]sdk.Msg{msgNoRoute{}}, 0, false} - err := app.Deliver(unknownRouteTx) - require.EqualValues(t, sdk.CodeUnknownRequest, err.Code) - require.EqualValues(t, sdk.CodespaceRoot, err.Codespace) + _, result, err := app.Deliver(unknownRouteTx) + require.Error(t, err) + require.Nil(t, result) + + space, code, _ := sdkerrors.ABCIInfo(err, false) + require.EqualValues(t, sdkerrors.ErrUnknownRequest.Codespace(), space, err) + require.EqualValues(t, sdkerrors.ErrUnknownRequest.ABCICode(), code, err) unknownRouteTx = txTest{[]sdk.Msg{msgCounter{}, msgNoRoute{}}, 0, false} - err = app.Deliver(unknownRouteTx) - require.EqualValues(t, sdk.CodeUnknownRequest, err.Code) - require.EqualValues(t, sdk.CodespaceRoot, err.Codespace) + _, result, err = app.Deliver(unknownRouteTx) + require.Error(t, err) + require.Nil(t, result) + + space, code, _ = sdkerrors.ABCIInfo(err, false) + require.EqualValues(t, sdkerrors.ErrUnknownRequest.Codespace(), space, err) + require.EqualValues(t, sdkerrors.ErrUnknownRequest.ABCICode(), code, err) } // Transaction with an unregistered message @@ -975,9 +1002,10 @@ func TestRunInvalidTransaction(t *testing.T) { txBytes, err := newCdc.MarshalBinaryLengthPrefixed(tx) require.NoError(t, err) + res := app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) - require.EqualValues(t, sdk.CodeTxDecode, res.Code) - require.EqualValues(t, sdk.CodespaceRoot, res.Codespace) + require.EqualValues(t, sdkerrors.ErrTxDecode.ABCICode(), res.Code) + require.EqualValues(t, sdkerrors.ErrTxDecode.Codespace(), res.Codespace) } } @@ -996,8 +1024,7 @@ func TestTxGasLimits(t *testing.T) { if r := recover(); r != nil { switch rType := r.(type) { case sdk.ErrorOutOfGas: - log := fmt.Sprintf("out of gas in location: %v", rType.Descriptor) - err = sdkerrors.Wrap(sdkerrors.ErrOutOfGas, log) + err = sdkerrors.Wrapf(sdkerrors.ErrOutOfGas, "out of gas in location: %v", rType.Descriptor) default: panic(r) } @@ -1007,16 +1034,16 @@ func TestTxGasLimits(t *testing.T) { count := tx.(*txTest).Counter newCtx.GasMeter().ConsumeGas(uint64(count), "counter-ante") - return + return newCtx, nil }) } routerOpt := func(bapp *BaseApp) { - bapp.Router().AddRoute(routeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + bapp.Router().AddRoute(routeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { count := msg.(msgCounter).Counter ctx.GasMeter().ConsumeGas(uint64(count), "counter-handler") - return sdk.Result{} + return &sdk.Result{}, nil }) } @@ -1051,17 +1078,21 @@ func TestTxGasLimits(t *testing.T) { for i, tc := range testCases { tx := tc.tx - res := app.Deliver(tx) + gInfo, result, err := app.Deliver(tx) // check gas used and wanted - require.Equal(t, tc.gasUsed, res.GasUsed, fmt.Sprintf("%d: %v, %v", i, tc, res)) + require.Equal(t, tc.gasUsed, gInfo.GasUsed, fmt.Sprintf("tc #%d; gas: %v, result: %v, err: %s", i, gInfo, result, err)) // check for out of gas if !tc.fail { - require.True(t, res.IsOK(), fmt.Sprintf("%d: %v, %v", i, tc, res)) + require.NotNil(t, result, fmt.Sprintf("%d: %v, %v", i, tc, err)) } else { - require.Equal(t, sdk.CodeOutOfGas, res.Code, fmt.Sprintf("%d: %v, %v", i, tc, res)) - require.Equal(t, sdk.CodespaceRoot, res.Codespace) + require.Error(t, err) + require.Nil(t, result) + + space, code, _ := sdkerrors.ABCIInfo(err, false) + require.EqualValues(t, sdkerrors.ErrOutOfGas.Codespace(), space, err) + require.EqualValues(t, sdkerrors.ErrOutOfGas.ABCICode(), code, err) } } } @@ -1093,10 +1124,10 @@ func TestMaxBlockGasLimits(t *testing.T) { } routerOpt := func(bapp *BaseApp) { - bapp.Router().AddRoute(routeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + bapp.Router().AddRoute(routeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { count := msg.(msgCounter).Counter ctx.GasMeter().ConsumeGas(uint64(count), "counter-handler") - return sdk.Result{} + return &sdk.Result{}, nil }) } @@ -1137,23 +1168,29 @@ func TestMaxBlockGasLimits(t *testing.T) { // execute the transaction multiple times for j := 0; j < tc.numDelivers; j++ { - res := app.Deliver(tx) + _, result, err := app.Deliver(tx) ctx := app.getState(runTxModeDeliver).ctx - blockGasUsed := ctx.BlockGasMeter().GasConsumed() // check for failed transactions if tc.fail && (j+1) > tc.failAfterDeliver { - require.Equal(t, res.Code, sdk.CodeOutOfGas, fmt.Sprintf("%d: %v, %v", i, tc, res)) - require.Equal(t, res.Codespace, sdk.CodespaceRoot, fmt.Sprintf("%d: %v, %v", i, tc, res)) + require.Error(t, err, fmt.Sprintf("tc #%d; result: %v, err: %s", i, result, err)) + require.Nil(t, result, fmt.Sprintf("tc #%d; result: %v, err: %s", i, result, err)) + + space, code, _ := sdkerrors.ABCIInfo(err, false) + require.EqualValues(t, sdkerrors.ErrOutOfGas.Codespace(), space, err) + require.EqualValues(t, sdkerrors.ErrOutOfGas.ABCICode(), code, err) require.True(t, ctx.BlockGasMeter().IsOutOfGas()) } else { // check gas used and wanted + blockGasUsed := ctx.BlockGasMeter().GasConsumed() expBlockGasUsed := tc.gasUsedPerDeliver * uint64(j+1) - require.Equal(t, expBlockGasUsed, blockGasUsed, - fmt.Sprintf("%d,%d: %v, %v, %v, %v", i, j, tc, expBlockGasUsed, blockGasUsed, res)) + require.Equal( + t, expBlockGasUsed, blockGasUsed, + fmt.Sprintf("%d,%d: %v, %v, %v, %v", i, j, tc, expBlockGasUsed, blockGasUsed, result), + ) - require.True(t, res.IsOK(), fmt.Sprintf("%d,%d: %v, %v", i, j, tc, res)) + require.NotNil(t, result, fmt.Sprintf("tc #%d; currDeliver: %d, result: %v, err: %s", i, j, result, err)) require.False(t, ctx.BlockGasMeter().IsPastLimit()) } } @@ -1260,10 +1297,10 @@ func TestGasConsumptionBadTx(t *testing.T) { } routerOpt := func(bapp *BaseApp) { - bapp.Router().AddRoute(routeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + bapp.Router().AddRoute(routeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { count := msg.(msgCounter).Counter ctx.GasMeter().ConsumeGas(uint64(count), "counter-handler") - return sdk.Result{} + return &sdk.Result{}, nil }) } @@ -1313,10 +1350,10 @@ func TestQuery(t *testing.T) { } routerOpt := func(bapp *BaseApp) { - bapp.Router().AddRoute(routeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + bapp.Router().AddRoute(routeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { store := ctx.KVStore(capKey1) store.Set(key, value) - return sdk.Result{} + return &sdk.Result{}, nil }) } @@ -1338,8 +1375,9 @@ func TestQuery(t *testing.T) { require.Equal(t, 0, len(res.Value)) // query is still empty after a CheckTx - resTx := app.Check(tx) - require.True(t, resTx.IsOK(), fmt.Sprintf("%v", resTx)) + _, resTx, err := app.Check(tx) + require.NoError(t, err) + require.NotNil(t, resTx) res = app.Query(query) require.Equal(t, 0, len(res.Value)) @@ -1347,8 +1385,9 @@ func TestQuery(t *testing.T) { header := abci.Header{Height: app.LastBlockHeight() + 1} app.BeginBlock(abci.RequestBeginBlock{Header: header}) - resTx = app.Deliver(tx) - require.True(t, resTx.IsOK(), fmt.Sprintf("%v", resTx)) + _, resTx, err = app.Deliver(tx) + require.NoError(t, err) + require.NotNil(t, resTx) res = app.Query(query) require.Equal(t, 0, len(res.Value)) diff --git a/baseapp/helpers.go b/baseapp/helpers.go index 5ea3cdcd9a77..aa9c10d328d7 100644 --- a/baseapp/helpers.go +++ b/baseapp/helpers.go @@ -10,15 +10,15 @@ import ( var isAlphaNumeric = regexp.MustCompile(`^[a-zA-Z0-9]+$`).MatchString -func (app *BaseApp) Check(tx sdk.Tx) (result sdk.Result) { +func (app *BaseApp) Check(tx sdk.Tx) (sdk.GasInfo, *sdk.Result, error) { return app.runTx(runTxModeCheck, nil, tx) } -func (app *BaseApp) Simulate(txBytes []byte, tx sdk.Tx) (result sdk.Result) { +func (app *BaseApp) Simulate(txBytes []byte, tx sdk.Tx) (sdk.GasInfo, *sdk.Result, error) { return app.runTx(runTxModeSimulate, txBytes, tx) } -func (app *BaseApp) Deliver(tx sdk.Tx) (result sdk.Result) { +func (app *BaseApp) Deliver(tx sdk.Tx) (sdk.GasInfo, *sdk.Result, error) { return app.runTx(runTxModeDeliver, nil, tx) } diff --git a/baseapp/queryrouter_test.go b/baseapp/queryrouter_test.go index 7743028313cc..c7637f17000e 100644 --- a/baseapp/queryrouter_test.go +++ b/baseapp/queryrouter_test.go @@ -10,7 +10,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -var testQuerier = func(_ sdk.Context, _ []string, _ abci.RequestQuery) (res []byte, err sdk.Error) { +var testQuerier = func(_ sdk.Context, _ []string, _ abci.RequestQuery) ([]byte, error) { return nil, nil } diff --git a/baseapp/router_test.go b/baseapp/router_test.go index 86e09cf21b79..1a6d999bcce6 100644 --- a/baseapp/router_test.go +++ b/baseapp/router_test.go @@ -8,8 +8,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -var testHandler = func(_ sdk.Context, _ sdk.Msg) sdk.Result { - return sdk.Result{} +var testHandler = func(_ sdk.Context, _ sdk.Msg) (*sdk.Result, error) { + return &sdk.Result{}, nil } func TestRouter(t *testing.T) { diff --git a/client/context/broadcast.go b/client/context/broadcast.go index 1996c47d99cb..67251b6da89d 100644 --- a/client/context/broadcast.go +++ b/client/context/broadcast.go @@ -9,6 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) // BroadcastTx broadcasts a transactions either synchronously or asynchronously @@ -52,19 +53,19 @@ func CheckTendermintError(err error, txBytes []byte) *sdk.TxResponse { switch { case strings.Contains(errStr, strings.ToLower(mempool.ErrTxInCache.Error())): return &sdk.TxResponse{ - Code: uint32(sdk.CodeTxInMempoolCache), + Code: sdkerrors.ErrTxInMempoolCache.ABCICode(), TxHash: txHash, } case strings.Contains(errStr, "mempool is full"): return &sdk.TxResponse{ - Code: uint32(sdk.CodeMempoolIsFull), + Code: sdkerrors.ErrMempoolIsFull.ABCICode(), TxHash: txHash, } case strings.Contains(errStr, "tx too large"): return &sdk.TxResponse{ - Code: uint32(sdk.CodeTxTooLarge), + Code: sdkerrors.ErrTxTooLarge.ABCICode(), TxHash: txHash, } diff --git a/client/context/broadcast_test.go b/client/context/broadcast_test.go index 2afddb8f3524..530645b9d187 100644 --- a/client/context/broadcast_test.go +++ b/client/context/broadcast_test.go @@ -4,16 +4,15 @@ import ( "fmt" "testing" - "github.com/tendermint/tendermint/crypto/tmhash" - "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/crypto/tmhash" "github.com/tendermint/tendermint/mempool" "github.com/tendermint/tendermint/rpc/client/mock" ctypes "github.com/tendermint/tendermint/rpc/core/types" tmtypes "github.com/tendermint/tendermint/types" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) type MockClient struct { @@ -43,9 +42,9 @@ func CreateContextWithErrorAndMode(err error, mode string) CLIContext { // Test the correct code is returned when func TestBroadcastError(t *testing.T) { errors := map[error]uint32{ - mempool.ErrTxInCache: uint32(types.CodeTxInMempoolCache), - mempool.ErrTxTooLarge{}: uint32(types.CodeTxTooLarge), - mempool.ErrMempoolIsFull{}: uint32(types.CodeMempoolIsFull), + mempool.ErrTxInCache: sdkerrors.ErrTxInMempoolCache.ABCICode(), + mempool.ErrTxTooLarge{}: sdkerrors.ErrTxTooLarge.ABCICode(), + mempool.ErrMempoolIsFull{}: sdkerrors.ErrMempoolIsFull.ABCICode(), } modes := []string{ diff --git a/docs/architecture/adr-015-ibc-packet-receiver.md b/docs/architecture/adr-015-ibc-packet-receiver.md index e772c3234c47..2ea26dcb5bae 100644 --- a/docs/architecture/adr-015-ibc-packet-receiver.md +++ b/docs/architecture/adr-015-ibc-packet-receiver.md @@ -204,7 +204,7 @@ type PacketDataI interface { GetCommitment() []byte // Commitment form that will be stored in the state. GetTimeoutHeight() uint64 - ValidateBasic() sdk.Error + ValidateBasic() error Type() string } ``` diff --git a/docs/building-modules/handler.md b/docs/building-modules/handler.md index 3b19bf9603a9..37b46511a09a 100644 --- a/docs/building-modules/handler.md +++ b/docs/building-modules/handler.md @@ -25,19 +25,24 @@ Let us break it down: ## Implementation of a module `handler`s -Module `handler`s are typically implemented in a `./handler.go` file inside the module's folder. The [module manager](./module-manager.md) is used to add the module's `handler`s to the [application's `router`](../core/baseapp.md#message-routing) via the `NewHandler()` method. Typically, the manager's `NewHandler()` method simply calls a `NewHandler()` method defined in `handler.go`, which looks like the following: +Module `handler`s are typically implemented in a `./handler.go` file inside the module's folder. The +[module manager](./module-manager.md) is used to add the module's `handler`s to the +[application's `router`](../core/baseapp.md#message-routing) via the `NewHandler()` method. Typically, +the manager's `NewHandler()` method simply calls a `NewHandler()` method defined in `handler.go`, +which looks like the following: ```go func NewHandler(keeper Keeper) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { switch msg := msg.(type) { case MsgType1: return handleMsgType1(ctx, keeper, msg) + case MsgType2: return handleMsgType2(ctx, keeper, msg) + default: - errMsg := fmt.Sprintf("Unrecognized nameservice Msg type: %v", msg.Type()) - return sdk.ErrUnknownRequest(errMsg).Result() + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s message type: %T", ModuleName, msg) } } } diff --git a/docs/building-modules/querier.md b/docs/building-modules/querier.md index 02c334fc3843..be4750778661 100644 --- a/docs/building-modules/querier.md +++ b/docs/building-modules/querier.md @@ -29,14 +29,16 @@ Module `querier`s are typically implemented in a `./internal/keeper/querier.go` ```go func NewQuerier(keeper Keeper) sdk.Querier { - return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err sdk.Error) { + return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) { switch path[0] { case QueryType1: return queryType1(ctx, path[1:], req, keeper) + case QueryType2: return queryType2(ctx, path[1:], req, keeper) + default: - return nil, sdk.ErrUnknownRequest("unknown nameservice query endpoint") + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown %s query endpoint: %s", types.ModuleName, path[0]) } } } diff --git a/server/mock/app.go b/server/mock/app.go index 9063bb7c5ea1..d1e1146d6a57 100644 --- a/server/mock/app.go +++ b/server/mock/app.go @@ -2,6 +2,7 @@ package mock import ( "encoding/json" + "errors" "fmt" "path/filepath" @@ -49,10 +50,10 @@ func NewApp(rootDir string, logger log.Logger) (abci.Application, error) { // KVStoreHandler is a simple handler that takes kvstoreTx and writes // them to the db func KVStoreHandler(storeKey sdk.StoreKey) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { dTx, ok := msg.(kvstoreTx) if !ok { - panic("KVStoreHandler should only receive kvstoreTx") + return nil, errors.New("KVStoreHandler should only receive kvstoreTx") } // tx is already unmarshalled @@ -62,10 +63,9 @@ func KVStoreHandler(storeKey sdk.StoreKey) sdk.Handler { store := ctx.KVStore(storeKey) store.Set(key, value) - return sdk.Result{ - Code: 0, - Log: fmt.Sprintf("set %s=%s", key, value), - } + return &sdk.Result{ + Log: fmt.Sprintf("set %s=%s", key, value), + }, nil } } diff --git a/server/mock/tx.go b/server/mock/tx.go index 6774fb28145a..27441051ce8a 100644 --- a/server/mock/tx.go +++ b/server/mock/tx.go @@ -6,6 +6,7 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) // An sdk.Tx which is its own sdk.Msg. @@ -47,7 +48,7 @@ func (tx kvstoreTx) GetSignBytes() []byte { } // Should the app be calling this? Or only handlers? -func (tx kvstoreTx) ValidateBasic() sdk.Error { +func (tx kvstoreTx) ValidateBasic() error { return nil } @@ -57,7 +58,7 @@ func (tx kvstoreTx) GetSigners() []sdk.AccAddress { // takes raw transaction bytes and decodes them into an sdk.Tx. An sdk.Tx has // all the signatures and can be used to authenticate. -func decodeTx(txBytes []byte) (sdk.Tx, sdk.Error) { +func decodeTx(txBytes []byte) (sdk.Tx, error) { var tx sdk.Tx split := bytes.Split(txBytes, []byte("=")) @@ -68,7 +69,7 @@ func decodeTx(txBytes []byte) (sdk.Tx, sdk.Error) { k, v := split[0], split[1] tx = kvstoreTx{k, v, txBytes} } else { - return nil, sdk.ErrTxDecode("too many =") + return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "too many '='") } return tx, nil diff --git a/simapp/app.go b/simapp/app.go index 2bd4ed3543f5..e4e4ede4e9d2 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -158,7 +158,7 @@ func NewSimApp( } // init params keeper and subspaces - app.ParamsKeeper = params.NewKeeper(app.cdc, keys[params.StoreKey], tkeys[params.TStoreKey], params.DefaultCodespace) + app.ParamsKeeper = params.NewKeeper(app.cdc, keys[params.StoreKey], tkeys[params.TStoreKey]) app.subspaces[auth.ModuleName] = app.ParamsKeeper.Subspace(auth.DefaultParamspace) app.subspaces[bank.ModuleName] = app.ParamsKeeper.Subspace(bank.DefaultParamspace) app.subspaces[staking.ModuleName] = app.ParamsKeeper.Subspace(staking.DefaultParamspace) @@ -174,25 +174,24 @@ func NewSimApp( app.cdc, keys[auth.StoreKey], app.subspaces[auth.ModuleName], auth.ProtoBaseAccount, ) app.BankKeeper = bank.NewBaseKeeper( - app.AccountKeeper, app.subspaces[bank.ModuleName], bank.DefaultCodespace, - app.BlacklistedAccAddrs(), + app.AccountKeeper, app.subspaces[bank.ModuleName], app.BlacklistedAccAddrs(), ) app.SupplyKeeper = supply.NewKeeper( app.cdc, keys[supply.StoreKey], app.AccountKeeper, app.BankKeeper, maccPerms, ) stakingKeeper := staking.NewKeeper( app.cdc, keys[staking.StoreKey], app.SupplyKeeper, app.subspaces[staking.ModuleName], - staking.DefaultCodespace) + ) app.MintKeeper = mint.NewKeeper( app.cdc, keys[mint.StoreKey], app.subspaces[mint.ModuleName], &stakingKeeper, app.SupplyKeeper, auth.FeeCollectorName, ) app.DistrKeeper = distr.NewKeeper( app.cdc, keys[distr.StoreKey], app.subspaces[distr.ModuleName], &stakingKeeper, - app.SupplyKeeper, distr.DefaultCodespace, auth.FeeCollectorName, app.ModuleAccountAddrs(), + app.SupplyKeeper, auth.FeeCollectorName, app.ModuleAccountAddrs(), ) app.SlashingKeeper = slashing.NewKeeper( - app.cdc, keys[slashing.StoreKey], &stakingKeeper, app.subspaces[slashing.ModuleName], slashing.DefaultCodespace, + app.cdc, keys[slashing.StoreKey], &stakingKeeper, app.subspaces[slashing.ModuleName], ) app.CrisisKeeper = crisis.NewKeeper( app.subspaces[crisis.ModuleName], invCheckPeriod, app.SupplyKeeper, auth.FeeCollectorName, @@ -201,8 +200,7 @@ func NewSimApp( // create evidence keeper with router evidenceKeeper := evidence.NewKeeper( - app.cdc, keys[evidence.StoreKey], app.subspaces[evidence.ModuleName], evidence.DefaultCodespace, - &app.StakingKeeper, app.SlashingKeeper, + app.cdc, keys[evidence.StoreKey], app.subspaces[evidence.ModuleName], &app.StakingKeeper, app.SlashingKeeper, ) evidenceRouter := evidence.NewRouter() // TODO: Register evidence routes. @@ -217,7 +215,7 @@ func NewSimApp( AddRoute(upgrade.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(app.UpgradeKeeper)) app.GovKeeper = gov.NewKeeper( app.cdc, keys[gov.StoreKey], app.subspaces[gov.ModuleName], app.SupplyKeeper, - &stakingKeeper, gov.DefaultCodespace, govRouter, + &stakingKeeper, govRouter, ) // register the staking hooks diff --git a/simapp/test_helpers.go b/simapp/test_helpers.go index 0e6d22150255..d132394c9bc7 100644 --- a/simapp/test_helpers.go +++ b/simapp/test_helpers.go @@ -115,7 +115,7 @@ func CheckBalance(t *testing.T, app *SimApp, addr sdk.AccAddress, exp sdk.Coins) func SignCheckDeliver( t *testing.T, cdc *codec.Codec, app *bam.BaseApp, header abci.Header, msgs []sdk.Msg, accNums, seq []uint64, expSimPass, expPass bool, priv ...crypto.PrivKey, -) sdk.Result { +) (sdk.GasInfo, *sdk.Result, error) { tx := helpers.GenTx( msgs, @@ -131,28 +131,32 @@ func SignCheckDeliver( require.Nil(t, err) // Must simulate now as CheckTx doesn't run Msgs anymore - res := app.Simulate(txBytes, tx) + _, res, err := app.Simulate(txBytes, tx) if expSimPass { - require.Equal(t, sdk.CodeOK, res.Code, res.Log) + require.NoError(t, err) + require.NotNil(t, res) } else { - require.NotEqual(t, sdk.CodeOK, res.Code, res.Log) + require.Error(t, err) + require.Nil(t, res) } // Simulate a sending a transaction and committing a block app.BeginBlock(abci.RequestBeginBlock{Header: header}) - res = app.Deliver(tx) + gInfo, res, err := app.Deliver(tx) if expPass { - require.Equal(t, sdk.CodeOK, res.Code, res.Log) + require.NoError(t, err) + require.NotNil(t, res) } else { - require.NotEqual(t, sdk.CodeOK, res.Code, res.Log) + require.Error(t, err) + require.Nil(t, res) } app.EndBlock(abci.RequestEndBlock{}) app.Commit() - return res + return gInfo, res, err } // GenSequenceOfTxs generates a set of signed transactions of messages, such diff --git a/store/errors/errors.go b/store/errors/errors.go deleted file mode 100644 index 98e1b8aa1330..000000000000 --- a/store/errors/errors.go +++ /dev/null @@ -1,26 +0,0 @@ -package errors - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" -) - -const ( - CodeOK = sdk.CodeOK - CodeInternal = sdk.CodeInternal - CodeTxDecode = sdk.CodeTxDecode - CodeUnknownRequest = sdk.CodeUnknownRequest - - CodespaceRoot = sdk.CodespaceRoot -) - -type Error = sdk.Error - -func ErrInternal(msg string) Error { - return sdk.ErrInternal(msg) -} -func ErrTxDecode(msg string) Error { - return sdk.ErrTxDecode(msg) -} -func ErrUnknownRequest(msg string) Error { - return sdk.ErrUnknownRequest(msg) -} diff --git a/store/iavl/store.go b/store/iavl/store.go index b7b94307bbe6..2faf786cd236 100644 --- a/store/iavl/store.go +++ b/store/iavl/store.go @@ -1,14 +1,13 @@ package iavl import ( - "fmt" "io" "sync" "github.com/cosmos/cosmos-sdk/store/cachekv" - serrors "github.com/cosmos/cosmos-sdk/store/errors" "github.com/cosmos/cosmos-sdk/store/tracekv" "github.com/cosmos/cosmos-sdk/store/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/pkg/errors" "github.com/tendermint/iavl" @@ -236,8 +235,7 @@ func getHeight(tree Tree, req abci.RequestQuery) int64 { // explicitly set the height you want to see func (st *Store) Query(req abci.RequestQuery) (res abci.ResponseQuery) { if len(req.Data) == 0 { - msg := "Query cannot be zero length" - return serrors.ErrTxDecode(msg).QueryResult() + return sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrTxDecode, "query cannot be zero length")) } tree := st.tree @@ -296,8 +294,7 @@ func (st *Store) Query(req abci.RequestQuery) (res abci.ResponseQuery) { res.Value = cdc.MustMarshalBinaryLengthPrefixed(KVs) default: - msg := fmt.Sprintf("Unexpected Query path: %v", req.Path) - return serrors.ErrUnknownRequest(msg).QueryResult() + return sdkerrors.QueryResult(sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unexpected query path: %v", req.Path)) } return res diff --git a/store/iavl/store_test.go b/store/iavl/store_test.go index b70be1dee138..d7c38aa0d548 100644 --- a/store/iavl/store_test.go +++ b/store/iavl/store_test.go @@ -11,7 +11,6 @@ import ( cmn "github.com/tendermint/tendermint/libs/common" dbm "github.com/tendermint/tm-db" - "github.com/cosmos/cosmos-sdk/store/errors" "github.com/cosmos/cosmos-sdk/store/types" ) @@ -497,7 +496,7 @@ func TestIAVLStoreQuery(t *testing.T) { // query subspace before anything set qres := iavlStore.Query(querySub) - require.Equal(t, uint32(errors.CodeOK), qres.Code) + require.Equal(t, uint32(0), qres.Code) require.Equal(t, valExpSubEmpty, qres.Value) // set data @@ -506,24 +505,24 @@ func TestIAVLStoreQuery(t *testing.T) { // set data without commit, doesn't show up qres = iavlStore.Query(query) - require.Equal(t, uint32(errors.CodeOK), qres.Code) + require.Equal(t, uint32(0), qres.Code) require.Nil(t, qres.Value) // commit it, but still don't see on old version cid = iavlStore.Commit() qres = iavlStore.Query(query) - require.Equal(t, uint32(errors.CodeOK), qres.Code) + require.Equal(t, uint32(0), qres.Code) require.Nil(t, qres.Value) // but yes on the new version query.Height = cid.Version qres = iavlStore.Query(query) - require.Equal(t, uint32(errors.CodeOK), qres.Code) + require.Equal(t, uint32(0), qres.Code) require.Equal(t, v1, qres.Value) // and for the subspace qres = iavlStore.Query(querySub) - require.Equal(t, uint32(errors.CodeOK), qres.Code) + require.Equal(t, uint32(0), qres.Code) require.Equal(t, valExpSub1, qres.Value) // modify @@ -532,28 +531,28 @@ func TestIAVLStoreQuery(t *testing.T) { // query will return old values, as height is fixed qres = iavlStore.Query(query) - require.Equal(t, uint32(errors.CodeOK), qres.Code) + require.Equal(t, uint32(0), qres.Code) require.Equal(t, v1, qres.Value) // update to latest in the query and we are happy query.Height = cid.Version qres = iavlStore.Query(query) - require.Equal(t, uint32(errors.CodeOK), qres.Code) + require.Equal(t, uint32(0), qres.Code) require.Equal(t, v3, qres.Value) query2 := abci.RequestQuery{Path: "/key", Data: k2, Height: cid.Version} qres = iavlStore.Query(query2) - require.Equal(t, uint32(errors.CodeOK), qres.Code) + require.Equal(t, uint32(0), qres.Code) require.Equal(t, v2, qres.Value) // and for the subspace qres = iavlStore.Query(querySub) - require.Equal(t, uint32(errors.CodeOK), qres.Code) + require.Equal(t, uint32(0), qres.Code) require.Equal(t, valExpSub2, qres.Value) // default (height 0) will show latest -1 query0 := abci.RequestQuery{Path: "/key", Data: k1} qres = iavlStore.Query(query0) - require.Equal(t, uint32(errors.CodeOK), qres.Code) + require.Equal(t, uint32(0), qres.Code) require.Equal(t, v1, qres.Value) } diff --git a/store/rootmulti/store.go b/store/rootmulti/store.go index 4f3d212e4914..0b22d5442cb0 100644 --- a/store/rootmulti/store.go +++ b/store/rootmulti/store.go @@ -12,11 +12,11 @@ import ( "github.com/cosmos/cosmos-sdk/store/cachemulti" "github.com/cosmos/cosmos-sdk/store/dbadapter" - "github.com/cosmos/cosmos-sdk/store/errors" "github.com/cosmos/cosmos-sdk/store/iavl" "github.com/cosmos/cosmos-sdk/store/tracekv" "github.com/cosmos/cosmos-sdk/store/transient" "github.com/cosmos/cosmos-sdk/store/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) const ( @@ -408,19 +408,17 @@ func (rs *Store) Query(req abci.RequestQuery) abci.ResponseQuery { path := req.Path storeName, subpath, err := parsePath(path) if err != nil { - return err.QueryResult() + return sdkerrors.QueryResult(err) } store := rs.getStoreByName(storeName) if store == nil { - msg := fmt.Sprintf("no such store: %s", storeName) - return errors.ErrUnknownRequest(msg).QueryResult() + return sdkerrors.QueryResult(sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "no such store: %s", storeName)) } queryable, ok := store.(types.Queryable) if !ok { - msg := fmt.Sprintf("store %s (type %T) doesn't support queries", storeName, store) - return errors.ErrUnknownRequest(msg).QueryResult() + return sdkerrors.QueryResult(sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "store %s (type %T) doesn't support queries", storeName, store)) } // trim the path and make the query @@ -432,12 +430,12 @@ func (rs *Store) Query(req abci.RequestQuery) abci.ResponseQuery { } if res.Proof == nil || len(res.Proof.Ops) == 0 { - return errors.ErrInternal("proof is unexpectedly empty; ensure height has not been pruned").QueryResult() + return sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "proof is unexpectedly empty; ensure height has not been pruned")) } commitInfo, errMsg := getCommitInfo(rs.db, res.Height) if errMsg != nil { - return errors.ErrInternal(errMsg.Error()).QueryResult() + return sdkerrors.QueryResult(err) } // Restore origin path and append proof op. @@ -454,10 +452,9 @@ func (rs *Store) Query(req abci.RequestQuery) abci.ResponseQuery { // parsePath expects a format like /[/] // Must start with /, subpath may be empty // Returns error if it doesn't start with / -func parsePath(path string) (storeName string, subpath string, err errors.Error) { +func parsePath(path string) (storeName string, subpath string, err error) { if !strings.HasPrefix(path, "/") { - err = errors.ErrUnknownRequest(fmt.Sprintf("invalid path: %s", path)) - return + return storeName, subpath, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid path: %s", path) } paths := strings.SplitN(path[1:], "/", 2) @@ -467,7 +464,7 @@ func parsePath(path string) (storeName string, subpath string, err errors.Error) subpath = "/" + paths[1] } - return + return storeName, subpath, nil } //---------------------------------------- diff --git a/store/rootmulti/store_test.go b/store/rootmulti/store_test.go index 47b2ece360a0..16181c4080f2 100644 --- a/store/rootmulti/store_test.go +++ b/store/rootmulti/store_test.go @@ -8,9 +8,9 @@ import ( "github.com/tendermint/tendermint/crypto/merkle" dbm "github.com/tendermint/tm-db" - "github.com/cosmos/cosmos-sdk/store/errors" "github.com/cosmos/cosmos-sdk/store/iavl" "github.com/cosmos/cosmos-sdk/store/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) func TestStoreType(t *testing.T) { @@ -324,37 +324,37 @@ func TestMultiStoreQuery(t *testing.T) { // Test bad path. query := abci.RequestQuery{Path: "/key", Data: k, Height: ver} qres := multi.Query(query) - require.EqualValues(t, errors.CodeUnknownRequest, qres.Code) - require.EqualValues(t, errors.CodespaceRoot, qres.Codespace) + require.EqualValues(t, sdkerrors.ErrUnknownRequest.ABCICode(), qres.Code) + require.EqualValues(t, sdkerrors.ErrUnknownRequest.Codespace(), qres.Codespace) query.Path = "h897fy32890rf63296r92" qres = multi.Query(query) - require.EqualValues(t, errors.CodeUnknownRequest, qres.Code) - require.EqualValues(t, errors.CodespaceRoot, qres.Codespace) + require.EqualValues(t, sdkerrors.ErrUnknownRequest.ABCICode(), qres.Code) + require.EqualValues(t, sdkerrors.ErrUnknownRequest.Codespace(), qres.Codespace) // Test invalid store name. query.Path = "/garbage/key" qres = multi.Query(query) - require.EqualValues(t, errors.CodeUnknownRequest, qres.Code) - require.EqualValues(t, errors.CodespaceRoot, qres.Codespace) + require.EqualValues(t, sdkerrors.ErrUnknownRequest.ABCICode(), qres.Code) + require.EqualValues(t, sdkerrors.ErrUnknownRequest.Codespace(), qres.Codespace) // Test valid query with data. query.Path = "/store1/key" qres = multi.Query(query) - require.EqualValues(t, errors.CodeOK, qres.Code) + require.EqualValues(t, 0, qres.Code) require.Equal(t, v, qres.Value) // Test valid but empty query. query.Path = "/store2/key" query.Prove = true qres = multi.Query(query) - require.EqualValues(t, errors.CodeOK, qres.Code) + require.EqualValues(t, 0, qres.Code) require.Nil(t, qres.Value) // Test store2 data. query.Data = k2 qres = multi.Query(query) - require.EqualValues(t, errors.CodeOK, qres.Code) + require.EqualValues(t, 0, qres.Code) require.Equal(t, v2, qres.Value) } diff --git a/types/decimal.go b/types/decimal.go index b066c3e43374..63aecf6cab18 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -2,6 +2,7 @@ package types import ( "encoding/json" + "errors" "fmt" "math/big" "strconv" @@ -33,6 +34,13 @@ var ( tenInt = big.NewInt(10) ) +// Decimal errors +var ( + ErrEmptyDecimalStr = errors.New("decimal string cannot be empty") + ErrInvalidDecimalLength = errors.New("invalid decimal length") + ErrInvalidDecimalStr = errors.New("invalid decimal string") +) + // Set precision multipliers func init() { precisionMultipliers = make([]*big.Int, Precision+1) @@ -123,9 +131,9 @@ func NewDecFromIntWithPrec(i Int, prec int64) Dec { // are provided in the string than the constant Precision. // // CONTRACT - This function does not mutate the input str. -func NewDecFromStr(str string) (d Dec, err Error) { +func NewDecFromStr(str string) (Dec, error) { if len(str) == 0 { - return d, ErrUnknownRequest("decimal string is empty") + return Dec{}, ErrEmptyDecimalStr } // first extract any negative symbol @@ -136,7 +144,7 @@ func NewDecFromStr(str string) (d Dec, err Error) { } if len(str) == 0 { - return d, ErrUnknownRequest("decimal string is empty") + return Dec{}, ErrEmptyDecimalStr } strs := strings.Split(str, ".") @@ -146,17 +154,16 @@ func NewDecFromStr(str string) (d Dec, err Error) { if len(strs) == 2 { // has a decimal place lenDecs = len(strs[1]) if lenDecs == 0 || len(combinedStr) == 0 { - return d, ErrUnknownRequest("bad decimal length") + return Dec{}, ErrInvalidDecimalLength } combinedStr += strs[1] } else if len(strs) > 2 { - return d, ErrUnknownRequest("too many periods to be a decimal string") + return Dec{}, ErrInvalidDecimalStr } if lenDecs > Precision { - return d, ErrUnknownRequest( - fmt.Sprintf("too much precision, maximum %v, len decimal %v", Precision, lenDecs)) + return Dec{}, fmt.Errorf("invalid precision; max: %d, got: %d", Precision, lenDecs) } // add some extra zero's to correct to the Precision factor @@ -166,11 +173,12 @@ func NewDecFromStr(str string) (d Dec, err Error) { combined, ok := new(big.Int).SetString(combinedStr, 10) // base 10 if !ok { - return d, ErrUnknownRequest(fmt.Sprintf("bad string to integer conversion, combinedStr: %v", combinedStr)) + return Dec{}, fmt.Errorf("failed to set decimal string: %s", combinedStr) } if neg { combined = new(big.Int).Neg(combined) } + return Dec{combined}, nil } diff --git a/types/errors.go b/types/errors.go deleted file mode 100644 index c59571bfe540..000000000000 --- a/types/errors.go +++ /dev/null @@ -1,361 +0,0 @@ -package types - -import ( - "bytes" - "encoding/json" - "fmt" - "strings" - - "github.com/pkg/errors" - - abci "github.com/tendermint/tendermint/abci/types" - cmn "github.com/tendermint/tendermint/libs/common" - - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" -) - -// CodeType - ABCI code identifier within codespace -type CodeType uint32 - -// CodespaceType - codespace identifier -type CodespaceType string - -// IsOK - is everything okay? -func (code CodeType) IsOK() bool { - return code == CodeOK -} - -// SDK error codes -const ( - // Base error codes - CodeOK CodeType = 0 - CodeInternal CodeType = 1 - CodeTxDecode CodeType = 2 - CodeInvalidSequence CodeType = 3 - CodeUnauthorized CodeType = 4 - CodeInsufficientFunds CodeType = 5 - CodeUnknownRequest CodeType = 6 - CodeInvalidAddress CodeType = 7 - CodeInvalidPubKey CodeType = 8 - CodeUnknownAddress CodeType = 9 - CodeInsufficientCoins CodeType = 10 - CodeInvalidCoins CodeType = 11 - CodeOutOfGas CodeType = 12 - CodeMemoTooLarge CodeType = 13 - CodeInsufficientFee CodeType = 14 - CodeTooManySignatures CodeType = 15 - CodeGasOverflow CodeType = 16 - CodeNoSignatures CodeType = 17 - CodeTxInMempoolCache CodeType = 18 - CodeMempoolIsFull CodeType = 19 - CodeTxTooLarge CodeType = 20 - - // CodespaceRoot is a codespace for error codes in this file only. - // Notice that 0 is an "unset" codespace, which can be overridden with - // Error.WithDefaultCodespace(). - CodespaceUndefined CodespaceType = "" - CodespaceRoot CodespaceType = "sdk" -) - -func unknownCodeMsg(code CodeType) string { - return fmt.Sprintf("unknown code %d", code) -} - -// NOTE: Don't stringer this, we'll put better messages in later. -func CodeToDefaultMsg(code CodeType) string { - switch code { - case CodeInternal: - return "internal error" - case CodeTxDecode: - return "tx parse error" - case CodeInvalidSequence: - return "invalid sequence" - case CodeUnauthorized: - return "unauthorized" - case CodeInsufficientFunds: - return "insufficient funds" - case CodeUnknownRequest: - return "unknown request" - case CodeInvalidAddress: - return "invalid address" - case CodeInvalidPubKey: - return "invalid pubkey" - case CodeUnknownAddress: - return "unknown address" - case CodeInsufficientCoins: - return "insufficient coins" - case CodeInvalidCoins: - return "invalid coins" - case CodeOutOfGas: - return "out of gas" - case CodeMemoTooLarge: - return "memo too large" - case CodeInsufficientFee: - return "insufficient fee" - case CodeTooManySignatures: - return "maximum numer of signatures exceeded" - case CodeNoSignatures: - return "no signatures supplied" - default: - return unknownCodeMsg(code) - } -} - -//-------------------------------------------------------------------------------- -// All errors are created via constructors so as to enable us to hijack them -// and inject stack traces if we really want to. - -// nolint -func ErrInternal(msg string) Error { - return newErrorWithRootCodespace(CodeInternal, msg) -} -func ErrTxDecode(msg string) Error { - return newErrorWithRootCodespace(CodeTxDecode, msg) -} -func ErrInvalidSequence(msg string) Error { - return newErrorWithRootCodespace(CodeInvalidSequence, msg) -} -func ErrUnauthorized(msg string) Error { - return newErrorWithRootCodespace(CodeUnauthorized, msg) -} -func ErrInsufficientFunds(msg string) Error { - return newErrorWithRootCodespace(CodeInsufficientFunds, msg) -} -func ErrUnknownRequest(msg string) Error { - return newErrorWithRootCodespace(CodeUnknownRequest, msg) -} -func ErrInvalidAddress(msg string) Error { - return newErrorWithRootCodespace(CodeInvalidAddress, msg) -} -func ErrUnknownAddress(msg string) Error { - return newErrorWithRootCodespace(CodeUnknownAddress, msg) -} -func ErrInvalidPubKey(msg string) Error { - return newErrorWithRootCodespace(CodeInvalidPubKey, msg) -} -func ErrInsufficientCoins(msg string) Error { - return newErrorWithRootCodespace(CodeInsufficientCoins, msg) -} -func ErrInvalidCoins(msg string) Error { - return newErrorWithRootCodespace(CodeInvalidCoins, msg) -} -func ErrOutOfGas(msg string) Error { - return newErrorWithRootCodespace(CodeOutOfGas, msg) -} -func ErrMemoTooLarge(msg string) Error { - return newErrorWithRootCodespace(CodeMemoTooLarge, msg) -} -func ErrInsufficientFee(msg string) Error { - return newErrorWithRootCodespace(CodeInsufficientFee, msg) -} -func ErrTooManySignatures(msg string) Error { - return newErrorWithRootCodespace(CodeTooManySignatures, msg) -} -func ErrNoSignatures(msg string) Error { - return newErrorWithRootCodespace(CodeNoSignatures, msg) -} -func ErrGasOverflow(msg string) Error { - return newErrorWithRootCodespace(CodeGasOverflow, msg) -} - -//---------------------------------------- -// Error & sdkError - -type cmnError = cmn.Error - -// sdk Error type -type Error interface { - // Implements cmn.Error - // Error() string - // Stacktrace() cmn.Error - // Trace(offset int, format string, args ...interface{}) cmn.Error - // Data() interface{} - cmnError - - // convenience - TraceSDK(format string, args ...interface{}) Error - - // set codespace - WithDefaultCodespace(CodespaceType) Error - - Code() CodeType - Codespace() CodespaceType - ABCILog() string - Result() Result - QueryResult() abci.ResponseQuery -} - -// NewError - create an error. -func NewError(codespace CodespaceType, code CodeType, format string, args ...interface{}) Error { - return newError(codespace, code, format, args...) -} - -func newErrorWithRootCodespace(code CodeType, format string, args ...interface{}) *sdkError { - return newError(CodespaceRoot, code, format, args...) -} - -func newError(codespace CodespaceType, code CodeType, format string, args ...interface{}) *sdkError { - if format == "" { - format = CodeToDefaultMsg(code) - } - return &sdkError{ - codespace: codespace, - code: code, - cmnError: cmn.NewError(format, args...), - } -} - -type sdkError struct { - codespace CodespaceType - code CodeType - cmnError -} - -// Implements Error. -func (err *sdkError) WithDefaultCodespace(cs CodespaceType) Error { - codespace := err.codespace - if codespace == CodespaceUndefined { - codespace = cs - } - return &sdkError{ - codespace: cs, - code: err.code, - cmnError: err.cmnError, - } -} - -// Implements ABCIError. -// nolint: errcheck -func (err *sdkError) TraceSDK(format string, args ...interface{}) Error { - err.Trace(1, format, args...) - return err -} - -// Implements ABCIError. -func (err *sdkError) Error() string { - return fmt.Sprintf(`ERROR: -Codespace: %s -Code: %d -Message: %#v -`, err.codespace, err.code, err.cmnError.Error()) -} - -// Implements Error. -func (err *sdkError) Codespace() CodespaceType { - return err.codespace -} - -// Implements Error. -func (err *sdkError) Code() CodeType { - return err.code -} - -// Implements ABCIError. -func (err *sdkError) ABCILog() string { - errMsg := err.cmnError.Error() - return encodeErrorLog(err.codespace, err.code, errMsg) -} - -func encodeErrorLog(codespace CodespaceType, code CodeType, msg string) string { - jsonErr := humanReadableError{ - Codespace: codespace, - Code: code, - Message: msg, - } - - var buff bytes.Buffer - enc := json.NewEncoder(&buff) - enc.SetEscapeHTML(false) - - if err := enc.Encode(jsonErr); err != nil { - panic(errors.Wrap(err, "failed to encode ABCI error log")) - } - - return strings.TrimSpace(buff.String()) -} - -func (err *sdkError) Result() Result { - return Result{ - Code: err.Code(), - Codespace: err.Codespace(), - Log: err.ABCILog(), - } -} - -// QueryResult allows us to return sdk.Error.QueryResult() in query responses -func (err *sdkError) QueryResult() abci.ResponseQuery { - return abci.ResponseQuery{ - Code: uint32(err.Code()), - Codespace: string(err.Codespace()), - Log: err.ABCILog(), - } -} - -// ResultFromError will return err.Result() if it implements sdk.Error -// Otherwise, it will use the reflecton from types/error to determine -// the code, codespace, and log. -// -// This is intended to provide a bridge to allow both error types -// to live side-by-side. -func ResultFromError(err error) Result { - if sdk, ok := err.(Error); ok { - return sdk.Result() - } - space, code, log := sdkerrors.ABCIInfo(err, false) - return Result{ - Codespace: CodespaceType(space), - Code: CodeType(code), - Log: encodeErrorLog(CodespaceType(space), CodeType(code), log), - } -} - -// ConvertError accepts a standard error and attempts to convert it to an sdk.Error. -// If the given error is already an sdk.Error, it'll simply be returned. Otherwise, -// it'll convert it to a types.Error. This is meant to provide a migration path -// away from sdk.Error in favor of types.Error. -func ConvertError(err error) Error { - if err == nil { - return nil - } - if sdkError, ok := err.(Error); ok { - return sdkError - } - - space, code, log := sdkerrors.ABCIInfo(err, false) - return NewError(CodespaceType(space), CodeType(code), log) -} - -//---------------------------------------- -// REST error utilities - -// appends a message to the head of the given error -func AppendMsgToErr(msg string, err string) string { - msgIdx := strings.Index(err, "message\":\"") - if msgIdx != -1 { - errMsg := err[msgIdx+len("message\":\"") : len(err)-2] - errMsg = fmt.Sprintf("%s; %s", msg, errMsg) - return fmt.Sprintf("%s%s%s", - err[:msgIdx+len("message\":\"")], - errMsg, - err[len(err)-2:], - ) - } - return fmt.Sprintf("%s; %s", msg, err) -} - -// returns the index of the message in the ABCI Log -// nolint:deadcode,unused -func mustGetMsgIndex(abciLog string) int { - msgIdx := strings.Index(abciLog, "message\":\"") - if msgIdx == -1 { - panic(fmt.Sprintf("invalid error format: %s", abciLog)) - } - return msgIdx + len("message\":\"") -} - -// parses the error into an object-like struct for exporting -type humanReadableError struct { - Codespace CodespaceType `json:"codespace"` - Code CodeType `json:"code"` - Message string `json:"message"` -} diff --git a/types/errors/abci.go b/types/errors/abci.go index 1f70758cdd1b..cc5633543192 100644 --- a/types/errors/abci.go +++ b/types/errors/abci.go @@ -4,6 +4,8 @@ import ( "errors" "fmt" "reflect" + + abci "github.com/tendermint/tendermint/abci/types" ) const ( @@ -40,6 +42,43 @@ func ABCIInfo(err error, debug bool) (codespace string, code uint32, log string) return abciCodespace(err), abciCode(err), encode(err) } +// ResponseCheckTx returns an ABCI ResponseCheckTx object with fields filled in +// from the given error and gas values. +func ResponseCheckTx(err error, gw, gu uint64) abci.ResponseCheckTx { + space, code, log := ABCIInfo(err, false) + return abci.ResponseCheckTx{ + Codespace: space, + Code: code, + Log: log, + GasWanted: int64(gw), + GasUsed: int64(gu), + } +} + +// ResponseDeliverTx returns an ABCI ResponseDeliverTx object with fields filled in +// from the given error and gas values. +func ResponseDeliverTx(err error, gw, gu uint64) abci.ResponseDeliverTx { + space, code, log := ABCIInfo(err, false) + return abci.ResponseDeliverTx{ + Codespace: space, + Code: code, + Log: log, + GasWanted: int64(gw), + GasUsed: int64(gu), + } +} + +// QueryResult returns a ResponseQuery from an error. It will try to parse ABCI +// info from the error. +func QueryResult(err error) abci.ResponseQuery { + space, code, log := ABCIInfo(err, false) + return abci.ResponseQuery{ + Codespace: space, + Code: code, + Log: log, + } +} + // The debugErrEncoder encodes the error with a stacktrace. func debugErrEncoder(err error) string { return fmt.Sprintf("%+v", err) diff --git a/types/errors/abci_test.go b/types/errors/abci_test.go index 20b4f74b6f8b..c098811ea474 100644 --- a/types/errors/abci_test.go +++ b/types/errors/abci_test.go @@ -15,17 +15,17 @@ func TestABCInfo(t *testing.T) { wantSpace string wantLog string }{ - "plain weave error": { + "plain SDK error": { err: ErrUnauthorized, debug: false, wantLog: "unauthorized", wantCode: ErrUnauthorized.code, wantSpace: RootCodespace, }, - "wrapped weave error": { + "wrapped SDK error": { err: Wrap(Wrap(ErrUnauthorized, "foo"), "bar"), debug: false, - wantLog: "bar: foo: unauthorized", + wantLog: "unauthorized: foo: bar", wantCode: ErrUnauthorized.code, wantSpace: RootCodespace, }, @@ -36,7 +36,7 @@ func TestABCInfo(t *testing.T) { wantCode: 0, wantSpace: "", }, - "nil weave error is not an error": { + "nil SDK error is not an error": { err: (*Error)(nil), debug: false, wantLog: "", @@ -112,23 +112,23 @@ func TestABCIInfoStacktrace(t *testing.T) { wantStacktrace bool wantErrMsg string }{ - "wrapped weave error in debug mode provides stacktrace": { + "wrapped SDK error in debug mode provides stacktrace": { err: Wrap(ErrUnauthorized, "wrapped"), debug: true, wantStacktrace: true, - wantErrMsg: "wrapped: unauthorized", + wantErrMsg: "unauthorized: wrapped", }, - "wrapped weave error in non-debug mode does not have stacktrace": { + "wrapped SDK error in non-debug mode does not have stacktrace": { err: Wrap(ErrUnauthorized, "wrapped"), debug: false, wantStacktrace: false, - wantErrMsg: "wrapped: unauthorized", + wantErrMsg: "unauthorized: wrapped", }, "wrapped stdlib error in debug mode provides stacktrace": { err: Wrap(fmt.Errorf("stdlib"), "wrapped"), debug: true, wantStacktrace: true, - wantErrMsg: "wrapped: stdlib", + wantErrMsg: "stdlib: wrapped", }, "wrapped stdlib error in non-debug mode does not have stacktrace": { err: Wrap(fmt.Errorf("stdlib"), "wrapped"), @@ -163,7 +163,7 @@ func TestABCIInfoHidesStacktrace(t *testing.T) { err := Wrap(ErrUnauthorized, "wrapped") _, _, log := ABCIInfo(err, false) - if log != "wrapped: unauthorized" { + if log != "unauthorized: wrapped" { t.Fatalf("unexpected message in non debug mode: %s", log) } } @@ -173,7 +173,7 @@ func TestRedact(t *testing.T) { t.Error("reduct must not pass through panic error") } if err := Redact(ErrUnauthorized); !ErrUnauthorized.Is(err) { - t.Error("reduct should pass through weave error") + t.Error("reduct should pass through SDK error") } var cerr customErr @@ -203,12 +203,12 @@ func TestABCIInfoSerializeErr(t *testing.T) { "single error": { src: myErrDecode, debug: false, - exp: "test: tx parse error", + exp: "tx parse error: test", }, "second error": { src: myErrAddr, debug: false, - exp: "tester: invalid address", + exp: "invalid address: tester", }, "single error with debug": { src: myErrDecode, diff --git a/types/errors/errors.go b/types/errors/errors.go index 22ed2f4c8c89..49624f784775 100644 --- a/types/errors/errors.go +++ b/types/errors/errors.go @@ -44,32 +44,43 @@ var ( // ErrUnknownAddress to doc ErrUnknownAddress = Register(RootCodespace, 9, "unknown address") - // ErrInsufficientCoins to doc (what is the difference between ErrInsufficientFunds???) - ErrInsufficientCoins = Register(RootCodespace, 10, "insufficient coins") - // ErrInvalidCoins to doc - ErrInvalidCoins = Register(RootCodespace, 11, "invalid coins") + ErrInvalidCoins = Register(RootCodespace, 10, "invalid coins") // ErrOutOfGas to doc - ErrOutOfGas = Register(RootCodespace, 12, "out of gas") + ErrOutOfGas = Register(RootCodespace, 11, "out of gas") // ErrMemoTooLarge to doc - ErrMemoTooLarge = Register(RootCodespace, 13, "memo too large") + ErrMemoTooLarge = Register(RootCodespace, 12, "memo too large") // ErrInsufficientFee to doc - ErrInsufficientFee = Register(RootCodespace, 14, "insufficient fee") + ErrInsufficientFee = Register(RootCodespace, 13, "insufficient fee") // ErrTooManySignatures to doc - ErrTooManySignatures = Register(RootCodespace, 15, "maximum numer of signatures exceeded") + ErrTooManySignatures = Register(RootCodespace, 14, "maximum number of signatures exceeded") // ErrNoSignatures to doc - ErrNoSignatures = Register(RootCodespace, 16, "no signatures supplied") + ErrNoSignatures = Register(RootCodespace, 15, "no signatures supplied") // ErrJSONMarshal defines an ABCI typed JSON marshalling error - ErrJSONMarshal = Register(RootCodespace, 17, "failed to marshal JSON bytes") + ErrJSONMarshal = Register(RootCodespace, 16, "failed to marshal JSON bytes") // ErrJSONUnmarshal defines an ABCI typed JSON unmarshalling error - ErrJSONUnmarshal = Register(RootCodespace, 18, "failed to unmarshal JSON bytes") + ErrJSONUnmarshal = Register(RootCodespace, 17, "failed to unmarshal JSON bytes") + + // ErrInvalidRequest defines an ABCI typed error where the request contains + // invalid data. + ErrInvalidRequest = Register(RootCodespace, 18, "invalid request") + + // ErrTxInMempoolCache defines an ABCI typed error where a tx already exists + // in the mempool. + ErrTxInMempoolCache = Register(RootCodespace, 19, "tx already in mempool") + + // ErrMempoolIsFull defines an ABCI typed error where the mempool is full. + ErrMempoolIsFull = Register(RootCodespace, 20, "mempool is full") + + // ErrTxTooLarge defines an ABCI typed error where tx is too large. + ErrTxTooLarge = Register(RootCodespace, 21, "tx too large") // ErrPanic is only set when we recover from a panic, so we know to // redact potentially sensitive system info @@ -89,12 +100,10 @@ func Register(codespace string, code uint32, description string) *Error { if e := getUsed(codespace, code); e != nil { panic(fmt.Sprintf("error with code %d is already registered: %q", code, e.desc)) } - err := &Error{ - code: code, - codespace: codespace, - desc: description, - } + + err := New(codespace, code, description) setUsed(err) + return err } @@ -247,7 +256,7 @@ type wrappedError struct { } func (e *wrappedError) Error() string { - return fmt.Sprintf("%s: %s", e.msg, e.parent.Error()) + return fmt.Sprintf("%s: %s", e.parent.Error(), e.msg) } func (e *wrappedError) Cause() error { diff --git a/types/errors/stacktrace_test.go b/types/errors/stacktrace_test.go index bef4bccb704e..042edc0b6919 100644 --- a/types/errors/stacktrace_test.go +++ b/types/errors/stacktrace_test.go @@ -15,19 +15,19 @@ func TestStackTrace(t *testing.T) { }{ "New gives us a stacktrace": { err: Wrap(ErrNoSignatures, "name"), - wantError: "name: no signatures supplied", + wantError: "no signatures supplied: name", }, "Wrapping stderr gives us a stacktrace": { err: Wrap(fmt.Errorf("foo"), "standard"), - wantError: "standard: foo", + wantError: "foo: standard", }, "Wrapping pkg/errors gives us clean stacktrace": { err: Wrap(errors.New("bar"), "pkg"), - wantError: "pkg: bar", + wantError: "bar: pkg", }, "Wrapping inside another function is still clean": { err: Wrap(fmt.Errorf("indirect"), "do the do"), - wantError: "do the do: indirect", + wantError: "indirect: do the do", }, } diff --git a/types/errors_test.go b/types/errors_test.go deleted file mode 100644 index 912de348a408..000000000000 --- a/types/errors_test.go +++ /dev/null @@ -1,138 +0,0 @@ -package types - -import ( - "fmt" - "testing" - - "github.com/stretchr/testify/require" - - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" -) - -var codeTypes = []CodeType{ - CodeInternal, - CodeTxDecode, - CodeInvalidSequence, - CodeUnauthorized, - CodeInsufficientFunds, - CodeUnknownRequest, - CodeInvalidAddress, - CodeInvalidPubKey, - CodeUnknownAddress, - CodeInsufficientCoins, - CodeInvalidCoins, - CodeOutOfGas, - CodeMemoTooLarge, -} - -type errFn func(msg string) Error - -var errFns = []errFn{ - ErrInternal, - ErrTxDecode, - ErrInvalidSequence, - ErrUnauthorized, - ErrInsufficientFunds, - ErrUnknownRequest, - ErrInvalidAddress, - ErrInvalidPubKey, - ErrUnknownAddress, - ErrInsufficientCoins, - ErrInvalidCoins, - ErrOutOfGas, - ErrMemoTooLarge, -} - -func TestCodeType(t *testing.T) { - require.True(t, CodeOK.IsOK()) - - for tcnum, c := range codeTypes { - msg := CodeToDefaultMsg(c) - require.NotEqual(t, unknownCodeMsg(c), msg, "Code expected to be known. tc #%d, code %d, msg %s", tcnum, c, msg) - } - - msg := CodeToDefaultMsg(CodeOK) - require.Equal(t, unknownCodeMsg(CodeOK), msg) -} - -func TestErrFn(t *testing.T) { - for i, errFn := range errFns { - err := errFn("") - codeType := codeTypes[i] - require.Equal(t, err.Code(), codeType, "Err function expected to return proper code. tc #%d", i) - require.Equal(t, err.Codespace(), CodespaceRoot, "Err function expected to return proper codespace. tc #%d", i) - require.Equal(t, err.QueryResult().Code, uint32(err.Code()), "Err function expected to return proper Code from QueryResult. tc #%d") - require.Equal(t, err.QueryResult().Log, err.ABCILog(), "Err function expected to return proper ABCILog from QueryResult. tc #%d") - } -} - -func TestAppendMsgToErr(t *testing.T) { - for i, errFn := range errFns { - err := errFn("") - errMsg := err.Stacktrace().Error() - abciLog := err.ABCILog() - - // plain msg error - msg := AppendMsgToErr("something unexpected happened", errMsg) - require.Equal( - t, - fmt.Sprintf("something unexpected happened; %s", errMsg), - msg, - fmt.Sprintf("Should have formatted the error message of ABCI Log. tc #%d", i), - ) - - // ABCI Log msg error - msg = AppendMsgToErr("something unexpected happened", abciLog) - msgIdx := mustGetMsgIndex(abciLog) - require.Equal( - t, - fmt.Sprintf("%s%s; %s}", - abciLog[:msgIdx], - "something unexpected happened", - abciLog[msgIdx:len(abciLog)-1], - ), - msg, - fmt.Sprintf("Should have formatted the error message of ABCI Log. tc #%d", i)) - } -} - -func TestResultFromError(t *testing.T) { - cases := map[string]struct { - err error - expect Result - }{ - "sdk.Error": { - err: ErrUnauthorized("not owner"), - expect: Result{ - Codespace: CodespaceRoot, - Code: CodeUnauthorized, - Log: `{"codespace":"sdk","code":4,"message":"not owner"}`, - }, - }, - "types/errors": { - err: sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "not owner"), - expect: Result{ - Codespace: CodespaceRoot, - Code: CodeUnauthorized, - Log: `{"codespace":"sdk","code":4,"message":"not owner: unauthorized"}`, - }, - }, - "stdlib errors": { - err: fmt.Errorf("not owner"), - expect: Result{ - Codespace: CodespaceType("undefined"), - Code: CodeInternal, - // note that we redact the internal errors in the new package to not leak eg. panics - Log: `{"codespace":"undefined","code":1,"message":"internal error"}`, - }, - }, - } - - for name, tc := range cases { - tc := tc - t.Run(name, func(t *testing.T) { - res := ResultFromError(tc.err) - require.Equal(t, tc.expect, res) - }) - } -} diff --git a/types/handler.go b/types/handler.go index d0cc41ec46dc..6815230a861f 100644 --- a/types/handler.go +++ b/types/handler.go @@ -1,7 +1,7 @@ package types // Handler defines the core of the state transition function of an application. -type Handler func(ctx Context, msg Msg) Result +type Handler func(ctx Context, msg Msg) (*Result, error) // AnteHandler authenticates transactions, before their internal messages are handled. // If newCtx.IsZero(), ctx is used instead. diff --git a/types/queryable.go b/types/queryable.go index 9223332bc833..f89965906af8 100644 --- a/types/queryable.go +++ b/types/queryable.go @@ -1,6 +1,9 @@ package types -import abci "github.com/tendermint/tendermint/abci/types" +import ( + abci "github.com/tendermint/tendermint/abci/types" +) -// Type for querier functions on keepers to implement to handle custom queries -type Querier = func(ctx Context, path []string, req abci.RequestQuery) (res []byte, err Error) +// Querier defines a function type that a module querier must implement to handle +// custom client queries. +type Querier = func(ctx Context, path []string, req abci.RequestQuery) ([]byte, error) diff --git a/types/result.go b/types/result.go index 41a31b84ba3c..8b9a28df502b 100644 --- a/types/result.go +++ b/types/result.go @@ -12,36 +12,27 @@ import ( ctypes "github.com/tendermint/tendermint/rpc/core/types" ) -// Result is the union of ResponseFormat and ResponseCheckTx. -type Result struct { - // Code is the response code, is stored back on the chain. - Code CodeType - - // Codespace is the string referring to the domain of an error - Codespace CodespaceType - - // Data is any data returned from the app. - // Data has to be length prefixed in order to separate - // results from multiple msgs executions - Data []byte - - // Log contains the txs log information. NOTE: nondeterministic. - Log string - +// GasInfo defines tx execution gas context. +type GasInfo struct { // GasWanted is the maximum units of work we allow this tx to perform. GasWanted uint64 // GasUsed is the amount of gas actually consumed. NOTE: unimplemented GasUsed uint64 - - // Events contains a slice of Event objects that were emitted during some - // execution. - Events Events } -// TODO: In the future, more codes may be OK. -func (res Result) IsOK() bool { - return res.Code.IsOK() +// Result is the union of ResponseFormat and ResponseCheckTx. +type Result struct { + // Data is any data returned from message or handler execution. It MUST be length + // prefixed in order to separate data from multiple message executions. + Data []byte + + // Log contains the log information from message or handler execution. + Log string + + // Events contains a slice of Event objects that were emitted during message or + // handler execution. + Events Events } // ABCIMessageLogs represents a slice of ABCIMessageLog. @@ -50,7 +41,6 @@ type ABCIMessageLogs []ABCIMessageLog // ABCIMessageLog defines a structure containing an indexed tx ABCI message log. type ABCIMessageLog struct { MsgIndex uint16 `json:"msg_index"` - Success bool `json:"success"` Log string `json:"log"` // Events contains a slice of Event objects that were emitted during some @@ -58,10 +48,9 @@ type ABCIMessageLog struct { Events StringEvents `json:"events"` } -func NewABCIMessageLog(i uint16, success bool, log string, events Events) ABCIMessageLog { +func NewABCIMessageLog(i uint16, log string, events Events) ABCIMessageLog { return ABCIMessageLog{ MsgIndex: i, - Success: success, Log: log, Events: StringifyEvents(events.ToABCIEvents()), } @@ -84,6 +73,7 @@ func (logs ABCIMessageLogs) String() (str string) { type TxResponse struct { Height int64 `json:"height"` TxHash string `json:"txhash"` + Codespace string `json:"codespace,omitempty"` Code uint32 `json:"code,omitempty"` Data string `json:"data,omitempty"` RawLog string `json:"raw_log,omitempty"` @@ -91,7 +81,6 @@ type TxResponse struct { Info string `json:"info,omitempty"` GasWanted int64 `json:"gas_wanted,omitempty"` GasUsed int64 `json:"gas_used,omitempty"` - Codespace string `json:"codespace,omitempty"` Tx Tx `json:"tx,omitempty"` Timestamp string `json:"timestamp,omitempty"` @@ -111,6 +100,7 @@ func NewResponseResultTx(res *ctypes.ResultTx, tx Tx, timestamp string) TxRespon return TxResponse{ TxHash: res.Hash.String(), Height: res.Height, + Codespace: res.TxResult.Codespace, Code: res.TxResult.Code, Data: strings.ToUpper(hex.EncodeToString(res.TxResult.Data)), RawLog: res.TxResult.Log, @@ -153,6 +143,7 @@ func newTxResponseCheckTx(res *ctypes.ResultBroadcastTxCommit) TxResponse { return TxResponse{ Height: res.Height, TxHash: txHash, + Codespace: res.CheckTx.Codespace, Code: res.CheckTx.Code, Data: strings.ToUpper(hex.EncodeToString(res.CheckTx.Data)), RawLog: res.CheckTx.Log, @@ -161,7 +152,6 @@ func newTxResponseCheckTx(res *ctypes.ResultBroadcastTxCommit) TxResponse { GasWanted: res.CheckTx.GasWanted, GasUsed: res.CheckTx.GasUsed, Events: StringifyEvents(res.CheckTx.Events), - Codespace: res.CheckTx.Codespace, } } @@ -180,6 +170,7 @@ func newTxResponseDeliverTx(res *ctypes.ResultBroadcastTxCommit) TxResponse { return TxResponse{ Height: res.Height, TxHash: txHash, + Codespace: res.DeliverTx.Codespace, Code: res.DeliverTx.Code, Data: strings.ToUpper(hex.EncodeToString(res.DeliverTx.Data)), RawLog: res.DeliverTx.Log, @@ -188,7 +179,6 @@ func newTxResponseDeliverTx(res *ctypes.ResultBroadcastTxCommit) TxResponse { GasWanted: res.DeliverTx.GasWanted, GasUsed: res.DeliverTx.GasUsed, Events: StringifyEvents(res.DeliverTx.Events), - Codespace: res.DeliverTx.Codespace, } } diff --git a/types/result_test.go b/types/result_test.go index c4fedc2992f3..bbdf3b75e70a 100644 --- a/types/result_test.go +++ b/types/result_test.go @@ -7,17 +7,6 @@ import ( "github.com/stretchr/testify/require" ) -func TestResult(t *testing.T) { - var res Result - require.True(t, res.IsOK()) - - res.Data = []byte("data") - require.True(t, res.IsOK()) - - res.Code = CodeType(1) - require.False(t, res.IsOK()) -} - func TestParseABCILog(t *testing.T) { logs := `[{"log":"","msg_index":1,"success":true}]` @@ -26,12 +15,11 @@ func TestParseABCILog(t *testing.T) { require.Len(t, res, 1) require.Equal(t, res[0].Log, "") require.Equal(t, res[0].MsgIndex, uint16(1)) - require.True(t, res[0].Success) } func TestABCIMessageLog(t *testing.T) { events := Events{NewEvent("transfer", NewAttribute("sender", "foo"))} - msgLog := NewABCIMessageLog(0, true, "", events) + msgLog := NewABCIMessageLog(0, "", events) msgLogs := ABCIMessageLogs{msgLog} bz, err := codec.Cdc.MarshalJSON(msgLogs) diff --git a/types/tx_msg.go b/types/tx_msg.go index bc4c2540d911..1b0da612b736 100644 --- a/types/tx_msg.go +++ b/types/tx_msg.go @@ -17,7 +17,7 @@ type Msg interface { // ValidateBasic does a simple validation check that // doesn't require access to any other information. - ValidateBasic() Error + ValidateBasic() error // Get the canonical byte representation of the Msg. GetSignBytes() []byte @@ -37,13 +37,13 @@ type Tx interface { // ValidateBasic does a simple and lightweight validation check that doesn't // require access to any other information. - ValidateBasic() Error + ValidateBasic() error } //__________________________________________________________ // TxDecoder unmarshals transaction bytes -type TxDecoder func(txBytes []byte) (Tx, Error) +type TxDecoder func(txBytes []byte) (Tx, error) // TxEncoder marshals transaction to bytes type TxEncoder func(tx Tx) ([]byte, error) @@ -73,7 +73,7 @@ func (msg *TestMsg) GetSignBytes() []byte { } return MustSortJSON(bz) } -func (msg *TestMsg) ValidateBasic() Error { return nil } +func (msg *TestMsg) ValidateBasic() error { return nil } func (msg *TestMsg) GetSigners() []AccAddress { return msg.signers } diff --git a/x/auth/ante/ante_test.go b/x/auth/ante/ante_test.go index 5ac42a6dc855..1d55b4d320c3 100644 --- a/x/auth/ante/ante_test.go +++ b/x/auth/ante/ante_test.go @@ -2,6 +2,7 @@ package ante_test import ( "encoding/json" + "errors" "fmt" "math/rand" "strings" @@ -26,14 +27,10 @@ func checkValidTx(t *testing.T, anteHandler sdk.AnteHandler, ctx sdk.Context, tx } // run the tx through the anteHandler and ensure it fails with the given code -func checkInvalidTx(t *testing.T, anteHandler sdk.AnteHandler, ctx sdk.Context, tx sdk.Tx, simulate bool, code sdk.CodeType) { +func checkInvalidTx(t *testing.T, anteHandler sdk.AnteHandler, ctx sdk.Context, tx sdk.Tx, simulate bool, expErr error) { _, err := anteHandler(ctx, tx, simulate) require.NotNil(t, err) - - result := sdk.ResultFromError(err) - - require.Equal(t, code, result.Code, fmt.Sprintf("Expected %v, got %v", code, result)) - require.Equal(t, sdk.CodespaceRoot, result.Codespace) + require.True(t, errors.Is(expErr, err)) } // Test that simulate transaction accurately estimates gas cost @@ -117,23 +114,23 @@ func TestAnteHandlerSigErrors(t *testing.T) { require.Equal(t, expectedSigners, stdTx.GetSigners()) // Check no signatures fails - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeNoSignatures) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrNoSignatures) // test num sigs dont match GetSigners privs, accNums, seqs = []crypto.PrivKey{priv1}, []uint64{0}, []uint64{0} tx = types.NewTestTx(ctx, msgs, privs, accNums, seqs, fee) - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeUnauthorized) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrUnauthorized) // test an unrecognized account privs, accNums, seqs = []crypto.PrivKey{priv1, priv2, priv3}, []uint64{0, 1, 2}, []uint64{0, 0, 0} tx = types.NewTestTx(ctx, msgs, privs, accNums, seqs, fee) - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeUnknownAddress) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrUnknownAddress) // save the first account, but second is still unrecognized acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) acc1.SetCoins(fee.Amount) app.AccountKeeper.SetAccount(ctx, acc1) - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeUnknownAddress) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrUnknownAddress) } // Test logic around account number checking with one signer and many signers. @@ -172,7 +169,7 @@ func TestAnteHandlerAccountNumbers(t *testing.T) { // new tx from wrong account number seqs = []uint64{1} tx = types.NewTestTx(ctx, msgs, privs, []uint64{1}, seqs, fee) - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeUnauthorized) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrUnauthorized) // from correct account number seqs = []uint64{1} @@ -185,7 +182,7 @@ func TestAnteHandlerAccountNumbers(t *testing.T) { msgs = []sdk.Msg{msg1, msg2} privs, accnums, seqs = []crypto.PrivKey{priv1, priv2}, []uint64{1, 0}, []uint64{2, 0} tx = types.NewTestTx(ctx, msgs, privs, accnums, seqs, fee) - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeUnauthorized) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrUnauthorized) // correct account numbers privs, accnums, seqs = []crypto.PrivKey{priv1, priv2}, []uint64{0, 1}, []uint64{2, 0} @@ -228,7 +225,7 @@ func TestAnteHandlerAccountNumbersAtBlockHeightZero(t *testing.T) { // new tx from wrong account number seqs = []uint64{1} tx = types.NewTestTx(ctx, msgs, privs, []uint64{1}, seqs, fee) - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeUnauthorized) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrUnauthorized) // from correct account number seqs = []uint64{1} @@ -241,7 +238,7 @@ func TestAnteHandlerAccountNumbersAtBlockHeightZero(t *testing.T) { msgs = []sdk.Msg{msg1, msg2} privs, accnums, seqs = []crypto.PrivKey{priv1, priv2}, []uint64{1, 0}, []uint64{2, 0} tx = types.NewTestTx(ctx, msgs, privs, accnums, seqs, fee) - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeUnauthorized) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrUnauthorized) // correct account numbers privs, accnums, seqs = []crypto.PrivKey{priv1, priv2}, []uint64{0, 0}, []uint64{2, 0} @@ -288,7 +285,7 @@ func TestAnteHandlerSequences(t *testing.T) { checkValidTx(t, anteHandler, ctx, tx, false) // test sending it again fails (replay protection) - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeUnauthorized) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrUnauthorized) // fix sequence, should pass seqs = []uint64{1} @@ -305,14 +302,14 @@ func TestAnteHandlerSequences(t *testing.T) { checkValidTx(t, anteHandler, ctx, tx, false) // replay fails - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeUnauthorized) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrUnauthorized) // tx from just second signer with incorrect sequence fails msg = types.NewTestMsg(addr2) msgs = []sdk.Msg{msg} privs, accnums, seqs = []crypto.PrivKey{priv2}, []uint64{1}, []uint64{0} tx = types.NewTestTx(ctx, msgs, privs, accnums, seqs, fee) - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeUnauthorized) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrUnauthorized) // fix the sequence and it passes tx = types.NewTestTx(ctx, msgs, []crypto.PrivKey{priv2}, []uint64{1}, []uint64{1}, fee) @@ -348,11 +345,11 @@ func TestAnteHandlerFees(t *testing.T) { // signer does not have enough funds to pay the fee tx = types.NewTestTx(ctx, msgs, privs, accnums, seqs, fee) - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInsufficientFunds) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrInsufficientFunds) acc1.SetCoins(sdk.NewCoins(sdk.NewInt64Coin("atom", 149))) app.AccountKeeper.SetAccount(ctx, acc1) - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInsufficientFunds) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrInsufficientFunds) require.True(t, app.SupplyKeeper.GetModuleAccount(ctx, types.FeeCollectorName).GetCoins().Empty()) require.True(sdk.IntEq(t, app.AccountKeeper.GetAccount(ctx, addr1).GetCoins().AmountOf("atom"), sdk.NewInt(149))) @@ -388,17 +385,17 @@ func TestAnteHandlerMemoGas(t *testing.T) { // tx does not have enough gas tx = types.NewTestTx(ctx, []sdk.Msg{msg}, privs, accnums, seqs, fee) - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeOutOfGas) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrOutOfGas) // tx with memo doesn't have enough gas fee = types.NewStdFee(801, sdk.NewCoins(sdk.NewInt64Coin("atom", 0))) tx = types.NewTestTxWithMemo(ctx, []sdk.Msg{msg}, privs, accnums, seqs, fee, "abcininasidniandsinasindiansdiansdinaisndiasndiadninsd") - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeOutOfGas) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrOutOfGas) // memo too large fee = types.NewStdFee(50000, sdk.NewCoins(sdk.NewInt64Coin("atom", 0))) tx = types.NewTestTxWithMemo(ctx, []sdk.Msg{msg}, privs, accnums, seqs, fee, strings.Repeat("01234567890", 500)) - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeMemoTooLarge) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrMemoTooLarge) // tx with memo has enough gas fee = types.NewStdFee(50000, sdk.NewCoins(sdk.NewInt64Coin("atom", 0))) @@ -492,7 +489,7 @@ func TestAnteHandlerBadSignBytes(t *testing.T) { chainID := ctx.ChainID() chainID2 := chainID + "somemorestuff" - codeUnauth := sdk.CodeUnauthorized + errUnauth := sdkerrors.ErrUnauthorized cases := []struct { chainID string @@ -500,14 +497,14 @@ func TestAnteHandlerBadSignBytes(t *testing.T) { seq uint64 fee types.StdFee msgs []sdk.Msg - code sdk.CodeType + err error }{ - {chainID2, 0, 1, fee, msgs, codeUnauth}, // test wrong chain_id - {chainID, 0, 2, fee, msgs, codeUnauth}, // test wrong seqs - {chainID, 1, 1, fee, msgs, codeUnauth}, // test wrong accnum - {chainID, 0, 1, fee, []sdk.Msg{types.NewTestMsg(addr2)}, codeUnauth}, // test wrong msg - {chainID, 0, 1, fee2, msgs, codeUnauth}, // test wrong fee - {chainID, 0, 1, fee3, msgs, codeUnauth}, // test wrong fee + {chainID2, 0, 1, fee, msgs, errUnauth}, // test wrong chain_id + {chainID, 0, 2, fee, msgs, errUnauth}, // test wrong seqs + {chainID, 1, 1, fee, msgs, errUnauth}, // test wrong accnum + {chainID, 0, 1, fee, []sdk.Msg{types.NewTestMsg(addr2)}, errUnauth}, // test wrong msg + {chainID, 0, 1, fee2, msgs, errUnauth}, // test wrong fee + {chainID, 0, 1, fee3, msgs, errUnauth}, // test wrong fee } privs, seqs = []crypto.PrivKey{priv1}, []uint64{1} @@ -517,20 +514,20 @@ func TestAnteHandlerBadSignBytes(t *testing.T) { types.StdSignBytes(cs.chainID, cs.accnum, cs.seq, cs.fee, cs.msgs, ""), "", ) - checkInvalidTx(t, anteHandler, ctx, tx, false, cs.code) + checkInvalidTx(t, anteHandler, ctx, tx, false, cs.err) } // test wrong signer if public key exist privs, accnums, seqs = []crypto.PrivKey{priv2}, []uint64{0}, []uint64{1} tx = types.NewTestTx(ctx, msgs, privs, accnums, seqs, fee) - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInvalidPubKey) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrInvalidPubKey) // test wrong signer if public doesn't exist msg = types.NewTestMsg(addr2) msgs = []sdk.Msg{msg} privs, accnums, seqs = []crypto.PrivKey{priv1}, []uint64{1}, []uint64{0} tx = types.NewTestTx(ctx, msgs, privs, accnums, seqs, fee) - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInvalidPubKey) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrInvalidPubKey) } func TestAnteHandlerSetPubKey(t *testing.T) { @@ -572,14 +569,14 @@ func TestAnteHandlerSetPubKey(t *testing.T) { tx = types.NewTestTx(ctx, msgs, privs, []uint64{1}, seqs, fee) sigs := tx.(types.StdTx).Signatures sigs[0].PubKey = nil - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInvalidPubKey) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrInvalidPubKey) acc2 = app.AccountKeeper.GetAccount(ctx, addr2) require.Nil(t, acc2.GetPubKey()) // test invalid signature and public key tx = types.NewTestTx(ctx, msgs, privs, []uint64{1}, seqs, fee) - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInvalidPubKey) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrInvalidPubKey) acc2 = app.AccountKeeper.GetAccount(ctx, addr2) require.Nil(t, acc2.GetPubKey()) @@ -686,7 +683,7 @@ func TestAnteHandlerSigLimitExceeded(t *testing.T) { privs, accnums, seqs := []crypto.PrivKey{priv1, priv2, priv3, priv4, priv5, priv6, priv7, priv8}, []uint64{0, 1, 2, 3, 4, 5, 6, 7}, []uint64{0, 0, 0, 0, 0, 0, 0, 0} tx = types.NewTestTx(ctx, msgs, privs, accnums, seqs, fee) - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeTooManySignatures) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrTooManySignatures) } // Test custom SignatureVerificationGasConsumer @@ -717,7 +714,7 @@ func TestCustomSignatureVerificationGasConsumer(t *testing.T) { fee := types.NewTestStdFee() msgs := []sdk.Msg{msg} tx = types.NewTestTx(ctx, msgs, privs, accnums, seqs, fee) - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInvalidPubKey) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrInvalidPubKey) // verify that an ed25519 account gets accepted priv2 := ed25519.GenPrivKey() diff --git a/x/auth/client/rest/query.go b/x/auth/client/rest/query.go index be094b6c69a4..77cba3e59c1e 100644 --- a/x/auth/client/rest/query.go +++ b/x/auth/client/rest/query.go @@ -61,8 +61,10 @@ func QueryTxsRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { err := r.ParseForm() if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, - sdk.AppendMsgToErr("could not parse query parameters", err.Error())) + rest.WriteErrorResponse( + w, http.StatusBadRequest, + fmt.Sprintf("failed to parse query parameters: %s", err), + ) return } diff --git a/x/auth/client/utils/tx.go b/x/auth/client/utils/tx.go index 7bdde2306518..55b7007002d9 100644 --- a/x/auth/client/utils/tx.go +++ b/x/auth/client/utils/tx.go @@ -278,12 +278,12 @@ func adjustGasEstimate(estimate uint64, adjustment float64) uint64 { } func parseQueryResponse(cdc *codec.Codec, rawRes []byte) (uint64, error) { - var simulationResult sdk.Result - if err := cdc.UnmarshalBinaryLengthPrefixed(rawRes, &simulationResult); err != nil { + var gasUsed uint64 + if err := cdc.UnmarshalBinaryLengthPrefixed(rawRes, &gasUsed); err != nil { return 0, err } - return simulationResult.GasUsed, nil + return gasUsed, nil } // PrepareTxBuilder populates a TxBuilder in preparation for the build of a Tx. diff --git a/x/auth/client/utils/tx_test.go b/x/auth/client/utils/tx_test.go index cde10cc56029..a9c33b232053 100644 --- a/x/auth/client/utils/tx_test.go +++ b/x/auth/client/utils/tx_test.go @@ -23,7 +23,7 @@ var ( func TestParseQueryResponse(t *testing.T) { cdc := makeCodec() - sdkResBytes := cdc.MustMarshalBinaryLengthPrefixed(sdk.Result{GasUsed: 10}) + sdkResBytes := cdc.MustMarshalBinaryLengthPrefixed(uint64(10)) gas, err := parseQueryResponse(cdc, sdkResBytes) assert.Equal(t, gas, uint64(10)) assert.Nil(t, err) @@ -39,14 +39,16 @@ func TestCalculateGas(t *testing.T) { if wantErr { return nil, 0, errors.New("") } - return cdc.MustMarshalBinaryLengthPrefixed(sdk.Result{GasUsed: gasUsed}), 0, nil + return cdc.MustMarshalBinaryLengthPrefixed(gasUsed), 0, nil } } + type args struct { queryFuncGasUsed uint64 queryFuncWantErr bool adjustment float64 } + tests := []struct { name string args args @@ -57,6 +59,7 @@ func TestCalculateGas(t *testing.T) { {"error", args{0, true, 1.2}, 0, 0, true}, {"adjusted gas", args{10, false, 1.2}, 10, 12, false}, } + for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { diff --git a/x/auth/keeper/keeper.go b/x/auth/keeper/keeper.go index d60a396d342b..244dec7c193b 100644 --- a/x/auth/keeper/keeper.go +++ b/x/auth/keeper/keeper.go @@ -8,6 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/auth/exported" "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/cosmos/cosmos-sdk/x/params/subspace" @@ -49,19 +50,19 @@ func (ak AccountKeeper) Logger(ctx sdk.Context) log.Logger { } // GetPubKey Returns the PubKey of the account at address -func (ak AccountKeeper) GetPubKey(ctx sdk.Context, addr sdk.AccAddress) (crypto.PubKey, sdk.Error) { +func (ak AccountKeeper) GetPubKey(ctx sdk.Context, addr sdk.AccAddress) (crypto.PubKey, error) { acc := ak.GetAccount(ctx, addr) if acc == nil { - return nil, sdk.ErrUnknownAddress(fmt.Sprintf("account %s does not exist", addr)) + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "account %s does not exist", addr) } return acc.GetPubKey(), nil } // GetSequence Returns the Sequence of the account at address -func (ak AccountKeeper) GetSequence(ctx sdk.Context, addr sdk.AccAddress) (uint64, sdk.Error) { +func (ak AccountKeeper) GetSequence(ctx sdk.Context, addr sdk.AccAddress) (uint64, error) { acc := ak.GetAccount(ctx, addr) if acc == nil { - return 0, sdk.ErrUnknownAddress(fmt.Sprintf("account %s does not exist", addr)) + return 0, sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "account %s does not exist", addr) } return acc.GetSequence(), nil } diff --git a/x/auth/keeper/querier.go b/x/auth/keeper/querier.go index b40dc0135d8f..28e505970b45 100644 --- a/x/auth/keeper/querier.go +++ b/x/auth/keeper/querier.go @@ -1,41 +1,40 @@ package keeper import ( - "fmt" - abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/auth/types" ) // NewQuerier creates a querier for auth REST endpoints func NewQuerier(keeper AccountKeeper) sdk.Querier { - return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, sdk.Error) { + return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) { switch path[0] { case types.QueryAccount: return queryAccount(ctx, req, keeper) default: - return nil, sdk.ErrUnknownRequest("unknown auth query endpoint") + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown query path: %s", path[0]) } } } -func queryAccount(ctx sdk.Context, req abci.RequestQuery, keeper AccountKeeper) ([]byte, sdk.Error) { +func queryAccount(ctx sdk.Context, req abci.RequestQuery, keeper AccountKeeper) ([]byte, error) { var params types.QueryAccountParams if err := keeper.cdc.UnmarshalJSON(req.Data, ¶ms); err != nil { - return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } account := keeper.GetAccount(ctx, params.Address) if account == nil { - return nil, sdk.ErrUnknownAddress(fmt.Sprintf("account %s does not exist", params.Address)) + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "account %s does not exist", params.Address) } bz, err := codec.MarshalJSONIndent(keeper.cdc, account) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return bz, nil diff --git a/x/auth/types/expected_keepers.go b/x/auth/types/expected_keepers.go index 11e03ef36cb8..499bc288c849 100644 --- a/x/auth/types/expected_keepers.go +++ b/x/auth/types/expected_keepers.go @@ -7,7 +7,7 @@ import ( // SupplyKeeper defines the expected supply Keeper (noalias) type SupplyKeeper interface { - SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) sdk.Error + SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error GetModuleAccount(ctx sdk.Context, moduleName string) exported.ModuleAccountI GetModuleAddress(moduleName string) sdk.AccAddress } diff --git a/x/auth/types/stdtx.go b/x/auth/types/stdtx.go index fa8b5d100d5f..bc6042abbbb2 100644 --- a/x/auth/types/stdtx.go +++ b/x/auth/types/stdtx.go @@ -10,6 +10,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/auth/exported" ) @@ -42,20 +43,29 @@ func (tx StdTx) GetMsgs() []sdk.Msg { return tx.Msgs } // ValidateBasic does a simple and lightweight validation check that doesn't // require access to any other information. -func (tx StdTx) ValidateBasic() sdk.Error { +func (tx StdTx) ValidateBasic() error { stdSigs := tx.GetSignatures() if tx.Fee.Gas > maxGasWanted { - return sdk.ErrGasOverflow(fmt.Sprintf("invalid gas supplied; %d > %d", tx.Fee.Gas, maxGasWanted)) + return sdkerrors.Wrapf( + sdkerrors.ErrInvalidRequest, + "invalid gas supplied; %d > %d", tx.Fee.Gas, maxGasWanted, + ) } if tx.Fee.Amount.IsAnyNegative() { - return sdk.ErrInsufficientFee(fmt.Sprintf("invalid fee %s amount provided", tx.Fee.Amount)) + return sdkerrors.Wrapf( + sdkerrors.ErrInsufficientFee, + "invalid fee provided: %s", tx.Fee.Amount, + ) } if len(stdSigs) == 0 { - return sdk.ErrNoSignatures("no signers") + return sdkerrors.ErrNoSignatures } if len(stdSigs) != len(tx.GetSigners()) { - return sdk.ErrUnauthorized("wrong number of signers") + return sdkerrors.Wrapf( + sdkerrors.ErrUnauthorized, + "wrong number of signers; expected %d, got %d", tx.GetSigners(), len(stdSigs), + ) } return nil @@ -240,18 +250,18 @@ type StdSignature struct { // DefaultTxDecoder logic for standard transaction decoding func DefaultTxDecoder(cdc *codec.Codec) sdk.TxDecoder { - return func(txBytes []byte) (sdk.Tx, sdk.Error) { + return func(txBytes []byte) (sdk.Tx, error) { var tx = StdTx{} if len(txBytes) == 0 { - return nil, sdk.ErrTxDecode("txBytes are empty") + return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "tx bytes are empty") } // StdTx.Msg is an interface. The concrete types // are registered by MakeTxCodec err := cdc.UnmarshalBinaryLengthPrefixed(txBytes, &tx) if err != nil { - return nil, sdk.ErrTxDecode("error decoding transaction").TraceSDK(err.Error()) + return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error()) } return tx, nil diff --git a/x/auth/types/stdtx_test.go b/x/auth/types/stdtx_test.go index 375a15c49cc4..8131006f59d5 100644 --- a/x/auth/types/stdtx_test.go +++ b/x/auth/types/stdtx_test.go @@ -13,6 +13,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) var ( @@ -78,7 +79,8 @@ func TestTxValidateBasic(t *testing.T) { err := tx.ValidateBasic() require.Error(t, err) - require.Equal(t, sdk.CodeInsufficientFee, err.Result().Code) + _, code, _ := sdkerrors.ABCIInfo(err, false) + require.Equal(t, sdkerrors.ErrInsufficientFee.ABCICode(), code) // require to fail validation when no signatures exist privs, accNums, seqs := []crypto.PrivKey{}, []uint64{}, []uint64{} @@ -86,7 +88,8 @@ func TestTxValidateBasic(t *testing.T) { err = tx.ValidateBasic() require.Error(t, err) - require.Equal(t, sdk.CodeNoSignatures, err.Result().Code) + _, code, _ = sdkerrors.ABCIInfo(err, false) + require.Equal(t, sdkerrors.ErrNoSignatures.ABCICode(), code) // require to fail validation when signatures do not match expected signers privs, accNums, seqs = []crypto.PrivKey{priv1}, []uint64{0, 1}, []uint64{0, 0} @@ -94,7 +97,8 @@ func TestTxValidateBasic(t *testing.T) { err = tx.ValidateBasic() require.Error(t, err) - require.Equal(t, sdk.CodeUnauthorized, err.Result().Code) + _, code, _ = sdkerrors.ABCIInfo(err, false) + require.Equal(t, sdkerrors.ErrUnauthorized.ABCICode(), code) // require to fail with invalid gas supplied badFee = NewTestStdFee() @@ -103,7 +107,8 @@ func TestTxValidateBasic(t *testing.T) { err = tx.ValidateBasic() require.Error(t, err) - require.Equal(t, sdk.CodeGasOverflow, err.Result().Code) + _, code, _ = sdkerrors.ABCIInfo(err, false) + require.Equal(t, sdkerrors.ErrInvalidRequest.ABCICode(), code) // require to pass when above criteria are matched privs, accNums, seqs = []crypto.PrivKey{priv1, priv2}, []uint64{0, 1}, []uint64{0, 0} diff --git a/x/bank/alias.go b/x/bank/alias.go index 3533e3084d9d..1ac7cecebd90 100644 --- a/x/bank/alias.go +++ b/x/bank/alias.go @@ -1,25 +1,19 @@ -// nolint -// autogenerated code using github.com/rigelrozanski/multitool -// aliases generated for the following subdirectories: -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/bank/internal/keeper -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/bank/internal/types package bank +// nolint + import ( "github.com/cosmos/cosmos-sdk/x/bank/internal/keeper" "github.com/cosmos/cosmos-sdk/x/bank/internal/types" ) const ( - QueryBalance = keeper.QueryBalance - DefaultCodespace = types.DefaultCodespace - CodeSendDisabled = types.CodeSendDisabled - CodeInvalidInputsOutputs = types.CodeInvalidInputsOutputs - ModuleName = types.ModuleName - QuerierRoute = types.QuerierRoute - RouterKey = types.RouterKey - DefaultParamspace = types.DefaultParamspace - DefaultSendEnabled = types.DefaultSendEnabled + QueryBalance = keeper.QueryBalance + ModuleName = types.ModuleName + QuerierRoute = types.QuerierRoute + RouterKey = types.RouterKey + DefaultParamspace = types.DefaultParamspace + DefaultSendEnabled = types.DefaultSendEnabled EventTypeTransfer = types.EventTypeTransfer AttributeKeyRecipient = types.AttributeKeyRecipient @@ -28,7 +22,6 @@ const ( ) var ( - // functions aliases RegisterInvariants = keeper.RegisterInvariants NonnegativeBalanceInvariant = keeper.NonnegativeBalanceInvariant NewBaseKeeper = keeper.NewBaseKeeper @@ -50,10 +43,8 @@ var ( ValidateInputsOutputs = types.ValidateInputsOutputs ParamKeyTable = types.ParamKeyTable NewQueryBalanceParams = types.NewQueryBalanceParams - - // variable aliases - ModuleCdc = types.ModuleCdc - ParamStoreKeySendEnabled = types.ParamStoreKeySendEnabled + ModuleCdc = types.ModuleCdc + ParamStoreKeySendEnabled = types.ParamStoreKeySendEnabled ) type ( diff --git a/x/bank/bench_test.go b/x/bank/bench_test.go index 9e0bd735484d..9161a88c31ba 100644 --- a/x/bank/bench_test.go +++ b/x/bank/bench_test.go @@ -34,10 +34,11 @@ func BenchmarkOneBankSendTxPerBlock(b *testing.B) { // Committing, and what time comes from Check/Deliver Tx. for i := 0; i < b.N; i++ { benchmarkApp.BeginBlock(abci.RequestBeginBlock{}) - x := benchmarkApp.Check(txs[i]) - if !x.IsOK() { + _, _, err := benchmarkApp.Check(txs[i]) + if err != nil { panic("something is broken in checking transaction") } + benchmarkApp.Deliver(txs[i]) benchmarkApp.EndBlock(abci.RequestEndBlock{}) benchmarkApp.Commit() @@ -63,10 +64,11 @@ func BenchmarkOneBankMultiSendTxPerBlock(b *testing.B) { // Committing, and what time comes from Check/Deliver Tx. for i := 0; i < b.N; i++ { benchmarkApp.BeginBlock(abci.RequestBeginBlock{}) - x := benchmarkApp.Check(txs[i]) - if !x.IsOK() { + _, _, err := benchmarkApp.Check(txs[i]) + if err != nil { panic("something is broken in checking transaction") } + benchmarkApp.Deliver(txs[i]) benchmarkApp.EndBlock(abci.RequestEndBlock{}) benchmarkApp.Commit() diff --git a/x/bank/handler.go b/x/bank/handler.go index 8e6133347715..3c83ec4c2af4 100644 --- a/x/bank/handler.go +++ b/x/bank/handler.go @@ -1,16 +1,15 @@ package bank import ( - "fmt" - sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/bank/internal/keeper" "github.com/cosmos/cosmos-sdk/x/bank/internal/types" ) // NewHandler returns a handler for "bank" type messages. func NewHandler(k keeper.Keeper) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { ctx = ctx.WithEventManager(sdk.NewEventManager()) switch msg := msg.(type) { @@ -21,25 +20,24 @@ func NewHandler(k keeper.Keeper) sdk.Handler { return handleMsgMultiSend(ctx, k, msg) default: - errMsg := fmt.Sprintf("unrecognized bank message type: %T", msg) - return sdk.ErrUnknownRequest(errMsg).Result() + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized bank message type: %T", msg) } } } // Handle MsgSend. -func handleMsgSend(ctx sdk.Context, k keeper.Keeper, msg types.MsgSend) sdk.Result { +func handleMsgSend(ctx sdk.Context, k keeper.Keeper, msg types.MsgSend) (*sdk.Result, error) { if !k.GetSendEnabled(ctx) { - return types.ErrSendDisabled(k.Codespace()).Result() + return nil, types.ErrSendDisabled } if k.BlacklistedAddr(msg.ToAddress) { - return sdk.ErrUnauthorized(fmt.Sprintf("%s is not allowed to receive transactions", msg.ToAddress)).Result() + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "%s is not allowed to receive transactions", msg.ToAddress) } err := k.SendCoins(ctx, msg.FromAddress, msg.ToAddress, msg.Amount) if err != nil { - return err.Result() + return nil, err } ctx.EventManager().EmitEvent( @@ -49,25 +47,25 @@ func handleMsgSend(ctx sdk.Context, k keeper.Keeper, msg types.MsgSend) sdk.Resu ), ) - return sdk.Result{Events: ctx.EventManager().Events()} + return &sdk.Result{Events: ctx.EventManager().Events()}, nil } // Handle MsgMultiSend. -func handleMsgMultiSend(ctx sdk.Context, k keeper.Keeper, msg types.MsgMultiSend) sdk.Result { +func handleMsgMultiSend(ctx sdk.Context, k keeper.Keeper, msg types.MsgMultiSend) (*sdk.Result, error) { // NOTE: totalIn == totalOut should already have been checked if !k.GetSendEnabled(ctx) { - return types.ErrSendDisabled(k.Codespace()).Result() + return nil, types.ErrSendDisabled } for _, out := range msg.Outputs { if k.BlacklistedAddr(out.Address) { - return sdk.ErrUnauthorized(fmt.Sprintf("%s is not allowed to receive transactions", out.Address)).Result() + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "%s is not allowed to receive transactions", out.Address) } } err := k.InputOutputCoins(ctx, msg.Inputs, msg.Outputs) if err != nil { - return err.Result() + return nil, err } ctx.EventManager().EmitEvent( @@ -77,5 +75,5 @@ func handleMsgMultiSend(ctx sdk.Context, k keeper.Keeper, msg types.MsgMultiSend ), ) - return sdk.Result{Events: ctx.EventManager().Events()} + return &sdk.Result{Events: ctx.EventManager().Events()}, nil } diff --git a/x/bank/handler_test.go b/x/bank/handler_test.go index 457afc8e69d9..f9d313385f0a 100644 --- a/x/bank/handler_test.go +++ b/x/bank/handler_test.go @@ -4,17 +4,20 @@ import ( "strings" "testing" + "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/stretchr/testify/require" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) func TestInvalidMsg(t *testing.T) { h := NewHandler(nil) - res := h(sdk.NewContext(nil, abci.Header{}, false, nil), sdk.NewTestMsg()) - require.False(t, res.IsOK()) - require.True(t, strings.Contains(res.Log, "unrecognized bank message type")) + res, err := h(sdk.NewContext(nil, abci.Header{}, false, nil), sdk.NewTestMsg()) + require.Error(t, err) + require.Nil(t, res) + + _, _, log := sdkerrors.ABCIInfo(err, false) + require.True(t, strings.Contains(log, "unrecognized bank message type")) } diff --git a/x/bank/internal/keeper/keeper.go b/x/bank/internal/keeper/keeper.go index cd0242e23f17..f36477f3c3b1 100644 --- a/x/bank/internal/keeper/keeper.go +++ b/x/bank/internal/keeper/keeper.go @@ -7,6 +7,7 @@ import ( "github.com/tendermint/tendermint/libs/log" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" vestexported "github.com/cosmos/cosmos-sdk/x/auth/vesting/exported" "github.com/cosmos/cosmos-sdk/x/bank/internal/types" @@ -20,8 +21,8 @@ var _ Keeper = (*BaseKeeper)(nil) type Keeper interface { SendKeeper - DelegateCoins(ctx sdk.Context, delegatorAddr, moduleAccAddr sdk.AccAddress, amt sdk.Coins) sdk.Error - UndelegateCoins(ctx sdk.Context, moduleAccAddr, delegatorAddr sdk.AccAddress, amt sdk.Coins) sdk.Error + DelegateCoins(ctx sdk.Context, delegatorAddr, moduleAccAddr sdk.AccAddress, amt sdk.Coins) error + UndelegateCoins(ctx sdk.Context, moduleAccAddr, delegatorAddr sdk.AccAddress, amt sdk.Coins) error } // BaseKeeper manages transfers between accounts. It implements the Keeper interface. @@ -33,13 +34,13 @@ type BaseKeeper struct { } // NewBaseKeeper returns a new BaseKeeper -func NewBaseKeeper(ak types.AccountKeeper, - paramSpace params.Subspace, - codespace sdk.CodespaceType, blacklistedAddrs map[string]bool) BaseKeeper { +func NewBaseKeeper( + ak types.AccountKeeper, paramSpace params.Subspace, blacklistedAddrs map[string]bool, +) BaseKeeper { ps := paramSpace.WithKeyTable(types.ParamKeyTable()) return BaseKeeper{ - BaseSendKeeper: NewBaseSendKeeper(ak, ps, codespace, blacklistedAddrs), + BaseSendKeeper: NewBaseSendKeeper(ak, ps, blacklistedAddrs), ak: ak, paramSpace: ps, } @@ -50,33 +51,32 @@ func NewBaseKeeper(ak types.AccountKeeper, // vesting and vested coins. // The coins are then transferred from the delegator address to a ModuleAccount address. // If any of the delegation amounts are negative, an error is returned. -func (keeper BaseKeeper) DelegateCoins(ctx sdk.Context, delegatorAddr, moduleAccAddr sdk.AccAddress, amt sdk.Coins) sdk.Error { - +func (keeper BaseKeeper) DelegateCoins(ctx sdk.Context, delegatorAddr, moduleAccAddr sdk.AccAddress, amt sdk.Coins) error { delegatorAcc := keeper.ak.GetAccount(ctx, delegatorAddr) if delegatorAcc == nil { - return sdk.ErrUnknownAddress(fmt.Sprintf("account %s does not exist", delegatorAddr)) + return sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "account %s does not exist", delegatorAddr) } moduleAcc := keeper.ak.GetAccount(ctx, moduleAccAddr) if moduleAcc == nil { - return sdk.ErrUnknownAddress(fmt.Sprintf("module account %s does not exist", moduleAccAddr)) + return sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", moduleAccAddr) } if !amt.IsValid() { - return sdk.ErrInvalidCoins(amt.String()) + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, amt.String()) } oldCoins := delegatorAcc.GetCoins() _, hasNeg := oldCoins.SafeSub(amt) if hasNeg { - return sdk.ErrInsufficientCoins( - fmt.Sprintf("insufficient account funds; %s < %s", oldCoins, amt), + return sdkerrors.Wrapf( + sdkerrors.ErrInsufficientFunds, "insufficient account funds; %s < %s", oldCoins, amt, ) } if err := trackDelegation(delegatorAcc, ctx.BlockHeader().Time, amt); err != nil { - return sdk.ErrInternal(fmt.Sprintf("failed to track delegation: %v", err)) + return sdkerrors.Wrap(err, "failed to track delegation") } keeper.ak.SetAccount(ctx, delegatorAcc) @@ -94,28 +94,27 @@ func (keeper BaseKeeper) DelegateCoins(ctx sdk.Context, delegatorAddr, moduleAcc // vesting and vested coins. // The coins are then transferred from a ModuleAccount address to the delegator address. // If any of the undelegation amounts are negative, an error is returned. -func (keeper BaseKeeper) UndelegateCoins(ctx sdk.Context, moduleAccAddr, delegatorAddr sdk.AccAddress, amt sdk.Coins) sdk.Error { - +func (keeper BaseKeeper) UndelegateCoins(ctx sdk.Context, moduleAccAddr, delegatorAddr sdk.AccAddress, amt sdk.Coins) error { delegatorAcc := keeper.ak.GetAccount(ctx, delegatorAddr) if delegatorAcc == nil { - return sdk.ErrUnknownAddress(fmt.Sprintf("account %s does not exist", delegatorAddr)) + return sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "account %s does not exist", delegatorAddr) } moduleAcc := keeper.ak.GetAccount(ctx, moduleAccAddr) if moduleAcc == nil { - return sdk.ErrUnknownAddress(fmt.Sprintf("module account %s does not exist", moduleAccAddr)) + return sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", moduleAccAddr) } if !amt.IsValid() { - return sdk.ErrInvalidCoins(amt.String()) + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, amt.String()) } oldCoins := moduleAcc.GetCoins() newCoins, hasNeg := oldCoins.SafeSub(amt) if hasNeg { - return sdk.ErrInsufficientCoins( - fmt.Sprintf("insufficient account funds; %s < %s", oldCoins, amt), + return sdkerrors.Wrapf( + sdkerrors.ErrInsufficientFunds, "insufficient account funds; %s < %s", oldCoins, amt, ) } @@ -125,7 +124,7 @@ func (keeper BaseKeeper) UndelegateCoins(ctx sdk.Context, moduleAccAddr, delegat } if err := trackUndelegation(delegatorAcc, amt); err != nil { - return sdk.ErrInternal(fmt.Sprintf("failed to track undelegation: %v", err)) + return sdkerrors.Wrap(err, "failed to track undelegation") } keeper.ak.SetAccount(ctx, delegatorAcc) @@ -137,12 +136,12 @@ func (keeper BaseKeeper) UndelegateCoins(ctx sdk.Context, moduleAccAddr, delegat type SendKeeper interface { ViewKeeper - InputOutputCoins(ctx sdk.Context, inputs []types.Input, outputs []types.Output) sdk.Error - SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) sdk.Error + InputOutputCoins(ctx sdk.Context, inputs []types.Input, outputs []types.Output) error + SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error - SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Error) - AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Error) - SetCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) sdk.Error + SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, error) + AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, error) + SetCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) error GetSendEnabled(ctx sdk.Context) bool SetSendEnabled(ctx sdk.Context, enabled bool) @@ -165,11 +164,12 @@ type BaseSendKeeper struct { } // NewBaseSendKeeper returns a new BaseSendKeeper. -func NewBaseSendKeeper(ak types.AccountKeeper, - paramSpace params.Subspace, codespace sdk.CodespaceType, blacklistedAddrs map[string]bool) BaseSendKeeper { +func NewBaseSendKeeper( + ak types.AccountKeeper, paramSpace params.Subspace, blacklistedAddrs map[string]bool, +) BaseSendKeeper { return BaseSendKeeper{ - BaseViewKeeper: NewBaseViewKeeper(ak, codespace), + BaseViewKeeper: NewBaseViewKeeper(ak), ak: ak, paramSpace: paramSpace, blacklistedAddrs: blacklistedAddrs, @@ -177,7 +177,7 @@ func NewBaseSendKeeper(ak types.AccountKeeper, } // InputOutputCoins handles a list of inputs and outputs -func (keeper BaseSendKeeper) InputOutputCoins(ctx sdk.Context, inputs []types.Input, outputs []types.Output) sdk.Error { +func (keeper BaseSendKeeper) InputOutputCoins(ctx sdk.Context, inputs []types.Input, outputs []types.Output) error { // Safety check ensuring that when sending coins the keeper must maintain the // Check supply invariant and validity of Coins. if err := types.ValidateInputsOutputs(inputs, outputs); err != nil { @@ -216,7 +216,7 @@ func (keeper BaseSendKeeper) InputOutputCoins(ctx sdk.Context, inputs []types.In } // SendCoins moves coins from one account to another -func (keeper BaseSendKeeper) SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) sdk.Error { +func (keeper BaseSendKeeper) SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error { ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( types.EventTypeTransfer, @@ -245,10 +245,9 @@ func (keeper BaseSendKeeper) SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, // SubtractCoins subtracts amt from the coins at the addr. // // CONTRACT: If the account is a vesting account, the amount has to be spendable. -func (keeper BaseSendKeeper) SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Error) { - +func (keeper BaseSendKeeper) SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, error) { if !amt.IsValid() { - return nil, sdk.ErrInvalidCoins(amt.String()) + return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, amt.String()) } oldCoins, spendableCoins := sdk.NewCoins(), sdk.NewCoins() @@ -263,8 +262,8 @@ func (keeper BaseSendKeeper) SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, // So the check here is sufficient instead of subtracting from oldCoins. _, hasNeg := spendableCoins.SafeSub(amt) if hasNeg { - return amt, sdk.ErrInsufficientCoins( - fmt.Sprintf("insufficient account funds; %s < %s", spendableCoins, amt), + return amt, sdkerrors.Wrapf( + sdkerrors.ErrInsufficientFunds, "insufficient account funds; %s < %s", spendableCoins, amt, ) } @@ -275,18 +274,17 @@ func (keeper BaseSendKeeper) SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, } // AddCoins adds amt to the coins at the addr. -func (keeper BaseSendKeeper) AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Error) { - +func (keeper BaseSendKeeper) AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, error) { if !amt.IsValid() { - return nil, sdk.ErrInvalidCoins(amt.String()) + return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, amt.String()) } oldCoins := keeper.GetCoins(ctx, addr) newCoins := oldCoins.Add(amt) if newCoins.IsAnyNegative() { - return amt, sdk.ErrInsufficientCoins( - fmt.Sprintf("insufficient account funds; %s < %s", oldCoins, amt), + return amt, sdkerrors.Wrapf( + sdkerrors.ErrInsufficientFunds, "insufficient account funds; %s < %s", oldCoins, amt, ) } @@ -295,10 +293,9 @@ func (keeper BaseSendKeeper) AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt } // SetCoins sets the coins at the addr. -func (keeper BaseSendKeeper) SetCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) sdk.Error { - +func (keeper BaseSendKeeper) SetCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) error { if !amt.IsValid() { - return sdk.ErrInvalidCoins(amt.String()) + sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, amt.String()) } acc := keeper.ak.GetAccount(ctx, addr) @@ -340,19 +337,16 @@ var _ ViewKeeper = (*BaseViewKeeper)(nil) type ViewKeeper interface { GetCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins HasCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) bool - - Codespace() sdk.CodespaceType } // BaseViewKeeper implements a read only keeper implementation of ViewKeeper. type BaseViewKeeper struct { - ak types.AccountKeeper - codespace sdk.CodespaceType + ak types.AccountKeeper } // NewBaseViewKeeper returns a new BaseViewKeeper. -func NewBaseViewKeeper(ak types.AccountKeeper, codespace sdk.CodespaceType) BaseViewKeeper { - return BaseViewKeeper{ak: ak, codespace: codespace} +func NewBaseViewKeeper(ak types.AccountKeeper) BaseViewKeeper { + return BaseViewKeeper{ak: ak} } // Logger returns a module-specific logger. @@ -374,11 +368,6 @@ func (keeper BaseViewKeeper) HasCoins(ctx sdk.Context, addr sdk.AccAddress, amt return keeper.GetCoins(ctx, addr).IsAllGTE(amt) } -// Codespace returns the keeper's codespace. -func (keeper BaseViewKeeper) Codespace() sdk.CodespaceType { - return keeper.codespace -} - // CONTRACT: assumes that amt is valid. func trackDelegation(acc authexported.Account, blockTime time.Time, amt sdk.Coins) error { vacc, ok := acc.(vestexported.VestingAccount) diff --git a/x/bank/internal/keeper/keeper_test.go b/x/bank/internal/keeper/keeper_test.go index ba6c3f56c440..f93ddaa52969 100644 --- a/x/bank/internal/keeper/keeper_test.go +++ b/x/bank/internal/keeper/keeper_test.go @@ -65,8 +65,7 @@ func TestKeeper(t *testing.T) { require.True(t, app.BankKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10)))) require.True(t, app.BankKeeper.GetCoins(ctx, addr2).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 5)))) - err2 := app.BankKeeper.SendCoins(ctx, addr, addr2, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 50))) - require.Implements(t, (*sdk.Error)(nil), err2) + app.BankKeeper.SendCoins(ctx, addr, addr2, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 50))) require.True(t, app.BankKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10)))) require.True(t, app.BankKeeper.GetCoins(ctx, addr2).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 5)))) @@ -109,7 +108,7 @@ func TestSendKeeper(t *testing.T) { blacklistedAddrs := make(map[string]bool) paramSpace := app.ParamsKeeper.Subspace("newspace") - sendKeeper := keep.NewBaseSendKeeper(app.AccountKeeper, paramSpace, types.DefaultCodespace, blacklistedAddrs) + sendKeeper := keep.NewBaseSendKeeper(app.AccountKeeper, paramSpace, blacklistedAddrs) app.BankKeeper.SetSendEnabled(ctx, true) addr := sdk.AccAddress([]byte("addr1")) @@ -136,8 +135,7 @@ func TestSendKeeper(t *testing.T) { require.True(t, sendKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10)))) require.True(t, sendKeeper.GetCoins(ctx, addr2).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 5)))) - err := sendKeeper.SendCoins(ctx, addr, addr2, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 50))) - require.Implements(t, (*sdk.Error)(nil), err) + sendKeeper.SendCoins(ctx, addr, addr2, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 50))) require.True(t, sendKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10)))) require.True(t, sendKeeper.GetCoins(ctx, addr2).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 5)))) @@ -149,7 +147,7 @@ func TestSendKeeper(t *testing.T) { // validate coins with invalid denoms or negative values cannot be sent // NOTE: We must use the Coin literal as the constructor does not allow // negative values. - err = sendKeeper.SendCoins(ctx, addr, addr2, sdk.Coins{sdk.Coin{Denom: "FOOCOIN", Amount: sdk.NewInt(-5)}}) + err := sendKeeper.SendCoins(ctx, addr, addr2, sdk.Coins{sdk.Coin{Denom: "FOOCOIN", Amount: sdk.NewInt(-5)}}) require.Error(t, err) } @@ -202,7 +200,7 @@ func TestViewKeeper(t *testing.T) { app, ctx := createTestApp(false) //paramSpace := app.ParamsKeeper.Subspace(types.DefaultParamspace) - viewKeeper := keep.NewBaseViewKeeper(app.AccountKeeper, types.DefaultCodespace) + viewKeeper := keep.NewBaseViewKeeper(app.AccountKeeper) addr := sdk.AccAddress([]byte("addr1")) acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr) diff --git a/x/bank/internal/keeper/querier.go b/x/bank/internal/keeper/querier.go index bf303e2930fa..165d01879621 100644 --- a/x/bank/internal/keeper/querier.go +++ b/x/bank/internal/keeper/querier.go @@ -1,12 +1,11 @@ package keeper import ( - "fmt" - abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/bank/internal/types" ) @@ -17,24 +16,24 @@ const ( // NewQuerier returns a new sdk.Keeper instance. func NewQuerier(k Keeper) sdk.Querier { - return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, sdk.Error) { + return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) { switch path[0] { case QueryBalance: return queryBalance(ctx, req, k) default: - return nil, sdk.ErrUnknownRequest("unknown bank query endpoint") + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown query path: %s", path[0]) } } } // queryBalance fetch an account's balance for the supplied height. // Height and account address are passed as first and second path components respectively. -func queryBalance(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryBalance(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryBalanceParams if err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms); err != nil { - return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } coins := k.GetCoins(ctx, params.Address) @@ -44,7 +43,7 @@ func queryBalance(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk bz, err := codec.MarshalJSONIndent(types.ModuleCdc, coins) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return bz, nil diff --git a/x/bank/internal/types/errors.go b/x/bank/internal/types/errors.go index d9c0c7d11d1d..157408c941b7 100644 --- a/x/bank/internal/types/errors.go +++ b/x/bank/internal/types/errors.go @@ -1,33 +1,13 @@ package types import ( - sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) -// Bank errors reserve 100 ~ 199. -const ( - DefaultCodespace sdk.CodespaceType = ModuleName - - CodeSendDisabled sdk.CodeType = 101 - CodeInvalidInputsOutputs sdk.CodeType = 102 +// x/bank module sentinel errors +var ( + ErrNoInputs = sdkerrors.Register(ModuleName, 1, "no inputs to send transaction") + ErrNoOutputs = sdkerrors.Register(ModuleName, 2, "no outputs to send transaction") + ErrInputOutputMismatch = sdkerrors.Register(ModuleName, 3, "sum inputs != sum outputs") + ErrSendDisabled = sdkerrors.Register(ModuleName, 4, "send transactions are disabled") ) - -// ErrNoInputs is an error -func ErrNoInputs(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidInputsOutputs, "no inputs to send transaction") -} - -// ErrNoOutputs is an error -func ErrNoOutputs(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidInputsOutputs, "no outputs to send transaction") -} - -// ErrInputOutputMismatch is an error -func ErrInputOutputMismatch(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidInputsOutputs, "sum inputs != sum outputs") -} - -// ErrSendDisabled is an error -func ErrSendDisabled(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeSendDisabled, "send transactions are currently disabled") -} diff --git a/x/bank/internal/types/msgs.go b/x/bank/internal/types/msgs.go index 58336e24d9e4..c8fdaa5afe92 100644 --- a/x/bank/internal/types/msgs.go +++ b/x/bank/internal/types/msgs.go @@ -2,6 +2,7 @@ package types import ( sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) // RouterKey is they name of the bank module @@ -28,18 +29,18 @@ func (msg MsgSend) Route() string { return RouterKey } func (msg MsgSend) Type() string { return "send" } // ValidateBasic Implements Msg. -func (msg MsgSend) ValidateBasic() sdk.Error { +func (msg MsgSend) ValidateBasic() error { if msg.FromAddress.Empty() { - return sdk.ErrInvalidAddress("missing sender address") + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "missing sender address") } if msg.ToAddress.Empty() { - return sdk.ErrInvalidAddress("missing recipient address") + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "missing recipient address") } if !msg.Amount.IsValid() { - return sdk.ErrInvalidCoins("send amount is invalid: " + msg.Amount.String()) + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, msg.Amount.String()) } if !msg.Amount.IsAllPositive() { - return sdk.ErrInsufficientCoins("send amount must be positive") + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, msg.Amount.String()) } return nil } @@ -74,14 +75,14 @@ func (msg MsgMultiSend) Route() string { return RouterKey } func (msg MsgMultiSend) Type() string { return "multisend" } // ValidateBasic Implements Msg. -func (msg MsgMultiSend) ValidateBasic() sdk.Error { +func (msg MsgMultiSend) ValidateBasic() error { // this just makes sure all the inputs and outputs are properly formatted, // not that they actually have the money inside if len(msg.Inputs) == 0 { - return ErrNoInputs(DefaultCodespace).TraceSDK("") + return ErrNoInputs } if len(msg.Outputs) == 0 { - return ErrNoOutputs(DefaultCodespace).TraceSDK("") + return ErrNoOutputs } return ValidateInputsOutputs(msg.Inputs, msg.Outputs) @@ -108,15 +109,15 @@ type Input struct { } // ValidateBasic - validate transaction input -func (in Input) ValidateBasic() sdk.Error { +func (in Input) ValidateBasic() error { if len(in.Address) == 0 { - return sdk.ErrInvalidAddress(in.Address.String()) + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "input address missing") } if !in.Coins.IsValid() { - return sdk.ErrInvalidCoins(in.Coins.String()) + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, in.Coins.String()) } if !in.Coins.IsAllPositive() { - return sdk.ErrInvalidCoins(in.Coins.String()) + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, in.Coins.String()) } return nil } @@ -136,15 +137,15 @@ type Output struct { } // ValidateBasic - validate transaction output -func (out Output) ValidateBasic() sdk.Error { +func (out Output) ValidateBasic() error { if len(out.Address) == 0 { - return sdk.ErrInvalidAddress(out.Address.String()) + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "output address missing") } if !out.Coins.IsValid() { - return sdk.ErrInvalidCoins(out.Coins.String()) + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, out.Coins.String()) } if !out.Coins.IsAllPositive() { - return sdk.ErrInvalidCoins(out.Coins.String()) + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, out.Coins.String()) } return nil } @@ -159,26 +160,28 @@ func NewOutput(addr sdk.AccAddress, coins sdk.Coins) Output { // ValidateInputsOutputs validates that each respective input and output is // valid and that the sum of inputs is equal to the sum of outputs. -func ValidateInputsOutputs(inputs []Input, outputs []Output) sdk.Error { +func ValidateInputsOutputs(inputs []Input, outputs []Output) error { var totalIn, totalOut sdk.Coins for _, in := range inputs { if err := in.ValidateBasic(); err != nil { - return err.TraceSDK("") + return err } + totalIn = totalIn.Add(in.Coins) } for _, out := range outputs { if err := out.ValidateBasic(); err != nil { - return err.TraceSDK("") + return err } + totalOut = totalOut.Add(out.Coins) } // make sure inputs and outputs match if !totalIn.IsEqual(totalOut) { - return ErrInputOutputMismatch(DefaultCodespace) + return ErrInputOutputMismatch } return nil diff --git a/x/bank/simulation/operations.go b/x/bank/simulation/operations.go index 71a88386c960..7cf08a8452f2 100644 --- a/x/bank/simulation/operations.go +++ b/x/bank/simulation/operations.go @@ -1,7 +1,6 @@ package simulation import ( - "errors" "math/rand" "github.com/tendermint/tendermint/crypto" @@ -115,9 +114,9 @@ func sendMsgSend( privkeys..., ) - res := app.Deliver(tx) - if !res.IsOK() { - return errors.New(res.Log) + _, _, err = app.Deliver(tx) + if err != nil { + return err } return nil @@ -259,9 +258,9 @@ func sendMsgMultiSend( privkeys..., ) - res := app.Deliver(tx) - if !res.IsOK() { - return errors.New(res.Log) + _, _, err = app.Deliver(tx) + if err != nil { + return err } return nil diff --git a/x/crisis/alias.go b/x/crisis/alias.go index 6c176e265544..1b05371f376b 100644 --- a/x/crisis/alias.go +++ b/x/crisis/alias.go @@ -1,38 +1,30 @@ -// nolint -// autogenerated code using github.com/rigelrozanski/multitool -// aliases generated for the following subdirectories: -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/crisis/types package crisis +// nolint + import ( "github.com/cosmos/cosmos-sdk/x/crisis/internal/keeper" "github.com/cosmos/cosmos-sdk/x/crisis/internal/types" ) const ( - DefaultCodespace = types.DefaultCodespace - CodeInvalidInput = types.CodeInvalidInput - ModuleName = types.ModuleName - DefaultParamspace = types.DefaultParamspace - + ModuleName = types.ModuleName + DefaultParamspace = types.DefaultParamspace EventTypeInvariant = types.EventTypeInvariant AttributeValueCrisis = types.AttributeValueCrisis AttributeKeyRoute = types.AttributeKeyRoute ) var ( - // functions aliases - RegisterCodec = types.RegisterCodec - ErrNilSender = types.ErrNilSender - ErrUnknownInvariant = types.ErrUnknownInvariant - NewGenesisState = types.NewGenesisState - DefaultGenesisState = types.DefaultGenesisState - NewMsgVerifyInvariant = types.NewMsgVerifyInvariant - ParamKeyTable = types.ParamKeyTable - NewInvarRoute = types.NewInvarRoute - NewKeeper = keeper.NewKeeper - - // variable aliases + RegisterCodec = types.RegisterCodec + ErrNoSender = types.ErrNoSender + ErrUnknownInvariant = types.ErrUnknownInvariant + NewGenesisState = types.NewGenesisState + DefaultGenesisState = types.DefaultGenesisState + NewMsgVerifyInvariant = types.NewMsgVerifyInvariant + ParamKeyTable = types.ParamKeyTable + NewInvarRoute = types.NewInvarRoute + NewKeeper = keeper.NewKeeper ModuleCdc = types.ModuleCdc ParamStoreKeyConstantFee = types.ParamStoreKeyConstantFee ) diff --git a/x/crisis/handler.go b/x/crisis/handler.go index 9ff52c2f339e..c7e58b6861be 100644 --- a/x/crisis/handler.go +++ b/x/crisis/handler.go @@ -1,9 +1,8 @@ package crisis import ( - "fmt" - sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/crisis/internal/keeper" "github.com/cosmos/cosmos-sdk/x/crisis/internal/types" ) @@ -12,7 +11,7 @@ import ( const RouterKey = types.ModuleName func NewHandler(k keeper.Keeper) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { ctx = ctx.WithEventManager(sdk.NewEventManager()) switch msg := msg.(type) { @@ -20,18 +19,16 @@ func NewHandler(k keeper.Keeper) sdk.Handler { return handleMsgVerifyInvariant(ctx, msg, k) default: - errMsg := fmt.Sprintf("unrecognized crisis message type: %T", msg) - return sdk.ErrUnknownRequest(errMsg).Result() + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized crisis message type: %T", msg) } } } -func handleMsgVerifyInvariant(ctx sdk.Context, msg types.MsgVerifyInvariant, k keeper.Keeper) sdk.Result { - // remove the constant fee +func handleMsgVerifyInvariant(ctx sdk.Context, msg types.MsgVerifyInvariant, k keeper.Keeper) (*sdk.Result, error) { constantFee := sdk.NewCoins(k.GetConstantFee(ctx)) if err := k.SendCoinsFromAccountToFeeCollector(ctx, msg.Sender, constantFee); err != nil { - return err.Result() + return nil, err } // use a cached context to avoid gas costs during invariants @@ -51,7 +48,7 @@ func handleMsgVerifyInvariant(ctx sdk.Context, msg types.MsgVerifyInvariant, k k } if !found { - return types.ErrUnknownInvariant(types.DefaultCodespace).Result() + return nil, types.ErrUnknownInvariant } if stop { @@ -86,5 +83,5 @@ func handleMsgVerifyInvariant(ctx sdk.Context, msg types.MsgVerifyInvariant, k k ), }) - return sdk.Result{Events: ctx.EventManager().Events()} + return &sdk.Result{Events: ctx.EventManager().Events()}, nil } diff --git a/x/crisis/handler_test.go b/x/crisis/handler_test.go index 064d6234bc9b..f4c2f8182dbf 100644 --- a/x/crisis/handler_test.go +++ b/x/crisis/handler_test.go @@ -69,14 +69,18 @@ func TestHandleMsgVerifyInvariant(t *testing.T) { switch tc.expectedResult { case "fail": - res := h(ctx, tc.msg) - require.False(t, res.IsOK()) + res, err := h(ctx, tc.msg) + require.Error(t, err) + require.Nil(t, res) + case "pass": - res := h(ctx, tc.msg) - require.True(t, res.IsOK()) + res, err := h(ctx, tc.msg) + require.NoError(t, err) + require.NotNil(t, res) + case "panic": require.Panics(t, func() { - _ = h(ctx, tc.msg) + h(ctx, tc.msg) }) } }) @@ -92,7 +96,10 @@ func TestHandleMsgVerifyInvariantWithNotEnoughSenderCoins(t *testing.T) { h := crisis.NewHandler(app.CrisisKeeper) msg := crisis.NewMsgVerifyInvariant(sender, testModuleName, dummyRouteWhichPasses.Route) - require.False(t, h(ctx, msg).IsOK()) + + res, err := h(ctx, msg) + require.Error(t, err) + require.Nil(t, res) } func TestHandleMsgVerifyInvariantWithInvariantBrokenAndNotEnoughPoolCoins(t *testing.T) { @@ -106,8 +113,9 @@ func TestHandleMsgVerifyInvariantWithInvariantBrokenAndNotEnoughPoolCoins(t *tes h := crisis.NewHandler(app.CrisisKeeper) msg := crisis.NewMsgVerifyInvariant(sender, testModuleName, dummyRouteWhichFails.Route) - var res sdk.Result + + var res *sdk.Result require.Panics(t, func() { - res = h(ctx, msg) + res, _ = h(ctx, msg) }, fmt.Sprintf("%v", res)) } diff --git a/x/crisis/internal/keeper/keeper.go b/x/crisis/internal/keeper/keeper.go index cb6f9a6548d8..f4c8163bb740 100644 --- a/x/crisis/internal/keeper/keeper.go +++ b/x/crisis/internal/keeper/keeper.go @@ -90,6 +90,6 @@ func (k Keeper) AssertInvariants(ctx sdk.Context) { func (k Keeper) InvCheckPeriod() uint { return k.invCheckPeriod } // SendCoinsFromAccountToFeeCollector transfers amt to the fee collector account. -func (k Keeper) SendCoinsFromAccountToFeeCollector(ctx sdk.Context, senderAddr sdk.AccAddress, amt sdk.Coins) sdk.Error { +func (k Keeper) SendCoinsFromAccountToFeeCollector(ctx sdk.Context, senderAddr sdk.AccAddress, amt sdk.Coins) error { return k.supplyKeeper.SendCoinsFromAccountToModule(ctx, senderAddr, k.feeCollectorName, amt) } diff --git a/x/crisis/internal/types/errors.go b/x/crisis/internal/types/errors.go index 3b7392abfae6..ac63f3ff43de 100644 --- a/x/crisis/internal/types/errors.go +++ b/x/crisis/internal/types/errors.go @@ -1,23 +1,11 @@ package types import ( - sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) -const ( - // default codespace for crisis module - DefaultCodespace sdk.CodespaceType = ModuleName - - // CodeInvalidInput is the codetype for invalid input for the crisis module - CodeInvalidInput sdk.CodeType = 103 +// x/crisis module sentinel errors +var ( + ErrNoSender = sdkerrors.Register(ModuleName, 1, "sender address is empty") + ErrUnknownInvariant = sdkerrors.Register(ModuleName, 2, "unknown invariant") ) - -// ErrNilSender - no sender provided for the input -func ErrNilSender(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidInput, "sender address is nil") -} - -// ErrUnknownInvariant - unknown invariant provided -func ErrUnknownInvariant(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidInput, "unknown invariant") -} diff --git a/x/crisis/internal/types/expected_keepers.go b/x/crisis/internal/types/expected_keepers.go index 5690c0c38688..3cd0e9e7f57a 100644 --- a/x/crisis/internal/types/expected_keepers.go +++ b/x/crisis/internal/types/expected_keepers.go @@ -6,5 +6,5 @@ import ( // SupplyKeeper defines the expected supply keeper (noalias) type SupplyKeeper interface { - SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) sdk.Error + SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error } diff --git a/x/crisis/internal/types/msgs.go b/x/crisis/internal/types/msgs.go index e16ffb528e0c..f496df636b60 100644 --- a/x/crisis/internal/types/msgs.go +++ b/x/crisis/internal/types/msgs.go @@ -39,9 +39,9 @@ func (msg MsgVerifyInvariant) GetSignBytes() []byte { } // quick validity check -func (msg MsgVerifyInvariant) ValidateBasic() sdk.Error { +func (msg MsgVerifyInvariant) ValidateBasic() error { if msg.Sender.Empty() { - return ErrNilSender(DefaultCodespace) + return ErrNoSender } return nil } diff --git a/x/distribution/alias.go b/x/distribution/alias.go index de6f269e6a1c..ff181d7331e3 100644 --- a/x/distribution/alias.go +++ b/x/distribution/alias.go @@ -10,11 +10,6 @@ import ( const ( DefaultParamspace = keeper.DefaultParamspace - DefaultCodespace = types.DefaultCodespace - CodeInvalidInput = types.CodeInvalidInput - CodeNoDistributionInfo = types.CodeNoDistributionInfo - CodeNoValidatorCommission = types.CodeNoValidatorCommission - CodeSetWithdrawAddrDisabled = types.CodeSetWithdrawAddrDisabled ModuleName = types.ModuleName StoreKey = types.StoreKey RouterKey = types.RouterKey @@ -70,11 +65,13 @@ var ( CreateTestInputAdvanced = keeper.CreateTestInputAdvanced RegisterCodec = types.RegisterCodec NewDelegatorStartingInfo = types.NewDelegatorStartingInfo - ErrNilDelegatorAddr = types.ErrNilDelegatorAddr - ErrNilWithdrawAddr = types.ErrNilWithdrawAddr - ErrNilValidatorAddr = types.ErrNilValidatorAddr - ErrNoDelegationDistInfo = types.ErrNoDelegationDistInfo + ErrEmptyDelegatorAddr = types.ErrEmptyDelegatorAddr + ErrEmptyWithdrawAddr = types.ErrEmptyWithdrawAddr + ErrEmptyValidatorAddr = types.ErrEmptyValidatorAddr + ErrEmptyDelegationDistInfo = types.ErrEmptyDelegationDistInfo ErrNoValidatorDistInfo = types.ErrNoValidatorDistInfo + ErrNoValidatorExists = types.ErrNoValidatorExists + ErrNoDelegationExists = types.ErrNoDelegationExists ErrNoValidatorCommission = types.ErrNoValidatorCommission ErrSetWithdrawAddrDisabled = types.ErrSetWithdrawAddrDisabled ErrBadDistribution = types.ErrBadDistribution @@ -134,7 +131,6 @@ type ( Hooks = keeper.Hooks Keeper = keeper.Keeper DelegatorStartingInfo = types.DelegatorStartingInfo - CodeType = types.CodeType FeePool = types.FeePool DelegatorWithdrawInfo = types.DelegatorWithdrawInfo ValidatorOutstandingRewardsRecord = types.ValidatorOutstandingRewardsRecord diff --git a/x/distribution/handler.go b/x/distribution/handler.go index 90c4bc14de93..642b9e0d89a1 100644 --- a/x/distribution/handler.go +++ b/x/distribution/handler.go @@ -1,16 +1,15 @@ package distribution import ( - "fmt" - sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/distribution/keeper" "github.com/cosmos/cosmos-sdk/x/distribution/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" ) func NewHandler(k keeper.Keeper) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { ctx = ctx.WithEventManager(sdk.NewEventManager()) switch msg := msg.(type) { @@ -27,18 +26,17 @@ func NewHandler(k keeper.Keeper) sdk.Handler { return handleMsgFundCommunityPool(ctx, msg, k) default: - errMsg := fmt.Sprintf("unrecognized distribution message type: %T", msg) - return sdk.ErrUnknownRequest(errMsg).Result() + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized distribution message type: %T", msg) } } } // These functions assume everything has been authenticated (ValidateBasic passed, and signatures checked) -func handleMsgModifyWithdrawAddress(ctx sdk.Context, msg types.MsgSetWithdrawAddress, k keeper.Keeper) sdk.Result { +func handleMsgModifyWithdrawAddress(ctx sdk.Context, msg types.MsgSetWithdrawAddress, k keeper.Keeper) (*sdk.Result, error) { err := k.SetWithdrawAddr(ctx, msg.DelegatorAddress, msg.WithdrawAddress) if err != nil { - return err.Result() + return nil, err } ctx.EventManager().EmitEvent( @@ -49,13 +47,13 @@ func handleMsgModifyWithdrawAddress(ctx sdk.Context, msg types.MsgSetWithdrawAdd ), ) - return sdk.Result{Events: ctx.EventManager().Events()} + return &sdk.Result{Events: ctx.EventManager().Events()}, nil } -func handleMsgWithdrawDelegatorReward(ctx sdk.Context, msg types.MsgWithdrawDelegatorReward, k keeper.Keeper) sdk.Result { +func handleMsgWithdrawDelegatorReward(ctx sdk.Context, msg types.MsgWithdrawDelegatorReward, k keeper.Keeper) (*sdk.Result, error) { _, err := k.WithdrawDelegationRewards(ctx, msg.DelegatorAddress, msg.ValidatorAddress) if err != nil { - return err.Result() + return nil, err } ctx.EventManager().EmitEvent( @@ -66,13 +64,13 @@ func handleMsgWithdrawDelegatorReward(ctx sdk.Context, msg types.MsgWithdrawDele ), ) - return sdk.Result{Events: ctx.EventManager().Events()} + return &sdk.Result{Events: ctx.EventManager().Events()}, nil } -func handleMsgWithdrawValidatorCommission(ctx sdk.Context, msg types.MsgWithdrawValidatorCommission, k keeper.Keeper) sdk.Result { +func handleMsgWithdrawValidatorCommission(ctx sdk.Context, msg types.MsgWithdrawValidatorCommission, k keeper.Keeper) (*sdk.Result, error) { _, err := k.WithdrawValidatorCommission(ctx, msg.ValidatorAddress) if err != nil { - return err.Result() + return nil, err } ctx.EventManager().EmitEvent( @@ -83,12 +81,12 @@ func handleMsgWithdrawValidatorCommission(ctx sdk.Context, msg types.MsgWithdraw ), ) - return sdk.Result{Events: ctx.EventManager().Events()} + return &sdk.Result{Events: ctx.EventManager().Events()}, nil } -func handleMsgFundCommunityPool(ctx sdk.Context, msg types.MsgFundCommunityPool, k keeper.Keeper) sdk.Result { +func handleMsgFundCommunityPool(ctx sdk.Context, msg types.MsgFundCommunityPool, k keeper.Keeper) (*sdk.Result, error) { if err := k.FundCommunityPool(ctx, msg.Amount, msg.Depositor); err != nil { - return sdk.ResultFromError(err) + return nil, err } ctx.EventManager().EmitEvent( @@ -99,18 +97,17 @@ func handleMsgFundCommunityPool(ctx sdk.Context, msg types.MsgFundCommunityPool, ), ) - return sdk.Result{Events: ctx.EventManager().Events()} + return &sdk.Result{Events: ctx.EventManager().Events()}, nil } func NewCommunityPoolSpendProposalHandler(k Keeper) govtypes.Handler { - return func(ctx sdk.Context, content govtypes.Content) sdk.Error { + return func(ctx sdk.Context, content govtypes.Content) error { switch c := content.(type) { case types.CommunityPoolSpendProposal: return keeper.HandleCommunityPoolSpendProposal(ctx, k, c) default: - errMsg := fmt.Sprintf("unrecognized distr proposal content type: %T", c) - return sdk.ErrUnknownRequest(errMsg) + return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized distr proposal content type: %T", c) } } } diff --git a/x/distribution/keeper/allocation_test.go b/x/distribution/keeper/allocation_test.go index 8f1b84c5f35c..83821ea3820d 100644 --- a/x/distribution/keeper/allocation_test.go +++ b/x/distribution/keeper/allocation_test.go @@ -16,9 +16,15 @@ func TestAllocateTokensToValidatorWithCommission(t *testing.T) { // create validator with 50% commission commission := staking.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0)) - msg := staking.NewMsgCreateValidator(valOpAddr1, valConsPk1, - sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), staking.Description{}, commission, sdk.OneInt()) - require.True(t, sh(ctx, msg).IsOK()) + msg := staking.NewMsgCreateValidator( + valOpAddr1, valConsPk1, + sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), staking.Description{}, commission, sdk.OneInt(), + ) + + res, err := sh(ctx, msg) + require.NoError(t, err) + require.NotNil(t, res) + val := sk.Validator(ctx, valOpAddr1) // allocate tokens @@ -45,13 +51,19 @@ func TestAllocateTokensToManyValidators(t *testing.T) { commission := staking.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0)) msg := staking.NewMsgCreateValidator(valOpAddr1, valConsPk1, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), staking.Description{}, commission, sdk.OneInt()) - require.True(t, sh(ctx, msg).IsOK()) + + res, err := sh(ctx, msg) + require.NoError(t, err) + require.NotNil(t, res) // create second validator with 0% commission commission = staking.NewCommissionRates(sdk.NewDec(0), sdk.NewDec(0), sdk.NewDec(0)) msg = staking.NewMsgCreateValidator(valOpAddr2, valConsPk2, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), staking.Description{}, commission, sdk.OneInt()) - require.True(t, sh(ctx, msg).IsOK()) + + res, err = sh(ctx, msg) + require.NoError(t, err) + require.NotNil(t, res) abciValA := abci.Validator{ Address: valConsPk1.Address(), @@ -76,7 +88,7 @@ func TestAllocateTokensToManyValidators(t *testing.T) { feeCollector := supplyKeeper.GetModuleAccount(ctx, k.feeCollectorName) require.NotNil(t, feeCollector) - err := feeCollector.SetCoins(fees) + err = feeCollector.SetCoins(fees) require.NoError(t, err) ak.SetAccount(ctx, feeCollector) @@ -116,19 +128,25 @@ func TestAllocateTokensTruncation(t *testing.T) { commission := staking.NewCommissionRates(sdk.NewDecWithPrec(1, 1), sdk.NewDecWithPrec(1, 1), sdk.NewDec(0)) msg := staking.NewMsgCreateValidator(valOpAddr1, valConsPk1, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(110)), staking.Description{}, commission, sdk.OneInt()) - require.True(t, sh(ctx, msg).IsOK()) + res, err := sh(ctx, msg) + require.NoError(t, err) + require.NotNil(t, res) // create second validator with 10% commission commission = staking.NewCommissionRates(sdk.NewDecWithPrec(1, 1), sdk.NewDecWithPrec(1, 1), sdk.NewDec(0)) msg = staking.NewMsgCreateValidator(valOpAddr2, valConsPk2, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), staking.Description{}, commission, sdk.OneInt()) - require.True(t, sh(ctx, msg).IsOK()) + res, err = sh(ctx, msg) + require.NoError(t, err) + require.NotNil(t, res) // create third validator with 10% commission commission = staking.NewCommissionRates(sdk.NewDecWithPrec(1, 1), sdk.NewDecWithPrec(1, 1), sdk.NewDec(0)) msg = staking.NewMsgCreateValidator(valOpAddr3, valConsPk3, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), staking.Description{}, commission, sdk.OneInt()) - require.True(t, sh(ctx, msg).IsOK()) + res, err = sh(ctx, msg) + require.NoError(t, err) + require.NotNil(t, res) abciValA := abci.Validator{ Address: valConsPk1.Address(), @@ -159,7 +177,7 @@ func TestAllocateTokensTruncation(t *testing.T) { feeCollector := supplyKeeper.GetModuleAccount(ctx, k.feeCollectorName) require.NotNil(t, feeCollector) - err := feeCollector.SetCoins(fees) + err = feeCollector.SetCoins(fees) require.NoError(t, err) ak.SetAccount(ctx, feeCollector) diff --git a/x/distribution/keeper/delegation.go b/x/distribution/keeper/delegation.go index 4044c4d1961a..7b28b6048eaf 100644 --- a/x/distribution/keeper/delegation.go +++ b/x/distribution/keeper/delegation.go @@ -136,10 +136,10 @@ func (k Keeper) calculateDelegationRewards(ctx sdk.Context, val exported.Validat return rewards } -func (k Keeper) withdrawDelegationRewards(ctx sdk.Context, val exported.ValidatorI, del exported.DelegationI) (sdk.Coins, sdk.Error) { +func (k Keeper) withdrawDelegationRewards(ctx sdk.Context, val exported.ValidatorI, del exported.DelegationI) (sdk.Coins, error) { // check existence of delegator starting info if !k.HasDelegatorStartingInfo(ctx, del.GetValidatorAddr(), del.GetDelegatorAddr()) { - return nil, types.ErrNoDelegationDistInfo(k.codespace) + return nil, types.ErrEmptyDelegationDistInfo } // end current period and calculate rewards diff --git a/x/distribution/keeper/delegation_test.go b/x/distribution/keeper/delegation_test.go index db6f6fb434ea..6d23ad958991 100644 --- a/x/distribution/keeper/delegation_test.go +++ b/x/distribution/keeper/delegation_test.go @@ -15,9 +15,13 @@ func TestCalculateRewardsBasic(t *testing.T) { // create validator with 50% commission commission := staking.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0)) - msg := staking.NewMsgCreateValidator(valOpAddr1, valConsPk1, - sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), staking.Description{}, commission, sdk.OneInt()) - require.True(t, sh(ctx, msg).IsOK()) + msg := staking.NewMsgCreateValidator( + valOpAddr1, valConsPk1, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), staking.Description{}, commission, sdk.OneInt(), + ) + + res, err := sh(ctx, msg) + require.NoError(t, err) + require.NotNil(t, res) // end block to bond validator staking.EndBlocker(ctx, sk) @@ -72,8 +76,10 @@ func TestCalculateRewardsAfterSlash(t *testing.T) { valTokens := sdk.TokensFromConsensusPower(valPower) msg := staking.NewMsgCreateValidator(valOpAddr1, valConsPk1, sdk.NewCoin(sdk.DefaultBondDenom, valTokens), staking.Description{}, commission, sdk.OneInt()) - got := sh(ctx, msg) - require.True(t, got.IsOK(), "%v", got) + + res, err := sh(ctx, msg) + require.NoError(t, err) + require.NotNil(t, res) // end block to bond validator staking.EndBlocker(ctx, sk) @@ -135,7 +141,10 @@ func TestCalculateRewardsAfterManySlashes(t *testing.T) { commission := staking.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0)) msg := staking.NewMsgCreateValidator(valOpAddr1, valConsPk1, sdk.NewCoin(sdk.DefaultBondDenom, valTokens), staking.Description{}, commission, sdk.OneInt()) - require.True(t, sh(ctx, msg).IsOK()) + + res, err := sh(ctx, msg) + require.NoError(t, err) + require.NotNil(t, res) // end block to bond validator staking.EndBlocker(ctx, sk) @@ -207,7 +216,10 @@ func TestCalculateRewardsMultiDelegator(t *testing.T) { commission := staking.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0)) msg := staking.NewMsgCreateValidator(valOpAddr1, valConsPk1, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), staking.Description{}, commission, sdk.OneInt()) - require.True(t, sh(ctx, msg).IsOK()) + + res, err := sh(ctx, msg) + require.NoError(t, err) + require.NotNil(t, res) // end block to bond validator staking.EndBlocker(ctx, sk) @@ -226,7 +238,11 @@ func TestCalculateRewardsMultiDelegator(t *testing.T) { // second delegation msg2 := staking.NewMsgDelegate(sdk.AccAddress(valOpAddr2), valOpAddr1, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))) - require.True(t, sh(ctx, msg2).IsOK()) + + res, err = sh(ctx, msg2) + require.NoError(t, err) + require.NotNil(t, res) + del2 := sk.Delegation(ctx, sdk.AccAddress(valOpAddr2), valOpAddr1) // fetch updated validator @@ -280,7 +296,10 @@ func TestWithdrawDelegationRewardsBasic(t *testing.T) { sdk.NewCoin(sdk.DefaultBondDenom, valTokens), staking.Description{}, commission, sdk.OneInt(), ) - require.True(t, sh(ctx, msg).IsOK()) + + res, err := sh(ctx, msg) + require.NoError(t, err) + require.NotNil(t, res) // assert correct initial balance expTokens := balanceTokens.Sub(valTokens) @@ -308,7 +327,7 @@ func TestWithdrawDelegationRewardsBasic(t *testing.T) { require.Equal(t, uint64(2), k.GetValidatorHistoricalReferenceCount(ctx)) // withdraw rewards - _, err := k.WithdrawDelegationRewards(ctx, sdk.AccAddress(valOpAddr1), valOpAddr1) + _, err = k.WithdrawDelegationRewards(ctx, sdk.AccAddress(valOpAddr1), valOpAddr1) require.Nil(t, err) // historical count should still be 2 (added one record, cleared one) @@ -343,7 +362,10 @@ func TestCalculateRewardsAfterManySlashesInSameBlock(t *testing.T) { commission := staking.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0)) msg := staking.NewMsgCreateValidator(valOpAddr1, valConsPk1, sdk.NewCoin(sdk.DefaultBondDenom, valTokens), staking.Description{}, commission, sdk.OneInt()) - require.True(t, sh(ctx, msg).IsOK()) + + res, err := sh(ctx, msg) + require.NoError(t, err) + require.NotNil(t, res) // end block to bond validator staking.EndBlocker(ctx, sk) @@ -410,7 +432,10 @@ func TestCalculateRewardsMultiDelegatorMultiSlash(t *testing.T) { valTokens := sdk.TokensFromConsensusPower(power) msg := staking.NewMsgCreateValidator(valOpAddr1, valConsPk1, sdk.NewCoin(sdk.DefaultBondDenom, valTokens), staking.Description{}, commission, sdk.OneInt()) - require.True(t, sh(ctx, msg).IsOK()) + + res, err := sh(ctx, msg) + require.NoError(t, err) + require.NotNil(t, res) // end block to bond validator staking.EndBlocker(ctx, sk) @@ -436,7 +461,11 @@ func TestCalculateRewardsMultiDelegatorMultiSlash(t *testing.T) { delTokens := sdk.TokensFromConsensusPower(100) msg2 := staking.NewMsgDelegate(sdk.AccAddress(valOpAddr2), valOpAddr1, sdk.NewCoin(sdk.DefaultBondDenom, delTokens)) - require.True(t, sh(ctx, msg2).IsOK()) + + res, err = sh(ctx, msg2) + require.NoError(t, err) + require.NotNil(t, res) + del2 := sk.Delegation(ctx, sdk.AccAddress(valOpAddr2), valOpAddr1) // end block @@ -491,7 +520,10 @@ func TestCalculateRewardsMultiDelegatorMultWithdraw(t *testing.T) { commission := staking.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0)) msg := staking.NewMsgCreateValidator(valOpAddr1, valConsPk1, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), staking.Description{}, commission, sdk.OneInt()) - require.True(t, sh(ctx, msg).IsOK()) + + res, err := sh(ctx, msg) + require.NoError(t, err) + require.NotNil(t, res) // end block to bond validator staking.EndBlocker(ctx, sk) @@ -511,7 +543,9 @@ func TestCalculateRewardsMultiDelegatorMultWithdraw(t *testing.T) { // second delegation msg2 := staking.NewMsgDelegate(sdk.AccAddress(valOpAddr2), valOpAddr1, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))) - require.True(t, sh(ctx, msg2).IsOK()) + res, err = sh(ctx, msg2) + require.NoError(t, err) + require.NotNil(t, res) // historical count should be 3 (second delegation init) require.Equal(t, uint64(3), k.GetValidatorHistoricalReferenceCount(ctx)) diff --git a/x/distribution/keeper/fee_pool.go b/x/distribution/keeper/fee_pool.go index a16e8258c029..34ad5f0d0d06 100644 --- a/x/distribution/keeper/fee_pool.go +++ b/x/distribution/keeper/fee_pool.go @@ -7,7 +7,7 @@ import ( // DistributeFromFeePool distributes funds from the distribution module account to // a receiver address while updating the community pool -func (k Keeper) DistributeFromFeePool(ctx sdk.Context, amount sdk.Coins, receiveAddr sdk.AccAddress) sdk.Error { +func (k Keeper) DistributeFromFeePool(ctx sdk.Context, amount sdk.Coins, receiveAddr sdk.AccAddress) error { feePool := k.GetFeePool(ctx) // NOTE the community pool isn't a module account, however its coins @@ -15,8 +15,9 @@ func (k Keeper) DistributeFromFeePool(ctx sdk.Context, amount sdk.Coins, receive // must be reduced separately from the SendCoinsFromModuleToAccount call newPool, negative := feePool.CommunityPool.SafeSub(sdk.NewDecCoins(amount)) if negative { - return types.ErrBadDistribution(k.codespace) + return types.ErrBadDistribution } + feePool.CommunityPool = newPool err := k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, receiveAddr, amount) diff --git a/x/distribution/keeper/keeper.go b/x/distribution/keeper/keeper.go index 6aca0d86fa10..76b582bae209 100644 --- a/x/distribution/keeper/keeper.go +++ b/x/distribution/keeper/keeper.go @@ -5,6 +5,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/distribution/types" "github.com/cosmos/cosmos-sdk/x/params" @@ -19,17 +20,17 @@ type Keeper struct { stakingKeeper types.StakingKeeper supplyKeeper types.SupplyKeeper - codespace sdk.CodespaceType - blacklistedAddrs map[string]bool feeCollectorName string // name of the FeeCollector ModuleAccount } // NewKeeper creates a new distribution Keeper instance -func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, paramSpace params.Subspace, - sk types.StakingKeeper, supplyKeeper types.SupplyKeeper, codespace sdk.CodespaceType, - feeCollectorName string, blacklistedAddrs map[string]bool) Keeper { +func NewKeeper( + cdc *codec.Codec, key sdk.StoreKey, paramSpace params.Subspace, + sk types.StakingKeeper, supplyKeeper types.SupplyKeeper, feeCollectorName string, + blacklistedAddrs map[string]bool, +) Keeper { // ensure distribution module account is set if addr := supplyKeeper.GetModuleAddress(types.ModuleName); addr == nil { @@ -42,7 +43,6 @@ func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, paramSpace params.Subspace, paramSpace: paramSpace.WithKeyTable(ParamKeyTable()), stakingKeeper: sk, supplyKeeper: supplyKeeper, - codespace: codespace, feeCollectorName: feeCollectorName, blacklistedAddrs: blacklistedAddrs, } @@ -54,13 +54,13 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { } // SetWithdrawAddr sets a new address that will receive the rewards upon withdrawal -func (k Keeper) SetWithdrawAddr(ctx sdk.Context, delegatorAddr sdk.AccAddress, withdrawAddr sdk.AccAddress) sdk.Error { +func (k Keeper) SetWithdrawAddr(ctx sdk.Context, delegatorAddr sdk.AccAddress, withdrawAddr sdk.AccAddress) error { if k.blacklistedAddrs[withdrawAddr.String()] { - return sdk.ErrUnauthorized(fmt.Sprintf("%s is blacklisted from receiving external funds", withdrawAddr)) + return sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "%s is blacklisted from receiving external funds", withdrawAddr) } if !k.GetWithdrawAddrEnabled(ctx) { - return types.ErrSetWithdrawAddrDisabled(k.codespace) + return types.ErrSetWithdrawAddrDisabled } ctx.EventManager().EmitEvent( @@ -75,15 +75,15 @@ func (k Keeper) SetWithdrawAddr(ctx sdk.Context, delegatorAddr sdk.AccAddress, w } // withdraw rewards from a delegation -func (k Keeper) WithdrawDelegationRewards(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) (sdk.Coins, sdk.Error) { +func (k Keeper) WithdrawDelegationRewards(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) (sdk.Coins, error) { val := k.stakingKeeper.Validator(ctx, valAddr) if val == nil { - return nil, types.ErrNoValidatorDistInfo(k.codespace) + return nil, types.ErrNoValidatorDistInfo } del := k.stakingKeeper.Delegation(ctx, delAddr, valAddr) if del == nil { - return nil, types.ErrNoDelegationDistInfo(k.codespace) + return nil, types.ErrEmptyDelegationDistInfo } // withdraw rewards @@ -106,11 +106,11 @@ func (k Keeper) WithdrawDelegationRewards(ctx sdk.Context, delAddr sdk.AccAddres } // withdraw validator commission -func (k Keeper) WithdrawValidatorCommission(ctx sdk.Context, valAddr sdk.ValAddress) (sdk.Coins, sdk.Error) { +func (k Keeper) WithdrawValidatorCommission(ctx sdk.Context, valAddr sdk.ValAddress) (sdk.Coins, error) { // fetch validator accumulated commission accumCommission := k.GetValidatorAccumulatedCommission(ctx, valAddr) if accumCommission.IsZero() { - return nil, types.ErrNoValidatorCommission(k.codespace) + return nil, types.ErrNoValidatorCommission } commission, remainder := accumCommission.TruncateDecimal() @@ -147,6 +147,7 @@ func (k Keeper) GetTotalRewards(ctx sdk.Context) (totalRewards sdk.DecCoins) { return false }, ) + return totalRewards } diff --git a/x/distribution/keeper/proposal_handler.go b/x/distribution/keeper/proposal_handler.go index 2daf2245ed76..f60a3f88154d 100644 --- a/x/distribution/keeper/proposal_handler.go +++ b/x/distribution/keeper/proposal_handler.go @@ -4,13 +4,14 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/distribution/types" ) // HandleCommunityPoolSpendProposal is a handler for executing a passed community spend proposal -func HandleCommunityPoolSpendProposal(ctx sdk.Context, k Keeper, p types.CommunityPoolSpendProposal) sdk.Error { +func HandleCommunityPoolSpendProposal(ctx sdk.Context, k Keeper, p types.CommunityPoolSpendProposal) error { if k.blacklistedAddrs[p.Recipient.String()] { - return sdk.ErrUnauthorized(fmt.Sprintf("%s is blacklisted from receiving external funds", p.Recipient)) + return sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "%s is blacklisted from receiving external funds", p.Recipient) } err := k.DistributeFromFeePool(ctx, p.Amount, p.Recipient) diff --git a/x/distribution/keeper/querier.go b/x/distribution/keeper/querier.go index a057340340db..7e7c404cee14 100644 --- a/x/distribution/keeper/querier.go +++ b/x/distribution/keeper/querier.go @@ -2,18 +2,18 @@ package keeper import ( "encoding/json" - "fmt" abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/distribution/types" "github.com/cosmos/cosmos-sdk/x/staking/exported" ) func NewQuerier(k Keeper) sdk.Querier { - return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, sdk.Error) { + return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) { switch path[0] { case types.QueryParams: return queryParams(ctx, path[1:], req, k) @@ -43,82 +43,93 @@ func NewQuerier(k Keeper) sdk.Querier { return queryCommunityPool(ctx, path[1:], req, k) default: - return nil, sdk.ErrUnknownRequest("unknown distr query endpoint") + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown query path: %s", path[0]) } } } -func queryParams(ctx sdk.Context, path []string, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryParams(ctx sdk.Context, path []string, req abci.RequestQuery, k Keeper) ([]byte, error) { switch path[0] { case types.ParamCommunityTax: bz, err := codec.MarshalJSONIndent(k.cdc, k.GetCommunityTax(ctx)) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return bz, nil + case types.ParamBaseProposerReward: bz, err := codec.MarshalJSONIndent(k.cdc, k.GetBaseProposerReward(ctx)) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return bz, nil + case types.ParamBonusProposerReward: bz, err := codec.MarshalJSONIndent(k.cdc, k.GetBonusProposerReward(ctx)) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return bz, nil + case types.ParamWithdrawAddrEnabled: bz, err := codec.MarshalJSONIndent(k.cdc, k.GetWithdrawAddrEnabled(ctx)) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return bz, nil + default: - return nil, sdk.ErrUnknownRequest(fmt.Sprintf("%s is not a valid query request path", req.Path)) + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "%s is not a valid query request path", req.Path) } } -func queryValidatorOutstandingRewards(ctx sdk.Context, path []string, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryValidatorOutstandingRewards(ctx sdk.Context, path []string, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryValidatorOutstandingRewardsParams err := k.cdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } + rewards := k.GetValidatorOutstandingRewards(ctx, params.ValidatorAddress) if rewards == nil { rewards = sdk.DecCoins{} } + bz, err := codec.MarshalJSONIndent(k.cdc, rewards) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } + return bz, nil } -func queryValidatorCommission(ctx sdk.Context, path []string, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryValidatorCommission(ctx sdk.Context, path []string, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryValidatorCommissionParams err := k.cdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } + commission := k.GetValidatorAccumulatedCommission(ctx, params.ValidatorAddress) if commission == nil { commission = sdk.DecCoins{} } + bz, err := codec.MarshalJSONIndent(k.cdc, commission) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } + return bz, nil } -func queryValidatorSlashes(ctx sdk.Context, path []string, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryValidatorSlashes(ctx sdk.Context, path []string, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryValidatorSlashesParams err := k.cdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } + events := make([]types.ValidatorSlashEvent, 0) k.IterateValidatorSlashEventsBetween(ctx, params.ValidatorAddress, params.StartingHeight, params.EndingHeight, func(height uint64, event types.ValidatorSlashEvent) (stop bool) { @@ -126,18 +137,20 @@ func queryValidatorSlashes(ctx sdk.Context, path []string, req abci.RequestQuery return false }, ) + bz, err := codec.MarshalJSONIndent(k.cdc, events) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } + return bz, nil } -func queryDelegationRewards(ctx sdk.Context, _ []string, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryDelegationRewards(ctx sdk.Context, _ []string, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryDelegationRewardsParams err := k.cdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } // cache-wrap context as to not persist state changes during querying @@ -145,14 +158,12 @@ func queryDelegationRewards(ctx sdk.Context, _ []string, req abci.RequestQuery, val := k.stakingKeeper.Validator(ctx, params.ValidatorAddress) if val == nil { - // TODO: Should use ErrNoValidatorFound from staking/types - return nil, sdk.ErrInternal(fmt.Sprintf("validator %s does not exist", params.ValidatorAddress)) + return nil, sdkerrors.Wrap(types.ErrNoValidatorExists, params.ValidatorAddress.String()) } del := k.stakingKeeper.Delegation(ctx, params.DelegatorAddress, params.ValidatorAddress) if del == nil { - // TODO: Should use ErrNoDelegation from staking/types - return nil, sdk.ErrInternal("delegation does not exist") + return nil, types.ErrNoDelegationExists } endingPeriod := k.incrementValidatorPeriod(ctx, val) @@ -163,17 +174,17 @@ func queryDelegationRewards(ctx sdk.Context, _ []string, req abci.RequestQuery, bz, err := codec.MarshalJSONIndent(k.cdc, rewards) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return bz, nil } -func queryDelegatorTotalRewards(ctx sdk.Context, _ []string, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryDelegatorTotalRewards(ctx sdk.Context, _ []string, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryDelegatorParams err := k.cdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } // cache-wrap context as to not persist state changes during querying @@ -192,24 +203,26 @@ func queryDelegatorTotalRewards(ctx sdk.Context, _ []string, req abci.RequestQue delRewards = append(delRewards, types.NewDelegationDelegatorReward(valAddr, delReward)) total = total.Add(delReward) + return false }, ) totalRewards := types.NewQueryDelegatorTotalRewardsResponse(delRewards, total) + bz, err := json.Marshal(totalRewards) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return bz, nil } -func queryDelegatorValidators(ctx sdk.Context, _ []string, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryDelegatorValidators(ctx sdk.Context, _ []string, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryDelegatorParams err := k.cdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } // cache-wrap context as to not persist state changes during querying @@ -227,16 +240,17 @@ func queryDelegatorValidators(ctx sdk.Context, _ []string, req abci.RequestQuery bz, err := codec.MarshalJSONIndent(k.cdc, validators) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } + return bz, nil } -func queryDelegatorWithdrawAddress(ctx sdk.Context, _ []string, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryDelegatorWithdrawAddress(ctx sdk.Context, _ []string, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryDelegatorWithdrawAddrParams err := k.cdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } // cache-wrap context as to not persist state changes during querying @@ -245,20 +259,22 @@ func queryDelegatorWithdrawAddress(ctx sdk.Context, _ []string, req abci.Request bz, err := codec.MarshalJSONIndent(k.cdc, withdrawAddr) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return bz, nil } -func queryCommunityPool(ctx sdk.Context, _ []string, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryCommunityPool(ctx sdk.Context, _ []string, req abci.RequestQuery, k Keeper) ([]byte, error) { pool := k.GetFeePoolCommunityCoins(ctx) if pool == nil { pool = sdk.DecCoins{} } + bz, err := k.cdc.MarshalJSON(pool) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } + return bz, nil } diff --git a/x/distribution/keeper/querier_test.go b/x/distribution/keeper/querier_test.go index 2a2d1455f9db..e70ca2ea0f4b 100644 --- a/x/distribution/keeper/querier_test.go +++ b/x/distribution/keeper/querier_test.go @@ -189,10 +189,16 @@ func TestQueries(t *testing.T) { // test delegation rewards query sh := staking.NewHandler(sk) comm := staking.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0)) - msg := staking.NewMsgCreateValidator(valOpAddr1, valConsPk1, - sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), staking.Description{}, comm, sdk.OneInt()) - require.True(t, sh(ctx, msg).IsOK()) + msg := staking.NewMsgCreateValidator( + valOpAddr1, valConsPk1, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), staking.Description{}, comm, sdk.OneInt(), + ) + + res, err := sh(ctx, msg) + require.NoError(t, err) + require.NotNil(t, res) + staking.EndBlocker(ctx, sk) + val := sk.Validator(ctx, valOpAddr1) rewards := getQueriedDelegationRewards(t, ctx, cdc, querier, sdk.AccAddress(valOpAddr1), valOpAddr1) require.True(t, rewards.IsZero()) diff --git a/x/distribution/keeper/test_common.go b/x/distribution/keeper/test_common.go index 73c709e317e1..1d53c9d1816a 100644 --- a/x/distribution/keeper/test_common.go +++ b/x/distribution/keeper/test_common.go @@ -119,11 +119,11 @@ func CreateTestInputAdvanced(t *testing.T, isCheckTx bool, initPower int64, blacklistedAddrs[distrAcc.GetAddress().String()] = true cdc := MakeTestCodec() - pk := params.NewKeeper(cdc, keyParams, tkeyParams, params.DefaultCodespace) + pk := params.NewKeeper(cdc, keyParams, tkeyParams) ctx := sdk.NewContext(ms, abci.Header{ChainID: "foochainid"}, isCheckTx, log.NewNopLogger()) accountKeeper := auth.NewAccountKeeper(cdc, keyAcc, pk.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount) - bankKeeper := bank.NewBaseKeeper(accountKeeper, pk.Subspace(bank.DefaultParamspace), bank.DefaultCodespace, blacklistedAddrs) + bankKeeper := bank.NewBaseKeeper(accountKeeper, pk.Subspace(bank.DefaultParamspace), blacklistedAddrs) maccPerms := map[string][]string{ auth.FeeCollectorName: nil, types.ModuleName: nil, @@ -132,10 +132,10 @@ func CreateTestInputAdvanced(t *testing.T, isCheckTx bool, initPower int64, } supplyKeeper := supply.NewKeeper(cdc, keySupply, accountKeeper, bankKeeper, maccPerms) - sk := staking.NewKeeper(cdc, keyStaking, supplyKeeper, pk.Subspace(staking.DefaultParamspace), staking.DefaultCodespace) + sk := staking.NewKeeper(cdc, keyStaking, supplyKeeper, pk.Subspace(staking.DefaultParamspace)) sk.SetParams(ctx, staking.DefaultParams()) - keeper := NewKeeper(cdc, keyDistr, pk.Subspace(DefaultParamspace), sk, supplyKeeper, types.DefaultCodespace, auth.FeeCollectorName, blacklistedAddrs) + keeper := NewKeeper(cdc, keyDistr, pk.Subspace(DefaultParamspace), sk, supplyKeeper, auth.FeeCollectorName, blacklistedAddrs) initCoins := sdk.NewCoins(sdk.NewCoin(sk.BondDenom(ctx), initTokens)) totalSupply := sdk.NewCoins(sdk.NewCoin(sk.BondDenom(ctx), initTokens.MulRaw(int64(len(TestAddrs))))) diff --git a/x/distribution/simulation/operations.go b/x/distribution/simulation/operations.go index 9a9dea6b8d4b..d2857e6c5aff 100644 --- a/x/distribution/simulation/operations.go +++ b/x/distribution/simulation/operations.go @@ -1,7 +1,6 @@ package simulation import ( - "errors" "fmt" "math/rand" @@ -109,9 +108,9 @@ func SimulateMsgSetWithdrawAddress(ak types.AccountKeeper, k keeper.Keeper) simu simAccount.PrivKey, ) - res := app.Deliver(tx) - if !res.IsOK() { - return simulation.NoOpMsg(types.ModuleName), nil, errors.New(res.Log) + _, _, err = app.Deliver(tx) + if err != nil { + return simulation.NoOpMsg(types.ModuleName), nil, err } return simulation.NewOperationMsg(msg, true, ""), nil, nil @@ -155,9 +154,9 @@ func SimulateMsgWithdrawDelegatorReward(ak types.AccountKeeper, k keeper.Keeper, simAccount.PrivKey, ) - res := app.Deliver(tx) - if !res.IsOK() { - return simulation.NoOpMsg(types.ModuleName), nil, errors.New(res.Log) + _, _, err = app.Deliver(tx) + if err != nil { + return simulation.NoOpMsg(types.ModuleName), nil, err } return simulation.NewOperationMsg(msg, true, ""), nil, nil @@ -204,9 +203,9 @@ func SimulateMsgWithdrawValidatorCommission(ak types.AccountKeeper, k keeper.Kee simAccount.PrivKey, ) - res := app.Deliver(tx) - if !res.IsOK() { - return simulation.NoOpMsg(types.ModuleName), nil, errors.New(res.Log) + _, _, err = app.Deliver(tx) + if err != nil { + return simulation.NoOpMsg(types.ModuleName), nil, err } return simulation.NewOperationMsg(msg, true, ""), nil, nil @@ -254,9 +253,9 @@ func SimulateMsgFundCommunityPool(ak types.AccountKeeper, k keeper.Keeper, sk st funder.PrivKey, ) - res := app.Deliver(tx) - if !res.IsOK() { - return simulation.NoOpMsg(types.ModuleName), nil, errors.New(res.Log) + _, _, err = app.Deliver(tx) + if err != nil { + return simulation.NoOpMsg(types.ModuleName), nil, err } return simulation.NewOperationMsg(msg, true, ""), nil, nil diff --git a/x/distribution/types/errors.go b/x/distribution/types/errors.go index 2b6394114133..c06b731b6ee4 100644 --- a/x/distribution/types/errors.go +++ b/x/distribution/types/errors.go @@ -1,47 +1,21 @@ -// nolint package types import ( - sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) -type CodeType = sdk.CodeType - -const ( - DefaultCodespace sdk.CodespaceType = "distr" - CodeInvalidInput CodeType = 103 - CodeNoDistributionInfo CodeType = 104 - CodeNoValidatorCommission CodeType = 105 - CodeSetWithdrawAddrDisabled CodeType = 106 +// x/distribution module sentinel errors +var ( + ErrEmptyDelegatorAddr = sdkerrors.Register(ModuleName, 1, "delegator address is empty") + ErrEmptyWithdrawAddr = sdkerrors.Register(ModuleName, 2, "withdraw address is empty") + ErrEmptyValidatorAddr = sdkerrors.Register(ModuleName, 3, "validator address is empty") + ErrEmptyDelegationDistInfo = sdkerrors.Register(ModuleName, 4, "no delegation distribution info") + ErrNoValidatorDistInfo = sdkerrors.Register(ModuleName, 5, "no validator distribution info") + ErrNoValidatorCommission = sdkerrors.Register(ModuleName, 6, "no validator commission to withdraw") + ErrSetWithdrawAddrDisabled = sdkerrors.Register(ModuleName, 7, "set withdraw address disabled") + ErrBadDistribution = sdkerrors.Register(ModuleName, 8, "community pool does not have sufficient coins to distribute") + ErrInvalidProposalAmount = sdkerrors.Register(ModuleName, 9, "invalid community pool spend proposal amount") + ErrEmptyProposalRecipient = sdkerrors.Register(ModuleName, 10, "invalid community pool spend proposal recipient") + ErrNoValidatorExists = sdkerrors.Register(ModuleName, 11, "validator does not exist") + ErrNoDelegationExists = sdkerrors.Register(ModuleName, 12, "delegation does not exist") ) - -func ErrNilDelegatorAddr(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidInput, "delegator address is nil") -} -func ErrNilWithdrawAddr(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidInput, "withdraw address is nil") -} -func ErrNilValidatorAddr(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidInput, "validator address is nil") -} -func ErrNoDelegationDistInfo(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeNoDistributionInfo, "no delegation distribution info") -} -func ErrNoValidatorDistInfo(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeNoDistributionInfo, "no validator distribution info") -} -func ErrNoValidatorCommission(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeNoValidatorCommission, "no validator commission to withdraw") -} -func ErrSetWithdrawAddrDisabled(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeSetWithdrawAddrDisabled, "set withdraw address disabled") -} -func ErrBadDistribution(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidInput, "community pool does not have sufficient coins to distribute") -} -func ErrInvalidProposalAmount(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidInput, "invalid community pool spend proposal amount") -} -func ErrEmptyProposalRecipient(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidInput, "invalid community pool spend proposal recipient") -} diff --git a/x/distribution/types/expected_keepers.go b/x/distribution/types/expected_keepers.go index a51bc9d0403f..faa2f37235da 100644 --- a/x/distribution/types/expected_keepers.go +++ b/x/distribution/types/expected_keepers.go @@ -70,7 +70,7 @@ type SupplyKeeper interface { // TODO remove with genesis 2-phases refactor https://github.com/cosmos/cosmos-sdk/issues/2862 SetModuleAccount(sdk.Context, supplyexported.ModuleAccountI) - SendCoinsFromModuleToModule(ctx sdk.Context, senderModule string, recipientModule string, amt sdk.Coins) sdk.Error - SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) sdk.Error - SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) sdk.Error + SendCoinsFromModuleToModule(ctx sdk.Context, senderModule string, recipientModule string, amt sdk.Coins) error + SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error + SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error } diff --git a/x/distribution/types/msg.go b/x/distribution/types/msg.go index 408983cb0ff2..2068caef149e 100644 --- a/x/distribution/types/msg.go +++ b/x/distribution/types/msg.go @@ -3,6 +3,7 @@ package types import ( sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) // Verify interface at compile time @@ -36,13 +37,14 @@ func (msg MsgSetWithdrawAddress) GetSignBytes() []byte { } // quick validity check -func (msg MsgSetWithdrawAddress) ValidateBasic() sdk.Error { +func (msg MsgSetWithdrawAddress) ValidateBasic() error { if msg.DelegatorAddress.Empty() { - return ErrNilDelegatorAddr(DefaultCodespace) + return ErrEmptyDelegatorAddr } if msg.WithdrawAddress.Empty() { - return ErrNilWithdrawAddr(DefaultCodespace) + return ErrEmptyWithdrawAddr } + return nil } @@ -74,12 +76,12 @@ func (msg MsgWithdrawDelegatorReward) GetSignBytes() []byte { } // quick validity check -func (msg MsgWithdrawDelegatorReward) ValidateBasic() sdk.Error { +func (msg MsgWithdrawDelegatorReward) ValidateBasic() error { if msg.DelegatorAddress.Empty() { - return ErrNilDelegatorAddr(DefaultCodespace) + return ErrEmptyDelegatorAddr } if msg.ValidatorAddress.Empty() { - return ErrNilValidatorAddr(DefaultCodespace) + return ErrEmptyValidatorAddr } return nil } @@ -110,9 +112,9 @@ func (msg MsgWithdrawValidatorCommission) GetSignBytes() []byte { } // quick validity check -func (msg MsgWithdrawValidatorCommission) ValidateBasic() sdk.Error { +func (msg MsgWithdrawValidatorCommission) ValidateBasic() error { if msg.ValidatorAddress.Empty() { - return ErrNilValidatorAddr(DefaultCodespace) + return ErrEmptyValidatorAddr } return nil } @@ -155,12 +157,12 @@ func (msg MsgFundCommunityPool) GetSignBytes() []byte { } // ValidateBasic performs basic MsgFundCommunityPool message validation. -func (msg MsgFundCommunityPool) ValidateBasic() sdk.Error { +func (msg MsgFundCommunityPool) ValidateBasic() error { if !msg.Amount.IsValid() { - return sdk.ErrInvalidCoins(msg.Amount.String()) + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, msg.Amount.String()) } if msg.Depositor.Empty() { - return sdk.ErrInvalidAddress(msg.Depositor.String()) + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Depositor.String()) } return nil diff --git a/x/distribution/types/proposal.go b/x/distribution/types/proposal.go index 0562d81df18d..931e111ba719 100644 --- a/x/distribution/types/proposal.go +++ b/x/distribution/types/proposal.go @@ -47,17 +47,18 @@ func (csp CommunityPoolSpendProposal) ProposalRoute() string { return RouterKey func (csp CommunityPoolSpendProposal) ProposalType() string { return ProposalTypeCommunityPoolSpend } // ValidateBasic runs basic stateless validity checks -func (csp CommunityPoolSpendProposal) ValidateBasic() sdk.Error { - err := govtypes.ValidateAbstract(DefaultCodespace, csp) +func (csp CommunityPoolSpendProposal) ValidateBasic() error { + err := govtypes.ValidateAbstract(csp) if err != nil { return err } if !csp.Amount.IsValid() { - return ErrInvalidProposalAmount(DefaultCodespace) + return ErrInvalidProposalAmount } if csp.Recipient.Empty() { - return ErrEmptyProposalRecipient(DefaultCodespace) + return ErrEmptyProposalRecipient } + return nil } diff --git a/x/evidence/alias.go b/x/evidence/alias.go index 411f39751578..29b8447a365e 100644 --- a/x/evidence/alias.go +++ b/x/evidence/alias.go @@ -8,23 +8,19 @@ import ( // nolint const ( - ModuleName = types.ModuleName - StoreKey = types.StoreKey - RouterKey = types.RouterKey - QuerierRoute = types.QuerierRoute - DefaultParamspace = types.DefaultParamspace - QueryEvidence = types.QueryEvidence - QueryAllEvidence = types.QueryAllEvidence - QueryParameters = types.QueryParameters - CodeNoEvidenceHandlerExists = types.CodeNoEvidenceHandlerExists - CodeInvalidEvidence = types.CodeInvalidEvidence - CodeNoEvidenceExists = types.CodeNoEvidenceExists - TypeMsgSubmitEvidence = types.TypeMsgSubmitEvidence - DefaultCodespace = types.DefaultCodespace - EventTypeSubmitEvidence = types.EventTypeSubmitEvidence - AttributeValueCategory = types.AttributeValueCategory - AttributeKeyEvidenceHash = types.AttributeKeyEvidenceHash - DefaultMaxEvidenceAge = types.DefaultMaxEvidenceAge + ModuleName = types.ModuleName + StoreKey = types.StoreKey + RouterKey = types.RouterKey + QuerierRoute = types.QuerierRoute + DefaultParamspace = types.DefaultParamspace + QueryEvidence = types.QueryEvidence + QueryAllEvidence = types.QueryAllEvidence + QueryParameters = types.QueryParameters + TypeMsgSubmitEvidence = types.TypeMsgSubmitEvidence + EventTypeSubmitEvidence = types.EventTypeSubmitEvidence + AttributeValueCategory = types.AttributeValueCategory + AttributeKeyEvidenceHash = types.AttributeKeyEvidenceHash + DefaultMaxEvidenceAge = types.DefaultMaxEvidenceAge ) var ( diff --git a/x/evidence/genesis_test.go b/x/evidence/genesis_test.go index a77b847db177..10a8a2c75730 100644 --- a/x/evidence/genesis_test.go +++ b/x/evidence/genesis_test.go @@ -32,8 +32,7 @@ func (suite *GenesisTestSuite) SetupTest() { // recreate keeper in order to use custom testing types evidenceKeeper := evidence.NewKeeper( - cdc, app.GetKey(evidence.StoreKey), app.GetSubspace(evidence.ModuleName), - evidence.DefaultCodespace, app.StakingKeeper, app.SlashingKeeper, + cdc, app.GetKey(evidence.StoreKey), app.GetSubspace(evidence.ModuleName), app.StakingKeeper, app.SlashingKeeper, ) router := evidence.NewRouter() router = router.AddRoute(types.TestEvidenceRouteEquivocation, types.TestEquivocationHandler(*evidenceKeeper)) diff --git a/x/evidence/handler.go b/x/evidence/handler.go index 714da444c444..d5af1206bc01 100644 --- a/x/evidence/handler.go +++ b/x/evidence/handler.go @@ -1,13 +1,12 @@ package evidence import ( - "fmt" - sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) func NewHandler(k Keeper) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { ctx = ctx.WithEventManager(sdk.NewEventManager()) switch msg := msg.(type) { @@ -15,14 +14,14 @@ func NewHandler(k Keeper) sdk.Handler { return handleMsgSubmitEvidence(ctx, k, msg) default: - return sdk.ErrUnknownRequest(fmt.Sprintf("unrecognized %s message type: %T", ModuleName, msg)).Result() + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s message type: %T", ModuleName, msg) } } } -func handleMsgSubmitEvidence(ctx sdk.Context, k Keeper, msg MsgSubmitEvidence) sdk.Result { +func handleMsgSubmitEvidence(ctx sdk.Context, k Keeper, msg MsgSubmitEvidence) (*sdk.Result, error) { if err := k.SubmitEvidence(ctx, msg.Evidence); err != nil { - return sdk.ConvertError(err).Result() + return nil, err } ctx.EventManager().EmitEvent( @@ -33,8 +32,8 @@ func handleMsgSubmitEvidence(ctx sdk.Context, k Keeper, msg MsgSubmitEvidence) s ), ) - return sdk.Result{ + return &sdk.Result{ Data: msg.Evidence.Hash(), Events: ctx.EventManager().Events(), - } + }, nil } diff --git a/x/evidence/handler_test.go b/x/evidence/handler_test.go index 1957778950ad..e5798bd01482 100644 --- a/x/evidence/handler_test.go +++ b/x/evidence/handler_test.go @@ -31,8 +31,7 @@ func (suite *HandlerTestSuite) SetupTest() { // recreate keeper in order to use custom testing types evidenceKeeper := evidence.NewKeeper( - cdc, app.GetKey(evidence.StoreKey), app.GetSubspace(evidence.ModuleName), - evidence.DefaultCodespace, app.StakingKeeper, app.SlashingKeeper, + cdc, app.GetKey(evidence.StoreKey), app.GetSubspace(evidence.ModuleName), app.StakingKeeper, app.SlashingKeeper, ) router := evidence.NewRouter() router = router.AddRoute(types.TestEvidenceRouteEquivocation, types.TestEquivocationHandler(*evidenceKeeper)) @@ -66,8 +65,9 @@ func (suite *HandlerTestSuite) TestMsgSubmitEvidence_Valid() { ctx := suite.ctx.WithIsCheckTx(false) msg := evidence.NewMsgSubmitEvidence(e, s) - res := suite.handler(ctx, msg) - suite.True(res.IsOK()) + res, err := suite.handler(ctx, msg) + suite.NoError(err) + suite.NotNil(res) suite.Equal(e.Hash().Bytes(), res.Data) } @@ -94,8 +94,9 @@ func (suite *HandlerTestSuite) TestMsgSubmitEvidence_Invalid() { ctx := suite.ctx.WithIsCheckTx(false) msg := evidence.NewMsgSubmitEvidence(e, s) - res := suite.handler(ctx, msg) - suite.False(res.IsOK()) + res, err := suite.handler(ctx, msg) + suite.Error(err) + suite.Nil(res) } func TestHandlerTestSuite(t *testing.T) { diff --git a/x/evidence/internal/keeper/infraction_test.go b/x/evidence/internal/keeper/infraction_test.go index ca68948f5eb1..cbef53de1921 100644 --- a/x/evidence/internal/keeper/infraction_test.go +++ b/x/evidence/internal/keeper/infraction_test.go @@ -28,8 +28,9 @@ func (suite *KeeperTestSuite) TestHandleDoubleSign() { operatorAddr, val := valAddresses[0], pubkeys[0] // create validator - res := staking.NewHandler(suite.app.StakingKeeper)(ctx, newTestMsgCreateValidator(operatorAddr, val, amt)) - suite.True(res.IsOK(), res.Log) + res, err := staking.NewHandler(suite.app.StakingKeeper)(ctx, newTestMsgCreateValidator(operatorAddr, val, amt)) + suite.NoError(err) + suite.NotNil(res) // execute end-blocker and verify validator attributes staking.EndBlocker(ctx, suite.app.StakingKeeper) @@ -78,8 +79,9 @@ func (suite *KeeperTestSuite) TestHandleDoubleSign() { validator, _ := suite.app.StakingKeeper.GetValidator(ctx, operatorAddr) totalBond := validator.TokensFromShares(del.GetShares()).TruncateInt() msgUnbond := staking.NewMsgUndelegate(sdk.AccAddress(operatorAddr), operatorAddr, sdk.NewCoin(stakingParams.BondDenom, totalBond)) - res = staking.NewHandler(suite.app.StakingKeeper)(ctx, msgUnbond) - suite.True(res.IsOK()) + res, err = staking.NewHandler(suite.app.StakingKeeper)(ctx, msgUnbond) + suite.NoError(err) + suite.NotNil(res) } func (suite *KeeperTestSuite) TestHandleDoubleSign_TooOld() { @@ -92,8 +94,9 @@ func (suite *KeeperTestSuite) TestHandleDoubleSign_TooOld() { operatorAddr, val := valAddresses[0], pubkeys[0] // create validator - res := staking.NewHandler(suite.app.StakingKeeper)(ctx, newTestMsgCreateValidator(operatorAddr, val, amt)) - suite.True(res.IsOK(), res.Log) + res, err := staking.NewHandler(suite.app.StakingKeeper)(ctx, newTestMsgCreateValidator(operatorAddr, val, amt)) + suite.NoError(err) + suite.NotNil(res) // execute end-blocker and verify validator attributes staking.EndBlocker(ctx, suite.app.StakingKeeper) diff --git a/x/evidence/internal/keeper/keeper.go b/x/evidence/internal/keeper/keeper.go index 26b45db7d69d..fd6c8027d8fd 100644 --- a/x/evidence/internal/keeper/keeper.go +++ b/x/evidence/internal/keeper/keeper.go @@ -9,6 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/evidence/exported" "github.com/cosmos/cosmos-sdk/x/evidence/internal/types" "github.com/cosmos/cosmos-sdk/x/params" @@ -24,11 +25,10 @@ type Keeper struct { router types.Router stakingKeeper types.StakingKeeper slashingKeeper types.SlashingKeeper - codespace sdk.CodespaceType } func NewKeeper( - cdc *codec.Codec, storeKey sdk.StoreKey, paramSpace params.Subspace, codespace sdk.CodespaceType, + cdc *codec.Codec, storeKey sdk.StoreKey, paramSpace params.Subspace, stakingKeeper types.StakingKeeper, slashingKeeper types.SlashingKeeper, ) *Keeper { @@ -43,7 +43,6 @@ func NewKeeper( paramSpace: paramSpace, stakingKeeper: stakingKeeper, slashingKeeper: slashingKeeper, - codespace: codespace, } } @@ -74,7 +73,7 @@ func (k *Keeper) SetRouter(rtr types.Router) { // no handler exists, an error is returned. func (k Keeper) GetEvidenceHandler(evidenceRoute string) (types.Handler, error) { if !k.router.HasRoute(evidenceRoute) { - return nil, types.ErrNoEvidenceHandlerExists(k.codespace, evidenceRoute) + return nil, sdkerrors.Wrap(types.ErrNoEvidenceHandlerExists, evidenceRoute) } return k.router.GetRoute(evidenceRoute), nil @@ -86,15 +85,15 @@ func (k Keeper) GetEvidenceHandler(evidenceRoute string) (types.Handler, error) // persisted. func (k Keeper) SubmitEvidence(ctx sdk.Context, evidence exported.Evidence) error { if _, ok := k.GetEvidence(ctx, evidence.Hash()); ok { - return types.ErrEvidenceExists(k.codespace, evidence.Hash().String()) + return sdkerrors.Wrap(types.ErrEvidenceExists, evidence.Hash().String()) } if !k.router.HasRoute(evidence.Route()) { - return types.ErrNoEvidenceHandlerExists(k.codespace, evidence.Route()) + return sdkerrors.Wrap(types.ErrNoEvidenceHandlerExists, evidence.Route()) } handler := k.router.GetRoute(evidence.Route()) if err := handler(ctx, evidence); err != nil { - return types.ErrInvalidEvidence(k.codespace, err.Error()) + return sdkerrors.Wrap(types.ErrInvalidEvidence, err.Error()) } ctx.EventManager().EmitEvent( diff --git a/x/evidence/internal/keeper/keeper_test.go b/x/evidence/internal/keeper/keeper_test.go index bde9f08f02ce..45347ab96be0 100644 --- a/x/evidence/internal/keeper/keeper_test.go +++ b/x/evidence/internal/keeper/keeper_test.go @@ -66,8 +66,7 @@ func (suite *KeeperTestSuite) SetupTest() { // recreate keeper in order to use custom testing types evidenceKeeper := evidence.NewKeeper( - cdc, app.GetKey(evidence.StoreKey), app.GetSubspace(evidence.ModuleName), - evidence.DefaultCodespace, app.StakingKeeper, app.SlashingKeeper, + cdc, app.GetKey(evidence.StoreKey), app.GetSubspace(evidence.ModuleName), app.StakingKeeper, app.SlashingKeeper, ) router := evidence.NewRouter() router = router.AddRoute(types.TestEvidenceRouteEquivocation, types.TestEquivocationHandler(*evidenceKeeper)) diff --git a/x/evidence/internal/keeper/querier.go b/x/evidence/internal/keeper/querier.go index dfbda68f66d6..cbb616677e8f 100644 --- a/x/evidence/internal/keeper/querier.go +++ b/x/evidence/internal/keeper/querier.go @@ -14,7 +14,7 @@ import ( ) func NewQuerier(k Keeper) sdk.Querier { - return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, sdk.Error) { + return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) { var ( res []byte err error @@ -31,10 +31,10 @@ func NewQuerier(k Keeper) sdk.Querier { res, err = queryAllEvidence(ctx, req, k) default: - err = sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown %s query endpoint", types.ModuleName) + err = sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown %s query endpoint: %s", types.ModuleName, path[0]) } - return res, sdk.ConvertError(err) + return res, err } } @@ -64,7 +64,7 @@ func queryEvidence(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, er evidence, ok := k.GetEvidence(ctx, hash) if !ok { - return nil, types.ErrNoEvidenceExists(k.codespace, params.EvidenceHash) + return nil, sdkerrors.Wrap(types.ErrNoEvidenceExists, params.EvidenceHash) } res, err := codec.MarshalJSONIndent(k.cdc, evidence) diff --git a/x/evidence/internal/types/errors.go b/x/evidence/internal/types/errors.go index 2054cee9fb66..83ffe06002ae 100644 --- a/x/evidence/internal/types/errors.go +++ b/x/evidence/internal/types/errors.go @@ -2,57 +2,13 @@ package types import ( - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) -// Error codes specific to the evidence module -const ( - DefaultCodespace sdk.CodespaceType = ModuleName - - CodeNoEvidenceHandlerExists sdk.CodeType = 1 - CodeInvalidEvidence sdk.CodeType = 2 - CodeNoEvidenceExists sdk.CodeType = 3 - CodeEvidenceExists sdk.CodeType = 4 +// x/evidence module sentinel errors +var ( + ErrNoEvidenceHandlerExists = sdkerrors.Register(ModuleName, 1, "unregistered handler for evidence type") + ErrInvalidEvidence = sdkerrors.Register(ModuleName, 2, "invalid evidence") + ErrNoEvidenceExists = sdkerrors.Register(ModuleName, 3, "evidence does not exist") + ErrEvidenceExists = sdkerrors.Register(ModuleName, 4, "evidence already exists") ) - -// ErrNoEvidenceHandlerExists returns a typed ABCI error for an invalid evidence -// handler route. -func ErrNoEvidenceHandlerExists(codespace sdk.CodespaceType, route string) error { - return sdkerrors.New( - string(codespace), - uint32(CodeNoEvidenceHandlerExists), - fmt.Sprintf("route '%s' does not have a registered evidence handler", route), - ) -} - -// ErrInvalidEvidence returns a typed ABCI error for invalid evidence. -func ErrInvalidEvidence(codespace sdk.CodespaceType, msg string) error { - return sdkerrors.New( - string(codespace), - uint32(CodeInvalidEvidence), - fmt.Sprintf("invalid evidence: %s", msg), - ) -} - -// ErrNoEvidenceExists returns a typed ABCI error for Evidence that does not exist -// for a given hash. -func ErrNoEvidenceExists(codespace sdk.CodespaceType, hash string) error { - return sdkerrors.New( - string(codespace), - uint32(CodeNoEvidenceExists), - fmt.Sprintf("evidence with hash %s does not exist", hash), - ) -} - -// ErrEvidenceExists returns a typed ABCI error for Evidence that already exists -// by hash in state. -func ErrEvidenceExists(codespace sdk.CodespaceType, hash string) error { - return sdkerrors.New( - string(codespace), - uint32(CodeEvidenceExists), - fmt.Sprintf("evidence with hash %s already exists", hash), - ) -} diff --git a/x/evidence/internal/types/msgs.go b/x/evidence/internal/types/msgs.go index b09f120da927..3fbb50844f57 100644 --- a/x/evidence/internal/types/msgs.go +++ b/x/evidence/internal/types/msgs.go @@ -33,15 +33,15 @@ func (m MsgSubmitEvidence) Route() string { return RouterKey } func (m MsgSubmitEvidence) Type() string { return TypeMsgSubmitEvidence } // ValidateBasic performs basic (non-state-dependant) validation on a MsgSubmitEvidence. -func (m MsgSubmitEvidence) ValidateBasic() sdk.Error { +func (m MsgSubmitEvidence) ValidateBasic() error { if m.Evidence == nil { - return sdk.ConvertError(ErrInvalidEvidence(DefaultCodespace, "missing evidence")) + return sdkerrors.Wrap(ErrInvalidEvidence, "missing evidence") } if err := m.Evidence.ValidateBasic(); err != nil { - return sdk.ConvertError(err) + return err } if m.Submitter.Empty() { - return sdk.ConvertError(sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, m.Submitter.String())) + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, m.Submitter.String()) } return nil diff --git a/x/genutil/client/rest/query.go b/x/genutil/client/rest/query.go index 4f0f318aa201..0159223e8e7c 100644 --- a/x/genutil/client/rest/query.go +++ b/x/genutil/client/rest/query.go @@ -1,6 +1,7 @@ package rest import ( + "fmt" "net/http" "github.com/cosmos/cosmos-sdk/client/context" @@ -14,15 +15,19 @@ import ( func QueryGenesisTxs(cliCtx context.CLIContext, w http.ResponseWriter) { resultGenesis, err := cliCtx.Client.Genesis() if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, - sdk.AppendMsgToErr("could not retrieve genesis from client", err.Error())) + rest.WriteErrorResponse( + w, http.StatusInternalServerError, + fmt.Sprintf("failed to retrieve genesis from client: %s", err), + ) return } appState, err := types.GenesisStateFromGenDoc(cliCtx.Codec, *resultGenesis.Genesis) if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, - sdk.AppendMsgToErr("could not decode genesis doc", err.Error())) + rest.WriteErrorResponse( + w, http.StatusInternalServerError, + fmt.Sprintf("failed to decode genesis doc: %s", err), + ) return } @@ -31,8 +36,10 @@ func QueryGenesisTxs(cliCtx context.CLIContext, w http.ResponseWriter) { for i, tx := range genState.GenTxs { err := cliCtx.Codec.UnmarshalJSON(tx, &genTxs[i]) if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, - sdk.AppendMsgToErr("could not decode genesis transaction", err.Error())) + rest.WriteErrorResponse( + w, http.StatusInternalServerError, + fmt.Sprintf("failed to decode genesis transaction: %s", err), + ) return } } diff --git a/x/gov/abci.go b/x/gov/abci.go index 31b1f40c9d2a..21db8f5cd2c2 100644 --- a/x/gov/abci.go +++ b/x/gov/abci.go @@ -65,7 +65,7 @@ func EndBlocker(ctx sdk.Context, keeper Keeper) { } else { proposal.Status = StatusFailed tagValue = types.AttributeValueProposalFailed - logMsg = fmt.Sprintf("passed, but failed on execution: %s", err.ABCILog()) + logMsg = fmt.Sprintf("passed, but failed on execution: %s", err) } } else { proposal.Status = StatusRejected diff --git a/x/gov/abci_test.go b/x/gov/abci_test.go index 42616b36c00b..6ee3a3075920 100644 --- a/x/gov/abci_test.go +++ b/x/gov/abci_test.go @@ -32,8 +32,9 @@ func TestTickExpiredDepositPeriod(t *testing.T) { input.addrs[0], ) - res := govHandler(ctx, newProposalMsg) - require.True(t, res.IsOK()) + res, err := govHandler(ctx, newProposalMsg) + require.NoError(t, err) + require.NotNil(t, res) inactiveQueue = input.keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) require.False(t, inactiveQueue.Valid()) @@ -81,8 +82,9 @@ func TestTickMultipleExpiredDepositPeriod(t *testing.T) { input.addrs[0], ) - res := govHandler(ctx, newProposalMsg) - require.True(t, res.IsOK()) + res, err := govHandler(ctx, newProposalMsg) + require.NoError(t, err) + require.NotNil(t, res) inactiveQueue = input.keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) require.False(t, inactiveQueue.Valid()) @@ -102,8 +104,9 @@ func TestTickMultipleExpiredDepositPeriod(t *testing.T) { input.addrs[0], ) - res = govHandler(ctx, newProposalMsg2) - require.True(t, res.IsOK()) + res, err = govHandler(ctx, newProposalMsg2) + require.NoError(t, err) + require.NotNil(t, res) newHeader = ctx.BlockHeader() newHeader.Time = ctx.BlockHeader().Time.Add(input.keeper.GetDepositParams(ctx).MaxDepositPeriod).Add(time.Duration(-1) * time.Second) @@ -152,8 +155,10 @@ func TestTickPassedDepositPeriod(t *testing.T) { input.addrs[0], ) - res := govHandler(ctx, newProposalMsg) - require.True(t, res.IsOK()) + res, err := govHandler(ctx, newProposalMsg) + require.NoError(t, err) + require.NotNil(t, res) + proposalID := GetProposalIDFromBytes(res.Data) inactiveQueue = input.keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) @@ -169,8 +174,10 @@ func TestTickPassedDepositPeriod(t *testing.T) { inactiveQueue.Close() newDepositMsg := NewMsgDeposit(input.addrs[1], proposalID, sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 5)}) - res = govHandler(ctx, newDepositMsg) - require.True(t, res.IsOK()) + + res, err = govHandler(ctx, newDepositMsg) + require.NoError(t, err) + require.NotNil(t, res) activeQueue = input.keeper.ActiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) require.False(t, activeQueue.Valid()) @@ -197,8 +204,10 @@ func TestTickPassedVotingPeriod(t *testing.T) { proposalCoins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(5))} newProposalMsg := NewMsgSubmitProposal(keep.TestProposal, proposalCoins, input.addrs[0]) - res := govHandler(ctx, newProposalMsg) - require.True(t, res.IsOK()) + res, err := govHandler(ctx, newProposalMsg) + require.NoError(t, err) + require.NotNil(t, res) + proposalID := GetProposalIDFromBytes(res.Data) newHeader := ctx.BlockHeader() @@ -206,8 +215,10 @@ func TestTickPassedVotingPeriod(t *testing.T) { ctx = ctx.WithBlockHeader(newHeader) newDepositMsg := NewMsgDeposit(input.addrs[1], proposalID, proposalCoins) - res = govHandler(ctx, newDepositMsg) - require.True(t, res.IsOK()) + + res, err = govHandler(ctx, newDepositMsg) + require.NoError(t, err) + require.NotNil(t, res) newHeader = ctx.BlockHeader() newHeader.Time = ctx.BlockHeader().Time.Add(input.keeper.GetDepositParams(ctx).MaxDepositPeriod).Add(input.keeper.GetVotingParams(ctx).VotingPeriod) @@ -259,8 +270,10 @@ func TestProposalPassedEndblocker(t *testing.T) { proposalCoins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(10))} newDepositMsg := NewMsgDeposit(input.addrs[0], proposal.ProposalID, proposalCoins) - res := handler(ctx, newDepositMsg) - require.True(t, res.IsOK()) + + res, err := handler(ctx, newDepositMsg) + require.NoError(t, err) + require.NotNil(t, res) macc = input.keeper.GetGovernanceAccount(ctx) require.NotNil(t, macc) @@ -308,8 +321,10 @@ func TestEndBlockerProposalHandlerFailed(t *testing.T) { proposalCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(10))) newDepositMsg := NewMsgDeposit(input.addrs[0], proposal.ProposalID, proposalCoins) - res := handler(ctx, newDepositMsg) - require.True(t, res.IsOK()) + + res, err := handler(ctx, newDepositMsg) + require.NoError(t, err) + require.NotNil(t, res) err = input.keeper.AddVote(ctx, proposal.ProposalID, input.addrs[0], OptionYes) require.NoError(t, err) diff --git a/x/gov/alias.go b/x/gov/alias.go index 0ca57b7a39fc..df5f2cb9ce77 100644 --- a/x/gov/alias.go +++ b/x/gov/alias.go @@ -1,62 +1,47 @@ -// nolint -// autogenerated code using github.com/rigelrozanski/multitool -// aliases generated for the following subdirectories: -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/gov/keeper -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/gov/types package gov +// nolint + import ( "github.com/cosmos/cosmos-sdk/x/gov/keeper" "github.com/cosmos/cosmos-sdk/x/gov/types" ) const ( - MaxDescriptionLength = types.MaxDescriptionLength - MaxTitleLength = types.MaxTitleLength - DefaultCodespace = types.DefaultCodespace - CodeUnknownProposal = types.CodeUnknownProposal - CodeInactiveProposal = types.CodeInactiveProposal - CodeAlreadyActiveProposal = types.CodeAlreadyActiveProposal - CodeAlreadyFinishedProposal = types.CodeAlreadyFinishedProposal - CodeAddressNotStaked = types.CodeAddressNotStaked - CodeInvalidContent = types.CodeInvalidContent - CodeInvalidProposalType = types.CodeInvalidProposalType - CodeInvalidVote = types.CodeInvalidVote - CodeInvalidGenesis = types.CodeInvalidGenesis - CodeInvalidProposalStatus = types.CodeInvalidProposalStatus - CodeProposalHandlerNotExists = types.CodeProposalHandlerNotExists - DefaultPeriod = types.DefaultPeriod - ModuleName = types.ModuleName - StoreKey = types.StoreKey - RouterKey = types.RouterKey - QuerierRoute = types.QuerierRoute - DefaultParamspace = types.DefaultParamspace - TypeMsgDeposit = types.TypeMsgDeposit - TypeMsgVote = types.TypeMsgVote - TypeMsgSubmitProposal = types.TypeMsgSubmitProposal - StatusNil = types.StatusNil - StatusDepositPeriod = types.StatusDepositPeriod - StatusVotingPeriod = types.StatusVotingPeriod - StatusPassed = types.StatusPassed - StatusRejected = types.StatusRejected - StatusFailed = types.StatusFailed - ProposalTypeText = types.ProposalTypeText - QueryParams = types.QueryParams - QueryProposals = types.QueryProposals - QueryProposal = types.QueryProposal - QueryDeposits = types.QueryDeposits - QueryDeposit = types.QueryDeposit - QueryVotes = types.QueryVotes - QueryVote = types.QueryVote - QueryTally = types.QueryTally - ParamDeposit = types.ParamDeposit - ParamVoting = types.ParamVoting - ParamTallying = types.ParamTallying - OptionEmpty = types.OptionEmpty - OptionYes = types.OptionYes - OptionAbstain = types.OptionAbstain - OptionNo = types.OptionNo - OptionNoWithVeto = types.OptionNoWithVeto + MaxDescriptionLength = types.MaxDescriptionLength + MaxTitleLength = types.MaxTitleLength + DefaultPeriod = types.DefaultPeriod + ModuleName = types.ModuleName + StoreKey = types.StoreKey + RouterKey = types.RouterKey + QuerierRoute = types.QuerierRoute + DefaultParamspace = types.DefaultParamspace + TypeMsgDeposit = types.TypeMsgDeposit + TypeMsgVote = types.TypeMsgVote + TypeMsgSubmitProposal = types.TypeMsgSubmitProposal + StatusNil = types.StatusNil + StatusDepositPeriod = types.StatusDepositPeriod + StatusVotingPeriod = types.StatusVotingPeriod + StatusPassed = types.StatusPassed + StatusRejected = types.StatusRejected + StatusFailed = types.StatusFailed + ProposalTypeText = types.ProposalTypeText + QueryParams = types.QueryParams + QueryProposals = types.QueryProposals + QueryProposal = types.QueryProposal + QueryDeposits = types.QueryDeposits + QueryDeposit = types.QueryDeposit + QueryVotes = types.QueryVotes + QueryVote = types.QueryVote + QueryTally = types.QueryTally + ParamDeposit = types.ParamDeposit + ParamVoting = types.ParamVoting + ParamTallying = types.ParamTallying + OptionEmpty = types.OptionEmpty + OptionYes = types.OptionYes + OptionAbstain = types.OptionAbstain + OptionNo = types.OptionNo + OptionNoWithVeto = types.OptionNoWithVeto ) var ( diff --git a/x/gov/genesis_test.go b/x/gov/genesis_test.go index 1beb0baecaa6..8626e7821e5f 100644 --- a/x/gov/genesis_test.go +++ b/x/gov/genesis_test.go @@ -29,7 +29,7 @@ func TestImportExportQueues(t *testing.T) { require.NoError(t, err) proposalID2 := proposal2.ProposalID - err, votingStarted := input.keeper.AddDeposit(ctx, proposalID2, input.addrs[0], input.keeper.GetDepositParams(ctx).MinDeposit) + votingStarted, err := input.keeper.AddDeposit(ctx, proposalID2, input.addrs[0], input.keeper.GetDepositParams(ctx).MinDeposit) require.NoError(t, err) require.True(t, votingStarted) diff --git a/x/gov/handler.go b/x/gov/handler.go index 47efe4473cd4..4e4aee2c5334 100644 --- a/x/gov/handler.go +++ b/x/gov/handler.go @@ -4,12 +4,13 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/gov/types" ) // NewHandler creates an sdk.Handler for all the gov type messages func NewHandler(keeper Keeper) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { ctx = ctx.WithEventManager(sdk.NewEventManager()) switch msg := msg.(type) { @@ -23,21 +24,20 @@ func NewHandler(keeper Keeper) sdk.Handler { return handleMsgVote(ctx, keeper, msg) default: - errMsg := fmt.Sprintf("unrecognized gov message type: %T", msg) - return sdk.ErrUnknownRequest(errMsg).Result() + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s message type: %T", ModuleName, msg) } } } -func handleMsgSubmitProposal(ctx sdk.Context, keeper Keeper, msg MsgSubmitProposal) sdk.Result { +func handleMsgSubmitProposal(ctx sdk.Context, keeper Keeper, msg MsgSubmitProposal) (*sdk.Result, error) { proposal, err := keeper.SubmitProposal(ctx, msg.Content) if err != nil { - return err.Result() + return nil, err } - err, votingStarted := keeper.AddDeposit(ctx, proposal.ProposalID, msg.Proposer, msg.InitialDeposit) + votingStarted, err := keeper.AddDeposit(ctx, proposal.ProposalID, msg.Proposer, msg.InitialDeposit) if err != nil { - return err.Result() + return nil, err } ctx.EventManager().EmitEvent( @@ -56,16 +56,16 @@ func handleMsgSubmitProposal(ctx sdk.Context, keeper Keeper, msg MsgSubmitPropos } ctx.EventManager().EmitEvent(submitEvent) - return sdk.Result{ + return &sdk.Result{ Data: GetProposalIDBytes(proposal.ProposalID), Events: ctx.EventManager().Events(), - } + }, nil } -func handleMsgDeposit(ctx sdk.Context, keeper Keeper, msg MsgDeposit) sdk.Result { - err, votingStarted := keeper.AddDeposit(ctx, msg.ProposalID, msg.Depositor, msg.Amount) +func handleMsgDeposit(ctx sdk.Context, keeper Keeper, msg MsgDeposit) (*sdk.Result, error) { + votingStarted, err := keeper.AddDeposit(ctx, msg.ProposalID, msg.Depositor, msg.Amount) if err != nil { - return err.Result() + return nil, err } ctx.EventManager().EmitEvent( @@ -85,13 +85,13 @@ func handleMsgDeposit(ctx sdk.Context, keeper Keeper, msg MsgDeposit) sdk.Result ) } - return sdk.Result{Events: ctx.EventManager().Events()} + return &sdk.Result{Events: ctx.EventManager().Events()}, nil } -func handleMsgVote(ctx sdk.Context, keeper Keeper, msg MsgVote) sdk.Result { +func handleMsgVote(ctx sdk.Context, keeper Keeper, msg MsgVote) (*sdk.Result, error) { err := keeper.AddVote(ctx, msg.ProposalID, msg.Voter, msg.Option) if err != nil { - return err.Result() + return nil, err } ctx.EventManager().EmitEvent( @@ -102,6 +102,5 @@ func handleMsgVote(ctx sdk.Context, keeper Keeper, msg MsgVote) sdk.Result { ), ) - return sdk.Result{Events: ctx.EventManager().Events()} - + return &sdk.Result{Events: ctx.EventManager().Events()}, nil } diff --git a/x/gov/handler_test.go b/x/gov/handler_test.go index 33dec83ff121..134b25ff0fc5 100644 --- a/x/gov/handler_test.go +++ b/x/gov/handler_test.go @@ -15,7 +15,8 @@ func TestInvalidMsg(t *testing.T) { k := Keeper{} h := NewHandler(k) - res := h(sdk.NewContext(nil, abci.Header{}, false, nil), sdk.NewTestMsg()) - require.False(t, res.IsOK()) - require.True(t, strings.Contains(res.Log, "unrecognized gov message type")) + res, err := h(sdk.NewContext(nil, abci.Header{}, false, nil), sdk.NewTestMsg()) + require.Error(t, err) + require.Nil(t, res) + require.True(t, strings.Contains(err.Error(), "unrecognized gov message type")) } diff --git a/x/gov/keeper/deposit.go b/x/gov/keeper/deposit.go index 426d43d4f14e..c86df046e5e0 100644 --- a/x/gov/keeper/deposit.go +++ b/x/gov/keeper/deposit.go @@ -4,6 +4,7 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/gov/types" ) @@ -93,22 +94,22 @@ func (keeper Keeper) IterateDeposits(ctx sdk.Context, proposalID uint64, cb func // AddDeposit adds or updates a deposit of a specific depositor on a specific proposal // Activates voting period when appropriate -func (keeper Keeper) AddDeposit(ctx sdk.Context, proposalID uint64, depositorAddr sdk.AccAddress, depositAmount sdk.Coins) (sdk.Error, bool) { +func (keeper Keeper) AddDeposit(ctx sdk.Context, proposalID uint64, depositorAddr sdk.AccAddress, depositAmount sdk.Coins) (bool, error) { // Checks to see if proposal exists proposal, ok := keeper.GetProposal(ctx, proposalID) if !ok { - return types.ErrUnknownProposal(keeper.codespace, proposalID), false + return false, sdkerrors.Wrapf(types.ErrUnknownProposal, "%d", proposalID) } // Check if proposal is still depositable if (proposal.Status != types.StatusDepositPeriod) && (proposal.Status != types.StatusVotingPeriod) { - return types.ErrInactiveProposal(keeper.codespace, proposalID), false + return false, sdkerrors.Wrapf(types.ErrInactiveProposal, "%d", proposalID) } // update the governance module's account coins pool err := keeper.supplyKeeper.SendCoinsFromAccountToModule(ctx, depositorAddr, types.ModuleName, depositAmount) if err != nil { - return err, false + return false, err } // Update proposal @@ -139,7 +140,7 @@ func (keeper Keeper) AddDeposit(ctx sdk.Context, proposalID uint64, depositorAdd ) keeper.SetDeposit(ctx, deposit) - return nil, activatedVotingPeriod + return activatedVotingPeriod, nil } // RefundDeposits refunds and deletes all the deposits on a specific proposal diff --git a/x/gov/keeper/deposit_test.go b/x/gov/keeper/deposit_test.go index c6c229893119..b5d6cce405a2 100644 --- a/x/gov/keeper/deposit_test.go +++ b/x/gov/keeper/deposit_test.go @@ -33,7 +33,7 @@ func TestDeposits(t *testing.T) { require.True(t, proposal.VotingStartTime.Equal(time.Time{})) // Check first deposit - err, votingStarted := keeper.AddDeposit(ctx, proposalID, TestAddrs[0], fourStake) + votingStarted, err := keeper.AddDeposit(ctx, proposalID, TestAddrs[0], fourStake) require.NoError(t, err) require.False(t, votingStarted) deposit, found = keeper.GetDeposit(ctx, proposalID, TestAddrs[0]) @@ -46,7 +46,7 @@ func TestDeposits(t *testing.T) { require.Equal(t, addr0Initial.Sub(fourStake), ak.GetAccount(ctx, TestAddrs[0]).GetCoins()) // Check a second deposit from same address - err, votingStarted = keeper.AddDeposit(ctx, proposalID, TestAddrs[0], fiveStake) + votingStarted, err = keeper.AddDeposit(ctx, proposalID, TestAddrs[0], fiveStake) require.NoError(t, err) require.False(t, votingStarted) deposit, found = keeper.GetDeposit(ctx, proposalID, TestAddrs[0]) @@ -59,7 +59,7 @@ func TestDeposits(t *testing.T) { require.Equal(t, addr0Initial.Sub(fourStake).Sub(fiveStake), ak.GetAccount(ctx, TestAddrs[0]).GetCoins()) // Check third deposit from a new address - err, votingStarted = keeper.AddDeposit(ctx, proposalID, TestAddrs[1], fourStake) + votingStarted, err = keeper.AddDeposit(ctx, proposalID, TestAddrs[1], fourStake) require.NoError(t, err) require.True(t, votingStarted) deposit, found = keeper.GetDeposit(ctx, proposalID, TestAddrs[1]) diff --git a/x/gov/keeper/keeper.go b/x/gov/keeper/keeper.go index b322d3e6b4cd..7a51e6e2bf29 100644 --- a/x/gov/keeper/keeper.go +++ b/x/gov/keeper/keeper.go @@ -29,9 +29,6 @@ type Keeper struct { // The codec codec for binary encoding/decoding. cdc *codec.Codec - // Reserved codespace - codespace sdk.CodespaceType - // Proposal router router types.Router } @@ -45,7 +42,7 @@ type Keeper struct { // CONTRACT: the parameter Subspace must have the param key table already initialized func NewKeeper( cdc *codec.Codec, key sdk.StoreKey, paramSpace types.ParamSubspace, - supplyKeeper types.SupplyKeeper, sk types.StakingKeeper, codespace sdk.CodespaceType, rtr types.Router, + supplyKeeper types.SupplyKeeper, sk types.StakingKeeper, rtr types.Router, ) Keeper { // ensure governance module account is set @@ -64,7 +61,6 @@ func NewKeeper( supplyKeeper: supplyKeeper, sk: sk, cdc: cdc, - codespace: codespace, router: rtr, } } diff --git a/x/gov/keeper/proposal.go b/x/gov/keeper/proposal.go index 2580565d38d4..c5d569314fb2 100644 --- a/x/gov/keeper/proposal.go +++ b/x/gov/keeper/proposal.go @@ -5,13 +5,14 @@ import ( "github.com/cosmos/cosmos-sdk/client" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/gov/types" ) // SubmitProposal create new proposal given a content -func (keeper Keeper) SubmitProposal(ctx sdk.Context, content types.Content) (types.Proposal, sdk.Error) { +func (keeper Keeper) SubmitProposal(ctx sdk.Context, content types.Content) (types.Proposal, error) { if !keeper.router.HasRoute(content.ProposalRoute()) { - return types.Proposal{}, types.ErrNoProposalHandlerExists(keeper.codespace, content) + return types.Proposal{}, sdkerrors.Wrap(types.ErrNoProposalHandlerExists, content.ProposalRoute()) } // Execute the proposal content in a cache-wrapped context to validate the @@ -20,7 +21,7 @@ func (keeper Keeper) SubmitProposal(ctx sdk.Context, content types.Content) (typ cacheCtx, _ := ctx.CacheContext() handler := keeper.router.GetRoute(content.ProposalRoute()) if err := handler(cacheCtx, content); err != nil { - return types.Proposal{}, types.ErrInvalidProposalContent(keeper.codespace, err.Result().Log) + return types.Proposal{}, sdkerrors.Wrap(types.ErrInvalidProposalContent, err.Error()) } proposalID, err := keeper.GetProposalID(ctx) @@ -149,12 +150,13 @@ func (keeper Keeper) GetProposalsFiltered(ctx sdk.Context, params types.QueryPro } // GetProposalID gets the highest proposal ID -func (keeper Keeper) GetProposalID(ctx sdk.Context) (proposalID uint64, err sdk.Error) { +func (keeper Keeper) GetProposalID(ctx sdk.Context) (proposalID uint64, err error) { store := ctx.KVStore(keeper.storeKey) bz := store.Get(types.ProposalIDKey) if bz == nil { - return 0, types.ErrInvalidGenesis(keeper.codespace, "initial proposal ID hasn't been set") + return 0, sdkerrors.Wrap(types.ErrInvalidGenesis, "initial proposal ID hasn't been set") } + proposalID = types.GetProposalIDFromBytes(bz) return proposalID, nil } diff --git a/x/gov/keeper/proposal_test.go b/x/gov/keeper/proposal_test.go index c359f1e5e1c8..67208bef6101 100644 --- a/x/gov/keeper/proposal_test.go +++ b/x/gov/keeper/proposal_test.go @@ -1,6 +1,7 @@ package keeper import ( + "errors" "strings" "testing" "time" @@ -51,12 +52,12 @@ func TestActivateVotingPeriod(t *testing.T) { type validProposal struct{} -func (validProposal) GetTitle() string { return "title" } -func (validProposal) GetDescription() string { return "description" } -func (validProposal) ProposalRoute() string { return types.RouterKey } -func (validProposal) ProposalType() string { return types.ProposalTypeText } -func (validProposal) String() string { return "" } -func (validProposal) ValidateBasic() sdk.Error { return nil } +func (validProposal) GetTitle() string { return "title" } +func (validProposal) GetDescription() string { return "description" } +func (validProposal) ProposalRoute() string { return types.RouterKey } +func (validProposal) ProposalType() string { return types.ProposalTypeText } +func (validProposal) String() string { return "" } +func (validProposal) ValidateBasic() error { return nil } type invalidProposalTitle1 struct{ validProposal } @@ -80,8 +81,8 @@ func (invalidProposalRoute) ProposalRoute() string { return "nonexistingroute" } type invalidProposalValidation struct{ validProposal } -func (invalidProposalValidation) ValidateBasic() sdk.Error { - return sdk.NewError(sdk.CodespaceUndefined, sdk.CodeInternal, "") +func (invalidProposalValidation) ValidateBasic() error { + return errors.New("invalid proposal") } func registerTestCodec(cdc *codec.Codec) { @@ -101,7 +102,7 @@ func TestSubmitProposal(t *testing.T) { testCases := []struct { content types.Content - expectedErr sdk.Error + expectedErr error }{ {validProposal{}, nil}, // Keeper does not check the validity of title and description, no error @@ -110,14 +111,14 @@ func TestSubmitProposal(t *testing.T) { {invalidProposalDesc1{}, nil}, {invalidProposalDesc2{}, nil}, // error only when invalid route - {invalidProposalRoute{}, types.ErrNoProposalHandlerExists(types.DefaultCodespace, invalidProposalRoute{})}, + {invalidProposalRoute{}, types.ErrNoProposalHandlerExists}, // Keeper does not call ValidateBasic, msg.ValidateBasic does {invalidProposalValidation{}, nil}, } - for _, tc := range testCases { + for i, tc := range testCases { _, err := keeper.SubmitProposal(ctx, tc.content) - require.Equal(t, tc.expectedErr, err, "unexpected type of error: %s", err) + require.True(t, errors.Is(tc.expectedErr, err), "tc #%d; got: %v, expected: %v", i, err, tc.expectedErr) } } diff --git a/x/gov/keeper/querier.go b/x/gov/keeper/querier.go index b5efc7619b05..9545e5e29b83 100644 --- a/x/gov/keeper/querier.go +++ b/x/gov/keeper/querier.go @@ -1,19 +1,18 @@ package keeper import ( - "fmt" - abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/gov/types" ) // NewQuerier creates a new gov Querier instance func NewQuerier(keeper Keeper) sdk.Querier { - return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, sdk.Error) { + return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) { switch path[0] { case types.QueryParams: return queryParams(ctx, path[1:], req, keeper) @@ -40,94 +39,100 @@ func NewQuerier(keeper Keeper) sdk.Querier { return queryTally(ctx, path[1:], req, keeper) default: - return nil, sdk.ErrUnknownRequest("unknown gov query endpoint") + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown query path: %s", path[0]) } } } -func queryParams(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) ([]byte, sdk.Error) { +func queryParams(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) ([]byte, error) { switch path[0] { case types.ParamDeposit: bz, err := codec.MarshalJSONIndent(keeper.cdc, keeper.GetDepositParams(ctx)) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return bz, nil + case types.ParamVoting: bz, err := codec.MarshalJSONIndent(keeper.cdc, keeper.GetVotingParams(ctx)) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return bz, nil + case types.ParamTallying: bz, err := codec.MarshalJSONIndent(keeper.cdc, keeper.GetTallyParams(ctx)) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return bz, nil + default: - return nil, sdk.ErrUnknownRequest(fmt.Sprintf("%s is not a valid query request path", req.Path)) + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "%s is not a valid query request path", req.Path) } } // nolint: unparam -func queryProposal(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) ([]byte, sdk.Error) { +func queryProposal(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) ([]byte, error) { var params types.QueryProposalParams err := keeper.cdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } proposal, ok := keeper.GetProposal(ctx, params.ProposalID) if !ok { - return nil, types.ErrUnknownProposal(types.DefaultCodespace, params.ProposalID) + return nil, sdkerrors.Wrapf(types.ErrUnknownProposal, "%d", params.ProposalID) } bz, err := codec.MarshalJSONIndent(keeper.cdc, proposal) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } + return bz, nil } // nolint: unparam -func queryDeposit(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) ([]byte, sdk.Error) { +func queryDeposit(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) ([]byte, error) { var params types.QueryDepositParams err := keeper.cdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } deposit, _ := keeper.GetDeposit(ctx, params.ProposalID, params.Depositor) bz, err := codec.MarshalJSONIndent(keeper.cdc, deposit) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } + return bz, nil } // nolint: unparam -func queryVote(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) ([]byte, sdk.Error) { +func queryVote(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) ([]byte, error) { var params types.QueryVoteParams err := keeper.cdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } vote, _ := keeper.GetVote(ctx, params.ProposalID, params.Voter) bz, err := codec.MarshalJSONIndent(keeper.cdc, vote) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } + return bz, nil } // nolint: unparam -func queryDeposits(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) ([]byte, sdk.Error) { +func queryDeposits(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) ([]byte, error) { var params types.QueryProposalParams err := keeper.cdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } deposits := keeper.GetDeposits(ctx, params.ProposalID) @@ -137,24 +142,25 @@ func queryDeposits(ctx sdk.Context, path []string, req abci.RequestQuery, keeper bz, err := codec.MarshalJSONIndent(keeper.cdc, deposits) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } + return bz, nil } // nolint: unparam -func queryTally(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) ([]byte, sdk.Error) { +func queryTally(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) ([]byte, error) { var params types.QueryProposalParams err := keeper.cdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } proposalID := params.ProposalID proposal, ok := keeper.GetProposal(ctx, proposalID) if !ok { - return nil, types.ErrUnknownProposal(types.DefaultCodespace, proposalID) + return nil, sdkerrors.Wrapf(types.ErrUnknownProposal, "%d", proposalID) } var tallyResult types.TallyResult @@ -162,8 +168,10 @@ func queryTally(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Ke switch { case proposal.Status == types.StatusDepositPeriod: tallyResult = types.EmptyTallyResult() + case proposal.Status == types.StatusPassed || proposal.Status == types.StatusRejected: tallyResult = proposal.FinalTallyResult + default: // proposal is in voting period _, _, tallyResult = keeper.Tally(ctx, proposal) @@ -171,18 +179,18 @@ func queryTally(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Ke bz, err := codec.MarshalJSONIndent(keeper.cdc, tallyResult) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } + return bz, nil } // nolint: unparam -func queryVotes(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) ([]byte, sdk.Error) { +func queryVotes(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) ([]byte, error) { var params types.QueryProposalVotesParams err := keeper.cdc.UnmarshalJSON(req.Data, ¶ms) - if err != nil { - return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } votes := keeper.GetVotes(ctx, params.ProposalID) @@ -199,17 +207,17 @@ func queryVotes(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Ke bz, err := codec.MarshalJSONIndent(keeper.cdc, votes) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } + return bz, nil } -func queryProposals(ctx sdk.Context, _ []string, req abci.RequestQuery, keeper Keeper) ([]byte, sdk.Error) { +func queryProposals(ctx sdk.Context, _ []string, req abci.RequestQuery, keeper Keeper) ([]byte, error) { var params types.QueryProposalsParams - err := keeper.cdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("failed to parse params", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } proposals := keeper.GetProposalsFiltered(ctx, params) @@ -219,7 +227,7 @@ func queryProposals(ctx sdk.Context, _ []string, req abci.RequestQuery, keeper K bz, err := codec.MarshalJSONIndent(keeper.cdc, proposals) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to JSON marshal result: %s", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return bz, nil diff --git a/x/gov/keeper/querier_test.go b/x/gov/keeper/querier_test.go index a5f781da1807..b8cce877608c 100644 --- a/x/gov/keeper/querier_test.go +++ b/x/gov/keeper/querier_test.go @@ -156,7 +156,7 @@ func TestQueries(t *testing.T) { proposal1, err := keeper.SubmitProposal(ctx, tp) require.NoError(t, err) deposit1 := types.NewDeposit(proposal1.ProposalID, TestAddrs[0], oneCoins) - err, _ = keeper.AddDeposit(ctx, deposit1.ProposalID, deposit1.Depositor, deposit1.Amount) + _, err = keeper.AddDeposit(ctx, deposit1.ProposalID, deposit1.Depositor, deposit1.Amount) require.NoError(t, err) proposal1.TotalDeposit = proposal1.TotalDeposit.Add(deposit1.Amount) @@ -164,7 +164,7 @@ func TestQueries(t *testing.T) { proposal2, err := keeper.SubmitProposal(ctx, tp) require.NoError(t, err) deposit2 := types.NewDeposit(proposal2.ProposalID, TestAddrs[0], consCoins) - err, _ = keeper.AddDeposit(ctx, deposit2.ProposalID, deposit2.Depositor, deposit2.Amount) + _, err = keeper.AddDeposit(ctx, deposit2.ProposalID, deposit2.Depositor, deposit2.Amount) require.NoError(t, err) proposal2.TotalDeposit = proposal2.TotalDeposit.Add(deposit2.Amount) @@ -173,14 +173,14 @@ func TestQueries(t *testing.T) { proposal3, err := keeper.SubmitProposal(ctx, tp) require.NoError(t, err) deposit3 := types.NewDeposit(proposal3.ProposalID, TestAddrs[1], oneCoins) - err, _ = keeper.AddDeposit(ctx, deposit3.ProposalID, deposit3.Depositor, deposit3.Amount) + _, err = keeper.AddDeposit(ctx, deposit3.ProposalID, deposit3.Depositor, deposit3.Amount) require.NoError(t, err) proposal3.TotalDeposit = proposal3.TotalDeposit.Add(deposit3.Amount) // TestAddrs[1] deposits on proposals #2 & #3 deposit4 := types.NewDeposit(proposal2.ProposalID, TestAddrs[1], depositParams.MinDeposit) - err, _ = keeper.AddDeposit(ctx, deposit4.ProposalID, deposit4.Depositor, deposit4.Amount) + _, err = keeper.AddDeposit(ctx, deposit4.ProposalID, deposit4.Depositor, deposit4.Amount) require.NoError(t, err) proposal2.TotalDeposit = proposal2.TotalDeposit.Add(deposit4.Amount) @@ -188,7 +188,7 @@ func TestQueries(t *testing.T) { proposal2.VotingEndTime = proposal2.VotingEndTime.Add(types.DefaultPeriod) deposit5 := types.NewDeposit(proposal3.ProposalID, TestAddrs[1], depositParams.MinDeposit) - err, _ = keeper.AddDeposit(ctx, deposit5.ProposalID, deposit5.Depositor, deposit5.Amount) + _, err = keeper.AddDeposit(ctx, deposit5.ProposalID, deposit5.Depositor, deposit5.Amount) require.NoError(t, err) proposal3.TotalDeposit = proposal3.TotalDeposit.Add(deposit5.Amount) diff --git a/x/gov/keeper/test_common.go b/x/gov/keeper/test_common.go index 781964a206d5..777d71a8c887 100644 --- a/x/gov/keeper/test_common.go +++ b/x/gov/keeper/test_common.go @@ -139,19 +139,19 @@ func createTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context blacklistedAddrs[notBondedPool.GetAddress().String()] = true blacklistedAddrs[bondPool.GetAddress().String()] = true - pk := params.NewKeeper(cdc, keyParams, tkeyParams, params.DefaultCodespace) + pk := params.NewKeeper(cdc, keyParams, tkeyParams) accountKeeper := auth.NewAccountKeeper(cdc, keyAcc, pk.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount) - bankKeeper := bank.NewBaseKeeper(accountKeeper, pk.Subspace(bank.DefaultParamspace), bank.DefaultCodespace, blacklistedAddrs) + bankKeeper := bank.NewBaseKeeper(accountKeeper, pk.Subspace(bank.DefaultParamspace), blacklistedAddrs) supplyKeeper := supply.NewKeeper(cdc, keySupply, accountKeeper, bankKeeper, maccPerms) - sk := staking.NewKeeper(cdc, keyStaking, supplyKeeper, pk.Subspace(staking.DefaultParamspace), staking.DefaultCodespace) + sk := staking.NewKeeper(cdc, keyStaking, supplyKeeper, pk.Subspace(staking.DefaultParamspace)) sk.SetParams(ctx, staking.DefaultParams()) rtr := types.NewRouter(). AddRoute(types.RouterKey, types.ProposalHandler) keeper := NewKeeper( - cdc, keyGov, pk.Subspace(types.DefaultParamspace).WithKeyTable(types.ParamKeyTable()), supplyKeeper, sk, types.DefaultCodespace, rtr, + cdc, keyGov, pk.Subspace(types.DefaultParamspace).WithKeyTable(types.ParamKeyTable()), supplyKeeper, sk, rtr, ) keeper.SetProposalID(ctx, types.DefaultStartingProposalID) diff --git a/x/gov/keeper/vote.go b/x/gov/keeper/vote.go index 0204e56be273..309446714287 100644 --- a/x/gov/keeper/vote.go +++ b/x/gov/keeper/vote.go @@ -4,21 +4,22 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/gov/types" ) // AddVote adds a vote on a specific proposal -func (keeper Keeper) AddVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.AccAddress, option types.VoteOption) sdk.Error { +func (keeper Keeper) AddVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.AccAddress, option types.VoteOption) error { proposal, ok := keeper.GetProposal(ctx, proposalID) if !ok { - return types.ErrUnknownProposal(keeper.codespace, proposalID) + return sdkerrors.Wrapf(types.ErrUnknownProposal, "%d", proposalID) } if proposal.Status != types.StatusVotingPeriod { - return types.ErrInactiveProposal(keeper.codespace, proposalID) + return sdkerrors.Wrapf(types.ErrInactiveProposal, "%d", proposalID) } if !types.ValidVoteOption(option) { - return types.ErrInvalidVote(keeper.codespace, option.String()) + return sdkerrors.Wrap(types.ErrInvalidVote, option.String()) } vote := types.NewVote(proposalID, voterAddr, option) diff --git a/x/gov/legacy/v0_36/types.go b/x/gov/legacy/v0_36/types.go index f18cddac1c50..faaaa4e32171 100644 --- a/x/gov/legacy/v0_36/types.go +++ b/x/gov/legacy/v0_36/types.go @@ -16,14 +16,10 @@ const ( ModuleName = "gov" RouterKey = ModuleName - DefaultCodespace sdk.CodespaceType = "gov" - ProposalTypeText string = "Text" MaxDescriptionLength int = 5000 MaxTitleLength int = 140 - - CodeInvalidContent sdk.CodeType = 6 ) var ( @@ -44,7 +40,7 @@ type ( GetDescription() string ProposalRoute() string ProposalType() string - ValidateBasic() sdk.Error + ValidateBasic() error String() string } @@ -94,11 +90,11 @@ func NewTextProposal(title, description string) Content { return TextProposal{title, description} } -func (tp TextProposal) GetTitle() string { return tp.Title } -func (tp TextProposal) GetDescription() string { return tp.Description } -func (tp TextProposal) ProposalRoute() string { return RouterKey } -func (tp TextProposal) ProposalType() string { return ProposalTypeText } -func (tp TextProposal) ValidateBasic() sdk.Error { return ValidateAbstract(DefaultCodespace, tp) } +func (tp TextProposal) GetTitle() string { return tp.Title } +func (tp TextProposal) GetDescription() string { return tp.Description } +func (tp TextProposal) ProposalRoute() string { return RouterKey } +func (tp TextProposal) ProposalType() string { return ProposalTypeText } +func (tp TextProposal) ValidateBasic() error { return ValidateAbstract(tp) } func (tp TextProposal) String() string { return fmt.Sprintf(`Text Proposal: @@ -107,25 +103,25 @@ func (tp TextProposal) String() string { `, tp.Title, tp.Description) } -func ErrInvalidProposalContent(cs sdk.CodespaceType, msg string) sdk.Error { - return sdk.NewError(cs, CodeInvalidContent, fmt.Sprintf("invalid proposal content: %s", msg)) +func ErrInvalidProposalContent(msg string) error { + return fmt.Errorf("invalid proposal content: %s", msg) } -func ValidateAbstract(codespace sdk.CodespaceType, c Content) sdk.Error { +func ValidateAbstract(c Content) error { title := c.GetTitle() if len(strings.TrimSpace(title)) == 0 { - return ErrInvalidProposalContent(codespace, "proposal title cannot be blank") + return ErrInvalidProposalContent("proposal title cannot be blank") } if len(title) > MaxTitleLength { - return ErrInvalidProposalContent(codespace, fmt.Sprintf("proposal title is longer than max length of %d", MaxTitleLength)) + return ErrInvalidProposalContent(fmt.Sprintf("proposal title is longer than max length of %d", MaxTitleLength)) } description := c.GetDescription() if len(description) == 0 { - return ErrInvalidProposalContent(codespace, "proposal description cannot be blank") + return ErrInvalidProposalContent("proposal description cannot be blank") } if len(description) > MaxDescriptionLength { - return ErrInvalidProposalContent(codespace, fmt.Sprintf("proposal description is longer than max length of %d", MaxDescriptionLength)) + return ErrInvalidProposalContent(fmt.Sprintf("proposal description is longer than max length of %d", MaxDescriptionLength)) } return nil diff --git a/x/gov/simulation/operations.go b/x/gov/simulation/operations.go index 0e0bcd06f600..b53a97350146 100644 --- a/x/gov/simulation/operations.go +++ b/x/gov/simulation/operations.go @@ -1,7 +1,6 @@ package simulation import ( - "errors" "math" "math/rand" "time" @@ -148,9 +147,9 @@ func SimulateSubmitProposal( simAccount.PrivKey, ) - res := app.Deliver(tx) - if !res.IsOK() { - return simulation.NoOpMsg(types.ModuleName), nil, errors.New(res.Log) + _, _, err = app.Deliver(tx) + if err != nil { + return simulation.NoOpMsg(types.ModuleName), nil, err } opMsg := simulation.NewOperationMsg(msg, true, "") @@ -231,9 +230,9 @@ func SimulateMsgDeposit(ak types.AccountKeeper, k keeper.Keeper) simulation.Oper simAccount.PrivKey, ) - res := app.Deliver(tx) - if !res.IsOK() { - return simulation.NoOpMsg(types.ModuleName), nil, errors.New(res.Log) + _, _, err = app.Deliver(tx) + if err != nil { + return simulation.NoOpMsg(types.ModuleName), nil, err } return simulation.NewOperationMsg(msg, true, ""), nil, nil @@ -289,9 +288,9 @@ func operationSimulateMsgVote(ak types.AccountKeeper, k keeper.Keeper, simAccount.PrivKey, ) - res := app.Deliver(tx) - if !res.IsOK() { - return simulation.NoOpMsg(types.ModuleName), nil, errors.New(res.Log) + _, _, err = app.Deliver(tx) + if err != nil { + return simulation.NoOpMsg(types.ModuleName), nil, err } return simulation.NewOperationMsg(msg, true, ""), nil, nil diff --git a/x/gov/test_common.go b/x/gov/test_common.go index 36479f7fa0c2..7ecd4bd50f68 100644 --- a/x/gov/test_common.go +++ b/x/gov/test_common.go @@ -4,7 +4,7 @@ package gov import ( "bytes" - "fmt" + "errors" "log" "sort" "testing" @@ -16,6 +16,7 @@ import ( "github.com/tendermint/tendermint/crypto" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" "github.com/cosmos/cosmos-sdk/x/bank" keep "github.com/cosmos/cosmos-sdk/x/gov/keeper" @@ -43,8 +44,11 @@ type testInput struct { privKeys []crypto.PrivKey } -func getMockApp(t *testing.T, numGenAccs int, genState types.GenesisState, genAccs []authexported.Account, - handler func(ctx sdk.Context, c types.Content) sdk.Error) testInput { +func getMockApp( + t *testing.T, numGenAccs int, genState types.GenesisState, genAccs []authexported.Account, + handler func(ctx sdk.Context, c types.Content) error, +) testInput { + mApp := mock.NewApp() staking.RegisterCodec(mApp.Cdc) @@ -69,7 +73,7 @@ func getMockApp(t *testing.T, numGenAccs int, genState types.GenesisState, genAc rtr := types.NewRouter(). AddRoute(types.RouterKey, handler) - bk := bank.NewBaseKeeper(mApp.AccountKeeper, mApp.ParamsKeeper.Subspace(bank.DefaultParamspace), bank.DefaultCodespace, blacklistedAddrs) + bk := bank.NewBaseKeeper(mApp.AccountKeeper, mApp.ParamsKeeper.Subspace(bank.DefaultParamspace), blacklistedAddrs) maccPerms := map[string][]string{ types.ModuleName: {supply.Burner}, @@ -78,11 +82,11 @@ func getMockApp(t *testing.T, numGenAccs int, genState types.GenesisState, genAc } supplyKeeper := supply.NewKeeper(mApp.Cdc, keySupply, mApp.AccountKeeper, bk, maccPerms) sk := staking.NewKeeper( - mApp.Cdc, keyStaking, supplyKeeper, pk.Subspace(staking.DefaultParamspace), staking.DefaultCodespace, + mApp.Cdc, keyStaking, supplyKeeper, pk.Subspace(staking.DefaultParamspace), ) keeper := keep.NewKeeper( - mApp.Cdc, keyGov, pk.Subspace(DefaultParamspace).WithKeyTable(ParamKeyTable()), supplyKeeper, sk, types.DefaultCodespace, rtr, + mApp.Cdc, keyGov, pk.Subspace(DefaultParamspace).WithKeyTable(ParamKeyTable()), supplyKeeper, sk, rtr, ) mApp.Router().AddRoute(types.RouterKey, NewHandler(keeper)) @@ -193,20 +197,19 @@ const contextKeyBadProposal = "contextKeyBadProposal" // badProposalHandler implements a governance proposal handler that is identical // to the actual handler except this fails if the context doesn't contain a value // for the key contextKeyBadProposal or if the value is false. -func badProposalHandler(ctx sdk.Context, c types.Content) sdk.Error { +func badProposalHandler(ctx sdk.Context, c types.Content) error { switch c.ProposalType() { case types.ProposalTypeText: v := ctx.Value(contextKeyBadProposal) if v == nil || !v.(bool) { - return sdk.ErrInternal("proposal failed") + return errors.New("proposal failed") } return nil default: - msg := fmt.Sprintf("unrecognized gov proposal type: %s", c.ProposalType()) - return sdk.ErrUnknownRequest(msg) + return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized gov proposal type: %s", c.ProposalType()) } } @@ -229,7 +232,8 @@ func createValidators(t *testing.T, stakingHandler sdk.Handler, ctx sdk.Context, keep.TestDescription, keep.TestCommissionRates, sdk.OneInt(), ) - res := stakingHandler(ctx, valCreateMsg) - require.True(t, res.IsOK()) + res, err := stakingHandler(ctx, valCreateMsg) + require.NoError(t, err) + require.NotNil(t, res) } } diff --git a/x/gov/types/content.go b/x/gov/types/content.go index 22a7f7a4af62..21d70d5ab1e8 100644 --- a/x/gov/types/content.go +++ b/x/gov/types/content.go @@ -1,10 +1,10 @@ package types import ( - "fmt" "strings" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) // Constants pertaining to a Content object @@ -22,31 +22,31 @@ type Content interface { GetDescription() string ProposalRoute() string ProposalType() string - ValidateBasic() sdk.Error + ValidateBasic() error String() string } // Handler defines a function that handles a proposal after it has passed the // governance process. -type Handler func(ctx sdk.Context, content Content) sdk.Error +type Handler func(ctx sdk.Context, content Content) error // ValidateAbstract validates a proposal's abstract contents returning an error // if invalid. -func ValidateAbstract(codespace sdk.CodespaceType, c Content) sdk.Error { +func ValidateAbstract(c Content) error { title := c.GetTitle() if len(strings.TrimSpace(title)) == 0 { - return ErrInvalidProposalContent(codespace, "proposal title cannot be blank") + return sdkerrors.Wrap(ErrInvalidProposalContent, "proposal title cannot be blank") } if len(title) > MaxTitleLength { - return ErrInvalidProposalContent(codespace, fmt.Sprintf("proposal title is longer than max length of %d", MaxTitleLength)) + return sdkerrors.Wrapf(ErrInvalidProposalContent, "proposal title is longer than max length of %d", MaxTitleLength) } description := c.GetDescription() if len(description) == 0 { - return ErrInvalidProposalContent(codespace, "proposal description cannot be blank") + return sdkerrors.Wrap(ErrInvalidProposalContent, "proposal description cannot be blank") } if len(description) > MaxDescriptionLength { - return ErrInvalidProposalContent(codespace, fmt.Sprintf("proposal description is longer than max length of %d", MaxDescriptionLength)) + return sdkerrors.Wrapf(ErrInvalidProposalContent, "proposal description is longer than max length of %d", MaxDescriptionLength) } return nil diff --git a/x/gov/types/errors.go b/x/gov/types/errors.go index dfc7bf5a4596..2327a6f05b5e 100644 --- a/x/gov/types/errors.go +++ b/x/gov/types/errors.go @@ -1,66 +1,17 @@ package types -// DONTCOVER - import ( - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) -// Codes for governance errors -const ( - DefaultCodespace sdk.CodespaceType = ModuleName - - CodeUnknownProposal sdk.CodeType = 1 - CodeInactiveProposal sdk.CodeType = 2 - CodeAlreadyActiveProposal sdk.CodeType = 3 - CodeAlreadyFinishedProposal sdk.CodeType = 4 - CodeAddressNotStaked sdk.CodeType = 5 - CodeInvalidContent sdk.CodeType = 6 - CodeInvalidProposalType sdk.CodeType = 7 - CodeInvalidVote sdk.CodeType = 8 - CodeInvalidGenesis sdk.CodeType = 9 - CodeInvalidProposalStatus sdk.CodeType = 10 - CodeProposalHandlerNotExists sdk.CodeType = 11 +// x/gov module sentinel errors +var ( + ErrUnknownProposal = sdkerrors.Register(ModuleName, 1, "unknown proposal") + ErrInactiveProposal = sdkerrors.Register(ModuleName, 2, "inactive proposal") + ErrAlreadyActiveProposal = sdkerrors.Register(ModuleName, 3, "proposal already active") + ErrInvalidProposalContent = sdkerrors.Register(ModuleName, 4, "invalid proposal content") + ErrInvalidProposalType = sdkerrors.Register(ModuleName, 5, "invalid proposal type") + ErrInvalidVote = sdkerrors.Register(ModuleName, 6, "invalid vote option") + ErrInvalidGenesis = sdkerrors.Register(ModuleName, 7, "invalid genesis state") + ErrNoProposalHandlerExists = sdkerrors.Register(ModuleName, 8, "no handler exists for proposal type") ) - -// ErrUnknownProposal error for unknown proposals -func ErrUnknownProposal(codespace sdk.CodespaceType, proposalID uint64) sdk.Error { - return sdk.NewError(codespace, CodeUnknownProposal, fmt.Sprintf("unknown proposal with id %d", proposalID)) -} - -// ErrInactiveProposal error for inactive (i.e finalized) proposals -func ErrInactiveProposal(codespace sdk.CodespaceType, proposalID uint64) sdk.Error { - return sdk.NewError(codespace, CodeInactiveProposal, fmt.Sprintf("inactive proposal with id %d", proposalID)) -} - -// ErrAlreadyActiveProposal error for proposals that are already active -func ErrAlreadyActiveProposal(codespace sdk.CodespaceType, proposalID uint64) sdk.Error { - return sdk.NewError(codespace, CodeAlreadyActiveProposal, fmt.Sprintf("proposal %d has been already active", proposalID)) -} - -// ErrInvalidProposalContent error for invalid proposal title or description -func ErrInvalidProposalContent(cs sdk.CodespaceType, msg string) sdk.Error { - return sdk.NewError(cs, CodeInvalidContent, fmt.Sprintf("invalid proposal content: %s", msg)) -} - -// ErrInvalidProposalType error for non registered proposal types -func ErrInvalidProposalType(codespace sdk.CodespaceType, proposalType string) sdk.Error { - return sdk.NewError(codespace, CodeInvalidProposalType, fmt.Sprintf("proposal type '%s' is not valid", proposalType)) -} - -// ErrInvalidVote error for an invalid vote option -func ErrInvalidVote(codespace sdk.CodespaceType, voteOption string) sdk.Error { - return sdk.NewError(codespace, CodeInvalidVote, fmt.Sprintf("'%v' is not a valid voting option", voteOption)) -} - -// ErrInvalidGenesis error for an invalid governance GenesisState -func ErrInvalidGenesis(codespace sdk.CodespaceType, msg string) sdk.Error { - return sdk.NewError(codespace, CodeInvalidVote, msg) -} - -// ErrNoProposalHandlerExists error when proposal handler is not defined -func ErrNoProposalHandlerExists(codespace sdk.CodespaceType, content interface{}) sdk.Error { - return sdk.NewError(codespace, CodeProposalHandlerNotExists, fmt.Sprintf("'%T' does not have a corresponding handler", content)) -} diff --git a/x/gov/types/expected_keepers.go b/x/gov/types/expected_keepers.go index c0fda62d61fe..31e5d1e05cff 100644 --- a/x/gov/types/expected_keepers.go +++ b/x/gov/types/expected_keepers.go @@ -21,21 +21,23 @@ type SupplyKeeper interface { // TODO remove with genesis 2-phases refactor https://github.com/cosmos/cosmos-sdk/issues/2862 SetModuleAccount(sdk.Context, supplyexported.ModuleAccountI) - SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) sdk.Error - SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) sdk.Error - BurnCoins(ctx sdk.Context, name string, amt sdk.Coins) sdk.Error + SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error + SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error + BurnCoins(ctx sdk.Context, name string, amt sdk.Coins) error } // StakingKeeper expected staking keeper (Validator and Delegator sets) (noalias) type StakingKeeper interface { // iterate through bonded validators by operator address, execute func for each validator - IterateBondedValidatorsByPower(sdk.Context, - func(index int64, validator stakingexported.ValidatorI) (stop bool)) + IterateBondedValidatorsByPower( + sdk.Context, func(index int64, validator stakingexported.ValidatorI) (stop bool), + ) TotalBondedTokens(sdk.Context) sdk.Int // total bonded tokens within the validator set - - IterateDelegations(ctx sdk.Context, delegator sdk.AccAddress, - fn func(index int64, delegation stakingexported.DelegationI) (stop bool)) + IterateDelegations( + ctx sdk.Context, delegator sdk.AccAddress, + fn func(index int64, delegation stakingexported.DelegationI) (stop bool), + ) } // AccountKeeper defines the expected account keeper (noalias) diff --git a/x/gov/types/msgs.go b/x/gov/types/msgs.go index b5b85ca167ea..882e0c560c31 100644 --- a/x/gov/types/msgs.go +++ b/x/gov/types/msgs.go @@ -4,6 +4,7 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) // Governance message types and routes @@ -35,21 +36,21 @@ func (msg MsgSubmitProposal) Route() string { return RouterKey } func (msg MsgSubmitProposal) Type() string { return TypeMsgSubmitProposal } // ValidateBasic implements Msg -func (msg MsgSubmitProposal) ValidateBasic() sdk.Error { +func (msg MsgSubmitProposal) ValidateBasic() error { if msg.Content == nil { - return ErrInvalidProposalContent(DefaultCodespace, "missing content") + return sdkerrors.Wrap(ErrInvalidProposalContent, "missing content") } if msg.Proposer.Empty() { - return sdk.ErrInvalidAddress(msg.Proposer.String()) + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Proposer.String()) } if !msg.InitialDeposit.IsValid() { - return sdk.ErrInvalidCoins(msg.InitialDeposit.String()) + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, msg.InitialDeposit.String()) } if msg.InitialDeposit.IsAnyNegative() { - return sdk.ErrInvalidCoins(msg.InitialDeposit.String()) + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, msg.InitialDeposit.String()) } if !IsValidProposalType(msg.Content.ProposalType()) { - return ErrInvalidProposalType(DefaultCodespace, msg.Content.ProposalType()) + return sdkerrors.Wrap(ErrInvalidProposalType, msg.Content.ProposalType()) } return msg.Content.ValidateBasic() @@ -93,15 +94,15 @@ func (msg MsgDeposit) Route() string { return RouterKey } func (msg MsgDeposit) Type() string { return TypeMsgDeposit } // ValidateBasic implements Msg -func (msg MsgDeposit) ValidateBasic() sdk.Error { +func (msg MsgDeposit) ValidateBasic() error { if msg.Depositor.Empty() { - return sdk.ErrInvalidAddress(msg.Depositor.String()) + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Depositor.String()) } if !msg.Amount.IsValid() { - return sdk.ErrInvalidCoins(msg.Amount.String()) + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, msg.Amount.String()) } if msg.Amount.IsAnyNegative() { - return sdk.ErrInvalidCoins(msg.Amount.String()) + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, msg.Amount.String()) } return nil @@ -146,12 +147,12 @@ func (msg MsgVote) Route() string { return RouterKey } func (msg MsgVote) Type() string { return TypeMsgVote } // ValidateBasic implements Msg -func (msg MsgVote) ValidateBasic() sdk.Error { +func (msg MsgVote) ValidateBasic() error { if msg.Voter.Empty() { - return sdk.ErrInvalidAddress(msg.Voter.String()) + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Voter.String()) } if !ValidVoteOption(msg.Option) { - return ErrInvalidVote(DefaultCodespace, msg.Option.String()) + return sdkerrors.Wrap(ErrInvalidVote, msg.Option.String()) } return nil diff --git a/x/gov/types/proposal.go b/x/gov/types/proposal.go index a02f7b54d6b9..945cf786687b 100644 --- a/x/gov/types/proposal.go +++ b/x/gov/types/proposal.go @@ -7,6 +7,7 @@ import ( "time" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) // DefaultStartingProposalID is 1 @@ -232,7 +233,7 @@ func (tp TextProposal) ProposalRoute() string { return RouterKey } func (tp TextProposal) ProposalType() string { return ProposalTypeText } // ValidateBasic validates the content's title and description of the proposal -func (tp TextProposal) ValidateBasic() sdk.Error { return ValidateAbstract(DefaultCodespace, tp) } +func (tp TextProposal) ValidateBasic() error { return ValidateAbstract(tp) } // String implements Stringer interface func (tp TextProposal) String() string { @@ -280,14 +281,13 @@ func IsValidProposalType(ty string) bool { // proposals (ie. TextProposal ). Since these are // merely signaling mechanisms at the moment and do not affect state, it // performs a no-op. -func ProposalHandler(_ sdk.Context, c Content) sdk.Error { +func ProposalHandler(_ sdk.Context, c Content) error { switch c.ProposalType() { case ProposalTypeText: // both proposal types do not change state so this performs a no-op return nil default: - errMsg := fmt.Sprintf("unrecognized gov proposal type: %s", c.ProposalType()) - return sdk.ErrUnknownRequest(errMsg) + return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized gov proposal type: %s", c.ProposalType()) } } diff --git a/x/mint/alias.go b/x/mint/alias.go index 9572d077b458..c6d2330f9a8b 100644 --- a/x/mint/alias.go +++ b/x/mint/alias.go @@ -1,10 +1,7 @@ -// nolint -// autogenerated code using github.com/rigelrozanski/multitool -// aliases generated for the following subdirectories: -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/mint/internal/keeper -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/mint/internal/types package mint +// nolint + import ( "github.com/cosmos/cosmos-sdk/x/mint/internal/keeper" "github.com/cosmos/cosmos-sdk/x/mint/internal/types" diff --git a/x/mint/internal/keeper/keeper.go b/x/mint/internal/keeper/keeper.go index ff4bd029dfda..3be3146fdf68 100644 --- a/x/mint/internal/keeper/keeper.go +++ b/x/mint/internal/keeper/keeper.go @@ -24,7 +24,8 @@ type Keeper struct { // NewKeeper creates a new mint Keeper instance func NewKeeper( cdc *codec.Codec, key sdk.StoreKey, paramSpace params.Subspace, - sk types.StakingKeeper, supplyKeeper types.SupplyKeeper, feeCollectorName string) Keeper { + sk types.StakingKeeper, supplyKeeper types.SupplyKeeper, feeCollectorName string, +) Keeper { // ensure mint module account is set if addr := supplyKeeper.GetModuleAddress(types.ModuleName); addr == nil { @@ -96,16 +97,17 @@ func (k Keeper) BondedRatio(ctx sdk.Context) sdk.Dec { // MintCoins implements an alias call to the underlying supply keeper's // MintCoins to be used in BeginBlocker. -func (k Keeper) MintCoins(ctx sdk.Context, newCoins sdk.Coins) sdk.Error { +func (k Keeper) MintCoins(ctx sdk.Context, newCoins sdk.Coins) error { if newCoins.Empty() { // skip as no coins need to be minted return nil } + return k.supplyKeeper.MintCoins(ctx, types.ModuleName, newCoins) } // AddCollectedFees implements an alias call to the underlying supply keeper's // AddCollectedFees to be used in BeginBlocker. -func (k Keeper) AddCollectedFees(ctx sdk.Context, fees sdk.Coins) sdk.Error { +func (k Keeper) AddCollectedFees(ctx sdk.Context, fees sdk.Coins) error { return k.supplyKeeper.SendCoinsFromModuleToModule(ctx, types.ModuleName, k.feeCollectorName, fees) } diff --git a/x/mint/internal/keeper/querier.go b/x/mint/internal/keeper/querier.go index fe3943f0896a..258d1b111ed2 100644 --- a/x/mint/internal/keeper/querier.go +++ b/x/mint/internal/keeper/querier.go @@ -1,18 +1,17 @@ package keeper import ( - "fmt" - abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/mint/internal/types" ) // NewQuerier returns a minting Querier handler. func NewQuerier(k Keeper) sdk.Querier { - return func(ctx sdk.Context, path []string, _ abci.RequestQuery) ([]byte, sdk.Error) { + return func(ctx sdk.Context, path []string, _ abci.RequestQuery) ([]byte, error) { switch path[0] { case types.QueryParameters: return queryParams(ctx, k) @@ -24,39 +23,39 @@ func NewQuerier(k Keeper) sdk.Querier { return queryAnnualProvisions(ctx, k) default: - return nil, sdk.ErrUnknownRequest(fmt.Sprintf("unknown minting query endpoint: %s", path[0])) + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown query path: %s", path[0]) } } } -func queryParams(ctx sdk.Context, k Keeper) ([]byte, sdk.Error) { +func queryParams(ctx sdk.Context, k Keeper) ([]byte, error) { params := k.GetParams(ctx) res, err := codec.MarshalJSONIndent(k.cdc, params) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to marshal JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil } -func queryInflation(ctx sdk.Context, k Keeper) ([]byte, sdk.Error) { +func queryInflation(ctx sdk.Context, k Keeper) ([]byte, error) { minter := k.GetMinter(ctx) res, err := codec.MarshalJSONIndent(k.cdc, minter.Inflation) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to marshal JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil } -func queryAnnualProvisions(ctx sdk.Context, k Keeper) ([]byte, sdk.Error) { +func queryAnnualProvisions(ctx sdk.Context, k Keeper) ([]byte, error) { minter := k.GetMinter(ctx) res, err := codec.MarshalJSONIndent(k.cdc, minter.AnnualProvisions) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to marshal JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil diff --git a/x/mint/internal/types/expected_keepers.go b/x/mint/internal/types/expected_keepers.go index 564a0136b5c7..ea20619164d3 100644 --- a/x/mint/internal/types/expected_keepers.go +++ b/x/mint/internal/types/expected_keepers.go @@ -18,7 +18,7 @@ type SupplyKeeper interface { // TODO remove with genesis 2-phases refactor https://github.com/cosmos/cosmos-sdk/issues/2862 SetModuleAccount(sdk.Context, exported.ModuleAccountI) - SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) sdk.Error - SendCoinsFromModuleToModule(ctx sdk.Context, senderModule, recipientModule string, amt sdk.Coins) sdk.Error - MintCoins(ctx sdk.Context, name string, amt sdk.Coins) sdk.Error + SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error + SendCoinsFromModuleToModule(ctx sdk.Context, senderModule, recipientModule string, amt sdk.Coins) error + MintCoins(ctx sdk.Context, name string, amt sdk.Coins) error } diff --git a/x/mock/app.go b/x/mock/app.go index 1e59e050507b..d0cee9f592af 100644 --- a/x/mock/app.go +++ b/x/mock/app.go @@ -64,7 +64,7 @@ func NewApp() *App { } // define keepers - app.ParamsKeeper = params.NewKeeper(app.Cdc, app.KeyParams, app.TKeyParams, params.DefaultCodespace) + app.ParamsKeeper = params.NewKeeper(app.Cdc, app.KeyParams, app.TKeyParams) app.AccountKeeper = auth.NewAccountKeeper( app.Cdc, diff --git a/x/mock/app_test.go b/x/mock/app_test.go index db5e29522539..95bed4fda085 100644 --- a/x/mock/app_test.go +++ b/x/mock/app_test.go @@ -7,6 +7,7 @@ import ( abci "github.com/tendermint/tendermint/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/supply/exported" ) @@ -32,18 +33,20 @@ func (tx testMsg) GetMemo() string { return "" } func (tx testMsg) GetSignBytes() []byte { return nil } func (tx testMsg) GetSigners() []sdk.AccAddress { return tx.signers } func (tx testMsg) GetSignatures() []auth.StdSignature { return nil } -func (tx testMsg) ValidateBasic() sdk.Error { +func (tx testMsg) ValidateBasic() error { if tx.positiveNum >= 0 { return nil } - return sdk.ErrTxDecode("positiveNum should be a non-negative integer.") + return sdkerrors.Wrap(sdkerrors.ErrTxDecode, "positiveNum should be a non-negative integer") } // getMockApp returns an initialized mock application. func getMockApp(t *testing.T) *App { mApp := NewApp() - mApp.Router().AddRoute(msgRoute, func(ctx sdk.Context, msg sdk.Msg) (res sdk.Result) { return }) + mApp.Router().AddRoute(msgRoute, func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { + return &sdk.Result{}, nil + }) require.NoError(t, mApp.CompleteSetup()) return mApp @@ -71,15 +74,16 @@ func TestCheckAndDeliverGenTx(t *testing.T) { // Signing a tx with the wrong privKey should result in an auth error header = abci.Header{Height: mApp.LastBlockHeight() + 1} - res := SignCheckDeliver( + _, _, err := SignCheckDeliver( t, mApp.Cdc, mApp.BaseApp, header, []sdk.Msg{msg}, []uint64{accs[1].GetAccountNumber()}, []uint64{accs[1].GetSequence() + 1}, true, false, privKeys[1], ) // Will fail on SetPubKey decorator - require.Equal(t, sdk.CodeInvalidPubKey, res.Code, res.Log) - require.Equal(t, sdk.CodespaceRoot, res.Codespace) + space, code, log := sdkerrors.ABCIInfo(err, false) + require.Equal(t, sdkerrors.ErrInvalidPubKey.ABCICode(), code, log) + require.Equal(t, sdkerrors.ErrInvalidPubKey.Codespace(), space) // Resigning the tx with the correct privKey should result in an OK result header = abci.Header{Height: mApp.LastBlockHeight() + 1} diff --git a/x/mock/test_utils.go b/x/mock/test_utils.go index 2b5978823363..11073e64f413 100644 --- a/x/mock/test_utils.go +++ b/x/mock/test_utils.go @@ -55,17 +55,19 @@ func CheckBalance(t *testing.T, app *App, addr sdk.AccAddress, exp sdk.Coins) { func CheckGenTx( t *testing.T, app *baseapp.BaseApp, msgs []sdk.Msg, accNums []uint64, seq []uint64, expPass bool, priv ...crypto.PrivKey, -) sdk.Result { +) (sdk.GasInfo, *sdk.Result, error) { tx := GenTx(msgs, accNums, seq, priv...) - res := app.Check(tx) + gInfo, res, err := app.Check(tx) if expPass { - require.Equal(t, sdk.CodeOK, res.Code, res.Log) + require.NoError(t, err) + require.NotNil(t, res) } else { - require.NotEqual(t, sdk.CodeOK, res.Code, res.Log) + require.Error(t, err) + require.Nil(t, res) } - return res + return gInfo, res, err } // SignCheckDeliver checks a generated signed transaction and simulates a @@ -75,7 +77,7 @@ func CheckGenTx( func SignCheckDeliver( t *testing.T, cdc *codec.Codec, app *baseapp.BaseApp, header abci.Header, msgs []sdk.Msg, accNums, seq []uint64, expSimPass, expPass bool, priv ...crypto.PrivKey, -) sdk.Result { +) (sdk.GasInfo, *sdk.Result, error) { tx := GenTx(msgs, accNums, seq, priv...) @@ -83,26 +85,31 @@ func SignCheckDeliver( require.Nil(t, err) // Must simulate now as CheckTx doesn't run Msgs anymore - res := app.Simulate(txBytes, tx) + _, res, err := app.Simulate(txBytes, tx) if expSimPass { - require.Equal(t, sdk.CodeOK, res.Code, res.Log) + require.NoError(t, err) + require.NotNil(t, res) } else { - require.NotEqual(t, sdk.CodeOK, res.Code, res.Log) + require.Error(t, err) + require.Nil(t, res) } // Simulate a sending a transaction and committing a block app.BeginBlock(abci.RequestBeginBlock{Header: header}) - res = app.Deliver(tx) + + gInfo, res, err := app.Deliver(tx) if expPass { - require.Equal(t, sdk.CodeOK, res.Code, res.Log) + require.NoError(t, err) + require.NotNil(t, res) } else { - require.NotEqual(t, sdk.CodeOK, res.Code, res.Log) + require.Error(t, err) + require.Nil(t, res) } app.EndBlock(abci.RequestEndBlock{}) app.Commit() - return res + return gInfo, res, err } diff --git a/x/mock/types.go b/x/mock/types.go index 14ec10772006..56912780dac1 100644 --- a/x/mock/types.go +++ b/x/mock/types.go @@ -4,7 +4,7 @@ import ( "github.com/tendermint/tendermint/crypto" sdk "github.com/cosmos/cosmos-sdk/types" - + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/supply" "github.com/cosmos/cosmos-sdk/x/supply/exported" @@ -22,24 +22,23 @@ func NewDummySupplyKeeper(ak auth.AccountKeeper) DummySupplyKeeper { } // SendCoinsFromAccountToModule for the dummy supply keeper -func (sk DummySupplyKeeper) SendCoinsFromAccountToModule(ctx sdk.Context, fromAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) sdk.Error { - +func (sk DummySupplyKeeper) SendCoinsFromAccountToModule(ctx sdk.Context, fromAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error { fromAcc := sk.ak.GetAccount(ctx, fromAddr) moduleAcc := sk.GetModuleAccount(ctx, recipientModule) newFromCoins, hasNeg := fromAcc.GetCoins().SafeSub(amt) if hasNeg { - return sdk.ErrInsufficientCoins(fromAcc.GetCoins().String()) + return sdkerrors.Wrap(sdkerrors.ErrInsufficientFunds, fromAcc.GetCoins().String()) } newToCoins := moduleAcc.GetCoins().Add(amt) if err := fromAcc.SetCoins(newFromCoins); err != nil { - return sdk.ErrInternal(err.Error()) + return err } if err := moduleAcc.SetCoins(newToCoins); err != nil { - return sdk.ErrInternal(err.Error()) + return err } sk.ak.SetAccount(ctx, fromAcc) diff --git a/x/params/alias.go b/x/params/alias.go index ace601c219dc..1198e93cede3 100644 --- a/x/params/alias.go +++ b/x/params/alias.go @@ -1,10 +1,6 @@ package params // nolint -// autogenerated code using github.com/rigelrozanski/multitool -// aliases generated for the following subdirectories: -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/params/subspace -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/params/types import ( "github.com/cosmos/cosmos-sdk/x/params/subspace" @@ -12,15 +8,11 @@ import ( ) const ( - StoreKey = subspace.StoreKey - TStoreKey = subspace.TStoreKey - DefaultCodespace = types.DefaultCodespace - CodeUnknownSubspace = types.CodeUnknownSubspace - CodeSettingParameter = types.CodeSettingParameter - CodeEmptyData = types.CodeEmptyData - ModuleName = types.ModuleName - RouterKey = types.RouterKey - ProposalTypeChange = types.ProposalTypeChange + StoreKey = subspace.StoreKey + TStoreKey = subspace.TStoreKey + ModuleName = types.ModuleName + RouterKey = types.RouterKey + ProposalTypeChange = types.ProposalTypeChange ) var ( diff --git a/x/params/commmon_test.go b/x/params/commmon_test.go index 5ca01ad98d40..ecebf8eb2e60 100644 --- a/x/params/commmon_test.go +++ b/x/params/commmon_test.go @@ -43,7 +43,7 @@ func testComponents() (*codec.Codec, sdk.Context, sdk.StoreKey, sdk.StoreKey, Ke mkey := sdk.NewKVStoreKey("test") tkey := sdk.NewTransientStoreKey("transient_test") ctx := defaultContext(mkey, tkey) - keeper := NewKeeper(cdc, mkey, tkey, DefaultCodespace) + keeper := NewKeeper(cdc, mkey, tkey) return cdc, ctx, mkey, tkey, keeper } diff --git a/x/params/keeper.go b/x/params/keeper.go index 9e91259df656..c3532f32834f 100644 --- a/x/params/keeper.go +++ b/x/params/keeper.go @@ -13,21 +13,19 @@ import ( // Keeper of the global paramstore type Keeper struct { - cdc *codec.Codec - key sdk.StoreKey - tkey sdk.StoreKey - codespace sdk.CodespaceType - spaces map[string]*Subspace + cdc *codec.Codec + key sdk.StoreKey + tkey sdk.StoreKey + spaces map[string]*Subspace } // NewKeeper constructs a params keeper -func NewKeeper(cdc *codec.Codec, key, tkey sdk.StoreKey, codespace sdk.CodespaceType) Keeper { +func NewKeeper(cdc *codec.Codec, key, tkey sdk.StoreKey) Keeper { return Keeper{ - cdc: cdc, - key: key, - tkey: tkey, - codespace: codespace, - spaces: make(map[string]*Subspace), + cdc: cdc, + key: key, + tkey: tkey, + spaces: make(map[string]*Subspace), } } diff --git a/x/params/proposal_handler.go b/x/params/proposal_handler.go index e2e976454275..339cfd7410ce 100644 --- a/x/params/proposal_handler.go +++ b/x/params/proposal_handler.go @@ -4,28 +4,28 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" ) // NewParamChangeProposalHandler creates a new governance Handler for a ParamChangeProposal func NewParamChangeProposalHandler(k Keeper) govtypes.Handler { - return func(ctx sdk.Context, content govtypes.Content) sdk.Error { + return func(ctx sdk.Context, content govtypes.Content) error { switch c := content.(type) { case ParameterChangeProposal: return handleParameterChangeProposal(ctx, k, c) default: - errMsg := fmt.Sprintf("unrecognized param proposal content type: %T", c) - return sdk.ErrUnknownRequest(errMsg) + return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized param proposal content type: %T", c) } } } -func handleParameterChangeProposal(ctx sdk.Context, k Keeper, p ParameterChangeProposal) sdk.Error { +func handleParameterChangeProposal(ctx sdk.Context, k Keeper, p ParameterChangeProposal) error { for _, c := range p.Changes { ss, ok := k.GetSubspace(c.Subspace) if !ok { - return ErrUnknownSubspace(k.codespace, c.Subspace) + return sdkerrors.Wrap(ErrUnknownSubspace, c.Subspace) } k.Logger(ctx).Info( @@ -33,7 +33,7 @@ func handleParameterChangeProposal(ctx sdk.Context, k Keeper, p ParameterChangeP ) if err := ss.Update(ctx, []byte(c.Key), []byte(c.Value)); err != nil { - return ErrSettingParameter(k.codespace, c.Key, c.Value, err.Error()) + return sdkerrors.Wrapf(ErrSettingParameter, "key: %s, value: %s, err: %s", c.Key, c.Value, err.Error()) } } diff --git a/x/params/proposal_handler_test.go b/x/params/proposal_handler_test.go index 841f832160c5..9d83975c1020 100644 --- a/x/params/proposal_handler_test.go +++ b/x/params/proposal_handler_test.go @@ -74,7 +74,7 @@ func newTestInput(t *testing.T) testInput { err := cms.LoadLatestVersion() require.Nil(t, err) - keeper := params.NewKeeper(cdc, keyParams, tKeyParams, params.DefaultCodespace) + keeper := params.NewKeeper(cdc, keyParams, tKeyParams) ctx := sdk.NewContext(cms, abci.Header{}, false, log.NewNopLogger()) return testInput{ctx, cdc, keeper} diff --git a/x/params/types/errors.go b/x/params/types/errors.go index 12726b0322f5..4b218d9444ee 100644 --- a/x/params/types/errors.go +++ b/x/params/types/errors.go @@ -1,46 +1,15 @@ package types import ( - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) -// Param module codespace constants -const ( - DefaultCodespace sdk.CodespaceType = "params" - - CodeUnknownSubspace sdk.CodeType = 1 - CodeSettingParameter sdk.CodeType = 2 - CodeEmptyData sdk.CodeType = 3 +// x/params module sentinel errors +var ( + ErrUnknownSubspace = sdkerrors.Register(ModuleName, 1, "unknown subspace") + ErrSettingParameter = sdkerrors.Register(ModuleName, 2, "failed to set parameter") + ErrEmptyChanges = sdkerrors.Register(ModuleName, 3, "submitted parameter changes are empty") + ErrEmptySubspace = sdkerrors.Register(ModuleName, 4, "parameter subspace is empty") + ErrEmptyKey = sdkerrors.Register(ModuleName, 5, "parameter key is empty") + ErrEmptyValue = sdkerrors.Register(ModuleName, 6, "parameter value is empty") ) - -// ErrUnknownSubspace returns an unknown subspace error. -func ErrUnknownSubspace(codespace sdk.CodespaceType, space string) sdk.Error { - return sdk.NewError(codespace, CodeUnknownSubspace, fmt.Sprintf("unknown subspace %s", space)) -} - -// ErrSettingParameter returns an error for failing to set a parameter. -func ErrSettingParameter(codespace sdk.CodespaceType, key, value, msg string) sdk.Error { - return sdk.NewError(codespace, CodeSettingParameter, fmt.Sprintf("error setting parameter %s on %s: %s", value, key, msg)) -} - -// ErrEmptyChanges returns an error for empty parameter changes. -func ErrEmptyChanges(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeEmptyData, "submitted parameter changes are empty") -} - -// ErrEmptySubspace returns an error for an empty subspace. -func ErrEmptySubspace(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeEmptyData, "parameter subspace is empty") -} - -// ErrEmptyKey returns an error for when an empty key is given. -func ErrEmptyKey(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeEmptyData, "parameter key is empty") -} - -// ErrEmptyValue returns an error for when an empty key is given. -func ErrEmptyValue(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeEmptyData, "parameter value is empty") -} diff --git a/x/params/types/proposal.go b/x/params/types/proposal.go index a4bcefab2df6..78f200d143e9 100644 --- a/x/params/types/proposal.go +++ b/x/params/types/proposal.go @@ -4,7 +4,6 @@ import ( "fmt" "strings" - sdk "github.com/cosmos/cosmos-sdk/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" ) @@ -46,8 +45,8 @@ func (pcp ParameterChangeProposal) ProposalRoute() string { return RouterKey } func (pcp ParameterChangeProposal) ProposalType() string { return ProposalTypeChange } // ValidateBasic validates the parameter change proposal -func (pcp ParameterChangeProposal) ValidateBasic() sdk.Error { - err := govtypes.ValidateAbstract(DefaultCodespace, pcp) +func (pcp ParameterChangeProposal) ValidateBasic() error { + err := govtypes.ValidateAbstract(pcp) if err != nil { return err } @@ -98,20 +97,20 @@ func (pc ParamChange) String() string { // ValidateChanges performs basic validation checks over a set of ParamChange. It // returns an error if any ParamChange is invalid. -func ValidateChanges(changes []ParamChange) sdk.Error { +func ValidateChanges(changes []ParamChange) error { if len(changes) == 0 { - return ErrEmptyChanges(DefaultCodespace) + return ErrEmptyChanges } for _, pc := range changes { if len(pc.Subspace) == 0 { - return ErrEmptySubspace(DefaultCodespace) + return ErrEmptySubspace } if len(pc.Key) == 0 { - return ErrEmptyKey(DefaultCodespace) + return ErrEmptyKey } if len(pc.Value) == 0 { - return ErrEmptyValue(DefaultCodespace) + return ErrEmptyValue } } diff --git a/x/slashing/abci_test.go b/x/slashing/abci_test.go index 84d36c6ee083..bcd1ee7ce8a2 100644 --- a/x/slashing/abci_test.go +++ b/x/slashing/abci_test.go @@ -20,8 +20,10 @@ func TestBeginBlocker(t *testing.T) { addr, pk := slashingkeeper.Addrs[2], slashingkeeper.Pks[2] // bond the validator - got := staking.NewHandler(sk)(ctx, slashingkeeper.NewTestMsgCreateValidator(addr, pk, amt)) - require.True(t, got.IsOK()) + res, err := staking.NewHandler(sk)(ctx, slashingkeeper.NewTestMsgCreateValidator(addr, pk, amt)) + require.NoError(t, err) + require.NotNil(t, res) + staking.EndBlocker(ctx, sk) require.Equal( t, ck.GetCoins(ctx, sdk.AccAddress(addr)), diff --git a/x/slashing/alias.go b/x/slashing/alias.go index 677228182c0d..38d556a6e492 100644 --- a/x/slashing/alias.go +++ b/x/slashing/alias.go @@ -1,23 +1,13 @@ -// nolint -// autogenerated code using github.com/rigelrozanski/multitool -// aliases generated for the following subdirectories: -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/slashing/internal/keeper -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/slashing/internal/types package slashing +// nolint + import ( "github.com/cosmos/cosmos-sdk/x/slashing/internal/keeper" "github.com/cosmos/cosmos-sdk/x/slashing/internal/types" ) const ( - DefaultCodespace = types.DefaultCodespace - CodeInvalidValidator = types.CodeInvalidValidator - CodeValidatorJailed = types.CodeValidatorJailed - CodeValidatorNotJailed = types.CodeValidatorNotJailed - CodeMissingSelfDelegation = types.CodeMissingSelfDelegation - CodeSelfDelegationTooLow = types.CodeSelfDelegationTooLow - CodeMissingSigningInfo = types.CodeMissingSigningInfo ModuleName = types.ModuleName StoreKey = types.StoreKey RouterKey = types.RouterKey @@ -89,7 +79,6 @@ var ( type ( Hooks = keeper.Hooks Keeper = keeper.Keeper - CodeType = types.CodeType GenesisState = types.GenesisState MissedBlock = types.MissedBlock MsgUnjail = types.MsgUnjail diff --git a/x/slashing/app_test.go b/x/slashing/app_test.go index 8704333b75b8..23dd43e590bf 100644 --- a/x/slashing/app_test.go +++ b/x/slashing/app_test.go @@ -3,6 +3,7 @@ package slashing import ( + "errors" "testing" "github.com/stretchr/testify/require" @@ -47,15 +48,15 @@ func getMockApp(t *testing.T) (*mock.App, staking.Keeper, Keeper) { blacklistedAddrs[notBondedPool.GetAddress().String()] = true blacklistedAddrs[bondPool.GetAddress().String()] = true - bankKeeper := bank.NewBaseKeeper(mapp.AccountKeeper, mapp.ParamsKeeper.Subspace(bank.DefaultParamspace), bank.DefaultCodespace, blacklistedAddrs) + bankKeeper := bank.NewBaseKeeper(mapp.AccountKeeper, mapp.ParamsKeeper.Subspace(bank.DefaultParamspace), blacklistedAddrs) maccPerms := map[string][]string{ auth.FeeCollectorName: nil, staking.NotBondedPoolName: {supply.Burner, supply.Staking}, staking.BondedPoolName: {supply.Burner, supply.Staking}, } supplyKeeper := supply.NewKeeper(mapp.Cdc, keySupply, mapp.AccountKeeper, bankKeeper, maccPerms) - stakingKeeper := staking.NewKeeper(mapp.Cdc, keyStaking, supplyKeeper, mapp.ParamsKeeper.Subspace(staking.DefaultParamspace), staking.DefaultCodespace) - keeper := NewKeeper(mapp.Cdc, keySlashing, stakingKeeper, mapp.ParamsKeeper.Subspace(DefaultParamspace), DefaultCodespace) + stakingKeeper := staking.NewKeeper(mapp.Cdc, keyStaking, supplyKeeper, mapp.ParamsKeeper.Subspace(staking.DefaultParamspace)) + keeper := NewKeeper(mapp.Cdc, keySlashing, stakingKeeper, mapp.ParamsKeeper.Subspace(DefaultParamspace)) mapp.Router().AddRoute(staking.RouterKey, staking.NewHandler(stakingKeeper)) mapp.Router().AddRoute(RouterKey, NewHandler(keeper)) @@ -152,7 +153,8 @@ func TestSlashingMsgs(t *testing.T) { // unjail should fail with unknown validator header = abci.Header{Height: mapp.LastBlockHeight() + 1} - res := mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, header, []sdk.Msg{unjailMsg}, []uint64{0}, []uint64{1}, false, false, priv1) - require.EqualValues(t, CodeValidatorNotJailed, res.Code) - require.EqualValues(t, DefaultCodespace, res.Codespace) + _, res, err := mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, header, []sdk.Msg{unjailMsg}, []uint64{0}, []uint64{1}, false, false, priv1) + require.Error(t, err) + require.Nil(t, res) + require.True(t, errors.Is(ErrValidatorNotJailed, err)) } diff --git a/x/slashing/handler.go b/x/slashing/handler.go index 3c338d0bc7b2..fe4ef7cb7c2e 100644 --- a/x/slashing/handler.go +++ b/x/slashing/handler.go @@ -1,15 +1,14 @@ package slashing import ( - "fmt" - sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/slashing/internal/types" ) // NewHandler creates an sdk.Handler for all the slashing type messages func NewHandler(k Keeper) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { ctx = ctx.WithEventManager(sdk.NewEventManager()) switch msg := msg.(type) { @@ -17,19 +16,17 @@ func NewHandler(k Keeper) sdk.Handler { return handleMsgUnjail(ctx, msg, k) default: - errMsg := fmt.Sprintf("unrecognized slashing message type: %T", msg) - return sdk.ErrUnknownRequest(errMsg).Result() + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s message type: %T", ModuleName, msg) } } } // Validators must submit a transaction to unjail itself after // having been jailed (and thus unbonded) for downtime -func handleMsgUnjail(ctx sdk.Context, msg MsgUnjail, k Keeper) sdk.Result { - +func handleMsgUnjail(ctx sdk.Context, msg MsgUnjail, k Keeper) (*sdk.Result, error) { err := k.Unjail(ctx, msg.ValidatorAddr) if err != nil { - return err.Result() + return nil, err } ctx.EventManager().EmitEvent( @@ -40,5 +37,5 @@ func handleMsgUnjail(ctx sdk.Context, msg MsgUnjail, k Keeper) sdk.Result { ), ) - return sdk.Result{Events: ctx.EventManager().Events()} + return &sdk.Result{Events: ctx.EventManager().Events()}, nil } diff --git a/x/slashing/handler_test.go b/x/slashing/handler_test.go index e0d5228326da..a137ff8d0d08 100644 --- a/x/slashing/handler_test.go +++ b/x/slashing/handler_test.go @@ -1,6 +1,7 @@ package slashing import ( + "errors" "strings" "testing" "time" @@ -20,9 +21,12 @@ func TestCannotUnjailUnlessJailed(t *testing.T) { slh := NewHandler(keeper) amt := sdk.TokensFromConsensusPower(100) addr, val := slashingkeeper.Addrs[0], slashingkeeper.Pks[0] + msg := slashingkeeper.NewTestMsgCreateValidator(addr, val, amt) - got := staking.NewHandler(sk)(ctx, msg) - require.True(t, got.IsOK(), "%v", got) + res, err := staking.NewHandler(sk)(ctx, msg) + require.NoError(t, err) + require.NotNil(t, res) + staking.EndBlocker(ctx, sk) require.Equal( @@ -32,10 +36,10 @@ func TestCannotUnjailUnlessJailed(t *testing.T) { require.Equal(t, amt, sk.Validator(ctx, addr).GetBondedTokens()) // assert non-jailed validator can't be unjailed - got = slh(ctx, NewMsgUnjail(addr)) - require.False(t, got.IsOK(), "allowed unjail of non-jailed validator") - require.EqualValues(t, CodeValidatorNotJailed, got.Code) - require.EqualValues(t, DefaultCodespace, got.Codespace) + res, err = slh(ctx, NewMsgUnjail(addr)) + require.Error(t, err) + require.Nil(t, res) + require.True(t, errors.Is(ErrValidatorNotJailed, err)) } func TestCannotUnjailUnlessMeetMinSelfDelegation(t *testing.T) { @@ -46,8 +50,11 @@ func TestCannotUnjailUnlessMeetMinSelfDelegation(t *testing.T) { addr, val, amt := slashingkeeper.Addrs[0], slashingkeeper.Pks[0], sdk.TokensFromConsensusPower(amtInt) msg := slashingkeeper.NewTestMsgCreateValidator(addr, val, amt) msg.MinSelfDelegation = amt - got := staking.NewHandler(sk)(ctx, msg) - require.True(t, got.IsOK()) + + res, err := staking.NewHandler(sk)(ctx, msg) + require.NoError(t, err) + require.NotNil(t, res) + staking.EndBlocker(ctx, sk) require.Equal( @@ -57,15 +64,17 @@ func TestCannotUnjailUnlessMeetMinSelfDelegation(t *testing.T) { unbondAmt := sdk.NewCoin(sk.GetParams(ctx).BondDenom, sdk.OneInt()) undelegateMsg := staking.NewMsgUndelegate(sdk.AccAddress(addr), addr, unbondAmt) - got = staking.NewHandler(sk)(ctx, undelegateMsg) + res, err = staking.NewHandler(sk)(ctx, undelegateMsg) + require.NoError(t, err) + require.NotNil(t, res) require.True(t, sk.Validator(ctx, addr).IsJailed()) // assert non-jailed validator can't be unjailed - got = slh(ctx, NewMsgUnjail(addr)) - require.False(t, got.IsOK(), "allowed unjail of validator with less than MinSelfDelegation") - require.EqualValues(t, CodeValidatorNotJailed, got.Code) - require.EqualValues(t, DefaultCodespace, got.Codespace) + res, err = slh(ctx, NewMsgUnjail(addr)) + require.Error(t, err) + require.Nil(t, res) + require.True(t, errors.Is(ErrSelfDelegationTooLowToUnjail, err)) } func TestJailedValidatorDelegations(t *testing.T) { @@ -80,8 +89,9 @@ func TestJailedValidatorDelegations(t *testing.T) { valAddr, consAddr := slashingkeeper.Addrs[1], sdk.ConsAddress(slashingkeeper.Addrs[0]) msgCreateVal := slashingkeeper.NewTestMsgCreateValidator(valAddr, valPubKey, bondAmount) - got := staking.NewHandler(stakingKeeper)(ctx, msgCreateVal) - require.True(t, got.IsOK(), "expected create validator msg to be ok, got: %v", got) + res, err := staking.NewHandler(stakingKeeper)(ctx, msgCreateVal) + require.NoError(t, err) + require.NotNil(t, res) // end block staking.EndBlocker(ctx, stakingKeeper) @@ -93,17 +103,19 @@ func TestJailedValidatorDelegations(t *testing.T) { // delegate tokens to the validator delAddr := sdk.AccAddress(slashingkeeper.Addrs[2]) msgDelegate := slashingkeeper.NewTestMsgDelegate(delAddr, valAddr, bondAmount) - got = staking.NewHandler(stakingKeeper)(ctx, msgDelegate) - require.True(t, got.IsOK(), "expected delegation to be ok, got %v", got) + res, err = staking.NewHandler(stakingKeeper)(ctx, msgDelegate) + require.NoError(t, err) + require.NotNil(t, res) unbondAmt := sdk.NewCoin(stakingKeeper.GetParams(ctx).BondDenom, bondAmount) // unbond validator total self-delegations (which should jail the validator) msgUndelegate := staking.NewMsgUndelegate(sdk.AccAddress(valAddr), valAddr, unbondAmt) - got = staking.NewHandler(stakingKeeper)(ctx, msgUndelegate) - require.True(t, got.IsOK(), "expected begin unbonding validator msg to be ok, got: %v", got) + res, err = staking.NewHandler(stakingKeeper)(ctx, msgUndelegate) + require.NoError(t, err) + require.NotNil(t, res) - err := stakingKeeper.CompleteUnbonding(ctx, sdk.AccAddress(valAddr), valAddr) + err = stakingKeeper.CompleteUnbonding(ctx, sdk.AccAddress(valAddr), valAddr) require.Nil(t, err, "expected complete unbonding validator to be ok, got: %v", err) // verify validator still exists and is jailed @@ -112,26 +124,30 @@ func TestJailedValidatorDelegations(t *testing.T) { require.True(t, validator.IsJailed()) // verify the validator cannot unjail itself - got = NewHandler(slashingKeeper)(ctx, NewMsgUnjail(valAddr)) - require.False(t, got.IsOK(), "expected jailed validator to not be able to unjail, got: %v", got) + res, err = NewHandler(slashingKeeper)(ctx, NewMsgUnjail(valAddr)) + require.Error(t, err) + require.Nil(t, res) // self-delegate to validator msgSelfDelegate := slashingkeeper.NewTestMsgDelegate(sdk.AccAddress(valAddr), valAddr, bondAmount) - got = staking.NewHandler(stakingKeeper)(ctx, msgSelfDelegate) - require.True(t, got.IsOK(), "expected delegation to not be ok, got %v", got) + res, err = staking.NewHandler(stakingKeeper)(ctx, msgSelfDelegate) + require.NoError(t, err) + require.NotNil(t, res) // verify the validator can now unjail itself - got = NewHandler(slashingKeeper)(ctx, NewMsgUnjail(valAddr)) - require.True(t, got.IsOK(), "expected jailed validator to be able to unjail, got: %v", got) + res, err = NewHandler(slashingKeeper)(ctx, NewMsgUnjail(valAddr)) + require.NoError(t, err) + require.NotNil(t, res) } func TestInvalidMsg(t *testing.T) { k := Keeper{} h := NewHandler(k) - res := h(sdk.NewContext(nil, abci.Header{}, false, nil), sdk.NewTestMsg()) - require.False(t, res.IsOK()) - require.True(t, strings.Contains(res.Log, "unrecognized slashing message type")) + res, err := h(sdk.NewContext(nil, abci.Header{}, false, nil), sdk.NewTestMsg()) + require.Error(t, err) + require.Nil(t, res) + require.True(t, strings.Contains(err.Error(), "unrecognized slashing message type")) } // Test a validator through uptime, downtime, revocation, @@ -145,8 +161,11 @@ func TestHandleAbsentValidator(t *testing.T) { addr, val := slashingkeeper.Addrs[0], slashingkeeper.Pks[0] sh := staking.NewHandler(sk) slh := NewHandler(keeper) - got := sh(ctx, slashingkeeper.NewTestMsgCreateValidator(addr, val, amt)) - require.True(t, got.IsOK()) + + res, err := sh(ctx, slashingkeeper.NewTestMsgCreateValidator(addr, val, amt)) + require.NoError(t, err) + require.NotNil(t, res) + staking.EndBlocker(ctx, sk) require.Equal( @@ -228,13 +247,15 @@ func TestHandleAbsentValidator(t *testing.T) { require.Equal(t, amt.Int64()-slashAmt, validator.GetTokens().Int64()) // unrevocation should fail prior to jail expiration - got = slh(ctx, types.NewMsgUnjail(addr)) - require.False(t, got.IsOK()) + res, err = slh(ctx, types.NewMsgUnjail(addr)) + require.Error(t, err) + require.Nil(t, res) // unrevocation should succeed after jail expiration ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(1, 0).Add(keeper.DowntimeJailDuration(ctx))}) - got = slh(ctx, types.NewMsgUnjail(addr)) - require.True(t, got.IsOK()) + res, err = slh(ctx, types.NewMsgUnjail(addr)) + require.NoError(t, err) + require.NotNil(t, res) // end block staking.EndBlocker(ctx, sk) diff --git a/x/slashing/internal/keeper/keeper.go b/x/slashing/internal/keeper/keeper.go index b7a3706369f9..e725519314d1 100644 --- a/x/slashing/internal/keeper/keeper.go +++ b/x/slashing/internal/keeper/keeper.go @@ -17,19 +17,16 @@ type Keeper struct { cdc *codec.Codec sk types.StakingKeeper paramspace types.ParamSubspace - codespace sdk.CodespaceType } // NewKeeper creates a slashing keeper -func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, sk types.StakingKeeper, paramspace types.ParamSubspace, codespace sdk.CodespaceType) Keeper { - keeper := Keeper{ +func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, sk types.StakingKeeper, paramspace types.ParamSubspace) Keeper { + return Keeper{ storeKey: key, cdc: cdc, sk: sk, paramspace: paramspace.WithKeyTable(types.ParamKeyTable()), - codespace: codespace, } - return keeper } // Logger returns a module-specific logger. diff --git a/x/slashing/internal/keeper/keeper_test.go b/x/slashing/internal/keeper/keeper_test.go index 54b77848a043..52eb6b59b77a 100644 --- a/x/slashing/internal/keeper/keeper_test.go +++ b/x/slashing/internal/keeper/keeper_test.go @@ -25,8 +25,10 @@ func TestHandleNewValidator(t *testing.T) { ctx = ctx.WithBlockHeight(keeper.SignedBlocksWindow(ctx) + 1) // Validator created - got := sh(ctx, NewTestMsgCreateValidator(addr, val, amt)) - require.True(t, got.IsOK()) + res, err := sh(ctx, NewTestMsgCreateValidator(addr, val, amt)) + require.NoError(t, err) + require.NotNil(t, res) + staking.EndBlocker(ctx, sk) require.Equal( @@ -65,8 +67,10 @@ func TestHandleAlreadyJailed(t *testing.T) { amt := sdk.TokensFromConsensusPower(power) addr, val := Addrs[0], Pks[0] sh := staking.NewHandler(sk) - got := sh(ctx, NewTestMsgCreateValidator(addr, val, amt)) - require.True(t, got.IsOK()) + res, err := sh(ctx, NewTestMsgCreateValidator(addr, val, amt)) + require.NoError(t, err) + require.NotNil(t, res) + staking.EndBlocker(ctx, sk) // 1000 first blocks OK @@ -119,8 +123,10 @@ func TestValidatorDippingInAndOut(t *testing.T) { addr, val := Addrs[0], Pks[0] consAddr := sdk.ConsAddress(addr) sh := staking.NewHandler(sk) - got := sh(ctx, NewTestMsgCreateValidator(addr, val, amt)) - require.True(t, got.IsOK()) + res, err := sh(ctx, NewTestMsgCreateValidator(addr, val, amt)) + require.NoError(t, err) + require.NotNil(t, res) + staking.EndBlocker(ctx, sk) // 100 first blocks OK @@ -132,8 +138,10 @@ func TestValidatorDippingInAndOut(t *testing.T) { // kick first validator out of validator set newAmt := sdk.TokensFromConsensusPower(101) - got = sh(ctx, NewTestMsgCreateValidator(Addrs[1], Pks[1], newAmt)) - require.True(t, got.IsOK()) + res, err = sh(ctx, NewTestMsgCreateValidator(Addrs[1], Pks[1], newAmt)) + require.NoError(t, err) + require.NotNil(t, res) + validatorUpdates := staking.EndBlocker(ctx, sk) require.Equal(t, 2, len(validatorUpdates)) validator, _ := sk.GetValidator(ctx, addr) @@ -145,8 +153,10 @@ func TestValidatorDippingInAndOut(t *testing.T) { // validator added back in delTokens := sdk.TokensFromConsensusPower(50) - got = sh(ctx, NewTestMsgDelegate(sdk.AccAddress(Addrs[2]), Addrs[0], delTokens)) - require.True(t, got.IsOK()) + res, err = sh(ctx, NewTestMsgDelegate(sdk.AccAddress(Addrs[2]), Addrs[0], delTokens)) + require.NoError(t, err) + require.NotNil(t, res) + validatorUpdates = staking.EndBlocker(ctx, sk) require.Equal(t, 2, len(validatorUpdates)) validator, _ = sk.GetValidator(ctx, addr) diff --git a/x/slashing/internal/keeper/querier.go b/x/slashing/internal/keeper/querier.go index 4633d8ba50e9..11b365e1ee1b 100644 --- a/x/slashing/internal/keeper/querier.go +++ b/x/slashing/internal/keeper/querier.go @@ -1,70 +1,72 @@ package keeper import ( - "fmt" - abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/slashing/internal/types" ) // NewQuerier creates a new querier for slashing clients. func NewQuerier(k Keeper) sdk.Querier { - return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, sdk.Error) { + return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) { switch path[0] { case types.QueryParameters: return queryParams(ctx, k) + case types.QuerySigningInfo: return querySigningInfo(ctx, req, k) + case types.QuerySigningInfos: return querySigningInfos(ctx, req, k) + default: - return nil, sdk.ErrUnknownRequest("unknown staking query endpoint") + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown %s query endpoint: %s", types.ModuleName, path[0]) } } } -func queryParams(ctx sdk.Context, k Keeper) ([]byte, sdk.Error) { +func queryParams(ctx sdk.Context, k Keeper) ([]byte, error) { params := k.GetParams(ctx) res, err := codec.MarshalJSONIndent(types.ModuleCdc, params) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to marshal JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil } -func querySigningInfo(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func querySigningInfo(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QuerySigningInfoParams err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } signingInfo, found := k.GetValidatorSigningInfo(ctx, params.ConsAddress) if !found { - return nil, types.ErrNoSigningInfoFound(types.DefaultCodespace, params.ConsAddress) + return nil, sdkerrors.Wrap(types.ErrNoSigningInfoFound, params.ConsAddress.String()) } res, err := codec.MarshalJSONIndent(types.ModuleCdc, signingInfo) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to JSON marshal result: %s", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil } -func querySigningInfos(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func querySigningInfos(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QuerySigningInfosParams err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } var signingInfos []types.ValidatorSigningInfo @@ -83,7 +85,7 @@ func querySigningInfos(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte res, err := codec.MarshalJSONIndent(types.ModuleCdc, signingInfos) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to JSON marshal result: %s", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil diff --git a/x/slashing/internal/keeper/test_common.go b/x/slashing/internal/keeper/test_common.go index 721967ca88c4..eb8870c1d199 100644 --- a/x/slashing/internal/keeper/test_common.go +++ b/x/slashing/internal/keeper/test_common.go @@ -88,10 +88,10 @@ func CreateTestInput(t *testing.T, defaults types.Params) (sdk.Context, bank.Kee blacklistedAddrs[notBondedPool.GetAddress().String()] = true blacklistedAddrs[bondPool.GetAddress().String()] = true - paramsKeeper := params.NewKeeper(cdc, keyParams, tkeyParams, params.DefaultCodespace) + paramsKeeper := params.NewKeeper(cdc, keyParams, tkeyParams) accountKeeper := auth.NewAccountKeeper(cdc, keyAcc, paramsKeeper.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount) - bk := bank.NewBaseKeeper(accountKeeper, paramsKeeper.Subspace(bank.DefaultParamspace), bank.DefaultCodespace, blacklistedAddrs) + bk := bank.NewBaseKeeper(accountKeeper, paramsKeeper.Subspace(bank.DefaultParamspace), blacklistedAddrs) maccPerms := map[string][]string{ auth.FeeCollectorName: nil, staking.NotBondedPoolName: {supply.Burner, supply.Staking}, @@ -102,7 +102,7 @@ func CreateTestInput(t *testing.T, defaults types.Params) (sdk.Context, bank.Kee totalSupply := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, InitTokens.MulRaw(int64(len(Addrs))))) supplyKeeper.SetSupply(ctx, supply.NewSupply(totalSupply)) - sk := staking.NewKeeper(cdc, keyStaking, supplyKeeper, paramsKeeper.Subspace(staking.DefaultParamspace), staking.DefaultCodespace) + sk := staking.NewKeeper(cdc, keyStaking, supplyKeeper, paramsKeeper.Subspace(staking.DefaultParamspace)) genesis := staking.DefaultGenesisState() // set module accounts @@ -117,7 +117,7 @@ func CreateTestInput(t *testing.T, defaults types.Params) (sdk.Context, bank.Kee } require.Nil(t, err) paramstore := paramsKeeper.Subspace(types.DefaultParamspace) - keeper := NewKeeper(cdc, keySlashing, &sk, paramstore, types.DefaultCodespace) + keeper := NewKeeper(cdc, keySlashing, &sk, paramstore) keeper.SetParams(ctx, defaults) sk.SetHooks(keeper.Hooks()) diff --git a/x/slashing/internal/keeper/unjail.go b/x/slashing/internal/keeper/unjail.go index 3fdab405eb91..51fda4855382 100644 --- a/x/slashing/internal/keeper/unjail.go +++ b/x/slashing/internal/keeper/unjail.go @@ -7,42 +7,42 @@ import ( // Unjail calls the staking Unjail function to unjail a validator if the // jailed period has concluded -func (k Keeper) Unjail(ctx sdk.Context, validatorAddr sdk.ValAddress) sdk.Error { +func (k Keeper) Unjail(ctx sdk.Context, validatorAddr sdk.ValAddress) error { validator := k.sk.Validator(ctx, validatorAddr) if validator == nil { - return types.ErrNoValidatorForAddress(k.codespace) + return types.ErrNoValidatorForAddress } // cannot be unjailed if no self-delegation exists selfDel := k.sk.Delegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) if selfDel == nil { - return types.ErrMissingSelfDelegation(k.codespace) + return types.ErrMissingSelfDelegation } if validator.TokensFromShares(selfDel.GetShares()).TruncateInt().LT(validator.GetMinSelfDelegation()) { - return types.ErrSelfDelegationTooLowToUnjail(k.codespace) + return types.ErrSelfDelegationTooLowToUnjail } // cannot be unjailed if not jailed if !validator.IsJailed() { - return types.ErrValidatorNotJailed(k.codespace) + return types.ErrValidatorNotJailed } consAddr := sdk.ConsAddress(validator.GetConsPubKey().Address()) info, found := k.GetValidatorSigningInfo(ctx, consAddr) if !found { - return types.ErrNoValidatorForAddress(k.codespace) + return types.ErrNoValidatorForAddress } // cannot be unjailed if tombstoned if info.Tombstoned { - return types.ErrValidatorJailed(k.codespace) + return types.ErrValidatorJailed } // cannot be unjailed until out of jail if ctx.BlockHeader().Time.Before(info.JailedUntil) { - return types.ErrValidatorJailed(k.codespace) + return types.ErrValidatorJailed } k.sk.Unjail(ctx, consAddr) diff --git a/x/slashing/internal/types/errors.go b/x/slashing/internal/types/errors.go index b00e6e4f94ab..290ed36cad66 100644 --- a/x/slashing/internal/types/errors.go +++ b/x/slashing/internal/types/errors.go @@ -1,53 +1,16 @@ -//nolint package types import ( - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) -// DONTCOVER - -// Local code type -type CodeType = sdk.CodeType - -const ( - // Default slashing codespace - DefaultCodespace sdk.CodespaceType = ModuleName - - CodeInvalidValidator CodeType = 101 - CodeValidatorJailed CodeType = 102 - CodeValidatorNotJailed CodeType = 103 - CodeMissingSelfDelegation CodeType = 104 - CodeSelfDelegationTooLow CodeType = 105 - CodeMissingSigningInfo CodeType = 106 +// x/slashing module sentinel errors +var ( + ErrNoValidatorForAddress = sdkerrors.Register(ModuleName, 1, "address is not associated with any known validator") + ErrBadValidatorAddr = sdkerrors.Register(ModuleName, 2, "validator does not exist for that address") + ErrValidatorJailed = sdkerrors.Register(ModuleName, 3, "validator still jailed; cannot be unjailed") + ErrValidatorNotJailed = sdkerrors.Register(ModuleName, 4, "validator not jailed; cannot be unjailed") + ErrMissingSelfDelegation = sdkerrors.Register(ModuleName, 5, "validator has no self-delegation; cannot be unjailed") + ErrSelfDelegationTooLowToUnjail = sdkerrors.Register(ModuleName, 6, "validator's self delegation less than minimum; cannot be unjailed") + ErrNoSigningInfoFound = sdkerrors.Register(ModuleName, 7, "no validator signing info found") ) - -func ErrNoValidatorForAddress(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidValidator, "that address is not associated with any known validator") -} - -func ErrBadValidatorAddr(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidValidator, "validator does not exist for that address") -} - -func ErrValidatorJailed(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeValidatorJailed, "validator still jailed, cannot yet be unjailed") -} - -func ErrValidatorNotJailed(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeValidatorNotJailed, "validator not jailed, cannot be unjailed") -} - -func ErrMissingSelfDelegation(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeMissingSelfDelegation, "validator has no self-delegation; cannot be unjailed") -} - -func ErrSelfDelegationTooLowToUnjail(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeValidatorNotJailed, "validator's self delegation less than MinSelfDelegation, cannot be unjailed") -} - -func ErrNoSigningInfoFound(codespace sdk.CodespaceType, consAddr sdk.ConsAddress) sdk.Error { - return sdk.NewError(codespace, CodeMissingSigningInfo, fmt.Sprintf("no signing info found for address: %s", consAddr)) -} diff --git a/x/slashing/internal/types/msg.go b/x/slashing/internal/types/msg.go index 3513d3b6c12b..b2ccdce173ba 100644 --- a/x/slashing/internal/types/msg.go +++ b/x/slashing/internal/types/msg.go @@ -33,9 +33,9 @@ func (msg MsgUnjail) GetSignBytes() []byte { } // ValidateBasic validity check for the AnteHandler -func (msg MsgUnjail) ValidateBasic() sdk.Error { +func (msg MsgUnjail) ValidateBasic() error { if msg.ValidatorAddr.Empty() { - return ErrBadValidatorAddr(DefaultCodespace) + return ErrBadValidatorAddr } return nil } diff --git a/x/slashing/simulation/operations.go b/x/slashing/simulation/operations.go index 3e2a3bc78bad..f5e263b778dc 100644 --- a/x/slashing/simulation/operations.go +++ b/x/slashing/simulation/operations.go @@ -93,7 +93,7 @@ func SimulateMsgUnjail(ak types.AccountKeeper, k keeper.Keeper, sk stakingkeeper simAccount.PrivKey, ) - res := app.Deliver(tx) + _, res, err := app.Deliver(tx) // result should fail if: // - validator cannot be unjailed due to tombstone @@ -102,7 +102,7 @@ func SimulateMsgUnjail(ak types.AccountKeeper, k keeper.Keeper, sk stakingkeeper if info.Tombstoned || ctx.BlockHeader().Time.Before(info.JailedUntil) || validator.TokensFromShares(selfDel.GetShares()).TruncateInt().LT(validator.GetMinSelfDelegation()) { - if res.IsOK() { + if res != nil && err == nil { if info.Tombstoned { return simulation.NewOperationMsg(msg, true, ""), nil, errors.New("validator should not have been unjailed if validator tombstoned") } @@ -117,7 +117,7 @@ func SimulateMsgUnjail(ak types.AccountKeeper, k keeper.Keeper, sk stakingkeeper return simulation.NewOperationMsg(msg, false, ""), nil, nil } - if !res.IsOK() { + if err != nil { return simulation.NoOpMsg(types.ModuleName), nil, errors.New(res.Log) } diff --git a/x/staking/alias.go b/x/staking/alias.go index 887b9b7bf690..51c7eecc7087 100644 --- a/x/staking/alias.go +++ b/x/staking/alias.go @@ -1,11 +1,7 @@ -// nolint -// autogenerated code using github.com/rigelrozanski/multitool -// aliases generated for the following subdirectories: -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/staking/keeper -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/staking/types -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/staking/exported package staking +// nolint + import ( "github.com/cosmos/cosmos-sdk/x/staking/exported" "github.com/cosmos/cosmos-sdk/x/staking/keeper" @@ -14,16 +10,6 @@ import ( const ( DefaultParamspace = keeper.DefaultParamspace - DefaultCodespace = types.DefaultCodespace - CodeInvalidValidator = types.CodeInvalidValidator - CodeInvalidDelegation = types.CodeInvalidDelegation - CodeInvalidInput = types.CodeInvalidInput - CodeValidatorJailed = types.CodeValidatorJailed - CodeInvalidHistoricalInfo = types.CodeInvalidHistoricalInfo - CodeInvalidAddress = types.CodeInvalidAddress - CodeUnauthorized = types.CodeUnauthorized - CodeInternal = types.CodeInternal - CodeUnknownRequest = types.CodeUnknownRequest ModuleName = types.ModuleName StoreKey = types.StoreKey TStoreKey = types.TStoreKey @@ -92,7 +78,7 @@ var ( MustMarshalHistoricalInfo = types.MustMarshalHistoricalInfo MustUnmarshalHistoricalInfo = types.MustUnmarshalHistoricalInfo UnmarshalHistoricalInfo = types.UnmarshalHistoricalInfo - ErrNilValidatorAddr = types.ErrNilValidatorAddr + ErrEmptyValidatorAddr = types.ErrEmptyValidatorAddr ErrBadValidatorAddr = types.ErrBadValidatorAddr ErrNoValidatorFound = types.ErrNoValidatorFound ErrValidatorOwnerExists = types.ErrValidatorOwnerExists @@ -100,7 +86,6 @@ var ( ErrValidatorPubKeyTypeNotSupported = types.ErrValidatorPubKeyTypeNotSupported ErrValidatorJailed = types.ErrValidatorJailed ErrBadRemoveValidator = types.ErrBadRemoveValidator - ErrDescriptionLength = types.ErrDescriptionLength ErrCommissionNegative = types.ErrCommissionNegative ErrCommissionHuge = types.ErrCommissionHuge ErrCommissionGTMaxRate = types.ErrCommissionGTMaxRate @@ -111,7 +96,7 @@ var ( ErrSelfDelegationBelowMinimum = types.ErrSelfDelegationBelowMinimum ErrMinSelfDelegationInvalid = types.ErrMinSelfDelegationInvalid ErrMinSelfDelegationDecreased = types.ErrMinSelfDelegationDecreased - ErrNilDelegatorAddr = types.ErrNilDelegatorAddr + ErrEmptyDelegatorAddr = types.ErrEmptyDelegatorAddr ErrBadDenom = types.ErrBadDenom ErrBadDelegationAddr = types.ErrBadDelegationAddr ErrBadDelegationAmount = types.ErrBadDelegationAmount @@ -129,14 +114,13 @@ var ( ErrBadRedelegationAddr = types.ErrBadRedelegationAddr ErrNoRedelegation = types.ErrNoRedelegation ErrSelfRedelegation = types.ErrSelfRedelegation - ErrVerySmallRedelegation = types.ErrVerySmallRedelegation + ErrTinyRedelegationAmount = types.ErrTinyRedelegationAmount ErrBadRedelegationDst = types.ErrBadRedelegationDst ErrTransitiveRedelegation = types.ErrTransitiveRedelegation ErrMaxRedelegationEntries = types.ErrMaxRedelegationEntries ErrDelegatorShareExRateInvalid = types.ErrDelegatorShareExRateInvalid ErrBothShareMsgsGiven = types.ErrBothShareMsgsGiven ErrNeitherShareMsgsGiven = types.ErrNeitherShareMsgsGiven - ErrMissingSignature = types.ErrMissingSignature ErrInvalidHistoricalInfo = types.ErrInvalidHistoricalInfo ErrNoHistoricalInfo = types.ErrNoHistoricalInfo NewGenesisState = types.NewGenesisState @@ -233,7 +217,6 @@ type ( RedelegationResponse = types.RedelegationResponse RedelegationEntryResponse = types.RedelegationEntryResponse RedelegationResponses = types.RedelegationResponses - CodeType = types.CodeType GenesisState = types.GenesisState LastValidatorPower = types.LastValidatorPower MultiStakingHooks = types.MultiStakingHooks diff --git a/x/staking/app_test.go b/x/staking/app_test.go index 0c2615d7a3ea..a56923113380 100644 --- a/x/staking/app_test.go +++ b/x/staking/app_test.go @@ -35,14 +35,14 @@ func getMockApp(t *testing.T) (*mock.App, Keeper) { blacklistedAddrs[notBondedPool.GetAddress().String()] = true blacklistedAddrs[bondPool.GetAddress().String()] = true - bankKeeper := bank.NewBaseKeeper(mApp.AccountKeeper, mApp.ParamsKeeper.Subspace(bank.DefaultParamspace), bank.DefaultCodespace, blacklistedAddrs) + bankKeeper := bank.NewBaseKeeper(mApp.AccountKeeper, mApp.ParamsKeeper.Subspace(bank.DefaultParamspace), blacklistedAddrs) maccPerms := map[string][]string{ auth.FeeCollectorName: nil, types.NotBondedPoolName: {supply.Burner, supply.Staking}, types.BondedPoolName: {supply.Burner, supply.Staking}, } supplyKeeper := supply.NewKeeper(mApp.Cdc, keySupply, mApp.AccountKeeper, bankKeeper, maccPerms) - keeper := NewKeeper(mApp.Cdc, keyStaking, supplyKeeper, mApp.ParamsKeeper.Subspace(DefaultParamspace), DefaultCodespace) + keeper := NewKeeper(mApp.Cdc, keyStaking, supplyKeeper, mApp.ParamsKeeper.Subspace(DefaultParamspace)) mApp.Router().AddRoute(RouterKey, NewHandler(keeper)) mApp.SetEndBlocker(getEndBlocker(keeper)) diff --git a/x/staking/client/cli/tx.go b/x/staking/client/cli/tx.go index 34ed0abce3c7..374d061e070a 100644 --- a/x/staking/client/cli/tx.go +++ b/x/staking/client/cli/tx.go @@ -119,8 +119,9 @@ func GetCmdEditValidator(cdc *codec.Codec) *cobra.Command { if minSelfDelegationString != "" { msb, ok := sdk.NewIntFromString(minSelfDelegationString) if !ok { - return fmt.Errorf(types.ErrMinSelfDelegationInvalid(types.DefaultCodespace).Error()) + return types.ErrMinSelfDelegationInvalid } + newMinSelfDelegation = &msb } @@ -378,7 +379,7 @@ func BuildCreateValidatorMsg(cliCtx context.CLIContext, txBldr auth.TxBuilder) ( msbStr := viper.GetString(FlagMinSelfDelegation) minSelfDelegation, ok := sdk.NewIntFromString(msbStr) if !ok { - return txBldr, nil, fmt.Errorf(types.ErrMinSelfDelegationInvalid(types.DefaultCodespace).Error()) + return txBldr, nil, types.ErrMinSelfDelegationInvalid } msg := types.NewMsgCreateValidator( diff --git a/x/staking/exported/exported.go b/x/staking/exported/exported.go index eae33c8ee105..7c8a257cd342 100644 --- a/x/staking/exported/exported.go +++ b/x/staking/exported/exported.go @@ -15,24 +15,24 @@ type DelegationI interface { // ValidatorI expected validator functions type ValidatorI interface { - IsJailed() bool // whether the validator is jailed - GetMoniker() string // moniker of the validator - GetStatus() sdk.BondStatus // status of the validator - IsBonded() bool // check if has a bonded status - IsUnbonded() bool // check if has status unbonded - IsUnbonding() bool // check if has status unbonding - GetOperator() sdk.ValAddress // operator address to receive/return validators coins - GetConsPubKey() crypto.PubKey // validation consensus pubkey - GetConsAddr() sdk.ConsAddress // validation consensus address - GetTokens() sdk.Int // validation tokens - GetBondedTokens() sdk.Int // validator bonded tokens - GetConsensusPower() int64 // validation power in tendermint - GetCommission() sdk.Dec // validator commission rate - GetMinSelfDelegation() sdk.Int // validator minimum self delegation - GetDelegatorShares() sdk.Dec // total outstanding delegator shares - TokensFromShares(sdk.Dec) sdk.Dec // token worth of provided delegator shares - TokensFromSharesTruncated(sdk.Dec) sdk.Dec // token worth of provided delegator shares, truncated - TokensFromSharesRoundUp(sdk.Dec) sdk.Dec // token worth of provided delegator shares, rounded up - SharesFromTokens(amt sdk.Int) (sdk.Dec, sdk.Error) // shares worth of delegator's bond - SharesFromTokensTruncated(amt sdk.Int) (sdk.Dec, sdk.Error) // truncated shares worth of delegator's bond + IsJailed() bool // whether the validator is jailed + GetMoniker() string // moniker of the validator + GetStatus() sdk.BondStatus // status of the validator + IsBonded() bool // check if has a bonded status + IsUnbonded() bool // check if has status unbonded + IsUnbonding() bool // check if has status unbonding + GetOperator() sdk.ValAddress // operator address to receive/return validators coins + GetConsPubKey() crypto.PubKey // validation consensus pubkey + GetConsAddr() sdk.ConsAddress // validation consensus address + GetTokens() sdk.Int // validation tokens + GetBondedTokens() sdk.Int // validator bonded tokens + GetConsensusPower() int64 // validation power in tendermint + GetCommission() sdk.Dec // validator commission rate + GetMinSelfDelegation() sdk.Int // validator minimum self delegation + GetDelegatorShares() sdk.Dec // total outstanding delegator shares + TokensFromShares(sdk.Dec) sdk.Dec // token worth of provided delegator shares + TokensFromSharesTruncated(sdk.Dec) sdk.Dec // token worth of provided delegator shares, truncated + TokensFromSharesRoundUp(sdk.Dec) sdk.Dec // token worth of provided delegator shares, rounded up + SharesFromTokens(amt sdk.Int) (sdk.Dec, error) // shares worth of delegator's bond + SharesFromTokensTruncated(amt sdk.Int) (sdk.Dec, error) // truncated shares worth of delegator's bond } diff --git a/x/staking/handler.go b/x/staking/handler.go index 376da255ea1c..da5933930382 100644 --- a/x/staking/handler.go +++ b/x/staking/handler.go @@ -1,19 +1,19 @@ package staking import ( - "fmt" "time" "github.com/tendermint/tendermint/libs/common" tmtypes "github.com/tendermint/tendermint/types" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/staking/keeper" "github.com/cosmos/cosmos-sdk/x/staking/types" ) func NewHandler(k keeper.Keeper) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { ctx = ctx.WithEventManager(sdk.NewEventManager()) switch msg := msg.(type) { @@ -33,8 +33,7 @@ func NewHandler(k keeper.Keeper) sdk.Handler { return handleMsgUndelegate(ctx, msg, k) default: - errMsg := fmt.Sprintf("unrecognized staking message type: %T", msg) - return sdk.ErrUnknownRequest(errMsg).Result() + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s message type: %T", ModuleName, msg) } } } @@ -42,30 +41,31 @@ func NewHandler(k keeper.Keeper) sdk.Handler { // These functions assume everything has been authenticated, // now we just perform action and save -func handleMsgCreateValidator(ctx sdk.Context, msg types.MsgCreateValidator, k keeper.Keeper) sdk.Result { +func handleMsgCreateValidator(ctx sdk.Context, msg types.MsgCreateValidator, k keeper.Keeper) (*sdk.Result, error) { // check to see if the pubkey or sender has been registered before if _, found := k.GetValidator(ctx, msg.ValidatorAddress); found { - return ErrValidatorOwnerExists(k.Codespace()).Result() + return nil, ErrValidatorOwnerExists } if _, found := k.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(msg.PubKey)); found { - return ErrValidatorPubKeyExists(k.Codespace()).Result() + return nil, ErrValidatorPubKeyExists } if msg.Value.Denom != k.BondDenom(ctx) { - return ErrBadDenom(k.Codespace()).Result() + return nil, ErrBadDenom } if _, err := msg.Description.EnsureLength(); err != nil { - return err.Result() + return nil, err } if ctx.ConsensusParams() != nil { tmPubKey := tmtypes.TM2PB.PubKey(msg.PubKey) if !common.StringInSlice(tmPubKey.Type, ctx.ConsensusParams().Validator.PubKeyTypes) { - return ErrValidatorPubKeyTypeNotSupported(k.Codespace(), - tmPubKey.Type, - ctx.ConsensusParams().Validator.PubKeyTypes).Result() + return nil, sdkerrors.Wrapf( + ErrValidatorPubKeyTypeNotSupported, + "got: %s, valid: %s", tmPubKey.Type, ctx.ConsensusParams().Validator.PubKeyTypes, + ) } } @@ -76,7 +76,7 @@ func handleMsgCreateValidator(ctx sdk.Context, msg types.MsgCreateValidator, k k ) validator, err := validator.SetInitialCommission(commission) if err != nil { - return err.Result() + return nil, err } validator.MinSelfDelegation = msg.MinSelfDelegation @@ -93,7 +93,7 @@ func handleMsgCreateValidator(ctx sdk.Context, msg types.MsgCreateValidator, k k // NOTE source will always be from a wallet which are unbonded _, err = k.Delegate(ctx, msg.DelegatorAddress, msg.Value.Amount, sdk.Unbonded, validator, true) if err != nil { - return err.Result() + return nil, err } ctx.EventManager().EmitEvents(sdk.Events{ @@ -109,20 +109,20 @@ func handleMsgCreateValidator(ctx sdk.Context, msg types.MsgCreateValidator, k k ), }) - return sdk.Result{Events: ctx.EventManager().Events()} + return &sdk.Result{Events: ctx.EventManager().Events()}, nil } -func handleMsgEditValidator(ctx sdk.Context, msg types.MsgEditValidator, k keeper.Keeper) sdk.Result { +func handleMsgEditValidator(ctx sdk.Context, msg types.MsgEditValidator, k keeper.Keeper) (*sdk.Result, error) { // validator must already be registered validator, found := k.GetValidator(ctx, msg.ValidatorAddress) if !found { - return ErrNoValidatorFound(k.Codespace()).Result() + return nil, ErrNoValidatorFound } // replace all editable fields (clients should autofill existing values) description, err := validator.Description.UpdateDescription(msg.Description) if err != nil { - return err.Result() + return nil, err } validator.Description = description @@ -130,7 +130,7 @@ func handleMsgEditValidator(ctx sdk.Context, msg types.MsgEditValidator, k keepe if msg.CommissionRate != nil { commission, err := k.UpdateValidatorCommission(ctx, validator, *msg.CommissionRate) if err != nil { - return err.Result() + return nil, err } // call the before-modification hook since we're about to update the commission @@ -141,11 +141,12 @@ func handleMsgEditValidator(ctx sdk.Context, msg types.MsgEditValidator, k keepe if msg.MinSelfDelegation != nil { if !msg.MinSelfDelegation.GT(validator.MinSelfDelegation) { - return ErrMinSelfDelegationDecreased(k.Codespace()).Result() + return nil, ErrMinSelfDelegationDecreased } if msg.MinSelfDelegation.GT(validator.Tokens) { - return ErrSelfDelegationBelowMinimum(k.Codespace()).Result() + return nil, ErrSelfDelegationBelowMinimum } + validator.MinSelfDelegation = (*msg.MinSelfDelegation) } @@ -164,23 +165,23 @@ func handleMsgEditValidator(ctx sdk.Context, msg types.MsgEditValidator, k keepe ), }) - return sdk.Result{Events: ctx.EventManager().Events()} + return &sdk.Result{Events: ctx.EventManager().Events()}, nil } -func handleMsgDelegate(ctx sdk.Context, msg types.MsgDelegate, k keeper.Keeper) sdk.Result { +func handleMsgDelegate(ctx sdk.Context, msg types.MsgDelegate, k keeper.Keeper) (*sdk.Result, error) { validator, found := k.GetValidator(ctx, msg.ValidatorAddress) if !found { - return ErrNoValidatorFound(k.Codespace()).Result() + return nil, ErrNoValidatorFound } if msg.Amount.Denom != k.BondDenom(ctx) { - return ErrBadDenom(k.Codespace()).Result() + return nil, ErrBadDenom } // NOTE: source funds are always unbonded _, err := k.Delegate(ctx, msg.DelegatorAddress, msg.Amount.Amount, sdk.Unbonded, validator, true) if err != nil { - return err.Result() + return nil, err } ctx.EventManager().EmitEvents(sdk.Events{ @@ -196,24 +197,24 @@ func handleMsgDelegate(ctx sdk.Context, msg types.MsgDelegate, k keeper.Keeper) ), }) - return sdk.Result{Events: ctx.EventManager().Events()} + return &sdk.Result{Events: ctx.EventManager().Events()}, nil } -func handleMsgUndelegate(ctx sdk.Context, msg types.MsgUndelegate, k keeper.Keeper) sdk.Result { +func handleMsgUndelegate(ctx sdk.Context, msg types.MsgUndelegate, k keeper.Keeper) (*sdk.Result, error) { shares, err := k.ValidateUnbondAmount( ctx, msg.DelegatorAddress, msg.ValidatorAddress, msg.Amount.Amount, ) if err != nil { - return err.Result() + return nil, err } if msg.Amount.Denom != k.BondDenom(ctx) { - return ErrBadDenom(k.Codespace()).Result() + return nil, ErrBadDenom } completionTime, err := k.Undelegate(ctx, msg.DelegatorAddress, msg.ValidatorAddress, shares) if err != nil { - return err.Result() + return nil, err } completionTimeBz := types.ModuleCdc.MustMarshalBinaryLengthPrefixed(completionTime) @@ -231,26 +232,26 @@ func handleMsgUndelegate(ctx sdk.Context, msg types.MsgUndelegate, k keeper.Keep ), }) - return sdk.Result{Data: completionTimeBz, Events: ctx.EventManager().Events()} + return &sdk.Result{Data: completionTimeBz, Events: ctx.EventManager().Events()}, nil } -func handleMsgBeginRedelegate(ctx sdk.Context, msg types.MsgBeginRedelegate, k keeper.Keeper) sdk.Result { +func handleMsgBeginRedelegate(ctx sdk.Context, msg types.MsgBeginRedelegate, k keeper.Keeper) (*sdk.Result, error) { shares, err := k.ValidateUnbondAmount( ctx, msg.DelegatorAddress, msg.ValidatorSrcAddress, msg.Amount.Amount, ) if err != nil { - return err.Result() + return nil, err } if msg.Amount.Denom != k.BondDenom(ctx) { - return ErrBadDenom(k.Codespace()).Result() + return nil, ErrBadDenom } completionTime, err := k.BeginRedelegation( ctx, msg.DelegatorAddress, msg.ValidatorSrcAddress, msg.ValidatorDstAddress, shares, ) if err != nil { - return err.Result() + return nil, err } completionTimeBz := types.ModuleCdc.MustMarshalBinaryLengthPrefixed(completionTime) @@ -269,5 +270,5 @@ func handleMsgBeginRedelegate(ctx sdk.Context, msg types.MsgBeginRedelegate, k k ), }) - return sdk.Result{Data: completionTimeBz, Events: ctx.EventManager().Events()} + return &sdk.Result{Data: completionTimeBz, Events: ctx.EventManager().Events()}, nil } diff --git a/x/staking/handler_test.go b/x/staking/handler_test.go index 0e999ba9b43b..92147eabb097 100644 --- a/x/staking/handler_test.go +++ b/x/staking/handler_test.go @@ -26,8 +26,9 @@ func TestValidatorByPowerIndex(t *testing.T) { // create validator msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], initBond) - got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected create-validator to be ok, got %v", got) + res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) // must end-block updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) @@ -47,8 +48,9 @@ func TestValidatorByPowerIndex(t *testing.T) { // create a second validator keep it bonded msgCreateValidator = NewTestMsgCreateValidator(validatorAddr3, keep.PKs[2], initBond) - got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected create-validator to be ok, got %v", got) + res, err = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) // must end-block updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx) @@ -84,11 +86,12 @@ func TestValidatorByPowerIndex(t *testing.T) { unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, totalBond) msgUndelegate := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) - got = handleMsgUndelegate(ctx, msgUndelegate, keeper) - require.True(t, got.IsOK(), "expected msg to be ok, got %v", got) + res, err = handleMsgUndelegate(ctx, msgUndelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) var finishTime time.Time - types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime) + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, &finishTime) ctx = ctx.WithBlockTime(finishTime) EndBlocker(ctx, keeper) @@ -108,8 +111,9 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) { valTokens := sdk.TokensFromConsensusPower(10) msgCreateValidator1 := NewTestMsgCreateValidator(addr1, pk1, valTokens) - got := handleMsgCreateValidator(ctx, msgCreateValidator1, keeper) - require.True(t, got.IsOK(), "%v", got) + res, err := handleMsgCreateValidator(ctx, msgCreateValidator1, keeper) + require.NoError(t, err) + require.NotNil(t, res) keeper.ApplyAndReturnValidatorSetUpdates(ctx) @@ -124,18 +128,21 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) { // two validators can't have the same operator address msgCreateValidator2 := NewTestMsgCreateValidator(addr1, pk2, valTokens) - got = handleMsgCreateValidator(ctx, msgCreateValidator2, keeper) - require.False(t, got.IsOK(), "%v", got) + res, err = handleMsgCreateValidator(ctx, msgCreateValidator2, keeper) + require.Error(t, err) + require.Nil(t, res) // two validators can't have the same pubkey msgCreateValidator3 := NewTestMsgCreateValidator(addr2, pk1, valTokens) - got = handleMsgCreateValidator(ctx, msgCreateValidator3, keeper) - require.False(t, got.IsOK(), "%v", got) + res, err = handleMsgCreateValidator(ctx, msgCreateValidator3, keeper) + require.Error(t, err) + require.Nil(t, res) // must have different pubkey and operator msgCreateValidator4 := NewTestMsgCreateValidator(addr2, pk2, valTokens) - got = handleMsgCreateValidator(ctx, msgCreateValidator4, keeper) - require.True(t, got.IsOK(), "%v", got) + res, err = handleMsgCreateValidator(ctx, msgCreateValidator4, keeper) + require.NoError(t, err) + require.NotNil(t, res) // must end-block updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) @@ -160,15 +167,17 @@ func TestInvalidPubKeyTypeMsgCreateValidator(t *testing.T) { // invalid pukKey type should not be allowed msgCreateValidator := NewTestMsgCreateValidator(addr, invalidPk, sdk.NewInt(10)) - got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.False(t, got.IsOK(), "%v", got) + res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.Error(t, err) + require.Nil(t, res) ctx = ctx.WithConsensusParams(&abci.ConsensusParams{ Validator: &abci.ValidatorParams{PubKeyTypes: []string{tmtypes.ABCIPubKeyTypeSecp256k1}}, }) - got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "%v", got) + res, err = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) } func TestLegacyValidatorDelegations(t *testing.T) { @@ -181,8 +190,9 @@ func TestLegacyValidatorDelegations(t *testing.T) { // create validator msgCreateVal := NewTestMsgCreateValidator(valAddr, valConsPubKey, bondAmount) - got := handleMsgCreateValidator(ctx, msgCreateVal, keeper) - require.True(t, got.IsOK(), "expected create validator msg to be ok, got %v", got) + res, err := handleMsgCreateValidator(ctx, msgCreateVal, keeper) + require.NoError(t, err) + require.NotNil(t, res) // must end-block updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) @@ -197,8 +207,9 @@ func TestLegacyValidatorDelegations(t *testing.T) { // delegate tokens to the validator msgDelegate := NewTestMsgDelegate(delAddr, valAddr, bondAmount) - got = handleMsgDelegate(ctx, msgDelegate, keeper) - require.True(t, got.IsOK(), "expected delegation to be ok, got %v", got) + res, err = handleMsgDelegate(ctx, msgDelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) // verify validator bonded shares validator, found = keeper.GetValidator(ctx, valAddr) @@ -210,11 +221,12 @@ func TestLegacyValidatorDelegations(t *testing.T) { unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, bondAmount) msgUndelegate := NewMsgUndelegate(sdk.AccAddress(valAddr), valAddr, unbondAmt) - got = handleMsgUndelegate(ctx, msgUndelegate, keeper) - require.True(t, got.IsOK(), "expected begin unbonding validator msg to be ok, got %v", got) + res, err = handleMsgUndelegate(ctx, msgUndelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) var finishTime time.Time - types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime) + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, &finishTime) ctx = ctx.WithBlockTime(finishTime) EndBlocker(ctx, keeper) @@ -232,8 +244,9 @@ func TestLegacyValidatorDelegations(t *testing.T) { // verify the validator can still self-delegate msgSelfDelegate := NewTestMsgDelegate(sdk.AccAddress(valAddr), valAddr, bondAmount) - got = handleMsgDelegate(ctx, msgSelfDelegate, keeper) - require.True(t, got.IsOK(), "expected delegation to be ok, got %v", got) + res, err = handleMsgDelegate(ctx, msgSelfDelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) // verify validator bonded shares validator, found = keeper.GetValidator(ctx, valAddr) @@ -246,8 +259,9 @@ func TestLegacyValidatorDelegations(t *testing.T) { // verify the validator can now accept delegations msgDelegate = NewTestMsgDelegate(delAddr, valAddr, bondAmount) - got = handleMsgDelegate(ctx, msgDelegate, keeper) - require.True(t, got.IsOK(), "expected delegation to be ok, got %v", got) + res, err = handleMsgDelegate(ctx, msgDelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) // verify validator bonded shares validator, found = keeper.GetValidator(ctx, valAddr) @@ -273,8 +287,9 @@ func TestIncrementsMsgDelegate(t *testing.T) { // first create validator msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], bondAmount) - got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected create validator msg to be ok, got %v", got) + res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) // apply TM updates keeper.ApplyAndReturnValidatorSetUpdates(ctx) @@ -301,8 +316,9 @@ func TestIncrementsMsgDelegate(t *testing.T) { for i := int64(0); i < 5; i++ { ctx = ctx.WithBlockHeight(i) - got := handleMsgDelegate(ctx, msgDelegate, keeper) - require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got) + res, err := handleMsgDelegate(ctx, msgDelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) //Check that the accounts and the bond account have the appropriate values validator, found := keeper.GetValidator(ctx, validatorAddr) @@ -340,8 +356,9 @@ func TestEditValidatorDecreaseMinSelfDelegation(t *testing.T) { // create validator msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], initBond) msgCreateValidator.MinSelfDelegation = sdk.NewInt(2) - got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected create-validator to be ok, got %v", got) + res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) // must end-block updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) @@ -357,8 +374,9 @@ func TestEditValidatorDecreaseMinSelfDelegation(t *testing.T) { newMinSelfDelegation := sdk.OneInt() msgEditValidator := NewMsgEditValidator(validatorAddr, Description{}, nil, &newMinSelfDelegation) - got = handleMsgEditValidator(ctx, msgEditValidator, keeper) - require.False(t, got.IsOK(), "should not be able to decrease minSelfDelegation") + res, err = handleMsgEditValidator(ctx, msgEditValidator, keeper) + require.Error(t, err) + require.Nil(t, res) } func TestEditValidatorIncreaseMinSelfDelegationBeyondCurrentBond(t *testing.T) { @@ -371,8 +389,9 @@ func TestEditValidatorIncreaseMinSelfDelegationBeyondCurrentBond(t *testing.T) { // create validator msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], initBond) msgCreateValidator.MinSelfDelegation = sdk.NewInt(2) - got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected create-validator to be ok, got %v", got) + res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) // must end-block updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) @@ -388,8 +407,9 @@ func TestEditValidatorIncreaseMinSelfDelegationBeyondCurrentBond(t *testing.T) { newMinSelfDelegation := initBond.Add(sdk.OneInt()) msgEditValidator := NewMsgEditValidator(validatorAddr, Description{}, nil, &newMinSelfDelegation) - got = handleMsgEditValidator(ctx, msgEditValidator, keeper) - require.False(t, got.IsOK(), "should not be able to increase minSelfDelegation above current self delegation") + res, err = handleMsgEditValidator(ctx, msgEditValidator, keeper) + require.Error(t, err) + require.Nil(t, res) } func TestIncrementsMsgUnbond(t *testing.T) { @@ -404,15 +424,17 @@ func TestIncrementsMsgUnbond(t *testing.T) { validatorAddr, delegatorAddr := sdk.ValAddress(keep.Addrs[0]), keep.Addrs[1] msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], initBond) - got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected create-validator to be ok, got %v", got) + res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) // initial balance amt1 := accMapper.GetAccount(ctx, delegatorAddr).GetCoins().AmountOf(denom) msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, initBond) - got = handleMsgDelegate(ctx, msgDelegate, keeper) - require.True(t, got.IsOK(), "expected delegation to be ok, got %v", got) + res, err = handleMsgDelegate(ctx, msgDelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) // balance should have been subtracted after delegation amt2 := accMapper.GetAccount(ctx, delegatorAddr).GetCoins().AmountOf(denom) @@ -431,12 +453,15 @@ func TestIncrementsMsgUnbond(t *testing.T) { unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) msgUndelegate := NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) numUnbonds := int64(5) + for i := int64(0); i < numUnbonds; i++ { + res, err := handleMsgUndelegate(ctx, msgUndelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) - got := handleMsgUndelegate(ctx, msgUndelegate, keeper) - require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got) var finishTime time.Time - types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime) + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, &finishTime) + ctx = ctx.WithBlockTime(finishTime) EndBlocker(ctx, keeper) @@ -474,11 +499,12 @@ func TestIncrementsMsgUnbond(t *testing.T) { initBond, } - for i, c := range errorCases { + for _, c := range errorCases { unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, c) msgUndelegate := NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) - got = handleMsgUndelegate(ctx, msgUndelegate, keeper) - require.False(t, got.IsOK(), "expected unbond msg to fail, index: %v", i) + res, err = handleMsgUndelegate(ctx, msgUndelegate, keeper) + require.Error(t, err) + require.Nil(t, res) } leftBonded := initBond.Sub(unbondAmt.Amount.Mul(sdk.NewInt(numUnbonds))) @@ -486,9 +512,9 @@ func TestIncrementsMsgUnbond(t *testing.T) { // should be able to unbond remaining unbondAmt = sdk.NewCoin(sdk.DefaultBondDenom, leftBonded) msgUndelegate = NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) - got = handleMsgUndelegate(ctx, msgUndelegate, keeper) - require.True(t, got.IsOK(), - "got: %v\nmsgUnbond: %v\nshares: %s\nleftBonded: %s\n", got.Log, msgUndelegate, unbondAmt, leftBonded) + res, err = handleMsgUndelegate(ctx, msgUndelegate, keeper) + require.NoError(t, err, "msgUnbond: %v\nshares: %s\nleftBonded: %s\n", msgUndelegate, unbondAmt, leftBonded) + require.NotNil(t, res, "msgUnbond: %v\nshares: %s\nleftBonded: %s\n", msgUndelegate, unbondAmt, leftBonded) } func TestMultipleMsgCreateValidator(t *testing.T) { @@ -516,8 +542,9 @@ func TestMultipleMsgCreateValidator(t *testing.T) { valTokens := sdk.TokensFromConsensusPower(10) msgCreateValidatorOnBehalfOf := NewTestMsgCreateValidator(validatorAddr, keep.PKs[i], valTokens) - got := handleMsgCreateValidator(ctx, msgCreateValidatorOnBehalfOf, keeper) - require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got) + res, err := handleMsgCreateValidator(ctx, msgCreateValidatorOnBehalfOf, keeper) + require.NoError(t, err) + require.NotNil(t, res) // verify that the account is bonded validators := keeper.GetValidators(ctx, 100) @@ -541,11 +568,12 @@ func TestMultipleMsgCreateValidator(t *testing.T) { unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(10)) msgUndelegate := NewMsgUndelegate(delegatorAddrs[i], validatorAddr, unbondAmt) // remove delegation - got := handleMsgUndelegate(ctx, msgUndelegate, keeper) - require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got) + res, err := handleMsgUndelegate(ctx, msgUndelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) var finishTime time.Time - types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime) + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, &finishTime) // adds validator into unbonding queue EndBlocker(ctx, keeper) @@ -572,14 +600,16 @@ func TestMultipleMsgDelegate(t *testing.T) { // first make a validator msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], sdk.NewInt(10)) - got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected msg to be ok, got %v", got) + res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) // delegate multiple parties - for i, delegatorAddr := range delegatorAddrs { + for _, delegatorAddr := range delegatorAddrs { msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, sdk.NewInt(10)) - got := handleMsgDelegate(ctx, msgDelegate, keeper) - require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got) + res, err := handleMsgDelegate(ctx, msgDelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) // check that the account is bonded bond, found := keeper.GetDelegation(ctx, delegatorAddr, validatorAddr) @@ -588,15 +618,16 @@ func TestMultipleMsgDelegate(t *testing.T) { } // unbond them all - for i, delegatorAddr := range delegatorAddrs { + for _, delegatorAddr := range delegatorAddrs { unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) msgUndelegate := NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) - got := handleMsgUndelegate(ctx, msgUndelegate, keeper) - require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got) + res, err := handleMsgUndelegate(ctx, msgUndelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) var finishTime time.Time - types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime) + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, &finishTime) ctx = ctx.WithBlockTime(finishTime) EndBlocker(ctx, keeper) @@ -613,22 +644,25 @@ func TestJailValidator(t *testing.T) { // create the validator msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], sdk.NewInt(10)) - got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) // bond a delegator msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, sdk.NewInt(10)) - got = handleMsgDelegate(ctx, msgDelegate, keeper) - require.True(t, got.IsOK(), "expected ok, got %v", got) + res, err = handleMsgDelegate(ctx, msgDelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) // unbond the validators bond portion unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) msgUndelegateValidator := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) - got = handleMsgUndelegate(ctx, msgUndelegateValidator, keeper) - require.True(t, got.IsOK(), "expected no error: %v", got) + res, err = handleMsgUndelegate(ctx, msgUndelegateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) var finishTime time.Time - types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime) + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, &finishTime) ctx = ctx.WithBlockTime(finishTime) EndBlocker(ctx, keeper) @@ -640,16 +674,18 @@ func TestJailValidator(t *testing.T) { // test that the delegator can still withdraw their bonds msgUndelegateDelegator := NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) - got = handleMsgUndelegate(ctx, msgUndelegateDelegator, keeper) - require.True(t, got.IsOK(), "expected no error") - types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime) + res, err = handleMsgUndelegate(ctx, msgUndelegateDelegator, keeper) + require.NoError(t, err) + require.NotNil(t, res) + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, &finishTime) ctx = ctx.WithBlockTime(finishTime) EndBlocker(ctx, keeper) // verify that the pubkey can now be reused - got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected ok, got %v", got) + res, err = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) } func TestValidatorQueue(t *testing.T) { @@ -664,25 +700,28 @@ func TestValidatorQueue(t *testing.T) { // create the validator valTokens := sdk.TokensFromConsensusPower(10) msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], valTokens) - got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) // bond a delegator delTokens := sdk.TokensFromConsensusPower(10) msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, delTokens) - got = handleMsgDelegate(ctx, msgDelegate, keeper) - require.True(t, got.IsOK(), "expected ok, got %v", got) + res, err = handleMsgDelegate(ctx, msgDelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) EndBlocker(ctx, keeper) // unbond the all self-delegation to put validator in unbonding state unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, delTokens) msgUndelegateValidator := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) - got = handleMsgUndelegate(ctx, msgUndelegateValidator, keeper) - require.True(t, got.IsOK(), "expected no error: %v", got) + res, err = handleMsgUndelegate(ctx, msgUndelegateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) var finishTime time.Time - types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime) + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, &finishTime) ctx = ctx.WithBlockTime(finishTime) EndBlocker(ctx, keeper) @@ -722,16 +761,18 @@ func TestUnbondingPeriod(t *testing.T) { // create the validator valTokens := sdk.TokensFromConsensusPower(10) msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], valTokens) - got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) EndBlocker(ctx, keeper) // begin unbonding unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(10)) msgUndelegate := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) - got = handleMsgUndelegate(ctx, msgUndelegate, keeper) - require.True(t, got.IsOK(), "expected no error") + res, err = handleMsgUndelegate(ctx, msgUndelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) origHeader := ctx.BlockHeader() @@ -762,29 +803,33 @@ func TestUnbondingFromUnbondingValidator(t *testing.T) { // create the validator msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], sdk.NewInt(10)) - got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) // bond a delegator msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, sdk.NewInt(10)) - got = handleMsgDelegate(ctx, msgDelegate, keeper) - require.True(t, got.IsOK(), "expected ok, got %v", got) + res, err = handleMsgDelegate(ctx, msgDelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) // unbond the validators bond portion unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) msgUndelegateValidator := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) - got = handleMsgUndelegate(ctx, msgUndelegateValidator, keeper) - require.True(t, got.IsOK(), "expected no error") + res, err = handleMsgUndelegate(ctx, msgUndelegateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) // change the ctx to Block Time one second before the validator would have unbonded var finishTime time.Time - types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime) + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, &finishTime) ctx = ctx.WithBlockTime(finishTime.Add(time.Second * -1)) // unbond the delegator from the validator msgUndelegateDelegator := NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) - got = handleMsgUndelegate(ctx, msgUndelegateDelegator, keeper) - require.True(t, got.IsOK(), "expected no error") + res, err = handleMsgUndelegate(ctx, msgUndelegateDelegator, keeper) + require.NoError(t, err) + require.NotNil(t, res) ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(keeper.UnbondingTime(ctx))) @@ -813,24 +858,27 @@ func TestRedelegationPeriod(t *testing.T) { // initial balance amt1 := AccMapper.GetAccount(ctx, sdk.AccAddress(validatorAddr)).GetCoins().AmountOf(denom) - got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) // balance should have been subtracted after creation amt2 := AccMapper.GetAccount(ctx, sdk.AccAddress(validatorAddr)).GetCoins().AmountOf(denom) require.Equal(t, amt1.Sub(sdk.NewInt(10)).Int64(), amt2.Int64(), "expected coins to be subtracted") msgCreateValidator = NewTestMsgCreateValidator(validatorAddr2, keep.PKs[1], sdk.NewInt(10)) - got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + res, err = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) bal1 := AccMapper.GetAccount(ctx, sdk.AccAddress(validatorAddr)).GetCoins() // begin redelegate redAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) msgBeginRedelegate := NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2, redAmt) - got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) - require.True(t, got.IsOK(), "expected no error, %v", got) + res, err = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) // origin account should not lose tokens as with a regular delegation bal2 := AccMapper.GetAccount(ctx, sdk.AccAddress(validatorAddr)).GetCoins() @@ -867,27 +915,32 @@ func TestTransitiveRedelegation(t *testing.T) { // create the validators msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], sdk.NewInt(10)) - got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) msgCreateValidator = NewTestMsgCreateValidator(validatorAddr2, keep.PKs[1], sdk.NewInt(10)) - got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + res, err = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) msgCreateValidator = NewTestMsgCreateValidator(validatorAddr3, keep.PKs[2], sdk.NewInt(10)) - got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + res, err = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) // begin redelegate redAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) msgBeginRedelegate := NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2, redAmt) - got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) - require.True(t, got.IsOK(), "expected no error, %v", got) + res, err = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) // cannot redelegation to next validator while first delegation exists msgBeginRedelegate = NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr2, validatorAddr3, redAmt) - got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) - require.True(t, !got.IsOK(), "expected an error, msg: %v", msgBeginRedelegate) + res, err = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) + require.Error(t, err) + require.Nil(t, res) params := keeper.GetParams(ctx) ctx = ctx.WithBlockTime(blockTime.Add(params.UnbondingTime)) @@ -896,8 +949,9 @@ func TestTransitiveRedelegation(t *testing.T) { EndBlocker(ctx, keeper) // now should be able to redelegate from the second validator to the third - got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) - require.True(t, got.IsOK(), "expected no error", got.Log) + res, err = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) } func TestMultipleRedelegationAtSameTime(t *testing.T) { @@ -913,12 +967,14 @@ func TestMultipleRedelegationAtSameTime(t *testing.T) { // create the validators valTokens := sdk.TokensFromConsensusPower(10) msgCreateValidator := NewTestMsgCreateValidator(valAddr, keep.PKs[0], valTokens) - got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) msgCreateValidator = NewTestMsgCreateValidator(valAddr2, keep.PKs[1], valTokens) - got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + res, err = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) // end block to bond them EndBlocker(ctx, keeper) @@ -927,8 +983,9 @@ func TestMultipleRedelegationAtSameTime(t *testing.T) { selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) redAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens.QuoRaw(2)) msgBeginRedelegate := NewMsgBeginRedelegate(selfDelAddr, valAddr, valAddr2, redAmt) - got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) - require.True(t, got.IsOK(), "expected no error, %v", got) + res, err = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) // there should only be one entry in the redelegation object rd, found := keeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) @@ -936,8 +993,9 @@ func TestMultipleRedelegationAtSameTime(t *testing.T) { require.Len(t, rd.Entries, 1) // start a second redelegation at this same time as the first - got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) - require.True(t, got.IsOK(), "expected no error, msg: %v", msgBeginRedelegate) + res, err = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) // now there should be two entries rd, found = keeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) @@ -965,12 +1023,14 @@ func TestMultipleRedelegationAtUniqueTimes(t *testing.T) { // create the validators valTokens := sdk.TokensFromConsensusPower(10) msgCreateValidator := NewTestMsgCreateValidator(valAddr, keep.PKs[0], valTokens) - got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) msgCreateValidator = NewTestMsgCreateValidator(valAddr2, keep.PKs[1], valTokens) - got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + res, err = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) // end block to bond them EndBlocker(ctx, keeper) @@ -979,13 +1039,15 @@ func TestMultipleRedelegationAtUniqueTimes(t *testing.T) { selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) redAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens.QuoRaw(2)) msgBeginRedelegate := NewMsgBeginRedelegate(selfDelAddr, valAddr, valAddr2, redAmt) - got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) - require.True(t, got.IsOK(), "expected no error, %v", got) + res, err = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) // move forward in time and start a second redelegation ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) - got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) - require.True(t, got.IsOK(), "expected no error, msg: %v", msgBeginRedelegate) + res, err = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) // now there should be two entries rd, found := keeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) @@ -1018,8 +1080,9 @@ func TestMultipleUnbondingDelegationAtSameTime(t *testing.T) { // create the validator valTokens := sdk.TokensFromConsensusPower(10) msgCreateValidator := NewTestMsgCreateValidator(valAddr, keep.PKs[0], valTokens) - got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) // end block to bond EndBlocker(ctx, keeper) @@ -1028,8 +1091,9 @@ func TestMultipleUnbondingDelegationAtSameTime(t *testing.T) { selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens.QuoRaw(2)) msgUndelegate := NewMsgUndelegate(selfDelAddr, valAddr, unbondAmt) - got = handleMsgUndelegate(ctx, msgUndelegate, keeper) - require.True(t, got.IsOK(), "expected no error, %v", got) + res, err = handleMsgUndelegate(ctx, msgUndelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) // there should only be one entry in the ubd object ubd, found := keeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) @@ -1037,8 +1101,9 @@ func TestMultipleUnbondingDelegationAtSameTime(t *testing.T) { require.Len(t, ubd.Entries, 1) // start a second ubd at this same time as the first - got = handleMsgUndelegate(ctx, msgUndelegate, keeper) - require.True(t, got.IsOK(), "expected no error, msg: %v", msgUndelegate) + res, err = handleMsgUndelegate(ctx, msgUndelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) // now there should be two entries ubd, found = keeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) @@ -1065,8 +1130,9 @@ func TestMultipleUnbondingDelegationAtUniqueTimes(t *testing.T) { // create the validator valTokens := sdk.TokensFromConsensusPower(10) msgCreateValidator := NewTestMsgCreateValidator(valAddr, keep.PKs[0], valTokens) - got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) // end block to bond EndBlocker(ctx, keeper) @@ -1075,8 +1141,9 @@ func TestMultipleUnbondingDelegationAtUniqueTimes(t *testing.T) { selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens.QuoRaw(2)) msgUndelegate := NewMsgUndelegate(selfDelAddr, valAddr, unbondAmt) - got = handleMsgUndelegate(ctx, msgUndelegate, keeper) - require.True(t, got.IsOK(), "expected no error, %v", got) + res, err = handleMsgUndelegate(ctx, msgUndelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) // there should only be one entry in the ubd object ubd, found := keeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) @@ -1085,8 +1152,9 @@ func TestMultipleUnbondingDelegationAtUniqueTimes(t *testing.T) { // move forwaubd in time and start a second redelegation ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) - got = handleMsgUndelegate(ctx, msgUndelegate, keeper) - require.True(t, got.IsOK(), "expected no error, msg: %v", msgUndelegate) + res, err = handleMsgUndelegate(ctx, msgUndelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) // now there should be two entries ubd, found = keeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) @@ -1121,24 +1189,30 @@ func TestUnbondingWhenExcessValidators(t *testing.T) { // add three validators valTokens1 := sdk.TokensFromConsensusPower(50) msgCreateValidator := NewTestMsgCreateValidator(validatorAddr1, keep.PKs[0], valTokens1) - got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) + // apply TM updates keeper.ApplyAndReturnValidatorSetUpdates(ctx) require.Equal(t, 1, len(keeper.GetLastValidators(ctx))) valTokens2 := sdk.TokensFromConsensusPower(30) msgCreateValidator = NewTestMsgCreateValidator(validatorAddr2, keep.PKs[1], valTokens2) - got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + res, err = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) + // apply TM updates keeper.ApplyAndReturnValidatorSetUpdates(ctx) require.Equal(t, 2, len(keeper.GetLastValidators(ctx))) valTokens3 := sdk.TokensFromConsensusPower(10) msgCreateValidator = NewTestMsgCreateValidator(validatorAddr3, keep.PKs[2], valTokens3) - got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + res, err = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) + // apply TM updates keeper.ApplyAndReturnValidatorSetUpdates(ctx) require.Equal(t, 2, len(keeper.GetLastValidators(ctx))) @@ -1146,8 +1220,9 @@ func TestUnbondingWhenExcessValidators(t *testing.T) { // unbond the validator-2 unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens2) msgUndelegate := NewMsgUndelegate(sdk.AccAddress(validatorAddr2), validatorAddr2, unbondAmt) - got = handleMsgUndelegate(ctx, msgUndelegate, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgUndelegate") + res, err = handleMsgUndelegate(ctx, msgUndelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) // apply TM updates keeper.ApplyAndReturnValidatorSetUpdates(ctx) @@ -1169,17 +1244,20 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) { valTokens := sdk.TokensFromConsensusPower(10) msgCreateValidator := NewTestMsgCreateValidator(valA, keep.PKs[0], valTokens) - got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) msgCreateValidator = NewTestMsgCreateValidator(valB, keep.PKs[1], valTokens) - got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + res, err = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) // delegate 10 stake msgDelegate := NewTestMsgDelegate(del, valA, valTokens) - got = handleMsgDelegate(ctx, msgDelegate, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgDelegate") + res, err = handleMsgDelegate(ctx, msgDelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) // apply Tendermint updates updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) @@ -1191,14 +1269,16 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) { // begin unbonding 4 stake unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(4)) msgUndelegate := NewMsgUndelegate(del, valA, unbondAmt) - got = handleMsgUndelegate(ctx, msgUndelegate, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgUndelegate") + res, err = handleMsgUndelegate(ctx, msgUndelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) // begin redelegate 6 stake redAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(6)) msgBeginRedelegate := NewMsgBeginRedelegate(del, valA, valB, redAmt) - got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgBeginRedelegate") + res, err = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) // destination delegation should have 6 shares delegation, found := keeper.GetDelegation(ctx, del, valB) @@ -1266,9 +1346,10 @@ func TestInvalidMsg(t *testing.T) { k := keep.Keeper{} h := NewHandler(k) - res := h(sdk.NewContext(nil, abci.Header{}, false, nil), sdk.NewTestMsg()) - require.False(t, res.IsOK()) - require.True(t, strings.Contains(res.Log, "unrecognized staking message type")) + res, err := h(sdk.NewContext(nil, abci.Header{}, false, nil), sdk.NewTestMsg()) + require.Error(t, err) + require.Nil(t, res) + require.True(t, strings.Contains(err.Error(), "unrecognized staking message type")) } func TestInvalidCoinDenom(t *testing.T) { @@ -1283,33 +1364,47 @@ func TestInvalidCoinDenom(t *testing.T) { commission := types.NewCommissionRates(sdk.OneDec(), sdk.OneDec(), sdk.ZeroDec()) msgCreate := types.NewMsgCreateValidator(valA, keep.PKs[0], invalidCoin, Description{}, commission, sdk.OneInt()) - got := handleMsgCreateValidator(ctx, msgCreate, keeper) - require.False(t, got.IsOK()) + res, err := handleMsgCreateValidator(ctx, msgCreate, keeper) + require.Error(t, err) + require.Nil(t, res) + msgCreate = types.NewMsgCreateValidator(valA, keep.PKs[0], validCoin, Description{}, commission, sdk.OneInt()) - got = handleMsgCreateValidator(ctx, msgCreate, keeper) - require.True(t, got.IsOK()) + res, err = handleMsgCreateValidator(ctx, msgCreate, keeper) + require.NoError(t, err) + require.NotNil(t, res) + msgCreate = types.NewMsgCreateValidator(valB, keep.PKs[1], validCoin, Description{}, commission, sdk.OneInt()) - got = handleMsgCreateValidator(ctx, msgCreate, keeper) - require.True(t, got.IsOK()) + res, err = handleMsgCreateValidator(ctx, msgCreate, keeper) + require.NoError(t, err) + require.NotNil(t, res) msgDelegate := types.NewMsgDelegate(delAddr, valA, invalidCoin) - got = handleMsgDelegate(ctx, msgDelegate, keeper) - require.False(t, got.IsOK()) + res, err = handleMsgDelegate(ctx, msgDelegate, keeper) + require.Error(t, err) + require.Nil(t, res) + msgDelegate = types.NewMsgDelegate(delAddr, valA, validCoin) - got = handleMsgDelegate(ctx, msgDelegate, keeper) - require.True(t, got.IsOK()) + res, err = handleMsgDelegate(ctx, msgDelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) msgUndelegate := types.NewMsgUndelegate(delAddr, valA, invalidCoin) - got = handleMsgUndelegate(ctx, msgUndelegate, keeper) - require.False(t, got.IsOK()) + res, err = handleMsgUndelegate(ctx, msgUndelegate, keeper) + require.Error(t, err) + require.Nil(t, res) + msgUndelegate = types.NewMsgUndelegate(delAddr, valA, oneCoin) - got = handleMsgUndelegate(ctx, msgUndelegate, keeper) - require.True(t, got.IsOK()) + res, err = handleMsgUndelegate(ctx, msgUndelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) msgRedelegate := types.NewMsgBeginRedelegate(delAddr, valA, valB, invalidCoin) - got = handleMsgBeginRedelegate(ctx, msgRedelegate, keeper) - require.False(t, got.IsOK()) + res, err = handleMsgBeginRedelegate(ctx, msgRedelegate, keeper) + require.Error(t, err) + require.Nil(t, res) + msgRedelegate = types.NewMsgBeginRedelegate(delAddr, valA, valB, oneCoin) - got = handleMsgBeginRedelegate(ctx, msgRedelegate, keeper) - require.True(t, got.IsOK()) + res, err = handleMsgBeginRedelegate(ctx, msgRedelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) } diff --git a/x/staking/keeper/delegation.go b/x/staking/keeper/delegation.go index 3aa244b3b3c9..faf8ba415ef7 100644 --- a/x/staking/keeper/delegation.go +++ b/x/staking/keeper/delegation.go @@ -6,6 +6,7 @@ import ( "time" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/staking/types" ) @@ -456,14 +457,16 @@ func (k Keeper) DequeueAllMatureRedelegationQueue(ctx sdk.Context, currTime time // Perform a delegation, set/update everything necessary within the store. // tokenSrc indicates the bond status of the incoming funds. -func (k Keeper) Delegate(ctx sdk.Context, delAddr sdk.AccAddress, bondAmt sdk.Int, tokenSrc sdk.BondStatus, - validator types.Validator, subtractAccount bool) (newShares sdk.Dec, err sdk.Error) { +func (k Keeper) Delegate( + ctx sdk.Context, delAddr sdk.AccAddress, bondAmt sdk.Int, tokenSrc sdk.BondStatus, + validator types.Validator, subtractAccount bool, +) (newShares sdk.Dec, err error) { // In some situations, the exchange rate becomes invalid, e.g. if // Validator loses all tokens due to slashing. In this case, // make all future delegations invalid. if validator.InvalidExRate() { - return sdk.ZeroDec(), types.ErrDelegatorShareExRateInvalid(k.Codespace()) + return sdk.ZeroDec(), types.ErrDelegatorShareExRateInvalid } // Get or create the delegation object @@ -534,13 +537,14 @@ func (k Keeper) Delegate(ctx sdk.Context, delAddr sdk.AccAddress, bondAmt sdk.In } // unbond a particular delegation and perform associated store operations -func (k Keeper) unbond(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress, - shares sdk.Dec) (amount sdk.Int, err sdk.Error) { +func (k Keeper) unbond( + ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress, shares sdk.Dec, +) (amount sdk.Int, err error) { // check if a delegation object exists in the store delegation, found := k.GetDelegation(ctx, delAddr, valAddr) if !found { - return amount, types.ErrNoDelegatorForAddress(k.Codespace()) + return amount, types.ErrNoDelegatorForAddress } // call the before-delegation-modified hook @@ -548,13 +552,13 @@ func (k Keeper) unbond(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValA // ensure that we have enough shares to remove if delegation.Shares.LT(shares) { - return amount, types.ErrNotEnoughDelegationShares(k.Codespace(), delegation.Shares.String()) + return amount, sdkerrors.Wrap(types.ErrNotEnoughDelegationShares, delegation.Shares.String()) } // get validator validator, found := k.GetValidator(ctx, valAddr) if !found { - return amount, types.ErrNoValidatorFound(k.Codespace()) + return amount, types.ErrNoValidatorFound } // subtract shares from delegation @@ -628,15 +632,15 @@ func (k Keeper) getBeginInfo( // processed during the staking EndBlocker. func (k Keeper) Undelegate( ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress, sharesAmount sdk.Dec, -) (time.Time, sdk.Error) { +) (time.Time, error) { validator, found := k.GetValidator(ctx, valAddr) if !found { - return time.Time{}, types.ErrNoDelegatorForAddress(k.Codespace()) + return time.Time{}, types.ErrNoDelegatorForAddress } if k.HasMaxUnbondingDelegationEntries(ctx, delAddr, valAddr) { - return time.Time{}, types.ErrMaxUnbondingDelegationEntries(k.Codespace()) + return time.Time{}, types.ErrMaxUnbondingDelegationEntries } returnAmount, err := k.unbond(ctx, delAddr, valAddr, sharesAmount) @@ -658,12 +662,10 @@ func (k Keeper) Undelegate( // CompleteUnbonding completes the unbonding of all mature entries in the // retrieved unbonding delegation object. -func (k Keeper) CompleteUnbonding(ctx sdk.Context, delAddr sdk.AccAddress, - valAddr sdk.ValAddress) sdk.Error { - +func (k Keeper) CompleteUnbonding(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) error { ubd, found := k.GetUnbondingDelegation(ctx, delAddr, valAddr) if !found { - return types.ErrNoUnbondingDelegation(k.Codespace()) + return types.ErrNoUnbondingDelegation } ctxTime := ctx.BlockHeader().Time @@ -697,31 +699,31 @@ func (k Keeper) CompleteUnbonding(ctx sdk.Context, delAddr sdk.AccAddress, } // begin unbonding / redelegation; create a redelegation record -func (k Keeper) BeginRedelegation(ctx sdk.Context, delAddr sdk.AccAddress, - valSrcAddr, valDstAddr sdk.ValAddress, sharesAmount sdk.Dec) ( - completionTime time.Time, errSdk sdk.Error) { +func (k Keeper) BeginRedelegation( + ctx sdk.Context, delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress, sharesAmount sdk.Dec, +) (completionTime time.Time, err error) { if bytes.Equal(valSrcAddr, valDstAddr) { - return time.Time{}, types.ErrSelfRedelegation(k.Codespace()) + return time.Time{}, types.ErrSelfRedelegation } dstValidator, found := k.GetValidator(ctx, valDstAddr) if !found { - return time.Time{}, types.ErrBadRedelegationDst(k.Codespace()) + return time.Time{}, types.ErrBadRedelegationDst } srcValidator, found := k.GetValidator(ctx, valSrcAddr) if !found { - return time.Time{}, types.ErrBadRedelegationDst(k.Codespace()) + return time.Time{}, types.ErrBadRedelegationDst } // check if this is a transitive redelegation if k.HasReceivingRedelegation(ctx, delAddr, valSrcAddr) { - return time.Time{}, types.ErrTransitiveRedelegation(k.Codespace()) + return time.Time{}, types.ErrTransitiveRedelegation } if k.HasMaxRedelegationEntries(ctx, delAddr, valSrcAddr, valDstAddr) { - return time.Time{}, types.ErrMaxRedelegationEntries(k.Codespace()) + return time.Time{}, types.ErrMaxRedelegationEntries } returnAmount, err := k.unbond(ctx, delAddr, valSrcAddr, sharesAmount) @@ -730,7 +732,7 @@ func (k Keeper) BeginRedelegation(ctx sdk.Context, delAddr sdk.AccAddress, } if returnAmount.IsZero() { - return time.Time{}, types.ErrVerySmallRedelegation(k.Codespace()) + return time.Time{}, types.ErrTinyRedelegationAmount } sharesCreated, err := k.Delegate(ctx, delAddr, returnAmount, srcValidator.GetStatus(), dstValidator, false) @@ -745,20 +747,23 @@ func (k Keeper) BeginRedelegation(ctx sdk.Context, delAddr sdk.AccAddress, return completionTime, nil } - red := k.SetRedelegationEntry(ctx, delAddr, valSrcAddr, valDstAddr, - height, completionTime, returnAmount, sharesAmount, sharesCreated) + red := k.SetRedelegationEntry( + ctx, delAddr, valSrcAddr, valDstAddr, + height, completionTime, returnAmount, sharesAmount, sharesCreated, + ) k.InsertRedelegationQueue(ctx, red, completionTime) return completionTime, nil } // CompleteRedelegation completes the unbonding of all mature entries in the // retrieved unbonding delegation object. -func (k Keeper) CompleteRedelegation(ctx sdk.Context, delAddr sdk.AccAddress, - valSrcAddr, valDstAddr sdk.ValAddress) sdk.Error { +func (k Keeper) CompleteRedelegation( + ctx sdk.Context, delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress, +) error { red, found := k.GetRedelegation(ctx, delAddr, valSrcAddr, valDstAddr) if !found { - return types.ErrNoRedelegation(k.Codespace()) + return types.ErrNoRedelegation } ctxTime := ctx.BlockHeader().Time @@ -787,16 +792,16 @@ func (k Keeper) CompleteRedelegation(ctx sdk.Context, delAddr sdk.AccAddress, // amount of respective shares is returned, otherwise an error is returned. func (k Keeper) ValidateUnbondAmount( ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress, amt sdk.Int, -) (shares sdk.Dec, err sdk.Error) { +) (shares sdk.Dec, err error) { validator, found := k.GetValidator(ctx, valAddr) if !found { - return shares, types.ErrNoValidatorFound(k.Codespace()) + return shares, types.ErrNoValidatorFound } del, found := k.GetDelegation(ctx, delAddr, valAddr) if !found { - return shares, types.ErrNoDelegation(k.Codespace()) + return shares, types.ErrNoDelegation } shares, err = validator.SharesFromTokens(amt) @@ -811,7 +816,7 @@ func (k Keeper) ValidateUnbondAmount( delShares := del.GetShares() if sharesTruncated.GT(delShares) { - return shares, types.ErrBadSharesAmount(k.Codespace()) + return shares, types.ErrBadSharesAmount } // Cap the shares at the delegation's shares. Shares being greater could occur diff --git a/x/staking/keeper/keeper.go b/x/staking/keeper/keeper.go index a63f5cf1ed68..fd51603115b7 100644 --- a/x/staking/keeper/keeper.go +++ b/x/staking/keeper/keeper.go @@ -29,14 +29,12 @@ type Keeper struct { paramstore params.Subspace validatorCache map[string]cachedValidator validatorCacheList *list.List - - // codespace - codespace sdk.CodespaceType } // NewKeeper creates a new staking Keeper instance -func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, supplyKeeper types.SupplyKeeper, - paramstore params.Subspace, codespace sdk.CodespaceType) Keeper { +func NewKeeper( + cdc *codec.Codec, key sdk.StoreKey, supplyKeeper types.SupplyKeeper, paramstore params.Subspace, +) Keeper { // ensure bonded and not bonded module accounts are set if addr := supplyKeeper.GetModuleAddress(types.BondedPoolName); addr == nil { @@ -55,7 +53,6 @@ func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, supplyKeeper types.SupplyKeep hooks: nil, validatorCache: make(map[string]cachedValidator, aminoCacheSize), validatorCacheList: list.New(), - codespace: codespace, } } @@ -73,11 +70,6 @@ func (k *Keeper) SetHooks(sh types.StakingHooks) *Keeper { return k } -// return the codespace -func (k Keeper) Codespace() sdk.CodespaceType { - return k.codespace -} - // Load the last total validator power. func (k Keeper) GetLastTotalPower(ctx sdk.Context) (power sdk.Int) { store := ctx.KVStore(k.storeKey) diff --git a/x/staking/keeper/pool.go b/x/staking/keeper/pool.go index 4ceb02446d93..004013ed8fe4 100644 --- a/x/staking/keeper/pool.go +++ b/x/staking/keeper/pool.go @@ -35,7 +35,7 @@ func (k Keeper) notBondedTokensToBonded(ctx sdk.Context, tokens sdk.Int) { } // burnBondedTokens removes coins from the bonded pool module account -func (k Keeper) burnBondedTokens(ctx sdk.Context, amt sdk.Int) sdk.Error { +func (k Keeper) burnBondedTokens(ctx sdk.Context, amt sdk.Int) error { if !amt.IsPositive() { // skip as no coins need to be burned return nil @@ -45,7 +45,7 @@ func (k Keeper) burnBondedTokens(ctx sdk.Context, amt sdk.Int) sdk.Error { } // burnNotBondedTokens removes coins from the not bonded pool module account -func (k Keeper) burnNotBondedTokens(ctx sdk.Context, amt sdk.Int) sdk.Error { +func (k Keeper) burnNotBondedTokens(ctx sdk.Context, amt sdk.Int) error { if !amt.IsPositive() { // skip as no coins need to be burned return nil diff --git a/x/staking/keeper/querier.go b/x/staking/keeper/querier.go index 15bc59ee5ff6..bc8a5b5b7fc0 100644 --- a/x/staking/keeper/querier.go +++ b/x/staking/keeper/querier.go @@ -1,7 +1,7 @@ package keeper import ( - "fmt" + "errors" "strings" abci "github.com/tendermint/tendermint/abci/types" @@ -9,53 +9,68 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/staking/types" ) // creates a querier for staking REST endpoints func NewQuerier(k Keeper) sdk.Querier { - return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err sdk.Error) { + return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) { switch path[0] { case types.QueryValidators: return queryValidators(ctx, req, k) + case types.QueryValidator: return queryValidator(ctx, req, k) + case types.QueryValidatorDelegations: return queryValidatorDelegations(ctx, req, k) + case types.QueryValidatorUnbondingDelegations: return queryValidatorUnbondingDelegations(ctx, req, k) + case types.QueryDelegation: return queryDelegation(ctx, req, k) + case types.QueryUnbondingDelegation: return queryUnbondingDelegation(ctx, req, k) + case types.QueryDelegatorDelegations: return queryDelegatorDelegations(ctx, req, k) + case types.QueryDelegatorUnbondingDelegations: return queryDelegatorUnbondingDelegations(ctx, req, k) + case types.QueryRedelegations: return queryRedelegations(ctx, req, k) + case types.QueryDelegatorValidators: return queryDelegatorValidators(ctx, req, k) + case types.QueryDelegatorValidator: return queryDelegatorValidator(ctx, req, k) + case types.QueryHistoricalInfo: return queryHistoricalInfo(ctx, req, k) + case types.QueryPool: return queryPool(ctx, k) + case types.QueryParameters: return queryParameters(ctx, k) + default: - return nil, sdk.ErrUnknownRequest("unknown staking query endpoint") + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown %s query endpoint: %s", types.ModuleName, path[0]) } } } -func queryValidators(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryValidators(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryValidatorsParams err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } validators := k.GetAllValidators(ctx) @@ -76,45 +91,45 @@ func queryValidators(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, res, err := codec.MarshalJSONIndent(types.ModuleCdc, filteredVals) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to JSON marshal result: %s", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil } -func queryValidator(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryValidator(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryValidatorParams err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } validator, found := k.GetValidator(ctx, params.ValidatorAddr) if !found { - return nil, types.ErrNoValidatorFound(types.DefaultCodespace) + return nil, types.ErrNoValidatorFound } res, err := codec.MarshalJSONIndent(types.ModuleCdc, validator) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil } -func queryValidatorDelegations(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryValidatorDelegations(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryValidatorParams err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } delegations := k.GetValidatorDelegations(ctx, params.ValidatorAddr) delegationResps, err := delegationsToDelegationResponses(ctx, k, delegations) if err != nil { - return nil, sdk.ErrInternal(err.Error()) + return nil, err } if delegationResps == nil { @@ -123,18 +138,18 @@ func queryValidatorDelegations(ctx sdk.Context, req abci.RequestQuery, k Keeper) res, err := codec.MarshalJSONIndent(types.ModuleCdc, delegationResps) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil } -func queryValidatorUnbondingDelegations(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryValidatorUnbondingDelegations(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryValidatorParams err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } unbonds := k.GetUnbondingDelegationsFromValidator(ctx, params.ValidatorAddr) @@ -144,24 +159,24 @@ func queryValidatorUnbondingDelegations(ctx sdk.Context, req abci.RequestQuery, res, err := codec.MarshalJSONIndent(types.ModuleCdc, unbonds) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil } -func queryDelegatorDelegations(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryDelegatorDelegations(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryDelegatorParams err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } delegations := k.GetAllDelegatorDelegations(ctx, params.DelegatorAddr) delegationResps, err := delegationsToDelegationResponses(ctx, k, delegations) if err != nil { - return nil, sdk.ErrInternal(err.Error()) + return nil, err } if delegationResps == nil { @@ -170,18 +185,18 @@ func queryDelegatorDelegations(ctx sdk.Context, req abci.RequestQuery, k Keeper) res, err := codec.MarshalJSONIndent(types.ModuleCdc, delegationResps) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil } -func queryDelegatorUnbondingDelegations(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryDelegatorUnbondingDelegations(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryDelegatorParams err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } unbondingDelegations := k.GetAllUnbondingDelegations(ctx, params.DelegatorAddr) @@ -191,20 +206,20 @@ func queryDelegatorUnbondingDelegations(ctx sdk.Context, req abci.RequestQuery, res, err := codec.MarshalJSONIndent(types.ModuleCdc, unbondingDelegations) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil } -func queryDelegatorValidators(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryDelegatorValidators(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryDelegatorParams stakingParams := k.GetParams(ctx) err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } validators := k.GetDelegatorValidators(ctx, params.DelegatorAddr, stakingParams.MaxValidators) @@ -214,86 +229,86 @@ func queryDelegatorValidators(ctx sdk.Context, req abci.RequestQuery, k Keeper) res, err := codec.MarshalJSONIndent(types.ModuleCdc, validators) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil } -func queryDelegatorValidator(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryDelegatorValidator(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryBondsParams err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } validator, err := k.GetDelegatorValidator(ctx, params.DelegatorAddr, params.ValidatorAddr) if err != nil { - return nil, sdk.ErrInternal(err.Error()) + return nil, err } res, err := codec.MarshalJSONIndent(types.ModuleCdc, validator) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil } -func queryDelegation(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryDelegation(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryBondsParams err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } delegation, found := k.GetDelegation(ctx, params.DelegatorAddr, params.ValidatorAddr) if !found { - return nil, types.ErrNoDelegation(types.DefaultCodespace) + return nil, types.ErrNoDelegation } delegationResp, err := delegationToDelegationResponse(ctx, k, delegation) if err != nil { - return nil, sdk.ErrInternal(err.Error()) + return nil, err } res, err := codec.MarshalJSONIndent(types.ModuleCdc, delegationResp) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil } -func queryUnbondingDelegation(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryUnbondingDelegation(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryBondsParams err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } unbond, found := k.GetUnbondingDelegation(ctx, params.DelegatorAddr, params.ValidatorAddr) if !found { - return nil, types.ErrNoUnbondingDelegation(types.DefaultCodespace) + return nil, types.ErrNoUnbondingDelegation } res, err := codec.MarshalJSONIndent(types.ModuleCdc, unbond) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil } -func queryRedelegations(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryRedelegations(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryRedelegationParams err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrUnknownRequest(string(req.Data)) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } var redels []types.Redelegation @@ -302,7 +317,7 @@ func queryRedelegations(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byt case !params.DelegatorAddr.Empty() && !params.SrcValidatorAddr.Empty() && !params.DstValidatorAddr.Empty(): redel, found := k.GetRedelegation(ctx, params.DelegatorAddr, params.SrcValidatorAddr, params.DstValidatorAddr) if !found { - return nil, types.ErrNoRedelegation(types.DefaultCodespace) + return nil, types.ErrNoRedelegation } redels = []types.Redelegation{redel} @@ -314,7 +329,7 @@ func queryRedelegations(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byt redelResponses, err := redelegationsToRedelegationResponses(ctx, k, redels) if err != nil { - return nil, sdk.ErrInternal(err.Error()) + return nil, err } if redelResponses == nil { @@ -323,39 +338,40 @@ func queryRedelegations(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byt res, err := codec.MarshalJSONIndent(types.ModuleCdc, redelResponses) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil } -func queryHistoricalInfo(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryHistoricalInfo(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryHistoricalInfoParams err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrUnknownRequest(string(req.Data)) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } hi, found := k.GetHistoricalInfo(ctx, params.Height) if !found { - return nil, types.ErrNoHistoricalInfo(types.DefaultCodespace) + return nil, types.ErrNoHistoricalInfo } res, err := codec.MarshalJSONIndent(types.ModuleCdc, hi) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil } -func queryPool(ctx sdk.Context, k Keeper) ([]byte, sdk.Error) { +func queryPool(ctx sdk.Context, k Keeper) ([]byte, error) { bondDenom := k.BondDenom(ctx) + bondedPool := k.GetBondedPool(ctx) notBondedPool := k.GetNotBondedPool(ctx) if bondedPool == nil || notBondedPool == nil { - return nil, sdk.ErrInternal("pool accounts haven't been set") + return nil, errors.New("pool accounts haven't been set") } pool := types.NewPool( @@ -365,18 +381,18 @@ func queryPool(ctx sdk.Context, k Keeper) ([]byte, sdk.Error) { res, err := codec.MarshalJSONIndent(types.ModuleCdc, pool) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil } -func queryParameters(ctx sdk.Context, k Keeper) ([]byte, sdk.Error) { +func queryParameters(ctx sdk.Context, k Keeper) ([]byte, error) { params := k.GetParams(ctx) res, err := codec.MarshalJSONIndent(types.ModuleCdc, params) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil @@ -385,10 +401,10 @@ func queryParameters(ctx sdk.Context, k Keeper) ([]byte, sdk.Error) { //______________________________________________________ // util -func delegationToDelegationResponse(ctx sdk.Context, k Keeper, del types.Delegation) (types.DelegationResponse, sdk.Error) { +func delegationToDelegationResponse(ctx sdk.Context, k Keeper, del types.Delegation) (types.DelegationResponse, error) { val, found := k.GetValidator(ctx, del.ValidatorAddress) if !found { - return types.DelegationResponse{}, types.ErrNoValidatorFound(types.DefaultCodespace) + return types.DelegationResponse{}, types.ErrNoValidatorFound } return types.NewDelegationResp( @@ -401,7 +417,7 @@ func delegationToDelegationResponse(ctx sdk.Context, k Keeper, del types.Delegat func delegationsToDelegationResponses( ctx sdk.Context, k Keeper, delegations types.Delegations, -) (types.DelegationResponses, sdk.Error) { +) (types.DelegationResponses, error) { resp := make(types.DelegationResponses, len(delegations)) for i, del := range delegations { @@ -418,13 +434,13 @@ func delegationsToDelegationResponses( func redelegationsToRedelegationResponses( ctx sdk.Context, k Keeper, redels types.Redelegations, -) (types.RedelegationResponses, sdk.Error) { +) (types.RedelegationResponses, error) { resp := make(types.RedelegationResponses, len(redels)) for i, redel := range redels { val, found := k.GetValidator(ctx, redel.ValidatorDstAddress) if !found { - return nil, types.ErrNoValidatorFound(types.DefaultCodespace) + return nil, types.ErrNoValidatorFound } entryResponses := make([]types.RedelegationEntryResponse, len(redel.Entries)) diff --git a/x/staking/keeper/query_utils.go b/x/staking/keeper/query_utils.go index 6bde68f5df6e..336bb842ab9e 100644 --- a/x/staking/keeper/query_utils.go +++ b/x/staking/keeper/query_utils.go @@ -21,7 +21,7 @@ func (k Keeper) GetDelegatorValidators(ctx sdk.Context, delegatorAddr sdk.AccAdd validator, found := k.GetValidator(ctx, delegation.ValidatorAddress) if !found { - panic(types.ErrNoValidatorFound(types.DefaultCodespace)) + panic(types.ErrNoValidatorFound) } validators[i] = validator i++ @@ -31,16 +31,16 @@ func (k Keeper) GetDelegatorValidators(ctx sdk.Context, delegatorAddr sdk.AccAdd // return a validator that a delegator is bonded to func (k Keeper) GetDelegatorValidator(ctx sdk.Context, delegatorAddr sdk.AccAddress, - validatorAddr sdk.ValAddress) (validator types.Validator, err sdk.Error) { + validatorAddr sdk.ValAddress) (validator types.Validator, err error) { delegation, found := k.GetDelegation(ctx, delegatorAddr, validatorAddr) if !found { - return validator, types.ErrNoDelegation(types.DefaultCodespace) + return validator, types.ErrNoDelegation } validator, found = k.GetValidator(ctx, delegation.ValidatorAddress) if !found { - panic(types.ErrNoValidatorFound(types.DefaultCodespace)) + panic(types.ErrNoValidatorFound) } return } diff --git a/x/staking/keeper/test_common.go b/x/staking/keeper/test_common.go index 51d7f71ae9d6..0d730b48b3ca 100644 --- a/x/staking/keeper/test_common.go +++ b/x/staking/keeper/test_common.go @@ -115,7 +115,7 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context blacklistedAddrs[notBondedPool.GetAddress().String()] = true blacklistedAddrs[bondPool.GetAddress().String()] = true - pk := params.NewKeeper(cdc, keyParams, tkeyParams, params.DefaultCodespace) + pk := params.NewKeeper(cdc, keyParams, tkeyParams) accountKeeper := auth.NewAccountKeeper( cdc, // amino codec @@ -127,7 +127,6 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context bk := bank.NewBaseKeeper( accountKeeper, pk.Subspace(bank.DefaultParamspace), - bank.DefaultCodespace, blacklistedAddrs, ) @@ -144,7 +143,7 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context supplyKeeper.SetSupply(ctx, supply.NewSupply(totalSupply)) - keeper := NewKeeper(cdc, keyStaking, supplyKeeper, pk.Subspace(DefaultParamspace), types.DefaultCodespace) + keeper := NewKeeper(cdc, keyStaking, supplyKeeper, pk.Subspace(DefaultParamspace)) keeper.SetParams(ctx, types.DefaultParams()) // set module accounts diff --git a/x/staking/keeper/validator.go b/x/staking/keeper/validator.go index cd5e912ca92a..48ecbb384313 100644 --- a/x/staking/keeper/validator.go +++ b/x/staking/keeper/validator.go @@ -156,7 +156,7 @@ func (k Keeper) RemoveValidatorTokens(ctx sdk.Context, // UpdateValidatorCommission attempts to update a validator's commission rate. // An error is returned if the new commission rate is invalid. func (k Keeper) UpdateValidatorCommission(ctx sdk.Context, - validator types.Validator, newRate sdk.Dec) (types.Commission, sdk.Error) { + validator types.Validator, newRate sdk.Dec) (types.Commission, error) { commission := validator.Commission blockTime := ctx.BlockHeader().Time diff --git a/x/staking/simulation/operations.go b/x/staking/simulation/operations.go index 8ddea88aa7c6..b1a932270641 100644 --- a/x/staking/simulation/operations.go +++ b/x/staking/simulation/operations.go @@ -1,7 +1,6 @@ package simulation import ( - "errors" "fmt" "math/rand" @@ -161,9 +160,9 @@ func SimulateMsgCreateValidator(ak types.AccountKeeper, k keeper.Keeper) simulat simAccount.PrivKey, ) - res := app.Deliver(tx) - if !res.IsOK() { - return simulation.NoOpMsg(types.ModuleName), nil, errors.New(res.Log) + _, _, err = app.Deliver(tx) + if err != nil { + return simulation.NoOpMsg(types.ModuleName), nil, err } return simulation.NewOperationMsg(msg, true, ""), nil, nil @@ -226,9 +225,9 @@ func SimulateMsgEditValidator(ak types.AccountKeeper, k keeper.Keeper) simulatio simAccount.PrivKey, ) - res := app.Deliver(tx) - if !res.IsOK() { - return simulation.NoOpMsg(types.ModuleName), nil, errors.New(res.Log) + _, _, err = app.Deliver(tx) + if err != nil { + return simulation.NoOpMsg(types.ModuleName), nil, err } return simulation.NewOperationMsg(msg, true, ""), nil, nil @@ -293,9 +292,9 @@ func SimulateMsgDelegate(ak types.AccountKeeper, k keeper.Keeper) simulation.Ope simAccount.PrivKey, ) - res := app.Deliver(tx) - if !res.IsOK() { - return simulation.NoOpMsg(types.ModuleName), nil, errors.New(res.Log) + _, _, err = app.Deliver(tx) + if err != nil { + return simulation.NoOpMsg(types.ModuleName), nil, err } return simulation.NewOperationMsg(msg, true, ""), nil, nil @@ -373,9 +372,9 @@ func SimulateMsgUndelegate(ak types.AccountKeeper, k keeper.Keeper) simulation.O simAccount.PrivKey, ) - res := app.Deliver(tx) - if !res.IsOK() { - return simulation.NoOpMsg(types.ModuleName), nil, errors.New(res.Log) + _, _, err = app.Deliver(tx) + if err != nil { + return simulation.NoOpMsg(types.ModuleName), nil, err } return simulation.NewOperationMsg(msg, true, ""), nil, nil @@ -479,9 +478,9 @@ func SimulateMsgBeginRedelegate(ak types.AccountKeeper, k keeper.Keeper) simulat simAccount.PrivKey, ) - res := app.Deliver(tx) - if !res.IsOK() { - return simulation.NoOpMsg(types.ModuleName), nil, errors.New(res.Log) + _, _, err = app.Deliver(tx) + if err != nil { + return simulation.NoOpMsg(types.ModuleName), nil, err } return simulation.NewOperationMsg(msg, true, ""), nil, nil diff --git a/x/staking/types/commission.go b/x/staking/types/commission.go index f447c452822f..38ab8e06a703 100644 --- a/x/staking/types/commission.go +++ b/x/staking/types/commission.go @@ -67,31 +67,31 @@ func (c Commission) String() string { // Validate performs basic sanity validation checks of initial commission // parameters. If validation fails, an SDK error is returned. -func (c CommissionRates) Validate() sdk.Error { +func (c CommissionRates) Validate() error { switch { case c.MaxRate.IsNegative(): // max rate cannot be negative - return ErrCommissionNegative(DefaultCodespace) + return ErrCommissionNegative case c.MaxRate.GT(sdk.OneDec()): // max rate cannot be greater than 1 - return ErrCommissionHuge(DefaultCodespace) + return ErrCommissionHuge case c.Rate.IsNegative(): // rate cannot be negative - return ErrCommissionNegative(DefaultCodespace) + return ErrCommissionNegative case c.Rate.GT(c.MaxRate): // rate cannot be greater than the max rate - return ErrCommissionGTMaxRate(DefaultCodespace) + return ErrCommissionGTMaxRate case c.MaxChangeRate.IsNegative(): // change rate cannot be negative - return ErrCommissionChangeRateNegative(DefaultCodespace) + return ErrCommissionChangeRateNegative case c.MaxChangeRate.GT(c.MaxRate): // change rate cannot be greater than the max rate - return ErrCommissionChangeRateGTMaxRate(DefaultCodespace) + return ErrCommissionChangeRateGTMaxRate } return nil @@ -99,23 +99,23 @@ func (c CommissionRates) Validate() sdk.Error { // ValidateNewRate performs basic sanity validation checks of a new commission // rate. If validation fails, an SDK error is returned. -func (c Commission) ValidateNewRate(newRate sdk.Dec, blockTime time.Time) sdk.Error { +func (c Commission) ValidateNewRate(newRate sdk.Dec, blockTime time.Time) error { switch { case blockTime.Sub(c.UpdateTime).Hours() < 24: // new rate cannot be changed more than once within 24 hours - return ErrCommissionUpdateTime(DefaultCodespace) + return ErrCommissionUpdateTime case newRate.IsNegative(): // new rate cannot be negative - return ErrCommissionNegative(DefaultCodespace) + return ErrCommissionNegative case newRate.GT(c.MaxRate): // new rate cannot be greater than the max rate - return ErrCommissionGTMaxRate(DefaultCodespace) + return ErrCommissionGTMaxRate case newRate.Sub(c.Rate).GT(c.MaxChangeRate): // new rate % points change cannot be greater than the max change rate - return ErrCommissionGTMaxChangeRate(DefaultCodespace) + return ErrCommissionGTMaxChangeRate } return nil diff --git a/x/staking/types/errors.go b/x/staking/types/errors.go index 523e720e2d98..d3ccf0a9dac2 100644 --- a/x/staking/types/errors.go +++ b/x/staking/types/errors.go @@ -1,223 +1,59 @@ -// nolint package types import ( - "fmt" - "strings" - "time" - - sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) -type CodeType = sdk.CodeType - -const ( - DefaultCodespace sdk.CodespaceType = ModuleName - - CodeInvalidValidator CodeType = 101 - CodeInvalidDelegation CodeType = 102 - CodeInvalidInput CodeType = 103 - CodeValidatorJailed CodeType = 104 - CodeInvalidHistoricalInfo CodeType = 105 - CodeInvalidAddress CodeType = sdk.CodeInvalidAddress - CodeUnauthorized CodeType = sdk.CodeUnauthorized - CodeInternal CodeType = sdk.CodeInternal - CodeUnknownRequest CodeType = sdk.CodeUnknownRequest +// x/staking module sentinel errors +// +// TODO: Many of these errors are redundant. They should be removed and replaced +// by sdkerrors.ErrInvalidRequest. +// +// REF: https://github.com/cosmos/cosmos-sdk/issues/5450 +var ( + ErrEmptyValidatorAddr = sdkerrors.Register(ModuleName, 1, "empty validator address") + ErrBadValidatorAddr = sdkerrors.Register(ModuleName, 2, "validator address is invalid") + ErrNoValidatorFound = sdkerrors.Register(ModuleName, 3, "validator does not exist") + ErrValidatorOwnerExists = sdkerrors.Register(ModuleName, 4, "validator already exist for this operator address; must use new validator operator address") + ErrValidatorPubKeyExists = sdkerrors.Register(ModuleName, 5, "validator already exist for this pubkey; must use new validator pubkey") + ErrValidatorPubKeyTypeNotSupported = sdkerrors.Register(ModuleName, 6, "validator pubkey type is not supported") + ErrValidatorJailed = sdkerrors.Register(ModuleName, 7, "validator for this address is currently jailed") + ErrBadRemoveValidator = sdkerrors.Register(ModuleName, 8, "failed to remove validator") + ErrCommissionNegative = sdkerrors.Register(ModuleName, 9, "commission must be positive") + ErrCommissionHuge = sdkerrors.Register(ModuleName, 10, "commission cannot be more than 100%") + ErrCommissionGTMaxRate = sdkerrors.Register(ModuleName, 11, "commission cannot be more than the max rate") + ErrCommissionUpdateTime = sdkerrors.Register(ModuleName, 12, "commission cannot be changed more than once in 24h") + ErrCommissionChangeRateNegative = sdkerrors.Register(ModuleName, 13, "commission change rate must be positive") + ErrCommissionChangeRateGTMaxRate = sdkerrors.Register(ModuleName, 14, "commission change rate cannot be more than the max rate") + ErrCommissionGTMaxChangeRate = sdkerrors.Register(ModuleName, 15, "commission cannot be changed more than max change rate") + ErrSelfDelegationBelowMinimum = sdkerrors.Register(ModuleName, 16, "validator's self delegation must be greater than their minimum self delegation") + ErrMinSelfDelegationInvalid = sdkerrors.Register(ModuleName, 17, "minimum self delegation must be a positive integer") + ErrMinSelfDelegationDecreased = sdkerrors.Register(ModuleName, 18, "minimum self delegation cannot be decrease") + ErrEmptyDelegatorAddr = sdkerrors.Register(ModuleName, 19, "empty delegator address") + ErrBadDenom = sdkerrors.Register(ModuleName, 20, "invalid coin denomination") + ErrBadDelegationAddr = sdkerrors.Register(ModuleName, 21, "invalid address for (address, validator) tuple") + ErrBadDelegationAmount = sdkerrors.Register(ModuleName, 22, "invalid delegation amount") + ErrNoDelegation = sdkerrors.Register(ModuleName, 23, "no delegation for (address, validator) tuple") + ErrBadDelegatorAddr = sdkerrors.Register(ModuleName, 24, "delegator does not exist with address") + ErrNoDelegatorForAddress = sdkerrors.Register(ModuleName, 25, "delegator does not contain delegation") + ErrInsufficientShares = sdkerrors.Register(ModuleName, 26, "insufficient delegation shares") + ErrDelegationValidatorEmpty = sdkerrors.Register(ModuleName, 27, "cannot delegate to an empty validator") + ErrNotEnoughDelegationShares = sdkerrors.Register(ModuleName, 28, "not enough delegation shares") + ErrBadSharesAmount = sdkerrors.Register(ModuleName, 29, "invalid shares amount") + ErrBadSharesPercent = sdkerrors.Register(ModuleName, 30, "Invalid shares percent") + ErrNotMature = sdkerrors.Register(ModuleName, 31, "entry not mature") + ErrNoUnbondingDelegation = sdkerrors.Register(ModuleName, 32, "no unbonding delegation found") + ErrMaxUnbondingDelegationEntries = sdkerrors.Register(ModuleName, 33, "too many unbonding delegation entries for (delegator, validator) tuple") + ErrBadRedelegationAddr = sdkerrors.Register(ModuleName, 34, "invalid address for (address, src-validator, dst-validator) tuple") + ErrNoRedelegation = sdkerrors.Register(ModuleName, 35, "no redelegation found") + ErrSelfRedelegation = sdkerrors.Register(ModuleName, 36, "cannot redelegate to the same validator") + ErrTinyRedelegationAmount = sdkerrors.Register(ModuleName, 37, "too few tokens to redelegate (truncates to zero tokens)") + ErrBadRedelegationDst = sdkerrors.Register(ModuleName, 38, "redelegation destination validator not found") + ErrTransitiveRedelegation = sdkerrors.Register(ModuleName, 39, "redelegation to this validator already in progress; first redelegation to this validator must complete before next redelegation") + ErrMaxRedelegationEntries = sdkerrors.Register(ModuleName, 40, "too many redelegation entries for (delegator, src-validator, dst-validator) tuple") + ErrDelegatorShareExRateInvalid = sdkerrors.Register(ModuleName, 41, "cannot delegate to validators with invalid (zero) ex-rate") + ErrBothShareMsgsGiven = sdkerrors.Register(ModuleName, 42, "both shares amount and shares percent provided") + ErrNeitherShareMsgsGiven = sdkerrors.Register(ModuleName, 43, "neither shares amount nor shares percent provided") + ErrInvalidHistoricalInfo = sdkerrors.Register(ModuleName, 44, "invalid historical info") + ErrNoHistoricalInfo = sdkerrors.Register(ModuleName, 45, "no historical info found") ) - -//validator -func ErrNilValidatorAddr(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidInput, "validator address is nil") -} - -func ErrBadValidatorAddr(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidAddress, "validator address is invalid") -} - -func ErrNoValidatorFound(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidValidator, "validator does not exist for that address") -} - -func ErrValidatorOwnerExists(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidValidator, "validator already exist for this operator address, must use new validator operator address") -} - -func ErrValidatorPubKeyExists(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidValidator, "validator already exist for this pubkey, must use new validator pubkey") -} - -func ErrValidatorPubKeyTypeNotSupported(codespace sdk.CodespaceType, keyType string, supportedTypes []string) sdk.Error { - msg := fmt.Sprintf("validator pubkey type %s is not supported, must use %s", keyType, strings.Join(supportedTypes, ",")) - return sdk.NewError(codespace, CodeInvalidValidator, msg) -} - -func ErrValidatorJailed(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidValidator, "validator for this address is currently jailed") -} - -func ErrBadRemoveValidator(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidValidator, "error removing validator") -} - -func ErrDescriptionLength(codespace sdk.CodespaceType, descriptor string, got, max int) sdk.Error { - msg := fmt.Sprintf("bad description length for %v, got length %v, max is %v", descriptor, got, max) - return sdk.NewError(codespace, CodeInvalidValidator, msg) -} - -func ErrCommissionNegative(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidValidator, "commission must be positive") -} - -func ErrCommissionHuge(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidValidator, "commission cannot be more than 100%") -} - -func ErrCommissionGTMaxRate(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidValidator, "commission cannot be more than the max rate") -} - -func ErrCommissionUpdateTime(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidValidator, "commission cannot be changed more than once in 24h") -} - -func ErrCommissionChangeRateNegative(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidValidator, "commission change rate must be positive") -} - -func ErrCommissionChangeRateGTMaxRate(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidValidator, "commission change rate cannot be more than the max rate") -} - -func ErrCommissionGTMaxChangeRate(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidValidator, "commission cannot be changed more than max change rate") -} - -func ErrSelfDelegationBelowMinimum(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidValidator, "validator's self delegation must be greater than their minimum self delegation") -} - -func ErrMinSelfDelegationInvalid(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidValidator, "minimum self delegation must be a positive integer") -} - -func ErrMinSelfDelegationDecreased(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidValidator, "minimum self delegation cannot be decrease") -} - -func ErrNilDelegatorAddr(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidInput, "delegator address is nil") -} - -func ErrBadDenom(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidDelegation, "invalid coin denomination") -} - -func ErrBadDelegationAddr(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidInput, "unexpected address length for this (address, validator) pair") -} - -func ErrBadDelegationAmount(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidDelegation, "amount must be > 0") -} - -func ErrNoDelegation(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidDelegation, "no delegation for this (address, validator) pair") -} - -func ErrBadDelegatorAddr(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidDelegation, "delegator does not exist for that address") -} - -func ErrNoDelegatorForAddress(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidDelegation, "delegator does not contain this delegation") -} - -func ErrInsufficientShares(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidDelegation, "insufficient delegation shares") -} - -func ErrDelegationValidatorEmpty(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidDelegation, "cannot delegate to an empty validator") -} - -func ErrNotEnoughDelegationShares(codespace sdk.CodespaceType, shares string) sdk.Error { - return sdk.NewError(codespace, CodeInvalidDelegation, fmt.Sprintf("not enough shares only have %v", shares)) -} - -func ErrBadSharesAmount(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidDelegation, "shares must be > 0") -} - -func ErrBadSharesPercent(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidDelegation, "shares percent must be >0 and <=1") -} - -func ErrNotMature(codespace sdk.CodespaceType, operation, descriptor string, got, min time.Time) sdk.Error { - msg := fmt.Sprintf("%v is not mature requires a min %v of %v, currently it is %v", - operation, descriptor, got, min) - return sdk.NewError(codespace, CodeUnauthorized, msg) -} - -func ErrNoUnbondingDelegation(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidDelegation, "no unbonding delegation found") -} - -func ErrMaxUnbondingDelegationEntries(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidDelegation, - "too many unbonding delegation entries in this delegator/validator duo, please wait for some entries to mature") -} - -func ErrBadRedelegationAddr(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidInput, "unexpected address length for this (address, srcValidator, dstValidator) tuple") -} - -func ErrNoRedelegation(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidDelegation, "no redelegation found") -} - -func ErrSelfRedelegation(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidDelegation, "cannot redelegate to the same validator") -} - -func ErrVerySmallRedelegation(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidDelegation, "too few tokens to redelegate, truncates to zero tokens") -} - -func ErrBadRedelegationDst(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidDelegation, "redelegation validator not found") -} - -func ErrTransitiveRedelegation(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidDelegation, - "redelegation to this validator already in progress, first redelegation to this validator must complete before next redelegation") -} - -func ErrMaxRedelegationEntries(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidDelegation, - "too many redelegation entries in this delegator/src-validator/dst-validator trio, please wait for some entries to mature") -} - -func ErrDelegatorShareExRateInvalid(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidDelegation, - "cannot delegate to validators with invalid (zero) ex-rate") -} - -func ErrBothShareMsgsGiven(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidInput, "both shares amount and shares percent provided") -} - -func ErrNeitherShareMsgsGiven(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidInput, "neither shares amount nor shares percent provided") -} - -func ErrMissingSignature(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidValidator, "missing signature") -} - -func ErrInvalidHistoricalInfo(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidHistoricalInfo, "invalid historical info") -} - -func ErrNoHistoricalInfo(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidHistoricalInfo, "no historical info found") -} diff --git a/x/staking/types/expected_keepers.go b/x/staking/types/expected_keepers.go index 8f346a71c4cb..5e98f0abbed0 100644 --- a/x/staking/types/expected_keepers.go +++ b/x/staking/types/expected_keepers.go @@ -29,11 +29,11 @@ type SupplyKeeper interface { // TODO remove with genesis 2-phases refactor https://github.com/cosmos/cosmos-sdk/issues/2862 SetModuleAccount(sdk.Context, supplyexported.ModuleAccountI) - SendCoinsFromModuleToModule(ctx sdk.Context, senderPool, recipientPool string, amt sdk.Coins) sdk.Error - UndelegateCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) sdk.Error - DelegateCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) sdk.Error + SendCoinsFromModuleToModule(ctx sdk.Context, senderPool, recipientPool string, amt sdk.Coins) error + UndelegateCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error + DelegateCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error - BurnCoins(ctx sdk.Context, name string, amt sdk.Coins) sdk.Error + BurnCoins(ctx sdk.Context, name string, amt sdk.Coins) error } // ValidatorSet expected properties for the set of all validators (noalias) diff --git a/x/staking/types/historical_info.go b/x/staking/types/historical_info.go index 8fae88f07f4e..78db1e7dd4a9 100644 --- a/x/staking/types/historical_info.go +++ b/x/staking/types/historical_info.go @@ -48,10 +48,10 @@ func UnmarshalHistoricalInfo(cdc *codec.Codec, value []byte) (hi HistoricalInfo, // ValidateBasic will ensure HistoricalInfo is not nil and sorted func ValidateBasic(hi HistoricalInfo) error { if len(hi.ValSet) == 0 { - return sdkerrors.Wrap(ErrInvalidHistoricalInfo(DefaultCodespace), "ValidatorSer is nil") + return sdkerrors.Wrap(ErrInvalidHistoricalInfo, "validator set is empty") } if !sort.IsSorted(Validators(hi.ValSet)) { - return sdkerrors.Wrap(ErrInvalidHistoricalInfo(DefaultCodespace), "ValidatorSet is not sorted by address") + return sdkerrors.Wrap(ErrInvalidHistoricalInfo, "validator set is not sorted by address") } return nil } diff --git a/x/staking/types/msg.go b/x/staking/types/msg.go index fa44090ac747..8b47cfec443c 100644 --- a/x/staking/types/msg.go +++ b/x/staking/types/msg.go @@ -8,6 +8,7 @@ import ( yaml "gopkg.in/yaml.v2" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) // ensure Msg interface compliance at compile time @@ -151,34 +152,34 @@ func (msg MsgCreateValidator) GetSignBytes() []byte { } // ValidateBasic implements the sdk.Msg interface. -func (msg MsgCreateValidator) ValidateBasic() sdk.Error { +func (msg MsgCreateValidator) ValidateBasic() error { // note that unmarshaling from bech32 ensures either empty or valid if msg.DelegatorAddress.Empty() { - return ErrNilDelegatorAddr(DefaultCodespace) + return ErrEmptyDelegatorAddr } if msg.ValidatorAddress.Empty() { - return ErrNilValidatorAddr(DefaultCodespace) + return ErrEmptyValidatorAddr } if !sdk.AccAddress(msg.ValidatorAddress).Equals(msg.DelegatorAddress) { - return ErrBadValidatorAddr(DefaultCodespace) + return ErrBadValidatorAddr } if !msg.Value.Amount.IsPositive() { - return ErrBadDelegationAmount(DefaultCodespace) + return ErrBadDelegationAmount } if msg.Description == (Description{}) { - return sdk.NewError(DefaultCodespace, CodeInvalidInput, "description must be included") + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "empty description") } if msg.Commission == (CommissionRates{}) { - return sdk.NewError(DefaultCodespace, CodeInvalidInput, "commission must be included") + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "empty commission") } if err := msg.Commission.Validate(); err != nil { return err } if !msg.MinSelfDelegation.IsPositive() { - return ErrMinSelfDelegationInvalid(DefaultCodespace) + return ErrMinSelfDelegationInvalid } if msg.Value.Amount.LT(msg.MinSelfDelegation) { - return ErrSelfDelegationBelowMinimum(DefaultCodespace) + return ErrSelfDelegationBelowMinimum } return nil @@ -226,22 +227,19 @@ func (msg MsgEditValidator) GetSignBytes() []byte { } // ValidateBasic implements the sdk.Msg interface. -func (msg MsgEditValidator) ValidateBasic() sdk.Error { +func (msg MsgEditValidator) ValidateBasic() error { if msg.ValidatorAddress.Empty() { - return sdk.NewError(DefaultCodespace, CodeInvalidInput, "nil validator address") + return ErrEmptyValidatorAddr } - if msg.Description == (Description{}) { - return sdk.NewError(DefaultCodespace, CodeInvalidInput, "transaction must include some information to modify") + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "empty description") } - if msg.MinSelfDelegation != nil && !msg.MinSelfDelegation.IsPositive() { - return ErrMinSelfDelegationInvalid(DefaultCodespace) + return ErrMinSelfDelegationInvalid } - if msg.CommissionRate != nil { if msg.CommissionRate.GT(sdk.OneDec()) || msg.CommissionRate.IsNegative() { - return sdk.NewError(DefaultCodespace, CodeInvalidInput, "commission rate must be between 0 and 1, inclusive") + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "commission rate must be between 0 and 1 (inclusive)") } } @@ -282,15 +280,15 @@ func (msg MsgDelegate) GetSignBytes() []byte { } // ValidateBasic implements the sdk.Msg interface. -func (msg MsgDelegate) ValidateBasic() sdk.Error { +func (msg MsgDelegate) ValidateBasic() error { if msg.DelegatorAddress.Empty() { - return ErrNilDelegatorAddr(DefaultCodespace) + return ErrEmptyDelegatorAddr } if msg.ValidatorAddress.Empty() { - return ErrNilValidatorAddr(DefaultCodespace) + return ErrEmptyValidatorAddr } if !msg.Amount.Amount.IsPositive() { - return ErrBadDelegationAmount(DefaultCodespace) + return ErrBadDelegationAmount } return nil } @@ -335,18 +333,18 @@ func (msg MsgBeginRedelegate) GetSignBytes() []byte { } // ValidateBasic implements the sdk.Msg interface. -func (msg MsgBeginRedelegate) ValidateBasic() sdk.Error { +func (msg MsgBeginRedelegate) ValidateBasic() error { if msg.DelegatorAddress.Empty() { - return ErrNilDelegatorAddr(DefaultCodespace) + return ErrEmptyDelegatorAddr } if msg.ValidatorSrcAddress.Empty() { - return ErrNilValidatorAddr(DefaultCodespace) + return ErrEmptyValidatorAddr } if msg.ValidatorDstAddress.Empty() { - return ErrNilValidatorAddr(DefaultCodespace) + return ErrEmptyValidatorAddr } if !msg.Amount.Amount.IsPositive() { - return ErrBadSharesAmount(DefaultCodespace) + return ErrBadSharesAmount } return nil } @@ -383,15 +381,15 @@ func (msg MsgUndelegate) GetSignBytes() []byte { } // ValidateBasic implements the sdk.Msg interface. -func (msg MsgUndelegate) ValidateBasic() sdk.Error { +func (msg MsgUndelegate) ValidateBasic() error { if msg.DelegatorAddress.Empty() { - return ErrNilDelegatorAddr(DefaultCodespace) + return ErrEmptyDelegatorAddr } if msg.ValidatorAddress.Empty() { - return ErrNilValidatorAddr(DefaultCodespace) + return ErrEmptyValidatorAddr } if !msg.Amount.Amount.IsPositive() { - return ErrBadSharesAmount(DefaultCodespace) + return ErrBadSharesAmount } return nil } diff --git a/x/staking/types/validator.go b/x/staking/types/validator.go index 37e6cbc02575..2ac2903dcf0b 100644 --- a/x/staking/types/validator.go +++ b/x/staking/types/validator.go @@ -14,6 +14,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/staking/exported" ) @@ -304,7 +305,7 @@ func NewDescription(moniker, identity, website, securityContact, details string) // UpdateDescription updates the fields of a given description. An error is // returned if the resulting description contains an invalid length. -func (d Description) UpdateDescription(d2 Description) (Description, sdk.Error) { +func (d Description) UpdateDescription(d2 Description) (Description, error) { if d2.Moniker == DoNotModifyDesc { d2.Moniker = d.Moniker } @@ -331,21 +332,21 @@ func (d Description) UpdateDescription(d2 Description) (Description, sdk.Error) } // EnsureLength ensures the length of a validator's description. -func (d Description) EnsureLength() (Description, sdk.Error) { +func (d Description) EnsureLength() (Description, error) { if len(d.Moniker) > MaxMonikerLength { - return d, ErrDescriptionLength(DefaultCodespace, "moniker", len(d.Moniker), MaxMonikerLength) + return d, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid moniker length; got: %d, max: %d", len(d.Moniker), MaxMonikerLength) } if len(d.Identity) > MaxIdentityLength { - return d, ErrDescriptionLength(DefaultCodespace, "identity", len(d.Identity), MaxIdentityLength) + return d, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid identity length; got: %d, max: %d", len(d.Identity), MaxIdentityLength) } if len(d.Website) > MaxWebsiteLength { - return d, ErrDescriptionLength(DefaultCodespace, "website", len(d.Website), MaxWebsiteLength) + return d, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid website length; got: %d, max: %d", len(d.Website), MaxWebsiteLength) } if len(d.SecurityContact) > MaxSecurityContactLength { - return d, ErrDescriptionLength(DefaultCodespace, "security contact", len(d.SecurityContact), MaxSecurityContactLength) + return d, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid security contact length; got: %d, max: %d", len(d.SecurityContact), MaxSecurityContactLength) } if len(d.Details) > MaxDetailsLength { - return d, ErrDescriptionLength(DefaultCodespace, "details", len(d.Details), MaxDetailsLength) + return d, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid details length; got: %d, max: %d", len(d.Details), MaxDetailsLength) } return d, nil @@ -371,7 +372,7 @@ func (v Validator) ABCIValidatorUpdateZero() abci.ValidatorUpdate { // SetInitialCommission attempts to set a validator's initial commission. An // error is returned if the commission is invalid. -func (v Validator) SetInitialCommission(commission Commission) (Validator, sdk.Error) { +func (v Validator) SetInitialCommission(commission Commission) (Validator, error) { if err := commission.Validate(); err != nil { return v, err } @@ -405,9 +406,9 @@ func (v Validator) TokensFromSharesRoundUp(shares sdk.Dec) sdk.Dec { // SharesFromTokens returns the shares of a delegation given a bond amount. It // returns an error if the validator has no tokens. -func (v Validator) SharesFromTokens(amt sdk.Int) (sdk.Dec, sdk.Error) { +func (v Validator) SharesFromTokens(amt sdk.Int) (sdk.Dec, error) { if v.Tokens.IsZero() { - return sdk.ZeroDec(), ErrInsufficientShares(DefaultCodespace) + return sdk.ZeroDec(), ErrInsufficientShares } return v.GetDelegatorShares().MulInt(amt).QuoInt(v.GetTokens()), nil @@ -415,9 +416,9 @@ func (v Validator) SharesFromTokens(amt sdk.Int) (sdk.Dec, sdk.Error) { // SharesFromTokensTruncated returns the truncated shares of a delegation given // a bond amount. It returns an error if the validator has no tokens. -func (v Validator) SharesFromTokensTruncated(amt sdk.Int) (sdk.Dec, sdk.Error) { +func (v Validator) SharesFromTokensTruncated(amt sdk.Int) (sdk.Dec, error) { if v.Tokens.IsZero() { - return sdk.ZeroDec(), ErrInsufficientShares(DefaultCodespace) + return sdk.ZeroDec(), ErrInsufficientShares } return v.GetDelegatorShares().MulInt(amt).QuoTruncate(v.GetTokens().ToDec()), nil diff --git a/x/supply/alias.go b/x/supply/alias.go index 9bc7f5f13530..1138f7c5eee2 100644 --- a/x/supply/alias.go +++ b/x/supply/alias.go @@ -38,8 +38,7 @@ var ( DefaultSupply = types.DefaultSupply // variable aliases - DefaultCodespace = keeper.DefaultCodespace - ModuleCdc = types.ModuleCdc + ModuleCdc = types.ModuleCdc ) type ( diff --git a/x/supply/internal/keeper/bank.go b/x/supply/internal/keeper/bank.go index 60efbc4c3df5..9117286aaeb6 100644 --- a/x/supply/internal/keeper/bank.go +++ b/x/supply/internal/keeper/bank.go @@ -4,103 +4,110 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/supply/internal/types" ) -// SendCoinsFromModuleToAccount transfers coins from a ModuleAccount to an AccAddress -func (k Keeper) SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, - recipientAddr sdk.AccAddress, amt sdk.Coins) sdk.Error { +// SendCoinsFromModuleToAccount transfers coins from a ModuleAccount to an AccAddress. +// It will panic if the module account does not exist. +func (k Keeper) SendCoinsFromModuleToAccount( + ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins, +) error { senderAddr := k.GetModuleAddress(senderModule) if senderAddr == nil { - return sdk.ErrUnknownAddress(fmt.Sprintf("module account %s does not exist", senderModule)) + panic(sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", senderModule)) } return k.bk.SendCoins(ctx, senderAddr, recipientAddr, amt) } -// SendCoinsFromModuleToModule transfers coins from a ModuleAccount to another -func (k Keeper) SendCoinsFromModuleToModule(ctx sdk.Context, senderModule, recipientModule string, amt sdk.Coins) sdk.Error { +// SendCoinsFromModuleToModule transfers coins from a ModuleAccount to another. +// It will panic if either module account does not exist. +func (k Keeper) SendCoinsFromModuleToModule( + ctx sdk.Context, senderModule, recipientModule string, amt sdk.Coins, +) error { senderAddr := k.GetModuleAddress(senderModule) if senderAddr == nil { - return sdk.ErrUnknownAddress(fmt.Sprintf("module account %s does not exist", senderModule)) + panic(sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", senderModule)) } - // create the account if it doesn't yet exist recipientAcc := k.GetModuleAccount(ctx, recipientModule) if recipientAcc == nil { - panic(fmt.Sprintf("module account %s isn't able to be created", recipientModule)) + panic(sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", recipientModule)) } return k.bk.SendCoins(ctx, senderAddr, recipientAcc.GetAddress(), amt) } -// SendCoinsFromAccountToModule transfers coins from an AccAddress to a ModuleAccount -func (k Keeper) SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, - recipientModule string, amt sdk.Coins) sdk.Error { +// SendCoinsFromAccountToModule transfers coins from an AccAddress to a ModuleAccount. +// It will panic if the module account does not exist. +func (k Keeper) SendCoinsFromAccountToModule( + ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins, +) error { - // create the account if it doesn't yet exist recipientAcc := k.GetModuleAccount(ctx, recipientModule) if recipientAcc == nil { - panic(fmt.Sprintf("module account %s isn't able to be created", recipientModule)) + panic(sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", recipientModule)) } return k.bk.SendCoins(ctx, senderAddr, recipientAcc.GetAddress(), amt) } -// DelegateCoinsFromAccountToModule delegates coins and transfers -// them from a delegator account to a module account -func (k Keeper) DelegateCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, - recipientModule string, amt sdk.Coins) sdk.Error { +// DelegateCoinsFromAccountToModule delegates coins and transfers them from a +// delegator account to a module account. It will panic if the module account +// does not exist or is unauthorized. +func (k Keeper) DelegateCoinsFromAccountToModule( + ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins, +) error { - // create the account if it doesn't yet exist recipientAcc := k.GetModuleAccount(ctx, recipientModule) if recipientAcc == nil { - panic(fmt.Sprintf("module account %s isn't able to be created", recipientModule)) + panic(sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", recipientModule)) } if !recipientAcc.HasPermission(types.Staking) { - panic(fmt.Sprintf("module account %s does not have permissions to receive delegated coins", recipientModule)) + panic(sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "module account %s does not have permissions to receive delegated coins", recipientModule)) } return k.bk.DelegateCoins(ctx, senderAddr, recipientAcc.GetAddress(), amt) } // UndelegateCoinsFromModuleToAccount undelegates the unbonding coins and transfers -// them from a module account to the delegator account -func (k Keeper) UndelegateCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, - recipientAddr sdk.AccAddress, amt sdk.Coins) sdk.Error { +// them from a module account to the delegator account. It will panic if the +// module account does not exist or is unauthorized. +func (k Keeper) UndelegateCoinsFromModuleToAccount( + ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins, +) error { acc := k.GetModuleAccount(ctx, senderModule) if acc == nil { - return sdk.ErrUnknownAddress(fmt.Sprintf("module account %s does not exist", senderModule)) + panic(sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", senderModule)) } if !acc.HasPermission(types.Staking) { - panic(fmt.Sprintf("module account %s does not have permissions to undelegate coins", senderModule)) + panic(sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "module account %s does not have permissions to undelegate coins", senderModule)) } return k.bk.UndelegateCoins(ctx, acc.GetAddress(), recipientAddr, amt) } // MintCoins creates new coins from thin air and adds it to the module account. -// Panics if the name maps to a non-minter module account or if the amount is invalid. -func (k Keeper) MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) sdk.Error { - - // create the account if it doesn't yet exist +// It will panic if the module account does not exist or is unauthorized. +func (k Keeper) MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error { acc := k.GetModuleAccount(ctx, moduleName) if acc == nil { - return sdk.ErrUnknownAddress(fmt.Sprintf("module account %s does not exist", moduleName)) + panic(sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", moduleName)) } if !acc.HasPermission(types.Minter) { - panic(fmt.Sprintf("module account %s does not have permissions to mint tokens", moduleName)) + panic(sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "module account %s does not have permissions to mint tokens", moduleName)) } _, err := k.bk.AddCoins(ctx, acc.GetAddress(), amt) if err != nil { - panic(err) + return err } // update total supply @@ -116,22 +123,20 @@ func (k Keeper) MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) sdk } // BurnCoins burns coins deletes coins from the balance of the module account. -// Panics if the name maps to a non-burner module account or if the amount is invalid. -func (k Keeper) BurnCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) sdk.Error { - - // create the account if it doesn't yet exist +// It will panic if the module account does not exist or is unauthorized. +func (k Keeper) BurnCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error { acc := k.GetModuleAccount(ctx, moduleName) if acc == nil { - return sdk.ErrUnknownAddress(fmt.Sprintf("module account %s does not exist", moduleName)) + panic(sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", moduleName)) } if !acc.HasPermission(types.Burner) { - panic(fmt.Sprintf("module account %s does not have permissions to burn tokens", moduleName)) + panic(sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "module account %s does not have permissions to burn tokens", moduleName)) } _, err := k.bk.SubtractCoins(ctx, acc.GetAddress(), amt) if err != nil { - panic(err) + return err } // update total supply diff --git a/x/supply/internal/keeper/bank_test.go b/x/supply/internal/keeper/bank_test.go index f0cb48f1fc1f..bdd0a9430a1d 100644 --- a/x/supply/internal/keeper/bank_test.go +++ b/x/supply/internal/keeper/bank_test.go @@ -48,15 +48,17 @@ func TestSendCoins(t *testing.T) { keeper.SetModuleAccount(ctx, burnerAcc) ak.SetAccount(ctx, baseAcc) - err = keeper.SendCoinsFromModuleToModule(ctx, "", holderAcc.GetName(), initCoins) - require.Error(t, err) + require.Panics(t, func() { + keeper.SendCoinsFromModuleToModule(ctx, "", holderAcc.GetName(), initCoins) + }) require.Panics(t, func() { keeper.SendCoinsFromModuleToModule(ctx, types.Burner, "", initCoins) }) - err = keeper.SendCoinsFromModuleToAccount(ctx, "", baseAcc.GetAddress(), initCoins) - require.Error(t, err) + require.Panics(t, func() { + keeper.SendCoinsFromModuleToAccount(ctx, "", baseAcc.GetAddress(), initCoins) + }) err = keeper.SendCoinsFromModuleToAccount(ctx, holderAcc.GetName(), baseAcc.GetAddress(), initCoins.Add(initCoins)) require.Error(t, err) @@ -90,13 +92,14 @@ func TestMintCoins(t *testing.T) { initialSupply := keeper.GetSupply(ctx) - require.Error(t, keeper.MintCoins(ctx, "", initCoins), "no module account") + require.Panics(t, func() { keeper.MintCoins(ctx, "", initCoins) }, "no module account") require.Panics(t, func() { keeper.MintCoins(ctx, types.Burner, initCoins) }, "invalid permission") - require.Panics(t, func() { keeper.MintCoins(ctx, types.Minter, sdk.Coins{sdk.Coin{"denom", sdk.NewInt(-10)}}) }, "insufficient coins") //nolint + err := keeper.MintCoins(ctx, types.Minter, sdk.Coins{sdk.Coin{Denom: "denom", Amount: sdk.NewInt(-10)}}) + require.Error(t, err, "insufficient coins") require.Panics(t, func() { keeper.MintCoins(ctx, randomPerm, initCoins) }) - err := keeper.MintCoins(ctx, types.Minter, initCoins) + err = keeper.MintCoins(ctx, types.Minter, initCoins) require.NoError(t, err) require.Equal(t, initCoins, getCoinsByName(ctx, keeper, ak, types.Minter)) require.Equal(t, initialSupply.GetTotal().Add(initCoins), keeper.GetSupply(ctx).GetTotal()) @@ -125,12 +128,13 @@ func TestBurnCoins(t *testing.T) { initialSupply = initialSupply.Inflate(initCoins) keeper.SetSupply(ctx, initialSupply) - require.Error(t, keeper.BurnCoins(ctx, "", initCoins), "no module account") + require.Panics(t, func() { keeper.BurnCoins(ctx, "", initCoins) }, "no module account") require.Panics(t, func() { keeper.BurnCoins(ctx, types.Minter, initCoins) }, "invalid permission") require.Panics(t, func() { keeper.BurnCoins(ctx, randomPerm, initialSupply.GetTotal()) }, "random permission") - require.Panics(t, func() { keeper.BurnCoins(ctx, types.Burner, initialSupply.GetTotal()) }, "insufficient coins") + err := keeper.BurnCoins(ctx, types.Burner, initialSupply.GetTotal()) + require.Error(t, err, "insufficient coins") - err := keeper.BurnCoins(ctx, types.Burner, initCoins) + err = keeper.BurnCoins(ctx, types.Burner, initCoins) require.NoError(t, err) require.Equal(t, sdk.Coins(nil), getCoinsByName(ctx, keeper, ak, types.Burner)) require.Equal(t, initialSupply.GetTotal().Sub(initCoins), keeper.GetSupply(ctx).GetTotal()) diff --git a/x/supply/internal/keeper/key.go b/x/supply/internal/keeper/key.go index 6428d5445c05..65a23382961f 100644 --- a/x/supply/internal/keeper/key.go +++ b/x/supply/internal/keeper/key.go @@ -1,13 +1,5 @@ package keeper -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/supply/internal/types" -) - -// DefaultCodespace from the supply module -var DefaultCodespace sdk.CodespaceType = types.ModuleName - // Keys for supply store // Items are stored with the following key: values // diff --git a/x/supply/internal/keeper/querier.go b/x/supply/internal/keeper/querier.go index 9b74a45ccbe6..093edd2c6bea 100644 --- a/x/supply/internal/keeper/querier.go +++ b/x/supply/internal/keeper/querier.go @@ -1,18 +1,17 @@ package keeper import ( - "fmt" - abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/client" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/supply/internal/types" ) // NewQuerier creates a querier for supply REST endpoints func NewQuerier(k Keeper) sdk.Querier { - return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err sdk.Error) { + return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) { switch path[0] { case types.QueryTotalSupply: @@ -22,17 +21,17 @@ func NewQuerier(k Keeper) sdk.Querier { return querySupplyOf(ctx, req, k) default: - return nil, sdk.ErrUnknownRequest("unknown supply query endpoint") + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown %s query endpoint: %s", types.ModuleName, path[0]) } } } -func queryTotalSupply(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryTotalSupply(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryTotalSupplyParams err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } totalSupply := k.GetSupply(ctx).GetTotal() @@ -46,25 +45,25 @@ func queryTotalSupply(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, res, err := totalSupply.MarshalJSON() if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to JSON marshal result: %s", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil } -func querySupplyOf(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func querySupplyOf(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QuerySupplyOfParams err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } supply := k.GetSupply(ctx).GetTotal().AmountOf(params.Denom) res, err := supply.MarshalJSON() if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to JSON marshal result: %s", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil diff --git a/x/supply/internal/types/expected_keepers.go b/x/supply/internal/types/expected_keepers.go index bf0cc6ec328a..3ad1d8b13ce4 100644 --- a/x/supply/internal/types/expected_keepers.go +++ b/x/supply/internal/types/expected_keepers.go @@ -15,10 +15,10 @@ type AccountKeeper interface { // BankKeeper defines the expected bank keeper (noalias) type BankKeeper interface { - SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) sdk.Error - DelegateCoins(ctx sdk.Context, fromAdd, toAddr sdk.AccAddress, amt sdk.Coins) sdk.Error - UndelegateCoins(ctx sdk.Context, fromAddr, toAddr sdk.AccAddress, amt sdk.Coins) sdk.Error + SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error + DelegateCoins(ctx sdk.Context, fromAdd, toAddr sdk.AccAddress, amt sdk.Coins) error + UndelegateCoins(ctx sdk.Context, fromAddr, toAddr sdk.AccAddress, amt sdk.Coins) error - SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Error) - AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Error) + SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, error) + AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, error) } diff --git a/x/upgrade/abci_test.go b/x/upgrade/abci_test.go index edc71590dc0f..34c8944e0017 100644 --- a/x/upgrade/abci_test.go +++ b/x/upgrade/abci_test.go @@ -1,11 +1,13 @@ package upgrade_test import ( + "errors" "testing" "time" "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/x/gov" "github.com/cosmos/cosmos-sdk/x/upgrade" @@ -37,25 +39,25 @@ func (s *TestSuite) SetupTest() { func (s *TestSuite) TestRequireName() { err := s.handler(s.ctx, upgrade.SoftwareUpgradeProposal{Title: "prop", Plan: upgrade.Plan{}}) s.Require().NotNil(err) - s.Require().Equal(sdk.CodeUnknownRequest, err.Code()) + s.Require().True(errors.Is(sdkerrors.ErrInvalidRequest, err), err) } func (s *TestSuite) TestRequireFutureTime() { err := s.handler(s.ctx, upgrade.SoftwareUpgradeProposal{Title: "prop", Plan: upgrade.Plan{Name: "test", Time: s.ctx.BlockHeader().Time}}) s.Require().NotNil(err) - s.Require().Equal(sdk.CodeUnknownRequest, err.Code()) + s.Require().True(errors.Is(sdkerrors.ErrInvalidRequest, err), err) } func (s *TestSuite) TestRequireFutureBlock() { err := s.handler(s.ctx, upgrade.SoftwareUpgradeProposal{Title: "prop", Plan: upgrade.Plan{Name: "test", Height: s.ctx.BlockHeight()}}) s.Require().NotNil(err) - s.Require().Equal(sdk.CodeUnknownRequest, err.Code()) + s.Require().True(errors.Is(sdkerrors.ErrInvalidRequest, err), err) } func (s *TestSuite) TestCantSetBothTimeAndHeight() { err := s.handler(s.ctx, upgrade.SoftwareUpgradeProposal{Title: "prop", Plan: upgrade.Plan{Name: "test", Time: time.Now(), Height: s.ctx.BlockHeight() + 1}}) s.Require().NotNil(err) - s.Require().Equal(sdk.CodeUnknownRequest, err.Code()) + s.Require().True(errors.Is(sdkerrors.ErrInvalidRequest, err), err) } func (s *TestSuite) TestDoTimeUpgrade() { @@ -156,7 +158,7 @@ func (s *TestSuite) TestCantApplySameUpgradeTwice() { s.T().Log("Verify an upgrade named \"test\" can't be scheduled twice") err := s.handler(s.ctx, upgrade.SoftwareUpgradeProposal{Title: "prop", Plan: upgrade.Plan{Name: "test", Time: time.Now()}}) s.Require().NotNil(err) - s.Require().Equal(sdk.CodeUnknownRequest, err.Code()) + s.Require().True(errors.Is(sdkerrors.ErrInvalidRequest, err), err) } func (s *TestSuite) TestNoSpuriousUpgrades() { diff --git a/x/upgrade/alias.go b/x/upgrade/alias.go index b7324f2c3e41..fe36f23097bc 100644 --- a/x/upgrade/alias.go +++ b/x/upgrade/alias.go @@ -1,10 +1,7 @@ -// nolint -// autogenerated code using github.com/rigelrozanski/multitool -// aliases generated for the following subdirectories: -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/upgrade/internal/types -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/upgrade/internal/keeper package upgrade +// nolint + import ( "github.com/cosmos/cosmos-sdk/x/upgrade/internal/keeper" "github.com/cosmos/cosmos-sdk/x/upgrade/internal/types" @@ -19,7 +16,6 @@ const ( DoneByte = types.DoneByte ProposalTypeSoftwareUpgrade = types.ProposalTypeSoftwareUpgrade ProposalTypeCancelSoftwareUpgrade = types.ProposalTypeCancelSoftwareUpgrade - DefaultCodespace = types.DefaultCodespace QueryCurrent = types.QueryCurrent QueryApplied = types.QueryApplied ) diff --git a/x/upgrade/handler.go b/x/upgrade/handler.go index 925d4e875c9d..8a4a9f89ab10 100644 --- a/x/upgrade/handler.go +++ b/x/upgrade/handler.go @@ -1,9 +1,8 @@ package upgrade import ( - "fmt" - sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" ) @@ -11,7 +10,7 @@ import ( // It enables SoftwareUpgradeProposal to propose an Upgrade, and CancelSoftwareUpgradeProposal // to abort a previously voted upgrade. func NewSoftwareUpgradeProposalHandler(k Keeper) govtypes.Handler { - return func(ctx sdk.Context, content govtypes.Content) sdk.Error { + return func(ctx sdk.Context, content govtypes.Content) error { switch c := content.(type) { case SoftwareUpgradeProposal: return handleSoftwareUpgradeProposal(ctx, k, c) @@ -20,17 +19,16 @@ func NewSoftwareUpgradeProposalHandler(k Keeper) govtypes.Handler { return handleCancelSoftwareUpgradeProposal(ctx, k, c) default: - errMsg := fmt.Sprintf("unrecognized software upgrade proposal content type: %T", c) - return sdk.ErrUnknownRequest(errMsg) + return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized software upgrade proposal content type: %T", c) } } } -func handleSoftwareUpgradeProposal(ctx sdk.Context, k Keeper, p SoftwareUpgradeProposal) sdk.Error { +func handleSoftwareUpgradeProposal(ctx sdk.Context, k Keeper, p SoftwareUpgradeProposal) error { return k.ScheduleUpgrade(ctx, p.Plan) } -func handleCancelSoftwareUpgradeProposal(ctx sdk.Context, k Keeper, p CancelSoftwareUpgradeProposal) sdk.Error { +func handleCancelSoftwareUpgradeProposal(ctx sdk.Context, k Keeper, p CancelSoftwareUpgradeProposal) error { k.ClearUpgradePlan(ctx) return nil } diff --git a/x/upgrade/internal/keeper/keeper.go b/x/upgrade/internal/keeper/keeper.go index bb95ec6eafdb..e0c0823b0842 100644 --- a/x/upgrade/internal/keeper/keeper.go +++ b/x/upgrade/internal/keeper/keeper.go @@ -7,6 +7,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/upgrade/internal/types" "github.com/tendermint/tendermint/libs/log" ) @@ -36,26 +37,27 @@ 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) -func (k Keeper) ScheduleUpgrade(ctx sdk.Context, plan types.Plan) sdk.Error { +func (k Keeper) ScheduleUpgrade(ctx sdk.Context, plan types.Plan) error { if err := plan.ValidateBasic(); err != nil { return err } if !plan.Time.IsZero() { if !plan.Time.After(ctx.BlockHeader().Time) { - return sdk.ErrUnknownRequest("upgrade cannot be scheduled in the past") + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "upgrade cannot be scheduled in the past") } } else if plan.Height <= ctx.BlockHeight() { - return sdk.ErrUnknownRequest("upgrade cannot be scheduled in the past") + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "upgrade cannot be scheduled in the past") } if k.getDoneHeight(ctx, plan.Name) != 0 { - return sdk.ErrUnknownRequest(fmt.Sprintf("upgrade with name %s has already been completed", plan.Name)) + 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) store.Set(types.PlanKey(), bz) + return nil } diff --git a/x/upgrade/internal/keeper/querier.go b/x/upgrade/internal/keeper/querier.go index 291f7bb9d049..164a2340c0a7 100644 --- a/x/upgrade/internal/keeper/querier.go +++ b/x/upgrade/internal/keeper/querier.go @@ -2,16 +2,16 @@ package keeper import ( "encoding/binary" - "fmt" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/upgrade/internal/types" abci "github.com/tendermint/tendermint/abci/types" ) // NewQuerier creates a querier for upgrade cli and REST endpoints func NewQuerier(k Keeper) sdk.Querier { - return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err sdk.Error) { + return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) { switch path[0] { case types.QueryCurrent: @@ -21,38 +21,40 @@ func NewQuerier(k Keeper) sdk.Querier { return queryApplied(ctx, req, k) default: - return nil, sdk.ErrUnknownRequest("unknown supply query endpoint") + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown %s query endpoint: %s", types.ModuleName, path[0]) } } } -func queryCurrent(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryCurrent(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { plan, has := k.GetUpgradePlan(ctx) if !has { - // empty data - client can respond Not Found return nil, nil } + res, err := k.cdc.MarshalJSON(&plan) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to JSON marshal result: %s", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } + return res, nil } -func queryApplied(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryApplied(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryAppliedParams err := k.cdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } applied := k.getDoneHeight(ctx, params.Name) if applied == 0 { - // empty data - client can respond Not Found return nil, nil } + bz := make([]byte, 8) binary.BigEndian.PutUint64(bz, uint64(applied)) + return bz, nil } diff --git a/x/upgrade/internal/types/plan.go b/x/upgrade/internal/types/plan.go index 24fd28b72005..c2b88171e218 100644 --- a/x/upgrade/internal/types/plan.go +++ b/x/upgrade/internal/types/plan.go @@ -6,6 +6,7 @@ import ( "time" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) // Plan specifies information about a planned upgrade and when it should occur @@ -40,19 +41,20 @@ func (p Plan) String() string { } // ValidateBasic does basic validation of a Plan -func (p Plan) ValidateBasic() sdk.Error { +func (p Plan) ValidateBasic() error { if len(p.Name) == 0 { - return sdk.ErrUnknownRequest("name cannot be empty") + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "name cannot be empty") } if p.Height < 0 { - return sdk.ErrUnknownRequest("height cannot be negative") + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "height cannot be negative") } if p.Time.IsZero() && p.Height == 0 { - return sdk.ErrUnknownRequest("must set either time or height") + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "must set either time or height") } if !p.Time.IsZero() && p.Height != 0 { - return sdk.ErrUnknownRequest("cannot set both time and height") + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "cannot set both time and height") } + return nil } diff --git a/x/upgrade/internal/types/proposal.go b/x/upgrade/internal/types/proposal.go index 3dc54f494f60..958c10674645 100644 --- a/x/upgrade/internal/types/proposal.go +++ b/x/upgrade/internal/types/proposal.go @@ -3,14 +3,12 @@ package types import ( "fmt" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/gov" ) const ( - ProposalTypeSoftwareUpgrade string = "SoftwareUpgrade" - ProposalTypeCancelSoftwareUpgrade string = "CancelSoftwareUpgrade" - DefaultCodespace sdk.CodespaceType = "upgrade" + ProposalTypeSoftwareUpgrade string = "SoftwareUpgrade" + ProposalTypeCancelSoftwareUpgrade string = "CancelSoftwareUpgrade" ) // Software Upgrade Proposals @@ -39,11 +37,11 @@ func (sup SoftwareUpgradeProposal) GetTitle() string { return sup.Title } func (sup SoftwareUpgradeProposal) GetDescription() string { return sup.Description } func (sup SoftwareUpgradeProposal) ProposalRoute() string { return RouterKey } func (sup SoftwareUpgradeProposal) ProposalType() string { return ProposalTypeSoftwareUpgrade } -func (sup SoftwareUpgradeProposal) ValidateBasic() sdk.Error { +func (sup SoftwareUpgradeProposal) ValidateBasic() error { if err := sup.Plan.ValidateBasic(); err != nil { return err } - return gov.ValidateAbstract(DefaultCodespace, sup) + return gov.ValidateAbstract(sup) } func (sup SoftwareUpgradeProposal) String() string { @@ -73,8 +71,8 @@ func (sup CancelSoftwareUpgradeProposal) ProposalRoute() string { return Router func (sup CancelSoftwareUpgradeProposal) ProposalType() string { return ProposalTypeCancelSoftwareUpgrade } -func (sup CancelSoftwareUpgradeProposal) ValidateBasic() sdk.Error { - return gov.ValidateAbstract(DefaultCodespace, sup) +func (sup CancelSoftwareUpgradeProposal) ValidateBasic() error { + return gov.ValidateAbstract(sup) } func (sup CancelSoftwareUpgradeProposal) String() string { From 43e25e283eed15ef829c8a2f92672c6a21332e6d Mon Sep 17 00:00:00 2001 From: Marko Date: Thu, 2 Jan 2020 16:25:09 +0100 Subject: [PATCH 052/529] Merge PR #5463: docs: add link to iavl documentation --- .github/workflows/linkchecker.yml | 11 +++++++++++ docs/architecture/adr-009-evidence-module.md | 2 +- docs/core/store.md | 2 ++ docs/spec/README.md | 2 +- go.sum | 8 ++++---- x/README.md | 20 ++++++++++---------- x/auth/spec/03_types.md | 2 +- x/staking/spec/01_state.md | 4 ++-- x/staking/spec/02_state_transitions.md | 2 +- x/staking/spec/03_messages.md | 2 +- 10 files changed, 34 insertions(+), 21 deletions(-) create mode 100644 .github/workflows/linkchecker.yml diff --git a/.github/workflows/linkchecker.yml b/.github/workflows/linkchecker.yml new file mode 100644 index 000000000000..c78daa396f45 --- /dev/null +++ b/.github/workflows/linkchecker.yml @@ -0,0 +1,11 @@ +name: Check links +on: [pull_request] +jobs: + link-check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Link Checker + uses: peter-evans/link-checker@v1 + with: + args: -v -r * \ No newline at end of file diff --git a/docs/architecture/adr-009-evidence-module.md b/docs/architecture/adr-009-evidence-module.md index b7d0fdc49a5f..8ef5d6e5cdd6 100644 --- a/docs/architecture/adr-009-evidence-module.md +++ b/docs/architecture/adr-009-evidence-module.md @@ -179,4 +179,4 @@ due to the inability to introduce the new evidence type's corresponding handler - [ICS](https://github.com/cosmos/ics) - [IBC Architecture](https://github.com/cosmos/ics/blob/master/ibc/1_IBC_ARCHITECTURE.md) -- [Tendermint Fork Accountability](https://github.com/tendermint/tendermint/blob/master/docs/spec/consensus/fork-accountability.md) +- [Tendermint Fork Accountability](https://github.com/tendermint/spec/blob/7b3138e69490f410768d9b1ffc7a17abc23ea397/spec/consensus/fork-accountability.md) diff --git a/docs/core/store.md b/docs/core/store.md index ee93f49e9332..35b3d0f2a2e1 100644 --- a/docs/core/store.md +++ b/docs/core/store.md @@ -150,6 +150,8 @@ The default implementation of `KVStore` and `CommitKVStore` used in `baseapp` is - Iteration efficiently returns the sorted elements within the range. - Each tree version is immutable and can be retrieved even after a commit (depending on the pruning settings). +The documentation on the IAVL Tree is located [here](https://github.com/tendermint/iavl/blob/f9d4b446a226948ed19286354f0d433a887cc4a3/docs/overview.md). + ### `DbAdapter` Store `dbadapter.Store` is a adapter for `dbm.DB` making it fulfilling the `KVStore` interface. diff --git a/docs/spec/README.md b/docs/spec/README.md index 2dd2321be23c..b66a024ab196 100644 --- a/docs/spec/README.md +++ b/docs/spec/README.md @@ -23,4 +23,4 @@ Go the [module directory](../../x/README.md) ## Tendermint For details on the underlying blockchain and p2p protocols, see -the [Tendermint specification](https://github.com/tendermint/tendermint/tree/master/docs/spec). +the [Tendermint specification](https://github.com/tendermint/spec/tree/master/spec). diff --git a/go.sum b/go.sum index e83a49d31f82..cc5d9b873f77 100644 --- a/go.sum +++ b/go.sum @@ -107,6 +107,7 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= @@ -132,6 +133,7 @@ github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d h1:Z+RDyXzjKE0i2sTjZ/b1uxiGtPhFy34Ou/Tk0qwN0kM= @@ -154,8 +156,6 @@ github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDe github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10= -github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= @@ -206,7 +206,9 @@ github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/snikch/goodman v0.0.0-20171125024755-10e37e294daa/go.mod h1:oJyF+mSPHbB5mVY2iO9KV3pTt/QbIkGaO8gQ2WrDbP4= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= @@ -316,8 +318,6 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191008105621-543471e840be h1:QAcqgptGM8IQBC9K/RC4o+O9YmqEm0diQn9QmZw/0mU= -golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= diff --git a/x/README.md b/x/README.md index a37fcfc31cf5..e123223f4a80 100644 --- a/x/README.md +++ b/x/README.md @@ -7,15 +7,15 @@ parent: Here are some production-grade modules that can be used in Cosmos SDK applications, along with their respective documentation: -- [Auth](./x/auth/spec/README.md) - Authentication of accounts and transactions for Cosmos SDK application. -- [Bank](./x/bank/spec/README.md) - Token transfer functionalities. -- [Governance](./x/gov/spec/README.md) - On-chain proposals and voting. -- [Staking](./x/staking/spec/README.md) - Proof-of-stake layer for public blockchains. -- [Slashing](./x/slashing/spec/README.md) - Validator punishment mechanisms. -- [Distribution](./x/distribution/spec/README.md) - Fee distribution, and staking token provision distribution. -- [Crisis](./x/crisis/spec/README.md) - Halting the blockchain under certain circumstances (e.g. if an invariant is broken). -- [Mint](./x/mint/spec/README.md) - Creation of new units of staking token. -- [Params](./x/params/spec/README.md) - Globally available parameter store. -- [Supply](./x/supply/spec/README.md) - Total token supply of the chain. +- [Auth](auth/spec/README.md) - Authentication of accounts and transactions for Cosmos SDK application. +- [Bank](bank/spec/README.md) - Token transfer functionalities. +- [Governance](gov/spec/README.md) - On-chain proposals and voting. +- [Staking](staking/spec/README.md) - Proof-of-stake layer for public blockchains. +- [Slashing](slashing/spec/README.md) - Validator punishment mechanisms. +- [Distribution](distribution/spec/README.md) - Fee distribution, and staking token provision distribution. +- [Crisis](crisis/spec/README.md) - Halting the blockchain under certain circumstances (e.g. if an invariant is broken). +- [Mint](mint/spec/README.md) - Creation of new units of staking token. +- [Params](params/spec/README.md) - Globally available parameter store. +- [Supply](supply/spec/README.md) - Total token supply of the chain. To learn more about the process of building modules, visit the [building modules reference documentation](../docs/building-modules/README.md). diff --git a/x/auth/spec/03_types.md b/x/auth/spec/03_types.md index 62c1d186c4e1..e71be190733f 100644 --- a/x/auth/spec/03_types.md +++ b/x/auth/spec/03_types.md @@ -4,7 +4,7 @@ order: 4 # Types -Besides accounts (specified in [State](state.md)), the types exposed by the auth module +Besides accounts (specified in [State](02_state.md)), the types exposed by the auth module are `StdFee`, the combination of an amount and gas limit, `StdSignature`, the combination of an optional public key and a cryptographic signature as a byte array, `StdTx`, a struct which implements the `sdk.Tx` interface using `StdFee` and `StdSignature`, and diff --git a/x/staking/spec/01_state.md b/x/staking/spec/01_state.md index 11b63d8dfc32..3ee6c7992ebf 100644 --- a/x/staking/spec/01_state.md +++ b/x/staking/spec/01_state.md @@ -33,7 +33,7 @@ Validators can have one of three statuses - `Unbonded`: The validator is not in the active set. They cannot sign blocks and do not earn rewards. They can receive delegations. - `Bonded`": Once the validator receives sufficient bonded tokens they automtically join the - active set during [`EndBlock`](./04_end_block.md#validator-set-changes) and their status is updated to `Bonded`. + active set during [`EndBlock`](./05_end_block.md#validator-set-changes) and their status is updated to `Bonded`. They are signing blocks and receiving rewards. They can receive further delegations. They can be slashed for misbehavior. Delegators to this validator who unbond their delegation must wait the duration of the UnbondingTime, a chain-specific param. during which time @@ -73,7 +73,7 @@ ConsensusPower is validator.Tokens/10^6. Note that all validators where `LastValidatorsPower` is a special index that provides a historical list of the last-block's bonded validators. This index remains constant during a block but -is updated during the validator set update process which takes place in [`EndBlock`](./04_end_block.md). +is updated during the validator set update process which takes place in [`EndBlock`](./05_end_block.md). Each validator's state is stored in a `Validator` struct: diff --git a/x/staking/spec/02_state_transitions.md b/x/staking/spec/02_state_transitions.md index 8aaa9c36443a..c2766aa43b79 100644 --- a/x/staking/spec/02_state_transitions.md +++ b/x/staking/spec/02_state_transitions.md @@ -11,7 +11,7 @@ This document describes the state transition operations pertaining to: 3. [Slashing](./02_state_transitions.md#slashing) ## Validators -State transitions in validators are performed on every [`EndBlock`](./04_end_block.md#validator-set-changes) +State transitions in validators are performed on every [`EndBlock`](./05_end_block.md#validator-set-changes) in order to check for changes in the active `ValidatorSet`. ### Unbonded to Bonded diff --git a/x/staking/spec/03_messages.md b/x/staking/spec/03_messages.md index d7b98b1aabab..bd9f21e2ceb0 100644 --- a/x/staking/spec/03_messages.md +++ b/x/staking/spec/03_messages.md @@ -4,7 +4,7 @@ order: 3 # Messages -In this section we describe the processing of the staking messages and the corresponding updates to the state. All created/modified state objects specified by each message are defined within the [state](./02_state.md) section. +In this section we describe the processing of the staking messages and the corresponding updates to the state. All created/modified state objects specified by each message are defined within the [state](./02_state_transitions.md) section. ## MsgCreateValidator From 900502fc21397dfefbae3b549ebe9afd149cec13 Mon Sep 17 00:00:00 2001 From: billy rennekamp Date: Thu, 2 Jan 2020 18:31:55 +0100 Subject: [PATCH 053/529] Merge PR #5464: Update config.js --- docs/.vuepress/config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index 9295d711284f..e25d835a7a39 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -56,7 +56,7 @@ module.exports = { children: [ { title: "Tutorials", - path: "https://github.com/cosmos/sdk-application-tutorial" + path: "https://tutorials.cosmos.network" }, { title: "SDK API Reference", From a5fc7d6ba67a14ebc792cdb7326469f67741b751 Mon Sep 17 00:00:00 2001 From: Anil Kumar Kammari Date: Fri, 3 Jan 2020 20:07:29 +0530 Subject: [PATCH 054/529] Merge PR #5367: Regen network/skip upgrade --- server/start.go | 23 +- simapp/app.go | 4 +- simapp/app_test.go | 6 +- simapp/sim_bench_test.go | 4 +- simapp/sim_test.go | 12 +- simapp/test_helpers.go | 4 +- x/crisis/handler_test.go | 2 +- x/crisis/internal/keeper/integration_test.go | 2 +- x/upgrade/abci.go | 18 +- x/upgrade/abci_test.go | 364 +++++++++++++++---- x/upgrade/internal/keeper/keeper.go | 29 +- x/upgrade/internal/keeper/querier.go | 2 +- 12 files changed, 350 insertions(+), 120 deletions(-) diff --git a/server/start.go b/server/start.go index 560d1614ac7a..8d1388791ad7 100644 --- a/server/start.go +++ b/server/start.go @@ -20,15 +20,16 @@ import ( // Tendermint full-node start flags const ( - flagWithTendermint = "with-tendermint" - flagAddress = "address" - flagTraceStore = "trace-store" - flagPruning = "pruning" - flagCPUProfile = "cpu-profile" - FlagMinGasPrices = "minimum-gas-prices" - FlagHaltHeight = "halt-height" - FlagHaltTime = "halt-time" - FlagInterBlockCache = "inter-block-cache" + flagWithTendermint = "with-tendermint" + flagAddress = "address" + flagTraceStore = "trace-store" + flagPruning = "pruning" + flagCPUProfile = "cpu-profile" + FlagMinGasPrices = "minimum-gas-prices" + FlagHaltHeight = "halt-height" + FlagHaltTime = "halt-time" + FlagInterBlockCache = "inter-block-cache" + FlagUnsafeSkipUpgrades = "unsafe-skip-upgrades" ) // StartCmd runs the service passed in, either stand-alone or in-process with @@ -77,6 +78,7 @@ which accepts a path for the resulting pprof file. FlagMinGasPrices, "", "Minimum gas prices to accept for transactions; Any fee in a tx must meet this minimum (e.g. 0.01photino;0.0001stake)", ) + cmd.Flags().IntSlice(FlagUnsafeSkipUpgrades, []int{}, "Skip a set of upgrade heights to continue the old binary") cmd.Flags().Uint64(FlagHaltHeight, 0, "Block height at which to gracefully halt the chain and shutdown the node") cmd.Flags().Uint64(FlagHaltTime, 0, "Minimum block time (in Unix seconds) at which to gracefully halt the chain and shutdown the node") cmd.Flags().Bool(FlagInterBlockCache, true, "Enable inter-block caching") @@ -130,12 +132,13 @@ func startStandAlone(ctx *Context, appCreator AppCreator) error { func startInProcess(ctx *Context, appCreator AppCreator) (*node.Node, error) { cfg := ctx.Config home := cfg.RootDir - traceWriterFile := viper.GetString(flagTraceStore) + traceWriterFile := viper.GetString(flagTraceStore) db, err := openDB(home) if err != nil { return nil, err } + traceWriter, err := openTraceWriter(traceWriterFile) if err != nil { return nil, err diff --git a/simapp/app.go b/simapp/app.go index e4e4ede4e9d2..2b5d240c3e5b 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -131,7 +131,7 @@ type SimApp struct { // NewSimApp returns a reference to an initialized SimApp. func NewSimApp( - logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool, + logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool, skipUpgradeHeights map[int64]bool, invCheckPeriod uint, baseAppOptions ...func(*bam.BaseApp), ) *SimApp { @@ -196,7 +196,7 @@ func NewSimApp( app.CrisisKeeper = crisis.NewKeeper( app.subspaces[crisis.ModuleName], invCheckPeriod, app.SupplyKeeper, auth.FeeCollectorName, ) - app.UpgradeKeeper = upgrade.NewKeeper(keys[upgrade.StoreKey], app.cdc) + app.UpgradeKeeper = upgrade.NewKeeper(skipUpgradeHeights, keys[upgrade.StoreKey], app.cdc) // create evidence keeper with router evidenceKeeper := evidence.NewKeeper( diff --git a/simapp/app_test.go b/simapp/app_test.go index 1f152976f1e9..9cf211a94176 100644 --- a/simapp/app_test.go +++ b/simapp/app_test.go @@ -15,7 +15,7 @@ import ( func TestSimAppExport(t *testing.T) { db := dbm.NewMemDB() - app := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, 0) + app := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, 0) genesisState := NewDefaultGenesisState() stateBytes, err := codec.MarshalJSONIndent(app.Codec(), genesisState) @@ -31,7 +31,7 @@ func TestSimAppExport(t *testing.T) { app.Commit() // Making a new app object with the db, so that initchain hasn't been called - app2 := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, 0) + app2 := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, 0) _, _, err = app2.ExportAppStateAndValidators(false, []string{}) require.NoError(t, err, "ExportAppStateAndValidators should not have an error") } @@ -39,7 +39,7 @@ func TestSimAppExport(t *testing.T) { // ensure that black listed addresses are properly set in bank keeper func TestBlackListedAddrs(t *testing.T) { db := dbm.NewMemDB() - app := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, 0) + app := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, 0) for acc := range maccPerms { require.Equal(t, !allowedReceivingModAcc[acc], app.BankKeeper.BlacklistedAddr(app.SupplyKeeper.GetModuleAddress(acc))) diff --git a/simapp/sim_bench_test.go b/simapp/sim_bench_test.go index 2b6c486bf9b8..8e10ccd46517 100644 --- a/simapp/sim_bench_test.go +++ b/simapp/sim_bench_test.go @@ -25,7 +25,7 @@ func BenchmarkFullAppSimulation(b *testing.B) { } }() - app := NewSimApp(logger, db, nil, true, FlagPeriodValue, interBlockCacheOpt()) + app := NewSimApp(logger, db, nil, true, map[int64]bool{}, FlagPeriodValue, interBlockCacheOpt()) // run randomized simulation _, simParams, simErr := simulation.SimulateFromSeed( @@ -64,7 +64,7 @@ func BenchmarkInvariants(b *testing.B) { } }() - app := NewSimApp(logger, db, nil, true, FlagPeriodValue, interBlockCacheOpt()) + app := NewSimApp(logger, db, nil, true, map[int64]bool{}, FlagPeriodValue, interBlockCacheOpt()) // run randomized simulation _, simParams, simErr := simulation.SimulateFromSeed( diff --git a/simapp/sim_test.go b/simapp/sim_test.go index 7738b29a4263..3d41fa3b8467 100644 --- a/simapp/sim_test.go +++ b/simapp/sim_test.go @@ -62,7 +62,7 @@ func TestFullAppSimulation(t *testing.T) { require.NoError(t, os.RemoveAll(dir)) }() - app := NewSimApp(logger, db, nil, true, FlagPeriodValue, fauxMerkleModeOpt) + app := NewSimApp(logger, db, nil, true, map[int64]bool{}, FlagPeriodValue, fauxMerkleModeOpt) require.Equal(t, "SimApp", app.Name()) // run randomized simulation @@ -94,7 +94,7 @@ func TestAppImportExport(t *testing.T) { require.NoError(t, os.RemoveAll(dir)) }() - app := NewSimApp(logger, db, nil, true, FlagPeriodValue, fauxMerkleModeOpt) + app := NewSimApp(logger, db, nil, true, map[int64]bool{}, FlagPeriodValue, fauxMerkleModeOpt) require.Equal(t, "SimApp", app.Name()) // Run randomized simulation @@ -128,7 +128,7 @@ func TestAppImportExport(t *testing.T) { require.NoError(t, os.RemoveAll(newDir)) }() - newApp := NewSimApp(log.NewNopLogger(), newDB, nil, true, FlagPeriodValue, fauxMerkleModeOpt) + newApp := NewSimApp(log.NewNopLogger(), newDB, nil, true, map[int64]bool{}, FlagPeriodValue, fauxMerkleModeOpt) require.Equal(t, "SimApp", newApp.Name()) var genesisState GenesisState @@ -180,7 +180,7 @@ func TestAppSimulationAfterImport(t *testing.T) { require.NoError(t, os.RemoveAll(dir)) }() - app := NewSimApp(logger, db, nil, true, FlagPeriodValue, fauxMerkleModeOpt) + app := NewSimApp(logger, db, nil, true, map[int64]bool{}, FlagPeriodValue, fauxMerkleModeOpt) require.Equal(t, "SimApp", app.Name()) // Run randomized simulation @@ -219,7 +219,7 @@ func TestAppSimulationAfterImport(t *testing.T) { require.NoError(t, os.RemoveAll(newDir)) }() - newApp := NewSimApp(log.NewNopLogger(), newDB, nil, true, FlagPeriodValue, fauxMerkleModeOpt) + newApp := NewSimApp(log.NewNopLogger(), newDB, nil, true, map[int64]bool{}, FlagPeriodValue, fauxMerkleModeOpt) require.Equal(t, "SimApp", newApp.Name()) newApp.InitChain(abci.RequestInitChain{ @@ -265,7 +265,7 @@ func TestAppStateDeterminism(t *testing.T) { db := dbm.NewMemDB() - app := NewSimApp(logger, db, nil, true, FlagPeriodValue, interBlockCacheOpt()) + app := NewSimApp(logger, db, nil, true, map[int64]bool{}, FlagPeriodValue, interBlockCacheOpt()) fmt.Printf( "running non-determinism simulation; seed %d: %d/%d, attempt: %d/%d\n", diff --git a/simapp/test_helpers.go b/simapp/test_helpers.go index d132394c9bc7..f06af61948d8 100644 --- a/simapp/test_helpers.go +++ b/simapp/test_helpers.go @@ -23,7 +23,7 @@ import ( // Setup initializes a new SimApp. A Nop logger is set in SimApp. func Setup(isCheckTx bool) *SimApp { db := dbm.NewMemDB() - app := NewSimApp(log.NewNopLogger(), db, nil, true, 0) + app := NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, 0) if !isCheckTx { // init chain must be called to stop deliverState from being nil genesisState := NewDefaultGenesisState() @@ -48,7 +48,7 @@ func Setup(isCheckTx bool) *SimApp { // genesis accounts. func SetupWithGenesisAccounts(genAccs []authexported.GenesisAccount) *SimApp { db := dbm.NewMemDB() - app := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, 0) + app := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, 0) // initialize the chain with the passed in genesis accounts genesisState := NewDefaultGenesisState() diff --git a/x/crisis/handler_test.go b/x/crisis/handler_test.go index f4c2f8182dbf..290b0c373cdb 100644 --- a/x/crisis/handler_test.go +++ b/x/crisis/handler_test.go @@ -25,7 +25,7 @@ var ( func createTestApp() (*simapp.SimApp, sdk.Context, []sdk.AccAddress) { db := dbm.NewMemDB() - app := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, 1) + app := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, 1) ctx := app.NewContext(true, abci.Header{}) constantFee := sdk.NewInt64Coin(sdk.DefaultBondDenom, 10) diff --git a/x/crisis/internal/keeper/integration_test.go b/x/crisis/internal/keeper/integration_test.go index 339244325e55..a98a0b44533c 100644 --- a/x/crisis/internal/keeper/integration_test.go +++ b/x/crisis/internal/keeper/integration_test.go @@ -11,7 +11,7 @@ import ( func createTestApp() *simapp.SimApp { db := dbm.NewMemDB() - app := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, 5) + app := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, 5) // init chain must be called to stop deliverState from being nil genesisState := simapp.NewDefaultGenesisState() stateBytes, err := codec.MarshalJSONIndent(app.Codec(), genesisState) diff --git a/x/upgrade/abci.go b/x/upgrade/abci.go index 01b0aae6a003..7a19e0f866ab 100644 --- a/x/upgrade/abci.go +++ b/x/upgrade/abci.go @@ -2,37 +2,47 @@ package upgrade import ( "fmt" - abci "github.com/tendermint/tendermint/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" ) // BeginBlock will check if there is a scheduled plan and if it is ready to be executed. +// If the current height is in the provided set of heights to skip, it will skip and clear the upgrade plan. // If it is ready, it will execute it if the handler is installed, and panic/abort otherwise. // If the plan is not ready, it will ensure the handler is not registered too early (and abort otherwise). // -// The purpose is to ensure the binary is switch EXACTLY at the desired block, and to allow +// The purpose is to ensure the binary is switched EXACTLY at the desired block, and to allow // a migration to be executed if needed upon this switch (migration defined in the new binary) +// skipUpgradeHeightArray is a set of block heights for which the upgrade must be skipped func BeginBlocker(k Keeper, ctx sdk.Context, _ abci.RequestBeginBlock) { plan, found := k.GetUpgradePlan(ctx) if !found { return } + // To make sure clear upgrade is executed at the same block if plan.ShouldExecute(ctx) { + // If skip upgrade has been set for current height, we clear the upgrade plan + if k.IsSkipHeight(ctx.BlockHeight()) { + skipUpgradeMsg := fmt.Sprintf("UPGRADE \"%s\" SKIPPED at %d: %s", plan.Name, plan.Height, plan.Info) + ctx.Logger().Info(skipUpgradeMsg) + + // Clear the upgrade plan at current height + k.ClearUpgradePlan(ctx) + return + } + if !k.HasHandler(plan.Name) { upgradeMsg := fmt.Sprintf("UPGRADE \"%s\" NEEDED at %s: %s", plan.Name, plan.DueAt(), plan.Info) // We don't have an upgrade handler for this upgrade name, meaning this software is out of date so shutdown ctx.Logger().Error(upgradeMsg) panic(upgradeMsg) } - // We have an upgrade handler for this upgrade name, so apply the upgrade ctx.Logger().Info(fmt.Sprintf("applying upgrade \"%s\" at %s", plan.Name, plan.DueAt())) ctx = ctx.WithBlockGasMeter(sdk.NewInfiniteGasMeter()) k.ApplyUpgrade(ctx, plan) - return } diff --git a/x/upgrade/abci_test.go b/x/upgrade/abci_test.go index 34c8944e0017..c82fe757a5e5 100644 --- a/x/upgrade/abci_test.go +++ b/x/upgrade/abci_test.go @@ -5,19 +5,21 @@ import ( "testing" "time" + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/libs/log" + dbm "github.com/tendermint/tm-db" + + "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/x/gov" "github.com/cosmos/cosmos-sdk/x/upgrade" - "github.com/stretchr/testify/suite" - abci "github.com/tendermint/tendermint/abci/types" ) type TestSuite struct { - suite.Suite - module module.AppModule keeper upgrade.Keeper querier sdk.Querier @@ -25,163 +27,369 @@ type TestSuite struct { ctx sdk.Context } -func (s *TestSuite) SetupTest() { - checkTx := false - app := simapp.Setup(checkTx) +var s TestSuite + +func setupTest(height int64, skip map[int64]bool) TestSuite { + db := dbm.NewMemDB() + app := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, skip, 0) + genesisState := simapp.NewDefaultGenesisState() + stateBytes, err := codec.MarshalJSONIndent(app.Codec(), genesisState) + if err != nil { + panic(err) + } + app.InitChain( + abci.RequestInitChain{ + Validators: []abci.ValidatorUpdate{}, + AppStateBytes: stateBytes, + }, + ) s.keeper = app.UpgradeKeeper - s.handler = upgrade.NewSoftwareUpgradeProposalHandler(s.keeper) - s.querier = upgrade.NewQuerier(s.keeper) - s.ctx = app.BaseApp.NewContext(checkTx, abci.Header{Height: 10, Time: time.Now()}) + s.ctx = app.BaseApp.NewContext(false, abci.Header{Height: height, Time: time.Now()}) + s.module = upgrade.NewAppModule(s.keeper) + s.querier = s.module.NewQuerierHandler() + s.handler = upgrade.NewSoftwareUpgradeProposalHandler(s.keeper) + return s } -func (s *TestSuite) TestRequireName() { +func TestRequireName(t *testing.T) { + s := setupTest(10, map[int64]bool{}) + err := s.handler(s.ctx, upgrade.SoftwareUpgradeProposal{Title: "prop", Plan: upgrade.Plan{}}) - s.Require().NotNil(err) - s.Require().True(errors.Is(sdkerrors.ErrInvalidRequest, err), err) + require.NotNil(t, err) + require.True(t, errors.Is(sdkerrors.ErrInvalidRequest, err), err) } -func (s *TestSuite) TestRequireFutureTime() { +func TestRequireFutureTime(t *testing.T) { + s := setupTest(10, map[int64]bool{}) err := s.handler(s.ctx, upgrade.SoftwareUpgradeProposal{Title: "prop", Plan: upgrade.Plan{Name: "test", Time: s.ctx.BlockHeader().Time}}) - s.Require().NotNil(err) - s.Require().True(errors.Is(sdkerrors.ErrInvalidRequest, err), err) + require.NotNil(t, err) + require.True(t, errors.Is(sdkerrors.ErrInvalidRequest, err), err) } -func (s *TestSuite) TestRequireFutureBlock() { +func TestRequireFutureBlock(t *testing.T) { + s := setupTest(10, map[int64]bool{}) err := s.handler(s.ctx, upgrade.SoftwareUpgradeProposal{Title: "prop", Plan: upgrade.Plan{Name: "test", Height: s.ctx.BlockHeight()}}) - s.Require().NotNil(err) - s.Require().True(errors.Is(sdkerrors.ErrInvalidRequest, err), err) + require.NotNil(t, err) + require.True(t, errors.Is(sdkerrors.ErrInvalidRequest, err), err) } -func (s *TestSuite) TestCantSetBothTimeAndHeight() { +func TestCantSetBothTimeAndHeight(t *testing.T) { + s := setupTest(10, map[int64]bool{}) err := s.handler(s.ctx, upgrade.SoftwareUpgradeProposal{Title: "prop", Plan: upgrade.Plan{Name: "test", Time: time.Now(), Height: s.ctx.BlockHeight() + 1}}) - s.Require().NotNil(err) - s.Require().True(errors.Is(sdkerrors.ErrInvalidRequest, err), err) + require.NotNil(t, err) + require.True(t, errors.Is(sdkerrors.ErrInvalidRequest, err), err) } -func (s *TestSuite) TestDoTimeUpgrade() { - s.T().Log("Verify can schedule an upgrade") +func TestDoTimeUpgrade(t *testing.T) { + s := setupTest(10, map[int64]bool{}) + t.Log("Verify can schedule an upgrade") err := s.handler(s.ctx, upgrade.SoftwareUpgradeProposal{Title: "prop", Plan: upgrade.Plan{Name: "test", Time: time.Now()}}) - s.Require().Nil(err) + require.Nil(t, err) - s.VerifyDoUpgrade() + VerifyDoUpgrade(t) } -func (s *TestSuite) TestDoHeightUpgrade() { - s.T().Log("Verify can schedule an upgrade") +func TestDoHeightUpgrade(t *testing.T) { + s := setupTest(10, map[int64]bool{}) + t.Log("Verify can schedule an upgrade") err := s.handler(s.ctx, upgrade.SoftwareUpgradeProposal{Title: "prop", Plan: upgrade.Plan{Name: "test", Height: s.ctx.BlockHeight() + 1}}) - s.Require().Nil(err) + require.Nil(t, err) - s.VerifyDoUpgrade() + VerifyDoUpgrade(t) } -func (s *TestSuite) TestCanOverwriteScheduleUpgrade() { - s.T().Log("Can overwrite plan") +func TestCanOverwriteScheduleUpgrade(t *testing.T) { + s := setupTest(10, map[int64]bool{}) + t.Log("Can overwrite plan") err := s.handler(s.ctx, upgrade.SoftwareUpgradeProposal{Title: "prop", Plan: upgrade.Plan{Name: "bad_test", Height: s.ctx.BlockHeight() + 10}}) - s.Require().Nil(err) + require.Nil(t, err) err = s.handler(s.ctx, upgrade.SoftwareUpgradeProposal{Title: "prop", Plan: upgrade.Plan{Name: "test", Height: s.ctx.BlockHeight() + 1}}) - s.Require().Nil(err) + require.Nil(t, err) - s.VerifyDoUpgrade() + VerifyDoUpgrade(t) } -func (s *TestSuite) VerifyDoUpgrade() { - s.T().Log("Verify that a panic happens at the upgrade time/height") +func VerifyDoUpgrade(t *testing.T) { + t.Log("Verify that a panic happens at the upgrade time/height") newCtx := s.ctx.WithBlockHeight(s.ctx.BlockHeight() + 1).WithBlockTime(time.Now()) req := abci.RequestBeginBlock{Header: newCtx.BlockHeader()} - s.Require().Panics(func() { + require.Panics(t, func() { s.module.BeginBlock(newCtx, req) }) - s.T().Log("Verify that the upgrade can be successfully applied with a handler") + t.Log("Verify that the upgrade can be successfully applied with a handler") s.keeper.SetUpgradeHandler("test", func(ctx sdk.Context, plan upgrade.Plan) {}) - s.Require().NotPanics(func() { + require.NotPanics(t, func() { s.module.BeginBlock(newCtx, req) }) - s.VerifyCleared(newCtx) + VerifyCleared(t, newCtx) } -func (s *TestSuite) TestHaltIfTooNew() { - s.T().Log("Verify that we don't panic with registered plan not in database at all") +func VerifyDoUpgradeWithCtx(t *testing.T, newCtx sdk.Context, proposalName string) { + t.Log("Verify that a panic happens at the upgrade time/height") + req := abci.RequestBeginBlock{Header: newCtx.BlockHeader()} + require.Panics(t, func() { + s.module.BeginBlock(newCtx, req) + }) + + t.Log("Verify that the upgrade can be successfully applied with a handler") + s.keeper.SetUpgradeHandler(proposalName, func(ctx sdk.Context, plan upgrade.Plan) {}) + require.NotPanics(t, func() { + s.module.BeginBlock(newCtx, req) + }) + + VerifyCleared(t, newCtx) +} + +func TestHaltIfTooNew(t *testing.T) { + s := setupTest(10, map[int64]bool{}) + t.Log("Verify that we don't panic with registered plan not in database at all") var called int s.keeper.SetUpgradeHandler("future", func(ctx sdk.Context, plan upgrade.Plan) { called++ }) newCtx := s.ctx.WithBlockHeight(s.ctx.BlockHeight() + 1).WithBlockTime(time.Now()) req := abci.RequestBeginBlock{Header: newCtx.BlockHeader()} - s.Require().NotPanics(func() { + require.NotPanics(t, func() { s.module.BeginBlock(newCtx, req) }) - s.Require().Equal(0, called) + require.Equal(t, 0, called) - s.T().Log("Verify we panic if we have a registered handler ahead of time") + t.Log("Verify we panic if we have a registered handler ahead of time") err := s.handler(s.ctx, upgrade.SoftwareUpgradeProposal{Title: "prop", Plan: upgrade.Plan{Name: "future", Height: s.ctx.BlockHeight() + 3}}) - s.Require().NoError(err) - s.Require().Panics(func() { + require.NoError(t, err) + require.Panics(t, func() { s.module.BeginBlock(newCtx, req) }) - s.Require().Equal(0, called) + require.Equal(t, 0, called) - s.T().Log("Verify we no longer panic if the plan is on time") + t.Log("Verify we no longer panic if the plan is on time") futCtx := s.ctx.WithBlockHeight(s.ctx.BlockHeight() + 3).WithBlockTime(time.Now()) req = abci.RequestBeginBlock{Header: futCtx.BlockHeader()} - s.Require().NotPanics(func() { + require.NotPanics(t, func() { s.module.BeginBlock(futCtx, req) }) - s.Require().Equal(1, called) + require.Equal(t, 1, called) - s.VerifyCleared(futCtx) + VerifyCleared(t, futCtx) } -func (s *TestSuite) VerifyCleared(newCtx sdk.Context) { - s.T().Log("Verify that the upgrade plan has been cleared") +func VerifyCleared(t *testing.T, newCtx sdk.Context) { + t.Log("Verify that the upgrade plan has been cleared") bz, err := s.querier(newCtx, []string{upgrade.QueryCurrent}, abci.RequestQuery{}) - s.Require().NoError(err) - s.Require().Nil(bz) + require.NoError(t, err) + require.Nil(t, bz) } -func (s *TestSuite) TestCanClear() { - s.T().Log("Verify upgrade is scheduled") +func TestCanClear(t *testing.T) { + s := setupTest(10, map[int64]bool{}) + t.Log("Verify upgrade is scheduled") err := s.handler(s.ctx, upgrade.SoftwareUpgradeProposal{Title: "prop", Plan: upgrade.Plan{Name: "test", Time: time.Now()}}) - s.Require().Nil(err) + require.Nil(t, err) - s.handler(s.ctx, upgrade.CancelSoftwareUpgradeProposal{Title: "cancel"}) + err = s.handler(s.ctx, upgrade.CancelSoftwareUpgradeProposal{Title: "cancel"}) + require.Nil(t, err) - s.VerifyCleared(s.ctx) + VerifyCleared(t, s.ctx) } -func (s *TestSuite) TestCantApplySameUpgradeTwice() { - s.TestDoTimeUpgrade() - s.T().Log("Verify an upgrade named \"test\" can't be scheduled twice") +func TestCantApplySameUpgradeTwice(t *testing.T) { + s := setupTest(10, map[int64]bool{}) err := s.handler(s.ctx, upgrade.SoftwareUpgradeProposal{Title: "prop", Plan: upgrade.Plan{Name: "test", Time: time.Now()}}) - s.Require().NotNil(err) - s.Require().True(errors.Is(sdkerrors.ErrInvalidRequest, err), err) + require.Nil(t, err) + VerifyDoUpgrade(t) + t.Log("Verify an executed upgrade \"test\" can't be rescheduled") + err = s.handler(s.ctx, upgrade.SoftwareUpgradeProposal{Title: "prop", Plan: upgrade.Plan{Name: "test", Time: time.Now()}}) + require.NotNil(t, err) + require.True(t, errors.Is(sdkerrors.ErrInvalidRequest, err), err) } -func (s *TestSuite) TestNoSpuriousUpgrades() { - s.T().Log("Verify that no upgrade panic is triggered in the BeginBlocker when we haven't scheduled an upgrade") +func TestNoSpuriousUpgrades(t *testing.T) { + s := setupTest(10, map[int64]bool{}) + t.Log("Verify that no upgrade panic is triggered in the BeginBlocker when we haven't scheduled an upgrade") req := abci.RequestBeginBlock{Header: s.ctx.BlockHeader()} - s.Require().NotPanics(func() { + require.NotPanics(t, func() { s.module.BeginBlock(s.ctx, req) }) } -func (s *TestSuite) TestPlanStringer() { - t, err := time.Parse(time.RFC3339, "2020-01-01T00:00:00Z") - s.Require().Nil(err) - s.Require().Equal(`Upgrade Plan +func TestPlanStringer(t *testing.T) { + 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: `, upgrade.Plan{Name: "test", Time: t}.String()) - s.Require().Equal(`Upgrade Plan + Info: `, upgrade.Plan{Name: "test", Time: ti}.String()) + require.Equal(t, `Upgrade Plan Name: test Height: 100 Info: `, upgrade.Plan{Name: "test", Height: 100}.String()) } -func TestTestSuite(t *testing.T) { - suite.Run(t, new(TestSuite)) +func VerifyNotDone(t *testing.T, newCtx sdk.Context, name string) { + t.Log("Verify that upgrade was not done") + height := s.keeper.GetDoneHeight(newCtx, name) + require.Zero(t, height) +} + +func VerifyDone(t *testing.T, newCtx sdk.Context, name string) { + t.Log("Verify that the upgrade plan has been executed") + height := s.keeper.GetDoneHeight(newCtx, name) + require.NotZero(t, height) +} + +func VerifySet(t *testing.T, skipUpgradeHeights map[int64]bool) { + t.Log("Verify if the skip upgrade has been set") + + for k := range skipUpgradeHeights { + require.True(t, s.keeper.IsSkipHeight(k)) + } +} + +func TestContains(t *testing.T) { + var ( + skipOne int64 = 11 + ) + s := setupTest(10, map[int64]bool{skipOne: true}) + + VerifySet(t, map[int64]bool{skipOne: true}) + t.Log("case where array contains the element") + require.True(t, s.keeper.IsSkipHeight(11)) + + t.Log("case where array doesn't contain the element") + require.False(t, s.keeper.IsSkipHeight(4)) +} + +func TestSkipUpgradeSkippingAll(t *testing.T) { + var ( + skipOne int64 = 11 + skipTwo int64 = 20 + ) + s := setupTest(10, map[int64]bool{skipOne: true, skipTwo: true}) + + newCtx := s.ctx + + req := abci.RequestBeginBlock{Header: newCtx.BlockHeader()} + err := s.handler(s.ctx, upgrade.SoftwareUpgradeProposal{Title: "prop", Plan: upgrade.Plan{Name: "test", Height: skipOne}}) + require.NoError(t, err) + + t.Log("Verify if skip upgrade flag clears upgrade plan in both cases") + VerifySet(t, map[int64]bool{skipOne: true, skipTwo: true}) + + newCtx = newCtx.WithBlockHeight(skipOne) + require.NotPanics(t, func() { + s.module.BeginBlock(newCtx, req) + }) + + t.Log("Verify a second proposal also is being cleared") + err = s.handler(s.ctx, upgrade.SoftwareUpgradeProposal{Title: "prop2", Plan: upgrade.Plan{Name: "test2", Height: skipTwo}}) + require.NoError(t, err) + + newCtx = newCtx.WithBlockHeight(skipTwo) + require.NotPanics(t, func() { + s.module.BeginBlock(newCtx, req) + }) + + // To ensure verification is being done only after both upgrades are cleared + t.Log("Verify if both proposals are cleared") + VerifyCleared(t, s.ctx) + VerifyNotDone(t, s.ctx, "test") + VerifyNotDone(t, s.ctx, "test2") +} + +func TestUpgradeSkippingOne(t *testing.T) { + var ( + skipOne int64 = 11 + skipTwo int64 = 20 + ) + s := setupTest(10, map[int64]bool{skipOne: true}) + + newCtx := s.ctx + + req := abci.RequestBeginBlock{Header: newCtx.BlockHeader()} + err := s.handler(s.ctx, upgrade.SoftwareUpgradeProposal{Title: "prop", Plan: upgrade.Plan{Name: "test", Height: skipOne}}) + require.Nil(t, err) + + t.Log("Verify if skip upgrade flag clears upgrade plan in one case and does upgrade on another") + VerifySet(t, map[int64]bool{skipOne: true}) + + // Setting block height of proposal test + newCtx = newCtx.WithBlockHeight(skipOne) + require.NotPanics(t, func() { + s.module.BeginBlock(newCtx, req) + }) + + t.Log("Verify the second proposal is not skipped") + err = s.handler(s.ctx, upgrade.SoftwareUpgradeProposal{Title: "prop2", Plan: upgrade.Plan{Name: "test2", Height: skipTwo}}) + require.Nil(t, err) + // Setting block height of proposal test2 + newCtx = newCtx.WithBlockHeight(skipTwo) + VerifyDoUpgradeWithCtx(t, newCtx, "test2") + + t.Log("Verify first proposal is cleared and second is done") + VerifyNotDone(t, s.ctx, "test") + VerifyDone(t, s.ctx, "test2") +} + +func TestUpgradeSkippingOnlyTwo(t *testing.T) { + var ( + skipOne int64 = 11 + skipTwo int64 = 20 + skipThree int64 = 25 + ) + s := setupTest(10, map[int64]bool{skipOne: true, skipTwo: true}) + + newCtx := s.ctx + + req := abci.RequestBeginBlock{Header: newCtx.BlockHeader()} + err := s.handler(s.ctx, upgrade.SoftwareUpgradeProposal{Title: "prop", Plan: upgrade.Plan{Name: "test", Height: skipOne}}) + require.Nil(t, err) + + t.Log("Verify if skip upgrade flag clears upgrade plan in both cases and does third upgrade") + VerifySet(t, map[int64]bool{skipOne: true, skipTwo: true}) + + // Setting block height of proposal test + newCtx = newCtx.WithBlockHeight(skipOne) + require.NotPanics(t, func() { + s.module.BeginBlock(newCtx, req) + }) + + // A new proposal with height in skipUpgradeHeights + err = s.handler(s.ctx, upgrade.SoftwareUpgradeProposal{Title: "prop2", Plan: upgrade.Plan{Name: "test2", Height: skipTwo}}) + require.Nil(t, err) + // Setting block height of proposal test2 + newCtx = newCtx.WithBlockHeight(skipTwo) + require.NotPanics(t, func() { + s.module.BeginBlock(newCtx, req) + }) + + t.Log("Verify a new proposal is not skipped") + err = s.handler(s.ctx, upgrade.SoftwareUpgradeProposal{Title: "prop3", Plan: upgrade.Plan{Name: "test3", Height: skipThree}}) + require.Nil(t, err) + newCtx = newCtx.WithBlockHeight(skipThree) + VerifyDoUpgradeWithCtx(t, newCtx, "test3") + + t.Log("Verify two proposals are cleared and third is done") + VerifyNotDone(t, s.ctx, "test") + VerifyNotDone(t, s.ctx, "test2") + VerifyDone(t, s.ctx, "test3") +} + +func TestUpgradeWithoutSkip(t *testing.T) { + s := setupTest(10, map[int64]bool{}) + newCtx := s.ctx.WithBlockHeight(s.ctx.BlockHeight() + 1).WithBlockTime(time.Now()) + req := abci.RequestBeginBlock{Header: newCtx.BlockHeader()} + err := s.handler(s.ctx, upgrade.SoftwareUpgradeProposal{Title: "prop", Plan: upgrade.Plan{Name: "test", Height: s.ctx.BlockHeight() + 1}}) + require.Nil(t, err) + t.Log("Verify if upgrade happens without skip upgrade") + require.Panics(t, func() { + s.module.BeginBlock(newCtx, req) + }) + + VerifyDoUpgrade(t) + VerifyDone(t, s.ctx, "test") } diff --git a/x/upgrade/internal/keeper/keeper.go b/x/upgrade/internal/keeper/keeper.go index e0c0823b0842..7a33d7e4b66c 100644 --- a/x/upgrade/internal/keeper/keeper.go +++ b/x/upgrade/internal/keeper/keeper.go @@ -4,26 +4,29 @@ import ( "encoding/binary" "fmt" + "github.com/tendermint/tendermint/libs/log" + "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/upgrade/internal/types" - "github.com/tendermint/tendermint/libs/log" ) type Keeper struct { - storeKey sdk.StoreKey - cdc *codec.Codec - upgradeHandlers map[string]types.UpgradeHandler + skipUpgradeHeights map[int64]bool + storeKey sdk.StoreKey + cdc *codec.Codec + upgradeHandlers map[string]types.UpgradeHandler } // NewKeeper constructs an upgrade Keeper -func NewKeeper(storeKey sdk.StoreKey, cdc *codec.Codec) Keeper { +func NewKeeper(skipUpgradeHeights map[int64]bool, storeKey sdk.StoreKey, cdc *codec.Codec) Keeper { return Keeper{ - storeKey: storeKey, - cdc: cdc, - upgradeHandlers: map[string]types.UpgradeHandler{}, + skipUpgradeHeights: skipUpgradeHeights, + storeKey: storeKey, + cdc: cdc, + upgradeHandlers: map[string]types.UpgradeHandler{}, } } @@ -50,7 +53,7 @@ func (k Keeper) ScheduleUpgrade(ctx sdk.Context, plan types.Plan) error { return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "upgrade cannot be scheduled in the past") } - if k.getDoneHeight(ctx, plan.Name) != 0 { + if k.GetDoneHeight(ctx, plan.Name) != 0 { return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "upgrade with name %s has already been completed", plan.Name) } @@ -61,7 +64,8 @@ func (k Keeper) ScheduleUpgrade(ctx sdk.Context, plan types.Plan) error { return nil } -func (k Keeper) getDoneHeight(ctx sdk.Context, name string) int64 { +// 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}) bz := store.Get([]byte(name)) if len(bz) == 0 { @@ -121,3 +125,8 @@ func (k Keeper) ApplyUpgrade(ctx sdk.Context, plan types.Plan) { k.ClearUpgradePlan(ctx) k.setDone(ctx, plan.Name) } + +// IsSkipHeight checks if the given height is part of skipUpgradeHeights +func (k Keeper) IsSkipHeight(height int64) bool { + return k.skipUpgradeHeights[height] +} diff --git a/x/upgrade/internal/keeper/querier.go b/x/upgrade/internal/keeper/querier.go index 164a2340c0a7..811acad2302f 100644 --- a/x/upgrade/internal/keeper/querier.go +++ b/x/upgrade/internal/keeper/querier.go @@ -48,7 +48,7 @@ func queryApplied(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, err return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } - applied := k.getDoneHeight(ctx, params.Name) + applied := k.GetDoneHeight(ctx, params.Name) if applied == 0 { return nil, nil } From fe9e50dd34c7f79f6bf5d8ebe7322a3553e727c3 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Fri, 3 Jan 2020 10:25:58 -0500 Subject: [PATCH 055/529] Merge PR #5465: Remove dep Events from TxResponse type --- types/result.go | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/types/result.go b/types/result.go index 8b9a28df502b..9530be01d25c 100644 --- a/types/result.go +++ b/types/result.go @@ -83,10 +83,6 @@ type TxResponse struct { GasUsed int64 `json:"gas_used,omitempty"` Tx Tx `json:"tx,omitempty"` Timestamp string `json:"timestamp,omitempty"` - - // DEPRECATED: Remove in the next next major release in favor of using the - // ABCIMessageLog.Events field. - Events StringEvents `json:"events,omitempty"` } // NewResponseResultTx returns a TxResponse given a ResultTx from tendermint @@ -108,7 +104,6 @@ func NewResponseResultTx(res *ctypes.ResultTx, tx Tx, timestamp string) TxRespon Info: res.TxResult.Info, GasWanted: res.TxResult.GasWanted, GasUsed: res.TxResult.GasUsed, - Events: StringifyEvents(res.TxResult.Events), Tx: tx, Timestamp: timestamp, } @@ -151,7 +146,6 @@ func newTxResponseCheckTx(res *ctypes.ResultBroadcastTxCommit) TxResponse { Info: res.CheckTx.Info, GasWanted: res.CheckTx.GasWanted, GasUsed: res.CheckTx.GasUsed, - Events: StringifyEvents(res.CheckTx.Events), } } @@ -178,7 +172,6 @@ func newTxResponseDeliverTx(res *ctypes.ResultBroadcastTxCommit) TxResponse { Info: res.DeliverTx.Info, GasWanted: res.DeliverTx.GasWanted, GasUsed: res.DeliverTx.GasUsed, - Events: StringifyEvents(res.DeliverTx.Events), } } @@ -206,51 +199,37 @@ func (r TxResponse) String() string { if r.Height > 0 { sb.WriteString(fmt.Sprintf(" Height: %d\n", r.Height)) } - if r.TxHash != "" { sb.WriteString(fmt.Sprintf(" TxHash: %s\n", r.TxHash)) } - if r.Code > 0 { sb.WriteString(fmt.Sprintf(" Code: %d\n", r.Code)) } - if r.Data != "" { sb.WriteString(fmt.Sprintf(" Data: %s\n", r.Data)) } - if r.RawLog != "" { sb.WriteString(fmt.Sprintf(" Raw Log: %s\n", r.RawLog)) } - if r.Logs != nil { sb.WriteString(fmt.Sprintf(" Logs: %s\n", r.Logs)) } - if r.Info != "" { sb.WriteString(fmt.Sprintf(" Info: %s\n", r.Info)) } - if r.GasWanted != 0 { sb.WriteString(fmt.Sprintf(" GasWanted: %d\n", r.GasWanted)) } - if r.GasUsed != 0 { sb.WriteString(fmt.Sprintf(" GasUsed: %d\n", r.GasUsed)) } - if r.Codespace != "" { sb.WriteString(fmt.Sprintf(" Codespace: %s\n", r.Codespace)) } - if r.Timestamp != "" { sb.WriteString(fmt.Sprintf(" Timestamp: %s\n", r.Timestamp)) } - if len(r.Events) > 0 { - sb.WriteString(fmt.Sprintf(" Events: \n%s\n", r.Events.String())) - } - return strings.TrimSpace(sb.String()) } From 066dd1114f846b131bc1c82071a8e3b4cbd3300d Mon Sep 17 00:00:00 2001 From: Ferenc Fabian Date: Fri, 3 Jan 2020 21:44:53 +0100 Subject: [PATCH 056/529] Merge PR #5449: Add New constructor for the DecCoin --- CHANGELOG.md | 2 + simapp/export.go | 2 +- simapp/genesis_account_test.go | 2 +- simapp/test_helpers.go | 2 +- types/coin.go | 24 ++++-- types/coin_benchmark_test.go | 4 +- types/coin_test.go | 2 +- types/dec_coin.go | 46 +++++++++--- types/dec_coin_test.go | 78 +++++++++++++++++++- x/auth/types/stdtx.go | 2 +- x/auth/vesting/types/genesis_test.go | 2 +- x/auth/vesting/types/vesting_account.go | 10 +-- x/auth/vesting/types/vesting_account_test.go | 8 +- x/bank/internal/keeper/keeper.go | 4 +- x/bank/internal/keeper/keeper_test.go | 8 +- x/bank/internal/types/msgs.go | 4 +- x/bank/simulation/operations.go | 2 +- x/crisis/handler_test.go | 2 +- x/distribution/genesis.go | 4 +- x/distribution/keeper/allocation.go | 12 +-- x/distribution/keeper/delegation.go | 6 +- x/distribution/keeper/fee_pool.go | 2 +- x/distribution/keeper/hooks.go | 4 +- x/distribution/keeper/invariants.go | 4 +- x/distribution/keeper/keeper.go | 6 +- x/distribution/keeper/keeper_test.go | 2 +- x/distribution/keeper/querier.go | 3 +- x/distribution/keeper/validator.go | 4 +- x/distribution/proposal_handler_test.go | 4 +- x/genaccounts/legacy/v0_36/migrate.go | 6 +- x/gov/abci_test.go | 2 +- x/gov/genesis.go | 2 +- x/gov/keeper/deposit.go | 4 +- x/gov/keeper/deposit_test.go | 8 +- x/gov/keeper/invariants.go | 2 +- x/gov/keeper/querier_test.go | 12 +-- x/mock/app.go | 2 +- x/mock/types.go | 2 +- x/staking/keeper/delegation_test.go | 32 ++++---- x/staking/keeper/slash_test.go | 8 +- x/staking/keeper/validator_test.go | 12 +-- x/supply/genesis.go | 2 +- x/supply/internal/keeper/bank_test.go | 6 +- x/supply/internal/keeper/invariants.go | 2 +- x/supply/internal/types/supply.go | 2 +- 45 files changed, 235 insertions(+), 124 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index be6b7cec3274..84aaaa61e0c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,8 @@ logic has been implemented for v0.38 target version. Applications can migrate vi ### API Breaking Changes +* (types) [\#5430](https://github.com/cosmos/cosmos-sdk/pull/5430) `DecCoins#Add` parameter changed from `DecCoins` + to `...DecCoin`, `Coins#Add` parameter changed from `Coins` to `...Coin` * (baseapp/types) [\#5421](https://github.com/cosmos/cosmos-sdk/pull/5421) The `Error` interface (`types/errors.go`) has been removed in favor of the concrete type defined in `types/errors/` which implements the standard `error` interface. As a result, the `Handler` and `Querier` implementations now return a standard `error`. diff --git a/simapp/export.go b/simapp/export.go index ea384ba22500..01b1424032cf 100644 --- a/simapp/export.go +++ b/simapp/export.go @@ -91,7 +91,7 @@ func (app *SimApp) prepForZeroHeightGenesis(ctx sdk.Context, jailWhiteList []str // donate any unwithdrawn outstanding reward fraction tokens to the community pool scraps := app.DistrKeeper.GetValidatorOutstandingRewards(ctx, val.GetOperator()) feePool := app.DistrKeeper.GetFeePool(ctx) - feePool.CommunityPool = feePool.CommunityPool.Add(scraps) + feePool.CommunityPool = feePool.CommunityPool.Add(scraps...) app.DistrKeeper.SetFeePool(ctx, feePool) app.DistrKeeper.Hooks().AfterValidatorCreated(ctx, val.GetOperator()) diff --git a/simapp/genesis_account_test.go b/simapp/genesis_account_test.go index db5c7fce2f3a..6c0c6d6775c5 100644 --- a/simapp/genesis_account_test.go +++ b/simapp/genesis_account_test.go @@ -82,7 +82,7 @@ func TestSimGenesisAccountValidate(t *testing.T) { "valid basic account with invalid original vesting coins", simapp.SimGenesisAccount{ BaseAccount: baseAcc, - OriginalVesting: coins.Add(coins), + OriginalVesting: coins.Add(coins...), StartTime: vestingStart.Unix(), EndTime: vestingStart.Add(1 * time.Hour).Unix(), }, diff --git a/simapp/test_helpers.go b/simapp/test_helpers.go index f06af61948d8..5192e59feab0 100644 --- a/simapp/test_helpers.go +++ b/simapp/test_helpers.go @@ -88,7 +88,7 @@ func AddTestAddrs(app *SimApp, ctx sdk.Context, accNum int, accAmt sdk.Int) []sd initCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), accAmt)) totalSupply := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), accAmt.MulRaw(int64(len(testAddrs))))) prevSupply := app.SupplyKeeper.GetSupply(ctx) - app.SupplyKeeper.SetSupply(ctx, supply.NewSupply(prevSupply.GetTotal().Add(totalSupply))) + app.SupplyKeeper.SetSupply(ctx, supply.NewSupply(prevSupply.GetTotal().Add(totalSupply...))) // fill all the addresses with some coins, set the loose pool tokens simultaneously for _, addr := range testAddrs { diff --git a/types/coin.go b/types/coin.go index 94b9dc901c77..98eaa6b806df 100644 --- a/types/coin.go +++ b/types/coin.go @@ -244,7 +244,7 @@ func (coins Coins) IsValid() bool { // // CONTRACT: Add will never return Coins where one Coin has a non-positive // amount. In otherwords, IsValid will always return true. -func (coins Coins) Add(coinsB Coins) Coins { +func (coins Coins) Add(coinsB ...Coin) Coins { return coins.safeAdd(coinsB) } @@ -506,6 +506,11 @@ func (coins Coins) AmountOf(denom string) Int { } } +// GetDenomByIndex returns the Denom of the certain coin to make the findDup generic +func (coins Coins) GetDenomByIndex(i int) string { + return coins[i].Denom +} + // IsAllPositive returns true if there is at least one coin and all currencies // have a positive value. func (coins Coins) IsAllPositive() bool { @@ -669,18 +674,23 @@ func ParseCoins(coinsStr string) (Coins, error) { return coins, nil } +type findDupDescriptor interface { + GetDenomByIndex(int) string + Len() int +} + // findDup works on the assumption that coins is sorted -func findDup(coins Coins) int { - if len(coins) <= 1 { +func findDup(coins findDupDescriptor) int { + if coins.Len() <= 1 { return -1 } - prevDenom := coins[0].Denom - for i := 1; i < len(coins); i++ { - if coins[i].Denom == prevDenom { + prevDenom := coins.GetDenomByIndex(0) + for i := 1; i < coins.Len(); i++ { + if coins.GetDenomByIndex(i) == prevDenom { return i } - prevDenom = coins[i].Denom + prevDenom = coins.GetDenomByIndex(i) } return -1 diff --git a/types/coin_benchmark_test.go b/types/coin_benchmark_test.go index 93a3fc8914b8..34e93d6229e4 100644 --- a/types/coin_benchmark_test.go +++ b/types/coin_benchmark_test.go @@ -21,7 +21,7 @@ func BenchmarkCoinsAdditionIntersect(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { - coinsA.Add(coinsB) + coinsA.Add(coinsB...) } } } @@ -50,7 +50,7 @@ func BenchmarkCoinsAdditionNoIntersect(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { - coinsA.Add(coinsB) + coinsA.Add(coinsB...) } } } diff --git a/types/coin_test.go b/types/coin_test.go index f18ff036500a..a090deb01518 100644 --- a/types/coin_test.go +++ b/types/coin_test.go @@ -251,7 +251,7 @@ func TestAddCoins(t *testing.T) { } for tcIndex, tc := range cases { - res := tc.inputOne.Add(tc.inputTwo) + res := tc.inputOne.Add(tc.inputTwo...) assert.True(t, res.IsValid()) require.Equal(t, tc.expected, res, "sum of coins is incorrect, tc #%d", tcIndex) } diff --git a/types/dec_coin.go b/types/dec_coin.go index e26a88f8755e..9b6e700104e7 100644 --- a/types/dec_coin.go +++ b/types/dec_coin.go @@ -157,9 +157,32 @@ func (coin DecCoin) IsValid() bool { // DecCoins defines a slice of coins with decimal values type DecCoins []DecCoin -// NewDecCoins constructs a new coin set with decimal values +// NewDecCoins constructs a new coin set with with decimal values +// from DecCoins. +func NewDecCoins(decCoins ...DecCoin) DecCoins { + // remove zeroes + newDecCoins := removeZeroDecCoins(DecCoins(decCoins)) + if len(newDecCoins) == 0 { + return DecCoins{} + } + + newDecCoins.Sort() + + // detect duplicate Denoms + if dupIndex := findDup(newDecCoins); dupIndex != -1 { + panic(fmt.Errorf("find duplicate denom: %s", newDecCoins[dupIndex])) + } + + if !newDecCoins.IsValid() { + panic(fmt.Errorf("invalid coin set: %s", newDecCoins)) + } + + return newDecCoins +} + +// NewDecCoinsFromCoin constructs a new coin set with decimal values // from regular Coins. -func NewDecCoins(coins Coins) DecCoins { +func NewDecCoinsFromCoins(coins ...Coin) DecCoins { decCoins := make(DecCoins, len(coins)) newCoins := NewCoins(coins...) for i, coin := range newCoins { @@ -191,10 +214,10 @@ func (coins DecCoins) TruncateDecimal() (truncatedCoins Coins, changeCoins DecCo for _, coin := range coins { truncated, change := coin.TruncateDecimal() if !truncated.IsZero() { - truncatedCoins = truncatedCoins.Add(NewCoins(truncated)) + truncatedCoins = truncatedCoins.Add(truncated) } if !change.IsZero() { - changeCoins = changeCoins.Add(DecCoins{change}) + changeCoins = changeCoins.Add(change) } } @@ -208,7 +231,7 @@ func (coins DecCoins) TruncateDecimal() (truncatedCoins Coins, changeCoins DecCo // // CONTRACT: Add will never return Coins where one Coin has a non-positive // amount. In otherwords, IsValid will always return true. -func (coins DecCoins) Add(coinsB DecCoins) DecCoins { +func (coins DecCoins) Add(coinsB ...DecCoin) DecCoins { return coins.safeAdd(coinsB) } @@ -311,6 +334,11 @@ func (coins DecCoins) Intersect(coinsB DecCoins) DecCoins { return removeZeroDecCoins(res) } +// GetDenomByIndex returns the Denom to make the findDup generic +func (coins DecCoins) GetDenomByIndex(i int) string { + return coins[i].Denom +} + // IsAnyNegative returns true if there is at least one coin whose amount // is negative; returns false otherwise. It returns false if the DecCoins set // is empty too. @@ -338,7 +366,7 @@ func (coins DecCoins) MulDec(d Dec) DecCoins { } if !product.IsZero() { - res = res.Add(DecCoins{product}) + res = res.Add(product) } } @@ -359,7 +387,7 @@ func (coins DecCoins) MulDecTruncate(d Dec) DecCoins { } if !product.IsZero() { - res = res.Add(DecCoins{product}) + res = res.Add(product) } } @@ -382,7 +410,7 @@ func (coins DecCoins) QuoDec(d Dec) DecCoins { } if !quotient.IsZero() { - res = res.Add(DecCoins{quotient}) + res = res.Add(quotient) } } @@ -406,7 +434,7 @@ func (coins DecCoins) QuoDecTruncate(d Dec) DecCoins { } if !quotient.IsZero() { - res = res.Add(DecCoins{quotient}) + res = res.Add(quotient) } } diff --git a/types/dec_coin_test.go b/types/dec_coin_test.go index 65408a0b3ab3..2a20bd6469f4 100644 --- a/types/dec_coin_test.go +++ b/types/dec_coin_test.go @@ -91,7 +91,7 @@ func TestAddDecCoins(t *testing.T) { } for tcIndex, tc := range cases { - res := tc.inputOne.Add(tc.inputTwo) + res := tc.inputOne.Add(tc.inputTwo...) require.Equal(t, tc.expected, res, "sum of coins is incorrect, tc #%d", tcIndex) } } @@ -172,7 +172,7 @@ func TestSubDecCoins(t *testing.T) { msg string }{ { - NewDecCoins(Coins{NewCoin("mytoken", NewInt(10)), NewCoin("btc", NewInt(20)), NewCoin("eth", NewInt(30))}), + NewDecCoinsFromCoins(NewCoin("mytoken", NewInt(10)), NewCoin("btc", NewInt(20)), NewCoin("eth", NewInt(30))), true, "sorted coins should have passed", }, @@ -188,7 +188,7 @@ func TestSubDecCoins(t *testing.T) { }, } - decCoins := NewDecCoins(Coins{NewCoin("btc", NewInt(10)), NewCoin("eth", NewInt(15)), NewCoin("mytoken", NewInt(5))}) + decCoins := NewDecCoinsFromCoins(NewCoin("btc", NewInt(10)), NewCoin("eth", NewInt(15)), NewCoin("mytoken", NewInt(5))) for _, tc := range tests { tc := tc @@ -421,3 +421,75 @@ func TestDecCoinsQuoDecTruncate(t *testing.T) { } } } + +func TestNewDecCoinsWithIsValid(t *testing.T) { + fake1 := append(NewDecCoins(NewDecCoin("mytoken", NewInt(10))), DecCoin{Denom: "BTC", Amount: NewDec(10)}) + fake2 := append(NewDecCoins(NewDecCoin("mytoken", NewInt(10))), DecCoin{Denom: "BTC", Amount: NewDec(-10)}) + + tests := []struct { + coin DecCoins + expectPass bool + msg string + }{ + { + NewDecCoins(NewDecCoin("mytoken", NewInt(10))), + true, + "valid coins should have passed", + }, + { + fake1, + false, + "invalid denoms", + }, + { + fake2, + false, + "negative amount", + }, + } + + for _, tc := range tests { + tc := tc + if tc.expectPass { + require.True(t, tc.coin.IsValid(), tc.msg) + } else { + require.False(t, tc.coin.IsValid(), tc.msg) + } + } +} + +func TestDecCoins_AddDecCoinWithIsValid(t *testing.T) { + lengthTestDecCoins := NewDecCoins().Add(NewDecCoin("mytoken", NewInt(10))).Add(DecCoin{Denom: "BTC", Amount: NewDec(10)}) + require.Equal(t, 2, len(lengthTestDecCoins), "should be 2") + + tests := []struct { + coin DecCoins + expectPass bool + msg string + }{ + { + NewDecCoins().Add(NewDecCoin("mytoken", NewInt(10))), + true, + "valid coins should have passed", + }, + { + NewDecCoins().Add(NewDecCoin("mytoken", NewInt(10))).Add(DecCoin{Denom: "BTC", Amount: NewDec(10)}), + false, + "invalid denoms", + }, + { + NewDecCoins().Add(NewDecCoin("mytoken", NewInt(10))).Add(DecCoin{Denom: "BTC", Amount: NewDec(-10)}), + false, + "negative amount", + }, + } + + for _, tc := range tests { + tc := tc + if tc.expectPass { + require.True(t, tc.coin.IsValid(), tc.msg) + } else { + require.False(t, tc.coin.IsValid(), tc.msg) + } + } +} diff --git a/x/auth/types/stdtx.go b/x/auth/types/stdtx.go index bc6042abbbb2..34cd11b934a6 100644 --- a/x/auth/types/stdtx.go +++ b/x/auth/types/stdtx.go @@ -203,7 +203,7 @@ func (fee StdFee) Bytes() []byte { // originally part of the submitted transaction because the fee is computed // as fee = ceil(gasWanted * gasPrices). func (fee StdFee) GasPrices() sdk.DecCoins { - return sdk.NewDecCoins(fee.Amount).QuoDec(sdk.NewDec(int64(fee.Gas))) + return sdk.NewDecCoinsFromCoins(fee.Amount...).QuoDec(sdk.NewDec(int64(fee.Gas))) } //__________________________________________________________ diff --git a/x/auth/vesting/types/genesis_test.go b/x/auth/vesting/types/genesis_test.go index 4c90e52a42fd..aee8d1fa091a 100644 --- a/x/auth/vesting/types/genesis_test.go +++ b/x/auth/vesting/types/genesis_test.go @@ -25,7 +25,7 @@ func TestValidateGenesisInvalidAccounts(t *testing.T) { baseVestingAcc, err := NewBaseVestingAccount(&acc1, acc1.Coins, 1548775410) require.NoError(t, err) // invalid delegated vesting - baseVestingAcc.DelegatedVesting = acc1.Coins.Add(acc1.Coins) + baseVestingAcc.DelegatedVesting = acc1.Coins.Add(acc1.Coins...) acc2 := authtypes.NewBaseAccountWithAddress(sdk.AccAddress(addr2)) acc2.Coins = sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 150)) diff --git a/x/auth/vesting/types/vesting_account.go b/x/auth/vesting/types/vesting_account.go index da9343024f14..05dca2857e33 100644 --- a/x/auth/vesting/types/vesting_account.go +++ b/x/auth/vesting/types/vesting_account.go @@ -74,7 +74,7 @@ func (bva BaseVestingAccount) SpendableCoinsVestingAccount(vestingCoins sdk.Coin spendableCoin := sdk.NewCoin(coin.Denom, min) if !spendableCoin.IsZero() { - spendableCoins = spendableCoins.Add(sdk.Coins{spendableCoin}) + spendableCoins = spendableCoins.Add(spendableCoin) } } @@ -108,12 +108,12 @@ func (bva *BaseVestingAccount) TrackDelegation(vestingCoins, amount sdk.Coins) { if !x.IsZero() { xCoin := sdk.NewCoin(coin.Denom, x) - bva.DelegatedVesting = bva.DelegatedVesting.Add(sdk.Coins{xCoin}) + bva.DelegatedVesting = bva.DelegatedVesting.Add(xCoin) } if !y.IsZero() { yCoin := sdk.NewCoin(coin.Denom, y) - bva.DelegatedFree = bva.DelegatedFree.Add(sdk.Coins{yCoin}) + bva.DelegatedFree = bva.DelegatedFree.Add(yCoin) } } } @@ -543,7 +543,7 @@ func (pva PeriodicVestingAccount) GetVestedCoins(blockTime time.Time) sdk.Coins if x < period.Length { break } - vestedCoins = vestedCoins.Add(period.Amount) + vestedCoins = vestedCoins.Add(period.Amount...) // Update the start time of the next period currentPeriodStartTime += period.Length } @@ -589,7 +589,7 @@ func (pva PeriodicVestingAccount) Validate() error { originalVesting := sdk.NewCoins() for _, p := range pva.VestingPeriods { endTime += p.Length - originalVesting = originalVesting.Add(p.Amount) + originalVesting = originalVesting.Add(p.Amount...) } if endTime != pva.EndTime { return errors.New("vesting end time does not match length of all vesting periods") diff --git a/x/auth/vesting/types/vesting_account_test.go b/x/auth/vesting/types/vesting_account_test.go index 8c87cbb9af1e..651416338c06 100644 --- a/x/auth/vesting/types/vesting_account_test.go +++ b/x/auth/vesting/types/vesting_account_test.go @@ -96,7 +96,7 @@ func TestSpendableCoinsContVestingAcc(t *testing.T) { // receive some coins recvAmt := sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)} - cva.SetCoins(cva.GetCoins().Add(recvAmt)) + cva.SetCoins(cva.GetCoins().Add(recvAmt...)) // require that all vested coins (50%) are spendable plus any received spendableCoins = cva.SpendableCoins(now.Add(12 * time.Hour)) @@ -268,7 +268,7 @@ func TestSpendableCoinsDelVestingAcc(t *testing.T) { // receive some coins recvAmt := sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)} - dva.SetCoins(dva.GetCoins().Add(recvAmt)) + dva.SetCoins(dva.GetCoins().Add(recvAmt...)) // require that only received coins are spendable since the account is still // vesting @@ -497,7 +497,7 @@ func TestSpendableCoinsPeriodicVestingAcc(t *testing.T) { // receive some coins recvAmt := sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)} - pva.SetCoins(pva.GetCoins().Add(recvAmt)) + pva.SetCoins(pva.GetCoins().Add(recvAmt...)) // require that all vested coins (50%) are spendable plus any received spendableCoins = pva.SpendableCoins(now.Add(12 * time.Hour)) @@ -549,7 +549,7 @@ func TestTrackDelegationPeriodicVestingAcc(t *testing.T) { // delegate 75% of coins, split between vested and vesting bacc.SetCoins(origCoins) pva = NewPeriodicVestingAccount(&bacc, now.Unix(), periods) - pva.TrackDelegation(now.Add(12*time.Hour), periods[0].Amount.Add(periods[1].Amount)) + pva.TrackDelegation(now.Add(12*time.Hour), periods[0].Amount.Add(periods[1].Amount...)) // require that the maximum possible amount of vesting coins are chosen for delegation. require.Equal(t, pva.DelegatedFree, periods[1].Amount) require.Equal(t, pva.DelegatedVesting, periods[0].Amount) diff --git a/x/bank/internal/keeper/keeper.go b/x/bank/internal/keeper/keeper.go index f36477f3c3b1..64e539c44ce2 100644 --- a/x/bank/internal/keeper/keeper.go +++ b/x/bank/internal/keeper/keeper.go @@ -280,7 +280,7 @@ func (keeper BaseSendKeeper) AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt } oldCoins := keeper.GetCoins(ctx, addr) - newCoins := oldCoins.Add(amt) + newCoins := oldCoins.Add(amt...) if newCoins.IsAnyNegative() { return amt, sdkerrors.Wrapf( @@ -387,5 +387,5 @@ func trackUndelegation(acc authexported.Account, amt sdk.Coins) error { vacc.TrackUndelegation(amt) } - return acc.SetCoins(acc.GetCoins().Add(amt)) + return acc.SetCoins(acc.GetCoins().Add(amt...)) } diff --git a/x/bank/internal/keeper/keeper_test.go b/x/bank/internal/keeper/keeper_test.go index f93ddaa52969..f028f054f840 100644 --- a/x/bank/internal/keeper/keeper_test.go +++ b/x/bank/internal/keeper/keeper_test.go @@ -240,7 +240,7 @@ func TestVestingAccountSend(t *testing.T) { require.Error(t, err) // receive some coins - vacc.SetCoins(origCoins.Add(sendCoins)) + vacc.SetCoins(origCoins.Add(sendCoins...)) app.AccountKeeper.SetAccount(ctx, vacc) // require that all vested coins are spendable plus any received @@ -275,7 +275,7 @@ func TestPeriodicVestingAccountSend(t *testing.T) { require.Error(t, err) // receive some coins - vacc.SetCoins(origCoins.Add(sendCoins)) + vacc.SetCoins(origCoins.Add(sendCoins...)) app.AccountKeeper.SetAccount(ctx, vacc) // require that all vested coins are spendable plus any received @@ -311,7 +311,7 @@ func TestVestingAccountReceive(t *testing.T) { // require the coins are spendable vacc = app.AccountKeeper.GetAccount(ctx, addr1).(*vesting.ContinuousVestingAccount) - require.Equal(t, origCoins.Add(sendCoins), vacc.GetCoins()) + require.Equal(t, origCoins.Add(sendCoins...), vacc.GetCoins()) require.Equal(t, vacc.SpendableCoins(now), sendCoins) // require coins are spendable plus any that have vested @@ -347,7 +347,7 @@ func TestPeriodicVestingAccountReceive(t *testing.T) { // require the coins are spendable vacc = app.AccountKeeper.GetAccount(ctx, addr1).(*vesting.PeriodicVestingAccount) - require.Equal(t, origCoins.Add(sendCoins), vacc.GetCoins()) + require.Equal(t, origCoins.Add(sendCoins...), vacc.GetCoins()) require.Equal(t, vacc.SpendableCoins(now), sendCoins) // require coins are spendable plus any that have vested diff --git a/x/bank/internal/types/msgs.go b/x/bank/internal/types/msgs.go index c8fdaa5afe92..50f8e3f06ff1 100644 --- a/x/bank/internal/types/msgs.go +++ b/x/bank/internal/types/msgs.go @@ -168,7 +168,7 @@ func ValidateInputsOutputs(inputs []Input, outputs []Output) error { return err } - totalIn = totalIn.Add(in.Coins) + totalIn = totalIn.Add(in.Coins...) } for _, out := range outputs { @@ -176,7 +176,7 @@ func ValidateInputsOutputs(inputs []Input, outputs []Output) error { return err } - totalOut = totalOut.Add(out.Coins) + totalOut = totalOut.Add(out.Coins...) } // make sure inputs and outputs match diff --git a/x/bank/simulation/operations.go b/x/bank/simulation/operations.go index 7cf08a8452f2..123e0b8eb45a 100644 --- a/x/bank/simulation/operations.go +++ b/x/bank/simulation/operations.go @@ -170,7 +170,7 @@ func SimulateMsgMultiSend(ak types.AccountKeeper, bk keeper.Keeper) simulation.O // set next input and accumulate total sent coins inputs[i] = types.NewInput(simAccount.Address, coins) - totalSentCoins = totalSentCoins.Add(coins) + totalSentCoins = totalSentCoins.Add(coins...) } for o := range outputs { diff --git a/x/crisis/handler_test.go b/x/crisis/handler_test.go index 290b0c373cdb..912bd863f7c5 100644 --- a/x/crisis/handler_test.go +++ b/x/crisis/handler_test.go @@ -36,7 +36,7 @@ func createTestApp() (*simapp.SimApp, sdk.Context, []sdk.AccAddress) { app.CrisisKeeper.RegisterRoute(testModuleName, dummyRouteWhichFails.Route, dummyRouteWhichFails.Invar) feePool := distr.InitialFeePool() - feePool.CommunityPool = sdk.NewDecCoins(sdk.NewCoins(constantFee)) + feePool.CommunityPool = sdk.NewDecCoinsFromCoins(sdk.NewCoins(constantFee)...) app.DistrKeeper.SetFeePool(ctx, feePool) app.SupplyKeeper.SetSupply(ctx, supply.NewSupply(sdk.Coins{})) diff --git a/x/distribution/genesis.go b/x/distribution/genesis.go index 3da1710fe6ec..c0fc05b9ea71 100644 --- a/x/distribution/genesis.go +++ b/x/distribution/genesis.go @@ -23,7 +23,7 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, supplyKeeper types.SupplyKeeper keeper.SetPreviousProposerConsAddr(ctx, data.PreviousProposer) for _, rew := range data.OutstandingRewards { keeper.SetValidatorOutstandingRewards(ctx, rew.ValidatorAddress, rew.OutstandingRewards) - moduleHoldings = moduleHoldings.Add(rew.OutstandingRewards) + moduleHoldings = moduleHoldings.Add(rew.OutstandingRewards...) } for _, acc := range data.ValidatorAccumulatedCommissions { keeper.SetValidatorAccumulatedCommission(ctx, acc.ValidatorAddress, acc.Accumulated) @@ -41,7 +41,7 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, supplyKeeper types.SupplyKeeper keeper.SetValidatorSlashEvent(ctx, evt.ValidatorAddress, evt.Height, evt.Period, evt.Event) } - moduleHoldings = moduleHoldings.Add(data.FeePool.CommunityPool) + moduleHoldings = moduleHoldings.Add(data.FeePool.CommunityPool...) moduleHoldingsInt, _ := moduleHoldings.TruncateDecimal() // check if the module account exists diff --git a/x/distribution/keeper/allocation.go b/x/distribution/keeper/allocation.go index 43a659999a7c..b6a34a3d643b 100644 --- a/x/distribution/keeper/allocation.go +++ b/x/distribution/keeper/allocation.go @@ -23,7 +23,7 @@ func (k Keeper) AllocateTokens( // (and distributed to the previous proposer) feeCollector := k.supplyKeeper.GetModuleAccount(ctx, k.feeCollectorName) feesCollectedInt := feeCollector.GetCoins() - feesCollected := sdk.NewDecCoins(feesCollectedInt) + feesCollected := sdk.NewDecCoinsFromCoins(feesCollectedInt...) // transfer collected fees to the distribution module account err := k.supplyKeeper.SendCoinsFromModuleToModule(ctx, k.feeCollectorName, types.ModuleName, feesCollectedInt) @@ -35,7 +35,7 @@ func (k Keeper) AllocateTokens( // general discussions here: https://github.com/cosmos/cosmos-sdk/issues/2906#issuecomment-441867634 feePool := k.GetFeePool(ctx) if totalPreviousPower == 0 { - feePool.CommunityPool = feePool.CommunityPool.Add(feesCollected) + feePool.CommunityPool = feePool.CommunityPool.Add(feesCollected...) k.SetFeePool(ctx, feePool) return } @@ -95,7 +95,7 @@ func (k Keeper) AllocateTokens( } // allocate community funding - feePool.CommunityPool = feePool.CommunityPool.Add(remaining) + feePool.CommunityPool = feePool.CommunityPool.Add(remaining...) k.SetFeePool(ctx, feePool) } @@ -114,12 +114,12 @@ func (k Keeper) AllocateTokensToValidator(ctx sdk.Context, val exported.Validato ), ) currentCommission := k.GetValidatorAccumulatedCommission(ctx, val.GetOperator()) - currentCommission = currentCommission.Add(commission) + currentCommission = currentCommission.Add(commission...) k.SetValidatorAccumulatedCommission(ctx, val.GetOperator(), currentCommission) // update current rewards currentRewards := k.GetValidatorCurrentRewards(ctx, val.GetOperator()) - currentRewards.Rewards = currentRewards.Rewards.Add(shared) + currentRewards.Rewards = currentRewards.Rewards.Add(shared...) k.SetValidatorCurrentRewards(ctx, val.GetOperator(), currentRewards) // update outstanding rewards @@ -131,6 +131,6 @@ func (k Keeper) AllocateTokensToValidator(ctx sdk.Context, val exported.Validato ), ) outstanding := k.GetValidatorOutstandingRewards(ctx, val.GetOperator()) - outstanding = outstanding.Add(tokens) + outstanding = outstanding.Add(tokens...) k.SetValidatorOutstandingRewards(ctx, val.GetOperator(), outstanding) } diff --git a/x/distribution/keeper/delegation.go b/x/distribution/keeper/delegation.go index 7b28b6048eaf..7d79a35b40b9 100644 --- a/x/distribution/keeper/delegation.go +++ b/x/distribution/keeper/delegation.go @@ -81,7 +81,7 @@ func (k Keeper) calculateDelegationRewards(ctx sdk.Context, val exported.Validat func(height uint64, event types.ValidatorSlashEvent) (stop bool) { endingPeriod := event.ValidatorPeriod if endingPeriod > startingPeriod { - rewards = rewards.Add(k.calculateDelegationRewardsBetween(ctx, val, startingPeriod, endingPeriod, stake)) + rewards = rewards.Add(k.calculateDelegationRewardsBetween(ctx, val, startingPeriod, endingPeriod, stake)...) // Note: It is necessary to truncate so we don't allow withdrawing // more rewards than owed. @@ -132,7 +132,7 @@ func (k Keeper) calculateDelegationRewards(ctx sdk.Context, val exported.Validat } // calculate rewards for final period - rewards = rewards.Add(k.calculateDelegationRewardsBetween(ctx, val, startingPeriod, endingPeriod, stake)) + rewards = rewards.Add(k.calculateDelegationRewardsBetween(ctx, val, startingPeriod, endingPeriod, stake)...) return rewards } @@ -173,7 +173,7 @@ func (k Keeper) withdrawDelegationRewards(ctx sdk.Context, val exported.Validato // transaction was successful k.SetValidatorOutstandingRewards(ctx, del.GetValidatorAddr(), outstanding.Sub(rewards)) feePool := k.GetFeePool(ctx) - feePool.CommunityPool = feePool.CommunityPool.Add(remainder) + feePool.CommunityPool = feePool.CommunityPool.Add(remainder...) k.SetFeePool(ctx, feePool) // decrement reference count of starting period diff --git a/x/distribution/keeper/fee_pool.go b/x/distribution/keeper/fee_pool.go index 34ad5f0d0d06..02107bb815aa 100644 --- a/x/distribution/keeper/fee_pool.go +++ b/x/distribution/keeper/fee_pool.go @@ -13,7 +13,7 @@ func (k Keeper) DistributeFromFeePool(ctx sdk.Context, amount sdk.Coins, receive // NOTE the community pool isn't a module account, however its coins // are held in the distribution module account. Thus the community pool // must be reduced separately from the SendCoinsFromModuleToAccount call - newPool, negative := feePool.CommunityPool.SafeSub(sdk.NewDecCoins(amount)) + newPool, negative := feePool.CommunityPool.SafeSub(sdk.NewDecCoinsFromCoins(amount...)) if negative { return types.ErrBadDistribution } diff --git a/x/distribution/keeper/hooks.go b/x/distribution/keeper/hooks.go index 598809b30a72..e7f843dd2bd7 100644 --- a/x/distribution/keeper/hooks.go +++ b/x/distribution/keeper/hooks.go @@ -39,7 +39,7 @@ func (h Hooks) AfterValidatorRemoved(ctx sdk.Context, _ sdk.ConsAddress, valAddr // remainder to community pool feePool := h.k.GetFeePool(ctx) - feePool.CommunityPool = feePool.CommunityPool.Add(remainder) + feePool.CommunityPool = feePool.CommunityPool.Add(remainder...) h.k.SetFeePool(ctx, feePool) // add to validator account @@ -56,7 +56,7 @@ func (h Hooks) AfterValidatorRemoved(ctx sdk.Context, _ sdk.ConsAddress, valAddr // add outstanding to community pool feePool := h.k.GetFeePool(ctx) - feePool.CommunityPool = feePool.CommunityPool.Add(outstanding) + feePool.CommunityPool = feePool.CommunityPool.Add(outstanding...) h.k.SetFeePool(ctx, feePool) // delete outstanding diff --git a/x/distribution/keeper/invariants.go b/x/distribution/keeper/invariants.go index 4ae8dfb469f6..cff02da07691 100644 --- a/x/distribution/keeper/invariants.go +++ b/x/distribution/keeper/invariants.go @@ -140,12 +140,12 @@ func ModuleAccountInvariant(k Keeper) sdk.Invariant { var expectedCoins sdk.DecCoins k.IterateValidatorOutstandingRewards(ctx, func(_ sdk.ValAddress, rewards types.ValidatorOutstandingRewards) (stop bool) { - expectedCoins = expectedCoins.Add(rewards) + expectedCoins = expectedCoins.Add(rewards...) return false }) communityPool := k.GetFeePoolCommunityCoins(ctx) - expectedInt, _ := expectedCoins.Add(communityPool).TruncateDecimal() + expectedInt, _ := expectedCoins.Add(communityPool...).TruncateDecimal() macc := k.GetDistributionAccount(ctx) diff --git a/x/distribution/keeper/keeper.go b/x/distribution/keeper/keeper.go index 76b582bae209..1ce723d11418 100644 --- a/x/distribution/keeper/keeper.go +++ b/x/distribution/keeper/keeper.go @@ -118,7 +118,7 @@ func (k Keeper) WithdrawValidatorCommission(ctx sdk.Context, valAddr sdk.ValAddr // update outstanding outstanding := k.GetValidatorOutstandingRewards(ctx, valAddr) - k.SetValidatorOutstandingRewards(ctx, valAddr, outstanding.Sub(sdk.NewDecCoins(commission))) + k.SetValidatorOutstandingRewards(ctx, valAddr, outstanding.Sub(sdk.NewDecCoinsFromCoins(commission...))) if !commission.IsZero() { accAddr := sdk.AccAddress(valAddr) @@ -143,7 +143,7 @@ func (k Keeper) WithdrawValidatorCommission(ctx sdk.Context, valAddr sdk.ValAddr func (k Keeper) GetTotalRewards(ctx sdk.Context) (totalRewards sdk.DecCoins) { k.IterateValidatorOutstandingRewards(ctx, func(_ sdk.ValAddress, rewards types.ValidatorOutstandingRewards) (stop bool) { - totalRewards = totalRewards.Add(rewards) + totalRewards = totalRewards.Add(rewards...) return false }, ) @@ -161,7 +161,7 @@ func (k Keeper) FundCommunityPool(ctx sdk.Context, amount sdk.Coins, sender sdk. } feePool := k.GetFeePool(ctx) - feePool.CommunityPool = feePool.CommunityPool.Add(sdk.NewDecCoins(amount)) + feePool.CommunityPool = feePool.CommunityPool.Add(sdk.NewDecCoinsFromCoins(amount...)...) k.SetFeePool(ctx, feePool) return nil diff --git a/x/distribution/keeper/keeper_test.go b/x/distribution/keeper/keeper_test.go index f0421d80ee5a..2536104c3b6b 100644 --- a/x/distribution/keeper/keeper_test.go +++ b/x/distribution/keeper/keeper_test.go @@ -105,6 +105,6 @@ func TestFundCommunityPool(t *testing.T) { err := keeper.FundCommunityPool(ctx, amount, delAddr1) assert.Nil(t, err) - assert.Equal(t, initPool.CommunityPool.Add(sdk.NewDecCoins(amount)), keeper.GetFeePool(ctx).CommunityPool) + assert.Equal(t, initPool.CommunityPool.Add(sdk.NewDecCoinsFromCoins(amount...)...), keeper.GetFeePool(ctx).CommunityPool) assert.Empty(t, bk.GetCoins(ctx, delAddr1)) } diff --git a/x/distribution/keeper/querier.go b/x/distribution/keeper/querier.go index 7e7c404cee14..641f59c29123 100644 --- a/x/distribution/keeper/querier.go +++ b/x/distribution/keeper/querier.go @@ -202,8 +202,7 @@ func queryDelegatorTotalRewards(ctx sdk.Context, _ []string, req abci.RequestQue delReward := k.calculateDelegationRewards(ctx, val, del, endingPeriod) delRewards = append(delRewards, types.NewDelegationDelegatorReward(valAddr, delReward)) - total = total.Add(delReward) - + total = total.Add(delReward...) return false }, ) diff --git a/x/distribution/keeper/validator.go b/x/distribution/keeper/validator.go index 4b0a4bbd6c42..ccedb7ede163 100644 --- a/x/distribution/keeper/validator.go +++ b/x/distribution/keeper/validator.go @@ -37,7 +37,7 @@ func (k Keeper) incrementValidatorPeriod(ctx sdk.Context, val exported.Validator // ergo we instead add to the community pool feePool := k.GetFeePool(ctx) outstanding := k.GetValidatorOutstandingRewards(ctx, val.GetOperator()) - feePool.CommunityPool = feePool.CommunityPool.Add(rewards.Rewards) + feePool.CommunityPool = feePool.CommunityPool.Add(rewards.Rewards...) outstanding = outstanding.Sub(rewards.Rewards) k.SetFeePool(ctx, feePool) k.SetValidatorOutstandingRewards(ctx, val.GetOperator(), outstanding) @@ -55,7 +55,7 @@ func (k Keeper) incrementValidatorPeriod(ctx sdk.Context, val exported.Validator k.decrementReferenceCount(ctx, val.GetOperator(), rewards.Period-1) // set new historical rewards with reference count of 1 - k.SetValidatorHistoricalRewards(ctx, val.GetOperator(), rewards.Period, types.NewValidatorHistoricalRewards(historical.Add(current), 1)) + k.SetValidatorHistoricalRewards(ctx, val.GetOperator(), rewards.Period, types.NewValidatorHistoricalRewards(historical.Add(current...), 1)) // set current rewards, incrementing period by 1 k.SetValidatorCurrentRewards(ctx, val.GetOperator(), types.NewValidatorCurrentRewards(sdk.DecCoins{}, rewards.Period+1)) diff --git a/x/distribution/proposal_handler_test.go b/x/distribution/proposal_handler_test.go index 6a451b41e0ac..1aeee1f2880a 100644 --- a/x/distribution/proposal_handler_test.go +++ b/x/distribution/proposal_handler_test.go @@ -33,7 +33,7 @@ func TestProposalHandlerPassed(t *testing.T) { // add coins to the module account macc := keeper.GetDistributionAccount(ctx) - err := macc.SetCoins(macc.GetCoins().Add(amount)) + err := macc.SetCoins(macc.GetCoins().Add(amount...)) require.NoError(t, err) supplyKeeper.SetModuleAccount(ctx, macc) @@ -43,7 +43,7 @@ func TestProposalHandlerPassed(t *testing.T) { accountKeeper.SetAccount(ctx, account) feePool := keeper.GetFeePool(ctx) - feePool.CommunityPool = sdk.NewDecCoins(amount) + feePool.CommunityPool = sdk.NewDecCoinsFromCoins(amount...) keeper.SetFeePool(ctx, feePool) tp := testProposal(recipient, amount) diff --git a/x/genaccounts/legacy/v0_36/migrate.go b/x/genaccounts/legacy/v0_36/migrate.go index d69aece98156..7fea5fed3f28 100644 --- a/x/genaccounts/legacy/v0_36/migrate.go +++ b/x/genaccounts/legacy/v0_36/migrate.go @@ -75,7 +75,7 @@ func Migrate( var expDeposits sdk.Coins for _, deposit := range deposits { - expDeposits = expDeposits.Add(deposit.Deposit.Amount) + expDeposits = expDeposits.Add(deposit.Deposit.Amount...) } if !expDeposits.IsEqual(govCoins) { @@ -113,10 +113,10 @@ func Migrate( // get distr module account coins var distrDecCoins sdk.DecCoins for _, reward := range valOutRewards { - distrDecCoins = distrDecCoins.Add(reward.OutstandingRewards) + distrDecCoins = distrDecCoins.Add(reward.OutstandingRewards...) } - distrCoins, _ := distrDecCoins.Add(communityPool).TruncateDecimal() + distrCoins, _ := distrDecCoins.Add(communityPool...).TruncateDecimal() // get module account addresses feeCollectorAddr := sdk.AccAddress(crypto.AddressHash([]byte(feeCollectorName))) diff --git a/x/gov/abci_test.go b/x/gov/abci_test.go index 6ee3a3075920..db5509f45e18 100644 --- a/x/gov/abci_test.go +++ b/x/gov/abci_test.go @@ -279,7 +279,7 @@ func TestProposalPassedEndblocker(t *testing.T) { require.NotNil(t, macc) moduleAccCoins := macc.GetCoins() - deposits := initialModuleAccCoins.Add(proposal.TotalDeposit).Add(proposalCoins) + deposits := initialModuleAccCoins.Add(proposal.TotalDeposit...).Add(proposalCoins...) require.True(t, moduleAccCoins.IsEqual(deposits)) err = input.keeper.AddVote(ctx, proposal.ProposalID, input.addrs[0], OptionYes) diff --git a/x/gov/genesis.go b/x/gov/genesis.go index 0eb019fc2d86..b487c23ef85d 100644 --- a/x/gov/genesis.go +++ b/x/gov/genesis.go @@ -24,7 +24,7 @@ func InitGenesis(ctx sdk.Context, k Keeper, supplyKeeper types.SupplyKeeper, dat var totalDeposits sdk.Coins for _, deposit := range data.Deposits { k.SetDeposit(ctx, deposit) - totalDeposits = totalDeposits.Add(deposit.Amount) + totalDeposits = totalDeposits.Add(deposit.Amount...) } for _, vote := range data.Votes { diff --git a/x/gov/keeper/deposit.go b/x/gov/keeper/deposit.go index c86df046e5e0..423679998b44 100644 --- a/x/gov/keeper/deposit.go +++ b/x/gov/keeper/deposit.go @@ -113,7 +113,7 @@ func (keeper Keeper) AddDeposit(ctx sdk.Context, proposalID uint64, depositorAdd } // Update proposal - proposal.TotalDeposit = proposal.TotalDeposit.Add(depositAmount) + proposal.TotalDeposit = proposal.TotalDeposit.Add(depositAmount...) keeper.SetProposal(ctx, proposal) // Check if deposit has provided sufficient total funds to transition the proposal into the voting period @@ -126,7 +126,7 @@ func (keeper Keeper) AddDeposit(ctx sdk.Context, proposalID uint64, depositorAdd // Add or update deposit object deposit, found := keeper.GetDeposit(ctx, proposalID, depositorAddr) if found { - deposit.Amount = deposit.Amount.Add(depositAmount) + deposit.Amount = deposit.Amount.Add(depositAmount...) } else { deposit = types.NewDeposit(proposalID, depositorAddr, depositAmount) } diff --git a/x/gov/keeper/deposit_test.go b/x/gov/keeper/deposit_test.go index b5d6cce405a2..edf452464094 100644 --- a/x/gov/keeper/deposit_test.go +++ b/x/gov/keeper/deposit_test.go @@ -51,11 +51,11 @@ func TestDeposits(t *testing.T) { require.False(t, votingStarted) deposit, found = keeper.GetDeposit(ctx, proposalID, TestAddrs[0]) require.True(t, found) - require.Equal(t, fourStake.Add(fiveStake), deposit.Amount) + require.Equal(t, fourStake.Add(fiveStake...), deposit.Amount) require.Equal(t, TestAddrs[0], deposit.Depositor) proposal, ok = keeper.GetProposal(ctx, proposalID) require.True(t, ok) - require.Equal(t, fourStake.Add(fiveStake), proposal.TotalDeposit) + require.Equal(t, fourStake.Add(fiveStake...), proposal.TotalDeposit) require.Equal(t, addr0Initial.Sub(fourStake).Sub(fiveStake), ak.GetAccount(ctx, TestAddrs[0]).GetCoins()) // Check third deposit from a new address @@ -68,7 +68,7 @@ func TestDeposits(t *testing.T) { require.Equal(t, fourStake, deposit.Amount) proposal, ok = keeper.GetProposal(ctx, proposalID) require.True(t, ok) - require.Equal(t, fourStake.Add(fiveStake).Add(fourStake), proposal.TotalDeposit) + require.Equal(t, fourStake.Add(fiveStake...).Add(fourStake...), proposal.TotalDeposit) require.Equal(t, addr1Initial.Sub(fourStake), ak.GetAccount(ctx, TestAddrs[1]).GetCoins()) // Check that proposal moved to voting period @@ -82,7 +82,7 @@ func TestDeposits(t *testing.T) { require.Len(t, deposits, 2) require.Equal(t, deposits, keeper.GetDeposits(ctx, proposalID)) require.Equal(t, TestAddrs[0], deposits[0].Depositor) - require.Equal(t, fourStake.Add(fiveStake), deposits[0].Amount) + require.Equal(t, fourStake.Add(fiveStake...), deposits[0].Amount) require.Equal(t, TestAddrs[1], deposits[1].Depositor) require.Equal(t, fourStake, deposits[1].Amount) diff --git a/x/gov/keeper/invariants.go b/x/gov/keeper/invariants.go index 2350ea553e6b..1ebe62c15d0a 100644 --- a/x/gov/keeper/invariants.go +++ b/x/gov/keeper/invariants.go @@ -28,7 +28,7 @@ func ModuleAccountInvariant(keeper Keeper) sdk.Invariant { var expectedDeposits sdk.Coins keeper.IterateAllDeposits(ctx, func(deposit types.Deposit) bool { - expectedDeposits = expectedDeposits.Add(deposit.Amount) + expectedDeposits = expectedDeposits.Add(deposit.Amount...) return false }) diff --git a/x/gov/keeper/querier_test.go b/x/gov/keeper/querier_test.go index b8cce877608c..f79057f03e96 100644 --- a/x/gov/keeper/querier_test.go +++ b/x/gov/keeper/querier_test.go @@ -159,7 +159,7 @@ func TestQueries(t *testing.T) { _, err = keeper.AddDeposit(ctx, deposit1.ProposalID, deposit1.Depositor, deposit1.Amount) require.NoError(t, err) - proposal1.TotalDeposit = proposal1.TotalDeposit.Add(deposit1.Amount) + proposal1.TotalDeposit = proposal1.TotalDeposit.Add(deposit1.Amount...) proposal2, err := keeper.SubmitProposal(ctx, tp) require.NoError(t, err) @@ -167,7 +167,7 @@ func TestQueries(t *testing.T) { _, err = keeper.AddDeposit(ctx, deposit2.ProposalID, deposit2.Depositor, deposit2.Amount) require.NoError(t, err) - proposal2.TotalDeposit = proposal2.TotalDeposit.Add(deposit2.Amount) + proposal2.TotalDeposit = proposal2.TotalDeposit.Add(deposit2.Amount...) // TestAddrs[1] proposes (and deposits) on proposal #3 proposal3, err := keeper.SubmitProposal(ctx, tp) @@ -176,14 +176,14 @@ func TestQueries(t *testing.T) { _, err = keeper.AddDeposit(ctx, deposit3.ProposalID, deposit3.Depositor, deposit3.Amount) require.NoError(t, err) - proposal3.TotalDeposit = proposal3.TotalDeposit.Add(deposit3.Amount) + proposal3.TotalDeposit = proposal3.TotalDeposit.Add(deposit3.Amount...) // TestAddrs[1] deposits on proposals #2 & #3 deposit4 := types.NewDeposit(proposal2.ProposalID, TestAddrs[1], depositParams.MinDeposit) _, err = keeper.AddDeposit(ctx, deposit4.ProposalID, deposit4.Depositor, deposit4.Amount) require.NoError(t, err) - proposal2.TotalDeposit = proposal2.TotalDeposit.Add(deposit4.Amount) + proposal2.TotalDeposit = proposal2.TotalDeposit.Add(deposit4.Amount...) proposal2.Status = types.StatusVotingPeriod proposal2.VotingEndTime = proposal2.VotingEndTime.Add(types.DefaultPeriod) @@ -191,11 +191,11 @@ func TestQueries(t *testing.T) { _, err = keeper.AddDeposit(ctx, deposit5.ProposalID, deposit5.Depositor, deposit5.Amount) require.NoError(t, err) - proposal3.TotalDeposit = proposal3.TotalDeposit.Add(deposit5.Amount) + proposal3.TotalDeposit = proposal3.TotalDeposit.Add(deposit5.Amount...) proposal3.Status = types.StatusVotingPeriod proposal3.VotingEndTime = proposal3.VotingEndTime.Add(types.DefaultPeriod) // total deposit of TestAddrs[1] on proposal #3 is worth the proposal deposit + individual deposit - deposit5.Amount = deposit5.Amount.Add(deposit3.Amount) + deposit5.Amount = deposit5.Amount.Add(deposit3.Amount...) // check deposits on proposal1 match individual deposits deposits := getQueriedDeposits(t, ctx, keeper.cdc, querier, proposal1.ProposalID) diff --git a/x/mock/app.go b/x/mock/app.go index d0cee9f592af..29448e8a9067 100644 --- a/x/mock/app.go +++ b/x/mock/app.go @@ -299,7 +299,7 @@ func RandomSetGenesis(r *rand.Rand, app *App, addrs []sdk.AccAddress, denoms []s } } - app.TotalCoinsSupply = app.TotalCoinsSupply.Add(coins) + app.TotalCoinsSupply = app.TotalCoinsSupply.Add(coins...) baseAcc := auth.NewBaseAccountWithAddress(addrs[i]) (&baseAcc).SetCoins(coins) diff --git a/x/mock/types.go b/x/mock/types.go index 56912780dac1..43dfbaecbb94 100644 --- a/x/mock/types.go +++ b/x/mock/types.go @@ -31,7 +31,7 @@ func (sk DummySupplyKeeper) SendCoinsFromAccountToModule(ctx sdk.Context, fromAd return sdkerrors.Wrap(sdkerrors.ErrInsufficientFunds, fromAcc.GetCoins().String()) } - newToCoins := moduleAcc.GetCoins().Add(amt) + newToCoins := moduleAcc.GetCoins().Add(amt...) if err := fromAcc.SetCoins(newFromCoins); err != nil { return err diff --git a/x/staking/keeper/delegation_test.go b/x/staking/keeper/delegation_test.go index 01620d762cfa..e3e619697679 100644 --- a/x/staking/keeper/delegation_test.go +++ b/x/staking/keeper/delegation_test.go @@ -296,7 +296,7 @@ func TestUndelegateSelfDelegationBelowMinSelfDelegation(t *testing.T) { // add bonded tokens to pool for delegations notBondedPool := keeper.GetNotBondedPool(ctx) - err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(delCoins)) + err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(delCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) @@ -308,7 +308,7 @@ func TestUndelegateSelfDelegationBelowMinSelfDelegation(t *testing.T) { // add bonded tokens to pool for delegations bondedPool := keeper.GetBondedPool(ctx) - err = bondedPool.SetCoins(bondedPool.GetCoins().Add(delCoins)) + err = bondedPool.SetCoins(bondedPool.GetCoins().Add(delCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) @@ -320,7 +320,7 @@ func TestUndelegateSelfDelegationBelowMinSelfDelegation(t *testing.T) { // add bonded tokens to pool for delegations bondedPool = keeper.GetBondedPool(ctx) - err = bondedPool.SetCoins(bondedPool.GetCoins().Add(delCoins)) + err = bondedPool.SetCoins(bondedPool.GetCoins().Add(delCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) @@ -356,7 +356,7 @@ func TestUndelegateFromUnbondingValidator(t *testing.T) { // add bonded tokens to pool for delegations notBondedPool := keeper.GetNotBondedPool(ctx) - err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(delCoins)) + err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(delCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) @@ -367,7 +367,7 @@ func TestUndelegateFromUnbondingValidator(t *testing.T) { keeper.SetDelegation(ctx, selfDelegation) bondedPool := keeper.GetBondedPool(ctx) - err = bondedPool.SetCoins(bondedPool.GetCoins().Add(delCoins)) + err = bondedPool.SetCoins(bondedPool.GetCoins().Add(delCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) @@ -378,7 +378,7 @@ func TestUndelegateFromUnbondingValidator(t *testing.T) { require.Equal(t, delTokens, issuedShares.RoundInt()) bondedPool = keeper.GetBondedPool(ctx) - err = bondedPool.SetCoins(bondedPool.GetCoins().Add(delCoins)) + err = bondedPool.SetCoins(bondedPool.GetCoins().Add(delCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) @@ -387,7 +387,7 @@ func TestUndelegateFromUnbondingValidator(t *testing.T) { keeper.SetDelegation(ctx, delegation) bondedPool = keeper.GetBondedPool(ctx) - err = bondedPool.SetCoins(bondedPool.GetCoins().Add(delCoins)) + err = bondedPool.SetCoins(bondedPool.GetCoins().Add(delCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) @@ -438,7 +438,7 @@ func TestUndelegateFromUnbondedValidator(t *testing.T) { // add bonded tokens to pool for delegations notBondedPool := keeper.GetNotBondedPool(ctx) - err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(delCoins)) + err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(delCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) @@ -456,7 +456,7 @@ func TestUndelegateFromUnbondedValidator(t *testing.T) { keeper.SetDelegation(ctx, selfDelegation) bondedPool := keeper.GetBondedPool(ctx) - err = bondedPool.SetCoins(bondedPool.GetCoins().Add(delCoins)) + err = bondedPool.SetCoins(bondedPool.GetCoins().Add(delCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) @@ -517,7 +517,7 @@ func TestUnbondingAllDelegationFromValidator(t *testing.T) { // add bonded tokens to pool for delegations notBondedPool := keeper.GetNotBondedPool(ctx) - err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(delCoins)) + err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(delCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) @@ -541,7 +541,7 @@ func TestUnbondingAllDelegationFromValidator(t *testing.T) { require.Equal(t, delTokens, issuedShares.RoundInt()) bondedPool := keeper.GetBondedPool(ctx) - err = bondedPool.SetCoins(bondedPool.GetCoins().Add(delCoins)) + err = bondedPool.SetCoins(bondedPool.GetCoins().Add(delCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) @@ -672,7 +672,7 @@ func TestRedelegateToSameValidator(t *testing.T) { // add bonded tokens to pool for delegations notBondedPool := keeper.GetNotBondedPool(ctx) - err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(startCoins)) + err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(startCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) @@ -699,7 +699,7 @@ func TestRedelegationMaxEntries(t *testing.T) { // add bonded tokens to pool for delegations notBondedPool := keeper.GetNotBondedPool(ctx) - err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(startCoins)) + err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(startCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) @@ -752,7 +752,7 @@ func TestRedelegateSelfDelegation(t *testing.T) { // add bonded tokens to pool for delegations notBondedPool := keeper.GetNotBondedPool(ctx) - err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(startCoins)) + err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(startCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) @@ -804,7 +804,7 @@ func TestRedelegateFromUnbondingValidator(t *testing.T) { // add bonded tokens to pool for delegations notBondedPool := keeper.GetNotBondedPool(ctx) - err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(startCoins)) + err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(startCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) @@ -883,7 +883,7 @@ func TestRedelegateFromUnbondedValidator(t *testing.T) { // add bonded tokens to pool for delegations notBondedPool := keeper.GetNotBondedPool(ctx) - err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(startCoins)) + err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(startCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) diff --git a/x/staking/keeper/slash_test.go b/x/staking/keeper/slash_test.go index bd46400edcdc..cc4d4651731a 100644 --- a/x/staking/keeper/slash_test.go +++ b/x/staking/keeper/slash_test.go @@ -117,7 +117,7 @@ func TestSlashRedelegation(t *testing.T) { // add bonded tokens to pool for (re)delegations startCoins := sdk.NewCoins(sdk.NewInt64Coin(keeper.BondDenom(ctx), 15)) bondedPool := keeper.GetBondedPool(ctx) - err := bondedPool.SetCoins(bondedPool.GetCoins().Add(startCoins)) + err := bondedPool.SetCoins(bondedPool.GetCoins().Add(startCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) @@ -371,7 +371,7 @@ func TestSlashWithRedelegation(t *testing.T) { bondedPool := keeper.GetBondedPool(ctx) notBondedPool := keeper.GetNotBondedPool(ctx) rdCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, rdTokens.MulRaw(2))) - err := bondedPool.SetCoins(bondedPool.GetCoins().Add(rdCoins)) + err := bondedPool.SetCoins(bondedPool.GetCoins().Add(rdCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) @@ -515,8 +515,8 @@ func TestSlashBoth(t *testing.T) { // update bonded tokens bondedPool := keeper.GetBondedPool(ctx) notBondedPool := keeper.GetNotBondedPool(ctx) - require.NoError(t, bondedPool.SetCoins(bondedPool.GetCoins().Add(bondedCoins))) - require.NoError(t, bondedPool.SetCoins(notBondedPool.GetCoins().Add(notBondedCoins))) + require.NoError(t, bondedPool.SetCoins(bondedPool.GetCoins().Add(bondedCoins...))) + require.NoError(t, bondedPool.SetCoins(notBondedPool.GetCoins().Add(notBondedCoins...))) keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) diff --git a/x/staking/keeper/validator_test.go b/x/staking/keeper/validator_test.go index 2f030428870d..c01fabbca2da 100644 --- a/x/staking/keeper/validator_test.go +++ b/x/staking/keeper/validator_test.go @@ -449,7 +449,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) { tokens := sdk.TokensFromConsensusPower(power) validators[i], _ = validators[i].AddTokensFromDel(tokens) notBondedPool := keeper.GetNotBondedPool(ctx) - require.NoError(t, notBondedPool.SetCoins(notBondedPool.GetCoins().Add(sdk.NewCoins(sdk.NewCoin(params.BondDenom, tokens))))) + require.NoError(t, notBondedPool.SetCoins(notBondedPool.GetCoins().Add(sdk.NewCoin(params.BondDenom, tokens)))) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) validators[i] = TestingUpdateValidator(keeper, ctx, validators[i], true) } @@ -465,8 +465,8 @@ func TestGetValidatorsEdgeCases(t *testing.T) { delTokens := sdk.TokensFromConsensusPower(500) validators[0], _ = validators[0].AddTokensFromDel(delTokens) notBondedPool := keeper.GetNotBondedPool(ctx) - newTokens := sdk.NewCoins(sdk.NewCoin(params.BondDenom, delTokens)) - require.NoError(t, notBondedPool.SetCoins(notBondedPool.GetCoins().Add(newTokens))) + newTokens := sdk.NewCoins() + require.NoError(t, notBondedPool.SetCoins(notBondedPool.GetCoins().Add(newTokens...))) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) // test that the two largest validators are @@ -496,7 +496,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) { notBondedPool = keeper.GetNotBondedPool(ctx) newTokens = sdk.NewCoins(sdk.NewCoin(params.BondDenom, sdk.TokensFromConsensusPower(1))) - require.NoError(t, notBondedPool.SetCoins(notBondedPool.GetCoins().Add(newTokens))) + require.NoError(t, notBondedPool.SetCoins(notBondedPool.GetCoins().Add(newTokens...))) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) validators[3] = TestingUpdateValidator(keeper, ctx, validators[3], true) @@ -511,7 +511,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) { validators[3], _ = validators[3].RemoveDelShares(sdk.NewDec(201)) bondedPool := keeper.GetBondedPool(ctx) - require.NoError(t, bondedPool.SetCoins(bondedPool.GetCoins().Add(sdk.NewCoins(sdk.NewCoin(params.BondDenom, rmTokens))))) + require.NoError(t, bondedPool.SetCoins(bondedPool.GetCoins().Add(sdk.NewCoin(params.BondDenom, rmTokens)))) keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) validators[3] = TestingUpdateValidator(keeper, ctx, validators[3], true) @@ -525,7 +525,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) { validators[3], _ = validators[3].AddTokensFromDel(sdk.NewInt(200)) notBondedPool = keeper.GetNotBondedPool(ctx) - require.NoError(t, notBondedPool.SetCoins(notBondedPool.GetCoins().Add(sdk.NewCoins(sdk.NewCoin(params.BondDenom, sdk.NewInt(200)))))) + require.NoError(t, notBondedPool.SetCoins(notBondedPool.GetCoins().Add(sdk.NewCoin(params.BondDenom, sdk.NewInt(200))))) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) validators[3] = TestingUpdateValidator(keeper, ctx, validators[3], true) diff --git a/x/supply/genesis.go b/x/supply/genesis.go index 7af02a61c7f3..e1dfc41ff555 100644 --- a/x/supply/genesis.go +++ b/x/supply/genesis.go @@ -15,7 +15,7 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, ak types.AccountKeeper, data Ge var totalSupply sdk.Coins ak.IterateAccounts(ctx, func(acc authexported.Account) (stop bool) { - totalSupply = totalSupply.Add(acc.GetCoins()) + totalSupply = totalSupply.Add(acc.GetCoins()...) return false }, ) diff --git a/x/supply/internal/keeper/bank_test.go b/x/supply/internal/keeper/bank_test.go index bdd0a9430a1d..6a817a164f8d 100644 --- a/x/supply/internal/keeper/bank_test.go +++ b/x/supply/internal/keeper/bank_test.go @@ -60,7 +60,7 @@ func TestSendCoins(t *testing.T) { keeper.SendCoinsFromModuleToAccount(ctx, "", baseAcc.GetAddress(), initCoins) }) - err = keeper.SendCoinsFromModuleToAccount(ctx, holderAcc.GetName(), baseAcc.GetAddress(), initCoins.Add(initCoins)) + err = keeper.SendCoinsFromModuleToAccount(ctx, holderAcc.GetName(), baseAcc.GetAddress(), initCoins.Add(initCoins...)) require.Error(t, err) err = keeper.SendCoinsFromModuleToModule(ctx, holderAcc.GetName(), types.Burner, initCoins) @@ -102,7 +102,7 @@ func TestMintCoins(t *testing.T) { err = keeper.MintCoins(ctx, types.Minter, initCoins) require.NoError(t, err) require.Equal(t, initCoins, getCoinsByName(ctx, keeper, ak, types.Minter)) - require.Equal(t, initialSupply.GetTotal().Add(initCoins), keeper.GetSupply(ctx).GetTotal()) + require.Equal(t, initialSupply.GetTotal().Add(initCoins...), keeper.GetSupply(ctx).GetTotal()) // test same functionality on module account with multiple permissions initialSupply = keeper.GetSupply(ctx) @@ -110,7 +110,7 @@ func TestMintCoins(t *testing.T) { err = keeper.MintCoins(ctx, multiPermAcc.GetName(), initCoins) require.NoError(t, err) require.Equal(t, initCoins, getCoinsByName(ctx, keeper, ak, multiPermAcc.GetName())) - require.Equal(t, initialSupply.GetTotal().Add(initCoins), keeper.GetSupply(ctx).GetTotal()) + require.Equal(t, initialSupply.GetTotal().Add(initCoins...), keeper.GetSupply(ctx).GetTotal()) require.Panics(t, func() { keeper.MintCoins(ctx, types.Burner, initCoins) }) } diff --git a/x/supply/internal/keeper/invariants.go b/x/supply/internal/keeper/invariants.go index d72bf4e0134d..aeec368e4bf9 100644 --- a/x/supply/internal/keeper/invariants.go +++ b/x/supply/internal/keeper/invariants.go @@ -27,7 +27,7 @@ func TotalSupply(k Keeper) sdk.Invariant { supply := k.GetSupply(ctx) k.ak.IterateAccounts(ctx, func(acc exported.Account) bool { - expectedTotal = expectedTotal.Add(acc.GetCoins()) + expectedTotal = expectedTotal.Add(acc.GetCoins()...) return false }) diff --git a/x/supply/internal/types/supply.go b/x/supply/internal/types/supply.go index 6009b22fac6e..92e4a3e5d2f5 100644 --- a/x/supply/internal/types/supply.go +++ b/x/supply/internal/types/supply.go @@ -40,7 +40,7 @@ func DefaultSupply() exported.SupplyI { // Inflate adds coins to the total supply func (supply Supply) Inflate(amount sdk.Coins) exported.SupplyI { - supply.Total = supply.Total.Add(amount) + supply.Total = supply.Total.Add(amount...) return supply } From 17d639aa6018de2d3927ee4924cc3836c0cb0693 Mon Sep 17 00:00:00 2001 From: Sunny Aggarwal Date: Sat, 4 Jan 2020 14:50:38 -0500 Subject: [PATCH 057/529] Merge PR #5452: Pass in sdk.Context to router.Route() --- CHANGELOG.md | 2 ++ baseapp/baseapp.go | 2 +- baseapp/baseapp_test.go | 65 +++++++++++++++++++++++++++++++++++++++++ baseapp/options.go | 8 +++++ baseapp/router.go | 2 +- baseapp/router_test.go | 2 +- docs/core/baseapp.md | 4 +-- types/router.go | 2 +- 8 files changed, 81 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 84aaaa61e0c2..0dea7da2b2bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -96,6 +96,8 @@ if the provided arguments are invalid. * (keys) [\#4941](https://github.com/cosmos/cosmos-sdk/issues/4941) Initializing a new keybase through `NewKeyringFromHomeFlag`, `NewKeyringFromDir`, `NewKeyBaseFromHomeFlag`, `NewKeyBaseFromDir`, or `NewInMemory` functions now accept optional parameters of type `KeybaseOption`. These optional parameters are also added on the keys subcommands functions, which are now public, and allows these options to be set on the commands or ignored to default to previous behavior. * The option introduced in this PR is `WithKeygenFunc` which allows a custom bytes to key implementation to be defined when keys are created. * (simapp) [\#5419](https://github.com/cosmos/cosmos-sdk/pull/5419) simapp/helpers.GenTx() now accepts a gas argument. +* (baseapp) [\#5455](https://github.com/cosmos/cosmos-sdk/issues/5455) An `sdk.Context` is passed into the `router.Route()` +function. ### Client Breaking Changes diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 46f3e2649907..3837a34ccc9a 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -654,7 +654,7 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode runTxMode) (*s } msgRoute := msg.Route() - handler := app.router.Route(msgRoute) + handler := app.router.Route(ctx, msgRoute) if handler == nil { return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized message route: %s; message index: %d", msgRoute, i) } diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index 01996e27ef40..179c80463bc4 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -6,6 +6,7 @@ import ( "fmt" "io/ioutil" "os" + "sync" "testing" "github.com/stretchr/testify/assert" @@ -416,6 +417,9 @@ func TestBaseAppOptionSeal(t *testing.T) { require.Panics(t, func() { app.SetFauxMerkleMode() }) + require.Panics(t, func() { + app.SetRouter(NewRouter()) + }) } func TestSetMinGasPrices(t *testing.T) { @@ -1443,3 +1447,64 @@ func TestGetMaximumBlockGas(t *testing.T) { app.setConsensusParams(&abci.ConsensusParams{Block: &abci.BlockParams{MaxGas: -5000000}}) require.Panics(t, func() { app.getMaximumBlockGas() }) } + +// NOTE: represents a new custom router for testing purposes of WithRouter() +type testCustomRouter struct { + routes sync.Map +} + +func (rtr *testCustomRouter) AddRoute(path string, h sdk.Handler) sdk.Router { + rtr.routes.Store(path, h) + return rtr +} + +func (rtr *testCustomRouter) Route(ctx sdk.Context, path string) sdk.Handler { + if v, ok := rtr.routes.Load(path); ok { + if h, ok := v.(sdk.Handler); ok { + return h + } + } + return nil +} + +func TestWithRouter(t *testing.T) { + // test increments in the ante + anteKey := []byte("ante-key") + anteOpt := func(bapp *BaseApp) { bapp.SetAnteHandler(anteHandlerTxTest(t, capKey1, anteKey)) } + + // test increments in the handler + deliverKey := []byte("deliver-key") + routerOpt := func(bapp *BaseApp) { + bapp.SetRouter(&testCustomRouter{routes: sync.Map{}}) + bapp.Router().AddRoute(routeMsgCounter, handlerMsgCounter(t, capKey1, deliverKey)) + } + + app := setupBaseApp(t, anteOpt, routerOpt) + app.InitChain(abci.RequestInitChain{}) + + // Create same codec used in txDecoder + codec := codec.New() + registerTestCodec(codec) + + nBlocks := 3 + txPerHeight := 5 + + for blockN := 0; blockN < nBlocks; blockN++ { + header := abci.Header{Height: int64(blockN) + 1} + app.BeginBlock(abci.RequestBeginBlock{Header: header}) + + for i := 0; i < txPerHeight; i++ { + counter := int64(blockN*txPerHeight + i) + tx := newTxCounter(counter, counter) + + txBytes, err := codec.MarshalBinaryLengthPrefixed(tx) + require.NoError(t, err) + + res := app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) + require.True(t, res.IsOK(), fmt.Sprintf("%v", res)) + } + + app.EndBlock(abci.RequestEndBlock{}) + app.Commit() + } +} diff --git a/baseapp/options.go b/baseapp/options.go index 632a97850664..ea3b42ac2451 100644 --- a/baseapp/options.go +++ b/baseapp/options.go @@ -135,3 +135,11 @@ func (app *BaseApp) SetStoreLoader(loader StoreLoader) { } app.storeLoader = loader } + +// SetRouter allows us to customize the router. +func (app *BaseApp) SetRouter(router sdk.Router) { + if app.sealed { + panic("SetRouter() on sealed BaseApp") + } + app.router = router +} diff --git a/baseapp/router.go b/baseapp/router.go index 96386e6eddca..77d2567c6cb2 100644 --- a/baseapp/router.go +++ b/baseapp/router.go @@ -36,6 +36,6 @@ func (rtr *Router) AddRoute(path string, h sdk.Handler) sdk.Router { // Route returns a handler for a given route path. // // TODO: Handle expressive matches. -func (rtr *Router) Route(path string) sdk.Handler { +func (rtr *Router) Route(_ sdk.Context, path string) sdk.Handler { return rtr.routes[path] } diff --git a/baseapp/router_test.go b/baseapp/router_test.go index 1a6d999bcce6..86b727568d5d 100644 --- a/baseapp/router_test.go +++ b/baseapp/router_test.go @@ -21,7 +21,7 @@ func TestRouter(t *testing.T) { }) rtr.AddRoute("testRoute", testHandler) - h := rtr.Route("testRoute") + h := rtr.Route(sdk.Context{}, "testRoute") require.NotNil(t, h) // require panic on duplicate route diff --git a/docs/core/baseapp.md b/docs/core/baseapp.md index 8ef2dbcdfdcc..04dbdfc61b47 100644 --- a/docs/core/baseapp.md +++ b/docs/core/baseapp.md @@ -184,9 +184,9 @@ When messages and queries are received by the application, they must be routed t ### Message Routing -[`Message`s](#../building-modules/messages-and-queries.md#messages) need to be routed after they are extracted from transactions, which are sent from the underlying Tendermint engine via the [`CheckTx`](#checktx) and [`DeliverTx`](#delivertx) ABCI messages. To do so, `baseapp` holds a `router` which maps `paths` (`string`) to the appropriate module [`handler`](../building-modules/handler.md). Usually, the `path` is the name of the module. +[`Message`s](#../building-modules/messages-and-queries.md#messages) need to be routed after they are extracted from transactions, which are sent from the underlying Tendermint engine via the [`CheckTx`](#checktx) and [`DeliverTx`](#delivertx) ABCI messages. To do so, `baseapp` holds a `router` which maps `paths` (`string`) to the appropriate module [`handler`](../building-modules/handler.md) using the `.Route(ctx sdk.Context, path string)` function. Usually, the `path` is the name of the module. -+++ https://github.com/cosmos/cosmos-sdk/blob/master/baseapp/router.go +The [default router included in baseapp](https://github.com/cosmos/cosmos-sdk/blob/master/baseapp/router.go) is stateless. However, some applications may want to make use of more stateful routing mechanisms such as allowing governance to disable certain routes or point them to new modules for upgrade purposes. For this reason, the `sdk.Context` is also passed into the `Route` function of the [Router interface](https://github.com/cosmos/cosmos-sdk/blob/master/types/router.go#L12). For a stateless router that doesn't want to make use of this, can just ignore the ctx. The application's `router` is initilalized with all the routes using the application's [module manager](../building-modules/module-manager.md#manager), which itself is initialized with all the application's modules in the application's [constructor](../basics/app-anatomy.md#app-constructor). diff --git a/types/router.go b/types/router.go index c14255d4ec76..f3593f5530ff 100644 --- a/types/router.go +++ b/types/router.go @@ -9,7 +9,7 @@ var IsAlphaNumeric = regexp.MustCompile(`^[a-zA-Z0-9]+$`).MatchString // Router provides handlers for each transaction type. type Router interface { AddRoute(r string, h Handler) Router - Route(path string) Handler + Route(ctx Context, path string) Handler } // QueryRouter provides queryables for each query path. From 3fc6240c949511dc6b17080731a949c18477e160 Mon Sep 17 00:00:00 2001 From: Sunny Aggarwal Date: Sat, 4 Jan 2020 15:16:12 -0500 Subject: [PATCH 058/529] Merge PR #5447: Added nth root function to sdk.Decimal type --- CHANGELOG.md | 2 ++ types/decimal.go | 75 ++++++++++++++++++++++++++++++++++--------- types/decimal_test.go | 45 +++++++++++++++++++++++++- types/int.go | 21 ++++++++++++ types/int_test.go | 8 +++++ 5 files changed, 134 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0dea7da2b2bc..b489664dedd6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -174,6 +174,8 @@ that allows for arbitrary vesting periods. * Introduces cli commands and rest routes to query historical information at a given height * (modules) [\#5249](https://github.com/cosmos/cosmos-sdk/pull/5249) Funds are now allowed to be directly sent to the community pool (via the distribution module account). * (keys) [\#4941](https://github.com/cosmos/cosmos-sdk/issues/4941) Introduce keybase option to allow overriding the default private key implementation of a key generated through the `keys add` cli command. +* (types) [\#5447](https://github.com/cosmos/cosmos-sdk/pull/5447) Added `ApproxRoot` function to sdk.Decimal type in order to get the nth root for a decimal number, where n is a positive integer. + * An `ApproxSqrt` function was also added for convenience around the common case of n=2. ### Improvements diff --git a/types/decimal.go b/types/decimal.go index 63aecf6cab18..839523080656 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -269,7 +269,6 @@ func (d Dec) MulInt64(i int64) Dec { // quotient func (d Dec) Quo(d2 Dec) Dec { - // multiply precision twice mul := new(big.Int).Mul(d.Int, precisionReuse) mul.Mul(mul, precisionReuse) @@ -326,30 +325,74 @@ func (d Dec) QuoInt64(i int64) Dec { return Dec{mul} } -// ApproxSqrt returns an approximate sqrt estimation using Newton's method to -// compute square roots x=√d for d > 0. The algorithm starts with some guess and +// ApproxRoot returns an approximate estimation of a Dec's positive real nth root +// using Newton's method (where n is positive). The algorithm starts with some guess and // computes the sequence of improved guesses until an answer converges to an -// approximate answer. It returns -(sqrt(abs(d)) if input is negative. -func (d Dec) ApproxSqrt() Dec { +// approximate answer. It returns `|d|.ApproxRoot() * -1` if input is negative. +func (d Dec) ApproxRoot(root uint64) (guess Dec, err error) { + defer func() { + if r := recover(); r != nil { + var ok bool + err, ok = r.(error) + if !ok { + err = errors.New("out of bounds") + } + } + }() + if d.IsNegative() { - return d.MulInt64(-1).ApproxSqrt().MulInt64(-1) + absRoot, err := d.MulInt64(-1).ApproxRoot(root) + return absRoot.MulInt64(-1), err + } + + if root == 1 || d.IsZero() || d.Equal(OneDec()) { + return d, nil + } + + if root == 0 { + return OneDec(), nil } - if d.IsZero() { - return ZeroDec() + rootInt := NewIntFromUint64(root) + guess, delta := OneDec(), OneDec() + + for delta.Abs().GT(SmallestDec()) { + prev := guess.Power(root - 1) + if prev.IsZero() { + prev = SmallestDec() + } + delta = d.Quo(prev) + delta = delta.Sub(guess) + delta = delta.QuoInt(rootInt) + + guess = guess.Add(delta) } - z := OneDec() - // first guess - z = z.Sub((z.Mul(z).Sub(d)).Quo(z.MulInt64(2))) + return guess, nil +} - // iterate until change is very small - for zNew, delta := z, z; delta.GT(SmallestDec()); z = zNew { - zNew = zNew.Sub((zNew.Mul(zNew).Sub(d)).Quo(zNew.MulInt64(2))) - delta = z.Sub(zNew) +// Power returns a the result of raising to a positive integer power +func (d Dec) Power(power uint64) Dec { + if power == 0 { + return OneDec() } + tmp := OneDec() + for i := power; i > 1; { + if i%2 == 0 { + i /= 2 + } else { + tmp = tmp.Mul(d) + i = (i - 1) / 2 + } + d = d.Mul(d) + } + return d.Mul(tmp) +} - return z +// ApproxSqrt is a wrapper around ApproxRoot for the common special case +// of finding the square root of a number. It returns -(sqrt(abs(d)) if input is negative. +func (d Dec) ApproxSqrt() (Dec, error) { + return d.ApproxRoot(2) } // is integer, e.g. decimals are zero diff --git a/types/decimal_test.go b/types/decimal_test.go index ea97a1029a5a..48c691a100dc 100644 --- a/types/decimal_test.go +++ b/types/decimal_test.go @@ -425,6 +425,48 @@ func TestDecCeil(t *testing.T) { } } +func TestPower(t *testing.T) { + testCases := []struct { + input Dec + power uint64 + expected Dec + }{ + {OneDec(), 10, OneDec()}, // 1.0 ^ (10) => 1.0 + {NewDecWithPrec(5, 1), 2, NewDecWithPrec(25, 2)}, // 0.5 ^ 2 => 0.25 + {NewDecWithPrec(2, 1), 2, NewDecWithPrec(4, 2)}, // 0.2 ^ 2 => 0.04 + {NewDecFromInt(NewInt(3)), 3, NewDecFromInt(NewInt(27))}, // 3 ^ 3 => 27 + {NewDecFromInt(NewInt(-3)), 4, NewDecFromInt(NewInt(81))}, // -3 ^ 4 = 81 + {NewDecWithPrec(1414213562373095049, 18), 2, NewDecFromInt(NewInt(2))}, // 1.414213562373095049 ^ 2 = 2 + } + + for i, tc := range testCases { + res := tc.input.Power(tc.power) + require.True(t, tc.expected.Sub(res).Abs().LTE(SmallestDec()), "unexpected result for test case %d, input: %v", i, tc.input) + } +} + +func TestApproxRoot(t *testing.T) { + testCases := []struct { + input Dec + root uint64 + expected Dec + }{ + {OneDec(), 10, OneDec()}, // 1.0 ^ (0.1) => 1.0 + {NewDecWithPrec(25, 2), 2, NewDecWithPrec(5, 1)}, // 0.25 ^ (0.5) => 0.5 + {NewDecWithPrec(4, 2), 2, NewDecWithPrec(2, 1)}, // 0.04 => 0.2 + {NewDecFromInt(NewInt(27)), 3, NewDecFromInt(NewInt(3))}, // 27 ^ (1/3) => 3 + {NewDecFromInt(NewInt(-81)), 4, NewDecFromInt(NewInt(-3))}, // -81 ^ (0.25) => -3 + {NewDecFromInt(NewInt(2)), 2, NewDecWithPrec(1414213562373095049, 18)}, // 2 ^ (0.5) => 1.414213562373095049 + {NewDecWithPrec(1005, 3), 31536000, MustNewDecFromStr("1.000000000158153904")}, + } + + for i, tc := range testCases { + res, err := tc.input.ApproxRoot(tc.root) + require.NoError(t, err) + require.True(t, tc.expected.Sub(res).Abs().LTE(SmallestDec()), "unexpected result for test case %d, input: %v", i, tc.input) + } +} + func TestApproxSqrt(t *testing.T) { testCases := []struct { input Dec @@ -439,7 +481,8 @@ func TestApproxSqrt(t *testing.T) { } for i, tc := range testCases { - res := tc.input.ApproxSqrt() + res, err := tc.input.ApproxSqrt() + require.NoError(t, err) require.Equal(t, tc.expected, res, "unexpected result for test case %d, input: %v", i, tc.input) } } diff --git a/types/int.go b/types/int.go index 41a6efef74c7..caabdb11318c 100644 --- a/types/int.go +++ b/types/int.go @@ -114,6 +114,13 @@ func NewInt(n int64) Int { return Int{big.NewInt(n)} } +// NewIntFromUint64 constructs an Int from a uint64. +func NewIntFromUint64(n uint64) Int { + b := big.NewInt(0) + b.SetUint64(n) + return Int{b} +} + // NewIntFromBigInt constructs Int from big.Int func NewIntFromBigInt(i *big.Int) Int { if i.BitLen() > maxBitLen { @@ -178,6 +185,20 @@ func (i Int) IsInt64() bool { return i.i.IsInt64() } +// Uint64 converts Int to uint64 +// Panics if the value is out of range +func (i Int) Uint64() uint64 { + if !i.i.IsUint64() { + panic("Uint64() out of bounds") + } + return i.i.Uint64() +} + +// IsUint64 returns true if Uint64() not panics +func (i Int) IsUint64() bool { + return i.i.IsUint64() +} + // IsZero returns true if Int is zero func (i Int) IsZero() bool { return i.i.Sign() == 0 diff --git a/types/int_test.go b/types/int_test.go index f6dbc1b407e9..072b2f47bb9a 100644 --- a/types/int_test.go +++ b/types/int_test.go @@ -16,6 +16,14 @@ func TestFromInt64(t *testing.T) { } } +func TestFromUint64(t *testing.T) { + for n := 0; n < 20; n++ { + r := rand.Uint64() + require.True(t, NewIntFromUint64(r).IsUint64()) + require.Equal(t, r, NewIntFromUint64(r).Uint64()) + } +} + func TestIntPanic(t *testing.T) { // Max Int = 2^255-1 = 5.789e+76 // Min Int = -(2^255-1) = -5.789e+76 From e77496f77e79409a5a323e574494f23766ee72f4 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Sun, 5 Jan 2020 21:25:56 +0100 Subject: [PATCH 059/529] Merge PR #5469: ADR 003 follow-up --- .../adr-003-dynamic-capability-store.md | 74 ++++++++++--------- 1 file changed, 40 insertions(+), 34 deletions(-) diff --git a/docs/architecture/adr-003-dynamic-capability-store.md b/docs/architecture/adr-003-dynamic-capability-store.md index 7272c138f816..7fd438fd931c 100644 --- a/docs/architecture/adr-003-dynamic-capability-store.md +++ b/docs/architecture/adr-003-dynamic-capability-store.md @@ -28,11 +28,11 @@ to the existing `TransientStore` but without erasure on `Commit()`, which this ` The `CapabilityKeeper` will use two stores: a regular, persistent `KVStore`, which will track what capabilities have been created by each module, and an in-memory `MemoryStore` (described below), which will store the actual capabilities. The `CapabilityKeeper` will define the following types & functions: -The `Capability` interface, similar to `StoreKey`, provides `Name()` and `String()` methods. +The `Capability` interface is similar to `StoreKey`, but has a globally unique `Index()` instead of a name. A `String()` method is provided for debugging. ```golang type Capability interface { - Name() string + Index() uint64 String() string } ``` @@ -99,18 +99,21 @@ func (ck CapabilityKeeper) InitialiseAndSeal(ctx Context) { persistentStore := ctx.KVStore(ck.persistentKey) memoryStore := ctx.KVStore(ck.memoryKey) // initialise memory store for all names in persistent store - for _, key := range persistentStore.Iter() { - capability = &CapabilityKey{name: key} - memoryStore.Set("fwd/" + capability, name) - memoryStore.Set("rev/" + name, capability) + for index, value := range persistentStore.Iter() { + capability = &CapabilityKey{index: index} + for moduleAndCapability := range value { + moduleName, capabilityName := moduleAndCapability.Split("/") + memoryStore.Set(moduleName + "/fwd/" + capability, capabilityName) + memoryStore.Set(moduleName + "/rev/" + capabilityName, capability) + } } ck.sealed = true } ``` `NewCapability` can be called by any module to create a new unique, unforgeable object-capability -reference. The newly created capability is *not* automatically persisted, `ClaimCapability` must be -called on the `ScopedCapabilityKeeper` in order to persist it. +reference. The newly created capability is automatically persisted; the calling module need not +call `ClaimCapability`. ```golang func (sck ScopedCapabilityKeeper) NewCapability(ctx Context, name string) (Capability, error) { @@ -119,44 +122,52 @@ func (sck ScopedCapabilityKeeper) NewCapability(ctx Context, name string) (Capab if memoryStore.Get("rev/" + name) != nil { return nil, errors.New("name already taken") } + // fetch the current index + index := persistentStore.Get("index") // create a new capability - capability := &CapabilityKey{name: name} + capability := &CapabilityKey{index: index} + // set persistent store + persistentStore.Set(index, Set.singleton(sck.moduleName + "/" + name)) + // update the index + index++ + persistentStore.Set("index", index) // set forward mapping in memory store from capability to name - memoryStore.Set("fwd/" + capability, name) + memoryStore.Set(sck.moduleName + "/fwd/" + capability, name) // set reverse mapping in memory store from name to capability - memoryStore.Set("rev/" + name, capability) + memoryStore.Set(sck.moduleName + "/rev/" + name, capability) // return the newly created capability return capability } ``` `AuthenticateCapability` can be called by any module to check that a capability -does in fact correspond to a particular name (the name can be untrusted user input). +does in fact correspond to a particular name (the name can be untrusted user input) +with which the calling module previously associated it. ```golang func (sck ScopedCapabilityKeeper) AuthenticateCapability(name string, capability Capability) bool { memoryStore := ctx.KVStore(sck.memoryKey) // return whether forward mapping in memory store matches name - return memoryStore.Get("fwd/" + capability) === name + return memoryStore.Get(sck.moduleName + "/fwd/" + capability) === name } ``` -`ClaimCapability` allows a module to claim a capability key which it has received (perhaps by calling `NewCapability`, or from another module), so that future `GetCapability` calls will succeed. +`ClaimCapability` allows a module to claim a capability key which it has received from another module so that future `GetCapability` calls will succeed. -`ClaimCapability` MUST be called, even if `NewCapability` was called by the same module. Capabilities are single-owner, so if multiple modules have a single `Capability` reference, the last module -to call `ClaimCapability` will own it. To avoid confusion, a module which calls `NewCapability` SHOULD either call `ClaimCapability` or pass the capability to another module which will then claim it. +`ClaimCapability` MUST be called if a module which receives a capability wishes to access it by name in the future. Capabilities are multi-owner, so if multiple modules have a single `Capability` reference, they will all own it. ```golang -func (sck ScopedCapabilityKeeper) ClaimCapability(ctx Context, capability Capability) error { +func (sck ScopedCapabilityKeeper) ClaimCapability(ctx Context, capability Capability, name string) error { persistentStore := ctx.KVStore(sck.persistentKey) memoryStore := ctx.KVStore(sck.memoryKey) - // fetch name from memory store - name := memoryStore.Get("fwd/" + capability) - if name === nil { - return errors.New("capability not found") - } - // set name to module in persistent store - persistentStore.Set(name, sck.moduleName) + // set forward mapping in memory store from capability to name + memoryStore.Set(sck.moduleName + "/fwd/" + capability, name) + // set reverse mapping in memory store from name to capability + memoryStore.Set(sck.moduleName + "/rev/" + name, capability) + // update owner set in persistent store + owners := persistentStore.Get(capability.Index()) + owners.add(sck.moduleName + "/" + name) + persistentStore.Set(capability.Index(), owners) } ``` @@ -165,15 +176,10 @@ claims a capability, the previously owning module will no longer be able to clai ```golang func (sck ScopedCapabilityKeeper) GetCapability(ctx Context, name string) (Capability, error) { - persistentStore := ctx.KVStore(sck.persistentKey) memoryStore := ctx.KVStore(sck.memoryKey) - // check that this module owns the capability with this name - res := persistentStore.Get(name) - if res != sck.moduleName { - return errors.New("capability of this name not owned by module") - } - // fetch capability from memory store, return it - capability := memoryStore.Get("rev/" + name) + // fetch capability from memory store + capability := memoryStore.Get(sck.moduleName + "/rev/" + name) + // return the capability return capability } ``` @@ -219,7 +225,7 @@ mod2Keeper.SomeFunction(ctx, capability, args...) ```golang func (k Mod2Keeper) SomeFunction(ctx Context, capability Capability) { - k.sck.ClaimCapability(ctx, capability) + k.sck.ClaimCapability(ctx, capability, "resourceABC") // other logic... } ``` @@ -245,7 +251,7 @@ func (k Mod1Keeper) UseResource(ctx Context, capability Capability, resource str ``` If module 2 passed the capability key to module 3, module 3 could then claim it and call module 1 just like module 2 did -(in which case module 2 could no longer call `GetCapability`, since it would then be owned uniquely by module 3). +(in which case module 1, module 2, and module 3 would all be able to use this capability). ## Status From 0e624429fceb8ce50210d2bfe0b3ac0da51c02e9 Mon Sep 17 00:00:00 2001 From: b-harvest <38277329+dlguddus@users.noreply.github.com> Date: Mon, 6 Jan 2020 06:57:18 +0900 Subject: [PATCH 060/529] Merge PR #5233: ADR 016: Validator consensus key rotation --- docs/architecture/README.md | 1 + ...dr-016-validator-consensus-key-rotation.md | 126 ++++++++++++++++++ 2 files changed, 127 insertions(+) create mode 100644 docs/architecture/adr-016-validator-consensus-key-rotation.md diff --git a/docs/architecture/README.md b/docs/architecture/README.md index a63e13fefc93..be9cf356406f 100644 --- a/docs/architecture/README.md +++ b/docs/architecture/README.md @@ -39,4 +39,5 @@ Please add a entry below in your Pull Request for an ADR. - [ADR 011: Generalize Genesis Accounts](./adr-011-generalize-genesis-accounts.md) - [ADR 012: State Accessors](./adr-012-state-accessors.md) - [ADR 015: IBC Packet Receiver](./adr-015-ibc-packet-receiver.md) +- [ADR 016: Validator Consensus Key Rotation](./adr-016-validator-consensus-key-rotation.md) - [ADR 017: Historical Header Module](./adr-017-historical-header-module.md) diff --git a/docs/architecture/adr-016-validator-consensus-key-rotation.md b/docs/architecture/adr-016-validator-consensus-key-rotation.md new file mode 100644 index 000000000000..c668b7d29daa --- /dev/null +++ b/docs/architecture/adr-016-validator-consensus-key-rotation.md @@ -0,0 +1,126 @@ +# ADR 016: Validator Consensus Key Rotation + +## Changelog + +- 2019 Oct 23: Initial draft +- 2019 Nov 28: Add key rotation fee + +## Context + +Validator consensus key rotation feature has been discussed and requested for a long time, for the sake of safer validator key management policy (e.g. https://github.com/tendermint/tendermint/issues/1136). So, we suggest one of the simplest form of validator consensus key rotation implementation mostly onto Cosmos-SDK. + +We don't need to make any update on consensus logic in Tendermint because Tendermint does not have any mapping information of consensus key and validator operator key, meaning that from Tendermint point of view, a consensus key rotation of a validator is simply a replacement of a consensus key to another. + +Also, it should be noted that this ADR includes only the simplest form of consensus key rotation without considering multiple consensus keys concept. Such multiple consensus keys concept shall remain a long term goal of Tendermint and Cosmos-SDK. + +## Decision + +### Pseudo procedure for consensus key rotation + +- create new random consensus key. +- create and broadcast a transaction with a `MsgRotateConsPubKey` that states the new consensus key is now coupled with the validator operator with signature from the validator's operator key. +- old consensus key becomes unable to participate on consensus immediately after the update of key mapping state on-chain. +- start validating with new consensus key. +- validators using HSM and KMS should update the consensus key in HSM to use the new rotated key after the height `h` when `MsgRotateConsPubKey` committed to the blockchain. + + +### Considerations + +- consensus key mapping information management strategy + - store history of each key mapping changes in the kvstore. + - the state machine can search corresponding consensus key paired with given validator operator for any arbitrary height in a recent unbonding period. + - the state machine does not need any historical mapping information which is past more than unbonding period. +- key rotation costs related to LCD and IBC + - LCD and IBC will have traffic/computation burden when there exists frequent power changes + - In current Tendermint design, consensus key rotations are seen as power changes from LCD or IBC perspective + - Therefore, to minimize unnecessary frequent key rotation behavior, we limited maximum number of rotation in recent unbonding period and also applied exponentially increasing rotation fee +- limits + - a validator cannot rotate its consensus key more than `MaxConsPubKeyRotations` time for any unbonding period, to prevent spam. + - parameters can be decided by governance and stored in genesis file. +- key rotation fee + - a validator should pay `KeyRotationFee` to rotate the consensus key which is calculated as below + - `KeyRotationFee` = (max(`VotingPowerPercentage` * 100, 1) * `InitialKeyRotationFee`) * 2^(number of rotations in `ConsPubKeyRotationHistory` in recent unbonding period) +- evidence module + - evidence module can search corresponding consensus key for any height from slashing keeper so that it can decide which consensus key is supposed to be used for given height. +- abci.ValidatorUpdate + - tendermint already has ability to change a consensus key by ABCI communication(`ValidatorUpdate`). + - validator consensus key update can be done via creating new + delete old by change the power to zero. + - therefore, we expect we even do not need to change tendermint codebase at all to implement this feature. +- new genesis parameters in `staking` module + - `MaxConsPubKeyRotations` : maximum number of rotation can be executed by a validator in recent unbonding period. default value 10 is suggested(11th key rotation will be rejected) + - `InitialKeyRotationFee` : the initial key rotation fee when no key rotation has happened in recent unbonding period. default value 1atom is suggested(1atom fee for the first key rotation in recent unbonding period) + + +### Workflow + +1. The validator generates a new consensus keypair. +2. The validator generates and signs a `MsgRotateConsPubKey` tx with their operator key and new ConsPubKey + + ```go + type MsgRotateConsPubKey struct { + ValidatorAddress sdk.ValAddress + NewPubKey crypto.PubKey + } + ``` + +3. `handleMsgRotateConsPubKey` gets `MsgRotateConsPubKey`, calls `RotateConsPubKey` with emits event +4. `RotateConsPubKey` + - checks if `NewPubKey` is not duplicated on `ValidatorsByConsAddr` + - checks if the validator is does not exceed parameter `MaxConsPubKeyRotations` by iterating `ConsPubKeyRotationHistory` + - checks if the signing account has enough balance to pay `KeyRotationFee` + - pays `KeyRotationFee` to community fund + - overwrites `NewPubKey` in `validator.ConsPubKey` + - deletes old `ValidatorByConsAddr` + - `SetValidatorByConsAddr` for `NewPubKey` + - Add `ConsPubKeyRotationHistory` for tracking rotation + + ```go + type ConsPubKeyRotationHistory struct { + OperatorAddress sdk.ValAddress + OldConsPubKey crypto.PubKey + NewConsPubKey crypto.PubKey + RotatedHeight int64 + } + ``` + +5. `ApplyAndReturnValidatorSetUpdates` checks if there is `ConsPubKeyRotationHistory` with `ConsPubKeyRotationHistory.RotatedHeight == ctx.BlockHeight()` and if so, generates 2 `ValidatorUpdate` , one for a remove validator and one for create new validator + + ```go + abci.ValidatorUpdate{ + PubKey: tmtypes.TM2PB.PubKey(OldConsPubKey), + Power: 0, + } + + abci.ValidatorUpdate{ + PubKey: tmtypes.TM2PB.PubKey(NewConsPubKey), + Power: v.ConsensusPower(), + } + ``` + +6. at `previousVotes` Iteration logic of `AllocateTokens`, `previousVote` using `OldConsPubKey` match up with `ConsPubKeyRotationHistory`, and replace validator for token allocation +7. Migrate `ValidatorSigningInfo` and `ValidatorMissedBlockBitArray` from `OldConsPubKey` to `NewConsPubKey` +- Note : All above features shall be implemented in `staking` module. + +## Status + +Proposed + +## Consequences + +### Positive + +- Validators can immediately or periodically rotate their consensus key to have better security policy +- improved security against Long-Range attacks (https://nearprotocol.com/blog/long-range-attacks-and-a-new-fork-choice-rule) given a validator throws away the old consensus key(s) + +### Negative + +- Slash module needs more computation because it needs to lookup corresponding consensus key of validators for each height +- frequent key rotations will make light client bisection less efficient + +### Neutral + +## References + +- on tendermint repo : https://github.com/tendermint/tendermint/issues/1136 +- on cosmos-sdk repo : https://github.com/cosmos/cosmos-sdk/issues/5231 +- about multiple consensus keys : https://github.com/tendermint/tendermint/issues/1758#issuecomment-545291698 From 25be589af6c9704e5dd43061e6440e7d5d46c620 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Mon, 6 Jan 2020 11:49:31 -0500 Subject: [PATCH 061/529] Merge PR #5482: Update Query Txs by Events Command --- CHANGELOG.md | 3 ++ docs/core/events.md | 68 ++++++++++++++++++++++++-------------- x/auth/client/cli/query.go | 65 ++++++++++++++++++++---------------- 3 files changed, 83 insertions(+), 53 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b489664dedd6..830178fb9d13 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -242,6 +242,9 @@ to detail this new feature and how state transitions occur. * (docs/interfaces/) Add documentation on building interfaces for the Cosmos SDK. * Redesigned user interface that features new dynamically generated sidebar, build-time code embedding from GitHub, new homepage as well as many other improvements. * (types) [\#5428](https://github.com/cosmos/cosmos-sdk/pull/5428) Add `Mod` (modulo) method and `RelativePow` (exponentation) function for `Uint`. +* (cli) [\#5482](https://github.com/cosmos/cosmos-sdk/pull/5482) Remove old "tags" nomenclature from the `q txs` command in + favor of the new events system. Functionality remains unchanged except that `=` is used instead of `:` to be + consistent with the API's use of event queries. ### Bug Fixes diff --git a/docs/core/events.md b/docs/core/events.md index 11b6ad1e59b0..aeb0efa1dea8 100644 --- a/docs/core/events.md +++ b/docs/core/events.md @@ -1,6 +1,8 @@ # Events @@ -11,54 +13,69 @@ synopsis: "`Event`s are objects that contain information about the execution of ## Events -`Event`s are implemented in the Cosmos SDK as an alias of the ABCI `event` type. +Events are implemented in the Cosmos SDK as an alias of the ABCI `Event` type and +take the form of: `{eventType}.{eventAttribute}={value}`. +++ https://github.com/tendermint/tendermint/blob/bc572217c07b90ad9cee851f193aaa8e9557cbc7/abci/types/types.pb.go#L2661-L2667 -They contain: +Events contain: -- A **`type`** of type `string`, which can refer to the type of action that led to the `event`'s emission (e.g. a certain value going above a threshold), or to the type of `message` if the event is triggered at the end of that `message` processing. -- A list of `attributes`, which are key-value pairs that give more information about the `event`. - +++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/events.go#L51-L56 +- A `type`, which is meant to categorize an event at a high-level (e.g. by module or action). +- A list of `attributes`, which are key-value pairs that give more information about + the categorized `event`. + +++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/events.go#L51-L56 -`Event`s are returned to the underlying consensus engine in the response of the following ABCI messages: [`CheckTx`](./baseapp.md#checktx), [`DeliverTx`](./baseapp.md#delivertx), [`BeginBlock`](./baseapp.md#beginblock) and [`EndBlock`](./baseapp.md#endblock). +Events are returned to the underlying consensus engine in the response of the following ABCI messages: -Typically, `event` `type`s and `attributes` are defined on a **per-module basis** in the module's `/internal/types/events.go` file, and triggered from the module's [`handler`](../building-modules/handler.md) via the [`EventManager`](#eventmanager). +- [`BeginBlock`](./baseapp.md#beginblock) +- [`EndBlock`](./baseapp.md#endblock) +- [`CheckTx`](./baseapp.md#checktx) +- [`DeliverTx`](./baseapp.md#delivertx) + +Events, the `type` and `attributes`, are defined on a **per-module basis** in the module's +`/internal/types/events.go` file, and triggered from the module's [`handler`](../building-modules/handler.md) +via the [`EventManager`](#eventmanager). In addition, each module documents its events under +`spec/xx_events.md`. ## EventManager -In Cosmos SDK applications, `event`s are generally managed by an object called the `EventManager`. It is implemented as a simple wrapper around a slice of `event`s: +In Cosmos SDK applications, events are managed by an abstraction called the `EventManager`. +Internally, the `EventManager` tracks a list of `Events` for the entire execution flow of a +transaction or `BeginBlock`/`EndBlock`. +++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/events.go#L16-L20 -The `EventManager` comes with a set of useful methods to manage `event`s. Among them, the one that is used the most by module and application developers is the `EmitEvent` method, which registers an `event` in the `EventManager`. +The `EventManager` comes with a set of useful methods to manage events. Among them, the one that is +used the most by module and application developers is the `EmitEvent` method, which tracks +an `event` in the `EventManager`. +++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/events.go#L29-L31 -Typically, module developers will implement event emission via the `EventManager` in the [`handler`](../building-modules/handler.md) of modules, as well as in the [`BeginBlocker` and/or`EndBlocker` functions](../building-modules/beginblock-endblock.md). The `EventManager` is accessed via the context [`ctx`](./context.md), and event emission generally follows this pattern: +Module developers should handle event emission via the `EventManager#EmitEvent` in each message +`Handler` and in each `BeginBlock`/`EndBlock` handler. The `EventManager` is accessed via +the [`Context`](./context.md), where event emission generally follows this pattern: ```go ctx.EventManager().EmitEvent( - sdk.NewEvent( - eventType, // e.g. sdk.EventTypeMessage for a message, types.CustomEventType for a custom event defined in the module - sdk.NewAttribute(attributeKey, attributeValue), - ), - ) + sdk.NewEvent(eventType, sdk.NewAttribute(attributeKey, attributeValue)), +) ``` -See the [`handler` concept doc](../building-modules/handler.md) for a more detailed view on how to typically implement `events` and use the `EventManager` in modules. +See the [`Handler`](../building-modules/handler.md) concept doc for a more detailed +view on how to typically implement `Events` and use the `EventManager` in modules. -## Subscribing to `events` +## Subscribing to Events -It is possible to subscribe to `events` via [Tendermint's Websocket](https://tendermint.com/docs/app-dev/subscribing-to-events-via-websocket.html#subscribing-to-events-via-websocket). This is done by calling the `subscribe` RPC method via Websocket: +It is possible to subscribe to `Events` via Tendermint's [Websocket](https://tendermint.com/docs/app-dev/subscribing-to-events-via-websocket.html#subscribing-to-events-via-websocket). +This is done by calling the `subscribe` RPC method via Websocket: -``` +```json { "jsonrpc": "2.0", "method": "subscribe", "id": "0", "params": { - "query": "tm.event='eventCategory' AND type.attribute='attributeValue'" + "query": "tm.event='eventCategory' AND eventType.eventAttribute='attributeValue'" } } ``` @@ -67,13 +84,14 @@ The main `eventCategory` you can subscribe to are: - `NewBlock`: Contains `events` triggered during `BeginBlock` and `EndBlock`. - `Tx`: Contains `events` triggered during `DeliverTx` (i.e. transaction processing). -- `ValidatorSetUpdates`: Contains validator set updates for the block. +- `ValidatorSetUpdates`: Contains validator set updates for the block. -These events are triggered from the `state` package after a block is committed. You can get the full list of `event` categories [here](https://godoc.org/github.com/tendermint/tendermint/types#pkg-constants). +These events are triggered from the `state` package after a block is committed. You can get the +full list of `event` categories [here](https://godoc.org/github.com/tendermint/tendermint/types#pkg-constants). The `type` and `attribute` value of the `query` allow you to filter the specific `event` you are looking for. For example, a `transfer` transaction triggers an `event` of type `Transfer` and has `Recipient` and `Sender` as `attributes` (as defined in the [`events` file of the `bank` module](https://github.com/cosmos/cosmos-sdk/blob/master/x/bank/internal/types/events.go)). Subscribing to this `event` would be done like so: -``` +```json { "jsonrpc": "2.0", "method": "subscribe", @@ -88,4 +106,4 @@ where `senderAddress` is an address following the [`AccAddress`](../basics/accou ## Next {hide} -Learn about [object-capabilities](./ocap.md) {hide} \ No newline at end of file +Learn about [object-capabilities](./ocap.md) {hide} diff --git a/x/auth/client/cli/query.go b/x/auth/client/cli/query.go index 9eee22127c50..8688d0e8d6df 100644 --- a/x/auth/client/cli/query.go +++ b/x/auth/client/cli/query.go @@ -13,6 +13,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/rest" + "github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/x/auth/client/utils" "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -20,9 +21,11 @@ import ( ) const ( - flagTags = "tags" - flagPage = "page" - flagLimit = "limit" + flagEvents = "events" + flagPage = "page" + flagLimit = "limit" + + eventFormat = "{eventType}.{eventAttribute}={value}" ) // GetQueryCmd returns the transaction commands for this module @@ -72,47 +75,52 @@ func GetAccountCmd(cdc *codec.Codec) *cobra.Command { func QueryTxsByEventsCmd(cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "txs", - Short: "Query for paginated transactions that match a set of tags", - Long: strings.TrimSpace(` -Search for transactions that match the exact given tags where results are paginated. + Short: "Query for paginated transactions that match a set of events", + Long: strings.TrimSpace( + fmt.Sprintf(` +Search for transactions that match the exact given events where results are paginated. +Each event takes the form of '%s'. Please refer +to each module's documentation for the full set of events to query for. Each module +documents its respective events under 'xx_events.md'. Example: -$ query txs --tags ':&:' --page 1 --limit 30 -`), +$ %s query txs --%s 'message.sender=cosmos1...&message.action=withdraw_delegator_reward' --page 1 --limit 30 +`, eventFormat, version.ClientName, flagEvents), + ), RunE: func(cmd *cobra.Command, args []string) error { - tagsStr := viper.GetString(flagTags) - tagsStr = strings.Trim(tagsStr, "'") + eventsStr := strings.Trim(viper.GetString(flagEvents), "'") - var tags []string - if strings.Contains(tagsStr, "&") { - tags = strings.Split(tagsStr, "&") + var events []string + if strings.Contains(eventsStr, "&") { + events = strings.Split(eventsStr, "&") } else { - tags = append(tags, tagsStr) + events = append(events, eventsStr) } - var tmTags []string - for _, tag := range tags { - if !strings.Contains(tag, ":") { - return fmt.Errorf("%s should be of the format :", tagsStr) - } else if strings.Count(tag, ":") > 1 { - return fmt.Errorf("%s should only contain one : pair", tagsStr) + var tmEvents []string + + for _, event := range events { + if !strings.Contains(event, "=") { + return fmt.Errorf("invalid event; event %s should be of the format: %s", event, eventFormat) + } else if strings.Count(event, "=") > 1 { + return fmt.Errorf("invalid event; event %s should be of the format: %s", event, eventFormat) } - keyValue := strings.Split(tag, ":") - if keyValue[0] == tmtypes.TxHeightKey { - tag = fmt.Sprintf("%s=%s", keyValue[0], keyValue[1]) + tokens := strings.Split(event, "=") + if tokens[0] == tmtypes.TxHeightKey { + event = fmt.Sprintf("%s=%s", tokens[0], tokens[1]) } else { - tag = fmt.Sprintf("%s='%s'", keyValue[0], keyValue[1]) + event = fmt.Sprintf("%s='%s'", tokens[0], tokens[1]) } - tmTags = append(tmTags, tag) + tmEvents = append(tmEvents, event) } page := viper.GetInt(flagPage) limit := viper.GetInt(flagLimit) cliCtx := context.NewCLIContext().WithCodec(cdc) - txs, err := utils.QueryTxsByEvents(cliCtx, tmTags, page, limit) + txs, err := utils.QueryTxsByEvents(cliCtx, tmEvents, page, limit) if err != nil { return err } @@ -135,13 +143,14 @@ $ query txs --tags ':&:' --page 1 --limit 3 cmd.Flags().StringP(flags.FlagNode, "n", "tcp://localhost:26657", "Node to connect to") viper.BindPFlag(flags.FlagNode, cmd.Flags().Lookup(flags.FlagNode)) + cmd.Flags().Bool(flags.FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)") viper.BindPFlag(flags.FlagTrustNode, cmd.Flags().Lookup(flags.FlagTrustNode)) - cmd.Flags().String(flagTags, "", "tag:value list of tags that must match") + cmd.Flags().String(flagEvents, "", fmt.Sprintf("list of transaction events in the form of %s", eventFormat)) cmd.Flags().Uint32(flagPage, rest.DefaultPage, "Query a specific page of paginated results") cmd.Flags().Uint32(flagLimit, rest.DefaultLimit, "Query number of transactions results per page returned") - cmd.MarkFlagRequired(flagTags) + cmd.MarkFlagRequired(flagEvents) return cmd } From 2968247d9c6772f3b46cc6b4accc24b61cb003a0 Mon Sep 17 00:00:00 2001 From: Matthew Slipper Date: Tue, 7 Jan 2020 07:17:01 -0800 Subject: [PATCH 062/529] Merge PR #5479: Add convenience Incr() and Decr() methods to Uint --- types/uint.go | 11 +++++++++++ types/uint_test.go | 12 ++++++++++++ 2 files changed, 23 insertions(+) diff --git a/types/uint.go b/types/uint.go index 1cc289b900dc..976b6414a93f 100644 --- a/types/uint.go +++ b/types/uint.go @@ -107,6 +107,17 @@ func (u Uint) Mod(u2 Uint) Uint { return Uint{mod(u.i, u2.i)} } +// Incr increments the Uint by one. +func (u Uint) Incr() Uint { + return u.Add(OneUint()) +} + +// Decr decrements the Uint by one. +// Decr will panic if the Uint is zero. +func (u Uint) Decr() Uint { + return u.Sub(OneUint()) +} + // Quo divides Uint with uint64 func (u Uint) QuoUint64(u2 uint64) Uint { return u.Quo(NewUint(u2)) } diff --git a/types/uint_test.go b/types/uint_test.go index e90fbf7f509c..548dea5064eb 100644 --- a/types/uint_test.go +++ b/types/uint_test.go @@ -50,7 +50,9 @@ func TestUintPanics(t *testing.T) { require.Panics(t, func() { ZeroUint().QuoUint64(0) }) require.Panics(t, func() { OneUint().Quo(ZeroUint().Sub(OneUint())) }) require.Panics(t, func() { uintmax.Add(OneUint()) }) + require.Panics(t, func() { uintmax.Incr() }) require.Panics(t, func() { uintmin.Sub(OneUint()) }) + require.Panics(t, func() { uintmin.Decr() }) require.Equal(t, uint64(0), MinUint(ZeroUint(), OneUint()).Uint64()) require.Equal(t, uint64(1), MaxUint(ZeroUint(), OneUint()).Uint64()) @@ -115,6 +117,7 @@ func TestArithUint(t *testing.T) { {u1.QuoUint64(n2), n1 / n2}, {MinUint(u1, u2), minuint(n1, n2)}, {MaxUint(u1, u2), maxuint(n1, n2)}, + {u1.Incr(), n1 + 1}, } for tcnum, tc := range cases { @@ -132,6 +135,7 @@ func TestArithUint(t *testing.T) { }{ {u1.Sub(u2), n1 - n2}, {u1.SubUint64(n2), n1 - n2}, + {u1.Decr(), n1 - 1}, } for tcnum, tc := range subs { @@ -183,6 +187,14 @@ func TestImmutabilityAllUint(t *testing.T) { func(i *Uint) { _ = i.LT(randuint()) }, func(i *Uint) { _ = i.LTE(randuint()) }, func(i *Uint) { _ = i.String() }, + func(i *Uint) { _ = i.Incr() }, + func(i *Uint) { + if i.IsZero() { + return + } + + _ = i.Decr() + }, } for i := 0; i < 1000; i++ { From e80fc463f7680619a7e9cc411a602714e4763738 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Wed, 8 Jan 2020 10:26:37 -0500 Subject: [PATCH 063/529] Merge PR #5488: Update changelog --- CHANGELOG.md | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 830178fb9d13..c2a73f07f27c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -242,21 +242,35 @@ to detail this new feature and how state transitions occur. * (docs/interfaces/) Add documentation on building interfaces for the Cosmos SDK. * Redesigned user interface that features new dynamically generated sidebar, build-time code embedding from GitHub, new homepage as well as many other improvements. * (types) [\#5428](https://github.com/cosmos/cosmos-sdk/pull/5428) Add `Mod` (modulo) method and `RelativePow` (exponentation) function for `Uint`. -* (cli) [\#5482](https://github.com/cosmos/cosmos-sdk/pull/5482) Remove old "tags" nomenclature from the `q txs` command in - favor of the new events system. Functionality remains unchanged except that `=` is used instead of `:` to be - consistent with the API's use of event queries. ### Bug Fixes -* (types) [\#5395](https://github.com/cosmos/cosmos-sdk/issues/5395) Fix `Uint#LTE` * (client) [\#5303](https://github.com/cosmos/cosmos-sdk/issues/5303) Fix ignored error in tx generate only mode. -* (iavl) [\#5276](https://github.com/cosmos/cosmos-sdk/issues/5276) Fix potential race condition in `iavlIterator#Close`. * (cli) [\#4763](https://github.com/cosmos/cosmos-sdk/issues/4763) Fix flag `--min-self-delegation` for staking `EditValidator` * (keys) Fix ledger custom coin type support bug * (x/gov) [\#5107](https://github.com/cosmos/cosmos-sdk/pull/5107) Sum validator operator's all voting power when tally votes * (rest) [\#5212](https://github.com/cosmos/cosmos-sdk/issues/5212) Fix pagination in the `/gov/proposals` handler. -* (baseapp) [\#5350](https://github.com/cosmos/cosmos-sdk/issues/5350) Allow a node to restart successfully after a `halt-height` or `halt-time` - has been triggered. + +## [v0.37.5] - 2020-01-07 + +### Features + +* (types) [\#5360](https://github.com/cosmos/cosmos-sdk/pull/5360) Implement `SortableDecBytes` which + allows the `Dec` type be sortable. + +### Improvements + +* (tendermint) Bump Tendermint version to [v0.32.8](https://github.com/tendermint/tendermint/releases/tag/v0.32.8) +* (cli) [\#5482](https://github.com/cosmos/cosmos-sdk/pull/5482) Remove old "tags" nomenclature from the `q txs` command in + favor of the new events system. Functionality remains unchanged except that `=` is used instead of `:` to be + consistent with the API's use of event queries. + +### Bug Fixes + +* (iavl) [\#5276](https://github.com/cosmos/cosmos-sdk/issues/5276) Fix potential race condition in `iavlIterator#Close`. +* (baseapp) [\#5350](https://github.com/cosmos/cosmos-sdk/issues/5350) Allow a node to restart successfully + after a `halt-height` or `halt-time` has been triggered. +* (types) [\#5395](https://github.com/cosmos/cosmos-sdk/issues/5395) Fix `Uint#LTE`. * (types) [\#5408](https://github.com/cosmos/cosmos-sdk/issues/5408) `NewDecCoins` constructor now sorts the coins. ## [v0.37.4] - 2019-11-04 @@ -2822,11 +2836,10 @@ BUG FIXES: -[Unreleased]: https://github.com/cosmos/cosmos-sdk/compare/v0.37.4...HEAD +[Unreleased]: https://github.com/cosmos/cosmos-sdk/compare/v0.37.5...HEAD +[v0.37.5]: https://github.com/cosmos/cosmos-sdk/releases/tag/v0.37.5 [v0.37.4]: https://github.com/cosmos/cosmos-sdk/releases/tag/v0.37.4 [v0.37.3]: https://github.com/cosmos/cosmos-sdk/releases/tag/v0.37.3 [v0.37.1]: https://github.com/cosmos/cosmos-sdk/releases/tag/v0.37.1 [v0.37.0]: https://github.com/cosmos/cosmos-sdk/releases/tag/v0.37.0 [v0.36.0]: https://github.com/cosmos/cosmos-sdk/releases/tag/v0.36.0 - - From 67c2acd75aaaaa724386acdf1cd629f20ebaecde Mon Sep 17 00:00:00 2001 From: Ferenc Fabian Date: Wed, 8 Jan 2020 19:41:10 +0100 Subject: [PATCH 064/529] Merge PR #5484: Add errors.Is support to the wrappedError --- types/errors/errors.go | 28 +++++++++++++++++++++ types/errors/errors_test.go | 50 +++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/types/errors/errors.go b/types/errors/errors.go index 49624f784775..3179aed26369 100644 --- a/types/errors/errors.go +++ b/types/errors/errors.go @@ -263,6 +263,34 @@ func (e *wrappedError) Cause() error { return e.parent } +// Is reports whether any error in e's chain matches a target. +func (e *wrappedError) Is(target error) bool { + if target == nil { + return e == target + } + + w := e.Cause() + + for { + if w == target { + return true + } + + x, ok := w.(causer) + if ok { + w = x.Cause() + } + if x == nil { + return false + } + } +} + +// Unwrap implements the built-in errors.Unwrap +func (e *wrappedError) Unwrap() error { + return e.parent +} + // Recover captures a panic and stop its propagation. If panic happens it is // transformed into a ErrPanic instance and assigned to given error. Call this // function using defer in order to work as expected. diff --git a/types/errors/errors_test.go b/types/errors/errors_test.go index a669ee150f95..f6e6e8cd7f52 100644 --- a/types/errors/errors_test.go +++ b/types/errors/errors_test.go @@ -5,6 +5,8 @@ import ( "fmt" "testing" + "github.com/stretchr/testify/require" + "github.com/pkg/errors" ) @@ -158,3 +160,51 @@ func TestWrapEmpty(t *testing.T) { t.Fatal(err) } } + +func TestWrappedIs(t *testing.T) { + err := Wrap(ErrTxTooLarge, "context") + require.True(t, stdlib.Is(err, ErrTxTooLarge)) + + err = Wrap(err, "more context") + require.True(t, stdlib.Is(err, ErrTxTooLarge)) + + err = Wrap(err, "even more context") + require.True(t, stdlib.Is(err, ErrTxTooLarge)) + + err = Wrap(ErrInsufficientFee, "...") + require.False(t, stdlib.Is(err, ErrTxTooLarge)) +} + +func TestWrappedIsMultiple(t *testing.T) { + var errTest = errors.New("test error") + var errTest2 = errors.New("test error 2") + err := Wrap(errTest2, Wrap(errTest, "some random description").Error()) + require.True(t, stdlib.Is(err, errTest2)) +} + +func TestWrappedIsFail(t *testing.T) { + var errTest = errors.New("test error") + var errTest2 = errors.New("test error 2") + err := Wrap(errTest2, Wrap(errTest, "some random description").Error()) + require.False(t, stdlib.Is(err, errTest)) +} + +func TestWrappedUnwrap(t *testing.T) { + var errTest = errors.New("test error") + err := Wrap(errTest, "some random description") + require.Equal(t, errTest, stdlib.Unwrap(err)) +} + +func TestWrappedUnwrapMultiple(t *testing.T) { + var errTest = errors.New("test error") + var errTest2 = errors.New("test error 2") + err := Wrap(errTest2, Wrap(errTest, "some random description").Error()) + require.Equal(t, errTest2, stdlib.Unwrap(err)) +} + +func TestWrappedUnwrapFail(t *testing.T) { + var errTest = errors.New("test error") + var errTest2 = errors.New("test error 2") + err := Wrap(errTest2, Wrap(errTest, "some random description").Error()) + require.NotEqual(t, errTest, stdlib.Unwrap(err)) +} From 869531ca922b0f20aee03b3eef18d06ad3c819ed Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Thu, 9 Jan 2020 09:04:28 -0500 Subject: [PATCH 065/529] Merge PR #5495: Replace Redundant Bech32 PubKey Functions --- CHANGELOG.md | 3 + client/debug/main.go | 91 ++++++++------- client/keys/add.go | 2 +- client/keys/add_ledger_test.go | 4 +- client/rpc/validators.go | 2 +- crypto/keys/keybase_test.go | 4 +- crypto/keys/output.go | 8 +- crypto/keys/output_test.go | 4 +- crypto/keys/types_test.go | 3 +- crypto/ledger_test.go | 8 +- server/tm_cmds.go | 2 +- types/address.go | 142 +++++++----------------- types/address_test.go | 31 +++--- x/auth/types/account.go | 6 +- x/auth/types/stdtx.go | 2 +- x/auth/types/stdtx_test.go | 4 +- x/auth/vesting/types/vesting_account.go | 22 ++-- x/genutil/client/cli/gentx.go | 2 +- x/slashing/client/cli/query.go | 2 +- x/slashing/client/rest/query.go | 2 +- x/slashing/simulation/decoder.go | 4 +- x/slashing/simulation/decoder_test.go | 2 +- x/staking/client/cli/tx.go | 4 +- x/staking/client/cli/tx_test.go | 2 +- x/staking/legacy/v0_34/types.go | 4 +- x/staking/legacy/v0_36/types.go | 4 +- x/staking/legacy/v0_38/types.go | 4 +- x/staking/types/msg.go | 6 +- x/staking/types/msg_test.go | 2 +- x/staking/types/validator.go | 8 +- x/staking/types/validator_test.go | 2 +- 31 files changed, 171 insertions(+), 215 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c2a73f07f27c..e26d15caed31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,9 @@ logic has been implemented for v0.38 target version. Applications can migrate vi ### API Breaking Changes +* (types) [\#5495](https://github.com/cosmos/cosmos-sdk/pull/5495) Remove redundant `(Must)Bech32ify*` and `(Must)Get*KeyBech32` + functions in favor of `(Must)Bech32ifyPubKey` and `(Must)GetPubKeyFromBech32` respectively, both of + which take a `Bech32PubKeyType` (string). * (types) [\#5430](https://github.com/cosmos/cosmos-sdk/pull/5430) `DecCoins#Add` parameter changed from `DecCoins` to `...DecCoin`, `Coins#Add` parameter changed from `Coins` to `...Coin` * (baseapp/types) [\#5421](https://github.com/cosmos/cosmos-sdk/pull/5421) The `Error` interface (`types/errors.go`) diff --git a/client/debug/main.go b/client/debug/main.go index abda8c5d9f0b..5264983caf75 100644 --- a/client/debug/main.go +++ b/client/debug/main.go @@ -32,10 +32,46 @@ func Cmd(cdc *codec.Codec) *cobra.Command { return cmd } +// getPubKeyFromString returns a Tendermint PubKey (PubKeyEd25519) by attempting +// to decode the pubkey string from hex, base64, and finally bech32. If all +// encodings fail, an error is returned. +func getPubKeyFromString(pkstr string) (crypto.PubKey, error) { + var pubKey ed25519.PubKeyEd25519 + + bz, err := hex.DecodeString(pkstr) + if err == nil { + copy(pubKey[:], bz) + return pubKey, nil + } + + bz, err = base64.StdEncoding.DecodeString(pkstr) + if err == nil { + copy(pubKey[:], bz) + return pubKey, nil + } + + pk, err := sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeAccPub, pkstr) + if err == nil { + return pk, nil + } + + pk, err = sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeValPub, pkstr) + if err == nil { + return pk, nil + } + + pk, err = sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeConsPub, pkstr) + if err == nil { + return pk, nil + } + + return nil, fmt.Errorf("pubkey '%s' invalid; expected hex, base64, or bech32", pubKey) +} + func PubkeyCmd(cdc *codec.Codec) *cobra.Command { return &cobra.Command{ Use: "pubkey [pubkey]", - Short: "Decode a pubkey from hex, base64, or bech32", + Short: "Decode a ED25519 pubkey from hex, base64, or bech32", Long: fmt.Sprintf(`Decode a pubkey from hex, base64, or bech32. Example: @@ -44,67 +80,40 @@ $ %s debug pubkey cosmos1e0jnq2sun3dzjh8p2xq95kk0expwmd7shwjpfg `, version.ClientName, version.ClientName), Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - - pubkeyString := args[0] - var pubKeyI crypto.PubKey - - // try hex, then base64, then bech32 - pubkeyBytes, err := hex.DecodeString(pubkeyString) + pk, err := getPubKeyFromString(args[0]) if err != nil { - var err2 error - pubkeyBytes, err2 = base64.StdEncoding.DecodeString(pubkeyString) - if err2 != nil { - var err3 error - pubKeyI, err3 = sdk.GetAccPubKeyBech32(pubkeyString) - if err3 != nil { - var err4 error - pubKeyI, err4 = sdk.GetValPubKeyBech32(pubkeyString) - - if err4 != nil { - var err5 error - pubKeyI, err5 = sdk.GetConsPubKeyBech32(pubkeyString) - if err5 != nil { - return fmt.Errorf("expected hex, base64, or bech32. Got errors: hex: %v, base64: %v, bech32 Acc: %v, bech32 Val: %v, bech32 Cons: %v", - err, err2, err3, err4, err5) - } - - } - } - - } + return err } - var pubKey ed25519.PubKeyEd25519 - if pubKeyI == nil { - copy(pubKey[:], pubkeyBytes) - } else { - pubKey = pubKeyI.(ed25519.PubKeyEd25519) - pubkeyBytes = pubKey[:] + edPK, ok := pk.(ed25519.PubKeyEd25519) + if !ok { + return fmt.Errorf("invalid pubkey type; expected ED25519") } - pubKeyJSONBytes, err := cdc.MarshalJSON(pubKey) + pubKeyJSONBytes, err := cdc.MarshalJSON(edPK) if err != nil { return err } - accPub, err := sdk.Bech32ifyAccPub(pubKey) + accPub, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, edPK) if err != nil { return err } - valPub, err := sdk.Bech32ifyValPub(pubKey) + valPub, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeValPub, edPK) if err != nil { return err } - - consenusPub, err := sdk.Bech32ifyConsPub(pubKey) + consenusPub, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, edPK) if err != nil { return err } - cmd.Println("Address:", pubKey.Address()) - cmd.Printf("Hex: %X\n", pubkeyBytes) + + cmd.Println("Address:", edPK.Address()) + cmd.Printf("Hex: %X\n", edPK[:]) cmd.Println("JSON (base64):", string(pubKeyJSONBytes)) cmd.Println("Bech32 Acc:", accPub) cmd.Println("Bech32 Validator Operator:", valPub) cmd.Println("Bech32 Validator Consensus:", consenusPub) + return nil }, } diff --git a/client/keys/add.go b/client/keys/add.go index 791ba6bc8b3a..47c6d574175b 100644 --- a/client/keys/add.go +++ b/client/keys/add.go @@ -160,7 +160,7 @@ func RunAddCmd(cmd *cobra.Command, args []string, kb keys.Keybase, inBuf *bufio. } if viper.GetString(FlagPublicKey) != "" { - pk, err := sdk.GetAccPubKeyBech32(viper.GetString(FlagPublicKey)) + pk, err := sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeAccPub, viper.GetString(FlagPublicKey)) if err != nil { return err } diff --git a/client/keys/add_ledger_test.go b/client/keys/add_ledger_test.go index 184e99597137..2ada0e113581 100644 --- a/client/keys/add_ledger_test.go +++ b/client/keys/add_ledger_test.go @@ -69,7 +69,7 @@ func Test_runAddCmdLedgerWithCustomCoinType(t *testing.T) { require.Equal(t, keys.TypeLedger, key1.GetType()) require.Equal(t, "terrapub1addwnpepqvpg7r26nl2pvqqern00m6s9uaax3hauu2rzg8qpjzq9hy6xve7sw0d84m6", - sdk.MustBech32ifyAccPub(key1.GetPubKey())) + sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, key1.GetPubKey())) config.SetCoinType(118) config.SetFullFundraiserPath("44'/118'/0'/0/0") @@ -116,5 +116,5 @@ func Test_runAddCmdLedger(t *testing.T) { require.Equal(t, keys.TypeLedger, key1.GetType()) require.Equal(t, "cosmospub1addwnpepqd87l8xhcnrrtzxnkql7k55ph8fr9jarf4hn6udwukfprlalu8lgw0urza0", - sdk.MustBech32ifyAccPub(key1.GetPubKey())) + sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, key1.GetPubKey())) } diff --git a/client/rpc/validators.go b/client/rpc/validators.go index 5aaa6985c506..7b68e526890c 100644 --- a/client/rpc/validators.go +++ b/client/rpc/validators.go @@ -100,7 +100,7 @@ func (rvo ResultValidatorsOutput) String() string { } func bech32ValidatorOutput(validator *tmtypes.Validator) (ValidatorOutput, error) { - bechValPubkey, err := sdk.Bech32ifyConsPub(validator.PubKey) + bechValPubkey, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, validator.PubKey) if err != nil { return ValidatorOutput{}, err } diff --git a/crypto/keys/keybase_test.go b/crypto/keys/keybase_test.go index f74d7c0c5785..a1dfa1c7e75e 100644 --- a/crypto/keys/keybase_test.go +++ b/crypto/keys/keybase_test.go @@ -69,7 +69,7 @@ func TestCreateLedger(t *testing.T) { // The mock is available, check that the address is correct pubKey := ledger.GetPubKey() - pk, err := sdk.Bech32ifyAccPub(pubKey) + pk, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pubKey) assert.NoError(t, err) assert.Equal(t, "cosmospub1addwnpepqdszcr95mrqqs8lw099aa9h8h906zmet22pmwe9vquzcgvnm93eqygufdlv", pk) @@ -80,7 +80,7 @@ func TestCreateLedger(t *testing.T) { assert.Equal(t, "some_account", restoredKey.GetName()) assert.Equal(t, TypeLedger, restoredKey.GetType()) pubKey = restoredKey.GetPubKey() - pk, err = sdk.Bech32ifyAccPub(pubKey) + pk, err = sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pubKey) assert.NoError(t, err) assert.Equal(t, "cosmospub1addwnpepqdszcr95mrqqs8lw099aa9h8h906zmet22pmwe9vquzcgvnm93eqygufdlv", pk) diff --git a/crypto/keys/output.go b/crypto/keys/output.go index 809715df67a4..6c911f46cebe 100644 --- a/crypto/keys/output.go +++ b/crypto/keys/output.go @@ -52,7 +52,7 @@ func Bech32KeysOutput(infos []Info) ([]KeyOutput, error) { func Bech32ConsKeyOutput(keyInfo Info) (KeyOutput, error) { consAddr := sdk.ConsAddress(keyInfo.GetPubKey().Address().Bytes()) - bechPubKey, err := sdk.Bech32ifyConsPub(keyInfo.GetPubKey()) + bechPubKey, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, keyInfo.GetPubKey()) if err != nil { return KeyOutput{}, err } @@ -64,7 +64,7 @@ func Bech32ConsKeyOutput(keyInfo Info) (KeyOutput, error) { func Bech32ValKeyOutput(keyInfo Info) (KeyOutput, error) { valAddr := sdk.ValAddress(keyInfo.GetPubKey().Address().Bytes()) - bechPubKey, err := sdk.Bech32ifyValPub(keyInfo.GetPubKey()) + bechPubKey, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeValPub, keyInfo.GetPubKey()) if err != nil { return KeyOutput{}, err } @@ -77,7 +77,7 @@ func Bech32ValKeyOutput(keyInfo Info) (KeyOutput, error) { // public keys will be added. func Bech32KeyOutput(keyInfo Info) (KeyOutput, error) { accAddr := sdk.AccAddress(keyInfo.GetPubKey().Address().Bytes()) - bechPubKey, err := sdk.Bech32ifyAccPub(keyInfo.GetPubKey()) + bechPubKey, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, keyInfo.GetPubKey()) if err != nil { return KeyOutput{}, err } @@ -90,7 +90,7 @@ func Bech32KeyOutput(keyInfo Info) (KeyOutput, error) { for i, pk := range mInfo.PubKeys { accAddr := sdk.AccAddress(pk.PubKey.Address().Bytes()) - bechPubKey, err := sdk.Bech32ifyAccPub(pk.PubKey) + bechPubKey, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pk.PubKey) if err != nil { return KeyOutput{}, err } diff --git a/crypto/keys/output_test.go b/crypto/keys/output_test.go index bec0e8b5bff3..d6091c190e85 100644 --- a/crypto/keys/output_test.go +++ b/crypto/keys/output_test.go @@ -13,13 +13,13 @@ import ( func TestBech32KeysOutput(t *testing.T) { tmpKey := secp256k1.GenPrivKey().PubKey() - bechTmpKey := sdk.MustBech32ifyAccPub(tmpKey) + bechTmpKey := sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, tmpKey) tmpAddr := sdk.AccAddress(tmpKey.Address().Bytes()) multisigPks := multisig.NewPubKeyMultisigThreshold(1, []crypto.PubKey{tmpKey}) multiInfo := NewMultiInfo("multisig", multisigPks) accAddr := sdk.AccAddress(multiInfo.GetPubKey().Address().Bytes()) - bechPubKey := sdk.MustBech32ifyAccPub(multiInfo.GetPubKey()) + bechPubKey := sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, multiInfo.GetPubKey()) expectedOutput := NewKeyOutput(multiInfo.GetName(), multiInfo.GetType().String(), accAddr.String(), bechPubKey) expectedOutput.Threshold = 1 diff --git a/crypto/keys/types_test.go b/crypto/keys/types_test.go index 5c2d28c3b7ea..089eee44ce23 100644 --- a/crypto/keys/types_test.go +++ b/crypto/keys/types_test.go @@ -9,6 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/keys/hd" "github.com/cosmos/cosmos-sdk/types" + sdk "github.com/cosmos/cosmos-sdk/types" ) func Test_writeReadLedgerInfo(t *testing.T) { @@ -24,7 +25,7 @@ func Test_writeReadLedgerInfo(t *testing.T) { assert.Equal(t, "44'/118'/5'/0/1", path.String()) assert.Equal(t, "cosmospub1addwnpepqddddqg2glc8x4fl7vxjlnr7p5a3czm5kcdp4239sg6yqdc4rc2r5wmxv8p", - types.MustBech32ifyAccPub(lInfo.GetPubKey())) + types.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, lInfo.GetPubKey())) // Serialize and restore serialized := marshalInfo(lInfo) diff --git a/crypto/ledger_test.go b/crypto/ledger_test.go index 0f726b410d55..0f6c4572ad9d 100644 --- a/crypto/ledger_test.go +++ b/crypto/ledger_test.go @@ -32,7 +32,7 @@ func TestPublicKeyUnsafe(t *testing.T) { fmt.Sprintf("%x", priv.PubKey().Bytes()), "Is your device using test mnemonic: %s ?", tests.TestMnemonic) - pubKeyAddr, err := sdk.Bech32ifyAccPub(priv.PubKey()) + pubKeyAddr, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, priv.PubKey()) require.NoError(t, err) require.Equal(t, "cosmospub1addwnpepqd87l8xhcnrrtzxnkql7k55ph8fr9jarf4hn6udwukfprlalu8lgw0urza0", pubKeyAddr, "Is your device using test mnemonic: %s ?", tests.TestMnemonic) @@ -74,7 +74,7 @@ func TestPublicKeyUnsafeHDPath(t *testing.T) { tmp := priv.(PrivKeyLedgerSecp256k1) (&tmp).AssertIsPrivKeyInner() - pubKeyAddr, err := sdk.Bech32ifyAccPub(priv.PubKey()) + pubKeyAddr, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, priv.PubKey()) require.NoError(t, err) require.Equal(t, expectedAnswers[i], pubKeyAddr, @@ -108,7 +108,7 @@ func TestPublicKeySafe(t *testing.T) { fmt.Sprintf("%x", priv.PubKey().Bytes()), "Is your device using test mnemonic: %s ?", tests.TestMnemonic) - pubKeyAddr, err := sdk.Bech32ifyAccPub(priv.PubKey()) + pubKeyAddr, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, priv.PubKey()) require.NoError(t, err) require.Equal(t, "cosmospub1addwnpepqd87l8xhcnrrtzxnkql7k55ph8fr9jarf4hn6udwukfprlalu8lgw0urza0", pubKeyAddr, "Is your device using test mnemonic: %s ?", tests.TestMnemonic) @@ -172,7 +172,7 @@ func TestPublicKeyHDPath(t *testing.T) { tmp := priv.(PrivKeyLedgerSecp256k1) (&tmp).AssertIsPrivKeyInner() - pubKeyAddr, err := sdk.Bech32ifyAccPub(priv.PubKey()) + pubKeyAddr, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, priv.PubKey()) require.NoError(t, err) require.Equal(t, expectedPubKeys[i], pubKeyAddr, diff --git a/server/tm_cmds.go b/server/tm_cmds.go index 9a4611a8e403..2667e55a7df5 100644 --- a/server/tm_cmds.go +++ b/server/tm_cmds.go @@ -53,7 +53,7 @@ func ShowValidatorCmd(ctx *Context) *cobra.Command { return printlnJSON(valPubKey) } - pubkey, err := sdk.Bech32ifyConsPub(valPubKey) + pubkey, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, valPubKey) if err != nil { return err } diff --git a/types/address.go b/types/address.go index 19e81a1a7712..dce02ec9c07a 100644 --- a/types/address.go +++ b/types/address.go @@ -9,7 +9,7 @@ import ( "strings" "github.com/tendermint/tendermint/crypto" - cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino" + tmamino "github.com/tendermint/tendermint/crypto/encoding/amino" yaml "gopkg.in/yaml.v2" "github.com/tendermint/tendermint/libs/bech32" @@ -574,124 +574,69 @@ func (ca ConsAddress) Format(s fmt.State, verb rune) { // auxiliary // ---------------------------------------------------------------------------- -// Bech32ifyAccPub returns a Bech32 encoded string containing the -// Bech32PrefixAccPub prefix for a given account PubKey. -func Bech32ifyAccPub(pub crypto.PubKey) (string, error) { - bech32PrefixAccPub := GetConfig().GetBech32AccountPubPrefix() - return bech32.ConvertAndEncode(bech32PrefixAccPub, pub.Bytes()) -} - -// MustBech32ifyAccPub returns the result of Bech32ifyAccPub panicing on failure. -func MustBech32ifyAccPub(pub crypto.PubKey) string { - enc, err := Bech32ifyAccPub(pub) - if err != nil { - panic(err) - } - - return enc -} - -// Bech32ifyValPub returns a Bech32 encoded string containing the -// Bech32PrefixValPub prefix for a given validator operator's PubKey. -func Bech32ifyValPub(pub crypto.PubKey) (string, error) { - bech32PrefixValPub := GetConfig().GetBech32ValidatorPubPrefix() - return bech32.ConvertAndEncode(bech32PrefixValPub, pub.Bytes()) -} - -// MustBech32ifyValPub returns the result of Bech32ifyValPub panicing on failure. -func MustBech32ifyValPub(pub crypto.PubKey) string { - enc, err := Bech32ifyValPub(pub) - if err != nil { - panic(err) - } +// Bech32PubKeyType defines a string type alias for a Bech32 public key type. +type Bech32PubKeyType string - return enc -} +// Bech32 conversion constants +const ( + Bech32PubKeyTypeAccPub Bech32PubKeyType = "accpub" + Bech32PubKeyTypeValPub Bech32PubKeyType = "valpub" + Bech32PubKeyTypeConsPub Bech32PubKeyType = "conspub" +) -// Bech32ifyConsPub returns a Bech32 encoded string containing the -// Bech32PrefixConsPub prefixfor a given consensus node's PubKey. -func Bech32ifyConsPub(pub crypto.PubKey) (string, error) { - bech32PrefixConsPub := GetConfig().GetBech32ConsensusPubPrefix() - return bech32.ConvertAndEncode(bech32PrefixConsPub, pub.Bytes()) -} +// Bech32ifyPubKey returns a Bech32 encoded string containing the appropriate +// prefix based on the key type provided for a given PublicKey. +func Bech32ifyPubKey(pkt Bech32PubKeyType, pubkey crypto.PubKey) (string, error) { + var bech32Prefix string -// MustBech32ifyConsPub returns the result of Bech32ifyConsPub panicing on -// failure. -func MustBech32ifyConsPub(pub crypto.PubKey) string { - enc, err := Bech32ifyConsPub(pub) - if err != nil { - panic(err) - } + switch pkt { + case Bech32PubKeyTypeAccPub: + bech32Prefix = GetConfig().GetBech32AccountPubPrefix() - return enc -} + case Bech32PubKeyTypeValPub: + bech32Prefix = GetConfig().GetBech32ValidatorPubPrefix() -// GetAccPubKeyBech32 creates a PubKey for an account with a given public key -// string using the Bech32 Bech32PrefixAccPub prefix. -func GetAccPubKeyBech32(pubkey string) (pk crypto.PubKey, err error) { - bech32PrefixAccPub := GetConfig().GetBech32AccountPubPrefix() - bz, err := GetFromBech32(pubkey, bech32PrefixAccPub) - if err != nil { - return nil, err - } + case Bech32PubKeyTypeConsPub: + bech32Prefix = GetConfig().GetBech32ConsensusPubPrefix() - pk, err = cryptoAmino.PubKeyFromBytes(bz) - if err != nil { - return nil, err } - return pk, nil + return bech32.ConvertAndEncode(bech32Prefix, pubkey.Bytes()) } -// MustGetAccPubKeyBech32 returns the result of GetAccPubKeyBech32 panicing on -// failure. -func MustGetAccPubKeyBech32(pubkey string) (pk crypto.PubKey) { - pk, err := GetAccPubKeyBech32(pubkey) +// MustBech32ifyPubKey calls Bech32ifyPubKey except it panics on error. +func MustBech32ifyPubKey(pkt Bech32PubKeyType, pubkey crypto.PubKey) string { + res, err := Bech32ifyPubKey(pkt, pubkey) if err != nil { panic(err) } - return pk + return res } -// GetValPubKeyBech32 creates a PubKey for a validator's operator with a given -// public key string using the Bech32 Bech32PrefixValPub prefix. -func GetValPubKeyBech32(pubkey string) (pk crypto.PubKey, err error) { - bech32PrefixValPub := GetConfig().GetBech32ValidatorPubPrefix() - bz, err := GetFromBech32(pubkey, bech32PrefixValPub) - if err != nil { - return nil, err - } +// GetPubKeyFromBech32 returns a PublicKey from a bech32-encoded PublicKey with +// a given key type. +func GetPubKeyFromBech32(pkt Bech32PubKeyType, pubkeyStr string) (crypto.PubKey, error) { + var bech32Prefix string - pk, err = cryptoAmino.PubKeyFromBytes(bz) - if err != nil { - return nil, err - } + switch pkt { + case Bech32PubKeyTypeAccPub: + bech32Prefix = GetConfig().GetBech32AccountPubPrefix() - return pk, nil -} + case Bech32PubKeyTypeValPub: + bech32Prefix = GetConfig().GetBech32ValidatorPubPrefix() -// MustGetValPubKeyBech32 returns the result of GetValPubKeyBech32 panicing on -// failure. -func MustGetValPubKeyBech32(pubkey string) (pk crypto.PubKey) { - pk, err := GetValPubKeyBech32(pubkey) - if err != nil { - panic(err) - } + case Bech32PubKeyTypeConsPub: + bech32Prefix = GetConfig().GetBech32ConsensusPubPrefix() - return pk -} + } -// GetConsPubKeyBech32 creates a PubKey for a consensus node with a given public -// key string using the Bech32 Bech32PrefixConsPub prefix. -func GetConsPubKeyBech32(pubkey string) (pk crypto.PubKey, err error) { - bech32PrefixConsPub := GetConfig().GetBech32ConsensusPubPrefix() - bz, err := GetFromBech32(pubkey, bech32PrefixConsPub) + bz, err := GetFromBech32(pubkeyStr, bech32Prefix) if err != nil { return nil, err } - pk, err = cryptoAmino.PubKeyFromBytes(bz) + pk, err := tmamino.PubKeyFromBytes(bz) if err != nil { return nil, err } @@ -699,15 +644,14 @@ func GetConsPubKeyBech32(pubkey string) (pk crypto.PubKey, err error) { return pk, nil } -// MustGetConsPubKeyBech32 returns the result of GetConsPubKeyBech32 panicing on -// failure. -func MustGetConsPubKeyBech32(pubkey string) (pk crypto.PubKey) { - pk, err := GetConsPubKeyBech32(pubkey) +// MustGetPubKeyFromBech32 calls GetPubKeyFromBech32 except it panics on error. +func MustGetPubKeyFromBech32(pkt Bech32PubKeyType, pubkeyStr string) crypto.PubKey { + res, err := GetPubKeyFromBech32(pkt, pubkeyStr) if err != nil { panic(err) } - return pk + return res } // GetFromBech32 decodes a bytestring from a Bech32 encoded string. diff --git a/types/address_test.go b/types/address_test.go index d79ed5be92c8..7326ab784293 100644 --- a/types/address_test.go +++ b/types/address_test.go @@ -60,33 +60,33 @@ func TestRandBech32PubkeyConsistency(t *testing.T) { for i := 0; i < 1000; i++ { rand.Read(pub[:]) - mustBech32AccPub := types.MustBech32ifyAccPub(pub) - bech32AccPub, err := types.Bech32ifyAccPub(pub) + mustBech32AccPub := types.MustBech32ifyPubKey(types.Bech32PubKeyTypeAccPub, pub) + bech32AccPub, err := types.Bech32ifyPubKey(types.Bech32PubKeyTypeAccPub, pub) require.Nil(t, err) require.Equal(t, bech32AccPub, mustBech32AccPub) - mustBech32ValPub := types.MustBech32ifyValPub(pub) - bech32ValPub, err := types.Bech32ifyValPub(pub) + mustBech32ValPub := types.MustBech32ifyPubKey(types.Bech32PubKeyTypeValPub, pub) + bech32ValPub, err := types.Bech32ifyPubKey(types.Bech32PubKeyTypeValPub, pub) require.Nil(t, err) require.Equal(t, bech32ValPub, mustBech32ValPub) - mustBech32ConsPub := types.MustBech32ifyConsPub(pub) - bech32ConsPub, err := types.Bech32ifyConsPub(pub) + mustBech32ConsPub := types.MustBech32ifyPubKey(types.Bech32PubKeyTypeConsPub, pub) + bech32ConsPub, err := types.Bech32ifyPubKey(types.Bech32PubKeyTypeConsPub, pub) require.Nil(t, err) require.Equal(t, bech32ConsPub, mustBech32ConsPub) - mustAccPub := types.MustGetAccPubKeyBech32(bech32AccPub) - accPub, err := types.GetAccPubKeyBech32(bech32AccPub) + mustAccPub := types.MustGetPubKeyFromBech32(types.Bech32PubKeyTypeAccPub, bech32AccPub) + accPub, err := types.GetPubKeyFromBech32(types.Bech32PubKeyTypeAccPub, bech32AccPub) require.Nil(t, err) require.Equal(t, accPub, mustAccPub) - mustValPub := types.MustGetValPubKeyBech32(bech32ValPub) - valPub, err := types.GetValPubKeyBech32(bech32ValPub) + mustValPub := types.MustGetPubKeyFromBech32(types.Bech32PubKeyTypeValPub, bech32ValPub) + valPub, err := types.GetPubKeyFromBech32(types.Bech32PubKeyTypeValPub, bech32ValPub) require.Nil(t, err) require.Equal(t, valPub, mustValPub) - mustConsPub := types.MustGetConsPubKeyBech32(bech32ConsPub) - consPub, err := types.GetConsPubKeyBech32(bech32ConsPub) + mustConsPub := types.MustGetPubKeyFromBech32(types.Bech32PubKeyTypeConsPub, bech32ConsPub) + consPub, err := types.GetPubKeyFromBech32(types.Bech32PubKeyTypeConsPub, bech32ConsPub) require.Nil(t, err) require.Equal(t, consPub, mustConsPub) @@ -246,7 +246,7 @@ func TestConfiguredPrefix(t *testing.T) { acc.String(), prefix+types.PrefixAccount), acc.String()) - bech32Pub := types.MustBech32ifyAccPub(pub) + bech32Pub := types.MustBech32ifyPubKey(types.Bech32PubKeyTypeAccPub, pub) require.True(t, strings.HasPrefix( bech32Pub, prefix+types.PrefixPublic)) @@ -260,7 +260,7 @@ func TestConfiguredPrefix(t *testing.T) { val.String(), prefix+types.PrefixValidator+types.PrefixAddress)) - bech32ValPub := types.MustBech32ifyValPub(pub) + bech32ValPub := types.MustBech32ifyPubKey(types.Bech32PubKeyTypeValPub, pub) require.True(t, strings.HasPrefix( bech32ValPub, prefix+types.PrefixValidator+types.PrefixPublic)) @@ -274,12 +274,11 @@ func TestConfiguredPrefix(t *testing.T) { cons.String(), prefix+types.PrefixConsensus+types.PrefixAddress)) - bech32ConsPub := types.MustBech32ifyConsPub(pub) + bech32ConsPub := types.MustBech32ifyPubKey(types.Bech32PubKeyTypeConsPub, pub) require.True(t, strings.HasPrefix( bech32ConsPub, prefix+types.PrefixConsensus+types.PrefixPublic)) } - } } diff --git a/x/auth/types/account.go b/x/auth/types/account.go index 69dc5be447d8..a8d919a385ee 100644 --- a/x/auth/types/account.go +++ b/x/auth/types/account.go @@ -153,7 +153,7 @@ func (acc BaseAccount) MarshalYAML() (interface{}, error) { } if acc.PubKey != nil { - pks, err := sdk.Bech32ifyAccPub(acc.PubKey) + pks, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, acc.PubKey) if err != nil { return nil, err } @@ -179,7 +179,7 @@ func (acc BaseAccount) MarshalJSON() ([]byte, error) { } if acc.PubKey != nil { - pks, err := sdk.Bech32ifyAccPub(acc.PubKey) + pks, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, acc.PubKey) if err != nil { return nil, err } @@ -198,7 +198,7 @@ func (acc *BaseAccount) UnmarshalJSON(bz []byte) error { } if alias.PubKey != "" { - pk, err := sdk.GetAccPubKeyBech32(alias.PubKey) + pk, err := sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeAccPub, alias.PubKey) if err != nil { return err } diff --git a/x/auth/types/stdtx.go b/x/auth/types/stdtx.go index 34cd11b934a6..a37408f9e9e6 100644 --- a/x/auth/types/stdtx.go +++ b/x/auth/types/stdtx.go @@ -284,7 +284,7 @@ func (ss StdSignature) MarshalYAML() (interface{}, error) { ) if ss.PubKey != nil { - pubkey, err = sdk.Bech32ifyAccPub(ss.PubKey) + pubkey, err = sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, ss.PubKey) if err != nil { return nil, err } diff --git a/x/auth/types/stdtx_test.go b/x/auth/types/stdtx_test.go index 8131006f59d5..a8ce9d721076 100644 --- a/x/auth/types/stdtx_test.go +++ b/x/auth/types/stdtx_test.go @@ -153,11 +153,11 @@ func TestStdSignatureMarshalYAML(t *testing.T) { }, { StdSignature{PubKey: pubKey, Signature: []byte("dummySig")}, - fmt.Sprintf("|\n pubkey: %s\n signature: dummySig\n", sdk.MustBech32ifyAccPub(pubKey)), + fmt.Sprintf("|\n pubkey: %s\n signature: dummySig\n", sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pubKey)), }, { StdSignature{PubKey: pubKey, Signature: nil}, - fmt.Sprintf("|\n pubkey: %s\n signature: \"\"\n", sdk.MustBech32ifyAccPub(pubKey)), + fmt.Sprintf("|\n pubkey: %s\n signature: \"\"\n", sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pubKey)), }, } diff --git a/x/auth/vesting/types/vesting_account.go b/x/auth/vesting/types/vesting_account.go index 05dca2857e33..256c9d598fec 100644 --- a/x/auth/vesting/types/vesting_account.go +++ b/x/auth/vesting/types/vesting_account.go @@ -220,7 +220,7 @@ func (bva BaseVestingAccount) MarshalYAML() (interface{}, error) { } if bva.PubKey != nil { - pks, err := sdk.Bech32ifyAccPub(bva.PubKey) + pks, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, bva.PubKey) if err != nil { return nil, err } @@ -250,7 +250,7 @@ func (bva BaseVestingAccount) MarshalJSON() ([]byte, error) { } if bva.PubKey != nil { - pks, err := sdk.Bech32ifyAccPub(bva.PubKey) + pks, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, bva.PubKey) if err != nil { return nil, err } @@ -274,7 +274,7 @@ func (bva *BaseVestingAccount) UnmarshalJSON(bz []byte) error { ) if alias.PubKey != "" { - pk, err = sdk.GetAccPubKeyBech32(alias.PubKey) + pk, err = sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeAccPub, alias.PubKey) if err != nil { return err } @@ -406,7 +406,7 @@ func (cva ContinuousVestingAccount) MarshalYAML() (interface{}, error) { } if cva.PubKey != nil { - pks, err := sdk.Bech32ifyAccPub(cva.PubKey) + pks, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, cva.PubKey) if err != nil { return nil, err } @@ -437,7 +437,7 @@ func (cva ContinuousVestingAccount) MarshalJSON() ([]byte, error) { } if cva.PubKey != nil { - pks, err := sdk.Bech32ifyAccPub(cva.PubKey) + pks, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, cva.PubKey) if err != nil { return nil, err } @@ -461,7 +461,7 @@ func (cva *ContinuousVestingAccount) UnmarshalJSON(bz []byte) error { ) if alias.PubKey != "" { - pk, err = sdk.GetAccPubKeyBech32(alias.PubKey) + pk, err = sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeAccPub, alias.PubKey) if err != nil { return err } @@ -622,7 +622,7 @@ func (pva PeriodicVestingAccount) MarshalYAML() (interface{}, error) { } if pva.PubKey != nil { - pks, err := sdk.Bech32ifyAccPub(pva.PubKey) + pks, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pva.PubKey) if err != nil { return nil, err } @@ -654,7 +654,7 @@ func (pva PeriodicVestingAccount) MarshalJSON() ([]byte, error) { } if pva.PubKey != nil { - pks, err := sdk.Bech32ifyAccPub(pva.PubKey) + pks, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pva.PubKey) if err != nil { return nil, err } @@ -678,7 +678,7 @@ func (pva *PeriodicVestingAccount) UnmarshalJSON(bz []byte) error { ) if alias.PubKey != "" { - pk, err = sdk.GetAccPubKeyBech32(alias.PubKey) + pk, err = sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeAccPub, alias.PubKey) if err != nil { return err } @@ -781,7 +781,7 @@ func (dva DelayedVestingAccount) MarshalJSON() ([]byte, error) { } if dva.PubKey != nil { - pks, err := sdk.Bech32ifyAccPub(dva.PubKey) + pks, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, dva.PubKey) if err != nil { return nil, err } @@ -805,7 +805,7 @@ func (dva *DelayedVestingAccount) UnmarshalJSON(bz []byte) error { ) if alias.PubKey != "" { - pk, err = sdk.GetAccPubKeyBech32(alias.PubKey) + pk, err = sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeAccPub, alias.PubKey) if err != nil { return err } diff --git a/x/genutil/client/cli/gentx.go b/x/genutil/client/cli/gentx.go index aae33d6b8b7c..7d0fb75207b2 100644 --- a/x/genutil/client/cli/gentx.go +++ b/x/genutil/client/cli/gentx.go @@ -76,7 +76,7 @@ func GenTxCmd(ctx *server.Context, cdc *codec.Codec, mbm module.BasicManager, sm } // Read --pubkey, if empty take it from priv_validator.json if valPubKeyString := viper.GetString(flagPubKey); valPubKeyString != "" { - valPubKey, err = sdk.GetConsPubKeyBech32(valPubKeyString) + valPubKey, err = sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeConsPub, valPubKeyString) if err != nil { return errors.Wrap(err, "failed to get consensus node public key") } diff --git a/x/slashing/client/cli/query.go b/x/slashing/client/cli/query.go index a5b0cd1be524..71f404230758 100644 --- a/x/slashing/client/cli/query.go +++ b/x/slashing/client/cli/query.go @@ -50,7 +50,7 @@ $ query slashing signing-info cosmosvalconspub1zcjduepqfhvwcmt7p06fvdge RunE: func(cmd *cobra.Command, args []string) error { cliCtx := context.NewCLIContext().WithCodec(cdc) - pk, err := sdk.GetConsPubKeyBech32(args[0]) + pk, err := sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeConsPub, args[0]) if err != nil { return err } diff --git a/x/slashing/client/rest/query.go b/x/slashing/client/rest/query.go index 2c1c845936d0..751fe648dc45 100644 --- a/x/slashing/client/rest/query.go +++ b/x/slashing/client/rest/query.go @@ -33,7 +33,7 @@ func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router) { func signingInfoHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) - pk, err := sdk.GetConsPubKeyBech32(vars["validatorPubKey"]) + pk, err := sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeConsPub, vars["validatorPubKey"]) if err != nil { rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return diff --git a/x/slashing/simulation/decoder.go b/x/slashing/simulation/decoder.go index 99af7c0b722b..89fdc795a795 100644 --- a/x/slashing/simulation/decoder.go +++ b/x/slashing/simulation/decoder.go @@ -31,8 +31,8 @@ func DecodeStore(cdc *codec.Codec, kvA, kvB cmn.KVPair) string { var pubKeyA, pubKeyB crypto.PubKey cdc.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &pubKeyA) cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &pubKeyB) - bechPKA := sdk.MustBech32ifyAccPub(pubKeyA) - bechPKB := sdk.MustBech32ifyAccPub(pubKeyB) + bechPKA := sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pubKeyA) + bechPKB := sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pubKeyB) return fmt.Sprintf("PubKeyA: %s\nPubKeyB: %s", bechPKA, bechPKB) default: diff --git a/x/slashing/simulation/decoder_test.go b/x/slashing/simulation/decoder_test.go index 9220ef917628..23d063110baa 100644 --- a/x/slashing/simulation/decoder_test.go +++ b/x/slashing/simulation/decoder_test.go @@ -35,7 +35,7 @@ func TestDecodeStore(t *testing.T) { cdc := makeTestCodec() info := types.NewValidatorSigningInfo(consAddr1, 0, 1, time.Now().UTC(), false, 0) - bechPK := sdk.MustBech32ifyAccPub(delPk1) + bechPK := sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, delPk1) missed := true kvPairs := cmn.KVPairs{ diff --git a/x/staking/client/cli/tx.go b/x/staking/client/cli/tx.go index 374d061e070a..a9b8b526303a 100644 --- a/x/staking/client/cli/tx.go +++ b/x/staking/client/cli/tx.go @@ -315,7 +315,7 @@ func PrepareFlagsForTxCreateValidator( viper.Set(flags.FlagFrom, viper.GetString(flags.FlagName)) viper.Set(FlagNodeID, nodeID) viper.Set(FlagIP, ip) - viper.Set(FlagPubKey, sdk.MustBech32ifyConsPub(valPubKey)) + viper.Set(FlagPubKey, sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, valPubKey)) viper.Set(FlagMoniker, config.Moniker) viper.Set(FlagWebsite, website) viper.Set(FlagSecurityContact, securityContact) @@ -353,7 +353,7 @@ func BuildCreateValidatorMsg(cliCtx context.CLIContext, txBldr auth.TxBuilder) ( valAddr := cliCtx.GetFromAddress() pkStr := viper.GetString(FlagPubKey) - pk, err := sdk.GetConsPubKeyBech32(pkStr) + pk, err := sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeConsPub, pkStr) if err != nil { return txBldr, nil, err } diff --git a/x/staking/client/cli/tx_test.go b/x/staking/client/cli/tx_test.go index 60283fa00700..5759c3897021 100644 --- a/x/staking/client/cli/tx_test.go +++ b/x/staking/client/cli/tx_test.go @@ -21,7 +21,7 @@ func TestPrepareFlagsForTxCreateValidator(t *testing.T) { logger := log.NewNopLogger() ctx := server.NewContext(config, logger) - valPubKey, _ := sdk.GetConsPubKeyBech32("cosmosvalconspub1zcjduepq7jsrkl9fgqk0wj3ahmfr8pgxj6vakj2wzn656s8pehh0zhv2w5as5gd80a") + valPubKey, _ := sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeConsPub, "cosmosvalconspub1zcjduepq7jsrkl9fgqk0wj3ahmfr8pgxj6vakj2wzn656s8pehh0zhv2w5as5gd80a") type args struct { config *cfg.Config diff --git a/x/staking/legacy/v0_34/types.go b/x/staking/legacy/v0_34/types.go index 64e997ebcf69..013edb792d9e 100644 --- a/x/staking/legacy/v0_34/types.go +++ b/x/staking/legacy/v0_34/types.go @@ -126,7 +126,7 @@ type ( ) func (v Validator) MarshalJSON() ([]byte, error) { - bechConsPubKey, err := sdk.Bech32ifyConsPub(v.ConsPubKey) + bechConsPubKey, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, v.ConsPubKey) if err != nil { return nil, err } @@ -152,7 +152,7 @@ func (v *Validator) UnmarshalJSON(data []byte) error { if err := codec.Cdc.UnmarshalJSON(data, bv); err != nil { return err } - consPubKey, err := sdk.GetConsPubKeyBech32(bv.ConsPubKey) + consPubKey, err := sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeConsPub, bv.ConsPubKey) if err != nil { return err } diff --git a/x/staking/legacy/v0_36/types.go b/x/staking/legacy/v0_36/types.go index 1e0ff71bd8f8..246d6b011821 100644 --- a/x/staking/legacy/v0_36/types.go +++ b/x/staking/legacy/v0_36/types.go @@ -89,7 +89,7 @@ func NewGenesisState( } func (v Validator) MarshalJSON() ([]byte, error) { - bechConsPubKey, err := sdk.Bech32ifyConsPub(v.ConsPubKey) + bechConsPubKey, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, v.ConsPubKey) if err != nil { return nil, err } @@ -114,7 +114,7 @@ func (v *Validator) UnmarshalJSON(data []byte) error { if err := codec.Cdc.UnmarshalJSON(data, bv); err != nil { return err } - consPubKey, err := sdk.GetConsPubKeyBech32(bv.ConsPubKey) + consPubKey, err := sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeConsPub, bv.ConsPubKey) if err != nil { return err } diff --git a/x/staking/legacy/v0_38/types.go b/x/staking/legacy/v0_38/types.go index 88bce2c5c505..b3c27e8b47cd 100644 --- a/x/staking/legacy/v0_38/types.go +++ b/x/staking/legacy/v0_38/types.go @@ -100,7 +100,7 @@ func NewGenesisState( // MarshalJSON marshals the validator to JSON using Bech32 func (v Validator) MarshalJSON() ([]byte, error) { - bechConsPubKey, err := sdk.Bech32ifyConsPub(v.ConsPubKey) + bechConsPubKey, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, v.ConsPubKey) if err != nil { return nil, err } @@ -126,7 +126,7 @@ func (v *Validator) UnmarshalJSON(data []byte) error { if err := codec.Cdc.UnmarshalJSON(data, bv); err != nil { return err } - consPubKey, err := sdk.GetConsPubKeyBech32(bv.ConsPubKey) + consPubKey, err := sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeConsPub, bv.ConsPubKey) if err != nil { return err } diff --git a/x/staking/types/msg.go b/x/staking/types/msg.go index 8b47cfec443c..62d2295fce6f 100644 --- a/x/staking/types/msg.go +++ b/x/staking/types/msg.go @@ -89,7 +89,7 @@ func (msg MsgCreateValidator) MarshalJSON() ([]byte, error) { Commission: msg.Commission, DelegatorAddress: msg.DelegatorAddress, ValidatorAddress: msg.ValidatorAddress, - PubKey: sdk.MustBech32ifyConsPub(msg.PubKey), + PubKey: sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, msg.PubKey), Value: msg.Value, MinSelfDelegation: msg.MinSelfDelegation, }) @@ -108,7 +108,7 @@ func (msg *MsgCreateValidator) UnmarshalJSON(bz []byte) error { msg.DelegatorAddress = msgCreateValJSON.DelegatorAddress msg.ValidatorAddress = msgCreateValJSON.ValidatorAddress var err error - msg.PubKey, err = sdk.GetConsPubKeyBech32(msgCreateValJSON.PubKey) + msg.PubKey, err = sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeConsPub, msgCreateValJSON.PubKey) if err != nil { return err } @@ -134,7 +134,7 @@ func (msg MsgCreateValidator) MarshalYAML() (interface{}, error) { MinSelfDelegation: msg.MinSelfDelegation, DelegatorAddress: msg.DelegatorAddress, ValidatorAddress: msg.ValidatorAddress, - PubKey: sdk.MustBech32ifyConsPub(msg.PubKey), + PubKey: sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, msg.PubKey), Value: msg.Value, }) diff --git a/x/staking/types/msg_test.go b/x/staking/types/msg_test.go index 1b5d826b8772..784b653d2b8f 100644 --- a/x/staking/types/msg_test.go +++ b/x/staking/types/msg_test.go @@ -175,7 +175,7 @@ func TestMsgMarshalYAML(t *testing.T) { msg := NewMsgCreateValidator(tc.validatorAddr, tc.pubkey, tc.bond, description, tc.CommissionRates, tc.minSelfDelegation) bs, err := yaml.Marshal(msg) require.NoError(t, err) - bechifiedPub, err := sdk.Bech32ifyConsPub(msg.PubKey) + bechifiedPub, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, msg.PubKey) require.NoError(t, err) want := fmt.Sprintf(`| diff --git a/x/staking/types/validator.go b/x/staking/types/validator.go index 2ac2903dcf0b..d64e0ce3e751 100644 --- a/x/staking/types/validator.go +++ b/x/staking/types/validator.go @@ -68,7 +68,7 @@ func (v Validator) MarshalYAML() (interface{}, error) { MinSelfDelegation sdk.Int }{ OperatorAddress: v.OperatorAddress, - ConsPubKey: sdk.MustBech32ifyConsPub(v.ConsPubKey), + ConsPubKey: sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, v.ConsPubKey), Jailed: v.Jailed, Status: v.Status, Tokens: v.Tokens, @@ -165,7 +165,7 @@ func UnmarshalValidator(cdc *codec.Codec, value []byte) (validator Validator, er // String returns a human readable string representation of a validator. func (v Validator) String() string { - bechConsPubKey, err := sdk.Bech32ifyConsPub(v.ConsPubKey) + bechConsPubKey, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, v.ConsPubKey) if err != nil { panic(err) } @@ -203,7 +203,7 @@ type bechValidator struct { // MarshalJSON marshals the validator to JSON using Bech32 func (v Validator) MarshalJSON() ([]byte, error) { - bechConsPubKey, err := sdk.Bech32ifyConsPub(v.ConsPubKey) + bechConsPubKey, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, v.ConsPubKey) if err != nil { return nil, err } @@ -229,7 +229,7 @@ func (v *Validator) UnmarshalJSON(data []byte) error { if err := codec.Cdc.UnmarshalJSON(data, bv); err != nil { return err } - consPubKey, err := sdk.GetConsPubKeyBech32(bv.ConsPubKey) + consPubKey, err := sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeConsPub, bv.ConsPubKey) if err != nil { return err } diff --git a/x/staking/types/validator_test.go b/x/staking/types/validator_test.go index f705d0d8df99..e6a7ccbe961a 100644 --- a/x/staking/types/validator_test.go +++ b/x/staking/types/validator_test.go @@ -278,7 +278,7 @@ func TestValidatorSetInitialCommission(t *testing.T) { func TestValidatorMarshalYAML(t *testing.T) { validator := NewValidator(valAddr1, pk1, Description{}) - bechifiedPub, err := sdk.Bech32ifyConsPub(validator.ConsPubKey) + bechifiedPub, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, validator.ConsPubKey) require.NoError(t, err) bs, err := yaml.Marshal(validator) require.NoError(t, err) From d7bdfe3110b57a4b2dc76de9d7a1e735d20a54d6 Mon Sep 17 00:00:00 2001 From: Jack Zampolin Date: Thu, 9 Jan 2020 09:38:56 -0800 Subject: [PATCH 066/529] Merge PR #5501: Fix keyring error message on macos --- go.mod | 2 ++ go.sum | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 93c6f3b209e9..98623a826dec 100644 --- a/go.mod +++ b/go.mod @@ -31,3 +31,5 @@ require ( ) go 1.13 + +replace github.com/keybase/go-keychain => github.com/keybase/go-keychain v0.0.0-20191220220820-f65a47cbe0b1 diff --git a/go.sum b/go.sum index cc5d9b873f77..e0479a70f8b8 100644 --- a/go.sum +++ b/go.sum @@ -136,8 +136,8 @@ github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlT github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d h1:Z+RDyXzjKE0i2sTjZ/b1uxiGtPhFy34Ou/Tk0qwN0kM= -github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d/go.mod h1:JJNrCn9otv/2QP4D7SMJBgaleKpOf66PnW6F5WGNRIc= +github.com/keybase/go-keychain v0.0.0-20191220220820-f65a47cbe0b1 h1:Lk38J60jgB05LTkSEElUXe49VEzWMNrPyPFf2vhKM1k= +github.com/keybase/go-keychain v0.0.0-20191220220820-f65a47cbe0b1/go.mod h1:JJNrCn9otv/2QP4D7SMJBgaleKpOf66PnW6F5WGNRIc= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= From 3df3887597d7decaca3bf7c950fd20aba55d3868 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Thu, 9 Jan 2020 15:14:23 -0500 Subject: [PATCH 067/529] Merge PR #5499: Cleanup genesis state validation + Genutil --- CHANGELOG.md | 1 + x/auth/module.go | 7 ++++--- x/bank/module.go | 7 ++++--- x/crisis/module.go | 4 +++- x/distribution/module.go | 7 ++++--- x/evidence/module.go | 3 +-- x/genutil/client/cli/validate_genesis.go | 2 +- x/genutil/genesis.go | 7 +++++-- x/genutil/module.go | 9 +++++---- x/genutil/types/genesis_state.go | 7 +++++++ x/gov/module.go | 7 ++++--- x/mint/module.go | 7 ++++--- x/slashing/module.go | 7 ++++--- x/staking/module.go | 7 ++++--- x/supply/module.go | 7 ++++--- 15 files changed, 55 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e26d15caed31..63226c53c871 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -248,6 +248,7 @@ to detail this new feature and how state transitions occur. ### Bug Fixes +* (x/genutil) [\#5499](https://github.com/cosmos/cosmos-sdk/pull/) Ensure `DefaultGenesis` returns valid and non-nil default genesis state. * (client) [\#5303](https://github.com/cosmos/cosmos-sdk/issues/5303) Fix ignored error in tx generate only mode. * (cli) [\#4763](https://github.com/cosmos/cosmos-sdk/issues/4763) Fix flag `--min-self-delegation` for staking `EditValidator` * (keys) Fix ledger custom coin type support bug diff --git a/x/auth/module.go b/x/auth/module.go index 510f4304d7c5..d3cf501e4f04 100644 --- a/x/auth/module.go +++ b/x/auth/module.go @@ -2,6 +2,7 @@ package auth import ( "encoding/json" + "fmt" "math/rand" "github.com/gorilla/mux" @@ -47,10 +48,10 @@ func (AppModuleBasic) DefaultGenesis() json.RawMessage { // ValidateGenesis performs genesis state validation for the auth module. func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error { var data types.GenesisState - err := types.ModuleCdc.UnmarshalJSON(bz, &data) - if err != nil { - return err + if err := types.ModuleCdc.UnmarshalJSON(bz, &data); err != nil { + return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) } + return types.ValidateGenesis(data) } diff --git a/x/bank/module.go b/x/bank/module.go index 0430d18f1550..114962382758 100644 --- a/x/bank/module.go +++ b/x/bank/module.go @@ -2,6 +2,7 @@ package bank import ( "encoding/json" + "fmt" "math/rand" "github.com/gorilla/mux" @@ -45,10 +46,10 @@ func (AppModuleBasic) DefaultGenesis() json.RawMessage { // ValidateGenesis performs genesis state validation for the bank module. func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error { var data GenesisState - err := ModuleCdc.UnmarshalJSON(bz, &data) - if err != nil { - return err + if err := ModuleCdc.UnmarshalJSON(bz, &data); err != nil { + return fmt.Errorf("failed to unmarshal %s genesis state: %w", ModuleName, err) } + return ValidateGenesis(data) } diff --git a/x/crisis/module.go b/x/crisis/module.go index 4318c516cea8..1885f69ade9f 100644 --- a/x/crisis/module.go +++ b/x/crisis/module.go @@ -2,6 +2,7 @@ package crisis import ( "encoding/json" + "fmt" "github.com/gorilla/mux" "github.com/spf13/cobra" @@ -45,8 +46,9 @@ func (AppModuleBasic) DefaultGenesis() json.RawMessage { func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error { var data types.GenesisState if err := types.ModuleCdc.UnmarshalJSON(bz, &data); err != nil { - return err + return fmt.Errorf("failed to unmarshal %s genesis state: %w", ModuleName, err) } + return types.ValidateGenesis(data) } diff --git a/x/distribution/module.go b/x/distribution/module.go index c0452ebb3c6b..0b143d6478b8 100644 --- a/x/distribution/module.go +++ b/x/distribution/module.go @@ -2,6 +2,7 @@ package distribution import ( "encoding/json" + "fmt" "math/rand" "github.com/gorilla/mux" @@ -49,10 +50,10 @@ func (AppModuleBasic) DefaultGenesis() json.RawMessage { // ValidateGenesis performs genesis state validation for the distribution module. func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error { var data GenesisState - err := ModuleCdc.UnmarshalJSON(bz, &data) - if err != nil { - return err + if err := ModuleCdc.UnmarshalJSON(bz, &data); err != nil { + return fmt.Errorf("failed to unmarshal %s genesis state: %w", ModuleName, err) } + return ValidateGenesis(data) } diff --git a/x/evidence/module.go b/x/evidence/module.go index aa4129469dab..30b427a95c1d 100644 --- a/x/evidence/module.go +++ b/x/evidence/module.go @@ -58,8 +58,7 @@ func (AppModuleBasic) DefaultGenesis() json.RawMessage { // ValidateGenesis performs genesis state validation for the evidence module. func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error { var gs GenesisState - err := ModuleCdc.UnmarshalJSON(bz, &gs) - if err != nil { + if err := ModuleCdc.UnmarshalJSON(bz, &gs); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", ModuleName, err) } diff --git a/x/genutil/client/cli/validate_genesis.go b/x/genutil/client/cli/validate_genesis.go index f4baa5dc9df3..6be33bdabf09 100644 --- a/x/genutil/client/cli/validate_genesis.go +++ b/x/genutil/client/cli/validate_genesis.go @@ -38,7 +38,7 @@ func ValidateGenesisCmd(ctx *server.Context, cdc *codec.Codec, mbm module.BasicM var genState map[string]json.RawMessage if err = cdc.UnmarshalJSON(genDoc.AppState, &genState); err != nil { - return fmt.Errorf("error unmarshaling genesis doc %s: %s", genesis, err.Error()) + return fmt.Errorf("error unmarshalling genesis doc %s: %s", genesis, err.Error()) } if err = mbm.ValidateGenesis(genState); err != nil { diff --git a/x/genutil/genesis.go b/x/genutil/genesis.go index c1a06a8b9aff..c8564bdc4e2d 100644 --- a/x/genutil/genesis.go +++ b/x/genutil/genesis.go @@ -9,12 +9,15 @@ import ( ) // InitGenesis - initialize accounts and deliver genesis transactions -func InitGenesis(ctx sdk.Context, cdc *codec.Codec, stakingKeeper types.StakingKeeper, - deliverTx deliverTxfn, genesisState GenesisState) []abci.ValidatorUpdate { +func InitGenesis( + ctx sdk.Context, cdc *codec.Codec, stakingKeeper types.StakingKeeper, + deliverTx deliverTxfn, genesisState GenesisState, +) []abci.ValidatorUpdate { var validators []abci.ValidatorUpdate if len(genesisState.GenTxs) > 0 { validators = DeliverGenTxs(ctx, cdc, genesisState.GenTxs, stakingKeeper, deliverTx) } + return validators } diff --git a/x/genutil/module.go b/x/genutil/module.go index 8d8f296ae1c9..31ca1b463523 100644 --- a/x/genutil/module.go +++ b/x/genutil/module.go @@ -2,6 +2,7 @@ package genutil import ( "encoding/json" + "fmt" "github.com/gorilla/mux" "github.com/spf13/cobra" @@ -34,16 +35,16 @@ func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) {} // DefaultGenesis returns default genesis state as raw bytes for the genutil // module. func (AppModuleBasic) DefaultGenesis() json.RawMessage { - return ModuleCdc.MustMarshalJSON(GenesisState{}) + return ModuleCdc.MustMarshalJSON(types.DefaultGenesisState()) } // ValidateGenesis performs genesis state validation for the genutil module. func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error { var data GenesisState - err := ModuleCdc.UnmarshalJSON(bz, &data) - if err != nil { - return err + if err := ModuleCdc.UnmarshalJSON(bz, &data); err != nil { + return fmt.Errorf("failed to unmarshal %s genesis state: %w", ModuleName, err) } + return ValidateGenesis(data) } diff --git a/x/genutil/types/genesis_state.go b/x/genutil/types/genesis_state.go index e568bb42076a..1303ee82ca4b 100644 --- a/x/genutil/types/genesis_state.go +++ b/x/genutil/types/genesis_state.go @@ -25,6 +25,13 @@ func NewGenesisState(genTxs []json.RawMessage) GenesisState { } } +// DefaultGenesisState returns the genutil module's default genesis state. +func DefaultGenesisState() GenesisState { + return GenesisState{ + GenTxs: []json.RawMessage{}, + } +} + // NewGenesisStateFromStdTx creates a new GenesisState object // from auth transactions func NewGenesisStateFromStdTx(genTxs []authtypes.StdTx) GenesisState { diff --git a/x/gov/module.go b/x/gov/module.go index 1ef3a8c0f5cf..7ad5ecbc0ace 100644 --- a/x/gov/module.go +++ b/x/gov/module.go @@ -4,6 +4,7 @@ package gov import ( "encoding/json" + "fmt" "math/rand" "github.com/gorilla/mux" @@ -60,10 +61,10 @@ func (AppModuleBasic) DefaultGenesis() json.RawMessage { // ValidateGenesis performs genesis state validation for the gov module. func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error { var data GenesisState - err := ModuleCdc.UnmarshalJSON(bz, &data) - if err != nil { - return err + if err := ModuleCdc.UnmarshalJSON(bz, &data); err != nil { + return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) } + return ValidateGenesis(data) } diff --git a/x/mint/module.go b/x/mint/module.go index f0e36e1693d7..95b171251ee1 100644 --- a/x/mint/module.go +++ b/x/mint/module.go @@ -2,6 +2,7 @@ package mint import ( "encoding/json" + "fmt" "math/rand" "github.com/gorilla/mux" @@ -47,10 +48,10 @@ func (AppModuleBasic) DefaultGenesis() json.RawMessage { // ValidateGenesis performs genesis state validation for the mint module. func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error { var data GenesisState - err := ModuleCdc.UnmarshalJSON(bz, &data) - if err != nil { - return err + if err := ModuleCdc.UnmarshalJSON(bz, &data); err != nil { + return fmt.Errorf("failed to unmarshal %s genesis state: %w", ModuleName, err) } + return ValidateGenesis(data) } diff --git a/x/slashing/module.go b/x/slashing/module.go index 47d15cf89937..e99b421574fe 100644 --- a/x/slashing/module.go +++ b/x/slashing/module.go @@ -2,6 +2,7 @@ package slashing import ( "encoding/json" + "fmt" "math/rand" "github.com/gorilla/mux" @@ -51,10 +52,10 @@ func (AppModuleBasic) DefaultGenesis() json.RawMessage { // ValidateGenesis performs genesis state validation for the slashing module. func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error { var data GenesisState - err := ModuleCdc.UnmarshalJSON(bz, &data) - if err != nil { - return err + if err := ModuleCdc.UnmarshalJSON(bz, &data); err != nil { + return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) } + return ValidateGenesis(data) } diff --git a/x/staking/module.go b/x/staking/module.go index 69a8cb940504..0f39343af843 100644 --- a/x/staking/module.go +++ b/x/staking/module.go @@ -2,6 +2,7 @@ package staking import ( "encoding/json" + "fmt" "math/rand" "github.com/gorilla/mux" @@ -54,10 +55,10 @@ func (AppModuleBasic) DefaultGenesis() json.RawMessage { // ValidateGenesis performs genesis state validation for the staking module. func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error { var data GenesisState - err := ModuleCdc.UnmarshalJSON(bz, &data) - if err != nil { - return err + if err := ModuleCdc.UnmarshalJSON(bz, &data); err != nil { + return fmt.Errorf("failed to unmarshal %s genesis state: %w", ModuleName, err) } + return ValidateGenesis(data) } diff --git a/x/supply/module.go b/x/supply/module.go index 307b77865b36..f9e45322a99c 100644 --- a/x/supply/module.go +++ b/x/supply/module.go @@ -2,6 +2,7 @@ package supply import ( "encoding/json" + "fmt" "math/rand" "github.com/gorilla/mux" @@ -48,10 +49,10 @@ func (AppModuleBasic) DefaultGenesis() json.RawMessage { // ValidateGenesis performs genesis state validation for the supply module. func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error { var data GenesisState - err := ModuleCdc.UnmarshalJSON(bz, &data) - if err != nil { - return err + if err := ModuleCdc.UnmarshalJSON(bz, &data); err != nil { + return fmt.Errorf("failed to unmarshal %s genesis state: %w", ModuleName, err) } + return ValidateGenesis(data) } From 602411566736e17b324ff3c7ea011b13a13b9b03 Mon Sep 17 00:00:00 2001 From: Xuefeng Zhu Date: Fri, 10 Jan 2020 08:33:43 -0600 Subject: [PATCH 068/529] Merge PR #5503: use build-in iterator function --- x/staking/keeper/val_state_change.go | 27 +++------------------------ 1 file changed, 3 insertions(+), 24 deletions(-) diff --git a/x/staking/keeper/val_state_change.go b/x/staking/keeper/val_state_change.go index f43a8f9da5a7..ed630f15ce22 100644 --- a/x/staking/keeper/val_state_change.go +++ b/x/staking/keeper/val_state_change.go @@ -81,7 +81,6 @@ func (k Keeper) BlockValidatorUpdates(ctx sdk.Context) []abci.ValidatorUpdate { // are returned to Tendermint. func (k Keeper) ApplyAndReturnValidatorSetUpdates(ctx sdk.Context) (updates []abci.ValidatorUpdate) { - store := ctx.KVStore(k.storeKey) maxValidators := k.GetParams(ctx).MaxValidators totalPower := sdk.ZeroInt() amtFromBondedToNotBonded, amtFromNotBondedToBonded := sdk.ZeroInt(), sdk.ZeroInt() @@ -92,14 +91,13 @@ func (k Keeper) ApplyAndReturnValidatorSetUpdates(ctx sdk.Context) (updates []ab last := k.getLastValidatorsByAddr(ctx) // Iterate over validators, highest power to lowest. - iterator := sdk.KVStoreReversePrefixIterator(store, types.ValidatorsByPowerIndexKey) + iterator := k.ValidatorsPowerStoreIterator(ctx) defer iterator.Close() for count := 0; iterator.Valid() && count < int(maxValidators); iterator.Next() { // everything that is iterated in this loop is becoming or already a // part of the bonded validator set - // fetch the validator valAddr := sdk.ValAddress(iterator.Value()) validator := k.mustGetValidator(ctx, valAddr) @@ -132,43 +130,28 @@ func (k Keeper) ApplyAndReturnValidatorSetUpdates(ctx sdk.Context) (updates []ab copy(valAddrBytes[:], valAddr[:]) oldPowerBytes, found := last[valAddrBytes] - // calculate the new power bytes newPower := validator.ConsensusPower() newPowerBytes := k.cdc.MustMarshalBinaryLengthPrefixed(newPower) // update the validator set if power has changed if !found || !bytes.Equal(oldPowerBytes, newPowerBytes) { updates = append(updates, validator.ABCIValidatorUpdate()) - - // set validator power on lookup index k.SetLastValidatorPower(ctx, valAddr, newPower) } - // validator still in the validator set, so delete from the copy delete(last, valAddrBytes) - // keep count count++ totalPower = totalPower.Add(sdk.NewInt(newPower)) } - // sort the no-longer-bonded validators noLongerBonded := sortNoLongerBonded(last) - - // iterate through the sorted no-longer-bonded validators for _, valAddrBytes := range noLongerBonded { - // fetch the validator validator := k.mustGetValidator(ctx, sdk.ValAddress(valAddrBytes)) - - // bonded to unbonding validator = k.bondedToUnbonding(ctx, validator) amtFromBondedToNotBonded = amtFromBondedToNotBonded.Add(validator.GetTokens()) - - // delete from the bonded validator index k.DeleteLastValidatorPower(ctx, validator.GetOperator()) - - // update the validator set updates = append(updates, validator.ABCIValidatorUpdateZero()) } @@ -255,7 +238,6 @@ func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types. // delete the validator by power index, as the key will change k.DeleteValidatorByPowerIndex(ctx, validator) - // set the status validator = validator.UpdateStatus(sdk.Bonded) // save the now bonded validator record to the two referenced stores @@ -284,7 +266,6 @@ func (k Keeper) beginUnbondingValidator(ctx sdk.Context, validator types.Validat panic(fmt.Sprintf("should not already be unbonded or unbonding, validator: %v\n", validator)) } - // set the status validator = validator.UpdateStatus(sdk.Unbonding) // set the unbonding completion time and completion height appropriately @@ -317,15 +298,13 @@ type validatorsByAddr map[[sdk.AddrLen]byte][]byte // get the last validator set func (k Keeper) getLastValidatorsByAddr(ctx sdk.Context) validatorsByAddr { last := make(validatorsByAddr) - store := ctx.KVStore(k.storeKey) - iterator := sdk.KVStorePrefixIterator(store, types.LastValidatorPowerKey) + iterator := k.LastValidatorsIterator(ctx) defer iterator.Close() - // iterate over the last validator set index + for ; iterator.Valid(); iterator.Next() { var valAddr [sdk.AddrLen]byte // extract the validator address from the key (prefix is 1-byte) copy(valAddr[:], iterator.Key()[1:]) - // power bytes is just the value powerBytes := iterator.Value() last[valAddr] = make([]byte, len(powerBytes)) copy(last[valAddr], powerBytes) From bf41deac62244e2001314fc4a45d267d68864197 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Fri, 10 Jan 2020 15:08:14 -0500 Subject: [PATCH 069/529] Merge Pr #5506: Refactor use of parameters in x/distribution to match module spec --- CHANGELOG.md | 6 + x/distribution/alias.go | 71 +++---- x/distribution/client/cli/query.go | 10 +- x/distribution/client/common/common.go | 32 --- x/distribution/client/common/pretty_params.go | 34 --- x/distribution/client/rest/query.go | 6 +- x/distribution/genesis.go | 20 +- x/distribution/keeper/keeper.go | 7 +- x/distribution/keeper/keeper_test.go | 7 +- x/distribution/keeper/key.go | 193 ------------------ x/distribution/keeper/params.go | 128 ++---------- x/distribution/keeper/querier.go | 36 +--- x/distribution/keeper/querier_test.go | 68 ++---- x/distribution/keeper/store.go | 94 ++++----- x/distribution/keeper/test_common.go | 11 +- x/distribution/legacy/v0_38/migrate.go | 27 +++ x/distribution/legacy/v0_38/types.go | 50 +++++ x/distribution/simulation/decoder.go | 19 +- x/distribution/simulation/decoder_test.go | 4 +- x/distribution/simulation/genesis.go | 12 +- x/distribution/types/genesis.go | 50 ++--- x/distribution/types/keys.go | 178 ++++++++++++++++ x/distribution/types/params.go | 143 +++++++++++++ x/distribution/types/querier.go | 5 - x/evidence/internal/types/params.go | 9 +- 25 files changed, 605 insertions(+), 615 deletions(-) delete mode 100644 x/distribution/client/common/pretty_params.go delete mode 100644 x/distribution/keeper/key.go create mode 100644 x/distribution/legacy/v0_38/migrate.go create mode 100644 x/distribution/legacy/v0_38/types.go create mode 100644 x/distribution/types/params.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 63226c53c871..44932a03c28a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,8 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### State Machine Breaking +* (genesis) [\#5506](https://github.com/cosmos/cosmos-sdk/pull/5506) The `x/distribution` genesis state + now includes `params` instead of individual parameters. * (genesis) [\#5017](https://github.com/cosmos/cosmos-sdk/pull/5017) The `x/genaccounts` module has been deprecated and all components removed except the `legacy/` package. This requires changes to the genesis state. Namely, `accounts` now exist under `app_state.auth.accounts`. The corresponding migration @@ -50,6 +52,8 @@ logic has been implemented for v0.38 target version. Applications can migrate vi ### API Breaking Changes +* (modules) [\#5506](https://github.com/cosmos/cosmos-sdk/pull/5506) Remove individual setters of `x/distribution` parameters. + Instead, follow the module spec in getting parameters, setting new value(s) and finally calling `SetParams`. * (types) [\#5495](https://github.com/cosmos/cosmos-sdk/pull/5495) Remove redundant `(Must)Bech32ify*` and `(Must)Get*KeyBech32` functions in favor of `(Must)Bech32ifyPubKey` and `(Must)GetPubKeyFromBech32` respectively, both of which take a `Bech32PubKeyType` (string). @@ -245,6 +249,8 @@ to detail this new feature and how state transitions occur. * (docs/interfaces/) Add documentation on building interfaces for the Cosmos SDK. * Redesigned user interface that features new dynamically generated sidebar, build-time code embedding from GitHub, new homepage as well as many other improvements. * (types) [\#5428](https://github.com/cosmos/cosmos-sdk/pull/5428) Add `Mod` (modulo) method and `RelativePow` (exponentation) function for `Uint`. +* (modules) [\#5506](https://github.com/cosmos/cosmos-sdk/pull/5506) Remove redundancy in `x/distribution`s use of parameters. There + now exists a single `Params` type with a getter and setter along with a getter for each individual parameter. ### Bug Fixes diff --git a/x/distribution/alias.go b/x/distribution/alias.go index ff181d7331e3..47143d995cbb 100644 --- a/x/distribution/alias.go +++ b/x/distribution/alias.go @@ -9,7 +9,6 @@ import ( // nolint const ( - DefaultParamspace = keeper.DefaultParamspace ModuleName = types.ModuleName StoreKey = types.StoreKey RouterKey = types.RouterKey @@ -24,10 +23,7 @@ const ( QueryDelegatorValidators = types.QueryDelegatorValidators QueryWithdrawAddr = types.QueryWithdrawAddr QueryCommunityPool = types.QueryCommunityPool - ParamCommunityTax = types.ParamCommunityTax - ParamBaseProposerReward = types.ParamBaseProposerReward - ParamBonusProposerReward = types.ParamBonusProposerReward - ParamWithdrawAddrEnabled = types.ParamWithdrawAddrEnabled + DefaultParamspace = types.DefaultParamspace TypeMsgFundCommunityPool = types.TypeMsgFundCommunityPool ) @@ -40,29 +36,30 @@ var ( ReferenceCountInvariant = keeper.ReferenceCountInvariant ModuleAccountInvariant = keeper.ModuleAccountInvariant NewKeeper = keeper.NewKeeper - GetValidatorOutstandingRewardsAddress = keeper.GetValidatorOutstandingRewardsAddress - GetDelegatorWithdrawInfoAddress = keeper.GetDelegatorWithdrawInfoAddress - GetDelegatorStartingInfoAddresses = keeper.GetDelegatorStartingInfoAddresses - GetValidatorHistoricalRewardsAddressPeriod = keeper.GetValidatorHistoricalRewardsAddressPeriod - GetValidatorCurrentRewardsAddress = keeper.GetValidatorCurrentRewardsAddress - GetValidatorAccumulatedCommissionAddress = keeper.GetValidatorAccumulatedCommissionAddress - GetValidatorSlashEventAddressHeight = keeper.GetValidatorSlashEventAddressHeight - GetValidatorOutstandingRewardsKey = keeper.GetValidatorOutstandingRewardsKey - GetDelegatorWithdrawAddrKey = keeper.GetDelegatorWithdrawAddrKey - GetDelegatorStartingInfoKey = keeper.GetDelegatorStartingInfoKey - GetValidatorHistoricalRewardsPrefix = keeper.GetValidatorHistoricalRewardsPrefix - GetValidatorHistoricalRewardsKey = keeper.GetValidatorHistoricalRewardsKey - GetValidatorCurrentRewardsKey = keeper.GetValidatorCurrentRewardsKey - GetValidatorAccumulatedCommissionKey = keeper.GetValidatorAccumulatedCommissionKey - GetValidatorSlashEventPrefix = keeper.GetValidatorSlashEventPrefix - GetValidatorSlashEventKeyPrefix = keeper.GetValidatorSlashEventKeyPrefix - GetValidatorSlashEventKey = keeper.GetValidatorSlashEventKey - ParamKeyTable = keeper.ParamKeyTable + GetValidatorOutstandingRewardsAddress = types.GetValidatorOutstandingRewardsAddress + GetDelegatorWithdrawInfoAddress = types.GetDelegatorWithdrawInfoAddress + GetDelegatorStartingInfoAddresses = types.GetDelegatorStartingInfoAddresses + GetValidatorHistoricalRewardsAddressPeriod = types.GetValidatorHistoricalRewardsAddressPeriod + GetValidatorCurrentRewardsAddress = types.GetValidatorCurrentRewardsAddress + GetValidatorAccumulatedCommissionAddress = types.GetValidatorAccumulatedCommissionAddress + GetValidatorSlashEventAddressHeight = types.GetValidatorSlashEventAddressHeight + GetValidatorOutstandingRewardsKey = types.GetValidatorOutstandingRewardsKey + GetDelegatorWithdrawAddrKey = types.GetDelegatorWithdrawAddrKey + GetDelegatorStartingInfoKey = types.GetDelegatorStartingInfoKey + GetValidatorHistoricalRewardsPrefix = types.GetValidatorHistoricalRewardsPrefix + GetValidatorHistoricalRewardsKey = types.GetValidatorHistoricalRewardsKey + GetValidatorCurrentRewardsKey = types.GetValidatorCurrentRewardsKey + GetValidatorAccumulatedCommissionKey = types.GetValidatorAccumulatedCommissionKey + GetValidatorSlashEventPrefix = types.GetValidatorSlashEventPrefix + GetValidatorSlashEventKeyPrefix = types.GetValidatorSlashEventKeyPrefix + GetValidatorSlashEventKey = types.GetValidatorSlashEventKey HandleCommunityPoolSpendProposal = keeper.HandleCommunityPoolSpendProposal NewQuerier = keeper.NewQuerier MakeTestCodec = keeper.MakeTestCodec CreateTestInputDefault = keeper.CreateTestInputDefault CreateTestInputAdvanced = keeper.CreateTestInputAdvanced + ParamKeyTable = types.ParamKeyTable + DefaultParams = types.DefaultParams RegisterCodec = types.RegisterCodec NewDelegatorStartingInfo = types.NewDelegatorStartingInfo ErrEmptyDelegatorAddr = types.ErrEmptyDelegatorAddr @@ -100,20 +97,19 @@ var ( NewValidatorSlashEvent = types.NewValidatorSlashEvent // variable aliases - FeePoolKey = keeper.FeePoolKey - ProposerKey = keeper.ProposerKey - ValidatorOutstandingRewardsPrefix = keeper.ValidatorOutstandingRewardsPrefix - DelegatorWithdrawAddrPrefix = keeper.DelegatorWithdrawAddrPrefix - DelegatorStartingInfoPrefix = keeper.DelegatorStartingInfoPrefix - ValidatorHistoricalRewardsPrefix = keeper.ValidatorHistoricalRewardsPrefix - ValidatorCurrentRewardsPrefix = keeper.ValidatorCurrentRewardsPrefix - ValidatorAccumulatedCommissionPrefix = keeper.ValidatorAccumulatedCommissionPrefix - ValidatorSlashEventPrefix = keeper.ValidatorSlashEventPrefix - ParamStoreKeyCommunityTax = keeper.ParamStoreKeyCommunityTax - ParamStoreKeyBaseProposerReward = keeper.ParamStoreKeyBaseProposerReward - ParamStoreKeyBonusProposerReward = keeper.ParamStoreKeyBonusProposerReward - ParamStoreKeyWithdrawAddrEnabled = keeper.ParamStoreKeyWithdrawAddrEnabled - TestAddrs = keeper.TestAddrs + FeePoolKey = types.FeePoolKey + ProposerKey = types.ProposerKey + ValidatorOutstandingRewardsPrefix = types.ValidatorOutstandingRewardsPrefix + DelegatorWithdrawAddrPrefix = types.DelegatorWithdrawAddrPrefix + DelegatorStartingInfoPrefix = types.DelegatorStartingInfoPrefix + ValidatorHistoricalRewardsPrefix = types.ValidatorHistoricalRewardsPrefix + ValidatorCurrentRewardsPrefix = types.ValidatorCurrentRewardsPrefix + ValidatorAccumulatedCommissionPrefix = types.ValidatorAccumulatedCommissionPrefix + ValidatorSlashEventPrefix = types.ValidatorSlashEventPrefix + ParamStoreKeyCommunityTax = types.ParamStoreKeyCommunityTax + ParamStoreKeyBaseProposerReward = types.ParamStoreKeyBaseProposerReward + ParamStoreKeyBonusProposerReward = types.ParamStoreKeyBonusProposerReward + ParamStoreKeyWithdrawAddrEnabled = types.ParamStoreKeyWithdrawAddrEnabled ModuleCdc = types.ModuleCdc EventTypeSetWithdrawAddress = types.EventTypeSetWithdrawAddress EventTypeRewards = types.EventTypeRewards @@ -139,6 +135,7 @@ type ( ValidatorCurrentRewardsRecord = types.ValidatorCurrentRewardsRecord DelegatorStartingInfoRecord = types.DelegatorStartingInfoRecord ValidatorSlashEventRecord = types.ValidatorSlashEventRecord + Params = types.Params GenesisState = types.GenesisState MsgSetWithdrawAddress = types.MsgSetWithdrawAddress MsgWithdrawDelegatorReward = types.MsgWithdrawDelegatorReward diff --git a/x/distribution/client/cli/query.go b/x/distribution/client/cli/query.go index dff8e5e06a5d..06bc2e677328 100644 --- a/x/distribution/client/cli/query.go +++ b/x/distribution/client/cli/query.go @@ -47,10 +47,18 @@ func GetCmdQueryParams(queryRoute string, cdc *codec.Codec) *cobra.Command { Short: "Query distribution params", RunE: func(cmd *cobra.Command, args []string) error { cliCtx := context.NewCLIContext().WithCodec(cdc) - params, err := common.QueryParams(cliCtx, queryRoute) + + route := fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryParams) + res, _, err := cliCtx.QueryWithData(route, nil) if err != nil { return err } + + var params types.Params + if err := cdc.UnmarshalJSON(res, ¶ms); err != nil { + return fmt.Errorf("failed to unmarshal params: %w", err) + } + return cliCtx.PrintOutput(params) }, } diff --git a/x/distribution/client/common/common.go b/x/distribution/client/common/common.go index 44c08e8d5f64..b20e87ec0586 100644 --- a/x/distribution/client/common/common.go +++ b/x/distribution/client/common/common.go @@ -8,38 +8,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/distribution/types" ) -// QueryParams actually queries distribution params. -func QueryParams(cliCtx context.CLIContext, queryRoute string) (PrettyParams, error) { - route := fmt.Sprintf("custom/%s/params/%s", queryRoute, types.ParamCommunityTax) - - retCommunityTax, _, err := cliCtx.QueryWithData(route, []byte{}) - if err != nil { - return PrettyParams{}, err - } - - route = fmt.Sprintf("custom/%s/params/%s", queryRoute, types.ParamBaseProposerReward) - retBaseProposerReward, _, err := cliCtx.QueryWithData(route, []byte{}) - if err != nil { - return PrettyParams{}, err - } - - route = fmt.Sprintf("custom/%s/params/%s", queryRoute, types.ParamBonusProposerReward) - retBonusProposerReward, _, err := cliCtx.QueryWithData(route, []byte{}) - if err != nil { - return PrettyParams{}, err - } - - route = fmt.Sprintf("custom/%s/params/%s", queryRoute, types.ParamWithdrawAddrEnabled) - retWithdrawAddrEnabled, _, err := cliCtx.QueryWithData(route, []byte{}) - if err != nil { - return PrettyParams{}, err - } - - return NewPrettyParams( - retCommunityTax, retBaseProposerReward, retBonusProposerReward, retWithdrawAddrEnabled, - ), nil -} - // QueryDelegatorTotalRewards queries delegator total rewards. func QueryDelegatorTotalRewards(cliCtx context.CLIContext, queryRoute, delAddr string) ([]byte, error) { delegatorAddr, err := sdk.AccAddressFromBech32(delAddr) diff --git a/x/distribution/client/common/pretty_params.go b/x/distribution/client/common/pretty_params.go deleted file mode 100644 index cbe22869b7d8..000000000000 --- a/x/distribution/client/common/pretty_params.go +++ /dev/null @@ -1,34 +0,0 @@ -package common - -import ( - "encoding/json" - "fmt" -) - -// Convenience struct for CLI output -type PrettyParams struct { - CommunityTax json.RawMessage `json:"community_tax"` - BaseProposerReward json.RawMessage `json:"base_proposer_reward"` - BonusProposerReward json.RawMessage `json:"bonus_proposer_reward"` - WithdrawAddrEnabled json.RawMessage `json:"withdraw_addr_enabled"` -} - -// Construct a new PrettyParams -func NewPrettyParams(communityTax json.RawMessage, baseProposerReward json.RawMessage, bonusProposerReward json.RawMessage, withdrawAddrEnabled json.RawMessage) PrettyParams { - return PrettyParams{ - CommunityTax: communityTax, - BaseProposerReward: baseProposerReward, - BonusProposerReward: bonusProposerReward, - WithdrawAddrEnabled: withdrawAddrEnabled, - } -} - -func (pp PrettyParams) String() string { - return fmt.Sprintf(`Distribution Params: - Community Tax: %s - Base Proposer Reward: %s - Bonus Proposer Reward: %s - Withdraw Addr Enabled: %s`, pp.CommunityTax, - pp.BaseProposerReward, pp.BonusProposerReward, pp.WithdrawAddrEnabled) - -} diff --git a/x/distribution/client/rest/query.go b/x/distribution/client/rest/query.go index 15b5c7fe07c7..d242157dd40f 100644 --- a/x/distribution/client/rest/query.go +++ b/x/distribution/client/rest/query.go @@ -216,13 +216,15 @@ func paramsHandlerFn(cliCtx context.CLIContext, queryRoute string) http.HandlerF return } - params, err := common.QueryParams(cliCtx, queryRoute) + route := fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryParams) + res, height, err := cliCtx.QueryWithData(route, nil) if err != nil { rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return } - rest.PostProcessResponse(w, cliCtx, params) + cliCtx = cliCtx.WithHeight(height) + rest.PostProcessResponse(w, cliCtx, res) } } diff --git a/x/distribution/genesis.go b/x/distribution/genesis.go index c0fc05b9ea71..6a7f9c1fdbaf 100644 --- a/x/distribution/genesis.go +++ b/x/distribution/genesis.go @@ -12,10 +12,7 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, supplyKeeper types.SupplyKeeper var moduleHoldings sdk.DecCoins keeper.SetFeePool(ctx, data.FeePool) - keeper.SetCommunityTax(ctx, data.CommunityTax) - keeper.SetBaseProposerReward(ctx, data.BaseProposerReward) - keeper.SetBonusProposerReward(ctx, data.BonusProposerReward) - keeper.SetWithdrawAddrEnabled(ctx, data.WithdrawAddrEnabled) + keeper.SetParams(ctx, data.Params) for _, dwi := range data.DelegatorWithdrawInfos { keeper.SetDelegatorWithdrawAddr(ctx, dwi.DelegatorAddress, dwi.WithdrawAddress) @@ -61,10 +58,8 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, supplyKeeper types.SupplyKeeper // ExportGenesis returns a GenesisState for a given context and keeper. func ExportGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState { feePool := keeper.GetFeePool(ctx) - communityTax := keeper.GetCommunityTax(ctx) - baseProposerRewards := keeper.GetBaseProposerReward(ctx) - bonusProposerRewards := keeper.GetBonusProposerReward(ctx) - withdrawAddrEnabled := keeper.GetWithdrawAddrEnabled(ctx) + params := keeper.GetParams(ctx) + dwi := make([]types.DelegatorWithdrawInfo, 0) keeper.IterateDelegatorWithdrawAddrs(ctx, func(del sdk.AccAddress, addr sdk.AccAddress) (stop bool) { dwi = append(dwi, types.DelegatorWithdrawInfo{ @@ -73,6 +68,7 @@ func ExportGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState { }) return false }) + pp := keeper.GetPreviousProposerConsAddr(ctx) outstanding := make([]types.ValidatorOutstandingRewardsRecord, 0) keeper.IterateValidatorOutstandingRewards(ctx, @@ -84,6 +80,7 @@ func ExportGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState { return false }, ) + acc := make([]types.ValidatorAccumulatedCommissionRecord, 0) keeper.IterateValidatorAccumulatedCommissions(ctx, func(addr sdk.ValAddress, commission types.ValidatorAccumulatedCommission) (stop bool) { @@ -94,6 +91,7 @@ func ExportGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState { return false }, ) + his := make([]types.ValidatorHistoricalRewardsRecord, 0) keeper.IterateValidatorHistoricalRewards(ctx, func(val sdk.ValAddress, period uint64, rewards types.ValidatorHistoricalRewards) (stop bool) { @@ -105,6 +103,7 @@ func ExportGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState { return false }, ) + cur := make([]types.ValidatorCurrentRewardsRecord, 0) keeper.IterateValidatorCurrentRewards(ctx, func(val sdk.ValAddress, rewards types.ValidatorCurrentRewards) (stop bool) { @@ -126,6 +125,7 @@ func ExportGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState { return false }, ) + slashes := make([]types.ValidatorSlashEventRecord, 0) keeper.IterateValidatorSlashEvents(ctx, func(val sdk.ValAddress, height uint64, event types.ValidatorSlashEvent) (stop bool) { @@ -138,6 +138,6 @@ func ExportGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState { return false }, ) - return types.NewGenesisState(feePool, communityTax, baseProposerRewards, bonusProposerRewards, withdrawAddrEnabled, - dwi, pp, outstanding, acc, his, cur, dels, slashes) + + return types.NewGenesisState(params, feePool, dwi, pp, outstanding, acc, his, cur, dels, slashes) } diff --git a/x/distribution/keeper/keeper.go b/x/distribution/keeper/keeper.go index 1ce723d11418..18cbce2b6848 100644 --- a/x/distribution/keeper/keeper.go +++ b/x/distribution/keeper/keeper.go @@ -37,10 +37,15 @@ func NewKeeper( panic(fmt.Sprintf("%s module account has not been set", types.ModuleName)) } + // set KeyTable if it has not already been set + if !paramSpace.HasKeyTable() { + paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable()) + } + return Keeper{ storeKey: key, cdc: cdc, - paramSpace: paramSpace.WithKeyTable(ParamKeyTable()), + paramSpace: paramSpace, stakingKeeper: sk, supplyKeeper: supplyKeeper, feeCollectorName: feeCollectorName, diff --git a/x/distribution/keeper/keeper_test.go b/x/distribution/keeper/keeper_test.go index 2536104c3b6b..5b2d989f7f82 100644 --- a/x/distribution/keeper/keeper_test.go +++ b/x/distribution/keeper/keeper_test.go @@ -13,12 +13,15 @@ import ( func TestSetWithdrawAddr(t *testing.T) { ctx, _, keeper, _, _ := CreateTestInputDefault(t, false, 1000) - keeper.SetWithdrawAddrEnabled(ctx, false) + params := keeper.GetParams(ctx) + params.WithdrawAddrEnabled = false + keeper.SetParams(ctx, params) err := keeper.SetWithdrawAddr(ctx, delAddr1, delAddr2) require.NotNil(t, err) - keeper.SetWithdrawAddrEnabled(ctx, true) + params.WithdrawAddrEnabled = true + keeper.SetParams(ctx, params) err = keeper.SetWithdrawAddr(ctx, delAddr1, delAddr2) require.Nil(t, err) diff --git a/x/distribution/keeper/key.go b/x/distribution/keeper/key.go deleted file mode 100644 index 0b8dda21b157..000000000000 --- a/x/distribution/keeper/key.go +++ /dev/null @@ -1,193 +0,0 @@ -package keeper - -import ( - "encoding/binary" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/distribution/types" -) - -const ( - // default paramspace for params keeper - DefaultParamspace = types.ModuleName -) - -// Keys for distribution store -// Items are stored with the following key: values -// -// - 0x00: FeePol -// -// - 0x01: sdk.ConsAddress -// -// - 0x02: ValidatorOutstandingRewards -// -// - 0x03: sdk.AccAddress -// -// - 0x04: DelegatorStartingInfo -// -// - 0x05: ValidatorHistoricalRewards -// -// - 0x06: ValidatorCurrentRewards -// -// - 0x07: ValidatorCurrentRewards -// -// - 0x08: ValidatorSlashEvent -var ( - FeePoolKey = []byte{0x00} // key for global distribution state - ProposerKey = []byte{0x01} // key for the proposer operator address - ValidatorOutstandingRewardsPrefix = []byte{0x02} // key for outstanding rewards - - DelegatorWithdrawAddrPrefix = []byte{0x03} // key for delegator withdraw address - DelegatorStartingInfoPrefix = []byte{0x04} // key for delegator starting info - ValidatorHistoricalRewardsPrefix = []byte{0x05} // key for historical validators rewards / stake - ValidatorCurrentRewardsPrefix = []byte{0x06} // key for current validator rewards - ValidatorAccumulatedCommissionPrefix = []byte{0x07} // key for accumulated validator commission - ValidatorSlashEventPrefix = []byte{0x08} // key for validator slash fraction - - ParamStoreKeyCommunityTax = []byte("communitytax") - ParamStoreKeyBaseProposerReward = []byte("baseproposerreward") - ParamStoreKeyBonusProposerReward = []byte("bonusproposerreward") - ParamStoreKeyWithdrawAddrEnabled = []byte("withdrawaddrenabled") -) - -// gets an address from a validator's outstanding rewards key -func GetValidatorOutstandingRewardsAddress(key []byte) (valAddr sdk.ValAddress) { - addr := key[1:] - if len(addr) != sdk.AddrLen { - panic("unexpected key length") - } - return sdk.ValAddress(addr) -} - -// gets an address from a delegator's withdraw info key -func GetDelegatorWithdrawInfoAddress(key []byte) (delAddr sdk.AccAddress) { - addr := key[1:] - if len(addr) != sdk.AddrLen { - panic("unexpected key length") - } - return sdk.AccAddress(addr) -} - -// gets the addresses from a delegator starting info key -func GetDelegatorStartingInfoAddresses(key []byte) (valAddr sdk.ValAddress, delAddr sdk.AccAddress) { - addr := key[1 : 1+sdk.AddrLen] - if len(addr) != sdk.AddrLen { - panic("unexpected key length") - } - valAddr = sdk.ValAddress(addr) - addr = key[1+sdk.AddrLen:] - if len(addr) != sdk.AddrLen { - panic("unexpected key length") - } - delAddr = sdk.AccAddress(addr) - return -} - -// gets the address & period from a validator's historical rewards key -func GetValidatorHistoricalRewardsAddressPeriod(key []byte) (valAddr sdk.ValAddress, period uint64) { - addr := key[1 : 1+sdk.AddrLen] - if len(addr) != sdk.AddrLen { - panic("unexpected key length") - } - valAddr = sdk.ValAddress(addr) - b := key[1+sdk.AddrLen:] - if len(b) != 8 { - panic("unexpected key length") - } - period = binary.LittleEndian.Uint64(b) - return -} - -// gets the address from a validator's current rewards key -func GetValidatorCurrentRewardsAddress(key []byte) (valAddr sdk.ValAddress) { - addr := key[1:] - if len(addr) != sdk.AddrLen { - panic("unexpected key length") - } - return sdk.ValAddress(addr) -} - -// gets the address from a validator's accumulated commission key -func GetValidatorAccumulatedCommissionAddress(key []byte) (valAddr sdk.ValAddress) { - addr := key[1:] - if len(addr) != sdk.AddrLen { - panic("unexpected key length") - } - return sdk.ValAddress(addr) -} - -// gets the height from a validator's slash event key -func GetValidatorSlashEventAddressHeight(key []byte) (valAddr sdk.ValAddress, height uint64) { - addr := key[1 : 1+sdk.AddrLen] - if len(addr) != sdk.AddrLen { - panic("unexpected key length") - } - valAddr = sdk.ValAddress(addr) - startB := 1 + sdk.AddrLen - b := key[startB : startB+8] // the next 8 bytes represent the height - height = binary.BigEndian.Uint64(b) - return -} - -// gets the outstanding rewards key for a validator -func GetValidatorOutstandingRewardsKey(valAddr sdk.ValAddress) []byte { - return append(ValidatorOutstandingRewardsPrefix, valAddr.Bytes()...) -} - -// gets the key for a delegator's withdraw addr -func GetDelegatorWithdrawAddrKey(delAddr sdk.AccAddress) []byte { - return append(DelegatorWithdrawAddrPrefix, delAddr.Bytes()...) -} - -// gets the key for a delegator's starting info -func GetDelegatorStartingInfoKey(v sdk.ValAddress, d sdk.AccAddress) []byte { - return append(append(DelegatorStartingInfoPrefix, v.Bytes()...), d.Bytes()...) -} - -// gets the prefix key for a validator's historical rewards -func GetValidatorHistoricalRewardsPrefix(v sdk.ValAddress) []byte { - return append(ValidatorHistoricalRewardsPrefix, v.Bytes()...) -} - -// gets the key for a validator's historical rewards -func GetValidatorHistoricalRewardsKey(v sdk.ValAddress, k uint64) []byte { - b := make([]byte, 8) - binary.LittleEndian.PutUint64(b, k) - return append(append(ValidatorHistoricalRewardsPrefix, v.Bytes()...), b...) -} - -// gets the key for a validator's current rewards -func GetValidatorCurrentRewardsKey(v sdk.ValAddress) []byte { - return append(ValidatorCurrentRewardsPrefix, v.Bytes()...) -} - -// gets the key for a validator's current commission -func GetValidatorAccumulatedCommissionKey(v sdk.ValAddress) []byte { - return append(ValidatorAccumulatedCommissionPrefix, v.Bytes()...) -} - -// gets the prefix key for a validator's slash fractions -func GetValidatorSlashEventPrefix(v sdk.ValAddress) []byte { - return append(ValidatorSlashEventPrefix, v.Bytes()...) -} - -// gets the prefix key for a validator's slash fraction (ValidatorSlashEventPrefix + height) -func GetValidatorSlashEventKeyPrefix(v sdk.ValAddress, height uint64) []byte { - heightBz := make([]byte, 8) - binary.BigEndian.PutUint64(heightBz, height) - return append( - ValidatorSlashEventPrefix, - append( - v.Bytes(), - heightBz..., - )..., - ) -} - -// gets the key for a validator's slash fraction -func GetValidatorSlashEventKey(v sdk.ValAddress, height, period uint64) []byte { - periodBz := make([]byte, 8) - binary.BigEndian.PutUint64(periodBz, period) - prefix := GetValidatorSlashEventKeyPrefix(v, height) - return append(prefix, periodBz...) -} diff --git a/x/distribution/keeper/params.go b/x/distribution/keeper/params.go index 764dfdc21731..63d6ecedc8ba 100644 --- a/x/distribution/keeper/params.go +++ b/x/distribution/keeper/params.go @@ -1,127 +1,43 @@ package keeper import ( - "fmt" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/params" + "github.com/cosmos/cosmos-sdk/x/distribution/types" ) -// type declaration for parameters -func ParamKeyTable() params.KeyTable { - return params.NewKeyTable( - params.NewParamSetPair(ParamStoreKeyCommunityTax, sdk.Dec{}, validateCommunityTax), - params.NewParamSetPair(ParamStoreKeyBaseProposerReward, sdk.Dec{}, validateBaseProposerReward), - params.NewParamSetPair(ParamStoreKeyBonusProposerReward, sdk.Dec{}, validateBonusProposerReward), - params.NewParamSetPair(ParamStoreKeyWithdrawAddrEnabled, false, validateWithdrawAddrEnabled), - ) -} - -func validateCommunityTax(i interface{}) error { - v, ok := i.(sdk.Dec) - if !ok { - return fmt.Errorf("invalid parameter type: %T", i) - } - - if v.IsNegative() { - return fmt.Errorf("community tax must be positive: %s", v) - } - if v.GT(sdk.OneDec()) { - return fmt.Errorf("community tax too large: %s", v) - } - - return nil -} - -func validateBaseProposerReward(i interface{}) error { - v, ok := i.(sdk.Dec) - if !ok { - return fmt.Errorf("invalid parameter type: %T", i) - } - - if v.IsNegative() { - return fmt.Errorf("base proposer reward must be positive: %s", v) - } - if v.GT(sdk.OneDec()) { - return fmt.Errorf("base proposer reward too large: %s", v) - } - - return nil -} - -func validateBonusProposerReward(i interface{}) error { - v, ok := i.(sdk.Dec) - if !ok { - return fmt.Errorf("invalid parameter type: %T", i) - } - - if v.IsNegative() { - return fmt.Errorf("bonus proposer reward must be positive: %s", v) - } - if v.GT(sdk.OneDec()) { - return fmt.Errorf("bonus proposer reward too large: %s", v) - } - - return nil +// GetParams returns the total set of distribution parameters. +func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) { + k.paramSpace.GetParamSet(ctx, ¶ms) + return params } -func validateWithdrawAddrEnabled(i interface{}) error { - _, ok := i.(bool) - if !ok { - return fmt.Errorf("invalid parameter type: %T", i) - } - - return nil +// SetParams sets the distribution parameters to the param space. +func (k Keeper) SetParams(ctx sdk.Context, params types.Params) { + k.paramSpace.SetParamSet(ctx, ¶ms) } -// returns the current CommunityTax rate from the global param store -// nolint: errcheck -func (k Keeper) GetCommunityTax(ctx sdk.Context) sdk.Dec { - var percent sdk.Dec - k.paramSpace.Get(ctx, ParamStoreKeyCommunityTax, &percent) +// GetCommunityTax returns the current distribution community tax. +func (k Keeper) GetCommunityTax(ctx sdk.Context) (percent sdk.Dec) { + k.paramSpace.Get(ctx, types.ParamStoreKeyCommunityTax, &percent) return percent } -// nolint: errcheck -func (k Keeper) SetCommunityTax(ctx sdk.Context, percent sdk.Dec) { - k.paramSpace.Set(ctx, ParamStoreKeyCommunityTax, &percent) -} - -// returns the current BaseProposerReward rate from the global param store -// nolint: errcheck -func (k Keeper) GetBaseProposerReward(ctx sdk.Context) sdk.Dec { - var percent sdk.Dec - k.paramSpace.Get(ctx, ParamStoreKeyBaseProposerReward, &percent) +// GetBaseProposerReward returns the current distribution base proposer rate. +func (k Keeper) GetBaseProposerReward(ctx sdk.Context) (percent sdk.Dec) { + k.paramSpace.Get(ctx, types.ParamStoreKeyBaseProposerReward, &percent) return percent } -// nolint: errcheck -func (k Keeper) SetBaseProposerReward(ctx sdk.Context, percent sdk.Dec) { - k.paramSpace.Set(ctx, ParamStoreKeyBaseProposerReward, &percent) -} - -// returns the current BaseProposerReward rate from the global param store -// nolint: errcheck -func (k Keeper) GetBonusProposerReward(ctx sdk.Context) sdk.Dec { - var percent sdk.Dec - k.paramSpace.Get(ctx, ParamStoreKeyBonusProposerReward, &percent) +// GetBonusProposerReward returns the current distribution bonus proposer reward +// rate. +func (k Keeper) GetBonusProposerReward(ctx sdk.Context) (percent sdk.Dec) { + k.paramSpace.Get(ctx, types.ParamStoreKeyBonusProposerReward, &percent) return percent } -// nolint: errcheck -func (k Keeper) SetBonusProposerReward(ctx sdk.Context, percent sdk.Dec) { - k.paramSpace.Set(ctx, ParamStoreKeyBonusProposerReward, &percent) -} - -// returns the current WithdrawAddrEnabled -// nolint: errcheck -func (k Keeper) GetWithdrawAddrEnabled(ctx sdk.Context) bool { - var enabled bool - k.paramSpace.Get(ctx, ParamStoreKeyWithdrawAddrEnabled, &enabled) +// GetWithdrawAddrEnabled returns the current distribution withdraw address +// enabled parameter. +func (k Keeper) GetWithdrawAddrEnabled(ctx sdk.Context) (enabled bool) { + k.paramSpace.Get(ctx, types.ParamStoreKeyWithdrawAddrEnabled, &enabled) return enabled } - -// nolint: errcheck -func (k Keeper) SetWithdrawAddrEnabled(ctx sdk.Context, enabled bool) { - k.paramSpace.Set(ctx, ParamStoreKeyWithdrawAddrEnabled, &enabled) -} diff --git a/x/distribution/keeper/querier.go b/x/distribution/keeper/querier.go index 641f59c29123..4757ea5ffe3e 100644 --- a/x/distribution/keeper/querier.go +++ b/x/distribution/keeper/querier.go @@ -49,38 +49,14 @@ func NewQuerier(k Keeper) sdk.Querier { } func queryParams(ctx sdk.Context, path []string, req abci.RequestQuery, k Keeper) ([]byte, error) { - switch path[0] { - case types.ParamCommunityTax: - bz, err := codec.MarshalJSONIndent(k.cdc, k.GetCommunityTax(ctx)) - if err != nil { - return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) - } - return bz, nil - - case types.ParamBaseProposerReward: - bz, err := codec.MarshalJSONIndent(k.cdc, k.GetBaseProposerReward(ctx)) - if err != nil { - return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) - } - return bz, nil - - case types.ParamBonusProposerReward: - bz, err := codec.MarshalJSONIndent(k.cdc, k.GetBonusProposerReward(ctx)) - if err != nil { - return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) - } - return bz, nil + params := k.GetParams(ctx) - case types.ParamWithdrawAddrEnabled: - bz, err := codec.MarshalJSONIndent(k.cdc, k.GetWithdrawAddrEnabled(ctx)) - if err != nil { - return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) - } - return bz, nil - - default: - return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "%s is not a valid query request path", req.Path) + res, err := codec.MarshalJSONIndent(k.cdc, params) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } + + return res, nil } func queryValidatorOutstandingRewards(ctx sdk.Context, path []string, req abci.RequestQuery, k Keeper) ([]byte, error) { diff --git a/x/distribution/keeper/querier_test.go b/x/distribution/keeper/querier_test.go index e70ca2ea0f4b..b5efd15a3a62 100644 --- a/x/distribution/keeper/querier_test.go +++ b/x/distribution/keeper/querier_test.go @@ -17,45 +17,14 @@ import ( const custom = "custom" -func getQueriedParams(t *testing.T, ctx sdk.Context, cdc *codec.Codec, querier sdk.Querier) (communityTax sdk.Dec, baseProposerReward sdk.Dec, bonusProposerReward sdk.Dec, withdrawAddrEnabled bool) { +func getQueriedParams(t *testing.T, ctx sdk.Context, cdc *codec.Codec, querier sdk.Querier) types.Params { + var params types.Params - query := abci.RequestQuery{ - Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryParams, types.ParamCommunityTax}, "/"), - Data: []byte{}, - } - - bz, err := querier(ctx, []string{types.QueryParams, types.ParamCommunityTax}, query) - require.Nil(t, err) - require.Nil(t, cdc.UnmarshalJSON(bz, &communityTax)) - - query = abci.RequestQuery{ - Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryParams, types.ParamBaseProposerReward}, "/"), - Data: []byte{}, - } - - bz, err = querier(ctx, []string{types.QueryParams, types.ParamBaseProposerReward}, query) - require.Nil(t, err) - require.Nil(t, cdc.UnmarshalJSON(bz, &baseProposerReward)) - - query = abci.RequestQuery{ - Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryParams, types.ParamBonusProposerReward}, "/"), - Data: []byte{}, - } - - bz, err = querier(ctx, []string{types.QueryParams, types.ParamBonusProposerReward}, query) + bz, err := querier(ctx, []string{types.QueryParams}, abci.RequestQuery{}) require.Nil(t, err) - require.Nil(t, cdc.UnmarshalJSON(bz, &bonusProposerReward)) - - query = abci.RequestQuery{ - Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryParams, types.ParamWithdrawAddrEnabled}, "/"), - Data: []byte{}, - } + require.Nil(t, cdc.UnmarshalJSON(bz, ¶ms)) - bz, err = querier(ctx, []string{types.QueryParams, types.ParamWithdrawAddrEnabled}, query) - require.Nil(t, err) - require.Nil(t, cdc.UnmarshalJSON(bz, &withdrawAddrEnabled)) - - return communityTax, baseProposerReward, bonusProposerReward, withdrawAddrEnabled + return params } func getQueriedValidatorOutstandingRewards(t *testing.T, ctx sdk.Context, cdc *codec.Codec, querier sdk.Querier, validatorAddr sdk.ValAddress) (outstandingRewards sdk.DecCoins) { @@ -144,19 +113,20 @@ func TestQueries(t *testing.T) { querier := NewQuerier(keeper) // test param queries - communityTax := sdk.NewDecWithPrec(3, 1) - baseProposerReward := sdk.NewDecWithPrec(2, 1) - bonusProposerReward := sdk.NewDecWithPrec(1, 1) - withdrawAddrEnabled := true - keeper.SetCommunityTax(ctx, communityTax) - keeper.SetBaseProposerReward(ctx, baseProposerReward) - keeper.SetBonusProposerReward(ctx, bonusProposerReward) - keeper.SetWithdrawAddrEnabled(ctx, withdrawAddrEnabled) - retCommunityTax, retBaseProposerReward, retBonusProposerReward, retWithdrawAddrEnabled := getQueriedParams(t, ctx, cdc, querier) - require.Equal(t, communityTax, retCommunityTax) - require.Equal(t, baseProposerReward, retBaseProposerReward) - require.Equal(t, bonusProposerReward, retBonusProposerReward) - require.Equal(t, withdrawAddrEnabled, retWithdrawAddrEnabled) + params := types.Params{ + CommunityTax: sdk.NewDecWithPrec(3, 1), + BaseProposerReward: sdk.NewDecWithPrec(2, 1), + BonusProposerReward: sdk.NewDecWithPrec(1, 1), + WithdrawAddrEnabled: true, + } + + keeper.SetParams(ctx, params) + + paramsRes := getQueriedParams(t, ctx, cdc, querier) + require.Equal(t, params.CommunityTax, paramsRes.CommunityTax) + require.Equal(t, params.BaseProposerReward, paramsRes.BaseProposerReward) + require.Equal(t, params.BonusProposerReward, paramsRes.BonusProposerReward) + require.Equal(t, params.WithdrawAddrEnabled, paramsRes.WithdrawAddrEnabled) // test outstanding rewards query outstandingRewards := sdk.DecCoins{{Denom: "mytoken", Amount: sdk.NewDec(3)}, {Denom: "myothertoken", Amount: sdk.NewDecWithPrec(3, 7)}} diff --git a/x/distribution/keeper/store.go b/x/distribution/keeper/store.go index 6bb766ee34b1..e1a1c50d4343 100644 --- a/x/distribution/keeper/store.go +++ b/x/distribution/keeper/store.go @@ -8,7 +8,7 @@ import ( // get the delegator withdraw address, defaulting to the delegator address func (k Keeper) GetDelegatorWithdrawAddr(ctx sdk.Context, delAddr sdk.AccAddress) sdk.AccAddress { store := ctx.KVStore(k.storeKey) - b := store.Get(GetDelegatorWithdrawAddrKey(delAddr)) + b := store.Get(types.GetDelegatorWithdrawAddrKey(delAddr)) if b == nil { return delAddr } @@ -18,23 +18,23 @@ func (k Keeper) GetDelegatorWithdrawAddr(ctx sdk.Context, delAddr sdk.AccAddress // set the delegator withdraw address func (k Keeper) SetDelegatorWithdrawAddr(ctx sdk.Context, delAddr, withdrawAddr sdk.AccAddress) { store := ctx.KVStore(k.storeKey) - store.Set(GetDelegatorWithdrawAddrKey(delAddr), withdrawAddr.Bytes()) + store.Set(types.GetDelegatorWithdrawAddrKey(delAddr), withdrawAddr.Bytes()) } // delete a delegator withdraw addr func (k Keeper) DeleteDelegatorWithdrawAddr(ctx sdk.Context, delAddr, withdrawAddr sdk.AccAddress) { store := ctx.KVStore(k.storeKey) - store.Delete(GetDelegatorWithdrawAddrKey(delAddr)) + store.Delete(types.GetDelegatorWithdrawAddrKey(delAddr)) } // iterate over delegator withdraw addrs func (k Keeper) IterateDelegatorWithdrawAddrs(ctx sdk.Context, handler func(del sdk.AccAddress, addr sdk.AccAddress) (stop bool)) { store := ctx.KVStore(k.storeKey) - iter := sdk.KVStorePrefixIterator(store, DelegatorWithdrawAddrPrefix) + iter := sdk.KVStorePrefixIterator(store, types.DelegatorWithdrawAddrPrefix) defer iter.Close() for ; iter.Valid(); iter.Next() { addr := sdk.AccAddress(iter.Value()) - del := GetDelegatorWithdrawInfoAddress(iter.Key()) + del := types.GetDelegatorWithdrawInfoAddress(iter.Key()) if handler(del, addr) { break } @@ -44,7 +44,7 @@ func (k Keeper) IterateDelegatorWithdrawAddrs(ctx sdk.Context, handler func(del // get the global fee pool distribution info func (k Keeper) GetFeePool(ctx sdk.Context) (feePool types.FeePool) { store := ctx.KVStore(k.storeKey) - b := store.Get(FeePoolKey) + b := store.Get(types.FeePoolKey) if b == nil { panic("Stored fee pool should not have been nil") } @@ -56,13 +56,13 @@ func (k Keeper) GetFeePool(ctx sdk.Context) (feePool types.FeePool) { func (k Keeper) SetFeePool(ctx sdk.Context, feePool types.FeePool) { store := ctx.KVStore(k.storeKey) b := k.cdc.MustMarshalBinaryLengthPrefixed(feePool) - store.Set(FeePoolKey, b) + store.Set(types.FeePoolKey, b) } // get the proposer public key for this block func (k Keeper) GetPreviousProposerConsAddr(ctx sdk.Context) (consAddr sdk.ConsAddress) { store := ctx.KVStore(k.storeKey) - b := store.Get(ProposerKey) + b := store.Get(types.ProposerKey) if b == nil { panic("Previous proposer not set") } @@ -74,13 +74,13 @@ func (k Keeper) GetPreviousProposerConsAddr(ctx sdk.Context) (consAddr sdk.ConsA func (k Keeper) SetPreviousProposerConsAddr(ctx sdk.Context, consAddr sdk.ConsAddress) { store := ctx.KVStore(k.storeKey) b := k.cdc.MustMarshalBinaryLengthPrefixed(consAddr) - store.Set(ProposerKey, b) + store.Set(types.ProposerKey, b) } // get the starting info associated with a delegator func (k Keeper) GetDelegatorStartingInfo(ctx sdk.Context, val sdk.ValAddress, del sdk.AccAddress) (period types.DelegatorStartingInfo) { store := ctx.KVStore(k.storeKey) - b := store.Get(GetDelegatorStartingInfoKey(val, del)) + b := store.Get(types.GetDelegatorStartingInfoKey(val, del)) k.cdc.MustUnmarshalBinaryLengthPrefixed(b, &period) return } @@ -89,30 +89,30 @@ func (k Keeper) GetDelegatorStartingInfo(ctx sdk.Context, val sdk.ValAddress, de func (k Keeper) SetDelegatorStartingInfo(ctx sdk.Context, val sdk.ValAddress, del sdk.AccAddress, period types.DelegatorStartingInfo) { store := ctx.KVStore(k.storeKey) b := k.cdc.MustMarshalBinaryLengthPrefixed(period) - store.Set(GetDelegatorStartingInfoKey(val, del), b) + store.Set(types.GetDelegatorStartingInfoKey(val, del), b) } // check existence of the starting info associated with a delegator func (k Keeper) HasDelegatorStartingInfo(ctx sdk.Context, val sdk.ValAddress, del sdk.AccAddress) bool { store := ctx.KVStore(k.storeKey) - return store.Has(GetDelegatorStartingInfoKey(val, del)) + return store.Has(types.GetDelegatorStartingInfoKey(val, del)) } // delete the starting info associated with a delegator func (k Keeper) DeleteDelegatorStartingInfo(ctx sdk.Context, val sdk.ValAddress, del sdk.AccAddress) { store := ctx.KVStore(k.storeKey) - store.Delete(GetDelegatorStartingInfoKey(val, del)) + store.Delete(types.GetDelegatorStartingInfoKey(val, del)) } // iterate over delegator starting infos func (k Keeper) IterateDelegatorStartingInfos(ctx sdk.Context, handler func(val sdk.ValAddress, del sdk.AccAddress, info types.DelegatorStartingInfo) (stop bool)) { store := ctx.KVStore(k.storeKey) - iter := sdk.KVStorePrefixIterator(store, DelegatorStartingInfoPrefix) + iter := sdk.KVStorePrefixIterator(store, types.DelegatorStartingInfoPrefix) defer iter.Close() for ; iter.Valid(); iter.Next() { var info types.DelegatorStartingInfo k.cdc.MustUnmarshalBinaryLengthPrefixed(iter.Value(), &info) - val, del := GetDelegatorStartingInfoAddresses(iter.Key()) + val, del := types.GetDelegatorStartingInfoAddresses(iter.Key()) if handler(val, del, info) { break } @@ -122,7 +122,7 @@ func (k Keeper) IterateDelegatorStartingInfos(ctx sdk.Context, handler func(val // get historical rewards for a particular period func (k Keeper) GetValidatorHistoricalRewards(ctx sdk.Context, val sdk.ValAddress, period uint64) (rewards types.ValidatorHistoricalRewards) { store := ctx.KVStore(k.storeKey) - b := store.Get(GetValidatorHistoricalRewardsKey(val, period)) + b := store.Get(types.GetValidatorHistoricalRewardsKey(val, period)) k.cdc.MustUnmarshalBinaryLengthPrefixed(b, &rewards) return } @@ -131,18 +131,18 @@ func (k Keeper) GetValidatorHistoricalRewards(ctx sdk.Context, val sdk.ValAddres func (k Keeper) SetValidatorHistoricalRewards(ctx sdk.Context, val sdk.ValAddress, period uint64, rewards types.ValidatorHistoricalRewards) { store := ctx.KVStore(k.storeKey) b := k.cdc.MustMarshalBinaryLengthPrefixed(rewards) - store.Set(GetValidatorHistoricalRewardsKey(val, period), b) + store.Set(types.GetValidatorHistoricalRewardsKey(val, period), b) } // iterate over historical rewards func (k Keeper) IterateValidatorHistoricalRewards(ctx sdk.Context, handler func(val sdk.ValAddress, period uint64, rewards types.ValidatorHistoricalRewards) (stop bool)) { store := ctx.KVStore(k.storeKey) - iter := sdk.KVStorePrefixIterator(store, ValidatorHistoricalRewardsPrefix) + iter := sdk.KVStorePrefixIterator(store, types.ValidatorHistoricalRewardsPrefix) defer iter.Close() for ; iter.Valid(); iter.Next() { var rewards types.ValidatorHistoricalRewards k.cdc.MustUnmarshalBinaryLengthPrefixed(iter.Value(), &rewards) - addr, period := GetValidatorHistoricalRewardsAddressPeriod(iter.Key()) + addr, period := types.GetValidatorHistoricalRewardsAddressPeriod(iter.Key()) if handler(addr, period, rewards) { break } @@ -152,13 +152,13 @@ func (k Keeper) IterateValidatorHistoricalRewards(ctx sdk.Context, handler func( // delete a historical reward func (k Keeper) DeleteValidatorHistoricalReward(ctx sdk.Context, val sdk.ValAddress, period uint64) { store := ctx.KVStore(k.storeKey) - store.Delete(GetValidatorHistoricalRewardsKey(val, period)) + store.Delete(types.GetValidatorHistoricalRewardsKey(val, period)) } // delete historical rewards for a validator func (k Keeper) DeleteValidatorHistoricalRewards(ctx sdk.Context, val sdk.ValAddress) { store := ctx.KVStore(k.storeKey) - iter := sdk.KVStorePrefixIterator(store, GetValidatorHistoricalRewardsPrefix(val)) + iter := sdk.KVStorePrefixIterator(store, types.GetValidatorHistoricalRewardsPrefix(val)) defer iter.Close() for ; iter.Valid(); iter.Next() { store.Delete(iter.Key()) @@ -168,7 +168,7 @@ func (k Keeper) DeleteValidatorHistoricalRewards(ctx sdk.Context, val sdk.ValAdd // delete all historical rewards func (k Keeper) DeleteAllValidatorHistoricalRewards(ctx sdk.Context) { store := ctx.KVStore(k.storeKey) - iter := sdk.KVStorePrefixIterator(store, ValidatorHistoricalRewardsPrefix) + iter := sdk.KVStorePrefixIterator(store, types.ValidatorHistoricalRewardsPrefix) defer iter.Close() for ; iter.Valid(); iter.Next() { store.Delete(iter.Key()) @@ -178,7 +178,7 @@ func (k Keeper) DeleteAllValidatorHistoricalRewards(ctx sdk.Context) { // historical reference count (used for testcases) func (k Keeper) GetValidatorHistoricalReferenceCount(ctx sdk.Context) (count uint64) { store := ctx.KVStore(k.storeKey) - iter := sdk.KVStorePrefixIterator(store, ValidatorHistoricalRewardsPrefix) + iter := sdk.KVStorePrefixIterator(store, types.ValidatorHistoricalRewardsPrefix) defer iter.Close() for ; iter.Valid(); iter.Next() { var rewards types.ValidatorHistoricalRewards @@ -191,7 +191,7 @@ func (k Keeper) GetValidatorHistoricalReferenceCount(ctx sdk.Context) (count uin // get current rewards for a validator func (k Keeper) GetValidatorCurrentRewards(ctx sdk.Context, val sdk.ValAddress) (rewards types.ValidatorCurrentRewards) { store := ctx.KVStore(k.storeKey) - b := store.Get(GetValidatorCurrentRewardsKey(val)) + b := store.Get(types.GetValidatorCurrentRewardsKey(val)) k.cdc.MustUnmarshalBinaryLengthPrefixed(b, &rewards) return } @@ -200,24 +200,24 @@ func (k Keeper) GetValidatorCurrentRewards(ctx sdk.Context, val sdk.ValAddress) func (k Keeper) SetValidatorCurrentRewards(ctx sdk.Context, val sdk.ValAddress, rewards types.ValidatorCurrentRewards) { store := ctx.KVStore(k.storeKey) b := k.cdc.MustMarshalBinaryLengthPrefixed(rewards) - store.Set(GetValidatorCurrentRewardsKey(val), b) + store.Set(types.GetValidatorCurrentRewardsKey(val), b) } // delete current rewards for a validator func (k Keeper) DeleteValidatorCurrentRewards(ctx sdk.Context, val sdk.ValAddress) { store := ctx.KVStore(k.storeKey) - store.Delete(GetValidatorCurrentRewardsKey(val)) + store.Delete(types.GetValidatorCurrentRewardsKey(val)) } // iterate over current rewards func (k Keeper) IterateValidatorCurrentRewards(ctx sdk.Context, handler func(val sdk.ValAddress, rewards types.ValidatorCurrentRewards) (stop bool)) { store := ctx.KVStore(k.storeKey) - iter := sdk.KVStorePrefixIterator(store, ValidatorCurrentRewardsPrefix) + iter := sdk.KVStorePrefixIterator(store, types.ValidatorCurrentRewardsPrefix) defer iter.Close() for ; iter.Valid(); iter.Next() { var rewards types.ValidatorCurrentRewards k.cdc.MustUnmarshalBinaryLengthPrefixed(iter.Value(), &rewards) - addr := GetValidatorCurrentRewardsAddress(iter.Key()) + addr := types.GetValidatorCurrentRewardsAddress(iter.Key()) if handler(addr, rewards) { break } @@ -227,7 +227,7 @@ func (k Keeper) IterateValidatorCurrentRewards(ctx sdk.Context, handler func(val // get accumulated commission for a validator func (k Keeper) GetValidatorAccumulatedCommission(ctx sdk.Context, val sdk.ValAddress) (commission types.ValidatorAccumulatedCommission) { store := ctx.KVStore(k.storeKey) - b := store.Get(GetValidatorAccumulatedCommissionKey(val)) + b := store.Get(types.GetValidatorAccumulatedCommissionKey(val)) if b == nil { return types.ValidatorAccumulatedCommission{} } @@ -246,24 +246,24 @@ func (k Keeper) SetValidatorAccumulatedCommission(ctx sdk.Context, val sdk.ValAd bz = k.cdc.MustMarshalBinaryLengthPrefixed(commission) } - store.Set(GetValidatorAccumulatedCommissionKey(val), bz) + store.Set(types.GetValidatorAccumulatedCommissionKey(val), bz) } // delete accumulated commission for a validator func (k Keeper) DeleteValidatorAccumulatedCommission(ctx sdk.Context, val sdk.ValAddress) { store := ctx.KVStore(k.storeKey) - store.Delete(GetValidatorAccumulatedCommissionKey(val)) + store.Delete(types.GetValidatorAccumulatedCommissionKey(val)) } // iterate over accumulated commissions func (k Keeper) IterateValidatorAccumulatedCommissions(ctx sdk.Context, handler func(val sdk.ValAddress, commission types.ValidatorAccumulatedCommission) (stop bool)) { store := ctx.KVStore(k.storeKey) - iter := sdk.KVStorePrefixIterator(store, ValidatorAccumulatedCommissionPrefix) + iter := sdk.KVStorePrefixIterator(store, types.ValidatorAccumulatedCommissionPrefix) defer iter.Close() for ; iter.Valid(); iter.Next() { var commission types.ValidatorAccumulatedCommission k.cdc.MustUnmarshalBinaryLengthPrefixed(iter.Value(), &commission) - addr := GetValidatorAccumulatedCommissionAddress(iter.Key()) + addr := types.GetValidatorAccumulatedCommissionAddress(iter.Key()) if handler(addr, commission) { break } @@ -273,7 +273,7 @@ func (k Keeper) IterateValidatorAccumulatedCommissions(ctx sdk.Context, handler // get validator outstanding rewards func (k Keeper) GetValidatorOutstandingRewards(ctx sdk.Context, val sdk.ValAddress) (rewards types.ValidatorOutstandingRewards) { store := ctx.KVStore(k.storeKey) - b := store.Get(GetValidatorOutstandingRewardsKey(val)) + b := store.Get(types.GetValidatorOutstandingRewardsKey(val)) k.cdc.MustUnmarshalBinaryLengthPrefixed(b, &rewards) return } @@ -282,24 +282,24 @@ func (k Keeper) GetValidatorOutstandingRewards(ctx sdk.Context, val sdk.ValAddre func (k Keeper) SetValidatorOutstandingRewards(ctx sdk.Context, val sdk.ValAddress, rewards types.ValidatorOutstandingRewards) { store := ctx.KVStore(k.storeKey) b := k.cdc.MustMarshalBinaryLengthPrefixed(rewards) - store.Set(GetValidatorOutstandingRewardsKey(val), b) + store.Set(types.GetValidatorOutstandingRewardsKey(val), b) } // delete validator outstanding rewards func (k Keeper) DeleteValidatorOutstandingRewards(ctx sdk.Context, val sdk.ValAddress) { store := ctx.KVStore(k.storeKey) - store.Delete(GetValidatorOutstandingRewardsKey(val)) + store.Delete(types.GetValidatorOutstandingRewardsKey(val)) } // iterate validator outstanding rewards func (k Keeper) IterateValidatorOutstandingRewards(ctx sdk.Context, handler func(val sdk.ValAddress, rewards types.ValidatorOutstandingRewards) (stop bool)) { store := ctx.KVStore(k.storeKey) - iter := sdk.KVStorePrefixIterator(store, ValidatorOutstandingRewardsPrefix) + iter := sdk.KVStorePrefixIterator(store, types.ValidatorOutstandingRewardsPrefix) defer iter.Close() for ; iter.Valid(); iter.Next() { var rewards types.ValidatorOutstandingRewards k.cdc.MustUnmarshalBinaryLengthPrefixed(iter.Value(), &rewards) - addr := GetValidatorOutstandingRewardsAddress(iter.Key()) + addr := types.GetValidatorOutstandingRewardsAddress(iter.Key()) if handler(addr, rewards) { break } @@ -309,7 +309,7 @@ func (k Keeper) IterateValidatorOutstandingRewards(ctx sdk.Context, handler func // get slash event for height func (k Keeper) GetValidatorSlashEvent(ctx sdk.Context, val sdk.ValAddress, height, period uint64) (event types.ValidatorSlashEvent, found bool) { store := ctx.KVStore(k.storeKey) - b := store.Get(GetValidatorSlashEventKey(val, height, period)) + b := store.Get(types.GetValidatorSlashEventKey(val, height, period)) if b == nil { return types.ValidatorSlashEvent{}, false } @@ -321,7 +321,7 @@ func (k Keeper) GetValidatorSlashEvent(ctx sdk.Context, val sdk.ValAddress, heig func (k Keeper) SetValidatorSlashEvent(ctx sdk.Context, val sdk.ValAddress, height, period uint64, event types.ValidatorSlashEvent) { store := ctx.KVStore(k.storeKey) b := k.cdc.MustMarshalBinaryLengthPrefixed(event) - store.Set(GetValidatorSlashEventKey(val, height, period), b) + store.Set(types.GetValidatorSlashEventKey(val, height, period), b) } // iterate over slash events between heights, inclusive @@ -329,14 +329,14 @@ func (k Keeper) IterateValidatorSlashEventsBetween(ctx sdk.Context, val sdk.ValA handler func(height uint64, event types.ValidatorSlashEvent) (stop bool)) { store := ctx.KVStore(k.storeKey) iter := store.Iterator( - GetValidatorSlashEventKeyPrefix(val, startingHeight), - GetValidatorSlashEventKeyPrefix(val, endingHeight+1), + types.GetValidatorSlashEventKeyPrefix(val, startingHeight), + types.GetValidatorSlashEventKeyPrefix(val, endingHeight+1), ) defer iter.Close() for ; iter.Valid(); iter.Next() { var event types.ValidatorSlashEvent k.cdc.MustUnmarshalBinaryLengthPrefixed(iter.Value(), &event) - _, height := GetValidatorSlashEventAddressHeight(iter.Key()) + _, height := types.GetValidatorSlashEventAddressHeight(iter.Key()) if handler(height, event) { break } @@ -346,12 +346,12 @@ func (k Keeper) IterateValidatorSlashEventsBetween(ctx sdk.Context, val sdk.ValA // iterate over all slash events func (k Keeper) IterateValidatorSlashEvents(ctx sdk.Context, handler func(val sdk.ValAddress, height uint64, event types.ValidatorSlashEvent) (stop bool)) { store := ctx.KVStore(k.storeKey) - iter := sdk.KVStorePrefixIterator(store, ValidatorSlashEventPrefix) + iter := sdk.KVStorePrefixIterator(store, types.ValidatorSlashEventPrefix) defer iter.Close() for ; iter.Valid(); iter.Next() { var event types.ValidatorSlashEvent k.cdc.MustUnmarshalBinaryLengthPrefixed(iter.Value(), &event) - val, height := GetValidatorSlashEventAddressHeight(iter.Key()) + val, height := types.GetValidatorSlashEventAddressHeight(iter.Key()) if handler(val, height, event) { break } @@ -361,7 +361,7 @@ func (k Keeper) IterateValidatorSlashEvents(ctx sdk.Context, handler func(val sd // delete slash events for a particular validator func (k Keeper) DeleteValidatorSlashEvents(ctx sdk.Context, val sdk.ValAddress) { store := ctx.KVStore(k.storeKey) - iter := sdk.KVStorePrefixIterator(store, GetValidatorSlashEventPrefix(val)) + iter := sdk.KVStorePrefixIterator(store, types.GetValidatorSlashEventPrefix(val)) defer iter.Close() for ; iter.Valid(); iter.Next() { store.Delete(iter.Key()) @@ -371,7 +371,7 @@ func (k Keeper) DeleteValidatorSlashEvents(ctx sdk.Context, val sdk.ValAddress) // delete all slash events func (k Keeper) DeleteAllValidatorSlashEvents(ctx sdk.Context) { store := ctx.KVStore(k.storeKey) - iter := sdk.KVStorePrefixIterator(store, ValidatorSlashEventPrefix) + iter := sdk.KVStorePrefixIterator(store, types.ValidatorSlashEventPrefix) defer iter.Close() for ; iter.Valid(); iter.Next() { store.Delete(iter.Key()) diff --git a/x/distribution/keeper/test_common.go b/x/distribution/keeper/test_common.go index 1d53c9d1816a..78425e47c11d 100644 --- a/x/distribution/keeper/test_common.go +++ b/x/distribution/keeper/test_common.go @@ -135,7 +135,7 @@ func CreateTestInputAdvanced(t *testing.T, isCheckTx bool, initPower int64, sk := staking.NewKeeper(cdc, keyStaking, supplyKeeper, pk.Subspace(staking.DefaultParamspace)) sk.SetParams(ctx, staking.DefaultParams()) - keeper := NewKeeper(cdc, keyDistr, pk.Subspace(DefaultParamspace), sk, supplyKeeper, auth.FeeCollectorName, blacklistedAddrs) + keeper := NewKeeper(cdc, keyDistr, pk.Subspace(types.DefaultParamspace), sk, supplyKeeper, auth.FeeCollectorName, blacklistedAddrs) initCoins := sdk.NewCoins(sdk.NewCoin(sk.BondDenom(ctx), initTokens)) totalSupply := sdk.NewCoins(sdk.NewCoin(sk.BondDenom(ctx), initTokens.MulRaw(int64(len(TestAddrs))))) @@ -158,9 +158,12 @@ func CreateTestInputAdvanced(t *testing.T, isCheckTx bool, initPower int64, // set genesis items required for distribution keeper.SetFeePool(ctx, types.InitialFeePool()) - keeper.SetCommunityTax(ctx, communityTax) - keeper.SetBaseProposerReward(ctx, sdk.NewDecWithPrec(1, 2)) - keeper.SetBonusProposerReward(ctx, sdk.NewDecWithPrec(4, 2)) + + params := types.DefaultParams() + params.CommunityTax = communityTax + params.BaseProposerReward = sdk.NewDecWithPrec(1, 2) + params.BonusProposerReward = sdk.NewDecWithPrec(4, 2) + keeper.SetParams(ctx, params) return ctx, accountKeeper, bankKeeper, keeper, sk, pk, supplyKeeper } diff --git a/x/distribution/legacy/v0_38/migrate.go b/x/distribution/legacy/v0_38/migrate.go new file mode 100644 index 000000000000..fb1b1d2f8f14 --- /dev/null +++ b/x/distribution/legacy/v0_38/migrate.go @@ -0,0 +1,27 @@ +package v0_38 + +// DONTCOVER +// nolint + +import ( + v036distr "github.com/cosmos/cosmos-sdk/x/distribution/legacy/v0_36" +) + +// Migrate accepts exported genesis state from v0.36 or v0.37 and migrates it to +// v0.38 genesis state. All entries are identical except for parameters. +func Migrate(oldGenState v036distr.GenesisState) GenesisState { + params := Params{ + CommunityTax: oldGenState.CommunityTax, + BaseProposerReward: oldGenState.BaseProposerReward, + BonusProposerReward: oldGenState.BonusProposerReward, + WithdrawAddrEnabled: oldGenState.WithdrawAddrEnabled, + } + + return NewGenesisState( + params, oldGenState.FeePool, + oldGenState.DelegatorWithdrawInfos, oldGenState.PreviousProposer, + oldGenState.OutstandingRewards, oldGenState.ValidatorAccumulatedCommissions, + oldGenState.ValidatorHistoricalRewards, oldGenState.ValidatorCurrentRewards, + oldGenState.DelegatorStartingInfos, oldGenState.ValidatorSlashEvents, + ) +} diff --git a/x/distribution/legacy/v0_38/types.go b/x/distribution/legacy/v0_38/types.go new file mode 100644 index 000000000000..4457e2738da3 --- /dev/null +++ b/x/distribution/legacy/v0_38/types.go @@ -0,0 +1,50 @@ +package v0_38 + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + v034distr "github.com/cosmos/cosmos-sdk/x/distribution/legacy/v0_34" + v036distr "github.com/cosmos/cosmos-sdk/x/distribution/legacy/v0_36" +) + +type ( + GenesisState struct { + Params Params `json:"params" yaml:"params"` + FeePool v034distr.FeePool `json:"fee_pool"` + DelegatorWithdrawInfos []v034distr.DelegatorWithdrawInfo `json:"delegator_withdraw_infos"` + PreviousProposer sdk.ConsAddress `json:"previous_proposer" yaml:"previous_proposer"` + OutstandingRewards []v034distr.ValidatorOutstandingRewardsRecord `json:"outstanding_rewards"` + ValidatorAccumulatedCommissions []v034distr.ValidatorAccumulatedCommissionRecord `json:"validator_accumulated_commissions"` + ValidatorHistoricalRewards []v034distr.ValidatorHistoricalRewardsRecord `json:"validator_historical_rewards"` + ValidatorCurrentRewards []v034distr.ValidatorCurrentRewardsRecord `json:"validator_current_rewards"` + DelegatorStartingInfos []v034distr.DelegatorStartingInfoRecord `json:"delegator_starting_infos"` + ValidatorSlashEvents []v036distr.ValidatorSlashEventRecord `json:"validator_slash_events" yaml:"validator_slash_events"` + } + + Params struct { + CommunityTax sdk.Dec `json:"community_tax" yaml:"community_tax"` + BaseProposerReward sdk.Dec `json:"base_proposer_reward" yaml:"base_proposer_reward"` + BonusProposerReward sdk.Dec `json:"bonus_proposer_reward" yaml:"bonus_proposer_reward"` + WithdrawAddrEnabled bool `json:"withdraw_addr_enabled" yaml:"withdraw_addr_enabled"` + } +) + +func NewGenesisState( + params Params, feePool v034distr.FeePool, dwis []v034distr.DelegatorWithdrawInfo, pp sdk.ConsAddress, + r []v034distr.ValidatorOutstandingRewardsRecord, acc []v034distr.ValidatorAccumulatedCommissionRecord, + historical []v034distr.ValidatorHistoricalRewardsRecord, cur []v034distr.ValidatorCurrentRewardsRecord, + dels []v034distr.DelegatorStartingInfoRecord, slashes []v036distr.ValidatorSlashEventRecord, +) GenesisState { + + return GenesisState{ + FeePool: feePool, + Params: params, + DelegatorWithdrawInfos: dwis, + PreviousProposer: pp, + OutstandingRewards: r, + ValidatorAccumulatedCommissions: acc, + ValidatorHistoricalRewards: historical, + ValidatorCurrentRewards: cur, + DelegatorStartingInfos: dels, + ValidatorSlashEvents: slashes, + } +} diff --git a/x/distribution/simulation/decoder.go b/x/distribution/simulation/decoder.go index c1b8dce42821..d6098a929fe1 100644 --- a/x/distribution/simulation/decoder.go +++ b/x/distribution/simulation/decoder.go @@ -9,56 +9,55 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/distribution/keeper" "github.com/cosmos/cosmos-sdk/x/distribution/types" ) // DecodeStore unmarshals the KVPair's Value to the corresponding distribution type func DecodeStore(cdc *codec.Codec, kvA, kvB cmn.KVPair) string { switch { - case bytes.Equal(kvA.Key[:1], keeper.FeePoolKey): + case bytes.Equal(kvA.Key[:1], types.FeePoolKey): var feePoolA, feePoolB types.FeePool cdc.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &feePoolA) cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &feePoolB) return fmt.Sprintf("%v\n%v", feePoolA, feePoolB) - case bytes.Equal(kvA.Key[:1], keeper.ProposerKey): + case bytes.Equal(kvA.Key[:1], types.ProposerKey): return fmt.Sprintf("%v\n%v", sdk.ConsAddress(kvA.Value), sdk.ConsAddress(kvB.Value)) - case bytes.Equal(kvA.Key[:1], keeper.ValidatorOutstandingRewardsPrefix): + case bytes.Equal(kvA.Key[:1], types.ValidatorOutstandingRewardsPrefix): var rewardsA, rewardsB types.ValidatorOutstandingRewards cdc.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &rewardsA) cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &rewardsB) return fmt.Sprintf("%v\n%v", rewardsA, rewardsB) - case bytes.Equal(kvA.Key[:1], keeper.DelegatorWithdrawAddrPrefix): + case bytes.Equal(kvA.Key[:1], types.DelegatorWithdrawAddrPrefix): return fmt.Sprintf("%v\n%v", sdk.AccAddress(kvA.Value), sdk.AccAddress(kvB.Value)) - case bytes.Equal(kvA.Key[:1], keeper.DelegatorStartingInfoPrefix): + case bytes.Equal(kvA.Key[:1], types.DelegatorStartingInfoPrefix): var infoA, infoB types.DelegatorStartingInfo cdc.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &infoA) cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &infoB) return fmt.Sprintf("%v\n%v", infoA, infoB) - case bytes.Equal(kvA.Key[:1], keeper.ValidatorHistoricalRewardsPrefix): + case bytes.Equal(kvA.Key[:1], types.ValidatorHistoricalRewardsPrefix): var rewardsA, rewardsB types.ValidatorHistoricalRewards cdc.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &rewardsA) cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &rewardsB) return fmt.Sprintf("%v\n%v", rewardsA, rewardsB) - case bytes.Equal(kvA.Key[:1], keeper.ValidatorCurrentRewardsPrefix): + case bytes.Equal(kvA.Key[:1], types.ValidatorCurrentRewardsPrefix): var rewardsA, rewardsB types.ValidatorCurrentRewards cdc.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &rewardsA) cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &rewardsB) return fmt.Sprintf("%v\n%v", rewardsA, rewardsB) - case bytes.Equal(kvA.Key[:1], keeper.ValidatorAccumulatedCommissionPrefix): + case bytes.Equal(kvA.Key[:1], types.ValidatorAccumulatedCommissionPrefix): var commissionA, commissionB types.ValidatorAccumulatedCommission cdc.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &commissionA) cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &commissionB) return fmt.Sprintf("%v\n%v", commissionA, commissionB) - case bytes.Equal(kvA.Key[:1], keeper.ValidatorSlashEventPrefix): + case bytes.Equal(kvA.Key[:1], types.ValidatorSlashEventPrefix): var eventA, eventB types.ValidatorSlashEvent cdc.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &eventA) cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &eventB) diff --git a/x/distribution/simulation/decoder_test.go b/x/distribution/simulation/decoder_test.go index f2c4d5f94d49..b804260acaf9 100644 --- a/x/distribution/simulation/decoder_test.go +++ b/x/distribution/simulation/decoder_test.go @@ -44,8 +44,8 @@ func TestDecodeDistributionStore(t *testing.T) { slashEvent := types.NewValidatorSlashEvent(10, sdk.OneDec()) kvPairs := cmn.KVPairs{ - cmn.KVPair{Key: keeper.FeePoolKey, Value: cdc.MustMarshalBinaryLengthPrefixed(feePool)}, - cmn.KVPair{Key: keeper.ProposerKey, Value: consAddr1.Bytes()}, + cmn.KVPair{Key: types.FeePoolKey, Value: cdc.MustMarshalBinaryLengthPrefixed(feePool)}, + cmn.KVPair{Key: types.ProposerKey, Value: consAddr1.Bytes()}, cmn.KVPair{Key: keeper.GetValidatorOutstandingRewardsKey(valAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(outstanding)}, cmn.KVPair{Key: keeper.GetDelegatorWithdrawAddrKey(delAddr1), Value: delAddr1.Bytes()}, cmn.KVPair{Key: keeper.GetDelegatorStartingInfoKey(valAddr1, delAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(info)}, diff --git a/x/distribution/simulation/genesis.go b/x/distribution/simulation/genesis.go index 207a14fe2e2c..9bc9df198c8b 100644 --- a/x/distribution/simulation/genesis.go +++ b/x/distribution/simulation/genesis.go @@ -68,11 +68,13 @@ func RandomizedGenState(simState *module.SimulationState) { ) distrGenesis := types.GenesisState{ - FeePool: types.InitialFeePool(), - CommunityTax: communityTax, - BaseProposerReward: baseProposerReward, - BonusProposerReward: bonusProposerReward, - WithdrawAddrEnabled: withdrawEnabled, + FeePool: types.InitialFeePool(), + Params: types.Params{ + CommunityTax: communityTax, + BaseProposerReward: baseProposerReward, + BonusProposerReward: bonusProposerReward, + WithdrawAddrEnabled: withdrawEnabled, + }, } fmt.Printf("Selected randomly generated distribution parameters:\n%s\n", codec.MustMarshalJSONIndent(simState.Cdc, distrGenesis)) diff --git a/x/distribution/types/genesis.go b/x/distribution/types/genesis.go index db4f119668a4..8ef054c72479 100644 --- a/x/distribution/types/genesis.go +++ b/x/distribution/types/genesis.go @@ -1,8 +1,6 @@ package types import ( - "fmt" - sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -55,11 +53,8 @@ type ValidatorSlashEventRecord struct { // GenesisState - all distribution state that must be provided at genesis type GenesisState struct { + Params Params `json:"params" yaml:"params"` FeePool FeePool `json:"fee_pool" yaml:"fee_pool"` - CommunityTax sdk.Dec `json:"community_tax" yaml:"community_tax"` - BaseProposerReward sdk.Dec `json:"base_proposer_reward" yaml:"base_proposer_reward"` - BonusProposerReward sdk.Dec `json:"bonus_proposer_reward" yaml:"bonus_proposer_reward"` - WithdrawAddrEnabled bool `json:"withdraw_addr_enabled" yaml:"withdraw_addr_enabled"` DelegatorWithdrawInfos []DelegatorWithdrawInfo `json:"delegator_withdraw_infos" yaml:"delegator_withdraw_infos"` PreviousProposer sdk.ConsAddress `json:"previous_proposer" yaml:"previous_proposer"` OutstandingRewards []ValidatorOutstandingRewardsRecord `json:"outstanding_rewards" yaml:"outstanding_rewards"` @@ -70,18 +65,15 @@ type GenesisState struct { ValidatorSlashEvents []ValidatorSlashEventRecord `json:"validator_slash_events" yaml:"validator_slash_events"` } -func NewGenesisState(feePool FeePool, communityTax, baseProposerReward, bonusProposerReward sdk.Dec, - withdrawAddrEnabled bool, dwis []DelegatorWithdrawInfo, pp sdk.ConsAddress, r []ValidatorOutstandingRewardsRecord, +func NewGenesisState( + params Params, fp FeePool, dwis []DelegatorWithdrawInfo, pp sdk.ConsAddress, r []ValidatorOutstandingRewardsRecord, acc []ValidatorAccumulatedCommissionRecord, historical []ValidatorHistoricalRewardsRecord, - cur []ValidatorCurrentRewardsRecord, dels []DelegatorStartingInfoRecord, - slashes []ValidatorSlashEventRecord) GenesisState { + cur []ValidatorCurrentRewardsRecord, dels []DelegatorStartingInfoRecord, slashes []ValidatorSlashEventRecord, +) GenesisState { return GenesisState{ - FeePool: feePool, - CommunityTax: communityTax, - BaseProposerReward: baseProposerReward, - BonusProposerReward: bonusProposerReward, - WithdrawAddrEnabled: withdrawAddrEnabled, + Params: params, + FeePool: fp, DelegatorWithdrawInfos: dwis, PreviousProposer: pp, OutstandingRewards: r, @@ -97,10 +89,7 @@ func NewGenesisState(feePool FeePool, communityTax, baseProposerReward, bonusPro func DefaultGenesisState() GenesisState { return GenesisState{ FeePool: InitialFeePool(), - CommunityTax: sdk.NewDecWithPrec(2, 2), // 2% - BaseProposerReward: sdk.NewDecWithPrec(1, 2), // 1% - BonusProposerReward: sdk.NewDecWithPrec(4, 2), // 4% - WithdrawAddrEnabled: true, + Params: DefaultParams(), DelegatorWithdrawInfos: []DelegatorWithdrawInfo{}, PreviousProposer: nil, OutstandingRewards: []ValidatorOutstandingRewardsRecord{}, @@ -113,24 +102,9 @@ func DefaultGenesisState() GenesisState { } // ValidateGenesis validates the genesis state of distribution genesis input -func ValidateGenesis(data GenesisState) error { - if data.CommunityTax.IsNegative() || data.CommunityTax.GT(sdk.OneDec()) { - return fmt.Errorf("mint parameter CommunityTax should non-negative and "+ - "less than one, is %s", data.CommunityTax.String()) - } - if data.BaseProposerReward.IsNegative() { - return fmt.Errorf("mint parameter BaseProposerReward should be positive, is %s", - data.BaseProposerReward.String()) - } - if data.BonusProposerReward.IsNegative() { - return fmt.Errorf("mint parameter BonusProposerReward should be positive, is %s", - data.BonusProposerReward.String()) - } - if (data.BaseProposerReward.Add(data.BonusProposerReward)). - GT(sdk.OneDec()) { - return fmt.Errorf("mint parameters BaseProposerReward and "+ - "BonusProposerReward cannot add to be greater than one, "+ - "adds to %s", data.BaseProposerReward.Add(data.BonusProposerReward).String()) +func ValidateGenesis(gs GenesisState) error { + if err := gs.Params.ValidateBasic(); err != nil { + return err } - return data.FeePool.ValidateGenesis() + return gs.FeePool.ValidateGenesis() } diff --git a/x/distribution/types/keys.go b/x/distribution/types/keys.go index 5bdeaecc20cc..12fe9b17b9ff 100644 --- a/x/distribution/types/keys.go +++ b/x/distribution/types/keys.go @@ -1,5 +1,11 @@ package types +import ( + "encoding/binary" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + const ( // ModuleName is the module name constant used in many places ModuleName = "distribution" @@ -13,3 +19,175 @@ const ( // QuerierRoute is the querier route for distribution QuerierRoute = ModuleName ) + +// Keys for distribution store +// Items are stored with the following key: values +// +// - 0x00: FeePol +// +// - 0x01: sdk.ConsAddress +// +// - 0x02: ValidatorOutstandingRewards +// +// - 0x03: sdk.AccAddress +// +// - 0x04: DelegatorStartingInfo +// +// - 0x05: ValidatorHistoricalRewards +// +// - 0x06: ValidatorCurrentRewards +// +// - 0x07: ValidatorCurrentRewards +// +// - 0x08: ValidatorSlashEvent +var ( + FeePoolKey = []byte{0x00} // key for global distribution state + ProposerKey = []byte{0x01} // key for the proposer operator address + ValidatorOutstandingRewardsPrefix = []byte{0x02} // key for outstanding rewards + + DelegatorWithdrawAddrPrefix = []byte{0x03} // key for delegator withdraw address + DelegatorStartingInfoPrefix = []byte{0x04} // key for delegator starting info + ValidatorHistoricalRewardsPrefix = []byte{0x05} // key for historical validators rewards / stake + ValidatorCurrentRewardsPrefix = []byte{0x06} // key for current validator rewards + ValidatorAccumulatedCommissionPrefix = []byte{0x07} // key for accumulated validator commission + ValidatorSlashEventPrefix = []byte{0x08} // key for validator slash fraction +) + +// gets an address from a validator's outstanding rewards key +func GetValidatorOutstandingRewardsAddress(key []byte) (valAddr sdk.ValAddress) { + addr := key[1:] + if len(addr) != sdk.AddrLen { + panic("unexpected key length") + } + return sdk.ValAddress(addr) +} + +// gets an address from a delegator's withdraw info key +func GetDelegatorWithdrawInfoAddress(key []byte) (delAddr sdk.AccAddress) { + addr := key[1:] + if len(addr) != sdk.AddrLen { + panic("unexpected key length") + } + return sdk.AccAddress(addr) +} + +// gets the addresses from a delegator starting info key +func GetDelegatorStartingInfoAddresses(key []byte) (valAddr sdk.ValAddress, delAddr sdk.AccAddress) { + addr := key[1 : 1+sdk.AddrLen] + if len(addr) != sdk.AddrLen { + panic("unexpected key length") + } + valAddr = sdk.ValAddress(addr) + addr = key[1+sdk.AddrLen:] + if len(addr) != sdk.AddrLen { + panic("unexpected key length") + } + delAddr = sdk.AccAddress(addr) + return +} + +// gets the address & period from a validator's historical rewards key +func GetValidatorHistoricalRewardsAddressPeriod(key []byte) (valAddr sdk.ValAddress, period uint64) { + addr := key[1 : 1+sdk.AddrLen] + if len(addr) != sdk.AddrLen { + panic("unexpected key length") + } + valAddr = sdk.ValAddress(addr) + b := key[1+sdk.AddrLen:] + if len(b) != 8 { + panic("unexpected key length") + } + period = binary.LittleEndian.Uint64(b) + return +} + +// gets the address from a validator's current rewards key +func GetValidatorCurrentRewardsAddress(key []byte) (valAddr sdk.ValAddress) { + addr := key[1:] + if len(addr) != sdk.AddrLen { + panic("unexpected key length") + } + return sdk.ValAddress(addr) +} + +// gets the address from a validator's accumulated commission key +func GetValidatorAccumulatedCommissionAddress(key []byte) (valAddr sdk.ValAddress) { + addr := key[1:] + if len(addr) != sdk.AddrLen { + panic("unexpected key length") + } + return sdk.ValAddress(addr) +} + +// gets the height from a validator's slash event key +func GetValidatorSlashEventAddressHeight(key []byte) (valAddr sdk.ValAddress, height uint64) { + addr := key[1 : 1+sdk.AddrLen] + if len(addr) != sdk.AddrLen { + panic("unexpected key length") + } + valAddr = sdk.ValAddress(addr) + startB := 1 + sdk.AddrLen + b := key[startB : startB+8] // the next 8 bytes represent the height + height = binary.BigEndian.Uint64(b) + return +} + +// gets the outstanding rewards key for a validator +func GetValidatorOutstandingRewardsKey(valAddr sdk.ValAddress) []byte { + return append(ValidatorOutstandingRewardsPrefix, valAddr.Bytes()...) +} + +// gets the key for a delegator's withdraw addr +func GetDelegatorWithdrawAddrKey(delAddr sdk.AccAddress) []byte { + return append(DelegatorWithdrawAddrPrefix, delAddr.Bytes()...) +} + +// gets the key for a delegator's starting info +func GetDelegatorStartingInfoKey(v sdk.ValAddress, d sdk.AccAddress) []byte { + return append(append(DelegatorStartingInfoPrefix, v.Bytes()...), d.Bytes()...) +} + +// gets the prefix key for a validator's historical rewards +func GetValidatorHistoricalRewardsPrefix(v sdk.ValAddress) []byte { + return append(ValidatorHistoricalRewardsPrefix, v.Bytes()...) +} + +// gets the key for a validator's historical rewards +func GetValidatorHistoricalRewardsKey(v sdk.ValAddress, k uint64) []byte { + b := make([]byte, 8) + binary.LittleEndian.PutUint64(b, k) + return append(append(ValidatorHistoricalRewardsPrefix, v.Bytes()...), b...) +} + +// gets the key for a validator's current rewards +func GetValidatorCurrentRewardsKey(v sdk.ValAddress) []byte { + return append(ValidatorCurrentRewardsPrefix, v.Bytes()...) +} + +// gets the key for a validator's current commission +func GetValidatorAccumulatedCommissionKey(v sdk.ValAddress) []byte { + return append(ValidatorAccumulatedCommissionPrefix, v.Bytes()...) +} + +// gets the prefix key for a validator's slash fractions +func GetValidatorSlashEventPrefix(v sdk.ValAddress) []byte { + return append(ValidatorSlashEventPrefix, v.Bytes()...) +} + +// gets the prefix key for a validator's slash fraction (ValidatorSlashEventPrefix + height) +func GetValidatorSlashEventKeyPrefix(v sdk.ValAddress, height uint64) []byte { + heightBz := make([]byte, 8) + binary.BigEndian.PutUint64(heightBz, height) + return append( + ValidatorSlashEventPrefix, + append(v.Bytes(), heightBz...)..., + ) +} + +// gets the key for a validator's slash fraction +func GetValidatorSlashEventKey(v sdk.ValAddress, height, period uint64) []byte { + periodBz := make([]byte, 8) + binary.BigEndian.PutUint64(periodBz, period) + prefix := GetValidatorSlashEventKeyPrefix(v, height) + return append(prefix, periodBz...) +} diff --git a/x/distribution/types/params.go b/x/distribution/types/params.go new file mode 100644 index 000000000000..19f781bf2951 --- /dev/null +++ b/x/distribution/types/params.go @@ -0,0 +1,143 @@ +package types + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/params" + "gopkg.in/yaml.v2" +) + +const ( + // default paramspace for params keeper + DefaultParamspace = ModuleName +) + +// Parameter keys +var ( + ParamStoreKeyCommunityTax = []byte("communitytax") + ParamStoreKeyBaseProposerReward = []byte("baseproposerreward") + ParamStoreKeyBonusProposerReward = []byte("bonusproposerreward") + ParamStoreKeyWithdrawAddrEnabled = []byte("withdrawaddrenabled") +) + +// Params defines the set of distribution parameters. +type Params struct { + CommunityTax sdk.Dec `json:"community_tax" yaml:"community_tax"` + BaseProposerReward sdk.Dec `json:"base_proposer_reward" yaml:"base_proposer_reward"` + BonusProposerReward sdk.Dec `json:"bonus_proposer_reward" yaml:"bonus_proposer_reward"` + WithdrawAddrEnabled bool `json:"withdraw_addr_enabled" yaml:"withdraw_addr_enabled"` +} + +// ParamKeyTable returns the parameter key table. +func ParamKeyTable() params.KeyTable { + return params.NewKeyTable().RegisterParamSet(&Params{}) +} + +// DefaultParams returns default distribution parameters +func DefaultParams() Params { + return Params{ + CommunityTax: sdk.NewDecWithPrec(2, 2), // 2% + BaseProposerReward: sdk.NewDecWithPrec(1, 2), // 1% + BonusProposerReward: sdk.NewDecWithPrec(4, 2), // 4% + WithdrawAddrEnabled: true, + } +} + +func (p Params) String() string { + out, _ := yaml.Marshal(p) + return string(out) +} + +// ParamSetPairs returns the parameter set pairs. +func (p *Params) ParamSetPairs() params.ParamSetPairs { + return params.ParamSetPairs{ + params.NewParamSetPair(ParamStoreKeyCommunityTax, &p.CommunityTax, validateCommunityTax), + params.NewParamSetPair(ParamStoreKeyBaseProposerReward, &p.BaseProposerReward, validateBaseProposerReward), + params.NewParamSetPair(ParamStoreKeyBonusProposerReward, &p.BonusProposerReward, validateBonusProposerReward), + params.NewParamSetPair(ParamStoreKeyWithdrawAddrEnabled, &p.WithdrawAddrEnabled, validateWithdrawAddrEnabled), + } +} + +// ValidateBasic performs basic validation on distribution parameters. +func (p Params) ValidateBasic() error { + if p.CommunityTax.IsNegative() || p.CommunityTax.GT(sdk.OneDec()) { + return fmt.Errorf( + "community tax should non-negative and less than one: %s", p.CommunityTax, + ) + } + if p.BaseProposerReward.IsNegative() { + return fmt.Errorf( + "base proposer reward should be positive: %s", p.BaseProposerReward, + ) + } + if p.BonusProposerReward.IsNegative() { + return fmt.Errorf( + "bonus proposer reward should be positive: %s", p.BonusProposerReward, + ) + } + if v := p.BaseProposerReward.Add(p.BonusProposerReward); v.GT(sdk.OneDec()) { + return fmt.Errorf( + "sum of base and bonus proposer reward cannot greater than one: %s", v, + ) + } + + return nil +} + +func validateCommunityTax(i interface{}) error { + v, ok := i.(sdk.Dec) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v.IsNegative() { + return fmt.Errorf("community tax must be positive: %s", v) + } + if v.GT(sdk.OneDec()) { + return fmt.Errorf("community tax too large: %s", v) + } + + return nil +} + +func validateBaseProposerReward(i interface{}) error { + v, ok := i.(sdk.Dec) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v.IsNegative() { + return fmt.Errorf("base proposer reward must be positive: %s", v) + } + if v.GT(sdk.OneDec()) { + return fmt.Errorf("base proposer reward too large: %s", v) + } + + return nil +} + +func validateBonusProposerReward(i interface{}) error { + v, ok := i.(sdk.Dec) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v.IsNegative() { + return fmt.Errorf("bonus proposer reward must be positive: %s", v) + } + if v.GT(sdk.OneDec()) { + return fmt.Errorf("bonus proposer reward too large: %s", v) + } + + return nil +} + +func validateWithdrawAddrEnabled(i interface{}) error { + _, ok := i.(bool) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + return nil +} diff --git a/x/distribution/types/querier.go b/x/distribution/types/querier.go index 32ed642ddf86..cbf7d8d0a426 100644 --- a/x/distribution/types/querier.go +++ b/x/distribution/types/querier.go @@ -13,11 +13,6 @@ const ( QueryDelegatorValidators = "delegator_validators" QueryWithdrawAddr = "withdraw_addr" QueryCommunityPool = "community_pool" - - ParamCommunityTax = "community_tax" - ParamBaseProposerReward = "base_proposer_reward" - ParamBonusProposerReward = "bonus_proposer_reward" - ParamWithdrawAddrEnabled = "withdraw_addr_enabled" ) // params for query 'custom/distr/validator_outstanding_rewards' diff --git a/x/evidence/internal/types/params.go b/x/evidence/internal/types/params.go index 6865eb2825ab..5c0dbe638fa3 100644 --- a/x/evidence/internal/types/params.go +++ b/x/evidence/internal/types/params.go @@ -36,14 +36,9 @@ func ParamKeyTable() params.KeyTable { return params.NewKeyTable().RegisterParamSet(&Params{}) } -func (p Params) MarshalYAML() (interface{}, error) { - bz, err := yaml.Marshal(p) - return string(bz), err -} - func (p Params) String() string { - out, _ := p.MarshalYAML() - return out.(string) + out, _ := yaml.Marshal(p) + return string(out) } // ParamSetPairs returns the parameter set pairs. From 214024431fbd950f389c361458ca7b7e63f204c6 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Fri, 10 Jan 2020 16:10:37 -0500 Subject: [PATCH 070/529] Merge PR #5508: Fix and Return Height in x/distribution REST Handlers --- CHANGELOG.md | 1 + x/distribution/client/cli/query.go | 28 +++++-- x/distribution/client/common/common.go | 32 +++----- x/distribution/client/common/common_test.go | 2 +- x/distribution/client/rest/query.go | 82 ++++++++++++--------- 5 files changed, 85 insertions(+), 60 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 44932a03c28a..4e2b582c6180 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -254,6 +254,7 @@ to detail this new feature and how state transitions occur. ### Bug Fixes +* (rest) [\#5508](https://github.com/cosmos/cosmos-sdk/pull/5508) Fix `x/distribution` endpoints to properly return height in the response. * (x/genutil) [\#5499](https://github.com/cosmos/cosmos-sdk/pull/) Ensure `DefaultGenesis` returns valid and non-nil default genesis state. * (client) [\#5303](https://github.com/cosmos/cosmos-sdk/issues/5303) Fix ignored error in tx generate only mode. * (cli) [\#4763](https://github.com/cosmos/cosmos-sdk/issues/4763) Fix flag `--min-self-delegation` for staking `EditValidator` diff --git a/x/distribution/client/cli/query.go b/x/distribution/client/cli/query.go index 06bc2e677328..92af18275233 100644 --- a/x/distribution/client/cli/query.go +++ b/x/distribution/client/cli/query.go @@ -217,26 +217,44 @@ $ %s query distribution rewards cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p co RunE: func(cmd *cobra.Command, args []string) error { cliCtx := context.NewCLIContext().WithCodec(cdc) + // query for rewards from a particular delegation if len(args) == 2 { - // query for rewards from a particular delegation - resp, err := common.QueryDelegationRewards(cliCtx, queryRoute, args[0], args[1]) + resp, _, err := common.QueryDelegationRewards(cliCtx, queryRoute, args[0], args[1]) if err != nil { return err } var result sdk.DecCoins - cdc.MustUnmarshalJSON(resp, &result) + if err = cdc.UnmarshalJSON(resp, &result); err != nil { + return fmt.Errorf("failed to unmarshal response: %w", err) + } + return cliCtx.PrintOutput(result) } + delegatorAddr, err := sdk.AccAddressFromBech32(args[0]) + if err != nil { + return err + } + + params := types.NewQueryDelegatorParams(delegatorAddr) + bz, err := cdc.MarshalJSON(params) + if err != nil { + return fmt.Errorf("failed to marshal params: %w", err) + } + // query for delegator total rewards - resp, err := common.QueryDelegatorTotalRewards(cliCtx, queryRoute, args[0]) + route := fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryDelegatorTotalRewards) + res, _, err := cliCtx.QueryWithData(route, bz) if err != nil { return err } var result types.QueryDelegatorTotalRewardsResponse - cdc.MustUnmarshalJSON(resp, &result) + if err = cdc.UnmarshalJSON(res, &result); err != nil { + return fmt.Errorf("failed to unmarshal response: %w", err) + } + return cliCtx.PrintOutput(result) }, } diff --git a/x/distribution/client/common/common.go b/x/distribution/client/common/common.go index b20e87ec0586..06860012c8cf 100644 --- a/x/distribution/client/common/common.go +++ b/x/distribution/client/common/common.go @@ -8,37 +8,27 @@ import ( "github.com/cosmos/cosmos-sdk/x/distribution/types" ) -// QueryDelegatorTotalRewards queries delegator total rewards. -func QueryDelegatorTotalRewards(cliCtx context.CLIContext, queryRoute, delAddr string) ([]byte, error) { +// QueryDelegationRewards queries a delegation rewards between a delegator and a +// validator. +func QueryDelegationRewards(cliCtx context.CLIContext, queryRoute, delAddr, valAddr string) ([]byte, int64, error) { delegatorAddr, err := sdk.AccAddressFromBech32(delAddr) if err != nil { - return nil, err + return nil, 0, err } - res, _, err := cliCtx.QueryWithData( - fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryDelegatorTotalRewards), - cliCtx.Codec.MustMarshalJSON(types.NewQueryDelegatorParams(delegatorAddr)), - ) - return res, err -} - -// QueryDelegationRewards queries a delegation rewards. -func QueryDelegationRewards(cliCtx context.CLIContext, queryRoute, delAddr, valAddr string) ([]byte, error) { - delegatorAddr, err := sdk.AccAddressFromBech32(delAddr) + validatorAddr, err := sdk.ValAddressFromBech32(valAddr) if err != nil { - return nil, err + return nil, 0, err } - validatorAddr, err := sdk.ValAddressFromBech32(valAddr) + params := types.NewQueryDelegationRewardsParams(delegatorAddr, validatorAddr) + bz, err := cliCtx.Codec.MarshalJSON(params) if err != nil { - return nil, err + return nil, 0, fmt.Errorf("failed to marshal params: %w", err) } - res, _, err := cliCtx.QueryWithData( - fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryDelegationRewards), - cliCtx.Codec.MustMarshalJSON(types.NewQueryDelegationRewardsParams(delegatorAddr, validatorAddr)), - ) - return res, err + route := fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryDelegationRewards) + return cliCtx.QueryWithData(route, bz) } // QueryDelegatorValidators returns delegator's list of validators diff --git a/x/distribution/client/common/common_test.go b/x/distribution/client/common/common_test.go index e4a554a31782..5954f9850742 100644 --- a/x/distribution/client/common/common_test.go +++ b/x/distribution/client/common/common_test.go @@ -30,7 +30,7 @@ func TestQueryDelegationRewardsAddrValidation(t *testing.T) { for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { - _, err := QueryDelegationRewards(ctx, "", tt.args.delAddr, tt.args.valAddr) + _, _, err := QueryDelegationRewards(ctx, "", tt.args.delAddr, tt.args.valAddr) require.True(t, err != nil, tt.wantErr) }) } diff --git a/x/distribution/client/rest/query.go b/x/distribution/client/rest/query.go index d242157dd40f..4c362409dd13 100644 --- a/x/distribution/client/rest/query.go +++ b/x/distribution/client/rest/query.go @@ -73,12 +73,26 @@ func delegatorRewardsHandlerFn(cliCtx context.CLIContext, queryRoute string) htt return } - // query for rewards from a particular delegator - res, ok := checkResponseQueryDelegatorTotalRewards(w, cliCtx, queryRoute, mux.Vars(r)["delegatorAddr"]) + delegatorAddr, ok := checkDelegatorAddressVar(w, r) if !ok { return } + params := types.NewQueryDelegatorParams(delegatorAddr) + bz, err := cliCtx.Codec.MarshalJSON(params) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("failed to marshal params: %s", err)) + return + } + + route := fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryDelegatorTotalRewards) + res, height, err := cliCtx.QueryWithData(route, bz) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + + cliCtx = cliCtx.WithHeight(height) rest.PostProcessResponse(w, cliCtx, res) } } @@ -91,12 +105,16 @@ func delegationRewardsHandlerFn(cliCtx context.CLIContext, queryRoute string) ht return } + delAddr := mux.Vars(r)["delegatorAddr"] + valAddr := mux.Vars(r)["validatorAddr"] + // query for rewards from a particular delegation - res, ok := checkResponseQueryDelegationRewards(w, cliCtx, queryRoute, mux.Vars(r)["delegatorAddr"], mux.Vars(r)["validatorAddr"]) + res, height, ok := checkResponseQueryDelegationRewards(w, cliCtx, queryRoute, delAddr, valAddr) if !ok { return } + cliCtx = cliCtx.WithHeight(height) rest.PostProcessResponse(w, cliCtx, res) } } @@ -147,8 +165,7 @@ func NewValidatorDistInfo(operatorAddr sdk.AccAddress, rewards sdk.DecCoins, // HTTP request handler to query validator's distribution information func validatorInfoHandlerFn(cliCtx context.CLIContext, queryRoute string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - valAddr := mux.Vars(r)["validatorAddr"] - validatorAddr, ok := checkValidatorAddressVar(w, r) + valAddr, ok := checkValidatorAddressVar(w, r) if !ok { return } @@ -159,28 +176,39 @@ func validatorInfoHandlerFn(cliCtx context.CLIContext, queryRoute string) http.H } // query commission - commissionRes, err := common.QueryValidatorCommission(cliCtx, queryRoute, validatorAddr) + bz, err := common.QueryValidatorCommission(cliCtx, queryRoute, valAddr) if err != nil { rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return } - var valCom types.ValidatorAccumulatedCommission - cliCtx.Codec.MustUnmarshalJSON(commissionRes, &valCom) + var commission types.ValidatorAccumulatedCommission + if err := cliCtx.Codec.UnmarshalJSON(bz, &commission); err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } // self bond rewards - delAddr := sdk.AccAddress(validatorAddr) - rewardsRes, ok := checkResponseQueryDelegationRewards(w, cliCtx, queryRoute, delAddr.String(), valAddr) + delAddr := sdk.AccAddress(valAddr) + bz, height, ok := checkResponseQueryDelegationRewards(w, cliCtx, queryRoute, delAddr.String(), valAddr.String()) if !ok { return } var rewards sdk.DecCoins - cliCtx.Codec.MustUnmarshalJSON(rewardsRes, &rewards) + if err := cliCtx.Codec.UnmarshalJSON(bz, &rewards); err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } - // Prepare response - res := cliCtx.Codec.MustMarshalJSON(NewValidatorDistInfo(delAddr, rewards, valCom)) - rest.PostProcessResponse(w, cliCtx, res) + bz, err = cliCtx.Codec.MarshalJSON(NewValidatorDistInfo(delAddr, rewards, commission)) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + + cliCtx = cliCtx.WithHeight(height) + rest.PostProcessResponse(w, cliCtx, bz) } } @@ -199,12 +227,13 @@ func validatorRewardsHandlerFn(cliCtx context.CLIContext, queryRoute string) htt } delAddr := sdk.AccAddress(validatorAddr).String() - res, ok := checkResponseQueryDelegationRewards(w, cliCtx, queryRoute, delAddr, valAddr) + bz, height, ok := checkResponseQueryDelegationRewards(w, cliCtx, queryRoute, delAddr, valAddr) if !ok { return } - rest.PostProcessResponse(w, cliCtx, res) + cliCtx = cliCtx.WithHeight(height) + rest.PostProcessResponse(w, cliCtx, bz) } } @@ -277,28 +306,15 @@ func outstandingRewardsHandlerFn(cliCtx context.CLIContext, queryRoute string) h } } -func checkResponseQueryDelegatorTotalRewards( - w http.ResponseWriter, cliCtx context.CLIContext, queryRoute, delAddr string, -) (res []byte, ok bool) { - - res, err := common.QueryDelegatorTotalRewards(cliCtx, queryRoute, delAddr) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) - return nil, false - } - - return res, true -} - func checkResponseQueryDelegationRewards( w http.ResponseWriter, cliCtx context.CLIContext, queryRoute, delAddr, valAddr string, -) (res []byte, ok bool) { +) (res []byte, height int64, ok bool) { - res, err := common.QueryDelegationRewards(cliCtx, queryRoute, delAddr, valAddr) + res, height, err := common.QueryDelegationRewards(cliCtx, queryRoute, delAddr, valAddr) if err != nil { rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) - return nil, false + return nil, 0, false } - return res, true + return res, height, true } From 54ded7b03c5e0f1cd33723a4e9d2b930ba5b6501 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Mon, 13 Jan 2020 00:45:43 -0500 Subject: [PATCH 071/529] Fix go-keychain Dep (#5512) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 98623a826dec..56bcf405d877 100644 --- a/go.mod +++ b/go.mod @@ -32,4 +32,4 @@ require ( go 1.13 -replace github.com/keybase/go-keychain => github.com/keybase/go-keychain v0.0.0-20191220220820-f65a47cbe0b1 +replace github.com/keybase/go-keychain => github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 diff --git a/go.sum b/go.sum index e0479a70f8b8..c65296d00ba5 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,6 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs= +github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4= github.com/99designs/keyring v1.1.3 h1:mEV3iyZWjkxQ7R8ia8GcG97vCX5zQQ7n4o8R2BylwQY= github.com/99designs/keyring v1.1.3/go.mod h1:657DQuMrBZRtuL/voxVyiyb6zpMehlm5vLB9Qwrv904= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= @@ -136,8 +138,6 @@ github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlT github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/keybase/go-keychain v0.0.0-20191220220820-f65a47cbe0b1 h1:Lk38J60jgB05LTkSEElUXe49VEzWMNrPyPFf2vhKM1k= -github.com/keybase/go-keychain v0.0.0-20191220220820-f65a47cbe0b1/go.mod h1:JJNrCn9otv/2QP4D7SMJBgaleKpOf66PnW6F5WGNRIc= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= From d0a5b9bf3668c0c14250a4048d1b21d1c1d2f340 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 13 Jan 2020 13:37:20 +0100 Subject: [PATCH 072/529] Bump github.com/pkg/errors from 0.8.1 to 0.9.0 (#5514) Bumps [github.com/pkg/errors](https://github.com/pkg/errors) from 0.8.1 to 0.9.0. - [Release notes](https://github.com/pkg/errors/releases) - [Commits](https://github.com/pkg/errors/compare/v0.8.1...v0.9.0) Signed-off-by: dependabot-preview[bot] --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 56bcf405d877..dc5b3b85e591 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/hashicorp/golang-lru v0.5.3 github.com/mattn/go-isatty v0.0.11 github.com/pelletier/go-toml v1.6.0 - github.com/pkg/errors v0.8.1 + github.com/pkg/errors v0.9.0 github.com/rakyll/statik v0.1.6 github.com/spf13/afero v1.2.1 // indirect github.com/spf13/cobra v0.0.5 diff --git a/go.sum b/go.sum index c65296d00ba5..5e04f11c35a4 100644 --- a/go.sum +++ b/go.sum @@ -177,6 +177,8 @@ github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.0 h1:J8lpUdobwIeCI7OiSxHqEwJUKvJwicL5+3v1oe2Yb4k= +github.com/pkg/errors v0.9.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= From d452e9398be5f59548a2b211ec1e4717f3093c79 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 14 Jan 2020 09:24:06 -0500 Subject: [PATCH 073/529] Merge PR #5515: Bump github.com/tendermint/tendermint from 0.32.8 to 0.32.9 Bumps [github.com/tendermint/tendermint](https://github.com/tendermint/tendermint) from 0.32.8 to 0.32.9. - [Release notes](https://github.com/tendermint/tendermint/releases) - [Changelog](https://github.com/tendermint/tendermint/blob/v0.32.9/CHANGELOG.md) - [Commits](https://github.com/tendermint/tendermint/compare/v0.32.8...v0.32.9) Signed-off-by: dependabot-preview[bot] Co-authored-by: Alexander Bezobchuk --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index dc5b3b85e591..51539aebd007 100644 --- a/go.mod +++ b/go.mod @@ -25,7 +25,7 @@ require ( github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 github.com/tendermint/go-amino v0.15.1 github.com/tendermint/iavl v0.12.4 - github.com/tendermint/tendermint v0.32.8 + github.com/tendermint/tendermint v0.32.9 github.com/tendermint/tm-db v0.2.0 gopkg.in/yaml.v2 v2.2.7 ) diff --git a/go.sum b/go.sum index 5e04f11c35a4..240520d52f83 100644 --- a/go.sum +++ b/go.sum @@ -263,6 +263,8 @@ github.com/tendermint/iavl v0.12.4/go.mod h1:8LHakzt8/0G3/I8FUU0ReNx98S/EP6eyPJk github.com/tendermint/tendermint v0.32.1/go.mod h1:jmPDAKuNkev9793/ivn/fTBnfpA9mGBww8MPRNPNxnU= github.com/tendermint/tendermint v0.32.8 h1:eOaLJGRi5x/Rb23fiVsxq9c5fZ/6O5QplExlGjNPDVI= github.com/tendermint/tendermint v0.32.8/go.mod h1:5/B1XZjNYtVBso8o1l/Eg4A0Mhu42lDcmftoQl95j/E= +github.com/tendermint/tendermint v0.32.9 h1:++dR46xpBq/yfQx2c5KyrZmb15p2jw9Q5iEtTB82d8s= +github.com/tendermint/tendermint v0.32.9/go.mod h1:5/B1XZjNYtVBso8o1l/Eg4A0Mhu42lDcmftoQl95j/E= github.com/tendermint/tm-db v0.1.1 h1:G3Xezy3sOk9+ekhjZ/kjArYIs1SmwV+1OUgNkj7RgV0= github.com/tendermint/tm-db v0.1.1/go.mod h1:0cPKWu2Mou3IlxecH+MEUSYc1Ch537alLe6CpFrKzgw= github.com/tendermint/tm-db v0.2.0 h1:rJxgdqn6fIiVJZy4zLpY1qVlyD0TU6vhkT4kEf71TQQ= From f3670877313a4dace48a5ed5cbaeeefd76490234 Mon Sep 17 00:00:00 2001 From: Sunny Aggarwal Date: Tue, 14 Jan 2020 10:40:10 -0500 Subject: [PATCH 074/529] Merge PR #5439: Keybase: Multiple Signature Algorithms --- CHANGELOG.md | 18 +++- client/keys/add.go | 34 +++++- client/keys/delete_test.go | 5 +- client/keys/export_test.go | 3 +- client/keys/list_test.go | 3 +- client/keys/show_test.go | 4 +- client/keys/update_test.go | 5 +- crypto/keys/keybase.go | 62 ++++++----- crypto/keys/keybase_base.go | 159 ++++++++++++++++++---------- crypto/keys/keybase_test.go | 53 ++++++++-- crypto/keys/keyring.go | 53 +++++----- crypto/keys/keyring_test.go | 8 +- crypto/keys/keys.go | 4 + crypto/keys/lazy_keybase.go | 29 +++-- crypto/keys/lazy_keybase_test.go | 12 ++- crypto/keys/mintkey/mintkey.go | 87 ++++++++++----- crypto/keys/mintkey/mintkey_test.go | 12 ++- crypto/keys/types.go | 56 +++++++--- crypto/keys/types_test.go | 2 +- server/init_test.go | 4 +- x/auth/ante/sigverify.go | 5 +- 21 files changed, 418 insertions(+), 200 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e2b582c6180..4d2142e26abf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -101,7 +101,16 @@ if the provided arguments are invalid. * (modules) [\#5299](https://github.com/cosmos/cosmos-sdk/pull/5299) `HandleDoubleSign` along with params `MaxEvidenceAge` and `DoubleSignJailEndTime` have moved from the `x/slashing` module to the `x/evidence` module. * (keys) [\#4941](https://github.com/cosmos/cosmos-sdk/issues/4941) Initializing a new keybase through `NewKeyringFromHomeFlag`, `NewKeyringFromDir`, `NewKeyBaseFromHomeFlag`, `NewKeyBaseFromDir`, or `NewInMemory` functions now accept optional parameters of type `KeybaseOption`. These optional parameters are also added on the keys subcommands functions, which are now public, and allows these options to be set on the commands or ignored to default to previous behavior. - * The option introduced in this PR is `WithKeygenFunc` which allows a custom bytes to key implementation to be defined when keys are created. +* [\#5439](https://github.com/cosmos/cosmos-sdk/pull/5439) Further modularization was done to the `keybase` + package to make it more suitable for use with different key formats and algorithms: + * The `WithKeygenFunc` function added as a `KeybaseOption` which allows a custom bytes to key + implementation to be defined when keys are created. + * The `WithDeriveFunc` function added as a `KeybaseOption` allows custom logic for deriving a key + from a mnemonic, bip39 password, and HD Path. + * BIP44 is no longer build into `keybase.CreateAccount()`. It is however the default when using + the `client/keys` add command. + * `SupportedAlgos` and `SupportedAlgosLedger` functions return a slice of `SigningAlgo`s that are + supported by the keybase and the ledger integration respectively. * (simapp) [\#5419](https://github.com/cosmos/cosmos-sdk/pull/5419) simapp/helpers.GenTx() now accepts a gas argument. * (baseapp) [\#5455](https://github.com/cosmos/cosmos-sdk/issues/5455) An `sdk.Context` is passed into the `router.Route()` function. @@ -177,10 +186,13 @@ that allows for arbitrary vesting periods. * `IncrementSequenceDecorator`: Increments the account sequence for each signer to prevent replay attacks. * (cli) [\#5223](https://github.com/cosmos/cosmos-sdk/issues/5223) Cosmos Ledger App v2.0.0 is now supported. The changes are backwards compatible and App v1.5.x is still supported. * (x/staking) [\#5380](https://github.com/cosmos/cosmos-sdk/pull/5380) Introduced ability to store historical info entries in staking keeper, allows applications to introspect specified number of past headers and validator sets - * Introduces new parameter `HistoricalEntries` which allows applications to determine how many recent historical info entries they want to persist in store. Default value is 0. - * Introduces cli commands and rest routes to query historical information at a given height + * Introduces new parameter `HistoricalEntries` which allows applications to determine how many recent historical info entries they want to persist in store. Default value is 0. + * Introduces cli commands and rest routes to query historical information at a given height * (modules) [\#5249](https://github.com/cosmos/cosmos-sdk/pull/5249) Funds are now allowed to be directly sent to the community pool (via the distribution module account). * (keys) [\#4941](https://github.com/cosmos/cosmos-sdk/issues/4941) Introduce keybase option to allow overriding the default private key implementation of a key generated through the `keys add` cli command. +* (keys) [\#5439](https://github.com/cosmos/cosmos-sdk/pull/5439) Flags `--algo` and `--hd-path` are added to + `keys add` command in order to make use of keybase modularized. By default, it uses (0, 0) bip44 + HD path and secp256k1 keys, so is non-breaking. * (types) [\#5447](https://github.com/cosmos/cosmos-sdk/pull/5447) Added `ApproxRoot` function to sdk.Decimal type in order to get the nth root for a decimal number, where n is a positive integer. * An `ApproxSqrt` function was also added for convenience around the common case of n=2. diff --git a/client/keys/add.go b/client/keys/add.go index 47c6d574175b..60f4dfe20060 100644 --- a/client/keys/add.go +++ b/client/keys/add.go @@ -32,6 +32,8 @@ const ( flagIndex = "index" flagMultisig = "multisig" flagNoSort = "nosort" + flagHDPath = "hd-path" + flagKeyAlgo = "algo" // DefaultKeyPass contains the default key password for genesis transactions DefaultKeyPass = "12345678" @@ -71,9 +73,11 @@ the flag --nosort is set. cmd.Flags().Bool(flagRecover, false, "Provide seed phrase to recover existing key instead of creating") cmd.Flags().Bool(flagNoBackup, false, "Don't print out seed phrase (if others are watching the terminal)") cmd.Flags().Bool(flagDryRun, false, "Perform action, but don't add key to local keystore") + cmd.Flags().String(flagHDPath, "", "Manual HD Path derivation (overrides BIP44 config)") cmd.Flags().Uint32(flagAccount, 0, "Account number for HD derivation") cmd.Flags().Uint32(flagIndex, 0, "Address index number for HD derivation") cmd.Flags().Bool(flags.FlagIndentResponse, false, "Add indent to JSON response") + cmd.Flags().String(flagKeyAlgo, string(keys.Secp256k1), "Key signing algorithm to generate keys for") return cmd } @@ -112,6 +116,14 @@ func RunAddCmd(cmd *cobra.Command, args []string, kb keys.Keybase, inBuf *bufio. interactive := viper.GetBool(flagInteractive) showMnemonic := !viper.GetBool(flagNoBackup) + algo := keys.SigningAlgo(viper.GetString(flagKeyAlgo)) + if algo == keys.SigningAlgo("") { + algo = keys.Secp256k1 + } + if !keys.IsSupportedAlgorithm(kb.SupportedAlgos(), algo) { + return keys.ErrUnsupportedSigningAlgo + } + if !viper.GetBool(flagDryRun) { _, err = kb.Get(name) if err == nil { @@ -164,7 +176,7 @@ func RunAddCmd(cmd *cobra.Command, args []string, kb keys.Keybase, inBuf *bufio. if err != nil { return err } - _, err = kb.CreateOffline(name, pk) + _, err = kb.CreateOffline(name, pk, algo) if err != nil { return err } @@ -174,8 +186,26 @@ func RunAddCmd(cmd *cobra.Command, args []string, kb keys.Keybase, inBuf *bufio. account := uint32(viper.GetInt(flagAccount)) index := uint32(viper.GetInt(flagIndex)) + useBIP44 := !viper.IsSet(flagHDPath) + var hdPath string + + if useBIP44 { + hdPath = keys.CreateHDPath(account, index).String() + } else { + hdPath = viper.GetString(flagHDPath) + } + // If we're using ledger, only thing we need is the path and the bech32 prefix. if viper.GetBool(flags.FlagUseLedger) { + + if !useBIP44 { + return errors.New("cannot set custom bip32 path with ledger") + } + + if !keys.IsSupportedAlgorithm(kb.SupportedAlgosLedger(), algo) { + return keys.ErrUnsupportedSigningAlgo + } + bech32PrefixAccAddr := sdk.GetConfig().GetBech32AccountAddrPrefix() info, err := kb.CreateLedger(name, keys.Secp256k1, bech32PrefixAccAddr, account, index) if err != nil { @@ -240,7 +270,7 @@ func RunAddCmd(cmd *cobra.Command, args []string, kb keys.Keybase, inBuf *bufio. } } - info, err := kb.CreateAccount(name, mnemonic, bip39Passphrase, DefaultKeyPass, account, index) + info, err := kb.CreateAccount(name, mnemonic, bip39Passphrase, DefaultKeyPass, hdPath, algo) if err != nil { return err } diff --git a/client/keys/delete_test.go b/client/keys/delete_test.go index 7593b7f010a3..eeafb40baa49 100644 --- a/client/keys/delete_test.go +++ b/client/keys/delete_test.go @@ -9,6 +9,7 @@ import ( "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/crypto/keys" "github.com/cosmos/cosmos-sdk/tests" ) @@ -44,13 +45,13 @@ func Test_runDeleteCmd(t *testing.T) { if runningUnattended { mockIn.Reset("testpass1\ntestpass1\n") } - _, err = kb.CreateAccount(fakeKeyName1, tests.TestMnemonic, "", "", 0, 0) + _, err = kb.CreateAccount(fakeKeyName1, tests.TestMnemonic, "", "", "0", keys.Secp256k1) require.NoError(t, err) if runningUnattended { mockIn.Reset("testpass1\ntestpass1\n") } - _, err = kb.CreateAccount(fakeKeyName2, tests.TestMnemonic, "", "", 0, 1) + _, err = kb.CreateAccount(fakeKeyName2, tests.TestMnemonic, "", "", "1", keys.Secp256k1) require.NoError(t, err) if runningUnattended { diff --git a/client/keys/export_test.go b/client/keys/export_test.go index 1279ae537a74..579cd829d170 100644 --- a/client/keys/export_test.go +++ b/client/keys/export_test.go @@ -7,6 +7,7 @@ import ( "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/crypto/keys" "github.com/cosmos/cosmos-sdk/tests" ) @@ -32,7 +33,7 @@ func Test_runExportCmd(t *testing.T) { if runningUnattended { mockIn.Reset("testpass1\ntestpass1\n") } - _, err = kb.CreateAccount("keyname1", tests.TestMnemonic, "", "123456789", 0, 0) + _, err = kb.CreateAccount("keyname1", tests.TestMnemonic, "", "123456789", "", keys.Secp256k1) require.NoError(t, err) // Now enter password diff --git a/client/keys/list_test.go b/client/keys/list_test.go index 129255fd541b..7ea8b3fb69d1 100644 --- a/client/keys/list_test.go +++ b/client/keys/list_test.go @@ -8,6 +8,7 @@ import ( "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/crypto/keys" "github.com/cosmos/cosmos-sdk/tests" ) @@ -36,7 +37,7 @@ func Test_runListCmd(t *testing.T) { mockIn.Reset("testpass1\ntestpass1\n") } - _, err = kb.CreateAccount("something", tests.TestMnemonic, "", "", 0, 0) + _, err = kb.CreateAccount("something", tests.TestMnemonic, "", "", "", keys.Secp256k1) require.NoError(t, err) defer func() { diff --git a/client/keys/show_test.go b/client/keys/show_test.go index 0483e06d1de3..6e261bd1e740 100644 --- a/client/keys/show_test.go +++ b/client/keys/show_test.go @@ -58,13 +58,13 @@ func Test_runShowCmd(t *testing.T) { if runningUnattended { mockIn.Reset("testpass1\ntestpass1\n") } - _, err = kb.CreateAccount(fakeKeyName1, tests.TestMnemonic, "", "", 0, 0) + _, err = kb.CreateAccount(fakeKeyName1, tests.TestMnemonic, "", "", "0", keys.Secp256k1) require.NoError(t, err) if runningUnattended { mockIn.Reset("testpass1\n") } - _, err = kb.CreateAccount(fakeKeyName2, tests.TestMnemonic, "", "", 0, 1) + _, err = kb.CreateAccount(fakeKeyName2, tests.TestMnemonic, "", "", "1", keys.Secp256k1) require.NoError(t, err) // Now try single key diff --git a/client/keys/update_test.go b/client/keys/update_test.go index 6cfd46d92f38..9d7b46c4aa81 100644 --- a/client/keys/update_test.go +++ b/client/keys/update_test.go @@ -7,6 +7,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/crypto/keys" "github.com/cosmos/cosmos-sdk/tests" ) @@ -38,9 +39,9 @@ func Test_runUpdateCmd(t *testing.T) { kb, err := NewKeyBaseFromHomeFlag() assert.NoError(t, err) - _, err = kb.CreateAccount(fakeKeyName1, tests.TestMnemonic, "", "", 0, 0) + _, err = kb.CreateAccount(fakeKeyName1, tests.TestMnemonic, "", "", "0", keys.Secp256k1) assert.NoError(t, err) - _, err = kb.CreateAccount(fakeKeyName2, tests.TestMnemonic, "", "", 0, 1) + _, err = kb.CreateAccount(fakeKeyName2, tests.TestMnemonic, "", "", "1", keys.Secp256k1) assert.NoError(t, err) // Try again now that we have keys diff --git a/crypto/keys/keybase.go b/crypto/keys/keybase.go index d1b67e914248..d7fdcea400f1 100644 --- a/crypto/keys/keybase.go +++ b/crypto/keys/keybase.go @@ -10,7 +10,6 @@ import ( cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino" dbm "github.com/tendermint/tm-db" - "github.com/cosmos/cosmos-sdk/crypto/keys/hd" "github.com/cosmos/cosmos-sdk/crypto/keys/keyerror" "github.com/cosmos/cosmos-sdk/crypto/keys/mintkey" "github.com/cosmos/cosmos-sdk/types" @@ -57,7 +56,7 @@ const ( var ( // ErrUnsupportedSigningAlgo is raised when the caller tries to use a // different signing scheme than secp256k1. - ErrUnsupportedSigningAlgo = errors.New("unsupported signing algo: only secp256k1 is supported") + ErrUnsupportedSigningAlgo = errors.New("unsupported signing algo") // ErrUnsupportedLanguage is raised when the caller tries to use a // different language than english for creating a mnemonic sentence. @@ -101,18 +100,10 @@ func (kb dbKeybase) CreateMnemonic( // CreateAccount converts a mnemonic to a private key and persists it, encrypted // with the given password. func (kb dbKeybase) CreateAccount( - name, mnemonic, bip39Passwd, encryptPasswd string, account uint32, index uint32, + name, mnemonic, bip39Passwd, encryptPasswd, hdPath string, algo SigningAlgo, ) (Info, error) { - return kb.base.CreateAccount(kb, name, mnemonic, bip39Passwd, encryptPasswd, account, index) -} - -// Derive computes a BIP39 seed from th mnemonic and bip39Passwd. -func (kb dbKeybase) Derive( - name, mnemonic, bip39Passphrase, encryptPasswd string, params hd.BIP44Params, -) (Info, error) { - - return kb.base.Derive(kb, name, mnemonic, bip39Passphrase, encryptPasswd, params) + return kb.base.CreateAccount(kb, name, mnemonic, bip39Passwd, encryptPasswd, hdPath, algo) } // CreateLedger creates a new locally-stored reference to a Ledger keypair. @@ -126,8 +117,8 @@ func (kb dbKeybase) CreateLedger( // CreateOffline creates a new reference to an offline keypair. It returns the // created key info. -func (kb dbKeybase) CreateOffline(name string, pub tmcrypto.PubKey) (Info, error) { - return kb.base.writeOfflineKey(kb, name, pub), nil +func (kb dbKeybase) CreateOffline(name string, pub tmcrypto.PubKey, algo SigningAlgo) (Info, error) { + return kb.base.writeOfflineKey(kb, name, pub, algo), nil } // CreateMulti creates a new reference to a multisig (offline) keypair. It @@ -199,7 +190,7 @@ func (kb dbKeybase) Sign(name, passphrase string, msg []byte) (sig []byte, pub t return } - priv, err = mintkey.UnarmorDecryptPrivKey(i.PrivKeyArmor, passphrase) + priv, _, err = mintkey.UnarmorDecryptPrivKey(i.PrivKeyArmor, passphrase) if err != nil { return nil, nil, err } @@ -238,7 +229,7 @@ func (kb dbKeybase) ExportPrivateKeyObject(name string, passphrase string) (tmcr return nil, err } - priv, err = mintkey.UnarmorDecryptPrivKey(linfo.PrivKeyArmor, passphrase) + priv, _, err = mintkey.UnarmorDecryptPrivKey(linfo.PrivKeyArmor, passphrase) if err != nil { return nil, err } @@ -272,7 +263,7 @@ func (kb dbKeybase) ExportPubKey(name string) (armor string, err error) { return } - return mintkey.ArmorPubKeyBytes(info.GetPubKey().Bytes()), nil + return mintkey.ArmorPubKeyBytes(info.GetPubKey().Bytes(), string(info.GetAlgo())), nil } // ExportPrivKey returns a private key in ASCII armored format. @@ -285,7 +276,12 @@ func (kb dbKeybase) ExportPrivKey(name string, decryptPassphrase string, return "", err } - return mintkey.EncryptArmorPrivKey(priv, encryptPassphrase), nil + info, err := kb.Get(name) + if err != nil { + return "", err + } + + return mintkey.EncryptArmorPrivKey(priv, encryptPassphrase, string(info.GetAlgo())), nil } // ImportPrivKey imports a private key in ASCII armor format. It returns an @@ -296,12 +292,12 @@ func (kb dbKeybase) ImportPrivKey(name string, armor string, passphrase string) return errors.New("Cannot overwrite key " + name) } - privKey, err := mintkey.UnarmorDecryptPrivKey(armor, passphrase) + privKey, algo, err := mintkey.UnarmorDecryptPrivKey(armor, passphrase) if err != nil { return errors.Wrap(err, "couldn't import private key") } - kb.writeLocalKey(name, privKey, passphrase) + kb.writeLocalKey(name, privKey, passphrase, SigningAlgo(algo)) return nil } @@ -329,7 +325,7 @@ func (kb dbKeybase) ImportPubKey(name string, armor string) (err error) { return errors.New("Cannot overwrite data for name " + name) } - pubBytes, err := mintkey.UnarmorPubKeyBytes(armor) + pubBytes, algo, err := mintkey.UnarmorPubKeyBytes(armor) if err != nil { return } @@ -339,7 +335,7 @@ func (kb dbKeybase) ImportPubKey(name string, armor string) (err error) { return } - kb.base.writeOfflineKey(kb, name, pubKey) + kb.base.writeOfflineKey(kb, name, pubKey, SigningAlgo(algo)) return } @@ -355,7 +351,7 @@ func (kb dbKeybase) Delete(name, passphrase string, skipPass bool) error { } if linfo, ok := info.(localInfo); ok && !skipPass { - if _, err = mintkey.UnarmorDecryptPrivKey(linfo.PrivKeyArmor, passphrase); err != nil { + if _, _, err = mintkey.UnarmorDecryptPrivKey(linfo.PrivKeyArmor, passphrase); err != nil { return err } } @@ -382,7 +378,7 @@ func (kb dbKeybase) Update(name, oldpass string, getNewpass func() (string, erro case localInfo: linfo := i - key, err := mintkey.UnarmorDecryptPrivKey(linfo.PrivKeyArmor, oldpass) + key, _, err := mintkey.UnarmorDecryptPrivKey(linfo.PrivKeyArmor, oldpass) if err != nil { return err } @@ -392,7 +388,7 @@ func (kb dbKeybase) Update(name, oldpass string, getNewpass func() (string, erro return err } - kb.writeLocalKey(name, key, newpass) + kb.writeLocalKey(name, key, newpass, i.GetAlgo()) return nil default: @@ -405,13 +401,23 @@ func (kb dbKeybase) CloseDB() { kb.db.Close() } -func (kb dbKeybase) writeLocalKey(name string, priv tmcrypto.PrivKey, passphrase string) Info { +// SupportedAlgos returns a list of supported signing algorithms. +func (kb dbKeybase) SupportedAlgos() []SigningAlgo { + return kb.base.SupportedAlgos() +} + +// SupportedAlgosLedger returns a list of supported ledger signing algorithms. +func (kb dbKeybase) SupportedAlgosLedger() []SigningAlgo { + return kb.base.SupportedAlgosLedger() +} + +func (kb dbKeybase) writeLocalKey(name string, priv tmcrypto.PrivKey, passphrase string, algo SigningAlgo) Info { // encrypt private key using passphrase - privArmor := mintkey.EncryptArmorPrivKey(priv, passphrase) + privArmor := mintkey.EncryptArmorPrivKey(priv, passphrase, string(algo)) // make Info pub := priv.PubKey() - info := newLocalInfo(name, pub, privArmor) + info := newLocalInfo(name, pub, privArmor, algo) kb.writeInfo(name, info) return info diff --git a/crypto/keys/keybase_base.go b/crypto/keys/keybase_base.go index ea3a60bb9b75..3003b08828ce 100644 --- a/crypto/keys/keybase_base.go +++ b/crypto/keys/keybase_base.go @@ -17,7 +17,10 @@ import ( type ( kbOptions struct { - keygenFunc PrivKeyGenFunc + keygenFunc PrivKeyGenFunc + deriveFunc DeriveKeyFunc + supportedAlgos []SigningAlgo + supportedAlgosLedger []SigningAlgo } // baseKeybase is an auxiliary type that groups Keybase storage agnostic features @@ -32,7 +35,7 @@ type ( } writeLocalKeyer interface { - writeLocalKey(name string, priv tmcrypto.PrivKey, passphrase string) Info + writeLocalKey(name string, priv tmcrypto.PrivKey, passphrase string, algo SigningAlgo) Info } infoWriter interface { @@ -47,10 +50,36 @@ func WithKeygenFunc(f PrivKeyGenFunc) KeybaseOption { } } +// WithDeriveFunc applies an overridden key derivation function to generate the private key. +func WithDeriveFunc(f DeriveKeyFunc) KeybaseOption { + return func(o *kbOptions) { + o.deriveFunc = f + } +} + +// WithSupportedAlgos defines the list of accepted SigningAlgos. +func WithSupportedAlgos(algos []SigningAlgo) KeybaseOption { + return func(o *kbOptions) { + o.supportedAlgos = algos + } +} + +// WithSupportedAlgosLedger defines the list of accepted SigningAlgos compatible with Ledger. +func WithSupportedAlgosLedger(algos []SigningAlgo) KeybaseOption { + return func(o *kbOptions) { + o.supportedAlgosLedger = algos + } +} + // newBaseKeybase generates the base keybase with defaulting to tendermint SECP256K1 key type func newBaseKeybase(optionsFns ...KeybaseOption) baseKeybase { // Default options for keybase - options := kbOptions{keygenFunc: baseSecpPrivKeyGen} + options := kbOptions{ + keygenFunc: StdPrivKeyGen, + deriveFunc: StdDeriveKey, + supportedAlgos: []SigningAlgo{Secp256k1}, + supportedAlgosLedger: []SigningAlgo{Secp256k1}, + } for _, optionFn := range optionsFns { optionFn(&options) @@ -59,9 +88,20 @@ func newBaseKeybase(optionsFns ...KeybaseOption) baseKeybase { return baseKeybase{options: options} } -// baseSecpPrivKeyGen generates a secp256k1 private key from the given bytes -func baseSecpPrivKeyGen(bz [32]byte) tmcrypto.PrivKey { - return secp256k1.PrivKeySecp256k1(bz) +// StdPrivKeyGen is the default PrivKeyGen function in the keybase. +// For now, it only supports Secp256k1 +func StdPrivKeyGen(bz []byte, algo SigningAlgo) (tmcrypto.PrivKey, error) { + if algo == Secp256k1 { + return SecpPrivKeyGen(bz), nil + } + return nil, ErrUnsupportedSigningAlgo +} + +// SecpPrivKeyGen generates a secp256k1 private key from the given bytes +func SecpPrivKeyGen(bz []byte) tmcrypto.PrivKey { + var bzArr [32]byte + copy(bzArr[:], bz) + return secp256k1.PrivKeySecp256k1(bzArr) } // SignWithLedger signs a binary message with the ledger device referenced by an Info object @@ -111,29 +151,26 @@ func (kb baseKeybase) DecodeSignature(info Info, msg []byte) (sig []byte, pub tm // CreateAccount creates an account Info object. func (kb baseKeybase) CreateAccount( - keyWriter keyWriter, name, mnemonic, bip39Passwd, encryptPasswd string, account, index uint32, -) (Info, error) { - - hdPath := CreateHDPath(account, index) - return kb.Derive(keyWriter, name, mnemonic, bip39Passwd, encryptPasswd, *hdPath) -} - -func (kb baseKeybase) persistDerivedKey( - keyWriter keyWriter, seed []byte, passwd, name, fullHdPath string, + keyWriter keyWriter, name, mnemonic, bip39Passphrase, encryptPasswd, hdPath string, algo SigningAlgo, ) (Info, error) { // create master key and derive first key for keyring - derivedPriv, err := ComputeDerivedKey(seed, fullHdPath) + derivedPriv, err := kb.options.deriveFunc(mnemonic, bip39Passphrase, hdPath, algo) + if err != nil { + return nil, err + } + + privKey, err := kb.options.keygenFunc(derivedPriv, algo) if err != nil { return nil, err } var info Info - if passwd != "" { - info = keyWriter.writeLocalKey(name, kb.options.keygenFunc(derivedPriv), passwd) + if encryptPasswd != "" { + info = keyWriter.writeLocalKey(name, privKey, encryptPasswd, algo) } else { - info = kb.writeOfflineKey(keyWriter, name, kb.options.keygenFunc(derivedPriv).PubKey()) + info = kb.writeOfflineKey(keyWriter, name, privKey.PubKey(), algo) } return info, nil @@ -145,7 +182,7 @@ func (kb baseKeybase) CreateLedger( w infoWriter, name string, algo SigningAlgo, hrp string, account, index uint32, ) (Info, error) { - if !IsAlgoSupported(algo) { + if !IsSupportedAlgorithm(kb.SupportedAlgosLedger(), algo) { return nil, ErrUnsupportedSigningAlgo } @@ -157,7 +194,7 @@ func (kb baseKeybase) CreateLedger( return nil, err } - return kb.writeLedgerKey(w, name, priv.PubKey(), *hdPath), nil + return kb.writeLedgerKey(w, name, priv.PubKey(), *hdPath, algo), nil } // CreateMnemonic generates a new key with the given algorithm and language pair. @@ -169,7 +206,7 @@ func (kb baseKeybase) CreateMnemonic( return nil, "", ErrUnsupportedLanguage } - if !IsAlgoSupported(algo) { + if !IsSupportedAlgorithm(kb.SupportedAlgos(), algo) { return nil, "", ErrUnsupportedSigningAlgo } @@ -185,37 +222,22 @@ func (kb baseKeybase) CreateMnemonic( return nil, "", err } - info, err = kb.persistDerivedKey( - keyWriter, - bip39.NewSeed(mnemonic, DefaultBIP39Passphrase), passwd, - name, types.GetConfig().GetFullFundraiserPath(), - ) - - return info, mnemonic, err -} - -// Derive computes a BIP39 seed from the mnemonic and bip39Passphrase. It creates -// a private key from the seed using the BIP44 params. -func (kb baseKeybase) Derive( - keyWriter keyWriter, name, mnemonic, bip39Passphrase, encryptPasswd string, params hd.BIP44Params, // nolint:interfacer -) (Info, error) { - - seed, err := bip39.NewSeedWithErrorChecking(mnemonic, bip39Passphrase) + info, err = kb.CreateAccount(keyWriter, name, mnemonic, DefaultBIP39Passphrase, passwd, types.GetConfig().GetFullFundraiserPath(), algo) if err != nil { - return nil, err + return nil, "", err } - return kb.persistDerivedKey(keyWriter, seed, encryptPasswd, name, params.String()) + return info, mnemonic, err } -func (kb baseKeybase) writeLedgerKey(w infoWriter, name string, pub tmcrypto.PubKey, path hd.BIP44Params) Info { - info := newLedgerInfo(name, pub, path) +func (kb baseKeybase) writeLedgerKey(w infoWriter, name string, pub tmcrypto.PubKey, path hd.BIP44Params, algo SigningAlgo) Info { + info := newLedgerInfo(name, pub, path, algo) w.writeInfo(name, info) return info } -func (kb baseKeybase) writeOfflineKey(w infoWriter, name string, pub tmcrypto.PubKey) Info { - info := newOfflineInfo(name, pub) +func (kb baseKeybase) writeOfflineKey(w infoWriter, name string, pub tmcrypto.PubKey, algo SigningAlgo) Info { + info := newOfflineInfo(name, pub, algo) w.writeInfo(name, info) return info } @@ -226,10 +248,28 @@ func (kb baseKeybase) writeMultisigKey(w infoWriter, name string, pub tmcrypto.P return info } -// ComputeDerivedKey derives and returns the private key for the given seed and HD path. -func ComputeDerivedKey(seed []byte, fullHdPath string) ([32]byte, error) { +// StdDeriveKey is the default DeriveKey function in the keybase. +// For now, it only supports Secp256k1 +func StdDeriveKey(mnemonic string, bip39Passphrase, hdPath string, algo SigningAlgo) ([]byte, error) { + if algo == Secp256k1 { + return SecpDeriveKey(mnemonic, bip39Passphrase, hdPath) + } + return nil, ErrUnsupportedSigningAlgo +} + +// SecpDeriveKey derives and returns the secp256k1 private key for the given seed and HD path. +func SecpDeriveKey(mnemonic string, bip39Passphrase, hdPath string) ([]byte, error) { + seed, err := bip39.NewSeedWithErrorChecking(mnemonic, bip39Passphrase) + if err != nil { + return nil, err + } + masterPriv, ch := hd.ComputeMastersFromSeed(seed) - return hd.DerivePrivateKeyForPath(masterPriv, ch, fullHdPath) + if len(hdPath) == 0 { + return masterPriv[:], nil + } + derivedKey, err := hd.DerivePrivateKeyForPath(masterPriv, ch, hdPath) + return derivedKey[:], err } // CreateHDPath returns BIP 44 object from account and index parameters. @@ -237,9 +277,22 @@ func CreateHDPath(account uint32, index uint32) *hd.BIP44Params { return hd.NewFundraiserParams(account, types.GetConfig().GetCoinType(), index) } -// IsAlgoSupported returns whether the signing algorithm is supported. -// -// TODO: Refactor this to be configurable to support interchangeable key signing -// and addressing. -// Ref: https://github.com/cosmos/cosmos-sdk/issues/4941 -func IsAlgoSupported(algo SigningAlgo) bool { return algo == Secp256k1 } +// SupportedAlgos returns a list of supported signing algorithms. +func (kb baseKeybase) SupportedAlgos() []SigningAlgo { + return kb.options.supportedAlgos +} + +// SupportedAlgosLedger returns a list of supported ledger signing algorithms. +func (kb baseKeybase) SupportedAlgosLedger() []SigningAlgo { + return kb.options.supportedAlgosLedger +} + +// IsSupportedAlgorithm returns whether the signing algorithm is in the passed-in list of supported algorithms. +func IsSupportedAlgorithm(supported []SigningAlgo, algo SigningAlgo) bool { + for _, supportedAlgo := range supported { + if algo == supportedAlgo { + return true + } + } + return false +} diff --git a/crypto/keys/keybase_test.go b/crypto/keys/keybase_test.go index a1dfa1c7e75e..0c2396afbf9c 100644 --- a/crypto/keys/keybase_test.go +++ b/crypto/keys/keybase_test.go @@ -38,25 +38,43 @@ func TestCreateAccountInvalidMnemonic(t *testing.T) { _, err := kb.CreateAccount( "some_account", "malarkey pair crucial catch public canyon evil outer stage ten gym tornado", - "", "", 0, 1) + "", "", CreateHDPath(0, 0).String(), Secp256k1) assert.Error(t, err) assert.Equal(t, "Invalid mnemonic", err.Error()) } func TestCreateLedgerUnsupportedAlgo(t *testing.T) { kb := NewInMemory() + + supportedLedgerAlgos := kb.SupportedAlgosLedger() + for _, supportedAlgo := range supportedLedgerAlgos { + if Ed25519 == supportedAlgo { + assert.FailNow(t, "Was not an unsupported algorithm") + } + } + _, err := kb.CreateLedger("some_account", Ed25519, "cosmos", 0, 1) assert.Error(t, err) - assert.Equal(t, "unsupported signing algo: only secp256k1 is supported", err.Error()) + assert.Equal(t, "unsupported signing algo", err.Error()) } func TestCreateLedger(t *testing.T) { - kb := NewInMemory() + kb := NewInMemory(WithSupportedAlgosLedger([]SigningAlgo{Secp256k1, Ed25519})) // test_cover and test_unit will result in different answers // test_cover does not compile some dependencies so ledger is disabled // test_unit may add a ledger mock // both cases are acceptable + supportedLedgerAlgos := kb.SupportedAlgosLedger() + secpSupported := false + edSupported := false + for _, supportedAlgo := range supportedLedgerAlgos { + secpSupported = secpSupported || (supportedAlgo == Secp256k1) + edSupported = edSupported || (supportedAlgo == Ed25519) + } + assert.True(t, secpSupported) + assert.True(t, edSupported) + ledger, err := kb.CreateLedger("some_account", Secp256k1, "cosmos", 3, 1) if err != nil { @@ -92,7 +110,21 @@ func TestCreateLedger(t *testing.T) { // TestKeyManagement makes sure we can manipulate these keys well func TestKeyManagement(t *testing.T) { // make the storage with reasonable defaults - cstore := NewInMemory() + cstore := NewInMemory(WithSupportedAlgos([]SigningAlgo{Secp256k1, Sr25519})) + + // Test modified supported algos + supportedAlgos := cstore.SupportedAlgos() + secpSupported := false + edSupported := false + srSupported := false + for _, supportedAlgo := range supportedAlgos { + secpSupported = secpSupported || (supportedAlgo == Secp256k1) + edSupported = edSupported || (supportedAlgo == Ed25519) + srSupported = srSupported || (supportedAlgo == Sr25519) + } + assert.True(t, secpSupported) + assert.False(t, edSupported) + assert.True(t, srSupported) algo := Secp256k1 n1, n2, n3 := "personal", "business", "other" @@ -152,10 +184,12 @@ func TestKeyManagement(t *testing.T) { o1 := "offline" priv1 := ed25519.GenPrivKey() pub1 := priv1.PubKey() - i, err = cstore.CreateOffline(o1, pub1) + i, err = cstore.CreateOffline(o1, pub1, algo) require.Nil(t, err) require.Equal(t, pub1, i.GetPubKey()) require.Equal(t, o1, i.GetName()) + iOffline := i.(*offlineInfo) + require.Equal(t, algo, iOffline.GetAlgo()) keyS, err = cstore.List() require.NoError(t, err) require.Equal(t, 2, len(keyS)) @@ -393,7 +427,8 @@ func TestSeedPhrase(t *testing.T) { // let us re-create it from the mnemonic-phrase params := *hd.NewFundraiserParams(0, sdk.CoinType, 0) - newInfo, err := cstore.Derive(n2, mnemonic, DefaultBIP39Passphrase, p2, params) + hdPath := params.String() + newInfo, err := cstore.CreateAccount(n2, mnemonic, DefaultBIP39Passphrase, p2, hdPath, Secp256k1) require.NoError(t, err) require.Equal(t, n2, newInfo.GetName()) require.Equal(t, info.GetPubKey().Address(), newInfo.GetPubKey().Address()) @@ -402,7 +437,11 @@ func TestSeedPhrase(t *testing.T) { func ExampleNew() { // Select the encryption and storage for your cryptostore - customKeyGenFunc := func(bz [32]byte) crypto.PrivKey { return secp256k1.PrivKeySecp256k1(bz) } + customKeyGenFunc := func(bz []byte, algo SigningAlgo) (crypto.PrivKey, error) { + var bzArr [32]byte + copy(bzArr[:], bz) + return secp256k1.PrivKeySecp256k1(bzArr), nil + } cstore := NewInMemory(WithKeygenFunc(customKeyGenFunc)) sec := Secp256k1 diff --git a/crypto/keys/keyring.go b/crypto/keys/keyring.go index 842db588c30f..8b82df377001 100644 --- a/crypto/keys/keyring.go +++ b/crypto/keys/keyring.go @@ -20,7 +20,6 @@ import ( cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino" "github.com/cosmos/cosmos-sdk/client/input" - "github.com/cosmos/cosmos-sdk/crypto/keys/hd" "github.com/cosmos/cosmos-sdk/crypto/keys/keyerror" "github.com/cosmos/cosmos-sdk/crypto/keys/mintkey" "github.com/cosmos/cosmos-sdk/types" @@ -90,19 +89,10 @@ func (kb keyringKeybase) CreateMnemonic( // CreateAccount converts a mnemonic to a private key and persists it, encrypted // with the given password. func (kb keyringKeybase) CreateAccount( - name, mnemonic, bip39Passwd, encryptPasswd string, account, index uint32, + name, mnemonic, bip39Passwd, encryptPasswd, hdPath string, algo SigningAlgo, ) (Info, error) { - return kb.base.CreateAccount(kb, name, mnemonic, bip39Passwd, encryptPasswd, account, index) -} - -// Derive computes a BIP39 seed from th mnemonic and bip39Passphrase. It creates -// a private key from the seed using the BIP44 params. -func (kb keyringKeybase) Derive( - name, mnemonic, bip39Passphrase, encryptPasswd string, params hd.BIP44Params, -) (info Info, err error) { - - return kb.base.Derive(kb, name, mnemonic, bip39Passphrase, encryptPasswd, params) + return kb.base.CreateAccount(kb, name, mnemonic, bip39Passwd, encryptPasswd, hdPath, algo) } // CreateLedger creates a new locally-stored reference to a Ledger keypair. @@ -116,8 +106,8 @@ func (kb keyringKeybase) CreateLedger( // CreateOffline creates a new reference to an offline keypair. It returns the // created key info. -func (kb keyringKeybase) CreateOffline(name string, pub tmcrypto.PubKey) (Info, error) { - return kb.base.writeOfflineKey(kb, name, pub), nil +func (kb keyringKeybase) CreateOffline(name string, pub tmcrypto.PubKey, algo SigningAlgo) (Info, error) { + return kb.base.writeOfflineKey(kb, name, pub, algo), nil } // CreateMulti creates a new reference to a multisig (offline) keypair. It @@ -284,7 +274,7 @@ func (kb keyringKeybase) ExportPubKey(name string) (armor string, err error) { return "", fmt.Errorf("no key to export with name: %s", name) } - return mintkey.ArmorPubKeyBytes(bz.GetPubKey().Bytes()), nil + return mintkey.ArmorPubKeyBytes(bz.GetPubKey().Bytes(), string(bz.GetAlgo())), nil } // Import imports armored private key. @@ -330,7 +320,12 @@ func (kb keyringKeybase) ExportPrivKey(name, decryptPassphrase, encryptPassphras return "", err } - return mintkey.EncryptArmorPrivKey(priv, encryptPassphrase), nil + info, err := kb.Get(name) + if err != nil { + return "", err + } + + return mintkey.EncryptArmorPrivKey(priv, encryptPassphrase, string(info.GetAlgo())), nil } // ImportPrivKey imports a private key in ASCII armor format. An error is returned @@ -341,13 +336,13 @@ func (kb keyringKeybase) ImportPrivKey(name, armor, passphrase string) error { return fmt.Errorf("cannot overwrite key: %s", name) } - privKey, err := mintkey.UnarmorDecryptPrivKey(armor, passphrase) + privKey, algo, err := mintkey.UnarmorDecryptPrivKey(armor, passphrase) if err != nil { return errors.Wrap(err, "failed to decrypt private key") } // NOTE: The keyring keystore has no need for a passphrase. - kb.writeLocalKey(name, privKey, "") + kb.writeLocalKey(name, privKey, "", SigningAlgo(algo)) return nil } @@ -370,7 +365,7 @@ func (kb keyringKeybase) ImportPubKey(name string, armor string) error { } } - pubBytes, err := mintkey.UnarmorPubKeyBytes(armor) + pubBytes, algo, err := mintkey.UnarmorPubKeyBytes(armor) if err != nil { return err } @@ -380,7 +375,7 @@ func (kb keyringKeybase) ImportPubKey(name string, armor string) error { return err } - kb.base.writeOfflineKey(kb, name, pubKey) + kb.base.writeOfflineKey(kb, name, pubKey, SigningAlgo(algo)) return nil } @@ -419,7 +414,7 @@ func (kb keyringKeybase) Update(name, oldpass string, getNewpass func() (string, switch linfo := info.(type) { case localInfo: - key, err := mintkey.UnarmorDecryptPrivKey(linfo.PrivKeyArmor, oldpass) + key, _, err := mintkey.UnarmorDecryptPrivKey(linfo.PrivKeyArmor, oldpass) if err != nil { return err } @@ -429,7 +424,7 @@ func (kb keyringKeybase) Update(name, oldpass string, getNewpass func() (string, return err } - kb.writeLocalKey(name, key, newpass) + kb.writeLocalKey(name, key, newpass, linfo.GetAlgo()) return nil default: @@ -437,13 +432,23 @@ func (kb keyringKeybase) Update(name, oldpass string, getNewpass func() (string, } } +// SupportedAlgos returns a list of supported signing algorithms. +func (kb keyringKeybase) SupportedAlgos() []SigningAlgo { + return kb.base.SupportedAlgos() +} + +// SupportedAlgosLedger returns a list of supported ledger signing algorithms. +func (kb keyringKeybase) SupportedAlgosLedger() []SigningAlgo { + return kb.base.SupportedAlgosLedger() +} + // CloseDB releases the lock and closes the storage backend. func (kb keyringKeybase) CloseDB() {} -func (kb keyringKeybase) writeLocalKey(name string, priv tmcrypto.PrivKey, _ string) Info { +func (kb keyringKeybase) writeLocalKey(name string, priv tmcrypto.PrivKey, _ string, algo SigningAlgo) Info { // encrypt private key using keyring pub := priv.PubKey() - info := newLocalInfo(name, pub, string(priv.Bytes())) + info := newLocalInfo(name, pub, string(priv.Bytes()), algo) kb.writeInfo(name, info) return info diff --git a/crypto/keys/keyring_test.go b/crypto/keys/keyring_test.go index 84cfe3816f34..1149a2691c09 100644 --- a/crypto/keys/keyring_test.go +++ b/crypto/keys/keyring_test.go @@ -79,7 +79,7 @@ func TestLazyKeyManagementKeyRing(t *testing.T) { o1 := "offline" priv1 := ed25519.GenPrivKey() pub1 := priv1.PubKey() - i, err = kb.CreateOffline(o1, pub1) + i, err = kb.CreateOffline(o1, pub1, Ed25519) require.Nil(t, err) require.Equal(t, pub1, i.GetPubKey()) require.Equal(t, o1, i.GetName()) @@ -209,10 +209,11 @@ func TestLazyExportImportPubKeyKeyRing(t *testing.T) { defer cleanup() kb, err := NewTestKeyring("keybasename", dir) require.NoError(t, err) + algo := Secp256k1 // CreateMnemonic a private-public key pair and ensure consistency notPasswd := "n9y25ah7" - info, _, err := kb.CreateMnemonic("john", English, notPasswd, Secp256k1) + info, _, err := kb.CreateMnemonic("john", English, notPasswd, algo) require.Nil(t, err) require.NotEqual(t, info, "") require.Equal(t, info.GetName(), "john") @@ -318,7 +319,8 @@ func TestLazySeedPhraseKeyRing(t *testing.T) { // let us re-create it from the mnemonic-phrase params := *hd.NewFundraiserParams(0, sdk.CoinType, 0) - newInfo, err := kb.Derive(n2, mnemonic, DefaultBIP39Passphrase, p2, params) + hdPath := params.String() + newInfo, err := kb.CreateAccount(n2, mnemonic, DefaultBIP39Passphrase, p2, hdPath, Secp256k1) require.NoError(t, err) require.Equal(t, n2, newInfo.GetName()) require.Equal(t, info.GetPubKey().Address(), newInfo.GetPubKey().Address()) diff --git a/crypto/keys/keys.go b/crypto/keys/keys.go index 58a58a95be04..af5590814b49 100644 --- a/crypto/keys/keys.go +++ b/crypto/keys/keys.go @@ -4,9 +4,13 @@ package keys type SigningAlgo string const ( + // MultiAlgo implies that a pubkey is a multisignature + MultiAlgo = SigningAlgo("multi") // Secp256k1 uses the Bitcoin secp256k1 ECDSA parameters. Secp256k1 = SigningAlgo("secp256k1") // Ed25519 represents the Ed25519 signature system. // It is currently not supported for end-user keys (wallets/ledgers). Ed25519 = SigningAlgo("ed25519") + // Sr25519 represents the Sr25519 signature system. + Sr25519 = SigningAlgo("sr25519") ) diff --git a/crypto/keys/lazy_keybase.go b/crypto/keys/lazy_keybase.go index 0c9b61c8588d..db0042732a4b 100644 --- a/crypto/keys/lazy_keybase.go +++ b/crypto/keys/lazy_keybase.go @@ -6,7 +6,6 @@ import ( "github.com/tendermint/tendermint/crypto" cmn "github.com/tendermint/tendermint/libs/common" - "github.com/cosmos/cosmos-sdk/crypto/keys/hd" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -88,7 +87,7 @@ func (lkb lazyKeybase) CreateMnemonic(name string, language Language, passwd str return newDBKeybase(db, lkb.options...).CreateMnemonic(name, language, passwd, algo) } -func (lkb lazyKeybase) CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd string, account uint32, index uint32) (Info, error) { +func (lkb lazyKeybase) CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd, hdPath string, algo SigningAlgo) (Info, error) { db, err := sdk.NewLevelDB(lkb.name, lkb.dir) if err != nil { return nil, err @@ -96,17 +95,7 @@ func (lkb lazyKeybase) CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd defer db.Close() return newDBKeybase(db, - lkb.options...).CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd, account, index) -} - -func (lkb lazyKeybase) Derive(name, mnemonic, bip39Passwd, encryptPasswd string, params hd.BIP44Params) (Info, error) { - db, err := sdk.NewLevelDB(lkb.name, lkb.dir) - if err != nil { - return nil, err - } - defer db.Close() - - return newDBKeybase(db, lkb.options...).Derive(name, mnemonic, bip39Passwd, encryptPasswd, params) + lkb.options...).CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd, hdPath, algo) } func (lkb lazyKeybase) CreateLedger(name string, algo SigningAlgo, hrp string, account, index uint32) (info Info, err error) { @@ -119,14 +108,14 @@ func (lkb lazyKeybase) CreateLedger(name string, algo SigningAlgo, hrp string, a return newDBKeybase(db, lkb.options...).CreateLedger(name, algo, hrp, account, index) } -func (lkb lazyKeybase) CreateOffline(name string, pubkey crypto.PubKey) (info Info, err error) { +func (lkb lazyKeybase) CreateOffline(name string, pubkey crypto.PubKey, algo SigningAlgo) (info Info, err error) { db, err := sdk.NewLevelDB(lkb.name, lkb.dir) if err != nil { return nil, err } defer db.Close() - return newDBKeybase(db, lkb.options...).CreateOffline(name, pubkey) + return newDBKeybase(db, lkb.options...).CreateOffline(name, pubkey, algo) } func (lkb lazyKeybase) CreateMulti(name string, pubkey crypto.PubKey) (info Info, err error) { @@ -221,4 +210,14 @@ func (lkb lazyKeybase) ExportPrivKey(name string, decryptPassphrase string, return newDBKeybase(db, lkb.options...).ExportPrivKey(name, decryptPassphrase, encryptPassphrase) } +// SupportedAlgos returns a list of supported signing algorithms. +func (lkb lazyKeybase) SupportedAlgos() []SigningAlgo { + return newBaseKeybase(lkb.options...).SupportedAlgos() +} + +// SupportedAlgosLedger returns a list of supported ledger signing algorithms. +func (lkb lazyKeybase) SupportedAlgosLedger() []SigningAlgo { + return newBaseKeybase(lkb.options...).SupportedAlgosLedger() +} + func (lkb lazyKeybase) CloseDB() {} diff --git a/crypto/keys/lazy_keybase_test.go b/crypto/keys/lazy_keybase_test.go index 31a9cf242f72..1b5991dae724 100644 --- a/crypto/keys/lazy_keybase_test.go +++ b/crypto/keys/lazy_keybase_test.go @@ -89,7 +89,7 @@ func TestLazyKeyManagement(t *testing.T) { o1 := "offline" priv1 := ed25519.GenPrivKey() pub1 := priv1.PubKey() - i, err = kb.CreateOffline(o1, pub1) + i, err = kb.CreateOffline(o1, pub1, algo) require.Nil(t, err) require.Equal(t, pub1, i.GetPubKey()) require.Equal(t, o1, i.GetName()) @@ -245,10 +245,11 @@ func TestLazyExportImportPubKey(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) defer cleanup() kb := New("keybasename", dir) + algo := Secp256k1 // CreateMnemonic a private-public key pair and ensure consistency notPasswd := "n9y25ah7" - info, _, err := kb.CreateMnemonic("john", English, notPasswd, Secp256k1) + info, _, err := kb.CreateMnemonic("john", English, notPasswd, algo) require.Nil(t, err) require.NotEqual(t, info, "") require.Equal(t, info.GetName(), "john") @@ -368,7 +369,8 @@ func TestLazySeedPhrase(t *testing.T) { // let us re-create it from the mnemonic-phrase params := *hd.NewFundraiserParams(0, sdk.CoinType, 0) - newInfo, err := kb.Derive(n2, mnemonic, DefaultBIP39Passphrase, p2, params) + hdPath := params.String() + newInfo, err := kb.CreateAccount(n2, mnemonic, DefaultBIP39Passphrase, p2, hdPath, algo) require.NoError(t, err) require.Equal(t, n2, newInfo.GetName()) require.Equal(t, info.GetPubKey().Address(), newInfo.GetPubKey().Address()) @@ -421,9 +423,9 @@ func TestKeygenOverride(t *testing.T) { CryptoCdc = testCdc overrideCalled := false - dummyFunc := func(bz [32]byte) crypto.PrivKey { + dummyFunc := func(bz []byte, algo SigningAlgo) (crypto.PrivKey, error) { overrideCalled = true - return testPriv(bz[:]) + return testPriv(bz[:]), nil } kb := New("keybasename", dir, WithKeygenFunc(dummyFunc)) diff --git a/crypto/keys/mintkey/mintkey.go b/crypto/keys/mintkey/mintkey.go index 6b3a3af8ad4a..585d148c924e 100644 --- a/crypto/keys/mintkey/mintkey.go +++ b/crypto/keys/mintkey/mintkey.go @@ -20,6 +20,11 @@ const ( blockTypePrivKey = "TENDERMINT PRIVATE KEY" blockTypeKeyInfo = "TENDERMINT KEY INFO" blockTypePubKey = "TENDERMINT PUBLIC KEY" + + defaultAlgo = "secp256k1" + + headerVersion = "version" + headerType = "type" ) // Make bcrypt security parameter var, so it can be changed within the lcd test @@ -42,36 +47,58 @@ var BcryptSecurityParameter = 12 // Armor the InfoBytes func ArmorInfoBytes(bz []byte) string { - return armorBytes(bz, blockTypeKeyInfo) + header := map[string]string{ + headerType: "Info", + headerVersion: "0.0.0", + } + return armor.EncodeArmor(blockTypeKeyInfo, header, bz) } // Armor the PubKeyBytes -func ArmorPubKeyBytes(bz []byte) string { - return armorBytes(bz, blockTypePubKey) -} - -func armorBytes(bz []byte, blockType string) string { +func ArmorPubKeyBytes(bz []byte, algo string) string { header := map[string]string{ - "type": "Info", - "version": "0.0.0", + headerVersion: "0.0.1", + } + if algo != "" { + header[headerType] = algo } - return armor.EncodeArmor(blockType, header, bz) + return armor.EncodeArmor(blockTypePubKey, header, bz) } //----------------------------------------------------------------- // remove armor // Unarmor the InfoBytes -func UnarmorInfoBytes(armorStr string) (bz []byte, err error) { - return unarmorBytes(armorStr, blockTypeKeyInfo) +func UnarmorInfoBytes(armorStr string) ([]byte, error) { + bz, header, err := unarmorBytes(armorStr, blockTypeKeyInfo) + if err != nil { + return nil, err + } + + if header[headerVersion] != "0.0.0" { + return nil, fmt.Errorf("unrecognized version: %v", header[headerVersion]) + } + return bz, nil } -// Unarmor the PubKeyBytes -func UnarmorPubKeyBytes(armorStr string) (bz []byte, err error) { - return unarmorBytes(armorStr, blockTypePubKey) +// UnarmorPubKeyBytes returns the pubkey byte slice, a string of the algo type, and an error +func UnarmorPubKeyBytes(armorStr string) (bz []byte, algo string, err error) { + bz, header, err := unarmorBytes(armorStr, blockTypePubKey) + switch header[headerVersion] { + case "0.0.0": + return bz, defaultAlgo, err + case "0.0.1": + if header[headerType] == "" { + header[headerType] = defaultAlgo + } + return bz, header[headerType], err + default: + err = fmt.Errorf("unrecognized version: %v", header[headerVersion]) + return nil, "", err + } } -func unarmorBytes(armorStr, blockType string) (bz []byte, err error) { +func unarmorBytes(armorStr, blockType string) (bz []byte, header map[string]string, err error) { bType, header, bz, err := armor.DecodeArmor(armorStr) if err != nil { return @@ -80,10 +107,6 @@ func unarmorBytes(armorStr, blockType string) (bz []byte, err error) { err = fmt.Errorf("unrecognized armor type %q, expected: %q", bType, blockType) return } - if header["version"] != "0.0.0" { - err = fmt.Errorf("unrecognized version: %v", header["version"]) - return - } return } @@ -91,12 +114,15 @@ func unarmorBytes(armorStr, blockType string) (bz []byte, err error) { // encrypt/decrypt with armor // Encrypt and armor the private key. -func EncryptArmorPrivKey(privKey crypto.PrivKey, passphrase string) string { +func EncryptArmorPrivKey(privKey crypto.PrivKey, passphrase string, algo string) string { saltBytes, encBytes := encryptPrivKey(privKey, passphrase) header := map[string]string{ "kdf": "bcrypt", "salt": fmt.Sprintf("%X", saltBytes), } + if algo != "" { + header[headerType] = algo + } armorStr := armor.EncodeArmor(blockTypePrivKey, header, encBytes) return armorStr } @@ -115,28 +141,31 @@ func encryptPrivKey(privKey crypto.PrivKey, passphrase string) (saltBytes []byte return saltBytes, xsalsa20symmetric.EncryptSymmetric(privKeyBytes, key) } -// Unarmor and decrypt the private key. -func UnarmorDecryptPrivKey(armorStr string, passphrase string) (crypto.PrivKey, error) { - var privKey crypto.PrivKey +// UnarmorDecryptPrivKey returns the privkey byte slice, a string of the algo type, and an error +func UnarmorDecryptPrivKey(armorStr string, passphrase string) (privKey crypto.PrivKey, algo string, err error) { blockType, header, encBytes, err := armor.DecodeArmor(armorStr) if err != nil { - return privKey, err + return privKey, "", err } if blockType != blockTypePrivKey { - return privKey, fmt.Errorf("unrecognized armor type: %v", blockType) + return privKey, "", fmt.Errorf("unrecognized armor type: %v", blockType) } if header["kdf"] != "bcrypt" { - return privKey, fmt.Errorf("unrecognized KDF type: %v", header["KDF"]) + return privKey, "", fmt.Errorf("unrecognized KDF type: %v", header["KDF"]) } if header["salt"] == "" { - return privKey, fmt.Errorf("missing salt bytes") + return privKey, "", fmt.Errorf("missing salt bytes") } saltBytes, err := hex.DecodeString(header["salt"]) if err != nil { - return privKey, fmt.Errorf("error decoding salt: %v", err.Error()) + return privKey, "", fmt.Errorf("error decoding salt: %v", err.Error()) } privKey, err = decryptPrivKey(saltBytes, encBytes, passphrase) - return privKey, err + + if header[headerType] == "" { + header[headerType] = defaultAlgo + } + return privKey, header[headerType], err } func decryptPrivKey(saltBytes []byte, encBytes []byte, passphrase string) (privKey crypto.PrivKey, err error) { diff --git a/crypto/keys/mintkey/mintkey_test.go b/crypto/keys/mintkey/mintkey_test.go index b4ce4d6a0f20..ef5f77d3372e 100644 --- a/crypto/keys/mintkey/mintkey_test.go +++ b/crypto/keys/mintkey/mintkey_test.go @@ -13,11 +13,12 @@ import ( func TestArmorUnarmorPrivKey(t *testing.T) { priv := secp256k1.GenPrivKey() - armor := mintkey.EncryptArmorPrivKey(priv, "passphrase") - _, err := mintkey.UnarmorDecryptPrivKey(armor, "wrongpassphrase") + armor := mintkey.EncryptArmorPrivKey(priv, "passphrase", "") + _, _, err := mintkey.UnarmorDecryptPrivKey(armor, "wrongpassphrase") require.Error(t, err) - decrypted, err := mintkey.UnarmorDecryptPrivKey(armor, "passphrase") + decrypted, algo, err := mintkey.UnarmorDecryptPrivKey(armor, "passphrase") require.NoError(t, err) + require.Equal(t, string(keys.Secp256k1), algo) require.True(t, priv.Equals(decrypted)) } @@ -28,10 +29,11 @@ func TestArmorUnarmorPubKey(t *testing.T) { // Add keys and see they return in alphabetical order info, _, err := cstore.CreateMnemonic("Bob", keys.English, "passphrase", keys.Secp256k1) require.NoError(t, err) - armor := mintkey.ArmorPubKeyBytes(info.GetPubKey().Bytes()) - pubBytes, err := mintkey.UnarmorPubKeyBytes(armor) + armor := mintkey.ArmorPubKeyBytes(info.GetPubKey().Bytes(), "") + pubBytes, algo, err := mintkey.UnarmorPubKeyBytes(armor) require.NoError(t, err) pub, err := cryptoAmino.PubKeyFromBytes(pubBytes) require.NoError(t, err) + require.Equal(t, string(keys.Secp256k1), algo) require.True(t, pub.Equals(info.GetPubKey())) } diff --git a/crypto/keys/types.go b/crypto/keys/types.go index 739250f98ef8..72fc7ecbc7d6 100644 --- a/crypto/keys/types.go +++ b/crypto/keys/types.go @@ -31,21 +31,15 @@ type Keybase interface { // same name. CreateMnemonic(name string, language Language, passwd string, algo SigningAlgo) (info Info, seed string, err error) - // CreateAccount converts a mnemonic to a private key using a BIP44 path 44'/118'/{account}'/0/{index} + // CreateAccount converts a mnemonic to a private key and BIP 32 HD Path // and persists it, encrypted with the given password. - CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd string, account uint32, index uint32) (Info, error) - - // Derive computes a BIP39 seed from th mnemonic and bip39Passwd. - // Derive private key from the seed using the BIP44 params. - // Encrypt the key to disk using encryptPasswd. - // See https://github.com/cosmos/cosmos-sdk/issues/2095 - Derive(name, mnemonic, bip39Passwd, encryptPasswd string, params hd.BIP44Params) (Info, error) + CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd, hdPath string, algo SigningAlgo) (Info, error) // CreateLedger creates, stores, and returns a new Ledger key reference CreateLedger(name string, algo SigningAlgo, hrp string, account, index uint32) (info Info, err error) // CreateOffline creates, stores, and returns a new offline key reference - CreateOffline(name string, pubkey crypto.PubKey) (info Info, err error) + CreateOffline(name string, pubkey crypto.PubKey, algo SigningAlgo) (info Info, err error) // CreateMulti creates, stores, and returns a new multsig (offline) key reference CreateMulti(name string, pubkey crypto.PubKey) (info Info, err error) @@ -81,6 +75,12 @@ type Keybase interface { // ExportPrivateKeyObject *only* works on locally-stored keys. Temporary method until we redo the exporting API ExportPrivateKeyObject(name string, passphrase string) (crypto.PrivKey, error) + // SupportedAlgos returns a list of signing algorithms supported by the keybase + SupportedAlgos() []SigningAlgo + + // SupportedAlgosLedger returns a list of signing algorithms supported by the keybase's ledger integration + SupportedAlgosLedger() []SigningAlgo + // CloseDB closes the database. CloseDB() } @@ -118,6 +118,8 @@ type Info interface { GetPubKey() crypto.PubKey // Address GetAddress() types.AccAddress + // Algo + GetAlgo() SigningAlgo // Bip44 Path GetPath() (*hd.BIP44Params, error) } @@ -132,15 +134,17 @@ var ( // localInfo is the public information about a locally stored key type localInfo struct { Name string `json:"name"` + Algo SigningAlgo `json:"algo"` PubKey crypto.PubKey `json:"pubkey"` PrivKeyArmor string `json:"privkey.armor"` } -func newLocalInfo(name string, pub crypto.PubKey, privArmor string) Info { +func newLocalInfo(name string, pub crypto.PubKey, privArmor string, algo SigningAlgo) Info { return &localInfo{ Name: name, PubKey: pub, PrivKeyArmor: privArmor, + Algo: algo, } } @@ -164,6 +168,11 @@ func (i localInfo) GetAddress() types.AccAddress { return i.PubKey.Address().Bytes() } +// GetType implements Info interface +func (i localInfo) GetAlgo() SigningAlgo { + return i.Algo +} + // GetType implements Info interface func (i localInfo) GetPath() (*hd.BIP44Params, error) { return nil, fmt.Errorf("BIP44 Paths are not available for this type") @@ -174,13 +183,15 @@ type ledgerInfo struct { Name string `json:"name"` PubKey crypto.PubKey `json:"pubkey"` Path hd.BIP44Params `json:"path"` + Algo SigningAlgo `json:"algo"` } -func newLedgerInfo(name string, pub crypto.PubKey, path hd.BIP44Params) Info { +func newLedgerInfo(name string, pub crypto.PubKey, path hd.BIP44Params, algo SigningAlgo) Info { return &ledgerInfo{ Name: name, PubKey: pub, Path: path, + Algo: algo, } } @@ -204,6 +215,11 @@ func (i ledgerInfo) GetAddress() types.AccAddress { return i.PubKey.Address().Bytes() } +// GetPath implements Info interface +func (i ledgerInfo) GetAlgo() SigningAlgo { + return i.Algo +} + // GetPath implements Info interface func (i ledgerInfo) GetPath() (*hd.BIP44Params, error) { tmp := i.Path @@ -213,13 +229,15 @@ func (i ledgerInfo) GetPath() (*hd.BIP44Params, error) { // offlineInfo is the public information about an offline key type offlineInfo struct { Name string `json:"name"` + Algo SigningAlgo `json:"algo"` PubKey crypto.PubKey `json:"pubkey"` } -func newOfflineInfo(name string, pub crypto.PubKey) Info { +func newOfflineInfo(name string, pub crypto.PubKey, algo SigningAlgo) Info { return &offlineInfo{ Name: name, PubKey: pub, + Algo: algo, } } @@ -238,6 +256,11 @@ func (i offlineInfo) GetPubKey() crypto.PubKey { return i.PubKey } +// GetAlgo returns the signing algorithm for the key +func (i offlineInfo) GetAlgo() SigningAlgo { + return i.Algo +} + // GetAddress implements Info interface func (i offlineInfo) GetAddress() types.AccAddress { return i.PubKey.Address().Bytes() @@ -299,6 +322,11 @@ func (i multiInfo) GetAddress() types.AccAddress { return i.PubKey.Address().Bytes() } +// GetPath implements Info interface +func (i multiInfo) GetAlgo() SigningAlgo { + return MultiAlgo +} + // GetPath implements Info interface func (i multiInfo) GetPath() (*hd.BIP44Params, error) { return nil, fmt.Errorf("BIP44 Paths are not available for this type") @@ -316,8 +344,10 @@ func unmarshalInfo(bz []byte) (info Info, err error) { } type ( + // DeriveKeyFunc defines the function to derive a new key from a seed and hd path + DeriveKeyFunc func(mnemonic string, bip39Passphrase, hdPath string, algo SigningAlgo) ([]byte, error) // PrivKeyGenFunc defines the function to convert derived key bytes to a tendermint private key - PrivKeyGenFunc func(bz [32]byte) crypto.PrivKey + PrivKeyGenFunc func(bz []byte, algo SigningAlgo) (crypto.PrivKey, error) // KeybaseOption overrides options for the db KeybaseOption func(*kbOptions) diff --git a/crypto/keys/types_test.go b/crypto/keys/types_test.go index 089eee44ce23..1376c3bbb70f 100644 --- a/crypto/keys/types_test.go +++ b/crypto/keys/types_test.go @@ -17,7 +17,7 @@ func Test_writeReadLedgerInfo(t *testing.T) { bz, _ := hex.DecodeString("035AD6810A47F073553FF30D2FCC7E0D3B1C0B74B61A1AAA2582344037151E143A") copy(tmpKey[:], bz) - lInfo := newLedgerInfo("some_name", tmpKey, *hd.NewFundraiserParams(5, types.CoinType, 1)) + lInfo := newLedgerInfo("some_name", tmpKey, *hd.NewFundraiserParams(5, types.CoinType, 1), Secp256k1) assert.Equal(t, TypeLedger, lInfo.GetType()) path, err := lInfo.GetPath() diff --git a/server/init_test.go b/server/init_test.go index 752540825a5d..2a447eef4f16 100644 --- a/server/init_test.go +++ b/server/init_test.go @@ -17,7 +17,7 @@ func TestGenerateCoinKey(t *testing.T) { require.NoError(t, err) // Test creation - info, err := keys.NewInMemoryKeyBase().CreateAccount("xxx", mnemonic, "", "012345678", 0, 0) + info, err := keys.NewInMemoryKeyBase().CreateAccount("xxx", mnemonic, "", "012345678", crkeys.CreateHDPath(0, 0).String(), crkeys.Secp256k1) require.NoError(t, err) require.Equal(t, addr, info.GetAddress()) } @@ -39,7 +39,7 @@ func TestGenerateSaveCoinKey(t *testing.T) { require.Equal(t, addr, info.GetAddress()) // Test in-memory recovery - info, err = keys.NewInMemoryKeyBase().CreateAccount("xxx", mnemonic, "", "012345678", 0, 0) + info, err = keys.NewInMemoryKeyBase().CreateAccount("xxx", mnemonic, "", "012345678", crkeys.CreateHDPath(0, 0).String(), crkeys.Secp256k1) require.NoError(t, err) require.Equal(t, addr, info.GetAddress()) } diff --git a/x/auth/ante/sigverify.go b/x/auth/ante/sigverify.go index 5a6eb7474692..4498b432d73d 100644 --- a/x/auth/ante/sigverify.go +++ b/x/auth/ante/sigverify.go @@ -312,7 +312,7 @@ func DefaultSigVerificationGasConsumer( var multisignature multisig.Multisignature codec.Cdc.MustUnmarshalBinaryBare(sig, &multisignature) - consumeMultisignatureVerificationGas(meter, multisignature, pubkey, params) + ConsumeMultisignatureVerificationGas(meter, multisignature, pubkey, params) return nil default: @@ -320,7 +320,8 @@ func DefaultSigVerificationGasConsumer( } } -func consumeMultisignatureVerificationGas(meter sdk.GasMeter, +// ConsumeMultisignatureVerificationGas consumes gas from a GasMeter for verifying a multisig pubkey signature +func ConsumeMultisignatureVerificationGas(meter sdk.GasMeter, sig multisig.Multisignature, pubkey multisig.PubKeyMultisigThreshold, params types.Params) { size := sig.BitArray.Size() From ca2ca2224131b8d0d36a8fadd49cd18e76b393f6 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Tue, 14 Jan 2020 16:51:20 +0100 Subject: [PATCH 075/529] Merge PR #5494: ADR 004: Split Denomination Keys --- docs/architecture/README.md | 1 + .../adr-004-split-denomination-keys.md | 73 +++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 docs/architecture/adr-004-split-denomination-keys.md diff --git a/docs/architecture/README.md b/docs/architecture/README.md index be9cf356406f..e882cb90cab2 100644 --- a/docs/architecture/README.md +++ b/docs/architecture/README.md @@ -33,6 +33,7 @@ Please add a entry below in your Pull Request for an ADR. - [ADR 002: SDK Documentation Structure](./adr-002-docs-structure.md) - [ADR 003: Dynamic Capability Store](./adr-003-dynamic-capability-store.md) +- [ADR 004: Split Denomination Keys](./adr-004-split-denomination-keys.md) - [ADR 006: Secret Store Replacement](./adr-006-secret-store-replacement.md) - [ADR 009: Evidence Module](./adr-009-evidence-module.md) - [ADR 010: Modular AnteHandler](./adr-010-modular-antehandler.md) diff --git a/docs/architecture/adr-004-split-denomination-keys.md b/docs/architecture/adr-004-split-denomination-keys.md new file mode 100644 index 000000000000..5e91f7da3561 --- /dev/null +++ b/docs/architecture/adr-004-split-denomination-keys.md @@ -0,0 +1,73 @@ +# ADR 004: Split Denomination Keys + +## Changelog + +- 2020-01-08: Initial version +- 2020-01-09: Alterations to handle vesting accounts +- 2020-01-14: Updates from review feedback + +## Context + +With permissionless IBC, anyone will be able to send arbitrary denominations to any other account. Currently, all non-zero balances are stored along with the account in an `sdk.Coins` struct, which creates a potential denial-of-service concern, as too many denominations will become expensive to load & store each time the account is modified. See issues [5467](https://github.com/cosmos/cosmos-sdk/issues/5467) and [4982](https://github.com/cosmos/cosmos-sdk/issues/4982) for additional context. + +Simply rejecting incoming deposits after a denomination count limit doesn't work, since it opens up a griefing vector: someone could send a user lots of nonsensical coins over IBC, and then prevent the user from receiving real denominations (such as staking rewards). + +## Decision + +Balances shall be stored per-account & per-denomination under a denomination- and account-unique key, thus enabling O(1) read & write access to the balance of a particular account in a particular denomination. + +### Account interface (x/auth) + +`GetCoins()` and `SetCoins()` will be removed from the account interface, since coin balances will now be stored in & managed by the bank module. + +`SpendableCoinsVestingAccount()` and `TrackDelegation()` will be altered to take a bank keeper and a denomination as two additional arguments, which will be used to lookup the balances from the base account as necessary. + +Vesting accounts will continue to store original vesting, delegated free, and delegated vesting coins (which is safe since these cannot contain arbitrary denominations). + +### Bank keeper (x/bank) + +`GetBalance(addr AccAddress, denom string) sdk.Coin` and `SetBalance(addr AccAddress, coin sdk.Coin)` methods will be added to the bank keeper to retrieve & set balances, respectively. + +Balances will be stored first by the address, then by the denomination (the reverse is also possible, but retrieval of all balances for a single account is presumed to be more frequent): + +```golang +func BalanceKey(addr sdk.AccAddress, denom string) []byte { + return append(append(BalanceKeyPrefix, addr.Bytes()...), []byte(denom)...) +} +``` + +`DelegateCoins()` and `UndelegateCoins()` will be altered to take a single `sdk.Coin` (one denomination & amount) instead of `sdk.Coins`, since they should only operate on one denomination. They will read balances directly instead of calling `GetCoins()` (which no longer exists). + +`SubtractCoins()` and `AddCoins()` will be altered to read & write the balances directly instead of calling `GetCoins()` / `SetCoins()` (which no longer exist). + +`trackDelegation()` and `trackUndelegation()` will be altered to read & write the balances directly instead of calling `GetCoins()` / `SetCoins()` (which no longer exist). + +External APIs will need to scan all balances under an account to retain backwards-compatibility - additional methods should be added to fetch a balance for a single denomination only. + +### Supply module + +The supply module, in order to implement the total supply invariant, will now need to scan all accounts & call `GetBalance` using the `x/bank` Keeper for the denomination in question, then sum the balances and check that they match the expected total supply. + +## Status + +Proposed. + +## Consequences + +### Positive + +- O(1) reads & writes of balances (with respect to the number of denominations for which an account has non-zero balances) + +### Negative + +- Slighly less efficient reads/writes when reading & writing all balances of a single account in a transaction. + +### Neutral + +None in particular. + +## References + +Ref https://github.com/cosmos/cosmos-sdk/issues/4982 +Ref https://github.com/cosmos/cosmos-sdk/issues/5467 +Ref https://github.com/cosmos/cosmos-sdk/issues/5492 From a93a596892ea9638327df287642a7c26d4345405 Mon Sep 17 00:00:00 2001 From: ykc Date: Wed, 15 Jan 2020 16:14:25 +0900 Subject: [PATCH 076/529] Fix typo (#5523) --- docs/architecture/adr-002-docs-structure.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/architecture/adr-002-docs-structure.md b/docs/architecture/adr-002-docs-structure.md index a6d357dbcf06..1c8201890c22 100644 --- a/docs/architecture/adr-002-docs-structure.md +++ b/docs/architecture/adr-002-docs-structure.md @@ -40,7 +40,7 @@ docs/ The files in each sub-folders do not matter and will likely change. What matters is the sectioning: - `README`: Landing page of the docs. -- `into`: Introductory material. Goal is to have a short explainer of the SDK and then channel people to the resource they need. The [sdk-tutorial](https://github.com/cosmos/sdk-application-tutorial/) will be highlighted, as well as the `godocs`. +- `intro`: Introductory material. Goal is to have a short explainer of the SDK and then channel people to the resource they need. The [sdk-tutorial](https://github.com/cosmos/sdk-application-tutorial/) will be highlighted, as well as the `godocs`. - `concepts`: Contains high-level explanations of the abstractions of the SDK. It does not contain specific code implementation and does not need to be updated often. **It is not an API specification of the interfaces**. API spec is the `godoc`. - `clients`: Contains specs and info about the various SDK clients. - `spec`: Contains specs of modules, and others. @@ -83,4 +83,4 @@ Accepted - https://github.com/cosmos/cosmos-sdk/issues/1460 - https://github.com/cosmos/cosmos-sdk/pull/2695 -- https://github.com/cosmos/cosmos-sdk/issues/2611 \ No newline at end of file +- https://github.com/cosmos/cosmos-sdk/issues/2611 From 7b6663d096709b8053f824aa2e6c32c50f7a3ab8 Mon Sep 17 00:00:00 2001 From: Sunny Aggarwal Date: Wed, 15 Jan 2020 08:38:09 -0500 Subject: [PATCH 077/529] Merge PR #5522: fixed amino backward compat --- crypto/keys/types.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/crypto/keys/types.go b/crypto/keys/types.go index 72fc7ecbc7d6..89f5cb2d539b 100644 --- a/crypto/keys/types.go +++ b/crypto/keys/types.go @@ -118,10 +118,10 @@ type Info interface { GetPubKey() crypto.PubKey // Address GetAddress() types.AccAddress - // Algo - GetAlgo() SigningAlgo // Bip44 Path GetPath() (*hd.BIP44Params, error) + // Algo + GetAlgo() SigningAlgo } var ( @@ -132,11 +132,12 @@ var ( ) // localInfo is the public information about a locally stored key +// Note: Algo must be last field in struct for backwards amino compatibility type localInfo struct { Name string `json:"name"` - Algo SigningAlgo `json:"algo"` PubKey crypto.PubKey `json:"pubkey"` PrivKeyArmor string `json:"privkey.armor"` + Algo SigningAlgo `json:"algo"` } func newLocalInfo(name string, pub crypto.PubKey, privArmor string, algo SigningAlgo) Info { @@ -179,6 +180,7 @@ func (i localInfo) GetPath() (*hd.BIP44Params, error) { } // ledgerInfo is the public information about a Ledger key +// Note: Algo must be last field in struct for backwards amino compatibility type ledgerInfo struct { Name string `json:"name"` PubKey crypto.PubKey `json:"pubkey"` @@ -227,10 +229,11 @@ func (i ledgerInfo) GetPath() (*hd.BIP44Params, error) { } // offlineInfo is the public information about an offline key +// Note: Algo must be last field in struct for backwards amino compatibility type offlineInfo struct { Name string `json:"name"` - Algo SigningAlgo `json:"algo"` PubKey crypto.PubKey `json:"pubkey"` + Algo SigningAlgo `json:"algo"` } func newOfflineInfo(name string, pub crypto.PubKey, algo SigningAlgo) Info { From 2679a511dc225f8c6348caf26815cdd19568d8d4 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 15 Jan 2020 09:21:01 -0500 Subject: [PATCH 078/529] Merge PR #5524: Bump github.com/pkg/errors from 0.9.0 to 0.9.1 Bumps [github.com/pkg/errors](https://github.com/pkg/errors) from 0.9.0 to 0.9.1. - [Release notes](https://github.com/pkg/errors/releases) - [Commits](https://github.com/pkg/errors/compare/v0.9.0...v0.9.1) Signed-off-by: dependabot-preview[bot] Co-authored-by: Alexander Bezobchuk --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 51539aebd007..9f7765665a29 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/hashicorp/golang-lru v0.5.3 github.com/mattn/go-isatty v0.0.11 github.com/pelletier/go-toml v1.6.0 - github.com/pkg/errors v0.9.0 + github.com/pkg/errors v0.9.1 github.com/rakyll/statik v0.1.6 github.com/spf13/afero v1.2.1 // indirect github.com/spf13/cobra v0.0.5 diff --git a/go.sum b/go.sum index 240520d52f83..7090029f731a 100644 --- a/go.sum +++ b/go.sum @@ -179,6 +179,8 @@ github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.0 h1:J8lpUdobwIeCI7OiSxHqEwJUKvJwicL5+3v1oe2Yb4k= github.com/pkg/errors v0.9.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= From c92a7389ff5e059a2d8cbb757279804f0f7903f7 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Wed, 15 Jan 2020 12:29:36 -0500 Subject: [PATCH 079/529] Merge PR #5526: Fix migrate command --- client/keys/migrate.go | 75 +++++++++++++++++++++++++++++++----------- crypto/keys/keyring.go | 29 ++++++++-------- 2 files changed, 69 insertions(+), 35 deletions(-) diff --git a/client/keys/migrate.go b/client/keys/migrate.go index 1b7c19f24c24..228248afceb5 100644 --- a/client/keys/migrate.go +++ b/client/keys/migrate.go @@ -3,6 +3,8 @@ package keys import ( "bufio" "fmt" + "io/ioutil" + "os" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/input" @@ -22,76 +24,111 @@ const migratePassphrase = "NOOP_PASSPHRASE" func MigrateCommand() *cobra.Command { cmd := &cobra.Command{ Use: "migrate", - Short: "Migrate key information from the lagacy key database to the OS secret store, or encrypted file store as a fall-back and save it", - Long: `Migrate keys from the legacy on-disk secret store to the OS keyring. -The command asks for every passphrase. If the passphrase is incorrect, it skips the respective key. + Short: "Migrate keys from the legacy (db-based) Keybase", + Long: `Migrate key information from the legacy (db-based) Keybase to the new keyring-based Keybase. +For each key material entry, the command will prompt if the key should be skipped or not. If the key +is not to be skipped, the passphrase must be entered. The key will only be migrated if the passphrase +is correct. Otherwise, the command will exit and migration must be repeated. + +It is recommended to run in 'dry-run' mode first to verify all key migration material. `, Args: cobra.ExactArgs(0), RunE: runMigrateCmd, } - cmd.Flags().Bool(flags.FlagDryRun, false, "Do everything which is supposed to be done, but don't write any changes to the keyring.") + cmd.Flags().Bool(flags.FlagDryRun, false, "Run migration without actually persisting any changes to the new Keybase") return cmd } func runMigrateCmd(cmd *cobra.Command, args []string) error { // instantiate legacy keybase rootDir := viper.GetString(flags.FlagHome) - legacykb, err := NewKeyBaseFromDir(rootDir) + legacyKb, err := NewKeyBaseFromDir(rootDir) if err != nil { return err } // fetch list of keys from legacy keybase - oldKeys, err := legacykb.List() + oldKeys, err := legacyKb.List() if err != nil { return err } - // instantiate keyring - var keyring keys.Keybase buf := bufio.NewReader(cmd.InOrStdin()) keyringServiceName := types.GetConfig().GetKeyringServiceName() + + var ( + tmpDir string + keybase keys.Keybase + ) + if viper.GetBool(flags.FlagDryRun) { - keyring, err = keys.NewTestKeyring(keyringServiceName, rootDir) + tmpDir, err = ioutil.TempDir("", "keybase-migrate-dryrun") + if err != nil { + return errors.Wrap(err, "failed to create temporary directory for dryrun migration") + } + + defer os.RemoveAll(tmpDir) + + keybase, err = keys.NewTestKeyring(keyringServiceName, tmpDir) } else { - keyring, err = keys.NewKeyring(keyringServiceName, rootDir, buf) + keybase, err = keys.NewKeyring(keyringServiceName, rootDir, buf) } if err != nil { return errors.Wrap(err, fmt.Sprintf( - "failed to initialize keyring for service %s at directory %s", - keyringServiceName, rootDir)) + "failed to initialize keybase for service %s at directory %s", + keyringServiceName, rootDir, + )) } for _, key := range oldKeys { - legKeyInfo, err := legacykb.Export(key.GetName()) + legKeyInfo, err := legacyKb.Export(key.GetName()) if err != nil { return err } keyName := key.GetName() keyType := key.GetType() - cmd.PrintErrf("Migrating %s (%s) ...\n", key.GetName(), keyType) + + // skip key if already migrated + if _, err := keybase.Get(keyName); err == nil { + cmd.PrintErrf("Key '%s (%s)' already exists; skipping ...\n", key.GetName(), keyType) + continue + } + + cmd.PrintErrf("Migrating key: '%s (%s)' ...\n", key.GetName(), keyType) + + // allow user to skip migrating specific keys + ok, err := input.GetConfirmation("Skip key migration?", buf) + if err != nil { + return err + } + if ok { + continue + } + if keyType != keys.TypeLocal { - if err := keyring.Import(keyName, legKeyInfo); err != nil { + if err := keybase.Import(keyName, legKeyInfo); err != nil { return err } + continue } - password, err := input.GetPassword("Enter passphrase to decrypt your key:", buf) + password, err := input.GetPassword("Enter passphrase to decrypt key:", buf) if err != nil { return err } // NOTE: A passphrase is not actually needed here as when the key information - // is imported into the Keyring keystore it only needs the password (see: writeLocalKey). - armoredPriv, err := legacykb.ExportPrivKey(keyName, password, migratePassphrase) + // is imported into the Keyring-based Keybase it only needs the password + // (see: writeLocalKey). + armoredPriv, err := legacyKb.ExportPrivKey(keyName, password, migratePassphrase) if err != nil { return err } - if err := keyring.ImportPrivKey(keyName, armoredPriv, migratePassphrase); err != nil { + if err := keybase.ImportPrivKey(keyName, armoredPriv, migratePassphrase); err != nil { return err } } diff --git a/crypto/keys/keyring.go b/crypto/keys/keyring.go index 8b82df377001..d5bd74a0d66e 100644 --- a/crypto/keys/keyring.go +++ b/crypto/keys/keyring.go @@ -41,6 +41,13 @@ type keyringKeybase struct { var maxPassphraseEntryAttempts = 3 +func newKeyringKeybase(db keyring.Keyring, opts ...KeybaseOption) Keybase { + return keyringKeybase{ + db: db, + base: newBaseKeybase(opts...), + } +} + // NewKeyring creates a new instance of a keyring. Keybase // options can be applied when generating this new Keybase. func NewKeyring( @@ -479,10 +486,12 @@ func (kb keyringKeybase) writeInfo(name string, info Info) { func lkbToKeyringConfig(name, dir string, buf io.Reader, test bool) keyring.Config { if test { return keyring.Config{ - AllowedBackends: []keyring.BackendType{"file"}, - ServiceName: name, - FileDir: filepath.Join(dir, testKeyringDirName), - FilePasswordFunc: fakePrompt, + AllowedBackends: []keyring.BackendType{"file"}, + ServiceName: name, + FileDir: filepath.Join(dir, testKeyringDirName), + FilePasswordFunc: func(_ string) (string, error) { + return "test", nil + }, } } @@ -574,15 +583,3 @@ func newRealPrompt(dir string, buf io.Reader) func(string) (string, error) { } } } - -func fakePrompt(prompt string) (string, error) { - fmt.Fprintln(os.Stderr, "Fake prompt for passphase. Testing only") - return "test", nil -} - -func newKeyringKeybase(db keyring.Keyring, opts ...KeybaseOption) Keybase { - return keyringKeybase{ - db: db, - base: newBaseKeybase(opts...), - } -} From c1991e31bdf66ad5148ed915fb769cc481f74fd7 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Thu, 16 Jan 2020 16:46:51 -0500 Subject: [PATCH 080/529] Merge PR #5527: Bump Tendermint Version to v0.33.0 * Bump Tendermint version to v0.33.0 * Deprecate old cmn package with new packages * Update update DB APIs * More DB updates * Bump IAVL to v0.13.0 * Handle error returned by iavl.NewMutableTree * Fix some IAVL stuffs * Update IAVL * More updates * Passing tests * Fix unit tests Co-authored-by: Jack Zampolin --- client/context/context.go | 14 ++++- client/context/query.go | 8 +-- client/context/verifier.go | 7 ++- client/context/verifier_test.go | 3 +- client/flags/flags.go | 2 + client/rpc/block.go | 6 +- client/rpc/validators.go | 39 ++++++++++-- crypto/encode_test.go | 2 + crypto/keys/keybase.go | 52 ++++++++++++---- crypto/keys/lazy_keybase.go | 4 +- crypto/keys/mintkey/mintkey.go | 6 +- go.mod | 8 +-- go.sum | 68 +++++++++------------ server/config/toml.go | 4 +- server/start.go | 8 +-- server/util.go | 2 +- simapp/app.go | 4 +- simapp/sim_bench_test.go | 3 +- simapp/utils.go | 4 +- simapp/utils_test.go | 17 +++--- store/cache/cache_test.go | 12 +++- store/cachekv/memiterator.go | 23 ++++++-- store/cachekv/mergeiterator.go | 28 ++++++--- store/cachekv/store.go | 11 ++-- store/cachekv/store_test.go | 10 ++-- store/dbadapter/store.go | 54 +++++++++++++++++ store/firstlast.go | 12 ++-- store/gaskv/store.go | 5 ++ store/iavl/store.go | 35 ++++++----- store/iavl/store_test.go | 69 +++++++++++++++++----- store/prefix/store.go | 11 ++++ store/prefix/store_test.go | 3 +- store/rootmulti/proof.go | 16 ++--- store/rootmulti/store.go | 18 +++--- store/tracekv/store.go | 5 ++ store/types/store.go | 4 +- store/types/utils.go | 10 ++-- tests/test_cover.sh | 2 +- tests/util.go | 23 ++++++-- types/events.go | 6 +- types/result_test.go | 3 +- types/store.go | 6 +- x/auth/client/cli/query.go | 10 ++-- x/auth/simulation/decoder.go | 4 +- x/auth/simulation/decoder_test.go | 10 ++-- x/bank/app_test.go | 3 +- x/bank/internal/keeper/keeper_test.go | 16 +++-- x/distribution/simulation/decoder.go | 5 +- x/distribution/simulation/decoder_test.go | 25 ++++---- x/distribution/types/params.go | 3 +- x/evidence/client/cli/query.go | 11 +--- x/evidence/exported/evidence.go | 4 +- x/evidence/internal/keeper/keeper.go | 4 +- x/evidence/internal/types/codec_test.go | 4 +- x/evidence/internal/types/evidence.go | 4 +- x/evidence/internal/types/evidence_test.go | 3 +- x/evidence/internal/types/test_util.go | 6 +- x/genutil/client/cli/gentx.go | 9 +-- x/genutil/client/cli/init.go | 7 ++- x/genutil/types/genesis_state.go | 4 +- x/genutil/utils.go | 6 +- x/gov/client/cli/query.go | 17 +++--- x/gov/client/cli/tx.go | 2 - x/gov/client/utils/query_test.go | 9 +-- x/gov/genesis_test.go | 3 +- x/gov/keeper/keeper_test.go | 3 +- x/gov/keeper/proposal_test.go | 3 +- x/gov/simulation/decoder.go | 4 +- x/gov/simulation/decoder_test.go | 14 ++--- x/mint/simulation/decoder.go | 4 +- x/mint/simulation/decoder_test.go | 8 +-- x/params/subspace/subspace_test.go | 9 +-- x/params/subspace/table_test.go | 3 +- x/simulation/mock_tendermint.go | 4 +- x/slashing/simulation/decoder.go | 4 +- x/slashing/simulation/decoder_test.go | 12 ++-- x/staking/abci.go | 3 +- x/staking/handler.go | 4 +- x/staking/keeper/historical_info_test.go | 3 +- x/staking/simulation/decoder.go | 4 +- x/staking/simulation/decoder_test.go | 18 +++--- x/supply/simulation/decoder.go | 4 +- x/supply/simulation/decoder_test.go | 8 +-- x/upgrade/abci.go | 1 + x/upgrade/client/cli/query.go | 3 +- x/upgrade/internal/keeper/querier.go | 3 +- x/upgrade/internal/types/plan_test.go | 3 +- x/upgrade/module.go | 3 +- 88 files changed, 577 insertions(+), 344 deletions(-) diff --git a/client/context/context.go b/client/context/context.go index c778a4345c3c..6ea577a31005 100644 --- a/client/context/context.go +++ b/client/context/context.go @@ -59,14 +59,18 @@ func NewCLIContextWithInputAndFrom(input io.Reader, from string) CLIContext { genOnly := viper.GetBool(flags.FlagGenerateOnly) fromAddress, fromName, err := GetFromFields(input, from, genOnly) if err != nil { - fmt.Printf("failed to get from fields: %v", err) + fmt.Printf("failed to get from fields: %v\n", err) os.Exit(1) } if !genOnly { nodeURI = viper.GetString(flags.FlagNode) if nodeURI != "" { - rpc = rpcclient.NewHTTP(nodeURI, "/websocket") + rpc, err = rpcclient.NewHTTP(nodeURI, "/websocket") + if err != nil { + fmt.Printf("failted to get client: %v\n", err) + os.Exit(1) + } } } @@ -154,7 +158,11 @@ func (ctx CLIContext) WithTrustNode(trustNode bool) CLIContext { // WithNodeURI returns a copy of the context with an updated node URI. func (ctx CLIContext) WithNodeURI(nodeURI string) CLIContext { ctx.NodeURI = nodeURI - ctx.Client = rpcclient.NewHTTP(nodeURI, "/websocket") + client, err := rpcclient.NewHTTP(nodeURI, "/websocket") + if err != nil { + panic(err) + } + ctx.Client = client return ctx } diff --git a/client/context/query.go b/client/context/query.go index 2a553d663367..dcf2c92b7f36 100644 --- a/client/context/query.go +++ b/client/context/query.go @@ -8,7 +8,7 @@ import ( abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto/merkle" - cmn "github.com/tendermint/tendermint/libs/common" + tmbytes "github.com/tendermint/tendermint/libs/bytes" tmliteErr "github.com/tendermint/tendermint/lite/errors" tmliteProxy "github.com/tendermint/tendermint/lite/proxy" rpcclient "github.com/tendermint/tendermint/rpc/client" @@ -45,7 +45,7 @@ func (ctx CLIContext) QueryWithData(path string, data []byte) ([]byte, int64, er // QueryStore performs a query to a Tendermint node with the provided key and // store name. It returns the result and height of the query upon success // or an error if the query fails. -func (ctx CLIContext) QueryStore(key cmn.HexBytes, storeName string) ([]byte, int64, error) { +func (ctx CLIContext) QueryStore(key tmbytes.HexBytes, storeName string) ([]byte, int64, error) { return ctx.queryStore(key, storeName, "key") } @@ -77,7 +77,7 @@ func (ctx CLIContext) GetFromName() string { // or an error if the query fails. In addition, it will verify the returned // proof if TrustNode is disabled. If proof verification fails or the query // height is invalid, an error will be returned. -func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, height int64, err error) { +func (ctx CLIContext) query(path string, key tmbytes.HexBytes) (res []byte, height int64, err error) { node, err := ctx.GetNode() if err != nil { return res, height, err @@ -167,7 +167,7 @@ func (ctx CLIContext) verifyProof(queryPath string, resp abci.ResponseQuery) err // queryStore performs a query to a Tendermint node with the provided a store // name and path. It returns the result and height of the query upon success // or an error if the query fails. -func (ctx CLIContext) queryStore(key cmn.HexBytes, storeName, endPath string) ([]byte, int64, error) { +func (ctx CLIContext) queryStore(key tmbytes.HexBytes, storeName, endPath string) ([]byte, int64, error) { path := fmt.Sprintf("/store/%s/%s", storeName, endPath) return ctx.query(path, key) } diff --git a/client/context/verifier.go b/client/context/verifier.go index 73a816745bf0..856c585b5a28 100644 --- a/client/context/verifier.go +++ b/client/context/verifier.go @@ -38,10 +38,15 @@ func CreateVerifier(ctx CLIContext, cacheSize int) (tmlite.Verifier, error) { return nil, errors.New("must provide a valid RPC client or RPC URI to create verifier") } + var err error + // create an RPC client based off of the RPC URI if no RPC client exists client := ctx.Client if client == nil { - client = rpcclient.NewHTTP(ctx.NodeURI, "/websocket") + client, err = rpcclient.NewHTTP(ctx.NodeURI, "/websocket") + if err != nil { + return nil, err + } } return tmliteproxy.NewVerifier( diff --git a/client/context/verifier_test.go b/client/context/verifier_test.go index 6eacccae5452..bd2539492349 100644 --- a/client/context/verifier_test.go +++ b/client/context/verifier_test.go @@ -4,8 +4,9 @@ import ( "io/ioutil" "testing" - "github.com/cosmos/cosmos-sdk/client/context" "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/client/context" ) func TestCreateVerifier(t *testing.T) { diff --git a/client/flags/flags.go b/client/flags/flags.go index d609e26729f6..ea2a5baa431a 100644 --- a/client/flags/flags.go +++ b/client/flags/flags.go @@ -61,6 +61,8 @@ const ( FlagOutputDocument = "output-document" // inspired by wget -O FlagSkipConfirmation = "yes" FlagKeyringBackend = "keyring-backend" + FlagPage = "page" + FlagLimit = "limit" ) // LineBreak can be included in a command list to provide a blank line diff --git a/client/rpc/block.go b/client/rpc/block.go index 6e3ea231f409..bce145370c33 100644 --- a/client/rpc/block.go +++ b/client/rpc/block.go @@ -53,13 +53,11 @@ func getBlock(cliCtx context.CLIContext, height *int64) ([]byte, error) { return nil, err } - err = tmliteProxy.ValidateBlockMeta(res.BlockMeta, check) - if err != nil { + if err := tmliteProxy.ValidateHeader(&res.Block.Header, check); err != nil { return nil, err } - err = tmliteProxy.ValidateBlock(res.Block, check) - if err != nil { + if err = tmliteProxy.ValidateBlock(res.Block, check); err != nil { return nil, err } } diff --git a/client/rpc/validators.go b/client/rpc/validators.go index 7b68e526890c..8f8d16968b9a 100644 --- a/client/rpc/validators.go +++ b/client/rpc/validators.go @@ -45,7 +45,7 @@ func ValidatorCommand(cdc *codec.Codec) *cobra.Command { cliCtx := context.NewCLIContext().WithCodec(cdc) - result, err := GetValidators(cliCtx, height) + result, err := GetValidators(cliCtx, height, viper.GetInt(flags.FlagPage), viper.GetInt(flags.FlagLimit)) if err != nil { return err } @@ -60,6 +60,9 @@ func ValidatorCommand(cdc *codec.Codec) *cobra.Command { viper.BindPFlag(flags.FlagTrustNode, cmd.Flags().Lookup(flags.FlagTrustNode)) cmd.Flags().Bool(flags.FlagIndentResponse, false, "indent JSON response") viper.BindPFlag(flags.FlagIndentResponse, cmd.Flags().Lookup(flags.FlagIndentResponse)) + cmd.Flags().Int(flags.FlagPage, 0, "Query a specific page of paginated results") + viper.BindPFlag(flags.FlagPage, cmd.Flags().Lookup(flags.FlagPage)) + cmd.Flags().Int(flags.FlagLimit, 100, "Query number of results returned per page") return cmd } @@ -114,14 +117,14 @@ func bech32ValidatorOutput(validator *tmtypes.Validator) (ValidatorOutput, error } // GetValidators from client -func GetValidators(cliCtx context.CLIContext, height *int64) (ResultValidatorsOutput, error) { +func GetValidators(cliCtx context.CLIContext, height *int64, page, limit int) (ResultValidatorsOutput, error) { // get the node node, err := cliCtx.GetNode() if err != nil { return ResultValidatorsOutput{}, err } - validatorsRes, err := node.Validators(height) + validatorsRes, err := node.Validators(height, page, limit) if err != nil { return ResultValidatorsOutput{}, err } @@ -159,6 +162,18 @@ func ValidatorSetRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) + page, err := strconv.ParseInt(vars["page"], 10, 64) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, "failed to parse page") + return + } + + limit, err := strconv.ParseInt(vars["limit"], 10, 64) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, "failed to parse limit") + return + } + height, err := strconv.ParseInt(vars["height"], 10, 64) if err != nil { rest.WriteErrorResponse(w, http.StatusBadRequest, "failed to parse block height; assumed format is '/validatorsets/{height}'") @@ -175,7 +190,7 @@ func ValidatorSetRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return } - output, err := GetValidators(cliCtx, &height) + output, err := GetValidators(cliCtx, &height, int(page), int(limit)) if err != nil { rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return @@ -187,7 +202,21 @@ func ValidatorSetRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { // Latest Validator Set REST handler func LatestValidatorSetRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - output, err := GetValidators(cliCtx, nil) + vars := mux.Vars(r) + + page, err := strconv.ParseInt(vars["page"], 10, 64) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, "failed to parse page") + return + } + + limit, err := strconv.ParseInt(vars["limit"], 10, 64) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, "failed to parse limit") + return + } + + output, err := GetValidators(cliCtx, nil, int(page), int(limit)) if err != nil { rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return diff --git a/crypto/encode_test.go b/crypto/encode_test.go index 90c5df68d963..858a703994c3 100644 --- a/crypto/encode_test.go +++ b/crypto/encode_test.go @@ -54,9 +54,11 @@ func ExamplePrintRegisteredTypes() { //| ---- | ---- | ------ | ----- | ------ | //| PrivKeyLedgerSecp256k1 | tendermint/PrivKeyLedgerSecp256k1 | 0x10CAB393 | variable | | //| PubKeyEd25519 | tendermint/PubKeyEd25519 | 0x1624DE64 | 0x20 | | + //| PubKeySr25519 | tendermint/PubKeySr25519 | 0x0DFB1005 | 0x20 | | //| PubKeySecp256k1 | tendermint/PubKeySecp256k1 | 0xEB5AE987 | 0x21 | | //| PubKeyMultisigThreshold | tendermint/PubKeyMultisigThreshold | 0x22C1F7E2 | variable | | //| PrivKeyEd25519 | tendermint/PrivKeyEd25519 | 0xA3288910 | 0x40 | | + //| PrivKeySr25519 | tendermint/PrivKeySr25519 | 0x2F82D78B | 0x20 | | //| PrivKeySecp256k1 | tendermint/PrivKeySecp256k1 | 0xE1B0F79B | 0x20 | | } diff --git a/crypto/keys/keybase.go b/crypto/keys/keybase.go index d7fdcea400f1..9d95a5ccda2b 100644 --- a/crypto/keys/keybase.go +++ b/crypto/keys/keybase.go @@ -131,7 +131,11 @@ func (kb dbKeybase) CreateMulti(name string, pub tmcrypto.PubKey) (Info, error) func (kb dbKeybase) List() ([]Info, error) { var res []Info - iter := kb.db.Iterator(nil, nil) + iter, err := kb.db.Iterator(nil, nil) + if err != nil { + return nil, err + } + defer iter.Close() for ; iter.Valid(); iter.Next() { @@ -153,7 +157,11 @@ func (kb dbKeybase) List() ([]Info, error) { // Get returns the public information about one key. func (kb dbKeybase) Get(name string) (Info, error) { - bs := kb.db.Get(infoKey(name)) + bs, err := kb.db.Get(infoKey(name)) + if err != nil { + return nil, err + } + if len(bs) == 0 { return nil, keyerror.NewErrKeyNotFound(name) } @@ -164,12 +172,20 @@ func (kb dbKeybase) Get(name string) (Info, error) { // GetByAddress returns Info based on a provided AccAddress. An error is returned // if the address does not exist. func (kb dbKeybase) GetByAddress(address types.AccAddress) (Info, error) { - ik := kb.db.Get(addrKey(address)) + ik, err := kb.db.Get(addrKey(address)) + if err != nil { + return nil, err + } + if len(ik) == 0 { return nil, fmt.Errorf("key with address %s not found", address) } - bs := kb.db.Get(ik) + bs, err := kb.db.Get(ik) + if err != nil { + return nil, err + } + return unmarshalInfo(bs) } @@ -242,7 +258,11 @@ func (kb dbKeybase) ExportPrivateKeyObject(name string, passphrase string) (tmcr } func (kb dbKeybase) Export(name string) (armor string, err error) { - bz := kb.db.Get(infoKey(name)) + bz, err := kb.db.Get(infoKey(name)) + if err != nil { + return "", err + } + if bz == nil { return "", fmt.Errorf("no key to export with name %s", name) } @@ -253,7 +273,11 @@ func (kb dbKeybase) Export(name string) (armor string, err error) { // ExportPubKey returns public keys in ASCII armored format. It retrieves a Info // object by its name and return the public key in a portable format. func (kb dbKeybase) ExportPubKey(name string) (armor string, err error) { - bz := kb.db.Get(infoKey(name)) + bz, err := kb.db.Get(infoKey(name)) + if err != nil { + return "", err + } + if bz == nil { return "", fmt.Errorf("no key to export with name %s", name) } @@ -302,9 +326,13 @@ func (kb dbKeybase) ImportPrivKey(name string, armor string, passphrase string) } func (kb dbKeybase) Import(name string, armor string) (err error) { - bz := kb.db.Get(infoKey(name)) + bz, err := kb.db.Get(infoKey(name)) + if err != nil { + return err + } + if len(bz) > 0 { - return errors.New("Cannot overwrite data for name " + name) + return errors.New("cannot overwrite data for name " + name) } infoBytes, err := mintkey.UnarmorInfoBytes(armor) @@ -320,9 +348,13 @@ func (kb dbKeybase) Import(name string, armor string) (err error) { // a public key only, i.e. it will not be possible to sign with it as it lacks the // secret key. func (kb dbKeybase) ImportPubKey(name string, armor string) (err error) { - bz := kb.db.Get(infoKey(name)) + bz, err := kb.db.Get(infoKey(name)) + if err != nil { + return err + } + if len(bz) > 0 { - return errors.New("Cannot overwrite data for name " + name) + return errors.New("cannot overwrite data for name " + name) } pubBytes, algo, err := mintkey.UnarmorPubKeyBytes(armor) diff --git a/crypto/keys/lazy_keybase.go b/crypto/keys/lazy_keybase.go index db0042732a4b..2a92ecd304ce 100644 --- a/crypto/keys/lazy_keybase.go +++ b/crypto/keys/lazy_keybase.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/tendermint/tendermint/crypto" - cmn "github.com/tendermint/tendermint/libs/common" + tmos "github.com/tendermint/tendermint/libs/os" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -20,7 +20,7 @@ type lazyKeybase struct { // New creates a new instance of a lazy keybase. func New(name, dir string, opts ...KeybaseOption) Keybase { - if err := cmn.EnsureDir(dir, 0700); err != nil { + if err := tmos.EnsureDir(dir, 0700); err != nil { panic(fmt.Sprintf("failed to create Keybase directory: %s", err)) } diff --git a/crypto/keys/mintkey/mintkey.go b/crypto/keys/mintkey/mintkey.go index 585d148c924e..8b458849833d 100644 --- a/crypto/keys/mintkey/mintkey.go +++ b/crypto/keys/mintkey/mintkey.go @@ -11,7 +11,7 @@ import ( cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino" "github.com/tendermint/tendermint/crypto/xsalsa20symmetric" - cmn "github.com/tendermint/tendermint/libs/common" + tmos "github.com/tendermint/tendermint/libs/os" "github.com/cosmos/cosmos-sdk/crypto/keys/keyerror" ) @@ -134,7 +134,7 @@ func encryptPrivKey(privKey crypto.PrivKey, passphrase string) (saltBytes []byte saltBytes = crypto.CRandBytes(16) key, err := bcrypt.GenerateFromPassword(saltBytes, []byte(passphrase), BcryptSecurityParameter) if err != nil { - cmn.Exit("Error generating bcrypt key from passphrase: " + err.Error()) + tmos.Exit("Error generating bcrypt key from passphrase: " + err.Error()) } key = crypto.Sha256(key) // get 32 bytes privKeyBytes := privKey.Bytes() @@ -171,7 +171,7 @@ func UnarmorDecryptPrivKey(armorStr string, passphrase string) (privKey crypto.P func decryptPrivKey(saltBytes []byte, encBytes []byte, passphrase string) (privKey crypto.PrivKey, err error) { key, err := bcrypt.GenerateFromPassword(saltBytes, []byte(passphrase), BcryptSecurityParameter) if err != nil { - cmn.Exit("error generating bcrypt key from passphrase: " + err.Error()) + tmos.Exit("error generating bcrypt key from passphrase: " + err.Error()) } key = crypto.Sha256(key) // Get 32 bytes privKeyBytes, err := xsalsa20symmetric.DecryptSymmetric(encBytes, key) diff --git a/go.mod b/go.mod index 9f7765665a29..c5e0860701f0 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ require ( github.com/bartekn/go-bip39 v0.0.0-20171116152956-a05967ea095d github.com/bgentry/speakeasy v0.1.0 github.com/btcsuite/btcd v0.0.0-20190115013929-ed77733ec07d - github.com/cosmos/go-bip39 v0.0.0-20180618194314-52158e4697b8 + github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d github.com/cosmos/ledger-cosmos-go v0.11.1 github.com/gogo/protobuf v1.3.1 github.com/golang/mock v1.3.1-0.20190508161146-9fa652df1129 @@ -24,9 +24,9 @@ require ( github.com/tendermint/btcd v0.1.1 github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 github.com/tendermint/go-amino v0.15.1 - github.com/tendermint/iavl v0.12.4 - github.com/tendermint/tendermint v0.32.9 - github.com/tendermint/tm-db v0.2.0 + github.com/tendermint/iavl v0.13.0 + github.com/tendermint/tendermint v0.33.0 + github.com/tendermint/tm-db v0.4.0 gopkg.in/yaml.v2 v2.2.7 ) diff --git a/go.sum b/go.sum index 7090029f731a..a636d84e6de8 100644 --- a/go.sum +++ b/go.sum @@ -5,6 +5,8 @@ github.com/99designs/keyring v1.1.3 h1:mEV3iyZWjkxQ7R8ia8GcG97vCX5zQQ7n4o8R2Bylw github.com/99designs/keyring v1.1.3/go.mod h1:657DQuMrBZRtuL/voxVyiyb6zpMehlm5vLB9Qwrv904= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/ChainSafe/go-schnorrkel v0.0.0-20200102211924-4bcbc698314f h1:4O1om+UVU+Hfcihr1timk8YNXHxzZWgCo7ofnrZRApw= +github.com/ChainSafe/go-schnorrkel v0.0.0-20200102211924-4bcbc698314f/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= @@ -40,8 +42,8 @@ github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8Nz github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cosmos/go-bip39 v0.0.0-20180618194314-52158e4697b8 h1:Iwin12wRQtyZhH6FV3ykFcdGNlYEzoeR0jN8Vn+JWsI= -github.com/cosmos/go-bip39 v0.0.0-20180618194314-52158e4697b8/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= +github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d h1:49RLWk1j44Xu4fjHb6JFYmeUnDORVwHNkDxaQ0ctCVU= +github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= github.com/cosmos/ledger-cosmos-go v0.11.1 h1:9JIYsGnXP613pb2vPjFeMMjBI5lEDsEaF6oYorTy6J4= github.com/cosmos/ledger-cosmos-go v0.11.1/go.mod h1:J8//BsAGTo3OC/vDLjMRFLW6q0WAaXvHnVc7ZmE8iUY= github.com/cosmos/ledger-go v0.9.2 h1:Nnao/dLwaVTk1Q5U9THldpUMMXU94BOTWPddSmVB6pI= @@ -57,9 +59,8 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dvsekhvalnov/jose2go v0.0.0-20180829124132-7f401d37b68a h1:mq+R6XEM6lJX5VlLyZIrUSP8tSuJp82xTK89hvBwJbU= github.com/dvsekhvalnov/jose2go v0.0.0-20180829124132-7f401d37b68a/go.mod h1:7BvyPhdbLxMXIYTFPLsyJRFMsKmOZnQmzh6Gb+uquuM= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/etcd-io/bbolt v1.3.2/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= github.com/etcd-io/bbolt v1.3.3 h1:gSJmxrs37LgTqR/oyJBWok6k6SvXEUerFTbltIhXkBM= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ= @@ -68,13 +69,11 @@ github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojt github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 h1:E2s37DuLxFhQDg5gKsWoLBOB0n+ZW8s599zru8FJ2/Y= github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= -github.com/fortytw2/leaktest v1.2.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-kit/kit v0.6.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.8.0 h1:Wz+5lgoB0kkuqLEc6NVmwRknTKP6dTGbSqvhZtBI/j0= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0 h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk= @@ -83,6 +82,8 @@ github.com/go-logfmt/logfmt v0.3.0 h1:8HUsc87TaSWLKwrnumgC8/YconD2fJQsRJAsWaPg2i github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= @@ -105,6 +106,7 @@ github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= @@ -113,7 +115,6 @@ github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGa github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= @@ -122,6 +123,10 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= +github.com/gtank/merlin v0.1.1-0.20191105220539-8318aed1a79f h1:8N8XWLZelZNibkhM1FuF+3Ad3YIbgirjdMiVA0eUkaM= +github.com/gtank/merlin v0.1.1-0.20191105220539-8318aed1a79f/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= +github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uMzcc= +github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o= github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk= github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= @@ -160,6 +165,8 @@ github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGe github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643 h1:hLDRPB66XQT/8+wG9WsDpiCvZf1yKO7sz7scAjSlBa0= +github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= @@ -177,8 +184,6 @@ github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.0 h1:J8lpUdobwIeCI7OiSxHqEwJUKvJwicL5+3v1oe2Yb4k= -github.com/pkg/errors v0.9.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -191,7 +196,6 @@ github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.0.0-20181020173914-7e9e6cabbd39/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.0 h1:7etb9YClo3a6HjLzfl6rIQaU+FDfi0VSX39io3aQ+DM= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= @@ -204,8 +208,6 @@ github.com/rakyll/statik v0.1.6/go.mod h1:OEi9wJV/fMUAGx1eNjq75DKDsJVuEv1U0oYdX6 github.com/rcrowley/go-metrics v0.0.0-20180503174638-e2704e165165 h1:nkcn14uNmFEuGCb2mBZbBb24RdNRL08b/wb+xBOYpuk= github.com/rcrowley/go-metrics v0.0.0-20180503174638-e2704e165165/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= -github.com/rs/cors v1.6.0 h1:G9tHG9lebljV9mfp9SNPDL36nCDxmo3zTlAf1YgvzmI= -github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= @@ -232,11 +234,8 @@ github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.0.0/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= github.com/spf13/viper v1.3.2 h1:VUFqw5KcqRf7i70GOzW7N+Q7+gxVBkSSqiXB12+JQ4M= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/spf13/viper v1.5.0 h1:GpsTwfsQ27oS/Aha/6d1oD7tpKIqWnOA6tgOX9HHkt4= -github.com/spf13/viper v1.5.0/go.mod h1:AkYRkVJF8TkSG/xet6PzXX+l39KhhXa2pdqVSxnTcn4= github.com/spf13/viper v1.6.1 h1:VPZzIkznI1YhVMRi6vNFLHSwhnhReBfgTxIPccpfdZk= github.com/spf13/viper v1.6.1/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -247,12 +246,12 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stumble/gorocksdb v0.0.3 h1:9UU+QA1pqFYJuf9+5p7z1IqdE5k0mma4UAeu2wmX8kA= -github.com/stumble/gorocksdb v0.0.3/go.mod h1:v6IHdFBXk5DJ1K4FZ0xi+eY737quiiBxYtSWXadLybY= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/syndtr/goleveldb v1.0.1-0.20190318030020-c3a204f8e965 h1:1oFLiOyVl+W7bnBzGhf7BbIv9loSFQcieWWYIjLqcAw= -github.com/syndtr/goleveldb v1.0.1-0.20190318030020-c3a204f8e965/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA= +github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d h1:gZZadD8H+fF+n9CmNhYL1Y0dJB+kLOmKd7FbPJLeGHs= +github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA= +github.com/tecbot/gorocksdb v0.0.0-20191017175515-d217d93fd4c5 h1:gVwAW5OwaZlDB5/CfqcGFM9p9C+KxvQKyNOltQ8orj0= +github.com/tecbot/gorocksdb v0.0.0-20191017175515-d217d93fd4c5/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8= github.com/tendermint/btcd v0.1.1 h1:0VcxPfflS2zZ3RiOAHkBiFUcPvbtRj5O7zHmcJWHV7s= github.com/tendermint/btcd v0.1.1/go.mod h1:DC6/m53jtQzr/NFmMNEu0rxf18/ktVoVtMrnDD5pN+U= github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 h1:hqAk8riJvK4RMWx1aInLzndwxKalgi5rTqgfXxOxbEI= @@ -260,17 +259,12 @@ github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15/go.mod h1:z4YtwM github.com/tendermint/go-amino v0.14.1/go.mod h1:i/UKE5Uocn+argJJBb12qTZsCDBcAYMbR92AaJVmKso= github.com/tendermint/go-amino v0.15.1 h1:D2uk35eT4iTsvJd9jWIetzthE5C0/k2QmMFkCN+4JgQ= github.com/tendermint/go-amino v0.15.1/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= -github.com/tendermint/iavl v0.12.4 h1:hd1woxUGISKkfUWBA4mmmTwOua6PQZTJM/F0FDrmMV8= -github.com/tendermint/iavl v0.12.4/go.mod h1:8LHakzt8/0G3/I8FUU0ReNx98S/EP6eyPJkAUvEXT/o= -github.com/tendermint/tendermint v0.32.1/go.mod h1:jmPDAKuNkev9793/ivn/fTBnfpA9mGBww8MPRNPNxnU= -github.com/tendermint/tendermint v0.32.8 h1:eOaLJGRi5x/Rb23fiVsxq9c5fZ/6O5QplExlGjNPDVI= -github.com/tendermint/tendermint v0.32.8/go.mod h1:5/B1XZjNYtVBso8o1l/Eg4A0Mhu42lDcmftoQl95j/E= -github.com/tendermint/tendermint v0.32.9 h1:++dR46xpBq/yfQx2c5KyrZmb15p2jw9Q5iEtTB82d8s= -github.com/tendermint/tendermint v0.32.9/go.mod h1:5/B1XZjNYtVBso8o1l/Eg4A0Mhu42lDcmftoQl95j/E= -github.com/tendermint/tm-db v0.1.1 h1:G3Xezy3sOk9+ekhjZ/kjArYIs1SmwV+1OUgNkj7RgV0= -github.com/tendermint/tm-db v0.1.1/go.mod h1:0cPKWu2Mou3IlxecH+MEUSYc1Ch537alLe6CpFrKzgw= -github.com/tendermint/tm-db v0.2.0 h1:rJxgdqn6fIiVJZy4zLpY1qVlyD0TU6vhkT4kEf71TQQ= -github.com/tendermint/tm-db v0.2.0/go.mod h1:0cPKWu2Mou3IlxecH+MEUSYc1Ch537alLe6CpFrKzgw= +github.com/tendermint/iavl v0.13.0 h1:r2sINvNFlJsLlLhGoqlqPlREWYkuK26BvMfkBt+XQnA= +github.com/tendermint/iavl v0.13.0/go.mod h1:7nSUPdrsHEZ2nNZa+9gaIrcJciWd1jCQZXtcyARU82k= +github.com/tendermint/tendermint v0.33.0 h1:TW1g9sQs3YSqKM8o1+opL3/VmBy4Ke/VKV9MxYpqNbI= +github.com/tendermint/tendermint v0.33.0/go.mod h1:s5UoymnPIY+GcA3mMte4P9gpMP8vS7UH7HBXikT1pHI= +github.com/tendermint/tm-db v0.4.0 h1:iPbCcLbf4nwDFhS39Zo1lpdS1X/cT9CkTlUx17FHQgA= +github.com/tendermint/tm-db v0.4.0/go.mod h1:+Cwhgowrf7NBGXmsqFMbwEtbo80XmyrlY5Jsk95JubQ= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= @@ -287,12 +281,11 @@ go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a h1:YX8ljsm6wXlHZO+aRz9Exqr0evNhKRNe5K/gi+zKh4U= -golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413 h1:ULYEB3JvPRE/IfO+9uO7vKV/xzVTO7XPAwm8xbf4w2g= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -341,18 +334,13 @@ google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9Ywl google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2 h1:67iHsV9djwGdZpdZNbLuQj6FOzCaZe3w+vhLjn5AcFA= -google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/grpc v1.13.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.22.0 h1:J0UbZOIrCAl+fpTOf8YLs4dJo8L/owV4LYVtAXQoPkw= -google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1 h1:wdKvqQk7IttEw92GoRyKG2IDrUIpgpj6H6m81yfeMW0= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0 h1:2dTRdpdFEEhJYQD8EMLB61nnrzSCTbG38PhqdhvOltg= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/server/config/toml.go b/server/config/toml.go index 0463d26a93fb..e556ed57656b 100644 --- a/server/config/toml.go +++ b/server/config/toml.go @@ -5,7 +5,7 @@ import ( "text/template" "github.com/spf13/viper" - cmn "github.com/tendermint/tendermint/libs/common" + tmos "github.com/tendermint/tendermint/libs/os" ) const defaultConfigTemplate = `# This is a TOML config file. @@ -68,5 +68,5 @@ func WriteConfigFile(configFilePath string, config *Config) { panic(err) } - cmn.MustWriteFile(configFilePath, buffer.Bytes(), 0644) + tmos.MustWriteFile(configFilePath, buffer.Bytes(), 0644) } diff --git a/server/start.go b/server/start.go index 8d1388791ad7..8edec4f831c1 100644 --- a/server/start.go +++ b/server/start.go @@ -11,7 +11,7 @@ import ( "github.com/spf13/viper" "github.com/tendermint/tendermint/abci/server" tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands" - cmn "github.com/tendermint/tendermint/libs/common" + tmos "github.com/tendermint/tendermint/libs/os" "github.com/tendermint/tendermint/node" "github.com/tendermint/tendermint/p2p" pvm "github.com/tendermint/tendermint/privval" @@ -114,14 +114,14 @@ func startStandAlone(ctx *Context, appCreator AppCreator) error { err = svr.Start() if err != nil { - cmn.Exit(err.Error()) + tmos.Exit(err.Error()) } - cmn.TrapSignal(ctx.Logger, func() { + tmos.TrapSignal(ctx.Logger, func() { // cleanup err = svr.Stop() if err != nil { - cmn.Exit(err.Error()) + tmos.Exit(err.Error()) } }) diff --git a/server/util.go b/server/util.go index 3926a37f4e68..eb22c230268e 100644 --- a/server/util.go +++ b/server/util.go @@ -91,7 +91,7 @@ func interceptLoadConfig() (conf *cfg.Config, err error) { conf.ProfListenAddress = "localhost:6060" conf.P2P.RecvRate = 5120000 conf.P2P.SendRate = 5120000 - conf.TxIndex.IndexAllTags = true + conf.TxIndex.IndexAllKeys = true conf.Consensus.TimeoutCommit = 5 * time.Second cfg.WriteConfigFile(configFilePath, conf) // Fall through, just so that its parsed into memory. diff --git a/simapp/app.go b/simapp/app.go index 2b5d240c3e5b..c074f8ccce05 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -5,8 +5,8 @@ import ( "os" abci "github.com/tendermint/tendermint/abci/types" - cmn "github.com/tendermint/tendermint/libs/common" "github.com/tendermint/tendermint/libs/log" + tmos "github.com/tendermint/tendermint/libs/os" dbm "github.com/tendermint/tm-db" bam "github.com/cosmos/cosmos-sdk/baseapp" @@ -289,7 +289,7 @@ func NewSimApp( if loadLatest { err := app.LoadLatestVersion(app.keys[bam.MainStoreKey]) if err != nil { - cmn.Exit(err.Error()) + tmos.Exit(err.Error()) } } diff --git a/simapp/sim_bench_test.go b/simapp/sim_bench_test.go index 8e10ccd46517..b09a3a9090fb 100644 --- a/simapp/sim_bench_test.go +++ b/simapp/sim_bench_test.go @@ -5,8 +5,9 @@ import ( "os" "testing" - "github.com/cosmos/cosmos-sdk/x/simulation" abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/x/simulation" ) // Profile with: diff --git a/simapp/utils.go b/simapp/utils.go index 63a07afc9de4..bc3e889fe68c 100644 --- a/simapp/utils.go +++ b/simapp/utils.go @@ -5,7 +5,7 @@ import ( "fmt" "io/ioutil" - cmn "github.com/tendermint/tendermint/libs/common" + tmkv "github.com/tendermint/tendermint/libs/kv" "github.com/tendermint/tendermint/libs/log" dbm "github.com/tendermint/tm-db" @@ -109,7 +109,7 @@ func PrintStats(db dbm.DB) { // GetSimulationLog unmarshals the KVPair's Value to the corresponding type based on the // each's module store key and the prefix bytes of the KVPair's key. -func GetSimulationLog(storeName string, sdr sdk.StoreDecoderRegistry, cdc *codec.Codec, kvAs, kvBs []cmn.KVPair) (log string) { +func GetSimulationLog(storeName string, sdr sdk.StoreDecoderRegistry, cdc *codec.Codec, kvAs, kvBs []tmkv.Pair) (log string) { for i := 0; i < len(kvAs); i++ { if len(kvAs[i].Value) == 0 && len(kvBs[i].Value) == 0 { diff --git a/simapp/utils_test.go b/simapp/utils_test.go index 9d5443b6e7d8..9cadfff0da40 100644 --- a/simapp/utils_test.go +++ b/simapp/utils_test.go @@ -5,40 +5,37 @@ import ( "testing" "github.com/stretchr/testify/require" - - cmn "github.com/tendermint/tendermint/libs/common" + tmkv "github.com/tendermint/tendermint/libs/kv" "github.com/cosmos/cosmos-sdk/codec" - - "github.com/cosmos/cosmos-sdk/x/auth" - sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" ) func TestGetSimulationLog(t *testing.T) { cdc := MakeCodec() decoders := make(sdk.StoreDecoderRegistry) - decoders[auth.StoreKey] = func(cdc *codec.Codec, kvAs, kvBs cmn.KVPair) string { return "10" } + decoders[auth.StoreKey] = func(cdc *codec.Codec, kvAs, kvBs tmkv.Pair) string { return "10" } tests := []struct { store string - kvPairs []cmn.KVPair + kvPairs []tmkv.Pair expectedLog string }{ { "Empty", - []cmn.KVPair{{}}, + []tmkv.Pair{{}}, "", }, { auth.StoreKey, - []cmn.KVPair{{Key: auth.GlobalAccountNumberKey, Value: cdc.MustMarshalBinaryLengthPrefixed(uint64(10))}}, + []tmkv.Pair{{Key: auth.GlobalAccountNumberKey, Value: cdc.MustMarshalBinaryLengthPrefixed(uint64(10))}}, "10", }, { "OtherStore", - []cmn.KVPair{{Key: []byte("key"), Value: []byte("value")}}, + []tmkv.Pair{{Key: []byte("key"), Value: []byte("value")}}, fmt.Sprintf("store A %X => %X\nstore B %X => %X\n", []byte("key"), []byte("value"), []byte("key"), []byte("value")), }, } diff --git a/store/cache/cache_test.go b/store/cache/cache_test.go index c430e33678fe..9dd4ff905b18 100644 --- a/store/cache/cache_test.go +++ b/store/cache/cache_test.go @@ -18,7 +18,9 @@ func TestGetOrSetStoreCache(t *testing.T) { mngr := cache.NewCommitKVStoreCacheManager(cache.DefaultCommitKVStoreCacheSize) sKey := types.NewKVStoreKey("test") - store := iavlstore.UnsafeNewStore(iavl.NewMutableTree(db, 100), 10, 10) + tree, err := iavl.NewMutableTree(db, 100) + require.NoError(t, err) + store := iavlstore.UnsafeNewStore(tree, 10, 10) store2 := mngr.GetStoreCache(sKey, store) require.NotNil(t, store2) @@ -30,7 +32,9 @@ func TestUnwrap(t *testing.T) { mngr := cache.NewCommitKVStoreCacheManager(cache.DefaultCommitKVStoreCacheSize) sKey := types.NewKVStoreKey("test") - store := iavlstore.UnsafeNewStore(iavl.NewMutableTree(db, 100), 10, 10) + tree, err := iavl.NewMutableTree(db, 100) + require.NoError(t, err) + store := iavlstore.UnsafeNewStore(tree, 10, 10) _ = mngr.GetStoreCache(sKey, store) require.Equal(t, store, mngr.Unwrap(sKey)) @@ -42,7 +46,9 @@ func TestStoreCache(t *testing.T) { mngr := cache.NewCommitKVStoreCacheManager(cache.DefaultCommitKVStoreCacheSize) sKey := types.NewKVStoreKey("test") - store := iavlstore.UnsafeNewStore(iavl.NewMutableTree(db, 100), 10, 10) + tree, err := iavl.NewMutableTree(db, 100) + require.NoError(t, err) + store := iavlstore.UnsafeNewStore(tree, 10, 10) kvStore := mngr.GetStoreCache(sKey, store) for i := uint(0); i < cache.DefaultCommitKVStoreCacheSize*2; i++ { diff --git a/store/cachekv/memiterator.go b/store/cachekv/memiterator.go index 2d1c9c5dac10..d0930b5df83c 100644 --- a/store/cachekv/memiterator.go +++ b/store/cachekv/memiterator.go @@ -2,8 +2,9 @@ package cachekv import ( "container/list" + "errors" - cmn "github.com/tendermint/tendermint/libs/common" + tmkv "github.com/tendermint/tendermint/libs/kv" dbm "github.com/tendermint/tm-db" ) @@ -12,15 +13,15 @@ import ( // Implements Iterator. type memIterator struct { start, end []byte - items []*cmn.KVPair + items []*tmkv.Pair ascending bool } func newMemIterator(start, end []byte, items *list.List, ascending bool) *memIterator { - itemsInDomain := make([]*cmn.KVPair, 0) + itemsInDomain := make([]*tmkv.Pair, 0) var entered bool for e := items.Front(); e != nil; e = e.Next() { - item := e.Value.(*cmn.KVPair) + item := e.Value.(*tmkv.Pair) if !dbm.IsKeyInDomain(item.Key, start, end) { if entered { break @@ -48,8 +49,8 @@ func (mi *memIterator) Valid() bool { } func (mi *memIterator) assertValid() { - if !mi.Valid() { - panic("memIterator is invalid") + if err := mi.Error(); err != nil { + panic(err) } } @@ -83,3 +84,13 @@ func (mi *memIterator) Close() { mi.end = nil mi.items = nil } + +// Error returns an error if the memIterator is invalid defined by the Valid +// method. +func (mi *memIterator) Error() error { + if !mi.Valid() { + return errors.New("invalid memIterator") + } + + return nil +} diff --git a/store/cachekv/mergeiterator.go b/store/cachekv/mergeiterator.go index d45303e074e0..2a85a5461fb4 100644 --- a/store/cachekv/mergeiterator.go +++ b/store/cachekv/mergeiterator.go @@ -2,6 +2,7 @@ package cachekv import ( "bytes" + "errors" "github.com/cosmos/cosmos-sdk/store/types" ) @@ -149,6 +150,24 @@ func (iter *cacheMergeIterator) Close() { iter.cache.Close() } +// Error returns an error if the cacheMergeIterator is invalid defined by the +// Valid method. +func (iter *cacheMergeIterator) Error() error { + if !iter.Valid() { + return errors.New("invalid cacheMergeIterator") + } + + return nil +} + +// If not valid, panics. +// NOTE: May have side-effect of iterating over cache. +func (iter *cacheMergeIterator) assertValid() { + if err := iter.Error(); err != nil { + panic(err) + } +} + // Like bytes.Compare but opposite if not ascending. func (iter *cacheMergeIterator) compare(a, b []byte) int { if iter.ascending { @@ -176,7 +195,6 @@ func (iter *cacheMergeIterator) skipCacheDeletes(until []byte) { // Returns whether the iterator is valid. func (iter *cacheMergeIterator) skipUntilExistsOrInvalid() bool { for { - // If parent is invalid, fast-forward cache. if !iter.parent.Valid() { iter.skipCacheDeletes(nil) @@ -224,11 +242,3 @@ func (iter *cacheMergeIterator) skipUntilExistsOrInvalid() bool { } } } - -// If not valid, panics. -// NOTE: May have side-effect of iterating over cache. -func (iter *cacheMergeIterator) assertValid() { - if !iter.Valid() { - panic("iterator is invalid") - } -} diff --git a/store/cachekv/store.go b/store/cachekv/store.go index d60cd2bf4a1e..fa9b42d60002 100644 --- a/store/cachekv/store.go +++ b/store/cachekv/store.go @@ -7,12 +7,11 @@ import ( "sort" "sync" - cmn "github.com/tendermint/tendermint/libs/common" + tmkv "github.com/tendermint/tendermint/libs/kv" dbm "github.com/tendermint/tm-db" - "github.com/cosmos/cosmos-sdk/store/types" - "github.com/cosmos/cosmos-sdk/store/tracekv" + "github.com/cosmos/cosmos-sdk/store/types" ) // If value is nil but deleted is false, it means the parent doesn't have the @@ -175,12 +174,12 @@ func (store *Store) iterator(start, end []byte, ascending bool) types.Iterator { // Constructs a slice of dirty items, to use w/ memIterator. func (store *Store) dirtyItems(start, end []byte) { - unsorted := make([]*cmn.KVPair, 0) + unsorted := make([]*tmkv.Pair, 0) for key := range store.unsortedCache { cacheValue := store.cache[key] if dbm.IsKeyInDomain([]byte(key), start, end) { - unsorted = append(unsorted, &cmn.KVPair{Key: []byte(key), Value: cacheValue.value}) + unsorted = append(unsorted, &tmkv.Pair{Key: []byte(key), Value: cacheValue.value}) delete(store.unsortedCache, key) } } @@ -191,7 +190,7 @@ func (store *Store) dirtyItems(start, end []byte) { for e := store.sortedCache.Front(); e != nil && len(unsorted) != 0; { uitem := unsorted[0] - sitem := e.Value.(*cmn.KVPair) + sitem := e.Value.(*tmkv.Pair) comp := bytes.Compare(uitem.Key, sitem.Key) switch comp { case -1: diff --git a/store/cachekv/store_test.go b/store/cachekv/store_test.go index 3074ae4fa2b1..f53940d9c47a 100644 --- a/store/cachekv/store_test.go +++ b/store/cachekv/store_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/stretchr/testify/require" - cmn "github.com/tendermint/tendermint/libs/common" + tmrand "github.com/tendermint/tendermint/libs/rand" dbm "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/store/cachekv" @@ -318,7 +318,7 @@ const ( ) func randInt(n int) int { - return cmn.RandInt() % n + return tmrand.NewRand().Int() % n } // useful for replaying a error case if we find one @@ -387,7 +387,8 @@ func assertIterateDomain(t *testing.T, st types.KVStore, expectedN int) { func assertIterateDomainCheck(t *testing.T, st types.KVStore, mem dbm.DB, r []keyRange) { // iterate over each and check they match the other itr := st.Iterator(nil, nil) - itr2 := mem.Iterator(nil, nil) // ground truth + itr2, err := mem.Iterator(nil, nil) // ground truth + require.NoError(t, err) krc := newKeyRangeCounter(r) i := 0 @@ -417,7 +418,8 @@ func assertIterateDomainCheck(t *testing.T, st types.KVStore, mem dbm.DB, r []ke func assertIterateDomainCompare(t *testing.T, st types.KVStore, mem dbm.DB) { // iterate over each and check they match the other itr := st.Iterator(nil, nil) - itr2 := mem.Iterator(nil, nil) // ground truth + itr2, err := mem.Iterator(nil, nil) // ground truth + require.NoError(t, err) checkIterators(t, itr, itr2) checkIterators(t, itr2, itr) } diff --git a/store/dbadapter/store.go b/store/dbadapter/store.go index d7a5c4f3437d..0c281c272a59 100644 --- a/store/dbadapter/store.go +++ b/store/dbadapter/store.go @@ -15,6 +15,60 @@ type Store struct { dbm.DB } +// Get wraps the underlying DB's Get method panicing on error. +func (dsa Store) Get(key []byte) []byte { + v, err := dsa.DB.Get(key) + if err != nil { + panic(err) + } + + return v +} + +// Has wraps the underlying DB's Has method panicing on error. +func (dsa Store) Has(key []byte) bool { + ok, err := dsa.DB.Has(key) + if err != nil { + panic(err) + } + + return ok +} + +// Set wraps the underlying DB's Set method panicing on error. +func (dsa Store) Set(key, value []byte) { + if err := dsa.DB.Set(key, value); err != nil { + panic(err) + } +} + +// Delete wraps the underlying DB's Delete method panicing on error. +func (dsa Store) Delete(key []byte) { + if err := dsa.DB.Delete(key); err != nil { + panic(err) + } +} + +// Iterator wraps the underlying DB's Iterator method panicing on error. +func (dsa Store) Iterator(start, end []byte) types.Iterator { + iter, err := dsa.DB.Iterator(start, end) + if err != nil { + panic(err) + } + + return iter +} + +// ReverseIterator wraps the underlying DB's ReverseIterator method panicing on error. +func (dsa Store) ReverseIterator(start, end []byte) types.Iterator { + iter, err := dsa.DB.ReverseIterator(start, end) + if err != nil { + panic(err) + } + + return iter +} + // GetStoreType returns the type of the store. func (Store) GetStoreType() types.StoreType { return types.StoreTypeDB diff --git a/store/firstlast.go b/store/firstlast.go index 708a7d0d3dce..05a9a5fd85e2 100644 --- a/store/firstlast.go +++ b/store/firstlast.go @@ -3,28 +3,28 @@ package store import ( "bytes" - cmn "github.com/tendermint/tendermint/libs/common" + tmkv "github.com/tendermint/tendermint/libs/kv" "github.com/cosmos/cosmos-sdk/store/types" ) // Gets the first item. -func First(st KVStore, start, end []byte) (kv cmn.KVPair, ok bool) { +func First(st KVStore, start, end []byte) (kv tmkv.Pair, ok bool) { iter := st.Iterator(start, end) if !iter.Valid() { return kv, false } defer iter.Close() - return cmn.KVPair{Key: iter.Key(), Value: iter.Value()}, true + return tmkv.Pair{Key: iter.Key(), Value: iter.Value()}, true } // Gets the last item. `end` is exclusive. -func Last(st KVStore, start, end []byte) (kv cmn.KVPair, ok bool) { +func Last(st KVStore, start, end []byte) (kv tmkv.Pair, ok bool) { iter := st.ReverseIterator(end, start) if !iter.Valid() { if v := st.Get(start); v != nil { - return cmn.KVPair{Key: types.Cp(start), Value: types.Cp(v)}, true + return tmkv.Pair{Key: types.Cp(start), Value: types.Cp(v)}, true } return kv, false } @@ -38,5 +38,5 @@ func Last(st KVStore, start, end []byte) (kv cmn.KVPair, ok bool) { } } - return cmn.KVPair{Key: iter.Key(), Value: iter.Value()}, true + return tmkv.Pair{Key: iter.Key(), Value: iter.Value()}, true } diff --git a/store/gaskv/store.go b/store/gaskv/store.go index e6bdbdc21ad5..3b611a4ed114 100644 --- a/store/gaskv/store.go +++ b/store/gaskv/store.go @@ -160,6 +160,11 @@ func (gi *gasIterator) Close() { gi.parent.Close() } +// Error delegates the Error call to the parent iterator. +func (gi *gasIterator) Error() error { + return gi.parent.Error() +} + // consumeSeekGas consumes a flat gas cost for seeking and a variable gas cost // based on the current value's length. func (gi *gasIterator) consumeSeekGas() { diff --git a/store/iavl/store.go b/store/iavl/store.go index 2faf786cd236..4a346a65d7b9 100644 --- a/store/iavl/store.go +++ b/store/iavl/store.go @@ -4,17 +4,17 @@ import ( "io" "sync" - "github.com/cosmos/cosmos-sdk/store/cachekv" - "github.com/cosmos/cosmos-sdk/store/tracekv" - "github.com/cosmos/cosmos-sdk/store/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/pkg/errors" "github.com/tendermint/iavl" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto/merkle" - cmn "github.com/tendermint/tendermint/libs/common" + tmkv "github.com/tendermint/tendermint/libs/kv" dbm "github.com/tendermint/tm-db" + + "github.com/cosmos/cosmos-sdk/store/cachekv" + "github.com/cosmos/cosmos-sdk/store/tracekv" + "github.com/cosmos/cosmos-sdk/store/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) const ( @@ -49,9 +49,11 @@ type Store struct { // store's version (id) from the provided DB. An error is returned if the version // fails to load. func LoadStore(db dbm.DB, id types.CommitID, pruning types.PruningOptions, lazyLoading bool) (types.CommitKVStore, error) { - tree := iavl.NewMutableTree(db, defaultIAVLCacheSize) + tree, err := iavl.NewMutableTree(db, defaultIAVLCacheSize) + if err != nil { + return nil, err + } - var err error if lazyLoading { _, err = tree.LazyLoadVersion(id.Version) } else { @@ -250,7 +252,7 @@ func (st *Store) Query(req abci.RequestQuery) (res abci.ResponseQuery) { res.Key = key if !st.VersionExists(res.Height) { - res.Log = cmn.ErrorWrap(iavl.ErrVersionDoesNotExist, "").Error() + res.Log = iavl.ErrVersionDoesNotExist.Error() break } @@ -269,11 +271,11 @@ func (st *Store) Query(req abci.RequestQuery) (res abci.ResponseQuery) { if value != nil { // value was found res.Value = value - res.Proof = &merkle.Proof{Ops: []merkle.ProofOp{iavl.NewIAVLValueOp(key, proof).ProofOp()}} + res.Proof = &merkle.Proof{Ops: []merkle.ProofOp{iavl.NewValueOp(key, proof).ProofOp()}} } else { // value wasn't found res.Value = nil - res.Proof = &merkle.Proof{Ops: []merkle.ProofOp{iavl.NewIAVLAbsenceOp(key, proof).ProofOp()}} + res.Proof = &merkle.Proof{Ops: []merkle.ProofOp{iavl.NewAbsenceOp(key, proof).ProofOp()}} } } else { _, res.Value = tree.GetVersioned(key, res.Height) @@ -314,7 +316,7 @@ type iavlIterator struct { tree *iavl.ImmutableTree // Channel to push iteration values. - iterCh chan cmn.KVPair + iterCh chan tmkv.Pair // Close this to release goroutine. quitCh chan struct{} @@ -340,7 +342,7 @@ func newIAVLIterator(tree *iavl.ImmutableTree, start, end []byte, ascending bool start: types.Cp(start), end: types.Cp(end), ascending: ascending, - iterCh: make(chan cmn.KVPair), // Set capacity > 0? + iterCh: make(chan tmkv.Pair), // Set capacity > 0? quitCh: make(chan struct{}), initCh: make(chan struct{}), } @@ -357,7 +359,7 @@ func (iter *iavlIterator) iterateRoutine() { select { case <-iter.quitCh: return true // done with iteration. - case iter.iterCh <- cmn.KVPair{Key: key, Value: value}: + case iter.iterCh <- tmkv.Pair{Key: key, Value: value}: return false // yay. } }, @@ -427,6 +429,11 @@ func (iter *iavlIterator) Close() { } } +// Error performs a no-op. +func (iter *iavlIterator) Error() error { + return nil +} + //---------------------------------------- func (iter *iavlIterator) setNext(key, value []byte) { diff --git a/store/iavl/store_test.go b/store/iavl/store_test.go index d7c38aa0d548..9edebc1e98fc 100644 --- a/store/iavl/store_test.go +++ b/store/iavl/store_test.go @@ -1,14 +1,13 @@ package iavl import ( + crand "crypto/rand" "fmt" "testing" "github.com/stretchr/testify/require" - "github.com/tendermint/iavl" abci "github.com/tendermint/tendermint/abci/types" - cmn "github.com/tendermint/tendermint/libs/common" dbm "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/store/types" @@ -28,19 +27,31 @@ var ( nMoreData = 0 ) +func randBytes(numBytes int) []byte { + b := make([]byte, numBytes) + _, _ = crand.Read(b) + + return b +} + // make a tree with data from above and save it func newAlohaTree(t *testing.T, db dbm.DB) (*iavl.MutableTree, types.CommitID) { - tree := iavl.NewMutableTree(db, cacheSize) + tree, err := iavl.NewMutableTree(db, cacheSize) + require.NoError(t, err) + for k, v := range treeData { tree.Set([]byte(k), []byte(v)) } + for i := 0; i < nMoreData; i++ { - key := cmn.RandBytes(12) - value := cmn.RandBytes(50) + key := randBytes(12) + value := randBytes(50) tree.Set(key, value) } + hash, ver, err := tree.SaveVersion() require.Nil(t, err) + return tree, types.CommitID{Version: ver, Hash: hash} } @@ -204,7 +215,10 @@ func TestIAVLIterator(t *testing.T) { func TestIAVLReverseIterator(t *testing.T) { db := dbm.NewMemDB() - tree := iavl.NewMutableTree(db, cacheSize) + + tree, err := iavl.NewMutableTree(db, cacheSize) + require.NoError(t, err) + iavlStore := UnsafeNewStore(tree, numRecent, storeEvery) iavlStore.Set([]byte{0x00}, []byte("0")) @@ -235,7 +249,9 @@ func TestIAVLReverseIterator(t *testing.T) { func TestIAVLPrefixIterator(t *testing.T) { db := dbm.NewMemDB() - tree := iavl.NewMutableTree(db, cacheSize) + tree, err := iavl.NewMutableTree(db, cacheSize) + require.NoError(t, err) + iavlStore := UnsafeNewStore(tree, numRecent, storeEvery) iavlStore.Set([]byte("test1"), []byte("test1")) @@ -297,7 +313,9 @@ func TestIAVLPrefixIterator(t *testing.T) { func TestIAVLReversePrefixIterator(t *testing.T) { db := dbm.NewMemDB() - tree := iavl.NewMutableTree(db, cacheSize) + tree, err := iavl.NewMutableTree(db, cacheSize) + require.NoError(t, err) + iavlStore := UnsafeNewStore(tree, numRecent, storeEvery) iavlStore.Set([]byte("test1"), []byte("test1")) @@ -416,59 +434,75 @@ type pruneState struct { func testPruning(t *testing.T, numRecent int64, storeEvery int64, states []pruneState) { db := dbm.NewMemDB() - tree := iavl.NewMutableTree(db, cacheSize) + tree, err := iavl.NewMutableTree(db, cacheSize) + require.NoError(t, err) + iavlStore := UnsafeNewStore(tree, numRecent, storeEvery) + for step, state := range states { for _, ver := range state.stored { require.True(t, iavlStore.VersionExists(ver), "Missing version %d with latest version %d. Should save last %d and every %d", ver, step, numRecent, storeEvery) } + for _, ver := range state.deleted { require.False(t, iavlStore.VersionExists(ver), "Unpruned version %d with latest version %d. Should prune all but last %d and every %d", ver, step, numRecent, storeEvery) } + nextVersion(iavlStore) } } func TestIAVLNoPrune(t *testing.T) { db := dbm.NewMemDB() - tree := iavl.NewMutableTree(db, cacheSize) + tree, err := iavl.NewMutableTree(db, cacheSize) + require.NoError(t, err) + iavlStore := UnsafeNewStore(tree, numRecent, int64(1)) nextVersion(iavlStore) + for i := 1; i < 100; i++ { for j := 1; j <= i; j++ { require.True(t, iavlStore.VersionExists(int64(j)), "Missing version %d with latest version %d. Should be storing all versions", j, i) } + nextVersion(iavlStore) } } func TestIAVLPruneEverything(t *testing.T) { db := dbm.NewMemDB() - tree := iavl.NewMutableTree(db, cacheSize) + tree, err := iavl.NewMutableTree(db, cacheSize) + require.NoError(t, err) + iavlStore := UnsafeNewStore(tree, int64(0), int64(0)) nextVersion(iavlStore) + for i := 1; i < 100; i++ { for j := 1; j < i; j++ { require.False(t, iavlStore.VersionExists(int64(j)), "Unpruned version %d with latest version %d. Should prune all old versions", j, i) } + require.True(t, iavlStore.VersionExists(int64(i)), "Missing current version on step %d, should not prune current state tree", i) + nextVersion(iavlStore) } } func TestIAVLStoreQuery(t *testing.T) { db := dbm.NewMemDB() - tree := iavl.NewMutableTree(db, cacheSize) + tree, err := iavl.NewMutableTree(db, cacheSize) + require.NoError(t, err) + iavlStore := UnsafeNewStore(tree, numRecent, storeEvery) k1, v1 := []byte("key1"), []byte("val1") @@ -559,17 +593,22 @@ func TestIAVLStoreQuery(t *testing.T) { func BenchmarkIAVLIteratorNext(b *testing.B) { db := dbm.NewMemDB() treeSize := 1000 - tree := iavl.NewMutableTree(db, cacheSize) + tree, err := iavl.NewMutableTree(db, cacheSize) + require.NoError(b, err) + for i := 0; i < treeSize; i++ { - key := cmn.RandBytes(4) - value := cmn.RandBytes(50) + key := randBytes(4) + value := randBytes(50) tree.Set(key, value) } + iavlStore := UnsafeNewStore(tree, numRecent, storeEvery) iterators := make([]types.Iterator, b.N/treeSize) + for i := 0; i < len(iterators); i++ { iterators[i] = iavlStore.Iterator([]byte{0}, []byte{255, 255, 255, 255, 255}) } + b.ResetTimer() for i := 0; i < len(iterators); i++ { iter := iterators[i] diff --git a/store/prefix/store.go b/store/prefix/store.go index 1b69787f721c..81a42e42f003 100644 --- a/store/prefix/store.go +++ b/store/prefix/store.go @@ -2,6 +2,7 @@ package prefix import ( "bytes" + "errors" "io" "github.com/cosmos/cosmos-sdk/store/cachekv" @@ -176,6 +177,16 @@ func (iter *prefixIterator) Close() { iter.iter.Close() } +// Error returns an error if the prefixIterator is invalid defined by the Valid +// method. +func (iter *prefixIterator) Error() error { + if !iter.Valid() { + return errors.New("invalid prefixIterator") + } + + return nil +} + // copied from github.com/tendermint/tendermint/libs/db/prefix_db.go func stripPrefix(key []byte, prefix []byte) []byte { if len(key) < len(prefix) || !bytes.Equal(key[:len(prefix)], prefix) { diff --git a/store/prefix/store_test.go b/store/prefix/store_test.go index 3414daec7cc4..ca1d5f822246 100644 --- a/store/prefix/store_test.go +++ b/store/prefix/store_test.go @@ -88,7 +88,8 @@ func testPrefixStore(t *testing.T, baseStore types.KVStore, prefix []byte) { func TestIAVLStorePrefix(t *testing.T) { db := dbm.NewMemDB() - tree := tiavl.NewMutableTree(db, cacheSize) + tree, err := tiavl.NewMutableTree(db, cacheSize) + require.NoError(t, err) iavlStore := iavl.UnsafeNewStore(tree, numRecent, storeEvery) testPrefixStore(t, iavlStore, []byte("test")) diff --git a/store/rootmulti/proof.go b/store/rootmulti/proof.go index 0c913ee093ab..ad090b706a63 100644 --- a/store/rootmulti/proof.go +++ b/store/rootmulti/proof.go @@ -2,11 +2,11 @@ package rootmulti import ( "bytes" + "errors" "fmt" "github.com/tendermint/iavl" "github.com/tendermint/tendermint/crypto/merkle" - cmn "github.com/tendermint/tendermint/libs/common" ) // MultiStoreProof defines a collection of store proofs in a multi-store @@ -63,7 +63,7 @@ func NewMultiStoreProofOp(key []byte, proof *MultiStoreProof) MultiStoreProofOp // given proof operation. func MultiStoreProofOpDecoder(pop merkle.ProofOp) (merkle.ProofOperator, error) { if pop.Type != ProofOpMultiStore { - return nil, cmn.NewError("unexpected ProofOp.Type; got %v, want %v", pop.Type, ProofOpMultiStore) + return nil, fmt.Errorf("unexpected ProofOp.Type; got %v, want %v", pop.Type, ProofOpMultiStore) } // XXX: a bit strange as we'll discard this, but it works @@ -71,7 +71,7 @@ func MultiStoreProofOpDecoder(pop merkle.ProofOp) (merkle.ProofOperator, error) err := cdc.UnmarshalBinaryLengthPrefixed(pop.Data, &op) if err != nil { - return nil, cmn.ErrorWrap(err, "decoding ProofOp.Data into MultiStoreProofOp") + return nil, fmt.Errorf("decoding ProofOp.Data into MultiStoreProofOp: %w", err) } return NewMultiStoreProofOp(pop.Key, op.Proof), nil @@ -103,7 +103,7 @@ func (op MultiStoreProofOp) GetKey() []byte { // error otherwise. func (op MultiStoreProofOp) Run(args [][]byte) ([][]byte, error) { if len(args) != 1 { - return nil, cmn.NewError("Value size is not 1") + return nil, errors.New("value size is not 1") } value := args[0] @@ -115,11 +115,11 @@ func (op MultiStoreProofOp) Run(args [][]byte) ([][]byte, error) { return [][]byte{root}, nil } - return nil, cmn.NewError("hash mismatch for substore %v: %X vs %X", si.Name, si.Core.CommitID.Hash, value) + return nil, fmt.Errorf("hash mismatch for substore %v: %X vs %X", si.Name, si.Core.CommitID.Hash, value) } } - return nil, cmn.NewError("key %v not found in multistore proof", op.key) + return nil, fmt.Errorf("key %v not found in multistore proof", op.key) } //----------------------------------------------------------------------------- @@ -129,8 +129,8 @@ func (op MultiStoreProofOp) Run(args [][]byte) ([][]byte, error) { func DefaultProofRuntime() (prt *merkle.ProofRuntime) { prt = merkle.NewProofRuntime() prt.RegisterOpDecoder(merkle.ProofOpSimpleValue, merkle.SimpleValueOpDecoder) - prt.RegisterOpDecoder(iavl.ProofOpIAVLValue, iavl.IAVLValueOpDecoder) - prt.RegisterOpDecoder(iavl.ProofOpIAVLAbsence, iavl.IAVLAbsenceOpDecoder) + prt.RegisterOpDecoder(iavl.ProofOpIAVLValue, iavl.ValueOpDecoder) + prt.RegisterOpDecoder(iavl.ProofOpIAVLAbsence, iavl.AbsenceOpDecoder) prt.RegisterOpDecoder(ProofOpMultiStore, MultiStoreProofOpDecoder) return } diff --git a/store/rootmulti/store.go b/store/rootmulti/store.go index 0b22d5442cb0..6e4452518fca 100644 --- a/store/rootmulti/store.go +++ b/store/rootmulti/store.go @@ -592,12 +592,14 @@ func (si storeInfo) Hash() []byte { func getLatestVersion(db dbm.DB) int64 { var latest int64 - latestBytes := db.Get([]byte(latestVersionKey)) - if latestBytes == nil { + latestBytes, err := db.Get([]byte(latestVersionKey)) + if err != nil { + panic(err) + } else if latestBytes == nil { return 0 } - err := cdc.UnmarshalBinaryLengthPrefixed(latestBytes, &latest) + err = cdc.UnmarshalBinaryLengthPrefixed(latestBytes, &latest) if err != nil { panic(err) } @@ -643,14 +645,16 @@ func getCommitInfo(db dbm.DB, ver int64) (commitInfo, error) { // Get from DB. cInfoKey := fmt.Sprintf(commitInfoKeyFmt, ver) - cInfoBytes := db.Get([]byte(cInfoKey)) - if cInfoBytes == nil { - return commitInfo{}, fmt.Errorf("failed to get Store: no data") + cInfoBytes, err := db.Get([]byte(cInfoKey)) + if err != nil { + return commitInfo{}, fmt.Errorf("failed to get commit info: %v", err) + } else if cInfoBytes == nil { + return commitInfo{}, fmt.Errorf("failed to get commit info: no data") } var cInfo commitInfo - err := cdc.UnmarshalBinaryLengthPrefixed(cInfoBytes, &cInfo) + err = cdc.UnmarshalBinaryLengthPrefixed(cInfoBytes, &cInfo) if err != nil { return commitInfo{}, fmt.Errorf("failed to get Store: %v", err) } diff --git a/store/tracekv/store.go b/store/tracekv/store.go index f95c7f5840dc..ef891526fc23 100644 --- a/store/tracekv/store.go +++ b/store/tracekv/store.go @@ -149,6 +149,11 @@ func (ti *traceIterator) Close() { ti.parent.Close() } +// Error delegates the Error call to the parent iterator. +func (ti *traceIterator) Error() error { + return ti.parent.Error() +} + // GetStoreType implements the KVStore interface. It returns the underlying // KVStore type. func (tkv *Store) GetStoreType() types.StoreType { diff --git a/store/types/store.go b/store/types/store.go index 5b5e64742552..377b43909e11 100644 --- a/store/types/store.go +++ b/store/types/store.go @@ -5,7 +5,7 @@ import ( "io" abci "github.com/tendermint/tendermint/abci/types" - cmn "github.com/tendermint/tendermint/libs/common" + tmkv "github.com/tendermint/tendermint/libs/kv" dbm "github.com/tendermint/tm-db" ) @@ -325,7 +325,7 @@ func (key *TransientStoreKey) String() string { //---------------------------------------- // key-value result for iterator queries -type KVPair cmn.KVPair +type KVPair tmkv.Pair //---------------------------------------- diff --git a/store/types/utils.go b/store/types/utils.go index 0c45933ed4a9..3149c07fb61a 100644 --- a/store/types/utils.go +++ b/store/types/utils.go @@ -3,7 +3,7 @@ package types import ( "bytes" - cmn "github.com/tendermint/tendermint/libs/common" + tmkv "github.com/tendermint/tendermint/libs/kv" ) // Iterator over all the keys with a certain prefix in ascending order @@ -18,7 +18,7 @@ func KVStoreReversePrefixIterator(kvs KVStore, prefix []byte) Iterator { // DiffKVStores compares two KVstores and returns all the key/value pairs // that differ from one another. It also skips value comparison for a set of provided prefixes -func DiffKVStores(a KVStore, b KVStore, prefixesToSkip [][]byte) (kvAs, kvBs []cmn.KVPair) { +func DiffKVStores(a KVStore, b KVStore, prefixesToSkip [][]byte) (kvAs, kvBs []tmkv.Pair) { iterA := a.Iterator(nil, nil) iterB := b.Iterator(nil, nil) @@ -26,13 +26,13 @@ func DiffKVStores(a KVStore, b KVStore, prefixesToSkip [][]byte) (kvAs, kvBs []c if !iterA.Valid() && !iterB.Valid() { break } - var kvA, kvB cmn.KVPair + var kvA, kvB tmkv.Pair if iterA.Valid() { - kvA = cmn.KVPair{Key: iterA.Key(), Value: iterA.Value()} + kvA = tmkv.Pair{Key: iterA.Key(), Value: iterA.Value()} iterA.Next() } if iterB.Valid() { - kvB = cmn.KVPair{Key: iterB.Key(), Value: iterB.Value()} + kvB = tmkv.Pair{Key: iterB.Key(), Value: iterB.Value()} iterB.Next() } if !bytes.Equal(kvA.Key, kvB.Key) { diff --git a/tests/test_cover.sh b/tests/test_cover.sh index 208de4ee0a85..24f7804b5162 100644 --- a/tests/test_cover.sh +++ b/tests/test_cover.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -e -PKGS=$(go list ./... | grep -v '/simulation') +PKGS=$(go list ./... | grep -v '/simapp') set -e echo "mode: atomic" > coverage.txt diff --git a/tests/util.go b/tests/util.go index b17ebec1c8de..9b37d12c6988 100644 --- a/tests/util.go +++ b/tests/util.go @@ -27,12 +27,16 @@ func WaitForNextHeightTM(port string) { // Wait for N tendermint blocks to pass using the Tendermint RPC // on localhost func WaitForNextNBlocksTM(n int64, port string) { - // get the latest block and wait for n more url := fmt.Sprintf("http://localhost:%v", port) - cl := tmclient.NewHTTP(url, "/websocket") - resBlock, err := cl.Block(nil) + cl, err := tmclient.NewHTTP(url, "/websocket") + if err != nil { + panic(fmt.Sprintf("failed to create Tendermint HTTP client: %s", err)) + } + var height int64 + + resBlock, err := cl.Block(nil) if err != nil || resBlock.Block == nil { // wait for the first block to exist WaitForHeightTM(1, port) @@ -40,6 +44,7 @@ func WaitForNextNBlocksTM(n int64, port string) { } else { height = resBlock.Block.Height + n } + waitForHeightTM(height, url) } @@ -51,7 +56,11 @@ func WaitForHeightTM(height int64, port string) { } func waitForHeightTM(height int64, url string) { - cl := tmclient.NewHTTP(url, "/websocket") + cl, err := tmclient.NewHTTP(url, "/websocket") + if err != nil { + panic(fmt.Sprintf("failed to create Tendermint HTTP client: %s", err)) + } + for { // get url, try a few times var resBlock *ctypes.ResultBlock @@ -177,7 +186,11 @@ func WaitForStart(url string) { // Wait for the RPC server to respond to /status func WaitForRPC(laddr string) { fmt.Println("LADDR", laddr) - client := rpcclient.NewJSONRPCClient(laddr) + client, err := rpcclient.NewJSONRPCClient(laddr) + if err != nil { + panic(fmt.Sprintf("failed to create Tendermint RPC client: %s", err)) + } + ctypes.RegisterAmino(client.Codec()) result := new(ctypes.ResultStatus) for { diff --git a/types/events.go b/types/events.go index a3f974275743..10723931e9cd 100644 --- a/types/events.go +++ b/types/events.go @@ -6,7 +6,7 @@ import ( "strings" abci "github.com/tendermint/tendermint/abci/types" - cmn "github.com/tendermint/tendermint/libs/common" + tmkv "github.com/tendermint/tendermint/libs/kv" ) // ---------------------------------------------------------------------------- @@ -86,8 +86,8 @@ func (a Attribute) String() string { } // ToKVPair converts an Attribute object into a Tendermint key/value pair. -func (a Attribute) ToKVPair() cmn.KVPair { - return cmn.KVPair{Key: toBytes(a.Key), Value: toBytes(a.Value)} +func (a Attribute) ToKVPair() tmkv.Pair { + return tmkv.Pair{Key: toBytes(a.Key), Value: toBytes(a.Value)} } // AppendAttributes adds one or more attributes to an Event. diff --git a/types/result_test.go b/types/result_test.go index bbdf3b75e70a..992045778654 100644 --- a/types/result_test.go +++ b/types/result_test.go @@ -3,8 +3,9 @@ package types import ( "testing" - "github.com/cosmos/cosmos-sdk/codec" "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/codec" ) func TestParseABCILog(t *testing.T) { diff --git a/types/store.go b/types/store.go index 1c50444c0efd..ce890f2f6f75 100644 --- a/types/store.go +++ b/types/store.go @@ -1,7 +1,7 @@ package types import ( - cmn "github.com/tendermint/tendermint/libs/common" + tmkv "github.com/tendermint/tendermint/libs/kv" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/types" @@ -28,7 +28,7 @@ type ( // StoreDecoderRegistry defines each of the modules store decoders. Used for ImportExport // simulation. -type StoreDecoderRegistry map[string]func(cdc *codec.Codec, kvA, kvB cmn.KVPair) string +type StoreDecoderRegistry map[string]func(cdc *codec.Codec, kvA, kvB tmkv.Pair) string // Iterator over all the keys with a certain prefix in ascending order func KVStorePrefixIterator(kvs KVStore, prefix []byte) Iterator { @@ -54,7 +54,7 @@ func KVStoreReversePrefixIteratorPaginated(kvs KVStore, prefix []byte, page, lim // DiffKVStores compares two KVstores and returns all the key/value pairs // that differ from one another. It also skips value comparison for a set of provided prefixes -func DiffKVStores(a KVStore, b KVStore, prefixesToSkip [][]byte) (kvAs, kvBs []cmn.KVPair) { +func DiffKVStores(a KVStore, b KVStore, prefixesToSkip [][]byte) (kvAs, kvBs []tmkv.Pair) { return types.DiffKVStores(a, b, prefixesToSkip) } diff --git a/x/auth/client/cli/query.go b/x/auth/client/cli/query.go index 8688d0e8d6df..08e796218bb0 100644 --- a/x/auth/client/cli/query.go +++ b/x/auth/client/cli/query.go @@ -22,8 +22,6 @@ import ( const ( flagEvents = "events" - flagPage = "page" - flagLimit = "limit" eventFormat = "{eventType}.{eventAttribute}={value}" ) @@ -116,8 +114,8 @@ $ %s query txs --%s 'message.sender=cosmos1...&message.action=withdraw_delegator tmEvents = append(tmEvents, event) } - page := viper.GetInt(flagPage) - limit := viper.GetInt(flagLimit) + page := viper.GetInt(flags.FlagPage) + limit := viper.GetInt(flags.FlagLimit) cliCtx := context.NewCLIContext().WithCodec(cdc) txs, err := utils.QueryTxsByEvents(cliCtx, tmEvents, page, limit) @@ -148,8 +146,8 @@ $ %s query txs --%s 'message.sender=cosmos1...&message.action=withdraw_delegator viper.BindPFlag(flags.FlagTrustNode, cmd.Flags().Lookup(flags.FlagTrustNode)) cmd.Flags().String(flagEvents, "", fmt.Sprintf("list of transaction events in the form of %s", eventFormat)) - cmd.Flags().Uint32(flagPage, rest.DefaultPage, "Query a specific page of paginated results") - cmd.Flags().Uint32(flagLimit, rest.DefaultLimit, "Query number of transactions results per page returned") + cmd.Flags().Uint32(flags.FlagPage, rest.DefaultPage, "Query a specific page of paginated results") + cmd.Flags().Uint32(flags.FlagLimit, rest.DefaultLimit, "Query number of transactions results per page returned") cmd.MarkFlagRequired(flagEvents) return cmd diff --git a/x/auth/simulation/decoder.go b/x/auth/simulation/decoder.go index 933421630bb9..725d82fc0a64 100644 --- a/x/auth/simulation/decoder.go +++ b/x/auth/simulation/decoder.go @@ -4,7 +4,7 @@ import ( "bytes" "fmt" - cmn "github.com/tendermint/tendermint/libs/common" + tmkv "github.com/tendermint/tendermint/libs/kv" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/x/auth/exported" @@ -12,7 +12,7 @@ import ( ) // DecodeStore unmarshals the KVPair's Value to the corresponding auth type -func DecodeStore(cdc *codec.Codec, kvA, kvB cmn.KVPair) string { +func DecodeStore(cdc *codec.Codec, kvA, kvB tmkv.Pair) string { switch { case bytes.Equal(kvA.Key[:1], types.AddressStoreKeyPrefix): var accA, accB exported.Account diff --git a/x/auth/simulation/decoder_test.go b/x/auth/simulation/decoder_test.go index 0023b66951fa..2ef143f15ef9 100644 --- a/x/auth/simulation/decoder_test.go +++ b/x/auth/simulation/decoder_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/crypto/ed25519" - cmn "github.com/tendermint/tendermint/libs/common" + tmkv "github.com/tendermint/tendermint/libs/kv" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" @@ -32,10 +32,10 @@ func TestDecodeStore(t *testing.T) { acc := types.NewBaseAccountWithAddress(delAddr1) globalAccNumber := uint64(10) - kvPairs := cmn.KVPairs{ - cmn.KVPair{Key: types.AddressStoreKey(delAddr1), Value: cdc.MustMarshalBinaryBare(acc)}, - cmn.KVPair{Key: types.GlobalAccountNumberKey, Value: cdc.MustMarshalBinaryLengthPrefixed(globalAccNumber)}, - cmn.KVPair{Key: []byte{0x99}, Value: []byte{0x99}}, + kvPairs := tmkv.Pairs{ + tmkv.Pair{Key: types.AddressStoreKey(delAddr1), Value: cdc.MustMarshalBinaryBare(acc)}, + tmkv.Pair{Key: types.GlobalAccountNumberKey, Value: cdc.MustMarshalBinaryLengthPrefixed(globalAccNumber)}, + tmkv.Pair{Key: []byte{0x99}, Value: []byte{0x99}}, } tests := []struct { name string diff --git a/x/bank/app_test.go b/x/bank/app_test.go index 9ec1bdfaa3f3..7a9894aa8c3b 100644 --- a/x/bank/app_test.go +++ b/x/bank/app_test.go @@ -3,9 +3,10 @@ package bank_test import ( "testing" + "github.com/stretchr/testify/require" + "github.com/cosmos/cosmos-sdk/x/distribution" "github.com/cosmos/cosmos-sdk/x/supply" - "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" diff --git a/x/bank/internal/keeper/keeper_test.go b/x/bank/internal/keeper/keeper_test.go index f028f054f840..92da5be72f6d 100644 --- a/x/bank/internal/keeper/keeper_test.go +++ b/x/bank/internal/keeper/keeper_test.go @@ -4,12 +4,9 @@ import ( "testing" "time" - "github.com/cosmos/cosmos-sdk/x/supply" - "github.com/tendermint/tendermint/libs/common" - "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" + tmkv "github.com/tendermint/tendermint/libs/kv" tmtime "github.com/tendermint/tendermint/types/time" "github.com/cosmos/cosmos-sdk/simapp" @@ -18,6 +15,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth/vesting" keep "github.com/cosmos/cosmos-sdk/x/bank/internal/keeper" "github.com/cosmos/cosmos-sdk/x/bank/internal/types" + "github.com/cosmos/cosmos-sdk/x/supply" ) func TestKeeper(t *testing.T) { @@ -168,21 +166,21 @@ func TestMsgSendEvents(t *testing.T) { require.Equal(t, 2, len(events)) event1 := sdk.Event{ Type: types.EventTypeTransfer, - Attributes: []common.KVPair{}, + Attributes: []tmkv.Pair{}, } event1.Attributes = append( event1.Attributes, - common.KVPair{Key: []byte(types.AttributeKeyRecipient), Value: []byte(addr2.String())}) + tmkv.Pair{Key: []byte(types.AttributeKeyRecipient), Value: []byte(addr2.String())}) event1.Attributes = append( event1.Attributes, - common.KVPair{Key: []byte(sdk.AttributeKeyAmount), Value: []byte(newCoins.String())}) + tmkv.Pair{Key: []byte(sdk.AttributeKeyAmount), Value: []byte(newCoins.String())}) event2 := sdk.Event{ Type: sdk.EventTypeMessage, - Attributes: []common.KVPair{}, + Attributes: []tmkv.Pair{}, } event2.Attributes = append( event2.Attributes, - common.KVPair{Key: []byte(types.AttributeKeySender), Value: []byte(addr.String())}) + tmkv.Pair{Key: []byte(types.AttributeKeySender), Value: []byte(addr.String())}) require.Equal(t, event1, events[0]) require.Equal(t, event2, events[1]) diff --git a/x/distribution/simulation/decoder.go b/x/distribution/simulation/decoder.go index d6098a929fe1..79298073a94d 100644 --- a/x/distribution/simulation/decoder.go +++ b/x/distribution/simulation/decoder.go @@ -4,16 +4,15 @@ import ( "bytes" "fmt" - cmn "github.com/tendermint/tendermint/libs/common" + tmkv "github.com/tendermint/tendermint/libs/kv" "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/distribution/types" ) // DecodeStore unmarshals the KVPair's Value to the corresponding distribution type -func DecodeStore(cdc *codec.Codec, kvA, kvB cmn.KVPair) string { +func DecodeStore(cdc *codec.Codec, kvA, kvB tmkv.Pair) string { switch { case bytes.Equal(kvA.Key[:1], types.FeePoolKey): var feePoolA, feePoolB types.FeePool diff --git a/x/distribution/simulation/decoder_test.go b/x/distribution/simulation/decoder_test.go index b804260acaf9..d8c6d719ce9e 100644 --- a/x/distribution/simulation/decoder_test.go +++ b/x/distribution/simulation/decoder_test.go @@ -7,11 +7,10 @@ import ( "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/crypto/ed25519" - cmn "github.com/tendermint/tendermint/libs/common" + tmkv "github.com/tendermint/tendermint/libs/kv" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/distribution/keeper" "github.com/cosmos/cosmos-sdk/x/distribution/types" ) @@ -43,17 +42,17 @@ func TestDecodeDistributionStore(t *testing.T) { currentRewards := types.NewValidatorCurrentRewards(decCoins, 5) slashEvent := types.NewValidatorSlashEvent(10, sdk.OneDec()) - kvPairs := cmn.KVPairs{ - cmn.KVPair{Key: types.FeePoolKey, Value: cdc.MustMarshalBinaryLengthPrefixed(feePool)}, - cmn.KVPair{Key: types.ProposerKey, Value: consAddr1.Bytes()}, - cmn.KVPair{Key: keeper.GetValidatorOutstandingRewardsKey(valAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(outstanding)}, - cmn.KVPair{Key: keeper.GetDelegatorWithdrawAddrKey(delAddr1), Value: delAddr1.Bytes()}, - cmn.KVPair{Key: keeper.GetDelegatorStartingInfoKey(valAddr1, delAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(info)}, - cmn.KVPair{Key: keeper.GetValidatorHistoricalRewardsKey(valAddr1, 100), Value: cdc.MustMarshalBinaryLengthPrefixed(historicalRewards)}, - cmn.KVPair{Key: keeper.GetValidatorCurrentRewardsKey(valAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(currentRewards)}, - cmn.KVPair{Key: keeper.GetValidatorAccumulatedCommissionKey(valAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(commission)}, - cmn.KVPair{Key: keeper.GetValidatorSlashEventKeyPrefix(valAddr1, 13), Value: cdc.MustMarshalBinaryLengthPrefixed(slashEvent)}, - cmn.KVPair{Key: []byte{0x99}, Value: []byte{0x99}}, + kvPairs := tmkv.Pairs{ + tmkv.Pair{Key: types.FeePoolKey, Value: cdc.MustMarshalBinaryLengthPrefixed(feePool)}, + tmkv.Pair{Key: types.ProposerKey, Value: consAddr1.Bytes()}, + tmkv.Pair{Key: types.GetValidatorOutstandingRewardsKey(valAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(outstanding)}, + tmkv.Pair{Key: types.GetDelegatorWithdrawAddrKey(delAddr1), Value: delAddr1.Bytes()}, + tmkv.Pair{Key: types.GetDelegatorStartingInfoKey(valAddr1, delAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(info)}, + tmkv.Pair{Key: types.GetValidatorHistoricalRewardsKey(valAddr1, 100), Value: cdc.MustMarshalBinaryLengthPrefixed(historicalRewards)}, + tmkv.Pair{Key: types.GetValidatorCurrentRewardsKey(valAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(currentRewards)}, + tmkv.Pair{Key: types.GetValidatorAccumulatedCommissionKey(valAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(commission)}, + tmkv.Pair{Key: types.GetValidatorSlashEventKeyPrefix(valAddr1, 13), Value: cdc.MustMarshalBinaryLengthPrefixed(slashEvent)}, + tmkv.Pair{Key: []byte{0x99}, Value: []byte{0x99}}, } tests := []struct { diff --git a/x/distribution/types/params.go b/x/distribution/types/params.go index 19f781bf2951..ac3387e9c48b 100644 --- a/x/distribution/types/params.go +++ b/x/distribution/types/params.go @@ -3,9 +3,10 @@ package types import ( "fmt" + "gopkg.in/yaml.v2" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/params" - "gopkg.in/yaml.v2" ) const ( diff --git a/x/evidence/client/cli/query.go b/x/evidence/client/cli/query.go index b4a1dffd0af5..da09ae7b4b42 100644 --- a/x/evidence/client/cli/query.go +++ b/x/evidence/client/cli/query.go @@ -17,11 +17,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/evidence/internal/types" ) -const ( - flagPage = "page" - flagLimit = "limit" -) - // GetQueryCmd returns the CLI command with all evidence module query commands // mounted. func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { @@ -44,8 +39,8 @@ $ %s query %s --page=2 --limit=50 RunE: QueryEvidenceCmd(cdc), } - cmd.Flags().Int(flagPage, 1, "pagination page of evidence to to query for") - cmd.Flags().Int(flagLimit, 100, "pagination limit of evidence to query for") + cmd.Flags().Int(flags.FlagPage, 1, "pagination page of evidence to to query for") + cmd.Flags().Int(flags.FlagLimit, 100, "pagination limit of evidence to query for") cmd.AddCommand(flags.GetCommands(QueryParamsCmd(cdc))...) @@ -126,7 +121,7 @@ func queryEvidence(cdc *codec.Codec, cliCtx context.CLIContext, hash string) err } func queryAllEvidence(cdc *codec.Codec, cliCtx context.CLIContext) error { - params := types.NewQueryAllEvidenceParams(viper.GetInt(flagPage), viper.GetInt(flagLimit)) + params := types.NewQueryAllEvidenceParams(viper.GetInt(flags.FlagPage), viper.GetInt(flags.FlagLimit)) bz, err := cdc.MarshalJSON(params) if err != nil { return fmt.Errorf("failed to marshal query params: %w", err) diff --git a/x/evidence/exported/evidence.go b/x/evidence/exported/evidence.go index 1c6adfdf8c0a..55b9ef1671cc 100644 --- a/x/evidence/exported/evidence.go +++ b/x/evidence/exported/evidence.go @@ -3,7 +3,7 @@ package exported import ( sdk "github.com/cosmos/cosmos-sdk/types" - cmn "github.com/tendermint/tendermint/libs/common" + tmbytes "github.com/tendermint/tendermint/libs/bytes" ) // Evidence defines the contract which concrete evidence types of misbehavior @@ -12,7 +12,7 @@ type Evidence interface { Route() string Type() string String() string - Hash() cmn.HexBytes + Hash() tmbytes.HexBytes ValidateBasic() error // The consensus address of the malicious validator at time of infraction diff --git a/x/evidence/internal/keeper/keeper.go b/x/evidence/internal/keeper/keeper.go index fd6c8027d8fd..29a3df0bf374 100644 --- a/x/evidence/internal/keeper/keeper.go +++ b/x/evidence/internal/keeper/keeper.go @@ -3,7 +3,7 @@ package keeper import ( "fmt" - cmn "github.com/tendermint/tendermint/libs/common" + tmbytes "github.com/tendermint/tendermint/libs/bytes" "github.com/tendermint/tendermint/libs/log" "github.com/cosmos/cosmos-sdk/codec" @@ -116,7 +116,7 @@ func (k Keeper) SetEvidence(ctx sdk.Context, evidence exported.Evidence) { // GetEvidence retrieves Evidence by hash if it exists. If no Evidence exists for // the given hash, (nil, false) is returned. -func (k Keeper) GetEvidence(ctx sdk.Context, hash cmn.HexBytes) (evidence exported.Evidence, found bool) { +func (k Keeper) GetEvidence(ctx sdk.Context, hash tmbytes.HexBytes) (evidence exported.Evidence, found bool) { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixEvidence) bz := store.Get(hash) diff --git a/x/evidence/internal/types/codec_test.go b/x/evidence/internal/types/codec_test.go index 1edf6d97cc43..e175a7292e94 100644 --- a/x/evidence/internal/types/codec_test.go +++ b/x/evidence/internal/types/codec_test.go @@ -4,7 +4,7 @@ import ( "testing" "github.com/stretchr/testify/require" - cmn "github.com/tendermint/tendermint/libs/common" + tmbytes "github.com/tendermint/tendermint/libs/bytes" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" @@ -21,7 +21,7 @@ func (te testEvidence) Type() string { return "" } func (te testEvidence) String() string { return "" } func (te testEvidence) ValidateBasic() error { return nil } func (te testEvidence) GetConsensusAddress() sdk.ConsAddress { return nil } -func (te testEvidence) Hash() cmn.HexBytes { return nil } +func (te testEvidence) Hash() tmbytes.HexBytes { return nil } func (te testEvidence) GetHeight() int64 { return 0 } func (te testEvidence) GetValidatorPower() int64 { return 0 } func (te testEvidence) GetTotalPower() int64 { return 0 } diff --git a/x/evidence/internal/types/evidence.go b/x/evidence/internal/types/evidence.go index d4dbfc1eafef..4306acbe0de7 100644 --- a/x/evidence/internal/types/evidence.go +++ b/x/evidence/internal/types/evidence.go @@ -9,7 +9,7 @@ import ( abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto/tmhash" - cmn "github.com/tendermint/tendermint/libs/common" + tmbytes "github.com/tendermint/tendermint/libs/bytes" "gopkg.in/yaml.v2" ) @@ -42,7 +42,7 @@ func (e Equivocation) String() string { } // Hash returns the hash of an Equivocation object. -func (e Equivocation) Hash() cmn.HexBytes { +func (e Equivocation) Hash() tmbytes.HexBytes { return tmhash.Sum(ModuleCdc.MustMarshalBinaryBare(e)) } diff --git a/x/evidence/internal/types/evidence_test.go b/x/evidence/internal/types/evidence_test.go index ad2107b8fa41..8871f553eb7d 100644 --- a/x/evidence/internal/types/evidence_test.go +++ b/x/evidence/internal/types/evidence_test.go @@ -4,9 +4,10 @@ import ( "testing" "time" + "github.com/stretchr/testify/require" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/evidence/internal/types" - "github.com/stretchr/testify/require" ) func TestEquivocation_Valid(t *testing.T) { diff --git a/x/evidence/internal/types/test_util.go b/x/evidence/internal/types/test_util.go index b138a352b971..24500cba993c 100644 --- a/x/evidence/internal/types/test_util.go +++ b/x/evidence/internal/types/test_util.go @@ -19,7 +19,7 @@ import ( "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/tmhash" - cmn "github.com/tendermint/tendermint/libs/common" + tmbytes "github.com/tendermint/tendermint/libs/bytes" ) var ( @@ -38,7 +38,7 @@ type ( Height int64 Round int64 Timestamp time.Time - ValidatorAddress cmn.HexBytes + ValidatorAddress tmbytes.HexBytes Signature []byte } @@ -96,7 +96,7 @@ func (e TestEquivocationEvidence) ValidateBasic() error { return nil } -func (e TestEquivocationEvidence) Hash() cmn.HexBytes { +func (e TestEquivocationEvidence) Hash() tmbytes.HexBytes { return tmhash.Sum(TestingCdc.MustMarshalBinaryBare(e)) } diff --git a/x/genutil/client/cli/gentx.go b/x/genutil/client/cli/gentx.go index 7d0fb75207b2..f76fcc3a36a2 100644 --- a/x/genutil/client/cli/gentx.go +++ b/x/genutil/client/cli/gentx.go @@ -11,14 +11,12 @@ import ( "path/filepath" "github.com/pkg/errors" - "github.com/spf13/cobra" flag "github.com/spf13/pflag" "github.com/spf13/viper" - cfg "github.com/tendermint/tendermint/config" "github.com/tendermint/tendermint/crypto" - "github.com/tendermint/tendermint/libs/common" + tmos "github.com/tendermint/tendermint/libs/os" tmtypes "github.com/tendermint/tendermint/types" "github.com/cosmos/cosmos-sdk/client/context" @@ -29,9 +27,8 @@ import ( "github.com/cosmos/cosmos-sdk/server" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" - "github.com/cosmos/cosmos-sdk/x/auth/client/utils" - "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/auth/client/utils" "github.com/cosmos/cosmos-sdk/x/genutil" "github.com/cosmos/cosmos-sdk/x/genutil/types" ) @@ -199,7 +196,7 @@ func GenTxCmd(ctx *server.Context, cdc *codec.Codec, mbm module.BasicManager, sm func makeOutputFilepath(rootDir, nodeID string) (string, error) { writePath := filepath.Join(rootDir, "config", "gentx") - if err := common.EnsureDir(writePath, 0700); err != nil { + if err := tmos.EnsureDir(writePath, 0700); err != nil { return "", err } return filepath.Join(writePath, fmt.Sprintf("gentx-%v.json", nodeID)), nil diff --git a/x/genutil/client/cli/init.go b/x/genutil/client/cli/init.go index c611556ae8f1..b87691d1d0f2 100644 --- a/x/genutil/client/cli/init.go +++ b/x/genutil/client/cli/init.go @@ -11,7 +11,8 @@ import ( "github.com/spf13/viper" cfg "github.com/tendermint/tendermint/config" "github.com/tendermint/tendermint/libs/cli" - "github.com/tendermint/tendermint/libs/common" + tmos "github.com/tendermint/tendermint/libs/os" + tmrand "github.com/tendermint/tendermint/libs/rand" "github.com/tendermint/tendermint/types" "github.com/cosmos/cosmos-sdk/client/flags" @@ -72,7 +73,7 @@ func InitCmd(ctx *server.Context, cdc *codec.Codec, mbm module.BasicManager, chainID := viper.GetString(flags.FlagChainID) if chainID == "" { - chainID = fmt.Sprintf("test-chain-%v", common.RandStr(6)) + chainID = fmt.Sprintf("test-chain-%v", tmrand.Str(6)) } nodeID, _, err := genutil.InitializeNodeValidatorFiles(config) @@ -83,7 +84,7 @@ func InitCmd(ctx *server.Context, cdc *codec.Codec, mbm module.BasicManager, config.Moniker = args[0] genFile := config.GenesisFile() - if !viper.GetBool(flagOverwrite) && common.FileExists(genFile) { + if !viper.GetBool(flagOverwrite) && tmos.FileExists(genFile) { return fmt.Errorf("genesis.json file already exists: %v", genFile) } appState, err := codec.MarshalJSONIndent(cdc, mbm.DefaultGenesis()) diff --git a/x/genutil/types/genesis_state.go b/x/genutil/types/genesis_state.go index 1303ee82ca4b..6c5c555482ee 100644 --- a/x/genutil/types/genesis_state.go +++ b/x/genutil/types/genesis_state.go @@ -5,7 +5,7 @@ import ( "errors" "fmt" - "github.com/tendermint/tendermint/libs/common" + tmos "github.com/tendermint/tendermint/libs/os" tmtypes "github.com/tendermint/tendermint/types" "github.com/cosmos/cosmos-sdk/codec" @@ -80,7 +80,7 @@ func GenesisStateFromGenDoc(cdc *codec.Codec, genDoc tmtypes.GenesisDoc, func GenesisStateFromGenFile(cdc *codec.Codec, genFile string, ) (genesisState map[string]json.RawMessage, genDoc *tmtypes.GenesisDoc, err error) { - if !common.FileExists(genFile) { + if !tmos.FileExists(genFile) { return genesisState, genDoc, fmt.Errorf("%s does not exist, run `init` first", genFile) } diff --git a/x/genutil/utils.go b/x/genutil/utils.go index 65f27a839a03..7d1a761ef562 100644 --- a/x/genutil/utils.go +++ b/x/genutil/utils.go @@ -7,7 +7,7 @@ import ( cfg "github.com/tendermint/tendermint/config" "github.com/tendermint/tendermint/crypto" - "github.com/tendermint/tendermint/libs/common" + tmos "github.com/tendermint/tendermint/libs/os" "github.com/tendermint/tendermint/p2p" "github.com/tendermint/tendermint/privval" tmtypes "github.com/tendermint/tendermint/types" @@ -59,12 +59,12 @@ func InitializeNodeValidatorFiles(config *cfg.Config, server.UpgradeOldPrivValFile(config) pvKeyFile := config.PrivValidatorKeyFile() - if err := common.EnsureDir(filepath.Dir(pvKeyFile), 0777); err != nil { + if err := tmos.EnsureDir(filepath.Dir(pvKeyFile), 0777); err != nil { return nodeID, valPubKey, nil } pvStateFile := config.PrivValidatorStateFile() - if err := common.EnsureDir(filepath.Dir(pvStateFile), 0777); err != nil { + if err := tmos.EnsureDir(filepath.Dir(pvStateFile), 0777); err != nil { return nodeID, valPubKey, nil } diff --git a/x/gov/client/cli/query.go b/x/gov/client/cli/query.go index 1a0c0a179ef7..52a238dfb48b 100644 --- a/x/gov/client/cli/query.go +++ b/x/gov/client/cli/query.go @@ -103,8 +103,8 @@ $ %s query gov proposals --page=2 --limit=100 bechDepositorAddr := viper.GetString(flagDepositor) bechVoterAddr := viper.GetString(flagVoter) strProposalStatus := viper.GetString(flagStatus) - page := viper.GetInt(flagPage) - limit := viper.GetInt(flagNumLimit) + page := viper.GetInt(flags.FlagPage) + limit := viper.GetInt(flags.FlagLimit) var depositorAddr sdk.AccAddress var voterAddr sdk.AccAddress @@ -162,8 +162,8 @@ $ %s query gov proposals --page=2 --limit=100 }, } - cmd.Flags().Int(flagPage, 1, "pagination page of proposals to to query for") - cmd.Flags().Int(flagNumLimit, 100, "pagination limit of proposals to query for") + cmd.Flags().Int(flags.FlagPage, 1, "pagination page of proposals to to query for") + cmd.Flags().Int(flags.FlagLimit, 100, "pagination limit of proposals to query for") cmd.Flags().String(flagDepositor, "", "(optional) filter by proposals deposited on by depositor") cmd.Flags().String(flagVoter, "", "(optional) filter by proposals voted on by voted") cmd.Flags().String(flagStatus, "", "(optional) filter proposals by proposal status, status: deposit_period/voting_period/passed/rejected") @@ -265,8 +265,9 @@ $ %[1]s query gov votes 1 --page=2 --limit=100 if err != nil { return fmt.Errorf("proposal-id %s not a valid int, please input a valid proposal-id", args[0]) } - page := viper.GetInt(flagPage) - limit := viper.GetInt(flagNumLimit) + + page := viper.GetInt(flags.FlagPage) + limit := viper.GetInt(flags.FlagLimit) params := types.NewQueryProposalVotesParams(proposalID, page, limit) bz, err := cdc.MarshalJSON(params) @@ -299,8 +300,8 @@ $ %[1]s query gov votes 1 --page=2 --limit=100 return cliCtx.PrintOutput(votes) }, } - cmd.Flags().Int(flagPage, 1, "pagination page of votes to to query for") - cmd.Flags().Int(flagNumLimit, 100, "pagination limit of votes to query for") + cmd.Flags().Int(flags.FlagPage, 1, "pagination page of votes to to query for") + cmd.Flags().Int(flags.FlagLimit, 100, "pagination limit of votes to query for") return cmd } diff --git a/x/gov/client/cli/tx.go b/x/gov/client/cli/tx.go index 8c6c1109c9d4..3946f9780c55 100644 --- a/x/gov/client/cli/tx.go +++ b/x/gov/client/cli/tx.go @@ -29,8 +29,6 @@ const ( flagVoter = "voter" flagDepositor = "depositor" flagStatus = "status" - flagNumLimit = "limit" - flagPage = "page" FlagProposal = "proposal" ) diff --git a/x/gov/client/utils/query_test.go b/x/gov/client/utils/query_test.go index 68762b248066..10d4e77c7e57 100644 --- a/x/gov/client/utils/query_test.go +++ b/x/gov/client/utils/query_test.go @@ -3,16 +3,17 @@ package utils import ( "testing" + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/rpc/client/mock" + ctypes "github.com/tendermint/tendermint/rpc/core/types" + tmtypes "github.com/tendermint/tendermint/types" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/cosmos/cosmos-sdk/x/gov/types" - "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/rpc/client/mock" - ctypes "github.com/tendermint/tendermint/rpc/core/types" - tmtypes "github.com/tendermint/tendermint/types" ) type TxSearchMock struct { diff --git a/x/gov/genesis_test.go b/x/gov/genesis_test.go index 8626e7821e5f..02b6eed9b42c 100644 --- a/x/gov/genesis_test.go +++ b/x/gov/genesis_test.go @@ -3,9 +3,10 @@ package gov import ( "testing" - keep "github.com/cosmos/cosmos-sdk/x/gov/keeper" "github.com/stretchr/testify/require" + keep "github.com/cosmos/cosmos-sdk/x/gov/keeper" + abci "github.com/tendermint/tendermint/abci/types" ) diff --git a/x/gov/keeper/keeper_test.go b/x/gov/keeper/keeper_test.go index 9832c6df3ade..5549049e3a35 100644 --- a/x/gov/keeper/keeper_test.go +++ b/x/gov/keeper/keeper_test.go @@ -3,8 +3,9 @@ package keeper import ( "testing" - "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/x/gov/types" ) func TestIncrementProposalNumber(t *testing.T) { diff --git a/x/gov/keeper/proposal_test.go b/x/gov/keeper/proposal_test.go index 67208bef6101..b8f37cbd3649 100644 --- a/x/gov/keeper/proposal_test.go +++ b/x/gov/keeper/proposal_test.go @@ -6,10 +6,11 @@ import ( "testing" "time" + "github.com/stretchr/testify/require" + "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/gov/types" - "github.com/stretchr/testify/require" ) func TestGetSetProposal(t *testing.T) { diff --git a/x/gov/simulation/decoder.go b/x/gov/simulation/decoder.go index 475721e8769e..6e4c3169ac1f 100644 --- a/x/gov/simulation/decoder.go +++ b/x/gov/simulation/decoder.go @@ -5,14 +5,14 @@ import ( "encoding/binary" "fmt" - cmn "github.com/tendermint/tendermint/libs/common" + tmkv "github.com/tendermint/tendermint/libs/kv" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/x/gov/types" ) // DecodeStore unmarshals the KVPair's Value to the corresponding gov type -func DecodeStore(cdc *codec.Codec, kvA, kvB cmn.KVPair) string { +func DecodeStore(cdc *codec.Codec, kvA, kvB tmkv.Pair) string { switch { case bytes.Equal(kvA.Key[:1], types.ProposalsKeyPrefix): var proposalA, proposalB types.Proposal diff --git a/x/gov/simulation/decoder_test.go b/x/gov/simulation/decoder_test.go index ec8f87cdbaa7..025dbeedc71c 100644 --- a/x/gov/simulation/decoder_test.go +++ b/x/gov/simulation/decoder_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/crypto/ed25519" - cmn "github.com/tendermint/tendermint/libs/common" + tmkv "github.com/tendermint/tendermint/libs/kv" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" @@ -41,12 +41,12 @@ func TestDecodeStore(t *testing.T) { deposit := types.NewDeposit(1, delAddr1, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.OneInt()))) vote := types.NewVote(1, delAddr1, types.OptionYes) - kvPairs := cmn.KVPairs{ - cmn.KVPair{Key: types.ProposalKey(1), Value: cdc.MustMarshalBinaryLengthPrefixed(proposal)}, - cmn.KVPair{Key: types.InactiveProposalQueueKey(1, endTime), Value: proposalIDBz}, - cmn.KVPair{Key: types.DepositKey(1, delAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(deposit)}, - cmn.KVPair{Key: types.VoteKey(1, delAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(vote)}, - cmn.KVPair{Key: []byte{0x99}, Value: []byte{0x99}}, + kvPairs := tmkv.Pairs{ + tmkv.Pair{Key: types.ProposalKey(1), Value: cdc.MustMarshalBinaryLengthPrefixed(proposal)}, + tmkv.Pair{Key: types.InactiveProposalQueueKey(1, endTime), Value: proposalIDBz}, + tmkv.Pair{Key: types.DepositKey(1, delAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(deposit)}, + tmkv.Pair{Key: types.VoteKey(1, delAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(vote)}, + tmkv.Pair{Key: []byte{0x99}, Value: []byte{0x99}}, } tests := []struct { diff --git a/x/mint/simulation/decoder.go b/x/mint/simulation/decoder.go index 0f1ab1960989..f1c9f6bda62d 100644 --- a/x/mint/simulation/decoder.go +++ b/x/mint/simulation/decoder.go @@ -4,14 +4,14 @@ import ( "bytes" "fmt" - cmn "github.com/tendermint/tendermint/libs/common" + tmkv "github.com/tendermint/tendermint/libs/kv" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/x/mint/internal/types" ) // DecodeStore unmarshals the KVPair's Value to the corresponding mint type -func DecodeStore(cdc *codec.Codec, kvA, kvB cmn.KVPair) string { +func DecodeStore(cdc *codec.Codec, kvA, kvB tmkv.Pair) string { switch { case bytes.Equal(kvA.Key, types.MinterKey): var minterA, minterB types.Minter diff --git a/x/mint/simulation/decoder_test.go b/x/mint/simulation/decoder_test.go index 853ddc3def4b..f92a84f5df21 100644 --- a/x/mint/simulation/decoder_test.go +++ b/x/mint/simulation/decoder_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/require" - cmn "github.com/tendermint/tendermint/libs/common" + tmkv "github.com/tendermint/tendermint/libs/kv" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" @@ -23,9 +23,9 @@ func TestDecodeStore(t *testing.T) { cdc := makeTestCodec() minter := types.NewMinter(sdk.OneDec(), sdk.NewDec(15)) - kvPairs := cmn.KVPairs{ - cmn.KVPair{Key: types.MinterKey, Value: cdc.MustMarshalBinaryLengthPrefixed(minter)}, - cmn.KVPair{Key: []byte{0x99}, Value: []byte{0x99}}, + kvPairs := tmkv.Pairs{ + tmkv.Pair{Key: types.MinterKey, Value: cdc.MustMarshalBinaryLengthPrefixed(minter)}, + tmkv.Pair{Key: []byte{0x99}, Value: []byte{0x99}}, } tests := []struct { name string diff --git a/x/params/subspace/subspace_test.go b/x/params/subspace/subspace_test.go index 31a5d7635126..05707097d478 100644 --- a/x/params/subspace/subspace_test.go +++ b/x/params/subspace/subspace_test.go @@ -5,14 +5,15 @@ import ( "testing" "time" - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/store" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/params/subspace" "github.com/stretchr/testify/suite" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" dbm "github.com/tendermint/tm-db" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/params/subspace" ) type SubspaceTestSuite struct { diff --git a/x/params/subspace/table_test.go b/x/params/subspace/table_test.go index fc47481a3bea..6bc1a8af2a81 100644 --- a/x/params/subspace/table_test.go +++ b/x/params/subspace/table_test.go @@ -4,8 +4,9 @@ import ( "testing" "time" - "github.com/cosmos/cosmos-sdk/x/params/subspace" "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/x/params/subspace" ) func TestKeyTable(t *testing.T) { diff --git a/x/simulation/mock_tendermint.go b/x/simulation/mock_tendermint.go index d9ab0ecd65ab..349de27b60c2 100644 --- a/x/simulation/mock_tendermint.go +++ b/x/simulation/mock_tendermint.go @@ -8,7 +8,7 @@ import ( "time" abci "github.com/tendermint/tendermint/abci/types" - cmn "github.com/tendermint/tendermint/libs/common" + tmbytes "github.com/tendermint/tendermint/libs/bytes" tmtypes "github.com/tendermint/tendermint/types" ) @@ -61,7 +61,7 @@ func (vals mockValidators) getKeys() []string { //_________________________________________________________________________________ // randomProposer picks a random proposer from the current validator set -func (vals mockValidators) randomProposer(r *rand.Rand) cmn.HexBytes { +func (vals mockValidators) randomProposer(r *rand.Rand) tmbytes.HexBytes { keys := vals.getKeys() if len(keys) == 0 { return nil diff --git a/x/slashing/simulation/decoder.go b/x/slashing/simulation/decoder.go index 89fdc795a795..9aea5f701b15 100644 --- a/x/slashing/simulation/decoder.go +++ b/x/slashing/simulation/decoder.go @@ -5,7 +5,7 @@ import ( "fmt" "github.com/tendermint/tendermint/crypto" - cmn "github.com/tendermint/tendermint/libs/common" + tmkv "github.com/tendermint/tendermint/libs/kv" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" @@ -13,7 +13,7 @@ import ( ) // DecodeStore unmarshals the KVPair's Value to the corresponding slashing type -func DecodeStore(cdc *codec.Codec, kvA, kvB cmn.KVPair) string { +func DecodeStore(cdc *codec.Codec, kvA, kvB tmkv.Pair) string { switch { case bytes.Equal(kvA.Key[:1], types.ValidatorSigningInfoKey): var infoA, infoB types.ValidatorSigningInfo diff --git a/x/slashing/simulation/decoder_test.go b/x/slashing/simulation/decoder_test.go index 23d063110baa..acd3be67c62f 100644 --- a/x/slashing/simulation/decoder_test.go +++ b/x/slashing/simulation/decoder_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/crypto/ed25519" - cmn "github.com/tendermint/tendermint/libs/common" + tmkv "github.com/tendermint/tendermint/libs/kv" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" @@ -38,11 +38,11 @@ func TestDecodeStore(t *testing.T) { bechPK := sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, delPk1) missed := true - kvPairs := cmn.KVPairs{ - cmn.KVPair{Key: types.GetValidatorSigningInfoKey(consAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(info)}, - cmn.KVPair{Key: types.GetValidatorMissedBlockBitArrayKey(consAddr1, 6), Value: cdc.MustMarshalBinaryLengthPrefixed(missed)}, - cmn.KVPair{Key: types.GetAddrPubkeyRelationKey(delAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(delPk1)}, - cmn.KVPair{Key: []byte{0x99}, Value: []byte{0x99}}, + kvPairs := tmkv.Pairs{ + tmkv.Pair{Key: types.GetValidatorSigningInfoKey(consAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(info)}, + tmkv.Pair{Key: types.GetValidatorMissedBlockBitArrayKey(consAddr1, 6), Value: cdc.MustMarshalBinaryLengthPrefixed(missed)}, + tmkv.Pair{Key: types.GetAddrPubkeyRelationKey(delAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(delPk1)}, + tmkv.Pair{Key: []byte{0x99}, Value: []byte{0x99}}, } tests := []struct { diff --git a/x/staking/abci.go b/x/staking/abci.go index 39755c24440c..6e4b1067e923 100644 --- a/x/staking/abci.go +++ b/x/staking/abci.go @@ -1,9 +1,10 @@ package staking import ( + abci "github.com/tendermint/tendermint/abci/types" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/staking/keeper" - abci "github.com/tendermint/tendermint/abci/types" ) // BeginBlocker will persist the current header and validator set as a historical entry diff --git a/x/staking/handler.go b/x/staking/handler.go index da5933930382..180bb8008672 100644 --- a/x/staking/handler.go +++ b/x/staking/handler.go @@ -3,7 +3,7 @@ package staking import ( "time" - "github.com/tendermint/tendermint/libs/common" + tmstrings "github.com/tendermint/tendermint/libs/strings" tmtypes "github.com/tendermint/tendermint/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -61,7 +61,7 @@ func handleMsgCreateValidator(ctx sdk.Context, msg types.MsgCreateValidator, k k if ctx.ConsensusParams() != nil { tmPubKey := tmtypes.TM2PB.PubKey(msg.PubKey) - if !common.StringInSlice(tmPubKey.Type, ctx.ConsensusParams().Validator.PubKeyTypes) { + if !tmstrings.StringInSlice(tmPubKey.Type, ctx.ConsensusParams().Validator.PubKeyTypes) { return nil, sdkerrors.Wrapf( ErrValidatorPubKeyTypeNotSupported, "got: %s, valid: %s", tmPubKey.Type, ctx.ConsensusParams().Validator.PubKeyTypes, diff --git a/x/staking/keeper/historical_info_test.go b/x/staking/keeper/historical_info_test.go index fa1fa2356cd9..204dd3ac512d 100644 --- a/x/staking/keeper/historical_info_test.go +++ b/x/staking/keeper/historical_info_test.go @@ -4,9 +4,10 @@ import ( "sort" "testing" + abci "github.com/tendermint/tendermint/abci/types" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/staking/types" - abci "github.com/tendermint/tendermint/abci/types" "github.com/stretchr/testify/require" ) diff --git a/x/staking/simulation/decoder.go b/x/staking/simulation/decoder.go index 45aba449f807..de5d50de9f7d 100644 --- a/x/staking/simulation/decoder.go +++ b/x/staking/simulation/decoder.go @@ -4,7 +4,7 @@ import ( "bytes" "fmt" - cmn "github.com/tendermint/tendermint/libs/common" + tmkv "github.com/tendermint/tendermint/libs/kv" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" @@ -12,7 +12,7 @@ import ( ) // DecodeStore unmarshals the KVPair's Value to the corresponding staking type -func DecodeStore(cdc *codec.Codec, kvA, kvB cmn.KVPair) string { +func DecodeStore(cdc *codec.Codec, kvA, kvB tmkv.Pair) string { switch { case bytes.Equal(kvA.Key[:1], types.LastTotalPowerKey): var powerA, powerB sdk.Int diff --git a/x/staking/simulation/decoder_test.go b/x/staking/simulation/decoder_test.go index f5b2de545d37..5e0407c59c07 100644 --- a/x/staking/simulation/decoder_test.go +++ b/x/staking/simulation/decoder_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/crypto/ed25519" - cmn "github.com/tendermint/tendermint/libs/common" + tmkv "github.com/tendermint/tendermint/libs/kv" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" @@ -39,14 +39,14 @@ func TestDecodeStore(t *testing.T) { ubd := types.NewUnbondingDelegation(delAddr1, valAddr1, 15, bondTime, sdk.OneInt()) red := types.NewRedelegation(delAddr1, valAddr1, valAddr1, 12, bondTime, sdk.OneInt(), sdk.OneDec()) - kvPairs := cmn.KVPairs{ - cmn.KVPair{Key: types.LastTotalPowerKey, Value: cdc.MustMarshalBinaryLengthPrefixed(sdk.OneInt())}, - cmn.KVPair{Key: types.GetValidatorKey(valAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(val)}, - cmn.KVPair{Key: types.LastValidatorPowerKey, Value: valAddr1.Bytes()}, - cmn.KVPair{Key: types.GetDelegationKey(delAddr1, valAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(del)}, - cmn.KVPair{Key: types.GetUBDKey(delAddr1, valAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(ubd)}, - cmn.KVPair{Key: types.GetREDKey(delAddr1, valAddr1, valAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(red)}, - cmn.KVPair{Key: []byte{0x99}, Value: []byte{0x99}}, + kvPairs := tmkv.Pairs{ + tmkv.Pair{Key: types.LastTotalPowerKey, Value: cdc.MustMarshalBinaryLengthPrefixed(sdk.OneInt())}, + tmkv.Pair{Key: types.GetValidatorKey(valAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(val)}, + tmkv.Pair{Key: types.LastValidatorPowerKey, Value: valAddr1.Bytes()}, + tmkv.Pair{Key: types.GetDelegationKey(delAddr1, valAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(del)}, + tmkv.Pair{Key: types.GetUBDKey(delAddr1, valAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(ubd)}, + tmkv.Pair{Key: types.GetREDKey(delAddr1, valAddr1, valAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(red)}, + tmkv.Pair{Key: []byte{0x99}, Value: []byte{0x99}}, } tests := []struct { diff --git a/x/supply/simulation/decoder.go b/x/supply/simulation/decoder.go index 7e22f33a5478..3337e4b0687f 100644 --- a/x/supply/simulation/decoder.go +++ b/x/supply/simulation/decoder.go @@ -4,7 +4,7 @@ import ( "bytes" "fmt" - cmn "github.com/tendermint/tendermint/libs/common" + tmkv "github.com/tendermint/tendermint/libs/kv" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/x/supply/internal/keeper" @@ -12,7 +12,7 @@ import ( ) // DecodeStore unmarshals the KVPair's Value to the corresponding supply type -func DecodeStore(cdc *codec.Codec, kvA, kvB cmn.KVPair) string { +func DecodeStore(cdc *codec.Codec, kvA, kvB tmkv.Pair) string { switch { case bytes.Equal(kvA.Key[:1], keeper.SupplyKey): var supplyA, supplyB types.Supply diff --git a/x/supply/simulation/decoder_test.go b/x/supply/simulation/decoder_test.go index d40f62535e6c..f653632f168d 100644 --- a/x/supply/simulation/decoder_test.go +++ b/x/supply/simulation/decoder_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/require" - cmn "github.com/tendermint/tendermint/libs/common" + tmkv "github.com/tendermint/tendermint/libs/kv" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" @@ -26,9 +26,9 @@ func TestDecodeStore(t *testing.T) { totalSupply := types.NewSupply(sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 1000))) - kvPairs := cmn.KVPairs{ - cmn.KVPair{Key: keeper.SupplyKey, Value: cdc.MustMarshalBinaryLengthPrefixed(totalSupply)}, - cmn.KVPair{Key: []byte{0x99}, Value: []byte{0x99}}, + kvPairs := tmkv.Pairs{ + tmkv.Pair{Key: keeper.SupplyKey, Value: cdc.MustMarshalBinaryLengthPrefixed(totalSupply)}, + tmkv.Pair{Key: []byte{0x99}, Value: []byte{0x99}}, } tests := []struct { diff --git a/x/upgrade/abci.go b/x/upgrade/abci.go index 7a19e0f866ab..11edf7fbbc0c 100644 --- a/x/upgrade/abci.go +++ b/x/upgrade/abci.go @@ -2,6 +2,7 @@ package upgrade import ( "fmt" + abci "github.com/tendermint/tendermint/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/x/upgrade/client/cli/query.go b/x/upgrade/client/cli/query.go index bf7d2163fa44..0b33a012071f 100644 --- a/x/upgrade/client/cli/query.go +++ b/x/upgrade/client/cli/query.go @@ -4,10 +4,11 @@ import ( "encoding/binary" "fmt" + "github.com/spf13/cobra" + "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/codec" upgrade "github.com/cosmos/cosmos-sdk/x/upgrade/internal/types" - "github.com/spf13/cobra" ) // GetPlanCmd returns the query upgrade plan command diff --git a/x/upgrade/internal/keeper/querier.go b/x/upgrade/internal/keeper/querier.go index 811acad2302f..7bddfad34566 100644 --- a/x/upgrade/internal/keeper/querier.go +++ b/x/upgrade/internal/keeper/querier.go @@ -3,10 +3,11 @@ package keeper import ( "encoding/binary" + abci "github.com/tendermint/tendermint/abci/types" + sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/upgrade/internal/types" - abci "github.com/tendermint/tendermint/abci/types" ) // NewQuerier creates a querier for upgrade cli and REST endpoints diff --git a/x/upgrade/internal/types/plan_test.go b/x/upgrade/internal/types/plan_test.go index d8e7e18d7fa3..57e025a0398d 100644 --- a/x/upgrade/internal/types/plan_test.go +++ b/x/upgrade/internal/types/plan_test.go @@ -7,9 +7,10 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - sdk "github.com/cosmos/cosmos-sdk/types" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" + + sdk "github.com/cosmos/cosmos-sdk/types" ) func mustParseTime(s string) time.Time { diff --git a/x/upgrade/module.go b/x/upgrade/module.go index 129cc904bf10..5605ca0b673e 100644 --- a/x/upgrade/module.go +++ b/x/upgrade/module.go @@ -6,6 +6,8 @@ import ( "github.com/gorilla/mux" "github.com/spf13/cobra" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" @@ -13,7 +15,6 @@ import ( "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/x/upgrade/client/cli" "github.com/cosmos/cosmos-sdk/x/upgrade/client/rest" - abci "github.com/tendermint/tendermint/abci/types" ) // module codec From 9a1046d74aa5d9b2ed0bac10bc5d8534da724c5d Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 17 Jan 2020 13:58:52 +0100 Subject: [PATCH 081/529] Bump github.com/spf13/viper from 1.6.1 to 1.6.2 (#5534) Bumps [github.com/spf13/viper](https://github.com/spf13/viper) from 1.6.1 to 1.6.2. - [Release notes](https://github.com/spf13/viper/releases) - [Commits](https://github.com/spf13/viper/compare/v1.6.1...v1.6.2) Signed-off-by: dependabot-preview[bot] --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index c5e0860701f0..c3e4279bb51c 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/spf13/cobra v0.0.5 github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 - github.com/spf13/viper v1.6.1 + github.com/spf13/viper v1.6.2 github.com/stretchr/testify v1.4.0 github.com/tendermint/btcd v0.1.1 github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 diff --git a/go.sum b/go.sum index a636d84e6de8..eef598ed3f92 100644 --- a/go.sum +++ b/go.sum @@ -238,6 +238,8 @@ github.com/spf13/viper v1.3.2 h1:VUFqw5KcqRf7i70GOzW7N+Q7+gxVBkSSqiXB12+JQ4M= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.6.1 h1:VPZzIkznI1YhVMRi6vNFLHSwhnhReBfgTxIPccpfdZk= github.com/spf13/viper v1.6.1/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k= +github.com/spf13/viper v1.6.2 h1:7aKfF+e8/k68gda3LOjo5RxiUqddoFxVq4BKBPrxk5E= +github.com/spf13/viper v1.6.2/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= From 0bbb01b5a935c592f0b290cde79a75471954eb06 Mon Sep 17 00:00:00 2001 From: Sunny Aggarwal Date: Fri, 17 Jan 2020 09:54:03 -0500 Subject: [PATCH 082/529] Merged PR #5211: [ADR: 014] Proportional Slashing --- .../adt-014-proportional-slashing.md | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 docs/architecture/adt-014-proportional-slashing.md diff --git a/docs/architecture/adt-014-proportional-slashing.md b/docs/architecture/adt-014-proportional-slashing.md new file mode 100644 index 000000000000..1ad1d6a31599 --- /dev/null +++ b/docs/architecture/adt-014-proportional-slashing.md @@ -0,0 +1,90 @@ +# ADR 14: Proportional Slashing + +## Changelog + +- 2019-10-15: Initial draft + +## Context + +In Proof of Stake-based chains, centralization of consensus power amongst a small set of validators can cause harm to the network due to increased risk of censorship, liveness failure, fork attacks, etc. However, while this centralization causes a negative externality to the network, it is not directly felt by the delegators contributing towards delegating towards already large validators. We would like a way to pass on the negative externality cost of centralization onto those large validators and their delegators. + +## Decision + +### Design + +To solve this problem, we will implement a procedure called Proportional Slashing. The desire is that the larger a validator is, the more they should be slashed. The first naive attempt is to make a validator's slash percent proportional to their share of consensus voting power. + +``` +slash_amount = k * power // power is the faulting validator's voting power and k is some on-chain constant +``` + +However, this will incentivize validators with large amounts of stake to split up their voting power amongst accounts, so that if they fault, they all get slashed at a lower percent. The solution to this is to take into account not just a validator's own voting percentage, but also the voting percentage of all the other validators who get slashed in a specified time frame. + +``` +slash_amount = k * (power_1 + power_2 + ... + power_n) // where power_i is the voting power of the ith validator faulting in the specified time frame and k is some on-chain constant +``` + +Now, if someone splits a validator of 10% into two validators of 5% each which both fault, then they both fault in the same time frame, they both will still get slashed at the sum 10% amount. + +However, an operator might still choose to split up their stake across multiple accounts with hopes that if any of them fault independently, they will not get slashed at the full amount. In the case that the validators do fault together, they will get slashed the same amount as if they were one entity. There is no con to splitting up. However, if operators are going to split up their stake without actually decorrelating their setups, this also causes a negative externality to the network as it fills up validator slots that could have gone to others or increases the commit size. In order to disincentivize this, we want it to be the case such that splitting up a validator into multiple validators and they fault together is punished more heavily that keeping it as a single validator that faults. + +We can achieve this by not only taking into account the sum of the percentages of the validators that faulted, but also the *number* of validators that faulted in the window. One general form for an equation that fits this desired property looks like this: + +``` +slash_amount = k * ((power_1)^(1/r) + (power_2)^(1/r) + ... + (power_n)^(1/r))^r // where k and r are both on-chain constants +``` + +So now, for example, assuming k=1 and r=2, if one validator of 10% faults, it gets a 10% slash, while if two validators of 5% each fault together, they both get a 20% slash ((sqrt(0.05)+sqrt(0.05))^2). + +#### Correlation across non-sybil validators + +One will note, that this model doesn't differentiate between multiple validators run by the same operators vs validators run by different operators. This can be seen as an additional benefit in fact. It incentivizes validators to differentiate their setups from other validators, to avoid having correlated faults with them or else they risk a higher slash. So for example, operators should avoid using the same popular cloud hosting platforms or using the same Staking as a Service providers. This will lead to a more resilient and decentralized network. + +#### Parameterization + +The value of k and r can be different for different types of slashable faults. For example, we may want to punish liveness faults 10% as severely as double signs. + +There can also be minimum and maximums put in place in order to bound the size of the slash percent. + +#### Griefing + +Griefing, the act of intentionally being slashed to make another's slash worse, could be a concern here. However, using the protocol described here, the attacker could not substantially grief without getting slashed a substantial amount themselves. The larger the validator is, the more heavily it can impact the slash, it needs to be non-trivial to have a significant impact on the slash percent. Furthermore, the larger the grief, the griefer loses quadratically more. + +It may also be possible to, rather than the k and r factors being constants, perhaps using an inverse gini coefficient may mitigate some griefing attacks, but this an area for future research. + +### Implementation + +In the slashing module, we will add two queues that will track all of the recent slash events. For double sign faults, we will define "recent slashes" as ones that have occured within the last `unbonding period`. For liveness faults, we will define "recent slashes" as ones that have occured withing the last `jail period`. + +``` +type SlashEvent struct { + Address sdk.ValAddress + SqrtValidatorVotingPercent sdk.Dec + SlashedSoFar sdk.Dec +} +``` + +These slash events will be pruned from the queue once they are older than their respective "recent slash period". + +Whenever a new slash occurs, a `SlashEvent` struct is created with the faulting validator's voting percent and a `SlashedSoFar` of 0. Because recent slash events are pruned before the unbonding period and unjail period expires, it should not be possible for the same validator to have multiple SlashEvents in the same Queue at the same time. + +We then will iterate over all the SlashEvents in the queue, adding their `SqrtValidatorVotingPercent` and squaring the result to calculate the new percent to slash all the validators in the queue at, using the "Square of Sum of Roots" formula introduced above. + +Once we have the `NewSlashPercent`, we then iterate over all the `SlashEvent`s in the queue once again, and if `NewSlashPercent > SlashedSoFar` for that SlashEvent, we call the `staking.Slash(slashEvent.Address, slashEvent.Power, Math.Min(Math.Max(minSlashPercent, NewSlashPercent - SlashedSoFar), maxSlashPercent)` (we pass in the power of the validator before any slashes occured, so that we slash the right amount of tokens). We then set `SlashEvent.SlashedSoFar` amount to `NewSlashPercent`. + + +## Status + +Proposed + +## Consequences + +### Positive + +- Increases decentralization by disincentivizing delegating to large validators +- Incentivizes Decorrelation of Validators +- More severely punishes attacks than accidental faults + +### Negative + +- May require computationally expensive root function in state machine From 0bb8e161721f97c00e04b17c3b776f196c891e0d Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 17 Jan 2020 10:11:24 -0500 Subject: [PATCH 083/529] Merge PR #5535: Bump github.com/hashicorp/golang-lru from 0.5.3 to 0.5.4 Bumps [github.com/hashicorp/golang-lru](https://github.com/hashicorp/golang-lru) from 0.5.3 to 0.5.4. - [Release notes](https://github.com/hashicorp/golang-lru/releases) - [Commits](https://github.com/hashicorp/golang-lru/compare/v0.5.3...v0.5.4) Signed-off-by: dependabot-preview[bot] Co-authored-by: Alexander Bezobchuk --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index c3e4279bb51c..9c9f0e45abc7 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/gogo/protobuf v1.3.1 github.com/golang/mock v1.3.1-0.20190508161146-9fa652df1129 github.com/gorilla/mux v1.7.3 - github.com/hashicorp/golang-lru v0.5.3 + github.com/hashicorp/golang-lru v0.5.4 github.com/mattn/go-isatty v0.0.11 github.com/pelletier/go-toml v1.6.0 github.com/pkg/errors v0.9.1 diff --git a/go.sum b/go.sum index eef598ed3f92..b177de14c78c 100644 --- a/go.sum +++ b/go.sum @@ -129,6 +129,8 @@ github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uM github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o= github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk= github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= From 13464f234c339338ce8944e101b393cbbf5e9f88 Mon Sep 17 00:00:00 2001 From: gamarin2 Date: Fri, 17 Jan 2020 18:11:22 +0100 Subject: [PATCH 084/529] Add quick start guide (#5517) * start * test * guide * Apply suggestions from code review * typo Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> --- docs/README.md | 1 + docs/basics/app-anatomy.md | 2 - docs/using-the-sdk/quick-start.md | 184 ++++++++++++++++++++++++++++++ 3 files changed, 185 insertions(+), 2 deletions(-) create mode 100644 docs/using-the-sdk/quick-start.md diff --git a/docs/README.md b/docs/README.md index 7eb27fdea435..04c306be3d41 100644 --- a/docs/README.md +++ b/docs/README.md @@ -63,6 +63,7 @@ aside: false ## Get Started - **[SDK Intro](./intro/overview.md)**: High-level overview of the Cosmos SDK. +- **[Quick Start Guide](./using-the-sdk/quick-start.md)**: Scaffold a standard Cosmos SDK app and run a node. - **[SDK Application Tutorial](https://github.com/cosmos/sdk-application-tutorial)**: A tutorial that showcases how to build an SDK-based blockchain from scratch and explains the basic principles of the SDK in the process. ## Reference diff --git a/docs/basics/app-anatomy.md b/docs/basics/app-anatomy.md index 0c7e084cea8b..359016b2c8e8 100644 --- a/docs/basics/app-anatomy.md +++ b/docs/basics/app-anatomy.md @@ -5,8 +5,6 @@ synopsis: "This document describes the core parts of a Cosmos SDK application. T # Anatomy of an SDK Application - - ## Node Client The Daemon, or [Full-Node Client](../core/node.md), is the core process of an SDK-based blockchain. Participants in the network run this process to initialize their state-machine, connect with other full-nodes and update their state-machine as new blocks come in. diff --git a/docs/using-the-sdk/quick-start.md b/docs/using-the-sdk/quick-start.md new file mode 100644 index 000000000000..4b2bf548b2e4 --- /dev/null +++ b/docs/using-the-sdk/quick-start.md @@ -0,0 +1,184 @@ +# Quick Start + +This guide serves as a practical introduction to building blockchains with the Cosmos SDK. It shows how to scaffold the code for a basic blockchain node, build and run it. Several important concepts of the Cosmos SDK are introduced along the way. + +## Setup + +::: tip +To follow this guide, you need to [install golang](https://golang.org/doc/install) and set [your $GOPATH environment variable](https://golang.org/doc/code.html#GOPATH) +::: + +::: warning +Make sure you are using the latest stable version of golang available on https://golang.org/dl/ +::: + +First, download the [`scaffold`](https://github.com/cosmos/scaffold) tool: + +```bash +git clone https://github.com/cosmos/scaffold +``` + +The `scaffold` tool lets you easily scaffold boilerplate Cosmos SDK applications. Once you have downloaded it, simply install it on your machine: + +```bash +cd scaffold +make +``` + +## Create a Basic Cosmos SDK Blockchain + +To create a basic Cosmos SDK application, simply type in the following command: + +```bash +scaffold app lvl-1 +``` + +where `username|org` is the name of your github/gitlab/atlassian username or organisation, and `repo` the name of the distant repository you would push your application too. These arguments are used to configure the imports so that people can easily download and install your application once (if) you upload it. + +The command above creates a starter application in a new folder named after the `repo` argument. This application contains the [basic logic most SDK applications](../intro/sdk-app-architecture.md) need as well as a set of standard [modules](../building-modules/intro.md) already hooked up. These include: + +- [`auth`](../../x/auth/spec/): Accounts, signatures and fees. +- [`bank`](../../x/bank/spec/): Token transfers. +- [`staking`](../../x/staking/spec/): Proof-of-Stake logic, which is a way of managing validator set changes in public decentralised networks. Also includes delegation logic. +- [`slashing`](../../x/slashing/spec/): Slash validators that misebehave. Complementary to the `staking` module. +- [`distribution`](../../x/distribution/spec/): Distribution of rewards and fees earned by participants in the Proof-of-Stake system (delegators and validators). +- [`params`](../../x/params/spec/): Global parameter store of the application. +- [`supply`](../../x/supply/spec/): Handles global token supply of the application. Enables modules to hold tokens. +- [`genutil`](../../x/genutil) and [`genaccounts`](../../x/genaccounts): Utility modules to facilitate creation of genesis file. + +Now, go into the application's folder. The structure should look like the following: + +``` +├── app/ +│   ├── app.go +│   └── export.go +├── cmd/ +│ ├── acli/ +│ │ └── main.go +│   ├── aud/ +│ │ └── main.go +├── Makefile +├── go.mod +└── x/ +``` + +where: + +- `app.go` is the [main file](../basics/app-anatomy.md#core-application-file) defining the application logic. This is where the state is intantiated and modules are declared. This is also where the Cosmos SDK is imported as a dependency to help build the application. +- `export.go` is a helper file used to export the state of the application into a new genesis file. It is helpful when you want to upgrade your chain to a new (breaking) version. +- `acli/main.go` builds the command-line interface for your blockchain application. It enables end-users to create transactions and query the chain for information. +- `aud/main.go` builds the main [daemon client](../basics/app-anatomy.md#node-client) of the chain. It is used to run a full-node that will connect to peers and sync its local application state with the latest state of the network. +- `go.mod` helps manage dependencies. The two main dependencies used are the Cosmos SDK to help build the application, and Tendermint to replicate it. +- `x/` is the folder to place all the custom modules built specifically for the application. In general, most of the modules used in an application have already been built by third-party developers and only need to be imported in `app.go`. These modules do not need to be cloned into the application's `x/` folder. This is why the basic application shown above, which uses several modules, works despite having an empty `x/` folder. + +## Run your Blockchain + +First, install the two main entrypoints of your blockchain, `aud` and `acli`: + +```bash +go mod tidy +make install +``` + +Make sure the clients are properly installed: + +```bash +acli --help +aud --help +``` + +Now that you have your daemon client `aud` and your command-line interface `acli` installed, go ahead and initialize your chain: + +```bash +aud init --chain-id test +``` + +The command above creates all the configuration files needed for your node to run, as well as a default genesis file, which defines the initial state of the network. Before starting the chain, you need to populate the state with at least one account. To do so, first create a new [account](../basics/accounts.md) named `validator` (feel free to choose another name): + +```bash +acli keys add validator +``` + +Now that you have created a local account, go ahead and grant it `stake` tokens in your chain's genesis file. Doing so will also make sure your chain is aware of this account's existence: + +```bash +aud add-genesis-account $(acli keys show validator -a) 100000000stake +``` + +Now that your account has some tokens, you need to add a validator to your chain. Validators are special full-nodes that participate in the consensus process (implemented in the [underlying consensus engine](../intro/sdk-app-architecture.md#tendermint)) in order to add new blocks to the chain. Any account can declare its intention to become a validator operator, but only those with sufficient delegation get to enter the active set (for example, only the top 125 validator candidates with the most delegation get to be validators in the Cosmos Hub). For this guide, you will add your local node (created via the `init` command above) as a validator of your chain. Validators can be declared before a chain is first started via a special transaction included in the genesis file called a `gentx`: + +```bash +// create a gentx +aud gentx --name validator --amount 100000stake + +// add the gentx to the genesis file +aud collect-gentxs +``` + +A `gentx` does three things: + + 1. Makes the `validator` account you created into a validator operator account (i.e. the account that controls the validator). + 2. Self-delegates the provided `amount` of staking tokens. + 3. Link the operator account with a Tendermint node pubkey that will be used for signing blocks. If no `--pubkey` flag is provided, it defaults to the local node pubkey created via the `aud init` command above. + +For more on `gentx`, use the following command: + +```bash +aud gentx --help +``` + +Now that everyting is set up, you can finally start your node: + +```bash +aud start +``` + +You should see blocks come in. + +## Send Tokens and Increase Delegation + +Now that your chain is running, it is time to try sending tokens from the first account you created to a second account. In a new terminal window, start by running the following query command: + +```bash +acli query account $(acli keys show validator -a) --chain-id test +``` + +You should see the current balance of the account you created, equal to the original balance of `stake` you granted it minus the amount you delegated via the `gentx`. Now, create a second account: + +```bash +acli keys add receiver +``` + +The command above creates a local key-pair that is not yet registered on the chain. An account is registered the first time it receives tokens from another account. Now, run the following command to send tokens to the second account: + +```bash +acli tx send $(acli keys show validator -a) $(acli keys show receiver -a) 1000stake --chain-id test +``` + +Check that the second account did receive the tokens: + +```bash +acli query account $(acli keys show receiver -a) --chain-id test +``` + +Finally, delegate some of the stake tokens sent to the `receiver` account to the validator: + +```bash +acli tx staking delegate $(acli keys show validator --bech val -a) 500stake --from receiver --chain-id test +``` + +Try to query the total delegations to `validator`: + +```bash +acli query staking delegations-to $(acli keys show validator --bech val -a) --chain-id test +``` + +You should see two delegations, the first one made from the `gentx`, and the second one you just performed from the `receiver` account. + +## Next + +Congratulations on making it to the end of this short introduction guide! If you want to learn more, check out the following resources: + +- [How to build a full SDK application from scratch](https://tutorials.cosmos.network/nameservice/tutorial/00-intro.html). +- [Read the Cosmos SDK Documentation](../intro/overview.md). + From 260fbc3cc8803a2ccc39bc32d8a3162b716406a3 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Fri, 17 Jan 2020 12:33:59 -0500 Subject: [PATCH 085/529] Merge PR #5537: Fix validatorset REST pagination --- client/rpc/validators.go | 31 ++++++++----------------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/client/rpc/validators.go b/client/rpc/validators.go index 8f8d16968b9a..0fa06db3b821 100644 --- a/client/rpc/validators.go +++ b/client/rpc/validators.go @@ -160,23 +160,16 @@ func GetValidators(cliCtx context.CLIContext, height *int64, page, limit int) (R // Validator Set at a height REST handler func ValidatorSetRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - - page, err := strconv.ParseInt(vars["page"], 10, 64) + _, page, limit, err := rest.ParseHTTPArgsWithLimit(r, 100) if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, "failed to parse page") - return - } - - limit, err := strconv.ParseInt(vars["limit"], 10, 64) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, "failed to parse limit") + rest.WriteErrorResponse(w, http.StatusBadRequest, "failed to parse pagination parameters") return } + vars := mux.Vars(r) height, err := strconv.ParseInt(vars["height"], 10, 64) if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, "failed to parse block height; assumed format is '/validatorsets/{height}'") + rest.WriteErrorResponse(w, http.StatusBadRequest, "failed to parse block height") return } @@ -190,7 +183,7 @@ func ValidatorSetRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return } - output, err := GetValidators(cliCtx, &height, int(page), int(limit)) + output, err := GetValidators(cliCtx, &height, page, limit) if err != nil { rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return @@ -202,21 +195,13 @@ func ValidatorSetRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { // Latest Validator Set REST handler func LatestValidatorSetRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - - page, err := strconv.ParseInt(vars["page"], 10, 64) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, "failed to parse page") - return - } - - limit, err := strconv.ParseInt(vars["limit"], 10, 64) + _, page, limit, err := rest.ParseHTTPArgsWithLimit(r, 100) if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, "failed to parse limit") + rest.WriteErrorResponse(w, http.StatusBadRequest, "failed to parse pagination parameters") return } - output, err := GetValidators(cliCtx, nil, int(page), int(limit)) + output, err := GetValidators(cliCtx, nil, page, limit) if err != nil { rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return From e37a6750ceb1c80d31b0378039426099605da298 Mon Sep 17 00:00:00 2001 From: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Date: Tue, 21 Jan 2020 16:45:21 +0100 Subject: [PATCH 086/529] Merge PR #5545: update CHANGELOG.md --- CHANGELOG.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d2142e26abf..a16a98bb4b91 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -274,6 +274,12 @@ to detail this new feature and how state transitions occur. * (x/gov) [\#5107](https://github.com/cosmos/cosmos-sdk/pull/5107) Sum validator operator's all voting power when tally votes * (rest) [\#5212](https://github.com/cosmos/cosmos-sdk/issues/5212) Fix pagination in the `/gov/proposals` handler. +## [v0.37.6] - 2020-01-21 + +### Improvements + +* (tendermint) Bump Tendermint version to [v0.32.9](https://github.com/tendermint/tendermint/releases/tag/v0.32.9) + ## [v0.37.5] - 2020-01-07 ### Features @@ -2859,7 +2865,8 @@ BUG FIXES: -[Unreleased]: https://github.com/cosmos/cosmos-sdk/compare/v0.37.5...HEAD +[Unreleased]: https://github.com/cosmos/cosmos-sdk/compare/v0.37.6...HEAD +[v0.37.6]: https://github.com/cosmos/cosmos-sdk/releases/tag/v0.37.6 [v0.37.5]: https://github.com/cosmos/cosmos-sdk/releases/tag/v0.37.5 [v0.37.4]: https://github.com/cosmos/cosmos-sdk/releases/tag/v0.37.4 [v0.37.3]: https://github.com/cosmos/cosmos-sdk/releases/tag/v0.37.3 From 81f39ece19c53b1971afb4ebe60194b454001fe7 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 22 Jan 2020 09:59:17 +0100 Subject: [PATCH 087/529] Bump github.com/mattn/go-isatty from 0.0.11 to 0.0.12 (#5551) Bumps [github.com/mattn/go-isatty](https://github.com/mattn/go-isatty) from 0.0.11 to 0.0.12. - [Release notes](https://github.com/mattn/go-isatty/releases) - [Commits](https://github.com/mattn/go-isatty/compare/v0.0.11...v0.0.12) Signed-off-by: dependabot-preview[bot] --- go.mod | 2 +- go.sum | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 9c9f0e45abc7..989492906653 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/golang/mock v1.3.1-0.20190508161146-9fa652df1129 github.com/gorilla/mux v1.7.3 github.com/hashicorp/golang-lru v0.5.4 - github.com/mattn/go-isatty v0.0.11 + github.com/mattn/go-isatty v0.0.12 github.com/pelletier/go-toml v1.6.0 github.com/pkg/errors v0.9.1 github.com/rakyll/statik v0.1.6 diff --git a/go.sum b/go.sum index b177de14c78c..796402b6b6c7 100644 --- a/go.sum +++ b/go.sum @@ -165,6 +165,8 @@ github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzR github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643 h1:hLDRPB66XQT/8+wG9WsDpiCvZf1yKO7sz7scAjSlBa0= @@ -323,6 +325,8 @@ golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= From 415eab7a567bb846724e9e61fc89ecd4ead87b17 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Wed, 22 Jan 2020 17:54:56 +0000 Subject: [PATCH 088/529] Create new generic keyring constructor: NewKeyring (#5547) Remove other convenience constructors: * Remove NewKeyBaseFromHomeFlag * Remove NewKeyringFromDir * Remove NewKeyringFromHomeFlag --- CHANGELOG.md | 5 +++- client/context/context.go | 10 +++---- client/flags/flags.go | 7 ++--- client/keys/add.go | 2 +- client/keys/add_ledger_test.go | 4 +-- client/keys/add_test.go | 4 ++- client/keys/delete.go | 4 ++- client/keys/delete_test.go | 5 ++-- client/keys/export.go | 6 +++- client/keys/export_test.go | 3 +- client/keys/import.go | 6 +++- client/keys/import_test.go | 4 ++- client/keys/list.go | 4 ++- client/keys/list_test.go | 3 +- client/keys/migrate.go | 4 +-- client/keys/root_test.go | 3 +- client/keys/show.go | 2 +- client/keys/show_test.go | 2 +- client/keys/update.go | 4 ++- client/keys/update_test.go | 2 +- client/keys/utils.go | 32 --------------------- client/keys/utils_test.go | 25 ---------------- crypto/keys/keyring.go | 47 +++++++++++++++---------------- crypto/keys/keyring_test.go | 23 +++++---------- server/init_test.go | 4 +-- x/auth/client/cli/tx_multisign.go | 14 ++++----- x/auth/types/txbuilder.go | 16 +++++------ x/genutil/client/cli/gentx.go | 8 +++--- 28 files changed, 105 insertions(+), 148 deletions(-) delete mode 100644 client/keys/utils_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index a16a98bb4b91..58b5577a6cbc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -100,7 +100,10 @@ if the provided arguments are invalid. `StdTx.Signatures` to get back the array of StdSignatures `[]StdSignature`. * (modules) [\#5299](https://github.com/cosmos/cosmos-sdk/pull/5299) `HandleDoubleSign` along with params `MaxEvidenceAge` and `DoubleSignJailEndTime` have moved from the `x/slashing` module to the `x/evidence` module. -* (keys) [\#4941](https://github.com/cosmos/cosmos-sdk/issues/4941) Initializing a new keybase through `NewKeyringFromHomeFlag`, `NewKeyringFromDir`, `NewKeyBaseFromHomeFlag`, `NewKeyBaseFromDir`, or `NewInMemory` functions now accept optional parameters of type `KeybaseOption`. These optional parameters are also added on the keys subcommands functions, which are now public, and allows these options to be set on the commands or ignored to default to previous behavior. +* (keys) [\#4941](https://github.com/cosmos/cosmos-sdk/issues/4941) Keybase concrete types constructors such as `NewKeyBaseFromDir` and `NewInMemory` + now accept optional parameters of type `KeybaseOption`. These optional parameters are also added on the keys subcommands + functions, which are now public, and allows these options to be set on the commands or ignored to default to previous behavior. +* [\#5547](https://github.com/cosmos/cosmos-sdk/pull/5547) `NewKeyBaseFromHomeFlag` constructor has been removed. * [\#5439](https://github.com/cosmos/cosmos-sdk/pull/5439) Further modularization was done to the `keybase` package to make it more suitable for use with different key formats and algorithms: * The `WithKeygenFunc` function added as a `KeybaseOption` which allows a custom bytes to key diff --git a/client/context/context.go b/client/context/context.go index 6ea577a31005..c6699c9065eb 100644 --- a/client/context/context.go +++ b/client/context/context.go @@ -14,9 +14,8 @@ import ( rpcclient "github.com/tendermint/tendermint/rpc/client" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/client/keys" "github.com/cosmos/cosmos-sdk/codec" - cryptokeys "github.com/cosmos/cosmos-sdk/crypto/keys" + "github.com/cosmos/cosmos-sdk/crypto/keys" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -26,7 +25,7 @@ type CLIContext struct { FromAddress sdk.AccAddress Client rpcclient.Client ChainID string - Keybase cryptokeys.Keybase + Keybase keys.Keybase Input io.Reader Output io.Writer OutputFormat string @@ -275,12 +274,13 @@ func GetFromFields(input io.Reader, from string, genOnly bool) (sdk.AccAddress, return addr, "", nil } - keybase, err := keys.NewKeyringFromHomeFlag(input) + keybase, err := keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), + viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), input) if err != nil { return nil, "", err } - var info cryptokeys.Info + var info keys.Info if addr, err := sdk.AccAddressFromBech32(from); err == nil { info, err = keybase.GetByAddress(addr) if err != nil { diff --git a/client/flags/flags.go b/client/flags/flags.go index ea2a5baa431a..2cdaa5f2137f 100644 --- a/client/flags/flags.go +++ b/client/flags/flags.go @@ -9,6 +9,8 @@ import ( "github.com/spf13/viper" tmcli "github.com/tendermint/tendermint/libs/cli" + + "github.com/cosmos/cosmos-sdk/crypto/keys" ) // nolint @@ -21,10 +23,7 @@ const ( GasFlagAuto = "auto" // DefaultKeyringBackend - DefaultKeyringBackend = KeyringBackendOS - KeyringBackendFile = "file" - KeyringBackendOS = "os" - KeyringBackendTest = "test" + DefaultKeyringBackend = keys.BackendOS // BroadcastBlock defines a tx broadcasting mode where the client waits for // the tx to be committed in a block. diff --git a/client/keys/add.go b/client/keys/add.go index 60f4dfe20060..995dfa74e859 100644 --- a/client/keys/add.go +++ b/client/keys/add.go @@ -86,7 +86,7 @@ func getKeybase(transient bool, buf io.Reader) (keys.Keybase, error) { return keys.NewInMemory(), nil } - return NewKeyringFromHomeFlag(buf) + return keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), buf) } func runAddCmd(cmd *cobra.Command, args []string) error { diff --git a/client/keys/add_ledger_test.go b/client/keys/add_ledger_test.go index 2ada0e113581..68c0390c8662 100644 --- a/client/keys/add_ledger_test.go +++ b/client/keys/add_ledger_test.go @@ -51,7 +51,7 @@ func Test_runAddCmdLedgerWithCustomCoinType(t *testing.T) { require.NoError(t, runAddCmd(cmd, []string{"keyname1"})) // Now check that it has been stored properly - kb, err := NewKeyringFromHomeFlag(mockIn) + kb, err := keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) require.NoError(t, err) require.NotNil(t, kb) defer func() { @@ -98,7 +98,7 @@ func Test_runAddCmdLedger(t *testing.T) { require.NoError(t, runAddCmd(cmd, []string{"keyname1"})) // Now check that it has been stored properly - kb, err := NewKeyringFromHomeFlag(mockIn) + kb, err := keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), kbHome, mockIn) require.NoError(t, err) require.NotNil(t, kb) defer func() { diff --git a/client/keys/add_test.go b/client/keys/add_test.go index d1a7dd04b3e0..0745ba620ad4 100644 --- a/client/keys/add_test.go +++ b/client/keys/add_test.go @@ -10,7 +10,9 @@ import ( "github.com/tendermint/tendermint/libs/cli" "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/crypto/keys" "github.com/cosmos/cosmos-sdk/tests" + sdk "github.com/cosmos/cosmos-sdk/types" ) func Test_runAddCmdBasic(t *testing.T) { @@ -29,7 +31,7 @@ func Test_runAddCmdBasic(t *testing.T) { mockIn.Reset("testpass1\ntestpass1\n") } else { mockIn.Reset("y\n") - kb, err := NewKeyringFromHomeFlag(mockIn) + kb, err := keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), kbHome, mockIn) require.NoError(t, err) defer func() { kb.Delete("keyname1", "", false) diff --git a/client/keys/delete.go b/client/keys/delete.go index 8e607a319ba4..1bfc6b10db46 100644 --- a/client/keys/delete.go +++ b/client/keys/delete.go @@ -4,8 +4,10 @@ import ( "bufio" "errors" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/input" "github.com/cosmos/cosmos-sdk/crypto/keys" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -41,7 +43,7 @@ private keys stored in a ledger device cannot be deleted with the CLI. func runDeleteCmd(cmd *cobra.Command, args []string) error { buf := bufio.NewReader(cmd.InOrStdin()) - kb, err := NewKeyringFromHomeFlag(buf) + kb, err := keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), buf) if err != nil { return err } diff --git a/client/keys/delete_test.go b/client/keys/delete_test.go index eeafb40baa49..c9ac44b4a14f 100644 --- a/client/keys/delete_test.go +++ b/client/keys/delete_test.go @@ -11,6 +11,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/crypto/keys" "github.com/cosmos/cosmos-sdk/tests" + sdk "github.com/cosmos/cosmos-sdk/types" ) func Test_runDeleteCmd(t *testing.T) { @@ -26,7 +27,7 @@ func Test_runDeleteCmd(t *testing.T) { fakeKeyName1 := "runDeleteCmd_Key1" fakeKeyName2 := "runDeleteCmd_Key2" if !runningUnattended { - kb, err := NewKeyringFromHomeFlag(mockIn) + kb, err := keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) require.NoError(t, err) defer func() { kb.Delete("runDeleteCmd_Key1", "", false) @@ -40,7 +41,7 @@ func Test_runDeleteCmd(t *testing.T) { viper.Set(flags.FlagHome, kbHome) // Now - kb, err := NewKeyringFromHomeFlag(mockIn) + kb, err := keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), kbHome, mockIn) require.NoError(t, err) if runningUnattended { mockIn.Reset("testpass1\ntestpass1\n") diff --git a/client/keys/export.go b/client/keys/export.go index 761cdc561c37..1051335b98e9 100644 --- a/client/keys/export.go +++ b/client/keys/export.go @@ -4,8 +4,12 @@ import ( "bufio" "github.com/spf13/cobra" + "github.com/spf13/viper" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/input" + "github.com/cosmos/cosmos-sdk/crypto/keys" + sdk "github.com/cosmos/cosmos-sdk/types" ) // ExportKeyCommand exports private keys from the key store. @@ -21,7 +25,7 @@ func ExportKeyCommand() *cobra.Command { func runExportCmd(cmd *cobra.Command, args []string) error { buf := bufio.NewReader(cmd.InOrStdin()) - kb, err := NewKeyringFromHomeFlag(buf) + kb, err := keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), buf) if err != nil { return err } diff --git a/client/keys/export_test.go b/client/keys/export_test.go index 579cd829d170..32c57df656d6 100644 --- a/client/keys/export_test.go +++ b/client/keys/export_test.go @@ -9,6 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/crypto/keys" "github.com/cosmos/cosmos-sdk/tests" + sdk "github.com/cosmos/cosmos-sdk/types" ) func Test_runExportCmd(t *testing.T) { @@ -22,7 +23,7 @@ func Test_runExportCmd(t *testing.T) { viper.Set(flags.FlagHome, kbHome) // create a key - kb, err := NewKeyringFromHomeFlag(mockIn) + kb, err := keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) require.NoError(t, err) if !runningUnattended { defer func() { diff --git a/client/keys/import.go b/client/keys/import.go index 7fb323c77478..289172168904 100644 --- a/client/keys/import.go +++ b/client/keys/import.go @@ -5,8 +5,12 @@ import ( "io/ioutil" "github.com/spf13/cobra" + "github.com/spf13/viper" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/input" + "github.com/cosmos/cosmos-sdk/crypto/keys" + sdk "github.com/cosmos/cosmos-sdk/types" ) // ImportKeyCommand imports private keys from a keyfile. @@ -22,7 +26,7 @@ func ImportKeyCommand() *cobra.Command { func runImportCmd(cmd *cobra.Command, args []string) error { buf := bufio.NewReader(cmd.InOrStdin()) - kb, err := NewKeyringFromHomeFlag(buf) + kb, err := keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), buf) if err != nil { return err } diff --git a/client/keys/import_test.go b/client/keys/import_test.go index aad96b83e8fe..8ec384c0c7b8 100644 --- a/client/keys/import_test.go +++ b/client/keys/import_test.go @@ -9,7 +9,9 @@ import ( "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/crypto/keys" "github.com/cosmos/cosmos-sdk/tests" + sdk "github.com/cosmos/cosmos-sdk/types" ) func Test_runImportCmd(t *testing.T) { @@ -23,7 +25,7 @@ func Test_runImportCmd(t *testing.T) { viper.Set(flags.FlagHome, kbHome) if !runningUnattended { - kb, err := NewKeyringFromHomeFlag(mockIn) + kb, err := keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) require.NoError(t, err) defer func() { kb.Delete("keyname1", "", false) diff --git a/client/keys/list.go b/client/keys/list.go index 1954a46de35c..104414b4164b 100644 --- a/client/keys/list.go +++ b/client/keys/list.go @@ -5,6 +5,8 @@ import ( "github.com/spf13/viper" "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/crypto/keys" + sdk "github.com/cosmos/cosmos-sdk/types" ) const flagListNames = "list-names" @@ -24,7 +26,7 @@ along with their associated name and address.`, } func runListCmd(cmd *cobra.Command, _ []string) error { - kb, err := NewKeyringFromHomeFlag(cmd.InOrStdin()) + kb, err := keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), cmd.InOrStdin()) if err != nil { return err } diff --git a/client/keys/list_test.go b/client/keys/list_test.go index 7ea8b3fb69d1..ac3953924b1b 100644 --- a/client/keys/list_test.go +++ b/client/keys/list_test.go @@ -10,6 +10,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/crypto/keys" "github.com/cosmos/cosmos-sdk/tests" + sdk "github.com/cosmos/cosmos-sdk/types" ) func Test_runListCmd(t *testing.T) { @@ -31,7 +32,7 @@ func Test_runListCmd(t *testing.T) { viper.Set(flags.FlagHome, kbHome2) mockIn, _, _ := tests.ApplyMockIO(cmdBasic) - kb, err := NewKeyringFromHomeFlag(mockIn) + kb, err := keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) require.NoError(t, err) if runningUnattended { mockIn.Reset("testpass1\ntestpass1\n") diff --git a/client/keys/migrate.go b/client/keys/migrate.go index 228248afceb5..fa15903afbc7 100644 --- a/client/keys/migrate.go +++ b/client/keys/migrate.go @@ -70,9 +70,9 @@ func runMigrateCmd(cmd *cobra.Command, args []string) error { defer os.RemoveAll(tmpDir) - keybase, err = keys.NewTestKeyring(keyringServiceName, tmpDir) + keybase, err = keys.NewKeyring(keyringServiceName, "test", tmpDir, buf) } else { - keybase, err = keys.NewKeyring(keyringServiceName, rootDir, buf) + keybase, err = keys.NewKeyring(keyringServiceName, viper.GetString(flags.FlagKeyringBackend), rootDir, buf) } if err != nil { return errors.Wrap(err, fmt.Sprintf( diff --git a/client/keys/root_test.go b/client/keys/root_test.go index 49681b17e95f..50bb3a5975c1 100644 --- a/client/keys/root_test.go +++ b/client/keys/root_test.go @@ -8,6 +8,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/crypto/keys" ) func TestCommands(t *testing.T) { @@ -19,6 +20,6 @@ func TestCommands(t *testing.T) { } func TestMain(m *testing.M) { - viper.Set(flags.FlagKeyringBackend, flags.KeyringBackendTest) + viper.Set(flags.FlagKeyringBackend, keys.BackendTest) os.Exit(m.Run()) } diff --git a/client/keys/show.go b/client/keys/show.go index e848a2208bb3..143d49bec885 100644 --- a/client/keys/show.go +++ b/client/keys/show.go @@ -57,7 +57,7 @@ consisting of all the keys provided by name and multisig threshold.`, func runShowCmd(cmd *cobra.Command, args []string) (err error) { var info keys.Info - kb, err := NewKeyringFromHomeFlag(cmd.InOrStdin()) + kb, err := keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), cmd.InOrStdin()) if err != nil { return err } diff --git a/client/keys/show_test.go b/client/keys/show_test.go index 6e261bd1e740..b8e7a8d5c73d 100644 --- a/client/keys/show_test.go +++ b/client/keys/show_test.go @@ -49,7 +49,7 @@ func Test_runShowCmd(t *testing.T) { fakeKeyName1 := "runShowCmd_Key1" fakeKeyName2 := "runShowCmd_Key2" - kb, err := NewKeyringFromHomeFlag(mockIn) + kb, err := keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) require.NoError(t, err) defer func() { kb.Delete("runShowCmd_Key1", "", false) diff --git a/client/keys/update.go b/client/keys/update.go index 79b3ad4498ae..2ca46d43289b 100644 --- a/client/keys/update.go +++ b/client/keys/update.go @@ -4,7 +4,9 @@ import ( "bufio" "github.com/spf13/cobra" + "github.com/spf13/viper" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/input" ) @@ -30,7 +32,7 @@ func runUpdateCmd(cmd *cobra.Command, args []string) error { name := args[0] buf := bufio.NewReader(cmd.InOrStdin()) - kb, err := NewKeyBaseFromHomeFlag() + kb, err := NewKeyBaseFromDir(viper.GetString(flags.FlagHome)) if err != nil { return err } diff --git a/client/keys/update_test.go b/client/keys/update_test.go index 9d7b46c4aa81..351cedd578ce 100644 --- a/client/keys/update_test.go +++ b/client/keys/update_test.go @@ -37,7 +37,7 @@ func Test_runUpdateCmd(t *testing.T) { defer cleanUp1() viper.Set(flags.FlagHome, kbHome) - kb, err := NewKeyBaseFromHomeFlag() + kb, err := NewKeyBaseFromDir(viper.GetString(flags.FlagHome)) assert.NoError(t, err) _, err = kb.CreateAccount(fakeKeyName1, tests.TestMnemonic, "", "", "0", keys.Secp256k1) assert.NoError(t, err) diff --git a/client/keys/utils.go b/client/keys/utils.go index f6cf20e818df..008d3ccf7822 100644 --- a/client/keys/utils.go +++ b/client/keys/utils.go @@ -2,7 +2,6 @@ package keys import ( "fmt" - "io" "path/filepath" "github.com/99designs/keyring" @@ -12,7 +11,6 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/crypto/keys" - sdk "github.com/cosmos/cosmos-sdk/types" ) // available output formats. @@ -26,13 +24,6 @@ const ( type bechKeyOutFn func(keyInfo keys.Info) (keys.KeyOutput, error) -// NewKeyBaseFromHomeFlag initializes a Keybase based on the configuration. Keybase -// options can be applied when generating this new Keybase. -func NewKeyBaseFromHomeFlag(opts ...keys.KeybaseOption) (keys.Keybase, error) { - rootDir := viper.GetString(flags.FlagHome) - return NewKeyBaseFromDir(rootDir, opts...) -} - // NewKeyBaseFromDir initializes a keybase at the rootDir directory. Keybase // options can be applied when generating this new Keybase. func NewKeyBaseFromDir(rootDir string, opts ...keys.KeybaseOption) (keys.Keybase, error) { @@ -42,29 +33,6 @@ func NewKeyBaseFromDir(rootDir string, opts ...keys.KeybaseOption) (keys.Keybase // NewInMemoryKeyBase returns a storage-less keybase. func NewInMemoryKeyBase() keys.Keybase { return keys.NewInMemory() } -// NewKeyBaseFromHomeFlag initializes a keyring based on configuration. Keybase -// options can be applied when generating this new Keybase. -func NewKeyringFromHomeFlag(input io.Reader, opts ...keys.KeybaseOption) (keys.Keybase, error) { - return NewKeyringFromDir(viper.GetString(flags.FlagHome), input, opts...) -} - -// NewKeyBaseFromDir initializes a keyring at the given directory. -// If the viper flag flags.FlagKeyringBackend is set to file, it returns an on-disk keyring with -// CLI prompt support only. If flags.FlagKeyringBackend is set to test it will return an on-disk, -// password-less keyring that could be used for testing purposes. -func NewKeyringFromDir(rootDir string, input io.Reader, opts ...keys.KeybaseOption) (keys.Keybase, error) { - keyringBackend := viper.GetString(flags.FlagKeyringBackend) - switch keyringBackend { - case flags.KeyringBackendTest: - return keys.NewTestKeyring(sdk.GetConfig().GetKeyringServiceName(), rootDir, opts...) - case flags.KeyringBackendFile: - return keys.NewKeyringFile(sdk.GetConfig().GetKeyringServiceName(), rootDir, input, opts...) - case flags.KeyringBackendOS: - return keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), rootDir, input, opts...) - } - return nil, fmt.Errorf("unknown keyring backend %q", keyringBackend) -} - func getLazyKeyBaseFromDir(rootDir string, opts ...keys.KeybaseOption) (keys.Keybase, error) { return keys.New(defaultKeyDBName, filepath.Join(rootDir, "keys"), opts...), nil } diff --git a/client/keys/utils_test.go b/client/keys/utils_test.go deleted file mode 100644 index 85fb7b63a116..000000000000 --- a/client/keys/utils_test.go +++ /dev/null @@ -1,25 +0,0 @@ -package keys - -import ( - "path/filepath" - "strings" - "testing" - - "github.com/spf13/viper" - "github.com/stretchr/testify/require" - - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/tests" -) - -func TestNewKeyringFromDir(t *testing.T) { - dir, cleanup := tests.NewTestCaseDir(t) - defer cleanup() - viper.Set(flags.FlagKeyringBackend, flags.KeyringBackendTest) - _, err := NewKeyringFromDir(filepath.Join(dir, "test"), nil) - require.NoError(t, err) - viper.Set(flags.FlagKeyringBackend, flags.KeyringBackendFile) - buf := strings.NewReader("password\npassword\n") - _, err = NewKeyringFromDir(filepath.Join(dir, "test"), buf) - require.NoError(t, err) -} diff --git a/crypto/keys/keyring.go b/crypto/keys/keyring.go index d5bd74a0d66e..92071f0706db 100644 --- a/crypto/keys/keyring.go +++ b/crypto/keys/keyring.go @@ -26,8 +26,14 @@ import ( ) const ( - keyringDirName = "keyring" - testKeyringDirName = "keyring-test" + BackendFile = "file" + BackendOS = "os" + BackendTest = "test" +) + +const ( + keyringDirNameFmt = "keyring-%s" + testKeyringDirNameFmt = "keyring-test-%s" ) var _ Keybase = keyringKeybase{} @@ -50,31 +56,24 @@ func newKeyringKeybase(db keyring.Keyring, opts ...KeybaseOption) Keybase { // NewKeyring creates a new instance of a keyring. Keybase // options can be applied when generating this new Keybase. +// Available backends are "os", "file", "test". func NewKeyring( - name string, dir string, userInput io.Reader, opts ...KeybaseOption, + svcName, backend, rootDir string, userInput io.Reader, opts ...KeybaseOption, ) (Keybase, error) { - db, err := keyring.Open(lkbToKeyringConfig(name, dir, userInput, false)) - if err != nil { - return nil, err - } - return newKeyringKeybase(db, opts...), nil -} + var db keyring.Keyring + var err error -// NewKeyringFile creates a new instance of an encrypted file-backed keyring. -func NewKeyringFile(name string, dir string, userInput io.Reader, opts ...KeybaseOption) (Keybase, error) { - db, err := keyring.Open(newFileBackendKeyringConfig(name, dir, userInput)) - if err != nil { - return nil, err + switch backend { + case BackendTest: + db, err = keyring.Open(lkbToKeyringConfig(svcName, rootDir, nil, true)) + case BackendFile: + db, err = keyring.Open(newFileBackendKeyringConfig(svcName, rootDir, userInput)) + case BackendOS: + db, err = keyring.Open(lkbToKeyringConfig(svcName, rootDir, userInput, false)) + default: + return nil, fmt.Errorf("unknown keyring backend %v", backend) } - - return newKeyringKeybase(db, opts...), nil -} - -// NewTestKeyring creates a new instance of an on-disk keyring for -// testing purposes that does not prompt users for password. -func NewTestKeyring(name string, dir string, opts ...KeybaseOption) (Keybase, error) { - db, err := keyring.Open(lkbToKeyringConfig(name, dir, nil, true)) if err != nil { return nil, err } @@ -488,7 +487,7 @@ func lkbToKeyringConfig(name, dir string, buf io.Reader, test bool) keyring.Conf return keyring.Config{ AllowedBackends: []keyring.BackendType{"file"}, ServiceName: name, - FileDir: filepath.Join(dir, testKeyringDirName), + FileDir: filepath.Join(dir, fmt.Sprintf(testKeyringDirNameFmt, name)), FilePasswordFunc: func(_ string) (string, error) { return "test", nil }, @@ -503,7 +502,7 @@ func lkbToKeyringConfig(name, dir string, buf io.Reader, test bool) keyring.Conf } func newFileBackendKeyringConfig(name, dir string, buf io.Reader) keyring.Config { - fileDir := filepath.Join(dir, keyringDirName) + fileDir := filepath.Join(dir, fmt.Sprintf(keyringDirNameFmt, name)) return keyring.Config{ AllowedBackends: []keyring.BackendType{"file"}, ServiceName: name, diff --git a/crypto/keys/keyring_test.go b/crypto/keys/keyring_test.go index 1149a2691c09..066f438e030f 100644 --- a/crypto/keys/keyring_test.go +++ b/crypto/keys/keyring_test.go @@ -2,7 +2,6 @@ package keys import ( - "strings" "testing" "github.com/stretchr/testify/assert" @@ -18,7 +17,7 @@ import ( func TestLazyKeyManagementKeyRing(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) defer cleanup() - kb, err := NewTestKeyring("keybasename", dir) + kb, err := NewKeyring("keybasename", "test", dir, nil) require.NoError(t, err) algo := Secp256k1 @@ -102,7 +101,7 @@ func TestLazyKeyManagementKeyRing(t *testing.T) { func TestLazySignVerifyKeyRing(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) defer cleanup() - kb, err := NewTestKeyring("keybasename", dir) + kb, err := NewKeyring("keybasename", "test", dir, nil) require.NoError(t, err) algo := Secp256k1 @@ -178,7 +177,7 @@ func TestLazySignVerifyKeyRing(t *testing.T) { func TestLazyExportImportKeyRing(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) defer cleanup() - kb, err := NewTestKeyring("keybasename", dir) + kb, err := NewKeyring("keybasename", "test", dir, nil) require.NoError(t, err) info, _, err := kb.CreateMnemonic("john", English, "secretcpw", Secp256k1) @@ -207,7 +206,7 @@ func TestLazyExportImportKeyRing(t *testing.T) { func TestLazyExportImportPubKeyKeyRing(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) defer cleanup() - kb, err := NewTestKeyring("keybasename", dir) + kb, err := NewKeyring("keybasename", "test", dir, nil) require.NoError(t, err) algo := Secp256k1 @@ -248,7 +247,7 @@ func TestLazyExportImportPubKeyKeyRing(t *testing.T) { func TestLazyExportPrivateKeyObjectKeyRing(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) defer cleanup() - kb, err := NewTestKeyring("keybasename", dir) + kb, err := NewKeyring("keybasename", "test", dir, nil) require.NoError(t, err) info, _, err := kb.CreateMnemonic("john", English, "secretcpw", Secp256k1) @@ -264,7 +263,7 @@ func TestLazyExportPrivateKeyObjectKeyRing(t *testing.T) { func TestLazyAdvancedKeyManagementKeyRing(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) defer cleanup() - kb, err := NewTestKeyring("keybasename", dir) + kb, err := NewKeyring("keybasename", "test", dir, nil) require.NoError(t, err) algo := Secp256k1 @@ -298,7 +297,7 @@ func TestLazyAdvancedKeyManagementKeyRing(t *testing.T) { func TestLazySeedPhraseKeyRing(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) defer cleanup() - kb, err := NewTestKeyring("keybasename", dir) + kb, err := NewKeyring("keybasename", "test", dir, nil) require.NoError(t, err) algo := Secp256k1 @@ -326,11 +325,3 @@ func TestLazySeedPhraseKeyRing(t *testing.T) { require.Equal(t, info.GetPubKey().Address(), newInfo.GetPubKey().Address()) require.Equal(t, info.GetPubKey(), newInfo.GetPubKey()) } - -func TestNewKeyringFile(t *testing.T) { - dir, cleanup := tests.NewTestCaseDir(t) - defer cleanup() - buf := strings.NewReader("password\npassword\n") - _, err := NewKeyringFile("test", dir, buf) - require.NoError(t, err) -} diff --git a/server/init_test.go b/server/init_test.go index 2a447eef4f16..5d353ddd3540 100644 --- a/server/init_test.go +++ b/server/init_test.go @@ -27,7 +27,7 @@ func TestGenerateSaveCoinKey(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) defer cleanup() // clean after itself - kb, err := crkeys.NewTestKeyring(t.Name(), dir) + kb, err := crkeys.NewKeyring(t.Name(), "test", dir, nil) require.NoError(t, err) addr, mnemonic, err := server.GenerateSaveCoinKey(kb, "keyname", "012345678", false) @@ -49,7 +49,7 @@ func TestGenerateSaveCoinKeyOverwriteFlag(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) defer cleanup() // clean after itself - kb, err := crkeys.NewTestKeyring(t.Name(), dir) + kb, err := crkeys.NewKeyring(t.Name(), "test", dir, nil) require.NoError(t, err) keyname := "justakey" diff --git a/x/auth/client/cli/tx_multisign.go b/x/auth/client/cli/tx_multisign.go index 49e9b6860731..e622febe74b2 100644 --- a/x/auth/client/cli/tx_multisign.go +++ b/x/auth/client/cli/tx_multisign.go @@ -11,13 +11,12 @@ import ( "github.com/spf13/viper" "github.com/tendermint/tendermint/crypto/multisig" - "github.com/tendermint/tendermint/libs/cli" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/client/keys" "github.com/cosmos/cosmos-sdk/codec" - crkeys "github.com/cosmos/cosmos-sdk/crypto/keys" + "github.com/cosmos/cosmos-sdk/crypto/keys" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/x/auth/client/utils" "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -67,17 +66,18 @@ func makeMultiSignCmd(cdc *codec.Codec) func(cmd *cobra.Command, args []string) } inBuf := bufio.NewReader(cmd.InOrStdin()) - keybase, err := keys.NewKeyringFromDir(viper.GetString(cli.HomeFlag), inBuf) + kb, err := keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), + viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), inBuf) if err != nil { return } - multisigInfo, err := keybase.Get(args[1]) + multisigInfo, err := kb.Get(args[1]) if err != nil { return } - if multisigInfo.GetType() != crkeys.TypeMulti { - return fmt.Errorf("%q must be of type %s: %s", args[1], crkeys.TypeMulti, multisigInfo.GetType()) + if multisigInfo.GetType() != keys.TypeMulti { + return fmt.Errorf("%q must be of type %s: %s", args[1], keys.TypeMulti, multisigInfo.GetType()) } multisigPub := multisigInfo.GetPubKey().(multisig.PubKeyMultisigThreshold) diff --git a/x/auth/types/txbuilder.go b/x/auth/types/txbuilder.go index b5f7eee8c68b..cc2387285368 100644 --- a/x/auth/types/txbuilder.go +++ b/x/auth/types/txbuilder.go @@ -10,15 +10,14 @@ import ( "github.com/spf13/viper" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/client/keys" - crkeys "github.com/cosmos/cosmos-sdk/crypto/keys" + "github.com/cosmos/cosmos-sdk/crypto/keys" sdk "github.com/cosmos/cosmos-sdk/types" ) // TxBuilder implements a transaction context created in SDK modules. type TxBuilder struct { txEncoder sdk.TxEncoder - keybase crkeys.Keybase + keybase keys.Keybase accountNumber uint64 sequence uint64 gas uint64 @@ -54,7 +53,7 @@ func NewTxBuilder( // NewTxBuilderFromCLI returns a new initialized TxBuilder with parameters from // the command line using Viper. func NewTxBuilderFromCLI(input io.Reader) TxBuilder { - kb, err := keys.NewKeyringFromHomeFlag(input) + kb, err := keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), input) if err != nil { panic(err) } @@ -91,7 +90,7 @@ func (bldr TxBuilder) Gas() uint64 { return bldr.gas } func (bldr TxBuilder) GasAdjustment() float64 { return bldr.gasAdjustment } // Keybase returns the keybase -func (bldr TxBuilder) Keybase() crkeys.Keybase { return bldr.keybase } +func (bldr TxBuilder) Keybase() keys.Keybase { return bldr.keybase } // SimulateAndExecute returns the option to simulate and then execute the transaction // using the gas from the simulation results @@ -150,7 +149,7 @@ func (bldr TxBuilder) WithGasPrices(gasPrices string) TxBuilder { } // WithKeybase returns a copy of the context with updated keybase. -func (bldr TxBuilder) WithKeybase(keybase crkeys.Keybase) TxBuilder { +func (bldr TxBuilder) WithKeybase(keybase keys.Keybase) TxBuilder { bldr.keybase = keybase return bldr } @@ -273,10 +272,11 @@ func (bldr TxBuilder) SignStdTx(name, passphrase string, stdTx StdTx, appendSig } // MakeSignature builds a StdSignature given keybase, key name, passphrase, and a StdSignMsg. -func MakeSignature(keybase crkeys.Keybase, name, passphrase string, +func MakeSignature(keybase keys.Keybase, name, passphrase string, msg StdSignMsg) (sig StdSignature, err error) { + if keybase == nil { - keybase, err = keys.NewKeyringFromHomeFlag(os.Stdin) + keybase, err = keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), os.Stdin) if err != nil { return } diff --git a/x/genutil/client/cli/gentx.go b/x/genutil/client/cli/gentx.go index f76fcc3a36a2..fc5de44973b3 100644 --- a/x/genutil/client/cli/gentx.go +++ b/x/genutil/client/cli/gentx.go @@ -21,9 +21,8 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/client/keys" "github.com/cosmos/cosmos-sdk/codec" - kbkeys "github.com/cosmos/cosmos-sdk/crypto/keys" + "github.com/cosmos/cosmos-sdk/crypto/keys" "github.com/cosmos/cosmos-sdk/server" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" @@ -94,7 +93,8 @@ func GenTxCmd(ctx *server.Context, cdc *codec.Codec, mbm module.BasicManager, sm } inBuf := bufio.NewReader(cmd.InOrStdin()) - kb, err := keys.NewKeyringFromDir(viper.GetString(flagClientHome), inBuf) + kb, err := keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), + viper.GetString(flags.FlagKeyringBackend), viper.GetString(flagClientHome), inBuf) if err != nil { return errors.Wrap(err, "failed to initialize keybase") } @@ -137,7 +137,7 @@ func GenTxCmd(ctx *server.Context, cdc *codec.Codec, mbm module.BasicManager, sm return errors.Wrap(err, "failed to build create-validator message") } - if key.GetType() == kbkeys.TypeOffline || key.GetType() == kbkeys.TypeMulti { + if key.GetType() == keys.TypeOffline || key.GetType() == keys.TypeMulti { fmt.Println("Offline key passed in. Use `tx sign` command to sign:") return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}) } From f18005d2f18bae619723066784c53d6bed925542 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Wed, 22 Jan 2020 14:52:56 -0500 Subject: [PATCH 089/529] Merge PR #5538: Refactor IAVL Pruning --- CHANGELOG.md | 1 + baseapp/baseapp_test.go | 4 +- store/cache/cache_test.go | 6 +-- store/iavl/store.go | 62 +++++++------------------ store/iavl/store_test.go | 86 +++++++++++++++++------------------ store/prefix/store_test.go | 2 +- store/rootmulti/proof_test.go | 2 +- store/rootmulti/store.go | 14 ++++-- store/rootmulti/store_test.go | 59 ++++++++++++------------ store/types/pruning.go | 2 +- 10 files changed, 106 insertions(+), 132 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 58b5577a6cbc..5b8d9ff1b224 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -201,6 +201,7 @@ that allows for arbitrary vesting periods. ### Improvements +* (iavl) [\#5538](https://github.com/cosmos/cosmos-sdk/pull/5538) Remove manual IAVL pruning in favor of IAVL's internal pruning strategy. * (server) [\#4215](https://github.com/cosmos/cosmos-sdk/issues/4215) The `--pruning` flag has been moved to the configuration file, to allow easier node configuration. * (cli) [\#5116](https://github.com/cosmos/cosmos-sdk/issues/5116) The `CLIContext` now supports multiple verifiers diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index 179c80463bc4..8e2caf466c99 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -151,7 +151,7 @@ func useFileUpgradeLoader(upgradeInfoPath string) func(*BaseApp) { func initStore(t *testing.T, db dbm.DB, storeKey string, k, v []byte) { rs := rootmulti.NewStore(db) - rs.SetPruning(store.PruneSyncable) + rs.SetPruning(store.PruneNothing) key := sdk.NewKVStoreKey(storeKey) rs.MountStoreWithDB(key, store.StoreTypeIAVL, nil) err := rs.LoadLatestVersion() @@ -244,7 +244,7 @@ func TestSetLoader(t *testing.T) { initStore(t, db, tc.origStoreKey, k, v) // load the app with the existing db - opts := []func(*BaseApp){SetPruning(store.PruneSyncable)} + opts := []func(*BaseApp){SetPruning(store.PruneNothing)} if tc.setLoader != nil { opts = append(opts, tc.setLoader) } diff --git a/store/cache/cache_test.go b/store/cache/cache_test.go index 9dd4ff905b18..93ece75083ed 100644 --- a/store/cache/cache_test.go +++ b/store/cache/cache_test.go @@ -20,7 +20,7 @@ func TestGetOrSetStoreCache(t *testing.T) { sKey := types.NewKVStoreKey("test") tree, err := iavl.NewMutableTree(db, 100) require.NoError(t, err) - store := iavlstore.UnsafeNewStore(tree, 10, 10) + store := iavlstore.UnsafeNewStore(tree) store2 := mngr.GetStoreCache(sKey, store) require.NotNil(t, store2) @@ -34,7 +34,7 @@ func TestUnwrap(t *testing.T) { sKey := types.NewKVStoreKey("test") tree, err := iavl.NewMutableTree(db, 100) require.NoError(t, err) - store := iavlstore.UnsafeNewStore(tree, 10, 10) + store := iavlstore.UnsafeNewStore(tree) _ = mngr.GetStoreCache(sKey, store) require.Equal(t, store, mngr.Unwrap(sKey)) @@ -48,7 +48,7 @@ func TestStoreCache(t *testing.T) { sKey := types.NewKVStoreKey("test") tree, err := iavl.NewMutableTree(db, 100) require.NoError(t, err) - store := iavlstore.UnsafeNewStore(tree, 10, 10) + store := iavlstore.UnsafeNewStore(tree) kvStore := mngr.GetStoreCache(sKey, store) for i := uint(0); i < cache.DefaultCommitKVStoreCacheSize*2; i++ { diff --git a/store/iavl/store.go b/store/iavl/store.go index 4a346a65d7b9..66c5e5262209 100644 --- a/store/iavl/store.go +++ b/store/iavl/store.go @@ -4,7 +4,6 @@ import ( "io" "sync" - "github.com/pkg/errors" "github.com/tendermint/iavl" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto/merkle" @@ -31,25 +30,18 @@ var ( // Store Implements types.KVStore and CommitKVStore. type Store struct { tree Tree - - // How many old versions we hold onto. - // A value of 0 means keep no recent states. - numRecent int64 - - // This is the distance between state-sync waypoint states to be stored. - // See https://github.com/tendermint/tendermint/issues/828 - // A value of 1 means store every state. - // A value of 0 means store no waypoints. (node cannot assist in state-sync) - // By default this value should be set the same across all nodes, - // so that nodes can know the waypoints their peers store. - storeEvery int64 } // LoadStore returns an IAVL Store as a CommitKVStore. Internally it will load the // store's version (id) from the provided DB. An error is returned if the version // fails to load. func LoadStore(db dbm.DB, id types.CommitID, pruning types.PruningOptions, lazyLoading bool) (types.CommitKVStore, error) { - tree, err := iavl.NewMutableTree(db, defaultIAVLCacheSize) + tree, err := iavl.NewMutableTreeWithOpts( + db, + dbm.NewMemDB(), + defaultIAVLCacheSize, + iavl.PruningOptions(pruning.KeepEvery(), pruning.KeepRecent()), + ) if err != nil { return nil, err } @@ -64,21 +56,15 @@ func LoadStore(db dbm.DB, id types.CommitID, pruning types.PruningOptions, lazyL return nil, err } - iavl := UnsafeNewStore(tree, int64(0), int64(0)) - iavl.SetPruning(pruning) - - return iavl, nil + return &Store{tree: tree}, nil } -// UnsafeNewStore returns a reference to a new IAVL Store. +// UnsafeNewStore returns a reference to a new IAVL Store with a given mutable +// IAVL tree reference. // // CONTRACT: The IAVL tree should be fully loaded. -func UnsafeNewStore(tree *iavl.MutableTree, numRecent int64, storeEvery int64) *Store { - return &Store{ - tree: tree, - numRecent: numRecent, - storeEvery: storeEvery, - } +func UnsafeNewStore(tree *iavl.MutableTree) *Store { + return &Store{tree: tree} } // GetImmutable returns a reference to a new store backed by an immutable IAVL @@ -96,11 +82,7 @@ func (st *Store) GetImmutable(version int64) (*Store, error) { return nil, err } - return &Store{ - tree: &immutableTree{iTree}, - numRecent: 0, - storeEvery: 0, - }, nil + return &Store{tree: &immutableTree{iTree}}, nil } // Implements Committer. @@ -112,18 +94,6 @@ func (st *Store) Commit() types.CommitID { panic(err) } - // Release an old version of history, if not a sync waypoint. - previous := version - 1 - if st.numRecent < previous { - toRelease := previous - st.numRecent - if st.storeEvery == 0 || toRelease%st.storeEvery != 0 { - err := st.tree.DeleteVersion(toRelease) - if errCause := errors.Cause(err); errCause != nil && errCause != iavl.ErrVersionDoesNotExist { - panic(err) - } - } - } - return types.CommitID{ Version: version, Hash: hash, @@ -138,10 +108,10 @@ func (st *Store) LastCommitID() types.CommitID { } } -// Implements Committer. -func (st *Store) SetPruning(opt types.PruningOptions) { - st.numRecent = opt.KeepRecent() - st.storeEvery = opt.KeepEvery() +// SetPruning panics as pruning options should be provided at initialization +// since IAVl accepts pruning options directly. +func (st *Store) SetPruning(_ types.PruningOptions) { + panic("cannot set pruning options on an initialized IAVL store") } // VersionExists returns whether or not a given version is stored. diff --git a/store/iavl/store_test.go b/store/iavl/store_test.go index 9edebc1e98fc..8f47286e4cb5 100644 --- a/store/iavl/store_test.go +++ b/store/iavl/store_test.go @@ -14,13 +14,8 @@ import ( ) var ( - cacheSize = 100 - numRecent int64 = 5 - storeEvery int64 = 3 -) - -var ( - treeData = map[string]string{ + cacheSize = 100 + treeData = map[string]string{ "hello": "goodbye", "aloha": "shalom", } @@ -30,7 +25,6 @@ var ( func randBytes(numBytes int) []byte { b := make([]byte, numBytes) _, _ = crand.Read(b) - return b } @@ -58,7 +52,7 @@ func newAlohaTree(t *testing.T, db dbm.DB) (*iavl.MutableTree, types.CommitID) { func TestGetImmutable(t *testing.T) { db := dbm.NewMemDB() tree, cID := newAlohaTree(t, db) - store := UnsafeNewStore(tree, 10, 10) + store := UnsafeNewStore(tree) require.True(t, tree.Set([]byte("hello"), []byte("adios"))) hash, ver, err := tree.SaveVersion() @@ -88,7 +82,7 @@ func TestGetImmutable(t *testing.T) { func TestTestGetImmutableIterator(t *testing.T) { db := dbm.NewMemDB() tree, cID := newAlohaTree(t, db) - store := UnsafeNewStore(tree, 10, 10) + store := UnsafeNewStore(tree) newStore, err := store.GetImmutable(cID.Version) require.NoError(t, err) @@ -111,7 +105,7 @@ func TestTestGetImmutableIterator(t *testing.T) { func TestIAVLStoreGetSetHasDelete(t *testing.T) { db := dbm.NewMemDB() tree, _ := newAlohaTree(t, db) - iavlStore := UnsafeNewStore(tree, numRecent, storeEvery) + iavlStore := UnsafeNewStore(tree) key := "hello" @@ -136,14 +130,14 @@ func TestIAVLStoreGetSetHasDelete(t *testing.T) { func TestIAVLStoreNoNilSet(t *testing.T) { db := dbm.NewMemDB() tree, _ := newAlohaTree(t, db) - iavlStore := UnsafeNewStore(tree, numRecent, storeEvery) + iavlStore := UnsafeNewStore(tree) require.Panics(t, func() { iavlStore.Set([]byte("key"), nil) }, "setting a nil value should panic") } func TestIAVLIterator(t *testing.T) { db := dbm.NewMemDB() tree, _ := newAlohaTree(t, db) - iavlStore := UnsafeNewStore(tree, numRecent, storeEvery) + iavlStore := UnsafeNewStore(tree) iter := iavlStore.Iterator([]byte("aloha"), []byte("hellz")) expected := []string{"aloha", "hello"} var i int @@ -219,7 +213,7 @@ func TestIAVLReverseIterator(t *testing.T) { tree, err := iavl.NewMutableTree(db, cacheSize) require.NoError(t, err) - iavlStore := UnsafeNewStore(tree, numRecent, storeEvery) + iavlStore := UnsafeNewStore(tree) iavlStore.Set([]byte{0x00}, []byte("0")) iavlStore.Set([]byte{0x00, 0x00}, []byte("0 0")) @@ -252,7 +246,7 @@ func TestIAVLPrefixIterator(t *testing.T) { tree, err := iavl.NewMutableTree(db, cacheSize) require.NoError(t, err) - iavlStore := UnsafeNewStore(tree, numRecent, storeEvery) + iavlStore := UnsafeNewStore(tree) iavlStore.Set([]byte("test1"), []byte("test1")) iavlStore.Set([]byte("test2"), []byte("test2")) @@ -316,7 +310,7 @@ func TestIAVLReversePrefixIterator(t *testing.T) { tree, err := iavl.NewMutableTree(db, cacheSize) require.NoError(t, err) - iavlStore := UnsafeNewStore(tree, numRecent, storeEvery) + iavlStore := UnsafeNewStore(tree) iavlStore.Set([]byte("test1"), []byte("test1")) iavlStore.Set([]byte("test2"), []byte("test2")) @@ -389,16 +383,16 @@ func TestIAVLDefaultPruning(t *testing.T) { {[]int64{1, 2, 3}, []int64{}}, {[]int64{1, 2, 3, 4}, []int64{}}, {[]int64{1, 2, 3, 4, 5}, []int64{}}, - {[]int64{1, 2, 3, 4, 5, 6}, []int64{}}, - {[]int64{2, 3, 4, 5, 6, 7}, []int64{1}}, + {[]int64{2, 3, 4, 5, 6}, []int64{1}}, + {[]int64{3, 4, 5, 6, 7}, []int64{1, 2}}, {[]int64{3, 4, 5, 6, 7, 8}, []int64{1, 2}}, - {[]int64{3, 4, 5, 6, 7, 8, 9}, []int64{1, 2}}, - {[]int64{3, 5, 6, 7, 8, 9, 10}, []int64{1, 2, 4}}, + {[]int64{3, 5, 6, 7, 8, 9}, []int64{1, 2, 4}}, + {[]int64{3, 6, 7, 8, 9, 10}, []int64{1, 2, 4, 5}}, {[]int64{3, 6, 7, 8, 9, 10, 11}, []int64{1, 2, 4, 5}}, - {[]int64{3, 6, 7, 8, 9, 10, 11, 12}, []int64{1, 2, 4, 5}}, - {[]int64{3, 6, 8, 9, 10, 11, 12, 13}, []int64{1, 2, 4, 5, 7}}, + {[]int64{3, 6, 8, 9, 10, 11, 12}, []int64{1, 2, 4, 5, 7}}, + {[]int64{3, 6, 9, 10, 11, 12, 13}, []int64{1, 2, 4, 5, 7, 8}}, {[]int64{3, 6, 9, 10, 11, 12, 13, 14}, []int64{1, 2, 4, 5, 7, 8}}, - {[]int64{3, 6, 9, 10, 11, 12, 13, 14, 15}, []int64{1, 2, 4, 5, 7, 8}}, + {[]int64{3, 6, 9, 11, 12, 13, 14, 15}, []int64{1, 2, 4, 5, 7, 8, 10}}, } testPruning(t, int64(5), int64(3), states) } @@ -411,18 +405,18 @@ func TestIAVLAlternativePruning(t *testing.T) { {[]int64{1}, []int64{}}, {[]int64{1, 2}, []int64{}}, {[]int64{1, 2, 3}, []int64{}}, - {[]int64{1, 2, 3, 4}, []int64{}}, - {[]int64{2, 3, 4, 5}, []int64{1}}, - {[]int64{3, 4, 5, 6}, []int64{1, 2}}, - {[]int64{4, 5, 6, 7}, []int64{1, 2, 3}}, + {[]int64{2, 3, 4}, []int64{1}}, + {[]int64{3, 4, 5}, []int64{1, 2}}, + {[]int64{4, 5, 6}, []int64{1, 2, 3}}, + {[]int64{5, 6, 7}, []int64{1, 2, 3, 4}}, {[]int64{5, 6, 7, 8}, []int64{1, 2, 3, 4}}, - {[]int64{5, 6, 7, 8, 9}, []int64{1, 2, 3, 4}}, - {[]int64{5, 7, 8, 9, 10}, []int64{1, 2, 3, 4, 6}}, - {[]int64{5, 8, 9, 10, 11}, []int64{1, 2, 3, 4, 6, 7}}, - {[]int64{5, 9, 10, 11, 12}, []int64{1, 2, 3, 4, 6, 7, 8}}, + {[]int64{5, 7, 8, 9}, []int64{1, 2, 3, 4, 6}}, + {[]int64{5, 8, 9, 10}, []int64{1, 2, 3, 4, 6, 7}}, + {[]int64{5, 9, 10, 11}, []int64{1, 2, 3, 4, 6, 7, 8}}, + {[]int64{5, 10, 11, 12}, []int64{1, 2, 3, 4, 6, 7, 8, 9}}, {[]int64{5, 10, 11, 12, 13}, []int64{1, 2, 3, 4, 6, 7, 8, 9}}, - {[]int64{5, 10, 11, 12, 13, 14}, []int64{1, 2, 3, 4, 6, 7, 8, 9}}, - {[]int64{5, 10, 12, 13, 14, 15}, []int64{1, 2, 3, 4, 6, 7, 8, 9, 11}}, + {[]int64{5, 10, 12, 13, 14}, []int64{1, 2, 3, 4, 6, 7, 8, 9, 11}}, + {[]int64{5, 10, 13, 14, 15}, []int64{1, 2, 3, 4, 6, 7, 8, 9, 11, 12}}, } testPruning(t, int64(3), int64(5), states) } @@ -434,21 +428,23 @@ type pruneState struct { func testPruning(t *testing.T, numRecent int64, storeEvery int64, states []pruneState) { db := dbm.NewMemDB() - tree, err := iavl.NewMutableTree(db, cacheSize) + iavlOpts := iavl.PruningOptions(storeEvery, numRecent) + + tree, err := iavl.NewMutableTreeWithOpts(db, dbm.NewMemDB(), cacheSize, iavlOpts) require.NoError(t, err) - iavlStore := UnsafeNewStore(tree, numRecent, storeEvery) + iavlStore := UnsafeNewStore(tree) for step, state := range states { for _, ver := range state.stored { require.True(t, iavlStore.VersionExists(ver), - "Missing version %d with latest version %d. Should save last %d and every %d", + "missing version %d with latest version %d; should save last %d and every %d", ver, step, numRecent, storeEvery) } for _, ver := range state.deleted { require.False(t, iavlStore.VersionExists(ver), - "Unpruned version %d with latest version %d. Should prune all but last %d and every %d", + "not pruned version %d with latest version %d; should prune all but last %d and every %d", ver, step, numRecent, storeEvery) } @@ -461,7 +457,7 @@ func TestIAVLNoPrune(t *testing.T) { tree, err := iavl.NewMutableTree(db, cacheSize) require.NoError(t, err) - iavlStore := UnsafeNewStore(tree, numRecent, int64(1)) + iavlStore := UnsafeNewStore(tree) nextVersion(iavlStore) for i := 1; i < 100; i++ { @@ -477,21 +473,23 @@ func TestIAVLNoPrune(t *testing.T) { func TestIAVLPruneEverything(t *testing.T) { db := dbm.NewMemDB() - tree, err := iavl.NewMutableTree(db, cacheSize) + iavlOpts := iavl.PruningOptions(0, 1) // only store latest version in memory + + tree, err := iavl.NewMutableTreeWithOpts(db, dbm.NewMemDB(), cacheSize, iavlOpts) require.NoError(t, err) - iavlStore := UnsafeNewStore(tree, int64(0), int64(0)) + iavlStore := UnsafeNewStore(tree) nextVersion(iavlStore) for i := 1; i < 100; i++ { for j := 1; j < i; j++ { require.False(t, iavlStore.VersionExists(int64(j)), - "Unpruned version %d with latest version %d. Should prune all old versions", + "not pruned version %d with latest version %d; should prune all old versions", j, i) } require.True(t, iavlStore.VersionExists(int64(i)), - "Missing current version on step %d, should not prune current state tree", + "missing current version on step %d; should not prune current state tree", i) nextVersion(iavlStore) @@ -503,7 +501,7 @@ func TestIAVLStoreQuery(t *testing.T) { tree, err := iavl.NewMutableTree(db, cacheSize) require.NoError(t, err) - iavlStore := UnsafeNewStore(tree, numRecent, storeEvery) + iavlStore := UnsafeNewStore(tree) k1, v1 := []byte("key1"), []byte("val1") k2, v2 := []byte("key2"), []byte("val2") @@ -602,7 +600,7 @@ func BenchmarkIAVLIteratorNext(b *testing.B) { tree.Set(key, value) } - iavlStore := UnsafeNewStore(tree, numRecent, storeEvery) + iavlStore := UnsafeNewStore(tree) iterators := make([]types.Iterator, b.N/treeSize) for i := 0; i < len(iterators); i++ { diff --git a/store/prefix/store_test.go b/store/prefix/store_test.go index ca1d5f822246..8431459748d0 100644 --- a/store/prefix/store_test.go +++ b/store/prefix/store_test.go @@ -90,7 +90,7 @@ func TestIAVLStorePrefix(t *testing.T) { db := dbm.NewMemDB() tree, err := tiavl.NewMutableTree(db, cacheSize) require.NoError(t, err) - iavlStore := iavl.UnsafeNewStore(tree, numRecent, storeEvery) + iavlStore := iavl.UnsafeNewStore(tree) testPrefixStore(t, iavlStore, []byte("test")) } diff --git a/store/rootmulti/proof_test.go b/store/rootmulti/proof_test.go index 03bf5e8c6956..4d316f2c85aa 100644 --- a/store/rootmulti/proof_test.go +++ b/store/rootmulti/proof_test.go @@ -61,7 +61,7 @@ func TestVerifyMultiStoreQueryProof(t *testing.T) { iavlStoreKey := types.NewKVStoreKey("iavlStoreKey") store.MountStoreWithDB(iavlStoreKey, types.StoreTypeIAVL, nil) - store.LoadVersion(0) + require.NoError(t, store.LoadVersion(0)) iavlStore := store.GetCommitStore(iavlStoreKey).(*iavl.Store) iavlStore.Set([]byte("MYKEY"), []byte("MYVALUE")) diff --git a/store/rootmulti/store.go b/store/rootmulti/store.go index 6e4452518fca..5239ab8a4e15 100644 --- a/store/rootmulti/store.go +++ b/store/rootmulti/store.go @@ -45,17 +45,26 @@ type Store struct { var _ types.CommitMultiStore = (*Store)(nil) var _ types.Queryable = (*Store)(nil) -// nolint +// NewStore returns a reference to a new Store object with the provided DB. The +// store will be created with a PruneNothing pruning strategy by default. After +// a store is created, KVStores must be mounted and finally LoadLatestVersion or +// LoadVersion must be called. func NewStore(db dbm.DB) *Store { return &Store{ db: db, + pruningOpts: types.PruneNothing, storesParams: make(map[types.StoreKey]storeParams), stores: make(map[types.StoreKey]types.CommitKVStore), keysByName: make(map[string]types.StoreKey), } } -// Implements CommitMultiStore +// SetPruning sets the pruning strategy on the root store and all the sub-stores. +// Note, calling SetPruning on the root store prior to LoadVersion or +// LoadLatestVersion performs a no-op as the stores aren't mounted yet. +// +// TODO: Consider removing this API altogether on sub-stores as a pruning +// strategy should only be provided on initialization. func (rs *Store) SetPruning(pruningOpts types.PruningOptions) { rs.pruningOpts = pruningOpts for _, substore := range rs.stores { @@ -156,7 +165,6 @@ func (rs *Store) loadVersion(ver int64, upgrades *types.StoreUpgrades) error { // load each Store (note this doesn't panic on unmounted keys now) var newStores = make(map[types.StoreKey]types.CommitKVStore) for key, storeParams := range rs.storesParams { - // Load it store, err := rs.loadCommitStoreFromParams(key, rs.getCommitID(infos, key.Name()), storeParams) if err != nil { diff --git a/store/rootmulti/store_test.go b/store/rootmulti/store_test.go index 16181c4080f2..56111436bd22 100644 --- a/store/rootmulti/store_test.go +++ b/store/rootmulti/store_test.go @@ -21,7 +21,7 @@ func TestStoreType(t *testing.T) { func TestGetCommitKVStore(t *testing.T) { var db dbm.DB = dbm.NewMemDB() - ms := newMultiStoreWithMounts(db) + ms := newMultiStoreWithMounts(db, types.PruneSyncable) err := ms.LoadLatestVersion() require.Nil(t, err) @@ -53,7 +53,7 @@ func TestStoreMount(t *testing.T) { func TestCacheMultiStoreWithVersion(t *testing.T) { var db dbm.DB = dbm.NewMemDB() - ms := newMultiStoreWithMounts(db) + ms := newMultiStoreWithMounts(db, types.PruneSyncable) err := ms.LoadLatestVersion() require.Nil(t, err) @@ -90,7 +90,7 @@ func TestCacheMultiStoreWithVersion(t *testing.T) { func TestHashStableWithEmptyCommit(t *testing.T) { var db dbm.DB = dbm.NewMemDB() - ms := newMultiStoreWithMounts(db) + ms := newMultiStoreWithMounts(db, types.PruneSyncable) err := ms.LoadLatestVersion() require.Nil(t, err) @@ -114,7 +114,7 @@ func TestHashStableWithEmptyCommit(t *testing.T) { func TestMultistoreCommitLoad(t *testing.T) { var db dbm.DB = dbm.NewMemDB() - store := newMultiStoreWithMounts(db) + store := newMultiStoreWithMounts(db, types.PruneSyncable) err := store.LoadLatestVersion() require.Nil(t, err) @@ -139,7 +139,7 @@ func TestMultistoreCommitLoad(t *testing.T) { } // Load the latest multistore again and check version. - store = newMultiStoreWithMounts(db) + store = newMultiStoreWithMounts(db, types.PruneSyncable) err = store.LoadLatestVersion() require.Nil(t, err) commitID = getExpectedCommitID(store, nCommits) @@ -152,7 +152,7 @@ func TestMultistoreCommitLoad(t *testing.T) { // Load an older multistore and check version. ver := nCommits - 1 - store = newMultiStoreWithMounts(db) + store = newMultiStoreWithMounts(db, types.PruneSyncable) err = store.LoadVersion(ver) require.Nil(t, err) commitID = getExpectedCommitID(store, ver) @@ -165,7 +165,7 @@ func TestMultistoreCommitLoad(t *testing.T) { // XXX: confirm old commit is overwritten and we have rolled back // LatestVersion - store = newMultiStoreWithMounts(db) + store = newMultiStoreWithMounts(db, types.PruneSyncable) err = store.LoadLatestVersion() require.Nil(t, err) commitID = getExpectedCommitID(store, ver+1) @@ -174,7 +174,7 @@ func TestMultistoreCommitLoad(t *testing.T) { func TestMultistoreLoadWithUpgrade(t *testing.T) { var db dbm.DB = dbm.NewMemDB() - store := newMultiStoreWithMounts(db) + store := newMultiStoreWithMounts(db, types.PruneNothing) err := store.LoadLatestVersion() require.Nil(t, err) @@ -206,7 +206,8 @@ func TestMultistoreLoadWithUpgrade(t *testing.T) { checkContains(t, ci.StoreInfos, []string{"store1", "store2", "store3"}) // Load without changes and make sure it is sensible - store = newMultiStoreWithMounts(db) + store = newMultiStoreWithMounts(db, types.PruneNothing) + err = store.LoadLatestVersion() require.Nil(t, err) commitID = getExpectedCommitID(store, 1) @@ -218,7 +219,7 @@ func TestMultistoreLoadWithUpgrade(t *testing.T) { require.Equal(t, v2, s2.Get(k2)) // now, let's load with upgrades... - restore, upgrades := newMultiStoreWithModifiedMounts(db) + restore, upgrades := newMultiStoreWithModifiedMounts(db, types.PruneNothing) err = restore.LoadLatestVersionAndUpgrade(upgrades) require.Nil(t, err) @@ -245,7 +246,7 @@ func TestMultistoreLoadWithUpgrade(t *testing.T) { migratedID := restore.Commit() require.Equal(t, migratedID.Version, int64(2)) - reload, _ := newMultiStoreWithModifiedMounts(db) + reload, _ := newMultiStoreWithModifiedMounts(db, types.PruneNothing) err = reload.LoadLatestVersion() require.Nil(t, err) require.Equal(t, migratedID, reload.LastCommitID()) @@ -290,7 +291,7 @@ func TestParsePath(t *testing.T) { func TestMultiStoreQuery(t *testing.T) { db := dbm.NewMemDB() - multi := newMultiStoreWithMounts(db) + multi := newMultiStoreWithMounts(db, types.PruneNothing) err := multi.LoadLatestVersion() require.Nil(t, err) @@ -317,7 +318,7 @@ func TestMultiStoreQuery(t *testing.T) { ver := cid.Version // Reload multistore from database - multi = newMultiStoreWithMounts(db) + multi = newMultiStoreWithMounts(db, types.PruneNothing) err = multi.LoadLatestVersion() require.Nil(t, err) @@ -361,29 +362,24 @@ func TestMultiStoreQuery(t *testing.T) { //----------------------------------------------------------------------- // utils -func newMultiStoreWithMounts(db dbm.DB) *Store { +func newMultiStoreWithMounts(db dbm.DB, pruningOpts types.PruningOptions) *Store { store := NewStore(db) - store.pruningOpts = types.PruneSyncable - store.MountStoreWithDB( - types.NewKVStoreKey("store1"), types.StoreTypeIAVL, nil) - store.MountStoreWithDB( - types.NewKVStoreKey("store2"), types.StoreTypeIAVL, nil) - store.MountStoreWithDB( - types.NewKVStoreKey("store3"), types.StoreTypeIAVL, nil) + store.pruningOpts = pruningOpts + + store.MountStoreWithDB(types.NewKVStoreKey("store1"), types.StoreTypeIAVL, nil) + store.MountStoreWithDB(types.NewKVStoreKey("store2"), types.StoreTypeIAVL, nil) + store.MountStoreWithDB(types.NewKVStoreKey("store3"), types.StoreTypeIAVL, nil) + return store } -// store2 -> restore2 -// store3 dropped data (but mount still there to test) -func newMultiStoreWithModifiedMounts(db dbm.DB) (*Store, *types.StoreUpgrades) { +func newMultiStoreWithModifiedMounts(db dbm.DB, pruningOpts types.PruningOptions) (*Store, *types.StoreUpgrades) { store := NewStore(db) - store.pruningOpts = types.PruneSyncable - store.MountStoreWithDB( - types.NewKVStoreKey("store1"), types.StoreTypeIAVL, nil) - store.MountStoreWithDB( - types.NewKVStoreKey("restore2"), types.StoreTypeIAVL, nil) - store.MountStoreWithDB( - types.NewKVStoreKey("store3"), types.StoreTypeIAVL, nil) + store.pruningOpts = pruningOpts + + store.MountStoreWithDB(types.NewKVStoreKey("store1"), types.StoreTypeIAVL, nil) + store.MountStoreWithDB(types.NewKVStoreKey("restore2"), types.StoreTypeIAVL, nil) + store.MountStoreWithDB(types.NewKVStoreKey("store3"), types.StoreTypeIAVL, nil) upgrades := &types.StoreUpgrades{ Renamed: []types.StoreRename{{ @@ -392,6 +388,7 @@ func newMultiStoreWithModifiedMounts(db dbm.DB) (*Store, *types.StoreUpgrades) { }}, Deleted: []string{"store3"}, } + return store, upgrades } diff --git a/store/types/pruning.go b/store/types/pruning.go index f82023a2c998..cd4f19b61689 100644 --- a/store/types/pruning.go +++ b/store/types/pruning.go @@ -27,7 +27,7 @@ func (po PruningOptions) KeepEvery() int64 { // default pruning strategies var ( // PruneEverything means all saved states will be deleted, storing only the current state - PruneEverything = NewPruningOptions(0, 0) + PruneEverything = NewPruningOptions(1, 0) // PruneNothing means all historic states will be saved, nothing will be deleted PruneNothing = NewPruningOptions(0, 1) // PruneSyncable means only those states not needed for state syncing will be deleted (keeps last 100 + every 10000th) From 7d953d1ad0c94c4ce47a67cdf48079c72714a877 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 23 Jan 2020 10:02:37 +0100 Subject: [PATCH 090/529] Bump gopkg.in/yaml.v2 from 2.2.7 to 2.2.8 (#5554) Bumps [gopkg.in/yaml.v2](https://github.com/go-yaml/yaml) from 2.2.7 to 2.2.8. - [Release notes](https://github.com/go-yaml/yaml/releases) - [Commits](https://github.com/go-yaml/yaml/compare/v2.2.7...v2.2.8) Signed-off-by: dependabot-preview[bot] --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 989492906653..612c513549fc 100644 --- a/go.mod +++ b/go.mod @@ -27,7 +27,7 @@ require ( github.com/tendermint/iavl v0.13.0 github.com/tendermint/tendermint v0.33.0 github.com/tendermint/tm-db v0.4.0 - gopkg.in/yaml.v2 v2.2.7 + gopkg.in/yaml.v2 v2.2.8 ) go 1.13 diff --git a/go.sum b/go.sum index 796402b6b6c7..4fd5999711d2 100644 --- a/go.sum +++ b/go.sum @@ -369,5 +369,7 @@ gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo= gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= From 1feb22c4f0ae8231d46471f80fe4529092ac2a28 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Thu, 23 Jan 2020 16:48:00 +0000 Subject: [PATCH 091/529] [keyring] support for kwallet, pass (#5560) Add support for KDE Wallet service and the pass command line tool. --- CHANGELOG.md | 2 ++ crypto/keys/keyring.go | 34 +++++++++++++++++++++++++++++----- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b8d9ff1b224..23a00c197ee2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -152,6 +152,8 @@ correct version via: `pkgutil --pkg-info=com.apple.pkg.CLTools_Executables`. by the new key store: - `os`: use OS default credentials storage (default). - `file`: use encrypted file-based store. + - `kwallet`: use [KDE Wallet](https://utils.kde.org/projects/kwalletmanager/) service. + - `pass`: use the [pass](https://www.passwordstore.org/) command line password manager. - `test`: use password-less key store. *For testing purposes only. Use it at your own risk.* * (keys) [\#5097](https://github.com/cosmos/cosmos-sdk/pull/5097) New `keys migrate` command to assist users migrate their keys to the new keyring. diff --git a/crypto/keys/keyring.go b/crypto/keys/keyring.go index 92071f0706db..fe32007d0e87 100644 --- a/crypto/keys/keyring.go +++ b/crypto/keys/keyring.go @@ -26,9 +26,11 @@ import ( ) const ( - BackendFile = "file" - BackendOS = "os" - BackendTest = "test" + BackendFile = "file" + BackendOS = "os" + BackendKWallet = "kwallet" + BackendPass = "pass" + BackendTest = "test" ) const ( @@ -71,6 +73,10 @@ func NewKeyring( db, err = keyring.Open(newFileBackendKeyringConfig(svcName, rootDir, userInput)) case BackendOS: db, err = keyring.Open(lkbToKeyringConfig(svcName, rootDir, userInput, false)) + case BackendKWallet: + db, err = keyring.Open(newKWalletBackendKeyringConfig(svcName, rootDir, userInput)) + case BackendPass: + db, err = keyring.Open(newPassBackendKeyringConfig(svcName, rootDir, userInput)) default: return nil, fmt.Errorf("unknown keyring backend %v", backend) } @@ -485,7 +491,7 @@ func (kb keyringKeybase) writeInfo(name string, info Info) { func lkbToKeyringConfig(name, dir string, buf io.Reader, test bool) keyring.Config { if test { return keyring.Config{ - AllowedBackends: []keyring.BackendType{"file"}, + AllowedBackends: []keyring.BackendType{keyring.FileBackend}, ServiceName: name, FileDir: filepath.Join(dir, fmt.Sprintf(testKeyringDirNameFmt, name)), FilePasswordFunc: func(_ string) (string, error) { @@ -501,10 +507,28 @@ func lkbToKeyringConfig(name, dir string, buf io.Reader, test bool) keyring.Conf } } +func newKWalletBackendKeyringConfig(name, _ string, _ io.Reader) keyring.Config { + return keyring.Config{ + AllowedBackends: []keyring.BackendType{keyring.KWalletBackend}, + ServiceName: "kdewallet", + KWalletAppID: name, + KWalletFolder: "", + } +} + +func newPassBackendKeyringConfig(name, dir string, _ io.Reader) keyring.Config { + prefix := filepath.Join(dir, fmt.Sprintf(keyringDirNameFmt, name)) + return keyring.Config{ + AllowedBackends: []keyring.BackendType{keyring.PassBackend}, + ServiceName: name, + PassPrefix: prefix, + } +} + func newFileBackendKeyringConfig(name, dir string, buf io.Reader) keyring.Config { fileDir := filepath.Join(dir, fmt.Sprintf(keyringDirNameFmt, name)) return keyring.Config{ - AllowedBackends: []keyring.BackendType{"file"}, + AllowedBackends: []keyring.BackendType{keyring.FileBackend}, ServiceName: name, FileDir: fileDir, FilePasswordFunc: newRealPrompt(fileDir, buf), From a4b36b9dcd4c320204ffd12e1cb7b53a44246d2e Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Thu, 23 Jan 2020 13:15:22 -0500 Subject: [PATCH 092/529] Merge PR #5561: v0.38 Migration Fixes --- x/auth/legacy/v0_38/migrate.go | 2 +- x/auth/legacy/v0_38/migrate_test.go | 8 +- x/auth/legacy/v0_38/types.go | 294 +++++++++++++++++++++++++-- x/auth/types/account_test.go | 7 + x/distribution/legacy/v0_38/types.go | 7 + x/genutil/legacy/v0_38/migrate.go | 19 +- 6 files changed, 316 insertions(+), 21 deletions(-) diff --git a/x/auth/legacy/v0_38/migrate.go b/x/auth/legacy/v0_38/migrate.go index 32a5b83467e2..e76937777678 100644 --- a/x/auth/legacy/v0_38/migrate.go +++ b/x/auth/legacy/v0_38/migrate.go @@ -13,7 +13,7 @@ func Migrate(authGenState v036auth.GenesisState, genAccountsGenState v036genacco for i, acc := range genAccountsGenState { var genAccount GenesisAccount - baseAccount := NewBaseAccount(acc.Address, acc.Coins.Sort(), acc.AccountNumber, acc.Sequence) + baseAccount := NewBaseAccount(acc.Address, acc.Coins.Sort(), nil, acc.AccountNumber, acc.Sequence) switch { case !acc.OriginalVesting.IsZero(): diff --git a/x/auth/legacy/v0_38/migrate_test.go b/x/auth/legacy/v0_38/migrate_test.go index 107545403d47..3afea8c87df0 100644 --- a/x/auth/legacy/v0_38/migrate_test.go +++ b/x/auth/legacy/v0_38/migrate_test.go @@ -70,21 +70,21 @@ func TestMigrate(t *testing.T) { ) }) - expectedAcc1 := NewBaseAccount(acc1.Address, acc1.Coins, acc1.AccountNumber, acc1.Sequence) + expectedAcc1 := NewBaseAccount(acc1.Address, acc1.Coins, nil, acc1.AccountNumber, acc1.Sequence) expectedAcc2 := NewModuleAccount( - NewBaseAccount(acc2.Address, acc2.Coins, acc2.AccountNumber, acc2.Sequence), + NewBaseAccount(acc2.Address, acc2.Coins, nil, acc2.AccountNumber, acc2.Sequence), acc2.ModuleName, acc2.ModulePermissions..., ) expectedAcc3 := NewContinuousVestingAccountRaw( NewBaseVestingAccount( - NewBaseAccount(acc3.Address, acc3.Coins, acc3.AccountNumber, acc3.Sequence), + NewBaseAccount(acc3.Address, acc3.Coins, nil, acc3.AccountNumber, acc3.Sequence), acc3.OriginalVesting, acc3.DelegatedFree, acc3.DelegatedVesting, acc3.EndTime, ), acc3.StartTime, ) expectedAcc4 := NewDelayedVestingAccountRaw( NewBaseVestingAccount( - NewBaseAccount(acc4.Address, acc4.Coins, acc4.AccountNumber, acc4.Sequence), + NewBaseAccount(acc4.Address, acc4.Coins, nil, acc4.AccountNumber, acc4.Sequence), acc4.OriginalVesting, acc4.DelegatedFree, acc4.DelegatedVesting, acc4.EndTime, ), ) diff --git a/x/auth/legacy/v0_38/types.go b/x/auth/legacy/v0_38/types.go index 90d42133b725..15896a39121f 100644 --- a/x/auth/legacy/v0_38/types.go +++ b/x/auth/legacy/v0_38/types.go @@ -5,6 +5,7 @@ package v038 import ( "bytes" + "encoding/json" "errors" "fmt" "sort" @@ -51,6 +52,14 @@ type ( Sequence uint64 `json:"sequence" yaml:"sequence"` } + baseAccountPretty struct { + Address sdk.AccAddress `json:"address" yaml:"address"` + Coins sdk.Coins `json:"coins" yaml:"coins"` + PubKey string `json:"public_key" yaml:"public_key"` + AccountNumber uint64 `json:"account_number" yaml:"account_number"` + Sequence uint64 `json:"sequence" yaml:"sequence"` + } + BaseVestingAccount struct { *BaseAccount @@ -61,6 +70,21 @@ type ( EndTime int64 `json:"end_time"` } + vestingAccountPretty struct { + Address sdk.AccAddress `json:"address" yaml:"address"` + Coins sdk.Coins `json:"coins" yaml:"coins"` + PubKey string `json:"public_key" yaml:"public_key"` + AccountNumber uint64 `json:"account_number" yaml:"account_number"` + Sequence uint64 `json:"sequence" yaml:"sequence"` + OriginalVesting sdk.Coins `json:"original_vesting" yaml:"original_vesting"` + DelegatedFree sdk.Coins `json:"delegated_free" yaml:"delegated_free"` + DelegatedVesting sdk.Coins `json:"delegated_vesting" yaml:"delegated_vesting"` + EndTime int64 `json:"end_time" yaml:"end_time"` + + // custom fields based on concrete vesting type which can be omitted + StartTime int64 `json:"start_time,omitempty" yaml:"start_time,omitempty"` + } + ContinuousVestingAccount struct { *BaseVestingAccount @@ -77,6 +101,16 @@ type ( Name string `json:"name" yaml:"name"` Permissions []string `json:"permissions" yaml:"permissions"` } + + moduleAccountPretty struct { + Address sdk.AccAddress `json:"address" yaml:"address"` + Coins sdk.Coins `json:"coins" yaml:"coins"` + PubKey string `json:"public_key" yaml:"public_key"` + AccountNumber uint64 `json:"account_number" yaml:"account_number"` + Sequence uint64 `json:"sequence" yaml:"sequence"` + Name string `json:"name" yaml:"name"` + Permissions []string `json:"permissions" yaml:"permissions"` + } ) func NewGenesisState(params v034auth.Params, accounts GenesisAccounts) GenesisState { @@ -93,13 +127,13 @@ func NewBaseAccountWithAddress(addr sdk.AccAddress) BaseAccount { } func NewBaseAccount( - address sdk.AccAddress, coins sdk.Coins, accountNumber, sequence uint64, + address sdk.AccAddress, coins sdk.Coins, pk crypto.PubKey, accountNumber, sequence uint64, ) *BaseAccount { return &BaseAccount{ Address: address, Coins: coins, - PubKey: nil, + PubKey: pk, AccountNumber: accountNumber, Sequence: sequence, } @@ -131,6 +165,50 @@ func (acc BaseAccount) Validate() error { return nil } +func (acc BaseAccount) MarshalJSON() ([]byte, error) { + alias := baseAccountPretty{ + Address: acc.Address, + Coins: acc.Coins, + AccountNumber: acc.AccountNumber, + Sequence: acc.Sequence, + } + + if acc.PubKey != nil { + pks, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, acc.PubKey) + if err != nil { + return nil, err + } + + alias.PubKey = pks + } + + return json.Marshal(alias) +} + +// UnmarshalJSON unmarshals raw JSON bytes into a BaseAccount. +func (acc *BaseAccount) UnmarshalJSON(bz []byte) error { + var alias baseAccountPretty + if err := json.Unmarshal(bz, &alias); err != nil { + return err + } + + if alias.PubKey != "" { + pk, err := sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeAccPub, alias.PubKey) + if err != nil { + return err + } + + acc.PubKey = pk + } + + acc.Address = alias.Address + acc.Coins = alias.Coins + acc.AccountNumber = alias.AccountNumber + acc.Sequence = alias.Sequence + + return nil +} + func NewBaseVestingAccount( baseAccount *BaseAccount, originalVesting, delegatedFree, delegatedVesting sdk.Coins, endTime int64, ) *BaseVestingAccount { @@ -153,6 +231,59 @@ func (bva BaseVestingAccount) Validate() error { return bva.BaseAccount.Validate() } +// MarshalJSON returns the JSON representation of a BaseVestingAccount. +func (bva BaseVestingAccount) MarshalJSON() ([]byte, error) { + alias := vestingAccountPretty{ + Address: bva.Address, + Coins: bva.Coins, + AccountNumber: bva.AccountNumber, + Sequence: bva.Sequence, + OriginalVesting: bva.OriginalVesting, + DelegatedFree: bva.DelegatedFree, + DelegatedVesting: bva.DelegatedVesting, + EndTime: bva.EndTime, + } + + if bva.PubKey != nil { + pks, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, bva.PubKey) + if err != nil { + return nil, err + } + + alias.PubKey = pks + } + + return json.Marshal(alias) +} + +// UnmarshalJSON unmarshals raw JSON bytes into a BaseVestingAccount. +func (bva *BaseVestingAccount) UnmarshalJSON(bz []byte) error { + var alias vestingAccountPretty + if err := json.Unmarshal(bz, &alias); err != nil { + return err + } + + var ( + pk crypto.PubKey + err error + ) + + if alias.PubKey != "" { + pk, err = sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeAccPub, alias.PubKey) + if err != nil { + return err + } + } + + bva.BaseAccount = NewBaseAccount(alias.Address, alias.Coins, pk, alias.AccountNumber, alias.Sequence) + bva.OriginalVesting = alias.OriginalVesting + bva.DelegatedFree = alias.DelegatedFree + bva.DelegatedVesting = alias.DelegatedVesting + bva.EndTime = alias.EndTime + + return nil +} + func NewContinuousVestingAccountRaw(bva *BaseVestingAccount, startTime int64) *ContinuousVestingAccount { return &ContinuousVestingAccount{ BaseVestingAccount: bva, @@ -168,6 +299,63 @@ func (cva ContinuousVestingAccount) Validate() error { return cva.BaseVestingAccount.Validate() } +// MarshalJSON returns the JSON representation of a ContinuousVestingAccount. +func (cva ContinuousVestingAccount) MarshalJSON() ([]byte, error) { + alias := vestingAccountPretty{ + Address: cva.Address, + Coins: cva.Coins, + AccountNumber: cva.AccountNumber, + Sequence: cva.Sequence, + OriginalVesting: cva.OriginalVesting, + DelegatedFree: cva.DelegatedFree, + DelegatedVesting: cva.DelegatedVesting, + EndTime: cva.EndTime, + StartTime: cva.StartTime, + } + + if cva.PubKey != nil { + pks, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, cva.PubKey) + if err != nil { + return nil, err + } + + alias.PubKey = pks + } + + return json.Marshal(alias) +} + +// UnmarshalJSON unmarshals raw JSON bytes into a ContinuousVestingAccount. +func (cva *ContinuousVestingAccount) UnmarshalJSON(bz []byte) error { + var alias vestingAccountPretty + if err := json.Unmarshal(bz, &alias); err != nil { + return err + } + + var ( + pk crypto.PubKey + err error + ) + + if alias.PubKey != "" { + pk, err = sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeAccPub, alias.PubKey) + if err != nil { + return err + } + } + + cva.BaseVestingAccount = &BaseVestingAccount{ + BaseAccount: NewBaseAccount(alias.Address, alias.Coins, pk, alias.AccountNumber, alias.Sequence), + OriginalVesting: alias.OriginalVesting, + DelegatedFree: alias.DelegatedFree, + DelegatedVesting: alias.DelegatedVesting, + EndTime: alias.EndTime, + } + cva.StartTime = alias.StartTime + + return nil +} + func NewDelayedVestingAccountRaw(bva *BaseVestingAccount) *DelayedVestingAccount { return &DelayedVestingAccount{ BaseVestingAccount: bva, @@ -178,6 +366,61 @@ func (dva DelayedVestingAccount) Validate() error { return dva.BaseVestingAccount.Validate() } +// MarshalJSON returns the JSON representation of a DelayedVestingAccount. +func (dva DelayedVestingAccount) MarshalJSON() ([]byte, error) { + alias := vestingAccountPretty{ + Address: dva.Address, + Coins: dva.Coins, + AccountNumber: dva.AccountNumber, + Sequence: dva.Sequence, + OriginalVesting: dva.OriginalVesting, + DelegatedFree: dva.DelegatedFree, + DelegatedVesting: dva.DelegatedVesting, + EndTime: dva.EndTime, + } + + if dva.PubKey != nil { + pks, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, dva.PubKey) + if err != nil { + return nil, err + } + + alias.PubKey = pks + } + + return json.Marshal(alias) +} + +// UnmarshalJSON unmarshals raw JSON bytes into a DelayedVestingAccount. +func (dva *DelayedVestingAccount) UnmarshalJSON(bz []byte) error { + var alias vestingAccountPretty + if err := json.Unmarshal(bz, &alias); err != nil { + return err + } + + var ( + pk crypto.PubKey + err error + ) + + if alias.PubKey != "" { + pk, err = sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeAccPub, alias.PubKey) + if err != nil { + return err + } + } + + dva.BaseVestingAccount = &BaseVestingAccount{ + BaseAccount: NewBaseAccount(alias.Address, alias.Coins, pk, alias.AccountNumber, alias.Sequence), + OriginalVesting: alias.OriginalVesting, + DelegatedFree: alias.DelegatedFree, + DelegatedVesting: alias.DelegatedVesting, + EndTime: alias.EndTime, + } + + return nil +} + func NewModuleAddress(name string) sdk.AccAddress { return sdk.AccAddress(crypto.AddressHash([]byte(name))) } @@ -190,16 +433,6 @@ func NewModuleAccount(baseAccount *BaseAccount, name string, permissions ...stri } } -func validatePermissions(permissions ...string) error { - for _, perm := range permissions { - if strings.TrimSpace(perm) == "" { - return fmt.Errorf("module permission is empty") - } - } - - return nil -} - func (ma ModuleAccount) Validate() error { if err := validatePermissions(ma.Permissions...); err != nil { return err @@ -216,6 +449,43 @@ func (ma ModuleAccount) Validate() error { return ma.BaseAccount.Validate() } +// MarshalJSON returns the JSON representation of a ModuleAccount. +func (ma ModuleAccount) MarshalJSON() ([]byte, error) { + return json.Marshal(moduleAccountPretty{ + Address: ma.Address, + Coins: ma.Coins, + PubKey: "", + AccountNumber: ma.AccountNumber, + Sequence: ma.Sequence, + Name: ma.Name, + Permissions: ma.Permissions, + }) +} + +// UnmarshalJSON unmarshals raw JSON bytes into a ModuleAccount. +func (ma *ModuleAccount) UnmarshalJSON(bz []byte) error { + var alias moduleAccountPretty + if err := json.Unmarshal(bz, &alias); err != nil { + return err + } + + ma.BaseAccount = NewBaseAccount(alias.Address, alias.Coins, nil, alias.AccountNumber, alias.Sequence) + ma.Name = alias.Name + ma.Permissions = alias.Permissions + + return nil +} + +func validatePermissions(permissions ...string) error { + for _, perm := range permissions { + if strings.TrimSpace(perm) == "" { + return fmt.Errorf("module permission is empty") + } + } + + return nil +} + func sanitizeGenesisAccounts(genAccounts GenesisAccounts) GenesisAccounts { sort.Slice(genAccounts, func(i, j int) bool { return genAccounts[i].GetAccountNumber() < genAccounts[j].GetAccountNumber() diff --git a/x/auth/types/account_test.go b/x/auth/types/account_test.go index 171c15d7210b..7be6a25e5623 100644 --- a/x/auth/types/account_test.go +++ b/x/auth/types/account_test.go @@ -146,4 +146,11 @@ func TestBaseAccountJSON(t *testing.T) { var a BaseAccount require.NoError(t, json.Unmarshal(bz, &a)) require.Equal(t, baseAcc.String(), a.String()) + + bz, err = ModuleCdc.MarshalJSON(baseAcc) + require.NoError(t, err) + + var b BaseAccount + require.NoError(t, ModuleCdc.UnmarshalJSON(bz, &b)) + require.Equal(t, baseAcc.String(), b.String()) } diff --git a/x/distribution/legacy/v0_38/types.go b/x/distribution/legacy/v0_38/types.go index 4457e2738da3..0b904372e63d 100644 --- a/x/distribution/legacy/v0_38/types.go +++ b/x/distribution/legacy/v0_38/types.go @@ -6,6 +6,13 @@ import ( v036distr "github.com/cosmos/cosmos-sdk/x/distribution/legacy/v0_36" ) +// DONTCOVER +// nolint + +const ( + ModuleName = "distribution" +) + type ( GenesisState struct { Params Params `json:"params" yaml:"params"` diff --git a/x/genutil/legacy/v0_38/migrate.go b/x/genutil/legacy/v0_38/migrate.go index ec7f495fa53c..59ba4772705f 100644 --- a/x/genutil/legacy/v0_38/migrate.go +++ b/x/genutil/legacy/v0_38/migrate.go @@ -4,13 +4,15 @@ import ( "github.com/cosmos/cosmos-sdk/codec" v036auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v0_36" v038auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v0_38" + v036distr "github.com/cosmos/cosmos-sdk/x/distribution/legacy/v0_36" + v038distr "github.com/cosmos/cosmos-sdk/x/distribution/legacy/v0_38" v036genaccounts "github.com/cosmos/cosmos-sdk/x/genaccounts/legacy/v0_36" "github.com/cosmos/cosmos-sdk/x/genutil" v036staking "github.com/cosmos/cosmos-sdk/x/staking/legacy/v0_36" v038staking "github.com/cosmos/cosmos-sdk/x/staking/legacy/v0_38" ) -// Migrate migrates exported state from v0.34 to a v0.36 genesis state. +// Migrate migrates exported state from v0.36/v0.37 to a v0.38 genesis state. func Migrate(appState genutil.AppMap) genutil.AppMap { v036Codec := codec.New() codec.RegisterCrypto(v036Codec) @@ -27,14 +29,14 @@ func Migrate(appState genutil.AppMap) genutil.AppMap { var genAccountsGenState v036genaccounts.GenesisState v036Codec.MustUnmarshalJSON(appState[v036genaccounts.ModuleName], &genAccountsGenState) + // delete deprecated genaccounts genesis state + delete(appState, v036genaccounts.ModuleName) + // Migrate relative source genesis application state and marshal it into // the respective key. appState[v038auth.ModuleName] = v038Codec.MustMarshalJSON( v038auth.Migrate(authGenState, genAccountsGenState), ) - - // delete deprecated genaccounts genesis state - delete(appState, v036genaccounts.ModuleName) } // migrate staking state @@ -46,5 +48,14 @@ func Migrate(appState genutil.AppMap) genutil.AppMap { appState[v038staking.ModuleName] = v038Codec.MustMarshalJSON(v038staking.Migrate(stakingGenState)) } + // migrate distribution state + if appState[v036distr.ModuleName] != nil { + var distrGenState v036distr.GenesisState + v036Codec.MustUnmarshalJSON(appState[v036distr.ModuleName], &distrGenState) + + delete(appState, v036distr.ModuleName) // delete old key in case the name changed + appState[v038distr.ModuleName] = v038Codec.MustMarshalJSON(v038distr.Migrate(distrGenState)) + } + return appState } From d0ff97338653957362358eac44d68004d41cddb9 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Thu, 23 Jan 2020 18:47:11 +0000 Subject: [PATCH 093/529] Merge PR #5562: Remove KeyringServiceName from the sdk.Config struct --- client/context/context.go | 2 +- client/keys/add.go | 2 +- client/keys/add_ledger_test.go | 4 ++-- client/keys/add_test.go | 2 +- client/keys/delete.go | 2 +- client/keys/delete_test.go | 4 ++-- client/keys/export.go | 2 +- client/keys/export_test.go | 2 +- client/keys/import.go | 2 +- client/keys/import_test.go | 2 +- client/keys/list.go | 2 +- client/keys/list_test.go | 2 +- client/keys/migrate.go | 4 ++-- client/keys/show.go | 2 +- client/keys/show_test.go | 2 +- crypto/keys/keyring.go | 30 +++++++++++++++--------------- types/config.go | 19 ++++++++----------- x/auth/client/cli/tx_multisign.go | 2 +- x/auth/types/txbuilder.go | 4 ++-- x/genutil/client/cli/gentx.go | 2 +- 20 files changed, 45 insertions(+), 48 deletions(-) diff --git a/client/context/context.go b/client/context/context.go index c6699c9065eb..28bfe8e830b0 100644 --- a/client/context/context.go +++ b/client/context/context.go @@ -274,7 +274,7 @@ func GetFromFields(input io.Reader, from string, genOnly bool) (sdk.AccAddress, return addr, "", nil } - keybase, err := keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), + keybase, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), input) if err != nil { return nil, "", err diff --git a/client/keys/add.go b/client/keys/add.go index 995dfa74e859..4f5fda67d731 100644 --- a/client/keys/add.go +++ b/client/keys/add.go @@ -86,7 +86,7 @@ func getKeybase(transient bool, buf io.Reader) (keys.Keybase, error) { return keys.NewInMemory(), nil } - return keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), buf) + return keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), buf) } func runAddCmd(cmd *cobra.Command, args []string) error { diff --git a/client/keys/add_ledger_test.go b/client/keys/add_ledger_test.go index 68c0390c8662..0b8efe8e66de 100644 --- a/client/keys/add_ledger_test.go +++ b/client/keys/add_ledger_test.go @@ -51,7 +51,7 @@ func Test_runAddCmdLedgerWithCustomCoinType(t *testing.T) { require.NoError(t, runAddCmd(cmd, []string{"keyname1"})) // Now check that it has been stored properly - kb, err := keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) + kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) require.NoError(t, err) require.NotNil(t, kb) defer func() { @@ -98,7 +98,7 @@ func Test_runAddCmdLedger(t *testing.T) { require.NoError(t, runAddCmd(cmd, []string{"keyname1"})) // Now check that it has been stored properly - kb, err := keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), kbHome, mockIn) + kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), kbHome, mockIn) require.NoError(t, err) require.NotNil(t, kb) defer func() { diff --git a/client/keys/add_test.go b/client/keys/add_test.go index 0745ba620ad4..b1ebee331684 100644 --- a/client/keys/add_test.go +++ b/client/keys/add_test.go @@ -31,7 +31,7 @@ func Test_runAddCmdBasic(t *testing.T) { mockIn.Reset("testpass1\ntestpass1\n") } else { mockIn.Reset("y\n") - kb, err := keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), kbHome, mockIn) + kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), kbHome, mockIn) require.NoError(t, err) defer func() { kb.Delete("keyname1", "", false) diff --git a/client/keys/delete.go b/client/keys/delete.go index 1bfc6b10db46..3559a228082a 100644 --- a/client/keys/delete.go +++ b/client/keys/delete.go @@ -43,7 +43,7 @@ private keys stored in a ledger device cannot be deleted with the CLI. func runDeleteCmd(cmd *cobra.Command, args []string) error { buf := bufio.NewReader(cmd.InOrStdin()) - kb, err := keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), buf) + kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), buf) if err != nil { return err } diff --git a/client/keys/delete_test.go b/client/keys/delete_test.go index c9ac44b4a14f..b2df8684dffe 100644 --- a/client/keys/delete_test.go +++ b/client/keys/delete_test.go @@ -27,7 +27,7 @@ func Test_runDeleteCmd(t *testing.T) { fakeKeyName1 := "runDeleteCmd_Key1" fakeKeyName2 := "runDeleteCmd_Key2" if !runningUnattended { - kb, err := keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) + kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) require.NoError(t, err) defer func() { kb.Delete("runDeleteCmd_Key1", "", false) @@ -41,7 +41,7 @@ func Test_runDeleteCmd(t *testing.T) { viper.Set(flags.FlagHome, kbHome) // Now - kb, err := keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), kbHome, mockIn) + kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), kbHome, mockIn) require.NoError(t, err) if runningUnattended { mockIn.Reset("testpass1\ntestpass1\n") diff --git a/client/keys/export.go b/client/keys/export.go index 1051335b98e9..fb12eb508d5e 100644 --- a/client/keys/export.go +++ b/client/keys/export.go @@ -25,7 +25,7 @@ func ExportKeyCommand() *cobra.Command { func runExportCmd(cmd *cobra.Command, args []string) error { buf := bufio.NewReader(cmd.InOrStdin()) - kb, err := keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), buf) + kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), buf) if err != nil { return err } diff --git a/client/keys/export_test.go b/client/keys/export_test.go index 32c57df656d6..4d0236cdd05a 100644 --- a/client/keys/export_test.go +++ b/client/keys/export_test.go @@ -23,7 +23,7 @@ func Test_runExportCmd(t *testing.T) { viper.Set(flags.FlagHome, kbHome) // create a key - kb, err := keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) + kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) require.NoError(t, err) if !runningUnattended { defer func() { diff --git a/client/keys/import.go b/client/keys/import.go index 289172168904..6e58dd872225 100644 --- a/client/keys/import.go +++ b/client/keys/import.go @@ -26,7 +26,7 @@ func ImportKeyCommand() *cobra.Command { func runImportCmd(cmd *cobra.Command, args []string) error { buf := bufio.NewReader(cmd.InOrStdin()) - kb, err := keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), buf) + kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), buf) if err != nil { return err } diff --git a/client/keys/import_test.go b/client/keys/import_test.go index 8ec384c0c7b8..faac935179bb 100644 --- a/client/keys/import_test.go +++ b/client/keys/import_test.go @@ -25,7 +25,7 @@ func Test_runImportCmd(t *testing.T) { viper.Set(flags.FlagHome, kbHome) if !runningUnattended { - kb, err := keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) + kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) require.NoError(t, err) defer func() { kb.Delete("keyname1", "", false) diff --git a/client/keys/list.go b/client/keys/list.go index 104414b4164b..dbac54502d98 100644 --- a/client/keys/list.go +++ b/client/keys/list.go @@ -26,7 +26,7 @@ along with their associated name and address.`, } func runListCmd(cmd *cobra.Command, _ []string) error { - kb, err := keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), cmd.InOrStdin()) + kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), cmd.InOrStdin()) if err != nil { return err } diff --git a/client/keys/list_test.go b/client/keys/list_test.go index ac3953924b1b..ac8ca97d0fb5 100644 --- a/client/keys/list_test.go +++ b/client/keys/list_test.go @@ -32,7 +32,7 @@ func Test_runListCmd(t *testing.T) { viper.Set(flags.FlagHome, kbHome2) mockIn, _, _ := tests.ApplyMockIO(cmdBasic) - kb, err := keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) + kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) require.NoError(t, err) if runningUnattended { mockIn.Reset("testpass1\ntestpass1\n") diff --git a/client/keys/migrate.go b/client/keys/migrate.go index fa15903afbc7..ef1d832ac113 100644 --- a/client/keys/migrate.go +++ b/client/keys/migrate.go @@ -9,7 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/input" "github.com/cosmos/cosmos-sdk/crypto/keys" - "github.com/cosmos/cosmos-sdk/types" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/pkg/errors" "github.com/spf13/cobra" @@ -55,7 +55,7 @@ func runMigrateCmd(cmd *cobra.Command, args []string) error { } buf := bufio.NewReader(cmd.InOrStdin()) - keyringServiceName := types.GetConfig().GetKeyringServiceName() + keyringServiceName := sdk.KeyringServiceName() var ( tmpDir string diff --git a/client/keys/show.go b/client/keys/show.go index 143d49bec885..539fb111e55f 100644 --- a/client/keys/show.go +++ b/client/keys/show.go @@ -57,7 +57,7 @@ consisting of all the keys provided by name and multisig threshold.`, func runShowCmd(cmd *cobra.Command, args []string) (err error) { var info keys.Info - kb, err := keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), cmd.InOrStdin()) + kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), cmd.InOrStdin()) if err != nil { return err } diff --git a/client/keys/show_test.go b/client/keys/show_test.go index b8e7a8d5c73d..ec84eea49ef6 100644 --- a/client/keys/show_test.go +++ b/client/keys/show_test.go @@ -49,7 +49,7 @@ func Test_runShowCmd(t *testing.T) { fakeKeyName1 := "runShowCmd_Key1" fakeKeyName2 := "runShowCmd_Key2" - kb, err := keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) + kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) require.NoError(t, err) defer func() { kb.Delete("runShowCmd_Key1", "", false) diff --git a/crypto/keys/keyring.go b/crypto/keys/keyring.go index fe32007d0e87..3e79c796bdbf 100644 --- a/crypto/keys/keyring.go +++ b/crypto/keys/keyring.go @@ -60,7 +60,7 @@ func newKeyringKeybase(db keyring.Keyring, opts ...KeybaseOption) Keybase { // options can be applied when generating this new Keybase. // Available backends are "os", "file", "test". func NewKeyring( - svcName, backend, rootDir string, userInput io.Reader, opts ...KeybaseOption, + appName, backend, rootDir string, userInput io.Reader, opts ...KeybaseOption, ) (Keybase, error) { var db keyring.Keyring @@ -68,15 +68,15 @@ func NewKeyring( switch backend { case BackendTest: - db, err = keyring.Open(lkbToKeyringConfig(svcName, rootDir, nil, true)) + db, err = keyring.Open(lkbToKeyringConfig(appName, rootDir, nil, true)) case BackendFile: - db, err = keyring.Open(newFileBackendKeyringConfig(svcName, rootDir, userInput)) + db, err = keyring.Open(newFileBackendKeyringConfig(appName, rootDir, userInput)) case BackendOS: - db, err = keyring.Open(lkbToKeyringConfig(svcName, rootDir, userInput, false)) + db, err = keyring.Open(lkbToKeyringConfig(appName, rootDir, userInput, false)) case BackendKWallet: - db, err = keyring.Open(newKWalletBackendKeyringConfig(svcName, rootDir, userInput)) + db, err = keyring.Open(newKWalletBackendKeyringConfig(appName, rootDir, userInput)) case BackendPass: - db, err = keyring.Open(newPassBackendKeyringConfig(svcName, rootDir, userInput)) + db, err = keyring.Open(newPassBackendKeyringConfig(appName, rootDir, userInput)) default: return nil, fmt.Errorf("unknown keyring backend %v", backend) } @@ -488,12 +488,12 @@ func (kb keyringKeybase) writeInfo(name string, info Info) { } } -func lkbToKeyringConfig(name, dir string, buf io.Reader, test bool) keyring.Config { +func lkbToKeyringConfig(appName, dir string, buf io.Reader, test bool) keyring.Config { if test { return keyring.Config{ AllowedBackends: []keyring.BackendType{keyring.FileBackend}, - ServiceName: name, - FileDir: filepath.Join(dir, fmt.Sprintf(testKeyringDirNameFmt, name)), + ServiceName: appName, + FileDir: filepath.Join(dir, fmt.Sprintf(testKeyringDirNameFmt, appName)), FilePasswordFunc: func(_ string) (string, error) { return "test", nil }, @@ -501,26 +501,26 @@ func lkbToKeyringConfig(name, dir string, buf io.Reader, test bool) keyring.Conf } return keyring.Config{ - ServiceName: name, + ServiceName: appName, FileDir: dir, FilePasswordFunc: newRealPrompt(dir, buf), } } -func newKWalletBackendKeyringConfig(name, _ string, _ io.Reader) keyring.Config { +func newKWalletBackendKeyringConfig(appName, _ string, _ io.Reader) keyring.Config { return keyring.Config{ AllowedBackends: []keyring.BackendType{keyring.KWalletBackend}, ServiceName: "kdewallet", - KWalletAppID: name, + KWalletAppID: appName, KWalletFolder: "", } } -func newPassBackendKeyringConfig(name, dir string, _ io.Reader) keyring.Config { - prefix := filepath.Join(dir, fmt.Sprintf(keyringDirNameFmt, name)) +func newPassBackendKeyringConfig(appName, dir string, _ io.Reader) keyring.Config { + prefix := filepath.Join(dir, fmt.Sprintf(keyringDirNameFmt, appName)) return keyring.Config{ AllowedBackends: []keyring.BackendType{keyring.PassBackend}, - ServiceName: name, + ServiceName: appName, PassPrefix: prefix, } } diff --git a/types/config.go b/types/config.go index e24ccef4c0e0..3e39fe30c272 100644 --- a/types/config.go +++ b/types/config.go @@ -2,6 +2,8 @@ package types import ( "sync" + + "github.com/cosmos/cosmos-sdk/version" ) // DefaultKeyringServiceName defines a default service name for the keyring. @@ -11,7 +13,6 @@ const DefaultKeyringServiceName = "cosmos" // This could be used to initialize certain configuration parameters for the SDK. type Config struct { fullFundraiserPath string - keyringServiceName string bech32AddressPrefix map[string]string txEncoder TxEncoder addressVerifier func([]byte) error @@ -28,6 +29,7 @@ func GetConfig() *Config { if sdkConfig != nil { return sdkConfig } + sdkConfig = &Config{ sealed: false, bech32AddressPrefix: map[string]string{ @@ -41,7 +43,6 @@ func GetConfig() *Config { coinType: CoinType, fullFundraiserPath: FullFundraiserPath, txEncoder: nil, - keyringServiceName: DefaultKeyringServiceName, } return sdkConfig } @@ -104,12 +105,6 @@ func (config *Config) SetFullFundraiserPath(fullFundraiserPath string) { config.fullFundraiserPath = fullFundraiserPath } -// Set the keyringServiceName (BIP44Prefix) on the config -func (config *Config) SetKeyringServiceName(keyringServiceName string) { - config.assertNotSealed() - config.keyringServiceName = keyringServiceName -} - // Seal seals the config such that the config state could not be modified further func (config *Config) Seal() *Config { config.mtx.Lock() @@ -169,7 +164,9 @@ func (config *Config) GetFullFundraiserPath() string { return config.fullFundraiserPath } -// GetKeyringServiceName returns the keyring service name from the config. -func (config *Config) GetKeyringServiceName() string { - return config.keyringServiceName +func KeyringServiceName() string { + if len(version.Name) == 0 { + return DefaultKeyringServiceName + } + return version.Name } diff --git a/x/auth/client/cli/tx_multisign.go b/x/auth/client/cli/tx_multisign.go index e622febe74b2..9d67f26ef9ba 100644 --- a/x/auth/client/cli/tx_multisign.go +++ b/x/auth/client/cli/tx_multisign.go @@ -66,7 +66,7 @@ func makeMultiSignCmd(cdc *codec.Codec) func(cmd *cobra.Command, args []string) } inBuf := bufio.NewReader(cmd.InOrStdin()) - kb, err := keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), + kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), inBuf) if err != nil { return diff --git a/x/auth/types/txbuilder.go b/x/auth/types/txbuilder.go index cc2387285368..533596ccb649 100644 --- a/x/auth/types/txbuilder.go +++ b/x/auth/types/txbuilder.go @@ -53,7 +53,7 @@ func NewTxBuilder( // NewTxBuilderFromCLI returns a new initialized TxBuilder with parameters from // the command line using Viper. func NewTxBuilderFromCLI(input io.Reader) TxBuilder { - kb, err := keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), input) + kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), input) if err != nil { panic(err) } @@ -276,7 +276,7 @@ func MakeSignature(keybase keys.Keybase, name, passphrase string, msg StdSignMsg) (sig StdSignature, err error) { if keybase == nil { - keybase, err = keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), os.Stdin) + keybase, err = keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), os.Stdin) if err != nil { return } diff --git a/x/genutil/client/cli/gentx.go b/x/genutil/client/cli/gentx.go index fc5de44973b3..4624d1540a4e 100644 --- a/x/genutil/client/cli/gentx.go +++ b/x/genutil/client/cli/gentx.go @@ -93,7 +93,7 @@ func GenTxCmd(ctx *server.Context, cdc *codec.Codec, mbm module.BasicManager, sm } inBuf := bufio.NewReader(cmd.InOrStdin()) - kb, err := keys.NewKeyring(sdk.GetConfig().GetKeyringServiceName(), + kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flagClientHome), inBuf) if err != nil { return errors.Wrap(err, "failed to initialize keybase") From f0912047cd69f8c751585ed5328bf045650ce31b Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Thu, 23 Jan 2020 15:25:39 -0500 Subject: [PATCH 094/529] Merge PR #5563: Add v0.38.0 changelog --- CHANGELOG.md | 60 +++++++++++++++++++++++----------------------------- 1 file changed, 26 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 23a00c197ee2..798b321d5159 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,8 @@ Ref: https://keepachangelog.com/en/1.0.0/ ## [Unreleased] +## [v0.38.0] - 2020-01-23 + ### State Machine Breaking * (genesis) [\#5506](https://github.com/cosmos/cosmos-sdk/pull/5506) The `x/distribution` genesis state @@ -52,23 +54,19 @@ logic has been implemented for v0.38 target version. Applications can migrate vi ### API Breaking Changes -* (modules) [\#5506](https://github.com/cosmos/cosmos-sdk/pull/5506) Remove individual setters of `x/distribution` parameters. - Instead, follow the module spec in getting parameters, setting new value(s) and finally calling `SetParams`. -* (types) [\#5495](https://github.com/cosmos/cosmos-sdk/pull/5495) Remove redundant `(Must)Bech32ify*` and `(Must)Get*KeyBech32` - functions in favor of `(Must)Bech32ifyPubKey` and `(Must)GetPubKeyFromBech32` respectively, both of - which take a `Bech32PubKeyType` (string). -* (types) [\#5430](https://github.com/cosmos/cosmos-sdk/pull/5430) `DecCoins#Add` parameter changed from `DecCoins` - to `...DecCoin`, `Coins#Add` parameter changed from `Coins` to `...Coin` +* (modules) [\#5506](https://github.com/cosmos/cosmos-sdk/pull/5506) Remove individual setters of `x/distribution` parameters. Instead, follow the module spec in getting parameters, setting new value(s) and finally calling `SetParams`. +* (types) [\#5495](https://github.com/cosmos/cosmos-sdk/pull/5495) Remove redundant `(Must)Bech32ify*` and `(Must)Get*KeyBech32` functions in favor of `(Must)Bech32ifyPubKey` and `(Must)GetPubKeyFromBech32` respectively, both of which take a `Bech32PubKeyType` (string). +* (types) [\#5430](https://github.com/cosmos/cosmos-sdk/pull/5430) `DecCoins#Add` parameter changed from `DecCoins` +to `...DecCoin`, `Coins#Add` parameter changed from `Coins` to `...Coin`. * (baseapp/types) [\#5421](https://github.com/cosmos/cosmos-sdk/pull/5421) The `Error` interface (`types/errors.go`) - has been removed in favor of the concrete type defined in `types/errors/` which implements the standard `error` - interface. As a result, the `Handler` and `Querier` implementations now return a standard `error`. +has been removed in favor of the concrete type defined in `types/errors/` which implements the standard `error` interface. + * As a result, the `Handler` and `Querier` implementations now return a standard `error`. Within `BaseApp`, `runTx` now returns a `(GasInfo, *Result, error)` tuple and `runMsgs` returns a `(*Result, error)` tuple. A reference to a `Result` is now used to indicate success whereas an error signals an invalid message or failed message execution. As a result, the fields `Code`, `Codespace`, `GasWanted`, and `GasUsed` have been removed the `Result` type. The latter two fields are now found in the `GasInfo` type which is always returned regardless of execution outcome. - - Note to developers: Since all handlers and queriers must now return a standard `error`, the `types/errors/` + * Note to developers: Since all handlers and queriers must now return a standard `error`, the `types/errors/` package contains all the relevant and pre-registered errors that you typically work with. A typical error returned will look like `sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "...")`. You can retrieve relevant ABCI information from the error via `ABCIInfo`. @@ -80,11 +78,8 @@ have this method perform a no-op. * (modules) [\#4665](https://github.com/cosmos/cosmos-sdk/issues/4665) Refactored `x/gov` module structure and dev-UX: * Prepare for module spec integration * Update gov keys to use big endian encoding instead of little endian -* (modules) [\#5017](https://github.com/cosmos/cosmos-sdk/pull/5017) The `x/genaccounts` module has been -deprecated and all components removed except the `legacy/` package. -* [\#4486](https://github.com/cosmos/cosmos-sdk/issues/4486) Vesting account types decoupled from the `x/auth` module and -now live under `x/auth/vesting`. Applications wishing to use vesting account types must be sure to register types via -`RegisterCodec` under the new vesting package. +* (modules) [\#5017](https://github.com/cosmos/cosmos-sdk/pull/5017) The `x/genaccounts` module has been deprecated and all components removed except the `legacy/` package. +* [\#4486](https://github.com/cosmos/cosmos-sdk/issues/4486) Vesting account types decoupled from the `x/auth` module and now live under `x/auth/vesting`. Applications wishing to use vesting account types must be sure to register types via `RegisterCodec` under the new vesting package. * [\#4486](https://github.com/cosmos/cosmos-sdk/issues/4486) The `NewBaseVestingAccount` constructor returns an error if the provided arguments are invalid. * (x/auth) [\#5006](https://github.com/cosmos/cosmos-sdk/pull/5006) Modular `AnteHandler` via composable decorators: @@ -98,14 +93,13 @@ if the provided arguments are invalid. * `StdTx#GetSignatures` will return an array of just signature byte slices `[][]byte` instead of returning an array of `StdSignature` structs. To replicate the old behavior, use the public field `StdTx.Signatures` to get back the array of StdSignatures `[]StdSignature`. -* (modules) [\#5299](https://github.com/cosmos/cosmos-sdk/pull/5299) `HandleDoubleSign` along with params `MaxEvidenceAge` - and `DoubleSignJailEndTime` have moved from the `x/slashing` module to the `x/evidence` module. -* (keys) [\#4941](https://github.com/cosmos/cosmos-sdk/issues/4941) Keybase concrete types constructors such as `NewKeyBaseFromDir` and `NewInMemory` - now accept optional parameters of type `KeybaseOption`. These optional parameters are also added on the keys subcommands - functions, which are now public, and allows these options to be set on the commands or ignored to default to previous behavior. +* (modules) [\#5299](https://github.com/cosmos/cosmos-sdk/pull/5299) `HandleDoubleSign` along with params `MaxEvidenceAge` and `DoubleSignJailEndTime` have moved from the `x/slashing` module to the `x/evidence` module. +* (keys) [\#4941](https://github.com/cosmos/cosmos-sdk/issues/4941) Keybase concrete types constructors such as `NewKeyBaseFromDir` and `NewInMemory` now accept optional parameters of type `KeybaseOption`. These +optional parameters are also added on the keys sub-commands functions, which are now public, and allows +these options to be set on the commands or ignored to default to previous behavior. * [\#5547](https://github.com/cosmos/cosmos-sdk/pull/5547) `NewKeyBaseFromHomeFlag` constructor has been removed. * [\#5439](https://github.com/cosmos/cosmos-sdk/pull/5439) Further modularization was done to the `keybase` - package to make it more suitable for use with different key formats and algorithms: +package to make it more suitable for use with different key formats and algorithms: * The `WithKeygenFunc` function added as a `KeybaseOption` which allows a custom bytes to key implementation to be defined when keys are created. * The `WithDeriveFunc` function added as a `KeybaseOption` allows custom logic for deriving a key @@ -114,9 +108,8 @@ if the provided arguments are invalid. the `client/keys` add command. * `SupportedAlgos` and `SupportedAlgosLedger` functions return a slice of `SigningAlgo`s that are supported by the keybase and the ledger integration respectively. -* (simapp) [\#5419](https://github.com/cosmos/cosmos-sdk/pull/5419) simapp/helpers.GenTx() now accepts a gas argument. -* (baseapp) [\#5455](https://github.com/cosmos/cosmos-sdk/issues/5455) An `sdk.Context` is passed into the `router.Route()` -function. +* (simapp) [\#5419](https://github.com/cosmos/cosmos-sdk/pull/5419) The `helpers.GenTx()` now accepts a gas argument. +* (baseapp) [\#5455](https://github.com/cosmos/cosmos-sdk/issues/5455) A `sdk.Context` is now passed into the `router.Route()` function. ### Client Breaking Changes @@ -150,11 +143,11 @@ upgrade via: `sudo rm -rf /Library/Developer/CommandLineTools; xcode-select --in correct version via: `pkgutil --pkg-info=com.apple.pkg.CLTools_Executables`. * [\#5355](https://github.com/cosmos/cosmos-sdk/pull/5355) Client commands accept a new `--keyring-backend` option through which users can specify which backend should be used by the new key store: - - `os`: use OS default credentials storage (default). - - `file`: use encrypted file-based store. - - `kwallet`: use [KDE Wallet](https://utils.kde.org/projects/kwalletmanager/) service. - - `pass`: use the [pass](https://www.passwordstore.org/) command line password manager. - - `test`: use password-less key store. *For testing purposes only. Use it at your own risk.* + * `os`: use OS default credentials storage (default). + * `file`: use encrypted file-based store. + * `kwallet`: use [KDE Wallet](https://utils.kde.org/projects/kwalletmanager/) service. + * `pass`: use the [pass](https://www.passwordstore.org/) command line password manager. + * `test`: use password-less key store. *For testing purposes only. Use it at your own risk.* * (keys) [\#5097](https://github.com/cosmos/cosmos-sdk/pull/5097) New `keys migrate` command to assist users migrate their keys to the new keyring. * (keys) [\#5366](https://github.com/cosmos/cosmos-sdk/pull/5366) `keys list` now accepts a `--list-names` option to list key names only, whilst the `keys delete` @@ -209,7 +202,6 @@ has been moved to the configuration file, to allow easier node configuration. * (cli) [\#5116](https://github.com/cosmos/cosmos-sdk/issues/5116) The `CLIContext` now supports multiple verifiers when connecting to multiple chains. The connecting chain's `CLIContext` will have to have the correct chain ID and node URI or client set. To use a `CLIContext` with a verifier for another chain: - ```go // main or parent chain (chain as if you're running without IBC) mainCtx := context.NewCLIContext() @@ -223,7 +215,6 @@ chain ID and node URI or client set. To use a `CLIContext` with a verifier for a context.CreateVerifier(sideCtx, context.DefaultVerifierCacheSize), ) ``` - * (modules) [\#5017](https://github.com/cosmos/cosmos-sdk/pull/5017) The `x/auth` package now supports generalized genesis accounts through the `GenesisAccount` interface. * (modules) [\#4762](https://github.com/cosmos/cosmos-sdk/issues/4762) Deprecate remove and add permissions in ModuleAccount. @@ -276,7 +267,7 @@ to detail this new feature and how state transitions occur. * (x/genutil) [\#5499](https://github.com/cosmos/cosmos-sdk/pull/) Ensure `DefaultGenesis` returns valid and non-nil default genesis state. * (client) [\#5303](https://github.com/cosmos/cosmos-sdk/issues/5303) Fix ignored error in tx generate only mode. * (cli) [\#4763](https://github.com/cosmos/cosmos-sdk/issues/4763) Fix flag `--min-self-delegation` for staking `EditValidator` -* (keys) Fix ledger custom coin type support bug +* (keys) Fix ledger custom coin type support bug. * (x/gov) [\#5107](https://github.com/cosmos/cosmos-sdk/pull/5107) Sum validator operator's all voting power when tally votes * (rest) [\#5212](https://github.com/cosmos/cosmos-sdk/issues/5212) Fix pagination in the `/gov/proposals` handler. @@ -2871,7 +2862,8 @@ BUG FIXES: -[Unreleased]: https://github.com/cosmos/cosmos-sdk/compare/v0.37.6...HEAD +[Unreleased]: https://github.com/cosmos/cosmos-sdk/compare/v0.38.0...HEAD +[v0.38.0]: https://github.com/cosmos/cosmos-sdk/releases/tag/v0.38.0 [v0.37.6]: https://github.com/cosmos/cosmos-sdk/releases/tag/v0.37.6 [v0.37.5]: https://github.com/cosmos/cosmos-sdk/releases/tag/v0.37.5 [v0.37.4]: https://github.com/cosmos/cosmos-sdk/releases/tag/v0.37.4 From 26d6e49d6ae7c6da073d6f6498b234fe853f2aa6 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Fri, 24 Jan 2020 10:32:00 -0500 Subject: [PATCH 095/529] Merge PR #5491: Protobuf Introduction + Types --- .circleci/config.yml | 15 + Makefile | 92 +-- buf.yaml | 19 + codec/amino.go | 70 +++ codec/amino_codec.go | 59 ++ codec/amino_codec_test.go | 118 ++++ codec/codec.go | 97 ++-- codec/hybrid_codec.go | 63 +++ codec/hybrid_codec_test.go | 107 ++++ codec/proto_codec.go | 130 +++++ codec/proto_codec_test.go | 107 ++++ codec/testdata/animal.go | 20 + codec/testdata/proto.pb.go | 579 +++++++++++++++++++ codec/testdata/proto.proto | 14 + contrib/devtools/Makefile | 82 ++- docs/core/encoding.md | 95 +++- go.mod | 5 +- go.sum | 49 +- scripts/protocgen.sh | 11 + third_party/proto/cosmos-proto/cosmos.proto | 10 + third_party/proto/gogoproto/gogo.proto | 145 +++++ types/codec.go | 4 +- types/coin.go | 14 - types/coin_test.go | 15 + types/dec_coin.go | 8 +- types/decimal.go | 194 ++++--- types/decimal_test.go | 107 ++-- types/int.go | 133 +++-- types/int_test.go | 144 +++-- types/proto.go | 20 + types/types.pb.go | 595 ++++++++++++++++++++ types/types.proto | 26 + types/uint.go | 73 ++- x/simulation/rand_util.go | 4 +- 34 files changed, 2826 insertions(+), 398 deletions(-) create mode 100644 buf.yaml create mode 100644 codec/amino.go create mode 100644 codec/amino_codec.go create mode 100644 codec/amino_codec_test.go create mode 100644 codec/hybrid_codec.go create mode 100644 codec/hybrid_codec_test.go create mode 100644 codec/proto_codec.go create mode 100644 codec/proto_codec_test.go create mode 100644 codec/testdata/animal.go create mode 100644 codec/testdata/proto.pb.go create mode 100644 codec/testdata/proto.proto create mode 100755 scripts/protocgen.sh create mode 100644 third_party/proto/cosmos-proto/cosmos.proto create mode 100644 third_party/proto/gogoproto/gogo.proto create mode 100644 types/proto.go create mode 100644 types/types.pb.go create mode 100644 types/types.proto diff --git a/.circleci/config.yml b/.circleci/config.yml index a6f67a43c02b..04ec877e3f9f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -9,6 +9,9 @@ executors: - image: tendermintdev/docker-website-deployment environment: AWS_REGION: us-east-1 + protoc: + docker: + - image: tendermintdev/docker-protoc commands: make: @@ -73,6 +76,15 @@ jobs: key: go-src-v1-{{ .Revision }} paths: - ".git" + proto: + executor: protoc + steps: + - make: + target: protoc-gen-gocosmos + description: "Generate go plugin for protoc" + - make: + target: proto-gen proto-lint proto-check-breaking + description: "Lint and verify Protocol Buffer definitions" test-sim-nondeterminism: executor: golang @@ -182,6 +194,9 @@ workflows: tags: only: - /^v.*/ + - proto: + requires: + - setup-dependencies - test-sim-nondeterminism: requires: - setup-dependencies diff --git a/Makefile b/Makefile index 8d947640f75a..03abf9fa66a8 100644 --- a/Makefile +++ b/Makefile @@ -11,28 +11,19 @@ MOCKS_DIR = $(CURDIR)/tests/mocks export GO111MODULE = on -all: tools build lint test - # The below include contains the tools and runsim targets. include contrib/devtools/Makefile -######################################## -### Build +all: tools build lint test + +############################################################################### +### Build ### +############################################################################### build: go.sum @go build -mod=readonly ./... .PHONY: build -update-swagger-docs: statik - $(BINDIR)/statik -src=client/lcd/swagger-ui -dest=client/lcd -f -m - @if [ -n "$(git status --porcelain)" ]; then \ - echo "\033[91mSwagger docs are out of sync!!!\033[0m";\ - exit 1;\ - else \ - echo "\033[92mSwagger docs are in sync\033[0m";\ - fi -.PHONY: update-swagger-docs - mocks: $(MOCKS_DIR) mockgen -source=x/auth/types/account_retriever.go -package mocks -destination tests/mocks/account_retriever.go .PHONY: mocks @@ -40,8 +31,17 @@ mocks: $(MOCKS_DIR) $(MOCKS_DIR): mkdir -p $(MOCKS_DIR) -######################################## -### Tools & dependencies +distclean: + rm -rf \ + gitian-build-darwin/ \ + gitian-build-linux/ \ + gitian-build-windows/ \ + .gitian-builder-cache/ +.PHONY: distclean + +############################################################################### +### Tools & Dependencies ### +############################################################################### go-mod-cache: go.sum @echo "--> Download go modules to local cache" @@ -53,16 +53,19 @@ go.sum: go.mod @go mod verify @go mod tidy -distclean: - rm -rf \ - gitian-build-darwin/ \ - gitian-build-linux/ \ - gitian-build-windows/ \ - .gitian-builder-cache/ -.PHONY: distclean +############################################################################### +### Documentation ### +############################################################################### -######################################## -### Documentation +update-swagger-docs: statik + $(BINDIR)/statik -src=client/lcd/swagger-ui -dest=client/lcd -f -m + @if [ -n "$(git status --porcelain)" ]; then \ + echo "\033[91mSwagger docs are out of sync!!!\033[0m";\ + exit 1;\ + else \ + echo "\033[92mSwagger docs are in sync\033[0m";\ + fi +.PHONY: update-swagger-docs godocs: @echo "--> Wait a few seconds and visit http://localhost:6060/pkg/github.com/cosmos/cosmos-sdk/types" @@ -85,8 +88,9 @@ sync-docs: aws cloudfront create-invalidation --distribution-id ${CF_DISTRIBUTION_ID} --profile terraform --path "/*" ; .PHONY: sync-docs -######################################## -### Testing +############################################################################### +### Tests & Simulation ### +############################################################################### test: test-unit test-all: test-unit test-ledger-mock test-race test-cover @@ -173,6 +177,14 @@ test-cover: @export VERSION=$(VERSION); bash -x tests/test_cover.sh .PHONY: test-cover +benchmark: + @go test -mod=readonly -bench=. $(PACKAGES_NOSIMULATION) +.PHONY: benchmark + +############################################################################### +### Linting ### +############################################################################### + lint: golangci-lint $(BINDIR)/golangci-lint run find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" | xargs gofmt -d -s @@ -185,12 +197,9 @@ format: tools find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" -not -path "./client/lcd/statik/statik.go" | xargs goimports -w -local github.com/cosmos/cosmos-sdk .PHONY: format -benchmark: - @go test -mod=readonly -bench=. $(PACKAGES_NOSIMULATION) -.PHONY: benchmark - -######################################## -### Devdoc +############################################################################### +### Devdoc ### +############################################################################### DEVDOC_SAVE = docker commit `docker ps -a -n 1 -q` devdoc:local @@ -213,3 +222,20 @@ devdoc-update: docker pull tendermint/devdoc .PHONY: devdoc devdoc-clean devdoc-init devdoc-save devdoc-update + +############################################################################### +### Protobuf ### +############################################################################### + +proto-all: proto-gen proto-lint proto-check-breaking + +proto-gen: + @./scripts/protocgen.sh + +proto-lint: + @buf check lint --error-format=json + +proto-check-breaking: + @buf check breaking --against-input '.git#branch=master' + +.PHONY: proto-all proto-gen proto-lint proto-check-breaking diff --git a/buf.yaml b/buf.yaml new file mode 100644 index 000000000000..8507c9cd41c0 --- /dev/null +++ b/buf.yaml @@ -0,0 +1,19 @@ +build: + roots: + - . +lint: + use: + - DEFAULT + - COMMENTS + - FILE_LOWER_SNAKE_CASE + except: + - UNARY_RPC + - COMMENT_FIELD + - PACKAGE_DIRECTORY_MATCH + ignore: + - third_party +breaking: + use: + - FILE + ignore: + - third_party diff --git a/codec/amino.go b/codec/amino.go new file mode 100644 index 000000000000..b2300aef6cc3 --- /dev/null +++ b/codec/amino.go @@ -0,0 +1,70 @@ +package codec + +import ( + "bytes" + "encoding/json" + "fmt" + + amino "github.com/tendermint/go-amino" + cryptoamino "github.com/tendermint/tendermint/crypto/encoding/amino" + tmtypes "github.com/tendermint/tendermint/types" +) + +// Cdc defines a global generic sealed Amino codec to be used throughout sdk. It +// has all Tendermint crypto and evidence types registered. +// +// TODO: Consider removing this global. +var Cdc *Codec + +func init() { + cdc := New() + RegisterCrypto(cdc) + RegisterEvidences(cdc) + Cdc = cdc.Seal() +} + +// Codec defines a type alias for an Amino codec. +type Codec = amino.Codec + +func New() *Codec { + return amino.NewCodec() +} + +// RegisterCrypto registers all crypto dependency types with the provided Amino +// codec. +func RegisterCrypto(cdc *Codec) { + cryptoamino.RegisterAmino(cdc) +} + +// RegisterEvidences registers Tendermint evidence types with the provided Amino +// codec. +func RegisterEvidences(cdc *Codec) { + tmtypes.RegisterEvidences(cdc) +} + +// MarshalJSONIndent provides a utility for indented JSON encoding of an object +// via an Amino codec. It returns an error if it cannot serialize or indent as +// JSON. +func MarshalJSONIndent(cdc *Codec, obj interface{}) ([]byte, error) { + bz, err := cdc.MarshalJSON(obj) + if err != nil { + return nil, err + } + + var out bytes.Buffer + if err = json.Indent(&out, bz, "", " "); err != nil { + return nil, err + } + + return out.Bytes(), nil +} + +// MustMarshalJSONIndent executes MarshalJSONIndent except it panics upon failure. +func MustMarshalJSONIndent(cdc *Codec, obj interface{}) []byte { + bz, err := MarshalJSONIndent(cdc, obj) + if err != nil { + panic(fmt.Sprintf("failed to marshal JSON: %s", err)) + } + + return bz +} diff --git a/codec/amino_codec.go b/codec/amino_codec.go new file mode 100644 index 000000000000..185c441366b3 --- /dev/null +++ b/codec/amino_codec.go @@ -0,0 +1,59 @@ +package codec + +// AminoCodec defines a codec that utilizes Amino for both binary and JSON +// encoding. +type AminoCodec struct { + amino *Codec +} + +func NewAminoCodec(amino *Codec) Marshaler { + return &AminoCodec{amino} +} + +func (ac *AminoCodec) MarshalBinaryBare(o ProtoMarshaler) ([]byte, error) { + return ac.amino.MarshalBinaryBare(o) +} + +func (ac *AminoCodec) MustMarshalBinaryBare(o ProtoMarshaler) []byte { + return ac.amino.MustMarshalBinaryBare(o) +} + +func (ac *AminoCodec) MarshalBinaryLengthPrefixed(o ProtoMarshaler) ([]byte, error) { + return ac.amino.MarshalBinaryLengthPrefixed(o) +} + +func (ac *AminoCodec) MustMarshalBinaryLengthPrefixed(o ProtoMarshaler) []byte { + return ac.amino.MustMarshalBinaryLengthPrefixed(o) +} + +func (ac *AminoCodec) UnmarshalBinaryBare(bz []byte, ptr ProtoMarshaler) error { + return ac.amino.UnmarshalBinaryBare(bz, ptr) +} + +func (ac *AminoCodec) MustUnmarshalBinaryBare(bz []byte, ptr ProtoMarshaler) { + ac.amino.MustUnmarshalBinaryBare(bz, ptr) +} + +func (ac *AminoCodec) UnmarshalBinaryLengthPrefixed(bz []byte, ptr ProtoMarshaler) error { + return ac.amino.UnmarshalBinaryLengthPrefixed(bz, ptr) +} + +func (ac *AminoCodec) MustUnmarshalBinaryLengthPrefixed(bz []byte, ptr ProtoMarshaler) { + ac.amino.MustUnmarshalBinaryLengthPrefixed(bz, ptr) +} + +func (ac *AminoCodec) MarshalJSON(o interface{}) ([]byte, error) { // nolint: stdmethods + return ac.amino.MarshalJSON(o) +} + +func (ac *AminoCodec) MustMarshalJSON(o interface{}) []byte { + return ac.amino.MustMarshalJSON(o) +} + +func (ac *AminoCodec) UnmarshalJSON(bz []byte, ptr interface{}) error { // nolint: stdmethods + return ac.amino.UnmarshalJSON(bz, ptr) +} + +func (ac *AminoCodec) MustUnmarshalJSON(bz []byte, ptr interface{}) { + ac.amino.MustUnmarshalJSON(bz, ptr) +} diff --git a/codec/amino_codec_test.go b/codec/amino_codec_test.go new file mode 100644 index 000000000000..31eeb413e828 --- /dev/null +++ b/codec/amino_codec_test.go @@ -0,0 +1,118 @@ +package codec_test + +import ( + "testing" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/testdata" + "github.com/stretchr/testify/require" + amino "github.com/tendermint/go-amino" +) + +func createTestCodec() *amino.Codec { + cdc := amino.NewCodec() + + cdc.RegisterInterface((*testdata.Animal)(nil), nil) + cdc.RegisterConcrete(testdata.Dog{}, "testdata/Dog", nil) + cdc.RegisterConcrete(testdata.Cat{}, "testdata/Cat", nil) + + return cdc +} + +func TestAminoCodec(t *testing.T) { + testCases := []struct { + name string + codec codec.Marshaler + input codec.ProtoMarshaler + recv codec.ProtoMarshaler + marshalErr bool + unmarshalErr bool + }{ + { + "valid encoding and decoding", + codec.NewAminoCodec(createTestCodec()), + &testdata.Dog{Name: "rufus"}, + &testdata.Dog{}, + false, + false, + }, + { + "invalid decode type", + codec.NewAminoCodec(createTestCodec()), + &testdata.Dog{Name: "rufus"}, + &testdata.Cat{}, + false, + true, + }, + } + + for _, tc := range testCases { + tc := tc + + t.Run(tc.name, func(t *testing.T) { + bz, err := tc.codec.MarshalBinaryBare(tc.input) + + if tc.marshalErr { + require.Error(t, err) + require.Panics(t, func() { tc.codec.MustMarshalBinaryBare(tc.input) }) + } else { + var bz2 []byte + require.NoError(t, err) + require.NotPanics(t, func() { bz2 = tc.codec.MustMarshalBinaryBare(tc.input) }) + require.Equal(t, bz, bz2) + + err := tc.codec.UnmarshalBinaryBare(bz, tc.recv) + if tc.unmarshalErr { + require.Error(t, err) + require.Panics(t, func() { tc.codec.MustUnmarshalBinaryBare(bz, tc.recv) }) + } else { + require.NoError(t, err) + require.NotPanics(t, func() { tc.codec.MustUnmarshalBinaryBare(bz, tc.recv) }) + require.Equal(t, tc.input, tc.recv) + } + } + + bz, err = tc.codec.MarshalBinaryLengthPrefixed(tc.input) + if tc.marshalErr { + require.Error(t, err) + require.Panics(t, func() { tc.codec.MustMarshalBinaryLengthPrefixed(tc.input) }) + } else { + var bz2 []byte + require.NoError(t, err) + require.NotPanics(t, func() { bz2 = tc.codec.MustMarshalBinaryLengthPrefixed(tc.input) }) + require.Equal(t, bz, bz2) + + err := tc.codec.UnmarshalBinaryLengthPrefixed(bz, tc.recv) + if tc.unmarshalErr { + require.Error(t, err) + require.Panics(t, func() { tc.codec.MustUnmarshalBinaryLengthPrefixed(bz, tc.recv) }) + } else { + require.NoError(t, err) + require.NotPanics(t, func() { tc.codec.MustUnmarshalBinaryLengthPrefixed(bz, tc.recv) }) + require.Equal(t, tc.input, tc.recv) + } + } + + bz, err = tc.codec.MarshalJSON(tc.input) + if tc.marshalErr { + require.Error(t, err) + require.Panics(t, func() { tc.codec.MustMarshalJSON(tc.input) }) + } else { + var bz2 []byte + require.NoError(t, err) + require.NotPanics(t, func() { bz2 = tc.codec.MustMarshalJSON(tc.input) }) + require.Equal(t, bz, bz2) + + err := tc.codec.UnmarshalJSON(bz, tc.recv) + if tc.unmarshalErr { + require.Error(t, err) + require.Panics(t, func() { tc.codec.MustUnmarshalJSON(bz, tc.recv) }) + } else { + require.NoError(t, err) + require.NotPanics(t, func() { tc.codec.MustUnmarshalJSON(bz, tc.recv) }) + require.Equal(t, tc.input, tc.recv) + } + } + }) + } +} diff --git a/codec/codec.go b/codec/codec.go index 6cf2f623d7e4..203a1ec1bbb6 100644 --- a/codec/codec.go +++ b/codec/codec.go @@ -1,65 +1,60 @@ package codec import ( - "bytes" - "encoding/json" - "fmt" + "encoding/binary" + "io" - amino "github.com/tendermint/go-amino" - cryptoamino "github.com/tendermint/tendermint/crypto/encoding/amino" - tmtypes "github.com/tendermint/tendermint/types" + "github.com/gogo/protobuf/proto" ) -// amino codec to marshal/unmarshal -type Codec = amino.Codec - -func New() *Codec { - return amino.NewCodec() -} - -// Register the go-crypto to the codec -func RegisterCrypto(cdc *Codec) { - cryptoamino.RegisterAmino(cdc) -} - -// RegisterEvidences registers Tendermint evidence types with the provided codec. -func RegisterEvidences(cdc *Codec) { - tmtypes.RegisterEvidences(cdc) -} - -// attempt to make some pretty json -func MarshalJSONIndent(cdc *Codec, obj interface{}) ([]byte, error) { - bz, err := cdc.MarshalJSON(obj) - if err != nil { - return nil, err +type ( + // Marshaler defines the interface module codecs must implement in order to support + // backwards compatibility with Amino while allowing custom Protobuf-based + // serialization. Note, Amino can still be used without any dependency on + // Protobuf. There are three typical implementations that fulfill this contract: + // + // 1. AminoCodec: Provides full Amino serialization compatibility. + // 2. ProtoCodec: Provides full Protobuf serialization compatibility. + // 3. HybridCodec: Provides Protobuf serialization for binary encoding and Amino + // for JSON encoding. + Marshaler interface { + MarshalBinaryBare(o ProtoMarshaler) ([]byte, error) + MustMarshalBinaryBare(o ProtoMarshaler) []byte + + MarshalBinaryLengthPrefixed(o ProtoMarshaler) ([]byte, error) + MustMarshalBinaryLengthPrefixed(o ProtoMarshaler) []byte + + UnmarshalBinaryBare(bz []byte, ptr ProtoMarshaler) error + MustUnmarshalBinaryBare(bz []byte, ptr ProtoMarshaler) + + UnmarshalBinaryLengthPrefixed(bz []byte, ptr ProtoMarshaler) error + MustUnmarshalBinaryLengthPrefixed(bz []byte, ptr ProtoMarshaler) + + MarshalJSON(o interface{}) ([]byte, error) // nolint: stdmethods + MustMarshalJSON(o interface{}) []byte + + UnmarshalJSON(bz []byte, ptr interface{}) error // nolint: stdmethods + MustUnmarshalJSON(bz []byte, ptr interface{}) } - var out bytes.Buffer - err = json.Indent(&out, bz, "", " ") - if err != nil { - return nil, err - } - return out.Bytes(), nil -} + // ProtoMarshaler defines an interface a type must implement as protocol buffer + // defined message. + ProtoMarshaler interface { + proto.Message // for JSON serialization -// MustMarshalJSONIndent executes MarshalJSONIndent except it panics upon failure. -func MustMarshalJSONIndent(cdc *Codec, obj interface{}) []byte { - bz, err := MarshalJSONIndent(cdc, obj) - if err != nil { - panic(fmt.Sprintf("failed to marshal JSON: %s", err)) + Marshal() ([]byte, error) + MarshalTo(data []byte) (n int, err error) + MarshalToSizedBuffer(dAtA []byte) (int, error) + Size() int + Unmarshal(data []byte) error } +) - return bz -} - -//__________________________________________________________________ +func encodeUvarint(w io.Writer, u uint64) (err error) { + var buf [10]byte -// generic sealed codec to be used throughout sdk -var Cdc *Codec + n := binary.PutUvarint(buf[:], u) + _, err = w.Write(buf[0:n]) -func init() { - cdc := New() - RegisterCrypto(cdc) - RegisterEvidences(cdc) - Cdc = cdc.Seal() + return err } diff --git a/codec/hybrid_codec.go b/codec/hybrid_codec.go new file mode 100644 index 000000000000..c004df1425ce --- /dev/null +++ b/codec/hybrid_codec.go @@ -0,0 +1,63 @@ +package codec + +// HybridCodec defines a codec that utilizes Protobuf for binary encoding +// and Amino for JSON encoding. +type HybridCodec struct { + proto Marshaler + amino Marshaler +} + +func NewHybridCodec(amino *Codec) Marshaler { + return &HybridCodec{ + proto: NewProtoCodec(), + amino: NewAminoCodec(amino), + } +} + +func (hc *HybridCodec) MarshalBinaryBare(o ProtoMarshaler) ([]byte, error) { + return hc.proto.MarshalBinaryBare(o) +} + +func (hc *HybridCodec) MustMarshalBinaryBare(o ProtoMarshaler) []byte { + return hc.proto.MustMarshalBinaryBare(o) +} + +func (hc *HybridCodec) MarshalBinaryLengthPrefixed(o ProtoMarshaler) ([]byte, error) { + return hc.proto.MarshalBinaryLengthPrefixed(o) +} + +func (hc *HybridCodec) MustMarshalBinaryLengthPrefixed(o ProtoMarshaler) []byte { + return hc.proto.MustMarshalBinaryLengthPrefixed(o) +} + +func (hc *HybridCodec) UnmarshalBinaryBare(bz []byte, ptr ProtoMarshaler) error { + return hc.proto.UnmarshalBinaryBare(bz, ptr) +} + +func (hc *HybridCodec) MustUnmarshalBinaryBare(bz []byte, ptr ProtoMarshaler) { + hc.proto.MustUnmarshalBinaryBare(bz, ptr) +} + +func (hc *HybridCodec) UnmarshalBinaryLengthPrefixed(bz []byte, ptr ProtoMarshaler) error { + return hc.proto.UnmarshalBinaryLengthPrefixed(bz, ptr) +} + +func (hc *HybridCodec) MustUnmarshalBinaryLengthPrefixed(bz []byte, ptr ProtoMarshaler) { + hc.proto.MustUnmarshalBinaryLengthPrefixed(bz, ptr) +} + +func (hc *HybridCodec) MarshalJSON(o interface{}) ([]byte, error) { // nolint: stdmethods + return hc.amino.MarshalJSON(o) +} + +func (hc *HybridCodec) MustMarshalJSON(o interface{}) []byte { + return hc.amino.MustMarshalJSON(o) +} + +func (hc *HybridCodec) UnmarshalJSON(bz []byte, ptr interface{}) error { // nolint: stdmethods + return hc.amino.UnmarshalJSON(bz, ptr) +} + +func (hc *HybridCodec) MustUnmarshalJSON(bz []byte, ptr interface{}) { + hc.amino.MustUnmarshalJSON(bz, ptr) +} diff --git a/codec/hybrid_codec_test.go b/codec/hybrid_codec_test.go new file mode 100644 index 000000000000..353f0c389643 --- /dev/null +++ b/codec/hybrid_codec_test.go @@ -0,0 +1,107 @@ +package codec_test + +import ( + "testing" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/testdata" + "github.com/stretchr/testify/require" +) + +func TestHybridCodec(t *testing.T) { + testCases := []struct { + name string + codec codec.Marshaler + input codec.ProtoMarshaler + recv codec.ProtoMarshaler + marshalErr bool + unmarshalErr bool + }{ + { + "valid encoding and decoding", + codec.NewHybridCodec(createTestCodec()), + &testdata.Dog{Name: "rufus"}, + &testdata.Dog{}, + false, + false, + }, + { + "invalid decode type", + codec.NewHybridCodec(createTestCodec()), + &testdata.Dog{Name: "rufus"}, + &testdata.Cat{}, + false, + true, + }, + } + + for _, tc := range testCases { + tc := tc + + t.Run(tc.name, func(t *testing.T) { + bz, err := tc.codec.MarshalBinaryBare(tc.input) + + if tc.marshalErr { + require.Error(t, err) + require.Panics(t, func() { tc.codec.MustMarshalBinaryBare(tc.input) }) + } else { + var bz2 []byte + require.NoError(t, err) + require.NotPanics(t, func() { bz2 = tc.codec.MustMarshalBinaryBare(tc.input) }) + require.Equal(t, bz, bz2) + + err := tc.codec.UnmarshalBinaryBare(bz, tc.recv) + if tc.unmarshalErr { + require.Error(t, err) + require.Panics(t, func() { tc.codec.MustUnmarshalBinaryBare(bz, tc.recv) }) + } else { + require.NoError(t, err) + require.NotPanics(t, func() { tc.codec.MustUnmarshalBinaryBare(bz, tc.recv) }) + require.Equal(t, tc.input, tc.recv) + } + } + + bz, err = tc.codec.MarshalBinaryLengthPrefixed(tc.input) + if tc.marshalErr { + require.Error(t, err) + require.Panics(t, func() { tc.codec.MustMarshalBinaryLengthPrefixed(tc.input) }) + } else { + var bz2 []byte + require.NoError(t, err) + require.NotPanics(t, func() { bz2 = tc.codec.MustMarshalBinaryLengthPrefixed(tc.input) }) + require.Equal(t, bz, bz2) + + err := tc.codec.UnmarshalBinaryLengthPrefixed(bz, tc.recv) + if tc.unmarshalErr { + require.Error(t, err) + require.Panics(t, func() { tc.codec.MustUnmarshalBinaryLengthPrefixed(bz, tc.recv) }) + } else { + require.NoError(t, err) + require.NotPanics(t, func() { tc.codec.MustUnmarshalBinaryLengthPrefixed(bz, tc.recv) }) + require.Equal(t, tc.input, tc.recv) + } + } + + bz, err = tc.codec.MarshalJSON(tc.input) + if tc.marshalErr { + require.Error(t, err) + require.Panics(t, func() { tc.codec.MustMarshalJSON(tc.input) }) + } else { + var bz2 []byte + require.NoError(t, err) + require.NotPanics(t, func() { bz2 = tc.codec.MustMarshalJSON(tc.input) }) + require.Equal(t, bz, bz2) + + err := tc.codec.UnmarshalJSON(bz, tc.recv) + if tc.unmarshalErr { + require.Error(t, err) + require.Panics(t, func() { tc.codec.MustUnmarshalJSON(bz, tc.recv) }) + } else { + require.NoError(t, err) + require.NotPanics(t, func() { tc.codec.MustUnmarshalJSON(bz, tc.recv) }) + require.Equal(t, tc.input, tc.recv) + } + } + }) + } +} diff --git a/codec/proto_codec.go b/codec/proto_codec.go new file mode 100644 index 000000000000..f8a4169d4d8b --- /dev/null +++ b/codec/proto_codec.go @@ -0,0 +1,130 @@ +package codec + +import ( + "bytes" + "encoding/binary" + "fmt" + "strings" + + "github.com/gogo/protobuf/jsonpb" +) + +// ProtoCodec defines a codec that utilizes Protobuf for both binary and JSON +// encoding. +type ProtoCodec struct{} + +func NewProtoCodec() Marshaler { + return &ProtoCodec{} +} + +func (pc *ProtoCodec) MarshalBinaryBare(o ProtoMarshaler) ([]byte, error) { + return o.Marshal() +} + +func (pc *ProtoCodec) MustMarshalBinaryBare(o ProtoMarshaler) []byte { + bz, err := pc.MarshalBinaryBare(o) + if err != nil { + panic(err) + } + + return bz +} + +func (pc *ProtoCodec) MarshalBinaryLengthPrefixed(o ProtoMarshaler) ([]byte, error) { + bz, err := pc.MarshalBinaryBare(o) + if err != nil { + return nil, err + } + + buf := new(bytes.Buffer) + if err := encodeUvarint(buf, uint64(o.Size())); err != nil { + return nil, err + } + + if _, err := buf.Write(bz); err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (pc *ProtoCodec) MustMarshalBinaryLengthPrefixed(o ProtoMarshaler) []byte { + bz, err := pc.MarshalBinaryLengthPrefixed(o) + if err != nil { + panic(err) + } + + return bz +} + +func (pc *ProtoCodec) UnmarshalBinaryBare(bz []byte, ptr ProtoMarshaler) error { + return ptr.Unmarshal(bz) +} + +func (pc *ProtoCodec) MustUnmarshalBinaryBare(bz []byte, ptr ProtoMarshaler) { + if err := pc.UnmarshalBinaryBare(bz, ptr); err != nil { + panic(err) + } +} + +func (pc *ProtoCodec) UnmarshalBinaryLengthPrefixed(bz []byte, ptr ProtoMarshaler) error { + size, n := binary.Uvarint(bz) + if n < 0 { + return fmt.Errorf("invalid number of bytes read from length-prefixed encoding: %d", n) + } + + if size > uint64(len(bz)-n) { + return fmt.Errorf("not enough bytes to read; want: %v, got: %v", size, len(bz)-n) + } else if size < uint64(len(bz)-n) { + return fmt.Errorf("too many bytes to read; want: %v, got: %v", size, len(bz)-n) + } + + bz = bz[n:] + return ptr.Unmarshal(bz) +} + +func (pc *ProtoCodec) MustUnmarshalBinaryLengthPrefixed(bz []byte, ptr ProtoMarshaler) { + if err := pc.UnmarshalBinaryLengthPrefixed(bz, ptr); err != nil { + panic(err) + } +} + +func (pc *ProtoCodec) MarshalJSON(o interface{}) ([]byte, error) { // nolint: stdmethods + m, ok := o.(ProtoMarshaler) + if !ok { + return nil, fmt.Errorf("cannot protobuf JSON encode unsupported type: %T", o) + } + + buf := new(bytes.Buffer) + + marshaler := &jsonpb.Marshaler{} + if err := marshaler.Marshal(buf, m); err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (pc *ProtoCodec) MustMarshalJSON(o interface{}) []byte { + bz, err := pc.MarshalJSON(o) + if err != nil { + panic(err) + } + + return bz +} + +func (pc *ProtoCodec) UnmarshalJSON(bz []byte, ptr interface{}) error { // nolint: stdmethods + m, ok := ptr.(ProtoMarshaler) + if !ok { + return fmt.Errorf("cannot protobuf JSON decode unsupported type: %T", ptr) + } + + return jsonpb.Unmarshal(strings.NewReader(string(bz)), m) +} + +func (pc *ProtoCodec) MustUnmarshalJSON(bz []byte, ptr interface{}) { + if err := pc.UnmarshalJSON(bz, ptr); err != nil { + panic(err) + } +} diff --git a/codec/proto_codec_test.go b/codec/proto_codec_test.go new file mode 100644 index 000000000000..c49544e060f1 --- /dev/null +++ b/codec/proto_codec_test.go @@ -0,0 +1,107 @@ +package codec_test + +import ( + "testing" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/testdata" + "github.com/stretchr/testify/require" +) + +func TestProtoCodec(t *testing.T) { + testCases := []struct { + name string + codec codec.Marshaler + input codec.ProtoMarshaler + recv codec.ProtoMarshaler + marshalErr bool + unmarshalErr bool + }{ + { + "valid encoding and decoding", + codec.NewProtoCodec(), + &testdata.Dog{Name: "rufus"}, + &testdata.Dog{}, + false, + false, + }, + { + "invalid decode type", + codec.NewProtoCodec(), + &testdata.Dog{Name: "rufus"}, + &testdata.Cat{}, + false, + true, + }, + } + + for _, tc := range testCases { + tc := tc + + t.Run(tc.name, func(t *testing.T) { + bz, err := tc.codec.MarshalBinaryBare(tc.input) + + if tc.marshalErr { + require.Error(t, err) + require.Panics(t, func() { tc.codec.MustMarshalBinaryBare(tc.input) }) + } else { + var bz2 []byte + require.NoError(t, err) + require.NotPanics(t, func() { bz2 = tc.codec.MustMarshalBinaryBare(tc.input) }) + require.Equal(t, bz, bz2) + + err := tc.codec.UnmarshalBinaryBare(bz, tc.recv) + if tc.unmarshalErr { + require.Error(t, err) + require.Panics(t, func() { tc.codec.MustUnmarshalBinaryBare(bz, tc.recv) }) + } else { + require.NoError(t, err) + require.NotPanics(t, func() { tc.codec.MustUnmarshalBinaryBare(bz, tc.recv) }) + require.Equal(t, tc.input, tc.recv) + } + } + + bz, err = tc.codec.MarshalBinaryLengthPrefixed(tc.input) + if tc.marshalErr { + require.Error(t, err) + require.Panics(t, func() { tc.codec.MustMarshalBinaryLengthPrefixed(tc.input) }) + } else { + var bz2 []byte + require.NoError(t, err) + require.NotPanics(t, func() { bz2 = tc.codec.MustMarshalBinaryLengthPrefixed(tc.input) }) + require.Equal(t, bz, bz2) + + err := tc.codec.UnmarshalBinaryLengthPrefixed(bz, tc.recv) + if tc.unmarshalErr { + require.Error(t, err) + require.Panics(t, func() { tc.codec.MustUnmarshalBinaryLengthPrefixed(bz, tc.recv) }) + } else { + require.NoError(t, err) + require.NotPanics(t, func() { tc.codec.MustUnmarshalBinaryLengthPrefixed(bz, tc.recv) }) + require.Equal(t, tc.input, tc.recv) + } + } + + bz, err = tc.codec.MarshalJSON(tc.input) + if tc.marshalErr { + require.Error(t, err) + require.Panics(t, func() { tc.codec.MustMarshalJSON(tc.input) }) + } else { + var bz2 []byte + require.NoError(t, err) + require.NotPanics(t, func() { bz2 = tc.codec.MustMarshalJSON(tc.input) }) + require.Equal(t, bz, bz2) + + err := tc.codec.UnmarshalJSON(bz, tc.recv) + if tc.unmarshalErr { + require.Error(t, err) + require.Panics(t, func() { tc.codec.MustUnmarshalJSON(bz, tc.recv) }) + } else { + require.NoError(t, err) + require.NotPanics(t, func() { tc.codec.MustUnmarshalJSON(bz, tc.recv) }) + require.Equal(t, tc.input, tc.recv) + } + } + }) + } +} diff --git a/codec/testdata/animal.go b/codec/testdata/animal.go new file mode 100644 index 000000000000..05c8102487d8 --- /dev/null +++ b/codec/testdata/animal.go @@ -0,0 +1,20 @@ +package testdata + +// DONTCOVER +// nolint + +import ( + "fmt" +) + +type Animal interface { + Greet() string +} + +func (c Cat) Greet() string { + return fmt.Sprintf("Meow, my name is %s", c.Moniker) +} + +func (d Dog) Greet() string { + return fmt.Sprintf("Roof, my name is %s", d.Name) +} diff --git a/codec/testdata/proto.pb.go b/codec/testdata/proto.pb.go new file mode 100644 index 000000000000..d92daf3ec229 --- /dev/null +++ b/codec/testdata/proto.pb.go @@ -0,0 +1,579 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: codec/testdata/proto.proto + +package testdata + +import ( + fmt "fmt" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type Dog struct { + Size_ string `protobuf:"bytes,1,opt,name=size,proto3" json:"size,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` +} + +func (m *Dog) Reset() { *m = Dog{} } +func (m *Dog) String() string { return proto.CompactTextString(m) } +func (*Dog) ProtoMessage() {} +func (*Dog) Descriptor() ([]byte, []int) { + return fileDescriptor_ae1353846770e6e2, []int{0} +} +func (m *Dog) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Dog) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Dog.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 *Dog) XXX_Merge(src proto.Message) { + xxx_messageInfo_Dog.Merge(m, src) +} +func (m *Dog) XXX_Size() int { + return m.Size() +} +func (m *Dog) XXX_DiscardUnknown() { + xxx_messageInfo_Dog.DiscardUnknown(m) +} + +var xxx_messageInfo_Dog proto.InternalMessageInfo + +func (m *Dog) GetSize_() string { + if m != nil { + return m.Size_ + } + return "" +} + +func (m *Dog) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +type Cat struct { + Moniker string `protobuf:"bytes,1,opt,name=moniker,proto3" json:"moniker,omitempty"` + Lives int32 `protobuf:"varint,2,opt,name=lives,proto3" json:"lives,omitempty"` +} + +func (m *Cat) Reset() { *m = Cat{} } +func (m *Cat) String() string { return proto.CompactTextString(m) } +func (*Cat) ProtoMessage() {} +func (*Cat) Descriptor() ([]byte, []int) { + return fileDescriptor_ae1353846770e6e2, []int{1} +} +func (m *Cat) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Cat) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Cat.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 *Cat) XXX_Merge(src proto.Message) { + xxx_messageInfo_Cat.Merge(m, src) +} +func (m *Cat) XXX_Size() int { + return m.Size() +} +func (m *Cat) XXX_DiscardUnknown() { + xxx_messageInfo_Cat.DiscardUnknown(m) +} + +var xxx_messageInfo_Cat proto.InternalMessageInfo + +func (m *Cat) GetMoniker() string { + if m != nil { + return m.Moniker + } + return "" +} + +func (m *Cat) GetLives() int32 { + if m != nil { + return m.Lives + } + return 0 +} + +func init() { + proto.RegisterType((*Dog)(nil), "cosmos_sdk.codec.v1.Dog") + proto.RegisterType((*Cat)(nil), "cosmos_sdk.codec.v1.Cat") +} + +func init() { proto.RegisterFile("codec/testdata/proto.proto", fileDescriptor_ae1353846770e6e2) } + +var fileDescriptor_ae1353846770e6e2 = []byte{ + // 195 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4a, 0xce, 0x4f, 0x49, + 0x4d, 0xd6, 0x2f, 0x49, 0x2d, 0x2e, 0x49, 0x49, 0x2c, 0x49, 0xd4, 0x2f, 0x28, 0xca, 0x2f, 0xc9, + 0xd7, 0x03, 0x93, 0x42, 0xc2, 0xc9, 0xf9, 0xc5, 0xb9, 0xf9, 0xc5, 0xf1, 0xc5, 0x29, 0xd9, 0x7a, + 0x60, 0x65, 0x7a, 0x65, 0x86, 0x4a, 0xba, 0x5c, 0xcc, 0x2e, 0xf9, 0xe9, 0x42, 0x42, 0x5c, 0x2c, + 0xc5, 0x99, 0x55, 0xa9, 0x12, 0x8c, 0x0a, 0x8c, 0x1a, 0x9c, 0x41, 0x60, 0x36, 0x48, 0x2c, 0x2f, + 0x31, 0x37, 0x55, 0x82, 0x09, 0x22, 0x06, 0x62, 0x2b, 0x99, 0x72, 0x31, 0x3b, 0x27, 0x96, 0x08, + 0x49, 0x70, 0xb1, 0xe7, 0xe6, 0xe7, 0x65, 0x66, 0xa7, 0x16, 0x41, 0x75, 0xc0, 0xb8, 0x42, 0x22, + 0x5c, 0xac, 0x39, 0x99, 0x65, 0xa9, 0xc5, 0x60, 0x5d, 0xac, 0x41, 0x10, 0x8e, 0x93, 0xeb, 0x89, + 0x47, 0x72, 0x8c, 0x17, 0x1e, 0xc9, 0x31, 0x3e, 0x78, 0x24, 0xc7, 0x38, 0xe1, 0xb1, 0x1c, 0xc3, + 0x85, 0xc7, 0x72, 0x0c, 0x37, 0x1e, 0xcb, 0x31, 0x44, 0x69, 0xa7, 0x67, 0x96, 0x64, 0x94, 0x26, + 0xe9, 0x25, 0xe7, 0xe7, 0xea, 0x43, 0xdc, 0x07, 0xa5, 0x74, 0x8b, 0x53, 0xb2, 0xf5, 0x51, 0x7d, + 0x93, 0xc4, 0x06, 0xf6, 0x88, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0x64, 0x25, 0x07, 0xc7, 0xe6, + 0x00, 0x00, 0x00, +} + +func (m *Dog) 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 *Dog) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Dog) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintProto(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0x12 + } + if len(m.Size_) > 0 { + i -= len(m.Size_) + copy(dAtA[i:], m.Size_) + i = encodeVarintProto(dAtA, i, uint64(len(m.Size_))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *Cat) 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 *Cat) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Cat) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Lives != 0 { + i = encodeVarintProto(dAtA, i, uint64(m.Lives)) + i-- + dAtA[i] = 0x10 + } + if len(m.Moniker) > 0 { + i -= len(m.Moniker) + copy(dAtA[i:], m.Moniker) + i = encodeVarintProto(dAtA, i, uint64(len(m.Moniker))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintProto(dAtA []byte, offset int, v uint64) int { + offset -= sovProto(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Dog) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Size_) + if l > 0 { + n += 1 + l + sovProto(uint64(l)) + } + l = len(m.Name) + if l > 0 { + n += 1 + l + sovProto(uint64(l)) + } + return n +} + +func (m *Cat) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Moniker) + if l > 0 { + n += 1 + l + sovProto(uint64(l)) + } + if m.Lives != 0 { + n += 1 + sovProto(uint64(m.Lives)) + } + return n +} + +func sovProto(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozProto(x uint64) (n int) { + return sovProto(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Dog) 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 ErrIntOverflowProto + } + 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: Dog: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Dog: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Size_", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProto + } + 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 ErrInvalidLengthProto + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProto + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Size_ = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProto + } + 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 ErrInvalidLengthProto + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProto + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipProto(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthProto + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthProto + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Cat) 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 ErrIntOverflowProto + } + 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: Cat: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Cat: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Moniker", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProto + } + 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 ErrInvalidLengthProto + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProto + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Moniker = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Lives", wireType) + } + m.Lives = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProto + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Lives |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipProto(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthProto + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthProto + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipProto(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowProto + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowProto + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowProto + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthProto + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupProto + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthProto + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthProto = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowProto = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupProto = fmt.Errorf("proto: unexpected end of group") +) diff --git a/codec/testdata/proto.proto b/codec/testdata/proto.proto new file mode 100644 index 000000000000..ed8c0418dbce --- /dev/null +++ b/codec/testdata/proto.proto @@ -0,0 +1,14 @@ +syntax = "proto3"; +package cosmos_sdk.codec.v1; + +option go_package = "github.com/cosmos/cosmos-sdk/codec/testdata"; + +message Dog { + string size = 1; + string name = 2; +} + +message Cat { + string moniker = 1; + int32 lives = 2; +} diff --git a/contrib/devtools/Makefile b/contrib/devtools/Makefile index 735ab395178c..f0bf0ae77b27 100644 --- a/contrib/devtools/Makefile +++ b/contrib/devtools/Makefile @@ -1,3 +1,6 @@ +.PHONY: all tools tools-clean statik runsim golangci-lint \ +protoc buf protoc-gen-buf-check-breaking protoc-gen-buf-check-lint protoc-gen-gocosmos + ### # Find OS and Go environment # GO contains the Go binary @@ -15,13 +18,11 @@ ifeq ($(GO),) $(error could not find go. Is it in PATH? $(GO)) endif -GOPATH ?= $(shell $(GO) env GOPATH) -GITHUBDIR := $(GOPATH)$(FS)src$(FS)github.com -GOLANGCI_LINT_HASHSUM := 8d21cc95da8d3daf8321ac40091456fc26123c964d7c2281d339d431f2f4c840 +all: tools -### -# Functions -### +############################################################################### +### Functions ### +############################################################################### go_get = $(if $(findstring Windows_NT,$(OS)),\ IF NOT EXIST $(GITHUBDIR)$(FS)$(1)$(FS) ( mkdir $(GITHUBDIR)$(FS)$(1) ) else (cd .) &\ @@ -35,19 +36,27 @@ cd $(GITHUBDIR)$(FS)$(1)$(FS)$(2) && git fetch origin && git checkout -q $(3) mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST))) mkfile_dir := $(shell cd $(shell dirname $(mkfile_path)); pwd) -### -# tools -### -TOOLS_DESTDIR ?= $(GOPATH)/bin +############################################################################### +### Tools ### +############################################################################### -GOLANGCI_LINT = $(TOOLS_DESTDIR)/golangci-lint -STATIK = $(TOOLS_DESTDIR)/statik -RUNSIM = $(TOOLS_DESTDIR)/runsim +BIN ?= /usr/local/bin +UNAME_S ?= $(shell uname -s) +UNAME_M ?= $(shell uname -m) -all: tools +GOPATH ?= $(shell $(GO) env GOPATH) +GITHUBDIR := $(GOPATH)$(FS)src$(FS)github.com +GOLANGCI_LINT_HASHSUM := f11179f445385a4a6d5079d67de63fe48a9113cee8e9ee0ced19327a83a4394b -tools: statik runsim golangci-lint +BUF_VERSION ?= 0.4.0 + +TOOLS_DESTDIR ?= $(GOPATH)/bin +GOLANGCI_LINT = $(TOOLS_DESTDIR)/golangci-lint +STATIK = $(TOOLS_DESTDIR)/statik +RUNSIM = $(TOOLS_DESTDIR)/runsim + +tools: protoc buf statik runsim golangci-lint golangci-lint: $(GOLANGCI_LINT) $(GOLANGCI_LINT): $(mkfile_dir)/install-golangci-lint.sh @@ -74,8 +83,47 @@ $(RUNSIM): @echo "Installing runsim..." @(cd /tmp && go get github.com/cosmos/tools/cmd/runsim@v1.0.0) +PROTOC_VERSION ?= 3.11.2 +ifeq ($(UNAME_S),Linux) + PROTOC_ZIP ?= protoc-3.11.2-linux-x86_64.zip +endif +ifeq ($(UNAME_S),Darwin) + PROTOC_ZIP ?= protoc-3.11.2-osx-x86_64.zip +endif + +protoc: + @echo "Installing protoc compiler..." + @(cd /tmp; \ + curl -OL "https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/${PROTOC_ZIP}"; \ + unzip -o ${PROTOC_ZIP} -d /usr/local bin/protoc; \ + unzip -o ${PROTOC_ZIP} -d /usr/local 'include/*'; \ + rm -f ${PROTOC_ZIP}) + +protoc-gen-gocosmos: + @echo "Installing protoc-gen-gocosmos..." + @go install github.com/regen-network/cosmos-proto/protoc-gen-gocosmos + +buf: protoc-gen-buf-check-breaking protoc-gen-buf-check-lint + @echo "Installing buf..." + @curl -sSL \ + "https://github.com/bufbuild/buf/releases/download/v${BUF_VERSION}/buf-${UNAME_S}-${UNAME_M}" \ + -o "${BIN}/buf" && \ + chmod +x "${BIN}/buf" + +protoc-gen-buf-check-breaking: + @echo "Installing protoc-gen-buf-check-breaking..." + @curl -sSL \ + "https://github.com/bufbuild/buf/releases/download/v${BUF_VERSION}/protoc-gen-buf-check-breaking-${UNAME_S}-${UNAME_M}" \ + -o "${BIN}/protoc-gen-buf-check-breaking" && \ + chmod +x "${BIN}/protoc-gen-buf-check-breaking" + +protoc-gen-buf-check-lint: + @echo "Installing protoc-gen-buf-check-lint..." + @curl -sSL \ + "https://github.com/bufbuild/buf/releases/download/v${BUF_VERSION}/protoc-gen-buf-check-lint-${UNAME_S}-${UNAME_M}" \ + -o "${BIN}/protoc-gen-buf-check-lint" && \ + chmod +x "${BIN}/protoc-gen-buf-check-lint" + tools-clean: rm -f $(STATIK) $(GOLANGCI_LINT) $(RUNSIM) rm -f tools-stamp - -.PHONY: all tools tools-clean diff --git a/docs/core/encoding.md b/docs/core/encoding.md index 6629612a3a24..ac05f52c676a 100644 --- a/docs/core/encoding.md +++ b/docs/core/encoding.md @@ -1,37 +1,84 @@ # Encoding +> NOTE: This document a WIP. + ## Pre-requisite Readings {hide} - [Anatomy of an SDK application](../basics/app-anatomy.md) {prereq} ## Encoding -Every Cosmos SDK application exposes a global `codec` to marshal/unmarshal structs and interfaces in order to store and/or transfer them. As of now, the `codec` used in the Cosmos SDK is [go-amino](https://github.com/tendermint/go-amino), which possesses the following important properties: - -- Interface support. -- Deterministic encoding of value (which is required considering that blockchains are deterministic replicated state-machines). -- Upgradeable schemas. - -The application's `codec` is typically initialized in the [application's constructor function](../basics/app-anatomy.md#constructor-function), where it is also passed to each of the application's modules via the [basic manager](../building-modules/module-manager.md#basic-manager). - -Among other things, the `codec` is used by module's [`keeper`s](../building-modules/keeper.md) to marshal objects into `[]byte` before storing them in the module's [`KVStore`](./store.md#kvstore), or to unmarshal them from `[]byte` when retrieving them: +The Cosmos SDK utilizes two binary wire encoding protocols, [Amino](https://github.com/tendermint/go-amino/) +and [Protocol Buffers](https://developers.google.com/protocol-buffers), where Amino +is an object encoding specification. It is a subset of Proto3 with an extension for +interface support. See the [Proto3 spec](https://developers.google.com/protocol-buffers/docs/proto3) +for more information on Proto3, which Amino is largely compatible with (but not with Proto2). + +Due to Amino having significant performance drawbacks, being reflection-based, and +not having any meaningful cross-language/client support, Protocol Buffers, specifically +[gogoprotobuf](https://github.com/gogo/protobuf/), is being used in place of Amino. +Note, this process of using Protocol Buffers over Amino is still an ongoing process. + +Binary wire encoding of types in the Cosmos SDK can be broken down into two main +categories, client encoding and store encoding. Client encoding mainly revolves +around transaction processing and signing, whereas store encoding revolves around +types used in state-machine transitions and what is ultimately stored in the Merkle +tree. + +For store encoding, protobuf definitions can exist for any type and will typically +have an Amino-based "intermediary" type. Specifically, the protobuf-based type +definition is used for serialization and persistence, whereas the Amino-based type +is used for business logic in the state-machine where they may converted back-n-forth. +Note, the Amino-based types may slowly be phased-out in the future so developers +should take note to use the protobuf message definitions where possible. + +In the `codec` package, there exists two core interfaces, `Marshaler` and `ProtoMarshaler`, +where the former encapsulates the current Amino interface except it operates on +types implementing the latter instead of generic `interface{}` types. + +In addition, there exists three implementations of `Marshaler`. The first being +`AminoCodec`, where both binary and JSON serialization is handled via Amino. The +second being `ProtoCodec`, where both binary and JSON serialization is handled +via Protobuf. Finally, `HybridCodec`, a codec that utilizes Protobuf for binary +serialization and Amino for JSON serialization. The `HybridCodec` is typically +the codec that used in majority in situations as it's easier to use for client +and state serialization. + +This means that modules may use Amino or Protobuf encoding but the types must +implement `ProtoMarshaler`. If modules wish to avoid implementing this interface +for their types, they may use an Amino codec directly. + +### Amino + +Every module uses an Amino codec to serialize types and interfaces. This codec typically +has types and interfaces registered in that module's domain only (e.g. messages), +but there are exceptions like `x/gov`. Each module exposes a `RegisterCodec` function +that allows a user to provide a codec and have all the types registered. An application +will call this method for each necessary module. + +Where there is no protobuf-based type definition for a module (see below), Amino +is used to encode and decode raw wire bytes to the concrete type or interface: ```go -// typical pattern to marshal an object to []byte before storing it -bz := keeper.cdc.MustMarshalBinaryBare(object) - -//typical pattern to unmarshal an object from []byte when retrieving it -keeper.cdc.MustUnmarshalBinaryBare(bz, &object) +bz := keeper.cdc.MustMarshalBinaryBare(typeOrInterface) +keeper.cdc.MustUnmarshalBinaryBare(bz, &typeOrInterface) ``` -Alternatively, it is possible to use `MustMarshalBinaryLengthPrefixed`/`MustUnmarshalBinaryLengthPrefixed` instead of `MustMarshalBinaryBare`/`MustUnmarshalBinaryBare` for the same encoding prefixed by a `uvarint` encoding of the object to encode. +Note, there are length-prefixed variants of the above functionality and this is +typically used for when the data needs to be streamed or grouped together +(e.g. `ResponseDeliverTx.Data`) -Another important use of the `codec` is the encoding and decoding of [transactions](./transactions.md). Transactions are defined at the Cosmos SDK level, but passed to the underlying consensus engine in order to be relayed to other peers. Since the underlying consensus engine is agnostic to the application, it only accepts transactions in the form of `[]byte`. The encoding is done by an object called `TxEncoder` and the decoding by an object called `TxDecoder`. +Another important use of the Amino is the encoding and decoding of +[transactions](./transactions.md). Transactions are defined by the application or +the SDK, but passed to the underlying consensus engine in order to be relayed to +other peers. Since the underlying consensus engine is agnostic to the application, +it only accepts transactions in the form of raw bytes. The encoding is done by an +object called `TxEncoder` and the decoding by an object called `TxDecoder`. +++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/tx_msg.go#L45-L49 @@ -39,6 +86,18 @@ A standard implementation of both these objects can be found in the [`auth` modu +++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/x/auth/types/stdtx.go#L241-L266 +### Gogoproto + +Modules are encouraged to utilize Protobuf encoding for their respective types. +If modules do not contain any interfaces (e.g. `Account` or `Content`), then they +may simply accept a `Marshaler` as the codec which is implemented via the `HybridCodec` +without any further customization. + +However, if modules are to handle type interfaces, they should seek to extend the +`Marshaler` interface contract for these types (e.g. `MarshalAccount`). Note, they +should still use a `HybridCodec` internally. These extended contracts will typically +use concrete types with unique `oneof` messages. + ## Next {hide} -Learn about [events](./events.md) {hide} \ No newline at end of file +Learn about [events](./events.md) {hide} diff --git a/go.mod b/go.mod index 612c513549fc..6ebb9fdde282 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,7 @@ require ( github.com/pelletier/go-toml v1.6.0 github.com/pkg/errors v0.9.1 github.com/rakyll/statik v0.1.6 + github.com/regen-network/cosmos-proto v0.1.0 github.com/spf13/afero v1.2.1 // indirect github.com/spf13/cobra v0.0.5 github.com/spf13/jwalterweatherman v1.1.0 // indirect @@ -30,6 +31,8 @@ require ( gopkg.in/yaml.v2 v2.2.8 ) -go 1.13 +replace github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.2-alpha.regen.1 replace github.com/keybase/go-keychain => github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 + +go 1.13 diff --git a/go.sum b/go.sum index 4fd5999711d2..097236eff67f 100644 --- a/go.sum +++ b/go.sum @@ -17,7 +17,6 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/bartekn/go-bip39 v0.0.0-20171116152956-a05967ea095d h1:1aAija9gr0Hyv4KfQcRcwlmFIrhkDmIj2dz5bkg/s/8= github.com/bartekn/go-bip39 v0.0.0-20171116152956-a05967ea095d/go.mod h1:icNx/6QdFblhsEjZehARqbNumymUT/ydwlLojFdv7Sk= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= @@ -74,13 +73,10 @@ github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHqu github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-kit/kit v0.8.0 h1:Wz+5lgoB0kkuqLEc6NVmwRknTKP6dTGbSqvhZtBI/j0= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0 h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-logfmt/logfmt v0.3.0 h1:8HUsc87TaSWLKwrnumgC8/YconD2fJQsRJAsWaPg2ic= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= @@ -88,10 +84,6 @@ github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= -github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -127,8 +119,6 @@ github.com/gtank/merlin v0.1.1-0.20191105220539-8318aed1a79f h1:8N8XWLZelZNibkhM github.com/gtank/merlin v0.1.1-0.20191105220539-8318aed1a79f/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uMzcc= github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o= -github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk= -github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= @@ -145,12 +135,10 @@ github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlT github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -159,12 +147,9 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs= github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= -github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM= -github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= @@ -186,7 +171,6 @@ github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9 github.com/pelletier/go-toml v1.6.0 h1:aetoXYr0Tv7xRU/V4B4IZJ2QcbtMUFoNb3ORp7TzIK4= github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -196,7 +180,6 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP github.com/prometheus/client_golang v0.9.3 h1:9iH4JKXLzFbOAdtqv/a+j8aewx2Y8lAjAydhbaScPF8= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -211,6 +194,10 @@ github.com/rakyll/statik v0.1.6 h1:uICcfUXpgqtw2VopbIncslhAmE5hwc4g20TEyEENBNs= github.com/rakyll/statik v0.1.6/go.mod h1:OEi9wJV/fMUAGx1eNjq75DKDsJVuEv1U0oYdX6GX8Zs= github.com/rcrowley/go-metrics v0.0.0-20180503174638-e2704e165165 h1:nkcn14uNmFEuGCb2mBZbBb24RdNRL08b/wb+xBOYpuk= github.com/rcrowley/go-metrics v0.0.0-20180503174638-e2704e165165/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/regen-network/cosmos-proto v0.1.0 h1:gsV+YO2kMvY430zQn8ioPXRxEJgb/ms0iMPeWo3VEyY= +github.com/regen-network/cosmos-proto v0.1.0/go.mod h1:+r7jN10xXCypD4yBgzKOa+vgLz0riqYMHeDcKekxPvA= +github.com/regen-network/protobuf v1.3.2-alpha.regen.1 h1:YdeZbBS0lG1D13COb7b57+nM/RGgIs8WF9DwitU6EBM= +github.com/regen-network/protobuf v1.3.2-alpha.regen.1/go.mod h1:lye6mqhOn/GCw1zRl3uPD5VP8rC+LPMyTyPAyQV872U= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= @@ -234,13 +221,10 @@ github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tL github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= -github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.3.2 h1:VUFqw5KcqRf7i70GOzW7N+Q7+gxVBkSSqiXB12+JQ4M= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/spf13/viper v1.6.1 h1:VPZzIkznI1YhVMRi6vNFLHSwhnhReBfgTxIPccpfdZk= github.com/spf13/viper v1.6.1/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k= github.com/spf13/viper v1.6.2 h1:7aKfF+e8/k68gda3LOjo5RxiUqddoFxVq4BKBPrxk5E= github.com/spf13/viper v1.6.2/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k= @@ -288,14 +272,15 @@ golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413 h1:ULYEB3JvPRE/IfO+9uO7vKV/xzVTO7XPAwm8xbf4w2g= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -305,8 +290,10 @@ golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7 h1:rTIdg5QFRR7XCaK4LCjBiPbx8j4DQRpdYMnGn/bJUEU= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -323,14 +310,14 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -338,19 +325,21 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20200110213125-a7a6caa82ab2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f h1:2wh8dWY8959cBGQvk1RD+/eQBgRYYDaZ+hT0/zsARoA= +google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.26.0 h1:2dTRdpdFEEhJYQD8EMLB61nnrzSCTbG38PhqdhvOltg= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -363,12 +352,8 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkep gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo= -gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/scripts/protocgen.sh b/scripts/protocgen.sh new file mode 100755 index 000000000000..0818824a41b8 --- /dev/null +++ b/scripts/protocgen.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +set -eo pipefail + +proto_dirs=$(find . -path ./third_party -prune -o -name '*.proto' -print0 | xargs -0 -n1 dirname | sort | uniq) +for dir in $proto_dirs; do + protoc \ + -I. \ + --gocosmos_out=plugins=interfacetype,paths=source_relative:. \ + $(find "${dir}" -name '*.proto') +done diff --git a/third_party/proto/cosmos-proto/cosmos.proto b/third_party/proto/cosmos-proto/cosmos.proto new file mode 100644 index 000000000000..a59821d4f6b4 --- /dev/null +++ b/third_party/proto/cosmos-proto/cosmos.proto @@ -0,0 +1,10 @@ +syntax = "proto3"; +package cosmos_proto; + +import "google/protobuf/descriptor.proto"; + +option go_package = "github.com/regen-network/cosmos-proto"; + +extend google.protobuf.MessageOptions { + string interface_type = 93001; +} diff --git a/third_party/proto/gogoproto/gogo.proto b/third_party/proto/gogoproto/gogo.proto new file mode 100644 index 000000000000..588291f0ec20 --- /dev/null +++ b/third_party/proto/gogoproto/gogo.proto @@ -0,0 +1,145 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto2"; +package gogoproto; + +import "google/protobuf/descriptor.proto"; + +option java_package = "com.google.protobuf"; +option java_outer_classname = "GoGoProtos"; +option go_package = "github.com/gogo/protobuf/gogoproto"; + +extend google.protobuf.EnumOptions { + optional bool goproto_enum_prefix = 62001; + optional bool goproto_enum_stringer = 62021; + optional bool enum_stringer = 62022; + optional string enum_customname = 62023; + optional bool enumdecl = 62024; +} + +extend google.protobuf.EnumValueOptions { + optional string enumvalue_customname = 66001; +} + +extend google.protobuf.FileOptions { + optional bool goproto_getters_all = 63001; + optional bool goproto_enum_prefix_all = 63002; + optional bool goproto_stringer_all = 63003; + optional bool verbose_equal_all = 63004; + optional bool face_all = 63005; + optional bool gostring_all = 63006; + optional bool populate_all = 63007; + optional bool stringer_all = 63008; + optional bool onlyone_all = 63009; + + optional bool equal_all = 63013; + optional bool description_all = 63014; + optional bool testgen_all = 63015; + optional bool benchgen_all = 63016; + optional bool marshaler_all = 63017; + optional bool unmarshaler_all = 63018; + optional bool stable_marshaler_all = 63019; + + optional bool sizer_all = 63020; + + optional bool goproto_enum_stringer_all = 63021; + optional bool enum_stringer_all = 63022; + + optional bool unsafe_marshaler_all = 63023; + optional bool unsafe_unmarshaler_all = 63024; + + optional bool goproto_extensions_map_all = 63025; + optional bool goproto_unrecognized_all = 63026; + optional bool gogoproto_import = 63027; + optional bool protosizer_all = 63028; + optional bool compare_all = 63029; + optional bool typedecl_all = 63030; + optional bool enumdecl_all = 63031; + + optional bool goproto_registration = 63032; + optional bool messagename_all = 63033; + + optional bool goproto_sizecache_all = 63034; + optional bool goproto_unkeyed_all = 63035; +} + +extend google.protobuf.MessageOptions { + optional bool goproto_getters = 64001; + optional bool goproto_stringer = 64003; + optional bool verbose_equal = 64004; + optional bool face = 64005; + optional bool gostring = 64006; + optional bool populate = 64007; + optional bool stringer = 67008; + optional bool onlyone = 64009; + + optional bool equal = 64013; + optional bool description = 64014; + optional bool testgen = 64015; + optional bool benchgen = 64016; + optional bool marshaler = 64017; + optional bool unmarshaler = 64018; + optional bool stable_marshaler = 64019; + + optional bool sizer = 64020; + + optional bool unsafe_marshaler = 64023; + optional bool unsafe_unmarshaler = 64024; + + optional bool goproto_extensions_map = 64025; + optional bool goproto_unrecognized = 64026; + + optional bool protosizer = 64028; + optional bool compare = 64029; + + optional bool typedecl = 64030; + + optional bool messagename = 64033; + + optional bool goproto_sizecache = 64034; + optional bool goproto_unkeyed = 64035; +} + +extend google.protobuf.FieldOptions { + optional bool nullable = 65001; + optional bool embed = 65002; + optional string customtype = 65003; + optional string customname = 65004; + optional string jsontag = 65005; + optional string moretags = 65006; + optional string casttype = 65007; + optional string castkey = 65008; + optional string castvalue = 65009; + + optional bool stdtime = 65010; + optional bool stdduration = 65011; + optional bool wktpointer = 65012; + + optional string castrepeated = 65013; +} \ No newline at end of file diff --git a/types/codec.go b/types/codec.go index 3d789afe9f0a..fdd884bd5f84 100644 --- a/types/codec.go +++ b/types/codec.go @@ -1,6 +1,8 @@ package types -import "github.com/cosmos/cosmos-sdk/codec" +import ( + "github.com/cosmos/cosmos-sdk/codec" +) // Register the sdk message type func RegisterCodec(cdc *codec.Codec) { diff --git a/types/coin.go b/types/coin.go index 98eaa6b806df..12d82a6e01e9 100644 --- a/types/coin.go +++ b/types/coin.go @@ -11,20 +11,6 @@ import ( //----------------------------------------------------------------------------- // Coin -// Coin hold some amount of one currency. -// -// CONTRACT: A coin will never hold a negative amount of any denomination. -// -// TODO: Make field members private for further safety. -type Coin struct { - Denom string `json:"denom"` - - // To allow the use of unsigned integers (see: #1273) a larger refactor will - // need to be made. So we use signed integers for now with safety measures in - // place preventing negative values being used. - Amount Int `json:"amount"` -} - // NewCoin returns a new coin with a denomination and amount. It will panic if // the amount is negative. func NewCoin(denom string, amount Int) Coin { diff --git a/types/coin_test.go b/types/coin_test.go index a090deb01518..63b3fe38e4ec 100644 --- a/types/coin_test.go +++ b/types/coin_test.go @@ -685,3 +685,18 @@ func TestMarshalJSONCoins(t *testing.T) { }) } } + +func TestCoinAminoEncoding(t *testing.T) { + c := NewInt64Coin(testDenom1, 5) + + bz1, err := cdc.MarshalBinaryBare(c) + require.NoError(t, err) + + bz2, err := cdc.MarshalBinaryLengthPrefixed(c) + require.NoError(t, err) + + bz3, err := c.Marshal() + require.NoError(t, err) + require.Equal(t, bz1, bz3) + require.Equal(t, bz2[1:], bz3) +} diff --git a/types/dec_coin.go b/types/dec_coin.go index 9b6e700104e7..87bf3d8a728c 100644 --- a/types/dec_coin.go +++ b/types/dec_coin.go @@ -11,12 +11,6 @@ import ( // ---------------------------------------------------------------------------- // Decimal Coin -// DecCoin defines a coin which can have additional decimal points -type DecCoin struct { - Denom string `json:"denom"` - Amount Dec `json:"amount"` -} - // NewDecCoin creates a new DecCoin instance from an Int. func NewDecCoin(denom string, amount Int) DecCoin { if err := validate(denom, amount); err != nil { @@ -134,7 +128,7 @@ func (coin DecCoin) IsPositive() bool { // // TODO: Remove once unsigned integers are used. func (coin DecCoin) IsNegative() bool { - return coin.Amount.Sign() == -1 + return coin.Amount.IsNegative() } // String implements the Stringer interface for DecCoin. It returns a diff --git a/types/decimal.go b/types/decimal.go index 839523080656..d6917182b66c 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -10,10 +10,12 @@ import ( "testing" ) +var _ CustomProtobufType = (*Dec)(nil) + // NOTE: never use new(Dec) or else we will panic unmarshalling into the // nil embedded big.Int type Dec struct { - *big.Int `json:"int"` + i *big.Int } // number of decimal places @@ -193,21 +195,27 @@ func MustNewDecFromStr(s string) Dec { //______________________________________________________________________________________________ //nolint -func (d Dec) IsNil() bool { return d.Int == nil } // is decimal nil -func (d Dec) IsZero() bool { return (d.Int).Sign() == 0 } // is equal to zero -func (d Dec) IsNegative() bool { return (d.Int).Sign() == -1 } // is negative -func (d Dec) IsPositive() bool { return (d.Int).Sign() == 1 } // is positive -func (d Dec) Equal(d2 Dec) bool { return (d.Int).Cmp(d2.Int) == 0 } // equal decimals -func (d Dec) GT(d2 Dec) bool { return (d.Int).Cmp(d2.Int) > 0 } // greater than -func (d Dec) GTE(d2 Dec) bool { return (d.Int).Cmp(d2.Int) >= 0 } // greater than or equal -func (d Dec) LT(d2 Dec) bool { return (d.Int).Cmp(d2.Int) < 0 } // less than -func (d Dec) LTE(d2 Dec) bool { return (d.Int).Cmp(d2.Int) <= 0 } // less than or equal -func (d Dec) Neg() Dec { return Dec{new(big.Int).Neg(d.Int)} } // reverse the decimal sign -func (d Dec) Abs() Dec { return Dec{new(big.Int).Abs(d.Int)} } // absolute value +func (d Dec) IsNil() bool { return d.i == nil } // is decimal nil +func (d Dec) IsZero() bool { return (d.i).Sign() == 0 } // is equal to zero +func (d Dec) IsNegative() bool { return (d.i).Sign() == -1 } // is negative +func (d Dec) IsPositive() bool { return (d.i).Sign() == 1 } // is positive +func (d Dec) Equal(d2 Dec) bool { return (d.i).Cmp(d2.i) == 0 } // equal decimals +func (d Dec) GT(d2 Dec) bool { return (d.i).Cmp(d2.i) > 0 } // greater than +func (d Dec) GTE(d2 Dec) bool { return (d.i).Cmp(d2.i) >= 0 } // greater than or equal +func (d Dec) LT(d2 Dec) bool { return (d.i).Cmp(d2.i) < 0 } // less than +func (d Dec) LTE(d2 Dec) bool { return (d.i).Cmp(d2.i) <= 0 } // less than or equal +func (d Dec) Neg() Dec { return Dec{new(big.Int).Neg(d.i)} } // reverse the decimal sign +func (d Dec) Abs() Dec { return Dec{new(big.Int).Abs(d.i)} } // absolute value + +// BigInt returns a copy of the underlying big.Int. +func (d Dec) BigInt() *big.Int { + copy := new(big.Int) + return copy.Set(d.i) +} // addition func (d Dec) Add(d2 Dec) Dec { - res := new(big.Int).Add(d.Int, d2.Int) + res := new(big.Int).Add(d.i, d2.i) if res.BitLen() > 255+DecimalPrecisionBits { panic("Int overflow") @@ -217,7 +225,7 @@ func (d Dec) Add(d2 Dec) Dec { // subtraction func (d Dec) Sub(d2 Dec) Dec { - res := new(big.Int).Sub(d.Int, d2.Int) + res := new(big.Int).Sub(d.i, d2.i) if res.BitLen() > 255+DecimalPrecisionBits { panic("Int overflow") @@ -227,7 +235,7 @@ func (d Dec) Sub(d2 Dec) Dec { // multiplication func (d Dec) Mul(d2 Dec) Dec { - mul := new(big.Int).Mul(d.Int, d2.Int) + mul := new(big.Int).Mul(d.i, d2.i) chopped := chopPrecisionAndRound(mul) if chopped.BitLen() > 255+DecimalPrecisionBits { @@ -238,7 +246,7 @@ func (d Dec) Mul(d2 Dec) Dec { // multiplication truncate func (d Dec) MulTruncate(d2 Dec) Dec { - mul := new(big.Int).Mul(d.Int, d2.Int) + mul := new(big.Int).Mul(d.i, d2.i) chopped := chopPrecisionAndTruncate(mul) if chopped.BitLen() > 255+DecimalPrecisionBits { @@ -249,7 +257,7 @@ func (d Dec) MulTruncate(d2 Dec) Dec { // multiplication func (d Dec) MulInt(i Int) Dec { - mul := new(big.Int).Mul(d.Int, i.i) + mul := new(big.Int).Mul(d.i, i.i) if mul.BitLen() > 255+DecimalPrecisionBits { panic("Int overflow") @@ -259,7 +267,7 @@ func (d Dec) MulInt(i Int) Dec { // MulInt64 - multiplication with int64 func (d Dec) MulInt64(i int64) Dec { - mul := new(big.Int).Mul(d.Int, big.NewInt(i)) + mul := new(big.Int).Mul(d.i, big.NewInt(i)) if mul.BitLen() > 255+DecimalPrecisionBits { panic("Int overflow") @@ -269,11 +277,12 @@ func (d Dec) MulInt64(i int64) Dec { // quotient func (d Dec) Quo(d2 Dec) Dec { + // multiply precision twice - mul := new(big.Int).Mul(d.Int, precisionReuse) + mul := new(big.Int).Mul(d.i, precisionReuse) mul.Mul(mul, precisionReuse) - quo := new(big.Int).Quo(mul, d2.Int) + quo := new(big.Int).Quo(mul, d2.i) chopped := chopPrecisionAndRound(quo) if chopped.BitLen() > 255+DecimalPrecisionBits { @@ -286,10 +295,10 @@ func (d Dec) Quo(d2 Dec) Dec { func (d Dec) QuoTruncate(d2 Dec) Dec { // multiply precision twice - mul := new(big.Int).Mul(d.Int, precisionReuse) + mul := new(big.Int).Mul(d.i, precisionReuse) mul.Mul(mul, precisionReuse) - quo := new(big.Int).Quo(mul, d2.Int) + quo := new(big.Int).Quo(mul, d2.i) chopped := chopPrecisionAndTruncate(quo) if chopped.BitLen() > 255+DecimalPrecisionBits { @@ -301,10 +310,10 @@ func (d Dec) QuoTruncate(d2 Dec) Dec { // quotient, round up func (d Dec) QuoRoundUp(d2 Dec) Dec { // multiply precision twice - mul := new(big.Int).Mul(d.Int, precisionReuse) + mul := new(big.Int).Mul(d.i, precisionReuse) mul.Mul(mul, precisionReuse) - quo := new(big.Int).Quo(mul, d2.Int) + quo := new(big.Int).Quo(mul, d2.i) chopped := chopPrecisionAndRoundUp(quo) if chopped.BitLen() > 255+DecimalPrecisionBits { @@ -315,13 +324,13 @@ func (d Dec) QuoRoundUp(d2 Dec) Dec { // quotient func (d Dec) QuoInt(i Int) Dec { - mul := new(big.Int).Quo(d.Int, i.i) + mul := new(big.Int).Quo(d.i, i.i) return Dec{mul} } // QuoInt64 - quotient with int64 func (d Dec) QuoInt64(i int64) Dec { - mul := new(big.Int).Quo(d.Int, big.NewInt(i)) + mul := new(big.Int).Quo(d.i, big.NewInt(i)) return Dec{mul} } @@ -397,7 +406,7 @@ func (d Dec) ApproxSqrt() (Dec, error) { // is integer, e.g. decimals are zero func (d Dec) IsInteger() bool { - return new(big.Int).Rem(d.Int, precisionReuse).Sign() == 0 + return new(big.Int).Rem(d.i, precisionReuse).Sign() == 0 } // format decimal state @@ -409,8 +418,8 @@ func (d Dec) Format(s fmt.State, verb rune) { } func (d Dec) String() string { - if d.Int == nil { - return d.Int.String() + if d.i == nil { + return d.i.String() } isNeg := d.IsNegative() @@ -418,7 +427,7 @@ func (d Dec) String() string { d = d.Neg() } - bzInt, err := d.Int.MarshalText() + bzInt, err := d.i.MarshalText() if err != nil { return "" } @@ -537,7 +546,7 @@ func chopPrecisionAndRoundNonMutative(d *big.Int) *big.Int { // RoundInt64 rounds the decimal using bankers rounding func (d Dec) RoundInt64() int64 { - chopped := chopPrecisionAndRoundNonMutative(d.Int) + chopped := chopPrecisionAndRoundNonMutative(d.i) if !chopped.IsInt64() { panic("Int64() out of bound") } @@ -546,7 +555,7 @@ func (d Dec) RoundInt64() int64 { // RoundInt round the decimal using bankers rounding func (d Dec) RoundInt() Int { - return NewIntFromBigInt(chopPrecisionAndRoundNonMutative(d.Int)) + return NewIntFromBigInt(chopPrecisionAndRoundNonMutative(d.i)) } //___________________________________________________________________________________ @@ -563,7 +572,7 @@ func chopPrecisionAndTruncateNonMutative(d *big.Int) *big.Int { // TruncateInt64 truncates the decimals from the number and returns an int64 func (d Dec) TruncateInt64() int64 { - chopped := chopPrecisionAndTruncateNonMutative(d.Int) + chopped := chopPrecisionAndTruncateNonMutative(d.i) if !chopped.IsInt64() { panic("Int64() out of bound") } @@ -572,18 +581,18 @@ func (d Dec) TruncateInt64() int64 { // TruncateInt truncates the decimals from the number and returns an Int func (d Dec) TruncateInt() Int { - return NewIntFromBigInt(chopPrecisionAndTruncateNonMutative(d.Int)) + return NewIntFromBigInt(chopPrecisionAndTruncateNonMutative(d.i)) } // TruncateDec truncates the decimals from the number and returns a Dec func (d Dec) TruncateDec() Dec { - return NewDecFromBigInt(chopPrecisionAndTruncateNonMutative(d.Int)) + return NewDecFromBigInt(chopPrecisionAndTruncateNonMutative(d.i)) } // Ceil returns the smallest interger value (as a decimal) that is greater than // or equal to the given decimal. func (d Dec) Ceil() Dec { - tmp := new(big.Int).Set(d.Int) + tmp := new(big.Int).Set(d.i) quo, rem := tmp, big.NewInt(0) quo, rem = quo.QuoRem(tmp, precisionReuse, rem) @@ -639,58 +648,26 @@ func SortableDecBytes(dec Dec) []byte { //___________________________________________________________________________________ // reuse nil values -var ( - nilAmino string - nilJSON []byte -) +var nilJSON []byte func init() { empty := new(big.Int) - bz, err := empty.MarshalText() - if err != nil { - panic("bad nil amino init") - } - nilAmino = string(bz) - - nilJSON, err = json.Marshal(string(bz)) - if err != nil { - panic("bad nil json init") - } -} - -// wraps d.MarshalText() -func (d Dec) MarshalAmino() (string, error) { - if d.Int == nil { - return nilAmino, nil - } - bz, err := d.Int.MarshalText() - return string(bz), err -} - -// requires a valid JSON string - strings quotes and calls UnmarshalText -func (d *Dec) UnmarshalAmino(text string) (err error) { - tempInt := new(big.Int) - err = tempInt.UnmarshalText([]byte(text)) - if err != nil { - return err - } - d.Int = tempInt - return nil + bz, _ := empty.MarshalText() + nilJSON, _ = json.Marshal(string(bz)) } // MarshalJSON marshals the decimal func (d Dec) MarshalJSON() ([]byte, error) { - if d.Int == nil { + if d.i == nil { return nilJSON, nil } - return json.Marshal(d.String()) } // UnmarshalJSON defines custom decoding scheme func (d *Dec) UnmarshalJSON(bz []byte) error { - if d.Int == nil { - d.Int = new(big.Int) + if d.i == nil { + d.i = new(big.Int) } var text string @@ -698,17 +675,80 @@ func (d *Dec) UnmarshalJSON(bz []byte) error { if err != nil { return err } + // TODO: Reuse dec allocation newDec, err := NewDecFromStr(text) if err != nil { return err } - d.Int = newDec.Int + + d.i = newDec.i return nil } -// MarshalYAML returns Ythe AML representation. -func (d Dec) MarshalYAML() (interface{}, error) { return d.String(), nil } +// MarshalYAML returns the YAML representation. +func (d Dec) MarshalYAML() (interface{}, error) { + return d.String(), nil +} + +// Marshal implements the gogo proto custom type interface. +func (d Dec) Marshal() ([]byte, error) { + if d.i == nil { + d.i = new(big.Int) + } + return d.i.MarshalText() +} + +// MarshalTo implements the gogo proto custom type interface. +func (d *Dec) MarshalTo(data []byte) (n int, err error) { + if d.i == nil { + d.i = new(big.Int) + } + if len(d.i.Bytes()) == 0 { + copy(data, []byte{0x30}) + return 1, nil + } + + bz, err := d.Marshal() + if err != nil { + return 0, err + } + + copy(data, bz) + return len(bz), nil +} + +// Unmarshal implements the gogo proto custom type interface. +func (d *Dec) Unmarshal(data []byte) error { + if len(data) == 0 { + d = nil + return nil + } + + if d.i == nil { + d.i = new(big.Int) + } + + if err := d.i.UnmarshalText(data); err != nil { + return err + } + + if d.i.BitLen() > maxBitLen { + return fmt.Errorf("decimal out of range; got: %d, max: %d", d.i.BitLen(), maxBitLen) + } + + return nil +} + +// Size implements the gogo proto custom type interface. +func (d *Dec) Size() int { + bz, _ := d.Marshal() + return len(bz) +} + +// Override Amino binary serialization by proxying to protobuf. +func (d Dec) MarshalAmino() ([]byte, error) { return d.Marshal() } +func (d *Dec) UnmarshalAmino(bz []byte) error { return d.Unmarshal(bz) } //___________________________________________________________________________________ // helpers diff --git a/types/decimal_test.go b/types/decimal_test.go index 48c691a100dc..b88f146094fe 100644 --- a/types/decimal_test.go +++ b/types/decimal_test.go @@ -1,14 +1,15 @@ package types import ( + "encoding/json" + "fmt" "math/big" "testing" + "github.com/cosmos/cosmos-sdk/codec" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/cosmos/cosmos-sdk/codec" + yaml "gopkg.in/yaml.v2" ) // create a decimal from a decimal string (ex. "1234.5678") @@ -273,7 +274,7 @@ var cdc = codec.New() func TestDecMarshalJSON(t *testing.T) { decimal := func(i int64) Dec { d := NewDec(0) - d.Int = new(big.Int).SetInt64(i) + d.i = new(big.Int).SetInt64(i) return d } tests := []struct { @@ -317,18 +318,6 @@ func TestZeroDeserializationJSON(t *testing.T) { require.NotNil(t, err) } -func TestSerializationText(t *testing.T) { - d := mustNewDecFromStr(t, "0.333") - - bz, err := d.MarshalText() - require.NoError(t, err) - - d2 := Dec{new(big.Int)} - err = d2.UnmarshalText(bz) - require.NoError(t, err) - require.True(t, d.Equal(d2), "original: %v, unmarshalled: %v", d, d2) -} - func TestSerializationGocodecJSON(t *testing.T) { d := mustNewDecFromStr(t, "0.333") @@ -341,39 +330,12 @@ func TestSerializationGocodecJSON(t *testing.T) { require.True(t, d.Equal(d2), "original: %v, unmarshalled: %v", d, d2) } -func TestSerializationGocodecBinary(t *testing.T) { - d := mustNewDecFromStr(t, "0.333") - - bz, err := cdc.MarshalBinaryLengthPrefixed(d) - require.NoError(t, err) - - var d2 Dec - err = cdc.UnmarshalBinaryLengthPrefixed(bz, &d2) - require.NoError(t, err) - require.True(t, d.Equal(d2), "original: %v, unmarshalled: %v", d, d2) -} - type testDEmbedStruct struct { Field1 string `json:"f1"` Field2 int `json:"f2"` Field3 Dec `json:"f3"` } -// TODO make work for UnmarshalJSON -func TestEmbeddedStructSerializationGocodec(t *testing.T) { - obj := testDEmbedStruct{"foo", 10, NewDecWithPrec(1, 3)} - bz, err := cdc.MarshalBinaryLengthPrefixed(obj) - require.Nil(t, err) - - var obj2 testDEmbedStruct - err = cdc.UnmarshalBinaryLengthPrefixed(bz, &obj2) - require.Nil(t, err) - - require.Equal(t, obj.Field1, obj2.Field1) - require.Equal(t, obj.Field2, obj2.Field2) - require.True(t, obj.Field3.Equal(obj2.Field3), "original: %v, unmarshalled: %v", obj, obj2) -} - func TestStringOverflow(t *testing.T) { // two random 64 bit primes dec1, err := NewDecFromStr("51643150036226787134389711697696177267") @@ -511,3 +473,62 @@ func TestDecSortableBytes(t *testing.T) { assert.Panics(t, func() { SortableDecBytes(NewDec(1000000000000000001)) }) assert.Panics(t, func() { SortableDecBytes(NewDec(-1000000000000000001)) }) } + +func TestDecEncoding(t *testing.T) { + testCases := []struct { + input Dec + rawBz string + jsonStr string + yamlStr string + }{ + { + NewDec(0), "30", + "\"0.000000000000000000\"", + "\"0.000000000000000000\"\n", + }, + { + NewDecWithPrec(4, 2), + "3430303030303030303030303030303030", + "\"0.040000000000000000\"", + "\"0.040000000000000000\"\n", + }, + { + NewDecWithPrec(-4, 2), + "2D3430303030303030303030303030303030", + "\"-0.040000000000000000\"", + "\"-0.040000000000000000\"\n", + }, + { + NewDecWithPrec(1414213562373095049, 18), + "31343134323133353632333733303935303439", + "\"1.414213562373095049\"", + "\"1.414213562373095049\"\n", + }, + { + NewDecWithPrec(-1414213562373095049, 18), + "2D31343134323133353632333733303935303439", + "\"-1.414213562373095049\"", + "\"-1.414213562373095049\"\n", + }, + } + + for _, tc := range testCases { + bz, err := tc.input.Marshal() + require.NoError(t, err) + require.Equal(t, tc.rawBz, fmt.Sprintf("%X", bz)) + + var other Dec + require.NoError(t, (&other).Unmarshal(bz)) + require.True(t, tc.input.Equal(other)) + + bz, err = json.Marshal(tc.input) + require.NoError(t, err) + require.Equal(t, tc.jsonStr, string(bz)) + require.NoError(t, json.Unmarshal(bz, &other)) + require.True(t, tc.input.Equal(other)) + + bz, err = yaml.Marshal(tc.input) + require.NoError(t, err) + require.Equal(t, tc.yamlStr, string(bz)) + } +} diff --git a/types/int.go b/types/int.go index caabdb11318c..9cc99a013263 100644 --- a/types/int.go +++ b/types/int.go @@ -1,6 +1,7 @@ package types import ( + "encoding" "encoding/json" "fmt" "testing" @@ -52,12 +53,6 @@ func max(i *big.Int, i2 *big.Int) *big.Int { return new(big.Int).Set(i) } -// MarshalAmino for custom encoding scheme -func marshalAmino(i *big.Int) (string, error) { - bz, err := i.MarshalText() - return string(bz), err -} - func unmarshalText(i *big.Int, text string) error { if err := i.UnmarshalText([]byte(text)); err != nil { return err @@ -70,32 +65,7 @@ func unmarshalText(i *big.Int, text string) error { return nil } -// UnmarshalAmino for custom decoding scheme -func unmarshalAmino(i *big.Int, text string) (err error) { - return unmarshalText(i, text) -} - -// MarshalJSON for custom encoding scheme -// Must be encoded as a string for JSON precision -func marshalJSON(i *big.Int) ([]byte, error) { - text, err := i.MarshalText() - if err != nil { - return nil, err - } - return json.Marshal(string(text)) -} - -// UnmarshalJSON for custom decoding scheme -// Must be encoded as a string for JSON precision -func unmarshalJSON(i *big.Int, bz []byte) error { - var text string - err := json.Unmarshal(bz, &text) - if err != nil { - return err - } - - return unmarshalText(i, text) -} +var _ CustomProtobufType = (*Int)(nil) // Int wraps integer with 256 bit range bound // Checks overflow, underflow and division by zero @@ -341,40 +311,107 @@ func (i Int) String() string { return i.i.String() } -// MarshalAmino defines custom encoding scheme -func (i Int) MarshalAmino() (string, error) { +// MarshalJSON defines custom encoding scheme +func (i Int) MarshalJSON() ([]byte, error) { if i.i == nil { // Necessary since default Uint initialization has i.i as nil i.i = new(big.Int) } - return marshalAmino(i.i) + return marshalJSON(i.i) } -// UnmarshalAmino defines custom decoding scheme -func (i *Int) UnmarshalAmino(text string) error { +// UnmarshalJSON defines custom decoding scheme +func (i *Int) UnmarshalJSON(bz []byte) error { if i.i == nil { // Necessary since default Int initialization has i.i as nil i.i = new(big.Int) } - return unmarshalAmino(i.i, text) + return unmarshalJSON(i.i, bz) } -// MarshalJSON defines custom encoding scheme -func (i Int) MarshalJSON() ([]byte, error) { - if i.i == nil { // Necessary since default Uint initialization has i.i as nil +// MarshalJSON for custom encoding scheme +// Must be encoded as a string for JSON precision +func marshalJSON(i encoding.TextMarshaler) ([]byte, error) { + text, err := i.MarshalText() + if err != nil { + return nil, err + } + + return json.Marshal(string(text)) +} + +// UnmarshalJSON for custom decoding scheme +// Must be encoded as a string for JSON precision +func unmarshalJSON(i *big.Int, bz []byte) error { + var text string + if err := json.Unmarshal(bz, &text); err != nil { + return err + } + + return unmarshalText(i, text) +} + +// MarshalYAML returns the YAML representation. +func (i Int) MarshalYAML() (interface{}, error) { + return i.String(), nil +} + +// Marshal implements the gogo proto custom type interface. +func (i Int) Marshal() ([]byte, error) { + if i.i == nil { i.i = new(big.Int) } - return marshalJSON(i.i) + return i.i.MarshalText() } -// UnmarshalJSON defines custom decoding scheme -func (i *Int) UnmarshalJSON(bz []byte) error { - if i.i == nil { // Necessary since default Int initialization has i.i as nil +// MarshalTo implements the gogo proto custom type interface. +func (i *Int) MarshalTo(data []byte) (n int, err error) { + if i.i == nil { i.i = new(big.Int) } - return unmarshalJSON(i.i, bz) + if len(i.i.Bytes()) == 0 { + copy(data, []byte{0x30}) + return 1, nil + } + + bz, err := i.Marshal() + if err != nil { + return 0, err + } + + copy(data, bz) + return len(bz), nil +} + +// Unmarshal implements the gogo proto custom type interface. +func (i *Int) Unmarshal(data []byte) error { + if len(data) == 0 { + i = nil + return nil + } + + if i.i == nil { + i.i = new(big.Int) + } + + if err := i.i.UnmarshalText(data); err != nil { + return err + } + + if i.i.BitLen() > maxBitLen { + return fmt.Errorf("integer out of range; got: %d, max: %d", i.i.BitLen(), maxBitLen) + } + + return nil +} + +// Size implements the gogo proto custom type interface. +func (i *Int) Size() int { + bz, _ := i.Marshal() + return len(bz) } -// MarshalYAML returns Ythe AML representation. -func (i Int) MarshalYAML() (interface{}, error) { return i.String(), nil } +// Override Amino binary serialization by proxying to protobuf. +func (i Int) MarshalAmino() ([]byte, error) { return i.Marshal() } +func (i *Int) UnmarshalAmino(bz []byte) error { return i.Unmarshal(bz) } // intended to be used with require/assert: require.True(IntEq(...)) func IntEq(t *testing.T, exp, got Int) (*testing.T, bool, string, string, string) { diff --git a/types/int_test.go b/types/int_test.go index 072b2f47bb9a..7a8ceade1748 100644 --- a/types/int_test.go +++ b/types/int_test.go @@ -282,21 +282,21 @@ func TestEncodingRandom(t *testing.T) { ni := NewInt(n) var ri Int - str, err := ni.MarshalAmino() + str, err := ni.Marshal() require.Nil(t, err) - err = (&ri).UnmarshalAmino(str) + err = (&ri).Unmarshal(str) require.Nil(t, err) - require.Equal(t, ni, ri, "MarshalAmino * UnmarshalAmino is not identity. tc #%d, Expected %s, Actual %s", i, ni.String(), ri.String()) - require.True(t, ni.i != ri.i, "Pointer addresses are equal. tc #%d", i) + require.Equal(t, ni, ri, "binary mismatch; tc #%d, expected %s, actual %s", i, ni.String(), ri.String()) + require.True(t, ni.i != ri.i, "pointer addresses are equal; tc #%d", i) bz, err := ni.MarshalJSON() require.Nil(t, err) err = (&ri).UnmarshalJSON(bz) require.Nil(t, err) - require.Equal(t, ni, ri, "MarshalJSON * UnmarshalJSON is not identity. tc #%d, Expected %s, Actual %s", i, ni.String(), ri.String()) - require.True(t, ni.i != ri.i, "Pointer addresses are equal. tc #%d", i) + require.Equal(t, ni, ri, "json mismatch; tc #%d, expected %s, actual %s", i, ni.String(), ri.String()) + require.True(t, ni.i != ri.i, "pointer addresses are equal; tc #%d", i) } for i := 0; i < 1000; i++ { @@ -304,21 +304,21 @@ func TestEncodingRandom(t *testing.T) { ni := NewUint(n) var ri Uint - str, err := ni.MarshalAmino() + str, err := ni.Marshal() require.Nil(t, err) - err = (&ri).UnmarshalAmino(str) + err = (&ri).Unmarshal(str) require.Nil(t, err) - require.Equal(t, ni, ri, "MarshalAmino * UnmarshalAmino is not identity. tc #%d, Expected %s, Actual %s", i, ni.String(), ri.String()) - require.True(t, ni.i != ri.i, "Pointer addresses are equal. tc #%d", i) + require.Equal(t, ni, ri, "binary mismatch; tc #%d, expected %s, actual %s", i, ni.String(), ri.String()) + require.True(t, ni.i != ri.i, "pointer addresses are equal; tc #%d", i) bz, err := ni.MarshalJSON() require.Nil(t, err) err = (&ri).UnmarshalJSON(bz) require.Nil(t, err) - require.Equal(t, ni, ri, "MarshalJSON * UnmarshalJSON is not identity. tc #%d, Expected %s, Actual %s", i, ni.String(), ri.String()) - require.True(t, ni.i != ri.i, "Pointer addresses are equal. tc #%d", i) + require.Equal(t, ni, ri, "json mismatch; tc #%d, expected %s, actual %s", i, ni.String(), ri.String()) + require.True(t, ni.i != ri.i, "pointer addresses are equal; tc #%d", i) } } @@ -326,29 +326,71 @@ func TestEncodingTableInt(t *testing.T) { var i Int cases := []struct { - i Int - bz []byte - str string + i Int + jsonBz []byte + rawBz []byte }{ - {NewInt(0), []byte("\"0\""), "0"}, - {NewInt(100), []byte("\"100\""), "100"}, - {NewInt(51842), []byte("\"51842\""), "51842"}, - {NewInt(19513368), []byte("\"19513368\""), "19513368"}, - {NewInt(999999999999), []byte("\"999999999999\""), "999999999999"}, + { + NewInt(0), + []byte("\"0\""), + []byte{0x30}, + }, + { + NewInt(100), + []byte("\"100\""), + []byte{0x31, 0x30, 0x30}, + }, + { + NewInt(-100), + []byte("\"-100\""), + []byte{0x2d, 0x31, 0x30, 0x30}, + }, + { + NewInt(51842), + []byte("\"51842\""), + []byte{0x35, 0x31, 0x38, 0x34, 0x32}, + }, + { + NewInt(-51842), + []byte("\"-51842\""), + []byte{0x2d, 0x35, 0x31, 0x38, 0x34, 0x32}, + }, + { + NewInt(19513368), + []byte("\"19513368\""), + []byte{0x31, 0x39, 0x35, 0x31, 0x33, 0x33, 0x36, 0x38}, + }, + { + NewInt(-19513368), + []byte("\"-19513368\""), + []byte{0x2d, 0x31, 0x39, 0x35, 0x31, 0x33, 0x33, 0x36, 0x38}, + }, + { + NewInt(999999999999), + []byte("\"999999999999\""), + []byte{0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39}, + }, + { + NewInt(-999999999999), + []byte("\"-999999999999\""), + []byte{0x2d, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39}, + }, } for tcnum, tc := range cases { bz, err := tc.i.MarshalJSON() require.Nil(t, err, "Error marshaling Int. tc #%d, err %s", tcnum, err) - require.Equal(t, tc.bz, bz, "Marshaled value is different from exported. tc #%d", tcnum) + require.Equal(t, tc.jsonBz, bz, "Marshaled value is different from exported. tc #%d", tcnum) + err = (&i).UnmarshalJSON(bz) require.Nil(t, err, "Error unmarshaling Int. tc #%d, err %s", tcnum, err) require.Equal(t, tc.i, i, "Unmarshaled value is different from exported. tc #%d", tcnum) - str, err := tc.i.MarshalAmino() + bz, err = tc.i.Marshal() require.Nil(t, err, "Error marshaling Int. tc #%d, err %s", tcnum, err) - require.Equal(t, tc.str, str, "Marshaled value is different from exported. tc #%d", tcnum) - err = (&i).UnmarshalAmino(str) + require.Equal(t, tc.rawBz, bz, "Marshaled value is different from exported. tc #%d", tcnum) + + err = (&i).Unmarshal(bz) require.Nil(t, err, "Error unmarshaling Int. tc #%d, err %s", tcnum, err) require.Equal(t, tc.i, i, "Unmarshaled value is different from exported. tc #%d", tcnum) } @@ -358,29 +400,51 @@ func TestEncodingTableUint(t *testing.T) { var i Uint cases := []struct { - i Uint - bz []byte - str string + i Uint + jsonBz []byte + rawBz []byte }{ - {NewUint(0), []byte("\"0\""), "0"}, - {NewUint(100), []byte("\"100\""), "100"}, - {NewUint(51842), []byte("\"51842\""), "51842"}, - {NewUint(19513368), []byte("\"19513368\""), "19513368"}, - {NewUint(999999999999), []byte("\"999999999999\""), "999999999999"}, + { + NewUint(0), + []byte("\"0\""), + []byte{0x30}, + }, + { + NewUint(100), + []byte("\"100\""), + []byte{0x31, 0x30, 0x30}, + }, + { + NewUint(51842), + []byte("\"51842\""), + []byte{0x35, 0x31, 0x38, 0x34, 0x32}, + }, + { + NewUint(19513368), + []byte("\"19513368\""), + []byte{0x31, 0x39, 0x35, 0x31, 0x33, 0x33, 0x36, 0x38}, + }, + { + NewUint(999999999999), + []byte("\"999999999999\""), + []byte{0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39}, + }, } for tcnum, tc := range cases { bz, err := tc.i.MarshalJSON() require.Nil(t, err, "Error marshaling Int. tc #%d, err %s", tcnum, err) - require.Equal(t, tc.bz, bz, "Marshaled value is different from exported. tc #%d", tcnum) + require.Equal(t, tc.jsonBz, bz, "Marshaled value is different from exported. tc #%d", tcnum) + err = (&i).UnmarshalJSON(bz) require.Nil(t, err, "Error unmarshaling Int. tc #%d, err %s", tcnum, err) require.Equal(t, tc.i, i, "Unmarshaled value is different from exported. tc #%d", tcnum) - str, err := tc.i.MarshalAmino() + bz, err = tc.i.Marshal() require.Nil(t, err, "Error marshaling Int. tc #%d, err %s", tcnum, err) - require.Equal(t, tc.str, str, "Marshaled value is different from exported. tc #%d", tcnum) - err = (&i).UnmarshalAmino(str) + require.Equal(t, tc.rawBz, bz, "Marshaled value is different from exported. tc #%d", tcnum) + + err = (&i).Unmarshal(bz) require.Nil(t, err, "Error unmarshaling Int. tc #%d, err %s", tcnum, err) require.Equal(t, tc.i, i, "Unmarshaled value is different from exported. tc #%d", tcnum) } @@ -391,15 +455,15 @@ func TestSerializationOverflow(t *testing.T) { x := Int{bx} y := new(Int) - // require amino deserialization to fail due to overflow - xStr, err := x.MarshalAmino() + bz, err := x.Marshal() require.NoError(t, err) - err = y.UnmarshalAmino(xStr) + // require deserialization to fail due to overflow + err = y.Unmarshal(bz) require.Error(t, err) // require JSON deserialization to fail due to overflow - bz, err := x.MarshalJSON() + bz, err = x.MarshalJSON() require.NoError(t, err) err = y.UnmarshalJSON(bz) diff --git a/types/proto.go b/types/proto.go new file mode 100644 index 000000000000..e4cdbdc511c0 --- /dev/null +++ b/types/proto.go @@ -0,0 +1,20 @@ +package types + +import ( + _ "github.com/gogo/protobuf/gogoproto" // nolint + _ "github.com/regen-network/cosmos-proto" // nolint +) + +// CustomProtobufType defines the interface custom gogo proto types must implement +// in order to be used as a "customtype" extension. +// +// ref: https://github.com/gogo/protobuf/blob/master/custom_types.md +type CustomProtobufType interface { + Marshal() ([]byte, error) + MarshalTo(data []byte) (n int, err error) + Unmarshal(data []byte) error + Size() int + + MarshalJSON() ([]byte, error) + UnmarshalJSON(data []byte) error +} diff --git a/types/types.pb.go b/types/types.pb.go new file mode 100644 index 000000000000..4ea0bfeec523 --- /dev/null +++ b/types/types.pb.go @@ -0,0 +1,595 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: types/types.proto + +package types + +import ( + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// Coin defines a token with a denomination and an amount. +// +// NOTE: The amount field is an Int which implements the custom method +// signatures required by gogoproto. +type Coin struct { + Denom string `protobuf:"bytes,1,opt,name=denom,proto3" json:"denom,omitempty"` + Amount Int `protobuf:"bytes,2,opt,name=amount,proto3,customtype=Int" json:"amount"` +} + +func (m *Coin) Reset() { *m = Coin{} } +func (*Coin) ProtoMessage() {} +func (*Coin) Descriptor() ([]byte, []int) { + return fileDescriptor_2c0f90c600ad7e2e, []int{0} +} +func (m *Coin) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Coin) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Coin.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 *Coin) XXX_Merge(src proto.Message) { + xxx_messageInfo_Coin.Merge(m, src) +} +func (m *Coin) XXX_Size() int { + return m.Size() +} +func (m *Coin) XXX_DiscardUnknown() { + xxx_messageInfo_Coin.DiscardUnknown(m) +} + +var xxx_messageInfo_Coin proto.InternalMessageInfo + +func (m *Coin) GetDenom() string { + if m != nil { + return m.Denom + } + return "" +} + +// DecCoin defines a token with a denomination and a decimal amount. +// +// NOTE: The amount field is an Dec which implements the custom method +// signatures required by gogoproto. +type DecCoin struct { + Denom string `protobuf:"bytes,1,opt,name=denom,proto3" json:"denom,omitempty"` + Amount Dec `protobuf:"bytes,2,opt,name=amount,proto3,customtype=Dec" json:"amount"` +} + +func (m *DecCoin) Reset() { *m = DecCoin{} } +func (*DecCoin) ProtoMessage() {} +func (*DecCoin) Descriptor() ([]byte, []int) { + return fileDescriptor_2c0f90c600ad7e2e, []int{1} +} +func (m *DecCoin) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DecCoin) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DecCoin.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 *DecCoin) XXX_Merge(src proto.Message) { + xxx_messageInfo_DecCoin.Merge(m, src) +} +func (m *DecCoin) XXX_Size() int { + return m.Size() +} +func (m *DecCoin) XXX_DiscardUnknown() { + xxx_messageInfo_DecCoin.DiscardUnknown(m) +} + +var xxx_messageInfo_DecCoin proto.InternalMessageInfo + +func (m *DecCoin) GetDenom() string { + if m != nil { + return m.Denom + } + return "" +} + +func init() { + proto.RegisterType((*Coin)(nil), "cosmos_sdk.v1.Coin") + proto.RegisterType((*DecCoin)(nil), "cosmos_sdk.v1.DecCoin") +} + +func init() { proto.RegisterFile("types/types.proto", fileDescriptor_2c0f90c600ad7e2e) } + +var fileDescriptor_2c0f90c600ad7e2e = []byte{ + // 214 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x2c, 0xa9, 0x2c, 0x48, + 0x2d, 0xd6, 0x07, 0x93, 0x7a, 0x05, 0x45, 0xf9, 0x25, 0xf9, 0x42, 0xbc, 0xc9, 0xf9, 0xc5, 0xb9, + 0xf9, 0xc5, 0xf1, 0xc5, 0x29, 0xd9, 0x7a, 0x65, 0x86, 0x52, 0x6a, 0x25, 0x19, 0x99, 0x45, 0x29, + 0xf1, 0x05, 0x89, 0x45, 0x25, 0x95, 0xfa, 0x60, 0x15, 0xfa, 0xe9, 0xf9, 0xe9, 0xf9, 0x08, 0x16, + 0x44, 0x9b, 0x92, 0x23, 0x17, 0x8b, 0x73, 0x7e, 0x66, 0x9e, 0x90, 0x08, 0x17, 0x6b, 0x4a, 0x6a, + 0x5e, 0x7e, 0xae, 0x04, 0xa3, 0x02, 0xa3, 0x06, 0x67, 0x10, 0x84, 0x23, 0xa4, 0xcc, 0xc5, 0x96, + 0x98, 0x9b, 0x5f, 0x9a, 0x57, 0x22, 0xc1, 0x04, 0x12, 0x76, 0xe2, 0x3e, 0x71, 0x4f, 0x9e, 0xe1, + 0xd6, 0x3d, 0x79, 0x66, 0xcf, 0xbc, 0x92, 0x20, 0xa8, 0x94, 0x92, 0x0b, 0x17, 0xbb, 0x4b, 0x6a, + 0x32, 0x39, 0xa6, 0xb8, 0xa4, 0x26, 0xc3, 0x4c, 0x71, 0x72, 0xb9, 0xf1, 0x50, 0x8e, 0xa1, 0xe1, + 0x91, 0x1c, 0xc3, 0x89, 0x47, 0x72, 0x8c, 0x17, 0x1e, 0xc9, 0x31, 0x3e, 0x78, 0x24, 0xc7, 0x38, + 0xe1, 0xb1, 0x1c, 0xc3, 0x85, 0xc7, 0x72, 0x0c, 0x37, 0x1e, 0xcb, 0x31, 0x44, 0x29, 0xa5, 0x67, + 0x96, 0x64, 0x94, 0x26, 0xe9, 0x25, 0xe7, 0xe7, 0xea, 0x43, 0x3c, 0x0b, 0xa5, 0x74, 0x8b, 0x53, + 0xb2, 0x21, 0x61, 0x91, 0xc4, 0x06, 0xf6, 0x95, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0x8d, 0xc6, + 0x8c, 0x7d, 0x21, 0x01, 0x00, 0x00, +} + +func (m *Coin) 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 *Coin) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Coin) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size := m.Amount.Size() + i -= size + if _, err := m.Amount.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Denom) > 0 { + i -= len(m.Denom) + copy(dAtA[i:], m.Denom) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Denom))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *DecCoin) 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 *DecCoin) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DecCoin) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size := m.Amount.Size() + i -= size + if _, err := m.Amount.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Denom) > 0 { + i -= len(m.Denom) + copy(dAtA[i:], m.Denom) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Denom))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintTypes(dAtA []byte, offset int, v uint64) int { + offset -= sovTypes(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Coin) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Denom) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = m.Amount.Size() + n += 1 + l + sovTypes(uint64(l)) + return n +} + +func (m *DecCoin) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Denom) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = m.Amount.Size() + n += 1 + l + sovTypes(uint64(l)) + return n +} + +func sovTypes(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTypes(x uint64) (n int) { + return sovTypes(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Coin) 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 ErrIntOverflowTypes + } + 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: Coin: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Coin: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Denom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *DecCoin) 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 ErrIntOverflowTypes + } + 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: DecCoin: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DecCoin: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Denom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTypes(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthTypes + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTypes + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTypes + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTypes = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTypes = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTypes = fmt.Errorf("proto: unexpected end of group") +) diff --git a/types/types.proto b/types/types.proto new file mode 100644 index 000000000000..49da4e5c69f9 --- /dev/null +++ b/types/types.proto @@ -0,0 +1,26 @@ +syntax = "proto3"; +package cosmos_sdk.v1; + +import "third_party/proto/gogoproto/gogo.proto"; + +option go_package = "github.com/cosmos/cosmos-sdk/types"; +option (gogoproto.goproto_stringer_all) = false; +option (gogoproto.stringer_all) = false; + +// Coin defines a token with a denomination and an amount. +// +// NOTE: The amount field is an Int which implements the custom method +// signatures required by gogoproto. +message Coin { + string denom = 1; + string amount = 2 [ (gogoproto.customtype) = "Int", (gogoproto.nullable) = false ]; +} + +// DecCoin defines a token with a denomination and a decimal amount. +// +// NOTE: The amount field is an Dec which implements the custom method +// signatures required by gogoproto. +message DecCoin { + string denom = 1; + string amount = 2 [ (gogoproto.customtype) = "Dec", (gogoproto.nullable) = false ]; +} diff --git a/types/uint.go b/types/uint.go index 976b6414a93f..2305d7386728 100644 --- a/types/uint.go +++ b/types/uint.go @@ -49,6 +49,8 @@ func ZeroUint() Uint { return Uint{big.NewInt(0)} } // OneUint returns Uint value with one. func OneUint() Uint { return Uint{big.NewInt(1)} } +var _ CustomProtobufType = (*Uint)(nil) + // Uint64 converts Uint to uint64 // Panics if the value is out of range func (u Uint) Uint64() uint64 { @@ -130,38 +132,81 @@ func MaxUint(u1, u2 Uint) Uint { return NewUintFromBigInt(max(u1.i, u2.i)) } // Human readable string func (u Uint) String() string { return u.i.String() } -// MarshalAmino defines custom encoding scheme -func (u Uint) MarshalAmino() (string, error) { +// MarshalJSON defines custom encoding scheme +func (u Uint) MarshalJSON() ([]byte, error) { if u.i == nil { // Necessary since default Uint initialization has i.i as nil u.i = new(big.Int) } - return marshalAmino(u.i) + return marshalJSON(u.i) } -// UnmarshalAmino defines custom decoding scheme -func (u *Uint) UnmarshalAmino(text string) error { +// UnmarshalJSON defines custom decoding scheme +func (u *Uint) UnmarshalJSON(bz []byte) error { if u.i == nil { // Necessary since default Uint initialization has i.i as nil u.i = new(big.Int) } - return unmarshalAmino(u.i, text) + return unmarshalJSON(u.i, bz) } -// MarshalJSON defines custom encoding scheme -func (u Uint) MarshalJSON() ([]byte, error) { - if u.i == nil { // Necessary since default Uint initialization has i.i as nil +// Marshal implements the gogo proto custom type interface. +func (u Uint) Marshal() ([]byte, error) { + if u.i == nil { u.i = new(big.Int) } - return marshalJSON(u.i) + return u.i.MarshalText() } -// UnmarshalJSON defines custom decoding scheme -func (u *Uint) UnmarshalJSON(bz []byte) error { - if u.i == nil { // Necessary since default Uint initialization has i.i as nil +// MarshalTo implements the gogo proto custom type interface. +func (u *Uint) MarshalTo(data []byte) (n int, err error) { + if u.i == nil { u.i = new(big.Int) } - return unmarshalJSON(u.i, bz) + if len(u.i.Bytes()) == 0 { + copy(data, []byte{0x30}) + return 1, nil + } + + bz, err := u.Marshal() + if err != nil { + return 0, err + } + + copy(data, bz) + return len(bz), nil } +// Unmarshal implements the gogo proto custom type interface. +func (u *Uint) Unmarshal(data []byte) error { + if len(data) == 0 { + u = nil + return nil + } + + if u.i == nil { + u.i = new(big.Int) + } + + if err := u.i.UnmarshalText(data); err != nil { + return err + } + + if u.i.BitLen() > maxBitLen { + return fmt.Errorf("integer out of range; got: %d, max: %d", u.i.BitLen(), maxBitLen) + } + + return nil +} + +// Size implements the gogo proto custom type interface. +func (u *Uint) Size() int { + bz, _ := u.Marshal() + return len(bz) +} + +// Override Amino binary serialization by proxying to protobuf. +func (u Uint) MarshalAmino() ([]byte, error) { return u.Marshal() } +func (u *Uint) UnmarshalAmino(bz []byte) error { return u.Unmarshal(bz) } + //__________________________________________________________________________ // UintOverflow returns true if a given unsigned integer overflows and false diff --git a/x/simulation/rand_util.go b/x/simulation/rand_util.go index b494b0fb8aab..7ef09100d545 100644 --- a/x/simulation/rand_util.go +++ b/x/simulation/rand_util.go @@ -69,9 +69,9 @@ func RandomDecAmount(r *rand.Rand, max sdk.Dec) sdk.Dec { case 0: // randInt = big.NewInt(0) case 1: - randInt = max.Int // the underlying big int with all precision bits. + randInt = max.BigInt() // the underlying big int with all precision bits. default: // NOTE: there are 10 total cases. - randInt = big.NewInt(0).Rand(r, max.Int) + randInt = big.NewInt(0).Rand(r, max.BigInt()) } return sdk.NewDecFromBigIntWithPrec(randInt, sdk.Precision) } From b647824716d9da2e93889c54f59af300bf1035cb Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Fri, 24 Jan 2020 16:40:56 +0000 Subject: [PATCH 096/529] Refactor x/auth/client/utils/ (#5555) Packages named utils, common, or misc provide clients with no sense of what the package contains. This makes it harder for clients to use the package and makes it harder for maintainers to keep the package focused. Over time, they accumulate dependencies that can make compilation significantly and unnecessarily slower, especially in large programs. And since such package names are generic, they are more likely to collide with other packages imported by client code, forcing clients to invent names to distinguish them. cit. https://blog.golang.org/package-names --- CHANGELOG.md | 4 ++++ x/auth/client/cli/broadcast.go | 4 ++-- x/auth/client/cli/encode.go | 4 ++-- x/auth/client/cli/query.go | 6 +++--- x/auth/client/cli/tx_multisign.go | 4 ++-- x/auth/client/cli/tx_sign.go | 8 ++++---- x/auth/client/{utils => }/query.go | 2 +- x/auth/client/{utils => }/rest.go | 4 ++-- x/auth/client/rest/query.go | 6 +++--- x/auth/client/{utils => }/tx.go | 6 +++--- x/auth/client/{utils => }/tx_test.go | 2 +- x/auth/client/utils/errors.go | 8 -------- x/auth/types/errors.go | 8 ++++++++ x/bank/client/cli/tx.go | 6 +++--- x/bank/client/rest/tx.go | 5 ++--- x/crisis/client/cli/tx.go | 6 +++--- x/distribution/client/cli/tx.go | 22 +++++++++++----------- x/distribution/client/cli/tx_test.go | 4 ++-- x/distribution/client/rest/rest.go | 4 ++-- x/distribution/client/rest/tx.go | 12 ++++++------ x/genutil/client/cli/gentx.go | 10 +++++----- x/gov/client/cli/tx.go | 14 +++++++------- x/gov/client/rest/tx.go | 8 ++++---- x/gov/client/utils/query.go | 12 ++++++------ x/params/client/cli/tx.go | 6 +++--- x/params/client/rest/rest.go | 4 ++-- x/slashing/client/cli/tx.go | 6 +++--- x/slashing/client/rest/tx.go | 4 ++-- x/staking/client/cli/tx.go | 14 +++++++------- x/staking/client/rest/tx.go | 8 ++++---- x/staking/client/rest/utils.go | 4 ++-- x/upgrade/client/cli/tx.go | 10 +++++----- x/upgrade/client/rest/tx.go | 6 +++--- 33 files changed, 117 insertions(+), 114 deletions(-) rename x/auth/client/{utils => }/query.go (99%) rename x/auth/client/{utils => }/rest.go (93%) rename x/auth/client/{utils => }/tx.go (98%) rename x/auth/client/{utils => }/tx_test.go (99%) delete mode 100644 x/auth/client/utils/errors.go create mode 100644 x/auth/types/errors.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 798b321d5159..f4c258b72e6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,10 @@ Ref: https://keepachangelog.com/en/1.0.0/ ## [Unreleased] +### API Breaking Changes + +* (modules) [\#5555](https://github.com/cosmos/cosmos-sdk/pull/5555) Move x/auth/client/utils/ types and functions to x/auth/client/. + ## [v0.38.0] - 2020-01-23 ### State Machine Breaking diff --git a/x/auth/client/cli/broadcast.go b/x/auth/client/cli/broadcast.go index 37590787b4dd..e5a62e388ed4 100644 --- a/x/auth/client/cli/broadcast.go +++ b/x/auth/client/cli/broadcast.go @@ -8,7 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/x/auth/client/utils" + "github.com/cosmos/cosmos-sdk/x/auth/client" ) // GetBroadcastCommand returns the tx broadcast command. @@ -26,7 +26,7 @@ $ tx broadcast ./mytxn.json Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) (err error) { cliCtx := context.NewCLIContext().WithCodec(cdc) - stdTx, err := utils.ReadStdTxFromFile(cliCtx.Codec, args[0]) + stdTx, err := client.ReadStdTxFromFile(cliCtx.Codec, args[0]) if err != nil { return } diff --git a/x/auth/client/cli/encode.go b/x/auth/client/cli/encode.go index 304411dba8a1..fa39a58cab93 100644 --- a/x/auth/client/cli/encode.go +++ b/x/auth/client/cli/encode.go @@ -8,7 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/x/auth/client/utils" + "github.com/cosmos/cosmos-sdk/x/auth/client" ) // txEncodeRespStr implements a simple Stringer wrapper for a encoded tx. @@ -31,7 +31,7 @@ If you supply a dash (-) argument in place of an input filename, the command rea RunE: func(cmd *cobra.Command, args []string) (err error) { cliCtx := context.NewCLIContext().WithCodec(cdc) - stdTx, err := utils.ReadStdTxFromFile(cliCtx.Codec, args[0]) + stdTx, err := client.ReadStdTxFromFile(cliCtx.Codec, args[0]) if err != nil { return } diff --git a/x/auth/client/cli/query.go b/x/auth/client/cli/query.go index 08e796218bb0..d0ebc155ef98 100644 --- a/x/auth/client/cli/query.go +++ b/x/auth/client/cli/query.go @@ -14,7 +14,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/rest" "github.com/cosmos/cosmos-sdk/version" - "github.com/cosmos/cosmos-sdk/x/auth/client/utils" + authclient "github.com/cosmos/cosmos-sdk/x/auth/client" "github.com/cosmos/cosmos-sdk/x/auth/types" tmtypes "github.com/tendermint/tendermint/types" @@ -118,7 +118,7 @@ $ %s query txs --%s 'message.sender=cosmos1...&message.action=withdraw_delegator limit := viper.GetInt(flags.FlagLimit) cliCtx := context.NewCLIContext().WithCodec(cdc) - txs, err := utils.QueryTxsByEvents(cliCtx, tmEvents, page, limit) + txs, err := authclient.QueryTxsByEvents(cliCtx, tmEvents, page, limit) if err != nil { return err } @@ -162,7 +162,7 @@ func QueryTxCmd(cdc *codec.Codec) *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { cliCtx := context.NewCLIContext().WithCodec(cdc) - output, err := utils.QueryTx(cliCtx, args[0]) + output, err := authclient.QueryTx(cliCtx, args[0]) if err != nil { return err } diff --git a/x/auth/client/cli/tx_multisign.go b/x/auth/client/cli/tx_multisign.go index 9d67f26ef9ba..b46192925dbd 100644 --- a/x/auth/client/cli/tx_multisign.go +++ b/x/auth/client/cli/tx_multisign.go @@ -18,7 +18,7 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/keys" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" - "github.com/cosmos/cosmos-sdk/x/auth/client/utils" + "github.com/cosmos/cosmos-sdk/x/auth/client" "github.com/cosmos/cosmos-sdk/x/auth/types" ) @@ -60,7 +60,7 @@ recommended to set such parameters manually. func makeMultiSignCmd(cdc *codec.Codec) func(cmd *cobra.Command, args []string) error { return func(cmd *cobra.Command, args []string) (err error) { - stdTx, err := utils.ReadStdTxFromFile(cdc, args[0]) + stdTx, err := client.ReadStdTxFromFile(cdc, args[0]) if err != nil { return } diff --git a/x/auth/client/cli/tx_sign.go b/x/auth/client/cli/tx_sign.go index f2e72cb4e3a9..ebbe936a78b4 100644 --- a/x/auth/client/cli/tx_sign.go +++ b/x/auth/client/cli/tx_sign.go @@ -14,7 +14,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth/client/utils" + "github.com/cosmos/cosmos-sdk/x/auth/client" "github.com/cosmos/cosmos-sdk/x/auth/types" ) @@ -94,7 +94,7 @@ func preSignCmd(cmd *cobra.Command, _ []string) { func makeSignCmd(cdc *codec.Codec) func(cmd *cobra.Command, args []string) error { return func(cmd *cobra.Command, args []string) error { - stdTx, err := utils.ReadStdTxFromFile(cdc, args[0]) + stdTx, err := client.ReadStdTxFromFile(cdc, args[0]) if err != nil { return err } @@ -125,13 +125,13 @@ func makeSignCmd(cdc *codec.Codec) func(cmd *cobra.Command, args []string) error return err } - newTx, err = utils.SignStdTxWithSignerAddress( + newTx, err = client.SignStdTxWithSignerAddress( txBldr, cliCtx, multisigAddr, cliCtx.GetFromName(), stdTx, offline, ) generateSignatureOnly = true } else { appendSig := viper.GetBool(flagAppend) && !generateSignatureOnly - newTx, err = utils.SignStdTx(txBldr, cliCtx, cliCtx.GetFromName(), stdTx, appendSig, offline) + newTx, err = client.SignStdTx(txBldr, cliCtx, cliCtx.GetFromName(), stdTx, appendSig, offline) } if err != nil { diff --git a/x/auth/client/utils/query.go b/x/auth/client/query.go similarity index 99% rename from x/auth/client/utils/query.go rename to x/auth/client/query.go index 8fc236952540..3a2c4c44f1b9 100644 --- a/x/auth/client/utils/query.go +++ b/x/auth/client/query.go @@ -1,4 +1,4 @@ -package utils +package client import ( "encoding/hex" diff --git a/x/auth/client/utils/rest.go b/x/auth/client/rest.go similarity index 93% rename from x/auth/client/utils/rest.go rename to x/auth/client/rest.go index 9423fe629ee4..f79caa1af30e 100644 --- a/x/auth/client/utils/rest.go +++ b/x/auth/client/rest.go @@ -1,4 +1,4 @@ -package utils +package client import ( "log" @@ -31,7 +31,7 @@ func WriteGenerateStdTxResponse(w http.ResponseWriter, cliCtx context.CLIContext if br.Simulate || simAndExec { if gasAdj < 0 { - rest.WriteErrorResponse(w, http.StatusBadRequest, errInvalidGasAdjustment.Error()) + rest.WriteErrorResponse(w, http.StatusBadRequest, types.ErrorInvalidGasAdjustment.Error()) return } diff --git a/x/auth/client/rest/query.go b/x/auth/client/rest/query.go index 77cba3e59c1e..9662ebcc683f 100644 --- a/x/auth/client/rest/query.go +++ b/x/auth/client/rest/query.go @@ -11,7 +11,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/rest" - "github.com/cosmos/cosmos-sdk/x/auth/client/utils" + "github.com/cosmos/cosmos-sdk/x/auth/client" "github.com/cosmos/cosmos-sdk/x/auth/types" genutilrest "github.com/cosmos/cosmos-sdk/x/genutil/client/rest" ) @@ -99,7 +99,7 @@ func QueryTxsRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return } - searchResult, err := utils.QueryTxsByEvents(cliCtx, events, page, limit) + searchResult, err := client.QueryTxsByEvents(cliCtx, events, page, limit) if err != nil { rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return @@ -121,7 +121,7 @@ func QueryTxRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return } - output, err := utils.QueryTx(cliCtx, hashHexStr) + output, err := client.QueryTx(cliCtx, hashHexStr) if err != nil { if strings.Contains(err.Error(), hashHexStr) { rest.WriteErrorResponse(w, http.StatusNotFound, err.Error()) diff --git a/x/auth/client/utils/tx.go b/x/auth/client/tx.go similarity index 98% rename from x/auth/client/utils/tx.go rename to x/auth/client/tx.go index 55b7007002d9..12d50a65ab03 100644 --- a/x/auth/client/utils/tx.go +++ b/x/auth/client/tx.go @@ -1,4 +1,4 @@ -package utils +package client import ( "bufio" @@ -182,7 +182,7 @@ func SignStdTx( // check whether the address is a signer if !isTxSigner(sdk.AccAddress(addr), stdTx.GetSigners()) { - return signedStdTx, fmt.Errorf("%s: %s", errInvalidSigner, name) + return signedStdTx, fmt.Errorf("%s: %s", authtypes.ErrorInvalidSigner, name) } if !offline { @@ -204,7 +204,7 @@ func SignStdTxWithSignerAddress(txBldr authtypes.TxBuilder, cliCtx context.CLICo // check whether the address is a signer if !isTxSigner(addr, stdTx.GetSigners()) { - return signedStdTx, fmt.Errorf("%s: %s", errInvalidSigner, name) + return signedStdTx, fmt.Errorf("%s: %s", authtypes.ErrorInvalidSigner, name) } if !offline { diff --git a/x/auth/client/utils/tx_test.go b/x/auth/client/tx_test.go similarity index 99% rename from x/auth/client/utils/tx_test.go rename to x/auth/client/tx_test.go index a9c33b232053..1fb4ca3d22d6 100644 --- a/x/auth/client/utils/tx_test.go +++ b/x/auth/client/tx_test.go @@ -1,4 +1,4 @@ -package utils +package client import ( "encoding/json" diff --git a/x/auth/client/utils/errors.go b/x/auth/client/utils/errors.go deleted file mode 100644 index 0a0fc7a0f657..000000000000 --- a/x/auth/client/utils/errors.go +++ /dev/null @@ -1,8 +0,0 @@ -package utils - -import "errors" - -var ( - errInvalidSigner = errors.New("tx intended signer does not match the given signer") - errInvalidGasAdjustment = errors.New("invalid gas adjustment") -) diff --git a/x/auth/types/errors.go b/x/auth/types/errors.go new file mode 100644 index 000000000000..3333cc8a467a --- /dev/null +++ b/x/auth/types/errors.go @@ -0,0 +1,8 @@ +package types + +import "errors" + +var ( + ErrorInvalidSigner = errors.New("tx intended signer does not match the given signer") + ErrorInvalidGasAdjustment = errors.New("invalid gas adjustment") +) diff --git a/x/bank/client/cli/tx.go b/x/bank/client/cli/tx.go index 58bce19eba6f..b2b36c45dbe7 100644 --- a/x/bank/client/cli/tx.go +++ b/x/bank/client/cli/tx.go @@ -11,7 +11,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/auth/client/utils" + authclient "github.com/cosmos/cosmos-sdk/x/auth/client" "github.com/cosmos/cosmos-sdk/x/bank/internal/types" ) @@ -38,7 +38,7 @@ func SendTxCmd(cdc *codec.Codec) *cobra.Command { Args: cobra.ExactArgs(3), RunE: func(cmd *cobra.Command, args []string) error { inBuf := bufio.NewReader(cmd.InOrStdin()) - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc)) + txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) cliCtx := context.NewCLIContextWithInputAndFrom(inBuf, args[0]).WithCodec(cdc) to, err := sdk.AccAddressFromBech32(args[1]) @@ -54,7 +54,7 @@ func SendTxCmd(cdc *codec.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint msg := types.NewMsgSend(cliCtx.GetFromAddress(), to, coins) - return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) }, } diff --git a/x/bank/client/rest/tx.go b/x/bank/client/rest/tx.go index 10ac15abc790..fdf245430dba 100644 --- a/x/bank/client/rest/tx.go +++ b/x/bank/client/rest/tx.go @@ -8,8 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/rest" - "github.com/cosmos/cosmos-sdk/x/auth/client/utils" - + authclient "github.com/cosmos/cosmos-sdk/x/auth/client" "github.com/cosmos/cosmos-sdk/x/bank/internal/types" ) @@ -54,6 +53,6 @@ func SendRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { } msg := types.NewMsgSend(fromAddr, toAddr, req.Amount) - utils.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) + authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) } } diff --git a/x/crisis/client/cli/tx.go b/x/crisis/client/cli/tx.go index e2df844db639..d54153b8f6fb 100644 --- a/x/crisis/client/cli/tx.go +++ b/x/crisis/client/cli/tx.go @@ -12,7 +12,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/auth/client/utils" + authclient "github.com/cosmos/cosmos-sdk/x/auth/client" "github.com/cosmos/cosmos-sdk/x/crisis/internal/types" ) @@ -25,13 +25,13 @@ func GetCmdInvariantBroken(cdc *codec.Codec) *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { inBuf := bufio.NewReader(cmd.InOrStdin()) - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc)) + txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) senderAddr := cliCtx.GetFromAddress() moduleName, route := args[0], args[1] msg := types.NewMsgVerifyInvariant(senderAddr, moduleName, route) - return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) }, } return cmd diff --git a/x/distribution/client/cli/tx.go b/x/distribution/client/cli/tx.go index 6eaee60992b6..a033fd28dc1c 100644 --- a/x/distribution/client/cli/tx.go +++ b/x/distribution/client/cli/tx.go @@ -16,7 +16,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/auth/client/utils" + authclient "github.com/cosmos/cosmos-sdk/x/auth/client" "github.com/cosmos/cosmos-sdk/x/gov" "github.com/cosmos/cosmos-sdk/x/distribution/client/common" @@ -105,7 +105,7 @@ $ %s tx distribution withdraw-rewards cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fx Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { inBuf := bufio.NewReader(cmd.InOrStdin()) - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc)) + txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) delAddr := cliCtx.GetFromAddress() @@ -119,7 +119,7 @@ $ %s tx distribution withdraw-rewards cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fx msgs = append(msgs, types.NewMsgWithdrawValidatorCommission(valAddr)) } - return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, msgs) + return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, msgs) }, } cmd.Flags().Bool(flagCommission, false, "also withdraw validator's commission") @@ -143,7 +143,7 @@ $ %s tx distribution withdraw-all-rewards --from mykey Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { inBuf := bufio.NewReader(cmd.InOrStdin()) - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc)) + txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) delAddr := cliCtx.GetFromAddress() @@ -160,7 +160,7 @@ $ %s tx distribution withdraw-all-rewards --from mykey } chunkSize := viper.GetInt(flagMaxMessagesPerTx) - return splitAndApply(utils.GenerateOrBroadcastMsgs, cliCtx, txBldr, msgs, chunkSize) + return splitAndApply(authclient.GenerateOrBroadcastMsgs, cliCtx, txBldr, msgs, chunkSize) }, } @@ -186,7 +186,7 @@ $ %s tx distribution set-withdraw-addr cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75 RunE: func(cmd *cobra.Command, args []string) error { inBuf := bufio.NewReader(cmd.InOrStdin()) - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc)) + txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) delAddr := cliCtx.GetFromAddress() @@ -196,7 +196,7 @@ $ %s tx distribution set-withdraw-addr cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75 } msg := types.NewMsgSetWithdrawAddress(delAddr, withdrawAddr) - return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) }, } } @@ -239,7 +239,7 @@ Where proposal.json contains: ), RunE: func(cmd *cobra.Command, args []string) error { inBuf := bufio.NewReader(cmd.InOrStdin()) - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc)) + txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) proposal, err := ParseCommunityPoolSpendProposalJSON(cdc, args[0]) @@ -255,7 +255,7 @@ Where proposal.json contains: return err } - return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) }, } @@ -280,7 +280,7 @@ $ %s tx distribution fund-community-pool 100uatom --from mykey ), RunE: func(cmd *cobra.Command, args []string) error { inBuf := bufio.NewReader(cmd.InOrStdin()) - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc)) + txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) depositorAddr := cliCtx.GetFromAddress() @@ -294,7 +294,7 @@ $ %s tx distribution fund-community-pool 100uatom --from mykey return err } - return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) }, } } diff --git a/x/distribution/client/cli/tx_test.go b/x/distribution/client/cli/tx_test.go index af09d5445a89..860b31fa634c 100644 --- a/x/distribution/client/cli/tx_test.go +++ b/x/distribution/client/cli/tx_test.go @@ -10,13 +10,13 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/auth/client/utils" + authclient "github.com/cosmos/cosmos-sdk/x/auth/client" ) func createFakeTxBuilder() auth.TxBuilder { cdc := codec.New() return auth.NewTxBuilder( - utils.GetTxEncoder(cdc), + authclient.GetTxEncoder(cdc), 123, 9876, 0, diff --git a/x/distribution/client/rest/rest.go b/x/distribution/client/rest/rest.go index 3b09478ece66..1a19f5b633a1 100644 --- a/x/distribution/client/rest/rest.go +++ b/x/distribution/client/rest/rest.go @@ -8,7 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/rest" - "github.com/cosmos/cosmos-sdk/x/auth/client/utils" + authclient "github.com/cosmos/cosmos-sdk/x/auth/client" "github.com/cosmos/cosmos-sdk/x/distribution/types" "github.com/cosmos/cosmos-sdk/x/gov" govrest "github.com/cosmos/cosmos-sdk/x/gov/client/rest" @@ -48,6 +48,6 @@ func postProposalHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return } - utils.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) + authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) } } diff --git a/x/distribution/client/rest/tx.go b/x/distribution/client/rest/tx.go index ace2c11a7aba..23713add7efd 100644 --- a/x/distribution/client/rest/tx.go +++ b/x/distribution/client/rest/tx.go @@ -6,7 +6,7 @@ import ( "github.com/gorilla/mux" "github.com/cosmos/cosmos-sdk/client/context" - "github.com/cosmos/cosmos-sdk/x/auth/client/utils" + authclient "github.com/cosmos/cosmos-sdk/x/auth/client" "github.com/cosmos/cosmos-sdk/x/distribution/client/common" "github.com/cosmos/cosmos-sdk/x/distribution/types" @@ -88,7 +88,7 @@ func withdrawDelegatorRewardsHandlerFn(cliCtx context.CLIContext, queryRoute str return } - utils.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, msgs) + authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, msgs) } } @@ -123,7 +123,7 @@ func withdrawDelegationRewardsHandlerFn(cliCtx context.CLIContext) http.HandlerF return } - utils.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) + authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) } } @@ -153,7 +153,7 @@ func setDelegatorWithdrawalAddrHandlerFn(cliCtx context.CLIContext) http.Handler return } - utils.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) + authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) } } @@ -184,7 +184,7 @@ func withdrawValidatorRewardsHandlerFn(cliCtx context.CLIContext) http.HandlerFu return } - utils.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, msgs) + authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, msgs) } } @@ -212,7 +212,7 @@ func fundCommunityPoolHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return } - utils.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) + authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) } } diff --git a/x/genutil/client/cli/gentx.go b/x/genutil/client/cli/gentx.go index 4624d1540a4e..18ef098ff670 100644 --- a/x/genutil/client/cli/gentx.go +++ b/x/genutil/client/cli/gentx.go @@ -27,7 +27,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/auth/client/utils" + authclient "github.com/cosmos/cosmos-sdk/x/auth/client" "github.com/cosmos/cosmos-sdk/x/genutil" "github.com/cosmos/cosmos-sdk/x/genutil/types" ) @@ -121,7 +121,7 @@ func GenTxCmd(ctx *server.Context, cdc *codec.Codec, mbm module.BasicManager, sm return errors.Wrap(err, "failed to validate account in genesis") } - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc)) + txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) // Set the generate-only flag here after the CLI context has @@ -139,14 +139,14 @@ func GenTxCmd(ctx *server.Context, cdc *codec.Codec, mbm module.BasicManager, sm if key.GetType() == keys.TypeOffline || key.GetType() == keys.TypeMulti { fmt.Println("Offline key passed in. Use `tx sign` command to sign:") - return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}) + return authclient.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}) } // write the unsigned transaction to the buffer w := bytes.NewBuffer([]byte{}) cliCtx = cliCtx.WithOutput(w) - if err = utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}); err != nil { + if err = authclient.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}); err != nil { return errors.Wrap(err, "failed to print unsigned std tx") } @@ -157,7 +157,7 @@ func GenTxCmd(ctx *server.Context, cdc *codec.Codec, mbm module.BasicManager, sm } // sign the transaction and write it to the output file - signedTx, err := utils.SignStdTx(txBldr, cliCtx, name, stdTx, false, true) + signedTx, err := authclient.SignStdTx(txBldr, cliCtx, name, stdTx, false, true) if err != nil { return errors.Wrap(err, "failed to sign std tx") } diff --git a/x/gov/client/cli/tx.go b/x/gov/client/cli/tx.go index 3946f9780c55..0af8eab61b2e 100644 --- a/x/gov/client/cli/tx.go +++ b/x/gov/client/cli/tx.go @@ -15,7 +15,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/auth/client/utils" + authclient "github.com/cosmos/cosmos-sdk/x/auth/client" govutils "github.com/cosmos/cosmos-sdk/x/gov/client/utils" "github.com/cosmos/cosmos-sdk/x/gov/types" ) @@ -107,7 +107,7 @@ $ %s tx gov submit-proposal --title="Test Proposal" --description="My awesome pr ), RunE: func(cmd *cobra.Command, args []string) error { inBuf := bufio.NewReader(cmd.InOrStdin()) - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc)) + txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) proposal, err := parseSubmitProposalFlags() @@ -127,7 +127,7 @@ $ %s tx gov submit-proposal --title="Test Proposal" --description="My awesome pr return err } - return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) }, } @@ -158,7 +158,7 @@ $ %s tx gov deposit 1 10stake --from mykey ), RunE: func(cmd *cobra.Command, args []string) error { inBuf := bufio.NewReader(cmd.InOrStdin()) - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc)) + txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) // validate that the proposal id is a uint @@ -182,7 +182,7 @@ $ %s tx gov deposit 1 10stake --from mykey return err } - return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) }, } } @@ -206,7 +206,7 @@ $ %s tx gov vote 1 yes --from mykey ), RunE: func(cmd *cobra.Command, args []string) error { inBuf := bufio.NewReader(cmd.InOrStdin()) - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc)) + txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) // Get voting address @@ -231,7 +231,7 @@ $ %s tx gov vote 1 yes --from mykey return err } - return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) }, } } diff --git a/x/gov/client/rest/tx.go b/x/gov/client/rest/tx.go index c705bddf4e2d..fb2bfa5c6420 100644 --- a/x/gov/client/rest/tx.go +++ b/x/gov/client/rest/tx.go @@ -9,7 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/rest" - "github.com/cosmos/cosmos-sdk/x/auth/client/utils" + authclient "github.com/cosmos/cosmos-sdk/x/auth/client" gcutils "github.com/cosmos/cosmos-sdk/x/gov/client/utils" "github.com/cosmos/cosmos-sdk/x/gov/types" ) @@ -46,7 +46,7 @@ func postProposalHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return } - utils.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) + authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) } } @@ -82,7 +82,7 @@ func depositHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return } - utils.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) + authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) } } @@ -124,6 +124,6 @@ func voteHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return } - utils.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) + authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) } } diff --git a/x/gov/client/utils/query.go b/x/gov/client/utils/query.go index d4be3c010f93..840f6df899e8 100644 --- a/x/gov/client/utils/query.go +++ b/x/gov/client/utils/query.go @@ -6,7 +6,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth/client/utils" + authclient "github.com/cosmos/cosmos-sdk/x/auth/client" "github.com/cosmos/cosmos-sdk/x/gov/types" ) @@ -45,7 +45,7 @@ func QueryDepositsByTxQuery(cliCtx context.CLIContext, params types.QueryProposa // NOTE: SearchTxs is used to facilitate the txs query which does not currently // support configurable pagination. - searchResult, err := utils.QueryTxsByEvents(cliCtx, events, defaultPage, defaultLimit) + searchResult, err := authclient.QueryTxsByEvents(cliCtx, events, defaultPage, defaultLimit) if err != nil { return nil, err } @@ -88,7 +88,7 @@ func QueryVotesByTxQuery(cliCtx context.CLIContext, params types.QueryProposalVo ) // query interrupted either if we collected enough votes or tx indexer run out of relevant txs for len(votes) < totalLimit { - searchResult, err := utils.QueryTxsByEvents(cliCtx, events, nextTxPage, defaultLimit) + searchResult, err := authclient.QueryTxsByEvents(cliCtx, events, nextTxPage, defaultLimit) if err != nil { return nil, err } @@ -132,7 +132,7 @@ func QueryVoteByTxQuery(cliCtx context.CLIContext, params types.QueryVoteParams) // NOTE: SearchTxs is used to facilitate the txs query which does not currently // support configurable pagination. - searchResult, err := utils.QueryTxsByEvents(cliCtx, events, defaultPage, defaultLimit) + searchResult, err := authclient.QueryTxsByEvents(cliCtx, events, defaultPage, defaultLimit) if err != nil { return nil, err } @@ -171,7 +171,7 @@ func QueryDepositByTxQuery(cliCtx context.CLIContext, params types.QueryDepositP // NOTE: SearchTxs is used to facilitate the txs query which does not currently // support configurable pagination. - searchResult, err := utils.QueryTxsByEvents(cliCtx, events, defaultPage, defaultLimit) + searchResult, err := authclient.QueryTxsByEvents(cliCtx, events, defaultPage, defaultLimit) if err != nil { return nil, err } @@ -210,7 +210,7 @@ func QueryProposerByTxQuery(cliCtx context.CLIContext, proposalID uint64) (Propo // NOTE: SearchTxs is used to facilitate the txs query which does not currently // support configurable pagination. - searchResult, err := utils.QueryTxsByEvents(cliCtx, events, defaultPage, defaultLimit) + searchResult, err := authclient.QueryTxsByEvents(cliCtx, events, defaultPage, defaultLimit) if err != nil { return Proposer{}, err } diff --git a/x/params/client/cli/tx.go b/x/params/client/cli/tx.go index 08dc1c985ee4..5b4fe2a9fa9c 100644 --- a/x/params/client/cli/tx.go +++ b/x/params/client/cli/tx.go @@ -12,7 +12,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/auth/client/utils" + authclient "github.com/cosmos/cosmos-sdk/x/auth/client" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" paramscutils "github.com/cosmos/cosmos-sdk/x/params/client/utils" "github.com/cosmos/cosmos-sdk/x/params/types" @@ -66,7 +66,7 @@ Where proposal.json contains: ), RunE: func(cmd *cobra.Command, args []string) error { inBuf := bufio.NewReader(cmd.InOrStdin()) - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc)) + txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) proposal, err := paramscutils.ParseParamChangeProposalJSON(cdc, args[0]) @@ -82,7 +82,7 @@ Where proposal.json contains: return err } - return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) }, } diff --git a/x/params/client/rest/rest.go b/x/params/client/rest/rest.go index 101dc49a4d7e..e7461d391423 100644 --- a/x/params/client/rest/rest.go +++ b/x/params/client/rest/rest.go @@ -6,7 +6,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/rest" - "github.com/cosmos/cosmos-sdk/x/auth/client/utils" + authclient "github.com/cosmos/cosmos-sdk/x/auth/client" govrest "github.com/cosmos/cosmos-sdk/x/gov/client/rest" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/cosmos/cosmos-sdk/x/params" @@ -42,6 +42,6 @@ func postProposalHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return } - utils.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) + authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) } } diff --git a/x/slashing/client/cli/tx.go b/x/slashing/client/cli/tx.go index 5aa262568d54..117e216a957a 100644 --- a/x/slashing/client/cli/tx.go +++ b/x/slashing/client/cli/tx.go @@ -11,7 +11,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/auth/client/utils" + authclient "github.com/cosmos/cosmos-sdk/x/auth/client" "github.com/cosmos/cosmos-sdk/x/slashing/internal/types" ) @@ -44,13 +44,13 @@ $ tx slashing unjail --from mykey `, RunE: func(cmd *cobra.Command, args []string) error { inBuf := bufio.NewReader(cmd.InOrStdin()) - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc)) + txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) valAddr := cliCtx.GetFromAddress() msg := types.NewMsgUnjail(sdk.ValAddress(valAddr)) - return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) }, } } diff --git a/x/slashing/client/rest/tx.go b/x/slashing/client/rest/tx.go index bd7188a1c006..1257b8e105a5 100644 --- a/x/slashing/client/rest/tx.go +++ b/x/slashing/client/rest/tx.go @@ -9,7 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/rest" - "github.com/cosmos/cosmos-sdk/x/auth/client/utils" + authclient "github.com/cosmos/cosmos-sdk/x/auth/client" "github.com/cosmos/cosmos-sdk/x/slashing/internal/types" ) @@ -65,6 +65,6 @@ func unjailRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return } - utils.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) + authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) } } diff --git a/x/staking/client/cli/tx.go b/x/staking/client/cli/tx.go index a9b8b526303a..3199ece93dc5 100644 --- a/x/staking/client/cli/tx.go +++ b/x/staking/client/cli/tx.go @@ -20,7 +20,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/auth/client/utils" + authclient "github.com/cosmos/cosmos-sdk/x/auth/client" "github.com/cosmos/cosmos-sdk/x/staking/types" ) @@ -52,7 +52,7 @@ func GetCmdCreateValidator(cdc *codec.Codec) *cobra.Command { Short: "create new validator initialized with a self-delegation to it", RunE: func(cmd *cobra.Command, args []string) error { inBuf := bufio.NewReader(cmd.InOrStdin()) - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc)) + txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) txBldr, msg, err := BuildCreateValidatorMsg(cliCtx, txBldr) @@ -60,7 +60,7 @@ func GetCmdCreateValidator(cdc *codec.Codec) *cobra.Command { return err } - return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) }, } @@ -128,7 +128,7 @@ func GetCmdEditValidator(cdc *codec.Codec) *cobra.Command { msg := types.NewMsgEditValidator(sdk.ValAddress(valAddr), description, newRate, newMinSelfDelegation) // build and sign the transaction, then broadcast to Tendermint - return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) }, } @@ -171,7 +171,7 @@ $ %s tx staking delegate cosmosvaloper1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm 10 } msg := types.NewMsgDelegate(delAddr, valAddr, amount) - return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) }, } } @@ -213,7 +213,7 @@ $ %s tx staking redelegate cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj } msg := types.NewMsgBeginRedelegate(delAddr, valSrcAddr, valDstAddr, amount) - return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) }, } } @@ -250,7 +250,7 @@ $ %s tx staking unbond cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj 100s } msg := types.NewMsgUndelegate(delAddr, valAddr, amount) - return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) }, } } diff --git a/x/staking/client/rest/tx.go b/x/staking/client/rest/tx.go index bd6016bed104..7838d95515cd 100644 --- a/x/staking/client/rest/tx.go +++ b/x/staking/client/rest/tx.go @@ -9,7 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/rest" - "github.com/cosmos/cosmos-sdk/x/auth/client/utils" + authclient "github.com/cosmos/cosmos-sdk/x/auth/client" "github.com/cosmos/cosmos-sdk/x/staking/types" ) @@ -85,7 +85,7 @@ func postDelegationsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return } - utils.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) + authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) } } @@ -119,7 +119,7 @@ func postRedelegationsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return } - utils.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) + authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) } } @@ -153,6 +153,6 @@ func postUnbondingDelegationsHandlerFn(cliCtx context.CLIContext) http.HandlerFu return } - utils.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) + authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) } } diff --git a/x/staking/client/rest/utils.go b/x/staking/client/rest/utils.go index 5d106823a97a..8b0ead70189a 100644 --- a/x/staking/client/rest/utils.go +++ b/x/staking/client/rest/utils.go @@ -9,7 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/rest" - "github.com/cosmos/cosmos-sdk/x/auth/client/utils" + authclient "github.com/cosmos/cosmos-sdk/x/auth/client" "github.com/cosmos/cosmos-sdk/x/staking/types" ) @@ -32,7 +32,7 @@ func queryTxs(cliCtx context.CLIContext, action string, delegatorAddr string) (* fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeySender, delegatorAddr), } - return utils.QueryTxsByEvents(cliCtx, events, page, limit) + return authclient.QueryTxsByEvents(cliCtx, events, page, limit) } func queryBonds(cliCtx context.CLIContext, endpoint string) http.HandlerFunc { diff --git a/x/upgrade/client/cli/tx.go b/x/upgrade/client/cli/tx.go index 26aa0848c269..a06347bc1def 100644 --- a/x/upgrade/client/cli/tx.go +++ b/x/upgrade/client/cli/tx.go @@ -5,6 +5,7 @@ import ( "fmt" "time" + authclient "github.com/cosmos/cosmos-sdk/x/auth/client" "github.com/cosmos/cosmos-sdk/x/gov/client/cli" "github.com/spf13/cobra" @@ -13,7 +14,6 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/auth/client/utils" "github.com/cosmos/cosmos-sdk/x/gov" upgrade "github.com/cosmos/cosmos-sdk/x/upgrade/internal/types" ) @@ -87,7 +87,7 @@ func GetCmdSubmitUpgradeProposal(cdc *codec.Codec) *cobra.Command { } inBuf := bufio.NewReader(cmd.InOrStdin()) - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc)) + txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) from := cliCtx.GetFromAddress() @@ -104,7 +104,7 @@ func GetCmdSubmitUpgradeProposal(cdc *codec.Codec) *cobra.Command { if err := msg.ValidateBasic(); err != nil { return err } - return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) }, } @@ -127,7 +127,7 @@ func GetCmdSubmitCancelUpgradeProposal(cdc *codec.Codec) *cobra.Command { Long: "Cancel a software upgrade along with an initial deposit.", RunE: func(cmd *cobra.Command, args []string) error { inBuf := bufio.NewReader(cmd.InOrStdin()) - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc)) + txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) from := cliCtx.GetFromAddress() @@ -158,7 +158,7 @@ func GetCmdSubmitCancelUpgradeProposal(cdc *codec.Codec) *cobra.Command { return err } - return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) }, } diff --git a/x/upgrade/client/rest/tx.go b/x/upgrade/client/rest/tx.go index acdec064328d..9354d9dd05a0 100644 --- a/x/upgrade/client/rest/tx.go +++ b/x/upgrade/client/rest/tx.go @@ -6,12 +6,12 @@ import ( "github.com/gorilla/mux" + authclient "github.com/cosmos/cosmos-sdk/x/auth/client" govrest "github.com/cosmos/cosmos-sdk/x/gov/client/rest" "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/rest" - "github.com/cosmos/cosmos-sdk/x/auth/client/utils" "github.com/cosmos/cosmos-sdk/x/gov" "github.com/cosmos/cosmos-sdk/x/upgrade/internal/types" ) @@ -84,7 +84,7 @@ func postPlanHandler(cliCtx context.CLIContext) http.HandlerFunc { return } - utils.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) + authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) } } @@ -114,6 +114,6 @@ func cancelPlanHandler(cliCtx context.CLIContext) http.HandlerFunc { return } - utils.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) + authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) } } From 1b6897ad1bdd7c466836375122db1e9b048afd7d Mon Sep 17 00:00:00 2001 From: Marko Date: Fri, 24 Jan 2020 18:32:15 +0100 Subject: [PATCH 097/529] Merge PR #5568: godoc: change nft to supply in godoc --- x/supply/module.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/supply/module.go b/x/supply/module.go index f9e45322a99c..05ae901ebf72 100644 --- a/x/supply/module.go +++ b/x/supply/module.go @@ -165,7 +165,7 @@ func (AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { sdr[StoreKey] = simulation.DecodeStore } -// WeightedOperations doesn't return any operation for the nft module. +// WeightedOperations doesn't return any operation for the supply module. func (AppModule) WeightedOperations(_ module.SimulationState) []sim.WeightedOperation { return nil } From d5d29ef67a96f714c47729385fda9573b7016dbd Mon Sep 17 00:00:00 2001 From: Miguel Dingli Date: Mon, 27 Jan 2020 15:46:55 +0100 Subject: [PATCH 098/529] Merge PR #5557: Added amount event to InputOutputCoins for MsgMultSend --- CHANGELOG.md | 4 ++ x/bank/internal/keeper/keeper.go | 1 + x/bank/internal/keeper/keeper_test.go | 88 +++++++++++++++++++++++++++ x/bank/spec/04_events.md | 1 + 4 files changed, 94 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f4c258b72e6b..5b1a9c20bcf4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,10 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (modules) [\#5555](https://github.com/cosmos/cosmos-sdk/pull/5555) Move x/auth/client/utils/ types and functions to x/auth/client/. +### Bug Fixes + +* (x/bank) [\#5531](https://github.com/cosmos/cosmos-sdk/issues/5531) Added missing amount event to MsgMultiSend, emitted for each output. + ## [v0.38.0] - 2020-01-23 ### State Machine Breaking diff --git a/x/bank/internal/keeper/keeper.go b/x/bank/internal/keeper/keeper.go index 64e539c44ce2..25e47b073932 100644 --- a/x/bank/internal/keeper/keeper.go +++ b/x/bank/internal/keeper/keeper.go @@ -208,6 +208,7 @@ func (keeper BaseSendKeeper) InputOutputCoins(ctx sdk.Context, inputs []types.In sdk.NewEvent( types.EventTypeTransfer, sdk.NewAttribute(types.AttributeKeyRecipient, out.Address.String()), + sdk.NewAttribute(sdk.AttributeKeyAmount, out.Coins.String()), ), ) } diff --git a/x/bank/internal/keeper/keeper_test.go b/x/bank/internal/keeper/keeper_test.go index 92da5be72f6d..6b6f3cd4048f 100644 --- a/x/bank/internal/keeper/keeper_test.go +++ b/x/bank/internal/keeper/keeper_test.go @@ -194,6 +194,94 @@ func TestMsgSendEvents(t *testing.T) { require.Equal(t, event2, events[3]) } +func TestMsgMultiSendEvents(t *testing.T) { + app, ctx := createTestApp(false) + + app.BankKeeper.SetSendEnabled(ctx, true) + + addr := sdk.AccAddress([]byte("addr1")) + addr2 := sdk.AccAddress([]byte("addr2")) + addr3 := sdk.AccAddress([]byte("addr3")) + addr4 := sdk.AccAddress([]byte("addr4")) + acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr) + acc2 := app.AccountKeeper.NewAccountWithAddress(ctx, addr2) + + app.AccountKeeper.SetAccount(ctx, acc) + app.AccountKeeper.SetAccount(ctx, acc2) + newCoins := sdk.NewCoins(sdk.NewInt64Coin("foocoin", 50)) + newCoins2 := sdk.NewCoins(sdk.NewInt64Coin("barcoin", 100)) + inputs := []types.Input{ + {Address: addr, Coins: newCoins}, + {Address: addr2, Coins: newCoins2}, + } + outputs := []types.Output{ + {Address: addr3, Coins: newCoins}, + {Address: addr4, Coins: newCoins2}, + } + err := app.BankKeeper.InputOutputCoins(ctx, inputs, outputs) + require.Error(t, err) + events := ctx.EventManager().Events() + require.Equal(t, 0, len(events)) + + // Set addr's coins but not addr2's coins + app.BankKeeper.SetCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 50))) + + err = app.BankKeeper.InputOutputCoins(ctx, inputs, outputs) + require.Error(t, err) + events = ctx.EventManager().Events() + require.Equal(t, 1, len(events)) + event1 := sdk.Event{ + Type: sdk.EventTypeMessage, + Attributes: []tmkv.Pair{}, + } + event1.Attributes = append( + event1.Attributes, + tmkv.Pair{Key: []byte(types.AttributeKeySender), Value: []byte(addr.String())}) + require.Equal(t, event1, events[0]) + + // Set addr's coins and addr2's coins + app.BankKeeper.SetCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 50))) + newCoins = sdk.NewCoins(sdk.NewInt64Coin("foocoin", 50)) + app.BankKeeper.SetCoins(ctx, addr2, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 100))) + newCoins2 = sdk.NewCoins(sdk.NewInt64Coin("barcoin", 100)) + + err = app.BankKeeper.InputOutputCoins(ctx, inputs, outputs) + require.NoError(t, err) + events = ctx.EventManager().Events() + require.Equal(t, 5, len(events)) + event2 := sdk.Event{ + Type: sdk.EventTypeMessage, + Attributes: []tmkv.Pair{}, + } + event2.Attributes = append( + event2.Attributes, + tmkv.Pair{Key: []byte(types.AttributeKeySender), Value: []byte(addr2.String())}) + event3 := sdk.Event{ + Type: types.EventTypeTransfer, + Attributes: []tmkv.Pair{}, + } + event3.Attributes = append( + event3.Attributes, + tmkv.Pair{Key: []byte(types.AttributeKeyRecipient), Value: []byte(addr3.String())}) + event3.Attributes = append( + event3.Attributes, + tmkv.Pair{Key: []byte(sdk.AttributeKeyAmount), Value: []byte(newCoins.String())}) + event4 := sdk.Event{ + Type: types.EventTypeTransfer, + Attributes: []tmkv.Pair{}, + } + event4.Attributes = append( + event4.Attributes, + tmkv.Pair{Key: []byte(types.AttributeKeyRecipient), Value: []byte(addr4.String())}) + event4.Attributes = append( + event4.Attributes, + tmkv.Pair{Key: []byte(sdk.AttributeKeyAmount), Value: []byte(newCoins2.String())}) + require.Equal(t, event1, events[1]) + require.Equal(t, event2, events[2]) + require.Equal(t, event3, events[3]) + require.Equal(t, event4, events[4]) +} + func TestViewKeeper(t *testing.T) { app, ctx := createTestApp(false) diff --git a/x/bank/spec/04_events.md b/x/bank/spec/04_events.md index 481ee9f0d2c5..1f97e7ab9b74 100644 --- a/x/bank/spec/04_events.md +++ b/x/bank/spec/04_events.md @@ -23,6 +23,7 @@ The bank module emits the following events: | Type | Attribute Key | Attribute Value | |----------|---------------|--------------------| | transfer | recipient | {recipientAddress} | +| transfer | amount | {amount} | | message | module | bank | | message | action | multisend | | message | sender | {senderAddress} | From deea89e52c0f162f6566a2cc2ede07e623a921cb Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Wed, 29 Jan 2020 10:48:53 +0100 Subject: [PATCH 099/529] Add convenience functions {,Must}Bech32ifyAddressBytes (#5581) --- CHANGELOG.md | 4 +++ types/address.go | 24 ++++++++++++++++ types/address_test.go | 65 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b1a9c20bcf4..dac8e9486a10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,10 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (x/bank) [\#5531](https://github.com/cosmos/cosmos-sdk/issues/5531) Added missing amount event to MsgMultiSend, emitted for each output. +### Improvements + +* (types) [\#5581](https://github.com/cosmos/cosmos-sdk/pull/5581) Add convenience functions {,Must}Bech32ifyAddressBytes. + ## [v0.38.0] - 2020-01-23 ### State Machine Breaking diff --git a/types/address.go b/types/address.go index dce02ec9c07a..839af224d01f 100644 --- a/types/address.go +++ b/types/address.go @@ -557,6 +557,30 @@ func (ca ConsAddress) String() string { return bech32Addr } +// Bech32ifyAddressBytes returns a bech32 representation of address bytes. +// Returns an empty sting if the byte slice is 0-length. Returns an error if the bech32 conversion +// fails or the prefix is empty. +func Bech32ifyAddressBytes(prefix string, bs []byte) (string, error) { + if len(bs) == 0 { + return "", nil + } + if len(prefix) == 0 { + return "", errors.New("prefix cannot be empty") + } + return bech32.ConvertAndEncode(prefix, bs) +} + +// MustBech32ifyAddressBytes returns a bech32 representation of address bytes. +// Returns an empty sting if the byte slice is 0-length. It panics if the bech32 conversion +// fails or the prefix is empty. +func MustBech32ifyAddressBytes(prefix string, bs []byte) string { + s, err := Bech32ifyAddressBytes(prefix, bs) + if err != nil { + panic(err) + } + return s +} + // Format implements the fmt.Formatter interface. // nolint: errcheck func (ca ConsAddress) Format(s fmt.State, verb rune) { diff --git a/types/address_test.go b/types/address_test.go index 7326ab784293..09e5bf93c463 100644 --- a/types/address_test.go +++ b/types/address_test.go @@ -345,3 +345,68 @@ func TestCustomAddressVerifier(t *testing.T) { _, err = types.ConsAddressFromBech32(consBech) require.Nil(t, err) } + +func TestBech32ifyAddressBytes(t *testing.T) { + addr10byte := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} + addr20byte := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19} + type args struct { + prefix string + bs []byte + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + {"empty address", args{"prefixA", []byte{}}, "", false}, + {"empty prefix", args{"", addr20byte}, "", true}, + {"10-byte address", args{"prefixA", addr10byte}, "prefixA1qqqsyqcyq5rqwzqfwvmuzx", false}, + {"10-byte address", args{"prefixB", addr10byte}, "prefixB1qqqsyqcyq5rqwzqf4xftmx", false}, + {"20-byte address", args{"prefixA", addr20byte}, "prefixA1qqqsyqcyq5rqwzqfpg9scrgwpugpzysn6j4npq", false}, + {"20-byte address", args{"prefixB", addr20byte}, "prefixB1qqqsyqcyq5rqwzqfpg9scrgwpugpzysn8e9wka", false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt := tt + got, err := types.Bech32ifyAddressBytes(tt.args.prefix, tt.args.bs) + if (err != nil) != tt.wantErr { + t.Errorf("Bech32ifyBytes() error = %v, wantErr %v", err, tt.wantErr) + return + } + require.Equal(t, tt.want, got) + }) + } +} + +func TestMustBech32ifyAddressBytes(t *testing.T) { + addr10byte := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} + addr20byte := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19} + type args struct { + prefix string + bs []byte + } + tests := []struct { + name string + args args + want string + wantPanic bool + }{ + {"empty address", args{"prefixA", []byte{}}, "", false}, + {"empty prefix", args{"", addr20byte}, "", true}, + {"10-byte address", args{"prefixA", addr10byte}, "prefixA1qqqsyqcyq5rqwzqfwvmuzx", false}, + {"10-byte address", args{"prefixB", addr10byte}, "prefixB1qqqsyqcyq5rqwzqf4xftmx", false}, + {"20-byte address", args{"prefixA", addr20byte}, "prefixA1qqqsyqcyq5rqwzqfpg9scrgwpugpzysn6j4npq", false}, + {"20-byte address", args{"prefixB", addr20byte}, "prefixB1qqqsyqcyq5rqwzqfpg9scrgwpugpzysn8e9wka", false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt := tt + if tt.wantPanic { + require.Panics(t, func() { types.MustBech32ifyAddressBytes(tt.args.prefix, tt.args.bs) }) + return + } + require.Equal(t, tt.want, types.MustBech32ifyAddressBytes(tt.args.prefix, tt.args.bs)) + }) + } +} From ec35cf2d91b35608a0db064df364fdd3bb45efe9 Mon Sep 17 00:00:00 2001 From: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Date: Wed, 29 Jan 2020 14:35:49 +0100 Subject: [PATCH 100/529] Merge PR #5584: Staking additions for IBC --- CHANGELOG.md | 1 + x/staking/types/historical_info.go | 6 +++--- x/staking/types/validator.go | 14 ++++++++++++++ x/staking/types/validator_test.go | 16 ++++++++++++++++ 4 files changed, 34 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dac8e9486a10..a0bbca18522d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Improvements * (types) [\#5581](https://github.com/cosmos/cosmos-sdk/pull/5581) Add convenience functions {,Must}Bech32ifyAddressBytes. +* (staking) [\#5584](https://github.com/cosmos/cosmos-sdk/pull/5584) Add util function `ToTmValidator` that converts a `staking.Validator` type to `*tmtypes.Validator`. ## [v0.38.0] - 2020-01-23 diff --git a/x/staking/types/historical_info.go b/x/staking/types/historical_info.go index 78db1e7dd4a9..1c08caebcde6 100644 --- a/x/staking/types/historical_info.go +++ b/x/staking/types/historical_info.go @@ -12,13 +12,13 @@ import ( // HistoricalInfo contains the historical information that gets stored at each height type HistoricalInfo struct { Header abci.Header `json:"header" yaml:"header"` - ValSet []Validator `json:"valset" yaml:"valset"` + ValSet Validators `json:"valset" yaml:"valset"` } // NewHistoricalInfo will create a historical information struct from header and valset // it will first sort valset before inclusion into historical info -func NewHistoricalInfo(header abci.Header, valSet []Validator) HistoricalInfo { - sort.Sort(Validators(valSet)) +func NewHistoricalInfo(header abci.Header, valSet Validators) HistoricalInfo { + sort.Sort(valSet) return HistoricalInfo{ Header: header, ValSet: valSet, diff --git a/x/staking/types/validator.go b/x/staking/types/validator.go index d64e0ce3e751..855ed988d290 100644 --- a/x/staking/types/validator.go +++ b/x/staking/types/validator.go @@ -104,6 +104,15 @@ func (v Validators) ToSDKValidators() (validators []exported.ValidatorI) { return validators } +// ToTmValidators casts all validators to the corresponding tendermint type. +func (v Validators) ToTmValidators() []*tmtypes.Validator { + validators := make([]*tmtypes.Validator, len(v)) + for i, val := range v { + validators[i] = val.ToTmValidator() + } + return validators +} + // Sort Validators sorts validator array in ascending operator address order func (v Validators) Sort() { sort.Sort(v) @@ -370,6 +379,11 @@ func (v Validator) ABCIValidatorUpdateZero() abci.ValidatorUpdate { } } +// ToTmValidator casts an SDK validator to a tendermint type Validator. +func (v Validator) ToTmValidator() *tmtypes.Validator { + return tmtypes.NewValidator(v.ConsPubKey, v.ConsensusPower()) +} + // SetInitialCommission attempts to set a validator's initial commission. An // error is returned if the commission is invalid. func (v Validator) SetInitialCommission(commission Commission) (Validator, error) { diff --git a/x/staking/types/validator_test.go b/x/staking/types/validator_test.go index e6a7ccbe961a..b8a572444e0c 100644 --- a/x/staking/types/validator_test.go +++ b/x/staking/types/validator_test.go @@ -335,3 +335,19 @@ func TestValidatorsSortDeterminism(t *testing.T) { require.True(t, reflect.DeepEqual(sortedVals, vals), "Validator sort returned different slices") } } + +func TestValidatorToTm(t *testing.T) { + vals := make(Validators, 10) + expected := make([]*tmtypes.Validator, 10) + + for i := range vals { + pk := ed25519.GenPrivKey().PubKey() + val := NewValidator(sdk.ValAddress(pk.Address()), pk, Description{}) + val.Status = sdk.Bonded + val.Tokens = sdk.NewInt(rand.Int63()) + vals[i] = val + expected[i] = tmtypes.NewValidator(pk, val.ConsensusPower()) + } + + require.Equal(t, expected, vals.ToTmValidators()) +} From ca952bc9c64f1501175de834e327b904db6827c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20Mah=C3=A9?= Date: Wed, 29 Jan 2020 20:43:48 +0700 Subject: [PATCH 101/529] Merge PR #5583: Add to the docs of events and handler to set a new EventManager to the Context --- docs/building-modules/handler.md | 4 +++- docs/core/events.md | 8 ++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/building-modules/handler.md b/docs/building-modules/handler.md index 37b46511a09a..1bb9c9b48a37 100644 --- a/docs/building-modules/handler.md +++ b/docs/building-modules/handler.md @@ -34,6 +34,7 @@ which looks like the following: ```go func NewHandler(keeper Keeper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { + ctx = ctx.WithEventManager(sdk.NewEventManager()) switch msg := msg.(type) { case MsgType1: return handleMsgType1(ctx, keeper, msg) @@ -48,7 +49,8 @@ func NewHandler(keeper Keeper) sdk.Handler { } ``` -This simple switch returns a `handler` function specific to the type of the received `message`. These `handler` functions are the ones that actually process `message`s, and usually follow the following 2 steps: +First, the `handler` function sets a new `EventManager` to the context to isolate events per `msg`. +Then, this simple switch returns a `handler` function specific to the type of the received `message`. These `handler` functions are the ones that actually process `message`s, and usually follow the following 2 steps: - First, they perform *stateful* checks to make sure the `message` is valid. At this stage, the `message`'s `ValidateBasic()` method has already been called, meaning *stateless* checks on the message (like making sure parameters are correctly formatted) have already been performed. Checks performed in the `handler` can be more expensive and require access to the state. For example, a `handler` for a `transfer` message might check that the sending account has enough funds to actually perform the transfer. To access the state, the `handler` needs to call the [`keeper`'s](./keeper.md) getter functions. - Then, if the checks are successfull, the `handler` calls the [`keeper`'s](./keeper.md) setter functions to actually perform the state transition. diff --git a/docs/core/events.md b/docs/core/events.md index aeb0efa1dea8..359e2b94a40e 100644 --- a/docs/core/events.md +++ b/docs/core/events.md @@ -61,6 +61,14 @@ ctx.EventManager().EmitEvent( ) ``` +Module's `handler` function should also set a new `EventManager` to the `context` to isolate emitted events per `message`: +```go +func NewHandler(keeper Keeper) sdk.Handler { + return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { + ctx = ctx.WithEventManager(sdk.NewEventManager()) + switch msg := msg.(type) { +``` + See the [`Handler`](../building-modules/handler.md) concept doc for a more detailed view on how to typically implement `Events` and use the `EventManager` in modules. From 677f27f589919e565bdbaa5f8b2b012ad5b38790 Mon Sep 17 00:00:00 2001 From: Marko Date: Wed, 29 Jan 2020 16:10:59 +0100 Subject: [PATCH 102/529] Merge PR #5587: docs: remove yarn --- docs/yarn.lock | 7290 ------------------------------------------------ 1 file changed, 7290 deletions(-) delete mode 100644 docs/yarn.lock diff --git a/docs/yarn.lock b/docs/yarn.lock deleted file mode 100644 index 977ae12f6248..000000000000 --- a/docs/yarn.lock +++ /dev/null @@ -1,7290 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.5.5": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.5.5.tgz#bc0782f6d69f7b7d49531219699b988f669a8f9d" - integrity sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw== - dependencies: - "@babel/highlight" "^7.0.0" - -"@babel/core@^7.0.0": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.5.5.tgz#17b2686ef0d6bc58f963dddd68ab669755582c30" - integrity sha512-i4qoSr2KTtce0DmkuuQBV4AuQgGPUcPXMr9L5MyYAtk06z068lQ10a4O009fe5OB/DfNV+h+qqT7ddNV8UnRjg== - dependencies: - "@babel/code-frame" "^7.5.5" - "@babel/generator" "^7.5.5" - "@babel/helpers" "^7.5.5" - "@babel/parser" "^7.5.5" - "@babel/template" "^7.4.4" - "@babel/traverse" "^7.5.5" - "@babel/types" "^7.5.5" - convert-source-map "^1.1.0" - debug "^4.1.0" - json5 "^2.1.0" - lodash "^4.17.13" - resolve "^1.3.2" - semver "^5.4.1" - source-map "^0.5.0" - -"@babel/generator@^7.5.5": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.5.5.tgz#873a7f936a3c89491b43536d12245b626664e3cf" - integrity sha512-ETI/4vyTSxTzGnU2c49XHv2zhExkv9JHLTwDAFz85kmcwuShvYG2H08FwgIguQf4JC75CBnXAUM5PqeF4fj0nQ== - dependencies: - "@babel/types" "^7.5.5" - jsesc "^2.5.1" - lodash "^4.17.13" - source-map "^0.5.0" - trim-right "^1.0.1" - -"@babel/helper-annotate-as-pure@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz#323d39dd0b50e10c7c06ca7d7638e6864d8c5c32" - integrity sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q== - dependencies: - "@babel/types" "^7.0.0" - -"@babel/helper-builder-binary-assignment-operator-visitor@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz#6b69628dfe4087798e0c4ed98e3d4a6b2fbd2f5f" - integrity sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w== - dependencies: - "@babel/helper-explode-assignable-expression" "^7.1.0" - "@babel/types" "^7.0.0" - -"@babel/helper-call-delegate@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.4.4.tgz#87c1f8ca19ad552a736a7a27b1c1fcf8b1ff1f43" - integrity sha512-l79boDFJ8S1c5hvQvG+rc+wHw6IuH7YldmRKsYtpbawsxURu/paVy57FZMomGK22/JckepaikOkY0MoAmdyOlQ== - dependencies: - "@babel/helper-hoist-variables" "^7.4.4" - "@babel/traverse" "^7.4.4" - "@babel/types" "^7.4.4" - -"@babel/helper-create-class-features-plugin@^7.4.4", "@babel/helper-create-class-features-plugin@^7.5.5": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.5.5.tgz#401f302c8ddbc0edd36f7c6b2887d8fa1122e5a4" - integrity sha512-ZsxkyYiRA7Bg+ZTRpPvB6AbOFKTFFK4LrvTet8lInm0V468MWCaSYJE+I7v2z2r8KNLtYiV+K5kTCnR7dvyZjg== - dependencies: - "@babel/helper-function-name" "^7.1.0" - "@babel/helper-member-expression-to-functions" "^7.5.5" - "@babel/helper-optimise-call-expression" "^7.0.0" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-replace-supers" "^7.5.5" - "@babel/helper-split-export-declaration" "^7.4.4" - -"@babel/helper-define-map@^7.5.5": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.5.5.tgz#3dec32c2046f37e09b28c93eb0b103fd2a25d369" - integrity sha512-fTfxx7i0B5NJqvUOBBGREnrqbTxRh7zinBANpZXAVDlsZxYdclDp467G1sQ8VZYMnAURY3RpBUAgOYT9GfzHBg== - dependencies: - "@babel/helper-function-name" "^7.1.0" - "@babel/types" "^7.5.5" - lodash "^4.17.13" - -"@babel/helper-explode-assignable-expression@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz#537fa13f6f1674df745b0c00ec8fe4e99681c8f6" - integrity sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA== - dependencies: - "@babel/traverse" "^7.1.0" - "@babel/types" "^7.0.0" - -"@babel/helper-function-name@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz#a0ceb01685f73355d4360c1247f582bfafc8ff53" - integrity sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw== - dependencies: - "@babel/helper-get-function-arity" "^7.0.0" - "@babel/template" "^7.1.0" - "@babel/types" "^7.0.0" - -"@babel/helper-get-function-arity@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz#83572d4320e2a4657263734113c42868b64e49c3" - integrity sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ== - dependencies: - "@babel/types" "^7.0.0" - -"@babel/helper-hoist-variables@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.4.4.tgz#0298b5f25c8c09c53102d52ac4a98f773eb2850a" - integrity sha512-VYk2/H/BnYbZDDg39hr3t2kKyifAm1W6zHRfhx8jGjIHpQEBv9dry7oQ2f3+J703TLu69nYdxsovl0XYfcnK4w== - dependencies: - "@babel/types" "^7.4.4" - -"@babel/helper-member-expression-to-functions@^7.5.5": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.5.5.tgz#1fb5b8ec4453a93c439ee9fe3aeea4a84b76b590" - integrity sha512-5qZ3D1uMclSNqYcXqiHoA0meVdv+xUEex9em2fqMnrk/scphGlGgg66zjMrPJESPwrFJ6sbfFQYUSa0Mz7FabA== - dependencies: - "@babel/types" "^7.5.5" - -"@babel/helper-module-imports@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz#96081b7111e486da4d2cd971ad1a4fe216cc2e3d" - integrity sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A== - dependencies: - "@babel/types" "^7.0.0" - -"@babel/helper-module-transforms@^7.1.0", "@babel/helper-module-transforms@^7.4.4": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.5.5.tgz#f84ff8a09038dcbca1fd4355661a500937165b4a" - integrity sha512-jBeCvETKuJqeiaCdyaheF40aXnnU1+wkSiUs/IQg3tB85up1LyL8x77ClY8qJpuRJUcXQo+ZtdNESmZl4j56Pw== - dependencies: - "@babel/helper-module-imports" "^7.0.0" - "@babel/helper-simple-access" "^7.1.0" - "@babel/helper-split-export-declaration" "^7.4.4" - "@babel/template" "^7.4.4" - "@babel/types" "^7.5.5" - lodash "^4.17.13" - -"@babel/helper-optimise-call-expression@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz#a2920c5702b073c15de51106200aa8cad20497d5" - integrity sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g== - dependencies: - "@babel/types" "^7.0.0" - -"@babel/helper-plugin-utils@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz#bbb3fbee98661c569034237cc03967ba99b4f250" - integrity sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA== - -"@babel/helper-regex@^7.0.0", "@babel/helper-regex@^7.4.4": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.5.5.tgz#0aa6824f7100a2e0e89c1527c23936c152cab351" - integrity sha512-CkCYQLkfkiugbRDO8eZn6lRuR8kzZoGXCg3149iTk5se7g6qykSpy3+hELSwquhu+TgHn8nkLiBwHvNX8Hofcw== - dependencies: - lodash "^4.17.13" - -"@babel/helper-remap-async-to-generator@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz#361d80821b6f38da75bd3f0785ece20a88c5fe7f" - integrity sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg== - dependencies: - "@babel/helper-annotate-as-pure" "^7.0.0" - "@babel/helper-wrap-function" "^7.1.0" - "@babel/template" "^7.1.0" - "@babel/traverse" "^7.1.0" - "@babel/types" "^7.0.0" - -"@babel/helper-replace-supers@^7.5.5": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.5.5.tgz#f84ce43df031222d2bad068d2626cb5799c34bc2" - integrity sha512-XvRFWrNnlsow2u7jXDuH4jDDctkxbS7gXssrP4q2nUD606ukXHRvydj346wmNg+zAgpFx4MWf4+usfC93bElJg== - dependencies: - "@babel/helper-member-expression-to-functions" "^7.5.5" - "@babel/helper-optimise-call-expression" "^7.0.0" - "@babel/traverse" "^7.5.5" - "@babel/types" "^7.5.5" - -"@babel/helper-simple-access@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz#65eeb954c8c245beaa4e859da6188f39d71e585c" - integrity sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w== - dependencies: - "@babel/template" "^7.1.0" - "@babel/types" "^7.0.0" - -"@babel/helper-split-export-declaration@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz#ff94894a340be78f53f06af038b205c49d993677" - integrity sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q== - dependencies: - "@babel/types" "^7.4.4" - -"@babel/helper-wrap-function@^7.1.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz#c4e0012445769e2815b55296ead43a958549f6fa" - integrity sha512-o9fP1BZLLSrYlxYEYyl2aS+Flun5gtjTIG8iln+XuEzQTs0PLagAGSXUcqruJwD5fM48jzIEggCKpIfWTcR7pQ== - dependencies: - "@babel/helper-function-name" "^7.1.0" - "@babel/template" "^7.1.0" - "@babel/traverse" "^7.1.0" - "@babel/types" "^7.2.0" - -"@babel/helpers@^7.5.5": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.5.5.tgz#63908d2a73942229d1e6685bc2a0e730dde3b75e" - integrity sha512-nRq2BUhxZFnfEn/ciJuhklHvFOqjJUD5wpx+1bxUF2axL9C+v4DE/dmp5sT2dKnpOs4orZWzpAZqlCy8QqE/7g== - dependencies: - "@babel/template" "^7.4.4" - "@babel/traverse" "^7.5.5" - "@babel/types" "^7.5.5" - -"@babel/highlight@^7.0.0": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.5.0.tgz#56d11312bd9248fa619591d02472be6e8cb32540" - integrity sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ== - dependencies: - chalk "^2.0.0" - esutils "^2.0.2" - js-tokens "^4.0.0" - -"@babel/parser@^7.4.4", "@babel/parser@^7.5.5": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.5.5.tgz#02f077ac8817d3df4a832ef59de67565e71cca4b" - integrity sha512-E5BN68cqR7dhKan1SfqgPGhQ178bkVKpXTPEXnFJBrEt8/DKRZlybmy+IgYLTeN7tp1R5Ccmbm2rBk17sHYU3g== - -"@babel/plugin-proposal-async-generator-functions@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz#b289b306669dce4ad20b0252889a15768c9d417e" - integrity sha512-+Dfo/SCQqrwx48ptLVGLdE39YtWRuKc/Y9I5Fy0P1DDBB9lsAHpjcEJQt+4IifuSOSTLBKJObJqMvaO1pIE8LQ== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-remap-async-to-generator" "^7.1.0" - "@babel/plugin-syntax-async-generators" "^7.2.0" - -"@babel/plugin-proposal-class-properties@^7.0.0": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.5.5.tgz#a974cfae1e37c3110e71f3c6a2e48b8e71958cd4" - integrity sha512-AF79FsnWFxjlaosgdi421vmYG6/jg79bVD0dpD44QdgobzHKuLZ6S3vl8la9qIeSwGi8i1fS0O1mfuDAAdo1/A== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.5.5" - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-proposal-decorators@^7.1.0": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.4.4.tgz#de9b2a1a8ab0196f378e2a82f10b6e2a36f21cc0" - integrity sha512-z7MpQz3XC/iQJWXH9y+MaWcLPNSMY9RQSthrLzak8R8hCj0fuyNk+Dzi9kfNe/JxxlWQ2g7wkABbgWjW36MTcw== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.4.4" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-decorators" "^7.2.0" - -"@babel/plugin-proposal-json-strings@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.2.0.tgz#568ecc446c6148ae6b267f02551130891e29f317" - integrity sha512-MAFV1CA/YVmYwZG0fBQyXhmj0BHCB5egZHCKWIFVv/XCxAeVGIHfos3SwDck4LvCllENIAg7xMKOG5kH0dzyUg== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-json-strings" "^7.2.0" - -"@babel/plugin-proposal-object-rest-spread@^7.3.4": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.5.5.tgz#61939744f71ba76a3ae46b5eea18a54c16d22e58" - integrity sha512-F2DxJJSQ7f64FyTVl5cw/9MWn6naXGdk3Q3UhDbFEEHv+EilCPoeRD3Zh/Utx1CJz4uyKlQ4uH+bJPbEhMV7Zw== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-object-rest-spread" "^7.2.0" - -"@babel/plugin-proposal-optional-catch-binding@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.2.0.tgz#135d81edb68a081e55e56ec48541ece8065c38f5" - integrity sha512-mgYj3jCcxug6KUcX4OBoOJz3CMrwRfQELPQ5560F70YQUBZB7uac9fqaWamKR1iWUzGiK2t0ygzjTScZnVz75g== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-optional-catch-binding" "^7.2.0" - -"@babel/plugin-proposal-unicode-property-regex@^7.2.0": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.4.4.tgz#501ffd9826c0b91da22690720722ac7cb1ca9c78" - integrity sha512-j1NwnOqMG9mFUOH58JTFsA/+ZYzQLUZ/drqWUqxCYLGeu2JFZL8YrNC9hBxKmWtAuOCHPcRpgv7fhap09Fb4kA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-regex" "^7.4.4" - regexpu-core "^4.5.4" - -"@babel/plugin-syntax-async-generators@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.2.0.tgz#69e1f0db34c6f5a0cf7e2b3323bf159a76c8cb7f" - integrity sha512-1ZrIRBv2t0GSlcwVoQ6VgSLpLgiN/FVQUzt9znxo7v2Ov4jJrs8RY8tv0wvDmFN3qIdMKWrmMMW6yZ0G19MfGg== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-syntax-decorators@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.2.0.tgz#c50b1b957dcc69e4b1127b65e1c33eef61570c1b" - integrity sha512-38QdqVoXdHUQfTpZo3rQwqQdWtCn5tMv4uV6r2RMfTqNBuv4ZBhz79SfaQWKTVmxHjeFv/DnXVC/+agHCklYWA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-syntax-dynamic-import@^7.0.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.2.0.tgz#69c159ffaf4998122161ad8ebc5e6d1f55df8612" - integrity sha512-mVxuJ0YroI/h/tbFTPGZR8cv6ai+STMKNBq0f8hFxsxWjl94qqhsb+wXbpNMDPU3cfR1TIsVFzU3nXyZMqyK4w== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-syntax-json-strings@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.2.0.tgz#72bd13f6ffe1d25938129d2a186b11fd62951470" - integrity sha512-5UGYnMSLRE1dqqZwug+1LISpA403HzlSfsg6P9VXU6TBjcSHeNlw4DxDx7LgpF+iKZoOG/+uzqoRHTdcUpiZNg== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-syntax-jsx@^7.0.0", "@babel/plugin-syntax-jsx@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.2.0.tgz#0b85a3b4bc7cdf4cc4b8bf236335b907ca22e7c7" - integrity sha512-VyN4QANJkRW6lDBmENzRszvZf3/4AXaj9YR7GwrWeeN9tEBPuXbmDYVU9bYBN0D70zCWVwUy0HWq2553VCb6Hw== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-syntax-object-rest-spread@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz#3b7a3e733510c57e820b9142a6579ac8b0dfad2e" - integrity sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-syntax-optional-catch-binding@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.2.0.tgz#a94013d6eda8908dfe6a477e7f9eda85656ecf5c" - integrity sha512-bDe4xKNhb0LI7IvZHiA13kff0KEfaGX/Hv4lMA9+7TEc63hMNvfKo6ZFpXhKuEp+II/q35Gc4NoMeDZyaUbj9w== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-arrow-functions@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.2.0.tgz#9aeafbe4d6ffc6563bf8f8372091628f00779550" - integrity sha512-ER77Cax1+8/8jCB9fo4Ud161OZzWN5qawi4GusDuRLcDbDG+bIGYY20zb2dfAFdTRGzrfq2xZPvF0R64EHnimg== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-async-to-generator@^7.3.4": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.5.0.tgz#89a3848a0166623b5bc481164b5936ab947e887e" - integrity sha512-mqvkzwIGkq0bEF1zLRRiTdjfomZJDV33AH3oQzHVGkI2VzEmXLpKKOBvEVaFZBJdN0XTyH38s9j/Kiqr68dggg== - dependencies: - "@babel/helper-module-imports" "^7.0.0" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-remap-async-to-generator" "^7.1.0" - -"@babel/plugin-transform-block-scoped-functions@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.2.0.tgz#5d3cc11e8d5ddd752aa64c9148d0db6cb79fd190" - integrity sha512-ntQPR6q1/NKuphly49+QiQiTN0O63uOwjdD6dhIjSWBI5xlrbUFh720TIpzBhpnrLfv2tNH/BXvLIab1+BAI0w== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-block-scoping@^7.3.4": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.5.5.tgz#a35f395e5402822f10d2119f6f8e045e3639a2ce" - integrity sha512-82A3CLRRdYubkG85lKwhZB0WZoHxLGsJdux/cOVaJCJpvYFl1LVzAIFyRsa7CvXqW8rBM4Zf3Bfn8PHt5DP0Sg== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - lodash "^4.17.13" - -"@babel/plugin-transform-classes@^7.3.4": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.5.5.tgz#d094299d9bd680a14a2a0edae38305ad60fb4de9" - integrity sha512-U2htCNK/6e9K7jGyJ++1p5XRU+LJjrwtoiVn9SzRlDT2KubcZ11OOwy3s24TjHxPgxNwonCYP7U2K51uVYCMDg== - dependencies: - "@babel/helper-annotate-as-pure" "^7.0.0" - "@babel/helper-define-map" "^7.5.5" - "@babel/helper-function-name" "^7.1.0" - "@babel/helper-optimise-call-expression" "^7.0.0" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-replace-supers" "^7.5.5" - "@babel/helper-split-export-declaration" "^7.4.4" - globals "^11.1.0" - -"@babel/plugin-transform-computed-properties@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.2.0.tgz#83a7df6a658865b1c8f641d510c6f3af220216da" - integrity sha512-kP/drqTxY6Xt3NNpKiMomfgkNn4o7+vKxK2DDKcBG9sHj51vHqMBGy8wbDS/J4lMxnqs153/T3+DmCEAkC5cpA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-destructuring@^7.2.0": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.5.0.tgz#f6c09fdfe3f94516ff074fe877db7bc9ef05855a" - integrity sha512-YbYgbd3TryYYLGyC7ZR+Tq8H/+bCmwoaxHfJHupom5ECstzbRLTch6gOQbhEY9Z4hiCNHEURgq06ykFv9JZ/QQ== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-dotall-regex@^7.2.0": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.4.4.tgz#361a148bc951444312c69446d76ed1ea8e4450c3" - integrity sha512-P05YEhRc2h53lZDjRPk/OektxCVevFzZs2Gfjd545Wde3k+yFDbXORgl2e0xpbq8mLcKJ7Idss4fAg0zORN/zg== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-regex" "^7.4.4" - regexpu-core "^4.5.4" - -"@babel/plugin-transform-duplicate-keys@^7.2.0": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.5.0.tgz#c5dbf5106bf84cdf691222c0974c12b1df931853" - integrity sha512-igcziksHizyQPlX9gfSjHkE2wmoCH3evvD2qR5w29/Dk0SMKE/eOI7f1HhBdNhR/zxJDqrgpoDTq5YSLH/XMsQ== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-exponentiation-operator@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.2.0.tgz#a63868289e5b4007f7054d46491af51435766008" - integrity sha512-umh4hR6N7mu4Elq9GG8TOu9M0bakvlsREEC+ialrQN6ABS4oDQ69qJv1VtR3uxlKMCQMCvzk7vr17RHKcjx68A== - dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor" "^7.1.0" - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-for-of@^7.2.0": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.4.4.tgz#0267fc735e24c808ba173866c6c4d1440fc3c556" - integrity sha512-9T/5Dlr14Z9TIEXLXkt8T1DU7F24cbhwhMNUziN3hB1AXoZcdzPcTiKGRn/6iOymDqtTKWnr/BtRKN9JwbKtdQ== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-function-name@^7.2.0": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.4.4.tgz#e1436116abb0610c2259094848754ac5230922ad" - integrity sha512-iU9pv7U+2jC9ANQkKeNF6DrPy4GBa4NWQtl6dHB4Pb3izX2JOEvDTFarlNsBj/63ZEzNNIAMs3Qw4fNCcSOXJA== - dependencies: - "@babel/helper-function-name" "^7.1.0" - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-literals@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.2.0.tgz#690353e81f9267dad4fd8cfd77eafa86aba53ea1" - integrity sha512-2ThDhm4lI4oV7fVQ6pNNK+sx+c/GM5/SaML0w/r4ZB7sAneD/piDJtwdKlNckXeyGK7wlwg2E2w33C/Hh+VFCg== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-modules-amd@^7.2.0": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.5.0.tgz#ef00435d46da0a5961aa728a1d2ecff063e4fb91" - integrity sha512-n20UsQMKnWrltocZZm24cRURxQnWIvsABPJlw/fvoy9c6AgHZzoelAIzajDHAQrDpuKFFPPcFGd7ChsYuIUMpg== - dependencies: - "@babel/helper-module-transforms" "^7.1.0" - "@babel/helper-plugin-utils" "^7.0.0" - babel-plugin-dynamic-import-node "^2.3.0" - -"@babel/plugin-transform-modules-commonjs@^7.2.0": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.5.0.tgz#425127e6045231360858eeaa47a71d75eded7a74" - integrity sha512-xmHq0B+ytyrWJvQTc5OWAC4ii6Dhr0s22STOoydokG51JjWhyYo5mRPXoi+ZmtHQhZZwuXNN+GG5jy5UZZJxIQ== - dependencies: - "@babel/helper-module-transforms" "^7.4.4" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-simple-access" "^7.1.0" - babel-plugin-dynamic-import-node "^2.3.0" - -"@babel/plugin-transform-modules-systemjs@^7.3.4": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.5.0.tgz#e75266a13ef94202db2a0620977756f51d52d249" - integrity sha512-Q2m56tyoQWmuNGxEtUyeEkm6qJYFqs4c+XyXH5RAuYxObRNz9Zgj/1g2GMnjYp2EUyEy7YTrxliGCXzecl/vJg== - dependencies: - "@babel/helper-hoist-variables" "^7.4.4" - "@babel/helper-plugin-utils" "^7.0.0" - babel-plugin-dynamic-import-node "^2.3.0" - -"@babel/plugin-transform-modules-umd@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.2.0.tgz#7678ce75169f0877b8eb2235538c074268dd01ae" - integrity sha512-BV3bw6MyUH1iIsGhXlOK6sXhmSarZjtJ/vMiD9dNmpY8QXFFQTj+6v92pcfy1iqa8DeAfJFwoxcrS/TUZda6sw== - dependencies: - "@babel/helper-module-transforms" "^7.1.0" - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-named-capturing-groups-regex@^7.3.0": - version "7.4.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.4.5.tgz#9d269fd28a370258199b4294736813a60bbdd106" - integrity sha512-z7+2IsWafTBbjNsOxU/Iv5CvTJlr5w4+HGu1HovKYTtgJ362f7kBcQglkfmlspKKZ3bgrbSGvLfNx++ZJgCWsg== - dependencies: - regexp-tree "^0.1.6" - -"@babel/plugin-transform-new-target@^7.0.0": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.4.4.tgz#18d120438b0cc9ee95a47f2c72bc9768fbed60a5" - integrity sha512-r1z3T2DNGQwwe2vPGZMBNjioT2scgWzK9BCnDEh+46z8EEwXBq24uRzd65I7pjtugzPSj921aM15RpESgzsSuA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-object-super@^7.2.0": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.5.5.tgz#c70021df834073c65eb613b8679cc4a381d1a9f9" - integrity sha512-un1zJQAhSosGFBduPgN/YFNvWVpRuHKU7IHBglLoLZsGmruJPOo6pbInneflUdmq7YvSVqhpPs5zdBvLnteltQ== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-replace-supers" "^7.5.5" - -"@babel/plugin-transform-parameters@^7.2.0": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.4.4.tgz#7556cf03f318bd2719fe4c922d2d808be5571e16" - integrity sha512-oMh5DUO1V63nZcu/ZVLQFqiihBGo4OpxJxR1otF50GMeCLiRx5nUdtokd+u9SuVJrvvuIh9OosRFPP4pIPnwmw== - dependencies: - "@babel/helper-call-delegate" "^7.4.4" - "@babel/helper-get-function-arity" "^7.0.0" - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-regenerator@^7.3.4": - version "7.4.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.4.5.tgz#629dc82512c55cee01341fb27bdfcb210354680f" - integrity sha512-gBKRh5qAaCWntnd09S8QC7r3auLCqq5DI6O0DlfoyDjslSBVqBibrMdsqO+Uhmx3+BlOmE/Kw1HFxmGbv0N9dA== - dependencies: - regenerator-transform "^0.14.0" - -"@babel/plugin-transform-runtime@^7.4.0": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.5.5.tgz#a6331afbfc59189d2135b2e09474457a8e3d28bc" - integrity sha512-6Xmeidsun5rkwnGfMOp6/z9nSzWpHFNVr2Jx7kwoq4mVatQfQx5S56drBgEHF+XQbKOdIaOiMIINvp/kAwMN+w== - dependencies: - "@babel/helper-module-imports" "^7.0.0" - "@babel/helper-plugin-utils" "^7.0.0" - resolve "^1.8.1" - semver "^5.5.1" - -"@babel/plugin-transform-shorthand-properties@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.2.0.tgz#6333aee2f8d6ee7e28615457298934a3b46198f0" - integrity sha512-QP4eUM83ha9zmYtpbnyjTLAGKQritA5XW/iG9cjtuOI8s1RuL/3V6a3DeSHfKutJQ+ayUfeZJPcnCYEQzaPQqg== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-spread@^7.2.0": - version "7.2.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.2.2.tgz#3103a9abe22f742b6d406ecd3cd49b774919b406" - integrity sha512-KWfky/58vubwtS0hLqEnrWJjsMGaOeSBn90Ezn5Jeg9Z8KKHmELbP1yGylMlm5N6TPKeY9A2+UaSYLdxahg01w== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-sticky-regex@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.2.0.tgz#a1e454b5995560a9c1e0d537dfc15061fd2687e1" - integrity sha512-KKYCoGaRAf+ckH8gEL3JHUaFVyNHKe3ASNsZ+AlktgHevvxGigoIttrEJb8iKN03Q7Eazlv1s6cx2B2cQ3Jabw== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-regex" "^7.0.0" - -"@babel/plugin-transform-template-literals@^7.2.0": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.4.4.tgz#9d28fea7bbce637fb7612a0750989d8321d4bcb0" - integrity sha512-mQrEC4TWkhLN0z8ygIvEL9ZEToPhG5K7KDW3pzGqOfIGZ28Jb0POUkeWcoz8HnHvhFy6dwAT1j8OzqN8s804+g== - dependencies: - "@babel/helper-annotate-as-pure" "^7.0.0" - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-typeof-symbol@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.2.0.tgz#117d2bcec2fbf64b4b59d1f9819894682d29f2b2" - integrity sha512-2LNhETWYxiYysBtrBTqL8+La0jIoQQnIScUJc74OYvUGRmkskNY4EzLCnjHBzdmb38wqtTaixpo1NctEcvMDZw== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-unicode-regex@^7.2.0": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.4.4.tgz#ab4634bb4f14d36728bf5978322b35587787970f" - integrity sha512-il+/XdNw01i93+M9J9u4T7/e/Ue/vWfNZE4IRUQjplu2Mqb/AFTDimkw2tdEdSH50wuQXZAbXSql0UphQke+vA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-regex" "^7.4.4" - regexpu-core "^4.5.4" - -"@babel/preset-env@^7.0.0 < 7.4.0": - version "7.3.4" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.3.4.tgz#887cf38b6d23c82f19b5135298bdb160062e33e1" - integrity sha512-2mwqfYMK8weA0g0uBKOt4FE3iEodiHy9/CW0b+nWXcbL+pGzLx8ESYc+j9IIxr6LTDHWKgPm71i9smo02bw+gA== - dependencies: - "@babel/helper-module-imports" "^7.0.0" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-proposal-async-generator-functions" "^7.2.0" - "@babel/plugin-proposal-json-strings" "^7.2.0" - "@babel/plugin-proposal-object-rest-spread" "^7.3.4" - "@babel/plugin-proposal-optional-catch-binding" "^7.2.0" - "@babel/plugin-proposal-unicode-property-regex" "^7.2.0" - "@babel/plugin-syntax-async-generators" "^7.2.0" - "@babel/plugin-syntax-json-strings" "^7.2.0" - "@babel/plugin-syntax-object-rest-spread" "^7.2.0" - "@babel/plugin-syntax-optional-catch-binding" "^7.2.0" - "@babel/plugin-transform-arrow-functions" "^7.2.0" - "@babel/plugin-transform-async-to-generator" "^7.3.4" - "@babel/plugin-transform-block-scoped-functions" "^7.2.0" - "@babel/plugin-transform-block-scoping" "^7.3.4" - "@babel/plugin-transform-classes" "^7.3.4" - "@babel/plugin-transform-computed-properties" "^7.2.0" - "@babel/plugin-transform-destructuring" "^7.2.0" - "@babel/plugin-transform-dotall-regex" "^7.2.0" - "@babel/plugin-transform-duplicate-keys" "^7.2.0" - "@babel/plugin-transform-exponentiation-operator" "^7.2.0" - "@babel/plugin-transform-for-of" "^7.2.0" - "@babel/plugin-transform-function-name" "^7.2.0" - "@babel/plugin-transform-literals" "^7.2.0" - "@babel/plugin-transform-modules-amd" "^7.2.0" - "@babel/plugin-transform-modules-commonjs" "^7.2.0" - "@babel/plugin-transform-modules-systemjs" "^7.3.4" - "@babel/plugin-transform-modules-umd" "^7.2.0" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.3.0" - "@babel/plugin-transform-new-target" "^7.0.0" - "@babel/plugin-transform-object-super" "^7.2.0" - "@babel/plugin-transform-parameters" "^7.2.0" - "@babel/plugin-transform-regenerator" "^7.3.4" - "@babel/plugin-transform-shorthand-properties" "^7.2.0" - "@babel/plugin-transform-spread" "^7.2.0" - "@babel/plugin-transform-sticky-regex" "^7.2.0" - "@babel/plugin-transform-template-literals" "^7.2.0" - "@babel/plugin-transform-typeof-symbol" "^7.2.0" - "@babel/plugin-transform-unicode-regex" "^7.2.0" - browserslist "^4.3.4" - invariant "^2.2.2" - js-levenshtein "^1.1.3" - semver "^5.3.0" - -"@babel/runtime-corejs2@^7.2.0": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/runtime-corejs2/-/runtime-corejs2-7.5.5.tgz#c3214c08ef20341af4187f1c9fbdc357fbec96b2" - integrity sha512-FYATQVR00NSNi7mUfpPDp7E8RYMXDuO8gaix7u/w3GekfUinKgX1AcTxs7SoiEmoEW9mbpjrwqWSW6zCmw5h8A== - dependencies: - core-js "^2.6.5" - regenerator-runtime "^0.13.2" - -"@babel/runtime@^7.0.0": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.5.5.tgz#74fba56d35efbeca444091c7850ccd494fd2f132" - integrity sha512-28QvEGyQyNkB0/m2B4FU7IEZGK2NUrcMtT6BZEFALTguLk+AUT6ofsHtPk5QyjAdUkpMJ+/Em+quwz4HOt30AQ== - dependencies: - regenerator-runtime "^0.13.2" - -"@babel/template@^7.1.0", "@babel/template@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.4.4.tgz#f4b88d1225689a08f5bc3a17483545be9e4ed237" - integrity sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw== - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/parser" "^7.4.4" - "@babel/types" "^7.4.4" - -"@babel/traverse@^7.1.0", "@babel/traverse@^7.4.4", "@babel/traverse@^7.5.5": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.5.5.tgz#f664f8f368ed32988cd648da9f72d5ca70f165bb" - integrity sha512-MqB0782whsfffYfSjH4TM+LMjrJnhCNEDMDIjeTpl+ASaUvxcjoiVCo/sM1GhS1pHOXYfWVCYneLjMckuUxDaQ== - dependencies: - "@babel/code-frame" "^7.5.5" - "@babel/generator" "^7.5.5" - "@babel/helper-function-name" "^7.1.0" - "@babel/helper-split-export-declaration" "^7.4.4" - "@babel/parser" "^7.5.5" - "@babel/types" "^7.5.5" - debug "^4.1.0" - globals "^11.1.0" - lodash "^4.17.13" - -"@babel/types@^7.0.0", "@babel/types@^7.2.0", "@babel/types@^7.4.4", "@babel/types@^7.5.5": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.5.5.tgz#97b9f728e182785909aa4ab56264f090a028d18a" - integrity sha512-s63F9nJioLqOlW3UkyMd+BYhXt44YuaFm/VV0VwuteqjYwRrObkU7ra9pY4wAJR3oXi8hJrMcrcJdO/HH33vtw== - dependencies: - esutils "^2.0.2" - lodash "^4.17.13" - to-fast-properties "^2.0.0" - -"@mrmlnc/readdir-enhanced@^2.2.1": - version "2.2.1" - resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" - integrity sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g== - dependencies: - call-me-maybe "^1.0.1" - glob-to-regexp "^0.3.0" - -"@nodelib/fs.stat@^1.1.2": - version "1.1.3" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b" - integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw== - -"@types/events@*": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" - integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g== - -"@types/glob@^7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575" - integrity sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w== - dependencies: - "@types/events" "*" - "@types/minimatch" "*" - "@types/node" "*" - -"@types/minimatch@*": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" - integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== - -"@types/node@*": - version "12.6.8" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.6.8.tgz#e469b4bf9d1c9832aee4907ba8a051494357c12c" - integrity sha512-aX+gFgA5GHcDi89KG5keey2zf0WfZk/HAQotEamsK2kbey+8yGKcson0hbK8E+v0NArlCJQCqMP161YhV6ZXLg== - -"@types/q@^1.5.1": - version "1.5.2" - resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.2.tgz#690a1475b84f2a884fd07cd797c00f5f31356ea8" - integrity sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw== - -"@vue/babel-helper-vue-jsx-merge-props@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@vue/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-1.0.0.tgz#048fe579958da408fb7a8b2a3ec050b50a661040" - integrity sha512-6tyf5Cqm4m6v7buITuwS+jHzPlIPxbFzEhXR5JGZpbrvOcp1hiQKckd305/3C7C36wFekNTQSxAtgeM0j0yoUw== - -"@vue/babel-plugin-transform-vue-jsx@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@vue/babel-plugin-transform-vue-jsx/-/babel-plugin-transform-vue-jsx-1.0.0.tgz#ebcbf39c312c94114c8c4f407ee4f6c97aa45432" - integrity sha512-U+JNwVQSmaLKjO3lzCUC3cNXxprgezV1N+jOdqbP4xWNaqtWUCJnkjTVcgECM18A/AinDKPcUUeoyhU7yxUxXQ== - dependencies: - "@babel/helper-module-imports" "^7.0.0" - "@babel/plugin-syntax-jsx" "^7.2.0" - "@vue/babel-helper-vue-jsx-merge-props" "^1.0.0" - html-tags "^2.0.0" - lodash.kebabcase "^4.1.1" - svg-tags "^1.0.0" - -"@vue/babel-preset-app@^3.1.1": - version "3.9.2" - resolved "https://registry.yarnpkg.com/@vue/babel-preset-app/-/babel-preset-app-3.9.2.tgz#b72a9b06abbe3f8f272783be13951271277be338" - integrity sha512-0suuCbu4jkVcVYBjPmuKxeDbrhwThYZHu3DUmtsVuOzFEGeXmco60VmXveniL/bnDUdZyknSuYP4FxgS34gw9w== - dependencies: - "@babel/helper-module-imports" "^7.0.0" - "@babel/plugin-proposal-class-properties" "^7.0.0" - "@babel/plugin-proposal-decorators" "^7.1.0" - "@babel/plugin-syntax-dynamic-import" "^7.0.0" - "@babel/plugin-syntax-jsx" "^7.0.0" - "@babel/plugin-transform-runtime" "^7.4.0" - "@babel/preset-env" "^7.0.0 < 7.4.0" - "@babel/runtime" "^7.0.0" - "@babel/runtime-corejs2" "^7.2.0" - "@vue/babel-preset-jsx" "^1.0.0" - babel-plugin-dynamic-import-node "^2.2.0" - babel-plugin-module-resolver "3.2.0" - core-js "^2.6.5" - -"@vue/babel-preset-jsx@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@vue/babel-preset-jsx/-/babel-preset-jsx-1.0.0.tgz#e515cd453a5a8ea6b0f30b2bb92f266d8ab4e9f5" - integrity sha512-5CbDu/QHS+TtQNw5aYAffiMxBBB2Eo9+RJpS8X+6FJbdG5Rvc4TVipEqkrg0pJviWadNg7TEy0Uz4o7VNXeIZw== - dependencies: - "@vue/babel-helper-vue-jsx-merge-props" "^1.0.0" - "@vue/babel-plugin-transform-vue-jsx" "^1.0.0" - "@vue/babel-sugar-functional-vue" "^1.0.0" - "@vue/babel-sugar-inject-h" "^1.0.0" - "@vue/babel-sugar-v-model" "^1.0.0" - "@vue/babel-sugar-v-on" "^1.0.0" - -"@vue/babel-sugar-functional-vue@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@vue/babel-sugar-functional-vue/-/babel-sugar-functional-vue-1.0.0.tgz#17e2c4ca27b74b244da3b923240ec91d10048cb3" - integrity sha512-XE/jNaaorTuhWayCz+QClk5AB9OV5HzrwbzEC6sIUY0J60A28ONQKeTwxfidW42egOkqNH/UU6eE3KLfmiDj0Q== - dependencies: - "@babel/plugin-syntax-jsx" "^7.2.0" - -"@vue/babel-sugar-inject-h@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@vue/babel-sugar-inject-h/-/babel-sugar-inject-h-1.0.0.tgz#e5efb6c5b5b7988dc03831af6d133bf7bcde6347" - integrity sha512-NxWU+DqtbZgfGvd25GPoFMj+rvyQ8ZA1pHj8vIeqRij+vx3sXoKkObjA9ulZunvWw5F6uG9xYy4ytpxab/X+Hg== - dependencies: - "@babel/plugin-syntax-jsx" "^7.2.0" - -"@vue/babel-sugar-v-model@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@vue/babel-sugar-v-model/-/babel-sugar-v-model-1.0.0.tgz#f4da56aa67f65a349bd2c269a95e72e601af4613" - integrity sha512-Pfg2Al0io66P1eO6zUbRIgpyKCU2qTnumiE0lao/wA/uNdb7Dx5Tfd1W6tO5SsByETPnEs8i8+gawRIXX40rFw== - dependencies: - "@babel/plugin-syntax-jsx" "^7.2.0" - "@vue/babel-helper-vue-jsx-merge-props" "^1.0.0" - "@vue/babel-plugin-transform-vue-jsx" "^1.0.0" - camelcase "^5.0.0" - html-tags "^2.0.0" - svg-tags "^1.0.0" - -"@vue/babel-sugar-v-on@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@vue/babel-sugar-v-on/-/babel-sugar-v-on-1.0.0.tgz#a633ee8fe205763e865b011246981b7f89668033" - integrity sha512-2aqJaDLKdSSGlxZU+GjFERaSNUaa6DQreV+V/K4W/6Lxj8520/r1lChWEa/zuAoPD2Vhy0D2QrqqO+I0D6CkKw== - dependencies: - "@babel/plugin-syntax-jsx" "^7.2.0" - "@vue/babel-plugin-transform-vue-jsx" "^1.0.0" - camelcase "^5.0.0" - -"@vue/component-compiler-utils@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@vue/component-compiler-utils/-/component-compiler-utils-3.0.0.tgz#d16fa26b836c06df5baaeb45f3d80afc47e35634" - integrity sha512-am+04/0UX7ektcmvhYmrf84BDVAD8afFOf4asZjN84q8xzxFclbk5x0MtxuKGfp+zjN5WWPJn3fjFAWtDdIGSw== - dependencies: - consolidate "^0.15.1" - hash-sum "^1.0.2" - lru-cache "^4.1.2" - merge-source-map "^1.1.0" - postcss "^7.0.14" - postcss-selector-parser "^5.0.0" - prettier "1.16.3" - source-map "~0.6.1" - vue-template-es2015-compiler "^1.9.0" - -"@vuepress/core@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@vuepress/core/-/core-1.0.2.tgz#75d0c6ccb4be92c6674c3bbfbe25639c8239921b" - integrity sha512-PUMaxq44wEuqXHutcmxj6q9cCRS4kZ1nyBvvHr9AIuxJflgYDw/k8wxhYuZjsxVWhpJjsPywLGNRyLN88vJcqQ== - dependencies: - "@babel/core" "^7.0.0" - "@vue/babel-preset-app" "^3.1.1" - "@vuepress/markdown" "^1.0.2" - "@vuepress/markdown-loader" "^1.0.2" - "@vuepress/plugin-last-updated" "^1.0.2" - "@vuepress/plugin-register-components" "^1.0.2" - "@vuepress/shared-utils" "^1.0.2" - autoprefixer "^9.5.1" - babel-loader "^8.0.4" - cache-loader "^3.0.0" - chokidar "^2.0.3" - connect-history-api-fallback "^1.5.0" - copy-webpack-plugin "^5.0.2" - cross-spawn "^6.0.5" - css-loader "^2.1.1" - file-loader "^3.0.1" - js-yaml "^3.11.0" - lru-cache "^5.1.1" - mini-css-extract-plugin "0.6.0" - optimize-css-assets-webpack-plugin "^5.0.1" - portfinder "^1.0.13" - postcss-loader "^3.0.0" - postcss-safe-parser "^4.0.1" - toml "^3.0.0" - url-loader "^1.0.1" - vue "^2.5.16" - vue-loader "^15.2.4" - vue-router "^3.0.2" - vue-server-renderer "^2.5.16" - vue-template-compiler "^2.5.16" - vuepress-html-webpack-plugin "^3.2.0" - vuepress-plugin-container "^2.0.0" - webpack "^4.8.1" - webpack-chain "^4.6.0" - webpack-dev-server "^3.5.1" - webpack-merge "^4.1.2" - webpackbar "3.2.0" - -"@vuepress/markdown-loader@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@vuepress/markdown-loader/-/markdown-loader-1.0.2.tgz#b068df3049f6b63cfee329f85aed3bb0aa9e7ab0" - integrity sha512-ljD2mVDpeq0VvCHMHfemGW+0fhLmOMldtWIAYQ/I8LjLuV2qknAwjzZ4tEAqveaVIFMUBRP3V6d8YGIK9dr6kg== - dependencies: - "@vuepress/markdown" "^1.0.2" - loader-utils "^1.1.0" - lru-cache "^5.1.1" - -"@vuepress/markdown@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@vuepress/markdown/-/markdown-1.0.2.tgz#436c5aa74e22cf7f6705b99c8892b6ba2d84cd0a" - integrity sha512-ddl0FG11aeidjcFYYNU53xZ1WLEYb3g5/hijfSCEQKyMv+gDXy7Z3/uc4I4oH2UNtB2Wpo3pQoeKGY56edcBuA== - dependencies: - "@vuepress/shared-utils" "^1.0.2" - markdown-it "^8.4.1" - markdown-it-anchor "^5.0.2" - markdown-it-chain "^1.3.0" - markdown-it-emoji "^1.4.0" - markdown-it-table-of-contents "^0.4.0" - prismjs "^1.13.0" - -"@vuepress/plugin-active-header-links@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@vuepress/plugin-active-header-links/-/plugin-active-header-links-1.0.2.tgz#df04f7fc21640d3e0a0b704037e360e75974d1a2" - integrity sha512-Wo9NP55OOJ/vGFnYwStZcDBJMnf1gNDL159K7oiiEltuz8kjZBqmtsIjQXOzXFjA8voYh/RVL48Sr4eGCDd7LQ== - dependencies: - lodash.throttle "^4.1.1" - -"@vuepress/plugin-last-updated@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@vuepress/plugin-last-updated/-/plugin-last-updated-1.0.2.tgz#c839c5fb585c469a8c2ff70c16204dd72478545a" - integrity sha512-SwugVHcllUwy9WPqtWWM+hUEvH6SDPFJAHnpIs0kXJmaxIIipqF/9+CokT5QzxzGVHeYPU4YKtLadEIXdRcXsw== - dependencies: - cross-spawn "^6.0.5" - -"@vuepress/plugin-nprogress@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@vuepress/plugin-nprogress/-/plugin-nprogress-1.0.2.tgz#3fae13c8af23292cf324d159c77e4d0ffc3133ab" - integrity sha512-degCJe2Z0eHbYblUGQXuDMIZSwH7twQcbWtkuH8goxXNilvtVxtWvBkUJouJ9RN3RuSk7EfPT171mrwq9yqbUg== - dependencies: - nprogress "^0.2.0" - -"@vuepress/plugin-register-components@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@vuepress/plugin-register-components/-/plugin-register-components-1.0.2.tgz#504c190b1c1836e3428d90749a2dbd59f6e596b9" - integrity sha512-iqUq4kgNdVHba0cZJLv81DfB9ZsTdJY7gynN0NYHFwDEjsdOh1cRMgteuWa/mmK9XfopMO5oysD9WDhzCiIjfQ== - dependencies: - "@vuepress/shared-utils" "^1.0.2" - -"@vuepress/plugin-search@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@vuepress/plugin-search/-/plugin-search-1.0.2.tgz#6d43fb46b207d48b797a5bc5b01824662db4684d" - integrity sha512-LCFZLp+adppdHETIEARwQhczj+mdpa+D25qL9RNmYxzU9mF6qItYNLl57P6omGU2Vr8frAc+rWgjbi4cjkbCvQ== - -"@vuepress/shared-utils@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@vuepress/shared-utils/-/shared-utils-1.0.2.tgz#4e1342748b7594fe4fde9dce3bf201538fa5ca67" - integrity sha512-QyNV76Dn0u2ooXbC3AXJZrQLuTNS4i8xSmJqZWsel2ooJKknXP3UIMIENcK1QFHnlIACznyV53u9hRAYBaZEWQ== - dependencies: - chalk "^2.3.2" - diacritics "^1.3.0" - escape-html "^1.0.3" - fs-extra "^7.0.1" - globby "^9.2.0" - gray-matter "^4.0.1" - hash-sum "^1.0.2" - semver "^6.0.0" - upath "^1.1.0" - -"@vuepress/theme-default@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@vuepress/theme-default/-/theme-default-1.0.2.tgz#7678c4755db9d891effee838991287d31ae9c5ed" - integrity sha512-fawiYshvQWXyaEgMXcyqj7j0atHLysIA2AzFt4K6y29WaMfiIAPE9lsxymTzT4zkc/T6nRP/TqwiuUaOK12wkw== - dependencies: - "@vuepress/plugin-active-header-links" "^1.0.2" - "@vuepress/plugin-nprogress" "^1.0.2" - "@vuepress/plugin-search" "^1.0.2" - docsearch.js "^2.5.2" - stylus "^0.54.5" - stylus-loader "^3.0.2" - vuepress-plugin-container "^2.0.0" - -"@webassemblyjs/ast@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.8.5.tgz#51b1c5fe6576a34953bf4b253df9f0d490d9e359" - integrity sha512-aJMfngIZ65+t71C3y2nBBg5FFG0Okt9m0XEgWZ7Ywgn1oMAT8cNwx00Uv1cQyHtidq0Xn94R4TAywO+LCQ+ZAQ== - dependencies: - "@webassemblyjs/helper-module-context" "1.8.5" - "@webassemblyjs/helper-wasm-bytecode" "1.8.5" - "@webassemblyjs/wast-parser" "1.8.5" - -"@webassemblyjs/floating-point-hex-parser@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.5.tgz#1ba926a2923613edce496fd5b02e8ce8a5f49721" - integrity sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ== - -"@webassemblyjs/helper-api-error@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.5.tgz#c49dad22f645227c5edb610bdb9697f1aab721f7" - integrity sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA== - -"@webassemblyjs/helper-buffer@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.5.tgz#fea93e429863dd5e4338555f42292385a653f204" - integrity sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q== - -"@webassemblyjs/helper-code-frame@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.5.tgz#9a740ff48e3faa3022b1dff54423df9aa293c25e" - integrity sha512-VQAadSubZIhNpH46IR3yWO4kZZjMxN1opDrzePLdVKAZ+DFjkGD/rf4v1jap744uPVU6yjL/smZbRIIJTOUnKQ== - dependencies: - "@webassemblyjs/wast-printer" "1.8.5" - -"@webassemblyjs/helper-fsm@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.5.tgz#ba0b7d3b3f7e4733da6059c9332275d860702452" - integrity sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow== - -"@webassemblyjs/helper-module-context@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.5.tgz#def4b9927b0101dc8cbbd8d1edb5b7b9c82eb245" - integrity sha512-/O1B236mN7UNEU4t9X7Pj38i4VoU8CcMHyy3l2cV/kIF4U5KoHXDVqcDuOs1ltkac90IM4vZdHc52t1x8Yfs3g== - dependencies: - "@webassemblyjs/ast" "1.8.5" - mamacro "^0.0.3" - -"@webassemblyjs/helper-wasm-bytecode@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.5.tgz#537a750eddf5c1e932f3744206551c91c1b93e61" - integrity sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ== - -"@webassemblyjs/helper-wasm-section@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.5.tgz#74ca6a6bcbe19e50a3b6b462847e69503e6bfcbf" - integrity sha512-VV083zwR+VTrIWWtgIUpqfvVdK4ff38loRmrdDBgBT8ADXYsEZ5mPQ4Nde90N3UYatHdYoDIFb7oHzMncI02tA== - dependencies: - "@webassemblyjs/ast" "1.8.5" - "@webassemblyjs/helper-buffer" "1.8.5" - "@webassemblyjs/helper-wasm-bytecode" "1.8.5" - "@webassemblyjs/wasm-gen" "1.8.5" - -"@webassemblyjs/ieee754@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.8.5.tgz#712329dbef240f36bf57bd2f7b8fb9bf4154421e" - integrity sha512-aaCvQYrvKbY/n6wKHb/ylAJr27GglahUO89CcGXMItrOBqRarUMxWLJgxm9PJNuKULwN5n1csT9bYoMeZOGF3g== - dependencies: - "@xtuc/ieee754" "^1.2.0" - -"@webassemblyjs/leb128@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.8.5.tgz#044edeb34ea679f3e04cd4fd9824d5e35767ae10" - integrity sha512-plYUuUwleLIziknvlP8VpTgO4kqNaH57Y3JnNa6DLpu/sGcP6hbVdfdX5aHAV716pQBKrfuU26BJK29qY37J7A== - dependencies: - "@xtuc/long" "4.2.2" - -"@webassemblyjs/utf8@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.8.5.tgz#a8bf3b5d8ffe986c7c1e373ccbdc2a0915f0cedc" - integrity sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw== - -"@webassemblyjs/wasm-edit@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.8.5.tgz#962da12aa5acc1c131c81c4232991c82ce56e01a" - integrity sha512-A41EMy8MWw5yvqj7MQzkDjU29K7UJq1VrX2vWLzfpRHt3ISftOXqrtojn7nlPsZ9Ijhp5NwuODuycSvfAO/26Q== - dependencies: - "@webassemblyjs/ast" "1.8.5" - "@webassemblyjs/helper-buffer" "1.8.5" - "@webassemblyjs/helper-wasm-bytecode" "1.8.5" - "@webassemblyjs/helper-wasm-section" "1.8.5" - "@webassemblyjs/wasm-gen" "1.8.5" - "@webassemblyjs/wasm-opt" "1.8.5" - "@webassemblyjs/wasm-parser" "1.8.5" - "@webassemblyjs/wast-printer" "1.8.5" - -"@webassemblyjs/wasm-gen@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.8.5.tgz#54840766c2c1002eb64ed1abe720aded714f98bc" - integrity sha512-BCZBT0LURC0CXDzj5FXSc2FPTsxwp3nWcqXQdOZE4U7h7i8FqtFK5Egia6f9raQLpEKT1VL7zr4r3+QX6zArWg== - dependencies: - "@webassemblyjs/ast" "1.8.5" - "@webassemblyjs/helper-wasm-bytecode" "1.8.5" - "@webassemblyjs/ieee754" "1.8.5" - "@webassemblyjs/leb128" "1.8.5" - "@webassemblyjs/utf8" "1.8.5" - -"@webassemblyjs/wasm-opt@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.8.5.tgz#b24d9f6ba50394af1349f510afa8ffcb8a63d264" - integrity sha512-HKo2mO/Uh9A6ojzu7cjslGaHaUU14LdLbGEKqTR7PBKwT6LdPtLLh9fPY33rmr5wcOMrsWDbbdCHq4hQUdd37Q== - dependencies: - "@webassemblyjs/ast" "1.8.5" - "@webassemblyjs/helper-buffer" "1.8.5" - "@webassemblyjs/wasm-gen" "1.8.5" - "@webassemblyjs/wasm-parser" "1.8.5" - -"@webassemblyjs/wasm-parser@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.8.5.tgz#21576f0ec88b91427357b8536383668ef7c66b8d" - integrity sha512-pi0SYE9T6tfcMkthwcgCpL0cM9nRYr6/6fjgDtL6q/ZqKHdMWvxitRi5JcZ7RI4SNJJYnYNaWy5UUrHQy998lw== - dependencies: - "@webassemblyjs/ast" "1.8.5" - "@webassemblyjs/helper-api-error" "1.8.5" - "@webassemblyjs/helper-wasm-bytecode" "1.8.5" - "@webassemblyjs/ieee754" "1.8.5" - "@webassemblyjs/leb128" "1.8.5" - "@webassemblyjs/utf8" "1.8.5" - -"@webassemblyjs/wast-parser@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.8.5.tgz#e10eecd542d0e7bd394f6827c49f3df6d4eefb8c" - integrity sha512-daXC1FyKWHF1i11obK086QRlsMsY4+tIOKgBqI1lxAnkp9xe9YMcgOxm9kLe+ttjs5aWV2KKE1TWJCN57/Btsg== - dependencies: - "@webassemblyjs/ast" "1.8.5" - "@webassemblyjs/floating-point-hex-parser" "1.8.5" - "@webassemblyjs/helper-api-error" "1.8.5" - "@webassemblyjs/helper-code-frame" "1.8.5" - "@webassemblyjs/helper-fsm" "1.8.5" - "@xtuc/long" "4.2.2" - -"@webassemblyjs/wast-printer@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.8.5.tgz#114bbc481fd10ca0e23b3560fa812748b0bae5bc" - integrity sha512-w0U0pD4EhlnvRyeJzBqaVSJAo9w/ce7/WPogeXLzGkO6hzhr4GnQIZ4W4uUt5b9ooAaXPtnXlj0gzsXEOUNYMg== - dependencies: - "@webassemblyjs/ast" "1.8.5" - "@webassemblyjs/wast-parser" "1.8.5" - "@xtuc/long" "4.2.2" - -"@xtuc/ieee754@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" - integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== - -"@xtuc/long@4.2.2": - version "4.2.2" - resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" - integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== - -abbrev@1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" - integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== - -accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7: - version "1.3.7" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" - integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== - dependencies: - mime-types "~2.1.24" - negotiator "0.6.2" - -acorn@^6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.2.0.tgz#67f0da2fc339d6cfb5d6fb244fd449f33cd8bbe3" - integrity sha512-8oe72N3WPMjA+2zVG71Ia0nXZ8DpQH+QyyHO+p06jT8eg8FGG3FbcUIi8KziHlAfheJQZeoqbvq1mQSQHXKYLw== - -agentkeepalive@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-2.2.0.tgz#c5d1bd4b129008f1163f236f86e5faea2026e2ef" - integrity sha1-xdG9SxKQCPEWPyNvhuX66iAm4u8= - -ajv-errors@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" - integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ== - -ajv-keywords@^3.1.0: - version "3.4.1" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.4.1.tgz#ef916e271c64ac12171fd8384eaae6b2345854da" - integrity sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ== - -ajv@^6.1.0, ajv@^6.5.5: - version "6.10.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52" - integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw== - dependencies: - fast-deep-equal "^2.0.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -algoliasearch@^3.24.5: - version "3.33.0" - resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-3.33.0.tgz#83b541124ebb0db54643009d4e660866b3177cdf" - integrity sha512-9DaVmOd7cvcZeYyV0BWAeJHVWJmgOL2DNUEBY/DTR4MzD1wCWs4Djl7LAlfvkGwGBdRHZCG+l0HA1572w3T8zg== - dependencies: - agentkeepalive "^2.2.0" - debug "^2.6.9" - envify "^4.0.0" - es6-promise "^4.1.0" - events "^1.1.0" - foreach "^2.0.5" - global "^4.3.2" - inherits "^2.0.1" - isarray "^2.0.1" - load-script "^1.0.0" - object-keys "^1.0.11" - querystring-es3 "^0.2.1" - reduce "^1.0.1" - semver "^5.1.0" - tunnel-agent "^0.6.0" - -alphanum-sort@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" - integrity sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM= - -amdefine@>=0.0.4: - version "1.0.1" - resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" - integrity sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU= - -ansi-colors@^3.0.0: - version "3.2.4" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf" - integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA== - -ansi-escapes@^4.1.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.2.0.tgz#c38600259cefba178ee3f7166c5ea3a5dd2e88fc" - integrity sha512-0+VX4uhi8m3aNbzoqKmkAVOEj6uQzcUHXoFPkKjhZPTpGRUBqVh930KbB6PS4zIyDZccphlLIYlu8nsjFzkXwg== - dependencies: - type-fest "^0.5.2" - -ansi-html@0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e" - integrity sha1-gTWEAhliqenm/QOflA0S9WynhZ4= - -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= - -ansi-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= - -ansi-regex@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" - integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== - -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= - -ansi-styles@^3.2.0, ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -anymatch@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" - integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== - dependencies: - micromatch "^3.1.4" - normalize-path "^2.1.1" - -aproba@^1.0.3, aproba@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" - integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== - -are-we-there-yet@~1.1.2: - version "1.1.5" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" - integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== - dependencies: - delegates "^1.0.0" - readable-stream "^2.0.6" - -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - -arr-diff@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" - integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= - -arr-flatten@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" - integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== - -arr-union@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" - integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= - -array-flatten@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" - integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= - -array-flatten@^2.1.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099" - integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ== - -array-union@^1.0.1, array-union@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" - integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= - dependencies: - array-uniq "^1.0.1" - -array-uniq@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" - integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= - -array-unique@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" - integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= - -asn1.js@^4.0.0: - version "4.10.1" - resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" - integrity sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw== - dependencies: - bn.js "^4.0.0" - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - -asn1@~0.2.3: - version "0.2.4" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" - integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== - dependencies: - safer-buffer "~2.1.0" - -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= - -assert@^1.1.1: - version "1.5.0" - resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb" - integrity sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA== - dependencies: - object-assign "^4.1.1" - util "0.10.3" - -assign-symbols@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" - integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= - -async-each@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" - integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== - -async@^1.5.2: - version "1.5.2" - resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" - integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo= - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= - -atob@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" - integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== - -autocomplete.js@0.36.0: - version "0.36.0" - resolved "https://registry.yarnpkg.com/autocomplete.js/-/autocomplete.js-0.36.0.tgz#94fe775fe64b6cd42e622d076dc7fd26bedd837b" - integrity sha512-jEwUXnVMeCHHutUt10i/8ZiRaCb0Wo+ZyKxeGsYwBDtw6EJHqEeDrq4UwZRD8YBSvp3g6klP678il2eeiVXN2Q== - dependencies: - immediate "^3.2.3" - -autoprefixer@^9.5.1: - version "9.6.1" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.6.1.tgz#51967a02d2d2300bb01866c1611ec8348d355a47" - integrity sha512-aVo5WxR3VyvyJxcJC3h4FKfwCQvQWb1tSI5VHNibddCVWrcD1NvlxEweg3TSgiPztMnWfjpy2FURKA2kvDE+Tw== - dependencies: - browserslist "^4.6.3" - caniuse-lite "^1.0.30000980" - chalk "^2.4.2" - normalize-range "^0.1.2" - num2fraction "^1.2.2" - postcss "^7.0.17" - postcss-value-parser "^4.0.0" - -aws-sign2@~0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= - -aws4@^1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" - integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== - -axios@^0.19.0: - version "0.19.0" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.0.tgz#8e09bff3d9122e133f7b8101c8fbdd00ed3d2ab8" - integrity sha512-1uvKqKQta3KBxIz14F2v06AEHZ/dIoeKfbTRkK1E5oqjDnuEerLmYTgJB5AiQZHJcljpg1TuRzdjDR06qNk0DQ== - dependencies: - follow-redirects "1.5.10" - is-buffer "^2.0.2" - -babel-loader@^8.0.4: - version "8.0.6" - resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.0.6.tgz#e33bdb6f362b03f4bb141a0c21ab87c501b70dfb" - integrity sha512-4BmWKtBOBm13uoUwd08UwjZlaw3O9GWf456R9j+5YykFZ6LUIjIKLc0zEZf+hauxPOJs96C8k6FvYD09vWzhYw== - dependencies: - find-cache-dir "^2.0.0" - loader-utils "^1.0.2" - mkdirp "^0.5.1" - pify "^4.0.1" - -babel-plugin-dynamic-import-node@^2.2.0, babel-plugin-dynamic-import-node@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz#f00f507bdaa3c3e3ff6e7e5e98d90a7acab96f7f" - integrity sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ== - dependencies: - object.assign "^4.1.0" - -babel-plugin-module-resolver@3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/babel-plugin-module-resolver/-/babel-plugin-module-resolver-3.2.0.tgz#ddfa5e301e3b9aa12d852a9979f18b37881ff5a7" - integrity sha512-tjR0GvSndzPew/Iayf4uICWZqjBwnlMWjSx6brryfQ81F9rxBVqwDJtFCV8oOs0+vJeefK9TmdZtkIFdFe1UnA== - dependencies: - find-babel-config "^1.1.0" - glob "^7.1.2" - pkg-up "^2.0.0" - reselect "^3.0.1" - resolve "^1.4.0" - -balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= - -base64-js@^1.0.2: - version "1.3.0" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3" - integrity sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw== - -base@^0.11.1: - version "0.11.2" - resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" - integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== - dependencies: - cache-base "^1.0.1" - class-utils "^0.3.5" - component-emitter "^1.2.1" - define-property "^1.0.0" - isobject "^3.0.1" - mixin-deep "^1.2.0" - pascalcase "^0.1.1" - -batch@0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" - integrity sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY= - -bcrypt-pbkdf@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" - integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= - dependencies: - tweetnacl "^0.14.3" - -big.js@^3.1.3: - version "3.2.0" - resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" - integrity sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q== - -big.js@^5.2.2: - version "5.2.2" - resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" - integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== - -binary-extensions@^1.0.0: - version "1.13.1" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" - integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== - -bluebird@^3.1.1, bluebird@^3.5.5: - version "3.5.5" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.5.tgz#a8d0afd73251effbbd5fe384a77d73003c17a71f" - integrity sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w== - -bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: - version "4.11.8" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" - integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA== - -body-parser@1.19.0: - version "1.19.0" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" - integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== - dependencies: - bytes "3.1.0" - content-type "~1.0.4" - debug "2.6.9" - depd "~1.1.2" - http-errors "1.7.2" - iconv-lite "0.4.24" - on-finished "~2.3.0" - qs "6.7.0" - raw-body "2.4.0" - type-is "~1.6.17" - -bonjour@^3.5.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/bonjour/-/bonjour-3.5.0.tgz#8e890a183d8ee9a2393b3844c691a42bcf7bc9f5" - integrity sha1-jokKGD2O6aI5OzhExpGkK897yfU= - dependencies: - array-flatten "^2.1.0" - deep-equal "^1.0.1" - dns-equal "^1.0.0" - dns-txt "^2.0.2" - multicast-dns "^6.0.1" - multicast-dns-service-types "^1.1.0" - -boolbase@^1.0.0, boolbase@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" - integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -braces@^2.3.1, braces@^2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" - integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== - dependencies: - arr-flatten "^1.1.0" - array-unique "^0.3.2" - extend-shallow "^2.0.1" - fill-range "^4.0.0" - isobject "^3.0.1" - repeat-element "^1.1.2" - snapdragon "^0.8.1" - snapdragon-node "^2.0.1" - split-string "^3.0.2" - to-regex "^3.0.1" - -brorand@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" - integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= - -browserify-aes@^1.0.0, browserify-aes@^1.0.4: - version "1.2.0" - resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" - integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== - dependencies: - buffer-xor "^1.0.3" - cipher-base "^1.0.0" - create-hash "^1.1.0" - evp_bytestokey "^1.0.3" - inherits "^2.0.1" - safe-buffer "^5.0.1" - -browserify-cipher@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" - integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== - dependencies: - browserify-aes "^1.0.4" - browserify-des "^1.0.0" - evp_bytestokey "^1.0.0" - -browserify-des@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" - integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== - dependencies: - cipher-base "^1.0.1" - des.js "^1.0.0" - inherits "^2.0.1" - safe-buffer "^5.1.2" - -browserify-rsa@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" - integrity sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ= - dependencies: - bn.js "^4.1.0" - randombytes "^2.0.1" - -browserify-sign@^4.0.0: - version "4.0.4" - resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298" - integrity sha1-qk62jl17ZYuqa/alfmMMvXqT0pg= - dependencies: - bn.js "^4.1.1" - browserify-rsa "^4.0.0" - create-hash "^1.1.0" - create-hmac "^1.1.2" - elliptic "^6.0.0" - inherits "^2.0.1" - parse-asn1 "^5.0.0" - -browserify-zlib@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" - integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== - dependencies: - pako "~1.0.5" - -browserslist@^4.0.0, browserslist@^4.3.4, browserslist@^4.6.3: - version "4.6.6" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.6.6.tgz#6e4bf467cde520bc9dbdf3747dafa03531cec453" - integrity sha512-D2Nk3W9JL9Fp/gIcWei8LrERCS+eXu9AM5cfXA8WEZ84lFks+ARnZ0q/R69m2SV3Wjma83QDDPxsNKXUwdIsyA== - dependencies: - caniuse-lite "^1.0.30000984" - electron-to-chromium "^1.3.191" - node-releases "^1.1.25" - -buffer-from@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" - integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== - -buffer-indexof@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c" - integrity sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g== - -buffer-json@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/buffer-json/-/buffer-json-2.0.0.tgz#f73e13b1e42f196fe2fd67d001c7d7107edd7c23" - integrity sha512-+jjPFVqyfF1esi9fvfUs3NqM0pH1ziZ36VP4hmA/y/Ssfo/5w5xHKfTw9BwQjoJ1w/oVtpLomqwUHKdefGyuHw== - -buffer-xor@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" - integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= - -buffer@^4.3.0: - version "4.9.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" - integrity sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg= - dependencies: - base64-js "^1.0.2" - ieee754 "^1.1.4" - isarray "^1.0.0" - -builtin-status-codes@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" - integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug= - -bytes@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" - integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= - -bytes@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" - integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== - -cac@^6.3.9: - version "6.5.2" - resolved "https://registry.yarnpkg.com/cac/-/cac-6.5.2.tgz#92ef1490b9ffde5f0be7eeadec5ea926f0e78ef6" - integrity sha512-8JdiD9/ZLsG418j/chyZQ3VWuhFELSGlH4EUxzNKgIH8wK8dO0j5Pqu6Pk7B/RP3kX9aasyQhPrrUjYO5e0w7w== - -cacache@^11.3.2: - version "11.3.3" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-11.3.3.tgz#8bd29df8c6a718a6ebd2d010da4d7972ae3bbadc" - integrity sha512-p8WcneCytvzPxhDvYp31PD039vi77I12W+/KfR9S8AZbaiARFBCpsPJS+9uhWfeBfeAtW7o/4vt3MUqLkbY6nA== - dependencies: - bluebird "^3.5.5" - chownr "^1.1.1" - figgy-pudding "^3.5.1" - glob "^7.1.4" - graceful-fs "^4.1.15" - lru-cache "^5.1.1" - mississippi "^3.0.0" - mkdirp "^0.5.1" - move-concurrently "^1.0.1" - promise-inflight "^1.0.1" - rimraf "^2.6.3" - ssri "^6.0.1" - unique-filename "^1.1.1" - y18n "^4.0.0" - -cache-base@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" - integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== - dependencies: - collection-visit "^1.0.0" - component-emitter "^1.2.1" - get-value "^2.0.6" - has-value "^1.0.0" - isobject "^3.0.1" - set-value "^2.0.0" - to-object-path "^0.3.0" - union-value "^1.0.0" - unset-value "^1.0.0" - -cache-loader@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/cache-loader/-/cache-loader-3.0.1.tgz#cee6cf4b3cdc7c610905b26bad6c2fc439c821af" - integrity sha512-HzJIvGiGqYsFUrMjAJNDbVZoG7qQA+vy9AIoKs7s9DscNfki0I589mf2w6/tW+kkFH3zyiknoWV5Jdynu6b/zw== - dependencies: - buffer-json "^2.0.0" - find-cache-dir "^2.1.0" - loader-utils "^1.2.3" - mkdirp "^0.5.1" - neo-async "^2.6.1" - schema-utils "^1.0.0" - -call-me-maybe@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" - integrity sha1-JtII6onje1y95gJQoV8DHBak1ms= - -caller-callsite@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134" - integrity sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ= - dependencies: - callsites "^2.0.0" - -caller-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-2.0.0.tgz#468f83044e369ab2010fac5f06ceee15bb2cb1f4" - integrity sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ= - dependencies: - caller-callsite "^2.0.0" - -callsites@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" - integrity sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA= - -camel-case@3.0.x: - version "3.0.0" - resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73" - integrity sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M= - dependencies: - no-case "^2.2.0" - upper-case "^1.1.1" - -camelcase@^5.0.0, camelcase@^5.2.0: - version "5.3.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" - integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== - -caniuse-api@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0" - integrity sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw== - dependencies: - browserslist "^4.0.0" - caniuse-lite "^1.0.0" - lodash.memoize "^4.1.2" - lodash.uniq "^4.5.0" - -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000980, caniuse-lite@^1.0.30000984: - version "1.0.30000984" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000984.tgz#dc96c3c469e9bcfc6ad5bdd24c77ec918ea76fe0" - integrity sha512-n5tKOjMaZ1fksIpQbjERuqCyfgec/m9pferkFQbLmWtqLUdmt12hNhjSwsmPdqeiG2NkITOQhr1VYIwWSAceiA== - -caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= - -chalk@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - -chalk@^2.0.0, chalk@^2.3.2, chalk@^2.4.1, chalk@^2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chokidar@^2.0.2, chokidar@^2.0.3, chokidar@^2.1.6: - version "2.1.6" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.6.tgz#b6cad653a929e244ce8a834244164d241fa954c5" - integrity sha512-V2jUo67OKkc6ySiRpJrjlpJKl9kDuG+Xb8VgsGzb+aEouhgS1D0weyPU4lEzdAcsCAvrih2J2BqyXqHWvVLw5g== - dependencies: - anymatch "^2.0.0" - async-each "^1.0.1" - braces "^2.3.2" - glob-parent "^3.1.0" - inherits "^2.0.3" - is-binary-path "^1.0.0" - is-glob "^4.0.0" - normalize-path "^3.0.0" - path-is-absolute "^1.0.0" - readdirp "^2.2.1" - upath "^1.1.1" - optionalDependencies: - fsevents "^1.2.7" - -chownr@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.2.tgz#a18f1e0b269c8a6a5d3c86eb298beb14c3dd7bf6" - integrity sha512-GkfeAQh+QNy3wquu9oIZr6SS5x7wGdSgNQvD10X3r+AZr1Oys22HW8kAmDMvNg2+Dm0TeGaEuO8gFwdBXxwO8A== - -chrome-trace-event@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz#234090ee97c7d4ad1a2c4beae27505deffc608a4" - integrity sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ== - dependencies: - tslib "^1.9.0" - -ci-info@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497" - integrity sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A== - -cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" - integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -class-utils@^0.3.5: - version "0.3.6" - resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" - integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== - dependencies: - arr-union "^3.1.0" - define-property "^0.2.5" - isobject "^3.0.0" - static-extend "^0.1.1" - -clean-css@4.2.x: - version "4.2.1" - resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.1.tgz#2d411ef76b8569b6d0c84068dabe85b0aa5e5c17" - integrity sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g== - dependencies: - source-map "~0.6.0" - -clipboard@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/clipboard/-/clipboard-2.0.4.tgz#836dafd66cf0fea5d71ce5d5b0bf6e958009112d" - integrity sha512-Vw26VSLRpJfBofiVaFb/I8PVfdI1OxKcYShe6fm0sP/DtmiWQNCjhM/okTvdCo0G+lMMm1rMYbk4IK4x1X+kgQ== - dependencies: - good-listener "^1.2.2" - select "^1.1.2" - tiny-emitter "^2.0.0" - -cliui@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" - integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ== - dependencies: - string-width "^2.1.1" - strip-ansi "^4.0.0" - wrap-ansi "^2.0.0" - -coa@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/coa/-/coa-2.0.2.tgz#43f6c21151b4ef2bf57187db0d73de229e3e7ec3" - integrity sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA== - dependencies: - "@types/q" "^1.5.1" - chalk "^2.4.1" - q "^1.1.2" - -code-point-at@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= - -collection-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" - integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= - dependencies: - map-visit "^1.0.0" - object-visit "^1.0.0" - -color-convert@^1.9.0, color-convert@^1.9.1: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= - -color-name@^1.0.0: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -color-string@^1.5.2: - version "1.5.3" - resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.3.tgz#c9bbc5f01b58b5492f3d6857459cb6590ce204cc" - integrity sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw== - dependencies: - color-name "^1.0.0" - simple-swizzle "^0.2.2" - -color@^3.0.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/color/-/color-3.1.2.tgz#68148e7f85d41ad7649c5fa8c8106f098d229e10" - integrity sha512-vXTJhHebByxZn3lDvDJYw4lR5+uB3vuoHsuYA5AKuxRVn5wzzIfQKGLBmgdVRHKTJYeK5rvJcHnrd0Li49CFpg== - dependencies: - color-convert "^1.9.1" - color-string "^1.5.2" - -combined-stream@^1.0.6, combined-stream@~1.0.6: - version "1.0.8" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" - integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== - dependencies: - delayed-stream "~1.0.0" - -commander@2.17.x: - version "2.17.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf" - integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg== - -commander@^2.20.0: - version "2.20.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" - integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ== - -commander@~2.19.0: - version "2.19.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" - integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg== - -commondir@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" - integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= - -component-emitter@^1.2.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" - integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== - -compressible@~2.0.16: - version "2.0.17" - resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.17.tgz#6e8c108a16ad58384a977f3a482ca20bff2f38c1" - integrity sha512-BGHeLCK1GV7j1bSmQQAi26X+GgWcTjLr/0tzSvMCl3LH1w1IJ4PFSPoV5316b30cneTziC+B1a+3OjoSUcQYmw== - dependencies: - mime-db ">= 1.40.0 < 2" - -compression@^1.7.4: - version "1.7.4" - resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" - integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== - dependencies: - accepts "~1.3.5" - bytes "3.0.0" - compressible "~2.0.16" - debug "2.6.9" - on-headers "~1.0.2" - safe-buffer "5.1.2" - vary "~1.1.2" - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= - -concat-stream@^1.5.0: - version "1.6.2" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" - integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== - dependencies: - buffer-from "^1.0.0" - inherits "^2.0.3" - readable-stream "^2.2.2" - typedarray "^0.0.6" - -connect-history-api-fallback@^1.5.0, connect-history-api-fallback@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc" - integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg== - -consola@^2.6.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/consola/-/consola-2.9.0.tgz#57760e3a65a53ec27337f4add31505802d902278" - integrity sha512-34Iue+LRcWbndFIfZc5boNizWlsrRjqIBJZTe591vImgbnq7nx2EzlrLtANj9TH2Fxm7puFJBJAOk5BhvZOddQ== - -console-browserify@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" - integrity sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA= - dependencies: - date-now "^0.1.4" - -console-control-strings@^1.0.0, console-control-strings@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" - integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= - -consolidate@^0.15.1: - version "0.15.1" - resolved "https://registry.yarnpkg.com/consolidate/-/consolidate-0.15.1.tgz#21ab043235c71a07d45d9aad98593b0dba56bab7" - integrity sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw== - dependencies: - bluebird "^3.1.1" - -constants-browserify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" - integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= - -content-disposition@0.5.3: - version "0.5.3" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" - integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== - dependencies: - safe-buffer "5.1.2" - -content-type@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" - integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== - -convert-source-map@^1.1.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20" - integrity sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A== - dependencies: - safe-buffer "~5.1.1" - -cookie-signature@1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" - integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= - -cookie@0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" - integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== - -copy-concurrently@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" - integrity sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A== - dependencies: - aproba "^1.1.1" - fs-write-stream-atomic "^1.0.8" - iferr "^0.1.5" - mkdirp "^0.5.1" - rimraf "^2.5.4" - run-queue "^1.0.0" - -copy-descriptor@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" - integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= - -copy-webpack-plugin@^5.0.2: - version "5.0.3" - resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-5.0.3.tgz#2179e3c8fd69f13afe74da338896f1f01a875b5c" - integrity sha512-PlZRs9CUMnAVylZq+vg2Juew662jWtwOXOqH4lbQD9ZFhRG9R7tVStOgHt21CBGVq7k5yIJaz8TXDLSjV+Lj8Q== - dependencies: - cacache "^11.3.2" - find-cache-dir "^2.1.0" - glob-parent "^3.1.0" - globby "^7.1.1" - is-glob "^4.0.1" - loader-utils "^1.2.3" - minimatch "^3.0.4" - normalize-path "^3.0.0" - p-limit "^2.2.0" - schema-utils "^1.0.0" - serialize-javascript "^1.7.0" - webpack-log "^2.0.0" - -core-js@^2.6.5: - version "2.6.9" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.9.tgz#6b4b214620c834152e179323727fc19741b084f2" - integrity sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A== - -core-util-is@1.0.2, core-util-is@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= - -cosmiconfig@^5.0.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a" - integrity sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA== - dependencies: - import-fresh "^2.0.0" - is-directory "^0.3.1" - js-yaml "^3.13.1" - parse-json "^4.0.0" - -create-ecdh@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff" - integrity sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw== - dependencies: - bn.js "^4.1.0" - elliptic "^6.0.0" - -create-hash@^1.1.0, create-hash@^1.1.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" - integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== - dependencies: - cipher-base "^1.0.1" - inherits "^2.0.1" - md5.js "^1.3.4" - ripemd160 "^2.0.1" - sha.js "^2.4.0" - -create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: - version "1.1.7" - resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" - integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== - dependencies: - cipher-base "^1.0.3" - create-hash "^1.1.0" - inherits "^2.0.1" - ripemd160 "^2.0.0" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - -cross-spawn@^6.0.0, cross-spawn@^6.0.5: - version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== - dependencies: - nice-try "^1.0.4" - path-key "^2.0.1" - semver "^5.5.0" - shebang-command "^1.2.0" - which "^1.2.9" - -crypto-browserify@^3.11.0: - version "3.12.0" - resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" - integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== - dependencies: - browserify-cipher "^1.0.0" - browserify-sign "^4.0.0" - create-ecdh "^4.0.0" - create-hash "^1.1.0" - create-hmac "^1.1.0" - diffie-hellman "^5.0.0" - inherits "^2.0.1" - pbkdf2 "^3.0.3" - public-encrypt "^4.0.0" - randombytes "^2.0.0" - randomfill "^1.0.3" - -css-color-names@0.0.4, css-color-names@^0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" - integrity sha1-gIrcLnnPhHOAabZGyyDsJ762KeA= - -css-declaration-sorter@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz#c198940f63a76d7e36c1e71018b001721054cb22" - integrity sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA== - dependencies: - postcss "^7.0.1" - timsort "^0.3.0" - -css-loader@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-2.1.1.tgz#d8254f72e412bb2238bb44dd674ffbef497333ea" - integrity sha512-OcKJU/lt232vl1P9EEDamhoO9iKY3tIjY5GU+XDLblAykTdgs6Ux9P1hTHve8nFKy5KPpOXOsVI/hIwi3841+w== - dependencies: - camelcase "^5.2.0" - icss-utils "^4.1.0" - loader-utils "^1.2.3" - normalize-path "^3.0.0" - postcss "^7.0.14" - postcss-modules-extract-imports "^2.0.0" - postcss-modules-local-by-default "^2.0.6" - postcss-modules-scope "^2.1.0" - postcss-modules-values "^2.0.0" - postcss-value-parser "^3.3.0" - schema-utils "^1.0.0" - -css-parse@1.7.x: - version "1.7.0" - resolved "https://registry.yarnpkg.com/css-parse/-/css-parse-1.7.0.tgz#321f6cf73782a6ff751111390fc05e2c657d8c9b" - integrity sha1-Mh9s9zeCpv91ERE5D8BeLGV9jJs= - -css-select-base-adapter@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz#3b2ff4972cc362ab88561507a95408a1432135d7" - integrity sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w== - -css-select@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858" - integrity sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg= - dependencies: - boolbase "~1.0.0" - css-what "2.1" - domutils "1.5.1" - nth-check "~1.0.1" - -css-select@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/css-select/-/css-select-2.0.2.tgz#ab4386cec9e1f668855564b17c3733b43b2a5ede" - integrity sha512-dSpYaDVoWaELjvZ3mS6IKZM/y2PMPa/XYoEfYNZePL4U/XgyxZNroHEHReDx/d+VgXh9VbCTtFqLkFbmeqeaRQ== - dependencies: - boolbase "^1.0.0" - css-what "^2.1.2" - domutils "^1.7.0" - nth-check "^1.0.2" - -css-tree@1.0.0-alpha.29: - version "1.0.0-alpha.29" - resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.29.tgz#3fa9d4ef3142cbd1c301e7664c1f352bd82f5a39" - integrity sha512-sRNb1XydwkW9IOci6iB2xmy8IGCj6r/fr+JWitvJ2JxQRPzN3T4AGGVWCMlVmVwM1gtgALJRmGIlWv5ppnGGkg== - dependencies: - mdn-data "~1.1.0" - source-map "^0.5.3" - -css-tree@1.0.0-alpha.33: - version "1.0.0-alpha.33" - resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.33.tgz#970e20e5a91f7a378ddd0fc58d0b6c8d4f3be93e" - integrity sha512-SPt57bh5nQnpsTBsx/IXbO14sRc9xXu5MtMAVuo0BaQQmyf0NupNPPSoMaqiAF5tDFafYsTkfeH4Q/HCKXkg4w== - dependencies: - mdn-data "2.0.4" - source-map "^0.5.3" - -css-unit-converter@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/css-unit-converter/-/css-unit-converter-1.1.1.tgz#d9b9281adcfd8ced935bdbaba83786897f64e996" - integrity sha1-2bkoGtz9jO2TW9urqDeGiX9k6ZY= - -css-what@2.1, css-what@^2.1.2: - version "2.1.3" - resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2" - integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg== - -cssesc@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-2.0.0.tgz#3b13bd1bb1cb36e1bcb5a4dcd27f54c5dcb35703" - integrity sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg== - -cssesc@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" - integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== - -cssnano-preset-default@^4.0.7: - version "4.0.7" - resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-4.0.7.tgz#51ec662ccfca0f88b396dcd9679cdb931be17f76" - integrity sha512-x0YHHx2h6p0fCl1zY9L9roD7rnlltugGu7zXSKQx6k2rYw0Hi3IqxcoAGF7u9Q5w1nt7vK0ulxV8Lo+EvllGsA== - dependencies: - css-declaration-sorter "^4.0.1" - cssnano-util-raw-cache "^4.0.1" - postcss "^7.0.0" - postcss-calc "^7.0.1" - postcss-colormin "^4.0.3" - postcss-convert-values "^4.0.1" - postcss-discard-comments "^4.0.2" - postcss-discard-duplicates "^4.0.2" - postcss-discard-empty "^4.0.1" - postcss-discard-overridden "^4.0.1" - postcss-merge-longhand "^4.0.11" - postcss-merge-rules "^4.0.3" - postcss-minify-font-values "^4.0.2" - postcss-minify-gradients "^4.0.2" - postcss-minify-params "^4.0.2" - postcss-minify-selectors "^4.0.2" - postcss-normalize-charset "^4.0.1" - postcss-normalize-display-values "^4.0.2" - postcss-normalize-positions "^4.0.2" - postcss-normalize-repeat-style "^4.0.2" - postcss-normalize-string "^4.0.2" - postcss-normalize-timing-functions "^4.0.2" - postcss-normalize-unicode "^4.0.1" - postcss-normalize-url "^4.0.1" - postcss-normalize-whitespace "^4.0.2" - postcss-ordered-values "^4.1.2" - postcss-reduce-initial "^4.0.3" - postcss-reduce-transforms "^4.0.2" - postcss-svgo "^4.0.2" - postcss-unique-selectors "^4.0.1" - -cssnano-util-get-arguments@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz#ed3a08299f21d75741b20f3b81f194ed49cc150f" - integrity sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8= - -cssnano-util-get-match@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz#c0e4ca07f5386bb17ec5e52250b4f5961365156d" - integrity sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0= - -cssnano-util-raw-cache@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz#b26d5fd5f72a11dfe7a7846fb4c67260f96bf282" - integrity sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA== - dependencies: - postcss "^7.0.0" - -cssnano-util-same-parent@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz#574082fb2859d2db433855835d9a8456ea18bbf3" - integrity sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q== - -cssnano@^4.1.10: - version "4.1.10" - resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-4.1.10.tgz#0ac41f0b13d13d465487e111b778d42da631b8b2" - integrity sha512-5wny+F6H4/8RgNlaqab4ktc3e0/blKutmq8yNlBFXA//nSFFAqAngjNVRzUvCgYROULmZZUoosL/KSoZo5aUaQ== - dependencies: - cosmiconfig "^5.0.0" - cssnano-preset-default "^4.0.7" - is-resolvable "^1.0.0" - postcss "^7.0.0" - -csso@^3.5.1: - version "3.5.1" - resolved "https://registry.yarnpkg.com/csso/-/csso-3.5.1.tgz#7b9eb8be61628973c1b261e169d2f024008e758b" - integrity sha512-vrqULLffYU1Q2tLdJvaCYbONStnfkfimRxXNaGjxMldI0C7JPBC4rB1RyjhfdZ4m1frm8pM9uRPKH3d2knZ8gg== - dependencies: - css-tree "1.0.0-alpha.29" - -cyclist@~0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640" - integrity sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA= - -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= - dependencies: - assert-plus "^1.0.0" - -date-now@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" - integrity sha1-6vQ5/U1ISK105cx9vvIAZyueNFs= - -de-indent@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d" - integrity sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0= - -debug@*, debug@^4.1.0, debug@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" - integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== - dependencies: - ms "^2.1.1" - -debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.9: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - -debug@=3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" - integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== - dependencies: - ms "2.0.0" - -debug@^3.2.5, debug@^3.2.6: - version "3.2.6" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" - integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== - dependencies: - ms "^2.1.1" - -decamelize@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= - -decode-uri-component@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" - integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= - -deep-equal@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" - integrity sha1-9dJgKStmDghO/0zbyfCK0yR0SLU= - -deep-extend@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" - integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== - -deepmerge@^1.5.2: - version "1.5.2" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-1.5.2.tgz#10499d868844cdad4fee0842df8c7f6f0c95a753" - integrity sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ== - -default-gateway@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-4.2.0.tgz#167104c7500c2115f6dd69b0a536bb8ed720552b" - integrity sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA== - dependencies: - execa "^1.0.0" - ip-regex "^2.1.0" - -define-properties@^1.1.2, define-properties@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" - integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== - dependencies: - object-keys "^1.0.12" - -define-property@^0.2.5: - version "0.2.5" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" - integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= - dependencies: - is-descriptor "^0.1.0" - -define-property@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" - integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= - dependencies: - is-descriptor "^1.0.0" - -define-property@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" - integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== - dependencies: - is-descriptor "^1.0.2" - isobject "^3.0.1" - -del@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/del/-/del-4.1.1.tgz#9e8f117222ea44a31ff3a156c049b99052a9f0b4" - integrity sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ== - dependencies: - "@types/glob" "^7.1.1" - globby "^6.1.0" - is-path-cwd "^2.0.0" - is-path-in-cwd "^2.0.0" - p-map "^2.0.0" - pify "^4.0.1" - rimraf "^2.6.3" - -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= - -delegate@^3.1.2: - version "3.2.0" - resolved "https://registry.yarnpkg.com/delegate/-/delegate-3.2.0.tgz#b66b71c3158522e8ab5744f720d8ca0c2af59166" - integrity sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw== - -delegates@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" - integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= - -depd@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" - integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= - -des.js@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc" - integrity sha1-wHTS4qpqipoH29YfmhXCzYPsjsw= - dependencies: - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - -destroy@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" - integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= - -detect-libc@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" - integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= - -detect-node@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c" - integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw== - -diacritics@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/diacritics/-/diacritics-1.3.0.tgz#3efa87323ebb863e6696cebb0082d48ff3d6f7a1" - integrity sha1-PvqHMj67hj5mls67AILUj/PW96E= - -diffie-hellman@^5.0.0: - version "5.0.3" - resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" - integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== - dependencies: - bn.js "^4.1.0" - miller-rabin "^4.0.0" - randombytes "^2.0.0" - -dir-glob@^2.0.0, dir-glob@^2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.2.2.tgz#fa09f0694153c8918b18ba0deafae94769fc50c4" - integrity sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw== - dependencies: - path-type "^3.0.0" - -dns-equal@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" - integrity sha1-s55/HabrCnW6nBcySzR1PEfgZU0= - -dns-packet@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-1.3.1.tgz#12aa426981075be500b910eedcd0b47dd7deda5a" - integrity sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg== - dependencies: - ip "^1.1.0" - safe-buffer "^5.0.1" - -dns-txt@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/dns-txt/-/dns-txt-2.0.2.tgz#b91d806f5d27188e4ab3e7d107d881a1cc4642b6" - integrity sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY= - dependencies: - buffer-indexof "^1.0.0" - -docsearch.js@^2.5.2: - version "2.6.3" - resolved "https://registry.yarnpkg.com/docsearch.js/-/docsearch.js-2.6.3.tgz#57cb4600d3b6553c677e7cbbe6a734593e38625d" - integrity sha512-GN+MBozuyz664ycpZY0ecdQE0ND/LSgJKhTLA0/v3arIS3S1Rpf2OJz6A35ReMsm91V5apcmzr5/kM84cvUg+A== - dependencies: - algoliasearch "^3.24.5" - autocomplete.js "0.36.0" - hogan.js "^3.0.2" - request "^2.87.0" - stack-utils "^1.0.1" - to-factory "^1.0.0" - zepto "^1.2.0" - -dom-converter@^0.2: - version "0.2.0" - resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768" - integrity sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA== - dependencies: - utila "~0.4" - -dom-serializer@0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.1.tgz#1ec4059e284babed36eec2941d4a970a189ce7c0" - integrity sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA== - dependencies: - domelementtype "^1.3.0" - entities "^1.1.1" - -dom-walk@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018" - integrity sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg= - -domain-browser@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" - integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== - -domelementtype@1, domelementtype@^1.3.0, domelementtype@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" - integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== - -domhandler@^2.3.0: - version "2.4.2" - resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803" - integrity sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA== - dependencies: - domelementtype "1" - -domutils@1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" - integrity sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8= - dependencies: - dom-serializer "0" - domelementtype "1" - -domutils@^1.5.1, domutils@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" - integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg== - dependencies: - dom-serializer "0" - domelementtype "1" - -dot-prop@^4.1.1: - version "4.2.0" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" - integrity sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ== - dependencies: - is-obj "^1.0.0" - -duplexify@^3.4.2, duplexify@^3.6.0: - version "3.7.1" - resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" - integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== - dependencies: - end-of-stream "^1.0.0" - inherits "^2.0.1" - readable-stream "^2.0.0" - stream-shift "^1.0.0" - -ecc-jsbn@~0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" - integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= - dependencies: - jsbn "~0.1.0" - safer-buffer "^2.1.0" - -ee-first@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= - -electron-to-chromium@^1.3.191: - version "1.3.194" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.194.tgz#a96452a96d4539131957aade9f634a45721f2819" - integrity sha512-w0LHR2YD9Ex1o+Sz4IN2hYzCB8vaFtMNW+yJcBf6SZlVqgFahkne/4rGVJdk4fPF98Gch9snY7PiabOh+vqHNg== - -elliptic@^6.0.0: - version "6.5.0" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.0.tgz#2b8ed4c891b7de3200e14412a5b8248c7af505ca" - integrity sha512-eFOJTMyCYb7xtE/caJ6JJu+bhi67WCYNbkGSknu20pmM8Ke/bqOfdnZWxyoGN26JgfxTbXrsCkEw4KheCT/KGg== - dependencies: - bn.js "^4.4.0" - brorand "^1.0.1" - hash.js "^1.0.0" - hmac-drbg "^1.0.0" - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.0" - -emoji-regex@^7.0.1: - version "7.0.3" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" - integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== - -emojis-list@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" - integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k= - -encodeurl@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" - integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= - -end-of-stream@^1.0.0, end-of-stream@^1.1.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" - integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q== - dependencies: - once "^1.4.0" - -enhanced-resolve@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz#41c7e0bfdfe74ac1ffe1e57ad6a5c6c9f3742a7f" - integrity sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng== - dependencies: - graceful-fs "^4.1.2" - memory-fs "^0.4.0" - tapable "^1.0.0" - -entities@^1.1.1, entities@~1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" - integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w== - -envify@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/envify/-/envify-4.1.0.tgz#f39ad3db9d6801b4e6b478b61028d3f0b6819f7e" - integrity sha512-IKRVVoAYr4pIx4yIWNsz9mOsboxlNXiu7TNBnem/K/uTHdkyzXWDzHCK7UTolqBbgaBz0tQHsD3YNls0uIIjiw== - dependencies: - esprima "^4.0.0" - through "~2.3.4" - -envinfo@^7.2.0: - version "7.3.1" - resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.3.1.tgz#892e42f7bf858b3446d9414ad240dbaf8da52f09" - integrity sha512-GvXiDTqLYrORVSCuJCsWHPXF5BFvoWMQA9xX4YVjPT1jyS3aZEHUBwjzxU/6LTPF9ReHgVEbX7IEN5UvSXHw/A== - -errno@^0.1.3, errno@~0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" - integrity sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg== - dependencies: - prr "~1.0.1" - -error-ex@^1.3.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" - integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== - dependencies: - is-arrayish "^0.2.1" - -es-abstract@^1.12.0, es-abstract@^1.5.1: - version "1.13.0" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.13.0.tgz#ac86145fdd5099d8dd49558ccba2eaf9b88e24e9" - integrity sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg== - dependencies: - es-to-primitive "^1.2.0" - function-bind "^1.1.1" - has "^1.0.3" - is-callable "^1.1.4" - is-regex "^1.0.4" - object-keys "^1.0.12" - -es-to-primitive@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.0.tgz#edf72478033456e8dda8ef09e00ad9650707f377" - integrity sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg== - dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" - -es6-promise@^4.1.0: - version "4.2.8" - resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" - integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== - -escape-html@^1.0.3, escape-html@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" - integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= - -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= - -eslint-scope@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" - integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg== - dependencies: - esrecurse "^4.1.0" - estraverse "^4.1.1" - -esprima@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - -esrecurse@^4.1.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" - integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ== - dependencies: - estraverse "^4.1.0" - -estraverse@^4.1.0, estraverse@^4.1.1: - version "4.2.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" - integrity sha1-De4/7TH81GlhjOc0IJn8GvoL2xM= - -esutils@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" - integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs= - -etag@~1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" - integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= - -eventemitter3@^3.0.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7" - integrity sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q== - -events@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" - integrity sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ= - -events@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/events/-/events-3.0.0.tgz#9a0a0dfaf62893d92b875b8f2698ca4114973e88" - integrity sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA== - -eventsource@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.0.7.tgz#8fbc72c93fcd34088090bc0a4e64f4b5cee6d8d0" - integrity sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ== - dependencies: - original "^1.0.0" - -evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" - integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== - dependencies: - md5.js "^1.3.4" - safe-buffer "^5.1.1" - -execa@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" - integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== - dependencies: - cross-spawn "^6.0.0" - get-stream "^4.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - -expand-brackets@^2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" - integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= - dependencies: - debug "^2.3.3" - define-property "^0.2.5" - extend-shallow "^2.0.1" - posix-character-classes "^0.1.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -express@^4.17.1: - version "4.17.1" - resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" - integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== - dependencies: - accepts "~1.3.7" - array-flatten "1.1.1" - body-parser "1.19.0" - content-disposition "0.5.3" - content-type "~1.0.4" - cookie "0.4.0" - cookie-signature "1.0.6" - debug "2.6.9" - depd "~1.1.2" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - finalhandler "~1.1.2" - fresh "0.5.2" - merge-descriptors "1.0.1" - methods "~1.1.2" - on-finished "~2.3.0" - parseurl "~1.3.3" - path-to-regexp "0.1.7" - proxy-addr "~2.0.5" - qs "6.7.0" - range-parser "~1.2.1" - safe-buffer "5.1.2" - send "0.17.1" - serve-static "1.14.1" - setprototypeof "1.1.1" - statuses "~1.5.0" - type-is "~1.6.18" - utils-merge "1.0.1" - vary "~1.1.2" - -extend-shallow@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" - integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= - dependencies: - is-extendable "^0.1.0" - -extend-shallow@^3.0.0, extend-shallow@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" - integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= - dependencies: - assign-symbols "^1.0.0" - is-extendable "^1.0.1" - -extend@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" - integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== - -extglob@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" - integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== - dependencies: - array-unique "^0.3.2" - define-property "^1.0.0" - expand-brackets "^2.1.4" - extend-shallow "^2.0.1" - fragment-cache "^0.2.1" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -extsprintf@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= - -extsprintf@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" - integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= - -fast-deep-equal@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" - integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= - -fast-glob@^2.2.6: - version "2.2.7" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.7.tgz#6953857c3afa475fff92ee6015d52da70a4cd39d" - integrity sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw== - dependencies: - "@mrmlnc/readdir-enhanced" "^2.2.1" - "@nodelib/fs.stat" "^1.1.2" - glob-parent "^3.1.0" - is-glob "^4.0.0" - merge2 "^1.2.3" - micromatch "^3.1.10" - -fast-json-stable-stringify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" - integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= - -faye-websocket@^0.10.0: - version "0.10.0" - resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" - integrity sha1-TkkvjQTftviQA1B/btvy1QHnxvQ= - dependencies: - websocket-driver ">=0.5.1" - -faye-websocket@~0.11.1: - version "0.11.3" - resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.3.tgz#5c0e9a8968e8912c286639fde977a8b209f2508e" - integrity sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA== - dependencies: - websocket-driver ">=0.5.1" - -figgy-pudding@^3.5.1: - version "3.5.1" - resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790" - integrity sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w== - -figures@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-3.0.0.tgz#756275c964646163cc6f9197c7a0295dbfd04de9" - integrity sha512-HKri+WoWoUgr83pehn/SIgLOMZ9nAWC6dcGj26RY2R4F50u4+RTUz0RCrUlOV3nKRAICW1UGzyb+kcX2qK1S/g== - dependencies: - escape-string-regexp "^1.0.5" - -file-loader@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-3.0.1.tgz#f8e0ba0b599918b51adfe45d66d1e771ad560faa" - integrity sha512-4sNIOXgtH/9WZq4NvlfU3Opn5ynUsqBwSLyM+I7UOwdGigTBYfVVQEwe/msZNX/j4pCJTIM14Fsw66Svo1oVrw== - dependencies: - loader-utils "^1.0.2" - schema-utils "^1.0.0" - -fill-range@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" - integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= - dependencies: - extend-shallow "^2.0.1" - is-number "^3.0.0" - repeat-string "^1.6.1" - to-regex-range "^2.1.0" - -finalhandler@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" - integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== - dependencies: - debug "2.6.9" - encodeurl "~1.0.2" - escape-html "~1.0.3" - on-finished "~2.3.0" - parseurl "~1.3.3" - statuses "~1.5.0" - unpipe "~1.0.0" - -find-babel-config@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/find-babel-config/-/find-babel-config-1.2.0.tgz#a9b7b317eb5b9860cda9d54740a8c8337a2283a2" - integrity sha512-jB2CHJeqy6a820ssiqwrKMeyC6nNdmrcgkKWJWmpoxpE8RKciYJXCcXRq1h2AzCo5I5BJeN2tkGEO3hLTuePRA== - dependencies: - json5 "^0.5.1" - path-exists "^3.0.0" - -find-cache-dir@^2.0.0, find-cache-dir@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" - integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== - dependencies: - commondir "^1.0.1" - make-dir "^2.0.0" - pkg-dir "^3.0.0" - -find-up@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" - integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= - dependencies: - locate-path "^2.0.0" - -find-up@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" - integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== - dependencies: - locate-path "^3.0.0" - -flush-write-stream@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8" - integrity sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w== - dependencies: - inherits "^2.0.3" - readable-stream "^2.3.6" - -follow-redirects@1.5.10: - version "1.5.10" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a" - integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ== - dependencies: - debug "=3.1.0" - -follow-redirects@^1.0.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.7.0.tgz#489ebc198dc0e7f64167bd23b03c4c19b5784c76" - integrity sha512-m/pZQy4Gj287eNy94nivy5wchN3Kp+Q5WgUPNy5lJSZ3sgkVKSYV/ZChMAQVIgx1SqfZ2zBZtPA2YlXIWxxJOQ== - dependencies: - debug "^3.2.6" - -for-in@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" - integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= - -foreach@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" - integrity sha1-C+4AUBiusmDQo6865ljdATbsG5k= - -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= - -form-data@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" - integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.6" - mime-types "^2.1.12" - -forwarded@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" - integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= - -fragment-cache@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" - integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= - dependencies: - map-cache "^0.2.2" - -fresh@0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" - integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= - -from2@^2.1.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" - integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= - dependencies: - inherits "^2.0.1" - readable-stream "^2.0.0" - -fs-extra@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" - integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== - dependencies: - graceful-fs "^4.1.2" - jsonfile "^4.0.0" - universalify "^0.1.0" - -fs-minipass@^1.2.5: - version "1.2.6" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.6.tgz#2c5cc30ded81282bfe8a0d7c7c1853ddeb102c07" - integrity sha512-crhvyXcMejjv3Z5d2Fa9sf5xLYVCF5O1c71QxbVnbLsmYMBEvDAftewesN/HhY03YRoA7zOMxjNGrF5svGaaeQ== - dependencies: - minipass "^2.2.1" - -fs-write-stream-atomic@^1.0.8: - version "1.0.10" - resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" - integrity sha1-tH31NJPvkR33VzHnCp3tAYnbQMk= - dependencies: - graceful-fs "^4.1.2" - iferr "^0.1.5" - imurmurhash "^0.1.4" - readable-stream "1 || 2" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= - -fsevents@^1.2.7: - version "1.2.9" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.9.tgz#3f5ed66583ccd6f400b5a00db6f7e861363e388f" - integrity sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw== - dependencies: - nan "^2.12.1" - node-pre-gyp "^0.12.0" - -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== - -gauge@~2.7.3: - version "2.7.4" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" - integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= - dependencies: - aproba "^1.0.3" - console-control-strings "^1.0.0" - has-unicode "^2.0.0" - object-assign "^4.1.0" - signal-exit "^3.0.0" - string-width "^1.0.1" - strip-ansi "^3.0.1" - wide-align "^1.1.0" - -get-caller-file@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" - integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== - -get-stream@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" - integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== - dependencies: - pump "^3.0.0" - -get-value@^2.0.3, get-value@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" - integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= - -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= - dependencies: - assert-plus "^1.0.0" - -glob-parent@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" - integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= - dependencies: - is-glob "^3.1.0" - path-dirname "^1.0.0" - -glob-to-regexp@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" - integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs= - -glob@7.0.x: - version "7.0.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.0.6.tgz#211bafaf49e525b8cd93260d14ab136152b3f57a" - integrity sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo= - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.2" - once "^1.3.0" - path-is-absolute "^1.0.0" - -glob@^7.0.3, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: - version "7.1.4" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" - integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -global@^4.3.2: - version "4.4.0" - resolved "https://registry.yarnpkg.com/global/-/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406" - integrity sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w== - dependencies: - min-document "^2.19.0" - process "^0.11.10" - -globals@^11.1.0: - version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - -globby@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" - integrity sha1-9abXDoOV4hyFj7BInWTfAkJNUGw= - dependencies: - array-union "^1.0.1" - glob "^7.0.3" - object-assign "^4.0.1" - pify "^2.0.0" - pinkie-promise "^2.0.0" - -globby@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/globby/-/globby-7.1.1.tgz#fb2ccff9401f8600945dfada97440cca972b8680" - integrity sha1-+yzP+UAfhgCUXfral0QMypcrhoA= - dependencies: - array-union "^1.0.1" - dir-glob "^2.0.0" - glob "^7.1.2" - ignore "^3.3.5" - pify "^3.0.0" - slash "^1.0.0" - -globby@^9.2.0: - version "9.2.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-9.2.0.tgz#fd029a706c703d29bdd170f4b6db3a3f7a7cb63d" - integrity sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg== - dependencies: - "@types/glob" "^7.1.1" - array-union "^1.0.2" - dir-glob "^2.2.2" - fast-glob "^2.2.6" - glob "^7.1.3" - ignore "^4.0.3" - pify "^4.0.1" - slash "^2.0.0" - -good-listener@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/good-listener/-/good-listener-1.2.2.tgz#d53b30cdf9313dffb7dc9a0d477096aa6d145c50" - integrity sha1-1TswzfkxPf+33JoNR3CWqm0UXFA= - dependencies: - delegate "^3.1.2" - -graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6: - version "4.2.0" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.0.tgz#8d8fdc73977cb04104721cb53666c1ca64cd328b" - integrity sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg== - -gray-matter@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/gray-matter/-/gray-matter-4.0.2.tgz#9aa379e3acaf421193fce7d2a28cebd4518ac454" - integrity sha512-7hB/+LxrOjq/dd8APlK0r24uL/67w7SkYnfwhNFwg/VDIGWGmduTDYf3WNstLW2fbbmRwrDGCVSJ2isuf2+4Hw== - dependencies: - js-yaml "^3.11.0" - kind-of "^6.0.2" - section-matter "^1.0.0" - strip-bom-string "^1.0.0" - -handle-thing@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.0.tgz#0e039695ff50c93fc288557d696f3c1dc6776754" - integrity sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ== - -har-schema@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= - -har-validator@~5.1.0: - version "5.1.3" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" - integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g== - dependencies: - ajv "^6.5.5" - har-schema "^2.0.0" - -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= - dependencies: - ansi-regex "^2.0.0" - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= - -has-symbols@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" - integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q= - -has-unicode@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" - integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= - -has-value@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" - integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= - dependencies: - get-value "^2.0.3" - has-values "^0.1.4" - isobject "^2.0.0" - -has-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" - integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= - dependencies: - get-value "^2.0.6" - has-values "^1.0.0" - isobject "^3.0.0" - -has-values@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" - integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= - -has-values@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" - integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= - dependencies: - is-number "^3.0.0" - kind-of "^4.0.0" - -has@^1.0.0, has@^1.0.1, has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== - dependencies: - function-bind "^1.1.1" - -hash-base@^3.0.0: - version "3.0.4" - resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" - integrity sha1-X8hoaEfs1zSZQDMZprCj8/auSRg= - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -hash-sum@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/hash-sum/-/hash-sum-1.0.2.tgz#33b40777754c6432573c120cc3808bbd10d47f04" - integrity sha1-M7QHd3VMZDJXPBIMw4CLvRDUfwQ= - -hash.js@^1.0.0, hash.js@^1.0.3: - version "1.1.7" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" - integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== - dependencies: - inherits "^2.0.3" - minimalistic-assert "^1.0.1" - -he@1.2.x, he@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" - integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== - -hex-color-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e" - integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ== - -hmac-drbg@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" - integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= - dependencies: - hash.js "^1.0.3" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.1" - -hogan.js@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/hogan.js/-/hogan.js-3.0.2.tgz#4cd9e1abd4294146e7679e41d7898732b02c7bfd" - integrity sha1-TNnhq9QpQUbnZ55B14mHMrAse/0= - dependencies: - mkdirp "0.3.0" - nopt "1.0.10" - -hpack.js@^2.1.6: - version "2.1.6" - resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" - integrity sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI= - dependencies: - inherits "^2.0.1" - obuf "^1.0.0" - readable-stream "^2.0.1" - wbuf "^1.1.0" - -hsl-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/hsl-regex/-/hsl-regex-1.0.0.tgz#d49330c789ed819e276a4c0d272dffa30b18fe6e" - integrity sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4= - -hsla-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/hsla-regex/-/hsla-regex-1.0.0.tgz#c1ce7a3168c8c6614033a4b5f7877f3b225f9c38" - integrity sha1-wc56MWjIxmFAM6S194d/OyJfnDg= - -html-comment-regex@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.2.tgz#97d4688aeb5c81886a364faa0cad1dda14d433a7" - integrity sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ== - -html-entities@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f" - integrity sha1-DfKTUfByEWNRXfueVUPl9u7VFi8= - -html-minifier@^3.2.3: - version "3.5.21" - resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.5.21.tgz#d0040e054730e354db008463593194015212d20c" - integrity sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA== - dependencies: - camel-case "3.0.x" - clean-css "4.2.x" - commander "2.17.x" - he "1.2.x" - param-case "2.1.x" - relateurl "0.2.x" - uglify-js "3.4.x" - -html-tags@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-2.0.0.tgz#10b30a386085f43cede353cc8fa7cb0deeea668b" - integrity sha1-ELMKOGCF9Dzt41PMj6fLDe7qZos= - -htmlparser2@^3.3.0: - version "3.10.1" - resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f" - integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ== - dependencies: - domelementtype "^1.3.1" - domhandler "^2.3.0" - domutils "^1.5.1" - entities "^1.1.1" - inherits "^2.0.1" - readable-stream "^3.1.1" - -http-deceiver@^1.2.7: - version "1.2.7" - resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" - integrity sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc= - -http-errors@1.7.2: - version "1.7.2" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" - integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== - dependencies: - depd "~1.1.2" - inherits "2.0.3" - setprototypeof "1.1.1" - statuses ">= 1.5.0 < 2" - toidentifier "1.0.0" - -http-errors@~1.6.2: - version "1.6.3" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" - integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= - dependencies: - depd "~1.1.2" - inherits "2.0.3" - setprototypeof "1.1.0" - statuses ">= 1.4.0 < 2" - -http-errors@~1.7.2: - version "1.7.3" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" - integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== - dependencies: - depd "~1.1.2" - inherits "2.0.4" - setprototypeof "1.1.1" - statuses ">= 1.5.0 < 2" - toidentifier "1.0.0" - -"http-parser-js@>=0.4.0 <0.4.11": - version "0.4.10" - resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.4.10.tgz#92c9c1374c35085f75db359ec56cc257cbb93fa4" - integrity sha1-ksnBN0w1CF912zWexWzCV8u5P6Q= - -http-proxy-middleware@^0.19.1: - version "0.19.1" - resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz#183c7dc4aa1479150306498c210cdaf96080a43a" - integrity sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q== - dependencies: - http-proxy "^1.17.0" - is-glob "^4.0.0" - lodash "^4.17.11" - micromatch "^3.1.10" - -http-proxy@^1.17.0: - version "1.17.0" - resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.17.0.tgz#7ad38494658f84605e2f6db4436df410f4e5be9a" - integrity sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g== - dependencies: - eventemitter3 "^3.0.0" - follow-redirects "^1.0.0" - requires-port "^1.0.0" - -http-signature@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" - integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= - dependencies: - assert-plus "^1.0.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - -https-browserify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" - integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= - -iconv-lite@0.4.24, iconv-lite@^0.4.4: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - -icss-replace-symbols@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded" - integrity sha1-Bupvg2ead0njhs/h/oEq5dsiPe0= - -icss-utils@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-4.1.1.tgz#21170b53789ee27447c2f47dd683081403f9a467" - integrity sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA== - dependencies: - postcss "^7.0.14" - -ieee754@^1.1.4: - version "1.1.13" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" - integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== - -iferr@^0.1.5: - version "0.1.5" - resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" - integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= - -ignore-walk@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" - integrity sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ== - dependencies: - minimatch "^3.0.4" - -ignore@^3.3.5: - version "3.3.10" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" - integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug== - -ignore@^4.0.3: - version "4.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== - -immediate@^3.2.3: - version "3.2.3" - resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.2.3.tgz#d140fa8f614659bd6541233097ddaac25cdd991c" - integrity sha1-0UD6j2FGWb1lQSMwl92qwlzdmRw= - -import-cwd@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9" - integrity sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk= - dependencies: - import-from "^2.1.0" - -import-fresh@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" - integrity sha1-2BNVwVYS04bGH53dOSLUMEgipUY= - dependencies: - caller-path "^2.0.0" - resolve-from "^3.0.0" - -import-from@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/import-from/-/import-from-2.1.0.tgz#335db7f2a7affd53aaa471d4b8021dee36b7f3b1" - integrity sha1-M1238qev/VOqpHHUuAId7ja387E= - dependencies: - resolve-from "^3.0.0" - -import-local@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d" - integrity sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ== - dependencies: - pkg-dir "^3.0.0" - resolve-cwd "^2.0.0" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= - -indexes-of@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" - integrity sha1-8w9xbI4r00bHtn0985FVZqfAVgc= - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -inherits@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" - integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= - -inherits@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= - -ini@~1.3.0: - version "1.3.5" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" - integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== - -internal-ip@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-4.3.0.tgz#845452baad9d2ca3b69c635a137acb9a0dad0907" - integrity sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg== - dependencies: - default-gateway "^4.2.0" - ipaddr.js "^1.9.0" - -invariant@^2.2.2: - version "2.2.4" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" - integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== - dependencies: - loose-envify "^1.0.0" - -invert-kv@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" - integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA== - -ip-regex@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" - integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= - -ip@^1.1.0, ip@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" - integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= - -ipaddr.js@1.9.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65" - integrity sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA== - -ipaddr.js@^1.9.0: - version "1.9.1" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" - integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== - -is-absolute-url@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6" - integrity sha1-UFMN+4T8yap9vnhS6Do3uTufKqY= - -is-accessor-descriptor@^0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" - integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= - dependencies: - kind-of "^3.0.2" - -is-accessor-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" - integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== - dependencies: - kind-of "^6.0.0" - -is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= - -is-arrayish@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" - integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== - -is-binary-path@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" - integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= - dependencies: - binary-extensions "^1.0.0" - -is-buffer@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" - integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== - -is-buffer@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.3.tgz#4ecf3fcf749cbd1e472689e109ac66261a25e725" - integrity sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw== - -is-callable@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" - integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA== - -is-color-stop@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-color-stop/-/is-color-stop-1.1.0.tgz#cfff471aee4dd5c9e158598fbe12967b5cdad345" - integrity sha1-z/9HGu5N1cnhWFmPvhKWe1za00U= - dependencies: - css-color-names "^0.0.4" - hex-color-regex "^1.1.0" - hsl-regex "^1.0.0" - hsla-regex "^1.0.0" - rgb-regex "^1.0.1" - rgba-regex "^1.0.0" - -is-data-descriptor@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" - integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= - dependencies: - kind-of "^3.0.2" - -is-data-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" - integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== - dependencies: - kind-of "^6.0.0" - -is-date-object@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" - integrity sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY= - -is-descriptor@^0.1.0: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" - integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== - dependencies: - is-accessor-descriptor "^0.1.6" - is-data-descriptor "^0.1.4" - kind-of "^5.0.0" - -is-descriptor@^1.0.0, is-descriptor@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" - integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== - dependencies: - is-accessor-descriptor "^1.0.0" - is-data-descriptor "^1.0.0" - kind-of "^6.0.2" - -is-directory@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" - integrity sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE= - -is-extendable@^0.1.0, is-extendable@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" - integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= - -is-extendable@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" - integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== - dependencies: - is-plain-object "^2.0.4" - -is-extglob@^2.1.0, is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= - -is-fullwidth-code-point@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= - dependencies: - number-is-nan "^1.0.0" - -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= - -is-glob@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" - integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= - dependencies: - is-extglob "^2.1.0" - -is-glob@^4.0.0, is-glob@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" - integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== - dependencies: - is-extglob "^2.1.1" - -is-number@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" - integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= - dependencies: - kind-of "^3.0.2" - -is-obj@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" - integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8= - -is-path-cwd@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb" - integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ== - -is-path-in-cwd@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz#bfe2dca26c69f397265a4009963602935a053acb" - integrity sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ== - dependencies: - is-path-inside "^2.1.0" - -is-path-inside@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-2.1.0.tgz#7c9810587d659a40d27bcdb4d5616eab059494b2" - integrity sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg== - dependencies: - path-is-inside "^1.0.2" - -is-plain-obj@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" - integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= - -is-plain-object@^2.0.3, is-plain-object@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" - integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== - dependencies: - isobject "^3.0.1" - -is-regex@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" - integrity sha1-VRdIm1RwkbCTDglWVM7SXul+lJE= - dependencies: - has "^1.0.1" - -is-resolvable@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" - integrity sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg== - -is-stream@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= - -is-svg@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-3.0.0.tgz#9321dbd29c212e5ca99c4fa9794c714bcafa2f75" - integrity sha512-gi4iHK53LR2ujhLVVj+37Ykh9GLqYHX6JOVXbLAucaG/Cqw9xwdFOjDM2qeifLs1sF1npXXFvDu0r5HNgCMrzQ== - dependencies: - html-comment-regex "^1.1.0" - -is-symbol@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38" - integrity sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw== - dependencies: - has-symbols "^1.0.0" - -is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= - -is-windows@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" - integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== - -is-wsl@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" - integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= - -isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= - -isarray@^2.0.1: - version "2.0.5" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" - integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= - -isobject@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" - integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= - dependencies: - isarray "1.0.0" - -isobject@^3.0.0, isobject@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" - integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= - -isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= - -javascript-stringify@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/javascript-stringify/-/javascript-stringify-1.6.0.tgz#142d111f3a6e3dae8f4a9afd77d45855b5a9cce3" - integrity sha1-FC0RHzpuPa6PSpr9d9RYVbWpzOM= - -js-levenshtein@^1.1.3: - version "1.1.6" - resolved "https://registry.yarnpkg.com/js-levenshtein/-/js-levenshtein-1.1.6.tgz#c6cee58eb3550372df8deb85fad5ce66ce01d59d" - integrity sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g== - -"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -js-yaml@^3.11.0, js-yaml@^3.13.1, js-yaml@^3.8.1: - version "3.13.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" - integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= - -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== - -jsesc@~0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" - integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= - -json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" - integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= - -json-stringify-safe@~5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= - -json3@^3.3.2: - version "3.3.3" - resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.3.tgz#7fc10e375fc5ae42c4705a5cc0aa6f62be305b81" - integrity sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA== - -json5@^0.5.0, json5@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" - integrity sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE= - -json5@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" - integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== - dependencies: - minimist "^1.2.0" - -json5@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.0.tgz#e7a0c62c48285c628d20a10b85c89bb807c32850" - integrity sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ== - dependencies: - minimist "^1.2.0" - -jsonfile@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= - optionalDependencies: - graceful-fs "^4.1.6" - -jsprim@^1.2.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" - integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.2.3" - verror "1.10.0" - -killable@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892" - integrity sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg== - -kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" - integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= - dependencies: - is-buffer "^1.1.5" - -kind-of@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" - integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= - dependencies: - is-buffer "^1.1.5" - -kind-of@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" - integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== - -kind-of@^6.0.0, kind-of@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" - integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== - -last-call-webpack-plugin@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/last-call-webpack-plugin/-/last-call-webpack-plugin-3.0.0.tgz#9742df0e10e3cf46e5c0381c2de90d3a7a2d7555" - integrity sha512-7KI2l2GIZa9p2spzPIVZBYyNKkN+e/SQPpnjlTiPhdbDW3F86tdKKELxKpzJ5sgU19wQWsACULZmpTPYHeWO5w== - dependencies: - lodash "^4.17.5" - webpack-sources "^1.1.0" - -lcid@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" - integrity sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA== - dependencies: - invert-kv "^2.0.0" - -linkify-it@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.2.0.tgz#e3b54697e78bf915c70a38acd78fd09e0058b1cf" - integrity sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw== - dependencies: - uc.micro "^1.0.1" - -load-script@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/load-script/-/load-script-1.0.0.tgz#0491939e0bee5643ee494a7e3da3d2bac70c6ca4" - integrity sha1-BJGTngvuVkPuSUp+PaPSuscMbKQ= - -loader-runner@^2.3.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" - integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw== - -loader-utils@^0.2.16: - version "0.2.17" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.17.tgz#f86e6374d43205a6e6c60e9196f17c0299bfb348" - integrity sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g= - dependencies: - big.js "^3.1.3" - emojis-list "^2.0.0" - json5 "^0.5.0" - object-assign "^4.0.1" - -loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7" - integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA== - dependencies: - big.js "^5.2.2" - emojis-list "^2.0.0" - json5 "^1.0.1" - -locate-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" - integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= - dependencies: - p-locate "^2.0.0" - path-exists "^3.0.0" - -locate-path@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" - integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== - dependencies: - p-locate "^3.0.0" - path-exists "^3.0.0" - -lodash._reinterpolate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" - integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= - -lodash.clonedeep@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" - integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= - -lodash.kebabcase@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz#8489b1cb0d29ff88195cceca448ff6d6cc295c36" - integrity sha1-hImxyw0p/4gZXM7KRI/21swpXDY= - -lodash.memoize@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" - integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= - -lodash.template@^4.4.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab" - integrity sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A== - dependencies: - lodash._reinterpolate "^3.0.0" - lodash.templatesettings "^4.0.0" - -lodash.templatesettings@^4.0.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz#e481310f049d3cf6d47e912ad09313b154f0fb33" - integrity sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ== - dependencies: - lodash._reinterpolate "^3.0.0" - -lodash.throttle@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" - integrity sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ= - -lodash.uniq@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" - integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= - -lodash@^4.17.11, lodash@^4.17.3, lodash@^4.17.5: - version "4.17.15" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" - integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== - -lodash@^4.17.13: - version "4.17.13" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.13.tgz#0bdc3a6adc873d2f4e0c4bac285df91b64fc7b93" - integrity sha512-vm3/XWXfWtRua0FkUyEHBZy8kCPjErNBT9fJx8Zvs+U6zjqPbTUOpkaoum3O5uiA8sm+yNMHXfYkTUHFoMxFNA== - -loglevel@^1.6.3: - version "1.6.3" - resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.3.tgz#77f2eb64be55a404c9fd04ad16d57c1d6d6b1280" - integrity sha512-LoEDv5pgpvWgPF4kNYuIp0qqSJVWak/dML0RY74xlzMZiT9w77teNAwKYKWBTYjlokMirg+o3jBwp+vlLrcfAA== - -loose-envify@^1.0.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== - dependencies: - js-tokens "^3.0.0 || ^4.0.0" - -lower-case@^1.1.1: - version "1.1.4" - resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac" - integrity sha1-miyr0bno4K6ZOkv31YdcOcQujqw= - -lru-cache@^4.1.2: - version "4.1.5" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" - integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== - dependencies: - pseudomap "^1.0.2" - yallist "^2.1.2" - -lru-cache@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" - integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== - dependencies: - yallist "^3.0.2" - -make-dir@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" - integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== - dependencies: - pify "^4.0.1" - semver "^5.6.0" - -mamacro@^0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/mamacro/-/mamacro-0.0.3.tgz#ad2c9576197c9f1abf308d0787865bd975a3f3e4" - integrity sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA== - -map-age-cleaner@^0.1.1: - version "0.1.3" - resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a" - integrity sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w== - dependencies: - p-defer "^1.0.0" - -map-cache@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" - integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= - -map-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" - integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= - dependencies: - object-visit "^1.0.0" - -markdown-it-anchor@^5.0.2: - version "5.2.4" - resolved "https://registry.yarnpkg.com/markdown-it-anchor/-/markdown-it-anchor-5.2.4.tgz#d39306fe4c199705b4479d3036842cf34dcba24f" - integrity sha512-n8zCGjxA3T+Mx1pG8HEgbJbkB8JFUuRkeTZQuIM8iPY6oQ8sWOPRZJDFC9a/pNg2QkHEjjGkhBEl/RSyzaDZ3A== - -markdown-it-chain@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/markdown-it-chain/-/markdown-it-chain-1.3.0.tgz#ccf6fe86c10266bafb4e547380dfd7f277cc17bc" - integrity sha512-XClV8I1TKy8L2qsT9iX3qiV+50ZtcInGXI80CA+DP62sMs7hXlyV/RM3hfwy5O3Ad0sJm9xIwQELgANfESo8mQ== - dependencies: - webpack-chain "^4.9.0" - -markdown-it-container@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/markdown-it-container/-/markdown-it-container-2.0.0.tgz#0019b43fd02eefece2f1960a2895fba81a404695" - integrity sha1-ABm0P9Au7+zi8ZYKKJX7qBpARpU= - -markdown-it-emoji@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/markdown-it-emoji/-/markdown-it-emoji-1.4.0.tgz#9bee0e9a990a963ba96df6980c4fddb05dfb4dcc" - integrity sha1-m+4OmpkKljupbfaYDE/dsF37Tcw= - -markdown-it-meta@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/markdown-it-meta/-/markdown-it-meta-0.0.1.tgz#d75b68f115659caf568e4ad43cb460a471248c39" - integrity sha1-11to8RVlnK9WjkrUPLRgpHEkjDk= - dependencies: - js-yaml "^3.8.1" - -markdown-it-table-of-contents@^0.4.0: - version "0.4.4" - resolved "https://registry.yarnpkg.com/markdown-it-table-of-contents/-/markdown-it-table-of-contents-0.4.4.tgz#3dc7ce8b8fc17e5981c77cc398d1782319f37fbc" - integrity sha512-TAIHTHPwa9+ltKvKPWulm/beozQU41Ab+FIefRaQV1NRnpzwcV9QOe6wXQS5WLivm5Q/nlo0rl6laGkMDZE7Gw== - -markdown-it@^8.4.1, markdown-it@^8.4.2: - version "8.4.2" - resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-8.4.2.tgz#386f98998dc15a37722aa7722084f4020bdd9b54" - integrity sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ== - dependencies: - argparse "^1.0.7" - entities "~1.1.1" - linkify-it "^2.0.0" - mdurl "^1.0.1" - uc.micro "^1.0.5" - -md5.js@^1.3.4: - version "1.3.5" - resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" - integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - safe-buffer "^5.1.2" - -mdn-data@2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.4.tgz#699b3c38ac6f1d728091a64650b65d388502fd5b" - integrity sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA== - -mdn-data@~1.1.0: - version "1.1.4" - resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-1.1.4.tgz#50b5d4ffc4575276573c4eedb8780812a8419f01" - integrity sha512-FSYbp3lyKjyj3E7fMl6rYvUdX0FBXaluGqlFoYESWQlyUTq8R+wp0rkFxoYFqZlHCvsUXGjyJmLQSnXToYhOSA== - -mdurl@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" - integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4= - -media-typer@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" - integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= - -mem@^4.0.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178" - integrity sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w== - dependencies: - map-age-cleaner "^0.1.1" - mimic-fn "^2.0.0" - p-is-promise "^2.0.0" - -memory-fs@^0.4.0, memory-fs@^0.4.1, memory-fs@~0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" - integrity sha1-OpoguEYlI+RHz7x+i7gO1me/xVI= - dependencies: - errno "^0.1.3" - readable-stream "^2.0.1" - -merge-descriptors@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" - integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= - -merge-source-map@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/merge-source-map/-/merge-source-map-1.1.0.tgz#2fdde7e6020939f70906a68f2d7ae685e4c8c646" - integrity sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw== - dependencies: - source-map "^0.6.1" - -merge2@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.2.3.tgz#7ee99dbd69bb6481689253f018488a1b902b0ed5" - integrity sha512-gdUU1Fwj5ep4kplwcmftruWofEFt6lfpkkr3h860CXbAB9c3hGb55EOL2ali0Td5oebvW0E1+3Sr+Ur7XfKpRA== - -methods@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" - integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= - -micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.8: - version "3.1.10" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" - integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - braces "^2.3.1" - define-property "^2.0.2" - extend-shallow "^3.0.2" - extglob "^2.0.4" - fragment-cache "^0.2.1" - kind-of "^6.0.2" - nanomatch "^1.2.9" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.2" - -miller-rabin@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" - integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== - dependencies: - bn.js "^4.0.0" - brorand "^1.0.1" - -mime-db@1.40.0, "mime-db@>= 1.40.0 < 2": - version "1.40.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32" - integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA== - -mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24: - version "2.1.24" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81" - integrity sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ== - dependencies: - mime-db "1.40.0" - -mime@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" - integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== - -mime@^2.0.3, mime@^2.4.2: - version "2.4.4" - resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.4.tgz#bd7b91135fc6b01cde3e9bae33d659b63d8857e5" - integrity sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA== - -mimic-fn@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" - integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== - -min-document@^2.19.0: - version "2.19.0" - resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" - integrity sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU= - dependencies: - dom-walk "^0.1.0" - -mini-css-extract-plugin@0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.6.0.tgz#a3f13372d6fcde912f3ee4cd039665704801e3b9" - integrity sha512-79q5P7YGI6rdnVyIAV4NXpBQJFWdkzJxCim3Kog4078fM0piAaFlwocqbejdWtLW1cEzCexPrh6EdyFsPgVdAw== - dependencies: - loader-utils "^1.1.0" - normalize-url "^2.0.1" - schema-utils "^1.0.0" - webpack-sources "^1.1.0" - -minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" - integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== - -minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" - integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= - -minimatch@^3.0.2, minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== - dependencies: - brace-expansion "^1.1.7" - -minimist@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" - integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= - -minimist@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" - integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= - -minipass@^2.2.1, minipass@^2.3.5: - version "2.3.5" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848" - integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA== - dependencies: - safe-buffer "^5.1.2" - yallist "^3.0.0" - -minizlib@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614" - integrity sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA== - dependencies: - minipass "^2.2.1" - -mississippi@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" - integrity sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA== - dependencies: - concat-stream "^1.5.0" - duplexify "^3.4.2" - end-of-stream "^1.1.0" - flush-write-stream "^1.0.0" - from2 "^2.1.0" - parallel-transform "^1.1.0" - pump "^3.0.0" - pumpify "^1.3.3" - stream-each "^1.1.0" - through2 "^2.0.0" - -mixin-deep@^1.2.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" - integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== - dependencies: - for-in "^1.0.2" - is-extendable "^1.0.1" - -mkdirp@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.0.tgz#1bbf5ab1ba827af23575143490426455f481fe1e" - integrity sha1-G79asbqCevI1dRQ0kEJkVfSB/h4= - -mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" - integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= - dependencies: - minimist "0.0.8" - -move-concurrently@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" - integrity sha1-viwAX9oy4LKa8fBdfEszIUxwH5I= - dependencies: - aproba "^1.1.1" - copy-concurrently "^1.0.0" - fs-write-stream-atomic "^1.0.8" - mkdirp "^0.5.1" - rimraf "^2.5.4" - run-queue "^1.0.3" - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= - -ms@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" - integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== - -ms@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -multicast-dns-service-types@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901" - integrity sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE= - -multicast-dns@^6.0.1: - version "6.2.3" - resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-6.2.3.tgz#a0ec7bd9055c4282f790c3c82f4e28db3b31b229" - integrity sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g== - dependencies: - dns-packet "^1.3.1" - thunky "^1.0.2" - -nan@^2.12.1: - version "2.14.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" - integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== - -nanomatch@^1.2.9: - version "1.2.13" - resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" - integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - define-property "^2.0.2" - extend-shallow "^3.0.2" - fragment-cache "^0.2.1" - is-windows "^1.0.2" - kind-of "^6.0.2" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -needle@^2.2.1: - version "2.4.0" - resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.0.tgz#6833e74975c444642590e15a750288c5f939b57c" - integrity sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg== - dependencies: - debug "^3.2.6" - iconv-lite "^0.4.4" - sax "^1.2.4" - -negotiator@0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" - integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== - -neo-async@^2.5.0, neo-async@^2.6.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c" - integrity sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw== - -nice-try@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" - integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== - -no-case@^2.2.0: - version "2.3.2" - resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac" - integrity sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ== - dependencies: - lower-case "^1.1.1" - -node-forge@0.7.5: - version "0.7.5" - resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.5.tgz#6c152c345ce11c52f465c2abd957e8639cd674df" - integrity sha512-MmbQJ2MTESTjt3Gi/3yG1wGpIMhUfcIypUCGtTizFR9IiccFwxSpfp0vtIZlkFclEqERemxfnSdZEMR9VqqEFQ== - -node-libs-browser@^2.0.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" - integrity sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q== - dependencies: - assert "^1.1.1" - browserify-zlib "^0.2.0" - buffer "^4.3.0" - console-browserify "^1.1.0" - constants-browserify "^1.0.0" - crypto-browserify "^3.11.0" - domain-browser "^1.1.1" - events "^3.0.0" - https-browserify "^1.0.0" - os-browserify "^0.3.0" - path-browserify "0.0.1" - process "^0.11.10" - punycode "^1.2.4" - querystring-es3 "^0.2.0" - readable-stream "^2.3.3" - stream-browserify "^2.0.1" - stream-http "^2.7.2" - string_decoder "^1.0.0" - timers-browserify "^2.0.4" - tty-browserify "0.0.0" - url "^0.11.0" - util "^0.11.0" - vm-browserify "^1.0.1" - -node-pre-gyp@^0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz#39ba4bb1439da030295f899e3b520b7785766149" - integrity sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A== - dependencies: - detect-libc "^1.0.2" - mkdirp "^0.5.1" - needle "^2.2.1" - nopt "^4.0.1" - npm-packlist "^1.1.6" - npmlog "^4.0.2" - rc "^1.2.7" - rimraf "^2.6.1" - semver "^5.3.0" - tar "^4" - -node-releases@^1.1.25: - version "1.1.25" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.25.tgz#0c2d7dbc7fed30fbe02a9ee3007b8c90bf0133d3" - integrity sha512-fI5BXuk83lKEoZDdH3gRhtsNgh05/wZacuXkgbiYkceE7+QIMXOg98n9ZV7mz27B+kFHnqHcUpscZZlGRSmTpQ== - dependencies: - semver "^5.3.0" - -nopt@1.0.10: - version "1.0.10" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" - integrity sha1-bd0hvSoxQXuScn3Vhfim83YI6+4= - dependencies: - abbrev "1" - -nopt@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" - integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00= - dependencies: - abbrev "1" - osenv "^0.1.4" - -normalize-path@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" - integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= - dependencies: - remove-trailing-separator "^1.0.1" - -normalize-path@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" - integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== - -normalize-range@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" - integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI= - -normalize-url@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-2.0.1.tgz#835a9da1551fa26f70e92329069a23aa6574d7e6" - integrity sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw== - dependencies: - prepend-http "^2.0.0" - query-string "^5.0.1" - sort-keys "^2.0.0" - -normalize-url@^3.0.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559" - integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg== - -npm-bundled@^1.0.1: - version "1.0.6" - resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.6.tgz#e7ba9aadcef962bb61248f91721cd932b3fe6bdd" - integrity sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g== - -npm-packlist@^1.1.6: - version "1.4.4" - resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.4.tgz#866224233850ac534b63d1a6e76050092b5d2f44" - integrity sha512-zTLo8UcVYtDU3gdeaFu2Xu0n0EvelfHDGuqtNIn5RO7yQj4H1TqNdBc/yZjxnWA0PVB8D3Woyp0i5B43JwQ6Vw== - dependencies: - ignore-walk "^3.0.1" - npm-bundled "^1.0.1" - -npm-run-path@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" - integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= - dependencies: - path-key "^2.0.0" - -npmlog@^4.0.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" - integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== - dependencies: - are-we-there-yet "~1.1.2" - console-control-strings "~1.1.0" - gauge "~2.7.3" - set-blocking "~2.0.0" - -nprogress@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/nprogress/-/nprogress-0.2.0.tgz#cb8f34c53213d895723fcbab907e9422adbcafb1" - integrity sha1-y480xTIT2JVyP8urkH6UIq28r7E= - -nth-check@^1.0.2, nth-check@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c" - integrity sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg== - dependencies: - boolbase "~1.0.0" - -num2fraction@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" - integrity sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4= - -number-is-nan@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= - -oauth-sign@~0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" - integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== - -object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= - -object-copy@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" - integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= - dependencies: - copy-descriptor "^0.1.0" - define-property "^0.2.5" - kind-of "^3.0.3" - -object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" - integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== - -object-visit@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" - integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= - dependencies: - isobject "^3.0.0" - -object.assign@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" - integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== - dependencies: - define-properties "^1.1.2" - function-bind "^1.1.1" - has-symbols "^1.0.0" - object-keys "^1.0.11" - -object.getownpropertydescriptors@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16" - integrity sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY= - dependencies: - define-properties "^1.1.2" - es-abstract "^1.5.1" - -object.pick@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" - integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= - dependencies: - isobject "^3.0.1" - -object.values@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.0.tgz#bf6810ef5da3e5325790eaaa2be213ea84624da9" - integrity sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.12.0" - function-bind "^1.1.1" - has "^1.0.3" - -obuf@^1.0.0, obuf@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" - integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== - -on-finished@~2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" - integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= - dependencies: - ee-first "1.1.1" - -on-headers@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" - integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== - -once@^1.3.0, once@^1.3.1, once@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - -opn@^5.5.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/opn/-/opn-5.5.0.tgz#fc7164fab56d235904c51c3b27da6758ca3b9bfc" - integrity sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA== - dependencies: - is-wsl "^1.1.0" - -optimize-css-assets-webpack-plugin@^5.0.1: - version "5.0.3" - resolved "https://registry.yarnpkg.com/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-5.0.3.tgz#e2f1d4d94ad8c0af8967ebd7cf138dcb1ef14572" - integrity sha512-q9fbvCRS6EYtUKKSwI87qm2IxlyJK5b4dygW1rKUBT6mMDhdG5e5bZT63v6tnJR9F9FB/H5a0HTmtw+laUBxKA== - dependencies: - cssnano "^4.1.10" - last-call-webpack-plugin "^3.0.0" - -original@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/original/-/original-1.0.2.tgz#e442a61cffe1c5fd20a65f3261c26663b303f25f" - integrity sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg== - dependencies: - url-parse "^1.4.3" - -os-browserify@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" - integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= - -os-homedir@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" - integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= - -os-locale@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" - integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q== - dependencies: - execa "^1.0.0" - lcid "^2.0.0" - mem "^4.0.0" - -os-tmpdir@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= - -osenv@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" - integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== - dependencies: - os-homedir "^1.0.0" - os-tmpdir "^1.0.0" - -p-defer@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" - integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww= - -p-finally@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" - integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= - -p-is-promise@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e" - integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg== - -p-limit@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" - integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== - dependencies: - p-try "^1.0.0" - -p-limit@^2.0.0, p-limit@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.0.tgz#417c9941e6027a9abcba5092dd2904e255b5fbc2" - integrity sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ== - dependencies: - p-try "^2.0.0" - -p-locate@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" - integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= - dependencies: - p-limit "^1.1.0" - -p-locate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" - integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== - dependencies: - p-limit "^2.0.0" - -p-map@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" - integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== - -p-retry@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-3.0.1.tgz#316b4c8893e2c8dc1cfa891f406c4b422bebf328" - integrity sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w== - dependencies: - retry "^0.12.0" - -p-try@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" - integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= - -p-try@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" - integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== - -pako@~1.0.5: - version "1.0.10" - resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.10.tgz#4328badb5086a426aa90f541977d4955da5c9732" - integrity sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw== - -parallel-transform@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.1.0.tgz#d410f065b05da23081fcd10f28854c29bda33b06" - integrity sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY= - dependencies: - cyclist "~0.2.2" - inherits "^2.0.3" - readable-stream "^2.1.5" - -param-case@2.1.x: - version "2.1.1" - resolved "https://registry.yarnpkg.com/param-case/-/param-case-2.1.1.tgz#df94fd8cf6531ecf75e6bef9a0858fbc72be2247" - integrity sha1-35T9jPZTHs915r75oIWPvHK+Ikc= - dependencies: - no-case "^2.2.0" - -parse-asn1@^5.0.0: - version "5.1.4" - resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.4.tgz#37f6628f823fbdeb2273b4d540434a22f3ef1fcc" - integrity sha512-Qs5duJcuvNExRfFZ99HDD3z4mAi3r9Wl/FOjEOijlxwCZs7E7mW2vjTpgQ4J8LpTF8x5v+1Vn5UQFejmWT11aw== - dependencies: - asn1.js "^4.0.0" - browserify-aes "^1.0.0" - create-hash "^1.1.0" - evp_bytestokey "^1.0.0" - pbkdf2 "^3.0.3" - safe-buffer "^5.1.1" - -parse-json@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" - integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= - dependencies: - error-ex "^1.3.1" - json-parse-better-errors "^1.0.1" - -parseurl@~1.3.2, parseurl@~1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" - integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== - -pascalcase@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" - integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= - -path-browserify@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a" - integrity sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ== - -path-dirname@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" - integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= - -path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - -path-is-inside@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" - integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= - -path-key@^2.0.0, path-key@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= - -path-parse@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" - integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== - -path-to-regexp@0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" - integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= - -path-type@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" - integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== - dependencies: - pify "^3.0.0" - -pbkdf2@^3.0.3: - version "3.0.17" - resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.17.tgz#976c206530617b14ebb32114239f7b09336e93a6" - integrity sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA== - dependencies: - create-hash "^1.1.2" - create-hmac "^1.1.4" - ripemd160 "^2.0.1" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - -performance-now@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= - -pify@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= - -pify@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" - integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= - -pify@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" - integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== - -pinkie-promise@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" - integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= - dependencies: - pinkie "^2.0.0" - -pinkie@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" - integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= - -pkg-dir@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" - integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== - dependencies: - find-up "^3.0.0" - -pkg-up@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-2.0.0.tgz#c819ac728059a461cab1c3889a2be3c49a004d7f" - integrity sha1-yBmscoBZpGHKscOImivjxJoATX8= - dependencies: - find-up "^2.1.0" - -portfinder@^1.0.13, portfinder@^1.0.20: - version "1.0.21" - resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.21.tgz#60e1397b95ac170749db70034ece306b9a27e324" - integrity sha512-ESabpDCzmBS3ekHbmpAIiESq3udRsCBGiBZLsC+HgBKv2ezb0R4oG+7RnYEVZ/ZCfhel5Tx3UzdNWA0Lox2QCA== - dependencies: - async "^1.5.2" - debug "^2.2.0" - mkdirp "0.5.x" - -posix-character-classes@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" - integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= - -postcss-calc@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-7.0.1.tgz#36d77bab023b0ecbb9789d84dcb23c4941145436" - integrity sha512-oXqx0m6tb4N3JGdmeMSc/i91KppbYsFZKdH0xMOqK8V1rJlzrKlTdokz8ozUXLVejydRN6u2IddxpcijRj2FqQ== - dependencies: - css-unit-converter "^1.1.1" - postcss "^7.0.5" - postcss-selector-parser "^5.0.0-rc.4" - postcss-value-parser "^3.3.1" - -postcss-colormin@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-4.0.3.tgz#ae060bce93ed794ac71264f08132d550956bd381" - integrity sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw== - dependencies: - browserslist "^4.0.0" - color "^3.0.0" - has "^1.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-convert-values@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz#ca3813ed4da0f812f9d43703584e449ebe189a7f" - integrity sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ== - dependencies: - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-discard-comments@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz#1fbabd2c246bff6aaad7997b2b0918f4d7af4033" - integrity sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg== - dependencies: - postcss "^7.0.0" - -postcss-discard-duplicates@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz#3fe133cd3c82282e550fc9b239176a9207b784eb" - integrity sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ== - dependencies: - postcss "^7.0.0" - -postcss-discard-empty@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz#c8c951e9f73ed9428019458444a02ad90bb9f765" - integrity sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w== - dependencies: - postcss "^7.0.0" - -postcss-discard-overridden@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz#652aef8a96726f029f5e3e00146ee7a4e755ff57" - integrity sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg== - dependencies: - postcss "^7.0.0" - -postcss-load-config@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-2.1.0.tgz#c84d692b7bb7b41ddced94ee62e8ab31b417b003" - integrity sha512-4pV3JJVPLd5+RueiVVB+gFOAa7GWc25XQcMp86Zexzke69mKf6Nx9LRcQywdz7yZI9n1udOxmLuAwTBypypF8Q== - dependencies: - cosmiconfig "^5.0.0" - import-cwd "^2.0.0" - -postcss-loader@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-3.0.0.tgz#6b97943e47c72d845fa9e03f273773d4e8dd6c2d" - integrity sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA== - dependencies: - loader-utils "^1.1.0" - postcss "^7.0.0" - postcss-load-config "^2.0.0" - schema-utils "^1.0.0" - -postcss-merge-longhand@^4.0.11: - version "4.0.11" - resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz#62f49a13e4a0ee04e7b98f42bb16062ca2549e24" - integrity sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw== - dependencies: - css-color-names "0.0.4" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - stylehacks "^4.0.0" - -postcss-merge-rules@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz#362bea4ff5a1f98e4075a713c6cb25aefef9a650" - integrity sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ== - dependencies: - browserslist "^4.0.0" - caniuse-api "^3.0.0" - cssnano-util-same-parent "^4.0.0" - postcss "^7.0.0" - postcss-selector-parser "^3.0.0" - vendors "^1.0.0" - -postcss-minify-font-values@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz#cd4c344cce474343fac5d82206ab2cbcb8afd5a6" - integrity sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg== - dependencies: - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-minify-gradients@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz#93b29c2ff5099c535eecda56c4aa6e665a663471" - integrity sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q== - dependencies: - cssnano-util-get-arguments "^4.0.0" - is-color-stop "^1.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-minify-params@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz#6b9cef030c11e35261f95f618c90036d680db874" - integrity sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg== - dependencies: - alphanum-sort "^1.0.0" - browserslist "^4.0.0" - cssnano-util-get-arguments "^4.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - uniqs "^2.0.0" - -postcss-minify-selectors@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz#e2e5eb40bfee500d0cd9243500f5f8ea4262fbd8" - integrity sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g== - dependencies: - alphanum-sort "^1.0.0" - has "^1.0.0" - postcss "^7.0.0" - postcss-selector-parser "^3.0.0" - -postcss-modules-extract-imports@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz#818719a1ae1da325f9832446b01136eeb493cd7e" - integrity sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ== - dependencies: - postcss "^7.0.5" - -postcss-modules-local-by-default@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-2.0.6.tgz#dd9953f6dd476b5fd1ef2d8830c8929760b56e63" - integrity sha512-oLUV5YNkeIBa0yQl7EYnxMgy4N6noxmiwZStaEJUSe2xPMcdNc8WmBQuQCx18H5psYbVxz8zoHk0RAAYZXP9gA== - dependencies: - postcss "^7.0.6" - postcss-selector-parser "^6.0.0" - postcss-value-parser "^3.3.1" - -postcss-modules-scope@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-2.1.0.tgz#ad3f5bf7856114f6fcab901b0502e2a2bc39d4eb" - integrity sha512-91Rjps0JnmtUB0cujlc8KIKCsJXWjzuxGeT/+Q2i2HXKZ7nBUeF9YQTZZTNvHVoNYj1AthsjnGLtqDUE0Op79A== - dependencies: - postcss "^7.0.6" - postcss-selector-parser "^6.0.0" - -postcss-modules-values@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-2.0.0.tgz#479b46dc0c5ca3dc7fa5270851836b9ec7152f64" - integrity sha512-Ki7JZa7ff1N3EIMlPnGTZfUMe69FFwiQPnVSXC9mnn3jozCRBYIxiZd44yJOV2AmabOo4qFf8s0dC/+lweG7+w== - dependencies: - icss-replace-symbols "^1.1.0" - postcss "^7.0.6" - -postcss-normalize-charset@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz#8b35add3aee83a136b0471e0d59be58a50285dd4" - integrity sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g== - dependencies: - postcss "^7.0.0" - -postcss-normalize-display-values@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz#0dbe04a4ce9063d4667ed2be476bb830c825935a" - integrity sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ== - dependencies: - cssnano-util-get-match "^4.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-positions@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz#05f757f84f260437378368a91f8932d4b102917f" - integrity sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA== - dependencies: - cssnano-util-get-arguments "^4.0.0" - has "^1.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-repeat-style@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz#c4ebbc289f3991a028d44751cbdd11918b17910c" - integrity sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q== - dependencies: - cssnano-util-get-arguments "^4.0.0" - cssnano-util-get-match "^4.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-string@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz#cd44c40ab07a0c7a36dc5e99aace1eca4ec2690c" - integrity sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA== - dependencies: - has "^1.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-timing-functions@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz#8e009ca2a3949cdaf8ad23e6b6ab99cb5e7d28d9" - integrity sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A== - dependencies: - cssnano-util-get-match "^4.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-unicode@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz#841bd48fdcf3019ad4baa7493a3d363b52ae1cfb" - integrity sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg== - dependencies: - browserslist "^4.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-url@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz#10e437f86bc7c7e58f7b9652ed878daaa95faae1" - integrity sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA== - dependencies: - is-absolute-url "^2.0.0" - normalize-url "^3.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-whitespace@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz#bf1d4070fe4fcea87d1348e825d8cc0c5faa7d82" - integrity sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA== - dependencies: - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-ordered-values@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz#0cf75c820ec7d5c4d280189559e0b571ebac0eee" - integrity sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw== - dependencies: - cssnano-util-get-arguments "^4.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-reduce-initial@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz#7fd42ebea5e9c814609639e2c2e84ae270ba48df" - integrity sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA== - dependencies: - browserslist "^4.0.0" - caniuse-api "^3.0.0" - has "^1.0.0" - postcss "^7.0.0" - -postcss-reduce-transforms@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz#17efa405eacc6e07be3414a5ca2d1074681d4e29" - integrity sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg== - dependencies: - cssnano-util-get-match "^4.0.0" - has "^1.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-safe-parser@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-safe-parser/-/postcss-safe-parser-4.0.1.tgz#8756d9e4c36fdce2c72b091bbc8ca176ab1fcdea" - integrity sha512-xZsFA3uX8MO3yAda03QrG3/Eg1LN3EPfjjf07vke/46HERLZyHrTsQ9E1r1w1W//fWEhtYNndo2hQplN2cVpCQ== - dependencies: - postcss "^7.0.0" - -postcss-selector-parser@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz#4f875f4afb0c96573d5cf4d74011aee250a7e865" - integrity sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU= - dependencies: - dot-prop "^4.1.1" - indexes-of "^1.0.1" - uniq "^1.0.1" - -postcss-selector-parser@^5.0.0, postcss-selector-parser@^5.0.0-rc.4: - version "5.0.0" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz#249044356697b33b64f1a8f7c80922dddee7195c" - integrity sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ== - dependencies: - cssesc "^2.0.0" - indexes-of "^1.0.1" - uniq "^1.0.1" - -postcss-selector-parser@^6.0.0: - version "6.0.2" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.2.tgz#934cf799d016c83411859e09dcecade01286ec5c" - integrity sha512-36P2QR59jDTOAiIkqEprfJDsoNrvwFei3eCqKd1Y0tUsBimsq39BLp7RD+JWny3WgB1zGhJX8XVePwm9k4wdBg== - dependencies: - cssesc "^3.0.0" - indexes-of "^1.0.1" - uniq "^1.0.1" - -postcss-svgo@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-4.0.2.tgz#17b997bc711b333bab143aaed3b8d3d6e3d38258" - integrity sha512-C6wyjo3VwFm0QgBy+Fu7gCYOkCmgmClghO+pjcxvrcBKtiKt0uCF+hvbMO1fyv5BMImRK90SMb+dwUnfbGd+jw== - dependencies: - is-svg "^3.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - svgo "^1.0.0" - -postcss-unique-selectors@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz#9446911f3289bfd64c6d680f073c03b1f9ee4bac" - integrity sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg== - dependencies: - alphanum-sort "^1.0.0" - postcss "^7.0.0" - uniqs "^2.0.0" - -postcss-value-parser@^3.0.0, postcss-value-parser@^3.3.0, postcss-value-parser@^3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" - integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ== - -postcss-value-parser@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.0.0.tgz#99a983d365f7b2ad8d0f9b8c3094926eab4b936d" - integrity sha512-ESPktioptiSUchCKgggAkzdmkgzKfmp0EU8jXH+5kbIUB+unr0Y4CY9SRMvibuvYUBjNh1ACLbxqYNpdTQOteQ== - -postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.17, postcss@^7.0.5, postcss@^7.0.6: - version "7.0.17" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.17.tgz#4da1bdff5322d4a0acaab4d87f3e782436bad31f" - integrity sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ== - dependencies: - chalk "^2.4.2" - source-map "^0.6.1" - supports-color "^6.1.0" - -prepend-http@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" - integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= - -prettier@1.16.3: - version "1.16.3" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.16.3.tgz#8c62168453badef702f34b45b6ee899574a6a65d" - integrity sha512-kn/GU6SMRYPxUakNXhpP0EedT/KmaPzr0H5lIsDogrykbaxOpOfAFfk5XA7DZrJyMAv1wlMV3CPcZruGXVVUZw== - -pretty-error@^2.0.2: - version "2.1.1" - resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.1.1.tgz#5f4f87c8f91e5ae3f3ba87ab4cf5e03b1a17f1a3" - integrity sha1-X0+HyPkeWuPzuoerTPXgOxoX8aM= - dependencies: - renderkid "^2.0.1" - utila "~0.4" - -pretty-time@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/pretty-time/-/pretty-time-1.1.0.tgz#ffb7429afabb8535c346a34e41873adf3d74dd0e" - integrity sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA== - -prismjs@^1.13.0: - version "1.16.0" - resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.16.0.tgz#406eb2c8aacb0f5f0f1167930cb83835d10a4308" - integrity sha512-OA4MKxjFZHSvZcisLGe14THYsug/nF6O1f0pAJc0KN0wTyAcLqmsbE+lTGKSpyh+9pEW57+k6pg2AfYR+coyHA== - optionalDependencies: - clipboard "^2.0.0" - -private@^0.1.6: - version "0.1.8" - resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" - integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== - -process-nextick-args@~2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" - integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== - -process@^0.11.10: - version "0.11.10" - resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" - integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= - -promise-inflight@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" - integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= - -proxy-addr@~2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.5.tgz#34cbd64a2d81f4b1fd21e76f9f06c8a45299ee34" - integrity sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ== - dependencies: - forwarded "~0.1.2" - ipaddr.js "1.9.0" - -prr@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" - integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= - -pseudomap@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" - integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= - -psl@^1.1.24: - version "1.2.0" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.2.0.tgz#df12b5b1b3a30f51c329eacbdef98f3a6e136dc6" - integrity sha512-GEn74ZffufCmkDDLNcl3uuyF/aSD6exEyh1v/ZSdAomB82t6G9hzJVRx0jBmLDW+VfZqks3aScmMw9DszwUalA== - -public-encrypt@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" - integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== - dependencies: - bn.js "^4.1.0" - browserify-rsa "^4.0.0" - create-hash "^1.1.0" - parse-asn1 "^5.0.0" - randombytes "^2.0.1" - safe-buffer "^5.1.2" - -pump@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" - integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - -pump@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" - integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - -pumpify@^1.3.3: - version "1.5.1" - resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" - integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ== - dependencies: - duplexify "^3.6.0" - inherits "^2.0.3" - pump "^2.0.0" - -punycode@1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" - integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= - -punycode@^1.2.4, punycode@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= - -punycode@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== - -q@^1.1.2: - version "1.5.1" - resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" - integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= - -qs@6.7.0: - version "6.7.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" - integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== - -qs@~6.5.2: - version "6.5.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" - integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== - -query-string@^5.0.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" - integrity sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw== - dependencies: - decode-uri-component "^0.2.0" - object-assign "^4.1.0" - strict-uri-encode "^1.0.0" - -querystring-es3@^0.2.0, querystring-es3@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" - integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM= - -querystring@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" - integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= - -querystringify@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.1.tgz#60e5a5fd64a7f8bfa4d2ab2ed6fdf4c85bad154e" - integrity sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA== - -randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: - version "2.1.0" - resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" - integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== - dependencies: - safe-buffer "^5.1.0" - -randomfill@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" - integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== - dependencies: - randombytes "^2.0.5" - safe-buffer "^5.1.0" - -range-parser@^1.2.1, range-parser@~1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" - integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== - -raw-body@2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" - integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== - dependencies: - bytes "3.1.0" - http-errors "1.7.2" - iconv-lite "0.4.24" - unpipe "1.0.0" - -rc@^1.2.7: - version "1.2.8" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" - integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== - dependencies: - deep-extend "^0.6.0" - ini "~1.3.0" - minimist "^1.2.0" - strip-json-comments "~2.0.1" - -"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: - version "2.3.6" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" - integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - -readable-stream@^3.0.6, readable-stream@^3.1.1: - version "3.4.0" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.4.0.tgz#a51c26754658e0a3c21dbf59163bd45ba6f447fc" - integrity sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ== - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - -readdirp@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" - integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== - dependencies: - graceful-fs "^4.1.11" - micromatch "^3.1.10" - readable-stream "^2.0.2" - -reduce@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/reduce/-/reduce-1.0.2.tgz#0cd680ad3ffe0b060e57a5c68bdfce37168d361b" - integrity sha512-xX7Fxke/oHO5IfZSk77lvPa/7bjMh9BuCk4OOoX5XTXrM7s0Z+MkPfSDfz0q7r91BhhGSs8gii/VEN/7zhCPpQ== - dependencies: - object-keys "^1.1.0" - -regenerate-unicode-properties@^8.0.2: - version "8.1.0" - resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz#ef51e0f0ea4ad424b77bf7cb41f3e015c70a3f0e" - integrity sha512-LGZzkgtLY79GeXLm8Dp0BVLdQlWICzBnJz/ipWUgo59qBaZ+BHtq51P2q1uVZlppMuUAT37SDk39qUbjTWB7bA== - dependencies: - regenerate "^1.4.0" - -regenerate@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" - integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg== - -regenerator-runtime@^0.13.2: - version "0.13.2" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz#32e59c9a6fb9b1a4aff09b4930ca2d4477343447" - integrity sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA== - -regenerator-transform@^0.14.0: - version "0.14.0" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.0.tgz#2ca9aaf7a2c239dd32e4761218425b8c7a86ecaf" - integrity sha512-rtOelq4Cawlbmq9xuMR5gdFmv7ku/sFoB7sRiywx7aq53bc52b4j6zvH7Te1Vt/X2YveDKnCGUbioieU7FEL3w== - dependencies: - private "^0.1.6" - -regex-not@^1.0.0, regex-not@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" - integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== - dependencies: - extend-shallow "^3.0.2" - safe-regex "^1.1.0" - -regexp-tree@^0.1.6: - version "0.1.11" - resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.11.tgz#c9c7f00fcf722e0a56c7390983a7a63dd6c272f3" - integrity sha512-7/l/DgapVVDzZobwMCCgMlqiqyLFJ0cduo/j+3BcDJIB+yJdsYCfKuI3l/04NV+H/rfNRdPIDbXNZHM9XvQatg== - -regexpu-core@^4.5.4: - version "4.5.4" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.5.4.tgz#080d9d02289aa87fe1667a4f5136bc98a6aebaae" - integrity sha512-BtizvGtFQKGPUcTy56o3nk1bGRp4SZOTYrDtGNlqCQufptV5IkkLN6Emw+yunAJjzf+C9FQFtvq7IoA3+oMYHQ== - dependencies: - regenerate "^1.4.0" - regenerate-unicode-properties "^8.0.2" - regjsgen "^0.5.0" - regjsparser "^0.6.0" - unicode-match-property-ecmascript "^1.0.4" - unicode-match-property-value-ecmascript "^1.1.0" - -regjsgen@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.0.tgz#a7634dc08f89209c2049adda3525711fb97265dd" - integrity sha512-RnIrLhrXCX5ow/E5/Mh2O4e/oa1/jW0eaBKTSy3LaCj+M3Bqvm97GWDp2yUtzIs4LEn65zR2yiYGFqb2ApnzDA== - -regjsparser@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.0.tgz#f1e6ae8b7da2bae96c99399b868cd6c933a2ba9c" - integrity sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ== - dependencies: - jsesc "~0.5.0" - -relateurl@0.2.x: - version "0.2.7" - resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" - integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk= - -remove-trailing-separator@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" - integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= - -renderkid@^2.0.1: - version "2.0.3" - resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-2.0.3.tgz#380179c2ff5ae1365c522bf2fcfcff01c5b74149" - integrity sha512-z8CLQp7EZBPCwCnncgf9C4XAi3WR0dv+uWu/PjIyhhAb5d6IJ/QZqlHFprHeKT+59//V6BNUsLbvN8+2LarxGA== - dependencies: - css-select "^1.1.0" - dom-converter "^0.2" - htmlparser2 "^3.3.0" - strip-ansi "^3.0.0" - utila "^0.4.0" - -repeat-element@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" - integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== - -repeat-string@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= - -request@^2.87.0: - version "2.88.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" - integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg== - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.8.0" - caseless "~0.12.0" - combined-stream "~1.0.6" - extend "~3.0.2" - forever-agent "~0.6.1" - form-data "~2.3.2" - har-validator "~5.1.0" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.19" - oauth-sign "~0.9.0" - performance-now "^2.1.0" - qs "~6.5.2" - safe-buffer "^5.1.2" - tough-cookie "~2.4.3" - tunnel-agent "^0.6.0" - uuid "^3.3.2" - -require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= - -require-main-filename@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" - integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= - -requires-port@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" - integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= - -reselect@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/reselect/-/reselect-3.0.1.tgz#efdaa98ea7451324d092b2b2163a6a1d7a9a2147" - integrity sha1-79qpjqdFEyTQkrKyFjpqHXqaIUc= - -resolve-cwd@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" - integrity sha1-AKn3OHVW4nA46uIyyqNypqWbZlo= - dependencies: - resolve-from "^3.0.0" - -resolve-from@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" - integrity sha1-six699nWiBvItuZTM17rywoYh0g= - -resolve-url@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" - integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= - -resolve@^1.2.0, resolve@^1.3.2, resolve@^1.4.0, resolve@^1.8.1: - version "1.11.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.11.1.tgz#ea10d8110376982fef578df8fc30b9ac30a07a3e" - integrity sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw== - dependencies: - path-parse "^1.0.6" - -ret@~0.1.10: - version "0.1.15" - resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" - integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== - -retry@^0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" - integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= - -rgb-regex@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/rgb-regex/-/rgb-regex-1.0.1.tgz#c0e0d6882df0e23be254a475e8edd41915feaeb1" - integrity sha1-wODWiC3w4jviVKR16O3UGRX+rrE= - -rgba-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3" - integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM= - -rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.3: - version "2.6.3" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" - integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== - dependencies: - glob "^7.1.3" - -ripemd160@^2.0.0, ripemd160@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" - integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - -run-queue@^1.0.0, run-queue@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" - integrity sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec= - dependencies: - aproba "^1.1.1" - -safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2: - version "5.2.0" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" - integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== - -safe-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" - integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= - dependencies: - ret "~0.1.10" - -"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - -sax@0.5.x: - version "0.5.8" - resolved "https://registry.yarnpkg.com/sax/-/sax-0.5.8.tgz#d472db228eb331c2506b0e8c15524adb939d12c1" - integrity sha1-1HLbIo6zMcJQaw6MFVJK25OdEsE= - -sax@^1.2.4, sax@~1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== - -schema-utils@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770" - integrity sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g== - dependencies: - ajv "^6.1.0" - ajv-errors "^1.0.0" - ajv-keywords "^3.1.0" - -section-matter@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/section-matter/-/section-matter-1.0.0.tgz#e9041953506780ec01d59f292a19c7b850b84167" - integrity sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA== - dependencies: - extend-shallow "^2.0.1" - kind-of "^6.0.0" - -select-hose@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" - integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo= - -select@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d" - integrity sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0= - -selfsigned@^1.10.4: - version "1.10.4" - resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.4.tgz#cdd7eccfca4ed7635d47a08bf2d5d3074092e2cd" - integrity sha512-9AukTiDmHXGXWtWjembZ5NDmVvP2695EtpgbCsxCa68w3c88B+alqbmZ4O3hZ4VWGXeGWzEVdvqgAJD8DQPCDw== - dependencies: - node-forge "0.7.5" - -semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: - version "5.7.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" - integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA== - -semver@^6.0.0, semver@^6.1.1: - version "6.2.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.2.0.tgz#4d813d9590aaf8a9192693d6c85b9344de5901db" - integrity sha512-jdFC1VdUGT/2Scgbimf7FSx9iJLXoqfglSF+gJeuNWVpiE37OIbc1jywR/GJyFdz3mnkz2/id0L0J/cr0izR5A== - -send@0.17.1: - version "0.17.1" - resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" - integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== - dependencies: - debug "2.6.9" - depd "~1.1.2" - destroy "~1.0.4" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - fresh "0.5.2" - http-errors "~1.7.2" - mime "1.6.0" - ms "2.1.1" - on-finished "~2.3.0" - range-parser "~1.2.1" - statuses "~1.5.0" - -serialize-javascript@^1.3.0, serialize-javascript@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.7.0.tgz#d6e0dfb2a3832a8c94468e6eb1db97e55a192a65" - integrity sha512-ke8UG8ulpFOxO8f8gRYabHQe/ZntKlcig2Mp+8+URDP1D8vJZ0KUt7LYo07q25Z/+JVSgpr/cui9PIp5H6/+nA== - -serve-index@^1.9.1: - version "1.9.1" - resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" - integrity sha1-03aNabHn2C5c4FD/9bRTvqEqkjk= - dependencies: - accepts "~1.3.4" - batch "0.6.1" - debug "2.6.9" - escape-html "~1.0.3" - http-errors "~1.6.2" - mime-types "~2.1.17" - parseurl "~1.3.2" - -serve-static@1.14.1: - version "1.14.1" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" - integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== - dependencies: - encodeurl "~1.0.2" - escape-html "~1.0.3" - parseurl "~1.3.3" - send "0.17.1" - -set-blocking@^2.0.0, set-blocking@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= - -set-value@^2.0.0, set-value@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" - integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== - dependencies: - extend-shallow "^2.0.1" - is-extendable "^0.1.1" - is-plain-object "^2.0.3" - split-string "^3.0.1" - -setimmediate@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" - integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= - -setprototypeof@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" - integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== - -setprototypeof@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" - integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== - -sha.js@^2.4.0, sha.js@^2.4.8: - version "2.4.11" - resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" - integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= - dependencies: - shebang-regex "^1.0.0" - -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= - -signal-exit@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" - integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= - -simple-swizzle@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" - integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo= - dependencies: - is-arrayish "^0.3.1" - -slash@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" - integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= - -slash@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" - integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== - -snapdragon-node@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" - integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== - dependencies: - define-property "^1.0.0" - isobject "^3.0.0" - snapdragon-util "^3.0.1" - -snapdragon-util@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" - integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== - dependencies: - kind-of "^3.2.0" - -snapdragon@^0.8.1: - version "0.8.2" - resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" - integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== - dependencies: - base "^0.11.1" - debug "^2.2.0" - define-property "^0.2.5" - extend-shallow "^2.0.1" - map-cache "^0.2.2" - source-map "^0.5.6" - source-map-resolve "^0.5.0" - use "^3.1.0" - -sockjs-client@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.3.0.tgz#12fc9d6cb663da5739d3dc5fb6e8687da95cb177" - integrity sha512-R9jxEzhnnrdxLCNln0xg5uGHqMnkhPSTzUZH2eXcR03S/On9Yvoq2wyUZILRUhZCNVu2PmwWVoyuiPz8th8zbg== - dependencies: - debug "^3.2.5" - eventsource "^1.0.7" - faye-websocket "~0.11.1" - inherits "^2.0.3" - json3 "^3.3.2" - url-parse "^1.4.3" - -sockjs@0.3.19: - version "0.3.19" - resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.19.tgz#d976bbe800af7bd20ae08598d582393508993c0d" - integrity sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw== - dependencies: - faye-websocket "^0.10.0" - uuid "^3.0.1" - -sort-keys@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-2.0.0.tgz#658535584861ec97d730d6cf41822e1f56684128" - integrity sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg= - dependencies: - is-plain-obj "^1.0.0" - -source-list-map@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" - integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== - -source-map-resolve@^0.5.0: - version "0.5.2" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" - integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA== - dependencies: - atob "^2.1.1" - decode-uri-component "^0.2.0" - resolve-url "^0.2.1" - source-map-url "^0.4.0" - urix "^0.1.0" - -source-map-support@~0.5.12: - version "0.5.12" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.12.tgz#b4f3b10d51857a5af0138d3ce8003b201613d599" - integrity sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map-url@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" - integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= - -source-map@0.1.x: - version "0.1.43" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.43.tgz#c24bc146ca517c1471f5dacbe2571b2b7f9e3346" - integrity sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y= - dependencies: - amdefine ">=0.0.4" - -source-map@0.5.6: - version "0.5.6" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" - integrity sha1-dc449SvwczxafwwRjYEzSiu19BI= - -source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= - -source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -spdy-transport@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31" - integrity sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw== - dependencies: - debug "^4.1.0" - detect-node "^2.0.4" - hpack.js "^2.1.6" - obuf "^1.1.2" - readable-stream "^3.0.6" - wbuf "^1.7.3" - -spdy@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.0.tgz#81f222b5a743a329aa12cea6a390e60e9b613c52" - integrity sha512-ot0oEGT/PGUpzf/6uk4AWLqkq+irlqHXkrdbk51oWONh3bxQmBuljxPNl66zlRRcIJStWq0QkLUCPOPjgjvU0Q== - dependencies: - debug "^4.1.0" - handle-thing "^2.0.0" - http-deceiver "^1.2.7" - select-hose "^2.0.0" - spdy-transport "^3.0.0" - -split-string@^3.0.1, split-string@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" - integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== - dependencies: - extend-shallow "^3.0.0" - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= - -sshpk@^1.7.0: - version "1.16.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" - integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - bcrypt-pbkdf "^1.0.0" - dashdash "^1.12.0" - ecc-jsbn "~0.1.1" - getpass "^0.1.1" - jsbn "~0.1.0" - safer-buffer "^2.0.2" - tweetnacl "~0.14.0" - -ssri@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.1.tgz#2a3c41b28dd45b62b63676ecb74001265ae9edd8" - integrity sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA== - dependencies: - figgy-pudding "^3.5.1" - -stable@^0.1.8: - version "0.1.8" - resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" - integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== - -stack-utils@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.2.tgz#33eba3897788558bebfc2db059dc158ec36cebb8" - integrity sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA== - -static-extend@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" - integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= - dependencies: - define-property "^0.2.5" - object-copy "^0.1.0" - -"statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2", statuses@~1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" - integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= - -std-env@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/std-env/-/std-env-2.2.1.tgz#2ffa0fdc9e2263e0004c1211966e960948a40f6b" - integrity sha512-IjYQUinA3lg5re/YMlwlfhqNRTzMZMqE+pezevdcTaHceqx8ngEi1alX9nNCk9Sc81fy1fLDeQoaCzeiW1yBOQ== - dependencies: - ci-info "^1.6.0" - -stream-browserify@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b" - integrity sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg== - dependencies: - inherits "~2.0.1" - readable-stream "^2.0.2" - -stream-each@^1.1.0: - version "1.2.3" - resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae" - integrity sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw== - dependencies: - end-of-stream "^1.1.0" - stream-shift "^1.0.0" - -stream-http@^2.7.2: - version "2.8.3" - resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" - integrity sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw== - dependencies: - builtin-status-codes "^3.0.0" - inherits "^2.0.1" - readable-stream "^2.3.6" - to-arraybuffer "^1.0.0" - xtend "^4.0.0" - -stream-shift@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" - integrity sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI= - -strict-uri-encode@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" - integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM= - -string-width@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - strip-ansi "^3.0.0" - -"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== - dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^4.0.0" - -string-width@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" - integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== - dependencies: - emoji-regex "^7.0.1" - is-fullwidth-code-point "^2.0.0" - strip-ansi "^5.1.0" - -string_decoder@^1.0.0, string_decoder@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.2.0.tgz#fe86e738b19544afe70469243b2a1ee9240eae8d" - integrity sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w== - dependencies: - safe-buffer "~5.1.0" - -string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - -strip-ansi@^3.0.0, strip-ansi@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= - dependencies: - ansi-regex "^2.0.0" - -strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= - dependencies: - ansi-regex "^3.0.0" - -strip-ansi@^5.0.0, strip-ansi@^5.1.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" - integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== - dependencies: - ansi-regex "^4.1.0" - -strip-bom-string@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-bom-string/-/strip-bom-string-1.0.0.tgz#e5211e9224369fbb81d633a2f00044dc8cedad92" - integrity sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI= - -strip-eof@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" - integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= - -strip-json-comments@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= - -stylehacks@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-4.0.3.tgz#6718fcaf4d1e07d8a1318690881e8d96726a71d5" - integrity sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g== - dependencies: - browserslist "^4.0.0" - postcss "^7.0.0" - postcss-selector-parser "^3.0.0" - -stylus-loader@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/stylus-loader/-/stylus-loader-3.0.2.tgz#27a706420b05a38e038e7cacb153578d450513c6" - integrity sha512-+VomPdZ6a0razP+zinir61yZgpw2NfljeSsdUF5kJuEzlo3khXhY19Fn6l8QQz1GRJGtMCo8nG5C04ePyV7SUA== - dependencies: - loader-utils "^1.0.2" - lodash.clonedeep "^4.5.0" - when "~3.6.x" - -stylus@^0.54.5: - version "0.54.5" - resolved "https://registry.yarnpkg.com/stylus/-/stylus-0.54.5.tgz#42b9560931ca7090ce8515a798ba9e6aa3d6dc79" - integrity sha1-QrlWCTHKcJDOhRWnmLqeaqPW3Hk= - dependencies: - css-parse "1.7.x" - debug "*" - glob "7.0.x" - mkdirp "0.5.x" - sax "0.5.x" - source-map "0.1.x" - -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= - -supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -supports-color@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" - integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== - dependencies: - has-flag "^3.0.0" - -svg-tags@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764" - integrity sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q= - -svgo@^1.0.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.3.0.tgz#bae51ba95ded9a33a36b7c46ce9c359ae9154313" - integrity sha512-MLfUA6O+qauLDbym+mMZgtXCGRfIxyQoeH6IKVcFslyODEe/ElJNwr0FohQ3xG4C6HK6bk3KYPPXwHVJk3V5NQ== - dependencies: - chalk "^2.4.1" - coa "^2.0.2" - css-select "^2.0.0" - css-select-base-adapter "^0.1.1" - css-tree "1.0.0-alpha.33" - csso "^3.5.1" - js-yaml "^3.13.1" - mkdirp "~0.5.1" - object.values "^1.1.0" - sax "~1.2.4" - stable "^0.1.8" - unquote "~1.1.1" - util.promisify "~1.0.0" - -tapable@^1.0.0, tapable@^1.1.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" - integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== - -tar@^4: - version "4.4.10" - resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.10.tgz#946b2810b9a5e0b26140cf78bea6b0b0d689eba1" - integrity sha512-g2SVs5QIxvo6OLp0GudTqEf05maawKUxXru104iaayWA09551tFCTI8f1Asb4lPfkBr91k07iL4c11XO3/b0tA== - dependencies: - chownr "^1.1.1" - fs-minipass "^1.2.5" - minipass "^2.3.5" - minizlib "^1.2.1" - mkdirp "^0.5.0" - safe-buffer "^5.1.2" - yallist "^3.0.3" - -terser-webpack-plugin@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.3.0.tgz#69aa22426299f4b5b3775cbed8cb2c5d419aa1d4" - integrity sha512-W2YWmxPjjkUcOWa4pBEv4OP4er1aeQJlSo2UhtCFQCuRXEHjOFscO8VyWHj9JLlA0RzQb8Y2/Ta78XZvT54uGg== - dependencies: - cacache "^11.3.2" - find-cache-dir "^2.0.0" - is-wsl "^1.1.0" - loader-utils "^1.2.3" - schema-utils "^1.0.0" - serialize-javascript "^1.7.0" - source-map "^0.6.1" - terser "^4.0.0" - webpack-sources "^1.3.0" - worker-farm "^1.7.0" - -terser@^4.0.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/terser/-/terser-4.1.2.tgz#b2656c8a506f7ce805a3f300a2ff48db022fa391" - integrity sha512-jvNoEQSPXJdssFwqPSgWjsOrb+ELoE+ILpHPKXC83tIxOlh2U75F1KuB2luLD/3a6/7K3Vw5pDn+hvu0C4AzSw== - dependencies: - commander "^2.20.0" - source-map "~0.6.1" - source-map-support "~0.5.12" - -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= - -through2@^2.0.0: - version "2.0.5" - resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" - integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== - dependencies: - readable-stream "~2.3.6" - xtend "~4.0.1" - -through@~2.3.4: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= - -thunky@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.0.3.tgz#f5df732453407b09191dae73e2a8cc73f381a826" - integrity sha512-YwT8pjmNcAXBZqrubu22P4FYsh2D4dxRmnWBOL8Jk8bUcRUtc5326kx32tuTmFDAZtLOGEVNl8POAR8j896Iow== - -timers-browserify@^2.0.4: - version "2.0.10" - resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.10.tgz#1d28e3d2aadf1d5a5996c4e9f95601cd053480ae" - integrity sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg== - dependencies: - setimmediate "^1.0.4" - -timsort@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" - integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= - -tiny-emitter@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz#1d1a56edfc51c43e863cbb5382a72330e3555423" - integrity sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q== - -to-arraybuffer@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" - integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= - -to-factory@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/to-factory/-/to-factory-1.0.0.tgz#8738af8bd97120ad1d4047972ada5563bf9479b1" - integrity sha1-hzivi9lxIK0dQEeXKtpVY7+UebE= - -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= - -to-object-path@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" - integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= - dependencies: - kind-of "^3.0.2" - -to-regex-range@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" - integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= - dependencies: - is-number "^3.0.0" - repeat-string "^1.6.1" - -to-regex@^3.0.1, to-regex@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" - integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== - dependencies: - define-property "^2.0.2" - extend-shallow "^3.0.2" - regex-not "^1.0.2" - safe-regex "^1.1.0" - -toidentifier@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" - integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== - -toml@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/toml/-/toml-3.0.0.tgz#342160f1af1904ec9d204d03a5d61222d762c5ee" - integrity sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w== - -toposort@^1.0.0: - version "1.0.7" - resolved "https://registry.yarnpkg.com/toposort/-/toposort-1.0.7.tgz#2e68442d9f64ec720b8cc89e6443ac6caa950029" - integrity sha1-LmhELZ9k7HILjMieZEOsbKqVACk= - -tough-cookie@~2.4.3: - version "2.4.3" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" - integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ== - dependencies: - psl "^1.1.24" - punycode "^1.4.1" - -trim-right@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" - integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM= - -tslib@^1.9.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" - integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== - -tty-browserify@0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" - integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= - -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= - dependencies: - safe-buffer "^5.0.1" - -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= - -type-fest@^0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.5.2.tgz#d6ef42a0356c6cd45f49485c3b6281fc148e48a2" - integrity sha512-DWkS49EQKVX//Tbupb9TFa19c7+MK1XmzkrZUR8TAktmE/DizXoaoJV6TZ/tSIPXipqNiRI6CyAe7x69Jb6RSw== - -type-is@~1.6.17, type-is@~1.6.18: - version "1.6.18" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" - integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== - dependencies: - media-typer "0.3.0" - mime-types "~2.1.24" - -typedarray@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" - integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= - -uc.micro@^1.0.1, uc.micro@^1.0.5: - version "1.0.6" - resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" - integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA== - -uglify-js@3.4.x: - version "3.4.10" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.10.tgz#9ad9563d8eb3acdfb8d38597d2af1d815f6a755f" - integrity sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw== - dependencies: - commander "~2.19.0" - source-map "~0.6.1" - -unicode-canonical-property-names-ecmascript@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" - integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ== - -unicode-match-property-ecmascript@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c" - integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg== - dependencies: - unicode-canonical-property-names-ecmascript "^1.0.4" - unicode-property-aliases-ecmascript "^1.0.4" - -unicode-match-property-value-ecmascript@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.1.0.tgz#5b4b426e08d13a80365e0d657ac7a6c1ec46a277" - integrity sha512-hDTHvaBk3RmFzvSl0UVrUmC3PuW9wKVnpoUDYH0JDkSIovzw+J5viQmeYHxVSBptubnr7PbH2e0fnpDRQnQl5g== - -unicode-property-aliases-ecmascript@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz#a9cc6cc7ce63a0a3023fc99e341b94431d405a57" - integrity sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw== - -union-value@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" - integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== - dependencies: - arr-union "^3.1.0" - get-value "^2.0.6" - is-extendable "^0.1.1" - set-value "^2.0.1" - -uniq@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" - integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8= - -uniqs@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02" - integrity sha1-/+3ks2slKQaW5uFl1KWe25mOawI= - -unique-filename@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" - integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== - dependencies: - unique-slug "^2.0.0" - -unique-slug@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c" - integrity sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w== - dependencies: - imurmurhash "^0.1.4" - -universalify@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" - integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== - -unpipe@1.0.0, unpipe@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= - -unquote@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/unquote/-/unquote-1.1.1.tgz#8fded7324ec6e88a0ff8b905e7c098cdc086d544" - integrity sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ= - -unset-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" - integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= - dependencies: - has-value "^0.3.1" - isobject "^3.0.0" - -upath@^1.1.0, upath@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.2.tgz#3db658600edaeeccbe6db5e684d67ee8c2acd068" - integrity sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q== - -upper-case@^1.1.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598" - integrity sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg= - -uri-js@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" - integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== - dependencies: - punycode "^2.1.0" - -urix@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" - integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= - -url-loader@^1.0.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-1.1.2.tgz#b971d191b83af693c5e3fea4064be9e1f2d7f8d8" - integrity sha512-dXHkKmw8FhPqu8asTc1puBfe3TehOCo2+RmOOev5suNCIYBcT626kxiWg1NBVkwc4rO8BGa7gP70W7VXuqHrjg== - dependencies: - loader-utils "^1.1.0" - mime "^2.0.3" - schema-utils "^1.0.0" - -url-parse@^1.4.3: - version "1.4.7" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.7.tgz#a8a83535e8c00a316e403a5db4ac1b9b853ae278" - integrity sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg== - dependencies: - querystringify "^2.1.1" - requires-port "^1.0.0" - -url@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" - integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= - dependencies: - punycode "1.3.2" - querystring "0.2.0" - -use@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" - integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== - -util-deprecate@^1.0.1, util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= - -util.promisify@1.0.0, util.promisify@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030" - integrity sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA== - dependencies: - define-properties "^1.1.2" - object.getownpropertydescriptors "^2.0.3" - -util@0.10.3: - version "0.10.3" - resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" - integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk= - dependencies: - inherits "2.0.1" - -util@^0.11.0: - version "0.11.1" - resolved "https://registry.yarnpkg.com/util/-/util-0.11.1.tgz#3236733720ec64bb27f6e26f421aaa2e1b588d61" - integrity sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ== - dependencies: - inherits "2.0.3" - -utila@^0.4.0, utila@~0.4: - version "0.4.0" - resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" - integrity sha1-ihagXURWV6Oupe7MWxKk+lN5dyw= - -utils-merge@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" - integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= - -uuid@^3.0.1, uuid@^3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" - integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== - -vary@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" - integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= - -vendors@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.3.tgz#a6467781abd366217c050f8202e7e50cc9eef8c0" - integrity sha512-fOi47nsJP5Wqefa43kyWSg80qF+Q3XA6MUkgi7Hp1HQaKDQW4cQrK2D0P7mmbFtsV1N89am55Yru/nyEwRubcw== - -verror@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - -vm-browserify@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.0.tgz#bd76d6a23323e2ca8ffa12028dc04559c75f9019" - integrity sha512-iq+S7vZJE60yejDYM0ek6zg308+UZsdtPExWP9VZoCFCz1zkJoXFnAX7aZfd/ZwrkidzdUZL0C/ryW+JwAiIGw== - -vue-hot-reload-api@^2.3.0: - version "2.3.3" - resolved "https://registry.yarnpkg.com/vue-hot-reload-api/-/vue-hot-reload-api-2.3.3.tgz#2756f46cb3258054c5f4723de8ae7e87302a1ccf" - integrity sha512-KmvZVtmM26BQOMK1rwUZsrqxEGeKiYSZGA7SNWE6uExx8UX/cj9hq2MRV/wWC3Cq6AoeDGk57rL9YMFRel/q+g== - -vue-loader@^15.2.4: - version "15.7.1" - resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.7.1.tgz#6ccacd4122aa80f69baaac08ff295a62e3aefcfd" - integrity sha512-fwIKtA23Pl/rqfYP5TSGK7gkEuLhoTvRYW+TU7ER3q9GpNLt/PjG5NLv3XHRDiTg7OPM1JcckBgds+VnAc+HbA== - dependencies: - "@vue/component-compiler-utils" "^3.0.0" - hash-sum "^1.0.2" - loader-utils "^1.1.0" - vue-hot-reload-api "^2.3.0" - vue-style-loader "^4.1.0" - -vue-router@^3.0.2: - version "3.0.7" - resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.0.7.tgz#b36ca107b4acb8ff5bc4ff824584059c23fcb87b" - integrity sha512-utJ+QR3YlIC/6x6xq17UMXeAfxEvXA0VKD3PiSio7hBOZNusA1jXcbxZxVEfJunLp48oonjTepY8ORoIlRx/EQ== - -vue-server-renderer@^2.5.16: - version "2.6.10" - resolved "https://registry.yarnpkg.com/vue-server-renderer/-/vue-server-renderer-2.6.10.tgz#cb2558842ead360ae2ec1f3719b75564a805b375" - integrity sha512-UYoCEutBpKzL2fKCwx8zlRtRtwxbPZXKTqbl2iIF4yRZUNO/ovrHyDAJDljft0kd+K0tZhN53XRHkgvCZoIhug== - dependencies: - chalk "^1.1.3" - hash-sum "^1.0.2" - he "^1.1.0" - lodash.template "^4.4.0" - lodash.uniq "^4.5.0" - resolve "^1.2.0" - serialize-javascript "^1.3.0" - source-map "0.5.6" - -vue-style-loader@^4.1.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/vue-style-loader/-/vue-style-loader-4.1.2.tgz#dedf349806f25ceb4e64f3ad7c0a44fba735fcf8" - integrity sha512-0ip8ge6Gzz/Bk0iHovU9XAUQaFt/G2B61bnWa2tCcqqdgfHs1lF9xXorFbE55Gmy92okFT+8bfmySuUOu13vxQ== - dependencies: - hash-sum "^1.0.2" - loader-utils "^1.0.2" - -vue-template-compiler@^2.5.16: - version "2.6.10" - resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.6.10.tgz#323b4f3495f04faa3503337a82f5d6507799c9cc" - integrity sha512-jVZkw4/I/HT5ZMvRnhv78okGusqe0+qH2A0Em0Cp8aq78+NK9TII263CDVz2QXZsIT+yyV/gZc/j/vlwa+Epyg== - dependencies: - de-indent "^1.0.2" - he "^1.1.0" - -vue-template-es2015-compiler@^1.9.0: - version "1.9.1" - resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz#1ee3bc9a16ecbf5118be334bb15f9c46f82f5825" - integrity sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw== - -vue@^2.5.16: - version "2.6.10" - resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.10.tgz#a72b1a42a4d82a721ea438d1b6bf55e66195c637" - integrity sha512-ImThpeNU9HbdZL3utgMCq0oiMzAkt1mcgy3/E6zWC/G6AaQoeuFdsl9nDhTDU3X1R6FK7nsIUuRACVcjI+A2GQ== - -vuepress-html-webpack-plugin@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/vuepress-html-webpack-plugin/-/vuepress-html-webpack-plugin-3.2.0.tgz#219be272ad510faa8750d2d4e70fd028bfd1c16e" - integrity sha512-BebAEl1BmWlro3+VyDhIOCY6Gef2MCBllEVAP3NUAtMguiyOwo/dClbwJ167WYmcxHJKLl7b0Chr9H7fpn1d0A== - dependencies: - html-minifier "^3.2.3" - loader-utils "^0.2.16" - lodash "^4.17.3" - pretty-error "^2.0.2" - tapable "^1.0.0" - toposort "^1.0.0" - util.promisify "1.0.0" - -vuepress-plugin-container@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/vuepress-plugin-container/-/vuepress-plugin-container-2.0.2.tgz#3489cc732c7a210b31f202556e1346125dffeb73" - integrity sha512-SrGYYT7lkie7xlIlAVhn+9sDW42MytNCoxWL/2uDr+q9wZA4h1uYlQvfc2DVjy+FsM9PPPSslkeo/zCpYVY82g== - dependencies: - markdown-it-container "^2.0.0" - -vuepress@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/vuepress/-/vuepress-1.0.2.tgz#da62d6e43faca0b8af0bcffff6975fa27dbfdea3" - integrity sha512-HPRWxrq6D+S9uCR3oJ8/OTCy8GcYm9l1HxHb44rvaN2gyySVXIiqSkCwzd9r2PY8+pwvrfYE4rcY1RsTTpJ25g== - dependencies: - "@vuepress/core" "^1.0.2" - "@vuepress/theme-default" "^1.0.2" - cac "^6.3.9" - envinfo "^7.2.0" - -watchpack@^1.5.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00" - integrity sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA== - dependencies: - chokidar "^2.0.2" - graceful-fs "^4.1.2" - neo-async "^2.5.0" - -wbuf@^1.1.0, wbuf@^1.7.3: - version "1.7.3" - resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df" - integrity sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA== - dependencies: - minimalistic-assert "^1.0.0" - -webpack-chain@^4.6.0, webpack-chain@^4.9.0: - version "4.12.1" - resolved "https://registry.yarnpkg.com/webpack-chain/-/webpack-chain-4.12.1.tgz#6c8439bbb2ab550952d60e1ea9319141906c02a6" - integrity sha512-BCfKo2YkDe2ByqkEWe1Rw+zko4LsyS75LVr29C6xIrxAg9JHJ4pl8kaIZ396SUSNp6b4815dRZPSTAS8LlURRQ== - dependencies: - deepmerge "^1.5.2" - javascript-stringify "^1.6.0" - -webpack-dev-middleware@^3.7.0: - version "3.7.0" - resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.7.0.tgz#ef751d25f4e9a5c8a35da600c5fda3582b5c6cff" - integrity sha512-qvDesR1QZRIAZHOE3iQ4CXLZZSQ1lAUsSpnQmlB1PBfoN/xdRjmge3Dok0W4IdaVLJOGJy3sGI4sZHwjRU0PCA== - dependencies: - memory-fs "^0.4.1" - mime "^2.4.2" - range-parser "^1.2.1" - webpack-log "^2.0.0" - -webpack-dev-server@^3.5.1: - version "3.7.2" - resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.7.2.tgz#f79caa5974b7f8b63268ef5421222a8486d792f5" - integrity sha512-mjWtrKJW2T9SsjJ4/dxDC2fkFVUw8jlpemDERqV0ZJIkjjjamR2AbQlr3oz+j4JLhYCHImHnXZK5H06P2wvUew== - dependencies: - ansi-html "0.0.7" - bonjour "^3.5.0" - chokidar "^2.1.6" - compression "^1.7.4" - connect-history-api-fallback "^1.6.0" - debug "^4.1.1" - del "^4.1.1" - express "^4.17.1" - html-entities "^1.2.1" - http-proxy-middleware "^0.19.1" - import-local "^2.0.0" - internal-ip "^4.3.0" - ip "^1.1.5" - killable "^1.0.1" - loglevel "^1.6.3" - opn "^5.5.0" - p-retry "^3.0.1" - portfinder "^1.0.20" - schema-utils "^1.0.0" - selfsigned "^1.10.4" - semver "^6.1.1" - serve-index "^1.9.1" - sockjs "0.3.19" - sockjs-client "1.3.0" - spdy "^4.0.0" - strip-ansi "^3.0.1" - supports-color "^6.1.0" - url "^0.11.0" - webpack-dev-middleware "^3.7.0" - webpack-log "^2.0.0" - yargs "12.0.5" - -webpack-log@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/webpack-log/-/webpack-log-2.0.0.tgz#5b7928e0637593f119d32f6227c1e0ac31e1b47f" - integrity sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg== - dependencies: - ansi-colors "^3.0.0" - uuid "^3.3.2" - -webpack-merge@^4.1.2: - version "4.2.1" - resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-4.2.1.tgz#5e923cf802ea2ace4fd5af1d3247368a633489b4" - integrity sha512-4p8WQyS98bUJcCvFMbdGZyZmsKuWjWVnVHnAS3FFg0HDaRVrPbkivx2RYCre8UiemD67RsiFFLfn4JhLAin8Vw== - dependencies: - lodash "^4.17.5" - -webpack-sources@^1.1.0, webpack-sources@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.3.0.tgz#2a28dcb9f1f45fe960d8f1493252b5ee6530fa85" - integrity sha512-OiVgSrbGu7NEnEvQJJgdSFPl2qWKkWq5lHMhgiToIiN9w34EBnjYzSYs+VbL5KoYiLNtFFa7BZIKxRED3I32pA== - dependencies: - source-list-map "^2.0.0" - source-map "~0.6.1" - -webpack@^4.8.1: - version "4.36.1" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.36.1.tgz#f546fda7a403a76faeaaa7196c50d12370ed18a9" - integrity sha512-Ej01/N9W8DVyhEpeQnbUdGvOECw0L46FxS12cCOs8gSK7bhUlrbHRnWkjiXckGlHjUrmL89kDpTRIkUk6Y+fKg== - dependencies: - "@webassemblyjs/ast" "1.8.5" - "@webassemblyjs/helper-module-context" "1.8.5" - "@webassemblyjs/wasm-edit" "1.8.5" - "@webassemblyjs/wasm-parser" "1.8.5" - acorn "^6.2.0" - ajv "^6.1.0" - ajv-keywords "^3.1.0" - chrome-trace-event "^1.0.0" - enhanced-resolve "^4.1.0" - eslint-scope "^4.0.0" - json-parse-better-errors "^1.0.2" - loader-runner "^2.3.0" - loader-utils "^1.1.0" - memory-fs "~0.4.1" - micromatch "^3.1.8" - mkdirp "~0.5.0" - neo-async "^2.5.0" - node-libs-browser "^2.0.0" - schema-utils "^1.0.0" - tapable "^1.1.0" - terser-webpack-plugin "^1.1.0" - watchpack "^1.5.0" - webpack-sources "^1.3.0" - -webpackbar@3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/webpackbar/-/webpackbar-3.2.0.tgz#bdaad103fad11a4e612500e72aaae98b08ba493f" - integrity sha512-PC4o+1c8gWWileUfwabe0gqptlXUDJd5E0zbpr2xHP1VSOVlZVPBZ8j6NCR8zM5zbKdxPhctHXahgpNK1qFDPw== - dependencies: - ansi-escapes "^4.1.0" - chalk "^2.4.1" - consola "^2.6.0" - figures "^3.0.0" - pretty-time "^1.1.0" - std-env "^2.2.1" - text-table "^0.2.0" - wrap-ansi "^5.1.0" - -websocket-driver@>=0.5.1: - version "0.7.3" - resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.3.tgz#a2d4e0d4f4f116f1e6297eba58b05d430100e9f9" - integrity sha512-bpxWlvbbB459Mlipc5GBzzZwhoZgGEZLuqPaR0INBGnPAY1vdBX6hPnoFXiw+3yWxDuHyQjO2oXTMyS8A5haFg== - dependencies: - http-parser-js ">=0.4.0 <0.4.11" - safe-buffer ">=5.1.0" - websocket-extensions ">=0.1.1" - -websocket-extensions@>=0.1.1: - version "0.1.3" - resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" - integrity sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg== - -when@~3.6.x: - version "3.6.4" - resolved "https://registry.yarnpkg.com/when/-/when-3.6.4.tgz#473b517ec159e2b85005497a13983f095412e34e" - integrity sha1-RztRfsFZ4rhQBUl6E5g/CVQS404= - -which-module@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" - integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= - -which@^1.2.9: - version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== - dependencies: - isexe "^2.0.0" - -wide-align@^1.1.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" - integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== - dependencies: - string-width "^1.0.2 || 2" - -worker-farm@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8" - integrity sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw== - dependencies: - errno "~0.1.7" - -wrap-ansi@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" - integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= - dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" - -wrap-ansi@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" - integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== - dependencies: - ansi-styles "^3.2.0" - string-width "^3.0.0" - strip-ansi "^5.0.0" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - -xtend@^4.0.0, xtend@~4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" - integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== - -"y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" - integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== - -yallist@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" - integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= - -yallist@^3.0.0, yallist@^3.0.2, yallist@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9" - integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A== - -yargs-parser@^11.1.1: - version "11.1.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4" - integrity sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - -yargs@12.0.5: - version "12.0.5" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13" - integrity sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw== - dependencies: - cliui "^4.0.0" - decamelize "^1.2.0" - find-up "^3.0.0" - get-caller-file "^1.0.1" - os-locale "^3.0.0" - require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^2.0.0" - which-module "^2.0.0" - y18n "^3.2.1 || ^4.0.0" - yargs-parser "^11.1.1" - -zepto@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/zepto/-/zepto-1.2.0.tgz#e127bd9e66fd846be5eab48c1394882f7c0e4f98" - integrity sha1-4Se9nmb9hGvl6rSME5SIL3wOT5g= From ea10d1cfc9e56b25dfc35bdf54944bcc515a16e6 Mon Sep 17 00:00:00 2001 From: ethan Date: Thu, 30 Jan 2020 21:11:05 +0800 Subject: [PATCH 103/529] fix chinese sdk tutorials URL (#5590) --- docs/cn/intro/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/cn/intro/README.md b/docs/cn/intro/README.md index 8181bcda1120..81609d2a7378 100644 --- a/docs/cn/intro/README.md +++ b/docs/cn/intro/README.md @@ -28,4 +28,4 @@ Cosmos SDK 是目前用于构建自定义的特定应用区块链的最先进的 ## 开始使用 Cosmos SDK * 了解[SDK 应用体系架构](./sdk-app-architecture.md)的详细信息 -* 了解如何从头构建特定应用区块链,参考[SDK教程](/docs/tutorial) 。 \ No newline at end of file +* 了解如何从头构建特定应用区块链,参考[SDK教程](https://tutorials.cosmos.network/) 。 From 5a0a36a8c97e59723c7eaa10ebe5e8a8a77ce43c Mon Sep 17 00:00:00 2001 From: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Date: Thu, 30 Jan 2020 16:13:42 +0100 Subject: [PATCH 104/529] Merge Pr #5585: client and types additions for IBC --- CHANGELOG.md | 6 +++++ client/context/query.go | 51 +++++++++++++++++++++++++++-------------- client/flags/flags.go | 6 +++++ store/types/store.go | 4 ++++ types/coin.go | 4 ++-- types/rest/rest.go | 11 +++++++++ types/store.go | 1 + 7 files changed, 64 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a0bbca18522d..ff09e4e9cb67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,12 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (types) [\#5581](https://github.com/cosmos/cosmos-sdk/pull/5581) Add convenience functions {,Must}Bech32ifyAddressBytes. * (staking) [\#5584](https://github.com/cosmos/cosmos-sdk/pull/5584) Add util function `ToTmValidator` that converts a `staking.Validator` type to `*tmtypes.Validator`. +* (client) [\#5585](https://github.com/cosmos/cosmos-sdk/pull/5585) IBC additions: + * Added `prove` flag for commitment proof verification. + * Added `queryABCI` function that returns the full `abci.ResponseQuery` with inclusion merkle proofs. +* (types) [\#5585](https://github.com/cosmos/cosmos-sdk/pull/5585) IBC additions: + * `Coin` denomination max lenght has been increased to 32. + * Added `CapabilityKey` alias for `StoreKey` to match IBC spec. ## [v0.38.0] - 2020-01-23 diff --git a/client/context/query.go b/client/context/query.go index dcf2c92b7f36..b5686f864165 100644 --- a/client/context/query.go +++ b/client/context/query.go @@ -49,6 +49,12 @@ func (ctx CLIContext) QueryStore(key tmbytes.HexBytes, storeName string) ([]byte return ctx.queryStore(key, storeName, "key") } +// QueryABCI performs a query to a Tendermint node with the provide RequestQuery. +// It returns the ResultQuery obtained from the query. +func (ctx CLIContext) QueryABCI(req abci.RequestQuery) (abci.ResponseQuery, error) { + return ctx.queryABCI(req) +} + // QuerySubspace performs a query to a Tendermint node with the provided // store name and subspace. It returns key value pair and height of the query // upon success or an error if the query fails. @@ -72,40 +78,51 @@ func (ctx CLIContext) GetFromName() string { return ctx.FromName } -// query performs a query to a Tendermint node with the provided store name -// and path. It returns the result and height of the query upon success -// or an error if the query fails. In addition, it will verify the returned -// proof if TrustNode is disabled. If proof verification fails or the query -// height is invalid, an error will be returned. -func (ctx CLIContext) query(path string, key tmbytes.HexBytes) (res []byte, height int64, err error) { +func (ctx CLIContext) queryABCI(req abci.RequestQuery) (abci.ResponseQuery, error) { node, err := ctx.GetNode() if err != nil { - return res, height, err + return abci.ResponseQuery{}, err } opts := rpcclient.ABCIQueryOptions{ Height: ctx.Height, - Prove: !ctx.TrustNode, + Prove: req.Prove || !ctx.TrustNode, } - result, err := node.ABCIQueryWithOptions(path, key, opts) + result, err := node.ABCIQueryWithOptions(req.Path, req.Data, opts) if err != nil { - return res, height, err + return abci.ResponseQuery{}, err } - resp := result.Response - if !resp.IsOK() { - return res, resp.Height, errors.New(resp.Log) + if !result.Response.IsOK() { + return abci.ResponseQuery{}, errors.New(result.Response.Log) } // data from trusted node or subspace query doesn't need verification - if ctx.TrustNode || !isQueryStoreWithProof(path) { - return resp.Value, resp.Height, nil + if ctx.TrustNode || !isQueryStoreWithProof(req.Path) { + return result.Response, nil } - err = ctx.verifyProof(path, resp) + err = ctx.verifyProof(req.Path, result.Response) + if err != nil { + return abci.ResponseQuery{}, err + } + + return result.Response, nil +} + +// query performs a query to a Tendermint node with the provided store name +// and path. It returns the result and height of the query upon success +// or an error if the query fails. In addition, it will verify the returned +// proof if TrustNode is disabled. If proof verification fails or the query +// height is invalid, an error will be returned. +func (ctx CLIContext) query(path string, key tmbytes.HexBytes) ([]byte, int64, error) { + resp, err := ctx.queryABCI(abci.RequestQuery{ + Path: path, + Data: key, + }) if err != nil { - return res, resp.Height, err + return nil, 0, err } return resp.Value, resp.Height, nil diff --git a/client/flags/flags.go b/client/flags/flags.go index 2cdaa5f2137f..64dc2f25a34f 100644 --- a/client/flags/flags.go +++ b/client/flags/flags.go @@ -24,7 +24,9 @@ const ( // DefaultKeyringBackend DefaultKeyringBackend = keys.BackendOS +) +const ( // BroadcastBlock defines a tx broadcasting mode where the client waits for // the tx to be committed in a block. BroadcastBlock = "block" @@ -34,7 +36,10 @@ const ( // BroadcastAsync defines a tx broadcasting mode where the client returns // immediately. BroadcastAsync = "async" +) +// List of CLI flags +const ( FlagHome = tmcli.HomeFlag FlagUseLedger = "ledger" FlagChainID = "chain-id" @@ -59,6 +64,7 @@ const ( FlagRPCWriteTimeout = "write-timeout" FlagOutputDocument = "output-document" // inspired by wget -O FlagSkipConfirmation = "yes" + FlagProve = "prove" FlagKeyringBackend = "keyring-backend" FlagPage = "page" FlagLimit = "limit" diff --git a/store/types/store.go b/store/types/store.go index 377b43909e11..d48585f8fce2 100644 --- a/store/types/store.go +++ b/store/types/store.go @@ -277,6 +277,10 @@ type StoreKey interface { String() string } +// CapabilityKey represent the Cosmos SDK keys for object-capability +// generation in the IBC protocol as defined in https://github.com/cosmos/ics/tree/master/spec/ics-005-port-allocation#data-structures +type CapabilityKey StoreKey + // KVStoreKey is used for accessing substores. // Only the pointer value should ever be used - it functions as a capabilities key. type KVStoreKey struct { diff --git a/types/coin.go b/types/coin.go index 12d82a6e01e9..6a759d569387 100644 --- a/types/coin.go +++ b/types/coin.go @@ -580,8 +580,8 @@ func (coins Coins) Sort() Coins { // Parsing var ( - // Denominations can be 3 ~ 16 characters long. - reDnmString = `[a-z][a-z0-9]{2,15}` + // Denominations can be 3 ~ 32 characters long. + reDnmString = `[a-z][a-z0-9/]{2,31}` reAmt = `[[:digit:]]+` reDecAmt = `[[:digit:]]*\.[[:digit:]]+` reSpc = `[[:space:]]*` diff --git a/types/rest/rest.go b/types/rest/rest.go index 89770c944650..a58a56252553 100644 --- a/types/rest/rest.go +++ b/types/rest/rest.go @@ -375,3 +375,14 @@ func ParseHTTPArgsWithLimit(r *http.Request, defaultLimit int) (tags []string, p func ParseHTTPArgs(r *http.Request) (tags []string, page, limit int, err error) { return ParseHTTPArgsWithLimit(r, DefaultLimit) } + +// ParseQueryParamBool parses the given param to a boolean. It returns false by +// default if the string is not parseable to bool. +func ParseQueryParamBool(r *http.Request, param string) bool { + valueStr := r.FormValue(param) + value := false + if ok, err := strconv.ParseBool(valueStr); err == nil { + value = ok + } + return value +} diff --git a/types/store.go b/types/store.go index ce890f2f6f75..6057526c80e9 100644 --- a/types/store.go +++ b/types/store.go @@ -81,6 +81,7 @@ const ( // nolint - reexport type ( StoreKey = types.StoreKey + CapabilityKey = types.CapabilityKey KVStoreKey = types.KVStoreKey TransientStoreKey = types.TransientStoreKey ) From b669ac5eaa8738c2807418628c32889b9870b325 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Thu, 30 Jan 2020 11:26:16 -0500 Subject: [PATCH 105/529] Merge PR #5591: Ignore testdata --- buf.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/buf.yaml b/buf.yaml index 8507c9cd41c0..a0b081889b21 100644 --- a/buf.yaml +++ b/buf.yaml @@ -12,6 +12,7 @@ lint: - PACKAGE_DIRECTORY_MATCH ignore: - third_party + - codec/testdata breaking: use: - FILE From 6890feb3d28a1d98a8c8cd52669aca78361f5250 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Thu, 30 Jan 2020 16:31:16 -0500 Subject: [PATCH 106/529] Merge PR #5572: ADR 004 Implementation --- CHANGELOG.md | 15 + .../adr-004-split-denomination-keys.md | 77 ++- simapp/app.go | 28 +- simapp/genesis_account.go | 3 - simapp/genesis_account_test.go | 17 +- simapp/test_helpers.go | 9 +- store/prefix/store_test.go | 4 +- x/auth/ante/ante_test.go | 61 +- x/auth/ante/fee.go | 21 - x/auth/ante/fee_test.go | 4 +- x/auth/client/cli/query.go | 2 +- x/auth/exported/exported.go | 10 +- x/auth/exported/exported_test.go | 2 +- x/auth/keeper/keeper_bench_test.go | 52 -- x/auth/legacy/v0_38/migrate.go | 4 +- x/auth/legacy/v0_38/types.go | 12 +- x/auth/legacy/v0_39/migrate.go | 23 + x/auth/legacy/v0_39/migrate_test.go | 87 +++ x/auth/legacy/v0_39/types.go | 8 + x/auth/simulation/genesis.go | 13 +- x/auth/spec/05_vesting.md | 114 +-- x/auth/types/account.go | 28 +- x/auth/types/account_test.go | 21 +- x/auth/types/genesis.go | 6 - x/auth/types/genesis_test.go | 15 - x/auth/vesting/exported/exported.go | 18 +- x/auth/vesting/types/genesis_test.go | 12 +- x/auth/vesting/types/vesting_account.go | 120 ++-- x/auth/vesting/types/vesting_account_test.go | 354 ++++------ x/bank/alias.go | 34 +- x/bank/app_test.go | 66 +- x/bank/bench_test.go | 37 +- x/bank/client/cli/query.go | 99 +++ x/bank/client/rest/query.go | 28 +- x/bank/client/rest/rest.go | 12 + x/bank/client/rest/tx.go | 6 - x/bank/exported/exported.go | 12 + x/bank/genesis.go | 42 +- x/bank/internal/keeper/integration_test.go | 19 - x/bank/internal/keeper/invariants.go | 33 +- x/bank/internal/keeper/keeper.go | 425 ++++++++---- x/bank/internal/keeper/keeper_test.go | 650 ++++++++++-------- x/bank/internal/keeper/querier.go | 36 +- x/bank/internal/keeper/querier_test.go | 96 ++- x/bank/internal/types/genesis.go | 82 ++- x/bank/internal/types/key.go | 35 +- x/bank/internal/types/key_test.go | 25 + x/bank/internal/types/msgs.go | 3 - x/bank/internal/types/querier.go | 21 +- x/bank/legacy/v0_38/types.go | 14 + x/bank/legacy/v0_39/migrate.go | 22 + x/bank/legacy/v0_39/migrate_test.go | 67 ++ x/bank/legacy/v0_39/types.go | 43 ++ x/bank/module.go | 6 +- x/bank/simulation/genesis.go | 21 +- x/bank/simulation/operations.go | 48 +- x/crisis/handler_test.go | 2 +- x/distribution/genesis.go | 7 +- x/distribution/keeper/allocation.go | 2 +- x/distribution/keeper/allocation_test.go | 10 +- x/distribution/keeper/delegation_test.go | 27 +- x/distribution/keeper/invariants.go | 10 +- x/distribution/keeper/keeper.go | 4 +- x/distribution/keeper/keeper_test.go | 16 +- x/distribution/keeper/querier_test.go | 2 +- x/distribution/keeper/test_common.go | 31 +- x/distribution/module.go | 15 +- x/distribution/proposal_handler_test.go | 34 +- x/distribution/simulation/operations.go | 36 +- x/distribution/types/expected_keepers.go | 9 + x/evidence/internal/keeper/infraction_test.go | 14 +- x/evidence/internal/keeper/keeper_test.go | 6 + x/genutil/client/cli/collect.go | 4 +- x/genutil/client/cli/gentx.go | 4 +- x/genutil/client/cli/migrate.go | 2 + x/genutil/collect.go | 46 +- x/genutil/gentx.go | 70 +- x/genutil/legacy/v0_39/migrate.go | 55 ++ x/genutil/types/expected_keepers.go | 12 +- x/gov/abci_test.go | 7 +- x/gov/genesis.go | 7 +- x/gov/genesis_test.go | 6 +- x/gov/keeper/deposit_test.go | 16 +- x/gov/keeper/invariants.go | 15 +- x/gov/keeper/keeper_test.go | 4 +- x/gov/keeper/proposal_test.go | 8 +- x/gov/keeper/querier_test.go | 4 +- x/gov/keeper/tally_test.go | 30 +- x/gov/keeper/test_common.go | 23 +- x/gov/keeper/vote_test.go | 2 +- x/gov/module.go | 15 +- x/gov/simulation/operations.go | 50 +- x/gov/test_common.go | 38 +- x/gov/types/expected_keepers.go | 9 + x/mock/app.go | 58 +- x/mock/app_test.go | 10 +- x/mock/test_utils.go | 6 +- x/mock/types.go | 18 +- x/simulation/account_test.go | 2 + x/simulation/rand_util_test.go | 2 + x/slashing/abci_test.go | 4 +- x/slashing/app_test.go | 32 +- x/slashing/handler_test.go | 19 +- x/slashing/internal/keeper/keeper_test.go | 6 +- x/slashing/internal/keeper/test_common.go | 16 +- x/slashing/internal/types/expected_keepers.go | 9 + x/slashing/module.go | 14 +- x/slashing/simulation/operations.go | 12 +- x/staking/app_test.go | 48 +- x/staking/genesis.go | 16 +- x/staking/genesis_test.go | 8 +- x/staking/handler_test.go | 66 +- x/staking/keeper/delegation_test.go | 137 ++-- x/staking/keeper/historical_info_test.go | 4 +- x/staking/keeper/invariants.go | 6 +- x/staking/keeper/keeper.go | 12 +- x/staking/keeper/keeper_test.go | 2 +- x/staking/keeper/pool.go | 7 +- x/staking/keeper/querier.go | 4 +- x/staking/keeper/querier_test.go | 21 +- x/staking/keeper/slash_test.go | 162 +++-- x/staking/keeper/test_common.go | 21 +- x/staking/keeper/validator_test.go | 74 +- x/staking/module.go | 15 +- x/staking/simulation/operations.go | 65 +- x/staking/types/expected_keepers.go | 9 + x/supply/genesis.go | 9 +- x/supply/internal/keeper/bank_test.go | 62 +- x/supply/internal/keeper/invariants.go | 5 +- x/supply/internal/types/account.go | 5 +- x/supply/internal/types/account_test.go | 7 +- x/supply/internal/types/expected_keepers.go | 5 + x/supply/module.go | 6 +- 133 files changed, 2942 insertions(+), 1816 deletions(-) create mode 100644 x/auth/legacy/v0_39/migrate.go create mode 100644 x/auth/legacy/v0_39/migrate_test.go create mode 100644 x/auth/legacy/v0_39/types.go create mode 100644 x/bank/client/cli/query.go create mode 100644 x/bank/client/rest/rest.go create mode 100644 x/bank/exported/exported.go delete mode 100644 x/bank/internal/keeper/integration_test.go create mode 100644 x/bank/internal/types/key_test.go create mode 100644 x/bank/legacy/v0_38/types.go create mode 100644 x/bank/legacy/v0_39/migrate.go create mode 100644 x/bank/legacy/v0_39/migrate_test.go create mode 100644 x/bank/legacy/v0_39/types.go create mode 100644 x/genutil/legacy/v0_39/migrate.go diff --git a/CHANGELOG.md b/CHANGELOG.md index ff09e4e9cb67..1764c8d33313 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,14 +37,29 @@ Ref: https://keepachangelog.com/en/1.0.0/ ## [Unreleased] +### Client Breaking + +* (modules) [\#5572](https://github.com/cosmos/cosmos-sdk/pull/5572) The `/bank/balances/{address}` endpoint now returns all account +balances or a single balance by denom when the `denom` query parameter is present. + ### API Breaking Changes * (modules) [\#5555](https://github.com/cosmos/cosmos-sdk/pull/5555) Move x/auth/client/utils/ types and functions to x/auth/client/. +* (modules) [\#5572](https://github.com/cosmos/cosmos-sdk/pull/5572) Move account balance logic and APIs from `x/auth` to `x/bank`. ### Bug Fixes * (x/bank) [\#5531](https://github.com/cosmos/cosmos-sdk/issues/5531) Added missing amount event to MsgMultiSend, emitted for each output. +### State Machine Breaking + +* (modules) [\#5572](https://github.com/cosmos/cosmos-sdk/pull/5572) Separate balance from accounts per ADR 004. + * Account balances are now persisted and retrieved via the `x/bank` module. + * Vesting account interface has been modified to account for changes. + * Callers to `NewBaseVestingAccount` are responsible for verifying account balance in relation to + the original vesting amount. + * The `SendKeeper` and `ViewKeeper` interfaces in `x/bank` have been modified to account for changes. + ### Improvements * (types) [\#5581](https://github.com/cosmos/cosmos-sdk/pull/5581) Add convenience functions {,Must}Bech32ifyAddressBytes. diff --git a/docs/architecture/adr-004-split-denomination-keys.md b/docs/architecture/adr-004-split-denomination-keys.md index 5e91f7da3561..8f97cb0d2a45 100644 --- a/docs/architecture/adr-004-split-denomination-keys.md +++ b/docs/architecture/adr-004-split-denomination-keys.md @@ -5,6 +5,7 @@ - 2020-01-08: Initial version - 2020-01-09: Alterations to handle vesting accounts - 2020-01-14: Updates from review feedback +- 2020-01-30: Updates from implementation ## Context @@ -18,35 +19,74 @@ Balances shall be stored per-account & per-denomination under a denomination- an ### Account interface (x/auth) -`GetCoins()` and `SetCoins()` will be removed from the account interface, since coin balances will now be stored in & managed by the bank module. +`GetCoins()` and `SetCoins()` will be removed from the account interface, since coin balances will +now be stored in & managed by the bank module. -`SpendableCoinsVestingAccount()` and `TrackDelegation()` will be altered to take a bank keeper and a denomination as two additional arguments, which will be used to lookup the balances from the base account as necessary. +The vesting account interface will replace `SpendableCoins` in favor of `LockedCoins` which does +not require the account balance anymore. In addition, `TrackDelegation()` will now accept the +account balance of all tokens denominated in the vesting balance instead of loading the entire +account balance. -Vesting accounts will continue to store original vesting, delegated free, and delegated vesting coins (which is safe since these cannot contain arbitrary denominations). +Vesting accounts will continue to store original vesting, delegated free, and delegated +vesting coins (which is safe since these cannot contain arbitrary denominations). ### Bank keeper (x/bank) -`GetBalance(addr AccAddress, denom string) sdk.Coin` and `SetBalance(addr AccAddress, coin sdk.Coin)` methods will be added to the bank keeper to retrieve & set balances, respectively. +The following APIs will be added to the `x/bank` keeper: -Balances will be stored first by the address, then by the denomination (the reverse is also possible, but retrieval of all balances for a single account is presumed to be more frequent): +- `GetAllBalances(ctx Context, addr AccAddress) Coins` +- `GetBalance(ctx Context, addr AccAddress, denom string) Coin` +- `SetBalance(ctx Context, addr AccAddress, coin Coin)` +- `LockedCoins(ctx Context, addr AccAddress) Coins` +- `SpendableCoins(ctx Context, addr AccAddress) Coins` + +Additional APIs may be added to facilitate iteration and auxiliary functionality not essential to +core functionality or persistence. + +Balances will be stored first by the address, then by the denomination (the reverse is also possible, +but retrieval of all balances for a single account is presumed to be more frequent): ```golang -func BalanceKey(addr sdk.AccAddress, denom string) []byte { - return append(append(BalanceKeyPrefix, addr.Bytes()...), []byte(denom)...) +var BalancesPrefix = []byte("balances") + +func (k Keeper) SetBalance(ctx Context, addr AccAddress, balance Coin) error { + if !balance.IsValid() { + return err + } + + store := ctx.KVStore(k.storeKey) + balancesStore := prefix.NewStore(store, BalancesPrefix) + accountStore := prefix.NewStore(balancesStore, addr.Bytes()) + + bz := Marshal(balance) + accountStore.Set([]byte(balance.Denom), bz) + + return nil } ``` -`DelegateCoins()` and `UndelegateCoins()` will be altered to take a single `sdk.Coin` (one denomination & amount) instead of `sdk.Coins`, since they should only operate on one denomination. They will read balances directly instead of calling `GetCoins()` (which no longer exists). +This will result in the balances being indexed by the byte representation of +`balances/{address}/{denom}`. + +`DelegateCoins()` and `UndelegateCoins()` will be altered to only load each individual +account balance by denomination found in the (un)delegation amount. As a result, +any mutations to the account balance by will made by denomination. -`SubtractCoins()` and `AddCoins()` will be altered to read & write the balances directly instead of calling `GetCoins()` / `SetCoins()` (which no longer exist). +`SubtractCoins()` and `AddCoins()` will be altered to read & write the balances +directly instead of calling `GetCoins()` / `SetCoins()` (which no longer exist). -`trackDelegation()` and `trackUndelegation()` will be altered to read & write the balances directly instead of calling `GetCoins()` / `SetCoins()` (which no longer exist). +`trackDelegation()` and `trackUndelegation()` will be altered to no longer update +account balances. -External APIs will need to scan all balances under an account to retain backwards-compatibility - additional methods should be added to fetch a balance for a single denomination only. +External APIs will need to scan all balances under an account to retain backwards-compatibility. It +is advised that these APIs use `GetBalance` and `SetBalance` instead of `GetAllBalances` when +possible as to not load the entire account balance. ### Supply module -The supply module, in order to implement the total supply invariant, will now need to scan all accounts & call `GetBalance` using the `x/bank` Keeper for the denomination in question, then sum the balances and check that they match the expected total supply. +The supply module, in order to implement the total supply invariant, will now need +to scan all accounts & call `GetAllBalances` using the `x/bank` Keeper, then sum +the balances and check that they match the expected total supply. ## Status @@ -56,11 +96,14 @@ Proposed. ### Positive -- O(1) reads & writes of balances (with respect to the number of denominations for which an account has non-zero balances) +- O(1) reads & writes of balances (with respect to the number of denominations for +which an account has non-zero balances). Note, this does not relate to the actual +I/O cost, rather the total number of direct reads needed. ### Negative -- Slighly less efficient reads/writes when reading & writing all balances of a single account in a transaction. +- Slightly less efficient reads/writes when reading & writing all balances of a +single account in a transaction. ### Neutral @@ -68,6 +111,6 @@ None in particular. ## References -Ref https://github.com/cosmos/cosmos-sdk/issues/4982 -Ref https://github.com/cosmos/cosmos-sdk/issues/5467 -Ref https://github.com/cosmos/cosmos-sdk/issues/5492 +- Ref: https://github.com/cosmos/cosmos-sdk/issues/4982 +- Ref: https://github.com/cosmos/cosmos-sdk/issues/5467 +- Ref: https://github.com/cosmos/cosmos-sdk/issues/5492 diff --git a/simapp/app.go b/simapp/app.go index c074f8ccce05..e3a589adb877 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -142,7 +142,7 @@ func NewSimApp( bApp.SetAppVersion(version.Version) keys := sdk.NewKVStoreKeys( - bam.MainStoreKey, auth.StoreKey, staking.StoreKey, + bam.MainStoreKey, auth.StoreKey, bank.StoreKey, staking.StoreKey, supply.StoreKey, mint.StoreKey, distr.StoreKey, slashing.StoreKey, gov.StoreKey, params.StoreKey, upgrade.StoreKey, evidence.StoreKey, ) @@ -174,20 +174,20 @@ func NewSimApp( app.cdc, keys[auth.StoreKey], app.subspaces[auth.ModuleName], auth.ProtoBaseAccount, ) app.BankKeeper = bank.NewBaseKeeper( - app.AccountKeeper, app.subspaces[bank.ModuleName], app.BlacklistedAccAddrs(), + app.cdc, keys[bank.StoreKey], app.AccountKeeper, app.subspaces[bank.ModuleName], app.BlacklistedAccAddrs(), ) app.SupplyKeeper = supply.NewKeeper( app.cdc, keys[supply.StoreKey], app.AccountKeeper, app.BankKeeper, maccPerms, ) stakingKeeper := staking.NewKeeper( - app.cdc, keys[staking.StoreKey], app.SupplyKeeper, app.subspaces[staking.ModuleName], + app.cdc, keys[staking.StoreKey], app.BankKeeper, app.SupplyKeeper, app.subspaces[staking.ModuleName], ) app.MintKeeper = mint.NewKeeper( app.cdc, keys[mint.StoreKey], app.subspaces[mint.ModuleName], &stakingKeeper, app.SupplyKeeper, auth.FeeCollectorName, ) app.DistrKeeper = distr.NewKeeper( - app.cdc, keys[distr.StoreKey], app.subspaces[distr.ModuleName], &stakingKeeper, + app.cdc, keys[distr.StoreKey], app.subspaces[distr.ModuleName], app.BankKeeper, &stakingKeeper, app.SupplyKeeper, auth.FeeCollectorName, app.ModuleAccountAddrs(), ) app.SlashingKeeper = slashing.NewKeeper( @@ -231,12 +231,12 @@ func NewSimApp( auth.NewAppModule(app.AccountKeeper), bank.NewAppModule(app.BankKeeper, app.AccountKeeper), crisis.NewAppModule(&app.CrisisKeeper), - supply.NewAppModule(app.SupplyKeeper, app.AccountKeeper), - gov.NewAppModule(app.GovKeeper, app.AccountKeeper, app.SupplyKeeper), + supply.NewAppModule(app.SupplyKeeper, app.BankKeeper, app.AccountKeeper), + gov.NewAppModule(app.GovKeeper, app.AccountKeeper, app.BankKeeper, app.SupplyKeeper), mint.NewAppModule(app.MintKeeper), - slashing.NewAppModule(app.SlashingKeeper, app.AccountKeeper, app.StakingKeeper), - distr.NewAppModule(app.DistrKeeper, app.AccountKeeper, app.SupplyKeeper, app.StakingKeeper), - staking.NewAppModule(app.StakingKeeper, app.AccountKeeper, app.SupplyKeeper), + slashing.NewAppModule(app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper), + distr.NewAppModule(app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.SupplyKeeper, app.StakingKeeper), + staking.NewAppModule(app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.SupplyKeeper), upgrade.NewAppModule(app.UpgradeKeeper), evidence.NewAppModule(app.EvidenceKeeper), ) @@ -265,12 +265,12 @@ func NewSimApp( app.sm = module.NewSimulationManager( auth.NewAppModule(app.AccountKeeper), bank.NewAppModule(app.BankKeeper, app.AccountKeeper), - supply.NewAppModule(app.SupplyKeeper, app.AccountKeeper), - gov.NewAppModule(app.GovKeeper, app.AccountKeeper, app.SupplyKeeper), + supply.NewAppModule(app.SupplyKeeper, app.BankKeeper, app.AccountKeeper), + gov.NewAppModule(app.GovKeeper, app.AccountKeeper, app.BankKeeper, app.SupplyKeeper), mint.NewAppModule(app.MintKeeper), - staking.NewAppModule(app.StakingKeeper, app.AccountKeeper, app.SupplyKeeper), - distr.NewAppModule(app.DistrKeeper, app.AccountKeeper, app.SupplyKeeper, app.StakingKeeper), - slashing.NewAppModule(app.SlashingKeeper, app.AccountKeeper, app.StakingKeeper), + staking.NewAppModule(app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.SupplyKeeper), + distr.NewAppModule(app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.SupplyKeeper, app.StakingKeeper), + slashing.NewAppModule(app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper), params.NewAppModule(), // NOTE: only used for simulation to generate randomized param change proposals ) diff --git a/simapp/genesis_account.go b/simapp/genesis_account.go index e6bc7f97c04d..d995f7023e14 100644 --- a/simapp/genesis_account.go +++ b/simapp/genesis_account.go @@ -31,9 +31,6 @@ type SimGenesisAccount struct { // Validate checks for errors on the vesting and module account parameters func (sga SimGenesisAccount) Validate() error { if !sga.OriginalVesting.IsZero() { - if sga.OriginalVesting.IsAnyGT(sga.Coins) { - return errors.New("vesting amount cannot be greater than total amount") - } if sga.StartTime >= sga.EndTime { return errors.New("vesting start-time cannot be before end-time") } diff --git a/simapp/genesis_account_test.go b/simapp/genesis_account_test.go index 6c0c6d6775c5..385bb7b217b6 100644 --- a/simapp/genesis_account_test.go +++ b/simapp/genesis_account_test.go @@ -20,8 +20,7 @@ func TestSimGenesisAccountValidate(t *testing.T) { vestingStart := time.Now().UTC() coins := sdk.NewCoins(sdk.NewInt64Coin("test", 1000)) - baseAcc := authtypes.NewBaseAccount(addr, nil, pubkey, 0, 0) - require.NoError(t, baseAcc.SetCoins(coins)) + baseAcc := authtypes.NewBaseAccount(addr, pubkey, 0, 0) testCases := []struct { name string @@ -38,14 +37,14 @@ func TestSimGenesisAccountValidate(t *testing.T) { { "invalid basic account with mismatching address/pubkey", simapp.SimGenesisAccount{ - BaseAccount: authtypes.NewBaseAccount(addr, nil, secp256k1.GenPrivKey().PubKey(), 0, 0), + BaseAccount: authtypes.NewBaseAccount(addr, secp256k1.GenPrivKey().PubKey(), 0, 0), }, true, }, { "valid basic account with module name", simapp.SimGenesisAccount{ - BaseAccount: authtypes.NewBaseAccount(sdk.AccAddress(crypto.AddressHash([]byte("testmod"))), nil, nil, 0, 0), + BaseAccount: authtypes.NewBaseAccount(sdk.AccAddress(crypto.AddressHash([]byte("testmod"))), nil, 0, 0), ModuleName: "testmod", }, false, @@ -78,16 +77,6 @@ func TestSimGenesisAccountValidate(t *testing.T) { }, true, }, - { - "valid basic account with invalid original vesting coins", - simapp.SimGenesisAccount{ - BaseAccount: baseAcc, - OriginalVesting: coins.Add(coins...), - StartTime: vestingStart.Unix(), - EndTime: vestingStart.Add(1 * time.Hour).Unix(), - }, - true, - }, } for _, tc := range testCases { diff --git a/simapp/test_helpers.go b/simapp/test_helpers.go index 5192e59feab0..3f2967e58f16 100644 --- a/simapp/test_helpers.go +++ b/simapp/test_helpers.go @@ -1,7 +1,6 @@ package simapp import ( - "os" "testing" "github.com/stretchr/testify/require" @@ -48,7 +47,7 @@ func Setup(isCheckTx bool) *SimApp { // genesis accounts. func SetupWithGenesisAccounts(genAccs []authexported.GenesisAccount) *SimApp { db := dbm.NewMemDB() - app := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, 0) + app := NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, 0) // initialize the chain with the passed in genesis accounts genesisState := NewDefaultGenesisState() @@ -101,11 +100,9 @@ func AddTestAddrs(app *SimApp, ctx sdk.Context, accNum int, accAmt sdk.Int) []sd } // CheckBalance checks the balance of an account. -func CheckBalance(t *testing.T, app *SimApp, addr sdk.AccAddress, exp sdk.Coins) { +func CheckBalance(t *testing.T, app *SimApp, addr sdk.AccAddress, balances sdk.Coins) { ctxCheck := app.BaseApp.NewContext(true, abci.Header{}) - res := app.AccountKeeper.GetAccount(ctxCheck, addr) - - require.True(t, exp.IsEqual(res.GetCoins())) + require.True(t, balances.IsEqual(app.BankKeeper.GetAllBalances(ctxCheck, addr))) } // SignCheckDeliver checks a generated signed transaction and simulates a diff --git a/store/prefix/store_test.go b/store/prefix/store_test.go index 8431459748d0..b5e99329055b 100644 --- a/store/prefix/store_test.go +++ b/store/prefix/store_test.go @@ -18,9 +18,7 @@ import ( // copied from iavl/store_test.go var ( - cacheSize = 100 - numRecent int64 = 5 - storeEvery int64 = 3 + cacheSize = 100 ) func bz(s string) []byte { return []byte(s) } diff --git a/x/auth/ante/ante_test.go b/x/auth/ante/ante_test.go index 1d55b4d320c3..752895456970 100644 --- a/x/auth/ante/ante_test.go +++ b/x/auth/ante/ante_test.go @@ -47,17 +47,17 @@ func TestSimulateGasCost(t *testing.T) { // set the accounts acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) - acc1.SetCoins(types.NewTestCoins()) require.NoError(t, acc1.SetAccountNumber(0)) app.AccountKeeper.SetAccount(ctx, acc1) + app.BankKeeper.SetBalances(ctx, acc1.GetAddress(), types.NewTestCoins()) acc2 := app.AccountKeeper.NewAccountWithAddress(ctx, addr2) - acc2.SetCoins(types.NewTestCoins()) require.NoError(t, acc2.SetAccountNumber(1)) app.AccountKeeper.SetAccount(ctx, acc2) + app.BankKeeper.SetBalances(ctx, acc2.GetAddress(), types.NewTestCoins()) acc3 := app.AccountKeeper.NewAccountWithAddress(ctx, addr3) - acc3.SetCoins(types.NewTestCoins()) require.NoError(t, acc3.SetAccountNumber(2)) app.AccountKeeper.SetAccount(ctx, acc3) + app.BankKeeper.SetBalances(ctx, acc3.GetAddress(), types.NewTestCoins()) // set up msgs and fee var tx sdk.Tx @@ -128,8 +128,8 @@ func TestAnteHandlerSigErrors(t *testing.T) { // save the first account, but second is still unrecognized acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) - acc1.SetCoins(fee.Amount) app.AccountKeeper.SetAccount(ctx, acc1) + app.BankKeeper.SetBalances(ctx, addr1, fee.Amount) checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrUnknownAddress) } @@ -146,13 +146,13 @@ func TestAnteHandlerAccountNumbers(t *testing.T) { // set the accounts acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) - acc1.SetCoins(types.NewTestCoins()) require.NoError(t, acc1.SetAccountNumber(0)) app.AccountKeeper.SetAccount(ctx, acc1) + app.BankKeeper.SetBalances(ctx, addr1, types.NewTestCoins()) acc2 := app.AccountKeeper.NewAccountWithAddress(ctx, addr2) - acc2.SetCoins(types.NewTestCoins()) require.NoError(t, acc2.SetAccountNumber(1)) app.AccountKeeper.SetAccount(ctx, acc2) + app.BankKeeper.SetBalances(ctx, addr2, types.NewTestCoins()) // msg and signatures var tx sdk.Tx @@ -203,12 +203,12 @@ func TestAnteHandlerAccountNumbersAtBlockHeightZero(t *testing.T) { // set the accounts, we don't need the acc numbers as it is in the genesis block acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) - acc1.SetCoins(types.NewTestCoins()) app.AccountKeeper.SetAccount(ctx, acc1) + app.BankKeeper.SetBalances(ctx, addr1, types.NewTestCoins()) acc2 := app.AccountKeeper.NewAccountWithAddress(ctx, addr2) - acc2.SetCoins(types.NewTestCoins()) require.NoError(t, acc2.SetAccountNumber(1)) app.AccountKeeper.SetAccount(ctx, acc2) + app.BankKeeper.SetBalances(ctx, addr2, types.NewTestCoins()) // msg and signatures var tx sdk.Tx @@ -260,17 +260,17 @@ func TestAnteHandlerSequences(t *testing.T) { // set the accounts acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) - acc1.SetCoins(types.NewTestCoins()) require.NoError(t, acc1.SetAccountNumber(0)) app.AccountKeeper.SetAccount(ctx, acc1) + app.BankKeeper.SetBalances(ctx, addr1, types.NewTestCoins()) acc2 := app.AccountKeeper.NewAccountWithAddress(ctx, addr2) - acc2.SetCoins(types.NewTestCoins()) require.NoError(t, acc2.SetAccountNumber(1)) app.AccountKeeper.SetAccount(ctx, acc2) + app.BankKeeper.SetBalances(ctx, addr2, types.NewTestCoins()) acc3 := app.AccountKeeper.NewAccountWithAddress(ctx, addr3) - acc3.SetCoins(types.NewTestCoins()) require.NoError(t, acc3.SetAccountNumber(2)) app.AccountKeeper.SetAccount(ctx, acc3) + app.BankKeeper.SetBalances(ctx, addr3, types.NewTestCoins()) // msg and signatures var tx sdk.Tx @@ -347,19 +347,21 @@ func TestAnteHandlerFees(t *testing.T) { tx = types.NewTestTx(ctx, msgs, privs, accnums, seqs, fee) checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrInsufficientFunds) - acc1.SetCoins(sdk.NewCoins(sdk.NewInt64Coin("atom", 149))) app.AccountKeeper.SetAccount(ctx, acc1) + app.BankKeeper.SetBalances(ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("atom", 149))) checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrInsufficientFunds) - require.True(t, app.SupplyKeeper.GetModuleAccount(ctx, types.FeeCollectorName).GetCoins().Empty()) - require.True(sdk.IntEq(t, app.AccountKeeper.GetAccount(ctx, addr1).GetCoins().AmountOf("atom"), sdk.NewInt(149))) + modAcc := app.SupplyKeeper.GetModuleAccount(ctx, types.FeeCollectorName) + + require.True(t, app.BankKeeper.GetAllBalances(ctx, modAcc.GetAddress()).Empty()) + require.True(sdk.IntEq(t, app.BankKeeper.GetAllBalances(ctx, addr1).AmountOf("atom"), sdk.NewInt(149))) - acc1.SetCoins(sdk.NewCoins(sdk.NewInt64Coin("atom", 150))) app.AccountKeeper.SetAccount(ctx, acc1) + app.BankKeeper.SetBalances(ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("atom", 150))) checkValidTx(t, anteHandler, ctx, tx, false) - require.True(sdk.IntEq(t, app.SupplyKeeper.GetModuleAccount(ctx, types.FeeCollectorName).GetCoins().AmountOf("atom"), sdk.NewInt(150))) - require.True(sdk.IntEq(t, app.AccountKeeper.GetAccount(ctx, addr1).GetCoins().AmountOf("atom"), sdk.NewInt(0))) + require.True(sdk.IntEq(t, app.BankKeeper.GetAllBalances(ctx, modAcc.GetAddress()).AmountOf("atom"), sdk.NewInt(150))) + require.True(sdk.IntEq(t, app.BankKeeper.GetAllBalances(ctx, addr1).AmountOf("atom"), sdk.NewInt(0))) } // Test logic around memo gas consumption. @@ -416,17 +418,17 @@ func TestAnteHandlerMultiSigner(t *testing.T) { // set the accounts acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) - acc1.SetCoins(types.NewTestCoins()) require.NoError(t, acc1.SetAccountNumber(0)) app.AccountKeeper.SetAccount(ctx, acc1) + app.BankKeeper.SetBalances(ctx, addr1, types.NewTestCoins()) acc2 := app.AccountKeeper.NewAccountWithAddress(ctx, addr2) - acc2.SetCoins(types.NewTestCoins()) require.NoError(t, acc2.SetAccountNumber(1)) app.AccountKeeper.SetAccount(ctx, acc2) + app.BankKeeper.SetBalances(ctx, addr2, types.NewTestCoins()) acc3 := app.AccountKeeper.NewAccountWithAddress(ctx, addr3) - acc3.SetCoins(types.NewTestCoins()) require.NoError(t, acc3.SetAccountNumber(2)) app.AccountKeeper.SetAccount(ctx, acc3) + app.BankKeeper.SetBalances(ctx, addr3, types.NewTestCoins()) // set up msgs and fee var tx sdk.Tx @@ -465,13 +467,13 @@ func TestAnteHandlerBadSignBytes(t *testing.T) { // set the accounts acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) - acc1.SetCoins(types.NewTestCoins()) require.NoError(t, acc1.SetAccountNumber(0)) app.AccountKeeper.SetAccount(ctx, acc1) + app.BankKeeper.SetBalances(ctx, addr1, types.NewTestCoins()) acc2 := app.AccountKeeper.NewAccountWithAddress(ctx, addr2) - acc2.SetCoins(types.NewTestCoins()) require.NoError(t, acc2.SetAccountNumber(1)) app.AccountKeeper.SetAccount(ctx, acc2) + app.BankKeeper.SetBalances(ctx, addr2, types.NewTestCoins()) var tx sdk.Tx msg := types.NewTestMsg(addr1) @@ -542,13 +544,13 @@ func TestAnteHandlerSetPubKey(t *testing.T) { // set the accounts acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) - acc1.SetCoins(types.NewTestCoins()) require.NoError(t, acc1.SetAccountNumber(0)) app.AccountKeeper.SetAccount(ctx, acc1) + app.BankKeeper.SetBalances(ctx, addr1, types.NewTestCoins()) acc2 := app.AccountKeeper.NewAccountWithAddress(ctx, addr2) - acc2.SetCoins(types.NewTestCoins()) require.NoError(t, acc2.SetAccountNumber(1)) app.AccountKeeper.SetAccount(ctx, acc2) + app.BankKeeper.SetBalances(ctx, addr2, types.NewTestCoins()) var tx sdk.Tx @@ -669,9 +671,9 @@ func TestAnteHandlerSigLimitExceeded(t *testing.T) { // set the accounts for i, addr := range addrs { acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr) - acc.SetCoins(types.NewTestCoins()) acc.SetAccountNumber(uint64(i)) app.AccountKeeper.SetAccount(ctx, acc) + app.BankKeeper.SetBalances(ctx, addr, types.NewTestCoins()) } var tx sdk.Tx @@ -705,8 +707,8 @@ func TestCustomSignatureVerificationGasConsumer(t *testing.T) { // verify that an secp256k1 account gets rejected priv1, _, addr1 := types.KeyTestPubAddr() acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) - _ = acc1.SetCoins(sdk.NewCoins(sdk.NewInt64Coin("atom", 150))) app.AccountKeeper.SetAccount(ctx, acc1) + app.BankKeeper.SetBalances(ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("atom", 150))) var tx sdk.Tx msg := types.NewTestMsg(addr1) @@ -721,7 +723,8 @@ func TestCustomSignatureVerificationGasConsumer(t *testing.T) { pub2 := priv2.PubKey() addr2 := sdk.AccAddress(pub2.Address()) acc2 := app.AccountKeeper.NewAccountWithAddress(ctx, addr2) - require.NoError(t, acc2.SetCoins(sdk.NewCoins(sdk.NewInt64Coin("atom", 150)))) + + require.NoError(t, app.BankKeeper.SetBalances(ctx, addr2, sdk.NewCoins(sdk.NewInt64Coin("atom", 150)))) require.NoError(t, acc2.SetAccountNumber(1)) app.AccountKeeper.SetAccount(ctx, acc2) msg = types.NewTestMsg(addr2) @@ -745,9 +748,9 @@ func TestAnteHandlerReCheck(t *testing.T) { // set the accounts acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) - acc1.SetCoins(types.NewTestCoins()) require.NoError(t, acc1.SetAccountNumber(0)) app.AccountKeeper.SetAccount(ctx, acc1) + app.BankKeeper.SetBalances(ctx, addr1, types.NewTestCoins()) antehandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, ante.DefaultSigVerificationGasConsumer) @@ -806,8 +809,8 @@ func TestAnteHandlerReCheck(t *testing.T) { ctx = ctx.WithMinGasPrices(sdk.DecCoins{}) // remove funds for account so antehandler fails on recheck - acc1.SetCoins(sdk.Coins{}) app.AccountKeeper.SetAccount(ctx, acc1) + app.BankKeeper.SetBalances(ctx, addr1, sdk.NewCoins()) _, err = antehandler(ctx, tx, false) require.NotNil(t, err, "antehandler on recheck did not fail once feePayer no longer has sufficient funds") diff --git a/x/auth/ante/fee.go b/x/auth/ante/fee.go index 3d81808b2d0c..3283b4fcb08e 100644 --- a/x/auth/ante/fee.go +++ b/x/auth/ante/fee.go @@ -113,32 +113,11 @@ func (dfd DeductFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bo } // DeductFees deducts fees from the given account. -// -// NOTE: We could use the BankKeeper (in addition to the AccountKeeper, because -// the BankKeeper doesn't give us accounts), but it seems easier to do this. func DeductFees(supplyKeeper types.SupplyKeeper, ctx sdk.Context, acc exported.Account, fees sdk.Coins) error { - blockTime := ctx.BlockHeader().Time - coins := acc.GetCoins() - if !fees.IsValid() { return sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "invalid fee amount: %s", fees) } - // verify the account has enough funds to pay for fees - _, hasNeg := coins.SafeSub(fees) - if hasNeg { - return sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, - "insufficient funds to pay for fees; %s < %s", coins, fees) - } - - // Validate the account has enough "spendable" coins as this will cover cases - // such as vesting accounts. - spendableCoins := acc.SpendableCoins(blockTime) - if _, hasNeg := spendableCoins.SafeSub(fees); hasNeg { - return sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, - "insufficient funds to pay for fees; %s < %s", spendableCoins, fees) - } - err := supplyKeeper.SendCoinsFromAccountToModule(ctx, acc.GetAddress(), types.FeeCollectorName, fees) if err != nil { return sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, err.Error()) diff --git a/x/auth/ante/fee_test.go b/x/auth/ante/fee_test.go index b088c1961951..e489b19ba8fb 100644 --- a/x/auth/ante/fee_test.go +++ b/x/auth/ante/fee_test.go @@ -78,8 +78,8 @@ func TestDeductFees(t *testing.T) { // Set account with insufficient funds acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) - acc.SetCoins([]sdk.Coin{sdk.NewCoin("atom", sdk.NewInt(10))}) app.AccountKeeper.SetAccount(ctx, acc) + app.BankKeeper.SetBalances(ctx, addr1, sdk.NewCoins(sdk.NewCoin("atom", sdk.NewInt(10)))) dfd := ante.NewDeductFeeDecorator(app.AccountKeeper, app.SupplyKeeper) antehandler := sdk.ChainAnteDecorators(dfd) @@ -89,8 +89,8 @@ func TestDeductFees(t *testing.T) { require.NotNil(t, err, "Tx did not error when fee payer had insufficient funds") // Set account with sufficient funds - acc.SetCoins([]sdk.Coin{sdk.NewCoin("atom", sdk.NewInt(200))}) app.AccountKeeper.SetAccount(ctx, acc) + app.BankKeeper.SetBalances(ctx, addr1, sdk.NewCoins(sdk.NewCoin("atom", sdk.NewInt(200)))) _, err = antehandler(ctx, tx, false) diff --git a/x/auth/client/cli/query.go b/x/auth/client/cli/query.go index d0ebc155ef98..b3856c565352 100644 --- a/x/auth/client/cli/query.go +++ b/x/auth/client/cli/query.go @@ -46,7 +46,7 @@ func GetQueryCmd(cdc *codec.Codec) *cobra.Command { func GetAccountCmd(cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "account [address]", - Short: "Query account balance", + Short: "Query for account by address", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { cliCtx := context.NewCLIContext().WithCodec(cdc) diff --git a/x/auth/exported/exported.go b/x/auth/exported/exported.go index fe4fb16d8336..7b97e8df1791 100644 --- a/x/auth/exported/exported.go +++ b/x/auth/exported/exported.go @@ -1,8 +1,6 @@ package exported import ( - "time" - "github.com/tendermint/tendermint/crypto" sdk "github.com/cosmos/cosmos-sdk/types" @@ -27,13 +25,6 @@ type Account interface { GetSequence() uint64 SetSequence(uint64) error - GetCoins() sdk.Coins - SetCoins(sdk.Coins) error - - // Calculates the amount of coins that can be sent to other accounts given - // the current time. - SpendableCoins(blockTime time.Time) sdk.Coins - // Ensure that account implements stringer String() string } @@ -56,5 +47,6 @@ func (ga GenesisAccounts) Contains(addr sdk.Address) bool { // GenesisAccount defines a genesis account that embeds an Account with validation capabilities. type GenesisAccount interface { Account + Validate() error } diff --git a/x/auth/exported/exported_test.go b/x/auth/exported/exported_test.go index 8eaab048a8ae..23de4f777e72 100644 --- a/x/auth/exported/exported_test.go +++ b/x/auth/exported/exported_test.go @@ -14,7 +14,7 @@ import ( func TestGenesisAccountsContains(t *testing.T) { pubkey := secp256k1.GenPrivKey().PubKey() addr := sdk.AccAddress(pubkey.Address()) - acc := authtypes.NewBaseAccount(addr, nil, secp256k1.GenPrivKey().PubKey(), 0, 0) + acc := authtypes.NewBaseAccount(addr, secp256k1.GenPrivKey().PubKey(), 0, 0) genAccounts := exported.GenesisAccounts{} require.False(t, genAccounts.Contains(acc.GetAddress())) diff --git a/x/auth/keeper/keeper_bench_test.go b/x/auth/keeper/keeper_bench_test.go index 818c36a7a949..a217eddacae3 100644 --- a/x/auth/keeper/keeper_bench_test.go +++ b/x/auth/keeper/keeper_bench_test.go @@ -24,34 +24,6 @@ func BenchmarkAccountMapperGetAccountFound(b *testing.B) { } } -func BenchmarkAccountMapperGetAccountFoundWithCoins(b *testing.B) { - app, ctx := createTestApp(false) - - coins := sdk.Coins{ - sdk.NewCoin("ltc", sdk.NewInt(1000)), - sdk.NewCoin("btc", sdk.NewInt(1000)), - sdk.NewCoin("eth", sdk.NewInt(1000)), - sdk.NewCoin("xrp", sdk.NewInt(1000)), - sdk.NewCoin("bch", sdk.NewInt(1000)), - sdk.NewCoin("eos", sdk.NewInt(1000)), - } - - // assumes b.N < 2**24 - for i := 0; i < b.N; i++ { - arr := []byte{byte((i & 0xFF0000) >> 16), byte((i & 0xFF00) >> 8), byte(i & 0xFF)} - addr := sdk.AccAddress(arr) - acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr) - acc.SetCoins(coins) - app.AccountKeeper.SetAccount(ctx, acc) - } - - b.ResetTimer() - for i := 0; i < b.N; i++ { - arr := []byte{byte((i & 0xFF0000) >> 16), byte((i & 0xFF00) >> 8), byte(i & 0xFF)} - app.AccountKeeper.GetAccount(ctx, sdk.AccAddress(arr)) - } -} - func BenchmarkAccountMapperSetAccount(b *testing.B) { app, ctx := createTestApp(false) @@ -65,27 +37,3 @@ func BenchmarkAccountMapperSetAccount(b *testing.B) { app.AccountKeeper.SetAccount(ctx, acc) } } - -func BenchmarkAccountMapperSetAccountWithCoins(b *testing.B) { - app, ctx := createTestApp(false) - - coins := sdk.Coins{ - sdk.NewCoin("ltc", sdk.NewInt(1000)), - sdk.NewCoin("btc", sdk.NewInt(1000)), - sdk.NewCoin("eth", sdk.NewInt(1000)), - sdk.NewCoin("xrp", sdk.NewInt(1000)), - sdk.NewCoin("bch", sdk.NewInt(1000)), - sdk.NewCoin("eos", sdk.NewInt(1000)), - } - - b.ResetTimer() - - // assumes b.N < 2**24 - for i := 0; i < b.N; i++ { - arr := []byte{byte((i & 0xFF0000) >> 16), byte((i & 0xFF00) >> 8), byte(i & 0xFF)} - addr := sdk.AccAddress(arr) - acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr) - acc.SetCoins(coins) - app.AccountKeeper.SetAccount(ctx, acc) - } -} diff --git a/x/auth/legacy/v0_38/migrate.go b/x/auth/legacy/v0_38/migrate.go index e76937777678..f4a32b4454c3 100644 --- a/x/auth/legacy/v0_38/migrate.go +++ b/x/auth/legacy/v0_38/migrate.go @@ -42,9 +42,9 @@ func Migrate(authGenState v036auth.GenesisState, genAccountsGenState v036genacco accounts[i] = genAccount } - accounts = sanitizeGenesisAccounts(accounts) + accounts = SanitizeGenesisAccounts(accounts) - if err := validateGenAccounts(accounts); err != nil { + if err := ValidateGenAccounts(accounts); err != nil { panic(err) } diff --git a/x/auth/legacy/v0_38/types.go b/x/auth/legacy/v0_38/types.go index 15896a39121f..1502fb27dbf0 100644 --- a/x/auth/legacy/v0_38/types.go +++ b/x/auth/legacy/v0_38/types.go @@ -46,7 +46,7 @@ type ( BaseAccount struct { Address sdk.AccAddress `json:"address" yaml:"address"` - Coins sdk.Coins `json:"coins" yaml:"coins"` + Coins sdk.Coins `json:"coins,omitempty" yaml:"coins,omitempty"` PubKey crypto.PubKey `json:"public_key" yaml:"public_key"` AccountNumber uint64 `json:"account_number" yaml:"account_number"` Sequence uint64 `json:"sequence" yaml:"sequence"` @@ -54,7 +54,7 @@ type ( baseAccountPretty struct { Address sdk.AccAddress `json:"address" yaml:"address"` - Coins sdk.Coins `json:"coins" yaml:"coins"` + Coins sdk.Coins `json:"coins,omitempty" yaml:"coins,omitempty"` PubKey string `json:"public_key" yaml:"public_key"` AccountNumber uint64 `json:"account_number" yaml:"account_number"` Sequence uint64 `json:"sequence" yaml:"sequence"` @@ -72,7 +72,7 @@ type ( vestingAccountPretty struct { Address sdk.AccAddress `json:"address" yaml:"address"` - Coins sdk.Coins `json:"coins" yaml:"coins"` + Coins sdk.Coins `json:"coins,omitempty" yaml:"coins,omitempty"` PubKey string `json:"public_key" yaml:"public_key"` AccountNumber uint64 `json:"account_number" yaml:"account_number"` Sequence uint64 `json:"sequence" yaml:"sequence"` @@ -104,7 +104,7 @@ type ( moduleAccountPretty struct { Address sdk.AccAddress `json:"address" yaml:"address"` - Coins sdk.Coins `json:"coins" yaml:"coins"` + Coins sdk.Coins `json:"coins,omitempty" yaml:"coins,omitempty"` PubKey string `json:"public_key" yaml:"public_key"` AccountNumber uint64 `json:"account_number" yaml:"account_number"` Sequence uint64 `json:"sequence" yaml:"sequence"` @@ -486,7 +486,7 @@ func validatePermissions(permissions ...string) error { return nil } -func sanitizeGenesisAccounts(genAccounts GenesisAccounts) GenesisAccounts { +func SanitizeGenesisAccounts(genAccounts GenesisAccounts) GenesisAccounts { sort.Slice(genAccounts, func(i, j int) bool { return genAccounts[i].GetAccountNumber() < genAccounts[j].GetAccountNumber() }) @@ -500,7 +500,7 @@ func sanitizeGenesisAccounts(genAccounts GenesisAccounts) GenesisAccounts { return genAccounts } -func validateGenAccounts(genAccounts GenesisAccounts) error { +func ValidateGenAccounts(genAccounts GenesisAccounts) error { addrMap := make(map[string]bool, len(genAccounts)) for _, acc := range genAccounts { diff --git a/x/auth/legacy/v0_39/migrate.go b/x/auth/legacy/v0_39/migrate.go new file mode 100644 index 000000000000..82b1390869f8 --- /dev/null +++ b/x/auth/legacy/v0_39/migrate.go @@ -0,0 +1,23 @@ +package v039 + +import ( + "fmt" + + v038auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v0_38" +) + +// Migrate accepts exported x/auth genesis state from v0.38 and migrates it to +// v0.39 x/auth genesis state. The migration includes: +// +// - Removing coins from account encoding. +func Migrate(authGenState v038auth.GenesisState) v038auth.GenesisState { + for _, account := range authGenState.Accounts { + // set coins to nil and allow the JSON encoding to omit coins + if err := account.SetCoins(nil); err != nil { + panic(fmt.Sprintf("failed to set account coins to nil: %s", err)) + } + } + + authGenState.Accounts = v038auth.SanitizeGenesisAccounts(authGenState.Accounts) + return authGenState +} diff --git a/x/auth/legacy/v0_39/migrate_test.go b/x/auth/legacy/v0_39/migrate_test.go new file mode 100644 index 000000000000..5f9cee0d257c --- /dev/null +++ b/x/auth/legacy/v0_39/migrate_test.go @@ -0,0 +1,87 @@ +package v039_test + +import ( + "testing" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth/legacy/v0_34" + v038auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v0_38" + v039 "github.com/cosmos/cosmos-sdk/x/auth/legacy/v0_39" + + "github.com/stretchr/testify/require" +) + +func TestMigrate(t *testing.T) { + v039Codec := codec.New() + codec.RegisterCrypto(v039Codec) + v038auth.RegisterCodec(v039Codec) + + coins := sdk.NewCoins(sdk.NewInt64Coin("stake", 50)) + addr1, _ := sdk.AccAddressFromBech32("cosmos1xxkueklal9vejv9unqu80w9vptyepfa95pd53u") + acc1 := v038auth.NewBaseAccount(addr1, coins, nil, 1, 0) + + addr2, _ := sdk.AccAddressFromBech32("cosmos15v50ymp6n5dn73erkqtmq0u8adpl8d3ujv2e74") + vaac := v038auth.NewContinuousVestingAccountRaw( + v038auth.NewBaseVestingAccount( + v038auth.NewBaseAccount(addr2, coins, nil, 1, 0), coins, nil, nil, 3160620846, + ), + 1580309972, + ) + + gs := v038auth.GenesisState{ + Params: v0_34.Params{ + MaxMemoCharacters: 10, + TxSigLimit: 10, + TxSizeCostPerByte: 10, + SigVerifyCostED25519: 10, + SigVerifyCostSecp256k1: 10, + }, + Accounts: v038auth.GenesisAccounts{acc1, vaac}, + } + + migrated := v039.Migrate(gs) + expected := `{ + "params": { + "max_memo_characters": "10", + "tx_sig_limit": "10", + "tx_size_cost_per_byte": "10", + "sig_verify_cost_ed25519": "10", + "sig_verify_cost_secp256k1": "10" + }, + "accounts": [ + { + "type": "cosmos-sdk/Account", + "value": { + "address": "cosmos1xxkueklal9vejv9unqu80w9vptyepfa95pd53u", + "public_key": "", + "account_number": 1, + "sequence": 0 + } + }, + { + "type": "cosmos-sdk/ContinuousVestingAccount", + "value": { + "address": "cosmos15v50ymp6n5dn73erkqtmq0u8adpl8d3ujv2e74", + "public_key": "", + "account_number": 1, + "sequence": 0, + "original_vesting": [ + { + "denom": "stake", + "amount": "50" + } + ], + "delegated_free": [], + "delegated_vesting": [], + "end_time": 3160620846, + "start_time": 1580309972 + } + } + ] +}` + + bz, err := v039Codec.MarshalJSONIndent(migrated, "", " ") + require.NoError(t, err) + require.Equal(t, expected, string(bz)) +} diff --git a/x/auth/legacy/v0_39/types.go b/x/auth/legacy/v0_39/types.go new file mode 100644 index 000000000000..419ffe39020d --- /dev/null +++ b/x/auth/legacy/v0_39/types.go @@ -0,0 +1,8 @@ +package v039 + +// DONTCOVER +// nolint + +const ( + ModuleName = "auth" +) diff --git a/x/auth/simulation/genesis.go b/x/auth/simulation/genesis.go index 808d81ac296f..94fd8ec5ff3d 100644 --- a/x/auth/simulation/genesis.go +++ b/x/auth/simulation/genesis.go @@ -97,17 +97,13 @@ func RandomizedGenState(simState *module.SimulationState) { // RandomGenesisAccounts returns randomly generated genesis accounts func RandomGenesisAccounts(simState *module.SimulationState) (genesisAccs exported.GenesisAccounts) { for i, acc := range simState.Accounts { - coins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(simState.InitialStake))} bacc := types.NewBaseAccountWithAddress(acc.Address) - if err := bacc.SetCoins(coins); err != nil { - panic(err) - } - var gacc exported.GenesisAccount = &bacc // Only consider making a vesting account once the initial bonded validator // set is exhausted due to needing to track DelegatedVesting. if int64(i) > simState.NumBonded && simState.Rand.Intn(100) < 50 { + initialVesting := sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, simState.Rand.Int63n(simState.InitialStake))) var endTime int64 startTime := simState.GenTimestamp.Unix() @@ -119,12 +115,15 @@ func RandomGenesisAccounts(simState *module.SimulationState) (genesisAccs export endTime = int64(simulation.RandIntBetween(simState.Rand, int(startTime)+1, int(startTime+(60*60*12)))) } + bva := vestingtypes.NewBaseVestingAccount(&bacc, initialVesting, endTime) + if simState.Rand.Intn(100) < 50 { - gacc = vestingtypes.NewContinuousVestingAccount(&bacc, startTime, endTime) + gacc = vestingtypes.NewContinuousVestingAccountRaw(bva, startTime) } else { - gacc = vestingtypes.NewDelayedVestingAccount(&bacc, endTime) + gacc = vestingtypes.NewDelayedVestingAccountRaw(bva) } } + genesisAccs = append(genesisAccs, gacc) } diff --git a/x/auth/spec/05_vesting.md b/x/auth/spec/05_vesting.md index 7cddc26e7c67..50bf70d03fcf 100644 --- a/x/auth/spec/05_vesting.md +++ b/x/auth/spec/05_vesting.md @@ -6,10 +6,12 @@ order: 6 - [Vesting](#vesting) - [Intro and Requirements](#intro-and-requirements) + - [Note](#note) - [Vesting Account Types](#vesting-account-types) - [Vesting Account Specification](#vesting-account-specification) - [Determining Vesting & Vested Amounts](#determining-vesting--vested-amounts) - [Continuously Vesting Accounts](#continuously-vesting-accounts) + - [Periodic Vesting Accounts](#periodic-vesting-accounts) - [Delayed/Discrete Vesting Accounts](#delayeddiscrete-vesting-accounts) - [Transferring/Sending](#transferringsending) - [Keepers/Handlers](#keepershandlers) @@ -22,6 +24,7 @@ order: 6 - [Examples](#examples) - [Simple](#simple) - [Slashing](#slashing) + - [Periodic Vesting](#periodic-vesting) - [Glossary](#glossary) ## Intro and Requirements @@ -67,45 +70,50 @@ having coins fail to vest). // VestingAccount defines an interface that any vesting account type must // implement. type VestingAccount interface { - Account + Account - GetVestedCoins(Time) Coins - GetVestingCoins(Time) Coins + GetVestedCoins(Time) Coins + GetVestingCoins(Time) Coins - // Delegation and undelegation accounting that returns the resulting base - // coins amount. - TrackDelegation(Time, Coins) - TrackUndelegation(Coins) + // TrackDelegation performs internal vesting accounting necessary when + // delegating from a vesting account. It accepts the current block time, the + // delegation amount and balance of all coins whose denomination exists in + // the account's original vesting balance. + TrackDelegation(Time, Coins, Coins) - GetStartTime() int64 - GetEndTime() int64 + // TrackUndelegation performs internal vesting accounting necessary when a + // vesting account performs an undelegation. + TrackUndelegation(Coins) + + GetStartTime() int64 + GetEndTime() int64 } // BaseVestingAccount implements the VestingAccount interface. It contains all // the necessary fields needed for any vesting account implementation. type BaseVestingAccount struct { - BaseAccount + BaseAccount - OriginalVesting Coins // coins in account upon initialization - DelegatedFree Coins // coins that are vested and delegated - DelegatedVesting Coins // coins that vesting and delegated + OriginalVesting Coins // coins in account upon initialization + DelegatedFree Coins // coins that are vested and delegated + DelegatedVesting Coins // coins that vesting and delegated - EndTime int64 // when the coins become unlocked + EndTime int64 // when the coins become unlocked } // ContinuousVestingAccount implements the VestingAccount interface. It // continuously vests by unlocking coins linearly with respect to time. type ContinuousVestingAccount struct { - BaseVestingAccount + BaseVestingAccount - StartTime int64 // when the coins start to vest + StartTime int64 // when the coins start to vest } // DelayedVestingAccount implements the VestingAccount interface. It vests all // coins after a specific time, but non prior. In other words, it keeps them // locked until a specified time. type DelayedVestingAccount struct { - BaseVestingAccount + BaseVestingAccount } // VestingPeriod defines a length of time and amount of coins that will vest @@ -127,16 +135,18 @@ type PeriodicVestingAccount struct { ``` In order to facilitate less ad-hoc type checking and assertions and to support -flexibility in account usage, the existing `Account` interface is updated to contain -the following: +flexibility in account balance usage, the existing `x/bank` `ViewKeeper` interface +is updated to contain the following: ```go -type Account interface { - // ... +type ViewKeeper interface { + // ... + + // Calculates the total locked account balance. + LockedCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins - // Calculates the amount of coins that can be sent to other accounts given - // the current time. - SpendableCoins(Time) Coins + // Calculates the total spendable balance that can be sent to other accounts. + SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins } ``` @@ -268,10 +278,31 @@ In other words, a vesting account may transfer the minimum of the base account balance and the base account balance plus the number of currently delegated vesting coins less the number of coins vested so far. +However, given that account balances are tracked via the `x/bank` module and that +we want to avoid loading the entire account balance, we can instead determine +the locked balance, which can be defined as `max(V - DV, 0)`, and infer the +spendable balance from that. + +```go +func (va VestingAccount) LockedCoins(t Time) Coins { + return max(va.GetVestingCoins(t) - va.DelegatedVesting, 0) +} +``` + +The `x/bank` `ViewKeeper` can then provide APIs to determine locked and spendable +coins for any account: + ```go -func (va VestingAccount) SpendableCoins(t Time) Coins { - bc := va.GetCoins() - return min((bc + va.DelegatedVesting) - va.GetVestingCoins(t), bc) +func (k Keeper) LockedCoins(ctx Context, addr AccAddress) Coins { + acc := k.GetAccount(ctx, addr) + if acc != nil { + if acc.IsVesting() { + return acc.LockedCoins(ctx.BlockTime()) + } + } + + // non-vesting accounts do not have any locked coins + return NewCoins() } ``` @@ -281,21 +312,18 @@ The corresponding `x/bank` keeper should appropriately handle sending coins based on if the account is a vesting account or not. ```go -func SendCoins(t Time, from Account, to Account, amount Coins) { - bc := from.GetCoins() +func (k Keeper) SendCoins(ctx Context, from Account, to Account, amount Coins) { + bc := k.GetBalances(ctx, from) + v := k.LockedCoins(ctx, from) - if isVesting(from) { - sc := from.SpendableCoins(t) - assert(amount <= sc) - } - - newCoins := bc - amount + spendable := bc - v + newCoins := spendable - amount assert(newCoins >= 0) - from.SetCoins(bc - amount) - to.SetCoins(amount) + from.SetBalance(newCoins) + to.AddBalance(amount) - // save accounts... + // save balances... } ``` @@ -310,7 +338,8 @@ For a vesting account attempting to delegate `D` coins, the following is perform 5. Set `DF += Y` ```go -func (va VestingAccount) TrackDelegation(t Time, amount Coins) { +func (va VestingAccount) TrackDelegation(t Time, balance Coins, amount Coins) { + assert(balance <= amount) x := min(max(va.GetVestingCoins(t) - va.DelegatedVesting, 0), amount) y := amount - x @@ -326,13 +355,10 @@ fields, so upstream callers MUST modify the `Coins` field by subtracting `amount ```go func DelegateCoins(t Time, from Account, amount Coins) { - bc := from.GetCoins() - assert(amount <= bc) - if isVesting(from) { from.TrackDelegation(t, amount) } else { - from.SetCoins(sc - amount) + from.SetBalance(sc - amount) } // save account... @@ -383,7 +409,7 @@ func UndelegateCoins(to Account, amount Coins) { // save account ... } } else { - AddCoins(to, amount) + AddBalance(to, amount) // save account... } } diff --git a/x/auth/types/account.go b/x/auth/types/account.go index a8d919a385ee..643c33abd28a 100644 --- a/x/auth/types/account.go +++ b/x/auth/types/account.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/json" "errors" - "time" "github.com/tendermint/tendermint/crypto" yaml "gopkg.in/yaml.v2" @@ -25,19 +24,15 @@ var _ exported.GenesisAccount = (*BaseAccount)(nil) // implements Account. type BaseAccount struct { Address sdk.AccAddress `json:"address" yaml:"address"` - Coins sdk.Coins `json:"coins" yaml:"coins"` PubKey crypto.PubKey `json:"public_key" yaml:"public_key"` AccountNumber uint64 `json:"account_number" yaml:"account_number"` Sequence uint64 `json:"sequence" yaml:"sequence"` } // NewBaseAccount creates a new BaseAccount object -func NewBaseAccount(address sdk.AccAddress, coins sdk.Coins, - pubKey crypto.PubKey, accountNumber uint64, sequence uint64) *BaseAccount { - +func NewBaseAccount(address sdk.AccAddress, pubKey crypto.PubKey, accountNumber, sequence uint64) *BaseAccount { return &BaseAccount{ Address: address, - Coins: coins, PubKey: pubKey, AccountNumber: accountNumber, Sequence: sequence, @@ -81,17 +76,6 @@ func (acc *BaseAccount) SetPubKey(pubKey crypto.PubKey) error { return nil } -// GetCoins - Implements sdk.Account. -func (acc *BaseAccount) GetCoins() sdk.Coins { - return acc.Coins -} - -// SetCoins - Implements sdk.Account. -func (acc *BaseAccount) SetCoins(coins sdk.Coins) error { - acc.Coins = coins - return nil -} - // GetAccountNumber - Implements Account func (acc *BaseAccount) GetAccountNumber() uint64 { return acc.AccountNumber @@ -114,12 +98,6 @@ func (acc *BaseAccount) SetSequence(seq uint64) error { return nil } -// SpendableCoins returns the total set of spendable coins. For a base account, -// this is simply the base coins. -func (acc *BaseAccount) SpendableCoins(_ time.Time) sdk.Coins { - return acc.GetCoins() -} - // Validate checks for errors on the account fields func (acc BaseAccount) Validate() error { if acc.PubKey != nil && acc.Address != nil && @@ -132,7 +110,6 @@ func (acc BaseAccount) Validate() error { type baseAccountPretty struct { Address sdk.AccAddress `json:"address" yaml:"address"` - Coins sdk.Coins `json:"coins" yaml:"coins"` PubKey string `json:"public_key" yaml:"public_key"` AccountNumber uint64 `json:"account_number" yaml:"account_number"` Sequence uint64 `json:"sequence" yaml:"sequence"` @@ -147,7 +124,6 @@ func (acc BaseAccount) String() string { func (acc BaseAccount) MarshalYAML() (interface{}, error) { alias := baseAccountPretty{ Address: acc.Address, - Coins: acc.Coins, AccountNumber: acc.AccountNumber, Sequence: acc.Sequence, } @@ -173,7 +149,6 @@ func (acc BaseAccount) MarshalYAML() (interface{}, error) { func (acc BaseAccount) MarshalJSON() ([]byte, error) { alias := baseAccountPretty{ Address: acc.Address, - Coins: acc.Coins, AccountNumber: acc.AccountNumber, Sequence: acc.Sequence, } @@ -207,7 +182,6 @@ func (acc *BaseAccount) UnmarshalJSON(bz []byte) error { } acc.Address = alias.Address - acc.Coins = alias.Coins acc.AccountNumber = alias.AccountNumber acc.Sequence = alias.Sequence diff --git a/x/auth/types/account_test.go b/x/auth/types/account_test.go index 7be6a25e5623..90a4dacb0c9f 100644 --- a/x/auth/types/account_test.go +++ b/x/auth/types/account_test.go @@ -46,17 +46,6 @@ func TestBaseAddressPubKey(t *testing.T) { require.EqualValues(t, addr2, acc2.GetAddress()) } -func TestBaseAccountCoins(t *testing.T) { - _, _, addr := KeyTestPubAddr() - acc := NewBaseAccountWithAddress(addr) - - someCoins := sdk.Coins{sdk.NewInt64Coin("atom", 123), sdk.NewInt64Coin("eth", 246)} - - err := acc.SetCoins(someCoins) - require.Nil(t, err) - require.Equal(t, someCoins, acc.GetCoins()) -} - func TestBaseAccountSequence(t *testing.T) { _, _, addr := KeyTestPubAddr() acc := NewBaseAccountWithAddress(addr) @@ -72,7 +61,6 @@ func TestBaseAccountMarshal(t *testing.T) { _, pub, addr := KeyTestPubAddr() acc := NewBaseAccountWithAddress(addr) - someCoins := sdk.Coins{sdk.NewInt64Coin("atom", 123), sdk.NewInt64Coin("eth", 246)} seq := uint64(7) // set everything on the account @@ -80,8 +68,6 @@ func TestBaseAccountMarshal(t *testing.T) { require.Nil(t, err) err = acc.SetSequence(seq) require.Nil(t, err) - err = acc.SetCoins(someCoins) - require.Nil(t, err) // need a codec for marshaling cdc := codec.New() @@ -104,7 +90,7 @@ func TestBaseAccountMarshal(t *testing.T) { func TestGenesisAccountValidate(t *testing.T) { pubkey := secp256k1.GenPrivKey().PubKey() addr := sdk.AccAddress(pubkey.Address()) - baseAcc := NewBaseAccount(addr, nil, pubkey, 0, 0) + baseAcc := NewBaseAccount(addr, pubkey, 0, 0) tests := []struct { name string acc exported.GenesisAccount @@ -117,7 +103,7 @@ func TestGenesisAccountValidate(t *testing.T) { }, { "invalid base valid account", - NewBaseAccount(addr, sdk.NewCoins(), secp256k1.GenPrivKey().PubKey(), 0, 0), + NewBaseAccount(addr, secp256k1.GenPrivKey().PubKey(), 0, 0), errors.New("pubkey and address pair is invalid"), }, } @@ -133,8 +119,7 @@ func TestGenesisAccountValidate(t *testing.T) { func TestBaseAccountJSON(t *testing.T) { pubkey := secp256k1.GenPrivKey().PubKey() addr := sdk.AccAddress(pubkey.Address()) - coins := sdk.NewCoins(sdk.NewInt64Coin("test", 5)) - baseAcc := NewBaseAccount(addr, coins, pubkey, 10, 50) + baseAcc := NewBaseAccount(addr, pubkey, 10, 50) bz, err := json.Marshal(baseAcc) require.NoError(t, err) diff --git a/x/auth/types/genesis.go b/x/auth/types/genesis.go index 78c4f5a5bd29..89999db447ca 100644 --- a/x/auth/types/genesis.go +++ b/x/auth/types/genesis.go @@ -55,12 +55,6 @@ func SanitizeGenesisAccounts(genAccs exported.GenesisAccounts) exported.GenesisA return genAccs[i].GetAccountNumber() < genAccs[j].GetAccountNumber() }) - for _, acc := range genAccs { - if err := acc.SetCoins(acc.GetCoins().Sort()); err != nil { - panic(err) - } - } - return genAccs } diff --git a/x/auth/types/genesis_test.go b/x/auth/types/genesis_test.go index f28b67b21a2d..3b892f48038d 100644 --- a/x/auth/types/genesis_test.go +++ b/x/auth/types/genesis_test.go @@ -14,31 +14,19 @@ import ( func TestSanitize(t *testing.T) { addr1 := sdk.AccAddress(ed25519.GenPrivKey().PubKey().Address()) authAcc1 := NewBaseAccountWithAddress(addr1) - authAcc1.SetCoins(sdk.Coins{ - sdk.NewInt64Coin("bcoin", 150), - sdk.NewInt64Coin("acoin", 150), - }) authAcc1.SetAccountNumber(1) addr2 := sdk.AccAddress(ed25519.GenPrivKey().PubKey().Address()) authAcc2 := NewBaseAccountWithAddress(addr2) - authAcc2.SetCoins(sdk.Coins{ - sdk.NewInt64Coin("acoin", 150), - sdk.NewInt64Coin("bcoin", 150), - }) genAccs := exported.GenesisAccounts{&authAcc1, &authAcc2} require.True(t, genAccs[0].GetAccountNumber() > genAccs[1].GetAccountNumber()) - require.Equal(t, genAccs[0].GetCoins()[0].Denom, "bcoin") - require.Equal(t, genAccs[0].GetCoins()[1].Denom, "acoin") require.Equal(t, genAccs[1].GetAddress(), addr2) genAccs = SanitizeGenesisAccounts(genAccs) require.False(t, genAccs[0].GetAccountNumber() > genAccs[1].GetAccountNumber()) require.Equal(t, genAccs[1].GetAddress(), addr1) - require.Equal(t, genAccs[1].GetCoins()[0].Denom, "acoin") - require.Equal(t, genAccs[1].GetCoins()[1].Denom, "bcoin") } var ( @@ -51,7 +39,6 @@ var ( // require duplicate accounts fails validation func TestValidateGenesisDuplicateAccounts(t *testing.T) { acc1 := NewBaseAccountWithAddress(sdk.AccAddress(addr1)) - acc1.Coins = sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 150)) genAccs := make(exported.GenesisAccounts, 2) genAccs[0] = &acc1 @@ -62,10 +49,8 @@ func TestValidateGenesisDuplicateAccounts(t *testing.T) { func TestGenesisAccountIterator(t *testing.T) { acc1 := NewBaseAccountWithAddress(sdk.AccAddress(addr1)) - acc1.Coins = sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 150)) acc2 := NewBaseAccountWithAddress(sdk.AccAddress(addr2)) - acc2.Coins = sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 150)) genAccounts := exported.GenesisAccounts{&acc1, &acc2} diff --git a/x/auth/vesting/exported/exported.go b/x/auth/vesting/exported/exported.go index 16b07d3614f4..09caaec4a44b 100644 --- a/x/auth/vesting/exported/exported.go +++ b/x/auth/vesting/exported/exported.go @@ -11,9 +11,21 @@ import ( type VestingAccount interface { authexported.Account - // Delegation and undelegation accounting that returns the resulting base - // coins amount. - TrackDelegation(blockTime time.Time, amount sdk.Coins) + // LockedCoins returns the set of coins that are not spendable (i.e. locked). + // + // To get spendable coins of a vesting account, first the total balance must + // be retrieved and the locked tokens can be subtracted from the total balance. + // Note, the spendable balance can be negative. + LockedCoins(blockTime time.Time) sdk.Coins + + // TrackDelegation performs internal vesting accounting necessary when + // delegating from a vesting account. It accepts the current block time, the + // delegation amount and balance of all coins whose denomination exists in + // the account's original vesting balance. + TrackDelegation(blockTime time.Time, balance, amount sdk.Coins) + + // TrackUndelegation performs internal vesting accounting necessary when a + // vesting account performs an undelegation. TrackUndelegation(amount sdk.Coins) GetVestedCoins(blockTime time.Time) sdk.Coins diff --git a/x/auth/vesting/types/genesis_test.go b/x/auth/vesting/types/genesis_test.go index aee8d1fa091a..7a9781eb7040 100644 --- a/x/auth/vesting/types/genesis_test.go +++ b/x/auth/vesting/types/genesis_test.go @@ -21,21 +21,21 @@ var ( // require invalid vesting account fails validation func TestValidateGenesisInvalidAccounts(t *testing.T) { acc1 := authtypes.NewBaseAccountWithAddress(sdk.AccAddress(addr1)) - acc1.Coins = sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 150)) - baseVestingAcc, err := NewBaseVestingAccount(&acc1, acc1.Coins, 1548775410) - require.NoError(t, err) + acc1Balance := sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 150)) + baseVestingAcc := NewBaseVestingAccount(&acc1, acc1Balance, 1548775410) + // invalid delegated vesting - baseVestingAcc.DelegatedVesting = acc1.Coins.Add(acc1.Coins...) + baseVestingAcc.DelegatedVesting = acc1Balance.Add(acc1Balance...) acc2 := authtypes.NewBaseAccountWithAddress(sdk.AccAddress(addr2)) - acc2.Coins = sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 150)) + // acc2Balance := sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 150)) genAccs := make([]exported.GenesisAccount, 2) genAccs[0] = baseVestingAcc genAccs[1] = &acc2 require.Error(t, authtypes.ValidateGenAccounts(genAccs)) - baseVestingAcc.DelegatedVesting = acc1.Coins + baseVestingAcc.DelegatedVesting = acc1Balance genAccs[0] = baseVestingAcc require.NoError(t, authtypes.ValidateGenAccounts(genAccs)) // invalid start time diff --git a/x/auth/vesting/types/vesting_account.go b/x/auth/vesting/types/vesting_account.go index 256c9d598fec..70efad2b33ef 100644 --- a/x/auth/vesting/types/vesting_account.go +++ b/x/auth/vesting/types/vesting_account.go @@ -41,56 +41,51 @@ type BaseVestingAccount struct { EndTime int64 `json:"end_time" yaml:"end_time"` // when the coins become unlocked } -// NewBaseVestingAccount creates a new BaseVestingAccount object -func NewBaseVestingAccount(baseAccount *authtypes.BaseAccount, originalVesting sdk.Coins, endTime int64) (*BaseVestingAccount, error) { - if (baseAccount.Coins.IsZero() && !originalVesting.IsZero()) || originalVesting.IsAnyGT(baseAccount.Coins) { - return &BaseVestingAccount{}, errors.New("vesting amount cannot be greater than total amount") - } +// NewBaseVestingAccount creates a new BaseVestingAccount object. It is the +// callers responsibility to ensure the base account has sufficient funds with +// regards to the original vesting amount. +func NewBaseVestingAccount(baseAccount *authtypes.BaseAccount, originalVesting sdk.Coins, endTime int64) *BaseVestingAccount { return &BaseVestingAccount{ BaseAccount: baseAccount, OriginalVesting: originalVesting, DelegatedFree: sdk.NewCoins(), DelegatedVesting: sdk.NewCoins(), EndTime: endTime, - }, nil + } } -// SpendableCoinsVestingAccount returns all the spendable coins for a vesting account given a -// set of vesting coins. +// LockedCoinsFromVesting returns all the coins that are not spendable (i.e. locked) +// for a vesting account given the current vesting coins. If no coins are locked, +// an empty slice of Coins is returned. // -// CONTRACT: The account's coins, delegated vesting coins, vestingCoins must be -// sorted. -func (bva BaseVestingAccount) SpendableCoinsVestingAccount(vestingCoins sdk.Coins) sdk.Coins { - var spendableCoins sdk.Coins - bc := bva.GetCoins() - - for _, coin := range bc { - baseAmt := coin.Amount - vestingAmt := vestingCoins.AmountOf(coin.Denom) - delVestingAmt := bva.DelegatedVesting.AmountOf(coin.Denom) +// CONTRACT: Delegated vesting coins and vestingCoins must be sorted. +func (bva BaseVestingAccount) LockedCoinsFromVesting(vestingCoins sdk.Coins) sdk.Coins { + lockedCoins := sdk.NewCoins() + + for _, vestingCoin := range vestingCoins { + vestingAmt := vestingCoin.Amount + delVestingAmt := bva.DelegatedVesting.AmountOf(vestingCoin.Denom) - // compute min((BC + DV) - V, BC) per the specification - min := sdk.MinInt(baseAmt.Add(delVestingAmt).Sub(vestingAmt), baseAmt) - spendableCoin := sdk.NewCoin(coin.Denom, min) + max := sdk.MaxInt(vestingAmt.Sub(delVestingAmt), sdk.ZeroInt()) + lockedCoin := sdk.NewCoin(vestingCoin.Denom, max) - if !spendableCoin.IsZero() { - spendableCoins = spendableCoins.Add(spendableCoin) + if !lockedCoin.IsZero() { + lockedCoins = lockedCoins.Add(lockedCoin) } } - return spendableCoins + return lockedCoins } // TrackDelegation tracks a delegation amount for any given vesting account type -// given the amount of coins currently vesting. +// given the amount of coins currently vesting and the current account balance +// of the delegation denominations. // // CONTRACT: The account's coins, delegation coins, vesting coins, and delegated // vesting coins must be sorted. -func (bva *BaseVestingAccount) TrackDelegation(vestingCoins, amount sdk.Coins) { - bc := bva.GetCoins() - +func (bva *BaseVestingAccount) TrackDelegation(balance, vestingCoins, amount sdk.Coins) { for _, coin := range amount { - baseAmt := bc.AmountOf(coin.Denom) + baseAmt := balance.AmountOf(coin.Denom) vestingAmt := vestingCoins.AmountOf(coin.Denom) delVestingAmt := bva.DelegatedVesting.AmountOf(coin.Denom) @@ -187,7 +182,6 @@ func (bva BaseVestingAccount) Validate() error { type vestingAccountPretty struct { Address sdk.AccAddress `json:"address" yaml:"address"` - Coins sdk.Coins `json:"coins" yaml:"coins"` PubKey string `json:"public_key" yaml:"public_key"` AccountNumber uint64 `json:"account_number" yaml:"account_number"` Sequence uint64 `json:"sequence" yaml:"sequence"` @@ -210,7 +204,6 @@ func (bva BaseVestingAccount) String() string { func (bva BaseVestingAccount) MarshalYAML() (interface{}, error) { alias := vestingAccountPretty{ Address: bva.Address, - Coins: bva.Coins, AccountNumber: bva.AccountNumber, Sequence: bva.Sequence, OriginalVesting: bva.OriginalVesting, @@ -240,7 +233,6 @@ func (bva BaseVestingAccount) MarshalYAML() (interface{}, error) { func (bva BaseVestingAccount) MarshalJSON() ([]byte, error) { alias := vestingAccountPretty{ Address: bva.Address, - Coins: bva.Coins, AccountNumber: bva.AccountNumber, Sequence: bva.Sequence, OriginalVesting: bva.OriginalVesting, @@ -280,7 +272,7 @@ func (bva *BaseVestingAccount) UnmarshalJSON(bz []byte) error { } } - bva.BaseAccount = authtypes.NewBaseAccount(alias.Address, alias.Coins, pk, alias.AccountNumber, alias.Sequence) + bva.BaseAccount = authtypes.NewBaseAccount(alias.Address, pk, alias.AccountNumber, alias.Sequence) bva.OriginalVesting = alias.OriginalVesting bva.DelegatedFree = alias.DelegatedFree bva.DelegatedVesting = alias.DelegatedVesting @@ -312,10 +304,10 @@ func NewContinuousVestingAccountRaw(bva *BaseVestingAccount, startTime int64) *C } // NewContinuousVestingAccount returns a new ContinuousVestingAccount -func NewContinuousVestingAccount(baseAcc *authtypes.BaseAccount, startTime, endTime int64) *ContinuousVestingAccount { +func NewContinuousVestingAccount(baseAcc *authtypes.BaseAccount, originalVesting sdk.Coins, startTime, endTime int64) *ContinuousVestingAccount { baseVestingAcc := &BaseVestingAccount{ BaseAccount: baseAcc, - OriginalVesting: baseAcc.Coins, + OriginalVesting: originalVesting, EndTime: endTime, } @@ -358,17 +350,16 @@ func (cva ContinuousVestingAccount) GetVestingCoins(blockTime time.Time) sdk.Coi return cva.OriginalVesting.Sub(cva.GetVestedCoins(blockTime)) } -// SpendableCoins returns the total number of spendable coins per denom for a -// continuous vesting account. -func (cva ContinuousVestingAccount) SpendableCoins(blockTime time.Time) sdk.Coins { - return cva.BaseVestingAccount.SpendableCoinsVestingAccount(cva.GetVestingCoins(blockTime)) +// LockedCoins returns the set of coins that are not spendable (i.e. locked). +func (cva ContinuousVestingAccount) LockedCoins(blockTime time.Time) sdk.Coins { + return cva.BaseVestingAccount.LockedCoinsFromVesting(cva.GetVestingCoins(blockTime)) } // TrackDelegation tracks a desired delegation amount by setting the appropriate // values for the amount of delegated vesting, delegated free, and reducing the // overall amount of base coins. -func (cva *ContinuousVestingAccount) TrackDelegation(blockTime time.Time, amount sdk.Coins) { - cva.BaseVestingAccount.TrackDelegation(cva.GetVestingCoins(blockTime), amount) +func (cva *ContinuousVestingAccount) TrackDelegation(blockTime time.Time, balance, amount sdk.Coins) { + cva.BaseVestingAccount.TrackDelegation(balance, cva.GetVestingCoins(blockTime), amount) } // GetStartTime returns the time when vesting starts for a continuous vesting @@ -395,7 +386,6 @@ func (cva ContinuousVestingAccount) String() string { func (cva ContinuousVestingAccount) MarshalYAML() (interface{}, error) { alias := vestingAccountPretty{ Address: cva.Address, - Coins: cva.Coins, AccountNumber: cva.AccountNumber, Sequence: cva.Sequence, OriginalVesting: cva.OriginalVesting, @@ -426,7 +416,6 @@ func (cva ContinuousVestingAccount) MarshalYAML() (interface{}, error) { func (cva ContinuousVestingAccount) MarshalJSON() ([]byte, error) { alias := vestingAccountPretty{ Address: cva.Address, - Coins: cva.Coins, AccountNumber: cva.AccountNumber, Sequence: cva.Sequence, OriginalVesting: cva.OriginalVesting, @@ -468,7 +457,7 @@ func (cva *ContinuousVestingAccount) UnmarshalJSON(bz []byte) error { } cva.BaseVestingAccount = &BaseVestingAccount{ - BaseAccount: authtypes.NewBaseAccount(alias.Address, alias.Coins, pk, alias.AccountNumber, alias.Sequence), + BaseAccount: authtypes.NewBaseAccount(alias.Address, pk, alias.AccountNumber, alias.Sequence), OriginalVesting: alias.OriginalVesting, DelegatedFree: alias.DelegatedFree, DelegatedVesting: alias.DelegatedVesting, @@ -503,14 +492,14 @@ func NewPeriodicVestingAccountRaw(bva *BaseVestingAccount, startTime int64, peri } // NewPeriodicVestingAccount returns a new PeriodicVestingAccount -func NewPeriodicVestingAccount(baseAcc *authtypes.BaseAccount, startTime int64, periods Periods) *PeriodicVestingAccount { +func NewPeriodicVestingAccount(baseAcc *authtypes.BaseAccount, originalVesting sdk.Coins, startTime int64, periods Periods) *PeriodicVestingAccount { endTime := startTime for _, p := range periods { endTime += p.Length } baseVestingAcc := &BaseVestingAccount{ BaseAccount: baseAcc, - OriginalVesting: baseAcc.Coins, + OriginalVesting: originalVesting, EndTime: endTime, } @@ -537,16 +526,20 @@ func (pva PeriodicVestingAccount) GetVestedCoins(blockTime time.Time) sdk.Coins // track the start time of the next period currentPeriodStartTime := pva.StartTime + // for each period, if the period is over, add those coins as vested and check the next period. for _, period := range pva.VestingPeriods { x := blockTime.Unix() - currentPeriodStartTime if x < period.Length { break } + vestedCoins = vestedCoins.Add(period.Amount...) - // Update the start time of the next period + + // update the start time of the next period currentPeriodStartTime += period.Length } + return vestedCoins } @@ -556,17 +549,16 @@ func (pva PeriodicVestingAccount) GetVestingCoins(blockTime time.Time) sdk.Coins return pva.OriginalVesting.Sub(pva.GetVestedCoins(blockTime)) } -// SpendableCoins returns the total number of spendable coins per denom for a -// periodic vesting account. -func (pva PeriodicVestingAccount) SpendableCoins(blockTime time.Time) sdk.Coins { - return pva.BaseVestingAccount.SpendableCoinsVestingAccount(pva.GetVestingCoins(blockTime)) +// LockedCoins returns the set of coins that are not spendable (i.e. locked). +func (pva PeriodicVestingAccount) LockedCoins(blockTime time.Time) sdk.Coins { + return pva.BaseVestingAccount.LockedCoinsFromVesting(pva.GetVestingCoins(blockTime)) } // TrackDelegation tracks a desired delegation amount by setting the appropriate // values for the amount of delegated vesting, delegated free, and reducing the // overall amount of base coins. -func (pva *PeriodicVestingAccount) TrackDelegation(blockTime time.Time, amount sdk.Coins) { - pva.BaseVestingAccount.TrackDelegation(pva.GetVestingCoins(blockTime), amount) +func (pva *PeriodicVestingAccount) TrackDelegation(blockTime time.Time, balance, amount sdk.Coins) { + pva.BaseVestingAccount.TrackDelegation(balance, pva.GetVestingCoins(blockTime), amount) } // GetStartTime returns the time when vesting starts for a periodic vesting @@ -610,7 +602,6 @@ func (pva PeriodicVestingAccount) String() string { func (pva PeriodicVestingAccount) MarshalYAML() (interface{}, error) { alias := vestingAccountPretty{ Address: pva.Address, - Coins: pva.Coins, AccountNumber: pva.AccountNumber, Sequence: pva.Sequence, OriginalVesting: pva.OriginalVesting, @@ -642,7 +633,6 @@ func (pva PeriodicVestingAccount) MarshalYAML() (interface{}, error) { func (pva PeriodicVestingAccount) MarshalJSON() ([]byte, error) { alias := vestingAccountPretty{ Address: pva.Address, - Coins: pva.Coins, AccountNumber: pva.AccountNumber, Sequence: pva.Sequence, OriginalVesting: pva.OriginalVesting, @@ -685,7 +675,7 @@ func (pva *PeriodicVestingAccount) UnmarshalJSON(bz []byte) error { } pva.BaseVestingAccount = &BaseVestingAccount{ - BaseAccount: authtypes.NewBaseAccount(alias.Address, alias.Coins, pk, alias.AccountNumber, alias.Sequence), + BaseAccount: authtypes.NewBaseAccount(alias.Address, pk, alias.AccountNumber, alias.Sequence), OriginalVesting: alias.OriginalVesting, DelegatedFree: alias.DelegatedFree, DelegatedVesting: alias.DelegatedVesting, @@ -718,10 +708,10 @@ func NewDelayedVestingAccountRaw(bva *BaseVestingAccount) *DelayedVestingAccount } // NewDelayedVestingAccount returns a DelayedVestingAccount -func NewDelayedVestingAccount(baseAcc *authtypes.BaseAccount, endTime int64) *DelayedVestingAccount { +func NewDelayedVestingAccount(baseAcc *authtypes.BaseAccount, originalVesting sdk.Coins, endTime int64) *DelayedVestingAccount { baseVestingAcc := &BaseVestingAccount{ BaseAccount: baseAcc, - OriginalVesting: baseAcc.Coins, + OriginalVesting: originalVesting, EndTime: endTime, } @@ -744,17 +734,16 @@ func (dva DelayedVestingAccount) GetVestingCoins(blockTime time.Time) sdk.Coins return dva.OriginalVesting.Sub(dva.GetVestedCoins(blockTime)) } -// SpendableCoins returns the total number of spendable coins for a delayed -// vesting account. -func (dva DelayedVestingAccount) SpendableCoins(blockTime time.Time) sdk.Coins { - return dva.BaseVestingAccount.SpendableCoinsVestingAccount(dva.GetVestingCoins(blockTime)) +// LockedCoins returns the set of coins that are not spendable (i.e. locked). +func (dva DelayedVestingAccount) LockedCoins(blockTime time.Time) sdk.Coins { + return dva.BaseVestingAccount.LockedCoinsFromVesting(dva.GetVestingCoins(blockTime)) } // TrackDelegation tracks a desired delegation amount by setting the appropriate // values for the amount of delegated vesting, delegated free, and reducing the // overall amount of base coins. -func (dva *DelayedVestingAccount) TrackDelegation(blockTime time.Time, amount sdk.Coins) { - dva.BaseVestingAccount.TrackDelegation(dva.GetVestingCoins(blockTime), amount) +func (dva *DelayedVestingAccount) TrackDelegation(blockTime time.Time, balance, amount sdk.Coins) { + dva.BaseVestingAccount.TrackDelegation(balance, dva.GetVestingCoins(blockTime), amount) } // GetStartTime returns zero since a delayed vesting account has no start time. @@ -771,7 +760,6 @@ func (dva DelayedVestingAccount) Validate() error { func (dva DelayedVestingAccount) MarshalJSON() ([]byte, error) { alias := vestingAccountPretty{ Address: dva.Address, - Coins: dva.Coins, AccountNumber: dva.AccountNumber, Sequence: dva.Sequence, OriginalVesting: dva.OriginalVesting, @@ -812,7 +800,7 @@ func (dva *DelayedVestingAccount) UnmarshalJSON(bz []byte) error { } dva.BaseVestingAccount = &BaseVestingAccount{ - BaseAccount: authtypes.NewBaseAccount(alias.Address, alias.Coins, pk, alias.AccountNumber, alias.Sequence), + BaseAccount: authtypes.NewBaseAccount(alias.Address, pk, alias.AccountNumber, alias.Sequence), OriginalVesting: alias.OriginalVesting, DelegatedFree: alias.DelegatedFree, DelegatedVesting: alias.DelegatedVesting, diff --git a/x/auth/vesting/types/vesting_account_test.go b/x/auth/vesting/types/vesting_account_test.go index 651416338c06..4555d329e625 100644 --- a/x/auth/vesting/types/vesting_account_test.go +++ b/x/auth/vesting/types/vesting_account_test.go @@ -27,8 +27,7 @@ func TestGetVestedCoinsContVestingAcc(t *testing.T) { _, _, addr := KeyTestPubAddr() origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) - bacc.SetCoins(origCoins) - cva := NewContinuousVestingAccount(&bacc, now.Unix(), endTime.Unix()) + cva := NewContinuousVestingAccount(&bacc, origCoins, now.Unix(), endTime.Unix()) // require no coins vested in the very beginning of the vesting schedule vestedCoins := cva.GetVestedCoins(now) @@ -54,8 +53,7 @@ func TestGetVestingCoinsContVestingAcc(t *testing.T) { _, _, addr := KeyTestPubAddr() origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) - bacc.SetCoins(origCoins) - cva := NewContinuousVestingAccount(&bacc, now.Unix(), endTime.Unix()) + cva := NewContinuousVestingAccount(&bacc, origCoins, now.Unix(), endTime.Unix()) // require all coins vesting in the beginning of the vesting schedule vestingCoins := cva.GetVestingCoins(now) @@ -77,37 +75,25 @@ func TestSpendableCoinsContVestingAcc(t *testing.T) { _, _, addr := KeyTestPubAddr() origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) - bacc.SetCoins(origCoins) - cva := NewContinuousVestingAccount(&bacc, now.Unix(), endTime.Unix()) - // require that there exist no spendable coins in the beginning of the - // vesting schedule - spendableCoins := cva.SpendableCoins(now) - require.Nil(t, spendableCoins) + cva := NewContinuousVestingAccount(&bacc, origCoins, now.Unix(), endTime.Unix()) - // require that all original coins are spendable at the end of the vesting + // require that all original coins are locked at the end of the vesting // schedule - spendableCoins = cva.SpendableCoins(endTime) - require.Equal(t, origCoins, spendableCoins) + lockedCoins := cva.LockedCoins(now) + require.Equal(t, origCoins, lockedCoins) - // require that all vested coins (50%) are spendable - spendableCoins = cva.SpendableCoins(now.Add(12 * time.Hour)) - require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}, spendableCoins) + // require that there exist no locked coins in the beginning of the + lockedCoins = cva.LockedCoins(endTime) + require.Equal(t, sdk.NewCoins(), lockedCoins) - // receive some coins - recvAmt := sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)} - cva.SetCoins(cva.GetCoins().Add(recvAmt...)) + // require that all vested coins (50%) are spendable + lockedCoins = cva.LockedCoins(now.Add(12 * time.Hour)) + require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}, lockedCoins) // require that all vested coins (50%) are spendable plus any received - spendableCoins = cva.SpendableCoins(now.Add(12 * time.Hour)) - require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 100)}, spendableCoins) - - // spend all spendable coins - cva.SetCoins(cva.GetCoins().Sub(spendableCoins)) - - // require that no more coins are spendable - spendableCoins = cva.SpendableCoins(now.Add(12 * time.Hour)) - require.Nil(t, spendableCoins) + lockedCoins = cva.LockedCoins(now.Add(12 * time.Hour)) + require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}, lockedCoins) } func TestTrackDelegationContVestingAcc(t *testing.T) { @@ -117,37 +103,33 @@ func TestTrackDelegationContVestingAcc(t *testing.T) { _, _, addr := KeyTestPubAddr() origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) - bacc.SetCoins(origCoins) // require the ability to delegate all vesting coins - cva := NewContinuousVestingAccount(&bacc, now.Unix(), endTime.Unix()) - cva.TrackDelegation(now, origCoins) + cva := NewContinuousVestingAccount(&bacc, origCoins, now.Unix(), endTime.Unix()) + cva.TrackDelegation(now, origCoins, origCoins) require.Equal(t, origCoins, cva.DelegatedVesting) require.Nil(t, cva.DelegatedFree) // require the ability to delegate all vested coins - bacc.SetCoins(origCoins) - cva = NewContinuousVestingAccount(&bacc, now.Unix(), endTime.Unix()) - cva.TrackDelegation(endTime, origCoins) + cva = NewContinuousVestingAccount(&bacc, origCoins, now.Unix(), endTime.Unix()) + cva.TrackDelegation(endTime, origCoins, origCoins) require.Nil(t, cva.DelegatedVesting) require.Equal(t, origCoins, cva.DelegatedFree) // require the ability to delegate all vesting coins (50%) and all vested coins (50%) - bacc.SetCoins(origCoins) - cva = NewContinuousVestingAccount(&bacc, now.Unix(), endTime.Unix()) - cva.TrackDelegation(now.Add(12*time.Hour), sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) + cva = NewContinuousVestingAccount(&bacc, origCoins, now.Unix(), endTime.Unix()) + cva.TrackDelegation(now.Add(12*time.Hour), origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) require.Equal(t, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}, cva.DelegatedVesting) require.Nil(t, cva.DelegatedFree) - cva.TrackDelegation(now.Add(12*time.Hour), sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) + cva.TrackDelegation(now.Add(12*time.Hour), origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) require.Equal(t, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}, cva.DelegatedVesting) require.Equal(t, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}, cva.DelegatedFree) // require no modifications when delegation amount is zero or not enough funds - bacc.SetCoins(origCoins) - cva = NewContinuousVestingAccount(&bacc, now.Unix(), endTime.Unix()) + cva = NewContinuousVestingAccount(&bacc, origCoins, now.Unix(), endTime.Unix()) require.Panics(t, func() { - cva.TrackDelegation(endTime, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 1000000)}) + cva.TrackDelegation(endTime, origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 1000000)}) }) require.Nil(t, cva.DelegatedVesting) require.Nil(t, cva.DelegatedFree) @@ -160,27 +142,24 @@ func TestTrackUndelegationContVestingAcc(t *testing.T) { _, _, addr := KeyTestPubAddr() origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) - bacc.SetCoins(origCoins) // require the ability to undelegate all vesting coins - cva := NewContinuousVestingAccount(&bacc, now.Unix(), endTime.Unix()) - cva.TrackDelegation(now, origCoins) + cva := NewContinuousVestingAccount(&bacc, origCoins, now.Unix(), endTime.Unix()) + cva.TrackDelegation(now, origCoins, origCoins) cva.TrackUndelegation(origCoins) require.Nil(t, cva.DelegatedFree) require.Nil(t, cva.DelegatedVesting) // require the ability to undelegate all vested coins - bacc.SetCoins(origCoins) - cva = NewContinuousVestingAccount(&bacc, now.Unix(), endTime.Unix()) + cva = NewContinuousVestingAccount(&bacc, origCoins, now.Unix(), endTime.Unix()) - cva.TrackDelegation(endTime, origCoins) + cva.TrackDelegation(endTime, origCoins, origCoins) cva.TrackUndelegation(origCoins) require.Nil(t, cva.DelegatedFree) require.Nil(t, cva.DelegatedVesting) // require no modifications when the undelegation amount is zero - bacc.SetCoins(origCoins) - cva = NewContinuousVestingAccount(&bacc, now.Unix(), endTime.Unix()) + cva = NewContinuousVestingAccount(&bacc, origCoins, now.Unix(), endTime.Unix()) require.Panics(t, func() { cva.TrackUndelegation(sdk.Coins{sdk.NewInt64Coin(stakeDenom, 0)}) @@ -189,9 +168,9 @@ func TestTrackUndelegationContVestingAcc(t *testing.T) { require.Nil(t, cva.DelegatedVesting) // vest 50% and delegate to two validators - cva = NewContinuousVestingAccount(&bacc, now.Unix(), endTime.Unix()) - cva.TrackDelegation(now.Add(12*time.Hour), sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) - cva.TrackDelegation(now.Add(12*time.Hour), sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) + cva = NewContinuousVestingAccount(&bacc, origCoins, now.Unix(), endTime.Unix()) + cva.TrackDelegation(now.Add(12*time.Hour), origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) + cva.TrackDelegation(now.Add(12*time.Hour), origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) // undelegate from one validator that got slashed 50% cva.TrackUndelegation(sdk.Coins{sdk.NewInt64Coin(stakeDenom, 25)}) @@ -211,10 +190,9 @@ func TestGetVestedCoinsDelVestingAcc(t *testing.T) { _, _, addr := KeyTestPubAddr() origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) - bacc.SetCoins(origCoins) // require no coins are vested until schedule maturation - dva := NewDelayedVestingAccount(&bacc, endTime.Unix()) + dva := NewDelayedVestingAccount(&bacc, origCoins, endTime.Unix()) vestedCoins := dva.GetVestedCoins(now) require.Nil(t, vestedCoins) @@ -230,10 +208,9 @@ func TestGetVestingCoinsDelVestingAcc(t *testing.T) { _, _, addr := KeyTestPubAddr() origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) - bacc.SetCoins(origCoins) // require all coins vesting at the beginning of the schedule - dva := NewDelayedVestingAccount(&bacc, endTime.Unix()) + dva := NewDelayedVestingAccount(&bacc, origCoins, endTime.Unix()) vestingCoins := dva.GetVestingCoins(now) require.Equal(t, origCoins, vestingCoins) @@ -249,38 +226,34 @@ func TestSpendableCoinsDelVestingAcc(t *testing.T) { _, _, addr := KeyTestPubAddr() origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) - bacc.SetCoins(origCoins) - // require that no coins are spendable in the beginning of the vesting + // require that all coins are locked in the beginning of the vesting // schedule - dva := NewDelayedVestingAccount(&bacc, endTime.Unix()) - spendableCoins := dva.SpendableCoins(now) - require.Nil(t, spendableCoins) + dva := NewDelayedVestingAccount(&bacc, origCoins, endTime.Unix()) + lockedCoins := dva.LockedCoins(now) + require.True(t, lockedCoins.IsEqual(origCoins)) // require that all coins are spendable after the maturation of the vesting // schedule - spendableCoins = dva.SpendableCoins(endTime) - require.Equal(t, origCoins, spendableCoins) + lockedCoins = dva.LockedCoins(endTime) + require.Equal(t, sdk.NewCoins(), lockedCoins) // require that all coins are still vesting after some time - spendableCoins = dva.SpendableCoins(now.Add(12 * time.Hour)) - require.Nil(t, spendableCoins) + lockedCoins = dva.LockedCoins(now.Add(12 * time.Hour)) + require.True(t, lockedCoins.IsEqual(origCoins)) // receive some coins - recvAmt := sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)} - dva.SetCoins(dva.GetCoins().Add(recvAmt...)) - // require that only received coins are spendable since the account is still // vesting - spendableCoins = dva.SpendableCoins(now.Add(12 * time.Hour)) - require.Equal(t, recvAmt, spendableCoins) - - // spend all spendable coins - dva.SetCoins(dva.GetCoins().Sub(spendableCoins)) - - // require that no more coins are spendable - spendableCoins = dva.SpendableCoins(now.Add(12 * time.Hour)) - require.Nil(t, spendableCoins) + lockedCoins = dva.LockedCoins(now.Add(12 * time.Hour)) + require.True(t, lockedCoins.IsEqual(origCoins)) + + // delegate some locked coins + // require that locked is reduced + delegatedAmount := sdk.NewCoins(sdk.NewInt64Coin(stakeDenom, 50)) + dva.TrackDelegation(now.Add(12*time.Hour), origCoins, delegatedAmount) + lockedCoins = dva.LockedCoins(now.Add(12 * time.Hour)) + require.True(t, lockedCoins.IsEqual(origCoins.Sub(delegatedAmount))) } func TestTrackDelegationDelVestingAcc(t *testing.T) { @@ -290,36 +263,31 @@ func TestTrackDelegationDelVestingAcc(t *testing.T) { _, _, addr := KeyTestPubAddr() origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) - bacc.SetCoins(origCoins) // require the ability to delegate all vesting coins - bacc.SetCoins(origCoins) - dva := NewDelayedVestingAccount(&bacc, endTime.Unix()) - dva.TrackDelegation(now, origCoins) + dva := NewDelayedVestingAccount(&bacc, origCoins, endTime.Unix()) + dva.TrackDelegation(now, origCoins, origCoins) require.Equal(t, origCoins, dva.DelegatedVesting) require.Nil(t, dva.DelegatedFree) // require the ability to delegate all vested coins - bacc.SetCoins(origCoins) - dva = NewDelayedVestingAccount(&bacc, endTime.Unix()) - dva.TrackDelegation(endTime, origCoins) + dva = NewDelayedVestingAccount(&bacc, origCoins, endTime.Unix()) + dva.TrackDelegation(endTime, origCoins, origCoins) require.Nil(t, dva.DelegatedVesting) require.Equal(t, origCoins, dva.DelegatedFree) // require the ability to delegate all coins half way through the vesting // schedule - bacc.SetCoins(origCoins) - dva = NewDelayedVestingAccount(&bacc, endTime.Unix()) - dva.TrackDelegation(now.Add(12*time.Hour), origCoins) + dva = NewDelayedVestingAccount(&bacc, origCoins, endTime.Unix()) + dva.TrackDelegation(now.Add(12*time.Hour), origCoins, origCoins) require.Equal(t, origCoins, dva.DelegatedVesting) require.Nil(t, dva.DelegatedFree) // require no modifications when delegation amount is zero or not enough funds - bacc.SetCoins(origCoins) - dva = NewDelayedVestingAccount(&bacc, endTime.Unix()) + dva = NewDelayedVestingAccount(&bacc, origCoins, endTime.Unix()) require.Panics(t, func() { - dva.TrackDelegation(endTime, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 1000000)}) + dva.TrackDelegation(endTime, origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 1000000)}) }) require.Nil(t, dva.DelegatedVesting) require.Nil(t, dva.DelegatedFree) @@ -332,27 +300,23 @@ func TestTrackUndelegationDelVestingAcc(t *testing.T) { _, _, addr := KeyTestPubAddr() origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) - bacc.SetCoins(origCoins) // require the ability to undelegate all vesting coins - bacc.SetCoins(origCoins) - dva := NewDelayedVestingAccount(&bacc, endTime.Unix()) - dva.TrackDelegation(now, origCoins) + dva := NewDelayedVestingAccount(&bacc, origCoins, endTime.Unix()) + dva.TrackDelegation(now, origCoins, origCoins) dva.TrackUndelegation(origCoins) require.Nil(t, dva.DelegatedFree) require.Nil(t, dva.DelegatedVesting) // require the ability to undelegate all vested coins - bacc.SetCoins(origCoins) - dva = NewDelayedVestingAccount(&bacc, endTime.Unix()) - dva.TrackDelegation(endTime, origCoins) + dva = NewDelayedVestingAccount(&bacc, origCoins, endTime.Unix()) + dva.TrackDelegation(endTime, origCoins, origCoins) dva.TrackUndelegation(origCoins) require.Nil(t, dva.DelegatedFree) require.Nil(t, dva.DelegatedVesting) // require no modifications when the undelegation amount is zero - bacc.SetCoins(origCoins) - dva = NewDelayedVestingAccount(&bacc, endTime.Unix()) + dva = NewDelayedVestingAccount(&bacc, origCoins, endTime.Unix()) require.Panics(t, func() { dva.TrackUndelegation(sdk.Coins{sdk.NewInt64Coin(stakeDenom, 0)}) @@ -361,10 +325,9 @@ func TestTrackUndelegationDelVestingAcc(t *testing.T) { require.Nil(t, dva.DelegatedVesting) // vest 50% and delegate to two validators - bacc.SetCoins(origCoins) - dva = NewDelayedVestingAccount(&bacc, endTime.Unix()) - dva.TrackDelegation(now.Add(12*time.Hour), sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) - dva.TrackDelegation(now.Add(12*time.Hour), sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) + dva = NewDelayedVestingAccount(&bacc, origCoins, endTime.Unix()) + dva.TrackDelegation(now.Add(12*time.Hour), origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) + dva.TrackDelegation(now.Add(12*time.Hour), origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) // undelegate from one validator that got slashed 50% dva.TrackUndelegation(sdk.Coins{sdk.NewInt64Coin(stakeDenom, 25)}) @@ -390,8 +353,7 @@ func TestGetVestedCoinsPeriodicVestingAcc(t *testing.T) { _, _, addr := KeyTestPubAddr() origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) - bacc.SetCoins(origCoins) - pva := NewPeriodicVestingAccount(&bacc, now.Unix(), periods) + pva := NewPeriodicVestingAccount(&bacc, origCoins, now.Unix(), periods) // require no coins vested at the beginning of the vesting schedule vestedCoins := pva.GetVestedCoins(now) @@ -437,8 +399,7 @@ func TestGetVestingCoinsPeriodicVestingAcc(t *testing.T) { origCoins := sdk.Coins{ sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) - bacc.SetCoins(origCoins) - pva := NewPeriodicVestingAccount(&bacc, now.Unix(), periods) + pva := NewPeriodicVestingAccount(&bacc, origCoins, now.Unix(), periods) // require all coins vesting at the beginning of the vesting schedule vestingCoins := pva.GetVestingCoins(now) @@ -478,37 +439,26 @@ func TestSpendableCoinsPeriodicVestingAcc(t *testing.T) { origCoins := sdk.Coins{ sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) - bacc.SetCoins(origCoins) - pva := NewPeriodicVestingAccount(&bacc, now.Unix(), periods) + pva := NewPeriodicVestingAccount(&bacc, origCoins, now.Unix(), periods) // require that there exist no spendable coins at the beginning of the // vesting schedule - spendableCoins := pva.SpendableCoins(now) - require.Nil(t, spendableCoins) + lockedCoins := pva.LockedCoins(now) + require.Equal(t, origCoins, lockedCoins) // require that all original coins are spendable at the end of the vesting // schedule - spendableCoins = pva.SpendableCoins(endTime) - require.Equal(t, origCoins, spendableCoins) + lockedCoins = pva.LockedCoins(endTime) + require.Equal(t, sdk.NewCoins(), lockedCoins) - // require that all vested coins (50%) are spendable - spendableCoins = pva.SpendableCoins(now.Add(12 * time.Hour)) - require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}, spendableCoins) + // require that all still vesting coins (50%) are locked + lockedCoins = pva.LockedCoins(now.Add(12 * time.Hour)) + require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}, lockedCoins) // receive some coins - recvAmt := sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)} - pva.SetCoins(pva.GetCoins().Add(recvAmt...)) - - // require that all vested coins (50%) are spendable plus any received - spendableCoins = pva.SpendableCoins(now.Add(12 * time.Hour)) - require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 100)}, spendableCoins) - - // spend all spendable coins - pva.SetCoins(pva.GetCoins().Sub(spendableCoins)) - - // require that no more coins are spendable - spendableCoins = pva.SpendableCoins(now.Add(12 * time.Hour)) - require.Nil(t, spendableCoins) + // require that all still vesting coins (50% of original) are locked plus any received + lockedCoins = pva.LockedCoins(now.Add(12 * time.Hour)) + require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}, lockedCoins) } func TestTrackDelegationPeriodicVestingAcc(t *testing.T) { @@ -523,53 +473,47 @@ func TestTrackDelegationPeriodicVestingAcc(t *testing.T) { _, _, addr := KeyTestPubAddr() origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) - bacc.SetCoins(origCoins) // require the ability to delegate all vesting coins - pva := NewPeriodicVestingAccount(&bacc, now.Unix(), periods) - pva.TrackDelegation(now, origCoins) + pva := NewPeriodicVestingAccount(&bacc, origCoins, now.Unix(), periods) + pva.TrackDelegation(now, origCoins, origCoins) require.Equal(t, origCoins, pva.DelegatedVesting) require.Nil(t, pva.DelegatedFree) // require the ability to delegate all vested coins - bacc.SetCoins(origCoins) - pva = NewPeriodicVestingAccount(&bacc, now.Unix(), periods) - pva.TrackDelegation(endTime, origCoins) + pva = NewPeriodicVestingAccount(&bacc, origCoins, now.Unix(), periods) + pva.TrackDelegation(endTime, origCoins, origCoins) require.Nil(t, pva.DelegatedVesting) require.Equal(t, origCoins, pva.DelegatedFree) // delegate half of vesting coins - bacc.SetCoins(origCoins) - pva = NewPeriodicVestingAccount(&bacc, now.Unix(), periods) - pva.TrackDelegation(now, periods[0].Amount) + pva = NewPeriodicVestingAccount(&bacc, origCoins, now.Unix(), periods) + pva.TrackDelegation(now, origCoins, periods[0].Amount) // require that all delegated coins are delegated vesting require.Equal(t, pva.DelegatedVesting, periods[0].Amount) require.Nil(t, pva.DelegatedFree) // delegate 75% of coins, split between vested and vesting - bacc.SetCoins(origCoins) - pva = NewPeriodicVestingAccount(&bacc, now.Unix(), periods) - pva.TrackDelegation(now.Add(12*time.Hour), periods[0].Amount.Add(periods[1].Amount...)) + pva = NewPeriodicVestingAccount(&bacc, origCoins, now.Unix(), periods) + pva.TrackDelegation(now.Add(12*time.Hour), origCoins, periods[0].Amount.Add(periods[1].Amount...)) // require that the maximum possible amount of vesting coins are chosen for delegation. require.Equal(t, pva.DelegatedFree, periods[1].Amount) require.Equal(t, pva.DelegatedVesting, periods[0].Amount) // require the ability to delegate all vesting coins (50%) and all vested coins (50%) - bacc.SetCoins(origCoins) - pva = NewPeriodicVestingAccount(&bacc, now.Unix(), periods) - pva.TrackDelegation(now.Add(12*time.Hour), sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) + pva = NewPeriodicVestingAccount(&bacc, origCoins, now.Unix(), periods) + pva.TrackDelegation(now.Add(12*time.Hour), origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) require.Equal(t, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}, pva.DelegatedVesting) require.Nil(t, pva.DelegatedFree) - pva.TrackDelegation(now.Add(12*time.Hour), sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) + pva.TrackDelegation(now.Add(12*time.Hour), origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) require.Equal(t, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}, pva.DelegatedVesting) require.Equal(t, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}, pva.DelegatedFree) // require no modifications when delegation amount is zero or not enough funds - bacc.SetCoins(origCoins) - pva = NewPeriodicVestingAccount(&bacc, now.Unix(), periods) + pva = NewPeriodicVestingAccount(&bacc, origCoins, now.Unix(), periods) require.Panics(t, func() { - pva.TrackDelegation(endTime, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 1000000)}) + pva.TrackDelegation(endTime, origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 1000000)}) }) require.Nil(t, pva.DelegatedVesting) require.Nil(t, pva.DelegatedFree) @@ -587,35 +531,31 @@ func TestTrackUndelegationPeriodicVestingAcc(t *testing.T) { _, _, addr := KeyTestPubAddr() origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) - bacc.SetCoins(origCoins) // require the ability to undelegate all vesting coins at the beginning of vesting - pva := NewPeriodicVestingAccount(&bacc, now.Unix(), periods) - pva.TrackDelegation(now, origCoins) + pva := NewPeriodicVestingAccount(&bacc, origCoins, now.Unix(), periods) + pva.TrackDelegation(now, origCoins, origCoins) pva.TrackUndelegation(origCoins) require.Nil(t, pva.DelegatedFree) require.Nil(t, pva.DelegatedVesting) // require the ability to undelegate all vested coins at the end of vesting - bacc.SetCoins(origCoins) - pva = NewPeriodicVestingAccount(&bacc, now.Unix(), periods) + pva = NewPeriodicVestingAccount(&bacc, origCoins, now.Unix(), periods) - pva.TrackDelegation(endTime, origCoins) + pva.TrackDelegation(endTime, origCoins, origCoins) pva.TrackUndelegation(origCoins) require.Nil(t, pva.DelegatedFree) require.Nil(t, pva.DelegatedVesting) // require the ability to undelegate half of coins - bacc.SetCoins(origCoins) - pva = NewPeriodicVestingAccount(&bacc, now.Unix(), periods) - pva.TrackDelegation(endTime, periods[0].Amount) + pva = NewPeriodicVestingAccount(&bacc, origCoins, now.Unix(), periods) + pva.TrackDelegation(endTime, origCoins, periods[0].Amount) pva.TrackUndelegation(periods[0].Amount) require.Nil(t, pva.DelegatedFree) require.Nil(t, pva.DelegatedVesting) // require no modifications when the undelegation amount is zero - bacc.SetCoins(origCoins) - pva = NewPeriodicVestingAccount(&bacc, now.Unix(), periods) + pva = NewPeriodicVestingAccount(&bacc, origCoins, now.Unix(), periods) require.Panics(t, func() { pva.TrackUndelegation(sdk.Coins{sdk.NewInt64Coin(stakeDenom, 0)}) @@ -624,9 +564,9 @@ func TestTrackUndelegationPeriodicVestingAcc(t *testing.T) { require.Nil(t, pva.DelegatedVesting) // vest 50% and delegate to two validators - pva = NewPeriodicVestingAccount(&bacc, now.Unix(), periods) - pva.TrackDelegation(now.Add(12*time.Hour), sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) - pva.TrackDelegation(now.Add(12*time.Hour), sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) + pva = NewPeriodicVestingAccount(&bacc, origCoins, now.Unix(), periods) + pva.TrackDelegation(now.Add(12*time.Hour), origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) + pva.TrackDelegation(now.Add(12*time.Hour), origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) // undelegate from one validator that got slashed 50% pva.TrackUndelegation(sdk.Coins{sdk.NewInt64Coin(stakeDenom, 25)}) @@ -639,42 +579,42 @@ func TestTrackUndelegationPeriodicVestingAcc(t *testing.T) { require.Equal(t, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 25)}, pva.DelegatedVesting) } -func TestNewBaseVestingAccount(t *testing.T) { - pubkey := secp256k1.GenPrivKey().PubKey() - addr := sdk.AccAddress(pubkey.Address()) - _, err := NewBaseVestingAccount( - authtypes.NewBaseAccount(addr, sdk.NewCoins(), pubkey, 0, 0), - sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)}, 100, - ) - require.Equal(t, errors.New("vesting amount cannot be greater than total amount"), err) - - _, err = NewBaseVestingAccount( - authtypes.NewBaseAccount(addr, sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 10)), pubkey, 0, 0), - sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)}, 100, - ) - require.Equal(t, errors.New("vesting amount cannot be greater than total amount"), err) - - _, err = NewBaseVestingAccount( - authtypes.NewBaseAccount(addr, sdk.NewCoins(sdk.NewInt64Coin("uatom", 50), sdk.NewInt64Coin("eth", 50)), pubkey, 0, 0), - sdk.NewCoins(sdk.NewInt64Coin("uatom", 100), sdk.NewInt64Coin("eth", 20)), 100, - ) - require.Equal(t, errors.New("vesting amount cannot be greater than total amount"), err) - - _, err = NewBaseVestingAccount( - authtypes.NewBaseAccount(addr, sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)}, pubkey, 0, 0), - sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)}, 100, - ) - require.NoError(t, err) - -} +// TODO: Move test to bank +// func TestNewBaseVestingAccount(t *testing.T) { +// pubkey := secp256k1.GenPrivKey().PubKey() +// addr := sdk.AccAddress(pubkey.Address()) +// _, err := NewBaseVestingAccount( +// authtypes.NewBaseAccount(addr, sdk.NewCoins(), pubkey, 0, 0), +// sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)}, 100, +// ) +// require.Equal(t, errors.New("vesting amount cannot be greater than total amount"), err) + +// _, err = NewBaseVestingAccount( +// authtypes.NewBaseAccount(addr, sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 10)), pubkey, 0, 0), +// sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)}, 100, +// ) +// require.Equal(t, errors.New("vesting amount cannot be greater than total amount"), err) + +// _, err = NewBaseVestingAccount( +// authtypes.NewBaseAccount(addr, sdk.NewCoins(sdk.NewInt64Coin("uatom", 50), sdk.NewInt64Coin("eth", 50)), pubkey, 0, 0), +// sdk.NewCoins(sdk.NewInt64Coin("uatom", 100), sdk.NewInt64Coin("eth", 20)), 100, +// ) +// require.Equal(t, errors.New("vesting amount cannot be greater than total amount"), err) + +// _, err = NewBaseVestingAccount( +// authtypes.NewBaseAccount(addr, sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)}, pubkey, 0, 0), +// sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)}, 100, +// ) +// require.NoError(t, err) + +// } func TestGenesisAccountValidate(t *testing.T) { pubkey := secp256k1.GenPrivKey().PubKey() addr := sdk.AccAddress(pubkey.Address()) - baseAcc := authtypes.NewBaseAccount(addr, nil, pubkey, 0, 0) - baseAccWithCoins := authtypes.NewBaseAccount(addr, nil, pubkey, 0, 0) - baseAccWithCoins.SetCoins(sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)}) - baseVestingWithCoins, _ := NewBaseVestingAccount(baseAccWithCoins, baseAccWithCoins.Coins, 100) + baseAcc := authtypes.NewBaseAccount(addr, pubkey, 0, 0) + initialVesting := sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)) + baseVestingWithCoins := NewBaseVestingAccount(baseAcc, initialVesting, 100) tests := []struct { name string acc authexported.GenesisAccount @@ -687,7 +627,7 @@ func TestGenesisAccountValidate(t *testing.T) { }, { "invalid base valid account", - authtypes.NewBaseAccount(addr, sdk.NewCoins(), secp256k1.GenPrivKey().PubKey(), 0, 0), + authtypes.NewBaseAccount(addr, secp256k1.GenPrivKey().PubKey(), 0, 0), errors.New("pubkey and address pair is invalid"), }, { @@ -697,17 +637,17 @@ func TestGenesisAccountValidate(t *testing.T) { }, { "valid continuous vesting account", - NewContinuousVestingAccount(baseAcc, 100, 200), + NewContinuousVestingAccount(baseAcc, initialVesting, 100, 200), nil, }, { "invalid vesting times", - NewContinuousVestingAccount(baseAcc, 1654668078, 1554668078), + NewContinuousVestingAccount(baseAcc, initialVesting, 1654668078, 1554668078), errors.New("vesting start-time cannot be before end-time"), }, { "valid periodic vesting account", - NewPeriodicVestingAccount(baseAccWithCoins, 0, Periods{Period{Length: int64(100), Amount: sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)}}}), + NewPeriodicVestingAccount(baseAcc, initialVesting, 0, Periods{Period{Length: int64(100), Amount: sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)}}}), nil, }, { @@ -738,10 +678,9 @@ func TestBaseVestingAccountJSON(t *testing.T) { pubkey := secp256k1.GenPrivKey().PubKey() addr := sdk.AccAddress(pubkey.Address()) coins := sdk.NewCoins(sdk.NewInt64Coin("test", 5)) - baseAcc := authtypes.NewBaseAccount(addr, coins, pubkey, 10, 50) + baseAcc := authtypes.NewBaseAccount(addr, pubkey, 10, 50) - acc, err := NewBaseVestingAccount(baseAcc, coins, time.Now().Unix()) - require.NoError(t, err) + acc := NewBaseVestingAccount(baseAcc, coins, time.Now().Unix()) bz, err := json.Marshal(acc) require.NoError(t, err) @@ -759,11 +698,10 @@ func TestContinuousVestingAccountJSON(t *testing.T) { pubkey := secp256k1.GenPrivKey().PubKey() addr := sdk.AccAddress(pubkey.Address()) coins := sdk.NewCoins(sdk.NewInt64Coin("test", 5)) - baseAcc := authtypes.NewBaseAccount(addr, coins, pubkey, 10, 50) + baseAcc := authtypes.NewBaseAccount(addr, pubkey, 10, 50) - baseVesting, err := NewBaseVestingAccount(baseAcc, coins, time.Now().Unix()) + baseVesting := NewBaseVestingAccount(baseAcc, coins, time.Now().Unix()) acc := NewContinuousVestingAccountRaw(baseVesting, baseVesting.EndTime) - require.NoError(t, err) bz, err := json.Marshal(acc) require.NoError(t, err) @@ -781,9 +719,9 @@ func TestPeriodicVestingAccountJSON(t *testing.T) { pubkey := secp256k1.GenPrivKey().PubKey() addr := sdk.AccAddress(pubkey.Address()) coins := sdk.NewCoins(sdk.NewInt64Coin("test", 5)) - baseAcc := authtypes.NewBaseAccount(addr, coins, pubkey, 10, 50) + baseAcc := authtypes.NewBaseAccount(addr, pubkey, 10, 50) - acc := NewPeriodicVestingAccount(baseAcc, time.Now().Unix(), Periods{Period{3600, coins}}) + acc := NewPeriodicVestingAccount(baseAcc, coins, time.Now().Unix(), Periods{Period{3600, coins}}) bz, err := json.Marshal(acc) require.NoError(t, err) @@ -801,9 +739,9 @@ func TestDelayedVestingAccountJSON(t *testing.T) { pubkey := secp256k1.GenPrivKey().PubKey() addr := sdk.AccAddress(pubkey.Address()) coins := sdk.NewCoins(sdk.NewInt64Coin("test", 5)) - baseAcc := authtypes.NewBaseAccount(addr, coins, pubkey, 10, 50) + baseAcc := authtypes.NewBaseAccount(addr, pubkey, 10, 50) - acc := NewDelayedVestingAccount(baseAcc, time.Now().Unix()) + acc := NewDelayedVestingAccount(baseAcc, coins, time.Now().Unix()) bz, err := json.Marshal(acc) require.NoError(t, err) diff --git a/x/bank/alias.go b/x/bank/alias.go index 1ac7cecebd90..2fdfa6602b82 100644 --- a/x/bank/alias.go +++ b/x/bank/alias.go @@ -8,10 +8,12 @@ import ( ) const ( - QueryBalance = keeper.QueryBalance + QueryBalance = types.QueryBalance + QueryAllBalances = types.QueryAllBalances ModuleName = types.ModuleName QuerierRoute = types.QuerierRoute RouterKey = types.RouterKey + StoreKey = types.StoreKey DefaultParamspace = types.DefaultParamspace DefaultSendEnabled = types.DefaultSendEnabled @@ -36,6 +38,7 @@ var ( NewGenesisState = types.NewGenesisState DefaultGenesisState = types.DefaultGenesisState ValidateGenesis = types.ValidateGenesis + SanitizeGenesisBalances = types.SanitizeGenesisBalances NewMsgSend = types.NewMsgSend NewMsgMultiSend = types.NewMsgMultiSend NewInput = types.NewInput @@ -43,21 +46,26 @@ var ( ValidateInputsOutputs = types.ValidateInputsOutputs ParamKeyTable = types.ParamKeyTable NewQueryBalanceParams = types.NewQueryBalanceParams + NewQueryAllBalancesParams = types.NewQueryAllBalancesParams ModuleCdc = types.ModuleCdc ParamStoreKeySendEnabled = types.ParamStoreKeySendEnabled + BalancesPrefix = types.BalancesPrefix + AddressFromBalancesStore = types.AddressFromBalancesStore ) type ( - Keeper = keeper.Keeper - BaseKeeper = keeper.BaseKeeper - SendKeeper = keeper.SendKeeper - BaseSendKeeper = keeper.BaseSendKeeper - ViewKeeper = keeper.ViewKeeper - BaseViewKeeper = keeper.BaseViewKeeper - GenesisState = types.GenesisState - MsgSend = types.MsgSend - MsgMultiSend = types.MsgMultiSend - Input = types.Input - Output = types.Output - QueryBalanceParams = types.QueryBalanceParams + Keeper = keeper.Keeper + BaseKeeper = keeper.BaseKeeper + SendKeeper = keeper.SendKeeper + BaseSendKeeper = keeper.BaseSendKeeper + ViewKeeper = keeper.ViewKeeper + BaseViewKeeper = keeper.BaseViewKeeper + GenesisState = types.GenesisState + Balance = types.Balance + MsgSend = types.MsgSend + MsgMultiSend = types.MsgMultiSend + Input = types.Input + Output = types.Output + QueryBalanceParams = types.QueryBalanceParams + QueryAllBalancesParams = types.QueryAllBalancesParams ) diff --git a/x/bank/app_test.go b/x/bank/app_test.go index 7a9894aa8c3b..e124baaeef7f 100644 --- a/x/bank/app_test.go +++ b/x/bank/app_test.go @@ -49,7 +49,6 @@ var ( halfCoins = sdk.Coins{sdk.NewInt64Coin("foocoin", 5)} sendMsg1 = types.NewMsgSend(addr1, addr2, coins) - sendMsg2 = types.NewMsgSend(addr1, moduleAccAddr, coins) multiSendMsg1 = types.MsgMultiSend{ Inputs: []types.Input{types.NewInput(addr1, coins)}, @@ -93,15 +92,18 @@ var ( func TestSendNotEnoughBalance(t *testing.T) { acc := &auth.BaseAccount{ Address: addr1, - Coins: sdk.Coins{sdk.NewInt64Coin("foocoin", 67)}, } genAccs := []authexported.GenesisAccount{acc} app := simapp.SetupWithGenesisAccounts(genAccs) + ctx := app.BaseApp.NewContext(false, abci.Header{}) - ctxCheck := app.BaseApp.NewContext(true, abci.Header{}) + err := app.BankKeeper.SetBalances(ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 67))) + require.NoError(t, err) + + app.Commit() - res1 := app.AccountKeeper.GetAccount(ctxCheck, addr1) + res1 := app.AccountKeeper.GetAccount(ctx, addr1) require.NotNil(t, res1) require.Equal(t, acc, res1.(*auth.BaseAccount)) @@ -157,15 +159,18 @@ func TestSendToModuleAcc(t *testing.T) { t.Run(test.name, func(t *testing.T) { acc := &auth.BaseAccount{ Address: test.msg.FromAddress, - Coins: test.fromBalance, } genAccs := []authexported.GenesisAccount{acc} app := simapp.SetupWithGenesisAccounts(genAccs) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + err := app.BankKeeper.SetBalances(ctx, test.msg.FromAddress, test.fromBalance) + require.NoError(t, err) - ctxCheck := app.BaseApp.NewContext(true, abci.Header{}) + app.Commit() - res1 := app.AccountKeeper.GetAccount(ctxCheck, test.msg.FromAddress) + res1 := app.AccountKeeper.GetAccount(ctx, test.msg.FromAddress) require.NotNil(t, res1) require.Equal(t, acc, res1.(*auth.BaseAccount)) @@ -190,15 +195,18 @@ func TestSendToModuleAcc(t *testing.T) { func TestMsgMultiSendWithAccounts(t *testing.T) { acc := &auth.BaseAccount{ Address: addr1, - Coins: sdk.Coins{sdk.NewInt64Coin("foocoin", 67)}, } genAccs := []authexported.GenesisAccount{acc} app := simapp.SetupWithGenesisAccounts(genAccs) + ctx := app.BaseApp.NewContext(false, abci.Header{}) - ctxCheck := app.BaseApp.NewContext(true, abci.Header{}) + err := app.BankKeeper.SetBalances(ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 67))) + require.NoError(t, err) + + app.Commit() - res1 := app.AccountKeeper.GetAccount(ctxCheck, addr1) + res1 := app.AccountKeeper.GetAccount(ctx, addr1) require.NotNil(t, res1) require.Equal(t, acc, res1.(*auth.BaseAccount)) @@ -244,18 +252,24 @@ func TestMsgMultiSendWithAccounts(t *testing.T) { } func TestMsgMultiSendMultipleOut(t *testing.T) { - acc1 := &auth.BaseAccount{ Address: addr1, - Coins: sdk.Coins{sdk.NewInt64Coin("foocoin", 42)}, } acc2 := &auth.BaseAccount{ Address: addr2, - Coins: sdk.Coins{sdk.NewInt64Coin("foocoin", 42)}, } genAccs := []authexported.GenesisAccount{acc1, acc2} app := simapp.SetupWithGenesisAccounts(genAccs) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + err := app.BankKeeper.SetBalances(ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42))) + require.NoError(t, err) + + err = app.BankKeeper.SetBalances(ctx, addr2, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42))) + require.NoError(t, err) + + app.Commit() testCases := []appTestCase{ { @@ -284,22 +298,30 @@ func TestMsgMultiSendMultipleOut(t *testing.T) { } func TestMsgMultiSendMultipleInOut(t *testing.T) { - acc1 := &auth.BaseAccount{ Address: addr1, - Coins: sdk.Coins{sdk.NewInt64Coin("foocoin", 42)}, } acc2 := &auth.BaseAccount{ Address: addr2, - Coins: sdk.Coins{sdk.NewInt64Coin("foocoin", 42)}, } acc4 := &auth.BaseAccount{ Address: addr4, - Coins: sdk.Coins{sdk.NewInt64Coin("foocoin", 42)}, } genAccs := []authexported.GenesisAccount{acc1, acc2, acc4} app := simapp.SetupWithGenesisAccounts(genAccs) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + err := app.BankKeeper.SetBalances(ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42))) + require.NoError(t, err) + + err = app.BankKeeper.SetBalances(ctx, addr2, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42))) + require.NoError(t, err) + + err = app.BankKeeper.SetBalances(ctx, addr4, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42))) + require.NoError(t, err) + + app.Commit() testCases := []appTestCase{ { @@ -331,13 +353,17 @@ func TestMsgMultiSendMultipleInOut(t *testing.T) { func TestMsgMultiSendDependent(t *testing.T) { acc1 := auth.NewBaseAccountWithAddress(addr1) acc2 := auth.NewBaseAccountWithAddress(addr2) - err := acc1.SetCoins(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42))) - require.NoError(t, err) - err = acc2.SetAccountNumber(1) + err := acc2.SetAccountNumber(1) require.NoError(t, err) genAccs := []authexported.GenesisAccount{&acc1, &acc2} app := simapp.SetupWithGenesisAccounts(genAccs) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + err = app.BankKeeper.SetBalances(ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42))) + require.NoError(t, err) + + app.Commit() testCases := []appTestCase{ { diff --git a/x/bank/bench_test.go b/x/bank/bench_test.go index 9161a88c31ba..d9ccdc5702a0 100644 --- a/x/bank/bench_test.go +++ b/x/bank/bench_test.go @@ -3,6 +3,7 @@ package bank_test import ( "testing" + "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/simapp" @@ -19,29 +20,38 @@ func BenchmarkOneBankSendTxPerBlock(b *testing.B) { // Add an account at genesis acc := auth.BaseAccount{ Address: addr1, - // Some value conceivably higher than the benchmarks would ever go - Coins: sdk.Coins{sdk.NewInt64Coin("foocoin", 100000000000)}, } - // Construct genesis state + // construct genesis state genAccs := []authexported.GenesisAccount{&acc} benchmarkApp := simapp.SetupWithGenesisAccounts(genAccs) + ctx := benchmarkApp.BaseApp.NewContext(false, abci.Header{}) + + // some value conceivably higher than the benchmarks would ever go + err := benchmarkApp.BankKeeper.SetBalances(ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 100000000000))) + require.NoError(b, err) + + benchmarkApp.Commit() // Precompute all txs txs := simapp.GenSequenceOfTxs([]sdk.Msg{sendMsg1}, []uint64{0}, []uint64{uint64(0)}, b.N, priv1) b.ResetTimer() + + height := int64(3) + // Run this with a profiler, so its easy to distinguish what time comes from // Committing, and what time comes from Check/Deliver Tx. for i := 0; i < b.N; i++ { - benchmarkApp.BeginBlock(abci.RequestBeginBlock{}) + benchmarkApp.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: height}}) _, _, err := benchmarkApp.Check(txs[i]) if err != nil { panic("something is broken in checking transaction") } benchmarkApp.Deliver(txs[i]) - benchmarkApp.EndBlock(abci.RequestEndBlock{}) + benchmarkApp.EndBlock(abci.RequestEndBlock{Height: height}) benchmarkApp.Commit() + height++ } } @@ -49,28 +59,37 @@ func BenchmarkOneBankMultiSendTxPerBlock(b *testing.B) { // Add an account at genesis acc := auth.BaseAccount{ Address: addr1, - // Some value conceivably higher than the benchmarks would ever go - Coins: sdk.Coins{sdk.NewInt64Coin("foocoin", 100000000000)}, } // Construct genesis state genAccs := []authexported.GenesisAccount{&acc} benchmarkApp := simapp.SetupWithGenesisAccounts(genAccs) + ctx := benchmarkApp.BaseApp.NewContext(false, abci.Header{}) + + // some value conceivably higher than the benchmarks would ever go + err := benchmarkApp.BankKeeper.SetBalances(ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 100000000000))) + require.NoError(b, err) + + benchmarkApp.Commit() // Precompute all txs txs := simapp.GenSequenceOfTxs([]sdk.Msg{multiSendMsg1}, []uint64{0}, []uint64{uint64(0)}, b.N, priv1) b.ResetTimer() + + height := int64(3) + // Run this with a profiler, so its easy to distinguish what time comes from // Committing, and what time comes from Check/Deliver Tx. for i := 0; i < b.N; i++ { - benchmarkApp.BeginBlock(abci.RequestBeginBlock{}) + benchmarkApp.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: height}}) _, _, err := benchmarkApp.Check(txs[i]) if err != nil { panic("something is broken in checking transaction") } benchmarkApp.Deliver(txs[i]) - benchmarkApp.EndBlock(abci.RequestEndBlock{}) + benchmarkApp.EndBlock(abci.RequestEndBlock{Height: height}) benchmarkApp.Commit() + height++ } } diff --git a/x/bank/client/cli/query.go b/x/bank/client/cli/query.go new file mode 100644 index 000000000000..046e84051448 --- /dev/null +++ b/x/bank/client/cli/query.go @@ -0,0 +1,99 @@ +package cli + +import ( + "fmt" + + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/bank/internal/types" +) + +const ( + flagDenom = "denom" +) + +// GetQueryCmd returns the parent querying command for the bank module. +func GetQueryCmd(cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: types.ModuleName, + Short: "Querying commands for the bank module", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + cmd.AddCommand(GetBalancesCmd(cdc)) + + return cmd +} + +// GetAccountCmd returns a CLI command handler that facilitates querying for a +// single or all account balances by address. +func GetBalancesCmd(cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "balances [address]", + Short: "Query for account balances by address", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + + addr, err := sdk.AccAddressFromBech32(args[0]) + if err != nil { + return err + } + + var ( + params interface{} + result interface{} + route string + ) + + denom := viper.GetString(flagDenom) + if denom == "" { + params = types.NewQueryAllBalancesParams(addr) + route = fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryAllBalances) + } else { + params = types.NewQueryBalanceParams(addr, denom) + route = fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryBalance) + } + + bz, err := cdc.MarshalJSON(params) + if err != nil { + return fmt.Errorf("failed to marshal params: %w", err) + } + + res, _, err := cliCtx.QueryWithData(route, bz) + if err != nil { + return err + } + + if denom == "" { + var balances sdk.Coins + if err := cdc.UnmarshalJSON(res, &balances); err != nil { + return err + } + + result = balances + } else { + var balance sdk.Coin + if err := cdc.UnmarshalJSON(res, &balance); err != nil { + return err + } + + result = balance + } + + return cliCtx.PrintOutput(result) + }, + } + + cmd.Flags().String(flagDenom, "", "The specific balance denomination to query for") + + return flags.GetCommands(cmd)[0] +} diff --git a/x/bank/client/rest/query.go b/x/bank/client/rest/query.go index 97bb16df3274..eb1f3463b7a6 100644 --- a/x/bank/client/rest/query.go +++ b/x/bank/client/rest/query.go @@ -1,6 +1,7 @@ package rest import ( + "fmt" "net/http" "github.com/gorilla/mux" @@ -11,7 +12,8 @@ import ( "github.com/cosmos/cosmos-sdk/x/bank/internal/types" ) -// query accountREST Handler +// QueryBalancesRequestHandlerFn returns a REST handler that queries for all +// account balances or a specific balance by denomination. func QueryBalancesRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") @@ -29,27 +31,33 @@ func QueryBalancesRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return } - params := types.NewQueryBalanceParams(addr) + var ( + params interface{} + route string + ) + + denom := r.FormValue("denom") + if denom == "" { + params = types.NewQueryAllBalancesParams(addr) + route = fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryAllBalances) + } else { + params = types.NewQueryBalanceParams(addr, denom) + route = fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryBalance) + } + bz, err := cliCtx.Codec.MarshalJSON(params) if err != nil { rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } - res, height, err := cliCtx.QueryWithData("custom/bank/balances", bz) + res, height, err := cliCtx.QueryWithData(route, bz) if err != nil { rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return } cliCtx = cliCtx.WithHeight(height) - - // the query will return empty if there is no data for this account - if len(res) == 0 { - rest.PostProcessResponse(w, cliCtx, sdk.Coins{}) - return - } - rest.PostProcessResponse(w, cliCtx, res) } } diff --git a/x/bank/client/rest/rest.go b/x/bank/client/rest/rest.go new file mode 100644 index 000000000000..b2b1ff84c894 --- /dev/null +++ b/x/bank/client/rest/rest.go @@ -0,0 +1,12 @@ +package rest + +import ( + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/gorilla/mux" +) + +// RegisterRoutes - Central function to define routes that get registered by the main application +func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router) { + r.HandleFunc("/bank/accounts/{address}/transfers", SendRequestHandlerFn(cliCtx)).Methods("POST") + r.HandleFunc("/bank/balances/{address}", QueryBalancesRequestHandlerFn(cliCtx)).Methods("GET") +} diff --git a/x/bank/client/rest/tx.go b/x/bank/client/rest/tx.go index fdf245430dba..52fa9f25136b 100644 --- a/x/bank/client/rest/tx.go +++ b/x/bank/client/rest/tx.go @@ -12,12 +12,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/bank/internal/types" ) -// RegisterRoutes - Central function to define routes that get registered by the main application -func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router) { - r.HandleFunc("/bank/accounts/{address}/transfers", SendRequestHandlerFn(cliCtx)).Methods("POST") - r.HandleFunc("/bank/balances/{address}", QueryBalancesRequestHandlerFn(cliCtx)).Methods("GET") -} - // SendReq defines the properties of a send request's body. type SendReq struct { BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` diff --git a/x/bank/exported/exported.go b/x/bank/exported/exported.go new file mode 100644 index 000000000000..c4f2e9f6da09 --- /dev/null +++ b/x/bank/exported/exported.go @@ -0,0 +1,12 @@ +package exported + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// GenesisBalance defines a genesis balance interface that allows for account +// address and balance retrieval. +type GenesisBalance interface { + GetAddress() sdk.AccAddress + GetCoins() sdk.Coins +} diff --git a/x/bank/genesis.go b/x/bank/genesis.go index 641875e6dc88..7f68e94cff8e 100644 --- a/x/bank/genesis.go +++ b/x/bank/genesis.go @@ -1,15 +1,47 @@ package bank import ( + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" ) -// InitGenesis sets distribution information for genesis. -func InitGenesis(ctx sdk.Context, keeper Keeper, data GenesisState) { - keeper.SetSendEnabled(ctx, data.SendEnabled) +// InitGenesis initializes the bank module's state from a given genesis state. +func InitGenesis(ctx sdk.Context, keeper Keeper, genState GenesisState) { + keeper.SetSendEnabled(ctx, genState.SendEnabled) + + genState.Balances = SanitizeGenesisBalances(genState.Balances) + for _, balance := range genState.Balances { + if err := keeper.ValidateBalance(ctx, balance.Address); err != nil { + panic(err) + } + + keeper.SetBalances(ctx, balance.Address, balance.Coins) + } } -// ExportGenesis returns a GenesisState for a given context and keeper. +// ExportGenesis returns the bank module's genesis state. func ExportGenesis(ctx sdk.Context, keeper Keeper) GenesisState { - return NewGenesisState(keeper.GetSendEnabled(ctx)) + balancesSet := make(map[string]sdk.Coins) + + keeper.IterateAllBalances(ctx, func(addr sdk.AccAddress, balance sdk.Coin) bool { + balancesSet[addr.String()] = balancesSet[addr.String()].Add(balance) + return false + }) + + balances := []Balance{} + + for addrStr, coins := range balancesSet { + addr, err := sdk.AccAddressFromBech32(addrStr) + if err != nil { + panic(fmt.Errorf("failed to convert address from string: %w", err)) + } + + balances = append(balances, Balance{ + Address: addr, + Coins: coins, + }) + } + + return NewGenesisState(keeper.GetSendEnabled(ctx), balances) } diff --git a/x/bank/internal/keeper/integration_test.go b/x/bank/internal/keeper/integration_test.go deleted file mode 100644 index f008a5558839..000000000000 --- a/x/bank/internal/keeper/integration_test.go +++ /dev/null @@ -1,19 +0,0 @@ -package keeper_test - -import ( - abci "github.com/tendermint/tendermint/abci/types" - - "github.com/cosmos/cosmos-sdk/simapp" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth" -) - -func createTestApp(isCheckTx bool) (*simapp.SimApp, sdk.Context) { - app := simapp.Setup(isCheckTx) - ctx := app.BaseApp.NewContext(isCheckTx, abci.Header{}) - - app.AccountKeeper.SetParams(ctx, auth.DefaultParams()) - app.BankKeeper.SetSendEnabled(ctx, true) - - return app, ctx -} diff --git a/x/bank/internal/keeper/invariants.go b/x/bank/internal/keeper/invariants.go index 0be1e8f58f23..65730451261b 100644 --- a/x/bank/internal/keeper/invariants.go +++ b/x/bank/internal/keeper/invariants.go @@ -8,30 +8,33 @@ import ( ) // RegisterInvariants registers the bank module invariants -func RegisterInvariants(ir sdk.InvariantRegistry, ak types.AccountKeeper) { +func RegisterInvariants(ir sdk.InvariantRegistry, bk ViewKeeper) { ir.RegisterRoute(types.ModuleName, "nonnegative-outstanding", - NonnegativeBalanceInvariant(ak)) + NonnegativeBalanceInvariant(bk)) } // NonnegativeBalanceInvariant checks that all accounts in the application have non-negative balances -func NonnegativeBalanceInvariant(ak types.AccountKeeper) sdk.Invariant { +func NonnegativeBalanceInvariant(bk ViewKeeper) sdk.Invariant { return func(ctx sdk.Context) (string, bool) { - var msg string - var count int + var ( + msg string + count int + ) - accts := ak.GetAllAccounts(ctx) - for _, acc := range accts { - coins := acc.GetCoins() - if coins.IsAnyNegative() { + bk.IterateAllBalances(ctx, func(addr sdk.AccAddress, balance sdk.Coin) bool { + if balance.IsNegative() { count++ - msg += fmt.Sprintf("\t%s has a negative denomination of %s\n", - acc.GetAddress().String(), - coins.String()) + msg += fmt.Sprintf("\t%s has a negative balance of %s\n", addr, balance) } - } + + return false + }) + broken := count != 0 - return sdk.FormatInvariant(types.ModuleName, "nonnegative-outstanding", - fmt.Sprintf("amount of negative accounts found %d\n%s", count, msg)), broken + return sdk.FormatInvariant( + types.ModuleName, "nonnegative-outstanding", + fmt.Sprintf("amount of negative balances found %d\n%s", count, msg), + ), broken } } diff --git a/x/bank/internal/keeper/keeper.go b/x/bank/internal/keeper/keeper.go index 25e47b073932..380507178635 100644 --- a/x/bank/internal/keeper/keeper.go +++ b/x/bank/internal/keeper/keeper.go @@ -6,9 +6,10 @@ import ( "github.com/tendermint/tendermint/libs/log" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" vestexported "github.com/cosmos/cosmos-sdk/x/auth/vesting/exported" "github.com/cosmos/cosmos-sdk/x/bank/internal/types" "github.com/cosmos/cosmos-sdk/x/params" @@ -33,14 +34,13 @@ type BaseKeeper struct { paramSpace params.Subspace } -// NewBaseKeeper returns a new BaseKeeper func NewBaseKeeper( - ak types.AccountKeeper, paramSpace params.Subspace, blacklistedAddrs map[string]bool, + cdc *codec.Codec, storeKey sdk.StoreKey, ak types.AccountKeeper, paramSpace params.Subspace, blacklistedAddrs map[string]bool, ) BaseKeeper { ps := paramSpace.WithKeyTable(types.ParamKeyTable()) return BaseKeeper{ - BaseSendKeeper: NewBaseSendKeeper(ak, ps, blacklistedAddrs), + BaseSendKeeper: NewBaseSendKeeper(cdc, storeKey, ak, ps, blacklistedAddrs), ak: ak, paramSpace: ps, } @@ -48,16 +48,11 @@ func NewBaseKeeper( // DelegateCoins performs delegation by deducting amt coins from an account with // address addr. For vesting accounts, delegations amounts are tracked for both -// vesting and vested coins. -// The coins are then transferred from the delegator address to a ModuleAccount address. -// If any of the delegation amounts are negative, an error is returned. -func (keeper BaseKeeper) DelegateCoins(ctx sdk.Context, delegatorAddr, moduleAccAddr sdk.AccAddress, amt sdk.Coins) error { - delegatorAcc := keeper.ak.GetAccount(ctx, delegatorAddr) - if delegatorAcc == nil { - return sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "account %s does not exist", delegatorAddr) - } - - moduleAcc := keeper.ak.GetAccount(ctx, moduleAccAddr) +// vesting and vested coins. The coins are then transferred from the delegator +// address to a ModuleAccount address. If any of the delegation amounts are negative, +// an error is returned. +func (k BaseKeeper) DelegateCoins(ctx sdk.Context, delegatorAddr, moduleAccAddr sdk.AccAddress, amt sdk.Coins) error { + moduleAcc := k.ak.GetAccount(ctx, moduleAccAddr) if moduleAcc == nil { return sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", moduleAccAddr) } @@ -66,22 +61,25 @@ func (keeper BaseKeeper) DelegateCoins(ctx sdk.Context, delegatorAddr, moduleAcc return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, amt.String()) } - oldCoins := delegatorAcc.GetCoins() + balances := sdk.NewCoins() - _, hasNeg := oldCoins.SafeSub(amt) - if hasNeg { - return sdkerrors.Wrapf( - sdkerrors.ErrInsufficientFunds, "insufficient account funds; %s < %s", oldCoins, amt, - ) + for _, coin := range amt { + balance := k.GetBalance(ctx, delegatorAddr, coin.Denom) + if balance.IsLT(coin) { + return sdkerrors.Wrapf( + sdkerrors.ErrInsufficientFunds, "failed to delegate; %s < %s", balance, amt, + ) + } + + balances = balances.Add(balance) + k.SetBalance(ctx, delegatorAddr, balance.Sub(coin)) } - if err := trackDelegation(delegatorAcc, ctx.BlockHeader().Time, amt); err != nil { + if err := k.trackDelegation(ctx, delegatorAddr, ctx.BlockHeader().Time, balances, amt); err != nil { return sdkerrors.Wrap(err, "failed to track delegation") } - keeper.ak.SetAccount(ctx, delegatorAcc) - - _, err := keeper.AddCoins(ctx, moduleAccAddr, amt) + _, err := k.AddCoins(ctx, moduleAccAddr, amt) if err != nil { return err } @@ -91,16 +89,11 @@ func (keeper BaseKeeper) DelegateCoins(ctx sdk.Context, delegatorAddr, moduleAcc // UndelegateCoins performs undelegation by crediting amt coins to an account with // address addr. For vesting accounts, undelegation amounts are tracked for both -// vesting and vested coins. -// The coins are then transferred from a ModuleAccount address to the delegator address. -// If any of the undelegation amounts are negative, an error is returned. -func (keeper BaseKeeper) UndelegateCoins(ctx sdk.Context, moduleAccAddr, delegatorAddr sdk.AccAddress, amt sdk.Coins) error { - delegatorAcc := keeper.ak.GetAccount(ctx, delegatorAddr) - if delegatorAcc == nil { - return sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "account %s does not exist", delegatorAddr) - } - - moduleAcc := keeper.ak.GetAccount(ctx, moduleAccAddr) +// vesting and vested coins. The coins are then transferred from a ModuleAccount +// address to the delegator address. If any of the undelegation amounts are +// negative, an error is returned. +func (k BaseKeeper) UndelegateCoins(ctx sdk.Context, moduleAccAddr, delegatorAddr sdk.AccAddress, amt sdk.Coins) error { + moduleAcc := k.ak.GetAccount(ctx, moduleAccAddr) if moduleAcc == nil { return sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", moduleAccAddr) } @@ -109,25 +102,20 @@ func (keeper BaseKeeper) UndelegateCoins(ctx sdk.Context, moduleAccAddr, delegat return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, amt.String()) } - oldCoins := moduleAcc.GetCoins() - - newCoins, hasNeg := oldCoins.SafeSub(amt) - if hasNeg { - return sdkerrors.Wrapf( - sdkerrors.ErrInsufficientFunds, "insufficient account funds; %s < %s", oldCoins, amt, - ) - } - - err := keeper.SetCoins(ctx, moduleAccAddr, newCoins) + _, err := k.SubtractCoins(ctx, moduleAccAddr, amt) if err != nil { return err } - if err := trackUndelegation(delegatorAcc, amt); err != nil { + if err := k.trackUndelegation(ctx, delegatorAddr, amt); err != nil { return sdkerrors.Wrap(err, "failed to track undelegation") } - keeper.ak.SetAccount(ctx, delegatorAcc) + _, err = k.AddCoins(ctx, delegatorAddr, amt) + if err != nil { + return err + } + return nil } @@ -141,7 +129,9 @@ type SendKeeper interface { SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, error) AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, error) - SetCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) error + + SetBalance(ctx sdk.Context, addr sdk.AccAddress, balance sdk.Coin) error + SetBalances(ctx sdk.Context, addr sdk.AccAddress, balances sdk.Coins) error GetSendEnabled(ctx sdk.Context) bool SetSendEnabled(ctx sdk.Context, enabled bool) @@ -156,28 +146,33 @@ var _ SendKeeper = (*BaseSendKeeper)(nil) type BaseSendKeeper struct { BaseViewKeeper + cdc *codec.Codec ak types.AccountKeeper + storeKey sdk.StoreKey paramSpace params.Subspace // list of addresses that are restricted from receiving transactions blacklistedAddrs map[string]bool } -// NewBaseSendKeeper returns a new BaseSendKeeper. func NewBaseSendKeeper( - ak types.AccountKeeper, paramSpace params.Subspace, blacklistedAddrs map[string]bool, + cdc *codec.Codec, storeKey sdk.StoreKey, ak types.AccountKeeper, paramSpace params.Subspace, blacklistedAddrs map[string]bool, ) BaseSendKeeper { return BaseSendKeeper{ - BaseViewKeeper: NewBaseViewKeeper(ak), + BaseViewKeeper: NewBaseViewKeeper(cdc, storeKey, ak), + cdc: cdc, ak: ak, + storeKey: storeKey, paramSpace: paramSpace, blacklistedAddrs: blacklistedAddrs, } } -// InputOutputCoins handles a list of inputs and outputs -func (keeper BaseSendKeeper) InputOutputCoins(ctx sdk.Context, inputs []types.Input, outputs []types.Output) error { +// InputOutputCoins performs multi-send functionality. It accepts a series of +// inputs that correspond to a series of outputs. It returns an error if the +// inputs and outputs don't lineup or if any single transfer of tokens fails. +func (k BaseSendKeeper) InputOutputCoins(ctx sdk.Context, inputs []types.Input, outputs []types.Output) error { // Safety check ensuring that when sending coins the keeper must maintain the // Check supply invariant and validity of Coins. if err := types.ValidateInputsOutputs(inputs, outputs); err != nil { @@ -185,7 +180,7 @@ func (keeper BaseSendKeeper) InputOutputCoins(ctx sdk.Context, inputs []types.In } for _, in := range inputs { - _, err := keeper.SubtractCoins(ctx, in.Address, in.Coins) + _, err := k.SubtractCoins(ctx, in.Address, in.Coins) if err != nil { return err } @@ -199,7 +194,7 @@ func (keeper BaseSendKeeper) InputOutputCoins(ctx sdk.Context, inputs []types.In } for _, out := range outputs { - _, err := keeper.AddCoins(ctx, out.Address, out.Coins) + _, err := k.AddCoins(ctx, out.Address, out.Coins) if err != nil { return err } @@ -216,8 +211,9 @@ func (keeper BaseSendKeeper) InputOutputCoins(ctx sdk.Context, inputs []types.In return nil } -// SendCoins moves coins from one account to another -func (keeper BaseSendKeeper) SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error { +// SendCoins transfers amt coins from a sending account to a receiving account. +// An error is returned upon failure. +func (k BaseSendKeeper) SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error { ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( types.EventTypeTransfer, @@ -230,12 +226,12 @@ func (keeper BaseSendKeeper) SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, ), }) - _, err := keeper.SubtractCoins(ctx, fromAddr, amt) + _, err := k.SubtractCoins(ctx, fromAddr, amt) if err != nil { return err } - _, err = keeper.AddCoins(ctx, toAddr, amt) + _, err = k.AddCoins(ctx, toAddr, amt) if err != nil { return err } @@ -243,92 +239,121 @@ func (keeper BaseSendKeeper) SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, return nil } -// SubtractCoins subtracts amt from the coins at the addr. -// -// CONTRACT: If the account is a vesting account, the amount has to be spendable. -func (keeper BaseSendKeeper) SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, error) { +// SubtractCoins removes amt coins the account by the given address. An error is +// returned if the resulting balance is negative or the initial amount is invalid. +func (k BaseSendKeeper) SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, error) { if !amt.IsValid() { return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, amt.String()) } - oldCoins, spendableCoins := sdk.NewCoins(), sdk.NewCoins() + resultCoins := sdk.NewCoins() + lockedCoins := k.LockedCoins(ctx, addr) - acc := keeper.ak.GetAccount(ctx, addr) - if acc != nil { - oldCoins = acc.GetCoins() - spendableCoins = acc.SpendableCoins(ctx.BlockHeader().Time) - } + for _, coin := range amt { + balance := k.GetBalance(ctx, addr, coin.Denom) + locked := sdk.NewCoin(coin.Denom, lockedCoins.AmountOf(coin.Denom)) + spendable := balance.Sub(locked) - // For non-vesting accounts, spendable coins will simply be the original coins. - // So the check here is sufficient instead of subtracting from oldCoins. - _, hasNeg := spendableCoins.SafeSub(amt) - if hasNeg { - return amt, sdkerrors.Wrapf( - sdkerrors.ErrInsufficientFunds, "insufficient account funds; %s < %s", spendableCoins, amt, - ) - } + _, hasNeg := sdk.Coins{spendable}.SafeSub(sdk.Coins{coin}) + if hasNeg { + return nil, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, "%s < %s", spendable, coin) + } + + newBalance := balance.Sub(coin) + resultCoins = resultCoins.Add(newBalance) - newCoins := oldCoins.Sub(amt) // should not panic as spendable coins was already checked - err := keeper.SetCoins(ctx, addr, newCoins) + k.SetBalance(ctx, addr, newBalance) + } - return newCoins, err + return resultCoins, nil } -// AddCoins adds amt to the coins at the addr. -func (keeper BaseSendKeeper) AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, error) { +// AddCoins adds amt to the account balance given by the provided address. An +// error is returned if the initial amount is invalid or if any resulting new +// balance is negative. +func (k BaseSendKeeper) AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, error) { if !amt.IsValid() { return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, amt.String()) } - oldCoins := keeper.GetCoins(ctx, addr) - newCoins := oldCoins.Add(amt...) + var resultCoins sdk.Coins - if newCoins.IsAnyNegative() { - return amt, sdkerrors.Wrapf( - sdkerrors.ErrInsufficientFunds, "insufficient account funds; %s < %s", oldCoins, amt, - ) + for _, coin := range amt { + balance := k.GetBalance(ctx, addr, coin.Denom) + newBalance := balance.Add(coin) + resultCoins = resultCoins.Add(newBalance) + + k.SetBalance(ctx, addr, newBalance) } - err := keeper.SetCoins(ctx, addr, newCoins) - return newCoins, err + return resultCoins, nil } -// SetCoins sets the coins at the addr. -func (keeper BaseSendKeeper) SetCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) error { - if !amt.IsValid() { - sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, amt.String()) +// ClearBalances removes all balances for a given account by address. +func (k BaseSendKeeper) ClearBalances(ctx sdk.Context, addr sdk.AccAddress) { + keys := [][]byte{} + k.IterateAccountBalances(ctx, addr, func(balance sdk.Coin) bool { + keys = append(keys, []byte(balance.Denom)) + return false + }) + + store := ctx.KVStore(k.storeKey) + balancesStore := prefix.NewStore(store, types.BalancesPrefix) + accountStore := prefix.NewStore(balancesStore, addr.Bytes()) + + for _, key := range keys { + accountStore.Delete(key) } +} - acc := keeper.ak.GetAccount(ctx, addr) - if acc == nil { - acc = keeper.ak.NewAccountWithAddress(ctx, addr) +// SetBalances sets the balance (multiple coins) for an account by address. It will +// clear out all balances prior to setting the new coins as to set existing balances +// to zero if they don't exist in amt. An error is returned upon failure. +func (k BaseSendKeeper) SetBalances(ctx sdk.Context, addr sdk.AccAddress, balances sdk.Coins) error { + k.ClearBalances(ctx, addr) + + for _, balance := range balances { + err := k.SetBalance(ctx, addr, balance) + if err != nil { + return err + } } - err := acc.SetCoins(amt) - if err != nil { - panic(err) + return nil +} + +// SetBalance sets the coin balance for an account by address. +func (k BaseSendKeeper) SetBalance(ctx sdk.Context, addr sdk.AccAddress, balance sdk.Coin) error { + if !balance.IsValid() { + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, balance.String()) } - keeper.ak.SetAccount(ctx, acc) + store := ctx.KVStore(k.storeKey) + balancesStore := prefix.NewStore(store, types.BalancesPrefix) + accountStore := prefix.NewStore(balancesStore, addr.Bytes()) + + bz := k.cdc.MustMarshalBinaryBare(balance) + accountStore.Set([]byte(balance.Denom), bz) + return nil } // GetSendEnabled returns the current SendEnabled -func (keeper BaseSendKeeper) GetSendEnabled(ctx sdk.Context) bool { +func (k BaseSendKeeper) GetSendEnabled(ctx sdk.Context) bool { var enabled bool - keeper.paramSpace.Get(ctx, types.ParamStoreKeySendEnabled, &enabled) + k.paramSpace.Get(ctx, types.ParamStoreKeySendEnabled, &enabled) return enabled } // SetSendEnabled sets the send enabled -func (keeper BaseSendKeeper) SetSendEnabled(ctx sdk.Context, enabled bool) { - keeper.paramSpace.Set(ctx, types.ParamStoreKeySendEnabled, &enabled) +func (k BaseSendKeeper) SetSendEnabled(ctx sdk.Context, enabled bool) { + k.paramSpace.Set(ctx, types.ParamStoreKeySendEnabled, &enabled) } // BlacklistedAddr checks if a given address is blacklisted (i.e restricted from // receiving funds) -func (keeper BaseSendKeeper) BlacklistedAddr(addr sdk.AccAddress) bool { - return keeper.blacklistedAddrs[addr.String()] +func (k BaseSendKeeper) BlacklistedAddr(addr sdk.AccAddress) bool { + return k.blacklistedAddrs[addr.String()] } var _ ViewKeeper = (*BaseViewKeeper)(nil) @@ -336,57 +361,203 @@ var _ ViewKeeper = (*BaseViewKeeper)(nil) // ViewKeeper defines a module interface that facilitates read only access to // account balances. type ViewKeeper interface { - GetCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins - HasCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) bool + ValidateBalance(ctx sdk.Context, addr sdk.AccAddress) error + HasBalance(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coin) bool + + GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin + + LockedCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + + IterateAccountBalances(ctx sdk.Context, addr sdk.AccAddress, cb func(coin sdk.Coin) (stop bool)) + IterateAllBalances(ctx sdk.Context, cb func(address sdk.AccAddress, coin sdk.Coin) (stop bool)) } // BaseViewKeeper implements a read only keeper implementation of ViewKeeper. type BaseViewKeeper struct { - ak types.AccountKeeper + cdc *codec.Codec + storeKey sdk.StoreKey + ak types.AccountKeeper } // NewBaseViewKeeper returns a new BaseViewKeeper. -func NewBaseViewKeeper(ak types.AccountKeeper) BaseViewKeeper { - return BaseViewKeeper{ak: ak} +func NewBaseViewKeeper(cdc *codec.Codec, storeKey sdk.StoreKey, ak types.AccountKeeper) BaseViewKeeper { + return BaseViewKeeper{ + cdc: cdc, + storeKey: storeKey, + ak: ak, + } } // Logger returns a module-specific logger. -func (keeper BaseViewKeeper) Logger(ctx sdk.Context) log.Logger { +func (k BaseViewKeeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) } -// GetCoins returns the coins at the addr. -func (keeper BaseViewKeeper) GetCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins { - acc := keeper.ak.GetAccount(ctx, addr) - if acc == nil { +// HasBalance returns whether or not an account has at least amt balance. +func (k BaseViewKeeper) HasBalance(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coin) bool { + return k.GetBalance(ctx, addr, amt.Denom).IsGTE(amt) +} + +// GetAllBalances returns all the account balances for the given account address. +func (k BaseViewKeeper) GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins { + balances := sdk.NewCoins() + k.IterateAccountBalances(ctx, addr, func(balance sdk.Coin) bool { + balances = balances.Add(balance) + return false + }) + + return balances.Sort() +} + +// GetBalance returns the balance of a specific denomination for a given account +// by address. +func (k BaseViewKeeper) GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin { + store := ctx.KVStore(k.storeKey) + balancesStore := prefix.NewStore(store, types.BalancesPrefix) + accountStore := prefix.NewStore(balancesStore, addr.Bytes()) + + bz := accountStore.Get([]byte(denom)) + if bz == nil { + return sdk.NewCoin(denom, sdk.ZeroInt()) + } + + var balance sdk.Coin + k.cdc.MustUnmarshalBinaryBare(bz, &balance) + + return balance +} + +// IterateAccountBalances iterates over the balances of a single account and +// provides the token balance to a callback. If true is returned from the +// callback, iteration is halted. +func (k BaseViewKeeper) IterateAccountBalances(ctx sdk.Context, addr sdk.AccAddress, cb func(sdk.Coin) bool) { + store := ctx.KVStore(k.storeKey) + balancesStore := prefix.NewStore(store, types.BalancesPrefix) + accountStore := prefix.NewStore(balancesStore, addr.Bytes()) + + iterator := accountStore.Iterator(nil, nil) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + var balance sdk.Coin + k.cdc.MustUnmarshalBinaryBare(iterator.Value(), &balance) + + if cb(balance) { + break + } + } +} + +// IterateAllBalances iterates over all the balances of all accounts and +// denominations that are provided to a callback. If true is returned from the +// callback, iteration is halted. +func (k BaseViewKeeper) IterateAllBalances(ctx sdk.Context, cb func(sdk.AccAddress, sdk.Coin) bool) { + store := ctx.KVStore(k.storeKey) + balancesStore := prefix.NewStore(store, types.BalancesPrefix) + + iterator := balancesStore.Iterator(nil, nil) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + address := types.AddressFromBalancesStore(iterator.Key()) + + var balance sdk.Coin + k.cdc.MustUnmarshalBinaryBare(iterator.Value(), &balance) + + if cb(address, balance) { + break + } + } +} + +// LockedCoins returns all the coins that are not spendable (i.e. locked) for an +// account by address. For standard accounts, the result will always be no coins. +// For vesting accounts, LockedCoins is delegated to the concrete vesting account +// type. +func (k BaseViewKeeper) LockedCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins { + acc := k.ak.GetAccount(ctx, addr) + if acc != nil { + vacc, ok := acc.(vestexported.VestingAccount) + if ok { + return vacc.LockedCoins(ctx.BlockTime()) + } + } + + return sdk.NewCoins() +} + +// SpendableCoins returns the total balances of spendable coins for an account +// by address. If the account has no spendable coins, an empty Coins slice is +// returned. +func (k BaseViewKeeper) SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins { + balances := k.GetAllBalances(ctx, addr) + locked := k.LockedCoins(ctx, addr) + + spendable, hasNeg := balances.SafeSub(locked) + if hasNeg { return sdk.NewCoins() } - return acc.GetCoins() + + return spendable } -// HasCoins returns whether or not an account has at least amt coins. -func (keeper BaseViewKeeper) HasCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) bool { - return keeper.GetCoins(ctx, addr).IsAllGTE(amt) +// ValidateBalance validates all balances for a given account address returning +// an error if any balance is invalid. It will check for vesting account types +// and validate the balances against the original vesting balances. +// +// CONTRACT: ValidateBalance should only be called upon genesis state. In the +// case of vesting accounts, balances may change in a valid manner that would +// otherwise yield an error from this call. +func (k BaseViewKeeper) ValidateBalance(ctx sdk.Context, addr sdk.AccAddress) error { + acc := k.ak.GetAccount(ctx, addr) + if acc == nil { + return sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "account %s does not exist", addr) + } + + balances := k.GetAllBalances(ctx, addr) + if !balances.IsValid() { + return fmt.Errorf("account balance of %s is invalid", balances) + } + + vacc, ok := acc.(vestexported.VestingAccount) + if ok { + ogv := vacc.GetOriginalVesting() + if ogv.IsAnyGT(balances) { + return fmt.Errorf("vesting amount %s cannot be greater than total amount %s", ogv, balances) + } + } + + return nil } -// CONTRACT: assumes that amt is valid. -func trackDelegation(acc authexported.Account, blockTime time.Time, amt sdk.Coins) error { +func (k BaseKeeper) trackDelegation(ctx sdk.Context, addr sdk.AccAddress, blockTime time.Time, balance, amt sdk.Coins) error { + acc := k.ak.GetAccount(ctx, addr) + if acc == nil { + return sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "account %s does not exist", addr) + } + vacc, ok := acc.(vestexported.VestingAccount) if ok { // TODO: return error on account.TrackDelegation - vacc.TrackDelegation(blockTime, amt) + vacc.TrackDelegation(blockTime, balance, amt) } - return acc.SetCoins(acc.GetCoins().Sub(amt)) + return nil } -// CONTRACT: assumes that amt is valid. -func trackUndelegation(acc authexported.Account, amt sdk.Coins) error { +func (k BaseKeeper) trackUndelegation(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) error { + acc := k.ak.GetAccount(ctx, addr) + if acc == nil { + return sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "account %s does not exist", addr) + } + vacc, ok := acc.(vestexported.VestingAccount) if ok { // TODO: return error on account.TrackUndelegation vacc.TrackUndelegation(amt) } - return acc.SetCoins(acc.GetCoins().Add(amt...)) + return nil } diff --git a/x/bank/internal/keeper/keeper_test.go b/x/bank/internal/keeper/keeper_test.go index 6b6f3cd4048f..8f2eab8138d8 100644 --- a/x/bank/internal/keeper/keeper_test.go +++ b/x/bank/internal/keeper/keeper_test.go @@ -4,7 +4,7 @@ import ( "testing" "time" - "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" abci "github.com/tendermint/tendermint/abci/types" tmkv "github.com/tendermint/tendermint/libs/kv" tmtime "github.com/tendermint/tendermint/types/time" @@ -13,189 +13,248 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/auth/vesting" - keep "github.com/cosmos/cosmos-sdk/x/bank/internal/keeper" "github.com/cosmos/cosmos-sdk/x/bank/internal/types" - "github.com/cosmos/cosmos-sdk/x/supply" ) -func TestKeeper(t *testing.T) { - app, ctx := createTestApp(false) - - addr := sdk.AccAddress([]byte("addr1")) - addr2 := sdk.AccAddress([]byte("addr2")) - addr3 := sdk.AccAddress([]byte("addr3")) - acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr) - - // Test GetCoins/SetCoins - app.AccountKeeper.SetAccount(ctx, acc) - require.True(t, app.BankKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins())) +const ( + fooDenom = "foo" + barDenom = "bar" +) - app.BankKeeper.SetCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10))) - require.True(t, app.BankKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10)))) +func newFooCoin(amt int64) sdk.Coin { + return sdk.NewInt64Coin(fooDenom, amt) +} - // Test HasCoins - require.True(t, app.BankKeeper.HasCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10)))) - require.True(t, app.BankKeeper.HasCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 5)))) - require.False(t, app.BankKeeper.HasCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 15)))) - require.False(t, app.BankKeeper.HasCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 5)))) +func newBarCoin(amt int64) sdk.Coin { + return sdk.NewInt64Coin(barDenom, amt) +} - // Test AddCoins - app.BankKeeper.AddCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 15))) - require.True(t, app.BankKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 25)))) +type IntegrationTestSuite struct { + suite.Suite - app.BankKeeper.AddCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 15))) - require.True(t, app.BankKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 15), sdk.NewInt64Coin("foocoin", 25)))) + app *simapp.SimApp + ctx sdk.Context +} - // Test SubtractCoins - app.BankKeeper.SubtractCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10))) - app.BankKeeper.SubtractCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 5))) - require.True(t, app.BankKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 10), sdk.NewInt64Coin("foocoin", 15)))) +func (suite *IntegrationTestSuite) SetupTest() { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) - app.BankKeeper.SubtractCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 11))) - require.True(t, app.BankKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 10), sdk.NewInt64Coin("foocoin", 15)))) + app.AccountKeeper.SetParams(ctx, auth.DefaultParams()) + app.BankKeeper.SetSendEnabled(ctx, true) - app.BankKeeper.SubtractCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 10))) - require.True(t, app.BankKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 15)))) - require.False(t, app.BankKeeper.HasCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 1)))) + suite.app = app + suite.ctx = ctx +} - // Test SendCoins - app.BankKeeper.SendCoins(ctx, addr, addr2, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 5))) - require.True(t, app.BankKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10)))) - require.True(t, app.BankKeeper.GetCoins(ctx, addr2).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 5)))) +func (suite *IntegrationTestSuite) TestInputOutputCoins() { + app, ctx := suite.app, suite.ctx + balances := sdk.NewCoins(newFooCoin(90), newBarCoin(30)) - app.BankKeeper.SendCoins(ctx, addr, addr2, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 50))) - require.True(t, app.BankKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10)))) - require.True(t, app.BankKeeper.GetCoins(ctx, addr2).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 5)))) + addr1 := sdk.AccAddress([]byte("addr1")) + acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) + app.AccountKeeper.SetAccount(ctx, acc1) - app.BankKeeper.AddCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 30))) - app.BankKeeper.SendCoins(ctx, addr, addr2, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 10), sdk.NewInt64Coin("foocoin", 5))) - require.True(t, app.BankKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 20), sdk.NewInt64Coin("foocoin", 5)))) - require.True(t, app.BankKeeper.GetCoins(ctx, addr2).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 10), sdk.NewInt64Coin("foocoin", 10)))) + addr2 := sdk.AccAddress([]byte("addr2")) + acc2 := app.AccountKeeper.NewAccountWithAddress(ctx, addr2) + app.AccountKeeper.SetAccount(ctx, acc2) - // Test InputOutputCoins - input1 := types.NewInput(addr2, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 2))) - output1 := types.NewOutput(addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 2))) - app.BankKeeper.InputOutputCoins(ctx, []types.Input{input1}, []types.Output{output1}) - require.True(t, app.BankKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 20), sdk.NewInt64Coin("foocoin", 7)))) - require.True(t, app.BankKeeper.GetCoins(ctx, addr2).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 10), sdk.NewInt64Coin("foocoin", 8)))) + addr3 := sdk.AccAddress([]byte("addr3")) + acc3 := app.AccountKeeper.NewAccountWithAddress(ctx, addr3) + app.AccountKeeper.SetAccount(ctx, acc3) inputs := []types.Input{ - types.NewInput(addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 3))), - types.NewInput(addr2, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 3), sdk.NewInt64Coin("foocoin", 2))), + {Address: addr1, Coins: sdk.NewCoins(newFooCoin(30), newBarCoin(10))}, + {Address: addr1, Coins: sdk.NewCoins(newFooCoin(30), newBarCoin(10))}, } - outputs := []types.Output{ - types.NewOutput(addr, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 1))), - types.NewOutput(addr3, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 2), sdk.NewInt64Coin("foocoin", 5))), + {Address: addr2, Coins: sdk.NewCoins(newFooCoin(30), newBarCoin(10))}, + {Address: addr3, Coins: sdk.NewCoins(newFooCoin(30), newBarCoin(10))}, } - app.BankKeeper.InputOutputCoins(ctx, inputs, outputs) - require.True(t, app.BankKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 21), sdk.NewInt64Coin("foocoin", 4)))) - require.True(t, app.BankKeeper.GetCoins(ctx, addr2).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 7), sdk.NewInt64Coin("foocoin", 6)))) - require.True(t, app.BankKeeper.GetCoins(ctx, addr3).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 2), sdk.NewInt64Coin("foocoin", 5)))) - - // Test retrieving black listed accounts - for acc := range simapp.GetMaccPerms() { - addr := supply.NewModuleAddress(acc) - require.Equal(t, app.BlacklistedAccAddrs()[addr.String()], app.BankKeeper.BlacklistedAddr(addr)) + + suite.Require().Error(app.BankKeeper.InputOutputCoins(ctx, inputs, []types.Output{})) + suite.Require().Error(app.BankKeeper.InputOutputCoins(ctx, inputs, outputs)) + + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, balances)) + + insufficientInputs := []types.Input{ + {Address: addr1, Coins: sdk.NewCoins(newFooCoin(300), newBarCoin(100))}, + {Address: addr1, Coins: sdk.NewCoins(newFooCoin(300), newBarCoin(100))}, } + insufficientOutputs := []types.Output{ + {Address: addr2, Coins: sdk.NewCoins(newFooCoin(300), newBarCoin(100))}, + {Address: addr3, Coins: sdk.NewCoins(newFooCoin(300), newBarCoin(100))}, + } + suite.Require().Error(app.BankKeeper.InputOutputCoins(ctx, insufficientInputs, insufficientOutputs)) + suite.Require().NoError(app.BankKeeper.InputOutputCoins(ctx, inputs, outputs)) + + acc1Balances := app.BankKeeper.GetAllBalances(ctx, addr1) + expected := sdk.NewCoins(newFooCoin(30), newBarCoin(10)) + suite.Require().Equal(expected, acc1Balances) + + acc2Balances := app.BankKeeper.GetAllBalances(ctx, addr2) + suite.Require().Equal(expected, acc2Balances) + + acc3Balances := app.BankKeeper.GetAllBalances(ctx, addr3) + suite.Require().Equal(expected, acc3Balances) } -func TestSendKeeper(t *testing.T) { - app, ctx := createTestApp(false) +func (suite *IntegrationTestSuite) TestSendCoins() { + app, ctx := suite.app, suite.ctx + balances := sdk.NewCoins(newFooCoin(100), newBarCoin(50)) - blacklistedAddrs := make(map[string]bool) + addr1 := sdk.AccAddress([]byte("addr1")) + acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) + app.AccountKeeper.SetAccount(ctx, acc1) - paramSpace := app.ParamsKeeper.Subspace("newspace") - sendKeeper := keep.NewBaseSendKeeper(app.AccountKeeper, paramSpace, blacklistedAddrs) - app.BankKeeper.SetSendEnabled(ctx, true) + addr2 := sdk.AccAddress([]byte("addr2")) + acc2 := app.AccountKeeper.NewAccountWithAddress(ctx, addr2) + app.AccountKeeper.SetAccount(ctx, acc2) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr2, balances)) - addr := sdk.AccAddress([]byte("addr1")) + sendAmt := sdk.NewCoins(newFooCoin(50), newBarCoin(25)) + suite.Require().Error(app.BankKeeper.SendCoins(ctx, addr1, addr2, sendAmt)) + + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, balances)) + suite.Require().NoError(app.BankKeeper.SendCoins(ctx, addr1, addr2, sendAmt)) + + acc1Balances := app.BankKeeper.GetAllBalances(ctx, addr1) + expected := sdk.NewCoins(newFooCoin(50), newBarCoin(25)) + suite.Require().Equal(expected, acc1Balances) + + acc2Balances := app.BankKeeper.GetAllBalances(ctx, addr2) + expected = sdk.NewCoins(newFooCoin(150), newBarCoin(75)) + suite.Require().Equal(expected, acc2Balances) +} + +func (suite *IntegrationTestSuite) TestValidateBalance() { + app, ctx := suite.app, suite.ctx + now := tmtime.Now() + ctx = ctx.WithBlockHeader(abci.Header{Time: now}) + endTime := now.Add(24 * time.Hour) + + addr1 := sdk.AccAddress([]byte("addr1")) addr2 := sdk.AccAddress([]byte("addr2")) - acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr) - // Test GetCoins/SetCoins + suite.Require().Error(app.BankKeeper.ValidateBalance(ctx, addr1)) + + acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) app.AccountKeeper.SetAccount(ctx, acc) - require.True(t, sendKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins())) - - app.BankKeeper.SetCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10))) - require.True(t, sendKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10)))) - - // Test HasCoins - require.True(t, sendKeeper.HasCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10)))) - require.True(t, sendKeeper.HasCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 5)))) - require.False(t, sendKeeper.HasCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 15)))) - require.False(t, sendKeeper.HasCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 5)))) - - app.BankKeeper.SetCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 15))) - - // Test SendCoins - sendKeeper.SendCoins(ctx, addr, addr2, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 5))) - require.True(t, sendKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10)))) - require.True(t, sendKeeper.GetCoins(ctx, addr2).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 5)))) - - sendKeeper.SendCoins(ctx, addr, addr2, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 50))) - require.True(t, sendKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10)))) - require.True(t, sendKeeper.GetCoins(ctx, addr2).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 5)))) - - app.BankKeeper.AddCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 30))) - sendKeeper.SendCoins(ctx, addr, addr2, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 10), sdk.NewInt64Coin("foocoin", 5))) - require.True(t, sendKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 20), sdk.NewInt64Coin("foocoin", 5)))) - require.True(t, sendKeeper.GetCoins(ctx, addr2).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 10), sdk.NewInt64Coin("foocoin", 10)))) - - // validate coins with invalid denoms or negative values cannot be sent - // NOTE: We must use the Coin literal as the constructor does not allow - // negative values. - err := sendKeeper.SendCoins(ctx, addr, addr2, sdk.Coins{sdk.Coin{Denom: "FOOCOIN", Amount: sdk.NewInt(-5)}}) - require.Error(t, err) + + balances := sdk.NewCoins(newFooCoin(100)) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, balances)) + suite.Require().NoError(app.BankKeeper.ValidateBalance(ctx, addr1)) + + bacc := auth.NewBaseAccountWithAddress(addr2) + vacc := vesting.NewContinuousVestingAccount(&bacc, balances.Add(balances...), now.Unix(), endTime.Unix()) + + app.AccountKeeper.SetAccount(ctx, vacc) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr2, balances)) + suite.Require().Error(app.BankKeeper.ValidateBalance(ctx, addr2)) } -func TestMsgSendEvents(t *testing.T) { - app, ctx := createTestApp(false) +func (suite *IntegrationTestSuite) TestBalance() { + app, ctx := suite.app, suite.ctx + addr := sdk.AccAddress([]byte("addr1")) - app.BankKeeper.SetSendEnabled(ctx, true) + acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr) + app.AccountKeeper.SetAccount(ctx, acc) + + suite.Require().Equal(sdk.NewCoin(fooDenom, sdk.ZeroInt()), app.BankKeeper.GetBalance(ctx, addr, fooDenom)) + balances := sdk.NewCoins(newFooCoin(100)) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr, balances)) + + suite.Require().Equal(balances.AmountOf(fooDenom), app.BankKeeper.GetBalance(ctx, addr, fooDenom).Amount) + suite.Require().Equal(balances, app.BankKeeper.GetAllBalances(ctx, addr)) + + newFooBalance := newFooCoin(99) + suite.Require().NoError(app.BankKeeper.SetBalance(ctx, addr, newFooBalance)) + suite.Require().Equal(newFooBalance, app.BankKeeper.GetBalance(ctx, addr, fooDenom)) + + balances = sdk.NewCoins(newBarCoin(500)) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr, balances)) + suite.Require().Equal(sdk.NewCoin(fooDenom, sdk.ZeroInt()), app.BankKeeper.GetBalance(ctx, addr, fooDenom)) + suite.Require().Equal(balances.AmountOf(barDenom), app.BankKeeper.GetBalance(ctx, addr, barDenom).Amount) + suite.Require().Equal(balances, app.BankKeeper.GetAllBalances(ctx, addr)) + invalidBalance := sdk.Coin{Denom: "fooDenom", Amount: sdk.NewInt(-50)} + suite.Require().Error(app.BankKeeper.SetBalance(ctx, addr, invalidBalance)) +} + +func (suite *IntegrationTestSuite) TestSendEnabled() { + app, ctx := suite.app, suite.ctx + enabled := false + app.BankKeeper.SetSendEnabled(ctx, enabled) + suite.Require().Equal(enabled, app.BankKeeper.GetSendEnabled(ctx)) +} + +func (suite *IntegrationTestSuite) TestHasBalance() { + app, ctx := suite.app, suite.ctx + addr := sdk.AccAddress([]byte("addr1")) + + acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr) + app.AccountKeeper.SetAccount(ctx, acc) + + balances := sdk.NewCoins(newFooCoin(100)) + suite.Require().False(app.BankKeeper.HasBalance(ctx, addr, newFooCoin(99))) + + app.BankKeeper.SetBalances(ctx, addr, balances) + suite.Require().False(app.BankKeeper.HasBalance(ctx, addr, newFooCoin(101))) + suite.Require().True(app.BankKeeper.HasBalance(ctx, addr, newFooCoin(100))) + suite.Require().True(app.BankKeeper.HasBalance(ctx, addr, newFooCoin(1))) +} + +func (suite *IntegrationTestSuite) TestMsgSendEvents() { + app, ctx := suite.app, suite.ctx addr := sdk.AccAddress([]byte("addr1")) addr2 := sdk.AccAddress([]byte("addr2")) acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr) app.AccountKeeper.SetAccount(ctx, acc) - newCoins := sdk.NewCoins(sdk.NewInt64Coin("foocoin", 50)) - err := app.BankKeeper.SendCoins(ctx, addr, addr2, newCoins) - require.Error(t, err) + newCoins := sdk.NewCoins(sdk.NewInt64Coin(fooDenom, 50)) + + suite.Require().Error(app.BankKeeper.SendCoins(ctx, addr, addr2, newCoins)) + events := ctx.EventManager().Events() - require.Equal(t, 2, len(events)) + suite.Require().Equal(2, len(events)) + event1 := sdk.Event{ Type: types.EventTypeTransfer, Attributes: []tmkv.Pair{}, } event1.Attributes = append( event1.Attributes, - tmkv.Pair{Key: []byte(types.AttributeKeyRecipient), Value: []byte(addr2.String())}) + tmkv.Pair{Key: []byte(types.AttributeKeyRecipient), Value: []byte(addr2.String())}, + ) event1.Attributes = append( event1.Attributes, - tmkv.Pair{Key: []byte(sdk.AttributeKeyAmount), Value: []byte(newCoins.String())}) + tmkv.Pair{Key: []byte(sdk.AttributeKeyAmount), Value: []byte(newCoins.String())}, + ) event2 := sdk.Event{ Type: sdk.EventTypeMessage, Attributes: []tmkv.Pair{}, } event2.Attributes = append( event2.Attributes, - tmkv.Pair{Key: []byte(types.AttributeKeySender), Value: []byte(addr.String())}) - require.Equal(t, event1, events[0]) - require.Equal(t, event2, events[1]) - - app.BankKeeper.SetCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 50))) - newCoins = sdk.NewCoins(sdk.NewInt64Coin("foocoin", 50)) - err = app.BankKeeper.SendCoins(ctx, addr, addr2, newCoins) - require.NoError(t, err) + tmkv.Pair{Key: []byte(types.AttributeKeySender), Value: []byte(addr.String())}, + ) + + suite.Require().Equal(event1, events[0]) + suite.Require().Equal(event2, events[1]) + + app.BankKeeper.SetBalances(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin(fooDenom, 50))) + newCoins = sdk.NewCoins(sdk.NewInt64Coin(fooDenom, 50)) + + suite.Require().NoError(app.BankKeeper.SendCoins(ctx, addr, addr2, newCoins)) + events = ctx.EventManager().Events() - require.Equal(t, 4, len(events)) - require.Equal(t, event1, events[2]) - require.Equal(t, event2, events[3]) + suite.Require().Equal(4, len(events)) + suite.Require().Equal(event1, events[2]) + suite.Require().Equal(event2, events[3]) } -func TestMsgMultiSendEvents(t *testing.T) { - app, ctx := createTestApp(false) +func (suite *IntegrationTestSuite) TestMsgMultiSendEvents() { + app, ctx := suite.app, suite.ctx app.BankKeeper.SetSendEnabled(ctx, true) @@ -208,8 +267,9 @@ func TestMsgMultiSendEvents(t *testing.T) { app.AccountKeeper.SetAccount(ctx, acc) app.AccountKeeper.SetAccount(ctx, acc2) - newCoins := sdk.NewCoins(sdk.NewInt64Coin("foocoin", 50)) - newCoins2 := sdk.NewCoins(sdk.NewInt64Coin("barcoin", 100)) + + newCoins := sdk.NewCoins(sdk.NewInt64Coin(fooDenom, 50)) + newCoins2 := sdk.NewCoins(sdk.NewInt64Coin(barDenom, 100)) inputs := []types.Input{ {Address: addr, Coins: newCoins}, {Address: addr2, Coins: newCoins2}, @@ -218,51 +278,58 @@ func TestMsgMultiSendEvents(t *testing.T) { {Address: addr3, Coins: newCoins}, {Address: addr4, Coins: newCoins2}, } - err := app.BankKeeper.InputOutputCoins(ctx, inputs, outputs) - require.Error(t, err) + + suite.Require().Error(app.BankKeeper.InputOutputCoins(ctx, inputs, outputs)) + events := ctx.EventManager().Events() - require.Equal(t, 0, len(events)) + suite.Require().Equal(0, len(events)) // Set addr's coins but not addr2's coins - app.BankKeeper.SetCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 50))) + app.BankKeeper.SetBalances(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin(fooDenom, 50))) + + suite.Require().Error(app.BankKeeper.InputOutputCoins(ctx, inputs, outputs)) - err = app.BankKeeper.InputOutputCoins(ctx, inputs, outputs) - require.Error(t, err) events = ctx.EventManager().Events() - require.Equal(t, 1, len(events)) + suite.Require().Equal(1, len(events)) + event1 := sdk.Event{ Type: sdk.EventTypeMessage, Attributes: []tmkv.Pair{}, } event1.Attributes = append( event1.Attributes, - tmkv.Pair{Key: []byte(types.AttributeKeySender), Value: []byte(addr.String())}) - require.Equal(t, event1, events[0]) + tmkv.Pair{Key: []byte(types.AttributeKeySender), Value: []byte(addr.String())}, + ) + suite.Require().Equal(event1, events[0]) // Set addr's coins and addr2's coins - app.BankKeeper.SetCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 50))) - newCoins = sdk.NewCoins(sdk.NewInt64Coin("foocoin", 50)) - app.BankKeeper.SetCoins(ctx, addr2, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 100))) - newCoins2 = sdk.NewCoins(sdk.NewInt64Coin("barcoin", 100)) + app.BankKeeper.SetBalances(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin(fooDenom, 50))) + newCoins = sdk.NewCoins(sdk.NewInt64Coin(fooDenom, 50)) + + app.BankKeeper.SetBalances(ctx, addr2, sdk.NewCoins(sdk.NewInt64Coin(barDenom, 100))) + newCoins2 = sdk.NewCoins(sdk.NewInt64Coin(barDenom, 100)) + + suite.Require().NoError(app.BankKeeper.InputOutputCoins(ctx, inputs, outputs)) - err = app.BankKeeper.InputOutputCoins(ctx, inputs, outputs) - require.NoError(t, err) events = ctx.EventManager().Events() - require.Equal(t, 5, len(events)) + suite.Require().Equal(5, len(events)) + event2 := sdk.Event{ Type: sdk.EventTypeMessage, Attributes: []tmkv.Pair{}, } event2.Attributes = append( event2.Attributes, - tmkv.Pair{Key: []byte(types.AttributeKeySender), Value: []byte(addr2.String())}) + tmkv.Pair{Key: []byte(types.AttributeKeySender), Value: []byte(addr2.String())}, + ) event3 := sdk.Event{ Type: types.EventTypeTransfer, Attributes: []tmkv.Pair{}, } event3.Attributes = append( event3.Attributes, - tmkv.Pair{Key: []byte(types.AttributeKeyRecipient), Value: []byte(addr3.String())}) + tmkv.Pair{Key: []byte(types.AttributeKeyRecipient), Value: []byte(addr3.String())}, + ) event3.Attributes = append( event3.Attributes, tmkv.Pair{Key: []byte(sdk.AttributeKeyAmount), Value: []byte(newCoins.String())}) @@ -272,41 +339,52 @@ func TestMsgMultiSendEvents(t *testing.T) { } event4.Attributes = append( event4.Attributes, - tmkv.Pair{Key: []byte(types.AttributeKeyRecipient), Value: []byte(addr4.String())}) + tmkv.Pair{Key: []byte(types.AttributeKeyRecipient), Value: []byte(addr4.String())}, + ) event4.Attributes = append( event4.Attributes, - tmkv.Pair{Key: []byte(sdk.AttributeKeyAmount), Value: []byte(newCoins2.String())}) - require.Equal(t, event1, events[1]) - require.Equal(t, event2, events[2]) - require.Equal(t, event3, events[3]) - require.Equal(t, event4, events[4]) + tmkv.Pair{Key: []byte(sdk.AttributeKeyAmount), Value: []byte(newCoins2.String())}, + ) + + suite.Require().Equal(event1, events[1]) + suite.Require().Equal(event2, events[2]) + suite.Require().Equal(event3, events[3]) + suite.Require().Equal(event4, events[4]) } -func TestViewKeeper(t *testing.T) { - app, ctx := createTestApp(false) +func (suite *IntegrationTestSuite) TestSpendableCoins() { + app, ctx := suite.app, suite.ctx + now := tmtime.Now() + ctx = ctx.WithBlockHeader(abci.Header{Time: now}) + endTime := now.Add(24 * time.Hour) - //paramSpace := app.ParamsKeeper.Subspace(types.DefaultParamspace) - viewKeeper := keep.NewBaseViewKeeper(app.AccountKeeper) + origCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 100)) + delCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 50)) - addr := sdk.AccAddress([]byte("addr1")) - acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr) + addr1 := sdk.AccAddress([]byte("addr1")) + addr2 := sdk.AccAddress([]byte("addr2")) + addrModule := sdk.AccAddress([]byte("moduleAcc")) + + macc := app.AccountKeeper.NewAccountWithAddress(ctx, addrModule) + bacc := auth.NewBaseAccountWithAddress(addr1) + vacc := vesting.NewContinuousVestingAccount(&bacc, origCoins, ctx.BlockHeader().Time.Unix(), endTime.Unix()) + acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr2) - // Test GetCoins/SetCoins + app.AccountKeeper.SetAccount(ctx, macc) + app.AccountKeeper.SetAccount(ctx, vacc) app.AccountKeeper.SetAccount(ctx, acc) - require.True(t, viewKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins())) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, origCoins)) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr2, origCoins)) - app.BankKeeper.SetCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10))) - require.True(t, viewKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10)))) + suite.Require().Equal(origCoins, app.BankKeeper.SpendableCoins(ctx, addr2)) - // Test HasCoins - require.True(t, viewKeeper.HasCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10)))) - require.True(t, viewKeeper.HasCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 5)))) - require.False(t, viewKeeper.HasCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 15)))) - require.False(t, viewKeeper.HasCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 5)))) + ctx = ctx.WithBlockTime(now.Add(12 * time.Hour)) + suite.Require().NoError(app.BankKeeper.DelegateCoins(ctx, addr2, addrModule, delCoins)) + suite.Require().Equal(origCoins.Sub(delCoins), app.BankKeeper.SpendableCoins(ctx, addr1)) } -func TestVestingAccountSend(t *testing.T) { - app, ctx := createTestApp(false) +func (suite *IntegrationTestSuite) TestVestingAccountSend() { + app, ctx := suite.app, suite.ctx now := tmtime.Now() ctx = ctx.WithBlockHeader(abci.Header{Time: now}) endTime := now.Add(24 * time.Hour) @@ -316,29 +394,27 @@ func TestVestingAccountSend(t *testing.T) { addr1 := sdk.AccAddress([]byte("addr1")) addr2 := sdk.AccAddress([]byte("addr2")) + bacc := auth.NewBaseAccountWithAddress(addr1) - bacc.SetCoins(origCoins) - vacc := vesting.NewContinuousVestingAccount(&bacc, ctx.BlockHeader().Time.Unix(), endTime.Unix()) + vacc := vesting.NewContinuousVestingAccount(&bacc, origCoins, now.Unix(), endTime.Unix()) + app.AccountKeeper.SetAccount(ctx, vacc) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, origCoins)) // require that no coins be sendable at the beginning of the vesting schedule - err := app.BankKeeper.SendCoins(ctx, addr1, addr2, sendCoins) - require.Error(t, err) + suite.Require().Error(app.BankKeeper.SendCoins(ctx, addr1, addr2, sendCoins)) // receive some coins - vacc.SetCoins(origCoins.Add(sendCoins...)) - app.AccountKeeper.SetAccount(ctx, vacc) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, origCoins.Add(sendCoins...))) // require that all vested coins are spendable plus any received ctx = ctx.WithBlockTime(now.Add(12 * time.Hour)) - err = app.BankKeeper.SendCoins(ctx, addr1, addr2, sendCoins) - vacc = app.AccountKeeper.GetAccount(ctx, addr1).(*vesting.ContinuousVestingAccount) - require.NoError(t, err) - require.Equal(t, origCoins, vacc.GetCoins()) + suite.Require().NoError(app.BankKeeper.SendCoins(ctx, addr1, addr2, sendCoins)) + suite.Require().Equal(origCoins, app.BankKeeper.GetAllBalances(ctx, addr1)) } -func TestPeriodicVestingAccountSend(t *testing.T) { - app, ctx := createTestApp(false) +func (suite *IntegrationTestSuite) TestPeriodicVestingAccountSend() { + app, ctx := suite.app, suite.ctx now := tmtime.Now() ctx = ctx.WithBlockHeader(abci.Header{Time: now}) origCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 100)) @@ -346,34 +422,32 @@ func TestPeriodicVestingAccountSend(t *testing.T) { addr1 := sdk.AccAddress([]byte("addr1")) addr2 := sdk.AccAddress([]byte("addr2")) - bacc := auth.NewBaseAccountWithAddress(addr1) - bacc.SetCoins(origCoins) periods := vesting.Periods{ vesting.Period{Length: int64(12 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin("stake", 50)}}, vesting.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin("stake", 25)}}, vesting.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin("stake", 25)}}, } - vacc := vesting.NewPeriodicVestingAccount(&bacc, ctx.BlockHeader().Time.Unix(), periods) + + bacc := auth.NewBaseAccountWithAddress(addr1) + vacc := vesting.NewPeriodicVestingAccount(&bacc, origCoins, ctx.BlockHeader().Time.Unix(), periods) + app.AccountKeeper.SetAccount(ctx, vacc) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, origCoins)) // require that no coins be sendable at the beginning of the vesting schedule - err := app.BankKeeper.SendCoins(ctx, addr1, addr2, sendCoins) - require.Error(t, err) + suite.Require().Error(app.BankKeeper.SendCoins(ctx, addr1, addr2, sendCoins)) // receive some coins - vacc.SetCoins(origCoins.Add(sendCoins...)) - app.AccountKeeper.SetAccount(ctx, vacc) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, origCoins.Add(sendCoins...))) // require that all vested coins are spendable plus any received ctx = ctx.WithBlockTime(now.Add(12 * time.Hour)) - err = app.BankKeeper.SendCoins(ctx, addr1, addr2, sendCoins) - vacc = app.AccountKeeper.GetAccount(ctx, addr1).(*vesting.PeriodicVestingAccount) - require.NoError(t, err) - require.Equal(t, origCoins, vacc.GetCoins()) + suite.Require().NoError(app.BankKeeper.SendCoins(ctx, addr1, addr2, sendCoins)) + suite.Require().Equal(origCoins, app.BankKeeper.GetAllBalances(ctx, addr1)) } -func TestVestingAccountReceive(t *testing.T) { - app, ctx := createTestApp(false) +func (suite *IntegrationTestSuite) TestVestingAccountReceive() { + app, ctx := suite.app, suite.ctx now := tmtime.Now() ctx = ctx.WithBlockHeader(abci.Header{Time: now}) endTime := now.Add(24 * time.Hour) @@ -385,27 +459,29 @@ func TestVestingAccountReceive(t *testing.T) { addr2 := sdk.AccAddress([]byte("addr2")) bacc := auth.NewBaseAccountWithAddress(addr1) - bacc.SetCoins(origCoins) - vacc := vesting.NewContinuousVestingAccount(&bacc, ctx.BlockHeader().Time.Unix(), endTime.Unix()) + vacc := vesting.NewContinuousVestingAccount(&bacc, origCoins, ctx.BlockHeader().Time.Unix(), endTime.Unix()) acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr2) + app.AccountKeeper.SetAccount(ctx, vacc) app.AccountKeeper.SetAccount(ctx, acc) - app.BankKeeper.SetCoins(ctx, addr2, origCoins) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, origCoins)) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr2, origCoins)) // send some coins to the vesting account - app.BankKeeper.SendCoins(ctx, addr2, addr1, sendCoins) + suite.Require().NoError(app.BankKeeper.SendCoins(ctx, addr2, addr1, sendCoins)) // require the coins are spendable vacc = app.AccountKeeper.GetAccount(ctx, addr1).(*vesting.ContinuousVestingAccount) - require.Equal(t, origCoins.Add(sendCoins...), vacc.GetCoins()) - require.Equal(t, vacc.SpendableCoins(now), sendCoins) + balances := app.BankKeeper.GetAllBalances(ctx, addr1) + suite.Require().Equal(origCoins.Add(sendCoins...), balances) + suite.Require().Equal(balances.Sub(vacc.LockedCoins(now)), sendCoins) // require coins are spendable plus any that have vested - require.Equal(t, vacc.SpendableCoins(now.Add(12*time.Hour)), origCoins) + suite.Require().Equal(balances.Sub(vacc.LockedCoins(now.Add(12*time.Hour))), origCoins) } -func TestPeriodicVestingAccountReceive(t *testing.T) { - app, ctx := createTestApp(false) +func (suite *IntegrationTestSuite) TestPeriodicVestingAccountReceive() { + app, ctx := suite.app, suite.ctx now := tmtime.Now() ctx = ctx.WithBlockHeader(abci.Header{Time: now}) @@ -416,36 +492,38 @@ func TestPeriodicVestingAccountReceive(t *testing.T) { addr2 := sdk.AccAddress([]byte("addr2")) bacc := auth.NewBaseAccountWithAddress(addr1) - bacc.SetCoins(origCoins) periods := vesting.Periods{ vesting.Period{Length: int64(12 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin("stake", 50)}}, vesting.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin("stake", 25)}}, vesting.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin("stake", 25)}}, } - vacc := vesting.NewPeriodicVestingAccount(&bacc, ctx.BlockHeader().Time.Unix(), periods) + + vacc := vesting.NewPeriodicVestingAccount(&bacc, origCoins, ctx.BlockHeader().Time.Unix(), periods) acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr2) + app.AccountKeeper.SetAccount(ctx, vacc) app.AccountKeeper.SetAccount(ctx, acc) - app.BankKeeper.SetCoins(ctx, addr2, origCoins) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, origCoins)) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr2, origCoins)) // send some coins to the vesting account - app.BankKeeper.SendCoins(ctx, addr2, addr1, sendCoins) + suite.Require().NoError(app.BankKeeper.SendCoins(ctx, addr2, addr1, sendCoins)) // require the coins are spendable vacc = app.AccountKeeper.GetAccount(ctx, addr1).(*vesting.PeriodicVestingAccount) - require.Equal(t, origCoins.Add(sendCoins...), vacc.GetCoins()) - require.Equal(t, vacc.SpendableCoins(now), sendCoins) + balances := app.BankKeeper.GetAllBalances(ctx, addr1) + suite.Require().Equal(origCoins.Add(sendCoins...), balances) + suite.Require().Equal(balances.Sub(vacc.LockedCoins(now)), sendCoins) // require coins are spendable plus any that have vested - require.Equal(t, vacc.SpendableCoins(now.Add(12*time.Hour)), origCoins) + suite.Require().Equal(balances.Sub(vacc.LockedCoins(now.Add(12*time.Hour))), origCoins) } -func TestDelegateCoins(t *testing.T) { - app, ctx := createTestApp(false) +func (suite *IntegrationTestSuite) TestDelegateCoins() { + app, ctx := suite.app, suite.ctx now := tmtime.Now() ctx = ctx.WithBlockHeader(abci.Header{Time: now}) endTime := now.Add(24 * time.Hour) - ak := app.AccountKeeper origCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 100)) delCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 50)) @@ -454,39 +532,58 @@ func TestDelegateCoins(t *testing.T) { addr2 := sdk.AccAddress([]byte("addr2")) addrModule := sdk.AccAddress([]byte("moduleAcc")) + macc := app.AccountKeeper.NewAccountWithAddress(ctx, addrModule) // we don't need to define an actual module account bc we just need the address for testing + acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr2) bacc := auth.NewBaseAccountWithAddress(addr1) - bacc.SetCoins(origCoins) - macc := ak.NewAccountWithAddress(ctx, addrModule) // we don't need to define an actual module account bc we just need the address for testing - vacc := vesting.NewContinuousVestingAccount(&bacc, ctx.BlockHeader().Time.Unix(), endTime.Unix()) - acc := ak.NewAccountWithAddress(ctx, addr2) - ak.SetAccount(ctx, vacc) - ak.SetAccount(ctx, acc) - ak.SetAccount(ctx, macc) - app.BankKeeper.SetCoins(ctx, addr2, origCoins) + vacc := vesting.NewContinuousVestingAccount(&bacc, origCoins, ctx.BlockHeader().Time.Unix(), endTime.Unix()) + + app.AccountKeeper.SetAccount(ctx, vacc) + app.AccountKeeper.SetAccount(ctx, acc) + app.AccountKeeper.SetAccount(ctx, macc) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, origCoins)) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr2, origCoins)) ctx = ctx.WithBlockTime(now.Add(12 * time.Hour)) // require the ability for a non-vesting account to delegate - err := app.BankKeeper.DelegateCoins(ctx, addr2, addrModule, delCoins) - acc = ak.GetAccount(ctx, addr2) - macc = ak.GetAccount(ctx, addrModule) - require.NoError(t, err) - require.Equal(t, origCoins.Sub(delCoins), acc.GetCoins()) - require.Equal(t, delCoins, macc.GetCoins()) + suite.Require().NoError(app.BankKeeper.DelegateCoins(ctx, addr2, addrModule, delCoins)) + suite.Require().Equal(origCoins.Sub(delCoins), app.BankKeeper.GetAllBalances(ctx, addr2)) + suite.Require().Equal(delCoins, app.BankKeeper.GetAllBalances(ctx, addrModule)) // require the ability for a vesting account to delegate - err = app.BankKeeper.DelegateCoins(ctx, addr1, addrModule, delCoins) - vacc = ak.GetAccount(ctx, addr1).(*vesting.ContinuousVestingAccount) - require.NoError(t, err) - require.Equal(t, delCoins, vacc.GetCoins()) + suite.Require().NoError(app.BankKeeper.DelegateCoins(ctx, addr1, addrModule, delCoins)) + suite.Require().Equal(delCoins, app.BankKeeper.GetAllBalances(ctx, addr1)) +} + +func (suite *IntegrationTestSuite) TestDelegateCoins_Invalid() { + app, ctx := suite.app, suite.ctx + + origCoins := sdk.NewCoins(newFooCoin(100)) + delCoins := sdk.NewCoins(newFooCoin(50)) + + addr1 := sdk.AccAddress([]byte("addr1")) + addrModule := sdk.AccAddress([]byte("moduleAcc")) + macc := app.AccountKeeper.NewAccountWithAddress(ctx, addrModule) // we don't need to define an actual module account bc we just need the address for testing + acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) + + suite.Require().Error(app.BankKeeper.DelegateCoins(ctx, addr1, addrModule, delCoins)) + invalidCoins := sdk.Coins{sdk.Coin{Denom: "fooDenom", Amount: sdk.NewInt(-50)}} + suite.Require().Error(app.BankKeeper.DelegateCoins(ctx, addr1, addrModule, invalidCoins)) + + app.AccountKeeper.SetAccount(ctx, macc) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, origCoins)) + + suite.Require().Error(app.BankKeeper.DelegateCoins(ctx, addr1, addrModule, delCoins)) + app.AccountKeeper.SetAccount(ctx, acc) + + suite.Require().Error(app.BankKeeper.DelegateCoins(ctx, addr1, addrModule, origCoins.Add(origCoins...))) } -func TestUndelegateCoins(t *testing.T) { - app, ctx := createTestApp(false) +func (suite *IntegrationTestSuite) TestUndelegateCoins() { + app, ctx := suite.app, suite.ctx now := tmtime.Now() ctx = ctx.WithBlockHeader(abci.Header{Time: now}) endTime := now.Add(24 * time.Hour) - ak := app.AccountKeeper origCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 100)) delCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 50)) @@ -496,50 +593,67 @@ func TestUndelegateCoins(t *testing.T) { addrModule := sdk.AccAddress([]byte("moduleAcc")) bacc := auth.NewBaseAccountWithAddress(addr1) - bacc.SetCoins(origCoins) - macc := ak.NewAccountWithAddress(ctx, addrModule) // we don't need to define an actual module account bc we just need the address for testing - vacc := vesting.NewContinuousVestingAccount(&bacc, ctx.BlockHeader().Time.Unix(), endTime.Unix()) - acc := ak.NewAccountWithAddress(ctx, addr2) - ak.SetAccount(ctx, vacc) - ak.SetAccount(ctx, acc) - ak.SetAccount(ctx, macc) - app.BankKeeper.SetCoins(ctx, addr2, origCoins) + macc := app.AccountKeeper.NewAccountWithAddress(ctx, addrModule) // we don't need to define an actual module account bc we just need the address for testing + + vacc := vesting.NewContinuousVestingAccount(&bacc, origCoins, ctx.BlockHeader().Time.Unix(), endTime.Unix()) + acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr2) + + app.AccountKeeper.SetAccount(ctx, vacc) + app.AccountKeeper.SetAccount(ctx, acc) + app.AccountKeeper.SetAccount(ctx, macc) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, origCoins)) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr2, origCoins)) ctx = ctx.WithBlockTime(now.Add(12 * time.Hour)) // require the ability for a non-vesting account to delegate err := app.BankKeeper.DelegateCoins(ctx, addr2, addrModule, delCoins) - require.NoError(t, err) + suite.Require().NoError(err) - acc = ak.GetAccount(ctx, addr2) - macc = ak.GetAccount(ctx, addrModule) - require.Equal(t, origCoins.Sub(delCoins), acc.GetCoins()) - require.Equal(t, delCoins, macc.GetCoins()) + suite.Require().Equal(origCoins.Sub(delCoins), app.BankKeeper.GetAllBalances(ctx, addr2)) + suite.Require().Equal(delCoins, app.BankKeeper.GetAllBalances(ctx, addrModule)) // require the ability for a non-vesting account to undelegate - err = app.BankKeeper.UndelegateCoins(ctx, addrModule, addr2, delCoins) - require.NoError(t, err) + suite.Require().NoError(app.BankKeeper.UndelegateCoins(ctx, addrModule, addr2, delCoins)) - acc = ak.GetAccount(ctx, addr2) - macc = ak.GetAccount(ctx, addrModule) - require.Equal(t, origCoins, acc.GetCoins()) - require.True(t, macc.GetCoins().Empty()) + suite.Require().Equal(origCoins, app.BankKeeper.GetAllBalances(ctx, addr2)) + suite.Require().True(app.BankKeeper.GetAllBalances(ctx, addrModule).Empty()) // require the ability for a vesting account to delegate - err = app.BankKeeper.DelegateCoins(ctx, addr1, addrModule, delCoins) - require.NoError(t, err) + suite.Require().NoError(app.BankKeeper.DelegateCoins(ctx, addr1, addrModule, delCoins)) - vacc = ak.GetAccount(ctx, addr1).(*vesting.ContinuousVestingAccount) - macc = ak.GetAccount(ctx, addrModule) - require.Equal(t, origCoins.Sub(delCoins), vacc.GetCoins()) - require.Equal(t, delCoins, macc.GetCoins()) + suite.Require().Equal(origCoins.Sub(delCoins), app.BankKeeper.GetAllBalances(ctx, addr1)) + suite.Require().Equal(delCoins, app.BankKeeper.GetAllBalances(ctx, addrModule)) // require the ability for a vesting account to undelegate - err = app.BankKeeper.UndelegateCoins(ctx, addrModule, addr1, delCoins) - require.NoError(t, err) + suite.Require().NoError(app.BankKeeper.UndelegateCoins(ctx, addrModule, addr1, delCoins)) + + suite.Require().Equal(origCoins, app.BankKeeper.GetAllBalances(ctx, addr1)) + suite.Require().True(app.BankKeeper.GetAllBalances(ctx, addrModule).Empty()) +} + +func (suite *IntegrationTestSuite) TestUndelegateCoins_Invalid() { + app, ctx := suite.app, suite.ctx + + origCoins := sdk.NewCoins(newFooCoin(100)) + delCoins := sdk.NewCoins(newFooCoin(50)) + + addr1 := sdk.AccAddress([]byte("addr1")) + addrModule := sdk.AccAddress([]byte("moduleAcc")) + macc := app.AccountKeeper.NewAccountWithAddress(ctx, addrModule) // we don't need to define an actual module account bc we just need the address for testing + acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) + + suite.Require().Error(app.BankKeeper.UndelegateCoins(ctx, addrModule, addr1, delCoins)) + + app.AccountKeeper.SetAccount(ctx, macc) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, origCoins)) + + suite.Require().Error(app.BankKeeper.UndelegateCoins(ctx, addrModule, addr1, delCoins)) + app.AccountKeeper.SetAccount(ctx, acc) + + suite.Require().Error(app.BankKeeper.UndelegateCoins(ctx, addrModule, addr1, delCoins)) +} - vacc = ak.GetAccount(ctx, addr1).(*vesting.ContinuousVestingAccount) - macc = ak.GetAccount(ctx, addrModule) - require.Equal(t, origCoins, vacc.GetCoins()) - require.True(t, macc.GetCoins().Empty()) +func TestKeeperTestSuite(t *testing.T) { + suite.Run(t, new(IntegrationTestSuite)) } diff --git a/x/bank/internal/keeper/querier.go b/x/bank/internal/keeper/querier.go index 165d01879621..072511b2d2a8 100644 --- a/x/bank/internal/keeper/querier.go +++ b/x/bank/internal/keeper/querier.go @@ -9,26 +9,22 @@ import ( "github.com/cosmos/cosmos-sdk/x/bank/internal/types" ) -const ( - // query balance path - QueryBalance = "balances" -) - // NewQuerier returns a new sdk.Keeper instance. func NewQuerier(k Keeper) sdk.Querier { return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) { switch path[0] { - case QueryBalance: + case types.QueryBalance: return queryBalance(ctx, req, k) + case types.QueryAllBalances: + return queryAllBalance(ctx, req, k) + default: - return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown query path: %s", path[0]) + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown %s query endpoint: %s", types.ModuleName, path[0]) } } } -// queryBalance fetch an account's balance for the supplied height. -// Height and account address are passed as first and second path components respectively. func queryBalance(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryBalanceParams @@ -36,12 +32,26 @@ func queryBalance(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, err return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } - coins := k.GetCoins(ctx, params.Address) - if coins == nil { - coins = sdk.NewCoins() + balance := k.GetBalance(ctx, params.Address, params.Denom) + + bz, err := codec.MarshalJSONIndent(types.ModuleCdc, balance) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } - bz, err := codec.MarshalJSONIndent(types.ModuleCdc, coins) + return bz, nil +} + +func queryAllBalance(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { + var params types.QueryAllBalancesParams + + if err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms); err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) + } + + balances := k.GetAllBalances(ctx, params.Address) + + bz, err := codec.MarshalJSONIndent(types.ModuleCdc, balances) if err != nil { return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } diff --git a/x/bank/internal/keeper/querier_test.go b/x/bank/internal/keeper/querier_test.go index 11f7504043a4..643f7b1798cf 100644 --- a/x/bank/internal/keeper/querier_test.go +++ b/x/bank/internal/keeper/querier_test.go @@ -2,59 +2,95 @@ package keeper_test import ( "fmt" - "testing" - - "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - keep "github.com/cosmos/cosmos-sdk/x/bank/internal/keeper" + "github.com/cosmos/cosmos-sdk/x/bank/internal/keeper" "github.com/cosmos/cosmos-sdk/x/bank/internal/types" ) -func TestBalances(t *testing.T) { - app, ctx := createTestApp(false) +func (suite *IntegrationTestSuite) TestQuerier_QueryBalance() { + app, ctx := suite.app, suite.ctx + _, _, addr := authtypes.KeyTestPubAddr() req := abci.RequestQuery{ - Path: fmt.Sprintf("custom/bank/%s", keep.QueryBalance), + Path: fmt.Sprintf("custom/%s/%s", types.ModuleName, types.QueryBalance), Data: []byte{}, } - querier := keep.NewQuerier(app.BankKeeper) + querier := keeper.NewQuerier(app.BankKeeper) + + res, err := querier(ctx, []string{types.QueryBalance}, req) + suite.Require().NotNil(err) + suite.Require().Nil(res) + + req.Data = app.Codec().MustMarshalJSON(types.NewQueryBalanceParams(addr, fooDenom)) + res, err = querier(ctx, []string{types.QueryBalance}, req) + suite.Require().NoError(err) + suite.Require().NotNil(res) + + var balance sdk.Coin + suite.Require().NoError(app.Codec().UnmarshalJSON(res, &balance)) + suite.True(balance.IsZero()) + + origCoins := sdk.NewCoins(newFooCoin(50), newBarCoin(30)) + acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr) + + app.AccountKeeper.SetAccount(ctx, acc) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, acc.GetAddress(), origCoins)) - res, err := querier(ctx, []string{"balances"}, req) - require.NotNil(t, err) - require.Nil(t, res) + res, err = querier(ctx, []string{types.QueryBalance}, req) + suite.Require().NoError(err) + suite.Require().NotNil(res) + suite.Require().NoError(app.Codec().UnmarshalJSON(res, &balance)) + suite.True(balance.IsEqual(newFooCoin(50))) +} +func (suite *IntegrationTestSuite) TestQuerier_QueryAllBalances() { + app, ctx := suite.app, suite.ctx _, _, addr := authtypes.KeyTestPubAddr() - req.Data = app.Codec().MustMarshalJSON(types.NewQueryBalanceParams(addr)) - res, err = querier(ctx, []string{"balances"}, req) - require.Nil(t, err) // the account does not exist, no error returned anyway - require.NotNil(t, res) + req := abci.RequestQuery{ + Path: fmt.Sprintf("custom/%s/%s", types.ModuleName, types.QueryAllBalances), + Data: []byte{}, + } + + querier := keeper.NewQuerier(app.BankKeeper) - var coins sdk.Coins - require.NoError(t, app.Codec().UnmarshalJSON(res, &coins)) - require.True(t, coins.IsZero()) + res, err := querier(ctx, []string{types.QueryAllBalances}, req) + suite.Require().NotNil(err) + suite.Require().Nil(res) + req.Data = app.Codec().MustMarshalJSON(types.NewQueryAllBalancesParams(addr)) + res, err = querier(ctx, []string{types.QueryAllBalances}, req) + suite.Require().NoError(err) + suite.Require().NotNil(res) + + var balances sdk.Coins + suite.Require().NoError(app.Codec().UnmarshalJSON(res, &balances)) + suite.True(balances.IsZero()) + + origCoins := sdk.NewCoins(newFooCoin(50), newBarCoin(30)) acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr) - acc.SetCoins(sdk.NewCoins(sdk.NewInt64Coin("foo", 10))) + app.AccountKeeper.SetAccount(ctx, acc) - res, err = querier(ctx, []string{"balances"}, req) - require.Nil(t, err) - require.NotNil(t, res) - require.NoError(t, app.Codec().UnmarshalJSON(res, &coins)) - require.True(t, coins.AmountOf("foo").Equal(sdk.NewInt(10))) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, acc.GetAddress(), origCoins)) + + res, err = querier(ctx, []string{types.QueryAllBalances}, req) + suite.Require().NoError(err) + suite.Require().NotNil(res) + suite.Require().NoError(app.Codec().UnmarshalJSON(res, &balances)) + suite.True(balances.IsEqual(origCoins)) } -func TestQuerierRouteNotFound(t *testing.T) { - app, ctx := createTestApp(false) +func (suite *IntegrationTestSuite) TestQuerierRouteNotFound() { + app, ctx := suite.app, suite.ctx req := abci.RequestQuery{ - Path: "custom/bank/notfound", + Path: fmt.Sprintf("custom/%s/invalid", types.ModuleName), Data: []byte{}, } - querier := keep.NewQuerier(app.BankKeeper) - _, err := querier(ctx, []string{"notfound"}, req) - require.Error(t, err) + querier := keeper.NewQuerier(app.BankKeeper) + _, err := querier(ctx, []string{"invalid"}, req) + suite.Error(err) } diff --git a/x/bank/internal/types/genesis.go b/x/bank/internal/types/genesis.go index 159b04f1f9a4..1505f64da553 100644 --- a/x/bank/internal/types/genesis.go +++ b/x/bank/internal/types/genesis.go @@ -1,18 +1,88 @@ package types -// GenesisState is the bank state that must be provided at genesis. +import ( + "bytes" + "encoding/json" + "sort" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/bank/exported" +) + +var _ exported.GenesisBalance = (*Balance)(nil) + +// GenesisState defines the bank module's genesis state. type GenesisState struct { - SendEnabled bool `json:"send_enabled" yaml:"send_enabled"` + SendEnabled bool `json:"send_enabled" yaml:"send_enabled"` + Balances []Balance `json:"balances" yaml:"balances"` +} + +// Balance defines an account address and balance pair used in the bank module's +// genesis state. +type Balance struct { + Address sdk.AccAddress `json:"address" yaml:"address"` + Coins sdk.Coins `json:"coins" yaml:"coins"` +} + +// GetAddress returns the account address of the Balance object. +func (b Balance) GetAddress() sdk.AccAddress { + return b.Address +} + +// GetAddress returns the account coins of the Balance object. +func (b Balance) GetCoins() sdk.Coins { + return b.Coins +} + +// SanitizeGenesisAccounts sorts addresses and coin sets. +func SanitizeGenesisBalances(balances []Balance) []Balance { + sort.Slice(balances, func(i, j int) bool { + return bytes.Compare(balances[i].Address.Bytes(), balances[j].Address.Bytes()) < 0 + }) + + for _, balance := range balances { + balance.Coins = balance.Coins.Sort() + } + + return balances } // NewGenesisState creates a new genesis state. -func NewGenesisState(sendEnabled bool) GenesisState { - return GenesisState{SendEnabled: sendEnabled} +func NewGenesisState(sendEnabled bool, balances []Balance) GenesisState { + return GenesisState{SendEnabled: sendEnabled, Balances: balances} } -// DefaultGenesisState returns a default genesis state -func DefaultGenesisState() GenesisState { return NewGenesisState(true) } +// DefaultGenesisState returns a default bank module genesis state. +func DefaultGenesisState() GenesisState { return NewGenesisState(true, []Balance{}) } // ValidateGenesis performs basic validation of bank genesis data returning an // error for any failed validation criteria. func ValidateGenesis(data GenesisState) error { return nil } + +// GetGenesisStateFromAppState returns x/bank GenesisState given raw application +// genesis state. +func GetGenesisStateFromAppState(cdc *codec.Codec, appState map[string]json.RawMessage) GenesisState { + var genesisState GenesisState + if appState[ModuleName] != nil { + cdc.MustUnmarshalJSON(appState[ModuleName], &genesisState) + } + + return genesisState +} + +// GenesisAccountIterator implements genesis account iteration. +type GenesisBalancesIterator struct{} + +// IterateGenesisAccounts iterates over all the genesis accounts found in +// appGenesis and invokes a callback on each genesis account. If any call +// returns true, iteration stops. +func (GenesisBalancesIterator) IterateGenesisBalances( + cdc *codec.Codec, appState map[string]json.RawMessage, cb func(exported.GenesisBalance) (stop bool), +) { + for _, balance := range GetGenesisStateFromAppState(cdc, appState).Balances { + if cb(balance) { + break + } + } +} diff --git a/x/bank/internal/types/key.go b/x/bank/internal/types/key.go index 7e38aeb52487..dcb106553478 100644 --- a/x/bank/internal/types/key.go +++ b/x/bank/internal/types/key.go @@ -1,7 +1,38 @@ package types +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + const ( - // module name - ModuleName = "bank" + // ModuleName defines the module name + ModuleName = "bank" + + // StoreKey defines the primary module store key + StoreKey = ModuleName + + // RouterKey defines the module's message routing key + RouterKey = ModuleName + + // QuerierRoute defines the module's query routing key QuerierRoute = ModuleName ) + +// KVStore key prefixes +var ( + BalancesPrefix = []byte("balances") +) + +// AddressFromBalancesStore returns an account address from a balances prefix +// store. The key must not contain the perfix BalancesPrefix as the prefix store +// iterator discards the actual prefix. +func AddressFromBalancesStore(key []byte) sdk.AccAddress { + addr := key[:sdk.AddrLen] + if len(addr) != sdk.AddrLen { + panic(fmt.Sprintf("unexpected account address key length; got: %d, expected: %d", len(addr), sdk.AddrLen)) + } + + return sdk.AccAddress(addr) +} diff --git a/x/bank/internal/types/key_test.go b/x/bank/internal/types/key_test.go new file mode 100644 index 000000000000..a16a22381d6e --- /dev/null +++ b/x/bank/internal/types/key_test.go @@ -0,0 +1,25 @@ +package types_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/bank/internal/types" + "github.com/stretchr/testify/require" +) + +func cloneAppend(bz []byte, tail []byte) (res []byte) { + res = make([]byte, len(bz)+len(tail)) + copy(res, bz) + copy(res[len(bz):], tail) + return +} + +func TestAddressFromBalancesStore(t *testing.T) { + addr, err := sdk.AccAddressFromBech32("cosmos1n88uc38xhjgxzw9nwre4ep2c8ga4fjxcar6mn7") + require.NoError(t, err) + + key := cloneAppend(addr.Bytes(), []byte("stake")) + res := types.AddressFromBalancesStore(key) + require.Equal(t, res, addr) +} diff --git a/x/bank/internal/types/msgs.go b/x/bank/internal/types/msgs.go index 50f8e3f06ff1..83db26aaefd1 100644 --- a/x/bank/internal/types/msgs.go +++ b/x/bank/internal/types/msgs.go @@ -5,9 +5,6 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) -// RouterKey is they name of the bank module -const RouterKey = ModuleName - // MsgSend - high level transaction of the coin module type MsgSend struct { FromAddress sdk.AccAddress `json:"from_address" yaml:"from_address"` diff --git a/x/bank/internal/types/querier.go b/x/bank/internal/types/querier.go index ef0a8576b879..7e0ef43fe7b2 100644 --- a/x/bank/internal/types/querier.go +++ b/x/bank/internal/types/querier.go @@ -4,12 +4,29 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) +// Querier path constants +const ( + QueryBalance = "balance" + QueryAllBalances = "all_balances" +) + // QueryBalanceParams defines the params for querying an account balance. type QueryBalanceParams struct { Address sdk.AccAddress + Denom string } // NewQueryBalanceParams creates a new instance of QueryBalanceParams. -func NewQueryBalanceParams(addr sdk.AccAddress) QueryBalanceParams { - return QueryBalanceParams{Address: addr} +func NewQueryBalanceParams(addr sdk.AccAddress, denom string) QueryBalanceParams { + return QueryBalanceParams{Address: addr, Denom: denom} +} + +// QueryAllBalancesParams defines the params for querying all account balances +type QueryAllBalancesParams struct { + Address sdk.AccAddress +} + +// NewQueryAllBalancesParams creates a new instance of QueryAllBalancesParams. +func NewQueryAllBalancesParams(addr sdk.AccAddress) QueryAllBalancesParams { + return QueryAllBalancesParams{Address: addr} } diff --git a/x/bank/legacy/v0_38/types.go b/x/bank/legacy/v0_38/types.go new file mode 100644 index 000000000000..e67640bf2b12 --- /dev/null +++ b/x/bank/legacy/v0_38/types.go @@ -0,0 +1,14 @@ +package v038 + +// DONTCOVER +// nolint + +const ( + ModuleName = "bank" +) + +type ( + GenesisState struct { + SendEnabled bool `json:"send_enabled" yaml:"send_enabled"` + } +) diff --git a/x/bank/legacy/v0_39/migrate.go b/x/bank/legacy/v0_39/migrate.go new file mode 100644 index 000000000000..222992357d9f --- /dev/null +++ b/x/bank/legacy/v0_39/migrate.go @@ -0,0 +1,22 @@ +package v039 + +import ( + v038auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v0_38" + v038bank "github.com/cosmos/cosmos-sdk/x/bank/legacy/v0_38" +) + +// Migrate accepts exported x/auth and x/bank genesis state from v0.38 and migrates +// it to v0.39 x/bank genesis state. The migration includes: +// +// - Moving balances from x/auth to x/bank genesis state. +func Migrate(bankGenState v038bank.GenesisState, authGenState v038auth.GenesisState) GenesisState { + balances := make([]Balance, len(authGenState.Accounts)) + for i, acc := range authGenState.Accounts { + balances[i] = Balance{ + Address: acc.GetAddress(), + Coins: acc.GetCoins(), + } + } + + return NewGenesisState(bankGenState.SendEnabled, balances) +} diff --git a/x/bank/legacy/v0_39/migrate_test.go b/x/bank/legacy/v0_39/migrate_test.go new file mode 100644 index 000000000000..ae51134d47c1 --- /dev/null +++ b/x/bank/legacy/v0_39/migrate_test.go @@ -0,0 +1,67 @@ +package v039_test + +import ( + "testing" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + v038auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v0_38" + v038bank "github.com/cosmos/cosmos-sdk/x/bank/legacy/v0_38" + v039bank "github.com/cosmos/cosmos-sdk/x/bank/legacy/v0_39" + + "github.com/stretchr/testify/require" +) + +func TestMigrate(t *testing.T) { + v039Codec := codec.New() + codec.RegisterCrypto(v039Codec) + v038auth.RegisterCodec(v039Codec) + + coins := sdk.NewCoins(sdk.NewInt64Coin("stake", 50)) + addr1, _ := sdk.AccAddressFromBech32("cosmos1xxkueklal9vejv9unqu80w9vptyepfa95pd53u") + acc1 := v038auth.NewBaseAccount(addr1, coins, nil, 1, 0) + + addr2, _ := sdk.AccAddressFromBech32("cosmos15v50ymp6n5dn73erkqtmq0u8adpl8d3ujv2e74") + vaac := v038auth.NewContinuousVestingAccountRaw( + v038auth.NewBaseVestingAccount( + v038auth.NewBaseAccount(addr2, coins, nil, 1, 0), coins, nil, nil, 3160620846, + ), + 1580309972, + ) + + bankGenState := v038bank.GenesisState{ + SendEnabled: true, + } + authGenState := v038auth.GenesisState{ + Accounts: v038auth.GenesisAccounts{acc1, vaac}, + } + + migrated := v039bank.Migrate(bankGenState, authGenState) + expected := `{ + "send_enabled": true, + "balances": [ + { + "address": "cosmos1xxkueklal9vejv9unqu80w9vptyepfa95pd53u", + "coins": [ + { + "denom": "stake", + "amount": "50" + } + ] + }, + { + "address": "cosmos15v50ymp6n5dn73erkqtmq0u8adpl8d3ujv2e74", + "coins": [ + { + "denom": "stake", + "amount": "50" + } + ] + } + ] +}` + + bz, err := v039Codec.MarshalJSONIndent(migrated, "", " ") + require.NoError(t, err) + require.Equal(t, expected, string(bz)) +} diff --git a/x/bank/legacy/v0_39/types.go b/x/bank/legacy/v0_39/types.go new file mode 100644 index 000000000000..d569ac4f7573 --- /dev/null +++ b/x/bank/legacy/v0_39/types.go @@ -0,0 +1,43 @@ +package v039 + +// DONTCOVER +// nolint + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +const ( + ModuleName = "bank" +) + +var _ GenesisBalance = (*Balance)(nil) + +type ( + GenesisBalance interface { + GetAddress() sdk.AccAddress + GetCoins() sdk.Coins + } + + GenesisState struct { + SendEnabled bool `json:"send_enabled" yaml:"send_enabled"` + Balances []Balance `json:"balances" yaml:"balances"` + } + + Balance struct { + Address sdk.AccAddress `json:"address" yaml:"address"` + Coins sdk.Coins `json:"coins" yaml:"coins"` + } +) + +func NewGenesisState(sendEnabled bool, balances []Balance) GenesisState { + return GenesisState{SendEnabled: sendEnabled, Balances: balances} +} + +func (b Balance) GetAddress() sdk.AccAddress { + return b.Address +} + +func (b Balance) GetCoins() sdk.Coins { + return b.Coins +} diff --git a/x/bank/module.go b/x/bank/module.go index 114962382758..72afda68622c 100644 --- a/x/bank/module.go +++ b/x/bank/module.go @@ -64,7 +64,9 @@ func (AppModuleBasic) GetTxCmd(cdc *codec.Codec) *cobra.Command { } // GetQueryCmd returns no root query command for the bank module. -func (AppModuleBasic) GetQueryCmd(_ *codec.Codec) *cobra.Command { return nil } +func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command { + return cli.GetQueryCmd(cdc) +} //____________________________________________________________________________ @@ -90,7 +92,7 @@ func (AppModule) Name() string { return ModuleName } // RegisterInvariants registers the bank module invariants. func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) { - keeper.RegisterInvariants(ir, am.accountKeeper) + keeper.RegisterInvariants(ir, am.keeper) } // Route returns the message routing key for the bank module. diff --git a/x/bank/simulation/genesis.go b/x/bank/simulation/genesis.go index 2dae431c9864..b593fa05b070 100644 --- a/x/bank/simulation/genesis.go +++ b/x/bank/simulation/genesis.go @@ -3,10 +3,9 @@ package simulation // DONTCOVER import ( - "fmt" "math/rand" - "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/x/bank/internal/types" ) @@ -21,6 +20,21 @@ func GenSendEnabled(r *rand.Rand) bool { return r.Int63n(101) <= 95 // 95% chance of transfers being enabled } +// RandomGenesisAccounts returns a slice of account balances. Each account has +// a balance of simState.InitialStake for sdk.DefaultBondDenom. +func RandomGenesisBalances(simState *module.SimulationState) []types.Balance { + genesisBalances := []types.Balance{} + + for _, acc := range simState.Accounts { + genesisBalances = append(genesisBalances, types.Balance{ + Address: acc.Address, + Coins: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(simState.InitialStake))), + }) + } + + return genesisBalances +} + // RandomizedGenState generates a random GenesisState for bank func RandomizedGenState(simState *module.SimulationState) { var sendEnabled bool @@ -29,8 +43,7 @@ func RandomizedGenState(simState *module.SimulationState) { func(r *rand.Rand) { sendEnabled = GenSendEnabled(r) }, ) - bankGenesis := types.NewGenesisState(sendEnabled) + bankGenesis := types.NewGenesisState(sendEnabled, RandomGenesisBalances(simState)) - fmt.Printf("Selected randomly generated bank parameters:\n%s\n", codec.MustMarshalJSONIndent(simState.Cdc, bankGenesis)) simState.GenState[types.ModuleName] = simState.Cdc.MustMarshalJSON(bankGenesis) } diff --git a/x/bank/simulation/operations.go b/x/bank/simulation/operations.go index 123e0b8eb45a..0c6d8d242b8d 100644 --- a/x/bank/simulation/operations.go +++ b/x/bank/simulation/operations.go @@ -22,8 +22,9 @@ const ( ) // WeightedOperations returns all the operations from the module with their respective weights -func WeightedOperations(appParams simulation.AppParams, cdc *codec.Codec, ak types.AccountKeeper, - bk keeper.Keeper) simulation.WeightedOperations { +func WeightedOperations( + appParams simulation.AppParams, cdc *codec.Codec, ak types.AccountKeeper, bk keeper.Keeper, +) simulation.WeightedOperations { var weightMsgSend, weightMsgMultiSend int appParams.GetOrGenerate(cdc, OpWeightMsgSend, &weightMsgSend, nil, @@ -63,7 +64,7 @@ func SimulateMsgSend(ak types.AccountKeeper, bk keeper.Keeper) simulation.Operat return simulation.NoOpMsg(types.ModuleName), nil, nil } - simAccount, toSimAcc, coins, skip, err := randomSendFields(r, ctx, accs, ak) + simAccount, toSimAcc, coins, skip, err := randomSendFields(r, ctx, accs, bk, ak) if err != nil { return simulation.NoOpMsg(types.ModuleName), nil, err } @@ -74,7 +75,7 @@ func SimulateMsgSend(ak types.AccountKeeper, bk keeper.Keeper) simulation.Operat msg := types.NewMsgSend(simAccount.Address, toSimAcc.Address, coins) - err = sendMsgSend(r, app, ak, msg, ctx, chainID, []crypto.PrivKey{simAccount.PrivKey}) + err = sendMsgSend(r, app, bk, ak, msg, ctx, chainID, []crypto.PrivKey{simAccount.PrivKey}) if err != nil { return simulation.NoOpMsg(types.ModuleName), nil, err } @@ -84,19 +85,21 @@ func SimulateMsgSend(ak types.AccountKeeper, bk keeper.Keeper) simulation.Operat } // sendMsgSend sends a transaction with a MsgSend from a provided random account. +// nolint: interfacer func sendMsgSend( - r *rand.Rand, app *baseapp.BaseApp, ak types.AccountKeeper, + r *rand.Rand, app *baseapp.BaseApp, bk keeper.Keeper, ak types.AccountKeeper, msg types.MsgSend, ctx sdk.Context, chainID string, privkeys []crypto.PrivKey, ) error { - account := ak.GetAccount(ctx, msg.FromAddress) - coins := account.SpendableCoins(ctx.BlockTime()) - var ( fees sdk.Coins err error ) - coins, hasNeg := coins.SafeSub(msg.Amount) + + account := ak.GetAccount(ctx, msg.FromAddress) + spendable := bk.SpendableCoins(ctx, account.GetAddress()) + + coins, hasNeg := spendable.SafeSub(msg.Amount) if !hasNeg { fees, err = simulation.RandomFees(r, ctx, coins) if err != nil { @@ -148,11 +151,11 @@ func SimulateMsgMultiSend(ak types.AccountKeeper, bk keeper.Keeper) simulation.O var totalSentCoins sdk.Coins for i := range inputs { // generate random input fields, ignore to address - simAccount, _, coins, skip, err := randomSendFields(r, ctx, accs, ak) + simAccount, _, coins, skip, err := randomSendFields(r, ctx, accs, bk, ak) // make sure account is fresh and not used in previous input for usedAddrs[simAccount.Address.String()] { - simAccount, _, coins, skip, err = randomSendFields(r, ctx, accs, ak) + simAccount, _, coins, skip, err = randomSendFields(r, ctx, accs, bk, ak) } if err != nil { @@ -207,7 +210,7 @@ func SimulateMsgMultiSend(ak types.AccountKeeper, bk keeper.Keeper) simulation.O Outputs: outputs, } - err := sendMsgMultiSend(r, app, ak, msg, ctx, chainID, privs) + err := sendMsgMultiSend(r, app, bk, ak, msg, ctx, chainID, privs) if err != nil { return simulation.NoOpMsg(types.ModuleName), nil, err } @@ -218,8 +221,9 @@ func SimulateMsgMultiSend(ak types.AccountKeeper, bk keeper.Keeper) simulation.O // sendMsgMultiSend sends a transaction with a MsgMultiSend from a provided random // account. +// nolint: interfacer func sendMsgMultiSend( - r *rand.Rand, app *baseapp.BaseApp, ak types.AccountKeeper, + r *rand.Rand, app *baseapp.BaseApp, bk keeper.Keeper, ak types.AccountKeeper, msg types.MsgMultiSend, ctx sdk.Context, chainID string, privkeys []crypto.PrivKey, ) error { @@ -232,15 +236,16 @@ func sendMsgMultiSend( sequenceNumbers[i] = acc.GetSequence() } - // feePayer is the first signer, i.e. first input address - feePayer := ak.GetAccount(ctx, msg.Inputs[0].Address) - coins := feePayer.SpendableCoins(ctx.BlockTime()) - var ( fees sdk.Coins err error ) - coins, hasNeg := coins.SafeSub(msg.Inputs[0].Coins) + + // feePayer is the first signer, i.e. first input address + feePayer := ak.GetAccount(ctx, msg.Inputs[0].Address) + spendable := bk.SpendableCoins(ctx, feePayer.GetAddress()) + + coins, hasNeg := spendable.SafeSub(msg.Inputs[0].Coins) if !hasNeg { fees, err = simulation.RandomFees(r, ctx, coins) if err != nil { @@ -268,8 +273,9 @@ func sendMsgMultiSend( // randomSendFields returns the sender and recipient simulation accounts as well // as the transferred amount. +// nolint: interfacer func randomSendFields( - r *rand.Rand, ctx sdk.Context, accs []simulation.Account, ak types.AccountKeeper, + r *rand.Rand, ctx sdk.Context, accs []simulation.Account, bk keeper.Keeper, ak types.AccountKeeper, ) (simulation.Account, simulation.Account, sdk.Coins, bool, error) { simAccount, _ := simulation.RandomAcc(r, accs) @@ -285,9 +291,9 @@ func randomSendFields( return simAccount, toSimAcc, nil, true, nil // skip error } - coins := acc.SpendableCoins(ctx.BlockHeader().Time) + spendable := bk.SpendableCoins(ctx, acc.GetAddress()) - sendCoins := simulation.RandSubsetCoins(r, coins) + sendCoins := simulation.RandSubsetCoins(r, spendable) if sendCoins.Empty() { return simAccount, toSimAcc, nil, true, nil // skip error } diff --git a/x/crisis/handler_test.go b/x/crisis/handler_test.go index 912bd863f7c5..2db4012d2f70 100644 --- a/x/crisis/handler_test.go +++ b/x/crisis/handler_test.go @@ -90,7 +90,7 @@ func TestHandleMsgVerifyInvariant(t *testing.T) { func TestHandleMsgVerifyInvariantWithNotEnoughSenderCoins(t *testing.T) { app, ctx, addrs := createTestApp() sender := addrs[0] - coin := app.AccountKeeper.GetAccount(ctx, sender).GetCoins()[0] + coin := app.BankKeeper.GetAllBalances(ctx, sender)[0] excessCoins := sdk.NewCoin(coin.Denom, coin.Amount.AddRaw(1)) app.CrisisKeeper.SetConstantFee(ctx, excessCoins) diff --git a/x/distribution/genesis.go b/x/distribution/genesis.go index 6a7f9c1fdbaf..9e00aeba2b7c 100644 --- a/x/distribution/genesis.go +++ b/x/distribution/genesis.go @@ -8,7 +8,7 @@ import ( ) // InitGenesis sets distribution information for genesis -func InitGenesis(ctx sdk.Context, keeper Keeper, supplyKeeper types.SupplyKeeper, data types.GenesisState) { +func InitGenesis(ctx sdk.Context, bk types.BankKeeper, supplyKeeper types.SupplyKeeper, keeper Keeper, data types.GenesisState) { var moduleHoldings sdk.DecCoins keeper.SetFeePool(ctx, data.FeePool) @@ -47,10 +47,11 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, supplyKeeper types.SupplyKeeper panic(fmt.Sprintf("%s module account has not been set", types.ModuleName)) } - if moduleAcc.GetCoins().IsZero() { - if err := moduleAcc.SetCoins(moduleHoldingsInt); err != nil { + if bk.GetAllBalances(ctx, moduleAcc.GetAddress()).IsZero() { + if err := bk.SetBalances(ctx, moduleAcc.GetAddress(), moduleHoldingsInt); err != nil { panic(err) } + supplyKeeper.SetModuleAccount(ctx, moduleAcc) } } diff --git a/x/distribution/keeper/allocation.go b/x/distribution/keeper/allocation.go index b6a34a3d643b..533aaac43858 100644 --- a/x/distribution/keeper/allocation.go +++ b/x/distribution/keeper/allocation.go @@ -22,7 +22,7 @@ func (k Keeper) AllocateTokens( // called in BeginBlock, collected fees will be from the previous block // (and distributed to the previous proposer) feeCollector := k.supplyKeeper.GetModuleAccount(ctx, k.feeCollectorName) - feesCollectedInt := feeCollector.GetCoins() + feesCollectedInt := k.bankKeeper.GetAllBalances(ctx, feeCollector.GetAddress()) feesCollected := sdk.NewDecCoinsFromCoins(feesCollectedInt...) // transfer collected fees to the distribution module account diff --git a/x/distribution/keeper/allocation_test.go b/x/distribution/keeper/allocation_test.go index 83821ea3820d..61513a02dca3 100644 --- a/x/distribution/keeper/allocation_test.go +++ b/x/distribution/keeper/allocation_test.go @@ -11,7 +11,7 @@ import ( ) func TestAllocateTokensToValidatorWithCommission(t *testing.T) { - ctx, _, k, sk, _ := CreateTestInputDefault(t, false, 1000) + ctx, _, _, k, sk, _ := CreateTestInputDefault(t, false, 1000) sh := staking.NewHandler(sk) // create validator with 50% commission @@ -44,7 +44,7 @@ func TestAllocateTokensToValidatorWithCommission(t *testing.T) { } func TestAllocateTokensToManyValidators(t *testing.T) { - ctx, ak, k, sk, supplyKeeper := CreateTestInputDefault(t, false, 1000) + ctx, ak, bk, k, sk, supplyKeeper := CreateTestInputDefault(t, false, 1000) sh := staking.NewHandler(sk) // create validator with 50% commission @@ -88,7 +88,7 @@ func TestAllocateTokensToManyValidators(t *testing.T) { feeCollector := supplyKeeper.GetModuleAccount(ctx, k.feeCollectorName) require.NotNil(t, feeCollector) - err = feeCollector.SetCoins(fees) + err = bk.SetBalances(ctx, feeCollector.GetAddress(), fees) require.NoError(t, err) ak.SetAccount(ctx, feeCollector) @@ -121,7 +121,7 @@ func TestAllocateTokensToManyValidators(t *testing.T) { func TestAllocateTokensTruncation(t *testing.T) { communityTax := sdk.NewDec(0) - ctx, ak, _, k, sk, _, supplyKeeper := CreateTestInputAdvanced(t, false, 1000000, communityTax) + ctx, ak, bk, k, sk, _, supplyKeeper := CreateTestInputAdvanced(t, false, 1000000, communityTax) sh := staking.NewHandler(sk) // create validator with 10% commission @@ -177,7 +177,7 @@ func TestAllocateTokensTruncation(t *testing.T) { feeCollector := supplyKeeper.GetModuleAccount(ctx, k.feeCollectorName) require.NotNil(t, feeCollector) - err = feeCollector.SetCoins(fees) + err = bk.SetBalances(ctx, feeCollector.GetAddress(), fees) require.NoError(t, err) ak.SetAccount(ctx, feeCollector) diff --git a/x/distribution/keeper/delegation_test.go b/x/distribution/keeper/delegation_test.go index 6d23ad958991..7f593fd5ecd6 100644 --- a/x/distribution/keeper/delegation_test.go +++ b/x/distribution/keeper/delegation_test.go @@ -10,7 +10,7 @@ import ( ) func TestCalculateRewardsBasic(t *testing.T) { - ctx, _, k, sk, _ := CreateTestInputDefault(t, false, 1000) + ctx, _, _, k, sk, _ := CreateTestInputDefault(t, false, 1000) sh := staking.NewHandler(sk) // create validator with 50% commission @@ -67,7 +67,7 @@ func TestCalculateRewardsBasic(t *testing.T) { } func TestCalculateRewardsAfterSlash(t *testing.T) { - ctx, _, k, sk, _ := CreateTestInputDefault(t, false, 1000) + ctx, _, _, k, sk, _ := CreateTestInputDefault(t, false, 1000) sh := staking.NewHandler(sk) // create validator with 50% commission @@ -132,7 +132,7 @@ func TestCalculateRewardsAfterSlash(t *testing.T) { } func TestCalculateRewardsAfterManySlashes(t *testing.T) { - ctx, _, k, sk, _ := CreateTestInputDefault(t, false, 1000) + ctx, _, _, k, sk, _ := CreateTestInputDefault(t, false, 1000) sh := staking.NewHandler(sk) // create validator with 50% commission @@ -209,7 +209,7 @@ func TestCalculateRewardsAfterManySlashes(t *testing.T) { } func TestCalculateRewardsMultiDelegator(t *testing.T) { - ctx, _, k, sk, _ := CreateTestInputDefault(t, false, 1000) + ctx, _, _, k, sk, _ := CreateTestInputDefault(t, false, 1000) sh := staking.NewHandler(sk) // create validator with 50% commission @@ -279,12 +279,12 @@ func TestCalculateRewardsMultiDelegator(t *testing.T) { func TestWithdrawDelegationRewardsBasic(t *testing.T) { balancePower := int64(1000) balanceTokens := sdk.TokensFromConsensusPower(balancePower) - ctx, ak, k, sk, _ := CreateTestInputDefault(t, false, balancePower) + ctx, _, bk, k, sk, _ := CreateTestInputDefault(t, false, balancePower) sh := staking.NewHandler(sk) // set module account coins distrAcc := k.GetDistributionAccount(ctx) - distrAcc.SetCoins(sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, balanceTokens))) + require.NoError(t, bk.SetBalances(ctx, distrAcc.GetAddress(), sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, balanceTokens)))) k.supplyKeeper.SetModuleAccount(ctx, distrAcc) // create validator with 50% commission @@ -305,7 +305,7 @@ func TestWithdrawDelegationRewardsBasic(t *testing.T) { expTokens := balanceTokens.Sub(valTokens) require.Equal(t, sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, expTokens)}, - ak.GetAccount(ctx, sdk.AccAddress(valOpAddr1)).GetCoins(), + bk.GetAllBalances(ctx, sdk.AccAddress(valOpAddr1)), ) // end block to bond validator @@ -337,7 +337,7 @@ func TestWithdrawDelegationRewardsBasic(t *testing.T) { exp := balanceTokens.Sub(valTokens).Add(initial.QuoRaw(2)) require.Equal(t, sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, exp)}, - ak.GetAccount(ctx, sdk.AccAddress(valOpAddr1)).GetCoins(), + bk.GetAllBalances(ctx, sdk.AccAddress(valOpAddr1)), ) // withdraw commission @@ -348,12 +348,12 @@ func TestWithdrawDelegationRewardsBasic(t *testing.T) { exp = balanceTokens.Sub(valTokens).Add(initial) require.Equal(t, sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, exp)}, - ak.GetAccount(ctx, sdk.AccAddress(valOpAddr1)).GetCoins(), + bk.GetAllBalances(ctx, sdk.AccAddress(valOpAddr1)), ) } func TestCalculateRewardsAfterManySlashesInSameBlock(t *testing.T) { - ctx, _, k, sk, _ := CreateTestInputDefault(t, false, 1000) + ctx, _, _, k, sk, _ := CreateTestInputDefault(t, false, 1000) sh := staking.NewHandler(sk) // create validator with 50% commission @@ -423,7 +423,7 @@ func TestCalculateRewardsAfterManySlashesInSameBlock(t *testing.T) { } func TestCalculateRewardsMultiDelegatorMultiSlash(t *testing.T) { - ctx, _, k, sk, _ := CreateTestInputDefault(t, false, 1000) + ctx, _, _, k, sk, _ := CreateTestInputDefault(t, false, 1000) sh := staking.NewHandler(sk) // create validator with 50% commission @@ -505,13 +505,14 @@ func TestCalculateRewardsMultiDelegatorMultiSlash(t *testing.T) { } func TestCalculateRewardsMultiDelegatorMultWithdraw(t *testing.T) { - ctx, _, k, sk, _ := CreateTestInputDefault(t, false, 1000) + ctx, _, bk, k, sk, _ := CreateTestInputDefault(t, false, 1000) sh := staking.NewHandler(sk) initial := int64(20) // set module account coins distrAcc := k.GetDistributionAccount(ctx) - distrAcc.SetCoins(sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(1000)))) + err := bk.SetBalances(ctx, distrAcc.GetAddress(), sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(1000)))) + require.NoError(t, err) k.supplyKeeper.SetModuleAccount(ctx, distrAcc) tokens := sdk.DecCoins{sdk.NewDecCoinFromDec(sdk.DefaultBondDenom, sdk.NewDec(initial))} diff --git a/x/distribution/keeper/invariants.go b/x/distribution/keeper/invariants.go index cff02da07691..cfafe1b11b27 100644 --- a/x/distribution/keeper/invariants.go +++ b/x/distribution/keeper/invariants.go @@ -148,11 +148,15 @@ func ModuleAccountInvariant(k Keeper) sdk.Invariant { expectedInt, _ := expectedCoins.Add(communityPool...).TruncateDecimal() macc := k.GetDistributionAccount(ctx) + balances := k.bankKeeper.GetAllBalances(ctx, macc.GetAddress()) - broken := !macc.GetCoins().IsEqual(expectedInt) - return sdk.FormatInvariant(types.ModuleName, "ModuleAccount coins", + broken := !balances.IsEqual(expectedInt) + return sdk.FormatInvariant( + types.ModuleName, "ModuleAccount coins", fmt.Sprintf("\texpected ModuleAccount coins: %s\n"+ "\tdistribution ModuleAccount coins: %s\n", - expectedInt, macc.GetCoins())), broken + expectedInt, balances, + ), + ), broken } } diff --git a/x/distribution/keeper/keeper.go b/x/distribution/keeper/keeper.go index 18cbce2b6848..5cce89d0c33f 100644 --- a/x/distribution/keeper/keeper.go +++ b/x/distribution/keeper/keeper.go @@ -17,6 +17,7 @@ type Keeper struct { storeKey sdk.StoreKey cdc *codec.Codec paramSpace params.Subspace + bankKeeper types.BankKeeper stakingKeeper types.StakingKeeper supplyKeeper types.SupplyKeeper @@ -27,7 +28,7 @@ type Keeper struct { // NewKeeper creates a new distribution Keeper instance func NewKeeper( - cdc *codec.Codec, key sdk.StoreKey, paramSpace params.Subspace, + cdc *codec.Codec, key sdk.StoreKey, paramSpace params.Subspace, bk types.BankKeeper, sk types.StakingKeeper, supplyKeeper types.SupplyKeeper, feeCollectorName string, blacklistedAddrs map[string]bool, ) Keeper { @@ -46,6 +47,7 @@ func NewKeeper( storeKey: key, cdc: cdc, paramSpace: paramSpace, + bankKeeper: bk, stakingKeeper: sk, supplyKeeper: supplyKeeper, feeCollectorName: feeCollectorName, diff --git a/x/distribution/keeper/keeper_test.go b/x/distribution/keeper/keeper_test.go index 5b2d989f7f82..ce0721ce6658 100644 --- a/x/distribution/keeper/keeper_test.go +++ b/x/distribution/keeper/keeper_test.go @@ -11,7 +11,7 @@ import ( ) func TestSetWithdrawAddr(t *testing.T) { - ctx, _, keeper, _, _ := CreateTestInputDefault(t, false, 1000) + ctx, _, _, keeper, _, _ := CreateTestInputDefault(t, false, 1000) // nolint: dogseld params := keeper.GetParams(ctx) params.WithdrawAddrEnabled = false @@ -31,7 +31,7 @@ func TestSetWithdrawAddr(t *testing.T) { } func TestWithdrawValidatorCommission(t *testing.T) { - ctx, ak, keeper, _, _ := CreateTestInputDefault(t, false, 1000) + ctx, _, bk, keeper, _, _ := CreateTestInputDefault(t, false, 1000) valCommission := sdk.DecCoins{ sdk.NewDecCoinFromDec("mytoken", sdk.NewDec(5).Quo(sdk.NewDec(4))), @@ -40,14 +40,14 @@ func TestWithdrawValidatorCommission(t *testing.T) { // set module account coins distrAcc := keeper.GetDistributionAccount(ctx) - distrAcc.SetCoins(sdk.NewCoins( + bk.SetBalances(ctx, distrAcc.GetAddress(), sdk.NewCoins( sdk.NewCoin("mytoken", sdk.NewInt(2)), sdk.NewCoin("stake", sdk.NewInt(2)), )) keeper.supplyKeeper.SetModuleAccount(ctx, distrAcc) // check initial balance - balance := ak.GetAccount(ctx, sdk.AccAddress(valOpAddr3)).GetCoins() + balance := bk.GetAllBalances(ctx, sdk.AccAddress(valOpAddr3)) expTokens := sdk.TokensFromConsensusPower(1000) expCoins := sdk.NewCoins(sdk.NewCoin("stake", expTokens)) require.Equal(t, expCoins, balance) @@ -62,7 +62,7 @@ func TestWithdrawValidatorCommission(t *testing.T) { keeper.WithdrawValidatorCommission(ctx, valOpAddr3) // check balance increase - balance = ak.GetAccount(ctx, sdk.AccAddress(valOpAddr3)).GetCoins() + balance = bk.GetAllBalances(ctx, sdk.AccAddress(valOpAddr3)) require.Equal(t, sdk.NewCoins( sdk.NewCoin("mytoken", sdk.NewInt(1)), sdk.NewCoin("stake", expTokens.AddRaw(1)), @@ -79,7 +79,7 @@ func TestWithdrawValidatorCommission(t *testing.T) { } func TestGetTotalRewards(t *testing.T) { - ctx, _, keeper, _, _ := CreateTestInputDefault(t, false, 1000) + ctx, _, _, keeper, _, _ := CreateTestInputDefault(t, false, 1000) // nolint: dogseld valCommission := sdk.DecCoins{ sdk.NewDecCoinFromDec("mytoken", sdk.NewDec(5).Quo(sdk.NewDec(4))), @@ -100,7 +100,7 @@ func TestFundCommunityPool(t *testing.T) { ctx, _, bk, keeper, _, _, _ := CreateTestInputAdvanced(t, false, 1000, sdk.NewDecWithPrec(2, 2)) amount := sdk.NewCoins(sdk.NewInt64Coin("stake", 100)) - _ = bk.SetCoins(ctx, delAddr1, amount) + require.NoError(t, bk.SetBalances(ctx, delAddr1, amount)) initPool := keeper.GetFeePool(ctx) assert.Empty(t, initPool.CommunityPool) @@ -109,5 +109,5 @@ func TestFundCommunityPool(t *testing.T) { assert.Nil(t, err) assert.Equal(t, initPool.CommunityPool.Add(sdk.NewDecCoinsFromCoins(amount...)...), keeper.GetFeePool(ctx).CommunityPool) - assert.Empty(t, bk.GetCoins(ctx, delAddr1)) + assert.Empty(t, bk.GetAllBalances(ctx, delAddr1)) } diff --git a/x/distribution/keeper/querier_test.go b/x/distribution/keeper/querier_test.go index b5efd15a3a62..ed87f42edd78 100644 --- a/x/distribution/keeper/querier_test.go +++ b/x/distribution/keeper/querier_test.go @@ -109,7 +109,7 @@ func TestQueries(t *testing.T) { cdc := codec.New() types.RegisterCodec(cdc) supply.RegisterCodec(cdc) - ctx, _, keeper, sk, _ := CreateTestInputDefault(t, false, 100) + ctx, _, _, keeper, sk, _ := CreateTestInputDefault(t, false, 100) querier := NewQuerier(keeper) // test param queries diff --git a/x/distribution/keeper/test_common.go b/x/distribution/keeper/test_common.go index 78425e47c11d..e049c3bbc57a 100644 --- a/x/distribution/keeper/test_common.go +++ b/x/distribution/keeper/test_common.go @@ -6,6 +6,7 @@ import ( "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/ed25519" "github.com/tendermint/tendermint/libs/log" dbm "github.com/tendermint/tm-db" @@ -53,6 +54,9 @@ var ( delAddr1, delAddr2, delAddr3, valAccAddr1, valAccAddr2, valAccAddr3, } + pubkeys = []crypto.PubKey{ + delPk1, delPk2, delPk3, valOpPk1, valOpPk2, valOpPk3, + } distrAcc = supply.NewEmptyModuleAccount(types.ModuleName) ) @@ -73,21 +77,23 @@ func MakeTestCodec() *codec.Codec { // test input with default values func CreateTestInputDefault(t *testing.T, isCheckTx bool, initPower int64) ( - sdk.Context, auth.AccountKeeper, Keeper, staking.Keeper, types.SupplyKeeper) { + sdk.Context, auth.AccountKeeper, bank.Keeper, Keeper, staking.Keeper, types.SupplyKeeper) { communityTax := sdk.NewDecWithPrec(2, 2) - ctx, ak, _, dk, sk, _, supplyKeeper := CreateTestInputAdvanced(t, isCheckTx, initPower, communityTax) - return ctx, ak, dk, sk, supplyKeeper + ctx, ak, bk, dk, sk, _, supplyKeeper := CreateTestInputAdvanced(t, isCheckTx, initPower, communityTax) + return ctx, ak, bk, dk, sk, supplyKeeper } // hogpodge of all sorts of input required for testing -func CreateTestInputAdvanced(t *testing.T, isCheckTx bool, initPower int64, - communityTax sdk.Dec) (sdk.Context, auth.AccountKeeper, bank.Keeper, - Keeper, staking.Keeper, params.Keeper, types.SupplyKeeper) { +func CreateTestInputAdvanced( + t *testing.T, isCheckTx bool, initPower int64, communityTax sdk.Dec, +) (sdk.Context, auth.AccountKeeper, bank.Keeper, Keeper, staking.Keeper, params.Keeper, types.SupplyKeeper, +) { initTokens := sdk.TokensFromConsensusPower(initPower) + keyBank := sdk.NewKVStoreKey(bank.StoreKey) keyDistr := sdk.NewKVStoreKey(types.StoreKey) keyStaking := sdk.NewKVStoreKey(staking.StoreKey) keyAcc := sdk.NewKVStoreKey(auth.StoreKey) @@ -98,6 +104,7 @@ func CreateTestInputAdvanced(t *testing.T, isCheckTx bool, initPower int64, db := dbm.NewMemDB() ms := store.NewCommitMultiStore(db) + ms.MountStoreWithDB(keyBank, sdk.StoreTypeIAVL, db) ms.MountStoreWithDB(keyDistr, sdk.StoreTypeIAVL, db) ms.MountStoreWithDB(keyStaking, sdk.StoreTypeIAVL, db) ms.MountStoreWithDB(keySupply, sdk.StoreTypeIAVL, db) @@ -123,7 +130,7 @@ func CreateTestInputAdvanced(t *testing.T, isCheckTx bool, initPower int64, ctx := sdk.NewContext(ms, abci.Header{ChainID: "foochainid"}, isCheckTx, log.NewNopLogger()) accountKeeper := auth.NewAccountKeeper(cdc, keyAcc, pk.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount) - bankKeeper := bank.NewBaseKeeper(accountKeeper, pk.Subspace(bank.DefaultParamspace), blacklistedAddrs) + bankKeeper := bank.NewBaseKeeper(cdc, keyBank, accountKeeper, pk.Subspace(bank.DefaultParamspace), blacklistedAddrs) maccPerms := map[string][]string{ auth.FeeCollectorName: nil, types.ModuleName: nil, @@ -132,19 +139,19 @@ func CreateTestInputAdvanced(t *testing.T, isCheckTx bool, initPower int64, } supplyKeeper := supply.NewKeeper(cdc, keySupply, accountKeeper, bankKeeper, maccPerms) - sk := staking.NewKeeper(cdc, keyStaking, supplyKeeper, pk.Subspace(staking.DefaultParamspace)) + sk := staking.NewKeeper(cdc, keyStaking, bankKeeper, supplyKeeper, pk.Subspace(staking.DefaultParamspace)) sk.SetParams(ctx, staking.DefaultParams()) - keeper := NewKeeper(cdc, keyDistr, pk.Subspace(types.DefaultParamspace), sk, supplyKeeper, auth.FeeCollectorName, blacklistedAddrs) + keeper := NewKeeper(cdc, keyDistr, pk.Subspace(types.DefaultParamspace), bankKeeper, sk, supplyKeeper, auth.FeeCollectorName, blacklistedAddrs) initCoins := sdk.NewCoins(sdk.NewCoin(sk.BondDenom(ctx), initTokens)) totalSupply := sdk.NewCoins(sdk.NewCoin(sk.BondDenom(ctx), initTokens.MulRaw(int64(len(TestAddrs))))) supplyKeeper.SetSupply(ctx, supply.NewSupply(totalSupply)) // fill all the addresses with some coins, set the loose pool tokens simultaneously - for _, addr := range TestAddrs { - _, err := bankKeeper.AddCoins(ctx, addr, initCoins) - require.Nil(t, err) + for i, addr := range TestAddrs { + accountKeeper.SetAccount(ctx, auth.NewBaseAccount(addr, pubkeys[i], uint64(i), 0)) + require.NoError(t, bankKeeper.SetBalances(ctx, addr, initCoins)) } // set module accounts diff --git a/x/distribution/module.go b/x/distribution/module.go index 0b143d6478b8..631d9b956fe2 100644 --- a/x/distribution/module.go +++ b/x/distribution/module.go @@ -80,17 +80,21 @@ type AppModule struct { keeper Keeper accountKeeper types.AccountKeeper + bankKeeper types.BankKeeper stakingKeeper stakingkeeper.Keeper supplyKeeper types.SupplyKeeper } // NewAppModule creates a new AppModule object -func NewAppModule(keeper Keeper, accountKeeper types.AccountKeeper, - supplyKeeper types.SupplyKeeper, stakingKeeper stakingkeeper.Keeper) AppModule { +func NewAppModule( + keeper Keeper, accountKeeper types.AccountKeeper, bankKeeper types.BankKeeper, + supplyKeeper types.SupplyKeeper, stakingKeeper stakingkeeper.Keeper, +) AppModule { return AppModule{ AppModuleBasic: AppModuleBasic{}, keeper: keeper, accountKeeper: accountKeeper, + bankKeeper: bankKeeper, supplyKeeper: supplyKeeper, stakingKeeper: stakingKeeper, } @@ -131,7 +135,7 @@ func (am AppModule) NewQuerierHandler() sdk.Querier { func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate { var genesisState GenesisState ModuleCdc.MustUnmarshalJSON(data, &genesisState) - InitGenesis(ctx, am.keeper, am.supplyKeeper, genesisState) + InitGenesis(ctx, am.bankKeeper, am.supplyKeeper, am.keeper, genesisState) return []abci.ValidatorUpdate{} } @@ -180,6 +184,7 @@ func (AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { // WeightedOperations returns the all the gov module operations with their respective weights. func (am AppModule) WeightedOperations(simState module.SimulationState) []sim.WeightedOperation { - return simulation.WeightedOperations(simState.AppParams, simState.Cdc, - am.accountKeeper, am.keeper, am.stakingKeeper) + return simulation.WeightedOperations( + simState.AppParams, simState.Cdc, am.accountKeeper, am.bankKeeper, am.keeper, am.stakingKeeper, + ) } diff --git a/x/distribution/proposal_handler_test.go b/x/distribution/proposal_handler_test.go index 1aeee1f2880a..1f13f15d5240 100644 --- a/x/distribution/proposal_handler_test.go +++ b/x/distribution/proposal_handler_test.go @@ -19,28 +19,24 @@ var ( ) func testProposal(recipient sdk.AccAddress, amount sdk.Coins) types.CommunityPoolSpendProposal { - return types.NewCommunityPoolSpendProposal( - "Test", - "description", - recipient, - amount, - ) + return types.NewCommunityPoolSpendProposal("Test", "description", recipient, amount) } func TestProposalHandlerPassed(t *testing.T) { - ctx, accountKeeper, keeper, _, supplyKeeper := CreateTestInputDefault(t, false, 10) + ctx, ak, bk, keeper, _, supplyKeeper := CreateTestInputDefault(t, false, 10) recipient := delAddr1 // add coins to the module account macc := keeper.GetDistributionAccount(ctx) - err := macc.SetCoins(macc.GetCoins().Add(amount...)) + balances := bk.GetAllBalances(ctx, macc.GetAddress()) + err := bk.SetBalances(ctx, macc.GetAddress(), balances.Add(amount...)) require.NoError(t, err) supplyKeeper.SetModuleAccount(ctx, macc) - account := accountKeeper.NewAccountWithAddress(ctx, recipient) - require.True(t, account.GetCoins().IsZero()) - accountKeeper.SetAccount(ctx, account) + account := ak.NewAccountWithAddress(ctx, recipient) + ak.SetAccount(ctx, account) + require.True(t, bk.GetAllBalances(ctx, account.GetAddress()).IsZero()) feePool := keeper.GetFeePool(ctx) feePool.CommunityPool = sdk.NewDecCoinsFromCoins(amount...) @@ -49,19 +45,23 @@ func TestProposalHandlerPassed(t *testing.T) { tp := testProposal(recipient, amount) hdlr := NewCommunityPoolSpendProposalHandler(keeper) require.NoError(t, hdlr(ctx, tp)) - require.Equal(t, accountKeeper.GetAccount(ctx, recipient).GetCoins(), amount) + + balances = bk.GetAllBalances(ctx, recipient) + require.Equal(t, balances, amount) } func TestProposalHandlerFailed(t *testing.T) { - ctx, accountKeeper, keeper, _, _ := CreateTestInputDefault(t, false, 10) + ctx, ak, bk, keeper, _, _ := CreateTestInputDefault(t, false, 10) recipient := delAddr1 - account := accountKeeper.NewAccountWithAddress(ctx, recipient) - require.True(t, account.GetCoins().IsZero()) - accountKeeper.SetAccount(ctx, account) + account := ak.NewAccountWithAddress(ctx, recipient) + ak.SetAccount(ctx, account) + require.True(t, bk.GetAllBalances(ctx, account.GetAddress()).IsZero()) tp := testProposal(recipient, amount) hdlr := NewCommunityPoolSpendProposalHandler(keeper) require.Error(t, hdlr(ctx, tp)) - require.True(t, accountKeeper.GetAccount(ctx, recipient).GetCoins().IsZero()) + + balances := bk.GetAllBalances(ctx, recipient) + require.True(t, balances.IsZero()) } diff --git a/x/distribution/simulation/operations.go b/x/distribution/simulation/operations.go index d2857e6c5aff..30bc1a61ec2e 100644 --- a/x/distribution/simulation/operations.go +++ b/x/distribution/simulation/operations.go @@ -26,7 +26,7 @@ const ( // WeightedOperations returns all the operations from the module with their respective weights func WeightedOperations( appParams simulation.AppParams, cdc *codec.Codec, ak types.AccountKeeper, - k keeper.Keeper, sk stakingkeeper.Keeper, + bk types.BankKeeper, k keeper.Keeper, sk stakingkeeper.Keeper, ) simulation.WeightedOperations { var weightMsgSetWithdrawAddress int @@ -60,26 +60,26 @@ func WeightedOperations( return simulation.WeightedOperations{ simulation.NewWeightedOperation( weightMsgSetWithdrawAddress, - SimulateMsgSetWithdrawAddress(ak, k), + SimulateMsgSetWithdrawAddress(ak, bk, k), ), simulation.NewWeightedOperation( weightMsgWithdrawDelegationReward, - SimulateMsgWithdrawDelegatorReward(ak, k, sk), + SimulateMsgWithdrawDelegatorReward(ak, bk, k, sk), ), simulation.NewWeightedOperation( weightMsgWithdrawValidatorCommission, - SimulateMsgWithdrawValidatorCommission(ak, k, sk), + SimulateMsgWithdrawValidatorCommission(ak, bk, k, sk), ), simulation.NewWeightedOperation( weightMsgFundCommunityPool, - SimulateMsgFundCommunityPool(ak, k, sk), + SimulateMsgFundCommunityPool(ak, bk, k, sk), ), } } // SimulateMsgSetWithdrawAddress generates a MsgSetWithdrawAddress with random values. // nolint: funlen -func SimulateMsgSetWithdrawAddress(ak types.AccountKeeper, k keeper.Keeper) simulation.Operation { +func SimulateMsgSetWithdrawAddress(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, ) (simulation.OperationMsg, []simulation.FutureOperation, error) { @@ -89,9 +89,11 @@ func SimulateMsgSetWithdrawAddress(ak types.AccountKeeper, k keeper.Keeper) simu simAccount, _ := simulation.RandomAcc(r, accs) simToAccount, _ := simulation.RandomAcc(r, accs) + account := ak.GetAccount(ctx, simAccount.Address) + spendable := bk.SpendableCoins(ctx, account.GetAddress()) - fees, err := simulation.RandomFees(r, ctx, account.SpendableCoins(ctx.BlockTime())) + fees, err := simulation.RandomFees(r, ctx, spendable) if err != nil { return simulation.NoOpMsg(types.ModuleName), nil, err } @@ -119,7 +121,7 @@ func SimulateMsgSetWithdrawAddress(ak types.AccountKeeper, k keeper.Keeper) simu // SimulateMsgWithdrawDelegatorReward generates a MsgWithdrawDelegatorReward with random values. // nolint: funlen -func SimulateMsgWithdrawDelegatorReward(ak types.AccountKeeper, k keeper.Keeper, sk stakingkeeper.Keeper) simulation.Operation { +func SimulateMsgWithdrawDelegatorReward(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, sk stakingkeeper.Keeper) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, ) (simulation.OperationMsg, []simulation.FutureOperation, error) { @@ -137,7 +139,9 @@ func SimulateMsgWithdrawDelegatorReward(ak types.AccountKeeper, k keeper.Keeper, } account := ak.GetAccount(ctx, simAccount.Address) - fees, err := simulation.RandomFees(r, ctx, account.SpendableCoins(ctx.BlockTime())) + spendable := bk.SpendableCoins(ctx, account.GetAddress()) + + fees, err := simulation.RandomFees(r, ctx, spendable) if err != nil { return simulation.NoOpMsg(types.ModuleName), nil, err } @@ -165,7 +169,7 @@ func SimulateMsgWithdrawDelegatorReward(ak types.AccountKeeper, k keeper.Keeper, // SimulateMsgWithdrawValidatorCommission generates a MsgWithdrawValidatorCommission with random values. // nolint: funlen -func SimulateMsgWithdrawValidatorCommission(ak types.AccountKeeper, k keeper.Keeper, sk stakingkeeper.Keeper) simulation.Operation { +func SimulateMsgWithdrawValidatorCommission(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, sk stakingkeeper.Keeper) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, ) (simulation.OperationMsg, []simulation.FutureOperation, error) { @@ -186,7 +190,9 @@ func SimulateMsgWithdrawValidatorCommission(ak types.AccountKeeper, k keeper.Kee } account := ak.GetAccount(ctx, simAccount.Address) - fees, err := simulation.RandomFees(r, ctx, account.SpendableCoins(ctx.BlockTime())) + spendable := bk.SpendableCoins(ctx, account.GetAddress()) + + fees, err := simulation.RandomFees(r, ctx, spendable) if err != nil { return simulation.NoOpMsg(types.ModuleName), nil, err } @@ -214,7 +220,7 @@ func SimulateMsgWithdrawValidatorCommission(ak types.AccountKeeper, k keeper.Kee // SimulateMsgFundCommunityPool simulates MsgFundCommunityPool execution where // a random account sends a random amount of its funds to the community pool. -func SimulateMsgFundCommunityPool(ak types.AccountKeeper, k keeper.Keeper, sk stakingkeeper.Keeper) simulation.Operation { +func SimulateMsgFundCommunityPool(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, sk stakingkeeper.Keeper) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, ) (simulation.OperationMsg, []simulation.FutureOperation, error) { @@ -222,9 +228,9 @@ func SimulateMsgFundCommunityPool(ak types.AccountKeeper, k keeper.Keeper, sk st funder, _ := simulation.RandomAcc(r, accs) account := ak.GetAccount(ctx, funder.Address) - coins := account.SpendableCoins(ctx.BlockTime()) + spendable := bk.SpendableCoins(ctx, account.GetAddress()) - fundAmount := simulation.RandSubsetCoins(r, coins) + fundAmount := simulation.RandSubsetCoins(r, spendable) if fundAmount.Empty() { return simulation.NoOpMsg(types.ModuleName), nil, nil } @@ -234,7 +240,7 @@ func SimulateMsgFundCommunityPool(ak types.AccountKeeper, k keeper.Keeper, sk st err error ) - coins, hasNeg := coins.SafeSub(fundAmount) + coins, hasNeg := spendable.SafeSub(fundAmount) if !hasNeg { fees, err = simulation.RandomFees(r, ctx, coins) if err != nil { diff --git a/x/distribution/types/expected_keepers.go b/x/distribution/types/expected_keepers.go index faa2f37235da..1f9d0a51a348 100644 --- a/x/distribution/types/expected_keepers.go +++ b/x/distribution/types/expected_keepers.go @@ -13,6 +13,15 @@ type AccountKeeper interface { GetAccount(ctx sdk.Context, addr sdk.AccAddress) authexported.Account } +// BankKeeper defines the expected interface needed to retrieve account balances. +type BankKeeper interface { + GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin + SetBalances(ctx sdk.Context, addr sdk.AccAddress, balances sdk.Coins) error + LockedCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins +} + // StakingKeeper expected staking keeper (noalias) type StakingKeeper interface { // iterate through validators by operator address, execute func for each validator diff --git a/x/evidence/internal/keeper/infraction_test.go b/x/evidence/internal/keeper/infraction_test.go index cbef53de1921..d0ae5d74239d 100644 --- a/x/evidence/internal/keeper/infraction_test.go +++ b/x/evidence/internal/keeper/infraction_test.go @@ -24,24 +24,24 @@ func (suite *KeeperTestSuite) TestHandleDoubleSign() { power := int64(100) stakingParams := suite.app.StakingKeeper.GetParams(ctx) - amt := sdk.TokensFromConsensusPower(power) + selfDelegation := sdk.TokensFromConsensusPower(power) operatorAddr, val := valAddresses[0], pubkeys[0] // create validator - res, err := staking.NewHandler(suite.app.StakingKeeper)(ctx, newTestMsgCreateValidator(operatorAddr, val, amt)) + res, err := staking.NewHandler(suite.app.StakingKeeper)(ctx, newTestMsgCreateValidator(operatorAddr, val, selfDelegation)) suite.NoError(err) suite.NotNil(res) // execute end-blocker and verify validator attributes staking.EndBlocker(ctx, suite.app.StakingKeeper) suite.Equal( - suite.app.BankKeeper.GetCoins(ctx, sdk.AccAddress(operatorAddr)), - sdk.NewCoins(sdk.NewCoin(stakingParams.BondDenom, initAmt.Sub(amt))), + suite.app.BankKeeper.GetAllBalances(ctx, sdk.AccAddress(operatorAddr)).String(), + sdk.NewCoins(sdk.NewCoin(stakingParams.BondDenom, initAmt.Sub(selfDelegation))).String(), ) - suite.Equal(amt, suite.app.StakingKeeper.Validator(ctx, operatorAddr).GetBondedTokens()) + suite.Equal(selfDelegation, suite.app.StakingKeeper.Validator(ctx, operatorAddr).GetBondedTokens()) // handle a signature to set signing info - suite.app.SlashingKeeper.HandleValidatorSignature(ctx, val.Address(), amt.Int64(), true) + suite.app.SlashingKeeper.HandleValidatorSignature(ctx, val.Address(), selfDelegation.Int64(), true) // double sign less than max age oldTokens := suite.app.StakingKeeper.Validator(ctx, operatorAddr).GetTokens() @@ -101,7 +101,7 @@ func (suite *KeeperTestSuite) TestHandleDoubleSign_TooOld() { // execute end-blocker and verify validator attributes staking.EndBlocker(ctx, suite.app.StakingKeeper) suite.Equal( - suite.app.BankKeeper.GetCoins(ctx, sdk.AccAddress(operatorAddr)), + suite.app.BankKeeper.GetAllBalances(ctx, sdk.AccAddress(operatorAddr)), sdk.NewCoins(sdk.NewCoin(stakingParams.BondDenom, initAmt.Sub(amt))), ) suite.Equal(amt, suite.app.StakingKeeper.Validator(ctx, operatorAddr).GetBondedTokens()) diff --git a/x/evidence/internal/keeper/keeper_test.go b/x/evidence/internal/keeper/keeper_test.go index 45347ab96be0..d6e35a4956a9 100644 --- a/x/evidence/internal/keeper/keeper_test.go +++ b/x/evidence/internal/keeper/keeper_test.go @@ -6,6 +6,7 @@ import ( "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/evidence" "github.com/cosmos/cosmos-sdk/x/evidence/exported" "github.com/cosmos/cosmos-sdk/x/evidence/internal/keeper" @@ -76,6 +77,11 @@ func (suite *KeeperTestSuite) SetupTest() { suite.querier = keeper.NewQuerier(*evidenceKeeper) suite.keeper = *evidenceKeeper suite.app = app + + for i, addr := range valAddresses { + addr := sdk.AccAddress(addr) + app.AccountKeeper.SetAccount(suite.ctx, auth.NewBaseAccount(addr, pubkeys[i], uint64(i), 0)) + } } func (suite *KeeperTestSuite) populateEvidence(ctx sdk.Context, numEvidence int) []exported.Evidence { diff --git a/x/genutil/client/cli/collect.go b/x/genutil/client/cli/collect.go index bc38ab74d287..f80bdabc0609 100644 --- a/x/genutil/client/cli/collect.go +++ b/x/genutil/client/cli/collect.go @@ -21,7 +21,7 @@ const flagGenTxDir = "gentx-dir" // CollectGenTxsCmd - return the cobra command to collect genesis transactions func CollectGenTxsCmd(ctx *server.Context, cdc *codec.Codec, - genAccIterator types.GenesisAccountsIterator, defaultNodeHome string) *cobra.Command { + genBalIterator types.GenesisBalancesIterator, defaultNodeHome string) *cobra.Command { cmd := &cobra.Command{ Use: "collect-gentxs", @@ -48,7 +48,7 @@ func CollectGenTxsCmd(ctx *server.Context, cdc *codec.Codec, toPrint := newPrintInfo(config.Moniker, genDoc.ChainID, nodeID, genTxsDir, json.RawMessage("")) initCfg := genutil.NewInitConfig(genDoc.ChainID, genTxsDir, name, nodeID, valPubKey) - appMessage, err := genutil.GenAppStateFromConfig(cdc, config, initCfg, *genDoc, genAccIterator) + appMessage, err := genutil.GenAppStateFromConfig(cdc, config, initCfg, *genDoc, genBalIterator) if err != nil { return errors.Wrap(err, "failed to get genesis app state from config") } diff --git a/x/genutil/client/cli/gentx.go b/x/genutil/client/cli/gentx.go index 18ef098ff670..b992f446fe7b 100644 --- a/x/genutil/client/cli/gentx.go +++ b/x/genutil/client/cli/gentx.go @@ -42,7 +42,7 @@ type StakingMsgBuildingHelpers interface { // GenTxCmd builds the application's gentx command. // nolint: errcheck func GenTxCmd(ctx *server.Context, cdc *codec.Codec, mbm module.BasicManager, smbh StakingMsgBuildingHelpers, - genAccIterator types.GenesisAccountsIterator, defaultNodeHome, defaultCLIHome string) *cobra.Command { + genBalIterator types.GenesisBalancesIterator, defaultNodeHome, defaultCLIHome string) *cobra.Command { ipDefault, _ := server.ExternalIP() fsCreateValidator, flagNodeID, flagPubKey, flagAmount, defaultsDesc := smbh.CreateValidatorMsgHelpers(ipDefault) @@ -116,7 +116,7 @@ func GenTxCmd(ctx *server.Context, cdc *codec.Codec, mbm module.BasicManager, sm return errors.Wrap(err, "failed to parse coins") } - err = genutil.ValidateAccountInGenesis(genesisState, genAccIterator, key.GetAddress(), coins, cdc) + err = genutil.ValidateAccountInGenesis(genesisState, genBalIterator, key.GetAddress(), coins, cdc) if err != nil { return errors.Wrap(err, "failed to validate account in genesis") } diff --git a/x/genutil/client/cli/migrate.go b/x/genutil/client/cli/migrate.go index 3ae77c506d61..eeba89356a95 100644 --- a/x/genutil/client/cli/migrate.go +++ b/x/genutil/client/cli/migrate.go @@ -16,6 +16,7 @@ import ( extypes "github.com/cosmos/cosmos-sdk/x/genutil" v036 "github.com/cosmos/cosmos-sdk/x/genutil/legacy/v0_36" v038 "github.com/cosmos/cosmos-sdk/x/genutil/legacy/v0_38" + v039 "github.com/cosmos/cosmos-sdk/x/genutil/legacy/v0_39" ) const ( @@ -29,6 +30,7 @@ const ( var migrationMap = extypes.MigrationMap{ "v0.36": v036.Migrate, "v0.38": v038.Migrate, // NOTE: v0.37 and v0.38 are genesis compatible + "v0.39": v039.Migrate, } // GetMigrationCallback returns a MigrationCallback for a given version. diff --git a/x/genutil/collect.go b/x/genutil/collect.go index 7145efb048a6..4e000b91b8f0 100644 --- a/x/genutil/collect.go +++ b/x/genutil/collect.go @@ -17,21 +17,21 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + bankexported "github.com/cosmos/cosmos-sdk/x/bank/exported" "github.com/cosmos/cosmos-sdk/x/genutil/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" ) // GenAppStateFromConfig gets the genesis app state from the config func GenAppStateFromConfig(cdc *codec.Codec, config *cfg.Config, - initCfg InitConfig, genDoc tmtypes.GenesisDoc, - genAccIterator types.GenesisAccountsIterator, + initCfg InitConfig, genDoc tmtypes.GenesisDoc, genBalIterator types.GenesisBalancesIterator, ) (appState json.RawMessage, err error) { // process genesis transactions, else create default genesis.json appGenTxs, persistentPeers, err := CollectStdTxs( - cdc, config.Moniker, initCfg.GenTxsDir, genDoc, genAccIterator) + cdc, config.Moniker, initCfg.GenTxsDir, genDoc, genBalIterator, + ) if err != nil { return appState, err } @@ -54,6 +54,7 @@ func GenAppStateFromConfig(cdc *codec.Codec, config *cfg.Config, if err != nil { return appState, err } + appState, err = codec.MarshalJSONIndent(cdc, appGenesisState) if err != nil { return appState, err @@ -61,13 +62,14 @@ func GenAppStateFromConfig(cdc *codec.Codec, config *cfg.Config, genDoc.AppState = appState err = ExportGenesisFile(&genDoc, config.GenesisFile()) + return appState, err } // CollectStdTxs processes and validates application's genesis StdTxs and returns // the list of appGenTxs, and persistent peers required to generate genesis.json. func CollectStdTxs(cdc *codec.Codec, moniker, genTxsDir string, - genDoc tmtypes.GenesisDoc, genAccIterator types.GenesisAccountsIterator, + genDoc tmtypes.GenesisDoc, genBalIterator types.GenesisBalancesIterator, ) (appGenTxs []authtypes.StdTx, persistentPeers string, err error) { var fos []os.FileInfo @@ -76,17 +78,18 @@ func CollectStdTxs(cdc *codec.Codec, moniker, genTxsDir string, return appGenTxs, persistentPeers, err } - // prepare a map of all accounts in genesis state to then validate + // prepare a map of all balances in genesis state to then validate // against the validators addresses var appState map[string]json.RawMessage if err := cdc.UnmarshalJSON(genDoc.AppState, &appState); err != nil { return appGenTxs, persistentPeers, err } - addrMap := make(map[string]authexported.Account) - genAccIterator.IterateGenesisAccounts(cdc, appState, - func(acc authexported.Account) (stop bool) { - addrMap[acc.GetAddress().String()] = acc + balancesMap := make(map[string]bankexported.GenesisBalance) + genBalIterator.IterateGenesisBalances( + cdc, appState, + func(balance bankexported.GenesisBalance) (stop bool) { + balancesMap[balance.GetAddress().String()] = balance return false }, ) @@ -105,10 +108,12 @@ func CollectStdTxs(cdc *codec.Codec, moniker, genTxsDir string, if jsonRawTx, err = ioutil.ReadFile(filename); err != nil { return appGenTxs, persistentPeers, err } + var genStdTx authtypes.StdTx if err = cdc.UnmarshalJSON(jsonRawTx, &genStdTx); err != nil { return appGenTxs, persistentPeers, err } + appGenTxs = append(appGenTxs, genStdTx) // the memo flag is used to store @@ -116,39 +121,36 @@ func CollectStdTxs(cdc *codec.Codec, moniker, genTxsDir string, // "528fd3df22b31f4969b05652bfe8f0fe921321d5@192.168.2.37:26656" nodeAddrIP := genStdTx.GetMemo() if len(nodeAddrIP) == 0 { - return appGenTxs, persistentPeers, fmt.Errorf( - "couldn't find node's address and IP in %s", fo.Name()) + return appGenTxs, persistentPeers, fmt.Errorf("failed to find node's address and IP in %s", fo.Name()) } // genesis transactions must be single-message msgs := genStdTx.GetMsgs() if len(msgs) != 1 { - return appGenTxs, persistentPeers, errors.New( - "each genesis transaction must provide a single genesis message") + return appGenTxs, persistentPeers, errors.New("each genesis transaction must provide a single genesis message") } // TODO abstract out staking message validation back to staking msg := msgs[0].(stakingtypes.MsgCreateValidator) + // validate delegator and validator addresses and funds against the accounts in the state delAddr := msg.DelegatorAddress.String() valAddr := sdk.AccAddress(msg.ValidatorAddress).String() - delAcc, delOk := addrMap[delAddr] + delBal, delOk := balancesMap[delAddr] if !delOk { - return appGenTxs, persistentPeers, fmt.Errorf( - "account %v not in genesis.json: %+v", delAddr, addrMap) + return appGenTxs, persistentPeers, fmt.Errorf("account %s balance not in genesis state: %+v", delAddr, balancesMap) } - _, valOk := addrMap[valAddr] + _, valOk := balancesMap[valAddr] if !valOk { - return appGenTxs, persistentPeers, fmt.Errorf( - "account %v not in genesis.json: %+v", valAddr, addrMap) + return appGenTxs, persistentPeers, fmt.Errorf("account %s balance not in genesis state: %+v", valAddr, balancesMap) } - if delAcc.GetCoins().AmountOf(msg.Value.Denom).LT(msg.Value.Amount) { + if delBal.GetCoins().AmountOf(msg.Value.Denom).LT(msg.Value.Amount) { return appGenTxs, persistentPeers, fmt.Errorf( "insufficient fund for delegation %v: %v < %v", - delAcc.GetAddress(), delAcc.GetCoins().AmountOf(msg.Value.Denom), msg.Value.Amount, + delBal.GetAddress().String(), delBal.GetCoins().AmountOf(msg.Value.Denom), msg.Value.Amount, ) } diff --git a/x/genutil/gentx.go b/x/genutil/gentx.go index 1ac4e64ed4c6..577fedcef6a9 100644 --- a/x/genutil/gentx.go +++ b/x/genutil/gentx.go @@ -10,24 +10,26 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + bankexported "github.com/cosmos/cosmos-sdk/x/bank/exported" "github.com/cosmos/cosmos-sdk/x/genutil/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" ) // SetGenTxsInAppGenesisState - sets the genesis transactions in the app genesis state -func SetGenTxsInAppGenesisState(cdc *codec.Codec, appGenesisState map[string]json.RawMessage, - genTxs []authtypes.StdTx) (map[string]json.RawMessage, error) { +func SetGenTxsInAppGenesisState( + cdc *codec.Codec, appGenesisState map[string]json.RawMessage, genTxs []authtypes.StdTx, +) (map[string]json.RawMessage, error) { genesisState := GetGenesisStateFromAppState(cdc, appGenesisState) - // convert all the GenTxs to JSON genTxsBz := make([]json.RawMessage, 0, len(genTxs)) + for _, genTx := range genTxs { txBz, err := cdc.MarshalJSON(genTx) if err != nil { return appGenesisState, err } + genTxsBz = append(genTxsBz, txBz) } @@ -35,53 +37,52 @@ func SetGenTxsInAppGenesisState(cdc *codec.Codec, appGenesisState map[string]jso return SetGenesisStateInAppState(cdc, appGenesisState, genesisState), nil } -// ValidateAccountInGenesis checks that the provided key has sufficient -// coins in the genesis accounts -func ValidateAccountInGenesis(appGenesisState map[string]json.RawMessage, - genAccIterator types.GenesisAccountsIterator, - key sdk.Address, coins sdk.Coins, cdc *codec.Codec) error { - - accountIsInGenesis := false +// ValidateAccountInGenesis checks that the provided account has a sufficient +// balance in the set of genesis accounts. +func ValidateAccountInGenesis( + appGenesisState map[string]json.RawMessage, genBalIterator types.GenesisBalancesIterator, + addr sdk.Address, coins sdk.Coins, cdc *codec.Codec, +) error { - // TODO: refactor out bond denom to common state area - stakingDataBz := appGenesisState[stakingtypes.ModuleName] var stakingData stakingtypes.GenesisState - cdc.MustUnmarshalJSON(stakingDataBz, &stakingData) + cdc.MustUnmarshalJSON(appGenesisState[stakingtypes.ModuleName], &stakingData) bondDenom := stakingData.Params.BondDenom - genUtilDataBz := appGenesisState[stakingtypes.ModuleName] - var genesisState GenesisState - cdc.MustUnmarshalJSON(genUtilDataBz, &genesisState) - var err error - genAccIterator.IterateGenesisAccounts(cdc, appGenesisState, - func(acc authexported.Account) (stop bool) { - accAddress := acc.GetAddress() - accCoins := acc.GetCoins() - // Ensure that account is in genesis - if accAddress.Equals(key) { + accountIsInGenesis := false + + genBalIterator.IterateGenesisBalances(cdc, appGenesisState, + func(bal bankexported.GenesisBalance) (stop bool) { + accAddress := bal.GetAddress() + accCoins := bal.GetCoins() - // Ensure account contains enough funds of default bond denom + // ensure that account is in genesis + if accAddress.Equals(addr) { + // ensure account contains enough funds of default bond denom if coins.AmountOf(bondDenom).GT(accCoins.AmountOf(bondDenom)) { err = fmt.Errorf( - "account %v is in genesis, but it only has %v%v available to stake, not %v%v", - key.String(), accCoins.AmountOf(bondDenom), bondDenom, coins.AmountOf(bondDenom), bondDenom, + "account %s has a balance in genesis, but it only has %v%s available to stake, not %v%s", + addr, accCoins.AmountOf(bondDenom), bondDenom, coins.AmountOf(bondDenom), bondDenom, ) + return true } + accountIsInGenesis = true return true } + return false }, ) + if err != nil { return err } if !accountIsInGenesis { - return fmt.Errorf("account %s in not in the app_state.accounts array of genesis.json", key) + return fmt.Errorf("account %s does not have a balance in the genesis state", addr) } return nil @@ -89,18 +90,25 @@ func ValidateAccountInGenesis(appGenesisState map[string]json.RawMessage, type deliverTxfn func(abci.RequestDeliverTx) abci.ResponseDeliverTx -// DeliverGenTxs - deliver a genesis transaction -func DeliverGenTxs(ctx sdk.Context, cdc *codec.Codec, genTxs []json.RawMessage, - stakingKeeper types.StakingKeeper, deliverTx deliverTxfn) []abci.ValidatorUpdate { +// DeliverGenTxs iterates over all genesis txs, decodes each into a StdTx and +// invokes the provided deliverTxfn with the decoded StdTx. It returns the result +// of the staking module's ApplyAndReturnValidatorSetUpdates. +func DeliverGenTxs( + ctx sdk.Context, cdc *codec.Codec, genTxs []json.RawMessage, + stakingKeeper types.StakingKeeper, deliverTx deliverTxfn, +) []abci.ValidatorUpdate { for _, genTx := range genTxs { var tx authtypes.StdTx cdc.MustUnmarshalJSON(genTx, &tx) + bz := cdc.MustMarshalBinaryLengthPrefixed(tx) + res := deliverTx(abci.RequestDeliverTx{Tx: bz}) if !res.IsOK() { panic(res.Log) } } + return stakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) } diff --git a/x/genutil/legacy/v0_39/migrate.go b/x/genutil/legacy/v0_39/migrate.go new file mode 100644 index 000000000000..aea5ccd3f91e --- /dev/null +++ b/x/genutil/legacy/v0_39/migrate.go @@ -0,0 +1,55 @@ +package v039 + +import ( + "github.com/cosmos/cosmos-sdk/codec" + v038auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v0_38" + v039auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v0_39" + v038bank "github.com/cosmos/cosmos-sdk/x/bank/legacy/v0_38" + v039bank "github.com/cosmos/cosmos-sdk/x/bank/legacy/v0_39" + "github.com/cosmos/cosmos-sdk/x/genutil" +) + +func Migrate(appState genutil.AppMap) genutil.AppMap { + v038Codec := codec.New() + codec.RegisterCrypto(v038Codec) + v038auth.RegisterCodec(v038Codec) + + v039Codec := codec.New() + codec.RegisterCrypto(v039Codec) + v038auth.RegisterCodec(v039Codec) + + // remove balances from existing accounts + if appState[v038auth.ModuleName] != nil { + // unmarshal relative source genesis application state + var authGenState v038auth.GenesisState + v038Codec.MustUnmarshalJSON(appState[v038auth.ModuleName], &authGenState) + + // delete deprecated x/auth genesis state + delete(appState, v038auth.ModuleName) + + // Migrate relative source genesis application state and marshal it into + // the respective key. + appState[v039auth.ModuleName] = v039Codec.MustMarshalJSON(v039auth.Migrate(authGenState)) + } + + if appState[v038bank.ModuleName] != nil { + // unmarshal relative source genesis application state + var bankGenState v038bank.GenesisState + v038Codec.MustUnmarshalJSON(appState[v038bank.ModuleName], &bankGenState) + + // unmarshal x/auth genesis state to retrieve all account balances + var authGenState v038auth.GenesisState + v038Codec.MustUnmarshalJSON(appState[v038auth.ModuleName], &authGenState) + + // delete deprecated x/bank genesis state + delete(appState, v038bank.ModuleName) + + // Migrate relative source genesis application state and marshal it into + // the respective key. + appState[v039bank.ModuleName] = v039Codec.MustMarshalJSON( + v039bank.Migrate(bankGenState, authGenState), + ) + } + + return appState +} diff --git a/x/genutil/types/expected_keepers.go b/x/genutil/types/expected_keepers.go index b44236d7d8d1..bd0e750f2f8b 100644 --- a/x/genutil/types/expected_keepers.go +++ b/x/genutil/types/expected_keepers.go @@ -8,6 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" + bankexported "github.com/cosmos/cosmos-sdk/x/bank/exported" ) // StakingKeeper defines the expected staking keeper (noalias) @@ -27,6 +28,15 @@ type GenesisAccountsIterator interface { IterateGenesisAccounts( cdc *codec.Codec, appGenesis map[string]json.RawMessage, - iterateFn func(authexported.Account) (stop bool), + cb func(authexported.Account) (stop bool), + ) +} + +// GenesisAccountsIterator defines the expected iterating genesis accounts object (noalias) +type GenesisBalancesIterator interface { + IterateGenesisBalances( + cdc *codec.Codec, + appGenesis map[string]json.RawMessage, + cb func(bankexported.GenesisBalance) (stop bool), ) } diff --git a/x/gov/abci_test.go b/x/gov/abci_test.go index db5509f45e18..355abed3e84e 100644 --- a/x/gov/abci_test.go +++ b/x/gov/abci_test.go @@ -5,7 +5,6 @@ import ( "time" "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -263,7 +262,7 @@ func TestProposalPassedEndblocker(t *testing.T) { macc := input.keeper.GetGovernanceAccount(ctx) require.NotNil(t, macc) - initialModuleAccCoins := macc.GetCoins() + initialModuleAccCoins := input.bk.GetAllBalances(ctx, macc.GetAddress()) proposal, err := input.keeper.SubmitProposal(ctx, keep.TestProposal) require.NoError(t, err) @@ -277,7 +276,7 @@ func TestProposalPassedEndblocker(t *testing.T) { macc = input.keeper.GetGovernanceAccount(ctx) require.NotNil(t, macc) - moduleAccCoins := macc.GetCoins() + moduleAccCoins := input.bk.GetAllBalances(ctx, macc.GetAddress()) deposits := initialModuleAccCoins.Add(proposal.TotalDeposit...).Add(proposalCoins...) require.True(t, moduleAccCoins.IsEqual(deposits)) @@ -293,7 +292,7 @@ func TestProposalPassedEndblocker(t *testing.T) { macc = input.keeper.GetGovernanceAccount(ctx) require.NotNil(t, macc) - require.True(t, macc.GetCoins().IsEqual(initialModuleAccCoins)) + require.True(t, input.bk.GetAllBalances(ctx, macc.GetAddress()).IsEqual(initialModuleAccCoins)) } func TestEndBlockerProposalHandlerFailed(t *testing.T) { diff --git a/x/gov/genesis.go b/x/gov/genesis.go index b487c23ef85d..f0eec06e1107 100644 --- a/x/gov/genesis.go +++ b/x/gov/genesis.go @@ -8,8 +8,7 @@ import ( ) // InitGenesis - store genesis parameters -func InitGenesis(ctx sdk.Context, k Keeper, supplyKeeper types.SupplyKeeper, data GenesisState) { - +func InitGenesis(ctx sdk.Context, bk types.BankKeeper, supplyKeeper types.SupplyKeeper, k Keeper, data GenesisState) { k.SetProposalID(ctx, data.StartingProposalID) k.SetDepositParams(ctx, data.DepositParams) k.SetVotingParams(ctx, data.VotingParams) @@ -42,8 +41,8 @@ func InitGenesis(ctx sdk.Context, k Keeper, supplyKeeper types.SupplyKeeper, dat } // add coins if not provided on genesis - if moduleAcc.GetCoins().IsZero() { - if err := moduleAcc.SetCoins(totalDeposits); err != nil { + if bk.GetAllBalances(ctx, moduleAcc.GetAddress()).IsZero() { + if err := bk.SetBalances(ctx, moduleAcc.GetAddress(), totalDeposits); err != nil { panic(err) } supplyKeeper.SetModuleAccount(ctx, moduleAcc) diff --git a/x/gov/genesis_test.go b/x/gov/genesis_test.go index 02b6eed9b42c..0add3343c406 100644 --- a/x/gov/genesis_test.go +++ b/x/gov/genesis_test.go @@ -3,9 +3,8 @@ package gov import ( "testing" - "github.com/stretchr/testify/require" - keep "github.com/cosmos/cosmos-sdk/x/gov/keeper" + "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" ) @@ -63,7 +62,8 @@ func TestImportExportQueues(t *testing.T) { require.True(t, proposal1.Status == StatusDepositPeriod) require.True(t, proposal2.Status == StatusVotingPeriod) - require.Equal(t, input2.keeper.GetDepositParams(ctx2).MinDeposit, input2.keeper.GetGovernanceAccount(ctx2).GetCoins()) + macc := input2.keeper.GetGovernanceAccount(ctx2) + require.Equal(t, input2.keeper.GetDepositParams(ctx2).MinDeposit, input2.bk.GetAllBalances(ctx2, macc.GetAddress())) // Run the endblocker. Check to make sure that proposal1 is removed from state, and proposal2 is finished VotingPeriod. EndBlocker(ctx2, input2.keeper) diff --git a/x/gov/keeper/deposit_test.go b/x/gov/keeper/deposit_test.go index edf452464094..ed17d4481551 100644 --- a/x/gov/keeper/deposit_test.go +++ b/x/gov/keeper/deposit_test.go @@ -10,7 +10,7 @@ import ( ) func TestDeposits(t *testing.T) { - ctx, ak, keeper, _, _ := createTestInput(t, false, 100) + ctx, _, bk, keeper, _, _ := createTestInput(t, false, 100) tp := TestProposal proposal, err := keeper.SubmitProposal(ctx, tp) @@ -20,8 +20,8 @@ func TestDeposits(t *testing.T) { fourStake := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(4))) fiveStake := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(5))) - addr0Initial := ak.GetAccount(ctx, TestAddrs[0]).GetCoins() - addr1Initial := ak.GetAccount(ctx, TestAddrs[1]).GetCoins() + addr0Initial := bk.GetAllBalances(ctx, TestAddrs[0]) + addr1Initial := bk.GetAllBalances(ctx, TestAddrs[1]) require.True(t, proposal.TotalDeposit.IsEqual(sdk.NewCoins())) @@ -43,7 +43,7 @@ func TestDeposits(t *testing.T) { proposal, ok = keeper.GetProposal(ctx, proposalID) require.True(t, ok) require.Equal(t, fourStake, proposal.TotalDeposit) - require.Equal(t, addr0Initial.Sub(fourStake), ak.GetAccount(ctx, TestAddrs[0]).GetCoins()) + require.Equal(t, addr0Initial.Sub(fourStake), bk.GetAllBalances(ctx, TestAddrs[0])) // Check a second deposit from same address votingStarted, err = keeper.AddDeposit(ctx, proposalID, TestAddrs[0], fiveStake) @@ -56,7 +56,7 @@ func TestDeposits(t *testing.T) { proposal, ok = keeper.GetProposal(ctx, proposalID) require.True(t, ok) require.Equal(t, fourStake.Add(fiveStake...), proposal.TotalDeposit) - require.Equal(t, addr0Initial.Sub(fourStake).Sub(fiveStake), ak.GetAccount(ctx, TestAddrs[0]).GetCoins()) + require.Equal(t, addr0Initial.Sub(fourStake).Sub(fiveStake), bk.GetAllBalances(ctx, TestAddrs[0])) // Check third deposit from a new address votingStarted, err = keeper.AddDeposit(ctx, proposalID, TestAddrs[1], fourStake) @@ -69,7 +69,7 @@ func TestDeposits(t *testing.T) { proposal, ok = keeper.GetProposal(ctx, proposalID) require.True(t, ok) require.Equal(t, fourStake.Add(fiveStake...).Add(fourStake...), proposal.TotalDeposit) - require.Equal(t, addr1Initial.Sub(fourStake), ak.GetAccount(ctx, TestAddrs[1]).GetCoins()) + require.Equal(t, addr1Initial.Sub(fourStake), bk.GetAllBalances(ctx, TestAddrs[1])) // Check that proposal moved to voting period proposal, ok = keeper.GetProposal(ctx, proposalID) @@ -93,6 +93,6 @@ func TestDeposits(t *testing.T) { keeper.RefundDeposits(ctx, proposalID) deposit, found = keeper.GetDeposit(ctx, proposalID, TestAddrs[1]) require.False(t, found) - require.Equal(t, addr0Initial, ak.GetAccount(ctx, TestAddrs[0]).GetCoins()) - require.Equal(t, addr1Initial, ak.GetAccount(ctx, TestAddrs[1]).GetCoins()) + require.Equal(t, addr0Initial, bk.GetAllBalances(ctx, TestAddrs[0])) + require.Equal(t, addr1Initial, bk.GetAllBalances(ctx, TestAddrs[1])) } diff --git a/x/gov/keeper/invariants.go b/x/gov/keeper/invariants.go index 1ebe62c15d0a..d0ec4dbfacc8 100644 --- a/x/gov/keeper/invariants.go +++ b/x/gov/keeper/invariants.go @@ -10,20 +10,20 @@ import ( ) // RegisterInvariants registers all governance invariants -func RegisterInvariants(ir sdk.InvariantRegistry, keeper Keeper) { - ir.RegisterRoute(types.ModuleName, "module-account", ModuleAccountInvariant(keeper)) +func RegisterInvariants(ir sdk.InvariantRegistry, keeper Keeper, bk types.BankKeeper) { + ir.RegisterRoute(types.ModuleName, "module-account", ModuleAccountInvariant(keeper, bk)) } // AllInvariants runs all invariants of the governance module -func AllInvariants(keeper Keeper) sdk.Invariant { +func AllInvariants(keeper Keeper, bk types.BankKeeper) sdk.Invariant { return func(ctx sdk.Context) (string, bool) { - return ModuleAccountInvariant(keeper)(ctx) + return ModuleAccountInvariant(keeper, bk)(ctx) } } // ModuleAccountInvariant checks that the module account coins reflects the sum of // deposit amounts held on store -func ModuleAccountInvariant(keeper Keeper) sdk.Invariant { +func ModuleAccountInvariant(keeper Keeper, bk types.BankKeeper) sdk.Invariant { return func(ctx sdk.Context) (string, bool) { var expectedDeposits sdk.Coins @@ -33,10 +33,11 @@ func ModuleAccountInvariant(keeper Keeper) sdk.Invariant { }) macc := keeper.GetGovernanceAccount(ctx) - broken := !macc.GetCoins().IsEqual(expectedDeposits) + balances := bk.GetAllBalances(ctx, macc.GetAddress()) + broken := !balances.IsEqual(expectedDeposits) return sdk.FormatInvariant(types.ModuleName, "deposits", fmt.Sprintf("\tgov ModuleAccount coins: %s\n\tsum of deposit amounts: %s\n", - macc.GetCoins(), expectedDeposits)), broken + balances, expectedDeposits)), broken } } diff --git a/x/gov/keeper/keeper_test.go b/x/gov/keeper/keeper_test.go index 5549049e3a35..9cd2a0559e65 100644 --- a/x/gov/keeper/keeper_test.go +++ b/x/gov/keeper/keeper_test.go @@ -9,7 +9,7 @@ import ( ) func TestIncrementProposalNumber(t *testing.T) { - ctx, _, keeper, _, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, _, _ := createTestInput(t, false, 100) // nolint: dogsled tp := TestProposal keeper.SubmitProposal(ctx, tp) @@ -24,7 +24,7 @@ func TestIncrementProposalNumber(t *testing.T) { } func TestProposalQueues(t *testing.T) { - ctx, _, keeper, _, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, _, _ := createTestInput(t, false, 100) // nolint: dogsled // create test proposals tp := TestProposal diff --git a/x/gov/keeper/proposal_test.go b/x/gov/keeper/proposal_test.go index b8f37cbd3649..5848e0d753e9 100644 --- a/x/gov/keeper/proposal_test.go +++ b/x/gov/keeper/proposal_test.go @@ -14,7 +14,7 @@ import ( ) func TestGetSetProposal(t *testing.T) { - ctx, _, keeper, _, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, _, _ := createTestInput(t, false, 100) // nolint: dogsled tp := TestProposal proposal, err := keeper.SubmitProposal(ctx, tp) @@ -28,7 +28,7 @@ func TestGetSetProposal(t *testing.T) { } func TestActivateVotingPeriod(t *testing.T) { - ctx, _, keeper, _, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, _, _ := createTestInput(t, false, 100) // nolint: dogsled tp := TestProposal proposal, err := keeper.SubmitProposal(ctx, tp) @@ -97,7 +97,7 @@ func registerTestCodec(cdc *codec.Codec) { } func TestSubmitProposal(t *testing.T) { - ctx, _, keeper, _, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, _, _ := createTestInput(t, false, 100) // nolint: dogsled registerTestCodec(keeper.cdc) @@ -125,7 +125,7 @@ func TestSubmitProposal(t *testing.T) { func TestGetProposalsFiltered(t *testing.T) { proposalID := uint64(1) - ctx, _, keeper, _, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, _, _ := createTestInput(t, false, 100) // nolint: dogsled status := []types.ProposalStatus{types.StatusDepositPeriod, types.StatusVotingPeriod} addr1 := sdk.AccAddress("foo") diff --git a/x/gov/keeper/querier_test.go b/x/gov/keeper/querier_test.go index f79057f03e96..54aeae6fe7a5 100644 --- a/x/gov/keeper/querier_test.go +++ b/x/gov/keeper/querier_test.go @@ -142,7 +142,7 @@ func getQueriedVotes(t *testing.T, ctx sdk.Context, cdc *codec.Codec, querier sd } func TestQueries(t *testing.T) { - ctx, _, keeper, _, _ := createTestInput(t, false, 1000) + ctx, _, _, keeper, _, _ := createTestInput(t, false, 1000) // nolint: dogsled querier := NewQuerier(keeper) oneCoins := sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 1)) @@ -285,7 +285,7 @@ func TestQueries(t *testing.T) { } func TestPaginatedVotesQuery(t *testing.T) { - ctx, _, keeper, _, _ := createTestInput(t, false, 1000) + ctx, _, _, keeper, _, _ := createTestInput(t, false, 1000) // nolint: dogsled proposal := types.Proposal{ ProposalID: 100, diff --git a/x/gov/keeper/tally_test.go b/x/gov/keeper/tally_test.go index ceaed4eb4437..52812793c951 100644 --- a/x/gov/keeper/tally_test.go +++ b/x/gov/keeper/tally_test.go @@ -11,7 +11,7 @@ import ( ) func TestTallyNoOneVotes(t *testing.T) { - ctx, _, keeper, sk, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{5, 5, 5}) tp := TestProposal @@ -31,7 +31,7 @@ func TestTallyNoOneVotes(t *testing.T) { } func TestTallyNoQuorum(t *testing.T) { - ctx, _, keeper, sk, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{2, 5, 0}) tp := TestProposal @@ -52,7 +52,7 @@ func TestTallyNoQuorum(t *testing.T) { } func TestTallyOnlyValidatorsAllYes(t *testing.T) { - ctx, _, keeper, sk, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{5, 5, 5}) tp := TestProposal @@ -76,7 +76,7 @@ func TestTallyOnlyValidatorsAllYes(t *testing.T) { } func TestTallyOnlyValidators51No(t *testing.T) { - ctx, _, keeper, sk, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{5, 6, 0}) tp := TestProposal @@ -98,7 +98,7 @@ func TestTallyOnlyValidators51No(t *testing.T) { } func TestTallyOnlyValidators51Yes(t *testing.T) { - ctx, _, keeper, sk, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{5, 6, 0}) tp := TestProposal @@ -121,7 +121,7 @@ func TestTallyOnlyValidators51Yes(t *testing.T) { } func TestTallyOnlyValidatorsVetoed(t *testing.T) { - ctx, _, keeper, sk, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{6, 6, 7}) tp := TestProposal @@ -146,7 +146,7 @@ func TestTallyOnlyValidatorsVetoed(t *testing.T) { } func TestTallyOnlyValidatorsAbstainPasses(t *testing.T) { - ctx, _, keeper, sk, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{6, 6, 7}) tp := TestProposal @@ -170,7 +170,7 @@ func TestTallyOnlyValidatorsAbstainPasses(t *testing.T) { } func TestTallyOnlyValidatorsAbstainFails(t *testing.T) { - ctx, _, keeper, sk, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{6, 6, 7}) tp := TestProposal @@ -194,7 +194,7 @@ func TestTallyOnlyValidatorsAbstainFails(t *testing.T) { } func TestTallyOnlyValidatorsNonVoter(t *testing.T) { - ctx, _, keeper, sk, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{5, 6, 7}) tp := TestProposal @@ -217,7 +217,7 @@ func TestTallyOnlyValidatorsNonVoter(t *testing.T) { } func TestTallyDelgatorOverride(t *testing.T) { - ctx, _, keeper, sk, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{5, 6, 7}) delTokens := sdk.TokensFromConsensusPower(30) @@ -251,7 +251,7 @@ func TestTallyDelgatorOverride(t *testing.T) { } func TestTallyDelgatorInherit(t *testing.T) { - ctx, _, keeper, sk, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{5, 6, 7}) delTokens := sdk.TokensFromConsensusPower(30) @@ -284,7 +284,7 @@ func TestTallyDelgatorInherit(t *testing.T) { } func TestTallyDelgatorMultipleOverride(t *testing.T) { - ctx, _, keeper, sk, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{5, 6, 7}) delTokens := sdk.TokensFromConsensusPower(10) @@ -322,7 +322,7 @@ func TestTallyDelgatorMultipleOverride(t *testing.T) { } func TestTallyDelgatorMultipleInherit(t *testing.T) { - ctx, _, keeper, sk, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{25, 6, 7}) delTokens := sdk.TokensFromConsensusPower(10) @@ -359,7 +359,7 @@ func TestTallyDelgatorMultipleInherit(t *testing.T) { } func TestTallyJailedValidator(t *testing.T) { - ctx, _, keeper, sk, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{25, 6, 7}) delTokens := sdk.TokensFromConsensusPower(10) @@ -398,7 +398,7 @@ func TestTallyJailedValidator(t *testing.T) { } func TestTallyValidatorMultipleDelegations(t *testing.T) { - ctx, _, keeper, sk, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{10, 10, 10}) delTokens := sdk.TokensFromConsensusPower(10) diff --git a/x/gov/keeper/test_common.go b/x/gov/keeper/test_common.go index 777d71a8c887..897ad8b05da5 100644 --- a/x/gov/keeper/test_common.go +++ b/x/gov/keeper/test_common.go @@ -52,6 +52,9 @@ var ( delAddr1, delAddr2, delAddr3, valAccAddr1, valAccAddr2, valAccAddr3, } + pubkeys = []crypto.PubKey{ + delPk1, delPk2, delPk3, valOpPk1, valOpPk2, valOpPk3, + } emptyDelAddr sdk.AccAddress emptyValAddr sdk.ValAddress @@ -88,11 +91,14 @@ func makeTestCodec() *codec.Codec { return cdc } -func createTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context, auth.AccountKeeper, Keeper, staking.Keeper, types.SupplyKeeper) { +func createTestInput( + t *testing.T, isCheckTx bool, initPower int64, +) (sdk.Context, auth.AccountKeeper, bank.Keeper, Keeper, staking.Keeper, types.SupplyKeeper, +) { initTokens := sdk.TokensFromConsensusPower(initPower) - keyAcc := sdk.NewKVStoreKey(auth.StoreKey) + keyBank := sdk.NewKVStoreKey(bank.StoreKey) keyGov := sdk.NewKVStoreKey(types.StoreKey) keyStaking := sdk.NewKVStoreKey(staking.StoreKey) keySupply := sdk.NewKVStoreKey(supply.StoreKey) @@ -104,6 +110,7 @@ func createTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context ms.MountStoreWithDB(keyAcc, sdk.StoreTypeIAVL, db) ms.MountStoreWithDB(keySupply, sdk.StoreTypeIAVL, db) + ms.MountStoreWithDB(keyBank, sdk.StoreTypeIAVL, db) ms.MountStoreWithDB(keyGov, sdk.StoreTypeIAVL, db) ms.MountStoreWithDB(keyStaking, sdk.StoreTypeIAVL, db) ms.MountStoreWithDB(keyParams, sdk.StoreTypeIAVL, db) @@ -141,10 +148,10 @@ func createTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context pk := params.NewKeeper(cdc, keyParams, tkeyParams) accountKeeper := auth.NewAccountKeeper(cdc, keyAcc, pk.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount) - bankKeeper := bank.NewBaseKeeper(accountKeeper, pk.Subspace(bank.DefaultParamspace), blacklistedAddrs) + bankKeeper := bank.NewBaseKeeper(cdc, keyBank, accountKeeper, pk.Subspace(bank.DefaultParamspace), blacklistedAddrs) supplyKeeper := supply.NewKeeper(cdc, keySupply, accountKeeper, bankKeeper, maccPerms) - sk := staking.NewKeeper(cdc, keyStaking, supplyKeeper, pk.Subspace(staking.DefaultParamspace)) + sk := staking.NewKeeper(cdc, keyStaking, bankKeeper, supplyKeeper, pk.Subspace(staking.DefaultParamspace)) sk.SetParams(ctx, staking.DefaultParams()) rtr := types.NewRouter(). @@ -163,9 +170,9 @@ func createTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context totalSupply := sdk.NewCoins(sdk.NewCoin(sk.BondDenom(ctx), initTokens.MulRaw(int64(len(TestAddrs))))) supplyKeeper.SetSupply(ctx, supply.NewSupply(totalSupply)) - for _, addr := range TestAddrs { - _, err := bankKeeper.AddCoins(ctx, addr, initCoins) - require.Nil(t, err) + for i, addr := range TestAddrs { + accountKeeper.SetAccount(ctx, auth.NewBaseAccount(addr, pubkeys[i], uint64(i), 0)) + require.NoError(t, bankKeeper.SetBalances(ctx, addr, initCoins)) } keeper.supplyKeeper.SetModuleAccount(ctx, feeCollectorAcc) @@ -173,7 +180,7 @@ func createTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context keeper.supplyKeeper.SetModuleAccount(ctx, bondPool) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) - return ctx, accountKeeper, keeper, sk, supplyKeeper + return ctx, accountKeeper, bankKeeper, keeper, sk, supplyKeeper } // ProposalEqual checks if two proposals are equal (note: slow, for tests only) diff --git a/x/gov/keeper/vote_test.go b/x/gov/keeper/vote_test.go index 36c02d091374..ae25c7fcc230 100644 --- a/x/gov/keeper/vote_test.go +++ b/x/gov/keeper/vote_test.go @@ -9,7 +9,7 @@ import ( ) func TestVotes(t *testing.T) { - ctx, _, keeper, _, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, _, _ := createTestInput(t, false, 100) // nolint: dogsled tp := TestProposal proposal, err := keeper.SubmitProposal(ctx, tp) diff --git a/x/gov/module.go b/x/gov/module.go index 7ad5ecbc0ace..bd2cabb97e78 100644 --- a/x/gov/module.go +++ b/x/gov/module.go @@ -102,16 +102,18 @@ type AppModule struct { keeper Keeper accountKeeper types.AccountKeeper + bankKeeper types.BankKeeper supplyKeeper types.SupplyKeeper } // NewAppModule creates a new AppModule object -func NewAppModule(keeper Keeper, accountKeeper types.AccountKeeper, supplyKeeper types.SupplyKeeper) AppModule { +func NewAppModule(keeper Keeper, ak types.AccountKeeper, bk types.BankKeeper, sk types.SupplyKeeper) AppModule { return AppModule{ AppModuleBasic: AppModuleBasic{}, keeper: keeper, - accountKeeper: accountKeeper, - supplyKeeper: supplyKeeper, + accountKeeper: ak, + bankKeeper: bk, + supplyKeeper: sk, } } @@ -122,7 +124,7 @@ func (AppModule) Name() string { // RegisterInvariants registers module invariants func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) { - RegisterInvariants(ir, am.keeper) + RegisterInvariants(ir, am.keeper, am.bankKeeper) } // Route returns the message routing key for the gov module. @@ -150,7 +152,7 @@ func (am AppModule) NewQuerierHandler() sdk.Querier { func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate { var genesisState GenesisState ModuleCdc.MustUnmarshalJSON(data, &genesisState) - InitGenesis(ctx, am.keeper, am.supplyKeeper, genesisState) + InitGenesis(ctx, am.bankKeeper, am.supplyKeeper, am.keeper, genesisState) return []abci.ValidatorUpdate{} } @@ -200,5 +202,6 @@ func (AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { func (am AppModule) WeightedOperations(simState module.SimulationState) []sim.WeightedOperation { return simulation.WeightedOperations( simState.AppParams, simState.Cdc, - am.accountKeeper, am.keeper, simState.Contents) + am.accountKeeper, am.bankKeeper, am.keeper, simState.Contents, + ) } diff --git a/x/gov/simulation/operations.go b/x/gov/simulation/operations.go index b53a97350146..91659bd423a1 100644 --- a/x/gov/simulation/operations.go +++ b/x/gov/simulation/operations.go @@ -24,8 +24,10 @@ const ( ) // WeightedOperations returns all the operations from the module with their respective weights -func WeightedOperations(appParams simulation.AppParams, cdc *codec.Codec, ak types.AccountKeeper, - k keeper.Keeper, wContents []simulation.WeightedProposalContent) simulation.WeightedOperations { +func WeightedOperations( + appParams simulation.AppParams, cdc *codec.Codec, ak types.AccountKeeper, + bk types.BankKeeper, k keeper.Keeper, wContents []simulation.WeightedProposalContent, +) simulation.WeightedOperations { var ( weightMsgDeposit int @@ -57,7 +59,7 @@ func WeightedOperations(appParams simulation.AppParams, cdc *codec.Codec, ak typ wProposalOps, simulation.NewWeightedOperation( weight, - SimulateSubmitProposal(ak, k, wContent.ContentSimulatorFn), + SimulateSubmitProposal(ak, bk, k, wContent.ContentSimulatorFn), ), ) } @@ -65,11 +67,11 @@ func WeightedOperations(appParams simulation.AppParams, cdc *codec.Codec, ak typ wGovOps := simulation.WeightedOperations{ simulation.NewWeightedOperation( weightMsgDeposit, - SimulateMsgDeposit(ak, k), + SimulateMsgDeposit(ak, bk, k), ), simulation.NewWeightedOperation( weightMsgVote, - SimulateMsgVote(ak, k), + SimulateMsgVote(ak, bk, k), ), } @@ -81,7 +83,7 @@ func WeightedOperations(appParams simulation.AppParams, cdc *codec.Codec, ak typ // future operations. // nolint: funlen func SimulateSubmitProposal( - ak types.AccountKeeper, k keeper.Keeper, contentSim simulation.ContentSimulatorFn, + ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, contentSim simulation.ContentSimulatorFn, ) simulation.Operation { // The states are: // column 1: All validators vote @@ -115,7 +117,7 @@ func SimulateSubmitProposal( } simAccount, _ := simulation.RandomAcc(r, accs) - deposit, skip, err := randomDeposit(r, ctx, ak, k, simAccount.Address) + deposit, skip, err := randomDeposit(r, ctx, ak, bk, k, simAccount.Address) switch { case skip: return simulation.NoOpMsg(types.ModuleName), nil, nil @@ -126,10 +128,10 @@ func SimulateSubmitProposal( msg := types.NewMsgSubmitProposal(content, deposit, simAccount.Address) account := ak.GetAccount(ctx, simAccount.Address) - coins := account.SpendableCoins(ctx.BlockTime()) + spendable := bk.SpendableCoins(ctx, account.GetAddress()) var fees sdk.Coins - coins, hasNeg := coins.SafeSub(deposit) + coins, hasNeg := spendable.SafeSub(deposit) if !hasNeg { fees, err = simulation.RandomFees(r, ctx, coins) if err != nil { @@ -177,7 +179,7 @@ func SimulateSubmitProposal( whenVote := ctx.BlockHeader().Time.Add(time.Duration(r.Int63n(int64(votingPeriod.Seconds()))) * time.Second) fops[i] = simulation.FutureOperation{ BlockTime: whenVote, - Op: operationSimulateMsgVote(ak, k, accs[whoVotes[i]], int64(proposalID)), + Op: operationSimulateMsgVote(ak, bk, k, accs[whoVotes[i]], int64(proposalID)), } } @@ -187,7 +189,7 @@ func SimulateSubmitProposal( // SimulateMsgDeposit generates a MsgDeposit with random values. // nolint: funlen -func SimulateMsgDeposit(ak types.AccountKeeper, k keeper.Keeper) simulation.Operation { +func SimulateMsgDeposit(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, @@ -198,7 +200,7 @@ func SimulateMsgDeposit(ak types.AccountKeeper, k keeper.Keeper) simulation.Oper return simulation.NoOpMsg(types.ModuleName), nil, nil } - deposit, skip, err := randomDeposit(r, ctx, ak, k, simAccount.Address) + deposit, skip, err := randomDeposit(r, ctx, ak, bk, k, simAccount.Address) switch { case skip: return simulation.NoOpMsg(types.ModuleName), nil, nil @@ -209,10 +211,10 @@ func SimulateMsgDeposit(ak types.AccountKeeper, k keeper.Keeper) simulation.Oper msg := types.NewMsgDeposit(simAccount.Address, proposalID, deposit) account := ak.GetAccount(ctx, simAccount.Address) - coins := account.SpendableCoins(ctx.BlockTime()) + spendable := bk.SpendableCoins(ctx, account.GetAddress()) var fees sdk.Coins - coins, hasNeg := coins.SafeSub(deposit) + coins, hasNeg := spendable.SafeSub(deposit) if !hasNeg { fees, err = simulation.RandomFees(r, ctx, coins) if err != nil { @@ -241,11 +243,11 @@ func SimulateMsgDeposit(ak types.AccountKeeper, k keeper.Keeper) simulation.Oper // SimulateMsgVote generates a MsgVote with random values. // nolint: funlen -func SimulateMsgVote(ak types.AccountKeeper, k keeper.Keeper) simulation.Operation { - return operationSimulateMsgVote(ak, k, simulation.Account{}, -1) +func SimulateMsgVote(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simulation.Operation { + return operationSimulateMsgVote(ak, bk, k, simulation.Account{}, -1) } -func operationSimulateMsgVote(ak types.AccountKeeper, k keeper.Keeper, +func operationSimulateMsgVote(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, simAccount simulation.Account, proposalIDInt int64) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, @@ -269,11 +271,12 @@ func operationSimulateMsgVote(ak types.AccountKeeper, k keeper.Keeper, } option := randomVotingOption(r) - msg := types.NewMsgVote(simAccount.Address, proposalID, option) account := ak.GetAccount(ctx, simAccount.Address) - fees, err := simulation.RandomFees(r, ctx, account.SpendableCoins(ctx.BlockTime())) + spendable := bk.SpendableCoins(ctx, account.GetAddress()) + + fees, err := simulation.RandomFees(r, ctx, spendable) if err != nil { return simulation.NoOpMsg(types.ModuleName), nil, err } @@ -302,11 +305,12 @@ func operationSimulateMsgVote(ak types.AccountKeeper, k keeper.Keeper, // This is to simulate multiple users depositing to get the // proposal above the minimum deposit amount func randomDeposit(r *rand.Rand, ctx sdk.Context, - ak types.AccountKeeper, k keeper.Keeper, addr sdk.AccAddress, + ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, addr sdk.AccAddress, ) (deposit sdk.Coins, skip bool, err error) { account := ak.GetAccount(ctx, addr) - coins := account.SpendableCoins(ctx.BlockHeader().Time) - if coins.Empty() { + spendable := bk.SpendableCoins(ctx, account.GetAddress()) + + if spendable.Empty() { return nil, true, nil // skip } @@ -314,7 +318,7 @@ func randomDeposit(r *rand.Rand, ctx sdk.Context, denomIndex := r.Intn(len(minDeposit)) denom := minDeposit[denomIndex].Denom - depositCoins := coins.AmountOf(denom) + depositCoins := spendable.AmountOf(denom) if depositCoins.IsZero() { return nil, true, nil } diff --git a/x/gov/test_common.go b/x/gov/test_common.go index 7ecd4bd50f68..c6fe5d7fcbba 100644 --- a/x/gov/test_common.go +++ b/x/gov/test_common.go @@ -19,6 +19,7 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" "github.com/cosmos/cosmos-sdk/x/bank" + bankexported "github.com/cosmos/cosmos-sdk/x/bank/exported" keep "github.com/cosmos/cosmos-sdk/x/gov/keeper" "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/cosmos/cosmos-sdk/x/mock" @@ -38,6 +39,7 @@ type testInput struct { mApp *mock.App keeper keep.Keeper router types.Router + bk bank.Keeper sk staking.Keeper addrs []sdk.AccAddress pubKeys []crypto.PubKey @@ -68,21 +70,18 @@ func getMockApp( blacklistedAddrs[notBondedPool.GetAddress().String()] = true blacklistedAddrs[bondPool.GetAddress().String()] = true - pk := mApp.ParamsKeeper - - rtr := types.NewRouter(). - AddRoute(types.RouterKey, handler) - - bk := bank.NewBaseKeeper(mApp.AccountKeeper, mApp.ParamsKeeper.Subspace(bank.DefaultParamspace), blacklistedAddrs) - + rtr := types.NewRouter().AddRoute(types.RouterKey, handler) maccPerms := map[string][]string{ types.ModuleName: {supply.Burner}, staking.NotBondedPoolName: {supply.Burner, supply.Staking}, staking.BondedPoolName: {supply.Burner, supply.Staking}, } + + pk := mApp.ParamsKeeper + bk := mApp.BankKeeper supplyKeeper := supply.NewKeeper(mApp.Cdc, keySupply, mApp.AccountKeeper, bk, maccPerms) sk := staking.NewKeeper( - mApp.Cdc, keyStaking, supplyKeeper, pk.Subspace(staking.DefaultParamspace), + mApp.Cdc, keyStaking, bk, supplyKeeper, pk.Subspace(staking.DefaultParamspace), ) keeper := keep.NewKeeper( @@ -93,24 +92,25 @@ func getMockApp( mApp.QueryRouter().AddRoute(types.QuerierRoute, keep.NewQuerier(keeper)) mApp.SetEndBlocker(getEndBlocker(keeper)) - mApp.SetInitChainer(getInitChainer(mApp, keeper, sk, supplyKeeper, genAccs, genState, + mApp.SetInitChainer(getInitChainer(mApp, bk, keeper, sk, supplyKeeper, genAccs, genState, []supplyexported.ModuleAccountI{govAcc, notBondedPool, bondPool})) require.NoError(t, mApp.CompleteSetup(keyStaking, keyGov, keySupply)) var ( - addrs []sdk.AccAddress - pubKeys []crypto.PubKey - privKeys []crypto.PrivKey + genBalances []bankexported.GenesisBalance + addrs []sdk.AccAddress + pubKeys []crypto.PubKey + privKeys []crypto.PrivKey ) if genAccs == nil || len(genAccs) == 0 { - genAccs, addrs, pubKeys, privKeys = mock.CreateGenAccounts(numGenAccs, valCoins) + genAccs, genBalances, addrs, pubKeys, privKeys = mock.CreateGenAccounts(numGenAccs, valCoins) } - mock.SetGenesis(mApp, genAccs) + mock.SetGenesis(mApp, genAccs, genBalances) - return testInput{mApp, keeper, rtr, sk, addrs, pubKeys, privKeys} + return testInput{mApp, keeper, rtr, bk, sk, addrs, pubKeys, privKeys} } // gov and staking endblocker @@ -122,7 +122,7 @@ func getEndBlocker(keeper Keeper) sdk.EndBlocker { } // gov and staking initchainer -func getInitChainer(mapp *mock.App, keeper Keeper, stakingKeeper staking.Keeper, supplyKeeper supply.Keeper, accs []authexported.Account, genState GenesisState, +func getInitChainer(mapp *mock.App, bk types.BankKeeper, keeper Keeper, stakingKeeper staking.Keeper, supplyKeeper supply.Keeper, accs []authexported.Account, genState GenesisState, blacklistedAddrs []supplyexported.ModuleAccountI) sdk.InitChainer { return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { mapp.InitChainer(ctx, req) @@ -137,11 +137,11 @@ func getInitChainer(mapp *mock.App, keeper Keeper, stakingKeeper staking.Keeper, supplyKeeper.SetModuleAccount(ctx, macc) } - validators := staking.InitGenesis(ctx, stakingKeeper, mapp.AccountKeeper, supplyKeeper, stakingGenesis) + validators := staking.InitGenesis(ctx, stakingKeeper, mapp.AccountKeeper, bk, supplyKeeper, stakingGenesis) if genState.IsEmpty() { - InitGenesis(ctx, keeper, supplyKeeper, types.DefaultGenesisState()) + InitGenesis(ctx, bk, supplyKeeper, keeper, types.DefaultGenesisState()) } else { - InitGenesis(ctx, keeper, supplyKeeper, genState) + InitGenesis(ctx, bk, supplyKeeper, keeper, genState) } return abci.ResponseInitChain{ Validators: validators, diff --git a/x/gov/types/expected_keepers.go b/x/gov/types/expected_keepers.go index 31e5d1e05cff..e2b7572016e2 100644 --- a/x/gov/types/expected_keepers.go +++ b/x/gov/types/expected_keepers.go @@ -44,3 +44,12 @@ type StakingKeeper interface { type AccountKeeper interface { GetAccount(ctx sdk.Context, addr sdk.AccAddress) authexported.Account } + +// BankKeeper defines the expected interface needed to retrieve account balances. +type BankKeeper interface { + GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin + SetBalances(ctx sdk.Context, addr sdk.AccAddress, balances sdk.Coins) error + LockedCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins +} diff --git a/x/mock/app.go b/x/mock/app.go index 29448e8a9067..3afccc555df9 100644 --- a/x/mock/app.go +++ b/x/mock/app.go @@ -19,6 +19,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" + "github.com/cosmos/cosmos-sdk/x/bank" + bankexported "github.com/cosmos/cosmos-sdk/x/bank/exported" "github.com/cosmos/cosmos-sdk/x/params" ) @@ -32,14 +34,17 @@ type App struct { Cdc *codec.Codec // Cdc is public since the codec is passed into the module anyways KeyMain *sdk.KVStoreKey KeyAccount *sdk.KVStoreKey + KeyBank *sdk.KVStoreKey KeyParams *sdk.KVStoreKey TKeyParams *sdk.TransientStoreKey // TODO: Abstract this out from not needing to be auth specifically AccountKeeper auth.AccountKeeper + BankKeeper bank.Keeper ParamsKeeper params.Keeper GenesisAccounts []authexported.Account + GenesisBalances []bankexported.GenesisBalance TotalCoinsSupply sdk.Coins } @@ -58,30 +63,34 @@ func NewApp() *App { Cdc: cdc, KeyMain: sdk.NewKVStoreKey(bam.MainStoreKey), KeyAccount: sdk.NewKVStoreKey(auth.StoreKey), + KeyBank: sdk.NewKVStoreKey(bank.StoreKey), KeyParams: sdk.NewKVStoreKey("params"), TKeyParams: sdk.NewTransientStoreKey("transient_params"), TotalCoinsSupply: sdk.NewCoins(), } - // define keepers app.ParamsKeeper = params.NewKeeper(app.Cdc, app.KeyParams, app.TKeyParams) - app.AccountKeeper = auth.NewAccountKeeper( app.Cdc, app.KeyAccount, app.ParamsKeeper.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount, ) - - supplyKeeper := NewDummySupplyKeeper(app.AccountKeeper) + app.BankKeeper = bank.NewBaseKeeper( + app.Cdc, + app.KeyBank, + app.AccountKeeper, + app.ParamsKeeper.Subspace(bank.DefaultParamspace), + make(map[string]bool), + ) + supplyKeeper := NewDummySupplyKeeper(app.AccountKeeper, app.BankKeeper) // Initialize the app. The chainers and blockers can be overwritten before // calling complete setup. app.SetInitChainer(app.InitChainer) app.SetAnteHandler(auth.NewAnteHandler(app.AccountKeeper, supplyKeeper, auth.DefaultSigVerificationGasConsumer)) - // Not sealing for custom extension - + // not sealing for custom extension return app } @@ -90,15 +99,17 @@ func NewApp() *App { func (app *App) CompleteSetup(newKeys ...sdk.StoreKey) error { newKeys = append( newKeys, - app.KeyMain, app.KeyAccount, app.KeyParams, app.TKeyParams, + app.KeyMain, app.KeyAccount, app.KeyBank, app.KeyParams, app.TKeyParams, ) for _, key := range newKeys { switch key.(type) { case *sdk.KVStoreKey: app.MountStore(key, sdk.StoreTypeIAVL) + case *sdk.TransientStoreKey: app.MountStore(key, sdk.StoreTypeTransient) + default: return fmt.Errorf("unsupported StoreKey: %+v", key) } @@ -111,15 +122,17 @@ func (app *App) CompleteSetup(newKeys ...sdk.StoreKey) error { // InitChainer performs custom logic for initialization. func (app *App) InitChainer(ctx sdk.Context, _ abci.RequestInitChain) abci.ResponseInitChain { - - // Load the genesis accounts for _, genacc := range app.GenesisAccounts { acc := app.AccountKeeper.NewAccountWithAddress(ctx, genacc.GetAddress()) - acc.SetCoins(genacc.GetCoins()) app.AccountKeeper.SetAccount(ctx, acc) } + for _, balance := range app.GenesisBalances { + app.BankKeeper.SetBalances(ctx, balance.GetAddress(), balance.GetCoins()) + } + auth.InitGenesis(ctx, app.AccountKeeper, auth.DefaultGenesisState()) + bank.InitGenesis(ctx, app.BankKeeper, bank.DefaultGenesisState()) return abci.ResponseInitChain{} } @@ -167,8 +180,10 @@ func (b AddrKeysSlice) Swap(i, j int) { // CreateGenAccounts generates genesis accounts loaded with coins, and returns // their addresses, pubkeys, and privkeys. -func CreateGenAccounts(numAccs int, genCoins sdk.Coins) (genAccs []authexported.Account, - addrs []sdk.AccAddress, pubKeys []crypto.PubKey, privKeys []crypto.PrivKey) { +func CreateGenAccounts(numAccs int, genCoins sdk.Coins) ( + genAccs []authexported.Account, genBalances []bankexported.GenesisBalance, + addrs []sdk.AccAddress, pubKeys []crypto.PubKey, privKeys []crypto.PrivKey, +) { addrKeysSlice := AddrKeysSlice{} @@ -188,6 +203,9 @@ func CreateGenAccounts(numAccs int, genCoins sdk.Coins) (genAccs []authexported. privKeys = append(privKeys, addrKeysSlice[i].PrivKey) genAccs = append(genAccs, &auth.BaseAccount{ Address: addrKeysSlice[i].Address, + }) + genBalances = append(genBalances, bank.Balance{ + Address: addrKeysSlice[i].Address, Coins: genCoins, }) } @@ -196,10 +214,11 @@ func CreateGenAccounts(numAccs int, genCoins sdk.Coins) (genAccs []authexported. } // SetGenesis sets the mock app genesis accounts. -func SetGenesis(app *App, accs []authexported.Account) { +func SetGenesis(app *App, accs []authexported.Account, balances []bankexported.GenesisBalance) { // Pass the accounts in via the application (lazy) instead of through // RequestInitChain. app.GenesisAccounts = accs + app.GenesisBalances = balances app.InitChain(abci.RequestInitChain{}) app.Commit() @@ -282,14 +301,15 @@ func GeneratePrivKeyAddressPairsFromRand(rand *rand.Rand, n int) (keys []crypto. // RandomSetGenesis set genesis accounts with random coin values using the // provided addresses and coin denominations. func RandomSetGenesis(r *rand.Rand, app *App, addrs []sdk.AccAddress, denoms []string) { - accts := make([]authexported.Account, len(addrs)) + accounts := make([]authexported.Account, len(addrs)) + balances := make([]bankexported.GenesisBalance, len(addrs)) randCoinIntervals := []BigInterval{ {sdk.NewIntWithDecimal(1, 0), sdk.NewIntWithDecimal(1, 1)}, {sdk.NewIntWithDecimal(1, 2), sdk.NewIntWithDecimal(1, 3)}, {sdk.NewIntWithDecimal(1, 40), sdk.NewIntWithDecimal(1, 50)}, } - for i := 0; i < len(accts); i++ { + for i := 0; i < len(accounts); i++ { coins := make([]sdk.Coin, len(denoms)) // generate a random coin for each denomination @@ -302,10 +322,12 @@ func RandomSetGenesis(r *rand.Rand, app *App, addrs []sdk.AccAddress, denoms []s app.TotalCoinsSupply = app.TotalCoinsSupply.Add(coins...) baseAcc := auth.NewBaseAccountWithAddress(addrs[i]) - (&baseAcc).SetCoins(coins) - accts[i] = &baseAcc + accounts[i] = &baseAcc + balances[i] = bank.Balance{Address: addrs[i], Coins: coins} } - app.GenesisAccounts = accts + + app.GenesisAccounts = accounts + app.GenesisBalances = balances } func createCodec() *codec.Codec { diff --git a/x/mock/app_test.go b/x/mock/app_test.go index 95bed4fda085..44b979405535 100644 --- a/x/mock/app_test.go +++ b/x/mock/app_test.go @@ -15,9 +15,9 @@ import ( const msgRoute = "testMsg" var ( - numAccts = 2 - genCoins = sdk.Coins{sdk.NewInt64Coin("foocoin", 77)} - accs, addrs, _, privKeys = CreateGenAccounts(numAccts, genCoins) + numAccts = 2 + genCoins = sdk.Coins{sdk.NewInt64Coin("foocoin", 77)} + accs, balances, addrs, _, privKeys = CreateGenAccounts(numAccts, genCoins) ) // testMsg is a mock transaction that has a validation which can fail. @@ -57,7 +57,7 @@ func TestCheckAndDeliverGenTx(t *testing.T) { mApp.Cdc.RegisterConcrete(testMsg{}, "mock/testMsg", nil) mApp.Cdc.RegisterInterface((*exported.ModuleAccountI)(nil), nil) - SetGenesis(mApp, accs) + SetGenesis(mApp, accs, balances) ctxCheck := mApp.BaseApp.NewContext(true, abci.Header{}) msg := testMsg{signers: []sdk.AccAddress{addrs[0]}, positiveNum: 1} @@ -99,7 +99,7 @@ func TestCheckGenTx(t *testing.T) { mApp.Cdc.RegisterConcrete(testMsg{}, "mock/testMsg", nil) mApp.Cdc.RegisterInterface((*exported.ModuleAccountI)(nil), nil) - SetGenesis(mApp, accs) + SetGenesis(mApp, accs, balances) msg1 := testMsg{signers: []sdk.AccAddress{addrs[0]}, positiveNum: 1} CheckGenTx( diff --git a/x/mock/test_utils.go b/x/mock/test_utils.go index 11073e64f413..cece7051ed25 100644 --- a/x/mock/test_utils.go +++ b/x/mock/test_utils.go @@ -42,11 +42,9 @@ func RandFromBigInterval(r *rand.Rand, intervals []BigInterval) sdk.Int { } // CheckBalance checks the balance of an account. -func CheckBalance(t *testing.T, app *App, addr sdk.AccAddress, exp sdk.Coins) { +func CheckBalance(t *testing.T, app *App, addr sdk.AccAddress, balance sdk.Coins) { ctxCheck := app.BaseApp.NewContext(true, abci.Header{}) - res := app.AccountKeeper.GetAccount(ctxCheck, addr) - - require.Equal(t, exp, res.GetCoins()) + require.Equal(t, balance, app.BankKeeper.GetAllBalances(ctxCheck, addr)) } // CheckGenTx checks a generated signed transaction. The result of the check is diff --git a/x/mock/types.go b/x/mock/types.go index 43dfbaecbb94..aed4a6c97f35 100644 --- a/x/mock/types.go +++ b/x/mock/types.go @@ -6,6 +6,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/bank" "github.com/cosmos/cosmos-sdk/x/supply" "github.com/cosmos/cosmos-sdk/x/supply/exported" ) @@ -14,30 +15,33 @@ import ( // circle dependencies type DummySupplyKeeper struct { ak auth.AccountKeeper + bk bank.Keeper } // NewDummySupplyKeeper creates a DummySupplyKeeper instance -func NewDummySupplyKeeper(ak auth.AccountKeeper) DummySupplyKeeper { - return DummySupplyKeeper{ak} +func NewDummySupplyKeeper(ak auth.AccountKeeper, bk bank.Keeper) DummySupplyKeeper { + return DummySupplyKeeper{ak, bk} } // SendCoinsFromAccountToModule for the dummy supply keeper func (sk DummySupplyKeeper) SendCoinsFromAccountToModule(ctx sdk.Context, fromAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error { fromAcc := sk.ak.GetAccount(ctx, fromAddr) moduleAcc := sk.GetModuleAccount(ctx, recipientModule) + fromBalances := sk.bk.GetAllBalances(ctx, fromAcc.GetAddress()) - newFromCoins, hasNeg := fromAcc.GetCoins().SafeSub(amt) + newFromCoins, hasNeg := fromBalances.SafeSub(amt) if hasNeg { - return sdkerrors.Wrap(sdkerrors.ErrInsufficientFunds, fromAcc.GetCoins().String()) + return sdkerrors.Wrap(sdkerrors.ErrInsufficientFunds, fromBalances.String()) } - newToCoins := moduleAcc.GetCoins().Add(amt...) + toBalances := sk.bk.GetAllBalances(ctx, moduleAcc.GetAddress()) + newToCoins := toBalances.Add(amt...) - if err := fromAcc.SetCoins(newFromCoins); err != nil { + if err := sk.bk.SetBalances(ctx, fromAcc.GetAddress(), newFromCoins); err != nil { return err } - if err := moduleAcc.SetCoins(newToCoins); err != nil { + if err := sk.bk.SetBalances(ctx, moduleAcc.GetAddress(), newToCoins); err != nil { return err } diff --git a/x/simulation/account_test.go b/x/simulation/account_test.go index adb28dcf984f..b0f6494fac30 100644 --- a/x/simulation/account_test.go +++ b/x/simulation/account_test.go @@ -65,6 +65,8 @@ func TestRandomFees(t *testing.T) { {"0 coins", sdk.NewCoins(sdk.NewInt64Coin("aaa", 10), sdk.NewInt64Coin("bbb", 5)), false, false}, } for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { got, err := simulation.RandomFees(r, sdk.Context{}, tt.spendableCoins) if (err != nil) != tt.wantErr { diff --git a/x/simulation/rand_util_test.go b/x/simulation/rand_util_test.go index 2128de4050aa..9d46164e59f6 100644 --- a/x/simulation/rand_util_test.go +++ b/x/simulation/rand_util_test.go @@ -46,6 +46,8 @@ func TestRandStringOfLength(t *testing.T) { {"10-size", 1_000_000_000, 1_000_000_000}, } for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { got := simulation.RandStringOfLength(r, tt.n) require.Equal(t, tt.want, len(got)) diff --git a/x/slashing/abci_test.go b/x/slashing/abci_test.go index bcd1ee7ce8a2..a2138479f2c6 100644 --- a/x/slashing/abci_test.go +++ b/x/slashing/abci_test.go @@ -14,7 +14,7 @@ import ( ) func TestBeginBlocker(t *testing.T) { - ctx, ck, sk, _, keeper := slashingkeeper.CreateTestInput(t, DefaultParams()) + ctx, bk, sk, _, keeper := slashingkeeper.CreateTestInput(t, DefaultParams()) power := int64(100) amt := sdk.TokensFromConsensusPower(power) addr, pk := slashingkeeper.Addrs[2], slashingkeeper.Pks[2] @@ -26,7 +26,7 @@ func TestBeginBlocker(t *testing.T) { staking.EndBlocker(ctx, sk) require.Equal( - t, ck.GetCoins(ctx, sdk.AccAddress(addr)), + t, bk.GetAllBalances(ctx, sdk.AccAddress(addr)), sdk.NewCoins(sdk.NewCoin(sk.GetParams(ctx).BondDenom, slashingkeeper.InitTokens.Sub(amt))), ) require.Equal(t, amt, sk.Validator(ctx, addr).GetBondedTokens()) diff --git a/x/slashing/app_test.go b/x/slashing/app_test.go index 23dd43e590bf..88ae3bb0b75a 100644 --- a/x/slashing/app_test.go +++ b/x/slashing/app_test.go @@ -14,6 +14,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth" authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" "github.com/cosmos/cosmos-sdk/x/bank" + bankexported "github.com/cosmos/cosmos-sdk/x/bank/exported" "github.com/cosmos/cosmos-sdk/x/mock" "github.com/cosmos/cosmos-sdk/x/staking" "github.com/cosmos/cosmos-sdk/x/staking/types" @@ -48,21 +49,24 @@ func getMockApp(t *testing.T) (*mock.App, staking.Keeper, Keeper) { blacklistedAddrs[notBondedPool.GetAddress().String()] = true blacklistedAddrs[bondPool.GetAddress().String()] = true - bankKeeper := bank.NewBaseKeeper(mapp.AccountKeeper, mapp.ParamsKeeper.Subspace(bank.DefaultParamspace), blacklistedAddrs) maccPerms := map[string][]string{ auth.FeeCollectorName: nil, staking.NotBondedPoolName: {supply.Burner, supply.Staking}, staking.BondedPoolName: {supply.Burner, supply.Staking}, } - supplyKeeper := supply.NewKeeper(mapp.Cdc, keySupply, mapp.AccountKeeper, bankKeeper, maccPerms) - stakingKeeper := staking.NewKeeper(mapp.Cdc, keyStaking, supplyKeeper, mapp.ParamsKeeper.Subspace(staking.DefaultParamspace)) + supplyKeeper := supply.NewKeeper(mapp.Cdc, keySupply, mapp.AccountKeeper, mapp.BankKeeper, maccPerms) + stakingKeeper := staking.NewKeeper(mapp.Cdc, keyStaking, mapp.BankKeeper, supplyKeeper, mapp.ParamsKeeper.Subspace(staking.DefaultParamspace)) keeper := NewKeeper(mapp.Cdc, keySlashing, stakingKeeper, mapp.ParamsKeeper.Subspace(DefaultParamspace)) mapp.Router().AddRoute(staking.RouterKey, staking.NewHandler(stakingKeeper)) mapp.Router().AddRoute(RouterKey, NewHandler(keeper)) mapp.SetEndBlocker(getEndBlocker(stakingKeeper)) - mapp.SetInitChainer(getInitChainer(mapp, stakingKeeper, mapp.AccountKeeper, supplyKeeper, - []supplyexported.ModuleAccountI{feeCollector, notBondedPool, bondPool})) + mapp.SetInitChainer( + getInitChainer( + mapp, stakingKeeper, mapp.AccountKeeper, mapp.BankKeeper, supplyKeeper, + []supplyexported.ModuleAccountI{feeCollector, notBondedPool, bondPool}, + ), + ) require.NoError(t, mapp.CompleteSetup(keyStaking, keySupply, keySlashing)) @@ -80,8 +84,11 @@ func getEndBlocker(keeper staking.Keeper) sdk.EndBlocker { } // overwrite the mock init chainer -func getInitChainer(mapp *mock.App, keeper staking.Keeper, accountKeeper types.AccountKeeper, supplyKeeper types.SupplyKeeper, - blacklistedAddrs []supplyexported.ModuleAccountI) sdk.InitChainer { +func getInitChainer( + mapp *mock.App, keeper staking.Keeper, accountKeeper types.AccountKeeper, bk types.BankKeeper, + supplyKeeper types.SupplyKeeper, blacklistedAddrs []supplyexported.ModuleAccountI, +) sdk.InitChainer { + return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { // set module accounts for _, macc := range blacklistedAddrs { @@ -90,7 +97,7 @@ func getInitChainer(mapp *mock.App, keeper staking.Keeper, accountKeeper types.A mapp.InitChainer(ctx, req) stakingGenesis := staking.DefaultGenesisState() - validators := staking.InitGenesis(ctx, keeper, accountKeeper, supplyKeeper, stakingGenesis) + validators := staking.InitGenesis(ctx, keeper, accountKeeper, bk, supplyKeeper, stakingGenesis) return abci.ResponseInitChain{ Validators: validators, } @@ -123,10 +130,15 @@ func TestSlashingMsgs(t *testing.T) { acc1 := &auth.BaseAccount{ Address: addr1, - Coins: sdk.Coins{genCoin}, } accs := []authexported.Account{acc1} - mock.SetGenesis(mapp, accs) + balances := []bankexported.GenesisBalance{ + bank.Balance{ + Address: addr1, + Coins: sdk.Coins{genCoin}, + }, + } + mock.SetGenesis(mapp, accs, balances) description := staking.NewDescription("foo_moniker", "", "", "", "") commission := staking.NewCommissionRates(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()) diff --git a/x/slashing/handler_test.go b/x/slashing/handler_test.go index a137ff8d0d08..b3d181c806e9 100644 --- a/x/slashing/handler_test.go +++ b/x/slashing/handler_test.go @@ -17,7 +17,7 @@ import ( func TestCannotUnjailUnlessJailed(t *testing.T) { // initial setup - ctx, ck, sk, _, keeper := slashingkeeper.CreateTestInput(t, DefaultParams()) + ctx, bk, sk, _, keeper := slashingkeeper.CreateTestInput(t, DefaultParams()) slh := NewHandler(keeper) amt := sdk.TokensFromConsensusPower(100) addr, val := slashingkeeper.Addrs[0], slashingkeeper.Pks[0] @@ -30,7 +30,7 @@ func TestCannotUnjailUnlessJailed(t *testing.T) { staking.EndBlocker(ctx, sk) require.Equal( - t, ck.GetCoins(ctx, sdk.AccAddress(addr)), + t, bk.GetAllBalances(ctx, sdk.AccAddress(addr)), sdk.Coins{sdk.NewCoin(sk.GetParams(ctx).BondDenom, slashingkeeper.InitTokens.Sub(amt))}, ) require.Equal(t, amt, sk.Validator(ctx, addr).GetBondedTokens()) @@ -44,7 +44,7 @@ func TestCannotUnjailUnlessJailed(t *testing.T) { func TestCannotUnjailUnlessMeetMinSelfDelegation(t *testing.T) { // initial setup - ctx, ck, sk, _, keeper := slashingkeeper.CreateTestInput(t, DefaultParams()) + ctx, bk, sk, _, keeper := slashingkeeper.CreateTestInput(t, DefaultParams()) slh := NewHandler(keeper) amtInt := int64(100) addr, val, amt := slashingkeeper.Addrs[0], slashingkeeper.Pks[0], sdk.TokensFromConsensusPower(amtInt) @@ -58,7 +58,7 @@ func TestCannotUnjailUnlessMeetMinSelfDelegation(t *testing.T) { staking.EndBlocker(ctx, sk) require.Equal( - t, ck.GetCoins(ctx, sdk.AccAddress(addr)), + t, bk.GetAllBalances(ctx, sdk.AccAddress(addr)), sdk.Coins{sdk.NewCoin(sk.GetParams(ctx).BondDenom, slashingkeeper.InitTokens.Sub(amt))}, ) @@ -153,9 +153,8 @@ func TestInvalidMsg(t *testing.T) { // Test a validator through uptime, downtime, revocation, // unrevocation, starting height reset, and revocation again func TestHandleAbsentValidator(t *testing.T) { - // initial setup - ctx, ck, sk, _, keeper := slashingkeeper.CreateTestInput(t, slashingkeeper.TestParams()) + ctx, bk, sk, _, keeper := slashingkeeper.CreateTestInput(t, slashingkeeper.TestParams()) power := int64(100) amt := sdk.TokensFromConsensusPower(power) addr, val := slashingkeeper.Addrs[0], slashingkeeper.Pks[0] @@ -169,7 +168,7 @@ func TestHandleAbsentValidator(t *testing.T) { staking.EndBlocker(ctx, sk) require.Equal( - t, ck.GetCoins(ctx, sdk.AccAddress(addr)), + t, bk.GetAllBalances(ctx, sdk.AccAddress(addr)), sdk.NewCoins(sdk.NewCoin(sk.GetParams(ctx).BondDenom, slashingkeeper.InitTokens.Sub(amt))), ) require.Equal(t, amt, sk.Validator(ctx, addr).GetBondedTokens()) @@ -206,8 +205,9 @@ func TestHandleAbsentValidator(t *testing.T) { // validator should be bonded still validator, _ := sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) require.Equal(t, sdk.Bonded, validator.GetStatus()) + bondPool := sk.GetBondedPool(ctx) - require.True(sdk.IntEq(t, amt, bondPool.GetCoins().AmountOf(sk.BondDenom(ctx)))) + require.True(sdk.IntEq(t, amt, bk.GetBalance(ctx, bondPool.GetAddress(), sk.BondDenom(ctx)).Amount)) // 501st block missed ctx = ctx.WithBlockHeight(height) @@ -265,8 +265,7 @@ func TestHandleAbsentValidator(t *testing.T) { require.Equal(t, sdk.Bonded, validator.GetStatus()) // validator should have been slashed - bondPool = sk.GetBondedPool(ctx) - require.Equal(t, amt.Int64()-slashAmt, bondPool.GetCoins().AmountOf(sk.BondDenom(ctx)).Int64()) + require.Equal(t, amt.Int64()-slashAmt, bk.GetBalance(ctx, bondPool.GetAddress(), sk.BondDenom(ctx)).Amount.Int64()) // Validator start height should not have been changed info, found = keeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) diff --git a/x/slashing/internal/keeper/keeper_test.go b/x/slashing/internal/keeper/keeper_test.go index 52eb6b59b77a..fdf50a261e27 100644 --- a/x/slashing/internal/keeper/keeper_test.go +++ b/x/slashing/internal/keeper/keeper_test.go @@ -16,7 +16,7 @@ import ( // and that they are not immediately jailed func TestHandleNewValidator(t *testing.T) { // initial setup - ctx, ck, sk, _, keeper := CreateTestInput(t, TestParams()) + ctx, bk, sk, _, keeper := CreateTestInput(t, TestParams()) addr, val := Addrs[0], Pks[0] amt := sdk.TokensFromConsensusPower(100) sh := staking.NewHandler(sk) @@ -32,7 +32,7 @@ func TestHandleNewValidator(t *testing.T) { staking.EndBlocker(ctx, sk) require.Equal( - t, ck.GetCoins(ctx, sdk.AccAddress(addr)), + t, bk.GetAllBalances(ctx, sdk.AccAddress(addr)), sdk.NewCoins(sdk.NewCoin(sk.GetParams(ctx).BondDenom, InitTokens.Sub(amt))), ) require.Equal(t, amt, sk.Validator(ctx, addr).GetBondedTokens()) @@ -54,7 +54,7 @@ func TestHandleNewValidator(t *testing.T) { require.Equal(t, sdk.Bonded, validator.GetStatus()) bondPool := sk.GetBondedPool(ctx) expTokens := sdk.TokensFromConsensusPower(100) - require.Equal(t, expTokens.Int64(), bondPool.GetCoins().AmountOf(sk.BondDenom(ctx)).Int64()) + require.Equal(t, expTokens.Int64(), bk.GetBalance(ctx, bondPool.GetAddress(), sk.BondDenom(ctx)).Amount.Int64()) } // Test a jailed validator being "down" twice diff --git a/x/slashing/internal/keeper/test_common.go b/x/slashing/internal/keeper/test_common.go index eb8870c1d199..79a436b2e1df 100644 --- a/x/slashing/internal/keeper/test_common.go +++ b/x/slashing/internal/keeper/test_common.go @@ -57,6 +57,7 @@ func createTestCodec() *codec.Codec { func CreateTestInput(t *testing.T, defaults types.Params) (sdk.Context, bank.Keeper, staking.Keeper, params.Subspace, Keeper) { keyAcc := sdk.NewKVStoreKey(auth.StoreKey) + keyBank := sdk.NewKVStoreKey(bank.StoreKey) keyStaking := sdk.NewKVStoreKey(staking.StoreKey) keySlashing := sdk.NewKVStoreKey(types.StoreKey) keySupply := sdk.NewKVStoreKey(supply.StoreKey) @@ -67,6 +68,7 @@ func CreateTestInput(t *testing.T, defaults types.Params) (sdk.Context, bank.Kee ms := store.NewCommitMultiStore(db) ms.MountStoreWithDB(keyAcc, sdk.StoreTypeIAVL, db) + ms.MountStoreWithDB(keyBank, sdk.StoreTypeIAVL, db) ms.MountStoreWithDB(keyStaking, sdk.StoreTypeIAVL, db) ms.MountStoreWithDB(keySupply, sdk.StoreTypeIAVL, db) ms.MountStoreWithDB(keySlashing, sdk.StoreTypeIAVL, db) @@ -91,7 +93,7 @@ func CreateTestInput(t *testing.T, defaults types.Params) (sdk.Context, bank.Kee paramsKeeper := params.NewKeeper(cdc, keyParams, tkeyParams) accountKeeper := auth.NewAccountKeeper(cdc, keyAcc, paramsKeeper.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount) - bk := bank.NewBaseKeeper(accountKeeper, paramsKeeper.Subspace(bank.DefaultParamspace), blacklistedAddrs) + bk := bank.NewBaseKeeper(cdc, keyBank, accountKeeper, paramsKeeper.Subspace(bank.DefaultParamspace), blacklistedAddrs) maccPerms := map[string][]string{ auth.FeeCollectorName: nil, staking.NotBondedPoolName: {supply.Burner, supply.Staking}, @@ -102,7 +104,7 @@ func CreateTestInput(t *testing.T, defaults types.Params) (sdk.Context, bank.Kee totalSupply := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, InitTokens.MulRaw(int64(len(Addrs))))) supplyKeeper.SetSupply(ctx, supply.NewSupply(totalSupply)) - sk := staking.NewKeeper(cdc, keyStaking, supplyKeeper, paramsKeeper.Subspace(staking.DefaultParamspace)) + sk := staking.NewKeeper(cdc, keyStaking, bk, supplyKeeper, paramsKeeper.Subspace(staking.DefaultParamspace)) genesis := staking.DefaultGenesisState() // set module accounts @@ -110,12 +112,14 @@ func CreateTestInput(t *testing.T, defaults types.Params) (sdk.Context, bank.Kee supplyKeeper.SetModuleAccount(ctx, bondPool) supplyKeeper.SetModuleAccount(ctx, notBondedPool) - _ = staking.InitGenesis(ctx, sk, accountKeeper, supplyKeeper, genesis) + _ = staking.InitGenesis(ctx, sk, accountKeeper, bk, supplyKeeper, genesis) - for _, addr := range Addrs { - _, err = bk.AddCoins(ctx, sdk.AccAddress(addr), initCoins) + for i, addr := range Addrs { + addr := sdk.AccAddress(addr) + accountKeeper.SetAccount(ctx, auth.NewBaseAccount(addr, Pks[i], uint64(i), 0)) + require.NoError(t, bk.SetBalances(ctx, addr, initCoins)) } - require.Nil(t, err) + paramstore := paramsKeeper.Subspace(types.DefaultParamspace) keeper := NewKeeper(cdc, keySlashing, &sk, paramstore) diff --git a/x/slashing/internal/types/expected_keepers.go b/x/slashing/internal/types/expected_keepers.go index 58e1f30d67ef..bf09731a03e6 100644 --- a/x/slashing/internal/types/expected_keepers.go +++ b/x/slashing/internal/types/expected_keepers.go @@ -15,6 +15,15 @@ type AccountKeeper interface { IterateAccounts(ctx sdk.Context, process func(authexported.Account) (stop bool)) } +// BankKeeper defines the expected interface needed to retrieve account balances. +type BankKeeper interface { + GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin + SetBalances(ctx sdk.Context, addr sdk.AccAddress, balances sdk.Coins) error + LockedCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins +} + // ParamSubspace defines the expected Subspace interfacace type ParamSubspace interface { WithKeyTable(table params.KeyTable) params.Subspace diff --git a/x/slashing/module.go b/x/slashing/module.go index e99b421574fe..4b739ef217e0 100644 --- a/x/slashing/module.go +++ b/x/slashing/module.go @@ -82,16 +82,18 @@ type AppModule struct { keeper Keeper accountKeeper types.AccountKeeper + bankKeeper types.BankKeeper stakingKeeper stakingkeeper.Keeper } // NewAppModule creates a new AppModule object -func NewAppModule(keeper Keeper, accountKeeper types.AccountKeeper, stakingKeeper stakingkeeper.Keeper) AppModule { +func NewAppModule(keeper Keeper, ak types.AccountKeeper, bk types.BankKeeper, sk stakingkeeper.Keeper) AppModule { return AppModule{ AppModuleBasic: AppModuleBasic{}, keeper: keeper, - accountKeeper: accountKeeper, - stakingKeeper: stakingKeeper, + accountKeeper: ak, + bankKeeper: bk, + stakingKeeper: sk, } } @@ -176,6 +178,8 @@ func (AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { // WeightedOperations returns the all the slashing module operations with their respective weights. func (am AppModule) WeightedOperations(simState module.SimulationState) []sim.WeightedOperation { - return simulation.WeightedOperations(simState.AppParams, simState.Cdc, - am.accountKeeper, am.keeper, am.stakingKeeper) + return simulation.WeightedOperations( + simState.AppParams, simState.Cdc, + am.accountKeeper, am.bankKeeper, am.keeper, am.stakingKeeper, + ) } diff --git a/x/slashing/simulation/operations.go b/x/slashing/simulation/operations.go index f5e263b778dc..c7e1b0bfb6c4 100644 --- a/x/slashing/simulation/operations.go +++ b/x/slashing/simulation/operations.go @@ -23,7 +23,7 @@ const ( // WeightedOperations returns all the operations from the module with their respective weights func WeightedOperations( appParams simulation.AppParams, cdc *codec.Codec, ak types.AccountKeeper, - k keeper.Keeper, sk stakingkeeper.Keeper, + bk types.BankKeeper, k keeper.Keeper, sk stakingkeeper.Keeper, ) simulation.WeightedOperations { var weightMsgUnjail int @@ -36,14 +36,14 @@ func WeightedOperations( return simulation.WeightedOperations{ simulation.NewWeightedOperation( weightMsgUnjail, - SimulateMsgUnjail(ak, k, sk), + SimulateMsgUnjail(ak, bk, k, sk), ), } } // SimulateMsgUnjail generates a MsgUnjail with random values -// nolint: funlen -func SimulateMsgUnjail(ak types.AccountKeeper, k keeper.Keeper, sk stakingkeeper.Keeper) simulation.Operation { +// nolint: funlen interfacer +func SimulateMsgUnjail(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, sk stakingkeeper.Keeper) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, @@ -76,7 +76,9 @@ func SimulateMsgUnjail(ak types.AccountKeeper, k keeper.Keeper, sk stakingkeeper } account := ak.GetAccount(ctx, sdk.AccAddress(validator.GetOperator())) - fees, err := simulation.RandomFees(r, ctx, account.SpendableCoins(ctx.BlockTime())) + spendable := bk.SpendableCoins(ctx, account.GetAddress()) + + fees, err := simulation.RandomFees(r, ctx, spendable) if err != nil { return simulation.NoOpMsg(types.ModuleName), nil, err } diff --git a/x/staking/app_test.go b/x/staking/app_test.go index a56923113380..586b5d95d757 100644 --- a/x/staking/app_test.go +++ b/x/staking/app_test.go @@ -10,6 +10,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth" authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" "github.com/cosmos/cosmos-sdk/x/bank" + bankexported "github.com/cosmos/cosmos-sdk/x/bank/exported" "github.com/cosmos/cosmos-sdk/x/mock" "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/cosmos/cosmos-sdk/x/supply" @@ -35,19 +36,22 @@ func getMockApp(t *testing.T) (*mock.App, Keeper) { blacklistedAddrs[notBondedPool.GetAddress().String()] = true blacklistedAddrs[bondPool.GetAddress().String()] = true - bankKeeper := bank.NewBaseKeeper(mApp.AccountKeeper, mApp.ParamsKeeper.Subspace(bank.DefaultParamspace), blacklistedAddrs) maccPerms := map[string][]string{ auth.FeeCollectorName: nil, types.NotBondedPoolName: {supply.Burner, supply.Staking}, types.BondedPoolName: {supply.Burner, supply.Staking}, } - supplyKeeper := supply.NewKeeper(mApp.Cdc, keySupply, mApp.AccountKeeper, bankKeeper, maccPerms) - keeper := NewKeeper(mApp.Cdc, keyStaking, supplyKeeper, mApp.ParamsKeeper.Subspace(DefaultParamspace)) + supplyKeeper := supply.NewKeeper(mApp.Cdc, keySupply, mApp.AccountKeeper, mApp.BankKeeper, maccPerms) + keeper := NewKeeper(mApp.Cdc, keyStaking, mApp.BankKeeper, supplyKeeper, mApp.ParamsKeeper.Subspace(DefaultParamspace)) mApp.Router().AddRoute(RouterKey, NewHandler(keeper)) mApp.SetEndBlocker(getEndBlocker(keeper)) - mApp.SetInitChainer(getInitChainer(mApp, keeper, mApp.AccountKeeper, supplyKeeper, - []supplyexported.ModuleAccountI{feeCollector, notBondedPool, bondPool})) + mApp.SetInitChainer( + getInitChainer( + mApp, keeper, mApp.AccountKeeper, mApp.BankKeeper, supplyKeeper, + []supplyexported.ModuleAccountI{feeCollector, notBondedPool, bondPool}, + ), + ) require.NoError(t, mApp.CompleteSetup(keyStaking, keySupply)) return mApp, keeper @@ -66,18 +70,22 @@ func getEndBlocker(keeper Keeper) sdk.EndBlocker { // getInitChainer initializes the chainer of the mock app and sets the genesis // state. It returns an empty ResponseInitChain. -func getInitChainer(mapp *mock.App, keeper Keeper, accountKeeper types.AccountKeeper, supplyKeeper types.SupplyKeeper, - blacklistedAddrs []supplyexported.ModuleAccountI) sdk.InitChainer { +func getInitChainer( + mapp *mock.App, keeper Keeper, ak types.AccountKeeper, bk types.BankKeeper, + sk types.SupplyKeeper, blacklistedAddrs []supplyexported.ModuleAccountI, +) sdk.InitChainer { + return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { mapp.InitChainer(ctx, req) // set module accounts for _, macc := range blacklistedAddrs { - supplyKeeper.SetModuleAccount(ctx, macc) + sk.SetModuleAccount(ctx, macc) } stakingGenesis := DefaultGenesisState() - validators := InitGenesis(ctx, keeper, accountKeeper, supplyKeeper, stakingGenesis) + validators := InitGenesis(ctx, keeper, ak, bk, sk, stakingGenesis) + return abci.ResponseInitChain{ Validators: validators, } @@ -121,17 +129,21 @@ func TestStakingMsgs(t *testing.T) { genCoin := sdk.NewCoin(sdk.DefaultBondDenom, genTokens) bondCoin := sdk.NewCoin(sdk.DefaultBondDenom, bondTokens) - acc1 := &auth.BaseAccount{ - Address: addr1, - Coins: sdk.Coins{genCoin}, - } - acc2 := &auth.BaseAccount{ - Address: addr2, - Coins: sdk.Coins{genCoin}, - } + acc1 := &auth.BaseAccount{Address: addr1} + acc2 := &auth.BaseAccount{Address: addr2} accs := []authexported.Account{acc1, acc2} + balances := []bankexported.GenesisBalance{ + bank.Balance{ + Address: addr1, + Coins: sdk.Coins{genCoin}, + }, + bank.Balance{ + Address: addr2, + Coins: sdk.Coins{genCoin}, + }, + } - mock.SetGenesis(mApp, accs) + mock.SetGenesis(mApp, accs, balances) mock.CheckBalance(t, mApp, addr1, sdk.Coins{genCoin}) mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin}) diff --git a/x/staking/genesis.go b/x/staking/genesis.go index 4c1bbee7072a..5c558ca4259b 100644 --- a/x/staking/genesis.go +++ b/x/staking/genesis.go @@ -16,8 +16,10 @@ import ( // setting the indexes. In addition, it also sets any delegations found in // data. Finally, it updates the bonded validators. // Returns final validator set after applying all declaration and delegations -func InitGenesis(ctx sdk.Context, keeper Keeper, accountKeeper types.AccountKeeper, - supplyKeeper types.SupplyKeeper, data types.GenesisState) (res []abci.ValidatorUpdate) { +func InitGenesis( + ctx sdk.Context, keeper Keeper, accountKeeper types.AccountKeeper, + bankKeeper types.BankKeeper, supplyKeeper types.SupplyKeeper, data types.GenesisState, +) (res []abci.ValidatorUpdate) { bondedTokens := sdk.ZeroInt() notBondedTokens := sdk.ZeroInt() @@ -98,10 +100,11 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, accountKeeper types.AccountKeep // TODO remove with genesis 2-phases refactor https://github.com/cosmos/cosmos-sdk/issues/2862 // add coins if not provided on genesis - if bondedPool.GetCoins().IsZero() { - if err := bondedPool.SetCoins(bondedCoins); err != nil { + if bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()).IsZero() { + if err := bankKeeper.SetBalances(ctx, bondedPool.GetAddress(), bondedCoins); err != nil { panic(err) } + supplyKeeper.SetModuleAccount(ctx, bondedPool) } @@ -110,10 +113,11 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, accountKeeper types.AccountKeep panic(fmt.Sprintf("%s module account has not been set", types.NotBondedPoolName)) } - if notBondedPool.GetCoins().IsZero() { - if err := notBondedPool.SetCoins(notBondedCoins); err != nil { + if bankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()).IsZero() { + if err := bankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), notBondedCoins); err != nil { panic(err) } + supplyKeeper.SetModuleAccount(ctx, notBondedPool) } diff --git a/x/staking/genesis_test.go b/x/staking/genesis_test.go index 4a56b3ac9c9c..4f3a7f1d05bf 100644 --- a/x/staking/genesis_test.go +++ b/x/staking/genesis_test.go @@ -17,7 +17,7 @@ import ( ) func TestInitGenesis(t *testing.T) { - ctx, accKeeper, keeper, supplyKeeper := keep.CreateTestInput(t, false, 1000) + ctx, accKeeper, bk, keeper, supplyKeeper := keep.CreateTestInput(t, false, 1000) valTokens := sdk.TokensFromConsensusPower(1) @@ -40,7 +40,7 @@ func TestInitGenesis(t *testing.T) { validators[1].DelegatorShares = valTokens.ToDec() genesisState := types.NewGenesisState(params, validators, delegations) - vals := InitGenesis(ctx, keeper, accKeeper, supplyKeeper, genesisState) + vals := InitGenesis(ctx, keeper, accKeeper, bk, supplyKeeper, genesisState) actualGenesis := ExportGenesis(ctx, keeper) require.Equal(t, genesisState.Params, actualGenesis.Params) @@ -68,7 +68,7 @@ func TestInitGenesisLargeValidatorSet(t *testing.T) { size := 200 require.True(t, size > 100) - ctx, accKeeper, keeper, supplyKeeper := keep.CreateTestInput(t, false, 1000) + ctx, accKeeper, bk, keeper, supplyKeeper := keep.CreateTestInput(t, false, 1000) params := keeper.GetParams(ctx) delegations := []Delegation{} @@ -89,7 +89,7 @@ func TestInitGenesisLargeValidatorSet(t *testing.T) { } genesisState := types.NewGenesisState(params, validators, delegations) - vals := InitGenesis(ctx, keeper, accKeeper, supplyKeeper, genesisState) + vals := InitGenesis(ctx, keeper, accKeeper, bk, supplyKeeper, genesisState) abcivals := make([]abci.ValidatorUpdate, 100) for i, val := range validators[:100] { diff --git a/x/staking/handler_test.go b/x/staking/handler_test.go index 92147eabb097..75e9242e07c7 100644 --- a/x/staking/handler_test.go +++ b/x/staking/handler_test.go @@ -22,7 +22,7 @@ func TestValidatorByPowerIndex(t *testing.T) { initPower := int64(1000000) initBond := sdk.TokensFromConsensusPower(initPower) - ctx, _, keeper, _ := keep.CreateTestInput(t, false, initPower) + ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, initPower) // create validator msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], initBond) @@ -104,7 +104,7 @@ func TestValidatorByPowerIndex(t *testing.T) { } func TestDuplicatesMsgCreateValidator(t *testing.T) { - ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) addr1, addr2 := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1]) pk1, pk2 := keep.PKs[0], keep.PKs[1] @@ -160,7 +160,7 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) { } func TestInvalidPubKeyTypeMsgCreateValidator(t *testing.T) { - ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) addr := sdk.ValAddress(keep.Addrs[0]) invalidPk := secp256k1.GenPrivKey().PubKey() @@ -181,7 +181,7 @@ func TestInvalidPubKeyTypeMsgCreateValidator(t *testing.T) { } func TestLegacyValidatorDelegations(t *testing.T) { - ctx, _, keeper, _ := keep.CreateTestInput(t, false, int64(1000)) + ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, int64(1000)) bondAmount := sdk.TokensFromConsensusPower(10) valAddr := sdk.ValAddress(keep.Addrs[0]) @@ -279,7 +279,7 @@ func TestLegacyValidatorDelegations(t *testing.T) { func TestIncrementsMsgDelegate(t *testing.T) { initPower := int64(1000) initBond := sdk.TokensFromConsensusPower(initPower) - ctx, accMapper, keeper, _ := keep.CreateTestInput(t, false, initPower) + ctx, _, bk, keeper, _ := keep.CreateTestInput(t, false, initPower) params := keeper.GetParams(ctx) bondAmount := sdk.TokensFromConsensusPower(10) @@ -332,7 +332,7 @@ func TestIncrementsMsgDelegate(t *testing.T) { gotBond := bond.Shares.RoundInt() gotDelegatorShares := validator.DelegatorShares.RoundInt() - gotDelegatorAcc := accMapper.GetAccount(ctx, delegatorAddr).GetCoins().AmountOf(params.BondDenom) + gotDelegatorAcc := bk.GetBalance(ctx, delegatorAddr, params.BondDenom).Amount require.Equal(t, expBond, gotBond, "i: %v\nexpBond: %v\ngotBond: %v\nvalidator: %v\nbond: %v\n", @@ -351,7 +351,7 @@ func TestEditValidatorDecreaseMinSelfDelegation(t *testing.T) { initPower := int64(100) initBond := sdk.TokensFromConsensusPower(100) - ctx, _, keeper, _ := keep.CreateTestInput(t, false, initPower) + ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, initPower) // create validator msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], initBond) @@ -384,7 +384,7 @@ func TestEditValidatorIncreaseMinSelfDelegationBeyondCurrentBond(t *testing.T) { initPower := int64(100) initBond := sdk.TokensFromConsensusPower(100) - ctx, _, keeper, _ := keep.CreateTestInput(t, false, initPower) + ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, initPower) // create validator msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], initBond) @@ -415,7 +415,7 @@ func TestEditValidatorIncreaseMinSelfDelegationBeyondCurrentBond(t *testing.T) { func TestIncrementsMsgUnbond(t *testing.T) { initPower := int64(1000) initBond := sdk.TokensFromConsensusPower(initPower) - ctx, accMapper, keeper, _ := keep.CreateTestInput(t, false, initPower) + ctx, _, bk, keeper, _ := keep.CreateTestInput(t, false, initPower) params := keeper.GetParams(ctx) denom := params.BondDenom @@ -429,7 +429,7 @@ func TestIncrementsMsgUnbond(t *testing.T) { require.NotNil(t, res) // initial balance - amt1 := accMapper.GetAccount(ctx, delegatorAddr).GetCoins().AmountOf(denom) + amt1 := bk.GetBalance(ctx, delegatorAddr, denom).Amount msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, initBond) res, err = handleMsgDelegate(ctx, msgDelegate, keeper) @@ -437,7 +437,7 @@ func TestIncrementsMsgUnbond(t *testing.T) { require.NotNil(t, res) // balance should have been subtracted after delegation - amt2 := accMapper.GetAccount(ctx, delegatorAddr).GetCoins().AmountOf(denom) + amt2 := bk.GetBalance(ctx, delegatorAddr, denom).Amount require.True(sdk.IntEq(t, amt1.Sub(initBond), amt2)) // apply TM updates @@ -477,7 +477,7 @@ func TestIncrementsMsgUnbond(t *testing.T) { gotBond := bond.Shares.RoundInt() gotDelegatorShares := validator.DelegatorShares.RoundInt() - gotDelegatorAcc := accMapper.GetAccount(ctx, delegatorAddr).GetCoins().AmountOf(params.BondDenom) + gotDelegatorAcc := bk.GetBalance(ctx, delegatorAddr, params.BondDenom).Amount require.Equal(t, expBond.Int64(), gotBond.Int64(), "i: %v\nexpBond: %v\ngotBond: %v\nvalidator: %v\nbond: %v\n", @@ -520,7 +520,7 @@ func TestIncrementsMsgUnbond(t *testing.T) { func TestMultipleMsgCreateValidator(t *testing.T) { initPower := int64(1000) initTokens := sdk.TokensFromConsensusPower(initPower) - ctx, accMapper, keeper, _ := keep.CreateTestInput(t, false, initPower) + ctx, _, bk, keeper, _ := keep.CreateTestInput(t, false, initPower) params := keeper.GetParams(ctx) blockTime := time.Now().UTC() @@ -552,7 +552,7 @@ func TestMultipleMsgCreateValidator(t *testing.T) { val := validators[i] balanceExpd := initTokens.Sub(valTokens) - balanceGot := accMapper.GetAccount(ctx, delegatorAddrs[i]).GetCoins().AmountOf(params.BondDenom) + balanceGot := bk.GetBalance(ctx, delegatorAddrs[i], params.BondDenom).Amount require.Equal(t, i+1, len(validators), "expected %d validators got %d, validators: %v", i+1, len(validators), validators) require.Equal(t, valTokens, val.DelegatorShares.RoundInt(), "expected %d shares, got %d", 10, val.DelegatorShares) @@ -589,13 +589,13 @@ func TestMultipleMsgCreateValidator(t *testing.T) { _, found = keeper.GetValidator(ctx, validatorAddr) require.False(t, found) - gotBalance := accMapper.GetAccount(ctx, delegatorAddrs[i]).GetCoins().AmountOf(params.BondDenom) + gotBalance := bk.GetBalance(ctx, delegatorAddrs[i], params.BondDenom).Amount require.Equal(t, initTokens, gotBalance, "expected account to have %d, got %d", initTokens, gotBalance) } } func TestMultipleMsgDelegate(t *testing.T) { - ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) validatorAddr, delegatorAddrs := sdk.ValAddress(keep.Addrs[0]), keep.Addrs[1:] // first make a validator @@ -639,7 +639,7 @@ func TestMultipleMsgDelegate(t *testing.T) { } func TestJailValidator(t *testing.T) { - ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) validatorAddr, delegatorAddr := sdk.ValAddress(keep.Addrs[0]), keep.Addrs[1] // create the validator @@ -689,7 +689,7 @@ func TestJailValidator(t *testing.T) { } func TestValidatorQueue(t *testing.T) { - ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) validatorAddr, delegatorAddr := sdk.ValAddress(keep.Addrs[0]), keep.Addrs[1] // set the unbonding time @@ -750,7 +750,7 @@ func TestValidatorQueue(t *testing.T) { } func TestUnbondingPeriod(t *testing.T) { - ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) validatorAddr := sdk.ValAddress(keep.Addrs[0]) // set the unbonding time @@ -798,7 +798,7 @@ func TestUnbondingPeriod(t *testing.T) { } func TestUnbondingFromUnbondingValidator(t *testing.T) { - ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) validatorAddr, delegatorAddr := sdk.ValAddress(keep.Addrs[0]), keep.Addrs[1] // create the validator @@ -843,7 +843,7 @@ func TestUnbondingFromUnbondingValidator(t *testing.T) { } func TestRedelegationPeriod(t *testing.T) { - ctx, AccMapper, keeper, _ := keep.CreateTestInput(t, false, 1000) + ctx, _, bk, keeper, _ := keep.CreateTestInput(t, false, 1000) validatorAddr, validatorAddr2 := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1]) denom := keeper.GetParams(ctx).BondDenom @@ -856,14 +856,14 @@ func TestRedelegationPeriod(t *testing.T) { msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], sdk.NewInt(10)) // initial balance - amt1 := AccMapper.GetAccount(ctx, sdk.AccAddress(validatorAddr)).GetCoins().AmountOf(denom) + amt1 := bk.GetBalance(ctx, sdk.AccAddress(validatorAddr), denom).Amount res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) require.NoError(t, err) require.NotNil(t, res) // balance should have been subtracted after creation - amt2 := AccMapper.GetAccount(ctx, sdk.AccAddress(validatorAddr)).GetCoins().AmountOf(denom) + amt2 := bk.GetBalance(ctx, sdk.AccAddress(validatorAddr), denom).Amount require.Equal(t, amt1.Sub(sdk.NewInt(10)).Int64(), amt2.Int64(), "expected coins to be subtracted") msgCreateValidator = NewTestMsgCreateValidator(validatorAddr2, keep.PKs[1], sdk.NewInt(10)) @@ -871,7 +871,7 @@ func TestRedelegationPeriod(t *testing.T) { require.NoError(t, err) require.NotNil(t, res) - bal1 := AccMapper.GetAccount(ctx, sdk.AccAddress(validatorAddr)).GetCoins() + bal1 := bk.GetAllBalances(ctx, sdk.AccAddress(validatorAddr)) // begin redelegate redAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) @@ -881,7 +881,7 @@ func TestRedelegationPeriod(t *testing.T) { require.NotNil(t, res) // origin account should not lose tokens as with a regular delegation - bal2 := AccMapper.GetAccount(ctx, sdk.AccAddress(validatorAddr)).GetCoins() + bal2 := bk.GetAllBalances(ctx, sdk.AccAddress(validatorAddr)) require.Equal(t, bal1, bal2) origHeader := ctx.BlockHeader() @@ -905,7 +905,7 @@ func TestRedelegationPeriod(t *testing.T) { } func TestTransitiveRedelegation(t *testing.T) { - ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) validatorAddr := sdk.ValAddress(keep.Addrs[0]) validatorAddr2 := sdk.ValAddress(keep.Addrs[1]) validatorAddr3 := sdk.ValAddress(keep.Addrs[2]) @@ -955,7 +955,7 @@ func TestTransitiveRedelegation(t *testing.T) { } func TestMultipleRedelegationAtSameTime(t *testing.T) { - ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) valAddr := sdk.ValAddress(keep.Addrs[0]) valAddr2 := sdk.ValAddress(keep.Addrs[1]) @@ -1011,7 +1011,7 @@ func TestMultipleRedelegationAtSameTime(t *testing.T) { } func TestMultipleRedelegationAtUniqueTimes(t *testing.T) { - ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) valAddr := sdk.ValAddress(keep.Addrs[0]) valAddr2 := sdk.ValAddress(keep.Addrs[1]) @@ -1069,7 +1069,7 @@ func TestMultipleRedelegationAtUniqueTimes(t *testing.T) { } func TestMultipleUnbondingDelegationAtSameTime(t *testing.T) { - ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) valAddr := sdk.ValAddress(keep.Addrs[0]) // set the unbonding time @@ -1119,7 +1119,7 @@ func TestMultipleUnbondingDelegationAtSameTime(t *testing.T) { } func TestMultipleUnbondingDelegationAtUniqueTimes(t *testing.T) { - ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) valAddr := sdk.ValAddress(keep.Addrs[0]) // set the unbonding time @@ -1176,7 +1176,7 @@ func TestMultipleUnbondingDelegationAtUniqueTimes(t *testing.T) { } func TestUnbondingWhenExcessValidators(t *testing.T) { - ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) validatorAddr1 := sdk.ValAddress(keep.Addrs[0]) validatorAddr2 := sdk.ValAddress(keep.Addrs[1]) validatorAddr3 := sdk.ValAddress(keep.Addrs[2]) @@ -1238,7 +1238,7 @@ func TestUnbondingWhenExcessValidators(t *testing.T) { } func TestBondUnbondRedelegateSlashTwice(t *testing.T) { - ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) valA, valB, del := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1]), keep.Addrs[2] consAddr0 := sdk.ConsAddress(keep.PKs[0].Address()) @@ -1353,7 +1353,7 @@ func TestInvalidMsg(t *testing.T) { } func TestInvalidCoinDenom(t *testing.T) { - ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) valA, valB, delAddr := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1]), keep.Addrs[2] valTokens := sdk.TokensFromConsensusPower(100) diff --git a/x/staking/keeper/delegation_test.go b/x/staking/keeper/delegation_test.go index e3e619697679..f2832dd498d2 100644 --- a/x/staking/keeper/delegation_test.go +++ b/x/staking/keeper/delegation_test.go @@ -13,7 +13,7 @@ import ( // tests GetDelegation, GetDelegatorDelegations, SetDelegation, RemoveDelegation, GetDelegatorDelegations func TestDelegation(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 10) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 10) //construct the validators amts := []sdk.Int{sdk.NewInt(9), sdk.NewInt(8), sdk.NewInt(7)} @@ -128,7 +128,7 @@ func TestDelegation(t *testing.T) { // tests Get/Set/Remove UnbondingDelegation func TestUnbondingDelegation(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 0) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 0) ubd := types.NewUnbondingDelegation(addrDels[0], addrVals[0], 0, time.Unix(0, 0), sdk.NewInt(5)) @@ -167,13 +167,12 @@ func TestUnbondingDelegation(t *testing.T) { } func TestUnbondDelegation(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 0) + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) startTokens := sdk.TokensFromConsensusPower(10) - notBondedPool := keeper.GetNotBondedPool(ctx) - err := notBondedPool.SetCoins(sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), startTokens))) - require.NoError(t, err) + + require.NoError(t, bk.SetBalances(ctx, notBondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), startTokens)))) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) // create a validator and a delegator to that validator @@ -204,12 +203,13 @@ func TestUnbondDelegation(t *testing.T) { } func TestUnbondingDelegationsMaxEntries(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 1) + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 1) startTokens := sdk.TokensFromConsensusPower(10) - bondDenom := keeper.BondDenom(ctx) + bondDenom := keeper.BondDenom(ctx) notBondedPool := keeper.GetNotBondedPool(ctx) - err := notBondedPool.SetCoins(sdk.NewCoins(sdk.NewCoin(bondDenom, startTokens))) + + err := bk.SetBalances(ctx, notBondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(bondDenom, startTokens))) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) @@ -228,8 +228,8 @@ func TestUnbondingDelegationsMaxEntries(t *testing.T) { maxEntries := keeper.MaxEntries(ctx) - oldBonded := keeper.GetBondedPool(ctx).GetCoins().AmountOf(bondDenom) - oldNotBonded := keeper.GetNotBondedPool(ctx).GetCoins().AmountOf(bondDenom) + oldBonded := bk.GetBalance(ctx, keeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount + oldNotBonded := bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount // should all pass var completionTime time.Time @@ -239,51 +239,50 @@ func TestUnbondingDelegationsMaxEntries(t *testing.T) { require.NoError(t, err) } - bondedPool := keeper.GetBondedPool(ctx) - notBondedPool = keeper.GetNotBondedPool(ctx) - require.True(sdk.IntEq(t, bondedPool.GetCoins().AmountOf(bondDenom), oldBonded.SubRaw(int64(maxEntries)))) - require.True(sdk.IntEq(t, notBondedPool.GetCoins().AmountOf(bondDenom), oldNotBonded.AddRaw(int64(maxEntries)))) + newBonded := bk.GetBalance(ctx, keeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount + newNotBonded := bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, newBonded, oldBonded.SubRaw(int64(maxEntries)))) + require.True(sdk.IntEq(t, newNotBonded, oldNotBonded.AddRaw(int64(maxEntries)))) - oldBonded = bondedPool.GetCoins().AmountOf(bondDenom) - oldNotBonded = notBondedPool.GetCoins().AmountOf(bondDenom) + oldBonded = bk.GetBalance(ctx, keeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount + oldNotBonded = bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount // an additional unbond should fail due to max entries _, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], sdk.NewDec(1)) require.Error(t, err) - bondedPool = keeper.GetBondedPool(ctx) - notBondedPool = keeper.GetNotBondedPool(ctx) - require.True(sdk.IntEq(t, bondedPool.GetCoins().AmountOf(bondDenom), oldBonded)) - require.True(sdk.IntEq(t, notBondedPool.GetCoins().AmountOf(bondDenom), oldNotBonded)) + newBonded = bk.GetBalance(ctx, keeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount + newNotBonded = bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount + + require.True(sdk.IntEq(t, newBonded, oldBonded)) + require.True(sdk.IntEq(t, newNotBonded, oldNotBonded)) // mature unbonding delegations ctx = ctx.WithBlockTime(completionTime) err = keeper.CompleteUnbonding(ctx, addrDels[0], addrVals[0]) require.NoError(t, err) - bondedPool = keeper.GetBondedPool(ctx) - notBondedPool = keeper.GetNotBondedPool(ctx) - require.True(sdk.IntEq(t, bondedPool.GetCoins().AmountOf(bondDenom), oldBonded)) - require.True(sdk.IntEq(t, notBondedPool.GetCoins().AmountOf(bondDenom), oldNotBonded.SubRaw(int64(maxEntries)))) + newBonded = bk.GetBalance(ctx, keeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount + newNotBonded = bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, newBonded, oldBonded)) + require.True(sdk.IntEq(t, newNotBonded, oldNotBonded.SubRaw(int64(maxEntries)))) - oldNotBonded = notBondedPool.GetCoins().AmountOf(bondDenom) + oldNotBonded = bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount // unbonding should work again _, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], sdk.NewDec(1)) require.NoError(t, err) - bondedPool = keeper.GetBondedPool(ctx) - - notBondedPool = keeper.GetNotBondedPool(ctx) - require.True(sdk.IntEq(t, bondedPool.GetCoins().AmountOf(bondDenom), oldBonded.SubRaw(1))) - require.True(sdk.IntEq(t, notBondedPool.GetCoins().AmountOf(bondDenom), oldNotBonded.AddRaw(1))) + newBonded = bk.GetBalance(ctx, keeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount + newNotBonded = bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, newBonded, oldBonded.SubRaw(1))) + require.True(sdk.IntEq(t, newNotBonded, oldNotBonded.AddRaw(1))) } // test undelegating self delegation from a validator pushing it below MinSelfDelegation // shift it from the bonded to unbonding state and jailed func TestUndelegateSelfDelegationBelowMinSelfDelegation(t *testing.T) { - - ctx, _, keeper, _ := CreateTestInput(t, false, 0) + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) delTokens := sdk.TokensFromConsensusPower(10) delCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), delTokens)) @@ -296,7 +295,8 @@ func TestUndelegateSelfDelegationBelowMinSelfDelegation(t *testing.T) { // add bonded tokens to pool for delegations notBondedPool := keeper.GetNotBondedPool(ctx) - err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(delCoins...)) + oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) + err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(delCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) @@ -308,7 +308,8 @@ func TestUndelegateSelfDelegationBelowMinSelfDelegation(t *testing.T) { // add bonded tokens to pool for delegations bondedPool := keeper.GetBondedPool(ctx) - err = bondedPool.SetCoins(bondedPool.GetCoins().Add(delCoins...)) + oldBonded := bk.GetAllBalances(ctx, bondedPool.GetAddress()) + err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) @@ -319,8 +320,8 @@ func TestUndelegateSelfDelegationBelowMinSelfDelegation(t *testing.T) { require.Equal(t, delTokens, issuedShares.RoundInt()) // add bonded tokens to pool for delegations - bondedPool = keeper.GetBondedPool(ctx) - err = bondedPool.SetCoins(bondedPool.GetCoins().Add(delCoins...)) + oldBonded = bk.GetAllBalances(ctx, bondedPool.GetAddress()) + err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) @@ -344,7 +345,7 @@ func TestUndelegateSelfDelegationBelowMinSelfDelegation(t *testing.T) { } func TestUndelegateFromUnbondingValidator(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 0) + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) delTokens := sdk.TokensFromConsensusPower(10) delCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), delTokens)) @@ -356,7 +357,8 @@ func TestUndelegateFromUnbondingValidator(t *testing.T) { // add bonded tokens to pool for delegations notBondedPool := keeper.GetNotBondedPool(ctx) - err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(delCoins...)) + oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) + err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(delCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) @@ -367,7 +369,8 @@ func TestUndelegateFromUnbondingValidator(t *testing.T) { keeper.SetDelegation(ctx, selfDelegation) bondedPool := keeper.GetBondedPool(ctx) - err = bondedPool.SetCoins(bondedPool.GetCoins().Add(delCoins...)) + oldBonded := bk.GetAllBalances(ctx, bondedPool.GetAddress()) + err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) @@ -377,8 +380,8 @@ func TestUndelegateFromUnbondingValidator(t *testing.T) { validator, issuedShares = validator.AddTokensFromDel(delTokens) require.Equal(t, delTokens, issuedShares.RoundInt()) - bondedPool = keeper.GetBondedPool(ctx) - err = bondedPool.SetCoins(bondedPool.GetCoins().Add(delCoins...)) + oldBonded = bk.GetAllBalances(ctx, bondedPool.GetAddress()) + err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) @@ -386,8 +389,8 @@ func TestUndelegateFromUnbondingValidator(t *testing.T) { delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) keeper.SetDelegation(ctx, delegation) - bondedPool = keeper.GetBondedPool(ctx) - err = bondedPool.SetCoins(bondedPool.GetCoins().Add(delCoins...)) + oldBonded = bk.GetAllBalances(ctx, bondedPool.GetAddress()) + err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) @@ -432,13 +435,14 @@ func TestUndelegateFromUnbondingValidator(t *testing.T) { } func TestUndelegateFromUnbondedValidator(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 1) + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 1) delTokens := sdk.TokensFromConsensusPower(10) delCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), delTokens)) // add bonded tokens to pool for delegations notBondedPool := keeper.GetNotBondedPool(ctx) - err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(delCoins...)) + oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) + err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(delCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) @@ -456,7 +460,8 @@ func TestUndelegateFromUnbondedValidator(t *testing.T) { keeper.SetDelegation(ctx, selfDelegation) bondedPool := keeper.GetBondedPool(ctx) - err = bondedPool.SetCoins(bondedPool.GetCoins().Add(delCoins...)) + oldBonded := bk.GetAllBalances(ctx, bondedPool.GetAddress()) + err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) @@ -511,13 +516,14 @@ func TestUndelegateFromUnbondedValidator(t *testing.T) { } func TestUnbondingAllDelegationFromValidator(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 0) + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) delTokens := sdk.TokensFromConsensusPower(10) delCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), delTokens)) // add bonded tokens to pool for delegations notBondedPool := keeper.GetNotBondedPool(ctx) - err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(delCoins...)) + oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) + err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(delCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) @@ -541,7 +547,8 @@ func TestUnbondingAllDelegationFromValidator(t *testing.T) { require.Equal(t, delTokens, issuedShares.RoundInt()) bondedPool := keeper.GetBondedPool(ctx) - err = bondedPool.SetCoins(bondedPool.GetCoins().Add(delCoins...)) + oldBonded := bk.GetAllBalances(ctx, bondedPool.GetAddress()) + err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) @@ -582,7 +589,7 @@ func TestUnbondingAllDelegationFromValidator(t *testing.T) { // Make sure that that the retrieving the delegations doesn't affect the state func TestGetRedelegationsFromSrcValidator(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 0) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 0) rd := types.NewRedelegation(addrDels[0], addrVals[0], addrVals[1], 0, time.Unix(0, 0), sdk.NewInt(5), @@ -606,7 +613,7 @@ func TestGetRedelegationsFromSrcValidator(t *testing.T) { // tests Get/Set/Remove/Has UnbondingDelegation func TestRedelegation(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 0) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 0) rd := types.NewRedelegation(addrDels[0], addrVals[0], addrVals[1], 0, time.Unix(0, 0), sdk.NewInt(5), @@ -666,13 +673,14 @@ func TestRedelegation(t *testing.T) { } func TestRedelegateToSameValidator(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 0) + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) valTokens := sdk.TokensFromConsensusPower(10) startCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), valTokens)) // add bonded tokens to pool for delegations notBondedPool := keeper.GetNotBondedPool(ctx) - err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(startCoins...)) + oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) + err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) @@ -689,17 +697,17 @@ func TestRedelegateToSameValidator(t *testing.T) { _, err = keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[0], sdk.NewDec(5)) require.Error(t, err) - } func TestRedelegationMaxEntries(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 0) + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) startTokens := sdk.TokensFromConsensusPower(20) startCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), startTokens)) // add bonded tokens to pool for delegations notBondedPool := keeper.GetNotBondedPool(ctx) - err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(startCoins...)) + oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) + err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) @@ -746,13 +754,14 @@ func TestRedelegationMaxEntries(t *testing.T) { } func TestRedelegateSelfDelegation(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 0) + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) startTokens := sdk.TokensFromConsensusPower(30) startCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), startTokens)) // add bonded tokens to pool for delegations notBondedPool := keeper.GetNotBondedPool(ctx) - err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(startCoins...)) + oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) + err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) @@ -798,13 +807,14 @@ func TestRedelegateSelfDelegation(t *testing.T) { } func TestRedelegateFromUnbondingValidator(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 0) + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) startTokens := sdk.TokensFromConsensusPower(30) startCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), startTokens)) // add bonded tokens to pool for delegations notBondedPool := keeper.GetNotBondedPool(ctx) - err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(startCoins...)) + oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) + err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) @@ -877,13 +887,14 @@ func TestRedelegateFromUnbondingValidator(t *testing.T) { } func TestRedelegateFromUnbondedValidator(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 0) + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) startTokens := sdk.TokensFromConsensusPower(30) startCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), startTokens)) // add bonded tokens to pool for delegations notBondedPool := keeper.GetNotBondedPool(ctx) - err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(startCoins...)) + oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) + err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) diff --git a/x/staking/keeper/historical_info_test.go b/x/staking/keeper/historical_info_test.go index 204dd3ac512d..574d0c9dd9af 100644 --- a/x/staking/keeper/historical_info_test.go +++ b/x/staking/keeper/historical_info_test.go @@ -13,7 +13,7 @@ import ( ) func TestHistoricalInfo(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 10) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 10) validators := make([]types.Validator, len(addrVals)) for i, valAddr := range addrVals { @@ -37,7 +37,7 @@ func TestHistoricalInfo(t *testing.T) { } func TestTrackHistoricalInfo(t *testing.T) { - ctx, _, k, _ := CreateTestInput(t, false, 10) + ctx, _, _, k, _ := CreateTestInput(t, false, 10) // set historical entries in params to 5 params := types.DefaultParams() diff --git a/x/staking/keeper/invariants.go b/x/staking/keeper/invariants.go index e89cfab1d047..0dc0a83824b3 100644 --- a/x/staking/keeper/invariants.go +++ b/x/staking/keeper/invariants.go @@ -74,9 +74,9 @@ func ModuleAccountInvariants(k Keeper) sdk.Invariant { return false }) - poolBonded := bondedPool.GetCoins().AmountOf(bondDenom) - poolNotBonded := notBondedPool.GetCoins().AmountOf(bondDenom) - broken := !poolBonded.Equal(bonded) || !poolNotBonded.Equal(notBonded) + poolBonded := k.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom) + poolNotBonded := k.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom) + broken := !poolBonded.Amount.Equal(bonded) || !poolNotBonded.Amount.Equal(notBonded) // Bonded tokens should equal sum of tokens with bonded validators // Not-bonded tokens should equal unbonding delegations plus tokens on unbonded validators diff --git a/x/staking/keeper/keeper.go b/x/staking/keeper/keeper.go index fd51603115b7..412f6a3a8464 100644 --- a/x/staking/keeper/keeper.go +++ b/x/staking/keeper/keeper.go @@ -24,6 +24,7 @@ var _ types.DelegationSet = Keeper{} type Keeper struct { storeKey sdk.StoreKey cdc *codec.Codec + bankKeeper types.BankKeeper supplyKeeper types.SupplyKeeper hooks types.StakingHooks paramstore params.Subspace @@ -33,23 +34,24 @@ type Keeper struct { // NewKeeper creates a new staking Keeper instance func NewKeeper( - cdc *codec.Codec, key sdk.StoreKey, supplyKeeper types.SupplyKeeper, paramstore params.Subspace, + cdc *codec.Codec, key sdk.StoreKey, bk types.BankKeeper, sk types.SupplyKeeper, ps params.Subspace, ) Keeper { // ensure bonded and not bonded module accounts are set - if addr := supplyKeeper.GetModuleAddress(types.BondedPoolName); addr == nil { + if addr := sk.GetModuleAddress(types.BondedPoolName); addr == nil { panic(fmt.Sprintf("%s module account has not been set", types.BondedPoolName)) } - if addr := supplyKeeper.GetModuleAddress(types.NotBondedPoolName); addr == nil { + if addr := sk.GetModuleAddress(types.NotBondedPoolName); addr == nil { panic(fmt.Sprintf("%s module account has not been set", types.NotBondedPoolName)) } return Keeper{ storeKey: key, cdc: cdc, - supplyKeeper: supplyKeeper, - paramstore: paramstore.WithKeyTable(ParamKeyTable()), + bankKeeper: bk, + supplyKeeper: sk, + paramstore: ps.WithKeyTable(ParamKeyTable()), hooks: nil, validatorCache: make(map[string]cachedValidator, aminoCacheSize), validatorCacheList: list.New(), diff --git a/x/staking/keeper/keeper_test.go b/x/staking/keeper/keeper_test.go index eb9d16459e49..dbde12e7b1a9 100644 --- a/x/staking/keeper/keeper_test.go +++ b/x/staking/keeper/keeper_test.go @@ -9,7 +9,7 @@ import ( ) func TestParams(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 0) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 0) expParams := types.DefaultParams() //check that the empty keeper loads the default diff --git a/x/staking/keeper/pool.go b/x/staking/keeper/pool.go index 004013ed8fe4..d593bbbe53be 100644 --- a/x/staking/keeper/pool.go +++ b/x/staking/keeper/pool.go @@ -57,7 +57,7 @@ func (k Keeper) burnNotBondedTokens(ctx sdk.Context, amt sdk.Int) error { // TotalBondedTokens total staking tokens supply which is bonded func (k Keeper) TotalBondedTokens(ctx sdk.Context) sdk.Int { bondedPool := k.GetBondedPool(ctx) - return bondedPool.GetCoins().AmountOf(k.BondDenom(ctx)) + return k.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), k.BondDenom(ctx)).Amount } // StakingTokenSupply staking tokens from the total supply @@ -67,11 +67,10 @@ func (k Keeper) StakingTokenSupply(ctx sdk.Context) sdk.Int { // BondedRatio the fraction of the staking tokens which are currently bonded func (k Keeper) BondedRatio(ctx sdk.Context) sdk.Dec { - bondedPool := k.GetBondedPool(ctx) - stakeSupply := k.StakingTokenSupply(ctx) if stakeSupply.IsPositive() { - return bondedPool.GetCoins().AmountOf(k.BondDenom(ctx)).ToDec().QuoInt(stakeSupply) + return k.TotalBondedTokens(ctx).ToDec().QuoInt(stakeSupply) } + return sdk.ZeroDec() } diff --git a/x/staking/keeper/querier.go b/x/staking/keeper/querier.go index bc8a5b5b7fc0..1c9f54e7d3f0 100644 --- a/x/staking/keeper/querier.go +++ b/x/staking/keeper/querier.go @@ -375,8 +375,8 @@ func queryPool(ctx sdk.Context, k Keeper) ([]byte, error) { } pool := types.NewPool( - notBondedPool.GetCoins().AmountOf(bondDenom), - bondedPool.GetCoins().AmountOf(bondDenom), + k.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount, + k.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount, ) res, err := codec.MarshalJSONIndent(types.ModuleCdc, pool) diff --git a/x/staking/keeper/querier_test.go b/x/staking/keeper/querier_test.go index 320266ca1a28..2bbd468ae075 100644 --- a/x/staking/keeper/querier_test.go +++ b/x/staking/keeper/querier_test.go @@ -20,7 +20,7 @@ var ( func TestNewQuerier(t *testing.T) { cdc := codec.New() - ctx, _, keeper, _ := CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) // Create Validators amts := []sdk.Int{sdk.NewInt(9), sdk.NewInt(8)} var validators [2]types.Validator @@ -107,7 +107,7 @@ func TestNewQuerier(t *testing.T) { func TestQueryParametersPool(t *testing.T) { cdc := codec.New() - ctx, _, keeper, _ := CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) bondDenom := sdk.DefaultBondDenom res, err := queryParameters(ctx, keeper) @@ -124,15 +124,14 @@ func TestQueryParametersPool(t *testing.T) { var pool types.Pool bondedPool := keeper.GetBondedPool(ctx) notBondedPool := keeper.GetNotBondedPool(ctx) - errRes = cdc.UnmarshalJSON(res, &pool) - require.NoError(t, errRes) - require.Equal(t, bondedPool.GetCoins().AmountOf(bondDenom), pool.BondedTokens) - require.Equal(t, notBondedPool.GetCoins().AmountOf(bondDenom), pool.NotBondedTokens) + require.NoError(t, cdc.UnmarshalJSON(res, &pool)) + require.Equal(t, keeper.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount, pool.NotBondedTokens) + require.Equal(t, keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount, pool.BondedTokens) } func TestQueryValidators(t *testing.T) { cdc := codec.New() - ctx, _, keeper, _ := CreateTestInput(t, false, 10000) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 10000) params := keeper.GetParams(ctx) // Create Validators @@ -195,7 +194,7 @@ func TestQueryValidators(t *testing.T) { func TestQueryDelegation(t *testing.T) { cdc := codec.New() - ctx, _, keeper, _ := CreateTestInput(t, false, 10000) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 10000) params := keeper.GetParams(ctx) // Create Validators and Delegation @@ -415,7 +414,7 @@ func TestQueryDelegation(t *testing.T) { func TestQueryRedelegations(t *testing.T) { cdc := codec.New() - ctx, _, keeper, _ := CreateTestInput(t, false, 10000) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 10000) // Create Validators and Delegation val1 := types.NewValidator(addrVal1, pk1, types.Description{}) @@ -480,7 +479,7 @@ func TestQueryRedelegations(t *testing.T) { func TestQueryUnbondingDelegation(t *testing.T) { cdc := codec.New() - ctx, _, keeper, _ := CreateTestInput(t, false, 10000) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 10000) // Create Validators and Delegation val1 := types.NewValidator(addrVal1, pk1, types.Description{}) @@ -571,7 +570,7 @@ func TestQueryUnbondingDelegation(t *testing.T) { func TestQueryHistoricalInfo(t *testing.T) { cdc := codec.New() - ctx, _, keeper, _ := CreateTestInput(t, false, 10000) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 10000) // Create Validators and Delegation val1 := types.NewValidator(addrVal1, pk1, types.Description{}) diff --git a/x/staking/keeper/slash_test.go b/x/staking/keeper/slash_test.go index cc4d4651731a..2127cf51e196 100644 --- a/x/staking/keeper/slash_test.go +++ b/x/staking/keeper/slash_test.go @@ -15,17 +15,15 @@ import ( // TODO integrate with test_common.go helper (CreateTestInput) // setup helper function - creates two validators func setupHelper(t *testing.T, power int64) (sdk.Context, Keeper, types.Params) { - // setup - ctx, _, keeper, _ := CreateTestInput(t, false, power) + ctx, _, _, keeper, _ := CreateTestInput(t, false, power) params := keeper.GetParams(ctx) numVals := int64(3) amt := sdk.TokensFromConsensusPower(power) bondedCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), amt.MulRaw(numVals))) bondedPool := keeper.GetBondedPool(ctx) - err := bondedPool.SetCoins(bondedCoins) - require.NoError(t, err) + require.NoError(t, keeper.bankKeeper.SetBalances(ctx, bondedPool.GetAddress(), bondedCoins)) keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) // add numVals validators @@ -43,7 +41,6 @@ func setupHelper(t *testing.T, power int64) (sdk.Context, Keeper, types.Params) // tests Jail, Unjail func TestRevocation(t *testing.T) { - // setup ctx, keeper, _ := setupHelper(t, 10) addr := addrVals[0] @@ -90,7 +87,8 @@ func TestSlashUnbondingDelegation(t *testing.T) { require.Equal(t, int64(0), slashAmount.Int64()) // test valid slash, before expiration timestamp and to which stake contributed - oldUnbondedPool := keeper.GetNotBondedPool(ctx) + notBondedPool := keeper.GetNotBondedPool(ctx) + oldUnbondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(0, 0)}) keeper.SetUnbondingDelegation(ctx, ubd) slashAmount = keeper.slashUnbondingDelegation(ctx, ubd, 0, fraction) @@ -104,9 +102,9 @@ func TestSlashUnbondingDelegation(t *testing.T) { // balance decreased require.Equal(t, sdk.NewInt(5), ubd.Entries[0].Balance) - newUnbondedPool := keeper.GetNotBondedPool(ctx) - diffTokens := oldUnbondedPool.GetCoins().Sub(newUnbondedPool.GetCoins()).AmountOf(keeper.BondDenom(ctx)) - require.Equal(t, int64(5), diffTokens.Int64()) + newUnbondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) + diffTokens := oldUnbondedPoolBalances.Sub(newUnbondedPoolBalances) + require.Equal(t, int64(5), diffTokens.AmountOf(keeper.BondDenom(ctx)).Int64()) } // tests slashRedelegation @@ -117,8 +115,9 @@ func TestSlashRedelegation(t *testing.T) { // add bonded tokens to pool for (re)delegations startCoins := sdk.NewCoins(sdk.NewInt64Coin(keeper.BondDenom(ctx), 15)) bondedPool := keeper.GetBondedPool(ctx) - err := bondedPool.SetCoins(bondedPool.GetCoins().Add(startCoins...)) - require.NoError(t, err) + balances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + + require.NoError(t, keeper.bankKeeper.SetBalances(ctx, bondedPool.GetAddress(), balances.Add(startCoins...))) keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) // set a redelegation with an expiration timestamp beyond which the @@ -146,6 +145,8 @@ func TestSlashRedelegation(t *testing.T) { slashAmount = keeper.slashRedelegation(ctx, validator, rd, 0, fraction) require.Equal(t, int64(0), slashAmount.Int64()) + balances = keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + // test valid slash, before expiration timestamp and to which stake contributed ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(0, 0)}) keeper.SetRedelegation(ctx, rd) @@ -171,8 +172,7 @@ func TestSlashRedelegation(t *testing.T) { // pool bonded tokens should decrease burnedCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), slashAmount)) - newBondedPool := keeper.GetBondedPool(ctx) - require.Equal(t, bondedPool.GetCoins().Sub(burnedCoins), newBondedPool.GetCoins()) + require.Equal(t, balances.Sub(burnedCoins), keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress())) } // tests Slash at a future height (must panic) @@ -190,7 +190,9 @@ func TestSlashAtNegativeHeight(t *testing.T) { consAddr := sdk.ConsAddress(PKs[0].Address()) fraction := sdk.NewDecWithPrec(5, 1) - oldBondedPool := keeper.GetBondedPool(ctx) + bondedPool := keeper.GetBondedPool(ctx) + oldBondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + validator, found := keeper.GetValidatorByConsAddr(ctx, consAddr) require.True(t, found) keeper.Slash(ctx, consAddr, -2, 10, fraction) @@ -198,7 +200,6 @@ func TestSlashAtNegativeHeight(t *testing.T) { // read updated state validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) require.True(t, found) - newBondedPool := keeper.GetBondedPool(ctx) // end block updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) @@ -207,9 +208,11 @@ func TestSlashAtNegativeHeight(t *testing.T) { validator = keeper.mustGetValidator(ctx, validator.OperatorAddress) // power decreased require.Equal(t, int64(5), validator.GetConsensusPower()) + // pool bonded shares decreased - diffTokens := oldBondedPool.GetCoins().Sub(newBondedPool.GetCoins()).AmountOf(keeper.BondDenom(ctx)) - require.Equal(t, sdk.TokensFromConsensusPower(5), diffTokens) + newBondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + diffTokens := oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(keeper.BondDenom(ctx)) + require.Equal(t, sdk.TokensFromConsensusPower(5).String(), diffTokens.String()) } // tests Slash at the current height @@ -218,7 +221,9 @@ func TestSlashValidatorAtCurrentHeight(t *testing.T) { consAddr := sdk.ConsAddress(PKs[0].Address()) fraction := sdk.NewDecWithPrec(5, 1) - oldBondedPool := keeper.GetBondedPool(ctx) + bondedPool := keeper.GetBondedPool(ctx) + oldBondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + validator, found := keeper.GetValidatorByConsAddr(ctx, consAddr) require.True(t, found) keeper.Slash(ctx, consAddr, ctx.BlockHeight(), 10, fraction) @@ -226,7 +231,6 @@ func TestSlashValidatorAtCurrentHeight(t *testing.T) { // read updated state validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) require.True(t, found) - newBondedPool := keeper.GetBondedPool(ctx) // end block updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) @@ -235,9 +239,11 @@ func TestSlashValidatorAtCurrentHeight(t *testing.T) { validator = keeper.mustGetValidator(ctx, validator.OperatorAddress) // power decreased require.Equal(t, int64(5), validator.GetConsensusPower()) + // pool bonded shares decreased - diffTokens := oldBondedPool.GetCoins().Sub(newBondedPool.GetCoins()).AmountOf(keeper.BondDenom(ctx)) - require.Equal(t, sdk.TokensFromConsensusPower(5), diffTokens) + newBondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + diffTokens := oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(keeper.BondDenom(ctx)) + require.Equal(t, sdk.TokensFromConsensusPower(5).String(), diffTokens.String()) } // tests Slash at a previous height with an unbonding delegation @@ -255,7 +261,9 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { // slash validator for the first time ctx = ctx.WithBlockHeight(12) - oldBondedPool := keeper.GetBondedPool(ctx) + bondedPool := keeper.GetBondedPool(ctx) + oldBondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + validator, found := keeper.GetValidatorByConsAddr(ctx, consAddr) require.True(t, found) keeper.Slash(ctx, consAddr, 10, 10, fraction) @@ -268,16 +276,19 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { ubd, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) require.True(t, found) require.Len(t, ubd.Entries, 1) + // balance decreased require.Equal(t, sdk.TokensFromConsensusPower(2), ubd.Entries[0].Balance) - // read updated pool - newBondedPool := keeper.GetBondedPool(ctx) + // bonded tokens burned - diffTokens := oldBondedPool.GetCoins().Sub(newBondedPool.GetCoins()).AmountOf(keeper.BondDenom(ctx)) + newBondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + diffTokens := oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(keeper.BondDenom(ctx)) require.Equal(t, sdk.TokensFromConsensusPower(3), diffTokens) + // read updated validator validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) require.True(t, found) + // power decreased by 3 - 6 stake originally bonded at the time of infraction // was still bonded at the time of discovery and was slashed by half, 4 stake // bonded at the time of discovery hadn't been bonded at the time of infraction @@ -287,19 +298,23 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { // slash validator again ctx = ctx.WithBlockHeight(13) keeper.Slash(ctx, consAddr, 9, 10, fraction) + ubd, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) require.True(t, found) require.Len(t, ubd.Entries, 1) + // balance decreased again require.Equal(t, sdk.NewInt(0), ubd.Entries[0].Balance) - // read updated pool - newBondedPool = keeper.GetBondedPool(ctx) + // bonded tokens burned again - diffTokens = oldBondedPool.GetCoins().Sub(newBondedPool.GetCoins()).AmountOf(keeper.BondDenom(ctx)) + newBondedPoolBalances = keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + diffTokens = oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(keeper.BondDenom(ctx)) require.Equal(t, sdk.TokensFromConsensusPower(6), diffTokens) + // read updated validator validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) require.True(t, found) + // power decreased by 3 again require.Equal(t, int64(4), validator.GetConsensusPower()) @@ -309,19 +324,23 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { // this may not be the desirable behaviour, ref https://github.com/cosmos/cosmos-sdk/issues/1440 ctx = ctx.WithBlockHeight(13) keeper.Slash(ctx, consAddr, 9, 10, fraction) + ubd, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) require.True(t, found) require.Len(t, ubd.Entries, 1) + // balance unchanged require.Equal(t, sdk.NewInt(0), ubd.Entries[0].Balance) - // read updated pool - newBondedPool = keeper.GetBondedPool(ctx) + // bonded tokens burned again - diffTokens = oldBondedPool.GetCoins().Sub(newBondedPool.GetCoins()).AmountOf(keeper.BondDenom(ctx)) + newBondedPoolBalances = keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + diffTokens = oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(keeper.BondDenom(ctx)) require.Equal(t, sdk.TokensFromConsensusPower(9), diffTokens) + // read updated validator validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) require.True(t, found) + // power decreased by 3 again require.Equal(t, int64(1), validator.GetConsensusPower()) @@ -331,18 +350,22 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { // this may not be the desirable behaviour, ref https://github.com/cosmos/cosmos-sdk/issues/1440 ctx = ctx.WithBlockHeight(13) keeper.Slash(ctx, consAddr, 9, 10, fraction) + ubd, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) require.True(t, found) require.Len(t, ubd.Entries, 1) + // balance unchanged require.Equal(t, sdk.NewInt(0), ubd.Entries[0].Balance) - // read updated pool - newBondedPool = keeper.GetBondedPool(ctx) + // just 1 bonded token burned again since that's all the validator now has - diffTokens = oldBondedPool.GetCoins().Sub(newBondedPool.GetCoins()).AmountOf(keeper.BondDenom(ctx)) + newBondedPoolBalances = keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + diffTokens = oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(keeper.BondDenom(ctx)) require.Equal(t, sdk.TokensFromConsensusPower(10), diffTokens) + // apply TM updates keeper.ApplyAndReturnValidatorSetUpdates(ctx) + // read updated validator // power decreased by 1 again, validator is out of stake // validator should be in unbonding period @@ -371,12 +394,15 @@ func TestSlashWithRedelegation(t *testing.T) { bondedPool := keeper.GetBondedPool(ctx) notBondedPool := keeper.GetNotBondedPool(ctx) rdCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, rdTokens.MulRaw(2))) - err := bondedPool.SetCoins(bondedPool.GetCoins().Add(rdCoins...)) + + balances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + err := keeper.bankKeeper.SetBalances(ctx, bondedPool.GetAddress(), balances.Add(rdCoins...)) require.NoError(t, err) + keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) - oldBonded := bondedPool.GetCoins().AmountOf(bondDenom) - oldNotBonded := notBondedPool.GetCoins().AmountOf(bondDenom) + oldBonded := keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount + oldNotBonded := keeper.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount // slash validator ctx = ctx.WithBlockHeight(12) @@ -388,10 +414,14 @@ func TestSlashWithRedelegation(t *testing.T) { bondedPool = keeper.GetBondedPool(ctx) notBondedPool = keeper.GetNotBondedPool(ctx) + // burn bonded tokens from only from delegations - require.True(sdk.IntEq(t, oldBonded.Sub(burnAmount), bondedPool.GetCoins().AmountOf(bondDenom))) - require.True(sdk.IntEq(t, oldNotBonded, notBondedPool.GetCoins().AmountOf(bondDenom))) - oldBonded = bondedPool.GetCoins().AmountOf(bondDenom) + bondedPoolBalance := keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldBonded.Sub(burnAmount), bondedPoolBalance)) + + notBondedPoolBalance := keeper.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldNotBonded, notBondedPoolBalance)) + oldBonded = keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount // read updating redelegation rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) @@ -416,10 +446,18 @@ func TestSlashWithRedelegation(t *testing.T) { // read updated pool bondedPool = keeper.GetBondedPool(ctx) notBondedPool = keeper.GetNotBondedPool(ctx) + // seven bonded tokens burned - require.True(sdk.IntEq(t, oldBonded.Sub(burnAmount), bondedPool.GetCoins().AmountOf(bondDenom))) - require.True(sdk.IntEq(t, oldNotBonded, notBondedPool.GetCoins().AmountOf(bondDenom))) - oldBonded = bondedPool.GetCoins().AmountOf(bondDenom) + bondedPoolBalance = keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldBonded.Sub(burnAmount), bondedPoolBalance)) + require.True(sdk.IntEq(t, oldNotBonded, notBondedPoolBalance)) + + bondedPoolBalance = keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldBonded.Sub(burnAmount), bondedPoolBalance)) + + notBondedPoolBalance = keeper.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldNotBonded, notBondedPoolBalance)) + oldBonded = keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount // read updating redelegation rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) @@ -444,9 +482,12 @@ func TestSlashWithRedelegation(t *testing.T) { // read updated pool bondedPool = keeper.GetBondedPool(ctx) notBondedPool = keeper.GetNotBondedPool(ctx) - require.True(sdk.IntEq(t, oldBonded.Sub(burnAmount), bondedPool.GetCoins().AmountOf(bondDenom))) - require.True(sdk.IntEq(t, oldNotBonded, notBondedPool.GetCoins().AmountOf(bondDenom))) - oldBonded = bondedPool.GetCoins().AmountOf(bondDenom) + + bondedPoolBalance = keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldBonded.Sub(burnAmount), bondedPoolBalance)) + notBondedPoolBalance = keeper.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldNotBonded, notBondedPoolBalance)) + oldBonded = keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount // read updating redelegation rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) @@ -471,8 +512,11 @@ func TestSlashWithRedelegation(t *testing.T) { // read updated pool bondedPool = keeper.GetBondedPool(ctx) notBondedPool = keeper.GetNotBondedPool(ctx) - require.True(sdk.IntEq(t, oldBonded, bondedPool.GetCoins().AmountOf(bondDenom))) - require.True(sdk.IntEq(t, oldNotBonded, notBondedPool.GetCoins().AmountOf(bondDenom))) + + bondedPoolBalance = keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldBonded, bondedPoolBalance)) + notBondedPoolBalance = keeper.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldNotBonded, notBondedPoolBalance)) // read updating redelegation rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) @@ -515,14 +559,18 @@ func TestSlashBoth(t *testing.T) { // update bonded tokens bondedPool := keeper.GetBondedPool(ctx) notBondedPool := keeper.GetNotBondedPool(ctx) - require.NoError(t, bondedPool.SetCoins(bondedPool.GetCoins().Add(bondedCoins...))) - require.NoError(t, bondedPool.SetCoins(notBondedPool.GetCoins().Add(notBondedCoins...))) + + bondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + require.NoError(t, keeper.bankKeeper.SetBalances(ctx, bondedPool.GetAddress(), bondedPoolBalances.Add(bondedCoins...))) + + notBondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) + require.NoError(t, keeper.bankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), notBondedPoolBalances.Add(notBondedCoins...))) + keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) - oldBonded := bondedPool.GetCoins().AmountOf(bondDenom) - oldNotBonded := notBondedPool.GetCoins().AmountOf(bondDenom) - + oldBonded := keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount + oldNotBonded := keeper.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount // slash validator ctx = ctx.WithBlockHeight(12) validator, found := keeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(PKs[0])) @@ -537,8 +585,12 @@ func TestSlashBoth(t *testing.T) { // read updated pool bondedPool = keeper.GetBondedPool(ctx) notBondedPool = keeper.GetNotBondedPool(ctx) - require.True(sdk.IntEq(t, oldBonded.Sub(burnedBondAmount), bondedPool.GetCoins().AmountOf(bondDenom))) - require.True(sdk.IntEq(t, oldNotBonded.Sub(burnedNotBondedAmount), notBondedPool.GetCoins().AmountOf(bondDenom))) + + bondedPoolBalance := keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldBonded.Sub(burnedBondAmount), bondedPoolBalance)) + + notBondedPoolBalance := keeper.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldNotBonded.Sub(burnedNotBondedAmount), notBondedPoolBalance)) // read updating redelegation rdA, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) diff --git a/x/staking/keeper/test_common.go b/x/staking/keeper/test_common.go index 0d730b48b3ca..65efabe4e25c 100644 --- a/x/staking/keeper/test_common.go +++ b/x/staking/keeper/test_common.go @@ -79,9 +79,10 @@ func MakeTestCodec() *codec.Codec { // Hogpodge of all sorts of input required for testing. // `initPower` is converted to an amount of tokens. // If `initPower` is 0, no addrs get created. -func CreateTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context, auth.AccountKeeper, Keeper, types.SupplyKeeper) { +func CreateTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context, auth.AccountKeeper, types.BankKeeper, Keeper, types.SupplyKeeper) { keyStaking := sdk.NewKVStoreKey(types.StoreKey) keyAcc := sdk.NewKVStoreKey(auth.StoreKey) + bankKey := sdk.NewKVStoreKey(bank.StoreKey) keyParams := sdk.NewKVStoreKey(params.StoreKey) tkeyParams := sdk.NewTransientStoreKey(params.TStoreKey) keySupply := sdk.NewKVStoreKey(supply.StoreKey) @@ -90,6 +91,7 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context ms := store.NewCommitMultiStore(db) ms.MountStoreWithDB(keyStaking, sdk.StoreTypeIAVL, db) ms.MountStoreWithDB(keyAcc, sdk.StoreTypeIAVL, db) + ms.MountStoreWithDB(bankKey, sdk.StoreTypeIAVL, db) ms.MountStoreWithDB(keyParams, sdk.StoreTypeIAVL, db) ms.MountStoreWithDB(tkeyParams, sdk.StoreTypeTransient, db) ms.MountStoreWithDB(keySupply, sdk.StoreTypeIAVL, db) @@ -125,6 +127,8 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context ) bk := bank.NewBaseKeeper( + cdc, + bankKey, accountKeeper, pk.Subspace(bank.DefaultParamspace), blacklistedAddrs, @@ -143,26 +147,23 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context supplyKeeper.SetSupply(ctx, supply.NewSupply(totalSupply)) - keeper := NewKeeper(cdc, keyStaking, supplyKeeper, pk.Subspace(DefaultParamspace)) + keeper := NewKeeper(cdc, keyStaking, bk, supplyKeeper, pk.Subspace(DefaultParamspace)) keeper.SetParams(ctx, types.DefaultParams()) // set module accounts - err = notBondedPool.SetCoins(totalSupply) - require.NoError(t, err) + require.NoError(t, bk.SetBalances(ctx, notBondedPool.GetAddress(), totalSupply)) supplyKeeper.SetModuleAccount(ctx, feeCollectorAcc) supplyKeeper.SetModuleAccount(ctx, bondPool) supplyKeeper.SetModuleAccount(ctx, notBondedPool) // fill all the addresses with some coins, set the loose pool tokens simultaneously - for _, addr := range Addrs { - _, err := bk.AddCoins(ctx, addr, initCoins) - if err != nil { - panic(err) - } + for i, addr := range Addrs { + accountKeeper.SetAccount(ctx, auth.NewBaseAccount(addr, PKs[i], uint64(i), 0)) + require.NoError(t, bk.SetBalances(ctx, addr, initCoins)) } - return ctx, accountKeeper, keeper, supplyKeeper + return ctx, accountKeeper, bk, keeper, supplyKeeper } func NewPubKey(pk string) (res crypto.PubKey) { diff --git a/x/staking/keeper/validator_test.go b/x/staking/keeper/validator_test.go index c01fabbca2da..ae2552fe8373 100644 --- a/x/staking/keeper/validator_test.go +++ b/x/staking/keeper/validator_test.go @@ -17,7 +17,7 @@ import ( //_______________________________________________________ func TestSetValidator(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 10) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 10) valPubKey := PKs[0] valAddr := sdk.ValAddress(valPubKey.Address().Bytes()) @@ -70,12 +70,12 @@ func TestSetValidator(t *testing.T) { } func TestUpdateValidatorByPowerIndex(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 0) + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) bondedPool := keeper.GetBondedPool(ctx) notBondedPool := keeper.GetNotBondedPool(ctx) - bondedPool.SetCoins(sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), sdk.TokensFromConsensusPower(1234)))) - notBondedPool.SetCoins(sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), sdk.TokensFromConsensusPower(10000)))) + bk.SetBalances(ctx, bondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), sdk.TokensFromConsensusPower(1234)))) + bk.SetBalances(ctx, notBondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), sdk.TokensFromConsensusPower(10000)))) keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) @@ -111,7 +111,7 @@ func TestUpdateBondedValidatorsDecreaseCliff(t *testing.T) { maxVals := 5 // create context, keeper, and pool for tests - ctx, _, keeper, _ := CreateTestInput(t, false, 0) + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) bondedPool := keeper.GetBondedPool(ctx) notBondedPool := keeper.GetNotBondedPool(ctx) @@ -121,8 +121,8 @@ func TestUpdateBondedValidatorsDecreaseCliff(t *testing.T) { keeper.SetParams(ctx, params) // create a random pool - bondedPool.SetCoins(sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), sdk.TokensFromConsensusPower(1234)))) - notBondedPool.SetCoins(sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), sdk.TokensFromConsensusPower(10000)))) + bk.SetBalances(ctx, bondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), sdk.TokensFromConsensusPower(1234)))) + bk.SetBalances(ctx, notBondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), sdk.TokensFromConsensusPower(10000)))) keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) @@ -165,14 +165,14 @@ func TestUpdateBondedValidatorsDecreaseCliff(t *testing.T) { func TestSlashToZeroPowerRemoved(t *testing.T) { // initialize setup - ctx, _, keeper, _ := CreateTestInput(t, false, 100) + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 100) // add a validator validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) valTokens := sdk.TokensFromConsensusPower(100) bondedPool := keeper.GetBondedPool(ctx) - err := bondedPool.SetCoins(sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), valTokens))) + err := bk.SetBalances(ctx, bondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), valTokens))) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) @@ -195,7 +195,7 @@ func TestSlashToZeroPowerRemoved(t *testing.T) { // This function tests UpdateValidator, GetValidator, GetLastValidators, RemoveValidator func TestValidatorBasics(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) //construct the validators var validators [3]types.Validator @@ -294,7 +294,7 @@ func TestValidatorBasics(t *testing.T) { // test how the validators are sorted, tests GetBondedValidatorsByPower func TestGetValidatorSortingUnmixed(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) // initialize some validators into the state amts := []int64{ @@ -374,11 +374,12 @@ func TestGetValidatorSortingUnmixed(t *testing.T) { } func TestGetValidatorSortingMixed(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 1000) + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 1000) bondedPool := keeper.GetBondedPool(ctx) notBondedPool := keeper.GetNotBondedPool(ctx) - bondedPool.SetCoins(sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), sdk.TokensFromConsensusPower(501)))) - notBondedPool.SetCoins(sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), sdk.TokensFromConsensusPower(0)))) + + bk.SetBalances(ctx, bondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), sdk.TokensFromConsensusPower(501)))) + bk.SetBalances(ctx, notBondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), sdk.TokensFromConsensusPower(0)))) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) @@ -432,7 +433,7 @@ func TestGetValidatorSortingMixed(t *testing.T) { // TODO separate out into multiple tests func TestGetValidatorsEdgeCases(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 1000) + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 1000) // set max validators to 2 params := keeper.GetParams(ctx) @@ -446,10 +447,14 @@ func TestGetValidatorsEdgeCases(t *testing.T) { for i, power := range powers { moniker := fmt.Sprintf("val#%d", int64(i)) validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{Moniker: moniker}) + tokens := sdk.TokensFromConsensusPower(power) validators[i], _ = validators[i].AddTokensFromDel(tokens) + notBondedPool := keeper.GetNotBondedPool(ctx) - require.NoError(t, notBondedPool.SetCoins(notBondedPool.GetCoins().Add(sdk.NewCoin(params.BondDenom, tokens)))) + balances := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) + require.NoError(t, bk.SetBalances(ctx, notBondedPool.GetAddress(), balances.Add(sdk.NewCoin(params.BondDenom, tokens)))) + keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) validators[i] = TestingUpdateValidator(keeper, ctx, validators[i], true) } @@ -465,8 +470,10 @@ func TestGetValidatorsEdgeCases(t *testing.T) { delTokens := sdk.TokensFromConsensusPower(500) validators[0], _ = validators[0].AddTokensFromDel(delTokens) notBondedPool := keeper.GetNotBondedPool(ctx) + newTokens := sdk.NewCoins() - require.NoError(t, notBondedPool.SetCoins(notBondedPool.GetCoins().Add(newTokens...))) + balances := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) + require.NoError(t, bk.SetBalances(ctx, notBondedPool.GetAddress(), balances.Add(newTokens...))) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) // test that the two largest validators are @@ -496,7 +503,8 @@ func TestGetValidatorsEdgeCases(t *testing.T) { notBondedPool = keeper.GetNotBondedPool(ctx) newTokens = sdk.NewCoins(sdk.NewCoin(params.BondDenom, sdk.TokensFromConsensusPower(1))) - require.NoError(t, notBondedPool.SetCoins(notBondedPool.GetCoins().Add(newTokens...))) + balances = bk.GetAllBalances(ctx, notBondedPool.GetAddress()) + require.NoError(t, bk.SetBalances(ctx, notBondedPool.GetAddress(), balances.Add(newTokens...))) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) validators[3] = TestingUpdateValidator(keeper, ctx, validators[3], true) @@ -511,7 +519,8 @@ func TestGetValidatorsEdgeCases(t *testing.T) { validators[3], _ = validators[3].RemoveDelShares(sdk.NewDec(201)) bondedPool := keeper.GetBondedPool(ctx) - require.NoError(t, bondedPool.SetCoins(bondedPool.GetCoins().Add(sdk.NewCoin(params.BondDenom, rmTokens)))) + balances = bk.GetAllBalances(ctx, bondedPool.GetAddress()) + require.NoError(t, bk.SetBalances(ctx, bondedPool.GetAddress(), balances.Add(sdk.NewCoin(params.BondDenom, rmTokens)))) keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) validators[3] = TestingUpdateValidator(keeper, ctx, validators[3], true) @@ -525,7 +534,8 @@ func TestGetValidatorsEdgeCases(t *testing.T) { validators[3], _ = validators[3].AddTokensFromDel(sdk.NewInt(200)) notBondedPool = keeper.GetNotBondedPool(ctx) - require.NoError(t, notBondedPool.SetCoins(notBondedPool.GetCoins().Add(sdk.NewCoin(params.BondDenom, sdk.NewInt(200))))) + balances = bk.GetAllBalances(ctx, notBondedPool.GetAddress()) + require.NoError(t, bk.SetBalances(ctx, notBondedPool.GetAddress(), balances.Add(sdk.NewCoin(params.BondDenom, sdk.NewInt(200))))) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) validators[3] = TestingUpdateValidator(keeper, ctx, validators[3], true) @@ -538,7 +548,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) { } func TestValidatorBondHeight(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) // now 2 max resValidators params := keeper.GetParams(ctx) @@ -585,7 +595,7 @@ func TestValidatorBondHeight(t *testing.T) { } func TestFullValidatorSetPowerChange(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) params := keeper.GetParams(ctx) max := 2 params.MaxValidators = uint16(2) @@ -627,7 +637,7 @@ func TestFullValidatorSetPowerChange(t *testing.T) { } func TestApplyAndReturnValidatorSetUpdatesAllNone(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) powers := []int64{10, 20} var validators [2]types.Validator @@ -657,7 +667,7 @@ func TestApplyAndReturnValidatorSetUpdatesAllNone(t *testing.T) { } func TestApplyAndReturnValidatorSetUpdatesIdentical(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) powers := []int64{10, 20} var validators [2]types.Validator @@ -680,7 +690,7 @@ func TestApplyAndReturnValidatorSetUpdatesIdentical(t *testing.T) { } func TestApplyAndReturnValidatorSetUpdatesSingleValueChange(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) powers := []int64{10, 20} var validators [2]types.Validator @@ -709,7 +719,7 @@ func TestApplyAndReturnValidatorSetUpdatesSingleValueChange(t *testing.T) { } func TestApplyAndReturnValidatorSetUpdatesMultipleValueChange(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) powers := []int64{10, 20} var validators [2]types.Validator @@ -741,7 +751,7 @@ func TestApplyAndReturnValidatorSetUpdatesMultipleValueChange(t *testing.T) { } func TestApplyAndReturnValidatorSetUpdatesInserted(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) powers := []int64{10, 20, 5, 15, 25} var validators [5]types.Validator @@ -787,7 +797,7 @@ func TestApplyAndReturnValidatorSetUpdatesInserted(t *testing.T) { } func TestApplyAndReturnValidatorSetUpdatesWithCliffValidator(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) params := types.DefaultParams() params.MaxValidators = 2 keeper.SetParams(ctx, params) @@ -828,7 +838,7 @@ func TestApplyAndReturnValidatorSetUpdatesWithCliffValidator(t *testing.T) { } func TestApplyAndReturnValidatorSetUpdatesPowerDecrease(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) powers := []int64{100, 100} var validators [2]types.Validator @@ -869,7 +879,7 @@ func TestApplyAndReturnValidatorSetUpdatesPowerDecrease(t *testing.T) { } func TestApplyAndReturnValidatorSetUpdatesNewValidator(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) params := keeper.GetParams(ctx) params.MaxValidators = uint16(3) @@ -950,7 +960,7 @@ func TestApplyAndReturnValidatorSetUpdatesNewValidator(t *testing.T) { } func TestApplyAndReturnValidatorSetUpdatesBondTransition(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) params := keeper.GetParams(ctx) params.MaxValidators = uint16(2) @@ -1027,7 +1037,7 @@ func TestApplyAndReturnValidatorSetUpdatesBondTransition(t *testing.T) { } func TestUpdateValidatorCommission(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) ctx = ctx.WithBlockHeader(abci.Header{Time: time.Now().UTC()}) commission1 := types.NewCommissionWithTime( diff --git a/x/staking/module.go b/x/staking/module.go index 0f39343af843..0c7023a01957 100644 --- a/x/staking/module.go +++ b/x/staking/module.go @@ -106,17 +106,19 @@ type AppModule struct { keeper Keeper accountKeeper types.AccountKeeper + bankKeeper types.BankKeeper supplyKeeper types.SupplyKeeper } // NewAppModule creates a new AppModule object -func NewAppModule(keeper Keeper, accountKeeper types.AccountKeeper, supplyKeeper types.SupplyKeeper) AppModule { +func NewAppModule(keeper Keeper, ak types.AccountKeeper, bk types.BankKeeper, sk types.SupplyKeeper) AppModule { return AppModule{ AppModuleBasic: AppModuleBasic{}, keeper: keeper, - accountKeeper: accountKeeper, - supplyKeeper: supplyKeeper, + accountKeeper: ak, + bankKeeper: bk, + supplyKeeper: sk, } } @@ -155,7 +157,7 @@ func (am AppModule) NewQuerierHandler() sdk.Querier { func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate { var genesisState GenesisState ModuleCdc.MustUnmarshalJSON(data, &genesisState) - return InitGenesis(ctx, am.keeper, am.accountKeeper, am.supplyKeeper, genesisState) + return InitGenesis(ctx, am.keeper, am.accountKeeper, am.bankKeeper, am.supplyKeeper, genesisState) } // ExportGenesis returns the exported genesis state as raw bytes for the staking @@ -202,6 +204,7 @@ func (AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { // WeightedOperations returns the all the staking module operations with their respective weights. func (am AppModule) WeightedOperations(simState module.SimulationState) []sim.WeightedOperation { - return simulation.WeightedOperations(simState.AppParams, simState.Cdc, - am.accountKeeper, am.keeper) + return simulation.WeightedOperations( + simState.AppParams, simState.Cdc, am.accountKeeper, am.bankKeeper, am.keeper, + ) } diff --git a/x/staking/simulation/operations.go b/x/staking/simulation/operations.go index b1a932270641..58451676a739 100644 --- a/x/staking/simulation/operations.go +++ b/x/staking/simulation/operations.go @@ -26,7 +26,7 @@ const ( // WeightedOperations returns all the operations from the module with their respective weights func WeightedOperations( appParams simulation.AppParams, cdc *codec.Codec, ak types.AccountKeeper, - k keeper.Keeper, + bk types.BankKeeper, k keeper.Keeper, ) simulation.WeightedOperations { var ( @@ -70,30 +70,30 @@ func WeightedOperations( return simulation.WeightedOperations{ simulation.NewWeightedOperation( weightMsgCreateValidator, - SimulateMsgCreateValidator(ak, k), + SimulateMsgCreateValidator(ak, bk, k), ), simulation.NewWeightedOperation( weightMsgEditValidator, - SimulateMsgEditValidator(ak, k), + SimulateMsgEditValidator(ak, bk, k), ), simulation.NewWeightedOperation( weightMsgDelegate, - SimulateMsgDelegate(ak, k), + SimulateMsgDelegate(ak, bk, k), ), simulation.NewWeightedOperation( weightMsgUndelegate, - SimulateMsgUndelegate(ak, k), + SimulateMsgUndelegate(ak, bk, k), ), simulation.NewWeightedOperation( weightMsgBeginRedelegate, - SimulateMsgBeginRedelegate(ak, k), + SimulateMsgBeginRedelegate(ak, bk, k), ), } } // SimulateMsgCreateValidator generates a MsgCreateValidator with random values -// nolint: funlen -func SimulateMsgCreateValidator(ak types.AccountKeeper, k keeper.Keeper) simulation.Operation { +// nolint: funlen interfacer +func SimulateMsgCreateValidator(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, ) (simulation.OperationMsg, []simulation.FutureOperation, error) { @@ -108,12 +108,13 @@ func SimulateMsgCreateValidator(ak types.AccountKeeper, k keeper.Keeper) simulat } denom := k.GetParams(ctx).BondDenom - amount := ak.GetAccount(ctx, simAccount.Address).GetCoins().AmountOf(denom) - if !amount.IsPositive() { + + balance := bk.GetBalance(ctx, simAccount.Address, denom).Amount + if !balance.IsPositive() { return simulation.NoOpMsg(types.ModuleName), nil, nil } - amount, err := simulation.RandPositiveInt(r, amount) + amount, err := simulation.RandPositiveInt(r, balance) if err != nil { return simulation.NoOpMsg(types.ModuleName), nil, err } @@ -121,10 +122,10 @@ func SimulateMsgCreateValidator(ak types.AccountKeeper, k keeper.Keeper) simulat selfDelegation := sdk.NewCoin(denom, amount) account := ak.GetAccount(ctx, simAccount.Address) - coins := account.SpendableCoins(ctx.BlockTime()) + spendable := bk.SpendableCoins(ctx, account.GetAddress()) var fees sdk.Coins - coins, hasNeg := coins.SafeSub(sdk.Coins{selfDelegation}) + coins, hasNeg := spendable.SafeSub(sdk.Coins{selfDelegation}) if !hasNeg { fees, err = simulation.RandomFees(r, ctx, coins) if err != nil { @@ -170,8 +171,8 @@ func SimulateMsgCreateValidator(ak types.AccountKeeper, k keeper.Keeper) simulat } // SimulateMsgEditValidator generates a MsgEditValidator with random values -// nolint: funlen -func SimulateMsgEditValidator(ak types.AccountKeeper, k keeper.Keeper) simulation.Operation { +// nolint: funlen interfacer +func SimulateMsgEditValidator(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, ) (simulation.OperationMsg, []simulation.FutureOperation, error) { @@ -200,7 +201,9 @@ func SimulateMsgEditValidator(ak types.AccountKeeper, k keeper.Keeper) simulatio } account := ak.GetAccount(ctx, simAccount.Address) - fees, err := simulation.RandomFees(r, ctx, account.SpendableCoins(ctx.BlockTime())) + spendable := bk.SpendableCoins(ctx, account.GetAddress()) + + fees, err := simulation.RandomFees(r, ctx, spendable) if err != nil { return simulation.NoOpMsg(types.ModuleName), nil, err } @@ -235,8 +238,8 @@ func SimulateMsgEditValidator(ak types.AccountKeeper, k keeper.Keeper) simulatio } // SimulateMsgDelegate generates a MsgDelegate with random values -// nolint: funlen -func SimulateMsgDelegate(ak types.AccountKeeper, k keeper.Keeper) simulation.Operation { +// nolint: funlen interfacer +func SimulateMsgDelegate(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, ) (simulation.OperationMsg, []simulation.FutureOperation, error) { @@ -256,7 +259,7 @@ func SimulateMsgDelegate(ak types.AccountKeeper, k keeper.Keeper) simulation.Ope return simulation.NoOpMsg(types.ModuleName), nil, nil } - amount := ak.GetAccount(ctx, simAccount.Address).GetCoins().AmountOf(denom) + amount := bk.GetBalance(ctx, simAccount.Address, denom).Amount if !amount.IsPositive() { return simulation.NoOpMsg(types.ModuleName), nil, nil } @@ -269,10 +272,10 @@ func SimulateMsgDelegate(ak types.AccountKeeper, k keeper.Keeper) simulation.Ope bondAmt := sdk.NewCoin(denom, amount) account := ak.GetAccount(ctx, simAccount.Address) - coins := account.SpendableCoins(ctx.BlockTime()) + spendable := bk.SpendableCoins(ctx, account.GetAddress()) var fees sdk.Coins - coins, hasNeg := coins.SafeSub(sdk.Coins{bondAmt}) + coins, hasNeg := spendable.SafeSub(sdk.Coins{bondAmt}) if !hasNeg { fees, err = simulation.RandomFees(r, ctx, coins) if err != nil { @@ -302,8 +305,8 @@ func SimulateMsgDelegate(ak types.AccountKeeper, k keeper.Keeper) simulation.Ope } // SimulateMsgUndelegate generates a MsgUndelegate with random values -// nolint: funlen -func SimulateMsgUndelegate(ak types.AccountKeeper, k keeper.Keeper) simulation.Operation { +// nolint: funlen,interfacer +func SimulateMsgUndelegate(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, ) (simulation.OperationMsg, []simulation.FutureOperation, error) { @@ -357,7 +360,9 @@ func SimulateMsgUndelegate(ak types.AccountKeeper, k keeper.Keeper) simulation.O } account := ak.GetAccount(ctx, delAddr) - fees, err := simulation.RandomFees(r, ctx, account.SpendableCoins(ctx.BlockTime())) + spendable := bk.SpendableCoins(ctx, account.GetAddress()) + + fees, err := simulation.RandomFees(r, ctx, spendable) if err != nil { return simulation.NoOpMsg(types.ModuleName), nil, err } @@ -382,8 +387,8 @@ func SimulateMsgUndelegate(ak types.AccountKeeper, k keeper.Keeper) simulation.O } // SimulateMsgBeginRedelegate generates a MsgBeginRedelegate with random values -// nolint: funlen -func SimulateMsgBeginRedelegate(ak types.AccountKeeper, k keeper.Keeper) simulation.Operation { +// nolint: funlen,interfacer +func SimulateMsgBeginRedelegate(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, ) (simulation.OperationMsg, []simulation.FutureOperation, error) { @@ -393,8 +398,8 @@ func SimulateMsgBeginRedelegate(ak types.AccountKeeper, k keeper.Keeper) simulat if !ok { return simulation.NoOpMsg(types.ModuleName), nil, nil } - srcAddr := srcVal.GetOperator() + srcAddr := srcVal.GetOperator() delegations := k.GetValidatorDelegations(ctx, srcAddr) // get random delegator from src validator @@ -451,14 +456,16 @@ func SimulateMsgBeginRedelegate(ak types.AccountKeeper, k keeper.Keeper) simulat break } } + // if simaccount.PrivKey == nil, delegation address does not exist in accs. Return error if simAccount.PrivKey == nil { return simulation.NoOpMsg(types.ModuleName), nil, fmt.Errorf("delegation addr: %s does not exist in simulation accounts", delAddr) } - // get tx fees account := ak.GetAccount(ctx, delAddr) - fees, err := simulation.RandomFees(r, ctx, account.SpendableCoins(ctx.BlockTime())) + spendable := bk.SpendableCoins(ctx, account.GetAddress()) + + fees, err := simulation.RandomFees(r, ctx, spendable) if err != nil { return simulation.NoOpMsg(types.ModuleName), nil, err } diff --git a/x/staking/types/expected_keepers.go b/x/staking/types/expected_keepers.go index 5e98f0abbed0..c9e69b9018bb 100644 --- a/x/staking/types/expected_keepers.go +++ b/x/staking/types/expected_keepers.go @@ -19,6 +19,15 @@ type AccountKeeper interface { GetAccount(ctx sdk.Context, addr sdk.AccAddress) authexported.Account // only used for simulation } +// BankKeeper defines the expected interface needed to retrieve account balances. +type BankKeeper interface { + GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin + SetBalances(ctx sdk.Context, addr sdk.AccAddress, balances sdk.Coins) error + LockedCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins +} + // SupplyKeeper defines the expected supply Keeper (noalias) type SupplyKeeper interface { GetSupply(ctx sdk.Context) supplyexported.SupplyI diff --git a/x/supply/genesis.go b/x/supply/genesis.go index e1dfc41ff555..17546515cf43 100644 --- a/x/supply/genesis.go +++ b/x/supply/genesis.go @@ -2,20 +2,19 @@ package supply import ( sdk "github.com/cosmos/cosmos-sdk/types" - authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" "github.com/cosmos/cosmos-sdk/x/supply/internal/types" ) // InitGenesis sets supply information for genesis. // // CONTRACT: all types of accounts must have been already initialized/created -func InitGenesis(ctx sdk.Context, keeper Keeper, ak types.AccountKeeper, data GenesisState) { +func InitGenesis(ctx sdk.Context, keeper Keeper, bk types.BankKeeper, data GenesisState) { // manually set the total supply based on accounts if not provided if data.Supply.Empty() { var totalSupply sdk.Coins - ak.IterateAccounts(ctx, - func(acc authexported.Account) (stop bool) { - totalSupply = totalSupply.Add(acc.GetCoins()...) + bk.IterateAllBalances(ctx, + func(_ sdk.AccAddress, balance sdk.Coin) (stop bool) { + totalSupply = totalSupply.Add(balance) return false }, ) diff --git a/x/supply/internal/keeper/bank_test.go b/x/supply/internal/keeper/bank_test.go index 6a817a164f8d..5388dc804d49 100644 --- a/x/supply/internal/keeper/bank_test.go +++ b/x/supply/internal/keeper/bank_test.go @@ -24,24 +24,26 @@ var ( initCoins = sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initTokens)) ) -func getCoinsByName(ctx sdk.Context, sk keep.Keeper, ak types.AccountKeeper, moduleName string) sdk.Coins { +// nolint +func getCoinsByName(ctx sdk.Context, sk keep.Keeper, ak types.AccountKeeper, bk types.BankKeeper, moduleName string) sdk.Coins { moduleAddress := sk.GetModuleAddress(moduleName) macc := ak.GetAccount(ctx, moduleAddress) if macc == nil { return sdk.Coins(nil) } - return macc.GetCoins() + + return bk.GetAllBalances(ctx, macc.GetAddress()) } func TestSendCoins(t *testing.T) { app, ctx := createTestApp(false) keeper := app.SupplyKeeper ak := app.AccountKeeper + bk := app.BankKeeper baseAcc := ak.NewAccountWithAddress(ctx, types.NewModuleAddress("baseAcc")) - err := holderAcc.SetCoins(initCoins) - require.NoError(t, err) + require.NoError(t, bk.SetBalances(ctx, holderAcc.GetAddress(), initCoins)) keeper.SetSupply(ctx, types.NewSupply(initCoins)) keeper.SetModuleAccount(ctx, holderAcc) @@ -60,30 +62,33 @@ func TestSendCoins(t *testing.T) { keeper.SendCoinsFromModuleToAccount(ctx, "", baseAcc.GetAddress(), initCoins) }) - err = keeper.SendCoinsFromModuleToAccount(ctx, holderAcc.GetName(), baseAcc.GetAddress(), initCoins.Add(initCoins...)) - require.Error(t, err) - - err = keeper.SendCoinsFromModuleToModule(ctx, holderAcc.GetName(), types.Burner, initCoins) - require.NoError(t, err) - require.Equal(t, sdk.Coins(nil), getCoinsByName(ctx, keeper, ak, holderAcc.GetName())) - require.Equal(t, initCoins, getCoinsByName(ctx, keeper, ak, types.Burner)) - - err = keeper.SendCoinsFromModuleToAccount(ctx, types.Burner, baseAcc.GetAddress(), initCoins) - require.NoError(t, err) - require.Equal(t, sdk.Coins(nil), getCoinsByName(ctx, keeper, ak, types.Burner)) - - require.Equal(t, initCoins, ak.GetAccount(ctx, baseAcc.GetAddress()).GetCoins()) - - err = keeper.SendCoinsFromAccountToModule(ctx, baseAcc.GetAddress(), types.Burner, initCoins) - require.NoError(t, err) - require.Equal(t, sdk.Coins(nil), ak.GetAccount(ctx, baseAcc.GetAddress()).GetCoins()) - require.Equal(t, initCoins, getCoinsByName(ctx, keeper, ak, types.Burner)) + require.Error( + t, + keeper.SendCoinsFromModuleToAccount(ctx, holderAcc.GetName(), baseAcc.GetAddress(), initCoins.Add(initCoins...)), + ) + + require.NoError( + t, keeper.SendCoinsFromModuleToModule(ctx, holderAcc.GetName(), types.Burner, initCoins), + ) + require.Equal(t, sdk.Coins(nil), getCoinsByName(ctx, keeper, ak, bk, holderAcc.GetName())) + require.Equal(t, initCoins, getCoinsByName(ctx, keeper, ak, bk, types.Burner)) + + require.NoError( + t, keeper.SendCoinsFromModuleToAccount(ctx, types.Burner, baseAcc.GetAddress(), initCoins), + ) + require.Equal(t, sdk.Coins(nil), getCoinsByName(ctx, keeper, ak, bk, types.Burner)) + require.Equal(t, initCoins, bk.GetAllBalances(ctx, baseAcc.GetAddress())) + + require.NoError(t, keeper.SendCoinsFromAccountToModule(ctx, baseAcc.GetAddress(), types.Burner, initCoins)) + require.Equal(t, sdk.Coins(nil), bk.GetAllBalances(ctx, baseAcc.GetAddress())) + require.Equal(t, initCoins, getCoinsByName(ctx, keeper, ak, bk, types.Burner)) } func TestMintCoins(t *testing.T) { app, ctx := createTestApp(false) keeper := app.SupplyKeeper ak := app.AccountKeeper + bk := app.BankKeeper keeper.SetModuleAccount(ctx, burnerAcc) keeper.SetModuleAccount(ctx, minterAcc) @@ -101,7 +106,7 @@ func TestMintCoins(t *testing.T) { err = keeper.MintCoins(ctx, types.Minter, initCoins) require.NoError(t, err) - require.Equal(t, initCoins, getCoinsByName(ctx, keeper, ak, types.Minter)) + require.Equal(t, initCoins, getCoinsByName(ctx, keeper, ak, bk, types.Minter)) require.Equal(t, initialSupply.GetTotal().Add(initCoins...), keeper.GetSupply(ctx).GetTotal()) // test same functionality on module account with multiple permissions @@ -109,7 +114,7 @@ func TestMintCoins(t *testing.T) { err = keeper.MintCoins(ctx, multiPermAcc.GetName(), initCoins) require.NoError(t, err) - require.Equal(t, initCoins, getCoinsByName(ctx, keeper, ak, multiPermAcc.GetName())) + require.Equal(t, initCoins, getCoinsByName(ctx, keeper, ak, bk, multiPermAcc.GetName())) require.Equal(t, initialSupply.GetTotal().Add(initCoins...), keeper.GetSupply(ctx).GetTotal()) require.Panics(t, func() { keeper.MintCoins(ctx, types.Burner, initCoins) }) @@ -119,8 +124,9 @@ func TestBurnCoins(t *testing.T) { app, ctx := createTestApp(false) keeper := app.SupplyKeeper ak := app.AccountKeeper + bk := app.BankKeeper - require.NoError(t, burnerAcc.SetCoins(initCoins)) + require.NoError(t, bk.SetBalances(ctx, burnerAcc.GetAddress(), initCoins)) keeper.SetSupply(ctx, types.NewSupply(initCoins)) keeper.SetModuleAccount(ctx, burnerAcc) @@ -136,7 +142,7 @@ func TestBurnCoins(t *testing.T) { err = keeper.BurnCoins(ctx, types.Burner, initCoins) require.NoError(t, err) - require.Equal(t, sdk.Coins(nil), getCoinsByName(ctx, keeper, ak, types.Burner)) + require.Equal(t, sdk.Coins(nil), getCoinsByName(ctx, keeper, ak, bk, types.Burner)) require.Equal(t, initialSupply.GetTotal().Sub(initCoins), keeper.GetSupply(ctx).GetTotal()) // test same functionality on module account with multiple permissions @@ -144,11 +150,11 @@ func TestBurnCoins(t *testing.T) { initialSupply = initialSupply.Inflate(initCoins) keeper.SetSupply(ctx, initialSupply) - require.NoError(t, multiPermAcc.SetCoins(initCoins)) + require.NoError(t, bk.SetBalances(ctx, multiPermAcc.GetAddress(), initCoins)) keeper.SetModuleAccount(ctx, multiPermAcc) err = keeper.BurnCoins(ctx, multiPermAcc.GetName(), initCoins) require.NoError(t, err) - require.Equal(t, sdk.Coins(nil), getCoinsByName(ctx, keeper, ak, multiPermAcc.GetName())) + require.Equal(t, sdk.Coins(nil), getCoinsByName(ctx, keeper, ak, bk, multiPermAcc.GetName())) require.Equal(t, initialSupply.GetTotal().Sub(initCoins), keeper.GetSupply(ctx).GetTotal()) } diff --git a/x/supply/internal/keeper/invariants.go b/x/supply/internal/keeper/invariants.go index aeec368e4bf9..0b5ca06694ed 100644 --- a/x/supply/internal/keeper/invariants.go +++ b/x/supply/internal/keeper/invariants.go @@ -4,7 +4,6 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth/exported" "github.com/cosmos/cosmos-sdk/x/supply/internal/types" ) @@ -26,8 +25,8 @@ func TotalSupply(k Keeper) sdk.Invariant { var expectedTotal sdk.Coins supply := k.GetSupply(ctx) - k.ak.IterateAccounts(ctx, func(acc exported.Account) bool { - expectedTotal = expectedTotal.Add(acc.GetCoins()...) + k.bk.IterateAllBalances(ctx, func(_ sdk.AccAddress, balance sdk.Coin) bool { + expectedTotal = expectedTotal.Add(balance) return false }) diff --git a/x/supply/internal/types/account.go b/x/supply/internal/types/account.go index ac2136ec6910..533084d2b0bd 100644 --- a/x/supply/internal/types/account.go +++ b/x/supply/internal/types/account.go @@ -116,7 +116,6 @@ func (ma ModuleAccount) Validate() error { type moduleAccountPretty struct { Address sdk.AccAddress `json:"address" yaml:"address"` - Coins sdk.Coins `json:"coins" yaml:"coins"` PubKey string `json:"public_key" yaml:"public_key"` AccountNumber uint64 `json:"account_number" yaml:"account_number"` Sequence uint64 `json:"sequence" yaml:"sequence"` @@ -133,7 +132,6 @@ func (ma ModuleAccount) String() string { func (ma ModuleAccount) MarshalYAML() (interface{}, error) { bs, err := yaml.Marshal(moduleAccountPretty{ Address: ma.Address, - Coins: ma.Coins, PubKey: "", AccountNumber: ma.AccountNumber, Sequence: ma.Sequence, @@ -152,7 +150,6 @@ func (ma ModuleAccount) MarshalYAML() (interface{}, error) { func (ma ModuleAccount) MarshalJSON() ([]byte, error) { return json.Marshal(moduleAccountPretty{ Address: ma.Address, - Coins: ma.Coins, PubKey: "", AccountNumber: ma.AccountNumber, Sequence: ma.Sequence, @@ -168,7 +165,7 @@ func (ma *ModuleAccount) UnmarshalJSON(bz []byte) error { return err } - ma.BaseAccount = authtypes.NewBaseAccount(alias.Address, alias.Coins, nil, alias.AccountNumber, alias.Sequence) + ma.BaseAccount = authtypes.NewBaseAccount(alias.Address, nil, alias.AccountNumber, alias.Sequence) ma.Name = alias.Name ma.Permissions = alias.Permissions diff --git a/x/supply/internal/types/account_test.go b/x/supply/internal/types/account_test.go index 396f1a90be14..a3ee01bf1afa 100644 --- a/x/supply/internal/types/account_test.go +++ b/x/supply/internal/types/account_test.go @@ -23,7 +23,7 @@ func TestModuleAccountMarshalYAML(t *testing.T) { bs, err := yaml.Marshal(moduleAcc) require.NoError(t, err) - want := "|\n address: cosmos1n7rdpqvgf37ktx30a2sv2kkszk3m7ncmg5drhe\n coins: []\n public_key: \"\"\n account_number: 0\n sequence: 0\n name: test\n permissions:\n - minter\n - burner\n - staking\n" + want := "|\n address: cosmos1n7rdpqvgf37ktx30a2sv2kkszk3m7ncmg5drhe\n public_key: \"\"\n account_number: 0\n sequence: 0\n name: test\n permissions:\n - minter\n - burner\n - staking\n" require.Equal(t, want, string(bs)) } @@ -52,7 +52,7 @@ func TestHasPermissions(t *testing.T) { func TestValidate(t *testing.T) { addr := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) - baseAcc := authtypes.NewBaseAccount(addr, sdk.Coins{}, nil, 0, 0) + baseAcc := authtypes.NewBaseAccount(addr, nil, 0, 0) tests := []struct { name string acc authexported.GenesisAccount @@ -86,8 +86,7 @@ func TestValidate(t *testing.T) { func TestModuleAccountJSON(t *testing.T) { pubkey := secp256k1.GenPrivKey().PubKey() addr := sdk.AccAddress(pubkey.Address()) - coins := sdk.NewCoins(sdk.NewInt64Coin("test", 5)) - baseAcc := authtypes.NewBaseAccount(addr, coins, nil, 10, 50) + baseAcc := authtypes.NewBaseAccount(addr, nil, 10, 50) acc := NewModuleAccount(baseAcc, "test", "burner") bz, err := json.Marshal(acc) diff --git a/x/supply/internal/types/expected_keepers.go b/x/supply/internal/types/expected_keepers.go index 3ad1d8b13ce4..de933b75145c 100644 --- a/x/supply/internal/types/expected_keepers.go +++ b/x/supply/internal/types/expected_keepers.go @@ -19,6 +19,11 @@ type BankKeeper interface { DelegateCoins(ctx sdk.Context, fromAdd, toAddr sdk.AccAddress, amt sdk.Coins) error UndelegateCoins(ctx sdk.Context, fromAddr, toAddr sdk.AccAddress, amt sdk.Coins) error + GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin + SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, error) AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, error) + + IterateAllBalances(ctx sdk.Context, cb func(address sdk.AccAddress, balance sdk.Coin) (stop bool)) } diff --git a/x/supply/module.go b/x/supply/module.go index 05ae901ebf72..73d05a772246 100644 --- a/x/supply/module.go +++ b/x/supply/module.go @@ -76,14 +76,16 @@ type AppModule struct { AppModuleBasic keeper Keeper + bk types.BankKeeper ak types.AccountKeeper } // NewAppModule creates a new AppModule object -func NewAppModule(keeper Keeper, ak types.AccountKeeper) AppModule { +func NewAppModule(keeper Keeper, bk types.BankKeeper, ak types.AccountKeeper) AppModule { return AppModule{ AppModuleBasic: AppModuleBasic{}, keeper: keeper, + bk: bk, ak: ak, } } @@ -121,7 +123,7 @@ func (am AppModule) NewQuerierHandler() sdk.Querier { func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate { var genesisState GenesisState ModuleCdc.MustUnmarshalJSON(data, &genesisState) - InitGenesis(ctx, am.keeper, am.ak, genesisState) + InitGenesis(ctx, am.keeper, am.bk, genesisState) return []abci.ValidatorUpdate{} } From c7a6299eb25b18899ed77f3885cefca47700e02f Mon Sep 17 00:00:00 2001 From: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Date: Fri, 31 Jan 2020 16:06:05 +0100 Subject: [PATCH 107/529] Simulation docs (#5033) * simulation docs * update docs with the latest simulation changes * minor imporvments * clean up of simulation.md * expand section on weights * minor reword * minor wording fix Co-authored-by: Marko --- docs/building-modules/simulator.md | 123 ++ docs/building-modules/structure.md | 17 +- docs/package-lock.json | 2165 +++++++++++++++------------- docs/package.json | 2 +- docs/using-the-sdk/README.md | 1 - docs/using-the-sdk/simulation.md | 89 +- 6 files changed, 1396 insertions(+), 1001 deletions(-) create mode 100644 docs/building-modules/simulator.md diff --git a/docs/building-modules/simulator.md b/docs/building-modules/simulator.md new file mode 100644 index 000000000000..d8b7aca42307 --- /dev/null +++ b/docs/building-modules/simulator.md @@ -0,0 +1,123 @@ +# Module Simulation + +## Prerequisites + +* [Cosmos Blockchain Simulator](./../using-the-sdk/simulation.md) + +## Synopsis + +This document details how to define each module simulation functions to be +integrated with the application `SimulationManager`. + +* [Simulation package](#simulation-package) + * [Store decoders](#store-decoders) + * [Randomized genesis](#randomized-genesis) + * [Randomized parameters](#randomized-parameters) + * [Random weighted operations](#random-weighted-operations) + * [Random proposal contents](#random-proposal-contents) +* [Registering the module simulation functions](#registering-simulation-functions) +* [App simulator manager](#app-simulator-manager) +* [Simulation tests](#simulation-tests) + +## Simulation package + +Every module that implements the SDK simulator needs to have a `x//simulation` +package which contains the primary functions required by the fuzz tests: store +decoders, randomized genesis state and parameters, weighted operations and proposal +contents. + +### Store decoders + +Registering the store decoders is required for the `AppImportExport`. This allows +for the key-value pairs from the stores to be decoded (_i.e_ unmarshalled) +to their corresponding types. In particular, it matches the key to a concrete type +and then unmarshals the value from the `KVPair` to the type provided. + +You can use the example [here](https://github.com/cosmos/cosmos-sdk/blob/release%2Fv0.38.0/x/distribution/simulation/decoder.go) from the distribution module to implement your store decoders. + +### Randomized genesis + +The simulator tests different scenarios and values for genesis parameters +in order to fully test the edge cases of specific modules. The `simulator` package from each module must expose a `RandomizedGenState` function to generate the initial random `GenesisState` from a given seed. In + +Once the module genesis parameter are generated randomly (or with the key and +values defined in a `params` file), they are marshaled to JSON format and added +to the app genesis JSON to use it on the simulations. + +You can check an example on how to create the randomized genesis [here](https://github.com/cosmos/cosmos-sdk/blob/release%2Fv0.38.0/x/staking/simulation/genesis.go). + +### Randomized parameter changes + +The simulator is able to test parameter changes at random. The simulator package from each module must contain a `RandomizedParams` func that will simulate parameter changes of the module throughout the simulations lifespan. + +You can see how an example of what is needed to fully test parameter changes [here](https://github.com/cosmos/cosmos-sdk/blob/release%2Fv0.38.0/x/staking/simulation/params.go) + +### Random weighted operations + +Operations are one of the crucial parts of the SDK simulation. They are the transactions +(`Msg`) that are simulated with random field values. The sender of the operation +is also assigned randomly. + +Operations on the simulation are simulated using the full [transaction cycle](../core/transactions.md) of a +`ABCI` application that exposes the `BaseApp`. + +Shown below is how weights are set: + ++++ https://github.com/cosmos/cosmos-sdk/blob/release%2Fv0.38.0/x/staking/simulation/operations.go#L18-L92 + +As you can see the weights are predefined in this case but there are options on how to override this behavior with different weights. One is allowing `*rand.Rand` to define a random weight for the operation, or you can inject your own predefined weights. + +Here is how one can override the above package `simappparams`. + ++++ https://github.com/cosmos/gaia/blob/master/sims.mk#L9-L22 + +For the last test a tool called runsim is used, this is used to parallelize go test instances, provide info to Github and slack integrations to provide information to your team on how the simulations are running. + +### Random proposal contents + +Randomized governance proposals are also supported on the SDK simulator. Each +module must define the governance proposal `Content`s that they expose and register +them to be used on the parameters. + +## Registering simulation functions + +Now that all the required functions are defined, we need to integrate them into the module pattern within the `module.go`: + ++++ https://github.com/cosmos/cosmos-sdk/blob/release%2Fv0.38.0/x/distribution/module.go#L156-L185 + +## App Simulator manager + +The following step is setting up the `SimulatorManager` at the app level. This +is required for the simulation test files on the next step. + +```go +type CustomApp struct { + ... + sm *module.SimulationManager +} +``` + +Then at the instantiation of the application, we create the `SimulationManager` +instance in the same way we create the `ModuleManager` but this time we only pass +the modules that implement the simulation functions from the `AppModuleSimulation` +interface described above. + +```go +func NewCustomApp(...) { + // create the simulation manager and define the order of the modules for deterministic simulations + app.sm = module.NewSimulationManager( + auth.NewAppModule(app.accountKeeper), + bank.NewAppModule(app.bankKeeper, app.accountKeeper), + supply.NewAppModule(app.supplyKeeper, app.accountKeeper), + ov.NewAppModule(app.govKeeper, app.accountKeeper, app.supplyKeeper), + mint.NewAppModule(app.mintKeeper), + distr.NewAppModule(app.distrKeeper, app.accountKeeper, app.supplyKeeper, app.stakingKeeper), + staking.NewAppModule(app.stakingKeeper, app.accountKeeper, app.supplyKeeper), + slashing.NewAppModule(app.slashingKeeper, app.accountKeeper, app.stakingKeeper), + ) + + // register the store decoders for simulation tests + app.sm.RegisterStoreDecoders() + ... +} +``` diff --git a/docs/building-modules/structure.md b/docs/building-modules/structure.md index 6b6d2f889a14..47d9a82b19ff 100644 --- a/docs/building-modules/structure.md +++ b/docs/building-modules/structure.md @@ -37,13 +37,18 @@ x/{module} │   ├── params.go │   ├── ... │   └── querier.go +├── simulation +│   ├── decoder.go +│   ├── genesis.go +│   ├── operations.go +│   ├── params.go +│   └── proposals.go ├── abci.go ├── alias.go ├── genesis.go ├── handler.go -├── module.go ├── ... -└── simulation.go +└── module.go ``` - `abci.go`: The module's `BeginBlocker` and `EndBlocker` implementations (if any). @@ -53,7 +58,7 @@ there is nothing preventing developers from importing other packages from the mo (excluding`internal/`) but it is recommended that `alias.go` have everything exposed that other modules may need. The majority of the exported values here will typically come from `internal/` (see below). -- `client/`: The module's CLI and REST client functionality implementation and +- `client/`: The module's CLI and REST client functionality implementation and testing. - `exported/`: The module's exported types -- typically type interfaces. If a module relies on other module keepers, it is expected to receive them as interface @@ -79,8 +84,10 @@ allows for greater freedom of development while maintaining API stability. implementations such as the querier and invariants. - `module.go`: The module's implementation of the `AppModule` and `AppModuleBasic` interfaces. -- `simulation.go`: The module's simulation messages and related types (if any). +- `simulation/`: The module's simulation package defines all the required functions +used on the blockchain simulator: randomized genesis state, parameters, weigthed +operations, proposal contents and types decoders. ## Next {hide} -Learn about [interfaces](../interfaces/interfaces-intro.md) {hide} \ No newline at end of file +Learn about [interfaces](../interfaces/interfaces-intro.md) {hide} diff --git a/docs/package-lock.json b/docs/package-lock.json index 3eee6f418b9a..b2aa82c75358 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -5,27 +5,28 @@ "requires": true, "dependencies": { "@babel/code-frame": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", - "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", + "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", "requires": { - "@babel/highlight": "^7.0.0" + "@babel/highlight": "^7.8.3" } }, "@babel/core": { - "version": "7.7.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.7.5.tgz", - "integrity": "sha512-M42+ScN4+1S9iB6f+TL7QBpoQETxbclx+KNoKJABghnKYE+fMzSGqst0BZJc8CpI625bwPwYgUyRvxZ+0mZzpw==", - "requires": { - "@babel/code-frame": "^7.5.5", - "@babel/generator": "^7.7.4", - "@babel/helpers": "^7.7.4", - "@babel/parser": "^7.7.5", - "@babel/template": "^7.7.4", - "@babel/traverse": "^7.7.4", - "@babel/types": "^7.7.4", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.8.3.tgz", + "integrity": "sha512-4XFkf8AwyrEG7Ziu3L2L0Cv+WyY47Tcsp70JFmpftbAA1K7YL/sgE9jh9HyNj08Y/U50ItUchpN0w6HxAoX1rA==", + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/generator": "^7.8.3", + "@babel/helpers": "^7.8.3", + "@babel/parser": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/traverse": "^7.8.3", + "@babel/types": "^7.8.3", "convert-source-map": "^1.7.0", "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", "json5": "^2.1.0", "lodash": "^4.17.13", "resolve": "^1.3.2", @@ -54,6 +55,11 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -62,11 +68,11 @@ } }, "@babel/generator": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.7.4.tgz", - "integrity": "sha512-m5qo2WgdOJeyYngKImbkyQrnUN1mPceaG5BV+G0E3gWsa4l/jCSryWJdM2x8OuGAOyh+3d5pVYfZWCiNFtynxg==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.3.tgz", + "integrity": "sha512-WjoPk8hRpDRqqzRpvaR8/gDUPkrnOOeuT2m8cNICJtZH6mwaCo3v0OKMI7Y6SM1pBtyijnLtAL0HDi41pf41ug==", "requires": { - "@babel/types": "^7.7.4", + "@babel/types": "^7.8.3", "jsesc": "^2.5.1", "lodash": "^4.17.13", "source-map": "^0.5.0" @@ -80,214 +86,214 @@ } }, "@babel/helper-annotate-as-pure": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.7.4.tgz", - "integrity": "sha512-2BQmQgECKzYKFPpiycoF9tlb5HA4lrVyAmLLVK177EcQAqjVLciUb2/R+n1boQ9y5ENV3uz2ZqiNw7QMBBw1Og==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.8.3.tgz", + "integrity": "sha512-6o+mJrZBxOoEX77Ezv9zwW7WV8DdluouRKNY/IR5u/YTMuKHgugHOzYWlYvYLpLA9nPsQCAAASpCIbjI9Mv+Uw==", "requires": { - "@babel/types": "^7.7.4" + "@babel/types": "^7.8.3" } }, "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.7.4.tgz", - "integrity": "sha512-Biq/d/WtvfftWZ9Uf39hbPBYDUo986m5Bb4zhkeYDGUllF43D+nUe5M6Vuo6/8JDK/0YX/uBdeoQpyaNhNugZQ==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.8.3.tgz", + "integrity": "sha512-5eFOm2SyFPK4Rh3XMMRDjN7lBH0orh3ss0g3rTYZnBQ+r6YPj7lgDyCvPphynHvUrobJmeMignBr6Acw9mAPlw==", "requires": { - "@babel/helper-explode-assignable-expression": "^7.7.4", - "@babel/types": "^7.7.4" + "@babel/helper-explode-assignable-expression": "^7.8.3", + "@babel/types": "^7.8.3" } }, "@babel/helper-call-delegate": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.7.4.tgz", - "integrity": "sha512-8JH9/B7J7tCYJ2PpWVpw9JhPuEVHztagNVuQAFBVFYluRMlpG7F1CgKEgGeL6KFqcsIa92ZYVj6DSc0XwmN1ZA==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.8.3.tgz", + "integrity": "sha512-6Q05px0Eb+N4/GTyKPPvnkig7Lylw+QzihMpws9iiZQv7ZImf84ZsZpQH7QoWN4n4tm81SnSzPgHw2qtO0Zf3A==", "requires": { - "@babel/helper-hoist-variables": "^7.7.4", - "@babel/traverse": "^7.7.4", - "@babel/types": "^7.7.4" + "@babel/helper-hoist-variables": "^7.8.3", + "@babel/traverse": "^7.8.3", + "@babel/types": "^7.8.3" } }, "@babel/helper-create-class-features-plugin": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.7.4.tgz", - "integrity": "sha512-l+OnKACG4uiDHQ/aJT8dwpR+LhCJALxL0mJ6nzjB25e5IPwqV1VOsY7ah6UB1DG+VOXAIMtuC54rFJGiHkxjgA==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.8.3.tgz", + "integrity": "sha512-qmp4pD7zeTxsv0JNecSBsEmG1ei2MqwJq4YQcK3ZWm/0t07QstWfvuV/vm3Qt5xNMFETn2SZqpMx2MQzbtq+KA==", "requires": { - "@babel/helper-function-name": "^7.7.4", - "@babel/helper-member-expression-to-functions": "^7.7.4", - "@babel/helper-optimise-call-expression": "^7.7.4", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.7.4", - "@babel/helper-split-export-declaration": "^7.7.4" + "@babel/helper-function-name": "^7.8.3", + "@babel/helper-member-expression-to-functions": "^7.8.3", + "@babel/helper-optimise-call-expression": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-replace-supers": "^7.8.3", + "@babel/helper-split-export-declaration": "^7.8.3" } }, "@babel/helper-create-regexp-features-plugin": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.7.4.tgz", - "integrity": "sha512-Mt+jBKaxL0zfOIWrfQpnfYCN7/rS6GKx6CCCfuoqVVd+17R8zNDlzVYmIi9qyb2wOk002NsmSTDymkIygDUH7A==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.3.tgz", + "integrity": "sha512-Gcsm1OHCUr9o9TcJln57xhWHtdXbA2pgQ58S0Lxlks0WMGNXuki4+GLfX0p+L2ZkINUGZvfkz8rzoqJQSthI+Q==", "requires": { - "@babel/helper-regex": "^7.4.4", + "@babel/helper-regex": "^7.8.3", "regexpu-core": "^4.6.0" } }, "@babel/helper-define-map": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.7.4.tgz", - "integrity": "sha512-v5LorqOa0nVQUvAUTUF3KPastvUt/HzByXNamKQ6RdJRTV7j8rLL+WB5C/MzzWAwOomxDhYFb1wLLxHqox86lg==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.8.3.tgz", + "integrity": "sha512-PoeBYtxoZGtct3md6xZOCWPcKuMuk3IHhgxsRRNtnNShebf4C8YonTSblsK4tvDbm+eJAw2HAPOfCr+Q/YRG/g==", "requires": { - "@babel/helper-function-name": "^7.7.4", - "@babel/types": "^7.7.4", + "@babel/helper-function-name": "^7.8.3", + "@babel/types": "^7.8.3", "lodash": "^4.17.13" } }, "@babel/helper-explode-assignable-expression": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.7.4.tgz", - "integrity": "sha512-2/SicuFrNSXsZNBxe5UGdLr+HZg+raWBLE9vC98bdYOKX/U6PY0mdGlYUJdtTDPSU0Lw0PNbKKDpwYHJLn2jLg==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.8.3.tgz", + "integrity": "sha512-N+8eW86/Kj147bO9G2uclsg5pwfs/fqqY5rwgIL7eTBklgXjcOJ3btzS5iM6AitJcftnY7pm2lGsrJVYLGjzIw==", "requires": { - "@babel/traverse": "^7.7.4", - "@babel/types": "^7.7.4" + "@babel/traverse": "^7.8.3", + "@babel/types": "^7.8.3" } }, "@babel/helper-function-name": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.7.4.tgz", - "integrity": "sha512-AnkGIdiBhEuiwdoMnKm7jfPfqItZhgRaZfMg1XX3bS25INOnLPjPG1Ppnajh8eqgt5kPJnfqrRHqFqmjKDZLzQ==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz", + "integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==", "requires": { - "@babel/helper-get-function-arity": "^7.7.4", - "@babel/template": "^7.7.4", - "@babel/types": "^7.7.4" + "@babel/helper-get-function-arity": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/types": "^7.8.3" } }, "@babel/helper-get-function-arity": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.7.4.tgz", - "integrity": "sha512-QTGKEdCkjgzgfJ3bAyRwF4yyT3pg+vDgan8DSivq1eS0gwi+KGKE5x8kRcbeFTb/673mkO5SN1IZfmCfA5o+EA==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", + "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", "requires": { - "@babel/types": "^7.7.4" + "@babel/types": "^7.8.3" } }, "@babel/helper-hoist-variables": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.7.4.tgz", - "integrity": "sha512-wQC4xyvc1Jo/FnLirL6CEgPgPCa8M74tOdjWpRhQYapz5JC7u3NYU1zCVoVAGCE3EaIP9T1A3iW0WLJ+reZlpQ==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.8.3.tgz", + "integrity": "sha512-ky1JLOjcDUtSc+xkt0xhYff7Z6ILTAHKmZLHPxAhOP0Nd77O+3nCsd6uSVYur6nJnCI029CrNbYlc0LoPfAPQg==", "requires": { - "@babel/types": "^7.7.4" + "@babel/types": "^7.8.3" } }, "@babel/helper-member-expression-to-functions": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.7.4.tgz", - "integrity": "sha512-9KcA1X2E3OjXl/ykfMMInBK+uVdfIVakVe7W7Lg3wfXUNyS3Q1HWLFRwZIjhqiCGbslummPDnmb7vIekS0C1vw==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz", + "integrity": "sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA==", "requires": { - "@babel/types": "^7.7.4" + "@babel/types": "^7.8.3" } }, "@babel/helper-module-imports": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.7.4.tgz", - "integrity": "sha512-dGcrX6K9l8258WFjyDLJwuVKxR4XZfU0/vTUgOQYWEnRD8mgr+p4d6fCUMq/ys0h4CCt/S5JhbvtyErjWouAUQ==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz", + "integrity": "sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg==", "requires": { - "@babel/types": "^7.7.4" + "@babel/types": "^7.8.3" } }, "@babel/helper-module-transforms": { - "version": "7.7.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.7.5.tgz", - "integrity": "sha512-A7pSxyJf1gN5qXVcidwLWydjftUN878VkalhXX5iQDuGyiGK3sOrrKKHF4/A4fwHtnsotv/NipwAeLzY4KQPvw==", - "requires": { - "@babel/helper-module-imports": "^7.7.4", - "@babel/helper-simple-access": "^7.7.4", - "@babel/helper-split-export-declaration": "^7.7.4", - "@babel/template": "^7.7.4", - "@babel/types": "^7.7.4", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.8.3.tgz", + "integrity": "sha512-C7NG6B7vfBa/pwCOshpMbOYUmrYQDfCpVL/JCRu0ek8B5p8kue1+BCXpg2vOYs7w5ACB9GTOBYQ5U6NwrMg+3Q==", + "requires": { + "@babel/helper-module-imports": "^7.8.3", + "@babel/helper-simple-access": "^7.8.3", + "@babel/helper-split-export-declaration": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/types": "^7.8.3", "lodash": "^4.17.13" } }, "@babel/helper-optimise-call-expression": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.7.4.tgz", - "integrity": "sha512-VB7gWZ2fDkSuqW6b1AKXkJWO5NyNI3bFL/kK79/30moK57blr6NbH8xcl2XcKCwOmJosftWunZqfO84IGq3ZZg==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz", + "integrity": "sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ==", "requires": { - "@babel/types": "^7.7.4" + "@babel/types": "^7.8.3" } }, "@babel/helper-plugin-utils": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz", - "integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==" + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==" }, "@babel/helper-regex": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.5.5.tgz", - "integrity": "sha512-CkCYQLkfkiugbRDO8eZn6lRuR8kzZoGXCg3149iTk5se7g6qykSpy3+hELSwquhu+TgHn8nkLiBwHvNX8Hofcw==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.8.3.tgz", + "integrity": "sha512-BWt0QtYv/cg/NecOAZMdcn/waj/5P26DR4mVLXfFtDokSR6fyuG0Pj+e2FqtSME+MqED1khnSMulkmGl8qWiUQ==", "requires": { "lodash": "^4.17.13" } }, "@babel/helper-remap-async-to-generator": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.7.4.tgz", - "integrity": "sha512-Sk4xmtVdM9sA/jCI80f+KS+Md+ZHIpjuqmYPk1M7F/upHou5e4ReYmExAiu6PVe65BhJPZA2CY9x9k4BqE5klw==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.8.3.tgz", + "integrity": "sha512-kgwDmw4fCg7AVgS4DukQR/roGp+jP+XluJE5hsRZwxCYGg+Rv9wSGErDWhlI90FODdYfd4xG4AQRiMDjjN0GzA==", "requires": { - "@babel/helper-annotate-as-pure": "^7.7.4", - "@babel/helper-wrap-function": "^7.7.4", - "@babel/template": "^7.7.4", - "@babel/traverse": "^7.7.4", - "@babel/types": "^7.7.4" + "@babel/helper-annotate-as-pure": "^7.8.3", + "@babel/helper-wrap-function": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/traverse": "^7.8.3", + "@babel/types": "^7.8.3" } }, "@babel/helper-replace-supers": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.7.4.tgz", - "integrity": "sha512-pP0tfgg9hsZWo5ZboYGuBn/bbYT/hdLPVSS4NMmiRJdwWhP0IznPwN9AE1JwyGsjSPLC364I0Qh5p+EPkGPNpg==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.8.3.tgz", + "integrity": "sha512-xOUssL6ho41U81etpLoT2RTdvdus4VfHamCuAm4AHxGr+0it5fnwoVdwUJ7GFEqCsQYzJUhcbsN9wB9apcYKFA==", "requires": { - "@babel/helper-member-expression-to-functions": "^7.7.4", - "@babel/helper-optimise-call-expression": "^7.7.4", - "@babel/traverse": "^7.7.4", - "@babel/types": "^7.7.4" + "@babel/helper-member-expression-to-functions": "^7.8.3", + "@babel/helper-optimise-call-expression": "^7.8.3", + "@babel/traverse": "^7.8.3", + "@babel/types": "^7.8.3" } }, "@babel/helper-simple-access": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.7.4.tgz", - "integrity": "sha512-zK7THeEXfan7UlWsG2A6CI/L9jVnI5+xxKZOdej39Y0YtDYKx9raHk5F2EtK9K8DHRTihYwg20ADt9S36GR78A==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz", + "integrity": "sha512-VNGUDjx5cCWg4vvCTR8qQ7YJYZ+HBjxOgXEl7ounz+4Sn7+LMD3CFrCTEU6/qXKbA2nKg21CwhhBzO0RpRbdCw==", "requires": { - "@babel/template": "^7.7.4", - "@babel/types": "^7.7.4" + "@babel/template": "^7.8.3", + "@babel/types": "^7.8.3" } }, "@babel/helper-split-export-declaration": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.7.4.tgz", - "integrity": "sha512-guAg1SXFcVr04Guk9eq0S4/rWS++sbmyqosJzVs8+1fH5NI+ZcmkaSkc7dmtAFbHFva6yRJnjW3yAcGxjueDug==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz", + "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==", "requires": { - "@babel/types": "^7.7.4" + "@babel/types": "^7.8.3" } }, "@babel/helper-wrap-function": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.7.4.tgz", - "integrity": "sha512-VsfzZt6wmsocOaVU0OokwrIytHND55yvyT4BPB9AIIgwr8+x7617hetdJTsuGwygN5RC6mxA9EJztTjuwm2ofg==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.8.3.tgz", + "integrity": "sha512-LACJrbUET9cQDzb6kG7EeD7+7doC3JNvUgTEQOx2qaO1fKlzE/Bf05qs9w1oXQMmXlPO65lC3Tq9S6gZpTErEQ==", "requires": { - "@babel/helper-function-name": "^7.7.4", - "@babel/template": "^7.7.4", - "@babel/traverse": "^7.7.4", - "@babel/types": "^7.7.4" + "@babel/helper-function-name": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/traverse": "^7.8.3", + "@babel/types": "^7.8.3" } }, "@babel/helpers": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.7.4.tgz", - "integrity": "sha512-ak5NGZGJ6LV85Q1Zc9gn2n+ayXOizryhjSUBTdu5ih1tlVCJeuQENzc4ItyCVhINVXvIT/ZQ4mheGIsfBkpskg==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.8.3.tgz", + "integrity": "sha512-LmU3q9Pah/XyZU89QvBgGt+BCsTPoQa+73RxAQh8fb8qkDyIfeQnmgs+hvzhTCKTzqOyk7JTkS3MS1S8Mq5yrQ==", "requires": { - "@babel/template": "^7.7.4", - "@babel/traverse": "^7.7.4", - "@babel/types": "^7.7.4" + "@babel/template": "^7.8.3", + "@babel/traverse": "^7.8.3", + "@babel/types": "^7.8.3" } }, "@babel/highlight": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", - "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", + "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", "requires": { "chalk": "^2.0.0", "esutils": "^2.0.2", @@ -295,391 +301,399 @@ } }, "@babel/parser": { - "version": "7.7.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.5.tgz", - "integrity": "sha512-KNlOe9+/nk4i29g0VXgl8PEXIRms5xKLJeuZ6UptN0fHv+jDiriG+y94X6qAgWTR0h3KaoM1wK5G5h7MHFRSig==" + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.3.tgz", + "integrity": "sha512-/V72F4Yp/qmHaTALizEm9Gf2eQHV3QyTL3K0cNfijwnMnb1L+LDlAubb/ZnSdGAVzVSWakujHYs1I26x66sMeQ==" }, "@babel/plugin-proposal-async-generator-functions": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.7.4.tgz", - "integrity": "sha512-1ypyZvGRXriY/QP668+s8sFr2mqinhkRDMPSQLNghCQE+GAkFtp+wkHVvg2+Hdki8gwP+NFzJBJ/N1BfzCCDEw==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.8.3.tgz", + "integrity": "sha512-NZ9zLv848JsV3hs8ryEh7Uaz/0KsmPLqv0+PdkDJL1cJy0K4kOCFa8zc1E3mp+RHPQcpdfb/6GovEsW4VDrOMw==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-remap-async-to-generator": "^7.7.4", - "@babel/plugin-syntax-async-generators": "^7.7.4" + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-remap-async-to-generator": "^7.8.3", + "@babel/plugin-syntax-async-generators": "^7.8.0" } }, "@babel/plugin-proposal-class-properties": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.7.4.tgz", - "integrity": "sha512-EcuXeV4Hv1X3+Q1TsuOmyyxeTRiSqurGJ26+I/FW1WbymmRRapVORm6x1Zl3iDIHyRxEs+VXWp6qnlcfcJSbbw==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.8.3.tgz", + "integrity": "sha512-EqFhbo7IosdgPgZggHaNObkmO1kNUe3slaKu54d5OWvy+p9QIKOzK1GAEpAIsZtWVtPXUHSMcT4smvDrCfY4AA==", "requires": { - "@babel/helper-create-class-features-plugin": "^7.7.4", - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-create-class-features-plugin": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" } }, "@babel/plugin-proposal-decorators": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.7.4.tgz", - "integrity": "sha512-GftcVDcLCwVdzKmwOBDjATd548+IE+mBo7ttgatqNDR7VG7GqIuZPtRWlMLHbhTXhcnFZiGER8iIYl1n/imtsg==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.8.3.tgz", + "integrity": "sha512-e3RvdvS4qPJVTe288DlXjwKflpfy1hr0j5dz5WpIYYeP7vQZg2WfAEIp8k5/Lwis/m5REXEteIz6rrcDtXXG7w==", "requires": { - "@babel/helper-create-class-features-plugin": "^7.7.4", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-decorators": "^7.7.4" + "@babel/helper-create-class-features-plugin": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-decorators": "^7.8.3" } }, "@babel/plugin-proposal-json-strings": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.7.4.tgz", - "integrity": "sha512-wQvt3akcBTfLU/wYoqm/ws7YOAQKu8EVJEvHip/mzkNtjaclQoCCIqKXFP5/eyfnfbQCDV3OLRIK3mIVyXuZlw==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.8.3.tgz", + "integrity": "sha512-KGhQNZ3TVCQG/MjRbAUwuH+14y9q0tpxs1nWWs3pbSleRdDro9SAMMDyye8HhY1gqZ7/NqIc8SKhya0wRDgP1Q==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-json-strings": "^7.7.4" + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.0" } }, "@babel/plugin-proposal-object-rest-spread": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.7.4.tgz", - "integrity": "sha512-rnpnZR3/iWKmiQyJ3LKJpSwLDcX/nSXhdLk4Aq/tXOApIvyu7qoabrige0ylsAJffaUC51WiBu209Q0U+86OWQ==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-8qvuPwU/xxUCt78HocNlv0mXXo0wdh9VT1R04WU8HGOfaOob26pF+9P5/lYjN/q7DHOX1bvX60hnhOvuQUJdbA==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-object-rest-spread": "^7.7.4" + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.0" } }, "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.7.4.tgz", - "integrity": "sha512-DyM7U2bnsQerCQ+sejcTNZh8KQEUuC3ufzdnVnSiUv/qoGJp2Z3hanKL18KDhsBT5Wj6a7CMT5mdyCNJsEaA9w==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-0gkX7J7E+AtAw9fcwlVQj8peP61qhdg/89D5swOkjYbkboA2CVckn3kiyum1DE0wskGb7KJJxBdyEBApDLLVdw==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-optional-catch-binding": "^7.7.4" + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.0" } }, "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.7.4.tgz", - "integrity": "sha512-cHgqHgYvffluZk85dJ02vloErm3Y6xtH+2noOBOJ2kXOJH3aVCDnj5eR/lVNlTnYu4hndAPJD3rTFjW3qee0PA==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.8.3.tgz", + "integrity": "sha512-1/1/rEZv2XGweRwwSkLpY+s60za9OZ1hJs4YDqFHCw0kYWYwL5IFljVY1MYBL+weT1l9pokDO2uhSTLVxzoHkQ==", "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.7.4", - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-create-regexp-features-plugin": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" } }, "@babel/plugin-syntax-async-generators": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.7.4.tgz", - "integrity": "sha512-Li4+EjSpBgxcsmeEF8IFcfV/+yJGxHXDirDkEoyFjumuwbmfCVHUt0HuowD/iGM7OhIRyXJH9YXxqiH6N815+g==", + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.8.0" } }, "@babel/plugin-syntax-decorators": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.7.4.tgz", - "integrity": "sha512-0oNLWNH4k5ZbBVfAwiTU53rKFWIeTh6ZlaWOXWJc4ywxs0tjz5fc3uZ6jKAnZSxN98eXVgg7bJIuzjX+3SXY+A==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.8.3.tgz", + "integrity": "sha512-8Hg4dNNT9/LcA1zQlfwuKR8BUc/if7Q7NkTam9sGTcJphLwpf2g4S42uhspQrIrR+dpzE0dtTqBVFoHl8GtnnQ==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.8.3" } }, "@babel/plugin-syntax-dynamic-import": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.7.4.tgz", - "integrity": "sha512-jHQW0vbRGvwQNgyVxwDh4yuXu4bH1f5/EICJLAhl1SblLs2CDhrsmCk+v5XLdE9wxtAFRyxx+P//Iw+a5L/tTg==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.8.0" } }, "@babel/plugin-syntax-json-strings": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.7.4.tgz", - "integrity": "sha512-QpGupahTQW1mHRXddMG5srgpHWqRLwJnJZKXTigB9RPFCCGbDGCgBeM/iC82ICXp414WeYx/tD54w7M2qRqTMg==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.8.0" } }, "@babel/plugin-syntax-jsx": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.7.4.tgz", - "integrity": "sha512-wuy6fiMe9y7HeZBWXYCGt2RGxZOj0BImZ9EyXJVnVGBKO/Br592rbR3rtIQn0eQhAk9vqaKP5n8tVqEFBQMfLg==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.8.3.tgz", + "integrity": "sha512-WxdW9xyLgBdefoo0Ynn3MRSkhe5tFVxxKNVdnZSh318WrG2e2jH+E9wd/++JsqcLJZPfz87njQJ8j2Upjm0M0A==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.8.3" } }, "@babel/plugin-syntax-object-rest-spread": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.7.4.tgz", - "integrity": "sha512-mObR+r+KZq0XhRVS2BrBKBpr5jqrqzlPvS9C9vuOf5ilSwzloAl7RPWLrgKdWS6IreaVrjHxTjtyqFiOisaCwg==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.8.0" } }, "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.7.4.tgz", - "integrity": "sha512-4ZSuzWgFxqHRE31Glu+fEr/MirNZOMYmD/0BhBWyLyOOQz/gTAl7QmWm2hX1QxEIXsr2vkdlwxIzTyiYRC4xcQ==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.8.0" } }, "@babel/plugin-transform-arrow-functions": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.7.4.tgz", - "integrity": "sha512-zUXy3e8jBNPiffmqkHRNDdZM2r8DWhCB7HhcoyZjiK1TxYEluLHAvQuYnTT+ARqRpabWqy/NHkO6e3MsYB5YfA==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.8.3.tgz", + "integrity": "sha512-0MRF+KC8EqH4dbuITCWwPSzsyO3HIWWlm30v8BbbpOrS1B++isGxPnnuq/IZvOX5J2D/p7DQalQm+/2PnlKGxg==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.8.3" } }, "@babel/plugin-transform-async-to-generator": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.7.4.tgz", - "integrity": "sha512-zpUTZphp5nHokuy8yLlyafxCJ0rSlFoSHypTUWgpdwoDXWQcseaect7cJ8Ppk6nunOM6+5rPMkod4OYKPR5MUg==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.8.3.tgz", + "integrity": "sha512-imt9tFLD9ogt56Dd5CI/6XgpukMwd/fLGSrix2httihVe7LOGVPhyhMh1BU5kDM7iHD08i8uUtmV2sWaBFlHVQ==", "requires": { - "@babel/helper-module-imports": "^7.7.4", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-remap-async-to-generator": "^7.7.4" + "@babel/helper-module-imports": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-remap-async-to-generator": "^7.8.3" } }, "@babel/plugin-transform-block-scoped-functions": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.7.4.tgz", - "integrity": "sha512-kqtQzwtKcpPclHYjLK//3lH8OFsCDuDJBaFhVwf8kqdnF6MN4l618UDlcA7TfRs3FayrHj+svYnSX8MC9zmUyQ==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.8.3.tgz", + "integrity": "sha512-vo4F2OewqjbB1+yaJ7k2EJFHlTP3jR634Z9Cj9itpqNjuLXvhlVxgnjsHsdRgASR8xYDrx6onw4vW5H6We0Jmg==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.8.3" } }, "@babel/plugin-transform-block-scoping": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.7.4.tgz", - "integrity": "sha512-2VBe9u0G+fDt9B5OV5DQH4KBf5DoiNkwFKOz0TCvBWvdAN2rOykCTkrL+jTLxfCAm76l9Qo5OqL7HBOx2dWggg==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.8.3.tgz", + "integrity": "sha512-pGnYfm7RNRgYRi7bids5bHluENHqJhrV4bCZRwc5GamaWIIs07N4rZECcmJL6ZClwjDz1GbdMZFtPs27hTB06w==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-plugin-utils": "^7.8.3", "lodash": "^4.17.13" } }, "@babel/plugin-transform-classes": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.7.4.tgz", - "integrity": "sha512-sK1mjWat7K+buWRuImEzjNf68qrKcrddtpQo3swi9j7dUcG6y6R6+Di039QN2bD1dykeswlagupEmpOatFHHUg==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.7.4", - "@babel/helper-define-map": "^7.7.4", - "@babel/helper-function-name": "^7.7.4", - "@babel/helper-optimise-call-expression": "^7.7.4", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.7.4", - "@babel/helper-split-export-declaration": "^7.7.4", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.8.3.tgz", + "integrity": "sha512-SjT0cwFJ+7Rbr1vQsvphAHwUHvSUPmMjMU/0P59G8U2HLFqSa082JO7zkbDNWs9kH/IUqpHI6xWNesGf8haF1w==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.8.3", + "@babel/helper-define-map": "^7.8.3", + "@babel/helper-function-name": "^7.8.3", + "@babel/helper-optimise-call-expression": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-replace-supers": "^7.8.3", + "@babel/helper-split-export-declaration": "^7.8.3", "globals": "^11.1.0" } }, "@babel/plugin-transform-computed-properties": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.7.4.tgz", - "integrity": "sha512-bSNsOsZnlpLLyQew35rl4Fma3yKWqK3ImWMSC/Nc+6nGjC9s5NFWAer1YQ899/6s9HxO2zQC1WoFNfkOqRkqRQ==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.8.3.tgz", + "integrity": "sha512-O5hiIpSyOGdrQZRQ2ccwtTVkgUDBBiCuK//4RJ6UfePllUTCENOzKxfh6ulckXKc0DixTFLCfb2HVkNA7aDpzA==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.8.3" } }, "@babel/plugin-transform-destructuring": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.7.4.tgz", - "integrity": "sha512-4jFMXI1Cu2aXbcXXl8Lr6YubCn6Oc7k9lLsu8v61TZh+1jny2BWmdtvY9zSUlLdGUvcy9DMAWyZEOqjsbeg/wA==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.8.3.tgz", + "integrity": "sha512-H4X646nCkiEcHZUZaRkhE2XVsoz0J/1x3VVujnn96pSoGCtKPA99ZZA+va+gK+92Zycd6OBKCD8tDb/731bhgQ==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.8.3" } }, "@babel/plugin-transform-dotall-regex": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.7.4.tgz", - "integrity": "sha512-mk0cH1zyMa/XHeb6LOTXTbG7uIJ8Rrjlzu91pUx/KS3JpcgaTDwMS8kM+ar8SLOvlL2Lofi4CGBAjCo3a2x+lw==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.8.3.tgz", + "integrity": "sha512-kLs1j9Nn4MQoBYdRXH6AeaXMbEJFaFu/v1nQkvib6QzTj8MZI5OQzqmD83/2jEM1z0DLilra5aWO5YpyC0ALIw==", "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.7.4", - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-create-regexp-features-plugin": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" } }, "@babel/plugin-transform-duplicate-keys": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.7.4.tgz", - "integrity": "sha512-g1y4/G6xGWMD85Tlft5XedGaZBCIVN+/P0bs6eabmcPP9egFleMAo65OOjlhcz1njpwagyY3t0nsQC9oTFegJA==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.8.3.tgz", + "integrity": "sha512-s8dHiBUbcbSgipS4SMFuWGqCvyge5V2ZeAWzR6INTVC3Ltjig/Vw1G2Gztv0vU/hRG9X8IvKvYdoksnUfgXOEQ==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.8.3" } }, "@babel/plugin-transform-exponentiation-operator": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.7.4.tgz", - "integrity": "sha512-MCqiLfCKm6KEA1dglf6Uqq1ElDIZwFuzz1WH5mTf8k2uQSxEJMbOIEh7IZv7uichr7PMfi5YVSrr1vz+ipp7AQ==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.8.3.tgz", + "integrity": "sha512-zwIpuIymb3ACcInbksHaNcR12S++0MDLKkiqXHl3AzpgdKlFNhog+z/K0+TGW+b0w5pgTq4H6IwV/WhxbGYSjQ==", "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.7.4", - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" } }, "@babel/plugin-transform-for-of": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.7.4.tgz", - "integrity": "sha512-zZ1fD1B8keYtEcKF+M1TROfeHTKnijcVQm0yO/Yu1f7qoDoxEIc/+GX6Go430Bg84eM/xwPFp0+h4EbZg7epAA==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.8.3.tgz", + "integrity": "sha512-ZjXznLNTxhpf4Q5q3x1NsngzGA38t9naWH8Gt+0qYZEJAcvPI9waSStSh56u19Ofjr7QmD0wUsQ8hw8s/p1VnA==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.8.3" } }, "@babel/plugin-transform-function-name": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.7.4.tgz", - "integrity": "sha512-E/x09TvjHNhsULs2IusN+aJNRV5zKwxu1cpirZyRPw+FyyIKEHPXTsadj48bVpc1R5Qq1B5ZkzumuFLytnbT6g==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.8.3.tgz", + "integrity": "sha512-rO/OnDS78Eifbjn5Py9v8y0aR+aSYhDhqAwVfsTl0ERuMZyr05L1aFSCJnbv2mmsLkit/4ReeQ9N2BgLnOcPCQ==", "requires": { - "@babel/helper-function-name": "^7.7.4", - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-function-name": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" } }, "@babel/plugin-transform-literals": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.7.4.tgz", - "integrity": "sha512-X2MSV7LfJFm4aZfxd0yLVFrEXAgPqYoDG53Br/tCKiKYfX0MjVjQeWPIhPHHsCqzwQANq+FLN786fF5rgLS+gw==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.8.3.tgz", + "integrity": "sha512-3Tqf8JJ/qB7TeldGl+TT55+uQei9JfYaregDcEAyBZ7akutriFrt6C/wLYIer6OYhleVQvH/ntEhjE/xMmy10A==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.8.3" } }, "@babel/plugin-transform-modules-amd": { - "version": "7.7.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.7.5.tgz", - "integrity": "sha512-CT57FG4A2ZUNU1v+HdvDSDrjNWBrtCmSH6YbbgN3Lrf0Di/q/lWRxZrE72p3+HCCz9UjfZOEBdphgC0nzOS6DQ==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.8.3.tgz", + "integrity": "sha512-MadJiU3rLKclzT5kBH4yxdry96odTUwuqrZM+GllFI/VhxfPz+k9MshJM+MwhfkCdxxclSbSBbUGciBngR+kEQ==", "requires": { - "@babel/helper-module-transforms": "^7.7.5", - "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-module-transforms": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", "babel-plugin-dynamic-import-node": "^2.3.0" } }, "@babel/plugin-transform-modules-commonjs": { - "version": "7.7.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.7.5.tgz", - "integrity": "sha512-9Cq4zTFExwFhQI6MT1aFxgqhIsMWQWDVwOgLzl7PTWJHsNaqFvklAU+Oz6AQLAS0dJKTwZSOCo20INwktxpi3Q==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.8.3.tgz", + "integrity": "sha512-JpdMEfA15HZ/1gNuB9XEDlZM1h/gF/YOH7zaZzQu2xCFRfwc01NXBMHHSTT6hRjlXJJs5x/bfODM3LiCk94Sxg==", "requires": { - "@babel/helper-module-transforms": "^7.7.5", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-simple-access": "^7.7.4", + "@babel/helper-module-transforms": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-simple-access": "^7.8.3", "babel-plugin-dynamic-import-node": "^2.3.0" } }, "@babel/plugin-transform-modules-systemjs": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.7.4.tgz", - "integrity": "sha512-y2c96hmcsUi6LrMqvmNDPBBiGCiQu0aYqpHatVVu6kD4mFEXKjyNxd/drc18XXAf9dv7UXjrZwBVmTTGaGP8iw==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.8.3.tgz", + "integrity": "sha512-8cESMCJjmArMYqa9AO5YuMEkE4ds28tMpZcGZB/jl3n0ZzlsxOAi3mC+SKypTfT8gjMupCnd3YiXCkMjj2jfOg==", "requires": { - "@babel/helper-hoist-variables": "^7.7.4", - "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-hoist-variables": "^7.8.3", + "@babel/helper-module-transforms": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", "babel-plugin-dynamic-import-node": "^2.3.0" } }, "@babel/plugin-transform-modules-umd": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.7.4.tgz", - "integrity": "sha512-u2B8TIi0qZI4j8q4C51ktfO7E3cQ0qnaXFI1/OXITordD40tt17g/sXqgNNCcMTcBFKrUPcGDx+TBJuZxLx7tw==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.8.3.tgz", + "integrity": "sha512-evhTyWhbwbI3/U6dZAnx/ePoV7H6OUG+OjiJFHmhr9FPn0VShjwC2kdxqIuQ/+1P50TMrneGzMeyMTFOjKSnAw==", "requires": { - "@babel/helper-module-transforms": "^7.7.4", - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-module-transforms": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" } }, "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.7.4.tgz", - "integrity": "sha512-jBUkiqLKvUWpv9GLSuHUFYdmHg0ujC1JEYoZUfeOOfNydZXp1sXObgyPatpcwjWgsdBGsagWW0cdJpX/DO2jMw==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.8.3.tgz", + "integrity": "sha512-f+tF/8UVPU86TrCb06JoPWIdDpTNSGGcAtaD9mLP0aYGA0OS0j7j7DHJR0GTFrUZPUU6loZhbsVZgTh0N+Qdnw==", "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.7.4" + "@babel/helper-create-regexp-features-plugin": "^7.8.3" } }, "@babel/plugin-transform-new-target": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.7.4.tgz", - "integrity": "sha512-CnPRiNtOG1vRodnsyGX37bHQleHE14B9dnnlgSeEs3ek3fHN1A1SScglTCg1sfbe7sRQ2BUcpgpTpWSfMKz3gg==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.8.3.tgz", + "integrity": "sha512-QuSGysibQpyxexRyui2vca+Cmbljo8bcRckgzYV4kRIsHpVeyeC3JDO63pY+xFZ6bWOBn7pfKZTqV4o/ix9sFw==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.8.3" } }, "@babel/plugin-transform-object-super": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.7.4.tgz", - "integrity": "sha512-ho+dAEhC2aRnff2JCA0SAK7V2R62zJd/7dmtoe7MHcso4C2mS+vZjn1Pb1pCVZvJs1mgsvv5+7sT+m3Bysb6eg==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.8.3.tgz", + "integrity": "sha512-57FXk+gItG/GejofIyLIgBKTas4+pEU47IXKDBWFTxdPd7F80H8zybyAY7UoblVfBhBGs2EKM+bJUu2+iUYPDQ==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.7.4" + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-replace-supers": "^7.8.3" } }, "@babel/plugin-transform-parameters": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.7.4.tgz", - "integrity": "sha512-VJwhVePWPa0DqE9vcfptaJSzNDKrWU/4FbYCjZERtmqEs05g3UMXnYMZoXja7JAJ7Y7sPZipwm/pGApZt7wHlw==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.8.3.tgz", + "integrity": "sha512-/pqngtGb54JwMBZ6S/D3XYylQDFtGjWrnoCF4gXZOUpFV/ujbxnoNGNvDGu6doFWRPBveE72qTx/RRU44j5I/Q==", "requires": { - "@babel/helper-call-delegate": "^7.7.4", - "@babel/helper-get-function-arity": "^7.7.4", - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-call-delegate": "^7.8.3", + "@babel/helper-get-function-arity": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" } }, "@babel/plugin-transform-regenerator": { - "version": "7.7.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.7.5.tgz", - "integrity": "sha512-/8I8tPvX2FkuEyWbjRCt4qTAgZK0DVy8QRguhA524UH48RfGJy94On2ri+dCuwOpcerPRl9O4ebQkRcVzIaGBw==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.3.tgz", + "integrity": "sha512-qt/kcur/FxrQrzFR432FGZznkVAjiyFtCOANjkAKwCbt465L6ZCiUQh2oMYGU3Wo8LRFJxNDFwWn106S5wVUNA==", "requires": { "regenerator-transform": "^0.14.0" } }, "@babel/plugin-transform-runtime": { - "version": "7.7.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.7.6.tgz", - "integrity": "sha512-tajQY+YmXR7JjTwRvwL4HePqoL3DYxpYXIHKVvrOIvJmeHe2y1w4tz5qz9ObUDC9m76rCzIMPyn4eERuwA4a4A==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.8.3.tgz", + "integrity": "sha512-/vqUt5Yh+cgPZXXjmaG9NT8aVfThKk7G4OqkVhrXqwsC5soMn/qTCxs36rZ2QFhpfTJcjw4SNDIZ4RUb8OL4jQ==", "requires": { - "@babel/helper-module-imports": "^7.7.4", - "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-module-imports": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", "resolve": "^1.8.1", "semver": "^5.5.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } } }, "@babel/plugin-transform-shorthand-properties": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.7.4.tgz", - "integrity": "sha512-q+suddWRfIcnyG5YiDP58sT65AJDZSUhXQDZE3r04AuqD6d/XLaQPPXSBzP2zGerkgBivqtQm9XKGLuHqBID6Q==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.8.3.tgz", + "integrity": "sha512-I9DI6Odg0JJwxCHzbzW08ggMdCezoWcuQRz3ptdudgwaHxTjxw5HgdFJmZIkIMlRymL6YiZcped4TTCB0JcC8w==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.8.3" } }, "@babel/plugin-transform-spread": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.7.4.tgz", - "integrity": "sha512-8OSs0FLe5/80cndziPlg4R0K6HcWSM0zyNhHhLsmw/Nc5MaA49cAsnoJ/t/YZf8qkG7fD+UjTRaApVDB526d7Q==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.8.3.tgz", + "integrity": "sha512-CkuTU9mbmAoFOI1tklFWYYbzX5qCIZVXPVy0jpXgGwkplCndQAa58s2jr66fTeQnA64bDox0HL4U56CFYoyC7g==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.8.3" } }, "@babel/plugin-transform-sticky-regex": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.7.4.tgz", - "integrity": "sha512-Ls2NASyL6qtVe1H1hXts9yuEeONV2TJZmplLONkMPUG158CtmnrzW5Q5teibM5UVOFjG0D3IC5mzXR6pPpUY7A==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.8.3.tgz", + "integrity": "sha512-9Spq0vGCD5Bb4Z/ZXXSK5wbbLFMG085qd2vhL1JYu1WcQ5bXqZBAYRzU1d+p79GcHs2szYv5pVQCX13QgldaWw==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-regex": "^7.0.0" + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-regex": "^7.8.3" } }, "@babel/plugin-transform-template-literals": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.7.4.tgz", - "integrity": "sha512-sA+KxLwF3QwGj5abMHkHgshp9+rRz+oY9uoRil4CyLtgEuE/88dpkeWgNk5qKVsJE9iSfly3nvHapdRiIS2wnQ==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.8.3.tgz", + "integrity": "sha512-820QBtykIQOLFT8NZOcTRJ1UNuztIELe4p9DCgvj4NK+PwluSJ49we7s9FB1HIGNIYT7wFUJ0ar2QpCDj0escQ==", "requires": { - "@babel/helper-annotate-as-pure": "^7.7.4", - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-annotate-as-pure": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" } }, "@babel/plugin-transform-typeof-symbol": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.7.4.tgz", - "integrity": "sha512-KQPUQ/7mqe2m0B8VecdyaW5XcQYaePyl9R7IsKd+irzj6jvbhoGnRE+M0aNkyAzI07VfUQ9266L5xMARitV3wg==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.8.3.tgz", + "integrity": "sha512-3TrkKd4LPqm4jHs6nPtSDI/SV9Cm5PRJkHLUgTcqRQQTMAZ44ZaAdDZJtvWFSaRcvT0a1rTmJ5ZA5tDKjleF3g==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.8.3" } }, "@babel/plugin-transform-unicode-regex": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.7.4.tgz", - "integrity": "sha512-N77UUIV+WCvE+5yHw+oks3m18/umd7y392Zv7mYTpFqHtkpcc+QUz+gLJNTWVlWROIWeLqY0f3OjZxV5TcXnRw==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.8.3.tgz", + "integrity": "sha512-+ufgJjYdmWfSQ+6NS9VGUR2ns8cjJjYbrbi11mZBTaWm+Fui/ncTLFF28Ei1okavY+xkojGr1eJxNsWYeA5aZw==", "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.7.4", - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-create-regexp-features-plugin": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" } }, "@babel/preset-env": { @@ -730,12 +744,19 @@ "invariant": "^2.2.2", "js-levenshtein": "^1.1.3", "semver": "^5.3.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } } }, "@babel/runtime": { - "version": "7.7.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.7.6.tgz", - "integrity": "sha512-BWAJxpNVa0QlE5gZdWjSxXtemZyZ9RmrmVozxt3NUXeZhVIJ5ANyqmMc0JDrivBZyxUuQvFxlvH4OWWOogGfUw==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.8.3.tgz", + "integrity": "sha512-fVHx1rzEmwB130VTkLnxR+HmxcTjGzH12LYQcFFoBwakMd3aOMD4OsRN7tGG/UOYE2ektgFrS8uACAoRk1CY0w==", "requires": { "regenerator-runtime": "^0.13.2" }, @@ -748,9 +769,9 @@ } }, "@babel/runtime-corejs2": { - "version": "7.7.6", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs2/-/runtime-corejs2-7.7.6.tgz", - "integrity": "sha512-QYp/8xdH8iMin3pH5gtT/rUuttVfIcOhWBC3wh9Eh/qs4jEe39+3DpCDLgWXhMQgiCTOH8mrLSvQ0OHOCcox9g==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs2/-/runtime-corejs2-7.8.3.tgz", + "integrity": "sha512-yxJXBKdIogkfF+wgeJrvU7Afp5ugBi92NzSgNPWWKVoQAlixH3gwMP6yYYr7SV1Dbc0HmNw7WUJkV5ksvtQuHg==", "requires": { "core-js": "^2.6.5", "regenerator-runtime": "^0.13.2" @@ -764,26 +785,26 @@ } }, "@babel/template": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.7.4.tgz", - "integrity": "sha512-qUzihgVPguAzXCK7WXw8pqs6cEwi54s3E+HrejlkuWO6ivMKx9hZl3Y2fSXp9i5HgyWmj7RKP+ulaYnKM4yYxw==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", + "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.7.4", - "@babel/types": "^7.7.4" + "@babel/code-frame": "^7.8.3", + "@babel/parser": "^7.8.3", + "@babel/types": "^7.8.3" } }, "@babel/traverse": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.7.4.tgz", - "integrity": "sha512-P1L58hQyupn8+ezVA2z5KBm4/Zr4lCC8dwKCMYzsa5jFMDMQAzaBNy9W5VjB+KAmBjb40U7a/H6ao+Xo+9saIw==", - "requires": { - "@babel/code-frame": "^7.5.5", - "@babel/generator": "^7.7.4", - "@babel/helper-function-name": "^7.7.4", - "@babel/helper-split-export-declaration": "^7.7.4", - "@babel/parser": "^7.7.4", - "@babel/types": "^7.7.4", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.3.tgz", + "integrity": "sha512-we+a2lti+eEImHmEXp7bM9cTxGzxPmBiVJlLVD+FuuQMeeO7RaDbutbgeheDkw+Xe3mCfJHnGOWLswT74m2IPg==", + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/generator": "^7.8.3", + "@babel/helper-function-name": "^7.8.3", + "@babel/helper-split-export-declaration": "^7.8.3", + "@babel/parser": "^7.8.3", + "@babel/types": "^7.8.3", "debug": "^4.1.0", "globals": "^11.1.0", "lodash": "^4.17.13" @@ -805,9 +826,9 @@ } }, "@babel/types": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.7.4.tgz", - "integrity": "sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", "requires": { "esutils": "^2.0.2", "lodash": "^4.17.13", @@ -822,10 +843,11 @@ } }, "@cosmos-ui/vue": { - "version": "0.5.17", - "resolved": "https://registry.npmjs.org/@cosmos-ui/vue/-/vue-0.5.17.tgz", - "integrity": "sha512-x9ruudnnUCDxFQZRRMBzmVYM1s7ukmGuyCd0M+fMo3kAwg/IePlyq3aA4aZXD411NvBFNG1A2BxWQAWd09hT0g==", + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/@cosmos-ui/vue/-/vue-0.5.21.tgz", + "integrity": "sha512-Y60AMxFKgHrgE/EHxnGKaTcYUN1nJa5m3SylhsCe/d0AvzF9RSYGSPwVgDxmW4KiufBKXkv4PmiNG9WDNWwdxw==", "requires": { + "tiny-cookie": "^2.3.1", "vue": "^2.6.10" } }, @@ -877,9 +899,9 @@ "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==" }, "@types/node": { - "version": "12.12.18", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.18.tgz", - "integrity": "sha512-DBkZuIMFuAfjJHiunyRc+aNvmXYNwV1IPMgGKGlwCp6zh6MKrVtmvjSWK/axWcD25KJffkXgkfvFra8ndenXAw==" + "version": "13.5.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.5.1.tgz", + "integrity": "sha512-Jj2W7VWQ2uM83f8Ls5ON9adxN98MvyJsMSASYFuSvrov8RMRY64Ayay7KV35ph1TSGIJ2gG9ZVDdEq3c3zaydA==" }, "@types/q": { "version": "1.5.2", @@ -991,26 +1013,21 @@ } }, "@vue/component-compiler-utils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-3.1.0.tgz", - "integrity": "sha512-OJ7swvl8LtKtX5aYP8jHhO6fQBIRIGkU6rvWzK+CGJiNOnvg16nzcBkd9qMZzW8trI2AsqAKx263nv7kb5rhZw==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-3.1.1.tgz", + "integrity": "sha512-+lN3nsfJJDGMNz7fCpcoYIORrXo0K3OTsdr8jCM7FuqdI4+70TY6gxY6viJ2Xi1clqyPg7LpeOWwjF31vSMmUw==", "requires": { "consolidate": "^0.15.1", "hash-sum": "^1.0.2", "lru-cache": "^4.1.2", "merge-source-map": "^1.1.0", "postcss": "^7.0.14", - "postcss-selector-parser": "^5.0.0", + "postcss-selector-parser": "^6.0.2", "prettier": "^1.18.2", "source-map": "~0.6.1", "vue-template-es2015-compiler": "^1.9.0" }, "dependencies": { - "cssesc": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", - "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==" - }, "lru-cache": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", @@ -1020,16 +1037,6 @@ "yallist": "^2.1.2" } }, - "postcss-selector-parser": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", - "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", - "requires": { - "cssesc": "^2.0.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - }, "yallist": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", @@ -1180,13 +1187,6 @@ "hash-sum": "^1.0.2", "semver": "^6.0.0", "upath": "^1.1.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } } }, "@vuepress/theme-default": { @@ -1423,11 +1423,11 @@ "integrity": "sha1-xdG9SxKQCPEWPyNvhuX66iAm4u8=" }, "ajv": { - "version": "6.10.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", - "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.11.0.tgz", + "integrity": "sha512-nCprB/0syFYy9fVYU1ox1l2KN8S9I+tziH8D4zdZuLT3N6RMlGSGt5FSTpAiHB/Whv8Qs1cWHma1aMKZyaHRKA==", "requires": { - "fast-deep-equal": "^2.0.1", + "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" @@ -1463,6 +1463,31 @@ "reduce": "^1.0.1", "semver": "^5.1.0", "tunnel-agent": "^0.6.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" + }, + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } } }, "align-text": { @@ -1475,11 +1500,6 @@ "repeat-string": "^1.5.2" }, "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -1690,16 +1710,16 @@ } }, "autoprefixer": { - "version": "9.7.3", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.7.3.tgz", - "integrity": "sha512-8T5Y1C5Iyj6PgkPSFd0ODvK9DIleuPKUPYniNxybS47g2k2wFgLZ46lGQHlBuGKIAEV8fbCDfKCCRS1tvOgc3Q==", + "version": "9.7.4", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.7.4.tgz", + "integrity": "sha512-g0Ya30YrMBAEZk60lp+qfX5YQllG+S5W3GYCFvyHTvhOki0AEQJLPEcIuGRsqVwLi8FvXPVtwTGhfr38hVpm0g==", "requires": { - "browserslist": "^4.8.0", - "caniuse-lite": "^1.0.30001012", + "browserslist": "^4.8.3", + "caniuse-lite": "^1.0.30001020", "chalk": "^2.4.2", "normalize-range": "^0.1.2", "num2fraction": "^1.2.2", - "postcss": "^7.0.23", + "postcss": "^7.0.26", "postcss-value-parser": "^4.0.2" } }, @@ -1709,17 +1729,16 @@ "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" }, "aws4": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.0.tgz", - "integrity": "sha512-Uvq6hVe90D0B2WEnUqtdgY1bATGz3mw33nH9Y+dmA+w5DHvUmBgkr5rM/KCHpCsiFNRUfokW/szpPPgMK2hm4A==" + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz", + "integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==" }, "axios": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.0.tgz", - "integrity": "sha512-1uvKqKQta3KBxIz14F2v06AEHZ/dIoeKfbTRkK1E5oqjDnuEerLmYTgJB5AiQZHJcljpg1TuRzdjDR06qNk0DQ==", + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", + "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", "requires": { - "follow-redirects": "1.5.10", - "is-buffer": "^2.0.2" + "follow-redirects": "1.5.10" } }, "babel-loader": { @@ -1731,21 +1750,6 @@ "loader-utils": "^1.0.2", "mkdirp": "^0.5.1", "pify": "^4.0.1" - }, - "dependencies": { - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "requires": { - "minimist": "0.0.8" - } - } } }, "babel-plugin-dynamic-import-node": { @@ -1917,10 +1921,13 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" }, - "qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } } } }, @@ -2039,13 +2046,13 @@ } }, "browserslist": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.8.2.tgz", - "integrity": "sha512-+M4oeaTplPm/f1pXDw84YohEv7B1i/2Aisei8s4s6k3QsoSHa7i5sz8u/cGQkkatCPxMASKxPualR4wwYgVboA==", + "version": "4.8.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.8.5.tgz", + "integrity": "sha512-4LMHuicxkabIB+n9874jZX/az1IaZ5a+EUuvD7KFOu9x/Bd5YHyO0DIz2ls/Kl8g0ItS4X/ilEgf4T1Br0lgSg==", "requires": { - "caniuse-lite": "^1.0.30001015", - "electron-to-chromium": "^1.3.322", - "node-releases": "^1.1.42" + "caniuse-lite": "^1.0.30001022", + "electron-to-chromium": "^1.3.338", + "node-releases": "^1.1.46" } }, "buffer": { @@ -2056,13 +2063,6 @@ "base64-js": "^1.0.2", "ieee754": "^1.1.4", "isarray": "^1.0.0" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - } } }, "buffer-from": { @@ -2096,9 +2096,9 @@ "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" }, "cac": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/cac/-/cac-6.5.3.tgz", - "integrity": "sha512-wZfzSWVXuue1H3J7TDNjbzg4KTqPXCmh7F3QIzEYXfnhMCcOUrx99M7rpO2UDVJA9dqv3butGj2nHvCV47CmPg==" + "version": "6.5.6", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.5.6.tgz", + "integrity": "sha512-8jsGLeBiYEVYTDExaj/rDPG4tyra4yjjacIL10TQ+MobPcg9/IST+dkKLu6sOzq0GcIC6fQqX1nkH9HoskQLAw==" }, "cacache": { "version": "12.0.3", @@ -2120,21 +2120,6 @@ "ssri": "^6.0.1", "unique-filename": "^1.1.1", "y18n": "^4.0.0" - }, - "dependencies": { - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "requires": { - "minimist": "0.0.8" - } - } } }, "cache-base": { @@ -2164,21 +2149,6 @@ "mkdirp": "^0.5.1", "neo-async": "^2.6.1", "schema-utils": "^1.0.0" - }, - "dependencies": { - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "requires": { - "minimist": "0.0.8" - } - } } }, "call-me-maybe": { @@ -2233,9 +2203,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001016", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001016.tgz", - "integrity": "sha512-yYQ2QfotceRiH4U+h1Us86WJXtVHDmy3nEKIdYPsZCYnOV5/tMgGbmoIlrMzmh2VXlproqYtVaKeGDBkMZifFA==" + "version": "1.0.30001023", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001023.tgz", + "integrity": "sha512-C5TDMiYG11EOhVOA62W1p3UsJ2z4DsHtMBQtjzp3ZsUglcQn62WOUgW0y795c7A5uZ+GCEIvzkMatLIlAsbNTA==" }, "caseless": { "version": "0.12.0", @@ -2269,6 +2239,26 @@ "is-regex": "^1.0.3" } }, + "cheerio": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.3.tgz", + "integrity": "sha512-0td5ijfUPuubwLUu0OBoe98gZj8C/AA+RW3v67GPlGOrvxWjZmBXiBCRU+I8VEiNyJzjth40POfHiz2RB3gImA==", + "requires": { + "css-select": "~1.2.0", + "dom-serializer": "~0.1.1", + "entities": "~1.1.1", + "htmlparser2": "^3.9.1", + "lodash": "^4.15.0", + "parse5": "^3.0.1" + }, + "dependencies": { + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" + } + } + }, "chokidar": { "version": "2.1.8", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", @@ -2337,9 +2327,9 @@ } }, "clean-css": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz", - "integrity": "sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", + "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==", "requires": { "source-map": "~0.6.0" } @@ -2449,11 +2439,11 @@ "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" }, "compressible": { - "version": "2.0.17", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.17.tgz", - "integrity": "sha512-BGHeLCK1GV7j1bSmQQAi26X+GgWcTjLr/0tzSvMCl3LH1w1IJ4PFSPoV5316b30cneTziC+B1a+3OjoSUcQYmw==", + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", "requires": { - "mime-db": ">= 1.40.0 < 2" + "mime-db": ">= 1.43.0 < 2" } }, "compression": { @@ -2470,6 +2460,14 @@ "vary": "~1.1.2" }, "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -2491,6 +2489,35 @@ "inherits": "^2.0.3", "readable-stream": "^2.2.2", "typedarray": "^0.0.6" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } } }, "connect-history-api-fallback": { @@ -2499,9 +2526,9 @@ "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==" }, "consola": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/consola/-/consola-2.11.0.tgz", - "integrity": "sha512-2bcAqHastlPSCvZ+ur8bgHInGAWvUnysWz3h3xRX+/XZoCY7avolJJnVXOPGoVoyCcg1b231XixonoArmgxaoA==" + "version": "2.11.3", + "resolved": "https://registry.npmjs.org/consola/-/consola-2.11.3.tgz", + "integrity": "sha512-aoW0YIIAmeftGR8GSpw6CGQluNdkWMWh3yEFjH/hmynTYnMtibXszii3lxCXmk8YxJtI3FAK5aTiquA5VH68Gw==" }, "console-browserify": { "version": "1.2.0", @@ -2588,21 +2615,6 @@ "mkdirp": "^0.5.1", "rimraf": "^2.5.4", "run-queue": "^1.0.0" - }, - "dependencies": { - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "requires": { - "minimist": "0.0.8" - } - } } }, "copy-descriptor": { @@ -2648,9 +2660,9 @@ "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==" }, "p-limit": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", - "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", + "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", "requires": { "p-try": "^2.0.0" } @@ -2737,6 +2749,13 @@ "semver": "^5.5.0", "shebang-command": "^1.2.0", "which": "^1.2.9" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } } }, "crypto-browserify": { @@ -2821,14 +2840,14 @@ } }, "css-select": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", - "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", + "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", "requires": { - "boolbase": "^1.0.0", - "css-what": "^3.2.1", - "domutils": "^1.7.0", - "nth-check": "^1.0.2" + "boolbase": "~1.0.0", + "css-what": "2.1", + "domutils": "1.5.1", + "nth-check": "~1.0.1" } }, "css-select-base-adapter": { @@ -2851,9 +2870,9 @@ "integrity": "sha1-2bkoGtz9jO2TW9urqDeGiX9k6ZY=" }, "css-what": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.2.1.tgz", - "integrity": "sha512-WwOrosiQTvyms+Ti5ZC5vGEK0Vod3FTt1ca+payZqvKuGJF+dq7bG63DstxtN0dpm6FxY27a/zS3Wten+gEtGw==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", + "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==" }, "cssesc": { "version": "3.0.0", @@ -2958,9 +2977,9 @@ "integrity": "sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0=" }, "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "requires": { "ms": "2.0.0" } @@ -3190,18 +3209,18 @@ } }, "dom-serializer": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", - "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", + "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", "requires": { - "domelementtype": "^2.0.1", - "entities": "^2.0.0" + "domelementtype": "^1.3.0", + "entities": "^1.1.1" }, "dependencies": { - "domelementtype": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.1.tgz", - "integrity": "sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ==" + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" } } }, @@ -3229,9 +3248,9 @@ } }, "domutils": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", - "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", "requires": { "dom-serializer": "0", "domelementtype": "1" @@ -3254,6 +3273,35 @@ "inherits": "^2.0.1", "readable-stream": "^2.0.0", "stream-shift": "^1.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } } }, "ecc-jsbn": { @@ -3271,9 +3319,9 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, "electron-to-chromium": { - "version": "1.3.322", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.322.tgz", - "integrity": "sha512-Tc8JQEfGQ1MzfSzI/bTlSr7btJv/FFO7Yh6tanqVmIWOuNCu6/D1MilIEgLtmWqIrsv+o4IjpLAhgMBr/ncNAA==" + "version": "1.3.341", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.341.tgz", + "integrity": "sha512-iezlV55/tan1rvdvt7yg7VHRSkt+sKfzQ16wTDqTbQqtl4+pSUkKPXpQHDvEt0c7gKcUHHwUbffOgXz6bn096g==" }, "elliptic": { "version": "6.5.2", @@ -3330,6 +3378,33 @@ "errno": "^0.1.3", "readable-stream": "^2.0.1" } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } } } }, @@ -3369,21 +3444,21 @@ } }, "es-abstract": { - "version": "1.17.0-next.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.0-next.1.tgz", - "integrity": "sha512-7MmGr03N7Rnuid6+wyhD9sHNE2n4tFSwExnU2lQl3lIo2ShXWGePY80zYaoMOmILWv57H0amMjZGHNzzGG70Rw==", + "version": "1.17.4", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz", + "integrity": "sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==", "requires": { "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", "has": "^1.0.3", "has-symbols": "^1.0.1", - "is-callable": "^1.1.4", - "is-regex": "^1.0.4", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", "object-inspect": "^1.7.0", "object-keys": "^1.1.1", "object.assign": "^4.1.0", - "string.prototype.trimleft": "^2.1.0", - "string.prototype.trimright": "^2.1.0" + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" } }, "es-to-primitive": { @@ -3454,9 +3529,9 @@ "integrity": "sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==" }, "events": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.1.0.tgz", + "integrity": "sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg==" }, "eventsource": { "version": "1.0.7", @@ -3503,6 +3578,14 @@ "to-regex": "^3.0.1" }, "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", @@ -3555,10 +3638,13 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, - "qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } }, "safe-buffer": { "version": "5.1.2", @@ -3637,9 +3723,9 @@ "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" }, "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", + "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==" }, "fast-glob": { "version": "2.2.7", @@ -3718,10 +3804,20 @@ "parseurl": "~1.3.3", "statuses": "~1.5.0", "unpipe": "~1.0.0" - } - }, - "find-babel-config": { - "version": "1.2.0", + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "find-babel-config": { + "version": "1.2.0", "resolved": "https://registry.npmjs.org/find-babel-config/-/find-babel-config-1.2.0.tgz", "integrity": "sha512-jB2CHJeqy6a820ssiqwrKMeyC6nNdmrcgkKWJWmpoxpE8RKciYJXCcXRq1h2AzCo5I5BJeN2tkGEO3hLTuePRA==", "requires": { @@ -3761,6 +3857,35 @@ "requires": { "inherits": "^2.0.3", "readable-stream": "^2.3.6" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } } }, "follow-redirects": { @@ -3769,16 +3894,6 @@ "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", "requires": { "debug": "=3.1.0" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - } } }, "for-in": { @@ -3831,6 +3946,35 @@ "requires": { "inherits": "^2.0.1", "readable-stream": "^2.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } } }, "fs-extra": { @@ -3852,6 +3996,35 @@ "iferr": "^0.1.5", "imurmurhash": "^0.1.4", "readable-stream": "1 || 2" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } } }, "fs.realpath": { @@ -4359,6 +4532,11 @@ "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-3.4.6.tgz", "integrity": "sha512-H6aJY4UpLFwxj1+5nAvufom5b2BT2v45P1MkPvdGIK8fWjQx/7o6tTT1+ALV0yawQvbmvCF0ufl2et8eJ7v7Cg==" }, + "gensync": { + "version": "1.0.0-beta.1", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz", + "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==" + }, "get-caller-file": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", @@ -4540,11 +4718,6 @@ "kind-of": "^4.0.0" }, "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, "kind-of": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", @@ -4605,6 +4778,13 @@ "requires": { "mkdirp": "0.3.0", "nopt": "1.0.10" + }, + "dependencies": { + "mkdirp": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", + "integrity": "sha1-G79asbqCevI1dRQ0kEJkVfSB/h4=" + } } }, "hotkeys-js": { @@ -4621,6 +4801,35 @@ "obuf": "^1.0.0", "readable-stream": "^2.0.1", "wbuf": "^1.1.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } } }, "hsl-regex": { @@ -4697,16 +4906,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" - }, - "readable-stream": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", - "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } } } }, @@ -4888,11 +5087,6 @@ "ipaddr.js": "^1.9.0" } }, - "intersection-observer": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/intersection-observer/-/intersection-observer-0.7.0.tgz", - "integrity": "sha512-Id0Fij0HsB/vKWGeBe9PxeY45ttRiBmhFyyt/geBdDHBYNctMRTE3dC1U3ujzz3lap+hVXlEcVaB56kZP/eEUg==" - }, "invariant": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", @@ -4934,11 +5128,6 @@ "kind-of": "^3.0.2" }, "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -4968,14 +5157,14 @@ } }, "is-buffer": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", - "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==" + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" }, "is-callable": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", - "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==" + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==" }, "is-color-stop": { "version": "1.1.0", @@ -4998,11 +5187,6 @@ "kind-of": "^3.0.2" }, "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -5014,9 +5198,9 @@ } }, "is-date-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", - "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=" + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==" }, "is-descriptor": { "version": "0.1.6", @@ -5087,11 +5271,6 @@ "kind-of": "^3.0.2" }, "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -5196,9 +5375,9 @@ "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=" }, "isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, "isexe": { "version": "2.0.0", @@ -5321,9 +5500,9 @@ "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==" }, "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" }, "last-call-webpack-plugin": { "version": "3.0.0", @@ -5482,11 +5661,6 @@ "yallist": "^3.0.2" } }, - "lunr": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.8.tgz", - "integrity": "sha512-oxMeX/Y35PNFuZoHp+jUj5OSEmLCaIH4KTFJh7a93cHBoFmpw2IoPs22VIz7vyO2YUnx2Tn9dzIwO2P/4quIRg==" - }, "make-dir": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", @@ -5494,6 +5668,13 @@ "requires": { "pify": "^4.0.1", "semver": "^5.6.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } } }, "mamacro": { @@ -5562,11 +5743,6 @@ "resolved": "https://registry.npmjs.org/markdown-it-emoji/-/markdown-it-emoji-1.4.0.tgz", "integrity": "sha1-m+4OmpkKljupbfaYDE/dsF37Tcw=" }, - "markdown-it-ins": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/markdown-it-ins/-/markdown-it-ins-3.0.0.tgz", - "integrity": "sha512-+vyAdBuMGwmT2yMlAFJSx2VR/0QZ1onQ/Mkkmr4l9tDFOh5sVoAgRbkgbuSsk+sxJ9vaMH/IQ323ydfvQrPO/Q==" - }, "markdown-it-table-of-contents": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/markdown-it-table-of-contents/-/markdown-it-table-of-contents-0.4.4.tgz", @@ -5614,6 +5790,35 @@ "requires": { "errno": "^0.1.3", "readable-stream": "^2.0.1" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } } }, "merge-descriptors": { @@ -5693,16 +5898,16 @@ "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==" }, "mime-db": { - "version": "1.42.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.42.0.tgz", - "integrity": "sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ==" + "version": "1.43.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", + "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==" }, "mime-types": { - "version": "2.1.25", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.25.tgz", - "integrity": "sha512-5KhStqB5xpTAeGqKBAMgwaYMnQik7teQN4IAzC7npDv6kzeU6prfkR67bc87J1kWMPGkoaZSq1npmexMgkmEVg==", + "version": "2.1.26", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", + "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", "requires": { - "mime-db": "1.42.0" + "mime-db": "1.43.0" } }, "mimic-fn": { @@ -5789,9 +5994,19 @@ } }, "mkdirp": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", - "integrity": "sha1-G79asbqCevI1dRQ0kEJkVfSB/h4=" + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + } + } }, "move-concurrently": { "version": "1.0.1", @@ -5804,21 +6019,6 @@ "mkdirp": "^0.5.1", "rimraf": "^2.5.4", "run-queue": "^1.0.3" - }, - "dependencies": { - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "requires": { - "minimist": "0.0.8" - } - } } }, "ms": { @@ -5941,31 +6141,48 @@ "vm-browserify": "^1.0.1" }, "dependencies": { - "events": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz", - "integrity": "sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA==" - }, "punycode": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" } } }, "node-releases": { - "version": "1.1.42", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.42.tgz", - "integrity": "sha512-OQ/ESmUqGawI2PRX+XIRao44qWYBBfN54ImQYdWVTQqUckuejOg76ysSqDBK8NG3zwySRVnX36JwDQ6x+9GxzA==", + "version": "1.1.47", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.47.tgz", + "integrity": "sha512-k4xjVPx5FpwBUj0Gw7uvFOTF4Ep8Hok1I6qjwL3pLfwe7Y0REQSAqOwwv9TWBCUtMHxcXfY4PgRLRozcChvTcA==", "requires": { "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } } }, "nopt": { @@ -6055,11 +6272,6 @@ "is-descriptor": "^0.1.0" } }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -6253,9 +6465,9 @@ "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" }, "pako": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz", - "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==" + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" }, "parallel-transform": { "version": "1.2.0", @@ -6265,6 +6477,35 @@ "cyclist": "^1.0.1", "inherits": "^2.0.3", "readable-stream": "^2.1.5" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } } }, "param-case": { @@ -6297,6 +6538,14 @@ "json-parse-better-errors": "^1.0.1" } }, + "parse5": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-3.0.3.tgz", + "integrity": "sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA==", + "requires": { + "@types/node": "*" + } + }, "parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -6423,9 +6672,9 @@ } }, "p-limit": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", - "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", + "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", "requires": { "p-try": "^2.0.0" } @@ -6471,19 +6720,6 @@ "ms": "^2.1.1" } }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "requires": { - "minimist": "0.0.8" - } - }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -6497,9 +6733,9 @@ "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" }, "postcss": { - "version": "7.0.24", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.24.tgz", - "integrity": "sha512-Xl0XvdNWg+CblAXzNvbSOUvgJXwSjmbAKORqyw9V2AlHrm1js2gFw9y3jibBAhpKZi8b5JzJCVh/FyzPsTtgTA==", + "version": "7.0.26", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.26.tgz", + "integrity": "sha512-IY4oRjpXWYshuTDFxMVkJDtWIk2LhsTlu8bZnbEJA4+bYT16Lvpo8Qv6EvDumhYRgzjZl489pmsY3qVgJQ08nA==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -7072,9 +7308,9 @@ "integrity": "sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA==" }, "prismjs": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.17.1.tgz", - "integrity": "sha512-PrEDJAFdUGbOP6xK/UsfkC5ghJsPJviKgnQOoxaDbBjwc8op68Quupwt1DeAFoG8GImPhiKXAvvsH7wDSLsu1Q==", + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.19.0.tgz", + "integrity": "sha512-IVFtbW9mCWm9eOIaEkNyo2Vl4NnEifis2GQ7/MLRG5TQe6t+4Sj9J5QWI9i3v+SS43uZBlCAOn+zYTVYQcPXJw==", "requires": { "clipboard": "^2.0.0" } @@ -7127,9 +7363,9 @@ "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" }, "psl": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.6.0.tgz", - "integrity": "sha512-SYKKmVel98NCOYXpkwUqZqh0ahZeeKfmisiLIcEZdsb+WbLv02g/dI5BUmZnIyOe7RzZtLax81nnb2HbvC2tzA==" + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.7.0.tgz", + "integrity": "sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ==" }, "public-encrypt": { "version": "4.0.3", @@ -7307,9 +7543,9 @@ "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=" }, "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" }, "query-string": { "version": "5.1.1", @@ -7377,29 +7613,13 @@ } }, "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.5.0.tgz", + "integrity": "sha512-gSz026xs2LfxBPudDuI41V1lka8cxg64E66SGe78zJlsUofOg/yqwezdIcdfwik6B4h8LFmWPA9ef9X3FiNFLA==", "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - } + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" } }, "readdirp": { @@ -7410,6 +7630,35 @@ "graceful-fs": "^4.1.11", "micromatch": "^3.1.10", "readable-stream": "^2.0.2" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } } }, "reduce": { @@ -7502,9 +7751,9 @@ "integrity": "sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg==" }, "regjsparser": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.1.tgz", - "integrity": "sha512-7LutE94sz/NKSYegK+/4E77+8DipxF+Qn2Tmu362AcmsF2NYq/wx3+ObvU90TKEhjf7hQoFXo23ajjrXP7eUgg==", + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.2.tgz", + "integrity": "sha512-E9ghzUtoLwDekPT0DYCp+c4h+bvuUpe6rRHCTYn6eGoqj1LgKXxT6I0Il4WbjhQkOghzi/V+y03bPKvbllL93Q==", "requires": { "jsesc": "~0.5.0" }, @@ -7536,33 +7785,6 @@ "htmlparser2": "^3.3.0", "strip-ansi": "^3.0.0", "utila": "^0.4.0" - }, - "dependencies": { - "css-select": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", - "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", - "requires": { - "boolbase": "~1.0.0", - "css-what": "2.1", - "domutils": "1.5.1", - "nth-check": "~1.0.1" - } - }, - "css-what": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", - "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==" - }, - "domutils": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", - "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", - "requires": { - "dom-serializer": "0", - "domelementtype": "1" - } - } } }, "repeat-element": { @@ -7600,6 +7822,13 @@ "tough-cookie": "~2.4.3", "tunnel-agent": "^0.6.0", "uuid": "^3.3.2" + }, + "dependencies": { + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + } } }, "require-directory": { @@ -7623,9 +7852,9 @@ "integrity": "sha1-79qpjqdFEyTQkrKyFjpqHXqaIUc=" }, "resolve": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.13.1.tgz", - "integrity": "sha512-CxqObCX8K8YtAhOBRg+lrcdn+LK+WYOS8tSjqSFbjtrI5PnS63QPhZl4+yKfrU9tdsbMu9Anr/amegT87M9Z6w==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.0.tgz", + "integrity": "sha512-+hTmAldEGE80U2wJJDC1lebb5jWqvTYAfm3YZ1ckk1gBr0MnCqUKlwK1e+anaFljIl+F5tR5IoZcm4ZDA1zMQw==", "requires": { "path-parse": "^1.0.6" } @@ -7763,9 +7992,9 @@ } }, "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" }, "send": { "version": "0.17.1", @@ -7787,6 +8016,21 @@ "statuses": "~1.5.0" }, "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, "mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -7818,6 +8062,14 @@ "parseurl": "~1.3.2" }, "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, "http-errors": { "version": "1.6.3", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", @@ -7956,6 +8208,14 @@ "use": "^3.1.0" }, "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", @@ -8025,11 +8285,6 @@ "kind-of": "^3.2.0" }, "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -8104,11 +8359,11 @@ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" }, "source-map-resolve": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", - "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", "requires": { - "atob": "^2.1.1", + "atob": "^2.1.2", "decode-uri-component": "^0.2.0", "resolve-url": "^0.2.1", "source-map-url": "^0.4.0", @@ -8181,16 +8436,6 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "readable-stream": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", - "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } } } }, @@ -8299,6 +8544,35 @@ "requires": { "inherits": "~2.0.1", "readable-stream": "^2.0.2" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } } }, "stream-each": { @@ -8320,6 +8594,35 @@ "readable-stream": "^2.3.6", "to-arraybuffer": "^1.0.0", "xtend": "^4.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } } }, "stream-shift": { @@ -8357,36 +8660,29 @@ } }, "string.prototype.trimleft": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz", - "integrity": "sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz", + "integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==", "requires": { "define-properties": "^1.1.3", "function-bind": "^1.1.1" } }, "string.prototype.trimright": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz", - "integrity": "sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz", + "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==", "requires": { "define-properties": "^1.1.3", "function-bind": "^1.1.1" } }, "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "requires": { - "safe-buffer": "~5.1.0" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - } + "safe-buffer": "~5.2.0" } }, "strip-ansi": { @@ -8444,32 +8740,6 @@ "source-map": "^0.7.3" }, "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "requires": { - "minimist": "0.0.8" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - }, "source-map": { "version": "0.7.3", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", @@ -8520,17 +8790,29 @@ "util.promisify": "~1.0.0" }, "dependencies": { - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + "css-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", + "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", + "requires": { + "boolbase": "^1.0.0", + "css-what": "^3.2.1", + "domutils": "^1.7.0", + "nth-check": "^1.0.2" + } }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "css-what": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.2.1.tgz", + "integrity": "sha512-WwOrosiQTvyms+Ti5ZC5vGEK0Vod3FTt1ca+payZqvKuGJF+dq7bG63DstxtN0dpm6FxY27a/zS3Wten+gEtGw==" + }, + "domutils": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", + "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", "requires": { - "minimist": "0.0.8" + "dom-serializer": "0", + "domelementtype": "1" } } } @@ -8541,9 +8823,9 @@ "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==" }, "terser": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/terser/-/terser-4.4.2.tgz", - "integrity": "sha512-Uufrsvhj9O1ikwgITGsZ5EZS6qPokUOkCegS7fYOdGTv+OA90vndUbU6PEjr5ePqHfNUbGyMO7xyIZv2MhsALQ==", + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.6.3.tgz", + "integrity": "sha512-Lw+ieAXmY69d09IIc/yqeBqXpEQIpDGZqT34ui1QWXIUpR2RjbqEkT8X7Lgex19hslSqcWM5iMN2kM11eMsESQ==", "requires": { "commander": "^2.20.0", "source-map": "~0.6.1", @@ -8590,6 +8872,35 @@ "requires": { "readable-stream": "~2.3.6", "xtend": "~4.0.1" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } } }, "thunky": { @@ -8621,33 +8932,6 @@ "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==", "optional": true }, - "tm-tooltip": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/tm-tooltip/-/tm-tooltip-0.0.10.tgz", - "integrity": "sha512-ud+LicFlyhwLwO/nfGvtASg3TyUCjaEQC5GCZaE/JzXQmwK0ndb+4F0/ek8xr07rOENFUIT9N+1tmUDqCAtv1g==", - "requires": { - "markdown-it": "^9.1.0" - }, - "dependencies": { - "entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" - }, - "markdown-it": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-9.1.0.tgz", - "integrity": "sha512-xHKG4C8iPriyfu/jc2hsCC045fKrMQ0VexX2F1FGYiRxDxqMB2aAhF8WauJ3fltn2kb90moGBkiiEdooGIg55w==", - "requires": { - "argparse": "^1.0.7", - "entities": "~1.1.1", - "linkify-it": "^2.0.0", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" - } - } - } - }, "to-arraybuffer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", @@ -8671,11 +8955,6 @@ "kind-of": "^3.0.2" }, "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -8948,11 +9227,6 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=" - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" } } }, @@ -9040,12 +9314,14 @@ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "util.promisify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", - "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz", + "integrity": "sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==", "requires": { - "define-properties": "^1.1.2", - "object.getownpropertydescriptors": "^2.0.3" + "define-properties": "^1.1.3", + "es-abstract": "^1.17.2", + "has-symbols": "^1.0.1", + "object.getownpropertydescriptors": "^2.1.0" } }, "utila": { @@ -9059,9 +9335,9 @@ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, "uuid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", - "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==" + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" }, "v-runtime-template": { "version": "1.10.0", @@ -9074,9 +9350,9 @@ "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" }, "vendors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.3.tgz", - "integrity": "sha512-fOi47nsJP5Wqefa43kyWSg80qF+Q3XA6MUkgi7Hp1HQaKDQW4cQrK2D0P7mmbFtsV1N89am55Yru/nyEwRubcw==" + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.4.tgz", + "integrity": "sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w==" }, "verror": { "version": "1.10.0", @@ -9121,9 +9397,9 @@ } }, "vue-router": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.1.3.tgz", - "integrity": "sha512-8iSa4mGNXBjyuSZFCCO4fiKfvzqk+mhL0lnKuGcQtO1eoj8nq3CmbEG8FwK5QqoqwDgsjsf1GDuisDX4cdb/aQ==" + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.1.5.tgz", + "integrity": "sha512-BszkPvhl7I9h334GjckCh7sVFyjTPMMJFJ4Bsrem/Ik+B/9gt5tgrk8k4gGLO4ZpdvciVdg7O41gW4DisQWurg==" }, "vue-server-renderer": { "version": "2.6.11", @@ -9238,6 +9514,15 @@ "json5": "^0.5.0", "object-assign": "^4.0.1" } + }, + "util.promisify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", + "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", + "requires": { + "define-properties": "^1.1.2", + "object.getownpropertydescriptors": "^2.0.3" + } } } }, @@ -9266,41 +9551,28 @@ } }, "vuepress-theme-cosmos": { -<<<<<<< HEAD - "version": "1.0.113", - "resolved": "https://registry.npmjs.org/vuepress-theme-cosmos/-/vuepress-theme-cosmos-1.0.113.tgz", - "integrity": "sha512-gSr9Hqp42Ursw7G9N7UG5KQMEVxEsFlPnfb5VlDo3k/s1mruSsZvXczfGEkno0U+lATGROWWU+No4xpOqMADiA==", -======= - "version": "1.0.105", - "resolved": "https://registry.npmjs.org/vuepress-theme-cosmos/-/vuepress-theme-cosmos-1.0.105.tgz", - "integrity": "sha512-UZOPEnNuz5r6cB/o75Qj81/n5BOlpDkf+lGpNxo70C1Eqqg/pjzgj3phhxzSvgXbY5bpdCyeXWySQ8zZnnYtPA==", ->>>>>>> master - "requires": { - "@cosmos-ui/vue": "^0.5.16", - "@vuepress/plugin-last-updated": "^1.2.0", - "@vuepress/plugin-search": "^1.1.0", - "algoliasearch": "^3.35.1", + "version": "1.0.146", + "resolved": "https://registry.npmjs.org/vuepress-theme-cosmos/-/vuepress-theme-cosmos-1.0.146.tgz", + "integrity": "sha512-guJcjAffvQcTBbuJarYIvt/O4IpmGKj/jHVlfooDK/NTZd/9/X1cYRSzYZbu+M+GgzV6QEjlikPAGnZI2o/MnQ==", + "requires": { + "@cosmos-ui/vue": "^0.5.20", "axios": "^0.19.0", + "cheerio": "^1.0.0-rc.3", "clipboard-copy": "^3.1.0", - "docsearch.js": "^2.6.3", + "entities": "^2.0.0", "fuse.js": "^3.4.6", "gray-matter": "^4.0.2", "hotkeys-js": "^3.7.3", - "intersection-observer": "^0.7.0", - "lunr": "^2.3.8", "markdown-it": "^10.0.0", "markdown-it-attrs": "^3.0.1", - "markdown-it-ins": "^3.0.0", "prismjs": "^1.17.1", "pug": "^2.0.4", "pug-plain-loader": "^1.0.0", "stylus": "^0.54.7", "stylus-loader": "^3.0.2", - "tm-tooltip": "0.0.10", "v-runtime-template": "^1.10.0", "vuepress": "^1.2.0", - "vuepress-plugin-sitemap": "^2.3.1", - "vuepress-plugin-smooth-scroll": "0.0.9" + "vuepress-plugin-sitemap": "^2.3.1" } }, "watchpack": { @@ -9327,9 +9599,9 @@ "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" }, "webpack": { - "version": "4.41.3", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.41.3.tgz", - "integrity": "sha512-EcNzP9jGoxpQAXq1VOoTet0ik7/VVU1MovIfcUSAjLowc7GhcQku/sOXALvq5nPpSei2HF6VRhibeJSC3i/Law==", + "version": "4.41.5", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.41.5.tgz", + "integrity": "sha512-wp0Co4vpyumnp3KlkmpM5LWuzvZYayDwM2n17EHFr4qxBBbRokC7DJawPJC7TfSFZ9HZ6GsdH40EBj4UV0nmpw==", "requires": { "@webassemblyjs/ast": "1.8.5", "@webassemblyjs/helper-module-context": "1.8.5", @@ -9360,19 +9632,6 @@ "version": "6.4.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.0.tgz", "integrity": "sha512-gac8OEcQ2Li1dxIEWGZzsp2BitJxwkwcOm0zHAJLcPJaVvm58FRnk6RkuLRpU1EujipU2ZFODv2P9DLMfnV8mw==" - }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "requires": { - "minimist": "0.0.8" - } } } }, @@ -9395,27 +9654,12 @@ "mkdirp": "^0.5.1", "range-parser": "^1.2.1", "webpack-log": "^2.0.0" - }, - "dependencies": { - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "requires": { - "minimist": "0.0.8" - } - } } }, "webpack-dev-server": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.9.0.tgz", - "integrity": "sha512-E6uQ4kRrTX9URN9s/lIbqTAztwEPdvzVrcmHE8EQ9YnuT9J8Es5Wrd8n9BKg1a0oZ5EgEke/EQFgUsp18dSTBw==", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.10.1.tgz", + "integrity": "sha512-AGG4+XrrXn4rbZUueyNrQgO4KGnol+0wm3MPdqGLmmA+NofZl3blZQKxZ9BND6RDNuvAK9OMYClhjOSnxpWRoA==", "requires": { "ansi-html": "0.0.7", "bonjour": "^3.5.0", @@ -9432,7 +9676,7 @@ "ip": "^1.1.5", "is-absolute-url": "^3.0.3", "killable": "^1.0.1", - "loglevel": "^1.6.4", + "loglevel": "^1.6.6", "opn": "^5.5.0", "p-retry": "^3.0.1", "portfinder": "^1.0.25", @@ -9513,9 +9757,9 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "p-limit": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", - "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", + "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", "requires": { "p-try": "^2.0.0" } @@ -9533,11 +9777,6 @@ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - }, "supports-color": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", diff --git a/docs/package.json b/docs/package.json index 06255f68eb6a..4189d8bd368c 100644 --- a/docs/package.json +++ b/docs/package.json @@ -19,4 +19,4 @@ "vuepress-plugin-smooth-scroll": "0.0.9", "vuepress-theme-cosmos": "^1.0.113" } -} \ No newline at end of file +} diff --git a/docs/using-the-sdk/README.md b/docs/using-the-sdk/README.md index 5254bf991ae5..747dfd500553 100644 --- a/docs/using-the-sdk/README.md +++ b/docs/using-the-sdk/README.md @@ -7,4 +7,3 @@ parent: - [Modules](../../x/README.md) - [Simulation](./simulation.md) - diff --git a/docs/using-the-sdk/simulation.md b/docs/using-the-sdk/simulation.md index 05147050933e..e8fcb8088f07 100644 --- a/docs/using-the-sdk/simulation.md +++ b/docs/using-the-sdk/simulation.md @@ -1,49 +1,65 @@ # Cosmos Blockchain Simulator -The Cosmos SDK offers a full fledged simulation framework to fuzz test every message defined by a module. +The Cosmos SDK offers a full fledged simulation framework to fuzz test every +message defined by a module. -This functionality is provided by the[`SimApp`](https://github.com/cosmos/cosmos-sdk/blob/master/simapp/app.go), -which is a dummy application that is used for running the [`simulation`](https://github.com/cosmos/cosmos-sdk/tree/master/x/simulation) module. -This module defines all the simulation logic as well as the operations for randomized parameters like accounts, balances etc. +On the SDK, this functionality is provided by the[`SimApp`](https://github.com/cosmos/cosmos-sdk/blob/master/simapp/app.go), which is a +`Baseapp` application that is used for running the [`simulation`](https://github.com/cosmos/cosmos-sdk/tree/master/x/simulation) module. +This module defines all the simulation logic as well as the operations for +randomized parameters like accounts, balances etc. ## Goals -The blockchain simulator tests how the blockchain application would behave under real life circumstances by generating and sending randomized messages. -The goal of this is to detect and debug failures that could halt a live chain, by providing logs and statistics about the operations run by the simulator as well as exporting the latest application state when a failure was found. +The blockchain simulator tests how the blockchain application would behave under +real life circumstances by generating and sending randomized messages. +The goal of this is to detect and debug failures that could halt a live chain, +by providing logs and statistics about the operations run by the simulator as +well as exporting the latest application state when a failure was found. -Its main difference with integration testing is that the simulator app allows you to pass parameters to customize the chain that's being simulated. -This comes in handy when trying to reproduce bugs that were generated in the provided operations (randomized or not). +Its main difference with integration testing is that the simulator app allows +you to pass parameters to customize the chain that's being simulated. +This comes in handy when trying to reproduce bugs that were generated in the +provided operations (randomized or not). ## Simulation commands -The simulation app has different commands, each of which tests a different failure type: +The simulation app has different commands, each of which tests a different +failure type: -- `AppImportExport`: The simulator exports the initial app state and then it creates a new app with the exported `genesis.json` as an input, checking for inconsistencies between the stores. -- `AppSimulationAfterImport`: Queues two simulations together. The first one provides the app state (_i.e_ genesis) to the second. Useful to test software upgrades or hard-forks from a live chain. -- `AppStateDeterminism`: Checks that all the nodes return the same values, in the same order. -- `BenchmarkInvariants`: Analyses the performance of running all the modules' invariants (_i.e_ secuentially runs a [benchmark](https://golang.org/pkg/testing/#hdr-Benchmarks) test). An invariant checks for differences between the values that are on the store and the passive tracker. Eg: total coins held by accounts vs total supply tracker. -- `FullAppSimulation`: General simulation mode. Runs the chain and the specified operations for a given number of blocks. Tests that there're no `panics` on the simulation. It does also run invariant checks on every `Period` but they are not benchmarked. +* `AppImportExport`: The simulator exports the initial app state and then it +creates a new app with the exported `genesis.json` as an input, checking for +inconsistencies between the stores. +* `AppSimulationAfterImport`: Queues two simulations together. The first one provides the app state (_i.e_ genesis) to the second. Useful to test software upgrades or hard-forks from a live chain. +* `AppStateDeterminism`: Checks that all the nodes return the same values, in the same order. +* `BenchmarkInvariants`: Analysis of the performance of running all modules' invariants (_i.e_ sequentially runs a [benchmark](https://golang.org/pkg/testing/#hdr-Benchmarks) test). An invariant checks for +differences between the values that are on the store and the passive tracker. Eg: total coins held by accounts vs total supply tracker. +* `FullAppSimulation`: General simulation mode. Runs the chain and the specified operations for a given number of blocks. Tests that there're no `panics` on the simulation. It does also run invariant checks on every `Period` but they are not benchmarked. -Each simulation must receive a set of inputs (_i.e_ flags) such as the number of blocks that the simulation is run, seed, block size, etc. +Each simulation must receive a set of inputs (_i.e_ flags) such as the number of +blocks that the simulation is run, seed, block size, etc. Check the full list of flags [here](https://github.com/cosmos/cosmos-sdk/blob/adf6ddd4a807c8363e33083a3281f6a5e112ab89/simapp/sim_test.go#L34-L50). ## Simulator Modes In addition to the various inputs and commands, the simulator runs in three modes: -1. Completely random where the initial state, module parameters and simulation parameters are **pseudo-randomly generated**. +1. Completely random where the initial state, module parameters and simulation +parameters are **pseudo-randomly generated**. 2. From a `genesis.json` file where the initial state and the module parameters are defined. This mode is helpful for running simulations on a known state such as a live network export where a new (mostly likely breaking) version of the application needs to be tested. 3. From a `params.json` file where the initial state is pseudo-randomly generated but the module and simulation parameters can be provided manually. -This allows for a more controlled and deterministic simulation setup while allowing the state space to still be pseudo-randomly simulated. The list of available parameters is listed [here](https://github.com/cosmos/cosmos-sdk/blob/adf6ddd4a807c8363e33083a3281f6a5e112ab89/x/simulation/params.go#L170-L178). +This allows for a more controlled and deterministic simulation setup while allowing the state space to still be pseudo-randomly simulated. +The list of available parameters are listed [here](https://github.com/cosmos/cosmos-sdk/blob/adf6ddd4a807c8363e33083a3281f6a5e112ab89/x/simulation/params.go#L170-L178). ::: tip -These modes are not mutually exclusive. So you can for example run a randomly generated genesis state (`1`) with manually generated simulation params (`3`). +These modes are not mutually exclusive. So you can for example run a randomly +generated genesis state (`1`) with manually generated simulation params (`3`). ::: ## Usage -This is a general example of how simulations are run. For more specific examples check the SDK [Makefile](https://github.com/cosmos/cosmos-sdk/blob/adf6ddd4a807c8363e33083a3281f6a5e112ab89/Makefile#L88-L123). +This is a general example of how simulations are run. For more specific examples +check the SDK [Makefile](https://github.com/cosmos/cosmos-sdk/blob/adf6ddd4a807c8363e33083a3281f6a5e112ab89/Makefile#L88-L123). ```bash $ go test -mod=readonly github.com/cosmos/cosmos-sdk/simapp \ @@ -56,15 +72,26 @@ This is a general example of how simulations are run. For more specific examples Here are some suggestions when encountering a simulation failure: -- Export the app state at the height were the failure was found. You can do this by passing the `-ExportStatePath` flag to the simulator. -- Use `-Verbose` logs. They could give you a better hint on all the operations involved. - -- Reduce the simulation `-Period`. This will run the invariants checks more frequently. -- Print all the failed invariants at once with `-PrintAllInvariants`. -- Try using another `-Seed`. If it can reproduce the same error and if it fails sooner you will spend less time running the simulations. -- Reduce the `-NumBlocks` . How's the app state at the height previous to the failure? -- Run invariants on every operation with `-SimulateEveryOperation`. _Note_: this will slow down your simulation **a lot**. -- Try adding logs to operations that are not logged. You will have to define a [Logger](https://github.com/cosmos/cosmos-sdk/blob/adf6ddd4a807c8363e33083a3281f6a5e112ab89/x/staking/keeper/keeper.go#L65:17) on your `Keeper`. - - - +* Export the app state at the height were the failure was found. You can do this +by passing the `-ExportStatePath` flag to the simulator. +* Use `-Verbose` logs. They could give you a better hint on all the operations +involved. +* Reduce the simulation `-Period`. This will run the invariants checks more +frequently. +* Print all the failed invariants at once with `-PrintAllInvariants`. +* Try using another `-Seed`. If it can reproduce the same error and if it fails +sooner you will spend less time running the simulations. +* Reduce the `-NumBlocks` . How's the app state at the height previous to the +failure? +* Run invariants on every operation with `-SimulateEveryOperation`. _Note_: this +will slow down your simulation **a lot**. +* Try adding logs to operations that are not logged. You will have to define a +[Logger](https://github.com/cosmos/cosmos-sdk/blob/adf6ddd4a807c8363e33083a3281f6a5e112ab89/x/staking/keeper/keeper.go#L65:17) on your `Keeper`. + +## Use simulation in your SDK-based application + +Learn how you can integrate the simulation into your SDK-based application: + +* Application Simulation Manager +* [Building modules: Simulator](../building-modules/simulator.md) +* Simulator tests From ce16e0a99df7d558e02420ac09bab6a9044d625e Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Fri, 31 Jan 2020 11:12:04 -0500 Subject: [PATCH 108/529] Merge PR #5597: Include Amount in Complete Unbonding/Redelegation Events --- CHANGELOG.md | 3 ++ x/staking/keeper/delegation.go | 59 +++++++++++++++++++++------- x/staking/keeper/val_state_change.go | 12 ++++-- x/staking/spec/07_events.md | 26 ++++++------ 4 files changed, 71 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1764c8d33313..fc45a176b45d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -62,6 +62,9 @@ balances or a single balance by denom when the `denom` query parameter is presen ### Improvements +* (modules) [\#5597](https://github.com/cosmos/cosmos-sdk/pull/5597) Add `amount` event attribute to the `complete_unbonding` +and `complete_redelegation` events that reflect the total balances of the completed unbondings and redelegations +respectively. * (types) [\#5581](https://github.com/cosmos/cosmos-sdk/pull/5581) Add convenience functions {,Must}Bech32ifyAddressBytes. * (staking) [\#5584](https://github.com/cosmos/cosmos-sdk/pull/5584) Add util function `ToTmValidator` that converts a `staking.Validator` type to `*tmtypes.Validator`. * (client) [\#5585](https://github.com/cosmos/cosmos-sdk/pull/5585) IBC additions: diff --git a/x/staking/keeper/delegation.go b/x/staking/keeper/delegation.go index faf8ba415ef7..219beef71271 100644 --- a/x/staking/keeper/delegation.go +++ b/x/staking/keeper/delegation.go @@ -660,14 +660,17 @@ func (k Keeper) Undelegate( return completionTime, nil } -// CompleteUnbonding completes the unbonding of all mature entries in the -// retrieved unbonding delegation object. -func (k Keeper) CompleteUnbonding(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) error { +// CompleteUnbondingWithAmount completes the unbonding of all mature entries in +// the retrieved unbonding delegation object and returns the total unbonding +// balance or an error upon failure. +func (k Keeper) CompleteUnbondingWithAmount(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) (sdk.Coins, error) { ubd, found := k.GetUnbondingDelegation(ctx, delAddr, valAddr) if !found { - return types.ErrNoUnbondingDelegation + return nil, types.ErrNoUnbondingDelegation } + bondDenom := k.GetParams(ctx).BondDenom + balances := sdk.NewCoins() ctxTime := ctx.BlockHeader().Time // loop through all the entries and complete unbonding mature entries @@ -679,11 +682,15 @@ func (k Keeper) CompleteUnbonding(ctx sdk.Context, delAddr sdk.AccAddress, valAd // track undelegation only when remaining or truncated shares are non-zero if !entry.Balance.IsZero() { - amt := sdk.NewCoins(sdk.NewCoin(k.GetParams(ctx).BondDenom, entry.Balance)) - err := k.supplyKeeper.UndelegateCoinsFromModuleToAccount(ctx, types.NotBondedPoolName, ubd.DelegatorAddress, amt) + amt := sdk.NewCoin(bondDenom, entry.Balance) + err := k.supplyKeeper.UndelegateCoinsFromModuleToAccount( + ctx, types.NotBondedPoolName, ubd.DelegatorAddress, sdk.NewCoins(amt), + ) if err != nil { - return err + return nil, err } + + balances = balances.Add(amt) } } } @@ -695,7 +702,14 @@ func (k Keeper) CompleteUnbonding(ctx sdk.Context, delAddr sdk.AccAddress, valAd k.SetUnbondingDelegation(ctx, ubd) } - return nil + return balances, nil +} + +// CompleteUnbonding performs the same logic as CompleteUnbondingWithAmount except +// it does not return the total unbonding amount. +func (k Keeper) CompleteUnbonding(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) error { + _, err := k.CompleteUnbondingWithAmount(ctx, delAddr, valAddr) + return err } // begin unbonding / redelegation; create a redelegation record @@ -755,17 +769,20 @@ func (k Keeper) BeginRedelegation( return completionTime, nil } -// CompleteRedelegation completes the unbonding of all mature entries in the -// retrieved unbonding delegation object. -func (k Keeper) CompleteRedelegation( +// CompleteRedelegationWithAmount completes the redelegations of all mature entries in the +// retrieved redelegation object and returns the total redelegation (initial) +// balance or an error upon failure. +func (k Keeper) CompleteRedelegationWithAmount( ctx sdk.Context, delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress, -) error { +) (sdk.Coins, error) { red, found := k.GetRedelegation(ctx, delAddr, valSrcAddr, valDstAddr) if !found { - return types.ErrNoRedelegation + return nil, types.ErrNoRedelegation } + bondDenom := k.GetParams(ctx).BondDenom + balances := sdk.NewCoins() ctxTime := ctx.BlockHeader().Time // loop through all the entries and complete mature redelegation entries @@ -774,6 +791,10 @@ func (k Keeper) CompleteRedelegation( if entry.IsMature(ctxTime) { red.RemoveEntry(int64(i)) i-- + + if !entry.InitialBalance.IsZero() { + balances = balances.Add(sdk.NewCoin(bondDenom, entry.InitialBalance)) + } } } @@ -784,7 +805,17 @@ func (k Keeper) CompleteRedelegation( k.SetRedelegation(ctx, red) } - return nil + return balances, nil +} + +// CompleteRedelegation performs the same logic as CompleteRedelegationWithAmount +// except it does not return the total redelegation amount. +func (k Keeper) CompleteRedelegation( + ctx sdk.Context, delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress, +) error { + + _, err := k.CompleteRedelegationWithAmount(ctx, delAddr, valSrcAddr, valDstAddr) + return err } // ValidateUnbondAmount validates that a given unbond or redelegation amount is diff --git a/x/staking/keeper/val_state_change.go b/x/staking/keeper/val_state_change.go index ed630f15ce22..101bc139215a 100644 --- a/x/staking/keeper/val_state_change.go +++ b/x/staking/keeper/val_state_change.go @@ -31,7 +31,7 @@ func (k Keeper) BlockValidatorUpdates(ctx sdk.Context) []abci.ValidatorUpdate { // Remove all mature unbonding delegations from the ubd queue. matureUnbonds := k.DequeueAllMatureUBDQueue(ctx, ctx.BlockHeader().Time) for _, dvPair := range matureUnbonds { - err := k.CompleteUnbonding(ctx, dvPair.DelegatorAddress, dvPair.ValidatorAddress) + balances, err := k.CompleteUnbondingWithAmount(ctx, dvPair.DelegatorAddress, dvPair.ValidatorAddress) if err != nil { continue } @@ -39,6 +39,7 @@ func (k Keeper) BlockValidatorUpdates(ctx sdk.Context) []abci.ValidatorUpdate { ctx.EventManager().EmitEvent( sdk.NewEvent( types.EventTypeCompleteUnbonding, + sdk.NewAttribute(sdk.AttributeKeyAmount, balances.String()), sdk.NewAttribute(types.AttributeKeyValidator, dvPair.ValidatorAddress.String()), sdk.NewAttribute(types.AttributeKeyDelegator, dvPair.DelegatorAddress.String()), ), @@ -48,8 +49,12 @@ func (k Keeper) BlockValidatorUpdates(ctx sdk.Context) []abci.ValidatorUpdate { // Remove all mature redelegations from the red queue. matureRedelegations := k.DequeueAllMatureRedelegationQueue(ctx, ctx.BlockHeader().Time) for _, dvvTriplet := range matureRedelegations { - err := k.CompleteRedelegation(ctx, dvvTriplet.DelegatorAddress, - dvvTriplet.ValidatorSrcAddress, dvvTriplet.ValidatorDstAddress) + balances, err := k.CompleteRedelegationWithAmount( + ctx, + dvvTriplet.DelegatorAddress, + dvvTriplet.ValidatorSrcAddress, + dvvTriplet.ValidatorDstAddress, + ) if err != nil { continue } @@ -57,6 +62,7 @@ func (k Keeper) BlockValidatorUpdates(ctx sdk.Context) []abci.ValidatorUpdate { ctx.EventManager().EmitEvent( sdk.NewEvent( types.EventTypeCompleteRedelegation, + sdk.NewAttribute(sdk.AttributeKeyAmount, balances.String()), sdk.NewAttribute(types.AttributeKeyDelegator, dvvTriplet.DelegatorAddress.String()), sdk.NewAttribute(types.AttributeKeySrcValidator, dvvTriplet.ValidatorSrcAddress.String()), sdk.NewAttribute(types.AttributeKeyDstValidator, dvvTriplet.ValidatorDstAddress.String()), diff --git a/x/staking/spec/07_events.md b/x/staking/spec/07_events.md index e16cf009570d..fe716baf9180 100644 --- a/x/staking/spec/07_events.md +++ b/x/staking/spec/07_events.md @@ -8,20 +8,22 @@ The staking module emits the following events: ## EndBlocker -| Type | Attribute Key | Attribute Value | -|-----------------------|-----------------------|-----------------------| -| complete_unbonding | validator | {validatorAddress} | -| complete_unbonding | delegator | {delegatorAddress} | -| complete_redelegation | source_validator | {srcValidatorAddress} | -| complete_redelegation | destination_validator | {dstValidatorAddress} | -| complete_redelegation | delegator | {delegatorAddress} | +| Type | Attribute Key | Attribute Value | +| --------------------- | --------------------- | ------------------------- | +| complete_unbonding | amount | {totalUnbondingAmount} | +| complete_unbonding | validator | {validatorAddress} | +| complete_unbonding | delegator | {delegatorAddress} | +| complete_redelegation | amount | {totalRedelegationAmount} | +| complete_redelegation | source_validator | {srcValidatorAddress} | +| complete_redelegation | destination_validator | {dstValidatorAddress} | +| complete_redelegation | delegator | {delegatorAddress} | ## Handlers ### MsgCreateValidator | Type | Attribute Key | Attribute Value | -|------------------|---------------|--------------------| +| ---------------- | ------------- | ------------------ | | create_validator | validator | {validatorAddress} | | create_validator | amount | {delegationAmount} | | message | module | staking | @@ -31,7 +33,7 @@ The staking module emits the following events: ### MsgEditValidator | Type | Attribute Key | Attribute Value | -|----------------|---------------------|---------------------| +| -------------- | ------------------- | ------------------- | | edit_validator | commission_rate | {commissionRate} | | edit_validator | min_self_delegation | {minSelfDelegation} | | message | module | staking | @@ -41,7 +43,7 @@ The staking module emits the following events: ### MsgDelegate | Type | Attribute Key | Attribute Value | -|----------|---------------|--------------------| +| -------- | ------------- | ------------------ | | delegate | validator | {validatorAddress} | | delegate | amount | {delegationAmount} | | message | module | staking | @@ -51,7 +53,7 @@ The staking module emits the following events: ### MsgUndelegate | Type | Attribute Key | Attribute Value | -|---------|---------------------|--------------------| +| ------- | ------------------- | ------------------ | | unbond | validator | {validatorAddress} | | unbond | amount | {unbondAmount} | | unbond | completion_time [0] | {completionTime} | @@ -64,7 +66,7 @@ The staking module emits the following events: ### MsgBeginRedelegate | Type | Attribute Key | Attribute Value | -|------------|-----------------------|-----------------------| +| ---------- | --------------------- | --------------------- | | redelegate | source_validator | {srcValidatorAddress} | | redelegate | destination_validator | {dstValidatorAddress} | | redelegate | amount | {unbondAmount} | From 43137ee893cefbdb2aacd25ef4ec39eacf6ae70c Mon Sep 17 00:00:00 2001 From: Mircea Colonescu Date: Mon, 3 Feb 2020 09:28:32 -0500 Subject: [PATCH 109/529] Merge PR #5605: Update swagger.yaml --- client/lcd/swagger-ui/swagger.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/lcd/swagger-ui/swagger.yaml b/client/lcd/swagger-ui/swagger.yaml index 23298942e0d3..c802f42a8e92 100644 --- a/client/lcd/swagger-ui/swagger.yaml +++ b/client/lcd/swagger-ui/swagger.yaml @@ -30,7 +30,7 @@ tags: description: Query app version schemes: - https -host: stargate.cosmos.network +host: api.cosmos.network securityDefinitions: kms: type: basic @@ -40,7 +40,7 @@ paths: description: Information about the connected node summary: The properties of the connected node tags: - - Tendermint RPC + - Gaia REST produces: - application/json responses: From 22ba931ec6b502405b918549cea3e13eb3559084 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Tue, 4 Feb 2020 10:07:39 -0500 Subject: [PATCH 110/529] Merge PR #5611: Add missing aliases --- x/bank/alias.go | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/x/bank/alias.go b/x/bank/alias.go index 2fdfa6602b82..faa59aa3fd98 100644 --- a/x/bank/alias.go +++ b/x/bank/alias.go @@ -39,6 +39,7 @@ var ( DefaultGenesisState = types.DefaultGenesisState ValidateGenesis = types.ValidateGenesis SanitizeGenesisBalances = types.SanitizeGenesisBalances + GetGenesisStateFromAppState = types.GetGenesisStateFromAppState NewMsgSend = types.NewMsgSend NewMsgMultiSend = types.NewMsgMultiSend NewInput = types.NewInput @@ -54,18 +55,19 @@ var ( ) type ( - Keeper = keeper.Keeper - BaseKeeper = keeper.BaseKeeper - SendKeeper = keeper.SendKeeper - BaseSendKeeper = keeper.BaseSendKeeper - ViewKeeper = keeper.ViewKeeper - BaseViewKeeper = keeper.BaseViewKeeper - GenesisState = types.GenesisState - Balance = types.Balance - MsgSend = types.MsgSend - MsgMultiSend = types.MsgMultiSend - Input = types.Input - Output = types.Output - QueryBalanceParams = types.QueryBalanceParams - QueryAllBalancesParams = types.QueryAllBalancesParams + Keeper = keeper.Keeper + BaseKeeper = keeper.BaseKeeper + SendKeeper = keeper.SendKeeper + BaseSendKeeper = keeper.BaseSendKeeper + ViewKeeper = keeper.ViewKeeper + BaseViewKeeper = keeper.BaseViewKeeper + GenesisState = types.GenesisState + Balance = types.Balance + MsgSend = types.MsgSend + MsgMultiSend = types.MsgMultiSend + Input = types.Input + Output = types.Output + QueryBalanceParams = types.QueryBalanceParams + QueryAllBalancesParams = types.QueryAllBalancesParams + GenesisBalancesIterator = types.GenesisBalancesIterator ) From 5412725b355539a5c944c109d3ab68f952e05e61 Mon Sep 17 00:00:00 2001 From: Sunny Aggarwal Date: Tue, 4 Feb 2020 11:23:49 -0500 Subject: [PATCH 111/529] Merge PR #5459: ADR 18: Extendable Governance Voting Periods --- docs/architecture/README.md | 1 + .../adr-018-extendable-voting-period.md | 66 +++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 docs/architecture/adr-018-extendable-voting-period.md diff --git a/docs/architecture/README.md b/docs/architecture/README.md index e882cb90cab2..afa60a75241a 100644 --- a/docs/architecture/README.md +++ b/docs/architecture/README.md @@ -42,3 +42,4 @@ Please add a entry below in your Pull Request for an ADR. - [ADR 015: IBC Packet Receiver](./adr-015-ibc-packet-receiver.md) - [ADR 016: Validator Consensus Key Rotation](./adr-016-validator-consensus-key-rotation.md) - [ADR 017: Historical Header Module](./adr-017-historical-header-module.md) +- [ADR 018: Extendable Voting Periods](./adr-018-extendable-voting-period.md) diff --git a/docs/architecture/adr-018-extendable-voting-period.md b/docs/architecture/adr-018-extendable-voting-period.md new file mode 100644 index 000000000000..fdf5bb2584e2 --- /dev/null +++ b/docs/architecture/adr-018-extendable-voting-period.md @@ -0,0 +1,66 @@ +# ADR 18: Extendable Voting Periods + +## Changelog + +- 1 January 2020: Start of first version + +## Context + +Currently the voting period for all governance proposals is the same. However, this is suboptimal as all governance proposals do not require the same time period. For more non-contentious proposals, they can be dealt with more efficently with a faster period, while more contentious or complex proposals may need a longer period for extended discussion/consideration. + +## Decision + +We would like to design a mechanism for making the voting period of a governance proposal variable based on the demand of voters. We would like it to be based on the view of the governance participants, rather than just the proposer of a governance proposal (thus, allowing the proposer to select the voting period length is not sufficient). + +However, we would like to avoid the creation of an entire second voting process to determine the length of the voting period, as it just pushed the problem to determining the length of that first voting period. + +Thus, we propose the following mechanism: + +### Params: + +- The current gov param `VotingPeriod` is to be replaced by a `MinVotingPeriod` param. This is the the default voting period that all governance proposal voting periods start with. +- There is a new gov param called `MaxVotingPeriodExtension`. + +### Mechanism + +There is a new `Msg` type called `MsgExtendVotingPeriod`, which can be sent by any staked account during a proposal's voting period. It allows the sender to unilaterally extend the length of the voting period by `MaxVotingPeriodExtension * sender's share of voting power`. Every address can only call `MsgExtendVotingPeriod` once per proposal. + +So for example, if the `MaxVotingPeriodExtension` is set to 100 Days, then anyone with 1% of voting power can extend the voting power by 1 day. If 33% of voting power has sent the message, the voting period will be extended by 33 days. Thus, if absolutely everyone chooses to extend the voting period, the absolute maximum voting period will be `MinVotingPeriod + MaxVotingPeriodExtension`. + +This system acts as a sort of distributed coordination, where individual stakers choosing to extend or not, allows the system the guage the conentiousness/complexity of the proposal. It is extremely unlikely that many stakers will choose to extend at the exact same time, it allows stakers to view how long others have already extended thus far, to decide whether or not to extend further. + +### Dealing with Unbonding/Redelegation + +There is one thing that needs to be addressed. How to deal with redelegation/unbonding during the voting period. If a staker of 5% calls `MsgExtendVotingPeriod` and then unbonds, does the voting period then decrease by 5 days again? This is not good as it can give people a false sense of how long they have to make their decision. For this reason, we want to design it such that the voting period length can only be extended, not shortened. To do this, the current extension amount is based on the highest percent that voted extension at any time. This is best explained by example: + +1. Let's say 2 stakers of voting power 4% and 3% respectively vote to extend. The voting period will be extended by 7 days. +2. Now the staker of 3% decides to unbond before the end of the voting period. The voting period extension remains 7 days. +3. Now, let's say another staker of 2% voting power decides to extend voting period. There is now 6% of active voting power choosing the extend. The voting power remains 7 days. +4. If a fourth staker of 10% chooses to extend now, there is a total of 16% of active voting power wishing to extend. The voting period will be extended to 16 days. + +### Delegators + +Just like votes in the actual voting period, delegators automatically inherit the extension of their validators. If their validator chooses to extend, their voting power will be used in the validator's extension. However, the delegator is unable to override their validator and "unextend" as that would contradict the "voting power length can only be ratcheted up" principle described in the previous section. However, a delegator may choose the extend using their personal voting power, if their validator has not done so. + +## Status + +Proposed + +## Consequences + +### Positive + +- More complex/contentious governance proposals will have more time to properly digest and deliberate + +### Negative + +- Governance process becomes more complex and requires more understanding to interact with effectively +- Can no longer predict when a governance proposal will end. Can't assume order in which governance proposals will end. + +### Neutral + +- The minimum voting period can be made shorter + +## References + +- [Cosmos Forum post where idea first originated](https://forum.cosmos.network/t/proposal-draft-reduce-governance-voting-period-to-7-days/3032/9) From e1517e7a1daba5f7ebe0e8601d49ff6805555849 Mon Sep 17 00:00:00 2001 From: Marko Date: Tue, 4 Feb 2020 19:16:56 +0100 Subject: [PATCH 112/529] Merge PR #5604: docs: minor doc formatting & touchup of the scaffold section --- docs/using-the-sdk/quick-start.md | 78 ++++++----------- x/gov/spec/01_concepts.md | 137 +++++++++++++++--------------- x/gov/spec/02_state.md | 22 ++--- x/gov/spec/03_messages.md | 32 +++---- x/gov/spec/04_events.md | 12 +-- 5 files changed, 131 insertions(+), 150 deletions(-) diff --git a/docs/using-the-sdk/quick-start.md b/docs/using-the-sdk/quick-start.md index 4b2bf548b2e4..09cbcd9c8966 100644 --- a/docs/using-the-sdk/quick-start.md +++ b/docs/using-the-sdk/quick-start.md @@ -1,16 +1,16 @@ # Quick Start -This guide serves as a practical introduction to building blockchains with the Cosmos SDK. It shows how to scaffold the code for a basic blockchain node, build and run it. Several important concepts of the Cosmos SDK are introduced along the way. +This guide serves as a practical introduction to building blockchains with the Cosmos SDK. It shows how to scaffold the code for a basic blockchain node, build and run it. Several important concepts of the Cosmos SDK are introduced along the way. ## Setup ::: tip -To follow this guide, you need to [install golang](https://golang.org/doc/install) and set [your $GOPATH environment variable](https://golang.org/doc/code.html#GOPATH) +To follow this guide, you need to [install golang](https://golang.org/doc/install) and set [your \$GOPATH environment variable](https://golang.org/doc/code.html#GOPATH) ::: ::: warning Make sure you are using the latest stable version of golang available on https://golang.org/dl/ -::: +::: First, download the [`scaffold`](https://github.com/cosmos/scaffold) tool: @@ -30,50 +30,27 @@ make To create a basic Cosmos SDK application, simply type in the following command: ```bash -scaffold app lvl-1 +scaffold app ``` -where `username|org` is the name of your github/gitlab/atlassian username or organisation, and `repo` the name of the distant repository you would push your application too. These arguments are used to configure the imports so that people can easily download and install your application once (if) you upload it. - -The command above creates a starter application in a new folder named after the `repo` argument. This application contains the [basic logic most SDK applications](../intro/sdk-app-architecture.md) need as well as a set of standard [modules](../building-modules/intro.md) already hooked up. These include: - -- [`auth`](../../x/auth/spec/): Accounts, signatures and fees. -- [`bank`](../../x/bank/spec/): Token transfers. -- [`staking`](../../x/staking/spec/): Proof-of-Stake logic, which is a way of managing validator set changes in public decentralised networks. Also includes delegation logic. -- [`slashing`](../../x/slashing/spec/): Slash validators that misebehave. Complementary to the `staking` module. -- [`distribution`](../../x/distribution/spec/): Distribution of rewards and fees earned by participants in the Proof-of-Stake system (delegators and validators). -- [`params`](../../x/params/spec/): Global parameter store of the application. -- [`supply`](../../x/supply/spec/): Handles global token supply of the application. Enables modules to hold tokens. -- [`genutil`](../../x/genutil) and [`genaccounts`](../../x/genaccounts): Utility modules to facilitate creation of genesis file. +There are multiple levels of apps to choose from, they can be found [here](https://github.com/cosmos/scaffold/blob/master/docs/app.md). -Now, go into the application's folder. The structure should look like the following: +where `username|org` is the name of your github/gitlab/atlassian username or organisation, and `repo` the name of the distant repository you would push your application too. These arguments are used to configure the imports so that people can easily download and install your application once (if) you upload it. -``` -├── app/ -│   ├── app.go -│   └── export.go -├── cmd/ -│ ├── acli/ -│ │ └── main.go -│   ├── aud/ -│ │ └── main.go -├── Makefile -├── go.mod -└── x/ -``` +The command above creates a starter application in a new folder named after the `repo` argument. This application contains the [basic logic most SDK applications](../intro/sdk-app-architecture.md) need as well as a set of standard [modules](../building-modules/intro.md) already hooked up. You can find which level consists of which modules [here](https://github.com/cosmos/scaffold/blob/master/docs/app.md) -where: +The structure of the generated app will look like similar to the [recommended folder structure](../building-modules/structure.md). Below you will find a simple break down of some of the files. -- `app.go` is the [main file](../basics/app-anatomy.md#core-application-file) defining the application logic. This is where the state is intantiated and modules are declared. This is also where the Cosmos SDK is imported as a dependency to help build the application. -- `export.go` is a helper file used to export the state of the application into a new genesis file. It is helpful when you want to upgrade your chain to a new (breaking) version. -- `acli/main.go` builds the command-line interface for your blockchain application. It enables end-users to create transactions and query the chain for information. -- `aud/main.go` builds the main [daemon client](../basics/app-anatomy.md#node-client) of the chain. It is used to run a full-node that will connect to peers and sync its local application state with the latest state of the network. -- `go.mod` helps manage dependencies. The two main dependencies used are the Cosmos SDK to help build the application, and Tendermint to replicate it. -- `x/` is the folder to place all the custom modules built specifically for the application. In general, most of the modules used in an application have already been built by third-party developers and only need to be imported in `app.go`. These modules do not need to be cloned into the application's `x/` folder. This is why the basic application shown above, which uses several modules, works despite having an empty `x/` folder. +- `app.go` is the [main file](../basics/app-anatomy.md#core-application-file) defining the application logic. This is where the state is instantiated and modules are declared. This is also where the Cosmos SDK is imported as a dependency to help build the application. +- `export.go` is a helper file used to export the state of the application into a new genesis file. It is helpful when you want to upgrade your chain to a new (breaking) version. +- `acli/main.go` builds the command-line interface for your blockchain application. It enables end-users to create transactions and query the chain for information. +- `aud/main.go` builds the main [daemon client](../basics/app-anatomy.md#node-client) of the chain. It is used to run a full-node that will connect to peers and sync its local application state with the latest state of the network. +- `go.mod` helps manage dependencies. The two main dependencies used are the Cosmos SDK to help build the application, and Tendermint to replicate it. +- `x/` is the folder to place all the custom modules built specifically for the application. In general, most of the modules used in an application have already been built by third-party developers and only need to be imported in `app.go`. These modules do not need to be cloned into the application's `x/` folder. This is why the basic application shown above, which uses several modules, works despite having an empty `x/` folder. ## Run your Blockchain -First, install the two main entrypoints of your blockchain, `aud` and `acli`: +First, install the two main entry points of your blockchain, `aud` and `acli`: ```bash go mod tidy @@ -93,17 +70,17 @@ Now that you have your daemon client `aud` and your command-line interface `acli aud init --chain-id test ``` -The command above creates all the configuration files needed for your node to run, as well as a default genesis file, which defines the initial state of the network. Before starting the chain, you need to populate the state with at least one account. To do so, first create a new [account](../basics/accounts.md) named `validator` (feel free to choose another name): +The command above creates all the configuration files needed for your node to run, as well as a default genesis file, which defines the initial state of the network. Before starting the chain, you need to populate the state with at least one account. To do so, first create a new [account](../basics/accounts.md) named `validator` (feel free to choose another name): ```bash acli keys add validator -``` +``` Now that you have created a local account, go ahead and grant it `stake` tokens in your chain's genesis file. Doing so will also make sure your chain is aware of this account's existence: ```bash aud add-genesis-account $(acli keys show validator -a) 100000000stake -``` +``` Now that your account has some tokens, you need to add a validator to your chain. Validators are special full-nodes that participate in the consensus process (implemented in the [underlying consensus engine](../intro/sdk-app-architecture.md#tendermint)) in order to add new blocks to the chain. Any account can declare its intention to become a validator operator, but only those with sufficient delegation get to enter the active set (for example, only the top 125 validator candidates with the most delegation get to be validators in the Cosmos Hub). For this guide, you will add your local node (created via the `init` command above) as a validator of your chain. Validators can be declared before a chain is first started via a special transaction included in the genesis file called a `gentx`: @@ -115,11 +92,11 @@ aud gentx --name validator --amount 100000stake aud collect-gentxs ``` -A `gentx` does three things: +A `gentx` does three things: 1. Makes the `validator` account you created into a validator operator account (i.e. the account that controls the validator). - 2. Self-delegates the provided `amount` of staking tokens. - 3. Link the operator account with a Tendermint node pubkey that will be used for signing blocks. If no `--pubkey` flag is provided, it defaults to the local node pubkey created via the `aud init` command above. + 2. Self-delegates the provided `amount` of staking tokens. + 3. Link the operator account with a Tendermint node pubkey that will be used for signing blocks. If no `--pubkey` flag is provided, it defaults to the local node pubkey created via the `aud init` command above. For more on `gentx`, use the following command: @@ -127,13 +104,13 @@ For more on `gentx`, use the following command: aud gentx --help ``` -Now that everyting is set up, you can finally start your node: +Now that everything is set up, you can finally start your node: ```bash aud start ``` -You should see blocks come in. +You should see blocks come in. ## Send Tokens and Increase Delegation @@ -149,7 +126,7 @@ You should see the current balance of the account you created, equal to the orig acli keys add receiver ``` -The command above creates a local key-pair that is not yet registered on the chain. An account is registered the first time it receives tokens from another account. Now, run the following command to send tokens to the second account: +The command above creates a local key-pair that is not yet registered on the chain. An account is registered the first time it receives tokens from another account. Now, run the following command to send tokens to the second account: ```bash acli tx send $(acli keys show validator -a) $(acli keys show receiver -a) 1000stake --chain-id test @@ -165,7 +142,7 @@ Finally, delegate some of the stake tokens sent to the `receiver` account to the ```bash acli tx staking delegate $(acli keys show validator --bech val -a) 500stake --from receiver --chain-id test -``` +``` Try to query the total delegations to `validator`: @@ -173,12 +150,11 @@ Try to query the total delegations to `validator`: acli query staking delegations-to $(acli keys show validator --bech val -a) --chain-id test ``` -You should see two delegations, the first one made from the `gentx`, and the second one you just performed from the `receiver` account. +You should see two delegations, the first one made from the `gentx`, and the second one you just performed from the `receiver` account. ## Next Congratulations on making it to the end of this short introduction guide! If you want to learn more, check out the following resources: - [How to build a full SDK application from scratch](https://tutorials.cosmos.network/nameservice/tutorial/00-intro.html). -- [Read the Cosmos SDK Documentation](../intro/overview.md). - +- [Read the Cosmos SDK Documentation](../intro/overview.md). diff --git a/x/gov/spec/01_concepts.md b/x/gov/spec/01_concepts.md index deed64b36c95..bc9de294016c 100644 --- a/x/gov/spec/01_concepts.md +++ b/x/gov/spec/01_concepts.md @@ -4,41 +4,42 @@ order: 1 # Concepts -*Disclaimer: This is work in progress. Mechanisms are susceptible to change.* +_Disclaimer: This is work in progress. Mechanisms are susceptible to change._ The governance process is divided in a few steps that are outlined below: -* **Proposal submission:** Proposal is submitted to the blockchain with a +- **Proposal submission:** Proposal is submitted to the blockchain with a deposit. -* **Vote:** Once deposit reaches a certain value (`MinDeposit`), proposal is - confirmed and vote opens. Bonded Atom holders can then send `TxGovVote` +- **Vote:** Once deposit reaches a certain value (`MinDeposit`), proposal is + confirmed and vote opens. Bonded Atom holders can then send `TxGovVote` transactions to vote on the proposal. -* If the proposal involves a software upgrade: - * **Signal:** Validators start signaling that they are ready to switch to the +- If the proposal involves a software upgrade: + - **Signal:** Validators start signaling that they are ready to switch to the new version. - * **Switch:** Once more than 75% of validators have signaled that they are + - **Switch:** Once more than 75% of validators have signaled that they are ready to switch, their software automatically flips to the new version. ## Proposal submission ### Right to submit a proposal -Any Atom holder, whether bonded or unbonded, can submit proposals by sending a -`TxGovProposal` transaction. Once a proposal is submitted, it is identified by +Any Atom holder, whether bonded or unbonded, can submit proposals by sending a +`TxGovProposal` transaction. Once a proposal is submitted, it is identified by its unique `proposalID`. ### Proposal types -In the initial version of the governance module, there are two types of +In the initial version of the governance module, there are two types of proposal: -* `PlainTextProposal` All the proposals that do not involve a modification of - the source code go under this type. For example, an opinion poll would use a + +- `PlainTextProposal` All the proposals that do not involve a modification of + the source code go under this type. For example, an opinion poll would use a proposal of type `PlainTextProposal`. -* `SoftwareUpgradeProposal`. If accepted, validators are expected to update - their software in accordance with the proposal. They must do so by following - a 2-steps process described in the [Software Upgrade](#software-upgrade) - section below. Software upgrade roadmap may be discussed and agreed on via - `PlainTextProposals`, but actual software upgrades must be performed via +- `SoftwareUpgradeProposal`. If accepted, validators are expected to update + their software in accordance with the proposal. They must do so by following + a 2-steps process described in the [Software Upgrade](#software-upgrade) + section below. Software upgrade roadmap may be discussed and agreed on via + `PlainTextProposals`, but actual software upgrades must be performed via `SoftwareUpgradeProposals`. Other modules may expand upon the governance module by implementing their own @@ -59,85 +60,87 @@ Once the proposal's deposit reaches `MinDeposit`, it enters voting period. If pr When a the a proposal finalized, the coins from the deposit are either refunded or burned, according to the final tally of the proposal: -* If the proposal is approved or if it's rejected but _not_ vetoed, deposits will automatically be refunded to their respective depositor (transferred from the governance `ModuleAccount`). -* When the proposal is vetoed with a supermajority, deposits be burned from the governance `ModuleAccount`. +- If the proposal is approved or if it's rejected but _not_ vetoed, deposits will automatically be refunded to their respective depositor (transferred from the governance `ModuleAccount`). +- When the proposal is vetoed with a supermajority, deposits be burned from the governance `ModuleAccount`. ## Vote ### Participants -*Participants* are users that have the right to vote on proposals. On the -Cosmos Hub, participants are bonded Atom holders. Unbonded Atom holders and -other users do not get the right to participate in governance. However, they +_Participants_ are users that have the right to vote on proposals. On the +Cosmos Hub, participants are bonded Atom holders. Unbonded Atom holders and +other users do not get the right to participate in governance. However, they can submit and deposit on proposals. -Note that some *participants* can be forbidden to vote on a proposal under a +Note that some _participants_ can be forbidden to vote on a proposal under a certain validator if: -* *participant* bonded or unbonded Atoms to said validator after proposal + +- _participant_ bonded or unbonded Atoms to said validator after proposal entered voting period. -* *participant* became validator after proposal entered voting period. +- _participant_ became validator after proposal entered voting period. -This does not prevent *participant* to vote with Atoms bonded to other -validators. For example, if a *participant* bonded some Atoms to validator A -before a proposal entered voting period and other Atoms to validator B after -proposal entered voting period, only the vote under validator B will be +This does not prevent _participant_ to vote with Atoms bonded to other +validators. For example, if a _participant_ bonded some Atoms to validator A +before a proposal entered voting period and other Atoms to validator B after +proposal entered voting period, only the vote under validator B will be forbidden. ### Voting period Once a proposal reaches `MinDeposit`, it immediately enters `Voting period`. We define `Voting period` as the interval between the moment the vote opens and -the moment the vote closes. `Voting period` should always be shorter than -`Unbonding period` to prevent double voting. The initial value of +the moment the vote closes. `Voting period` should always be shorter than +`Unbonding period` to prevent double voting. The initial value of `Voting period` is 2 weeks. ### Option set -The option set of a proposal refers to the set of choices a participant can +The option set of a proposal refers to the set of choices a participant can choose from when casting its vote. -The initial option set includes the following options: +The initial option set includes the following options: + - `Yes` - `No` -- `NoWithVeto` -- `Abstain` +- `NoWithVeto` +- `Abstain` -`NoWithVeto` counts as `No` but also adds a `Veto` vote. `Abstain` option +`NoWithVeto` counts as `No` but also adds a `Veto` vote. `Abstain` option allows voters to signal that they do not intend to vote in favor or against the -proposal but accept the result of the vote. +proposal but accept the result of the vote. -*Note: from the UI, for urgent proposals we should maybe add a ‘Not Urgent’ -option that casts a `NoWithVeto` vote.* +_Note: from the UI, for urgent proposals we should maybe add a ‘Not Urgent’ +option that casts a `NoWithVeto` vote._ -### Quorum +### Quorum -Quorum is defined as the minimum percentage of voting power that needs to be -casted on a proposal for the result to be valid. +Quorum is defined as the minimum percentage of voting power that needs to be +casted on a proposal for the result to be valid. ### Threshold -Threshold is defined as the minimum proportion of `Yes` votes (excluding +Threshold is defined as the minimum proportion of `Yes` votes (excluding `Abstain` votes) for the proposal to be accepted. Initially, the threshold is set at 50% with a possibility to veto if more than -1/3rd of votes (excluding `Abstain` votes) are `NoWithVeto` votes. This means -that proposals are accepted if the proportion of `Yes` votes (excluding -`Abstain` votes) at the end of the voting period is superior to 50% and if the -proportion of `NoWithVeto` votes is inferior to 1/3 (excluding `Abstain` +1/3rd of votes (excluding `Abstain` votes) are `NoWithVeto` votes. This means +that proposals are accepted if the proportion of `Yes` votes (excluding +`Abstain` votes) at the end of the voting period is superior to 50% and if the +proportion of `NoWithVeto` votes is inferior to 1/3 (excluding `Abstain` votes). -Proposals can be accepted before the end of the voting period if they meet a special condition. Namely, if the ratio of `Yes` votes to `InitTotalVotingPower`exceeds 2:3, the proposal will be immediately accepted, even if the `Voting period` is not finished. `InitTotalVotingPower` is the total voting power of all bonded Atom holders at the moment when the vote opens. +Proposals can be accepted before the end of the voting period if they meet a special condition. Namely, if the ratio of `Yes` votes to `InitTotalVotingPower`exceeds 2:3, the proposal will be immediately accepted, even if the `Voting period` is not finished. `InitTotalVotingPower` is the total voting power of all bonded Atom holders at the moment when the vote opens. This condition exists so that the network can react quickly in case of urgency. ### Inheritance If a delegator does not vote, it will inherit its validator vote. -* If the delegator votes before its validator, it will not inherit from the +- If the delegator votes before its validator, it will not inherit from the validator's vote. -* If the delegator votes after its validator, it will override its validator - vote with its own. If the proposal is urgent, it is possible - that the vote will close before delegators have a chance to react and +- If the delegator votes after its validator, it will override its validator + vote with its own. If the proposal is urgent, it is possible + that the vote will close before delegators have a chance to react and override their validator's vote. This is not a problem, as proposals require more than 2/3rd of the total voting power to pass before the end of the voting period. If more than 2/3rd of validators collude, they can censor the votes of delegators anyway. ### Validator’s punishment for non-voting @@ -150,29 +153,29 @@ Later, we may add permissioned keys that could only sign txs from certain module ## Software Upgrade -If proposals are of type `SoftwareUpgradeProposal`, then nodes need to upgrade -their software to the new version that was voted. This process is divided in +If proposals are of type `SoftwareUpgradeProposal`, then nodes need to upgrade +their software to the new version that was voted. This process is divided in two steps. ### Signal -After a `SoftwareUpgradeProposal` is accepted, validators are expected to -download and install the new version of the software while continuing to run -the previous version. Once a validator has downloaded and installed the -upgrade, it will start signaling to the network that it is ready to switch by -including the proposal's `proposalID` in its *precommits*.(*Note: Confirmation -that we want it in the precommit?*) +After a `SoftwareUpgradeProposal` is accepted, validators are expected to +download and install the new version of the software while continuing to run +the previous version. Once a validator has downloaded and installed the +upgrade, it will start signaling to the network that it is ready to switch by +including the proposal's `proposalID` in its _precommits_.(_Note: Confirmation +that we want it in the precommit?_) -Note: There is only one signal slot per *precommit*. If several -`SoftwareUpgradeProposals` are accepted in a short timeframe, a pipeline will -form and they will be implemented one after the other in the order that they +Note: There is only one signal slot per _precommit_. If several +`SoftwareUpgradeProposals` are accepted in a short timeframe, a pipeline will +form and they will be implemented one after the other in the order that they were accepted. ### Switch -Once a block contains more than 2/3rd *precommits* where a common -`SoftwareUpgradeProposal` is signaled, all the nodes (including validator +Once a block contains more than 2/3rd _precommits_ where a common +`SoftwareUpgradeProposal` is signaled, all the nodes (including validator nodes, non-validating full nodes and light-nodes) are expected to switch to the -new version of the software. +new version of the software. -*Note: Not clear how the flip is handled programmatically* +_Note: Not clear how the flip is handled programmatically_ diff --git a/x/gov/spec/02_state.md b/x/gov/spec/02_state.md index e180c2839461..ba3b12b3f3a7 100644 --- a/x/gov/spec/02_state.md +++ b/x/gov/spec/02_state.md @@ -96,7 +96,7 @@ the governance process. type Proposal struct { Content // Proposal content interface - ProposalID uint64 + ProposalID uint64 Status ProposalStatus // Status of the Proposal {Pending, Active, Passed, Rejected} FinalTallyResult TallyResult // Result of Tallies @@ -145,26 +145,26 @@ We also mention a method to update the tally for a given proposal: ## Stores -*Stores are KVStores in the multi-store. The key to find the store is the first -parameter in the list*` +_Stores are KVStores in the multi-store. The key to find the store is the first +parameter in the list_` We will use one KVStore `Governance` to store two mappings: -* A mapping from `proposalID|'proposal'` to `Proposal`. -* A mapping from `proposalID|'addresses'|address` to `Vote`. This mapping allows -us to query all addresses that voted on the proposal along with their vote by -doing a range query on `proposalID:addresses`. - +- A mapping from `proposalID|'proposal'` to `Proposal`. +- A mapping from `proposalID|'addresses'|address` to `Vote`. This mapping allows + us to query all addresses that voted on the proposal along with their vote by + doing a range query on `proposalID:addresses`. For pseudocode purposes, here are the two function we will use to read or write in stores: -* `load(StoreKey, Key)`: Retrieve item stored at key `Key` in store found at key `StoreKey` in the multistore -* `store(StoreKey, Key, value)`: Write value `Value` at key `Key` in store found at key `StoreKey` in the multistore +- `load(StoreKey, Key)`: Retrieve item stored at key `Key` in store found at key `StoreKey` in the multistore +- `store(StoreKey, Key, value)`: Write value `Value` at key `Key` in store found at key `StoreKey` in the multistore ## Proposal Processing Queue **Store:** -* `ProposalProcessingQueue`: A queue `queue[proposalID]` containing all the + +- `ProposalProcessingQueue`: A queue `queue[proposalID]` containing all the `ProposalIDs` of proposals that reached `MinDeposit`. During each `EndBlock`, all the proposals that have reached the end of their voting period are processed. To process a finished proposal, the application tallies the votes, computes the diff --git a/x/gov/spec/03_messages.md b/x/gov/spec/03_messages.md index f0e8dc9161c5..cac55b5ed945 100644 --- a/x/gov/spec/03_messages.md +++ b/x/gov/spec/03_messages.md @@ -21,13 +21,14 @@ The `Content` of a `TxGovSubmitProposal` message must have an appropriate router set in the governance module. **State modifications:** -* Generate new `proposalID` -* Create new `Proposal` -* Initialise `Proposals` attributes -* Decrease balance of sender by `InitialDeposit` -* If `MinDeposit` is reached: - * Push `proposalID` in `ProposalProcessingQueue` -* Transfer `InitialDeposit` from the `Proposer` to the governance `ModuleAccount` + +- Generate new `proposalID` +- Create new `Proposal` +- Initialise `Proposals` attributes +- Decrease balance of sender by `InitialDeposit` +- If `MinDeposit` is reached: + - Push `proposalID` in `ProposalProcessingQueue` +- Transfer `InitialDeposit` from the `Proposer` to the governance `ModuleAccount` A `TxGovSubmitProposal` transaction can be handled according to the following pseudocode. @@ -88,12 +89,13 @@ type TxGovDeposit struct { ``` **State modifications:** -* Decrease balance of sender by `deposit` -* Add `deposit` of sender in `proposal.Deposits` -* Increase `proposal.TotalDeposit` by sender's `deposit` -* If `MinDeposit` is reached: - * Push `proposalID` in `ProposalProcessingQueueEnd` -* Transfer `Deposit` from the `proposer` to the governance `ModuleAccount` + +- Decrease balance of sender by `deposit` +- Add `deposit` of sender in `proposal.Deposits` +- Increase `proposal.TotalDeposit` by sender's `deposit` +- If `MinDeposit` is reached: + - Push `proposalID` in `ProposalProcessingQueueEnd` +- Transfer `Deposit` from the `proposer` to the governance `ModuleAccount` A `TxGovDeposit` transaction has to go through a number of checks to be valid. These checks are outlined in the following pseudocode. @@ -158,10 +160,10 @@ vote on the proposal. ``` **State modifications:** -* Record `Vote` of sender -*Note: Gas cost for this message has to take into account the future tallying of the vote in EndBlocker* +- Record `Vote` of sender +_Note: Gas cost for this message has to take into account the future tallying of the vote in EndBlocker_ Next is a pseudocode proposal of the way `TxGovVote` transactions are handled: diff --git a/x/gov/spec/04_events.md b/x/gov/spec/04_events.md index 918b3754ed19..dc3b1bf3a231 100644 --- a/x/gov/spec/04_events.md +++ b/x/gov/spec/04_events.md @@ -9,7 +9,7 @@ The governance module emits the following events: ## EndBlocker | Type | Attribute Key | Attribute Value | -|-------------------|-----------------|------------------| +| ----------------- | --------------- | ---------------- | | inactive_proposal | proposal_id | {proposalID} | | inactive_proposal | proposal_result | {proposalResult} | | active_proposal | proposal_id | {proposalID} | @@ -20,7 +20,7 @@ The governance module emits the following events: ### MsgSubmitProposal | Type | Attribute Key | Attribute Value | -|---------------------|---------------------|-----------------| +| ------------------- | ------------------- | --------------- | | submit_proposal | proposal_id | {proposalID} | | submit_proposal [0] | voting_period_start | {proposalID} | | proposal_deposit | amount | {depositAmount} | @@ -29,12 +29,12 @@ The governance module emits the following events: | message | action | submit_proposal | | message | sender | {senderAddress} | -* [0] Event only emitted if the voting period starts during the submission. +- [0] Event only emitted if the voting period starts during the submission. ### MsgVote | Type | Attribute Key | Attribute Value | -|---------------|---------------|-----------------| +| ------------- | ------------- | --------------- | | proposal_vote | option | {voteOption} | | proposal_vote | proposal_id | {proposalID} | | message | module | governance | @@ -44,7 +44,7 @@ The governance module emits the following events: ### MsgDeposit | Type | Attribute Key | Attribute Value | -|----------------------|---------------------|-----------------| +| -------------------- | ------------------- | --------------- | | proposal_deposit | amount | {depositAmount} | | proposal_deposit | proposal_id | {proposalID} | | proposal_deposit [0] | voting_period_start | {proposalID} | @@ -52,4 +52,4 @@ The governance module emits the following events: | message | action | deposit | | message | sender | {senderAddress} | -* [0] Event only emitted if the voting period starts during the submission. +- [0] Event only emitted if the voting period starts during the submission. From 05e40d3ff3e8f173452d96f2437f20291b598d81 Mon Sep 17 00:00:00 2001 From: Erik Grinaker Date: Tue, 4 Feb 2020 19:43:48 +0100 Subject: [PATCH 113/529] Merge PR #5612: Makefile: remove golangci-lint installation --- Makefile | 4 +-- contrib/devtools/Makefile | 11 ++------ contrib/devtools/install-golangci-lint.sh | 33 ----------------------- 3 files changed, 4 insertions(+), 44 deletions(-) delete mode 100644 contrib/devtools/install-golangci-lint.sh diff --git a/Makefile b/Makefile index 03abf9fa66a8..2e5984dd3ad8 100644 --- a/Makefile +++ b/Makefile @@ -185,8 +185,8 @@ benchmark: ### Linting ### ############################################################################### -lint: golangci-lint - $(BINDIR)/golangci-lint run +lint: + golangci-lint run find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" | xargs gofmt -d -s go mod verify .PHONY: lint diff --git a/contrib/devtools/Makefile b/contrib/devtools/Makefile index f0bf0ae77b27..993d1b7b7436 100644 --- a/contrib/devtools/Makefile +++ b/contrib/devtools/Makefile @@ -1,4 +1,4 @@ -.PHONY: all tools tools-clean statik runsim golangci-lint \ +.PHONY: all tools tools-clean statik runsim \ protoc buf protoc-gen-buf-check-breaking protoc-gen-buf-check-lint protoc-gen-gocosmos ### @@ -47,21 +47,14 @@ UNAME_M ?= $(shell uname -m) GOPATH ?= $(shell $(GO) env GOPATH) GITHUBDIR := $(GOPATH)$(FS)src$(FS)github.com -GOLANGCI_LINT_HASHSUM := f11179f445385a4a6d5079d67de63fe48a9113cee8e9ee0ced19327a83a4394b BUF_VERSION ?= 0.4.0 TOOLS_DESTDIR ?= $(GOPATH)/bin -GOLANGCI_LINT = $(TOOLS_DESTDIR)/golangci-lint STATIK = $(TOOLS_DESTDIR)/statik RUNSIM = $(TOOLS_DESTDIR)/runsim -tools: protoc buf statik runsim golangci-lint - -golangci-lint: $(GOLANGCI_LINT) -$(GOLANGCI_LINT): $(mkfile_dir)/install-golangci-lint.sh - @echo "Installing golangci-lint..." - @bash $(mkfile_dir)/install-golangci-lint.sh $(TOOLS_DESTDIR) $(GOLANGCI_LINT_HASHSUM) +tools: protoc buf statik runsim # Install the runsim binary with a temporary workaround of entering an outside # directory as the "go get" command ignores the -mod option and will polute the diff --git a/contrib/devtools/install-golangci-lint.sh b/contrib/devtools/install-golangci-lint.sh deleted file mode 100644 index 3b0842e59cf3..000000000000 --- a/contrib/devtools/install-golangci-lint.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash - -set -euo pipefail - -installer="$(mktemp)" -trap "rm -f ${installer}" EXIT - -GOBIN="${1}" -CURL="$(which curl)" -HASHSUM="${2}" - -f_sha256() { - local l_file - l_file=$1 - python -sBc "import hashlib;print(hashlib.sha256(open('$l_file','rb').read()).hexdigest())" -} - -get_latest_release() { - "${CURL}" --silent "https://api.github.com/repos/$1/releases/latest" | \ - grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/' -} - -VERSION="$(get_latest_release golangci/golangci-lint)" - -echo "Downloading golangci-lint ${VERSION} installer ..." >&2 -"${CURL}" -sfL "https://raw.githubusercontent.com/golangci/golangci-lint/${VERSION}/install.sh" > "${installer}" - -echo "Checking hashsum ..." >&2 -[ "${HASHSUM}" = "$(f_sha256 ${installer})" ] -chmod +x "${installer}" - -echo "Launching installer ..." >&2 -exec "${installer}" -d -b "${GOBIN}" "${VERSION}" From 30d5f7daf3581e0d55fe0af7edd3dc7eefbcc934 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Tue, 4 Feb 2020 21:33:02 -0500 Subject: [PATCH 114/529] Merge PR #5615: Create Account on SendCoins --- x/bank/internal/keeper/keeper.go | 9 +++++++++ x/bank/internal/keeper/keeper_test.go | 25 +++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/x/bank/internal/keeper/keeper.go b/x/bank/internal/keeper/keeper.go index 380507178635..3f8529ad7923 100644 --- a/x/bank/internal/keeper/keeper.go +++ b/x/bank/internal/keeper/keeper.go @@ -236,6 +236,15 @@ func (k BaseSendKeeper) SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAd return err } + // Create account if recipient does not exist. + // + // NOTE: This should ultimately be removed in favor a more flexible approach + // such as delegated fee messages. + acc := k.ak.GetAccount(ctx, toAddr) + if acc == nil { + k.ak.SetAccount(ctx, k.ak.NewAccountWithAddress(ctx, toAddr)) + } + return nil } diff --git a/x/bank/internal/keeper/keeper_test.go b/x/bank/internal/keeper/keeper_test.go index 8f2eab8138d8..fbe41870f7bd 100644 --- a/x/bank/internal/keeper/keeper_test.go +++ b/x/bank/internal/keeper/keeper_test.go @@ -47,6 +47,31 @@ func (suite *IntegrationTestSuite) SetupTest() { suite.ctx = ctx } +func (suite *IntegrationTestSuite) TestSendCoinsNewAccount() { + app, ctx := suite.app, suite.ctx + balances := sdk.NewCoins(newFooCoin(100), newBarCoin(50)) + + addr1 := sdk.AccAddress([]byte("addr1")) + acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) + app.AccountKeeper.SetAccount(ctx, acc1) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, balances)) + + acc1Balances := app.BankKeeper.GetAllBalances(ctx, addr1) + suite.Require().Equal(balances, acc1Balances) + + addr2 := sdk.AccAddress([]byte("addr2")) + + suite.Require().Nil(app.AccountKeeper.GetAccount(ctx, addr2)) + suite.Require().Empty(app.BankKeeper.GetAllBalances(ctx, addr2)) + + sendAmt := sdk.NewCoins(newFooCoin(50), newBarCoin(25)) + suite.Require().NoError(app.BankKeeper.SendCoins(ctx, addr1, addr2, sendAmt)) + + acc2Balances := app.BankKeeper.GetAllBalances(ctx, addr2) + suite.Require().Equal(sendAmt, acc2Balances) + suite.Require().NotNil(app.AccountKeeper.GetAccount(ctx, addr2)) +} + func (suite *IntegrationTestSuite) TestInputOutputCoins() { app, ctx := suite.app, suite.ctx balances := sdk.NewCoins(newFooCoin(90), newBarCoin(30)) From a7f25ade03cc11c012f30386f5b630ba0396099c Mon Sep 17 00:00:00 2001 From: Erik Grinaker Date: Wed, 5 Feb 2020 20:32:45 +0100 Subject: [PATCH 115/529] Merge PR #5613: update to golangci-lint v1.23.3 Co-authored-by: Jack Zampolin --- .golangci.yml | 5 +++++ crypto/keys/lazy_keybase_test.go | 2 +- types/address_test.go | 4 ++-- types/decimal_test.go | 6 ------ types/module/simulation.go | 4 ++-- x/bank/simulation/operations.go | 2 -- x/distribution/keeper/keeper_test.go | 4 ++-- x/distribution/simulation/operations.go | 3 --- x/distribution/simulation/proposals.go | 1 - x/genutil/client/cli/migrate.go | 1 - x/gov/simulation/operations.go | 3 --- x/mock/app.go | 2 +- x/slashing/simulation/operations.go | 2 +- x/staking/keeper/historical_info_test.go | 2 +- x/staking/simulation/operations.go | 10 +++++----- x/staking/types/historical_info.go | 2 +- x/staking/types/historical_info_test.go | 4 ++-- x/upgrade/alias.go | 2 +- 18 files changed, 24 insertions(+), 35 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 9d790040dbcc..f3e6c70e6dad 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -47,6 +47,11 @@ issues: - text: "ST1003:" linters: - stylecheck + # FIXME disabled until golangci-lint updates stylecheck with this fix: + # https://github.com/dominikh/go-tools/issues/389 + - text: "ST1016:" + linters: + - stylecheck linters-settings: dogsled: diff --git a/crypto/keys/lazy_keybase_test.go b/crypto/keys/lazy_keybase_test.go index 1b5991dae724..19d5445297f2 100644 --- a/crypto/keys/lazy_keybase_test.go +++ b/crypto/keys/lazy_keybase_test.go @@ -425,7 +425,7 @@ func TestKeygenOverride(t *testing.T) { overrideCalled := false dummyFunc := func(bz []byte, algo SigningAlgo) (crypto.PrivKey, error) { overrideCalled = true - return testPriv(bz[:]), nil + return testPriv(bz), nil } kb := New("keybasename", dir, WithKeygenFunc(dummyFunc)) diff --git a/types/address_test.go b/types/address_test.go index 09e5bf93c463..5193404d093f 100644 --- a/types/address_test.go +++ b/types/address_test.go @@ -367,8 +367,8 @@ func TestBech32ifyAddressBytes(t *testing.T) { {"20-byte address", args{"prefixB", addr20byte}, "prefixB1qqqsyqcyq5rqwzqfpg9scrgwpugpzysn8e9wka", false}, } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { - tt := tt got, err := types.Bech32ifyAddressBytes(tt.args.prefix, tt.args.bs) if (err != nil) != tt.wantErr { t.Errorf("Bech32ifyBytes() error = %v, wantErr %v", err, tt.wantErr) @@ -400,8 +400,8 @@ func TestMustBech32ifyAddressBytes(t *testing.T) { {"20-byte address", args{"prefixB", addr20byte}, "prefixB1qqqsyqcyq5rqwzqfpg9scrgwpugpzysn8e9wka", false}, } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { - tt := tt if tt.wantPanic { require.Panics(t, func() { types.MustBech32ifyAddressBytes(tt.args.prefix, tt.args.bs) }) return diff --git a/types/decimal_test.go b/types/decimal_test.go index b88f146094fe..c56d303ee1e4 100644 --- a/types/decimal_test.go +++ b/types/decimal_test.go @@ -330,12 +330,6 @@ func TestSerializationGocodecJSON(t *testing.T) { require.True(t, d.Equal(d2), "original: %v, unmarshalled: %v", d, d2) } -type testDEmbedStruct struct { - Field1 string `json:"f1"` - Field2 int `json:"f2"` - Field3 Dec `json:"f3"` -} - func TestStringOverflow(t *testing.T) { // two random 64 bit primes dec1, err := NewDecFromStr("51643150036226787134389711697696177267") diff --git a/types/module/simulation.go b/types/module/simulation.go index fab432c8a57e..e142b3c882d7 100644 --- a/types/module/simulation.go +++ b/types/module/simulation.go @@ -50,7 +50,7 @@ func NewSimulationManager(modules ...AppModuleSimulation) *SimulationManager { // GetProposalContents returns each module's proposal content generator function // with their default operation weight and key. func (sm *SimulationManager) GetProposalContents(simState SimulationState) []simulation.WeightedProposalContent { - var wContents []simulation.WeightedProposalContent + wContents := make([]simulation.WeightedProposalContent, 0, len(sm.Modules)) for _, module := range sm.Modules { wContents = append(wContents, module.ProposalContents(simState)...) } @@ -87,7 +87,7 @@ func (sm *SimulationManager) GenerateParamChanges(seed int64) (paramChanges []si // WeightedOperations returns all the modules' weighted operations of an application func (sm *SimulationManager) WeightedOperations(simState SimulationState) []simulation.WeightedOperation { - var wOps []simulation.WeightedOperation + wOps := make([]simulation.WeightedOperation, 0, len(sm.Modules)) for _, module := range sm.Modules { wOps = append(wOps, module.WeightedOperations(simState)...) } diff --git a/x/bank/simulation/operations.go b/x/bank/simulation/operations.go index 0c6d8d242b8d..2d9e8468359a 100644 --- a/x/bank/simulation/operations.go +++ b/x/bank/simulation/operations.go @@ -53,7 +53,6 @@ func WeightedOperations( // SimulateMsgSend tests and runs a single msg send where both // accounts already exist. -// nolint: funlen func SimulateMsgSend(ak types.AccountKeeper, bk keeper.Keeper) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, @@ -127,7 +126,6 @@ func sendMsgSend( // SimulateMsgMultiSend tests and runs a single msg multisend, with randomized, capped number of inputs/outputs. // all accounts in msg fields exist in state -// nolint: funlen func SimulateMsgMultiSend(ak types.AccountKeeper, bk keeper.Keeper) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, diff --git a/x/distribution/keeper/keeper_test.go b/x/distribution/keeper/keeper_test.go index ce0721ce6658..17d809becc91 100644 --- a/x/distribution/keeper/keeper_test.go +++ b/x/distribution/keeper/keeper_test.go @@ -11,7 +11,7 @@ import ( ) func TestSetWithdrawAddr(t *testing.T) { - ctx, _, _, keeper, _, _ := CreateTestInputDefault(t, false, 1000) // nolint: dogseld + ctx, _, _, keeper, _, _ := CreateTestInputDefault(t, false, 1000) // nolint: dogsled params := keeper.GetParams(ctx) params.WithdrawAddrEnabled = false @@ -79,7 +79,7 @@ func TestWithdrawValidatorCommission(t *testing.T) { } func TestGetTotalRewards(t *testing.T) { - ctx, _, _, keeper, _, _ := CreateTestInputDefault(t, false, 1000) // nolint: dogseld + ctx, _, _, keeper, _, _ := CreateTestInputDefault(t, false, 1000) // nolint: dogsled valCommission := sdk.DecCoins{ sdk.NewDecCoinFromDec("mytoken", sdk.NewDec(5).Quo(sdk.NewDec(4))), diff --git a/x/distribution/simulation/operations.go b/x/distribution/simulation/operations.go index 30bc1a61ec2e..cb30376ab429 100644 --- a/x/distribution/simulation/operations.go +++ b/x/distribution/simulation/operations.go @@ -78,7 +78,6 @@ func WeightedOperations( } // SimulateMsgSetWithdrawAddress generates a MsgSetWithdrawAddress with random values. -// nolint: funlen func SimulateMsgSetWithdrawAddress(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, @@ -120,7 +119,6 @@ func SimulateMsgSetWithdrawAddress(ak types.AccountKeeper, bk types.BankKeeper, } // SimulateMsgWithdrawDelegatorReward generates a MsgWithdrawDelegatorReward with random values. -// nolint: funlen func SimulateMsgWithdrawDelegatorReward(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, sk stakingkeeper.Keeper) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, @@ -168,7 +166,6 @@ func SimulateMsgWithdrawDelegatorReward(ak types.AccountKeeper, bk types.BankKee } // SimulateMsgWithdrawValidatorCommission generates a MsgWithdrawValidatorCommission with random values. -// nolint: funlen func SimulateMsgWithdrawValidatorCommission(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, sk stakingkeeper.Keeper) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, diff --git a/x/distribution/simulation/proposals.go b/x/distribution/simulation/proposals.go index cd6fcb1b7506..f212397b5342 100644 --- a/x/distribution/simulation/proposals.go +++ b/x/distribution/simulation/proposals.go @@ -26,7 +26,6 @@ func ProposalContents(k keeper.Keeper) []simulation.WeightedProposalContent { } // SimulateCommunityPoolSpendProposalContent generates random community-pool-spend proposal content -// nolint: funlen func SimulateCommunityPoolSpendProposalContent(k keeper.Keeper) simulation.ContentSimulatorFn { return func(r *rand.Rand, ctx sdk.Context, accs []simulation.Account) govtypes.Content { simAccount, _ := simulation.RandomAcc(r, accs) diff --git a/x/genutil/client/cli/migrate.go b/x/genutil/client/cli/migrate.go index eeba89356a95..58dd9319f981 100644 --- a/x/genutil/client/cli/migrate.go +++ b/x/genutil/client/cli/migrate.go @@ -53,7 +53,6 @@ func GetMigrationVersions() []string { } // MigrateGenesisCmd returns a command to execute genesis state migration. -// nolint: funlen func MigrateGenesisCmd(_ *server.Context, cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "migrate [target-version] [genesis-file]", diff --git a/x/gov/simulation/operations.go b/x/gov/simulation/operations.go index 91659bd423a1..608585adaf84 100644 --- a/x/gov/simulation/operations.go +++ b/x/gov/simulation/operations.go @@ -81,7 +81,6 @@ func WeightedOperations( // SimulateSubmitProposal simulates creating a msg Submit Proposal // voting on the proposal, and subsequently slashing the proposal. It is implemented using // future operations. -// nolint: funlen func SimulateSubmitProposal( ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, contentSim simulation.ContentSimulatorFn, ) simulation.Operation { @@ -188,7 +187,6 @@ func SimulateSubmitProposal( } // SimulateMsgDeposit generates a MsgDeposit with random values. -// nolint: funlen func SimulateMsgDeposit(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, @@ -242,7 +240,6 @@ func SimulateMsgDeposit(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Ke } // SimulateMsgVote generates a MsgVote with random values. -// nolint: funlen func SimulateMsgVote(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simulation.Operation { return operationSimulateMsgVote(ak, bk, k, simulation.Account{}, -1) } diff --git a/x/mock/app.go b/x/mock/app.go index 3afccc555df9..ad584df1bc0f 100644 --- a/x/mock/app.go +++ b/x/mock/app.go @@ -210,7 +210,7 @@ func CreateGenAccounts(numAccs int, genCoins sdk.Coins) ( }) } - return + return // nolint } // SetGenesis sets the mock app genesis accounts. diff --git a/x/slashing/simulation/operations.go b/x/slashing/simulation/operations.go index c7e1b0bfb6c4..8b7124609c09 100644 --- a/x/slashing/simulation/operations.go +++ b/x/slashing/simulation/operations.go @@ -42,7 +42,7 @@ func WeightedOperations( } // SimulateMsgUnjail generates a MsgUnjail with random values -// nolint: funlen interfacer +// nolint: interfacer func SimulateMsgUnjail(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, sk stakingkeeper.Keeper) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, diff --git a/x/staking/keeper/historical_info_test.go b/x/staking/keeper/historical_info_test.go index 574d0c9dd9af..068771984084 100644 --- a/x/staking/keeper/historical_info_test.go +++ b/x/staking/keeper/historical_info_test.go @@ -27,7 +27,7 @@ func TestHistoricalInfo(t *testing.T) { recv, found := keeper.GetHistoricalInfo(ctx, 2) require.True(t, found, "HistoricalInfo not found after set") require.Equal(t, hi, recv, "HistoricalInfo not equal") - require.True(t, sort.IsSorted(types.Validators(recv.ValSet)), "HistoricalInfo validators is not sorted") + require.True(t, sort.IsSorted(recv.ValSet), "HistoricalInfo validators is not sorted") keeper.DeleteHistoricalInfo(ctx, 2) diff --git a/x/staking/simulation/operations.go b/x/staking/simulation/operations.go index 58451676a739..6d87a8c425c4 100644 --- a/x/staking/simulation/operations.go +++ b/x/staking/simulation/operations.go @@ -92,7 +92,7 @@ func WeightedOperations( } // SimulateMsgCreateValidator generates a MsgCreateValidator with random values -// nolint: funlen interfacer +// nolint: interfacer func SimulateMsgCreateValidator(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, @@ -171,7 +171,7 @@ func SimulateMsgCreateValidator(ak types.AccountKeeper, bk types.BankKeeper, k k } // SimulateMsgEditValidator generates a MsgEditValidator with random values -// nolint: funlen interfacer +// nolint: interfacer func SimulateMsgEditValidator(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, @@ -238,7 +238,7 @@ func SimulateMsgEditValidator(ak types.AccountKeeper, bk types.BankKeeper, k kee } // SimulateMsgDelegate generates a MsgDelegate with random values -// nolint: funlen interfacer +// nolint: interfacer func SimulateMsgDelegate(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, @@ -305,7 +305,7 @@ func SimulateMsgDelegate(ak types.AccountKeeper, bk types.BankKeeper, k keeper.K } // SimulateMsgUndelegate generates a MsgUndelegate with random values -// nolint: funlen,interfacer +// nolint: interfacer func SimulateMsgUndelegate(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, @@ -387,7 +387,7 @@ func SimulateMsgUndelegate(ak types.AccountKeeper, bk types.BankKeeper, k keeper } // SimulateMsgBeginRedelegate generates a MsgBeginRedelegate with random values -// nolint: funlen,interfacer +// nolint: interfacer func SimulateMsgBeginRedelegate(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, diff --git a/x/staking/types/historical_info.go b/x/staking/types/historical_info.go index 1c08caebcde6..9aa07c95d72e 100644 --- a/x/staking/types/historical_info.go +++ b/x/staking/types/historical_info.go @@ -50,7 +50,7 @@ func ValidateBasic(hi HistoricalInfo) error { if len(hi.ValSet) == 0 { return sdkerrors.Wrap(ErrInvalidHistoricalInfo, "validator set is empty") } - if !sort.IsSorted(Validators(hi.ValSet)) { + if !sort.IsSorted(hi.ValSet) { return sdkerrors.Wrap(ErrInvalidHistoricalInfo, "validator set is not sorted by address") } return nil diff --git a/x/staking/types/historical_info_test.go b/x/staking/types/historical_info_test.go index f607ba15031c..69596ef3190b 100644 --- a/x/staking/types/historical_info_test.go +++ b/x/staking/types/historical_info_test.go @@ -23,7 +23,7 @@ var ( func TestHistoricalInfo(t *testing.T) { hi := NewHistoricalInfo(header, validators) - require.True(t, sort.IsSorted(Validators(hi.ValSet)), "Validators are not sorted") + require.True(t, sort.IsSorted(hi.ValSet), "Validators are not sorted") var value []byte require.NotPanics(t, func() { @@ -35,7 +35,7 @@ func TestHistoricalInfo(t *testing.T) { recv, err := UnmarshalHistoricalInfo(ModuleCdc, value) require.Nil(t, err, "Unmarshalling HistoricalInfo failed") require.Equal(t, hi, recv, "Unmarshalled HistoricalInfo is different from original") - require.True(t, sort.IsSorted(Validators(hi.ValSet)), "Validators are not sorted") + require.True(t, sort.IsSorted(hi.ValSet), "Validators are not sorted") } func TestValidateBasic(t *testing.T) { diff --git a/x/upgrade/alias.go b/x/upgrade/alias.go index fe36f23097bc..d8089d35d543 100644 --- a/x/upgrade/alias.go +++ b/x/upgrade/alias.go @@ -32,7 +32,7 @@ var ( ) type ( - UpgradeHandler = types.UpgradeHandler + UpgradeHandler = types.UpgradeHandler // nolint Plan = types.Plan SoftwareUpgradeProposal = types.SoftwareUpgradeProposal CancelSoftwareUpgradeProposal = types.CancelSoftwareUpgradeProposal From b0c6c750dfb5d0ea72b004810d6444242b228850 Mon Sep 17 00:00:00 2001 From: Anthony Date: Thu, 6 Feb 2020 22:27:23 +0700 Subject: [PATCH 116/529] Merge PR #5618: Add test of missing verifier in cli context --- CHANGELOG.md | 1 + client/context/query.go | 3 +++ 2 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fc45a176b45d..6d53438b58a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,7 @@ balances or a single balance by denom when the `denom` query parameter is presen ### Bug Fixes * (x/bank) [\#5531](https://github.com/cosmos/cosmos-sdk/issues/5531) Added missing amount event to MsgMultiSend, emitted for each output. +* (client) [\#5618](https://github.com/cosmos/cosmos-sdk/pull/5618) Fix crash on the client when the verifier is not set. ### State Machine Breaking diff --git a/client/context/query.go b/client/context/query.go index b5686f864165..c0c45a226fb7 100644 --- a/client/context/query.go +++ b/client/context/query.go @@ -130,6 +130,9 @@ func (ctx CLIContext) query(path string, key tmbytes.HexBytes) ([]byte, int64, e // Verify verifies the consensus proof at given height. func (ctx CLIContext) Verify(height int64) (tmtypes.SignedHeader, error) { + if ctx.Verifier == nil { + return tmtypes.SignedHeader{}, fmt.Errorf("missing valid certifier to verify data from distrusted node") + } check, err := tmliteProxy.GetCertifiedCommit(height, ctx.Client, ctx.Verifier) switch { case tmliteErr.IsErrCommitNotFound(err): From 53bf2271d5bac054a8f74723732f21055c1b72d4 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Thu, 6 Feb 2020 14:21:02 -0500 Subject: [PATCH 117/529] Merge PR #5600: Migrate x/staking to Protobuf --- .codecov.yml | 1 + .golangci.yml | 2 +- CHANGELOG.md | 8 + codec/amino.go | 8 +- codec/codec.go | 4 + go.mod | 1 + simapp/app.go | 16 +- simapp/codec.go | 40 + .../proto/tendermint/abci/types/types.proto | 350 + .../tendermint/crypto/merkle/merkle.proto | 31 + .../proto/tendermint/libs/kv/types.proto | 29 + types/address_bench_test.go | 48 + types/decimal.go | 4 + types/int.go | 4 + types/staking.go | 17 +- types/types.pb.go | 554 +- types/types.proto | 25 +- x/distribution/keeper/test_common.go | 2 +- x/distribution/types/expected_keepers.go | 2 +- x/gov/keeper/tally_test.go | 2 +- x/gov/keeper/test_common.go | 2 +- x/gov/test_common.go | 2 +- x/slashing/app_test.go | 4 +- x/slashing/internal/keeper/test_common.go | 2 +- x/slashing/internal/types/expected_keepers.go | 2 +- x/staking/alias.go | 3 + x/staking/app_test.go | 2 +- x/staking/client/cli/query.go | 21 +- x/staking/genesis.go | 9 +- x/staking/genesis_test.go | 10 +- x/staking/handler.go | 31 +- x/staking/handler_test.go | 71 +- x/staking/keeper/delegation.go | 49 +- x/staking/keeper/delegation_test.go | 16 +- x/staking/keeper/historical_info_test.go | 7 +- x/staking/keeper/keeper.go | 20 +- x/staking/keeper/params.go | 6 +- x/staking/keeper/query_utils.go | 28 +- x/staking/keeper/test_common.go | 8 +- x/staking/keeper/val_state_change.go | 11 +- x/staking/keeper/validator.go | 61 +- x/staking/keeper/validator_test.go | 27 +- x/staking/simulation/genesis.go | 8 +- x/staking/types/codec.go | 30 +- x/staking/types/commission.go | 52 +- x/staking/types/delegation.go | 236 +- x/staking/types/errors.go | 1 + x/staking/types/expected_keepers.go | 2 +- x/staking/types/historical_info.go | 21 +- x/staking/types/historical_info_test.go | 6 +- x/staking/types/msg.go | 138 +- x/staking/types/msg_test.go | 49 +- x/staking/types/params.go | 53 +- x/staking/types/types.pb.go | 6831 +++++++++++++++++ x/staking/types/types.proto | 368 + x/staking/types/validator.go | 259 +- x/staking/types/validator_test.go | 52 +- 57 files changed, 8796 insertions(+), 850 deletions(-) create mode 100644 simapp/codec.go create mode 100644 third_party/proto/tendermint/abci/types/types.proto create mode 100644 third_party/proto/tendermint/crypto/merkle/merkle.proto create mode 100644 third_party/proto/tendermint/libs/kv/types.proto create mode 100644 types/address_bench_test.go create mode 100644 x/staking/types/types.pb.go create mode 100644 x/staking/types/types.proto diff --git a/.codecov.yml b/.codecov.yml index 80b53809f8bc..e6009c46ada3 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -46,6 +46,7 @@ ignore: - "docs" - "*.md" - "*.rst" + - "*.pb.go" - "x/**/test_common.go" - "scripts/" - "contrib" diff --git a/.golangci.yml b/.golangci.yml index f3e6c70e6dad..8e5c493b49b2 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -47,7 +47,7 @@ issues: - text: "ST1003:" linters: - stylecheck - # FIXME disabled until golangci-lint updates stylecheck with this fix: + # FIXME: Disabled until golangci-lint updates stylecheck with this fix: # https://github.com/dominikh/go-tools/issues/389 - text: "ST1016:" linters: diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d53438b58a6..6aec3843db5b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -60,6 +60,14 @@ balances or a single balance by denom when the `denom` query parameter is presen * Callers to `NewBaseVestingAccount` are responsible for verifying account balance in relation to the original vesting amount. * The `SendKeeper` and `ViewKeeper` interfaces in `x/bank` have been modified to account for changes. +* (staking) [\#5600](https://github.com/cosmos/cosmos-sdk/pull/5600) Migrate the `x/staking` module to use Protocol Buffer for state +serialization instead of Amino. The exact codec used is `codec.HybridCodec` which utilizes Protobuf for binary encoding and Amino +for JSON encoding. + * `BondStatus` is now of type `int32` instead of `byte`. + * Types of `int16` in the `Params` type are now of type `int32`. + * Every reference of `crypto.Pubkey` in context of a `Validator` is now of type string. `GetPubKeyFromBech32` must be used to get the `crypto.Pubkey`. + * The `Keeper` constructor now takes a `codec.Marshaler` instead of a concrete Amino codec. This exact type + provided is specified by `ModuleCdc`. ### Improvements diff --git a/codec/amino.go b/codec/amino.go index b2300aef6cc3..c0936e70460b 100644 --- a/codec/amino.go +++ b/codec/amino.go @@ -45,8 +45,8 @@ func RegisterEvidences(cdc *Codec) { // MarshalJSONIndent provides a utility for indented JSON encoding of an object // via an Amino codec. It returns an error if it cannot serialize or indent as // JSON. -func MarshalJSONIndent(cdc *Codec, obj interface{}) ([]byte, error) { - bz, err := cdc.MarshalJSON(obj) +func MarshalJSONIndent(m JSONMarshaler, obj interface{}) ([]byte, error) { + bz, err := m.MarshalJSON(obj) if err != nil { return nil, err } @@ -60,8 +60,8 @@ func MarshalJSONIndent(cdc *Codec, obj interface{}) ([]byte, error) { } // MustMarshalJSONIndent executes MarshalJSONIndent except it panics upon failure. -func MustMarshalJSONIndent(cdc *Codec, obj interface{}) []byte { - bz, err := MarshalJSONIndent(cdc, obj) +func MustMarshalJSONIndent(m JSONMarshaler, obj interface{}) []byte { + bz, err := MarshalJSONIndent(m, obj) if err != nil { panic(fmt.Sprintf("failed to marshal JSON: %s", err)) } diff --git a/codec/codec.go b/codec/codec.go index 203a1ec1bbb6..323d2607c851 100644 --- a/codec/codec.go +++ b/codec/codec.go @@ -30,6 +30,10 @@ type ( UnmarshalBinaryLengthPrefixed(bz []byte, ptr ProtoMarshaler) error MustUnmarshalBinaryLengthPrefixed(bz []byte, ptr ProtoMarshaler) + JSONMarshaler + } + + JSONMarshaler interface { MarshalJSON(o interface{}) ([]byte, error) // nolint: stdmethods MustMarshalJSON(o interface{}) []byte diff --git a/go.mod b/go.mod index 6ebb9fdde282..77bb6bda0ee1 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/cosmos/ledger-cosmos-go v0.11.1 github.com/gogo/protobuf v1.3.1 github.com/golang/mock v1.3.1-0.20190508161146-9fa652df1129 + github.com/golang/protobuf v1.3.2 github.com/gorilla/mux v1.7.3 github.com/hashicorp/golang-lru v0.5.4 github.com/mattn/go-isatty v0.0.12 diff --git a/simapp/app.go b/simapp/app.go index e3a589adb877..721c1ff6bd80 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -16,7 +16,6 @@ import ( "github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/auth/ante" - "github.com/cosmos/cosmos-sdk/x/auth/vesting" "github.com/cosmos/cosmos-sdk/x/bank" "github.com/cosmos/cosmos-sdk/x/crisis" distr "github.com/cosmos/cosmos-sdk/x/distribution" @@ -79,16 +78,6 @@ var ( } ) -// MakeCodec - custom tx codec -func MakeCodec() *codec.Codec { - var cdc = codec.New() - ModuleBasics.RegisterCodec(cdc) - vesting.RegisterCodec(cdc) - sdk.RegisterCodec(cdc) - codec.RegisterCrypto(cdc) - return cdc -} - // Verify app interface at compile time var _ App = (*SimApp)(nil) @@ -135,6 +124,9 @@ func NewSimApp( invCheckPeriod uint, baseAppOptions ...func(*bam.BaseApp), ) *SimApp { + appCodec := NewAppCodec() + + // TODO: Remove cdc in favor of appCodec once all modules are migrated. cdc := MakeCodec() bApp := bam.NewBaseApp(appName, logger, db, auth.DefaultTxDecoder(cdc), baseAppOptions...) @@ -180,7 +172,7 @@ func NewSimApp( app.cdc, keys[supply.StoreKey], app.AccountKeeper, app.BankKeeper, maccPerms, ) stakingKeeper := staking.NewKeeper( - app.cdc, keys[staking.StoreKey], app.BankKeeper, app.SupplyKeeper, app.subspaces[staking.ModuleName], + appCodec.Staking, keys[staking.StoreKey], app.BankKeeper, app.SupplyKeeper, app.subspaces[staking.ModuleName], ) app.MintKeeper = mint.NewKeeper( app.cdc, keys[mint.StoreKey], app.subspaces[mint.ModuleName], &stakingKeeper, diff --git a/simapp/codec.go b/simapp/codec.go new file mode 100644 index 000000000000..8f87e7e324b1 --- /dev/null +++ b/simapp/codec.go @@ -0,0 +1,40 @@ +package simapp + +import ( + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth/vesting" + "github.com/cosmos/cosmos-sdk/x/staking" +) + +// AppCodec defines the application-level codec. This codec contains all the +// required module-specific codecs that are to be provided upon initialization. +type AppCodec struct { + amino *codec.Codec + + Staking *staking.Codec +} + +func NewAppCodec() *AppCodec { + amino := MakeCodec() + + return &AppCodec{ + amino: amino, + Staking: staking.NewCodec(amino), + } +} + +// MakeCodec creates and returns a reference to an Amino codec that has all the +// necessary types and interfaces registered. This codec is provided to all the +// modules the application depends on. +// +// NOTE: This codec will be deprecated in favor of AppCodec once all modules are +// migrated. +func MakeCodec() *codec.Codec { + var cdc = codec.New() + ModuleBasics.RegisterCodec(cdc) + vesting.RegisterCodec(cdc) + sdk.RegisterCodec(cdc) + codec.RegisterCrypto(cdc) + return cdc +} diff --git a/third_party/proto/tendermint/abci/types/types.proto b/third_party/proto/tendermint/abci/types/types.proto new file mode 100644 index 000000000000..eff32d4c5322 --- /dev/null +++ b/third_party/proto/tendermint/abci/types/types.proto @@ -0,0 +1,350 @@ +syntax = "proto3"; +package tendermint.abci.types; +option go_package = "github.com/tendermint/tendermint/abci/types"; + +// For more information on gogo.proto, see: +// https://github.com/gogo/protobuf/blob/master/extensions.md +import "third_party/proto/gogoproto/gogo.proto"; +import "third_party/proto/tendermint/crypto/merkle/merkle.proto"; +import "third_party/proto/tendermint/libs/kv/types.proto"; +import "google/protobuf/timestamp.proto"; +import "google/protobuf/duration.proto"; + +// This file is copied from http://github.com/tendermint/abci +// NOTE: When using custom types, mind the warnings. +// https://github.com/gogo/protobuf/blob/master/custom_types.md#warnings-and-issues + +option (gogoproto.marshaler_all) = true; +option (gogoproto.unmarshaler_all) = true; +option (gogoproto.sizer_all) = true; +option (gogoproto.goproto_registration) = true; + +// Generate tests +option (gogoproto.populate_all) = true; +option (gogoproto.equal_all) = true; +option (gogoproto.testgen_all) = true; + +//---------------------------------------- +// Request types + +message Request { + oneof value { + RequestEcho echo = 2; + RequestFlush flush = 3; + RequestInfo info = 4; + RequestSetOption set_option = 5; + RequestInitChain init_chain = 6; + RequestQuery query = 7; + RequestBeginBlock begin_block = 8; + RequestCheckTx check_tx = 9; + RequestDeliverTx deliver_tx = 19; + RequestEndBlock end_block = 11; + RequestCommit commit = 12; + } +} + +message RequestEcho { string message = 1; } + +message RequestFlush {} + +message RequestInfo { + string version = 1; + uint64 block_version = 2; + uint64 p2p_version = 3; +} + +// nondeterministic +message RequestSetOption { + string key = 1; + string value = 2; +} + +message RequestInitChain { + google.protobuf.Timestamp time = 1 + [ (gogoproto.nullable) = false, (gogoproto.stdtime) = true ]; + string chain_id = 2; + ConsensusParams consensus_params = 3; + repeated ValidatorUpdate validators = 4 [ (gogoproto.nullable) = false ]; + bytes app_state_bytes = 5; +} + +message RequestQuery { + bytes data = 1; + string path = 2; + int64 height = 3; + bool prove = 4; +} + +message RequestBeginBlock { + bytes hash = 1; + Header header = 2 [ (gogoproto.nullable) = false ]; + LastCommitInfo last_commit_info = 3 [ (gogoproto.nullable) = false ]; + repeated Evidence byzantine_validators = 4 [ (gogoproto.nullable) = false ]; +} + +enum CheckTxType { + New = 0; + Recheck = 1; +} + +message RequestCheckTx { + bytes tx = 1; + CheckTxType type = 2; +} + +message RequestDeliverTx { bytes tx = 1; } + +message RequestEndBlock { int64 height = 1; } + +message RequestCommit {} + +//---------------------------------------- +// Response types + +message Response { + oneof value { + ResponseException exception = 1; + ResponseEcho echo = 2; + ResponseFlush flush = 3; + ResponseInfo info = 4; + ResponseSetOption set_option = 5; + ResponseInitChain init_chain = 6; + ResponseQuery query = 7; + ResponseBeginBlock begin_block = 8; + ResponseCheckTx check_tx = 9; + ResponseDeliverTx deliver_tx = 10; + ResponseEndBlock end_block = 11; + ResponseCommit commit = 12; + } +} + +// nondeterministic +message ResponseException { string error = 1; } + +message ResponseEcho { string message = 1; } + +message ResponseFlush {} + +message ResponseInfo { + string data = 1; + + string version = 2; + uint64 app_version = 3; + + int64 last_block_height = 4; + bytes last_block_app_hash = 5; +} + +// nondeterministic +message ResponseSetOption { + uint32 code = 1; + // bytes data = 2; + string log = 3; + string info = 4; +} + +message ResponseInitChain { + ConsensusParams consensus_params = 1; + repeated ValidatorUpdate validators = 2 [ (gogoproto.nullable) = false ]; +} + +message ResponseQuery { + uint32 code = 1; + // bytes data = 2; // use "value" instead. + string log = 3; // nondeterministic + string info = 4; // nondeterministic + int64 index = 5; + bytes key = 6; + bytes value = 7; + tendermint.crypto.merkle.Proof proof = 8; + int64 height = 9; + string codespace = 10; +} + +message ResponseBeginBlock { + repeated Event events = 1 [ + (gogoproto.nullable) = false, + (gogoproto.jsontag) = "events,omitempty" + ]; +} + +message ResponseCheckTx { + uint32 code = 1; + bytes data = 2; + string log = 3; // nondeterministic + string info = 4; // nondeterministic + int64 gas_wanted = 5; + int64 gas_used = 6; + repeated Event events = 7 [ + (gogoproto.nullable) = false, + (gogoproto.jsontag) = "events,omitempty" + ]; + string codespace = 8; +} + +message ResponseDeliverTx { + uint32 code = 1; + bytes data = 2; + string log = 3; // nondeterministic + string info = 4; // nondeterministic + int64 gas_wanted = 5; + int64 gas_used = 6; + repeated Event events = 7 [ + (gogoproto.nullable) = false, + (gogoproto.jsontag) = "events,omitempty" + ]; + string codespace = 8; +} + +message ResponseEndBlock { + repeated ValidatorUpdate validator_updates = 1 + [ (gogoproto.nullable) = false ]; + ConsensusParams consensus_param_updates = 2; + repeated Event events = 3 [ + (gogoproto.nullable) = false, + (gogoproto.jsontag) = "events,omitempty" + ]; +} + +message ResponseCommit { + // reserve 1 + bytes data = 2; +} + +//---------------------------------------- +// Misc. + +// ConsensusParams contains all consensus-relevant parameters +// that can be adjusted by the abci app +message ConsensusParams { + BlockParams block = 1; + EvidenceParams evidence = 2; + ValidatorParams validator = 3; +} + +// BlockParams contains limits on the block size. +message BlockParams { + // Note: must be greater than 0 + int64 max_bytes = 1; + // Note: must be greater or equal to -1 + int64 max_gas = 2; +} + +message EvidenceParams { + // Note: must be greater than 0 + int64 max_age_num_blocks = 1; + google.protobuf.Duration max_age_duration = 2 + [ (gogoproto.nullable) = false, (gogoproto.stdduration) = true ]; +} + +// ValidatorParams contains limits on validators. +message ValidatorParams { repeated string pub_key_types = 1; } + +message LastCommitInfo { + int32 round = 1; + repeated VoteInfo votes = 2 [ (gogoproto.nullable) = false ]; +} + +message Event { + string type = 1; + repeated tendermint.libs.kv.Pair attributes = 2 [ + (gogoproto.nullable) = false, + (gogoproto.jsontag) = "attributes,omitempty" + ]; +} + +//---------------------------------------- +// Blockchain Types + +message Header { + // basic block info + Version version = 1 [ (gogoproto.nullable) = false ]; + string chain_id = 2 [ (gogoproto.customname) = "ChainID" ]; + int64 height = 3; + google.protobuf.Timestamp time = 4 + [ (gogoproto.nullable) = false, (gogoproto.stdtime) = true ]; + + // prev block info + BlockID last_block_id = 5 [ (gogoproto.nullable) = false ]; + + // hashes of block data + bytes last_commit_hash = 6; // commit from validators from the last block + bytes data_hash = 7; // transactions + + // hashes from the app output from the prev block + bytes validators_hash = 8; // validators for the current block + bytes next_validators_hash = 9; // validators for the next block + bytes consensus_hash = 10; // consensus params for current block + bytes app_hash = 11; // state after txs from the previous block + bytes last_results_hash = + 12; // root hash of all results from the txs from the previous block + + // consensus info + bytes evidence_hash = 13; // evidence included in the block + bytes proposer_address = 14; // original proposer of the block +} + +message Version { + uint64 Block = 1; + uint64 App = 2; +} + +message BlockID { + bytes hash = 1; + PartSetHeader parts_header = 2 [ (gogoproto.nullable) = false ]; +} + +message PartSetHeader { + int32 total = 1; + bytes hash = 2; +} + +// Validator +message Validator { + bytes address = 1; + // PubKey pub_key = 2 [(gogoproto.nullable)=false]; + int64 power = 3; +} + +// ValidatorUpdate +message ValidatorUpdate { + PubKey pub_key = 1 [ (gogoproto.nullable) = false ]; + int64 power = 2; +} + +// VoteInfo +message VoteInfo { + Validator validator = 1 [ (gogoproto.nullable) = false ]; + bool signed_last_block = 2; +} + +message PubKey { + string type = 1; + bytes data = 2; +} + +message Evidence { + string type = 1; + Validator validator = 2 [ (gogoproto.nullable) = false ]; + int64 height = 3; + google.protobuf.Timestamp time = 4 + [ (gogoproto.nullable) = false, (gogoproto.stdtime) = true ]; + int64 total_voting_power = 5; +} + +//---------------------------------------- +// Service Definition + +service ABCIApplication { + rpc Echo(RequestEcho) returns (ResponseEcho); + rpc Flush(RequestFlush) returns (ResponseFlush); + rpc Info(RequestInfo) returns (ResponseInfo); + rpc SetOption(RequestSetOption) returns (ResponseSetOption); + rpc DeliverTx(RequestDeliverTx) returns (ResponseDeliverTx); + rpc CheckTx(RequestCheckTx) returns (ResponseCheckTx); + rpc Query(RequestQuery) returns (ResponseQuery); + rpc Commit(RequestCommit) returns (ResponseCommit); + rpc InitChain(RequestInitChain) returns (ResponseInitChain); + rpc BeginBlock(RequestBeginBlock) returns (ResponseBeginBlock); + rpc EndBlock(RequestEndBlock) returns (ResponseEndBlock); +} diff --git a/third_party/proto/tendermint/crypto/merkle/merkle.proto b/third_party/proto/tendermint/crypto/merkle/merkle.proto new file mode 100644 index 000000000000..9dbb2be074e8 --- /dev/null +++ b/third_party/proto/tendermint/crypto/merkle/merkle.proto @@ -0,0 +1,31 @@ +syntax = "proto3"; +package tendermint.crypto.merkle; +option go_package = "github.com/tendermint/tendermint/crypto/merkle"; + +// For more information on gogo.proto, see: +// https://github.com/gogo/protobuf/blob/master/extensions.md +import "third_party/proto/gogoproto/gogo.proto"; + +option (gogoproto.marshaler_all) = true; +option (gogoproto.unmarshaler_all) = true; +option (gogoproto.sizer_all) = true; + +option (gogoproto.populate_all) = true; +option (gogoproto.equal_all) = true; + +//---------------------------------------- +// Message types + +// ProofOp defines an operation used for calculating Merkle root +// The data could be arbitrary format, providing nessecary data +// for example neighbouring node hash +message ProofOp { + string type = 1; + bytes key = 2; + bytes data = 3; +} + +// Proof is Merkle proof defined by the list of ProofOps +message Proof { + repeated ProofOp ops = 1 [(gogoproto.nullable)=false]; +} diff --git a/third_party/proto/tendermint/libs/kv/types.proto b/third_party/proto/tendermint/libs/kv/types.proto new file mode 100644 index 000000000000..247022798347 --- /dev/null +++ b/third_party/proto/tendermint/libs/kv/types.proto @@ -0,0 +1,29 @@ +syntax = "proto3"; +package tendermint.libs.kv; +option go_package = "github.com/tendermint/tendermint/libs/kv"; + +import "third_party/proto/gogoproto/gogo.proto"; + +option (gogoproto.marshaler_all) = true; +option (gogoproto.unmarshaler_all) = true; +option (gogoproto.sizer_all) = true; +option (gogoproto.goproto_registration) = true; +// Generate tests +option (gogoproto.populate_all) = true; +option (gogoproto.equal_all) = true; +option (gogoproto.testgen_all) = true; + +//---------------------------------------- +// Abstract types + +// Define these here for compatibility but use tmlibs/common.KVPair. +message Pair { + bytes key = 1; + bytes value = 2; +} + +// Define these here for compatibility but use tmlibs/common.KI64Pair. +message KI64Pair { + bytes key = 1; + int64 value = 2; +} diff --git a/types/address_bench_test.go b/types/address_bench_test.go new file mode 100644 index 000000000000..8e438a81dacd --- /dev/null +++ b/types/address_bench_test.go @@ -0,0 +1,48 @@ +package types_test + +import ( + "math/rand" + "testing" + "time" + + "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + + "github.com/tendermint/tendermint/crypto/ed25519" +) + +func BenchmarkBech32ifyPubKey(b *testing.B) { + var pk ed25519.PubKeyEd25519 + rng := rand.New(rand.NewSource(time.Now().Unix())) + + b.ResetTimer() + + for i := 0; i < b.N; i++ { + b.StopTimer() + rng.Read(pk[:]) + b.StartTimer() + + _, err := types.Bech32ifyPubKey(types.Bech32PubKeyTypeConsPub, pk) + require.NoError(b, err) + } +} + +func BenchmarkGetPubKeyFromBech32(b *testing.B) { + var pk ed25519.PubKeyEd25519 + rng := rand.New(rand.NewSource(time.Now().Unix())) + + b.ResetTimer() + + for i := 0; i < b.N; i++ { + b.StopTimer() + rng.Read(pk[:]) + + pkStr, err := types.Bech32ifyPubKey(types.Bech32PubKeyTypeConsPub, pk) + require.NoError(b, err) + + b.StartTimer() + pk2, err := types.GetPubKeyFromBech32(types.Bech32PubKeyTypeConsPub, pkStr) + require.NoError(b, err) + require.Equal(b, pk, pk2) + } +} diff --git a/types/decimal.go b/types/decimal.go index d6917182b66c..c1cfc25bcc08 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -750,6 +750,10 @@ func (d *Dec) Size() int { func (d Dec) MarshalAmino() ([]byte, error) { return d.Marshal() } func (d *Dec) UnmarshalAmino(bz []byte) error { return d.Unmarshal(bz) } +func (dp DecProto) String() string { + return dp.Dec.String() +} + //___________________________________________________________________________________ // helpers diff --git a/types/int.go b/types/int.go index 9cc99a013263..4326a3ee9931 100644 --- a/types/int.go +++ b/types/int.go @@ -417,3 +417,7 @@ func (i *Int) UnmarshalAmino(bz []byte) error { return i.Unmarshal(bz) } func IntEq(t *testing.T, exp, got Int) (*testing.T, bool, string, string, string) { return t, exp.Equal(got), "expected:\t%v\ngot:\t\t%v", exp.String(), got.String() } + +func (ip IntProto) String() string { + return ip.Int.String() +} diff --git a/types/staking.go b/types/staking.go index 9f623b3575e6..91c7601386d6 100644 --- a/types/staking.go +++ b/types/staking.go @@ -36,13 +36,13 @@ func TokensFromConsensusPower(power int64) Int { } // BondStatus is the status of a validator -type BondStatus byte +type BondStatus int32 // staking constants const ( - Unbonded BondStatus = 0x00 - Unbonding BondStatus = 0x01 - Bonded BondStatus = 0x02 + Unbonded BondStatus = 1 + Unbonding BondStatus = 2 + Bonded BondStatus = 3 BondStatusUnbonded = "Unbonded" BondStatusUnbonding = "Unbonding" @@ -57,12 +57,15 @@ func (b BondStatus) Equal(b2 BondStatus) bool { // String implements the Stringer interface for BondStatus. func (b BondStatus) String() string { switch b { - case 0x00: + case Unbonded: return BondStatusUnbonded - case 0x01: + + case Unbonding: return BondStatusUnbonding - case 0x02: + + case Bonded: return BondStatusBonded + default: panic("invalid bond status") } diff --git a/types/types.pb.go b/types/types.pb.go index 4ea0bfeec523..4d2136c0a030 100644 --- a/types/types.pb.go +++ b/types/types.pb.go @@ -10,6 +10,8 @@ import ( io "io" math "math" math_bits "math/bits" + reflect "reflect" + strings "strings" ) // Reference imports to suppress errors if they are not otherwise used. @@ -119,15 +121,136 @@ func (m *DecCoin) GetDenom() string { return "" } +// IntProto defines a Protobuf wrapper around an Int object. +type IntProto struct { + Int Int `protobuf:"bytes,1,opt,name=int,proto3,customtype=Int" json:"int"` +} + +func (m *IntProto) Reset() { *m = IntProto{} } +func (*IntProto) ProtoMessage() {} +func (*IntProto) Descriptor() ([]byte, []int) { + return fileDescriptor_2c0f90c600ad7e2e, []int{2} +} +func (m *IntProto) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *IntProto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_IntProto.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 *IntProto) XXX_Merge(src proto.Message) { + xxx_messageInfo_IntProto.Merge(m, src) +} +func (m *IntProto) XXX_Size() int { + return m.Size() +} +func (m *IntProto) XXX_DiscardUnknown() { + xxx_messageInfo_IntProto.DiscardUnknown(m) +} + +var xxx_messageInfo_IntProto proto.InternalMessageInfo + +// DecProto defines a Protobuf wrapper around a Dec object. +type DecProto struct { + Dec Dec `protobuf:"bytes,1,opt,name=dec,proto3,customtype=Dec" json:"dec"` +} + +func (m *DecProto) Reset() { *m = DecProto{} } +func (*DecProto) ProtoMessage() {} +func (*DecProto) Descriptor() ([]byte, []int) { + return fileDescriptor_2c0f90c600ad7e2e, []int{3} +} +func (m *DecProto) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DecProto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DecProto.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 *DecProto) XXX_Merge(src proto.Message) { + xxx_messageInfo_DecProto.Merge(m, src) +} +func (m *DecProto) XXX_Size() int { + return m.Size() +} +func (m *DecProto) XXX_DiscardUnknown() { + xxx_messageInfo_DecProto.DiscardUnknown(m) +} + +var xxx_messageInfo_DecProto proto.InternalMessageInfo + +// ValAddresses defines a repeated set of validator addresses. +type ValAddresses struct { + Addresses []ValAddress `protobuf:"bytes,1,rep,name=addresses,proto3,casttype=ValAddress" json:"addresses,omitempty"` +} + +func (m *ValAddresses) Reset() { *m = ValAddresses{} } +func (*ValAddresses) ProtoMessage() {} +func (*ValAddresses) Descriptor() ([]byte, []int) { + return fileDescriptor_2c0f90c600ad7e2e, []int{4} +} +func (m *ValAddresses) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ValAddresses) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ValAddresses.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 *ValAddresses) XXX_Merge(src proto.Message) { + xxx_messageInfo_ValAddresses.Merge(m, src) +} +func (m *ValAddresses) XXX_Size() int { + return m.Size() +} +func (m *ValAddresses) XXX_DiscardUnknown() { + xxx_messageInfo_ValAddresses.DiscardUnknown(m) +} + +var xxx_messageInfo_ValAddresses proto.InternalMessageInfo + +func (m *ValAddresses) GetAddresses() []ValAddress { + if m != nil { + return m.Addresses + } + return nil +} + func init() { proto.RegisterType((*Coin)(nil), "cosmos_sdk.v1.Coin") proto.RegisterType((*DecCoin)(nil), "cosmos_sdk.v1.DecCoin") + proto.RegisterType((*IntProto)(nil), "cosmos_sdk.v1.IntProto") + proto.RegisterType((*DecProto)(nil), "cosmos_sdk.v1.DecProto") + proto.RegisterType((*ValAddresses)(nil), "cosmos_sdk.v1.ValAddresses") } func init() { proto.RegisterFile("types/types.proto", fileDescriptor_2c0f90c600ad7e2e) } var fileDescriptor_2c0f90c600ad7e2e = []byte{ - // 214 bytes of a gzipped FileDescriptorProto + // 298 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x2c, 0xa9, 0x2c, 0x48, 0x2d, 0xd6, 0x07, 0x93, 0x7a, 0x05, 0x45, 0xf9, 0x25, 0xf9, 0x42, 0xbc, 0xc9, 0xf9, 0xc5, 0xb9, 0xf9, 0xc5, 0xf1, 0xc5, 0x29, 0xd9, 0x7a, 0x65, 0x86, 0x52, 0x6a, 0x25, 0x19, 0x99, 0x45, 0x29, @@ -136,12 +259,17 @@ var fileDescriptor_2c0f90c600ad7e2e = []byte{ 0x5e, 0x7e, 0xae, 0x04, 0xa3, 0x02, 0xa3, 0x06, 0x67, 0x10, 0x84, 0x23, 0xa4, 0xcc, 0xc5, 0x96, 0x98, 0x9b, 0x5f, 0x9a, 0x57, 0x22, 0xc1, 0x04, 0x12, 0x76, 0xe2, 0x3e, 0x71, 0x4f, 0x9e, 0xe1, 0xd6, 0x3d, 0x79, 0x66, 0xcf, 0xbc, 0x92, 0x20, 0xa8, 0x94, 0x92, 0x0b, 0x17, 0xbb, 0x4b, 0x6a, - 0x32, 0x39, 0xa6, 0xb8, 0xa4, 0x26, 0xc3, 0x4c, 0x71, 0x72, 0xb9, 0xf1, 0x50, 0x8e, 0xa1, 0xe1, - 0x91, 0x1c, 0xc3, 0x89, 0x47, 0x72, 0x8c, 0x17, 0x1e, 0xc9, 0x31, 0x3e, 0x78, 0x24, 0xc7, 0x38, - 0xe1, 0xb1, 0x1c, 0xc3, 0x85, 0xc7, 0x72, 0x0c, 0x37, 0x1e, 0xcb, 0x31, 0x44, 0x29, 0xa5, 0x67, - 0x96, 0x64, 0x94, 0x26, 0xe9, 0x25, 0xe7, 0xe7, 0xea, 0x43, 0x3c, 0x0b, 0xa5, 0x74, 0x8b, 0x53, - 0xb2, 0x21, 0x61, 0x91, 0xc4, 0x06, 0xf6, 0x95, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0x8d, 0xc6, - 0x8c, 0x7d, 0x21, 0x01, 0x00, 0x00, + 0x32, 0x39, 0xa6, 0xb8, 0xa4, 0x26, 0xc3, 0x4d, 0xd1, 0xe4, 0xe2, 0xf0, 0xcc, 0x2b, 0x09, 0x00, + 0xfb, 0x45, 0x96, 0x8b, 0x39, 0x33, 0xaf, 0x04, 0x62, 0x08, 0xaa, 0x9d, 0x20, 0x71, 0x90, 0x52, + 0x97, 0xd4, 0x64, 0xb8, 0xd2, 0x94, 0xd4, 0x64, 0x74, 0xa5, 0x20, 0x83, 0x41, 0xe2, 0x4a, 0x4e, + 0x5c, 0x3c, 0x61, 0x89, 0x39, 0x8e, 0x29, 0x29, 0x45, 0xa9, 0xc5, 0xc5, 0xa9, 0xc5, 0x42, 0x3a, + 0x5c, 0x9c, 0x89, 0x30, 0x8e, 0x04, 0xa3, 0x02, 0xb3, 0x06, 0x8f, 0x13, 0xdf, 0xaf, 0x7b, 0xf2, + 0x5c, 0x08, 0x45, 0x41, 0x08, 0x05, 0x56, 0x2c, 0x0d, 0x77, 0x14, 0x18, 0x9d, 0x5c, 0x6e, 0x3c, + 0x94, 0x63, 0x68, 0x78, 0x24, 0xc7, 0x70, 0xe2, 0x91, 0x1c, 0xe3, 0x85, 0x47, 0x72, 0x8c, 0x0f, + 0x1e, 0xc9, 0x31, 0x4e, 0x78, 0x2c, 0xc7, 0x70, 0xe1, 0xb1, 0x1c, 0xc3, 0x8d, 0xc7, 0x72, 0x0c, + 0x51, 0x4a, 0xe9, 0x99, 0x25, 0x19, 0xa5, 0x49, 0x7a, 0xc9, 0xf9, 0xb9, 0xfa, 0x90, 0x68, 0x80, + 0x52, 0xba, 0xc5, 0x29, 0xd9, 0x90, 0x58, 0x4a, 0x62, 0x03, 0x87, 0xb7, 0x31, 0x20, 0x00, 0x00, + 0xff, 0xff, 0xd6, 0x08, 0x09, 0x0f, 0xbb, 0x01, 0x00, 0x00, } func (m *Coin) Marshal() (dAtA []byte, err error) { @@ -224,6 +352,104 @@ func (m *DecCoin) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *IntProto) 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 *IntProto) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *IntProto) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size := m.Int.Size() + i -= size + if _, err := m.Int.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *DecProto) 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 *DecProto) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DecProto) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size := m.Dec.Size() + i -= size + if _, err := m.Dec.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *ValAddresses) 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 *ValAddresses) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ValAddresses) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Addresses) > 0 { + for iNdEx := len(m.Addresses) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Addresses[iNdEx]) + copy(dAtA[i:], m.Addresses[iNdEx]) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Addresses[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + func encodeVarintTypes(dAtA []byte, offset int, v uint64) int { offset -= sovTypes(v) base := offset @@ -265,12 +491,67 @@ func (m *DecCoin) Size() (n int) { return n } +func (m *IntProto) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Int.Size() + n += 1 + l + sovTypes(uint64(l)) + return n +} + +func (m *DecProto) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Dec.Size() + n += 1 + l + sovTypes(uint64(l)) + return n +} + +func (m *ValAddresses) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Addresses) > 0 { + for _, b := range m.Addresses { + l = len(b) + n += 1 + l + sovTypes(uint64(l)) + } + } + return n +} + func sovTypes(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } func sozTypes(x uint64) (n int) { return sovTypes(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } +func (this *ValAddresses) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&ValAddresses{`, + `Addresses:` + fmt.Sprintf("%v", this.Addresses) + `,`, + `}`, + }, "") + return s +} +func valueToStringTypes(v interface{}) string { + rv := reflect.ValueOf(v) + if rv.IsNil() { + return "nil" + } + pv := reflect.Indirect(rv).Interface() + return fmt.Sprintf("*%v", pv) +} func (m *Coin) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -509,6 +790,265 @@ func (m *DecCoin) Unmarshal(dAtA []byte) error { } return nil } +func (m *IntProto) 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 ErrIntOverflowTypes + } + 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: IntProto: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: IntProto: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Int", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Int.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *DecProto) 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 ErrIntOverflowTypes + } + 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: DecProto: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DecProto: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Dec", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Dec.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ValAddresses) 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 ErrIntOverflowTypes + } + 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: ValAddresses: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ValAddresses: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Addresses", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Addresses = append(m.Addresses, make([]byte, postIndex-iNdEx)) + copy(m.Addresses[len(m.Addresses)-1], dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipTypes(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/types/types.proto b/types/types.proto index 49da4e5c69f9..590d21ccd9be 100644 --- a/types/types.proto +++ b/types/types.proto @@ -13,7 +13,8 @@ option (gogoproto.stringer_all) = false; // signatures required by gogoproto. message Coin { string denom = 1; - string amount = 2 [ (gogoproto.customtype) = "Int", (gogoproto.nullable) = false ]; + string amount = 2 + [ (gogoproto.customtype) = "Int", (gogoproto.nullable) = false ]; } // DecCoin defines a token with a denomination and a decimal amount. @@ -22,5 +23,25 @@ message Coin { // signatures required by gogoproto. message DecCoin { string denom = 1; - string amount = 2 [ (gogoproto.customtype) = "Dec", (gogoproto.nullable) = false ]; + string amount = 2 + [ (gogoproto.customtype) = "Dec", (gogoproto.nullable) = false ]; } + +// IntProto defines a Protobuf wrapper around an Int object. +message IntProto { + string int = 1 + [ (gogoproto.customtype) = "Int", (gogoproto.nullable) = false ]; +} + +// DecProto defines a Protobuf wrapper around a Dec object. +message DecProto { + string dec = 1 + [ (gogoproto.customtype) = "Dec", (gogoproto.nullable) = false ]; +} + +// ValAddresses defines a repeated set of validator addresses. +message ValAddresses { + option (gogoproto.stringer) = true; + + repeated bytes addresses = 1 [ (gogoproto.casttype) = "ValAddress" ]; +} \ No newline at end of file diff --git a/x/distribution/keeper/test_common.go b/x/distribution/keeper/test_common.go index e049c3bbc57a..2fe0e22b36ab 100644 --- a/x/distribution/keeper/test_common.go +++ b/x/distribution/keeper/test_common.go @@ -139,7 +139,7 @@ func CreateTestInputAdvanced( } supplyKeeper := supply.NewKeeper(cdc, keySupply, accountKeeper, bankKeeper, maccPerms) - sk := staking.NewKeeper(cdc, keyStaking, bankKeeper, supplyKeeper, pk.Subspace(staking.DefaultParamspace)) + sk := staking.NewKeeper(staking.ModuleCdc, keyStaking, bankKeeper, supplyKeeper, pk.Subspace(staking.DefaultParamspace)) sk.SetParams(ctx, staking.DefaultParams()) keeper := NewKeeper(cdc, keyDistr, pk.Subspace(types.DefaultParamspace), bankKeeper, sk, supplyKeeper, auth.FeeCollectorName, blacklistedAddrs) diff --git a/x/distribution/types/expected_keepers.go b/x/distribution/types/expected_keepers.go index 1f9d0a51a348..d7c909bacec0 100644 --- a/x/distribution/types/expected_keepers.go +++ b/x/distribution/types/expected_keepers.go @@ -49,7 +49,7 @@ type StakingKeeper interface { Delegation(sdk.Context, sdk.AccAddress, sdk.ValAddress) stakingexported.DelegationI // MaxValidators returns the maximum amount of bonded validators - MaxValidators(sdk.Context) uint16 + MaxValidators(sdk.Context) uint32 IterateDelegations(ctx sdk.Context, delegator sdk.AccAddress, fn func(index int64, delegation stakingexported.DelegationI) (stop bool)) diff --git a/x/gov/keeper/tally_test.go b/x/gov/keeper/tally_test.go index 52812793c951..e93f6b387e6b 100644 --- a/x/gov/keeper/tally_test.go +++ b/x/gov/keeper/tally_test.go @@ -375,7 +375,7 @@ func TestTallyJailedValidator(t *testing.T) { _ = staking.EndBlocker(ctx, sk) - sk.Jail(ctx, sdk.ConsAddress(val2.ConsPubKey.Address())) + sk.Jail(ctx, sdk.ConsAddress(val2.GetConsPubKey().Address())) tp := TestProposal proposal, err := keeper.SubmitProposal(ctx, tp) diff --git a/x/gov/keeper/test_common.go b/x/gov/keeper/test_common.go index 897ad8b05da5..bb57f7ab0275 100644 --- a/x/gov/keeper/test_common.go +++ b/x/gov/keeper/test_common.go @@ -151,7 +151,7 @@ func createTestInput( bankKeeper := bank.NewBaseKeeper(cdc, keyBank, accountKeeper, pk.Subspace(bank.DefaultParamspace), blacklistedAddrs) supplyKeeper := supply.NewKeeper(cdc, keySupply, accountKeeper, bankKeeper, maccPerms) - sk := staking.NewKeeper(cdc, keyStaking, bankKeeper, supplyKeeper, pk.Subspace(staking.DefaultParamspace)) + sk := staking.NewKeeper(staking.ModuleCdc, keyStaking, bankKeeper, supplyKeeper, pk.Subspace(staking.DefaultParamspace)) sk.SetParams(ctx, staking.DefaultParams()) rtr := types.NewRouter(). diff --git a/x/gov/test_common.go b/x/gov/test_common.go index c6fe5d7fcbba..a01a79c6566d 100644 --- a/x/gov/test_common.go +++ b/x/gov/test_common.go @@ -81,7 +81,7 @@ func getMockApp( bk := mApp.BankKeeper supplyKeeper := supply.NewKeeper(mApp.Cdc, keySupply, mApp.AccountKeeper, bk, maccPerms) sk := staking.NewKeeper( - mApp.Cdc, keyStaking, bk, supplyKeeper, pk.Subspace(staking.DefaultParamspace), + staking.ModuleCdc, keyStaking, bk, supplyKeeper, pk.Subspace(staking.DefaultParamspace), ) keeper := keep.NewKeeper( diff --git a/x/slashing/app_test.go b/x/slashing/app_test.go index 88ae3bb0b75a..b62d5dcb1385 100644 --- a/x/slashing/app_test.go +++ b/x/slashing/app_test.go @@ -55,7 +55,7 @@ func getMockApp(t *testing.T) (*mock.App, staking.Keeper, Keeper) { staking.BondedPoolName: {supply.Burner, supply.Staking}, } supplyKeeper := supply.NewKeeper(mapp.Cdc, keySupply, mapp.AccountKeeper, mapp.BankKeeper, maccPerms) - stakingKeeper := staking.NewKeeper(mapp.Cdc, keyStaking, mapp.BankKeeper, supplyKeeper, mapp.ParamsKeeper.Subspace(staking.DefaultParamspace)) + stakingKeeper := staking.NewKeeper(staking.ModuleCdc, keyStaking, mapp.BankKeeper, supplyKeeper, mapp.ParamsKeeper.Subspace(staking.DefaultParamspace)) keeper := NewKeeper(mapp.Cdc, keySlashing, stakingKeeper, mapp.ParamsKeeper.Subspace(DefaultParamspace)) mapp.Router().AddRoute(staking.RouterKey, staking.NewHandler(stakingKeeper)) mapp.Router().AddRoute(RouterKey, NewHandler(keeper)) @@ -158,7 +158,7 @@ func TestSlashingMsgs(t *testing.T) { require.Equal(t, sdk.ValAddress(addr1), validator.OperatorAddress) require.Equal(t, sdk.Bonded, validator.Status) require.True(sdk.IntEq(t, bondTokens, validator.BondedTokens())) - unjailMsg := MsgUnjail{ValidatorAddr: sdk.ValAddress(validator.ConsPubKey.Address())} + unjailMsg := MsgUnjail{ValidatorAddr: sdk.ValAddress(validator.GetConsPubKey().Address())} // no signing info yet checkValidatorSigningInfo(t, mapp, keeper, sdk.ConsAddress(addr1), false) diff --git a/x/slashing/internal/keeper/test_common.go b/x/slashing/internal/keeper/test_common.go index 79a436b2e1df..128c7438a7f9 100644 --- a/x/slashing/internal/keeper/test_common.go +++ b/x/slashing/internal/keeper/test_common.go @@ -104,7 +104,7 @@ func CreateTestInput(t *testing.T, defaults types.Params) (sdk.Context, bank.Kee totalSupply := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, InitTokens.MulRaw(int64(len(Addrs))))) supplyKeeper.SetSupply(ctx, supply.NewSupply(totalSupply)) - sk := staking.NewKeeper(cdc, keyStaking, bk, supplyKeeper, paramsKeeper.Subspace(staking.DefaultParamspace)) + sk := staking.NewKeeper(staking.ModuleCdc, keyStaking, bk, supplyKeeper, paramsKeeper.Subspace(staking.DefaultParamspace)) genesis := staking.DefaultGenesisState() // set module accounts diff --git a/x/slashing/internal/types/expected_keepers.go b/x/slashing/internal/types/expected_keepers.go index bf09731a03e6..fe5695eebbf2 100644 --- a/x/slashing/internal/types/expected_keepers.go +++ b/x/slashing/internal/types/expected_keepers.go @@ -51,7 +51,7 @@ type StakingKeeper interface { Delegation(sdk.Context, sdk.AccAddress, sdk.ValAddress) stakingexported.DelegationI // MaxValidators returns the maximum amount of bonded validators - MaxValidators(sdk.Context) uint16 + MaxValidators(sdk.Context) uint32 } // StakingHooks event hooks for staking validator object (noalias) diff --git a/x/staking/alias.go b/x/staking/alias.go index 51c7eecc7087..445ead018e15 100644 --- a/x/staking/alias.go +++ b/x/staking/alias.go @@ -123,6 +123,7 @@ var ( ErrNeitherShareMsgsGiven = types.ErrNeitherShareMsgsGiven ErrInvalidHistoricalInfo = types.ErrInvalidHistoricalInfo ErrNoHistoricalInfo = types.ErrNoHistoricalInfo + ErrEmptyValidatorPubKey = types.ErrEmptyValidatorPubKey NewGenesisState = types.NewGenesisState DefaultGenesisState = types.DefaultGenesisState NewMultiStakingHooks = types.NewMultiStakingHooks @@ -175,6 +176,7 @@ var ( NewDescription = types.NewDescription // variable aliases + NewCodec = types.NewCodec ModuleCdc = types.ModuleCdc LastValidatorPowerKey = types.LastValidatorPowerKey LastTotalPowerKey = types.LastTotalPowerKey @@ -199,6 +201,7 @@ var ( type ( Keeper = keeper.Keeper + Codec = types.Codec Commission = types.Commission CommissionRates = types.CommissionRates DVPair = types.DVPair diff --git a/x/staking/app_test.go b/x/staking/app_test.go index 586b5d95d757..28bd943edce0 100644 --- a/x/staking/app_test.go +++ b/x/staking/app_test.go @@ -42,7 +42,7 @@ func getMockApp(t *testing.T) (*mock.App, Keeper) { types.BondedPoolName: {supply.Burner, supply.Staking}, } supplyKeeper := supply.NewKeeper(mApp.Cdc, keySupply, mApp.AccountKeeper, mApp.BankKeeper, maccPerms) - keeper := NewKeeper(mApp.Cdc, keyStaking, mApp.BankKeeper, supplyKeeper, mApp.ParamsKeeper.Subspace(DefaultParamspace)) + keeper := NewKeeper(ModuleCdc, keyStaking, mApp.BankKeeper, supplyKeeper, mApp.ParamsKeeper.Subspace(DefaultParamspace)) mApp.Router().AddRoute(RouterKey, NewHandler(keeper)) mApp.SetEndBlocker(getEndBlocker(keeper)) diff --git a/x/staking/client/cli/query.go b/x/staking/client/cli/query.go index 14a60c49bc04..a38c004fde42 100644 --- a/x/staking/client/cli/query.go +++ b/x/staking/client/cli/query.go @@ -77,7 +77,12 @@ $ %s query staking validator cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhff return fmt.Errorf("no validator found with address %s", addr) } - return cliCtx.PrintOutput(types.MustUnmarshalValidator(cdc, res)) + validator, err := types.UnmarshalValidator(types.ModuleCdc, res) + if err != nil { + return err + } + + return cliCtx.PrintOutput(validator) }, } } @@ -107,7 +112,12 @@ $ %s query staking validators var validators types.Validators for _, kv := range resKVs { - validators = append(validators, types.MustUnmarshalValidator(cdc, kv.Value)) + validator, err := types.UnmarshalValidator(types.ModuleCdc, kv.Value) + if err != nil { + return err + } + + validators = append(validators, validator) } return cliCtx.PrintOutput(validators) @@ -380,7 +390,12 @@ $ %s query staking unbonding-delegation cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld7 return err } - return cliCtx.PrintOutput(types.MustUnmarshalUBD(cdc, res)) + ubd, err := types.UnmarshalUBD(types.ModuleCdc, res) + if err != nil { + return err + } + + return cliCtx.PrintOutput(ubd) }, } } diff --git a/x/staking/genesis.go b/x/staking/genesis.go index 5c558ca4259b..8a2ecce10740 100644 --- a/x/staking/genesis.go +++ b/x/staking/genesis.go @@ -210,17 +210,20 @@ func validateGenesisStateValidators(validators []types.Validator) (err error) { addrMap := make(map[string]bool, len(validators)) for i := 0; i < len(validators); i++ { val := validators[i] - strKey := string(val.ConsPubKey.Bytes()) + strKey := string(val.GetConsPubKey().Bytes()) + if _, ok := addrMap[strKey]; ok { - return fmt.Errorf("duplicate validator in genesis state: moniker %v, address %v", val.Description.Moniker, val.ConsAddress()) + return fmt.Errorf("duplicate validator in genesis state: moniker %v, address %v", val.Description.Moniker, val.GetConsAddr()) } if val.Jailed && val.IsBonded() { - return fmt.Errorf("validator is bonded and jailed in genesis state: moniker %v, address %v", val.Description.Moniker, val.ConsAddress()) + return fmt.Errorf("validator is bonded and jailed in genesis state: moniker %v, address %v", val.Description.Moniker, val.GetConsAddr()) } if val.DelegatorShares.IsZero() && !val.IsUnbonding() { return fmt.Errorf("bonded/unbonded genesis validator cannot have zero delegator shares, validator: %v", val) } + addrMap[strKey] = true } + return } diff --git a/x/staking/genesis_test.go b/x/staking/genesis_test.go index 4f3a7f1d05bf..551239185fca 100644 --- a/x/staking/genesis_test.go +++ b/x/staking/genesis_test.go @@ -25,15 +25,21 @@ func TestInitGenesis(t *testing.T) { validators := make([]Validator, 2) var delegations []Delegation + pk0, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, keep.PKs[0]) + require.NoError(t, err) + + pk1, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, keep.PKs[1]) + require.NoError(t, err) + // initialize the validators validators[0].OperatorAddress = sdk.ValAddress(keep.Addrs[0]) - validators[0].ConsPubKey = keep.PKs[0] + validators[0].ConsensusPubkey = pk0 validators[0].Description = NewDescription("hoop", "", "", "", "") validators[0].Status = sdk.Bonded validators[0].Tokens = valTokens validators[0].DelegatorShares = valTokens.ToDec() validators[1].OperatorAddress = sdk.ValAddress(keep.Addrs[1]) - validators[1].ConsPubKey = keep.PKs[1] + validators[1].ConsensusPubkey = pk1 validators[1].Description = NewDescription("bloop", "", "", "", "") validators[1].Status = sdk.Bonded validators[1].Tokens = valTokens diff --git a/x/staking/handler.go b/x/staking/handler.go index 180bb8008672..e6ed8e3b57c3 100644 --- a/x/staking/handler.go +++ b/x/staking/handler.go @@ -3,6 +3,7 @@ package staking import ( "time" + gogotypes "github.com/gogo/protobuf/types" tmstrings "github.com/tendermint/tendermint/libs/strings" tmtypes "github.com/tendermint/tendermint/types" @@ -47,7 +48,12 @@ func handleMsgCreateValidator(ctx sdk.Context, msg types.MsgCreateValidator, k k return nil, ErrValidatorOwnerExists } - if _, found := k.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(msg.PubKey)); found { + pk, err := sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeConsPub, msg.Pubkey) + if err != nil { + return nil, err + } + + if _, found := k.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(pk)); found { return nil, ErrValidatorPubKeyExists } @@ -60,21 +66,22 @@ func handleMsgCreateValidator(ctx sdk.Context, msg types.MsgCreateValidator, k k } if ctx.ConsensusParams() != nil { - tmPubKey := tmtypes.TM2PB.PubKey(msg.PubKey) + tmPubKey := tmtypes.TM2PB.PubKey(pk) if !tmstrings.StringInSlice(tmPubKey.Type, ctx.ConsensusParams().Validator.PubKeyTypes) { return nil, sdkerrors.Wrapf( ErrValidatorPubKeyTypeNotSupported, - "got: %s, valid: %s", tmPubKey.Type, ctx.ConsensusParams().Validator.PubKeyTypes, + "got: %s, expected: %s", tmPubKey.Type, ctx.ConsensusParams().Validator.PubKeyTypes, ) } } - validator := NewValidator(msg.ValidatorAddress, msg.PubKey, msg.Description) + validator := NewValidator(msg.ValidatorAddress, pk, msg.Description) commission := NewCommissionWithTime( msg.Commission.Rate, msg.Commission.MaxRate, msg.Commission.MaxChangeRate, ctx.BlockHeader().Time, ) - validator, err := validator.SetInitialCommission(commission) + + validator, err = validator.SetInitialCommission(commission) if err != nil { return nil, err } @@ -217,7 +224,12 @@ func handleMsgUndelegate(ctx sdk.Context, msg types.MsgUndelegate, k keeper.Keep return nil, err } - completionTimeBz := types.ModuleCdc.MustMarshalBinaryLengthPrefixed(completionTime) + ts, err := gogotypes.TimestampProto(completionTime) + if err != nil { + return nil, ErrBadRedelegationAddr + } + + completionTimeBz := types.ModuleCdc.MustMarshalBinaryLengthPrefixed(ts) ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( types.EventTypeUnbond, @@ -254,7 +266,12 @@ func handleMsgBeginRedelegate(ctx sdk.Context, msg types.MsgBeginRedelegate, k k return nil, err } - completionTimeBz := types.ModuleCdc.MustMarshalBinaryLengthPrefixed(completionTime) + ts, err := gogotypes.TimestampProto(completionTime) + if err != nil { + return nil, ErrBadRedelegationAddr + } + + completionTimeBz := types.ModuleCdc.MustMarshalBinaryLengthPrefixed(ts) ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( types.EventTypeRedelegate, diff --git a/x/staking/handler_test.go b/x/staking/handler_test.go index 75e9242e07c7..64a5d579f99d 100644 --- a/x/staking/handler_test.go +++ b/x/staking/handler_test.go @@ -5,9 +5,9 @@ import ( "testing" "time" + gogotypes "github.com/gogo/protobuf/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto/secp256k1" tmtypes "github.com/tendermint/tendermint/types" @@ -90,8 +90,11 @@ func TestValidatorByPowerIndex(t *testing.T) { require.NoError(t, err) require.NotNil(t, res) - var finishTime time.Time - types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, &finishTime) + ts := &gogotypes.Timestamp{} + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) + + finishTime, err := gogotypes.TimestampFromProto(ts) + require.NoError(t, err) ctx = ctx.WithBlockTime(finishTime) EndBlocker(ctx, keeper) @@ -121,7 +124,7 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) { require.True(t, found) assert.Equal(t, sdk.Bonded, validator.Status) assert.Equal(t, addr1, validator.OperatorAddress) - assert.Equal(t, pk1, validator.ConsPubKey) + assert.Equal(t, pk1, validator.GetConsPubKey()) assert.Equal(t, valTokens, validator.BondedTokens()) assert.Equal(t, valTokens.ToDec(), validator.DelegatorShares) assert.Equal(t, Description{}, validator.Description) @@ -153,7 +156,7 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) { require.True(t, found) assert.Equal(t, sdk.Bonded, validator.Status) assert.Equal(t, addr2, validator.OperatorAddress) - assert.Equal(t, pk2, validator.ConsPubKey) + assert.Equal(t, pk2, validator.GetConsPubKey()) assert.True(sdk.IntEq(t, valTokens, validator.Tokens)) assert.True(sdk.DecEq(t, valTokens.ToDec(), validator.DelegatorShares)) assert.Equal(t, Description{}, validator.Description) @@ -225,8 +228,12 @@ func TestLegacyValidatorDelegations(t *testing.T) { require.NoError(t, err) require.NotNil(t, res) - var finishTime time.Time - types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, &finishTime) + ts := &gogotypes.Timestamp{} + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) + + finishTime, err := gogotypes.TimestampFromProto(ts) + require.NoError(t, err) + ctx = ctx.WithBlockTime(finishTime) EndBlocker(ctx, keeper) @@ -459,8 +466,11 @@ func TestIncrementsMsgUnbond(t *testing.T) { require.NoError(t, err) require.NotNil(t, res) - var finishTime time.Time - types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, &finishTime) + ts := &gogotypes.Timestamp{} + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) + + finishTime, err := gogotypes.TimestampFromProto(ts) + require.NoError(t, err) ctx = ctx.WithBlockTime(finishTime) EndBlocker(ctx, keeper) @@ -572,8 +582,11 @@ func TestMultipleMsgCreateValidator(t *testing.T) { require.NoError(t, err) require.NotNil(t, res) - var finishTime time.Time - types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, &finishTime) + ts := &gogotypes.Timestamp{} + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) + + _, err = gogotypes.TimestampFromProto(ts) + require.NoError(t, err) // adds validator into unbonding queue EndBlocker(ctx, keeper) @@ -626,8 +639,11 @@ func TestMultipleMsgDelegate(t *testing.T) { require.NoError(t, err) require.NotNil(t, res) - var finishTime time.Time - types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, &finishTime) + ts := &gogotypes.Timestamp{} + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) + + finishTime, err := gogotypes.TimestampFromProto(ts) + require.NoError(t, err) ctx = ctx.WithBlockTime(finishTime) EndBlocker(ctx, keeper) @@ -661,8 +677,11 @@ func TestJailValidator(t *testing.T) { require.NoError(t, err) require.NotNil(t, res) - var finishTime time.Time - types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, &finishTime) + ts := &gogotypes.Timestamp{} + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) + + finishTime, err := gogotypes.TimestampFromProto(ts) + require.NoError(t, err) ctx = ctx.WithBlockTime(finishTime) EndBlocker(ctx, keeper) @@ -677,7 +696,12 @@ func TestJailValidator(t *testing.T) { res, err = handleMsgUndelegate(ctx, msgUndelegateDelegator, keeper) require.NoError(t, err) require.NotNil(t, res) - types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, &finishTime) + + ts = &gogotypes.Timestamp{} + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) + + finishTime, err = gogotypes.TimestampFromProto(ts) + require.NoError(t, err) ctx = ctx.WithBlockTime(finishTime) EndBlocker(ctx, keeper) @@ -720,8 +744,11 @@ func TestValidatorQueue(t *testing.T) { require.NoError(t, err) require.NotNil(t, res) - var finishTime time.Time - types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, &finishTime) + ts := &gogotypes.Timestamp{} + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) + + finishTime, err := gogotypes.TimestampFromProto(ts) + require.NoError(t, err) ctx = ctx.WithBlockTime(finishTime) EndBlocker(ctx, keeper) @@ -821,8 +848,12 @@ func TestUnbondingFromUnbondingValidator(t *testing.T) { require.NotNil(t, res) // change the ctx to Block Time one second before the validator would have unbonded - var finishTime time.Time - types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, &finishTime) + ts := &gogotypes.Timestamp{} + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) + + finishTime, err := gogotypes.TimestampFromProto(ts) + require.NoError(t, err) + ctx = ctx.WithBlockTime(finishTime.Add(time.Second * -1)) // unbond the delegator from the validator diff --git a/x/staking/keeper/delegation.go b/x/staking/keeper/delegation.go index 219beef71271..9524c4feffa8 100644 --- a/x/staking/keeper/delegation.go +++ b/x/staking/keeper/delegation.go @@ -120,8 +120,9 @@ func (k Keeper) GetUnbondingDelegations(ctx sdk.Context, delegator sdk.AccAddres } // return a unbonding delegation -func (k Keeper) GetUnbondingDelegation(ctx sdk.Context, - delAddr sdk.AccAddress, valAddr sdk.ValAddress) (ubd types.UnbondingDelegation, found bool) { +func (k Keeper) GetUnbondingDelegation( + ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress, +) (ubd types.UnbondingDelegation, found bool) { store := ctx.KVStore(k.storeKey) key := types.GetUBDKey(delAddr, valAddr) @@ -194,9 +195,10 @@ func (k Keeper) RemoveUnbondingDelegation(ctx sdk.Context, ubd types.UnbondingDe // SetUnbondingDelegationEntry adds an entry to the unbonding delegation at // the given addresses. It creates the unbonding delegation if it does not exist -func (k Keeper) SetUnbondingDelegationEntry(ctx sdk.Context, - delegatorAddr sdk.AccAddress, validatorAddr sdk.ValAddress, - creationHeight int64, minTime time.Time, balance sdk.Int) types.UnbondingDelegation { +func (k Keeper) SetUnbondingDelegationEntry( + ctx sdk.Context, delegatorAddr sdk.AccAddress, validatorAddr sdk.ValAddress, + creationHeight int64, minTime time.Time, balance sdk.Int, +) types.UnbondingDelegation { ubd, found := k.GetUnbondingDelegation(ctx, delegatorAddr, validatorAddr) if found { @@ -204,6 +206,7 @@ func (k Keeper) SetUnbondingDelegationEntry(ctx sdk.Context, } else { ubd = types.NewUnbondingDelegation(delegatorAddr, validatorAddr, creationHeight, minTime, balance) } + k.SetUnbondingDelegation(ctx, ubd) return ubd } @@ -218,14 +221,16 @@ func (k Keeper) GetUBDQueueTimeSlice(ctx sdk.Context, timestamp time.Time) (dvPa if bz == nil { return []types.DVPair{} } - k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &dvPairs) - return dvPairs + + pairs := types.DVPairs{} + k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &pairs) + return pairs.Pairs } // Sets a specific unbonding queue timeslice. func (k Keeper) SetUBDQueueTimeSlice(ctx sdk.Context, timestamp time.Time, keys []types.DVPair) { store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinaryLengthPrefixed(keys) + bz := k.cdc.MustMarshalBinaryLengthPrefixed(&types.DVPairs{Pairs: keys}) store.Set(types.GetUnbondingDelegationTimeKey(timestamp), bz) } @@ -252,19 +257,20 @@ func (k Keeper) UBDQueueIterator(ctx sdk.Context, endTime time.Time) sdk.Iterato // Returns a concatenated list of all the timeslices inclusively previous to // currTime, and deletes the timeslices from the queue -func (k Keeper) DequeueAllMatureUBDQueue(ctx sdk.Context, - currTime time.Time) (matureUnbonds []types.DVPair) { - +func (k Keeper) DequeueAllMatureUBDQueue(ctx sdk.Context, currTime time.Time) (matureUnbonds []types.DVPair) { store := ctx.KVStore(k.storeKey) + // gets an iterator for all timeslices from time 0 until the current Blockheader time unbondingTimesliceIterator := k.UBDQueueIterator(ctx, ctx.BlockHeader().Time) for ; unbondingTimesliceIterator.Valid(); unbondingTimesliceIterator.Next() { - timeslice := []types.DVPair{} + timeslice := types.DVPairs{} value := unbondingTimesliceIterator.Value() k.cdc.MustUnmarshalBinaryLengthPrefixed(value, ×lice) - matureUnbonds = append(matureUnbonds, timeslice...) + + matureUnbonds = append(matureUnbonds, timeslice.Pairs...) store.Delete(unbondingTimesliceIterator.Key()) } + return matureUnbonds } @@ -404,14 +410,16 @@ func (k Keeper) GetRedelegationQueueTimeSlice(ctx sdk.Context, timestamp time.Ti if bz == nil { return []types.DVVTriplet{} } - k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &dvvTriplets) - return dvvTriplets + + triplets := types.DVVTriplets{} + k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &triplets) + return triplets.Triplets } // Sets a specific redelegation queue timeslice. func (k Keeper) SetRedelegationQueueTimeSlice(ctx sdk.Context, timestamp time.Time, keys []types.DVVTriplet) { store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinaryLengthPrefixed(keys) + bz := k.cdc.MustMarshalBinaryLengthPrefixed(&types.DVVTriplets{Triplets: keys}) store.Set(types.GetRedelegationTimeKey(timestamp), bz) } @@ -443,15 +451,18 @@ func (k Keeper) RedelegationQueueIterator(ctx sdk.Context, endTime time.Time) sd // currTime, and deletes the timeslices from the queue func (k Keeper) DequeueAllMatureRedelegationQueue(ctx sdk.Context, currTime time.Time) (matureRedelegations []types.DVVTriplet) { store := ctx.KVStore(k.storeKey) + // gets an iterator for all timeslices from time 0 until the current Blockheader time redelegationTimesliceIterator := k.RedelegationQueueIterator(ctx, ctx.BlockHeader().Time) for ; redelegationTimesliceIterator.Valid(); redelegationTimesliceIterator.Next() { - timeslice := []types.DVVTriplet{} + timeslice := types.DVVTriplets{} value := redelegationTimesliceIterator.Value() k.cdc.MustUnmarshalBinaryLengthPrefixed(value, ×lice) - matureRedelegations = append(matureRedelegations, timeslice...) + + matureRedelegations = append(matureRedelegations, timeslice.Triplets...) store.Delete(redelegationTimesliceIterator.Key()) } + return matureRedelegations } @@ -618,7 +629,7 @@ func (k Keeper) getBeginInfo( return completionTime, height, true case validator.IsUnbonding(): - return validator.UnbondingCompletionTime, validator.UnbondingHeight, false + return validator.UnbondingTime, validator.UnbondingHeight, false default: panic(fmt.Sprintf("unknown validator status: %s", validator.Status)) diff --git a/x/staking/keeper/delegation_test.go b/x/staking/keeper/delegation_test.go index f2832dd498d2..eda1a550cd67 100644 --- a/x/staking/keeper/delegation_test.go +++ b/x/staking/keeper/delegation_test.go @@ -233,7 +233,7 @@ func TestUnbondingDelegationsMaxEntries(t *testing.T) { // should all pass var completionTime time.Time - for i := uint16(0); i < maxEntries; i++ { + for i := uint32(0); i < maxEntries; i++ { var err error completionTime, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], sdk.NewDec(1)) require.NoError(t, err) @@ -414,7 +414,7 @@ func TestUndelegateFromUnbondingValidator(t *testing.T) { require.True(t, found) require.Equal(t, blockHeight, validator.UnbondingHeight) params := keeper.GetParams(ctx) - require.True(t, blockTime.Add(params.UnbondingTime).Equal(validator.UnbondingCompletionTime)) + require.True(t, blockTime.Add(params.UnbondingTime).Equal(validator.UnbondingTime)) blockHeight2 := int64(20) blockTime2 := time.Unix(444, 0).UTC() @@ -489,10 +489,10 @@ func TestUndelegateFromUnbondedValidator(t *testing.T) { require.True(t, found) require.Equal(t, ctx.BlockHeight(), validator.UnbondingHeight) params := keeper.GetParams(ctx) - require.True(t, ctx.BlockHeader().Time.Add(params.UnbondingTime).Equal(validator.UnbondingCompletionTime)) + require.True(t, ctx.BlockHeader().Time.Add(params.UnbondingTime).Equal(validator.UnbondingTime)) // unbond the validator - ctx = ctx.WithBlockTime(validator.UnbondingCompletionTime) + ctx = ctx.WithBlockTime(validator.UnbondingTime) keeper.UnbondAllMatureValidatorQueue(ctx) // Make sure validator is still in state because there is still an outstanding delegation @@ -579,7 +579,7 @@ func TestUnbondingAllDelegationFromValidator(t *testing.T) { require.Equal(t, validator.Status, sdk.Unbonding) // unbond the validator - ctx = ctx.WithBlockTime(validator.UnbondingCompletionTime) + ctx = ctx.WithBlockTime(validator.UnbondingTime) keeper.UnbondAllMatureValidatorQueue(ctx) // validator should now be deleted from state @@ -733,7 +733,7 @@ func TestRedelegationMaxEntries(t *testing.T) { // redelegations should pass var completionTime time.Time - for i := uint16(0); i < maxEntries; i++ { + for i := uint32(0); i < maxEntries; i++ { var err error completionTime, err = keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1], sdk.NewDec(1)) require.NoError(t, err) @@ -863,7 +863,7 @@ func TestRedelegateFromUnbondingValidator(t *testing.T) { require.True(t, found) require.Equal(t, blockHeight, validator.UnbondingHeight) params := keeper.GetParams(ctx) - require.True(t, blockTime.Add(params.UnbondingTime).Equal(validator.UnbondingCompletionTime)) + require.True(t, blockTime.Add(params.UnbondingTime).Equal(validator.UnbondingTime)) //change the context header = ctx.BlockHeader() @@ -940,7 +940,7 @@ func TestRedelegateFromUnbondedValidator(t *testing.T) { require.True(t, found) require.Equal(t, ctx.BlockHeight(), validator.UnbondingHeight) params := keeper.GetParams(ctx) - require.True(t, ctx.BlockHeader().Time.Add(params.UnbondingTime).Equal(validator.UnbondingCompletionTime)) + require.True(t, ctx.BlockHeader().Time.Add(params.UnbondingTime).Equal(validator.UnbondingTime)) // unbond the validator keeper.unbondingToUnbonded(ctx, validator) diff --git a/x/staking/keeper/historical_info_test.go b/x/staking/keeper/historical_info_test.go index 068771984084..db372bce2cae 100644 --- a/x/staking/keeper/historical_info_test.go +++ b/x/staking/keeper/historical_info_test.go @@ -4,12 +4,11 @@ import ( "sort" "testing" - abci "github.com/tendermint/tendermint/abci/types" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" ) func TestHistoricalInfo(t *testing.T) { @@ -27,7 +26,7 @@ func TestHistoricalInfo(t *testing.T) { recv, found := keeper.GetHistoricalInfo(ctx, 2) require.True(t, found, "HistoricalInfo not found after set") require.Equal(t, hi, recv, "HistoricalInfo not equal") - require.True(t, sort.IsSorted(recv.ValSet), "HistoricalInfo validators is not sorted") + require.True(t, sort.IsSorted(types.Validators(recv.Valset)), "HistoricalInfo validators is not sorted") keeper.DeleteHistoricalInfo(ctx, 2) @@ -91,7 +90,7 @@ func TestTrackHistoricalInfo(t *testing.T) { // Check HistoricalInfo at height 10 is persisted expected := types.HistoricalInfo{ Header: header, - ValSet: vals, + Valset: vals, } recv, found = k.GetHistoricalInfo(ctx, 10) require.True(t, found, "GetHistoricalInfo failed after BeginBlock") diff --git a/x/staking/keeper/keeper.go b/x/staking/keeper/keeper.go index 412f6a3a8464..ef7aab43557f 100644 --- a/x/staking/keeper/keeper.go +++ b/x/staking/keeper/keeper.go @@ -23,7 +23,7 @@ var _ types.DelegationSet = Keeper{} // keeper of the staking store type Keeper struct { storeKey sdk.StoreKey - cdc *codec.Codec + cdc codec.Marshaler bankKeeper types.BankKeeper supplyKeeper types.SupplyKeeper hooks types.StakingHooks @@ -34,7 +34,7 @@ type Keeper struct { // NewKeeper creates a new staking Keeper instance func NewKeeper( - cdc *codec.Codec, key sdk.StoreKey, bk types.BankKeeper, sk types.SupplyKeeper, ps params.Subspace, + cdc codec.Marshaler, key sdk.StoreKey, bk types.BankKeeper, sk types.SupplyKeeper, ps params.Subspace, ) Keeper { // ensure bonded and not bonded module accounts are set @@ -73,19 +73,21 @@ func (k *Keeper) SetHooks(sh types.StakingHooks) *Keeper { } // Load the last total validator power. -func (k Keeper) GetLastTotalPower(ctx sdk.Context) (power sdk.Int) { +func (k Keeper) GetLastTotalPower(ctx sdk.Context) sdk.Int { store := ctx.KVStore(k.storeKey) - b := store.Get(types.LastTotalPowerKey) - if b == nil { + bz := store.Get(types.LastTotalPowerKey) + if bz == nil { return sdk.ZeroInt() } - k.cdc.MustUnmarshalBinaryLengthPrefixed(b, &power) - return + + ip := sdk.IntProto{} + k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &ip) + return ip.Int } // Set the last total validator power. func (k Keeper) SetLastTotalPower(ctx sdk.Context, power sdk.Int) { store := ctx.KVStore(k.storeKey) - b := k.cdc.MustMarshalBinaryLengthPrefixed(power) - store.Set(types.LastTotalPowerKey, b) + bz := k.cdc.MustMarshalBinaryLengthPrefixed(&sdk.IntProto{Int: power}) + store.Set(types.LastTotalPowerKey, bz) } diff --git a/x/staking/keeper/params.go b/x/staking/keeper/params.go index 11f4b57bc55b..e50e6ccd6455 100644 --- a/x/staking/keeper/params.go +++ b/x/staking/keeper/params.go @@ -25,21 +25,21 @@ func (k Keeper) UnbondingTime(ctx sdk.Context) (res time.Duration) { } // MaxValidators - Maximum number of validators -func (k Keeper) MaxValidators(ctx sdk.Context) (res uint16) { +func (k Keeper) MaxValidators(ctx sdk.Context) (res uint32) { k.paramstore.Get(ctx, types.KeyMaxValidators, &res) return } // MaxEntries - Maximum number of simultaneous unbonding // delegations or redelegations (per pair/trio) -func (k Keeper) MaxEntries(ctx sdk.Context) (res uint16) { +func (k Keeper) MaxEntries(ctx sdk.Context) (res uint32) { k.paramstore.Get(ctx, types.KeyMaxEntries, &res) return } // HistoricalEntries = number of historical info entries // to persist in store -func (k Keeper) HistoricalEntries(ctx sdk.Context) (res uint16) { +func (k Keeper) HistoricalEntries(ctx sdk.Context) (res uint32) { k.paramstore.Get(ctx, types.KeyHistoricalEntries, &res) return } diff --git a/x/staking/keeper/query_utils.go b/x/staking/keeper/query_utils.go index 336bb842ab9e..e29e73c899ef 100644 --- a/x/staking/keeper/query_utils.go +++ b/x/staking/keeper/query_utils.go @@ -6,9 +6,11 @@ import ( ) // Return all validators that a delegator is bonded to. If maxRetrieve is supplied, the respective amount will be returned. -func (k Keeper) GetDelegatorValidators(ctx sdk.Context, delegatorAddr sdk.AccAddress, - maxRetrieve uint16) (validators []types.Validator) { - validators = make([]types.Validator, maxRetrieve) +func (k Keeper) GetDelegatorValidators( + ctx sdk.Context, delegatorAddr sdk.AccAddress, maxRetrieve uint32, +) []types.Validator { + + validators := make([]types.Validator, maxRetrieve) store := ctx.KVStore(k.storeKey) delegatorPrefixKey := types.GetDelegationsKey(delegatorAddr) @@ -23,15 +25,18 @@ func (k Keeper) GetDelegatorValidators(ctx sdk.Context, delegatorAddr sdk.AccAdd if !found { panic(types.ErrNoValidatorFound) } + validators[i] = validator i++ } + return validators[:i] // trim } // return a validator that a delegator is bonded to -func (k Keeper) GetDelegatorValidator(ctx sdk.Context, delegatorAddr sdk.AccAddress, - validatorAddr sdk.ValAddress) (validator types.Validator, err error) { +func (k Keeper) GetDelegatorValidator( + ctx sdk.Context, delegatorAddr sdk.AccAddress, validatorAddr sdk.ValAddress, +) (validator types.Validator, err error) { delegation, found := k.GetDelegation(ctx, delegatorAddr, validatorAddr) if !found { @@ -42,7 +47,8 @@ func (k Keeper) GetDelegatorValidator(ctx sdk.Context, delegatorAddr sdk.AccAddr if !found { panic(types.ErrNoValidatorFound) } - return + + return validator, nil } //_____________________________________________________________________________________ @@ -85,9 +91,9 @@ func (k Keeper) GetAllUnbondingDelegations(ctx sdk.Context, delegator sdk.AccAdd } // return all redelegations for a delegator -func (k Keeper) GetAllRedelegations(ctx sdk.Context, delegator sdk.AccAddress, - srcValAddress, dstValAddress sdk.ValAddress) ( - redelegations []types.Redelegation) { +func (k Keeper) GetAllRedelegations( + ctx sdk.Context, delegator sdk.AccAddress, srcValAddress, dstValAddress sdk.ValAddress, +) []types.Redelegation { store := ctx.KVStore(k.storeKey) delegatorPrefixKey := types.GetREDsKey(delegator) @@ -97,6 +103,8 @@ func (k Keeper) GetAllRedelegations(ctx sdk.Context, delegator sdk.AccAddress, srcValFilter := !(srcValAddress.Empty()) dstValFilter := !(dstValAddress.Empty()) + redelegations := []types.Redelegation{} + for ; iterator.Valid(); iterator.Next() { redelegation := types.MustUnmarshalRED(k.cdc, iterator.Value()) if srcValFilter && !(srcValAddress.Equals(redelegation.ValidatorSrcAddress)) { @@ -105,7 +113,9 @@ func (k Keeper) GetAllRedelegations(ctx sdk.Context, delegator sdk.AccAddress, if dstValFilter && !(dstValAddress.Equals(redelegation.ValidatorDstAddress)) { continue } + redelegations = append(redelegations, redelegation) } + return redelegations } diff --git a/x/staking/keeper/test_common.go b/x/staking/keeper/test_common.go index 65efabe4e25c..d24365084221 100644 --- a/x/staking/keeper/test_common.go +++ b/x/staking/keeper/test_common.go @@ -8,7 +8,6 @@ import ( "testing" "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/ed25519" @@ -50,7 +49,7 @@ var ( // intended to be used with require/assert: require.True(ValEq(...)) func ValEq(t *testing.T, exp, got types.Validator) (*testing.T, bool, string, types.Validator, types.Validator) { - return t, exp.TestEquivalent(got), "expected:\t%v\ngot:\t\t%v", exp, got + return t, exp.MinEqual(got), "expected:\n%v\ngot:\n%v", exp, got } //_______________________________________________________________________________________ @@ -147,7 +146,7 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context supplyKeeper.SetSupply(ctx, supply.NewSupply(totalSupply)) - keeper := NewKeeper(cdc, keyStaking, bk, supplyKeeper, pk.Subspace(DefaultParamspace)) + keeper := NewKeeper(types.ModuleCdc, keyStaking, bk, supplyKeeper, pk.Subspace(DefaultParamspace)) keeper.SetParams(ctx, types.DefaultParams()) // set module accounts @@ -273,12 +272,15 @@ func TestingUpdateValidator(keeper Keeper, ctx sdk.Context, validator types.Vali } return validator } + cachectx, _ := ctx.CacheContext() keeper.ApplyAndReturnValidatorSetUpdates(cachectx) + validator, found := keeper.GetValidator(cachectx, validator.OperatorAddress) if !found { panic("validator expected but not found") } + return validator } diff --git a/x/staking/keeper/val_state_change.go b/x/staking/keeper/val_state_change.go index 101bc139215a..e05182e92876 100644 --- a/x/staking/keeper/val_state_change.go +++ b/x/staking/keeper/val_state_change.go @@ -5,6 +5,7 @@ import ( "fmt" "sort" + gogotypes "github.com/gogo/protobuf/types" abci "github.com/tendermint/tendermint/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -137,7 +138,7 @@ func (k Keeper) ApplyAndReturnValidatorSetUpdates(ctx sdk.Context) (updates []ab oldPowerBytes, found := last[valAddrBytes] newPower := validator.ConsensusPower() - newPowerBytes := k.cdc.MustMarshalBinaryLengthPrefixed(newPower) + newPowerBytes := k.cdc.MustMarshalBinaryLengthPrefixed(&gogotypes.Int64Value{Value: newPower}) // update the validator set if power has changed if !found || !bytes.Equal(oldPowerBytes, newPowerBytes) { @@ -240,7 +241,6 @@ func (k Keeper) unjailValidator(ctx sdk.Context, validator types.Validator) { // perform all the store operations for when a validator status becomes bonded func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types.Validator { - // delete the validator by power index, as the key will change k.DeleteValidatorByPowerIndex(ctx, validator) @@ -254,14 +254,13 @@ func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types. k.DeleteValidatorQueue(ctx, validator) // trigger hook - k.AfterValidatorBonded(ctx, validator.ConsAddress(), validator.OperatorAddress) + k.AfterValidatorBonded(ctx, validator.GetConsAddr(), validator.OperatorAddress) return validator } // perform all the store operations for when a validator begins unbonding func (k Keeper) beginUnbondingValidator(ctx sdk.Context, validator types.Validator) types.Validator { - params := k.GetParams(ctx) // delete the validator by power index, as the key will change @@ -275,7 +274,7 @@ func (k Keeper) beginUnbondingValidator(ctx sdk.Context, validator types.Validat validator = validator.UpdateStatus(sdk.Unbonding) // set the unbonding completion time and completion height appropriately - validator.UnbondingCompletionTime = ctx.BlockHeader().Time.Add(params.UnbondingTime) + validator.UnbondingTime = ctx.BlockHeader().Time.Add(params.UnbondingTime) validator.UnbondingHeight = ctx.BlockHeader().Height // save the now unbonded validator record and power index @@ -286,7 +285,7 @@ func (k Keeper) beginUnbondingValidator(ctx sdk.Context, validator types.Validat k.InsertValidatorQueue(ctx, validator) // trigger hook - k.AfterValidatorBeginUnbonding(ctx, validator.ConsAddress(), validator.OperatorAddress) + k.AfterValidatorBeginUnbonding(ctx, validator.GetConsAddr(), validator.OperatorAddress) return validator } diff --git a/x/staking/keeper/validator.go b/x/staking/keeper/validator.go index 48ecbb384313..efc0ff517e9d 100644 --- a/x/staking/keeper/validator.go +++ b/x/staking/keeper/validator.go @@ -5,6 +5,8 @@ import ( "fmt" "time" + gogotypes "github.com/gogo/protobuf/types" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/staking/types" ) @@ -94,8 +96,7 @@ func (k Keeper) SetValidator(ctx sdk.Context, validator types.Validator) { // validator index func (k Keeper) SetValidatorByConsAddr(ctx sdk.Context, validator types.Validator) { store := ctx.KVStore(k.storeKey) - consAddr := sdk.ConsAddress(validator.ConsPubKey.Address()) - store.Set(types.GetValidatorByConsAddrKey(consAddr), validator.OperatorAddress) + store.Set(types.GetValidatorByConsAddrKey(validator.GetConsAddr()), validator.OperatorAddress) } // validator index @@ -191,14 +192,16 @@ func (k Keeper) RemoveValidator(ctx sdk.Context, address sdk.ValAddress) { panic("validator being removed should never have positive tokens") } + valConsAddr := validator.GetConsAddr() + // delete the old validator record store := ctx.KVStore(k.storeKey) store.Delete(types.GetValidatorKey(address)) - store.Delete(types.GetValidatorByConsAddrKey(sdk.ConsAddress(validator.ConsPubKey.Address()))) + store.Delete(types.GetValidatorByConsAddrKey(valConsAddr)) store.Delete(types.GetValidatorsByPowerIndexKey(validator)) // call hooks - k.AfterValidatorRemoved(ctx, validator.ConsAddress(), validator.OperatorAddress) + k.AfterValidatorRemoved(ctx, valConsAddr, validator.OperatorAddress) } // get groups of validators @@ -213,11 +216,12 @@ func (k Keeper) GetAllValidators(ctx sdk.Context) (validators []types.Validator) validator := types.MustUnmarshalValidator(k.cdc, iterator.Value()) validators = append(validators, validator) } + return validators } // return a given amount of all the validators -func (k Keeper) GetValidators(ctx sdk.Context, maxRetrieve uint16) (validators []types.Validator) { +func (k Keeper) GetValidators(ctx sdk.Context, maxRetrieve uint32) (validators []types.Validator) { store := ctx.KVStore(k.storeKey) validators = make([]types.Validator, maxRetrieve) @@ -230,6 +234,7 @@ func (k Keeper) GetValidators(ctx sdk.Context, maxRetrieve uint16) (validators [ validators[i] = validator i++ } + return validators[:i] // trim if the array length < maxRetrieve } @@ -271,14 +276,16 @@ func (k Keeper) GetLastValidatorPower(ctx sdk.Context, operator sdk.ValAddress) if bz == nil { return 0 } - k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &power) - return + + intV := gogotypes.Int64Value{} + k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &intV) + return intV.GetValue() } // Set the last validator power. func (k Keeper) SetLastValidatorPower(ctx sdk.Context, operator sdk.ValAddress, power int64) { store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinaryLengthPrefixed(power) + bz := k.cdc.MustMarshalBinaryLengthPrefixed(&gogotypes.Int64Value{Value: power}) store.Set(types.GetLastValidatorPowerKey(operator), bz) } @@ -302,9 +309,10 @@ func (k Keeper) IterateLastValidatorPowers(ctx sdk.Context, handler func(operato defer iter.Close() for ; iter.Valid(); iter.Next() { addr := sdk.ValAddress(iter.Key()[len(types.LastValidatorPowerKey):]) - var power int64 - k.cdc.MustUnmarshalBinaryLengthPrefixed(iter.Value(), &power) - if handler(addr, power) { + intV := &gogotypes.Int64Value{} + + k.cdc.MustUnmarshalBinaryLengthPrefixed(iter.Value(), intV) + if handler(addr, intV.GetValue()) { break } } @@ -342,20 +350,22 @@ func (k Keeper) GetLastValidators(ctx sdk.Context) (validators []types.Validator // gets a specific validator queue timeslice. A timeslice is a slice of ValAddresses corresponding to unbonding validators // that expire at a certain time. -func (k Keeper) GetValidatorQueueTimeSlice(ctx sdk.Context, timestamp time.Time) (valAddrs []sdk.ValAddress) { +func (k Keeper) GetValidatorQueueTimeSlice(ctx sdk.Context, timestamp time.Time) []sdk.ValAddress { store := ctx.KVStore(k.storeKey) bz := store.Get(types.GetValidatorQueueTimeKey(timestamp)) if bz == nil { return []sdk.ValAddress{} } - k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &valAddrs) - return valAddrs + + va := sdk.ValAddresses{} + k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &va) + return va.Addresses } // Sets a specific validator queue timeslice. func (k Keeper) SetValidatorQueueTimeSlice(ctx sdk.Context, timestamp time.Time, keys []sdk.ValAddress) { store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinaryLengthPrefixed(keys) + bz := k.cdc.MustMarshalBinaryLengthPrefixed(&sdk.ValAddresses{Addresses: keys}) store.Set(types.GetValidatorQueueTimeKey(timestamp), bz) } @@ -367,24 +377,25 @@ func (k Keeper) DeleteValidatorQueueTimeSlice(ctx sdk.Context, timestamp time.Ti // Insert an validator address to the appropriate timeslice in the validator queue func (k Keeper) InsertValidatorQueue(ctx sdk.Context, val types.Validator) { - timeSlice := k.GetValidatorQueueTimeSlice(ctx, val.UnbondingCompletionTime) + timeSlice := k.GetValidatorQueueTimeSlice(ctx, val.UnbondingTime) timeSlice = append(timeSlice, val.OperatorAddress) - k.SetValidatorQueueTimeSlice(ctx, val.UnbondingCompletionTime, timeSlice) + k.SetValidatorQueueTimeSlice(ctx, val.UnbondingTime, timeSlice) } // Delete a validator address from the validator queue func (k Keeper) DeleteValidatorQueue(ctx sdk.Context, val types.Validator) { - timeSlice := k.GetValidatorQueueTimeSlice(ctx, val.UnbondingCompletionTime) + timeSlice := k.GetValidatorQueueTimeSlice(ctx, val.UnbondingTime) newTimeSlice := []sdk.ValAddress{} for _, addr := range timeSlice { if !bytes.Equal(addr, val.OperatorAddress) { newTimeSlice = append(newTimeSlice, addr) } } + if len(newTimeSlice) == 0 { - k.DeleteValidatorQueueTimeSlice(ctx, val.UnbondingCompletionTime) + k.DeleteValidatorQueueTimeSlice(ctx, val.UnbondingTime) } else { - k.SetValidatorQueueTimeSlice(ctx, val.UnbondingCompletionTime, newTimeSlice) + k.SetValidatorQueueTimeSlice(ctx, val.UnbondingTime, newTimeSlice) } } @@ -401,9 +412,10 @@ func (k Keeper) GetAllMatureValidatorQueue(ctx sdk.Context, currTime time.Time) defer validatorTimesliceIterator.Close() for ; validatorTimesliceIterator.Valid(); validatorTimesliceIterator.Next() { - timeslice := []sdk.ValAddress{} + timeslice := sdk.ValAddresses{} k.cdc.MustUnmarshalBinaryLengthPrefixed(validatorTimesliceIterator.Value(), ×lice) - matureValsAddrs = append(matureValsAddrs, timeslice...) + + matureValsAddrs = append(matureValsAddrs, timeslice.Addresses...) } return matureValsAddrs @@ -416,10 +428,10 @@ func (k Keeper) UnbondAllMatureValidatorQueue(ctx sdk.Context) { defer validatorTimesliceIterator.Close() for ; validatorTimesliceIterator.Valid(); validatorTimesliceIterator.Next() { - timeslice := []sdk.ValAddress{} + timeslice := sdk.ValAddresses{} k.cdc.MustUnmarshalBinaryLengthPrefixed(validatorTimesliceIterator.Value(), ×lice) - for _, valAddr := range timeslice { + for _, valAddr := range timeslice.Addresses { val, found := k.GetValidator(ctx, valAddr) if !found { panic("validator in the unbonding queue was not found") @@ -428,6 +440,7 @@ func (k Keeper) UnbondAllMatureValidatorQueue(ctx sdk.Context) { if !val.IsUnbonding() { panic("unexpected validator in unbonding queue; status was not unbonding") } + val = k.unbondingToUnbonded(ctx, val) if val.GetDelegatorShares().IsZero() { k.RemoveValidator(ctx, val.OperatorAddress) diff --git a/x/staking/keeper/validator_test.go b/x/staking/keeper/validator_test.go index ae2552fe8373..1b4d8f6a5ac8 100644 --- a/x/staking/keeper/validator_test.go +++ b/x/staking/keeper/validator_test.go @@ -5,13 +5,12 @@ import ( "testing" "time" - abci "github.com/tendermint/tendermint/abci/types" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" ) //_______________________________________________________ @@ -117,7 +116,7 @@ func TestUpdateBondedValidatorsDecreaseCliff(t *testing.T) { // create keeper parameters params := keeper.GetParams(ctx) - params.MaxValidators = uint16(maxVals) + params.MaxValidators = uint32(maxVals) keeper.SetParams(ctx, params) // create a random pool @@ -437,7 +436,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) { // set max validators to 2 params := keeper.GetParams(ctx) - nMax := uint16(2) + nMax := uint32(2) params.MaxValidators = nMax keeper.SetParams(ctx, params) @@ -461,7 +460,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) { // ensure that the first two bonded validators are the largest validators resValidators := keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, nMax, uint16(len(resValidators))) + require.Equal(t, nMax, uint32(len(resValidators))) assert.True(ValEq(t, validators[2], resValidators[0])) assert.True(ValEq(t, validators[3], resValidators[1])) @@ -481,7 +480,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) { // b) validator 2 with 400 tokens (delegated before validator 3) validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], true) resValidators = keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, nMax, uint16(len(resValidators))) + require.Equal(t, nMax, uint32(len(resValidators))) assert.True(ValEq(t, validators[0], resValidators[0])) assert.True(ValEq(t, validators[2], resValidators[1])) @@ -509,7 +508,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) { validators[3] = TestingUpdateValidator(keeper, ctx, validators[3], true) resValidators = keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, nMax, uint16(len(resValidators))) + require.Equal(t, nMax, uint32(len(resValidators))) assert.True(ValEq(t, validators[0], resValidators[0])) assert.True(ValEq(t, validators[3], resValidators[1])) @@ -525,7 +524,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) { validators[3] = TestingUpdateValidator(keeper, ctx, validators[3], true) resValidators = keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, nMax, uint16(len(resValidators))) + require.Equal(t, nMax, uint32(len(resValidators))) assert.True(ValEq(t, validators[0], resValidators[0])) assert.True(ValEq(t, validators[2], resValidators[1])) @@ -540,7 +539,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) { validators[3] = TestingUpdateValidator(keeper, ctx, validators[3], true) resValidators = keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, nMax, uint16(len(resValidators))) + require.Equal(t, nMax, uint32(len(resValidators))) assert.True(ValEq(t, validators[0], resValidators[0])) assert.True(ValEq(t, validators[2], resValidators[1])) _, exists := keeper.GetValidator(ctx, validators[3].OperatorAddress) @@ -577,7 +576,7 @@ func TestValidatorBondHeight(t *testing.T) { validators[2] = TestingUpdateValidator(keeper, ctx, validators[2], true) resValidators := keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, uint16(len(resValidators)), params.MaxValidators) + require.Equal(t, uint32(len(resValidators)), params.MaxValidators) assert.True(ValEq(t, validators[0], resValidators[0])) assert.True(ValEq(t, validators[1], resValidators[1])) @@ -588,7 +587,7 @@ func TestValidatorBondHeight(t *testing.T) { validators[2], _ = validators[2].AddTokensFromDel(delTokens) validators[2] = TestingUpdateValidator(keeper, ctx, validators[2], true) resValidators = keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, params.MaxValidators, uint16(len(resValidators))) + require.Equal(t, params.MaxValidators, uint32(len(resValidators))) validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], true) assert.True(ValEq(t, validators[0], resValidators[0])) assert.True(ValEq(t, validators[2], resValidators[1])) @@ -598,7 +597,7 @@ func TestFullValidatorSetPowerChange(t *testing.T) { ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) params := keeper.GetParams(ctx) max := 2 - params.MaxValidators = uint16(2) + params.MaxValidators = uint32(2) keeper.SetParams(ctx, params) // initialize some validators into the state @@ -881,7 +880,7 @@ func TestApplyAndReturnValidatorSetUpdatesPowerDecrease(t *testing.T) { func TestApplyAndReturnValidatorSetUpdatesNewValidator(t *testing.T) { ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) params := keeper.GetParams(ctx) - params.MaxValidators = uint16(3) + params.MaxValidators = uint32(3) keeper.SetParams(ctx, params) @@ -962,7 +961,7 @@ func TestApplyAndReturnValidatorSetUpdatesNewValidator(t *testing.T) { func TestApplyAndReturnValidatorSetUpdatesBondTransition(t *testing.T) { ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) params := keeper.GetParams(ctx) - params.MaxValidators = uint16(2) + params.MaxValidators = uint32(2) keeper.SetParams(ctx, params) diff --git a/x/staking/simulation/genesis.go b/x/staking/simulation/genesis.go index cca02bee8cc9..1ce83be9ef18 100644 --- a/x/staking/simulation/genesis.go +++ b/x/staking/simulation/genesis.go @@ -27,8 +27,8 @@ func GenUnbondingTime(r *rand.Rand) (ubdTime time.Duration) { } // GenMaxValidators randomized MaxValidators -func GenMaxValidators(r *rand.Rand) (maxValidators uint16) { - return uint16(r.Intn(250) + 1) +func GenMaxValidators(r *rand.Rand) (maxValidators uint32) { + return uint32(r.Intn(250) + 1) } // RandomizedGenState generates a random GenesisState for staking @@ -40,7 +40,7 @@ func RandomizedGenState(simState *module.SimulationState) { func(r *rand.Rand) { unbondTime = GenUnbondingTime(r) }, ) - var maxValidators uint16 + var maxValidators uint32 simState.AppParams.GetOrGenerate( simState.Cdc, MaxValidators, &maxValidators, simState.Rand, func(r *rand.Rand) { maxValidators = GenMaxValidators(r) }, @@ -82,6 +82,6 @@ func RandomizedGenState(simState *module.SimulationState) { stakingGenesis := types.NewGenesisState(params, validators, delegations) - fmt.Printf("Selected randomly generated staking parameters:\n%s\n", codec.MustMarshalJSONIndent(simState.Cdc, stakingGenesis.Params)) + fmt.Printf("Selected randomly generated staking parameters:\n%s\n", codec.MustMarshalJSONIndent(types.ModuleCdc, stakingGenesis.Params)) simState.GenState[types.ModuleName] = simState.Cdc.MustMarshalJSON(stakingGenesis) } diff --git a/x/staking/types/codec.go b/x/staking/types/codec.go index 6fadfd9a68f9..9832789b6971 100644 --- a/x/staking/types/codec.go +++ b/x/staking/types/codec.go @@ -4,7 +4,22 @@ import ( "github.com/cosmos/cosmos-sdk/codec" ) -// Register concrete types on codec codec +type Codec struct { + codec.Marshaler + + // Keep reference to the amino codec to allow backwards compatibility along + // with type, and interface registration. + amino *codec.Codec +} + +func NewCodec(amino *codec.Codec) *Codec { + return &Codec{Marshaler: codec.NewHybridCodec(amino), amino: amino} +} + +// ---------------------------------------------------------------------------- + +// RegisterCodec registers all the necessary staking module concrete types and +// interfaces with the provided codec reference. func RegisterCodec(cdc *codec.Codec) { cdc.RegisterConcrete(MsgCreateValidator{}, "cosmos-sdk/MsgCreateValidator", nil) cdc.RegisterConcrete(MsgEditValidator{}, "cosmos-sdk/MsgEditValidator", nil) @@ -13,12 +28,13 @@ func RegisterCodec(cdc *codec.Codec) { cdc.RegisterConcrete(MsgBeginRedelegate{}, "cosmos-sdk/MsgBeginRedelegate", nil) } -// generic sealed codec to be used throughout this module -var ModuleCdc *codec.Codec +// ModuleCdc defines a staking module global Amino codec. +var ModuleCdc *Codec func init() { - ModuleCdc = codec.New() - RegisterCodec(ModuleCdc) - codec.RegisterCrypto(ModuleCdc) - ModuleCdc.Seal() + ModuleCdc = NewCodec(codec.New()) + + RegisterCodec(ModuleCdc.amino) + codec.RegisterCrypto(ModuleCdc.amino) + ModuleCdc.amino.Seal() } diff --git a/x/staking/types/commission.go b/x/staking/types/commission.go index 38ab8e06a703..9a58210f612e 100644 --- a/x/staking/types/commission.go +++ b/x/staking/types/commission.go @@ -1,26 +1,10 @@ package types import ( - "fmt" "time" sdk "github.com/cosmos/cosmos-sdk/types" -) - -type ( - // Commission defines a commission parameters for a given validator. - Commission struct { - CommissionRates `json:"commission_rates" yaml:"commission_rates"` - UpdateTime time.Time `json:"update_time" yaml:"update_time"` // the last time the commission rate was changed - } - - // CommissionRates defines the initial commission rates to be used for creating a - // validator. - CommissionRates struct { - Rate sdk.Dec `json:"rate" yaml:"rate"` // the commission rate charged to delegators, as a fraction - MaxRate sdk.Dec `json:"max_rate" yaml:"max_rate"` // maximum commission rate which validator can ever charge, as a fraction - MaxChangeRate sdk.Dec `json:"max_change_rate" yaml:"max_change_rate"` // maximum daily increase of the validator commission, as a fraction - } + yaml "gopkg.in/yaml.v2" ) // NewCommissionRates returns an initialized validator commission rates. @@ -49,47 +33,43 @@ func NewCommissionWithTime(rate, maxRate, maxChangeRate sdk.Dec, updatedAt time. } } -// Equal checks if the given Commission object is equal to the receiving -// Commission object. -func (c Commission) Equal(c2 Commission) bool { - return c.Rate.Equal(c2.Rate) && - c.MaxRate.Equal(c2.MaxRate) && - c.MaxChangeRate.Equal(c2.MaxChangeRate) && - c.UpdateTime.Equal(c2.UpdateTime) +// String implements the Stringer interface for a Commission object. +func (c Commission) String() string { + out, _ := yaml.Marshal(c) + return string(out) } -// String implements the Stringer interface for a Commission. -func (c Commission) String() string { - return fmt.Sprintf("rate: %s, maxRate: %s, maxChangeRate: %s, updateTime: %s", - c.Rate, c.MaxRate, c.MaxChangeRate, c.UpdateTime, - ) +// String implements the Stringer interface for a CommissionRates object. +func (cr CommissionRates) String() string { + out, _ := yaml.Marshal(cr) + return string(out) } // Validate performs basic sanity validation checks of initial commission // parameters. If validation fails, an SDK error is returned. -func (c CommissionRates) Validate() error { +func (cr CommissionRates) Validate() error { switch { - case c.MaxRate.IsNegative(): + case cr.MaxRate.IsNegative(): // max rate cannot be negative return ErrCommissionNegative - case c.MaxRate.GT(sdk.OneDec()): + case cr.MaxRate.GT(sdk.OneDec()): // max rate cannot be greater than 1 return ErrCommissionHuge - case c.Rate.IsNegative(): + case cr.Rate.IsNegative(): // rate cannot be negative return ErrCommissionNegative - case c.Rate.GT(c.MaxRate): + case cr.Rate.GT(cr.MaxRate): // rate cannot be greater than the max rate return ErrCommissionGTMaxRate - case c.MaxChangeRate.IsNegative(): + case cr.MaxChangeRate.IsNegative(): // change rate cannot be negative return ErrCommissionChangeRateNegative - case c.MaxChangeRate.GT(c.MaxRate): + case cr.MaxChangeRate.GT(cr.MaxRate): // change rate cannot be greater than the max rate return ErrCommissionChangeRateGTMaxRate } diff --git a/x/staking/types/delegation.go b/x/staking/types/delegation.go index 672edd5a90ed..f25aaac7b22a 100644 --- a/x/staking/types/delegation.go +++ b/x/staking/types/delegation.go @@ -1,7 +1,6 @@ package types import ( - "bytes" "encoding/json" "fmt" "strings" @@ -10,41 +9,26 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/staking/exported" + yaml "gopkg.in/yaml.v2" ) -// DVPair is struct that just has a delegator-validator pair with no other data. -// It is intended to be used as a marshalable pointer. For example, a DVPair can be used to construct the -// key to getting an UnbondingDelegation from state. -type DVPair struct { - DelegatorAddress sdk.AccAddress - ValidatorAddress sdk.ValAddress -} - -// DVVTriplet is struct that just has a delegator-validator-validator triplet with no other data. -// It is intended to be used as a marshalable pointer. For example, a DVVTriplet can be used to construct the -// key to getting a Redelegation from state. -type DVVTriplet struct { - DelegatorAddress sdk.AccAddress - ValidatorSrcAddress sdk.ValAddress - ValidatorDstAddress sdk.ValAddress -} - // Implements Delegation interface var _ exported.DelegationI = Delegation{} -// Delegation represents the bond with tokens held by an account. It is -// owned by one delegator, and is associated with the voting power of one -// validator. -type Delegation struct { - DelegatorAddress sdk.AccAddress `json:"delegator_address" yaml:"delegator_address"` - ValidatorAddress sdk.ValAddress `json:"validator_address" yaml:"validator_address"` - Shares sdk.Dec `json:"shares" yaml:"shares"` +// String implements the Stringer interface for a DVPair object. +func (dv DVPair) String() string { + out, _ := yaml.Marshal(dv) + return string(out) } -// NewDelegation creates a new delegation object -func NewDelegation(delegatorAddr sdk.AccAddress, validatorAddr sdk.ValAddress, - shares sdk.Dec) Delegation { +// String implements the Stringer interface for a DVVTriplet object. +func (dvv DVVTriplet) String() string { + out, _ := yaml.Marshal(dvv) + return string(out) +} +// NewDelegation creates a new delegation object +func NewDelegation(delegatorAddr sdk.AccAddress, validatorAddr sdk.ValAddress, shares sdk.Dec) Delegation { return Delegation{ DelegatorAddress: delegatorAddr, ValidatorAddress: validatorAddr, @@ -53,13 +37,13 @@ func NewDelegation(delegatorAddr sdk.AccAddress, validatorAddr sdk.ValAddress, } // MustMarshalDelegation returns the delegation bytes. Panics if fails -func MustMarshalDelegation(cdc *codec.Codec, delegation Delegation) []byte { - return cdc.MustMarshalBinaryLengthPrefixed(delegation) +func MustMarshalDelegation(cdc codec.Marshaler, delegation Delegation) []byte { + return cdc.MustMarshalBinaryLengthPrefixed(&delegation) } // MustUnmarshalDelegation return the unmarshaled delegation from bytes. // Panics if fails. -func MustUnmarshalDelegation(cdc *codec.Codec, value []byte) Delegation { +func MustUnmarshalDelegation(cdc codec.Marshaler, value []byte) Delegation { delegation, err := UnmarshalDelegation(cdc, value) if err != nil { panic(err) @@ -68,18 +52,11 @@ func MustUnmarshalDelegation(cdc *codec.Codec, value []byte) Delegation { } // return the delegation -func UnmarshalDelegation(cdc *codec.Codec, value []byte) (delegation Delegation, err error) { +func UnmarshalDelegation(cdc codec.Marshaler, value []byte) (delegation Delegation, err error) { err = cdc.UnmarshalBinaryLengthPrefixed(value, &delegation) return delegation, err } -// nolint -func (d Delegation) Equal(d2 Delegation) bool { - return bytes.Equal(d.DelegatorAddress, d2.DelegatorAddress) && - bytes.Equal(d.ValidatorAddress, d2.ValidatorAddress) && - d.Shares.Equal(d2.Shares) -} - // nolint - for Delegation func (d Delegation) GetDelegatorAddr() sdk.AccAddress { return d.DelegatorAddress } func (d Delegation) GetValidatorAddr() sdk.ValAddress { return d.ValidatorAddress } @@ -87,11 +64,8 @@ func (d Delegation) GetShares() sdk.Dec { return d.Shares } // String returns a human readable string representation of a Delegation. func (d Delegation) String() string { - return fmt.Sprintf(`Delegation: - Delegator: %s - Validator: %s - Shares: %s`, d.DelegatorAddress, - d.ValidatorAddress, d.Shares) + out, _ := yaml.Marshal(d) + return string(out) } // Delegations is a collection of delegations @@ -104,20 +78,19 @@ func (d Delegations) String() (out string) { return strings.TrimSpace(out) } -// UnbondingDelegation stores all of a single delegator's unbonding bonds -// for a single validator in an time-ordered list -type UnbondingDelegation struct { - DelegatorAddress sdk.AccAddress `json:"delegator_address" yaml:"delegator_address"` // delegator - ValidatorAddress sdk.ValAddress `json:"validator_address" yaml:"validator_address"` // validator unbonding from operator addr - Entries []UnbondingDelegationEntry `json:"entries" yaml:"entries"` // unbonding delegation entries +func NewUnbondingDelegationEntry(creationHeight int64, completionTime time.Time, balance sdk.Int) UnbondingDelegationEntry { + return UnbondingDelegationEntry{ + CreationHeight: creationHeight, + CompletionTime: completionTime, + InitialBalance: balance, + Balance: balance, + } } -// UnbondingDelegationEntry - entry to an UnbondingDelegation -type UnbondingDelegationEntry struct { - CreationHeight int64 `json:"creation_height" yaml:"creation_height"` // height which the unbonding took place - CompletionTime time.Time `json:"completion_time" yaml:"completion_time"` // time at which the unbonding delegation will complete - InitialBalance sdk.Int `json:"initial_balance" yaml:"initial_balance"` // atoms initially scheduled to receive at completion - Balance sdk.Int `json:"balance" yaml:"balance"` // atoms to receive at completion +// String implements the stringer interface for a UnbondingDelegationEntry. +func (e UnbondingDelegationEntry) String() string { + out, _ := yaml.Marshal(e) + return string(out) } // IsMature - is the current entry mature @@ -126,50 +99,38 @@ func (e UnbondingDelegationEntry) IsMature(currentTime time.Time) bool { } // NewUnbondingDelegation - create a new unbonding delegation object -func NewUnbondingDelegation(delegatorAddr sdk.AccAddress, - validatorAddr sdk.ValAddress, creationHeight int64, minTime time.Time, - balance sdk.Int) UnbondingDelegation { +func NewUnbondingDelegation( + delegatorAddr sdk.AccAddress, validatorAddr sdk.ValAddress, + creationHeight int64, minTime time.Time, balance sdk.Int, +) UnbondingDelegation { - entry := NewUnbondingDelegationEntry(creationHeight, minTime, balance) return UnbondingDelegation{ DelegatorAddress: delegatorAddr, ValidatorAddress: validatorAddr, - Entries: []UnbondingDelegationEntry{entry}, - } -} - -// NewUnbondingDelegationEntry - create a new unbonding delegation object -func NewUnbondingDelegationEntry(creationHeight int64, completionTime time.Time, - balance sdk.Int) UnbondingDelegationEntry { - - return UnbondingDelegationEntry{ - CreationHeight: creationHeight, - CompletionTime: completionTime, - InitialBalance: balance, - Balance: balance, + Entries: []UnbondingDelegationEntry{ + NewUnbondingDelegationEntry(creationHeight, minTime, balance), + }, } } // AddEntry - append entry to the unbonding delegation -func (d *UnbondingDelegation) AddEntry(creationHeight int64, - minTime time.Time, balance sdk.Int) { - +func (ubd *UnbondingDelegation) AddEntry(creationHeight int64, minTime time.Time, balance sdk.Int) { entry := NewUnbondingDelegationEntry(creationHeight, minTime, balance) - d.Entries = append(d.Entries, entry) + ubd.Entries = append(ubd.Entries, entry) } // RemoveEntry - remove entry at index i to the unbonding delegation -func (d *UnbondingDelegation) RemoveEntry(i int64) { - d.Entries = append(d.Entries[:i], d.Entries[i+1:]...) +func (ubd *UnbondingDelegation) RemoveEntry(i int64) { + ubd.Entries = append(ubd.Entries[:i], ubd.Entries[i+1:]...) } // return the unbonding delegation -func MustMarshalUBD(cdc *codec.Codec, ubd UnbondingDelegation) []byte { - return cdc.MustMarshalBinaryLengthPrefixed(ubd) +func MustMarshalUBD(cdc codec.Marshaler, ubd UnbondingDelegation) []byte { + return cdc.MustMarshalBinaryLengthPrefixed(&ubd) } // unmarshal a unbonding delegation from a store value -func MustUnmarshalUBD(cdc *codec.Codec, value []byte) UnbondingDelegation { +func MustUnmarshalUBD(cdc codec.Marshaler, value []byte) UnbondingDelegation { ubd, err := UnmarshalUBD(cdc, value) if err != nil { panic(err) @@ -178,26 +139,18 @@ func MustUnmarshalUBD(cdc *codec.Codec, value []byte) UnbondingDelegation { } // unmarshal a unbonding delegation from a store value -func UnmarshalUBD(cdc *codec.Codec, value []byte) (ubd UnbondingDelegation, err error) { +func UnmarshalUBD(cdc codec.Marshaler, value []byte) (ubd UnbondingDelegation, err error) { err = cdc.UnmarshalBinaryLengthPrefixed(value, &ubd) return ubd, err } -// nolint -// inefficient but only used in testing -func (d UnbondingDelegation) Equal(d2 UnbondingDelegation) bool { - bz1 := ModuleCdc.MustMarshalBinaryLengthPrefixed(&d) - bz2 := ModuleCdc.MustMarshalBinaryLengthPrefixed(&d2) - return bytes.Equal(bz1, bz2) -} - // String returns a human readable string representation of an UnbondingDelegation. -func (d UnbondingDelegation) String() string { +func (ubd UnbondingDelegation) String() string { out := fmt.Sprintf(`Unbonding Delegations between: Delegator: %s Validator: %s - Entries:`, d.DelegatorAddress, d.ValidatorAddress) - for i, entry := range d.Entries { + Entries:`, ubd.DelegatorAddress, ubd.ValidatorAddress) + for i, entry := range ubd.Entries { out += fmt.Sprintf(` Unbonding Delegation %d: Creation Height: %v Min time to unbond (unix): %v @@ -217,46 +170,7 @@ func (ubds UnbondingDelegations) String() (out string) { return strings.TrimSpace(out) } -// Redelegation contains the list of a particular delegator's -// redelegating bonds from a particular source validator to a -// particular destination validator -type Redelegation struct { - DelegatorAddress sdk.AccAddress `json:"delegator_address" yaml:"delegator_address"` // delegator - ValidatorSrcAddress sdk.ValAddress `json:"validator_src_address" yaml:"validator_src_address"` // validator redelegation source operator addr - ValidatorDstAddress sdk.ValAddress `json:"validator_dst_address" yaml:"validator_dst_address"` // validator redelegation destination operator addr - Entries []RedelegationEntry `json:"entries" yaml:"entries"` // redelegation entries -} - -// RedelegationEntry - entry to a Redelegation -type RedelegationEntry struct { - CreationHeight int64 `json:"creation_height" yaml:"creation_height"` // height at which the redelegation took place - CompletionTime time.Time `json:"completion_time" yaml:"completion_time"` // time at which the redelegation will complete - InitialBalance sdk.Int `json:"initial_balance" yaml:"initial_balance"` // initial balance when redelegation started - SharesDst sdk.Dec `json:"shares_dst" yaml:"shares_dst"` // amount of destination-validator shares created by redelegation -} - -// NewRedelegation - create a new redelegation object -func NewRedelegation(delegatorAddr sdk.AccAddress, validatorSrcAddr, - validatorDstAddr sdk.ValAddress, creationHeight int64, - minTime time.Time, balance sdk.Int, - sharesDst sdk.Dec) Redelegation { - - entry := NewRedelegationEntry(creationHeight, - minTime, balance, sharesDst) - - return Redelegation{ - DelegatorAddress: delegatorAddr, - ValidatorSrcAddress: validatorSrcAddr, - ValidatorDstAddress: validatorDstAddr, - Entries: []RedelegationEntry{entry}, - } -} - -// NewRedelegationEntry - create a new redelegation object -func NewRedelegationEntry(creationHeight int64, - completionTime time.Time, balance sdk.Int, - sharesDst sdk.Dec) RedelegationEntry { - +func NewRedelegationEntry(creationHeight int64, completionTime time.Time, balance sdk.Int, sharesDst sdk.Dec) RedelegationEntry { return RedelegationEntry{ CreationHeight: creationHeight, CompletionTime: completionTime, @@ -265,32 +179,50 @@ func NewRedelegationEntry(creationHeight int64, } } +// String implements the Stringer interface for a RedelegationEntry object. +func (e RedelegationEntry) String() string { + out, _ := yaml.Marshal(e) + return string(out) +} + // IsMature - is the current entry mature func (e RedelegationEntry) IsMature(currentTime time.Time) bool { return !e.CompletionTime.After(currentTime) } -// AddEntry - append entry to the unbonding delegation -func (d *Redelegation) AddEntry(creationHeight int64, - minTime time.Time, balance sdk.Int, - sharesDst sdk.Dec) { +func NewRedelegation( + delegatorAddr sdk.AccAddress, validatorSrcAddr, validatorDstAddr sdk.ValAddress, + creationHeight int64, minTime time.Time, balance sdk.Int, sharesDst sdk.Dec, +) Redelegation { + + return Redelegation{ + DelegatorAddress: delegatorAddr, + ValidatorSrcAddress: validatorSrcAddr, + ValidatorDstAddress: validatorDstAddr, + Entries: []RedelegationEntry{ + NewRedelegationEntry(creationHeight, minTime, balance, sharesDst), + }, + } +} +// AddEntry - append entry to the unbonding delegation +func (red *Redelegation) AddEntry(creationHeight int64, minTime time.Time, balance sdk.Int, sharesDst sdk.Dec) { entry := NewRedelegationEntry(creationHeight, minTime, balance, sharesDst) - d.Entries = append(d.Entries, entry) + red.Entries = append(red.Entries, entry) } // RemoveEntry - remove entry at index i to the unbonding delegation -func (d *Redelegation) RemoveEntry(i int64) { - d.Entries = append(d.Entries[:i], d.Entries[i+1:]...) +func (red *Redelegation) RemoveEntry(i int64) { + red.Entries = append(red.Entries[:i], red.Entries[i+1:]...) } // MustMarshalRED returns the Redelegation bytes. Panics if fails. -func MustMarshalRED(cdc *codec.Codec, red Redelegation) []byte { - return cdc.MustMarshalBinaryLengthPrefixed(red) +func MustMarshalRED(cdc codec.Marshaler, red Redelegation) []byte { + return cdc.MustMarshalBinaryLengthPrefixed(&red) } // MustUnmarshalRED unmarshals a redelegation from a store value. Panics if fails. -func MustUnmarshalRED(cdc *codec.Codec, value []byte) Redelegation { +func MustUnmarshalRED(cdc codec.Marshaler, value []byte) Redelegation { red, err := UnmarshalRED(cdc, value) if err != nil { panic(err) @@ -299,31 +231,23 @@ func MustUnmarshalRED(cdc *codec.Codec, value []byte) Redelegation { } // UnmarshalRED unmarshals a redelegation from a store value -func UnmarshalRED(cdc *codec.Codec, value []byte) (red Redelegation, err error) { +func UnmarshalRED(cdc codec.Marshaler, value []byte) (red Redelegation, err error) { err = cdc.UnmarshalBinaryLengthPrefixed(value, &red) return red, err } -// nolint -// inefficient but only used in tests -func (d Redelegation) Equal(d2 Redelegation) bool { - bz1 := ModuleCdc.MustMarshalBinaryLengthPrefixed(&d) - bz2 := ModuleCdc.MustMarshalBinaryLengthPrefixed(&d2) - return bytes.Equal(bz1, bz2) -} - // String returns a human readable string representation of a Redelegation. -func (d Redelegation) String() string { +func (red Redelegation) String() string { out := fmt.Sprintf(`Redelegations between: Delegator: %s Source Validator: %s Destination Validator: %s Entries: `, - d.DelegatorAddress, d.ValidatorSrcAddress, d.ValidatorDstAddress, + red.DelegatorAddress, red.ValidatorSrcAddress, red.ValidatorDstAddress, ) - for i, entry := range d.Entries { + for i, entry := range red.Entries { out += fmt.Sprintf(` Redelegation Entry #%d: Creation height: %v Min time to unbond (unix): %v diff --git a/x/staking/types/errors.go b/x/staking/types/errors.go index d3ccf0a9dac2..62fdd0725b90 100644 --- a/x/staking/types/errors.go +++ b/x/staking/types/errors.go @@ -56,4 +56,5 @@ var ( ErrNeitherShareMsgsGiven = sdkerrors.Register(ModuleName, 43, "neither shares amount nor shares percent provided") ErrInvalidHistoricalInfo = sdkerrors.Register(ModuleName, 44, "invalid historical info") ErrNoHistoricalInfo = sdkerrors.Register(ModuleName, 45, "no historical info found") + ErrEmptyValidatorPubKey = sdkerrors.Register(ModuleName, 46, "empty validator public key") ) diff --git a/x/staking/types/expected_keepers.go b/x/staking/types/expected_keepers.go index c9e69b9018bb..331840468142 100644 --- a/x/staking/types/expected_keepers.go +++ b/x/staking/types/expected_keepers.go @@ -74,7 +74,7 @@ type ValidatorSet interface { Delegation(sdk.Context, sdk.AccAddress, sdk.ValAddress) stakingexported.DelegationI // MaxValidators returns the maximum amount of bonded validators - MaxValidators(sdk.Context) uint16 + MaxValidators(sdk.Context) uint32 } // DelegationSet expected properties for the set of all delegations for a particular (noalias) diff --git a/x/staking/types/historical_info.go b/x/staking/types/historical_info.go index 9aa07c95d72e..98f2ea86a5cd 100644 --- a/x/staking/types/historical_info.go +++ b/x/staking/types/historical_info.go @@ -9,29 +9,23 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) -// HistoricalInfo contains the historical information that gets stored at each height -type HistoricalInfo struct { - Header abci.Header `json:"header" yaml:"header"` - ValSet Validators `json:"valset" yaml:"valset"` -} - // NewHistoricalInfo will create a historical information struct from header and valset // it will first sort valset before inclusion into historical info func NewHistoricalInfo(header abci.Header, valSet Validators) HistoricalInfo { sort.Sort(valSet) return HistoricalInfo{ Header: header, - ValSet: valSet, + Valset: valSet, } } // MustMarshalHistoricalInfo wll marshal historical info and panic on error -func MustMarshalHistoricalInfo(cdc *codec.Codec, hi HistoricalInfo) []byte { - return cdc.MustMarshalBinaryLengthPrefixed(hi) +func MustMarshalHistoricalInfo(cdc codec.Marshaler, hi HistoricalInfo) []byte { + return cdc.MustMarshalBinaryLengthPrefixed(&hi) } // MustUnmarshalHistoricalInfo wll unmarshal historical info and panic on error -func MustUnmarshalHistoricalInfo(cdc *codec.Codec, value []byte) HistoricalInfo { +func MustUnmarshalHistoricalInfo(cdc codec.Marshaler, value []byte) HistoricalInfo { hi, err := UnmarshalHistoricalInfo(cdc, value) if err != nil { panic(err) @@ -40,18 +34,19 @@ func MustUnmarshalHistoricalInfo(cdc *codec.Codec, value []byte) HistoricalInfo } // UnmarshalHistoricalInfo will unmarshal historical info and return any error -func UnmarshalHistoricalInfo(cdc *codec.Codec, value []byte) (hi HistoricalInfo, err error) { +func UnmarshalHistoricalInfo(cdc codec.Marshaler, value []byte) (hi HistoricalInfo, err error) { err = cdc.UnmarshalBinaryLengthPrefixed(value, &hi) return hi, err } // ValidateBasic will ensure HistoricalInfo is not nil and sorted func ValidateBasic(hi HistoricalInfo) error { - if len(hi.ValSet) == 0 { + if len(hi.Valset) == 0 { return sdkerrors.Wrap(ErrInvalidHistoricalInfo, "validator set is empty") } - if !sort.IsSorted(hi.ValSet) { + if !sort.IsSorted(Validators(hi.Valset)) { return sdkerrors.Wrap(ErrInvalidHistoricalInfo, "validator set is not sorted by address") } + return nil } diff --git a/x/staking/types/historical_info_test.go b/x/staking/types/historical_info_test.go index 69596ef3190b..32e149af56a9 100644 --- a/x/staking/types/historical_info_test.go +++ b/x/staking/types/historical_info_test.go @@ -23,7 +23,7 @@ var ( func TestHistoricalInfo(t *testing.T) { hi := NewHistoricalInfo(header, validators) - require.True(t, sort.IsSorted(hi.ValSet), "Validators are not sorted") + require.True(t, sort.IsSorted(Validators(hi.Valset)), "Validators are not sorted") var value []byte require.NotPanics(t, func() { @@ -35,7 +35,7 @@ func TestHistoricalInfo(t *testing.T) { recv, err := UnmarshalHistoricalInfo(ModuleCdc, value) require.Nil(t, err, "Unmarshalling HistoricalInfo failed") require.Equal(t, hi, recv, "Unmarshalled HistoricalInfo is different from original") - require.True(t, sort.IsSorted(hi.ValSet), "Validators are not sorted") + require.True(t, sort.IsSorted(Validators(hi.Valset)), "Validators are not sorted") } func TestValidateBasic(t *testing.T) { @@ -56,7 +56,7 @@ func TestValidateBasic(t *testing.T) { hi = HistoricalInfo{ Header: header, - ValSet: validators, + Valset: validators, } err = ValidateBasic(hi) require.Error(t, err, "ValidateBasic passed on unsorted ValSet") diff --git a/x/staking/types/msg.go b/x/staking/types/msg.go index 62d2295fce6f..18e0bac2dc13 100644 --- a/x/staking/types/msg.go +++ b/x/staking/types/msg.go @@ -2,16 +2,13 @@ package types import ( "bytes" - "encoding/json" "github.com/tendermint/tendermint/crypto" - yaml "gopkg.in/yaml.v2" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) -// ensure Msg interface compliance at compile time var ( _ sdk.Msg = &MsgCreateValidator{} _ sdk.Msg = &MsgEditValidator{} @@ -20,29 +17,6 @@ var ( _ sdk.Msg = &MsgBeginRedelegate{} ) -//______________________________________________________________________ - -// MsgCreateValidator - struct for bonding transactions -type MsgCreateValidator struct { - Description Description `json:"description" yaml:"description"` - Commission CommissionRates `json:"commission" yaml:"commission"` - MinSelfDelegation sdk.Int `json:"min_self_delegation" yaml:"min_self_delegation"` - DelegatorAddress sdk.AccAddress `json:"delegator_address" yaml:"delegator_address"` - ValidatorAddress sdk.ValAddress `json:"validator_address" yaml:"validator_address"` - PubKey crypto.PubKey `json:"pubkey" yaml:"pubkey"` - Value sdk.Coin `json:"value" yaml:"value"` -} - -type msgCreateValidatorJSON struct { - Description Description `json:"description" yaml:"description"` - Commission CommissionRates `json:"commission" yaml:"commission"` - MinSelfDelegation sdk.Int `json:"min_self_delegation" yaml:"min_self_delegation"` - DelegatorAddress sdk.AccAddress `json:"delegator_address" yaml:"delegator_address"` - ValidatorAddress sdk.ValAddress `json:"validator_address" yaml:"validator_address"` - PubKey string `json:"pubkey" yaml:"pubkey"` - Value sdk.Coin `json:"value" yaml:"value"` -} - // NewMsgCreateValidator creates a new MsgCreateValidator instance. // Delegator address and validator address are the same. func NewMsgCreateValidator( @@ -50,11 +24,16 @@ func NewMsgCreateValidator( description Description, commission CommissionRates, minSelfDelegation sdk.Int, ) MsgCreateValidator { + var pkStr string + if pubKey != nil { + pkStr = sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, pubKey) + } + return MsgCreateValidator{ Description: description, DelegatorAddress: sdk.AccAddress(valAddr), ValidatorAddress: valAddr, - PubKey: pubKey, + Pubkey: pkStr, Value: selfDelegation, Commission: commission, MinSelfDelegation: minSelfDelegation, @@ -81,70 +60,6 @@ func (msg MsgCreateValidator) GetSigners() []sdk.AccAddress { return addrs } -// MarshalJSON implements the json.Marshaler interface to provide custom JSON -// serialization of the MsgCreateValidator type. -func (msg MsgCreateValidator) MarshalJSON() ([]byte, error) { - return json.Marshal(msgCreateValidatorJSON{ - Description: msg.Description, - Commission: msg.Commission, - DelegatorAddress: msg.DelegatorAddress, - ValidatorAddress: msg.ValidatorAddress, - PubKey: sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, msg.PubKey), - Value: msg.Value, - MinSelfDelegation: msg.MinSelfDelegation, - }) -} - -// UnmarshalJSON implements the json.Unmarshaler interface to provide custom -// JSON deserialization of the MsgCreateValidator type. -func (msg *MsgCreateValidator) UnmarshalJSON(bz []byte) error { - var msgCreateValJSON msgCreateValidatorJSON - if err := json.Unmarshal(bz, &msgCreateValJSON); err != nil { - return err - } - - msg.Description = msgCreateValJSON.Description - msg.Commission = msgCreateValJSON.Commission - msg.DelegatorAddress = msgCreateValJSON.DelegatorAddress - msg.ValidatorAddress = msgCreateValJSON.ValidatorAddress - var err error - msg.PubKey, err = sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeConsPub, msgCreateValJSON.PubKey) - if err != nil { - return err - } - msg.Value = msgCreateValJSON.Value - msg.MinSelfDelegation = msgCreateValJSON.MinSelfDelegation - - return nil -} - -// MarshalYAML implements a custom marshal yaml function due to consensus pubkey. -func (msg MsgCreateValidator) MarshalYAML() (interface{}, error) { - bs, err := yaml.Marshal(struct { - Description Description - Commission CommissionRates - MinSelfDelegation sdk.Int - DelegatorAddress sdk.AccAddress - ValidatorAddress sdk.ValAddress - PubKey string - Value sdk.Coin - }{ - Description: msg.Description, - Commission: msg.Commission, - MinSelfDelegation: msg.MinSelfDelegation, - DelegatorAddress: msg.DelegatorAddress, - ValidatorAddress: msg.ValidatorAddress, - PubKey: sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, msg.PubKey), - Value: msg.Value, - }) - - if err != nil { - return nil, err - } - - return string(bs), nil -} - // GetSignBytes returns the message bytes to sign over. func (msg MsgCreateValidator) GetSignBytes() []byte { bz := ModuleCdc.MustMarshalJSON(msg) @@ -163,6 +78,9 @@ func (msg MsgCreateValidator) ValidateBasic() error { if !sdk.AccAddress(msg.ValidatorAddress).Equals(msg.DelegatorAddress) { return ErrBadValidatorAddr } + if msg.Pubkey == "" { + return ErrEmptyValidatorPubKey + } if !msg.Value.Amount.IsPositive() { return ErrBadDelegationAmount } @@ -185,20 +103,6 @@ func (msg MsgCreateValidator) ValidateBasic() error { return nil } -// MsgEditValidator - struct for editing a validator -type MsgEditValidator struct { - Description Description `json:"description" yaml:"description"` - ValidatorAddress sdk.ValAddress `json:"address" yaml:"address"` - - // We pass a reference to the new commission rate and min self delegation as it's not mandatory to - // update. If not updated, the deserialized rate will be zero with no way to - // distinguish if an update was intended. - // - // REF: #2373 - CommissionRate *sdk.Dec `json:"commission_rate" yaml:"commission_rate"` - MinSelfDelegation *sdk.Int `json:"min_self_delegation" yaml:"min_self_delegation"` -} - // NewMsgEditValidator creates a new MsgEditValidator instance func NewMsgEditValidator(valAddr sdk.ValAddress, description Description, newRate *sdk.Dec, newMinSelfDelegation *sdk.Int) MsgEditValidator { return MsgEditValidator{ @@ -246,13 +150,6 @@ func (msg MsgEditValidator) ValidateBasic() error { return nil } -// MsgDelegate - struct for bonding transactions -type MsgDelegate struct { - DelegatorAddress sdk.AccAddress `json:"delegator_address" yaml:"delegator_address"` - ValidatorAddress sdk.ValAddress `json:"validator_address" yaml:"validator_address"` - Amount sdk.Coin `json:"amount" yaml:"amount"` -} - // NewMsgDelegate creates a new MsgDelegate instance. func NewMsgDelegate(delAddr sdk.AccAddress, valAddr sdk.ValAddress, amount sdk.Coin) MsgDelegate { return MsgDelegate{ @@ -293,16 +190,6 @@ func (msg MsgDelegate) ValidateBasic() error { return nil } -//______________________________________________________________________ - -// MsgBeginRedelegate defines the attributes of a bonding transaction. -type MsgBeginRedelegate struct { - DelegatorAddress sdk.AccAddress `json:"delegator_address" yaml:"delegator_address"` - ValidatorSrcAddress sdk.ValAddress `json:"validator_src_address" yaml:"validator_src_address"` - ValidatorDstAddress sdk.ValAddress `json:"validator_dst_address" yaml:"validator_dst_address"` - Amount sdk.Coin `json:"amount" yaml:"amount"` -} - // NewMsgBeginRedelegate creates a new MsgBeginRedelegate instance. func NewMsgBeginRedelegate( delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress, amount sdk.Coin, @@ -349,13 +236,6 @@ func (msg MsgBeginRedelegate) ValidateBasic() error { return nil } -// MsgUndelegate - struct for unbonding transactions -type MsgUndelegate struct { - DelegatorAddress sdk.AccAddress `json:"delegator_address" yaml:"delegator_address"` - ValidatorAddress sdk.ValAddress `json:"validator_address" yaml:"validator_address"` - Amount sdk.Coin `json:"amount" yaml:"amount"` -} - // NewMsgUndelegate creates a new MsgUndelegate instance. func NewMsgUndelegate(delAddr sdk.AccAddress, valAddr sdk.ValAddress, amount sdk.Coin) MsgUndelegate { return MsgUndelegate{ diff --git a/x/staking/types/msg_test.go b/x/staking/types/msg_test.go index 784b653d2b8f..99866b11ca65 100644 --- a/x/staking/types/msg_test.go +++ b/x/staking/types/msg_test.go @@ -1,11 +1,8 @@ package types import ( - "fmt" "testing" - yaml "gopkg.in/yaml.v2" - "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/crypto" @@ -35,7 +32,7 @@ func TestMsgCreateValidator(t *testing.T) { {"partial description", "", "", "c", "", "", commission1, sdk.OneInt(), valAddr1, pk1, coinPos, true}, {"empty description", "", "", "", "", "", commission2, sdk.OneInt(), valAddr1, pk1, coinPos, false}, {"empty address", "a", "b", "c", "d", "e", commission2, sdk.OneInt(), emptyAddr, pk1, coinPos, false}, - {"empty pubkey", "a", "b", "c", "d", "e", commission1, sdk.OneInt(), valAddr1, emptyPubkey, coinPos, true}, + {"empty pubkey", "a", "b", "c", "d", "e", commission1, sdk.OneInt(), valAddr1, emptyPubkey, coinPos, false}, {"empty bond", "a", "b", "c", "d", "e", commission2, sdk.OneInt(), valAddr1, pk1, coinZero, false}, {"zero min self delegation", "a", "b", "c", "d", "e", commission1, sdk.ZeroInt(), valAddr1, pk1, coinPos, false}, {"negative min self delegation", "a", "b", "c", "d", "e", commission1, sdk.NewInt(-1), valAddr1, pk1, coinPos, false}, @@ -157,47 +154,3 @@ func TestMsgUndelegate(t *testing.T) { } } } - -//test to validate if NewMsgCreateValidator implements yaml marshaller -func TestMsgMarshalYAML(t *testing.T) { - commission1 := NewCommissionRates(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()) - tc := struct { - name, moniker, identity, website, securityContact, details string - CommissionRates CommissionRates - minSelfDelegation sdk.Int - validatorAddr sdk.ValAddress - pubkey crypto.PubKey - bond sdk.Coin - expectPass bool - }{"basic good", "a", "b", "c", "d", "e", commission1, sdk.OneInt(), valAddr1, pk1, coinPos, true} - - description := NewDescription(tc.moniker, tc.identity, tc.website, tc.securityContact, tc.details) - msg := NewMsgCreateValidator(tc.validatorAddr, tc.pubkey, tc.bond, description, tc.CommissionRates, tc.minSelfDelegation) - bs, err := yaml.Marshal(msg) - require.NoError(t, err) - bechifiedPub, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, msg.PubKey) - require.NoError(t, err) - - want := fmt.Sprintf(`| - description: - moniker: a - identity: b - website: c - security_contact: d - details: e - commission: - rate: "0.000000000000000000" - max_rate: "0.000000000000000000" - max_change_rate: "0.000000000000000000" - minselfdelegation: "1" - delegatoraddress: %s - validatoraddress: %s - pubkey: %s - value: - denom: stake - amount: "1000" -`, msg.DelegatorAddress, msg.ValidatorAddress, bechifiedPub) - - require.Equal(t, want, string(bs)) - -} diff --git a/x/staking/types/params.go b/x/staking/types/params.go index f3aefb404899..ae3dd7cf8ae7 100644 --- a/x/staking/types/params.go +++ b/x/staking/types/params.go @@ -1,7 +1,6 @@ package types import ( - "bytes" "errors" "fmt" "strings" @@ -10,6 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/params" + yaml "gopkg.in/yaml.v2" ) // Staking params default values @@ -20,14 +20,14 @@ const ( DefaultUnbondingTime time.Duration = time.Hour * 24 * 7 * 3 // Default maximum number of bonded validators - DefaultMaxValidators uint16 = 100 + DefaultMaxValidators uint32 = 100 // Default maximum entries in a UBD/RED pair - DefaultMaxEntries uint16 = 7 + DefaultMaxEntries uint32 = 7 // DefaultHistorical entries is 0 since it must only be non-zero for // IBC connected chains - DefaultHistoricalEntries uint16 = 0 + DefaultHistoricalEntries uint32 = 0 ) // nolint - Keys for parameter access @@ -41,18 +41,10 @@ var ( var _ params.ParamSet = (*Params)(nil) -// Params defines the high level settings for staking -type Params struct { - UnbondingTime time.Duration `json:"unbonding_time" yaml:"unbonding_time"` // time duration of unbonding - MaxValidators uint16 `json:"max_validators" yaml:"max_validators"` // maximum number of validators (max uint16 = 65535) - MaxEntries uint16 `json:"max_entries" yaml:"max_entries"` // max entries for either unbonding delegation or redelegation (per pair/trio) - HistoricalEntries uint16 `json:"historical_entries" yaml:"historical_entries"` // number of historical entries to persist - BondDenom string `json:"bond_denom" yaml:"bond_denom"` // bondable coin denomination -} - // NewParams creates a new Params instance -func NewParams(unbondingTime time.Duration, maxValidators, maxEntries, historicalEntries uint16, - bondDenom string) Params { +func NewParams( + unbondingTime time.Duration, maxValidators, maxEntries, historicalEntries uint32, bondDenom string, +) Params { return Params{ UnbondingTime: unbondingTime, @@ -74,28 +66,21 @@ func (p *Params) ParamSetPairs() params.ParamSetPairs { } } -// Equal returns a boolean determining if two Param types are identical. -// TODO: This is slower than comparing struct fields directly -func (p Params) Equal(p2 Params) bool { - bz1 := ModuleCdc.MustMarshalBinaryLengthPrefixed(&p) - bz2 := ModuleCdc.MustMarshalBinaryLengthPrefixed(&p2) - return bytes.Equal(bz1, bz2) -} - // DefaultParams returns a default set of parameters. func DefaultParams() Params { - return NewParams(DefaultUnbondingTime, DefaultMaxValidators, DefaultMaxEntries, DefaultHistoricalEntries, sdk.DefaultBondDenom) + return NewParams( + DefaultUnbondingTime, + DefaultMaxValidators, + DefaultMaxEntries, + DefaultHistoricalEntries, + sdk.DefaultBondDenom, + ) } // String returns a human readable string representation of the parameters. func (p Params) String() string { - return fmt.Sprintf(`Params: - Unbonding Time: %s - Max Validators: %d - Max Entries: %d - Historical Entries: %d - Bonded Coin Denom: %s`, p.UnbondingTime, - p.MaxValidators, p.MaxEntries, p.HistoricalEntries, p.BondDenom) + out, _ := yaml.Marshal(p) + return string(out) } // unmarshal the current staking params value from store key or panic @@ -148,7 +133,7 @@ func validateUnbondingTime(i interface{}) error { } func validateMaxValidators(i interface{}) error { - v, ok := i.(uint16) + v, ok := i.(uint32) if !ok { return fmt.Errorf("invalid parameter type: %T", i) } @@ -161,7 +146,7 @@ func validateMaxValidators(i interface{}) error { } func validateMaxEntries(i interface{}) error { - v, ok := i.(uint16) + v, ok := i.(uint32) if !ok { return fmt.Errorf("invalid parameter type: %T", i) } @@ -174,7 +159,7 @@ func validateMaxEntries(i interface{}) error { } func validateHistoricalEntries(i interface{}) error { - _, ok := i.(uint16) + _, ok := i.(uint32) if !ok { return fmt.Errorf("invalid parameter type: %T", i) } diff --git a/x/staking/types/types.pb.go b/x/staking/types/types.pb.go new file mode 100644 index 000000000000..78da36fae466 --- /dev/null +++ b/x/staking/types/types.pb.go @@ -0,0 +1,6831 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: x/staking/types/types.proto + +package types + +import ( + bytes "bytes" + fmt "fmt" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" + _ "github.com/golang/protobuf/ptypes/duration" + _ "github.com/golang/protobuf/ptypes/timestamp" + types1 "github.com/tendermint/tendermint/abci/types" + io "io" + math "math" + math_bits "math/bits" + time "time" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf +var _ = time.Kitchen + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// MsgCreateValidator defines an SDK message for creating a new validator. +type MsgCreateValidator struct { + Description Description `protobuf:"bytes,1,opt,name=description,proto3" json:"description"` + Commission CommissionRates `protobuf:"bytes,2,opt,name=commission,proto3" json:"commission"` + MinSelfDelegation github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,3,opt,name=min_self_delegation,json=minSelfDelegation,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"min_self_delegation" yaml:"min_self_delegation"` + DelegatorAddress github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,4,opt,name=delegator_address,json=delegatorAddress,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"delegator_address,omitempty" yaml:"delegator_address"` + ValidatorAddress github_com_cosmos_cosmos_sdk_types.ValAddress `protobuf:"bytes,5,opt,name=validator_address,json=validatorAddress,proto3,casttype=github.com/cosmos/cosmos-sdk/types.ValAddress" json:"validator_address,omitempty" yaml:"validator_address"` + Pubkey string `protobuf:"bytes,6,opt,name=pubkey,proto3" json:"pubkey,omitempty"` + Value types.Coin `protobuf:"bytes,7,opt,name=value,proto3" json:"value"` +} + +func (m *MsgCreateValidator) Reset() { *m = MsgCreateValidator{} } +func (m *MsgCreateValidator) String() string { return proto.CompactTextString(m) } +func (*MsgCreateValidator) ProtoMessage() {} +func (*MsgCreateValidator) Descriptor() ([]byte, []int) { + return fileDescriptor_c669c0a3ee1b124c, []int{0} +} +func (m *MsgCreateValidator) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgCreateValidator) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgCreateValidator.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 *MsgCreateValidator) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgCreateValidator.Merge(m, src) +} +func (m *MsgCreateValidator) XXX_Size() int { + return m.Size() +} +func (m *MsgCreateValidator) XXX_DiscardUnknown() { + xxx_messageInfo_MsgCreateValidator.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgCreateValidator proto.InternalMessageInfo + +func (m *MsgCreateValidator) GetDescription() Description { + if m != nil { + return m.Description + } + return Description{} +} + +func (m *MsgCreateValidator) GetCommission() CommissionRates { + if m != nil { + return m.Commission + } + return CommissionRates{} +} + +func (m *MsgCreateValidator) GetDelegatorAddress() github_com_cosmos_cosmos_sdk_types.AccAddress { + if m != nil { + return m.DelegatorAddress + } + return nil +} + +func (m *MsgCreateValidator) GetValidatorAddress() github_com_cosmos_cosmos_sdk_types.ValAddress { + if m != nil { + return m.ValidatorAddress + } + return nil +} + +func (m *MsgCreateValidator) GetPubkey() string { + if m != nil { + return m.Pubkey + } + return "" +} + +func (m *MsgCreateValidator) GetValue() types.Coin { + if m != nil { + return m.Value + } + return types.Coin{} +} + +// MsgEditValidator defines an SDK message for editing an existing validator. +type MsgEditValidator struct { + Description Description `protobuf:"bytes,1,opt,name=description,proto3" json:"description"` + ValidatorAddress github_com_cosmos_cosmos_sdk_types.ValAddress `protobuf:"bytes,2,opt,name=validator_address,json=validatorAddress,proto3,casttype=github.com/cosmos/cosmos-sdk/types.ValAddress" json:"validator_address,omitempty" yaml:"address"` + // We pass a reference to the new commission rate and min self delegation as + // it's not mandatory to update. If not updated, the deserialized rate will be + // zero with no way to distinguish if an update was intended. + // + // REF: #2373 + CommissionRate *github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,3,opt,name=commission_rate,json=commissionRate,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"commission_rate,omitempty" yaml:"commission_rate"` + MinSelfDelegation *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,4,opt,name=min_self_delegation,json=minSelfDelegation,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"min_self_delegation,omitempty" yaml:"min_self_delegation"` +} + +func (m *MsgEditValidator) Reset() { *m = MsgEditValidator{} } +func (m *MsgEditValidator) String() string { return proto.CompactTextString(m) } +func (*MsgEditValidator) ProtoMessage() {} +func (*MsgEditValidator) Descriptor() ([]byte, []int) { + return fileDescriptor_c669c0a3ee1b124c, []int{1} +} +func (m *MsgEditValidator) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgEditValidator) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgEditValidator.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 *MsgEditValidator) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgEditValidator.Merge(m, src) +} +func (m *MsgEditValidator) XXX_Size() int { + return m.Size() +} +func (m *MsgEditValidator) XXX_DiscardUnknown() { + xxx_messageInfo_MsgEditValidator.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgEditValidator proto.InternalMessageInfo + +func (m *MsgEditValidator) GetDescription() Description { + if m != nil { + return m.Description + } + return Description{} +} + +func (m *MsgEditValidator) GetValidatorAddress() github_com_cosmos_cosmos_sdk_types.ValAddress { + if m != nil { + return m.ValidatorAddress + } + return nil +} + +// MsgDelegate defines an SDK message for performing a delegation from a +// delegate to a validator. +type MsgDelegate struct { + DelegatorAddress github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,1,opt,name=delegator_address,json=delegatorAddress,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"delegator_address,omitempty" yaml:"delegator_address"` + ValidatorAddress github_com_cosmos_cosmos_sdk_types.ValAddress `protobuf:"bytes,2,opt,name=validator_address,json=validatorAddress,proto3,casttype=github.com/cosmos/cosmos-sdk/types.ValAddress" json:"validator_address,omitempty" yaml:"validator_address"` + Amount types.Coin `protobuf:"bytes,3,opt,name=amount,proto3" json:"amount"` +} + +func (m *MsgDelegate) Reset() { *m = MsgDelegate{} } +func (m *MsgDelegate) String() string { return proto.CompactTextString(m) } +func (*MsgDelegate) ProtoMessage() {} +func (*MsgDelegate) Descriptor() ([]byte, []int) { + return fileDescriptor_c669c0a3ee1b124c, []int{2} +} +func (m *MsgDelegate) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgDelegate) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgDelegate.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 *MsgDelegate) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgDelegate.Merge(m, src) +} +func (m *MsgDelegate) XXX_Size() int { + return m.Size() +} +func (m *MsgDelegate) XXX_DiscardUnknown() { + xxx_messageInfo_MsgDelegate.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgDelegate proto.InternalMessageInfo + +func (m *MsgDelegate) GetDelegatorAddress() github_com_cosmos_cosmos_sdk_types.AccAddress { + if m != nil { + return m.DelegatorAddress + } + return nil +} + +func (m *MsgDelegate) GetValidatorAddress() github_com_cosmos_cosmos_sdk_types.ValAddress { + if m != nil { + return m.ValidatorAddress + } + return nil +} + +func (m *MsgDelegate) GetAmount() types.Coin { + if m != nil { + return m.Amount + } + return types.Coin{} +} + +// MsgBeginRedelegate defines an SDK message for performing a redelegation from +// a delegate and source validator to a destination validator. +type MsgBeginRedelegate struct { + DelegatorAddress github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,1,opt,name=delegator_address,json=delegatorAddress,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"delegator_address,omitempty" yaml:"delegator_address"` + ValidatorSrcAddress github_com_cosmos_cosmos_sdk_types.ValAddress `protobuf:"bytes,2,opt,name=validator_src_address,json=validatorSrcAddress,proto3,casttype=github.com/cosmos/cosmos-sdk/types.ValAddress" json:"validator_src_address,omitempty" yaml:"validator_src_address"` + ValidatorDstAddress github_com_cosmos_cosmos_sdk_types.ValAddress `protobuf:"bytes,3,opt,name=validator_dst_address,json=validatorDstAddress,proto3,casttype=github.com/cosmos/cosmos-sdk/types.ValAddress" json:"validator_dst_address,omitempty" yaml:"validator_dst_address"` + Amount types.Coin `protobuf:"bytes,4,opt,name=amount,proto3" json:"amount"` +} + +func (m *MsgBeginRedelegate) Reset() { *m = MsgBeginRedelegate{} } +func (m *MsgBeginRedelegate) String() string { return proto.CompactTextString(m) } +func (*MsgBeginRedelegate) ProtoMessage() {} +func (*MsgBeginRedelegate) Descriptor() ([]byte, []int) { + return fileDescriptor_c669c0a3ee1b124c, []int{3} +} +func (m *MsgBeginRedelegate) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgBeginRedelegate) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgBeginRedelegate.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 *MsgBeginRedelegate) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgBeginRedelegate.Merge(m, src) +} +func (m *MsgBeginRedelegate) XXX_Size() int { + return m.Size() +} +func (m *MsgBeginRedelegate) XXX_DiscardUnknown() { + xxx_messageInfo_MsgBeginRedelegate.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgBeginRedelegate proto.InternalMessageInfo + +func (m *MsgBeginRedelegate) GetDelegatorAddress() github_com_cosmos_cosmos_sdk_types.AccAddress { + if m != nil { + return m.DelegatorAddress + } + return nil +} + +func (m *MsgBeginRedelegate) GetValidatorSrcAddress() github_com_cosmos_cosmos_sdk_types.ValAddress { + if m != nil { + return m.ValidatorSrcAddress + } + return nil +} + +func (m *MsgBeginRedelegate) GetValidatorDstAddress() github_com_cosmos_cosmos_sdk_types.ValAddress { + if m != nil { + return m.ValidatorDstAddress + } + return nil +} + +func (m *MsgBeginRedelegate) GetAmount() types.Coin { + if m != nil { + return m.Amount + } + return types.Coin{} +} + +// MsgUndelegate defines an SDK message for performing an undelegation from a +// delegate and a validator. +type MsgUndelegate struct { + DelegatorAddress github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,1,opt,name=delegator_address,json=delegatorAddress,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"delegator_address,omitempty" yaml:"delegator_address"` + ValidatorAddress github_com_cosmos_cosmos_sdk_types.ValAddress `protobuf:"bytes,2,opt,name=validator_address,json=validatorAddress,proto3,casttype=github.com/cosmos/cosmos-sdk/types.ValAddress" json:"validator_address,omitempty" yaml:"validator_address"` + Amount types.Coin `protobuf:"bytes,3,opt,name=amount,proto3" json:"amount"` +} + +func (m *MsgUndelegate) Reset() { *m = MsgUndelegate{} } +func (m *MsgUndelegate) String() string { return proto.CompactTextString(m) } +func (*MsgUndelegate) ProtoMessage() {} +func (*MsgUndelegate) Descriptor() ([]byte, []int) { + return fileDescriptor_c669c0a3ee1b124c, []int{4} +} +func (m *MsgUndelegate) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUndelegate) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUndelegate.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 *MsgUndelegate) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUndelegate.Merge(m, src) +} +func (m *MsgUndelegate) XXX_Size() int { + return m.Size() +} +func (m *MsgUndelegate) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUndelegate.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUndelegate proto.InternalMessageInfo + +func (m *MsgUndelegate) GetDelegatorAddress() github_com_cosmos_cosmos_sdk_types.AccAddress { + if m != nil { + return m.DelegatorAddress + } + return nil +} + +func (m *MsgUndelegate) GetValidatorAddress() github_com_cosmos_cosmos_sdk_types.ValAddress { + if m != nil { + return m.ValidatorAddress + } + return nil +} + +func (m *MsgUndelegate) GetAmount() types.Coin { + if m != nil { + return m.Amount + } + return types.Coin{} +} + +// HistoricalInfo contains the historical information that gets stored at +// each height. +type HistoricalInfo struct { + Header types1.Header `protobuf:"bytes,1,opt,name=header,proto3" json:"header"` + Valset []Validator `protobuf:"bytes,2,rep,name=valset,proto3" json:"valset"` +} + +func (m *HistoricalInfo) Reset() { *m = HistoricalInfo{} } +func (m *HistoricalInfo) String() string { return proto.CompactTextString(m) } +func (*HistoricalInfo) ProtoMessage() {} +func (*HistoricalInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_c669c0a3ee1b124c, []int{5} +} +func (m *HistoricalInfo) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *HistoricalInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_HistoricalInfo.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 *HistoricalInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_HistoricalInfo.Merge(m, src) +} +func (m *HistoricalInfo) XXX_Size() int { + return m.Size() +} +func (m *HistoricalInfo) XXX_DiscardUnknown() { + xxx_messageInfo_HistoricalInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_HistoricalInfo proto.InternalMessageInfo + +func (m *HistoricalInfo) GetHeader() types1.Header { + if m != nil { + return m.Header + } + return types1.Header{} +} + +func (m *HistoricalInfo) GetValset() []Validator { + if m != nil { + return m.Valset + } + return nil +} + +// CommissionRates defines the initial commission rates to be used for creating +// a validator. +type CommissionRates struct { + Rate github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,1,opt,name=rate,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"rate"` + MaxRate github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,2,opt,name=max_rate,json=maxRate,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"max_rate" yaml:"max_rate"` + MaxChangeRate github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,3,opt,name=max_change_rate,json=maxChangeRate,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"max_change_rate" yaml:"max_change_rate"` +} + +func (m *CommissionRates) Reset() { *m = CommissionRates{} } +func (*CommissionRates) ProtoMessage() {} +func (*CommissionRates) Descriptor() ([]byte, []int) { + return fileDescriptor_c669c0a3ee1b124c, []int{6} +} +func (m *CommissionRates) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CommissionRates) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CommissionRates.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 *CommissionRates) XXX_Merge(src proto.Message) { + xxx_messageInfo_CommissionRates.Merge(m, src) +} +func (m *CommissionRates) XXX_Size() int { + return m.Size() +} +func (m *CommissionRates) XXX_DiscardUnknown() { + xxx_messageInfo_CommissionRates.DiscardUnknown(m) +} + +var xxx_messageInfo_CommissionRates proto.InternalMessageInfo + +// Commission defines a commission parameters for a given validator. +type Commission struct { + CommissionRates `protobuf:"bytes,1,opt,name=commission_rates,json=commissionRates,proto3,embedded=commission_rates" json:"commission_rates"` + UpdateTime time.Time `protobuf:"bytes,2,opt,name=update_time,json=updateTime,proto3,stdtime" json:"update_time" yaml:"update_time"` +} + +func (m *Commission) Reset() { *m = Commission{} } +func (*Commission) ProtoMessage() {} +func (*Commission) Descriptor() ([]byte, []int) { + return fileDescriptor_c669c0a3ee1b124c, []int{7} +} +func (m *Commission) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Commission) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Commission.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 *Commission) XXX_Merge(src proto.Message) { + xxx_messageInfo_Commission.Merge(m, src) +} +func (m *Commission) XXX_Size() int { + return m.Size() +} +func (m *Commission) XXX_DiscardUnknown() { + xxx_messageInfo_Commission.DiscardUnknown(m) +} + +var xxx_messageInfo_Commission proto.InternalMessageInfo + +func (m *Commission) GetUpdateTime() time.Time { + if m != nil { + return m.UpdateTime + } + return time.Time{} +} + +// Description defines a validator description. +type Description struct { + Moniker string `protobuf:"bytes,1,opt,name=moniker,proto3" json:"moniker,omitempty"` + Identity string `protobuf:"bytes,2,opt,name=identity,proto3" json:"identity,omitempty"` + Website string `protobuf:"bytes,3,opt,name=website,proto3" json:"website,omitempty"` + SecurityContact string `protobuf:"bytes,4,opt,name=security_contact,json=securityContact,proto3" json:"security_contact,omitempty" yaml:"security_contact"` + Details string `protobuf:"bytes,5,opt,name=details,proto3" json:"details,omitempty"` +} + +func (m *Description) Reset() { *m = Description{} } +func (*Description) ProtoMessage() {} +func (*Description) Descriptor() ([]byte, []int) { + return fileDescriptor_c669c0a3ee1b124c, []int{8} +} +func (m *Description) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Description) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Description.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 *Description) XXX_Merge(src proto.Message) { + xxx_messageInfo_Description.Merge(m, src) +} +func (m *Description) XXX_Size() int { + return m.Size() +} +func (m *Description) XXX_DiscardUnknown() { + xxx_messageInfo_Description.DiscardUnknown(m) +} + +var xxx_messageInfo_Description proto.InternalMessageInfo + +func (m *Description) GetMoniker() string { + if m != nil { + return m.Moniker + } + return "" +} + +func (m *Description) GetIdentity() string { + if m != nil { + return m.Identity + } + return "" +} + +func (m *Description) GetWebsite() string { + if m != nil { + return m.Website + } + return "" +} + +func (m *Description) GetSecurityContact() string { + if m != nil { + return m.SecurityContact + } + return "" +} + +func (m *Description) GetDetails() string { + if m != nil { + return m.Details + } + return "" +} + +// Validator defines the total amount of bond shares and their exchange rate to +// coins. Slashing results in a decrease in the exchange rate, allowing correct +// calculation of future undelegations without iterating over delegators. +// When coins are delegated to this validator, the validator is credited with a +// delegation whose number of bond shares is based on the amount of coins +// delegated divided by the current exchange rate. Voting power can be +// calculated as total bonded shares multiplied by exchange rate. +type Validator struct { + OperatorAddress github_com_cosmos_cosmos_sdk_types.ValAddress `protobuf:"bytes,1,opt,name=operator_address,json=operatorAddress,proto3,casttype=github.com/cosmos/cosmos-sdk/types.ValAddress" json:"operator_address,omitempty" yaml:"operator_address"` + ConsensusPubkey string `protobuf:"bytes,2,opt,name=consensus_pubkey,json=consensusPubkey,proto3" json:"consensus_pubkey,omitempty" yaml:"consensus_pubkey"` + Jailed bool `protobuf:"varint,3,opt,name=jailed,proto3" json:"jailed,omitempty"` + Status github_com_cosmos_cosmos_sdk_types.BondStatus `protobuf:"varint,4,opt,name=status,proto3,casttype=github.com/cosmos/cosmos-sdk/types.BondStatus" json:"status,omitempty"` + Tokens github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,5,opt,name=tokens,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"tokens"` + DelegatorShares github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,6,opt,name=delegator_shares,json=delegatorShares,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"delegator_shares" yaml:"delegator_shares"` + Description Description `protobuf:"bytes,7,opt,name=description,proto3" json:"description"` + UnbondingHeight int64 `protobuf:"varint,8,opt,name=unbonding_height,json=unbondingHeight,proto3" json:"unbonding_height,omitempty" yaml:"unbonding_height"` + UnbondingTime time.Time `protobuf:"bytes,9,opt,name=unbonding_time,json=unbondingTime,proto3,stdtime" json:"unbonding_time" yaml:"unbonding_time"` + Commission Commission `protobuf:"bytes,10,opt,name=commission,proto3" json:"commission"` + MinSelfDelegation github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,11,opt,name=min_self_delegation,json=minSelfDelegation,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"min_self_delegation" yaml:"min_self_delegation"` +} + +func (m *Validator) Reset() { *m = Validator{} } +func (*Validator) ProtoMessage() {} +func (*Validator) Descriptor() ([]byte, []int) { + return fileDescriptor_c669c0a3ee1b124c, []int{9} +} +func (m *Validator) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Validator) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Validator.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 *Validator) XXX_Merge(src proto.Message) { + xxx_messageInfo_Validator.Merge(m, src) +} +func (m *Validator) XXX_Size() int { + return m.Size() +} +func (m *Validator) XXX_DiscardUnknown() { + xxx_messageInfo_Validator.DiscardUnknown(m) +} + +var xxx_messageInfo_Validator proto.InternalMessageInfo + +// DVPair is struct that just has a delegator-validator pair with no other data. +// It is intended to be used as a marshalable pointer. For example, a DVPair can +// be used to construct the key to getting an UnbondingDelegation from state. +type DVPair struct { + DelegatorAddress github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,1,opt,name=delegator_address,json=delegatorAddress,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"delegator_address,omitempty" yaml:"delegator_address"` + ValidatorAddress github_com_cosmos_cosmos_sdk_types.ValAddress `protobuf:"bytes,2,opt,name=validator_address,json=validatorAddress,proto3,casttype=github.com/cosmos/cosmos-sdk/types.ValAddress" json:"validator_address,omitempty" yaml:"validator_address"` +} + +func (m *DVPair) Reset() { *m = DVPair{} } +func (*DVPair) ProtoMessage() {} +func (*DVPair) Descriptor() ([]byte, []int) { + return fileDescriptor_c669c0a3ee1b124c, []int{10} +} +func (m *DVPair) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DVPair) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DVPair.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 *DVPair) XXX_Merge(src proto.Message) { + xxx_messageInfo_DVPair.Merge(m, src) +} +func (m *DVPair) XXX_Size() int { + return m.Size() +} +func (m *DVPair) XXX_DiscardUnknown() { + xxx_messageInfo_DVPair.DiscardUnknown(m) +} + +var xxx_messageInfo_DVPair proto.InternalMessageInfo + +func (m *DVPair) GetDelegatorAddress() github_com_cosmos_cosmos_sdk_types.AccAddress { + if m != nil { + return m.DelegatorAddress + } + return nil +} + +func (m *DVPair) GetValidatorAddress() github_com_cosmos_cosmos_sdk_types.ValAddress { + if m != nil { + return m.ValidatorAddress + } + return nil +} + +// DVPairs defines an array of DVPair objects. +type DVPairs struct { + Pairs []DVPair `protobuf:"bytes,1,rep,name=pairs,proto3" json:"pairs"` +} + +func (m *DVPairs) Reset() { *m = DVPairs{} } +func (m *DVPairs) String() string { return proto.CompactTextString(m) } +func (*DVPairs) ProtoMessage() {} +func (*DVPairs) Descriptor() ([]byte, []int) { + return fileDescriptor_c669c0a3ee1b124c, []int{11} +} +func (m *DVPairs) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DVPairs) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DVPairs.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 *DVPairs) XXX_Merge(src proto.Message) { + xxx_messageInfo_DVPairs.Merge(m, src) +} +func (m *DVPairs) XXX_Size() int { + return m.Size() +} +func (m *DVPairs) XXX_DiscardUnknown() { + xxx_messageInfo_DVPairs.DiscardUnknown(m) +} + +var xxx_messageInfo_DVPairs proto.InternalMessageInfo + +func (m *DVPairs) GetPairs() []DVPair { + if m != nil { + return m.Pairs + } + return nil +} + +// DVVTriplet is struct that just has a delegator-validator-validator triplet +// with no other data. It is intended to be used as a marshalable pointer. For +// example, a DVVTriplet can be used to construct the key to getting a +// Redelegation from state. +type DVVTriplet struct { + DelegatorAddress github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,1,opt,name=delegator_address,json=delegatorAddress,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"delegator_address,omitempty" yaml:"delegator_address"` + ValidatorSrcAddress github_com_cosmos_cosmos_sdk_types.ValAddress `protobuf:"bytes,2,opt,name=validator_src_address,json=validatorSrcAddress,proto3,casttype=github.com/cosmos/cosmos-sdk/types.ValAddress" json:"validator_src_address,omitempty" yaml:"validator_src_address"` + ValidatorDstAddress github_com_cosmos_cosmos_sdk_types.ValAddress `protobuf:"bytes,3,opt,name=validator_dst_address,json=validatorDstAddress,proto3,casttype=github.com/cosmos/cosmos-sdk/types.ValAddress" json:"validator_dst_address,omitempty" yaml:"validator_dst_address"` +} + +func (m *DVVTriplet) Reset() { *m = DVVTriplet{} } +func (*DVVTriplet) ProtoMessage() {} +func (*DVVTriplet) Descriptor() ([]byte, []int) { + return fileDescriptor_c669c0a3ee1b124c, []int{12} +} +func (m *DVVTriplet) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DVVTriplet) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DVVTriplet.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 *DVVTriplet) XXX_Merge(src proto.Message) { + xxx_messageInfo_DVVTriplet.Merge(m, src) +} +func (m *DVVTriplet) XXX_Size() int { + return m.Size() +} +func (m *DVVTriplet) XXX_DiscardUnknown() { + xxx_messageInfo_DVVTriplet.DiscardUnknown(m) +} + +var xxx_messageInfo_DVVTriplet proto.InternalMessageInfo + +func (m *DVVTriplet) GetDelegatorAddress() github_com_cosmos_cosmos_sdk_types.AccAddress { + if m != nil { + return m.DelegatorAddress + } + return nil +} + +func (m *DVVTriplet) GetValidatorSrcAddress() github_com_cosmos_cosmos_sdk_types.ValAddress { + if m != nil { + return m.ValidatorSrcAddress + } + return nil +} + +func (m *DVVTriplet) GetValidatorDstAddress() github_com_cosmos_cosmos_sdk_types.ValAddress { + if m != nil { + return m.ValidatorDstAddress + } + return nil +} + +// DVVTriplets defines an array of DVVTriplet objects. +type DVVTriplets struct { + Triplets []DVVTriplet `protobuf:"bytes,1,rep,name=triplets,proto3" json:"triplets"` +} + +func (m *DVVTriplets) Reset() { *m = DVVTriplets{} } +func (m *DVVTriplets) String() string { return proto.CompactTextString(m) } +func (*DVVTriplets) ProtoMessage() {} +func (*DVVTriplets) Descriptor() ([]byte, []int) { + return fileDescriptor_c669c0a3ee1b124c, []int{13} +} +func (m *DVVTriplets) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DVVTriplets) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DVVTriplets.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 *DVVTriplets) XXX_Merge(src proto.Message) { + xxx_messageInfo_DVVTriplets.Merge(m, src) +} +func (m *DVVTriplets) XXX_Size() int { + return m.Size() +} +func (m *DVVTriplets) XXX_DiscardUnknown() { + xxx_messageInfo_DVVTriplets.DiscardUnknown(m) +} + +var xxx_messageInfo_DVVTriplets proto.InternalMessageInfo + +func (m *DVVTriplets) GetTriplets() []DVVTriplet { + if m != nil { + return m.Triplets + } + return nil +} + +// Delegation represents the bond with tokens held by an account. It is +// owned by one delegator, and is associated with the voting power of one +// validator. +type Delegation struct { + DelegatorAddress github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,1,opt,name=delegator_address,json=delegatorAddress,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"delegator_address,omitempty" yaml:"delegator_address"` + ValidatorAddress github_com_cosmos_cosmos_sdk_types.ValAddress `protobuf:"bytes,2,opt,name=validator_address,json=validatorAddress,proto3,casttype=github.com/cosmos/cosmos-sdk/types.ValAddress" json:"validator_address,omitempty" yaml:"validator_address"` + Shares github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,3,opt,name=shares,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"shares"` +} + +func (m *Delegation) Reset() { *m = Delegation{} } +func (*Delegation) ProtoMessage() {} +func (*Delegation) Descriptor() ([]byte, []int) { + return fileDescriptor_c669c0a3ee1b124c, []int{14} +} +func (m *Delegation) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Delegation) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Delegation.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 *Delegation) XXX_Merge(src proto.Message) { + xxx_messageInfo_Delegation.Merge(m, src) +} +func (m *Delegation) XXX_Size() int { + return m.Size() +} +func (m *Delegation) XXX_DiscardUnknown() { + xxx_messageInfo_Delegation.DiscardUnknown(m) +} + +var xxx_messageInfo_Delegation proto.InternalMessageInfo + +func (m *Delegation) GetDelegatorAddress() github_com_cosmos_cosmos_sdk_types.AccAddress { + if m != nil { + return m.DelegatorAddress + } + return nil +} + +func (m *Delegation) GetValidatorAddress() github_com_cosmos_cosmos_sdk_types.ValAddress { + if m != nil { + return m.ValidatorAddress + } + return nil +} + +// UnbondingDelegation stores all of a single delegator's unbonding bonds +// for a single validator in an time-ordered list +type UnbondingDelegation struct { + DelegatorAddress github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,1,opt,name=delegator_address,json=delegatorAddress,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"delegator_address,omitempty" yaml:"delegator_address"` + ValidatorAddress github_com_cosmos_cosmos_sdk_types.ValAddress `protobuf:"bytes,2,opt,name=validator_address,json=validatorAddress,proto3,casttype=github.com/cosmos/cosmos-sdk/types.ValAddress" json:"validator_address,omitempty" yaml:"validator_address"` + Entries []UnbondingDelegationEntry `protobuf:"bytes,3,rep,name=entries,proto3" json:"entries"` +} + +func (m *UnbondingDelegation) Reset() { *m = UnbondingDelegation{} } +func (*UnbondingDelegation) ProtoMessage() {} +func (*UnbondingDelegation) Descriptor() ([]byte, []int) { + return fileDescriptor_c669c0a3ee1b124c, []int{15} +} +func (m *UnbondingDelegation) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *UnbondingDelegation) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_UnbondingDelegation.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 *UnbondingDelegation) XXX_Merge(src proto.Message) { + xxx_messageInfo_UnbondingDelegation.Merge(m, src) +} +func (m *UnbondingDelegation) XXX_Size() int { + return m.Size() +} +func (m *UnbondingDelegation) XXX_DiscardUnknown() { + xxx_messageInfo_UnbondingDelegation.DiscardUnknown(m) +} + +var xxx_messageInfo_UnbondingDelegation proto.InternalMessageInfo + +func (m *UnbondingDelegation) GetDelegatorAddress() github_com_cosmos_cosmos_sdk_types.AccAddress { + if m != nil { + return m.DelegatorAddress + } + return nil +} + +func (m *UnbondingDelegation) GetValidatorAddress() github_com_cosmos_cosmos_sdk_types.ValAddress { + if m != nil { + return m.ValidatorAddress + } + return nil +} + +func (m *UnbondingDelegation) GetEntries() []UnbondingDelegationEntry { + if m != nil { + return m.Entries + } + return nil +} + +// UnbondingDelegationEntry defines an unbonding object with relevant metadata. +type UnbondingDelegationEntry struct { + CreationHeight int64 `protobuf:"varint,1,opt,name=creation_height,json=creationHeight,proto3" json:"creation_height,omitempty" yaml:"creation_height"` + CompletionTime time.Time `protobuf:"bytes,2,opt,name=completion_time,json=completionTime,proto3,stdtime" json:"completion_time" yaml:"completion_time"` + InitialBalance github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,3,opt,name=initial_balance,json=initialBalance,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"initial_balance" yaml:"initial_balance"` + Balance github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,4,opt,name=balance,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"balance"` +} + +func (m *UnbondingDelegationEntry) Reset() { *m = UnbondingDelegationEntry{} } +func (*UnbondingDelegationEntry) ProtoMessage() {} +func (*UnbondingDelegationEntry) Descriptor() ([]byte, []int) { + return fileDescriptor_c669c0a3ee1b124c, []int{16} +} +func (m *UnbondingDelegationEntry) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *UnbondingDelegationEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_UnbondingDelegationEntry.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 *UnbondingDelegationEntry) XXX_Merge(src proto.Message) { + xxx_messageInfo_UnbondingDelegationEntry.Merge(m, src) +} +func (m *UnbondingDelegationEntry) XXX_Size() int { + return m.Size() +} +func (m *UnbondingDelegationEntry) XXX_DiscardUnknown() { + xxx_messageInfo_UnbondingDelegationEntry.DiscardUnknown(m) +} + +var xxx_messageInfo_UnbondingDelegationEntry proto.InternalMessageInfo + +func (m *UnbondingDelegationEntry) GetCreationHeight() int64 { + if m != nil { + return m.CreationHeight + } + return 0 +} + +func (m *UnbondingDelegationEntry) GetCompletionTime() time.Time { + if m != nil { + return m.CompletionTime + } + return time.Time{} +} + +// RedelegationEntry defines a redelegation object with relevant metadata. +type RedelegationEntry struct { + CreationHeight int64 `protobuf:"varint,1,opt,name=creation_height,json=creationHeight,proto3" json:"creation_height,omitempty" yaml:"creation_height"` + CompletionTime time.Time `protobuf:"bytes,2,opt,name=completion_time,json=completionTime,proto3,stdtime" json:"completion_time" yaml:"completion_time"` + InitialBalance github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,3,opt,name=initial_balance,json=initialBalance,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"initial_balance" yaml:"initial_balance"` + SharesDst github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,4,opt,name=shares_dst,json=sharesDst,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"shares_dst"` +} + +func (m *RedelegationEntry) Reset() { *m = RedelegationEntry{} } +func (*RedelegationEntry) ProtoMessage() {} +func (*RedelegationEntry) Descriptor() ([]byte, []int) { + return fileDescriptor_c669c0a3ee1b124c, []int{17} +} +func (m *RedelegationEntry) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RedelegationEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RedelegationEntry.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 *RedelegationEntry) XXX_Merge(src proto.Message) { + xxx_messageInfo_RedelegationEntry.Merge(m, src) +} +func (m *RedelegationEntry) XXX_Size() int { + return m.Size() +} +func (m *RedelegationEntry) XXX_DiscardUnknown() { + xxx_messageInfo_RedelegationEntry.DiscardUnknown(m) +} + +var xxx_messageInfo_RedelegationEntry proto.InternalMessageInfo + +func (m *RedelegationEntry) GetCreationHeight() int64 { + if m != nil { + return m.CreationHeight + } + return 0 +} + +func (m *RedelegationEntry) GetCompletionTime() time.Time { + if m != nil { + return m.CompletionTime + } + return time.Time{} +} + +// Redelegation contains the list of a particular delegator's redelegating bonds +// from a particular source validator to a particular destination validator. +type Redelegation struct { + DelegatorAddress github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,1,opt,name=delegator_address,json=delegatorAddress,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"delegator_address,omitempty" yaml:"delegator_address"` + ValidatorSrcAddress github_com_cosmos_cosmos_sdk_types.ValAddress `protobuf:"bytes,2,opt,name=validator_src_address,json=validatorSrcAddress,proto3,casttype=github.com/cosmos/cosmos-sdk/types.ValAddress" json:"validator_src_address,omitempty" yaml:"validator_src_address"` + ValidatorDstAddress github_com_cosmos_cosmos_sdk_types.ValAddress `protobuf:"bytes,3,opt,name=validator_dst_address,json=validatorDstAddress,proto3,casttype=github.com/cosmos/cosmos-sdk/types.ValAddress" json:"validator_dst_address,omitempty" yaml:"validator_dst_address"` + Entries []RedelegationEntry `protobuf:"bytes,4,rep,name=entries,proto3" json:"entries"` +} + +func (m *Redelegation) Reset() { *m = Redelegation{} } +func (*Redelegation) ProtoMessage() {} +func (*Redelegation) Descriptor() ([]byte, []int) { + return fileDescriptor_c669c0a3ee1b124c, []int{18} +} +func (m *Redelegation) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Redelegation) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Redelegation.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 *Redelegation) XXX_Merge(src proto.Message) { + xxx_messageInfo_Redelegation.Merge(m, src) +} +func (m *Redelegation) XXX_Size() int { + return m.Size() +} +func (m *Redelegation) XXX_DiscardUnknown() { + xxx_messageInfo_Redelegation.DiscardUnknown(m) +} + +var xxx_messageInfo_Redelegation proto.InternalMessageInfo + +func (m *Redelegation) GetDelegatorAddress() github_com_cosmos_cosmos_sdk_types.AccAddress { + if m != nil { + return m.DelegatorAddress + } + return nil +} + +func (m *Redelegation) GetValidatorSrcAddress() github_com_cosmos_cosmos_sdk_types.ValAddress { + if m != nil { + return m.ValidatorSrcAddress + } + return nil +} + +func (m *Redelegation) GetValidatorDstAddress() github_com_cosmos_cosmos_sdk_types.ValAddress { + if m != nil { + return m.ValidatorDstAddress + } + return nil +} + +func (m *Redelegation) GetEntries() []RedelegationEntry { + if m != nil { + return m.Entries + } + return nil +} + +// Params defines the parameters for the staking module. +type Params struct { + UnbondingTime time.Duration `protobuf:"bytes,1,opt,name=unbonding_time,json=unbondingTime,proto3,stdduration" json:"unbonding_time" yaml:"unbonding_time"` + MaxValidators uint32 `protobuf:"varint,2,opt,name=max_validators,json=maxValidators,proto3" json:"max_validators,omitempty" yaml:"max_validators"` + MaxEntries uint32 `protobuf:"varint,3,opt,name=max_entries,json=maxEntries,proto3" json:"max_entries,omitempty" yaml:"max_entries"` + HistoricalEntries uint32 `protobuf:"varint,4,opt,name=historical_entries,json=historicalEntries,proto3" json:"historical_entries,omitempty" yaml:"historical_entries"` + BondDenom string `protobuf:"bytes,5,opt,name=bond_denom,json=bondDenom,proto3" json:"bond_denom,omitempty" yaml:"bond_denom"` +} + +func (m *Params) Reset() { *m = Params{} } +func (*Params) ProtoMessage() {} +func (*Params) Descriptor() ([]byte, []int) { + return fileDescriptor_c669c0a3ee1b124c, []int{19} +} +func (m *Params) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Params) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Params.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 *Params) XXX_Merge(src proto.Message) { + xxx_messageInfo_Params.Merge(m, src) +} +func (m *Params) XXX_Size() int { + return m.Size() +} +func (m *Params) XXX_DiscardUnknown() { + xxx_messageInfo_Params.DiscardUnknown(m) +} + +var xxx_messageInfo_Params proto.InternalMessageInfo + +func (m *Params) GetUnbondingTime() time.Duration { + if m != nil { + return m.UnbondingTime + } + return 0 +} + +func (m *Params) GetMaxValidators() uint32 { + if m != nil { + return m.MaxValidators + } + return 0 +} + +func (m *Params) GetMaxEntries() uint32 { + if m != nil { + return m.MaxEntries + } + return 0 +} + +func (m *Params) GetHistoricalEntries() uint32 { + if m != nil { + return m.HistoricalEntries + } + return 0 +} + +func (m *Params) GetBondDenom() string { + if m != nil { + return m.BondDenom + } + return "" +} + +func init() { + proto.RegisterType((*MsgCreateValidator)(nil), "cosmos_sdk.x.staking.v1.MsgCreateValidator") + proto.RegisterType((*MsgEditValidator)(nil), "cosmos_sdk.x.staking.v1.MsgEditValidator") + proto.RegisterType((*MsgDelegate)(nil), "cosmos_sdk.x.staking.v1.MsgDelegate") + proto.RegisterType((*MsgBeginRedelegate)(nil), "cosmos_sdk.x.staking.v1.MsgBeginRedelegate") + proto.RegisterType((*MsgUndelegate)(nil), "cosmos_sdk.x.staking.v1.MsgUndelegate") + proto.RegisterType((*HistoricalInfo)(nil), "cosmos_sdk.x.staking.v1.HistoricalInfo") + proto.RegisterType((*CommissionRates)(nil), "cosmos_sdk.x.staking.v1.CommissionRates") + proto.RegisterType((*Commission)(nil), "cosmos_sdk.x.staking.v1.Commission") + proto.RegisterType((*Description)(nil), "cosmos_sdk.x.staking.v1.Description") + proto.RegisterType((*Validator)(nil), "cosmos_sdk.x.staking.v1.Validator") + proto.RegisterType((*DVPair)(nil), "cosmos_sdk.x.staking.v1.DVPair") + proto.RegisterType((*DVPairs)(nil), "cosmos_sdk.x.staking.v1.DVPairs") + proto.RegisterType((*DVVTriplet)(nil), "cosmos_sdk.x.staking.v1.DVVTriplet") + proto.RegisterType((*DVVTriplets)(nil), "cosmos_sdk.x.staking.v1.DVVTriplets") + proto.RegisterType((*Delegation)(nil), "cosmos_sdk.x.staking.v1.Delegation") + proto.RegisterType((*UnbondingDelegation)(nil), "cosmos_sdk.x.staking.v1.UnbondingDelegation") + proto.RegisterType((*UnbondingDelegationEntry)(nil), "cosmos_sdk.x.staking.v1.UnbondingDelegationEntry") + proto.RegisterType((*RedelegationEntry)(nil), "cosmos_sdk.x.staking.v1.RedelegationEntry") + proto.RegisterType((*Redelegation)(nil), "cosmos_sdk.x.staking.v1.Redelegation") + proto.RegisterType((*Params)(nil), "cosmos_sdk.x.staking.v1.Params") +} + +func init() { proto.RegisterFile("x/staking/types/types.proto", fileDescriptor_c669c0a3ee1b124c) } + +var fileDescriptor_c669c0a3ee1b124c = []byte{ + // 1678 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x59, 0xcd, 0x6f, 0x23, 0x49, + 0x15, 0x4f, 0xdb, 0x8e, 0x9d, 0x3c, 0x4f, 0xec, 0xa4, 0xa3, 0xc9, 0x78, 0xb2, 0xac, 0x3b, 0xf4, + 0xa2, 0x55, 0x84, 0x58, 0x5b, 0xd9, 0x45, 0x42, 0xca, 0x5e, 0x76, 0x1c, 0x27, 0x4a, 0x50, 0x82, + 0x66, 0x3b, 0xb3, 0x39, 0xf0, 0x21, 0xab, 0xdc, 0x5d, 0x69, 0x17, 0x71, 0x77, 0x9b, 0xae, 0x72, + 0xd6, 0x41, 0x5c, 0x91, 0x10, 0x12, 0x62, 0x2f, 0x48, 0x73, 0x1c, 0xf1, 0x0f, 0x70, 0x45, 0x70, + 0xe1, 0x38, 0xdc, 0x46, 0x20, 0x21, 0xc4, 0xc1, 0xa0, 0x99, 0x0b, 0xe2, 0x04, 0x3e, 0x70, 0xe0, + 0x84, 0xba, 0xaa, 0xfa, 0x23, 0x6d, 0x7b, 0xc6, 0xc9, 0x30, 0xc3, 0x48, 0x93, 0xcb, 0x8c, 0xeb, + 0xf5, 0x7b, 0xbf, 0x57, 0xf5, 0xbe, 0xab, 0x02, 0xef, 0x0c, 0xea, 0x94, 0xa1, 0x33, 0xe2, 0xda, + 0x75, 0x76, 0xd1, 0xc3, 0x54, 0xfc, 0x5b, 0xeb, 0xf9, 0x1e, 0xf3, 0xd4, 0x3b, 0xa6, 0x47, 0x1d, + 0x8f, 0xb6, 0xa8, 0x75, 0x56, 0x1b, 0xd4, 0x24, 0x5f, 0xed, 0x7c, 0x6b, 0xfd, 0x7d, 0xd6, 0x21, + 0xbe, 0xd5, 0xea, 0x21, 0x9f, 0x5d, 0xd4, 0x39, 0x6f, 0xdd, 0xf6, 0x6c, 0x2f, 0xfe, 0x25, 0x00, + 0xd6, 0x3f, 0x1a, 0xe7, 0x63, 0xd8, 0xb5, 0xb0, 0xef, 0x10, 0x97, 0xd5, 0x51, 0xdb, 0x24, 0xe3, + 0x5a, 0xd7, 0x35, 0xdb, 0xf3, 0xec, 0x2e, 0x16, 0xfc, 0xed, 0xfe, 0x69, 0x9d, 0x11, 0x07, 0x53, + 0x86, 0x9c, 0x9e, 0x64, 0xa8, 0xa6, 0x19, 0xac, 0xbe, 0x8f, 0x18, 0xf1, 0x5c, 0xf9, 0x7d, 0x65, + 0x0c, 0x53, 0xff, 0x57, 0x0e, 0xd4, 0x23, 0x6a, 0xef, 0xf8, 0x18, 0x31, 0x7c, 0x82, 0xba, 0xc4, + 0x42, 0xcc, 0xf3, 0xd5, 0x43, 0x28, 0x5a, 0x98, 0x9a, 0x3e, 0xe9, 0x05, 0xe2, 0x15, 0x65, 0x43, + 0xd9, 0x2c, 0x7e, 0xf8, 0x95, 0xda, 0x94, 0x63, 0xd7, 0x9a, 0x31, 0x6f, 0x23, 0xf7, 0x78, 0xa8, + 0xcd, 0x19, 0x49, 0x71, 0xf5, 0x5b, 0x00, 0xa6, 0xe7, 0x38, 0x84, 0xd2, 0x00, 0x2c, 0xc3, 0xc1, + 0x36, 0xa7, 0x82, 0xed, 0x44, 0xac, 0x06, 0x62, 0x98, 0x4a, 0xc0, 0x04, 0x82, 0xfa, 0x23, 0x58, + 0x75, 0x88, 0xdb, 0xa2, 0xb8, 0x7b, 0xda, 0xb2, 0x70, 0x17, 0xdb, 0xfc, 0x90, 0x95, 0xec, 0x86, + 0xb2, 0xb9, 0xd8, 0x38, 0x0c, 0xd8, 0xff, 0x32, 0xd4, 0xde, 0xb7, 0x09, 0xeb, 0xf4, 0xdb, 0x35, + 0xd3, 0x73, 0xea, 0x42, 0x95, 0xfc, 0xef, 0x03, 0x6a, 0x9d, 0x49, 0x1b, 0x1c, 0xb8, 0x6c, 0x34, + 0xd4, 0xd6, 0x2f, 0x90, 0xd3, 0xdd, 0xd6, 0x27, 0x40, 0xea, 0xc6, 0x8a, 0x43, 0xdc, 0x63, 0xdc, + 0x3d, 0x6d, 0x46, 0x34, 0xf5, 0x87, 0xb0, 0x22, 0x39, 0x3c, 0xbf, 0x85, 0x2c, 0xcb, 0xc7, 0x94, + 0x56, 0x72, 0x1b, 0xca, 0xe6, 0xad, 0xc6, 0xd1, 0x68, 0xa8, 0x55, 0x04, 0xda, 0x18, 0x8b, 0xfe, + 0x9f, 0xa1, 0xf6, 0xc1, 0x0c, 0x7b, 0xba, 0x67, 0x9a, 0xf7, 0x84, 0x84, 0xb1, 0x1c, 0x81, 0x48, + 0x4a, 0xa0, 0xfb, 0x3c, 0x74, 0x52, 0xa4, 0x7b, 0x3e, 0xad, 0x7b, 0x8c, 0x65, 0x56, 0xdd, 0x27, + 0xa8, 0x1b, 0xe9, 0x8e, 0x40, 0x42, 0xdd, 0x6b, 0x90, 0xef, 0xf5, 0xdb, 0x67, 0xf8, 0xa2, 0x92, + 0x0f, 0x0c, 0x6d, 0xc8, 0x95, 0x5a, 0x87, 0xf9, 0x73, 0xd4, 0xed, 0xe3, 0x4a, 0x81, 0x3b, 0x76, + 0x35, 0xe9, 0x58, 0xee, 0x4e, 0x12, 0x06, 0x85, 0xe0, 0xd3, 0x7f, 0x9b, 0x85, 0xe5, 0x23, 0x6a, + 0xef, 0x5a, 0x84, 0xbd, 0xaa, 0x88, 0xeb, 0x4d, 0xb2, 0x53, 0x86, 0xdb, 0x69, 0x67, 0x34, 0xd4, + 0x4a, 0xc2, 0x4e, 0xff, 0x4b, 0xeb, 0x38, 0x50, 0x8e, 0x23, 0xb4, 0xe5, 0x23, 0x86, 0x65, 0x3c, + 0x36, 0x67, 0x8c, 0xc5, 0x26, 0x36, 0x47, 0x43, 0x6d, 0x4d, 0xec, 0x2c, 0x05, 0xa5, 0x1b, 0x25, + 0xf3, 0x52, 0x56, 0xa8, 0x83, 0xc9, 0x29, 0x90, 0xe3, 0x2a, 0xf7, 0x5f, 0x61, 0xf8, 0xeb, 0xbf, + 0xce, 0x40, 0xf1, 0x88, 0xda, 0x92, 0x82, 0x27, 0xa7, 0x83, 0xf2, 0x7f, 0x4c, 0x87, 0xcc, 0xeb, + 0x49, 0x87, 0x2d, 0xc8, 0x23, 0xc7, 0xeb, 0xbb, 0x8c, 0xfb, 0xf9, 0xb9, 0x71, 0x2f, 0x19, 0xf5, + 0x3f, 0x66, 0x79, 0xb1, 0x6d, 0x60, 0x9b, 0xb8, 0x06, 0xb6, 0xde, 0x04, 0x0b, 0xfe, 0x58, 0x81, + 0xdb, 0xb1, 0x7d, 0xa8, 0x6f, 0xa6, 0xcc, 0xf8, 0xe9, 0x68, 0xa8, 0x7d, 0x29, 0x6d, 0xc6, 0x04, + 0xdb, 0x35, 0x4c, 0xb9, 0x1a, 0x01, 0x1d, 0xfb, 0xe6, 0xe4, 0x7d, 0x58, 0x94, 0x45, 0xfb, 0xc8, + 0x4e, 0xdf, 0x47, 0x82, 0xed, 0xa5, 0xf6, 0xd1, 0xa4, 0x6c, 0xdc, 0xab, 0xb9, 0x59, 0xbd, 0xfa, + 0x9b, 0x0c, 0x2c, 0x1d, 0x51, 0xfb, 0x33, 0xd7, 0xba, 0x49, 0x89, 0x2b, 0xa7, 0xc4, 0x2f, 0x14, + 0x28, 0xed, 0x13, 0xca, 0x3c, 0x9f, 0x98, 0xa8, 0x7b, 0xe0, 0x9e, 0x7a, 0xea, 0xc7, 0x90, 0xef, + 0x60, 0x64, 0x61, 0x5f, 0x36, 0x81, 0x77, 0x6b, 0xf1, 0x68, 0x54, 0x0b, 0x46, 0xa3, 0x9a, 0xd8, + 0xca, 0x3e, 0x67, 0x0a, 0xf1, 0x84, 0x88, 0xfa, 0x09, 0xe4, 0xcf, 0x51, 0x97, 0x62, 0x56, 0xc9, + 0x6c, 0x64, 0x37, 0x8b, 0x1f, 0xea, 0x53, 0x3b, 0x48, 0xd4, 0x7a, 0x42, 0x04, 0x21, 0xb7, 0x9d, + 0xfb, 0xfb, 0x23, 0x4d, 0xd1, 0x7f, 0x95, 0x81, 0x72, 0x6a, 0x10, 0x51, 0x1b, 0x90, 0xe3, 0x75, + 0x5d, 0xe1, 0x45, 0xb6, 0x76, 0x85, 0x39, 0xa3, 0x89, 0x4d, 0x83, 0xcb, 0xaa, 0xdf, 0x85, 0x05, + 0x07, 0x0d, 0x44, 0x7f, 0xc8, 0x70, 0x9c, 0x7b, 0x57, 0xc3, 0x19, 0x0d, 0xb5, 0xb2, 0x2c, 0xd8, + 0x12, 0x47, 0x37, 0x0a, 0x0e, 0x1a, 0xf0, 0xae, 0xd0, 0x83, 0x72, 0x40, 0x35, 0x3b, 0xc8, 0xb5, + 0x71, 0xb2, 0x09, 0xed, 0x5f, 0x59, 0xc9, 0x5a, 0xac, 0x24, 0x01, 0xa7, 0x1b, 0x4b, 0x0e, 0x1a, + 0xec, 0x70, 0x42, 0xa0, 0x71, 0x7b, 0xe1, 0xe1, 0x23, 0x6d, 0x8e, 0x5b, 0xec, 0x0f, 0x0a, 0x40, + 0x6c, 0x31, 0xf5, 0x7b, 0xb0, 0x9c, 0x6a, 0x62, 0x54, 0xfa, 0x73, 0xf6, 0xc9, 0x6f, 0x21, 0xd8, + 0xf5, 0x93, 0xa1, 0xa6, 0x18, 0x65, 0x33, 0xe5, 0x8b, 0xef, 0x40, 0xb1, 0xdf, 0xb3, 0x10, 0xc3, + 0xad, 0x60, 0x08, 0x96, 0x33, 0xe5, 0x7a, 0x4d, 0x0c, 0xc0, 0xb5, 0x70, 0x00, 0xae, 0x3d, 0x08, + 0x27, 0xe4, 0x46, 0x35, 0xc0, 0x1a, 0x0d, 0x35, 0x55, 0x9c, 0x2b, 0x21, 0xac, 0x7f, 0xf1, 0x57, + 0x4d, 0x31, 0x40, 0x50, 0x02, 0x81, 0xc4, 0xa1, 0x7e, 0xaf, 0x40, 0x31, 0x31, 0x6a, 0xa8, 0x15, + 0x28, 0x38, 0x9e, 0x4b, 0xce, 0x64, 0x70, 0x2e, 0x1a, 0xe1, 0x52, 0x5d, 0x87, 0x05, 0x62, 0x61, + 0x97, 0x11, 0x76, 0x21, 0x1c, 0x6b, 0x44, 0xeb, 0x40, 0xea, 0x73, 0xdc, 0xa6, 0x24, 0x74, 0x87, + 0x11, 0x2e, 0xd5, 0x3d, 0x58, 0xa6, 0xd8, 0xec, 0xfb, 0x84, 0x5d, 0xb4, 0x4c, 0xcf, 0x65, 0xc8, + 0x64, 0xb2, 0x87, 0xbf, 0x33, 0x1a, 0x6a, 0x77, 0xc4, 0x5e, 0xd3, 0x1c, 0xba, 0x51, 0x0e, 0x49, + 0x3b, 0x82, 0x12, 0x68, 0xb0, 0x30, 0x43, 0xa4, 0x2b, 0xa6, 0xc1, 0x45, 0x23, 0x5c, 0x26, 0xce, + 0xf2, 0xbb, 0x02, 0x2c, 0xc6, 0xf3, 0xd6, 0xe7, 0xb0, 0xec, 0xf5, 0xb0, 0x3f, 0xa1, 0x44, 0x1d, + 0xc6, 0x9a, 0xd3, 0x1c, 0xd7, 0xa8, 0x12, 0xe5, 0x10, 0x23, 0x2c, 0x12, 0x7b, 0x41, 0x60, 0xb8, + 0x14, 0xbb, 0xb4, 0x4f, 0x5b, 0x72, 0xa0, 0xcc, 0xa4, 0x8f, 0x9c, 0xe6, 0xd0, 0x83, 0x08, 0x90, + 0xa4, 0xfb, 0x62, 0xec, 0x5c, 0x83, 0xfc, 0xf7, 0x11, 0xe9, 0x62, 0x8b, 0xdb, 0x74, 0xc1, 0x90, + 0x2b, 0xf5, 0x00, 0xf2, 0x94, 0x21, 0xd6, 0x17, 0x33, 0xf9, 0x7c, 0x63, 0x6b, 0xc6, 0x3d, 0x37, + 0x3c, 0xd7, 0x3a, 0xe6, 0x82, 0x86, 0x04, 0x50, 0xf7, 0x20, 0xcf, 0xbc, 0x33, 0xec, 0x4a, 0xa3, + 0x5e, 0x29, 0xe5, 0x0f, 0x5c, 0x66, 0x48, 0x69, 0x95, 0x41, 0x5c, 0xa7, 0x5b, 0xb4, 0x83, 0x7c, + 0x4c, 0xc5, 0x0c, 0xdd, 0x38, 0xb8, 0x72, 0x5e, 0xde, 0x49, 0x37, 0x0f, 0x81, 0xa7, 0x1b, 0xe5, + 0x88, 0x74, 0xcc, 0x29, 0xe9, 0x89, 0xba, 0xf0, 0x72, 0x13, 0xf5, 0x1e, 0x2c, 0xf7, 0xdd, 0xb6, + 0xe7, 0x5a, 0xc4, 0xb5, 0x5b, 0x1d, 0x4c, 0xec, 0x0e, 0xab, 0x2c, 0x6c, 0x28, 0x9b, 0xd9, 0xa4, + 0xdb, 0xd2, 0x1c, 0xba, 0x51, 0x8e, 0x48, 0xfb, 0x9c, 0xa2, 0x5a, 0x50, 0x8a, 0xb9, 0x78, 0xee, + 0x2e, 0xbe, 0x30, 0x77, 0xbf, 0x2c, 0x73, 0xf7, 0x76, 0x5a, 0x4b, 0x9c, 0xbe, 0x4b, 0x11, 0x31, + 0x10, 0x53, 0x0f, 0x2e, 0xdd, 0x38, 0x81, 0x6b, 0x78, 0x6f, 0x86, 0xba, 0x33, 0xfb, 0x65, 0xb3, + 0xf8, 0x5a, 0x2e, 0x9b, 0xdb, 0xb7, 0x7e, 0xf2, 0x48, 0x9b, 0x8b, 0x52, 0xf8, 0xa7, 0x19, 0xc8, + 0x37, 0x4f, 0xee, 0x23, 0xe2, 0xbf, 0xad, 0x33, 0x46, 0xa2, 0x9e, 0xed, 0x41, 0x41, 0xd8, 0x82, + 0xaa, 0x1f, 0xc3, 0x7c, 0x2f, 0xf8, 0x51, 0x51, 0x78, 0xd3, 0xd7, 0xa6, 0x07, 0x39, 0x17, 0x08, + 0xaf, 0xa3, 0x5c, 0x46, 0xff, 0x65, 0x16, 0xa0, 0x79, 0x72, 0xf2, 0xc0, 0x27, 0xbd, 0x2e, 0x66, + 0x37, 0xd3, 0xf8, 0x9b, 0x33, 0x8d, 0x27, 0x9c, 0xfd, 0x00, 0x8a, 0xb1, 0x8f, 0xa8, 0xba, 0x0b, + 0x0b, 0x4c, 0xfe, 0x96, 0x3e, 0x7f, 0xef, 0x39, 0x3e, 0x0f, 0xe5, 0xa4, 0xdf, 0x23, 0x51, 0xfd, + 0x4f, 0x19, 0x80, 0x17, 0xbd, 0xec, 0xbc, 0x05, 0x73, 0xfb, 0x1e, 0xe4, 0x65, 0x57, 0xca, 0x5e, + 0x6b, 0xb4, 0x95, 0xd2, 0x09, 0x77, 0xfd, 0x23, 0x03, 0xab, 0x9f, 0x85, 0x15, 0xf9, 0xc6, 0xc2, + 0xea, 0xa7, 0x50, 0xc0, 0x2e, 0xf3, 0x09, 0x37, 0x71, 0x10, 0xae, 0x5b, 0x53, 0xc3, 0x75, 0x82, + 0xd9, 0x76, 0x5d, 0xe6, 0x5f, 0xc8, 0xe0, 0x0d, 0x71, 0x12, 0xc6, 0xfe, 0x79, 0x16, 0x2a, 0xd3, + 0xa4, 0xd4, 0x1d, 0x28, 0x9b, 0x3e, 0xe6, 0x84, 0xb0, 0x6d, 0x2b, 0xbc, 0x6d, 0xaf, 0x27, 0x5e, + 0x9b, 0x2e, 0x33, 0xe8, 0x46, 0x29, 0xa4, 0xc8, 0xa6, 0x6d, 0xf3, 0xc7, 0xad, 0x20, 0x67, 0x02, + 0xae, 0x19, 0x27, 0x6e, 0x5d, 0x76, 0xed, 0xf8, 0x49, 0x2b, 0x09, 0x20, 0xda, 0x76, 0x29, 0xa6, + 0xf2, 0xbe, 0xfd, 0x03, 0x28, 0x13, 0x97, 0x30, 0x82, 0xba, 0xad, 0x36, 0xea, 0x22, 0xd7, 0xbc, + 0xce, 0x05, 0x46, 0x34, 0x5a, 0xa9, 0x36, 0x05, 0xa7, 0x1b, 0x25, 0x49, 0x69, 0x08, 0x82, 0xba, + 0x0f, 0x85, 0x50, 0x55, 0xee, 0x5a, 0x53, 0x5e, 0x28, 0x9e, 0xf0, 0xc8, 0xcf, 0xb2, 0xb0, 0x12, + 0x3d, 0xf0, 0xdc, 0xb8, 0x62, 0x56, 0x57, 0x1c, 0x01, 0x88, 0x4a, 0x12, 0xf4, 0x92, 0x6b, 0x78, + 0x23, 0xa8, 0x45, 0x8b, 0x02, 0xa1, 0x49, 0x59, 0xc2, 0x1f, 0xff, 0xcc, 0xc2, 0xad, 0xa4, 0x3f, + 0x6e, 0x9a, 0xfc, 0x1b, 0xf4, 0xe4, 0xf6, 0xcd, 0xb8, 0x36, 0xe6, 0x78, 0x6d, 0xfc, 0xea, 0xd4, + 0xda, 0x38, 0x96, 0x53, 0xd3, 0x8b, 0xe2, 0xbf, 0x33, 0x90, 0xbf, 0x8f, 0x7c, 0xe4, 0x50, 0xd5, + 0x1c, 0xbb, 0x72, 0x88, 0x87, 0x88, 0xbb, 0x63, 0x19, 0xd3, 0x94, 0x7f, 0x2f, 0x7b, 0xc1, 0x8d, + 0xe3, 0xe1, 0x84, 0x1b, 0xc7, 0x27, 0x50, 0x72, 0xd0, 0xa0, 0x15, 0x1d, 0x50, 0x78, 0x73, 0xa9, + 0x71, 0x37, 0x46, 0xb9, 0xfc, 0x5d, 0x3c, 0xa5, 0x44, 0x17, 0x72, 0xaa, 0x7e, 0x03, 0x8a, 0x01, + 0x47, 0xdc, 0x27, 0x02, 0xf1, 0xb5, 0xf8, 0xc9, 0x22, 0xf1, 0x51, 0x37, 0xc0, 0x41, 0x83, 0x5d, + 0xb1, 0x50, 0x0f, 0x41, 0xed, 0x44, 0x4f, 0x68, 0xad, 0xd8, 0x96, 0x81, 0xfc, 0xbb, 0xa3, 0xa1, + 0x76, 0x57, 0xc8, 0x8f, 0xf3, 0xe8, 0xc6, 0x4a, 0x4c, 0x0c, 0xd1, 0xbe, 0x0e, 0x10, 0x9c, 0xab, + 0x65, 0x61, 0xd7, 0x73, 0xe4, 0xc5, 0xf7, 0xf6, 0x68, 0xa8, 0xad, 0x08, 0x94, 0xf8, 0x9b, 0x6e, + 0x2c, 0x06, 0x8b, 0x66, 0xf0, 0x3b, 0x36, 0x7c, 0x63, 0xef, 0xf1, 0xd3, 0xaa, 0xf2, 0xe4, 0x69, + 0x55, 0xf9, 0xdb, 0xd3, 0xaa, 0xf2, 0xc5, 0xb3, 0xea, 0xdc, 0x93, 0x67, 0xd5, 0xb9, 0x3f, 0x3f, + 0xab, 0xce, 0x7d, 0xfb, 0x6b, 0xcf, 0x0d, 0x96, 0xd4, 0xdf, 0x5b, 0xdb, 0x79, 0xee, 0x95, 0x8f, + 0xfe, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x62, 0xe9, 0xa4, 0xfa, 0x89, 0x1d, 0x00, 0x00, +} + +func (this *HistoricalInfo) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*HistoricalInfo) + if !ok { + that2, ok := that.(HistoricalInfo) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !this.Header.Equal(&that1.Header) { + return false + } + if len(this.Valset) != len(that1.Valset) { + return false + } + for i := range this.Valset { + if !this.Valset[i].Equal(&that1.Valset[i]) { + return false + } + } + return true +} +func (this *CommissionRates) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*CommissionRates) + if !ok { + that2, ok := that.(CommissionRates) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !this.Rate.Equal(that1.Rate) { + return false + } + if !this.MaxRate.Equal(that1.MaxRate) { + return false + } + if !this.MaxChangeRate.Equal(that1.MaxChangeRate) { + return false + } + return true +} +func (this *Commission) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*Commission) + if !ok { + that2, ok := that.(Commission) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !this.CommissionRates.Equal(&that1.CommissionRates) { + return false + } + if !this.UpdateTime.Equal(that1.UpdateTime) { + return false + } + return true +} +func (this *Description) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*Description) + if !ok { + that2, ok := that.(Description) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Moniker != that1.Moniker { + return false + } + if this.Identity != that1.Identity { + return false + } + if this.Website != that1.Website { + return false + } + if this.SecurityContact != that1.SecurityContact { + return false + } + if this.Details != that1.Details { + return false + } + return true +} +func (this *Validator) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*Validator) + if !ok { + that2, ok := that.(Validator) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !bytes.Equal(this.OperatorAddress, that1.OperatorAddress) { + return false + } + if this.ConsensusPubkey != that1.ConsensusPubkey { + return false + } + if this.Jailed != that1.Jailed { + return false + } + if this.Status != that1.Status { + return false + } + if !this.Tokens.Equal(that1.Tokens) { + return false + } + if !this.DelegatorShares.Equal(that1.DelegatorShares) { + return false + } + if !this.Description.Equal(&that1.Description) { + return false + } + if this.UnbondingHeight != that1.UnbondingHeight { + return false + } + if !this.UnbondingTime.Equal(that1.UnbondingTime) { + return false + } + if !this.Commission.Equal(&that1.Commission) { + return false + } + if !this.MinSelfDelegation.Equal(that1.MinSelfDelegation) { + return false + } + return true +} +func (this *DVPair) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*DVPair) + if !ok { + that2, ok := that.(DVPair) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !bytes.Equal(this.DelegatorAddress, that1.DelegatorAddress) { + return false + } + if !bytes.Equal(this.ValidatorAddress, that1.ValidatorAddress) { + return false + } + return true +} +func (this *DVVTriplet) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*DVVTriplet) + if !ok { + that2, ok := that.(DVVTriplet) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !bytes.Equal(this.DelegatorAddress, that1.DelegatorAddress) { + return false + } + if !bytes.Equal(this.ValidatorSrcAddress, that1.ValidatorSrcAddress) { + return false + } + if !bytes.Equal(this.ValidatorDstAddress, that1.ValidatorDstAddress) { + return false + } + return true +} +func (this *Delegation) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*Delegation) + if !ok { + that2, ok := that.(Delegation) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !bytes.Equal(this.DelegatorAddress, that1.DelegatorAddress) { + return false + } + if !bytes.Equal(this.ValidatorAddress, that1.ValidatorAddress) { + return false + } + if !this.Shares.Equal(that1.Shares) { + return false + } + return true +} +func (this *UnbondingDelegation) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*UnbondingDelegation) + if !ok { + that2, ok := that.(UnbondingDelegation) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !bytes.Equal(this.DelegatorAddress, that1.DelegatorAddress) { + return false + } + if !bytes.Equal(this.ValidatorAddress, that1.ValidatorAddress) { + return false + } + if len(this.Entries) != len(that1.Entries) { + return false + } + for i := range this.Entries { + if !this.Entries[i].Equal(&that1.Entries[i]) { + return false + } + } + return true +} +func (this *UnbondingDelegationEntry) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*UnbondingDelegationEntry) + if !ok { + that2, ok := that.(UnbondingDelegationEntry) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.CreationHeight != that1.CreationHeight { + return false + } + if !this.CompletionTime.Equal(that1.CompletionTime) { + return false + } + if !this.InitialBalance.Equal(that1.InitialBalance) { + return false + } + if !this.Balance.Equal(that1.Balance) { + return false + } + return true +} +func (this *RedelegationEntry) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*RedelegationEntry) + if !ok { + that2, ok := that.(RedelegationEntry) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.CreationHeight != that1.CreationHeight { + return false + } + if !this.CompletionTime.Equal(that1.CompletionTime) { + return false + } + if !this.InitialBalance.Equal(that1.InitialBalance) { + return false + } + if !this.SharesDst.Equal(that1.SharesDst) { + return false + } + return true +} +func (this *Redelegation) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*Redelegation) + if !ok { + that2, ok := that.(Redelegation) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !bytes.Equal(this.DelegatorAddress, that1.DelegatorAddress) { + return false + } + if !bytes.Equal(this.ValidatorSrcAddress, that1.ValidatorSrcAddress) { + return false + } + if !bytes.Equal(this.ValidatorDstAddress, that1.ValidatorDstAddress) { + return false + } + if len(this.Entries) != len(that1.Entries) { + return false + } + for i := range this.Entries { + if !this.Entries[i].Equal(&that1.Entries[i]) { + return false + } + } + return true +} +func (this *Params) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*Params) + if !ok { + that2, ok := that.(Params) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.UnbondingTime != that1.UnbondingTime { + return false + } + if this.MaxValidators != that1.MaxValidators { + return false + } + if this.MaxEntries != that1.MaxEntries { + return false + } + if this.HistoricalEntries != that1.HistoricalEntries { + return false + } + if this.BondDenom != that1.BondDenom { + return false + } + return true +} +func (m *MsgCreateValidator) 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 *MsgCreateValidator) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgCreateValidator) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Value.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a + if len(m.Pubkey) > 0 { + i -= len(m.Pubkey) + copy(dAtA[i:], m.Pubkey) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Pubkey))) + i-- + dAtA[i] = 0x32 + } + if len(m.ValidatorAddress) > 0 { + i -= len(m.ValidatorAddress) + copy(dAtA[i:], m.ValidatorAddress) + i = encodeVarintTypes(dAtA, i, uint64(len(m.ValidatorAddress))) + i-- + dAtA[i] = 0x2a + } + if len(m.DelegatorAddress) > 0 { + i -= len(m.DelegatorAddress) + copy(dAtA[i:], m.DelegatorAddress) + i = encodeVarintTypes(dAtA, i, uint64(len(m.DelegatorAddress))) + i-- + dAtA[i] = 0x22 + } + { + size := m.MinSelfDelegation.Size() + i -= size + if _, err := m.MinSelfDelegation.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + { + size, err := m.Commission.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + { + size, err := m.Description.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *MsgEditValidator) 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 *MsgEditValidator) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgEditValidator) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.MinSelfDelegation != nil { + { + size := m.MinSelfDelegation.Size() + i -= size + if _, err := m.MinSelfDelegation.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + if m.CommissionRate != nil { + { + size := m.CommissionRate.Size() + i -= size + if _, err := m.CommissionRate.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + if len(m.ValidatorAddress) > 0 { + i -= len(m.ValidatorAddress) + copy(dAtA[i:], m.ValidatorAddress) + i = encodeVarintTypes(dAtA, i, uint64(len(m.ValidatorAddress))) + i-- + dAtA[i] = 0x12 + } + { + size, err := m.Description.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *MsgDelegate) 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 *MsgDelegate) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgDelegate) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Amount.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + if len(m.ValidatorAddress) > 0 { + i -= len(m.ValidatorAddress) + copy(dAtA[i:], m.ValidatorAddress) + i = encodeVarintTypes(dAtA, i, uint64(len(m.ValidatorAddress))) + i-- + dAtA[i] = 0x12 + } + if len(m.DelegatorAddress) > 0 { + i -= len(m.DelegatorAddress) + copy(dAtA[i:], m.DelegatorAddress) + i = encodeVarintTypes(dAtA, i, uint64(len(m.DelegatorAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgBeginRedelegate) 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 *MsgBeginRedelegate) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgBeginRedelegate) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Amount.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + if len(m.ValidatorDstAddress) > 0 { + i -= len(m.ValidatorDstAddress) + copy(dAtA[i:], m.ValidatorDstAddress) + i = encodeVarintTypes(dAtA, i, uint64(len(m.ValidatorDstAddress))) + i-- + dAtA[i] = 0x1a + } + if len(m.ValidatorSrcAddress) > 0 { + i -= len(m.ValidatorSrcAddress) + copy(dAtA[i:], m.ValidatorSrcAddress) + i = encodeVarintTypes(dAtA, i, uint64(len(m.ValidatorSrcAddress))) + i-- + dAtA[i] = 0x12 + } + if len(m.DelegatorAddress) > 0 { + i -= len(m.DelegatorAddress) + copy(dAtA[i:], m.DelegatorAddress) + i = encodeVarintTypes(dAtA, i, uint64(len(m.DelegatorAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgUndelegate) 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 *MsgUndelegate) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUndelegate) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Amount.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + if len(m.ValidatorAddress) > 0 { + i -= len(m.ValidatorAddress) + copy(dAtA[i:], m.ValidatorAddress) + i = encodeVarintTypes(dAtA, i, uint64(len(m.ValidatorAddress))) + i-- + dAtA[i] = 0x12 + } + if len(m.DelegatorAddress) > 0 { + i -= len(m.DelegatorAddress) + copy(dAtA[i:], m.DelegatorAddress) + i = encodeVarintTypes(dAtA, i, uint64(len(m.DelegatorAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *HistoricalInfo) 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 *HistoricalInfo) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *HistoricalInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Valset) > 0 { + for iNdEx := len(m.Valset) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Valset[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + { + size, err := m.Header.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *CommissionRates) 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 *CommissionRates) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CommissionRates) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size := m.MaxChangeRate.Size() + i -= size + if _, err := m.MaxChangeRate.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + { + size := m.MaxRate.Size() + i -= size + if _, err := m.MaxRate.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + { + size := m.Rate.Size() + i -= size + if _, err := m.Rate.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *Commission) 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 *Commission) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Commission) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + n9, err9 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.UpdateTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdateTime):]) + if err9 != nil { + return 0, err9 + } + i -= n9 + i = encodeVarintTypes(dAtA, i, uint64(n9)) + i-- + dAtA[i] = 0x12 + { + size, err := m.CommissionRates.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *Description) 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 *Description) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Description) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Details) > 0 { + i -= len(m.Details) + copy(dAtA[i:], m.Details) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Details))) + i-- + dAtA[i] = 0x2a + } + if len(m.SecurityContact) > 0 { + i -= len(m.SecurityContact) + copy(dAtA[i:], m.SecurityContact) + i = encodeVarintTypes(dAtA, i, uint64(len(m.SecurityContact))) + i-- + dAtA[i] = 0x22 + } + if len(m.Website) > 0 { + i -= len(m.Website) + copy(dAtA[i:], m.Website) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Website))) + i-- + dAtA[i] = 0x1a + } + if len(m.Identity) > 0 { + i -= len(m.Identity) + copy(dAtA[i:], m.Identity) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Identity))) + i-- + dAtA[i] = 0x12 + } + if len(m.Moniker) > 0 { + i -= len(m.Moniker) + copy(dAtA[i:], m.Moniker) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Moniker))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *Validator) 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 *Validator) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Validator) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size := m.MinSelfDelegation.Size() + i -= size + if _, err := m.MinSelfDelegation.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x5a + { + size, err := m.Commission.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x52 + n12, err12 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.UnbondingTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.UnbondingTime):]) + if err12 != nil { + return 0, err12 + } + i -= n12 + i = encodeVarintTypes(dAtA, i, uint64(n12)) + i-- + dAtA[i] = 0x4a + if m.UnbondingHeight != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.UnbondingHeight)) + i-- + dAtA[i] = 0x40 + } + { + size, err := m.Description.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a + { + size := m.DelegatorShares.Size() + i -= size + if _, err := m.DelegatorShares.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + { + size := m.Tokens.Size() + i -= size + if _, err := m.Tokens.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + if m.Status != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.Status)) + i-- + dAtA[i] = 0x20 + } + if m.Jailed { + i-- + if m.Jailed { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x18 + } + if len(m.ConsensusPubkey) > 0 { + i -= len(m.ConsensusPubkey) + copy(dAtA[i:], m.ConsensusPubkey) + i = encodeVarintTypes(dAtA, i, uint64(len(m.ConsensusPubkey))) + i-- + dAtA[i] = 0x12 + } + if len(m.OperatorAddress) > 0 { + i -= len(m.OperatorAddress) + copy(dAtA[i:], m.OperatorAddress) + i = encodeVarintTypes(dAtA, i, uint64(len(m.OperatorAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *DVPair) 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 *DVPair) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DVPair) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ValidatorAddress) > 0 { + i -= len(m.ValidatorAddress) + copy(dAtA[i:], m.ValidatorAddress) + i = encodeVarintTypes(dAtA, i, uint64(len(m.ValidatorAddress))) + i-- + dAtA[i] = 0x12 + } + if len(m.DelegatorAddress) > 0 { + i -= len(m.DelegatorAddress) + copy(dAtA[i:], m.DelegatorAddress) + i = encodeVarintTypes(dAtA, i, uint64(len(m.DelegatorAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *DVPairs) 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 *DVPairs) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DVPairs) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Pairs) > 0 { + for iNdEx := len(m.Pairs) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Pairs[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *DVVTriplet) 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 *DVVTriplet) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DVVTriplet) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ValidatorDstAddress) > 0 { + i -= len(m.ValidatorDstAddress) + copy(dAtA[i:], m.ValidatorDstAddress) + i = encodeVarintTypes(dAtA, i, uint64(len(m.ValidatorDstAddress))) + i-- + dAtA[i] = 0x1a + } + if len(m.ValidatorSrcAddress) > 0 { + i -= len(m.ValidatorSrcAddress) + copy(dAtA[i:], m.ValidatorSrcAddress) + i = encodeVarintTypes(dAtA, i, uint64(len(m.ValidatorSrcAddress))) + i-- + dAtA[i] = 0x12 + } + if len(m.DelegatorAddress) > 0 { + i -= len(m.DelegatorAddress) + copy(dAtA[i:], m.DelegatorAddress) + i = encodeVarintTypes(dAtA, i, uint64(len(m.DelegatorAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *DVVTriplets) 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 *DVVTriplets) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DVVTriplets) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Triplets) > 0 { + for iNdEx := len(m.Triplets) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Triplets[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *Delegation) 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 *Delegation) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Delegation) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size := m.Shares.Size() + i -= size + if _, err := m.Shares.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + if len(m.ValidatorAddress) > 0 { + i -= len(m.ValidatorAddress) + copy(dAtA[i:], m.ValidatorAddress) + i = encodeVarintTypes(dAtA, i, uint64(len(m.ValidatorAddress))) + i-- + dAtA[i] = 0x12 + } + if len(m.DelegatorAddress) > 0 { + i -= len(m.DelegatorAddress) + copy(dAtA[i:], m.DelegatorAddress) + i = encodeVarintTypes(dAtA, i, uint64(len(m.DelegatorAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *UnbondingDelegation) 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 *UnbondingDelegation) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *UnbondingDelegation) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Entries) > 0 { + for iNdEx := len(m.Entries) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Entries[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.ValidatorAddress) > 0 { + i -= len(m.ValidatorAddress) + copy(dAtA[i:], m.ValidatorAddress) + i = encodeVarintTypes(dAtA, i, uint64(len(m.ValidatorAddress))) + i-- + dAtA[i] = 0x12 + } + if len(m.DelegatorAddress) > 0 { + i -= len(m.DelegatorAddress) + copy(dAtA[i:], m.DelegatorAddress) + i = encodeVarintTypes(dAtA, i, uint64(len(m.DelegatorAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *UnbondingDelegationEntry) 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 *UnbondingDelegationEntry) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *UnbondingDelegationEntry) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size := m.Balance.Size() + i -= size + if _, err := m.Balance.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + { + size := m.InitialBalance.Size() + i -= size + if _, err := m.InitialBalance.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + n14, err14 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.CompletionTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.CompletionTime):]) + if err14 != nil { + return 0, err14 + } + i -= n14 + i = encodeVarintTypes(dAtA, i, uint64(n14)) + i-- + dAtA[i] = 0x12 + if m.CreationHeight != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.CreationHeight)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *RedelegationEntry) 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 *RedelegationEntry) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RedelegationEntry) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size := m.SharesDst.Size() + i -= size + if _, err := m.SharesDst.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + { + size := m.InitialBalance.Size() + i -= size + if _, err := m.InitialBalance.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + n15, err15 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.CompletionTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.CompletionTime):]) + if err15 != nil { + return 0, err15 + } + i -= n15 + i = encodeVarintTypes(dAtA, i, uint64(n15)) + i-- + dAtA[i] = 0x12 + if m.CreationHeight != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.CreationHeight)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *Redelegation) 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 *Redelegation) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Redelegation) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Entries) > 0 { + for iNdEx := len(m.Entries) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Entries[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + } + if len(m.ValidatorDstAddress) > 0 { + i -= len(m.ValidatorDstAddress) + copy(dAtA[i:], m.ValidatorDstAddress) + i = encodeVarintTypes(dAtA, i, uint64(len(m.ValidatorDstAddress))) + i-- + dAtA[i] = 0x1a + } + if len(m.ValidatorSrcAddress) > 0 { + i -= len(m.ValidatorSrcAddress) + copy(dAtA[i:], m.ValidatorSrcAddress) + i = encodeVarintTypes(dAtA, i, uint64(len(m.ValidatorSrcAddress))) + i-- + dAtA[i] = 0x12 + } + if len(m.DelegatorAddress) > 0 { + i -= len(m.DelegatorAddress) + copy(dAtA[i:], m.DelegatorAddress) + i = encodeVarintTypes(dAtA, i, uint64(len(m.DelegatorAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *Params) 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 *Params) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.BondDenom) > 0 { + i -= len(m.BondDenom) + copy(dAtA[i:], m.BondDenom) + i = encodeVarintTypes(dAtA, i, uint64(len(m.BondDenom))) + i-- + dAtA[i] = 0x2a + } + if m.HistoricalEntries != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.HistoricalEntries)) + i-- + dAtA[i] = 0x20 + } + if m.MaxEntries != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.MaxEntries)) + i-- + dAtA[i] = 0x18 + } + if m.MaxValidators != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.MaxValidators)) + i-- + dAtA[i] = 0x10 + } + n16, err16 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.UnbondingTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.UnbondingTime):]) + if err16 != nil { + return 0, err16 + } + i -= n16 + i = encodeVarintTypes(dAtA, i, uint64(n16)) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func encodeVarintTypes(dAtA []byte, offset int, v uint64) int { + offset -= sovTypes(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgCreateValidator) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Description.Size() + n += 1 + l + sovTypes(uint64(l)) + l = m.Commission.Size() + n += 1 + l + sovTypes(uint64(l)) + l = m.MinSelfDelegation.Size() + n += 1 + l + sovTypes(uint64(l)) + l = len(m.DelegatorAddress) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.ValidatorAddress) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.Pubkey) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = m.Value.Size() + n += 1 + l + sovTypes(uint64(l)) + return n +} + +func (m *MsgEditValidator) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Description.Size() + n += 1 + l + sovTypes(uint64(l)) + l = len(m.ValidatorAddress) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + if m.CommissionRate != nil { + l = m.CommissionRate.Size() + n += 1 + l + sovTypes(uint64(l)) + } + if m.MinSelfDelegation != nil { + l = m.MinSelfDelegation.Size() + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + +func (m *MsgDelegate) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.DelegatorAddress) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.ValidatorAddress) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = m.Amount.Size() + n += 1 + l + sovTypes(uint64(l)) + return n +} + +func (m *MsgBeginRedelegate) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.DelegatorAddress) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.ValidatorSrcAddress) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.ValidatorDstAddress) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = m.Amount.Size() + n += 1 + l + sovTypes(uint64(l)) + return n +} + +func (m *MsgUndelegate) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.DelegatorAddress) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.ValidatorAddress) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = m.Amount.Size() + n += 1 + l + sovTypes(uint64(l)) + return n +} + +func (m *HistoricalInfo) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Header.Size() + n += 1 + l + sovTypes(uint64(l)) + if len(m.Valset) > 0 { + for _, e := range m.Valset { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + return n +} + +func (m *CommissionRates) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Rate.Size() + n += 1 + l + sovTypes(uint64(l)) + l = m.MaxRate.Size() + n += 1 + l + sovTypes(uint64(l)) + l = m.MaxChangeRate.Size() + n += 1 + l + sovTypes(uint64(l)) + return n +} + +func (m *Commission) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.CommissionRates.Size() + n += 1 + l + sovTypes(uint64(l)) + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdateTime) + n += 1 + l + sovTypes(uint64(l)) + return n +} + +func (m *Description) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Moniker) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.Identity) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.Website) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.SecurityContact) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.Details) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + +func (m *Validator) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.OperatorAddress) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.ConsensusPubkey) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + if m.Jailed { + n += 2 + } + if m.Status != 0 { + n += 1 + sovTypes(uint64(m.Status)) + } + l = m.Tokens.Size() + n += 1 + l + sovTypes(uint64(l)) + l = m.DelegatorShares.Size() + n += 1 + l + sovTypes(uint64(l)) + l = m.Description.Size() + n += 1 + l + sovTypes(uint64(l)) + if m.UnbondingHeight != 0 { + n += 1 + sovTypes(uint64(m.UnbondingHeight)) + } + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.UnbondingTime) + n += 1 + l + sovTypes(uint64(l)) + l = m.Commission.Size() + n += 1 + l + sovTypes(uint64(l)) + l = m.MinSelfDelegation.Size() + n += 1 + l + sovTypes(uint64(l)) + return n +} + +func (m *DVPair) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.DelegatorAddress) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.ValidatorAddress) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + +func (m *DVPairs) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Pairs) > 0 { + for _, e := range m.Pairs { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + return n +} + +func (m *DVVTriplet) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.DelegatorAddress) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.ValidatorSrcAddress) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.ValidatorDstAddress) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + +func (m *DVVTriplets) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Triplets) > 0 { + for _, e := range m.Triplets { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + return n +} + +func (m *Delegation) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.DelegatorAddress) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.ValidatorAddress) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = m.Shares.Size() + n += 1 + l + sovTypes(uint64(l)) + return n +} + +func (m *UnbondingDelegation) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.DelegatorAddress) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.ValidatorAddress) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + if len(m.Entries) > 0 { + for _, e := range m.Entries { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + return n +} + +func (m *UnbondingDelegationEntry) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.CreationHeight != 0 { + n += 1 + sovTypes(uint64(m.CreationHeight)) + } + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.CompletionTime) + n += 1 + l + sovTypes(uint64(l)) + l = m.InitialBalance.Size() + n += 1 + l + sovTypes(uint64(l)) + l = m.Balance.Size() + n += 1 + l + sovTypes(uint64(l)) + return n +} + +func (m *RedelegationEntry) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.CreationHeight != 0 { + n += 1 + sovTypes(uint64(m.CreationHeight)) + } + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.CompletionTime) + n += 1 + l + sovTypes(uint64(l)) + l = m.InitialBalance.Size() + n += 1 + l + sovTypes(uint64(l)) + l = m.SharesDst.Size() + n += 1 + l + sovTypes(uint64(l)) + return n +} + +func (m *Redelegation) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.DelegatorAddress) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.ValidatorSrcAddress) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.ValidatorDstAddress) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + if len(m.Entries) > 0 { + for _, e := range m.Entries { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + return n +} + +func (m *Params) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = github_com_gogo_protobuf_types.SizeOfStdDuration(m.UnbondingTime) + n += 1 + l + sovTypes(uint64(l)) + if m.MaxValidators != 0 { + n += 1 + sovTypes(uint64(m.MaxValidators)) + } + if m.MaxEntries != 0 { + n += 1 + sovTypes(uint64(m.MaxEntries)) + } + if m.HistoricalEntries != 0 { + n += 1 + sovTypes(uint64(m.HistoricalEntries)) + } + l = len(m.BondDenom) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + +func sovTypes(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTypes(x uint64) (n int) { + return sovTypes(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *MsgCreateValidator) 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 ErrIntOverflowTypes + } + 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: MsgCreateValidator: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgCreateValidator: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Description.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Commission", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Commission.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MinSelfDelegation", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.MinSelfDelegation.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DelegatorAddress", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DelegatorAddress = append(m.DelegatorAddress[:0], dAtA[iNdEx:postIndex]...) + if m.DelegatorAddress == nil { + m.DelegatorAddress = []byte{} + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ValidatorAddress", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ValidatorAddress = append(m.ValidatorAddress[:0], dAtA[iNdEx:postIndex]...) + if m.ValidatorAddress == nil { + m.ValidatorAddress = []byte{} + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pubkey", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Pubkey = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Value.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgEditValidator) 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 ErrIntOverflowTypes + } + 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: MsgEditValidator: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgEditValidator: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Description.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ValidatorAddress", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ValidatorAddress = append(m.ValidatorAddress[:0], dAtA[iNdEx:postIndex]...) + if m.ValidatorAddress == nil { + m.ValidatorAddress = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CommissionRate", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v github_com_cosmos_cosmos_sdk_types.Dec + m.CommissionRate = &v + if err := m.CommissionRate.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MinSelfDelegation", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v github_com_cosmos_cosmos_sdk_types.Int + m.MinSelfDelegation = &v + if err := m.MinSelfDelegation.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgDelegate) 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 ErrIntOverflowTypes + } + 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: MsgDelegate: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgDelegate: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DelegatorAddress", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DelegatorAddress = append(m.DelegatorAddress[:0], dAtA[iNdEx:postIndex]...) + if m.DelegatorAddress == nil { + m.DelegatorAddress = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ValidatorAddress", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ValidatorAddress = append(m.ValidatorAddress[:0], dAtA[iNdEx:postIndex]...) + if m.ValidatorAddress == nil { + m.ValidatorAddress = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgBeginRedelegate) 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 ErrIntOverflowTypes + } + 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: MsgBeginRedelegate: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgBeginRedelegate: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DelegatorAddress", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DelegatorAddress = append(m.DelegatorAddress[:0], dAtA[iNdEx:postIndex]...) + if m.DelegatorAddress == nil { + m.DelegatorAddress = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ValidatorSrcAddress", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ValidatorSrcAddress = append(m.ValidatorSrcAddress[:0], dAtA[iNdEx:postIndex]...) + if m.ValidatorSrcAddress == nil { + m.ValidatorSrcAddress = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ValidatorDstAddress", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ValidatorDstAddress = append(m.ValidatorDstAddress[:0], dAtA[iNdEx:postIndex]...) + if m.ValidatorDstAddress == nil { + m.ValidatorDstAddress = []byte{} + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgUndelegate) 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 ErrIntOverflowTypes + } + 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: MsgUndelegate: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUndelegate: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DelegatorAddress", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DelegatorAddress = append(m.DelegatorAddress[:0], dAtA[iNdEx:postIndex]...) + if m.DelegatorAddress == nil { + m.DelegatorAddress = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ValidatorAddress", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ValidatorAddress = append(m.ValidatorAddress[:0], dAtA[iNdEx:postIndex]...) + if m.ValidatorAddress == nil { + m.ValidatorAddress = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *HistoricalInfo) 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 ErrIntOverflowTypes + } + 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: HistoricalInfo: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: HistoricalInfo: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Header", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Header.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Valset", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Valset = append(m.Valset, Validator{}) + if err := m.Valset[len(m.Valset)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *CommissionRates) 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 ErrIntOverflowTypes + } + 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: CommissionRates: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CommissionRates: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Rate", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Rate.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxRate", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.MaxRate.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxChangeRate", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.MaxChangeRate.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Commission) 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 ErrIntOverflowTypes + } + 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: Commission: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Commission: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CommissionRates", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.CommissionRates.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UpdateTime", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.UpdateTime, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Description) 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 ErrIntOverflowTypes + } + 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: Description: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Description: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Moniker", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Moniker = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Identity", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Identity = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Website", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Website = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SecurityContact", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SecurityContact = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Details", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Details = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Validator) 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 ErrIntOverflowTypes + } + 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: Validator: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Validator: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field OperatorAddress", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.OperatorAddress = append(m.OperatorAddress[:0], dAtA[iNdEx:postIndex]...) + if m.OperatorAddress == nil { + m.OperatorAddress = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConsensusPubkey", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ConsensusPubkey = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Jailed", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Jailed = bool(v != 0) + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType) + } + m.Status = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Status |= github_com_cosmos_cosmos_sdk_types.BondStatus(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Tokens", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Tokens.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DelegatorShares", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.DelegatorShares.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Description.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field UnbondingHeight", wireType) + } + m.UnbondingHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.UnbondingHeight |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UnbondingTime", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.UnbondingTime, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Commission", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Commission.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MinSelfDelegation", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.MinSelfDelegation.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *DVPair) 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 ErrIntOverflowTypes + } + 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: DVPair: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DVPair: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DelegatorAddress", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DelegatorAddress = append(m.DelegatorAddress[:0], dAtA[iNdEx:postIndex]...) + if m.DelegatorAddress == nil { + m.DelegatorAddress = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ValidatorAddress", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ValidatorAddress = append(m.ValidatorAddress[:0], dAtA[iNdEx:postIndex]...) + if m.ValidatorAddress == nil { + m.ValidatorAddress = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *DVPairs) 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 ErrIntOverflowTypes + } + 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: DVPairs: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DVPairs: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pairs", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Pairs = append(m.Pairs, DVPair{}) + if err := m.Pairs[len(m.Pairs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *DVVTriplet) 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 ErrIntOverflowTypes + } + 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: DVVTriplet: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DVVTriplet: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DelegatorAddress", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DelegatorAddress = append(m.DelegatorAddress[:0], dAtA[iNdEx:postIndex]...) + if m.DelegatorAddress == nil { + m.DelegatorAddress = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ValidatorSrcAddress", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ValidatorSrcAddress = append(m.ValidatorSrcAddress[:0], dAtA[iNdEx:postIndex]...) + if m.ValidatorSrcAddress == nil { + m.ValidatorSrcAddress = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ValidatorDstAddress", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ValidatorDstAddress = append(m.ValidatorDstAddress[:0], dAtA[iNdEx:postIndex]...) + if m.ValidatorDstAddress == nil { + m.ValidatorDstAddress = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *DVVTriplets) 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 ErrIntOverflowTypes + } + 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: DVVTriplets: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DVVTriplets: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Triplets", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Triplets = append(m.Triplets, DVVTriplet{}) + if err := m.Triplets[len(m.Triplets)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Delegation) 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 ErrIntOverflowTypes + } + 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: Delegation: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Delegation: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DelegatorAddress", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DelegatorAddress = append(m.DelegatorAddress[:0], dAtA[iNdEx:postIndex]...) + if m.DelegatorAddress == nil { + m.DelegatorAddress = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ValidatorAddress", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ValidatorAddress = append(m.ValidatorAddress[:0], dAtA[iNdEx:postIndex]...) + if m.ValidatorAddress == nil { + m.ValidatorAddress = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Shares", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Shares.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *UnbondingDelegation) 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 ErrIntOverflowTypes + } + 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: UnbondingDelegation: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: UnbondingDelegation: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DelegatorAddress", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DelegatorAddress = append(m.DelegatorAddress[:0], dAtA[iNdEx:postIndex]...) + if m.DelegatorAddress == nil { + m.DelegatorAddress = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ValidatorAddress", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ValidatorAddress = append(m.ValidatorAddress[:0], dAtA[iNdEx:postIndex]...) + if m.ValidatorAddress == nil { + m.ValidatorAddress = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Entries", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Entries = append(m.Entries, UnbondingDelegationEntry{}) + if err := m.Entries[len(m.Entries)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *UnbondingDelegationEntry) 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 ErrIntOverflowTypes + } + 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: UnbondingDelegationEntry: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: UnbondingDelegationEntry: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CreationHeight", wireType) + } + m.CreationHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CreationHeight |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CompletionTime", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.CompletionTime, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InitialBalance", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.InitialBalance.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Balance", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Balance.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RedelegationEntry) 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 ErrIntOverflowTypes + } + 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: RedelegationEntry: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RedelegationEntry: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CreationHeight", wireType) + } + m.CreationHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CreationHeight |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CompletionTime", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.CompletionTime, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InitialBalance", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.InitialBalance.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SharesDst", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.SharesDst.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Redelegation) 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 ErrIntOverflowTypes + } + 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: Redelegation: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Redelegation: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DelegatorAddress", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DelegatorAddress = append(m.DelegatorAddress[:0], dAtA[iNdEx:postIndex]...) + if m.DelegatorAddress == nil { + m.DelegatorAddress = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ValidatorSrcAddress", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ValidatorSrcAddress = append(m.ValidatorSrcAddress[:0], dAtA[iNdEx:postIndex]...) + if m.ValidatorSrcAddress == nil { + m.ValidatorSrcAddress = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ValidatorDstAddress", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ValidatorDstAddress = append(m.ValidatorDstAddress[:0], dAtA[iNdEx:postIndex]...) + if m.ValidatorDstAddress == nil { + m.ValidatorDstAddress = []byte{} + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Entries", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Entries = append(m.Entries, RedelegationEntry{}) + if err := m.Entries[len(m.Entries)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Params) 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 ErrIntOverflowTypes + } + 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: Params: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UnbondingTime", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_gogo_protobuf_types.StdDurationUnmarshal(&m.UnbondingTime, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxValidators", wireType) + } + m.MaxValidators = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MaxValidators |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxEntries", wireType) + } + m.MaxEntries = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MaxEntries |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field HistoricalEntries", wireType) + } + m.HistoricalEntries = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.HistoricalEntries |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BondDenom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.BondDenom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTypes(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthTypes + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTypes + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTypes + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTypes = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTypes = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTypes = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/staking/types/types.proto b/x/staking/types/types.proto new file mode 100644 index 000000000000..281d1db89207 --- /dev/null +++ b/x/staking/types/types.proto @@ -0,0 +1,368 @@ +syntax = "proto3"; +package cosmos_sdk.x.staking.v1; + +import "third_party/proto/gogoproto/gogo.proto"; +import "third_party/proto/tendermint/abci/types/types.proto"; +import "google/protobuf/timestamp.proto"; +import "google/protobuf/duration.proto"; +import "types/types.proto"; + +option go_package = "github.com/cosmos/cosmos-sdk/x/staking/types"; + +// MsgCreateValidator defines an SDK message for creating a new validator. +message MsgCreateValidator { + Description description = 1 [(gogoproto.nullable) = false]; + CommissionRates commission = 2 [(gogoproto.nullable) = false]; + string min_self_delegation = 3 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.moretags) = "yaml:\"min_self_delegation\"", + (gogoproto.nullable) = false + ]; + bytes delegator_address = 4 [ + (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress", + (gogoproto.moretags) = "yaml:\"delegator_address\"" + ]; + bytes validator_address = 5 [ + (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.ValAddress", + (gogoproto.moretags) = "yaml:\"validator_address\"" + ]; + string pubkey = 6; + cosmos_sdk.v1.Coin value = 7 [(gogoproto.nullable) = false]; +} + +// MsgEditValidator defines an SDK message for editing an existing validator. +message MsgEditValidator { + Description description = 1 [(gogoproto.nullable) = false]; + bytes validator_address = 2 [ + (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.ValAddress", + (gogoproto.moretags) = "yaml:\"address\"" + ]; + + // We pass a reference to the new commission rate and min self delegation as + // it's not mandatory to update. If not updated, the deserialized rate will be + // zero with no way to distinguish if an update was intended. + // + // REF: #2373 + string commission_rate = 3 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.moretags) = "yaml:\"commission_rate\"" + ]; + string min_self_delegation = 4 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.moretags) = "yaml:\"min_self_delegation\"" + ]; +} + +// MsgDelegate defines an SDK message for performing a delegation from a +// delegate to a validator. +message MsgDelegate { + bytes delegator_address = 1 [ + (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress", + (gogoproto.moretags) = "yaml:\"delegator_address\"" + ]; + bytes validator_address = 2 [ + (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.ValAddress", + (gogoproto.moretags) = "yaml:\"validator_address\"" + ]; + cosmos_sdk.v1.Coin amount = 3 [(gogoproto.nullable) = false]; +} + +// MsgBeginRedelegate defines an SDK message for performing a redelegation from +// a delegate and source validator to a destination validator. +message MsgBeginRedelegate { + bytes delegator_address = 1 [ + (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress", + (gogoproto.moretags) = "yaml:\"delegator_address\"" + ]; + bytes validator_src_address = 2 [ + (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.ValAddress", + (gogoproto.moretags) = "yaml:\"validator_src_address\"" + ]; + bytes validator_dst_address = 3 [ + (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.ValAddress", + (gogoproto.moretags) = "yaml:\"validator_dst_address\"" + ]; + cosmos_sdk.v1.Coin amount = 4 [(gogoproto.nullable) = false]; +} + +// MsgUndelegate defines an SDK message for performing an undelegation from a +// delegate and a validator. +message MsgUndelegate { + bytes delegator_address = 1 [ + (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress", + (gogoproto.moretags) = "yaml:\"delegator_address\"" + ]; + bytes validator_address = 2 [ + (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.ValAddress", + (gogoproto.moretags) = "yaml:\"validator_address\"" + ]; + cosmos_sdk.v1.Coin amount = 3 [(gogoproto.nullable) = false]; +} + +// HistoricalInfo contains the historical information that gets stored at +// each height. +message HistoricalInfo { + option (gogoproto.equal) = true; + + tendermint.abci.types.Header header = 1 [(gogoproto.nullable) = false]; + repeated Validator valset = 2 [(gogoproto.nullable) = false]; +} + +// CommissionRates defines the initial commission rates to be used for creating +// a validator. +message CommissionRates { + option (gogoproto.equal) = true; + option (gogoproto.goproto_stringer) = false; + + string rate = 1 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; + string max_rate = 2 [ + (gogoproto.moretags) = "yaml:\"max_rate\"", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; + string max_change_rate = 3 [ + (gogoproto.moretags) = "yaml:\"max_change_rate\"", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; +} + +// Commission defines a commission parameters for a given validator. +message Commission { + option (gogoproto.equal) = true; + option (gogoproto.goproto_stringer) = false; + + CommissionRates commission_rates = 1 [(gogoproto.embed) = true, (gogoproto.nullable) = false]; + google.protobuf.Timestamp update_time = 2 [ + (gogoproto.nullable) = false, + (gogoproto.stdtime) = true, + (gogoproto.moretags) = "yaml:\"update_time\"" + ]; +} + +// Description defines a validator description. +message Description { + option (gogoproto.equal) = true; + option (gogoproto.goproto_stringer) = false; + + string moniker = 1; + string identity = 2; + string website = 3; + string security_contact = 4 [(gogoproto.moretags) = "yaml:\"security_contact\""]; + string details = 5; +} + +// Validator defines the total amount of bond shares and their exchange rate to +// coins. Slashing results in a decrease in the exchange rate, allowing correct +// calculation of future undelegations without iterating over delegators. +// When coins are delegated to this validator, the validator is credited with a +// delegation whose number of bond shares is based on the amount of coins +// delegated divided by the current exchange rate. Voting power can be +// calculated as total bonded shares multiplied by exchange rate. +message Validator { + option (gogoproto.equal) = true; + option (gogoproto.goproto_stringer) = false; + option (gogoproto.goproto_getters) = false; + + bytes operator_address = 1 [ + (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.ValAddress", + (gogoproto.moretags) = "yaml:\"operator_address\"" + ]; + string consensus_pubkey = 2 [(gogoproto.moretags) = "yaml:\"consensus_pubkey\""]; + bool jailed = 3; + int32 status = 4 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.BondStatus"]; + string tokens = 5 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false + ]; + string delegator_shares = 6 [ + (gogoproto.moretags) = "yaml:\"delegator_shares\"", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; + Description description = 7 [(gogoproto.nullable) = false]; + int64 unbonding_height = 8 [(gogoproto.moretags) = "yaml:\"unbonding_height\""]; + google.protobuf.Timestamp unbonding_time = 9 [ + (gogoproto.nullable) = false, + (gogoproto.stdtime) = true, + (gogoproto.moretags) = "yaml:\"unbonding_time\"" + ]; + Commission commission = 10 [(gogoproto.nullable) = false]; + string min_self_delegation = 11 [ + (gogoproto.moretags) = "yaml:\"min_self_delegation\"", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false + ]; +} + +// DVPair is struct that just has a delegator-validator pair with no other data. +// It is intended to be used as a marshalable pointer. For example, a DVPair can +// be used to construct the key to getting an UnbondingDelegation from state. +message DVPair { + option (gogoproto.equal) = true; + option (gogoproto.goproto_stringer) = false; + + bytes delegator_address = 1 [ + (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress", + (gogoproto.moretags) = "yaml:\"delegator_address\"" + ]; + bytes validator_address = 2 [ + (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.ValAddress", + (gogoproto.moretags) = "yaml:\"validator_address\"" + ]; +} + +// DVPairs defines an array of DVPair objects. +message DVPairs { + repeated DVPair pairs = 1 [(gogoproto.nullable) = false]; +} + +// DVVTriplet is struct that just has a delegator-validator-validator triplet +// with no other data. It is intended to be used as a marshalable pointer. For +// example, a DVVTriplet can be used to construct the key to getting a +// Redelegation from state. +message DVVTriplet { + option (gogoproto.equal) = true; + option (gogoproto.goproto_stringer) = false; + + bytes delegator_address = 1 [ + (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress", + (gogoproto.moretags) = "yaml:\"delegator_address\"" + ]; + bytes validator_src_address = 2 [ + (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.ValAddress", + (gogoproto.moretags) = "yaml:\"validator_src_address\"" + ]; + bytes validator_dst_address = 3 [ + (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.ValAddress", + (gogoproto.moretags) = "yaml:\"validator_dst_address\"" + ]; +} + +// DVVTriplets defines an array of DVVTriplet objects. +message DVVTriplets { + repeated DVVTriplet triplets = 1 [(gogoproto.nullable) = false]; +} + +// Delegation represents the bond with tokens held by an account. It is +// owned by one delegator, and is associated with the voting power of one +// validator. +message Delegation { + option (gogoproto.equal) = true; + option (gogoproto.goproto_stringer) = false; + + bytes delegator_address = 1 [ + (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress", + (gogoproto.moretags) = "yaml:\"delegator_address\"" + ]; + bytes validator_address = 2 [ + (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.ValAddress", + (gogoproto.moretags) = "yaml:\"validator_address\"" + ]; + string shares = 3 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; +} + +// UnbondingDelegation stores all of a single delegator's unbonding bonds +// for a single validator in an time-ordered list +message UnbondingDelegation { + option (gogoproto.equal) = true; + option (gogoproto.goproto_stringer) = false; + + bytes delegator_address = 1 [ + (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress", + (gogoproto.moretags) = "yaml:\"delegator_address\"" + ]; + bytes validator_address = 2 [ + (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.ValAddress", + (gogoproto.moretags) = "yaml:\"validator_address\"" + ]; + repeated UnbondingDelegationEntry entries = 3 + [(gogoproto.nullable) = false]; // unbonding delegation entries +} + +// UnbondingDelegationEntry defines an unbonding object with relevant metadata. +message UnbondingDelegationEntry { + option (gogoproto.equal) = true; + option (gogoproto.goproto_stringer) = false; + + int64 creation_height = 1 [(gogoproto.moretags) = "yaml:\"creation_height\""]; + google.protobuf.Timestamp completion_time = 2 [ + (gogoproto.nullable) = false, + (gogoproto.stdtime) = true, + (gogoproto.moretags) = "yaml:\"completion_time\"" + ]; + string initial_balance = 3 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false, + (gogoproto.moretags) = "yaml:\"initial_balance\"" + ]; + string balance = 4 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false + ]; +} + +// RedelegationEntry defines a redelegation object with relevant metadata. +message RedelegationEntry { + option (gogoproto.equal) = true; + option (gogoproto.goproto_stringer) = false; + + int64 creation_height = 1 [(gogoproto.moretags) = "yaml:\"creation_height\""]; + google.protobuf.Timestamp completion_time = 2 [ + (gogoproto.nullable) = false, + (gogoproto.stdtime) = true, + (gogoproto.moretags) = "yaml:\"completion_time\"" + ]; + string initial_balance = 3 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false, + (gogoproto.moretags) = "yaml:\"initial_balance\"" + ]; + string shares_dst = 4 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; +} + +// Redelegation contains the list of a particular delegator's redelegating bonds +// from a particular source validator to a particular destination validator. +message Redelegation { + option (gogoproto.equal) = true; + option (gogoproto.goproto_stringer) = false; + + bytes delegator_address = 1 [ + (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress", + (gogoproto.moretags) = "yaml:\"delegator_address\"" + ]; + bytes validator_src_address = 2 [ + (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.ValAddress", + (gogoproto.moretags) = "yaml:\"validator_src_address\"" + ]; + bytes validator_dst_address = 3 [ + (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.ValAddress", + (gogoproto.moretags) = "yaml:\"validator_dst_address\"" + ]; + repeated RedelegationEntry entries = 4 [(gogoproto.nullable) = false]; // redelegation entries +} + +// Params defines the parameters for the staking module. +message Params { + option (gogoproto.equal) = true; + option (gogoproto.goproto_stringer) = false; + + google.protobuf.Duration unbonding_time = 1 [ + (gogoproto.nullable) = false, + (gogoproto.stdduration) = true, + (gogoproto.moretags) = "yaml:\"unbonding_time\"" + ]; + uint32 max_validators = 2 [(gogoproto.moretags) = "yaml:\"max_validators\""]; + uint32 max_entries = 3 [(gogoproto.moretags) = "yaml:\"max_entries\""]; + uint32 historical_entries = 4 [(gogoproto.moretags) = "yaml:\"historical_entries\""]; + string bond_denom = 5 [(gogoproto.moretags) = "yaml:\"bond_denom\""]; +} diff --git a/x/staking/types/validator.go b/x/staking/types/validator.go index 855ed988d290..2304596ae2b9 100644 --- a/x/staking/types/validator.go +++ b/x/staking/types/validator.go @@ -28,62 +28,33 @@ const ( MaxDetailsLength = 280 ) -// Implements Validator interface var _ exported.ValidatorI = Validator{} -// Validator defines the total amount of bond shares and their exchange rate to -// coins. Slashing results in a decrease in the exchange rate, allowing correct -// calculation of future undelegations without iterating over delegators. -// When coins are delegated to this validator, the validator is credited with a -// delegation whose number of bond shares is based on the amount of coins delegated -// divided by the current exchange rate. Voting power can be calculated as total -// bonded shares multiplied by exchange rate. -type Validator struct { - OperatorAddress sdk.ValAddress `json:"operator_address" yaml:"operator_address"` // address of the validator's operator; bech encoded in JSON - ConsPubKey crypto.PubKey `json:"consensus_pubkey" yaml:"consensus_pubkey"` // the consensus public key of the validator; bech encoded in JSON - Jailed bool `json:"jailed" yaml:"jailed"` // has the validator been jailed from bonded status? - Status sdk.BondStatus `json:"status" yaml:"status"` // validator status (bonded/unbonding/unbonded) - Tokens sdk.Int `json:"tokens" yaml:"tokens"` // delegated tokens (incl. self-delegation) - DelegatorShares sdk.Dec `json:"delegator_shares" yaml:"delegator_shares"` // total shares issued to a validator's delegators - Description Description `json:"description" yaml:"description"` // description terms for the validator - UnbondingHeight int64 `json:"unbonding_height" yaml:"unbonding_height"` // if unbonding, height at which this validator has begun unbonding - UnbondingCompletionTime time.Time `json:"unbonding_time" yaml:"unbonding_time"` // if unbonding, min time for the validator to complete unbonding - Commission Commission `json:"commission" yaml:"commission"` // commission parameters - MinSelfDelegation sdk.Int `json:"min_self_delegation" yaml:"min_self_delegation"` // validator's self declared minimum self delegation -} - -// custom marshal yaml function due to consensus pubkey -func (v Validator) MarshalYAML() (interface{}, error) { - bs, err := yaml.Marshal(struct { - OperatorAddress sdk.ValAddress - ConsPubKey string - Jailed bool - Status sdk.BondStatus - Tokens sdk.Int - DelegatorShares sdk.Dec - Description Description - UnbondingHeight int64 - UnbondingCompletionTime time.Time - Commission Commission - MinSelfDelegation sdk.Int - }{ - OperatorAddress: v.OperatorAddress, - ConsPubKey: sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, v.ConsPubKey), - Jailed: v.Jailed, - Status: v.Status, - Tokens: v.Tokens, - DelegatorShares: v.DelegatorShares, - Description: v.Description, - UnbondingHeight: v.UnbondingHeight, - UnbondingCompletionTime: v.UnbondingCompletionTime, - Commission: v.Commission, - MinSelfDelegation: v.MinSelfDelegation, - }) - if err != nil { - return nil, err +func NewValidator(operator sdk.ValAddress, pubKey crypto.PubKey, description Description) Validator { + var pkStr string + if pubKey != nil { + pkStr = sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, pubKey) + } + + return Validator{ + OperatorAddress: operator, + ConsensusPubkey: pkStr, + Jailed: false, + Status: sdk.Unbonded, + Tokens: sdk.ZeroInt(), + DelegatorShares: sdk.ZeroDec(), + Description: description, + UnbondingHeight: int64(0), + UnbondingTime: time.Unix(0, 0).UTC(), + Commission: NewCommission(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()), + MinSelfDelegation: sdk.OneInt(), } +} - return string(bs), nil +// String implements the Stringer interface for a Validator object. +func (v Validator) String() string { + out, _ := yaml.Marshal(v) + return string(out) } // Validators is a collection of Validator @@ -135,30 +106,13 @@ func (v Validators) Swap(i, j int) { v[j] = it } -// NewValidator - initialize a new validator -func NewValidator(operator sdk.ValAddress, pubKey crypto.PubKey, description Description) Validator { - return Validator{ - OperatorAddress: operator, - ConsPubKey: pubKey, - Jailed: false, - Status: sdk.Unbonded, - Tokens: sdk.ZeroInt(), - DelegatorShares: sdk.ZeroDec(), - Description: description, - UnbondingHeight: int64(0), - UnbondingCompletionTime: time.Unix(0, 0).UTC(), - Commission: NewCommission(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()), - MinSelfDelegation: sdk.OneInt(), - } -} - // return the redelegation -func MustMarshalValidator(cdc *codec.Codec, validator Validator) []byte { - return cdc.MustMarshalBinaryLengthPrefixed(validator) +func MustMarshalValidator(cdc codec.Marshaler, validator Validator) []byte { + return cdc.MustMarshalBinaryLengthPrefixed(&validator) } // unmarshal a redelegation from a store value -func MustUnmarshalValidator(cdc *codec.Codec, value []byte) Validator { +func MustUnmarshalValidator(cdc codec.Marshaler, value []byte) Validator { validator, err := UnmarshalValidator(cdc, value) if err != nil { panic(err) @@ -167,111 +121,9 @@ func MustUnmarshalValidator(cdc *codec.Codec, value []byte) Validator { } // unmarshal a redelegation from a store value -func UnmarshalValidator(cdc *codec.Codec, value []byte) (validator Validator, err error) { - err = cdc.UnmarshalBinaryLengthPrefixed(value, &validator) - return validator, err -} - -// String returns a human readable string representation of a validator. -func (v Validator) String() string { - bechConsPubKey, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, v.ConsPubKey) - if err != nil { - panic(err) - } - return fmt.Sprintf(`Validator - Operator Address: %s - Validator Consensus Pubkey: %s - Jailed: %v - Status: %s - Tokens: %s - Delegator Shares: %s - Description: %s - Unbonding Height: %d - Unbonding Completion Time: %v - Minimum Self Delegation: %v - Commission: %s`, v.OperatorAddress, bechConsPubKey, - v.Jailed, v.Status, v.Tokens, - v.DelegatorShares, v.Description, - v.UnbondingHeight, v.UnbondingCompletionTime, v.MinSelfDelegation, v.Commission) -} - -// this is a helper struct used for JSON de- and encoding only -type bechValidator struct { - OperatorAddress sdk.ValAddress `json:"operator_address" yaml:"operator_address"` // the bech32 address of the validator's operator - ConsPubKey string `json:"consensus_pubkey" yaml:"consensus_pubkey"` // the bech32 consensus public key of the validator - Jailed bool `json:"jailed" yaml:"jailed"` // has the validator been jailed from bonded status? - Status sdk.BondStatus `json:"status" yaml:"status"` // validator status (bonded/unbonding/unbonded) - Tokens sdk.Int `json:"tokens" yaml:"tokens"` // delegated tokens (incl. self-delegation) - DelegatorShares sdk.Dec `json:"delegator_shares" yaml:"delegator_shares"` // total shares issued to a validator's delegators - Description Description `json:"description" yaml:"description"` // description terms for the validator - UnbondingHeight int64 `json:"unbonding_height" yaml:"unbonding_height"` // if unbonding, height at which this validator has begun unbonding - UnbondingCompletionTime time.Time `json:"unbonding_time" yaml:"unbonding_time"` // if unbonding, min time for the validator to complete unbonding - Commission Commission `json:"commission" yaml:"commission"` // commission parameters - MinSelfDelegation sdk.Int `json:"min_self_delegation" yaml:"min_self_delegation"` // minimum self delegation -} - -// MarshalJSON marshals the validator to JSON using Bech32 -func (v Validator) MarshalJSON() ([]byte, error) { - bechConsPubKey, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, v.ConsPubKey) - if err != nil { - return nil, err - } - - return codec.Cdc.MarshalJSON(bechValidator{ - OperatorAddress: v.OperatorAddress, - ConsPubKey: bechConsPubKey, - Jailed: v.Jailed, - Status: v.Status, - Tokens: v.Tokens, - DelegatorShares: v.DelegatorShares, - Description: v.Description, - UnbondingHeight: v.UnbondingHeight, - UnbondingCompletionTime: v.UnbondingCompletionTime, - MinSelfDelegation: v.MinSelfDelegation, - Commission: v.Commission, - }) -} - -// UnmarshalJSON unmarshals the validator from JSON using Bech32 -func (v *Validator) UnmarshalJSON(data []byte) error { - bv := &bechValidator{} - if err := codec.Cdc.UnmarshalJSON(data, bv); err != nil { - return err - } - consPubKey, err := sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeConsPub, bv.ConsPubKey) - if err != nil { - return err - } - *v = Validator{ - OperatorAddress: bv.OperatorAddress, - ConsPubKey: consPubKey, - Jailed: bv.Jailed, - Tokens: bv.Tokens, - Status: bv.Status, - DelegatorShares: bv.DelegatorShares, - Description: bv.Description, - UnbondingHeight: bv.UnbondingHeight, - UnbondingCompletionTime: bv.UnbondingCompletionTime, - Commission: bv.Commission, - MinSelfDelegation: bv.MinSelfDelegation, - } - return nil -} - -// only the vitals -func (v Validator) TestEquivalent(v2 Validator) bool { - return v.ConsPubKey.Equals(v2.ConsPubKey) && - bytes.Equal(v.OperatorAddress, v2.OperatorAddress) && - v.Status.Equal(v2.Status) && - v.Tokens.Equal(v2.Tokens) && - v.DelegatorShares.Equal(v2.DelegatorShares) && - v.Description == v2.Description && - v.Commission.Equal(v2.Commission) -} - -// return the TM validator address -func (v Validator) ConsAddress() sdk.ConsAddress { - return sdk.ConsAddress(v.ConsPubKey.Address()) +func UnmarshalValidator(cdc codec.Marshaler, value []byte) (v Validator, err error) { + err = cdc.UnmarshalBinaryLengthPrefixed(value, &v) + return v, err } // IsBonded checks if the validator status equals Bonded @@ -292,16 +144,6 @@ func (v Validator) IsUnbonding() bool { // constant used in flags to indicate that description field should not be updated const DoNotModifyDesc = "[do-not-modify]" -// Description - description fields for a validator -type Description struct { - Moniker string `json:"moniker" yaml:"moniker"` // name - Identity string `json:"identity" yaml:"identity"` // optional identity signature (ex. UPort or Keybase) - Website string `json:"website" yaml:"website"` // optional website link - SecurityContact string `json:"security_contact" yaml:"security_contact"` // optional security contact info - Details string `json:"details" yaml:"details"` // optional details -} - -// NewDescription returns a new Description with the provided values. func NewDescription(moniker, identity, website, securityContact, details string) Description { return Description{ Moniker: moniker, @@ -312,6 +154,12 @@ func NewDescription(moniker, identity, website, securityContact, details string) } } +// String implements the Stringer interface for a Description object. +func (d Description) String() string { + out, _ := yaml.Marshal(d) + return string(out) +} + // UpdateDescription updates the fields of a given description. An error is // returned if the resulting description contains an invalid length. func (d Description) UpdateDescription(d2 Description) (Description, error) { @@ -365,7 +213,7 @@ func (d Description) EnsureLength() (Description, error) { // with the full validator power func (v Validator) ABCIValidatorUpdate() abci.ValidatorUpdate { return abci.ValidatorUpdate{ - PubKey: tmtypes.TM2PB.PubKey(v.ConsPubKey), + PubKey: tmtypes.TM2PB.PubKey(v.GetConsPubKey()), Power: v.ConsensusPower(), } } @@ -374,14 +222,14 @@ func (v Validator) ABCIValidatorUpdate() abci.ValidatorUpdate { // with zero power used for validator updates. func (v Validator) ABCIValidatorUpdateZero() abci.ValidatorUpdate { return abci.ValidatorUpdate{ - PubKey: tmtypes.TM2PB.PubKey(v.ConsPubKey), + PubKey: tmtypes.TM2PB.PubKey(v.GetConsPubKey()), Power: 0, } } // ToTmValidator casts an SDK validator to a tendermint type Validator. func (v Validator) ToTmValidator() *tmtypes.Validator { - return tmtypes.NewValidator(v.ConsPubKey, v.ConsensusPower()) + return tmtypes.NewValidator(v.GetConsPubKey(), v.ConsensusPower()) } // SetInitialCommission attempts to set a validator's initial commission. An @@ -506,20 +354,19 @@ func (v Validator) RemoveTokens(tokens sdk.Int) Validator { // NOTE: because token fractions are left in the valiadator, // the exchange rate of future shares of this validator can increase. func (v Validator) RemoveDelShares(delShares sdk.Dec) (Validator, sdk.Int) { - remainingShares := v.DelegatorShares.Sub(delShares) + var issuedTokens sdk.Int if remainingShares.IsZero() { - // last delegation share gets any trimmings issuedTokens = v.Tokens v.Tokens = sdk.ZeroInt() } else { - // leave excess tokens in the validator // however fully use all the delegator shares issuedTokens = v.TokensFromShares(delShares).TruncateInt() v.Tokens = v.Tokens.Sub(issuedTokens) + if v.Tokens.IsNegative() { panic("attempting to remove more tokens than available in validator") } @@ -529,13 +376,27 @@ func (v Validator) RemoveDelShares(delShares sdk.Dec) (Validator, sdk.Int) { return v, issuedTokens } +// MinEqual defines a more minimum set of equality conditions when comparing two +// validators. +func (v Validator) MinEqual(other Validator) bool { + return v.ConsensusPubkey == other.ConsensusPubkey && + bytes.Equal(v.OperatorAddress, other.OperatorAddress) && + v.Status.Equal(other.Status) && + v.Tokens.Equal(other.Tokens) && + v.DelegatorShares.Equal(other.DelegatorShares) && + v.Description == other.Description && + v.Commission.Equal(other.Commission) +} + // nolint - for ValidatorI -func (v Validator) IsJailed() bool { return v.Jailed } -func (v Validator) GetMoniker() string { return v.Description.Moniker } -func (v Validator) GetStatus() sdk.BondStatus { return v.Status } -func (v Validator) GetOperator() sdk.ValAddress { return v.OperatorAddress } -func (v Validator) GetConsPubKey() crypto.PubKey { return v.ConsPubKey } -func (v Validator) GetConsAddr() sdk.ConsAddress { return sdk.ConsAddress(v.ConsPubKey.Address()) } +func (v Validator) IsJailed() bool { return v.Jailed } +func (v Validator) GetMoniker() string { return v.Description.Moniker } +func (v Validator) GetStatus() sdk.BondStatus { return v.Status } +func (v Validator) GetOperator() sdk.ValAddress { return v.OperatorAddress } +func (v Validator) GetConsPubKey() crypto.PubKey { + return sdk.MustGetPubKeyFromBech32(sdk.Bech32PubKeyTypeConsPub, v.ConsensusPubkey) +} +func (v Validator) GetConsAddr() sdk.ConsAddress { return sdk.ConsAddress(v.GetConsPubKey().Address()) } func (v Validator) GetTokens() sdk.Int { return v.Tokens } func (v Validator) GetBondedTokens() sdk.Int { return v.BondedTokens() } func (v Validator) GetConsensusPower() int64 { return v.ConsensusPower() } diff --git a/x/staking/types/validator_test.go b/x/staking/types/validator_test.go index b8a572444e0c..54e0c7ebb639 100644 --- a/x/staking/types/validator_test.go +++ b/x/staking/types/validator_test.go @@ -1,7 +1,6 @@ package types import ( - "fmt" "math/rand" "reflect" "sort" @@ -11,7 +10,6 @@ import ( "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/crypto/ed25519" tmtypes "github.com/tendermint/tendermint/types" - yaml "gopkg.in/yaml.v2" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" @@ -21,12 +19,12 @@ func TestValidatorTestEquivalent(t *testing.T) { val1 := NewValidator(valAddr1, pk1, Description{}) val2 := NewValidator(valAddr1, pk1, Description{}) - ok := val1.TestEquivalent(val2) + ok := val1.Equal(val2) require.True(t, ok) val2 = NewValidator(valAddr2, pk2, Description{}) - ok = val1.TestEquivalent(val2) + ok = val1.Equal(val2) require.False(t, ok) } @@ -63,7 +61,7 @@ func TestABCIValidatorUpdate(t *testing.T) { validator := NewValidator(valAddr1, pk1, Description{}) abciVal := validator.ABCIValidatorUpdate() - require.Equal(t, tmtypes.TM2PB.PubKey(validator.ConsPubKey), abciVal.PubKey) + require.Equal(t, tmtypes.TM2PB.PubKey(validator.GetConsPubKey()), abciVal.PubKey) require.Equal(t, validator.BondedTokens().Int64(), abciVal.Power) } @@ -71,14 +69,14 @@ func TestABCIValidatorUpdateZero(t *testing.T) { validator := NewValidator(valAddr1, pk1, Description{}) abciVal := validator.ABCIValidatorUpdateZero() - require.Equal(t, tmtypes.TM2PB.PubKey(validator.ConsPubKey), abciVal.PubKey) + require.Equal(t, tmtypes.TM2PB.PubKey(validator.GetConsPubKey()), abciVal.PubKey) require.Equal(t, int64(0), abciVal.Power) } func TestShareTokens(t *testing.T) { validator := Validator{ OperatorAddress: valAddr1, - ConsPubKey: pk1, + ConsensusPubkey: sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, pk1), Status: sdk.Bonded, Tokens: sdk.NewInt(100), DelegatorShares: sdk.NewDec(100), @@ -96,7 +94,7 @@ func TestRemoveTokens(t *testing.T) { validator := Validator{ OperatorAddress: valAddr, - ConsPubKey: valPubKey, + ConsensusPubkey: sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, valPubKey), Status: sdk.Bonded, Tokens: sdk.NewInt(100), DelegatorShares: sdk.NewDec(100), @@ -152,7 +150,7 @@ func TestAddTokensValidatorUnbonded(t *testing.T) { func TestRemoveDelShares(t *testing.T) { valA := Validator{ OperatorAddress: sdk.ValAddress(pk1.Address().Bytes()), - ConsPubKey: pk1, + ConsensusPubkey: sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, pk1), Status: sdk.Bonded, Tokens: sdk.NewInt(100), DelegatorShares: sdk.NewDec(100), @@ -169,7 +167,7 @@ func TestRemoveDelShares(t *testing.T) { delShares := sdk.NewDec(115) validator := Validator{ OperatorAddress: sdk.ValAddress(pk1.Address().Bytes()), - ConsPubKey: pk1, + ConsensusPubkey: sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, pk1), Status: sdk.Bonded, Tokens: poolTokens, DelegatorShares: delShares, @@ -218,7 +216,7 @@ func TestPossibleOverflow(t *testing.T) { delShares := sdk.NewDec(391432570689183511).Quo(sdk.NewDec(40113011844664)) validator := Validator{ OperatorAddress: sdk.ValAddress(pk1.Address().Bytes()), - ConsPubKey: pk1, + ConsensusPubkey: sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, pk1), Status: sdk.Bonded, Tokens: sdk.NewInt(2159), DelegatorShares: delShares, @@ -276,38 +274,6 @@ func TestValidatorSetInitialCommission(t *testing.T) { } } -func TestValidatorMarshalYAML(t *testing.T) { - validator := NewValidator(valAddr1, pk1, Description{}) - bechifiedPub, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, validator.ConsPubKey) - require.NoError(t, err) - bs, err := yaml.Marshal(validator) - require.NoError(t, err) - want := fmt.Sprintf(`| - operatoraddress: %s - conspubkey: %s - jailed: false - status: 0 - tokens: "0" - delegatorshares: "0.000000000000000000" - description: - moniker: "" - identity: "" - website: "" - security_contact: "" - details: "" - unbondingheight: 0 - unbondingcompletiontime: 1970-01-01T00:00:00Z - commission: - commission_rates: - rate: "0.000000000000000000" - max_rate: "0.000000000000000000" - max_change_rate: "0.000000000000000000" - update_time: 1970-01-01T00:00:00Z - minselfdelegation: "1" -`, validator.OperatorAddress.String(), bechifiedPub) - require.Equal(t, want, string(bs)) -} - // Check that sort will create deterministic ordering of validators func TestValidatorsSortDeterminism(t *testing.T) { vals := make([]Validator, 10) From dba80caec0b8576416bb765f9d08029986a843c9 Mon Sep 17 00:00:00 2001 From: Aditya Date: Thu, 6 Feb 2020 12:58:32 -0800 Subject: [PATCH 118/529] Merge PR #5579: Fix Restart application issue --- CHANGELOG.md | 12 +++++ baseapp/baseapp_test.go | 86 +++++++++++++++++++++++++++++++- server/start.go | 2 +- store/cache/cache_test.go | 6 +-- store/iavl/store.go | 68 +++++++++++++++++++++---- store/iavl/store_test.go | 84 ++++++++++++++++--------------- store/prefix/store_test.go | 2 +- store/rootmulti/store.go | 74 ++++++++++++++++------------ store/rootmulti/store_test.go | 93 +++++++++++++++++++++++++++++++++-- store/types/pruning.go | 79 ++++++++++++++++++++--------- 10 files changed, 389 insertions(+), 117 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6aec3843db5b..745ed246ce78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,11 +44,23 @@ balances or a single balance by denom when the `denom` query parameter is presen ### API Breaking Changes +* (types) [\#5579](https://github.com/cosmos/cosmos-sdk/pull/5579) The `keepRecent` field has been removed from the `PruningOptions` type. +The `PruningOptions` type now only includes fields `KeepEvery` and `SnapshotEvery`, where `KeepEvery` +determines which committed heights are flushed to disk and `SnapshotEvery` determines which of these +heights are kept after pruning. The `IsValid` method should be called whenever using these options. Methods +`SnapshotVersion` and `FlushVersion` accept a version arugment and determine if the version should be +flushed to disk or kept as a snapshot. Note, `KeepRecent` is automatically inferred from the options +and provided directly the IAVL store. * (modules) [\#5555](https://github.com/cosmos/cosmos-sdk/pull/5555) Move x/auth/client/utils/ types and functions to x/auth/client/. * (modules) [\#5572](https://github.com/cosmos/cosmos-sdk/pull/5572) Move account balance logic and APIs from `x/auth` to `x/bank`. ### Bug Fixes +* (types) [\#5579](https://github.com/cosmos/cosmos-sdk/pull/5579) The IAVL `Store#Commit` method has been refactored to +delete a flushed version if it is not a snapshot version. The root multi-store now keeps track of `commitInfo` instead +of `types.CommitID`. During `Commit` of the root multi-store, `lastCommitInfo` is updated from the saved state +and is only flushed to disk if it is a snapshot version. During `Query` of the root multi-store, if the request height +is the latest height, we'll use the store's `lastCommitInfo`. Otherwise, we fetch `commitInfo` from disk. * (x/bank) [\#5531](https://github.com/cosmos/cosmos-sdk/issues/5531) Added missing amount event to MsgMultiSend, emitted for each output. * (client) [\#5618](https://github.com/cosmos/cosmos-sdk/pull/5618) Fix crash on the client when the verifier is not set. diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index 8e2caf466c99..6ee5aabbb0a8 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -83,7 +83,7 @@ func TestMountStores(t *testing.T) { // Test that LoadLatestVersion actually does. func TestLoadVersion(t *testing.T) { logger := defaultLogger() - pruningOpt := SetPruning(store.PruneSyncable) + pruningOpt := SetPruning(store.PruneNothing) db := dbm.NewMemDB() name := t.Name() app := NewBaseApp(name, logger, db, nil, pruningOpt) @@ -293,7 +293,7 @@ func TestAppVersionSetterGetter(t *testing.T) { func TestLoadVersionInvalid(t *testing.T) { logger := log.NewNopLogger() - pruningOpt := SetPruning(store.PruneSyncable) + pruningOpt := SetPruning(store.PruneNothing) db := dbm.NewMemDB() name := t.Name() app := NewBaseApp(name, logger, db, nil, pruningOpt) @@ -326,6 +326,88 @@ func TestLoadVersionInvalid(t *testing.T) { require.Error(t, err) } +func TestLoadVersionPruning(t *testing.T) { + logger := log.NewNopLogger() + pruningOptions := store.PruningOptions{ + KeepEvery: 2, + SnapshotEvery: 6, + } + pruningOpt := SetPruning(pruningOptions) + db := dbm.NewMemDB() + name := t.Name() + app := NewBaseApp(name, logger, db, nil, pruningOpt) + + // make a cap key and mount the store + capKey := sdk.NewKVStoreKey(MainStoreKey) + app.MountStores(capKey) + err := app.LoadLatestVersion(capKey) // needed to make stores non-nil + require.Nil(t, err) + + emptyCommitID := sdk.CommitID{} + + // fresh store has zero/empty last commit + lastHeight := app.LastBlockHeight() + lastID := app.LastCommitID() + require.Equal(t, int64(0), lastHeight) + require.Equal(t, emptyCommitID, lastID) + + // execute a block + header := abci.Header{Height: 1} + app.BeginBlock(abci.RequestBeginBlock{Header: header}) + res := app.Commit() + + // execute a block, collect commit ID + header = abci.Header{Height: 2} + app.BeginBlock(abci.RequestBeginBlock{Header: header}) + res = app.Commit() + commitID2 := sdk.CommitID{Version: 2, Hash: res.Data} + + // execute a block + header = abci.Header{Height: 3} + app.BeginBlock(abci.RequestBeginBlock{Header: header}) + res = app.Commit() + commitID3 := sdk.CommitID{Version: 3, Hash: res.Data} + + // reload with LoadLatestVersion, check it loads last flushed version + app = NewBaseApp(name, logger, db, nil, pruningOpt) + app.MountStores(capKey) + err = app.LoadLatestVersion(capKey) + require.Nil(t, err) + testLoadVersionHelper(t, app, int64(2), commitID2) + + // re-execute block 3 and check it is same CommitID + header = abci.Header{Height: 3} + app.BeginBlock(abci.RequestBeginBlock{Header: header}) + res = app.Commit() + recommitID3 := sdk.CommitID{Version: 3, Hash: res.Data} + require.Equal(t, commitID3, recommitID3, "Commits of identical blocks not equal after reload") + + // execute a block, collect commit ID + header = abci.Header{Height: 4} + app.BeginBlock(abci.RequestBeginBlock{Header: header}) + res = app.Commit() + commitID4 := sdk.CommitID{Version: 4, Hash: res.Data} + + // execute a block + header = abci.Header{Height: 5} + app.BeginBlock(abci.RequestBeginBlock{Header: header}) + res = app.Commit() + + // reload with LoadLatestVersion, check it loads last flushed version + app = NewBaseApp(name, logger, db, nil, pruningOpt) + app.MountStores(capKey) + err = app.LoadLatestVersion(capKey) + require.Nil(t, err) + testLoadVersionHelper(t, app, int64(4), commitID4) + + // reload with LoadVersion of previous flushed version + // and check it fails since previous flush should be pruned + app = NewBaseApp(name, logger, db, nil, pruningOpt) + app.MountStores(capKey) + err = app.LoadVersion(2, capKey) + require.NotNil(t, err) +} + func testLoadVersionHelper(t *testing.T, app *BaseApp, expectedHeight int64, expectedID sdk.CommitID) { lastHeight := app.LastBlockHeight() lastID := app.LastCommitID() diff --git a/server/start.go b/server/start.go index 8edec4f831c1..5a9cd0500884 100644 --- a/server/start.go +++ b/server/start.go @@ -43,7 +43,7 @@ default, the application will run with Tendermint in process. Pruning options can be provided via the '--pruning' flag. The options are as follows: -syncable: only those states not needed for state syncing will be deleted (keeps last 100 + every 10000th) +syncable: only those states not needed for state syncing will be deleted (flushes every 100th to disk and keeps every 10000th) nothing: all historic states will be saved, nothing will be deleted (i.e. archiving node) everything: all saved states will be deleted, storing only the current state diff --git a/store/cache/cache_test.go b/store/cache/cache_test.go index 93ece75083ed..3fc5f9157dbc 100644 --- a/store/cache/cache_test.go +++ b/store/cache/cache_test.go @@ -20,7 +20,7 @@ func TestGetOrSetStoreCache(t *testing.T) { sKey := types.NewKVStoreKey("test") tree, err := iavl.NewMutableTree(db, 100) require.NoError(t, err) - store := iavlstore.UnsafeNewStore(tree) + store := iavlstore.UnsafeNewStore(tree, types.PruneNothing) store2 := mngr.GetStoreCache(sKey, store) require.NotNil(t, store2) @@ -34,7 +34,7 @@ func TestUnwrap(t *testing.T) { sKey := types.NewKVStoreKey("test") tree, err := iavl.NewMutableTree(db, 100) require.NoError(t, err) - store := iavlstore.UnsafeNewStore(tree) + store := iavlstore.UnsafeNewStore(tree, types.PruneNothing) _ = mngr.GetStoreCache(sKey, store) require.Equal(t, store, mngr.Unwrap(sKey)) @@ -48,7 +48,7 @@ func TestStoreCache(t *testing.T) { sKey := types.NewKVStoreKey("test") tree, err := iavl.NewMutableTree(db, 100) require.NoError(t, err) - store := iavlstore.UnsafeNewStore(tree) + store := iavlstore.UnsafeNewStore(tree, types.PruneNothing) kvStore := mngr.GetStoreCache(sKey, store) for i := uint(0); i < cache.DefaultCommitKVStoreCacheSize*2; i++ { diff --git a/store/iavl/store.go b/store/iavl/store.go index 66c5e5262209..d1e1d9c4cae0 100644 --- a/store/iavl/store.go +++ b/store/iavl/store.go @@ -1,9 +1,11 @@ package iavl import ( + "fmt" "io" "sync" + "github.com/pkg/errors" "github.com/tendermint/iavl" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto/merkle" @@ -29,18 +31,38 @@ var ( // Store Implements types.KVStore and CommitKVStore. type Store struct { - tree Tree + tree Tree + pruning types.PruningOptions } -// LoadStore returns an IAVL Store as a CommitKVStore. Internally it will load the +// LoadStore returns an IAVL Store as a CommitKVStore. Internally, it will load the // store's version (id) from the provided DB. An error is returned if the version // fails to load. func LoadStore(db dbm.DB, id types.CommitID, pruning types.PruningOptions, lazyLoading bool) (types.CommitKVStore, error) { + if !pruning.IsValid() { + return nil, fmt.Errorf("pruning options are invalid: %v", pruning) + } + + var keepRecent int64 + + // Determine the value of keepRecent based on the following: + // + // If KeepEvery = 1, keepRecent should be 0 since there is no need to keep + // latest version in a in-memory cache. + // + // If KeepEvery > 1, keepRecent should be 1 so that state changes in between + // flushed states can be saved in the in-memory latest tree. + if pruning.KeepEvery == 1 { + keepRecent = 0 + } else { + keepRecent = 1 + } + tree, err := iavl.NewMutableTreeWithOpts( db, dbm.NewMemDB(), defaultIAVLCacheSize, - iavl.PruningOptions(pruning.KeepEvery(), pruning.KeepRecent()), + iavl.PruningOptions(pruning.KeepEvery, keepRecent), ) if err != nil { return nil, err @@ -56,15 +78,23 @@ func LoadStore(db dbm.DB, id types.CommitID, pruning types.PruningOptions, lazyL return nil, err } - return &Store{tree: tree}, nil + return &Store{ + tree: tree, + pruning: pruning, + }, nil } // UnsafeNewStore returns a reference to a new IAVL Store with a given mutable -// IAVL tree reference. +// IAVL tree reference. It should only be used for testing purposes. // // CONTRACT: The IAVL tree should be fully loaded. -func UnsafeNewStore(tree *iavl.MutableTree) *Store { - return &Store{tree: tree} +// CONTRACT: PruningOptions passed in as argument must be the same as pruning options +// passed into iavl.MutableTree +func UnsafeNewStore(tree *iavl.MutableTree, po types.PruningOptions) *Store { + return &Store{ + tree: tree, + pruning: po, + } } // GetImmutable returns a reference to a new store backed by an immutable IAVL @@ -82,18 +112,36 @@ func (st *Store) GetImmutable(version int64) (*Store, error) { return nil, err } - return &Store{tree: &immutableTree{iTree}}, nil + return &Store{ + tree: &immutableTree{iTree}, + pruning: st.pruning, + }, nil } -// Implements Committer. +// Commit commits the current store state and returns a CommitID with the new +// version and hash. func (st *Store) Commit() types.CommitID { - // Save a new version. hash, version, err := st.tree.SaveVersion() if err != nil { // TODO: Do we want to extend Commit to allow returning errors? panic(err) } + // If the version we saved got flushed to disk, check if previous flushed + // version should be deleted. + if st.pruning.FlushVersion(version) { + previous := version - st.pruning.KeepEvery + + // Previous flushed version should only be pruned if the previous version is + // not a snapshot version OR if snapshotting is disabled (SnapshotEvery == 0). + if previous != 0 && !st.pruning.SnapshotVersion(previous) { + err := st.tree.DeleteVersion(previous) + if errCause := errors.Cause(err); errCause != nil && errCause != iavl.ErrVersionDoesNotExist { + panic(err) + } + } + } + return types.CommitID{ Version: version, Hash: hash, diff --git a/store/iavl/store_test.go b/store/iavl/store_test.go index 8f47286e4cb5..ed138c84964f 100644 --- a/store/iavl/store_test.go +++ b/store/iavl/store_test.go @@ -52,7 +52,7 @@ func newAlohaTree(t *testing.T, db dbm.DB) (*iavl.MutableTree, types.CommitID) { func TestGetImmutable(t *testing.T) { db := dbm.NewMemDB() tree, cID := newAlohaTree(t, db) - store := UnsafeNewStore(tree) + store := UnsafeNewStore(tree, types.PruneNothing) require.True(t, tree.Set([]byte("hello"), []byte("adios"))) hash, ver, err := tree.SaveVersion() @@ -82,7 +82,7 @@ func TestGetImmutable(t *testing.T) { func TestTestGetImmutableIterator(t *testing.T) { db := dbm.NewMemDB() tree, cID := newAlohaTree(t, db) - store := UnsafeNewStore(tree) + store := UnsafeNewStore(tree, types.PruneNothing) newStore, err := store.GetImmutable(cID.Version) require.NoError(t, err) @@ -105,7 +105,7 @@ func TestTestGetImmutableIterator(t *testing.T) { func TestIAVLStoreGetSetHasDelete(t *testing.T) { db := dbm.NewMemDB() tree, _ := newAlohaTree(t, db) - iavlStore := UnsafeNewStore(tree) + iavlStore := UnsafeNewStore(tree, types.PruneNothing) key := "hello" @@ -130,14 +130,14 @@ func TestIAVLStoreGetSetHasDelete(t *testing.T) { func TestIAVLStoreNoNilSet(t *testing.T) { db := dbm.NewMemDB() tree, _ := newAlohaTree(t, db) - iavlStore := UnsafeNewStore(tree) + iavlStore := UnsafeNewStore(tree, types.PruneNothing) require.Panics(t, func() { iavlStore.Set([]byte("key"), nil) }, "setting a nil value should panic") } func TestIAVLIterator(t *testing.T) { db := dbm.NewMemDB() tree, _ := newAlohaTree(t, db) - iavlStore := UnsafeNewStore(tree) + iavlStore := UnsafeNewStore(tree, types.PruneNothing) iter := iavlStore.Iterator([]byte("aloha"), []byte("hellz")) expected := []string{"aloha", "hello"} var i int @@ -213,7 +213,7 @@ func TestIAVLReverseIterator(t *testing.T) { tree, err := iavl.NewMutableTree(db, cacheSize) require.NoError(t, err) - iavlStore := UnsafeNewStore(tree) + iavlStore := UnsafeNewStore(tree, types.PruneNothing) iavlStore.Set([]byte{0x00}, []byte("0")) iavlStore.Set([]byte{0x00, 0x00}, []byte("0 0")) @@ -246,7 +246,7 @@ func TestIAVLPrefixIterator(t *testing.T) { tree, err := iavl.NewMutableTree(db, cacheSize) require.NoError(t, err) - iavlStore := UnsafeNewStore(tree) + iavlStore := UnsafeNewStore(tree, types.PruneNothing) iavlStore.Set([]byte("test1"), []byte("test1")) iavlStore.Set([]byte("test2"), []byte("test2")) @@ -310,7 +310,7 @@ func TestIAVLReversePrefixIterator(t *testing.T) { tree, err := iavl.NewMutableTree(db, cacheSize) require.NoError(t, err) - iavlStore := UnsafeNewStore(tree) + iavlStore := UnsafeNewStore(tree, types.PruneNothing) iavlStore.Set([]byte("test1"), []byte("test1")) iavlStore.Set([]byte("test2"), []byte("test2")) @@ -375,7 +375,7 @@ func nextVersion(iavl *Store) { func TestIAVLDefaultPruning(t *testing.T) { //Expected stored / deleted version numbers for: - //numRecent = 5, storeEvery = 3 + //numRecent = 5, storeEvery = 3, snapshotEvery = 5 var states = []pruneState{ {[]int64{}, []int64{}}, {[]int64{1}, []int64{}}, @@ -383,23 +383,23 @@ func TestIAVLDefaultPruning(t *testing.T) { {[]int64{1, 2, 3}, []int64{}}, {[]int64{1, 2, 3, 4}, []int64{}}, {[]int64{1, 2, 3, 4, 5}, []int64{}}, - {[]int64{2, 3, 4, 5, 6}, []int64{1}}, - {[]int64{3, 4, 5, 6, 7}, []int64{1, 2}}, - {[]int64{3, 4, 5, 6, 7, 8}, []int64{1, 2}}, - {[]int64{3, 5, 6, 7, 8, 9}, []int64{1, 2, 4}}, - {[]int64{3, 6, 7, 8, 9, 10}, []int64{1, 2, 4, 5}}, - {[]int64{3, 6, 7, 8, 9, 10, 11}, []int64{1, 2, 4, 5}}, - {[]int64{3, 6, 8, 9, 10, 11, 12}, []int64{1, 2, 4, 5, 7}}, - {[]int64{3, 6, 9, 10, 11, 12, 13}, []int64{1, 2, 4, 5, 7, 8}}, - {[]int64{3, 6, 9, 10, 11, 12, 13, 14}, []int64{1, 2, 4, 5, 7, 8}}, - {[]int64{3, 6, 9, 11, 12, 13, 14, 15}, []int64{1, 2, 4, 5, 7, 8, 10}}, - } - testPruning(t, int64(5), int64(3), states) + {[]int64{2, 4, 5, 6}, []int64{1, 3}}, + {[]int64{4, 5, 6, 7}, []int64{1, 2, 3}}, + {[]int64{4, 5, 6, 7, 8}, []int64{1, 2, 3}}, + {[]int64{5, 6, 7, 8, 9}, []int64{1, 2, 3, 4}}, + {[]int64{6, 7, 8, 9, 10}, []int64{1, 2, 3, 4, 5}}, + {[]int64{6, 7, 8, 9, 10, 11}, []int64{1, 2, 3, 4, 5}}, + {[]int64{6, 8, 10, 11, 12}, []int64{1, 2, 3, 4, 5, 7, 9}}, + {[]int64{6, 10, 11, 12, 13}, []int64{1, 2, 3, 4, 5, 7, 8, 9}}, + {[]int64{6, 10, 11, 12, 13, 14}, []int64{1, 2, 3, 4, 5, 7, 8, 9}}, + {[]int64{6, 11, 12, 13, 14, 15}, []int64{1, 2, 3, 4, 5, 7, 8, 9, 10}}, + } + testPruning(t, int64(5), int64(3), int64(6), states) } func TestIAVLAlternativePruning(t *testing.T) { //Expected stored / deleted version numbers for: - //numRecent = 3, storeEvery = 5 + //numRecent = 3, storeEvery = 5, snapshotEvery = 10 var states = []pruneState{ {[]int64{}, []int64{}}, {[]int64{1}, []int64{}}, @@ -411,14 +411,14 @@ func TestIAVLAlternativePruning(t *testing.T) { {[]int64{5, 6, 7}, []int64{1, 2, 3, 4}}, {[]int64{5, 6, 7, 8}, []int64{1, 2, 3, 4}}, {[]int64{5, 7, 8, 9}, []int64{1, 2, 3, 4, 6}}, - {[]int64{5, 8, 9, 10}, []int64{1, 2, 3, 4, 6, 7}}, - {[]int64{5, 9, 10, 11}, []int64{1, 2, 3, 4, 6, 7, 8}}, - {[]int64{5, 10, 11, 12}, []int64{1, 2, 3, 4, 6, 7, 8, 9}}, - {[]int64{5, 10, 11, 12, 13}, []int64{1, 2, 3, 4, 6, 7, 8, 9}}, - {[]int64{5, 10, 12, 13, 14}, []int64{1, 2, 3, 4, 6, 7, 8, 9, 11}}, - {[]int64{5, 10, 13, 14, 15}, []int64{1, 2, 3, 4, 6, 7, 8, 9, 11, 12}}, - } - testPruning(t, int64(3), int64(5), states) + {[]int64{8, 9, 10}, []int64{1, 2, 3, 4, 6, 7}}, + {[]int64{9, 10, 11}, []int64{1, 2, 3, 4, 6, 7, 8}}, + {[]int64{10, 11, 12}, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9}}, + {[]int64{10, 11, 12, 13}, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9}}, + {[]int64{10, 12, 13, 14}, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 11}}, + {[]int64{10, 13, 14, 15}, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12}}, + } + testPruning(t, int64(3), int64(5), int64(10), states) } type pruneState struct { @@ -426,26 +426,30 @@ type pruneState struct { deleted []int64 } -func testPruning(t *testing.T, numRecent int64, storeEvery int64, states []pruneState) { +func testPruning(t *testing.T, numRecent int64, storeEvery int64, snapshotEvery int64, states []pruneState) { db := dbm.NewMemDB() + pruningOpts := types.PruningOptions{ + KeepEvery: storeEvery, + SnapshotEvery: snapshotEvery, + } iavlOpts := iavl.PruningOptions(storeEvery, numRecent) tree, err := iavl.NewMutableTreeWithOpts(db, dbm.NewMemDB(), cacheSize, iavlOpts) require.NoError(t, err) - iavlStore := UnsafeNewStore(tree) + iavlStore := UnsafeNewStore(tree, pruningOpts) for step, state := range states { for _, ver := range state.stored { require.True(t, iavlStore.VersionExists(ver), - "missing version %d with latest version %d; should save last %d and every %d", - ver, step, numRecent, storeEvery) + "missing version %d with latest version %d; should save last %d, store every %d, and snapshot every %d", + ver, step, numRecent, storeEvery, snapshotEvery) } for _, ver := range state.deleted { require.False(t, iavlStore.VersionExists(ver), - "not pruned version %d with latest version %d; should prune all but last %d and every %d", - ver, step, numRecent, storeEvery) + "not pruned version %d with latest version %d; should prune all but last %d and every %d with intermediate flush interval %d", + ver, step, numRecent, snapshotEvery, storeEvery) } nextVersion(iavlStore) @@ -457,7 +461,7 @@ func TestIAVLNoPrune(t *testing.T) { tree, err := iavl.NewMutableTree(db, cacheSize) require.NoError(t, err) - iavlStore := UnsafeNewStore(tree) + iavlStore := UnsafeNewStore(tree, types.PruneNothing) nextVersion(iavlStore) for i := 1; i < 100; i++ { @@ -478,7 +482,7 @@ func TestIAVLPruneEverything(t *testing.T) { tree, err := iavl.NewMutableTreeWithOpts(db, dbm.NewMemDB(), cacheSize, iavlOpts) require.NoError(t, err) - iavlStore := UnsafeNewStore(tree) + iavlStore := UnsafeNewStore(tree, types.PruneEverything) nextVersion(iavlStore) for i := 1; i < 100; i++ { @@ -501,7 +505,7 @@ func TestIAVLStoreQuery(t *testing.T) { tree, err := iavl.NewMutableTree(db, cacheSize) require.NoError(t, err) - iavlStore := UnsafeNewStore(tree) + iavlStore := UnsafeNewStore(tree, types.PruneNothing) k1, v1 := []byte("key1"), []byte("val1") k2, v2 := []byte("key2"), []byte("val2") @@ -600,7 +604,7 @@ func BenchmarkIAVLIteratorNext(b *testing.B) { tree.Set(key, value) } - iavlStore := UnsafeNewStore(tree) + iavlStore := UnsafeNewStore(tree, types.PruneNothing) iterators := make([]types.Iterator, b.N/treeSize) for i := 0; i < len(iterators); i++ { diff --git a/store/prefix/store_test.go b/store/prefix/store_test.go index b5e99329055b..40540f44571d 100644 --- a/store/prefix/store_test.go +++ b/store/prefix/store_test.go @@ -88,7 +88,7 @@ func TestIAVLStorePrefix(t *testing.T) { db := dbm.NewMemDB() tree, err := tiavl.NewMutableTree(db, cacheSize) require.NoError(t, err) - iavlStore := iavl.UnsafeNewStore(tree) + iavlStore := iavl.UnsafeNewStore(tree, types.PruneNothing) testPrefixStore(t, iavlStore, []byte("test")) } diff --git a/store/rootmulti/store.go b/store/rootmulti/store.go index 5239ab8a4e15..42c7b05ab589 100644 --- a/store/rootmulti/store.go +++ b/store/rootmulti/store.go @@ -28,13 +28,13 @@ const ( // cacheMultiStore which is for cache-wrapping other MultiStores. It implements // the CommitMultiStore interface. type Store struct { - db dbm.DB - lastCommitID types.CommitID - pruningOpts types.PruningOptions - storesParams map[types.StoreKey]storeParams - stores map[types.StoreKey]types.CommitKVStore - keysByName map[string]types.StoreKey - lazyLoading bool + db dbm.DB + lastCommitInfo commitInfo + pruningOpts types.PruningOptions + storesParams map[types.StoreKey]storeParams + stores map[types.StoreKey]types.CommitKVStore + keysByName map[string]types.StoreKey + lazyLoading bool traceWriter io.Writer traceContext types.TraceContext @@ -146,11 +146,12 @@ func (rs *Store) LoadVersion(ver int64) error { func (rs *Store) loadVersion(ver int64, upgrades *types.StoreUpgrades) error { infos := make(map[string]storeInfo) - var lastCommitID types.CommitID + var cInfo commitInfo // load old data if we are not version 0 if ver != 0 { - cInfo, err := getCommitInfo(rs.db, ver) + var err error + cInfo, err = getCommitInfo(rs.db, ver) if err != nil { return err } @@ -159,7 +160,6 @@ func (rs *Store) loadVersion(ver int64, upgrades *types.StoreUpgrades) error { for _, storeInfo := range cInfo.StoreInfos { infos[storeInfo.Name] = storeInfo } - lastCommitID = cInfo.CommitID() } // load each Store (note this doesn't panic on unmounted keys now) @@ -197,7 +197,7 @@ func (rs *Store) loadVersion(ver int64, upgrades *types.StoreUpgrades) error { } } - rs.lastCommitID = lastCommitID + rs.lastCommitInfo = cInfo rs.stores = newStores return nil @@ -281,29 +281,26 @@ func (rs *Store) TracingEnabled() bool { // Implements Committer/CommitStore. func (rs *Store) LastCommitID() types.CommitID { - return rs.lastCommitID + return rs.lastCommitInfo.CommitID() } // Implements Committer/CommitStore. func (rs *Store) Commit() types.CommitID { // Commit stores. - version := rs.lastCommitID.Version + 1 - commitInfo := commitStores(version, rs.stores) + version := rs.lastCommitInfo.Version + 1 + rs.lastCommitInfo = commitStores(version, rs.stores) - // Need to update atomically. - batch := rs.db.NewBatch() - defer batch.Close() - setCommitInfo(batch, version, commitInfo) - setLatestVersion(batch, version) - batch.Write() + // write CommitInfo to disk only if this version was flushed to disk + if rs.pruningOpts.FlushVersion(version) { + flushCommitInfo(rs.db, version, rs.lastCommitInfo) + } // Prepare for next version. commitID := types.CommitID{ Version: version, - Hash: commitInfo.Hash(), + Hash: rs.lastCommitInfo.Hash(), } - rs.lastCommitID = commitID return commitID } @@ -412,7 +409,6 @@ func (rs *Store) getStoreByName(name string) types.Store { // Ie. `req.Path` here is `//`, and trimmed to `/` for the substore. // TODO: add proof for `multistore -> substore`. func (rs *Store) Query(req abci.RequestQuery) abci.ResponseQuery { - // Query just routes this to a substore. path := req.Path storeName, subpath, err := parsePath(path) if err != nil { @@ -441,9 +437,18 @@ func (rs *Store) Query(req abci.RequestQuery) abci.ResponseQuery { return sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "proof is unexpectedly empty; ensure height has not been pruned")) } - commitInfo, errMsg := getCommitInfo(rs.db, res.Height) - if errMsg != nil { - return sdkerrors.QueryResult(err) + // If the request's height is the latest height we've committed, then utilize + // the store's lastCommitInfo as this commit info may not be flushed to disk. + // Otherwise, we query for the commit info from disk. + var commitInfo commitInfo + + if res.Height == rs.lastCommitInfo.Version { + commitInfo = rs.lastCommitInfo + } else { + commitInfo, err = getCommitInfo(rs.db, res.Height) + if err != nil { + return sdkerrors.QueryResult(err) + } } // Restore origin path and append proof op. @@ -626,26 +631,22 @@ func commitStores(version int64, storeMap map[types.StoreKey]types.CommitKVStore storeInfos := make([]storeInfo, 0, len(storeMap)) for key, store := range storeMap { - // Commit commitID := store.Commit() if store.GetStoreType() == types.StoreTypeTransient { continue } - // Record CommitID si := storeInfo{} si.Name = key.Name() si.Core.CommitID = commitID - // si.Core.StoreType = store.GetStoreType() storeInfos = append(storeInfos, si) } - ci := commitInfo{ + return commitInfo{ Version: version, StoreInfos: storeInfos, } - return ci } // Gets commitInfo from disk. @@ -676,3 +677,14 @@ func setCommitInfo(batch dbm.Batch, version int64, cInfo commitInfo) { cInfoKey := fmt.Sprintf(commitInfoKeyFmt, version) batch.Set([]byte(cInfoKey), cInfoBytes) } + +// flushCommitInfo flushes a commitInfo for given version to the DB. Note, this +// needs to happen atomically. +func flushCommitInfo(db dbm.DB, version int64, cInfo commitInfo) { + batch := db.NewBatch() + defer batch.Close() + + setCommitInfo(batch, version, cInfo) + setLatestVersion(batch, version) + batch.Write() +} diff --git a/store/rootmulti/store_test.go b/store/rootmulti/store_test.go index 56111436bd22..164f231a2ac2 100644 --- a/store/rootmulti/store_test.go +++ b/store/rootmulti/store_test.go @@ -1,6 +1,7 @@ package rootmulti import ( + "fmt" "testing" "github.com/stretchr/testify/require" @@ -53,7 +54,7 @@ func TestStoreMount(t *testing.T) { func TestCacheMultiStoreWithVersion(t *testing.T) { var db dbm.DB = dbm.NewMemDB() - ms := newMultiStoreWithMounts(db, types.PruneSyncable) + ms := newMultiStoreWithMounts(db, types.PruneNothing) err := ms.LoadLatestVersion() require.Nil(t, err) @@ -90,7 +91,7 @@ func TestCacheMultiStoreWithVersion(t *testing.T) { func TestHashStableWithEmptyCommit(t *testing.T) { var db dbm.DB = dbm.NewMemDB() - ms := newMultiStoreWithMounts(db, types.PruneSyncable) + ms := newMultiStoreWithMounts(db, types.PruneNothing) err := ms.LoadLatestVersion() require.Nil(t, err) @@ -114,7 +115,7 @@ func TestHashStableWithEmptyCommit(t *testing.T) { func TestMultistoreCommitLoad(t *testing.T) { var db dbm.DB = dbm.NewMemDB() - store := newMultiStoreWithMounts(db, types.PruneSyncable) + store := newMultiStoreWithMounts(db, types.PruneNothing) err := store.LoadLatestVersion() require.Nil(t, err) @@ -139,7 +140,7 @@ func TestMultistoreCommitLoad(t *testing.T) { } // Load the latest multistore again and check version. - store = newMultiStoreWithMounts(db, types.PruneSyncable) + store = newMultiStoreWithMounts(db, types.PruneNothing) err = store.LoadLatestVersion() require.Nil(t, err) commitID = getExpectedCommitID(store, nCommits) @@ -152,7 +153,7 @@ func TestMultistoreCommitLoad(t *testing.T) { // Load an older multistore and check version. ver := nCommits - 1 - store = newMultiStoreWithMounts(db, types.PruneSyncable) + store = newMultiStoreWithMounts(db, types.PruneNothing) err = store.LoadVersion(ver) require.Nil(t, err) commitID = getExpectedCommitID(store, ver) @@ -289,6 +290,88 @@ func TestParsePath(t *testing.T) { } +func TestMultiStoreRestart(t *testing.T) { + db := dbm.NewMemDB() + pruning := types.PruningOptions{ + KeepEvery: 3, + SnapshotEvery: 6, + } + multi := newMultiStoreWithMounts(db, pruning) + err := multi.LoadLatestVersion() + require.Nil(t, err) + + initCid := multi.LastCommitID() + + k, v := "wind", "blows" + k2, v2 := "water", "flows" + k3, v3 := "fire", "burns" + + for i := 1; i < 3; i++ { + // Set and commit data in one store. + store1 := multi.getStoreByName("store1").(types.KVStore) + store1.Set([]byte(k), []byte(fmt.Sprintf("%s:%d", v, i))) + + // ... and another. + store2 := multi.getStoreByName("store2").(types.KVStore) + store2.Set([]byte(k2), []byte(fmt.Sprintf("%s:%d", v2, i))) + + // ... and another. + store3 := multi.getStoreByName("store3").(types.KVStore) + store3.Set([]byte(k3), []byte(fmt.Sprintf("%s:%d", v3, i))) + + multi.Commit() + + cinfo, err := getCommitInfo(multi.db, int64(i)) + require.NotNil(t, err) + require.Equal(t, commitInfo{}, cinfo) + } + + // Set and commit data in one store. + store1 := multi.getStoreByName("store1").(types.KVStore) + store1.Set([]byte(k), []byte(fmt.Sprintf("%s:%d", v, 3))) + + // ... and another. + store2 := multi.getStoreByName("store2").(types.KVStore) + store2.Set([]byte(k2), []byte(fmt.Sprintf("%s:%d", v2, 3))) + + multi.Commit() + + flushedCinfo, err := getCommitInfo(multi.db, 3) + require.Nil(t, err) + require.NotEqual(t, initCid, flushedCinfo, "CID is different after flush to disk") + + // ... and another. + store3 := multi.getStoreByName("store3").(types.KVStore) + store3.Set([]byte(k3), []byte(fmt.Sprintf("%s:%d", v3, 3))) + + multi.Commit() + + postFlushCinfo, err := getCommitInfo(multi.db, 4) + require.NotNil(t, err) + require.Equal(t, commitInfo{}, postFlushCinfo, "Commit changed after in-memory commit") + + multi = newMultiStoreWithMounts(db, pruning) + err = multi.LoadLatestVersion() + require.Nil(t, err) + + reloadedCid := multi.LastCommitID() + require.Equal(t, flushedCinfo.CommitID(), reloadedCid, "Reloaded CID is not the same as last flushed CID") + + // Check that store1 and store2 retained date from 3rd commit + store1 = multi.getStoreByName("store1").(types.KVStore) + val := store1.Get([]byte(k)) + require.Equal(t, []byte(fmt.Sprintf("%s:%d", v, 3)), val, "Reloaded value not the same as last flushed value") + + store2 = multi.getStoreByName("store2").(types.KVStore) + val2 := store2.Get([]byte(k2)) + require.Equal(t, []byte(fmt.Sprintf("%s:%d", v2, 3)), val2, "Reloaded value not the same as last flushed value") + + // Check that store3 still has data from last commit even though update happened on 2nd commit + store3 = multi.getStoreByName("store3").(types.KVStore) + val3 := store3.Get([]byte(k3)) + require.Equal(t, []byte(fmt.Sprintf("%s:%d", v3, 2)), val3, "Reloaded value not the same as last flushed value") +} + func TestMultiStoreQuery(t *testing.T) { db := dbm.NewMemDB() multi := newMultiStoreWithMounts(db, types.PruneNothing) diff --git a/store/types/pruning.go b/store/types/pruning.go index cd4f19b61689..c540443521ff 100644 --- a/store/types/pruning.go +++ b/store/types/pruning.go @@ -1,35 +1,66 @@ package types -// PruningStrategy specifies how old states will be deleted over time where -// keepRecent can be used with keepEvery to create a pruning "strategy". +var ( + // PruneEverything defines a pruning strategy where all committed states will + // be deleted, persisting only the current state. + PruneEverything = PruningOptions{ + KeepEvery: 1, + SnapshotEvery: 0, + } + + // PruneNothing defines a pruning strategy where all committed states will be + // kept on disk, i.e. no states will be pruned. + PruneNothing = PruningOptions{ + KeepEvery: 1, + SnapshotEvery: 1, + } + + // PruneSyncable defines a pruning strategy where only those states not needed + // for state syncing will be pruned. It flushes every 100th state to disk and + // keeps every 10000th. + PruneSyncable = PruningOptions{ + KeepEvery: 100, + SnapshotEvery: 10000, + } +) + +// PruningOptions defines the specific pruning strategy every store in a multi-store +// will use when committing state, where keepEvery determines which committed +// heights are flushed to disk and snapshotEvery determines which of these heights +// are kept after pruning. type PruningOptions struct { - keepRecent int64 - keepEvery int64 + KeepEvery int64 + SnapshotEvery int64 } -func NewPruningOptions(keepRecent, keepEvery int64) PruningOptions { - return PruningOptions{ - keepRecent: keepRecent, - keepEvery: keepEvery, +// IsValid verifies if the pruning options are valid. It returns false if invalid +// and true otherwise. Pruning options are considered valid iff: +// +// - KeepEvery > 0 +// - SnapshotEvery >= 0 +// - SnapshotEvery % KeepEvery = 0 +func (po PruningOptions) IsValid() bool { + // must flush at positive block interval + if po.KeepEvery <= 0 { + return false + } + + // cannot snapshot negative intervals + if po.SnapshotEvery < 0 { + return false } -} -// How much recent state will be kept. Older state will be deleted. -func (po PruningOptions) KeepRecent() int64 { - return po.keepRecent + return po.SnapshotEvery%po.KeepEvery == 0 } -// Keeps every N stated, deleting others. -func (po PruningOptions) KeepEvery() int64 { - return po.keepEvery +// FlushVersion returns a boolean signaling if the provided version/height should +// be flushed to disk. +func (po PruningOptions) FlushVersion(ver int64) bool { + return po.KeepEvery != 0 && ver%po.KeepEvery == 0 } -// default pruning strategies -var ( - // PruneEverything means all saved states will be deleted, storing only the current state - PruneEverything = NewPruningOptions(1, 0) - // PruneNothing means all historic states will be saved, nothing will be deleted - PruneNothing = NewPruningOptions(0, 1) - // PruneSyncable means only those states not needed for state syncing will be deleted (keeps last 100 + every 10000th) - PruneSyncable = NewPruningOptions(100, 10000) -) +// SnapshotVersion returns a boolean signaling if the provided version/height +// should be snapshotted (kept on disk). +func (po PruningOptions) SnapshotVersion(ver int64) bool { + return po.SnapshotEvery != 0 && ver%po.SnapshotEvery == 0 +} From cd9b2d450b76bedc22d9e65ea445a1308ab3820c Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Thu, 6 Feb 2020 16:19:26 -0500 Subject: [PATCH 119/529] Merge PR #5622: Track proposal handler events on success --- CHANGELOG.md | 3 ++- x/gov/abci.go | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 745ed246ce78..fed89e850a14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -56,13 +56,14 @@ and provided directly the IAVL store. ### Bug Fixes +* (x/gov) [\#5622](https://github.com/cosmos/cosmos-sdk/pull/5622) Track any events emitted from a proposal's handler upon successful execution. * (types) [\#5579](https://github.com/cosmos/cosmos-sdk/pull/5579) The IAVL `Store#Commit` method has been refactored to delete a flushed version if it is not a snapshot version. The root multi-store now keeps track of `commitInfo` instead of `types.CommitID`. During `Commit` of the root multi-store, `lastCommitInfo` is updated from the saved state and is only flushed to disk if it is a snapshot version. During `Query` of the root multi-store, if the request height is the latest height, we'll use the store's `lastCommitInfo`. Otherwise, we fetch `commitInfo` from disk. * (x/bank) [\#5531](https://github.com/cosmos/cosmos-sdk/issues/5531) Added missing amount event to MsgMultiSend, emitted for each output. -* (client) [\#5618](https://github.com/cosmos/cosmos-sdk/pull/5618) Fix crash on the client when the verifier is not set. +* (client) [\#5618](https://github.com/cosmos/cosmos-sdk/pull/5618) Fix crash on the client when the verifier is not set. ### State Machine Breaking diff --git a/x/gov/abci.go b/x/gov/abci.go index 21db8f5cd2c2..fa990acbf0e9 100644 --- a/x/gov/abci.go +++ b/x/gov/abci.go @@ -60,6 +60,12 @@ func EndBlocker(ctx sdk.Context, keeper Keeper) { tagValue = types.AttributeValueProposalPassed logMsg = "passed" + // The cached context is created with a new EventManager. However, since + // the proposal handler execution was successful, we want to track/keep + // any events emitted, so we re-emit to "merge" the events into the + // original Context's EventManager. + ctx.EventManager().EmitEvents(cacheCtx.EventManager().Events()) + // write state to the underlying multi-store writeCache() } else { From c8a82aaba2c74aa69b0ebc31ff7052ffe18d65b3 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 7 Feb 2020 10:10:51 -0500 Subject: [PATCH 120/529] Merge PR #5624: Bump github.com/golang/protobuf from 1.3.2 to 1.3.3 --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 77bb6bda0ee1..94f6cbf8a978 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/cosmos/ledger-cosmos-go v0.11.1 github.com/gogo/protobuf v1.3.1 github.com/golang/mock v1.3.1-0.20190508161146-9fa652df1129 - github.com/golang/protobuf v1.3.2 + github.com/golang/protobuf v1.3.3 github.com/gorilla/mux v1.7.3 github.com/hashicorp/golang-lru v0.5.4 github.com/mattn/go-isatty v0.0.12 diff --git a/go.sum b/go.sum index 097236eff67f..c6ec163ba216 100644 --- a/go.sum +++ b/go.sum @@ -95,6 +95,8 @@ github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= From 605afd49eb3cbcfdbc9c0f28237b089850ebadde Mon Sep 17 00:00:00 2001 From: Marko Date: Fri, 7 Feb 2020 16:28:54 +0100 Subject: [PATCH 121/529] Merge PR #5625: docs: sentence about gas is not correct currently --- docs/basics/tx-lifecycle.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/basics/tx-lifecycle.md b/docs/basics/tx-lifecycle.md index 5d99c290e376..098b1507b341 100644 --- a/docs/basics/tx-lifecycle.md +++ b/docs/basics/tx-lifecycle.md @@ -210,9 +210,7 @@ wrong, a deferred function at the end appropriately errors or panics. If there are any failed state changes resulting from a `Tx` being invalid or `GasMeter` running out, the transaction processing terminates and any state changes are reverted. Invalid transactions in a -block proposal cause validator nodes to reject the block and vote for a `nil` block instead. If a -`Tx` is delivered successfully, any leftover gas is returned to the user and the transaction is -validated. +block proposal cause validator nodes to reject the block and vote for a `nil` block instead. ### Commit From dd2d1c2573a937baa462fd9be5c54422e0638d83 Mon Sep 17 00:00:00 2001 From: Gavin <13985253+gavinly@users.noreply.github.com> Date: Fri, 7 Feb 2020 11:15:55 -0500 Subject: [PATCH 122/529] Merge PR #5626: Update README.md --- x/staking/spec/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x/staking/spec/README.md b/x/staking/spec/README.md index 437790ce74e2..0005088ae837 100644 --- a/x/staking/spec/README.md +++ b/x/staking/spec/README.md @@ -15,8 +15,8 @@ in June 2016. The module enables Cosmos-SDK based blockchain to support an advanced Proof-of-Stake system. In this system, holders of the native staking token of -the chain can become validators and can delegate tokens to validator -validators, ultimately determining the effective validator set for the system. +the chain can become validators and can delegate tokens to validators, +ultimately determining the effective validator set for the system. This module will be used in the Cosmos Hub, the first Hub in the Cosmos network. From 6cbf634ad59ec50345317d44badd01cabd3773ad Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Fri, 7 Feb 2020 19:09:19 +0100 Subject: [PATCH 123/529] Merge PR #5620: Fix nil pointer deref in distribution tax/rewward validation helpers --- CHANGELOG.md | 3 ++- x/distribution/types/params.go | 9 ++++++++ x/distribution/types/params_test.go | 34 +++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 x/distribution/types/params_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index fed89e850a14..8e7e6b943f3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -63,7 +63,8 @@ of `types.CommitID`. During `Commit` of the root multi-store, `lastCommitInfo` i and is only flushed to disk if it is a snapshot version. During `Query` of the root multi-store, if the request height is the latest height, we'll use the store's `lastCommitInfo`. Otherwise, we fetch `commitInfo` from disk. * (x/bank) [\#5531](https://github.com/cosmos/cosmos-sdk/issues/5531) Added missing amount event to MsgMultiSend, emitted for each output. -* (client) [\#5618](https://github.com/cosmos/cosmos-sdk/pull/5618) Fix crash on the client when the verifier is not set. +* (client) [\#5618](https://github.com/cosmos/cosmos-sdk/pull/5618) Fix crash on the client when the verifier is not set. +* (x/distribution) [\#5620](https://github.com/cosmos/cosmos-sdk/pull/5620) Fix nil pointer deref in distribution tax/rewward validation helpers. ### State Machine Breaking diff --git a/x/distribution/types/params.go b/x/distribution/types/params.go index ac3387e9c48b..f4530dd81c3b 100644 --- a/x/distribution/types/params.go +++ b/x/distribution/types/params.go @@ -92,6 +92,9 @@ func validateCommunityTax(i interface{}) error { return fmt.Errorf("invalid parameter type: %T", i) } + if v.IsNil() { + return fmt.Errorf("community tax must be not nil") + } if v.IsNegative() { return fmt.Errorf("community tax must be positive: %s", v) } @@ -108,6 +111,9 @@ func validateBaseProposerReward(i interface{}) error { return fmt.Errorf("invalid parameter type: %T", i) } + if v.IsNil() { + return fmt.Errorf("base proposer reward must be not nil") + } if v.IsNegative() { return fmt.Errorf("base proposer reward must be positive: %s", v) } @@ -124,6 +130,9 @@ func validateBonusProposerReward(i interface{}) error { return fmt.Errorf("invalid parameter type: %T", i) } + if v.IsNil() { + return fmt.Errorf("bonus proposer reward must be not nil") + } if v.IsNegative() { return fmt.Errorf("bonus proposer reward must be positive: %s", v) } diff --git a/x/distribution/types/params_test.go b/x/distribution/types/params_test.go new file mode 100644 index 000000000000..143e2d30d77d --- /dev/null +++ b/x/distribution/types/params_test.go @@ -0,0 +1,34 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func Test_validateAuxFuncs(t *testing.T) { + type args struct { + i interface{} + } + tests := []struct { + name string + args args + wantErr bool + }{ + {"wrong type", args{10.5}, true}, + {"nil Int pointer", args{sdk.Dec{}}, true}, + {"negative", args{sdk.NewDec(-1)}, true}, + {"one dec", args{sdk.NewDec(1)}, false}, + {"two dec", args{sdk.NewDec(2)}, true}, + } + for _, tt := range tests { + tt = tt + t.Run(tt.name, func(t *testing.T) { + require.Equal(t, tt.wantErr, validateCommunityTax(tt.args.i) != nil) + require.Equal(t, tt.wantErr, validateBaseProposerReward(tt.args.i) != nil) + require.Equal(t, tt.wantErr, validateBonusProposerReward(tt.args.i) != nil) + }) + } +} From 7edd41439c1531361101d21ed68e65f112f8936e Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Mon, 10 Feb 2020 11:03:31 -0500 Subject: [PATCH 124/529] Merge PR #5629: Add v0.37.7 changelog entry --- CHANGELOG.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e7e6b943f3d..8860d40db16e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -331,6 +331,19 @@ to detail this new feature and how state transitions occur. * (x/gov) [\#5107](https://github.com/cosmos/cosmos-sdk/pull/5107) Sum validator operator's all voting power when tally votes * (rest) [\#5212](https://github.com/cosmos/cosmos-sdk/issues/5212) Fix pagination in the `/gov/proposals` handler. +## [v0.37.7] - 2020-02-10 + +### Improvements + +* (modules) [\#5597](https://github.com/cosmos/cosmos-sdk/pull/5597) Add `amount` event attribute to the `complete_unbonding` +and `complete_redelegation` events that reflect the total balances of the completed unbondings and redelegations +respectively. + +### Bug Fixes + +* (x/gov) [\#5622](https://github.com/cosmos/cosmos-sdk/pull/5622) Track any events emitted from a proposal's handler upon successful execution. +* (x/bank) [\#5531](https://github.com/cosmos/cosmos-sdk/issues/5531) Added missing amount event to MsgMultiSend, emitted for each output. + ## [v0.37.6] - 2020-01-21 ### Improvements @@ -2924,6 +2937,7 @@ BUG FIXES: [Unreleased]: https://github.com/cosmos/cosmos-sdk/compare/v0.38.0...HEAD [v0.38.0]: https://github.com/cosmos/cosmos-sdk/releases/tag/v0.38.0 +[v0.37.7]: https://github.com/cosmos/cosmos-sdk/releases/tag/v0.37.7 [v0.37.6]: https://github.com/cosmos/cosmos-sdk/releases/tag/v0.37.6 [v0.37.5]: https://github.com/cosmos/cosmos-sdk/releases/tag/v0.37.5 [v0.37.4]: https://github.com/cosmos/cosmos-sdk/releases/tag/v0.37.4 From e2d4b9de448d8105a05ddb06785662226f7ae092 Mon Sep 17 00:00:00 2001 From: Chad Barraford Date: Mon, 10 Feb 2020 15:32:17 -0500 Subject: [PATCH 125/529] Merge PR #5497: ensure non-nil gentxs --- CHANGELOG.md | 1 + x/genutil/types/genesis_state.go | 4 ++++ x/genutil/types/genesis_state_test.go | 14 ++++++++++++++ 3 files changed, 19 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8860d40db16e..12e798c23615 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -65,6 +65,7 @@ is the latest height, we'll use the store's `lastCommitInfo`. Otherwise, we fetc * (x/bank) [\#5531](https://github.com/cosmos/cosmos-sdk/issues/5531) Added missing amount event to MsgMultiSend, emitted for each output. * (client) [\#5618](https://github.com/cosmos/cosmos-sdk/pull/5618) Fix crash on the client when the verifier is not set. * (x/distribution) [\#5620](https://github.com/cosmos/cosmos-sdk/pull/5620) Fix nil pointer deref in distribution tax/rewward validation helpers. +* (genesis) [\#5086](https://github.com/cosmos/cosmos-sdk/issues/5086) Ensure `gentxs` are always an empty array instead of `nil` ### State Machine Breaking diff --git a/x/genutil/types/genesis_state.go b/x/genutil/types/genesis_state.go index 6c5c555482ee..453ecdedc9a4 100644 --- a/x/genutil/types/genesis_state.go +++ b/x/genutil/types/genesis_state.go @@ -20,6 +20,10 @@ type GenesisState struct { // NewGenesisState creates a new GenesisState object func NewGenesisState(genTxs []json.RawMessage) GenesisState { + // Ensure genTxs is never nil, https://github.com/cosmos/cosmos-sdk/issues/5086 + if len(genTxs) == 0 { + genTxs = make([]json.RawMessage, 0) + } return GenesisState{ GenTxs: genTxs, } diff --git a/x/genutil/types/genesis_state_test.go b/x/genutil/types/genesis_state_test.go index aed7cd7f311e..b82a89b98a13 100644 --- a/x/genutil/types/genesis_state_test.go +++ b/x/genutil/types/genesis_state_test.go @@ -1,8 +1,10 @@ package types import ( + "encoding/json" "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/crypto/ed25519" @@ -16,6 +18,18 @@ var ( pk2 = ed25519.GenPrivKey().PubKey() ) +func TestNetGenesisState(t *testing.T) { + gen := NewGenesisState(nil) + assert.NotNil(t, gen.GenTxs) // https://github.com/cosmos/cosmos-sdk/issues/5086 + + gen = NewGenesisState( + []json.RawMessage{ + []byte(`{"foo":"bar"}`), + }, + ) + assert.Equal(t, string(gen.GenTxs[0]), `{"foo":"bar"}`) +} + func TestValidateGenesisMultipleMessages(t *testing.T) { desc := stakingtypes.NewDescription("testname", "", "", "", "") From 61c9902aae4ddbb75399618804a30520f765006f Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 11 Feb 2020 08:57:45 -0500 Subject: [PATCH 126/529] Bump github.com/99designs/keyring from 1.1.3 to 1.1.4 (#5632) Bumps [github.com/99designs/keyring](https://github.com/99designs/keyring) from 1.1.3 to 1.1.4. - [Release notes](https://github.com/99designs/keyring/releases) - [Commits](https://github.com/99designs/keyring/compare/v1.1.3...v1.1.4) Signed-off-by: dependabot-preview[bot] --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 94f6cbf8a978..2c39c61e4c3d 100644 --- a/go.mod +++ b/go.mod @@ -1,7 +1,7 @@ module github.com/cosmos/cosmos-sdk require ( - github.com/99designs/keyring v1.1.3 + github.com/99designs/keyring v1.1.4 github.com/bartekn/go-bip39 v0.0.0-20171116152956-a05967ea095d github.com/bgentry/speakeasy v0.1.0 github.com/btcsuite/btcd v0.0.0-20190115013929-ed77733ec07d diff --git a/go.sum b/go.sum index c6ec163ba216..637ed80ce04b 100644 --- a/go.sum +++ b/go.sum @@ -3,6 +3,8 @@ github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMb github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4= github.com/99designs/keyring v1.1.3 h1:mEV3iyZWjkxQ7R8ia8GcG97vCX5zQQ7n4o8R2BylwQY= github.com/99designs/keyring v1.1.3/go.mod h1:657DQuMrBZRtuL/voxVyiyb6zpMehlm5vLB9Qwrv904= +github.com/99designs/keyring v1.1.4 h1:x0g0zQ9bQKgNsLo0XSXAy1H8Q1RG/td+5OXJt+Ci8b8= +github.com/99designs/keyring v1.1.4/go.mod h1:657DQuMrBZRtuL/voxVyiyb6zpMehlm5vLB9Qwrv904= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/ChainSafe/go-schnorrkel v0.0.0-20200102211924-4bcbc698314f h1:4O1om+UVU+Hfcihr1timk8YNXHxzZWgCo7ofnrZRApw= From 56c5868975250d52e17c6da5ffd9a64737db7c45 Mon Sep 17 00:00:00 2001 From: Marko Date: Tue, 11 Feb 2020 15:58:37 +0100 Subject: [PATCH 127/529] Merge PR #5610: proto: migrate x/distr to use hybrid codec --- CHANGELOG.md | 9 + Makefile | 23 +- contrib/devtools/Makefile | 2 +- simapp/app.go | 2 +- simapp/codec.go | 9 +- simapp/export.go | 3 +- .../proto/tendermint/abci/types/types.proto | 126 +- x/crisis/internal/types/codec.go | 29 +- x/crisis/internal/types/msgs.go | 7 - x/crisis/internal/types/types.pb.go | 435 +++ x/crisis/internal/types/types.proto | 13 + x/distribution/alias.go | 2 + x/distribution/genesis.go | 4 +- x/distribution/keeper/alias_functions.go | 2 +- x/distribution/keeper/allocation.go | 4 +- x/distribution/keeper/allocation_test.go | 34 +- x/distribution/keeper/delegation.go | 4 +- x/distribution/keeper/delegation_test.go | 18 +- x/distribution/keeper/hooks.go | 5 +- x/distribution/keeper/invariants.go | 6 +- x/distribution/keeper/keeper.go | 16 +- x/distribution/keeper/keeper_test.go | 11 +- x/distribution/keeper/querier.go | 8 +- x/distribution/keeper/querier_test.go | 14 +- x/distribution/keeper/store.go | 47 +- x/distribution/keeper/test_common.go | 2 +- x/distribution/keeper/validator.go | 4 +- x/distribution/simulation/decoder_test.go | 4 +- x/distribution/simulation/operations.go | 2 +- x/distribution/types/codec.go | 27 +- x/distribution/types/delegator.go | 13 - x/distribution/types/fee_pool.go | 5 - x/distribution/types/msg.go | 24 - x/distribution/types/params.go | 8 - x/distribution/types/proposal.go | 8 - x/distribution/types/types.pb.go | 3343 +++++++++++++++++ x/distribution/types/types.proto | 182 + x/distribution/types/validator.go | 53 +- 38 files changed, 4216 insertions(+), 292 deletions(-) create mode 100644 x/crisis/internal/types/types.pb.go create mode 100644 x/crisis/internal/types/types.proto create mode 100644 x/distribution/types/types.pb.go create mode 100644 x/distribution/types/types.proto diff --git a/CHANGELOG.md b/CHANGELOG.md index 12e798c23615..aff20cb2eb1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -83,6 +83,15 @@ for JSON encoding. * Every reference of `crypto.Pubkey` in context of a `Validator` is now of type string. `GetPubKeyFromBech32` must be used to get the `crypto.Pubkey`. * The `Keeper` constructor now takes a `codec.Marshaler` instead of a concrete Amino codec. This exact type provided is specified by `ModuleCdc`. +* (distr) [\#5610](https://github.com/cosmos/cosmos-sdk/pull/5610) Migrate the `x/distribution` module to use Protocol Buffer for state +serialization instead of Amino. The exact codec used is `codec.HybridCodec` which utilizes Protobuf for binary encoding and Amino +for JSON encoding. + * `ValidatorHistoricalRewards.ReferenceCount` is now of types `uint32` instead of `uint16`. + * `ValidatorSlashEvents` is now a struct with `slashevents`. + * `ValidatorOutstandingRewards` is now a struct with `rewards`. + * `ValidatorAccumulatedCommission` is now a struct with `commission`. + * The `Keeper` constructor now takes a `codec.Marshaler` instead of a concrete Amino codec. This exact type + provided is specified by `ModuleCdc`. ### Improvements diff --git a/Makefile b/Makefile index 2e5984dd3ad8..2cf897fe985a 100644 --- a/Makefile +++ b/Makefile @@ -238,4 +238,25 @@ proto-lint: proto-check-breaking: @buf check breaking --against-input '.git#branch=master' -.PHONY: proto-all proto-gen proto-lint proto-check-breaking +# Origin +# TODO: Update to the version of Tendermint that is being used in go.mod +version_branch = v0.33.0 +tendermint = https://raw.githubusercontent.com/tendermint/tendermint/$(version_branch) + +# Outputs +tmkv = third_party/proto/tendermint/libs/kv/types.proto +tmmerkle = third_party/proto/tendermint/crypto/merkle/merkle.proto +tmabci = third_party/proto/tendermint/abci/types/types.proto + +# You *only* need to run this to rebuild protobufs from the tendermint source +proto-update-tendermint: + @curl $(tendermint)/abci/types/types.proto > $(tmabci) + sed -i '' '8,9 s|github.com/tendermint|third_party/proto|g' $(tmabci) + sed -i '' '7 s|github.com/gogo/protobuf|third_party/proto|' $(tmabci) + @curl $(tendermint)/libs/kv/types.proto > $(tmkv) + sed -i '' 's|github.com/gogo/protobuf|third_party/proto|' $(tmkv) + @curl $(tendermint)/crypto/merkle/merkle.proto > $(tmmerkle) + sed -i '' '7 s|github.com/gogo/protobuf|third_party/proto|' $(tmmerkle) + + +.PHONY: proto-all proto-gen proto-lint proto-check-breaking proto-update-tendermint diff --git a/contrib/devtools/Makefile b/contrib/devtools/Makefile index 993d1b7b7436..51194db7789c 100644 --- a/contrib/devtools/Makefile +++ b/contrib/devtools/Makefile @@ -48,7 +48,7 @@ UNAME_M ?= $(shell uname -m) GOPATH ?= $(shell $(GO) env GOPATH) GITHUBDIR := $(GOPATH)$(FS)src$(FS)github.com -BUF_VERSION ?= 0.4.0 +BUF_VERSION ?= 0.7.0 TOOLS_DESTDIR ?= $(GOPATH)/bin STATIK = $(TOOLS_DESTDIR)/statik diff --git a/simapp/app.go b/simapp/app.go index 721c1ff6bd80..dff6ab5b9f18 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -179,7 +179,7 @@ func NewSimApp( app.SupplyKeeper, auth.FeeCollectorName, ) app.DistrKeeper = distr.NewKeeper( - app.cdc, keys[distr.StoreKey], app.subspaces[distr.ModuleName], app.BankKeeper, &stakingKeeper, + appCodec.Distribution, keys[distr.StoreKey], app.subspaces[distr.ModuleName], app.BankKeeper, &stakingKeeper, app.SupplyKeeper, auth.FeeCollectorName, app.ModuleAccountAddrs(), ) app.SlashingKeeper = slashing.NewKeeper( diff --git a/simapp/codec.go b/simapp/codec.go index 8f87e7e324b1..96b2d6a70a15 100644 --- a/simapp/codec.go +++ b/simapp/codec.go @@ -4,6 +4,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth/vesting" + distr "github.com/cosmos/cosmos-sdk/x/distribution" "github.com/cosmos/cosmos-sdk/x/staking" ) @@ -12,15 +13,17 @@ import ( type AppCodec struct { amino *codec.Codec - Staking *staking.Codec + Staking *staking.Codec + Distribution *distr.Codec } func NewAppCodec() *AppCodec { amino := MakeCodec() return &AppCodec{ - amino: amino, - Staking: staking.NewCodec(amino), + amino: amino, + Staking: staking.NewCodec(amino), + Distribution: distr.NewCodec(amino), } } diff --git a/simapp/export.go b/simapp/export.go index 01b1424032cf..39cf18586f10 100644 --- a/simapp/export.go +++ b/simapp/export.go @@ -87,9 +87,8 @@ func (app *SimApp) prepForZeroHeightGenesis(ctx sdk.Context, jailWhiteList []str // reinitialize all validators app.StakingKeeper.IterateValidators(ctx, func(_ int64, val exported.ValidatorI) (stop bool) { - // donate any unwithdrawn outstanding reward fraction tokens to the community pool - scraps := app.DistrKeeper.GetValidatorOutstandingRewards(ctx, val.GetOperator()) + scraps := app.DistrKeeper.GetValidatorOutstandingRewardsCoins(ctx, val.GetOperator()) feePool := app.DistrKeeper.GetFeePool(ctx) feePool.CommunityPool = feePool.CommunityPool.Add(scraps...) app.DistrKeeper.SetFeePool(ctx, feePool) diff --git a/third_party/proto/tendermint/abci/types/types.proto b/third_party/proto/tendermint/abci/types/types.proto index eff32d4c5322..6c65444b0755 100644 --- a/third_party/proto/tendermint/abci/types/types.proto +++ b/third_party/proto/tendermint/abci/types/types.proto @@ -18,7 +18,6 @@ option (gogoproto.marshaler_all) = true; option (gogoproto.unmarshaler_all) = true; option (gogoproto.sizer_all) = true; option (gogoproto.goproto_registration) = true; - // Generate tests option (gogoproto.populate_all) = true; option (gogoproto.equal_all) = true; @@ -43,9 +42,12 @@ message Request { } } -message RequestEcho { string message = 1; } +message RequestEcho { + string message = 1; +} -message RequestFlush {} +message RequestFlush { +} message RequestInfo { string version = 1; @@ -60,11 +62,10 @@ message RequestSetOption { } message RequestInitChain { - google.protobuf.Timestamp time = 1 - [ (gogoproto.nullable) = false, (gogoproto.stdtime) = true ]; + google.protobuf.Timestamp time = 1 [(gogoproto.nullable)=false, (gogoproto.stdtime)=true]; string chain_id = 2; ConsensusParams consensus_params = 3; - repeated ValidatorUpdate validators = 4 [ (gogoproto.nullable) = false ]; + repeated ValidatorUpdate validators = 4 [(gogoproto.nullable)=false]; bytes app_state_bytes = 5; } @@ -77,9 +78,9 @@ message RequestQuery { message RequestBeginBlock { bytes hash = 1; - Header header = 2 [ (gogoproto.nullable) = false ]; - LastCommitInfo last_commit_info = 3 [ (gogoproto.nullable) = false ]; - repeated Evidence byzantine_validators = 4 [ (gogoproto.nullable) = false ]; + Header header = 2 [(gogoproto.nullable)=false]; + LastCommitInfo last_commit_info = 3 [(gogoproto.nullable)=false]; + repeated Evidence byzantine_validators = 4 [(gogoproto.nullable)=false]; } enum CheckTxType { @@ -92,11 +93,16 @@ message RequestCheckTx { CheckTxType type = 2; } -message RequestDeliverTx { bytes tx = 1; } +message RequestDeliverTx { + bytes tx = 1; +} -message RequestEndBlock { int64 height = 1; } +message RequestEndBlock { + int64 height = 1; +} -message RequestCommit {} +message RequestCommit { +} //---------------------------------------- // Response types @@ -119,11 +125,16 @@ message Response { } // nondeterministic -message ResponseException { string error = 1; } +message ResponseException { + string error = 1; +} -message ResponseEcho { string message = 1; } +message ResponseEcho { + string message = 1; +} -message ResponseFlush {} +message ResponseFlush { +} message ResponseInfo { string data = 1; @@ -145,13 +156,13 @@ message ResponseSetOption { message ResponseInitChain { ConsensusParams consensus_params = 1; - repeated ValidatorUpdate validators = 2 [ (gogoproto.nullable) = false ]; + repeated ValidatorUpdate validators = 2 [(gogoproto.nullable)=false]; } message ResponseQuery { uint32 code = 1; // bytes data = 2; // use "value" instead. - string log = 3; // nondeterministic + string log = 3; // nondeterministic string info = 4; // nondeterministic int64 index = 5; bytes key = 6; @@ -162,48 +173,35 @@ message ResponseQuery { } message ResponseBeginBlock { - repeated Event events = 1 [ - (gogoproto.nullable) = false, - (gogoproto.jsontag) = "events,omitempty" - ]; + repeated Event events = 1 [(gogoproto.nullable)=false, (gogoproto.jsontag)="events,omitempty"]; } message ResponseCheckTx { uint32 code = 1; bytes data = 2; - string log = 3; // nondeterministic + string log = 3; // nondeterministic string info = 4; // nondeterministic - int64 gas_wanted = 5; + int64 gas_wanted = 5; int64 gas_used = 6; - repeated Event events = 7 [ - (gogoproto.nullable) = false, - (gogoproto.jsontag) = "events,omitempty" - ]; + repeated Event events = 7 [(gogoproto.nullable)=false, (gogoproto.jsontag)="events,omitempty"]; string codespace = 8; } message ResponseDeliverTx { uint32 code = 1; bytes data = 2; - string log = 3; // nondeterministic + string log = 3; // nondeterministic string info = 4; // nondeterministic int64 gas_wanted = 5; int64 gas_used = 6; - repeated Event events = 7 [ - (gogoproto.nullable) = false, - (gogoproto.jsontag) = "events,omitempty" - ]; + repeated Event events = 7 [(gogoproto.nullable)=false, (gogoproto.jsontag)="events,omitempty"]; string codespace = 8; } message ResponseEndBlock { - repeated ValidatorUpdate validator_updates = 1 - [ (gogoproto.nullable) = false ]; + repeated ValidatorUpdate validator_updates = 1 [(gogoproto.nullable)=false]; ConsensusParams consensus_param_updates = 2; - repeated Event events = 3 [ - (gogoproto.nullable) = false, - (gogoproto.jsontag) = "events,omitempty" - ]; + repeated Event events = 3 [(gogoproto.nullable)=false, (gogoproto.jsontag)="events,omitempty"]; } message ResponseCommit { @@ -233,24 +231,22 @@ message BlockParams { message EvidenceParams { // Note: must be greater than 0 int64 max_age_num_blocks = 1; - google.protobuf.Duration max_age_duration = 2 - [ (gogoproto.nullable) = false, (gogoproto.stdduration) = true ]; + google.protobuf.Duration max_age_duration = 2 [(gogoproto.nullable)=false, (gogoproto.stdduration)=true]; } // ValidatorParams contains limits on validators. -message ValidatorParams { repeated string pub_key_types = 1; } +message ValidatorParams { + repeated string pub_key_types = 1; +} message LastCommitInfo { int32 round = 1; - repeated VoteInfo votes = 2 [ (gogoproto.nullable) = false ]; + repeated VoteInfo votes = 2 [(gogoproto.nullable)=false]; } message Event { string type = 1; - repeated tendermint.libs.kv.Pair attributes = 2 [ - (gogoproto.nullable) = false, - (gogoproto.jsontag) = "attributes,omitempty" - ]; + repeated tendermint.libs.kv.Pair attributes = 2 [(gogoproto.nullable)=false, (gogoproto.jsontag)="attributes,omitempty"]; } //---------------------------------------- @@ -258,26 +254,24 @@ message Event { message Header { // basic block info - Version version = 1 [ (gogoproto.nullable) = false ]; - string chain_id = 2 [ (gogoproto.customname) = "ChainID" ]; + Version version = 1 [(gogoproto.nullable)=false]; + string chain_id = 2 [(gogoproto.customname)="ChainID"]; int64 height = 3; - google.protobuf.Timestamp time = 4 - [ (gogoproto.nullable) = false, (gogoproto.stdtime) = true ]; + google.protobuf.Timestamp time = 4 [(gogoproto.nullable)=false, (gogoproto.stdtime)=true]; // prev block info - BlockID last_block_id = 5 [ (gogoproto.nullable) = false ]; + BlockID last_block_id = 5 [(gogoproto.nullable)=false]; // hashes of block data bytes last_commit_hash = 6; // commit from validators from the last block bytes data_hash = 7; // transactions // hashes from the app output from the prev block - bytes validators_hash = 8; // validators for the current block - bytes next_validators_hash = 9; // validators for the next block - bytes consensus_hash = 10; // consensus params for current block - bytes app_hash = 11; // state after txs from the previous block - bytes last_results_hash = - 12; // root hash of all results from the txs from the previous block + bytes validators_hash = 8; // validators for the current block + bytes next_validators_hash = 9; // validators for the next block + bytes consensus_hash = 10; // consensus params for current block + bytes app_hash = 11; // state after txs from the previous block + bytes last_results_hash = 12;// root hash of all results from the txs from the previous block // consensus info bytes evidence_hash = 13; // evidence included in the block @@ -289,9 +283,10 @@ message Version { uint64 App = 2; } + message BlockID { bytes hash = 1; - PartSetHeader parts_header = 2 [ (gogoproto.nullable) = false ]; + PartSetHeader parts_header = 2 [(gogoproto.nullable)=false]; } message PartSetHeader { @@ -302,33 +297,32 @@ message PartSetHeader { // Validator message Validator { bytes address = 1; - // PubKey pub_key = 2 [(gogoproto.nullable)=false]; + //PubKey pub_key = 2 [(gogoproto.nullable)=false]; int64 power = 3; } // ValidatorUpdate message ValidatorUpdate { - PubKey pub_key = 1 [ (gogoproto.nullable) = false ]; + PubKey pub_key = 1 [(gogoproto.nullable)=false]; int64 power = 2; } // VoteInfo message VoteInfo { - Validator validator = 1 [ (gogoproto.nullable) = false ]; + Validator validator = 1 [(gogoproto.nullable)=false]; bool signed_last_block = 2; } message PubKey { string type = 1; - bytes data = 2; + bytes data = 2; } message Evidence { string type = 1; - Validator validator = 2 [ (gogoproto.nullable) = false ]; + Validator validator = 2 [(gogoproto.nullable)=false]; int64 height = 3; - google.protobuf.Timestamp time = 4 - [ (gogoproto.nullable) = false, (gogoproto.stdtime) = true ]; + google.protobuf.Timestamp time = 4 [(gogoproto.nullable)=false, (gogoproto.stdtime)=true]; int64 total_voting_power = 5; } @@ -336,7 +330,7 @@ message Evidence { // Service Definition service ABCIApplication { - rpc Echo(RequestEcho) returns (ResponseEcho); + rpc Echo(RequestEcho) returns (ResponseEcho) ; rpc Flush(RequestFlush) returns (ResponseFlush); rpc Info(RequestInfo) returns (ResponseInfo); rpc SetOption(RequestSetOption) returns (ResponseSetOption); diff --git a/x/crisis/internal/types/codec.go b/x/crisis/internal/types/codec.go index 92aeb130bce8..fc9178eb386b 100644 --- a/x/crisis/internal/types/codec.go +++ b/x/crisis/internal/types/codec.go @@ -4,17 +4,32 @@ import ( "github.com/cosmos/cosmos-sdk/codec" ) -// Register concrete types on codec codec +type Codec struct { + codec.Marshaler + + // Keep reference to the amino codec to allow backwards compatibility along + // with type, and interface registration. + amino *codec.Codec +} + +func NewCodec(amino *codec.Codec) *Codec { + return &Codec{Marshaler: codec.NewHybridCodec(amino), amino: amino} +} + +// ---------------------------------------------------------------------------- + +// RegisterCodec registers all the necessary crisis module concrete types and +// interfaces with the provided codec reference. func RegisterCodec(cdc *codec.Codec) { cdc.RegisterConcrete(MsgVerifyInvariant{}, "cosmos-sdk/MsgVerifyInvariant", nil) } -// generic sealed codec to be used throughout module -var ModuleCdc *codec.Codec +// ModuleCdc defines a crisis module global Amino codec. +var ModuleCdc *Codec func init() { - ModuleCdc = codec.New() - RegisterCodec(ModuleCdc) - codec.RegisterCrypto(ModuleCdc) - ModuleCdc.Seal() + ModuleCdc = NewCodec(codec.New()) + RegisterCodec(ModuleCdc.amino) + codec.RegisterCrypto(ModuleCdc.amino) + ModuleCdc.amino.Seal() } diff --git a/x/crisis/internal/types/msgs.go b/x/crisis/internal/types/msgs.go index f496df636b60..49698c1ca943 100644 --- a/x/crisis/internal/types/msgs.go +++ b/x/crisis/internal/types/msgs.go @@ -4,13 +4,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -// MsgVerifyInvariant - message struct to verify a particular invariance -type MsgVerifyInvariant struct { - Sender sdk.AccAddress `json:"sender" yaml:"sender"` - InvariantModuleName string `json:"invariant_module_name" yaml:"invariant_module_name"` - InvariantRoute string `json:"invariant_route" yaml:"invariant_route"` -} - // ensure Msg interface compliance at compile time var _ sdk.Msg = &MsgVerifyInvariant{} diff --git a/x/crisis/internal/types/types.pb.go b/x/crisis/internal/types/types.pb.go new file mode 100644 index 000000000000..bf584c384409 --- /dev/null +++ b/x/crisis/internal/types/types.pb.go @@ -0,0 +1,435 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: x/crisis/internal/types/types.proto + +package types + +import ( + fmt "fmt" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// MsgVerifyInvariant - message struct to verify a particular invariance +type MsgVerifyInvariant struct { + Sender github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,1,opt,name=sender,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"sender,omitempty"` + InvariantModuleName string `protobuf:"bytes,2,opt,name=invariant_module_name,json=invariantModuleName,proto3" json:"invariant_module_name,omitempty" yaml:"invariant_module_name"` + InvariantRoute string `protobuf:"bytes,3,opt,name=invariant_route,json=invariantRoute,proto3" json:"invariant_route,omitempty" yaml:"invariant_route"` +} + +func (m *MsgVerifyInvariant) Reset() { *m = MsgVerifyInvariant{} } +func (m *MsgVerifyInvariant) String() string { return proto.CompactTextString(m) } +func (*MsgVerifyInvariant) ProtoMessage() {} +func (*MsgVerifyInvariant) Descriptor() ([]byte, []int) { + return fileDescriptor_df1c0b8e580cce76, []int{0} +} +func (m *MsgVerifyInvariant) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgVerifyInvariant) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgVerifyInvariant.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 *MsgVerifyInvariant) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgVerifyInvariant.Merge(m, src) +} +func (m *MsgVerifyInvariant) XXX_Size() int { + return m.Size() +} +func (m *MsgVerifyInvariant) XXX_DiscardUnknown() { + xxx_messageInfo_MsgVerifyInvariant.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgVerifyInvariant proto.InternalMessageInfo + +func (m *MsgVerifyInvariant) GetSender() github_com_cosmos_cosmos_sdk_types.AccAddress { + if m != nil { + return m.Sender + } + return nil +} + +func (m *MsgVerifyInvariant) GetInvariantModuleName() string { + if m != nil { + return m.InvariantModuleName + } + return "" +} + +func (m *MsgVerifyInvariant) GetInvariantRoute() string { + if m != nil { + return m.InvariantRoute + } + return "" +} + +func init() { + proto.RegisterType((*MsgVerifyInvariant)(nil), "cosmos_sdk.x.crisis.v1.MsgVerifyInvariant") +} + +func init() { + proto.RegisterFile("x/crisis/internal/types/types.proto", fileDescriptor_df1c0b8e580cce76) +} + +var fileDescriptor_df1c0b8e580cce76 = []byte{ + // 301 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x90, 0xcf, 0x4a, 0xfb, 0x30, + 0x00, 0x80, 0x97, 0xdf, 0x0f, 0x07, 0x16, 0x51, 0xa8, 0x38, 0xc6, 0x90, 0x74, 0x54, 0x90, 0x5d, + 0xd6, 0x30, 0xbc, 0x79, 0xdb, 0x3c, 0xed, 0x30, 0x0f, 0x45, 0x3c, 0x78, 0x29, 0x59, 0x13, 0xbb, + 0xb0, 0x25, 0x29, 0x49, 0x3a, 0xd6, 0xb7, 0xf0, 0xb1, 0x3c, 0xee, 0xe8, 0xa9, 0x48, 0xfb, 0x06, + 0x3b, 0xee, 0x24, 0xa6, 0x75, 0x03, 0xf1, 0x92, 0x84, 0x8f, 0x2f, 0x5f, 0xfe, 0x38, 0x37, 0x1b, + 0x14, 0x2b, 0xa6, 0x99, 0x46, 0x4c, 0x18, 0xaa, 0x04, 0x5e, 0x21, 0x93, 0xa7, 0x54, 0xd7, 0x63, + 0x90, 0x2a, 0x69, 0xa4, 0xdb, 0x89, 0xa5, 0xe6, 0x52, 0x47, 0x9a, 0x2c, 0x83, 0x4d, 0x50, 0xfb, + 0xc1, 0x7a, 0xd4, 0xbb, 0x35, 0x0b, 0xa6, 0x48, 0x94, 0x62, 0x65, 0x72, 0x64, 0x55, 0x94, 0xc8, + 0x44, 0x1e, 0x57, 0xf5, 0x7e, 0x7f, 0x0f, 0x1c, 0x77, 0xa6, 0x93, 0x67, 0xaa, 0xd8, 0x6b, 0x3e, + 0x15, 0x6b, 0xac, 0x18, 0x16, 0xc6, 0x9d, 0x3a, 0x6d, 0x4d, 0x05, 0xa1, 0xaa, 0x0b, 0xfa, 0x60, + 0x70, 0x36, 0x19, 0xed, 0x0b, 0x6f, 0x98, 0x30, 0xb3, 0xc8, 0xe6, 0x41, 0x2c, 0x39, 0xaa, 0x4f, + 0x6d, 0xa6, 0xa1, 0x26, 0xcb, 0xe6, 0x52, 0xe3, 0x38, 0x1e, 0x13, 0xa2, 0xa8, 0xd6, 0x61, 0x13, + 0x70, 0x9f, 0x9c, 0x2b, 0xf6, 0xd3, 0x8d, 0xb8, 0x24, 0xd9, 0x8a, 0x46, 0x02, 0x73, 0xda, 0xfd, + 0xd7, 0x07, 0x83, 0xd3, 0x49, 0x7f, 0x57, 0x78, 0xd7, 0x39, 0xe6, 0xab, 0x7b, 0xff, 0x4f, 0xcd, + 0x0f, 0x2f, 0x0f, 0x7c, 0x66, 0xf1, 0x23, 0xe6, 0xd4, 0x7d, 0x70, 0x2e, 0x8e, 0xba, 0x92, 0x99, + 0xa1, 0xdd, 0xff, 0xb6, 0xd7, 0xdb, 0x15, 0x5e, 0xe7, 0x77, 0xcf, 0x0a, 0x7e, 0x78, 0x7e, 0x20, + 0xe1, 0x37, 0x98, 0x78, 0xef, 0x25, 0x04, 0xdb, 0x12, 0x82, 0xcf, 0x12, 0x82, 0xb7, 0x0a, 0xb6, + 0xb6, 0x15, 0x6c, 0x7d, 0x54, 0xb0, 0xf5, 0x72, 0x62, 0x9f, 0x33, 0x6f, 0xdb, 0x4f, 0xba, 0xfb, + 0x0a, 0x00, 0x00, 0xff, 0xff, 0xa7, 0xed, 0x2c, 0x98, 0x8b, 0x01, 0x00, 0x00, +} + +func (m *MsgVerifyInvariant) 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 *MsgVerifyInvariant) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgVerifyInvariant) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.InvariantRoute) > 0 { + i -= len(m.InvariantRoute) + copy(dAtA[i:], m.InvariantRoute) + i = encodeVarintTypes(dAtA, i, uint64(len(m.InvariantRoute))) + i-- + dAtA[i] = 0x1a + } + if len(m.InvariantModuleName) > 0 { + i -= len(m.InvariantModuleName) + copy(dAtA[i:], m.InvariantModuleName) + i = encodeVarintTypes(dAtA, i, uint64(len(m.InvariantModuleName))) + i-- + dAtA[i] = 0x12 + } + if len(m.Sender) > 0 { + i -= len(m.Sender) + copy(dAtA[i:], m.Sender) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Sender))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintTypes(dAtA []byte, offset int, v uint64) int { + offset -= sovTypes(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgVerifyInvariant) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Sender) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.InvariantModuleName) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.InvariantRoute) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + +func sovTypes(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTypes(x uint64) (n int) { + return sovTypes(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *MsgVerifyInvariant) 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 ErrIntOverflowTypes + } + 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: MsgVerifyInvariant: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgVerifyInvariant: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Sender = append(m.Sender[:0], dAtA[iNdEx:postIndex]...) + if m.Sender == nil { + m.Sender = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InvariantModuleName", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.InvariantModuleName = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InvariantRoute", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.InvariantRoute = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTypes(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthTypes + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTypes + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTypes + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTypes = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTypes = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTypes = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/crisis/internal/types/types.proto b/x/crisis/internal/types/types.proto new file mode 100644 index 000000000000..64b4c5fc60e8 --- /dev/null +++ b/x/crisis/internal/types/types.proto @@ -0,0 +1,13 @@ +syntax = "proto3"; +package cosmos_sdk.x.crisis.v1; + +option go_package = "types"; + +import "third_party/proto/gogoproto/gogo.proto"; + +// MsgVerifyInvariant - message struct to verify a particular invariance +message MsgVerifyInvariant { + bytes sender = 1 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; + string invariant_module_name = 2 [(gogoproto.moretags) = "yaml:\"invariant_module_name\""]; + string invariant_route = 3 [(gogoproto.moretags) = "yaml:\"invariant_route\""]; +} diff --git a/x/distribution/alias.go b/x/distribution/alias.go index 47143d995cbb..ba16c5f47f28 100644 --- a/x/distribution/alias.go +++ b/x/distribution/alias.go @@ -111,6 +111,7 @@ var ( ParamStoreKeyBonusProposerReward = types.ParamStoreKeyBonusProposerReward ParamStoreKeyWithdrawAddrEnabled = types.ParamStoreKeyWithdrawAddrEnabled ModuleCdc = types.ModuleCdc + NewCodec = types.NewCodec EventTypeSetWithdrawAddress = types.EventTypeSetWithdrawAddress EventTypeRewards = types.EventTypeRewards EventTypeCommission = types.EventTypeCommission @@ -155,4 +156,5 @@ type ( ValidatorSlashEvent = types.ValidatorSlashEvent ValidatorSlashEvents = types.ValidatorSlashEvents ValidatorOutstandingRewards = types.ValidatorOutstandingRewards + Codec = types.Codec ) diff --git a/x/distribution/genesis.go b/x/distribution/genesis.go index 9e00aeba2b7c..2e05a85556f6 100644 --- a/x/distribution/genesis.go +++ b/x/distribution/genesis.go @@ -19,7 +19,7 @@ func InitGenesis(ctx sdk.Context, bk types.BankKeeper, supplyKeeper types.Supply } keeper.SetPreviousProposerConsAddr(ctx, data.PreviousProposer) for _, rew := range data.OutstandingRewards { - keeper.SetValidatorOutstandingRewards(ctx, rew.ValidatorAddress, rew.OutstandingRewards) + keeper.SetValidatorOutstandingRewards(ctx, rew.ValidatorAddress, types.ValidatorOutstandingRewards{Rewards: rew.OutstandingRewards}) moduleHoldings = moduleHoldings.Add(rew.OutstandingRewards...) } for _, acc := range data.ValidatorAccumulatedCommissions { @@ -76,7 +76,7 @@ func ExportGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState { func(addr sdk.ValAddress, rewards types.ValidatorOutstandingRewards) (stop bool) { outstanding = append(outstanding, types.ValidatorOutstandingRewardsRecord{ ValidatorAddress: addr, - OutstandingRewards: rewards, + OutstandingRewards: rewards.Rewards, }) return false }, diff --git a/x/distribution/keeper/alias_functions.go b/x/distribution/keeper/alias_functions.go index a02d2f2a0b4d..392881c7491b 100644 --- a/x/distribution/keeper/alias_functions.go +++ b/x/distribution/keeper/alias_functions.go @@ -8,7 +8,7 @@ import ( // get outstanding rewards func (k Keeper) GetValidatorOutstandingRewardsCoins(ctx sdk.Context, val sdk.ValAddress) sdk.DecCoins { - return k.GetValidatorOutstandingRewards(ctx, val) + return k.GetValidatorOutstandingRewards(ctx, val).Rewards } // get the community coins diff --git a/x/distribution/keeper/allocation.go b/x/distribution/keeper/allocation.go index 533aaac43858..385da6b00efd 100644 --- a/x/distribution/keeper/allocation.go +++ b/x/distribution/keeper/allocation.go @@ -114,7 +114,7 @@ func (k Keeper) AllocateTokensToValidator(ctx sdk.Context, val exported.Validato ), ) currentCommission := k.GetValidatorAccumulatedCommission(ctx, val.GetOperator()) - currentCommission = currentCommission.Add(commission...) + currentCommission.Commission = currentCommission.Commission.Add(commission...) k.SetValidatorAccumulatedCommission(ctx, val.GetOperator(), currentCommission) // update current rewards @@ -131,6 +131,6 @@ func (k Keeper) AllocateTokensToValidator(ctx sdk.Context, val exported.Validato ), ) outstanding := k.GetValidatorOutstandingRewards(ctx, val.GetOperator()) - outstanding = outstanding.Add(tokens...) + outstanding.Rewards = outstanding.Rewards.Add(tokens...) k.SetValidatorOutstandingRewards(ctx, val.GetOperator(), outstanding) } diff --git a/x/distribution/keeper/allocation_test.go b/x/distribution/keeper/allocation_test.go index 61513a02dca3..9628b74597fa 100644 --- a/x/distribution/keeper/allocation_test.go +++ b/x/distribution/keeper/allocation_test.go @@ -37,7 +37,7 @@ func TestAllocateTokensToValidatorWithCommission(t *testing.T) { expected := sdk.DecCoins{ {Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(5)}, } - require.Equal(t, expected, k.GetValidatorAccumulatedCommission(ctx, val.GetOperator())) + require.Equal(t, expected, k.GetValidatorAccumulatedCommission(ctx, val.GetOperator()).Commission) // check current rewards require.Equal(t, expected, k.GetValidatorCurrentRewards(ctx, val.GetOperator()).Rewards) @@ -75,11 +75,11 @@ func TestAllocateTokensToManyValidators(t *testing.T) { } // assert initial state: zero outstanding rewards, zero community pool, zero commission, zero current rewards - require.True(t, k.GetValidatorOutstandingRewards(ctx, valOpAddr1).IsZero()) - require.True(t, k.GetValidatorOutstandingRewards(ctx, valOpAddr2).IsZero()) + require.True(t, k.GetValidatorOutstandingRewards(ctx, valOpAddr1).Rewards.IsZero()) + require.True(t, k.GetValidatorOutstandingRewards(ctx, valOpAddr2).Rewards.IsZero()) require.True(t, k.GetFeePool(ctx).CommunityPool.IsZero()) - require.True(t, k.GetValidatorAccumulatedCommission(ctx, valOpAddr1).IsZero()) - require.True(t, k.GetValidatorAccumulatedCommission(ctx, valOpAddr2).IsZero()) + require.True(t, k.GetValidatorAccumulatedCommission(ctx, valOpAddr1).Commission.IsZero()) + require.True(t, k.GetValidatorAccumulatedCommission(ctx, valOpAddr2).Commission.IsZero()) require.True(t, k.GetValidatorCurrentRewards(ctx, valOpAddr1).Rewards.IsZero()) require.True(t, k.GetValidatorCurrentRewards(ctx, valOpAddr2).Rewards.IsZero()) @@ -105,14 +105,14 @@ func TestAllocateTokensToManyValidators(t *testing.T) { k.AllocateTokens(ctx, 200, 200, valConsAddr2, votes) // 98 outstanding rewards (100 less 2 to community pool) - require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecWithPrec(465, 1)}}, k.GetValidatorOutstandingRewards(ctx, valOpAddr1)) - require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecWithPrec(515, 1)}}, k.GetValidatorOutstandingRewards(ctx, valOpAddr2)) + require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecWithPrec(465, 1)}}, k.GetValidatorOutstandingRewards(ctx, valOpAddr1).Rewards) + require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecWithPrec(515, 1)}}, k.GetValidatorOutstandingRewards(ctx, valOpAddr2).Rewards) // 2 community pool coins require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(2)}}, k.GetFeePool(ctx).CommunityPool) // 50% commission for first proposer, (0.5 * 93%) * 100 / 2 = 23.25 - require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecWithPrec(2325, 2)}}, k.GetValidatorAccumulatedCommission(ctx, valOpAddr1)) + require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecWithPrec(2325, 2)}}, k.GetValidatorAccumulatedCommission(ctx, valOpAddr1).Commission) // zero commission for second proposer - require.True(t, k.GetValidatorAccumulatedCommission(ctx, valOpAddr2).IsZero()) + require.True(t, k.GetValidatorAccumulatedCommission(ctx, valOpAddr2).Commission.IsZero()) // just staking.proportional for first proposer less commission = (0.5 * 93%) * 100 / 2 = 23.25 require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecWithPrec(2325, 2)}}, k.GetValidatorCurrentRewards(ctx, valOpAddr1).Rewards) // proposer reward + staking.proportional for second proposer = (5 % + 0.5 * (93%)) * 100 = 51.5 @@ -162,12 +162,12 @@ func TestAllocateTokensTruncation(t *testing.T) { } // assert initial state: zero outstanding rewards, zero community pool, zero commission, zero current rewards - require.True(t, k.GetValidatorOutstandingRewards(ctx, valOpAddr1).IsZero()) - require.True(t, k.GetValidatorOutstandingRewards(ctx, valOpAddr2).IsZero()) - require.True(t, k.GetValidatorOutstandingRewards(ctx, valOpAddr3).IsZero()) + require.True(t, k.GetValidatorOutstandingRewards(ctx, valOpAddr1).Rewards.IsZero()) + require.True(t, k.GetValidatorOutstandingRewards(ctx, valOpAddr2).Rewards.IsZero()) + require.True(t, k.GetValidatorOutstandingRewards(ctx, valOpAddr3).Rewards.IsZero()) require.True(t, k.GetFeePool(ctx).CommunityPool.IsZero()) - require.True(t, k.GetValidatorAccumulatedCommission(ctx, valOpAddr1).IsZero()) - require.True(t, k.GetValidatorAccumulatedCommission(ctx, valOpAddr2).IsZero()) + require.True(t, k.GetValidatorAccumulatedCommission(ctx, valOpAddr1).Commission.IsZero()) + require.True(t, k.GetValidatorAccumulatedCommission(ctx, valOpAddr2).Commission.IsZero()) require.True(t, k.GetValidatorCurrentRewards(ctx, valOpAddr1).Rewards.IsZero()) require.True(t, k.GetValidatorCurrentRewards(ctx, valOpAddr2).Rewards.IsZero()) @@ -198,7 +198,7 @@ func TestAllocateTokensTruncation(t *testing.T) { } k.AllocateTokens(ctx, 31, 31, valConsAddr2, votes) - require.True(t, k.GetValidatorOutstandingRewards(ctx, valOpAddr1).IsValid()) - require.True(t, k.GetValidatorOutstandingRewards(ctx, valOpAddr2).IsValid()) - require.True(t, k.GetValidatorOutstandingRewards(ctx, valOpAddr3).IsValid()) + require.True(t, k.GetValidatorOutstandingRewards(ctx, valOpAddr1).Rewards.IsValid()) + require.True(t, k.GetValidatorOutstandingRewards(ctx, valOpAddr2).Rewards.IsValid()) + require.True(t, k.GetValidatorOutstandingRewards(ctx, valOpAddr3).Rewards.IsValid()) } diff --git a/x/distribution/keeper/delegation.go b/x/distribution/keeper/delegation.go index 7d79a35b40b9..48f474e5c570 100644 --- a/x/distribution/keeper/delegation.go +++ b/x/distribution/keeper/delegation.go @@ -145,7 +145,7 @@ func (k Keeper) withdrawDelegationRewards(ctx sdk.Context, val exported.Validato // end current period and calculate rewards endingPeriod := k.incrementValidatorPeriod(ctx, val) rewardsRaw := k.calculateDelegationRewards(ctx, val, del, endingPeriod) - outstanding := k.GetValidatorOutstandingRewards(ctx, del.GetValidatorAddr()) + outstanding := k.GetValidatorOutstandingRewardsCoins(ctx, del.GetValidatorAddr()) // defensive edge case may happen on the very final digits // of the decCoins due to operation order of the distribution mechanism. @@ -171,7 +171,7 @@ func (k Keeper) withdrawDelegationRewards(ctx sdk.Context, val exported.Validato // update the outstanding rewards and the community pool only if the // transaction was successful - k.SetValidatorOutstandingRewards(ctx, del.GetValidatorAddr(), outstanding.Sub(rewards)) + k.SetValidatorOutstandingRewards(ctx, del.GetValidatorAddr(), types.ValidatorOutstandingRewards{Rewards: outstanding.Sub(rewards)}) feePool := k.GetFeePool(ctx) feePool.CommunityPool = feePool.CommunityPool.Add(remainder...) k.SetFeePool(ctx, feePool) diff --git a/x/distribution/keeper/delegation_test.go b/x/distribution/keeper/delegation_test.go index 7f593fd5ecd6..a297eb5ba3a1 100644 --- a/x/distribution/keeper/delegation_test.go +++ b/x/distribution/keeper/delegation_test.go @@ -63,7 +63,7 @@ func TestCalculateRewardsBasic(t *testing.T) { require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(initial / 2)}}, rewards) // commission should be the other half - require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(initial / 2)}}, k.GetValidatorAccumulatedCommission(ctx, valOpAddr1)) + require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(initial / 2)}}, k.GetValidatorAccumulatedCommission(ctx, valOpAddr1).Commission) } func TestCalculateRewardsAfterSlash(t *testing.T) { @@ -128,7 +128,7 @@ func TestCalculateRewardsAfterSlash(t *testing.T) { // commission should be the other half require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial.QuoRaw(2).ToDec()}}, - k.GetValidatorAccumulatedCommission(ctx, valOpAddr1)) + k.GetValidatorAccumulatedCommission(ctx, valOpAddr1).Commission) } func TestCalculateRewardsAfterManySlashes(t *testing.T) { @@ -205,7 +205,7 @@ func TestCalculateRewardsAfterManySlashes(t *testing.T) { // commission should be the other half require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial.ToDec()}}, - k.GetValidatorAccumulatedCommission(ctx, valOpAddr1)) + k.GetValidatorAccumulatedCommission(ctx, valOpAddr1).Commission) } func TestCalculateRewardsMultiDelegator(t *testing.T) { @@ -273,7 +273,7 @@ func TestCalculateRewardsMultiDelegator(t *testing.T) { require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(initial * 1 / 4)}}, rewards) // commission should be equal to initial (50% twice) - require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(initial)}}, k.GetValidatorAccumulatedCommission(ctx, valOpAddr1)) + require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(initial)}}, k.GetValidatorAccumulatedCommission(ctx, valOpAddr1).Commission) } func TestWithdrawDelegationRewardsBasic(t *testing.T) { @@ -419,7 +419,7 @@ func TestCalculateRewardsAfterManySlashesInSameBlock(t *testing.T) { require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial}}, rewards) // commission should be the other half - require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial}}, k.GetValidatorAccumulatedCommission(ctx, valOpAddr1)) + require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial}}, k.GetValidatorAccumulatedCommission(ctx, valOpAddr1).Commission) } func TestCalculateRewardsMultiDelegatorMultiSlash(t *testing.T) { @@ -501,7 +501,7 @@ func TestCalculateRewardsMultiDelegatorMultiSlash(t *testing.T) { require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial.QuoInt64(3)}}, rewards) // commission should be equal to initial (twice 50% commission, unaffected by slashing) - require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial}}, k.GetValidatorAccumulatedCommission(ctx, valOpAddr1)) + require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial}}, k.GetValidatorAccumulatedCommission(ctx, valOpAddr1).Commission) } func TestCalculateRewardsMultiDelegatorMultWithdraw(t *testing.T) { @@ -592,7 +592,7 @@ func TestCalculateRewardsMultiDelegatorMultWithdraw(t *testing.T) { require.True(t, rewards.IsZero()) // commission should be zero - require.True(t, k.GetValidatorAccumulatedCommission(ctx, valOpAddr1).IsZero()) + require.True(t, k.GetValidatorAccumulatedCommission(ctx, valOpAddr1).Commission.IsZero()) // next block ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) @@ -619,7 +619,7 @@ func TestCalculateRewardsMultiDelegatorMultWithdraw(t *testing.T) { require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(initial / 4)}}, rewards) // commission should be half initial - require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(initial / 2)}}, k.GetValidatorAccumulatedCommission(ctx, valOpAddr1)) + require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(initial / 2)}}, k.GetValidatorAccumulatedCommission(ctx, valOpAddr1).Commission) // next block ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) @@ -646,5 +646,5 @@ func TestCalculateRewardsMultiDelegatorMultWithdraw(t *testing.T) { require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(initial / 2)}}, rewards) // commission should be zero - require.True(t, k.GetValidatorAccumulatedCommission(ctx, valOpAddr1).IsZero()) + require.True(t, k.GetValidatorAccumulatedCommission(ctx, valOpAddr1).Commission.IsZero()) } diff --git a/x/distribution/keeper/hooks.go b/x/distribution/keeper/hooks.go index e7f843dd2bd7..c68b5909f734 100644 --- a/x/distribution/keeper/hooks.go +++ b/x/distribution/keeper/hooks.go @@ -24,12 +24,11 @@ func (h Hooks) AfterValidatorCreated(ctx sdk.Context, valAddr sdk.ValAddress) { // cleanup for after validator is removed func (h Hooks) AfterValidatorRemoved(ctx sdk.Context, _ sdk.ConsAddress, valAddr sdk.ValAddress) { - // fetch outstanding - outstanding := h.k.GetValidatorOutstandingRewards(ctx, valAddr) + outstanding := h.k.GetValidatorOutstandingRewardsCoins(ctx, valAddr) // force-withdraw commission - commission := h.k.GetValidatorAccumulatedCommission(ctx, valAddr) + commission := h.k.GetValidatorAccumulatedCommission(ctx, valAddr).Commission if !commission.IsZero() { // subtract from outstanding outstanding = outstanding.Sub(commission) diff --git a/x/distribution/keeper/invariants.go b/x/distribution/keeper/invariants.go index cfafe1b11b27..45534b622e50 100644 --- a/x/distribution/keeper/invariants.go +++ b/x/distribution/keeper/invariants.go @@ -47,7 +47,7 @@ func NonNegativeOutstandingInvariant(k Keeper) sdk.Invariant { var outstanding sdk.DecCoins k.IterateValidatorOutstandingRewards(ctx, func(addr sdk.ValAddress, rewards types.ValidatorOutstandingRewards) (stop bool) { - outstanding = rewards + outstanding = rewards.GetRewards() if outstanding.IsAnyNegative() { count++ msg += fmt.Sprintf("\t%v has negative outstanding coins: %v\n", addr, outstanding) @@ -89,7 +89,7 @@ func CanWithdrawInvariant(k Keeper) sdk.Invariant { } } - remaining = k.GetValidatorOutstandingRewards(ctx, val.GetOperator()) + remaining = k.GetValidatorOutstandingRewardsCoins(ctx, val.GetOperator()) if len(remaining) > 0 && remaining[0].Amount.IsNegative() { return true } @@ -140,7 +140,7 @@ func ModuleAccountInvariant(k Keeper) sdk.Invariant { var expectedCoins sdk.DecCoins k.IterateValidatorOutstandingRewards(ctx, func(_ sdk.ValAddress, rewards types.ValidatorOutstandingRewards) (stop bool) { - expectedCoins = expectedCoins.Add(rewards...) + expectedCoins = expectedCoins.Add(rewards.Rewards...) return false }) diff --git a/x/distribution/keeper/keeper.go b/x/distribution/keeper/keeper.go index 5cce89d0c33f..0074f84042a6 100644 --- a/x/distribution/keeper/keeper.go +++ b/x/distribution/keeper/keeper.go @@ -15,7 +15,7 @@ import ( // Keeper of the distribution store type Keeper struct { storeKey sdk.StoreKey - cdc *codec.Codec + cdc codec.Marshaler paramSpace params.Subspace bankKeeper types.BankKeeper stakingKeeper types.StakingKeeper @@ -28,7 +28,7 @@ type Keeper struct { // NewKeeper creates a new distribution Keeper instance func NewKeeper( - cdc *codec.Codec, key sdk.StoreKey, paramSpace params.Subspace, bk types.BankKeeper, + cdc codec.Marshaler, key sdk.StoreKey, paramSpace params.Subspace, bk types.BankKeeper, sk types.StakingKeeper, supplyKeeper types.SupplyKeeper, feeCollectorName string, blacklistedAddrs map[string]bool, ) Keeper { @@ -116,16 +116,16 @@ func (k Keeper) WithdrawDelegationRewards(ctx sdk.Context, delAddr sdk.AccAddres func (k Keeper) WithdrawValidatorCommission(ctx sdk.Context, valAddr sdk.ValAddress) (sdk.Coins, error) { // fetch validator accumulated commission accumCommission := k.GetValidatorAccumulatedCommission(ctx, valAddr) - if accumCommission.IsZero() { + if accumCommission.Commission.IsZero() { return nil, types.ErrNoValidatorCommission } - commission, remainder := accumCommission.TruncateDecimal() - k.SetValidatorAccumulatedCommission(ctx, valAddr, remainder) // leave remainder to withdraw later + commission, remainder := accumCommission.Commission.TruncateDecimal() + k.SetValidatorAccumulatedCommission(ctx, valAddr, types.ValidatorAccumulatedCommission{Commission: remainder}) // leave remainder to withdraw later // update outstanding - outstanding := k.GetValidatorOutstandingRewards(ctx, valAddr) - k.SetValidatorOutstandingRewards(ctx, valAddr, outstanding.Sub(sdk.NewDecCoinsFromCoins(commission...))) + outstanding := k.GetValidatorOutstandingRewards(ctx, valAddr).Rewards + k.SetValidatorOutstandingRewards(ctx, valAddr, types.ValidatorOutstandingRewards{Rewards: outstanding.Sub(sdk.NewDecCoinsFromCoins(commission...))}) if !commission.IsZero() { accAddr := sdk.AccAddress(valAddr) @@ -150,7 +150,7 @@ func (k Keeper) WithdrawValidatorCommission(ctx sdk.Context, valAddr sdk.ValAddr func (k Keeper) GetTotalRewards(ctx sdk.Context) (totalRewards sdk.DecCoins) { k.IterateValidatorOutstandingRewards(ctx, func(_ sdk.ValAddress, rewards types.ValidatorOutstandingRewards) (stop bool) { - totalRewards = totalRewards.Add(rewards...) + totalRewards = totalRewards.Add(rewards.Rewards...) return false }, ) diff --git a/x/distribution/keeper/keeper_test.go b/x/distribution/keeper/keeper_test.go index 17d809becc91..f4846e61e2fa 100644 --- a/x/distribution/keeper/keeper_test.go +++ b/x/distribution/keeper/keeper_test.go @@ -8,6 +8,7 @@ import ( "github.com/stretchr/testify/require" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/distribution/types" ) func TestSetWithdrawAddr(t *testing.T) { @@ -53,10 +54,10 @@ func TestWithdrawValidatorCommission(t *testing.T) { require.Equal(t, expCoins, balance) // set outstanding rewards - keeper.SetValidatorOutstandingRewards(ctx, valOpAddr3, valCommission) + keeper.SetValidatorOutstandingRewards(ctx, valOpAddr3, types.ValidatorOutstandingRewards{Rewards: valCommission}) // set commission - keeper.SetValidatorAccumulatedCommission(ctx, valOpAddr3, valCommission) + keeper.SetValidatorAccumulatedCommission(ctx, valOpAddr3, types.ValidatorAccumulatedCommission{Commission: valCommission}) // withdraw commission keeper.WithdrawValidatorCommission(ctx, valOpAddr3) @@ -69,7 +70,7 @@ func TestWithdrawValidatorCommission(t *testing.T) { ), balance) // check remainder - remainder := keeper.GetValidatorAccumulatedCommission(ctx, valOpAddr3) + remainder := keeper.GetValidatorAccumulatedCommission(ctx, valOpAddr3).Commission require.Equal(t, sdk.DecCoins{ sdk.NewDecCoinFromDec("mytoken", sdk.NewDec(1).Quo(sdk.NewDec(4))), sdk.NewDecCoinFromDec("stake", sdk.NewDec(1).Quo(sdk.NewDec(2))), @@ -86,8 +87,8 @@ func TestGetTotalRewards(t *testing.T) { sdk.NewDecCoinFromDec("stake", sdk.NewDec(3).Quo(sdk.NewDec(2))), } - keeper.SetValidatorOutstandingRewards(ctx, valOpAddr1, valCommission) - keeper.SetValidatorOutstandingRewards(ctx, valOpAddr2, valCommission) + keeper.SetValidatorOutstandingRewards(ctx, valOpAddr1, types.ValidatorOutstandingRewards{Rewards: valCommission}) + keeper.SetValidatorOutstandingRewards(ctx, valOpAddr2, types.ValidatorOutstandingRewards{Rewards: valCommission}) expectedRewards := valCommission.MulDec(sdk.NewDec(2)) totalRewards := keeper.GetTotalRewards(ctx) diff --git a/x/distribution/keeper/querier.go b/x/distribution/keeper/querier.go index 4757ea5ffe3e..77d4c6520971 100644 --- a/x/distribution/keeper/querier.go +++ b/x/distribution/keeper/querier.go @@ -67,8 +67,8 @@ func queryValidatorOutstandingRewards(ctx sdk.Context, path []string, req abci.R } rewards := k.GetValidatorOutstandingRewards(ctx, params.ValidatorAddress) - if rewards == nil { - rewards = sdk.DecCoins{} + if rewards.GetRewards() == nil { + rewards.Rewards = sdk.DecCoins{} } bz, err := codec.MarshalJSONIndent(k.cdc, rewards) @@ -87,8 +87,8 @@ func queryValidatorCommission(ctx sdk.Context, path []string, req abci.RequestQu } commission := k.GetValidatorAccumulatedCommission(ctx, params.ValidatorAddress) - if commission == nil { - commission = sdk.DecCoins{} + if commission.Commission == nil { + commission.Commission = sdk.DecCoins{} } bz, err := codec.MarshalJSONIndent(k.cdc, commission) diff --git a/x/distribution/keeper/querier_test.go b/x/distribution/keeper/querier_test.go index ed87f42edd78..7d032a6ccd95 100644 --- a/x/distribution/keeper/querier_test.go +++ b/x/distribution/keeper/querier_test.go @@ -27,7 +27,7 @@ func getQueriedParams(t *testing.T, ctx sdk.Context, cdc *codec.Codec, querier s return params } -func getQueriedValidatorOutstandingRewards(t *testing.T, ctx sdk.Context, cdc *codec.Codec, querier sdk.Querier, validatorAddr sdk.ValAddress) (outstandingRewards sdk.DecCoins) { +func getQueriedValidatorOutstandingRewards(t *testing.T, ctx sdk.Context, cdc *codec.Codec, querier sdk.Querier, validatorAddr sdk.ValAddress) sdk.DecCoins { query := abci.RequestQuery{ Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryValidatorOutstandingRewards}, "/"), Data: cdc.MustMarshalJSON(types.NewQueryValidatorOutstandingRewardsParams(validatorAddr)), @@ -35,12 +35,13 @@ func getQueriedValidatorOutstandingRewards(t *testing.T, ctx sdk.Context, cdc *c bz, err := querier(ctx, []string{types.QueryValidatorOutstandingRewards}, query) require.Nil(t, err) + outstandingRewards := types.ValidatorOutstandingRewards{} require.Nil(t, cdc.UnmarshalJSON(bz, &outstandingRewards)) - return + return outstandingRewards.GetRewards() } -func getQueriedValidatorCommission(t *testing.T, ctx sdk.Context, cdc *codec.Codec, querier sdk.Querier, validatorAddr sdk.ValAddress) (validatorCommission sdk.DecCoins) { +func getQueriedValidatorCommission(t *testing.T, ctx sdk.Context, cdc *codec.Codec, querier sdk.Querier, validatorAddr sdk.ValAddress) sdk.DecCoins { query := abci.RequestQuery{ Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryValidatorCommission}, "/"), Data: cdc.MustMarshalJSON(types.NewQueryValidatorCommissionParams(validatorAddr)), @@ -48,9 +49,10 @@ func getQueriedValidatorCommission(t *testing.T, ctx sdk.Context, cdc *codec.Cod bz, err := querier(ctx, []string{types.QueryValidatorCommission}, query) require.Nil(t, err) + validatorCommission := types.ValidatorAccumulatedCommission{} require.Nil(t, cdc.UnmarshalJSON(bz, &validatorCommission)) - return + return validatorCommission.GetCommission() } func getQueriedValidatorSlashes(t *testing.T, ctx sdk.Context, cdc *codec.Codec, querier sdk.Querier, validatorAddr sdk.ValAddress, startHeight uint64, endHeight uint64) (slashes []types.ValidatorSlashEvent) { @@ -130,13 +132,13 @@ func TestQueries(t *testing.T) { // test outstanding rewards query outstandingRewards := sdk.DecCoins{{Denom: "mytoken", Amount: sdk.NewDec(3)}, {Denom: "myothertoken", Amount: sdk.NewDecWithPrec(3, 7)}} - keeper.SetValidatorOutstandingRewards(ctx, valOpAddr1, outstandingRewards) + keeper.SetValidatorOutstandingRewards(ctx, valOpAddr1, types.ValidatorOutstandingRewards{Rewards: outstandingRewards}) retOutstandingRewards := getQueriedValidatorOutstandingRewards(t, ctx, cdc, querier, valOpAddr1) require.Equal(t, outstandingRewards, retOutstandingRewards) // test validator commission query commission := sdk.DecCoins{{Denom: "token1", Amount: sdk.NewDec(4)}, {Denom: "token2", Amount: sdk.NewDec(2)}} - keeper.SetValidatorAccumulatedCommission(ctx, valOpAddr1, commission) + keeper.SetValidatorAccumulatedCommission(ctx, valOpAddr1, types.ValidatorAccumulatedCommission{Commission: commission}) retCommission := getQueriedValidatorCommission(t, ctx, cdc, querier, valOpAddr1) require.Equal(t, commission, retCommission) diff --git a/x/distribution/keeper/store.go b/x/distribution/keeper/store.go index e1a1c50d4343..ffdd807163ed 100644 --- a/x/distribution/keeper/store.go +++ b/x/distribution/keeper/store.go @@ -1,6 +1,8 @@ package keeper import ( + gogotypes "github.com/gogo/protobuf/types" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/distribution/types" ) @@ -55,26 +57,29 @@ func (k Keeper) GetFeePool(ctx sdk.Context) (feePool types.FeePool) { // set the global fee pool distribution info func (k Keeper) SetFeePool(ctx sdk.Context, feePool types.FeePool) { store := ctx.KVStore(k.storeKey) - b := k.cdc.MustMarshalBinaryLengthPrefixed(feePool) + b := k.cdc.MustMarshalBinaryLengthPrefixed(&feePool) store.Set(types.FeePoolKey, b) } -// get the proposer public key for this block -func (k Keeper) GetPreviousProposerConsAddr(ctx sdk.Context) (consAddr sdk.ConsAddress) { +// GetPreviousProposerConsAddr returns the proposer consensus address for the +// current block. +func (k Keeper) GetPreviousProposerConsAddr(ctx sdk.Context) sdk.ConsAddress { store := ctx.KVStore(k.storeKey) - b := store.Get(types.ProposerKey) - if b == nil { - panic("Previous proposer not set") + bz := store.Get(types.ProposerKey) + if bz == nil { + panic("previous proposer not set") } - k.cdc.MustUnmarshalBinaryLengthPrefixed(b, &consAddr) - return + + addrValue := gogotypes.BytesValue{} + k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &addrValue) + return sdk.ConsAddress(addrValue.GetValue()) } // set the proposer public key for this block func (k Keeper) SetPreviousProposerConsAddr(ctx sdk.Context, consAddr sdk.ConsAddress) { store := ctx.KVStore(k.storeKey) - b := k.cdc.MustMarshalBinaryLengthPrefixed(consAddr) - store.Set(types.ProposerKey, b) + bz := k.cdc.MustMarshalBinaryLengthPrefixed(&gogotypes.BytesValue{Value: consAddr}) + store.Set(types.ProposerKey, bz) } // get the starting info associated with a delegator @@ -88,7 +93,7 @@ func (k Keeper) GetDelegatorStartingInfo(ctx sdk.Context, val sdk.ValAddress, de // set the starting info associated with a delegator func (k Keeper) SetDelegatorStartingInfo(ctx sdk.Context, val sdk.ValAddress, del sdk.AccAddress, period types.DelegatorStartingInfo) { store := ctx.KVStore(k.storeKey) - b := k.cdc.MustMarshalBinaryLengthPrefixed(period) + b := k.cdc.MustMarshalBinaryLengthPrefixed(&period) store.Set(types.GetDelegatorStartingInfoKey(val, del), b) } @@ -130,7 +135,7 @@ func (k Keeper) GetValidatorHistoricalRewards(ctx sdk.Context, val sdk.ValAddres // set historical rewards for a particular period func (k Keeper) SetValidatorHistoricalRewards(ctx sdk.Context, val sdk.ValAddress, period uint64, rewards types.ValidatorHistoricalRewards) { store := ctx.KVStore(k.storeKey) - b := k.cdc.MustMarshalBinaryLengthPrefixed(rewards) + b := k.cdc.MustMarshalBinaryLengthPrefixed(&rewards) store.Set(types.GetValidatorHistoricalRewardsKey(val, period), b) } @@ -199,7 +204,7 @@ func (k Keeper) GetValidatorCurrentRewards(ctx sdk.Context, val sdk.ValAddress) // set current rewards for a validator func (k Keeper) SetValidatorCurrentRewards(ctx sdk.Context, val sdk.ValAddress, rewards types.ValidatorCurrentRewards) { store := ctx.KVStore(k.storeKey) - b := k.cdc.MustMarshalBinaryLengthPrefixed(rewards) + b := k.cdc.MustMarshalBinaryLengthPrefixed(&rewards) store.Set(types.GetValidatorCurrentRewardsKey(val), b) } @@ -240,10 +245,10 @@ func (k Keeper) SetValidatorAccumulatedCommission(ctx sdk.Context, val sdk.ValAd var bz []byte store := ctx.KVStore(k.storeKey) - if commission.IsZero() { - bz = k.cdc.MustMarshalBinaryLengthPrefixed(types.InitialValidatorAccumulatedCommission()) + if commission.Commission.IsZero() { + bz = k.cdc.MustMarshalBinaryLengthPrefixed(&types.ValidatorAccumulatedCommission{}) } else { - bz = k.cdc.MustMarshalBinaryLengthPrefixed(commission) + bz = k.cdc.MustMarshalBinaryLengthPrefixed(&commission) } store.Set(types.GetValidatorAccumulatedCommissionKey(val), bz) @@ -273,15 +278,15 @@ func (k Keeper) IterateValidatorAccumulatedCommissions(ctx sdk.Context, handler // get validator outstanding rewards func (k Keeper) GetValidatorOutstandingRewards(ctx sdk.Context, val sdk.ValAddress) (rewards types.ValidatorOutstandingRewards) { store := ctx.KVStore(k.storeKey) - b := store.Get(types.GetValidatorOutstandingRewardsKey(val)) - k.cdc.MustUnmarshalBinaryLengthPrefixed(b, &rewards) + bz := store.Get(types.GetValidatorOutstandingRewardsKey(val)) + k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &rewards) return } // set validator outstanding rewards func (k Keeper) SetValidatorOutstandingRewards(ctx sdk.Context, val sdk.ValAddress, rewards types.ValidatorOutstandingRewards) { store := ctx.KVStore(k.storeKey) - b := k.cdc.MustMarshalBinaryLengthPrefixed(rewards) + b := k.cdc.MustMarshalBinaryLengthPrefixed(&rewards) store.Set(types.GetValidatorOutstandingRewardsKey(val), b) } @@ -297,7 +302,7 @@ func (k Keeper) IterateValidatorOutstandingRewards(ctx sdk.Context, handler func iter := sdk.KVStorePrefixIterator(store, types.ValidatorOutstandingRewardsPrefix) defer iter.Close() for ; iter.Valid(); iter.Next() { - var rewards types.ValidatorOutstandingRewards + rewards := types.ValidatorOutstandingRewards{} k.cdc.MustUnmarshalBinaryLengthPrefixed(iter.Value(), &rewards) addr := types.GetValidatorOutstandingRewardsAddress(iter.Key()) if handler(addr, rewards) { @@ -320,7 +325,7 @@ func (k Keeper) GetValidatorSlashEvent(ctx sdk.Context, val sdk.ValAddress, heig // set slash event for height func (k Keeper) SetValidatorSlashEvent(ctx sdk.Context, val sdk.ValAddress, height, period uint64, event types.ValidatorSlashEvent) { store := ctx.KVStore(k.storeKey) - b := k.cdc.MustMarshalBinaryLengthPrefixed(event) + b := k.cdc.MustMarshalBinaryLengthPrefixed(&event) store.Set(types.GetValidatorSlashEventKey(val, height, period), b) } diff --git a/x/distribution/keeper/test_common.go b/x/distribution/keeper/test_common.go index 2fe0e22b36ab..dae0734c8d39 100644 --- a/x/distribution/keeper/test_common.go +++ b/x/distribution/keeper/test_common.go @@ -142,7 +142,7 @@ func CreateTestInputAdvanced( sk := staking.NewKeeper(staking.ModuleCdc, keyStaking, bankKeeper, supplyKeeper, pk.Subspace(staking.DefaultParamspace)) sk.SetParams(ctx, staking.DefaultParams()) - keeper := NewKeeper(cdc, keyDistr, pk.Subspace(types.DefaultParamspace), bankKeeper, sk, supplyKeeper, auth.FeeCollectorName, blacklistedAddrs) + keeper := NewKeeper(types.ModuleCdc, keyDistr, pk.Subspace(types.DefaultParamspace), bankKeeper, sk, supplyKeeper, auth.FeeCollectorName, blacklistedAddrs) initCoins := sdk.NewCoins(sdk.NewCoin(sk.BondDenom(ctx), initTokens)) totalSupply := sdk.NewCoins(sdk.NewCoin(sk.BondDenom(ctx), initTokens.MulRaw(int64(len(TestAddrs))))) diff --git a/x/distribution/keeper/validator.go b/x/distribution/keeper/validator.go index ccedb7ede163..6b9711a76443 100644 --- a/x/distribution/keeper/validator.go +++ b/x/distribution/keeper/validator.go @@ -21,7 +21,7 @@ func (k Keeper) initializeValidator(ctx sdk.Context, val exported.ValidatorI) { k.SetValidatorAccumulatedCommission(ctx, val.GetOperator(), types.InitialValidatorAccumulatedCommission()) // set outstanding rewards - k.SetValidatorOutstandingRewards(ctx, val.GetOperator(), sdk.DecCoins{}) + k.SetValidatorOutstandingRewards(ctx, val.GetOperator(), types.ValidatorOutstandingRewards{Rewards: sdk.DecCoins{}}) } // increment validator period, returning the period just ended @@ -38,7 +38,7 @@ func (k Keeper) incrementValidatorPeriod(ctx sdk.Context, val exported.Validator feePool := k.GetFeePool(ctx) outstanding := k.GetValidatorOutstandingRewards(ctx, val.GetOperator()) feePool.CommunityPool = feePool.CommunityPool.Add(rewards.Rewards...) - outstanding = outstanding.Sub(rewards.Rewards) + outstanding.Rewards = outstanding.GetRewards().Sub(rewards.Rewards) k.SetFeePool(ctx, feePool) k.SetValidatorOutstandingRewards(ctx, val.GetOperator(), outstanding) diff --git a/x/distribution/simulation/decoder_test.go b/x/distribution/simulation/decoder_test.go index d8c6d719ce9e..059c2d625afd 100644 --- a/x/distribution/simulation/decoder_test.go +++ b/x/distribution/simulation/decoder_test.go @@ -36,8 +36,8 @@ func TestDecodeDistributionStore(t *testing.T) { feePool := types.InitialFeePool() feePool.CommunityPool = decCoins info := types.NewDelegatorStartingInfo(2, sdk.OneDec(), 200) - outstanding := types.ValidatorOutstandingRewards{decCoins[0]} - commission := types.ValidatorAccumulatedCommission{decCoins[0]} + outstanding := types.ValidatorOutstandingRewards{Rewards: decCoins} + commission := types.ValidatorAccumulatedCommission{Commission: decCoins} historicalRewards := types.NewValidatorHistoricalRewards(decCoins, 100) currentRewards := types.NewValidatorCurrentRewards(decCoins, 5) slashEvent := types.NewValidatorSlashEvent(10, sdk.OneDec()) diff --git a/x/distribution/simulation/operations.go b/x/distribution/simulation/operations.go index cb30376ab429..f134861ab139 100644 --- a/x/distribution/simulation/operations.go +++ b/x/distribution/simulation/operations.go @@ -177,7 +177,7 @@ func SimulateMsgWithdrawValidatorCommission(ak types.AccountKeeper, bk types.Ban } commission := k.GetValidatorAccumulatedCommission(ctx, validator.GetOperator()) - if commission.IsZero() { + if commission.Commission.IsZero() { return simulation.NoOpMsg(types.ModuleName), nil, nil } diff --git a/x/distribution/types/codec.go b/x/distribution/types/codec.go index a2d4bf11eaae..85412d65c77e 100644 --- a/x/distribution/types/codec.go +++ b/x/distribution/types/codec.go @@ -4,7 +4,22 @@ import ( "github.com/cosmos/cosmos-sdk/codec" ) -// Register concrete types on codec codec +type Codec struct { + codec.Marshaler + + // Keep reference to the amino codec to allow backwards compatibility along + // with type, and interface registration. + amino *codec.Codec +} + +func NewCodec(amino *codec.Codec) *Codec { + return &Codec{Marshaler: codec.NewHybridCodec(amino), amino: amino} +} + +// ---------------------------------------------------------------------------- + +// RegisterCodec registers all the necessary crisis module concrete types and +// interfaces with the provided codec reference. func RegisterCodec(cdc *codec.Codec) { cdc.RegisterConcrete(MsgWithdrawDelegatorReward{}, "cosmos-sdk/MsgWithdrawDelegationReward", nil) cdc.RegisterConcrete(MsgWithdrawValidatorCommission{}, "cosmos-sdk/MsgWithdrawValidatorCommission", nil) @@ -13,11 +28,11 @@ func RegisterCodec(cdc *codec.Codec) { } // generic sealed codec to be used throughout module -var ModuleCdc *codec.Codec +var ModuleCdc *Codec func init() { - ModuleCdc = codec.New() - RegisterCodec(ModuleCdc) - codec.RegisterCrypto(ModuleCdc) - ModuleCdc.Seal() + ModuleCdc = NewCodec(codec.New()) + RegisterCodec(ModuleCdc.amino) + codec.RegisterCrypto(ModuleCdc.amino) + ModuleCdc.amino.Seal() } diff --git a/x/distribution/types/delegator.go b/x/distribution/types/delegator.go index 8c9e0b9933ce..850878660780 100644 --- a/x/distribution/types/delegator.go +++ b/x/distribution/types/delegator.go @@ -4,19 +4,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -// starting info for a delegator reward period -// tracks the previous validator period, the delegation's amount -// of staking token, and the creation height (to check later on -// if any slashes have occurred) -// NOTE that even though validators are slashed to whole staking tokens, the -// delegators within the validator may be left with less than a full token, -// thus sdk.Dec is used -type DelegatorStartingInfo struct { - PreviousPeriod uint64 `json:"previous_period" yaml:"previous_period"` // period at which the delegation should withdraw starting from - Stake sdk.Dec `json:"stake" yaml:"stake"` // amount of staking token delegated - Height uint64 `json:"creation_height" yaml:"creation_height"` // height at which delegation was created -} - // create a new DelegatorStartingInfo func NewDelegatorStartingInfo(previousPeriod uint64, stake sdk.Dec, height uint64) DelegatorStartingInfo { return DelegatorStartingInfo{ diff --git a/x/distribution/types/fee_pool.go b/x/distribution/types/fee_pool.go index b542ced7be24..645afd401a33 100644 --- a/x/distribution/types/fee_pool.go +++ b/x/distribution/types/fee_pool.go @@ -6,11 +6,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -// global fee pool for distribution -type FeePool struct { - CommunityPool sdk.DecCoins `json:"community_pool" yaml:"community_pool"` // pool for community funds yet to be spent -} - // zero fee pool func InitialFeePool() FeePool { return FeePool{ diff --git a/x/distribution/types/msg.go b/x/distribution/types/msg.go index 2068caef149e..4641c95663e9 100644 --- a/x/distribution/types/msg.go +++ b/x/distribution/types/msg.go @@ -9,12 +9,6 @@ import ( // Verify interface at compile time var _, _, _ sdk.Msg = &MsgSetWithdrawAddress{}, &MsgWithdrawDelegatorReward{}, &MsgWithdrawValidatorCommission{} -// msg struct for changing the withdraw address for a delegator (or validator self-delegation) -type MsgSetWithdrawAddress struct { - DelegatorAddress sdk.AccAddress `json:"delegator_address" yaml:"delegator_address"` - WithdrawAddress sdk.AccAddress `json:"withdraw_address" yaml:"withdraw_address"` -} - func NewMsgSetWithdrawAddress(delAddr, withdrawAddr sdk.AccAddress) MsgSetWithdrawAddress { return MsgSetWithdrawAddress{ DelegatorAddress: delAddr, @@ -48,12 +42,6 @@ func (msg MsgSetWithdrawAddress) ValidateBasic() error { return nil } -// msg struct for delegation withdraw from a single validator -type MsgWithdrawDelegatorReward struct { - DelegatorAddress sdk.AccAddress `json:"delegator_address" yaml:"delegator_address"` - ValidatorAddress sdk.ValAddress `json:"validator_address" yaml:"validator_address"` -} - func NewMsgWithdrawDelegatorReward(delAddr sdk.AccAddress, valAddr sdk.ValAddress) MsgWithdrawDelegatorReward { return MsgWithdrawDelegatorReward{ DelegatorAddress: delAddr, @@ -86,11 +74,6 @@ func (msg MsgWithdrawDelegatorReward) ValidateBasic() error { return nil } -// msg struct for validator withdraw -type MsgWithdrawValidatorCommission struct { - ValidatorAddress sdk.ValAddress `json:"validator_address" yaml:"validator_address"` -} - func NewMsgWithdrawValidatorCommission(valAddr sdk.ValAddress) MsgWithdrawValidatorCommission { return MsgWithdrawValidatorCommission{ ValidatorAddress: valAddr, @@ -121,13 +104,6 @@ func (msg MsgWithdrawValidatorCommission) ValidateBasic() error { const TypeMsgFundCommunityPool = "fund_community_pool" -// MsgFundCommunityPool defines a Msg type that allows an account to directly -// fund the community pool. -type MsgFundCommunityPool struct { - Amount sdk.Coins `json:"amount" yaml:"amount"` - Depositor sdk.AccAddress `json:"depositor" yaml:"depositor"` -} - // NewMsgFundCommunityPool returns a new MsgFundCommunityPool with a sender and // a funding amount. func NewMsgFundCommunityPool(amount sdk.Coins, depositor sdk.AccAddress) MsgFundCommunityPool { diff --git a/x/distribution/types/params.go b/x/distribution/types/params.go index f4530dd81c3b..12daed847d47 100644 --- a/x/distribution/types/params.go +++ b/x/distribution/types/params.go @@ -22,14 +22,6 @@ var ( ParamStoreKeyWithdrawAddrEnabled = []byte("withdrawaddrenabled") ) -// Params defines the set of distribution parameters. -type Params struct { - CommunityTax sdk.Dec `json:"community_tax" yaml:"community_tax"` - BaseProposerReward sdk.Dec `json:"base_proposer_reward" yaml:"base_proposer_reward"` - BonusProposerReward sdk.Dec `json:"bonus_proposer_reward" yaml:"bonus_proposer_reward"` - WithdrawAddrEnabled bool `json:"withdraw_addr_enabled" yaml:"withdraw_addr_enabled"` -} - // ParamKeyTable returns the parameter key table. func ParamKeyTable() params.KeyTable { return params.NewKeyTable().RegisterParamSet(&Params{}) diff --git a/x/distribution/types/proposal.go b/x/distribution/types/proposal.go index 931e111ba719..db65da94286e 100644 --- a/x/distribution/types/proposal.go +++ b/x/distribution/types/proposal.go @@ -21,14 +21,6 @@ func init() { govtypes.RegisterProposalTypeCodec(CommunityPoolSpendProposal{}, "cosmos-sdk/CommunityPoolSpendProposal") } -// CommunityPoolSpendProposal spends from the community pool -type CommunityPoolSpendProposal struct { - Title string `json:"title" yaml:"title"` - Description string `json:"description" yaml:"description"` - Recipient sdk.AccAddress `json:"recipient" yaml:"recipient"` - Amount sdk.Coins `json:"amount" yaml:"amount"` -} - // NewCommunityPoolSpendProposal creates a new community pool spned proposal. func NewCommunityPoolSpendProposal(title, description string, recipient sdk.AccAddress, amount sdk.Coins) CommunityPoolSpendProposal { return CommunityPoolSpendProposal{title, description, recipient, amount} diff --git a/x/distribution/types/types.pb.go b/x/distribution/types/types.pb.go new file mode 100644 index 000000000000..21a6dfbee38d --- /dev/null +++ b/x/distribution/types/types.pb.go @@ -0,0 +1,3343 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: x/distribution/types/types.proto + +package types + +import ( + fmt "fmt" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// msg struct for changing the withdraw address for a delegator (or validator self-delegation) +type MsgSetWithdrawAddress struct { + DelegatorAddress github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,1,opt,name=delegator_address,json=delegatorAddress,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"delegator_address,omitempty" yaml:"delegator_address"` + WithdrawAddress github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,2,opt,name=withdraw_address,json=withdrawAddress,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"withdraw_address,omitempty" yaml:"withdraw_address"` +} + +func (m *MsgSetWithdrawAddress) Reset() { *m = MsgSetWithdrawAddress{} } +func (m *MsgSetWithdrawAddress) String() string { return proto.CompactTextString(m) } +func (*MsgSetWithdrawAddress) ProtoMessage() {} +func (*MsgSetWithdrawAddress) Descriptor() ([]byte, []int) { + return fileDescriptor_9fddf2a8e4a90b09, []int{0} +} +func (m *MsgSetWithdrawAddress) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgSetWithdrawAddress) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgSetWithdrawAddress.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 *MsgSetWithdrawAddress) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgSetWithdrawAddress.Merge(m, src) +} +func (m *MsgSetWithdrawAddress) XXX_Size() int { + return m.Size() +} +func (m *MsgSetWithdrawAddress) XXX_DiscardUnknown() { + xxx_messageInfo_MsgSetWithdrawAddress.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgSetWithdrawAddress proto.InternalMessageInfo + +func (m *MsgSetWithdrawAddress) GetDelegatorAddress() github_com_cosmos_cosmos_sdk_types.AccAddress { + if m != nil { + return m.DelegatorAddress + } + return nil +} + +func (m *MsgSetWithdrawAddress) GetWithdrawAddress() github_com_cosmos_cosmos_sdk_types.AccAddress { + if m != nil { + return m.WithdrawAddress + } + return nil +} + +// msg struct for delegation withdraw from a single validator +type MsgWithdrawDelegatorReward struct { + DelegatorAddress github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,1,opt,name=delegator_address,json=delegatorAddress,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"delegator_address,omitempty" yaml:"delegator_address"` + ValidatorAddress github_com_cosmos_cosmos_sdk_types.ValAddress `protobuf:"bytes,2,opt,name=validator_address,json=validatorAddress,proto3,casttype=github.com/cosmos/cosmos-sdk/types.ValAddress" json:"validator_address,omitempty" yaml:"validator_address"` +} + +func (m *MsgWithdrawDelegatorReward) Reset() { *m = MsgWithdrawDelegatorReward{} } +func (m *MsgWithdrawDelegatorReward) String() string { return proto.CompactTextString(m) } +func (*MsgWithdrawDelegatorReward) ProtoMessage() {} +func (*MsgWithdrawDelegatorReward) Descriptor() ([]byte, []int) { + return fileDescriptor_9fddf2a8e4a90b09, []int{1} +} +func (m *MsgWithdrawDelegatorReward) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgWithdrawDelegatorReward) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgWithdrawDelegatorReward.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 *MsgWithdrawDelegatorReward) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgWithdrawDelegatorReward.Merge(m, src) +} +func (m *MsgWithdrawDelegatorReward) XXX_Size() int { + return m.Size() +} +func (m *MsgWithdrawDelegatorReward) XXX_DiscardUnknown() { + xxx_messageInfo_MsgWithdrawDelegatorReward.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgWithdrawDelegatorReward proto.InternalMessageInfo + +func (m *MsgWithdrawDelegatorReward) GetDelegatorAddress() github_com_cosmos_cosmos_sdk_types.AccAddress { + if m != nil { + return m.DelegatorAddress + } + return nil +} + +func (m *MsgWithdrawDelegatorReward) GetValidatorAddress() github_com_cosmos_cosmos_sdk_types.ValAddress { + if m != nil { + return m.ValidatorAddress + } + return nil +} + +// msg struct for validator withdraw +type MsgWithdrawValidatorCommission struct { + ValidatorAddress github_com_cosmos_cosmos_sdk_types.ValAddress `protobuf:"bytes,1,opt,name=validator_address,json=validatorAddress,proto3,casttype=github.com/cosmos/cosmos-sdk/types.ValAddress" json:"validator_address,omitempty" yaml:"validator_address"` +} + +func (m *MsgWithdrawValidatorCommission) Reset() { *m = MsgWithdrawValidatorCommission{} } +func (m *MsgWithdrawValidatorCommission) String() string { return proto.CompactTextString(m) } +func (*MsgWithdrawValidatorCommission) ProtoMessage() {} +func (*MsgWithdrawValidatorCommission) Descriptor() ([]byte, []int) { + return fileDescriptor_9fddf2a8e4a90b09, []int{2} +} +func (m *MsgWithdrawValidatorCommission) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgWithdrawValidatorCommission) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgWithdrawValidatorCommission.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 *MsgWithdrawValidatorCommission) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgWithdrawValidatorCommission.Merge(m, src) +} +func (m *MsgWithdrawValidatorCommission) XXX_Size() int { + return m.Size() +} +func (m *MsgWithdrawValidatorCommission) XXX_DiscardUnknown() { + xxx_messageInfo_MsgWithdrawValidatorCommission.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgWithdrawValidatorCommission proto.InternalMessageInfo + +func (m *MsgWithdrawValidatorCommission) GetValidatorAddress() github_com_cosmos_cosmos_sdk_types.ValAddress { + if m != nil { + return m.ValidatorAddress + } + return nil +} + +// MsgFundCommunityPool defines a Msg type that allows an account to directly +// fund the community pool. +type MsgFundCommunityPool struct { + Amount github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,1,rep,name=amount,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"amount"` + Depositor github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,2,opt,name=depositor,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"depositor,omitempty"` +} + +func (m *MsgFundCommunityPool) Reset() { *m = MsgFundCommunityPool{} } +func (m *MsgFundCommunityPool) String() string { return proto.CompactTextString(m) } +func (*MsgFundCommunityPool) ProtoMessage() {} +func (*MsgFundCommunityPool) Descriptor() ([]byte, []int) { + return fileDescriptor_9fddf2a8e4a90b09, []int{3} +} +func (m *MsgFundCommunityPool) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgFundCommunityPool) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgFundCommunityPool.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 *MsgFundCommunityPool) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgFundCommunityPool.Merge(m, src) +} +func (m *MsgFundCommunityPool) XXX_Size() int { + return m.Size() +} +func (m *MsgFundCommunityPool) XXX_DiscardUnknown() { + xxx_messageInfo_MsgFundCommunityPool.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgFundCommunityPool proto.InternalMessageInfo + +func (m *MsgFundCommunityPool) GetAmount() github_com_cosmos_cosmos_sdk_types.Coins { + if m != nil { + return m.Amount + } + return nil +} + +func (m *MsgFundCommunityPool) GetDepositor() github_com_cosmos_cosmos_sdk_types.AccAddress { + if m != nil { + return m.Depositor + } + return nil +} + +// Params defines the set of distribution parameters. +type Params struct { + CommunityTax github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,1,opt,name=community_tax,json=communityTax,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"community_tax" yaml:"community_tax"` + BaseProposerReward github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,2,opt,name=base_proposer_reward,json=baseProposerReward,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"base_proposer_reward" yaml:"base_proposer_reward"` + BonusProposerReward github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,3,opt,name=bonus_proposer_reward,json=bonusProposerReward,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"bonus_proposer_reward" yaml:"bonus_proposer_reward"` + WithdrawAddrEnabled bool `protobuf:"varint,4,opt,name=withdraw_addr_enabled,json=withdrawAddrEnabled,proto3" json:"withdraw_addr_enabled,omitempty" yaml:"withdraw_addr_enabled"` +} + +func (m *Params) Reset() { *m = Params{} } +func (*Params) ProtoMessage() {} +func (*Params) Descriptor() ([]byte, []int) { + return fileDescriptor_9fddf2a8e4a90b09, []int{4} +} +func (m *Params) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Params) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Params.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 *Params) XXX_Merge(src proto.Message) { + xxx_messageInfo_Params.Merge(m, src) +} +func (m *Params) XXX_Size() int { + return m.Size() +} +func (m *Params) XXX_DiscardUnknown() { + xxx_messageInfo_Params.DiscardUnknown(m) +} + +var xxx_messageInfo_Params proto.InternalMessageInfo + +func (m *Params) GetWithdrawAddrEnabled() bool { + if m != nil { + return m.WithdrawAddrEnabled + } + return false +} + +// historical rewards for a validator +// height is implicit within the store key +// cumulative reward ratio is the sum from the zeroeth period +// until this period of rewards / tokens, per the spec +// The reference count indicates the number of objects +// which might need to reference this historical entry +// at any point. +// ReferenceCount = +// number of outstanding delegations which ended the associated period (and might need to read +// that record) +// + number of slashes which ended the associated period (and might need to read that record) +// + one per validator for the zeroeth period, set on initialization +type ValidatorHistoricalRewards struct { + CumulativeRewardRatio github_com_cosmos_cosmos_sdk_types.DecCoins `protobuf:"bytes,1,rep,name=cumulative_reward_ratio,json=cumulativeRewardRatio,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.DecCoins" json:"cumulative_reward_ratio" yaml:"cumulative_reward_ratio"` + ReferenceCount uint32 `protobuf:"varint,2,opt,name=reference_count,json=referenceCount,proto3" json:"reference_count,omitempty" yaml:"reference_count"` +} + +func (m *ValidatorHistoricalRewards) Reset() { *m = ValidatorHistoricalRewards{} } +func (m *ValidatorHistoricalRewards) String() string { return proto.CompactTextString(m) } +func (*ValidatorHistoricalRewards) ProtoMessage() {} +func (*ValidatorHistoricalRewards) Descriptor() ([]byte, []int) { + return fileDescriptor_9fddf2a8e4a90b09, []int{5} +} +func (m *ValidatorHistoricalRewards) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ValidatorHistoricalRewards) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ValidatorHistoricalRewards.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 *ValidatorHistoricalRewards) XXX_Merge(src proto.Message) { + xxx_messageInfo_ValidatorHistoricalRewards.Merge(m, src) +} +func (m *ValidatorHistoricalRewards) XXX_Size() int { + return m.Size() +} +func (m *ValidatorHistoricalRewards) XXX_DiscardUnknown() { + xxx_messageInfo_ValidatorHistoricalRewards.DiscardUnknown(m) +} + +var xxx_messageInfo_ValidatorHistoricalRewards proto.InternalMessageInfo + +func (m *ValidatorHistoricalRewards) GetCumulativeRewardRatio() github_com_cosmos_cosmos_sdk_types.DecCoins { + if m != nil { + return m.CumulativeRewardRatio + } + return nil +} + +func (m *ValidatorHistoricalRewards) GetReferenceCount() uint32 { + if m != nil { + return m.ReferenceCount + } + return 0 +} + +// current rewards and current period for a validator +// kept as a running counter and incremented each block +// as long as the validator's tokens remain constant +type ValidatorCurrentRewards struct { + Rewards github_com_cosmos_cosmos_sdk_types.DecCoins `protobuf:"bytes,1,rep,name=rewards,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.DecCoins" json:"rewards"` + Period uint64 `protobuf:"varint,2,opt,name=period,proto3" json:"period,omitempty"` +} + +func (m *ValidatorCurrentRewards) Reset() { *m = ValidatorCurrentRewards{} } +func (m *ValidatorCurrentRewards) String() string { return proto.CompactTextString(m) } +func (*ValidatorCurrentRewards) ProtoMessage() {} +func (*ValidatorCurrentRewards) Descriptor() ([]byte, []int) { + return fileDescriptor_9fddf2a8e4a90b09, []int{6} +} +func (m *ValidatorCurrentRewards) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ValidatorCurrentRewards) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ValidatorCurrentRewards.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 *ValidatorCurrentRewards) XXX_Merge(src proto.Message) { + xxx_messageInfo_ValidatorCurrentRewards.Merge(m, src) +} +func (m *ValidatorCurrentRewards) XXX_Size() int { + return m.Size() +} +func (m *ValidatorCurrentRewards) XXX_DiscardUnknown() { + xxx_messageInfo_ValidatorCurrentRewards.DiscardUnknown(m) +} + +var xxx_messageInfo_ValidatorCurrentRewards proto.InternalMessageInfo + +func (m *ValidatorCurrentRewards) GetRewards() github_com_cosmos_cosmos_sdk_types.DecCoins { + if m != nil { + return m.Rewards + } + return nil +} + +func (m *ValidatorCurrentRewards) GetPeriod() uint64 { + if m != nil { + return m.Period + } + return 0 +} + +// accumulated commission for a validator +// kept as a running counter, can be withdrawn at any time +type ValidatorAccumulatedCommission struct { + Commission github_com_cosmos_cosmos_sdk_types.DecCoins `protobuf:"bytes,1,rep,name=commission,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.DecCoins" json:"commission"` +} + +func (m *ValidatorAccumulatedCommission) Reset() { *m = ValidatorAccumulatedCommission{} } +func (m *ValidatorAccumulatedCommission) String() string { return proto.CompactTextString(m) } +func (*ValidatorAccumulatedCommission) ProtoMessage() {} +func (*ValidatorAccumulatedCommission) Descriptor() ([]byte, []int) { + return fileDescriptor_9fddf2a8e4a90b09, []int{7} +} +func (m *ValidatorAccumulatedCommission) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ValidatorAccumulatedCommission) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ValidatorAccumulatedCommission.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 *ValidatorAccumulatedCommission) XXX_Merge(src proto.Message) { + xxx_messageInfo_ValidatorAccumulatedCommission.Merge(m, src) +} +func (m *ValidatorAccumulatedCommission) XXX_Size() int { + return m.Size() +} +func (m *ValidatorAccumulatedCommission) XXX_DiscardUnknown() { + xxx_messageInfo_ValidatorAccumulatedCommission.DiscardUnknown(m) +} + +var xxx_messageInfo_ValidatorAccumulatedCommission proto.InternalMessageInfo + +func (m *ValidatorAccumulatedCommission) GetCommission() github_com_cosmos_cosmos_sdk_types.DecCoins { + if m != nil { + return m.Commission + } + return nil +} + +// outstanding (un-withdrawn) rewards for a validator +// inexpensive to track, allows simple sanity checks +type ValidatorOutstandingRewards struct { + Rewards github_com_cosmos_cosmos_sdk_types.DecCoins `protobuf:"bytes,1,rep,name=rewards,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.DecCoins" json:"rewards" yaml:"rewards"` +} + +func (m *ValidatorOutstandingRewards) Reset() { *m = ValidatorOutstandingRewards{} } +func (m *ValidatorOutstandingRewards) String() string { return proto.CompactTextString(m) } +func (*ValidatorOutstandingRewards) ProtoMessage() {} +func (*ValidatorOutstandingRewards) Descriptor() ([]byte, []int) { + return fileDescriptor_9fddf2a8e4a90b09, []int{8} +} +func (m *ValidatorOutstandingRewards) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ValidatorOutstandingRewards) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ValidatorOutstandingRewards.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 *ValidatorOutstandingRewards) XXX_Merge(src proto.Message) { + xxx_messageInfo_ValidatorOutstandingRewards.Merge(m, src) +} +func (m *ValidatorOutstandingRewards) XXX_Size() int { + return m.Size() +} +func (m *ValidatorOutstandingRewards) XXX_DiscardUnknown() { + xxx_messageInfo_ValidatorOutstandingRewards.DiscardUnknown(m) +} + +var xxx_messageInfo_ValidatorOutstandingRewards proto.InternalMessageInfo + +func (m *ValidatorOutstandingRewards) GetRewards() github_com_cosmos_cosmos_sdk_types.DecCoins { + if m != nil { + return m.Rewards + } + return nil +} + +// validator slash event +// height is implicit within the store key +// needed to calculate appropriate amounts of staking token +// for delegations which withdraw after a slash has occurred +type ValidatorSlashEvent struct { + ValidatorPeriod uint64 `protobuf:"varint,1,opt,name=validator_period,json=validatorPeriod,proto3" json:"validator_period,omitempty" yaml:"validator_period"` + Fraction github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,2,opt,name=fraction,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"fraction"` +} + +func (m *ValidatorSlashEvent) Reset() { *m = ValidatorSlashEvent{} } +func (m *ValidatorSlashEvent) String() string { return proto.CompactTextString(m) } +func (*ValidatorSlashEvent) ProtoMessage() {} +func (*ValidatorSlashEvent) Descriptor() ([]byte, []int) { + return fileDescriptor_9fddf2a8e4a90b09, []int{9} +} +func (m *ValidatorSlashEvent) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ValidatorSlashEvent) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ValidatorSlashEvent.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 *ValidatorSlashEvent) XXX_Merge(src proto.Message) { + xxx_messageInfo_ValidatorSlashEvent.Merge(m, src) +} +func (m *ValidatorSlashEvent) XXX_Size() int { + return m.Size() +} +func (m *ValidatorSlashEvent) XXX_DiscardUnknown() { + xxx_messageInfo_ValidatorSlashEvent.DiscardUnknown(m) +} + +var xxx_messageInfo_ValidatorSlashEvent proto.InternalMessageInfo + +func (m *ValidatorSlashEvent) GetValidatorPeriod() uint64 { + if m != nil { + return m.ValidatorPeriod + } + return 0 +} + +// ValidatorSlashEvents is a collection of ValidatorSlashEvent +type ValidatorSlashEvents struct { + ValidatorSlashEvents []ValidatorSlashEvent `protobuf:"bytes,1,rep,name=validator_slash_events,json=validatorSlashEvents,proto3" json:"validator_slash_events" yaml:"validator_slash_events"` +} + +func (m *ValidatorSlashEvents) Reset() { *m = ValidatorSlashEvents{} } +func (*ValidatorSlashEvents) ProtoMessage() {} +func (*ValidatorSlashEvents) Descriptor() ([]byte, []int) { + return fileDescriptor_9fddf2a8e4a90b09, []int{10} +} +func (m *ValidatorSlashEvents) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ValidatorSlashEvents) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ValidatorSlashEvents.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 *ValidatorSlashEvents) XXX_Merge(src proto.Message) { + xxx_messageInfo_ValidatorSlashEvents.Merge(m, src) +} +func (m *ValidatorSlashEvents) XXX_Size() int { + return m.Size() +} +func (m *ValidatorSlashEvents) XXX_DiscardUnknown() { + xxx_messageInfo_ValidatorSlashEvents.DiscardUnknown(m) +} + +var xxx_messageInfo_ValidatorSlashEvents proto.InternalMessageInfo + +func (m *ValidatorSlashEvents) GetValidatorSlashEvents() []ValidatorSlashEvent { + if m != nil { + return m.ValidatorSlashEvents + } + return nil +} + +// global fee pool for distribution +type FeePool struct { + CommunityPool github_com_cosmos_cosmos_sdk_types.DecCoins `protobuf:"bytes,1,rep,name=community_pool,json=communityPool,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.DecCoins" json:"community_pool" yaml:"community_pool"` +} + +func (m *FeePool) Reset() { *m = FeePool{} } +func (m *FeePool) String() string { return proto.CompactTextString(m) } +func (*FeePool) ProtoMessage() {} +func (*FeePool) Descriptor() ([]byte, []int) { + return fileDescriptor_9fddf2a8e4a90b09, []int{11} +} +func (m *FeePool) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *FeePool) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_FeePool.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 *FeePool) XXX_Merge(src proto.Message) { + xxx_messageInfo_FeePool.Merge(m, src) +} +func (m *FeePool) XXX_Size() int { + return m.Size() +} +func (m *FeePool) XXX_DiscardUnknown() { + xxx_messageInfo_FeePool.DiscardUnknown(m) +} + +var xxx_messageInfo_FeePool proto.InternalMessageInfo + +func (m *FeePool) GetCommunityPool() github_com_cosmos_cosmos_sdk_types.DecCoins { + if m != nil { + return m.CommunityPool + } + return nil +} + +// CommunityPoolSpendProposal spends from the community pool +type CommunityPoolSpendProposal struct { + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` + Recipient github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,3,opt,name=recipient,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"recipient,omitempty"` + Amount github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,4,rep,name=amount,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"amount"` +} + +func (m *CommunityPoolSpendProposal) Reset() { *m = CommunityPoolSpendProposal{} } +func (*CommunityPoolSpendProposal) ProtoMessage() {} +func (*CommunityPoolSpendProposal) Descriptor() ([]byte, []int) { + return fileDescriptor_9fddf2a8e4a90b09, []int{12} +} +func (m *CommunityPoolSpendProposal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CommunityPoolSpendProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CommunityPoolSpendProposal.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 *CommunityPoolSpendProposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_CommunityPoolSpendProposal.Merge(m, src) +} +func (m *CommunityPoolSpendProposal) XXX_Size() int { + return m.Size() +} +func (m *CommunityPoolSpendProposal) XXX_DiscardUnknown() { + xxx_messageInfo_CommunityPoolSpendProposal.DiscardUnknown(m) +} + +var xxx_messageInfo_CommunityPoolSpendProposal proto.InternalMessageInfo + +// starting info for a delegator reward period +// tracks the previous validator period, the delegation's amount +// of staking token, and the creation height (to check later on +// if any slashes have occurred) +// NOTE that even though validators are slashed to whole staking tokens, the +// delegators within the validator may be left with less than a full token, +// thus sdk.Dec is used +type DelegatorStartingInfo struct { + PreviousPeriod uint64 `protobuf:"varint,1,opt,name=previous_period,json=previousPeriod,proto3" json:"previous_period,omitempty" yaml:"previous_period"` + Stake github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,2,opt,name=stake,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"stake" yaml:"stake"` + Height uint64 `protobuf:"varint,3,opt,name=height,proto3" json:"creation_height" yaml:"creation_height"` +} + +func (m *DelegatorStartingInfo) Reset() { *m = DelegatorStartingInfo{} } +func (m *DelegatorStartingInfo) String() string { return proto.CompactTextString(m) } +func (*DelegatorStartingInfo) ProtoMessage() {} +func (*DelegatorStartingInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_9fddf2a8e4a90b09, []int{13} +} +func (m *DelegatorStartingInfo) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DelegatorStartingInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DelegatorStartingInfo.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 *DelegatorStartingInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_DelegatorStartingInfo.Merge(m, src) +} +func (m *DelegatorStartingInfo) XXX_Size() int { + return m.Size() +} +func (m *DelegatorStartingInfo) XXX_DiscardUnknown() { + xxx_messageInfo_DelegatorStartingInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_DelegatorStartingInfo proto.InternalMessageInfo + +func (m *DelegatorStartingInfo) GetPreviousPeriod() uint64 { + if m != nil { + return m.PreviousPeriod + } + return 0 +} + +func (m *DelegatorStartingInfo) GetHeight() uint64 { + if m != nil { + return m.Height + } + return 0 +} + +func init() { + proto.RegisterType((*MsgSetWithdrawAddress)(nil), "cosmos_sdk.x.ditribution.v1.MsgSetWithdrawAddress") + proto.RegisterType((*MsgWithdrawDelegatorReward)(nil), "cosmos_sdk.x.ditribution.v1.MsgWithdrawDelegatorReward") + proto.RegisterType((*MsgWithdrawValidatorCommission)(nil), "cosmos_sdk.x.ditribution.v1.MsgWithdrawValidatorCommission") + proto.RegisterType((*MsgFundCommunityPool)(nil), "cosmos_sdk.x.ditribution.v1.MsgFundCommunityPool") + proto.RegisterType((*Params)(nil), "cosmos_sdk.x.ditribution.v1.Params") + proto.RegisterType((*ValidatorHistoricalRewards)(nil), "cosmos_sdk.x.ditribution.v1.ValidatorHistoricalRewards") + proto.RegisterType((*ValidatorCurrentRewards)(nil), "cosmos_sdk.x.ditribution.v1.ValidatorCurrentRewards") + proto.RegisterType((*ValidatorAccumulatedCommission)(nil), "cosmos_sdk.x.ditribution.v1.ValidatorAccumulatedCommission") + proto.RegisterType((*ValidatorOutstandingRewards)(nil), "cosmos_sdk.x.ditribution.v1.ValidatorOutstandingRewards") + proto.RegisterType((*ValidatorSlashEvent)(nil), "cosmos_sdk.x.ditribution.v1.ValidatorSlashEvent") + proto.RegisterType((*ValidatorSlashEvents)(nil), "cosmos_sdk.x.ditribution.v1.ValidatorSlashEvents") + proto.RegisterType((*FeePool)(nil), "cosmos_sdk.x.ditribution.v1.FeePool") + proto.RegisterType((*CommunityPoolSpendProposal)(nil), "cosmos_sdk.x.ditribution.v1.CommunityPoolSpendProposal") + proto.RegisterType((*DelegatorStartingInfo)(nil), "cosmos_sdk.x.ditribution.v1.DelegatorStartingInfo") +} + +func init() { proto.RegisterFile("x/distribution/types/types.proto", fileDescriptor_9fddf2a8e4a90b09) } + +var fileDescriptor_9fddf2a8e4a90b09 = []byte{ + // 1110 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x57, 0xcf, 0x6f, 0x1b, 0x45, + 0x1b, 0xf6, 0x38, 0x4e, 0x9a, 0x4c, 0xd3, 0xa4, 0xd9, 0xd8, 0x49, 0xe4, 0x7c, 0x9f, 0xd7, 0x1a, + 0x89, 0x2a, 0x12, 0x8a, 0xd3, 0xd0, 0x5b, 0x0e, 0x48, 0x71, 0x7e, 0x08, 0x50, 0x43, 0xa3, 0x4d, + 0x28, 0x12, 0x12, 0x5a, 0x8d, 0x77, 0x27, 0xf6, 0x28, 0xeb, 0x9d, 0xd5, 0xcc, 0xd8, 0x4e, 0x7a, + 0x41, 0xe2, 0x04, 0x82, 0x22, 0x0e, 0x08, 0x7a, 0xe0, 0xd0, 0x0b, 0x07, 0x2a, 0xfe, 0x0e, 0xd4, + 0x63, 0x6f, 0x20, 0x0e, 0x2e, 0x4a, 0x6e, 0x1c, 0x73, 0x83, 0x13, 0xda, 0x9d, 0xd9, 0x5d, 0xc7, + 0xb1, 0xa8, 0x1d, 0xa9, 0x70, 0x49, 0x32, 0xef, 0xbc, 0xf3, 0x3c, 0xcf, 0x3c, 0x33, 0xf3, 0xbe, + 0x1b, 0x58, 0x3e, 0x59, 0x73, 0xa9, 0x90, 0x9c, 0xd6, 0x5a, 0x92, 0x32, 0x7f, 0x4d, 0x9e, 0x06, + 0x44, 0xa8, 0x9f, 0x95, 0x80, 0x33, 0xc9, 0x8c, 0x65, 0x87, 0x89, 0x26, 0x13, 0xb6, 0x70, 0x8f, + 0x2b, 0x27, 0x15, 0x97, 0x26, 0xb9, 0x95, 0xf6, 0x7a, 0xf1, 0x8e, 0x6c, 0x50, 0xee, 0xda, 0x01, + 0xe6, 0xf2, 0x74, 0x2d, 0xca, 0x5f, 0xab, 0xb3, 0x3a, 0x4b, 0xff, 0x52, 0x20, 0xc5, 0xb9, 0x2b, + 0xb8, 0xe8, 0xcb, 0x2c, 0x2c, 0xec, 0x89, 0xfa, 0x01, 0x91, 0x1f, 0x52, 0xd9, 0x70, 0x39, 0xee, + 0x6c, 0xba, 0x2e, 0x27, 0x42, 0x18, 0x8f, 0xe0, 0x9c, 0x4b, 0x3c, 0x52, 0xc7, 0x92, 0x71, 0x1b, + 0xab, 0xe0, 0x12, 0x28, 0x83, 0x95, 0xe9, 0xea, 0xde, 0x45, 0xd7, 0x5c, 0x3a, 0xc5, 0x4d, 0x6f, + 0x03, 0x5d, 0x49, 0x41, 0x7f, 0x75, 0xcd, 0xd5, 0x3a, 0x95, 0x8d, 0x56, 0xad, 0xe2, 0xb0, 0xe6, + 0x9a, 0xd2, 0xad, 0x7f, 0xad, 0x0a, 0xf7, 0x58, 0xd3, 0x6f, 0x3a, 0x8e, 0x66, 0xb2, 0x6e, 0x27, + 0x20, 0x31, 0x77, 0x07, 0xde, 0xee, 0x68, 0x39, 0x09, 0x75, 0x36, 0xa2, 0xbe, 0x7f, 0xd1, 0x35, + 0x17, 0x15, 0x75, 0x7f, 0xc6, 0x35, 0x98, 0x67, 0x3b, 0x97, 0x37, 0x8d, 0xbe, 0xc9, 0xc2, 0xe2, + 0x9e, 0xa8, 0xc7, 0x5e, 0x6c, 0xc7, 0xc2, 0x2c, 0xd2, 0xc1, 0xdc, 0xfd, 0x4f, 0x3d, 0x79, 0x04, + 0xe7, 0xda, 0xd8, 0xa3, 0xee, 0x25, 0xee, 0x6c, 0x3f, 0xf7, 0x95, 0x94, 0x61, 0xb9, 0x1f, 0x62, + 0x2f, 0xe1, 0x4e, 0x40, 0x62, 0x5b, 0xbe, 0x07, 0xb0, 0xd4, 0x63, 0xcb, 0xc3, 0x78, 0x7e, 0x8b, + 0x35, 0x9b, 0x54, 0x08, 0xca, 0xfc, 0xc1, 0xf2, 0xc0, 0xbf, 0x23, 0xef, 0x67, 0x00, 0xf3, 0x7b, + 0xa2, 0xbe, 0xdb, 0xf2, 0xdd, 0x50, 0x51, 0xcb, 0xa7, 0xf2, 0x74, 0x9f, 0x31, 0xcf, 0xf8, 0x18, + 0x4e, 0xe0, 0x26, 0x6b, 0xf9, 0x72, 0x09, 0x94, 0xc7, 0x56, 0x6e, 0xbe, 0x35, 0x5f, 0xe9, 0x79, + 0x46, 0xed, 0xf5, 0xca, 0x16, 0xa3, 0x7e, 0xf5, 0xee, 0xf3, 0xae, 0x99, 0x79, 0xf6, 0xd2, 0x5c, + 0x19, 0x42, 0x46, 0xb8, 0x40, 0x58, 0x1a, 0xd4, 0x78, 0x00, 0xa7, 0x5c, 0x12, 0x30, 0x41, 0x25, + 0xe3, 0xfa, 0x28, 0xd6, 0x47, 0x3f, 0xea, 0x14, 0x03, 0xfd, 0x32, 0x06, 0x27, 0xf6, 0x31, 0xc7, + 0x4d, 0x61, 0x1c, 0xc3, 0x5b, 0x4e, 0xbc, 0x17, 0x5b, 0xe2, 0x93, 0xc8, 0xcb, 0xa9, 0xea, 0x6e, + 0x28, 0xf6, 0xb7, 0xae, 0x79, 0x67, 0x08, 0x8e, 0x6d, 0xe2, 0x5c, 0x74, 0xcd, 0xbc, 0x72, 0xfe, + 0x12, 0x18, 0xb2, 0xa6, 0x93, 0xf1, 0x21, 0x3e, 0x31, 0x3e, 0x81, 0xf9, 0x1a, 0x16, 0xc4, 0x0e, + 0x38, 0x0b, 0x98, 0x20, 0xdc, 0xe6, 0xd1, 0x7d, 0x8f, 0xf6, 0x34, 0x55, 0xdd, 0x1b, 0x99, 0x73, + 0x59, 0x71, 0x0e, 0xc2, 0x44, 0x96, 0x11, 0x86, 0xf7, 0x75, 0x54, 0x3f, 0xac, 0x4f, 0x01, 0x2c, + 0xd4, 0x98, 0xdf, 0x12, 0x57, 0x24, 0x8c, 0x45, 0x12, 0xde, 0x1f, 0x59, 0xc2, 0xff, 0xb4, 0x84, + 0x41, 0xa0, 0xc8, 0x9a, 0x8f, 0xe2, 0x7d, 0x22, 0x0e, 0x61, 0xe1, 0x52, 0x4d, 0xb1, 0x89, 0x8f, + 0x6b, 0x1e, 0x71, 0x97, 0x72, 0x65, 0xb0, 0x32, 0x59, 0x2d, 0xa7, 0xa8, 0x03, 0xd3, 0x90, 0x35, + 0xdf, 0x5b, 0x4e, 0x76, 0x54, 0x74, 0x23, 0xf7, 0xe4, 0xa9, 0x99, 0x41, 0x9f, 0x67, 0x61, 0x31, + 0x79, 0x36, 0xef, 0x50, 0x21, 0x19, 0xa7, 0x0e, 0xf6, 0x14, 0xb3, 0x30, 0x7e, 0x00, 0x70, 0xd1, + 0x69, 0x35, 0x5b, 0x1e, 0x96, 0xb4, 0x4d, 0xb4, 0x4c, 0x9b, 0x63, 0x49, 0x99, 0xbe, 0xba, 0x0b, + 0x7d, 0x57, 0x77, 0x9b, 0x38, 0xd1, 0xed, 0xfd, 0x20, 0x74, 0xe6, 0xa2, 0x6b, 0x96, 0xf4, 0x31, + 0x0f, 0x06, 0x41, 0xcf, 0x5e, 0x9a, 0x6f, 0x0e, 0xe7, 0x9d, 0xba, 0xe2, 0x85, 0x14, 0x48, 0x69, + 0xb4, 0x42, 0x18, 0x63, 0x0b, 0xce, 0x72, 0x72, 0x44, 0x38, 0xf1, 0x1d, 0x62, 0x3b, 0xd1, 0xcb, + 0x0a, 0xef, 0xc8, 0xad, 0x6a, 0xf1, 0xa2, 0x6b, 0x2e, 0x28, 0x09, 0x7d, 0x09, 0xc8, 0x9a, 0x49, + 0x22, 0x5b, 0x51, 0xe0, 0x09, 0x80, 0x8b, 0x69, 0x09, 0x69, 0x71, 0x4e, 0x7c, 0x19, 0x1b, 0x41, + 0xe0, 0x0d, 0xa5, 0x5b, 0xbc, 0x62, 0xdf, 0xf7, 0xf4, 0xab, 0x1d, 0x69, 0x57, 0x31, 0xb6, 0xb1, + 0x00, 0x27, 0x02, 0xc2, 0x29, 0x53, 0x57, 0x3c, 0x67, 0xe9, 0x11, 0x7a, 0x0c, 0x60, 0x29, 0x91, + 0xb6, 0xe9, 0x68, 0x13, 0x88, 0xdb, 0x53, 0xe8, 0x8e, 0x21, 0x74, 0x92, 0xd1, 0xeb, 0x10, 0xd9, + 0x03, 0x8f, 0xbe, 0x05, 0x70, 0x39, 0xd1, 0xf3, 0xa0, 0x25, 0x85, 0xc4, 0xbe, 0x4b, 0xfd, 0x7a, + 0x6c, 0x57, 0x67, 0x58, 0xbb, 0x76, 0xf4, 0x35, 0x99, 0x89, 0xcf, 0x28, 0x5a, 0x84, 0xae, 0x6b, + 0x20, 0xfa, 0x11, 0xc0, 0xf9, 0x44, 0xd8, 0x81, 0x87, 0x45, 0x63, 0xa7, 0x4d, 0x7c, 0x69, 0xec, + 0xc2, 0xb4, 0x3c, 0xdb, 0xda, 0xe2, 0xb0, 0x72, 0xe5, 0xaa, 0xcb, 0x69, 0xe7, 0xee, 0xcf, 0x40, + 0xd6, 0x6c, 0x12, 0xda, 0x8f, 0x22, 0xc6, 0x7b, 0x70, 0xf2, 0x88, 0x63, 0x27, 0xfc, 0xc2, 0xd1, + 0x55, 0xa8, 0x32, 0x5a, 0x09, 0xb0, 0x92, 0xf5, 0xe8, 0x27, 0x00, 0xf3, 0x03, 0xb4, 0x0a, 0xe3, + 0x31, 0x80, 0x0b, 0xa9, 0x16, 0x11, 0xce, 0xd8, 0x24, 0x9a, 0xd2, 0x6e, 0xde, 0xad, 0xfc, 0xc3, + 0x67, 0x57, 0x65, 0x00, 0x66, 0xf5, 0x0d, 0xed, 0xf3, 0xff, 0xfb, 0x77, 0xda, 0x8b, 0x8e, 0xac, + 0x7c, 0x7b, 0x80, 0x1e, 0x5d, 0x2a, 0xbe, 0x03, 0xf0, 0xc6, 0x2e, 0x21, 0x51, 0x03, 0xfb, 0x02, + 0xc0, 0x99, 0xb4, 0x72, 0x07, 0x8c, 0x79, 0xaf, 0x38, 0xe7, 0xfb, 0x9a, 0xbf, 0xd0, 0x5f, 0xf5, + 0xc3, 0xb5, 0x23, 0x1f, 0x77, 0xda, 0x82, 0x42, 0x35, 0xe8, 0xab, 0x2c, 0x2c, 0x5e, 0x6a, 0xb0, + 0x07, 0x01, 0xf1, 0x5d, 0x55, 0x45, 0xb1, 0x67, 0xe4, 0xe1, 0xb8, 0xa4, 0xd2, 0x23, 0xaa, 0x55, + 0x59, 0x6a, 0x60, 0x94, 0xe1, 0x4d, 0x97, 0x08, 0x87, 0xd3, 0x20, 0x3d, 0x4c, 0xab, 0x37, 0x14, + 0xb6, 0x51, 0x4e, 0x1c, 0x1a, 0x50, 0xe2, 0xcb, 0xa8, 0xde, 0x5f, 0xaf, 0x8d, 0x26, 0x18, 0x3d, + 0x6d, 0x3f, 0xf7, 0x1a, 0xda, 0xfe, 0xc6, 0xe4, 0x67, 0x4f, 0xcd, 0x4c, 0x74, 0x54, 0x7f, 0x02, + 0x58, 0x48, 0xbe, 0x11, 0x0f, 0x24, 0xe6, 0x92, 0xfa, 0xf5, 0x77, 0xfd, 0xa3, 0xa8, 0x50, 0x06, + 0x9c, 0xb4, 0x29, 0x0b, 0xbb, 0x4f, 0xef, 0x33, 0xe8, 0x29, 0x94, 0x7d, 0x09, 0xc8, 0x9a, 0x89, + 0x23, 0xfa, 0x11, 0x1c, 0xc2, 0x71, 0x21, 0xf1, 0x31, 0xd1, 0x2f, 0xe0, 0xed, 0x91, 0x9b, 0xe0, + 0xb4, 0x22, 0x8a, 0x40, 0x90, 0xa5, 0xc0, 0x8c, 0x1d, 0x38, 0xd1, 0x20, 0xb4, 0xde, 0x50, 0x5e, + 0xe7, 0xaa, 0xab, 0x7f, 0x74, 0xcd, 0x59, 0x87, 0x93, 0xb0, 0xc0, 0xfb, 0xb6, 0x9a, 0x4a, 0x45, + 0xf6, 0x4d, 0x20, 0x4b, 0x2f, 0xae, 0x9a, 0xcf, 0xcf, 0x4a, 0xe0, 0xc5, 0x59, 0x09, 0xfc, 0x7e, + 0x56, 0x02, 0x5f, 0x9f, 0x97, 0x32, 0x2f, 0xce, 0x4b, 0x99, 0x5f, 0xcf, 0x4b, 0x99, 0x8f, 0xc6, + 0x23, 0x09, 0xb5, 0x89, 0xe8, 0x3f, 0x8c, 0x7b, 0x7f, 0x07, 0x00, 0x00, 0xff, 0xff, 0x2c, 0xac, + 0x10, 0x4b, 0xdd, 0x0c, 0x00, 0x00, +} + +func (m *MsgSetWithdrawAddress) 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 *MsgSetWithdrawAddress) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgSetWithdrawAddress) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.WithdrawAddress) > 0 { + i -= len(m.WithdrawAddress) + copy(dAtA[i:], m.WithdrawAddress) + i = encodeVarintTypes(dAtA, i, uint64(len(m.WithdrawAddress))) + i-- + dAtA[i] = 0x12 + } + if len(m.DelegatorAddress) > 0 { + i -= len(m.DelegatorAddress) + copy(dAtA[i:], m.DelegatorAddress) + i = encodeVarintTypes(dAtA, i, uint64(len(m.DelegatorAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgWithdrawDelegatorReward) 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 *MsgWithdrawDelegatorReward) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgWithdrawDelegatorReward) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ValidatorAddress) > 0 { + i -= len(m.ValidatorAddress) + copy(dAtA[i:], m.ValidatorAddress) + i = encodeVarintTypes(dAtA, i, uint64(len(m.ValidatorAddress))) + i-- + dAtA[i] = 0x12 + } + if len(m.DelegatorAddress) > 0 { + i -= len(m.DelegatorAddress) + copy(dAtA[i:], m.DelegatorAddress) + i = encodeVarintTypes(dAtA, i, uint64(len(m.DelegatorAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgWithdrawValidatorCommission) 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 *MsgWithdrawValidatorCommission) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgWithdrawValidatorCommission) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ValidatorAddress) > 0 { + i -= len(m.ValidatorAddress) + copy(dAtA[i:], m.ValidatorAddress) + i = encodeVarintTypes(dAtA, i, uint64(len(m.ValidatorAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgFundCommunityPool) 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 *MsgFundCommunityPool) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgFundCommunityPool) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Depositor) > 0 { + i -= len(m.Depositor) + copy(dAtA[i:], m.Depositor) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Depositor))) + i-- + dAtA[i] = 0x12 + } + if len(m.Amount) > 0 { + for iNdEx := len(m.Amount) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Amount[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *Params) 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 *Params) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.WithdrawAddrEnabled { + i-- + if m.WithdrawAddrEnabled { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x20 + } + { + size := m.BonusProposerReward.Size() + i -= size + if _, err := m.BonusProposerReward.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + { + size := m.BaseProposerReward.Size() + i -= size + if _, err := m.BaseProposerReward.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + { + size := m.CommunityTax.Size() + i -= size + if _, err := m.CommunityTax.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *ValidatorHistoricalRewards) 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 *ValidatorHistoricalRewards) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ValidatorHistoricalRewards) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.ReferenceCount != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.ReferenceCount)) + i-- + dAtA[i] = 0x10 + } + if len(m.CumulativeRewardRatio) > 0 { + for iNdEx := len(m.CumulativeRewardRatio) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.CumulativeRewardRatio[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *ValidatorCurrentRewards) 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 *ValidatorCurrentRewards) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ValidatorCurrentRewards) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Period != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.Period)) + i-- + dAtA[i] = 0x10 + } + if len(m.Rewards) > 0 { + for iNdEx := len(m.Rewards) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Rewards[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *ValidatorAccumulatedCommission) 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 *ValidatorAccumulatedCommission) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ValidatorAccumulatedCommission) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Commission) > 0 { + for iNdEx := len(m.Commission) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Commission[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *ValidatorOutstandingRewards) 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 *ValidatorOutstandingRewards) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ValidatorOutstandingRewards) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Rewards) > 0 { + for iNdEx := len(m.Rewards) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Rewards[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *ValidatorSlashEvent) 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 *ValidatorSlashEvent) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ValidatorSlashEvent) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size := m.Fraction.Size() + i -= size + if _, err := m.Fraction.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if m.ValidatorPeriod != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.ValidatorPeriod)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *ValidatorSlashEvents) 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 *ValidatorSlashEvents) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ValidatorSlashEvents) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ValidatorSlashEvents) > 0 { + for iNdEx := len(m.ValidatorSlashEvents) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.ValidatorSlashEvents[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *FeePool) 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 *FeePool) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *FeePool) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.CommunityPool) > 0 { + for iNdEx := len(m.CommunityPool) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.CommunityPool[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *CommunityPoolSpendProposal) 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 *CommunityPoolSpendProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CommunityPoolSpendProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Amount) > 0 { + for iNdEx := len(m.Amount) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Amount[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + } + if len(m.Recipient) > 0 { + i -= len(m.Recipient) + copy(dAtA[i:], m.Recipient) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Recipient))) + i-- + dAtA[i] = 0x1a + } + if len(m.Description) > 0 { + i -= len(m.Description) + copy(dAtA[i:], m.Description) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Description))) + i-- + dAtA[i] = 0x12 + } + if len(m.Title) > 0 { + i -= len(m.Title) + copy(dAtA[i:], m.Title) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Title))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *DelegatorStartingInfo) 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 *DelegatorStartingInfo) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DelegatorStartingInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Height != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.Height)) + i-- + dAtA[i] = 0x18 + } + { + size := m.Stake.Size() + i -= size + if _, err := m.Stake.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if m.PreviousPeriod != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.PreviousPeriod)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func encodeVarintTypes(dAtA []byte, offset int, v uint64) int { + offset -= sovTypes(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgSetWithdrawAddress) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.DelegatorAddress) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.WithdrawAddress) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + +func (m *MsgWithdrawDelegatorReward) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.DelegatorAddress) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.ValidatorAddress) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + +func (m *MsgWithdrawValidatorCommission) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ValidatorAddress) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + +func (m *MsgFundCommunityPool) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Amount) > 0 { + for _, e := range m.Amount { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + l = len(m.Depositor) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + +func (m *Params) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.CommunityTax.Size() + n += 1 + l + sovTypes(uint64(l)) + l = m.BaseProposerReward.Size() + n += 1 + l + sovTypes(uint64(l)) + l = m.BonusProposerReward.Size() + n += 1 + l + sovTypes(uint64(l)) + if m.WithdrawAddrEnabled { + n += 2 + } + return n +} + +func (m *ValidatorHistoricalRewards) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.CumulativeRewardRatio) > 0 { + for _, e := range m.CumulativeRewardRatio { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + if m.ReferenceCount != 0 { + n += 1 + sovTypes(uint64(m.ReferenceCount)) + } + return n +} + +func (m *ValidatorCurrentRewards) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Rewards) > 0 { + for _, e := range m.Rewards { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + if m.Period != 0 { + n += 1 + sovTypes(uint64(m.Period)) + } + return n +} + +func (m *ValidatorAccumulatedCommission) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Commission) > 0 { + for _, e := range m.Commission { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + return n +} + +func (m *ValidatorOutstandingRewards) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Rewards) > 0 { + for _, e := range m.Rewards { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + return n +} + +func (m *ValidatorSlashEvent) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ValidatorPeriod != 0 { + n += 1 + sovTypes(uint64(m.ValidatorPeriod)) + } + l = m.Fraction.Size() + n += 1 + l + sovTypes(uint64(l)) + return n +} + +func (m *ValidatorSlashEvents) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.ValidatorSlashEvents) > 0 { + for _, e := range m.ValidatorSlashEvents { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + return n +} + +func (m *FeePool) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.CommunityPool) > 0 { + for _, e := range m.CommunityPool { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + return n +} + +func (m *CommunityPoolSpendProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Title) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.Description) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.Recipient) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + if len(m.Amount) > 0 { + for _, e := range m.Amount { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + return n +} + +func (m *DelegatorStartingInfo) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.PreviousPeriod != 0 { + n += 1 + sovTypes(uint64(m.PreviousPeriod)) + } + l = m.Stake.Size() + n += 1 + l + sovTypes(uint64(l)) + if m.Height != 0 { + n += 1 + sovTypes(uint64(m.Height)) + } + return n +} + +func sovTypes(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTypes(x uint64) (n int) { + return sovTypes(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *MsgSetWithdrawAddress) 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 ErrIntOverflowTypes + } + 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: MsgSetWithdrawAddress: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSetWithdrawAddress: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DelegatorAddress", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DelegatorAddress = append(m.DelegatorAddress[:0], dAtA[iNdEx:postIndex]...) + if m.DelegatorAddress == nil { + m.DelegatorAddress = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field WithdrawAddress", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.WithdrawAddress = append(m.WithdrawAddress[:0], dAtA[iNdEx:postIndex]...) + if m.WithdrawAddress == nil { + m.WithdrawAddress = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgWithdrawDelegatorReward) 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 ErrIntOverflowTypes + } + 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: MsgWithdrawDelegatorReward: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgWithdrawDelegatorReward: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DelegatorAddress", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DelegatorAddress = append(m.DelegatorAddress[:0], dAtA[iNdEx:postIndex]...) + if m.DelegatorAddress == nil { + m.DelegatorAddress = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ValidatorAddress", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ValidatorAddress = append(m.ValidatorAddress[:0], dAtA[iNdEx:postIndex]...) + if m.ValidatorAddress == nil { + m.ValidatorAddress = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgWithdrawValidatorCommission) 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 ErrIntOverflowTypes + } + 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: MsgWithdrawValidatorCommission: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgWithdrawValidatorCommission: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ValidatorAddress", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ValidatorAddress = append(m.ValidatorAddress[:0], dAtA[iNdEx:postIndex]...) + if m.ValidatorAddress == nil { + m.ValidatorAddress = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgFundCommunityPool) 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 ErrIntOverflowTypes + } + 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: MsgFundCommunityPool: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgFundCommunityPool: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Amount = append(m.Amount, types.Coin{}) + if err := m.Amount[len(m.Amount)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Depositor", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Depositor = append(m.Depositor[:0], dAtA[iNdEx:postIndex]...) + if m.Depositor == nil { + m.Depositor = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Params) 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 ErrIntOverflowTypes + } + 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: Params: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CommunityTax", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.CommunityTax.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BaseProposerReward", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.BaseProposerReward.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BonusProposerReward", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.BonusProposerReward.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field WithdrawAddrEnabled", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.WithdrawAddrEnabled = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ValidatorHistoricalRewards) 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 ErrIntOverflowTypes + } + 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: ValidatorHistoricalRewards: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ValidatorHistoricalRewards: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CumulativeRewardRatio", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CumulativeRewardRatio = append(m.CumulativeRewardRatio, types.DecCoin{}) + if err := m.CumulativeRewardRatio[len(m.CumulativeRewardRatio)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ReferenceCount", wireType) + } + m.ReferenceCount = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ReferenceCount |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ValidatorCurrentRewards) 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 ErrIntOverflowTypes + } + 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: ValidatorCurrentRewards: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ValidatorCurrentRewards: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Rewards", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Rewards = append(m.Rewards, types.DecCoin{}) + if err := m.Rewards[len(m.Rewards)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Period", wireType) + } + m.Period = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Period |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ValidatorAccumulatedCommission) 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 ErrIntOverflowTypes + } + 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: ValidatorAccumulatedCommission: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ValidatorAccumulatedCommission: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Commission", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Commission = append(m.Commission, types.DecCoin{}) + if err := m.Commission[len(m.Commission)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ValidatorOutstandingRewards) 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 ErrIntOverflowTypes + } + 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: ValidatorOutstandingRewards: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ValidatorOutstandingRewards: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Rewards", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Rewards = append(m.Rewards, types.DecCoin{}) + if err := m.Rewards[len(m.Rewards)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ValidatorSlashEvent) 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 ErrIntOverflowTypes + } + 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: ValidatorSlashEvent: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ValidatorSlashEvent: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ValidatorPeriod", wireType) + } + m.ValidatorPeriod = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ValidatorPeriod |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Fraction", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Fraction.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ValidatorSlashEvents) 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 ErrIntOverflowTypes + } + 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: ValidatorSlashEvents: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ValidatorSlashEvents: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ValidatorSlashEvents", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ValidatorSlashEvents = append(m.ValidatorSlashEvents, ValidatorSlashEvent{}) + if err := m.ValidatorSlashEvents[len(m.ValidatorSlashEvents)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *FeePool) 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 ErrIntOverflowTypes + } + 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: FeePool: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: FeePool: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CommunityPool", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CommunityPool = append(m.CommunityPool, types.DecCoin{}) + if err := m.CommunityPool[len(m.CommunityPool)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *CommunityPoolSpendProposal) 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 ErrIntOverflowTypes + } + 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: CommunityPoolSpendProposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CommunityPoolSpendProposal: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Title", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Title = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Description = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Recipient", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Recipient = append(m.Recipient[:0], dAtA[iNdEx:postIndex]...) + if m.Recipient == nil { + m.Recipient = []byte{} + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Amount = append(m.Amount, types.Coin{}) + if err := m.Amount[len(m.Amount)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *DelegatorStartingInfo) 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 ErrIntOverflowTypes + } + 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: DelegatorStartingInfo: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DelegatorStartingInfo: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PreviousPeriod", wireType) + } + m.PreviousPeriod = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PreviousPeriod |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Stake", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Stake.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Height", wireType) + } + m.Height = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Height |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTypes(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthTypes + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTypes + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTypes + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTypes = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTypes = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTypes = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/distribution/types/types.proto b/x/distribution/types/types.proto new file mode 100644 index 000000000000..be398e09126a --- /dev/null +++ b/x/distribution/types/types.proto @@ -0,0 +1,182 @@ +syntax = "proto3"; +package cosmos_sdk.x.ditribution.v1; + +option go_package = "types"; + +import "third_party/proto/gogoproto/gogo.proto"; +import "types/types.proto"; + +// msg struct for changing the withdraw address for a delegator (or validator self-delegation) +message MsgSetWithdrawAddress { + bytes delegator_address = 1 [ + (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress", + (gogoproto.moretags) = "yaml:\"delegator_address\"" + ]; + bytes withdraw_address = 2 [ + (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress", + (gogoproto.moretags) = "yaml:\"withdraw_address\"" + ]; +} + +// msg struct for delegation withdraw from a single validator +message MsgWithdrawDelegatorReward { + bytes delegator_address = 1 [ + (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress", + (gogoproto.moretags) = "yaml:\"delegator_address\"" + ]; + bytes validator_address = 2 [ + (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.ValAddress", + (gogoproto.moretags) = "yaml:\"validator_address\"" + ]; +} + +// msg struct for validator withdraw +message MsgWithdrawValidatorCommission { + bytes validator_address = 1 [ + (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.ValAddress", + (gogoproto.moretags) = "yaml:\"validator_address\"" + ]; +} + +// MsgFundCommunityPool defines a Msg type that allows an account to directly +// fund the community pool. +message MsgFundCommunityPool { + repeated cosmos_sdk.v1.Coin amount = 1 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + ]; + bytes depositor = 2 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; +} + +// Params defines the set of distribution parameters. +message Params { + option (gogoproto.goproto_stringer) = false; + string community_tax = 1 [ + (gogoproto.moretags) = "yaml:\"community_tax\"", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; + string base_proposer_reward = 2 [ + (gogoproto.moretags) = "yaml:\"base_proposer_reward\"", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; + string bonus_proposer_reward = 3 [ + (gogoproto.moretags) = "yaml:\"bonus_proposer_reward\"", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; + bool withdraw_addr_enabled = 4 [(gogoproto.moretags) = "yaml:\"withdraw_addr_enabled\""]; +} + +// historical rewards for a validator +// height is implicit within the store key +// cumulative reward ratio is the sum from the zeroeth period +// until this period of rewards / tokens, per the spec +// The reference count indicates the number of objects +// which might need to reference this historical entry +// at any point. +// ReferenceCount = +// number of outstanding delegations which ended the associated period (and might need to read +// that record) +// + number of slashes which ended the associated period (and might need to read that record) +// + one per validator for the zeroeth period, set on initialization +message ValidatorHistoricalRewards { + repeated cosmos_sdk.v1.DecCoin cumulative_reward_ratio = 1 [ + (gogoproto.moretags) = "yaml:\"cumulative_reward_ratio\"", + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.DecCoins", + (gogoproto.nullable) = false + ]; + uint32 reference_count = 2 [(gogoproto.moretags) = "yaml:\"reference_count\""]; +} + +// current rewards and current period for a validator +// kept as a running counter and incremented each block +// as long as the validator's tokens remain constant +message ValidatorCurrentRewards { + repeated cosmos_sdk.v1.DecCoin rewards = 1 [ + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.DecCoins", + (gogoproto.nullable) = false + ]; + uint64 period = 2; +} + +// accumulated commission for a validator +// kept as a running counter, can be withdrawn at any time +message ValidatorAccumulatedCommission { + repeated cosmos_sdk.v1.DecCoin commission = 1 [ + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.DecCoins", + (gogoproto.nullable) = false + ]; +} + +// outstanding (un-withdrawn) rewards for a validator +// inexpensive to track, allows simple sanity checks +message ValidatorOutstandingRewards { + repeated cosmos_sdk.v1.DecCoin rewards = 1 [ + (gogoproto.moretags) = "yaml:\"rewards\"", + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.DecCoins", + (gogoproto.nullable) = false + ]; +} + +// validator slash event +// height is implicit within the store key +// needed to calculate appropriate amounts of staking token +// for delegations which withdraw after a slash has occurred +message ValidatorSlashEvent { + uint64 validator_period = 1 [(gogoproto.moretags) = "yaml:\"validator_period\""]; + string fraction = 2 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; +} + +// ValidatorSlashEvents is a collection of ValidatorSlashEvent +message ValidatorSlashEvents { + option (gogoproto.goproto_stringer) = false; + repeated ValidatorSlashEvent validator_slash_events = 1 + [(gogoproto.moretags) = "yaml:\"validator_slash_events\"", (gogoproto.nullable) = false]; +} + +// global fee pool for distribution +message FeePool { + repeated cosmos_sdk.v1.DecCoin community_pool = 1 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.DecCoins", + (gogoproto.moretags) = "yaml:\"community_pool\"" + ]; +} + +// CommunityPoolSpendProposal spends from the community pool +message CommunityPoolSpendProposal { + option (gogoproto.goproto_stringer) = false; + option (gogoproto.goproto_getters) = false; + string title = 1; + string description = 2; + bytes recipient = 3 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; + repeated cosmos_sdk.v1.Coin amount = 4 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + ]; +} + +// starting info for a delegator reward period +// tracks the previous validator period, the delegation's amount +// of staking token, and the creation height (to check later on +// if any slashes have occurred) +// NOTE that even though validators are slashed to whole staking tokens, the +// delegators within the validator may be left with less than a full token, +// thus sdk.Dec is used +message DelegatorStartingInfo { + uint64 previous_period = 1 [(gogoproto.moretags) = "yaml:\"previous_period\""]; + string stake = 2 [ + (gogoproto.moretags) = "yaml:\"stake\"", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; + uint64 height = 3 [ + (gogoproto.moretags) = "yaml:\"creation_height\"", + (gogoproto.jsontag) = "creation_height" + ]; +} diff --git a/x/distribution/types/validator.go b/x/distribution/types/validator.go index 9ff1f4c9aa1f..aa64a3703068 100644 --- a/x/distribution/types/validator.go +++ b/x/distribution/types/validator.go @@ -7,38 +7,14 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -// historical rewards for a validator -// height is implicit within the store key -// cumulative reward ratio is the sum from the zeroeth period -// until this period of rewards / tokens, per the spec -// The reference count indicates the number of objects -// which might need to reference this historical entry -// at any point. -// ReferenceCount = -// number of outstanding delegations which ended the associated period (and might need to read that record) -// + number of slashes which ended the associated period (and might need to read that record) -// + one per validator for the zeroeth period, set on initialization -type ValidatorHistoricalRewards struct { - CumulativeRewardRatio sdk.DecCoins `json:"cumulative_reward_ratio" yaml:"cumulative_reward_ratio"` - ReferenceCount uint16 `json:"reference_count" yaml:"reference_count"` -} - // create a new ValidatorHistoricalRewards -func NewValidatorHistoricalRewards(cumulativeRewardRatio sdk.DecCoins, referenceCount uint16) ValidatorHistoricalRewards { +func NewValidatorHistoricalRewards(cumulativeRewardRatio sdk.DecCoins, referenceCount uint32) ValidatorHistoricalRewards { return ValidatorHistoricalRewards{ CumulativeRewardRatio: cumulativeRewardRatio, ReferenceCount: referenceCount, } } -// current rewards and current period for a validator -// kept as a running counter and incremented each block -// as long as the validator's tokens remain constant -type ValidatorCurrentRewards struct { - Rewards sdk.DecCoins `json:"rewards" yaml:"rewards"` // current rewards - Period uint64 `json:"period" yaml:"period"` // current period -} - // create a new ValidatorCurrentRewards func NewValidatorCurrentRewards(rewards sdk.DecCoins, period uint64) ValidatorCurrentRewards { return ValidatorCurrentRewards{ @@ -47,24 +23,11 @@ func NewValidatorCurrentRewards(rewards sdk.DecCoins, period uint64) ValidatorCu } } -// accumulated commission for a validator -// kept as a running counter, can be withdrawn at any time -type ValidatorAccumulatedCommission = sdk.DecCoins - // return the initial accumulated commission (zero) func InitialValidatorAccumulatedCommission() ValidatorAccumulatedCommission { return ValidatorAccumulatedCommission{} } -// validator slash event -// height is implicit within the store key -// needed to calculate appropriate amounts of staking token -// for delegations which withdraw after a slash has occurred -type ValidatorSlashEvent struct { - ValidatorPeriod uint64 `json:"validator_period" yaml:"validator_period"` // period when the slash occurred - Fraction sdk.Dec `json:"fraction" yaml:"fraction"` // slash fraction -} - // create a new ValidatorSlashEvent func NewValidatorSlashEvent(validatorPeriod uint64, fraction sdk.Dec) ValidatorSlashEvent { return ValidatorSlashEvent{ @@ -73,17 +36,9 @@ func NewValidatorSlashEvent(validatorPeriod uint64, fraction sdk.Dec) ValidatorS } } -func (vs ValidatorSlashEvent) String() string { - return fmt.Sprintf(`Period: %d -Fraction: %s`, vs.ValidatorPeriod, vs.Fraction) -} - -// ValidatorSlashEvents is a collection of ValidatorSlashEvent -type ValidatorSlashEvents []ValidatorSlashEvent - func (vs ValidatorSlashEvents) String() string { out := "Validator Slash Events:\n" - for i, sl := range vs { + for i, sl := range vs.ValidatorSlashEvents { out += fmt.Sprintf(` Slash %d: Period: %d Fraction: %s @@ -91,7 +46,3 @@ func (vs ValidatorSlashEvents) String() string { } return strings.TrimSpace(out) } - -// outstanding (un-withdrawn) rewards for a validator -// inexpensive to track, allows simple sanity checks -type ValidatorOutstandingRewards = sdk.DecCoins From 77a47ca4a1b6ac8fcfbcf40a2af89cab3bc910c9 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Tue, 11 Feb 2020 12:14:00 -0500 Subject: [PATCH 128/529] Merge PR #5633: Add v0.38.1 changelog entry --- CHANGELOG.md | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aff20cb2eb1a..5151296590c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -56,14 +56,7 @@ and provided directly the IAVL store. ### Bug Fixes -* (x/gov) [\#5622](https://github.com/cosmos/cosmos-sdk/pull/5622) Track any events emitted from a proposal's handler upon successful execution. -* (types) [\#5579](https://github.com/cosmos/cosmos-sdk/pull/5579) The IAVL `Store#Commit` method has been refactored to -delete a flushed version if it is not a snapshot version. The root multi-store now keeps track of `commitInfo` instead -of `types.CommitID`. During `Commit` of the root multi-store, `lastCommitInfo` is updated from the saved state -and is only flushed to disk if it is a snapshot version. During `Query` of the root multi-store, if the request height -is the latest height, we'll use the store's `lastCommitInfo`. Otherwise, we fetch `commitInfo` from disk. -* (x/bank) [\#5531](https://github.com/cosmos/cosmos-sdk/issues/5531) Added missing amount event to MsgMultiSend, emitted for each output. -* (client) [\#5618](https://github.com/cosmos/cosmos-sdk/pull/5618) Fix crash on the client when the verifier is not set. +* (client) [\#5618](https://github.com/cosmos/cosmos-sdk/pull/5618) Fix crash on the client when the verifier is not set. * (x/distribution) [\#5620](https://github.com/cosmos/cosmos-sdk/pull/5620) Fix nil pointer deref in distribution tax/rewward validation helpers. * (genesis) [\#5086](https://github.com/cosmos/cosmos-sdk/issues/5086) Ensure `gentxs` are always an empty array instead of `nil` @@ -95,9 +88,6 @@ for JSON encoding. ### Improvements -* (modules) [\#5597](https://github.com/cosmos/cosmos-sdk/pull/5597) Add `amount` event attribute to the `complete_unbonding` -and `complete_redelegation` events that reflect the total balances of the completed unbondings and redelegations -respectively. * (types) [\#5581](https://github.com/cosmos/cosmos-sdk/pull/5581) Add convenience functions {,Must}Bech32ifyAddressBytes. * (staking) [\#5584](https://github.com/cosmos/cosmos-sdk/pull/5584) Add util function `ToTmValidator` that converts a `staking.Validator` type to `*tmtypes.Validator`. * (client) [\#5585](https://github.com/cosmos/cosmos-sdk/pull/5585) IBC additions: @@ -107,6 +97,24 @@ respectively. * `Coin` denomination max lenght has been increased to 32. * Added `CapabilityKey` alias for `StoreKey` to match IBC spec. +## [v0.38.1] - 2020-02-11 + +### Improvements + +* (modules) [\#5597](https://github.com/cosmos/cosmos-sdk/pull/5597) Add `amount` event attribute to the `complete_unbonding` +and `complete_redelegation` events that reflect the total balances of the completed unbondings and redelegations +respectively. + +### Bug Fixes + +* (types) [\#5579](https://github.com/cosmos/cosmos-sdk/pull/5579) The IAVL `Store#Commit` method has been refactored to +delete a flushed version if it is not a snapshot version. The root multi-store now keeps track of `commitInfo` instead +of `types.CommitID`. During `Commit` of the root multi-store, `lastCommitInfo` is updated from the saved state +and is only flushed to disk if it is a snapshot version. During `Query` of the root multi-store, if the request height +is the latest height, we'll use the store's `lastCommitInfo`. Otherwise, we fetch `commitInfo` from disk. +* (x/bank) [\#5531](https://github.com/cosmos/cosmos-sdk/issues/5531) Added missing amount event to MsgMultiSend, emitted for each output. +* (x/gov) [\#5622](https://github.com/cosmos/cosmos-sdk/pull/5622) Track any events emitted from a proposal's handler upon successful execution. + ## [v0.38.0] - 2020-01-23 ### State Machine Breaking @@ -2945,7 +2953,8 @@ BUG FIXES: -[Unreleased]: https://github.com/cosmos/cosmos-sdk/compare/v0.38.0...HEAD +[Unreleased]: https://github.com/cosmos/cosmos-sdk/compare/v0.38.1...HEAD +[v0.38.1]: https://github.com/cosmos/cosmos-sdk/releases/tag/v0.38.1 [v0.38.0]: https://github.com/cosmos/cosmos-sdk/releases/tag/v0.38.0 [v0.37.7]: https://github.com/cosmos/cosmos-sdk/releases/tag/v0.37.7 [v0.37.6]: https://github.com/cosmos/cosmos-sdk/releases/tag/v0.37.6 From dca724699770f008cd2b4cf70415f404f174c33c Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 12 Feb 2020 08:11:09 -0500 Subject: [PATCH 129/529] Merge PR #5636: Bump github.com/gorilla/mux from 1.7.3 to 1.7.4 --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 2c39c61e4c3d..e0be4a5f4f83 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/gogo/protobuf v1.3.1 github.com/golang/mock v1.3.1-0.20190508161146-9fa652df1129 github.com/golang/protobuf v1.3.3 - github.com/gorilla/mux v1.7.3 + github.com/gorilla/mux v1.7.4 github.com/hashicorp/golang-lru v0.5.4 github.com/mattn/go-isatty v0.0.12 github.com/pelletier/go-toml v1.6.0 diff --git a/go.sum b/go.sum index 637ed80ce04b..90b9290dc67e 100644 --- a/go.sum +++ b/go.sum @@ -111,6 +111,8 @@ github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGa github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc= +github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= From 48d39e344e846f67471c4b8cb691167978808f38 Mon Sep 17 00:00:00 2001 From: Marko Date: Wed, 12 Feb 2020 17:34:09 +0100 Subject: [PATCH 130/529] Merge PR #5619: proto: migrate params to hybrid codec --- CHANGELOG.md | 2 + simapp/app.go | 2 +- simapp/codec.go | 3 + x/distribution/keeper/test_common.go | 2 +- x/gov/keeper/test_common.go | 2 +- x/mock/app.go | 2 +- x/params/alias.go | 2 + x/params/commmon_test.go | 6 +- x/params/keeper.go | 4 +- x/params/proposal_handler_test.go | 2 +- x/params/subspace/subspace.go | 6 +- x/params/subspace/subspace_test.go | 7 +- x/params/types/codec.go | 21 +- x/params/types/proposal.go | 24 +- x/params/types/types.pb.go | 694 ++++++++++++++++++++++ x/params/types/types.proto | 26 + x/slashing/internal/keeper/test_common.go | 2 +- x/staking/keeper/test_common.go | 2 +- 18 files changed, 768 insertions(+), 41 deletions(-) create mode 100644 x/params/types/types.pb.go create mode 100644 x/params/types/types.proto diff --git a/CHANGELOG.md b/CHANGELOG.md index 5151296590c8..54274ff56728 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,8 @@ balances or a single balance by denom when the `denom` query parameter is presen ### API Breaking Changes +* (x/params) [\#5619](https://github.com/cosmos/cosmos-sdk/pull/5619) The `x/params` keeper now accepts a `codec.Marshaller` instead of +a reference to an amino codec. Amino is still used for JSON serialization. * (types) [\#5579](https://github.com/cosmos/cosmos-sdk/pull/5579) The `keepRecent` field has been removed from the `PruningOptions` type. The `PruningOptions` type now only includes fields `KeepEvery` and `SnapshotEvery`, where `KeepEvery` determines which committed heights are flushed to disk and `SnapshotEvery` determines which of these diff --git a/simapp/app.go b/simapp/app.go index dff6ab5b9f18..20215e8486f9 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -150,7 +150,7 @@ func NewSimApp( } // init params keeper and subspaces - app.ParamsKeeper = params.NewKeeper(app.cdc, keys[params.StoreKey], tkeys[params.TStoreKey]) + app.ParamsKeeper = params.NewKeeper(appCodec.Params, keys[params.StoreKey], tkeys[params.TStoreKey]) app.subspaces[auth.ModuleName] = app.ParamsKeeper.Subspace(auth.DefaultParamspace) app.subspaces[bank.ModuleName] = app.ParamsKeeper.Subspace(bank.DefaultParamspace) app.subspaces[staking.ModuleName] = app.ParamsKeeper.Subspace(staking.DefaultParamspace) diff --git a/simapp/codec.go b/simapp/codec.go index 96b2d6a70a15..0e8aabe15cb2 100644 --- a/simapp/codec.go +++ b/simapp/codec.go @@ -5,6 +5,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth/vesting" distr "github.com/cosmos/cosmos-sdk/x/distribution" + "github.com/cosmos/cosmos-sdk/x/params" "github.com/cosmos/cosmos-sdk/x/staking" ) @@ -13,6 +14,7 @@ import ( type AppCodec struct { amino *codec.Codec + Params *params.Codec Staking *staking.Codec Distribution *distr.Codec } @@ -22,6 +24,7 @@ func NewAppCodec() *AppCodec { return &AppCodec{ amino: amino, + Params: params.NewCodec(amino), Staking: staking.NewCodec(amino), Distribution: distr.NewCodec(amino), } diff --git a/x/distribution/keeper/test_common.go b/x/distribution/keeper/test_common.go index dae0734c8d39..dca88dfd1671 100644 --- a/x/distribution/keeper/test_common.go +++ b/x/distribution/keeper/test_common.go @@ -126,7 +126,7 @@ func CreateTestInputAdvanced( blacklistedAddrs[distrAcc.GetAddress().String()] = true cdc := MakeTestCodec() - pk := params.NewKeeper(cdc, keyParams, tkeyParams) + pk := params.NewKeeper(params.ModuleCdc, keyParams, tkeyParams) ctx := sdk.NewContext(ms, abci.Header{ChainID: "foochainid"}, isCheckTx, log.NewNopLogger()) accountKeeper := auth.NewAccountKeeper(cdc, keyAcc, pk.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount) diff --git a/x/gov/keeper/test_common.go b/x/gov/keeper/test_common.go index bb57f7ab0275..42fe87626bcf 100644 --- a/x/gov/keeper/test_common.go +++ b/x/gov/keeper/test_common.go @@ -146,7 +146,7 @@ func createTestInput( blacklistedAddrs[notBondedPool.GetAddress().String()] = true blacklistedAddrs[bondPool.GetAddress().String()] = true - pk := params.NewKeeper(cdc, keyParams, tkeyParams) + pk := params.NewKeeper(params.ModuleCdc, keyParams, tkeyParams) accountKeeper := auth.NewAccountKeeper(cdc, keyAcc, pk.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount) bankKeeper := bank.NewBaseKeeper(cdc, keyBank, accountKeeper, pk.Subspace(bank.DefaultParamspace), blacklistedAddrs) supplyKeeper := supply.NewKeeper(cdc, keySupply, accountKeeper, bankKeeper, maccPerms) diff --git a/x/mock/app.go b/x/mock/app.go index ad584df1bc0f..d541b138e211 100644 --- a/x/mock/app.go +++ b/x/mock/app.go @@ -69,7 +69,7 @@ func NewApp() *App { TotalCoinsSupply: sdk.NewCoins(), } - app.ParamsKeeper = params.NewKeeper(app.Cdc, app.KeyParams, app.TKeyParams) + app.ParamsKeeper = params.NewKeeper(params.ModuleCdc, app.KeyParams, app.TKeyParams) app.AccountKeeper = auth.NewAccountKeeper( app.Cdc, app.KeyAccount, diff --git a/x/params/alias.go b/x/params/alias.go index 1198e93cede3..668056267e62 100644 --- a/x/params/alias.go +++ b/x/params/alias.go @@ -30,12 +30,14 @@ var ( NewParameterChangeProposal = types.NewParameterChangeProposal NewParamChange = types.NewParamChange ValidateChanges = types.ValidateChanges + NewCodec = types.NewCodec // variable aliases ModuleCdc = types.ModuleCdc ) type ( + Codec = types.Codec ParamSetPair = subspace.ParamSetPair ParamSetPairs = subspace.ParamSetPairs ParamSet = subspace.ParamSet diff --git a/x/params/commmon_test.go b/x/params/commmon_test.go index ecebf8eb2e60..c1d4bd0242ae 100644 --- a/x/params/commmon_test.go +++ b/x/params/commmon_test.go @@ -17,12 +17,12 @@ type s struct { I int } -func createTestCodec() *codec.Codec { +func createTestCodec() codec.Marshaler { cdc := codec.New() sdk.RegisterCodec(cdc) cdc.RegisterConcrete(s{}, "test/s", nil) cdc.RegisterConcrete(invalid{}, "test/invalid", nil) - return cdc + return NewCodec(cdc) } func defaultContext(key sdk.StoreKey, tkey sdk.StoreKey) sdk.Context { @@ -38,7 +38,7 @@ func defaultContext(key sdk.StoreKey, tkey sdk.StoreKey) sdk.Context { return ctx } -func testComponents() (*codec.Codec, sdk.Context, sdk.StoreKey, sdk.StoreKey, Keeper) { +func testComponents() (codec.Marshaler, sdk.Context, sdk.StoreKey, sdk.StoreKey, Keeper) { cdc := createTestCodec() mkey := sdk.NewKVStoreKey("test") tkey := sdk.NewTransientStoreKey("transient_test") diff --git a/x/params/keeper.go b/x/params/keeper.go index c3532f32834f..a290e6561270 100644 --- a/x/params/keeper.go +++ b/x/params/keeper.go @@ -13,14 +13,14 @@ import ( // Keeper of the global paramstore type Keeper struct { - cdc *codec.Codec + cdc codec.Marshaler key sdk.StoreKey tkey sdk.StoreKey spaces map[string]*Subspace } // NewKeeper constructs a params keeper -func NewKeeper(cdc *codec.Codec, key, tkey sdk.StoreKey) Keeper { +func NewKeeper(cdc codec.Marshaler, key, tkey sdk.StoreKey) Keeper { return Keeper{ cdc: cdc, key: key, diff --git a/x/params/proposal_handler_test.go b/x/params/proposal_handler_test.go index 9d83975c1020..b0444f32abc6 100644 --- a/x/params/proposal_handler_test.go +++ b/x/params/proposal_handler_test.go @@ -74,7 +74,7 @@ func newTestInput(t *testing.T) testInput { err := cms.LoadLatestVersion() require.Nil(t, err) - keeper := params.NewKeeper(cdc, keyParams, tKeyParams) + keeper := params.NewKeeper(types.ModuleCdc, keyParams, tKeyParams) ctx := sdk.NewContext(cms, abci.Header{}, false, log.NewNopLogger()) return testInput{ctx, cdc, keeper} diff --git a/x/params/subspace/subspace.go b/x/params/subspace/subspace.go index 94533f9451f1..90dc143ebbe8 100644 --- a/x/params/subspace/subspace.go +++ b/x/params/subspace/subspace.go @@ -22,7 +22,7 @@ const ( // Transient store persists for a block, so we use it for // recording whether the parameter has been changed or not type Subspace struct { - cdc *codec.Codec + cdc codec.Marshaler key sdk.StoreKey // []byte -> []byte, stores parameter tkey sdk.StoreKey // []byte -> bool, stores parameter change name []byte @@ -30,7 +30,7 @@ type Subspace struct { } // NewSubspace constructs a store with namestore -func NewSubspace(cdc *codec.Codec, key sdk.StoreKey, tkey sdk.StoreKey, name string) Subspace { +func NewSubspace(cdc codec.Marshaler, key sdk.StoreKey, tkey sdk.StoreKey, name string) Subspace { return Subspace{ cdc: cdc, key: key, @@ -99,6 +99,8 @@ func (s Subspace) Validate(ctx sdk.Context, key []byte, value interface{}) error // Get queries for a parameter by key from the Subspace's KVStore and sets the // value to the provided pointer. If the value does not exist, it will panic. func (s Subspace) Get(ctx sdk.Context, key []byte, ptr interface{}) { + s.checkType(key, ptr) + store := s.kvStore(ctx) bz := store.Get(key) diff --git a/x/params/subspace/subspace_test.go b/x/params/subspace/subspace_test.go index 05707097d478..3a1e56ae6bc4 100644 --- a/x/params/subspace/subspace_test.go +++ b/x/params/subspace/subspace_test.go @@ -14,18 +14,19 @@ import ( "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/params/subspace" + "github.com/cosmos/cosmos-sdk/x/params/types" ) type SubspaceTestSuite struct { suite.Suite - cdc *codec.Codec + cdc codec.Marshaler ctx sdk.Context ss subspace.Subspace } func (suite *SubspaceTestSuite) SetupTest() { - cdc := codec.New() + cdc := types.ModuleCdc db := dbm.NewMemDB() ms := store.NewCommitMultiStore(db) @@ -46,7 +47,7 @@ func (suite *SubspaceTestSuite) TestKeyTable() { suite.ss.WithKeyTable(paramKeyTable()) }) suite.Require().NotPanics(func() { - ss := subspace.NewSubspace(codec.New(), key, tkey, "testsubspace2") + ss := subspace.NewSubspace(types.ModuleCdc, key, tkey, "testsubspace2") ss = ss.WithKeyTable(paramKeyTable()) }) } diff --git a/x/params/types/codec.go b/x/params/types/codec.go index 525836346f90..a9436062cb10 100644 --- a/x/params/types/codec.go +++ b/x/params/types/codec.go @@ -4,13 +4,26 @@ import ( "github.com/cosmos/cosmos-sdk/codec" ) +type Codec struct { + codec.Marshaler + + // Keep reference to the amino codec to allow backwards compatibility along + // with type, and interface registration. + amino *codec.Codec +} + +func NewCodec(amino *codec.Codec) *Codec { + return &Codec{Marshaler: codec.NewHybridCodec(amino), amino: amino} +} + // module codec -var ModuleCdc *codec.Codec +var ModuleCdc *Codec func init() { - ModuleCdc = codec.New() - RegisterCodec(ModuleCdc) - ModuleCdc.Seal() + ModuleCdc = NewCodec(codec.New()) + + RegisterCodec(ModuleCdc.amino) + ModuleCdc.amino.Seal() } // RegisterCodec registers all necessary param module types with a given codec. diff --git a/x/params/types/proposal.go b/x/params/types/proposal.go index 78f200d143e9..b61b59d25cf3 100644 --- a/x/params/types/proposal.go +++ b/x/params/types/proposal.go @@ -4,6 +4,8 @@ import ( "fmt" "strings" + "gopkg.in/yaml.v2" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" ) @@ -20,14 +22,6 @@ func init() { govtypes.RegisterProposalTypeCodec(ParameterChangeProposal{}, "cosmos-sdk/ParameterChangeProposal") } -// ParameterChangeProposal defines a proposal which contains multiple parameter -// changes. -type ParameterChangeProposal struct { - Title string `json:"title" yaml:"title"` - Description string `json:"description" yaml:"description"` - Changes []ParamChange `json:"changes" yaml:"changes"` -} - func NewParameterChangeProposal(title, description string, changes []ParamChange) ParameterChangeProposal { return ParameterChangeProposal{title, description, changes} } @@ -75,24 +69,14 @@ func (pcp ParameterChangeProposal) String() string { return b.String() } -// ParamChange defines a parameter change. -type ParamChange struct { - Subspace string `json:"subspace" yaml:"subspace"` - Key string `json:"key" yaml:"key"` - Value string `json:"value" yaml:"value"` -} - func NewParamChange(subspace, key, value string) ParamChange { return ParamChange{subspace, key, value} } // String implements the Stringer interface. func (pc ParamChange) String() string { - return fmt.Sprintf(`Param Change: - Subspace: %s - Key: %s - Value: %X -`, pc.Subspace, pc.Key, pc.Value) + out, _ := yaml.Marshal(pc) + return string(out) } // ValidateChanges performs basic validation checks over a set of ParamChange. It diff --git a/x/params/types/types.pb.go b/x/params/types/types.pb.go new file mode 100644 index 000000000000..5f27a306bde2 --- /dev/null +++ b/x/params/types/types.pb.go @@ -0,0 +1,694 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: x/params/types/types.proto + +package types + +import ( + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// ParameterChangeProposal defines a proposal which contains multiple parameter +// changes. +type ParameterChangeProposal struct { + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` + Changes []ParamChange `protobuf:"bytes,3,rep,name=changes,proto3" json:"changes"` +} + +func (m *ParameterChangeProposal) Reset() { *m = ParameterChangeProposal{} } +func (*ParameterChangeProposal) ProtoMessage() {} +func (*ParameterChangeProposal) Descriptor() ([]byte, []int) { + return fileDescriptor_ed04c33aa1766c78, []int{0} +} +func (m *ParameterChangeProposal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ParameterChangeProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ParameterChangeProposal.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 *ParameterChangeProposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_ParameterChangeProposal.Merge(m, src) +} +func (m *ParameterChangeProposal) XXX_Size() int { + return m.Size() +} +func (m *ParameterChangeProposal) XXX_DiscardUnknown() { + xxx_messageInfo_ParameterChangeProposal.DiscardUnknown(m) +} + +var xxx_messageInfo_ParameterChangeProposal proto.InternalMessageInfo + +// ParamChange defines a parameter change. +type ParamChange struct { + Subspace string `protobuf:"bytes,1,opt,name=subspace,proto3" json:"subspace,omitempty"` + Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` + Value string `protobuf:"bytes,3,opt,name=value,proto3" json:"value,omitempty"` +} + +func (m *ParamChange) Reset() { *m = ParamChange{} } +func (*ParamChange) ProtoMessage() {} +func (*ParamChange) Descriptor() ([]byte, []int) { + return fileDescriptor_ed04c33aa1766c78, []int{1} +} +func (m *ParamChange) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ParamChange) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ParamChange.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 *ParamChange) XXX_Merge(src proto.Message) { + xxx_messageInfo_ParamChange.Merge(m, src) +} +func (m *ParamChange) XXX_Size() int { + return m.Size() +} +func (m *ParamChange) XXX_DiscardUnknown() { + xxx_messageInfo_ParamChange.DiscardUnknown(m) +} + +var xxx_messageInfo_ParamChange proto.InternalMessageInfo + +func (m *ParamChange) GetSubspace() string { + if m != nil { + return m.Subspace + } + return "" +} + +func (m *ParamChange) GetKey() string { + if m != nil { + return m.Key + } + return "" +} + +func (m *ParamChange) GetValue() string { + if m != nil { + return m.Value + } + return "" +} + +func init() { + proto.RegisterType((*ParameterChangeProposal)(nil), "cosmos_sdk.x.params.v1.ParameterChangeProposal") + proto.RegisterType((*ParamChange)(nil), "cosmos_sdk.x.params.v1.ParamChange") +} + +func init() { proto.RegisterFile("x/params/types/types.proto", fileDescriptor_ed04c33aa1766c78) } + +var fileDescriptor_ed04c33aa1766c78 = []byte{ + // 287 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xaa, 0xd0, 0x2f, 0x48, + 0x2c, 0x4a, 0xcc, 0x2d, 0xd6, 0x2f, 0xa9, 0x2c, 0x48, 0x85, 0x92, 0x7a, 0x05, 0x45, 0xf9, 0x25, + 0xf9, 0x42, 0x62, 0xc9, 0xf9, 0xc5, 0xb9, 0xf9, 0xc5, 0xf1, 0xc5, 0x29, 0xd9, 0x7a, 0x15, 0x7a, + 0x10, 0x65, 0x7a, 0x65, 0x86, 0x52, 0x6a, 0x25, 0x19, 0x99, 0x45, 0x29, 0xf1, 0x05, 0x89, 0x45, + 0x25, 0x95, 0xfa, 0x60, 0xa5, 0xfa, 0xe9, 0xf9, 0xe9, 0xf9, 0x08, 0x16, 0x44, 0xbf, 0xd2, 0x02, + 0x46, 0x2e, 0xf1, 0x00, 0x90, 0xae, 0xd4, 0x92, 0xd4, 0x22, 0xe7, 0x8c, 0xc4, 0xbc, 0xf4, 0xd4, + 0x80, 0xa2, 0xfc, 0x82, 0xfc, 0xe2, 0xc4, 0x1c, 0x21, 0x11, 0x2e, 0xd6, 0x92, 0xcc, 0x92, 0x9c, + 0x54, 0x09, 0x46, 0x05, 0x46, 0x0d, 0xce, 0x20, 0x08, 0x47, 0x48, 0x81, 0x8b, 0x3b, 0x25, 0xb5, + 0x38, 0xb9, 0x28, 0xb3, 0xa0, 0x24, 0x33, 0x3f, 0x4f, 0x82, 0x09, 0x2c, 0x87, 0x2c, 0x24, 0xe4, + 0xcc, 0xc5, 0x9e, 0x0c, 0x36, 0xa9, 0x58, 0x82, 0x59, 0x81, 0x59, 0x83, 0xdb, 0x48, 0x59, 0x0f, + 0xbb, 0x2b, 0xf5, 0xc0, 0x36, 0x43, 0x6c, 0x75, 0x62, 0x39, 0x71, 0x4f, 0x9e, 0x21, 0x08, 0xa6, + 0xd3, 0x8a, 0xa3, 0x63, 0x81, 0x3c, 0xc3, 0x8c, 0x05, 0xf2, 0x0c, 0x4a, 0xe1, 0x5c, 0xdc, 0x48, + 0xea, 0x84, 0xa4, 0xb8, 0x38, 0x8a, 0x4b, 0x93, 0x8a, 0x0b, 0x12, 0x93, 0x61, 0x0e, 0x83, 0xf3, + 0x85, 0x04, 0xb8, 0x98, 0xb3, 0x53, 0x2b, 0xa1, 0x6e, 0x02, 0x31, 0x41, 0x7e, 0x28, 0x4b, 0xcc, + 0x29, 0x4d, 0x95, 0x60, 0x86, 0xf8, 0x01, 0xcc, 0xb1, 0x62, 0x01, 0x19, 0xec, 0x24, 0x7f, 0xe2, + 0x91, 0x1c, 0xe3, 0x85, 0x47, 0x72, 0x8c, 0x0f, 0x1e, 0xc9, 0x31, 0x4e, 0x78, 0x2c, 0xc7, 0x70, + 0xe1, 0xb1, 0x1c, 0xc3, 0x8d, 0xc7, 0x72, 0x0c, 0x51, 0xac, 0xe0, 0x20, 0x4e, 0x62, 0x03, 0x87, + 0x91, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0x83, 0x64, 0xb6, 0xa5, 0x81, 0x01, 0x00, 0x00, +} + +func (m *ParameterChangeProposal) 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 *ParameterChangeProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ParameterChangeProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Changes) > 0 { + for iNdEx := len(m.Changes) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Changes[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.Description) > 0 { + i -= len(m.Description) + copy(dAtA[i:], m.Description) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Description))) + i-- + dAtA[i] = 0x12 + } + if len(m.Title) > 0 { + i -= len(m.Title) + copy(dAtA[i:], m.Title) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Title))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ParamChange) 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 *ParamChange) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ParamChange) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Value) > 0 { + i -= len(m.Value) + copy(dAtA[i:], m.Value) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Value))) + i-- + dAtA[i] = 0x1a + } + if len(m.Key) > 0 { + i -= len(m.Key) + copy(dAtA[i:], m.Key) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Key))) + i-- + dAtA[i] = 0x12 + } + if len(m.Subspace) > 0 { + i -= len(m.Subspace) + copy(dAtA[i:], m.Subspace) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Subspace))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintTypes(dAtA []byte, offset int, v uint64) int { + offset -= sovTypes(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *ParameterChangeProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Title) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.Description) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + if len(m.Changes) > 0 { + for _, e := range m.Changes { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + return n +} + +func (m *ParamChange) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Subspace) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.Key) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.Value) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + +func sovTypes(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTypes(x uint64) (n int) { + return sovTypes(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *ParameterChangeProposal) 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 ErrIntOverflowTypes + } + 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: ParameterChangeProposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ParameterChangeProposal: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Title", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Title = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Description = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Changes", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Changes = append(m.Changes, ParamChange{}) + if err := m.Changes[len(m.Changes)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ParamChange) 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 ErrIntOverflowTypes + } + 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: ParamChange: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ParamChange: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Subspace", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Subspace = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Key", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Key = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Value = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTypes(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthTypes + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTypes + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTypes + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTypes = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTypes = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTypes = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/params/types/types.proto b/x/params/types/types.proto new file mode 100644 index 000000000000..74f25fe097ee --- /dev/null +++ b/x/params/types/types.proto @@ -0,0 +1,26 @@ +syntax = "proto3"; +package cosmos_sdk.x.params.v1; + +option go_package = "types"; + +import "third_party/proto/gogoproto/gogo.proto"; + +// ParameterChangeProposal defines a proposal which contains multiple parameter +// changes. +message ParameterChangeProposal { + option (gogoproto.goproto_getters) = false; + option (gogoproto.goproto_stringer) = false; + + string title = 1; + string description = 2; + repeated ParamChange changes = 3 [(gogoproto.nullable) = false]; +} + +// ParamChange defines a parameter change. +message ParamChange { + option (gogoproto.goproto_stringer) = false; + + string subspace = 1; + string key = 2; + string value = 3; +} diff --git a/x/slashing/internal/keeper/test_common.go b/x/slashing/internal/keeper/test_common.go index 128c7438a7f9..60dc3946043e 100644 --- a/x/slashing/internal/keeper/test_common.go +++ b/x/slashing/internal/keeper/test_common.go @@ -90,7 +90,7 @@ func CreateTestInput(t *testing.T, defaults types.Params) (sdk.Context, bank.Kee blacklistedAddrs[notBondedPool.GetAddress().String()] = true blacklistedAddrs[bondPool.GetAddress().String()] = true - paramsKeeper := params.NewKeeper(cdc, keyParams, tkeyParams) + paramsKeeper := params.NewKeeper(params.ModuleCdc, keyParams, tkeyParams) accountKeeper := auth.NewAccountKeeper(cdc, keyAcc, paramsKeeper.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount) bk := bank.NewBaseKeeper(cdc, keyBank, accountKeeper, paramsKeeper.Subspace(bank.DefaultParamspace), blacklistedAddrs) diff --git a/x/staking/keeper/test_common.go b/x/staking/keeper/test_common.go index d24365084221..005cfbfb1ffa 100644 --- a/x/staking/keeper/test_common.go +++ b/x/staking/keeper/test_common.go @@ -116,7 +116,7 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context blacklistedAddrs[notBondedPool.GetAddress().String()] = true blacklistedAddrs[bondPool.GetAddress().String()] = true - pk := params.NewKeeper(cdc, keyParams, tkeyParams) + pk := params.NewKeeper(params.ModuleCdc, keyParams, tkeyParams) accountKeeper := auth.NewAccountKeeper( cdc, // amino codec From 07d4263cf6d8f26135af46f0bb1ed56abe0117df Mon Sep 17 00:00:00 2001 From: Marko Date: Wed, 12 Feb 2020 21:18:12 +0100 Subject: [PATCH 131/529] Merge PR #5639: fix codecov --- .codecov.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.codecov.yml b/.codecov.yml index e6009c46ada3..8fd6c94d4ad8 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -46,7 +46,7 @@ ignore: - "docs" - "*.md" - "*.rst" - - "*.pb.go" + - "**/*.pb.go" - "x/**/test_common.go" - "scripts/" - "contrib" From 242f674e7825b5130d9df9685f00fa9efafc52dd Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Thu, 13 Feb 2020 18:08:34 +0100 Subject: [PATCH 132/529] Merge PR #5640: change default path to show swagger --- CHANGELOG.md | 2 ++ client/lcd/root.go | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 54274ff56728..aa10acf3c1e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,8 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (modules) [\#5572](https://github.com/cosmos/cosmos-sdk/pull/5572) The `/bank/balances/{address}` endpoint now returns all account balances or a single balance by denom when the `denom` query parameter is present. +* (client) [\#5640](https://github.com/cosmos/cosmos-sdk/pull/5640) The rest server endpoint `/swagger-ui/` is replaced by +´/´. ### API Breaking Changes diff --git a/client/lcd/root.go b/client/lcd/root.go index af0e74b48557..12697944c006 100644 --- a/client/lcd/root.go +++ b/client/lcd/root.go @@ -105,5 +105,5 @@ func (rs *RestServer) registerSwaggerUI() { panic(err) } staticServer := http.FileServer(statikFS) - rs.Mux.PathPrefix("/swagger-ui/").Handler(http.StripPrefix("/swagger-ui/", staticServer)) + rs.Mux.PathPrefix("/").Handler(staticServer) } From 09b661d1faeac35eb07f085bcdb2f974ac3f1236 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Fri, 14 Feb 2020 12:35:25 +0000 Subject: [PATCH 133/529] Remove replace statement (#5643) Mac OS users will be presented with a warning at compile time. No actual problems are resolved by keeping the replace statement in place though. --- go.mod | 2 -- go.sum | 8 ++------ 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index e0be4a5f4f83..b2b7683f1b89 100644 --- a/go.mod +++ b/go.mod @@ -34,6 +34,4 @@ require ( replace github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.2-alpha.regen.1 -replace github.com/keybase/go-keychain => github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 - go 1.13 diff --git a/go.sum b/go.sum index 90b9290dc67e..c79f2a400a0c 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,4 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs= -github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4= -github.com/99designs/keyring v1.1.3 h1:mEV3iyZWjkxQ7R8ia8GcG97vCX5zQQ7n4o8R2BylwQY= -github.com/99designs/keyring v1.1.3/go.mod h1:657DQuMrBZRtuL/voxVyiyb6zpMehlm5vLB9Qwrv904= github.com/99designs/keyring v1.1.4 h1:x0g0zQ9bQKgNsLo0XSXAy1H8Q1RG/td+5OXJt+Ci8b8= github.com/99designs/keyring v1.1.4/go.mod h1:657DQuMrBZRtuL/voxVyiyb6zpMehlm5vLB9Qwrv904= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= @@ -109,8 +105,6 @@ github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw= -github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc= github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= @@ -141,6 +135,8 @@ github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlT github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d h1:Z+RDyXzjKE0i2sTjZ/b1uxiGtPhFy34Ou/Tk0qwN0kM= +github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d/go.mod h1:JJNrCn9otv/2QP4D7SMJBgaleKpOf66PnW6F5WGNRIc= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= From e44f9148937c8cf3de404db0a2c32ab3b88110b8 Mon Sep 17 00:00:00 2001 From: Marko Date: Fri, 14 Feb 2020 15:04:05 +0100 Subject: [PATCH 134/529] dep: bump tendermint version to 0.33.1 (#5645) * dep: bump tendermint version to 0.33.1 Signed-off-by: Marko Baricevic * minor touch up Co-authored-by: Alexander Bezobchuk --- go.mod | 2 +- go.sum | 4 ++++ x/auth/client/cli/query.go | 2 +- x/auth/client/query.go | 5 +++-- x/auth/client/rest/query.go | 2 +- x/gov/client/utils/query.go | 10 +++++----- x/gov/client/utils/query_test.go | 2 +- x/staking/client/rest/utils.go | 2 +- 8 files changed, 17 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index b2b7683f1b89..47579d904e90 100644 --- a/go.mod +++ b/go.mod @@ -27,7 +27,7 @@ require ( github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 github.com/tendermint/go-amino v0.15.1 github.com/tendermint/iavl v0.13.0 - github.com/tendermint/tendermint v0.33.0 + github.com/tendermint/tendermint v0.33.1 github.com/tendermint/tm-db v0.4.0 gopkg.in/yaml.v2 v2.2.8 ) diff --git a/go.sum b/go.sum index c79f2a400a0c..8177d91a3f08 100644 --- a/go.sum +++ b/go.sum @@ -255,6 +255,8 @@ github.com/tendermint/iavl v0.13.0 h1:r2sINvNFlJsLlLhGoqlqPlREWYkuK26BvMfkBt+XQn github.com/tendermint/iavl v0.13.0/go.mod h1:7nSUPdrsHEZ2nNZa+9gaIrcJciWd1jCQZXtcyARU82k= github.com/tendermint/tendermint v0.33.0 h1:TW1g9sQs3YSqKM8o1+opL3/VmBy4Ke/VKV9MxYpqNbI= github.com/tendermint/tendermint v0.33.0/go.mod h1:s5UoymnPIY+GcA3mMte4P9gpMP8vS7UH7HBXikT1pHI= +github.com/tendermint/tendermint v0.33.1 h1:8f68LUBz8yhISZvaLFP4siXXrLWsWeoYfelbdNtmvm4= +github.com/tendermint/tendermint v0.33.1/go.mod h1:fBOKyrlXOETqQ+heL8x/TZgSdmItON54csyabvktBp0= github.com/tendermint/tm-db v0.4.0 h1:iPbCcLbf4nwDFhS39Zo1lpdS1X/cT9CkTlUx17FHQgA= github.com/tendermint/tm-db v0.4.0/go.mod h1:+Cwhgowrf7NBGXmsqFMbwEtbo80XmyrlY5Jsk95JubQ= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= @@ -341,6 +343,8 @@ google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ij google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.26.0 h1:2dTRdpdFEEhJYQD8EMLB61nnrzSCTbG38PhqdhvOltg= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= diff --git a/x/auth/client/cli/query.go b/x/auth/client/cli/query.go index b3856c565352..af9f00b4ddc7 100644 --- a/x/auth/client/cli/query.go +++ b/x/auth/client/cli/query.go @@ -118,7 +118,7 @@ $ %s query txs --%s 'message.sender=cosmos1...&message.action=withdraw_delegator limit := viper.GetInt(flags.FlagLimit) cliCtx := context.NewCLIContext().WithCodec(cdc) - txs, err := authclient.QueryTxsByEvents(cliCtx, tmEvents, page, limit) + txs, err := authclient.QueryTxsByEvents(cliCtx, tmEvents, page, limit, "") if err != nil { return err } diff --git a/x/auth/client/query.go b/x/auth/client/query.go index 3a2c4c44f1b9..ad00ca740371 100644 --- a/x/auth/client/query.go +++ b/x/auth/client/query.go @@ -19,7 +19,8 @@ import ( // "{eventAttribute}.{attributeKey} = '{attributeValue}'". Each event is // concatenated with an 'AND' operand. It returns a slice of Info object // containing txs and metadata. An error is returned if the query fails. -func QueryTxsByEvents(cliCtx context.CLIContext, events []string, page, limit int) (*sdk.SearchTxsResult, error) { +// If an empty string is provided it will order txs by asc +func QueryTxsByEvents(cliCtx context.CLIContext, events []string, page, limit int, orderBy string) (*sdk.SearchTxsResult, error) { if len(events) == 0 { return nil, errors.New("must declare at least one event to search") } @@ -42,7 +43,7 @@ func QueryTxsByEvents(cliCtx context.CLIContext, events []string, page, limit in prove := !cliCtx.TrustNode - resTxs, err := node.TxSearch(query, prove, page, limit) + resTxs, err := node.TxSearch(query, prove, page, limit, orderBy) if err != nil { return nil, err } diff --git a/x/auth/client/rest/query.go b/x/auth/client/rest/query.go index 9662ebcc683f..44f1bbb5b0ef 100644 --- a/x/auth/client/rest/query.go +++ b/x/auth/client/rest/query.go @@ -99,7 +99,7 @@ func QueryTxsRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return } - searchResult, err := client.QueryTxsByEvents(cliCtx, events, page, limit) + searchResult, err := client.QueryTxsByEvents(cliCtx, events, page, limit, "") if err != nil { rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return diff --git a/x/gov/client/utils/query.go b/x/gov/client/utils/query.go index 840f6df899e8..0d83a9d1e975 100644 --- a/x/gov/client/utils/query.go +++ b/x/gov/client/utils/query.go @@ -45,7 +45,7 @@ func QueryDepositsByTxQuery(cliCtx context.CLIContext, params types.QueryProposa // NOTE: SearchTxs is used to facilitate the txs query which does not currently // support configurable pagination. - searchResult, err := authclient.QueryTxsByEvents(cliCtx, events, defaultPage, defaultLimit) + searchResult, err := authclient.QueryTxsByEvents(cliCtx, events, defaultPage, defaultLimit, "") if err != nil { return nil, err } @@ -88,7 +88,7 @@ func QueryVotesByTxQuery(cliCtx context.CLIContext, params types.QueryProposalVo ) // query interrupted either if we collected enough votes or tx indexer run out of relevant txs for len(votes) < totalLimit { - searchResult, err := authclient.QueryTxsByEvents(cliCtx, events, nextTxPage, defaultLimit) + searchResult, err := authclient.QueryTxsByEvents(cliCtx, events, nextTxPage, defaultLimit, "") if err != nil { return nil, err } @@ -132,7 +132,7 @@ func QueryVoteByTxQuery(cliCtx context.CLIContext, params types.QueryVoteParams) // NOTE: SearchTxs is used to facilitate the txs query which does not currently // support configurable pagination. - searchResult, err := authclient.QueryTxsByEvents(cliCtx, events, defaultPage, defaultLimit) + searchResult, err := authclient.QueryTxsByEvents(cliCtx, events, defaultPage, defaultLimit, "") if err != nil { return nil, err } @@ -171,7 +171,7 @@ func QueryDepositByTxQuery(cliCtx context.CLIContext, params types.QueryDepositP // NOTE: SearchTxs is used to facilitate the txs query which does not currently // support configurable pagination. - searchResult, err := authclient.QueryTxsByEvents(cliCtx, events, defaultPage, defaultLimit) + searchResult, err := authclient.QueryTxsByEvents(cliCtx, events, defaultPage, defaultLimit, "") if err != nil { return nil, err } @@ -210,7 +210,7 @@ func QueryProposerByTxQuery(cliCtx context.CLIContext, proposalID uint64) (Propo // NOTE: SearchTxs is used to facilitate the txs query which does not currently // support configurable pagination. - searchResult, err := authclient.QueryTxsByEvents(cliCtx, events, defaultPage, defaultLimit) + searchResult, err := authclient.QueryTxsByEvents(cliCtx, events, defaultPage, defaultLimit, "") if err != nil { return Proposer{}, err } diff --git a/x/gov/client/utils/query_test.go b/x/gov/client/utils/query_test.go index 10d4e77c7e57..eb4d71e0b061 100644 --- a/x/gov/client/utils/query_test.go +++ b/x/gov/client/utils/query_test.go @@ -21,7 +21,7 @@ type TxSearchMock struct { txs []tmtypes.Tx } -func (mock TxSearchMock) TxSearch(query string, prove bool, page, perPage int) (*ctypes.ResultTxSearch, error) { +func (mock TxSearchMock) TxSearch(query string, prove bool, page, perPage int, orderBy string) (*ctypes.ResultTxSearch, error) { start, end := client.Paginate(len(mock.txs), page, perPage, 100) if start < 0 || end < 0 { // nil result with nil error crashes utils.QueryTxsByEvents diff --git a/x/staking/client/rest/utils.go b/x/staking/client/rest/utils.go index 8b0ead70189a..80e0a54be1a4 100644 --- a/x/staking/client/rest/utils.go +++ b/x/staking/client/rest/utils.go @@ -32,7 +32,7 @@ func queryTxs(cliCtx context.CLIContext, action string, delegatorAddr string) (* fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeySender, delegatorAddr), } - return authclient.QueryTxsByEvents(cliCtx, events, page, limit) + return authclient.QueryTxsByEvents(cliCtx, events, page, limit, "") } func queryBonds(cliCtx context.CLIContext, endpoint string) http.HandlerFunc { From 05c21a534a2d7187db93220bdcbd0801de1e5cbe Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Fri, 14 Feb 2020 10:30:51 -0500 Subject: [PATCH 135/529] Merge Pr #5642: Remove x/mock --- simapp/test_helpers.go | 17 +- x/gov/abci_test.go | 226 ++++++++++++------------ x/gov/common_test.go | 93 ++++++++++ x/gov/genesis_test.go | 119 ++++++++----- x/gov/handler_test.go | 10 +- x/gov/test_common.go | 239 -------------------------- x/mock/app.go | 339 ------------------------------------ x/mock/app_test.go | 117 ------------- x/mock/doc.go | 4 - x/mock/test_utils.go | 113 ------------ x/mock/types.go | 84 --------- x/slashing/abci_test.go | 15 +- x/slashing/app_test.go | 136 +++------------ x/slashing/handler_test.go | 33 ++-- x/staking/app_test.go | 164 +++++------------- x/staking/common_test.go | 40 +++++ x/staking/handler_test.go | 340 ++++++++++++++++++++----------------- x/staking/test_common.go | 57 ------- 18 files changed, 622 insertions(+), 1524 deletions(-) create mode 100644 x/gov/common_test.go delete mode 100644 x/gov/test_common.go delete mode 100644 x/mock/app.go delete mode 100644 x/mock/app_test.go delete mode 100644 x/mock/doc.go delete mode 100644 x/mock/test_utils.go delete mode 100644 x/mock/types.go create mode 100644 x/staking/common_test.go delete mode 100644 x/staking/test_common.go diff --git a/simapp/test_helpers.go b/simapp/test_helpers.go index 3f2967e58f16..abc87ed635cc 100644 --- a/simapp/test_helpers.go +++ b/simapp/test_helpers.go @@ -16,6 +16,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" + "github.com/cosmos/cosmos-sdk/x/bank" "github.com/cosmos/cosmos-sdk/x/supply" ) @@ -43,9 +44,9 @@ func Setup(isCheckTx bool) *SimApp { return app } -// SetupWithGenesisAccounts initializes a new SimApp with the passed in -// genesis accounts. -func SetupWithGenesisAccounts(genAccs []authexported.GenesisAccount) *SimApp { +// SetupWithGenesisAccounts initializes a new SimApp with the provided genesis +// accounts and possible balances. +func SetupWithGenesisAccounts(genAccs []authexported.GenesisAccount, balances ...bank.Balance) *SimApp { db := dbm.NewMemDB() app := NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, 0) @@ -53,15 +54,16 @@ func SetupWithGenesisAccounts(genAccs []authexported.GenesisAccount) *SimApp { genesisState := NewDefaultGenesisState() authGenesis := auth.NewGenesisState(auth.DefaultParams(), genAccs) - genesisStateBz := app.Codec().MustMarshalJSON(authGenesis) - genesisState[auth.ModuleName] = genesisStateBz + genesisState[auth.ModuleName] = app.Codec().MustMarshalJSON(authGenesis) + + bankGenesis := bank.NewGenesisState(bank.DefaultGenesisState().SendEnabled, balances) + genesisState[bank.ModuleName] = app.Codec().MustMarshalJSON(bankGenesis) stateBytes, err := codec.MarshalJSONIndent(app.Codec(), genesisState) if err != nil { panic(err) } - // Initialize the chain app.InitChain( abci.RequestInitChain{ Validators: []abci.ValidatorUpdate{}, @@ -91,6 +93,9 @@ func AddTestAddrs(app *SimApp, ctx sdk.Context, accNum int, accAmt sdk.Int) []sd // fill all the addresses with some coins, set the loose pool tokens simultaneously for _, addr := range testAddrs { + acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr) + app.AccountKeeper.SetAccount(ctx, acc) + _, err := app.BankKeeper.AddCoins(ctx, addr, initCoins) if err != nil { panic(err) diff --git a/x/gov/abci_test.go b/x/gov/abci_test.go index 355abed3e84e..3e87d44e56a7 100644 --- a/x/gov/abci_test.go +++ b/x/gov/abci_test.go @@ -1,4 +1,4 @@ -package gov +package gov_test import ( "testing" @@ -7,35 +7,38 @@ import ( "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" + "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/gov" keep "github.com/cosmos/cosmos-sdk/x/gov/keeper" "github.com/cosmos/cosmos-sdk/x/staking" ) func TestTickExpiredDepositPeriod(t *testing.T) { - input := getMockApp(t, 10, GenesisState{}, nil, ProposalHandler) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + addrs := simapp.AddTestAddrs(app, ctx, 10, valTokens) - header := abci.Header{Height: input.mApp.LastBlockHeight() + 1} - input.mApp.BeginBlock(abci.RequestBeginBlock{Header: header}) + header := abci.Header{Height: app.LastBlockHeight() + 1} + app.BeginBlock(abci.RequestBeginBlock{Header: header}) - ctx := input.mApp.BaseApp.NewContext(false, abci.Header{}) - govHandler := NewHandler(input.keeper) + govHandler := gov.NewHandler(app.GovKeeper) - inactiveQueue := input.keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) + inactiveQueue := app.GovKeeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) require.False(t, inactiveQueue.Valid()) inactiveQueue.Close() - newProposalMsg := NewMsgSubmitProposal( - ContentFromProposalType("test", "test", ProposalTypeText), + newProposalMsg := gov.NewMsgSubmitProposal( + gov.ContentFromProposalType("test", "test", gov.ProposalTypeText), sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 5)}, - input.addrs[0], + addrs[0], ) res, err := govHandler(ctx, newProposalMsg) require.NoError(t, err) require.NotNil(t, res) - inactiveQueue = input.keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) + inactiveQueue = app.GovKeeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) require.False(t, inactiveQueue.Valid()) inactiveQueue.Close() @@ -43,49 +46,50 @@ func TestTickExpiredDepositPeriod(t *testing.T) { newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(1) * time.Second) ctx = ctx.WithBlockHeader(newHeader) - inactiveQueue = input.keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) + inactiveQueue = app.GovKeeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) require.False(t, inactiveQueue.Valid()) inactiveQueue.Close() newHeader = ctx.BlockHeader() - newHeader.Time = ctx.BlockHeader().Time.Add(input.keeper.GetDepositParams(ctx).MaxDepositPeriod) + newHeader.Time = ctx.BlockHeader().Time.Add(app.GovKeeper.GetDepositParams(ctx).MaxDepositPeriod) ctx = ctx.WithBlockHeader(newHeader) - inactiveQueue = input.keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) + inactiveQueue = app.GovKeeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) require.True(t, inactiveQueue.Valid()) inactiveQueue.Close() - EndBlocker(ctx, input.keeper) + gov.EndBlocker(ctx, app.GovKeeper) - inactiveQueue = input.keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) + inactiveQueue = app.GovKeeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) require.False(t, inactiveQueue.Valid()) inactiveQueue.Close() } func TestTickMultipleExpiredDepositPeriod(t *testing.T) { - input := getMockApp(t, 10, GenesisState{}, nil, ProposalHandler) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + addrs := simapp.AddTestAddrs(app, ctx, 10, valTokens) - header := abci.Header{Height: input.mApp.LastBlockHeight() + 1} - input.mApp.BeginBlock(abci.RequestBeginBlock{Header: header}) + header := abci.Header{Height: app.LastBlockHeight() + 1} + app.BeginBlock(abci.RequestBeginBlock{Header: header}) - ctx := input.mApp.BaseApp.NewContext(false, abci.Header{}) - govHandler := NewHandler(input.keeper) + govHandler := gov.NewHandler(app.GovKeeper) - inactiveQueue := input.keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) + inactiveQueue := app.GovKeeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) require.False(t, inactiveQueue.Valid()) inactiveQueue.Close() - newProposalMsg := NewMsgSubmitProposal( - ContentFromProposalType("test", "test", ProposalTypeText), + newProposalMsg := gov.NewMsgSubmitProposal( + gov.ContentFromProposalType("test", "test", gov.ProposalTypeText), sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 5)}, - input.addrs[0], + addrs[0], ) res, err := govHandler(ctx, newProposalMsg) require.NoError(t, err) require.NotNil(t, res) - inactiveQueue = input.keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) + inactiveQueue = app.GovKeeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) require.False(t, inactiveQueue.Valid()) inactiveQueue.Close() @@ -93,14 +97,14 @@ func TestTickMultipleExpiredDepositPeriod(t *testing.T) { newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(2) * time.Second) ctx = ctx.WithBlockHeader(newHeader) - inactiveQueue = input.keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) + inactiveQueue = app.GovKeeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) require.False(t, inactiveQueue.Valid()) inactiveQueue.Close() - newProposalMsg2 := NewMsgSubmitProposal( - ContentFromProposalType("test2", "test2", ProposalTypeText), + newProposalMsg2 := gov.NewMsgSubmitProposal( + gov.ContentFromProposalType("test2", "test2", gov.ProposalTypeText), sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 5)}, - input.addrs[0], + addrs[0], ) res, err = govHandler(ctx, newProposalMsg2) @@ -108,14 +112,16 @@ func TestTickMultipleExpiredDepositPeriod(t *testing.T) { require.NotNil(t, res) newHeader = ctx.BlockHeader() - newHeader.Time = ctx.BlockHeader().Time.Add(input.keeper.GetDepositParams(ctx).MaxDepositPeriod).Add(time.Duration(-1) * time.Second) + newHeader.Time = ctx.BlockHeader().Time.Add(app.GovKeeper.GetDepositParams(ctx).MaxDepositPeriod).Add(time.Duration(-1) * time.Second) ctx = ctx.WithBlockHeader(newHeader) - inactiveQueue = input.keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) + inactiveQueue = app.GovKeeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) require.True(t, inactiveQueue.Valid()) inactiveQueue.Close() - EndBlocker(ctx, input.keeper) - inactiveQueue = input.keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) + + gov.EndBlocker(ctx, app.GovKeeper) + + inactiveQueue = app.GovKeeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) require.False(t, inactiveQueue.Valid()) inactiveQueue.Close() @@ -123,44 +129,47 @@ func TestTickMultipleExpiredDepositPeriod(t *testing.T) { newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(5) * time.Second) ctx = ctx.WithBlockHeader(newHeader) - inactiveQueue = input.keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) + inactiveQueue = app.GovKeeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) require.True(t, inactiveQueue.Valid()) inactiveQueue.Close() - EndBlocker(ctx, input.keeper) - inactiveQueue = input.keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) + + gov.EndBlocker(ctx, app.GovKeeper) + + inactiveQueue = app.GovKeeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) require.False(t, inactiveQueue.Valid()) inactiveQueue.Close() } func TestTickPassedDepositPeriod(t *testing.T) { - input := getMockApp(t, 10, GenesisState{}, nil, ProposalHandler) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + addrs := simapp.AddTestAddrs(app, ctx, 10, valTokens) - header := abci.Header{Height: input.mApp.LastBlockHeight() + 1} - input.mApp.BeginBlock(abci.RequestBeginBlock{Header: header}) + header := abci.Header{Height: app.LastBlockHeight() + 1} + app.BeginBlock(abci.RequestBeginBlock{Header: header}) - ctx := input.mApp.BaseApp.NewContext(false, abci.Header{}) - govHandler := NewHandler(input.keeper) + govHandler := gov.NewHandler(app.GovKeeper) - inactiveQueue := input.keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) + inactiveQueue := app.GovKeeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) require.False(t, inactiveQueue.Valid()) inactiveQueue.Close() - activeQueue := input.keeper.ActiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) + activeQueue := app.GovKeeper.ActiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) require.False(t, activeQueue.Valid()) activeQueue.Close() - newProposalMsg := NewMsgSubmitProposal( - ContentFromProposalType("test2", "test2", ProposalTypeText), + newProposalMsg := gov.NewMsgSubmitProposal( + gov.ContentFromProposalType("test2", "test2", gov.ProposalTypeText), sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 5)}, - input.addrs[0], + addrs[0], ) res, err := govHandler(ctx, newProposalMsg) require.NoError(t, err) require.NotNil(t, res) - proposalID := GetProposalIDFromBytes(res.Data) + proposalID := gov.GetProposalIDFromBytes(res.Data) - inactiveQueue = input.keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) + inactiveQueue = app.GovKeeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) require.False(t, inactiveQueue.Valid()) inactiveQueue.Close() @@ -168,168 +177,173 @@ func TestTickPassedDepositPeriod(t *testing.T) { newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(1) * time.Second) ctx = ctx.WithBlockHeader(newHeader) - inactiveQueue = input.keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) + inactiveQueue = app.GovKeeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) require.False(t, inactiveQueue.Valid()) inactiveQueue.Close() - newDepositMsg := NewMsgDeposit(input.addrs[1], proposalID, sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 5)}) + newDepositMsg := gov.NewMsgDeposit(addrs[1], proposalID, sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 5)}) res, err = govHandler(ctx, newDepositMsg) require.NoError(t, err) require.NotNil(t, res) - activeQueue = input.keeper.ActiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) + activeQueue = app.GovKeeper.ActiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) require.False(t, activeQueue.Valid()) activeQueue.Close() } func TestTickPassedVotingPeriod(t *testing.T) { - input := getMockApp(t, 10, GenesisState{}, nil, ProposalHandler) - SortAddresses(input.addrs) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + addrs := simapp.AddTestAddrs(app, ctx, 10, valTokens) - header := abci.Header{Height: input.mApp.LastBlockHeight() + 1} - input.mApp.BeginBlock(abci.RequestBeginBlock{Header: header}) + SortAddresses(addrs) - ctx := input.mApp.BaseApp.NewContext(false, abci.Header{}) - govHandler := NewHandler(input.keeper) + header := abci.Header{Height: app.LastBlockHeight() + 1} + app.BeginBlock(abci.RequestBeginBlock{Header: header}) - inactiveQueue := input.keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) + govHandler := gov.NewHandler(app.GovKeeper) + + inactiveQueue := app.GovKeeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) require.False(t, inactiveQueue.Valid()) inactiveQueue.Close() - activeQueue := input.keeper.ActiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) + activeQueue := app.GovKeeper.ActiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) require.False(t, activeQueue.Valid()) activeQueue.Close() proposalCoins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(5))} - newProposalMsg := NewMsgSubmitProposal(keep.TestProposal, proposalCoins, input.addrs[0]) + newProposalMsg := gov.NewMsgSubmitProposal(keep.TestProposal, proposalCoins, addrs[0]) res, err := govHandler(ctx, newProposalMsg) require.NoError(t, err) require.NotNil(t, res) - proposalID := GetProposalIDFromBytes(res.Data) + proposalID := gov.GetProposalIDFromBytes(res.Data) newHeader := ctx.BlockHeader() newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(1) * time.Second) ctx = ctx.WithBlockHeader(newHeader) - newDepositMsg := NewMsgDeposit(input.addrs[1], proposalID, proposalCoins) + newDepositMsg := gov.NewMsgDeposit(addrs[1], proposalID, proposalCoins) res, err = govHandler(ctx, newDepositMsg) require.NoError(t, err) require.NotNil(t, res) newHeader = ctx.BlockHeader() - newHeader.Time = ctx.BlockHeader().Time.Add(input.keeper.GetDepositParams(ctx).MaxDepositPeriod).Add(input.keeper.GetVotingParams(ctx).VotingPeriod) + newHeader.Time = ctx.BlockHeader().Time.Add(app.GovKeeper.GetDepositParams(ctx).MaxDepositPeriod).Add(app.GovKeeper.GetVotingParams(ctx).VotingPeriod) ctx = ctx.WithBlockHeader(newHeader) - inactiveQueue = input.keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) + inactiveQueue = app.GovKeeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) require.False(t, inactiveQueue.Valid()) inactiveQueue.Close() - activeQueue = input.keeper.ActiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) + activeQueue = app.GovKeeper.ActiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) require.True(t, activeQueue.Valid()) - activeProposalID := GetProposalIDFromBytes(activeQueue.Value()) - proposal, ok := input.keeper.GetProposal(ctx, activeProposalID) + activeProposalID := gov.GetProposalIDFromBytes(activeQueue.Value()) + proposal, ok := app.GovKeeper.GetProposal(ctx, activeProposalID) require.True(t, ok) - require.Equal(t, StatusVotingPeriod, proposal.Status) + require.Equal(t, gov.StatusVotingPeriod, proposal.Status) activeQueue.Close() - EndBlocker(ctx, input.keeper) + gov.EndBlocker(ctx, app.GovKeeper) - activeQueue = input.keeper.ActiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) + activeQueue = app.GovKeeper.ActiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) require.False(t, activeQueue.Valid()) activeQueue.Close() } func TestProposalPassedEndblocker(t *testing.T) { - input := getMockApp(t, 1, GenesisState{}, nil, ProposalHandler) - SortAddresses(input.addrs) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + addrs := simapp.AddTestAddrs(app, ctx, 10, valTokens) + + SortAddresses(addrs) - handler := NewHandler(input.keeper) - stakingHandler := staking.NewHandler(input.sk) + handler := gov.NewHandler(app.GovKeeper) + stakingHandler := staking.NewHandler(app.StakingKeeper) - header := abci.Header{Height: input.mApp.LastBlockHeight() + 1} - input.mApp.BeginBlock(abci.RequestBeginBlock{Header: header}) - ctx := input.mApp.BaseApp.NewContext(false, abci.Header{}) + header := abci.Header{Height: app.LastBlockHeight() + 1} + app.BeginBlock(abci.RequestBeginBlock{Header: header}) - valAddr := sdk.ValAddress(input.addrs[0]) + valAddr := sdk.ValAddress(addrs[0]) createValidators(t, stakingHandler, ctx, []sdk.ValAddress{valAddr}, []int64{10}) - staking.EndBlocker(ctx, input.sk) + staking.EndBlocker(ctx, app.StakingKeeper) - macc := input.keeper.GetGovernanceAccount(ctx) + macc := app.GovKeeper.GetGovernanceAccount(ctx) require.NotNil(t, macc) - initialModuleAccCoins := input.bk.GetAllBalances(ctx, macc.GetAddress()) + initialModuleAccCoins := app.BankKeeper.GetAllBalances(ctx, macc.GetAddress()) - proposal, err := input.keeper.SubmitProposal(ctx, keep.TestProposal) + proposal, err := app.GovKeeper.SubmitProposal(ctx, keep.TestProposal) require.NoError(t, err) proposalCoins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(10))} - newDepositMsg := NewMsgDeposit(input.addrs[0], proposal.ProposalID, proposalCoins) + newDepositMsg := gov.NewMsgDeposit(addrs[0], proposal.ProposalID, proposalCoins) res, err := handler(ctx, newDepositMsg) require.NoError(t, err) require.NotNil(t, res) - macc = input.keeper.GetGovernanceAccount(ctx) + macc = app.GovKeeper.GetGovernanceAccount(ctx) require.NotNil(t, macc) - moduleAccCoins := input.bk.GetAllBalances(ctx, macc.GetAddress()) + moduleAccCoins := app.BankKeeper.GetAllBalances(ctx, macc.GetAddress()) deposits := initialModuleAccCoins.Add(proposal.TotalDeposit...).Add(proposalCoins...) require.True(t, moduleAccCoins.IsEqual(deposits)) - err = input.keeper.AddVote(ctx, proposal.ProposalID, input.addrs[0], OptionYes) + err = app.GovKeeper.AddVote(ctx, proposal.ProposalID, addrs[0], gov.OptionYes) require.NoError(t, err) newHeader := ctx.BlockHeader() - newHeader.Time = ctx.BlockHeader().Time.Add(input.keeper.GetDepositParams(ctx).MaxDepositPeriod).Add(input.keeper.GetVotingParams(ctx).VotingPeriod) + newHeader.Time = ctx.BlockHeader().Time.Add(app.GovKeeper.GetDepositParams(ctx).MaxDepositPeriod).Add(app.GovKeeper.GetVotingParams(ctx).VotingPeriod) ctx = ctx.WithBlockHeader(newHeader) - EndBlocker(ctx, input.keeper) + gov.EndBlocker(ctx, app.GovKeeper) - macc = input.keeper.GetGovernanceAccount(ctx) + macc = app.GovKeeper.GetGovernanceAccount(ctx) require.NotNil(t, macc) - require.True(t, input.bk.GetAllBalances(ctx, macc.GetAddress()).IsEqual(initialModuleAccCoins)) + require.True(t, app.BankKeeper.GetAllBalances(ctx, macc.GetAddress()).IsEqual(initialModuleAccCoins)) } func TestEndBlockerProposalHandlerFailed(t *testing.T) { - // hijack the router to one that will fail in a proposal's handler - input := getMockApp(t, 1, GenesisState{}, nil, badProposalHandler) - SortAddresses(input.addrs) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + addrs := simapp.AddTestAddrs(app, ctx, 1, valTokens) + + SortAddresses(addrs) - handler := NewHandler(input.keeper) - stakingHandler := staking.NewHandler(input.sk) + handler := gov.NewHandler(app.GovKeeper) + stakingHandler := staking.NewHandler(app.StakingKeeper) - header := abci.Header{Height: input.mApp.LastBlockHeight() + 1} - input.mApp.BeginBlock(abci.RequestBeginBlock{Header: header}) - ctx := input.mApp.BaseApp.NewContext(false, abci.Header{}) + header := abci.Header{Height: app.LastBlockHeight() + 1} + app.BeginBlock(abci.RequestBeginBlock{Header: header}) - valAddr := sdk.ValAddress(input.addrs[0]) + valAddr := sdk.ValAddress(addrs[0]) createValidators(t, stakingHandler, ctx, []sdk.ValAddress{valAddr}, []int64{10}) - staking.EndBlocker(ctx, input.sk) + staking.EndBlocker(ctx, app.StakingKeeper) // Create a proposal where the handler will pass for the test proposal // because the value of contextKeyBadProposal is true. ctx = ctx.WithValue(contextKeyBadProposal, true) - proposal, err := input.keeper.SubmitProposal(ctx, keep.TestProposal) + proposal, err := app.GovKeeper.SubmitProposal(ctx, keep.TestProposal) require.NoError(t, err) proposalCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(10))) - newDepositMsg := NewMsgDeposit(input.addrs[0], proposal.ProposalID, proposalCoins) + newDepositMsg := gov.NewMsgDeposit(addrs[0], proposal.ProposalID, proposalCoins) res, err := handler(ctx, newDepositMsg) require.NoError(t, err) require.NotNil(t, res) - err = input.keeper.AddVote(ctx, proposal.ProposalID, input.addrs[0], OptionYes) + err = app.GovKeeper.AddVote(ctx, proposal.ProposalID, addrs[0], gov.OptionYes) require.NoError(t, err) newHeader := ctx.BlockHeader() - newHeader.Time = ctx.BlockHeader().Time.Add(input.keeper.GetDepositParams(ctx).MaxDepositPeriod).Add(input.keeper.GetVotingParams(ctx).VotingPeriod) + newHeader.Time = ctx.BlockHeader().Time.Add(app.GovKeeper.GetDepositParams(ctx).MaxDepositPeriod).Add(app.GovKeeper.GetVotingParams(ctx).VotingPeriod) ctx = ctx.WithBlockHeader(newHeader) // Set the contextKeyBadProposal value to false so that the handler will fail @@ -337,5 +351,5 @@ func TestEndBlockerProposalHandlerFailed(t *testing.T) { ctx = ctx.WithValue(contextKeyBadProposal, false) // validate that the proposal fails/has been rejected - EndBlocker(ctx, input.keeper) + gov.EndBlocker(ctx, app.GovKeeper) } diff --git a/x/gov/common_test.go b/x/gov/common_test.go new file mode 100644 index 000000000000..79e927fd50de --- /dev/null +++ b/x/gov/common_test.go @@ -0,0 +1,93 @@ +package gov_test + +import ( + "bytes" + "log" + "sort" + "testing" + + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/crypto" + "github.com/tendermint/tendermint/crypto/ed25519" + + sdk "github.com/cosmos/cosmos-sdk/types" + keep "github.com/cosmos/cosmos-sdk/x/gov/keeper" + "github.com/cosmos/cosmos-sdk/x/staking" +) + +var ( + valTokens = sdk.TokensFromConsensusPower(42) +) + +// SortAddresses - Sorts Addresses +func SortAddresses(addrs []sdk.AccAddress) { + byteAddrs := make([][]byte, len(addrs)) + + for i, addr := range addrs { + byteAddrs[i] = addr.Bytes() + } + + SortByteArrays(byteAddrs) + + for i, byteAddr := range byteAddrs { + addrs[i] = byteAddr + } +} + +// implement `Interface` in sort package. +type sortByteArrays [][]byte + +func (b sortByteArrays) Len() int { + return len(b) +} + +func (b sortByteArrays) Less(i, j int) bool { + // bytes package already implements Comparable for []byte. + switch bytes.Compare(b[i], b[j]) { + case -1: + return true + case 0, 1: + return false + default: + log.Panic("not fail-able with `bytes.Comparable` bounded [-1, 1].") + return false + } +} + +func (b sortByteArrays) Swap(i, j int) { + b[j], b[i] = b[i], b[j] +} + +// SortByteArrays - sorts the provided byte array +func SortByteArrays(src [][]byte) [][]byte { + sorted := sortByteArrays(src) + sort.Sort(sorted) + return sorted +} + +const contextKeyBadProposal = "contextKeyBadProposal" + +var ( + pubkeys = []crypto.PubKey{ + ed25519.GenPrivKey().PubKey(), + ed25519.GenPrivKey().PubKey(), + ed25519.GenPrivKey().PubKey(), + } +) + +func createValidators(t *testing.T, stakingHandler sdk.Handler, ctx sdk.Context, addrs []sdk.ValAddress, powerAmt []int64) { + require.True(t, len(addrs) <= len(pubkeys), "Not enough pubkeys specified at top of file.") + + for i := 0; i < len(addrs); i++ { + + valTokens := sdk.TokensFromConsensusPower(powerAmt[i]) + valCreateMsg := staking.NewMsgCreateValidator( + addrs[i], pubkeys[i], sdk.NewCoin(sdk.DefaultBondDenom, valTokens), + keep.TestDescription, keep.TestCommissionRates, sdk.OneInt(), + ) + + res, err := stakingHandler(ctx, valCreateMsg) + require.NoError(t, err) + require.NotNil(t, res) + } +} diff --git a/x/gov/genesis_test.go b/x/gov/genesis_test.go index 0add3343c406..5e86d71cf731 100644 --- a/x/gov/genesis_test.go +++ b/x/gov/genesis_test.go @@ -1,95 +1,126 @@ -package gov +package gov_test import ( "testing" - keep "github.com/cosmos/cosmos-sdk/x/gov/keeper" "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/libs/log" + dbm "github.com/tendermint/tm-db" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/simapp" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/gov" + keep "github.com/cosmos/cosmos-sdk/x/gov/keeper" ) func TestImportExportQueues(t *testing.T) { - // Generate mock app and keepers - input := getMockApp(t, 2, GenesisState{}, nil, ProposalHandler) - SortAddresses(input.addrs) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + addrs := simapp.AddTestAddrs(app, ctx, 2, valTokens) + + SortAddresses(addrs) - header := abci.Header{Height: input.mApp.LastBlockHeight() + 1} - input.mApp.BeginBlock(abci.RequestBeginBlock{Header: header}) + header := abci.Header{Height: app.LastBlockHeight() + 1} + app.BeginBlock(abci.RequestBeginBlock{Header: header}) - ctx := input.mApp.BaseApp.NewContext(false, abci.Header{}) + ctx = app.BaseApp.NewContext(false, abci.Header{}) // Create two proposals, put the second into the voting period proposal := keep.TestProposal - proposal1, err := input.keeper.SubmitProposal(ctx, proposal) + proposal1, err := app.GovKeeper.SubmitProposal(ctx, proposal) require.NoError(t, err) proposalID1 := proposal1.ProposalID - proposal2, err := input.keeper.SubmitProposal(ctx, proposal) + proposal2, err := app.GovKeeper.SubmitProposal(ctx, proposal) require.NoError(t, err) proposalID2 := proposal2.ProposalID - votingStarted, err := input.keeper.AddDeposit(ctx, proposalID2, input.addrs[0], input.keeper.GetDepositParams(ctx).MinDeposit) + votingStarted, err := app.GovKeeper.AddDeposit(ctx, proposalID2, addrs[0], app.GovKeeper.GetDepositParams(ctx).MinDeposit) require.NoError(t, err) require.True(t, votingStarted) - proposal1, ok := input.keeper.GetProposal(ctx, proposalID1) + proposal1, ok := app.GovKeeper.GetProposal(ctx, proposalID1) require.True(t, ok) - proposal2, ok = input.keeper.GetProposal(ctx, proposalID2) + proposal2, ok = app.GovKeeper.GetProposal(ctx, proposalID2) require.True(t, ok) - require.True(t, proposal1.Status == StatusDepositPeriod) - require.True(t, proposal2.Status == StatusVotingPeriod) + require.True(t, proposal1.Status == gov.StatusDepositPeriod) + require.True(t, proposal2.Status == gov.StatusVotingPeriod) + + authGenState := auth.ExportGenesis(ctx, app.AccountKeeper) - genAccs := input.mApp.AccountKeeper.GetAllAccounts(ctx) + // export the state and import it into a new app + govGenState := gov.ExportGenesis(ctx, app.GovKeeper) - // Export the state and import it into a new Mock App - genState := ExportGenesis(ctx, input.keeper) - input2 := getMockApp(t, 2, genState, genAccs, ProposalHandler) + db := dbm.NewMemDB() + app2 := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, 0) + genesisState := simapp.NewDefaultGenesisState() - header = abci.Header{Height: input.mApp.LastBlockHeight() + 1} - input2.mApp.BeginBlock(abci.RequestBeginBlock{Header: header}) + genesisState[auth.ModuleName] = app.Codec().MustMarshalJSON(authGenState) + genesisState[gov.ModuleName] = app.Codec().MustMarshalJSON(govGenState) - ctx2 := input2.mApp.BaseApp.NewContext(false, abci.Header{}) + stateBytes, err := codec.MarshalJSONIndent(app2.Codec(), genesisState) + if err != nil { + panic(err) + } + + app2.InitChain( + abci.RequestInitChain{ + Validators: []abci.ValidatorUpdate{}, + AppStateBytes: stateBytes, + }, + ) + + app2.Commit() + app2.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: app2.LastBlockHeight() + 1}}) + + header = abci.Header{Height: app2.LastBlockHeight() + 1} + app2.BeginBlock(abci.RequestBeginBlock{Header: header}) + + ctx2 := app2.BaseApp.NewContext(false, abci.Header{}) // Jump the time forward past the DepositPeriod and VotingPeriod - ctx2 = ctx2.WithBlockTime(ctx2.BlockHeader().Time.Add(input2.keeper.GetDepositParams(ctx2).MaxDepositPeriod).Add(input2.keeper.GetVotingParams(ctx2).VotingPeriod)) + ctx2 = ctx2.WithBlockTime(ctx2.BlockHeader().Time.Add(app2.GovKeeper.GetDepositParams(ctx2).MaxDepositPeriod).Add(app2.GovKeeper.GetVotingParams(ctx2).VotingPeriod)) // Make sure that they are still in the DepositPeriod and VotingPeriod respectively - proposal1, ok = input2.keeper.GetProposal(ctx2, proposalID1) + proposal1, ok = app2.GovKeeper.GetProposal(ctx2, proposalID1) require.True(t, ok) - proposal2, ok = input2.keeper.GetProposal(ctx2, proposalID2) + proposal2, ok = app2.GovKeeper.GetProposal(ctx2, proposalID2) require.True(t, ok) - require.True(t, proposal1.Status == StatusDepositPeriod) - require.True(t, proposal2.Status == StatusVotingPeriod) + require.True(t, proposal1.Status == gov.StatusDepositPeriod) + require.True(t, proposal2.Status == gov.StatusVotingPeriod) - macc := input2.keeper.GetGovernanceAccount(ctx2) - require.Equal(t, input2.keeper.GetDepositParams(ctx2).MinDeposit, input2.bk.GetAllBalances(ctx2, macc.GetAddress())) + macc := app2.GovKeeper.GetGovernanceAccount(ctx2) + require.Equal(t, app2.GovKeeper.GetDepositParams(ctx2).MinDeposit, app2.BankKeeper.GetAllBalances(ctx2, macc.GetAddress())) // Run the endblocker. Check to make sure that proposal1 is removed from state, and proposal2 is finished VotingPeriod. - EndBlocker(ctx2, input2.keeper) + gov.EndBlocker(ctx2, app2.GovKeeper) - proposal1, ok = input2.keeper.GetProposal(ctx2, proposalID1) + proposal1, ok = app2.GovKeeper.GetProposal(ctx2, proposalID1) require.False(t, ok) - proposal2, ok = input2.keeper.GetProposal(ctx2, proposalID2) + + proposal2, ok = app2.GovKeeper.GetProposal(ctx2, proposalID2) require.True(t, ok) - require.True(t, proposal2.Status == StatusRejected) + require.True(t, proposal2.Status == gov.StatusRejected) } func TestEqualProposals(t *testing.T) { - // Generate mock app and keepers - input := getMockApp(t, 2, GenesisState{}, nil, ProposalHandler) - SortAddresses(input.addrs) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + addrs := simapp.AddTestAddrs(app, ctx, 2, valTokens) - header := abci.Header{Height: input.mApp.LastBlockHeight() + 1} - input.mApp.BeginBlock(abci.RequestBeginBlock{Header: header}) + SortAddresses(addrs) - ctx := input.mApp.BaseApp.NewContext(false, abci.Header{}) + header := abci.Header{Height: app.LastBlockHeight() + 1} + app.BeginBlock(abci.RequestBeginBlock{Header: header}) // Submit two proposals proposal := keep.TestProposal - proposal1, err := input.keeper.SubmitProposal(ctx, proposal) + proposal1, err := app.GovKeeper.SubmitProposal(ctx, proposal) require.NoError(t, err) - proposal2, err := input.keeper.SubmitProposal(ctx, proposal) + + proposal2, err := app.GovKeeper.SubmitProposal(ctx, proposal) require.NoError(t, err) // They are similar but their IDs should be different @@ -97,8 +128,8 @@ func TestEqualProposals(t *testing.T) { require.False(t, keep.ProposalEqual(proposal1, proposal2)) // Now create two genesis blocks - state1 := GenesisState{Proposals: []Proposal{proposal1}} - state2 := GenesisState{Proposals: []Proposal{proposal2}} + state1 := gov.GenesisState{Proposals: []gov.Proposal{proposal1}} + state2 := gov.GenesisState{Proposals: []gov.Proposal{proposal2}} require.NotEqual(t, state1, state2) require.False(t, state1.Equal(state2)) diff --git a/x/gov/handler_test.go b/x/gov/handler_test.go index 134b25ff0fc5..e52573b1e0f9 100644 --- a/x/gov/handler_test.go +++ b/x/gov/handler_test.go @@ -1,19 +1,19 @@ -package gov +package gov_test import ( "strings" "testing" + "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/stretchr/testify/require" + "github.com/cosmos/cosmos-sdk/x/gov" ) func TestInvalidMsg(t *testing.T) { - k := Keeper{} - h := NewHandler(k) + k := gov.Keeper{} + h := gov.NewHandler(k) res, err := h(sdk.NewContext(nil, abci.Header{}, false, nil), sdk.NewTestMsg()) require.Error(t, err) diff --git a/x/gov/test_common.go b/x/gov/test_common.go deleted file mode 100644 index a01a79c6566d..000000000000 --- a/x/gov/test_common.go +++ /dev/null @@ -1,239 +0,0 @@ -// nolint -// DONTCOVER -package gov - -import ( - "bytes" - "errors" - "log" - "sort" - "testing" - - "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/crypto/ed25519" - - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/crypto" - - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" - "github.com/cosmos/cosmos-sdk/x/bank" - bankexported "github.com/cosmos/cosmos-sdk/x/bank/exported" - keep "github.com/cosmos/cosmos-sdk/x/gov/keeper" - "github.com/cosmos/cosmos-sdk/x/gov/types" - "github.com/cosmos/cosmos-sdk/x/mock" - "github.com/cosmos/cosmos-sdk/x/staking" - "github.com/cosmos/cosmos-sdk/x/supply" - supplyexported "github.com/cosmos/cosmos-sdk/x/supply/exported" -) - -var ( - valTokens = sdk.TokensFromConsensusPower(42) - initTokens = sdk.TokensFromConsensusPower(100000) - valCoins = sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, valTokens)) - initCoins = sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initTokens)) -) - -type testInput struct { - mApp *mock.App - keeper keep.Keeper - router types.Router - bk bank.Keeper - sk staking.Keeper - addrs []sdk.AccAddress - pubKeys []crypto.PubKey - privKeys []crypto.PrivKey -} - -func getMockApp( - t *testing.T, numGenAccs int, genState types.GenesisState, genAccs []authexported.Account, - handler func(ctx sdk.Context, c types.Content) error, -) testInput { - - mApp := mock.NewApp() - - staking.RegisterCodec(mApp.Cdc) - types.RegisterCodec(mApp.Cdc) - supply.RegisterCodec(mApp.Cdc) - - keyStaking := sdk.NewKVStoreKey(staking.StoreKey) - keyGov := sdk.NewKVStoreKey(types.StoreKey) - keySupply := sdk.NewKVStoreKey(supply.StoreKey) - - govAcc := supply.NewEmptyModuleAccount(types.ModuleName, supply.Burner) - notBondedPool := supply.NewEmptyModuleAccount(staking.NotBondedPoolName, supply.Burner, supply.Staking) - bondPool := supply.NewEmptyModuleAccount(staking.BondedPoolName, supply.Burner, supply.Staking) - - blacklistedAddrs := make(map[string]bool) - blacklistedAddrs[govAcc.GetAddress().String()] = true - blacklistedAddrs[notBondedPool.GetAddress().String()] = true - blacklistedAddrs[bondPool.GetAddress().String()] = true - - rtr := types.NewRouter().AddRoute(types.RouterKey, handler) - maccPerms := map[string][]string{ - types.ModuleName: {supply.Burner}, - staking.NotBondedPoolName: {supply.Burner, supply.Staking}, - staking.BondedPoolName: {supply.Burner, supply.Staking}, - } - - pk := mApp.ParamsKeeper - bk := mApp.BankKeeper - supplyKeeper := supply.NewKeeper(mApp.Cdc, keySupply, mApp.AccountKeeper, bk, maccPerms) - sk := staking.NewKeeper( - staking.ModuleCdc, keyStaking, bk, supplyKeeper, pk.Subspace(staking.DefaultParamspace), - ) - - keeper := keep.NewKeeper( - mApp.Cdc, keyGov, pk.Subspace(DefaultParamspace).WithKeyTable(ParamKeyTable()), supplyKeeper, sk, rtr, - ) - - mApp.Router().AddRoute(types.RouterKey, NewHandler(keeper)) - mApp.QueryRouter().AddRoute(types.QuerierRoute, keep.NewQuerier(keeper)) - - mApp.SetEndBlocker(getEndBlocker(keeper)) - mApp.SetInitChainer(getInitChainer(mApp, bk, keeper, sk, supplyKeeper, genAccs, genState, - []supplyexported.ModuleAccountI{govAcc, notBondedPool, bondPool})) - - require.NoError(t, mApp.CompleteSetup(keyStaking, keyGov, keySupply)) - - var ( - genBalances []bankexported.GenesisBalance - addrs []sdk.AccAddress - pubKeys []crypto.PubKey - privKeys []crypto.PrivKey - ) - - if genAccs == nil || len(genAccs) == 0 { - genAccs, genBalances, addrs, pubKeys, privKeys = mock.CreateGenAccounts(numGenAccs, valCoins) - } - - mock.SetGenesis(mApp, genAccs, genBalances) - - return testInput{mApp, keeper, rtr, bk, sk, addrs, pubKeys, privKeys} -} - -// gov and staking endblocker -func getEndBlocker(keeper Keeper) sdk.EndBlocker { - return func(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock { - EndBlocker(ctx, keeper) - return abci.ResponseEndBlock{} - } -} - -// gov and staking initchainer -func getInitChainer(mapp *mock.App, bk types.BankKeeper, keeper Keeper, stakingKeeper staking.Keeper, supplyKeeper supply.Keeper, accs []authexported.Account, genState GenesisState, - blacklistedAddrs []supplyexported.ModuleAccountI) sdk.InitChainer { - return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { - mapp.InitChainer(ctx, req) - - stakingGenesis := staking.DefaultGenesisState() - - totalSupply := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initTokens.MulRaw(int64(len(mapp.GenesisAccounts))))) - supplyKeeper.SetSupply(ctx, supply.NewSupply(totalSupply)) - - // set module accounts - for _, macc := range blacklistedAddrs { - supplyKeeper.SetModuleAccount(ctx, macc) - } - - validators := staking.InitGenesis(ctx, stakingKeeper, mapp.AccountKeeper, bk, supplyKeeper, stakingGenesis) - if genState.IsEmpty() { - InitGenesis(ctx, bk, supplyKeeper, keeper, types.DefaultGenesisState()) - } else { - InitGenesis(ctx, bk, supplyKeeper, keeper, genState) - } - return abci.ResponseInitChain{ - Validators: validators, - } - } -} - -// SortAddresses - Sorts Addresses -func SortAddresses(addrs []sdk.AccAddress) { - var byteAddrs [][]byte - for _, addr := range addrs { - byteAddrs = append(byteAddrs, addr.Bytes()) - } - SortByteArrays(byteAddrs) - for i, byteAddr := range byteAddrs { - addrs[i] = byteAddr - } -} - -// implement `Interface` in sort package. -type sortByteArrays [][]byte - -func (b sortByteArrays) Len() int { - return len(b) -} - -func (b sortByteArrays) Less(i, j int) bool { - // bytes package already implements Comparable for []byte. - switch bytes.Compare(b[i], b[j]) { - case -1: - return true - case 0, 1: - return false - default: - log.Panic("not fail-able with `bytes.Comparable` bounded [-1, 1].") - return false - } -} - -func (b sortByteArrays) Swap(i, j int) { - b[j], b[i] = b[i], b[j] -} - -// SortByteArrays - sorts the provided byte array -func SortByteArrays(src [][]byte) [][]byte { - sorted := sortByteArrays(src) - sort.Sort(sorted) - return sorted -} - -const contextKeyBadProposal = "contextKeyBadProposal" - -// badProposalHandler implements a governance proposal handler that is identical -// to the actual handler except this fails if the context doesn't contain a value -// for the key contextKeyBadProposal or if the value is false. -func badProposalHandler(ctx sdk.Context, c types.Content) error { - switch c.ProposalType() { - case types.ProposalTypeText: - v := ctx.Value(contextKeyBadProposal) - - if v == nil || !v.(bool) { - return errors.New("proposal failed") - } - - return nil - - default: - return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized gov proposal type: %s", c.ProposalType()) - } -} - -var ( - pubkeys = []crypto.PubKey{ - ed25519.GenPrivKey().PubKey(), - ed25519.GenPrivKey().PubKey(), - ed25519.GenPrivKey().PubKey(), - } -) - -func createValidators(t *testing.T, stakingHandler sdk.Handler, ctx sdk.Context, addrs []sdk.ValAddress, powerAmt []int64) { - require.True(t, len(addrs) <= len(pubkeys), "Not enough pubkeys specified at top of file.") - - for i := 0; i < len(addrs); i++ { - - valTokens := sdk.TokensFromConsensusPower(powerAmt[i]) - valCreateMsg := staking.NewMsgCreateValidator( - addrs[i], pubkeys[i], sdk.NewCoin(sdk.DefaultBondDenom, valTokens), - keep.TestDescription, keep.TestCommissionRates, sdk.OneInt(), - ) - - res, err := stakingHandler(ctx, valCreateMsg) - require.NoError(t, err) - require.NotNil(t, res) - } -} diff --git a/x/mock/app.go b/x/mock/app.go deleted file mode 100644 index d541b138e211..000000000000 --- a/x/mock/app.go +++ /dev/null @@ -1,339 +0,0 @@ -package mock - -import ( - "bytes" - "fmt" - "math/rand" - "os" - "sort" - - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/crypto" - "github.com/tendermint/tendermint/crypto/ed25519" - "github.com/tendermint/tendermint/crypto/secp256k1" - "github.com/tendermint/tendermint/libs/log" - dbm "github.com/tendermint/tm-db" - - bam "github.com/cosmos/cosmos-sdk/baseapp" - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth" - authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" - "github.com/cosmos/cosmos-sdk/x/bank" - bankexported "github.com/cosmos/cosmos-sdk/x/bank/exported" - "github.com/cosmos/cosmos-sdk/x/params" -) - -const chainID = "" - -// App extends an ABCI application, but with most of its parameters exported. -// They are exported for convenience in creating helper functions, as object -// capabilities aren't needed for testing. -type App struct { - *bam.BaseApp - Cdc *codec.Codec // Cdc is public since the codec is passed into the module anyways - KeyMain *sdk.KVStoreKey - KeyAccount *sdk.KVStoreKey - KeyBank *sdk.KVStoreKey - KeyParams *sdk.KVStoreKey - TKeyParams *sdk.TransientStoreKey - - // TODO: Abstract this out from not needing to be auth specifically - AccountKeeper auth.AccountKeeper - BankKeeper bank.Keeper - ParamsKeeper params.Keeper - - GenesisAccounts []authexported.Account - GenesisBalances []bankexported.GenesisBalance - TotalCoinsSupply sdk.Coins -} - -// NewApp partially constructs a new app on the memstore for module and genesis -// testing. -func NewApp() *App { - logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "sdk/app") - db := dbm.NewMemDB() - - // Create the cdc with some standard codecs - cdc := createCodec() - - // Create your application object - app := &App{ - BaseApp: bam.NewBaseApp("mock", logger, db, auth.DefaultTxDecoder(cdc)), - Cdc: cdc, - KeyMain: sdk.NewKVStoreKey(bam.MainStoreKey), - KeyAccount: sdk.NewKVStoreKey(auth.StoreKey), - KeyBank: sdk.NewKVStoreKey(bank.StoreKey), - KeyParams: sdk.NewKVStoreKey("params"), - TKeyParams: sdk.NewTransientStoreKey("transient_params"), - TotalCoinsSupply: sdk.NewCoins(), - } - - app.ParamsKeeper = params.NewKeeper(params.ModuleCdc, app.KeyParams, app.TKeyParams) - app.AccountKeeper = auth.NewAccountKeeper( - app.Cdc, - app.KeyAccount, - app.ParamsKeeper.Subspace(auth.DefaultParamspace), - auth.ProtoBaseAccount, - ) - app.BankKeeper = bank.NewBaseKeeper( - app.Cdc, - app.KeyBank, - app.AccountKeeper, - app.ParamsKeeper.Subspace(bank.DefaultParamspace), - make(map[string]bool), - ) - supplyKeeper := NewDummySupplyKeeper(app.AccountKeeper, app.BankKeeper) - - // Initialize the app. The chainers and blockers can be overwritten before - // calling complete setup. - app.SetInitChainer(app.InitChainer) - app.SetAnteHandler(auth.NewAnteHandler(app.AccountKeeper, supplyKeeper, auth.DefaultSigVerificationGasConsumer)) - - // not sealing for custom extension - return app -} - -// CompleteSetup completes the application setup after the routes have been -// registered. -func (app *App) CompleteSetup(newKeys ...sdk.StoreKey) error { - newKeys = append( - newKeys, - app.KeyMain, app.KeyAccount, app.KeyBank, app.KeyParams, app.TKeyParams, - ) - - for _, key := range newKeys { - switch key.(type) { - case *sdk.KVStoreKey: - app.MountStore(key, sdk.StoreTypeIAVL) - - case *sdk.TransientStoreKey: - app.MountStore(key, sdk.StoreTypeTransient) - - default: - return fmt.Errorf("unsupported StoreKey: %+v", key) - } - } - - err := app.LoadLatestVersion(app.KeyMain) - - return err -} - -// InitChainer performs custom logic for initialization. -func (app *App) InitChainer(ctx sdk.Context, _ abci.RequestInitChain) abci.ResponseInitChain { - for _, genacc := range app.GenesisAccounts { - acc := app.AccountKeeper.NewAccountWithAddress(ctx, genacc.GetAddress()) - app.AccountKeeper.SetAccount(ctx, acc) - } - - for _, balance := range app.GenesisBalances { - app.BankKeeper.SetBalances(ctx, balance.GetAddress(), balance.GetCoins()) - } - - auth.InitGenesis(ctx, app.AccountKeeper, auth.DefaultGenesisState()) - bank.InitGenesis(ctx, app.BankKeeper, bank.DefaultGenesisState()) - - return abci.ResponseInitChain{} -} - -// Type that combines an Address with the privKey and pubKey to that address -type AddrKeys struct { - Address sdk.AccAddress - PubKey crypto.PubKey - PrivKey crypto.PrivKey -} - -func NewAddrKeys(address sdk.AccAddress, pubKey crypto.PubKey, - privKey crypto.PrivKey) AddrKeys { - - return AddrKeys{ - Address: address, - PubKey: pubKey, - PrivKey: privKey, - } -} - -// implement `Interface` in sort package. -type AddrKeysSlice []AddrKeys - -func (b AddrKeysSlice) Len() int { - return len(b) -} - -// Sorts lexographically by Address -func (b AddrKeysSlice) Less(i, j int) bool { - // bytes package already implements Comparable for []byte. - switch bytes.Compare(b[i].Address.Bytes(), b[j].Address.Bytes()) { - case -1: - return true - case 0, 1: - return false - default: - panic("not fail-able with `bytes.Comparable` bounded [-1, 1].") - } -} - -func (b AddrKeysSlice) Swap(i, j int) { - b[j], b[i] = b[i], b[j] -} - -// CreateGenAccounts generates genesis accounts loaded with coins, and returns -// their addresses, pubkeys, and privkeys. -func CreateGenAccounts(numAccs int, genCoins sdk.Coins) ( - genAccs []authexported.Account, genBalances []bankexported.GenesisBalance, - addrs []sdk.AccAddress, pubKeys []crypto.PubKey, privKeys []crypto.PrivKey, -) { - - addrKeysSlice := AddrKeysSlice{} - - for i := 0; i < numAccs; i++ { - privKey := secp256k1.GenPrivKey() - pubKey := privKey.PubKey() - addr := sdk.AccAddress(pubKey.Address()) - - addrKeysSlice = append(addrKeysSlice, NewAddrKeys(addr, pubKey, privKey)) - } - - sort.Sort(addrKeysSlice) - - for i := range addrKeysSlice { - addrs = append(addrs, addrKeysSlice[i].Address) - pubKeys = append(pubKeys, addrKeysSlice[i].PubKey) - privKeys = append(privKeys, addrKeysSlice[i].PrivKey) - genAccs = append(genAccs, &auth.BaseAccount{ - Address: addrKeysSlice[i].Address, - }) - genBalances = append(genBalances, bank.Balance{ - Address: addrKeysSlice[i].Address, - Coins: genCoins, - }) - } - - return // nolint -} - -// SetGenesis sets the mock app genesis accounts. -func SetGenesis(app *App, accs []authexported.Account, balances []bankexported.GenesisBalance) { - // Pass the accounts in via the application (lazy) instead of through - // RequestInitChain. - app.GenesisAccounts = accs - app.GenesisBalances = balances - - app.InitChain(abci.RequestInitChain{}) - app.Commit() -} - -// GenTx generates a signed mock transaction. -func GenTx(msgs []sdk.Msg, accnums []uint64, seq []uint64, priv ...crypto.PrivKey) auth.StdTx { - // Make the transaction free - fee := auth.StdFee{ - Amount: sdk.NewCoins(sdk.NewInt64Coin("foocoin", 0)), - Gas: 100000, - } - - sigs := make([]auth.StdSignature, len(priv)) - memo := "testmemotestmemo" - - for i, p := range priv { - sig, err := p.Sign(auth.StdSignBytes(chainID, accnums[i], seq[i], fee, msgs, memo)) - if err != nil { - panic(err) - } - - sigs[i] = auth.StdSignature{ - PubKey: p.PubKey(), - Signature: sig, - } - } - - return auth.NewStdTx(msgs, fee, sigs, memo) -} - -// GeneratePrivKeys generates a total n secp256k1 private keys. -func GeneratePrivKeys(n int) (keys []crypto.PrivKey) { - // TODO: Randomize this between ed25519 and secp256k1 - keys = make([]crypto.PrivKey, n) - for i := 0; i < n; i++ { - keys[i] = secp256k1.GenPrivKey() - } - - return -} - -// GeneratePrivKeyAddressPairs generates a total of n private key, address -// pairs. -func GeneratePrivKeyAddressPairs(n int) (keys []crypto.PrivKey, addrs []sdk.AccAddress) { - keys = make([]crypto.PrivKey, n) - addrs = make([]sdk.AccAddress, n) - for i := 0; i < n; i++ { - if rand.Int63()%2 == 0 { - keys[i] = secp256k1.GenPrivKey() - } else { - keys[i] = ed25519.GenPrivKey() - } - addrs[i] = sdk.AccAddress(keys[i].PubKey().Address()) - } - return -} - -// GeneratePrivKeyAddressPairsFromRand generates a total of n private key, address -// pairs using the provided randomness source. -func GeneratePrivKeyAddressPairsFromRand(rand *rand.Rand, n int) (keys []crypto.PrivKey, addrs []sdk.AccAddress) { - keys = make([]crypto.PrivKey, n) - addrs = make([]sdk.AccAddress, n) - for i := 0; i < n; i++ { - secret := make([]byte, 32) - _, err := rand.Read(secret) - if err != nil { - panic("Could not read randomness") - } - if rand.Int63()%2 == 0 { - keys[i] = secp256k1.GenPrivKeySecp256k1(secret) - } else { - keys[i] = ed25519.GenPrivKeyFromSecret(secret) - } - addrs[i] = sdk.AccAddress(keys[i].PubKey().Address()) - } - return -} - -// RandomSetGenesis set genesis accounts with random coin values using the -// provided addresses and coin denominations. -func RandomSetGenesis(r *rand.Rand, app *App, addrs []sdk.AccAddress, denoms []string) { - accounts := make([]authexported.Account, len(addrs)) - balances := make([]bankexported.GenesisBalance, len(addrs)) - randCoinIntervals := []BigInterval{ - {sdk.NewIntWithDecimal(1, 0), sdk.NewIntWithDecimal(1, 1)}, - {sdk.NewIntWithDecimal(1, 2), sdk.NewIntWithDecimal(1, 3)}, - {sdk.NewIntWithDecimal(1, 40), sdk.NewIntWithDecimal(1, 50)}, - } - - for i := 0; i < len(accounts); i++ { - coins := make([]sdk.Coin, len(denoms)) - - // generate a random coin for each denomination - for j := 0; j < len(denoms); j++ { - coins[j] = sdk.Coin{Denom: denoms[j], - Amount: RandFromBigInterval(r, randCoinIntervals), - } - } - - app.TotalCoinsSupply = app.TotalCoinsSupply.Add(coins...) - baseAcc := auth.NewBaseAccountWithAddress(addrs[i]) - - accounts[i] = &baseAcc - balances[i] = bank.Balance{Address: addrs[i], Coins: coins} - } - - app.GenesisAccounts = accounts - app.GenesisBalances = balances -} - -func createCodec() *codec.Codec { - cdc := codec.New() - sdk.RegisterCodec(cdc) - codec.RegisterCrypto(cdc) - auth.RegisterCodec(cdc) - return cdc -} diff --git a/x/mock/app_test.go b/x/mock/app_test.go deleted file mode 100644 index 44b979405535..000000000000 --- a/x/mock/app_test.go +++ /dev/null @@ -1,117 +0,0 @@ -package mock - -import ( - "testing" - - "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" - - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/supply/exported" -) - -const msgRoute = "testMsg" - -var ( - numAccts = 2 - genCoins = sdk.Coins{sdk.NewInt64Coin("foocoin", 77)} - accs, balances, addrs, _, privKeys = CreateGenAccounts(numAccts, genCoins) -) - -// testMsg is a mock transaction that has a validation which can fail. -type testMsg struct { - signers []sdk.AccAddress - positiveNum int64 -} - -func (tx testMsg) Route() string { return msgRoute } -func (tx testMsg) Type() string { return "test" } -func (tx testMsg) GetMsg() sdk.Msg { return tx } -func (tx testMsg) GetMemo() string { return "" } -func (tx testMsg) GetSignBytes() []byte { return nil } -func (tx testMsg) GetSigners() []sdk.AccAddress { return tx.signers } -func (tx testMsg) GetSignatures() []auth.StdSignature { return nil } -func (tx testMsg) ValidateBasic() error { - if tx.positiveNum >= 0 { - return nil - } - return sdkerrors.Wrap(sdkerrors.ErrTxDecode, "positiveNum should be a non-negative integer") -} - -// getMockApp returns an initialized mock application. -func getMockApp(t *testing.T) *App { - mApp := NewApp() - - mApp.Router().AddRoute(msgRoute, func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { - return &sdk.Result{}, nil - }) - require.NoError(t, mApp.CompleteSetup()) - - return mApp -} - -func TestCheckAndDeliverGenTx(t *testing.T) { - mApp := getMockApp(t) - mApp.Cdc.RegisterConcrete(testMsg{}, "mock/testMsg", nil) - mApp.Cdc.RegisterInterface((*exported.ModuleAccountI)(nil), nil) - - SetGenesis(mApp, accs, balances) - ctxCheck := mApp.BaseApp.NewContext(true, abci.Header{}) - - msg := testMsg{signers: []sdk.AccAddress{addrs[0]}, positiveNum: 1} - - acct := mApp.AccountKeeper.GetAccount(ctxCheck, addrs[0]) - require.Equal(t, accs[0], acct.(*auth.BaseAccount)) - - header := abci.Header{Height: mApp.LastBlockHeight() + 1} - SignCheckDeliver( - t, mApp.Cdc, mApp.BaseApp, header, []sdk.Msg{msg}, - []uint64{accs[0].GetAccountNumber()}, []uint64{accs[0].GetSequence()}, - true, true, privKeys[0], - ) - - // Signing a tx with the wrong privKey should result in an auth error - header = abci.Header{Height: mApp.LastBlockHeight() + 1} - _, _, err := SignCheckDeliver( - t, mApp.Cdc, mApp.BaseApp, header, []sdk.Msg{msg}, - []uint64{accs[1].GetAccountNumber()}, []uint64{accs[1].GetSequence() + 1}, - true, false, privKeys[1], - ) - - // Will fail on SetPubKey decorator - space, code, log := sdkerrors.ABCIInfo(err, false) - require.Equal(t, sdkerrors.ErrInvalidPubKey.ABCICode(), code, log) - require.Equal(t, sdkerrors.ErrInvalidPubKey.Codespace(), space) - - // Resigning the tx with the correct privKey should result in an OK result - header = abci.Header{Height: mApp.LastBlockHeight() + 1} - SignCheckDeliver( - t, mApp.Cdc, mApp.BaseApp, header, []sdk.Msg{msg}, - []uint64{accs[0].GetAccountNumber()}, []uint64{accs[0].GetSequence() + 1}, - true, true, privKeys[0], - ) -} - -func TestCheckGenTx(t *testing.T) { - mApp := getMockApp(t) - mApp.Cdc.RegisterConcrete(testMsg{}, "mock/testMsg", nil) - mApp.Cdc.RegisterInterface((*exported.ModuleAccountI)(nil), nil) - - SetGenesis(mApp, accs, balances) - - msg1 := testMsg{signers: []sdk.AccAddress{addrs[0]}, positiveNum: 1} - CheckGenTx( - t, mApp.BaseApp, []sdk.Msg{msg1}, - []uint64{accs[0].GetAccountNumber()}, []uint64{accs[0].GetSequence()}, - true, privKeys[0], - ) - - msg2 := testMsg{signers: []sdk.AccAddress{addrs[0]}, positiveNum: -1} - CheckGenTx( - t, mApp.BaseApp, []sdk.Msg{msg2}, - []uint64{accs[0].GetAccountNumber()}, []uint64{accs[0].GetSequence()}, - false, privKeys[0], - ) -} diff --git a/x/mock/doc.go b/x/mock/doc.go deleted file mode 100644 index 139cd87a5e97..000000000000 --- a/x/mock/doc.go +++ /dev/null @@ -1,4 +0,0 @@ -/* -Package mock provides utility methods to ease writing tests. -*/ -package mock diff --git a/x/mock/test_utils.go b/x/mock/test_utils.go deleted file mode 100644 index cece7051ed25..000000000000 --- a/x/mock/test_utils.go +++ /dev/null @@ -1,113 +0,0 @@ -package mock - -import ( - "math/big" - "math/rand" - "testing" - - "github.com/cosmos/cosmos-sdk/codec" - - "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/crypto" - - "github.com/cosmos/cosmos-sdk/baseapp" - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// BigInterval is a representation of the interval [lo, hi), where -// lo and hi are both of type sdk.Int -type BigInterval struct { - lo sdk.Int - hi sdk.Int -} - -// RandFromBigInterval chooses an interval uniformly from the provided list of -// BigIntervals, and then chooses an element from an interval uniformly at random. -func RandFromBigInterval(r *rand.Rand, intervals []BigInterval) sdk.Int { - if len(intervals) == 0 { - return sdk.ZeroInt() - } - - interval := intervals[r.Intn(len(intervals))] - - lo := interval.lo - hi := interval.hi - - diff := hi.Sub(lo) - result := sdk.NewIntFromBigInt(new(big.Int).Rand(r, diff.BigInt())) - result = result.Add(lo) - - return result -} - -// CheckBalance checks the balance of an account. -func CheckBalance(t *testing.T, app *App, addr sdk.AccAddress, balance sdk.Coins) { - ctxCheck := app.BaseApp.NewContext(true, abci.Header{}) - require.Equal(t, balance, app.BankKeeper.GetAllBalances(ctxCheck, addr)) -} - -// CheckGenTx checks a generated signed transaction. The result of the check is -// compared against the parameter 'expPass'. A test assertion is made using the -// parameter 'expPass' against the result. A corresponding result is returned. -func CheckGenTx( - t *testing.T, app *baseapp.BaseApp, msgs []sdk.Msg, accNums []uint64, - seq []uint64, expPass bool, priv ...crypto.PrivKey, -) (sdk.GasInfo, *sdk.Result, error) { - tx := GenTx(msgs, accNums, seq, priv...) - gInfo, res, err := app.Check(tx) - - if expPass { - require.NoError(t, err) - require.NotNil(t, res) - } else { - require.Error(t, err) - require.Nil(t, res) - } - - return gInfo, res, err -} - -// SignCheckDeliver checks a generated signed transaction and simulates a -// block commitment with the given transaction. A test assertion is made using -// the parameter 'expPass' against the result. A corresponding result is -// returned. -func SignCheckDeliver( - t *testing.T, cdc *codec.Codec, app *baseapp.BaseApp, header abci.Header, msgs []sdk.Msg, - accNums, seq []uint64, expSimPass, expPass bool, priv ...crypto.PrivKey, -) (sdk.GasInfo, *sdk.Result, error) { - - tx := GenTx(msgs, accNums, seq, priv...) - - txBytes, err := cdc.MarshalBinaryLengthPrefixed(tx) - require.Nil(t, err) - - // Must simulate now as CheckTx doesn't run Msgs anymore - _, res, err := app.Simulate(txBytes, tx) - - if expSimPass { - require.NoError(t, err) - require.NotNil(t, res) - } else { - require.Error(t, err) - require.Nil(t, res) - } - - // Simulate a sending a transaction and committing a block - app.BeginBlock(abci.RequestBeginBlock{Header: header}) - - gInfo, res, err := app.Deliver(tx) - - if expPass { - require.NoError(t, err) - require.NotNil(t, res) - } else { - require.Error(t, err) - require.Nil(t, res) - } - - app.EndBlock(abci.RequestEndBlock{}) - app.Commit() - - return gInfo, res, err -} diff --git a/x/mock/types.go b/x/mock/types.go deleted file mode 100644 index aed4a6c97f35..000000000000 --- a/x/mock/types.go +++ /dev/null @@ -1,84 +0,0 @@ -package mock - -import ( - "github.com/tendermint/tendermint/crypto" - - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/bank" - "github.com/cosmos/cosmos-sdk/x/supply" - "github.com/cosmos/cosmos-sdk/x/supply/exported" -) - -// DummySupplyKeeper defines a supply keeper used only for testing to avoid -// circle dependencies -type DummySupplyKeeper struct { - ak auth.AccountKeeper - bk bank.Keeper -} - -// NewDummySupplyKeeper creates a DummySupplyKeeper instance -func NewDummySupplyKeeper(ak auth.AccountKeeper, bk bank.Keeper) DummySupplyKeeper { - return DummySupplyKeeper{ak, bk} -} - -// SendCoinsFromAccountToModule for the dummy supply keeper -func (sk DummySupplyKeeper) SendCoinsFromAccountToModule(ctx sdk.Context, fromAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error { - fromAcc := sk.ak.GetAccount(ctx, fromAddr) - moduleAcc := sk.GetModuleAccount(ctx, recipientModule) - fromBalances := sk.bk.GetAllBalances(ctx, fromAcc.GetAddress()) - - newFromCoins, hasNeg := fromBalances.SafeSub(amt) - if hasNeg { - return sdkerrors.Wrap(sdkerrors.ErrInsufficientFunds, fromBalances.String()) - } - - toBalances := sk.bk.GetAllBalances(ctx, moduleAcc.GetAddress()) - newToCoins := toBalances.Add(amt...) - - if err := sk.bk.SetBalances(ctx, fromAcc.GetAddress(), newFromCoins); err != nil { - return err - } - - if err := sk.bk.SetBalances(ctx, moduleAcc.GetAddress(), newToCoins); err != nil { - return err - } - - sk.ak.SetAccount(ctx, fromAcc) - sk.ak.SetAccount(ctx, moduleAcc) - - return nil -} - -// GetModuleAccount for dummy supply keeper -func (sk DummySupplyKeeper) GetModuleAccount(ctx sdk.Context, moduleName string) exported.ModuleAccountI { - addr := sk.GetModuleAddress(moduleName) - - acc := sk.ak.GetAccount(ctx, addr) - if acc != nil { - macc, ok := acc.(exported.ModuleAccountI) - if ok { - return macc - } - } - - moduleAddress := sk.GetModuleAddress(moduleName) - baseAcc := auth.NewBaseAccountWithAddress(moduleAddress) - - // create a new module account - macc := &supply.ModuleAccount{ - BaseAccount: &baseAcc, - Name: moduleName, - Permissions: nil, - } - - maccI := (sk.ak.NewAccount(ctx, macc)).(exported.ModuleAccountI) - sk.ak.SetAccount(ctx, maccI) - return maccI -} - -// GetModuleAddress for dummy supply keeper -func (sk DummySupplyKeeper) GetModuleAddress(moduleName string) sdk.AccAddress { - return sdk.AccAddress(crypto.AddressHash([]byte(moduleName))) -} diff --git a/x/slashing/abci_test.go b/x/slashing/abci_test.go index a2138479f2c6..a6a14c885b3d 100644 --- a/x/slashing/abci_test.go +++ b/x/slashing/abci_test.go @@ -1,20 +1,20 @@ -package slashing +package slashing_test import ( "testing" "time" "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/slashing" slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/internal/keeper" "github.com/cosmos/cosmos-sdk/x/staking" ) func TestBeginBlocker(t *testing.T) { - ctx, bk, sk, _, keeper := slashingkeeper.CreateTestInput(t, DefaultParams()) + ctx, bk, sk, _, keeper := slashingkeeper.CreateTestInput(t, slashing.DefaultParams()) power := int64(100) amt := sdk.TokensFromConsensusPower(power) addr, pk := slashingkeeper.Addrs[2], slashingkeeper.Pks[2] @@ -45,7 +45,8 @@ func TestBeginBlocker(t *testing.T) { }}, }, } - BeginBlocker(ctx, req, keeper) + + slashing.BeginBlocker(ctx, req, keeper) info, found := keeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(pk.Address())) require.True(t, found) @@ -67,7 +68,8 @@ func TestBeginBlocker(t *testing.T) { }}, }, } - BeginBlocker(ctx, req, keeper) + + slashing.BeginBlocker(ctx, req, keeper) } // for 500 blocks, mark the validator as having not signed @@ -81,7 +83,8 @@ func TestBeginBlocker(t *testing.T) { }}, }, } - BeginBlocker(ctx, req, keeper) + + slashing.BeginBlocker(ctx, req, keeper) } // end block diff --git a/x/slashing/app_test.go b/x/slashing/app_test.go index b62d5dcb1385..1cb0fcd437a3 100644 --- a/x/slashing/app_test.go +++ b/x/slashing/app_test.go @@ -1,6 +1,4 @@ -// nolint -// DONTCOVER -package slashing +package slashing_test import ( "errors" @@ -10,16 +8,13 @@ import ( abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto/secp256k1" + "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" "github.com/cosmos/cosmos-sdk/x/bank" - bankexported "github.com/cosmos/cosmos-sdk/x/bank/exported" - "github.com/cosmos/cosmos-sdk/x/mock" + "github.com/cosmos/cosmos-sdk/x/slashing" "github.com/cosmos/cosmos-sdk/x/staking" - "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/cosmos/cosmos-sdk/x/supply" - supplyexported "github.com/cosmos/cosmos-sdk/x/supply/exported" ) var ( @@ -28,101 +23,21 @@ var ( coins = sdk.Coins{sdk.NewInt64Coin("foocoin", 10)} ) -// initialize the mock application for this module -func getMockApp(t *testing.T) (*mock.App, staking.Keeper, Keeper) { - mapp := mock.NewApp() - - RegisterCodec(mapp.Cdc) - staking.RegisterCodec(mapp.Cdc) - supply.RegisterCodec(mapp.Cdc) - - keyStaking := sdk.NewKVStoreKey(staking.StoreKey) - keySlashing := sdk.NewKVStoreKey(StoreKey) - keySupply := sdk.NewKVStoreKey(supply.StoreKey) - - feeCollector := supply.NewEmptyModuleAccount(auth.FeeCollectorName) - notBondedPool := supply.NewEmptyModuleAccount(types.NotBondedPoolName, supply.Burner, supply.Staking) - bondPool := supply.NewEmptyModuleAccount(types.BondedPoolName, supply.Burner, supply.Staking) - - blacklistedAddrs := make(map[string]bool) - blacklistedAddrs[feeCollector.GetAddress().String()] = true - blacklistedAddrs[notBondedPool.GetAddress().String()] = true - blacklistedAddrs[bondPool.GetAddress().String()] = true - - maccPerms := map[string][]string{ - auth.FeeCollectorName: nil, - staking.NotBondedPoolName: {supply.Burner, supply.Staking}, - staking.BondedPoolName: {supply.Burner, supply.Staking}, - } - supplyKeeper := supply.NewKeeper(mapp.Cdc, keySupply, mapp.AccountKeeper, mapp.BankKeeper, maccPerms) - stakingKeeper := staking.NewKeeper(staking.ModuleCdc, keyStaking, mapp.BankKeeper, supplyKeeper, mapp.ParamsKeeper.Subspace(staking.DefaultParamspace)) - keeper := NewKeeper(mapp.Cdc, keySlashing, stakingKeeper, mapp.ParamsKeeper.Subspace(DefaultParamspace)) - mapp.Router().AddRoute(staking.RouterKey, staking.NewHandler(stakingKeeper)) - mapp.Router().AddRoute(RouterKey, NewHandler(keeper)) - - mapp.SetEndBlocker(getEndBlocker(stakingKeeper)) - mapp.SetInitChainer( - getInitChainer( - mapp, stakingKeeper, mapp.AccountKeeper, mapp.BankKeeper, supplyKeeper, - []supplyexported.ModuleAccountI{feeCollector, notBondedPool, bondPool}, - ), - ) - - require.NoError(t, mapp.CompleteSetup(keyStaking, keySupply, keySlashing)) - - return mapp, stakingKeeper, keeper -} - -// staking endblocker -func getEndBlocker(keeper staking.Keeper) sdk.EndBlocker { - return func(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock { - validatorUpdates := staking.EndBlocker(ctx, keeper) - return abci.ResponseEndBlock{ - ValidatorUpdates: validatorUpdates, - } - } -} - -// overwrite the mock init chainer -func getInitChainer( - mapp *mock.App, keeper staking.Keeper, accountKeeper types.AccountKeeper, bk types.BankKeeper, - supplyKeeper types.SupplyKeeper, blacklistedAddrs []supplyexported.ModuleAccountI, -) sdk.InitChainer { - - return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { - // set module accounts - for _, macc := range blacklistedAddrs { - supplyKeeper.SetModuleAccount(ctx, macc) - } - - mapp.InitChainer(ctx, req) - stakingGenesis := staking.DefaultGenesisState() - validators := staking.InitGenesis(ctx, keeper, accountKeeper, bk, supplyKeeper, stakingGenesis) - return abci.ResponseInitChain{ - Validators: validators, - } - } -} - -func checkValidator(t *testing.T, mapp *mock.App, keeper staking.Keeper, - addr sdk.AccAddress, expFound bool) staking.Validator { - ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{}) - validator, found := keeper.GetValidator(ctxCheck, sdk.ValAddress(addr1)) +func checkValidator(t *testing.T, app *simapp.SimApp, addr sdk.AccAddress, expFound bool) staking.Validator { + ctxCheck := app.BaseApp.NewContext(true, abci.Header{}) + validator, found := app.StakingKeeper.GetValidator(ctxCheck, sdk.ValAddress(addr1)) require.Equal(t, expFound, found) return validator } -func checkValidatorSigningInfo(t *testing.T, mapp *mock.App, keeper Keeper, - addr sdk.ConsAddress, expFound bool) ValidatorSigningInfo { - ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{}) - signingInfo, found := keeper.GetValidatorSigningInfo(ctxCheck, addr) +func checkValidatorSigningInfo(t *testing.T, app *simapp.SimApp, addr sdk.ConsAddress, expFound bool) slashing.ValidatorSigningInfo { + ctxCheck := app.BaseApp.NewContext(true, abci.Header{}) + signingInfo, found := app.SlashingKeeper.GetValidatorSigningInfo(ctxCheck, addr) require.Equal(t, expFound, found) return signingInfo } func TestSlashingMsgs(t *testing.T) { - mapp, stakingKeeper, keeper := getMockApp(t) - genTokens := sdk.TokensFromConsensusPower(42) bondTokens := sdk.TokensFromConsensusPower(10) genCoin := sdk.NewCoin(sdk.DefaultBondDenom, genTokens) @@ -131,14 +46,16 @@ func TestSlashingMsgs(t *testing.T) { acc1 := &auth.BaseAccount{ Address: addr1, } - accs := []authexported.Account{acc1} - balances := []bankexported.GenesisBalance{ - bank.Balance{ + accs := authexported.GenesisAccounts{acc1} + balances := []bank.Balance{ + { Address: addr1, Coins: sdk.Coins{genCoin}, }, } - mock.SetGenesis(mapp, accs, balances) + + app := simapp.SetupWithGenesisAccounts(accs, balances...) + simapp.CheckBalance(t, app, addr1, sdk.Coins{genCoin}) description := staking.NewDescription("foo_moniker", "", "", "", "") commission := staking.NewCommissionRates(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()) @@ -147,26 +64,25 @@ func TestSlashingMsgs(t *testing.T) { sdk.ValAddress(addr1), priv1.PubKey(), bondCoin, description, commission, sdk.OneInt(), ) - header := abci.Header{Height: mapp.LastBlockHeight() + 1} - mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, header, []sdk.Msg{createValidatorMsg}, []uint64{0}, []uint64{0}, true, true, priv1) - mock.CheckBalance(t, mapp, addr1, sdk.Coins{genCoin.Sub(bondCoin)}) + header := abci.Header{Height: app.LastBlockHeight() + 1} + simapp.SignCheckDeliver(t, app.Codec(), app.BaseApp, header, []sdk.Msg{createValidatorMsg}, []uint64{0}, []uint64{0}, true, true, priv1) + simapp.CheckBalance(t, app, addr1, sdk.Coins{genCoin.Sub(bondCoin)}) - header = abci.Header{Height: mapp.LastBlockHeight() + 1} - mapp.BeginBlock(abci.RequestBeginBlock{Header: header}) + header = abci.Header{Height: app.LastBlockHeight() + 1} + app.BeginBlock(abci.RequestBeginBlock{Header: header}) - validator := checkValidator(t, mapp, stakingKeeper, addr1, true) + validator := checkValidator(t, app, addr1, true) require.Equal(t, sdk.ValAddress(addr1), validator.OperatorAddress) require.Equal(t, sdk.Bonded, validator.Status) require.True(sdk.IntEq(t, bondTokens, validator.BondedTokens())) - unjailMsg := MsgUnjail{ValidatorAddr: sdk.ValAddress(validator.GetConsPubKey().Address())} + unjailMsg := slashing.MsgUnjail{ValidatorAddr: sdk.ValAddress(validator.GetConsPubKey().Address())} - // no signing info yet - checkValidatorSigningInfo(t, mapp, keeper, sdk.ConsAddress(addr1), false) + checkValidatorSigningInfo(t, app, sdk.ConsAddress(addr1), true) // unjail should fail with unknown validator - header = abci.Header{Height: mapp.LastBlockHeight() + 1} - _, res, err := mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, header, []sdk.Msg{unjailMsg}, []uint64{0}, []uint64{1}, false, false, priv1) + header = abci.Header{Height: app.LastBlockHeight() + 1} + _, res, err := simapp.SignCheckDeliver(t, app.Codec(), app.BaseApp, header, []sdk.Msg{unjailMsg}, []uint64{0}, []uint64{1}, false, false, priv1) require.Error(t, err) require.Nil(t, res) - require.True(t, errors.Is(ErrValidatorNotJailed, err)) + require.True(t, errors.Is(slashing.ErrValidatorNotJailed, err)) } diff --git a/x/slashing/handler_test.go b/x/slashing/handler_test.go index b3d181c806e9..c168f8052ffb 100644 --- a/x/slashing/handler_test.go +++ b/x/slashing/handler_test.go @@ -1,4 +1,4 @@ -package slashing +package slashing_test import ( "errors" @@ -10,6 +10,7 @@ import ( abci "github.com/tendermint/tendermint/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/slashing" slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/internal/keeper" "github.com/cosmos/cosmos-sdk/x/slashing/internal/types" "github.com/cosmos/cosmos-sdk/x/staking" @@ -17,8 +18,8 @@ import ( func TestCannotUnjailUnlessJailed(t *testing.T) { // initial setup - ctx, bk, sk, _, keeper := slashingkeeper.CreateTestInput(t, DefaultParams()) - slh := NewHandler(keeper) + ctx, bk, sk, _, keeper := slashingkeeper.CreateTestInput(t, slashing.DefaultParams()) + slh := slashing.NewHandler(keeper) amt := sdk.TokensFromConsensusPower(100) addr, val := slashingkeeper.Addrs[0], slashingkeeper.Pks[0] @@ -36,16 +37,16 @@ func TestCannotUnjailUnlessJailed(t *testing.T) { require.Equal(t, amt, sk.Validator(ctx, addr).GetBondedTokens()) // assert non-jailed validator can't be unjailed - res, err = slh(ctx, NewMsgUnjail(addr)) + res, err = slh(ctx, slashing.NewMsgUnjail(addr)) require.Error(t, err) require.Nil(t, res) - require.True(t, errors.Is(ErrValidatorNotJailed, err)) + require.True(t, errors.Is(slashing.ErrValidatorNotJailed, err)) } func TestCannotUnjailUnlessMeetMinSelfDelegation(t *testing.T) { // initial setup - ctx, bk, sk, _, keeper := slashingkeeper.CreateTestInput(t, DefaultParams()) - slh := NewHandler(keeper) + ctx, bk, sk, _, keeper := slashingkeeper.CreateTestInput(t, slashing.DefaultParams()) + slh := slashing.NewHandler(keeper) amtInt := int64(100) addr, val, amt := slashingkeeper.Addrs[0], slashingkeeper.Pks[0], sdk.TokensFromConsensusPower(amtInt) msg := slashingkeeper.NewTestMsgCreateValidator(addr, val, amt) @@ -71,14 +72,14 @@ func TestCannotUnjailUnlessMeetMinSelfDelegation(t *testing.T) { require.True(t, sk.Validator(ctx, addr).IsJailed()) // assert non-jailed validator can't be unjailed - res, err = slh(ctx, NewMsgUnjail(addr)) + res, err = slh(ctx, slashing.NewMsgUnjail(addr)) require.Error(t, err) require.Nil(t, res) - require.True(t, errors.Is(ErrSelfDelegationTooLowToUnjail, err)) + require.True(t, errors.Is(slashing.ErrSelfDelegationTooLowToUnjail, err)) } func TestJailedValidatorDelegations(t *testing.T) { - ctx, _, stakingKeeper, _, slashingKeeper := slashingkeeper.CreateTestInput(t, DefaultParams()) + ctx, _, stakingKeeper, _, slashingKeeper := slashingkeeper.CreateTestInput(t, slashing.DefaultParams()) stakingParams := stakingKeeper.GetParams(ctx) stakingKeeper.SetParams(ctx, stakingParams) @@ -97,7 +98,7 @@ func TestJailedValidatorDelegations(t *testing.T) { staking.EndBlocker(ctx, stakingKeeper) // set dummy signing info - newInfo := NewValidatorSigningInfo(consAddr, 0, 0, time.Unix(0, 0), false, 0) + newInfo := slashing.NewValidatorSigningInfo(consAddr, 0, 0, time.Unix(0, 0), false, 0) slashingKeeper.SetValidatorSigningInfo(ctx, consAddr, newInfo) // delegate tokens to the validator @@ -124,7 +125,7 @@ func TestJailedValidatorDelegations(t *testing.T) { require.True(t, validator.IsJailed()) // verify the validator cannot unjail itself - res, err = NewHandler(slashingKeeper)(ctx, NewMsgUnjail(valAddr)) + res, err = slashing.NewHandler(slashingKeeper)(ctx, slashing.NewMsgUnjail(valAddr)) require.Error(t, err) require.Nil(t, res) @@ -135,14 +136,14 @@ func TestJailedValidatorDelegations(t *testing.T) { require.NotNil(t, res) // verify the validator can now unjail itself - res, err = NewHandler(slashingKeeper)(ctx, NewMsgUnjail(valAddr)) + res, err = slashing.NewHandler(slashingKeeper)(ctx, slashing.NewMsgUnjail(valAddr)) require.NoError(t, err) require.NotNil(t, res) } func TestInvalidMsg(t *testing.T) { - k := Keeper{} - h := NewHandler(k) + k := slashing.Keeper{} + h := slashing.NewHandler(k) res, err := h(sdk.NewContext(nil, abci.Header{}, false, nil), sdk.NewTestMsg()) require.Error(t, err) @@ -159,7 +160,7 @@ func TestHandleAbsentValidator(t *testing.T) { amt := sdk.TokensFromConsensusPower(power) addr, val := slashingkeeper.Addrs[0], slashingkeeper.Pks[0] sh := staking.NewHandler(sk) - slh := NewHandler(keeper) + slh := slashing.NewHandler(keeper) res, err := sh(ctx, slashingkeeper.NewTestMsgCreateValidator(addr, val, amt)) require.NoError(t, err) diff --git a/x/staking/app_test.go b/x/staking/app_test.go index 28bd943edce0..03aab5d64339 100644 --- a/x/staking/app_test.go +++ b/x/staking/app_test.go @@ -1,4 +1,4 @@ -package staking +package staking_test import ( "testing" @@ -6,111 +6,29 @@ import ( "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" + "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" "github.com/cosmos/cosmos-sdk/x/bank" - bankexported "github.com/cosmos/cosmos-sdk/x/bank/exported" - "github.com/cosmos/cosmos-sdk/x/mock" - "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/cosmos/cosmos-sdk/x/supply" - supplyexported "github.com/cosmos/cosmos-sdk/x/supply/exported" + "github.com/cosmos/cosmos-sdk/x/staking" ) -// getMockApp returns an initialized mock application for this module. -func getMockApp(t *testing.T) (*mock.App, Keeper) { - mApp := mock.NewApp() - - RegisterCodec(mApp.Cdc) - supply.RegisterCodec(mApp.Cdc) - - keyStaking := sdk.NewKVStoreKey(StoreKey) - keySupply := sdk.NewKVStoreKey(supply.StoreKey) - - feeCollector := supply.NewEmptyModuleAccount(auth.FeeCollectorName) - notBondedPool := supply.NewEmptyModuleAccount(types.NotBondedPoolName, supply.Burner, supply.Staking) - bondPool := supply.NewEmptyModuleAccount(types.BondedPoolName, supply.Burner, supply.Staking) - - blacklistedAddrs := make(map[string]bool) - blacklistedAddrs[feeCollector.GetAddress().String()] = true - blacklistedAddrs[notBondedPool.GetAddress().String()] = true - blacklistedAddrs[bondPool.GetAddress().String()] = true - - maccPerms := map[string][]string{ - auth.FeeCollectorName: nil, - types.NotBondedPoolName: {supply.Burner, supply.Staking}, - types.BondedPoolName: {supply.Burner, supply.Staking}, - } - supplyKeeper := supply.NewKeeper(mApp.Cdc, keySupply, mApp.AccountKeeper, mApp.BankKeeper, maccPerms) - keeper := NewKeeper(ModuleCdc, keyStaking, mApp.BankKeeper, supplyKeeper, mApp.ParamsKeeper.Subspace(DefaultParamspace)) - - mApp.Router().AddRoute(RouterKey, NewHandler(keeper)) - mApp.SetEndBlocker(getEndBlocker(keeper)) - mApp.SetInitChainer( - getInitChainer( - mApp, keeper, mApp.AccountKeeper, mApp.BankKeeper, supplyKeeper, - []supplyexported.ModuleAccountI{feeCollector, notBondedPool, bondPool}, - ), - ) - - require.NoError(t, mApp.CompleteSetup(keyStaking, keySupply)) - return mApp, keeper -} - -// getEndBlocker returns a staking endblocker. -func getEndBlocker(keeper Keeper) sdk.EndBlocker { - return func(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock { - validatorUpdates := EndBlocker(ctx, keeper) - - return abci.ResponseEndBlock{ - ValidatorUpdates: validatorUpdates, - } - } -} - -// getInitChainer initializes the chainer of the mock app and sets the genesis -// state. It returns an empty ResponseInitChain. -func getInitChainer( - mapp *mock.App, keeper Keeper, ak types.AccountKeeper, bk types.BankKeeper, - sk types.SupplyKeeper, blacklistedAddrs []supplyexported.ModuleAccountI, -) sdk.InitChainer { - - return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { - mapp.InitChainer(ctx, req) - - // set module accounts - for _, macc := range blacklistedAddrs { - sk.SetModuleAccount(ctx, macc) - } - - stakingGenesis := DefaultGenesisState() - validators := InitGenesis(ctx, keeper, ak, bk, sk, stakingGenesis) - - return abci.ResponseInitChain{ - Validators: validators, - } - } -} - -//__________________________________________________________________________________________ - -func checkValidator(t *testing.T, mapp *mock.App, keeper Keeper, - addr sdk.ValAddress, expFound bool) Validator { - - ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{}) - validator, found := keeper.GetValidator(ctxCheck, addr) +func checkValidator(t *testing.T, app *simapp.SimApp, addr sdk.ValAddress, expFound bool) staking.Validator { + ctxCheck := app.BaseApp.NewContext(true, abci.Header{}) + validator, found := app.StakingKeeper.GetValidator(ctxCheck, addr) require.Equal(t, expFound, found) return validator } func checkDelegation( - t *testing.T, mapp *mock.App, keeper Keeper, delegatorAddr sdk.AccAddress, + t *testing.T, app *simapp.SimApp, delegatorAddr sdk.AccAddress, validatorAddr sdk.ValAddress, expFound bool, expShares sdk.Dec, ) { - ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{}) - delegation, found := keeper.GetDelegation(ctxCheck, delegatorAddr, validatorAddr) + ctxCheck := app.BaseApp.NewContext(true, abci.Header{}) + delegation, found := app.StakingKeeper.GetDelegation(ctxCheck, delegatorAddr, validatorAddr) if expFound { require.True(t, found) require.True(sdk.DecEq(t, expShares, delegation.Shares)) @@ -122,8 +40,6 @@ func checkDelegation( } func TestStakingMsgs(t *testing.T) { - mApp, keeper := getMockApp(t) - genTokens := sdk.TokensFromConsensusPower(42) bondTokens := sdk.TokensFromConsensusPower(10) genCoin := sdk.NewCoin(sdk.DefaultBondDenom, genTokens) @@ -131,8 +47,8 @@ func TestStakingMsgs(t *testing.T) { acc1 := &auth.BaseAccount{Address: addr1} acc2 := &auth.BaseAccount{Address: addr2} - accs := []authexported.Account{acc1, acc2} - balances := []bankexported.GenesisBalance{ + accs := authexported.GenesisAccounts{acc1, acc2} + balances := []bank.Balance{ bank.Balance{ Address: addr1, Coins: sdk.Coins{genCoin}, @@ -143,58 +59,58 @@ func TestStakingMsgs(t *testing.T) { }, } - mock.SetGenesis(mApp, accs, balances) - mock.CheckBalance(t, mApp, addr1, sdk.Coins{genCoin}) - mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin}) + app := simapp.SetupWithGenesisAccounts(accs, balances...) + simapp.CheckBalance(t, app, addr1, sdk.Coins{genCoin}) + simapp.CheckBalance(t, app, addr2, sdk.Coins{genCoin}) // create validator - description := NewDescription("foo_moniker", "", "", "", "") - createValidatorMsg := NewMsgCreateValidator( + description := staking.NewDescription("foo_moniker", "", "", "", "") + createValidatorMsg := staking.NewMsgCreateValidator( sdk.ValAddress(addr1), priv1.PubKey(), bondCoin, description, commissionRates, sdk.OneInt(), ) - header := abci.Header{Height: mApp.LastBlockHeight() + 1} - mock.SignCheckDeliver(t, mApp.Cdc, mApp.BaseApp, header, []sdk.Msg{createValidatorMsg}, []uint64{0}, []uint64{0}, true, true, priv1) - mock.CheckBalance(t, mApp, addr1, sdk.Coins{genCoin.Sub(bondCoin)}) + header := abci.Header{Height: app.LastBlockHeight() + 1} + simapp.SignCheckDeliver(t, app.Codec(), app.BaseApp, header, []sdk.Msg{createValidatorMsg}, []uint64{0}, []uint64{0}, true, true, priv1) + simapp.CheckBalance(t, app, addr1, sdk.Coins{genCoin.Sub(bondCoin)}) - header = abci.Header{Height: mApp.LastBlockHeight() + 1} - mApp.BeginBlock(abci.RequestBeginBlock{Header: header}) + header = abci.Header{Height: app.LastBlockHeight() + 1} + app.BeginBlock(abci.RequestBeginBlock{Header: header}) - validator := checkValidator(t, mApp, keeper, sdk.ValAddress(addr1), true) + validator := checkValidator(t, app, sdk.ValAddress(addr1), true) require.Equal(t, sdk.ValAddress(addr1), validator.OperatorAddress) require.Equal(t, sdk.Bonded, validator.Status) require.True(sdk.IntEq(t, bondTokens, validator.BondedTokens())) - header = abci.Header{Height: mApp.LastBlockHeight() + 1} - mApp.BeginBlock(abci.RequestBeginBlock{Header: header}) + header = abci.Header{Height: app.LastBlockHeight() + 1} + app.BeginBlock(abci.RequestBeginBlock{Header: header}) // edit the validator - description = NewDescription("bar_moniker", "", "", "", "") - editValidatorMsg := NewMsgEditValidator(sdk.ValAddress(addr1), description, nil, nil) + description = staking.NewDescription("bar_moniker", "", "", "", "") + editValidatorMsg := staking.NewMsgEditValidator(sdk.ValAddress(addr1), description, nil, nil) - header = abci.Header{Height: mApp.LastBlockHeight() + 1} - mock.SignCheckDeliver(t, mApp.Cdc, mApp.BaseApp, header, []sdk.Msg{editValidatorMsg}, []uint64{0}, []uint64{1}, true, true, priv1) + header = abci.Header{Height: app.LastBlockHeight() + 1} + simapp.SignCheckDeliver(t, app.Codec(), app.BaseApp, header, []sdk.Msg{editValidatorMsg}, []uint64{0}, []uint64{1}, true, true, priv1) - validator = checkValidator(t, mApp, keeper, sdk.ValAddress(addr1), true) + validator = checkValidator(t, app, sdk.ValAddress(addr1), true) require.Equal(t, description, validator.Description) // delegate - mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin}) - delegateMsg := NewMsgDelegate(addr2, sdk.ValAddress(addr1), bondCoin) + simapp.CheckBalance(t, app, addr2, sdk.Coins{genCoin}) + delegateMsg := staking.NewMsgDelegate(addr2, sdk.ValAddress(addr1), bondCoin) - header = abci.Header{Height: mApp.LastBlockHeight() + 1} - mock.SignCheckDeliver(t, mApp.Cdc, mApp.BaseApp, header, []sdk.Msg{delegateMsg}, []uint64{1}, []uint64{0}, true, true, priv2) - mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin.Sub(bondCoin)}) - checkDelegation(t, mApp, keeper, addr2, sdk.ValAddress(addr1), true, bondTokens.ToDec()) + header = abci.Header{Height: app.LastBlockHeight() + 1} + simapp.SignCheckDeliver(t, app.Codec(), app.BaseApp, header, []sdk.Msg{delegateMsg}, []uint64{1}, []uint64{0}, true, true, priv2) + simapp.CheckBalance(t, app, addr2, sdk.Coins{genCoin.Sub(bondCoin)}) + checkDelegation(t, app, addr2, sdk.ValAddress(addr1), true, bondTokens.ToDec()) // begin unbonding - beginUnbondingMsg := NewMsgUndelegate(addr2, sdk.ValAddress(addr1), bondCoin) - header = abci.Header{Height: mApp.LastBlockHeight() + 1} - mock.SignCheckDeliver(t, mApp.Cdc, mApp.BaseApp, header, []sdk.Msg{beginUnbondingMsg}, []uint64{1}, []uint64{1}, true, true, priv2) + beginUnbondingMsg := staking.NewMsgUndelegate(addr2, sdk.ValAddress(addr1), bondCoin) + header = abci.Header{Height: app.LastBlockHeight() + 1} + simapp.SignCheckDeliver(t, app.Codec(), app.BaseApp, header, []sdk.Msg{beginUnbondingMsg}, []uint64{1}, []uint64{1}, true, true, priv2) // delegation should exist anymore - checkDelegation(t, mApp, keeper, addr2, sdk.ValAddress(addr1), false, sdk.Dec{}) + checkDelegation(t, app, addr2, sdk.ValAddress(addr1), false, sdk.Dec{}) // balance should be the same because bonding not yet complete - mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin.Sub(bondCoin)}) + simapp.CheckBalance(t, app, addr2, sdk.Coins{genCoin.Sub(bondCoin)}) } diff --git a/x/staking/common_test.go b/x/staking/common_test.go new file mode 100644 index 000000000000..225832dd170f --- /dev/null +++ b/x/staking/common_test.go @@ -0,0 +1,40 @@ +package staking_test + +import ( + "github.com/tendermint/tendermint/crypto" + "github.com/tendermint/tendermint/crypto/secp256k1" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/staking" + "github.com/cosmos/cosmos-sdk/x/staking/types" +) + +// nolint:deadcode,unused,varcheck +var ( + priv1 = secp256k1.GenPrivKey() + addr1 = sdk.AccAddress(priv1.PubKey().Address()) + priv2 = secp256k1.GenPrivKey() + addr2 = sdk.AccAddress(priv2.PubKey().Address()) + addr3 = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) + priv4 = secp256k1.GenPrivKey() + addr4 = sdk.AccAddress(priv4.PubKey().Address()) + coins = sdk.Coins{sdk.NewCoin("foocoin", sdk.NewInt(10))} + fee = auth.NewStdFee( + 100000, + sdk.Coins{sdk.NewCoin("foocoin", sdk.NewInt(0))}, + ) + + commissionRates = staking.NewCommissionRates(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()) +) + +func NewTestMsgCreateValidator(address sdk.ValAddress, pubKey crypto.PubKey, amt sdk.Int) staking.MsgCreateValidator { + return types.NewMsgCreateValidator( + address, pubKey, sdk.NewCoin(sdk.DefaultBondDenom, amt), staking.Description{}, commissionRates, sdk.OneInt(), + ) +} + +func NewTestMsgDelegate(delAddr sdk.AccAddress, valAddr sdk.ValAddress, amt sdk.Int) staking.MsgDelegate { + amount := sdk.NewCoin(sdk.DefaultBondDenom, amt) + return staking.NewMsgDelegate(delAddr, valAddr, amount) +} diff --git a/x/staking/handler_test.go b/x/staking/handler_test.go index 64a5d579f99d..51a2e61aa6c5 100644 --- a/x/staking/handler_test.go +++ b/x/staking/handler_test.go @@ -1,4 +1,4 @@ -package staking +package staking_test import ( "strings" @@ -13,6 +13,7 @@ import ( tmtypes "github.com/tendermint/tendermint/types" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/staking" keep "github.com/cosmos/cosmos-sdk/x/staking/keeper" "github.com/cosmos/cosmos-sdk/x/staking/types" ) @@ -23,10 +24,11 @@ func TestValidatorByPowerIndex(t *testing.T) { initPower := int64(1000000) initBond := sdk.TokensFromConsensusPower(initPower) ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, initPower) + handler := staking.NewHandler(keeper) // create validator msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], initBond) - res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + res, err := handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) @@ -43,12 +45,12 @@ func TestValidatorByPowerIndex(t *testing.T) { // verify that the by power index exists validator, found := keeper.GetValidator(ctx, validatorAddr) require.True(t, found) - power := GetValidatorsByPowerIndexKey(validator) + power := staking.GetValidatorsByPowerIndexKey(validator) require.True(t, keep.ValidatorByPowerIndexExists(ctx, keeper, power)) // create a second validator keep it bonded msgCreateValidator = NewTestMsgCreateValidator(validatorAddr3, keep.PKs[2], initBond) - res, err = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + res, err = handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) @@ -74,19 +76,19 @@ func TestValidatorByPowerIndex(t *testing.T) { // but the new power record should have been created validator, found = keeper.GetValidator(ctx, validatorAddr) require.True(t, found) - power2 := GetValidatorsByPowerIndexKey(validator) + power2 := staking.GetValidatorsByPowerIndexKey(validator) require.True(t, keep.ValidatorByPowerIndexExists(ctx, keeper, power2)) // now the new record power index should be the same as the original record - power3 := GetValidatorsByPowerIndexKey(validator) + power3 := staking.GetValidatorsByPowerIndexKey(validator) require.Equal(t, power2, power3) // unbond self-delegation totalBond := validator.TokensFromShares(bond.GetShares()).TruncateInt() unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, totalBond) - msgUndelegate := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) + msgUndelegate := staking.NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) - res, err = handleMsgUndelegate(ctx, msgUndelegate, keeper) + res, err = handler(ctx, msgUndelegate) require.NoError(t, err) require.NotNil(t, res) @@ -97,8 +99,8 @@ func TestValidatorByPowerIndex(t *testing.T) { require.NoError(t, err) ctx = ctx.WithBlockTime(finishTime) - EndBlocker(ctx, keeper) - EndBlocker(ctx, keeper) + staking.EndBlocker(ctx, keeper) + staking.EndBlocker(ctx, keeper) // verify that by power key nolonger exists _, found = keeper.GetValidator(ctx, validatorAddr) @@ -108,13 +110,14 @@ func TestValidatorByPowerIndex(t *testing.T) { func TestDuplicatesMsgCreateValidator(t *testing.T) { ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + handler := staking.NewHandler(keeper) addr1, addr2 := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1]) pk1, pk2 := keep.PKs[0], keep.PKs[1] valTokens := sdk.TokensFromConsensusPower(10) msgCreateValidator1 := NewTestMsgCreateValidator(addr1, pk1, valTokens) - res, err := handleMsgCreateValidator(ctx, msgCreateValidator1, keeper) + res, err := handler(ctx, msgCreateValidator1) require.NoError(t, err) require.NotNil(t, res) @@ -127,23 +130,23 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) { assert.Equal(t, pk1, validator.GetConsPubKey()) assert.Equal(t, valTokens, validator.BondedTokens()) assert.Equal(t, valTokens.ToDec(), validator.DelegatorShares) - assert.Equal(t, Description{}, validator.Description) + assert.Equal(t, staking.Description{}, validator.Description) // two validators can't have the same operator address msgCreateValidator2 := NewTestMsgCreateValidator(addr1, pk2, valTokens) - res, err = handleMsgCreateValidator(ctx, msgCreateValidator2, keeper) + res, err = handler(ctx, msgCreateValidator2) require.Error(t, err) require.Nil(t, res) // two validators can't have the same pubkey msgCreateValidator3 := NewTestMsgCreateValidator(addr2, pk1, valTokens) - res, err = handleMsgCreateValidator(ctx, msgCreateValidator3, keeper) + res, err = handler(ctx, msgCreateValidator3) require.Error(t, err) require.Nil(t, res) // must have different pubkey and operator msgCreateValidator4 := NewTestMsgCreateValidator(addr2, pk2, valTokens) - res, err = handleMsgCreateValidator(ctx, msgCreateValidator4, keeper) + res, err = handler(ctx, msgCreateValidator4) require.NoError(t, err) require.NotNil(t, res) @@ -159,18 +162,19 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) { assert.Equal(t, pk2, validator.GetConsPubKey()) assert.True(sdk.IntEq(t, valTokens, validator.Tokens)) assert.True(sdk.DecEq(t, valTokens.ToDec(), validator.DelegatorShares)) - assert.Equal(t, Description{}, validator.Description) + assert.Equal(t, staking.Description{}, validator.Description) } func TestInvalidPubKeyTypeMsgCreateValidator(t *testing.T) { ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + handler := staking.NewHandler(keeper) addr := sdk.ValAddress(keep.Addrs[0]) invalidPk := secp256k1.GenPrivKey().PubKey() // invalid pukKey type should not be allowed msgCreateValidator := NewTestMsgCreateValidator(addr, invalidPk, sdk.NewInt(10)) - res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + res, err := handler(ctx, msgCreateValidator) require.Error(t, err) require.Nil(t, res) @@ -178,13 +182,14 @@ func TestInvalidPubKeyTypeMsgCreateValidator(t *testing.T) { Validator: &abci.ValidatorParams{PubKeyTypes: []string{tmtypes.ABCIPubKeyTypeSecp256k1}}, }) - res, err = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + res, err = handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) } func TestLegacyValidatorDelegations(t *testing.T) { ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, int64(1000)) + handler := staking.NewHandler(keeper) bondAmount := sdk.TokensFromConsensusPower(10) valAddr := sdk.ValAddress(keep.Addrs[0]) @@ -193,7 +198,7 @@ func TestLegacyValidatorDelegations(t *testing.T) { // create validator msgCreateVal := NewTestMsgCreateValidator(valAddr, valConsPubKey, bondAmount) - res, err := handleMsgCreateValidator(ctx, msgCreateVal, keeper) + res, err := handler(ctx, msgCreateVal) require.NoError(t, err) require.NotNil(t, res) @@ -210,7 +215,7 @@ func TestLegacyValidatorDelegations(t *testing.T) { // delegate tokens to the validator msgDelegate := NewTestMsgDelegate(delAddr, valAddr, bondAmount) - res, err = handleMsgDelegate(ctx, msgDelegate, keeper) + res, err = handler(ctx, msgDelegate) require.NoError(t, err) require.NotNil(t, res) @@ -222,9 +227,9 @@ func TestLegacyValidatorDelegations(t *testing.T) { // unbond validator total self-delegations (which should jail the validator) unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, bondAmount) - msgUndelegate := NewMsgUndelegate(sdk.AccAddress(valAddr), valAddr, unbondAmt) + msgUndelegate := staking.NewMsgUndelegate(sdk.AccAddress(valAddr), valAddr, unbondAmt) - res, err = handleMsgUndelegate(ctx, msgUndelegate, keeper) + res, err = handler(ctx, msgUndelegate) require.NoError(t, err) require.NotNil(t, res) @@ -235,7 +240,7 @@ func TestLegacyValidatorDelegations(t *testing.T) { require.NoError(t, err) ctx = ctx.WithBlockTime(finishTime) - EndBlocker(ctx, keeper) + staking.EndBlocker(ctx, keeper) // verify the validator record still exists, is jailed, and has correct tokens validator, found = keeper.GetValidator(ctx, valAddr) @@ -251,7 +256,7 @@ func TestLegacyValidatorDelegations(t *testing.T) { // verify the validator can still self-delegate msgSelfDelegate := NewTestMsgDelegate(sdk.AccAddress(valAddr), valAddr, bondAmount) - res, err = handleMsgDelegate(ctx, msgSelfDelegate, keeper) + res, err = handler(ctx, msgSelfDelegate) require.NoError(t, err) require.NotNil(t, res) @@ -266,7 +271,7 @@ func TestLegacyValidatorDelegations(t *testing.T) { // verify the validator can now accept delegations msgDelegate = NewTestMsgDelegate(delAddr, valAddr, bondAmount) - res, err = handleMsgDelegate(ctx, msgDelegate, keeper) + res, err = handler(ctx, msgDelegate) require.NoError(t, err) require.NotNil(t, res) @@ -287,6 +292,8 @@ func TestIncrementsMsgDelegate(t *testing.T) { initPower := int64(1000) initBond := sdk.TokensFromConsensusPower(initPower) ctx, _, bk, keeper, _ := keep.CreateTestInput(t, false, initPower) + handler := staking.NewHandler(keeper) + params := keeper.GetParams(ctx) bondAmount := sdk.TokensFromConsensusPower(10) @@ -294,7 +301,7 @@ func TestIncrementsMsgDelegate(t *testing.T) { // first create validator msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], bondAmount) - res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + res, err := handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) @@ -323,7 +330,7 @@ func TestIncrementsMsgDelegate(t *testing.T) { for i := int64(0); i < 5; i++ { ctx = ctx.WithBlockHeight(i) - res, err := handleMsgDelegate(ctx, msgDelegate, keeper) + res, err := handler(ctx, msgDelegate) require.NoError(t, err) require.NotNil(t, res) @@ -359,11 +366,12 @@ func TestEditValidatorDecreaseMinSelfDelegation(t *testing.T) { initPower := int64(100) initBond := sdk.TokensFromConsensusPower(100) ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, initPower) + handler := staking.NewHandler(keeper) // create validator msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], initBond) msgCreateValidator.MinSelfDelegation = sdk.NewInt(2) - res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + res, err := handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) @@ -380,8 +388,8 @@ func TestEditValidatorDecreaseMinSelfDelegation(t *testing.T) { initBond, gotBond, bond) newMinSelfDelegation := sdk.OneInt() - msgEditValidator := NewMsgEditValidator(validatorAddr, Description{}, nil, &newMinSelfDelegation) - res, err = handleMsgEditValidator(ctx, msgEditValidator, keeper) + msgEditValidator := staking.NewMsgEditValidator(validatorAddr, staking.Description{}, nil, &newMinSelfDelegation) + res, err = handler(ctx, msgEditValidator) require.Error(t, err) require.Nil(t, res) } @@ -392,11 +400,12 @@ func TestEditValidatorIncreaseMinSelfDelegationBeyondCurrentBond(t *testing.T) { initPower := int64(100) initBond := sdk.TokensFromConsensusPower(100) ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, initPower) + handler := staking.NewHandler(keeper) // create validator msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], initBond) msgCreateValidator.MinSelfDelegation = sdk.NewInt(2) - res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + res, err := handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) @@ -413,8 +422,8 @@ func TestEditValidatorIncreaseMinSelfDelegationBeyondCurrentBond(t *testing.T) { initBond, gotBond, bond) newMinSelfDelegation := initBond.Add(sdk.OneInt()) - msgEditValidator := NewMsgEditValidator(validatorAddr, Description{}, nil, &newMinSelfDelegation) - res, err = handleMsgEditValidator(ctx, msgEditValidator, keeper) + msgEditValidator := staking.NewMsgEditValidator(validatorAddr, staking.Description{}, nil, &newMinSelfDelegation) + res, err = handler(ctx, msgEditValidator) require.Error(t, err) require.Nil(t, res) } @@ -423,6 +432,7 @@ func TestIncrementsMsgUnbond(t *testing.T) { initPower := int64(1000) initBond := sdk.TokensFromConsensusPower(initPower) ctx, _, bk, keeper, _ := keep.CreateTestInput(t, false, initPower) + handler := staking.NewHandler(keeper) params := keeper.GetParams(ctx) denom := params.BondDenom @@ -431,7 +441,7 @@ func TestIncrementsMsgUnbond(t *testing.T) { validatorAddr, delegatorAddr := sdk.ValAddress(keep.Addrs[0]), keep.Addrs[1] msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], initBond) - res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + res, err := handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) @@ -439,7 +449,7 @@ func TestIncrementsMsgUnbond(t *testing.T) { amt1 := bk.GetBalance(ctx, delegatorAddr, denom).Amount msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, initBond) - res, err = handleMsgDelegate(ctx, msgDelegate, keeper) + res, err = handler(ctx, msgDelegate) require.NoError(t, err) require.NotNil(t, res) @@ -458,11 +468,11 @@ func TestIncrementsMsgUnbond(t *testing.T) { // just send the same msgUnbond multiple times // TODO use decimals here unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) - msgUndelegate := NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) + msgUndelegate := staking.NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) numUnbonds := int64(5) for i := int64(0); i < numUnbonds; i++ { - res, err := handleMsgUndelegate(ctx, msgUndelegate, keeper) + res, err := handler(ctx, msgUndelegate) require.NoError(t, err) require.NotNil(t, res) @@ -473,7 +483,7 @@ func TestIncrementsMsgUnbond(t *testing.T) { require.NoError(t, err) ctx = ctx.WithBlockTime(finishTime) - EndBlocker(ctx, keeper) + staking.EndBlocker(ctx, keeper) // check that the accounts and the bond account have the appropriate values validator, found = keeper.GetValidator(ctx, validatorAddr) @@ -511,8 +521,8 @@ func TestIncrementsMsgUnbond(t *testing.T) { for _, c := range errorCases { unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, c) - msgUndelegate := NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) - res, err = handleMsgUndelegate(ctx, msgUndelegate, keeper) + msgUndelegate := staking.NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) + res, err = handler(ctx, msgUndelegate) require.Error(t, err) require.Nil(t, res) } @@ -521,8 +531,8 @@ func TestIncrementsMsgUnbond(t *testing.T) { // should be able to unbond remaining unbondAmt = sdk.NewCoin(sdk.DefaultBondDenom, leftBonded) - msgUndelegate = NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) - res, err = handleMsgUndelegate(ctx, msgUndelegate, keeper) + msgUndelegate = staking.NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) + res, err = handler(ctx, msgUndelegate) require.NoError(t, err, "msgUnbond: %v\nshares: %s\nleftBonded: %s\n", msgUndelegate, unbondAmt, leftBonded) require.NotNil(t, res, "msgUnbond: %v\nshares: %s\nleftBonded: %s\n", msgUndelegate, unbondAmt, leftBonded) } @@ -531,6 +541,7 @@ func TestMultipleMsgCreateValidator(t *testing.T) { initPower := int64(1000) initTokens := sdk.TokensFromConsensusPower(initPower) ctx, _, bk, keeper, _ := keep.CreateTestInput(t, false, initPower) + handler := staking.NewHandler(keeper) params := keeper.GetParams(ctx) blockTime := time.Now().UTC() @@ -552,7 +563,7 @@ func TestMultipleMsgCreateValidator(t *testing.T) { valTokens := sdk.TokensFromConsensusPower(10) msgCreateValidatorOnBehalfOf := NewTestMsgCreateValidator(validatorAddr, keep.PKs[i], valTokens) - res, err := handleMsgCreateValidator(ctx, msgCreateValidatorOnBehalfOf, keeper) + res, err := handler(ctx, msgCreateValidatorOnBehalfOf) require.NoError(t, err) require.NotNil(t, res) @@ -569,7 +580,7 @@ func TestMultipleMsgCreateValidator(t *testing.T) { require.Equal(t, balanceExpd, balanceGot, "expected account to have %d, got %d", balanceExpd, balanceGot) } - EndBlocker(ctx, keeper) + staking.EndBlocker(ctx, keeper) // unbond them all by removing delegation for i, validatorAddr := range validatorAddrs { @@ -577,8 +588,8 @@ func TestMultipleMsgCreateValidator(t *testing.T) { require.True(t, found) unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(10)) - msgUndelegate := NewMsgUndelegate(delegatorAddrs[i], validatorAddr, unbondAmt) // remove delegation - res, err := handleMsgUndelegate(ctx, msgUndelegate, keeper) + msgUndelegate := staking.NewMsgUndelegate(delegatorAddrs[i], validatorAddr, unbondAmt) // remove delegation + res, err := handler(ctx, msgUndelegate) require.NoError(t, err) require.NotNil(t, res) @@ -589,10 +600,10 @@ func TestMultipleMsgCreateValidator(t *testing.T) { require.NoError(t, err) // adds validator into unbonding queue - EndBlocker(ctx, keeper) + staking.EndBlocker(ctx, keeper) // removes validator from queue and set - EndBlocker(ctx.WithBlockTime(blockTime.Add(params.UnbondingTime)), keeper) + staking.EndBlocker(ctx.WithBlockTime(blockTime.Add(params.UnbondingTime)), keeper) // Check that the validator is deleted from state validators := keeper.GetValidators(ctx, 100) @@ -609,18 +620,19 @@ func TestMultipleMsgCreateValidator(t *testing.T) { func TestMultipleMsgDelegate(t *testing.T) { ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + handler := staking.NewHandler(keeper) validatorAddr, delegatorAddrs := sdk.ValAddress(keep.Addrs[0]), keep.Addrs[1:] // first make a validator msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], sdk.NewInt(10)) - res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + res, err := handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) // delegate multiple parties for _, delegatorAddr := range delegatorAddrs { msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, sdk.NewInt(10)) - res, err := handleMsgDelegate(ctx, msgDelegate, keeper) + res, err := handler(ctx, msgDelegate) require.NoError(t, err) require.NotNil(t, res) @@ -633,9 +645,9 @@ func TestMultipleMsgDelegate(t *testing.T) { // unbond them all for _, delegatorAddr := range delegatorAddrs { unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) - msgUndelegate := NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) + msgUndelegate := staking.NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) - res, err := handleMsgUndelegate(ctx, msgUndelegate, keeper) + res, err := handler(ctx, msgUndelegate) require.NoError(t, err) require.NotNil(t, res) @@ -646,7 +658,7 @@ func TestMultipleMsgDelegate(t *testing.T) { require.NoError(t, err) ctx = ctx.WithBlockTime(finishTime) - EndBlocker(ctx, keeper) + staking.EndBlocker(ctx, keeper) // check that the account is unbonded _, found := keeper.GetDelegation(ctx, delegatorAddr, validatorAddr) @@ -656,24 +668,25 @@ func TestMultipleMsgDelegate(t *testing.T) { func TestJailValidator(t *testing.T) { ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + handler := staking.NewHandler(keeper) validatorAddr, delegatorAddr := sdk.ValAddress(keep.Addrs[0]), keep.Addrs[1] // create the validator msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], sdk.NewInt(10)) - res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + res, err := handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) // bond a delegator msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, sdk.NewInt(10)) - res, err = handleMsgDelegate(ctx, msgDelegate, keeper) + res, err = handler(ctx, msgDelegate) require.NoError(t, err) require.NotNil(t, res) // unbond the validators bond portion unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) - msgUndelegateValidator := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) - res, err = handleMsgUndelegate(ctx, msgUndelegateValidator, keeper) + msgUndelegateValidator := staking.NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) + res, err = handler(ctx, msgUndelegateValidator) require.NoError(t, err) require.NotNil(t, res) @@ -684,16 +697,16 @@ func TestJailValidator(t *testing.T) { require.NoError(t, err) ctx = ctx.WithBlockTime(finishTime) - EndBlocker(ctx, keeper) + staking.EndBlocker(ctx, keeper) validator, found := keeper.GetValidator(ctx, validatorAddr) require.True(t, found) require.True(t, validator.Jailed, "%v", validator) // test that the delegator can still withdraw their bonds - msgUndelegateDelegator := NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) + msgUndelegateDelegator := staking.NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) - res, err = handleMsgUndelegate(ctx, msgUndelegateDelegator, keeper) + res, err = handler(ctx, msgUndelegateDelegator) require.NoError(t, err) require.NotNil(t, res) @@ -704,16 +717,17 @@ func TestJailValidator(t *testing.T) { require.NoError(t, err) ctx = ctx.WithBlockTime(finishTime) - EndBlocker(ctx, keeper) + staking.EndBlocker(ctx, keeper) // verify that the pubkey can now be reused - res, err = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + res, err = handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) } func TestValidatorQueue(t *testing.T) { ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + handler := staking.NewHandler(keeper) validatorAddr, delegatorAddr := sdk.ValAddress(keep.Addrs[0]), keep.Addrs[1] // set the unbonding time @@ -724,23 +738,23 @@ func TestValidatorQueue(t *testing.T) { // create the validator valTokens := sdk.TokensFromConsensusPower(10) msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], valTokens) - res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + res, err := handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) // bond a delegator delTokens := sdk.TokensFromConsensusPower(10) msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, delTokens) - res, err = handleMsgDelegate(ctx, msgDelegate, keeper) + res, err = handler(ctx, msgDelegate) require.NoError(t, err) require.NotNil(t, res) - EndBlocker(ctx, keeper) + staking.EndBlocker(ctx, keeper) // unbond the all self-delegation to put validator in unbonding state unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, delTokens) - msgUndelegateValidator := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) - res, err = handleMsgUndelegate(ctx, msgUndelegateValidator, keeper) + msgUndelegateValidator := staking.NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) + res, err = handler(ctx, msgUndelegateValidator) require.NoError(t, err) require.NotNil(t, res) @@ -751,7 +765,7 @@ func TestValidatorQueue(t *testing.T) { require.NoError(t, err) ctx = ctx.WithBlockTime(finishTime) - EndBlocker(ctx, keeper) + staking.EndBlocker(ctx, keeper) origHeader := ctx.BlockHeader() @@ -761,7 +775,7 @@ func TestValidatorQueue(t *testing.T) { // should still be unbonding at time 6 seconds later ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 6)) - EndBlocker(ctx, keeper) + staking.EndBlocker(ctx, keeper) validator, found = keeper.GetValidator(ctx, validatorAddr) require.True(t, found) @@ -769,7 +783,7 @@ func TestValidatorQueue(t *testing.T) { // should be in unbonded state at time 7 seconds later ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 7)) - EndBlocker(ctx, keeper) + staking.EndBlocker(ctx, keeper) validator, found = keeper.GetValidator(ctx, validatorAddr) require.True(t, found) @@ -778,6 +792,7 @@ func TestValidatorQueue(t *testing.T) { func TestUnbondingPeriod(t *testing.T) { ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + handler := staking.NewHandler(keeper) validatorAddr := sdk.ValAddress(keep.Addrs[0]) // set the unbonding time @@ -788,16 +803,16 @@ func TestUnbondingPeriod(t *testing.T) { // create the validator valTokens := sdk.TokensFromConsensusPower(10) msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], valTokens) - res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + res, err := handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) - EndBlocker(ctx, keeper) + staking.EndBlocker(ctx, keeper) // begin unbonding unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(10)) - msgUndelegate := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) - res, err = handleMsgUndelegate(ctx, msgUndelegate, keeper) + msgUndelegate := staking.NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) + res, err = handler(ctx, msgUndelegate) require.NoError(t, err) require.NotNil(t, res) @@ -807,43 +822,44 @@ func TestUnbondingPeriod(t *testing.T) { require.True(t, found, "should not have unbonded") // cannot complete unbonding at same time - EndBlocker(ctx, keeper) + staking.EndBlocker(ctx, keeper) _, found = keeper.GetUnbondingDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) require.True(t, found, "should not have unbonded") // cannot complete unbonding at time 6 seconds later ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 6)) - EndBlocker(ctx, keeper) + staking.EndBlocker(ctx, keeper) _, found = keeper.GetUnbondingDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) require.True(t, found, "should not have unbonded") // can complete unbonding at time 7 seconds later ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 7)) - EndBlocker(ctx, keeper) + staking.EndBlocker(ctx, keeper) _, found = keeper.GetUnbondingDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) require.False(t, found, "should have unbonded") } func TestUnbondingFromUnbondingValidator(t *testing.T) { ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + handler := staking.NewHandler(keeper) validatorAddr, delegatorAddr := sdk.ValAddress(keep.Addrs[0]), keep.Addrs[1] // create the validator msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], sdk.NewInt(10)) - res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + res, err := handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) // bond a delegator msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, sdk.NewInt(10)) - res, err = handleMsgDelegate(ctx, msgDelegate, keeper) + res, err = handler(ctx, msgDelegate) require.NoError(t, err) require.NotNil(t, res) // unbond the validators bond portion unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) - msgUndelegateValidator := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) - res, err = handleMsgUndelegate(ctx, msgUndelegateValidator, keeper) + msgUndelegateValidator := staking.NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) + res, err = handler(ctx, msgUndelegateValidator) require.NoError(t, err) require.NotNil(t, res) @@ -857,15 +873,15 @@ func TestUnbondingFromUnbondingValidator(t *testing.T) { ctx = ctx.WithBlockTime(finishTime.Add(time.Second * -1)) // unbond the delegator from the validator - msgUndelegateDelegator := NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) - res, err = handleMsgUndelegate(ctx, msgUndelegateDelegator, keeper) + msgUndelegateDelegator := staking.NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) + res, err = handler(ctx, msgUndelegateDelegator) require.NoError(t, err) require.NotNil(t, res) ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(keeper.UnbondingTime(ctx))) // Run the EndBlocker - EndBlocker(ctx, keeper) + staking.EndBlocker(ctx, keeper) // Check to make sure that the unbonding delegation is no longer in state // (meaning it was deleted in the above EndBlocker) @@ -875,6 +891,7 @@ func TestUnbondingFromUnbondingValidator(t *testing.T) { func TestRedelegationPeriod(t *testing.T) { ctx, _, bk, keeper, _ := keep.CreateTestInput(t, false, 1000) + handler := staking.NewHandler(keeper) validatorAddr, validatorAddr2 := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1]) denom := keeper.GetParams(ctx).BondDenom @@ -889,7 +906,7 @@ func TestRedelegationPeriod(t *testing.T) { // initial balance amt1 := bk.GetBalance(ctx, sdk.AccAddress(validatorAddr), denom).Amount - res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + res, err := handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) @@ -898,7 +915,7 @@ func TestRedelegationPeriod(t *testing.T) { require.Equal(t, amt1.Sub(sdk.NewInt(10)).Int64(), amt2.Int64(), "expected coins to be subtracted") msgCreateValidator = NewTestMsgCreateValidator(validatorAddr2, keep.PKs[1], sdk.NewInt(10)) - res, err = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + res, err = handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) @@ -906,8 +923,8 @@ func TestRedelegationPeriod(t *testing.T) { // begin redelegate redAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) - msgBeginRedelegate := NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2, redAmt) - res, err = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) + msgBeginRedelegate := staking.NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2, redAmt) + res, err = handler(ctx, msgBeginRedelegate) require.NoError(t, err) require.NotNil(t, res) @@ -918,25 +935,27 @@ func TestRedelegationPeriod(t *testing.T) { origHeader := ctx.BlockHeader() // cannot complete redelegation at same time - EndBlocker(ctx, keeper) + staking.EndBlocker(ctx, keeper) _, found := keeper.GetRedelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2) require.True(t, found, "should not have unbonded") // cannot complete redelegation at time 6 seconds later ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 6)) - EndBlocker(ctx, keeper) + staking.EndBlocker(ctx, keeper) _, found = keeper.GetRedelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2) require.True(t, found, "should not have unbonded") // can complete redelegation at time 7 seconds later ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 7)) - EndBlocker(ctx, keeper) + staking.EndBlocker(ctx, keeper) _, found = keeper.GetRedelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2) require.False(t, found, "should have unbonded") } func TestTransitiveRedelegation(t *testing.T) { ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + handler := staking.NewHandler(keeper) + validatorAddr := sdk.ValAddress(keep.Addrs[0]) validatorAddr2 := sdk.ValAddress(keep.Addrs[1]) validatorAddr3 := sdk.ValAddress(keep.Addrs[2]) @@ -946,30 +965,30 @@ func TestTransitiveRedelegation(t *testing.T) { // create the validators msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], sdk.NewInt(10)) - res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + res, err := handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) msgCreateValidator = NewTestMsgCreateValidator(validatorAddr2, keep.PKs[1], sdk.NewInt(10)) - res, err = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + res, err = handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) msgCreateValidator = NewTestMsgCreateValidator(validatorAddr3, keep.PKs[2], sdk.NewInt(10)) - res, err = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + res, err = handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) // begin redelegate redAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) - msgBeginRedelegate := NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2, redAmt) - res, err = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) + msgBeginRedelegate := staking.NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2, redAmt) + res, err = handler(ctx, msgBeginRedelegate) require.NoError(t, err) require.NotNil(t, res) // cannot redelegation to next validator while first delegation exists - msgBeginRedelegate = NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr2, validatorAddr3, redAmt) - res, err = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) + msgBeginRedelegate = staking.NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr2, validatorAddr3, redAmt) + res, err = handler(ctx, msgBeginRedelegate) require.Error(t, err) require.Nil(t, res) @@ -977,16 +996,18 @@ func TestTransitiveRedelegation(t *testing.T) { ctx = ctx.WithBlockTime(blockTime.Add(params.UnbondingTime)) // complete first redelegation - EndBlocker(ctx, keeper) + staking.EndBlocker(ctx, keeper) // now should be able to redelegate from the second validator to the third - res, err = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) + res, err = handler(ctx, msgBeginRedelegate) require.NoError(t, err) require.NotNil(t, res) } func TestMultipleRedelegationAtSameTime(t *testing.T) { ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + handler := staking.NewHandler(keeper) + valAddr := sdk.ValAddress(keep.Addrs[0]) valAddr2 := sdk.ValAddress(keep.Addrs[1]) @@ -998,23 +1019,23 @@ func TestMultipleRedelegationAtSameTime(t *testing.T) { // create the validators valTokens := sdk.TokensFromConsensusPower(10) msgCreateValidator := NewTestMsgCreateValidator(valAddr, keep.PKs[0], valTokens) - res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + res, err := handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) msgCreateValidator = NewTestMsgCreateValidator(valAddr2, keep.PKs[1], valTokens) - res, err = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + res, err = handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) // end block to bond them - EndBlocker(ctx, keeper) + staking.EndBlocker(ctx, keeper) // begin a redelegate selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) redAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens.QuoRaw(2)) - msgBeginRedelegate := NewMsgBeginRedelegate(selfDelAddr, valAddr, valAddr2, redAmt) - res, err = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) + msgBeginRedelegate := staking.NewMsgBeginRedelegate(selfDelAddr, valAddr, valAddr2, redAmt) + res, err = handler(ctx, msgBeginRedelegate) require.NoError(t, err) require.NotNil(t, res) @@ -1024,7 +1045,7 @@ func TestMultipleRedelegationAtSameTime(t *testing.T) { require.Len(t, rd.Entries, 1) // start a second redelegation at this same time as the first - res, err = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) + res, err = handler(ctx, msgBeginRedelegate) require.NoError(t, err) require.NotNil(t, res) @@ -1035,7 +1056,7 @@ func TestMultipleRedelegationAtSameTime(t *testing.T) { // move forward in time, should complete both redelegations ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(1 * time.Second)) - EndBlocker(ctx, keeper) + staking.EndBlocker(ctx, keeper) rd, found = keeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) require.False(t, found) @@ -1043,6 +1064,8 @@ func TestMultipleRedelegationAtSameTime(t *testing.T) { func TestMultipleRedelegationAtUniqueTimes(t *testing.T) { ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + handler := staking.NewHandler(keeper) + valAddr := sdk.ValAddress(keep.Addrs[0]) valAddr2 := sdk.ValAddress(keep.Addrs[1]) @@ -1054,29 +1077,29 @@ func TestMultipleRedelegationAtUniqueTimes(t *testing.T) { // create the validators valTokens := sdk.TokensFromConsensusPower(10) msgCreateValidator := NewTestMsgCreateValidator(valAddr, keep.PKs[0], valTokens) - res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + res, err := handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) msgCreateValidator = NewTestMsgCreateValidator(valAddr2, keep.PKs[1], valTokens) - res, err = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + res, err = handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) // end block to bond them - EndBlocker(ctx, keeper) + staking.EndBlocker(ctx, keeper) // begin a redelegate selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) redAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens.QuoRaw(2)) - msgBeginRedelegate := NewMsgBeginRedelegate(selfDelAddr, valAddr, valAddr2, redAmt) - res, err = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) + msgBeginRedelegate := staking.NewMsgBeginRedelegate(selfDelAddr, valAddr, valAddr2, redAmt) + res, err = handler(ctx, msgBeginRedelegate) require.NoError(t, err) require.NotNil(t, res) // move forward in time and start a second redelegation ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) - res, err = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) + res, err = handler(ctx, msgBeginRedelegate) require.NoError(t, err) require.NotNil(t, res) @@ -1087,20 +1110,22 @@ func TestMultipleRedelegationAtUniqueTimes(t *testing.T) { // move forward in time, should complete the first redelegation, but not the second ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) - EndBlocker(ctx, keeper) + staking.EndBlocker(ctx, keeper) rd, found = keeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) require.True(t, found) require.Len(t, rd.Entries, 1) // move forward in time, should complete the second redelegation ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) - EndBlocker(ctx, keeper) + staking.EndBlocker(ctx, keeper) rd, found = keeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) require.False(t, found) } func TestMultipleUnbondingDelegationAtSameTime(t *testing.T) { ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + handler := staking.NewHandler(keeper) + valAddr := sdk.ValAddress(keep.Addrs[0]) // set the unbonding time @@ -1111,18 +1136,18 @@ func TestMultipleUnbondingDelegationAtSameTime(t *testing.T) { // create the validator valTokens := sdk.TokensFromConsensusPower(10) msgCreateValidator := NewTestMsgCreateValidator(valAddr, keep.PKs[0], valTokens) - res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + res, err := handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) // end block to bond - EndBlocker(ctx, keeper) + staking.EndBlocker(ctx, keeper) // begin an unbonding delegation selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens.QuoRaw(2)) - msgUndelegate := NewMsgUndelegate(selfDelAddr, valAddr, unbondAmt) - res, err = handleMsgUndelegate(ctx, msgUndelegate, keeper) + msgUndelegate := staking.NewMsgUndelegate(selfDelAddr, valAddr, unbondAmt) + res, err = handler(ctx, msgUndelegate) require.NoError(t, err) require.NotNil(t, res) @@ -1132,7 +1157,7 @@ func TestMultipleUnbondingDelegationAtSameTime(t *testing.T) { require.Len(t, ubd.Entries, 1) // start a second ubd at this same time as the first - res, err = handleMsgUndelegate(ctx, msgUndelegate, keeper) + res, err = handler(ctx, msgUndelegate) require.NoError(t, err) require.NotNil(t, res) @@ -1143,7 +1168,7 @@ func TestMultipleUnbondingDelegationAtSameTime(t *testing.T) { // move forwaubd in time, should complete both ubds ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(1 * time.Second)) - EndBlocker(ctx, keeper) + staking.EndBlocker(ctx, keeper) ubd, found = keeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) require.False(t, found) @@ -1151,6 +1176,7 @@ func TestMultipleUnbondingDelegationAtSameTime(t *testing.T) { func TestMultipleUnbondingDelegationAtUniqueTimes(t *testing.T) { ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + handler := staking.NewHandler(keeper) valAddr := sdk.ValAddress(keep.Addrs[0]) // set the unbonding time @@ -1161,18 +1187,18 @@ func TestMultipleUnbondingDelegationAtUniqueTimes(t *testing.T) { // create the validator valTokens := sdk.TokensFromConsensusPower(10) msgCreateValidator := NewTestMsgCreateValidator(valAddr, keep.PKs[0], valTokens) - res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + res, err := handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) // end block to bond - EndBlocker(ctx, keeper) + staking.EndBlocker(ctx, keeper) // begin an unbonding delegation selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens.QuoRaw(2)) - msgUndelegate := NewMsgUndelegate(selfDelAddr, valAddr, unbondAmt) - res, err = handleMsgUndelegate(ctx, msgUndelegate, keeper) + msgUndelegate := staking.NewMsgUndelegate(selfDelAddr, valAddr, unbondAmt) + res, err = handler(ctx, msgUndelegate) require.NoError(t, err) require.NotNil(t, res) @@ -1183,7 +1209,7 @@ func TestMultipleUnbondingDelegationAtUniqueTimes(t *testing.T) { // move forwaubd in time and start a second redelegation ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) - res, err = handleMsgUndelegate(ctx, msgUndelegate, keeper) + res, err = handler(ctx, msgUndelegate) require.NoError(t, err) require.NotNil(t, res) @@ -1194,20 +1220,22 @@ func TestMultipleUnbondingDelegationAtUniqueTimes(t *testing.T) { // move forwaubd in time, should complete the first redelegation, but not the second ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) - EndBlocker(ctx, keeper) + staking.EndBlocker(ctx, keeper) ubd, found = keeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) require.True(t, found) require.Len(t, ubd.Entries, 1) // move forwaubd in time, should complete the second redelegation ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) - EndBlocker(ctx, keeper) + staking.EndBlocker(ctx, keeper) ubd, found = keeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) require.False(t, found) } func TestUnbondingWhenExcessValidators(t *testing.T) { ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + handler := staking.NewHandler(keeper) + validatorAddr1 := sdk.ValAddress(keep.Addrs[0]) validatorAddr2 := sdk.ValAddress(keep.Addrs[1]) validatorAddr3 := sdk.ValAddress(keep.Addrs[2]) @@ -1220,7 +1248,7 @@ func TestUnbondingWhenExcessValidators(t *testing.T) { // add three validators valTokens1 := sdk.TokensFromConsensusPower(50) msgCreateValidator := NewTestMsgCreateValidator(validatorAddr1, keep.PKs[0], valTokens1) - res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + res, err := handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) @@ -1230,7 +1258,7 @@ func TestUnbondingWhenExcessValidators(t *testing.T) { valTokens2 := sdk.TokensFromConsensusPower(30) msgCreateValidator = NewTestMsgCreateValidator(validatorAddr2, keep.PKs[1], valTokens2) - res, err = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + res, err = handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) @@ -1240,7 +1268,7 @@ func TestUnbondingWhenExcessValidators(t *testing.T) { valTokens3 := sdk.TokensFromConsensusPower(10) msgCreateValidator = NewTestMsgCreateValidator(validatorAddr3, keep.PKs[2], valTokens3) - res, err = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + res, err = handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) @@ -1250,8 +1278,8 @@ func TestUnbondingWhenExcessValidators(t *testing.T) { // unbond the validator-2 unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens2) - msgUndelegate := NewMsgUndelegate(sdk.AccAddress(validatorAddr2), validatorAddr2, unbondAmt) - res, err = handleMsgUndelegate(ctx, msgUndelegate, keeper) + msgUndelegate := staking.NewMsgUndelegate(sdk.AccAddress(validatorAddr2), validatorAddr2, unbondAmt) + res, err = handler(ctx, msgUndelegate) require.NoError(t, err) require.NotNil(t, res) @@ -1270,23 +1298,25 @@ func TestUnbondingWhenExcessValidators(t *testing.T) { func TestBondUnbondRedelegateSlashTwice(t *testing.T) { ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + handler := staking.NewHandler(keeper) + valA, valB, del := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1]), keep.Addrs[2] consAddr0 := sdk.ConsAddress(keep.PKs[0].Address()) valTokens := sdk.TokensFromConsensusPower(10) msgCreateValidator := NewTestMsgCreateValidator(valA, keep.PKs[0], valTokens) - res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + res, err := handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) msgCreateValidator = NewTestMsgCreateValidator(valB, keep.PKs[1], valTokens) - res, err = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + res, err = handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) // delegate 10 stake msgDelegate := NewTestMsgDelegate(del, valA, valTokens) - res, err = handleMsgDelegate(ctx, msgDelegate, keeper) + res, err = handler(ctx, msgDelegate) require.NoError(t, err) require.NotNil(t, res) @@ -1299,15 +1329,15 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) { // begin unbonding 4 stake unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(4)) - msgUndelegate := NewMsgUndelegate(del, valA, unbondAmt) - res, err = handleMsgUndelegate(ctx, msgUndelegate, keeper) + msgUndelegate := staking.NewMsgUndelegate(del, valA, unbondAmt) + res, err = handler(ctx, msgUndelegate) require.NoError(t, err) require.NotNil(t, res) // begin redelegate 6 stake redAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(6)) - msgBeginRedelegate := NewMsgBeginRedelegate(del, valA, valB, redAmt) - res, err = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) + msgBeginRedelegate := staking.NewMsgBeginRedelegate(del, valA, valB, redAmt) + res, err = handler(ctx, msgBeginRedelegate) require.NoError(t, err) require.NotNil(t, res) @@ -1365,7 +1395,7 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) { require.Equal(t, sdk.NewDecFromInt(redAmt.Amount.QuoRaw(2)), delegation.Shares) // end blocker - EndBlocker(ctx, keeper) + staking.EndBlocker(ctx, keeper) // validator power should have been reduced to zero // validator should be in unbonding state @@ -1375,7 +1405,7 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) { func TestInvalidMsg(t *testing.T) { k := keep.Keeper{} - h := NewHandler(k) + h := staking.NewHandler(k) res, err := h(sdk.NewContext(nil, abci.Header{}, false, nil), sdk.NewTestMsg()) require.Error(t, err) @@ -1385,6 +1415,8 @@ func TestInvalidMsg(t *testing.T) { func TestInvalidCoinDenom(t *testing.T) { ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + handler := staking.NewHandler(keeper) + valA, valB, delAddr := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1]), keep.Addrs[2] valTokens := sdk.TokensFromConsensusPower(100) @@ -1394,48 +1426,48 @@ func TestInvalidCoinDenom(t *testing.T) { commission := types.NewCommissionRates(sdk.OneDec(), sdk.OneDec(), sdk.ZeroDec()) - msgCreate := types.NewMsgCreateValidator(valA, keep.PKs[0], invalidCoin, Description{}, commission, sdk.OneInt()) - res, err := handleMsgCreateValidator(ctx, msgCreate, keeper) + msgCreate := types.NewMsgCreateValidator(valA, keep.PKs[0], invalidCoin, staking.Description{}, commission, sdk.OneInt()) + res, err := handler(ctx, msgCreate) require.Error(t, err) require.Nil(t, res) - msgCreate = types.NewMsgCreateValidator(valA, keep.PKs[0], validCoin, Description{}, commission, sdk.OneInt()) - res, err = handleMsgCreateValidator(ctx, msgCreate, keeper) + msgCreate = types.NewMsgCreateValidator(valA, keep.PKs[0], validCoin, staking.Description{}, commission, sdk.OneInt()) + res, err = handler(ctx, msgCreate) require.NoError(t, err) require.NotNil(t, res) - msgCreate = types.NewMsgCreateValidator(valB, keep.PKs[1], validCoin, Description{}, commission, sdk.OneInt()) - res, err = handleMsgCreateValidator(ctx, msgCreate, keeper) + msgCreate = types.NewMsgCreateValidator(valB, keep.PKs[1], validCoin, staking.Description{}, commission, sdk.OneInt()) + res, err = handler(ctx, msgCreate) require.NoError(t, err) require.NotNil(t, res) msgDelegate := types.NewMsgDelegate(delAddr, valA, invalidCoin) - res, err = handleMsgDelegate(ctx, msgDelegate, keeper) + res, err = handler(ctx, msgDelegate) require.Error(t, err) require.Nil(t, res) msgDelegate = types.NewMsgDelegate(delAddr, valA, validCoin) - res, err = handleMsgDelegate(ctx, msgDelegate, keeper) + res, err = handler(ctx, msgDelegate) require.NoError(t, err) require.NotNil(t, res) msgUndelegate := types.NewMsgUndelegate(delAddr, valA, invalidCoin) - res, err = handleMsgUndelegate(ctx, msgUndelegate, keeper) + res, err = handler(ctx, msgUndelegate) require.Error(t, err) require.Nil(t, res) msgUndelegate = types.NewMsgUndelegate(delAddr, valA, oneCoin) - res, err = handleMsgUndelegate(ctx, msgUndelegate, keeper) + res, err = handler(ctx, msgUndelegate) require.NoError(t, err) require.NotNil(t, res) msgRedelegate := types.NewMsgBeginRedelegate(delAddr, valA, valB, invalidCoin) - res, err = handleMsgBeginRedelegate(ctx, msgRedelegate, keeper) + res, err = handler(ctx, msgRedelegate) require.Error(t, err) require.Nil(t, res) msgRedelegate = types.NewMsgBeginRedelegate(delAddr, valA, valB, oneCoin) - res, err = handleMsgBeginRedelegate(ctx, msgRedelegate, keeper) + res, err = handler(ctx, msgRedelegate) require.NoError(t, err) require.NotNil(t, res) } diff --git a/x/staking/test_common.go b/x/staking/test_common.go deleted file mode 100644 index c7b1073fc74f..000000000000 --- a/x/staking/test_common.go +++ /dev/null @@ -1,57 +0,0 @@ -package staking - -import ( - "github.com/tendermint/tendermint/crypto" - "github.com/tendermint/tendermint/crypto/secp256k1" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/staking/types" -) - -// nolint:deadcode,unused,varcheck -var ( - priv1 = secp256k1.GenPrivKey() - addr1 = sdk.AccAddress(priv1.PubKey().Address()) - priv2 = secp256k1.GenPrivKey() - addr2 = sdk.AccAddress(priv2.PubKey().Address()) - addr3 = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) - priv4 = secp256k1.GenPrivKey() - addr4 = sdk.AccAddress(priv4.PubKey().Address()) - coins = sdk.Coins{sdk.NewCoin("foocoin", sdk.NewInt(10))} - fee = auth.NewStdFee( - 100000, - sdk.Coins{sdk.NewCoin("foocoin", sdk.NewInt(0))}, - ) - - commissionRates = NewCommissionRates(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()) -) - -func NewTestMsgCreateValidator(address sdk.ValAddress, pubKey crypto.PubKey, amt sdk.Int) MsgCreateValidator { - return types.NewMsgCreateValidator( - address, pubKey, sdk.NewCoin(sdk.DefaultBondDenom, amt), Description{}, commissionRates, sdk.OneInt(), - ) -} - -func NewTestMsgCreateValidatorWithCommission(address sdk.ValAddress, pubKey crypto.PubKey, - amt sdk.Int, commissionRate sdk.Dec) MsgCreateValidator { - - commission := NewCommissionRates(commissionRate, sdk.OneDec(), sdk.ZeroDec()) - - return types.NewMsgCreateValidator( - address, pubKey, sdk.NewCoin(sdk.DefaultBondDenom, amt), Description{}, commission, sdk.OneInt(), - ) -} - -func NewTestMsgCreateValidatorWithMinSelfDelegation(address sdk.ValAddress, pubKey crypto.PubKey, - amt sdk.Int, minSelfDelegation sdk.Int) MsgCreateValidator { - - return types.NewMsgCreateValidator( - address, pubKey, sdk.NewCoin(sdk.DefaultBondDenom, amt), Description{}, commissionRates, minSelfDelegation, - ) -} - -func NewTestMsgDelegate(delAddr sdk.AccAddress, valAddr sdk.ValAddress, amt sdk.Int) MsgDelegate { - amount := sdk.NewCoin(sdk.DefaultBondDenom, amt) - return NewMsgDelegate(delAddr, valAddr, amount) -} From c77bb7b038e9876a98dbf4c89f2bc794e960d3e5 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Sun, 16 Feb 2020 19:06:45 +0000 Subject: [PATCH 136/529] Squash various linter warnings (#5652) Closes: #5651 --- server/export.go | 2 +- server/util.go | 4 ++-- x/distribution/types/params_test.go | 2 +- x/genutil/client/cli/init.go | 4 ++-- x/slashing/app_test.go | 1 - x/staking/app_test.go | 4 ++-- 6 files changed, 8 insertions(+), 9 deletions(-) diff --git a/server/export.go b/server/export.go index e2e74943bec4..b4f52f639c59 100644 --- a/server/export.go +++ b/server/export.go @@ -24,7 +24,7 @@ const ( ) // ExportCmd dumps app state to JSON. -func ExportCmd(ctx *Context, cdc *codec.Codec, appExporter AppExporter) *cobra.Command { +func ExportCmd(ctx *Context, cdc codec.JSONMarshaler, appExporter AppExporter) *cobra.Command { cmd := &cobra.Command{ Use: "export", Short: "Export state to JSON", diff --git a/server/util.go b/server/util.go index eb22c230268e..0f4f62945c7c 100644 --- a/server/util.go +++ b/server/util.go @@ -118,7 +118,7 @@ func interceptLoadConfig() (conf *cfg.Config, err error) { // add server commands func AddCommands( - ctx *Context, cdc *codec.Codec, + ctx *Context, cdc codec.JSONMarshaler, rootCmd *cobra.Command, appCreator AppCreator, appExport AppExporter) { @@ -154,7 +154,7 @@ func AddCommands( // // NOTE: The ordering of the keys returned as the resulting JSON message is // non-deterministic, so the client should not rely on key ordering. -func InsertKeyJSON(cdc *codec.Codec, baseJSON []byte, key string, value json.RawMessage) ([]byte, error) { +func InsertKeyJSON(cdc codec.JSONMarshaler, baseJSON []byte, key string, value json.RawMessage) ([]byte, error) { var jsonMap map[string]json.RawMessage if err := cdc.UnmarshalJSON(baseJSON, &jsonMap); err != nil { diff --git a/x/distribution/types/params_test.go b/x/distribution/types/params_test.go index 143e2d30d77d..cf250160477a 100644 --- a/x/distribution/types/params_test.go +++ b/x/distribution/types/params_test.go @@ -24,7 +24,7 @@ func Test_validateAuxFuncs(t *testing.T) { {"two dec", args{sdk.NewDec(2)}, true}, } for _, tt := range tests { - tt = tt + tt := tt t.Run(tt.name, func(t *testing.T) { require.Equal(t, tt.wantErr, validateCommunityTax(tt.args.i) != nil) require.Equal(t, tt.wantErr, validateBaseProposerReward(tt.args.i) != nil) diff --git a/x/genutil/client/cli/init.go b/x/genutil/client/cli/init.go index b87691d1d0f2..618f389da579 100644 --- a/x/genutil/client/cli/init.go +++ b/x/genutil/client/cli/init.go @@ -48,7 +48,7 @@ func newPrintInfo(moniker, chainID, nodeID, genTxsDir string, } } -func displayInfo(cdc *codec.Codec, info printInfo) error { +func displayInfo(cdc codec.JSONMarshaler, info printInfo) error { out, err := codec.MarshalJSONIndent(cdc, info) if err != nil { return err @@ -60,7 +60,7 @@ func displayInfo(cdc *codec.Codec, info printInfo) error { // InitCmd returns a command that initializes all files needed for Tendermint // and the respective application. -func InitCmd(ctx *server.Context, cdc *codec.Codec, mbm module.BasicManager, +func InitCmd(ctx *server.Context, cdc codec.JSONMarshaler, mbm module.BasicManager, defaultNodeHome string) *cobra.Command { // nolint: golint cmd := &cobra.Command{ Use: "init [moniker]", diff --git a/x/slashing/app_test.go b/x/slashing/app_test.go index 1cb0fcd437a3..262e0227f196 100644 --- a/x/slashing/app_test.go +++ b/x/slashing/app_test.go @@ -20,7 +20,6 @@ import ( var ( priv1 = secp256k1.GenPrivKey() addr1 = sdk.AccAddress(priv1.PubKey().Address()) - coins = sdk.Coins{sdk.NewInt64Coin("foocoin", 10)} ) func checkValidator(t *testing.T, app *simapp.SimApp, addr sdk.AccAddress, expFound bool) staking.Validator { diff --git a/x/staking/app_test.go b/x/staking/app_test.go index 03aab5d64339..f013e6323b48 100644 --- a/x/staking/app_test.go +++ b/x/staking/app_test.go @@ -49,11 +49,11 @@ func TestStakingMsgs(t *testing.T) { acc2 := &auth.BaseAccount{Address: addr2} accs := authexported.GenesisAccounts{acc1, acc2} balances := []bank.Balance{ - bank.Balance{ + { Address: addr1, Coins: sdk.Coins{genCoin}, }, - bank.Balance{ + { Address: addr2, Coins: sdk.Coins{genCoin}, }, From 235aa6c091aa66d6108be3faf99b8bb93e41b626 Mon Sep 17 00:00:00 2001 From: Gerry Agbobada <10496163+gagbo@users.noreply.github.com> Date: Mon, 17 Feb 2020 10:17:34 +0100 Subject: [PATCH 137/529] Merge PR #5648: Add min-height and max-height filters to TxSearch --- CHANGELOG.md | 3 +++ client/lcd/swagger-ui/swagger.yaml | 10 ++++++++++ types/rest/rest.go | 6 ++++++ types/rest/rest_test.go | 3 +++ 4 files changed, 22 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa10acf3c1e3..5c6b57be3ef6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -100,6 +100,9 @@ for JSON encoding. * (types) [\#5585](https://github.com/cosmos/cosmos-sdk/pull/5585) IBC additions: * `Coin` denomination max lenght has been increased to 32. * Added `CapabilityKey` alias for `StoreKey` to match IBC spec. +* (rest) [\#5648](https://github.com/cosmos/cosmos-sdk/pull/5648) Enhance /txs usability: + * Add `tx.minheight` key to filter transaction with an inclusive minimum block height + * Add `tx.maxheight` key to filter transaction with an inclusive maximum block height ## [v0.38.1] - 2020-02-11 diff --git a/client/lcd/swagger-ui/swagger.yaml b/client/lcd/swagger-ui/swagger.yaml index c802f42a8e92..0b246d4b466d 100644 --- a/client/lcd/swagger-ui/swagger.yaml +++ b/client/lcd/swagger-ui/swagger.yaml @@ -268,6 +268,16 @@ paths: description: Maximum number of items per page type: integer x-example: 1 + - in: query + name: tx.minheight + type: integer + description: "transactions on blocks with height greater or equal this value" + x-example: 25 + - in: query + name: tx.maxheight + type: integer + description: "transactions on blocks with height less than or equal this value" + x-example: 800000 responses: 200: description: All txs matching the provided events diff --git a/types/rest/rest.go b/types/rest/rest.go index a58a56252553..0a2f6486a8bc 100644 --- a/types/rest/rest.go +++ b/types/rest/rest.go @@ -22,6 +22,8 @@ import ( const ( DefaultPage = 1 DefaultLimit = 30 // should be consistent with tendermint/tendermint/rpc/core/pipe.go:19 + TxMinHeightKey = "tx.minheight" // Inclusive minimum height filter + TxMaxHeightKey = "tx.maxheight" // Inclusive maximum height filter ) // ResponseWithHeight defines a response object type that wraps an original @@ -337,6 +339,10 @@ func ParseHTTPArgsWithLimit(r *http.Request, defaultLimit int) (tags []string, p var tag string if key == types.TxHeightKey { tag = fmt.Sprintf("%s=%s", key, value) + } else if key == TxMinHeightKey { + tag = fmt.Sprintf("%s>=%s", types.TxHeightKey, value) + } else if key == TxMaxHeightKey { + tag = fmt.Sprintf("%s<=%s", types.TxHeightKey, value) } else { tag = fmt.Sprintf("%s='%s'", key, value) } diff --git a/types/rest/rest_test.go b/types/rest/rest_test.go index 4c283a90e260..e23766cdd342 100644 --- a/types/rest/rest_test.go +++ b/types/rest/rest_test.go @@ -71,6 +71,8 @@ func TestParseHTTPArgs(t *testing.T) { reqE2 := mustNewRequest(t, "", "/?limit=-1", nil) req4 := mustNewRequest(t, "", "/?foo=faa", nil) + reqTxH := mustNewRequest(t, "", "/?tx.minheight=12&tx.maxheight=14", nil) + tests := []struct { name string req *http.Request @@ -89,6 +91,7 @@ func TestParseHTTPArgs(t *testing.T) { {"error limit 0", reqE2, httptest.NewRecorder(), []string{}, DefaultPage, DefaultLimit, true}, {"tags", req4, httptest.NewRecorder(), []string{"foo='faa'"}, DefaultPage, DefaultLimit, false}, + {"tags", reqTxH, httptest.NewRecorder(), []string{"tx.height>=12", "tx.height<=14"}, DefaultPage, DefaultLimit, false}, } for _, tt := range tests { tt := tt From 9b3296be793243082ea1828400a308b137c16ead Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Mon, 17 Feb 2020 14:46:48 +0100 Subject: [PATCH 138/529] Merge PR #5655: Fix TestParseHTTPArgs --- types/rest/rest_test.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/types/rest/rest_test.go b/types/rest/rest_test.go index e23766cdd342..6088569c8f09 100644 --- a/types/rest/rest_test.go +++ b/types/rest/rest_test.go @@ -7,6 +7,7 @@ import ( "io/ioutil" "net/http" "net/http/httptest" + "sort" "testing" "github.com/stretchr/testify/require" @@ -91,12 +92,15 @@ func TestParseHTTPArgs(t *testing.T) { {"error limit 0", reqE2, httptest.NewRecorder(), []string{}, DefaultPage, DefaultLimit, true}, {"tags", req4, httptest.NewRecorder(), []string{"foo='faa'"}, DefaultPage, DefaultLimit, false}, - {"tags", reqTxH, httptest.NewRecorder(), []string{"tx.height>=12", "tx.height<=14"}, DefaultPage, DefaultLimit, false}, + {"tags", reqTxH, httptest.NewRecorder(), []string{"tx.height<=14", "tx.height>=12"}, DefaultPage, DefaultLimit, false}, } for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { tags, page, limit, err := ParseHTTPArgs(tt.req) + + sort.Strings(tags) + if tt.err { require.NotNil(t, err) } else { From fa5120a5d851f1eb918f9bb7681725b15f5f1e3d Mon Sep 17 00:00:00 2001 From: gamarin2 Date: Mon, 17 Feb 2020 15:08:16 +0100 Subject: [PATCH 139/529] Merge PR #5654: Replace Lino with Kava in docs --- docs/intro/overview.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/intro/overview.md b/docs/intro/overview.md index f7e2242afcfa..b6f1ebce97c3 100644 --- a/docs/intro/overview.md +++ b/docs/intro/overview.md @@ -25,7 +25,7 @@ The Cosmos SDK is the most advanced framework for building custom application-sp - The default consensus engine available within the SDK is [Tendermint Core](https://github.com/tendermint/tendermint). Tendermint is the most (and only) mature BFT consensus engine in existence. It is widely used across the industry and is considered the gold standard consensus engine for building Proof-of-Stake systems. - The SDK is open source and designed to make it easy to build blockchains out of composable [modules](../../x/). As the ecosystem of open source SDK modules grows, it will become increasingly easier to build complex decentralised platforms with it. - The SDK is inspired by capabilities-based security, and informed by years of wrestling with blockchain state-machines. This makes the Cosmos SDK a very secure environment to build blockchains. -- Most importantly, the Cosmos SDK has already been used to build many application-specific blockchains that are already in production. Among others, we can cite [Cosmos Hub](https://hub.cosmos.network), [IRIS Hub](https://irisnet.org), [Binance Chain](https://docs.binance.org/), [Terra](https://terra.money/) or [Lino](https://lino.network/). [Many more](https://cosmos.network/ecosystem) are building on the Cosmos SDK. +- Most importantly, the Cosmos SDK has already been used to build many application-specific blockchains that are already in production. Among others, we can cite [Cosmos Hub](https://hub.cosmos.network), [IRIS Hub](https://irisnet.org), [Binance Chain](https://docs.binance.org/), [Terra](https://terra.money/) or [Kava](https://www.kava.io/). [Many more](https://cosmos.network/ecosystem) are building on the Cosmos SDK. ## Getting started with the Cosmos SDK @@ -34,4 +34,4 @@ The Cosmos SDK is the most advanced framework for building custom application-sp ## Next {hide} -Learn about [application-specific blockchains](./why-app-specific.md) {hide} \ No newline at end of file +Learn about [application-specific blockchains](./why-app-specific.md) {hide} From 5ee65cb897c94011c4a3ed7f72c34e8d45d97c67 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Mon, 17 Feb 2020 17:10:54 +0100 Subject: [PATCH 140/529] Merge PR #5650: ADR 019 - Protocol Buffer State Encoding --- docs/architecture/README.md | 1 + .../adr-019-protobuf-state-encoding.md | 248 ++++++++++++++++++ docs/architecture/adr-template.md | 2 +- 3 files changed, 250 insertions(+), 1 deletion(-) create mode 100644 docs/architecture/adr-019-protobuf-state-encoding.md diff --git a/docs/architecture/README.md b/docs/architecture/README.md index afa60a75241a..09632c114eb6 100644 --- a/docs/architecture/README.md +++ b/docs/architecture/README.md @@ -43,3 +43,4 @@ Please add a entry below in your Pull Request for an ADR. - [ADR 016: Validator Consensus Key Rotation](./adr-016-validator-consensus-key-rotation.md) - [ADR 017: Historical Header Module](./adr-017-historical-header-module.md) - [ADR 018: Extendable Voting Periods](./adr-018-extendable-voting-period.md) +- [ADR 019: Protocol Buffer State Encoding](./adr-019-protobuf-state-encoding.md) diff --git a/docs/architecture/adr-019-protobuf-state-encoding.md b/docs/architecture/adr-019-protobuf-state-encoding.md new file mode 100644 index 000000000000..f43c53e8155c --- /dev/null +++ b/docs/architecture/adr-019-protobuf-state-encoding.md @@ -0,0 +1,248 @@ +# ADR 019: Protocol Buffer State Encoding + +## Changelog + +- 2020 Feb 15: Initial Draft + +## Status + +Accepted + +## Context + +Currently, the Cosmos SDK utilizes [go-amino](https://github.com/tendermint/go-amino/) for binary +and JSON object encoding over the wire bringing parity between logical objects and persistence objects. + +From the Amino docs: + +> Amino is an object encoding specification. It is a subset of Proto3 with an extension for interface +> support. See the [Proto3 spec](https://developers.google.com/protocol-buffers/docs/proto3) for more +> information on Proto3, which Amino is largely compatible with (but not with Proto2). +> +> The goal of the Amino encoding protocol is to bring parity into logic objects and persistence objects. + +Amino also aims to have the following goals (not a complete list): + +- Binary bytes must be decode-able with a schema. +- Schema must be upgradeable. +- The encoder and decoder logic must be reasonably simple. + +However, we believe that Amino does not fulfill these goals completely and does not fully meet the +needs of a truly flexible cross-language and multi-client compatible encoding protocol in the Cosmos SDK. +Namely, Amino has proven to be a big pain-point in regards to supporting object serialization across +clients written in various languages while providing virtually little in the way of true backwards +compatibility and upgradeability. Furthermore, through profiling and various benchmarks, Amino has +been shown to be an extremely large performance bottleneck in the Cosmos SDK 1. This is +largely reflected in the performance of simulations and application transaction throughput. + +Thus, we need to adopt an encoding protocol that meets the following criteria for state serialization: + +- Language agnostic +- Platform agnostic +- Rich client support and thriving ecosystem +- High performance +- Minimal encoded message size +- Codegen-based over reflection-based +- Supports backward and forward compatibility + +Note, migrating away from Amino should be viewed as a two-pronged approach, state and client encoding. +This ADR focuses on state serialization in the Cosmos SDK state machine. A corresponding ADR will be +made to address client-side encoding. + +## Decision + +We will adopt [Protocol Buffers](https://developers.google.com/protocol-buffers) for serializing +persisted structured data in the Cosmos SDK while providing a clean mechanism and developer UX for +applications wishing to continue to use Amino. We will provide this mechanism by updating modules to +accept a codec interface, `Marshaler`, instead of a concrete Amino codec. Furthermore, the Cosmos SDK +will provide three concrete implementations of the `Marshaler` interface: `AminoCodec`, `ProtoCodec`, +and `HybridCodec`. + +- `AminoCodec`: Uses Amino for both binary and JSON encoding. +- `ProtoCodec`: Uses Protobuf for or both binary and JSON encoding. +- `HybridCodec`: Uses Amino for JSON encoding and Protobuf for binary encoding. + +Until the client migration landscape is fully understood and designed, modules will use a `HybridCodec` +as the concrete codec it accepts and/or extends. This means that all client JSON encoding, including +genesis state, will still use Amino. The ultimate goal will be to replace Amino JSON encoding with +Protbuf encoding and thus have modules accept and/or extend `ProtoCodec`. + +### Module Design + +Modules that do not require the ability to work with and serialize interfaces, the path to Protobuf +migration is pretty straightforward. These modules are to simply migrate any existing types that +are encoded and persisted via their concrete Amino codec to Protobuf and have their keeper accept a +`Marshaler` that will be a `HybridCodec`. This migration is simple as things will just work as-is. + +Note, any business logic that needs to encode primitive types like `bool` or `int64` should use +[gogoprotobuf](https://github.com/gogo/protobuf) Value types. + +Example: + +```go + ts, err := gogotypes.TimestampProto(completionTime) + if err != nil { + // ... + } + + bz := cdc.MustMarshalBinaryLengthPrefixed(ts) +``` + +However, modules can vary greatly in purpose and design and so we must support the ability for modules +to be able to encode and work with interfaces (e.g. `Account` or `Content`). For these modules, they +must define their own codec interface that extends `Marshaler`. These specific interfaces are unique +to the module and will contain method contracts that know how to serialize the needed interfaces. + +Example: + +```go +// x/auth/types/codec.go + +type Codec interface { + codec.Marshaler + + MarshalAccount(acc exported.Account) ([]byte, error) + UnmarshalAccount(bz []byte) (exported.Account, error) + + MarshalAccountJSON(acc exported.Account) ([]byte, error) + UnmarshalAccountJSON(bz []byte) (exported.Account, error) +} +``` + +Note, concrete types implementing these interfaces can be defined outside the scope of the module +that defines the interface (e.g. `ModuleAccount` in `x/supply`). To handle these cases, a Protobuf +message must be defined at the application-level along with a single codec that will be passed to _all_ +modules using a `oneof` approach. + +Example: + +```protobuf +// app/codec/codec.proto + +import "third_party/proto/cosmos-proto/cosmos.proto"; +import "x/auth/types/types.proto"; +import "x/auth/vesting/types/types.proto"; +import "x/supply/types/types.proto"; + +message Account { + option (cosmos_proto.interface_type) = "*github.com/cosmos/cosmos-sdk/x/auth/exported.Account"; + + // sum defines a list of all acceptable concrete Account implementations. + oneof sum { + cosmos_sdk.x.auth.v1.BaseAccount base_account = 1; + cosmos_sdk.x.auth.vesting.v1.ContinuousVestingAccount continuous_vesting_account = 2; + cosmos_sdk.x.auth.vesting.v1.DelayedVestingAccount delayed_vesting_account = 3; + cosmos_sdk.x.auth.vesting.v1.PeriodicVestingAccount periodic_vesting_account = 4; + cosmos_sdk.x.supply.v1.ModuleAccount module_account = 5; + } + + // ... +} +``` + +```go +// app/codec/codec.go + +import ( + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/supply" + authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" + // ... +) + +var ( + _ auth.Codec = (*Codec)(nil) + // ... +) + +type Codec struct { + codec.Marshaler + + + amino *codec.Codec +} + +func NewAppCodec(amino *codec.Codec) *Codec { + return &Codec{Marshaler: codec.NewHybridCodec(amino), amino: amino} +} + +func (c *Codec) MarshalAccount(accI authexported.Account) ([]byte, error) { + acc := &Account{} + if err := acc.SetAccount(accI); err != nil { + return nil, err + } + + return c.Marshaler.MarshalBinaryLengthPrefixed(acc) +} + +func (c *Codec) UnmarshalAccount(bz []byte) (authexported.Account, error) { + acc := &Account{} + if err := c.Marshaler.UnmarshalBinaryLengthPrefixed(bz, acc); err != nil { + return nil, err + } + + return acc.GetAccount(), nil +} +``` + +Since the `Codec` implements `auth.Codec` (and all other required interfaces), it is passed to _all_ +the modules and satisfies all the interfaces. Now each module needing to work with interfaces will know +about all the required types. Note, the use of `interface_type` allows us to avoid a significant +amount of code boilerplate when implementing the `Codec`. + +A similar concept is to be applied for messages that contain interfaces fields. The module will +define a "base" concrete message type (e.g. `MsgSubmitProposalBase`) that the application-level codec +will extend via `oneof` (e.g. `MsgSubmitProposal`) that fulfills the required interface +(e.g. `MsgSubmitProposalI`). Note, however, the module's message handler must now switch on the +interface rather than the concrete type for this particular message. + +### Why Wasn't X Chosen Instead + +For a more complete comparison to alternative protocols, see [here](https://codeburst.io/json-vs-protocol-buffers-vs-flatbuffers-a4247f8bda6f). + +### Cap'n Proto + +While [Cap’n Proto](https://capnproto.org/) does seem like an advantageous alternative to Protobuf +due to it's native support for interfaces/generics and built in canonicalization, it does lack the +rich client ecosystem compared to Protobuf and is a bit less mature. + +### FlatBuffers + +[FlatBuffers](https://google.github.io/flatbuffers/) is also a potentially viable alternative, with the +primary difference being that FlatBuffers does not need a parsing/unpacking step to a secondary +representation before you can access data, often coupled with per-object memory allocation. + +However, it would require great efforts into research and full understanding the scope of the migration +and path forward -- which isn't immediately clear. In addition, FlatBuffers aren't designed for +untrusted inputs. + +## Future Improvements & Roadmap + +The landscape and roadmap to restructuring queriers and tx generation to fully support +Protobuf isn't fully understood yet. Once all modules are migrated, we will have a better +understanding on how to proceed with client improvements (e.g. gRPC) 2. + +## Consequences + +### Positive + +- Significant performance gains. +- Supports backward and forward type compatibility. +- Better support for cross-language clients. + +### Negative + +- Learning curve required to understand and implement Protobuf messages. +- Less flexibility in cross-module type registration. We now need to define types +at the application-level. +- Client business logic and tx generation may become a bit more complex. + +### Neutral + +{neutral consequences} + +## References + +1. https://github.com/cosmos/cosmos-sdk/issues/4977 +2. https://github.com/cosmos/cosmos-sdk/issues/5444 diff --git a/docs/architecture/adr-template.md b/docs/architecture/adr-template.md index 0638a71f4535..71b67a011c40 100644 --- a/docs/architecture/adr-template.md +++ b/docs/architecture/adr-template.md @@ -37,4 +37,4 @@ ## References -- {reference link} \ No newline at end of file +- {reference link} From 8a74dcafb5718a855951d7f01774f816771954fb Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Mon, 17 Feb 2020 16:30:18 +0000 Subject: [PATCH 141/529] Merge PR #5656: Make golangci-lint happy again --- types/rest/rest.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/types/rest/rest.go b/types/rest/rest.go index 0a2f6486a8bc..a6339097e765 100644 --- a/types/rest/rest.go +++ b/types/rest/rest.go @@ -20,8 +20,8 @@ import ( ) const ( - DefaultPage = 1 - DefaultLimit = 30 // should be consistent with tendermint/tendermint/rpc/core/pipe.go:19 + DefaultPage = 1 + DefaultLimit = 30 // should be consistent with tendermint/tendermint/rpc/core/pipe.go:19 TxMinHeightKey = "tx.minheight" // Inclusive minimum height filter TxMaxHeightKey = "tx.maxheight" // Inclusive maximum height filter ) @@ -337,13 +337,14 @@ func ParseHTTPArgsWithLimit(r *http.Request, defaultLimit int) (tags []string, p } var tag string - if key == types.TxHeightKey { + switch key { + case types.TxHeightKey: tag = fmt.Sprintf("%s=%s", key, value) - } else if key == TxMinHeightKey { + case TxMinHeightKey: tag = fmt.Sprintf("%s>=%s", types.TxHeightKey, value) - } else if key == TxMaxHeightKey { + case TxMaxHeightKey: tag = fmt.Sprintf("%s<=%s", types.TxHeightKey, value) - } else { + default: tag = fmt.Sprintf("%s='%s'", key, value) } tags = append(tags, tag) From c0a4222e6bc2acb6113b8d0108ad8cf1a6b56036 Mon Sep 17 00:00:00 2001 From: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Date: Mon, 17 Feb 2020 21:22:48 +0100 Subject: [PATCH 142/529] remove Rigel from codeowners (#5552) * remove Rigel from codeowners * [skip ci] * [skip ci] Co-authored-by: Christopher Goes Co-authored-by: Alexander Bezobchuk --- .github/CODEOWNERS | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 1c7206ff75f8..ca82ba88da02 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,13 +1,4 @@ # CODEOWNERS: https://help.github.com/articles/about-codeowners/ # Primary repo maintainers -* @rigelrozanski @alexanderbez @jackzampolin @alessio @fedekunze - -############################################################################### -# Module Specific Ownership -# See CONTRIBUTING.md for further details -############################################################################### - -# The following contributors own all files in the x/nft directory at the root -# of the repository and any of its subdirectories. -x/nft @okwme @fedekunze +* @alexanderbez @jackzampolin @alessio @fedekunze From f912618b8a68efce3240ea2051627b50e2a9aadb Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Tue, 18 Feb 2020 13:42:53 +0100 Subject: [PATCH 143/529] use simapp into keeper --- x/staking/keeper/keeper_test.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/x/staking/keeper/keeper_test.go b/x/staking/keeper/keeper_test.go index dbde12e7b1a9..8b59555e6554 100644 --- a/x/staking/keeper/keeper_test.go +++ b/x/staking/keeper/keeper_test.go @@ -1,24 +1,28 @@ -package keeper +package keeper_test import ( "testing" "github.com/stretchr/testify/require" + "github.com/cosmos/cosmos-sdk/simapp" "github.com/cosmos/cosmos-sdk/x/staking/types" + abci "github.com/tendermint/tendermint/abci/types" ) func TestParams(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 0) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + expParams := types.DefaultParams() //check that the empty keeper loads the default - resParams := keeper.GetParams(ctx) + resParams := app.StakingKeeper.GetParams(ctx) require.True(t, expParams.Equal(resParams)) //modify a params, save, and retrieve expParams.MaxValidators = 777 - keeper.SetParams(ctx, expParams) - resParams = keeper.GetParams(ctx) + app.StakingKeeper.SetParams(ctx, expParams) + resParams = app.StakingKeeper.GetParams(ctx) require.True(t, expParams.Equal(resParams)) } From 794a496892fda71adfae748eddba483a86187671 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Tue, 18 Feb 2020 13:50:13 +0100 Subject: [PATCH 144/529] Merge PR #5533: Protobuf: x/auth & x/supply --- CHANGELOG.md | 21 +- go.mod | 2 +- go.sum | 7 +- simapp/app.go | 20 +- simapp/codec.go | 46 - simapp/codec/codec.go | 128 ++ simapp/codec/codec.pb.go | 1039 ++++++++++++ simapp/codec/codec.proto | 33 + simapp/export.go | 2 +- simapp/genesis.go | 6 +- simapp/sim_test.go | 2 +- simapp/utils_test.go | 3 +- types/module/module.go | 31 +- x/auth/alias.go | 11 +- x/auth/ante/basic.go | 8 +- x/auth/ante/sigverify.go | 10 +- x/auth/client/cli/query.go | 2 +- x/auth/client/cli/tx_multisign.go | 2 +- x/auth/client/cli/tx_sign.go | 2 +- x/auth/client/rest/query.go | 2 +- x/auth/client/tx.go | 22 +- x/auth/keeper/account.go | 20 +- x/auth/keeper/keeper.go | 36 +- x/auth/module.go | 16 +- x/auth/simulation/decoder.go | 2 + x/auth/simulation/genesis.go | 4 +- x/auth/types/account.go | 127 +- x/auth/types/account_retriever.go | 15 +- x/auth/types/account_retriever_test.go | 7 +- x/auth/types/account_test.go | 66 +- x/auth/types/codec.go | 37 +- x/auth/types/common_test.go | 11 + x/auth/types/genesis.go | 5 +- x/auth/types/genesis_test.go | 36 +- x/auth/types/params.go | 34 +- x/auth/types/stdtx.go | 19 +- .../types/{test_common.go => test_utils.go} | 0 x/auth/types/types.pb.go | 1001 ++++++++++++ x/auth/types/types.proto | 49 + x/auth/vesting/alias.go | 11 +- x/auth/vesting/types/codec.go | 12 +- x/auth/vesting/types/common_test.go | 11 + x/auth/vesting/types/genesis_test.go | 4 +- x/auth/vesting/types/period.go | 13 +- x/auth/vesting/types/types.pb.go | 1404 +++++++++++++++++ x/auth/vesting/types/types.proto | 76 + x/auth/vesting/types/vesting_account.go | 118 +- x/auth/vesting/types/vesting_account_test.go | 273 ++-- x/bank/app_test.go | 2 +- x/bank/internal/keeper/keeper_test.go | 16 +- x/bank/module.go | 16 +- x/crisis/internal/types/codec.go | 38 +- x/crisis/module.go | 16 +- x/distribution/alias.go | 2 - x/distribution/keeper/test_common.go | 9 +- x/distribution/module.go | 16 +- x/distribution/types/codec.go | 38 +- x/evidence/module.go | 16 +- x/genutil/client/cli/gentx.go | 2 +- x/genutil/client/cli/init.go | 2 +- x/genutil/client/cli/validate_genesis.go | 2 +- x/genutil/module.go | 14 +- x/gov/genesis_test.go | 8 +- x/gov/keeper/test_common.go | 16 +- x/gov/module.go | 16 +- x/mint/module.go | 16 +- x/params/module.go | 4 +- x/slashing/internal/keeper/test_common.go | 10 +- x/slashing/module.go | 14 +- x/staking/alias.go | 2 - x/staking/keeper/test_common.go | 15 +- x/staking/module.go | 16 +- x/staking/types/codec.go | 39 +- x/supply/alias.go | 13 +- x/supply/client/cli/query.go | 2 +- x/supply/client/rest/query.go | 2 +- x/supply/exported/exported.go | 9 +- x/supply/genesis.go | 2 +- x/supply/internal/keeper/integration_test.go | 35 - x/supply/internal/keeper/keeper_test.go | 38 - x/supply/internal/types/codec.go | 24 - x/supply/{internal => }/keeper/account.go | 2 +- x/supply/{internal => }/keeper/bank.go | 6 +- x/supply/{internal => }/keeper/bank_test.go | 66 +- x/supply/{internal => }/keeper/invariants.go | 2 +- x/supply/{internal => }/keeper/keeper.go | 36 +- x/supply/keeper/keeper_test.go | 55 + x/supply/{internal => }/keeper/key.go | 0 x/supply/{internal => }/keeper/querier.go | 2 +- .../{internal => }/keeper/querier_test.go | 13 +- x/supply/module.go | 18 +- x/supply/simulation/decoder.go | 5 +- x/supply/simulation/decoder_test.go | 4 +- x/supply/simulation/genesis.go | 2 +- x/supply/{internal => }/types/account.go | 21 +- x/supply/{internal => }/types/account_test.go | 6 +- x/supply/types/codec.go | 45 + .../{internal => }/types/expected_keepers.go | 0 x/supply/{internal => }/types/genesis.go | 0 x/supply/{internal => }/types/key.go | 0 x/supply/{internal => }/types/permissions.go | 0 .../{internal => }/types/permissions_test.go | 0 x/supply/{internal => }/types/querier.go | 0 x/supply/{internal => }/types/supply.go | 41 +- x/supply/{internal => }/types/supply_test.go | 2 +- x/supply/types/types.pb.go | 605 +++++++ x/supply/types/types.proto | 31 + x/upgrade/module.go | 10 +- 108 files changed, 5235 insertions(+), 1013 deletions(-) delete mode 100644 simapp/codec.go create mode 100644 simapp/codec/codec.go create mode 100644 simapp/codec/codec.pb.go create mode 100644 simapp/codec/codec.proto create mode 100644 x/auth/types/common_test.go rename x/auth/types/{test_common.go => test_utils.go} (100%) create mode 100644 x/auth/types/types.pb.go create mode 100644 x/auth/types/types.proto create mode 100644 x/auth/vesting/types/common_test.go create mode 100644 x/auth/vesting/types/types.pb.go create mode 100644 x/auth/vesting/types/types.proto delete mode 100644 x/supply/internal/keeper/integration_test.go delete mode 100644 x/supply/internal/keeper/keeper_test.go delete mode 100644 x/supply/internal/types/codec.go rename x/supply/{internal => }/keeper/account.go (97%) rename x/supply/{internal => }/keeper/bank.go (97%) rename x/supply/{internal => }/keeper/bank_test.go (72%) rename x/supply/{internal => }/keeper/invariants.go (95%) rename x/supply/{internal => }/keeper/keeper.go (74%) create mode 100644 x/supply/keeper/keeper_test.go rename x/supply/{internal => }/keeper/key.go (100%) rename x/supply/{internal => }/keeper/querier.go (97%) rename x/supply/{internal => }/keeper/querier_test.go (89%) rename x/supply/{internal => }/types/account.go (85%) rename x/supply/{internal => }/types/account_test.go (99%) create mode 100644 x/supply/types/codec.go rename x/supply/{internal => }/types/expected_keepers.go (100%) rename x/supply/{internal => }/types/genesis.go (100%) rename x/supply/{internal => }/types/key.go (100%) rename x/supply/{internal => }/types/permissions.go (100%) rename x/supply/{internal => }/types/permissions_test.go (100%) rename x/supply/{internal => }/types/querier.go (100%) rename x/supply/{internal => }/types/supply.go (56%) rename x/supply/{internal => }/types/supply_test.go (94%) create mode 100644 x/supply/types/types.pb.go create mode 100644 x/supply/types/types.proto diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c6b57be3ef6..09179f2640bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -57,6 +57,8 @@ flushed to disk or kept as a snapshot. Note, `KeepRecent` is automatically infer and provided directly the IAVL store. * (modules) [\#5555](https://github.com/cosmos/cosmos-sdk/pull/5555) Move x/auth/client/utils/ types and functions to x/auth/client/. * (modules) [\#5572](https://github.com/cosmos/cosmos-sdk/pull/5572) Move account balance logic and APIs from `x/auth` to `x/bank`. +* (types) [\#5533](https://github.com/cosmos/cosmos-sdk/pull/5533) Refactored `AppModuleBasic` and `AppModuleGenesis` +to now accept a `codec.JSONMarshaler` for modular serialization of genesis state. ### Bug Fixes @@ -72,7 +74,7 @@ and provided directly the IAVL store. * Callers to `NewBaseVestingAccount` are responsible for verifying account balance in relation to the original vesting amount. * The `SendKeeper` and `ViewKeeper` interfaces in `x/bank` have been modified to account for changes. -* (staking) [\#5600](https://github.com/cosmos/cosmos-sdk/pull/5600) Migrate the `x/staking` module to use Protocol Buffer for state +* (x/staking) [\#5600](https://github.com/cosmos/cosmos-sdk/pull/5600) Migrate the `x/staking` module to use Protocol Buffers for state serialization instead of Amino. The exact codec used is `codec.HybridCodec` which utilizes Protobuf for binary encoding and Amino for JSON encoding. * `BondStatus` is now of type `int32` instead of `byte`. @@ -80,7 +82,7 @@ for JSON encoding. * Every reference of `crypto.Pubkey` in context of a `Validator` is now of type string. `GetPubKeyFromBech32` must be used to get the `crypto.Pubkey`. * The `Keeper` constructor now takes a `codec.Marshaler` instead of a concrete Amino codec. This exact type provided is specified by `ModuleCdc`. -* (distr) [\#5610](https://github.com/cosmos/cosmos-sdk/pull/5610) Migrate the `x/distribution` module to use Protocol Buffer for state +* (x/distribution) [\#5610](https://github.com/cosmos/cosmos-sdk/pull/5610) Migrate the `x/distribution` module to use Protocol Buffers for state serialization instead of Amino. The exact codec used is `codec.HybridCodec` which utilizes Protobuf for binary encoding and Amino for JSON encoding. * `ValidatorHistoricalRewards.ReferenceCount` is now of types `uint32` instead of `uint16`. @@ -89,6 +91,21 @@ for JSON encoding. * `ValidatorAccumulatedCommission` is now a struct with `commission`. * The `Keeper` constructor now takes a `codec.Marshaler` instead of a concrete Amino codec. This exact type provided is specified by `ModuleCdc`. +* (x/auth) [\#5533](https://github.com/cosmos/cosmos-sdk/pull/5533) Migrate the `x/auth` module to use Protocol Buffers for state +serialization instead of Amino. + * The `BaseAccount.PubKey` field is now represented as a Bech32 string instead of a `crypto.Pubkey`. + * `NewBaseAccountWithAddress` now returns a reference to a `BaseAccount`. + * The `x/auth` module now accepts a `Codec` interface which extends the `codec.Marshaler` interface by + requiring a concrete codec to know how to serialize accounts. + * The `AccountRetriever` type now accepts a `Codec` in its constructor in order to know how to + serialize accounts. +* (x/supply) [\#5533](https://github.com/cosmos/cosmos-sdk/pull/5533) Migrate the `x/supply` module to use Protocol Buffers for state +serialization instead of Amino. + * The `internal` sub-package has been removed in order to expose the types proto file. + * The `x/supply` module now accepts a `Codec` interface which extends the `codec.Marshaler` interface by + requiring a concrete codec to know how to serialize `SupplyI` types. + * The `SupplyI` interface has been modified to no longer return `SupplyI` on methods. Instead the + concrete type's receiver should modify the type. ### Improvements diff --git a/go.mod b/go.mod index 47579d904e90..7d634c42c83b 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/pelletier/go-toml v1.6.0 github.com/pkg/errors v0.9.1 github.com/rakyll/statik v0.1.6 - github.com/regen-network/cosmos-proto v0.1.0 + github.com/regen-network/cosmos-proto v0.1.1-0.20200213154359-02baa11ea7c2 github.com/spf13/afero v1.2.1 // indirect github.com/spf13/cobra v0.0.5 github.com/spf13/jwalterweatherman v1.1.0 // indirect diff --git a/go.sum b/go.sum index 8177d91a3f08..1aa44bd73fe1 100644 --- a/go.sum +++ b/go.sum @@ -91,7 +91,6 @@ github.com/golang/mock v1.3.1-0.20190508161146-9fa652df1129/go.mod h1:sBzyDLLjw3 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= @@ -196,8 +195,8 @@ github.com/rakyll/statik v0.1.6 h1:uICcfUXpgqtw2VopbIncslhAmE5hwc4g20TEyEENBNs= github.com/rakyll/statik v0.1.6/go.mod h1:OEi9wJV/fMUAGx1eNjq75DKDsJVuEv1U0oYdX6GX8Zs= github.com/rcrowley/go-metrics v0.0.0-20180503174638-e2704e165165 h1:nkcn14uNmFEuGCb2mBZbBb24RdNRL08b/wb+xBOYpuk= github.com/rcrowley/go-metrics v0.0.0-20180503174638-e2704e165165/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/regen-network/cosmos-proto v0.1.0 h1:gsV+YO2kMvY430zQn8ioPXRxEJgb/ms0iMPeWo3VEyY= -github.com/regen-network/cosmos-proto v0.1.0/go.mod h1:+r7jN10xXCypD4yBgzKOa+vgLz0riqYMHeDcKekxPvA= +github.com/regen-network/cosmos-proto v0.1.1-0.20200213154359-02baa11ea7c2 h1:jQK1YoH972Aptd22YKgtNu5jM2X2xMGkyIENOAc71to= +github.com/regen-network/cosmos-proto v0.1.1-0.20200213154359-02baa11ea7c2/go.mod h1:+r7jN10xXCypD4yBgzKOa+vgLz0riqYMHeDcKekxPvA= github.com/regen-network/protobuf v1.3.2-alpha.regen.1 h1:YdeZbBS0lG1D13COb7b57+nM/RGgIs8WF9DwitU6EBM= github.com/regen-network/protobuf v1.3.2-alpha.regen.1/go.mod h1:lye6mqhOn/GCw1zRl3uPD5VP8rC+LPMyTyPAyQV872U= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= @@ -253,7 +252,6 @@ github.com/tendermint/go-amino v0.15.1 h1:D2uk35eT4iTsvJd9jWIetzthE5C0/k2QmMFkCN github.com/tendermint/go-amino v0.15.1/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= github.com/tendermint/iavl v0.13.0 h1:r2sINvNFlJsLlLhGoqlqPlREWYkuK26BvMfkBt+XQnA= github.com/tendermint/iavl v0.13.0/go.mod h1:7nSUPdrsHEZ2nNZa+9gaIrcJciWd1jCQZXtcyARU82k= -github.com/tendermint/tendermint v0.33.0 h1:TW1g9sQs3YSqKM8o1+opL3/VmBy4Ke/VKV9MxYpqNbI= github.com/tendermint/tendermint v0.33.0/go.mod h1:s5UoymnPIY+GcA3mMte4P9gpMP8vS7UH7HBXikT1pHI= github.com/tendermint/tendermint v0.33.1 h1:8f68LUBz8yhISZvaLFP4siXXrLWsWeoYfelbdNtmvm4= github.com/tendermint/tendermint v0.33.1/go.mod h1:fBOKyrlXOETqQ+heL8x/TZgSdmItON54csyabvktBp0= @@ -341,7 +339,6 @@ google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvx google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.26.0 h1:2dTRdpdFEEhJYQD8EMLB61nnrzSCTbG38PhqdhvOltg= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= diff --git a/simapp/app.go b/simapp/app.go index 20215e8486f9..8c77d03c54ad 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -11,6 +11,7 @@ import ( bam "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/codec" + simappcodec "github.com/cosmos/cosmos-sdk/simapp/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/version" @@ -78,7 +79,6 @@ var ( } ) -// Verify app interface at compile time var _ App = (*SimApp)(nil) // SimApp extends an ABCI application, but with most of its parameters exported. @@ -124,10 +124,10 @@ func NewSimApp( invCheckPeriod uint, baseAppOptions ...func(*bam.BaseApp), ) *SimApp { - appCodec := NewAppCodec() - // TODO: Remove cdc in favor of appCodec once all modules are migrated. - cdc := MakeCodec() + cdc := simappcodec.MakeCodec(ModuleBasics) + + appCodec := simappcodec.NewAppCodec(cdc) bApp := bam.NewBaseApp(appName, logger, db, auth.DefaultTxDecoder(cdc), baseAppOptions...) bApp.SetCommitMultiStoreTracer(traceStore) @@ -150,7 +150,7 @@ func NewSimApp( } // init params keeper and subspaces - app.ParamsKeeper = params.NewKeeper(appCodec.Params, keys[params.StoreKey], tkeys[params.TStoreKey]) + app.ParamsKeeper = params.NewKeeper(appCodec, keys[params.StoreKey], tkeys[params.TStoreKey]) app.subspaces[auth.ModuleName] = app.ParamsKeeper.Subspace(auth.DefaultParamspace) app.subspaces[bank.ModuleName] = app.ParamsKeeper.Subspace(bank.DefaultParamspace) app.subspaces[staking.ModuleName] = app.ParamsKeeper.Subspace(staking.DefaultParamspace) @@ -163,23 +163,23 @@ func NewSimApp( // add keepers app.AccountKeeper = auth.NewAccountKeeper( - app.cdc, keys[auth.StoreKey], app.subspaces[auth.ModuleName], auth.ProtoBaseAccount, + appCodec, keys[auth.StoreKey], app.subspaces[auth.ModuleName], auth.ProtoBaseAccount, ) app.BankKeeper = bank.NewBaseKeeper( app.cdc, keys[bank.StoreKey], app.AccountKeeper, app.subspaces[bank.ModuleName], app.BlacklistedAccAddrs(), ) app.SupplyKeeper = supply.NewKeeper( - app.cdc, keys[supply.StoreKey], app.AccountKeeper, app.BankKeeper, maccPerms, + appCodec, keys[supply.StoreKey], app.AccountKeeper, app.BankKeeper, maccPerms, ) stakingKeeper := staking.NewKeeper( - appCodec.Staking, keys[staking.StoreKey], app.BankKeeper, app.SupplyKeeper, app.subspaces[staking.ModuleName], + appCodec, keys[staking.StoreKey], app.BankKeeper, app.SupplyKeeper, app.subspaces[staking.ModuleName], ) app.MintKeeper = mint.NewKeeper( app.cdc, keys[mint.StoreKey], app.subspaces[mint.ModuleName], &stakingKeeper, app.SupplyKeeper, auth.FeeCollectorName, ) app.DistrKeeper = distr.NewKeeper( - appCodec.Distribution, keys[distr.StoreKey], app.subspaces[distr.ModuleName], app.BankKeeper, &stakingKeeper, + appCodec, keys[distr.StoreKey], app.subspaces[distr.ModuleName], app.BankKeeper, &stakingKeeper, app.SupplyKeeper, auth.FeeCollectorName, app.ModuleAccountAddrs(), ) app.SlashingKeeper = slashing.NewKeeper( @@ -305,7 +305,7 @@ func (app *SimApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.Re func (app *SimApp) InitChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { var genesisState GenesisState app.cdc.MustUnmarshalJSON(req.AppStateBytes, &genesisState) - return app.mm.InitGenesis(ctx, genesisState) + return app.mm.InitGenesis(ctx, app.cdc, genesisState) } // LoadHeight loads a particular height diff --git a/simapp/codec.go b/simapp/codec.go deleted file mode 100644 index 0e8aabe15cb2..000000000000 --- a/simapp/codec.go +++ /dev/null @@ -1,46 +0,0 @@ -package simapp - -import ( - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth/vesting" - distr "github.com/cosmos/cosmos-sdk/x/distribution" - "github.com/cosmos/cosmos-sdk/x/params" - "github.com/cosmos/cosmos-sdk/x/staking" -) - -// AppCodec defines the application-level codec. This codec contains all the -// required module-specific codecs that are to be provided upon initialization. -type AppCodec struct { - amino *codec.Codec - - Params *params.Codec - Staking *staking.Codec - Distribution *distr.Codec -} - -func NewAppCodec() *AppCodec { - amino := MakeCodec() - - return &AppCodec{ - amino: amino, - Params: params.NewCodec(amino), - Staking: staking.NewCodec(amino), - Distribution: distr.NewCodec(amino), - } -} - -// MakeCodec creates and returns a reference to an Amino codec that has all the -// necessary types and interfaces registered. This codec is provided to all the -// modules the application depends on. -// -// NOTE: This codec will be deprecated in favor of AppCodec once all modules are -// migrated. -func MakeCodec() *codec.Codec { - var cdc = codec.New() - ModuleBasics.RegisterCodec(cdc) - vesting.RegisterCodec(cdc) - sdk.RegisterCodec(cdc) - codec.RegisterCrypto(cdc) - return cdc -} diff --git a/simapp/codec/codec.go b/simapp/codec/codec.go new file mode 100644 index 000000000000..912bd355bc86 --- /dev/null +++ b/simapp/codec/codec.go @@ -0,0 +1,128 @@ +package codec + +import ( + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + "github.com/cosmos/cosmos-sdk/x/auth" + authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" + "github.com/cosmos/cosmos-sdk/x/auth/vesting" + "github.com/cosmos/cosmos-sdk/x/supply" + "github.com/cosmos/cosmos-sdk/x/supply/exported" +) + +var ( + _ auth.Codec = (*Codec)(nil) + _ supply.Codec = (*Codec)(nil) +) + +// Codec defines the application-level codec. This codec contains all the +// required module-specific codecs that are to be provided upon initialization. +type Codec struct { + codec.Marshaler + + // Keep reference to the amino codec to allow backwards compatibility along + // with type, and interface registration. + amino *codec.Codec +} + +func NewAppCodec(amino *codec.Codec) *Codec { + return &Codec{Marshaler: codec.NewHybridCodec(amino), amino: amino} +} + +// MarshalAccount marshals an Account interface. If the given type implements +// the Marshaler interface, it is treated as a Proto-defined message and +// serialized that way. Otherwise, it falls back on the internal Amino codec. +func (c *Codec) MarshalAccount(accI authexported.Account) ([]byte, error) { + acc := &Account{} + if err := acc.SetAccount(accI); err != nil { + return nil, err + } + + return c.Marshaler.MarshalBinaryLengthPrefixed(acc) +} + +// UnmarshalAccount returns an Account interface from raw encoded account bytes +// of a Proto-based Account type. An error is returned upon decoding failure. +func (c *Codec) UnmarshalAccount(bz []byte) (authexported.Account, error) { + acc := &Account{} + if err := c.Marshaler.UnmarshalBinaryLengthPrefixed(bz, acc); err != nil { + return nil, err + } + + return acc.GetAccount(), nil +} + +// MarshalAccountJSON JSON encodes an account object implementing the Account +// interface. +func (c *Codec) MarshalAccountJSON(acc authexported.Account) ([]byte, error) { + return c.Marshaler.MarshalJSON(acc) +} + +// UnmarshalAccountJSON returns an Account from JSON encoded bytes. +func (c *Codec) UnmarshalAccountJSON(bz []byte) (authexported.Account, error) { + acc := &Account{} + if err := c.Marshaler.UnmarshalJSON(bz, acc); err != nil { + return nil, err + } + + return acc.GetAccount(), nil +} + +// MarshalSupply marshals a SupplyI interface. If the given type implements +// the Marshaler interface, it is treated as a Proto-defined message and +// serialized that way. Otherwise, it falls back on the internal Amino codec. +func (c *Codec) MarshalSupply(supplyI exported.SupplyI) ([]byte, error) { + supply := &Supply{} + if err := supply.SetSupplyI(supplyI); err != nil { + return nil, err + } + + return c.Marshaler.MarshalBinaryLengthPrefixed(supply) +} + +// UnmarshalSupply returns a SupplyI interface from raw encoded account bytes +// of a Proto-based SupplyI type. An error is returned upon decoding failure. +func (c *Codec) UnmarshalSupply(bz []byte) (exported.SupplyI, error) { + supply := &Supply{} + if err := c.Marshaler.UnmarshalBinaryLengthPrefixed(bz, supply); err != nil { + return nil, err + } + + return supply.GetSupplyI(), nil +} + +// MarshalSupplyJSON JSON encodes a supply object implementing the SupplyI +// interface. +func (c *Codec) MarshalSupplyJSON(supply exported.SupplyI) ([]byte, error) { + return c.Marshaler.MarshalJSON(supply) +} + +// UnmarshalSupplyJSON returns a SupplyI from JSON encoded bytes. +func (c *Codec) UnmarshalSupplyJSON(bz []byte) (exported.SupplyI, error) { + supply := &Supply{} + if err := c.Marshaler.UnmarshalJSON(bz, supply); err != nil { + return nil, err + } + + return supply.GetSupplyI(), nil +} + +// ---------------------------------------------------------------------------- + +// MakeCodec creates and returns a reference to an Amino codec that has all the +// necessary types and interfaces registered. This codec is provided to all the +// modules the application depends on. +// +// NOTE: This codec will be deprecated in favor of AppCodec once all modules are +// migrated. +func MakeCodec(bm module.BasicManager) *codec.Codec { + cdc := codec.New() + + bm.RegisterCodec(cdc) + vesting.RegisterCodec(cdc) + sdk.RegisterCodec(cdc) + codec.RegisterCrypto(cdc) + + return cdc +} diff --git a/simapp/codec/codec.pb.go b/simapp/codec/codec.pb.go new file mode 100644 index 000000000000..775948f5a35f --- /dev/null +++ b/simapp/codec/codec.pb.go @@ -0,0 +1,1039 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: simapp/codec/codec.proto + +package codec + +import ( + fmt "fmt" + github_com_cosmos_cosmos_sdk_x_auth_exported "github.com/cosmos/cosmos-sdk/x/auth/exported" + types "github.com/cosmos/cosmos-sdk/x/auth/types" + types1 "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" + github_com_cosmos_cosmos_sdk_x_supply_exported "github.com/cosmos/cosmos-sdk/x/supply/exported" + types2 "github.com/cosmos/cosmos-sdk/x/supply/types" + proto "github.com/gogo/protobuf/proto" + _ "github.com/regen-network/cosmos-proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// Account defines the application-level Account type. +type Account struct { + // sum defines a list of all acceptable concrete Account implementations. + // + // Types that are valid to be assigned to Sum: + // *Account_BaseAccount + // *Account_ContinuousVestingAccount + // *Account_DelayedVestingAccount + // *Account_PeriodicVestingAccount + // *Account_ModuleAccount + Sum isAccount_Sum `protobuf_oneof:"sum"` +} + +func (m *Account) Reset() { *m = Account{} } +func (m *Account) String() string { return proto.CompactTextString(m) } +func (*Account) ProtoMessage() {} +func (*Account) Descriptor() ([]byte, []int) { + return fileDescriptor_3c6d4085e4065f5a, []int{0} +} +func (m *Account) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Account) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Account.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 *Account) XXX_Merge(src proto.Message) { + xxx_messageInfo_Account.Merge(m, src) +} +func (m *Account) XXX_Size() int { + return m.Size() +} +func (m *Account) XXX_DiscardUnknown() { + xxx_messageInfo_Account.DiscardUnknown(m) +} + +var xxx_messageInfo_Account proto.InternalMessageInfo + +type isAccount_Sum interface { + isAccount_Sum() + MarshalTo([]byte) (int, error) + Size() int +} + +type Account_BaseAccount struct { + BaseAccount *types.BaseAccount `protobuf:"bytes,1,opt,name=base_account,json=baseAccount,proto3,oneof" json:"base_account,omitempty"` +} +type Account_ContinuousVestingAccount struct { + ContinuousVestingAccount *types1.ContinuousVestingAccount `protobuf:"bytes,2,opt,name=continuous_vesting_account,json=continuousVestingAccount,proto3,oneof" json:"continuous_vesting_account,omitempty"` +} +type Account_DelayedVestingAccount struct { + DelayedVestingAccount *types1.DelayedVestingAccount `protobuf:"bytes,3,opt,name=delayed_vesting_account,json=delayedVestingAccount,proto3,oneof" json:"delayed_vesting_account,omitempty"` +} +type Account_PeriodicVestingAccount struct { + PeriodicVestingAccount *types1.PeriodicVestingAccount `protobuf:"bytes,4,opt,name=periodic_vesting_account,json=periodicVestingAccount,proto3,oneof" json:"periodic_vesting_account,omitempty"` +} +type Account_ModuleAccount struct { + ModuleAccount *types2.ModuleAccount `protobuf:"bytes,5,opt,name=module_account,json=moduleAccount,proto3,oneof" json:"module_account,omitempty"` +} + +func (*Account_BaseAccount) isAccount_Sum() {} +func (*Account_ContinuousVestingAccount) isAccount_Sum() {} +func (*Account_DelayedVestingAccount) isAccount_Sum() {} +func (*Account_PeriodicVestingAccount) isAccount_Sum() {} +func (*Account_ModuleAccount) isAccount_Sum() {} + +func (m *Account) GetSum() isAccount_Sum { + if m != nil { + return m.Sum + } + return nil +} + +func (m *Account) GetBaseAccount() *types.BaseAccount { + if x, ok := m.GetSum().(*Account_BaseAccount); ok { + return x.BaseAccount + } + return nil +} + +func (m *Account) GetContinuousVestingAccount() *types1.ContinuousVestingAccount { + if x, ok := m.GetSum().(*Account_ContinuousVestingAccount); ok { + return x.ContinuousVestingAccount + } + return nil +} + +func (m *Account) GetDelayedVestingAccount() *types1.DelayedVestingAccount { + if x, ok := m.GetSum().(*Account_DelayedVestingAccount); ok { + return x.DelayedVestingAccount + } + return nil +} + +func (m *Account) GetPeriodicVestingAccount() *types1.PeriodicVestingAccount { + if x, ok := m.GetSum().(*Account_PeriodicVestingAccount); ok { + return x.PeriodicVestingAccount + } + return nil +} + +func (m *Account) GetModuleAccount() *types2.ModuleAccount { + if x, ok := m.GetSum().(*Account_ModuleAccount); ok { + return x.ModuleAccount + } + return nil +} + +// XXX_OneofWrappers is for the internal use of the proto package. +func (*Account) XXX_OneofWrappers() []interface{} { + return []interface{}{ + (*Account_BaseAccount)(nil), + (*Account_ContinuousVestingAccount)(nil), + (*Account_DelayedVestingAccount)(nil), + (*Account_PeriodicVestingAccount)(nil), + (*Account_ModuleAccount)(nil), + } +} + +// Supply defines the application-level Supply type. +type Supply struct { + // sum defines a list of all acceptable concrete Supply implementations. + // + // Types that are valid to be assigned to Sum: + // *Supply_Supply + Sum isSupply_Sum `protobuf_oneof:"sum"` +} + +func (m *Supply) Reset() { *m = Supply{} } +func (m *Supply) String() string { return proto.CompactTextString(m) } +func (*Supply) ProtoMessage() {} +func (*Supply) Descriptor() ([]byte, []int) { + return fileDescriptor_3c6d4085e4065f5a, []int{1} +} +func (m *Supply) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Supply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Supply.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 *Supply) XXX_Merge(src proto.Message) { + xxx_messageInfo_Supply.Merge(m, src) +} +func (m *Supply) XXX_Size() int { + return m.Size() +} +func (m *Supply) XXX_DiscardUnknown() { + xxx_messageInfo_Supply.DiscardUnknown(m) +} + +var xxx_messageInfo_Supply proto.InternalMessageInfo + +type isSupply_Sum interface { + isSupply_Sum() + MarshalTo([]byte) (int, error) + Size() int +} + +type Supply_Supply struct { + Supply *types2.Supply `protobuf:"bytes,1,opt,name=supply,proto3,oneof" json:"supply,omitempty"` +} + +func (*Supply_Supply) isSupply_Sum() {} + +func (m *Supply) GetSum() isSupply_Sum { + if m != nil { + return m.Sum + } + return nil +} + +func (m *Supply) GetSupply() *types2.Supply { + if x, ok := m.GetSum().(*Supply_Supply); ok { + return x.Supply + } + return nil +} + +// XXX_OneofWrappers is for the internal use of the proto package. +func (*Supply) XXX_OneofWrappers() []interface{} { + return []interface{}{ + (*Supply_Supply)(nil), + } +} + +func init() { + proto.RegisterType((*Account)(nil), "cosmos_sdk.simapp.codec.v1.Account") + proto.RegisterType((*Supply)(nil), "cosmos_sdk.simapp.codec.v1.Supply") +} + +func init() { proto.RegisterFile("simapp/codec/codec.proto", fileDescriptor_3c6d4085e4065f5a) } + +var fileDescriptor_3c6d4085e4065f5a = []byte{ + // 444 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x93, 0x4f, 0x8b, 0xd3, 0x40, + 0x18, 0xc6, 0x13, 0x77, 0xb7, 0xc2, 0xac, 0x7a, 0x08, 0xa8, 0x21, 0x87, 0xb0, 0x2e, 0x08, 0xfe, + 0xa1, 0x13, 0xd6, 0xf5, 0xef, 0x7a, 0xb2, 0x15, 0xa9, 0x07, 0x45, 0x2a, 0x78, 0xf0, 0x12, 0x92, + 0x99, 0xa1, 0x0d, 0x6d, 0x32, 0x43, 0x66, 0x26, 0x24, 0x5f, 0xc0, 0xb3, 0x1f, 0xa6, 0x47, 0x3f, + 0x80, 0xf4, 0xd4, 0xa3, 0x47, 0x69, 0xbf, 0x88, 0x74, 0x66, 0x6c, 0x22, 0x49, 0xeb, 0x25, 0xf0, + 0xce, 0xf3, 0xbc, 0xcf, 0xef, 0x0d, 0xf3, 0x0e, 0x70, 0x79, 0x92, 0x46, 0x8c, 0x05, 0x88, 0x62, + 0x82, 0xf4, 0x17, 0xb2, 0x9c, 0x0a, 0xea, 0x78, 0x88, 0xf2, 0x94, 0xf2, 0x90, 0xe3, 0x19, 0xd4, + 0x26, 0xa8, 0xe5, 0xe2, 0xc2, 0x7b, 0x2c, 0xa6, 0x49, 0x8e, 0x43, 0x16, 0xe5, 0xa2, 0x0a, 0x94, + 0x3d, 0xd0, 0xee, 0x7e, 0xb3, 0xd0, 0x41, 0x9e, 0x5b, 0x06, 0x91, 0x14, 0xd3, 0x40, 0x54, 0x8c, + 0x70, 0xfd, 0x35, 0xca, 0x99, 0x51, 0x0a, 0xc2, 0x45, 0x92, 0x4d, 0x3a, 0x1c, 0x5e, 0x19, 0x70, + 0xc9, 0xd8, 0xbc, 0x6a, 0x6b, 0xe7, 0x3f, 0x8e, 0xc1, 0xf5, 0x37, 0x08, 0x51, 0x99, 0x09, 0xe7, + 0x1d, 0xb8, 0x11, 0x47, 0x9c, 0x84, 0x91, 0xae, 0x5d, 0xfb, 0xcc, 0x7e, 0x70, 0xfa, 0xe4, 0x1e, + 0x6c, 0xfc, 0x43, 0x09, 0xb7, 0x2c, 0x58, 0x5c, 0xc0, 0x41, 0xc4, 0x89, 0x69, 0x1c, 0x59, 0xe3, + 0xd3, 0xb8, 0x2e, 0x9d, 0x02, 0x78, 0x88, 0x66, 0x22, 0xc9, 0x24, 0x95, 0x3c, 0x34, 0x73, 0xed, + 0x52, 0xaf, 0xa9, 0xd4, 0xe7, 0x5d, 0xa9, 0xda, 0xb9, 0x4d, 0x1f, 0xee, 0xfa, 0xbf, 0xe8, 0xc3, + 0x1a, 0xe5, 0xa2, 0x3d, 0x9a, 0x93, 0x82, 0xbb, 0x98, 0xcc, 0xa3, 0x8a, 0xe0, 0x16, 0xf4, 0x48, + 0x41, 0x2f, 0x0f, 0x43, 0xdf, 0xea, 0xe6, 0x16, 0xf1, 0x36, 0xee, 0x12, 0x1c, 0x06, 0x5c, 0x46, + 0xf2, 0x84, 0xe2, 0x04, 0xb5, 0x78, 0xc7, 0x8a, 0xf7, 0xf4, 0x30, 0xef, 0x93, 0xe9, 0x6e, 0x01, + 0xef, 0xb0, 0x4e, 0xc5, 0xf9, 0x08, 0x6e, 0xa5, 0x14, 0xcb, 0x79, 0x7d, 0x45, 0x27, 0x8a, 0x73, + 0xff, 0x5f, 0x8e, 0xbe, 0xec, 0x2d, 0xe1, 0x83, 0x72, 0xd7, 0xc1, 0x37, 0xd3, 0xe6, 0xc1, 0xd5, + 0xab, 0xe5, 0xa2, 0xff, 0xec, 0xd1, 0x24, 0x11, 0x53, 0x19, 0x43, 0x44, 0x53, 0xb3, 0x72, 0x7f, + 0xd7, 0x90, 0xe3, 0x59, 0x60, 0x96, 0x8b, 0x94, 0x8c, 0xe6, 0x82, 0x60, 0x68, 0x5a, 0x07, 0x27, + 0xe0, 0x88, 0xcb, 0xf4, 0xfc, 0x9b, 0x0d, 0x7a, 0x9f, 0x15, 0xce, 0x79, 0x09, 0x7a, 0x1a, 0x6c, + 0xf6, 0xc6, 0xdf, 0x37, 0x94, 0xf6, 0x8f, 0xac, 0xb1, 0xf1, 0x5f, 0xbd, 0x5e, 0x2e, 0xfa, 0x2f, + 0xfe, 0x37, 0x86, 0xd9, 0xe0, 0xdd, 0x20, 0x3a, 0xe5, 0xbd, 0x19, 0x64, 0x30, 0xfc, 0xb9, 0xf6, + 0xed, 0xd5, 0xda, 0xb7, 0x7f, 0xaf, 0x7d, 0xfb, 0xfb, 0xc6, 0xb7, 0x56, 0x1b, 0xdf, 0xfa, 0xb5, + 0xf1, 0xad, 0xaf, 0x0f, 0x0f, 0x06, 0x37, 0x5f, 0x6e, 0xdc, 0x53, 0x6f, 0xe2, 0xf2, 0x4f, 0x00, + 0x00, 0x00, 0xff, 0xff, 0xdc, 0xbb, 0x4f, 0xcf, 0xd0, 0x03, 0x00, 0x00, +} + +func (this *Account) GetAccount() github_com_cosmos_cosmos_sdk_x_auth_exported.Account { + if x := this.GetBaseAccount(); x != nil { + return x + } + if x := this.GetContinuousVestingAccount(); x != nil { + return x + } + if x := this.GetDelayedVestingAccount(); x != nil { + return x + } + if x := this.GetPeriodicVestingAccount(); x != nil { + return x + } + if x := this.GetModuleAccount(); x != nil { + return x + } + return nil +} + +func (this *Account) SetAccount(value github_com_cosmos_cosmos_sdk_x_auth_exported.Account) error { + if value == nil { + this.Sum = nil + return nil + } + switch vt := value.(type) { + case *types.BaseAccount: + this.Sum = &Account_BaseAccount{vt} + return nil + case *types1.ContinuousVestingAccount: + this.Sum = &Account_ContinuousVestingAccount{vt} + return nil + case *types1.DelayedVestingAccount: + this.Sum = &Account_DelayedVestingAccount{vt} + return nil + case *types1.PeriodicVestingAccount: + this.Sum = &Account_PeriodicVestingAccount{vt} + return nil + case *types2.ModuleAccount: + this.Sum = &Account_ModuleAccount{vt} + return nil + } + return fmt.Errorf("can't encode value of type %T as message Account", value) +} + +func (this *Supply) GetSupplyI() github_com_cosmos_cosmos_sdk_x_supply_exported.SupplyI { + if x := this.GetSupply(); x != nil { + return x + } + return nil +} + +func (this *Supply) SetSupplyI(value github_com_cosmos_cosmos_sdk_x_supply_exported.SupplyI) error { + if value == nil { + this.Sum = nil + return nil + } + switch vt := value.(type) { + case *types2.Supply: + this.Sum = &Supply_Supply{vt} + return nil + } + return fmt.Errorf("can't encode value of type %T as message Supply", value) +} + +func (m *Account) 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 *Account) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Account) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Sum != nil { + { + size := m.Sum.Size() + i -= size + if _, err := m.Sum.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + } + } + return len(dAtA) - i, nil +} + +func (m *Account_BaseAccount) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Account_BaseAccount) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.BaseAccount != nil { + { + size, err := m.BaseAccount.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} +func (m *Account_ContinuousVestingAccount) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Account_ContinuousVestingAccount) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.ContinuousVestingAccount != nil { + { + size, err := m.ContinuousVestingAccount.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + return len(dAtA) - i, nil +} +func (m *Account_DelayedVestingAccount) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Account_DelayedVestingAccount) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.DelayedVestingAccount != nil { + { + size, err := m.DelayedVestingAccount.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + return len(dAtA) - i, nil +} +func (m *Account_PeriodicVestingAccount) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Account_PeriodicVestingAccount) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.PeriodicVestingAccount != nil { + { + size, err := m.PeriodicVestingAccount.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + return len(dAtA) - i, nil +} +func (m *Account_ModuleAccount) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Account_ModuleAccount) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.ModuleAccount != nil { + { + size, err := m.ModuleAccount.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + return len(dAtA) - i, nil +} +func (m *Supply) 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 *Supply) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Supply) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Sum != nil { + { + size := m.Sum.Size() + i -= size + if _, err := m.Sum.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + } + } + return len(dAtA) - i, nil +} + +func (m *Supply_Supply) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Supply_Supply) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.Supply != nil { + { + size, err := m.Supply.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} +func encodeVarintCodec(dAtA []byte, offset int, v uint64) int { + offset -= sovCodec(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Account) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Sum != nil { + n += m.Sum.Size() + } + return n +} + +func (m *Account_BaseAccount) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.BaseAccount != nil { + l = m.BaseAccount.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *Account_ContinuousVestingAccount) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ContinuousVestingAccount != nil { + l = m.ContinuousVestingAccount.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *Account_DelayedVestingAccount) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.DelayedVestingAccount != nil { + l = m.DelayedVestingAccount.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *Account_PeriodicVestingAccount) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.PeriodicVestingAccount != nil { + l = m.PeriodicVestingAccount.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *Account_ModuleAccount) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ModuleAccount != nil { + l = m.ModuleAccount.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *Supply) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Sum != nil { + n += m.Sum.Size() + } + return n +} + +func (m *Supply_Supply) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Supply != nil { + l = m.Supply.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} + +func sovCodec(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozCodec(x uint64) (n int) { + return sovCodec(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Account) 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 ErrIntOverflowCodec + } + 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: Account: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Account: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BaseAccount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &types.BaseAccount{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Sum = &Account_BaseAccount{v} + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ContinuousVestingAccount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &types1.ContinuousVestingAccount{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Sum = &Account_ContinuousVestingAccount{v} + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DelayedVestingAccount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &types1.DelayedVestingAccount{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Sum = &Account_DelayedVestingAccount{v} + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PeriodicVestingAccount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &types1.PeriodicVestingAccount{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Sum = &Account_PeriodicVestingAccount{v} + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ModuleAccount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &types2.ModuleAccount{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Sum = &Account_ModuleAccount{v} + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCodec(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Supply) 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 ErrIntOverflowCodec + } + 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: Supply: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Supply: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Supply", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &types2.Supply{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Sum = &Supply_Supply{v} + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCodec(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipCodec(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowCodec + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowCodec + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowCodec + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthCodec + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupCodec + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthCodec + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthCodec = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowCodec = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupCodec = fmt.Errorf("proto: unexpected end of group") +) diff --git a/simapp/codec/codec.proto b/simapp/codec/codec.proto new file mode 100644 index 000000000000..811e65d514b8 --- /dev/null +++ b/simapp/codec/codec.proto @@ -0,0 +1,33 @@ +syntax = "proto3"; +package cosmos_sdk.simapp.codec.v1; + +import "third_party/proto/cosmos-proto/cosmos.proto"; +import "x/auth/types/types.proto"; +import "x/auth/vesting/types/types.proto"; +import "x/supply/types/types.proto"; + +option go_package = "github.com/cosmos/cosmos-sdk/simapp/codec"; + +// Account defines the application-level Account type. +message Account { + option (cosmos_proto.interface_type) = "*github.com/cosmos/cosmos-sdk/x/auth/exported.Account"; + + // sum defines a list of all acceptable concrete Account implementations. + oneof sum { + cosmos_sdk.x.auth.v1.BaseAccount base_account = 1; + cosmos_sdk.x.auth.vesting.v1.ContinuousVestingAccount continuous_vesting_account = 2; + cosmos_sdk.x.auth.vesting.v1.DelayedVestingAccount delayed_vesting_account = 3; + cosmos_sdk.x.auth.vesting.v1.PeriodicVestingAccount periodic_vesting_account = 4; + cosmos_sdk.x.supply.v1.ModuleAccount module_account = 5; + } +} + +// Supply defines the application-level Supply type. +message Supply { + option (cosmos_proto.interface_type) = "*github.com/cosmos/cosmos-sdk/x/supply/exported.SupplyI"; + + // sum defines a list of all acceptable concrete Supply implementations. + oneof sum { + cosmos_sdk.x.supply.v1.Supply supply = 1; + } +} diff --git a/simapp/export.go b/simapp/export.go index 39cf18586f10..23a23527921d 100644 --- a/simapp/export.go +++ b/simapp/export.go @@ -27,7 +27,7 @@ func (app *SimApp) ExportAppStateAndValidators( app.prepForZeroHeightGenesis(ctx, jailWhiteList) } - genState := app.mm.ExportGenesis(ctx) + genState := app.mm.ExportGenesis(ctx, app.cdc) appState, err = codec.MarshalJSONIndent(app.cdc, genState) if err != nil { return nil, nil, err diff --git a/simapp/genesis.go b/simapp/genesis.go index d96c6feec954..1a760e3e49a6 100644 --- a/simapp/genesis.go +++ b/simapp/genesis.go @@ -2,6 +2,8 @@ package simapp import ( "encoding/json" + + simappcodec "github.com/cosmos/cosmos-sdk/simapp/codec" ) // The genesis state of the blockchain is represented here as a map of raw json @@ -15,5 +17,7 @@ type GenesisState map[string]json.RawMessage // NewDefaultGenesisState generates the default state for the application. func NewDefaultGenesisState() GenesisState { - return ModuleBasics.DefaultGenesis() + cdc := simappcodec.MakeCodec(ModuleBasics) + + return ModuleBasics.DefaultGenesis(cdc) } diff --git a/simapp/sim_test.go b/simapp/sim_test.go index 3d41fa3b8467..e10afad8a4a1 100644 --- a/simapp/sim_test.go +++ b/simapp/sim_test.go @@ -137,7 +137,7 @@ func TestAppImportExport(t *testing.T) { ctxA := app.NewContext(true, abci.Header{Height: app.LastBlockHeight()}) ctxB := newApp.NewContext(true, abci.Header{Height: app.LastBlockHeight()}) - newApp.mm.InitGenesis(ctxB, genesisState) + newApp.mm.InitGenesis(ctxB, app.Codec(), genesisState) fmt.Printf("comparing stores...\n") diff --git a/simapp/utils_test.go b/simapp/utils_test.go index 9cadfff0da40..b6d5fa1f358a 100644 --- a/simapp/utils_test.go +++ b/simapp/utils_test.go @@ -8,12 +8,13 @@ import ( tmkv "github.com/tendermint/tendermint/libs/kv" "github.com/cosmos/cosmos-sdk/codec" + simappcodec "github.com/cosmos/cosmos-sdk/simapp/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" ) func TestGetSimulationLog(t *testing.T) { - cdc := MakeCodec() + cdc := simappcodec.MakeCodec(ModuleBasics) decoders := make(sdk.StoreDecoderRegistry) decoders[auth.StoreKey] = func(cdc *codec.Codec, kvAs, kvBs tmkv.Pair) string { return "10" } diff --git a/types/module/module.go b/types/module/module.go index 924c99834250..0b1633e3cd24 100644 --- a/types/module/module.go +++ b/types/module/module.go @@ -48,9 +48,8 @@ type AppModuleBasic interface { Name() string RegisterCodec(*codec.Codec) - // genesis - DefaultGenesis() json.RawMessage - ValidateGenesis(json.RawMessage) error + DefaultGenesis(codec.JSONMarshaler) json.RawMessage + ValidateGenesis(codec.JSONMarshaler, json.RawMessage) error // client functionality RegisterRESTRoutes(context.CLIContext, *mux.Router) @@ -78,21 +77,23 @@ func (bm BasicManager) RegisterCodec(cdc *codec.Codec) { } // DefaultGenesis provides default genesis information for all modules -func (bm BasicManager) DefaultGenesis() map[string]json.RawMessage { +func (bm BasicManager) DefaultGenesis(cdc codec.JSONMarshaler) map[string]json.RawMessage { genesis := make(map[string]json.RawMessage) for _, b := range bm { - genesis[b.Name()] = b.DefaultGenesis() + genesis[b.Name()] = b.DefaultGenesis(cdc) } + return genesis } // ValidateGenesis performs genesis state validation for all modules -func (bm BasicManager) ValidateGenesis(genesis map[string]json.RawMessage) error { +func (bm BasicManager) ValidateGenesis(cdc codec.JSONMarshaler, genesis map[string]json.RawMessage) error { for _, b := range bm { - if err := b.ValidateGenesis(genesis[b.Name()]); err != nil { + if err := b.ValidateGenesis(cdc, genesis[b.Name()]); err != nil { return err } } + return nil } @@ -126,8 +127,9 @@ func (bm BasicManager) AddQueryCommands(rootQueryCmd *cobra.Command, cdc *codec. // AppModuleGenesis is the standard form for an application module genesis functions type AppModuleGenesis interface { AppModuleBasic - InitGenesis(sdk.Context, json.RawMessage) []abci.ValidatorUpdate - ExportGenesis(sdk.Context) json.RawMessage + + InitGenesis(sdk.Context, codec.JSONMarshaler, json.RawMessage) []abci.ValidatorUpdate + ExportGenesis(sdk.Context, codec.JSONMarshaler) json.RawMessage } // AppModule is the standard form for an application module @@ -256,13 +258,14 @@ func (m *Manager) RegisterRoutes(router sdk.Router, queryRouter sdk.QueryRouter) } // InitGenesis performs init genesis functionality for modules -func (m *Manager) InitGenesis(ctx sdk.Context, genesisData map[string]json.RawMessage) abci.ResponseInitChain { +func (m *Manager) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, genesisData map[string]json.RawMessage) abci.ResponseInitChain { var validatorUpdates []abci.ValidatorUpdate for _, moduleName := range m.OrderInitGenesis { if genesisData[moduleName] == nil { continue } - moduleValUpdates := m.Modules[moduleName].InitGenesis(ctx, genesisData[moduleName]) + + moduleValUpdates := m.Modules[moduleName].InitGenesis(ctx, cdc, genesisData[moduleName]) // use these validator updates if provided, the module manager assumes // only one module will update the validator set @@ -273,17 +276,19 @@ func (m *Manager) InitGenesis(ctx sdk.Context, genesisData map[string]json.RawMe validatorUpdates = moduleValUpdates } } + return abci.ResponseInitChain{ Validators: validatorUpdates, } } // ExportGenesis performs export genesis functionality for modules -func (m *Manager) ExportGenesis(ctx sdk.Context) map[string]json.RawMessage { +func (m *Manager) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) map[string]json.RawMessage { genesisData := make(map[string]json.RawMessage) for _, moduleName := range m.OrderExportGenesis { - genesisData[moduleName] = m.Modules[moduleName].ExportGenesis(ctx) + genesisData[moduleName] = m.Modules[moduleName].ExportGenesis(ctx, cdc) } + return genesisData } diff --git a/x/auth/alias.go b/x/auth/alias.go index 01b20a68f3d7..b5d5516352e6 100644 --- a/x/auth/alias.go +++ b/x/auth/alias.go @@ -1,9 +1,3 @@ -// nolint -// autogenerated code using github.com/rigelrozanski/multitool -// aliases generated for the following subdirectories: -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/auth/ante -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/auth/keeper -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/auth/types package auth import ( @@ -12,6 +6,9 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth/types" ) +// DONTCOVER +// nolint + const ( ModuleName = types.ModuleName StoreKey = types.StoreKey @@ -40,7 +37,6 @@ var ( NewBaseAccountWithAddress = types.NewBaseAccountWithAddress NewAccountRetriever = types.NewAccountRetriever RegisterCodec = types.RegisterCodec - RegisterAccountTypeCodec = types.RegisterAccountTypeCodec NewGenesisState = types.NewGenesisState DefaultGenesisState = types.DefaultGenesisState ValidateGenesis = types.ValidateGenesis @@ -89,4 +85,5 @@ type ( StdSignature = types.StdSignature TxBuilder = types.TxBuilder GenesisAccountIterator = types.GenesisAccountIterator + Codec = types.Codec ) diff --git a/x/auth/ante/basic.go b/x/auth/ante/basic.go index 0e999a9d4781..05e570ca2854 100644 --- a/x/auth/ante/basic.go +++ b/x/auth/ante/basic.go @@ -1,6 +1,7 @@ package ante import ( + "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" err "github.com/cosmos/cosmos-sdk/types/errors" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" @@ -112,21 +113,24 @@ func (cgts ConsumeTxSizeGasDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, sim if sigs[i] != nil { continue } - acc := cgts.ak.GetAccount(ctx, signer) var pubkey crypto.PubKey + acc := cgts.ak.GetAccount(ctx, signer) + // use placeholder simSecp256k1Pubkey if sig is nil if acc == nil || acc.GetPubKey() == nil { pubkey = simSecp256k1Pubkey } else { pubkey = acc.GetPubKey() } + // use stdsignature to mock the size of a full signature simSig := types.StdSignature{ Signature: simSecp256k1Sig[:], PubKey: pubkey, } - sigBz := types.ModuleCdc.MustMarshalBinaryLengthPrefixed(simSig) + + sigBz := codec.Cdc.MustMarshalBinaryLengthPrefixed(simSig) cost := sdk.Gas(len(sigBz) + 6) // If the pubkey is a multi-signature pubkey, then we estimate for the maximum diff --git a/x/auth/ante/sigverify.go b/x/auth/ante/sigverify.go index 4498b432d73d..895be5373c61 100644 --- a/x/auth/ante/sigverify.go +++ b/x/auth/ante/sigverify.go @@ -299,6 +299,7 @@ func (vscd ValidateSigCountDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, sim func DefaultSigVerificationGasConsumer( meter sdk.GasMeter, sig []byte, pubkey crypto.PubKey, params types.Params, ) error { + switch pubkey := pubkey.(type) { case ed25519.PubKeyEd25519: meter.ConsumeGas(params.SigVerifyCostED25519, "ante verify: ed25519") @@ -321,11 +322,13 @@ func DefaultSigVerificationGasConsumer( } // ConsumeMultisignatureVerificationGas consumes gas from a GasMeter for verifying a multisig pubkey signature -func ConsumeMultisignatureVerificationGas(meter sdk.GasMeter, - sig multisig.Multisignature, pubkey multisig.PubKeyMultisigThreshold, - params types.Params) { +func ConsumeMultisignatureVerificationGas( + meter sdk.GasMeter, sig multisig.Multisignature, pubkey multisig.PubKeyMultisigThreshold, params types.Params, +) { + size := sig.BitArray.Size() sigIndex := 0 + for i := 0; i < size; i++ { if sig.BitArray.GetIndex(i) { DefaultSigVerificationGasConsumer(meter, sig.Sigs[sigIndex], pubkey.PubKeys[i], params) @@ -340,5 +343,6 @@ func GetSignerAcc(ctx sdk.Context, ak keeper.AccountKeeper, addr sdk.AccAddress) if acc := ak.GetAccount(ctx, addr); acc != nil { return acc, nil } + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "account %s does not exist", addr) } diff --git a/x/auth/client/cli/query.go b/x/auth/client/cli/query.go index af9f00b4ddc7..ebb5f3f508a8 100644 --- a/x/auth/client/cli/query.go +++ b/x/auth/client/cli/query.go @@ -50,7 +50,7 @@ func GetAccountCmd(cdc *codec.Codec) *cobra.Command { Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { cliCtx := context.NewCLIContext().WithCodec(cdc) - accGetter := types.NewAccountRetriever(cliCtx) + accGetter := types.NewAccountRetriever(authclient.Codec, cliCtx) key, err := sdk.AccAddressFromBech32(args[0]) if err != nil { diff --git a/x/auth/client/cli/tx_multisign.go b/x/auth/client/cli/tx_multisign.go index b46192925dbd..f1ea091d0b1e 100644 --- a/x/auth/client/cli/tx_multisign.go +++ b/x/auth/client/cli/tx_multisign.go @@ -86,7 +86,7 @@ func makeMultiSignCmd(cdc *codec.Codec) func(cmd *cobra.Command, args []string) txBldr := types.NewTxBuilderFromCLI(inBuf) if !viper.GetBool(flagOffline) { - accnum, seq, err := types.NewAccountRetriever(cliCtx).GetAccountNumberSequence(multisigInfo.GetAddress()) + accnum, seq, err := types.NewAccountRetriever(client.Codec, cliCtx).GetAccountNumberSequence(multisigInfo.GetAddress()) if err != nil { return err } diff --git a/x/auth/client/cli/tx_sign.go b/x/auth/client/cli/tx_sign.go index ebbe936a78b4..a6434be7ef92 100644 --- a/x/auth/client/cli/tx_sign.go +++ b/x/auth/client/cli/tx_sign.go @@ -224,7 +224,7 @@ func printAndValidateSigs( // Validate the actual signature over the transaction bytes since we can // reach out to a full node to query accounts. if !offline && success { - acc, err := types.NewAccountRetriever(cliCtx).GetAccount(sigAddr) + acc, err := types.NewAccountRetriever(client.Codec, cliCtx).GetAccount(sigAddr) if err != nil { fmt.Printf("failed to get account: %s\n", sigAddr) return false diff --git a/x/auth/client/rest/query.go b/x/auth/client/rest/query.go index 44f1bbb5b0ef..6f245e40a2cf 100644 --- a/x/auth/client/rest/query.go +++ b/x/auth/client/rest/query.go @@ -33,7 +33,7 @@ func QueryAccountRequestHandlerFn(storeName string, cliCtx context.CLIContext) h return } - accGetter := types.NewAccountRetriever(cliCtx) + accGetter := types.NewAccountRetriever(client.Codec, cliCtx) account, height, err := accGetter.GetAccountWithHeight(addr) if err != nil { diff --git a/x/auth/client/tx.go b/x/auth/client/tx.go index 12d50a65ab03..3c35aebe61c0 100644 --- a/x/auth/client/tx.go +++ b/x/auth/client/tx.go @@ -19,6 +19,15 @@ import ( authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" ) +// Codec defines the x/auth account codec to be used for use with the +// AccountRetriever. The application must be sure to set this to their respective +// codec that implements the Codec interface and must be the same codec that +// passed to the x/auth module. +// +// TODO:/XXX: Using a package-level global isn't ideal and we should consider +// refactoring the module manager to allow passing in the correct module codec. +var Codec authtypes.Codec + // GasEstimateResponse defines a response definition for tx gas estimation. type GasEstimateResponse struct { GasEstimate uint64 `json:"gas_estimate" yaml:"gas_estimate"` @@ -198,9 +207,10 @@ func SignStdTx( // SignStdTxWithSignerAddress attaches a signature to a StdTx and returns a copy of a it. // Don't perform online validation or lookups if offline is true, else // populate account and sequence numbers from a foreign account. -func SignStdTxWithSignerAddress(txBldr authtypes.TxBuilder, cliCtx context.CLIContext, - addr sdk.AccAddress, name string, stdTx authtypes.StdTx, - offline bool) (signedStdTx authtypes.StdTx, err error) { +func SignStdTxWithSignerAddress( + txBldr authtypes.TxBuilder, cliCtx context.CLIContext, + addr sdk.AccAddress, name string, stdTx authtypes.StdTx, offline bool, +) (signedStdTx authtypes.StdTx, err error) { // check whether the address is a signer if !isTxSigner(addr, stdTx.GetSigners()) { @@ -242,7 +252,7 @@ func populateAccountFromState( txBldr authtypes.TxBuilder, cliCtx context.CLIContext, addr sdk.AccAddress, ) (authtypes.TxBuilder, error) { - num, seq, err := authtypes.NewAccountRetriever(cliCtx).GetAccountNumberSequence(addr) + num, seq, err := authtypes.NewAccountRetriever(Codec, cliCtx).GetAccountNumberSequence(addr) if err != nil { return txBldr, err } @@ -290,7 +300,7 @@ func parseQueryResponse(cdc *codec.Codec, rawRes []byte) (uint64, error) { func PrepareTxBuilder(txBldr authtypes.TxBuilder, cliCtx context.CLIContext) (authtypes.TxBuilder, error) { from := cliCtx.GetFromAddress() - accGetter := authtypes.NewAccountRetriever(cliCtx) + accGetter := authtypes.NewAccountRetriever(Codec, cliCtx) if err := accGetter.EnsureExists(from); err != nil { return txBldr, err } @@ -299,7 +309,7 @@ func PrepareTxBuilder(txBldr authtypes.TxBuilder, cliCtx context.CLIContext) (au // TODO: (ref #1903) Allow for user supplied account number without // automatically doing a manual lookup. if txbldrAccNum == 0 || txbldrAccSeq == 0 { - num, seq, err := authtypes.NewAccountRetriever(cliCtx).GetAccountNumberSequence(from) + num, seq, err := authtypes.NewAccountRetriever(Codec, cliCtx).GetAccountNumberSequence(from) if err != nil { return txBldr, err } diff --git a/x/auth/keeper/account.go b/x/auth/keeper/account.go index 8417a4a34d2b..f2e9292b47c1 100644 --- a/x/auth/keeper/account.go +++ b/x/auth/keeper/account.go @@ -13,6 +13,7 @@ func (ak AccountKeeper) NewAccountWithAddress(ctx sdk.Context, addr sdk.AccAddre if err != nil { panic(err) } + return ak.NewAccount(ctx, acc) } @@ -21,6 +22,7 @@ func (ak AccountKeeper) NewAccount(ctx sdk.Context, acc exported.Account) export if err := acc.SetAccountNumber(ak.GetNextAccountNumber(ctx)); err != nil { panic(err) } + return acc } @@ -31,17 +33,17 @@ func (ak AccountKeeper) GetAccount(ctx sdk.Context, addr sdk.AccAddress) exporte if bz == nil { return nil } - acc := ak.decodeAccount(bz) - return acc + + return ak.decodeAccount(bz) } // GetAllAccounts returns all accounts in the accountKeeper. func (ak AccountKeeper) GetAllAccounts(ctx sdk.Context) (accounts []exported.Account) { - ak.IterateAccounts(ctx, - func(acc exported.Account) (stop bool) { - accounts = append(accounts, acc) - return false - }) + ak.IterateAccounts(ctx, func(acc exported.Account) (stop bool) { + accounts = append(accounts, acc) + return false + }) + return accounts } @@ -49,10 +51,12 @@ func (ak AccountKeeper) GetAllAccounts(ctx sdk.Context) (accounts []exported.Acc func (ak AccountKeeper) SetAccount(ctx sdk.Context, acc exported.Account) { addr := acc.GetAddress() store := ctx.KVStore(ak.key) - bz, err := ak.cdc.MarshalBinaryBare(acc) + + bz, err := ak.cdc.MarshalAccount(acc) if err != nil { panic(err) } + store.Set(types.AddressStoreKey(addr), bz) } diff --git a/x/auth/keeper/keeper.go b/x/auth/keeper/keeper.go index 244dec7c193b..18ecc0471119 100644 --- a/x/auth/keeper/keeper.go +++ b/x/auth/keeper/keeper.go @@ -3,10 +3,10 @@ package keeper import ( "fmt" + gogotypes "github.com/gogo/protobuf/types" "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/libs/log" - "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/auth/exported" @@ -17,23 +17,18 @@ import ( // AccountKeeper encodes/decodes accounts using the go-amino (binary) // encoding/decoding library. type AccountKeeper struct { - // The (unexposed) key used to access the store from the Context. - key sdk.StoreKey + key sdk.StoreKey + cdc types.Codec + paramSubspace subspace.Subspace // The prototypical Account constructor. proto func() exported.Account - - // The codec codec for binary encoding/decoding of accounts. - cdc *codec.Codec - - paramSubspace subspace.Subspace } // NewAccountKeeper returns a new sdk.AccountKeeper that uses go-amino to // (binary) encode and decode concrete sdk.Accounts. -// nolint func NewAccountKeeper( - cdc *codec.Codec, key sdk.StoreKey, paramstore subspace.Subspace, proto func() exported.Account, + cdc types.Codec, key sdk.StoreKey, paramstore subspace.Subspace, proto func() exported.Account, ) AccountKeeper { return AccountKeeper{ @@ -55,6 +50,7 @@ func (ak AccountKeeper) GetPubKey(ctx sdk.Context, addr sdk.AccAddress) (crypto. if acc == nil { return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "account %s does not exist", addr) } + return acc.GetPubKey(), nil } @@ -64,6 +60,7 @@ func (ak AccountKeeper) GetSequence(ctx sdk.Context, addr sdk.AccAddress) (uint6 if acc == nil { return 0, sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "account %s does not exist", addr) } + return acc.GetSequence(), nil } @@ -72,30 +69,33 @@ func (ak AccountKeeper) GetSequence(ctx sdk.Context, addr sdk.AccAddress) (uint6 func (ak AccountKeeper) GetNextAccountNumber(ctx sdk.Context) uint64 { var accNumber uint64 store := ctx.KVStore(ak.key) + bz := store.Get(types.GlobalAccountNumberKey) if bz == nil { // initialize the account numbers accNumber = 0 } else { - err := ak.cdc.UnmarshalBinaryLengthPrefixed(bz, &accNumber) + val := gogotypes.UInt64Value{} + + err := ak.cdc.UnmarshalBinaryLengthPrefixed(bz, &val) if err != nil { panic(err) } + + accNumber = val.GetValue() } - bz = ak.cdc.MustMarshalBinaryLengthPrefixed(accNumber + 1) + bz = ak.cdc.MustMarshalBinaryLengthPrefixed(&gogotypes.UInt64Value{Value: accNumber + 1}) store.Set(types.GlobalAccountNumberKey, bz) return accNumber } -// ----------------------------------------------------------------------------- -// Misc. - -func (ak AccountKeeper) decodeAccount(bz []byte) (acc exported.Account) { - err := ak.cdc.UnmarshalBinaryBare(bz, &acc) +func (ak AccountKeeper) decodeAccount(bz []byte) exported.Account { + acc, err := ak.cdc.UnmarshalAccount(bz) if err != nil { panic(err) } - return + + return acc } diff --git a/x/auth/module.go b/x/auth/module.go index d3cf501e4f04..c5adc5811328 100644 --- a/x/auth/module.go +++ b/x/auth/module.go @@ -41,14 +41,14 @@ func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) { // DefaultGenesis returns default genesis state as raw bytes for the auth // module. -func (AppModuleBasic) DefaultGenesis() json.RawMessage { - return types.ModuleCdc.MustMarshalJSON(types.DefaultGenesisState()) +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { + return cdc.MustMarshalJSON(types.DefaultGenesisState()) } // ValidateGenesis performs genesis state validation for the auth module. -func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, bz json.RawMessage) error { var data types.GenesisState - if err := types.ModuleCdc.UnmarshalJSON(bz, &data); err != nil { + if err := cdc.UnmarshalJSON(bz, &data); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) } @@ -113,18 +113,18 @@ func (am AppModule) NewQuerierHandler() sdk.Querier { // InitGenesis performs genesis initialization for the auth module. It returns // no validator updates. -func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate { +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data json.RawMessage) []abci.ValidatorUpdate { var genesisState GenesisState - types.ModuleCdc.MustUnmarshalJSON(data, &genesisState) + cdc.MustUnmarshalJSON(data, &genesisState) InitGenesis(ctx, am.accountKeeper, genesisState) return []abci.ValidatorUpdate{} } // ExportGenesis returns the exported genesis state as raw bytes for the auth // module. -func (am AppModule) ExportGenesis(ctx sdk.Context) json.RawMessage { +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json.RawMessage { gs := ExportGenesis(ctx, am.accountKeeper) - return types.ModuleCdc.MustMarshalJSON(gs) + return cdc.MustMarshalJSON(gs) } // BeginBlock returns the begin blocker for the auth module. diff --git a/x/auth/simulation/decoder.go b/x/auth/simulation/decoder.go index 725d82fc0a64..d157aab94349 100644 --- a/x/auth/simulation/decoder.go +++ b/x/auth/simulation/decoder.go @@ -19,11 +19,13 @@ func DecodeStore(cdc *codec.Codec, kvA, kvB tmkv.Pair) string { cdc.MustUnmarshalBinaryBare(kvA.Value, &accA) cdc.MustUnmarshalBinaryBare(kvB.Value, &accB) return fmt.Sprintf("%v\n%v", accA, accB) + case bytes.Equal(kvA.Key, types.GlobalAccountNumberKey): var globalAccNumberA, globalAccNumberB uint64 cdc.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &globalAccNumberA) cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &globalAccNumberB) return fmt.Sprintf("GlobalAccNumberA: %d\nGlobalAccNumberB: %d", globalAccNumberA, globalAccNumberB) + default: panic(fmt.Sprintf("invalid account key %X", kvA.Key)) } diff --git a/x/auth/simulation/genesis.go b/x/auth/simulation/genesis.go index 94fd8ec5ff3d..f809042d1426 100644 --- a/x/auth/simulation/genesis.go +++ b/x/auth/simulation/genesis.go @@ -98,7 +98,7 @@ func RandomizedGenState(simState *module.SimulationState) { func RandomGenesisAccounts(simState *module.SimulationState) (genesisAccs exported.GenesisAccounts) { for i, acc := range simState.Accounts { bacc := types.NewBaseAccountWithAddress(acc.Address) - var gacc exported.GenesisAccount = &bacc + var gacc exported.GenesisAccount = bacc // Only consider making a vesting account once the initial bonded validator // set is exhausted due to needing to track DelegatedVesting. @@ -115,7 +115,7 @@ func RandomGenesisAccounts(simState *module.SimulationState) (genesisAccs export endTime = int64(simulation.RandIntBetween(simState.Rand, int(startTime)+1, int(startTime+(60*60*12)))) } - bva := vestingtypes.NewBaseVestingAccount(&bacc, initialVesting, endTime) + bva := vestingtypes.NewBaseVestingAccount(bacc, initialVesting, endTime) if simState.Rand.Intn(100) < 50 { gacc = vestingtypes.NewContinuousVestingAccountRaw(bva, startTime) diff --git a/x/auth/types/account.go b/x/auth/types/account.go index 643c33abd28a..1c2460166e22 100644 --- a/x/auth/types/account.go +++ b/x/auth/types/account.go @@ -2,7 +2,6 @@ package types import ( "bytes" - "encoding/json" "errors" "github.com/tendermint/tendermint/crypto" @@ -12,28 +11,19 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth/exported" ) -//----------------------------------------------------------------------------- -// BaseAccount - var _ exported.Account = (*BaseAccount)(nil) var _ exported.GenesisAccount = (*BaseAccount)(nil) -// BaseAccount - a base account structure. -// This can be extended by embedding within in your AppAccount. -// However one doesn't have to use BaseAccount as long as your struct -// implements Account. -type BaseAccount struct { - Address sdk.AccAddress `json:"address" yaml:"address"` - PubKey crypto.PubKey `json:"public_key" yaml:"public_key"` - AccountNumber uint64 `json:"account_number" yaml:"account_number"` - Sequence uint64 `json:"sequence" yaml:"sequence"` -} - // NewBaseAccount creates a new BaseAccount object func NewBaseAccount(address sdk.AccAddress, pubKey crypto.PubKey, accountNumber, sequence uint64) *BaseAccount { + var pkStr string + if pubKey != nil { + pkStr = sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pubKey) + } + return &BaseAccount{ Address: address, - PubKey: pubKey, + PubKey: pkStr, AccountNumber: accountNumber, Sequence: sequence, } @@ -45,8 +35,8 @@ func ProtoBaseAccount() exported.Account { } // NewBaseAccountWithAddress - returns a new base account with a given address -func NewBaseAccountWithAddress(addr sdk.AccAddress) BaseAccount { - return BaseAccount{ +func NewBaseAccountWithAddress(addr sdk.AccAddress) *BaseAccount { + return &BaseAccount{ Address: addr, } } @@ -61,23 +51,33 @@ func (acc *BaseAccount) SetAddress(addr sdk.AccAddress) error { if len(acc.Address) != 0 { return errors.New("cannot override BaseAccount address") } + acc.Address = addr return nil } // GetPubKey - Implements sdk.Account. func (acc BaseAccount) GetPubKey() crypto.PubKey { - return acc.PubKey + if acc.PubKey == "" { + return nil + } + + return sdk.MustGetPubKeyFromBech32(sdk.Bech32PubKeyTypeAccPub, acc.PubKey) } // SetPubKey - Implements sdk.Account. func (acc *BaseAccount) SetPubKey(pubKey crypto.PubKey) error { - acc.PubKey = pubKey + pkStr, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pubKey) + if err != nil { + return err + } + + acc.PubKey = pkStr return nil } // GetAccountNumber - Implements Account -func (acc *BaseAccount) GetAccountNumber() uint64 { +func (acc BaseAccount) GetAccountNumber() uint64 { return acc.AccountNumber } @@ -88,7 +88,7 @@ func (acc *BaseAccount) SetAccountNumber(accNumber uint64) error { } // GetSequence - Implements sdk.Account. -func (acc *BaseAccount) GetSequence() uint64 { +func (acc BaseAccount) GetSequence() uint64 { return acc.Sequence } @@ -100,90 +100,15 @@ func (acc *BaseAccount) SetSequence(seq uint64) error { // Validate checks for errors on the account fields func (acc BaseAccount) Validate() error { - if acc.PubKey != nil && acc.Address != nil && - !bytes.Equal(acc.PubKey.Address().Bytes(), acc.Address.Bytes()) { + if acc.PubKey != "" && acc.Address != nil && + !bytes.Equal(acc.GetPubKey().Address().Bytes(), acc.Address.Bytes()) { return errors.New("pubkey and address pair is invalid") } return nil } -type baseAccountPretty struct { - Address sdk.AccAddress `json:"address" yaml:"address"` - PubKey string `json:"public_key" yaml:"public_key"` - AccountNumber uint64 `json:"account_number" yaml:"account_number"` - Sequence uint64 `json:"sequence" yaml:"sequence"` -} - func (acc BaseAccount) String() string { - out, _ := acc.MarshalYAML() - return out.(string) -} - -// MarshalYAML returns the YAML representation of an account. -func (acc BaseAccount) MarshalYAML() (interface{}, error) { - alias := baseAccountPretty{ - Address: acc.Address, - AccountNumber: acc.AccountNumber, - Sequence: acc.Sequence, - } - - if acc.PubKey != nil { - pks, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, acc.PubKey) - if err != nil { - return nil, err - } - - alias.PubKey = pks - } - - bz, err := yaml.Marshal(alias) - if err != nil { - return nil, err - } - - return string(bz), err -} - -// MarshalJSON returns the JSON representation of a BaseAccount. -func (acc BaseAccount) MarshalJSON() ([]byte, error) { - alias := baseAccountPretty{ - Address: acc.Address, - AccountNumber: acc.AccountNumber, - Sequence: acc.Sequence, - } - - if acc.PubKey != nil { - pks, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, acc.PubKey) - if err != nil { - return nil, err - } - - alias.PubKey = pks - } - - return json.Marshal(alias) -} - -// UnmarshalJSON unmarshals raw JSON bytes into a BaseAccount. -func (acc *BaseAccount) UnmarshalJSON(bz []byte) error { - var alias baseAccountPretty - if err := json.Unmarshal(bz, &alias); err != nil { - return err - } - - if alias.PubKey != "" { - pk, err := sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeAccPub, alias.PubKey) - if err != nil { - return err - } - - acc.PubKey = pk - } - - acc.Address = alias.Address - acc.AccountNumber = alias.AccountNumber - acc.Sequence = alias.Sequence - - return nil + out, _ := yaml.Marshal(acc) + return string(out) } diff --git a/x/auth/types/account_retriever.go b/x/auth/types/account_retriever.go index ab87e3259b95..65aa4297ed19 100644 --- a/x/auth/types/account_retriever.go +++ b/x/auth/types/account_retriever.go @@ -18,12 +18,13 @@ type NodeQuerier interface { // AccountRetriever defines the properties of a type that can be used to // retrieve accounts. type AccountRetriever struct { + codec Codec querier NodeQuerier } // NewAccountRetriever initialises a new AccountRetriever instance. -func NewAccountRetriever(querier NodeQuerier) AccountRetriever { - return AccountRetriever{querier: querier} +func NewAccountRetriever(codec Codec, querier NodeQuerier) AccountRetriever { + return AccountRetriever{codec: codec, querier: querier} } // GetAccount queries for an account given an address and a block height. An @@ -37,22 +38,22 @@ func (ar AccountRetriever) GetAccount(addr sdk.AccAddress) (exported.Account, er // height of the query with the account. An error is returned if the query // or decoding fails. func (ar AccountRetriever) GetAccountWithHeight(addr sdk.AccAddress) (exported.Account, int64, error) { - bs, err := ModuleCdc.MarshalJSON(NewQueryAccountParams(addr)) + bs, err := ar.codec.MarshalJSON(NewQueryAccountParams(addr)) if err != nil { return nil, 0, err } - res, height, err := ar.querier.QueryWithData(fmt.Sprintf("custom/%s/%s", QuerierRoute, QueryAccount), bs) + bz, height, err := ar.querier.QueryWithData(fmt.Sprintf("custom/%s/%s", QuerierRoute, QueryAccount), bs) if err != nil { return nil, height, err } - var account exported.Account - if err := ModuleCdc.UnmarshalJSON(res, &account); err != nil { + acc, err := ar.codec.UnmarshalAccountJSON(bz) + if err != nil { return nil, height, err } - return account, height, nil + return acc, height, nil } // EnsureExists returns an error if no account exists for the given address else nil. diff --git a/x/auth/types/account_retriever_test.go b/x/auth/types/account_retriever_test.go index 76126db115d3..0481e00b263b 100644 --- a/x/auth/types/account_retriever_test.go +++ b/x/auth/types/account_retriever_test.go @@ -1,4 +1,4 @@ -package types +package types_test import ( "errors" @@ -8,6 +8,7 @@ import ( "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/tests/mocks" + "github.com/cosmos/cosmos-sdk/x/auth/types" ) var errFoo = errors.New("dummy") @@ -17,9 +18,9 @@ func TestAccountRetriever(t *testing.T) { defer mockCtrl.Finish() mockNodeQuerier := mocks.NewMockNodeQuerier(mockCtrl) - accRetr := NewAccountRetriever(mockNodeQuerier) + accRetr := types.NewAccountRetriever(appCodec, mockNodeQuerier) addr := []byte("test") - bs, err := ModuleCdc.MarshalJSON(NewQueryAccountParams(addr)) + bs, err := appCodec.MarshalJSON(types.NewQueryAccountParams(addr)) require.NoError(t, err) mockNodeQuerier.EXPECT().QueryWithData(gomock.Eq("custom/acc/account"), diff --git a/x/auth/types/account_test.go b/x/auth/types/account_test.go index 90a4dacb0c9f..e86f4b5940b1 100644 --- a/x/auth/types/account_test.go +++ b/x/auth/types/account_test.go @@ -1,22 +1,21 @@ -package types +package types_test import ( - "encoding/json" "errors" "testing" "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/crypto/secp256k1" - "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth/exported" + "github.com/cosmos/cosmos-sdk/x/auth/types" ) func TestBaseAddressPubKey(t *testing.T) { - _, pub1, addr1 := KeyTestPubAddr() - _, pub2, addr2 := KeyTestPubAddr() - acc := NewBaseAccountWithAddress(addr1) + _, pub1, addr1 := types.KeyTestPubAddr() + _, pub2, addr2 := types.KeyTestPubAddr() + acc := types.NewBaseAccountWithAddress(addr1) // check the address (set) and pubkey (not set) require.EqualValues(t, addr1, acc.GetAddress()) @@ -40,16 +39,15 @@ func TestBaseAddressPubKey(t *testing.T) { //------------------------------------ // can set address on empty account - acc2 := BaseAccount{} + acc2 := types.BaseAccount{} err = acc2.SetAddress(addr2) require.Nil(t, err) require.EqualValues(t, addr2, acc2.GetAddress()) } func TestBaseAccountSequence(t *testing.T) { - _, _, addr := KeyTestPubAddr() - acc := NewBaseAccountWithAddress(addr) - + _, _, addr := types.KeyTestPubAddr() + acc := types.NewBaseAccountWithAddress(addr) seq := uint64(7) err := acc.SetSequence(seq) @@ -58,9 +56,8 @@ func TestBaseAccountSequence(t *testing.T) { } func TestBaseAccountMarshal(t *testing.T) { - _, pub, addr := KeyTestPubAddr() - acc := NewBaseAccountWithAddress(addr) - + _, pub, addr := types.KeyTestPubAddr() + acc := types.NewBaseAccountWithAddress(addr) seq := uint64(7) // set everything on the account @@ -69,28 +66,23 @@ func TestBaseAccountMarshal(t *testing.T) { err = acc.SetSequence(seq) require.Nil(t, err) - // need a codec for marshaling - cdc := codec.New() - codec.RegisterCrypto(cdc) - - b, err := cdc.MarshalBinaryLengthPrefixed(acc) + bz, err := appCodec.MarshalAccount(acc) require.Nil(t, err) - acc2 := BaseAccount{} - err = cdc.UnmarshalBinaryLengthPrefixed(b, &acc2) + acc2, err := appCodec.UnmarshalAccount(bz) require.Nil(t, err) require.Equal(t, acc, acc2) // error on bad bytes - acc2 = BaseAccount{} - err = cdc.UnmarshalBinaryLengthPrefixed(b[:len(b)/2], &acc2) + _, err = appCodec.UnmarshalAccount(bz[:len(bz)/2]) require.NotNil(t, err) } func TestGenesisAccountValidate(t *testing.T) { pubkey := secp256k1.GenPrivKey().PubKey() addr := sdk.AccAddress(pubkey.Address()) - baseAcc := NewBaseAccount(addr, pubkey, 0, 0) + baseAcc := types.NewBaseAccount(addr, pubkey, 0, 0) + tests := []struct { name string acc exported.GenesisAccount @@ -103,39 +95,17 @@ func TestGenesisAccountValidate(t *testing.T) { }, { "invalid base valid account", - NewBaseAccount(addr, secp256k1.GenPrivKey().PubKey(), 0, 0), + types.NewBaseAccount(addr, secp256k1.GenPrivKey().PubKey(), 0, 0), errors.New("pubkey and address pair is invalid"), }, } + for _, tt := range tests { tt := tt + t.Run(tt.name, func(t *testing.T) { err := tt.acc.Validate() require.Equal(t, tt.expErr, err) }) } } - -func TestBaseAccountJSON(t *testing.T) { - pubkey := secp256k1.GenPrivKey().PubKey() - addr := sdk.AccAddress(pubkey.Address()) - baseAcc := NewBaseAccount(addr, pubkey, 10, 50) - - bz, err := json.Marshal(baseAcc) - require.NoError(t, err) - - bz1, err := baseAcc.MarshalJSON() - require.NoError(t, err) - require.Equal(t, string(bz1), string(bz)) - - var a BaseAccount - require.NoError(t, json.Unmarshal(bz, &a)) - require.Equal(t, baseAcc.String(), a.String()) - - bz, err = ModuleCdc.MarshalJSON(baseAcc) - require.NoError(t, err) - - var b BaseAccount - require.NoError(t, ModuleCdc.UnmarshalJSON(bz, &b)) - require.Equal(t, baseAcc.String(), b.String()) -} diff --git a/x/auth/types/codec.go b/x/auth/types/codec.go index c6be8883f7ad..be7f21b3f1d1 100644 --- a/x/auth/types/codec.go +++ b/x/auth/types/codec.go @@ -5,10 +5,20 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth/exported" ) -// ModuleCdc auth module wide codec -var ModuleCdc = codec.New() +// Codec defines the interface needed to serialize x/auth state. It must be +// aware of all concrete account types. +type Codec interface { + codec.Marshaler -// RegisterCodec registers concrete types on the codec + MarshalAccount(acc exported.Account) ([]byte, error) + UnmarshalAccount(bz []byte) (exported.Account, error) + + MarshalAccountJSON(acc exported.Account) ([]byte, error) + UnmarshalAccountJSON(bz []byte) (exported.Account, error) +} + +// RegisterCodec registers the account interfaces and concrete types on the +// provided Amino codec. func RegisterCodec(cdc *codec.Codec) { cdc.RegisterInterface((*exported.GenesisAccount)(nil), nil) cdc.RegisterInterface((*exported.Account)(nil), nil) @@ -16,13 +26,20 @@ func RegisterCodec(cdc *codec.Codec) { cdc.RegisterConcrete(StdTx{}, "cosmos-sdk/StdTx", nil) } -// RegisterAccountTypeCodec registers an external account type defined in -// another module for the internal ModuleCdc. -func RegisterAccountTypeCodec(o interface{}, name string) { - ModuleCdc.RegisterConcrete(o, name, nil) -} +var ( + amino = codec.New() + + // ModuleCdc references the global x/auth module codec. Note, the codec should + // ONLY be used in certain instances of tests and for JSON encoding as Amino is + // still used for that purpose. + // + // The actual codec used for serialization should be provided to x/auth and + // defined at the application level. + ModuleCdc = codec.NewHybridCodec(amino) +) func init() { - RegisterCodec(ModuleCdc) - codec.RegisterCrypto(ModuleCdc) + RegisterCodec(amino) + codec.RegisterCrypto(amino) + amino.Seal() } diff --git a/x/auth/types/common_test.go b/x/auth/types/common_test.go new file mode 100644 index 000000000000..02b80ac6aa6d --- /dev/null +++ b/x/auth/types/common_test.go @@ -0,0 +1,11 @@ +package types_test + +import ( + "github.com/cosmos/cosmos-sdk/simapp" + simappcodec "github.com/cosmos/cosmos-sdk/simapp/codec" +) + +var ( + app = simapp.Setup(false) + appCodec = simappcodec.NewAppCodec(app.Codec()) +) diff --git a/x/auth/types/genesis.go b/x/auth/types/genesis.go index 89999db447ca..1b83380e352e 100644 --- a/x/auth/types/genesis.go +++ b/x/auth/types/genesis.go @@ -5,7 +5,6 @@ import ( "fmt" "sort" - "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/x/auth/exported" ) @@ -30,7 +29,7 @@ func DefaultGenesisState() GenesisState { // GetGenesisStateFromAppState returns x/auth GenesisState given raw application // genesis state. -func GetGenesisStateFromAppState(cdc *codec.Codec, appState map[string]json.RawMessage) GenesisState { +func GetGenesisStateFromAppState(cdc Codec, appState map[string]json.RawMessage) GenesisState { var genesisState GenesisState if appState[ModuleName] != nil { cdc.MustUnmarshalJSON(appState[ModuleName], &genesisState) @@ -86,7 +85,7 @@ type GenesisAccountIterator struct{} // appGenesis and invokes a callback on each genesis account. If any call // returns true, iteration stops. func (GenesisAccountIterator) IterateGenesisAccounts( - cdc *codec.Codec, appGenesis map[string]json.RawMessage, cb func(exported.Account) (stop bool), + cdc Codec, appGenesis map[string]json.RawMessage, cb func(exported.Account) (stop bool), ) { for _, genAcc := range GetGenesisStateFromAppState(cdc, appGenesis).Accounts { diff --git a/x/auth/types/genesis_test.go b/x/auth/types/genesis_test.go index 3b892f48038d..c5e482cf0356 100644 --- a/x/auth/types/genesis_test.go +++ b/x/auth/types/genesis_test.go @@ -1,4 +1,4 @@ -package types +package types_test import ( "encoding/json" @@ -9,21 +9,22 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth/exported" + "github.com/cosmos/cosmos-sdk/x/auth/types" ) func TestSanitize(t *testing.T) { addr1 := sdk.AccAddress(ed25519.GenPrivKey().PubKey().Address()) - authAcc1 := NewBaseAccountWithAddress(addr1) + authAcc1 := types.NewBaseAccountWithAddress(addr1) authAcc1.SetAccountNumber(1) addr2 := sdk.AccAddress(ed25519.GenPrivKey().PubKey().Address()) - authAcc2 := NewBaseAccountWithAddress(addr2) + authAcc2 := types.NewBaseAccountWithAddress(addr2) - genAccs := exported.GenesisAccounts{&authAcc1, &authAcc2} + genAccs := exported.GenesisAccounts{authAcc1, authAcc2} require.True(t, genAccs[0].GetAccountNumber() > genAccs[1].GetAccountNumber()) require.Equal(t, genAccs[1].GetAddress(), addr2) - genAccs = SanitizeGenesisAccounts(genAccs) + genAccs = types.SanitizeGenesisAccounts(genAccs) require.False(t, genAccs[0].GetAccountNumber() > genAccs[1].GetAccountNumber()) require.Equal(t, genAccs[1].GetAddress(), addr1) @@ -38,34 +39,33 @@ var ( // require duplicate accounts fails validation func TestValidateGenesisDuplicateAccounts(t *testing.T) { - acc1 := NewBaseAccountWithAddress(sdk.AccAddress(addr1)) + acc1 := types.NewBaseAccountWithAddress(sdk.AccAddress(addr1)) genAccs := make(exported.GenesisAccounts, 2) - genAccs[0] = &acc1 - genAccs[1] = &acc1 + genAccs[0] = acc1 + genAccs[1] = acc1 - require.Error(t, ValidateGenAccounts(genAccs)) + require.Error(t, types.ValidateGenAccounts(genAccs)) } func TestGenesisAccountIterator(t *testing.T) { - acc1 := NewBaseAccountWithAddress(sdk.AccAddress(addr1)) + acc1 := types.NewBaseAccountWithAddress(sdk.AccAddress(addr1)) + acc2 := types.NewBaseAccountWithAddress(sdk.AccAddress(addr2)) - acc2 := NewBaseAccountWithAddress(sdk.AccAddress(addr2)) + genAccounts := exported.GenesisAccounts{acc1, acc2} - genAccounts := exported.GenesisAccounts{&acc1, &acc2} - - authGenState := DefaultGenesisState() + authGenState := types.DefaultGenesisState() authGenState.Accounts = genAccounts appGenesis := make(map[string]json.RawMessage) - authGenStateBz, err := ModuleCdc.MarshalJSON(authGenState) + authGenStateBz, err := appCodec.MarshalJSON(authGenState) require.NoError(t, err) - appGenesis[ModuleName] = authGenStateBz + appGenesis[types.ModuleName] = authGenStateBz var addresses []sdk.AccAddress - GenesisAccountIterator{}.IterateGenesisAccounts( - ModuleCdc, appGenesis, func(acc exported.Account) (stop bool) { + types.GenesisAccountIterator{}.IterateGenesisAccounts( + appCodec, appGenesis, func(acc exported.Account) (stop bool) { addresses = append(addresses, acc.GetAddress()) return false }, diff --git a/x/auth/types/params.go b/x/auth/types/params.go index 2f994ef7eecf..8ad49df1157b 100644 --- a/x/auth/types/params.go +++ b/x/auth/types/params.go @@ -1,12 +1,11 @@ package types import ( - "bytes" "fmt" - "strings" "github.com/cosmos/cosmos-sdk/x/params" "github.com/cosmos/cosmos-sdk/x/params/subspace" + yaml "gopkg.in/yaml.v2" ) // DefaultParamspace defines the default auth module parameter subspace @@ -32,18 +31,10 @@ var ( var _ subspace.ParamSet = &Params{} -// Params defines the parameters for the auth module. -type Params struct { - MaxMemoCharacters uint64 `json:"max_memo_characters" yaml:"max_memo_characters"` - TxSigLimit uint64 `json:"tx_sig_limit" yaml:"tx_sig_limit"` - TxSizeCostPerByte uint64 `json:"tx_size_cost_per_byte" yaml:"tx_size_cost_per_byte"` - SigVerifyCostED25519 uint64 `json:"sig_verify_cost_ed25519" yaml:"sig_verify_cost_ed25519"` - SigVerifyCostSecp256k1 uint64 `json:"sig_verify_cost_secp256k1" yaml:"sig_verify_cost_secp256k1"` -} - // NewParams creates a new Params object -func NewParams(maxMemoCharacters, txSigLimit, txSizeCostPerByte, - sigVerifyCostED25519, sigVerifyCostSecp256k1 uint64) Params { +func NewParams( + maxMemoCharacters, txSigLimit, txSizeCostPerByte, sigVerifyCostED25519, sigVerifyCostSecp256k1 uint64, +) Params { return Params{ MaxMemoCharacters: maxMemoCharacters, @@ -72,13 +63,6 @@ func (p *Params) ParamSetPairs() subspace.ParamSetPairs { } } -// Equal returns a boolean determining if two Params types are identical. -func (p Params) Equal(p2 Params) bool { - bz1 := ModuleCdc.MustMarshalBinaryLengthPrefixed(&p) - bz2 := ModuleCdc.MustMarshalBinaryLengthPrefixed(&p2) - return bytes.Equal(bz1, bz2) -} - // DefaultParams returns a default set of parameters. func DefaultParams() Params { return Params{ @@ -92,14 +76,8 @@ func DefaultParams() Params { // String implements the stringer interface. func (p Params) String() string { - var sb strings.Builder - sb.WriteString("Params: \n") - sb.WriteString(fmt.Sprintf("MaxMemoCharacters: %d\n", p.MaxMemoCharacters)) - sb.WriteString(fmt.Sprintf("TxSigLimit: %d\n", p.TxSigLimit)) - sb.WriteString(fmt.Sprintf("TxSizeCostPerByte: %d\n", p.TxSizeCostPerByte)) - sb.WriteString(fmt.Sprintf("SigVerifyCostED25519: %d\n", p.SigVerifyCostED25519)) - sb.WriteString(fmt.Sprintf("SigVerifyCostSecp256k1: %d\n", p.SigVerifyCostSecp256k1)) - return sb.String() + out, _ := yaml.Marshal(p) + return string(out) } func validateTxSigLimit(i interface{}) error { diff --git a/x/auth/types/stdtx.go b/x/auth/types/stdtx.go index a37408f9e9e6..a9a6cd3e9daf 100644 --- a/x/auth/types/stdtx.go +++ b/x/auth/types/stdtx.go @@ -163,16 +163,6 @@ func (tx StdTx) FeePayer() sdk.AccAddress { return sdk.AccAddress{} } -//__________________________________________________________ - -// StdFee includes the amount of coins paid in fees and the maximum -// gas to be used by the transaction. The ratio yields an effective "gasprice", -// which must be above some miminum to be accepted into the mempool. -type StdFee struct { - Amount sdk.Coins `json:"amount" yaml:"amount"` - Gas uint64 `json:"gas" yaml:"gas"` -} - // NewStdFee returns a new instance of StdFee func NewStdFee(gas uint64, amount sdk.Coins) StdFee { return StdFee{ @@ -190,10 +180,12 @@ func (fee StdFee) Bytes() []byte { if len(fee.Amount) == 0 { fee.Amount = sdk.NewCoins() } - bz, err := ModuleCdc.MarshalJSON(fee) // TODO + + bz, err := codec.Cdc.MarshalJSON(fee) // TODO if err != nil { panic(err) } + return bz } @@ -228,7 +220,8 @@ func StdSignBytes(chainID string, accnum uint64, sequence uint64, fee StdFee, ms for _, msg := range msgs { msgsBytes = append(msgsBytes, json.RawMessage(msg.GetSignBytes())) } - bz, err := ModuleCdc.MarshalJSON(StdSignDoc{ + + bz, err := codec.Cdc.MarshalJSON(StdSignDoc{ AccountNumber: accnum, ChainID: chainID, Fee: json.RawMessage(fee.Bytes()), @@ -236,9 +229,11 @@ func StdSignBytes(chainID string, accnum uint64, sequence uint64, fee StdFee, ms Msgs: msgsBytes, Sequence: sequence, }) + if err != nil { panic(err) } + return sdk.MustSortJSON(bz) } diff --git a/x/auth/types/test_common.go b/x/auth/types/test_utils.go similarity index 100% rename from x/auth/types/test_common.go rename to x/auth/types/test_utils.go diff --git a/x/auth/types/types.pb.go b/x/auth/types/types.pb.go new file mode 100644 index 000000000000..04705c07d3d3 --- /dev/null +++ b/x/auth/types/types.pb.go @@ -0,0 +1,1001 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: x/auth/types/types.proto + +package types + +import ( + fmt "fmt" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// BaseAccount defines a base account type. It contains all the necessary fields +// for basic account functionality. Any custom account type should extend this +// type for additional functionality (e.g. vesting). +type BaseAccount struct { + Address github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,1,opt,name=address,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"address,omitempty"` + PubKey string `protobuf:"bytes,2,opt,name=pub_key,json=pubKey,proto3" json:"pub_key,omitempty" yaml:"public_key"` + AccountNumber uint64 `protobuf:"varint,3,opt,name=account_number,json=accountNumber,proto3" json:"account_number,omitempty" yaml:"account_number"` + Sequence uint64 `protobuf:"varint,4,opt,name=sequence,proto3" json:"sequence,omitempty"` +} + +func (m *BaseAccount) Reset() { *m = BaseAccount{} } +func (*BaseAccount) ProtoMessage() {} +func (*BaseAccount) Descriptor() ([]byte, []int) { + return fileDescriptor_2d526fa662daab74, []int{0} +} +func (m *BaseAccount) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *BaseAccount) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_BaseAccount.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 *BaseAccount) XXX_Merge(src proto.Message) { + xxx_messageInfo_BaseAccount.Merge(m, src) +} +func (m *BaseAccount) XXX_Size() int { + return m.Size() +} +func (m *BaseAccount) XXX_DiscardUnknown() { + xxx_messageInfo_BaseAccount.DiscardUnknown(m) +} + +var xxx_messageInfo_BaseAccount proto.InternalMessageInfo + +// StdFee includes the amount of coins paid in fees and the maximum +// gas to be used by the transaction. The ratio yields an effective "gasprice", +// which must be above some miminum to be accepted into the mempool. +type StdFee struct { + Amount github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,1,rep,name=amount,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"amount"` + Gas uint64 `protobuf:"varint,2,opt,name=gas,proto3" json:"gas,omitempty"` +} + +func (m *StdFee) Reset() { *m = StdFee{} } +func (m *StdFee) String() string { return proto.CompactTextString(m) } +func (*StdFee) ProtoMessage() {} +func (*StdFee) Descriptor() ([]byte, []int) { + return fileDescriptor_2d526fa662daab74, []int{1} +} +func (m *StdFee) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StdFee) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_StdFee.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 *StdFee) XXX_Merge(src proto.Message) { + xxx_messageInfo_StdFee.Merge(m, src) +} +func (m *StdFee) XXX_Size() int { + return m.Size() +} +func (m *StdFee) XXX_DiscardUnknown() { + xxx_messageInfo_StdFee.DiscardUnknown(m) +} + +var xxx_messageInfo_StdFee proto.InternalMessageInfo + +func (m *StdFee) GetAmount() github_com_cosmos_cosmos_sdk_types.Coins { + if m != nil { + return m.Amount + } + return nil +} + +func (m *StdFee) GetGas() uint64 { + if m != nil { + return m.Gas + } + return 0 +} + +// Params defines the parameters for the auth module. +type Params struct { + MaxMemoCharacters uint64 `protobuf:"varint,1,opt,name=max_memo_characters,json=maxMemoCharacters,proto3" json:"max_memo_characters,omitempty" yaml:"max_memo_characters"` + TxSigLimit uint64 `protobuf:"varint,2,opt,name=tx_sig_limit,json=txSigLimit,proto3" json:"tx_sig_limit,omitempty" yaml:"tx_sig_limit"` + TxSizeCostPerByte uint64 `protobuf:"varint,3,opt,name=tx_size_cost_per_byte,json=txSizeCostPerByte,proto3" json:"tx_size_cost_per_byte,omitempty" yaml:"tx_size_cost_per_byte"` + SigVerifyCostED25519 uint64 `protobuf:"varint,4,opt,name=sig_verify_cost_ed25519,json=sigVerifyCostEd25519,proto3" json:"sig_verify_cost_ed25519,omitempty" yaml:"sig_verify_cost_ed25519"` + SigVerifyCostSecp256k1 uint64 `protobuf:"varint,5,opt,name=sig_verify_cost_secp256k1,json=sigVerifyCostSecp256k1,proto3" json:"sig_verify_cost_secp256k1,omitempty" yaml:"sig_verify_cost_secp256k1"` +} + +func (m *Params) Reset() { *m = Params{} } +func (*Params) ProtoMessage() {} +func (*Params) Descriptor() ([]byte, []int) { + return fileDescriptor_2d526fa662daab74, []int{2} +} +func (m *Params) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Params) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Params.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 *Params) XXX_Merge(src proto.Message) { + xxx_messageInfo_Params.Merge(m, src) +} +func (m *Params) XXX_Size() int { + return m.Size() +} +func (m *Params) XXX_DiscardUnknown() { + xxx_messageInfo_Params.DiscardUnknown(m) +} + +var xxx_messageInfo_Params proto.InternalMessageInfo + +func (m *Params) GetMaxMemoCharacters() uint64 { + if m != nil { + return m.MaxMemoCharacters + } + return 0 +} + +func (m *Params) GetTxSigLimit() uint64 { + if m != nil { + return m.TxSigLimit + } + return 0 +} + +func (m *Params) GetTxSizeCostPerByte() uint64 { + if m != nil { + return m.TxSizeCostPerByte + } + return 0 +} + +func (m *Params) GetSigVerifyCostED25519() uint64 { + if m != nil { + return m.SigVerifyCostED25519 + } + return 0 +} + +func (m *Params) GetSigVerifyCostSecp256k1() uint64 { + if m != nil { + return m.SigVerifyCostSecp256k1 + } + return 0 +} + +func init() { + proto.RegisterType((*BaseAccount)(nil), "cosmos_sdk.x.auth.v1.BaseAccount") + proto.RegisterType((*StdFee)(nil), "cosmos_sdk.x.auth.v1.StdFee") + proto.RegisterType((*Params)(nil), "cosmos_sdk.x.auth.v1.Params") +} + +func init() { proto.RegisterFile("x/auth/types/types.proto", fileDescriptor_2d526fa662daab74) } + +var fileDescriptor_2d526fa662daab74 = []byte{ + // 610 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x53, 0x3d, 0x6f, 0xd3, 0x4e, + 0x18, 0x8f, 0xff, 0xc9, 0x3f, 0x2d, 0xd7, 0x82, 0x88, 0xfb, 0xe6, 0x46, 0xc8, 0x17, 0x79, 0x40, + 0x61, 0xa8, 0x43, 0x8a, 0x8a, 0xd4, 0x0c, 0x88, 0x3a, 0xc0, 0x52, 0xa8, 0x2a, 0x47, 0x62, 0x40, + 0x42, 0xd6, 0xf9, 0x7c, 0x38, 0x56, 0x7a, 0x39, 0xd7, 0x77, 0xae, 0xec, 0x7e, 0x02, 0x46, 0x46, + 0xc6, 0xce, 0x7c, 0x92, 0x8e, 0x1d, 0x99, 0x5c, 0x94, 0x2e, 0xcc, 0x1e, 0x99, 0x90, 0x7d, 0x69, + 0x49, 0x4b, 0x41, 0x2c, 0xc9, 0x3d, 0xcf, 0xef, 0xed, 0xee, 0xf1, 0x1d, 0xd0, 0x92, 0x0e, 0x8a, + 0xc5, 0xb0, 0x23, 0xd2, 0x90, 0x70, 0xf9, 0x6b, 0x86, 0x11, 0x13, 0x4c, 0x5d, 0xc6, 0x8c, 0x53, + 0xc6, 0x1d, 0xee, 0x8d, 0xcc, 0xc4, 0x2c, 0x48, 0xe6, 0x51, 0xb7, 0xf9, 0x50, 0x0c, 0x83, 0xc8, + 0x73, 0x42, 0x14, 0x89, 0xb4, 0x53, 0x12, 0x3b, 0x3e, 0xf3, 0xd9, 0xaf, 0x95, 0x54, 0x37, 0x1b, + 0xbf, 0x19, 0x1a, 0xb9, 0x02, 0x16, 0x2c, 0xc4, 0xc9, 0x0e, 0xc6, 0x2c, 0x1e, 0x0b, 0x75, 0x17, + 0xcc, 0x21, 0xcf, 0x8b, 0x08, 0xe7, 0x9a, 0xd2, 0x52, 0xda, 0x8b, 0x56, 0xf7, 0x47, 0x06, 0x37, + 0xfc, 0x40, 0x0c, 0x63, 0xd7, 0xc4, 0x8c, 0x76, 0xe4, 0x06, 0xa6, 0x7f, 0x1b, 0xdc, 0x1b, 0x4d, + 0xed, 0x76, 0x30, 0xde, 0x91, 0x42, 0xfb, 0xd2, 0x41, 0x35, 0xc1, 0x5c, 0x18, 0xbb, 0xce, 0x88, + 0xa4, 0xda, 0x7f, 0x2d, 0xa5, 0x7d, 0xc7, 0x5a, 0xc9, 0x33, 0xd8, 0x48, 0x11, 0x3d, 0xe8, 0x19, + 0x61, 0xec, 0x1e, 0x04, 0xb8, 0xc0, 0x0c, 0xbb, 0x1e, 0xc6, 0xee, 0x2e, 0x49, 0xd5, 0xe7, 0xe0, + 0x1e, 0x92, 0xfb, 0x70, 0xc6, 0x31, 0x75, 0x49, 0xa4, 0x55, 0x5b, 0x4a, 0xbb, 0x66, 0xad, 0xe7, + 0x19, 0x5c, 0x91, 0xb2, 0xeb, 0xb8, 0x61, 0xdf, 0x9d, 0x36, 0xf6, 0xca, 0x5a, 0x6d, 0x82, 0x79, + 0x4e, 0x0e, 0x63, 0x32, 0xc6, 0x44, 0xab, 0x15, 0x5a, 0xfb, 0xaa, 0xee, 0xcd, 0x7f, 0x3c, 0x81, + 0x95, 0xcf, 0x27, 0xb0, 0x62, 0xa4, 0xa0, 0x3e, 0x10, 0xde, 0x2b, 0x42, 0xd4, 0xf7, 0xa0, 0x8e, + 0x68, 0xa1, 0xd7, 0x94, 0x56, 0xb5, 0xbd, 0xb0, 0xb9, 0x64, 0xce, 0x0c, 0xf8, 0xa8, 0x6b, 0xf6, + 0x59, 0x30, 0xb6, 0x1e, 0x9f, 0x66, 0xb0, 0xf2, 0xe5, 0x1c, 0xb6, 0xff, 0x61, 0x0c, 0x85, 0x80, + 0xdb, 0x53, 0x53, 0xf5, 0x3e, 0xa8, 0xfa, 0x88, 0x97, 0x87, 0xaf, 0xd9, 0xc5, 0xd2, 0x38, 0xaf, + 0x82, 0xfa, 0x3e, 0x8a, 0x10, 0xe5, 0xea, 0x1e, 0x58, 0xa2, 0x28, 0x71, 0x28, 0xa1, 0xcc, 0xc1, + 0x43, 0x14, 0x21, 0x2c, 0x48, 0x24, 0xc7, 0x5e, 0xb3, 0xf4, 0x3c, 0x83, 0x4d, 0x79, 0xe4, 0x5b, + 0x48, 0x86, 0xdd, 0xa0, 0x28, 0x79, 0x43, 0x28, 0xeb, 0x5f, 0xf5, 0xd4, 0x6d, 0xb0, 0x28, 0x12, + 0x87, 0x07, 0xbe, 0x73, 0x10, 0xd0, 0x40, 0xc8, 0x54, 0x6b, 0x2d, 0xcf, 0xe0, 0x92, 0x34, 0x9a, + 0x45, 0x0d, 0x1b, 0x88, 0x64, 0x10, 0xf8, 0xaf, 0x8b, 0x42, 0xb5, 0xc1, 0x4a, 0x09, 0x1e, 0x13, + 0x07, 0x33, 0x2e, 0x9c, 0x90, 0x44, 0x8e, 0x9b, 0x0a, 0x32, 0x9d, 0x7f, 0x2b, 0xcf, 0xe0, 0x83, + 0x19, 0x8f, 0x9b, 0x34, 0xc3, 0x6e, 0x14, 0x66, 0xc7, 0xa4, 0xcf, 0xb8, 0xd8, 0x27, 0x91, 0x95, + 0x0a, 0xa2, 0x1e, 0x82, 0xb5, 0x22, 0xed, 0x88, 0x44, 0xc1, 0x87, 0x54, 0xf2, 0x89, 0xb7, 0xb9, + 0xb5, 0xd5, 0xdd, 0x96, 0x5f, 0xc6, 0xea, 0x4d, 0x32, 0xb8, 0x3c, 0x08, 0xfc, 0xb7, 0x25, 0xa3, + 0x90, 0xbe, 0x7c, 0x51, 0xe2, 0x79, 0x06, 0x75, 0x99, 0xf6, 0x07, 0x03, 0xc3, 0x5e, 0xe6, 0xd7, + 0x74, 0xb2, 0xad, 0xa6, 0x60, 0xfd, 0xa6, 0x82, 0x13, 0x1c, 0x6e, 0x6e, 0x3d, 0x1d, 0x75, 0xb5, + 0xff, 0xcb, 0xd0, 0x67, 0x93, 0x0c, 0xae, 0x5e, 0x0b, 0x1d, 0x5c, 0x32, 0xf2, 0x0c, 0xb6, 0x6e, + 0x8f, 0xbd, 0x32, 0x31, 0xec, 0x55, 0x7e, 0xab, 0xb6, 0x37, 0x5f, 0x5c, 0xac, 0xef, 0x27, 0x50, + 0xb1, 0xfa, 0xa7, 0x13, 0x5d, 0x39, 0x9b, 0xe8, 0xca, 0xb7, 0x89, 0xae, 0x7c, 0xba, 0xd0, 0x2b, + 0x67, 0x17, 0x7a, 0xe5, 0xeb, 0x85, 0x5e, 0x79, 0xf7, 0xe8, 0xaf, 0xf7, 0x67, 0xf6, 0xcd, 0xbb, + 0xf5, 0xf2, 0x75, 0x3e, 0xf9, 0x19, 0x00, 0x00, 0xff, 0xff, 0xd6, 0x52, 0x88, 0x39, 0x0a, 0x04, + 0x00, 0x00, +} + +func (this *Params) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*Params) + if !ok { + that2, ok := that.(Params) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.MaxMemoCharacters != that1.MaxMemoCharacters { + return false + } + if this.TxSigLimit != that1.TxSigLimit { + return false + } + if this.TxSizeCostPerByte != that1.TxSizeCostPerByte { + return false + } + if this.SigVerifyCostED25519 != that1.SigVerifyCostED25519 { + return false + } + if this.SigVerifyCostSecp256k1 != that1.SigVerifyCostSecp256k1 { + return false + } + return true +} +func (m *BaseAccount) 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 *BaseAccount) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *BaseAccount) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Sequence != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.Sequence)) + i-- + dAtA[i] = 0x20 + } + if m.AccountNumber != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.AccountNumber)) + i-- + dAtA[i] = 0x18 + } + if len(m.PubKey) > 0 { + i -= len(m.PubKey) + copy(dAtA[i:], m.PubKey) + i = encodeVarintTypes(dAtA, i, uint64(len(m.PubKey))) + i-- + dAtA[i] = 0x12 + } + if len(m.Address) > 0 { + i -= len(m.Address) + copy(dAtA[i:], m.Address) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Address))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *StdFee) 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 *StdFee) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StdFee) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Gas != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.Gas)) + i-- + dAtA[i] = 0x10 + } + if len(m.Amount) > 0 { + for iNdEx := len(m.Amount) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Amount[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *Params) 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 *Params) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.SigVerifyCostSecp256k1 != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.SigVerifyCostSecp256k1)) + i-- + dAtA[i] = 0x28 + } + if m.SigVerifyCostED25519 != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.SigVerifyCostED25519)) + i-- + dAtA[i] = 0x20 + } + if m.TxSizeCostPerByte != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.TxSizeCostPerByte)) + i-- + dAtA[i] = 0x18 + } + if m.TxSigLimit != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.TxSigLimit)) + i-- + dAtA[i] = 0x10 + } + if m.MaxMemoCharacters != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.MaxMemoCharacters)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func encodeVarintTypes(dAtA []byte, offset int, v uint64) int { + offset -= sovTypes(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *BaseAccount) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Address) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.PubKey) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + if m.AccountNumber != 0 { + n += 1 + sovTypes(uint64(m.AccountNumber)) + } + if m.Sequence != 0 { + n += 1 + sovTypes(uint64(m.Sequence)) + } + return n +} + +func (m *StdFee) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Amount) > 0 { + for _, e := range m.Amount { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + if m.Gas != 0 { + n += 1 + sovTypes(uint64(m.Gas)) + } + return n +} + +func (m *Params) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.MaxMemoCharacters != 0 { + n += 1 + sovTypes(uint64(m.MaxMemoCharacters)) + } + if m.TxSigLimit != 0 { + n += 1 + sovTypes(uint64(m.TxSigLimit)) + } + if m.TxSizeCostPerByte != 0 { + n += 1 + sovTypes(uint64(m.TxSizeCostPerByte)) + } + if m.SigVerifyCostED25519 != 0 { + n += 1 + sovTypes(uint64(m.SigVerifyCostED25519)) + } + if m.SigVerifyCostSecp256k1 != 0 { + n += 1 + sovTypes(uint64(m.SigVerifyCostSecp256k1)) + } + return n +} + +func sovTypes(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTypes(x uint64) (n int) { + return sovTypes(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *BaseAccount) 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 ErrIntOverflowTypes + } + 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: BaseAccount: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: BaseAccount: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Address = append(m.Address[:0], dAtA[iNdEx:postIndex]...) + if m.Address == nil { + m.Address = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PubKey", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PubKey = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field AccountNumber", wireType) + } + m.AccountNumber = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.AccountNumber |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Sequence", wireType) + } + m.Sequence = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Sequence |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *StdFee) 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 ErrIntOverflowTypes + } + 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: StdFee: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: StdFee: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Amount = append(m.Amount, types.Coin{}) + if err := m.Amount[len(m.Amount)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Gas", wireType) + } + m.Gas = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Gas |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Params) 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 ErrIntOverflowTypes + } + 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: Params: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxMemoCharacters", wireType) + } + m.MaxMemoCharacters = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MaxMemoCharacters |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TxSigLimit", wireType) + } + m.TxSigLimit = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TxSigLimit |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TxSizeCostPerByte", wireType) + } + m.TxSizeCostPerByte = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TxSizeCostPerByte |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field SigVerifyCostED25519", wireType) + } + m.SigVerifyCostED25519 = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.SigVerifyCostED25519 |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field SigVerifyCostSecp256k1", wireType) + } + m.SigVerifyCostSecp256k1 = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.SigVerifyCostSecp256k1 |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTypes(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthTypes + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTypes + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTypes + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTypes = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTypes = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTypes = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/auth/types/types.proto b/x/auth/types/types.proto new file mode 100644 index 000000000000..c707eb9c55ab --- /dev/null +++ b/x/auth/types/types.proto @@ -0,0 +1,49 @@ +syntax = "proto3"; +package cosmos_sdk.x.auth.v1; + +import "third_party/proto/gogoproto/gogo.proto"; +import "types/types.proto"; + +option go_package = "github.com/cosmos/cosmos-sdk/x/auth/types"; + +// BaseAccount defines a base account type. It contains all the necessary fields +// for basic account functionality. Any custom account type should extend this +// type for additional functionality (e.g. vesting). +message BaseAccount { + option (gogoproto.goproto_getters) = false; + option (gogoproto.goproto_stringer) = false; + + bytes address = 1 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; + string pub_key = 2 [(gogoproto.moretags) = "yaml:\"public_key\""]; + uint64 account_number = 3 [(gogoproto.moretags) = "yaml:\"account_number\""]; + uint64 sequence = 4; +} + +// StdFee includes the amount of coins paid in fees and the maximum +// gas to be used by the transaction. The ratio yields an effective "gasprice", +// which must be above some miminum to be accepted into the mempool. +message StdFee { + repeated cosmos_sdk.v1.Coin amount = 1 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + ]; + uint64 gas = 2; +} + +// Params defines the parameters for the auth module. +message Params { + option (gogoproto.equal) = true; + option (gogoproto.goproto_stringer) = false; + + uint64 max_memo_characters = 1 [(gogoproto.moretags) = "yaml:\"max_memo_characters\""]; + uint64 tx_sig_limit = 2 [(gogoproto.moretags) = "yaml:\"tx_sig_limit\""]; + uint64 tx_size_cost_per_byte = 3 [(gogoproto.moretags) = "yaml:\"tx_size_cost_per_byte\""]; + uint64 sig_verify_cost_ed25519 = 4 [ + (gogoproto.customname) = "SigVerifyCostED25519", + (gogoproto.moretags) = "yaml:\"sig_verify_cost_ed25519\"" + ]; + uint64 sig_verify_cost_secp256k1 = 5 [ + (gogoproto.customname) = "SigVerifyCostSecp256k1", + (gogoproto.moretags) = "yaml:\"sig_verify_cost_secp256k1\"" + ]; +} diff --git a/x/auth/vesting/alias.go b/x/auth/vesting/alias.go index 387ca51e51f4..9591aa12a0d9 100644 --- a/x/auth/vesting/alias.go +++ b/x/auth/vesting/alias.go @@ -1,15 +1,13 @@ -// nolint -// autogenerated code using github.com/rigelrozanski/multitool -// aliases generated for the following subdirectories: -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/auth/vesting/types/ package vesting +// DONTCOVER +// nolint + import ( "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" ) var ( - // functions aliases RegisterCodec = types.RegisterCodec NewBaseVestingAccount = types.NewBaseVestingAccount NewContinuousVestingAccountRaw = types.NewContinuousVestingAccountRaw @@ -18,9 +16,6 @@ var ( NewPeriodicVestingAccount = types.NewPeriodicVestingAccount NewDelayedVestingAccountRaw = types.NewDelayedVestingAccountRaw NewDelayedVestingAccount = types.NewDelayedVestingAccount - - // variable aliases - VestingCdc = types.VestingCdc ) type ( diff --git a/x/auth/vesting/types/codec.go b/x/auth/vesting/types/codec.go index 556e71117849..c0b938e2e1c3 100644 --- a/x/auth/vesting/types/codec.go +++ b/x/auth/vesting/types/codec.go @@ -5,7 +5,8 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth/vesting/exported" ) -// RegisterCodec registers concrete types on the codec +// RegisterCodec registers the vesting interfaces and concrete types on the +// provided Amino codec. func RegisterCodec(cdc *codec.Codec) { cdc.RegisterInterface((*exported.VestingAccount)(nil), nil) cdc.RegisterConcrete(&BaseVestingAccount{}, "cosmos-sdk/BaseVestingAccount", nil) @@ -13,12 +14,3 @@ func RegisterCodec(cdc *codec.Codec) { cdc.RegisterConcrete(&DelayedVestingAccount{}, "cosmos-sdk/DelayedVestingAccount", nil) cdc.RegisterConcrete(&PeriodicVestingAccount{}, "cosmos-sdk/PeriodicVestingAccount", nil) } - -// VestingCdc module wide codec -var VestingCdc *codec.Codec - -func init() { - VestingCdc = codec.New() - RegisterCodec(VestingCdc) - VestingCdc.Seal() -} diff --git a/x/auth/vesting/types/common_test.go b/x/auth/vesting/types/common_test.go new file mode 100644 index 000000000000..02b80ac6aa6d --- /dev/null +++ b/x/auth/vesting/types/common_test.go @@ -0,0 +1,11 @@ +package types_test + +import ( + "github.com/cosmos/cosmos-sdk/simapp" + simappcodec "github.com/cosmos/cosmos-sdk/simapp/codec" +) + +var ( + app = simapp.Setup(false) + appCodec = simappcodec.NewAppCodec(app.Codec()) +) diff --git a/x/auth/vesting/types/genesis_test.go b/x/auth/vesting/types/genesis_test.go index 7a9781eb7040..fb3fea0a2fdf 100644 --- a/x/auth/vesting/types/genesis_test.go +++ b/x/auth/vesting/types/genesis_test.go @@ -22,7 +22,7 @@ var ( func TestValidateGenesisInvalidAccounts(t *testing.T) { acc1 := authtypes.NewBaseAccountWithAddress(sdk.AccAddress(addr1)) acc1Balance := sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 150)) - baseVestingAcc := NewBaseVestingAccount(&acc1, acc1Balance, 1548775410) + baseVestingAcc := NewBaseVestingAccount(acc1, acc1Balance, 1548775410) // invalid delegated vesting baseVestingAcc.DelegatedVesting = acc1Balance.Add(acc1Balance...) @@ -32,7 +32,7 @@ func TestValidateGenesisInvalidAccounts(t *testing.T) { genAccs := make([]exported.GenesisAccount, 2) genAccs[0] = baseVestingAcc - genAccs[1] = &acc2 + genAccs[1] = acc2 require.Error(t, authtypes.ValidateGenAccounts(genAccs)) baseVestingAcc.DelegatedVesting = acc1Balance diff --git a/x/auth/vesting/types/period.go b/x/auth/vesting/types/period.go index 1c4a5e2f4735..27b7a65c75be 100644 --- a/x/auth/vesting/types/period.go +++ b/x/auth/vesting/types/period.go @@ -4,22 +4,16 @@ import ( "fmt" "strings" - sdk "github.com/cosmos/cosmos-sdk/types" + "gopkg.in/yaml.v2" ) -// Period defines a length of time and amount of coins that will vest -type Period struct { - Length int64 `json:"length" yaml:"length"` // length of the period, in seconds - Amount sdk.Coins `json:"amount" yaml:"amount"` // amount of coins vesting during this period -} - // Periods stores all vesting periods passed as part of a PeriodicVestingAccount type Periods []Period // String Period implements stringer interface func (p Period) String() string { - return fmt.Sprintf(`Length: %d - Amount: %s`, p.Length, p.Amount) + out, _ := yaml.Marshal(p) + return string(out) } // String Periods implements stringer interface @@ -28,6 +22,7 @@ func (vp Periods) String() string { for _, period := range vp { periodsListString = append(periodsListString, period.String()) } + return strings.TrimSpace(fmt.Sprintf(`Vesting Periods: %s`, strings.Join(periodsListString, ", "))) } diff --git a/x/auth/vesting/types/types.pb.go b/x/auth/vesting/types/types.pb.go new file mode 100644 index 000000000000..adfa4af2ee88 --- /dev/null +++ b/x/auth/vesting/types/types.pb.go @@ -0,0 +1,1404 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: x/auth/vesting/types/types.proto + +package types + +import ( + fmt "fmt" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + types1 "github.com/cosmos/cosmos-sdk/types" + types "github.com/cosmos/cosmos-sdk/x/auth/types" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// BaseVestingAccount implements the VestingAccount interface. It contains all +// the necessary fields needed for any vesting account implementation. +type BaseVestingAccount struct { + *types.BaseAccount `protobuf:"bytes,1,opt,name=base_account,json=baseAccount,proto3,embedded=base_account" json:"base_account,omitempty"` + OriginalVesting github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,2,rep,name=original_vesting,json=originalVesting,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"original_vesting" yaml:"original_vesting"` + DelegatedFree github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,3,rep,name=delegated_free,json=delegatedFree,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"delegated_free" yaml:"delegated_free"` + DelegatedVesting github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,4,rep,name=delegated_vesting,json=delegatedVesting,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"delegated_vesting" yaml:"delegated_vesting"` + EndTime int64 `protobuf:"varint,5,opt,name=end_time,json=endTime,proto3" json:"end_time,omitempty" yaml:"end_time"` +} + +func (m *BaseVestingAccount) Reset() { *m = BaseVestingAccount{} } +func (*BaseVestingAccount) ProtoMessage() {} +func (*BaseVestingAccount) Descriptor() ([]byte, []int) { + return fileDescriptor_b7f744d63a45e116, []int{0} +} +func (m *BaseVestingAccount) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *BaseVestingAccount) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_BaseVestingAccount.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 *BaseVestingAccount) XXX_Merge(src proto.Message) { + xxx_messageInfo_BaseVestingAccount.Merge(m, src) +} +func (m *BaseVestingAccount) XXX_Size() int { + return m.Size() +} +func (m *BaseVestingAccount) XXX_DiscardUnknown() { + xxx_messageInfo_BaseVestingAccount.DiscardUnknown(m) +} + +var xxx_messageInfo_BaseVestingAccount proto.InternalMessageInfo + +// ContinuousVestingAccount implements the VestingAccount interface. It +// continuously vests by unlocking coins linearly with respect to time. +type ContinuousVestingAccount struct { + *BaseVestingAccount `protobuf:"bytes,1,opt,name=base_vesting_account,json=baseVestingAccount,proto3,embedded=base_vesting_account" json:"base_vesting_account,omitempty"` + StartTime int64 `protobuf:"varint,2,opt,name=start_time,json=startTime,proto3" json:"start_time,omitempty" yaml:"start_time"` +} + +func (m *ContinuousVestingAccount) Reset() { *m = ContinuousVestingAccount{} } +func (*ContinuousVestingAccount) ProtoMessage() {} +func (*ContinuousVestingAccount) Descriptor() ([]byte, []int) { + return fileDescriptor_b7f744d63a45e116, []int{1} +} +func (m *ContinuousVestingAccount) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ContinuousVestingAccount) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ContinuousVestingAccount.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 *ContinuousVestingAccount) XXX_Merge(src proto.Message) { + xxx_messageInfo_ContinuousVestingAccount.Merge(m, src) +} +func (m *ContinuousVestingAccount) XXX_Size() int { + return m.Size() +} +func (m *ContinuousVestingAccount) XXX_DiscardUnknown() { + xxx_messageInfo_ContinuousVestingAccount.DiscardUnknown(m) +} + +var xxx_messageInfo_ContinuousVestingAccount proto.InternalMessageInfo + +// DelayedVestingAccount implements the VestingAccount interface. It vests all +// coins after a specific time, but non prior. In other words, it keeps them +// locked until a specified time. +type DelayedVestingAccount struct { + *BaseVestingAccount `protobuf:"bytes,1,opt,name=base_vesting_account,json=baseVestingAccount,proto3,embedded=base_vesting_account" json:"base_vesting_account,omitempty"` +} + +func (m *DelayedVestingAccount) Reset() { *m = DelayedVestingAccount{} } +func (*DelayedVestingAccount) ProtoMessage() {} +func (*DelayedVestingAccount) Descriptor() ([]byte, []int) { + return fileDescriptor_b7f744d63a45e116, []int{2} +} +func (m *DelayedVestingAccount) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DelayedVestingAccount) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DelayedVestingAccount.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 *DelayedVestingAccount) XXX_Merge(src proto.Message) { + xxx_messageInfo_DelayedVestingAccount.Merge(m, src) +} +func (m *DelayedVestingAccount) XXX_Size() int { + return m.Size() +} +func (m *DelayedVestingAccount) XXX_DiscardUnknown() { + xxx_messageInfo_DelayedVestingAccount.DiscardUnknown(m) +} + +var xxx_messageInfo_DelayedVestingAccount proto.InternalMessageInfo + +// Period defines a length of time and amount of coins that will vest +type Period struct { + Length int64 `protobuf:"varint,1,opt,name=length,proto3" json:"length,omitempty"` + Amount github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,2,rep,name=amount,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"amount"` +} + +func (m *Period) Reset() { *m = Period{} } +func (*Period) ProtoMessage() {} +func (*Period) Descriptor() ([]byte, []int) { + return fileDescriptor_b7f744d63a45e116, []int{3} +} +func (m *Period) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Period) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Period.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 *Period) XXX_Merge(src proto.Message) { + xxx_messageInfo_Period.Merge(m, src) +} +func (m *Period) XXX_Size() int { + return m.Size() +} +func (m *Period) XXX_DiscardUnknown() { + xxx_messageInfo_Period.DiscardUnknown(m) +} + +var xxx_messageInfo_Period proto.InternalMessageInfo + +func (m *Period) GetLength() int64 { + if m != nil { + return m.Length + } + return 0 +} + +func (m *Period) GetAmount() github_com_cosmos_cosmos_sdk_types.Coins { + if m != nil { + return m.Amount + } + return nil +} + +// PeriodicVestingAccount implements the VestingAccount interface. It +// periodically vests by unlocking coins during each specified period +type PeriodicVestingAccount struct { + *BaseVestingAccount `protobuf:"bytes,1,opt,name=base_vesting_account,json=baseVestingAccount,proto3,embedded=base_vesting_account" json:"base_vesting_account,omitempty"` + StartTime int64 `protobuf:"varint,2,opt,name=start_time,json=startTime,proto3" json:"start_time,omitempty" yaml:"start_time"` + VestingPeriods []Period `protobuf:"bytes,3,rep,name=vesting_periods,json=vestingPeriods,proto3" json:"vesting_periods" yaml:"vesting_periods"` +} + +func (m *PeriodicVestingAccount) Reset() { *m = PeriodicVestingAccount{} } +func (*PeriodicVestingAccount) ProtoMessage() {} +func (*PeriodicVestingAccount) Descriptor() ([]byte, []int) { + return fileDescriptor_b7f744d63a45e116, []int{4} +} +func (m *PeriodicVestingAccount) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PeriodicVestingAccount) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PeriodicVestingAccount.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 *PeriodicVestingAccount) XXX_Merge(src proto.Message) { + xxx_messageInfo_PeriodicVestingAccount.Merge(m, src) +} +func (m *PeriodicVestingAccount) XXX_Size() int { + return m.Size() +} +func (m *PeriodicVestingAccount) XXX_DiscardUnknown() { + xxx_messageInfo_PeriodicVestingAccount.DiscardUnknown(m) +} + +var xxx_messageInfo_PeriodicVestingAccount proto.InternalMessageInfo + +func init() { + proto.RegisterType((*BaseVestingAccount)(nil), "cosmos_sdk.x.auth.vesting.v1.BaseVestingAccount") + proto.RegisterType((*ContinuousVestingAccount)(nil), "cosmos_sdk.x.auth.vesting.v1.ContinuousVestingAccount") + proto.RegisterType((*DelayedVestingAccount)(nil), "cosmos_sdk.x.auth.vesting.v1.DelayedVestingAccount") + proto.RegisterType((*Period)(nil), "cosmos_sdk.x.auth.vesting.v1.Period") + proto.RegisterType((*PeriodicVestingAccount)(nil), "cosmos_sdk.x.auth.vesting.v1.PeriodicVestingAccount") +} + +func init() { proto.RegisterFile("x/auth/vesting/types/types.proto", fileDescriptor_b7f744d63a45e116) } + +var fileDescriptor_b7f744d63a45e116 = []byte{ + // 593 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x55, 0x4f, 0x8f, 0xd2, 0x40, + 0x1c, 0xed, 0x2c, 0x88, 0xeb, 0xa0, 0xcb, 0xd2, 0x15, 0x6c, 0x88, 0x69, 0xb1, 0x31, 0x86, 0x8b, + 0xd3, 0x65, 0xf5, 0xc4, 0xcd, 0xae, 0x31, 0xd1, 0xf5, 0x60, 0x1a, 0xe3, 0xc1, 0xc4, 0x34, 0x85, + 0x8e, 0x65, 0xb2, 0xb4, 0x43, 0x3a, 0x03, 0x59, 0x3e, 0xc0, 0x26, 0x26, 0x9b, 0x18, 0x8f, 0x1e, + 0xf7, 0xec, 0xcd, 0x8f, 0x60, 0xe2, 0x61, 0x8f, 0x1c, 0x3d, 0xa1, 0x81, 0x6f, 0xc0, 0x27, 0x30, + 0x74, 0x06, 0x58, 0xcb, 0x2e, 0xc9, 0x7a, 0x30, 0xf1, 0x02, 0x9d, 0x3f, 0xef, 0xfd, 0xde, 0xfb, + 0xcd, 0x9b, 0x16, 0x56, 0x8f, 0x2c, 0xaf, 0xc7, 0xdb, 0x56, 0x1f, 0x33, 0x4e, 0xa2, 0xc0, 0xe2, + 0x83, 0x2e, 0x66, 0xe2, 0x17, 0x75, 0x63, 0xca, 0xa9, 0x7a, 0xb7, 0x45, 0x59, 0x48, 0x99, 0xcb, + 0xfc, 0x43, 0x74, 0x84, 0x66, 0x9b, 0x91, 0xdc, 0x8c, 0xfa, 0xf5, 0xca, 0x03, 0xde, 0x26, 0xb1, + 0xef, 0x76, 0xbd, 0x98, 0x0f, 0xac, 0x04, 0x60, 0x05, 0x34, 0xa0, 0xcb, 0x27, 0xc1, 0x52, 0x29, + 0xae, 0x10, 0x57, 0x34, 0x59, 0x7a, 0x65, 0xc5, 0xfc, 0x96, 0x85, 0xaa, 0xed, 0x31, 0xfc, 0x46, + 0xd4, 0x79, 0xd2, 0x6a, 0xd1, 0x5e, 0xc4, 0xd5, 0x17, 0xf0, 0x66, 0xd3, 0x63, 0xd8, 0xf5, 0xc4, + 0x58, 0x03, 0x55, 0x50, 0xcb, 0xef, 0xdd, 0x43, 0x17, 0x08, 0xac, 0xa3, 0x19, 0x5e, 0x02, 0xed, + 0xec, 0x70, 0x64, 0x00, 0x27, 0xdf, 0x5c, 0x4e, 0xa9, 0x27, 0x00, 0x6e, 0xd3, 0x98, 0x04, 0x24, + 0xf2, 0x3a, 0xae, 0xf4, 0xa3, 0x6d, 0x54, 0x33, 0xb5, 0xfc, 0xde, 0xce, 0x79, 0xc2, 0x7e, 0x1d, + 0xed, 0x53, 0x12, 0xd9, 0x07, 0x67, 0x23, 0x43, 0x99, 0x8e, 0x8c, 0x3b, 0x03, 0x2f, 0xec, 0x34, + 0xcc, 0x34, 0xd4, 0xfc, 0xf2, 0xd3, 0xa8, 0x05, 0x84, 0xb7, 0x7b, 0x4d, 0xd4, 0xa2, 0xa1, 0x25, + 0x18, 0xe4, 0xdf, 0x43, 0xe6, 0x1f, 0x4a, 0x7f, 0x33, 0x2e, 0xe6, 0x14, 0xe6, 0x70, 0x69, 0x50, + 0x3d, 0x06, 0x70, 0xcb, 0xc7, 0x1d, 0x1c, 0x78, 0x1c, 0xfb, 0xee, 0xfb, 0x18, 0x63, 0x2d, 0x73, + 0xb9, 0x96, 0xe7, 0x52, 0x4b, 0x49, 0x68, 0xf9, 0x13, 0x78, 0x35, 0x25, 0xb7, 0x16, 0xe0, 0x67, + 0x31, 0xc6, 0xea, 0x47, 0x00, 0x8b, 0x4b, 0xba, 0x79, 0x5b, 0xb2, 0x97, 0x4b, 0x79, 0x29, 0xa5, + 0x68, 0x69, 0x29, 0x7f, 0xd5, 0x97, 0xed, 0x05, 0x7e, 0xde, 0x18, 0x04, 0x37, 0x71, 0xe4, 0xbb, + 0x9c, 0x84, 0x58, 0xbb, 0x56, 0x05, 0xb5, 0x8c, 0xbd, 0x33, 0x1d, 0x19, 0x05, 0x51, 0x6d, 0xbe, + 0x62, 0x3a, 0xd7, 0x71, 0xe4, 0xbf, 0x26, 0x21, 0x6e, 0x6c, 0x7e, 0x38, 0x35, 0x94, 0xcf, 0xa7, + 0x86, 0x62, 0x7e, 0x07, 0x50, 0xdb, 0xa7, 0x11, 0x27, 0x51, 0x8f, 0xf6, 0x58, 0x2a, 0x49, 0x6d, + 0x78, 0x3b, 0x49, 0x92, 0x54, 0x99, 0x4a, 0xd4, 0x2e, 0x5a, 0x17, 0x79, 0xb4, 0x9a, 0x4c, 0x19, + 0x30, 0xb5, 0xb9, 0x9a, 0xd9, 0xc7, 0x10, 0x32, 0xee, 0xc5, 0x5c, 0x58, 0xd8, 0x48, 0x2c, 0x94, + 0xa6, 0x23, 0xa3, 0x28, 0x2c, 0x2c, 0xd7, 0x4c, 0xe7, 0x46, 0x32, 0x48, 0xd9, 0x38, 0x01, 0xb0, + 0xf4, 0x14, 0x77, 0xbc, 0xc1, 0xa2, 0x27, 0xff, 0xdc, 0xc3, 0x39, 0x35, 0xc7, 0x00, 0xe6, 0x5e, + 0xe1, 0x98, 0x50, 0x5f, 0x2d, 0xc3, 0x5c, 0x07, 0x47, 0x01, 0x6f, 0x27, 0x05, 0x33, 0x8e, 0x1c, + 0xa9, 0xef, 0x60, 0xce, 0x0b, 0x13, 0x21, 0x6b, 0x6e, 0xd3, 0xee, 0x2c, 0x36, 0x57, 0x8a, 0x86, + 0x24, 0x6d, 0x64, 0x13, 0x1d, 0x5f, 0x37, 0x60, 0x59, 0xe8, 0x20, 0xad, 0xff, 0xeb, 0x68, 0xd5, + 0x10, 0x16, 0xe6, 0xd2, 0xba, 0x89, 0x03, 0x26, 0xaf, 0xfa, 0xfd, 0xf5, 0xd2, 0x84, 0x5d, 0x5b, + 0x97, 0x17, 0xae, 0x2c, 0x8a, 0xa4, 0xa8, 0x4c, 0x67, 0x4b, 0xce, 0x88, 0xed, 0x6c, 0x79, 0x76, + 0xf6, 0xc1, 0xd9, 0x58, 0x07, 0xc3, 0xb1, 0x0e, 0x7e, 0x8d, 0x75, 0xf0, 0x69, 0xa2, 0x2b, 0xc3, + 0x89, 0xae, 0xfc, 0x98, 0xe8, 0xca, 0xdb, 0xfa, 0xda, 0x53, 0xb8, 0xe8, 0x03, 0xd1, 0xcc, 0x25, + 0x2f, 0xea, 0x47, 0xbf, 0x03, 0x00, 0x00, 0xff, 0xff, 0x89, 0x54, 0xae, 0x4f, 0x3f, 0x06, 0x00, + 0x00, +} + +func (m *BaseVestingAccount) 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 *BaseVestingAccount) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *BaseVestingAccount) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.EndTime != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.EndTime)) + i-- + dAtA[i] = 0x28 + } + if len(m.DelegatedVesting) > 0 { + for iNdEx := len(m.DelegatedVesting) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.DelegatedVesting[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + } + if len(m.DelegatedFree) > 0 { + for iNdEx := len(m.DelegatedFree) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.DelegatedFree[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.OriginalVesting) > 0 { + for iNdEx := len(m.OriginalVesting) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.OriginalVesting[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if m.BaseAccount != nil { + { + size, err := m.BaseAccount.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ContinuousVestingAccount) 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 *ContinuousVestingAccount) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ContinuousVestingAccount) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.StartTime != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.StartTime)) + i-- + dAtA[i] = 0x10 + } + if m.BaseVestingAccount != nil { + { + size, err := m.BaseVestingAccount.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *DelayedVestingAccount) 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 *DelayedVestingAccount) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DelayedVestingAccount) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.BaseVestingAccount != nil { + { + size, err := m.BaseVestingAccount.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *Period) 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 *Period) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Period) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Amount) > 0 { + for iNdEx := len(m.Amount) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Amount[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if m.Length != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.Length)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *PeriodicVestingAccount) 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 *PeriodicVestingAccount) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PeriodicVestingAccount) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.VestingPeriods) > 0 { + for iNdEx := len(m.VestingPeriods) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.VestingPeriods[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if m.StartTime != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.StartTime)) + i-- + dAtA[i] = 0x10 + } + if m.BaseVestingAccount != nil { + { + size, err := m.BaseVestingAccount.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintTypes(dAtA []byte, offset int, v uint64) int { + offset -= sovTypes(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *BaseVestingAccount) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.BaseAccount != nil { + l = m.BaseAccount.Size() + n += 1 + l + sovTypes(uint64(l)) + } + if len(m.OriginalVesting) > 0 { + for _, e := range m.OriginalVesting { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + if len(m.DelegatedFree) > 0 { + for _, e := range m.DelegatedFree { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + if len(m.DelegatedVesting) > 0 { + for _, e := range m.DelegatedVesting { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + if m.EndTime != 0 { + n += 1 + sovTypes(uint64(m.EndTime)) + } + return n +} + +func (m *ContinuousVestingAccount) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.BaseVestingAccount != nil { + l = m.BaseVestingAccount.Size() + n += 1 + l + sovTypes(uint64(l)) + } + if m.StartTime != 0 { + n += 1 + sovTypes(uint64(m.StartTime)) + } + return n +} + +func (m *DelayedVestingAccount) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.BaseVestingAccount != nil { + l = m.BaseVestingAccount.Size() + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + +func (m *Period) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Length != 0 { + n += 1 + sovTypes(uint64(m.Length)) + } + if len(m.Amount) > 0 { + for _, e := range m.Amount { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + return n +} + +func (m *PeriodicVestingAccount) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.BaseVestingAccount != nil { + l = m.BaseVestingAccount.Size() + n += 1 + l + sovTypes(uint64(l)) + } + if m.StartTime != 0 { + n += 1 + sovTypes(uint64(m.StartTime)) + } + if len(m.VestingPeriods) > 0 { + for _, e := range m.VestingPeriods { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + return n +} + +func sovTypes(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTypes(x uint64) (n int) { + return sovTypes(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *BaseVestingAccount) 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 ErrIntOverflowTypes + } + 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: BaseVestingAccount: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: BaseVestingAccount: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BaseAccount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.BaseAccount == nil { + m.BaseAccount = &types.BaseAccount{} + } + if err := m.BaseAccount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field OriginalVesting", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.OriginalVesting = append(m.OriginalVesting, types1.Coin{}) + if err := m.OriginalVesting[len(m.OriginalVesting)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DelegatedFree", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DelegatedFree = append(m.DelegatedFree, types1.Coin{}) + if err := m.DelegatedFree[len(m.DelegatedFree)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DelegatedVesting", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DelegatedVesting = append(m.DelegatedVesting, types1.Coin{}) + if err := m.DelegatedVesting[len(m.DelegatedVesting)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field EndTime", wireType) + } + m.EndTime = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.EndTime |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ContinuousVestingAccount) 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 ErrIntOverflowTypes + } + 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: ContinuousVestingAccount: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ContinuousVestingAccount: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BaseVestingAccount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.BaseVestingAccount == nil { + m.BaseVestingAccount = &BaseVestingAccount{} + } + if err := m.BaseVestingAccount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field StartTime", wireType) + } + m.StartTime = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.StartTime |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *DelayedVestingAccount) 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 ErrIntOverflowTypes + } + 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: DelayedVestingAccount: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DelayedVestingAccount: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BaseVestingAccount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.BaseVestingAccount == nil { + m.BaseVestingAccount = &BaseVestingAccount{} + } + if err := m.BaseVestingAccount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Period) 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 ErrIntOverflowTypes + } + 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: Period: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Period: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Length", wireType) + } + m.Length = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Length |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Amount = append(m.Amount, types1.Coin{}) + if err := m.Amount[len(m.Amount)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *PeriodicVestingAccount) 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 ErrIntOverflowTypes + } + 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: PeriodicVestingAccount: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PeriodicVestingAccount: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BaseVestingAccount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.BaseVestingAccount == nil { + m.BaseVestingAccount = &BaseVestingAccount{} + } + if err := m.BaseVestingAccount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field StartTime", wireType) + } + m.StartTime = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.StartTime |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field VestingPeriods", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.VestingPeriods = append(m.VestingPeriods, Period{}) + if err := m.VestingPeriods[len(m.VestingPeriods)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTypes(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthTypes + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTypes + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTypes + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTypes = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTypes = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTypes = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/auth/vesting/types/types.proto b/x/auth/vesting/types/types.proto new file mode 100644 index 000000000000..7ce129553289 --- /dev/null +++ b/x/auth/vesting/types/types.proto @@ -0,0 +1,76 @@ +syntax = "proto3"; +package cosmos_sdk.x.auth.vesting.v1; + +import "third_party/proto/gogoproto/gogo.proto"; +import "types/types.proto"; +import "x/auth/types/types.proto"; + +option go_package = "github.com/cosmos/cosmos-sdk/x/auth/vesting/types"; + +// BaseVestingAccount implements the VestingAccount interface. It contains all +// the necessary fields needed for any vesting account implementation. +message BaseVestingAccount { + option (gogoproto.goproto_getters) = false; + option (gogoproto.goproto_stringer) = false; + + cosmos_sdk.x.auth.v1.BaseAccount base_account = 1 [(gogoproto.embed) = true]; + repeated cosmos_sdk.v1.Coin original_vesting = 2 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", + (gogoproto.moretags) = "yaml:\"original_vesting\"" + ]; + repeated cosmos_sdk.v1.Coin delegated_free = 3 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", + (gogoproto.moretags) = "yaml:\"delegated_free\"" + ]; + repeated cosmos_sdk.v1.Coin delegated_vesting = 4 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", + (gogoproto.moretags) = "yaml:\"delegated_vesting\"" + ]; + int64 end_time = 5 [(gogoproto.moretags) = "yaml:\"end_time\""]; +} + +// ContinuousVestingAccount implements the VestingAccount interface. It +// continuously vests by unlocking coins linearly with respect to time. +message ContinuousVestingAccount { + option (gogoproto.goproto_getters) = false; + option (gogoproto.goproto_stringer) = false; + + BaseVestingAccount base_vesting_account = 1 [(gogoproto.embed) = true]; + int64 start_time = 2 [(gogoproto.moretags) = "yaml:\"start_time\""]; +} + +// DelayedVestingAccount implements the VestingAccount interface. It vests all +// coins after a specific time, but non prior. In other words, it keeps them +// locked until a specified time. +message DelayedVestingAccount { + option (gogoproto.goproto_getters) = false; + option (gogoproto.goproto_stringer) = false; + + BaseVestingAccount base_vesting_account = 1 [(gogoproto.embed) = true]; +} + +// Period defines a length of time and amount of coins that will vest +message Period { + option (gogoproto.goproto_stringer) = false; + + int64 length = 1; + repeated cosmos_sdk.v1.Coin amount = 2 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + ]; +} + +// PeriodicVestingAccount implements the VestingAccount interface. It +// periodically vests by unlocking coins during each specified period +message PeriodicVestingAccount { + option (gogoproto.goproto_getters) = false; + option (gogoproto.goproto_stringer) = false; + + BaseVestingAccount base_vesting_account = 1 [(gogoproto.embed) = true]; + int64 start_time = 2 [(gogoproto.moretags) = "yaml:\"start_time\""]; + repeated Period vesting_periods = 3 + [(gogoproto.moretags) = "yaml:\"vesting_periods\"", (gogoproto.nullable) = false]; +} diff --git a/x/auth/vesting/types/vesting_account.go b/x/auth/vesting/types/vesting_account.go index 70efad2b33ef..cbbeffc03143 100644 --- a/x/auth/vesting/types/vesting_account.go +++ b/x/auth/vesting/types/vesting_account.go @@ -22,24 +22,8 @@ var ( _ vestexported.VestingAccount = (*DelayedVestingAccount)(nil) ) -// Register the vesting account types on the auth module codec -func init() { - authtypes.RegisterAccountTypeCodec(&BaseVestingAccount{}, "cosmos-sdk/BaseVestingAccount") - authtypes.RegisterAccountTypeCodec(&ContinuousVestingAccount{}, "cosmos-sdk/ContinuousVestingAccount") - authtypes.RegisterAccountTypeCodec(&DelayedVestingAccount{}, "cosmos-sdk/DelayedVestingAccount") - authtypes.RegisterAccountTypeCodec(&PeriodicVestingAccount{}, "cosmos-sdk/PeriodicVestingAccount") -} - -// BaseVestingAccount implements the VestingAccount interface. It contains all -// the necessary fields needed for any vesting account implementation. -type BaseVestingAccount struct { - *authtypes.BaseAccount - - OriginalVesting sdk.Coins `json:"original_vesting" yaml:"original_vesting"` // coins in account upon initialization - DelegatedFree sdk.Coins `json:"delegated_free" yaml:"delegated_free"` // coins that are vested and delegated - DelegatedVesting sdk.Coins `json:"delegated_vesting" yaml:"delegated_vesting"` // coins that vesting and delegated - EndTime int64 `json:"end_time" yaml:"end_time"` // when the coins become unlocked -} +//----------------------------------------------------------------------------- +// Base Vesting Account // NewBaseVestingAccount creates a new BaseVestingAccount object. It is the // callers responsibility to ensure the base account has sufficient funds with @@ -204,6 +188,7 @@ func (bva BaseVestingAccount) String() string { func (bva BaseVestingAccount) MarshalYAML() (interface{}, error) { alias := vestingAccountPretty{ Address: bva.Address, + PubKey: bva.PubKey, AccountNumber: bva.AccountNumber, Sequence: bva.Sequence, OriginalVesting: bva.OriginalVesting, @@ -212,15 +197,6 @@ func (bva BaseVestingAccount) MarshalYAML() (interface{}, error) { EndTime: bva.EndTime, } - if bva.PubKey != nil { - pks, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, bva.PubKey) - if err != nil { - return nil, err - } - - alias.PubKey = pks - } - bz, err := yaml.Marshal(alias) if err != nil { return nil, err @@ -233,6 +209,7 @@ func (bva BaseVestingAccount) MarshalYAML() (interface{}, error) { func (bva BaseVestingAccount) MarshalJSON() ([]byte, error) { alias := vestingAccountPretty{ Address: bva.Address, + PubKey: bva.PubKey, AccountNumber: bva.AccountNumber, Sequence: bva.Sequence, OriginalVesting: bva.OriginalVesting, @@ -241,15 +218,6 @@ func (bva BaseVestingAccount) MarshalJSON() ([]byte, error) { EndTime: bva.EndTime, } - if bva.PubKey != nil { - pks, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, bva.PubKey) - if err != nil { - return nil, err - } - - alias.PubKey = pks - } - return json.Marshal(alias) } @@ -287,14 +255,6 @@ func (bva *BaseVestingAccount) UnmarshalJSON(bz []byte) error { var _ vestexported.VestingAccount = (*ContinuousVestingAccount)(nil) var _ authexported.GenesisAccount = (*ContinuousVestingAccount)(nil) -// ContinuousVestingAccount implements the VestingAccount interface. It -// continuously vests by unlocking coins linearly with respect to time. -type ContinuousVestingAccount struct { - *BaseVestingAccount - - StartTime int64 `json:"start_time" yaml:"start_time"` // when the coins start to vest -} - // NewContinuousVestingAccountRaw creates a new ContinuousVestingAccount object from BaseVestingAccount func NewContinuousVestingAccountRaw(bva *BaseVestingAccount, startTime int64) *ContinuousVestingAccount { return &ContinuousVestingAccount{ @@ -386,6 +346,7 @@ func (cva ContinuousVestingAccount) String() string { func (cva ContinuousVestingAccount) MarshalYAML() (interface{}, error) { alias := vestingAccountPretty{ Address: cva.Address, + PubKey: cva.PubKey, AccountNumber: cva.AccountNumber, Sequence: cva.Sequence, OriginalVesting: cva.OriginalVesting, @@ -395,15 +356,6 @@ func (cva ContinuousVestingAccount) MarshalYAML() (interface{}, error) { StartTime: cva.StartTime, } - if cva.PubKey != nil { - pks, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, cva.PubKey) - if err != nil { - return nil, err - } - - alias.PubKey = pks - } - bz, err := yaml.Marshal(alias) if err != nil { return nil, err @@ -416,6 +368,7 @@ func (cva ContinuousVestingAccount) MarshalYAML() (interface{}, error) { func (cva ContinuousVestingAccount) MarshalJSON() ([]byte, error) { alias := vestingAccountPretty{ Address: cva.Address, + PubKey: cva.PubKey, AccountNumber: cva.AccountNumber, Sequence: cva.Sequence, OriginalVesting: cva.OriginalVesting, @@ -425,15 +378,6 @@ func (cva ContinuousVestingAccount) MarshalJSON() ([]byte, error) { StartTime: cva.StartTime, } - if cva.PubKey != nil { - pks, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, cva.PubKey) - if err != nil { - return nil, err - } - - alias.PubKey = pks - } - return json.Marshal(alias) } @@ -474,14 +418,6 @@ func (cva *ContinuousVestingAccount) UnmarshalJSON(bz []byte) error { var _ vestexported.VestingAccount = (*PeriodicVestingAccount)(nil) var _ authexported.GenesisAccount = (*PeriodicVestingAccount)(nil) -// PeriodicVestingAccount implements the VestingAccount interface. It -// periodically vests by unlocking coins during each specified period -type PeriodicVestingAccount struct { - *BaseVestingAccount - StartTime int64 `json:"start_time" yaml:"start_time"` // when the coins start to vest - VestingPeriods Periods `json:"vesting_periods" yaml:"vesting_periods"` // the vesting schedule -} - // NewPeriodicVestingAccountRaw creates a new PeriodicVestingAccount object from BaseVestingAccount func NewPeriodicVestingAccountRaw(bva *BaseVestingAccount, startTime int64, periods Periods) *PeriodicVestingAccount { return &PeriodicVestingAccount{ @@ -602,6 +538,7 @@ func (pva PeriodicVestingAccount) String() string { func (pva PeriodicVestingAccount) MarshalYAML() (interface{}, error) { alias := vestingAccountPretty{ Address: pva.Address, + PubKey: pva.PubKey, AccountNumber: pva.AccountNumber, Sequence: pva.Sequence, OriginalVesting: pva.OriginalVesting, @@ -612,15 +549,6 @@ func (pva PeriodicVestingAccount) MarshalYAML() (interface{}, error) { VestingPeriods: pva.VestingPeriods, } - if pva.PubKey != nil { - pks, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pva.PubKey) - if err != nil { - return nil, err - } - - alias.PubKey = pks - } - bz, err := yaml.Marshal(alias) if err != nil { return nil, err @@ -633,6 +561,7 @@ func (pva PeriodicVestingAccount) MarshalYAML() (interface{}, error) { func (pva PeriodicVestingAccount) MarshalJSON() ([]byte, error) { alias := vestingAccountPretty{ Address: pva.Address, + PubKey: pva.PubKey, AccountNumber: pva.AccountNumber, Sequence: pva.Sequence, OriginalVesting: pva.OriginalVesting, @@ -643,15 +572,6 @@ func (pva PeriodicVestingAccount) MarshalJSON() ([]byte, error) { VestingPeriods: pva.VestingPeriods, } - if pva.PubKey != nil { - pks, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pva.PubKey) - if err != nil { - return nil, err - } - - alias.PubKey = pks - } - return json.Marshal(alias) } @@ -693,13 +613,6 @@ func (pva *PeriodicVestingAccount) UnmarshalJSON(bz []byte) error { var _ vestexported.VestingAccount = (*DelayedVestingAccount)(nil) var _ authexported.GenesisAccount = (*DelayedVestingAccount)(nil) -// DelayedVestingAccount implements the VestingAccount interface. It vests all -// coins after a specific time, but non prior. In other words, it keeps them -// locked until a specified time. -type DelayedVestingAccount struct { - *BaseVestingAccount -} - // NewDelayedVestingAccountRaw creates a new DelayedVestingAccount object from BaseVestingAccount func NewDelayedVestingAccountRaw(bva *BaseVestingAccount) *DelayedVestingAccount { return &DelayedVestingAccount{ @@ -756,10 +669,16 @@ func (dva DelayedVestingAccount) Validate() error { return dva.BaseVestingAccount.Validate() } +func (dva DelayedVestingAccount) String() string { + out, _ := dva.MarshalYAML() + return out.(string) +} + // MarshalJSON returns the JSON representation of a DelayedVestingAccount. func (dva DelayedVestingAccount) MarshalJSON() ([]byte, error) { alias := vestingAccountPretty{ Address: dva.Address, + PubKey: dva.PubKey, AccountNumber: dva.AccountNumber, Sequence: dva.Sequence, OriginalVesting: dva.OriginalVesting, @@ -768,15 +687,6 @@ func (dva DelayedVestingAccount) MarshalJSON() ([]byte, error) { EndTime: dva.EndTime, } - if dva.PubKey != nil { - pks, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, dva.PubKey) - if err != nil { - return nil, err - } - - alias.PubKey = pks - } - return json.Marshal(alias) } diff --git a/x/auth/vesting/types/vesting_account_test.go b/x/auth/vesting/types/vesting_account_test.go index 4555d329e625..e36661111fef 100644 --- a/x/auth/vesting/types/vesting_account_test.go +++ b/x/auth/vesting/types/vesting_account_test.go @@ -1,4 +1,4 @@ -package types +package types_test import ( "encoding/json" @@ -13,6 +13,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" ) var ( @@ -24,10 +25,10 @@ func TestGetVestedCoinsContVestingAcc(t *testing.T) { now := tmtime.Now() endTime := now.Add(24 * time.Hour) - _, _, addr := KeyTestPubAddr() + _, _, addr := authtypes.KeyTestPubAddr() origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) - cva := NewContinuousVestingAccount(&bacc, origCoins, now.Unix(), endTime.Unix()) + cva := types.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) // require no coins vested in the very beginning of the vesting schedule vestedCoins := cva.GetVestedCoins(now) @@ -50,10 +51,10 @@ func TestGetVestingCoinsContVestingAcc(t *testing.T) { now := tmtime.Now() endTime := now.Add(24 * time.Hour) - _, _, addr := KeyTestPubAddr() + _, _, addr := authtypes.KeyTestPubAddr() origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) - cva := NewContinuousVestingAccount(&bacc, origCoins, now.Unix(), endTime.Unix()) + cva := types.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) // require all coins vesting in the beginning of the vesting schedule vestingCoins := cva.GetVestingCoins(now) @@ -72,11 +73,11 @@ func TestSpendableCoinsContVestingAcc(t *testing.T) { now := tmtime.Now() endTime := now.Add(24 * time.Hour) - _, _, addr := KeyTestPubAddr() + _, _, addr := authtypes.KeyTestPubAddr() origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) - cva := NewContinuousVestingAccount(&bacc, origCoins, now.Unix(), endTime.Unix()) + cva := types.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) // require that all original coins are locked at the end of the vesting // schedule @@ -100,24 +101,24 @@ func TestTrackDelegationContVestingAcc(t *testing.T) { now := tmtime.Now() endTime := now.Add(24 * time.Hour) - _, _, addr := KeyTestPubAddr() + _, _, addr := authtypes.KeyTestPubAddr() origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) // require the ability to delegate all vesting coins - cva := NewContinuousVestingAccount(&bacc, origCoins, now.Unix(), endTime.Unix()) + cva := types.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) cva.TrackDelegation(now, origCoins, origCoins) require.Equal(t, origCoins, cva.DelegatedVesting) require.Nil(t, cva.DelegatedFree) // require the ability to delegate all vested coins - cva = NewContinuousVestingAccount(&bacc, origCoins, now.Unix(), endTime.Unix()) + cva = types.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) cva.TrackDelegation(endTime, origCoins, origCoins) require.Nil(t, cva.DelegatedVesting) require.Equal(t, origCoins, cva.DelegatedFree) // require the ability to delegate all vesting coins (50%) and all vested coins (50%) - cva = NewContinuousVestingAccount(&bacc, origCoins, now.Unix(), endTime.Unix()) + cva = types.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) cva.TrackDelegation(now.Add(12*time.Hour), origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) require.Equal(t, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}, cva.DelegatedVesting) require.Nil(t, cva.DelegatedFree) @@ -127,7 +128,7 @@ func TestTrackDelegationContVestingAcc(t *testing.T) { require.Equal(t, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}, cva.DelegatedFree) // require no modifications when delegation amount is zero or not enough funds - cva = NewContinuousVestingAccount(&bacc, origCoins, now.Unix(), endTime.Unix()) + cva = types.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) require.Panics(t, func() { cva.TrackDelegation(endTime, origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 1000000)}) }) @@ -139,19 +140,19 @@ func TestTrackUndelegationContVestingAcc(t *testing.T) { now := tmtime.Now() endTime := now.Add(24 * time.Hour) - _, _, addr := KeyTestPubAddr() + _, _, addr := authtypes.KeyTestPubAddr() origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) // require the ability to undelegate all vesting coins - cva := NewContinuousVestingAccount(&bacc, origCoins, now.Unix(), endTime.Unix()) + cva := types.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) cva.TrackDelegation(now, origCoins, origCoins) cva.TrackUndelegation(origCoins) require.Nil(t, cva.DelegatedFree) require.Nil(t, cva.DelegatedVesting) // require the ability to undelegate all vested coins - cva = NewContinuousVestingAccount(&bacc, origCoins, now.Unix(), endTime.Unix()) + cva = types.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) cva.TrackDelegation(endTime, origCoins, origCoins) cva.TrackUndelegation(origCoins) @@ -159,7 +160,7 @@ func TestTrackUndelegationContVestingAcc(t *testing.T) { require.Nil(t, cva.DelegatedVesting) // require no modifications when the undelegation amount is zero - cva = NewContinuousVestingAccount(&bacc, origCoins, now.Unix(), endTime.Unix()) + cva = types.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) require.Panics(t, func() { cva.TrackUndelegation(sdk.Coins{sdk.NewInt64Coin(stakeDenom, 0)}) @@ -168,7 +169,7 @@ func TestTrackUndelegationContVestingAcc(t *testing.T) { require.Nil(t, cva.DelegatedVesting) // vest 50% and delegate to two validators - cva = NewContinuousVestingAccount(&bacc, origCoins, now.Unix(), endTime.Unix()) + cva = types.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) cva.TrackDelegation(now.Add(12*time.Hour), origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) cva.TrackDelegation(now.Add(12*time.Hour), origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) @@ -187,12 +188,12 @@ func TestGetVestedCoinsDelVestingAcc(t *testing.T) { now := tmtime.Now() endTime := now.Add(24 * time.Hour) - _, _, addr := KeyTestPubAddr() + _, _, addr := authtypes.KeyTestPubAddr() origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) // require no coins are vested until schedule maturation - dva := NewDelayedVestingAccount(&bacc, origCoins, endTime.Unix()) + dva := types.NewDelayedVestingAccount(bacc, origCoins, endTime.Unix()) vestedCoins := dva.GetVestedCoins(now) require.Nil(t, vestedCoins) @@ -205,12 +206,12 @@ func TestGetVestingCoinsDelVestingAcc(t *testing.T) { now := tmtime.Now() endTime := now.Add(24 * time.Hour) - _, _, addr := KeyTestPubAddr() + _, _, addr := authtypes.KeyTestPubAddr() origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) // require all coins vesting at the beginning of the schedule - dva := NewDelayedVestingAccount(&bacc, origCoins, endTime.Unix()) + dva := types.NewDelayedVestingAccount(bacc, origCoins, endTime.Unix()) vestingCoins := dva.GetVestingCoins(now) require.Equal(t, origCoins, vestingCoins) @@ -223,13 +224,13 @@ func TestSpendableCoinsDelVestingAcc(t *testing.T) { now := tmtime.Now() endTime := now.Add(24 * time.Hour) - _, _, addr := KeyTestPubAddr() + _, _, addr := authtypes.KeyTestPubAddr() origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) // require that all coins are locked in the beginning of the vesting // schedule - dva := NewDelayedVestingAccount(&bacc, origCoins, endTime.Unix()) + dva := types.NewDelayedVestingAccount(bacc, origCoins, endTime.Unix()) lockedCoins := dva.LockedCoins(now) require.True(t, lockedCoins.IsEqual(origCoins)) @@ -260,31 +261,31 @@ func TestTrackDelegationDelVestingAcc(t *testing.T) { now := tmtime.Now() endTime := now.Add(24 * time.Hour) - _, _, addr := KeyTestPubAddr() + _, _, addr := authtypes.KeyTestPubAddr() origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) // require the ability to delegate all vesting coins - dva := NewDelayedVestingAccount(&bacc, origCoins, endTime.Unix()) + dva := types.NewDelayedVestingAccount(bacc, origCoins, endTime.Unix()) dva.TrackDelegation(now, origCoins, origCoins) require.Equal(t, origCoins, dva.DelegatedVesting) require.Nil(t, dva.DelegatedFree) // require the ability to delegate all vested coins - dva = NewDelayedVestingAccount(&bacc, origCoins, endTime.Unix()) + dva = types.NewDelayedVestingAccount(bacc, origCoins, endTime.Unix()) dva.TrackDelegation(endTime, origCoins, origCoins) require.Nil(t, dva.DelegatedVesting) require.Equal(t, origCoins, dva.DelegatedFree) // require the ability to delegate all coins half way through the vesting // schedule - dva = NewDelayedVestingAccount(&bacc, origCoins, endTime.Unix()) + dva = types.NewDelayedVestingAccount(bacc, origCoins, endTime.Unix()) dva.TrackDelegation(now.Add(12*time.Hour), origCoins, origCoins) require.Equal(t, origCoins, dva.DelegatedVesting) require.Nil(t, dva.DelegatedFree) // require no modifications when delegation amount is zero or not enough funds - dva = NewDelayedVestingAccount(&bacc, origCoins, endTime.Unix()) + dva = types.NewDelayedVestingAccount(bacc, origCoins, endTime.Unix()) require.Panics(t, func() { dva.TrackDelegation(endTime, origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 1000000)}) @@ -297,26 +298,26 @@ func TestTrackUndelegationDelVestingAcc(t *testing.T) { now := tmtime.Now() endTime := now.Add(24 * time.Hour) - _, _, addr := KeyTestPubAddr() + _, _, addr := authtypes.KeyTestPubAddr() origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) // require the ability to undelegate all vesting coins - dva := NewDelayedVestingAccount(&bacc, origCoins, endTime.Unix()) + dva := types.NewDelayedVestingAccount(bacc, origCoins, endTime.Unix()) dva.TrackDelegation(now, origCoins, origCoins) dva.TrackUndelegation(origCoins) require.Nil(t, dva.DelegatedFree) require.Nil(t, dva.DelegatedVesting) // require the ability to undelegate all vested coins - dva = NewDelayedVestingAccount(&bacc, origCoins, endTime.Unix()) + dva = types.NewDelayedVestingAccount(bacc, origCoins, endTime.Unix()) dva.TrackDelegation(endTime, origCoins, origCoins) dva.TrackUndelegation(origCoins) require.Nil(t, dva.DelegatedFree) require.Nil(t, dva.DelegatedVesting) // require no modifications when the undelegation amount is zero - dva = NewDelayedVestingAccount(&bacc, origCoins, endTime.Unix()) + dva = types.NewDelayedVestingAccount(bacc, origCoins, endTime.Unix()) require.Panics(t, func() { dva.TrackUndelegation(sdk.Coins{sdk.NewInt64Coin(stakeDenom, 0)}) @@ -325,7 +326,7 @@ func TestTrackUndelegationDelVestingAcc(t *testing.T) { require.Nil(t, dva.DelegatedVesting) // vest 50% and delegate to two validators - dva = NewDelayedVestingAccount(&bacc, origCoins, endTime.Unix()) + dva = types.NewDelayedVestingAccount(bacc, origCoins, endTime.Unix()) dva.TrackDelegation(now.Add(12*time.Hour), origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) dva.TrackDelegation(now.Add(12*time.Hour), origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) @@ -344,16 +345,16 @@ func TestTrackUndelegationDelVestingAcc(t *testing.T) { func TestGetVestedCoinsPeriodicVestingAcc(t *testing.T) { now := tmtime.Now() endTime := now.Add(24 * time.Hour) - periods := Periods{ - Period{Length: int64(12 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}}, - Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, - Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, + periods := types.Periods{ + types.Period{Length: int64(12 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}}, + types.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, + types.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, } - _, _, addr := KeyTestPubAddr() + _, _, addr := authtypes.KeyTestPubAddr() origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) - pva := NewPeriodicVestingAccount(&bacc, origCoins, now.Unix(), periods) + pva := types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) // require no coins vested at the beginning of the vesting schedule vestedCoins := pva.GetVestedCoins(now) @@ -389,17 +390,17 @@ func TestGetVestedCoinsPeriodicVestingAcc(t *testing.T) { func TestGetVestingCoinsPeriodicVestingAcc(t *testing.T) { now := tmtime.Now() endTime := now.Add(24 * time.Hour) - periods := Periods{ - Period{Length: int64(12 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}}, - Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, - Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, + periods := types.Periods{ + types.Period{Length: int64(12 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}}, + types.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, + types.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, } - _, _, addr := KeyTestPubAddr() + _, _, addr := authtypes.KeyTestPubAddr() origCoins := sdk.Coins{ sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) - pva := NewPeriodicVestingAccount(&bacc, origCoins, now.Unix(), periods) + pva := types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) // require all coins vesting at the beginning of the vesting schedule vestingCoins := pva.GetVestingCoins(now) @@ -429,17 +430,17 @@ func TestGetVestingCoinsPeriodicVestingAcc(t *testing.T) { func TestSpendableCoinsPeriodicVestingAcc(t *testing.T) { now := tmtime.Now() endTime := now.Add(24 * time.Hour) - periods := Periods{ - Period{Length: int64(12 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}}, - Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, - Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, + periods := types.Periods{ + types.Period{Length: int64(12 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}}, + types.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, + types.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, } - _, _, addr := KeyTestPubAddr() + _, _, addr := authtypes.KeyTestPubAddr() origCoins := sdk.Coins{ sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) - pva := NewPeriodicVestingAccount(&bacc, origCoins, now.Unix(), periods) + pva := types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) // require that there exist no spendable coins at the beginning of the // vesting schedule @@ -464,44 +465,44 @@ func TestSpendableCoinsPeriodicVestingAcc(t *testing.T) { func TestTrackDelegationPeriodicVestingAcc(t *testing.T) { now := tmtime.Now() endTime := now.Add(24 * time.Hour) - periods := Periods{ - Period{Length: int64(12 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}}, - Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, - Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, + periods := types.Periods{ + types.Period{Length: int64(12 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}}, + types.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, + types.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, } - _, _, addr := KeyTestPubAddr() + _, _, addr := authtypes.KeyTestPubAddr() origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) // require the ability to delegate all vesting coins - pva := NewPeriodicVestingAccount(&bacc, origCoins, now.Unix(), periods) + pva := types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) pva.TrackDelegation(now, origCoins, origCoins) require.Equal(t, origCoins, pva.DelegatedVesting) require.Nil(t, pva.DelegatedFree) // require the ability to delegate all vested coins - pva = NewPeriodicVestingAccount(&bacc, origCoins, now.Unix(), periods) + pva = types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) pva.TrackDelegation(endTime, origCoins, origCoins) require.Nil(t, pva.DelegatedVesting) require.Equal(t, origCoins, pva.DelegatedFree) // delegate half of vesting coins - pva = NewPeriodicVestingAccount(&bacc, origCoins, now.Unix(), periods) + pva = types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) pva.TrackDelegation(now, origCoins, periods[0].Amount) // require that all delegated coins are delegated vesting require.Equal(t, pva.DelegatedVesting, periods[0].Amount) require.Nil(t, pva.DelegatedFree) // delegate 75% of coins, split between vested and vesting - pva = NewPeriodicVestingAccount(&bacc, origCoins, now.Unix(), periods) + pva = types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) pva.TrackDelegation(now.Add(12*time.Hour), origCoins, periods[0].Amount.Add(periods[1].Amount...)) // require that the maximum possible amount of vesting coins are chosen for delegation. require.Equal(t, pva.DelegatedFree, periods[1].Amount) require.Equal(t, pva.DelegatedVesting, periods[0].Amount) // require the ability to delegate all vesting coins (50%) and all vested coins (50%) - pva = NewPeriodicVestingAccount(&bacc, origCoins, now.Unix(), periods) + pva = types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) pva.TrackDelegation(now.Add(12*time.Hour), origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) require.Equal(t, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}, pva.DelegatedVesting) require.Nil(t, pva.DelegatedFree) @@ -511,7 +512,7 @@ func TestTrackDelegationPeriodicVestingAcc(t *testing.T) { require.Equal(t, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}, pva.DelegatedFree) // require no modifications when delegation amount is zero or not enough funds - pva = NewPeriodicVestingAccount(&bacc, origCoins, now.Unix(), periods) + pva = types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) require.Panics(t, func() { pva.TrackDelegation(endTime, origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 1000000)}) }) @@ -522,25 +523,25 @@ func TestTrackDelegationPeriodicVestingAcc(t *testing.T) { func TestTrackUndelegationPeriodicVestingAcc(t *testing.T) { now := tmtime.Now() endTime := now.Add(24 * time.Hour) - periods := Periods{ - Period{Length: int64(12 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}}, - Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, - Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, + periods := types.Periods{ + types.Period{Length: int64(12 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}}, + types.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, + types.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, } - _, _, addr := KeyTestPubAddr() + _, _, addr := authtypes.KeyTestPubAddr() origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) // require the ability to undelegate all vesting coins at the beginning of vesting - pva := NewPeriodicVestingAccount(&bacc, origCoins, now.Unix(), periods) + pva := types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) pva.TrackDelegation(now, origCoins, origCoins) pva.TrackUndelegation(origCoins) require.Nil(t, pva.DelegatedFree) require.Nil(t, pva.DelegatedVesting) // require the ability to undelegate all vested coins at the end of vesting - pva = NewPeriodicVestingAccount(&bacc, origCoins, now.Unix(), periods) + pva = types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) pva.TrackDelegation(endTime, origCoins, origCoins) pva.TrackUndelegation(origCoins) @@ -548,14 +549,14 @@ func TestTrackUndelegationPeriodicVestingAcc(t *testing.T) { require.Nil(t, pva.DelegatedVesting) // require the ability to undelegate half of coins - pva = NewPeriodicVestingAccount(&bacc, origCoins, now.Unix(), periods) + pva = types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) pva.TrackDelegation(endTime, origCoins, periods[0].Amount) pva.TrackUndelegation(periods[0].Amount) require.Nil(t, pva.DelegatedFree) require.Nil(t, pva.DelegatedVesting) // require no modifications when the undelegation amount is zero - pva = NewPeriodicVestingAccount(&bacc, origCoins, now.Unix(), periods) + pva = types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) require.Panics(t, func() { pva.TrackUndelegation(sdk.Coins{sdk.NewInt64Coin(stakeDenom, 0)}) @@ -564,7 +565,7 @@ func TestTrackUndelegationPeriodicVestingAcc(t *testing.T) { require.Nil(t, pva.DelegatedVesting) // vest 50% and delegate to two validators - pva = NewPeriodicVestingAccount(&bacc, origCoins, now.Unix(), periods) + pva = types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) pva.TrackDelegation(now.Add(12*time.Hour), origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) pva.TrackDelegation(now.Add(12*time.Hour), origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) @@ -579,42 +580,12 @@ func TestTrackUndelegationPeriodicVestingAcc(t *testing.T) { require.Equal(t, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 25)}, pva.DelegatedVesting) } -// TODO: Move test to bank -// func TestNewBaseVestingAccount(t *testing.T) { -// pubkey := secp256k1.GenPrivKey().PubKey() -// addr := sdk.AccAddress(pubkey.Address()) -// _, err := NewBaseVestingAccount( -// authtypes.NewBaseAccount(addr, sdk.NewCoins(), pubkey, 0, 0), -// sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)}, 100, -// ) -// require.Equal(t, errors.New("vesting amount cannot be greater than total amount"), err) - -// _, err = NewBaseVestingAccount( -// authtypes.NewBaseAccount(addr, sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 10)), pubkey, 0, 0), -// sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)}, 100, -// ) -// require.Equal(t, errors.New("vesting amount cannot be greater than total amount"), err) - -// _, err = NewBaseVestingAccount( -// authtypes.NewBaseAccount(addr, sdk.NewCoins(sdk.NewInt64Coin("uatom", 50), sdk.NewInt64Coin("eth", 50)), pubkey, 0, 0), -// sdk.NewCoins(sdk.NewInt64Coin("uatom", 100), sdk.NewInt64Coin("eth", 20)), 100, -// ) -// require.Equal(t, errors.New("vesting amount cannot be greater than total amount"), err) - -// _, err = NewBaseVestingAccount( -// authtypes.NewBaseAccount(addr, sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)}, pubkey, 0, 0), -// sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)}, 100, -// ) -// require.NoError(t, err) - -// } - func TestGenesisAccountValidate(t *testing.T) { pubkey := secp256k1.GenPrivKey().PubKey() addr := sdk.AccAddress(pubkey.Address()) baseAcc := authtypes.NewBaseAccount(addr, pubkey, 0, 0) initialVesting := sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)) - baseVestingWithCoins := NewBaseVestingAccount(baseAcc, initialVesting, 100) + baseVestingWithCoins := types.NewBaseVestingAccount(baseAcc, initialVesting, 100) tests := []struct { name string acc authexported.GenesisAccount @@ -637,31 +608,31 @@ func TestGenesisAccountValidate(t *testing.T) { }, { "valid continuous vesting account", - NewContinuousVestingAccount(baseAcc, initialVesting, 100, 200), + types.NewContinuousVestingAccount(baseAcc, initialVesting, 100, 200), nil, }, { "invalid vesting times", - NewContinuousVestingAccount(baseAcc, initialVesting, 1654668078, 1554668078), + types.NewContinuousVestingAccount(baseAcc, initialVesting, 1654668078, 1554668078), errors.New("vesting start-time cannot be before end-time"), }, { "valid periodic vesting account", - NewPeriodicVestingAccount(baseAcc, initialVesting, 0, Periods{Period{Length: int64(100), Amount: sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)}}}), + types.NewPeriodicVestingAccount(baseAcc, initialVesting, 0, types.Periods{types.Period{Length: int64(100), Amount: sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)}}}), nil, }, { "invalid vesting period lengths", - NewPeriodicVestingAccountRaw( + types.NewPeriodicVestingAccountRaw( baseVestingWithCoins, - 0, Periods{Period{Length: int64(50), Amount: sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)}}}), + 0, types.Periods{types.Period{Length: int64(50), Amount: sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)}}}), errors.New("vesting end time does not match length of all vesting periods"), }, { "invalid vesting period amounts", - NewPeriodicVestingAccountRaw( + types.NewPeriodicVestingAccountRaw( baseVestingWithCoins, - 0, Periods{Period{Length: int64(100), Amount: sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 25)}}}), + 0, types.Periods{types.Period{Length: int64(100), Amount: sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 25)}}}), errors.New("original vesting coins does not match the sum of all coins in vesting periods"), }, } @@ -680,7 +651,7 @@ func TestBaseVestingAccountJSON(t *testing.T) { coins := sdk.NewCoins(sdk.NewInt64Coin("test", 5)) baseAcc := authtypes.NewBaseAccount(addr, pubkey, 10, 50) - acc := NewBaseVestingAccount(baseAcc, coins, time.Now().Unix()) + acc := types.NewBaseVestingAccount(baseAcc, coins, time.Now().Unix()) bz, err := json.Marshal(acc) require.NoError(t, err) @@ -689,19 +660,41 @@ func TestBaseVestingAccountJSON(t *testing.T) { require.NoError(t, err) require.Equal(t, string(bz1), string(bz)) - var a BaseVestingAccount + var a types.BaseVestingAccount require.NoError(t, json.Unmarshal(bz, &a)) require.Equal(t, acc.String(), a.String()) } +func TestContinuousVestingAccountMarshal(t *testing.T) { + pubkey := secp256k1.GenPrivKey().PubKey() + addr := sdk.AccAddress(pubkey.Address()) + coins := sdk.NewCoins(sdk.NewInt64Coin("test", 5)) + baseAcc := authtypes.NewBaseAccount(addr, pubkey, 10, 50) + + baseVesting := types.NewBaseVestingAccount(baseAcc, coins, time.Now().Unix()) + acc := types.NewContinuousVestingAccountRaw(baseVesting, baseVesting.EndTime) + + bz, err := appCodec.MarshalAccount(acc) + require.Nil(t, err) + + acc2, err := appCodec.UnmarshalAccount(bz) + require.Nil(t, err) + require.IsType(t, &types.ContinuousVestingAccount{}, acc2) + require.Equal(t, acc.String(), acc2.String()) + + // error on bad bytes + _, err = appCodec.UnmarshalAccount(bz[:len(bz)/2]) + require.NotNil(t, err) +} + func TestContinuousVestingAccountJSON(t *testing.T) { pubkey := secp256k1.GenPrivKey().PubKey() addr := sdk.AccAddress(pubkey.Address()) coins := sdk.NewCoins(sdk.NewInt64Coin("test", 5)) baseAcc := authtypes.NewBaseAccount(addr, pubkey, 10, 50) - baseVesting := NewBaseVestingAccount(baseAcc, coins, time.Now().Unix()) - acc := NewContinuousVestingAccountRaw(baseVesting, baseVesting.EndTime) + baseVesting := types.NewBaseVestingAccount(baseAcc, coins, time.Now().Unix()) + acc := types.NewContinuousVestingAccountRaw(baseVesting, baseVesting.EndTime) bz, err := json.Marshal(acc) require.NoError(t, err) @@ -710,18 +703,39 @@ func TestContinuousVestingAccountJSON(t *testing.T) { require.NoError(t, err) require.Equal(t, string(bz1), string(bz)) - var a ContinuousVestingAccount + var a types.ContinuousVestingAccount require.NoError(t, json.Unmarshal(bz, &a)) require.Equal(t, acc.String(), a.String()) } +func TestPeriodicVestingAccountMarshal(t *testing.T) { + pubkey := secp256k1.GenPrivKey().PubKey() + addr := sdk.AccAddress(pubkey.Address()) + coins := sdk.NewCoins(sdk.NewInt64Coin("test", 5)) + baseAcc := authtypes.NewBaseAccount(addr, pubkey, 10, 50) + + acc := types.NewPeriodicVestingAccount(baseAcc, coins, time.Now().Unix(), types.Periods{types.Period{3600, coins}}) + + bz, err := appCodec.MarshalAccount(acc) + require.Nil(t, err) + + acc2, err := appCodec.UnmarshalAccount(bz) + require.Nil(t, err) + require.IsType(t, &types.PeriodicVestingAccount{}, acc2) + require.Equal(t, acc.String(), acc2.String()) + + // error on bad bytes + _, err = appCodec.UnmarshalAccount(bz[:len(bz)/2]) + require.NotNil(t, err) +} + func TestPeriodicVestingAccountJSON(t *testing.T) { pubkey := secp256k1.GenPrivKey().PubKey() addr := sdk.AccAddress(pubkey.Address()) coins := sdk.NewCoins(sdk.NewInt64Coin("test", 5)) baseAcc := authtypes.NewBaseAccount(addr, pubkey, 10, 50) - acc := NewPeriodicVestingAccount(baseAcc, coins, time.Now().Unix(), Periods{Period{3600, coins}}) + acc := types.NewPeriodicVestingAccount(baseAcc, coins, time.Now().Unix(), types.Periods{types.Period{3600, coins}}) bz, err := json.Marshal(acc) require.NoError(t, err) @@ -730,18 +744,39 @@ func TestPeriodicVestingAccountJSON(t *testing.T) { require.NoError(t, err) require.Equal(t, string(bz1), string(bz)) - var a PeriodicVestingAccount + var a types.PeriodicVestingAccount require.NoError(t, json.Unmarshal(bz, &a)) require.Equal(t, acc.String(), a.String()) } +func TestDelayedVestingAccountMarshal(t *testing.T) { + pubkey := secp256k1.GenPrivKey().PubKey() + addr := sdk.AccAddress(pubkey.Address()) + coins := sdk.NewCoins(sdk.NewInt64Coin("test", 5)) + baseAcc := authtypes.NewBaseAccount(addr, pubkey, 10, 50) + + acc := types.NewDelayedVestingAccount(baseAcc, coins, time.Now().Unix()) + + bz, err := appCodec.MarshalAccount(acc) + require.Nil(t, err) + + acc2, err := appCodec.UnmarshalAccount(bz) + require.Nil(t, err) + require.IsType(t, &types.DelayedVestingAccount{}, acc2) + require.Equal(t, acc.String(), acc2.String()) + + // error on bad bytes + _, err = appCodec.UnmarshalAccount(bz[:len(bz)/2]) + require.NotNil(t, err) +} + func TestDelayedVestingAccountJSON(t *testing.T) { pubkey := secp256k1.GenPrivKey().PubKey() addr := sdk.AccAddress(pubkey.Address()) coins := sdk.NewCoins(sdk.NewInt64Coin("test", 5)) baseAcc := authtypes.NewBaseAccount(addr, pubkey, 10, 50) - acc := NewDelayedVestingAccount(baseAcc, coins, time.Now().Unix()) + acc := types.NewDelayedVestingAccount(baseAcc, coins, time.Now().Unix()) bz, err := json.Marshal(acc) require.NoError(t, err) @@ -750,7 +785,7 @@ func TestDelayedVestingAccountJSON(t *testing.T) { require.NoError(t, err) require.Equal(t, string(bz1), string(bz)) - var a DelayedVestingAccount + var a types.DelayedVestingAccount require.NoError(t, json.Unmarshal(bz, &a)) require.Equal(t, acc.String(), a.String()) } diff --git a/x/bank/app_test.go b/x/bank/app_test.go index e124baaeef7f..46a33d3f62f6 100644 --- a/x/bank/app_test.go +++ b/x/bank/app_test.go @@ -356,7 +356,7 @@ func TestMsgMultiSendDependent(t *testing.T) { err := acc2.SetAccountNumber(1) require.NoError(t, err) - genAccs := []authexported.GenesisAccount{&acc1, &acc2} + genAccs := []authexported.GenesisAccount{acc1, acc2} app := simapp.SetupWithGenesisAccounts(genAccs) ctx := app.BaseApp.NewContext(false, abci.Header{}) diff --git a/x/bank/internal/keeper/keeper_test.go b/x/bank/internal/keeper/keeper_test.go index fbe41870f7bd..d71f1274f1d2 100644 --- a/x/bank/internal/keeper/keeper_test.go +++ b/x/bank/internal/keeper/keeper_test.go @@ -171,7 +171,7 @@ func (suite *IntegrationTestSuite) TestValidateBalance() { suite.Require().NoError(app.BankKeeper.ValidateBalance(ctx, addr1)) bacc := auth.NewBaseAccountWithAddress(addr2) - vacc := vesting.NewContinuousVestingAccount(&bacc, balances.Add(balances...), now.Unix(), endTime.Unix()) + vacc := vesting.NewContinuousVestingAccount(bacc, balances.Add(balances...), now.Unix(), endTime.Unix()) app.AccountKeeper.SetAccount(ctx, vacc) suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr2, balances)) @@ -392,7 +392,7 @@ func (suite *IntegrationTestSuite) TestSpendableCoins() { macc := app.AccountKeeper.NewAccountWithAddress(ctx, addrModule) bacc := auth.NewBaseAccountWithAddress(addr1) - vacc := vesting.NewContinuousVestingAccount(&bacc, origCoins, ctx.BlockHeader().Time.Unix(), endTime.Unix()) + vacc := vesting.NewContinuousVestingAccount(bacc, origCoins, ctx.BlockHeader().Time.Unix(), endTime.Unix()) acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr2) app.AccountKeeper.SetAccount(ctx, macc) @@ -421,7 +421,7 @@ func (suite *IntegrationTestSuite) TestVestingAccountSend() { addr2 := sdk.AccAddress([]byte("addr2")) bacc := auth.NewBaseAccountWithAddress(addr1) - vacc := vesting.NewContinuousVestingAccount(&bacc, origCoins, now.Unix(), endTime.Unix()) + vacc := vesting.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) app.AccountKeeper.SetAccount(ctx, vacc) suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, origCoins)) @@ -454,7 +454,7 @@ func (suite *IntegrationTestSuite) TestPeriodicVestingAccountSend() { } bacc := auth.NewBaseAccountWithAddress(addr1) - vacc := vesting.NewPeriodicVestingAccount(&bacc, origCoins, ctx.BlockHeader().Time.Unix(), periods) + vacc := vesting.NewPeriodicVestingAccount(bacc, origCoins, ctx.BlockHeader().Time.Unix(), periods) app.AccountKeeper.SetAccount(ctx, vacc) suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, origCoins)) @@ -484,7 +484,7 @@ func (suite *IntegrationTestSuite) TestVestingAccountReceive() { addr2 := sdk.AccAddress([]byte("addr2")) bacc := auth.NewBaseAccountWithAddress(addr1) - vacc := vesting.NewContinuousVestingAccount(&bacc, origCoins, ctx.BlockHeader().Time.Unix(), endTime.Unix()) + vacc := vesting.NewContinuousVestingAccount(bacc, origCoins, ctx.BlockHeader().Time.Unix(), endTime.Unix()) acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr2) app.AccountKeeper.SetAccount(ctx, vacc) @@ -523,7 +523,7 @@ func (suite *IntegrationTestSuite) TestPeriodicVestingAccountReceive() { vesting.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin("stake", 25)}}, } - vacc := vesting.NewPeriodicVestingAccount(&bacc, origCoins, ctx.BlockHeader().Time.Unix(), periods) + vacc := vesting.NewPeriodicVestingAccount(bacc, origCoins, ctx.BlockHeader().Time.Unix(), periods) acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr2) app.AccountKeeper.SetAccount(ctx, vacc) @@ -560,7 +560,7 @@ func (suite *IntegrationTestSuite) TestDelegateCoins() { macc := app.AccountKeeper.NewAccountWithAddress(ctx, addrModule) // we don't need to define an actual module account bc we just need the address for testing acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr2) bacc := auth.NewBaseAccountWithAddress(addr1) - vacc := vesting.NewContinuousVestingAccount(&bacc, origCoins, ctx.BlockHeader().Time.Unix(), endTime.Unix()) + vacc := vesting.NewContinuousVestingAccount(bacc, origCoins, ctx.BlockHeader().Time.Unix(), endTime.Unix()) app.AccountKeeper.SetAccount(ctx, vacc) app.AccountKeeper.SetAccount(ctx, acc) @@ -620,7 +620,7 @@ func (suite *IntegrationTestSuite) TestUndelegateCoins() { bacc := auth.NewBaseAccountWithAddress(addr1) macc := app.AccountKeeper.NewAccountWithAddress(ctx, addrModule) // we don't need to define an actual module account bc we just need the address for testing - vacc := vesting.NewContinuousVestingAccount(&bacc, origCoins, ctx.BlockHeader().Time.Unix(), endTime.Unix()) + vacc := vesting.NewContinuousVestingAccount(bacc, origCoins, ctx.BlockHeader().Time.Unix(), endTime.Unix()) acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr2) app.AccountKeeper.SetAccount(ctx, vacc) diff --git a/x/bank/module.go b/x/bank/module.go index 72afda68622c..dfde67f4a85e 100644 --- a/x/bank/module.go +++ b/x/bank/module.go @@ -39,14 +39,14 @@ func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) { RegisterCodec(cdc) } // DefaultGenesis returns default genesis state as raw bytes for the bank // module. -func (AppModuleBasic) DefaultGenesis() json.RawMessage { - return ModuleCdc.MustMarshalJSON(DefaultGenesisState()) +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { + return cdc.MustMarshalJSON(DefaultGenesisState()) } // ValidateGenesis performs genesis state validation for the bank module. -func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, bz json.RawMessage) error { var data GenesisState - if err := ModuleCdc.UnmarshalJSON(bz, &data); err != nil { + if err := cdc.UnmarshalJSON(bz, &data); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", ModuleName, err) } @@ -111,18 +111,18 @@ func (am AppModule) NewQuerierHandler() sdk.Querier { // InitGenesis performs genesis initialization for the bank module. It returns // no validator updates. -func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate { +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data json.RawMessage) []abci.ValidatorUpdate { var genesisState GenesisState - ModuleCdc.MustUnmarshalJSON(data, &genesisState) + cdc.MustUnmarshalJSON(data, &genesisState) InitGenesis(ctx, am.keeper, genesisState) return []abci.ValidatorUpdate{} } // ExportGenesis returns the exported genesis state as raw bytes for the bank // module. -func (am AppModule) ExportGenesis(ctx sdk.Context) json.RawMessage { +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json.RawMessage { gs := ExportGenesis(ctx, am.keeper) - return ModuleCdc.MustMarshalJSON(gs) + return cdc.MustMarshalJSON(gs) } // BeginBlock performs a no-op. diff --git a/x/crisis/internal/types/codec.go b/x/crisis/internal/types/codec.go index fc9178eb386b..b7906953cf69 100644 --- a/x/crisis/internal/types/codec.go +++ b/x/crisis/internal/types/codec.go @@ -4,32 +4,26 @@ import ( "github.com/cosmos/cosmos-sdk/codec" ) -type Codec struct { - codec.Marshaler - - // Keep reference to the amino codec to allow backwards compatibility along - // with type, and interface registration. - amino *codec.Codec -} - -func NewCodec(amino *codec.Codec) *Codec { - return &Codec{Marshaler: codec.NewHybridCodec(amino), amino: amino} -} - -// ---------------------------------------------------------------------------- - -// RegisterCodec registers all the necessary crisis module concrete types and -// interfaces with the provided codec reference. +// RegisterCodec registers the necessary x/crisis interfaces and concrete types +// on the provided Amino codec. These types are used for Amino JSON serialization. func RegisterCodec(cdc *codec.Codec) { cdc.RegisterConcrete(MsgVerifyInvariant{}, "cosmos-sdk/MsgVerifyInvariant", nil) } -// ModuleCdc defines a crisis module global Amino codec. -var ModuleCdc *Codec +var ( + amino = codec.New() + + // ModuleCdc references the global x/crisis module codec. Note, the codec should + // ONLY be used in certain instances of tests and for JSON encoding as Amino is + // still used for that purpose. + // + // The actual codec used for serialization should be provided to x/crisis and + // defined at the application level. + ModuleCdc = codec.NewHybridCodec(amino) +) func init() { - ModuleCdc = NewCodec(codec.New()) - RegisterCodec(ModuleCdc.amino) - codec.RegisterCrypto(ModuleCdc.amino) - ModuleCdc.amino.Seal() + RegisterCodec(amino) + codec.RegisterCrypto(amino) + amino.Seal() } diff --git a/x/crisis/module.go b/x/crisis/module.go index 1885f69ade9f..dd7ae3677217 100644 --- a/x/crisis/module.go +++ b/x/crisis/module.go @@ -38,14 +38,14 @@ func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) { // DefaultGenesis returns default genesis state as raw bytes for the crisis // module. -func (AppModuleBasic) DefaultGenesis() json.RawMessage { - return types.ModuleCdc.MustMarshalJSON(DefaultGenesisState()) +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { + return cdc.MustMarshalJSON(DefaultGenesisState()) } // ValidateGenesis performs genesis state validation for the crisis module. -func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, bz json.RawMessage) error { var data types.GenesisState - if err := types.ModuleCdc.UnmarshalJSON(bz, &data); err != nil { + if err := cdc.UnmarshalJSON(bz, &data); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", ModuleName, err) } @@ -109,9 +109,9 @@ func (AppModule) NewQuerierHandler() sdk.Querier { return nil } // InitGenesis performs genesis initialization for the crisis module. It returns // no validator updates. -func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate { +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data json.RawMessage) []abci.ValidatorUpdate { var genesisState GenesisState - types.ModuleCdc.MustUnmarshalJSON(data, &genesisState) + cdc.MustUnmarshalJSON(data, &genesisState) InitGenesis(ctx, *am.keeper, genesisState) am.keeper.AssertInvariants(ctx) @@ -120,9 +120,9 @@ func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.Va // ExportGenesis returns the exported genesis state as raw bytes for the crisis // module. -func (am AppModule) ExportGenesis(ctx sdk.Context) json.RawMessage { +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json.RawMessage { gs := ExportGenesis(ctx, *am.keeper) - return types.ModuleCdc.MustMarshalJSON(gs) + return cdc.MustMarshalJSON(gs) } // BeginBlock performs a no-op. diff --git a/x/distribution/alias.go b/x/distribution/alias.go index ba16c5f47f28..47143d995cbb 100644 --- a/x/distribution/alias.go +++ b/x/distribution/alias.go @@ -111,7 +111,6 @@ var ( ParamStoreKeyBonusProposerReward = types.ParamStoreKeyBonusProposerReward ParamStoreKeyWithdrawAddrEnabled = types.ParamStoreKeyWithdrawAddrEnabled ModuleCdc = types.ModuleCdc - NewCodec = types.NewCodec EventTypeSetWithdrawAddress = types.EventTypeSetWithdrawAddress EventTypeRewards = types.EventTypeRewards EventTypeCommission = types.EventTypeCommission @@ -156,5 +155,4 @@ type ( ValidatorSlashEvent = types.ValidatorSlashEvent ValidatorSlashEvents = types.ValidatorSlashEvents ValidatorOutstandingRewards = types.ValidatorOutstandingRewards - Codec = types.Codec ) diff --git a/x/distribution/keeper/test_common.go b/x/distribution/keeper/test_common.go index dca88dfd1671..811c46f553a1 100644 --- a/x/distribution/keeper/test_common.go +++ b/x/distribution/keeper/test_common.go @@ -12,15 +12,15 @@ import ( dbm "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/codec" + simappcodec "github.com/cosmos/cosmos-sdk/simapp/codec" "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank" + "github.com/cosmos/cosmos-sdk/x/distribution/types" "github.com/cosmos/cosmos-sdk/x/params" "github.com/cosmos/cosmos-sdk/x/staking" "github.com/cosmos/cosmos-sdk/x/supply" - - "github.com/cosmos/cosmos-sdk/x/distribution/types" ) //nolint:deadcode,unused @@ -126,10 +126,11 @@ func CreateTestInputAdvanced( blacklistedAddrs[distrAcc.GetAddress().String()] = true cdc := MakeTestCodec() + appCodec := simappcodec.NewAppCodec(cdc) pk := params.NewKeeper(params.ModuleCdc, keyParams, tkeyParams) ctx := sdk.NewContext(ms, abci.Header{ChainID: "foochainid"}, isCheckTx, log.NewNopLogger()) - accountKeeper := auth.NewAccountKeeper(cdc, keyAcc, pk.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount) + accountKeeper := auth.NewAccountKeeper(appCodec, keyAcc, pk.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount) bankKeeper := bank.NewBaseKeeper(cdc, keyBank, accountKeeper, pk.Subspace(bank.DefaultParamspace), blacklistedAddrs) maccPerms := map[string][]string{ auth.FeeCollectorName: nil, @@ -137,7 +138,7 @@ func CreateTestInputAdvanced( staking.NotBondedPoolName: {supply.Burner, supply.Staking}, staking.BondedPoolName: {supply.Burner, supply.Staking}, } - supplyKeeper := supply.NewKeeper(cdc, keySupply, accountKeeper, bankKeeper, maccPerms) + supplyKeeper := supply.NewKeeper(appCodec, keySupply, accountKeeper, bankKeeper, maccPerms) sk := staking.NewKeeper(staking.ModuleCdc, keyStaking, bankKeeper, supplyKeeper, pk.Subspace(staking.DefaultParamspace)) sk.SetParams(ctx, staking.DefaultParams()) diff --git a/x/distribution/module.go b/x/distribution/module.go index 631d9b956fe2..dfa1b10244e9 100644 --- a/x/distribution/module.go +++ b/x/distribution/module.go @@ -43,14 +43,14 @@ func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) { // DefaultGenesis returns default genesis state as raw bytes for the distribution // module. -func (AppModuleBasic) DefaultGenesis() json.RawMessage { - return ModuleCdc.MustMarshalJSON(DefaultGenesisState()) +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { + return cdc.MustMarshalJSON(DefaultGenesisState()) } // ValidateGenesis performs genesis state validation for the distribution module. -func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, bz json.RawMessage) error { var data GenesisState - if err := ModuleCdc.UnmarshalJSON(bz, &data); err != nil { + if err := cdc.UnmarshalJSON(bz, &data); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", ModuleName, err) } @@ -132,18 +132,18 @@ func (am AppModule) NewQuerierHandler() sdk.Querier { // InitGenesis performs genesis initialization for the distribution module. It returns // no validator updates. -func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate { +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data json.RawMessage) []abci.ValidatorUpdate { var genesisState GenesisState - ModuleCdc.MustUnmarshalJSON(data, &genesisState) + cdc.MustUnmarshalJSON(data, &genesisState) InitGenesis(ctx, am.bankKeeper, am.supplyKeeper, am.keeper, genesisState) return []abci.ValidatorUpdate{} } // ExportGenesis returns the exported genesis state as raw bytes for the distribution // module. -func (am AppModule) ExportGenesis(ctx sdk.Context) json.RawMessage { +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json.RawMessage { gs := ExportGenesis(ctx, am.keeper) - return ModuleCdc.MustMarshalJSON(gs) + return cdc.MustMarshalJSON(gs) } // BeginBlock returns the begin blocker for the distribution module. diff --git a/x/distribution/types/codec.go b/x/distribution/types/codec.go index 85412d65c77e..0bc8316abf3b 100644 --- a/x/distribution/types/codec.go +++ b/x/distribution/types/codec.go @@ -4,22 +4,8 @@ import ( "github.com/cosmos/cosmos-sdk/codec" ) -type Codec struct { - codec.Marshaler - - // Keep reference to the amino codec to allow backwards compatibility along - // with type, and interface registration. - amino *codec.Codec -} - -func NewCodec(amino *codec.Codec) *Codec { - return &Codec{Marshaler: codec.NewHybridCodec(amino), amino: amino} -} - -// ---------------------------------------------------------------------------- - -// RegisterCodec registers all the necessary crisis module concrete types and -// interfaces with the provided codec reference. +// RegisterCodec registers the necessary x/distribution interfaces and concrete types +// on the provided Amino codec. These types are used for Amino JSON serialization. func RegisterCodec(cdc *codec.Codec) { cdc.RegisterConcrete(MsgWithdrawDelegatorReward{}, "cosmos-sdk/MsgWithdrawDelegationReward", nil) cdc.RegisterConcrete(MsgWithdrawValidatorCommission{}, "cosmos-sdk/MsgWithdrawValidatorCommission", nil) @@ -27,12 +13,20 @@ func RegisterCodec(cdc *codec.Codec) { cdc.RegisterConcrete(CommunityPoolSpendProposal{}, "cosmos-sdk/CommunityPoolSpendProposal", nil) } -// generic sealed codec to be used throughout module -var ModuleCdc *Codec +var ( + amino = codec.New() + + // ModuleCdc references the global x/distribution module codec. Note, the codec + // should ONLY be used in certain instances of tests and for JSON encoding as Amino + // is still used for that purpose. + // + // The actual codec used for serialization should be provided to x/distribution and + // defined at the application level. + ModuleCdc = codec.NewHybridCodec(amino) +) func init() { - ModuleCdc = NewCodec(codec.New()) - RegisterCodec(ModuleCdc.amino) - codec.RegisterCrypto(ModuleCdc.amino) - ModuleCdc.amino.Seal() + RegisterCodec(amino) + codec.RegisterCrypto(amino) + amino.Seal() } diff --git a/x/evidence/module.go b/x/evidence/module.go index 30b427a95c1d..87900aba30df 100644 --- a/x/evidence/module.go +++ b/x/evidence/module.go @@ -51,14 +51,14 @@ func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) { } // DefaultGenesis returns the evidence module's default genesis state. -func (AppModuleBasic) DefaultGenesis() json.RawMessage { - return ModuleCdc.MustMarshalJSON(DefaultGenesisState()) +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { + return cdc.MustMarshalJSON(DefaultGenesisState()) } // ValidateGenesis performs genesis state validation for the evidence module. -func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, bz json.RawMessage) error { var gs GenesisState - if err := ModuleCdc.UnmarshalJSON(bz, &gs); err != nil { + if err := cdc.UnmarshalJSON(bz, &gs); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", ModuleName, err) } @@ -140,9 +140,9 @@ func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) {} // InitGenesis performs the evidence module's genesis initialization It returns // no validator updates. -func (am AppModule) InitGenesis(ctx sdk.Context, bz json.RawMessage) []abci.ValidatorUpdate { +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, bz json.RawMessage) []abci.ValidatorUpdate { var gs GenesisState - err := ModuleCdc.UnmarshalJSON(bz, &gs) + err := cdc.UnmarshalJSON(bz, &gs) if err != nil { panic(fmt.Sprintf("failed to unmarshal %s genesis state: %s", ModuleName, err)) } @@ -152,8 +152,8 @@ func (am AppModule) InitGenesis(ctx sdk.Context, bz json.RawMessage) []abci.Vali } // ExportGenesis returns the evidence module's exported genesis state as raw JSON bytes. -func (am AppModule) ExportGenesis(ctx sdk.Context) json.RawMessage { - return ModuleCdc.MustMarshalJSON(ExportGenesis(ctx, am.keeper)) +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json.RawMessage { + return cdc.MustMarshalJSON(ExportGenesis(ctx, am.keeper)) } // BeginBlock executes all ABCI BeginBlock logic respective to the evidence module. diff --git a/x/genutil/client/cli/gentx.go b/x/genutil/client/cli/gentx.go index b992f446fe7b..641a6099907f 100644 --- a/x/genutil/client/cli/gentx.go +++ b/x/genutil/client/cli/gentx.go @@ -88,7 +88,7 @@ func GenTxCmd(ctx *server.Context, cdc *codec.Codec, mbm module.BasicManager, sm return errors.Wrap(err, "failed to unmarshal genesis state") } - if err = mbm.ValidateGenesis(genesisState); err != nil { + if err = mbm.ValidateGenesis(cdc, genesisState); err != nil { return errors.Wrap(err, "failed to validate genesis state") } diff --git a/x/genutil/client/cli/init.go b/x/genutil/client/cli/init.go index 618f389da579..0f81c51f7700 100644 --- a/x/genutil/client/cli/init.go +++ b/x/genutil/client/cli/init.go @@ -87,7 +87,7 @@ func InitCmd(ctx *server.Context, cdc codec.JSONMarshaler, mbm module.BasicManag if !viper.GetBool(flagOverwrite) && tmos.FileExists(genFile) { return fmt.Errorf("genesis.json file already exists: %v", genFile) } - appState, err := codec.MarshalJSONIndent(cdc, mbm.DefaultGenesis()) + appState, err := codec.MarshalJSONIndent(cdc, mbm.DefaultGenesis(cdc)) if err != nil { return errors.Wrap(err, "Failed to marshall default genesis state") } diff --git a/x/genutil/client/cli/validate_genesis.go b/x/genutil/client/cli/validate_genesis.go index 6be33bdabf09..70e26f01ebbb 100644 --- a/x/genutil/client/cli/validate_genesis.go +++ b/x/genutil/client/cli/validate_genesis.go @@ -41,7 +41,7 @@ func ValidateGenesisCmd(ctx *server.Context, cdc *codec.Codec, mbm module.BasicM return fmt.Errorf("error unmarshalling genesis doc %s: %s", genesis, err.Error()) } - if err = mbm.ValidateGenesis(genState); err != nil { + if err = mbm.ValidateGenesis(cdc, genState); err != nil { return fmt.Errorf("error validating genesis file %s: %s", genesis, err.Error()) } diff --git a/x/genutil/module.go b/x/genutil/module.go index 31ca1b463523..cedf7171f564 100644 --- a/x/genutil/module.go +++ b/x/genutil/module.go @@ -34,14 +34,14 @@ func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) {} // DefaultGenesis returns default genesis state as raw bytes for the genutil // module. -func (AppModuleBasic) DefaultGenesis() json.RawMessage { - return ModuleCdc.MustMarshalJSON(types.DefaultGenesisState()) +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { + return cdc.MustMarshalJSON(types.DefaultGenesisState()) } // ValidateGenesis performs genesis state validation for the genutil module. -func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, bz json.RawMessage) error { var data GenesisState - if err := ModuleCdc.UnmarshalJSON(bz, &data); err != nil { + if err := cdc.UnmarshalJSON(bz, &data); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", ModuleName, err) } @@ -82,14 +82,14 @@ func NewAppModule(accountKeeper types.AccountKeeper, // InitGenesis performs genesis initialization for the genutil module. It returns // no validator updates. -func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate { +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data json.RawMessage) []abci.ValidatorUpdate { var genesisState GenesisState - ModuleCdc.MustUnmarshalJSON(data, &genesisState) + cdc.MustUnmarshalJSON(data, &genesisState) return InitGenesis(ctx, ModuleCdc, am.stakingKeeper, am.deliverTx, genesisState) } // ExportGenesis returns the exported genesis state as raw bytes for the genutil // module. -func (am AppModule) ExportGenesis(ctx sdk.Context) json.RawMessage { +func (am AppModule) ExportGenesis(_ sdk.Context, _ codec.JSONMarshaler) json.RawMessage { return nil } diff --git a/x/gov/genesis_test.go b/x/gov/genesis_test.go index 5e86d71cf731..133c7c4f3ab3 100644 --- a/x/gov/genesis_test.go +++ b/x/gov/genesis_test.go @@ -52,19 +52,19 @@ func TestImportExportQueues(t *testing.T) { // export the state and import it into a new app govGenState := gov.ExportGenesis(ctx, app.GovKeeper) - - db := dbm.NewMemDB() - app2 := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, 0) genesisState := simapp.NewDefaultGenesisState() genesisState[auth.ModuleName] = app.Codec().MustMarshalJSON(authGenState) genesisState[gov.ModuleName] = app.Codec().MustMarshalJSON(govGenState) - stateBytes, err := codec.MarshalJSONIndent(app2.Codec(), genesisState) + stateBytes, err := codec.MarshalJSONIndent(app.Codec(), genesisState) if err != nil { panic(err) } + db := dbm.NewMemDB() + app2 := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, 0) + app2.InitChain( abci.RequestInitChain{ Validators: []abci.ValidatorUpdate{}, diff --git a/x/gov/keeper/test_common.go b/x/gov/keeper/test_common.go index 42fe87626bcf..13c6fc15da1d 100644 --- a/x/gov/keeper/test_common.go +++ b/x/gov/keeper/test_common.go @@ -1,6 +1,7 @@ -// nolint -package keeper // noalias +package keeper +// noalias +// nolint // DONTCOVER import ( @@ -9,16 +10,15 @@ import ( "testing" "github.com/stretchr/testify/require" - + abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/ed25519" - - abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" tmtypes "github.com/tendermint/tendermint/types" dbm "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/codec" + simappcodec "github.com/cosmos/cosmos-sdk/simapp/codec" "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" @@ -125,7 +125,9 @@ func createTestInput( }, }, ) + cdc := makeTestCodec() + appCodec := simappcodec.NewAppCodec(cdc) maccPerms := map[string][]string{ auth.FeeCollectorName: nil, @@ -147,9 +149,9 @@ func createTestInput( blacklistedAddrs[bondPool.GetAddress().String()] = true pk := params.NewKeeper(params.ModuleCdc, keyParams, tkeyParams) - accountKeeper := auth.NewAccountKeeper(cdc, keyAcc, pk.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount) + accountKeeper := auth.NewAccountKeeper(appCodec, keyAcc, pk.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount) bankKeeper := bank.NewBaseKeeper(cdc, keyBank, accountKeeper, pk.Subspace(bank.DefaultParamspace), blacklistedAddrs) - supplyKeeper := supply.NewKeeper(cdc, keySupply, accountKeeper, bankKeeper, maccPerms) + supplyKeeper := supply.NewKeeper(appCodec, keySupply, accountKeeper, bankKeeper, maccPerms) sk := staking.NewKeeper(staking.ModuleCdc, keyStaking, bankKeeper, supplyKeeper, pk.Subspace(staking.DefaultParamspace)) sk.SetParams(ctx, staking.DefaultParams()) diff --git a/x/gov/module.go b/x/gov/module.go index bd2cabb97e78..5d07091fd1ab 100644 --- a/x/gov/module.go +++ b/x/gov/module.go @@ -54,14 +54,14 @@ func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) { // DefaultGenesis returns default genesis state as raw bytes for the gov // module. -func (AppModuleBasic) DefaultGenesis() json.RawMessage { - return ModuleCdc.MustMarshalJSON(DefaultGenesisState()) +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { + return cdc.MustMarshalJSON(DefaultGenesisState()) } // ValidateGenesis performs genesis state validation for the gov module. -func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, bz json.RawMessage) error { var data GenesisState - if err := ModuleCdc.UnmarshalJSON(bz, &data); err != nil { + if err := cdc.UnmarshalJSON(bz, &data); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) } @@ -149,18 +149,18 @@ func (am AppModule) NewQuerierHandler() sdk.Querier { // InitGenesis performs genesis initialization for the gov module. It returns // no validator updates. -func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate { +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data json.RawMessage) []abci.ValidatorUpdate { var genesisState GenesisState - ModuleCdc.MustUnmarshalJSON(data, &genesisState) + cdc.MustUnmarshalJSON(data, &genesisState) InitGenesis(ctx, am.bankKeeper, am.supplyKeeper, am.keeper, genesisState) return []abci.ValidatorUpdate{} } // ExportGenesis returns the exported genesis state as raw bytes for the gov // module. -func (am AppModule) ExportGenesis(ctx sdk.Context) json.RawMessage { +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json.RawMessage { gs := ExportGenesis(ctx, am.keeper) - return ModuleCdc.MustMarshalJSON(gs) + return cdc.MustMarshalJSON(gs) } // BeginBlock performs a no-op. diff --git a/x/mint/module.go b/x/mint/module.go index 95b171251ee1..53bd8fff13a6 100644 --- a/x/mint/module.go +++ b/x/mint/module.go @@ -41,14 +41,14 @@ func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) {} // DefaultGenesis returns default genesis state as raw bytes for the mint // module. -func (AppModuleBasic) DefaultGenesis() json.RawMessage { - return ModuleCdc.MustMarshalJSON(DefaultGenesisState()) +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { + return cdc.MustMarshalJSON(DefaultGenesisState()) } // ValidateGenesis performs genesis state validation for the mint module. -func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, bz json.RawMessage) error { var data GenesisState - if err := ModuleCdc.UnmarshalJSON(bz, &data); err != nil { + if err := cdc.UnmarshalJSON(bz, &data); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", ModuleName, err) } @@ -111,18 +111,18 @@ func (am AppModule) NewQuerierHandler() sdk.Querier { // InitGenesis performs genesis initialization for the mint module. It returns // no validator updates. -func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate { +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data json.RawMessage) []abci.ValidatorUpdate { var genesisState GenesisState - ModuleCdc.MustUnmarshalJSON(data, &genesisState) + cdc.MustUnmarshalJSON(data, &genesisState) InitGenesis(ctx, am.keeper, genesisState) return []abci.ValidatorUpdate{} } // ExportGenesis returns the exported genesis state as raw bytes for the mint // module. -func (am AppModule) ExportGenesis(ctx sdk.Context) json.RawMessage { +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json.RawMessage { gs := ExportGenesis(ctx, am.keeper) - return ModuleCdc.MustMarshalJSON(gs) + return cdc.MustMarshalJSON(gs) } // BeginBlock returns the begin blocker for the mint module. diff --git a/x/params/module.go b/x/params/module.go index 5817b482b3b8..12005b8bc407 100644 --- a/x/params/module.go +++ b/x/params/module.go @@ -36,10 +36,10 @@ func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) { // DefaultGenesis returns default genesis state as raw bytes for the params // module. -func (AppModuleBasic) DefaultGenesis() json.RawMessage { return nil } +func (AppModuleBasic) DefaultGenesis(_ codec.JSONMarshaler) json.RawMessage { return nil } // ValidateGenesis performs genesis state validation for the params module. -func (AppModuleBasic) ValidateGenesis(_ json.RawMessage) error { return nil } +func (AppModuleBasic) ValidateGenesis(_ codec.JSONMarshaler, _ json.RawMessage) error { return nil } // RegisterRESTRoutes registers the REST routes for the params module. func (AppModuleBasic) RegisterRESTRoutes(_ context.CLIContext, _ *mux.Router) {} diff --git a/x/slashing/internal/keeper/test_common.go b/x/slashing/internal/keeper/test_common.go index 60dc3946043e..8ddd7bd7e1d3 100644 --- a/x/slashing/internal/keeper/test_common.go +++ b/x/slashing/internal/keeper/test_common.go @@ -1,7 +1,8 @@ +package keeper + // nolint:deadcode,unused // DONTCOVER // noalias -package keeper import ( "encoding/hex" @@ -9,7 +10,6 @@ import ( "time" "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/ed25519" @@ -17,6 +17,7 @@ import ( dbm "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/codec" + simappcodec "github.com/cosmos/cosmos-sdk/simapp/codec" "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" @@ -80,6 +81,7 @@ func CreateTestInput(t *testing.T, defaults types.Params) (sdk.Context, bank.Kee ctx := sdk.NewContext(ms, abci.Header{Time: time.Unix(0, 0)}, false, log.NewNopLogger()) cdc := createTestCodec() + appCodec := simappcodec.NewAppCodec(cdc) feeCollectorAcc := supply.NewEmptyModuleAccount(auth.FeeCollectorName) notBondedPool := supply.NewEmptyModuleAccount(staking.NotBondedPoolName, supply.Burner, supply.Staking) @@ -91,7 +93,7 @@ func CreateTestInput(t *testing.T, defaults types.Params) (sdk.Context, bank.Kee blacklistedAddrs[bondPool.GetAddress().String()] = true paramsKeeper := params.NewKeeper(params.ModuleCdc, keyParams, tkeyParams) - accountKeeper := auth.NewAccountKeeper(cdc, keyAcc, paramsKeeper.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount) + accountKeeper := auth.NewAccountKeeper(appCodec, keyAcc, paramsKeeper.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount) bk := bank.NewBaseKeeper(cdc, keyBank, accountKeeper, paramsKeeper.Subspace(bank.DefaultParamspace), blacklistedAddrs) maccPerms := map[string][]string{ @@ -99,7 +101,7 @@ func CreateTestInput(t *testing.T, defaults types.Params) (sdk.Context, bank.Kee staking.NotBondedPoolName: {supply.Burner, supply.Staking}, staking.BondedPoolName: {supply.Burner, supply.Staking}, } - supplyKeeper := supply.NewKeeper(cdc, keySupply, accountKeeper, bk, maccPerms) + supplyKeeper := supply.NewKeeper(appCodec, keySupply, accountKeeper, bk, maccPerms) totalSupply := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, InitTokens.MulRaw(int64(len(Addrs))))) supplyKeeper.SetSupply(ctx, supply.NewSupply(totalSupply)) diff --git a/x/slashing/module.go b/x/slashing/module.go index 4b739ef217e0..3e4c0b7a99e8 100644 --- a/x/slashing/module.go +++ b/x/slashing/module.go @@ -45,14 +45,14 @@ func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) { // DefaultGenesis returns default genesis state as raw bytes for the slashing // module. -func (AppModuleBasic) DefaultGenesis() json.RawMessage { - return ModuleCdc.MustMarshalJSON(DefaultGenesisState()) +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { + return cdc.MustMarshalJSON(DefaultGenesisState()) } // ValidateGenesis performs genesis state validation for the slashing module. -func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, bz json.RawMessage) error { var data GenesisState - if err := ModuleCdc.UnmarshalJSON(bz, &data); err != nil { + if err := cdc.UnmarshalJSON(bz, &data); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) } @@ -127,7 +127,7 @@ func (am AppModule) NewQuerierHandler() sdk.Querier { // InitGenesis performs genesis initialization for the slashing module. It returns // no validator updates. -func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate { +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data json.RawMessage) []abci.ValidatorUpdate { var genesisState GenesisState ModuleCdc.MustUnmarshalJSON(data, &genesisState) InitGenesis(ctx, am.keeper, am.stakingKeeper, genesisState) @@ -136,9 +136,9 @@ func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.Va // ExportGenesis returns the exported genesis state as raw bytes for the slashing // module. -func (am AppModule) ExportGenesis(ctx sdk.Context) json.RawMessage { +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json.RawMessage { gs := ExportGenesis(ctx, am.keeper) - return ModuleCdc.MustMarshalJSON(gs) + return cdc.MustMarshalJSON(gs) } // BeginBlock returns the begin blocker for the slashing module. diff --git a/x/staking/alias.go b/x/staking/alias.go index 445ead018e15..1b7c78772f73 100644 --- a/x/staking/alias.go +++ b/x/staking/alias.go @@ -176,7 +176,6 @@ var ( NewDescription = types.NewDescription // variable aliases - NewCodec = types.NewCodec ModuleCdc = types.ModuleCdc LastValidatorPowerKey = types.LastValidatorPowerKey LastTotalPowerKey = types.LastTotalPowerKey @@ -201,7 +200,6 @@ var ( type ( Keeper = keeper.Keeper - Codec = types.Codec Commission = types.Commission CommissionRates = types.CommissionRates DVPair = types.DVPair diff --git a/x/staking/keeper/test_common.go b/x/staking/keeper/test_common.go index 005cfbfb1ffa..9d97cc873266 100644 --- a/x/staking/keeper/test_common.go +++ b/x/staking/keeper/test_common.go @@ -1,4 +1,6 @@ -package keeper // noalias +package keeper + +// noalias import ( "bytes" @@ -16,6 +18,7 @@ import ( dbm "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/codec" + simappcodec "github.com/cosmos/cosmos-sdk/simapp/codec" "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" @@ -105,7 +108,9 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context }, }, ) + cdc := MakeTestCodec() + appCodec := simappcodec.NewAppCodec(cdc) feeCollectorAcc := supply.NewEmptyModuleAccount(auth.FeeCollectorName) notBondedPool := supply.NewEmptyModuleAccount(types.NotBondedPoolName, supply.Burner, supply.Staking) @@ -119,10 +124,10 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context pk := params.NewKeeper(params.ModuleCdc, keyParams, tkeyParams) accountKeeper := auth.NewAccountKeeper( - cdc, // amino codec - keyAcc, // target store + appCodec, + keyAcc, pk.Subspace(auth.DefaultParamspace), - auth.ProtoBaseAccount, // prototype + auth.ProtoBaseAccount, ) bk := bank.NewBaseKeeper( @@ -138,7 +143,7 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context types.NotBondedPoolName: {supply.Burner, supply.Staking}, types.BondedPoolName: {supply.Burner, supply.Staking}, } - supplyKeeper := supply.NewKeeper(cdc, keySupply, accountKeeper, bk, maccPerms) + supplyKeeper := supply.NewKeeper(appCodec, keySupply, accountKeeper, bk, maccPerms) initTokens := sdk.TokensFromConsensusPower(initPower) initCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initTokens)) diff --git a/x/staking/module.go b/x/staking/module.go index 0c7023a01957..33034842f75d 100644 --- a/x/staking/module.go +++ b/x/staking/module.go @@ -48,14 +48,14 @@ func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) { // DefaultGenesis returns default genesis state as raw bytes for the staking // module. -func (AppModuleBasic) DefaultGenesis() json.RawMessage { - return ModuleCdc.MustMarshalJSON(DefaultGenesisState()) +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { + return cdc.MustMarshalJSON(DefaultGenesisState()) } // ValidateGenesis performs genesis state validation for the staking module. -func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, bz json.RawMessage) error { var data GenesisState - if err := ModuleCdc.UnmarshalJSON(bz, &data); err != nil { + if err := cdc.UnmarshalJSON(bz, &data); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", ModuleName, err) } @@ -154,17 +154,17 @@ func (am AppModule) NewQuerierHandler() sdk.Querier { // InitGenesis performs genesis initialization for the staking module. It returns // no validator updates. -func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate { +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data json.RawMessage) []abci.ValidatorUpdate { var genesisState GenesisState - ModuleCdc.MustUnmarshalJSON(data, &genesisState) + cdc.MustUnmarshalJSON(data, &genesisState) return InitGenesis(ctx, am.keeper, am.accountKeeper, am.bankKeeper, am.supplyKeeper, genesisState) } // ExportGenesis returns the exported genesis state as raw bytes for the staking // module. -func (am AppModule) ExportGenesis(ctx sdk.Context) json.RawMessage { +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json.RawMessage { gs := ExportGenesis(ctx, am.keeper) - return ModuleCdc.MustMarshalJSON(gs) + return cdc.MustMarshalJSON(gs) } // BeginBlock returns the begin blocker for the staking module. diff --git a/x/staking/types/codec.go b/x/staking/types/codec.go index 9832789b6971..940e5ac8a4a2 100644 --- a/x/staking/types/codec.go +++ b/x/staking/types/codec.go @@ -4,22 +4,8 @@ import ( "github.com/cosmos/cosmos-sdk/codec" ) -type Codec struct { - codec.Marshaler - - // Keep reference to the amino codec to allow backwards compatibility along - // with type, and interface registration. - amino *codec.Codec -} - -func NewCodec(amino *codec.Codec) *Codec { - return &Codec{Marshaler: codec.NewHybridCodec(amino), amino: amino} -} - -// ---------------------------------------------------------------------------- - -// RegisterCodec registers all the necessary staking module concrete types and -// interfaces with the provided codec reference. +// RegisterCodec registers the necessary x/staking interfaces and concrete types +// on the provided Amino codec. These types are used for Amino JSON serialization. func RegisterCodec(cdc *codec.Codec) { cdc.RegisterConcrete(MsgCreateValidator{}, "cosmos-sdk/MsgCreateValidator", nil) cdc.RegisterConcrete(MsgEditValidator{}, "cosmos-sdk/MsgEditValidator", nil) @@ -28,13 +14,20 @@ func RegisterCodec(cdc *codec.Codec) { cdc.RegisterConcrete(MsgBeginRedelegate{}, "cosmos-sdk/MsgBeginRedelegate", nil) } -// ModuleCdc defines a staking module global Amino codec. -var ModuleCdc *Codec +var ( + amino = codec.New() -func init() { - ModuleCdc = NewCodec(codec.New()) + // ModuleCdc references the global x/staking module codec. Note, the codec should + // ONLY be used in certain instances of tests and for JSON encoding as Amino is + // still used for that purpose. + // + // The actual codec used for serialization should be provided to x/staking and + // defined at the application level. + ModuleCdc = codec.NewHybridCodec(amino) +) - RegisterCodec(ModuleCdc.amino) - codec.RegisterCrypto(ModuleCdc.amino) - ModuleCdc.amino.Seal() +func init() { + RegisterCodec(amino) + codec.RegisterCrypto(amino) + amino.Seal() } diff --git a/x/supply/alias.go b/x/supply/alias.go index 1138f7c5eee2..40d9c2fbe192 100644 --- a/x/supply/alias.go +++ b/x/supply/alias.go @@ -1,13 +1,11 @@ -// nolint -// autogenerated code using github.com/rigelrozanski/multitool -// aliases generated for the following subdirectories: -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/supply/internal/keeper -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/supply/internal/types package supply +// DONTCOVER +// nolint + import ( - "github.com/cosmos/cosmos-sdk/x/supply/internal/keeper" - "github.com/cosmos/cosmos-sdk/x/supply/internal/types" + "github.com/cosmos/cosmos-sdk/x/supply/keeper" + "github.com/cosmos/cosmos-sdk/x/supply/types" ) const ( @@ -46,4 +44,5 @@ type ( ModuleAccount = types.ModuleAccount GenesisState = types.GenesisState Supply = types.Supply + Codec = types.Codec ) diff --git a/x/supply/client/cli/query.go b/x/supply/client/cli/query.go index 26c4a77cd506..95dd5b7bc589 100644 --- a/x/supply/client/cli/query.go +++ b/x/supply/client/cli/query.go @@ -12,7 +12,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" - "github.com/cosmos/cosmos-sdk/x/supply/internal/types" + "github.com/cosmos/cosmos-sdk/x/supply/types" ) // GetQueryCmd returns the cli query commands for this module diff --git a/x/supply/client/rest/query.go b/x/supply/client/rest/query.go index cea93b50b095..021159dfaf17 100644 --- a/x/supply/client/rest/query.go +++ b/x/supply/client/rest/query.go @@ -8,7 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/types/rest" - "github.com/cosmos/cosmos-sdk/x/supply/internal/types" + "github.com/cosmos/cosmos-sdk/x/supply/types" ) // RegisterRoutes registers staking-related REST handlers to a router diff --git a/x/supply/exported/exported.go b/x/supply/exported/exported.go index e872e1deabd1..cecfc8e20429 100644 --- a/x/supply/exported/exported.go +++ b/x/supply/exported/exported.go @@ -6,7 +6,8 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth/exported" ) -// ModuleAccountI defines an account interface for modules that hold tokens in an escrow +// ModuleAccountI defines an account interface for modules that hold tokens in +// an escrow. type ModuleAccountI interface { exported.Account @@ -19,10 +20,10 @@ type ModuleAccountI interface { // token supply. type SupplyI interface { GetTotal() sdk.Coins - SetTotal(total sdk.Coins) SupplyI + SetTotal(total sdk.Coins) - Inflate(amount sdk.Coins) SupplyI - Deflate(amount sdk.Coins) SupplyI + Inflate(amount sdk.Coins) + Deflate(amount sdk.Coins) String() string ValidateBasic() error diff --git a/x/supply/genesis.go b/x/supply/genesis.go index 17546515cf43..98f0e1f4f714 100644 --- a/x/supply/genesis.go +++ b/x/supply/genesis.go @@ -2,7 +2,7 @@ package supply import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/supply/internal/types" + "github.com/cosmos/cosmos-sdk/x/supply/types" ) // InitGenesis sets supply information for genesis. diff --git a/x/supply/internal/keeper/integration_test.go b/x/supply/internal/keeper/integration_test.go deleted file mode 100644 index be065ea16ae8..000000000000 --- a/x/supply/internal/keeper/integration_test.go +++ /dev/null @@ -1,35 +0,0 @@ -package keeper_test - -import ( - abci "github.com/tendermint/tendermint/abci/types" - - "github.com/cosmos/cosmos-sdk/simapp" - sdk "github.com/cosmos/cosmos-sdk/types" - keep "github.com/cosmos/cosmos-sdk/x/supply/internal/keeper" - "github.com/cosmos/cosmos-sdk/x/supply/internal/types" -) - -var ( - multiPerm = "multiple permissions account" - randomPerm = "random permission" - holder = "holder" -) - -// nolint:deadcode,unused -func createTestApp(isCheckTx bool) (*simapp.SimApp, sdk.Context) { - app := simapp.Setup(isCheckTx) - - // add module accounts to supply keeper - maccPerms := simapp.GetMaccPerms() - maccPerms[holder] = nil - maccPerms[types.Burner] = []string{types.Burner} - maccPerms[types.Minter] = []string{types.Minter} - maccPerms[multiPerm] = []string{types.Burner, types.Minter, types.Staking} - maccPerms[randomPerm] = []string{"random"} - - ctx := app.BaseApp.NewContext(isCheckTx, abci.Header{}) - app.SupplyKeeper = keep.NewKeeper(app.Codec(), app.GetKey(types.StoreKey), app.AccountKeeper, app.BankKeeper, maccPerms) - app.SupplyKeeper.SetSupply(ctx, types.NewSupply(sdk.NewCoins())) - - return app, ctx -} diff --git a/x/supply/internal/keeper/keeper_test.go b/x/supply/internal/keeper/keeper_test.go deleted file mode 100644 index d4ff2849e4ca..000000000000 --- a/x/supply/internal/keeper/keeper_test.go +++ /dev/null @@ -1,38 +0,0 @@ -package keeper_test - -import ( - "testing" - - "github.com/stretchr/testify/require" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/supply/internal/types" -) - -func TestSupply(t *testing.T) { - initialPower := int64(100) - initTokens := sdk.TokensFromConsensusPower(initialPower) - - app, ctx := createTestApp(false) - totalSupply := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initTokens)) - app.SupplyKeeper.SetSupply(ctx, types.NewSupply(totalSupply)) - - total := app.SupplyKeeper.GetSupply(ctx).GetTotal() - - require.Equal(t, totalSupply, total) -} - -func TestValidatePermissions(t *testing.T) { - app, _ := createTestApp(false) - - err := app.SupplyKeeper.ValidatePermissions(multiPermAcc) - require.NoError(t, err) - - err = app.SupplyKeeper.ValidatePermissions(randomPermAcc) - require.NoError(t, err) - - // unregistered permissions - otherAcc := types.NewEmptyModuleAccount("other", "other") - err = app.SupplyKeeper.ValidatePermissions(otherAcc) - require.Error(t, err) -} diff --git a/x/supply/internal/types/codec.go b/x/supply/internal/types/codec.go deleted file mode 100644 index 89bc9a2ffcf3..000000000000 --- a/x/supply/internal/types/codec.go +++ /dev/null @@ -1,24 +0,0 @@ -package types - -import ( - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/x/supply/exported" -) - -// RegisterCodec registers the account types and interface -func RegisterCodec(cdc *codec.Codec) { - cdc.RegisterInterface((*exported.ModuleAccountI)(nil), nil) - cdc.RegisterInterface((*exported.SupplyI)(nil), nil) - cdc.RegisterConcrete(&ModuleAccount{}, "cosmos-sdk/ModuleAccount", nil) - cdc.RegisterConcrete(&Supply{}, "cosmos-sdk/Supply", nil) -} - -// ModuleCdc generic sealed codec to be used throughout module -var ModuleCdc *codec.Codec - -func init() { - cdc := codec.New() - RegisterCodec(cdc) - codec.RegisterCrypto(cdc) - ModuleCdc = cdc.Seal() -} diff --git a/x/supply/internal/keeper/account.go b/x/supply/keeper/account.go similarity index 97% rename from x/supply/internal/keeper/account.go rename to x/supply/keeper/account.go index 312b039be2c5..685308cf6102 100644 --- a/x/supply/internal/keeper/account.go +++ b/x/supply/keeper/account.go @@ -3,7 +3,7 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/supply/exported" - "github.com/cosmos/cosmos-sdk/x/supply/internal/types" + "github.com/cosmos/cosmos-sdk/x/supply/types" ) // GetModuleAddress returns an address based on the module name diff --git a/x/supply/internal/keeper/bank.go b/x/supply/keeper/bank.go similarity index 97% rename from x/supply/internal/keeper/bank.go rename to x/supply/keeper/bank.go index 9117286aaeb6..4213c8b0d8ee 100644 --- a/x/supply/internal/keeper/bank.go +++ b/x/supply/keeper/bank.go @@ -5,7 +5,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/cosmos-sdk/x/supply/internal/types" + "github.com/cosmos/cosmos-sdk/x/supply/types" ) // SendCoinsFromModuleToAccount transfers coins from a ModuleAccount to an AccAddress. @@ -112,7 +112,7 @@ func (k Keeper) MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) err // update total supply supply := k.GetSupply(ctx) - supply = supply.Inflate(amt) + supply.Inflate(amt) k.SetSupply(ctx, supply) @@ -141,7 +141,7 @@ func (k Keeper) BurnCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) err // update total supply supply := k.GetSupply(ctx) - supply = supply.Deflate(amt) + supply.Deflate(amt) k.SetSupply(ctx, supply) logger := k.Logger(ctx) diff --git a/x/supply/internal/keeper/bank_test.go b/x/supply/keeper/bank_test.go similarity index 72% rename from x/supply/internal/keeper/bank_test.go rename to x/supply/keeper/bank_test.go index 5388dc804d49..cb6237147864 100644 --- a/x/supply/internal/keeper/bank_test.go +++ b/x/supply/keeper/bank_test.go @@ -4,13 +4,21 @@ import ( "testing" "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/cosmos/cosmos-sdk/simapp" + simappcodec "github.com/cosmos/cosmos-sdk/simapp/codec" sdk "github.com/cosmos/cosmos-sdk/types" - keep "github.com/cosmos/cosmos-sdk/x/supply/internal/keeper" - "github.com/cosmos/cosmos-sdk/x/supply/internal/types" + keep "github.com/cosmos/cosmos-sdk/x/supply/keeper" + "github.com/cosmos/cosmos-sdk/x/supply/types" ) -const initialPower = int64(100) +const ( + initialPower = int64(100) + holder = "holder" + multiPerm = "multiple permissions account" + randomPerm = "random permission" +) // create module accounts for testing var ( @@ -36,8 +44,20 @@ func getCoinsByName(ctx sdk.Context, sk keep.Keeper, ak types.AccountKeeper, bk } func TestSendCoins(t *testing.T) { - app, ctx := createTestApp(false) - keeper := app.SupplyKeeper + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{Height: 1}) + + // add module accounts to supply keeper + maccPerms := simapp.GetMaccPerms() + maccPerms[holder] = nil + maccPerms[types.Burner] = []string{types.Burner} + maccPerms[types.Minter] = []string{types.Minter} + maccPerms[multiPerm] = []string{types.Burner, types.Minter, types.Staking} + maccPerms[randomPerm] = []string{"random"} + + appCodec := simappcodec.NewAppCodec(app.Codec()) + + keeper := keep.NewKeeper(appCodec, app.GetKey(types.StoreKey), app.AccountKeeper, app.BankKeeper, maccPerms) ak := app.AccountKeeper bk := app.BankKeeper @@ -85,8 +105,20 @@ func TestSendCoins(t *testing.T) { } func TestMintCoins(t *testing.T) { - app, ctx := createTestApp(false) - keeper := app.SupplyKeeper + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{Height: 1}) + + // add module accounts to supply keeper + maccPerms := simapp.GetMaccPerms() + maccPerms[holder] = nil + maccPerms[types.Burner] = []string{types.Burner} + maccPerms[types.Minter] = []string{types.Minter} + maccPerms[multiPerm] = []string{types.Burner, types.Minter, types.Staking} + maccPerms[randomPerm] = []string{"random"} + + appCodec := simappcodec.NewAppCodec(app.Codec()) + + keeper := keep.NewKeeper(appCodec, app.GetKey(types.StoreKey), app.AccountKeeper, app.BankKeeper, maccPerms) ak := app.AccountKeeper bk := app.BankKeeper @@ -121,8 +153,20 @@ func TestMintCoins(t *testing.T) { } func TestBurnCoins(t *testing.T) { - app, ctx := createTestApp(false) - keeper := app.SupplyKeeper + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{Height: 1}) + + // add module accounts to supply keeper + maccPerms := simapp.GetMaccPerms() + maccPerms[holder] = nil + maccPerms[types.Burner] = []string{types.Burner} + maccPerms[types.Minter] = []string{types.Minter} + maccPerms[multiPerm] = []string{types.Burner, types.Minter, types.Staking} + maccPerms[randomPerm] = []string{"random"} + + appCodec := simappcodec.NewAppCodec(app.Codec()) + + keeper := keep.NewKeeper(appCodec, app.GetKey(types.StoreKey), app.AccountKeeper, app.BankKeeper, maccPerms) ak := app.AccountKeeper bk := app.BankKeeper @@ -131,7 +175,7 @@ func TestBurnCoins(t *testing.T) { keeper.SetModuleAccount(ctx, burnerAcc) initialSupply := keeper.GetSupply(ctx) - initialSupply = initialSupply.Inflate(initCoins) + initialSupply.Inflate(initCoins) keeper.SetSupply(ctx, initialSupply) require.Panics(t, func() { keeper.BurnCoins(ctx, "", initCoins) }, "no module account") @@ -147,7 +191,7 @@ func TestBurnCoins(t *testing.T) { // test same functionality on module account with multiple permissions initialSupply = keeper.GetSupply(ctx) - initialSupply = initialSupply.Inflate(initCoins) + initialSupply.Inflate(initCoins) keeper.SetSupply(ctx, initialSupply) require.NoError(t, bk.SetBalances(ctx, multiPermAcc.GetAddress(), initCoins)) diff --git a/x/supply/internal/keeper/invariants.go b/x/supply/keeper/invariants.go similarity index 95% rename from x/supply/internal/keeper/invariants.go rename to x/supply/keeper/invariants.go index 0b5ca06694ed..d53b7637f1ef 100644 --- a/x/supply/internal/keeper/invariants.go +++ b/x/supply/keeper/invariants.go @@ -4,7 +4,7 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/supply/internal/types" + "github.com/cosmos/cosmos-sdk/x/supply/types" ) // RegisterInvariants register all supply invariants diff --git a/x/supply/internal/keeper/keeper.go b/x/supply/keeper/keeper.go similarity index 74% rename from x/supply/internal/keeper/keeper.go rename to x/supply/keeper/keeper.go index b071f878db33..012a5cf284aa 100644 --- a/x/supply/internal/keeper/keeper.go +++ b/x/supply/keeper/keeper.go @@ -5,15 +5,14 @@ import ( "github.com/tendermint/tendermint/libs/log" - "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/supply/exported" - "github.com/cosmos/cosmos-sdk/x/supply/internal/types" + "github.com/cosmos/cosmos-sdk/x/supply/types" ) // Keeper of the supply store type Keeper struct { - cdc *codec.Codec + cdc types.Codec storeKey sdk.StoreKey ak types.AccountKeeper bk types.BankKeeper @@ -21,8 +20,11 @@ type Keeper struct { } // NewKeeper creates a new Keeper instance -func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, ak types.AccountKeeper, bk types.BankKeeper, maccPerms map[string][]string) Keeper { - // set the addresses +func NewKeeper( + cdc types.Codec, key sdk.StoreKey, ak types.AccountKeeper, + bk types.BankKeeper, maccPerms map[string][]string, +) Keeper { + permAddrs := make(map[string]types.PermissionsForAddress) for name, perms := range maccPerms { permAddrs[name] = types.NewPermissionsForAddress(name, perms) @@ -43,21 +45,30 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { } // GetSupply retrieves the Supply from store -func (k Keeper) GetSupply(ctx sdk.Context) (supply exported.SupplyI) { +func (k Keeper) GetSupply(ctx sdk.Context) exported.SupplyI { store := ctx.KVStore(k.storeKey) - b := store.Get(SupplyKey) - if b == nil { + bz := store.Get(SupplyKey) + if bz == nil { panic("stored supply should not have been nil") } - k.cdc.MustUnmarshalBinaryLengthPrefixed(b, &supply) - return + + supply, err := k.cdc.UnmarshalSupply(bz) + if err != nil { + panic(err) + } + + return supply } // SetSupply sets the Supply to store func (k Keeper) SetSupply(ctx sdk.Context, supply exported.SupplyI) { store := ctx.KVStore(k.storeKey) - b := k.cdc.MustMarshalBinaryLengthPrefixed(supply) - store.Set(SupplyKey, b) + bz, err := k.cdc.MarshalSupply(supply) + if err != nil { + panic(err) + } + + store.Set(SupplyKey, bz) } // ValidatePermissions validates that the module account has been granted @@ -69,5 +80,6 @@ func (k Keeper) ValidatePermissions(macc exported.ModuleAccountI) error { return fmt.Errorf("invalid module permission %s", perm) } } + return nil } diff --git a/x/supply/keeper/keeper_test.go b/x/supply/keeper/keeper_test.go new file mode 100644 index 000000000000..a81575914abc --- /dev/null +++ b/x/supply/keeper/keeper_test.go @@ -0,0 +1,55 @@ +package keeper_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/simapp" + simappcodec "github.com/cosmos/cosmos-sdk/simapp/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + keep "github.com/cosmos/cosmos-sdk/x/supply/keeper" + "github.com/cosmos/cosmos-sdk/x/supply/types" +) + +func TestSupply(t *testing.T) { + initialPower := int64(100) + initTokens := sdk.TokensFromConsensusPower(initialPower) + + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{Height: 1}) + + totalSupply := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initTokens)) + app.SupplyKeeper.SetSupply(ctx, types.NewSupply(totalSupply)) + + total := app.SupplyKeeper.GetSupply(ctx).GetTotal() + + require.Equal(t, totalSupply, total) +} + +func TestValidatePermissions(t *testing.T) { + app := simapp.Setup(false) + + // add module accounts to supply keeper + maccPerms := simapp.GetMaccPerms() + maccPerms[holder] = nil + maccPerms[types.Burner] = []string{types.Burner} + maccPerms[types.Minter] = []string{types.Minter} + maccPerms[multiPerm] = []string{types.Burner, types.Minter, types.Staking} + maccPerms[randomPerm] = []string{"random"} + + appCodec := simappcodec.NewAppCodec(app.Codec()) + keeper := keep.NewKeeper(appCodec, app.GetKey(types.StoreKey), app.AccountKeeper, app.BankKeeper, maccPerms) + + err := keeper.ValidatePermissions(multiPermAcc) + require.NoError(t, err) + + err = keeper.ValidatePermissions(randomPermAcc) + require.NoError(t, err) + + // unregistered permissions + otherAcc := types.NewEmptyModuleAccount("other", "other") + err = app.SupplyKeeper.ValidatePermissions(otherAcc) + require.Error(t, err) +} diff --git a/x/supply/internal/keeper/key.go b/x/supply/keeper/key.go similarity index 100% rename from x/supply/internal/keeper/key.go rename to x/supply/keeper/key.go diff --git a/x/supply/internal/keeper/querier.go b/x/supply/keeper/querier.go similarity index 97% rename from x/supply/internal/keeper/querier.go rename to x/supply/keeper/querier.go index 093edd2c6bea..1150fe3ad4f0 100644 --- a/x/supply/internal/keeper/querier.go +++ b/x/supply/keeper/querier.go @@ -6,7 +6,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/cosmos-sdk/x/supply/internal/types" + "github.com/cosmos/cosmos-sdk/x/supply/types" ) // NewQuerier creates a querier for supply REST endpoints diff --git a/x/supply/internal/keeper/querier_test.go b/x/supply/keeper/querier_test.go similarity index 89% rename from x/supply/internal/keeper/querier_test.go rename to x/supply/keeper/querier_test.go index 92b0dcf32b15..e71fa664bbac 100644 --- a/x/supply/internal/keeper/querier_test.go +++ b/x/supply/keeper/querier_test.go @@ -7,13 +7,16 @@ import ( "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" + "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" - keep "github.com/cosmos/cosmos-sdk/x/supply/internal/keeper" - "github.com/cosmos/cosmos-sdk/x/supply/internal/types" + keep "github.com/cosmos/cosmos-sdk/x/supply/keeper" + "github.com/cosmos/cosmos-sdk/x/supply/types" ) func TestNewQuerier(t *testing.T) { - app, ctx := createTestApp(false) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{Height: 1}) + keeper := app.SupplyKeeper cdc := app.Codec() @@ -59,7 +62,9 @@ func TestNewQuerier(t *testing.T) { } func TestQuerySupply(t *testing.T) { - app, ctx := createTestApp(false) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{Height: 1}) + keeper := app.SupplyKeeper cdc := app.Codec() diff --git a/x/supply/module.go b/x/supply/module.go index 73d05a772246..1a2531d99259 100644 --- a/x/supply/module.go +++ b/x/supply/module.go @@ -17,8 +17,8 @@ import ( sim "github.com/cosmos/cosmos-sdk/x/simulation" "github.com/cosmos/cosmos-sdk/x/supply/client/cli" "github.com/cosmos/cosmos-sdk/x/supply/client/rest" - "github.com/cosmos/cosmos-sdk/x/supply/internal/types" "github.com/cosmos/cosmos-sdk/x/supply/simulation" + "github.com/cosmos/cosmos-sdk/x/supply/types" ) var ( @@ -42,14 +42,14 @@ func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) { // DefaultGenesis returns default genesis state as raw bytes for the supply // module. -func (AppModuleBasic) DefaultGenesis() json.RawMessage { - return ModuleCdc.MustMarshalJSON(DefaultGenesisState()) +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { + return cdc.MustMarshalJSON(DefaultGenesisState()) } // ValidateGenesis performs genesis state validation for the supply module. -func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, bz json.RawMessage) error { var data GenesisState - if err := ModuleCdc.UnmarshalJSON(bz, &data); err != nil { + if err := cdc.UnmarshalJSON(bz, &data); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", ModuleName, err) } @@ -120,18 +120,18 @@ func (am AppModule) NewQuerierHandler() sdk.Querier { // InitGenesis performs genesis initialization for the supply module. It returns // no validator updates. -func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate { +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data json.RawMessage) []abci.ValidatorUpdate { var genesisState GenesisState - ModuleCdc.MustUnmarshalJSON(data, &genesisState) + cdc.MustUnmarshalJSON(data, &genesisState) InitGenesis(ctx, am.keeper, am.bk, genesisState) return []abci.ValidatorUpdate{} } // ExportGenesis returns the exported genesis state as raw bytes for the supply // module. -func (am AppModule) ExportGenesis(ctx sdk.Context) json.RawMessage { +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json.RawMessage { gs := ExportGenesis(ctx, am.keeper) - return ModuleCdc.MustMarshalJSON(gs) + return cdc.MustMarshalJSON(gs) } // BeginBlock returns the begin blocker for the supply module. diff --git a/x/supply/simulation/decoder.go b/x/supply/simulation/decoder.go index 3337e4b0687f..b67e07651be4 100644 --- a/x/supply/simulation/decoder.go +++ b/x/supply/simulation/decoder.go @@ -7,8 +7,8 @@ import ( tmkv "github.com/tendermint/tendermint/libs/kv" "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/x/supply/internal/keeper" - "github.com/cosmos/cosmos-sdk/x/supply/internal/types" + "github.com/cosmos/cosmos-sdk/x/supply/keeper" + "github.com/cosmos/cosmos-sdk/x/supply/types" ) // DecodeStore unmarshals the KVPair's Value to the corresponding supply type @@ -19,6 +19,7 @@ func DecodeStore(cdc *codec.Codec, kvA, kvB tmkv.Pair) string { cdc.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &supplyA) cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &supplyB) return fmt.Sprintf("%v\n%v", supplyB, supplyB) + default: panic(fmt.Sprintf("invalid supply key %X", kvA.Key)) } diff --git a/x/supply/simulation/decoder_test.go b/x/supply/simulation/decoder_test.go index f653632f168d..413e0a930e9d 100644 --- a/x/supply/simulation/decoder_test.go +++ b/x/supply/simulation/decoder_test.go @@ -10,8 +10,8 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/supply/internal/keeper" - "github.com/cosmos/cosmos-sdk/x/supply/internal/types" + "github.com/cosmos/cosmos-sdk/x/supply/keeper" + "github.com/cosmos/cosmos-sdk/x/supply/types" ) func makeTestCodec() (cdc *codec.Codec) { diff --git a/x/supply/simulation/genesis.go b/x/supply/simulation/genesis.go index 53775fbc07d6..b261fa8aa884 100644 --- a/x/supply/simulation/genesis.go +++ b/x/supply/simulation/genesis.go @@ -9,7 +9,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" - "github.com/cosmos/cosmos-sdk/x/supply/internal/types" + "github.com/cosmos/cosmos-sdk/x/supply/types" ) // RandomizedGenState generates a random GenesisState for supply diff --git a/x/supply/internal/types/account.go b/x/supply/types/account.go similarity index 85% rename from x/supply/internal/types/account.go rename to x/supply/types/account.go index 533084d2b0bd..14b91bb234ea 100644 --- a/x/supply/internal/types/account.go +++ b/x/supply/types/account.go @@ -21,21 +21,6 @@ var ( _ exported.ModuleAccountI = (*ModuleAccount)(nil) ) -func init() { - // Register the ModuleAccount type as a GenesisAccount so that when no - // concrete GenesisAccount types exist and **default** genesis state is used, - // the genesis state will serialize correctly. - authtypes.RegisterAccountTypeCodec(&ModuleAccount{}, "cosmos-sdk/ModuleAccount") -} - -// ModuleAccount defines an account for modules that holds coins on a pool -type ModuleAccount struct { - *authtypes.BaseAccount - - Name string `json:"name" yaml:"name"` // name of the module - Permissions []string `json:"permissions" yaml:"permissions"` // permissions of module account -} - // NewModuleAddress creates an AccAddress from the hash of the module's name func NewModuleAddress(name string) sdk.AccAddress { return sdk.AccAddress(crypto.AddressHash([]byte(name))) @@ -51,16 +36,14 @@ func NewEmptyModuleAccount(name string, permissions ...string) *ModuleAccount { } return &ModuleAccount{ - BaseAccount: &baseAcc, + BaseAccount: baseAcc, Name: name, Permissions: permissions, } } // NewModuleAccount creates a new ModuleAccount instance -func NewModuleAccount(ba *authtypes.BaseAccount, - name string, permissions ...string) *ModuleAccount { - +func NewModuleAccount(ba *authtypes.BaseAccount, name string, permissions ...string) *ModuleAccount { if err := validatePermissions(permissions...); err != nil { panic(err) } diff --git a/x/supply/internal/types/account_test.go b/x/supply/types/account_test.go similarity index 99% rename from x/supply/internal/types/account_test.go rename to x/supply/types/account_test.go index a3ee01bf1afa..a93fa5c94929 100644 --- a/x/supply/internal/types/account_test.go +++ b/x/supply/types/account_test.go @@ -6,15 +6,13 @@ import ( "fmt" "testing" - yaml "gopkg.in/yaml.v2" - + "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/crypto/secp256k1" + yaml "gopkg.in/yaml.v2" sdk "github.com/cosmos/cosmos-sdk/types" authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - - "github.com/stretchr/testify/require" ) func TestModuleAccountMarshalYAML(t *testing.T) { diff --git a/x/supply/types/codec.go b/x/supply/types/codec.go new file mode 100644 index 000000000000..f452d4b5a987 --- /dev/null +++ b/x/supply/types/codec.go @@ -0,0 +1,45 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/x/supply/exported" +) + +// Codec defines the interface needed to serialize x/supply state. It must +// be aware of all concrete supply types. +type Codec interface { + codec.Marshaler + + MarshalSupply(supply exported.SupplyI) ([]byte, error) + UnmarshalSupply(bz []byte) (exported.SupplyI, error) + + MarshalSupplyJSON(supply exported.SupplyI) ([]byte, error) + UnmarshalSupplyJSON(bz []byte) (exported.SupplyI, error) +} + +// RegisterCodec registers the necessary x/supply interfaces and concrete types +// on the provided Amino codec. These types are used for Amino JSON serialization. +func RegisterCodec(cdc *codec.Codec) { + cdc.RegisterInterface((*exported.ModuleAccountI)(nil), nil) + cdc.RegisterInterface((*exported.SupplyI)(nil), nil) + cdc.RegisterConcrete(&ModuleAccount{}, "cosmos-sdk/ModuleAccount", nil) + cdc.RegisterConcrete(&Supply{}, "cosmos-sdk/Supply", nil) +} + +var ( + amino = codec.New() + + // ModuleCdc references the global x/supply module codec. Note, the codec should + // ONLY be used in certain instances of tests and for JSON encoding as Amino is + // still used for that purpose. + // + // The actual codec used for serialization should be provided to x/supply and + // defined at the application level. + ModuleCdc = codec.NewHybridCodec(amino) +) + +func init() { + RegisterCodec(amino) + codec.RegisterCrypto(amino) + amino.Seal() +} diff --git a/x/supply/internal/types/expected_keepers.go b/x/supply/types/expected_keepers.go similarity index 100% rename from x/supply/internal/types/expected_keepers.go rename to x/supply/types/expected_keepers.go diff --git a/x/supply/internal/types/genesis.go b/x/supply/types/genesis.go similarity index 100% rename from x/supply/internal/types/genesis.go rename to x/supply/types/genesis.go diff --git a/x/supply/internal/types/key.go b/x/supply/types/key.go similarity index 100% rename from x/supply/internal/types/key.go rename to x/supply/types/key.go diff --git a/x/supply/internal/types/permissions.go b/x/supply/types/permissions.go similarity index 100% rename from x/supply/internal/types/permissions.go rename to x/supply/types/permissions.go diff --git a/x/supply/internal/types/permissions_test.go b/x/supply/types/permissions_test.go similarity index 100% rename from x/supply/internal/types/permissions_test.go rename to x/supply/types/permissions_test.go diff --git a/x/supply/internal/types/querier.go b/x/supply/types/querier.go similarity index 100% rename from x/supply/internal/types/querier.go rename to x/supply/types/querier.go diff --git a/x/supply/internal/types/supply.go b/x/supply/types/supply.go similarity index 56% rename from x/supply/internal/types/supply.go rename to x/supply/types/supply.go index 92e4a3e5d2f5..de5a4d751f7a 100644 --- a/x/supply/internal/types/supply.go +++ b/x/supply/types/supply.go @@ -10,17 +10,21 @@ import ( ) // Implements Delegation interface -var _ exported.SupplyI = Supply{} +var _ exported.SupplyI = (*Supply)(nil) -// Supply represents a struct that passively keeps track of the total supply amounts in the network -type Supply struct { - Total sdk.Coins `json:"total" yaml:"total"` // total supply of tokens registered on the chain +// NewSupply creates a new Supply instance +func NewSupply(total sdk.Coins) *Supply { + return &Supply{total} +} + +// DefaultSupply creates an empty Supply +func DefaultSupply() *Supply { + return NewSupply(sdk.NewCoins()) } // SetTotal sets the total supply. -func (supply Supply) SetTotal(total sdk.Coins) exported.SupplyI { +func (supply *Supply) SetTotal(total sdk.Coins) { supply.Total = total - return supply } // GetTotal returns the supply total. @@ -28,35 +32,20 @@ func (supply Supply) GetTotal() sdk.Coins { return supply.Total } -// NewSupply creates a new Supply instance -func NewSupply(total sdk.Coins) exported.SupplyI { - return Supply{total} -} - -// DefaultSupply creates an empty Supply -func DefaultSupply() exported.SupplyI { - return NewSupply(sdk.NewCoins()) -} - // Inflate adds coins to the total supply -func (supply Supply) Inflate(amount sdk.Coins) exported.SupplyI { +func (supply *Supply) Inflate(amount sdk.Coins) { supply.Total = supply.Total.Add(amount...) - return supply } -// Deflate subtracts coins from the total supply -func (supply Supply) Deflate(amount sdk.Coins) exported.SupplyI { +// Deflate subtracts coins from the total supply. +func (supply *Supply) Deflate(amount sdk.Coins) { supply.Total = supply.Total.Sub(amount) - return supply } // String returns a human readable string representation of a supplier. func (supply Supply) String() string { - b, err := yaml.Marshal(supply) - if err != nil { - panic(err) - } - return string(b) + bz, _ := yaml.Marshal(supply) + return string(bz) } // ValidateBasic validates the Supply coins and returns error if invalid diff --git a/x/supply/internal/types/supply_test.go b/x/supply/types/supply_test.go similarity index 94% rename from x/supply/internal/types/supply_test.go rename to x/supply/types/supply_test.go index e99e1e5aea49..4af49d362fd1 100644 --- a/x/supply/internal/types/supply_test.go +++ b/x/supply/types/supply_test.go @@ -14,7 +14,7 @@ import ( func TestSupplyMarshalYAML(t *testing.T) { supply := DefaultSupply() coins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.OneInt())) - supply = supply.Inflate(coins) + supply.Inflate(coins) bz, err := yaml.Marshal(supply) require.NoError(t, err) diff --git a/x/supply/types/types.pb.go b/x/supply/types/types.pb.go new file mode 100644 index 000000000000..399056115635 --- /dev/null +++ b/x/supply/types/types.pb.go @@ -0,0 +1,605 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: x/supply/types/types.proto + +package types + +import ( + fmt "fmt" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + types1 "github.com/cosmos/cosmos-sdk/types" + types "github.com/cosmos/cosmos-sdk/x/auth/types" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// ModuleAccount defines an account for modules that holds coins on a pool +type ModuleAccount struct { + *types.BaseAccount `protobuf:"bytes,1,opt,name=base_account,json=baseAccount,proto3,embedded=base_account" json:"base_account,omitempty" yaml:"base_account"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Permissions []string `protobuf:"bytes,3,rep,name=permissions,proto3" json:"permissions,omitempty"` +} + +func (m *ModuleAccount) Reset() { *m = ModuleAccount{} } +func (*ModuleAccount) ProtoMessage() {} +func (*ModuleAccount) Descriptor() ([]byte, []int) { + return fileDescriptor_e14b855c341cf347, []int{0} +} +func (m *ModuleAccount) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ModuleAccount) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ModuleAccount.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 *ModuleAccount) XXX_Merge(src proto.Message) { + xxx_messageInfo_ModuleAccount.Merge(m, src) +} +func (m *ModuleAccount) XXX_Size() int { + return m.Size() +} +func (m *ModuleAccount) XXX_DiscardUnknown() { + xxx_messageInfo_ModuleAccount.DiscardUnknown(m) +} + +var xxx_messageInfo_ModuleAccount proto.InternalMessageInfo + +// Supply represents a struct that passively keeps track of the total supply +// amounts in the network. +type Supply struct { + Total github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,1,rep,name=total,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"total"` +} + +func (m *Supply) Reset() { *m = Supply{} } +func (*Supply) ProtoMessage() {} +func (*Supply) Descriptor() ([]byte, []int) { + return fileDescriptor_e14b855c341cf347, []int{1} +} +func (m *Supply) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Supply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Supply.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 *Supply) XXX_Merge(src proto.Message) { + xxx_messageInfo_Supply.Merge(m, src) +} +func (m *Supply) XXX_Size() int { + return m.Size() +} +func (m *Supply) XXX_DiscardUnknown() { + xxx_messageInfo_Supply.DiscardUnknown(m) +} + +var xxx_messageInfo_Supply proto.InternalMessageInfo + +func init() { + proto.RegisterType((*ModuleAccount)(nil), "cosmos_sdk.x.supply.v1.ModuleAccount") + proto.RegisterType((*Supply)(nil), "cosmos_sdk.x.supply.v1.Supply") +} + +func init() { proto.RegisterFile("x/supply/types/types.proto", fileDescriptor_e14b855c341cf347) } + +var fileDescriptor_e14b855c341cf347 = []byte{ + // 348 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xaa, 0xd0, 0x2f, 0x2e, + 0x2d, 0x28, 0xc8, 0xa9, 0xd4, 0x2f, 0xa9, 0x2c, 0x48, 0x2d, 0x86, 0x90, 0x7a, 0x05, 0x45, 0xf9, + 0x25, 0xf9, 0x42, 0x62, 0xc9, 0xf9, 0xc5, 0xb9, 0xf9, 0xc5, 0xf1, 0xc5, 0x29, 0xd9, 0x7a, 0x15, + 0x7a, 0x10, 0x65, 0x7a, 0x65, 0x86, 0x52, 0x6a, 0x25, 0x19, 0x99, 0x45, 0x29, 0xf1, 0x05, 0x89, + 0x45, 0x25, 0x95, 0xfa, 0x60, 0xa5, 0xfa, 0xe9, 0xf9, 0xe9, 0xf9, 0x08, 0x16, 0x44, 0xbf, 0x94, + 0x20, 0x86, 0x91, 0x52, 0x12, 0x15, 0xfa, 0x89, 0xa5, 0x25, 0x19, 0x98, 0x96, 0x29, 0x6d, 0x62, + 0xe4, 0xe2, 0xf5, 0xcd, 0x4f, 0x29, 0xcd, 0x49, 0x75, 0x4c, 0x4e, 0xce, 0x2f, 0xcd, 0x2b, 0x11, + 0x4a, 0xe4, 0xe2, 0x49, 0x4a, 0x2c, 0x4e, 0x8d, 0x4f, 0x84, 0xf0, 0x25, 0x18, 0x15, 0x18, 0x35, + 0xb8, 0x8d, 0x14, 0xf5, 0x50, 0x5c, 0x05, 0x32, 0x4d, 0xaf, 0xcc, 0x50, 0xcf, 0x29, 0xb1, 0x18, + 0xa6, 0xd1, 0x49, 0xfa, 0xc2, 0x3d, 0x79, 0xc6, 0x4f, 0xf7, 0xe4, 0x85, 0x2b, 0x13, 0x73, 0x73, + 0xac, 0x94, 0x90, 0x0d, 0x51, 0x0a, 0xe2, 0x4e, 0x42, 0xa8, 0x14, 0x12, 0xe2, 0x62, 0xc9, 0x4b, + 0xcc, 0x4d, 0x95, 0x60, 0x52, 0x60, 0xd4, 0xe0, 0x0c, 0x02, 0xb3, 0x85, 0x14, 0xb8, 0xb8, 0x0b, + 0x52, 0x8b, 0x72, 0x33, 0x8b, 0x8b, 0x33, 0xf3, 0xf3, 0x8a, 0x25, 0x98, 0x15, 0x98, 0x35, 0x38, + 0x83, 0x90, 0x85, 0xac, 0x38, 0x3a, 0x16, 0xc8, 0x33, 0xcc, 0x58, 0x20, 0xcf, 0xa0, 0x94, 0xcf, + 0xc5, 0x16, 0x0c, 0x0e, 0x16, 0xa1, 0x68, 0x2e, 0xd6, 0x92, 0xfc, 0x92, 0xc4, 0x1c, 0x09, 0x46, + 0x05, 0x66, 0x0d, 0x6e, 0x23, 0x61, 0x64, 0x57, 0x96, 0x19, 0xea, 0x39, 0xe7, 0x67, 0xe6, 0x39, + 0x19, 0x9c, 0xb8, 0x27, 0xcf, 0xb0, 0xea, 0xbe, 0xbc, 0x46, 0x7a, 0x66, 0x49, 0x46, 0x69, 0x92, + 0x5e, 0x72, 0x7e, 0xae, 0x3e, 0x44, 0x19, 0x94, 0xd2, 0x2d, 0x4e, 0xc9, 0x86, 0x06, 0x0a, 0x48, + 0x43, 0x71, 0x10, 0xc4, 0x4c, 0x84, 0x85, 0x4e, 0xae, 0x27, 0x1e, 0xc9, 0x31, 0x5e, 0x78, 0x24, + 0xc7, 0xf8, 0xe0, 0x91, 0x1c, 0xe3, 0x84, 0xc7, 0x72, 0x0c, 0x17, 0x1e, 0xcb, 0x31, 0xdc, 0x78, + 0x2c, 0xc7, 0x10, 0xa5, 0x8d, 0xd7, 0x50, 0xd4, 0x58, 0x4e, 0x62, 0x03, 0x87, 0xb9, 0x31, 0x20, + 0x00, 0x00, 0xff, 0xff, 0x95, 0xfd, 0xe3, 0x40, 0xfe, 0x01, 0x00, 0x00, +} + +func (m *ModuleAccount) 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 *ModuleAccount) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ModuleAccount) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Permissions) > 0 { + for iNdEx := len(m.Permissions) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Permissions[iNdEx]) + copy(dAtA[i:], m.Permissions[iNdEx]) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Permissions[iNdEx]))) + i-- + dAtA[i] = 0x1a + } + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0x12 + } + if m.BaseAccount != nil { + { + size, err := m.BaseAccount.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *Supply) 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 *Supply) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Supply) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Total) > 0 { + for iNdEx := len(m.Total) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Total[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarintTypes(dAtA []byte, offset int, v uint64) int { + offset -= sovTypes(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *ModuleAccount) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.BaseAccount != nil { + l = m.BaseAccount.Size() + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.Name) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + if len(m.Permissions) > 0 { + for _, s := range m.Permissions { + l = len(s) + n += 1 + l + sovTypes(uint64(l)) + } + } + return n +} + +func (m *Supply) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Total) > 0 { + for _, e := range m.Total { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + return n +} + +func sovTypes(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTypes(x uint64) (n int) { + return sovTypes(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *ModuleAccount) 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 ErrIntOverflowTypes + } + 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: ModuleAccount: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ModuleAccount: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BaseAccount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.BaseAccount == nil { + m.BaseAccount = &types.BaseAccount{} + } + if err := m.BaseAccount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Permissions", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Permissions = append(m.Permissions, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Supply) 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 ErrIntOverflowTypes + } + 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: Supply: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Supply: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Total", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Total = append(m.Total, types1.Coin{}) + if err := m.Total[len(m.Total)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTypes(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthTypes + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTypes + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTypes + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTypes = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTypes = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTypes = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/supply/types/types.proto b/x/supply/types/types.proto new file mode 100644 index 000000000000..0c14740ea29d --- /dev/null +++ b/x/supply/types/types.proto @@ -0,0 +1,31 @@ +syntax = "proto3"; +package cosmos_sdk.x.supply.v1; + +import "third_party/proto/gogoproto/gogo.proto"; +import "types/types.proto"; +import "x/auth/types/types.proto"; + +option go_package = "github.com/cosmos/cosmos-sdk/x/supply/types"; + +// ModuleAccount defines an account for modules that holds coins on a pool +message ModuleAccount { + option (gogoproto.goproto_getters) = false; + option (gogoproto.goproto_stringer) = false; + + cosmos_sdk.x.auth.v1.BaseAccount base_account = 1 + [(gogoproto.embed) = true, (gogoproto.moretags) = "yaml:\"base_account\""]; + string name = 2; + repeated string permissions = 3; +} + +// Supply represents a struct that passively keeps track of the total supply +// amounts in the network. +message Supply { + option (gogoproto.goproto_getters) = false; + option (gogoproto.goproto_stringer) = false; + + repeated cosmos_sdk.v1.Coin total = 1 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + ]; +} diff --git a/x/upgrade/module.go b/x/upgrade/module.go index 5605ca0b673e..f5a9b461ef8d 100644 --- a/x/upgrade/module.go +++ b/x/upgrade/module.go @@ -103,23 +103,23 @@ func (am AppModule) NewQuerierHandler() sdk.Querier { } // InitGenesis is ignored, no sense in serializing future upgrades -func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate { +func (am AppModule) InitGenesis(_ sdk.Context, _ codec.JSONMarshaler, _ json.RawMessage) []abci.ValidatorUpdate { return []abci.ValidatorUpdate{} } // DefaultGenesis is an empty object -func (AppModuleBasic) DefaultGenesis() json.RawMessage { +func (AppModuleBasic) DefaultGenesis(_ codec.JSONMarshaler) json.RawMessage { return []byte("{}") } // ValidateGenesis is always successful, as we ignore the value -func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(_ codec.JSONMarshaler, _ json.RawMessage) error { return nil } // ExportGenesis is always empty, as InitGenesis does nothing either -func (am AppModule) ExportGenesis(ctx sdk.Context) json.RawMessage { - return am.DefaultGenesis() +func (am AppModule) ExportGenesis(_ sdk.Context, cdc codec.JSONMarshaler) json.RawMessage { + return am.DefaultGenesis(cdc) } // BeginBlock calls the upgrade module hooks From 918949cf231978da0926015dccfbb04db403471f Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Tue, 18 Feb 2020 14:00:59 +0100 Subject: [PATCH 145/529] refactor TestHistoricalInfo to use simapp --- x/staking/keeper/common_refactor_test.go | 97 ++++++++++++++ x/staking/keeper/historical_info_test.go | 155 ++++++++++++----------- 2 files changed, 176 insertions(+), 76 deletions(-) create mode 100644 x/staking/keeper/common_refactor_test.go diff --git a/x/staking/keeper/common_refactor_test.go b/x/staking/keeper/common_refactor_test.go new file mode 100644 index 000000000000..33a4f0c1ab50 --- /dev/null +++ b/x/staking/keeper/common_refactor_test.go @@ -0,0 +1,97 @@ +package keeper_test + +import ( + "bytes" + "encoding/hex" + "strconv" + + "github.com/tendermint/tendermint/crypto/ed25519" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/tendermint/tendermint/crypto" +) + +var ( + Addrs = createTestAddrs(500) + PKs = createTestPubKeys(500) + + addrDels = []sdk.AccAddress{ + Addrs[0], + Addrs[1], + } + addrVals = []sdk.ValAddress{ + sdk.ValAddress(Addrs[2]), + sdk.ValAddress(Addrs[3]), + sdk.ValAddress(Addrs[4]), + sdk.ValAddress(Addrs[5]), + sdk.ValAddress(Addrs[6]), + } +) + +func createTestAddrs(numAddrs int) []sdk.AccAddress { + var addresses []sdk.AccAddress + var buffer bytes.Buffer + + // start at 100 so we can make up to 999 test addresses with valid test addresses + for i := 100; i < (numAddrs + 100); i++ { + numString := strconv.Itoa(i) + buffer.WriteString("A58856F0FD53BF058B4909A21AEC019107BA6") //base address string + + buffer.WriteString(numString) //adding on final two digits to make addresses unique + res, _ := sdk.AccAddressFromHex(buffer.String()) + bech := res.String() + addresses = append(addresses, CreateTestAddr(buffer.String(), bech)) + buffer.Reset() + } + return addresses +} + +// nolint: unparam +func createTestPubKeys(numPubKeys int) []crypto.PubKey { + var publicKeys []crypto.PubKey + var buffer bytes.Buffer + + //start at 10 to avoid changing 1 to 01, 2 to 02, etc + for i := 100; i < (numPubKeys + 100); i++ { + numString := strconv.Itoa(i) + buffer.WriteString("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AF") //base pubkey string + buffer.WriteString(numString) //adding on final two digits to make pubkeys unique + publicKeys = append(publicKeys, NewPubKey(buffer.String())) + buffer.Reset() + } + return publicKeys +} + +func NewPubKey(pk string) (res crypto.PubKey) { + pkBytes, err := hex.DecodeString(pk) + if err != nil { + panic(err) + } + //res, err = crypto.PubKeyFromBytes(pkBytes) + var pkEd ed25519.PubKeyEd25519 + copy(pkEd[:], pkBytes) + return pkEd +} + +// for incode address generation +func CreateTestAddr(addr string, bech string) sdk.AccAddress { + + res, err := sdk.AccAddressFromHex(addr) + if err != nil { + panic(err) + } + bechexpected := res.String() + if bech != bechexpected { + panic("Bech encoding doesn't match reference") + } + + bechres, err := sdk.AccAddressFromBech32(bech) + if err != nil { + panic(err) + } + if !bytes.Equal(bechres, res) { + panic("Bech decode and hex decode don't match") + } + + return res +} diff --git a/x/staking/keeper/historical_info_test.go b/x/staking/keeper/historical_info_test.go index db372bce2cae..50250116ef0b 100644 --- a/x/staking/keeper/historical_info_test.go +++ b/x/staking/keeper/historical_info_test.go @@ -1,10 +1,11 @@ -package keeper +package keeper_test import ( "sort" "testing" - sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/simapp" + "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/stretchr/testify/require" @@ -12,7 +13,9 @@ import ( ) func TestHistoricalInfo(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 10) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + validators := make([]types.Validator, len(addrVals)) for i, valAddr := range addrVals { @@ -21,86 +24,86 @@ func TestHistoricalInfo(t *testing.T) { hi := types.NewHistoricalInfo(ctx.BlockHeader(), validators) - keeper.SetHistoricalInfo(ctx, 2, hi) + app.StakingKeeper.SetHistoricalInfo(ctx, 2, hi) - recv, found := keeper.GetHistoricalInfo(ctx, 2) + recv, found := app.StakingKeeper.GetHistoricalInfo(ctx, 2) require.True(t, found, "HistoricalInfo not found after set") require.Equal(t, hi, recv, "HistoricalInfo not equal") require.True(t, sort.IsSorted(types.Validators(recv.Valset)), "HistoricalInfo validators is not sorted") - keeper.DeleteHistoricalInfo(ctx, 2) + app.StakingKeeper.DeleteHistoricalInfo(ctx, 2) - recv, found = keeper.GetHistoricalInfo(ctx, 2) + recv, found = app.StakingKeeper.GetHistoricalInfo(ctx, 2) require.False(t, found, "HistoricalInfo found after delete") require.Equal(t, types.HistoricalInfo{}, recv, "HistoricalInfo is not empty") } -func TestTrackHistoricalInfo(t *testing.T) { - ctx, _, _, k, _ := CreateTestInput(t, false, 10) - - // set historical entries in params to 5 - params := types.DefaultParams() - params.HistoricalEntries = 5 - k.SetParams(ctx, params) - - // set historical info at 5, 4 which should be pruned - // and check that it has been stored - h4 := abci.Header{ - ChainID: "HelloChain", - Height: 4, - } - h5 := abci.Header{ - ChainID: "HelloChain", - Height: 5, - } - valSet := []types.Validator{ - types.NewValidator(sdk.ValAddress(Addrs[0]), PKs[0], types.Description{}), - types.NewValidator(sdk.ValAddress(Addrs[1]), PKs[1], types.Description{}), - } - hi4 := types.NewHistoricalInfo(h4, valSet) - hi5 := types.NewHistoricalInfo(h5, valSet) - k.SetHistoricalInfo(ctx, 4, hi4) - k.SetHistoricalInfo(ctx, 5, hi5) - recv, found := k.GetHistoricalInfo(ctx, 4) - require.True(t, found) - require.Equal(t, hi4, recv) - recv, found = k.GetHistoricalInfo(ctx, 5) - require.True(t, found) - require.Equal(t, hi5, recv) - - // Set last validators in keeper - val1 := types.NewValidator(sdk.ValAddress(Addrs[2]), PKs[2], types.Description{}) - k.SetValidator(ctx, val1) - k.SetLastValidatorPower(ctx, val1.OperatorAddress, 10) - val2 := types.NewValidator(sdk.ValAddress(Addrs[3]), PKs[3], types.Description{}) - vals := []types.Validator{val1, val2} - sort.Sort(types.Validators(vals)) - k.SetValidator(ctx, val2) - k.SetLastValidatorPower(ctx, val2.OperatorAddress, 8) - - // Set Header for BeginBlock context - header := abci.Header{ - ChainID: "HelloChain", - Height: 10, - } - ctx = ctx.WithBlockHeader(header) - - k.TrackHistoricalInfo(ctx) - - // Check HistoricalInfo at height 10 is persisted - expected := types.HistoricalInfo{ - Header: header, - Valset: vals, - } - recv, found = k.GetHistoricalInfo(ctx, 10) - require.True(t, found, "GetHistoricalInfo failed after BeginBlock") - require.Equal(t, expected, recv, "GetHistoricalInfo returned eunexpected result") - - // Check HistoricalInfo at height 5, 4 is pruned - recv, found = k.GetHistoricalInfo(ctx, 4) - require.False(t, found, "GetHistoricalInfo did not prune earlier height") - require.Equal(t, types.HistoricalInfo{}, recv, "GetHistoricalInfo at height 4 is not empty after prune") - recv, found = k.GetHistoricalInfo(ctx, 5) - require.False(t, found, "GetHistoricalInfo did not prune first prune height") - require.Equal(t, types.HistoricalInfo{}, recv, "GetHistoricalInfo at height 5 is not empty after prune") -} +//func TestTrackHistoricalInfo(t *testing.T) { +// ctx, _, _, k, _ := CreateTestInput(t, false, 10) +// +// // set historical entries in params to 5 +// params := types.DefaultParams() +// params.HistoricalEntries = 5 +// k.SetParams(ctx, params) +// +// // set historical info at 5, 4 which should be pruned +// // and check that it has been stored +// h4 := abci.Header{ +// ChainID: "HelloChain", +// Height: 4, +// } +// h5 := abci.Header{ +// ChainID: "HelloChain", +// Height: 5, +// } +// valSet := []types.Validator{ +// types.NewValidator(sdk.ValAddress(Addrs[0]), PKs[0], types.Description{}), +// types.NewValidator(sdk.ValAddress(Addrs[1]), PKs[1], types.Description{}), +// } +// hi4 := types.NewHistoricalInfo(h4, valSet) +// hi5 := types.NewHistoricalInfo(h5, valSet) +// k.SetHistoricalInfo(ctx, 4, hi4) +// k.SetHistoricalInfo(ctx, 5, hi5) +// recv, found := k.GetHistoricalInfo(ctx, 4) +// require.True(t, found) +// require.Equal(t, hi4, recv) +// recv, found = k.GetHistoricalInfo(ctx, 5) +// require.True(t, found) +// require.Equal(t, hi5, recv) +// +// // Set last validators in keeper +// val1 := types.NewValidator(sdk.ValAddress(Addrs[2]), PKs[2], types.Description{}) +// k.SetValidator(ctx, val1) +// k.SetLastValidatorPower(ctx, val1.OperatorAddress, 10) +// val2 := types.NewValidator(sdk.ValAddress(Addrs[3]), PKs[3], types.Description{}) +// vals := []types.Validator{val1, val2} +// sort.Sort(types.Validators(vals)) +// k.SetValidator(ctx, val2) +// k.SetLastValidatorPower(ctx, val2.OperatorAddress, 8) +// +// // Set Header for BeginBlock context +// header := abci.Header{ +// ChainID: "HelloChain", +// Height: 10, +// } +// ctx = ctx.WithBlockHeader(header) +// +// k.TrackHistoricalInfo(ctx) +// +// // Check HistoricalInfo at height 10 is persisted +// expected := types.HistoricalInfo{ +// Header: header, +// Valset: vals, +// } +// recv, found = k.GetHistoricalInfo(ctx, 10) +// require.True(t, found, "GetHistoricalInfo failed after BeginBlock") +// require.Equal(t, expected, recv, "GetHistoricalInfo returned eunexpected result") +// +// // Check HistoricalInfo at height 5, 4 is pruned +// recv, found = k.GetHistoricalInfo(ctx, 4) +// require.False(t, found, "GetHistoricalInfo did not prune earlier height") +// require.Equal(t, types.HistoricalInfo{}, recv, "GetHistoricalInfo at height 4 is not empty after prune") +// recv, found = k.GetHistoricalInfo(ctx, 5) +// require.False(t, found, "GetHistoricalInfo did not prune first prune height") +// require.Equal(t, types.HistoricalInfo{}, recv, "GetHistoricalInfo at height 5 is not empty after prune") +//} From 6025132720efad5d442bb7d86bbd972ac42b0870 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Tue, 18 Feb 2020 14:03:06 +0100 Subject: [PATCH 146/529] refactor historical info test --- x/staking/keeper/historical_info_test.go | 141 ++++++++++++----------- 1 file changed, 72 insertions(+), 69 deletions(-) diff --git a/x/staking/keeper/historical_info_test.go b/x/staking/keeper/historical_info_test.go index 50250116ef0b..73cc64de0f4e 100644 --- a/x/staking/keeper/historical_info_test.go +++ b/x/staking/keeper/historical_info_test.go @@ -4,6 +4,8 @@ import ( "sort" "testing" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/simapp" "github.com/cosmos/cosmos-sdk/x/staking/types" @@ -38,72 +40,73 @@ func TestHistoricalInfo(t *testing.T) { require.Equal(t, types.HistoricalInfo{}, recv, "HistoricalInfo is not empty") } -//func TestTrackHistoricalInfo(t *testing.T) { -// ctx, _, _, k, _ := CreateTestInput(t, false, 10) -// -// // set historical entries in params to 5 -// params := types.DefaultParams() -// params.HistoricalEntries = 5 -// k.SetParams(ctx, params) -// -// // set historical info at 5, 4 which should be pruned -// // and check that it has been stored -// h4 := abci.Header{ -// ChainID: "HelloChain", -// Height: 4, -// } -// h5 := abci.Header{ -// ChainID: "HelloChain", -// Height: 5, -// } -// valSet := []types.Validator{ -// types.NewValidator(sdk.ValAddress(Addrs[0]), PKs[0], types.Description{}), -// types.NewValidator(sdk.ValAddress(Addrs[1]), PKs[1], types.Description{}), -// } -// hi4 := types.NewHistoricalInfo(h4, valSet) -// hi5 := types.NewHistoricalInfo(h5, valSet) -// k.SetHistoricalInfo(ctx, 4, hi4) -// k.SetHistoricalInfo(ctx, 5, hi5) -// recv, found := k.GetHistoricalInfo(ctx, 4) -// require.True(t, found) -// require.Equal(t, hi4, recv) -// recv, found = k.GetHistoricalInfo(ctx, 5) -// require.True(t, found) -// require.Equal(t, hi5, recv) -// -// // Set last validators in keeper -// val1 := types.NewValidator(sdk.ValAddress(Addrs[2]), PKs[2], types.Description{}) -// k.SetValidator(ctx, val1) -// k.SetLastValidatorPower(ctx, val1.OperatorAddress, 10) -// val2 := types.NewValidator(sdk.ValAddress(Addrs[3]), PKs[3], types.Description{}) -// vals := []types.Validator{val1, val2} -// sort.Sort(types.Validators(vals)) -// k.SetValidator(ctx, val2) -// k.SetLastValidatorPower(ctx, val2.OperatorAddress, 8) -// -// // Set Header for BeginBlock context -// header := abci.Header{ -// ChainID: "HelloChain", -// Height: 10, -// } -// ctx = ctx.WithBlockHeader(header) -// -// k.TrackHistoricalInfo(ctx) -// -// // Check HistoricalInfo at height 10 is persisted -// expected := types.HistoricalInfo{ -// Header: header, -// Valset: vals, -// } -// recv, found = k.GetHistoricalInfo(ctx, 10) -// require.True(t, found, "GetHistoricalInfo failed after BeginBlock") -// require.Equal(t, expected, recv, "GetHistoricalInfo returned eunexpected result") -// -// // Check HistoricalInfo at height 5, 4 is pruned -// recv, found = k.GetHistoricalInfo(ctx, 4) -// require.False(t, found, "GetHistoricalInfo did not prune earlier height") -// require.Equal(t, types.HistoricalInfo{}, recv, "GetHistoricalInfo at height 4 is not empty after prune") -// recv, found = k.GetHistoricalInfo(ctx, 5) -// require.False(t, found, "GetHistoricalInfo did not prune first prune height") -// require.Equal(t, types.HistoricalInfo{}, recv, "GetHistoricalInfo at height 5 is not empty after prune") -//} +func TestTrackHistoricalInfo(t *testing.T) { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + // set historical entries in params to 5 + params := types.DefaultParams() + params.HistoricalEntries = 5 + app.StakingKeeper.SetParams(ctx, params) + + // set historical info at 5, 4 which should be pruned + // and check that it has been stored + h4 := abci.Header{ + ChainID: "HelloChain", + Height: 4, + } + h5 := abci.Header{ + ChainID: "HelloChain", + Height: 5, + } + valSet := []types.Validator{ + types.NewValidator(sdk.ValAddress(Addrs[0]), PKs[0], types.Description{}), + types.NewValidator(sdk.ValAddress(Addrs[1]), PKs[1], types.Description{}), + } + hi4 := types.NewHistoricalInfo(h4, valSet) + hi5 := types.NewHistoricalInfo(h5, valSet) + app.StakingKeeper.SetHistoricalInfo(ctx, 4, hi4) + app.StakingKeeper.SetHistoricalInfo(ctx, 5, hi5) + recv, found := app.StakingKeeper.GetHistoricalInfo(ctx, 4) + require.True(t, found) + require.Equal(t, hi4, recv) + recv, found = app.StakingKeeper.GetHistoricalInfo(ctx, 5) + require.True(t, found) + require.Equal(t, hi5, recv) + + // Set last validators in keeper + val1 := types.NewValidator(sdk.ValAddress(Addrs[2]), PKs[2], types.Description{}) + app.StakingKeeper.SetValidator(ctx, val1) + app.StakingKeeper.SetLastValidatorPower(ctx, val1.OperatorAddress, 10) + val2 := types.NewValidator(sdk.ValAddress(Addrs[3]), PKs[3], types.Description{}) + vals := []types.Validator{val1, val2} + sort.Sort(types.Validators(vals)) + app.StakingKeeper.SetValidator(ctx, val2) + app.StakingKeeper.SetLastValidatorPower(ctx, val2.OperatorAddress, 8) + + // Set Header for BeginBlock context + header := abci.Header{ + ChainID: "HelloChain", + Height: 10, + } + ctx = ctx.WithBlockHeader(header) + + app.StakingKeeper.TrackHistoricalInfo(ctx) + + // Check HistoricalInfo at height 10 is persisted + expected := types.HistoricalInfo{ + Header: header, + Valset: vals, + } + recv, found = app.StakingKeeper.GetHistoricalInfo(ctx, 10) + require.True(t, found, "GetHistoricalInfo failed after BeginBlock") + require.Equal(t, expected, recv, "GetHistoricalInfo returned eunexpected result") + + // Check HistoricalInfo at height 5, 4 is pruned + recv, found = app.StakingKeeper.GetHistoricalInfo(ctx, 4) + require.False(t, found, "GetHistoricalInfo did not prune earlier height") + require.Equal(t, types.HistoricalInfo{}, recv, "GetHistoricalInfo at height 4 is not empty after prune") + recv, found = app.StakingKeeper.GetHistoricalInfo(ctx, 5) + require.False(t, found, "GetHistoricalInfo did not prune first prune height") + require.Equal(t, types.HistoricalInfo{}, recv, "GetHistoricalInfo at height 5 is not empty after prune") +} From a63de303b8005a9143e696d8918bb4101d605a2c Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Tue, 18 Feb 2020 14:43:00 +0100 Subject: [PATCH 147/529] Merge PR #5665: Bump Module ABCI Error Codes --- types/errors/abci.go | 7 +-- x/auth/types/errors.go | 8 ++- x/bank/internal/types/errors.go | 8 +-- x/crisis/internal/types/errors.go | 4 +- x/distribution/types/errors.go | 24 ++++---- x/evidence/internal/types/errors.go | 8 +-- x/gov/types/errors.go | 16 ++--- x/params/types/errors.go | 12 ++-- x/slashing/internal/types/errors.go | 14 ++--- x/staking/types/errors.go | 92 ++++++++++++++--------------- 10 files changed, 97 insertions(+), 96 deletions(-) diff --git a/types/errors/abci.go b/types/errors/abci.go index cc5633543192..04ba8413d374 100644 --- a/types/errors/abci.go +++ b/types/errors/abci.go @@ -154,10 +154,9 @@ func errIsNil(err error) bool { return false } -// Redact replace all errors that do not initialize with a weave error with a -// generic internal error instance. This function is supposed to hide -// implementation details errors and leave only those that weave framework -// originates. +// Redact replaces an error that is not initialized as an ABCI Error with a +// generic internal error instance. If the error is an ABCI Error, that error is +// simply returned. func Redact(err error) error { if ErrPanic.Is(err) { return errors.New(internalABCILog) diff --git a/x/auth/types/errors.go b/x/auth/types/errors.go index 3333cc8a467a..8e765ceb9891 100644 --- a/x/auth/types/errors.go +++ b/x/auth/types/errors.go @@ -1,8 +1,10 @@ package types -import "errors" +import ( + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) var ( - ErrorInvalidSigner = errors.New("tx intended signer does not match the given signer") - ErrorInvalidGasAdjustment = errors.New("invalid gas adjustment") + ErrorInvalidSigner = sdkerrors.Register(ModuleName, 2, "tx intended signer does not match the given signer") + ErrorInvalidGasAdjustment = sdkerrors.Register(ModuleName, 3, "invalid gas adjustment") ) diff --git a/x/bank/internal/types/errors.go b/x/bank/internal/types/errors.go index 157408c941b7..dce69d0ac6bf 100644 --- a/x/bank/internal/types/errors.go +++ b/x/bank/internal/types/errors.go @@ -6,8 +6,8 @@ import ( // x/bank module sentinel errors var ( - ErrNoInputs = sdkerrors.Register(ModuleName, 1, "no inputs to send transaction") - ErrNoOutputs = sdkerrors.Register(ModuleName, 2, "no outputs to send transaction") - ErrInputOutputMismatch = sdkerrors.Register(ModuleName, 3, "sum inputs != sum outputs") - ErrSendDisabled = sdkerrors.Register(ModuleName, 4, "send transactions are disabled") + ErrNoInputs = sdkerrors.Register(ModuleName, 2, "no inputs to send transaction") + ErrNoOutputs = sdkerrors.Register(ModuleName, 3, "no outputs to send transaction") + ErrInputOutputMismatch = sdkerrors.Register(ModuleName, 4, "sum inputs != sum outputs") + ErrSendDisabled = sdkerrors.Register(ModuleName, 5, "send transactions are disabled") ) diff --git a/x/crisis/internal/types/errors.go b/x/crisis/internal/types/errors.go index ac63f3ff43de..cf8c4901b315 100644 --- a/x/crisis/internal/types/errors.go +++ b/x/crisis/internal/types/errors.go @@ -6,6 +6,6 @@ import ( // x/crisis module sentinel errors var ( - ErrNoSender = sdkerrors.Register(ModuleName, 1, "sender address is empty") - ErrUnknownInvariant = sdkerrors.Register(ModuleName, 2, "unknown invariant") + ErrNoSender = sdkerrors.Register(ModuleName, 2, "sender address is empty") + ErrUnknownInvariant = sdkerrors.Register(ModuleName, 3, "unknown invariant") ) diff --git a/x/distribution/types/errors.go b/x/distribution/types/errors.go index c06b731b6ee4..147cfd320341 100644 --- a/x/distribution/types/errors.go +++ b/x/distribution/types/errors.go @@ -6,16 +6,16 @@ import ( // x/distribution module sentinel errors var ( - ErrEmptyDelegatorAddr = sdkerrors.Register(ModuleName, 1, "delegator address is empty") - ErrEmptyWithdrawAddr = sdkerrors.Register(ModuleName, 2, "withdraw address is empty") - ErrEmptyValidatorAddr = sdkerrors.Register(ModuleName, 3, "validator address is empty") - ErrEmptyDelegationDistInfo = sdkerrors.Register(ModuleName, 4, "no delegation distribution info") - ErrNoValidatorDistInfo = sdkerrors.Register(ModuleName, 5, "no validator distribution info") - ErrNoValidatorCommission = sdkerrors.Register(ModuleName, 6, "no validator commission to withdraw") - ErrSetWithdrawAddrDisabled = sdkerrors.Register(ModuleName, 7, "set withdraw address disabled") - ErrBadDistribution = sdkerrors.Register(ModuleName, 8, "community pool does not have sufficient coins to distribute") - ErrInvalidProposalAmount = sdkerrors.Register(ModuleName, 9, "invalid community pool spend proposal amount") - ErrEmptyProposalRecipient = sdkerrors.Register(ModuleName, 10, "invalid community pool spend proposal recipient") - ErrNoValidatorExists = sdkerrors.Register(ModuleName, 11, "validator does not exist") - ErrNoDelegationExists = sdkerrors.Register(ModuleName, 12, "delegation does not exist") + ErrEmptyDelegatorAddr = sdkerrors.Register(ModuleName, 2, "delegator address is empty") + ErrEmptyWithdrawAddr = sdkerrors.Register(ModuleName, 3, "withdraw address is empty") + ErrEmptyValidatorAddr = sdkerrors.Register(ModuleName, 4, "validator address is empty") + ErrEmptyDelegationDistInfo = sdkerrors.Register(ModuleName, 5, "no delegation distribution info") + ErrNoValidatorDistInfo = sdkerrors.Register(ModuleName, 6, "no validator distribution info") + ErrNoValidatorCommission = sdkerrors.Register(ModuleName, 7, "no validator commission to withdraw") + ErrSetWithdrawAddrDisabled = sdkerrors.Register(ModuleName, 8, "set withdraw address disabled") + ErrBadDistribution = sdkerrors.Register(ModuleName, 9, "community pool does not have sufficient coins to distribute") + ErrInvalidProposalAmount = sdkerrors.Register(ModuleName, 10, "invalid community pool spend proposal amount") + ErrEmptyProposalRecipient = sdkerrors.Register(ModuleName, 11, "invalid community pool spend proposal recipient") + ErrNoValidatorExists = sdkerrors.Register(ModuleName, 12, "validator does not exist") + ErrNoDelegationExists = sdkerrors.Register(ModuleName, 13, "delegation does not exist") ) diff --git a/x/evidence/internal/types/errors.go b/x/evidence/internal/types/errors.go index 83ffe06002ae..f44802709149 100644 --- a/x/evidence/internal/types/errors.go +++ b/x/evidence/internal/types/errors.go @@ -7,8 +7,8 @@ import ( // x/evidence module sentinel errors var ( - ErrNoEvidenceHandlerExists = sdkerrors.Register(ModuleName, 1, "unregistered handler for evidence type") - ErrInvalidEvidence = sdkerrors.Register(ModuleName, 2, "invalid evidence") - ErrNoEvidenceExists = sdkerrors.Register(ModuleName, 3, "evidence does not exist") - ErrEvidenceExists = sdkerrors.Register(ModuleName, 4, "evidence already exists") + ErrNoEvidenceHandlerExists = sdkerrors.Register(ModuleName, 2, "unregistered handler for evidence type") + ErrInvalidEvidence = sdkerrors.Register(ModuleName, 3, "invalid evidence") + ErrNoEvidenceExists = sdkerrors.Register(ModuleName, 4, "evidence does not exist") + ErrEvidenceExists = sdkerrors.Register(ModuleName, 5, "evidence already exists") ) diff --git a/x/gov/types/errors.go b/x/gov/types/errors.go index 2327a6f05b5e..96973f1751a2 100644 --- a/x/gov/types/errors.go +++ b/x/gov/types/errors.go @@ -6,12 +6,12 @@ import ( // x/gov module sentinel errors var ( - ErrUnknownProposal = sdkerrors.Register(ModuleName, 1, "unknown proposal") - ErrInactiveProposal = sdkerrors.Register(ModuleName, 2, "inactive proposal") - ErrAlreadyActiveProposal = sdkerrors.Register(ModuleName, 3, "proposal already active") - ErrInvalidProposalContent = sdkerrors.Register(ModuleName, 4, "invalid proposal content") - ErrInvalidProposalType = sdkerrors.Register(ModuleName, 5, "invalid proposal type") - ErrInvalidVote = sdkerrors.Register(ModuleName, 6, "invalid vote option") - ErrInvalidGenesis = sdkerrors.Register(ModuleName, 7, "invalid genesis state") - ErrNoProposalHandlerExists = sdkerrors.Register(ModuleName, 8, "no handler exists for proposal type") + ErrUnknownProposal = sdkerrors.Register(ModuleName, 2, "unknown proposal") + ErrInactiveProposal = sdkerrors.Register(ModuleName, 3, "inactive proposal") + ErrAlreadyActiveProposal = sdkerrors.Register(ModuleName, 4, "proposal already active") + ErrInvalidProposalContent = sdkerrors.Register(ModuleName, 5, "invalid proposal content") + ErrInvalidProposalType = sdkerrors.Register(ModuleName, 6, "invalid proposal type") + ErrInvalidVote = sdkerrors.Register(ModuleName, 7, "invalid vote option") + ErrInvalidGenesis = sdkerrors.Register(ModuleName, 8, "invalid genesis state") + ErrNoProposalHandlerExists = sdkerrors.Register(ModuleName, 9, "no handler exists for proposal type") ) diff --git a/x/params/types/errors.go b/x/params/types/errors.go index 4b218d9444ee..0611a3de214b 100644 --- a/x/params/types/errors.go +++ b/x/params/types/errors.go @@ -6,10 +6,10 @@ import ( // x/params module sentinel errors var ( - ErrUnknownSubspace = sdkerrors.Register(ModuleName, 1, "unknown subspace") - ErrSettingParameter = sdkerrors.Register(ModuleName, 2, "failed to set parameter") - ErrEmptyChanges = sdkerrors.Register(ModuleName, 3, "submitted parameter changes are empty") - ErrEmptySubspace = sdkerrors.Register(ModuleName, 4, "parameter subspace is empty") - ErrEmptyKey = sdkerrors.Register(ModuleName, 5, "parameter key is empty") - ErrEmptyValue = sdkerrors.Register(ModuleName, 6, "parameter value is empty") + ErrUnknownSubspace = sdkerrors.Register(ModuleName, 2, "unknown subspace") + ErrSettingParameter = sdkerrors.Register(ModuleName, 3, "failed to set parameter") + ErrEmptyChanges = sdkerrors.Register(ModuleName, 4, "submitted parameter changes are empty") + ErrEmptySubspace = sdkerrors.Register(ModuleName, 5, "parameter subspace is empty") + ErrEmptyKey = sdkerrors.Register(ModuleName, 6, "parameter key is empty") + ErrEmptyValue = sdkerrors.Register(ModuleName, 7, "parameter value is empty") ) diff --git a/x/slashing/internal/types/errors.go b/x/slashing/internal/types/errors.go index 290ed36cad66..daff6ecc04af 100644 --- a/x/slashing/internal/types/errors.go +++ b/x/slashing/internal/types/errors.go @@ -6,11 +6,11 @@ import ( // x/slashing module sentinel errors var ( - ErrNoValidatorForAddress = sdkerrors.Register(ModuleName, 1, "address is not associated with any known validator") - ErrBadValidatorAddr = sdkerrors.Register(ModuleName, 2, "validator does not exist for that address") - ErrValidatorJailed = sdkerrors.Register(ModuleName, 3, "validator still jailed; cannot be unjailed") - ErrValidatorNotJailed = sdkerrors.Register(ModuleName, 4, "validator not jailed; cannot be unjailed") - ErrMissingSelfDelegation = sdkerrors.Register(ModuleName, 5, "validator has no self-delegation; cannot be unjailed") - ErrSelfDelegationTooLowToUnjail = sdkerrors.Register(ModuleName, 6, "validator's self delegation less than minimum; cannot be unjailed") - ErrNoSigningInfoFound = sdkerrors.Register(ModuleName, 7, "no validator signing info found") + ErrNoValidatorForAddress = sdkerrors.Register(ModuleName, 2, "address is not associated with any known validator") + ErrBadValidatorAddr = sdkerrors.Register(ModuleName, 3, "validator does not exist for that address") + ErrValidatorJailed = sdkerrors.Register(ModuleName, 4, "validator still jailed; cannot be unjailed") + ErrValidatorNotJailed = sdkerrors.Register(ModuleName, 5, "validator not jailed; cannot be unjailed") + ErrMissingSelfDelegation = sdkerrors.Register(ModuleName, 6, "validator has no self-delegation; cannot be unjailed") + ErrSelfDelegationTooLowToUnjail = sdkerrors.Register(ModuleName, 7, "validator's self delegation less than minimum; cannot be unjailed") + ErrNoSigningInfoFound = sdkerrors.Register(ModuleName, 8, "no validator signing info found") ) diff --git a/x/staking/types/errors.go b/x/staking/types/errors.go index 62fdd0725b90..d6c31a15dc74 100644 --- a/x/staking/types/errors.go +++ b/x/staking/types/errors.go @@ -11,50 +11,50 @@ import ( // // REF: https://github.com/cosmos/cosmos-sdk/issues/5450 var ( - ErrEmptyValidatorAddr = sdkerrors.Register(ModuleName, 1, "empty validator address") - ErrBadValidatorAddr = sdkerrors.Register(ModuleName, 2, "validator address is invalid") - ErrNoValidatorFound = sdkerrors.Register(ModuleName, 3, "validator does not exist") - ErrValidatorOwnerExists = sdkerrors.Register(ModuleName, 4, "validator already exist for this operator address; must use new validator operator address") - ErrValidatorPubKeyExists = sdkerrors.Register(ModuleName, 5, "validator already exist for this pubkey; must use new validator pubkey") - ErrValidatorPubKeyTypeNotSupported = sdkerrors.Register(ModuleName, 6, "validator pubkey type is not supported") - ErrValidatorJailed = sdkerrors.Register(ModuleName, 7, "validator for this address is currently jailed") - ErrBadRemoveValidator = sdkerrors.Register(ModuleName, 8, "failed to remove validator") - ErrCommissionNegative = sdkerrors.Register(ModuleName, 9, "commission must be positive") - ErrCommissionHuge = sdkerrors.Register(ModuleName, 10, "commission cannot be more than 100%") - ErrCommissionGTMaxRate = sdkerrors.Register(ModuleName, 11, "commission cannot be more than the max rate") - ErrCommissionUpdateTime = sdkerrors.Register(ModuleName, 12, "commission cannot be changed more than once in 24h") - ErrCommissionChangeRateNegative = sdkerrors.Register(ModuleName, 13, "commission change rate must be positive") - ErrCommissionChangeRateGTMaxRate = sdkerrors.Register(ModuleName, 14, "commission change rate cannot be more than the max rate") - ErrCommissionGTMaxChangeRate = sdkerrors.Register(ModuleName, 15, "commission cannot be changed more than max change rate") - ErrSelfDelegationBelowMinimum = sdkerrors.Register(ModuleName, 16, "validator's self delegation must be greater than their minimum self delegation") - ErrMinSelfDelegationInvalid = sdkerrors.Register(ModuleName, 17, "minimum self delegation must be a positive integer") - ErrMinSelfDelegationDecreased = sdkerrors.Register(ModuleName, 18, "minimum self delegation cannot be decrease") - ErrEmptyDelegatorAddr = sdkerrors.Register(ModuleName, 19, "empty delegator address") - ErrBadDenom = sdkerrors.Register(ModuleName, 20, "invalid coin denomination") - ErrBadDelegationAddr = sdkerrors.Register(ModuleName, 21, "invalid address for (address, validator) tuple") - ErrBadDelegationAmount = sdkerrors.Register(ModuleName, 22, "invalid delegation amount") - ErrNoDelegation = sdkerrors.Register(ModuleName, 23, "no delegation for (address, validator) tuple") - ErrBadDelegatorAddr = sdkerrors.Register(ModuleName, 24, "delegator does not exist with address") - ErrNoDelegatorForAddress = sdkerrors.Register(ModuleName, 25, "delegator does not contain delegation") - ErrInsufficientShares = sdkerrors.Register(ModuleName, 26, "insufficient delegation shares") - ErrDelegationValidatorEmpty = sdkerrors.Register(ModuleName, 27, "cannot delegate to an empty validator") - ErrNotEnoughDelegationShares = sdkerrors.Register(ModuleName, 28, "not enough delegation shares") - ErrBadSharesAmount = sdkerrors.Register(ModuleName, 29, "invalid shares amount") - ErrBadSharesPercent = sdkerrors.Register(ModuleName, 30, "Invalid shares percent") - ErrNotMature = sdkerrors.Register(ModuleName, 31, "entry not mature") - ErrNoUnbondingDelegation = sdkerrors.Register(ModuleName, 32, "no unbonding delegation found") - ErrMaxUnbondingDelegationEntries = sdkerrors.Register(ModuleName, 33, "too many unbonding delegation entries for (delegator, validator) tuple") - ErrBadRedelegationAddr = sdkerrors.Register(ModuleName, 34, "invalid address for (address, src-validator, dst-validator) tuple") - ErrNoRedelegation = sdkerrors.Register(ModuleName, 35, "no redelegation found") - ErrSelfRedelegation = sdkerrors.Register(ModuleName, 36, "cannot redelegate to the same validator") - ErrTinyRedelegationAmount = sdkerrors.Register(ModuleName, 37, "too few tokens to redelegate (truncates to zero tokens)") - ErrBadRedelegationDst = sdkerrors.Register(ModuleName, 38, "redelegation destination validator not found") - ErrTransitiveRedelegation = sdkerrors.Register(ModuleName, 39, "redelegation to this validator already in progress; first redelegation to this validator must complete before next redelegation") - ErrMaxRedelegationEntries = sdkerrors.Register(ModuleName, 40, "too many redelegation entries for (delegator, src-validator, dst-validator) tuple") - ErrDelegatorShareExRateInvalid = sdkerrors.Register(ModuleName, 41, "cannot delegate to validators with invalid (zero) ex-rate") - ErrBothShareMsgsGiven = sdkerrors.Register(ModuleName, 42, "both shares amount and shares percent provided") - ErrNeitherShareMsgsGiven = sdkerrors.Register(ModuleName, 43, "neither shares amount nor shares percent provided") - ErrInvalidHistoricalInfo = sdkerrors.Register(ModuleName, 44, "invalid historical info") - ErrNoHistoricalInfo = sdkerrors.Register(ModuleName, 45, "no historical info found") - ErrEmptyValidatorPubKey = sdkerrors.Register(ModuleName, 46, "empty validator public key") + ErrEmptyValidatorAddr = sdkerrors.Register(ModuleName, 2, "empty validator address") + ErrBadValidatorAddr = sdkerrors.Register(ModuleName, 3, "validator address is invalid") + ErrNoValidatorFound = sdkerrors.Register(ModuleName, 4, "validator does not exist") + ErrValidatorOwnerExists = sdkerrors.Register(ModuleName, 5, "validator already exist for this operator address; must use new validator operator address") + ErrValidatorPubKeyExists = sdkerrors.Register(ModuleName, 6, "validator already exist for this pubkey; must use new validator pubkey") + ErrValidatorPubKeyTypeNotSupported = sdkerrors.Register(ModuleName, 7, "validator pubkey type is not supported") + ErrValidatorJailed = sdkerrors.Register(ModuleName, 8, "validator for this address is currently jailed") + ErrBadRemoveValidator = sdkerrors.Register(ModuleName, 9, "failed to remove validator") + ErrCommissionNegative = sdkerrors.Register(ModuleName, 10, "commission must be positive") + ErrCommissionHuge = sdkerrors.Register(ModuleName, 11, "commission cannot be more than 100%") + ErrCommissionGTMaxRate = sdkerrors.Register(ModuleName, 12, "commission cannot be more than the max rate") + ErrCommissionUpdateTime = sdkerrors.Register(ModuleName, 13, "commission cannot be changed more than once in 24h") + ErrCommissionChangeRateNegative = sdkerrors.Register(ModuleName, 14, "commission change rate must be positive") + ErrCommissionChangeRateGTMaxRate = sdkerrors.Register(ModuleName, 15, "commission change rate cannot be more than the max rate") + ErrCommissionGTMaxChangeRate = sdkerrors.Register(ModuleName, 16, "commission cannot be changed more than max change rate") + ErrSelfDelegationBelowMinimum = sdkerrors.Register(ModuleName, 17, "validator's self delegation must be greater than their minimum self delegation") + ErrMinSelfDelegationInvalid = sdkerrors.Register(ModuleName, 18, "minimum self delegation must be a positive integer") + ErrMinSelfDelegationDecreased = sdkerrors.Register(ModuleName, 19, "minimum self delegation cannot be decrease") + ErrEmptyDelegatorAddr = sdkerrors.Register(ModuleName, 20, "empty delegator address") + ErrBadDenom = sdkerrors.Register(ModuleName, 21, "invalid coin denomination") + ErrBadDelegationAddr = sdkerrors.Register(ModuleName, 22, "invalid address for (address, validator) tuple") + ErrBadDelegationAmount = sdkerrors.Register(ModuleName, 23, "invalid delegation amount") + ErrNoDelegation = sdkerrors.Register(ModuleName, 24, "no delegation for (address, validator) tuple") + ErrBadDelegatorAddr = sdkerrors.Register(ModuleName, 25, "delegator does not exist with address") + ErrNoDelegatorForAddress = sdkerrors.Register(ModuleName, 26, "delegator does not contain delegation") + ErrInsufficientShares = sdkerrors.Register(ModuleName, 27, "insufficient delegation shares") + ErrDelegationValidatorEmpty = sdkerrors.Register(ModuleName, 28, "cannot delegate to an empty validator") + ErrNotEnoughDelegationShares = sdkerrors.Register(ModuleName, 29, "not enough delegation shares") + ErrBadSharesAmount = sdkerrors.Register(ModuleName, 30, "invalid shares amount") + ErrBadSharesPercent = sdkerrors.Register(ModuleName, 31, "Invalid shares percent") + ErrNotMature = sdkerrors.Register(ModuleName, 32, "entry not mature") + ErrNoUnbondingDelegation = sdkerrors.Register(ModuleName, 33, "no unbonding delegation found") + ErrMaxUnbondingDelegationEntries = sdkerrors.Register(ModuleName, 34, "too many unbonding delegation entries for (delegator, validator) tuple") + ErrBadRedelegationAddr = sdkerrors.Register(ModuleName, 35, "invalid address for (address, src-validator, dst-validator) tuple") + ErrNoRedelegation = sdkerrors.Register(ModuleName, 36, "no redelegation found") + ErrSelfRedelegation = sdkerrors.Register(ModuleName, 37, "cannot redelegate to the same validator") + ErrTinyRedelegationAmount = sdkerrors.Register(ModuleName, 38, "too few tokens to redelegate (truncates to zero tokens)") + ErrBadRedelegationDst = sdkerrors.Register(ModuleName, 39, "redelegation destination validator not found") + ErrTransitiveRedelegation = sdkerrors.Register(ModuleName, 40, "redelegation to this validator already in progress; first redelegation to this validator must complete before next redelegation") + ErrMaxRedelegationEntries = sdkerrors.Register(ModuleName, 41, "too many redelegation entries for (delegator, src-validator, dst-validator) tuple") + ErrDelegatorShareExRateInvalid = sdkerrors.Register(ModuleName, 42, "cannot delegate to validators with invalid (zero) ex-rate") + ErrBothShareMsgsGiven = sdkerrors.Register(ModuleName, 43, "both shares amount and shares percent provided") + ErrNeitherShareMsgsGiven = sdkerrors.Register(ModuleName, 44, "neither shares amount nor shares percent provided") + ErrInvalidHistoricalInfo = sdkerrors.Register(ModuleName, 45, "invalid historical info") + ErrNoHistoricalInfo = sdkerrors.Register(ModuleName, 46, "no historical info found") + ErrEmptyValidatorPubKey = sdkerrors.Register(ModuleName, 47, "empty validator public key") ) From c84c5922e4acb199bd7c69bd7d6af7c5bcc96af6 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Tue, 18 Feb 2020 16:44:23 +0100 Subject: [PATCH 148/529] temporal commit on querier test, it passes --- x/staking/keeper/common_refactor_test.go | 2 +- x/staking/keeper/querier_test.go | 889 ++++++++++++----------- 2 files changed, 451 insertions(+), 440 deletions(-) diff --git a/x/staking/keeper/common_refactor_test.go b/x/staking/keeper/common_refactor_test.go index 33a4f0c1ab50..8b43af1739f2 100644 --- a/x/staking/keeper/common_refactor_test.go +++ b/x/staking/keeper/common_refactor_test.go @@ -5,10 +5,10 @@ import ( "encoding/hex" "strconv" + "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/ed25519" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/tendermint/tendermint/crypto" ) var ( diff --git a/x/staking/keeper/querier_test.go b/x/staking/keeper/querier_test.go index 2bbd468ae075..202290762ba5 100644 --- a/x/staking/keeper/querier_test.go +++ b/x/staking/keeper/querier_test.go @@ -1,4 +1,4 @@ -package keeper +package keeper_test import ( "fmt" @@ -8,7 +8,9 @@ import ( abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/staking" "github.com/cosmos/cosmos-sdk/x/staking/types" ) @@ -20,15 +22,17 @@ var ( func TestNewQuerier(t *testing.T) { cdc := codec.New() - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + // Create Validators amts := []sdk.Int{sdk.NewInt(9), sdk.NewInt(8)} var validators [2]types.Validator for i, amt := range amts { validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) validators[i], _ = validators[i].AddTokensFromDel(amt) - keeper.SetValidator(ctx, validators[i]) - keeper.SetValidatorByPowerIndex(ctx, validators[i]) + app.StakingKeeper.SetValidator(ctx, validators[i]) + app.StakingKeeper.SetValidatorByPowerIndex(ctx, validators[i]) } header := abci.Header{ @@ -36,14 +40,14 @@ func TestNewQuerier(t *testing.T) { Height: 5, } hi := types.NewHistoricalInfo(header, validators[:]) - keeper.SetHistoricalInfo(ctx, 5, hi) + app.StakingKeeper.SetHistoricalInfo(ctx, 5, hi) query := abci.RequestQuery{ Path: "", Data: []byte{}, } - querier := NewQuerier(keeper) + querier := staking.NewQuerier(app.StakingKeeper) bz, err := querier(ctx, []string{"other"}, query) require.Error(t, err) @@ -107,32 +111,37 @@ func TestNewQuerier(t *testing.T) { func TestQueryParametersPool(t *testing.T) { cdc := codec.New() - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + querier := staking.NewQuerier(app.StakingKeeper) + bondDenom := sdk.DefaultBondDenom - res, err := queryParameters(ctx, keeper) + res, err := querier(ctx, []string{staking.QueryParameters}, abci.RequestQuery{}) require.NoError(t, err) var params types.Params errRes := cdc.UnmarshalJSON(res, ¶ms) require.NoError(t, errRes) - require.Equal(t, keeper.GetParams(ctx), params) + require.Equal(t, app.StakingKeeper.GetParams(ctx), params) - res, err = queryPool(ctx, keeper) + res, err = querier(ctx, []string{staking.QueryPool}, abci.RequestQuery{}) require.NoError(t, err) var pool types.Pool - bondedPool := keeper.GetBondedPool(ctx) - notBondedPool := keeper.GetNotBondedPool(ctx) + bondedPool := app.StakingKeeper.GetBondedPool(ctx) + notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) require.NoError(t, cdc.UnmarshalJSON(res, &pool)) - require.Equal(t, keeper.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount, pool.NotBondedTokens) - require.Equal(t, keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount, pool.BondedTokens) + require.Equal(t, app.BankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount, pool.NotBondedTokens) + require.Equal(t, app.BankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount, pool.BondedTokens) } func TestQueryValidators(t *testing.T) { cdc := codec.New() - ctx, _, _, keeper, _ := CreateTestInput(t, false, 10000) - params := keeper.GetParams(ctx) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + params := app.StakingKeeper.GetParams(ctx) + querier := staking.NewQuerier(app.StakingKeeper) // Create Validators amts := []sdk.Int{sdk.NewInt(9), sdk.NewInt(8), sdk.NewInt(7)} @@ -144,12 +153,12 @@ func TestQueryValidators(t *testing.T) { validators[i] = validators[i].UpdateStatus(status[i]) } - keeper.SetValidator(ctx, validators[0]) - keeper.SetValidator(ctx, validators[1]) - keeper.SetValidator(ctx, validators[2]) + app.StakingKeeper.SetValidator(ctx, validators[0]) + app.StakingKeeper.SetValidator(ctx, validators[1]) + app.StakingKeeper.SetValidator(ctx, validators[2]) // Query Validators - queriedValidators := keeper.GetValidators(ctx, params.MaxValidators) + queriedValidators := app.StakingKeeper.GetValidators(ctx, params.MaxValidators) for i, s := range status { queryValsParams := types.NewQueryValidatorsParams(1, int(params.MaxValidators), s.String()) @@ -161,7 +170,7 @@ func TestQueryValidators(t *testing.T) { Data: bz, } - res, err := queryValidators(ctx, req, keeper) + res, err := querier(ctx, []string{types.QueryValidators}, req) require.NoError(t, err) var validatorsResp []types.Validator @@ -182,7 +191,7 @@ func TestQueryValidators(t *testing.T) { Path: "/custom/staking/validator", Data: bz, } - res, err := queryValidator(ctx, query, keeper) + res, err := querier(ctx, []string{types.QueryValidator}, query) require.NoError(t, err) var validator types.Validator @@ -192,420 +201,422 @@ func TestQueryValidators(t *testing.T) { require.Equal(t, queriedValidators[0], validator) } -func TestQueryDelegation(t *testing.T) { - cdc := codec.New() - ctx, _, _, keeper, _ := CreateTestInput(t, false, 10000) - params := keeper.GetParams(ctx) - - // Create Validators and Delegation - val1 := types.NewValidator(addrVal1, pk1, types.Description{}) - keeper.SetValidator(ctx, val1) - keeper.SetValidatorByPowerIndex(ctx, val1) - - val2 := types.NewValidator(addrVal2, pk2, types.Description{}) - keeper.SetValidator(ctx, val2) - keeper.SetValidatorByPowerIndex(ctx, val2) - - delTokens := sdk.TokensFromConsensusPower(20) - keeper.Delegate(ctx, addrAcc2, delTokens, sdk.Unbonded, val1, true) - - // apply TM updates - keeper.ApplyAndReturnValidatorSetUpdates(ctx) - - // Query Delegator bonded validators - queryParams := types.NewQueryDelegatorParams(addrAcc2) - bz, errRes := cdc.MarshalJSON(queryParams) - require.NoError(t, errRes) - - query := abci.RequestQuery{ - Path: "/custom/staking/delegatorValidators", - Data: bz, - } - - delValidators := keeper.GetDelegatorValidators(ctx, addrAcc2, params.MaxValidators) - - res, err := queryDelegatorValidators(ctx, query, keeper) - require.NoError(t, err) - - var validatorsResp []types.Validator - errRes = cdc.UnmarshalJSON(res, &validatorsResp) - require.NoError(t, errRes) - - require.Equal(t, len(delValidators), len(validatorsResp)) - require.ElementsMatch(t, delValidators, validatorsResp) - - // error unknown request - query.Data = bz[:len(bz)-1] - - _, err = queryDelegatorValidators(ctx, query, keeper) - require.Error(t, err) - - // Query bonded validator - queryBondParams := types.NewQueryBondsParams(addrAcc2, addrVal1) - bz, errRes = cdc.MarshalJSON(queryBondParams) - require.NoError(t, errRes) - - query = abci.RequestQuery{ - Path: "/custom/staking/delegatorValidator", - Data: bz, - } - - res, err = queryDelegatorValidator(ctx, query, keeper) - require.NoError(t, err) - - var validator types.Validator - errRes = cdc.UnmarshalJSON(res, &validator) - require.NoError(t, errRes) - - require.Equal(t, delValidators[0], validator) - - // error unknown request - query.Data = bz[:len(bz)-1] - - _, err = queryDelegatorValidator(ctx, query, keeper) - require.Error(t, err) - - // Query delegation - - query = abci.RequestQuery{ - Path: "/custom/staking/delegation", - Data: bz, - } - - delegation, found := keeper.GetDelegation(ctx, addrAcc2, addrVal1) - require.True(t, found) - - res, err = queryDelegation(ctx, query, keeper) - require.NoError(t, err) - - var delegationRes types.DelegationResponse - errRes = cdc.UnmarshalJSON(res, &delegationRes) - require.NoError(t, errRes) - - require.Equal(t, delegation.ValidatorAddress, delegationRes.ValidatorAddress) - require.Equal(t, delegation.DelegatorAddress, delegationRes.DelegatorAddress) - require.Equal(t, sdk.NewCoin(sdk.DefaultBondDenom, delegation.Shares.TruncateInt()), delegationRes.Balance) - - // Query Delegator Delegations - query = abci.RequestQuery{ - Path: "/custom/staking/delegatorDelegations", - Data: bz, - } - - res, err = queryDelegatorDelegations(ctx, query, keeper) - require.NoError(t, err) - - var delegatorDelegations types.DelegationResponses - errRes = cdc.UnmarshalJSON(res, &delegatorDelegations) - require.NoError(t, errRes) - require.Len(t, delegatorDelegations, 1) - require.Equal(t, delegation.ValidatorAddress, delegatorDelegations[0].ValidatorAddress) - require.Equal(t, delegation.DelegatorAddress, delegatorDelegations[0].DelegatorAddress) - require.Equal(t, sdk.NewCoin(sdk.DefaultBondDenom, delegation.Shares.TruncateInt()), delegatorDelegations[0].Balance) - - // error unknown request - query.Data = bz[:len(bz)-1] - - _, err = queryDelegation(ctx, query, keeper) - require.Error(t, err) - - // Query validator delegations - - bz, errRes = cdc.MarshalJSON(types.NewQueryValidatorParams(addrVal1)) - require.NoError(t, errRes) - - query = abci.RequestQuery{ - Path: "custom/staking/validatorDelegations", - Data: bz, - } - - res, err = queryValidatorDelegations(ctx, query, keeper) - require.NoError(t, err) - - var delegationsRes types.DelegationResponses - errRes = cdc.UnmarshalJSON(res, &delegationsRes) - require.NoError(t, errRes) - require.Len(t, delegatorDelegations, 1) - require.Equal(t, delegation.ValidatorAddress, delegationsRes[0].ValidatorAddress) - require.Equal(t, delegation.DelegatorAddress, delegationsRes[0].DelegatorAddress) - require.Equal(t, sdk.NewCoin(sdk.DefaultBondDenom, delegation.Shares.TruncateInt()), delegationsRes[0].Balance) - - // Query unbonging delegation - unbondingTokens := sdk.TokensFromConsensusPower(10) - _, err = keeper.Undelegate(ctx, addrAcc2, val1.OperatorAddress, unbondingTokens.ToDec()) - require.NoError(t, err) - - queryBondParams = types.NewQueryBondsParams(addrAcc2, addrVal1) - bz, errRes = cdc.MarshalJSON(queryBondParams) - require.NoError(t, errRes) - - query = abci.RequestQuery{ - Path: "/custom/staking/unbondingDelegation", - Data: bz, - } - - unbond, found := keeper.GetUnbondingDelegation(ctx, addrAcc2, addrVal1) - require.True(t, found) - - res, err = queryUnbondingDelegation(ctx, query, keeper) - require.NoError(t, err) - - var unbondRes types.UnbondingDelegation - errRes = cdc.UnmarshalJSON(res, &unbondRes) - require.NoError(t, errRes) - - require.Equal(t, unbond, unbondRes) - - // error unknown request - query.Data = bz[:len(bz)-1] - - _, err = queryUnbondingDelegation(ctx, query, keeper) - require.Error(t, err) - - // Query Delegator Delegations - - query = abci.RequestQuery{ - Path: "/custom/staking/delegatorUnbondingDelegations", - Data: bz, - } - - res, err = queryDelegatorUnbondingDelegations(ctx, query, keeper) - require.NoError(t, err) - - var delegatorUbds []types.UnbondingDelegation - errRes = cdc.UnmarshalJSON(res, &delegatorUbds) - require.NoError(t, errRes) - require.Equal(t, unbond, delegatorUbds[0]) - - // error unknown request - query.Data = bz[:len(bz)-1] - - _, err = queryDelegatorUnbondingDelegations(ctx, query, keeper) - require.Error(t, err) - - // Query redelegation - redelegationTokens := sdk.TokensFromConsensusPower(10) - _, err = keeper.BeginRedelegation(ctx, addrAcc2, val1.OperatorAddress, - val2.OperatorAddress, redelegationTokens.ToDec()) - require.NoError(t, err) - redel, found := keeper.GetRedelegation(ctx, addrAcc2, val1.OperatorAddress, val2.OperatorAddress) - require.True(t, found) - - bz, errRes = cdc.MarshalJSON(types.NewQueryRedelegationParams(addrAcc2, val1.OperatorAddress, val2.OperatorAddress)) - require.NoError(t, errRes) - - query = abci.RequestQuery{ - Path: "/custom/staking/redelegations", - Data: bz, - } - - res, err = queryRedelegations(ctx, query, keeper) - require.NoError(t, err) - - var redelRes types.RedelegationResponses - errRes = cdc.UnmarshalJSON(res, &redelRes) - require.NoError(t, errRes) - require.Len(t, redelRes, 1) - require.Equal(t, redel.DelegatorAddress, redelRes[0].DelegatorAddress) - require.Equal(t, redel.ValidatorSrcAddress, redelRes[0].ValidatorSrcAddress) - require.Equal(t, redel.ValidatorDstAddress, redelRes[0].ValidatorDstAddress) - require.Len(t, redel.Entries, len(redelRes[0].Entries)) -} - -func TestQueryRedelegations(t *testing.T) { - cdc := codec.New() - ctx, _, _, keeper, _ := CreateTestInput(t, false, 10000) - - // Create Validators and Delegation - val1 := types.NewValidator(addrVal1, pk1, types.Description{}) - val2 := types.NewValidator(addrVal2, pk2, types.Description{}) - keeper.SetValidator(ctx, val1) - keeper.SetValidator(ctx, val2) - - delAmount := sdk.TokensFromConsensusPower(100) - keeper.Delegate(ctx, addrAcc2, delAmount, sdk.Unbonded, val1, true) - _ = keeper.ApplyAndReturnValidatorSetUpdates(ctx) - - rdAmount := sdk.TokensFromConsensusPower(20) - keeper.BeginRedelegation(ctx, addrAcc2, val1.GetOperator(), val2.GetOperator(), rdAmount.ToDec()) - keeper.ApplyAndReturnValidatorSetUpdates(ctx) - - redel, found := keeper.GetRedelegation(ctx, addrAcc2, val1.OperatorAddress, val2.OperatorAddress) - require.True(t, found) - - // delegator redelegations - queryDelegatorParams := types.NewQueryDelegatorParams(addrAcc2) - bz, errRes := cdc.MarshalJSON(queryDelegatorParams) - require.NoError(t, errRes) - - query := abci.RequestQuery{ - Path: "/custom/staking/redelegations", - Data: bz, - } - - res, err := queryRedelegations(ctx, query, keeper) - require.NoError(t, err) - - var redelRes types.RedelegationResponses - errRes = cdc.UnmarshalJSON(res, &redelRes) - require.NoError(t, errRes) - require.Len(t, redelRes, 1) - require.Equal(t, redel.DelegatorAddress, redelRes[0].DelegatorAddress) - require.Equal(t, redel.ValidatorSrcAddress, redelRes[0].ValidatorSrcAddress) - require.Equal(t, redel.ValidatorDstAddress, redelRes[0].ValidatorDstAddress) - require.Len(t, redel.Entries, len(redelRes[0].Entries)) - - // validator redelegations - queryValidatorParams := types.NewQueryValidatorParams(val1.GetOperator()) - bz, errRes = cdc.MarshalJSON(queryValidatorParams) - require.NoError(t, errRes) - - query = abci.RequestQuery{ - Path: "/custom/staking/redelegations", - Data: bz, - } - - res, err = queryRedelegations(ctx, query, keeper) - require.NoError(t, err) - - errRes = cdc.UnmarshalJSON(res, &redelRes) - require.NoError(t, errRes) - require.Len(t, redelRes, 1) - require.Equal(t, redel.DelegatorAddress, redelRes[0].DelegatorAddress) - require.Equal(t, redel.ValidatorSrcAddress, redelRes[0].ValidatorSrcAddress) - require.Equal(t, redel.ValidatorDstAddress, redelRes[0].ValidatorDstAddress) - require.Len(t, redel.Entries, len(redelRes[0].Entries)) -} - -func TestQueryUnbondingDelegation(t *testing.T) { - cdc := codec.New() - ctx, _, _, keeper, _ := CreateTestInput(t, false, 10000) - - // Create Validators and Delegation - val1 := types.NewValidator(addrVal1, pk1, types.Description{}) - keeper.SetValidator(ctx, val1) - - // delegate - delAmount := sdk.TokensFromConsensusPower(100) - _, err := keeper.Delegate(ctx, addrAcc1, delAmount, sdk.Unbonded, val1, true) - require.NoError(t, err) - _ = keeper.ApplyAndReturnValidatorSetUpdates(ctx) - - // undelegate - undelAmount := sdk.TokensFromConsensusPower(20) - _, err = keeper.Undelegate(ctx, addrAcc1, val1.GetOperator(), undelAmount.ToDec()) - require.NoError(t, err) - keeper.ApplyAndReturnValidatorSetUpdates(ctx) - - _, found := keeper.GetUnbondingDelegation(ctx, addrAcc1, val1.OperatorAddress) - require.True(t, found) - - // - // found: query unbonding delegation by delegator and validator - // - queryValidatorParams := types.NewQueryBondsParams(addrAcc1, val1.GetOperator()) - bz, errRes := cdc.MarshalJSON(queryValidatorParams) - require.NoError(t, errRes) - query := abci.RequestQuery{ - Path: "/custom/staking/unbondingDelegation", - Data: bz, - } - res, err := queryUnbondingDelegation(ctx, query, keeper) - require.NoError(t, err) - require.NotNil(t, res) - var ubDel types.UnbondingDelegation - require.NoError(t, cdc.UnmarshalJSON(res, &ubDel)) - require.Equal(t, addrAcc1, ubDel.DelegatorAddress) - require.Equal(t, val1.OperatorAddress, ubDel.ValidatorAddress) - require.Equal(t, 1, len(ubDel.Entries)) - - // - // not found: query unbonding delegation by delegator and validator - // - queryValidatorParams = types.NewQueryBondsParams(addrAcc2, val1.GetOperator()) - bz, errRes = cdc.MarshalJSON(queryValidatorParams) - require.NoError(t, errRes) - query = abci.RequestQuery{ - Path: "/custom/staking/unbondingDelegation", - Data: bz, - } - _, err = queryUnbondingDelegation(ctx, query, keeper) - require.Error(t, err) - - // - // found: query unbonding delegation by delegator and validator - // - queryDelegatorParams := types.NewQueryDelegatorParams(addrAcc1) - bz, errRes = cdc.MarshalJSON(queryDelegatorParams) - require.NoError(t, errRes) - query = abci.RequestQuery{ - Path: "/custom/staking/delegatorUnbondingDelegations", - Data: bz, - } - res, err = queryDelegatorUnbondingDelegations(ctx, query, keeper) - require.NoError(t, err) - require.NotNil(t, res) - var ubDels []types.UnbondingDelegation - require.NoError(t, cdc.UnmarshalJSON(res, &ubDels)) - require.Equal(t, 1, len(ubDels)) - require.Equal(t, addrAcc1, ubDels[0].DelegatorAddress) - require.Equal(t, val1.OperatorAddress, ubDels[0].ValidatorAddress) - - // - // not found: query unbonding delegation by delegator and validator - // - queryDelegatorParams = types.NewQueryDelegatorParams(addrAcc2) - bz, errRes = cdc.MarshalJSON(queryDelegatorParams) - require.NoError(t, errRes) - query = abci.RequestQuery{ - Path: "/custom/staking/delegatorUnbondingDelegations", - Data: bz, - } - res, err = queryDelegatorUnbondingDelegations(ctx, query, keeper) - require.NoError(t, err) - require.NotNil(t, res) - require.NoError(t, cdc.UnmarshalJSON(res, &ubDels)) - require.Equal(t, 0, len(ubDels)) -} - -func TestQueryHistoricalInfo(t *testing.T) { - cdc := codec.New() - ctx, _, _, keeper, _ := CreateTestInput(t, false, 10000) - - // Create Validators and Delegation - val1 := types.NewValidator(addrVal1, pk1, types.Description{}) - val2 := types.NewValidator(addrVal2, pk2, types.Description{}) - vals := []types.Validator{val1, val2} - keeper.SetValidator(ctx, val1) - keeper.SetValidator(ctx, val2) - - header := abci.Header{ - ChainID: "HelloChain", - Height: 5, - } - hi := types.NewHistoricalInfo(header, vals) - keeper.SetHistoricalInfo(ctx, 5, hi) - - queryHistoricalParams := types.NewQueryHistoricalInfoParams(4) - bz, errRes := cdc.MarshalJSON(queryHistoricalParams) - require.NoError(t, errRes) - query := abci.RequestQuery{ - Path: "/custom/staking/historicalInfo", - Data: bz, - } - res, err := queryHistoricalInfo(ctx, query, keeper) - require.Error(t, err, "Invalid query passed") - require.Nil(t, res, "Invalid query returned non-nil result") - - queryHistoricalParams = types.NewQueryHistoricalInfoParams(5) - bz, errRes = cdc.MarshalJSON(queryHistoricalParams) - require.NoError(t, errRes) - query.Data = bz - res, err = queryHistoricalInfo(ctx, query, keeper) - require.NoError(t, err, "Valid query passed") - require.NotNil(t, res, "Valid query returned nil result") - - var recv types.HistoricalInfo - require.NoError(t, cdc.UnmarshalJSON(res, &recv)) - require.Equal(t, hi, recv, "HistoricalInfo query returned wrong result") -} +//func TestQueryDelegation(t *testing.T) { +// cdc := codec.New() +// app := simapp.Setup(false) +// ctx := app.BaseApp.NewContext(false, abci.Header{}) +// params := app.StakingKeeper.GetParams(ctx) +// querier := staking.NewQuerier(app.StakingKeeper) +// +// // Create Validators and Delegation +// val1 := types.NewValidator(addrVal1, pk1, types.Description{}) +// app.StakingKeeper.SetValidator(ctx, val1) +// app.StakingKeeper.SetValidatorByPowerIndex(ctx, val1) +// +// val2 := types.NewValidator(addrVal2, pk2, types.Description{}) +// app.StakingKeeper.SetValidator(ctx, val2) +// app.StakingKeeper.SetValidatorByPowerIndex(ctx, val2) +// +// delTokens := sdk.TokensFromConsensusPower(20) +// app.StakingKeeper.Delegate(ctx, addrAcc2, delTokens, sdk.Unbonded, val1, true) +// +// // apply TM updates +// app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) +// +// // Query Delegator bonded validators +// queryParams := types.NewQueryDelegatorParams(addrAcc2) +// bz, errRes := cdc.MarshalJSON(queryParams) +// require.NoError(t, errRes) +// +// query := abci.RequestQuery{ +// Path: "/custom/staking/delegatorValidators", +// Data: bz, +// } +// +// delValidators := app.StakingKeeper.GetDelegatorValidators(ctx, addrAcc2, params.MaxValidators) +// +// res, err := querier(ctx, []string{types.QueryDelegatorValidators}, query) +// require.NoError(t, err) +// +// var validatorsResp []types.Validator +// errRes = cdc.UnmarshalJSON(res, &validatorsResp) +// require.NoError(t, errRes) +// +// require.Equal(t, len(delValidators), len(validatorsResp)) +// require.ElementsMatch(t, delValidators, validatorsResp) +// +// // error unknown request +// query.Data = bz[:len(bz)-1] +// +// res, err = querier(ctx, []string{types.QueryDelegatorValidators}, query) +// require.Error(t, err) +// +// // Query bonded validator +// queryBondParams := types.NewQueryBondsParams(addrAcc2, addrVal1) +// bz, errRes = cdc.MarshalJSON(queryBondParams) +// require.NoError(t, errRes) +// +// query = abci.RequestQuery{ +// Path: "/custom/staking/delegatorValidator", +// Data: bz, +// } +// +// res, err = querier(ctx, []string{types.QueryDelegatorValidator}, query) +// require.NoError(t, err) +// +// var validator types.Validator +// errRes = cdc.UnmarshalJSON(res, &validator) +// require.NoError(t, errRes) +// +// require.Equal(t, delValidators[0], validator) +// +// // error unknown request +// query.Data = bz[:len(bz)-1] +// +// res, err = querier(ctx, []string{types.QueryDelegatorValidator}, query) +// require.Error(t, err) +// +// // Query delegation +// +// query = abci.RequestQuery{ +// Path: "/custom/staking/delegation", +// Data: bz, +// } +// +// delegation, found := app.StakingKeeper.GetDelegation(ctx, addrAcc2, addrVal1) +// require.True(t, found) +// +// res, err = querier(ctx, []string{types.QueryDelegation}, query) +// require.NoError(t, err) +// +// var delegationRes types.DelegationResponse +// errRes = cdc.UnmarshalJSON(res, &delegationRes) +// require.NoError(t, errRes) +// +// require.Equal(t, delegation.ValidatorAddress, delegationRes.ValidatorAddress) +// require.Equal(t, delegation.DelegatorAddress, delegationRes.DelegatorAddress) +// require.Equal(t, sdk.NewCoin(sdk.DefaultBondDenom, delegation.Shares.TruncateInt()), delegationRes.Balance) +// +// // Query Delegator Delegations +// query = abci.RequestQuery{ +// Path: "/custom/staking/delegatorDelegations", +// Data: bz, +// } +// +// res, err = querier(ctx, []string{types.QueryDelegatorDelegations}, query) +// require.NoError(t, err) +// +// var delegatorDelegations types.DelegationResponses +// errRes = cdc.UnmarshalJSON(res, &delegatorDelegations) +// require.NoError(t, errRes) +// require.Len(t, delegatorDelegations, 1) +// require.Equal(t, delegation.ValidatorAddress, delegatorDelegations[0].ValidatorAddress) +// require.Equal(t, delegation.DelegatorAddress, delegatorDelegations[0].DelegatorAddress) +// require.Equal(t, sdk.NewCoin(sdk.DefaultBondDenom, delegation.Shares.TruncateInt()), delegatorDelegations[0].Balance) +// +// // error unknown request +// query.Data = bz[:len(bz)-1] +// +// res, err = querier(ctx, []string{types.QueryDelegation}, query) +// require.Error(t, err) +// +// // Query validator delegations +// +// bz, errRes = cdc.MarshalJSON(types.NewQueryValidatorParams(addrVal1)) +// require.NoError(t, errRes) +// +// query = abci.RequestQuery{ +// Path: "custom/staking/validatorDelegations", +// Data: bz, +// } +// +// res, err = querier(ctx, []string{types.QueryValidatorDelegations}, query) +// require.NoError(t, err) +// +// var delegationsRes types.DelegationResponses +// errRes = cdc.UnmarshalJSON(res, &delegationsRes) +// require.NoError(t, errRes) +// require.Len(t, delegatorDelegations, 1) +// require.Equal(t, delegation.ValidatorAddress, delegationsRes[0].ValidatorAddress) +// require.Equal(t, delegation.DelegatorAddress, delegationsRes[0].DelegatorAddress) +// require.Equal(t, sdk.NewCoin(sdk.DefaultBondDenom, delegation.Shares.TruncateInt()), delegationsRes[0].Balance) +// +// // Query unbonging delegation +// unbondingTokens := sdk.TokensFromConsensusPower(10) +// _, err = app.StakingKeeper.Undelegate(ctx, addrAcc2, val1.OperatorAddress, unbondingTokens.ToDec()) +// require.NoError(t, err) +// +// queryBondParams = types.NewQueryBondsParams(addrAcc2, addrVal1) +// bz, errRes = cdc.MarshalJSON(queryBondParams) +// require.NoError(t, errRes) +// +// query = abci.RequestQuery{ +// Path: "/custom/staking/unbondingDelegation", +// Data: bz, +// } +// +// unbond, found := app.StakingKeeper.GetUnbondingDelegation(ctx, addrAcc2, addrVal1) +// require.True(t, found) +// +// res, err = querier(ctx, []string{types.QueryUnbondingDelegation}, query) +// require.NoError(t, err) +// +// var unbondRes types.UnbondingDelegation +// errRes = cdc.UnmarshalJSON(res, &unbondRes) +// require.NoError(t, errRes) +// +// require.Equal(t, unbond, unbondRes) +// +// // error unknown request +// query.Data = bz[:len(bz)-1] +// +// _, err = querier(ctx, []string{types.QueryUnbondingDelegation}, query) +// require.Error(t, err) +// +// // Query Delegator Delegations +// +// query = abci.RequestQuery{ +// Path: "/custom/staking/delegatorUnbondingDelegations", +// Data: bz, +// } +// +// res, err = querier(ctx, []string{types.QueryDelegatorUnbondingDelegations}, query) +// require.NoError(t, err) +// +// var delegatorUbds []types.UnbondingDelegation +// errRes = cdc.UnmarshalJSON(res, &delegatorUbds) +// require.NoError(t, errRes) +// require.Equal(t, unbond, delegatorUbds[0]) +// +// // error unknown request +// query.Data = bz[:len(bz)-1] +// +// _, err = querier(ctx, []string{types.QueryDelegatorUnbondingDelegations}, query) +// require.Error(t, err) +// +// // Query redelegation +// redelegationTokens := sdk.TokensFromConsensusPower(10) +// _, err = app.StakingKeeper.BeginRedelegation(ctx, addrAcc2, val1.OperatorAddress, +// val2.OperatorAddress, redelegationTokens.ToDec()) +// require.NoError(t, err) +// redel, found := app.StakingKeeper.GetRedelegation(ctx, addrAcc2, val1.OperatorAddress, val2.OperatorAddress) +// require.True(t, found) +// +// bz, errRes = cdc.MarshalJSON(types.NewQueryRedelegationParams(addrAcc2, val1.OperatorAddress, val2.OperatorAddress)) +// require.NoError(t, errRes) +// +// query = abci.RequestQuery{ +// Path: "/custom/staking/redelegations", +// Data: bz, +// } +// +// res, err = querier(ctx, []string{types.QueryRedelegations}, query) +// require.NoError(t, err) +// +// var redelRes types.RedelegationResponses +// errRes = cdc.UnmarshalJSON(res, &redelRes) +// require.NoError(t, errRes) +// require.Len(t, redelRes, 1) +// require.Equal(t, redel.DelegatorAddress, redelRes[0].DelegatorAddress) +// require.Equal(t, redel.ValidatorSrcAddress, redelRes[0].ValidatorSrcAddress) +// require.Equal(t, redel.ValidatorDstAddress, redelRes[0].ValidatorDstAddress) +// require.Len(t, redel.Entries, len(redelRes[0].Entries)) +//} +// +//func TestQueryRedelegations(t *testing.T) { +// cdc := codec.New() +// ctx, _, _, keeper, _ := CreateTestInput(t, false, 10000) +// +// // Create Validators and Delegation +// val1 := types.NewValidator(addrVal1, pk1, types.Description{}) +// val2 := types.NewValidator(addrVal2, pk2, types.Description{}) +// keeper.SetValidator(ctx, val1) +// keeper.SetValidator(ctx, val2) +// +// delAmount := sdk.TokensFromConsensusPower(100) +// keeper.Delegate(ctx, addrAcc2, delAmount, sdk.Unbonded, val1, true) +// _ = keeper.ApplyAndReturnValidatorSetUpdates(ctx) +// +// rdAmount := sdk.TokensFromConsensusPower(20) +// keeper.BeginRedelegation(ctx, addrAcc2, val1.GetOperator(), val2.GetOperator(), rdAmount.ToDec()) +// keeper.ApplyAndReturnValidatorSetUpdates(ctx) +// +// redel, found := keeper.GetRedelegation(ctx, addrAcc2, val1.OperatorAddress, val2.OperatorAddress) +// require.True(t, found) +// +// // delegator redelegations +// queryDelegatorParams := types.NewQueryDelegatorParams(addrAcc2) +// bz, errRes := cdc.MarshalJSON(queryDelegatorParams) +// require.NoError(t, errRes) +// +// query := abci.RequestQuery{ +// Path: "/custom/staking/redelegations", +// Data: bz, +// } +// +// res, err := queryRedelegations(ctx, query, keeper) +// require.NoError(t, err) +// +// var redelRes types.RedelegationResponses +// errRes = cdc.UnmarshalJSON(res, &redelRes) +// require.NoError(t, errRes) +// require.Len(t, redelRes, 1) +// require.Equal(t, redel.DelegatorAddress, redelRes[0].DelegatorAddress) +// require.Equal(t, redel.ValidatorSrcAddress, redelRes[0].ValidatorSrcAddress) +// require.Equal(t, redel.ValidatorDstAddress, redelRes[0].ValidatorDstAddress) +// require.Len(t, redel.Entries, len(redelRes[0].Entries)) +// +// // validator redelegations +// queryValidatorParams := types.NewQueryValidatorParams(val1.GetOperator()) +// bz, errRes = cdc.MarshalJSON(queryValidatorParams) +// require.NoError(t, errRes) +// +// query = abci.RequestQuery{ +// Path: "/custom/staking/redelegations", +// Data: bz, +// } +// +// res, err = queryRedelegations(ctx, query, keeper) +// require.NoError(t, err) +// +// errRes = cdc.UnmarshalJSON(res, &redelRes) +// require.NoError(t, errRes) +// require.Len(t, redelRes, 1) +// require.Equal(t, redel.DelegatorAddress, redelRes[0].DelegatorAddress) +// require.Equal(t, redel.ValidatorSrcAddress, redelRes[0].ValidatorSrcAddress) +// require.Equal(t, redel.ValidatorDstAddress, redelRes[0].ValidatorDstAddress) +// require.Len(t, redel.Entries, len(redelRes[0].Entries)) +//} +// +//func TestQueryUnbondingDelegation(t *testing.T) { +// cdc := codec.New() +// ctx, _, _, keeper, _ := CreateTestInput(t, false, 10000) +// +// // Create Validators and Delegation +// val1 := types.NewValidator(addrVal1, pk1, types.Description{}) +// keeper.SetValidator(ctx, val1) +// +// // delegate +// delAmount := sdk.TokensFromConsensusPower(100) +// _, err := keeper.Delegate(ctx, addrAcc1, delAmount, sdk.Unbonded, val1, true) +// require.NoError(t, err) +// _ = keeper.ApplyAndReturnValidatorSetUpdates(ctx) +// +// // undelegate +// undelAmount := sdk.TokensFromConsensusPower(20) +// _, err = keeper.Undelegate(ctx, addrAcc1, val1.GetOperator(), undelAmount.ToDec()) +// require.NoError(t, err) +// keeper.ApplyAndReturnValidatorSetUpdates(ctx) +// +// _, found := keeper.GetUnbondingDelegation(ctx, addrAcc1, val1.OperatorAddress) +// require.True(t, found) +// +// // +// // found: query unbonding delegation by delegator and validator +// // +// queryValidatorParams := types.NewQueryBondsParams(addrAcc1, val1.GetOperator()) +// bz, errRes := cdc.MarshalJSON(queryValidatorParams) +// require.NoError(t, errRes) +// query := abci.RequestQuery{ +// Path: "/custom/staking/unbondingDelegation", +// Data: bz, +// } +// res, err := queryUnbondingDelegation(ctx, query, keeper) +// require.NoError(t, err) +// require.NotNil(t, res) +// var ubDel types.UnbondingDelegation +// require.NoError(t, cdc.UnmarshalJSON(res, &ubDel)) +// require.Equal(t, addrAcc1, ubDel.DelegatorAddress) +// require.Equal(t, val1.OperatorAddress, ubDel.ValidatorAddress) +// require.Equal(t, 1, len(ubDel.Entries)) +// +// // +// // not found: query unbonding delegation by delegator and validator +// // +// queryValidatorParams = types.NewQueryBondsParams(addrAcc2, val1.GetOperator()) +// bz, errRes = cdc.MarshalJSON(queryValidatorParams) +// require.NoError(t, errRes) +// query = abci.RequestQuery{ +// Path: "/custom/staking/unbondingDelegation", +// Data: bz, +// } +// _, err = queryUnbondingDelegation(ctx, query, keeper) +// require.Error(t, err) +// +// // +// // found: query unbonding delegation by delegator and validator +// // +// queryDelegatorParams := types.NewQueryDelegatorParams(addrAcc1) +// bz, errRes = cdc.MarshalJSON(queryDelegatorParams) +// require.NoError(t, errRes) +// query = abci.RequestQuery{ +// Path: "/custom/staking/delegatorUnbondingDelegations", +// Data: bz, +// } +// res, err = queryDelegatorUnbondingDelegations(ctx, query, keeper) +// require.NoError(t, err) +// require.NotNil(t, res) +// var ubDels []types.UnbondingDelegation +// require.NoError(t, cdc.UnmarshalJSON(res, &ubDels)) +// require.Equal(t, 1, len(ubDels)) +// require.Equal(t, addrAcc1, ubDels[0].DelegatorAddress) +// require.Equal(t, val1.OperatorAddress, ubDels[0].ValidatorAddress) +// +// // +// // not found: query unbonding delegation by delegator and validator +// // +// queryDelegatorParams = types.NewQueryDelegatorParams(addrAcc2) +// bz, errRes = cdc.MarshalJSON(queryDelegatorParams) +// require.NoError(t, errRes) +// query = abci.RequestQuery{ +// Path: "/custom/staking/delegatorUnbondingDelegations", +// Data: bz, +// } +// res, err = queryDelegatorUnbondingDelegations(ctx, query, keeper) +// require.NoError(t, err) +// require.NotNil(t, res) +// require.NoError(t, cdc.UnmarshalJSON(res, &ubDels)) +// require.Equal(t, 0, len(ubDels)) +//} +// +//func TestQueryHistoricalInfo(t *testing.T) { +// cdc := codec.New() +// ctx, _, _, keeper, _ := CreateTestInput(t, false, 10000) +// +// // Create Validators and Delegation +// val1 := types.NewValidator(addrVal1, pk1, types.Description{}) +// val2 := types.NewValidator(addrVal2, pk2, types.Description{}) +// vals := []types.Validator{val1, val2} +// keeper.SetValidator(ctx, val1) +// keeper.SetValidator(ctx, val2) +// +// header := abci.Header{ +// ChainID: "HelloChain", +// Height: 5, +// } +// hi := types.NewHistoricalInfo(header, vals) +// keeper.SetHistoricalInfo(ctx, 5, hi) +// +// queryHistoricalParams := types.NewQueryHistoricalInfoParams(4) +// bz, errRes := cdc.MarshalJSON(queryHistoricalParams) +// require.NoError(t, errRes) +// query := abci.RequestQuery{ +// Path: "/custom/staking/historicalInfo", +// Data: bz, +// } +// res, err := queryHistoricalInfo(ctx, query, keeper) +// require.Error(t, err, "Invalid query passed") +// require.Nil(t, res, "Invalid query returned non-nil result") +// +// queryHistoricalParams = types.NewQueryHistoricalInfoParams(5) +// bz, errRes = cdc.MarshalJSON(queryHistoricalParams) +// require.NoError(t, errRes) +// query.Data = bz +// res, err = queryHistoricalInfo(ctx, query, keeper) +// require.NoError(t, err, "Valid query passed") +// require.NotNil(t, res, "Valid query returned nil result") +// +// var recv types.HistoricalInfo +// require.NoError(t, cdc.UnmarshalJSON(res, &recv)) +// require.Equal(t, hi, recv, "HistoricalInfo query returned wrong result") +//} From 1736692f3b5d52c239c6c0dd3ff91223d8489730 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Tue, 18 Feb 2020 16:53:11 +0100 Subject: [PATCH 149/529] Merge PR #5668: Fix GetAccountWithHeight --- x/auth/types/account_retriever.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x/auth/types/account_retriever.go b/x/auth/types/account_retriever.go index 65aa4297ed19..bc24b4a9c480 100644 --- a/x/auth/types/account_retriever.go +++ b/x/auth/types/account_retriever.go @@ -48,12 +48,12 @@ func (ar AccountRetriever) GetAccountWithHeight(addr sdk.AccAddress) (exported.A return nil, height, err } - acc, err := ar.codec.UnmarshalAccountJSON(bz) - if err != nil { + var account exported.Account + if err := ar.codec.UnmarshalJSON(bz, &account); err != nil { return nil, height, err } - return acc, height, nil + return account, height, nil } // EnsureExists returns an error if no account exists for the given address else nil. From 7f8d0e60476323ef755dac2db2cdcb0b71effaab Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Tue, 18 Feb 2020 19:10:53 +0100 Subject: [PATCH 150/529] commit end of day refactoring --- x/staking/keeper/old_querier_test.go | 436 +++++++++++++++++++++++++++ x/staking/keeper/querier_test.go | 17 +- 2 files changed, 445 insertions(+), 8 deletions(-) create mode 100644 x/staking/keeper/old_querier_test.go diff --git a/x/staking/keeper/old_querier_test.go b/x/staking/keeper/old_querier_test.go new file mode 100644 index 000000000000..3203755cc6ab --- /dev/null +++ b/x/staking/keeper/old_querier_test.go @@ -0,0 +1,436 @@ +package keeper + +import ( + "testing" + + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/stretchr/testify/require" +) + +var ( + addrAcc1, addrAcc2 = Addrs[0], Addrs[1] + addrVal1, addrVal2 = sdk.ValAddress(Addrs[0]), sdk.ValAddress(Addrs[1]) + pk1, pk2 = PKs[0], PKs[1] +) + +func TestQueryDelegation(t *testing.T) { + cdc := codec.New() + ctx, _, _, keeper, _ := CreateTestInput(t, false, 10000) + params := keeper.GetParams(ctx) + + // Create Validators and Delegation + val1 := types.NewValidator(addrVal1, pk1, types.Description{}) + keeper.SetValidator(ctx, val1) + keeper.SetValidatorByPowerIndex(ctx, val1) + + val2 := types.NewValidator(addrVal2, pk2, types.Description{}) + keeper.SetValidator(ctx, val2) + keeper.SetValidatorByPowerIndex(ctx, val2) + + delTokens := sdk.TokensFromConsensusPower(20) + keeper.Delegate(ctx, addrAcc2, delTokens, sdk.Unbonded, val1, true) + + // apply TM updates + keeper.ApplyAndReturnValidatorSetUpdates(ctx) + + // Query Delegator bonded validators + queryParams := types.NewQueryDelegatorParams(addrAcc2) + bz, errRes := cdc.MarshalJSON(queryParams) + require.NoError(t, errRes) + + query := abci.RequestQuery{ + Path: "/custom/staking/delegatorValidators", + Data: bz, + } + + delValidators := keeper.GetDelegatorValidators(ctx, addrAcc2, params.MaxValidators) + + res, err := queryDelegatorValidators(ctx, query, keeper) + require.NoError(t, err) + + var validatorsResp []types.Validator + errRes = cdc.UnmarshalJSON(res, &validatorsResp) + require.NoError(t, errRes) + + require.Equal(t, len(delValidators), len(validatorsResp)) + require.ElementsMatch(t, delValidators, validatorsResp) + + // error unknown request + query.Data = bz[:len(bz)-1] + + _, err = queryDelegatorValidators(ctx, query, keeper) + require.Error(t, err) + + // Query bonded validator + queryBondParams := types.NewQueryBondsParams(addrAcc2, addrVal1) + bz, errRes = cdc.MarshalJSON(queryBondParams) + require.NoError(t, errRes) + + query = abci.RequestQuery{ + Path: "/custom/staking/delegatorValidator", + Data: bz, + } + + res, err = queryDelegatorValidator(ctx, query, keeper) + require.NoError(t, err) + + var validator types.Validator + errRes = cdc.UnmarshalJSON(res, &validator) + require.NoError(t, errRes) + + require.Equal(t, delValidators[0], validator) + + // error unknown request + query.Data = bz[:len(bz)-1] + + _, err = queryDelegatorValidator(ctx, query, keeper) + require.Error(t, err) + + // Query delegation + + query = abci.RequestQuery{ + Path: "/custom/staking/delegation", + Data: bz, + } + + delegation, found := keeper.GetDelegation(ctx, addrAcc2, addrVal1) + require.True(t, found) + + res, err = queryDelegation(ctx, query, keeper) + require.NoError(t, err) + + var delegationRes types.DelegationResponse + errRes = cdc.UnmarshalJSON(res, &delegationRes) + require.NoError(t, errRes) + + require.Equal(t, delegation.ValidatorAddress, delegationRes.ValidatorAddress) + require.Equal(t, delegation.DelegatorAddress, delegationRes.DelegatorAddress) + require.Equal(t, sdk.NewCoin(sdk.DefaultBondDenom, delegation.Shares.TruncateInt()), delegationRes.Balance) + + // Query Delegator Delegations + query = abci.RequestQuery{ + Path: "/custom/staking/delegatorDelegations", + Data: bz, + } + + res, err = queryDelegatorDelegations(ctx, query, keeper) + require.NoError(t, err) + + var delegatorDelegations types.DelegationResponses + errRes = cdc.UnmarshalJSON(res, &delegatorDelegations) + require.NoError(t, errRes) + require.Len(t, delegatorDelegations, 1) + require.Equal(t, delegation.ValidatorAddress, delegatorDelegations[0].ValidatorAddress) + require.Equal(t, delegation.DelegatorAddress, delegatorDelegations[0].DelegatorAddress) + require.Equal(t, sdk.NewCoin(sdk.DefaultBondDenom, delegation.Shares.TruncateInt()), delegatorDelegations[0].Balance) + + // error unknown request + query.Data = bz[:len(bz)-1] + + _, err = queryDelegation(ctx, query, keeper) + require.Error(t, err) + + // Query validator delegations + + bz, errRes = cdc.MarshalJSON(types.NewQueryValidatorParams(addrVal1)) + require.NoError(t, errRes) + + query = abci.RequestQuery{ + Path: "custom/staking/validatorDelegations", + Data: bz, + } + + res, err = queryValidatorDelegations(ctx, query, keeper) + require.NoError(t, err) + + var delegationsRes types.DelegationResponses + errRes = cdc.UnmarshalJSON(res, &delegationsRes) + require.NoError(t, errRes) + require.Len(t, delegatorDelegations, 1) + require.Equal(t, delegation.ValidatorAddress, delegationsRes[0].ValidatorAddress) + require.Equal(t, delegation.DelegatorAddress, delegationsRes[0].DelegatorAddress) + require.Equal(t, sdk.NewCoin(sdk.DefaultBondDenom, delegation.Shares.TruncateInt()), delegationsRes[0].Balance) + + // Query unbonging delegation + unbondingTokens := sdk.TokensFromConsensusPower(10) + _, err = keeper.Undelegate(ctx, addrAcc2, val1.OperatorAddress, unbondingTokens.ToDec()) + require.NoError(t, err) + + queryBondParams = types.NewQueryBondsParams(addrAcc2, addrVal1) + bz, errRes = cdc.MarshalJSON(queryBondParams) + require.NoError(t, errRes) + + query = abci.RequestQuery{ + Path: "/custom/staking/unbondingDelegation", + Data: bz, + } + + unbond, found := keeper.GetUnbondingDelegation(ctx, addrAcc2, addrVal1) + require.True(t, found) + + res, err = queryUnbondingDelegation(ctx, query, keeper) + require.NoError(t, err) + + var unbondRes types.UnbondingDelegation + errRes = cdc.UnmarshalJSON(res, &unbondRes) + require.NoError(t, errRes) + + require.Equal(t, unbond, unbondRes) + + // error unknown request + query.Data = bz[:len(bz)-1] + + _, err = queryUnbondingDelegation(ctx, query, keeper) + require.Error(t, err) + + // Query Delegator Delegations + + query = abci.RequestQuery{ + Path: "/custom/staking/delegatorUnbondingDelegations", + Data: bz, + } + + res, err = queryDelegatorUnbondingDelegations(ctx, query, keeper) + require.NoError(t, err) + + var delegatorUbds []types.UnbondingDelegation + errRes = cdc.UnmarshalJSON(res, &delegatorUbds) + require.NoError(t, errRes) + require.Equal(t, unbond, delegatorUbds[0]) + + // error unknown request + query.Data = bz[:len(bz)-1] + + _, err = queryDelegatorUnbondingDelegations(ctx, query, keeper) + require.Error(t, err) + + // Query redelegation + redelegationTokens := sdk.TokensFromConsensusPower(10) + _, err = keeper.BeginRedelegation(ctx, addrAcc2, val1.OperatorAddress, + val2.OperatorAddress, redelegationTokens.ToDec()) + require.NoError(t, err) + redel, found := keeper.GetRedelegation(ctx, addrAcc2, val1.OperatorAddress, val2.OperatorAddress) + require.True(t, found) + + bz, errRes = cdc.MarshalJSON(types.NewQueryRedelegationParams(addrAcc2, val1.OperatorAddress, val2.OperatorAddress)) + require.NoError(t, errRes) + + query = abci.RequestQuery{ + Path: "/custom/staking/redelegations", + Data: bz, + } + + res, err = queryRedelegations(ctx, query, keeper) + require.NoError(t, err) + + var redelRes types.RedelegationResponses + errRes = cdc.UnmarshalJSON(res, &redelRes) + require.NoError(t, errRes) + require.Len(t, redelRes, 1) + require.Equal(t, redel.DelegatorAddress, redelRes[0].DelegatorAddress) + require.Equal(t, redel.ValidatorSrcAddress, redelRes[0].ValidatorSrcAddress) + require.Equal(t, redel.ValidatorDstAddress, redelRes[0].ValidatorDstAddress) + require.Len(t, redel.Entries, len(redelRes[0].Entries)) +} + +func TestQueryRedelegations(t *testing.T) { + cdc := codec.New() + ctx, _, _, keeper, _ := CreateTestInput(t, false, 10000) + + // Create Validators and Delegation + val1 := types.NewValidator(addrVal1, pk1, types.Description{}) + val2 := types.NewValidator(addrVal2, pk2, types.Description{}) + keeper.SetValidator(ctx, val1) + keeper.SetValidator(ctx, val2) + + delAmount := sdk.TokensFromConsensusPower(100) + keeper.Delegate(ctx, addrAcc2, delAmount, sdk.Unbonded, val1, true) + _ = keeper.ApplyAndReturnValidatorSetUpdates(ctx) + + rdAmount := sdk.TokensFromConsensusPower(20) + keeper.BeginRedelegation(ctx, addrAcc2, val1.GetOperator(), val2.GetOperator(), rdAmount.ToDec()) + keeper.ApplyAndReturnValidatorSetUpdates(ctx) + + redel, found := keeper.GetRedelegation(ctx, addrAcc2, val1.OperatorAddress, val2.OperatorAddress) + require.True(t, found) + + // delegator redelegations + queryDelegatorParams := types.NewQueryDelegatorParams(addrAcc2) + bz, errRes := cdc.MarshalJSON(queryDelegatorParams) + require.NoError(t, errRes) + + query := abci.RequestQuery{ + Path: "/custom/staking/redelegations", + Data: bz, + } + + res, err := queryRedelegations(ctx, query, keeper) + require.NoError(t, err) + + var redelRes types.RedelegationResponses + errRes = cdc.UnmarshalJSON(res, &redelRes) + require.NoError(t, errRes) + require.Len(t, redelRes, 1) + require.Equal(t, redel.DelegatorAddress, redelRes[0].DelegatorAddress) + require.Equal(t, redel.ValidatorSrcAddress, redelRes[0].ValidatorSrcAddress) + require.Equal(t, redel.ValidatorDstAddress, redelRes[0].ValidatorDstAddress) + require.Len(t, redel.Entries, len(redelRes[0].Entries)) + + // validator redelegations + queryValidatorParams := types.NewQueryValidatorParams(val1.GetOperator()) + bz, errRes = cdc.MarshalJSON(queryValidatorParams) + require.NoError(t, errRes) + + query = abci.RequestQuery{ + Path: "/custom/staking/redelegations", + Data: bz, + } + + res, err = queryRedelegations(ctx, query, keeper) + require.NoError(t, err) + + errRes = cdc.UnmarshalJSON(res, &redelRes) + require.NoError(t, errRes) + require.Len(t, redelRes, 1) + require.Equal(t, redel.DelegatorAddress, redelRes[0].DelegatorAddress) + require.Equal(t, redel.ValidatorSrcAddress, redelRes[0].ValidatorSrcAddress) + require.Equal(t, redel.ValidatorDstAddress, redelRes[0].ValidatorDstAddress) + require.Len(t, redel.Entries, len(redelRes[0].Entries)) +} + +func TestQueryUnbondingDelegation(t *testing.T) { + cdc := codec.New() + ctx, _, _, keeper, _ := CreateTestInput(t, false, 10000) + + // Create Validators and Delegation + val1 := types.NewValidator(addrVal1, pk1, types.Description{}) + keeper.SetValidator(ctx, val1) + + // delegate + delAmount := sdk.TokensFromConsensusPower(100) + _, err := keeper.Delegate(ctx, addrAcc1, delAmount, sdk.Unbonded, val1, true) + require.NoError(t, err) + _ = keeper.ApplyAndReturnValidatorSetUpdates(ctx) + + // undelegate + undelAmount := sdk.TokensFromConsensusPower(20) + _, err = keeper.Undelegate(ctx, addrAcc1, val1.GetOperator(), undelAmount.ToDec()) + require.NoError(t, err) + keeper.ApplyAndReturnValidatorSetUpdates(ctx) + + _, found := keeper.GetUnbondingDelegation(ctx, addrAcc1, val1.OperatorAddress) + require.True(t, found) + + // + // found: query unbonding delegation by delegator and validator + // + queryValidatorParams := types.NewQueryBondsParams(addrAcc1, val1.GetOperator()) + bz, errRes := cdc.MarshalJSON(queryValidatorParams) + require.NoError(t, errRes) + query := abci.RequestQuery{ + Path: "/custom/staking/unbondingDelegation", + Data: bz, + } + res, err := queryUnbondingDelegation(ctx, query, keeper) + require.NoError(t, err) + require.NotNil(t, res) + var ubDel types.UnbondingDelegation + require.NoError(t, cdc.UnmarshalJSON(res, &ubDel)) + require.Equal(t, addrAcc1, ubDel.DelegatorAddress) + require.Equal(t, val1.OperatorAddress, ubDel.ValidatorAddress) + require.Equal(t, 1, len(ubDel.Entries)) + + // + // not found: query unbonding delegation by delegator and validator + // + queryValidatorParams = types.NewQueryBondsParams(addrAcc2, val1.GetOperator()) + bz, errRes = cdc.MarshalJSON(queryValidatorParams) + require.NoError(t, errRes) + query = abci.RequestQuery{ + Path: "/custom/staking/unbondingDelegation", + Data: bz, + } + _, err = queryUnbondingDelegation(ctx, query, keeper) + require.Error(t, err) + + // + // found: query unbonding delegation by delegator and validator + // + queryDelegatorParams := types.NewQueryDelegatorParams(addrAcc1) + bz, errRes = cdc.MarshalJSON(queryDelegatorParams) + require.NoError(t, errRes) + query = abci.RequestQuery{ + Path: "/custom/staking/delegatorUnbondingDelegations", + Data: bz, + } + res, err = queryDelegatorUnbondingDelegations(ctx, query, keeper) + require.NoError(t, err) + require.NotNil(t, res) + var ubDels []types.UnbondingDelegation + require.NoError(t, cdc.UnmarshalJSON(res, &ubDels)) + require.Equal(t, 1, len(ubDels)) + require.Equal(t, addrAcc1, ubDels[0].DelegatorAddress) + require.Equal(t, val1.OperatorAddress, ubDels[0].ValidatorAddress) + + // + // not found: query unbonding delegation by delegator and validator + // + queryDelegatorParams = types.NewQueryDelegatorParams(addrAcc2) + bz, errRes = cdc.MarshalJSON(queryDelegatorParams) + require.NoError(t, errRes) + query = abci.RequestQuery{ + Path: "/custom/staking/delegatorUnbondingDelegations", + Data: bz, + } + res, err = queryDelegatorUnbondingDelegations(ctx, query, keeper) + require.NoError(t, err) + require.NotNil(t, res) + require.NoError(t, cdc.UnmarshalJSON(res, &ubDels)) + require.Equal(t, 0, len(ubDels)) +} + +func TestQueryHistoricalInfo(t *testing.T) { + cdc := codec.New() + ctx, _, _, keeper, _ := CreateTestInput(t, false, 10000) + + // Create Validators and Delegation + val1 := types.NewValidator(addrVal1, pk1, types.Description{}) + val2 := types.NewValidator(addrVal2, pk2, types.Description{}) + vals := []types.Validator{val1, val2} + keeper.SetValidator(ctx, val1) + keeper.SetValidator(ctx, val2) + + header := abci.Header{ + ChainID: "HelloChain", + Height: 5, + } + hi := types.NewHistoricalInfo(header, vals) + keeper.SetHistoricalInfo(ctx, 5, hi) + + queryHistoricalParams := types.NewQueryHistoricalInfoParams(4) + bz, errRes := cdc.MarshalJSON(queryHistoricalParams) + require.NoError(t, errRes) + query := abci.RequestQuery{ + Path: "/custom/staking/historicalInfo", + Data: bz, + } + res, err := queryHistoricalInfo(ctx, query, keeper) + require.Error(t, err, "Invalid query passed") + require.Nil(t, res, "Invalid query returned non-nil result") + + queryHistoricalParams = types.NewQueryHistoricalInfoParams(5) + bz, errRes = cdc.MarshalJSON(queryHistoricalParams) + require.NoError(t, errRes) + query.Data = bz + res, err = queryHistoricalInfo(ctx, query, keeper) + require.NoError(t, err, "Valid query passed") + require.NotNil(t, res, "Valid query returned nil result") + + var recv types.HistoricalInfo + require.NoError(t, cdc.UnmarshalJSON(res, &recv)) + require.Equal(t, hi, recv, "HistoricalInfo query returned wrong result") +} diff --git a/x/staking/keeper/querier_test.go b/x/staking/keeper/querier_test.go index 202290762ba5..50bb8b34d03f 100644 --- a/x/staking/keeper/querier_test.go +++ b/x/staking/keeper/querier_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/codec" @@ -14,22 +15,19 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking/types" ) -var ( - addrAcc1, addrAcc2 = Addrs[0], Addrs[1] - addrVal1, addrVal2 = sdk.ValAddress(Addrs[0]), sdk.ValAddress(Addrs[1]) - pk1, pk2 = PKs[0], PKs[1] -) - func TestNewQuerier(t *testing.T) { cdc := codec.New() app := simapp.Setup(false) ctx := app.BaseApp.NewContext(false, abci.Header{}) + addrs := simapp.AddTestAddrs(app, ctx, 500, sdk.NewInt(10000)) + _, addrAcc2 := addrs[0], addrs[1] + addrVal1, _ := sdk.ValAddress(addrs[0]), sdk.ValAddress(addrs[1]) // Create Validators amts := []sdk.Int{sdk.NewInt(9), sdk.NewInt(8)} var validators [2]types.Validator for i, amt := range amts { - validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) + validators[i] = types.NewValidator(sdk.ValAddress(addrs[i]), PKs[i], types.Description{}) validators[i], _ = validators[i].AddTokensFromDel(amt) app.StakingKeeper.SetValidator(ctx, validators[i]) app.StakingKeeper.SetValidatorByPowerIndex(ctx, validators[i]) @@ -143,12 +141,15 @@ func TestQueryValidators(t *testing.T) { params := app.StakingKeeper.GetParams(ctx) querier := staking.NewQuerier(app.StakingKeeper) + addrs := simapp.AddTestAddrs(app, ctx, 500, sdk.NewInt(10000)) + addrVal1, _ := sdk.ValAddress(addrs[0]), sdk.ValAddress(addrs[1]) + // Create Validators amts := []sdk.Int{sdk.NewInt(9), sdk.NewInt(8), sdk.NewInt(7)} status := []sdk.BondStatus{sdk.Bonded, sdk.Unbonded, sdk.Unbonding} var validators [3]types.Validator for i, amt := range amts { - validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) + validators[i] = types.NewValidator(sdk.ValAddress(addrs[i]), PKs[i], types.Description{}) validators[i], _ = validators[i].AddTokensFromDel(amt) validators[i] = validators[i].UpdateStatus(status[i]) } From 69c5b4641306bdd6bf44f3df521e44682b158d2d Mon Sep 17 00:00:00 2001 From: Xuefeng Zhu Date: Wed, 19 Feb 2020 01:05:27 -0800 Subject: [PATCH 151/529] Get Uin64 directly instead of Int64 (#5672) --- x/auth/types/txbuilder.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x/auth/types/txbuilder.go b/x/auth/types/txbuilder.go index 533596ccb649..4ffd327d66a7 100644 --- a/x/auth/types/txbuilder.go +++ b/x/auth/types/txbuilder.go @@ -59,8 +59,8 @@ func NewTxBuilderFromCLI(input io.Reader) TxBuilder { } txbldr := TxBuilder{ keybase: kb, - accountNumber: uint64(viper.GetInt64(flags.FlagAccountNumber)), - sequence: uint64(viper.GetInt64(flags.FlagSequence)), + accountNumber: viper.GetUint64(flags.FlagAccountNumber), + sequence: viper.GetUint64(flags.FlagSequence), gas: flags.GasFlagVar.Gas, gasAdjustment: viper.GetFloat64(flags.FlagGasAdjustment), simulateAndExecute: flags.GasFlagVar.Simulate, From 4cb77f031c9ba0a1452738669e924139f6584c78 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 19 Feb 2020 10:45:10 +0100 Subject: [PATCH 152/529] Bump github.com/stretchr/testify from 1.4.0 to 1.5.0 (#5675) Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.4.0 to 1.5.0. - [Release notes](https://github.com/stretchr/testify/releases) - [Commits](https://github.com/stretchr/testify/compare/v1.4.0...v1.5.0) Signed-off-by: dependabot-preview[bot] --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 7d634c42c83b..54dc76100f07 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.6.2 - github.com/stretchr/testify v1.4.0 + github.com/stretchr/testify v1.5.0 github.com/tendermint/btcd v0.1.1 github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 github.com/tendermint/go-amino v0.15.1 diff --git a/go.sum b/go.sum index 1aa44bd73fe1..a0e82c697eff 100644 --- a/go.sum +++ b/go.sum @@ -237,6 +237,8 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.0 h1:DMOzIV76tmoDNE9pX6RSN0aDtCYeCg5VueieJaAo1uw= +github.com/stretchr/testify v1.5.0/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d h1:gZZadD8H+fF+n9CmNhYL1Y0dJB+kLOmKd7FbPJLeGHs= From cdcbecb2f4da1eb142c6762444830336881b6faf Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Wed, 19 Feb 2020 10:53:43 +0100 Subject: [PATCH 153/529] rename and temp commit --- .../{test_common.go => old_test_common.go} | 0 x/staking/keeper/querier_test.go | 421 +++++++++--------- ...n_refactor_test.go => test_common_test.go} | 3 +- 3 files changed, 214 insertions(+), 210 deletions(-) rename x/staking/keeper/{test_common.go => old_test_common.go} (100%) rename x/staking/keeper/{common_refactor_test.go => test_common_test.go} (99%) diff --git a/x/staking/keeper/test_common.go b/x/staking/keeper/old_test_common.go similarity index 100% rename from x/staking/keeper/test_common.go rename to x/staking/keeper/old_test_common.go diff --git a/x/staking/keeper/querier_test.go b/x/staking/keeper/querier_test.go index 50bb8b34d03f..4f348a429a77 100644 --- a/x/staking/keeper/querier_test.go +++ b/x/staking/keeper/querier_test.go @@ -202,215 +202,218 @@ func TestQueryValidators(t *testing.T) { require.Equal(t, queriedValidators[0], validator) } -//func TestQueryDelegation(t *testing.T) { -// cdc := codec.New() -// app := simapp.Setup(false) -// ctx := app.BaseApp.NewContext(false, abci.Header{}) -// params := app.StakingKeeper.GetParams(ctx) -// querier := staking.NewQuerier(app.StakingKeeper) -// -// // Create Validators and Delegation -// val1 := types.NewValidator(addrVal1, pk1, types.Description{}) -// app.StakingKeeper.SetValidator(ctx, val1) -// app.StakingKeeper.SetValidatorByPowerIndex(ctx, val1) -// -// val2 := types.NewValidator(addrVal2, pk2, types.Description{}) -// app.StakingKeeper.SetValidator(ctx, val2) -// app.StakingKeeper.SetValidatorByPowerIndex(ctx, val2) -// -// delTokens := sdk.TokensFromConsensusPower(20) -// app.StakingKeeper.Delegate(ctx, addrAcc2, delTokens, sdk.Unbonded, val1, true) -// -// // apply TM updates -// app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) -// -// // Query Delegator bonded validators -// queryParams := types.NewQueryDelegatorParams(addrAcc2) -// bz, errRes := cdc.MarshalJSON(queryParams) -// require.NoError(t, errRes) -// -// query := abci.RequestQuery{ -// Path: "/custom/staking/delegatorValidators", -// Data: bz, -// } -// -// delValidators := app.StakingKeeper.GetDelegatorValidators(ctx, addrAcc2, params.MaxValidators) -// -// res, err := querier(ctx, []string{types.QueryDelegatorValidators}, query) -// require.NoError(t, err) -// -// var validatorsResp []types.Validator -// errRes = cdc.UnmarshalJSON(res, &validatorsResp) -// require.NoError(t, errRes) -// -// require.Equal(t, len(delValidators), len(validatorsResp)) -// require.ElementsMatch(t, delValidators, validatorsResp) -// -// // error unknown request -// query.Data = bz[:len(bz)-1] -// -// res, err = querier(ctx, []string{types.QueryDelegatorValidators}, query) -// require.Error(t, err) -// -// // Query bonded validator -// queryBondParams := types.NewQueryBondsParams(addrAcc2, addrVal1) -// bz, errRes = cdc.MarshalJSON(queryBondParams) -// require.NoError(t, errRes) -// -// query = abci.RequestQuery{ -// Path: "/custom/staking/delegatorValidator", -// Data: bz, -// } -// -// res, err = querier(ctx, []string{types.QueryDelegatorValidator}, query) -// require.NoError(t, err) -// -// var validator types.Validator -// errRes = cdc.UnmarshalJSON(res, &validator) -// require.NoError(t, errRes) -// -// require.Equal(t, delValidators[0], validator) -// -// // error unknown request -// query.Data = bz[:len(bz)-1] -// -// res, err = querier(ctx, []string{types.QueryDelegatorValidator}, query) -// require.Error(t, err) -// -// // Query delegation -// -// query = abci.RequestQuery{ -// Path: "/custom/staking/delegation", -// Data: bz, -// } -// -// delegation, found := app.StakingKeeper.GetDelegation(ctx, addrAcc2, addrVal1) -// require.True(t, found) -// -// res, err = querier(ctx, []string{types.QueryDelegation}, query) -// require.NoError(t, err) -// -// var delegationRes types.DelegationResponse -// errRes = cdc.UnmarshalJSON(res, &delegationRes) -// require.NoError(t, errRes) -// -// require.Equal(t, delegation.ValidatorAddress, delegationRes.ValidatorAddress) -// require.Equal(t, delegation.DelegatorAddress, delegationRes.DelegatorAddress) -// require.Equal(t, sdk.NewCoin(sdk.DefaultBondDenom, delegation.Shares.TruncateInt()), delegationRes.Balance) -// -// // Query Delegator Delegations -// query = abci.RequestQuery{ -// Path: "/custom/staking/delegatorDelegations", -// Data: bz, -// } -// -// res, err = querier(ctx, []string{types.QueryDelegatorDelegations}, query) -// require.NoError(t, err) -// -// var delegatorDelegations types.DelegationResponses -// errRes = cdc.UnmarshalJSON(res, &delegatorDelegations) -// require.NoError(t, errRes) -// require.Len(t, delegatorDelegations, 1) -// require.Equal(t, delegation.ValidatorAddress, delegatorDelegations[0].ValidatorAddress) -// require.Equal(t, delegation.DelegatorAddress, delegatorDelegations[0].DelegatorAddress) -// require.Equal(t, sdk.NewCoin(sdk.DefaultBondDenom, delegation.Shares.TruncateInt()), delegatorDelegations[0].Balance) -// -// // error unknown request -// query.Data = bz[:len(bz)-1] -// -// res, err = querier(ctx, []string{types.QueryDelegation}, query) -// require.Error(t, err) -// -// // Query validator delegations -// -// bz, errRes = cdc.MarshalJSON(types.NewQueryValidatorParams(addrVal1)) -// require.NoError(t, errRes) -// -// query = abci.RequestQuery{ -// Path: "custom/staking/validatorDelegations", -// Data: bz, -// } -// -// res, err = querier(ctx, []string{types.QueryValidatorDelegations}, query) -// require.NoError(t, err) -// -// var delegationsRes types.DelegationResponses -// errRes = cdc.UnmarshalJSON(res, &delegationsRes) -// require.NoError(t, errRes) -// require.Len(t, delegatorDelegations, 1) -// require.Equal(t, delegation.ValidatorAddress, delegationsRes[0].ValidatorAddress) -// require.Equal(t, delegation.DelegatorAddress, delegationsRes[0].DelegatorAddress) -// require.Equal(t, sdk.NewCoin(sdk.DefaultBondDenom, delegation.Shares.TruncateInt()), delegationsRes[0].Balance) -// -// // Query unbonging delegation -// unbondingTokens := sdk.TokensFromConsensusPower(10) -// _, err = app.StakingKeeper.Undelegate(ctx, addrAcc2, val1.OperatorAddress, unbondingTokens.ToDec()) -// require.NoError(t, err) -// -// queryBondParams = types.NewQueryBondsParams(addrAcc2, addrVal1) -// bz, errRes = cdc.MarshalJSON(queryBondParams) -// require.NoError(t, errRes) -// -// query = abci.RequestQuery{ -// Path: "/custom/staking/unbondingDelegation", -// Data: bz, -// } -// -// unbond, found := app.StakingKeeper.GetUnbondingDelegation(ctx, addrAcc2, addrVal1) -// require.True(t, found) -// -// res, err = querier(ctx, []string{types.QueryUnbondingDelegation}, query) -// require.NoError(t, err) -// -// var unbondRes types.UnbondingDelegation -// errRes = cdc.UnmarshalJSON(res, &unbondRes) -// require.NoError(t, errRes) -// -// require.Equal(t, unbond, unbondRes) -// -// // error unknown request -// query.Data = bz[:len(bz)-1] -// -// _, err = querier(ctx, []string{types.QueryUnbondingDelegation}, query) -// require.Error(t, err) -// -// // Query Delegator Delegations -// -// query = abci.RequestQuery{ -// Path: "/custom/staking/delegatorUnbondingDelegations", -// Data: bz, -// } -// -// res, err = querier(ctx, []string{types.QueryDelegatorUnbondingDelegations}, query) -// require.NoError(t, err) -// -// var delegatorUbds []types.UnbondingDelegation -// errRes = cdc.UnmarshalJSON(res, &delegatorUbds) -// require.NoError(t, errRes) -// require.Equal(t, unbond, delegatorUbds[0]) -// -// // error unknown request -// query.Data = bz[:len(bz)-1] -// -// _, err = querier(ctx, []string{types.QueryDelegatorUnbondingDelegations}, query) -// require.Error(t, err) -// -// // Query redelegation -// redelegationTokens := sdk.TokensFromConsensusPower(10) -// _, err = app.StakingKeeper.BeginRedelegation(ctx, addrAcc2, val1.OperatorAddress, -// val2.OperatorAddress, redelegationTokens.ToDec()) -// require.NoError(t, err) -// redel, found := app.StakingKeeper.GetRedelegation(ctx, addrAcc2, val1.OperatorAddress, val2.OperatorAddress) -// require.True(t, found) -// -// bz, errRes = cdc.MarshalJSON(types.NewQueryRedelegationParams(addrAcc2, val1.OperatorAddress, val2.OperatorAddress)) -// require.NoError(t, errRes) -// -// query = abci.RequestQuery{ -// Path: "/custom/staking/redelegations", -// Data: bz, -// } -// +func TestQueryDelegation(t *testing.T) { + cdc := codec.New() + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + params := app.StakingKeeper.GetParams(ctx) + querier := staking.NewQuerier(app.StakingKeeper) + + addrs := simapp.AddTestAddrs(app, ctx, 500, sdk.NewInt(10000)) + + + // Create Validators and Delegation + val1 := types.NewValidator(addrVal1, pk1, types.Description{}) + app.StakingKeeper.SetValidator(ctx, val1) + app.StakingKeeper.SetValidatorByPowerIndex(ctx, val1) + + val2 := types.NewValidator(addrVal2, pk2, types.Description{}) + app.StakingKeeper.SetValidator(ctx, val2) + app.StakingKeeper.SetValidatorByPowerIndex(ctx, val2) + + delTokens := sdk.TokensFromConsensusPower(20) + app.StakingKeeper.Delegate(ctx, addrAcc2, delTokens, sdk.Unbonded, val1, true) + + // apply TM updates + app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + + // Query Delegator bonded validators + queryParams := types.NewQueryDelegatorParams(addrAcc2) + bz, errRes := cdc.MarshalJSON(queryParams) + require.NoError(t, errRes) + + query := abci.RequestQuery{ + Path: "/custom/staking/delegatorValidators", + Data: bz, + } + + delValidators := app.StakingKeeper.GetDelegatorValidators(ctx, addrAcc2, params.MaxValidators) + + res, err := querier(ctx, []string{types.QueryDelegatorValidators}, query) + require.NoError(t, err) + + var validatorsResp []types.Validator + errRes = cdc.UnmarshalJSON(res, &validatorsResp) + require.NoError(t, errRes) + + require.Equal(t, len(delValidators), len(validatorsResp)) + require.ElementsMatch(t, delValidators, validatorsResp) + + // error unknown request + query.Data = bz[:len(bz)-1] + + res, err = querier(ctx, []string{types.QueryDelegatorValidators}, query) + require.Error(t, err) + + // Query bonded validator + queryBondParams := types.NewQueryBondsParams(addrAcc2, addrVal1) + bz, errRes = cdc.MarshalJSON(queryBondParams) + require.NoError(t, errRes) + + query = abci.RequestQuery{ + Path: "/custom/staking/delegatorValidator", + Data: bz, + } + + res, err = querier(ctx, []string{types.QueryDelegatorValidator}, query) + require.NoError(t, err) + + var validator types.Validator + errRes = cdc.UnmarshalJSON(res, &validator) + require.NoError(t, errRes) + + require.Equal(t, delValidators[0], validator) + + // error unknown request + query.Data = bz[:len(bz)-1] + + res, err = querier(ctx, []string{types.QueryDelegatorValidator}, query) + require.Error(t, err) + + // Query delegation + + query = abci.RequestQuery{ + Path: "/custom/staking/delegation", + Data: bz, + } + + delegation, found := app.StakingKeeper.GetDelegation(ctx, addrAcc2, addrVal1) + require.True(t, found) + + res, err = querier(ctx, []string{types.QueryDelegation}, query) + require.NoError(t, err) + + var delegationRes types.DelegationResponse + errRes = cdc.UnmarshalJSON(res, &delegationRes) + require.NoError(t, errRes) + + require.Equal(t, delegation.ValidatorAddress, delegationRes.ValidatorAddress) + require.Equal(t, delegation.DelegatorAddress, delegationRes.DelegatorAddress) + require.Equal(t, sdk.NewCoin(sdk.DefaultBondDenom, delegation.Shares.TruncateInt()), delegationRes.Balance) + + // Query Delegator Delegations + query = abci.RequestQuery{ + Path: "/custom/staking/delegatorDelegations", + Data: bz, + } + + res, err = querier(ctx, []string{types.QueryDelegatorDelegations}, query) + require.NoError(t, err) + + var delegatorDelegations types.DelegationResponses + errRes = cdc.UnmarshalJSON(res, &delegatorDelegations) + require.NoError(t, errRes) + require.Len(t, delegatorDelegations, 1) + require.Equal(t, delegation.ValidatorAddress, delegatorDelegations[0].ValidatorAddress) + require.Equal(t, delegation.DelegatorAddress, delegatorDelegations[0].DelegatorAddress) + require.Equal(t, sdk.NewCoin(sdk.DefaultBondDenom, delegation.Shares.TruncateInt()), delegatorDelegations[0].Balance) + + // error unknown request + query.Data = bz[:len(bz)-1] + + res, err = querier(ctx, []string{types.QueryDelegation}, query) + require.Error(t, err) + + // Query validator delegations + + bz, errRes = cdc.MarshalJSON(types.NewQueryValidatorParams(addrVal1)) + require.NoError(t, errRes) + + query = abci.RequestQuery{ + Path: "custom/staking/validatorDelegations", + Data: bz, + } + + res, err = querier(ctx, []string{types.QueryValidatorDelegations}, query) + require.NoError(t, err) + + var delegationsRes types.DelegationResponses + errRes = cdc.UnmarshalJSON(res, &delegationsRes) + require.NoError(t, errRes) + require.Len(t, delegatorDelegations, 1) + require.Equal(t, delegation.ValidatorAddress, delegationsRes[0].ValidatorAddress) + require.Equal(t, delegation.DelegatorAddress, delegationsRes[0].DelegatorAddress) + require.Equal(t, sdk.NewCoin(sdk.DefaultBondDenom, delegation.Shares.TruncateInt()), delegationsRes[0].Balance) + + // Query unbonging delegation + unbondingTokens := sdk.TokensFromConsensusPower(10) + _, err = app.StakingKeeper.Undelegate(ctx, addrAcc2, val1.OperatorAddress, unbondingTokens.ToDec()) + require.NoError(t, err) + + queryBondParams = types.NewQueryBondsParams(addrAcc2, addrVal1) + bz, errRes = cdc.MarshalJSON(queryBondParams) + require.NoError(t, errRes) + + query = abci.RequestQuery{ + Path: "/custom/staking/unbondingDelegation", + Data: bz, + } + + unbond, found := app.StakingKeeper.GetUnbondingDelegation(ctx, addrAcc2, addrVal1) + require.True(t, found) + + res, err = querier(ctx, []string{types.QueryUnbondingDelegation}, query) + require.NoError(t, err) + + var unbondRes types.UnbondingDelegation + errRes = cdc.UnmarshalJSON(res, &unbondRes) + require.NoError(t, errRes) + + require.Equal(t, unbond, unbondRes) + + // error unknown request + query.Data = bz[:len(bz)-1] + + _, err = querier(ctx, []string{types.QueryUnbondingDelegation}, query) + require.Error(t, err) + + // Query Delegator Delegations + + query = abci.RequestQuery{ + Path: "/custom/staking/delegatorUnbondingDelegations", + Data: bz, + } + + res, err = querier(ctx, []string{types.QueryDelegatorUnbondingDelegations}, query) + require.NoError(t, err) + + var delegatorUbds []types.UnbondingDelegation + errRes = cdc.UnmarshalJSON(res, &delegatorUbds) + require.NoError(t, errRes) + require.Equal(t, unbond, delegatorUbds[0]) + + // error unknown request + query.Data = bz[:len(bz)-1] + + _, err = querier(ctx, []string{types.QueryDelegatorUnbondingDelegations}, query) + require.Error(t, err) + + // Query redelegation + redelegationTokens := sdk.TokensFromConsensusPower(10) + _, err = app.StakingKeeper.BeginRedelegation(ctx, addrAcc2, val1.OperatorAddress, + val2.OperatorAddress, redelegationTokens.ToDec()) + require.NoError(t, err) + redel, found := app.StakingKeeper.GetRedelegation(ctx, addrAcc2, val1.OperatorAddress, val2.OperatorAddress) + require.True(t, found) + + bz, errRes = cdc.MarshalJSON(types.NewQueryRedelegationParams(addrAcc2, val1.OperatorAddress, val2.OperatorAddress)) + require.NoError(t, errRes) + + query = abci.RequestQuery{ + Path: "/custom/staking/redelegations", + Data: bz, + } + // res, err = querier(ctx, []string{types.QueryRedelegations}, query) // require.NoError(t, err) // diff --git a/x/staking/keeper/common_refactor_test.go b/x/staking/keeper/test_common_test.go similarity index 99% rename from x/staking/keeper/common_refactor_test.go rename to x/staking/keeper/test_common_test.go index 8b43af1739f2..936c028148d2 100644 --- a/x/staking/keeper/common_refactor_test.go +++ b/x/staking/keeper/test_common_test.go @@ -59,6 +59,7 @@ func createTestPubKeys(numPubKeys int) []crypto.PubKey { publicKeys = append(publicKeys, NewPubKey(buffer.String())) buffer.Reset() } + return publicKeys } @@ -75,11 +76,11 @@ func NewPubKey(pk string) (res crypto.PubKey) { // for incode address generation func CreateTestAddr(addr string, bech string) sdk.AccAddress { - res, err := sdk.AccAddressFromHex(addr) if err != nil { panic(err) } + bechexpected := res.String() if bech != bechexpected { panic("Bech encoding doesn't match reference") From 4aa078b5f347cbe5efb5b07cf64501eaf51374cb Mon Sep 17 00:00:00 2001 From: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Date: Wed, 19 Feb 2020 10:56:22 +0100 Subject: [PATCH 154/529] x/ibc ICS24 (#5588) * x/ibc ICS24 * changelog * move regex to /types * address @alexanderbez comments Co-authored-by: Jack Zampolin Co-authored-by: Alexander Bezobchuk --- CHANGELOG.md | 4 ++ types/router.go | 24 ++++++++-- x/ibc/24-host/errors.go | 15 ++++++ x/ibc/24-host/utils.go | 11 +++++ x/ibc/24-host/validate.go | 96 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 147 insertions(+), 3 deletions(-) create mode 100644 x/ibc/24-host/errors.go create mode 100644 x/ibc/24-host/utils.go create mode 100644 x/ibc/24-host/validate.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 09179f2640bc..34c617d89f9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -60,6 +60,10 @@ and provided directly the IAVL store. * (types) [\#5533](https://github.com/cosmos/cosmos-sdk/pull/5533) Refactored `AppModuleBasic` and `AppModuleGenesis` to now accept a `codec.JSONMarshaler` for modular serialization of genesis state. +### Features + +* (x/ibc) [\#5588](https://github.com/cosmos/cosmos-sdk/pull/5588) Add [ICS 024 - Host State Machine Requirements](https://github.com/cosmos/ics/tree/master/spec/ics-024-host-requirements) subpackage to `x/ibc` module. + ### Bug Fixes * (client) [\#5618](https://github.com/cosmos/cosmos-sdk/pull/5618) Fix crash on the client when the verifier is not set. diff --git a/types/router.go b/types/router.go index f3593f5530ff..12d0455f805d 100644 --- a/types/router.go +++ b/types/router.go @@ -2,9 +2,27 @@ package types import "regexp" -// IsAlphaNumeric defines a regular expression for matching against alpha-numeric -// values. -var IsAlphaNumeric = regexp.MustCompile(`^[a-zA-Z0-9]+$`).MatchString +var ( + // IsAlphaNumeric defines a regular expression for matching against alpha-numeric + // values. + IsAlphaNumeric = regexp.MustCompile(`^[a-zA-Z0-9]+$`).MatchString + + // IsAlphaLower defines regular expression to check if the string has lowercase + // alphabetic characters only. + IsAlphaLower = regexp.MustCompile(`^[a-z]+$`).MatchString + + // IsAlphaUpper defines regular expression to check if the string has uppercase + // alphabetic characters only. + IsAlphaUpper = regexp.MustCompile(`^[A-Z]+$`).MatchString + + // IsAlpha defines regular expression to check if the string has alphabetic + // characters only. + IsAlpha = regexp.MustCompile(`^[a-zA-Z]+$`).MatchString + + // IsNumeric defines regular expression to check if the string has numeric + // characters only. + IsNumeric = regexp.MustCompile(`^[0-9]+$`).MatchString +) // Router provides handlers for each transaction type. type Router interface { diff --git a/x/ibc/24-host/errors.go b/x/ibc/24-host/errors.go new file mode 100644 index 000000000000..26b7919e6cb5 --- /dev/null +++ b/x/ibc/24-host/errors.go @@ -0,0 +1,15 @@ +package host + +import ( + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +// SubModuleName defines the ICS 24 host +const SubModuleName = "host" + +// IBC client sentinel errors +var ( + ErrInvalidID = sdkerrors.Register(SubModuleName, 1, "invalid identifier") + ErrInvalidPath = sdkerrors.Register(SubModuleName, 2, "invalid path") + ErrInvalidPacket = sdkerrors.Register(SubModuleName, 3, "invalid packet") +) diff --git a/x/ibc/24-host/utils.go b/x/ibc/24-host/utils.go new file mode 100644 index 000000000000..c75f356561f6 --- /dev/null +++ b/x/ibc/24-host/utils.go @@ -0,0 +1,11 @@ +package host + +// RemovePath is an util function to remove a path from a set. +func RemovePath(paths []string, path string) ([]string, bool) { + for i, p := range paths { + if p == path { + return append(paths[:i], paths[i+1:]...), true + } + } + return paths, false +} diff --git a/x/ibc/24-host/validate.go b/x/ibc/24-host/validate.go new file mode 100644 index 000000000000..e75e63e6c2dd --- /dev/null +++ b/x/ibc/24-host/validate.go @@ -0,0 +1,96 @@ +package host + +import ( + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +// ICS 024 Identifier and Path Validation Implementation +// +// This file defines ValidateFn to validate identifier and path strings +// The spec for ICS 024 can be located here: +// https://github.com/cosmos/ics/tree/master/spec/ics-024-host-requirements + +// ValidateFn function type to validate path and identifier bytestrings +type ValidateFn func(string) error + +func defaultIdentifierValidator(id string, min, max int) error { + // valid id MUST NOT contain "/" separator + if strings.Contains(id, "/") { + return sdkerrors.Wrapf(ErrInvalidID, "identifier %s cannot contain separator '/'", id) + } + // valid id must be between 10 and 20 characters + if len(id) < min || len(id) > max { + return sdkerrors.Wrapf(ErrInvalidID, "identifier %s has invalid length: %d, must be between %d-%d characters", id, len(id), min, max) + } + // valid id must contain only lower alphabetic characters + if !sdk.IsAlphaLower(id) { + return sdkerrors.Wrapf(ErrInvalidID, "identifier %s must contain only lowercase alphabetic characters", id) + } + return nil +} + +// DefaultClientIdentifierValidator is the default validator function for Client identifiers +// A valid Identifier must be between 10-20 characters and only contain lowercase +// alphabetic characters, +func DefaultClientIdentifierValidator(id string) error { + return defaultIdentifierValidator(id, 10, 20) +} + +// DefaultConnectionIdentifierValidator is the default validator function for Connection identifiers +// A valid Identifier must be between 10-20 characters and only contain lowercase +// alphabetic characters, +func DefaultConnectionIdentifierValidator(id string) error { + return defaultIdentifierValidator(id, 10, 20) +} + +// DefaultChannelIdentifierValidator is the default validator function for Channel identifiers +// A valid Identifier must be between 10-20 characters and only contain lowercase +// alphabetic characters, +func DefaultChannelIdentifierValidator(id string) error { + return defaultIdentifierValidator(id, 10, 20) +} + +// DefaultPortIdentifierValidator is the default validator function for Port identifiers +// A valid Identifier must be between 2-20 characters and only contain lowercase +// alphabetic characters, +func DefaultPortIdentifierValidator(id string) error { + return defaultIdentifierValidator(id, 2, 20) +} + +// NewPathValidator takes in a Identifier Validator function and returns +// a Path Validator function which requires path only has valid identifiers +// alphanumeric character strings, and "/" separators +func NewPathValidator(idValidator ValidateFn) ValidateFn { + return func(path string) error { + pathArr := strings.Split(path, "/") + for _, p := range pathArr { + // Each path element must either be valid identifier or alphanumeric + err := idValidator(p) + if err != nil && !sdk.IsAlphaNumeric(p) { + return sdkerrors.Wrapf(ErrInvalidPath, "path %s contains invalid identifier or non-alphanumeric path element: %s", path, p) + } + } + return nil + } +} + +// DefaultPathValidator takes in path string and validates +// with default identifier rules. This is optimized by simply +// checking that all path elements are alphanumeric +func DefaultPathValidator(path string) error { + pathArr := strings.Split(path, "/") + if pathArr[0] == path { + return sdkerrors.Wrapf(ErrInvalidPath, "path %s doesn't contain any separator '/'", path) + } + + for _, p := range pathArr { + // Each path element must be alphanumeric and non-blank + if strings.TrimSpace(p) == "" || !sdk.IsAlphaNumeric(p) { + return sdkerrors.Wrapf(ErrInvalidPath, "path %s contains an invalid non-alphanumeric character: '%s'", path, p) + } + } + return nil +} From 434f539bffea6a9d5c7a60e07229f9af0e125c6a Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Wed, 19 Feb 2020 12:52:20 +0100 Subject: [PATCH 155/529] Merge PR #5649: Update x/params to follow module standards --- simapp/app.go | 3 +- simapp/sim_test.go | 5 +- x/auth/keeper/keeper.go | 6 +-- x/auth/types/params.go | 24 ++++----- x/bank/internal/keeper/keeper.go | 10 ++-- x/bank/internal/types/params.go | 8 +-- x/crisis/internal/keeper/keeper.go | 6 +-- x/crisis/internal/types/params.go | 8 +-- x/distribution/keeper/keeper.go | 10 ++-- x/distribution/keeper/test_common.go | 11 ++-- x/distribution/types/params.go | 18 +++---- x/evidence/internal/keeper/keeper.go | 6 +-- x/evidence/internal/types/params.go | 14 ++--- x/gov/keeper/test_common.go | 9 ++-- x/gov/types/params.go | 12 ++--- x/mint/internal/keeper/keeper.go | 6 +-- x/mint/internal/types/params.go | 22 ++++---- x/params/alias.go | 43 ++++----------- x/params/client/cli/tx.go | 4 +- x/params/client/rest/rest.go | 4 +- x/params/client/utils/utils.go | 10 ++-- .../common_test.go} | 34 ++++++------ x/params/{ => keeper}/keeper.go | 22 ++++---- x/params/{ => keeper}/keeper_test.go | 54 +++++++++---------- x/params/module.go | 6 +-- x/params/proposal_handler.go | 12 +++-- x/params/proposal_handler_test.go | 39 +++++++------- x/params/simulation/operations.go | 8 +-- x/params/subspace/table_test.go | 46 ---------------- x/params/{subspace => types}/common_test.go | 12 ++--- x/params/{subspace => types}/doc.go | 2 +- x/params/{subspace => types}/paramset.go | 2 +- x/params/types/{ => proposal}/codec.go | 2 +- x/params/types/{ => proposal}/errors.go | 2 +- x/params/types/{ => proposal}/keys.go | 2 +- x/params/types/{ => proposal}/proposal.go | 2 +- .../types/{ => proposal}/proposal_test.go | 2 +- x/params/types/{ => proposal}/types.pb.go | 54 ++++++++++--------- x/params/types/{ => proposal}/types.proto | 2 +- x/params/{subspace => types}/subspace.go | 5 +- x/params/{subspace => types}/subspace_test.go | 14 ++--- x/params/{subspace => types}/table.go | 2 +- x/params/types/table_test.go | 45 ++++++++++++++++ x/slashing/internal/keeper/test_common.go | 11 ++-- x/slashing/internal/types/expected_keepers.go | 8 +-- x/slashing/internal/types/params.go | 20 +++---- x/staking/keeper/keeper.go | 6 +-- x/staking/keeper/params.go | 6 +-- x/staking/keeper/test_common.go | 10 ++-- x/staking/types/params.go | 18 +++---- 50 files changed, 339 insertions(+), 348 deletions(-) rename x/params/{commmon_test.go => keeper/common_test.go} (81%) rename x/params/{ => keeper}/keeper.go (67%) rename x/params/{ => keeper}/keeper_test.go (81%) delete mode 100644 x/params/subspace/table_test.go rename x/params/{subspace => types}/common_test.go (83%) rename x/params/{subspace => types}/doc.go (97%) rename x/params/{subspace => types}/paramset.go (97%) rename x/params/types/{ => proposal}/codec.go (97%) rename x/params/types/{ => proposal}/errors.go (97%) rename x/params/types/{ => proposal}/keys.go (90%) rename x/params/types/{ => proposal}/proposal.go (99%) rename x/params/types/{ => proposal}/proposal_test.go (98%) rename x/params/types/{ => proposal}/types.pb.go (87%) rename x/params/types/{ => proposal}/types.proto (89%) rename x/params/{subspace => types}/subspace.go (99%) rename x/params/{subspace => types}/subspace_test.go (94%) rename x/params/{subspace => types}/table.go (98%) create mode 100644 x/params/types/table_test.go diff --git a/simapp/app.go b/simapp/app.go index 8c77d03c54ad..e1d646f7c978 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -26,6 +26,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/mint" "github.com/cosmos/cosmos-sdk/x/params" paramsclient "github.com/cosmos/cosmos-sdk/x/params/client" + paramproposal "github.com/cosmos/cosmos-sdk/x/params/types/proposal" "github.com/cosmos/cosmos-sdk/x/slashing" "github.com/cosmos/cosmos-sdk/x/staking" "github.com/cosmos/cosmos-sdk/x/supply" @@ -202,7 +203,7 @@ func NewSimApp( // register the proposal types govRouter := gov.NewRouter() govRouter.AddRoute(gov.RouterKey, gov.ProposalHandler). - AddRoute(params.RouterKey, params.NewParamChangeProposalHandler(app.ParamsKeeper)). + AddRoute(paramproposal.RouterKey, params.NewParamChangeProposalHandler(app.ParamsKeeper)). AddRoute(distr.RouterKey, distr.NewCommunityPoolSpendProposalHandler(app.DistrKeeper)). AddRoute(upgrade.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(app.UpgradeKeeper)) app.GovKeeper = gov.NewKeeper( diff --git a/simapp/sim_test.go b/simapp/sim_test.go index e10afad8a4a1..18cb24a89484 100644 --- a/simapp/sim_test.go +++ b/simapp/sim_test.go @@ -8,6 +8,7 @@ import ( "testing" "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" dbm "github.com/tendermint/tm-db" @@ -20,7 +21,7 @@ import ( distr "github.com/cosmos/cosmos-sdk/x/distribution" "github.com/cosmos/cosmos-sdk/x/gov" "github.com/cosmos/cosmos-sdk/x/mint" - "github.com/cosmos/cosmos-sdk/x/params" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" "github.com/cosmos/cosmos-sdk/x/simulation" "github.com/cosmos/cosmos-sdk/x/slashing" "github.com/cosmos/cosmos-sdk/x/staking" @@ -152,7 +153,7 @@ func TestAppImportExport(t *testing.T) { {app.keys[mint.StoreKey], newApp.keys[mint.StoreKey], [][]byte{}}, {app.keys[distr.StoreKey], newApp.keys[distr.StoreKey], [][]byte{}}, {app.keys[supply.StoreKey], newApp.keys[supply.StoreKey], [][]byte{}}, - {app.keys[params.StoreKey], newApp.keys[params.StoreKey], [][]byte{}}, + {app.keys[paramtypes.StoreKey], newApp.keys[paramtypes.StoreKey], [][]byte{}}, {app.keys[gov.StoreKey], newApp.keys[gov.StoreKey], [][]byte{}}, } diff --git a/x/auth/keeper/keeper.go b/x/auth/keeper/keeper.go index 18ecc0471119..df5228fa7f03 100644 --- a/x/auth/keeper/keeper.go +++ b/x/auth/keeper/keeper.go @@ -11,7 +11,7 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/auth/exported" "github.com/cosmos/cosmos-sdk/x/auth/types" - "github.com/cosmos/cosmos-sdk/x/params/subspace" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" ) // AccountKeeper encodes/decodes accounts using the go-amino (binary) @@ -19,7 +19,7 @@ import ( type AccountKeeper struct { key sdk.StoreKey cdc types.Codec - paramSubspace subspace.Subspace + paramSubspace paramtypes.Subspace // The prototypical Account constructor. proto func() exported.Account @@ -28,7 +28,7 @@ type AccountKeeper struct { // NewAccountKeeper returns a new sdk.AccountKeeper that uses go-amino to // (binary) encode and decode concrete sdk.Accounts. func NewAccountKeeper( - cdc types.Codec, key sdk.StoreKey, paramstore subspace.Subspace, proto func() exported.Account, + cdc types.Codec, key sdk.StoreKey, paramstore paramtypes.Subspace, proto func() exported.Account, ) AccountKeeper { return AccountKeeper{ diff --git a/x/auth/types/params.go b/x/auth/types/params.go index 8ad49df1157b..f2347e299b5a 100644 --- a/x/auth/types/params.go +++ b/x/auth/types/params.go @@ -3,9 +3,9 @@ package types import ( "fmt" - "github.com/cosmos/cosmos-sdk/x/params" - "github.com/cosmos/cosmos-sdk/x/params/subspace" yaml "gopkg.in/yaml.v2" + + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" ) // DefaultParamspace defines the default auth module parameter subspace @@ -29,7 +29,7 @@ var ( KeySigVerifyCostSecp256k1 = []byte("SigVerifyCostSecp256k1") ) -var _ subspace.ParamSet = &Params{} +var _ paramtypes.ParamSet = &Params{} // NewParams creates a new Params object func NewParams( @@ -46,20 +46,20 @@ func NewParams( } // ParamKeyTable for auth module -func ParamKeyTable() subspace.KeyTable { - return subspace.NewKeyTable().RegisterParamSet(&Params{}) +func ParamKeyTable() paramtypes.KeyTable { + return paramtypes.NewKeyTable().RegisterParamSet(&Params{}) } // ParamSetPairs implements the ParamSet interface and returns all the key/value pairs // pairs of auth module's parameters. // nolint -func (p *Params) ParamSetPairs() subspace.ParamSetPairs { - return subspace.ParamSetPairs{ - params.NewParamSetPair(KeyMaxMemoCharacters, &p.MaxMemoCharacters, validateMaxMemoCharacters), - params.NewParamSetPair(KeyTxSigLimit, &p.TxSigLimit, validateTxSigLimit), - params.NewParamSetPair(KeyTxSizeCostPerByte, &p.TxSizeCostPerByte, validateTxSizeCostPerByte), - params.NewParamSetPair(KeySigVerifyCostED25519, &p.SigVerifyCostED25519, validateSigVerifyCostED25519), - params.NewParamSetPair(KeySigVerifyCostSecp256k1, &p.SigVerifyCostSecp256k1, validateSigVerifyCostSecp256k1), +func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { + return paramtypes.ParamSetPairs{ + paramtypes.NewParamSetPair(KeyMaxMemoCharacters, &p.MaxMemoCharacters, validateMaxMemoCharacters), + paramtypes.NewParamSetPair(KeyTxSigLimit, &p.TxSigLimit, validateTxSigLimit), + paramtypes.NewParamSetPair(KeyTxSizeCostPerByte, &p.TxSizeCostPerByte, validateTxSizeCostPerByte), + paramtypes.NewParamSetPair(KeySigVerifyCostED25519, &p.SigVerifyCostED25519, validateSigVerifyCostED25519), + paramtypes.NewParamSetPair(KeySigVerifyCostSecp256k1, &p.SigVerifyCostSecp256k1, validateSigVerifyCostSecp256k1), } } diff --git a/x/bank/internal/keeper/keeper.go b/x/bank/internal/keeper/keeper.go index 3f8529ad7923..1475a85cfb92 100644 --- a/x/bank/internal/keeper/keeper.go +++ b/x/bank/internal/keeper/keeper.go @@ -12,7 +12,7 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" vestexported "github.com/cosmos/cosmos-sdk/x/auth/vesting/exported" "github.com/cosmos/cosmos-sdk/x/bank/internal/types" - "github.com/cosmos/cosmos-sdk/x/params" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" ) var _ Keeper = (*BaseKeeper)(nil) @@ -31,11 +31,11 @@ type BaseKeeper struct { BaseSendKeeper ak types.AccountKeeper - paramSpace params.Subspace + paramSpace paramtypes.Subspace } func NewBaseKeeper( - cdc *codec.Codec, storeKey sdk.StoreKey, ak types.AccountKeeper, paramSpace params.Subspace, blacklistedAddrs map[string]bool, + cdc *codec.Codec, storeKey sdk.StoreKey, ak types.AccountKeeper, paramSpace paramtypes.Subspace, blacklistedAddrs map[string]bool, ) BaseKeeper { ps := paramSpace.WithKeyTable(types.ParamKeyTable()) @@ -149,14 +149,14 @@ type BaseSendKeeper struct { cdc *codec.Codec ak types.AccountKeeper storeKey sdk.StoreKey - paramSpace params.Subspace + paramSpace paramtypes.Subspace // list of addresses that are restricted from receiving transactions blacklistedAddrs map[string]bool } func NewBaseSendKeeper( - cdc *codec.Codec, storeKey sdk.StoreKey, ak types.AccountKeeper, paramSpace params.Subspace, blacklistedAddrs map[string]bool, + cdc *codec.Codec, storeKey sdk.StoreKey, ak types.AccountKeeper, paramSpace paramtypes.Subspace, blacklistedAddrs map[string]bool, ) BaseSendKeeper { return BaseSendKeeper{ diff --git a/x/bank/internal/types/params.go b/x/bank/internal/types/params.go index cdd6aff84f81..68a8fcd49864 100644 --- a/x/bank/internal/types/params.go +++ b/x/bank/internal/types/params.go @@ -3,7 +3,7 @@ package types import ( "fmt" - "github.com/cosmos/cosmos-sdk/x/params" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" ) const ( @@ -17,9 +17,9 @@ const ( var ParamStoreKeySendEnabled = []byte("sendenabled") // ParamKeyTable type declaration for parameters -func ParamKeyTable() params.KeyTable { - return params.NewKeyTable( - params.NewParamSetPair(ParamStoreKeySendEnabled, false, validateSendEnabled), +func ParamKeyTable() paramtypes.KeyTable { + return paramtypes.NewKeyTable( + paramtypes.NewParamSetPair(ParamStoreKeySendEnabled, false, validateSendEnabled), ) } diff --git a/x/crisis/internal/keeper/keeper.go b/x/crisis/internal/keeper/keeper.go index f4c8163bb740..d57030ed6c1f 100644 --- a/x/crisis/internal/keeper/keeper.go +++ b/x/crisis/internal/keeper/keeper.go @@ -8,13 +8,13 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/crisis/internal/types" - "github.com/cosmos/cosmos-sdk/x/params" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" ) // Keeper - crisis keeper type Keeper struct { routes []types.InvarRoute - paramSpace params.Subspace + paramSpace paramtypes.Subspace invCheckPeriod uint supplyKeeper types.SupplyKeeper @@ -24,7 +24,7 @@ type Keeper struct { // NewKeeper creates a new Keeper object func NewKeeper( - paramSpace params.Subspace, invCheckPeriod uint, supplyKeeper types.SupplyKeeper, + paramSpace paramtypes.Subspace, invCheckPeriod uint, supplyKeeper types.SupplyKeeper, feeCollectorName string, ) Keeper { diff --git a/x/crisis/internal/types/params.go b/x/crisis/internal/types/params.go index 5749c9192e34..90aacd98ad24 100644 --- a/x/crisis/internal/types/params.go +++ b/x/crisis/internal/types/params.go @@ -4,7 +4,7 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/params" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" ) // Default parameter namespace @@ -18,9 +18,9 @@ var ( ) // type declaration for parameters -func ParamKeyTable() params.KeyTable { - return params.NewKeyTable( - params.NewParamSetPair(ParamStoreKeyConstantFee, sdk.Coin{}, validateConstantFee), +func ParamKeyTable() paramtypes.KeyTable { + return paramtypes.NewKeyTable( + paramtypes.NewParamSetPair(ParamStoreKeyConstantFee, sdk.Coin{}, validateConstantFee), ) } diff --git a/x/distribution/keeper/keeper.go b/x/distribution/keeper/keeper.go index 0074f84042a6..e1aeed7cad60 100644 --- a/x/distribution/keeper/keeper.go +++ b/x/distribution/keeper/keeper.go @@ -3,20 +3,20 @@ package keeper import ( "fmt" + "github.com/tendermint/tendermint/libs/log" + "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/distribution/types" - "github.com/cosmos/cosmos-sdk/x/params" - - "github.com/tendermint/tendermint/libs/log" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" ) // Keeper of the distribution store type Keeper struct { storeKey sdk.StoreKey cdc codec.Marshaler - paramSpace params.Subspace + paramSpace paramtypes.Subspace bankKeeper types.BankKeeper stakingKeeper types.StakingKeeper supplyKeeper types.SupplyKeeper @@ -28,7 +28,7 @@ type Keeper struct { // NewKeeper creates a new distribution Keeper instance func NewKeeper( - cdc codec.Marshaler, key sdk.StoreKey, paramSpace params.Subspace, bk types.BankKeeper, + cdc codec.Marshaler, key sdk.StoreKey, paramSpace paramtypes.Subspace, bk types.BankKeeper, sk types.StakingKeeper, supplyKeeper types.SupplyKeeper, feeCollectorName string, blacklistedAddrs map[string]bool, ) Keeper { diff --git a/x/distribution/keeper/test_common.go b/x/distribution/keeper/test_common.go index 811c46f553a1..a60b36985a4b 100644 --- a/x/distribution/keeper/test_common.go +++ b/x/distribution/keeper/test_common.go @@ -18,7 +18,8 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank" "github.com/cosmos/cosmos-sdk/x/distribution/types" - "github.com/cosmos/cosmos-sdk/x/params" + "github.com/cosmos/cosmos-sdk/x/params/keeper" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" "github.com/cosmos/cosmos-sdk/x/staking" "github.com/cosmos/cosmos-sdk/x/supply" ) @@ -88,7 +89,7 @@ func CreateTestInputDefault(t *testing.T, isCheckTx bool, initPower int64) ( // hogpodge of all sorts of input required for testing func CreateTestInputAdvanced( t *testing.T, isCheckTx bool, initPower int64, communityTax sdk.Dec, -) (sdk.Context, auth.AccountKeeper, bank.Keeper, Keeper, staking.Keeper, params.Keeper, types.SupplyKeeper, +) (sdk.Context, auth.AccountKeeper, bank.Keeper, Keeper, staking.Keeper, keeper.Keeper, types.SupplyKeeper, ) { initTokens := sdk.TokensFromConsensusPower(initPower) @@ -98,8 +99,8 @@ func CreateTestInputAdvanced( keyStaking := sdk.NewKVStoreKey(staking.StoreKey) keyAcc := sdk.NewKVStoreKey(auth.StoreKey) keySupply := sdk.NewKVStoreKey(supply.StoreKey) - keyParams := sdk.NewKVStoreKey(params.StoreKey) - tkeyParams := sdk.NewTransientStoreKey(params.TStoreKey) + keyParams := sdk.NewKVStoreKey(paramtypes.StoreKey) + tkeyParams := sdk.NewTransientStoreKey(paramtypes.TStoreKey) db := dbm.NewMemDB() ms := store.NewCommitMultiStore(db) @@ -127,7 +128,7 @@ func CreateTestInputAdvanced( cdc := MakeTestCodec() appCodec := simappcodec.NewAppCodec(cdc) - pk := params.NewKeeper(params.ModuleCdc, keyParams, tkeyParams) + pk := keeper.NewKeeper(appCodec, keyParams, tkeyParams) ctx := sdk.NewContext(ms, abci.Header{ChainID: "foochainid"}, isCheckTx, log.NewNopLogger()) accountKeeper := auth.NewAccountKeeper(appCodec, keyAcc, pk.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount) diff --git a/x/distribution/types/params.go b/x/distribution/types/params.go index 12daed847d47..33b6b2ca20cc 100644 --- a/x/distribution/types/params.go +++ b/x/distribution/types/params.go @@ -6,7 +6,7 @@ import ( "gopkg.in/yaml.v2" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/params" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" ) const ( @@ -23,8 +23,8 @@ var ( ) // ParamKeyTable returns the parameter key table. -func ParamKeyTable() params.KeyTable { - return params.NewKeyTable().RegisterParamSet(&Params{}) +func ParamKeyTable() paramtypes.KeyTable { + return paramtypes.NewKeyTable().RegisterParamSet(&Params{}) } // DefaultParams returns default distribution parameters @@ -43,12 +43,12 @@ func (p Params) String() string { } // ParamSetPairs returns the parameter set pairs. -func (p *Params) ParamSetPairs() params.ParamSetPairs { - return params.ParamSetPairs{ - params.NewParamSetPair(ParamStoreKeyCommunityTax, &p.CommunityTax, validateCommunityTax), - params.NewParamSetPair(ParamStoreKeyBaseProposerReward, &p.BaseProposerReward, validateBaseProposerReward), - params.NewParamSetPair(ParamStoreKeyBonusProposerReward, &p.BonusProposerReward, validateBonusProposerReward), - params.NewParamSetPair(ParamStoreKeyWithdrawAddrEnabled, &p.WithdrawAddrEnabled, validateWithdrawAddrEnabled), +func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { + return paramtypes.ParamSetPairs{ + paramtypes.NewParamSetPair(ParamStoreKeyCommunityTax, &p.CommunityTax, validateCommunityTax), + paramtypes.NewParamSetPair(ParamStoreKeyBaseProposerReward, &p.BaseProposerReward, validateBaseProposerReward), + paramtypes.NewParamSetPair(ParamStoreKeyBonusProposerReward, &p.BonusProposerReward, validateBonusProposerReward), + paramtypes.NewParamSetPair(ParamStoreKeyWithdrawAddrEnabled, &p.WithdrawAddrEnabled, validateWithdrawAddrEnabled), } } diff --git a/x/evidence/internal/keeper/keeper.go b/x/evidence/internal/keeper/keeper.go index 29a3df0bf374..ae6c66e623e7 100644 --- a/x/evidence/internal/keeper/keeper.go +++ b/x/evidence/internal/keeper/keeper.go @@ -12,7 +12,7 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/evidence/exported" "github.com/cosmos/cosmos-sdk/x/evidence/internal/types" - "github.com/cosmos/cosmos-sdk/x/params" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" ) // Keeper defines the evidence module's keeper. The keeper is responsible for @@ -21,14 +21,14 @@ import ( type Keeper struct { cdc *codec.Codec storeKey sdk.StoreKey - paramSpace params.Subspace + paramSpace paramtypes.Subspace router types.Router stakingKeeper types.StakingKeeper slashingKeeper types.SlashingKeeper } func NewKeeper( - cdc *codec.Codec, storeKey sdk.StoreKey, paramSpace params.Subspace, + cdc *codec.Codec, storeKey sdk.StoreKey, paramSpace paramtypes.Subspace, stakingKeeper types.StakingKeeper, slashingKeeper types.SlashingKeeper, ) *Keeper { diff --git a/x/evidence/internal/types/params.go b/x/evidence/internal/types/params.go index 5c0dbe638fa3..73f19ea0a804 100644 --- a/x/evidence/internal/types/params.go +++ b/x/evidence/internal/types/params.go @@ -4,9 +4,9 @@ import ( "fmt" "time" - "github.com/cosmos/cosmos-sdk/x/params" - "gopkg.in/yaml.v2" + + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" ) // DONTCOVER @@ -32,8 +32,8 @@ type Params struct { } // ParamKeyTable returns the parameter key table. -func ParamKeyTable() params.KeyTable { - return params.NewKeyTable().RegisterParamSet(&Params{}) +func ParamKeyTable() paramtypes.KeyTable { + return paramtypes.NewKeyTable().RegisterParamSet(&Params{}) } func (p Params) String() string { @@ -42,9 +42,9 @@ func (p Params) String() string { } // ParamSetPairs returns the parameter set pairs. -func (p *Params) ParamSetPairs() params.ParamSetPairs { - return params.ParamSetPairs{ - params.NewParamSetPair(KeyMaxEvidenceAge, &p.MaxEvidenceAge, validateMaxEvidenceAge), +func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { + return paramtypes.ParamSetPairs{ + paramtypes.NewParamSetPair(KeyMaxEvidenceAge, &p.MaxEvidenceAge, validateMaxEvidenceAge), } } diff --git a/x/gov/keeper/test_common.go b/x/gov/keeper/test_common.go index 13c6fc15da1d..d521b10bef3b 100644 --- a/x/gov/keeper/test_common.go +++ b/x/gov/keeper/test_common.go @@ -24,7 +24,8 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank" "github.com/cosmos/cosmos-sdk/x/gov/types" - "github.com/cosmos/cosmos-sdk/x/params" + "github.com/cosmos/cosmos-sdk/x/params/keeper" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" "github.com/cosmos/cosmos-sdk/x/staking" "github.com/cosmos/cosmos-sdk/x/supply" ) @@ -102,8 +103,8 @@ func createTestInput( keyGov := sdk.NewKVStoreKey(types.StoreKey) keyStaking := sdk.NewKVStoreKey(staking.StoreKey) keySupply := sdk.NewKVStoreKey(supply.StoreKey) - keyParams := sdk.NewKVStoreKey(params.StoreKey) - tkeyParams := sdk.NewTransientStoreKey(params.TStoreKey) + keyParams := sdk.NewKVStoreKey(paramtypes.StoreKey) + tkeyParams := sdk.NewTransientStoreKey(paramtypes.TStoreKey) db := dbm.NewMemDB() ms := store.NewCommitMultiStore(db) @@ -148,7 +149,7 @@ func createTestInput( blacklistedAddrs[notBondedPool.GetAddress().String()] = true blacklistedAddrs[bondPool.GetAddress().String()] = true - pk := params.NewKeeper(params.ModuleCdc, keyParams, tkeyParams) + pk := keeper.NewKeeper(appCodec, keyParams, tkeyParams) accountKeeper := auth.NewAccountKeeper(appCodec, keyAcc, pk.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount) bankKeeper := bank.NewBaseKeeper(cdc, keyBank, accountKeeper, pk.Subspace(bank.DefaultParamspace), blacklistedAddrs) supplyKeeper := supply.NewKeeper(appCodec, keySupply, accountKeeper, bankKeeper, maccPerms) diff --git a/x/gov/types/params.go b/x/gov/types/params.go index ff671d493169..d15ae88b8548 100644 --- a/x/gov/types/params.go +++ b/x/gov/types/params.go @@ -5,7 +5,7 @@ import ( "time" sdk "github.com/cosmos/cosmos-sdk/types" - params "github.com/cosmos/cosmos-sdk/x/params/subspace" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" ) // Default period for deposits & voting @@ -29,11 +29,11 @@ var ( ) // ParamKeyTable - Key declaration for parameters -func ParamKeyTable() params.KeyTable { - return params.NewKeyTable( - params.NewParamSetPair(ParamStoreKeyDepositParams, DepositParams{}, validateDepositParams), - params.NewParamSetPair(ParamStoreKeyVotingParams, VotingParams{}, validateVotingParams), - params.NewParamSetPair(ParamStoreKeyTallyParams, TallyParams{}, validateTallyParams), +func ParamKeyTable() paramtypes.KeyTable { + return paramtypes.NewKeyTable( + paramtypes.NewParamSetPair(ParamStoreKeyDepositParams, DepositParams{}, validateDepositParams), + paramtypes.NewParamSetPair(ParamStoreKeyVotingParams, VotingParams{}, validateVotingParams), + paramtypes.NewParamSetPair(ParamStoreKeyTallyParams, TallyParams{}, validateTallyParams), ) } diff --git a/x/mint/internal/keeper/keeper.go b/x/mint/internal/keeper/keeper.go index 3be3146fdf68..86721d7bbcc0 100644 --- a/x/mint/internal/keeper/keeper.go +++ b/x/mint/internal/keeper/keeper.go @@ -8,14 +8,14 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/mint/internal/types" - "github.com/cosmos/cosmos-sdk/x/params" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" ) // Keeper of the mint store type Keeper struct { cdc *codec.Codec storeKey sdk.StoreKey - paramSpace params.Subspace + paramSpace paramtypes.Subspace sk types.StakingKeeper supplyKeeper types.SupplyKeeper feeCollectorName string @@ -23,7 +23,7 @@ type Keeper struct { // NewKeeper creates a new mint Keeper instance func NewKeeper( - cdc *codec.Codec, key sdk.StoreKey, paramSpace params.Subspace, + cdc *codec.Codec, key sdk.StoreKey, paramSpace paramtypes.Subspace, sk types.StakingKeeper, supplyKeeper types.SupplyKeeper, feeCollectorName string, ) Keeper { diff --git a/x/mint/internal/types/params.go b/x/mint/internal/types/params.go index 082c9ff22599..56604621f583 100644 --- a/x/mint/internal/types/params.go +++ b/x/mint/internal/types/params.go @@ -6,7 +6,7 @@ import ( "strings" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/params" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" ) // Parameter store keys @@ -30,8 +30,8 @@ type Params struct { } // ParamTable for minting module. -func ParamKeyTable() params.KeyTable { - return params.NewKeyTable().RegisterParamSet(&Params{}) +func ParamKeyTable() paramtypes.KeyTable { + return paramtypes.NewKeyTable().RegisterParamSet(&Params{}) } func NewParams( @@ -106,14 +106,14 @@ func (p Params) String() string { } // Implements params.ParamSet -func (p *Params) ParamSetPairs() params.ParamSetPairs { - return params.ParamSetPairs{ - params.NewParamSetPair(KeyMintDenom, &p.MintDenom, validateMintDenom), - params.NewParamSetPair(KeyInflationRateChange, &p.InflationRateChange, validateInflationRateChange), - params.NewParamSetPair(KeyInflationMax, &p.InflationMax, validateInflationMax), - params.NewParamSetPair(KeyInflationMin, &p.InflationMin, validateInflationMin), - params.NewParamSetPair(KeyGoalBonded, &p.GoalBonded, validateGoalBonded), - params.NewParamSetPair(KeyBlocksPerYear, &p.BlocksPerYear, validateBlocksPerYear), +func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { + return paramtypes.ParamSetPairs{ + paramtypes.NewParamSetPair(KeyMintDenom, &p.MintDenom, validateMintDenom), + paramtypes.NewParamSetPair(KeyInflationRateChange, &p.InflationRateChange, validateInflationRateChange), + paramtypes.NewParamSetPair(KeyInflationMax, &p.InflationMax, validateInflationMax), + paramtypes.NewParamSetPair(KeyInflationMin, &p.InflationMin, validateInflationMin), + paramtypes.NewParamSetPair(KeyGoalBonded, &p.GoalBonded, validateGoalBonded), + paramtypes.NewParamSetPair(KeyBlocksPerYear, &p.BlocksPerYear, validateBlocksPerYear), } } diff --git a/x/params/alias.go b/x/params/alias.go index 668056267e62..3824236d23db 100644 --- a/x/params/alias.go +++ b/x/params/alias.go @@ -3,47 +3,26 @@ package params // nolint import ( - "github.com/cosmos/cosmos-sdk/x/params/subspace" + "github.com/cosmos/cosmos-sdk/x/params/keeper" "github.com/cosmos/cosmos-sdk/x/params/types" ) const ( - StoreKey = subspace.StoreKey - TStoreKey = subspace.TStoreKey - ModuleName = types.ModuleName - RouterKey = types.RouterKey - ProposalTypeChange = types.ProposalTypeChange + StoreKey = types.StoreKey + TStoreKey = types.TStoreKey ) var ( // functions aliases - NewParamSetPair = subspace.NewParamSetPair - NewSubspace = subspace.NewSubspace - NewKeyTable = subspace.NewKeyTable - RegisterCodec = types.RegisterCodec - ErrUnknownSubspace = types.ErrUnknownSubspace - ErrSettingParameter = types.ErrSettingParameter - ErrEmptyChanges = types.ErrEmptyChanges - ErrEmptySubspace = types.ErrEmptySubspace - ErrEmptyKey = types.ErrEmptyKey - ErrEmptyValue = types.ErrEmptyValue - NewParameterChangeProposal = types.NewParameterChangeProposal - NewParamChange = types.NewParamChange - ValidateChanges = types.ValidateChanges - NewCodec = types.NewCodec - - // variable aliases - ModuleCdc = types.ModuleCdc + NewKeeper = keeper.NewKeeper ) type ( - Codec = types.Codec - ParamSetPair = subspace.ParamSetPair - ParamSetPairs = subspace.ParamSetPairs - ParamSet = subspace.ParamSet - Subspace = subspace.Subspace - ReadOnlySubspace = subspace.ReadOnlySubspace - KeyTable = subspace.KeyTable - ParameterChangeProposal = types.ParameterChangeProposal - ParamChange = types.ParamChange + Keeper = keeper.Keeper + ParamSetPair = types.ParamSetPair + ParamSetPairs = types.ParamSetPairs + ParamSet = types.ParamSet + Subspace = types.Subspace + ReadOnlySubspace = types.ReadOnlySubspace + KeyTable = types.KeyTable ) diff --git a/x/params/client/cli/tx.go b/x/params/client/cli/tx.go index 5b4fe2a9fa9c..67a890a51e96 100644 --- a/x/params/client/cli/tx.go +++ b/x/params/client/cli/tx.go @@ -15,7 +15,7 @@ import ( authclient "github.com/cosmos/cosmos-sdk/x/auth/client" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" paramscutils "github.com/cosmos/cosmos-sdk/x/params/client/utils" - "github.com/cosmos/cosmos-sdk/x/params/types" + paramproposal "github.com/cosmos/cosmos-sdk/x/params/types/proposal" ) // GetCmdSubmitProposal implements a command handler for submitting a parameter @@ -75,7 +75,7 @@ Where proposal.json contains: } from := cliCtx.GetFromAddress() - content := types.NewParameterChangeProposal(proposal.Title, proposal.Description, proposal.Changes.ToParamChanges()) + content := paramproposal.NewParameterChangeProposal(proposal.Title, proposal.Description, proposal.Changes.ToParamChanges()) msg := govtypes.NewMsgSubmitProposal(content, proposal.Deposit, from) if err := msg.ValidateBasic(); err != nil { diff --git a/x/params/client/rest/rest.go b/x/params/client/rest/rest.go index e7461d391423..665dea834f05 100644 --- a/x/params/client/rest/rest.go +++ b/x/params/client/rest/rest.go @@ -9,8 +9,8 @@ import ( authclient "github.com/cosmos/cosmos-sdk/x/auth/client" govrest "github.com/cosmos/cosmos-sdk/x/gov/client/rest" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" - "github.com/cosmos/cosmos-sdk/x/params" paramscutils "github.com/cosmos/cosmos-sdk/x/params/client/utils" + "github.com/cosmos/cosmos-sdk/x/params/types/proposal" ) // ProposalRESTHandler returns a ProposalRESTHandler that exposes the param @@ -34,7 +34,7 @@ func postProposalHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return } - content := params.NewParameterChangeProposal(req.Title, req.Description, req.Changes.ToParamChanges()) + content := proposal.NewParameterChangeProposal(req.Title, req.Description, req.Changes.ToParamChanges()) msg := govtypes.NewMsgSubmitProposal(content, req.Deposit, req.Proposer) if err := msg.ValidateBasic(); err != nil { diff --git a/x/params/client/utils/utils.go b/x/params/client/utils/utils.go index 748d98502dc3..231c5e2b0605 100644 --- a/x/params/client/utils/utils.go +++ b/x/params/client/utils/utils.go @@ -7,7 +7,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/rest" - "github.com/cosmos/cosmos-sdk/x/params" + "github.com/cosmos/cosmos-sdk/x/params/types/proposal" ) type ( @@ -49,14 +49,14 @@ func NewParamChangeJSON(subspace, key string, value json.RawMessage) ParamChange } // ToParamChange converts a ParamChangeJSON object to ParamChange. -func (pcj ParamChangeJSON) ToParamChange() params.ParamChange { - return params.NewParamChange(pcj.Subspace, pcj.Key, string(pcj.Value)) +func (pcj ParamChangeJSON) ToParamChange() proposal.ParamChange { + return proposal.NewParamChange(pcj.Subspace, pcj.Key, string(pcj.Value)) } // ToParamChanges converts a slice of ParamChangeJSON objects to a slice of // ParamChange. -func (pcj ParamChangesJSON) ToParamChanges() []params.ParamChange { - res := make([]params.ParamChange, len(pcj)) +func (pcj ParamChangesJSON) ToParamChanges() []proposal.ParamChange { + res := make([]proposal.ParamChange, len(pcj)) for i, pc := range pcj { res[i] = pc.ToParamChange() } diff --git a/x/params/commmon_test.go b/x/params/keeper/common_test.go similarity index 81% rename from x/params/commmon_test.go rename to x/params/keeper/common_test.go index c1d4bd0242ae..92d9f1ee5660 100644 --- a/x/params/commmon_test.go +++ b/x/params/keeper/common_test.go @@ -1,16 +1,26 @@ -// nolint:deadcode,unused -package params +package keeper_test import ( - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/libs/log" - dbm "github.com/tendermint/tm-db" - "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" + paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper" + "github.com/cosmos/cosmos-sdk/x/params/types/proposal" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/libs/log" + dbm "github.com/tendermint/tm-db" ) +func testComponents() (codec.Marshaler, sdk.Context, sdk.StoreKey, sdk.StoreKey, paramskeeper.Keeper) { + cdc := createTestCodec() + mkey := sdk.NewKVStoreKey("test") + tkey := sdk.NewTransientStoreKey("transient_test") + ctx := defaultContext(mkey, tkey) + keeper := paramskeeper.NewKeeper(cdc, mkey, tkey) + + return cdc, ctx, mkey, tkey, keeper +} + type invalid struct{} type s struct { @@ -22,7 +32,7 @@ func createTestCodec() codec.Marshaler { sdk.RegisterCodec(cdc) cdc.RegisterConcrete(s{}, "test/s", nil) cdc.RegisterConcrete(invalid{}, "test/invalid", nil) - return NewCodec(cdc) + return proposal.NewCodec(cdc) } func defaultContext(key sdk.StoreKey, tkey sdk.StoreKey) sdk.Context { @@ -37,13 +47,3 @@ func defaultContext(key sdk.StoreKey, tkey sdk.StoreKey) sdk.Context { ctx := sdk.NewContext(cms, abci.Header{}, false, log.NewNopLogger()) return ctx } - -func testComponents() (codec.Marshaler, sdk.Context, sdk.StoreKey, sdk.StoreKey, Keeper) { - cdc := createTestCodec() - mkey := sdk.NewKVStoreKey("test") - tkey := sdk.NewTransientStoreKey("transient_test") - ctx := defaultContext(mkey, tkey) - keeper := NewKeeper(cdc, mkey, tkey) - - return cdc, ctx, mkey, tkey, keeper -} diff --git a/x/params/keeper.go b/x/params/keeper/keeper.go similarity index 67% rename from x/params/keeper.go rename to x/params/keeper/keeper.go index a290e6561270..628548acb109 100644 --- a/x/params/keeper.go +++ b/x/params/keeper/keeper.go @@ -1,14 +1,14 @@ -package params +package keeper import ( "fmt" + "github.com/tendermint/tendermint/libs/log" + "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/params/subspace" "github.com/cosmos/cosmos-sdk/x/params/types" - - "github.com/tendermint/tendermint/libs/log" + "github.com/cosmos/cosmos-sdk/x/params/types/proposal" ) // Keeper of the global paramstore @@ -16,7 +16,7 @@ type Keeper struct { cdc codec.Marshaler key sdk.StoreKey tkey sdk.StoreKey - spaces map[string]*Subspace + spaces map[string]*types.Subspace } // NewKeeper constructs a params keeper @@ -25,17 +25,17 @@ func NewKeeper(cdc codec.Marshaler, key, tkey sdk.StoreKey) Keeper { cdc: cdc, key: key, tkey: tkey, - spaces: make(map[string]*Subspace), + spaces: make(map[string]*types.Subspace), } } // Logger returns a module-specific logger. func (k Keeper) Logger(ctx sdk.Context) log.Logger { - return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) + return ctx.Logger().With("module", fmt.Sprintf("x/%s", proposal.ModuleName)) } // Allocate subspace used for keepers -func (k Keeper) Subspace(s string) Subspace { +func (k Keeper) Subspace(s string) types.Subspace { _, ok := k.spaces[s] if ok { panic("subspace already occupied") @@ -45,17 +45,17 @@ func (k Keeper) Subspace(s string) Subspace { panic("cannot use empty string for subspace") } - space := subspace.NewSubspace(k.cdc, k.key, k.tkey, s) + space := types.NewSubspace(k.cdc, k.key, k.tkey, s) k.spaces[s] = &space return space } // Get existing substore from keeper -func (k Keeper) GetSubspace(s string) (Subspace, bool) { +func (k Keeper) GetSubspace(s string) (types.Subspace, bool) { space, ok := k.spaces[s] if !ok { - return Subspace{}, false + return types.Subspace{}, false } return *space, ok } diff --git a/x/params/keeper_test.go b/x/params/keeper/keeper_test.go similarity index 81% rename from x/params/keeper_test.go rename to x/params/keeper/keeper_test.go index 3f2f1a4b2bf4..0c34558e9ff8 100644 --- a/x/params/keeper_test.go +++ b/x/params/keeper/keeper_test.go @@ -1,13 +1,13 @@ -package params +package keeper_test import ( "reflect" "testing" - "github.com/stretchr/testify/require" - "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/params/types" + "github.com/stretchr/testify/require" ) func validateNoOp(_ interface{}) error { return nil } @@ -26,16 +26,16 @@ func TestKeeper(t *testing.T) { {"key7", 9058701}, } - table := NewKeyTable( - NewParamSetPair([]byte("key1"), int64(0), validateNoOp), - NewParamSetPair([]byte("key2"), int64(0), validateNoOp), - NewParamSetPair([]byte("key3"), int64(0), validateNoOp), - NewParamSetPair([]byte("key4"), int64(0), validateNoOp), - NewParamSetPair([]byte("key5"), int64(0), validateNoOp), - NewParamSetPair([]byte("key6"), int64(0), validateNoOp), - NewParamSetPair([]byte("key7"), int64(0), validateNoOp), - NewParamSetPair([]byte("extra1"), bool(false), validateNoOp), - NewParamSetPair([]byte("extra2"), string(""), validateNoOp), + table := types.NewKeyTable( + types.NewParamSetPair([]byte("key1"), int64(0), validateNoOp), + types.NewParamSetPair([]byte("key2"), int64(0), validateNoOp), + types.NewParamSetPair([]byte("key3"), int64(0), validateNoOp), + types.NewParamSetPair([]byte("key4"), int64(0), validateNoOp), + types.NewParamSetPair([]byte("key5"), int64(0), validateNoOp), + types.NewParamSetPair([]byte("key6"), int64(0), validateNoOp), + types.NewParamSetPair([]byte("key7"), int64(0), validateNoOp), + types.NewParamSetPair([]byte("extra1"), bool(false), validateNoOp), + types.NewParamSetPair([]byte("extra2"), string(""), validateNoOp), ) cdc, ctx, skey, _, keeper := testComponents() @@ -136,19 +136,19 @@ func TestSubspace(t *testing.T) { {"struct", s{1}, s{0}, new(s)}, } - table := NewKeyTable( - NewParamSetPair([]byte("string"), string(""), validateNoOp), - NewParamSetPair([]byte("bool"), bool(false), validateNoOp), - NewParamSetPair([]byte("int16"), int16(0), validateNoOp), - NewParamSetPair([]byte("int32"), int32(0), validateNoOp), - NewParamSetPair([]byte("int64"), int64(0), validateNoOp), - NewParamSetPair([]byte("uint16"), uint16(0), validateNoOp), - NewParamSetPair([]byte("uint32"), uint32(0), validateNoOp), - NewParamSetPair([]byte("uint64"), uint64(0), validateNoOp), - NewParamSetPair([]byte("int"), sdk.Int{}, validateNoOp), - NewParamSetPair([]byte("uint"), sdk.Uint{}, validateNoOp), - NewParamSetPair([]byte("dec"), sdk.Dec{}, validateNoOp), - NewParamSetPair([]byte("struct"), s{}, validateNoOp), + table := types.NewKeyTable( + types.NewParamSetPair([]byte("string"), "", validateNoOp), + types.NewParamSetPair([]byte("bool"), false, validateNoOp), + types.NewParamSetPair([]byte("int16"), int16(0), validateNoOp), + types.NewParamSetPair([]byte("int32"), int32(0), validateNoOp), + types.NewParamSetPair([]byte("int64"), int64(0), validateNoOp), + types.NewParamSetPair([]byte("uint16"), uint16(0), validateNoOp), + types.NewParamSetPair([]byte("uint32"), uint32(0), validateNoOp), + types.NewParamSetPair([]byte("uint64"), uint64(0), validateNoOp), + types.NewParamSetPair([]byte("int"), sdk.Int{}, validateNoOp), + types.NewParamSetPair([]byte("uint"), sdk.Uint{}, validateNoOp), + types.NewParamSetPair([]byte("dec"), sdk.Dec{}, validateNoOp), + types.NewParamSetPair([]byte("struct"), s{}, validateNoOp), ) store := prefix.NewStore(ctx.KVStore(key), []byte("test/")) @@ -202,7 +202,7 @@ func TestJSONUpdate(t *testing.T) { key := []byte("key") - space := keeper.Subspace("test").WithKeyTable(NewKeyTable(NewParamSetPair(key, paramJSON{}, validateNoOp))) + space := keeper.Subspace("test").WithKeyTable(types.NewKeyTable(types.NewParamSetPair(key, paramJSON{}, validateNoOp))) var param paramJSON diff --git a/x/params/module.go b/x/params/module.go index 12005b8bc407..0510ed5f92c9 100644 --- a/x/params/module.go +++ b/x/params/module.go @@ -12,7 +12,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/x/params/simulation" - "github.com/cosmos/cosmos-sdk/x/params/types" + "github.com/cosmos/cosmos-sdk/x/params/types/proposal" sim "github.com/cosmos/cosmos-sdk/x/simulation" ) @@ -26,12 +26,12 @@ type AppModuleBasic struct{} // Name returns the params module's name. func (AppModuleBasic) Name() string { - return ModuleName + return proposal.ModuleName } // RegisterCodec registers the params module's types for the given codec. func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) { - types.RegisterCodec(cdc) + proposal.RegisterCodec(cdc) } // DefaultGenesis returns default genesis state as raw bytes for the params diff --git a/x/params/proposal_handler.go b/x/params/proposal_handler.go index 339cfd7410ce..6af7668aa3e0 100644 --- a/x/params/proposal_handler.go +++ b/x/params/proposal_handler.go @@ -6,13 +6,15 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/cosmos/cosmos-sdk/x/params/keeper" + "github.com/cosmos/cosmos-sdk/x/params/types/proposal" ) // NewParamChangeProposalHandler creates a new governance Handler for a ParamChangeProposal -func NewParamChangeProposalHandler(k Keeper) govtypes.Handler { +func NewParamChangeProposalHandler(k keeper.Keeper) govtypes.Handler { return func(ctx sdk.Context, content govtypes.Content) error { switch c := content.(type) { - case ParameterChangeProposal: + case proposal.ParameterChangeProposal: return handleParameterChangeProposal(ctx, k, c) default: @@ -21,11 +23,11 @@ func NewParamChangeProposalHandler(k Keeper) govtypes.Handler { } } -func handleParameterChangeProposal(ctx sdk.Context, k Keeper, p ParameterChangeProposal) error { +func handleParameterChangeProposal(ctx sdk.Context, k keeper.Keeper, p proposal.ParameterChangeProposal) error { for _, c := range p.Changes { ss, ok := k.GetSubspace(c.Subspace) if !ok { - return sdkerrors.Wrap(ErrUnknownSubspace, c.Subspace) + return sdkerrors.Wrap(proposal.ErrUnknownSubspace, c.Subspace) } k.Logger(ctx).Info( @@ -33,7 +35,7 @@ func handleParameterChangeProposal(ctx sdk.Context, k Keeper, p ParameterChangeP ) if err := ss.Update(ctx, []byte(c.Key), []byte(c.Value)); err != nil { - return sdkerrors.Wrapf(ErrSettingParameter, "key: %s, value: %s, err: %s", c.Key, c.Value, err.Error()) + return sdkerrors.Wrapf(proposal.ErrSettingParameter, "key: %s, value: %s, err: %s", c.Key, c.Value, err.Error()) } } diff --git a/x/params/proposal_handler_test.go b/x/params/proposal_handler_test.go index b0444f32abc6..e15fea359648 100644 --- a/x/params/proposal_handler_test.go +++ b/x/params/proposal_handler_test.go @@ -4,17 +4,18 @@ import ( "testing" "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" - dbm "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/params" - "github.com/cosmos/cosmos-sdk/x/params/subspace" + "github.com/cosmos/cosmos-sdk/x/params/keeper" "github.com/cosmos/cosmos-sdk/x/params/types" + "github.com/cosmos/cosmos-sdk/x/params/types/proposal" ) func validateNoOp(_ interface{}) error { return nil } @@ -22,11 +23,11 @@ func validateNoOp(_ interface{}) error { return nil } type testInput struct { ctx sdk.Context cdc *codec.Codec - keeper params.Keeper + keeper keeper.Keeper } var ( - _ subspace.ParamSet = (*testParams)(nil) + _ types.ParamSet = (*testParams)(nil) keyMaxValidators = "MaxValidators" keySlashingRate = "SlashingRate" @@ -43,15 +44,15 @@ type testParams struct { SlashingRate testParamsSlashingRate `json:"slashing_rate" yaml:"slashing_rate"` } -func (tp *testParams) ParamSetPairs() subspace.ParamSetPairs { - return subspace.ParamSetPairs{ - params.NewParamSetPair([]byte(keyMaxValidators), &tp.MaxValidators, validateNoOp), - params.NewParamSetPair([]byte(keySlashingRate), &tp.SlashingRate, validateNoOp), +func (tp *testParams) ParamSetPairs() types.ParamSetPairs { + return types.ParamSetPairs{ + types.NewParamSetPair([]byte(keyMaxValidators), &tp.MaxValidators, validateNoOp), + types.NewParamSetPair([]byte(keySlashingRate), &tp.SlashingRate, validateNoOp), } } -func testProposal(changes ...params.ParamChange) params.ParameterChangeProposal { - return params.NewParameterChangeProposal( +func testProposal(changes ...proposal.ParamChange) proposal.ParameterChangeProposal { + return proposal.NewParameterChangeProposal( "Test", "description", changes, @@ -60,7 +61,7 @@ func testProposal(changes ...params.ParamChange) params.ParameterChangeProposal func newTestInput(t *testing.T) testInput { cdc := codec.New() - types.RegisterCodec(cdc) + proposal.RegisterCodec(cdc) db := dbm.NewMemDB() cms := store.NewCommitMultiStore(db) @@ -74,7 +75,7 @@ func newTestInput(t *testing.T) testInput { err := cms.LoadLatestVersion() require.Nil(t, err) - keeper := params.NewKeeper(types.ModuleCdc, keyParams, tKeyParams) + keeper := keeper.NewKeeper(proposal.ModuleCdc, keyParams, tKeyParams) ctx := sdk.NewContext(cms, abci.Header{}, false, log.NewNopLogger()) return testInput{ctx, cdc, keeper} @@ -83,10 +84,10 @@ func newTestInput(t *testing.T) testInput { func TestProposalHandlerPassed(t *testing.T) { input := newTestInput(t) ss := input.keeper.Subspace(testSubspace).WithKeyTable( - params.NewKeyTable().RegisterParamSet(&testParams{}), + types.NewKeyTable().RegisterParamSet(&testParams{}), ) - tp := testProposal(params.NewParamChange(testSubspace, keyMaxValidators, "1")) + tp := testProposal(proposal.NewParamChange(testSubspace, keyMaxValidators, "1")) hdlr := params.NewParamChangeProposalHandler(input.keeper) require.NoError(t, hdlr(input.ctx, tp)) @@ -98,10 +99,10 @@ func TestProposalHandlerPassed(t *testing.T) { func TestProposalHandlerFailed(t *testing.T) { input := newTestInput(t) ss := input.keeper.Subspace(testSubspace).WithKeyTable( - params.NewKeyTable().RegisterParamSet(&testParams{}), + types.NewKeyTable().RegisterParamSet(&testParams{}), ) - tp := testProposal(params.NewParamChange(testSubspace, keyMaxValidators, "invalidType")) + tp := testProposal(proposal.NewParamChange(testSubspace, keyMaxValidators, "invalidType")) hdlr := params.NewParamChangeProposalHandler(input.keeper) require.Error(t, hdlr(input.ctx, tp)) @@ -111,19 +112,19 @@ func TestProposalHandlerFailed(t *testing.T) { func TestProposalHandlerUpdateOmitempty(t *testing.T) { input := newTestInput(t) ss := input.keeper.Subspace(testSubspace).WithKeyTable( - params.NewKeyTable().RegisterParamSet(&testParams{}), + types.NewKeyTable().RegisterParamSet(&testParams{}), ) hdlr := params.NewParamChangeProposalHandler(input.keeper) var param testParamsSlashingRate - tp := testProposal(params.NewParamChange(testSubspace, keySlashingRate, `{"downtime": 7}`)) + tp := testProposal(proposal.NewParamChange(testSubspace, keySlashingRate, `{"downtime": 7}`)) require.NoError(t, hdlr(input.ctx, tp)) ss.Get(input.ctx, []byte(keySlashingRate), ¶m) require.Equal(t, testParamsSlashingRate{0, 7}, param) - tp = testProposal(params.NewParamChange(testSubspace, keySlashingRate, `{"double_sign": 10}`)) + tp = testProposal(proposal.NewParamChange(testSubspace, keySlashingRate, `{"double_sign": 10}`)) require.NoError(t, hdlr(input.ctx, tp)) ss.Get(input.ctx, []byte(keySlashingRate), ¶m) diff --git a/x/params/simulation/operations.go b/x/params/simulation/operations.go index c9415a68e1df..82018b158b83 100644 --- a/x/params/simulation/operations.go +++ b/x/params/simulation/operations.go @@ -5,7 +5,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" - "github.com/cosmos/cosmos-sdk/x/params/types" + "github.com/cosmos/cosmos-sdk/x/params/types/proposal" "github.com/cosmos/cosmos-sdk/x/simulation" ) @@ -21,7 +21,7 @@ func SimulateParamChangeProposalContent(paramChangePool []simulation.ParamChange } numChanges := simulation.RandIntBetween(r, 1, lenParamChange) - paramChanges := make([]types.ParamChange, numChanges) + paramChanges := make([]proposal.ParamChange, numChanges) // map from key to empty struct; used only for look-up of the keys of the // parameters that are already in the random set of changes. @@ -40,10 +40,10 @@ func SimulateParamChangeProposalContent(paramChangePool []simulation.ParamChange // add a new distinct parameter to the set of changes and register the key // to avoid further duplicates paramChangesKeys[spc.ComposedKey()] = struct{}{} - paramChanges[i] = types.NewParamChange(spc.Subspace, spc.Key, spc.SimValue(r)) + paramChanges[i] = proposal.NewParamChange(spc.Subspace, spc.Key, spc.SimValue(r)) } - return types.NewParameterChangeProposal( + return proposal.NewParameterChangeProposal( simulation.RandStringOfLength(r, 140), // title simulation.RandStringOfLength(r, 5000), // description paramChanges, // set of changes diff --git a/x/params/subspace/table_test.go b/x/params/subspace/table_test.go deleted file mode 100644 index 6bc1a8af2a81..000000000000 --- a/x/params/subspace/table_test.go +++ /dev/null @@ -1,46 +0,0 @@ -package subspace_test - -import ( - "testing" - "time" - - "github.com/stretchr/testify/require" - - "github.com/cosmos/cosmos-sdk/x/params/subspace" -) - -func TestKeyTable(t *testing.T) { - table := subspace.NewKeyTable() - - require.Panics(t, func() { table.RegisterType(subspace.ParamSetPair{[]byte(""), nil, nil}) }) - require.Panics(t, func() { table.RegisterType(subspace.ParamSetPair{[]byte("!@#$%"), nil, nil}) }) - require.Panics(t, func() { table.RegisterType(subspace.ParamSetPair{[]byte("hello,"), nil, nil}) }) - require.Panics(t, func() { table.RegisterType(subspace.ParamSetPair{[]byte("hello"), nil, nil}) }) - - require.NotPanics(t, func() { - table.RegisterType(subspace.ParamSetPair{keyBondDenom, string("stake"), validateBondDenom}) - }) - require.NotPanics(t, func() { - table.RegisterType(subspace.ParamSetPair{keyMaxValidators, uint16(100), validateMaxValidators}) - }) - require.Panics(t, func() { - table.RegisterType(subspace.ParamSetPair{keyUnbondingTime, time.Duration(1), nil}) - }) - require.NotPanics(t, func() { - table.RegisterType(subspace.ParamSetPair{keyUnbondingTime, time.Duration(1), validateMaxValidators}) - }) - require.NotPanics(t, func() { - newTable := subspace.NewKeyTable() - newTable.RegisterParamSet(¶ms{}) - }) - - require.Panics(t, func() { table.RegisterParamSet(¶ms{}) }) - require.Panics(t, func() { subspace.NewKeyTable(subspace.ParamSetPair{[]byte(""), nil, nil}) }) - - require.NotPanics(t, func() { - subspace.NewKeyTable( - subspace.ParamSetPair{[]byte("test"), string("stake"), validateBondDenom}, - subspace.ParamSetPair{[]byte("test2"), uint16(100), validateMaxValidators}, - ) - }) -} diff --git a/x/params/subspace/common_test.go b/x/params/types/common_test.go similarity index 83% rename from x/params/subspace/common_test.go rename to x/params/types/common_test.go index 69c41478dbcc..c7cb067c62c4 100644 --- a/x/params/subspace/common_test.go +++ b/x/params/types/common_test.go @@ -1,4 +1,4 @@ -package subspace_test +package types_test import ( "errors" @@ -6,7 +6,7 @@ import ( "time" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/params/subspace" + "github.com/cosmos/cosmos-sdk/x/params/types" ) var ( @@ -59,14 +59,14 @@ func validateBondDenom(i interface{}) error { return nil } -func (p *params) ParamSetPairs() subspace.ParamSetPairs { - return subspace.ParamSetPairs{ +func (p *params) ParamSetPairs() types.ParamSetPairs { + return types.ParamSetPairs{ {keyUnbondingTime, &p.UnbondingTime, validateUnbondingTime}, {keyMaxValidators, &p.MaxValidators, validateMaxValidators}, {keyBondDenom, &p.BondDenom, validateBondDenom}, } } -func paramKeyTable() subspace.KeyTable { - return subspace.NewKeyTable().RegisterParamSet(¶ms{}) +func paramKeyTable() types.KeyTable { + return types.NewKeyTable().RegisterParamSet(¶ms{}) } diff --git a/x/params/subspace/doc.go b/x/params/types/doc.go similarity index 97% rename from x/params/subspace/doc.go rename to x/params/types/doc.go index 0bde2ebe62d4..861a4a2f5842 100644 --- a/x/params/subspace/doc.go +++ b/x/params/types/doc.go @@ -10,4 +10,4 @@ respective parameters safely. Keeper can be treated as master permission for all Subspaces (via Keeper.GetSubspace), so should be passed to proper modules (ex. x/governance). */ -package subspace +package types diff --git a/x/params/subspace/paramset.go b/x/params/types/paramset.go similarity index 97% rename from x/params/subspace/paramset.go rename to x/params/types/paramset.go index 195944d8c9c4..80d0852be4f0 100644 --- a/x/params/subspace/paramset.go +++ b/x/params/types/paramset.go @@ -1,4 +1,4 @@ -package subspace +package types type ( ValueValidatorFn func(value interface{}) error diff --git a/x/params/types/codec.go b/x/params/types/proposal/codec.go similarity index 97% rename from x/params/types/codec.go rename to x/params/types/proposal/codec.go index a9436062cb10..8160d51c1a54 100644 --- a/x/params/types/codec.go +++ b/x/params/types/proposal/codec.go @@ -1,4 +1,4 @@ -package types +package proposal import ( "github.com/cosmos/cosmos-sdk/codec" diff --git a/x/params/types/errors.go b/x/params/types/proposal/errors.go similarity index 97% rename from x/params/types/errors.go rename to x/params/types/proposal/errors.go index 0611a3de214b..a8c891af2ce3 100644 --- a/x/params/types/errors.go +++ b/x/params/types/proposal/errors.go @@ -1,4 +1,4 @@ -package types +package proposal import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" diff --git a/x/params/types/keys.go b/x/params/types/proposal/keys.go similarity index 90% rename from x/params/types/keys.go rename to x/params/types/proposal/keys.go index 1355a7427b95..0649f417433c 100644 --- a/x/params/types/keys.go +++ b/x/params/types/proposal/keys.go @@ -1,4 +1,4 @@ -package types +package proposal const ( // ModuleName defines the name of the module diff --git a/x/params/types/proposal.go b/x/params/types/proposal/proposal.go similarity index 99% rename from x/params/types/proposal.go rename to x/params/types/proposal/proposal.go index b61b59d25cf3..60fd6ce8001b 100644 --- a/x/params/types/proposal.go +++ b/x/params/types/proposal/proposal.go @@ -1,4 +1,4 @@ -package types +package proposal import ( "fmt" diff --git a/x/params/types/proposal_test.go b/x/params/types/proposal/proposal_test.go similarity index 98% rename from x/params/types/proposal_test.go rename to x/params/types/proposal/proposal_test.go index aa891c82031d..a18f9c407609 100644 --- a/x/params/types/proposal_test.go +++ b/x/params/types/proposal/proposal_test.go @@ -1,4 +1,4 @@ -package types +package proposal import ( "testing" diff --git a/x/params/types/types.pb.go b/x/params/types/proposal/types.pb.go similarity index 87% rename from x/params/types/types.pb.go rename to x/params/types/proposal/types.pb.go index 5f27a306bde2..fdc33948cf25 100644 --- a/x/params/types/types.pb.go +++ b/x/params/types/proposal/types.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: x/params/types/types.proto +// source: x/params/types/proposal/types.proto -package types +package proposal import ( fmt "fmt" @@ -34,7 +34,7 @@ type ParameterChangeProposal struct { func (m *ParameterChangeProposal) Reset() { *m = ParameterChangeProposal{} } func (*ParameterChangeProposal) ProtoMessage() {} func (*ParameterChangeProposal) Descriptor() ([]byte, []int) { - return fileDescriptor_ed04c33aa1766c78, []int{0} + return fileDescriptor_0ab50f1d22a2cb61, []int{0} } func (m *ParameterChangeProposal) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -73,7 +73,7 @@ type ParamChange struct { func (m *ParamChange) Reset() { *m = ParamChange{} } func (*ParamChange) ProtoMessage() {} func (*ParamChange) Descriptor() ([]byte, []int) { - return fileDescriptor_ed04c33aa1766c78, []int{1} + return fileDescriptor_0ab50f1d22a2cb61, []int{1} } func (m *ParamChange) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -128,28 +128,32 @@ func init() { proto.RegisterType((*ParamChange)(nil), "cosmos_sdk.x.params.v1.ParamChange") } -func init() { proto.RegisterFile("x/params/types/types.proto", fileDescriptor_ed04c33aa1766c78) } +func init() { + proto.RegisterFile("x/params/types/proposal/types.proto", fileDescriptor_0ab50f1d22a2cb61) +} -var fileDescriptor_ed04c33aa1766c78 = []byte{ - // 287 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xaa, 0xd0, 0x2f, 0x48, - 0x2c, 0x4a, 0xcc, 0x2d, 0xd6, 0x2f, 0xa9, 0x2c, 0x48, 0x85, 0x92, 0x7a, 0x05, 0x45, 0xf9, 0x25, - 0xf9, 0x42, 0x62, 0xc9, 0xf9, 0xc5, 0xb9, 0xf9, 0xc5, 0xf1, 0xc5, 0x29, 0xd9, 0x7a, 0x15, 0x7a, - 0x10, 0x65, 0x7a, 0x65, 0x86, 0x52, 0x6a, 0x25, 0x19, 0x99, 0x45, 0x29, 0xf1, 0x05, 0x89, 0x45, - 0x25, 0x95, 0xfa, 0x60, 0xa5, 0xfa, 0xe9, 0xf9, 0xe9, 0xf9, 0x08, 0x16, 0x44, 0xbf, 0xd2, 0x02, - 0x46, 0x2e, 0xf1, 0x00, 0x90, 0xae, 0xd4, 0x92, 0xd4, 0x22, 0xe7, 0x8c, 0xc4, 0xbc, 0xf4, 0xd4, - 0x80, 0xa2, 0xfc, 0x82, 0xfc, 0xe2, 0xc4, 0x1c, 0x21, 0x11, 0x2e, 0xd6, 0x92, 0xcc, 0x92, 0x9c, - 0x54, 0x09, 0x46, 0x05, 0x46, 0x0d, 0xce, 0x20, 0x08, 0x47, 0x48, 0x81, 0x8b, 0x3b, 0x25, 0xb5, - 0x38, 0xb9, 0x28, 0xb3, 0xa0, 0x24, 0x33, 0x3f, 0x4f, 0x82, 0x09, 0x2c, 0x87, 0x2c, 0x24, 0xe4, - 0xcc, 0xc5, 0x9e, 0x0c, 0x36, 0xa9, 0x58, 0x82, 0x59, 0x81, 0x59, 0x83, 0xdb, 0x48, 0x59, 0x0f, - 0xbb, 0x2b, 0xf5, 0xc0, 0x36, 0x43, 0x6c, 0x75, 0x62, 0x39, 0x71, 0x4f, 0x9e, 0x21, 0x08, 0xa6, - 0xd3, 0x8a, 0xa3, 0x63, 0x81, 0x3c, 0xc3, 0x8c, 0x05, 0xf2, 0x0c, 0x4a, 0xe1, 0x5c, 0xdc, 0x48, - 0xea, 0x84, 0xa4, 0xb8, 0x38, 0x8a, 0x4b, 0x93, 0x8a, 0x0b, 0x12, 0x93, 0x61, 0x0e, 0x83, 0xf3, - 0x85, 0x04, 0xb8, 0x98, 0xb3, 0x53, 0x2b, 0xa1, 0x6e, 0x02, 0x31, 0x41, 0x7e, 0x28, 0x4b, 0xcc, - 0x29, 0x4d, 0x95, 0x60, 0x86, 0xf8, 0x01, 0xcc, 0xb1, 0x62, 0x01, 0x19, 0xec, 0x24, 0x7f, 0xe2, - 0x91, 0x1c, 0xe3, 0x85, 0x47, 0x72, 0x8c, 0x0f, 0x1e, 0xc9, 0x31, 0x4e, 0x78, 0x2c, 0xc7, 0x70, - 0xe1, 0xb1, 0x1c, 0xc3, 0x8d, 0xc7, 0x72, 0x0c, 0x51, 0xac, 0xe0, 0x20, 0x4e, 0x62, 0x03, 0x87, - 0x91, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0x83, 0x64, 0xb6, 0xa5, 0x81, 0x01, 0x00, 0x00, +var fileDescriptor_0ab50f1d22a2cb61 = []byte{ + // 313 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0xae, 0xd0, 0x2f, 0x48, + 0x2c, 0x4a, 0xcc, 0x2d, 0xd6, 0x2f, 0xa9, 0x2c, 0x48, 0x2d, 0xd6, 0x2f, 0x28, 0xca, 0x2f, 0xc8, + 0x2f, 0x4e, 0xcc, 0x81, 0x70, 0xf5, 0x0a, 0x8a, 0xf2, 0x4b, 0xf2, 0x85, 0xc4, 0x92, 0xf3, 0x8b, + 0x73, 0xf3, 0x8b, 0xe3, 0x8b, 0x53, 0xb2, 0xf5, 0x2a, 0xf4, 0x20, 0xea, 0xf5, 0xca, 0x0c, 0xa5, + 0xd4, 0x4a, 0x32, 0x32, 0x8b, 0x52, 0xe2, 0x0b, 0x12, 0x8b, 0x4a, 0x2a, 0xf5, 0xc1, 0x4a, 0xf5, + 0xd3, 0xf3, 0xd3, 0xf3, 0x11, 0x2c, 0x88, 0x7e, 0xa5, 0x05, 0x8c, 0x5c, 0xe2, 0x01, 0x20, 0x5d, + 0xa9, 0x25, 0xa9, 0x45, 0xce, 0x19, 0x89, 0x79, 0xe9, 0xa9, 0x01, 0x50, 0x7b, 0x84, 0x44, 0xb8, + 0x58, 0x4b, 0x32, 0x4b, 0x72, 0x52, 0x25, 0x18, 0x15, 0x18, 0x35, 0x38, 0x83, 0x20, 0x1c, 0x21, + 0x05, 0x2e, 0xee, 0x94, 0xd4, 0xe2, 0xe4, 0xa2, 0xcc, 0x82, 0x92, 0xcc, 0xfc, 0x3c, 0x09, 0x26, + 0xb0, 0x1c, 0xb2, 0x90, 0x90, 0x33, 0x17, 0x7b, 0x32, 0xd8, 0xa4, 0x62, 0x09, 0x66, 0x05, 0x66, + 0x0d, 0x6e, 0x23, 0x65, 0x3d, 0xec, 0xae, 0xd4, 0x03, 0xdb, 0x0c, 0xb1, 0xd5, 0x89, 0xe5, 0xc4, + 0x3d, 0x79, 0x86, 0x20, 0x98, 0x4e, 0x2b, 0x8e, 0x8e, 0x05, 0xf2, 0x0c, 0x33, 0x16, 0xc8, 0x33, + 0x28, 0x85, 0x73, 0x71, 0x23, 0xa9, 0x13, 0x92, 0xe2, 0xe2, 0x28, 0x2e, 0x4d, 0x2a, 0x2e, 0x48, + 0x4c, 0x86, 0x39, 0x0c, 0xce, 0x17, 0x12, 0xe0, 0x62, 0xce, 0x4e, 0xad, 0x84, 0xba, 0x09, 0xc4, + 0x04, 0xf9, 0xa1, 0x2c, 0x31, 0xa7, 0x34, 0x55, 0x82, 0x19, 0xe2, 0x07, 0x30, 0xc7, 0x8a, 0x05, + 0x64, 0xb0, 0x93, 0xdf, 0x89, 0x47, 0x72, 0x8c, 0x17, 0x1e, 0xc9, 0x31, 0x3e, 0x78, 0x24, 0xc7, + 0x38, 0xe1, 0xb1, 0x1c, 0xc3, 0x85, 0xc7, 0x72, 0x0c, 0x37, 0x1e, 0xcb, 0x31, 0x44, 0x99, 0xa4, + 0x67, 0x96, 0x64, 0x94, 0x26, 0xe9, 0x25, 0xe7, 0xe7, 0xea, 0x43, 0x9c, 0x0e, 0xa5, 0x74, 0x8b, + 0x53, 0xb2, 0xf5, 0x71, 0xc4, 0x4b, 0x12, 0x1b, 0x38, 0x48, 0x8d, 0x01, 0x01, 0x00, 0x00, 0xff, + 0xff, 0x11, 0x0a, 0x5a, 0xe0, 0xb9, 0x01, 0x00, 0x00, } func (m *ParameterChangeProposal) Marshal() (dAtA []byte, err error) { diff --git a/x/params/types/types.proto b/x/params/types/proposal/types.proto similarity index 89% rename from x/params/types/types.proto rename to x/params/types/proposal/types.proto index 74f25fe097ee..2e4e18f72f4a 100644 --- a/x/params/types/types.proto +++ b/x/params/types/proposal/types.proto @@ -1,7 +1,7 @@ syntax = "proto3"; package cosmos_sdk.x.params.v1; -option go_package = "types"; +option go_package = "github.com/cosmos/cosmos-sdk/x/params/types/proposal"; import "third_party/proto/gogoproto/gogo.proto"; diff --git a/x/params/subspace/subspace.go b/x/params/types/subspace.go similarity index 99% rename from x/params/subspace/subspace.go rename to x/params/types/subspace.go index 90dc143ebbe8..e7fd47d3c201 100644 --- a/x/params/subspace/subspace.go +++ b/x/params/types/subspace.go @@ -1,13 +1,12 @@ -package subspace +package types import ( "fmt" "reflect" "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" ) const ( diff --git a/x/params/subspace/subspace_test.go b/x/params/types/subspace_test.go similarity index 94% rename from x/params/subspace/subspace_test.go rename to x/params/types/subspace_test.go index 3a1e56ae6bc4..a4c4f74d4cc8 100644 --- a/x/params/subspace/subspace_test.go +++ b/x/params/types/subspace_test.go @@ -1,4 +1,4 @@ -package subspace_test +package types_test import ( "fmt" @@ -13,8 +13,8 @@ import ( "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/params/subspace" "github.com/cosmos/cosmos-sdk/x/params/types" + "github.com/cosmos/cosmos-sdk/x/params/types/proposal" ) type SubspaceTestSuite struct { @@ -22,11 +22,11 @@ type SubspaceTestSuite struct { cdc codec.Marshaler ctx sdk.Context - ss subspace.Subspace + ss types.Subspace } func (suite *SubspaceTestSuite) SetupTest() { - cdc := types.ModuleCdc + cdc := proposal.ModuleCdc db := dbm.NewMemDB() ms := store.NewCommitMultiStore(db) @@ -34,7 +34,7 @@ func (suite *SubspaceTestSuite) SetupTest() { ms.MountStoreWithDB(tkey, sdk.StoreTypeTransient, db) suite.NoError(ms.LoadLatestVersion()) - ss := subspace.NewSubspace(cdc, key, tkey, "testsubspace") + ss := types.NewSubspace(cdc, key, tkey, "testsubspace") suite.cdc = cdc suite.ctx = sdk.NewContext(ms, abci.Header{}, false, log.NewNopLogger()) @@ -47,7 +47,7 @@ func (suite *SubspaceTestSuite) TestKeyTable() { suite.ss.WithKeyTable(paramKeyTable()) }) suite.Require().NotPanics(func() { - ss := subspace.NewSubspace(types.ModuleCdc, key, tkey, "testsubspace2") + ss := types.NewSubspace(proposal.ModuleCdc, key, tkey, "testsubspace2") ss = ss.WithKeyTable(paramKeyTable()) }) } @@ -163,7 +163,7 @@ func (suite *SubspaceTestSuite) TestGetParamSet() { func (suite *SubspaceTestSuite) TestSetParamSet() { testCases := []struct { name string - ps subspace.ParamSet + ps types.ParamSet }{ {"invalid unbonding time", ¶ms{time.Hour * 1, 100, "stake"}}, {"invalid bond denom", ¶ms{time.Hour * 48, 100, ""}}, diff --git a/x/params/subspace/table.go b/x/params/types/table.go similarity index 98% rename from x/params/subspace/table.go rename to x/params/types/table.go index 92e72242b967..72c24dedc8c7 100644 --- a/x/params/subspace/table.go +++ b/x/params/types/table.go @@ -1,4 +1,4 @@ -package subspace +package types import ( "reflect" diff --git a/x/params/types/table_test.go b/x/params/types/table_test.go new file mode 100644 index 000000000000..db2c9d321544 --- /dev/null +++ b/x/params/types/table_test.go @@ -0,0 +1,45 @@ +package types_test + +import ( + "testing" + "time" + + "github.com/cosmos/cosmos-sdk/x/params/types" + "github.com/stretchr/testify/require" +) + +func TestKeyTable(t *testing.T) { + table := types.NewKeyTable() + + require.Panics(t, func() { table.RegisterType(types.ParamSetPair{[]byte(""), nil, nil}) }) + require.Panics(t, func() { table.RegisterType(types.ParamSetPair{[]byte("!@#$%"), nil, nil}) }) + require.Panics(t, func() { table.RegisterType(types.ParamSetPair{[]byte("hello,"), nil, nil}) }) + require.Panics(t, func() { table.RegisterType(types.ParamSetPair{[]byte("hello"), nil, nil}) }) + + require.NotPanics(t, func() { + table.RegisterType(types.ParamSetPair{keyBondDenom, string("stake"), validateBondDenom}) + }) + require.NotPanics(t, func() { + table.RegisterType(types.ParamSetPair{keyMaxValidators, uint16(100), validateMaxValidators}) + }) + require.Panics(t, func() { + table.RegisterType(types.ParamSetPair{keyUnbondingTime, time.Duration(1), nil}) + }) + require.NotPanics(t, func() { + table.RegisterType(types.ParamSetPair{keyUnbondingTime, time.Duration(1), validateMaxValidators}) + }) + require.NotPanics(t, func() { + newTable := types.NewKeyTable() + newTable.RegisterParamSet(¶ms{}) + }) + + require.Panics(t, func() { table.RegisterParamSet(¶ms{}) }) + require.Panics(t, func() { types.NewKeyTable(types.ParamSetPair{[]byte(""), nil, nil}) }) + + require.NotPanics(t, func() { + types.NewKeyTable( + types.ParamSetPair{[]byte("test"), string("stake"), validateBondDenom}, + types.ParamSetPair{[]byte("test2"), uint16(100), validateMaxValidators}, + ) + }) +} diff --git a/x/slashing/internal/keeper/test_common.go b/x/slashing/internal/keeper/test_common.go index 8ddd7bd7e1d3..ca388dd24d18 100644 --- a/x/slashing/internal/keeper/test_common.go +++ b/x/slashing/internal/keeper/test_common.go @@ -22,7 +22,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank" - "github.com/cosmos/cosmos-sdk/x/params" + "github.com/cosmos/cosmos-sdk/x/params/keeper" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" "github.com/cosmos/cosmos-sdk/x/slashing/internal/types" "github.com/cosmos/cosmos-sdk/x/staking" "github.com/cosmos/cosmos-sdk/x/supply" @@ -56,14 +57,14 @@ func createTestCodec() *codec.Codec { return cdc } -func CreateTestInput(t *testing.T, defaults types.Params) (sdk.Context, bank.Keeper, staking.Keeper, params.Subspace, Keeper) { +func CreateTestInput(t *testing.T, defaults types.Params) (sdk.Context, bank.Keeper, staking.Keeper, paramtypes.Subspace, Keeper) { keyAcc := sdk.NewKVStoreKey(auth.StoreKey) keyBank := sdk.NewKVStoreKey(bank.StoreKey) keyStaking := sdk.NewKVStoreKey(staking.StoreKey) keySlashing := sdk.NewKVStoreKey(types.StoreKey) keySupply := sdk.NewKVStoreKey(supply.StoreKey) - keyParams := sdk.NewKVStoreKey(params.StoreKey) - tkeyParams := sdk.NewTransientStoreKey(params.TStoreKey) + keyParams := sdk.NewKVStoreKey(paramtypes.StoreKey) + tkeyParams := sdk.NewTransientStoreKey(paramtypes.TStoreKey) db := dbm.NewMemDB() @@ -92,7 +93,7 @@ func CreateTestInput(t *testing.T, defaults types.Params) (sdk.Context, bank.Kee blacklistedAddrs[notBondedPool.GetAddress().String()] = true blacklistedAddrs[bondPool.GetAddress().String()] = true - paramsKeeper := params.NewKeeper(params.ModuleCdc, keyParams, tkeyParams) + paramsKeeper := keeper.NewKeeper(appCodec, keyParams, tkeyParams) accountKeeper := auth.NewAccountKeeper(appCodec, keyAcc, paramsKeeper.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount) bk := bank.NewBaseKeeper(cdc, keyBank, accountKeeper, paramsKeeper.Subspace(bank.DefaultParamspace), blacklistedAddrs) diff --git a/x/slashing/internal/types/expected_keepers.go b/x/slashing/internal/types/expected_keepers.go index fe5695eebbf2..4a9dd4f7f2d6 100644 --- a/x/slashing/internal/types/expected_keepers.go +++ b/x/slashing/internal/types/expected_keepers.go @@ -5,7 +5,7 @@ package types import ( sdk "github.com/cosmos/cosmos-sdk/types" authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" - "github.com/cosmos/cosmos-sdk/x/params" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" stakingexported "github.com/cosmos/cosmos-sdk/x/staking/exported" ) @@ -26,10 +26,10 @@ type BankKeeper interface { // ParamSubspace defines the expected Subspace interfacace type ParamSubspace interface { - WithKeyTable(table params.KeyTable) params.Subspace + WithKeyTable(table paramtypes.KeyTable) paramtypes.Subspace Get(ctx sdk.Context, key []byte, ptr interface{}) - GetParamSet(ctx sdk.Context, ps params.ParamSet) - SetParamSet(ctx sdk.Context, ps params.ParamSet) + GetParamSet(ctx sdk.Context, ps paramtypes.ParamSet) + SetParamSet(ctx sdk.Context, ps paramtypes.ParamSet) } // StakingKeeper expected staking keeper diff --git a/x/slashing/internal/types/params.go b/x/slashing/internal/types/params.go index 15dd6cca6238..8499efdbac1f 100644 --- a/x/slashing/internal/types/params.go +++ b/x/slashing/internal/types/params.go @@ -5,7 +5,7 @@ import ( "time" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/params" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" ) // Default parameter namespace @@ -31,8 +31,8 @@ var ( ) // ParamKeyTable for slashing module -func ParamKeyTable() params.KeyTable { - return params.NewKeyTable().RegisterParamSet(&Params{}) +func ParamKeyTable() paramtypes.KeyTable { + return paramtypes.NewKeyTable().RegisterParamSet(&Params{}) } // Params - used for initializing default parameter for slashing at genesis @@ -73,13 +73,13 @@ func (p Params) String() string { } // ParamSetPairs - Implements params.ParamSet -func (p *Params) ParamSetPairs() params.ParamSetPairs { - return params.ParamSetPairs{ - params.NewParamSetPair(KeySignedBlocksWindow, &p.SignedBlocksWindow, validateSignedBlocksWindow), - params.NewParamSetPair(KeyMinSignedPerWindow, &p.MinSignedPerWindow, validateMinSignedPerWindow), - params.NewParamSetPair(KeyDowntimeJailDuration, &p.DowntimeJailDuration, validateDowntimeJailDuration), - params.NewParamSetPair(KeySlashFractionDoubleSign, &p.SlashFractionDoubleSign, validateSlashFractionDoubleSign), - params.NewParamSetPair(KeySlashFractionDowntime, &p.SlashFractionDowntime, validateSlashFractionDowntime), +func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { + return paramtypes.ParamSetPairs{ + paramtypes.NewParamSetPair(KeySignedBlocksWindow, &p.SignedBlocksWindow, validateSignedBlocksWindow), + paramtypes.NewParamSetPair(KeyMinSignedPerWindow, &p.MinSignedPerWindow, validateMinSignedPerWindow), + paramtypes.NewParamSetPair(KeyDowntimeJailDuration, &p.DowntimeJailDuration, validateDowntimeJailDuration), + paramtypes.NewParamSetPair(KeySlashFractionDoubleSign, &p.SlashFractionDoubleSign, validateSlashFractionDoubleSign), + paramtypes.NewParamSetPair(KeySlashFractionDowntime, &p.SlashFractionDowntime, validateSlashFractionDowntime), } } diff --git a/x/staking/keeper/keeper.go b/x/staking/keeper/keeper.go index ef7aab43557f..4e241ded201f 100644 --- a/x/staking/keeper/keeper.go +++ b/x/staking/keeper/keeper.go @@ -8,7 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/params" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" "github.com/cosmos/cosmos-sdk/x/staking/types" ) @@ -27,14 +27,14 @@ type Keeper struct { bankKeeper types.BankKeeper supplyKeeper types.SupplyKeeper hooks types.StakingHooks - paramstore params.Subspace + paramstore paramtypes.Subspace validatorCache map[string]cachedValidator validatorCacheList *list.List } // NewKeeper creates a new staking Keeper instance func NewKeeper( - cdc codec.Marshaler, key sdk.StoreKey, bk types.BankKeeper, sk types.SupplyKeeper, ps params.Subspace, + cdc codec.Marshaler, key sdk.StoreKey, bk types.BankKeeper, sk types.SupplyKeeper, ps paramtypes.Subspace, ) Keeper { // ensure bonded and not bonded module accounts are set diff --git a/x/staking/keeper/params.go b/x/staking/keeper/params.go index e50e6ccd6455..25ef7cf4bb87 100644 --- a/x/staking/keeper/params.go +++ b/x/staking/keeper/params.go @@ -4,7 +4,7 @@ import ( "time" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/params" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" "github.com/cosmos/cosmos-sdk/x/staking/types" ) @@ -14,8 +14,8 @@ const ( ) // ParamTable for staking module -func ParamKeyTable() params.KeyTable { - return params.NewKeyTable().RegisterParamSet(&types.Params{}) +func ParamKeyTable() paramtypes.KeyTable { + return paramtypes.NewKeyTable().RegisterParamSet(&types.Params{}) } // UnbondingTime diff --git a/x/staking/keeper/test_common.go b/x/staking/keeper/test_common.go index 9d97cc873266..18a0dfc509ca 100644 --- a/x/staking/keeper/test_common.go +++ b/x/staking/keeper/test_common.go @@ -24,7 +24,9 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth" authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" "github.com/cosmos/cosmos-sdk/x/bank" - "github.com/cosmos/cosmos-sdk/x/params" + "github.com/cosmos/cosmos-sdk/x/params/keeper" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + "github.com/cosmos/cosmos-sdk/x/params/types/proposal" "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/cosmos/cosmos-sdk/x/supply" ) @@ -85,8 +87,8 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context keyStaking := sdk.NewKVStoreKey(types.StoreKey) keyAcc := sdk.NewKVStoreKey(auth.StoreKey) bankKey := sdk.NewKVStoreKey(bank.StoreKey) - keyParams := sdk.NewKVStoreKey(params.StoreKey) - tkeyParams := sdk.NewTransientStoreKey(params.TStoreKey) + keyParams := sdk.NewKVStoreKey(paramtypes.StoreKey) + tkeyParams := sdk.NewTransientStoreKey(paramtypes.TStoreKey) keySupply := sdk.NewKVStoreKey(supply.StoreKey) db := dbm.NewMemDB() @@ -121,7 +123,7 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context blacklistedAddrs[notBondedPool.GetAddress().String()] = true blacklistedAddrs[bondPool.GetAddress().String()] = true - pk := params.NewKeeper(params.ModuleCdc, keyParams, tkeyParams) + pk := keeper.NewKeeper(proposal.ModuleCdc, keyParams, tkeyParams) accountKeeper := auth.NewAccountKeeper( appCodec, diff --git a/x/staking/types/params.go b/x/staking/types/params.go index ae3dd7cf8ae7..b738f1b06ea6 100644 --- a/x/staking/types/params.go +++ b/x/staking/types/params.go @@ -8,7 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/params" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" yaml "gopkg.in/yaml.v2" ) @@ -39,7 +39,7 @@ var ( KeyHistoricalEntries = []byte("HistoricalEntries") ) -var _ params.ParamSet = (*Params)(nil) +var _ paramtypes.ParamSet = (*Params)(nil) // NewParams creates a new Params instance func NewParams( @@ -56,13 +56,13 @@ func NewParams( } // Implements params.ParamSet -func (p *Params) ParamSetPairs() params.ParamSetPairs { - return params.ParamSetPairs{ - params.NewParamSetPair(KeyUnbondingTime, &p.UnbondingTime, validateUnbondingTime), - params.NewParamSetPair(KeyMaxValidators, &p.MaxValidators, validateMaxValidators), - params.NewParamSetPair(KeyMaxEntries, &p.MaxEntries, validateMaxEntries), - params.NewParamSetPair(KeyHistoricalEntries, &p.HistoricalEntries, validateHistoricalEntries), - params.NewParamSetPair(KeyBondDenom, &p.BondDenom, validateBondDenom), +func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { + return paramtypes.ParamSetPairs{ + paramtypes.NewParamSetPair(KeyUnbondingTime, &p.UnbondingTime, validateUnbondingTime), + paramtypes.NewParamSetPair(KeyMaxValidators, &p.MaxValidators, validateMaxValidators), + paramtypes.NewParamSetPair(KeyMaxEntries, &p.MaxEntries, validateMaxEntries), + paramtypes.NewParamSetPair(KeyHistoricalEntries, &p.HistoricalEntries, validateHistoricalEntries), + paramtypes.NewParamSetPair(KeyBondDenom, &p.BondDenom, validateBondDenom), } } From 2f2e7b99cb6819dfafcb0066c444dcf560422ed9 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Wed, 19 Feb 2020 18:13:25 +0100 Subject: [PATCH 156/529] Merge PR #5678: Errors Guidelines Doc --- docs/building-modules/README.md | 1 + docs/building-modules/errors.md | 53 ++++++++++++++++++++++++++++++ docs/building-modules/structure.md | 4 +-- 3 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 docs/building-modules/errors.md diff --git a/docs/building-modules/README.md b/docs/building-modules/README.md index f23a129e7bb4..15a2f0c4640f 100644 --- a/docs/building-modules/README.md +++ b/docs/building-modules/README.md @@ -19,3 +19,4 @@ This repository contains documentation on concepts developers need to know in or 9. [Genesis](./genesis.md) 10. [Module Interfaces](./module-interfaces.md) 11. [Standard Module Structure](./structure.md) +12. [Errors](./errors.md) diff --git a/docs/building-modules/errors.md b/docs/building-modules/errors.md new file mode 100644 index 000000000000..426a9d6d9177 --- /dev/null +++ b/docs/building-modules/errors.md @@ -0,0 +1,53 @@ + + +# Errors + +Modules are encouraged to define and register their own errors to provide better +context on failed message or handler execution. Typically, these errors should be +common or general errors which can be further wrapped to provide additional specific +execution context. + +## Registration + +Modules should define and register their custom errors in `x/{module}/types/errors.go`. Registration +of errors is handled via the `types/errors` package. + +Example: + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.38.1/x/distribution/types/errors.go#L1-L21 + +Each custom module error must provide the codespace, which is typically the module name +(e.g. "distribution") and is unique per module, and a uint32 code. Together, the codespace and code +provide a globally unique SDK error. Typically, the code is monotonically increasing but does not +necessarily have to be. The only restrictions on error codes are the following: + +* Must be greater than one, as a code value of one is reserved for internal errors. +* Must be unique within the module. + +Note, the SDK provides a core set of *common* errors. These errors are defined in `types/errors/errors.go`. + +## Wrapping + +The custom module errors can be returned as their concrete type as they already fulfill the `error` +interface. However, module errors can be wrapped to provide further context and meaning to failed +execution. + +Example: + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.38.1/x/distribution/keeper/querier.go#L62-L80 + +Regardless if an error is wrapped or not, the SDK's `errors` package provides an API to determine if +an error is of a particular kind via `Is`. + +## ABCI + +If a module error is registered, the SDK `errors` package allows ABCI information to be extracted +through the `ABCIInfo` API. The package also provides `ResponseCheckTx` and `ResponseDeliverTx` as +auxiliary APIs to automatically get `CheckTx` and `DeliverTx` responses from an error. + +## Next {hide} + +Learn about [interfaces](../interfaces/interfaces-intro.md) {hide} diff --git a/docs/building-modules/structure.md b/docs/building-modules/structure.md index 47d9a82b19ff..bb20c9945ed5 100644 --- a/docs/building-modules/structure.md +++ b/docs/building-modules/structure.md @@ -85,9 +85,9 @@ allows for greater freedom of development while maintaining API stability. - `module.go`: The module's implementation of the `AppModule` and `AppModuleBasic` interfaces. - `simulation/`: The module's simulation package defines all the required functions -used on the blockchain simulator: randomized genesis state, parameters, weigthed +used on the blockchain simulator: randomized genesis state, parameters, weighted operations, proposal contents and types decoders. ## Next {hide} -Learn about [interfaces](../interfaces/interfaces-intro.md) {hide} +Learn about [Errors](./errors.md) {hide} From 883c1a2bc1a4b03f921c014ca827e993eee5ee5c Mon Sep 17 00:00:00 2001 From: Anil Kumar Kammari Date: Thu, 20 Feb 2020 05:34:13 +0530 Subject: [PATCH 157/529] Merge PR #5627: Regen Network/Slashing protobuf --- CHANGELOG.md | 5 + simapp/app.go | 2 +- types/proto.go | 2 +- x/slashing/abci_test.go | 2 +- x/slashing/alias.go | 4 +- x/slashing/client/cli/query.go | 8 +- x/slashing/client/cli/tx.go | 2 +- x/slashing/client/rest/query.go | 2 +- x/slashing/client/rest/tx.go | 2 +- x/slashing/genesis.go | 2 +- x/slashing/handler.go | 2 +- x/slashing/handler_test.go | 4 +- x/slashing/internal/types/codec.go | 20 - x/slashing/{internal => }/keeper/hooks.go | 2 +- .../{internal => }/keeper/infractions.go | 2 +- x/slashing/{internal => }/keeper/keeper.go | 32 +- .../{internal => }/keeper/keeper_test.go | 2 +- x/slashing/{internal => }/keeper/params.go | 2 +- x/slashing/{internal => }/keeper/querier.go | 2 +- .../{internal => }/keeper/querier_test.go | 2 +- .../{internal => }/keeper/signing_info.go | 22 +- .../keeper/signing_info_test.go | 2 +- .../{internal => }/keeper/test_common.go | 4 +- x/slashing/{internal => }/keeper/unjail.go | 2 +- x/slashing/module.go | 2 +- x/slashing/simulation/decoder.go | 7 +- x/slashing/simulation/decoder_test.go | 10 +- x/slashing/simulation/genesis.go | 2 +- x/slashing/simulation/operations.go | 4 +- x/slashing/simulation/params.go | 2 +- x/slashing/types/codec.go | 28 + x/slashing/{internal => }/types/errors.go | 0 x/slashing/{internal => }/types/events.go | 0 .../{internal => }/types/expected_keepers.go | 0 x/slashing/{internal => }/types/genesis.go | 0 x/slashing/{internal => }/types/keys.go | 0 x/slashing/{internal => }/types/msg.go | 6 +- x/slashing/{internal => }/types/msg_test.go | 0 x/slashing/{internal => }/types/params.go | 0 x/slashing/{internal => }/types/querier.go | 0 .../{internal => }/types/signing_info.go | 18 +- x/slashing/types/types.pb.go | 761 ++++++++++++++++++ x/slashing/types/types.proto | 35 + 43 files changed, 918 insertions(+), 88 deletions(-) delete mode 100644 x/slashing/internal/types/codec.go rename x/slashing/{internal => }/keeper/hooks.go (97%) rename x/slashing/{internal => }/keeper/infractions.go (98%) rename x/slashing/{internal => }/keeper/keeper.go (77%) rename x/slashing/{internal => }/keeper/keeper_test.go (99%) rename x/slashing/{internal => }/keeper/params.go (96%) rename x/slashing/{internal => }/keeper/querier.go (97%) rename x/slashing/{internal => }/keeper/querier_test.go (92%) rename x/slashing/{internal => }/keeper/signing_info.go (91%) rename x/slashing/{internal => }/keeper/signing_info_test.go (97%) rename x/slashing/{internal => }/keeper/test_common.go (98%) rename x/slashing/{internal => }/keeper/unjail.go (95%) create mode 100644 x/slashing/types/codec.go rename x/slashing/{internal => }/types/errors.go (100%) rename x/slashing/{internal => }/types/events.go (100%) rename x/slashing/{internal => }/types/expected_keepers.go (100%) rename x/slashing/{internal => }/types/genesis.go (100%) rename x/slashing/{internal => }/types/keys.go (100%) rename x/slashing/{internal => }/types/msg.go (83%) rename x/slashing/{internal => }/types/msg_test.go (100%) rename x/slashing/{internal => }/types/params.go (100%) rename x/slashing/{internal => }/types/querier.go (100%) rename x/slashing/{internal => }/types/signing_info.go (50%) create mode 100644 x/slashing/types/types.pb.go create mode 100644 x/slashing/types/types.proto diff --git a/CHANGELOG.md b/CHANGELOG.md index 34c617d89f9c..5804dbb319d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -86,6 +86,11 @@ for JSON encoding. * Every reference of `crypto.Pubkey` in context of a `Validator` is now of type string. `GetPubKeyFromBech32` must be used to get the `crypto.Pubkey`. * The `Keeper` constructor now takes a `codec.Marshaler` instead of a concrete Amino codec. This exact type provided is specified by `ModuleCdc`. +* (x/slashing) [\#5627](https://github.com/cosmos/cosmos-sdk/pull/5627) Migrate the `x/slashing` module to use Protocol Buffers for state +serialization instead of Amino. The exact codec used is `codec.HybridCodec` which utilizes Protobuf for binary encoding and Amino +for JSON encoding. + * The `Keeper` constructor now takes a `codec.Marshaler` instead of a concrete Amino codec. This exact type + provided is specified by `ModuleCdc`. * (x/distribution) [\#5610](https://github.com/cosmos/cosmos-sdk/pull/5610) Migrate the `x/distribution` module to use Protocol Buffers for state serialization instead of Amino. The exact codec used is `codec.HybridCodec` which utilizes Protobuf for binary encoding and Amino for JSON encoding. diff --git a/simapp/app.go b/simapp/app.go index e1d646f7c978..56f5513e2d2b 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -184,7 +184,7 @@ func NewSimApp( app.SupplyKeeper, auth.FeeCollectorName, app.ModuleAccountAddrs(), ) app.SlashingKeeper = slashing.NewKeeper( - app.cdc, keys[slashing.StoreKey], &stakingKeeper, app.subspaces[slashing.ModuleName], + appCodec, keys[slashing.StoreKey], &stakingKeeper, app.subspaces[slashing.ModuleName], ) app.CrisisKeeper = crisis.NewKeeper( app.subspaces[crisis.ModuleName], invCheckPeriod, app.SupplyKeeper, auth.FeeCollectorName, diff --git a/types/proto.go b/types/proto.go index e4cdbdc511c0..b6978c1eb9a5 100644 --- a/types/proto.go +++ b/types/proto.go @@ -1,7 +1,7 @@ package types import ( - _ "github.com/gogo/protobuf/gogoproto" // nolint + _ "github.com/gogo/protobuf/gogoproto" // nolint _ "github.com/regen-network/cosmos-proto" // nolint ) diff --git a/x/slashing/abci_test.go b/x/slashing/abci_test.go index a6a14c885b3d..c1b0f62fffb4 100644 --- a/x/slashing/abci_test.go +++ b/x/slashing/abci_test.go @@ -9,7 +9,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/slashing" - slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/internal/keeper" + slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" "github.com/cosmos/cosmos-sdk/x/staking" ) diff --git a/x/slashing/alias.go b/x/slashing/alias.go index 38d556a6e492..9ebdd29edf35 100644 --- a/x/slashing/alias.go +++ b/x/slashing/alias.go @@ -3,8 +3,8 @@ package slashing // nolint import ( - "github.com/cosmos/cosmos-sdk/x/slashing/internal/keeper" - "github.com/cosmos/cosmos-sdk/x/slashing/internal/types" + "github.com/cosmos/cosmos-sdk/x/slashing/keeper" + "github.com/cosmos/cosmos-sdk/x/slashing/types" ) const ( diff --git a/x/slashing/client/cli/query.go b/x/slashing/client/cli/query.go index 71f404230758..c661b589f1d0 100644 --- a/x/slashing/client/cli/query.go +++ b/x/slashing/client/cli/query.go @@ -12,7 +12,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/slashing/internal/types" + "github.com/cosmos/cosmos-sdk/x/slashing/types" ) // GetQueryCmd returns the cli query commands for this module @@ -68,7 +68,11 @@ $ query slashing signing-info cosmosvalconspub1zcjduepqfhvwcmt7p06fvdge } var signingInfo types.ValidatorSigningInfo - cdc.MustUnmarshalBinaryLengthPrefixed(res, &signingInfo) + signingInfo, err = types.UnmarshalValSigningInfo(types.ModuleCdc, res) + if err != nil { + return err + } + return cliCtx.PrintOutput(signingInfo) }, } diff --git a/x/slashing/client/cli/tx.go b/x/slashing/client/cli/tx.go index 117e216a957a..4233d5c7a072 100644 --- a/x/slashing/client/cli/tx.go +++ b/x/slashing/client/cli/tx.go @@ -12,7 +12,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" authclient "github.com/cosmos/cosmos-sdk/x/auth/client" - "github.com/cosmos/cosmos-sdk/x/slashing/internal/types" + "github.com/cosmos/cosmos-sdk/x/slashing/types" ) // GetTxCmd returns the transaction commands for this module diff --git a/x/slashing/client/rest/query.go b/x/slashing/client/rest/query.go index 751fe648dc45..2d3d9bfab798 100644 --- a/x/slashing/client/rest/query.go +++ b/x/slashing/client/rest/query.go @@ -9,7 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/rest" - "github.com/cosmos/cosmos-sdk/x/slashing/internal/types" + "github.com/cosmos/cosmos-sdk/x/slashing/types" ) func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router) { diff --git a/x/slashing/client/rest/tx.go b/x/slashing/client/rest/tx.go index 1257b8e105a5..9498ea8ba5ff 100644 --- a/x/slashing/client/rest/tx.go +++ b/x/slashing/client/rest/tx.go @@ -10,7 +10,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/rest" authclient "github.com/cosmos/cosmos-sdk/x/auth/client" - "github.com/cosmos/cosmos-sdk/x/slashing/internal/types" + "github.com/cosmos/cosmos-sdk/x/slashing/types" ) func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router) { diff --git a/x/slashing/genesis.go b/x/slashing/genesis.go index 8b959c8a0bac..a5d2eb0f1350 100644 --- a/x/slashing/genesis.go +++ b/x/slashing/genesis.go @@ -2,7 +2,7 @@ package slashing import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/slashing/internal/types" + "github.com/cosmos/cosmos-sdk/x/slashing/types" "github.com/cosmos/cosmos-sdk/x/staking/exported" ) diff --git a/x/slashing/handler.go b/x/slashing/handler.go index fe4ef7cb7c2e..629a92dde29e 100644 --- a/x/slashing/handler.go +++ b/x/slashing/handler.go @@ -3,7 +3,7 @@ package slashing import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/cosmos-sdk/x/slashing/internal/types" + "github.com/cosmos/cosmos-sdk/x/slashing/types" ) // NewHandler creates an sdk.Handler for all the slashing type messages diff --git a/x/slashing/handler_test.go b/x/slashing/handler_test.go index c168f8052ffb..abd5e52559fd 100644 --- a/x/slashing/handler_test.go +++ b/x/slashing/handler_test.go @@ -11,8 +11,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/slashing" - slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/internal/keeper" - "github.com/cosmos/cosmos-sdk/x/slashing/internal/types" + slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" + "github.com/cosmos/cosmos-sdk/x/slashing/types" "github.com/cosmos/cosmos-sdk/x/staking" ) diff --git a/x/slashing/internal/types/codec.go b/x/slashing/internal/types/codec.go deleted file mode 100644 index 34790d54d630..000000000000 --- a/x/slashing/internal/types/codec.go +++ /dev/null @@ -1,20 +0,0 @@ -package types - -import ( - "github.com/cosmos/cosmos-sdk/codec" -) - -// RegisterCodec registers concrete types on codec -func RegisterCodec(cdc *codec.Codec) { - cdc.RegisterConcrete(MsgUnjail{}, "cosmos-sdk/MsgUnjail", nil) -} - -// ModuleCdc defines the module codec -var ModuleCdc *codec.Codec - -func init() { - ModuleCdc = codec.New() - RegisterCodec(ModuleCdc) - codec.RegisterCrypto(ModuleCdc) - ModuleCdc.Seal() -} diff --git a/x/slashing/internal/keeper/hooks.go b/x/slashing/keeper/hooks.go similarity index 97% rename from x/slashing/internal/keeper/hooks.go rename to x/slashing/keeper/hooks.go index a8ef6e093e15..e6374a87f990 100644 --- a/x/slashing/internal/keeper/hooks.go +++ b/x/slashing/keeper/hooks.go @@ -7,7 +7,7 @@ import ( "github.com/tendermint/tendermint/crypto" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/slashing/internal/types" + "github.com/cosmos/cosmos-sdk/x/slashing/types" ) func (k Keeper) AfterValidatorBonded(ctx sdk.Context, address sdk.ConsAddress, _ sdk.ValAddress) { diff --git a/x/slashing/internal/keeper/infractions.go b/x/slashing/keeper/infractions.go similarity index 98% rename from x/slashing/internal/keeper/infractions.go rename to x/slashing/keeper/infractions.go index a10b6f945b3a..a8e349b75be8 100644 --- a/x/slashing/internal/keeper/infractions.go +++ b/x/slashing/keeper/infractions.go @@ -6,7 +6,7 @@ import ( "github.com/tendermint/tendermint/crypto" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/slashing/internal/types" + "github.com/cosmos/cosmos-sdk/x/slashing/types" ) // HandleValidatorSignature handles a validator signature, must be called once per validator per block. diff --git a/x/slashing/internal/keeper/keeper.go b/x/slashing/keeper/keeper.go similarity index 77% rename from x/slashing/internal/keeper/keeper.go rename to x/slashing/keeper/keeper.go index e725519314d1..43f21a516edb 100644 --- a/x/slashing/internal/keeper/keeper.go +++ b/x/slashing/keeper/keeper.go @@ -3,24 +3,26 @@ package keeper import ( "fmt" + gogotypes "github.com/gogo/protobuf/types" + "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/libs/log" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/slashing/internal/types" + "github.com/cosmos/cosmos-sdk/x/slashing/types" ) // Keeper of the slashing store type Keeper struct { storeKey sdk.StoreKey - cdc *codec.Codec + cdc codec.Marshaler sk types.StakingKeeper paramspace types.ParamSubspace } // NewKeeper creates a slashing keeper -func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, sk types.StakingKeeper, paramspace types.ParamSubspace) Keeper { +func NewKeeper(cdc codec.Marshaler, key sdk.StoreKey, sk types.StakingKeeper, paramspace types.ParamSubspace) Keeper { return Keeper{ storeKey: key, cdc: cdc, @@ -37,18 +39,31 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { // AddPubkey sets a address-pubkey relation func (k Keeper) AddPubkey(ctx sdk.Context, pubkey crypto.PubKey) { addr := pubkey.Address() - k.setAddrPubkeyRelation(ctx, addr, pubkey) + + pkStr, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, pubkey) + if err != nil { + panic(fmt.Errorf("error while setting address-pubkey relation: %s", addr)) + } + + k.setAddrPubkeyRelation(ctx, addr, pkStr) } // GetPubkey returns the pubkey from the adddress-pubkey relation func (k Keeper) GetPubkey(ctx sdk.Context, address crypto.Address) (crypto.PubKey, error) { store := ctx.KVStore(k.storeKey) - var pubkey crypto.PubKey + + var pubkey gogotypes.StringValue err := k.cdc.UnmarshalBinaryLengthPrefixed(store.Get(types.GetAddrPubkeyRelationKey(address)), &pubkey) if err != nil { return nil, fmt.Errorf("address %s not found", sdk.ConsAddress(address)) } - return pubkey, nil + + pkStr, err := sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeConsPub, pubkey.Value) + if err != nil { + return pkStr, err + } + + return pkStr, nil } // Slash attempts to slash a validator. The slash is delegated to the staking @@ -79,9 +94,10 @@ func (k Keeper) Jail(ctx sdk.Context, consAddr sdk.ConsAddress) { k.sk.Jail(ctx, consAddr) } -func (k Keeper) setAddrPubkeyRelation(ctx sdk.Context, addr crypto.Address, pubkey crypto.PubKey) { +func (k Keeper) setAddrPubkeyRelation(ctx sdk.Context, addr crypto.Address, pubkey string) { store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinaryLengthPrefixed(pubkey) + + bz := k.cdc.MustMarshalBinaryLengthPrefixed(&gogotypes.StringValue{Value: pubkey}) store.Set(types.GetAddrPubkeyRelationKey(addr), bz) } diff --git a/x/slashing/internal/keeper/keeper_test.go b/x/slashing/keeper/keeper_test.go similarity index 99% rename from x/slashing/internal/keeper/keeper_test.go rename to x/slashing/keeper/keeper_test.go index fdf50a261e27..4f4f555bbffc 100644 --- a/x/slashing/internal/keeper/keeper_test.go +++ b/x/slashing/keeper/keeper_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/require" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/slashing/internal/types" + "github.com/cosmos/cosmos-sdk/x/slashing/types" "github.com/cosmos/cosmos-sdk/x/staking" ) diff --git a/x/slashing/internal/keeper/params.go b/x/slashing/keeper/params.go similarity index 96% rename from x/slashing/internal/keeper/params.go rename to x/slashing/keeper/params.go index 82fe991cccc1..8ece97a687ad 100644 --- a/x/slashing/internal/keeper/params.go +++ b/x/slashing/keeper/params.go @@ -4,7 +4,7 @@ import ( "time" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/slashing/internal/types" + "github.com/cosmos/cosmos-sdk/x/slashing/types" ) // SignedBlocksWindow - sliding window for downtime slashing diff --git a/x/slashing/internal/keeper/querier.go b/x/slashing/keeper/querier.go similarity index 97% rename from x/slashing/internal/keeper/querier.go rename to x/slashing/keeper/querier.go index 11b365e1ee1b..1eab719a63f7 100644 --- a/x/slashing/internal/keeper/querier.go +++ b/x/slashing/keeper/querier.go @@ -7,7 +7,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/cosmos-sdk/x/slashing/internal/types" + "github.com/cosmos/cosmos-sdk/x/slashing/types" ) // NewQuerier creates a new querier for slashing clients. diff --git a/x/slashing/internal/keeper/querier_test.go b/x/slashing/keeper/querier_test.go similarity index 92% rename from x/slashing/internal/keeper/querier_test.go rename to x/slashing/keeper/querier_test.go index ea4095dc61b1..fd924bc8e823 100644 --- a/x/slashing/internal/keeper/querier_test.go +++ b/x/slashing/keeper/querier_test.go @@ -7,7 +7,7 @@ import ( abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/x/slashing/internal/types" + "github.com/cosmos/cosmos-sdk/x/slashing/types" ) func TestNewQuerier(t *testing.T) { diff --git a/x/slashing/internal/keeper/signing_info.go b/x/slashing/keeper/signing_info.go similarity index 91% rename from x/slashing/internal/keeper/signing_info.go rename to x/slashing/keeper/signing_info.go index 1162c258f35a..0e1a82c62fa2 100644 --- a/x/slashing/internal/keeper/signing_info.go +++ b/x/slashing/keeper/signing_info.go @@ -3,8 +3,10 @@ package keeper import ( "time" + gogotypes "github.com/gogo/protobuf/types" + sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/slashing/internal/types" + "github.com/cosmos/cosmos-sdk/x/slashing/types" ) // GetValidatorSigningInfo retruns the ValidatorSigningInfo for a specific validator @@ -31,7 +33,7 @@ func (k Keeper) HasValidatorSigningInfo(ctx sdk.Context, consAddr sdk.ConsAddres // SetValidatorSigningInfo sets the validator signing info to a consensus address key func (k Keeper) SetValidatorSigningInfo(ctx sdk.Context, address sdk.ConsAddress, info types.ValidatorSigningInfo) { store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinaryLengthPrefixed(info) + bz := k.cdc.MustMarshalBinaryLengthPrefixed(&info) store.Set(types.GetValidatorSigningInfoKey(address), bz) } @@ -53,16 +55,17 @@ func (k Keeper) IterateValidatorSigningInfos(ctx sdk.Context, } // GetValidatorMissedBlockBitArray gets the bit for the missed blocks array -func (k Keeper) GetValidatorMissedBlockBitArray(ctx sdk.Context, address sdk.ConsAddress, index int64) (missed bool) { +func (k Keeper) GetValidatorMissedBlockBitArray(ctx sdk.Context, address sdk.ConsAddress, index int64) bool { store := ctx.KVStore(k.storeKey) bz := store.Get(types.GetValidatorMissedBlockBitArrayKey(address, index)) + var missed gogotypes.BoolValue if bz == nil { // lazy: treat empty key as not missed - missed = false - return + return false } k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &missed) - return + + return missed.Value } // IterateValidatorMissedBlockBitArray iterates over the signed blocks window @@ -74,13 +77,14 @@ func (k Keeper) IterateValidatorMissedBlockBitArray(ctx sdk.Context, index := int64(0) // Array may be sparse for ; index < k.SignedBlocksWindow(ctx); index++ { - var missed bool + var missed gogotypes.BoolValue bz := store.Get(types.GetValidatorMissedBlockBitArrayKey(address, index)) if bz == nil { continue } + k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &missed) - if handler(index, missed) { + if handler(index, missed.Value) { break } } @@ -128,7 +132,7 @@ func (k Keeper) IsTombstoned(ctx sdk.Context, consAddr sdk.ConsAddress) bool { // missed a block in the current window func (k Keeper) SetValidatorMissedBlockBitArray(ctx sdk.Context, address sdk.ConsAddress, index int64, missed bool) { store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinaryLengthPrefixed(missed) + bz := k.cdc.MustMarshalBinaryLengthPrefixed(&gogotypes.BoolValue{Value: missed}) store.Set(types.GetValidatorMissedBlockBitArrayKey(address, index), bz) } diff --git a/x/slashing/internal/keeper/signing_info_test.go b/x/slashing/keeper/signing_info_test.go similarity index 97% rename from x/slashing/internal/keeper/signing_info_test.go rename to x/slashing/keeper/signing_info_test.go index 7d9e7c56e526..ac8c5075276f 100644 --- a/x/slashing/internal/keeper/signing_info_test.go +++ b/x/slashing/keeper/signing_info_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/require" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/slashing/internal/types" + "github.com/cosmos/cosmos-sdk/x/slashing/types" ) func TestGetSetValidatorSigningInfo(t *testing.T) { diff --git a/x/slashing/internal/keeper/test_common.go b/x/slashing/keeper/test_common.go similarity index 98% rename from x/slashing/internal/keeper/test_common.go rename to x/slashing/keeper/test_common.go index ca388dd24d18..6fa24149f5ef 100644 --- a/x/slashing/internal/keeper/test_common.go +++ b/x/slashing/keeper/test_common.go @@ -24,7 +24,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/bank" "github.com/cosmos/cosmos-sdk/x/params/keeper" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" - "github.com/cosmos/cosmos-sdk/x/slashing/internal/types" + "github.com/cosmos/cosmos-sdk/x/slashing/types" "github.com/cosmos/cosmos-sdk/x/staking" "github.com/cosmos/cosmos-sdk/x/supply" ) @@ -124,7 +124,7 @@ func CreateTestInput(t *testing.T, defaults types.Params) (sdk.Context, bank.Kee } paramstore := paramsKeeper.Subspace(types.DefaultParamspace) - keeper := NewKeeper(cdc, keySlashing, &sk, paramstore) + keeper := NewKeeper(types.ModuleCdc, keySlashing, &sk, paramstore) keeper.SetParams(ctx, defaults) sk.SetHooks(keeper.Hooks()) diff --git a/x/slashing/internal/keeper/unjail.go b/x/slashing/keeper/unjail.go similarity index 95% rename from x/slashing/internal/keeper/unjail.go rename to x/slashing/keeper/unjail.go index 51fda4855382..cf57c1e71c4a 100644 --- a/x/slashing/internal/keeper/unjail.go +++ b/x/slashing/keeper/unjail.go @@ -2,7 +2,7 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/slashing/internal/types" + "github.com/cosmos/cosmos-sdk/x/slashing/types" ) // Unjail calls the staking Unjail function to unjail a validator if the diff --git a/x/slashing/module.go b/x/slashing/module.go index 3e4c0b7a99e8..b404b8c4ecde 100644 --- a/x/slashing/module.go +++ b/x/slashing/module.go @@ -17,8 +17,8 @@ import ( sim "github.com/cosmos/cosmos-sdk/x/simulation" "github.com/cosmos/cosmos-sdk/x/slashing/client/cli" "github.com/cosmos/cosmos-sdk/x/slashing/client/rest" - "github.com/cosmos/cosmos-sdk/x/slashing/internal/types" "github.com/cosmos/cosmos-sdk/x/slashing/simulation" + "github.com/cosmos/cosmos-sdk/x/slashing/types" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" ) diff --git a/x/slashing/simulation/decoder.go b/x/slashing/simulation/decoder.go index 9aea5f701b15..48a12705a780 100644 --- a/x/slashing/simulation/decoder.go +++ b/x/slashing/simulation/decoder.go @@ -4,12 +4,13 @@ import ( "bytes" "fmt" + gogotypes "github.com/gogo/protobuf/types" "github.com/tendermint/tendermint/crypto" tmkv "github.com/tendermint/tendermint/libs/kv" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/slashing/internal/types" + "github.com/cosmos/cosmos-sdk/x/slashing/types" ) // DecodeStore unmarshals the KVPair's Value to the corresponding slashing type @@ -22,10 +23,10 @@ func DecodeStore(cdc *codec.Codec, kvA, kvB tmkv.Pair) string { return fmt.Sprintf("%v\n%v", infoA, infoB) case bytes.Equal(kvA.Key[:1], types.ValidatorMissedBlockBitArrayKey): - var missedA, missedB bool + var missedA, missedB gogotypes.BoolValue cdc.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &missedA) cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &missedB) - return fmt.Sprintf("missedA: %v\nmissedB: %v", missedA, missedB) + return fmt.Sprintf("missedA: %v\nmissedB: %v", missedA.Value, missedB.Value) case bytes.Equal(kvA.Key[:1], types.AddrPubkeyRelationKey): var pubKeyA, pubKeyB crypto.PubKey diff --git a/x/slashing/simulation/decoder_test.go b/x/slashing/simulation/decoder_test.go index acd3be67c62f..522bff74750d 100644 --- a/x/slashing/simulation/decoder_test.go +++ b/x/slashing/simulation/decoder_test.go @@ -5,6 +5,8 @@ import ( "testing" "time" + gogotypes "github.com/gogo/protobuf/types" + "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/crypto/ed25519" @@ -12,7 +14,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/slashing/internal/types" + "github.com/cosmos/cosmos-sdk/x/slashing/types" ) // nolint:deadcode,unused,varcheck @@ -36,11 +38,11 @@ func TestDecodeStore(t *testing.T) { info := types.NewValidatorSigningInfo(consAddr1, 0, 1, time.Now().UTC(), false, 0) bechPK := sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, delPk1) - missed := true + missed := gogotypes.BoolValue{Value: true} kvPairs := tmkv.Pairs{ tmkv.Pair{Key: types.GetValidatorSigningInfoKey(consAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(info)}, - tmkv.Pair{Key: types.GetValidatorMissedBlockBitArrayKey(consAddr1, 6), Value: cdc.MustMarshalBinaryLengthPrefixed(missed)}, + tmkv.Pair{Key: types.GetValidatorMissedBlockBitArrayKey(consAddr1, 6), Value: cdc.MustMarshalBinaryLengthPrefixed(&missed)}, tmkv.Pair{Key: types.GetAddrPubkeyRelationKey(delAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(delPk1)}, tmkv.Pair{Key: []byte{0x99}, Value: []byte{0x99}}, } @@ -50,7 +52,7 @@ func TestDecodeStore(t *testing.T) { expectedLog string }{ {"ValidatorSigningInfo", fmt.Sprintf("%v\n%v", info, info)}, - {"ValidatorMissedBlockBitArray", fmt.Sprintf("missedA: %v\nmissedB: %v", missed, missed)}, + {"ValidatorMissedBlockBitArray", fmt.Sprintf("missedA: %v\nmissedB: %v", missed.Value, missed.Value)}, {"AddrPubkeyRelation", fmt.Sprintf("PubKeyA: %s\nPubKeyB: %s", bechPK, bechPK)}, {"other", ""}, } diff --git a/x/slashing/simulation/genesis.go b/x/slashing/simulation/genesis.go index a26a626642b7..d9dae7cd3d7b 100644 --- a/x/slashing/simulation/genesis.go +++ b/x/slashing/simulation/genesis.go @@ -12,7 +12,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/x/simulation" - "github.com/cosmos/cosmos-sdk/x/slashing/internal/types" + "github.com/cosmos/cosmos-sdk/x/slashing/types" ) // Simulation parameter constants diff --git a/x/slashing/simulation/operations.go b/x/slashing/simulation/operations.go index 8b7124609c09..c0f0b94554f6 100644 --- a/x/slashing/simulation/operations.go +++ b/x/slashing/simulation/operations.go @@ -10,8 +10,8 @@ import ( simappparams "github.com/cosmos/cosmos-sdk/simapp/params" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/simulation" - "github.com/cosmos/cosmos-sdk/x/slashing/internal/keeper" - "github.com/cosmos/cosmos-sdk/x/slashing/internal/types" + "github.com/cosmos/cosmos-sdk/x/slashing/keeper" + "github.com/cosmos/cosmos-sdk/x/slashing/types" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" ) diff --git a/x/slashing/simulation/params.go b/x/slashing/simulation/params.go index 6679928d8fc4..72048f2264bd 100644 --- a/x/slashing/simulation/params.go +++ b/x/slashing/simulation/params.go @@ -7,7 +7,7 @@ import ( "math/rand" "github.com/cosmos/cosmos-sdk/x/simulation" - "github.com/cosmos/cosmos-sdk/x/slashing/internal/types" + "github.com/cosmos/cosmos-sdk/x/slashing/types" ) const ( diff --git a/x/slashing/types/codec.go b/x/slashing/types/codec.go new file mode 100644 index 000000000000..04114f1465a1 --- /dev/null +++ b/x/slashing/types/codec.go @@ -0,0 +1,28 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" +) + +// RegisterCodec registers concrete types on codec +func RegisterCodec(cdc *codec.Codec) { + cdc.RegisterConcrete(MsgUnjail{}, "cosmos-sdk/MsgUnjail", nil) +} + +var ( + amino = codec.New() + + // ModuleCdc references the global x/slashing module codec. Note, the codec + // should ONLY be used in certain instances of tests and for JSON encoding as Amino + // is still used for that purpose. + // + // The actual codec used for serialization should be provided to x/slashing and + // defined at the application level. + ModuleCdc = codec.NewHybridCodec(amino) +) + +func init() { + RegisterCodec(amino) + codec.RegisterCrypto(amino) + amino.Seal() +} diff --git a/x/slashing/internal/types/errors.go b/x/slashing/types/errors.go similarity index 100% rename from x/slashing/internal/types/errors.go rename to x/slashing/types/errors.go diff --git a/x/slashing/internal/types/events.go b/x/slashing/types/events.go similarity index 100% rename from x/slashing/internal/types/events.go rename to x/slashing/types/events.go diff --git a/x/slashing/internal/types/expected_keepers.go b/x/slashing/types/expected_keepers.go similarity index 100% rename from x/slashing/internal/types/expected_keepers.go rename to x/slashing/types/expected_keepers.go diff --git a/x/slashing/internal/types/genesis.go b/x/slashing/types/genesis.go similarity index 100% rename from x/slashing/internal/types/genesis.go rename to x/slashing/types/genesis.go diff --git a/x/slashing/internal/types/keys.go b/x/slashing/types/keys.go similarity index 100% rename from x/slashing/internal/types/keys.go rename to x/slashing/types/keys.go diff --git a/x/slashing/internal/types/msg.go b/x/slashing/types/msg.go similarity index 83% rename from x/slashing/internal/types/msg.go rename to x/slashing/types/msg.go index b2ccdce173ba..a9798615f6ad 100644 --- a/x/slashing/internal/types/msg.go +++ b/x/slashing/types/msg.go @@ -7,11 +7,6 @@ import ( // verify interface at compile time var _ sdk.Msg = &MsgUnjail{} -// MsgUnjail - struct for unjailing jailed validator -type MsgUnjail struct { - ValidatorAddr sdk.ValAddress `json:"address" yaml:"address"` // address of the validator operator -} - // NewMsgUnjail creates a new MsgUnjail instance func NewMsgUnjail(validatorAddr sdk.ValAddress) MsgUnjail { return MsgUnjail{ @@ -37,5 +32,6 @@ func (msg MsgUnjail) ValidateBasic() error { if msg.ValidatorAddr.Empty() { return ErrBadValidatorAddr } + return nil } diff --git a/x/slashing/internal/types/msg_test.go b/x/slashing/types/msg_test.go similarity index 100% rename from x/slashing/internal/types/msg_test.go rename to x/slashing/types/msg_test.go diff --git a/x/slashing/internal/types/params.go b/x/slashing/types/params.go similarity index 100% rename from x/slashing/internal/types/params.go rename to x/slashing/types/params.go diff --git a/x/slashing/internal/types/querier.go b/x/slashing/types/querier.go similarity index 100% rename from x/slashing/internal/types/querier.go rename to x/slashing/types/querier.go diff --git a/x/slashing/internal/types/signing_info.go b/x/slashing/types/signing_info.go similarity index 50% rename from x/slashing/internal/types/signing_info.go rename to x/slashing/types/signing_info.go index 431658c2241a..315cac792c56 100644 --- a/x/slashing/internal/types/signing_info.go +++ b/x/slashing/types/signing_info.go @@ -4,19 +4,11 @@ import ( "fmt" "time" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" ) -// ValidatorSigningInfo defines the signing info for a validator -type ValidatorSigningInfo struct { - Address sdk.ConsAddress `json:"address" yaml:"address"` // validator consensus address - StartHeight int64 `json:"start_height" yaml:"start_height"` // height at which validator was first a candidate OR was unjailed - IndexOffset int64 `json:"index_offset" yaml:"index_offset"` // index offset into signed block bit array - JailedUntil time.Time `json:"jailed_until" yaml:"jailed_until"` // timestamp validator cannot be unjailed until - Tombstoned bool `json:"tombstoned" yaml:"tombstoned"` // whether or not a validator has been tombstoned (killed out of validator set) - MissedBlocksCounter int64 `json:"missed_blocks_counter" yaml:"missed_blocks_counter"` // missed blocks counter (to avoid scanning the array every time) -} - // NewValidatorSigningInfo creates a new ValidatorSigningInfo instance func NewValidatorSigningInfo( condAddr sdk.ConsAddress, startHeight, indexOffset int64, @@ -45,3 +37,9 @@ func (i ValidatorSigningInfo) String() string { i.Address, i.StartHeight, i.IndexOffset, i.JailedUntil, i.Tombstoned, i.MissedBlocksCounter) } + +// unmarshal a validator signing info from a store value +func UnmarshalValSigningInfo(cdc codec.Marshaler, value []byte) (signingInfo ValidatorSigningInfo, err error) { + err = cdc.UnmarshalBinaryLengthPrefixed(value, &signingInfo) + return signingInfo, err +} diff --git a/x/slashing/types/types.pb.go b/x/slashing/types/types.pb.go new file mode 100644 index 000000000000..82791e7bcdcd --- /dev/null +++ b/x/slashing/types/types.pb.go @@ -0,0 +1,761 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: x/slashing/internal/types/types.proto + +package types + +import ( + bytes "bytes" + fmt "fmt" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" + _ "github.com/golang/protobuf/ptypes/timestamp" + io "io" + math "math" + math_bits "math/bits" + time "time" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf +var _ = time.Kitchen + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// MsgUnjail - struct for unjailing jailed validator +type MsgUnjail struct { + ValidatorAddr github_com_cosmos_cosmos_sdk_types.ValAddress `protobuf:"bytes,1,opt,name=validator_addr,json=validatorAddr,proto3,casttype=github.com/cosmos/cosmos-sdk/types.ValAddress" json:"address" yaml:"address"` +} + +func (m *MsgUnjail) Reset() { *m = MsgUnjail{} } +func (m *MsgUnjail) String() string { return proto.CompactTextString(m) } +func (*MsgUnjail) ProtoMessage() {} +func (*MsgUnjail) Descriptor() ([]byte, []int) { + return fileDescriptor_2b882c3b0cdd6f57, []int{0} +} +func (m *MsgUnjail) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUnjail) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUnjail.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 *MsgUnjail) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUnjail.Merge(m, src) +} +func (m *MsgUnjail) XXX_Size() int { + return m.Size() +} +func (m *MsgUnjail) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUnjail.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUnjail proto.InternalMessageInfo + +func (m *MsgUnjail) GetValidatorAddr() github_com_cosmos_cosmos_sdk_types.ValAddress { + if m != nil { + return m.ValidatorAddr + } + return nil +} + +// ValidatorSigningInfo defines the signing info for a validator +type ValidatorSigningInfo struct { + Address github_com_cosmos_cosmos_sdk_types.ConsAddress `protobuf:"bytes,1,opt,name=address,proto3,casttype=github.com/cosmos/cosmos-sdk/types.ConsAddress" json:"address,omitempty"` + StartHeight int64 `protobuf:"varint,2,opt,name=start_height,json=startHeight,proto3" json:"start_height,omitempty" yaml:"start_height"` + IndexOffset int64 `protobuf:"varint,3,opt,name=index_offset,json=indexOffset,proto3" json:"index_offset,omitempty" yaml:"index_offset"` + JailedUntil time.Time `protobuf:"bytes,4,opt,name=jailed_until,json=jailedUntil,proto3,stdtime" json:"jailed_until" yaml:"jailed_until"` + Tombstoned bool `protobuf:"varint,5,opt,name=tombstoned,proto3" json:"tombstoned,omitempty"` + MissedBlocksCounter int64 `protobuf:"varint,6,opt,name=missed_blocks_counter,json=missedBlocksCounter,proto3" json:"missed_blocks_counter,omitempty" yaml:"missed_blocks_counter"` +} + +func (m *ValidatorSigningInfo) Reset() { *m = ValidatorSigningInfo{} } +func (*ValidatorSigningInfo) ProtoMessage() {} +func (*ValidatorSigningInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_2b882c3b0cdd6f57, []int{1} +} +func (m *ValidatorSigningInfo) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ValidatorSigningInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ValidatorSigningInfo.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 *ValidatorSigningInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_ValidatorSigningInfo.Merge(m, src) +} +func (m *ValidatorSigningInfo) XXX_Size() int { + return m.Size() +} +func (m *ValidatorSigningInfo) XXX_DiscardUnknown() { + xxx_messageInfo_ValidatorSigningInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_ValidatorSigningInfo proto.InternalMessageInfo + +func (m *ValidatorSigningInfo) GetAddress() github_com_cosmos_cosmos_sdk_types.ConsAddress { + if m != nil { + return m.Address + } + return nil +} + +func (m *ValidatorSigningInfo) GetStartHeight() int64 { + if m != nil { + return m.StartHeight + } + return 0 +} + +func (m *ValidatorSigningInfo) GetIndexOffset() int64 { + if m != nil { + return m.IndexOffset + } + return 0 +} + +func (m *ValidatorSigningInfo) GetJailedUntil() time.Time { + if m != nil { + return m.JailedUntil + } + return time.Time{} +} + +func (m *ValidatorSigningInfo) GetTombstoned() bool { + if m != nil { + return m.Tombstoned + } + return false +} + +func (m *ValidatorSigningInfo) GetMissedBlocksCounter() int64 { + if m != nil { + return m.MissedBlocksCounter + } + return 0 +} + +func init() { + proto.RegisterType((*MsgUnjail)(nil), "cosmos_sdk.x.slashing.v1.MsgUnjail") + proto.RegisterType((*ValidatorSigningInfo)(nil), "cosmos_sdk.x.slashing.v1.ValidatorSigningInfo") +} + +func init() { + proto.RegisterFile("x/slashing/internal/types/types.proto", fileDescriptor_2b882c3b0cdd6f57) +} + +var fileDescriptor_2b882c3b0cdd6f57 = []byte{ + // 491 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0x3f, 0x6f, 0xd3, 0x4e, + 0x18, 0xc7, 0x73, 0xbf, 0xfc, 0x5a, 0xca, 0x25, 0x74, 0x70, 0x41, 0x58, 0x11, 0xf2, 0x59, 0x96, + 0x40, 0x59, 0x6a, 0x8b, 0xb2, 0x65, 0xc3, 0x5d, 0x40, 0xe2, 0x8f, 0x64, 0xda, 0x0e, 0x0c, 0x58, + 0xe7, 0xdc, 0xe5, 0x7c, 0xc4, 0xbe, 0x8b, 0x7c, 0xe7, 0x2a, 0x59, 0x79, 0x05, 0x1d, 0x19, 0xfb, + 0x42, 0x78, 0x01, 0x1d, 0x3b, 0x32, 0x19, 0x94, 0x2c, 0x88, 0x31, 0x63, 0x27, 0x64, 0x5f, 0x4c, + 0x23, 0xc4, 0xc0, 0x92, 0xf8, 0xfb, 0xb9, 0xe7, 0xfb, 0x7c, 0xef, 0xf1, 0x63, 0xf8, 0x78, 0x1e, + 0xa8, 0x0c, 0xab, 0x94, 0x0b, 0x16, 0x70, 0xa1, 0x69, 0x21, 0x70, 0x16, 0xe8, 0xc5, 0x8c, 0x2a, + 0xf3, 0xeb, 0xcf, 0x0a, 0xa9, 0xa5, 0x65, 0x8f, 0xa5, 0xca, 0xa5, 0x8a, 0x15, 0x99, 0xfa, 0x73, + 0xbf, 0x75, 0xf8, 0xe7, 0x4f, 0x07, 0x4f, 0x74, 0xca, 0x0b, 0x12, 0xcf, 0x70, 0xa1, 0x17, 0x41, + 0x53, 0x1c, 0x30, 0xc9, 0xe4, 0xed, 0x93, 0xe9, 0x30, 0x40, 0x4c, 0x4a, 0x96, 0x51, 0x53, 0x92, + 0x94, 0x93, 0x40, 0xf3, 0x9c, 0x2a, 0x8d, 0xf3, 0x99, 0x29, 0xf0, 0x3e, 0x01, 0x78, 0xf7, 0xb5, + 0x62, 0xa7, 0xe2, 0x23, 0xe6, 0x99, 0x55, 0xc2, 0xfd, 0x73, 0x9c, 0x71, 0x82, 0xb5, 0x2c, 0x62, + 0x4c, 0x48, 0x61, 0x03, 0x17, 0x0c, 0xfb, 0xe1, 0x9b, 0x9f, 0x15, 0xba, 0x53, 0x6b, 0xaa, 0xd4, + 0xba, 0x42, 0xfb, 0x0b, 0x9c, 0x67, 0x23, 0x6f, 0x03, 0xbc, 0x9b, 0x0a, 0x1d, 0x32, 0xae, 0xd3, + 0x32, 0xf1, 0xc7, 0x32, 0x0f, 0xcc, 0xa5, 0x37, 0x7f, 0x87, 0x8a, 0x4c, 0x37, 0x33, 0x9d, 0xe1, + 0xec, 0xb9, 0x71, 0x44, 0xf7, 0x7e, 0xa7, 0xd4, 0xc4, 0xfb, 0xd2, 0x85, 0xf7, 0xcf, 0x5a, 0xf2, + 0x8e, 0x33, 0xc1, 0x05, 0x7b, 0x29, 0x26, 0xd2, 0x7a, 0x05, 0xdb, 0xd4, 0xcd, 0x45, 0x8e, 0x6e, + 0x2a, 0xe4, 0xff, 0x43, 0xd6, 0xb1, 0x14, 0xaa, 0x0d, 0x6b, 0x5b, 0x58, 0x23, 0xd8, 0x57, 0x1a, + 0x17, 0x3a, 0x4e, 0x29, 0x67, 0xa9, 0xb6, 0xff, 0x73, 0xc1, 0xb0, 0x1b, 0x3e, 0x5c, 0x57, 0xe8, + 0xc0, 0x0c, 0xb4, 0x7d, 0xea, 0x45, 0xbd, 0x46, 0xbe, 0x68, 0x54, 0xed, 0xe5, 0x82, 0xd0, 0x79, + 0x2c, 0x27, 0x13, 0x45, 0xb5, 0xdd, 0xfd, 0xd3, 0xbb, 0x7d, 0xea, 0x45, 0xbd, 0x46, 0xbe, 0x6d, + 0x94, 0xf5, 0x01, 0xf6, 0xeb, 0xb7, 0x4b, 0x49, 0x5c, 0x0a, 0xcd, 0x33, 0xfb, 0x7f, 0x17, 0x0c, + 0x7b, 0x47, 0x03, 0xdf, 0xec, 0xc6, 0x6f, 0x77, 0xe3, 0x9f, 0xb4, 0xbb, 0x09, 0xd1, 0x55, 0x85, + 0x3a, 0xb7, 0xbd, 0xb7, 0xdd, 0xde, 0xc5, 0x37, 0x04, 0xa2, 0x9e, 0x41, 0xa7, 0x35, 0xb1, 0x1c, + 0x08, 0xb5, 0xcc, 0x13, 0xa5, 0xa5, 0xa0, 0xc4, 0xde, 0x71, 0xc1, 0x70, 0x2f, 0xda, 0x22, 0xd6, + 0x09, 0x7c, 0x90, 0x73, 0xa5, 0x28, 0x89, 0x93, 0x4c, 0x8e, 0xa7, 0x2a, 0x1e, 0xcb, 0xb2, 0xfe, + 0xe8, 0xec, 0xdd, 0x66, 0x08, 0x77, 0x5d, 0xa1, 0x47, 0x26, 0xe8, 0xaf, 0x65, 0x5e, 0x74, 0x60, + 0x78, 0xd8, 0xe0, 0x63, 0x43, 0x47, 0x7b, 0x9f, 0x2f, 0x51, 0xe7, 0xc7, 0x25, 0x02, 0x21, 0xba, + 0x5a, 0x3a, 0xe0, 0x7a, 0xe9, 0x80, 0xef, 0x4b, 0x07, 0x5c, 0xac, 0x9c, 0xce, 0xf5, 0xca, 0xe9, + 0x7c, 0x5d, 0x39, 0x9d, 0xf7, 0x3b, 0xcd, 0x36, 0x92, 0xdd, 0x66, 0xc4, 0x67, 0xbf, 0x02, 0x00, + 0x00, 0xff, 0xff, 0x61, 0xf4, 0xaf, 0xf7, 0xf7, 0x02, 0x00, 0x00, +} + +func (this *ValidatorSigningInfo) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*ValidatorSigningInfo) + if !ok { + that2, ok := that.(ValidatorSigningInfo) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !bytes.Equal(this.Address, that1.Address) { + return false + } + if this.StartHeight != that1.StartHeight { + return false + } + if this.IndexOffset != that1.IndexOffset { + return false + } + if !this.JailedUntil.Equal(that1.JailedUntil) { + return false + } + if this.Tombstoned != that1.Tombstoned { + return false + } + if this.MissedBlocksCounter != that1.MissedBlocksCounter { + return false + } + return true +} +func (m *MsgUnjail) 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 *MsgUnjail) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUnjail) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ValidatorAddr) > 0 { + i -= len(m.ValidatorAddr) + copy(dAtA[i:], m.ValidatorAddr) + i = encodeVarintTypes(dAtA, i, uint64(len(m.ValidatorAddr))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ValidatorSigningInfo) 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 *ValidatorSigningInfo) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ValidatorSigningInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.MissedBlocksCounter != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.MissedBlocksCounter)) + i-- + dAtA[i] = 0x30 + } + if m.Tombstoned { + i-- + if m.Tombstoned { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x28 + } + n1, err1 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.JailedUntil, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.JailedUntil):]) + if err1 != nil { + return 0, err1 + } + i -= n1 + i = encodeVarintTypes(dAtA, i, uint64(n1)) + i-- + dAtA[i] = 0x22 + if m.IndexOffset != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.IndexOffset)) + i-- + dAtA[i] = 0x18 + } + if m.StartHeight != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.StartHeight)) + i-- + dAtA[i] = 0x10 + } + if len(m.Address) > 0 { + i -= len(m.Address) + copy(dAtA[i:], m.Address) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Address))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintTypes(dAtA []byte, offset int, v uint64) int { + offset -= sovTypes(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgUnjail) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ValidatorAddr) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + +func (m *ValidatorSigningInfo) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Address) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + if m.StartHeight != 0 { + n += 1 + sovTypes(uint64(m.StartHeight)) + } + if m.IndexOffset != 0 { + n += 1 + sovTypes(uint64(m.IndexOffset)) + } + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.JailedUntil) + n += 1 + l + sovTypes(uint64(l)) + if m.Tombstoned { + n += 2 + } + if m.MissedBlocksCounter != 0 { + n += 1 + sovTypes(uint64(m.MissedBlocksCounter)) + } + return n +} + +func sovTypes(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTypes(x uint64) (n int) { + return sovTypes(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *MsgUnjail) 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 ErrIntOverflowTypes + } + 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: MsgUnjail: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUnjail: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ValidatorAddr", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ValidatorAddr = append(m.ValidatorAddr[:0], dAtA[iNdEx:postIndex]...) + if m.ValidatorAddr == nil { + m.ValidatorAddr = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ValidatorSigningInfo) 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 ErrIntOverflowTypes + } + 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: ValidatorSigningInfo: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ValidatorSigningInfo: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Address = append(m.Address[:0], dAtA[iNdEx:postIndex]...) + if m.Address == nil { + m.Address = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field StartHeight", wireType) + } + m.StartHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.StartHeight |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field IndexOffset", wireType) + } + m.IndexOffset = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.IndexOffset |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field JailedUntil", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.JailedUntil, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Tombstoned", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Tombstoned = bool(v != 0) + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MissedBlocksCounter", wireType) + } + m.MissedBlocksCounter = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MissedBlocksCounter |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTypes(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthTypes + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTypes + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTypes + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTypes = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTypes = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTypes = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/slashing/types/types.proto b/x/slashing/types/types.proto new file mode 100644 index 000000000000..9aafe07c3bf3 --- /dev/null +++ b/x/slashing/types/types.proto @@ -0,0 +1,35 @@ +syntax = "proto3"; +package cosmos_sdk.x.slashing.v1; + +option go_package = "github.com/cosmos/cosmos-sdk/x/slashing/types"; + +import "third_party/proto/gogoproto/gogo.proto"; +import "google/protobuf/timestamp.proto"; + +// MsgUnjail - struct for unjailing jailed validator +message MsgUnjail { + bytes validator_addr = 1 [ + (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.ValAddress", + (gogoproto.moretags) = "yaml:\"address\"", + (gogoproto.jsontag) = "address" + ]; +} + +// ValidatorSigningInfo defines the signing info for a validator +message ValidatorSigningInfo { + option (gogoproto.equal) = true; + option (gogoproto.goproto_stringer) = false; + + bytes address = 1 [ + (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.ConsAddress" // validator consensus address + ]; + int64 start_height = 2 [(gogoproto.moretags) = "yaml:\"start_height\""]; // height at which validator was first a candidate OR was unjailed + int64 index_offset = 3 [(gogoproto.moretags) = "yaml:\"index_offset\""]; // index offset into signed block bit array + google.protobuf.Timestamp jailed_until = 4 [ + (gogoproto.moretags) = "yaml:\"jailed_until\"", + (gogoproto.stdtime) = true, + (gogoproto.nullable) = false + ]; // timestamp validator cannot be unjailed until + bool tombstoned = 5; // whether or not a validator has been tombstoned (killed out of validator set) + int64 missed_blocks_counter = 6 [(gogoproto.moretags) = "yaml:\"missed_blocks_counter\""]; // missed blocks counter (to avoid scanning the array every time) +} \ No newline at end of file From b54d07e5ce287d8b9f71dedc7337561ed796ba3c Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 20 Feb 2020 11:16:41 +0100 Subject: [PATCH 158/529] Merge PR #5680: Bump github.com/stretchr/testify from 1.5.0 to 1.5.1 Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.5.0 to 1.5.1. - [Release notes](https://github.com/stretchr/testify/releases) - [Commits](https://github.com/stretchr/testify/compare/v1.5.0...v1.5.1) Signed-off-by: dependabot-preview[bot] --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 54dc76100f07..ace0be09309c 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.6.2 - github.com/stretchr/testify v1.5.0 + github.com/stretchr/testify v1.5.1 github.com/tendermint/btcd v0.1.1 github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 github.com/tendermint/go-amino v0.15.1 diff --git a/go.sum b/go.sum index a0e82c697eff..7e0165233f77 100644 --- a/go.sum +++ b/go.sum @@ -239,6 +239,8 @@ github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJy github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.0 h1:DMOzIV76tmoDNE9pX6RSN0aDtCYeCg5VueieJaAo1uw= github.com/stretchr/testify v1.5.0/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d h1:gZZadD8H+fF+n9CmNhYL1Y0dJB+kLOmKd7FbPJLeGHs= From 32b40fdb27b0bbbce2f5955b0b2cc522bc53388f Mon Sep 17 00:00:00 2001 From: Marko Date: Thu, 20 Feb 2020 11:38:07 +0100 Subject: [PATCH 159/529] Merge PR #5669: proto: update tendermint proto files --- Makefile | 56 ++-- third_party/proto/gogoproto/gogo.proto | 2 +- .../proto/tendermint/abci/types/types.proto | 240 +++++++++--------- .../tendermint/crypto/merkle/merkle.proto | 14 +- .../proto/tendermint/libs/kv/types.proto | 20 +- 5 files changed, 173 insertions(+), 159 deletions(-) diff --git a/Makefile b/Makefile index 2cf897fe985a..96f04d16a8f6 100644 --- a/Makefile +++ b/Makefile @@ -238,25 +238,37 @@ proto-lint: proto-check-breaking: @buf check breaking --against-input '.git#branch=master' -# Origin -# TODO: Update to the version of Tendermint that is being used in go.mod -version_branch = v0.33.0 -tendermint = https://raw.githubusercontent.com/tendermint/tendermint/$(version_branch) - -# Outputs -tmkv = third_party/proto/tendermint/libs/kv/types.proto -tmmerkle = third_party/proto/tendermint/crypto/merkle/merkle.proto -tmabci = third_party/proto/tendermint/abci/types/types.proto - -# You *only* need to run this to rebuild protobufs from the tendermint source -proto-update-tendermint: - @curl $(tendermint)/abci/types/types.proto > $(tmabci) - sed -i '' '8,9 s|github.com/tendermint|third_party/proto|g' $(tmabci) - sed -i '' '7 s|github.com/gogo/protobuf|third_party/proto|' $(tmabci) - @curl $(tendermint)/libs/kv/types.proto > $(tmkv) - sed -i '' 's|github.com/gogo/protobuf|third_party/proto|' $(tmkv) - @curl $(tendermint)/crypto/merkle/merkle.proto > $(tmmerkle) - sed -i '' '7 s|github.com/gogo/protobuf|third_party/proto|' $(tmmerkle) - - -.PHONY: proto-all proto-gen proto-lint proto-check-breaking proto-update-tendermint +TM_URL = https://raw.githubusercontent.com/tendermint/tendermint/v0.33.1 +GOGO_PROTO_URL = https://raw.githubusercontent.com/regen-network/protobuf/cosmos +COSMOS_PROTO_URL = https://raw.githubusercontent.com/regen-network/cosmos-proto/master + +TM_KV_TYPES = third_party/proto/tendermint/libs/kv +TM_MERKLE_TYPES = third_party/proto/tendermint/crypto/merkle +TM_ABCI_TYPES = third_party/proto/tendermint/abci/types +GOGO_PROTO_TYPES = third_party/proto/gogoproto +COSMOS_PROTO_TYPES = third_party/proto/cosmos-proto +SDK_PROTO_TYPES = third_party/proto/cosmos-sdk/types +AUTH_PROTO_TYPES = third_party/proto/cosmos-sdk/x/auth/types +VESTING_PROTO_TYPES = third_party/proto/cosmos-sdk/x/auth/vesting/types +SUPPLY_PROTO_TYPES = third_party/proto/cosmos-sdk/x/supply/types + +proto-update-deps: + @mkdir -p $(GOGO_PROTO_TYPES) + @curl -sSL $(GOGO_PROTO_URL)/gogoproto/gogo.proto > $(GOGO_PROTO_TYPES)/gogo.proto + + @mkdir -p $(COSMOS_PROTO_TYPES) + @curl -sSL $(COSMOS_PROTO_URL)/cosmos.proto > $(COSMOS_PROTO_TYPES)/cosmos.proto + + @mkdir -p $(TM_ABCI_TYPES) + @curl -sSL $(TM_URL)/abci/types/types.proto > $(TM_ABCI_TYPES)/types.proto + @sed -i '' '8 s|crypto/merkle/merkle.proto|third_party/proto/tendermint/crypto/merkle/merkle.proto|g' $(TM_ABCI_TYPES)/types.proto + @sed -i '' '9 s|libs/kv/types.proto|third_party/proto/tendermint/libs/kv/types.proto|g' $(TM_ABCI_TYPES)/types.proto + + @mkdir -p $(TM_KV_TYPES) + @curl -sSL $(TM_URL)/libs/kv/types.proto > $(TM_KV_TYPES)/types.proto + + @mkdir -p $(TM_MERKLE_TYPES) + @curl -sSL $(TM_URL)/crypto/merkle/merkle.proto > $(TM_MERKLE_TYPES)/merkle.proto + + +.PHONY: proto-all proto-gen proto-lint proto-check-breaking proto-update-deps diff --git a/third_party/proto/gogoproto/gogo.proto b/third_party/proto/gogoproto/gogo.proto index 588291f0ec20..49e78f99fe57 100644 --- a/third_party/proto/gogoproto/gogo.proto +++ b/third_party/proto/gogoproto/gogo.proto @@ -142,4 +142,4 @@ extend google.protobuf.FieldOptions { optional bool wktpointer = 65012; optional string castrepeated = 65013; -} \ No newline at end of file +} diff --git a/third_party/proto/tendermint/abci/types/types.proto b/third_party/proto/tendermint/abci/types/types.proto index 6c65444b0755..7fb4b1bdb703 100644 --- a/third_party/proto/tendermint/abci/types/types.proto +++ b/third_party/proto/tendermint/abci/types/types.proto @@ -1,6 +1,6 @@ syntax = "proto3"; package tendermint.abci.types; -option go_package = "github.com/tendermint/tendermint/abci/types"; +option go_package = "github.com/tendermint/tendermint/abci/types"; // For more information on gogo.proto, see: // https://github.com/gogo/protobuf/blob/master/extensions.md @@ -14,31 +14,31 @@ import "google/protobuf/duration.proto"; // NOTE: When using custom types, mind the warnings. // https://github.com/gogo/protobuf/blob/master/custom_types.md#warnings-and-issues -option (gogoproto.marshaler_all) = true; -option (gogoproto.unmarshaler_all) = true; -option (gogoproto.sizer_all) = true; +option (gogoproto.marshaler_all) = true; +option (gogoproto.unmarshaler_all) = true; +option (gogoproto.sizer_all) = true; option (gogoproto.goproto_registration) = true; // Generate tests option (gogoproto.populate_all) = true; -option (gogoproto.equal_all) = true; -option (gogoproto.testgen_all) = true; +option (gogoproto.equal_all) = true; +option (gogoproto.testgen_all) = true; //---------------------------------------- // Request types message Request { oneof value { - RequestEcho echo = 2; - RequestFlush flush = 3; - RequestInfo info = 4; - RequestSetOption set_option = 5; - RequestInitChain init_chain = 6; - RequestQuery query = 7; + RequestEcho echo = 2; + RequestFlush flush = 3; + RequestInfo info = 4; + RequestSetOption set_option = 5; + RequestInitChain init_chain = 6; + RequestQuery query = 7; RequestBeginBlock begin_block = 8; - RequestCheckTx check_tx = 9; - RequestDeliverTx deliver_tx = 19; - RequestEndBlock end_block = 11; - RequestCommit commit = 12; + RequestCheckTx check_tx = 9; + RequestDeliverTx deliver_tx = 19; + RequestEndBlock end_block = 11; + RequestCommit commit = 12; } } @@ -46,50 +46,49 @@ message RequestEcho { string message = 1; } -message RequestFlush { -} +message RequestFlush {} message RequestInfo { - string version = 1; + string version = 1; uint64 block_version = 2; - uint64 p2p_version = 3; + uint64 p2p_version = 3; } // nondeterministic message RequestSetOption { - string key = 1; + string key = 1; string value = 2; } message RequestInitChain { - google.protobuf.Timestamp time = 1 [(gogoproto.nullable)=false, (gogoproto.stdtime)=true]; - string chain_id = 2; - ConsensusParams consensus_params = 3; - repeated ValidatorUpdate validators = 4 [(gogoproto.nullable)=false]; - bytes app_state_bytes = 5; + google.protobuf.Timestamp time = 1 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; + string chain_id = 2; + ConsensusParams consensus_params = 3; + repeated ValidatorUpdate validators = 4 [(gogoproto.nullable) = false]; + bytes app_state_bytes = 5; } message RequestQuery { - bytes data = 1; - string path = 2; - int64 height = 3; - bool prove = 4; + bytes data = 1; + string path = 2; + int64 height = 3; + bool prove = 4; } message RequestBeginBlock { - bytes hash = 1; - Header header = 2 [(gogoproto.nullable)=false]; - LastCommitInfo last_commit_info = 3 [(gogoproto.nullable)=false]; - repeated Evidence byzantine_validators = 4 [(gogoproto.nullable)=false]; + bytes hash = 1; + Header header = 2 [(gogoproto.nullable) = false]; + LastCommitInfo last_commit_info = 3 [(gogoproto.nullable) = false]; + repeated Evidence byzantine_validators = 4 [(gogoproto.nullable) = false]; } enum CheckTxType { - New = 0; + New = 0; Recheck = 1; } message RequestCheckTx { - bytes tx = 1; + bytes tx = 1; CheckTxType type = 2; } @@ -101,26 +100,25 @@ message RequestEndBlock { int64 height = 1; } -message RequestCommit { -} +message RequestCommit {} //---------------------------------------- // Response types message Response { oneof value { - ResponseException exception = 1; - ResponseEcho echo = 2; - ResponseFlush flush = 3; - ResponseInfo info = 4; - ResponseSetOption set_option = 5; - ResponseInitChain init_chain = 6; - ResponseQuery query = 7; + ResponseException exception = 1; + ResponseEcho echo = 2; + ResponseFlush flush = 3; + ResponseInfo info = 4; + ResponseSetOption set_option = 5; + ResponseInitChain init_chain = 6; + ResponseQuery query = 7; ResponseBeginBlock begin_block = 8; - ResponseCheckTx check_tx = 9; - ResponseDeliverTx deliver_tx = 10; - ResponseEndBlock end_block = 11; - ResponseCommit commit = 12; + ResponseCheckTx check_tx = 9; + ResponseDeliverTx deliver_tx = 10; + ResponseEndBlock end_block = 11; + ResponseCommit commit = 12; } } @@ -133,16 +131,15 @@ message ResponseEcho { string message = 1; } -message ResponseFlush { -} +message ResponseFlush {} message ResponseInfo { string data = 1; - string version = 2; + string version = 2; uint64 app_version = 3; - int64 last_block_height = 4; + int64 last_block_height = 4; bytes last_block_app_hash = 5; } @@ -150,58 +147,62 @@ message ResponseInfo { message ResponseSetOption { uint32 code = 1; // bytes data = 2; - string log = 3; + string log = 3; string info = 4; } message ResponseInitChain { - ConsensusParams consensus_params = 1; - repeated ValidatorUpdate validators = 2 [(gogoproto.nullable)=false]; + ConsensusParams consensus_params = 1; + repeated ValidatorUpdate validators = 2 [(gogoproto.nullable) = false]; } message ResponseQuery { uint32 code = 1; // bytes data = 2; // use "value" instead. - string log = 3; // nondeterministic - string info = 4; // nondeterministic - int64 index = 5; - bytes key = 6; - bytes value = 7; - tendermint.crypto.merkle.Proof proof = 8; - int64 height = 9; - string codespace = 10; + string log = 3; // nondeterministic + string info = 4; // nondeterministic + int64 index = 5; + bytes key = 6; + bytes value = 7; + tendermint.crypto.merkle.Proof proof = 8; + int64 height = 9; + string codespace = 10; } message ResponseBeginBlock { - repeated Event events = 1 [(gogoproto.nullable)=false, (gogoproto.jsontag)="events,omitempty"]; + repeated Event events = 1 + [(gogoproto.nullable) = false, (gogoproto.jsontag) = "events,omitempty"]; } message ResponseCheckTx { - uint32 code = 1; - bytes data = 2; - string log = 3; // nondeterministic - string info = 4; // nondeterministic - int64 gas_wanted = 5; - int64 gas_used = 6; - repeated Event events = 7 [(gogoproto.nullable)=false, (gogoproto.jsontag)="events,omitempty"]; + uint32 code = 1; + bytes data = 2; + string log = 3; // nondeterministic + string info = 4; // nondeterministic + int64 gas_wanted = 5; + int64 gas_used = 6; + repeated Event events = 7 + [(gogoproto.nullable) = false, (gogoproto.jsontag) = "events,omitempty"]; string codespace = 8; } message ResponseDeliverTx { - uint32 code = 1; - bytes data = 2; - string log = 3; // nondeterministic - string info = 4; // nondeterministic - int64 gas_wanted = 5; - int64 gas_used = 6; - repeated Event events = 7 [(gogoproto.nullable)=false, (gogoproto.jsontag)="events,omitempty"]; + uint32 code = 1; + bytes data = 2; + string log = 3; // nondeterministic + string info = 4; // nondeterministic + int64 gas_wanted = 5; + int64 gas_used = 6; + repeated Event events = 7 + [(gogoproto.nullable) = false, (gogoproto.jsontag) = "events,omitempty"]; string codespace = 8; } message ResponseEndBlock { - repeated ValidatorUpdate validator_updates = 1 [(gogoproto.nullable)=false]; - ConsensusParams consensus_param_updates = 2; - repeated Event events = 3 [(gogoproto.nullable)=false, (gogoproto.jsontag)="events,omitempty"]; + repeated ValidatorUpdate validator_updates = 1 [(gogoproto.nullable) = false]; + ConsensusParams consensus_param_updates = 2; + repeated Event events = 3 + [(gogoproto.nullable) = false, (gogoproto.jsontag) = "events,omitempty"]; } message ResponseCommit { @@ -215,8 +216,8 @@ message ResponseCommit { // ConsensusParams contains all consensus-relevant parameters // that can be adjusted by the abci app message ConsensusParams { - BlockParams block = 1; - EvidenceParams evidence = 2; + BlockParams block = 1; + EvidenceParams evidence = 2; ValidatorParams validator = 3; } @@ -230,8 +231,9 @@ message BlockParams { message EvidenceParams { // Note: must be greater than 0 - int64 max_age_num_blocks = 1; - google.protobuf.Duration max_age_duration = 2 [(gogoproto.nullable)=false, (gogoproto.stdduration)=true]; + int64 max_age_num_blocks = 1; + google.protobuf.Duration max_age_duration = 2 + [(gogoproto.nullable) = false, (gogoproto.stdduration) = true]; } // ValidatorParams contains limits on validators. @@ -240,13 +242,14 @@ message ValidatorParams { } message LastCommitInfo { - int32 round = 1; - repeated VoteInfo votes = 2 [(gogoproto.nullable)=false]; + int32 round = 1; + repeated VoteInfo votes = 2 [(gogoproto.nullable) = false]; } message Event { - string type = 1; - repeated tendermint.libs.kv.Pair attributes = 2 [(gogoproto.nullable)=false, (gogoproto.jsontag)="attributes,omitempty"]; + string type = 1; + repeated tendermint.libs.kv.Pair attributes = 2 + [(gogoproto.nullable) = false, (gogoproto.jsontag) = "attributes,omitempty"]; } //---------------------------------------- @@ -254,63 +257,62 @@ message Event { message Header { // basic block info - Version version = 1 [(gogoproto.nullable)=false]; - string chain_id = 2 [(gogoproto.customname)="ChainID"]; - int64 height = 3; - google.protobuf.Timestamp time = 4 [(gogoproto.nullable)=false, (gogoproto.stdtime)=true]; + Version version = 1 [(gogoproto.nullable) = false]; + string chain_id = 2 [(gogoproto.customname) = "ChainID"]; + int64 height = 3; + google.protobuf.Timestamp time = 4 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; // prev block info - BlockID last_block_id = 5 [(gogoproto.nullable)=false]; + BlockID last_block_id = 5 [(gogoproto.nullable) = false]; // hashes of block data - bytes last_commit_hash = 6; // commit from validators from the last block - bytes data_hash = 7; // transactions + bytes last_commit_hash = 6; // commit from validators from the last block + bytes data_hash = 7; // transactions // hashes from the app output from the prev block - bytes validators_hash = 8; // validators for the current block + bytes validators_hash = 8; // validators for the current block bytes next_validators_hash = 9; // validators for the next block - bytes consensus_hash = 10; // consensus params for current block - bytes app_hash = 11; // state after txs from the previous block - bytes last_results_hash = 12;// root hash of all results from the txs from the previous block + bytes consensus_hash = 10; // consensus params for current block + bytes app_hash = 11; // state after txs from the previous block + bytes last_results_hash = 12; // root hash of all results from the txs from the previous block // consensus info - bytes evidence_hash = 13; // evidence included in the block - bytes proposer_address = 14; // original proposer of the block + bytes evidence_hash = 13; // evidence included in the block + bytes proposer_address = 14; // original proposer of the block } message Version { uint64 Block = 1; - uint64 App = 2; + uint64 App = 2; } - message BlockID { - bytes hash = 1; - PartSetHeader parts_header = 2 [(gogoproto.nullable)=false]; + bytes hash = 1; + PartSetHeader parts_header = 2 [(gogoproto.nullable) = false]; } message PartSetHeader { int32 total = 1; - bytes hash = 2; + bytes hash = 2; } // Validator message Validator { bytes address = 1; - //PubKey pub_key = 2 [(gogoproto.nullable)=false]; + // PubKey pub_key = 2 [(gogoproto.nullable)=false]; int64 power = 3; } // ValidatorUpdate message ValidatorUpdate { - PubKey pub_key = 1 [(gogoproto.nullable)=false]; - int64 power = 2; + PubKey pub_key = 1 [(gogoproto.nullable) = false]; + int64 power = 2; } // VoteInfo message VoteInfo { - Validator validator = 1 [(gogoproto.nullable)=false]; - bool signed_last_block = 2; + Validator validator = 1 [(gogoproto.nullable) = false]; + bool signed_last_block = 2; } message PubKey { @@ -319,18 +321,18 @@ message PubKey { } message Evidence { - string type = 1; - Validator validator = 2 [(gogoproto.nullable)=false]; - int64 height = 3; - google.protobuf.Timestamp time = 4 [(gogoproto.nullable)=false, (gogoproto.stdtime)=true]; - int64 total_voting_power = 5; + string type = 1; + Validator validator = 2 [(gogoproto.nullable) = false]; + int64 height = 3; + google.protobuf.Timestamp time = 4 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; + int64 total_voting_power = 5; } //---------------------------------------- // Service Definition service ABCIApplication { - rpc Echo(RequestEcho) returns (ResponseEcho) ; + rpc Echo(RequestEcho) returns (ResponseEcho); rpc Flush(RequestFlush) returns (ResponseFlush); rpc Info(RequestInfo) returns (ResponseInfo); rpc SetOption(RequestSetOption) returns (ResponseSetOption); diff --git a/third_party/proto/tendermint/crypto/merkle/merkle.proto b/third_party/proto/tendermint/crypto/merkle/merkle.proto index 9dbb2be074e8..159fc58c98dd 100644 --- a/third_party/proto/tendermint/crypto/merkle/merkle.proto +++ b/third_party/proto/tendermint/crypto/merkle/merkle.proto @@ -1,17 +1,17 @@ syntax = "proto3"; package tendermint.crypto.merkle; -option go_package = "github.com/tendermint/tendermint/crypto/merkle"; +option go_package = "github.com/tendermint/tendermint/crypto/merkle"; // For more information on gogo.proto, see: // https://github.com/gogo/protobuf/blob/master/extensions.md import "third_party/proto/gogoproto/gogo.proto"; -option (gogoproto.marshaler_all) = true; +option (gogoproto.marshaler_all) = true; option (gogoproto.unmarshaler_all) = true; -option (gogoproto.sizer_all) = true; +option (gogoproto.sizer_all) = true; option (gogoproto.populate_all) = true; -option (gogoproto.equal_all) = true; +option (gogoproto.equal_all) = true; //---------------------------------------- // Message types @@ -21,11 +21,11 @@ option (gogoproto.equal_all) = true; // for example neighbouring node hash message ProofOp { string type = 1; - bytes key = 2; - bytes data = 3; + bytes key = 2; + bytes data = 3; } // Proof is Merkle proof defined by the list of ProofOps message Proof { - repeated ProofOp ops = 1 [(gogoproto.nullable)=false]; + repeated ProofOp ops = 1 [(gogoproto.nullable) = false]; } diff --git a/third_party/proto/tendermint/libs/kv/types.proto b/third_party/proto/tendermint/libs/kv/types.proto index 247022798347..7e1375c21aba 100644 --- a/third_party/proto/tendermint/libs/kv/types.proto +++ b/third_party/proto/tendermint/libs/kv/types.proto @@ -1,29 +1,29 @@ syntax = "proto3"; package tendermint.libs.kv; -option go_package = "github.com/tendermint/tendermint/libs/kv"; +option go_package = "github.com/tendermint/tendermint/libs/kv"; import "third_party/proto/gogoproto/gogo.proto"; -option (gogoproto.marshaler_all) = true; -option (gogoproto.unmarshaler_all) = true; -option (gogoproto.sizer_all) = true; +option (gogoproto.marshaler_all) = true; +option (gogoproto.unmarshaler_all) = true; +option (gogoproto.sizer_all) = true; option (gogoproto.goproto_registration) = true; // Generate tests option (gogoproto.populate_all) = true; -option (gogoproto.equal_all) = true; -option (gogoproto.testgen_all) = true; +option (gogoproto.equal_all) = true; +option (gogoproto.testgen_all) = true; //---------------------------------------- // Abstract types -// Define these here for compatibility but use tmlibs/common.KVPair. +// Define these here for compatibility but use tmlibs/kv.Pair. message Pair { - bytes key = 1; + bytes key = 1; bytes value = 2; } -// Define these here for compatibility but use tmlibs/common.KI64Pair. +// Define these here for compatibility but use tmlibs/kv.KI64Pair. message KI64Pair { - bytes key = 1; + bytes key = 1; int64 value = 2; } From ebbfaf2a47d3e97a4720f643ca21d5a41676cdc0 Mon Sep 17 00:00:00 2001 From: Marko Date: Thu, 20 Feb 2020 15:24:26 +0100 Subject: [PATCH 160/529] Merge PR #5681: proto: migrate bank to hybridcodec --- .codecov.yml | 1 + simapp/app.go | 2 +- x/bank/alias.go | 4 +- x/bank/app_test.go | 2 +- x/bank/client/cli/query.go | 2 +- x/bank/client/cli/tx.go | 2 +- x/bank/client/rest/query.go | 2 +- x/bank/client/rest/tx.go | 2 +- x/bank/handler.go | 4 +- x/bank/internal/types/codec.go | 20 - x/bank/{internal => }/keeper/invariants.go | 2 +- x/bank/{internal => }/keeper/keeper.go | 14 +- x/bank/{internal => }/keeper/keeper_test.go | 2 +- x/bank/{internal => }/keeper/querier.go | 2 +- x/bank/{internal => }/keeper/querier_test.go | 4 +- x/bank/module.go | 4 +- x/bank/simulation/genesis.go | 2 +- x/bank/simulation/operations.go | 4 +- x/bank/simulation/params.go | 2 +- x/bank/types/codec.go | 28 + x/bank/{internal => }/types/errors.go | 0 x/bank/{internal => }/types/events.go | 0 .../{internal => }/types/expected_keepers.go | 0 x/bank/{internal => }/types/genesis.go | 0 x/bank/{internal => }/types/key.go | 0 x/bank/{internal => }/types/key_test.go | 2 +- x/bank/{internal => }/types/msgs.go | 25 - x/bank/{internal => }/types/msgs_test.go | 0 x/bank/{internal => }/types/params.go | 0 x/bank/{internal => }/types/querier.go | 0 x/bank/types/types.pb.go | 1177 +++++++++++++++++ x/bank/types/types.proto | 48 + x/distribution/keeper/test_common.go | 2 +- x/gov/keeper/test_common.go | 2 +- x/slashing/keeper/test_common.go | 2 +- x/slashing/types/types.pb.go | 78 +- x/staking/keeper/test_common.go | 2 +- 37 files changed, 1325 insertions(+), 118 deletions(-) delete mode 100644 x/bank/internal/types/codec.go rename x/bank/{internal => }/keeper/invariants.go (94%) rename x/bank/{internal => }/keeper/keeper.go (97%) rename x/bank/{internal => }/keeper/keeper_test.go (99%) rename x/bank/{internal => }/keeper/querier.go (96%) rename x/bank/{internal => }/keeper/querier_test.go (96%) create mode 100644 x/bank/types/codec.go rename x/bank/{internal => }/types/errors.go (100%) rename x/bank/{internal => }/types/events.go (100%) rename x/bank/{internal => }/types/expected_keepers.go (100%) rename x/bank/{internal => }/types/genesis.go (100%) rename x/bank/{internal => }/types/key.go (100%) rename x/bank/{internal => }/types/key_test.go (91%) rename x/bank/{internal => }/types/msgs.go (84%) rename x/bank/{internal => }/types/msgs_test.go (100%) rename x/bank/{internal => }/types/params.go (100%) rename x/bank/{internal => }/types/querier.go (100%) create mode 100644 x/bank/types/types.pb.go create mode 100644 x/bank/types/types.proto diff --git a/.codecov.yml b/.codecov.yml index 8fd6c94d4ad8..c10133afd9e5 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -47,6 +47,7 @@ ignore: - "*.md" - "*.rst" - "**/*.pb.go" + - "x/**/*.pb.go" - "x/**/test_common.go" - "scripts/" - "contrib" diff --git a/simapp/app.go b/simapp/app.go index 56f5513e2d2b..049f12270837 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -167,7 +167,7 @@ func NewSimApp( appCodec, keys[auth.StoreKey], app.subspaces[auth.ModuleName], auth.ProtoBaseAccount, ) app.BankKeeper = bank.NewBaseKeeper( - app.cdc, keys[bank.StoreKey], app.AccountKeeper, app.subspaces[bank.ModuleName], app.BlacklistedAccAddrs(), + appCodec, keys[bank.StoreKey], app.AccountKeeper, app.subspaces[bank.ModuleName], app.BlacklistedAccAddrs(), ) app.SupplyKeeper = supply.NewKeeper( appCodec, keys[supply.StoreKey], app.AccountKeeper, app.BankKeeper, maccPerms, diff --git a/x/bank/alias.go b/x/bank/alias.go index faa59aa3fd98..9811c9e001ee 100644 --- a/x/bank/alias.go +++ b/x/bank/alias.go @@ -3,8 +3,8 @@ package bank // nolint import ( - "github.com/cosmos/cosmos-sdk/x/bank/internal/keeper" - "github.com/cosmos/cosmos-sdk/x/bank/internal/types" + "github.com/cosmos/cosmos-sdk/x/bank/keeper" + "github.com/cosmos/cosmos-sdk/x/bank/types" ) const ( diff --git a/x/bank/app_test.go b/x/bank/app_test.go index 46a33d3f62f6..4a36d2d8af77 100644 --- a/x/bank/app_test.go +++ b/x/bank/app_test.go @@ -16,7 +16,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" - "github.com/cosmos/cosmos-sdk/x/bank/internal/types" + "github.com/cosmos/cosmos-sdk/x/bank/types" ) type ( diff --git a/x/bank/client/cli/query.go b/x/bank/client/cli/query.go index 046e84051448..e7327a091eb4 100644 --- a/x/bank/client/cli/query.go +++ b/x/bank/client/cli/query.go @@ -11,7 +11,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/bank/internal/types" + "github.com/cosmos/cosmos-sdk/x/bank/types" ) const ( diff --git a/x/bank/client/cli/tx.go b/x/bank/client/cli/tx.go index b2b36c45dbe7..0764045968a7 100644 --- a/x/bank/client/cli/tx.go +++ b/x/bank/client/cli/tx.go @@ -12,7 +12,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" authclient "github.com/cosmos/cosmos-sdk/x/auth/client" - "github.com/cosmos/cosmos-sdk/x/bank/internal/types" + "github.com/cosmos/cosmos-sdk/x/bank/types" ) // GetTxCmd returns the transaction commands for this module diff --git a/x/bank/client/rest/query.go b/x/bank/client/rest/query.go index eb1f3463b7a6..99b3680bbb16 100644 --- a/x/bank/client/rest/query.go +++ b/x/bank/client/rest/query.go @@ -9,7 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/rest" - "github.com/cosmos/cosmos-sdk/x/bank/internal/types" + "github.com/cosmos/cosmos-sdk/x/bank/types" ) // QueryBalancesRequestHandlerFn returns a REST handler that queries for all diff --git a/x/bank/client/rest/tx.go b/x/bank/client/rest/tx.go index 52fa9f25136b..30178166bb5f 100644 --- a/x/bank/client/rest/tx.go +++ b/x/bank/client/rest/tx.go @@ -9,7 +9,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/rest" authclient "github.com/cosmos/cosmos-sdk/x/auth/client" - "github.com/cosmos/cosmos-sdk/x/bank/internal/types" + "github.com/cosmos/cosmos-sdk/x/bank/types" ) // SendReq defines the properties of a send request's body. diff --git a/x/bank/handler.go b/x/bank/handler.go index 3c83ec4c2af4..30341ab47b57 100644 --- a/x/bank/handler.go +++ b/x/bank/handler.go @@ -3,8 +3,8 @@ package bank import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/cosmos-sdk/x/bank/internal/keeper" - "github.com/cosmos/cosmos-sdk/x/bank/internal/types" + "github.com/cosmos/cosmos-sdk/x/bank/keeper" + "github.com/cosmos/cosmos-sdk/x/bank/types" ) // NewHandler returns a handler for "bank" type messages. diff --git a/x/bank/internal/types/codec.go b/x/bank/internal/types/codec.go deleted file mode 100644 index 6d4d49adc118..000000000000 --- a/x/bank/internal/types/codec.go +++ /dev/null @@ -1,20 +0,0 @@ -package types - -import ( - "github.com/cosmos/cosmos-sdk/codec" -) - -// Register concrete types on codec codec -func RegisterCodec(cdc *codec.Codec) { - cdc.RegisterConcrete(MsgSend{}, "cosmos-sdk/MsgSend", nil) - cdc.RegisterConcrete(MsgMultiSend{}, "cosmos-sdk/MsgMultiSend", nil) -} - -// module codec -var ModuleCdc *codec.Codec - -func init() { - ModuleCdc = codec.New() - RegisterCodec(ModuleCdc) - ModuleCdc.Seal() -} diff --git a/x/bank/internal/keeper/invariants.go b/x/bank/keeper/invariants.go similarity index 94% rename from x/bank/internal/keeper/invariants.go rename to x/bank/keeper/invariants.go index 65730451261b..3833c034d3df 100644 --- a/x/bank/internal/keeper/invariants.go +++ b/x/bank/keeper/invariants.go @@ -4,7 +4,7 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/bank/internal/types" + "github.com/cosmos/cosmos-sdk/x/bank/types" ) // RegisterInvariants registers the bank module invariants diff --git a/x/bank/internal/keeper/keeper.go b/x/bank/keeper/keeper.go similarity index 97% rename from x/bank/internal/keeper/keeper.go rename to x/bank/keeper/keeper.go index 1475a85cfb92..b1b2bdfa7a4e 100644 --- a/x/bank/internal/keeper/keeper.go +++ b/x/bank/keeper/keeper.go @@ -11,7 +11,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" vestexported "github.com/cosmos/cosmos-sdk/x/auth/vesting/exported" - "github.com/cosmos/cosmos-sdk/x/bank/internal/types" + "github.com/cosmos/cosmos-sdk/x/bank/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" ) @@ -35,7 +35,7 @@ type BaseKeeper struct { } func NewBaseKeeper( - cdc *codec.Codec, storeKey sdk.StoreKey, ak types.AccountKeeper, paramSpace paramtypes.Subspace, blacklistedAddrs map[string]bool, + cdc codec.Marshaler, storeKey sdk.StoreKey, ak types.AccountKeeper, paramSpace paramtypes.Subspace, blacklistedAddrs map[string]bool, ) BaseKeeper { ps := paramSpace.WithKeyTable(types.ParamKeyTable()) @@ -146,7 +146,7 @@ var _ SendKeeper = (*BaseSendKeeper)(nil) type BaseSendKeeper struct { BaseViewKeeper - cdc *codec.Codec + cdc codec.Marshaler ak types.AccountKeeper storeKey sdk.StoreKey paramSpace paramtypes.Subspace @@ -156,7 +156,7 @@ type BaseSendKeeper struct { } func NewBaseSendKeeper( - cdc *codec.Codec, storeKey sdk.StoreKey, ak types.AccountKeeper, paramSpace paramtypes.Subspace, blacklistedAddrs map[string]bool, + cdc codec.Marshaler, storeKey sdk.StoreKey, ak types.AccountKeeper, paramSpace paramtypes.Subspace, blacklistedAddrs map[string]bool, ) BaseSendKeeper { return BaseSendKeeper{ @@ -341,7 +341,7 @@ func (k BaseSendKeeper) SetBalance(ctx sdk.Context, addr sdk.AccAddress, balance balancesStore := prefix.NewStore(store, types.BalancesPrefix) accountStore := prefix.NewStore(balancesStore, addr.Bytes()) - bz := k.cdc.MustMarshalBinaryBare(balance) + bz := k.cdc.MustMarshalBinaryBare(&balance) accountStore.Set([]byte(balance.Denom), bz) return nil @@ -385,13 +385,13 @@ type ViewKeeper interface { // BaseViewKeeper implements a read only keeper implementation of ViewKeeper. type BaseViewKeeper struct { - cdc *codec.Codec + cdc codec.Marshaler storeKey sdk.StoreKey ak types.AccountKeeper } // NewBaseViewKeeper returns a new BaseViewKeeper. -func NewBaseViewKeeper(cdc *codec.Codec, storeKey sdk.StoreKey, ak types.AccountKeeper) BaseViewKeeper { +func NewBaseViewKeeper(cdc codec.Marshaler, storeKey sdk.StoreKey, ak types.AccountKeeper) BaseViewKeeper { return BaseViewKeeper{ cdc: cdc, storeKey: storeKey, diff --git a/x/bank/internal/keeper/keeper_test.go b/x/bank/keeper/keeper_test.go similarity index 99% rename from x/bank/internal/keeper/keeper_test.go rename to x/bank/keeper/keeper_test.go index d71f1274f1d2..472fe39972d5 100644 --- a/x/bank/internal/keeper/keeper_test.go +++ b/x/bank/keeper/keeper_test.go @@ -13,7 +13,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/auth/vesting" - "github.com/cosmos/cosmos-sdk/x/bank/internal/types" + "github.com/cosmos/cosmos-sdk/x/bank/types" ) const ( diff --git a/x/bank/internal/keeper/querier.go b/x/bank/keeper/querier.go similarity index 96% rename from x/bank/internal/keeper/querier.go rename to x/bank/keeper/querier.go index 072511b2d2a8..be17b371629a 100644 --- a/x/bank/internal/keeper/querier.go +++ b/x/bank/keeper/querier.go @@ -6,7 +6,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/cosmos-sdk/x/bank/internal/types" + "github.com/cosmos/cosmos-sdk/x/bank/types" ) // NewQuerier returns a new sdk.Keeper instance. diff --git a/x/bank/internal/keeper/querier_test.go b/x/bank/keeper/querier_test.go similarity index 96% rename from x/bank/internal/keeper/querier_test.go rename to x/bank/keeper/querier_test.go index 643f7b1798cf..3732aaa74429 100644 --- a/x/bank/internal/keeper/querier_test.go +++ b/x/bank/keeper/querier_test.go @@ -7,8 +7,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - "github.com/cosmos/cosmos-sdk/x/bank/internal/keeper" - "github.com/cosmos/cosmos-sdk/x/bank/internal/types" + "github.com/cosmos/cosmos-sdk/x/bank/keeper" + "github.com/cosmos/cosmos-sdk/x/bank/types" ) func (suite *IntegrationTestSuite) TestQuerier_QueryBalance() { diff --git a/x/bank/module.go b/x/bank/module.go index dfde67f4a85e..7cb86714272c 100644 --- a/x/bank/module.go +++ b/x/bank/module.go @@ -16,9 +16,9 @@ import ( "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/x/bank/client/cli" "github.com/cosmos/cosmos-sdk/x/bank/client/rest" - "github.com/cosmos/cosmos-sdk/x/bank/internal/keeper" - "github.com/cosmos/cosmos-sdk/x/bank/internal/types" + "github.com/cosmos/cosmos-sdk/x/bank/keeper" "github.com/cosmos/cosmos-sdk/x/bank/simulation" + "github.com/cosmos/cosmos-sdk/x/bank/types" sim "github.com/cosmos/cosmos-sdk/x/simulation" ) diff --git a/x/bank/simulation/genesis.go b/x/bank/simulation/genesis.go index b593fa05b070..97716bd2fa6c 100644 --- a/x/bank/simulation/genesis.go +++ b/x/bank/simulation/genesis.go @@ -7,7 +7,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" - "github.com/cosmos/cosmos-sdk/x/bank/internal/types" + "github.com/cosmos/cosmos-sdk/x/bank/types" ) // Simulation parameter constants diff --git a/x/bank/simulation/operations.go b/x/bank/simulation/operations.go index 2d9e8468359a..c3ff22f9ceed 100644 --- a/x/bank/simulation/operations.go +++ b/x/bank/simulation/operations.go @@ -10,8 +10,8 @@ import ( "github.com/cosmos/cosmos-sdk/simapp/helpers" simappparams "github.com/cosmos/cosmos-sdk/simapp/params" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/bank/internal/keeper" - "github.com/cosmos/cosmos-sdk/x/bank/internal/types" + "github.com/cosmos/cosmos-sdk/x/bank/keeper" + "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/cosmos/cosmos-sdk/x/simulation" ) diff --git a/x/bank/simulation/params.go b/x/bank/simulation/params.go index f5aa25bf6a0c..458a8a09a16e 100644 --- a/x/bank/simulation/params.go +++ b/x/bank/simulation/params.go @@ -6,7 +6,7 @@ import ( "fmt" "math/rand" - "github.com/cosmos/cosmos-sdk/x/bank/internal/types" + "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/cosmos/cosmos-sdk/x/simulation" ) diff --git a/x/bank/types/codec.go b/x/bank/types/codec.go new file mode 100644 index 000000000000..652fb3f2fe23 --- /dev/null +++ b/x/bank/types/codec.go @@ -0,0 +1,28 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" +) + +// Register concrete types on codec codec +func RegisterCodec(cdc *codec.Codec) { + cdc.RegisterConcrete(MsgSend{}, "cosmos-sdk/MsgSend", nil) + cdc.RegisterConcrete(MsgMultiSend{}, "cosmos-sdk/MsgMultiSend", nil) +} + +var ( + amino = codec.New() + + // ModuleCdc references the global x/staking module codec. Note, the codec should + // ONLY be used in certain instances of tests and for JSON encoding as Amino is + // still used for that purpose. + // + // The actual codec used for serialization should be provided to x/staking and + // defined at the application level. + ModuleCdc = codec.NewHybridCodec(amino) +) + +func init() { + RegisterCodec(amino) + amino.Seal() +} diff --git a/x/bank/internal/types/errors.go b/x/bank/types/errors.go similarity index 100% rename from x/bank/internal/types/errors.go rename to x/bank/types/errors.go diff --git a/x/bank/internal/types/events.go b/x/bank/types/events.go similarity index 100% rename from x/bank/internal/types/events.go rename to x/bank/types/events.go diff --git a/x/bank/internal/types/expected_keepers.go b/x/bank/types/expected_keepers.go similarity index 100% rename from x/bank/internal/types/expected_keepers.go rename to x/bank/types/expected_keepers.go diff --git a/x/bank/internal/types/genesis.go b/x/bank/types/genesis.go similarity index 100% rename from x/bank/internal/types/genesis.go rename to x/bank/types/genesis.go diff --git a/x/bank/internal/types/key.go b/x/bank/types/key.go similarity index 100% rename from x/bank/internal/types/key.go rename to x/bank/types/key.go diff --git a/x/bank/internal/types/key_test.go b/x/bank/types/key_test.go similarity index 91% rename from x/bank/internal/types/key_test.go rename to x/bank/types/key_test.go index a16a22381d6e..b1e5a7614106 100644 --- a/x/bank/internal/types/key_test.go +++ b/x/bank/types/key_test.go @@ -4,7 +4,7 @@ import ( "testing" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/bank/internal/types" + "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/stretchr/testify/require" ) diff --git a/x/bank/internal/types/msgs.go b/x/bank/types/msgs.go similarity index 84% rename from x/bank/internal/types/msgs.go rename to x/bank/types/msgs.go index 83db26aaefd1..3dab0c6bb538 100644 --- a/x/bank/internal/types/msgs.go +++ b/x/bank/types/msgs.go @@ -5,13 +5,6 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) -// MsgSend - high level transaction of the coin module -type MsgSend struct { - FromAddress sdk.AccAddress `json:"from_address" yaml:"from_address"` - ToAddress sdk.AccAddress `json:"to_address" yaml:"to_address"` - Amount sdk.Coins `json:"amount" yaml:"amount"` -} - var _ sdk.Msg = MsgSend{} // NewMsgSend - construct arbitrary multi-in, multi-out send msg. @@ -52,12 +45,6 @@ func (msg MsgSend) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.FromAddress} } -// MsgMultiSend - high level transaction of the coin module -type MsgMultiSend struct { - Inputs []Input `json:"inputs" yaml:"inputs"` - Outputs []Output `json:"outputs" yaml:"outputs"` -} - var _ sdk.Msg = MsgMultiSend{} // NewMsgMultiSend - construct arbitrary multi-in, multi-out send msg. @@ -99,12 +86,6 @@ func (msg MsgMultiSend) GetSigners() []sdk.AccAddress { return addrs } -// Input models transaction input -type Input struct { - Address sdk.AccAddress `json:"address" yaml:"address"` - Coins sdk.Coins `json:"coins" yaml:"coins"` -} - // ValidateBasic - validate transaction input func (in Input) ValidateBasic() error { if len(in.Address) == 0 { @@ -127,12 +108,6 @@ func NewInput(addr sdk.AccAddress, coins sdk.Coins) Input { } } -// Output models transaction outputs -type Output struct { - Address sdk.AccAddress `json:"address" yaml:"address"` - Coins sdk.Coins `json:"coins" yaml:"coins"` -} - // ValidateBasic - validate transaction output func (out Output) ValidateBasic() error { if len(out.Address) == 0 { diff --git a/x/bank/internal/types/msgs_test.go b/x/bank/types/msgs_test.go similarity index 100% rename from x/bank/internal/types/msgs_test.go rename to x/bank/types/msgs_test.go diff --git a/x/bank/internal/types/params.go b/x/bank/types/params.go similarity index 100% rename from x/bank/internal/types/params.go rename to x/bank/types/params.go diff --git a/x/bank/internal/types/querier.go b/x/bank/types/querier.go similarity index 100% rename from x/bank/internal/types/querier.go rename to x/bank/types/querier.go diff --git a/x/bank/types/types.pb.go b/x/bank/types/types.pb.go new file mode 100644 index 000000000000..0de721984735 --- /dev/null +++ b/x/bank/types/types.pb.go @@ -0,0 +1,1177 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: x/bank/types/types.proto + +package types + +import ( + fmt "fmt" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// MsgSend - high level transaction of the coin module +type MsgSend struct { + FromAddress github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,1,opt,name=from_address,json=fromAddress,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"from_address,omitempty" yaml:"from_address"` + ToAddress github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,2,opt,name=to_address,json=toAddress,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"to_address,omitempty" yaml:"to_address"` + Amount github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,3,rep,name=amount,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"amount"` +} + +func (m *MsgSend) Reset() { *m = MsgSend{} } +func (m *MsgSend) String() string { return proto.CompactTextString(m) } +func (*MsgSend) ProtoMessage() {} +func (*MsgSend) Descriptor() ([]byte, []int) { + return fileDescriptor_934ff6b24d3432e2, []int{0} +} +func (m *MsgSend) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgSend) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgSend.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 *MsgSend) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgSend.Merge(m, src) +} +func (m *MsgSend) XXX_Size() int { + return m.Size() +} +func (m *MsgSend) XXX_DiscardUnknown() { + xxx_messageInfo_MsgSend.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgSend proto.InternalMessageInfo + +func (m *MsgSend) GetFromAddress() github_com_cosmos_cosmos_sdk_types.AccAddress { + if m != nil { + return m.FromAddress + } + return nil +} + +func (m *MsgSend) GetToAddress() github_com_cosmos_cosmos_sdk_types.AccAddress { + if m != nil { + return m.ToAddress + } + return nil +} + +func (m *MsgSend) GetAmount() github_com_cosmos_cosmos_sdk_types.Coins { + if m != nil { + return m.Amount + } + return nil +} + +// Input models transaction input +type Input struct { + Address github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,1,opt,name=address,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"address,omitempty"` + Coins github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,2,rep,name=coins,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"coins"` +} + +func (m *Input) Reset() { *m = Input{} } +func (m *Input) String() string { return proto.CompactTextString(m) } +func (*Input) ProtoMessage() {} +func (*Input) Descriptor() ([]byte, []int) { + return fileDescriptor_934ff6b24d3432e2, []int{1} +} +func (m *Input) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Input) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Input.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 *Input) XXX_Merge(src proto.Message) { + xxx_messageInfo_Input.Merge(m, src) +} +func (m *Input) XXX_Size() int { + return m.Size() +} +func (m *Input) XXX_DiscardUnknown() { + xxx_messageInfo_Input.DiscardUnknown(m) +} + +var xxx_messageInfo_Input proto.InternalMessageInfo + +func (m *Input) GetAddress() github_com_cosmos_cosmos_sdk_types.AccAddress { + if m != nil { + return m.Address + } + return nil +} + +func (m *Input) GetCoins() github_com_cosmos_cosmos_sdk_types.Coins { + if m != nil { + return m.Coins + } + return nil +} + +// Output models transaction outputs +type Output struct { + Address github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,1,opt,name=address,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"address,omitempty"` + Coins github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,2,rep,name=coins,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"coins"` +} + +func (m *Output) Reset() { *m = Output{} } +func (m *Output) String() string { return proto.CompactTextString(m) } +func (*Output) ProtoMessage() {} +func (*Output) Descriptor() ([]byte, []int) { + return fileDescriptor_934ff6b24d3432e2, []int{2} +} +func (m *Output) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Output) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Output.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 *Output) XXX_Merge(src proto.Message) { + xxx_messageInfo_Output.Merge(m, src) +} +func (m *Output) XXX_Size() int { + return m.Size() +} +func (m *Output) XXX_DiscardUnknown() { + xxx_messageInfo_Output.DiscardUnknown(m) +} + +var xxx_messageInfo_Output proto.InternalMessageInfo + +func (m *Output) GetAddress() github_com_cosmos_cosmos_sdk_types.AccAddress { + if m != nil { + return m.Address + } + return nil +} + +func (m *Output) GetCoins() github_com_cosmos_cosmos_sdk_types.Coins { + if m != nil { + return m.Coins + } + return nil +} + +// MsgMultiSend - high level transaction of the coin module +type MsgMultiSend struct { + Inputs []Input `protobuf:"bytes,1,rep,name=inputs,proto3" json:"inputs"` + Outputs []Output `protobuf:"bytes,2,rep,name=outputs,proto3" json:"outputs"` +} + +func (m *MsgMultiSend) Reset() { *m = MsgMultiSend{} } +func (m *MsgMultiSend) String() string { return proto.CompactTextString(m) } +func (*MsgMultiSend) ProtoMessage() {} +func (*MsgMultiSend) Descriptor() ([]byte, []int) { + return fileDescriptor_934ff6b24d3432e2, []int{3} +} +func (m *MsgMultiSend) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgMultiSend) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgMultiSend.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 *MsgMultiSend) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgMultiSend.Merge(m, src) +} +func (m *MsgMultiSend) XXX_Size() int { + return m.Size() +} +func (m *MsgMultiSend) XXX_DiscardUnknown() { + xxx_messageInfo_MsgMultiSend.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgMultiSend proto.InternalMessageInfo + +func (m *MsgMultiSend) GetInputs() []Input { + if m != nil { + return m.Inputs + } + return nil +} + +func (m *MsgMultiSend) GetOutputs() []Output { + if m != nil { + return m.Outputs + } + return nil +} + +func init() { + proto.RegisterType((*MsgSend)(nil), "cosmos_sdk.x.bank.v1.MsgSend") + proto.RegisterType((*Input)(nil), "cosmos_sdk.x.bank.v1.Input") + proto.RegisterType((*Output)(nil), "cosmos_sdk.x.bank.v1.Output") + proto.RegisterType((*MsgMultiSend)(nil), "cosmos_sdk.x.bank.v1.MsgMultiSend") +} + +func init() { proto.RegisterFile("x/bank/types/types.proto", fileDescriptor_934ff6b24d3432e2) } + +var fileDescriptor_934ff6b24d3432e2 = []byte{ + // 403 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xa8, 0xd0, 0x4f, 0x4a, + 0xcc, 0xcb, 0xd6, 0x2f, 0xa9, 0x2c, 0x48, 0x2d, 0x86, 0x90, 0x7a, 0x05, 0x45, 0xf9, 0x25, 0xf9, + 0x42, 0x22, 0xc9, 0xf9, 0xc5, 0xb9, 0xf9, 0xc5, 0xf1, 0xc5, 0x29, 0xd9, 0x7a, 0x15, 0x7a, 0x20, + 0x45, 0x7a, 0x65, 0x86, 0x52, 0x6a, 0x25, 0x19, 0x99, 0x45, 0x29, 0xf1, 0x05, 0x89, 0x45, 0x25, + 0x95, 0xfa, 0x60, 0x85, 0xfa, 0xe9, 0xf9, 0xe9, 0xf9, 0x08, 0x16, 0x44, 0xb7, 0x94, 0x20, 0x86, + 0x81, 0x4a, 0x7b, 0x98, 0xb8, 0xd8, 0x7d, 0x8b, 0xd3, 0x83, 0x53, 0xf3, 0x52, 0x84, 0xb2, 0xb9, + 0x78, 0xd2, 0x8a, 0xf2, 0x73, 0xe3, 0x13, 0x53, 0x52, 0x8a, 0x52, 0x8b, 0x8b, 0x25, 0x18, 0x15, + 0x18, 0x35, 0x78, 0x9c, 0x3c, 0x3e, 0xdd, 0x93, 0x17, 0xae, 0x4c, 0xcc, 0xcd, 0xb1, 0x52, 0x42, + 0x96, 0x55, 0xfa, 0x75, 0x4f, 0x5e, 0x37, 0x3d, 0xb3, 0x24, 0xa3, 0x34, 0x49, 0x2f, 0x39, 0x3f, + 0x57, 0x1f, 0xe2, 0x30, 0x28, 0xa5, 0x5b, 0x9c, 0x02, 0x75, 0xbd, 0x9e, 0x63, 0x72, 0xb2, 0x23, + 0x44, 0x47, 0x10, 0x37, 0x48, 0x3f, 0x94, 0x23, 0x94, 0xca, 0xc5, 0x55, 0x92, 0x0f, 0xb7, 0x8a, + 0x09, 0x6c, 0x95, 0xdb, 0xa7, 0x7b, 0xf2, 0x82, 0x10, 0xab, 0x10, 0x72, 0x64, 0x58, 0xc4, 0x59, + 0x92, 0x0f, 0xb3, 0x26, 0x96, 0x8b, 0x2d, 0x31, 0x37, 0xbf, 0x34, 0xaf, 0x44, 0x82, 0x59, 0x81, + 0x59, 0x83, 0xdb, 0x48, 0x58, 0x0f, 0x29, 0x04, 0xcb, 0x0c, 0xf5, 0x9c, 0xf3, 0x33, 0xf3, 0x9c, + 0x0c, 0x4e, 0xdc, 0x93, 0x67, 0x58, 0x75, 0x5f, 0x5e, 0x83, 0x08, 0x6b, 0x40, 0x1a, 0x8a, 0x83, + 0xa0, 0x86, 0x2a, 0x6d, 0x64, 0xe4, 0x62, 0xf5, 0xcc, 0x2b, 0x28, 0x2d, 0x11, 0xf2, 0xe6, 0x62, + 0x47, 0x0d, 0x37, 0x43, 0xd2, 0xdd, 0x0d, 0x33, 0x41, 0x28, 0x9a, 0x8b, 0x35, 0x19, 0x64, 0x8f, + 0x04, 0x13, 0x35, 0x1d, 0x0d, 0x31, 0x53, 0x69, 0x13, 0x23, 0x17, 0x9b, 0x7f, 0x69, 0xc9, 0xd0, + 0x72, 0x74, 0x3b, 0x23, 0x17, 0x8f, 0x6f, 0x71, 0xba, 0x6f, 0x69, 0x4e, 0x49, 0x26, 0x38, 0xb1, + 0x5a, 0x72, 0xb1, 0x65, 0x82, 0x02, 0x1e, 0xe4, 0x72, 0x90, 0x75, 0xd2, 0x7a, 0xd8, 0xb2, 0x86, + 0x1e, 0x38, 0x72, 0x9c, 0x58, 0x40, 0xd6, 0x06, 0x41, 0x35, 0x08, 0xd9, 0x70, 0xb1, 0xe7, 0x83, + 0xfd, 0x0f, 0x73, 0xaa, 0x0c, 0x76, 0xbd, 0x90, 0x40, 0x82, 0x6a, 0x86, 0x69, 0x71, 0x72, 0x3e, + 0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39, 0xc6, 0x07, 0x8f, 0xe4, 0x18, 0x27, 0x3c, 0x96, 0x63, + 0xb8, 0xf0, 0x58, 0x8e, 0xe1, 0xc6, 0x63, 0x39, 0x86, 0x28, 0x4d, 0xbc, 0x9e, 0x42, 0xce, 0xd3, + 0x49, 0x6c, 0xe0, 0xdc, 0x67, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0x64, 0xad, 0xc1, 0x15, 0xea, + 0x03, 0x00, 0x00, +} + +func (m *MsgSend) 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 *MsgSend) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgSend) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Amount) > 0 { + for iNdEx := len(m.Amount) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Amount[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.ToAddress) > 0 { + i -= len(m.ToAddress) + copy(dAtA[i:], m.ToAddress) + i = encodeVarintTypes(dAtA, i, uint64(len(m.ToAddress))) + i-- + dAtA[i] = 0x12 + } + if len(m.FromAddress) > 0 { + i -= len(m.FromAddress) + copy(dAtA[i:], m.FromAddress) + i = encodeVarintTypes(dAtA, i, uint64(len(m.FromAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *Input) 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 *Input) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Input) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Coins) > 0 { + for iNdEx := len(m.Coins) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Coins[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.Address) > 0 { + i -= len(m.Address) + copy(dAtA[i:], m.Address) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Address))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *Output) 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 *Output) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Output) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Coins) > 0 { + for iNdEx := len(m.Coins) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Coins[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.Address) > 0 { + i -= len(m.Address) + copy(dAtA[i:], m.Address) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Address))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgMultiSend) 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 *MsgMultiSend) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgMultiSend) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Outputs) > 0 { + for iNdEx := len(m.Outputs) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Outputs[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.Inputs) > 0 { + for iNdEx := len(m.Inputs) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Inputs[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarintTypes(dAtA []byte, offset int, v uint64) int { + offset -= sovTypes(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgSend) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.FromAddress) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.ToAddress) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + if len(m.Amount) > 0 { + for _, e := range m.Amount { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + return n +} + +func (m *Input) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Address) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + if len(m.Coins) > 0 { + for _, e := range m.Coins { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + return n +} + +func (m *Output) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Address) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + if len(m.Coins) > 0 { + for _, e := range m.Coins { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + return n +} + +func (m *MsgMultiSend) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Inputs) > 0 { + for _, e := range m.Inputs { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + if len(m.Outputs) > 0 { + for _, e := range m.Outputs { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + return n +} + +func sovTypes(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTypes(x uint64) (n int) { + return sovTypes(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *MsgSend) 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 ErrIntOverflowTypes + } + 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: MsgSend: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSend: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FromAddress", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.FromAddress = append(m.FromAddress[:0], dAtA[iNdEx:postIndex]...) + if m.FromAddress == nil { + m.FromAddress = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ToAddress", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ToAddress = append(m.ToAddress[:0], dAtA[iNdEx:postIndex]...) + if m.ToAddress == nil { + m.ToAddress = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Amount = append(m.Amount, types.Coin{}) + if err := m.Amount[len(m.Amount)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Input) 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 ErrIntOverflowTypes + } + 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: Input: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Input: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Address = append(m.Address[:0], dAtA[iNdEx:postIndex]...) + if m.Address == nil { + m.Address = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Coins", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Coins = append(m.Coins, types.Coin{}) + if err := m.Coins[len(m.Coins)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Output) 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 ErrIntOverflowTypes + } + 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: Output: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Output: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Address = append(m.Address[:0], dAtA[iNdEx:postIndex]...) + if m.Address == nil { + m.Address = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Coins", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Coins = append(m.Coins, types.Coin{}) + if err := m.Coins[len(m.Coins)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgMultiSend) 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 ErrIntOverflowTypes + } + 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: MsgMultiSend: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgMultiSend: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Inputs", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Inputs = append(m.Inputs, Input{}) + if err := m.Inputs[len(m.Inputs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Outputs", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Outputs = append(m.Outputs, Output{}) + if err := m.Outputs[len(m.Outputs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTypes(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthTypes + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTypes + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTypes + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTypes = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTypes = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTypes = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/bank/types/types.proto b/x/bank/types/types.proto new file mode 100644 index 000000000000..9aee8d22a319 --- /dev/null +++ b/x/bank/types/types.proto @@ -0,0 +1,48 @@ +syntax = "proto3"; + +package cosmos_sdk.x.bank.v1; + +option go_package = "github.com/cosmos/cosmos-sdk/x/bank/types"; + +import "third_party/proto/gogoproto/gogo.proto"; +import "types/types.proto"; + +// MsgSend - high level transaction of the coin module +message MsgSend { + bytes from_address = 1 [ + (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress", + (gogoproto.moretags) = "yaml:\"from_address\"" + ]; + bytes to_address = 2 [ + (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress", + (gogoproto.moretags) = "yaml:\"to_address\"" + ]; + repeated cosmos_sdk.v1.Coin amount = 3 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + ]; +} + +// Input models transaction input +message Input { + bytes address = 1 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; + repeated cosmos_sdk.v1.Coin coins = 2 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + ]; +} + +// Output models transaction outputs +message Output { + bytes address = 1 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; + repeated cosmos_sdk.v1.Coin coins = 2 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + ]; +} + +// MsgMultiSend - high level transaction of the coin module +message MsgMultiSend { + repeated Input inputs = 1 [(gogoproto.nullable) = false]; + repeated Output outputs = 2 [(gogoproto.nullable) = false]; +} diff --git a/x/distribution/keeper/test_common.go b/x/distribution/keeper/test_common.go index a60b36985a4b..0c18e9249525 100644 --- a/x/distribution/keeper/test_common.go +++ b/x/distribution/keeper/test_common.go @@ -132,7 +132,7 @@ func CreateTestInputAdvanced( ctx := sdk.NewContext(ms, abci.Header{ChainID: "foochainid"}, isCheckTx, log.NewNopLogger()) accountKeeper := auth.NewAccountKeeper(appCodec, keyAcc, pk.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount) - bankKeeper := bank.NewBaseKeeper(cdc, keyBank, accountKeeper, pk.Subspace(bank.DefaultParamspace), blacklistedAddrs) + bankKeeper := bank.NewBaseKeeper(appCodec, keyBank, accountKeeper, pk.Subspace(bank.DefaultParamspace), blacklistedAddrs) maccPerms := map[string][]string{ auth.FeeCollectorName: nil, types.ModuleName: nil, diff --git a/x/gov/keeper/test_common.go b/x/gov/keeper/test_common.go index d521b10bef3b..84df63afb549 100644 --- a/x/gov/keeper/test_common.go +++ b/x/gov/keeper/test_common.go @@ -151,7 +151,7 @@ func createTestInput( pk := keeper.NewKeeper(appCodec, keyParams, tkeyParams) accountKeeper := auth.NewAccountKeeper(appCodec, keyAcc, pk.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount) - bankKeeper := bank.NewBaseKeeper(cdc, keyBank, accountKeeper, pk.Subspace(bank.DefaultParamspace), blacklistedAddrs) + bankKeeper := bank.NewBaseKeeper(appCodec, keyBank, accountKeeper, pk.Subspace(bank.DefaultParamspace), blacklistedAddrs) supplyKeeper := supply.NewKeeper(appCodec, keySupply, accountKeeper, bankKeeper, maccPerms) sk := staking.NewKeeper(staking.ModuleCdc, keyStaking, bankKeeper, supplyKeeper, pk.Subspace(staking.DefaultParamspace)) diff --git a/x/slashing/keeper/test_common.go b/x/slashing/keeper/test_common.go index 6fa24149f5ef..d80c68b7ed9e 100644 --- a/x/slashing/keeper/test_common.go +++ b/x/slashing/keeper/test_common.go @@ -96,7 +96,7 @@ func CreateTestInput(t *testing.T, defaults types.Params) (sdk.Context, bank.Kee paramsKeeper := keeper.NewKeeper(appCodec, keyParams, tkeyParams) accountKeeper := auth.NewAccountKeeper(appCodec, keyAcc, paramsKeeper.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount) - bk := bank.NewBaseKeeper(cdc, keyBank, accountKeeper, paramsKeeper.Subspace(bank.DefaultParamspace), blacklistedAddrs) + bk := bank.NewBaseKeeper(appCodec, keyBank, accountKeeper, paramsKeeper.Subspace(bank.DefaultParamspace), blacklistedAddrs) maccPerms := map[string][]string{ auth.FeeCollectorName: nil, staking.NotBondedPoolName: {supply.Burner, supply.Staking}, diff --git a/x/slashing/types/types.pb.go b/x/slashing/types/types.pb.go index 82791e7bcdcd..3537919b2c05 100644 --- a/x/slashing/types/types.pb.go +++ b/x/slashing/types/types.pb.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: x/slashing/internal/types/types.proto +// source: x/slashing/types/types.proto package types @@ -38,7 +38,7 @@ func (m *MsgUnjail) Reset() { *m = MsgUnjail{} } func (m *MsgUnjail) String() string { return proto.CompactTextString(m) } func (*MsgUnjail) ProtoMessage() {} func (*MsgUnjail) Descriptor() ([]byte, []int) { - return fileDescriptor_2b882c3b0cdd6f57, []int{0} + return fileDescriptor_57cb37764f972476, []int{0} } func (m *MsgUnjail) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -87,7 +87,7 @@ type ValidatorSigningInfo struct { func (m *ValidatorSigningInfo) Reset() { *m = ValidatorSigningInfo{} } func (*ValidatorSigningInfo) ProtoMessage() {} func (*ValidatorSigningInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_2b882c3b0cdd6f57, []int{1} + return fileDescriptor_57cb37764f972476, []int{1} } func (m *ValidatorSigningInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -163,43 +163,41 @@ func init() { proto.RegisterType((*ValidatorSigningInfo)(nil), "cosmos_sdk.x.slashing.v1.ValidatorSigningInfo") } -func init() { - proto.RegisterFile("x/slashing/internal/types/types.proto", fileDescriptor_2b882c3b0cdd6f57) -} - -var fileDescriptor_2b882c3b0cdd6f57 = []byte{ - // 491 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0x3f, 0x6f, 0xd3, 0x4e, - 0x18, 0xc7, 0x73, 0xbf, 0xfc, 0x5a, 0xca, 0x25, 0x74, 0x70, 0x41, 0x58, 0x11, 0xf2, 0x59, 0x96, - 0x40, 0x59, 0x6a, 0x8b, 0xb2, 0x65, 0xc3, 0x5d, 0x40, 0xe2, 0x8f, 0x64, 0xda, 0x0e, 0x0c, 0x58, - 0xe7, 0xdc, 0xe5, 0x7c, 0xc4, 0xbe, 0x8b, 0x7c, 0xe7, 0x2a, 0x59, 0x79, 0x05, 0x1d, 0x19, 0xfb, - 0x42, 0x78, 0x01, 0x1d, 0x3b, 0x32, 0x19, 0x94, 0x2c, 0x88, 0x31, 0x63, 0x27, 0x64, 0x5f, 0x4c, - 0x23, 0xc4, 0xc0, 0x92, 0xf8, 0xfb, 0xb9, 0xe7, 0xfb, 0x7c, 0xef, 0xf1, 0x63, 0xf8, 0x78, 0x1e, - 0xa8, 0x0c, 0xab, 0x94, 0x0b, 0x16, 0x70, 0xa1, 0x69, 0x21, 0x70, 0x16, 0xe8, 0xc5, 0x8c, 0x2a, - 0xf3, 0xeb, 0xcf, 0x0a, 0xa9, 0xa5, 0x65, 0x8f, 0xa5, 0xca, 0xa5, 0x8a, 0x15, 0x99, 0xfa, 0x73, - 0xbf, 0x75, 0xf8, 0xe7, 0x4f, 0x07, 0x4f, 0x74, 0xca, 0x0b, 0x12, 0xcf, 0x70, 0xa1, 0x17, 0x41, - 0x53, 0x1c, 0x30, 0xc9, 0xe4, 0xed, 0x93, 0xe9, 0x30, 0x40, 0x4c, 0x4a, 0x96, 0x51, 0x53, 0x92, - 0x94, 0x93, 0x40, 0xf3, 0x9c, 0x2a, 0x8d, 0xf3, 0x99, 0x29, 0xf0, 0x3e, 0x01, 0x78, 0xf7, 0xb5, - 0x62, 0xa7, 0xe2, 0x23, 0xe6, 0x99, 0x55, 0xc2, 0xfd, 0x73, 0x9c, 0x71, 0x82, 0xb5, 0x2c, 0x62, - 0x4c, 0x48, 0x61, 0x03, 0x17, 0x0c, 0xfb, 0xe1, 0x9b, 0x9f, 0x15, 0xba, 0x53, 0x6b, 0xaa, 0xd4, - 0xba, 0x42, 0xfb, 0x0b, 0x9c, 0x67, 0x23, 0x6f, 0x03, 0xbc, 0x9b, 0x0a, 0x1d, 0x32, 0xae, 0xd3, - 0x32, 0xf1, 0xc7, 0x32, 0x0f, 0xcc, 0xa5, 0x37, 0x7f, 0x87, 0x8a, 0x4c, 0x37, 0x33, 0x9d, 0xe1, - 0xec, 0xb9, 0x71, 0x44, 0xf7, 0x7e, 0xa7, 0xd4, 0xc4, 0xfb, 0xd2, 0x85, 0xf7, 0xcf, 0x5a, 0xf2, - 0x8e, 0x33, 0xc1, 0x05, 0x7b, 0x29, 0x26, 0xd2, 0x7a, 0x05, 0xdb, 0xd4, 0xcd, 0x45, 0x8e, 0x6e, - 0x2a, 0xe4, 0xff, 0x43, 0xd6, 0xb1, 0x14, 0xaa, 0x0d, 0x6b, 0x5b, 0x58, 0x23, 0xd8, 0x57, 0x1a, - 0x17, 0x3a, 0x4e, 0x29, 0x67, 0xa9, 0xb6, 0xff, 0x73, 0xc1, 0xb0, 0x1b, 0x3e, 0x5c, 0x57, 0xe8, - 0xc0, 0x0c, 0xb4, 0x7d, 0xea, 0x45, 0xbd, 0x46, 0xbe, 0x68, 0x54, 0xed, 0xe5, 0x82, 0xd0, 0x79, - 0x2c, 0x27, 0x13, 0x45, 0xb5, 0xdd, 0xfd, 0xd3, 0xbb, 0x7d, 0xea, 0x45, 0xbd, 0x46, 0xbe, 0x6d, - 0x94, 0xf5, 0x01, 0xf6, 0xeb, 0xb7, 0x4b, 0x49, 0x5c, 0x0a, 0xcd, 0x33, 0xfb, 0x7f, 0x17, 0x0c, - 0x7b, 0x47, 0x03, 0xdf, 0xec, 0xc6, 0x6f, 0x77, 0xe3, 0x9f, 0xb4, 0xbb, 0x09, 0xd1, 0x55, 0x85, - 0x3a, 0xb7, 0xbd, 0xb7, 0xdd, 0xde, 0xc5, 0x37, 0x04, 0xa2, 0x9e, 0x41, 0xa7, 0x35, 0xb1, 0x1c, - 0x08, 0xb5, 0xcc, 0x13, 0xa5, 0xa5, 0xa0, 0xc4, 0xde, 0x71, 0xc1, 0x70, 0x2f, 0xda, 0x22, 0xd6, - 0x09, 0x7c, 0x90, 0x73, 0xa5, 0x28, 0x89, 0x93, 0x4c, 0x8e, 0xa7, 0x2a, 0x1e, 0xcb, 0xb2, 0xfe, - 0xe8, 0xec, 0xdd, 0x66, 0x08, 0x77, 0x5d, 0xa1, 0x47, 0x26, 0xe8, 0xaf, 0x65, 0x5e, 0x74, 0x60, - 0x78, 0xd8, 0xe0, 0x63, 0x43, 0x47, 0x7b, 0x9f, 0x2f, 0x51, 0xe7, 0xc7, 0x25, 0x02, 0x21, 0xba, - 0x5a, 0x3a, 0xe0, 0x7a, 0xe9, 0x80, 0xef, 0x4b, 0x07, 0x5c, 0xac, 0x9c, 0xce, 0xf5, 0xca, 0xe9, - 0x7c, 0x5d, 0x39, 0x9d, 0xf7, 0x3b, 0xcd, 0x36, 0x92, 0xdd, 0x66, 0xc4, 0x67, 0xbf, 0x02, 0x00, - 0x00, 0xff, 0xff, 0x61, 0xf4, 0xaf, 0xf7, 0xf7, 0x02, 0x00, 0x00, +func init() { proto.RegisterFile("x/slashing/types/types.proto", fileDescriptor_57cb37764f972476) } + +var fileDescriptor_57cb37764f972476 = []byte{ + // 488 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0xbf, 0x6f, 0xd3, 0x40, + 0x14, 0xc7, 0x73, 0x04, 0x4a, 0xb9, 0x84, 0x0e, 0x2e, 0x08, 0x2b, 0xaa, 0x7c, 0x91, 0x07, 0x94, + 0xa5, 0xb6, 0x28, 0x5b, 0x36, 0xdc, 0x01, 0x90, 0xf8, 0x21, 0x99, 0xb6, 0x03, 0x03, 0xd6, 0x39, + 0x77, 0x39, 0x1f, 0xb1, 0xef, 0x22, 0xdf, 0xb9, 0x4a, 0x56, 0xfe, 0x82, 0x8e, 0x8c, 0xfd, 0x43, + 0xf8, 0x03, 0x3a, 0x76, 0x64, 0x32, 0x28, 0x59, 0x10, 0x63, 0xc6, 0x4e, 0xc8, 0xbe, 0x98, 0x46, + 0x15, 0x42, 0x5d, 0xec, 0x7b, 0x9f, 0xfb, 0xbe, 0xf7, 0xbd, 0x77, 0xef, 0xe0, 0xde, 0xcc, 0x57, + 0x29, 0x56, 0x09, 0x17, 0xcc, 0xd7, 0xf3, 0x29, 0x55, 0xe6, 0xeb, 0x4d, 0x73, 0xa9, 0xa5, 0x65, + 0x8f, 0xa4, 0xca, 0xa4, 0x8a, 0x14, 0x99, 0x78, 0x33, 0xaf, 0x11, 0x7a, 0xa7, 0xcf, 0x7a, 0x4f, + 0x75, 0xc2, 0x73, 0x12, 0x4d, 0x71, 0xae, 0xe7, 0x7e, 0x2d, 0xf6, 0x99, 0x64, 0xf2, 0x7a, 0x65, + 0x2a, 0xf4, 0x10, 0x93, 0x92, 0xa5, 0xd4, 0x48, 0xe2, 0x62, 0xec, 0x6b, 0x9e, 0x51, 0xa5, 0x71, + 0x36, 0x35, 0x02, 0xf7, 0x0b, 0x80, 0x0f, 0xde, 0x2a, 0x76, 0x2c, 0x3e, 0x63, 0x9e, 0x5a, 0x05, + 0xdc, 0x39, 0xc5, 0x29, 0x27, 0x58, 0xcb, 0x3c, 0xc2, 0x84, 0xe4, 0x36, 0xe8, 0x83, 0x41, 0x37, + 0x78, 0xf7, 0xbb, 0x44, 0xf7, 0xab, 0x98, 0x2a, 0xb5, 0x2a, 0xd1, 0xce, 0x1c, 0x67, 0xe9, 0xd0, + 0x5d, 0x03, 0xf7, 0xaa, 0x44, 0xfb, 0x8c, 0xeb, 0xa4, 0x88, 0xbd, 0x91, 0xcc, 0x7c, 0x73, 0xe8, + 0xf5, 0x6f, 0x5f, 0x91, 0xc9, 0xba, 0xa7, 0x13, 0x9c, 0xbe, 0x30, 0x19, 0xe1, 0xc3, 0xbf, 0x2e, + 0x15, 0x71, 0xbf, 0xb5, 0xe1, 0xa3, 0x93, 0x86, 0x7c, 0xe0, 0x4c, 0x70, 0xc1, 0x5e, 0x8b, 0xb1, + 0xb4, 0xde, 0xc0, 0xc6, 0x75, 0x7d, 0x90, 0x83, 0xab, 0x12, 0x79, 0xb7, 0xf0, 0x3a, 0x94, 0x42, + 0x35, 0x66, 0x4d, 0x09, 0x6b, 0x08, 0xbb, 0x4a, 0xe3, 0x5c, 0x47, 0x09, 0xe5, 0x2c, 0xd1, 0xf6, + 0x9d, 0x3e, 0x18, 0xb4, 0x83, 0x27, 0xab, 0x12, 0xed, 0x9a, 0x86, 0x36, 0x77, 0xdd, 0xb0, 0x53, + 0x87, 0xaf, 0xea, 0xa8, 0xca, 0xe5, 0x82, 0xd0, 0x59, 0x24, 0xc7, 0x63, 0x45, 0xb5, 0xdd, 0xbe, + 0x99, 0xbb, 0xb9, 0xeb, 0x86, 0x9d, 0x3a, 0x7c, 0x5f, 0x47, 0xd6, 0x27, 0xd8, 0xad, 0x6e, 0x97, + 0x92, 0xa8, 0x10, 0x9a, 0xa7, 0xf6, 0xdd, 0x3e, 0x18, 0x74, 0x0e, 0x7a, 0x9e, 0x99, 0x8d, 0xd7, + 0xcc, 0xc6, 0x3b, 0x6a, 0x66, 0x13, 0xa0, 0x8b, 0x12, 0xb5, 0xae, 0x6b, 0x6f, 0x66, 0xbb, 0x67, + 0x3f, 0x10, 0x08, 0x3b, 0x06, 0x1d, 0x57, 0xc4, 0x72, 0x20, 0xd4, 0x32, 0x8b, 0x95, 0x96, 0x82, + 0x12, 0xfb, 0x5e, 0x1f, 0x0c, 0xb6, 0xc3, 0x0d, 0x62, 0x1d, 0xc1, 0xc7, 0x19, 0x57, 0x8a, 0x92, + 0x28, 0x4e, 0xe5, 0x68, 0xa2, 0xa2, 0x91, 0x2c, 0x84, 0xa6, 0xb9, 0xbd, 0x55, 0x37, 0xd1, 0x5f, + 0x95, 0x68, 0xcf, 0x18, 0xfd, 0x53, 0xe6, 0x86, 0xbb, 0x86, 0x07, 0x35, 0x3e, 0x34, 0x74, 0xb8, + 0xfd, 0xf5, 0x1c, 0xb5, 0x7e, 0x9d, 0x23, 0x10, 0xbc, 0xbc, 0x58, 0x38, 0xe0, 0x72, 0xe1, 0x80, + 0x9f, 0x0b, 0x07, 0x9c, 0x2d, 0x9d, 0xd6, 0xe5, 0xd2, 0x69, 0x7d, 0x5f, 0x3a, 0xad, 0x8f, 0xff, + 0x7f, 0x16, 0x37, 0xdf, 0x7e, 0xbc, 0x55, 0x5f, 0xc5, 0xf3, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, + 0xf7, 0x43, 0x16, 0x33, 0x16, 0x03, 0x00, 0x00, } func (this *ValidatorSigningInfo) Equal(that interface{}) bool { diff --git a/x/staking/keeper/test_common.go b/x/staking/keeper/test_common.go index 18a0dfc509ca..3e83a310bf64 100644 --- a/x/staking/keeper/test_common.go +++ b/x/staking/keeper/test_common.go @@ -133,7 +133,7 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context ) bk := bank.NewBaseKeeper( - cdc, + appCodec, bankKey, accountKeeper, pk.Subspace(bank.DefaultParamspace), From 0d24d2b2cbc6c8e7183b7152271c1705739091b8 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Thu, 20 Feb 2020 16:09:25 +0100 Subject: [PATCH 161/529] fix test query validators --- simapp/test_helpers.go | 30 +++++++++++++ x/staking/keeper/old_test_common.go | 3 +- x/staking/keeper/querier_test.go | 68 ++++++++++++++++------------- 3 files changed, 69 insertions(+), 32 deletions(-) diff --git a/simapp/test_helpers.go b/simapp/test_helpers.go index abc87ed635cc..31b4db3b80cd 100644 --- a/simapp/test_helpers.go +++ b/simapp/test_helpers.go @@ -1,6 +1,9 @@ package simapp import ( + "bytes" + "encoding/hex" + "strconv" "testing" "github.com/stretchr/testify/require" @@ -187,3 +190,30 @@ func incrementAllSequenceNumbers(initSeqNums []uint64) { initSeqNums[i]++ } } + +func CreateTestPubKeys(numPubKeys int) []crypto.PubKey { + var publicKeys []crypto.PubKey + var buffer bytes.Buffer + + //start at 10 to avoid changing 1 to 01, 2 to 02, etc + for i := 100; i < (numPubKeys + 100); i++ { + numString := strconv.Itoa(i) + buffer.WriteString("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AF") //base pubkey string + buffer.WriteString(numString) //adding on final two digits to make pubkeys unique + publicKeys = append(publicKeys, NewPubKey(buffer.String())) + buffer.Reset() + } + + return publicKeys +} + +func NewPubKey(pk string) (res crypto.PubKey) { + pkBytes, err := hex.DecodeString(pk) + if err != nil { + panic(err) + } + //res, err = crypto.PubKeyFromBytes(pkBytes) + var pkEd ed25519.PubKeyEd25519 + copy(pkEd[:], pkBytes) + return pkEd +} diff --git a/x/staking/keeper/old_test_common.go b/x/staking/keeper/old_test_common.go index 005cfbfb1ffa..8e4cd6b9aac7 100644 --- a/x/staking/keeper/old_test_common.go +++ b/x/staking/keeper/old_test_common.go @@ -83,9 +83,10 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context keyAcc := sdk.NewKVStoreKey(auth.StoreKey) bankKey := sdk.NewKVStoreKey(bank.StoreKey) keyParams := sdk.NewKVStoreKey(params.StoreKey) - tkeyParams := sdk.NewTransientStoreKey(params.TStoreKey) keySupply := sdk.NewKVStoreKey(supply.StoreKey) + tkeyParams := sdk.NewTransientStoreKey(params.TStoreKey) + db := dbm.NewMemDB() ms := store.NewCommitMultiStore(db) ms.MountStoreWithDB(keyStaking, sdk.StoreTypeIAVL, db) diff --git a/x/staking/keeper/querier_test.go b/x/staking/keeper/querier_test.go index 4f348a429a77..333b3b28e655 100644 --- a/x/staking/keeper/querier_test.go +++ b/x/staking/keeper/querier_test.go @@ -141,8 +141,7 @@ func TestQueryValidators(t *testing.T) { params := app.StakingKeeper.GetParams(ctx) querier := staking.NewQuerier(app.StakingKeeper) - addrs := simapp.AddTestAddrs(app, ctx, 500, sdk.NewInt(10000)) - addrVal1, _ := sdk.ValAddress(addrs[0]), sdk.ValAddress(addrs[1]) + addrs := simapp.AddTestAddrs(app, ctx, 500, sdk.TokensFromConsensusPower(10000)) // Create Validators amts := []sdk.Int{sdk.NewInt(9), sdk.NewInt(8), sdk.NewInt(7)} @@ -160,6 +159,7 @@ func TestQueryValidators(t *testing.T) { // Query Validators queriedValidators := app.StakingKeeper.GetValidators(ctx, params.MaxValidators) + require.Len(t, queriedValidators, 3) for i, s := range status { queryValsParams := types.NewQueryValidatorsParams(1, int(params.MaxValidators), s.String()) @@ -180,26 +180,27 @@ func TestQueryValidators(t *testing.T) { require.Equal(t, 1, len(validatorsResp)) require.ElementsMatch(t, validators[i].OperatorAddress, validatorsResp[0].OperatorAddress) - } // Query each validator - queryParams := types.NewQueryValidatorParams(addrVal1) - bz, err := cdc.MarshalJSON(queryParams) - require.NoError(t, err) + for _, validator := range validators { + queryParams := types.NewQueryValidatorParams(validator.OperatorAddress) + bz, err := cdc.MarshalJSON(queryParams) + require.NoError(t, err) - query := abci.RequestQuery{ - Path: "/custom/staking/validator", - Data: bz, - } - res, err := querier(ctx, []string{types.QueryValidator}, query) - require.NoError(t, err) + query := abci.RequestQuery{ + Path: "/custom/staking/validator", + Data: bz, + } + res, err := querier(ctx, []string{types.QueryValidator}, query) + require.NoError(t, err) - var validator types.Validator - err = cdc.UnmarshalJSON(res, &validator) - require.NoError(t, err) + var queriedValidator types.Validator + err = cdc.UnmarshalJSON(res, &queriedValidator) + require.NoError(t, err) - require.Equal(t, queriedValidators[0], validator) + require.Equal(t, validator, queriedValidator) + } } func TestQueryDelegation(t *testing.T) { @@ -209,8 +210,12 @@ func TestQueryDelegation(t *testing.T) { params := app.StakingKeeper.GetParams(ctx) querier := staking.NewQuerier(app.StakingKeeper) - addrs := simapp.AddTestAddrs(app, ctx, 500, sdk.NewInt(10000)) + addrs := simapp.AddTestAddrs(app, ctx, 500, sdk.TokensFromConsensusPower(10000)) + addrAcc1, addrAcc2 := addrs[0], addrs[1] + addrVal1, addrVal2 := sdk.ValAddress(addrAcc1), sdk.ValAddress(addrAcc2) + pubKeys := simapp.CreateTestPubKeys(2) + pk1, pk2 := pubKeys[0], pubKeys[1] // Create Validators and Delegation val1 := types.NewValidator(addrVal1, pk1, types.Description{}) @@ -222,7 +227,8 @@ func TestQueryDelegation(t *testing.T) { app.StakingKeeper.SetValidatorByPowerIndex(ctx, val2) delTokens := sdk.TokensFromConsensusPower(20) - app.StakingKeeper.Delegate(ctx, addrAcc2, delTokens, sdk.Unbonded, val1, true) + _, err := app.StakingKeeper.Delegate(ctx, addrAcc2, delTokens, sdk.Unbonded, val1, true) + require.NoError(t, err) // apply TM updates app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) @@ -414,19 +420,19 @@ func TestQueryDelegation(t *testing.T) { Data: bz, } -// res, err = querier(ctx, []string{types.QueryRedelegations}, query) -// require.NoError(t, err) -// -// var redelRes types.RedelegationResponses -// errRes = cdc.UnmarshalJSON(res, &redelRes) -// require.NoError(t, errRes) -// require.Len(t, redelRes, 1) -// require.Equal(t, redel.DelegatorAddress, redelRes[0].DelegatorAddress) -// require.Equal(t, redel.ValidatorSrcAddress, redelRes[0].ValidatorSrcAddress) -// require.Equal(t, redel.ValidatorDstAddress, redelRes[0].ValidatorDstAddress) -// require.Len(t, redel.Entries, len(redelRes[0].Entries)) -//} -// + res, err = querier(ctx, []string{types.QueryRedelegations}, query) + require.NoError(t, err) + + var redelRes types.RedelegationResponses + errRes = cdc.UnmarshalJSON(res, &redelRes) + require.NoError(t, errRes) + require.Len(t, redelRes, 1) + require.Equal(t, redel.DelegatorAddress, redelRes[0].DelegatorAddress) + require.Equal(t, redel.ValidatorSrcAddress, redelRes[0].ValidatorSrcAddress) + require.Equal(t, redel.ValidatorDstAddress, redelRes[0].ValidatorDstAddress) + require.Len(t, redel.Entries, len(redelRes[0].Entries)) +} + //func TestQueryRedelegations(t *testing.T) { // cdc := codec.New() // ctx, _, _, keeper, _ := CreateTestInput(t, false, 10000) From 9b4707917138099f7577ae705faf4fb3ba7124a8 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Thu, 20 Feb 2020 17:15:22 +0100 Subject: [PATCH 162/529] Merge PR #5682: Change pubkey to bytes --- x/auth/types/account.go | 67 +++++--- x/auth/types/account_test.go | 10 +- x/auth/types/types.pb.go | 95 ++++++------ x/auth/types/types.proto | 2 +- x/auth/vesting/types/vesting_account.go | 154 +++++++++---------- x/auth/vesting/types/vesting_account_test.go | 24 +-- x/slashing/types/types.pb.go | 17 +- x/slashing/types/types.proto | 24 +-- 8 files changed, 214 insertions(+), 179 deletions(-) diff --git a/x/auth/types/account.go b/x/auth/types/account.go index 1c2460166e22..08b67facc3de 100644 --- a/x/auth/types/account.go +++ b/x/auth/types/account.go @@ -7,6 +7,7 @@ import ( "github.com/tendermint/tendermint/crypto" yaml "gopkg.in/yaml.v2" + "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth/exported" ) @@ -16,17 +17,14 @@ var _ exported.GenesisAccount = (*BaseAccount)(nil) // NewBaseAccount creates a new BaseAccount object func NewBaseAccount(address sdk.AccAddress, pubKey crypto.PubKey, accountNumber, sequence uint64) *BaseAccount { - var pkStr string - if pubKey != nil { - pkStr = sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pubKey) - } - - return &BaseAccount{ + acc := &BaseAccount{ Address: address, - PubKey: pkStr, AccountNumber: accountNumber, Sequence: sequence, } + + acc.SetPubKey(pubKey) + return acc } // ProtoBaseAccount - a prototype function for BaseAccount @@ -57,22 +55,23 @@ func (acc *BaseAccount) SetAddress(addr sdk.AccAddress) error { } // GetPubKey - Implements sdk.Account. -func (acc BaseAccount) GetPubKey() crypto.PubKey { - if acc.PubKey == "" { +func (acc BaseAccount) GetPubKey() (pk crypto.PubKey) { + if len(acc.PubKey) == 0 { return nil } - return sdk.MustGetPubKeyFromBech32(sdk.Bech32PubKeyTypeAccPub, acc.PubKey) + codec.Cdc.MustUnmarshalBinaryBare(acc.PubKey, &pk) + return pk } // SetPubKey - Implements sdk.Account. func (acc *BaseAccount) SetPubKey(pubKey crypto.PubKey) error { - pkStr, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pubKey) - if err != nil { - return err + if pubKey == nil { + acc.PubKey = nil + } else { + acc.PubKey = pubKey.Bytes() } - acc.PubKey = pkStr return nil } @@ -100,15 +99,47 @@ func (acc *BaseAccount) SetSequence(seq uint64) error { // Validate checks for errors on the account fields func (acc BaseAccount) Validate() error { - if acc.PubKey != "" && acc.Address != nil && + if len(acc.PubKey) != 0 && acc.Address != nil && !bytes.Equal(acc.GetPubKey().Address().Bytes(), acc.Address.Bytes()) { - return errors.New("pubkey and address pair is invalid") + return errors.New("account address and pubkey address do not match") } return nil } func (acc BaseAccount) String() string { - out, _ := yaml.Marshal(acc) - return string(out) + out, _ := acc.MarshalYAML() + return out.(string) +} + +type baseAccountPretty struct { + Address sdk.AccAddress `json:"address" yaml:"address"` + PubKey string `json:"public_key" yaml:"public_key"` + AccountNumber uint64 `json:"account_number" yaml:"account_number"` + Sequence uint64 `json:"sequence" yaml:"sequence"` +} + +// MarshalYAML returns the YAML representation of an account. +func (acc BaseAccount) MarshalYAML() (interface{}, error) { + alias := baseAccountPretty{ + Address: acc.Address, + AccountNumber: acc.AccountNumber, + Sequence: acc.Sequence, + } + + if acc.PubKey != nil { + pks, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, acc.GetPubKey()) + if err != nil { + return nil, err + } + + alias.PubKey = pks + } + + bz, err := yaml.Marshal(alias) + if err != nil { + return nil, err + } + + return string(bz), err } diff --git a/x/auth/types/account_test.go b/x/auth/types/account_test.go index e86f4b5940b1..ca612f1fe188 100644 --- a/x/auth/types/account_test.go +++ b/x/auth/types/account_test.go @@ -1,7 +1,6 @@ package types_test import ( - "errors" "testing" "github.com/stretchr/testify/require" @@ -86,17 +85,17 @@ func TestGenesisAccountValidate(t *testing.T) { tests := []struct { name string acc exported.GenesisAccount - expErr error + expErr bool }{ { "valid base account", baseAcc, - nil, + false, }, { "invalid base valid account", types.NewBaseAccount(addr, secp256k1.GenPrivKey().PubKey(), 0, 0), - errors.New("pubkey and address pair is invalid"), + true, }, } @@ -104,8 +103,7 @@ func TestGenesisAccountValidate(t *testing.T) { tt := tt t.Run(tt.name, func(t *testing.T) { - err := tt.acc.Validate() - require.Equal(t, tt.expErr, err) + require.Equal(t, tt.expErr, tt.acc.Validate() != nil) }) } } diff --git a/x/auth/types/types.pb.go b/x/auth/types/types.pb.go index 04705c07d3d3..6770d4eb2b2b 100644 --- a/x/auth/types/types.pb.go +++ b/x/auth/types/types.pb.go @@ -30,7 +30,7 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // type for additional functionality (e.g. vesting). type BaseAccount struct { Address github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,1,opt,name=address,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"address,omitempty"` - PubKey string `protobuf:"bytes,2,opt,name=pub_key,json=pubKey,proto3" json:"pub_key,omitempty" yaml:"public_key"` + PubKey []byte `protobuf:"bytes,2,opt,name=pub_key,json=pubKey,proto3" json:"pub_key,omitempty" yaml:"public_key"` AccountNumber uint64 `protobuf:"varint,3,opt,name=account_number,json=accountNumber,proto3" json:"account_number,omitempty" yaml:"account_number"` Sequence uint64 `protobuf:"varint,4,opt,name=sequence,proto3" json:"sequence,omitempty"` } @@ -207,46 +207,45 @@ func init() { func init() { proto.RegisterFile("x/auth/types/types.proto", fileDescriptor_2d526fa662daab74) } var fileDescriptor_2d526fa662daab74 = []byte{ - // 610 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x53, 0x3d, 0x6f, 0xd3, 0x4e, - 0x18, 0x8f, 0xff, 0xc9, 0x3f, 0x2d, 0xd7, 0x82, 0x88, 0xfb, 0xe6, 0x46, 0xc8, 0x17, 0x79, 0x40, - 0x61, 0xa8, 0x43, 0x8a, 0x8a, 0xd4, 0x0c, 0x88, 0x3a, 0xc0, 0x52, 0xa8, 0x2a, 0x47, 0x62, 0x40, - 0x42, 0xd6, 0xf9, 0x7c, 0x38, 0x56, 0x7a, 0x39, 0xd7, 0x77, 0xae, 0xec, 0x7e, 0x02, 0x46, 0x46, - 0xc6, 0xce, 0x7c, 0x92, 0x8e, 0x1d, 0x99, 0x5c, 0x94, 0x2e, 0xcc, 0x1e, 0x99, 0x90, 0x7d, 0x69, - 0x49, 0x4b, 0x41, 0x2c, 0xc9, 0x3d, 0xcf, 0xef, 0xed, 0xee, 0xf1, 0x1d, 0xd0, 0x92, 0x0e, 0x8a, - 0xc5, 0xb0, 0x23, 0xd2, 0x90, 0x70, 0xf9, 0x6b, 0x86, 0x11, 0x13, 0x4c, 0x5d, 0xc6, 0x8c, 0x53, - 0xc6, 0x1d, 0xee, 0x8d, 0xcc, 0xc4, 0x2c, 0x48, 0xe6, 0x51, 0xb7, 0xf9, 0x50, 0x0c, 0x83, 0xc8, - 0x73, 0x42, 0x14, 0x89, 0xb4, 0x53, 0x12, 0x3b, 0x3e, 0xf3, 0xd9, 0xaf, 0x95, 0x54, 0x37, 0x1b, - 0xbf, 0x19, 0x1a, 0xb9, 0x02, 0x16, 0x2c, 0xc4, 0xc9, 0x0e, 0xc6, 0x2c, 0x1e, 0x0b, 0x75, 0x17, - 0xcc, 0x21, 0xcf, 0x8b, 0x08, 0xe7, 0x9a, 0xd2, 0x52, 0xda, 0x8b, 0x56, 0xf7, 0x47, 0x06, 0x37, - 0xfc, 0x40, 0x0c, 0x63, 0xd7, 0xc4, 0x8c, 0x76, 0xe4, 0x06, 0xa6, 0x7f, 0x1b, 0xdc, 0x1b, 0x4d, - 0xed, 0x76, 0x30, 0xde, 0x91, 0x42, 0xfb, 0xd2, 0x41, 0x35, 0xc1, 0x5c, 0x18, 0xbb, 0xce, 0x88, - 0xa4, 0xda, 0x7f, 0x2d, 0xa5, 0x7d, 0xc7, 0x5a, 0xc9, 0x33, 0xd8, 0x48, 0x11, 0x3d, 0xe8, 0x19, - 0x61, 0xec, 0x1e, 0x04, 0xb8, 0xc0, 0x0c, 0xbb, 0x1e, 0xc6, 0xee, 0x2e, 0x49, 0xd5, 0xe7, 0xe0, - 0x1e, 0x92, 0xfb, 0x70, 0xc6, 0x31, 0x75, 0x49, 0xa4, 0x55, 0x5b, 0x4a, 0xbb, 0x66, 0xad, 0xe7, - 0x19, 0x5c, 0x91, 0xb2, 0xeb, 0xb8, 0x61, 0xdf, 0x9d, 0x36, 0xf6, 0xca, 0x5a, 0x6d, 0x82, 0x79, - 0x4e, 0x0e, 0x63, 0x32, 0xc6, 0x44, 0xab, 0x15, 0x5a, 0xfb, 0xaa, 0xee, 0xcd, 0x7f, 0x3c, 0x81, - 0x95, 0xcf, 0x27, 0xb0, 0x62, 0xa4, 0xa0, 0x3e, 0x10, 0xde, 0x2b, 0x42, 0xd4, 0xf7, 0xa0, 0x8e, - 0x68, 0xa1, 0xd7, 0x94, 0x56, 0xb5, 0xbd, 0xb0, 0xb9, 0x64, 0xce, 0x0c, 0xf8, 0xa8, 0x6b, 0xf6, - 0x59, 0x30, 0xb6, 0x1e, 0x9f, 0x66, 0xb0, 0xf2, 0xe5, 0x1c, 0xb6, 0xff, 0x61, 0x0c, 0x85, 0x80, - 0xdb, 0x53, 0x53, 0xf5, 0x3e, 0xa8, 0xfa, 0x88, 0x97, 0x87, 0xaf, 0xd9, 0xc5, 0xd2, 0x38, 0xaf, - 0x82, 0xfa, 0x3e, 0x8a, 0x10, 0xe5, 0xea, 0x1e, 0x58, 0xa2, 0x28, 0x71, 0x28, 0xa1, 0xcc, 0xc1, - 0x43, 0x14, 0x21, 0x2c, 0x48, 0x24, 0xc7, 0x5e, 0xb3, 0xf4, 0x3c, 0x83, 0x4d, 0x79, 0xe4, 0x5b, - 0x48, 0x86, 0xdd, 0xa0, 0x28, 0x79, 0x43, 0x28, 0xeb, 0x5f, 0xf5, 0xd4, 0x6d, 0xb0, 0x28, 0x12, - 0x87, 0x07, 0xbe, 0x73, 0x10, 0xd0, 0x40, 0xc8, 0x54, 0x6b, 0x2d, 0xcf, 0xe0, 0x92, 0x34, 0x9a, - 0x45, 0x0d, 0x1b, 0x88, 0x64, 0x10, 0xf8, 0xaf, 0x8b, 0x42, 0xb5, 0xc1, 0x4a, 0x09, 0x1e, 0x13, - 0x07, 0x33, 0x2e, 0x9c, 0x90, 0x44, 0x8e, 0x9b, 0x0a, 0x32, 0x9d, 0x7f, 0x2b, 0xcf, 0xe0, 0x83, - 0x19, 0x8f, 0x9b, 0x34, 0xc3, 0x6e, 0x14, 0x66, 0xc7, 0xa4, 0xcf, 0xb8, 0xd8, 0x27, 0x91, 0x95, - 0x0a, 0xa2, 0x1e, 0x82, 0xb5, 0x22, 0xed, 0x88, 0x44, 0xc1, 0x87, 0x54, 0xf2, 0x89, 0xb7, 0xb9, - 0xb5, 0xd5, 0xdd, 0x96, 0x5f, 0xc6, 0xea, 0x4d, 0x32, 0xb8, 0x3c, 0x08, 0xfc, 0xb7, 0x25, 0xa3, - 0x90, 0xbe, 0x7c, 0x51, 0xe2, 0x79, 0x06, 0x75, 0x99, 0xf6, 0x07, 0x03, 0xc3, 0x5e, 0xe6, 0xd7, - 0x74, 0xb2, 0xad, 0xa6, 0x60, 0xfd, 0xa6, 0x82, 0x13, 0x1c, 0x6e, 0x6e, 0x3d, 0x1d, 0x75, 0xb5, - 0xff, 0xcb, 0xd0, 0x67, 0x93, 0x0c, 0xae, 0x5e, 0x0b, 0x1d, 0x5c, 0x32, 0xf2, 0x0c, 0xb6, 0x6e, - 0x8f, 0xbd, 0x32, 0x31, 0xec, 0x55, 0x7e, 0xab, 0xb6, 0x37, 0x5f, 0x5c, 0xac, 0xef, 0x27, 0x50, - 0xb1, 0xfa, 0xa7, 0x13, 0x5d, 0x39, 0x9b, 0xe8, 0xca, 0xb7, 0x89, 0xae, 0x7c, 0xba, 0xd0, 0x2b, - 0x67, 0x17, 0x7a, 0xe5, 0xeb, 0x85, 0x5e, 0x79, 0xf7, 0xe8, 0xaf, 0xf7, 0x67, 0xf6, 0xcd, 0xbb, - 0xf5, 0xf2, 0x75, 0x3e, 0xf9, 0x19, 0x00, 0x00, 0xff, 0xff, 0xd6, 0x52, 0x88, 0x39, 0x0a, 0x04, - 0x00, 0x00, + // 606 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x53, 0x3f, 0x6f, 0xd3, 0x40, + 0x14, 0x8f, 0x49, 0x48, 0xab, 0x6b, 0x41, 0xc4, 0xfd, 0xe7, 0x46, 0xc8, 0x17, 0x79, 0x40, 0x61, + 0xa8, 0x43, 0x8a, 0x8a, 0xd4, 0x0c, 0x88, 0x3a, 0xc0, 0x52, 0xa8, 0x2a, 0x47, 0x62, 0x40, 0x42, + 0xd6, 0xf9, 0x7c, 0x38, 0x56, 0x7a, 0x39, 0xd7, 0x77, 0xae, 0xec, 0x7e, 0x02, 0x46, 0x46, 0xc6, + 0xce, 0x7c, 0x92, 0x8e, 0x1d, 0x99, 0x5c, 0x94, 0x2e, 0xcc, 0x1e, 0x99, 0x90, 0x7d, 0x69, 0x49, + 0x4b, 0x41, 0x2c, 0xc9, 0xbd, 0xf7, 0xfb, 0x77, 0xf7, 0x7c, 0x07, 0xb4, 0xa4, 0x83, 0x62, 0x31, + 0xec, 0x88, 0x34, 0x24, 0x5c, 0xfe, 0x9a, 0x61, 0xc4, 0x04, 0x53, 0x97, 0x31, 0xe3, 0x94, 0x71, + 0x87, 0x7b, 0x23, 0x33, 0x31, 0x0b, 0x92, 0x79, 0xd4, 0x6d, 0x3e, 0x12, 0xc3, 0x20, 0xf2, 0x9c, + 0x10, 0x45, 0x22, 0xed, 0x94, 0xc4, 0x8e, 0xcf, 0x7c, 0xf6, 0x7b, 0x25, 0xd5, 0xcd, 0xc6, 0x1f, + 0x86, 0x46, 0xae, 0x80, 0x05, 0x0b, 0x71, 0xb2, 0x83, 0x31, 0x8b, 0xc7, 0x42, 0xdd, 0x05, 0x73, + 0xc8, 0xf3, 0x22, 0xc2, 0xb9, 0xa6, 0xb4, 0x94, 0xf6, 0xa2, 0xd5, 0xfd, 0x99, 0xc1, 0x0d, 0x3f, + 0x10, 0xc3, 0xd8, 0x35, 0x31, 0xa3, 0x1d, 0xb9, 0x81, 0xe9, 0xdf, 0x06, 0xf7, 0x46, 0x53, 0xbb, + 0x1d, 0x8c, 0x77, 0xa4, 0xd0, 0xbe, 0x74, 0x50, 0x4d, 0x30, 0x17, 0xc6, 0xae, 0x33, 0x22, 0xa9, + 0x76, 0xa7, 0x34, 0x5b, 0xc9, 0x33, 0xd8, 0x48, 0x11, 0x3d, 0xe8, 0x19, 0x61, 0xec, 0x1e, 0x04, + 0xb8, 0xc0, 0x0c, 0xbb, 0x1e, 0xc6, 0xee, 0x2e, 0x49, 0xd5, 0x17, 0xe0, 0x3e, 0x92, 0xfb, 0x70, + 0xc6, 0x31, 0x75, 0x49, 0xa4, 0x55, 0x5b, 0x4a, 0xbb, 0x66, 0xad, 0xe7, 0x19, 0x5c, 0x91, 0xb2, + 0xeb, 0xb8, 0x61, 0xdf, 0x9b, 0x36, 0xf6, 0xca, 0x5a, 0x6d, 0x82, 0x79, 0x4e, 0x0e, 0x63, 0x32, + 0xc6, 0x44, 0xab, 0x15, 0x5a, 0xfb, 0xaa, 0xee, 0xcd, 0x7f, 0x3a, 0x81, 0x95, 0x2f, 0x27, 0xb0, + 0x62, 0xa4, 0xa0, 0x3e, 0x10, 0xde, 0x6b, 0x42, 0xd4, 0x0f, 0xa0, 0x8e, 0x68, 0xa1, 0xd7, 0x94, + 0x56, 0xb5, 0xbd, 0xb0, 0xb9, 0x64, 0xce, 0x0c, 0xf8, 0xa8, 0x6b, 0xf6, 0x59, 0x30, 0xb6, 0x9e, + 0x9c, 0x66, 0xb0, 0xf2, 0xf5, 0x1c, 0xb6, 0xff, 0x63, 0x0c, 0x85, 0x80, 0xdb, 0x53, 0x53, 0xf5, + 0x01, 0xa8, 0xfa, 0x88, 0x97, 0x87, 0xaf, 0xd9, 0xc5, 0xd2, 0x38, 0xaf, 0x82, 0xfa, 0x3e, 0x8a, + 0x10, 0xe5, 0xea, 0x1e, 0x58, 0xa2, 0x28, 0x71, 0x28, 0xa1, 0xcc, 0xc1, 0x43, 0x14, 0x21, 0x2c, + 0x48, 0x24, 0xc7, 0x5e, 0xb3, 0xf4, 0x3c, 0x83, 0x4d, 0x79, 0xe4, 0x5b, 0x48, 0x86, 0xdd, 0xa0, + 0x28, 0x79, 0x4b, 0x28, 0xeb, 0x5f, 0xf5, 0xd4, 0x6d, 0xb0, 0x28, 0x12, 0x87, 0x07, 0xbe, 0x73, + 0x10, 0xd0, 0x40, 0xc8, 0x54, 0x6b, 0x2d, 0xcf, 0xe0, 0x92, 0x34, 0x9a, 0x45, 0x0d, 0x1b, 0x88, + 0x64, 0x10, 0xf8, 0x6f, 0x8a, 0x42, 0xb5, 0xc1, 0x4a, 0x09, 0x1e, 0x13, 0x07, 0x33, 0x2e, 0x9c, + 0x90, 0x44, 0x8e, 0x9b, 0x0a, 0x32, 0x9d, 0x7f, 0x2b, 0xcf, 0xe0, 0xc3, 0x19, 0x8f, 0x9b, 0x34, + 0xc3, 0x6e, 0x14, 0x66, 0xc7, 0xa4, 0xcf, 0xb8, 0xd8, 0x27, 0x91, 0x95, 0x0a, 0xa2, 0x1e, 0x82, + 0xb5, 0x22, 0xed, 0x88, 0x44, 0xc1, 0xc7, 0x54, 0xf2, 0x89, 0xb7, 0xb9, 0xb5, 0xd5, 0xdd, 0x96, + 0x5f, 0xc6, 0xea, 0x4d, 0x32, 0xb8, 0x3c, 0x08, 0xfc, 0x77, 0x25, 0xa3, 0x90, 0xbe, 0x7a, 0x59, + 0xe2, 0x79, 0x06, 0x75, 0x99, 0xf6, 0x17, 0x03, 0xc3, 0x5e, 0xe6, 0xd7, 0x74, 0xb2, 0xad, 0xa6, + 0x60, 0xfd, 0xa6, 0x82, 0x13, 0x1c, 0x6e, 0x6e, 0x3d, 0x1b, 0x75, 0xb5, 0xbb, 0x65, 0xe8, 0xf3, + 0x49, 0x06, 0x57, 0xaf, 0x85, 0x0e, 0x2e, 0x19, 0x79, 0x06, 0x5b, 0xb7, 0xc7, 0x5e, 0x99, 0x18, + 0xf6, 0x2a, 0xbf, 0x55, 0xdb, 0x9b, 0x2f, 0x2e, 0xd6, 0x8f, 0x13, 0xa8, 0x58, 0xfd, 0xd3, 0x89, + 0xae, 0x9c, 0x4d, 0x74, 0xe5, 0xfb, 0x44, 0x57, 0x3e, 0x5f, 0xe8, 0x95, 0xb3, 0x0b, 0xbd, 0xf2, + 0xed, 0x42, 0xaf, 0xbc, 0x7f, 0xfc, 0xcf, 0xfb, 0x33, 0xfb, 0xe6, 0xdd, 0x7a, 0xf9, 0x3a, 0x9f, + 0xfe, 0x0a, 0x00, 0x00, 0xff, 0xff, 0x84, 0x2e, 0x85, 0xe8, 0x0a, 0x04, 0x00, 0x00, } func (this *Params) Equal(that interface{}) bool { @@ -571,7 +570,7 @@ func (m *BaseAccount) Unmarshal(dAtA []byte) error { if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field PubKey", wireType) } - var stringLen uint64 + var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTypes @@ -581,23 +580,25 @@ func (m *BaseAccount) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + byteLen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if byteLen < 0 { return ErrInvalidLengthTypes } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + byteLen if postIndex < 0 { return ErrInvalidLengthTypes } if postIndex > l { return io.ErrUnexpectedEOF } - m.PubKey = string(dAtA[iNdEx:postIndex]) + m.PubKey = append(m.PubKey[:0], dAtA[iNdEx:postIndex]...) + if m.PubKey == nil { + m.PubKey = []byte{} + } iNdEx = postIndex case 3: if wireType != 0 { diff --git a/x/auth/types/types.proto b/x/auth/types/types.proto index c707eb9c55ab..8a0d6555c7c5 100644 --- a/x/auth/types/types.proto +++ b/x/auth/types/types.proto @@ -14,7 +14,7 @@ message BaseAccount { option (gogoproto.goproto_stringer) = false; bytes address = 1 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; - string pub_key = 2 [(gogoproto.moretags) = "yaml:\"public_key\""]; + bytes pub_key = 2 [(gogoproto.moretags) = "yaml:\"public_key\""]; uint64 account_number = 3 [(gogoproto.moretags) = "yaml:\"account_number\""]; uint64 sequence = 4; } diff --git a/x/auth/vesting/types/vesting_account.go b/x/auth/vesting/types/vesting_account.go index cbbeffc03143..d4b6fc6345cf 100644 --- a/x/auth/vesting/types/vesting_account.go +++ b/x/auth/vesting/types/vesting_account.go @@ -1,10 +1,10 @@ package types import ( - "encoding/json" "errors" "time" + "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -164,7 +164,7 @@ func (bva BaseVestingAccount) Validate() error { return bva.BaseAccount.Validate() } -type vestingAccountPretty struct { +type vestingAccountYAML struct { Address sdk.AccAddress `json:"address" yaml:"address"` PubKey string `json:"public_key" yaml:"public_key"` AccountNumber uint64 `json:"account_number" yaml:"account_number"` @@ -179,6 +179,21 @@ type vestingAccountPretty struct { VestingPeriods Periods `json:"vesting_periods,omitempty" yaml:"vesting_periods,omitempty"` } +type vestingAccountJSON struct { + Address sdk.AccAddress `json:"address" yaml:"address"` + PubKey crypto.PubKey `json:"public_key" yaml:"public_key"` + AccountNumber uint64 `json:"account_number" yaml:"account_number"` + Sequence uint64 `json:"sequence" yaml:"sequence"` + OriginalVesting sdk.Coins `json:"original_vesting" yaml:"original_vesting"` + DelegatedFree sdk.Coins `json:"delegated_free" yaml:"delegated_free"` + DelegatedVesting sdk.Coins `json:"delegated_vesting" yaml:"delegated_vesting"` + EndTime int64 `json:"end_time" yaml:"end_time"` + + // custom fields based on concrete vesting type which can be omitted + StartTime int64 `json:"start_time,omitempty" yaml:"start_time,omitempty"` + VestingPeriods Periods `json:"vesting_periods,omitempty" yaml:"vesting_periods,omitempty"` +} + func (bva BaseVestingAccount) String() string { out, _ := bva.MarshalYAML() return out.(string) @@ -186,9 +201,8 @@ func (bva BaseVestingAccount) String() string { // MarshalYAML returns the YAML representation of a BaseVestingAccount. func (bva BaseVestingAccount) MarshalYAML() (interface{}, error) { - alias := vestingAccountPretty{ + alias := vestingAccountYAML{ Address: bva.Address, - PubKey: bva.PubKey, AccountNumber: bva.AccountNumber, Sequence: bva.Sequence, OriginalVesting: bva.OriginalVesting, @@ -197,6 +211,16 @@ func (bva BaseVestingAccount) MarshalYAML() (interface{}, error) { EndTime: bva.EndTime, } + pk := bva.GetPubKey() + if pk != nil { + pks, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pk) + if err != nil { + return nil, err + } + + alias.PubKey = pks + } + bz, err := yaml.Marshal(alias) if err != nil { return nil, err @@ -207,9 +231,9 @@ func (bva BaseVestingAccount) MarshalYAML() (interface{}, error) { // MarshalJSON returns the JSON representation of a BaseVestingAccount. func (bva BaseVestingAccount) MarshalJSON() ([]byte, error) { - alias := vestingAccountPretty{ + alias := vestingAccountJSON{ Address: bva.Address, - PubKey: bva.PubKey, + PubKey: bva.GetPubKey(), AccountNumber: bva.AccountNumber, Sequence: bva.Sequence, OriginalVesting: bva.OriginalVesting, @@ -218,29 +242,17 @@ func (bva BaseVestingAccount) MarshalJSON() ([]byte, error) { EndTime: bva.EndTime, } - return json.Marshal(alias) + return codec.Cdc.MarshalJSON(alias) } // UnmarshalJSON unmarshals raw JSON bytes into a BaseVestingAccount. func (bva *BaseVestingAccount) UnmarshalJSON(bz []byte) error { - var alias vestingAccountPretty - if err := json.Unmarshal(bz, &alias); err != nil { + var alias vestingAccountJSON + if err := codec.Cdc.UnmarshalJSON(bz, &alias); err != nil { return err } - var ( - pk crypto.PubKey - err error - ) - - if alias.PubKey != "" { - pk, err = sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeAccPub, alias.PubKey) - if err != nil { - return err - } - } - - bva.BaseAccount = authtypes.NewBaseAccount(alias.Address, pk, alias.AccountNumber, alias.Sequence) + bva.BaseAccount = authtypes.NewBaseAccount(alias.Address, alias.PubKey, alias.AccountNumber, alias.Sequence) bva.OriginalVesting = alias.OriginalVesting bva.DelegatedFree = alias.DelegatedFree bva.DelegatedVesting = alias.DelegatedVesting @@ -344,9 +356,8 @@ func (cva ContinuousVestingAccount) String() string { // MarshalYAML returns the YAML representation of a ContinuousVestingAccount. func (cva ContinuousVestingAccount) MarshalYAML() (interface{}, error) { - alias := vestingAccountPretty{ + alias := vestingAccountYAML{ Address: cva.Address, - PubKey: cva.PubKey, AccountNumber: cva.AccountNumber, Sequence: cva.Sequence, OriginalVesting: cva.OriginalVesting, @@ -356,6 +367,16 @@ func (cva ContinuousVestingAccount) MarshalYAML() (interface{}, error) { StartTime: cva.StartTime, } + pk := cva.GetPubKey() + if pk != nil { + pks, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pk) + if err != nil { + return nil, err + } + + alias.PubKey = pks + } + bz, err := yaml.Marshal(alias) if err != nil { return nil, err @@ -366,9 +387,9 @@ func (cva ContinuousVestingAccount) MarshalYAML() (interface{}, error) { // MarshalJSON returns the JSON representation of a ContinuousVestingAccount. func (cva ContinuousVestingAccount) MarshalJSON() ([]byte, error) { - alias := vestingAccountPretty{ + alias := vestingAccountJSON{ Address: cva.Address, - PubKey: cva.PubKey, + PubKey: cva.GetPubKey(), AccountNumber: cva.AccountNumber, Sequence: cva.Sequence, OriginalVesting: cva.OriginalVesting, @@ -378,30 +399,18 @@ func (cva ContinuousVestingAccount) MarshalJSON() ([]byte, error) { StartTime: cva.StartTime, } - return json.Marshal(alias) + return codec.Cdc.MarshalJSON(alias) } // UnmarshalJSON unmarshals raw JSON bytes into a ContinuousVestingAccount. func (cva *ContinuousVestingAccount) UnmarshalJSON(bz []byte) error { - var alias vestingAccountPretty - if err := json.Unmarshal(bz, &alias); err != nil { + var alias vestingAccountJSON + if err := codec.Cdc.UnmarshalJSON(bz, &alias); err != nil { return err } - var ( - pk crypto.PubKey - err error - ) - - if alias.PubKey != "" { - pk, err = sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeAccPub, alias.PubKey) - if err != nil { - return err - } - } - cva.BaseVestingAccount = &BaseVestingAccount{ - BaseAccount: authtypes.NewBaseAccount(alias.Address, pk, alias.AccountNumber, alias.Sequence), + BaseAccount: authtypes.NewBaseAccount(alias.Address, alias.PubKey, alias.AccountNumber, alias.Sequence), OriginalVesting: alias.OriginalVesting, DelegatedFree: alias.DelegatedFree, DelegatedVesting: alias.DelegatedVesting, @@ -536,9 +545,8 @@ func (pva PeriodicVestingAccount) String() string { // MarshalYAML returns the YAML representation of a PeriodicVestingAccount. func (pva PeriodicVestingAccount) MarshalYAML() (interface{}, error) { - alias := vestingAccountPretty{ + alias := vestingAccountYAML{ Address: pva.Address, - PubKey: pva.PubKey, AccountNumber: pva.AccountNumber, Sequence: pva.Sequence, OriginalVesting: pva.OriginalVesting, @@ -549,6 +557,16 @@ func (pva PeriodicVestingAccount) MarshalYAML() (interface{}, error) { VestingPeriods: pva.VestingPeriods, } + pk := pva.GetPubKey() + if pk != nil { + pks, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pk) + if err != nil { + return nil, err + } + + alias.PubKey = pks + } + bz, err := yaml.Marshal(alias) if err != nil { return nil, err @@ -559,9 +577,9 @@ func (pva PeriodicVestingAccount) MarshalYAML() (interface{}, error) { // MarshalJSON returns the JSON representation of a PeriodicVestingAccount. func (pva PeriodicVestingAccount) MarshalJSON() ([]byte, error) { - alias := vestingAccountPretty{ + alias := vestingAccountJSON{ Address: pva.Address, - PubKey: pva.PubKey, + PubKey: pva.GetPubKey(), AccountNumber: pva.AccountNumber, Sequence: pva.Sequence, OriginalVesting: pva.OriginalVesting, @@ -572,30 +590,18 @@ func (pva PeriodicVestingAccount) MarshalJSON() ([]byte, error) { VestingPeriods: pva.VestingPeriods, } - return json.Marshal(alias) + return codec.Cdc.MarshalJSON(alias) } // UnmarshalJSON unmarshals raw JSON bytes into a PeriodicVestingAccount. func (pva *PeriodicVestingAccount) UnmarshalJSON(bz []byte) error { - var alias vestingAccountPretty - if err := json.Unmarshal(bz, &alias); err != nil { + var alias vestingAccountJSON + if err := codec.Cdc.UnmarshalJSON(bz, &alias); err != nil { return err } - var ( - pk crypto.PubKey - err error - ) - - if alias.PubKey != "" { - pk, err = sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeAccPub, alias.PubKey) - if err != nil { - return err - } - } - pva.BaseVestingAccount = &BaseVestingAccount{ - BaseAccount: authtypes.NewBaseAccount(alias.Address, pk, alias.AccountNumber, alias.Sequence), + BaseAccount: authtypes.NewBaseAccount(alias.Address, alias.PubKey, alias.AccountNumber, alias.Sequence), OriginalVesting: alias.OriginalVesting, DelegatedFree: alias.DelegatedFree, DelegatedVesting: alias.DelegatedVesting, @@ -676,9 +682,9 @@ func (dva DelayedVestingAccount) String() string { // MarshalJSON returns the JSON representation of a DelayedVestingAccount. func (dva DelayedVestingAccount) MarshalJSON() ([]byte, error) { - alias := vestingAccountPretty{ + alias := vestingAccountJSON{ Address: dva.Address, - PubKey: dva.PubKey, + PubKey: dva.GetPubKey(), AccountNumber: dva.AccountNumber, Sequence: dva.Sequence, OriginalVesting: dva.OriginalVesting, @@ -687,30 +693,18 @@ func (dva DelayedVestingAccount) MarshalJSON() ([]byte, error) { EndTime: dva.EndTime, } - return json.Marshal(alias) + return codec.Cdc.MarshalJSON(alias) } // UnmarshalJSON unmarshals raw JSON bytes into a DelayedVestingAccount. func (dva *DelayedVestingAccount) UnmarshalJSON(bz []byte) error { - var alias vestingAccountPretty - if err := json.Unmarshal(bz, &alias); err != nil { + var alias vestingAccountJSON + if err := codec.Cdc.UnmarshalJSON(bz, &alias); err != nil { return err } - var ( - pk crypto.PubKey - err error - ) - - if alias.PubKey != "" { - pk, err = sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeAccPub, alias.PubKey) - if err != nil { - return err - } - } - dva.BaseVestingAccount = &BaseVestingAccount{ - BaseAccount: authtypes.NewBaseAccount(alias.Address, pk, alias.AccountNumber, alias.Sequence), + BaseAccount: authtypes.NewBaseAccount(alias.Address, alias.PubKey, alias.AccountNumber, alias.Sequence), OriginalVesting: alias.OriginalVesting, DelegatedFree: alias.DelegatedFree, DelegatedVesting: alias.DelegatedVesting, diff --git a/x/auth/vesting/types/vesting_account_test.go b/x/auth/vesting/types/vesting_account_test.go index e36661111fef..974a1f3149c2 100644 --- a/x/auth/vesting/types/vesting_account_test.go +++ b/x/auth/vesting/types/vesting_account_test.go @@ -2,7 +2,6 @@ package types_test import ( "encoding/json" - "errors" "testing" "time" @@ -589,58 +588,59 @@ func TestGenesisAccountValidate(t *testing.T) { tests := []struct { name string acc authexported.GenesisAccount - expErr error + expErr bool }{ { "valid base account", baseAcc, - nil, + false, }, { "invalid base valid account", authtypes.NewBaseAccount(addr, secp256k1.GenPrivKey().PubKey(), 0, 0), - errors.New("pubkey and address pair is invalid"), + true, }, { "valid base vesting account", baseVestingWithCoins, - nil, + false, }, { "valid continuous vesting account", types.NewContinuousVestingAccount(baseAcc, initialVesting, 100, 200), - nil, + false, }, { "invalid vesting times", types.NewContinuousVestingAccount(baseAcc, initialVesting, 1654668078, 1554668078), - errors.New("vesting start-time cannot be before end-time"), + true, }, { "valid periodic vesting account", types.NewPeriodicVestingAccount(baseAcc, initialVesting, 0, types.Periods{types.Period{Length: int64(100), Amount: sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)}}}), - nil, + false, }, { "invalid vesting period lengths", types.NewPeriodicVestingAccountRaw( baseVestingWithCoins, 0, types.Periods{types.Period{Length: int64(50), Amount: sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)}}}), - errors.New("vesting end time does not match length of all vesting periods"), + true, }, { "invalid vesting period amounts", types.NewPeriodicVestingAccountRaw( baseVestingWithCoins, 0, types.Periods{types.Period{Length: int64(100), Amount: sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 25)}}}), - errors.New("original vesting coins does not match the sum of all coins in vesting periods"), + true, }, } + for _, tt := range tests { tt := tt + t.Run(tt.name, func(t *testing.T) { - err := tt.acc.Validate() - require.Equal(t, tt.expErr, err) + require.Equal(t, tt.expErr, tt.acc.Validate() != nil) }) } } diff --git a/x/slashing/types/types.pb.go b/x/slashing/types/types.pb.go index 3537919b2c05..a5444def9e35 100644 --- a/x/slashing/types/types.pb.go +++ b/x/slashing/types/types.pb.go @@ -76,12 +76,17 @@ func (m *MsgUnjail) GetValidatorAddr() github_com_cosmos_cosmos_sdk_types.ValAdd // ValidatorSigningInfo defines the signing info for a validator type ValidatorSigningInfo struct { - Address github_com_cosmos_cosmos_sdk_types.ConsAddress `protobuf:"bytes,1,opt,name=address,proto3,casttype=github.com/cosmos/cosmos-sdk/types.ConsAddress" json:"address,omitempty"` - StartHeight int64 `protobuf:"varint,2,opt,name=start_height,json=startHeight,proto3" json:"start_height,omitempty" yaml:"start_height"` - IndexOffset int64 `protobuf:"varint,3,opt,name=index_offset,json=indexOffset,proto3" json:"index_offset,omitempty" yaml:"index_offset"` - JailedUntil time.Time `protobuf:"bytes,4,opt,name=jailed_until,json=jailedUntil,proto3,stdtime" json:"jailed_until" yaml:"jailed_until"` - Tombstoned bool `protobuf:"varint,5,opt,name=tombstoned,proto3" json:"tombstoned,omitempty"` - MissedBlocksCounter int64 `protobuf:"varint,6,opt,name=missed_blocks_counter,json=missedBlocksCounter,proto3" json:"missed_blocks_counter,omitempty" yaml:"missed_blocks_counter"` + Address github_com_cosmos_cosmos_sdk_types.ConsAddress `protobuf:"bytes,1,opt,name=address,proto3,casttype=github.com/cosmos/cosmos-sdk/types.ConsAddress" json:"address,omitempty"` + // height at which validator was first a candidate OR was unjailed + StartHeight int64 `protobuf:"varint,2,opt,name=start_height,json=startHeight,proto3" json:"start_height,omitempty" yaml:"start_height"` + // index offset into signed block bit array + IndexOffset int64 `protobuf:"varint,3,opt,name=index_offset,json=indexOffset,proto3" json:"index_offset,omitempty" yaml:"index_offset"` + // timestamp validator cannot be unjailed until + JailedUntil time.Time `protobuf:"bytes,4,opt,name=jailed_until,json=jailedUntil,proto3,stdtime" json:"jailed_until" yaml:"jailed_until"` + // whether or not a validator has been tombstoned (killed out of validator set) + Tombstoned bool `protobuf:"varint,5,opt,name=tombstoned,proto3" json:"tombstoned,omitempty"` + // missed blocks counter (to avoid scanning the array every time) + MissedBlocksCounter int64 `protobuf:"varint,6,opt,name=missed_blocks_counter,json=missedBlocksCounter,proto3" json:"missed_blocks_counter,omitempty" yaml:"missed_blocks_counter"` } func (m *ValidatorSigningInfo) Reset() { *m = ValidatorSigningInfo{} } diff --git a/x/slashing/types/types.proto b/x/slashing/types/types.proto index 9aafe07c3bf3..dfd7cf75dbe4 100644 --- a/x/slashing/types/types.proto +++ b/x/slashing/types/types.proto @@ -11,7 +11,7 @@ message MsgUnjail { bytes validator_addr = 1 [ (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.ValAddress", (gogoproto.moretags) = "yaml:\"address\"", - (gogoproto.jsontag) = "address" + (gogoproto.jsontag) = "address" ]; } @@ -21,15 +21,21 @@ message ValidatorSigningInfo { option (gogoproto.goproto_stringer) = false; bytes address = 1 [ - (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.ConsAddress" // validator consensus address + (gogoproto.casttype) = + "github.com/cosmos/cosmos-sdk/types.ConsAddress" // validator consensus address ]; - int64 start_height = 2 [(gogoproto.moretags) = "yaml:\"start_height\""]; // height at which validator was first a candidate OR was unjailed - int64 index_offset = 3 [(gogoproto.moretags) = "yaml:\"index_offset\""]; // index offset into signed block bit array + // height at which validator was first a candidate OR was unjailed + int64 start_height = 2 [(gogoproto.moretags) = "yaml:\"start_height\""]; + // index offset into signed block bit array + int64 index_offset = 3 [(gogoproto.moretags) = "yaml:\"index_offset\""]; + // timestamp validator cannot be unjailed until google.protobuf.Timestamp jailed_until = 4 [ - (gogoproto.moretags) = "yaml:\"jailed_until\"", + (gogoproto.moretags) = "yaml:\"jailed_until\"", (gogoproto.stdtime) = true, (gogoproto.nullable) = false - ]; // timestamp validator cannot be unjailed until - bool tombstoned = 5; // whether or not a validator has been tombstoned (killed out of validator set) - int64 missed_blocks_counter = 6 [(gogoproto.moretags) = "yaml:\"missed_blocks_counter\""]; // missed blocks counter (to avoid scanning the array every time) -} \ No newline at end of file + ]; + // whether or not a validator has been tombstoned (killed out of validator set) + bool tombstoned = 5; + // missed blocks counter (to avoid scanning the array every time) + int64 missed_blocks_counter = 6 [(gogoproto.moretags) = "yaml:\"missed_blocks_counter\""]; +} From 29987a095b83c2952a74987953b8f4e305bf3537 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Thu, 20 Feb 2020 17:30:13 +0100 Subject: [PATCH 163/529] make TestQueryDelegations pass with simapp :D --- x/staking/keeper/querier_test.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/x/staking/keeper/querier_test.go b/x/staking/keeper/querier_test.go index 333b3b28e655..0289bb102cf3 100644 --- a/x/staking/keeper/querier_test.go +++ b/x/staking/keeper/querier_test.go @@ -4,6 +4,8 @@ import ( "fmt" "testing" + "github.com/cosmos/cosmos-sdk/x/distribution" + "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" @@ -203,14 +205,14 @@ func TestQueryValidators(t *testing.T) { } } -func TestQueryDelegation(t *testing.T) { +func TestQueryDelegations(t *testing.T) { cdc := codec.New() app := simapp.Setup(false) ctx := app.BaseApp.NewContext(false, abci.Header{}) params := app.StakingKeeper.GetParams(ctx) querier := staking.NewQuerier(app.StakingKeeper) - addrs := simapp.AddTestAddrs(app, ctx, 500, sdk.TokensFromConsensusPower(10000)) + addrs := simapp.AddTestAddrs(app, ctx, 2, sdk.TokensFromConsensusPower(10000)) addrAcc1, addrAcc2 := addrs[0], addrs[1] addrVal1, addrVal2 := sdk.ValAddress(addrAcc1), sdk.ValAddress(addrAcc2) @@ -221,6 +223,8 @@ func TestQueryDelegation(t *testing.T) { val1 := types.NewValidator(addrVal1, pk1, types.Description{}) app.StakingKeeper.SetValidator(ctx, val1) app.StakingKeeper.SetValidatorByPowerIndex(ctx, val1) + app.DistrKeeper.SetValidatorHistoricalRewards(ctx, addrVal1, 18446744073709551615, distribution.ValidatorHistoricalRewards{ReferenceCount: 1}) + app.DistrKeeper.SetValidatorHistoricalRewards(ctx, addrVal2, 18446744073709551615, distribution.ValidatorHistoricalRewards{ReferenceCount: 1}) val2 := types.NewValidator(addrVal2, pk2, types.Description{}) app.StakingKeeper.SetValidator(ctx, val2) @@ -351,7 +355,7 @@ func TestQueryDelegation(t *testing.T) { require.Equal(t, delegation.DelegatorAddress, delegationsRes[0].DelegatorAddress) require.Equal(t, sdk.NewCoin(sdk.DefaultBondDenom, delegation.Shares.TruncateInt()), delegationsRes[0].Balance) - // Query unbonging delegation + // Query unbonding delegation unbondingTokens := sdk.TokensFromConsensusPower(10) _, err = app.StakingKeeper.Undelegate(ctx, addrAcc2, val1.OperatorAddress, unbondingTokens.ToDec()) require.NoError(t, err) From 06c144805d71001a7bffc3aea1ae02c028e54c1c Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Thu, 20 Feb 2020 17:30:45 +0100 Subject: [PATCH 164/529] rename function --- x/staking/keeper/querier_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/staking/keeper/querier_test.go b/x/staking/keeper/querier_test.go index 0289bb102cf3..948529173198 100644 --- a/x/staking/keeper/querier_test.go +++ b/x/staking/keeper/querier_test.go @@ -205,7 +205,7 @@ func TestQueryValidators(t *testing.T) { } } -func TestQueryDelegations(t *testing.T) { +func TestQueryDelegation(t *testing.T) { cdc := codec.New() app := simapp.Setup(false) ctx := app.BaseApp.NewContext(false, abci.Header{}) From 32a27afbd5fc26eeccfe1af5986b452321e7b3a3 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Thu, 20 Feb 2020 17:58:17 +0100 Subject: [PATCH 165/529] make TestQueryRedelegations pass with simapp --- x/staking/keeper/old_querier_test.go | 285 --------------------------- x/staking/keeper/querier_test.go | 143 +++++++------- 2 files changed, 75 insertions(+), 353 deletions(-) diff --git a/x/staking/keeper/old_querier_test.go b/x/staking/keeper/old_querier_test.go index 3203755cc6ab..15074cfa6563 100644 --- a/x/staking/keeper/old_querier_test.go +++ b/x/staking/keeper/old_querier_test.go @@ -17,291 +17,6 @@ var ( pk1, pk2 = PKs[0], PKs[1] ) -func TestQueryDelegation(t *testing.T) { - cdc := codec.New() - ctx, _, _, keeper, _ := CreateTestInput(t, false, 10000) - params := keeper.GetParams(ctx) - - // Create Validators and Delegation - val1 := types.NewValidator(addrVal1, pk1, types.Description{}) - keeper.SetValidator(ctx, val1) - keeper.SetValidatorByPowerIndex(ctx, val1) - - val2 := types.NewValidator(addrVal2, pk2, types.Description{}) - keeper.SetValidator(ctx, val2) - keeper.SetValidatorByPowerIndex(ctx, val2) - - delTokens := sdk.TokensFromConsensusPower(20) - keeper.Delegate(ctx, addrAcc2, delTokens, sdk.Unbonded, val1, true) - - // apply TM updates - keeper.ApplyAndReturnValidatorSetUpdates(ctx) - - // Query Delegator bonded validators - queryParams := types.NewQueryDelegatorParams(addrAcc2) - bz, errRes := cdc.MarshalJSON(queryParams) - require.NoError(t, errRes) - - query := abci.RequestQuery{ - Path: "/custom/staking/delegatorValidators", - Data: bz, - } - - delValidators := keeper.GetDelegatorValidators(ctx, addrAcc2, params.MaxValidators) - - res, err := queryDelegatorValidators(ctx, query, keeper) - require.NoError(t, err) - - var validatorsResp []types.Validator - errRes = cdc.UnmarshalJSON(res, &validatorsResp) - require.NoError(t, errRes) - - require.Equal(t, len(delValidators), len(validatorsResp)) - require.ElementsMatch(t, delValidators, validatorsResp) - - // error unknown request - query.Data = bz[:len(bz)-1] - - _, err = queryDelegatorValidators(ctx, query, keeper) - require.Error(t, err) - - // Query bonded validator - queryBondParams := types.NewQueryBondsParams(addrAcc2, addrVal1) - bz, errRes = cdc.MarshalJSON(queryBondParams) - require.NoError(t, errRes) - - query = abci.RequestQuery{ - Path: "/custom/staking/delegatorValidator", - Data: bz, - } - - res, err = queryDelegatorValidator(ctx, query, keeper) - require.NoError(t, err) - - var validator types.Validator - errRes = cdc.UnmarshalJSON(res, &validator) - require.NoError(t, errRes) - - require.Equal(t, delValidators[0], validator) - - // error unknown request - query.Data = bz[:len(bz)-1] - - _, err = queryDelegatorValidator(ctx, query, keeper) - require.Error(t, err) - - // Query delegation - - query = abci.RequestQuery{ - Path: "/custom/staking/delegation", - Data: bz, - } - - delegation, found := keeper.GetDelegation(ctx, addrAcc2, addrVal1) - require.True(t, found) - - res, err = queryDelegation(ctx, query, keeper) - require.NoError(t, err) - - var delegationRes types.DelegationResponse - errRes = cdc.UnmarshalJSON(res, &delegationRes) - require.NoError(t, errRes) - - require.Equal(t, delegation.ValidatorAddress, delegationRes.ValidatorAddress) - require.Equal(t, delegation.DelegatorAddress, delegationRes.DelegatorAddress) - require.Equal(t, sdk.NewCoin(sdk.DefaultBondDenom, delegation.Shares.TruncateInt()), delegationRes.Balance) - - // Query Delegator Delegations - query = abci.RequestQuery{ - Path: "/custom/staking/delegatorDelegations", - Data: bz, - } - - res, err = queryDelegatorDelegations(ctx, query, keeper) - require.NoError(t, err) - - var delegatorDelegations types.DelegationResponses - errRes = cdc.UnmarshalJSON(res, &delegatorDelegations) - require.NoError(t, errRes) - require.Len(t, delegatorDelegations, 1) - require.Equal(t, delegation.ValidatorAddress, delegatorDelegations[0].ValidatorAddress) - require.Equal(t, delegation.DelegatorAddress, delegatorDelegations[0].DelegatorAddress) - require.Equal(t, sdk.NewCoin(sdk.DefaultBondDenom, delegation.Shares.TruncateInt()), delegatorDelegations[0].Balance) - - // error unknown request - query.Data = bz[:len(bz)-1] - - _, err = queryDelegation(ctx, query, keeper) - require.Error(t, err) - - // Query validator delegations - - bz, errRes = cdc.MarshalJSON(types.NewQueryValidatorParams(addrVal1)) - require.NoError(t, errRes) - - query = abci.RequestQuery{ - Path: "custom/staking/validatorDelegations", - Data: bz, - } - - res, err = queryValidatorDelegations(ctx, query, keeper) - require.NoError(t, err) - - var delegationsRes types.DelegationResponses - errRes = cdc.UnmarshalJSON(res, &delegationsRes) - require.NoError(t, errRes) - require.Len(t, delegatorDelegations, 1) - require.Equal(t, delegation.ValidatorAddress, delegationsRes[0].ValidatorAddress) - require.Equal(t, delegation.DelegatorAddress, delegationsRes[0].DelegatorAddress) - require.Equal(t, sdk.NewCoin(sdk.DefaultBondDenom, delegation.Shares.TruncateInt()), delegationsRes[0].Balance) - - // Query unbonging delegation - unbondingTokens := sdk.TokensFromConsensusPower(10) - _, err = keeper.Undelegate(ctx, addrAcc2, val1.OperatorAddress, unbondingTokens.ToDec()) - require.NoError(t, err) - - queryBondParams = types.NewQueryBondsParams(addrAcc2, addrVal1) - bz, errRes = cdc.MarshalJSON(queryBondParams) - require.NoError(t, errRes) - - query = abci.RequestQuery{ - Path: "/custom/staking/unbondingDelegation", - Data: bz, - } - - unbond, found := keeper.GetUnbondingDelegation(ctx, addrAcc2, addrVal1) - require.True(t, found) - - res, err = queryUnbondingDelegation(ctx, query, keeper) - require.NoError(t, err) - - var unbondRes types.UnbondingDelegation - errRes = cdc.UnmarshalJSON(res, &unbondRes) - require.NoError(t, errRes) - - require.Equal(t, unbond, unbondRes) - - // error unknown request - query.Data = bz[:len(bz)-1] - - _, err = queryUnbondingDelegation(ctx, query, keeper) - require.Error(t, err) - - // Query Delegator Delegations - - query = abci.RequestQuery{ - Path: "/custom/staking/delegatorUnbondingDelegations", - Data: bz, - } - - res, err = queryDelegatorUnbondingDelegations(ctx, query, keeper) - require.NoError(t, err) - - var delegatorUbds []types.UnbondingDelegation - errRes = cdc.UnmarshalJSON(res, &delegatorUbds) - require.NoError(t, errRes) - require.Equal(t, unbond, delegatorUbds[0]) - - // error unknown request - query.Data = bz[:len(bz)-1] - - _, err = queryDelegatorUnbondingDelegations(ctx, query, keeper) - require.Error(t, err) - - // Query redelegation - redelegationTokens := sdk.TokensFromConsensusPower(10) - _, err = keeper.BeginRedelegation(ctx, addrAcc2, val1.OperatorAddress, - val2.OperatorAddress, redelegationTokens.ToDec()) - require.NoError(t, err) - redel, found := keeper.GetRedelegation(ctx, addrAcc2, val1.OperatorAddress, val2.OperatorAddress) - require.True(t, found) - - bz, errRes = cdc.MarshalJSON(types.NewQueryRedelegationParams(addrAcc2, val1.OperatorAddress, val2.OperatorAddress)) - require.NoError(t, errRes) - - query = abci.RequestQuery{ - Path: "/custom/staking/redelegations", - Data: bz, - } - - res, err = queryRedelegations(ctx, query, keeper) - require.NoError(t, err) - - var redelRes types.RedelegationResponses - errRes = cdc.UnmarshalJSON(res, &redelRes) - require.NoError(t, errRes) - require.Len(t, redelRes, 1) - require.Equal(t, redel.DelegatorAddress, redelRes[0].DelegatorAddress) - require.Equal(t, redel.ValidatorSrcAddress, redelRes[0].ValidatorSrcAddress) - require.Equal(t, redel.ValidatorDstAddress, redelRes[0].ValidatorDstAddress) - require.Len(t, redel.Entries, len(redelRes[0].Entries)) -} - -func TestQueryRedelegations(t *testing.T) { - cdc := codec.New() - ctx, _, _, keeper, _ := CreateTestInput(t, false, 10000) - - // Create Validators and Delegation - val1 := types.NewValidator(addrVal1, pk1, types.Description{}) - val2 := types.NewValidator(addrVal2, pk2, types.Description{}) - keeper.SetValidator(ctx, val1) - keeper.SetValidator(ctx, val2) - - delAmount := sdk.TokensFromConsensusPower(100) - keeper.Delegate(ctx, addrAcc2, delAmount, sdk.Unbonded, val1, true) - _ = keeper.ApplyAndReturnValidatorSetUpdates(ctx) - - rdAmount := sdk.TokensFromConsensusPower(20) - keeper.BeginRedelegation(ctx, addrAcc2, val1.GetOperator(), val2.GetOperator(), rdAmount.ToDec()) - keeper.ApplyAndReturnValidatorSetUpdates(ctx) - - redel, found := keeper.GetRedelegation(ctx, addrAcc2, val1.OperatorAddress, val2.OperatorAddress) - require.True(t, found) - - // delegator redelegations - queryDelegatorParams := types.NewQueryDelegatorParams(addrAcc2) - bz, errRes := cdc.MarshalJSON(queryDelegatorParams) - require.NoError(t, errRes) - - query := abci.RequestQuery{ - Path: "/custom/staking/redelegations", - Data: bz, - } - - res, err := queryRedelegations(ctx, query, keeper) - require.NoError(t, err) - - var redelRes types.RedelegationResponses - errRes = cdc.UnmarshalJSON(res, &redelRes) - require.NoError(t, errRes) - require.Len(t, redelRes, 1) - require.Equal(t, redel.DelegatorAddress, redelRes[0].DelegatorAddress) - require.Equal(t, redel.ValidatorSrcAddress, redelRes[0].ValidatorSrcAddress) - require.Equal(t, redel.ValidatorDstAddress, redelRes[0].ValidatorDstAddress) - require.Len(t, redel.Entries, len(redelRes[0].Entries)) - - // validator redelegations - queryValidatorParams := types.NewQueryValidatorParams(val1.GetOperator()) - bz, errRes = cdc.MarshalJSON(queryValidatorParams) - require.NoError(t, errRes) - - query = abci.RequestQuery{ - Path: "/custom/staking/redelegations", - Data: bz, - } - - res, err = queryRedelegations(ctx, query, keeper) - require.NoError(t, err) - - errRes = cdc.UnmarshalJSON(res, &redelRes) - require.NoError(t, errRes) - require.Len(t, redelRes, 1) - require.Equal(t, redel.DelegatorAddress, redelRes[0].DelegatorAddress) - require.Equal(t, redel.ValidatorSrcAddress, redelRes[0].ValidatorSrcAddress) - require.Equal(t, redel.ValidatorDstAddress, redelRes[0].ValidatorDstAddress) - require.Len(t, redel.Entries, len(redelRes[0].Entries)) -} - func TestQueryUnbondingDelegation(t *testing.T) { cdc := codec.New() ctx, _, _, keeper, _ := CreateTestInput(t, false, 10000) diff --git a/x/staking/keeper/querier_test.go b/x/staking/keeper/querier_test.go index 948529173198..7008547c4a62 100644 --- a/x/staking/keeper/querier_test.go +++ b/x/staking/keeper/querier_test.go @@ -4,8 +4,6 @@ import ( "fmt" "testing" - "github.com/cosmos/cosmos-sdk/x/distribution" - "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" @@ -13,6 +11,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/distribution" "github.com/cosmos/cosmos-sdk/x/staking" "github.com/cosmos/cosmos-sdk/x/staking/types" ) @@ -224,11 +223,11 @@ func TestQueryDelegation(t *testing.T) { app.StakingKeeper.SetValidator(ctx, val1) app.StakingKeeper.SetValidatorByPowerIndex(ctx, val1) app.DistrKeeper.SetValidatorHistoricalRewards(ctx, addrVal1, 18446744073709551615, distribution.ValidatorHistoricalRewards{ReferenceCount: 1}) - app.DistrKeeper.SetValidatorHistoricalRewards(ctx, addrVal2, 18446744073709551615, distribution.ValidatorHistoricalRewards{ReferenceCount: 1}) val2 := types.NewValidator(addrVal2, pk2, types.Description{}) app.StakingKeeper.SetValidator(ctx, val2) app.StakingKeeper.SetValidatorByPowerIndex(ctx, val2) + app.DistrKeeper.SetValidatorHistoricalRewards(ctx, addrVal2, 18446744073709551615, distribution.ValidatorHistoricalRewards{ReferenceCount: 1}) delTokens := sdk.TokensFromConsensusPower(20) _, err := app.StakingKeeper.Delegate(ctx, addrAcc2, delTokens, sdk.Unbonded, val1, true) @@ -437,71 +436,79 @@ func TestQueryDelegation(t *testing.T) { require.Len(t, redel.Entries, len(redelRes[0].Entries)) } -//func TestQueryRedelegations(t *testing.T) { -// cdc := codec.New() -// ctx, _, _, keeper, _ := CreateTestInput(t, false, 10000) -// -// // Create Validators and Delegation -// val1 := types.NewValidator(addrVal1, pk1, types.Description{}) -// val2 := types.NewValidator(addrVal2, pk2, types.Description{}) -// keeper.SetValidator(ctx, val1) -// keeper.SetValidator(ctx, val2) -// -// delAmount := sdk.TokensFromConsensusPower(100) -// keeper.Delegate(ctx, addrAcc2, delAmount, sdk.Unbonded, val1, true) -// _ = keeper.ApplyAndReturnValidatorSetUpdates(ctx) -// -// rdAmount := sdk.TokensFromConsensusPower(20) -// keeper.BeginRedelegation(ctx, addrAcc2, val1.GetOperator(), val2.GetOperator(), rdAmount.ToDec()) -// keeper.ApplyAndReturnValidatorSetUpdates(ctx) -// -// redel, found := keeper.GetRedelegation(ctx, addrAcc2, val1.OperatorAddress, val2.OperatorAddress) -// require.True(t, found) -// -// // delegator redelegations -// queryDelegatorParams := types.NewQueryDelegatorParams(addrAcc2) -// bz, errRes := cdc.MarshalJSON(queryDelegatorParams) -// require.NoError(t, errRes) -// -// query := abci.RequestQuery{ -// Path: "/custom/staking/redelegations", -// Data: bz, -// } -// -// res, err := queryRedelegations(ctx, query, keeper) -// require.NoError(t, err) -// -// var redelRes types.RedelegationResponses -// errRes = cdc.UnmarshalJSON(res, &redelRes) -// require.NoError(t, errRes) -// require.Len(t, redelRes, 1) -// require.Equal(t, redel.DelegatorAddress, redelRes[0].DelegatorAddress) -// require.Equal(t, redel.ValidatorSrcAddress, redelRes[0].ValidatorSrcAddress) -// require.Equal(t, redel.ValidatorDstAddress, redelRes[0].ValidatorDstAddress) -// require.Len(t, redel.Entries, len(redelRes[0].Entries)) -// -// // validator redelegations -// queryValidatorParams := types.NewQueryValidatorParams(val1.GetOperator()) -// bz, errRes = cdc.MarshalJSON(queryValidatorParams) -// require.NoError(t, errRes) -// -// query = abci.RequestQuery{ -// Path: "/custom/staking/redelegations", -// Data: bz, -// } -// -// res, err = queryRedelegations(ctx, query, keeper) -// require.NoError(t, err) -// -// errRes = cdc.UnmarshalJSON(res, &redelRes) -// require.NoError(t, errRes) -// require.Len(t, redelRes, 1) -// require.Equal(t, redel.DelegatorAddress, redelRes[0].DelegatorAddress) -// require.Equal(t, redel.ValidatorSrcAddress, redelRes[0].ValidatorSrcAddress) -// require.Equal(t, redel.ValidatorDstAddress, redelRes[0].ValidatorDstAddress) -// require.Len(t, redel.Entries, len(redelRes[0].Entries)) -//} -// +func TestQueryRedelegations(t *testing.T) { + cdc := codec.New() + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + querier := staking.NewQuerier(app.StakingKeeper) + + addrs := simapp.AddTestAddrs(app, ctx, 2, sdk.TokensFromConsensusPower(10000)) + addrAcc1, addrAcc2 := addrs[0], addrs[1] + addrVal1, addrVal2 := sdk.ValAddress(addrAcc1), sdk.ValAddress(addrAcc2) + + // Create Validators and Delegation + val1 := types.NewValidator(addrVal1, PKs[0], types.Description{}) + val2 := types.NewValidator(addrVal2, PKs[1], types.Description{}) + app.StakingKeeper.SetValidator(ctx, val1) + app.StakingKeeper.SetValidator(ctx, val2) + app.DistrKeeper.SetValidatorHistoricalRewards(ctx, addrVal1, 18446744073709551615, distribution.ValidatorHistoricalRewards{ReferenceCount: 1}) + app.DistrKeeper.SetValidatorHistoricalRewards(ctx, addrVal2, 18446744073709551615, distribution.ValidatorHistoricalRewards{ReferenceCount: 1}) + + delAmount := sdk.TokensFromConsensusPower(100) + app.StakingKeeper.Delegate(ctx, addrAcc2, delAmount, sdk.Unbonded, val1, true) + _ = app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + + rdAmount := sdk.TokensFromConsensusPower(20) + app.StakingKeeper.BeginRedelegation(ctx, addrAcc2, val1.GetOperator(), val2.GetOperator(), rdAmount.ToDec()) + app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + + redel, found := app.StakingKeeper.GetRedelegation(ctx, addrAcc2, val1.OperatorAddress, val2.OperatorAddress) + require.True(t, found) + + // delegator redelegations + queryDelegatorParams := types.NewQueryDelegatorParams(addrAcc2) + bz, errRes := cdc.MarshalJSON(queryDelegatorParams) + require.NoError(t, errRes) + + query := abci.RequestQuery{ + Path: "/custom/staking/redelegations", + Data: bz, + } + + res, err := querier(ctx, []string{types.QueryRedelegations}, query) + require.NoError(t, err) + + var redelRes types.RedelegationResponses + errRes = cdc.UnmarshalJSON(res, &redelRes) + require.NoError(t, errRes) + require.Len(t, redelRes, 1) + require.Equal(t, redel.DelegatorAddress, redelRes[0].DelegatorAddress) + require.Equal(t, redel.ValidatorSrcAddress, redelRes[0].ValidatorSrcAddress) + require.Equal(t, redel.ValidatorDstAddress, redelRes[0].ValidatorDstAddress) + require.Len(t, redel.Entries, len(redelRes[0].Entries)) + + // validator redelegations + queryValidatorParams := types.NewQueryValidatorParams(val1.GetOperator()) + bz, errRes = cdc.MarshalJSON(queryValidatorParams) + require.NoError(t, errRes) + + query = abci.RequestQuery{ + Path: "/custom/staking/redelegations", + Data: bz, + } + + res, err = querier(ctx, []string{types.QueryRedelegations}, query) + require.NoError(t, err) + + errRes = cdc.UnmarshalJSON(res, &redelRes) + require.NoError(t, errRes) + require.Len(t, redelRes, 1) + require.Equal(t, redel.DelegatorAddress, redelRes[0].DelegatorAddress) + require.Equal(t, redel.ValidatorSrcAddress, redelRes[0].ValidatorSrcAddress) + require.Equal(t, redel.ValidatorDstAddress, redelRes[0].ValidatorDstAddress) + require.Len(t, redel.Entries, len(redelRes[0].Entries)) +} + //func TestQueryUnbondingDelegation(t *testing.T) { // cdc := codec.New() // ctx, _, _, keeper, _ := CreateTestInput(t, false, 10000) From fdba5b5904278bb8e79130ad3b34111e56005b6f Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Thu, 20 Feb 2020 18:10:37 +0100 Subject: [PATCH 166/529] finish keeper refactor for querier in staking using simapp --- x/staking/keeper/old_querier_test.go | 151 --------------- x/staking/keeper/querier_test.go | 277 ++++++++++++++------------- 2 files changed, 145 insertions(+), 283 deletions(-) delete mode 100644 x/staking/keeper/old_querier_test.go diff --git a/x/staking/keeper/old_querier_test.go b/x/staking/keeper/old_querier_test.go deleted file mode 100644 index 15074cfa6563..000000000000 --- a/x/staking/keeper/old_querier_test.go +++ /dev/null @@ -1,151 +0,0 @@ -package keeper - -import ( - "testing" - - abci "github.com/tendermint/tendermint/abci/types" - - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/stretchr/testify/require" -) - -var ( - addrAcc1, addrAcc2 = Addrs[0], Addrs[1] - addrVal1, addrVal2 = sdk.ValAddress(Addrs[0]), sdk.ValAddress(Addrs[1]) - pk1, pk2 = PKs[0], PKs[1] -) - -func TestQueryUnbondingDelegation(t *testing.T) { - cdc := codec.New() - ctx, _, _, keeper, _ := CreateTestInput(t, false, 10000) - - // Create Validators and Delegation - val1 := types.NewValidator(addrVal1, pk1, types.Description{}) - keeper.SetValidator(ctx, val1) - - // delegate - delAmount := sdk.TokensFromConsensusPower(100) - _, err := keeper.Delegate(ctx, addrAcc1, delAmount, sdk.Unbonded, val1, true) - require.NoError(t, err) - _ = keeper.ApplyAndReturnValidatorSetUpdates(ctx) - - // undelegate - undelAmount := sdk.TokensFromConsensusPower(20) - _, err = keeper.Undelegate(ctx, addrAcc1, val1.GetOperator(), undelAmount.ToDec()) - require.NoError(t, err) - keeper.ApplyAndReturnValidatorSetUpdates(ctx) - - _, found := keeper.GetUnbondingDelegation(ctx, addrAcc1, val1.OperatorAddress) - require.True(t, found) - - // - // found: query unbonding delegation by delegator and validator - // - queryValidatorParams := types.NewQueryBondsParams(addrAcc1, val1.GetOperator()) - bz, errRes := cdc.MarshalJSON(queryValidatorParams) - require.NoError(t, errRes) - query := abci.RequestQuery{ - Path: "/custom/staking/unbondingDelegation", - Data: bz, - } - res, err := queryUnbondingDelegation(ctx, query, keeper) - require.NoError(t, err) - require.NotNil(t, res) - var ubDel types.UnbondingDelegation - require.NoError(t, cdc.UnmarshalJSON(res, &ubDel)) - require.Equal(t, addrAcc1, ubDel.DelegatorAddress) - require.Equal(t, val1.OperatorAddress, ubDel.ValidatorAddress) - require.Equal(t, 1, len(ubDel.Entries)) - - // - // not found: query unbonding delegation by delegator and validator - // - queryValidatorParams = types.NewQueryBondsParams(addrAcc2, val1.GetOperator()) - bz, errRes = cdc.MarshalJSON(queryValidatorParams) - require.NoError(t, errRes) - query = abci.RequestQuery{ - Path: "/custom/staking/unbondingDelegation", - Data: bz, - } - _, err = queryUnbondingDelegation(ctx, query, keeper) - require.Error(t, err) - - // - // found: query unbonding delegation by delegator and validator - // - queryDelegatorParams := types.NewQueryDelegatorParams(addrAcc1) - bz, errRes = cdc.MarshalJSON(queryDelegatorParams) - require.NoError(t, errRes) - query = abci.RequestQuery{ - Path: "/custom/staking/delegatorUnbondingDelegations", - Data: bz, - } - res, err = queryDelegatorUnbondingDelegations(ctx, query, keeper) - require.NoError(t, err) - require.NotNil(t, res) - var ubDels []types.UnbondingDelegation - require.NoError(t, cdc.UnmarshalJSON(res, &ubDels)) - require.Equal(t, 1, len(ubDels)) - require.Equal(t, addrAcc1, ubDels[0].DelegatorAddress) - require.Equal(t, val1.OperatorAddress, ubDels[0].ValidatorAddress) - - // - // not found: query unbonding delegation by delegator and validator - // - queryDelegatorParams = types.NewQueryDelegatorParams(addrAcc2) - bz, errRes = cdc.MarshalJSON(queryDelegatorParams) - require.NoError(t, errRes) - query = abci.RequestQuery{ - Path: "/custom/staking/delegatorUnbondingDelegations", - Data: bz, - } - res, err = queryDelegatorUnbondingDelegations(ctx, query, keeper) - require.NoError(t, err) - require.NotNil(t, res) - require.NoError(t, cdc.UnmarshalJSON(res, &ubDels)) - require.Equal(t, 0, len(ubDels)) -} - -func TestQueryHistoricalInfo(t *testing.T) { - cdc := codec.New() - ctx, _, _, keeper, _ := CreateTestInput(t, false, 10000) - - // Create Validators and Delegation - val1 := types.NewValidator(addrVal1, pk1, types.Description{}) - val2 := types.NewValidator(addrVal2, pk2, types.Description{}) - vals := []types.Validator{val1, val2} - keeper.SetValidator(ctx, val1) - keeper.SetValidator(ctx, val2) - - header := abci.Header{ - ChainID: "HelloChain", - Height: 5, - } - hi := types.NewHistoricalInfo(header, vals) - keeper.SetHistoricalInfo(ctx, 5, hi) - - queryHistoricalParams := types.NewQueryHistoricalInfoParams(4) - bz, errRes := cdc.MarshalJSON(queryHistoricalParams) - require.NoError(t, errRes) - query := abci.RequestQuery{ - Path: "/custom/staking/historicalInfo", - Data: bz, - } - res, err := queryHistoricalInfo(ctx, query, keeper) - require.Error(t, err, "Invalid query passed") - require.Nil(t, res, "Invalid query returned non-nil result") - - queryHistoricalParams = types.NewQueryHistoricalInfoParams(5) - bz, errRes = cdc.MarshalJSON(queryHistoricalParams) - require.NoError(t, errRes) - query.Data = bz - res, err = queryHistoricalInfo(ctx, query, keeper) - require.NoError(t, err, "Valid query passed") - require.NotNil(t, res, "Valid query returned nil result") - - var recv types.HistoricalInfo - require.NoError(t, cdc.UnmarshalJSON(res, &recv)) - require.Equal(t, hi, recv, "HistoricalInfo query returned wrong result") -} diff --git a/x/staking/keeper/querier_test.go b/x/staking/keeper/querier_test.go index 7008547c4a62..19a260d531da 100644 --- a/x/staking/keeper/querier_test.go +++ b/x/staking/keeper/querier_test.go @@ -509,135 +509,148 @@ func TestQueryRedelegations(t *testing.T) { require.Len(t, redel.Entries, len(redelRes[0].Entries)) } -//func TestQueryUnbondingDelegation(t *testing.T) { -// cdc := codec.New() -// ctx, _, _, keeper, _ := CreateTestInput(t, false, 10000) -// -// // Create Validators and Delegation -// val1 := types.NewValidator(addrVal1, pk1, types.Description{}) -// keeper.SetValidator(ctx, val1) -// -// // delegate -// delAmount := sdk.TokensFromConsensusPower(100) -// _, err := keeper.Delegate(ctx, addrAcc1, delAmount, sdk.Unbonded, val1, true) -// require.NoError(t, err) -// _ = keeper.ApplyAndReturnValidatorSetUpdates(ctx) -// -// // undelegate -// undelAmount := sdk.TokensFromConsensusPower(20) -// _, err = keeper.Undelegate(ctx, addrAcc1, val1.GetOperator(), undelAmount.ToDec()) -// require.NoError(t, err) -// keeper.ApplyAndReturnValidatorSetUpdates(ctx) -// -// _, found := keeper.GetUnbondingDelegation(ctx, addrAcc1, val1.OperatorAddress) -// require.True(t, found) -// -// // -// // found: query unbonding delegation by delegator and validator -// // -// queryValidatorParams := types.NewQueryBondsParams(addrAcc1, val1.GetOperator()) -// bz, errRes := cdc.MarshalJSON(queryValidatorParams) -// require.NoError(t, errRes) -// query := abci.RequestQuery{ -// Path: "/custom/staking/unbondingDelegation", -// Data: bz, -// } -// res, err := queryUnbondingDelegation(ctx, query, keeper) -// require.NoError(t, err) -// require.NotNil(t, res) -// var ubDel types.UnbondingDelegation -// require.NoError(t, cdc.UnmarshalJSON(res, &ubDel)) -// require.Equal(t, addrAcc1, ubDel.DelegatorAddress) -// require.Equal(t, val1.OperatorAddress, ubDel.ValidatorAddress) -// require.Equal(t, 1, len(ubDel.Entries)) -// -// // -// // not found: query unbonding delegation by delegator and validator -// // -// queryValidatorParams = types.NewQueryBondsParams(addrAcc2, val1.GetOperator()) -// bz, errRes = cdc.MarshalJSON(queryValidatorParams) -// require.NoError(t, errRes) -// query = abci.RequestQuery{ -// Path: "/custom/staking/unbondingDelegation", -// Data: bz, -// } -// _, err = queryUnbondingDelegation(ctx, query, keeper) -// require.Error(t, err) -// -// // -// // found: query unbonding delegation by delegator and validator -// // -// queryDelegatorParams := types.NewQueryDelegatorParams(addrAcc1) -// bz, errRes = cdc.MarshalJSON(queryDelegatorParams) -// require.NoError(t, errRes) -// query = abci.RequestQuery{ -// Path: "/custom/staking/delegatorUnbondingDelegations", -// Data: bz, -// } -// res, err = queryDelegatorUnbondingDelegations(ctx, query, keeper) -// require.NoError(t, err) -// require.NotNil(t, res) -// var ubDels []types.UnbondingDelegation -// require.NoError(t, cdc.UnmarshalJSON(res, &ubDels)) -// require.Equal(t, 1, len(ubDels)) -// require.Equal(t, addrAcc1, ubDels[0].DelegatorAddress) -// require.Equal(t, val1.OperatorAddress, ubDels[0].ValidatorAddress) -// -// // -// // not found: query unbonding delegation by delegator and validator -// // -// queryDelegatorParams = types.NewQueryDelegatorParams(addrAcc2) -// bz, errRes = cdc.MarshalJSON(queryDelegatorParams) -// require.NoError(t, errRes) -// query = abci.RequestQuery{ -// Path: "/custom/staking/delegatorUnbondingDelegations", -// Data: bz, -// } -// res, err = queryDelegatorUnbondingDelegations(ctx, query, keeper) -// require.NoError(t, err) -// require.NotNil(t, res) -// require.NoError(t, cdc.UnmarshalJSON(res, &ubDels)) -// require.Equal(t, 0, len(ubDels)) -//} -// -//func TestQueryHistoricalInfo(t *testing.T) { -// cdc := codec.New() -// ctx, _, _, keeper, _ := CreateTestInput(t, false, 10000) -// -// // Create Validators and Delegation -// val1 := types.NewValidator(addrVal1, pk1, types.Description{}) -// val2 := types.NewValidator(addrVal2, pk2, types.Description{}) -// vals := []types.Validator{val1, val2} -// keeper.SetValidator(ctx, val1) -// keeper.SetValidator(ctx, val2) -// -// header := abci.Header{ -// ChainID: "HelloChain", -// Height: 5, -// } -// hi := types.NewHistoricalInfo(header, vals) -// keeper.SetHistoricalInfo(ctx, 5, hi) -// -// queryHistoricalParams := types.NewQueryHistoricalInfoParams(4) -// bz, errRes := cdc.MarshalJSON(queryHistoricalParams) -// require.NoError(t, errRes) -// query := abci.RequestQuery{ -// Path: "/custom/staking/historicalInfo", -// Data: bz, -// } -// res, err := queryHistoricalInfo(ctx, query, keeper) -// require.Error(t, err, "Invalid query passed") -// require.Nil(t, res, "Invalid query returned non-nil result") -// -// queryHistoricalParams = types.NewQueryHistoricalInfoParams(5) -// bz, errRes = cdc.MarshalJSON(queryHistoricalParams) -// require.NoError(t, errRes) -// query.Data = bz -// res, err = queryHistoricalInfo(ctx, query, keeper) -// require.NoError(t, err, "Valid query passed") -// require.NotNil(t, res, "Valid query returned nil result") -// -// var recv types.HistoricalInfo -// require.NoError(t, cdc.UnmarshalJSON(res, &recv)) -// require.Equal(t, hi, recv, "HistoricalInfo query returned wrong result") -//} +func TestQueryUnbondingDelegation(t *testing.T) { + cdc := codec.New() + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + querier := staking.NewQuerier(app.StakingKeeper) + + addrs := simapp.AddTestAddrs(app, ctx, 2, sdk.TokensFromConsensusPower(10000)) + addrAcc1, addrAcc2 := addrs[0], addrs[1] + addrVal1 := sdk.ValAddress(addrAcc1) + + // Create Validators and Delegation + val1 := types.NewValidator(addrVal1, PKs[0], types.Description{}) + app.StakingKeeper.SetValidator(ctx, val1) + app.DistrKeeper.SetValidatorHistoricalRewards(ctx, addrVal1, 18446744073709551615, distribution.ValidatorHistoricalRewards{ReferenceCount: 1}) + + // delegate + delAmount := sdk.TokensFromConsensusPower(100) + _, err := app.StakingKeeper.Delegate(ctx, addrAcc1, delAmount, sdk.Unbonded, val1, true) + require.NoError(t, err) + _ = app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + + // undelegate + undelAmount := sdk.TokensFromConsensusPower(20) + _, err = app.StakingKeeper.Undelegate(ctx, addrAcc1, val1.GetOperator(), undelAmount.ToDec()) + require.NoError(t, err) + app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + + _, found := app.StakingKeeper.GetUnbondingDelegation(ctx, addrAcc1, val1.OperatorAddress) + require.True(t, found) + + // + // found: query unbonding delegation by delegator and validator + // + queryValidatorParams := types.NewQueryBondsParams(addrAcc1, val1.GetOperator()) + bz, errRes := cdc.MarshalJSON(queryValidatorParams) + require.NoError(t, errRes) + query := abci.RequestQuery{ + Path: "/custom/staking/unbondingDelegation", + Data: bz, + } + res, err := querier(ctx, []string{types.QueryUnbondingDelegation}, query) + require.NoError(t, err) + require.NotNil(t, res) + var ubDel types.UnbondingDelegation + require.NoError(t, cdc.UnmarshalJSON(res, &ubDel)) + require.Equal(t, addrAcc1, ubDel.DelegatorAddress) + require.Equal(t, val1.OperatorAddress, ubDel.ValidatorAddress) + require.Equal(t, 1, len(ubDel.Entries)) + + // + // not found: query unbonding delegation by delegator and validator + // + queryValidatorParams = types.NewQueryBondsParams(addrAcc2, val1.GetOperator()) + bz, errRes = cdc.MarshalJSON(queryValidatorParams) + require.NoError(t, errRes) + query = abci.RequestQuery{ + Path: "/custom/staking/unbondingDelegation", + Data: bz, + } + res, err = querier(ctx, []string{types.QueryUnbondingDelegation}, query) + require.Error(t, err) + + // + // found: query unbonding delegation by delegator and validator + // + queryDelegatorParams := types.NewQueryDelegatorParams(addrAcc1) + bz, errRes = cdc.MarshalJSON(queryDelegatorParams) + require.NoError(t, errRes) + query = abci.RequestQuery{ + Path: "/custom/staking/delegatorUnbondingDelegations", + Data: bz, + } + res, err = querier(ctx, []string{types.QueryDelegatorUnbondingDelegations}, query) + require.NoError(t, err) + require.NotNil(t, res) + var ubDels []types.UnbondingDelegation + require.NoError(t, cdc.UnmarshalJSON(res, &ubDels)) + require.Equal(t, 1, len(ubDels)) + require.Equal(t, addrAcc1, ubDels[0].DelegatorAddress) + require.Equal(t, val1.OperatorAddress, ubDels[0].ValidatorAddress) + + // + // not found: query unbonding delegation by delegator and validator + // + queryDelegatorParams = types.NewQueryDelegatorParams(addrAcc2) + bz, errRes = cdc.MarshalJSON(queryDelegatorParams) + require.NoError(t, errRes) + query = abci.RequestQuery{ + Path: "/custom/staking/delegatorUnbondingDelegations", + Data: bz, + } + res, err = querier(ctx, []string{types.QueryDelegatorUnbondingDelegations}, query) + require.NoError(t, err) + require.NotNil(t, res) + require.NoError(t, cdc.UnmarshalJSON(res, &ubDels)) + require.Equal(t, 0, len(ubDels)) +} + +func TestQueryHistoricalInfo(t *testing.T) { + cdc := codec.New() + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + querier := staking.NewQuerier(app.StakingKeeper) + + addrs := simapp.AddTestAddrs(app, ctx, 2, sdk.TokensFromConsensusPower(10000)) + addrAcc1, addrAcc2 := addrs[0], addrs[1] + addrVal1, addrVal2 := sdk.ValAddress(addrAcc1), sdk.ValAddress(addrAcc2) + + // Create Validators and Delegation + val1 := types.NewValidator(addrVal1, PKs[0], types.Description{}) + val2 := types.NewValidator(addrVal2, PKs[1], types.Description{}) + vals := []types.Validator{val1, val2} + app.StakingKeeper.SetValidator(ctx, val1) + app.StakingKeeper.SetValidator(ctx, val2) + + header := abci.Header{ + ChainID: "HelloChain", + Height: 5, + } + hi := types.NewHistoricalInfo(header, vals) + app.StakingKeeper.SetHistoricalInfo(ctx, 5, hi) + + queryHistoricalParams := types.NewQueryHistoricalInfoParams(4) + bz, errRes := cdc.MarshalJSON(queryHistoricalParams) + require.NoError(t, errRes) + query := abci.RequestQuery{ + Path: "/custom/staking/historicalInfo", + Data: bz, + } + res, err := querier(ctx, []string{types.QueryHistoricalInfo}, query) + require.Error(t, err, "Invalid query passed") + require.Nil(t, res, "Invalid query returned non-nil result") + + queryHistoricalParams = types.NewQueryHistoricalInfoParams(5) + bz, errRes = cdc.MarshalJSON(queryHistoricalParams) + require.NoError(t, errRes) + query.Data = bz + res, err = querier(ctx, []string{types.QueryHistoricalInfo}, query) + require.NoError(t, err, "Valid query passed") + require.NotNil(t, res, "Valid query returned nil result") + + var recv types.HistoricalInfo + require.NoError(t, cdc.UnmarshalJSON(res, &recv)) + require.Equal(t, hi, recv, "HistoricalInfo query returned wrong result") +} From 0c0c251397dedfaad76160735418a9c76c0e6abb Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 21 Feb 2020 09:19:58 +0100 Subject: [PATCH 167/529] Bump github.com/spf13/cobra from 0.0.5 to 0.0.6 (#5687) Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 0.0.5 to 0.0.6. - [Release notes](https://github.com/spf13/cobra/releases) - [Commits](https://github.com/spf13/cobra/compare/0.0.5...v0.0.6) Signed-off-by: dependabot-preview[bot] --- go.mod | 2 +- go.sum | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index ace0be09309c..8c99717efd62 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/rakyll/statik v0.1.6 github.com/regen-network/cosmos-proto v0.1.1-0.20200213154359-02baa11ea7c2 github.com/spf13/afero v1.2.1 // indirect - github.com/spf13/cobra v0.0.5 + github.com/spf13/cobra v0.0.6 github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.6.2 diff --git a/go.sum b/go.sum index 7e0165233f77..a13a77447fa7 100644 --- a/go.sum +++ b/go.sum @@ -46,6 +46,7 @@ github.com/cosmos/ledger-cosmos-go v0.11.1/go.mod h1:J8//BsAGTo3OC/vDLjMRFLW6q0W github.com/cosmos/ledger-go v0.9.2 h1:Nnao/dLwaVTk1Q5U9THldpUMMXU94BOTWPddSmVB6pI= github.com/cosmos/ledger-go v0.9.2/go.mod h1:oZJ2hHAZROdlHiwTg4t7kP+GKIIkBT+o6c9QWFanOyI= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/danieljoos/wincred v1.0.2 h1:zf4bhty2iLuwgjgpraD2E9UbvO+fe54XXGJbOwe23fU= github.com/danieljoos/wincred v1.0.2/go.mod h1:SnuYRW9lp1oJrZX/dXJqr0cPK5gYXqx3EJbmjhLdK9U= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -203,6 +204,8 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= @@ -219,6 +222,8 @@ github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU github.com/spf13/cobra v0.0.1/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/cobra v0.0.6 h1:breEStsVwemnKh2/s6gMvSdMEkwW0sK8vGStnlVBMCs= +github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= @@ -226,6 +231,7 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.6.1/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k= github.com/spf13/viper v1.6.2 h1:7aKfF+e8/k68gda3LOjo5RxiUqddoFxVq4BKBPrxk5E= github.com/spf13/viper v1.6.2/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k= From 238928ed5037a0e5658a2287ba7c93f00c01f74f Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Fri, 21 Feb 2020 11:31:16 +0100 Subject: [PATCH 168/529] Merge PR #5688: Proto Option Updates --- types/types.pb.go | 83 ++++- types/types.proto | 28 +- x/auth/types/types.pb.go | 111 ++++-- x/auth/types/types.proto | 2 + x/bank/types/types.pb.go | 163 +++++++- x/bank/types/types.proto | 8 + x/crisis/internal/types/types.pb.go | 72 +++- x/crisis/internal/types/types.proto | 2 + x/distribution/types/types.pb.go | 559 ++++++++++++++++++++++++---- x/distribution/types/types.proto | 9 +- x/params/types/proposal/types.pb.go | 77 +++- x/params/types/proposal/types.proto | 3 +- x/slashing/types/types.pb.go | 86 +++-- x/slashing/types/types.proto | 3 +- x/staking/types/types.pb.go | 345 ++++++++++++----- x/staking/types/types.proto | 10 + x/supply/types/types.pb.go | 42 ++- x/supply/types/types.proto | 1 + 18 files changed, 1300 insertions(+), 304 deletions(-) diff --git a/types/types.pb.go b/types/types.pb.go index 4d2136c0a030..845bf267ba4f 100644 --- a/types/types.pb.go +++ b/types/types.pb.go @@ -250,28 +250,83 @@ func init() { func init() { proto.RegisterFile("types/types.proto", fileDescriptor_2c0f90c600ad7e2e) } var fileDescriptor_2c0f90c600ad7e2e = []byte{ - // 298 bytes of a gzipped FileDescriptorProto + // 305 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x2c, 0xa9, 0x2c, 0x48, 0x2d, 0xd6, 0x07, 0x93, 0x7a, 0x05, 0x45, 0xf9, 0x25, 0xf9, 0x42, 0xbc, 0xc9, 0xf9, 0xc5, 0xb9, 0xf9, 0xc5, 0xf1, 0xc5, 0x29, 0xd9, 0x7a, 0x65, 0x86, 0x52, 0x6a, 0x25, 0x19, 0x99, 0x45, 0x29, 0xf1, 0x05, 0x89, 0x45, 0x25, 0x95, 0xfa, 0x60, 0x15, 0xfa, 0xe9, 0xf9, 0xe9, 0xf9, 0x08, 0x16, - 0x44, 0x9b, 0x92, 0x23, 0x17, 0x8b, 0x73, 0x7e, 0x66, 0x9e, 0x90, 0x08, 0x17, 0x6b, 0x4a, 0x6a, + 0x44, 0x9b, 0x92, 0x3b, 0x17, 0x8b, 0x73, 0x7e, 0x66, 0x9e, 0x90, 0x08, 0x17, 0x6b, 0x4a, 0x6a, 0x5e, 0x7e, 0xae, 0x04, 0xa3, 0x02, 0xa3, 0x06, 0x67, 0x10, 0x84, 0x23, 0xa4, 0xcc, 0xc5, 0x96, 0x98, 0x9b, 0x5f, 0x9a, 0x57, 0x22, 0xc1, 0x04, 0x12, 0x76, 0xe2, 0x3e, 0x71, 0x4f, 0x9e, 0xe1, - 0xd6, 0x3d, 0x79, 0x66, 0xcf, 0xbc, 0x92, 0x20, 0xa8, 0x94, 0x92, 0x0b, 0x17, 0xbb, 0x4b, 0x6a, - 0x32, 0x39, 0xa6, 0xb8, 0xa4, 0x26, 0xc3, 0x4d, 0xd1, 0xe4, 0xe2, 0xf0, 0xcc, 0x2b, 0x09, 0x00, - 0xfb, 0x45, 0x96, 0x8b, 0x39, 0x33, 0xaf, 0x04, 0x62, 0x08, 0xaa, 0x9d, 0x20, 0x71, 0x90, 0x52, - 0x97, 0xd4, 0x64, 0xb8, 0xd2, 0x94, 0xd4, 0x64, 0x74, 0xa5, 0x20, 0x83, 0x41, 0xe2, 0x4a, 0x4e, - 0x5c, 0x3c, 0x61, 0x89, 0x39, 0x8e, 0x29, 0x29, 0x45, 0xa9, 0xc5, 0xc5, 0xa9, 0xc5, 0x42, 0x3a, - 0x5c, 0x9c, 0x89, 0x30, 0x8e, 0x04, 0xa3, 0x02, 0xb3, 0x06, 0x8f, 0x13, 0xdf, 0xaf, 0x7b, 0xf2, - 0x5c, 0x08, 0x45, 0x41, 0x08, 0x05, 0x56, 0x2c, 0x0d, 0x77, 0x14, 0x18, 0x9d, 0x5c, 0x6e, 0x3c, - 0x94, 0x63, 0x68, 0x78, 0x24, 0xc7, 0x70, 0xe2, 0x91, 0x1c, 0xe3, 0x85, 0x47, 0x72, 0x8c, 0x0f, - 0x1e, 0xc9, 0x31, 0x4e, 0x78, 0x2c, 0xc7, 0x70, 0xe1, 0xb1, 0x1c, 0xc3, 0x8d, 0xc7, 0x72, 0x0c, - 0x51, 0x4a, 0xe9, 0x99, 0x25, 0x19, 0xa5, 0x49, 0x7a, 0xc9, 0xf9, 0xb9, 0xfa, 0x90, 0x68, 0x80, - 0x52, 0xba, 0xc5, 0x29, 0xd9, 0x90, 0x58, 0x4a, 0x62, 0x03, 0x87, 0xb7, 0x31, 0x20, 0x00, 0x00, - 0xff, 0xff, 0xd6, 0x08, 0x09, 0x0f, 0xbb, 0x01, 0x00, 0x00, + 0xd6, 0x3d, 0x79, 0x66, 0xcf, 0xbc, 0x92, 0x20, 0xa8, 0x94, 0x15, 0xcb, 0x8b, 0x05, 0xf2, 0x8c, + 0x4a, 0x5e, 0x5c, 0xec, 0x2e, 0xa9, 0xc9, 0xe4, 0x98, 0xe5, 0x92, 0x9a, 0x8c, 0x66, 0x96, 0x26, + 0x17, 0x87, 0x67, 0x5e, 0x49, 0x00, 0xd8, 0x5f, 0xb2, 0x5c, 0xcc, 0x99, 0x79, 0x25, 0x10, 0xa3, + 0x50, 0xed, 0x07, 0x89, 0x83, 0x94, 0xba, 0xa4, 0x26, 0xc3, 0x95, 0xa6, 0xa4, 0x26, 0xa3, 0x2b, + 0x05, 0x19, 0x0f, 0x12, 0x57, 0x72, 0xe2, 0xe2, 0x09, 0x4b, 0xcc, 0x71, 0x4c, 0x49, 0x29, 0x4a, + 0x2d, 0x2e, 0x4e, 0x2d, 0x16, 0xd2, 0xe1, 0xe2, 0x4c, 0x84, 0x71, 0x24, 0x18, 0x15, 0x98, 0x35, + 0x78, 0x9c, 0xf8, 0x7e, 0xdd, 0x93, 0xe7, 0x42, 0x28, 0x0a, 0x42, 0x28, 0xb0, 0x62, 0x69, 0xb8, + 0xa3, 0xc0, 0xe8, 0xe4, 0x72, 0xe3, 0xa1, 0x1c, 0x43, 0xc3, 0x23, 0x39, 0x86, 0x13, 0x8f, 0xe4, + 0x18, 0x2f, 0x3c, 0x92, 0x63, 0x7c, 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, 0x39, 0x86, 0x0b, 0x8f, + 0xe5, 0x18, 0x6e, 0x3c, 0x96, 0x63, 0x88, 0x52, 0x4a, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, + 0xce, 0xcf, 0xd5, 0x87, 0x44, 0x09, 0x94, 0xd2, 0x2d, 0x4e, 0xc9, 0x86, 0xc4, 0x58, 0x12, 0x1b, + 0x38, 0xec, 0x8d, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0xa7, 0x40, 0xd2, 0x04, 0xc7, 0x01, 0x00, + 0x00, } +func (this *Coin) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*Coin) + if !ok { + that2, ok := that.(Coin) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Denom != that1.Denom { + return false + } + if !this.Amount.Equal(that1.Amount) { + return false + } + return true +} +func (this *DecCoin) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*DecCoin) + if !ok { + that2, ok := that.(DecCoin) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Denom != that1.Denom { + return false + } + if !this.Amount.Equal(that1.Amount) { + return false + } + return true +} func (m *Coin) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) diff --git a/types/types.proto b/types/types.proto index 590d21ccd9be..7fff608b9c9d 100644 --- a/types/types.proto +++ b/types/types.proto @@ -3,18 +3,19 @@ package cosmos_sdk.v1; import "third_party/proto/gogoproto/gogo.proto"; -option go_package = "github.com/cosmos/cosmos-sdk/types"; +option go_package = "github.com/cosmos/cosmos-sdk/types"; option (gogoproto.goproto_stringer_all) = false; -option (gogoproto.stringer_all) = false; +option (gogoproto.stringer_all) = false; // Coin defines a token with a denomination and an amount. // // NOTE: The amount field is an Int which implements the custom method // signatures required by gogoproto. message Coin { - string denom = 1; - string amount = 2 - [ (gogoproto.customtype) = "Int", (gogoproto.nullable) = false ]; + option (gogoproto.equal) = true; + + string denom = 1; + string amount = 2 [(gogoproto.customtype) = "Int", (gogoproto.nullable) = false]; } // DecCoin defines a token with a denomination and a decimal amount. @@ -22,26 +23,25 @@ message Coin { // NOTE: The amount field is an Dec which implements the custom method // signatures required by gogoproto. message DecCoin { - string denom = 1; - string amount = 2 - [ (gogoproto.customtype) = "Dec", (gogoproto.nullable) = false ]; + option (gogoproto.equal) = true; + + string denom = 1; + string amount = 2 [(gogoproto.customtype) = "Dec", (gogoproto.nullable) = false]; } // IntProto defines a Protobuf wrapper around an Int object. message IntProto { - string int = 1 - [ (gogoproto.customtype) = "Int", (gogoproto.nullable) = false ]; + string int = 1 [(gogoproto.customtype) = "Int", (gogoproto.nullable) = false]; } // DecProto defines a Protobuf wrapper around a Dec object. message DecProto { - string dec = 1 - [ (gogoproto.customtype) = "Dec", (gogoproto.nullable) = false ]; + string dec = 1 [(gogoproto.customtype) = "Dec", (gogoproto.nullable) = false]; } // ValAddresses defines a repeated set of validator addresses. message ValAddresses { option (gogoproto.stringer) = true; - repeated bytes addresses = 1 [ (gogoproto.casttype) = "ValAddress" ]; -} \ No newline at end of file + repeated bytes addresses = 1 [(gogoproto.casttype) = "ValAddress"]; +} diff --git a/x/auth/types/types.pb.go b/x/auth/types/types.pb.go index 6770d4eb2b2b..d4aaf520d2f1 100644 --- a/x/auth/types/types.pb.go +++ b/x/auth/types/types.pb.go @@ -207,47 +207,80 @@ func init() { func init() { proto.RegisterFile("x/auth/types/types.proto", fileDescriptor_2d526fa662daab74) } var fileDescriptor_2d526fa662daab74 = []byte{ - // 606 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x53, 0x3f, 0x6f, 0xd3, 0x40, - 0x14, 0x8f, 0x49, 0x48, 0xab, 0x6b, 0x41, 0xc4, 0xfd, 0xe7, 0x46, 0xc8, 0x17, 0x79, 0x40, 0x61, - 0xa8, 0x43, 0x8a, 0x8a, 0xd4, 0x0c, 0x88, 0x3a, 0xc0, 0x52, 0xa8, 0x2a, 0x47, 0x62, 0x40, 0x42, - 0xd6, 0xf9, 0x7c, 0x38, 0x56, 0x7a, 0x39, 0xd7, 0x77, 0xae, 0xec, 0x7e, 0x02, 0x46, 0x46, 0xc6, - 0xce, 0x7c, 0x92, 0x8e, 0x1d, 0x99, 0x5c, 0x94, 0x2e, 0xcc, 0x1e, 0x99, 0x90, 0x7d, 0x69, 0x49, - 0x4b, 0x41, 0x2c, 0xc9, 0xbd, 0xf7, 0xfb, 0x77, 0xf7, 0x7c, 0x07, 0xb4, 0xa4, 0x83, 0x62, 0x31, - 0xec, 0x88, 0x34, 0x24, 0x5c, 0xfe, 0x9a, 0x61, 0xc4, 0x04, 0x53, 0x97, 0x31, 0xe3, 0x94, 0x71, - 0x87, 0x7b, 0x23, 0x33, 0x31, 0x0b, 0x92, 0x79, 0xd4, 0x6d, 0x3e, 0x12, 0xc3, 0x20, 0xf2, 0x9c, - 0x10, 0x45, 0x22, 0xed, 0x94, 0xc4, 0x8e, 0xcf, 0x7c, 0xf6, 0x7b, 0x25, 0xd5, 0xcd, 0xc6, 0x1f, - 0x86, 0x46, 0xae, 0x80, 0x05, 0x0b, 0x71, 0xb2, 0x83, 0x31, 0x8b, 0xc7, 0x42, 0xdd, 0x05, 0x73, - 0xc8, 0xf3, 0x22, 0xc2, 0xb9, 0xa6, 0xb4, 0x94, 0xf6, 0xa2, 0xd5, 0xfd, 0x99, 0xc1, 0x0d, 0x3f, - 0x10, 0xc3, 0xd8, 0x35, 0x31, 0xa3, 0x1d, 0xb9, 0x81, 0xe9, 0xdf, 0x06, 0xf7, 0x46, 0x53, 0xbb, - 0x1d, 0x8c, 0x77, 0xa4, 0xd0, 0xbe, 0x74, 0x50, 0x4d, 0x30, 0x17, 0xc6, 0xae, 0x33, 0x22, 0xa9, - 0x76, 0xa7, 0x34, 0x5b, 0xc9, 0x33, 0xd8, 0x48, 0x11, 0x3d, 0xe8, 0x19, 0x61, 0xec, 0x1e, 0x04, - 0xb8, 0xc0, 0x0c, 0xbb, 0x1e, 0xc6, 0xee, 0x2e, 0x49, 0xd5, 0x17, 0xe0, 0x3e, 0x92, 0xfb, 0x70, - 0xc6, 0x31, 0x75, 0x49, 0xa4, 0x55, 0x5b, 0x4a, 0xbb, 0x66, 0xad, 0xe7, 0x19, 0x5c, 0x91, 0xb2, - 0xeb, 0xb8, 0x61, 0xdf, 0x9b, 0x36, 0xf6, 0xca, 0x5a, 0x6d, 0x82, 0x79, 0x4e, 0x0e, 0x63, 0x32, - 0xc6, 0x44, 0xab, 0x15, 0x5a, 0xfb, 0xaa, 0xee, 0xcd, 0x7f, 0x3a, 0x81, 0x95, 0x2f, 0x27, 0xb0, - 0x62, 0xa4, 0xa0, 0x3e, 0x10, 0xde, 0x6b, 0x42, 0xd4, 0x0f, 0xa0, 0x8e, 0x68, 0xa1, 0xd7, 0x94, - 0x56, 0xb5, 0xbd, 0xb0, 0xb9, 0x64, 0xce, 0x0c, 0xf8, 0xa8, 0x6b, 0xf6, 0x59, 0x30, 0xb6, 0x9e, - 0x9c, 0x66, 0xb0, 0xf2, 0xf5, 0x1c, 0xb6, 0xff, 0x63, 0x0c, 0x85, 0x80, 0xdb, 0x53, 0x53, 0xf5, - 0x01, 0xa8, 0xfa, 0x88, 0x97, 0x87, 0xaf, 0xd9, 0xc5, 0xd2, 0x38, 0xaf, 0x82, 0xfa, 0x3e, 0x8a, - 0x10, 0xe5, 0xea, 0x1e, 0x58, 0xa2, 0x28, 0x71, 0x28, 0xa1, 0xcc, 0xc1, 0x43, 0x14, 0x21, 0x2c, - 0x48, 0x24, 0xc7, 0x5e, 0xb3, 0xf4, 0x3c, 0x83, 0x4d, 0x79, 0xe4, 0x5b, 0x48, 0x86, 0xdd, 0xa0, - 0x28, 0x79, 0x4b, 0x28, 0xeb, 0x5f, 0xf5, 0xd4, 0x6d, 0xb0, 0x28, 0x12, 0x87, 0x07, 0xbe, 0x73, - 0x10, 0xd0, 0x40, 0xc8, 0x54, 0x6b, 0x2d, 0xcf, 0xe0, 0x92, 0x34, 0x9a, 0x45, 0x0d, 0x1b, 0x88, - 0x64, 0x10, 0xf8, 0x6f, 0x8a, 0x42, 0xb5, 0xc1, 0x4a, 0x09, 0x1e, 0x13, 0x07, 0x33, 0x2e, 0x9c, - 0x90, 0x44, 0x8e, 0x9b, 0x0a, 0x32, 0x9d, 0x7f, 0x2b, 0xcf, 0xe0, 0xc3, 0x19, 0x8f, 0x9b, 0x34, - 0xc3, 0x6e, 0x14, 0x66, 0xc7, 0xa4, 0xcf, 0xb8, 0xd8, 0x27, 0x91, 0x95, 0x0a, 0xa2, 0x1e, 0x82, - 0xb5, 0x22, 0xed, 0x88, 0x44, 0xc1, 0xc7, 0x54, 0xf2, 0x89, 0xb7, 0xb9, 0xb5, 0xd5, 0xdd, 0x96, - 0x5f, 0xc6, 0xea, 0x4d, 0x32, 0xb8, 0x3c, 0x08, 0xfc, 0x77, 0x25, 0xa3, 0x90, 0xbe, 0x7a, 0x59, - 0xe2, 0x79, 0x06, 0x75, 0x99, 0xf6, 0x17, 0x03, 0xc3, 0x5e, 0xe6, 0xd7, 0x74, 0xb2, 0xad, 0xa6, - 0x60, 0xfd, 0xa6, 0x82, 0x13, 0x1c, 0x6e, 0x6e, 0x3d, 0x1b, 0x75, 0xb5, 0xbb, 0x65, 0xe8, 0xf3, - 0x49, 0x06, 0x57, 0xaf, 0x85, 0x0e, 0x2e, 0x19, 0x79, 0x06, 0x5b, 0xb7, 0xc7, 0x5e, 0x99, 0x18, - 0xf6, 0x2a, 0xbf, 0x55, 0xdb, 0x9b, 0x2f, 0x2e, 0xd6, 0x8f, 0x13, 0xa8, 0x58, 0xfd, 0xd3, 0x89, - 0xae, 0x9c, 0x4d, 0x74, 0xe5, 0xfb, 0x44, 0x57, 0x3e, 0x5f, 0xe8, 0x95, 0xb3, 0x0b, 0xbd, 0xf2, - 0xed, 0x42, 0xaf, 0xbc, 0x7f, 0xfc, 0xcf, 0xfb, 0x33, 0xfb, 0xe6, 0xdd, 0x7a, 0xf9, 0x3a, 0x9f, - 0xfe, 0x0a, 0x00, 0x00, 0xff, 0xff, 0x84, 0x2e, 0x85, 0xe8, 0x0a, 0x04, 0x00, 0x00, + // 613 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x53, 0xbf, 0x6f, 0xd3, 0x4e, + 0x14, 0x8f, 0xbf, 0xc9, 0x37, 0xad, 0xae, 0x05, 0x11, 0xf7, 0x97, 0x1b, 0x21, 0x5f, 0xe4, 0x01, + 0x85, 0xa1, 0x0e, 0x29, 0x2a, 0x52, 0x33, 0x20, 0xea, 0x00, 0x4b, 0xa1, 0xaa, 0x1c, 0x89, 0x01, + 0x09, 0x59, 0x67, 0xfb, 0x70, 0xac, 0xf4, 0x72, 0xae, 0xef, 0x5c, 0xd9, 0x5d, 0x58, 0x19, 0x19, + 0x19, 0x3b, 0xf3, 0x97, 0x74, 0xec, 0xc8, 0xe4, 0xa2, 0x74, 0x61, 0xf6, 0xc8, 0x84, 0xce, 0x97, + 0x96, 0xb4, 0x14, 0xc4, 0x62, 0xdf, 0x7b, 0xef, 0xf3, 0xe3, 0xee, 0xbd, 0x3b, 0xa0, 0xa5, 0x1d, + 0x94, 0xf0, 0x61, 0x87, 0x67, 0x11, 0x66, 0xf2, 0x6b, 0x46, 0x31, 0xe5, 0x54, 0x5d, 0xf6, 0x28, + 0x23, 0x94, 0x39, 0xcc, 0x1f, 0x99, 0xa9, 0x29, 0x40, 0xe6, 0x51, 0xb7, 0xf9, 0x80, 0x0f, 0xc3, + 0xd8, 0x77, 0x22, 0x14, 0xf3, 0xac, 0x53, 0x02, 0x3b, 0x01, 0x0d, 0xe8, 0xaf, 0x95, 0x64, 0x37, + 0x1b, 0xbf, 0x09, 0x1a, 0x85, 0x02, 0x16, 0x2c, 0xc4, 0xf0, 0x8e, 0xe7, 0xd1, 0x64, 0xcc, 0xd5, + 0x5d, 0x30, 0x87, 0x7c, 0x3f, 0xc6, 0x8c, 0x69, 0x4a, 0x4b, 0x69, 0x2f, 0x5a, 0xdd, 0x1f, 0x39, + 0xdc, 0x08, 0x42, 0x3e, 0x4c, 0x5c, 0xd3, 0xa3, 0xa4, 0x23, 0x37, 0x30, 0xfd, 0x6d, 0x30, 0x7f, + 0x34, 0x95, 0xdb, 0xf1, 0xbc, 0x1d, 0x49, 0xb4, 0x2f, 0x15, 0x54, 0x13, 0xcc, 0x45, 0x89, 0xeb, + 0x8c, 0x70, 0xa6, 0xfd, 0x57, 0x8a, 0xad, 0x14, 0x39, 0x6c, 0x64, 0x88, 0x1c, 0xf4, 0x8c, 0x28, + 0x71, 0x0f, 0x42, 0x4f, 0xd4, 0x0c, 0xbb, 0x1e, 0x25, 0xee, 0x2e, 0xce, 0xd4, 0x67, 0xe0, 0x2e, + 0x92, 0xfb, 0x70, 0xc6, 0x09, 0x71, 0x71, 0xac, 0x55, 0x5b, 0x4a, 0xbb, 0x66, 0xad, 0x17, 0x39, + 0x5c, 0x91, 0xb4, 0xeb, 0x75, 0xc3, 0xbe, 0x33, 0x4d, 0xec, 0x95, 0xb1, 0xda, 0x04, 0xf3, 0x0c, + 0x1f, 0x26, 0x78, 0xec, 0x61, 0xad, 0x26, 0xb8, 0xf6, 0x55, 0xdc, 0x9b, 0xff, 0x78, 0x02, 0x2b, + 0x9f, 0x4f, 0x60, 0xc5, 0xf8, 0x00, 0xea, 0x03, 0xee, 0xbf, 0xc4, 0x58, 0x7d, 0x07, 0xea, 0x88, + 0x08, 0xbe, 0xa6, 0xb4, 0xaa, 0xed, 0x85, 0xcd, 0x25, 0x73, 0xa6, 0xc1, 0x47, 0x5d, 0xb3, 0x4f, + 0xc3, 0xb1, 0xf5, 0xe8, 0x34, 0x87, 0x95, 0x2f, 0xe7, 0xb0, 0xfd, 0x0f, 0x6d, 0x10, 0x04, 0x66, + 0x4f, 0x45, 0xd5, 0x7b, 0xa0, 0x1a, 0x20, 0x56, 0x1e, 0xbe, 0x66, 0x8b, 0x65, 0xaf, 0xf6, 0xfd, + 0x04, 0x2a, 0xc6, 0x79, 0x15, 0xd4, 0xf7, 0x51, 0x8c, 0x08, 0x53, 0xf7, 0xc0, 0x12, 0x41, 0xa9, + 0x43, 0x30, 0xa1, 0x8e, 0x37, 0x44, 0x31, 0xf2, 0x38, 0x8e, 0x65, 0xf3, 0x6b, 0x96, 0x5e, 0xe4, + 0xb0, 0x29, 0x0f, 0x7e, 0x0b, 0xc8, 0xb0, 0x1b, 0x04, 0xa5, 0xaf, 0x31, 0xa1, 0xfd, 0xab, 0x9c, + 0xba, 0x0d, 0x16, 0x79, 0xea, 0xb0, 0x30, 0x70, 0x0e, 0x42, 0x12, 0x72, 0xe9, 0x6d, 0xad, 0x15, + 0x39, 0x5c, 0x92, 0x42, 0xb3, 0x55, 0xc3, 0x06, 0x3c, 0x1d, 0x84, 0xc1, 0x2b, 0x11, 0xa8, 0x36, + 0x58, 0x29, 0x8b, 0xc7, 0xd8, 0xf1, 0x28, 0xe3, 0x4e, 0x84, 0x63, 0xc7, 0xcd, 0x38, 0x9e, 0x4e, + 0xa1, 0x55, 0xe4, 0xf0, 0xfe, 0x8c, 0xc6, 0x4d, 0x98, 0x61, 0x37, 0x84, 0xd8, 0x31, 0xee, 0x53, + 0xc6, 0xf7, 0x71, 0x6c, 0x65, 0x1c, 0xab, 0x87, 0x60, 0x4d, 0xb8, 0x1d, 0xe1, 0x38, 0x7c, 0x9f, + 0x49, 0x3c, 0xf6, 0x37, 0xb7, 0xb6, 0xba, 0xdb, 0x72, 0x3e, 0x56, 0x6f, 0x92, 0xc3, 0xe5, 0x41, + 0x18, 0xbc, 0x29, 0x11, 0x82, 0xfa, 0xe2, 0x79, 0x59, 0x2f, 0x72, 0xa8, 0x4b, 0xb7, 0x3f, 0x08, + 0x18, 0xf6, 0x32, 0xbb, 0xc6, 0x93, 0x69, 0x35, 0x03, 0xeb, 0x37, 0x19, 0x0c, 0x7b, 0xd1, 0xe6, + 0xd6, 0x93, 0x51, 0x57, 0xfb, 0xbf, 0x34, 0x7d, 0x3a, 0xc9, 0xe1, 0xea, 0x35, 0xd3, 0xc1, 0x25, + 0xa2, 0xc8, 0x61, 0xeb, 0x76, 0xdb, 0x2b, 0x11, 0xc3, 0x5e, 0x65, 0xb7, 0x72, 0x7b, 0xf3, 0xe2, + 0x7a, 0x89, 0x09, 0x5b, 0xfd, 0xd3, 0x89, 0xae, 0x9c, 0x4d, 0x74, 0xe5, 0xdb, 0x44, 0x57, 0x3e, + 0x5d, 0xe8, 0x95, 0xb3, 0x0b, 0xbd, 0xf2, 0xf5, 0x42, 0xaf, 0xbc, 0x7d, 0xf8, 0xd7, 0x5b, 0x34, + 0xfb, 0xf2, 0xdd, 0x7a, 0xf9, 0x46, 0x1f, 0xff, 0x0c, 0x00, 0x00, 0xff, 0xff, 0xa8, 0xcb, 0x64, + 0x0b, 0x10, 0x04, 0x00, 0x00, } +func (this *StdFee) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*StdFee) + if !ok { + that2, ok := that.(StdFee) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if len(this.Amount) != len(that1.Amount) { + return false + } + for i := range this.Amount { + if !this.Amount[i].Equal(&that1.Amount[i]) { + return false + } + } + if this.Gas != that1.Gas { + return false + } + return true +} func (this *Params) Equal(that interface{}) bool { if that == nil { return this == nil diff --git a/x/auth/types/types.proto b/x/auth/types/types.proto index 8a0d6555c7c5..eb059f4724f2 100644 --- a/x/auth/types/types.proto +++ b/x/auth/types/types.proto @@ -23,6 +23,8 @@ message BaseAccount { // gas to be used by the transaction. The ratio yields an effective "gasprice", // which must be above some miminum to be accepted into the mempool. message StdFee { + option (gogoproto.equal) = true; + repeated cosmos_sdk.v1.Coin amount = 1 [ (gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" diff --git a/x/bank/types/types.pb.go b/x/bank/types/types.pb.go index 0de721984735..b5a5c128830d 100644 --- a/x/bank/types/types.pb.go +++ b/x/bank/types/types.pb.go @@ -4,6 +4,7 @@ package types import ( + bytes "bytes" fmt "fmt" github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" types "github.com/cosmos/cosmos-sdk/types" @@ -255,13 +256,13 @@ func init() { func init() { proto.RegisterFile("x/bank/types/types.proto", fileDescriptor_934ff6b24d3432e2) } var fileDescriptor_934ff6b24d3432e2 = []byte{ - // 403 bytes of a gzipped FileDescriptorProto + // 413 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xa8, 0xd0, 0x4f, 0x4a, 0xcc, 0xcb, 0xd6, 0x2f, 0xa9, 0x2c, 0x48, 0x2d, 0x86, 0x90, 0x7a, 0x05, 0x45, 0xf9, 0x25, 0xf9, 0x42, 0x22, 0xc9, 0xf9, 0xc5, 0xb9, 0xf9, 0xc5, 0xf1, 0xc5, 0x29, 0xd9, 0x7a, 0x15, 0x7a, 0x20, 0x45, 0x7a, 0x65, 0x86, 0x52, 0x6a, 0x25, 0x19, 0x99, 0x45, 0x29, 0xf1, 0x05, 0x89, 0x45, 0x25, 0x95, 0xfa, 0x60, 0x85, 0xfa, 0xe9, 0xf9, 0xe9, 0xf9, 0x08, 0x16, 0x44, 0xb7, 0x94, 0x20, 0x86, - 0x81, 0x4a, 0x7b, 0x98, 0xb8, 0xd8, 0x7d, 0x8b, 0xd3, 0x83, 0x53, 0xf3, 0x52, 0x84, 0xb2, 0xb9, + 0x81, 0x4a, 0x87, 0x98, 0xb8, 0xd8, 0x7d, 0x8b, 0xd3, 0x83, 0x53, 0xf3, 0x52, 0x84, 0xb2, 0xb9, 0x78, 0xd2, 0x8a, 0xf2, 0x73, 0xe3, 0x13, 0x53, 0x52, 0x8a, 0x52, 0x8b, 0x8b, 0x25, 0x18, 0x15, 0x18, 0x35, 0x78, 0x9c, 0x3c, 0x3e, 0xdd, 0x93, 0x17, 0xae, 0x4c, 0xcc, 0xcd, 0xb1, 0x52, 0x42, 0x96, 0x55, 0xfa, 0x75, 0x4f, 0x5e, 0x37, 0x3d, 0xb3, 0x24, 0xa3, 0x34, 0x49, 0x2f, 0x39, 0x3f, @@ -271,19 +272,155 @@ var fileDescriptor_934ff6b24d3432e2 = []byte{ 0x92, 0x0f, 0xb3, 0x26, 0x96, 0x8b, 0x2d, 0x31, 0x37, 0xbf, 0x34, 0xaf, 0x44, 0x82, 0x59, 0x81, 0x59, 0x83, 0xdb, 0x48, 0x58, 0x0f, 0x29, 0x04, 0xcb, 0x0c, 0xf5, 0x9c, 0xf3, 0x33, 0xf3, 0x9c, 0x0c, 0x4e, 0xdc, 0x93, 0x67, 0x58, 0x75, 0x5f, 0x5e, 0x83, 0x08, 0x6b, 0x40, 0x1a, 0x8a, 0x83, - 0xa0, 0x86, 0x2a, 0x6d, 0x64, 0xe4, 0x62, 0xf5, 0xcc, 0x2b, 0x28, 0x2d, 0x11, 0xf2, 0xe6, 0x62, - 0x47, 0x0d, 0x37, 0x43, 0xd2, 0xdd, 0x0d, 0x33, 0x41, 0x28, 0x9a, 0x8b, 0x35, 0x19, 0x64, 0x8f, - 0x04, 0x13, 0x35, 0x1d, 0x0d, 0x31, 0x53, 0x69, 0x13, 0x23, 0x17, 0x9b, 0x7f, 0x69, 0xc9, 0xd0, - 0x72, 0x74, 0x3b, 0x23, 0x17, 0x8f, 0x6f, 0x71, 0xba, 0x6f, 0x69, 0x4e, 0x49, 0x26, 0x38, 0xb1, - 0x5a, 0x72, 0xb1, 0x65, 0x82, 0x02, 0x1e, 0xe4, 0x72, 0x90, 0x75, 0xd2, 0x7a, 0xd8, 0xb2, 0x86, - 0x1e, 0x38, 0x72, 0x9c, 0x58, 0x40, 0xd6, 0x06, 0x41, 0x35, 0x08, 0xd9, 0x70, 0xb1, 0xe7, 0x83, - 0xfd, 0x0f, 0x73, 0xaa, 0x0c, 0x76, 0xbd, 0x90, 0x40, 0x82, 0x6a, 0x86, 0x69, 0x71, 0x72, 0x3e, - 0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39, 0xc6, 0x07, 0x8f, 0xe4, 0x18, 0x27, 0x3c, 0x96, 0x63, - 0xb8, 0xf0, 0x58, 0x8e, 0xe1, 0xc6, 0x63, 0x39, 0x86, 0x28, 0x4d, 0xbc, 0x9e, 0x42, 0xce, 0xd3, - 0x49, 0x6c, 0xe0, 0xdc, 0x67, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0x64, 0xad, 0xc1, 0x15, 0xea, - 0x03, 0x00, 0x00, + 0xa0, 0x86, 0x5a, 0xb1, 0xbc, 0x58, 0x20, 0xcf, 0xa8, 0xb4, 0x9d, 0x91, 0x8b, 0xd5, 0x33, 0xaf, + 0xa0, 0xb4, 0x44, 0xc8, 0x9b, 0x8b, 0x1d, 0x35, 0xf4, 0x0c, 0x49, 0x77, 0x3d, 0xcc, 0x04, 0xa1, + 0x68, 0x2e, 0xd6, 0x64, 0x90, 0x6d, 0x12, 0x4c, 0xd4, 0x74, 0x3a, 0xc4, 0x4c, 0xa8, 0xcb, 0x77, + 0x30, 0x72, 0xb1, 0xf9, 0x97, 0x96, 0x0c, 0x45, 0xa7, 0xf7, 0x32, 0x72, 0xf1, 0xf8, 0x16, 0xa7, + 0xfb, 0x96, 0xe6, 0x94, 0x64, 0x82, 0x93, 0xaf, 0x25, 0x17, 0x5b, 0x26, 0x28, 0x12, 0x40, 0xee, + 0x07, 0x59, 0x2a, 0xad, 0x87, 0x2d, 0xb3, 0xe8, 0x81, 0x23, 0xca, 0x89, 0x05, 0x64, 0x79, 0x10, + 0x54, 0x83, 0x90, 0x0d, 0x17, 0x7b, 0x3e, 0x38, 0x14, 0x60, 0x0e, 0x96, 0xc1, 0xae, 0x17, 0x12, + 0x54, 0x50, 0xcd, 0x30, 0x2d, 0x10, 0xf7, 0x38, 0x39, 0x9f, 0x78, 0x24, 0xc7, 0x78, 0xe1, 0x91, + 0x1c, 0xe3, 0x83, 0x47, 0x72, 0x8c, 0x13, 0x1e, 0xcb, 0x31, 0x5c, 0x78, 0x2c, 0xc7, 0x70, 0xe3, + 0xb1, 0x1c, 0x43, 0x94, 0x26, 0x5e, 0x0f, 0x22, 0xe7, 0xf5, 0x24, 0x36, 0x70, 0xae, 0x34, 0x06, + 0x04, 0x00, 0x00, 0xff, 0xff, 0x57, 0x42, 0x17, 0x1f, 0x02, 0x04, 0x00, 0x00, } +func (this *MsgSend) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*MsgSend) + if !ok { + that2, ok := that.(MsgSend) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !bytes.Equal(this.FromAddress, that1.FromAddress) { + return false + } + if !bytes.Equal(this.ToAddress, that1.ToAddress) { + return false + } + if len(this.Amount) != len(that1.Amount) { + return false + } + for i := range this.Amount { + if !this.Amount[i].Equal(&that1.Amount[i]) { + return false + } + } + return true +} +func (this *Input) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*Input) + if !ok { + that2, ok := that.(Input) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !bytes.Equal(this.Address, that1.Address) { + return false + } + if len(this.Coins) != len(that1.Coins) { + return false + } + for i := range this.Coins { + if !this.Coins[i].Equal(&that1.Coins[i]) { + return false + } + } + return true +} +func (this *Output) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*Output) + if !ok { + that2, ok := that.(Output) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !bytes.Equal(this.Address, that1.Address) { + return false + } + if len(this.Coins) != len(that1.Coins) { + return false + } + for i := range this.Coins { + if !this.Coins[i].Equal(&that1.Coins[i]) { + return false + } + } + return true +} +func (this *MsgMultiSend) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*MsgMultiSend) + if !ok { + that2, ok := that.(MsgMultiSend) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if len(this.Inputs) != len(that1.Inputs) { + return false + } + for i := range this.Inputs { + if !this.Inputs[i].Equal(&that1.Inputs[i]) { + return false + } + } + if len(this.Outputs) != len(that1.Outputs) { + return false + } + for i := range this.Outputs { + if !this.Outputs[i].Equal(&that1.Outputs[i]) { + return false + } + } + return true +} func (m *MsgSend) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) diff --git a/x/bank/types/types.proto b/x/bank/types/types.proto index 9aee8d22a319..ceb990314989 100644 --- a/x/bank/types/types.proto +++ b/x/bank/types/types.proto @@ -9,6 +9,8 @@ import "types/types.proto"; // MsgSend - high level transaction of the coin module message MsgSend { + option (gogoproto.equal) = true; + bytes from_address = 1 [ (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress", (gogoproto.moretags) = "yaml:\"from_address\"" @@ -25,6 +27,8 @@ message MsgSend { // Input models transaction input message Input { + option (gogoproto.equal) = true; + bytes address = 1 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; repeated cosmos_sdk.v1.Coin coins = 2 [ (gogoproto.nullable) = false, @@ -34,6 +38,8 @@ message Input { // Output models transaction outputs message Output { + option (gogoproto.equal) = true; + bytes address = 1 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; repeated cosmos_sdk.v1.Coin coins = 2 [ (gogoproto.nullable) = false, @@ -43,6 +49,8 @@ message Output { // MsgMultiSend - high level transaction of the coin module message MsgMultiSend { + option (gogoproto.equal) = true; + repeated Input inputs = 1 [(gogoproto.nullable) = false]; repeated Output outputs = 2 [(gogoproto.nullable) = false]; } diff --git a/x/crisis/internal/types/types.pb.go b/x/crisis/internal/types/types.pb.go index bf584c384409..6e9507e1ac41 100644 --- a/x/crisis/internal/types/types.pb.go +++ b/x/crisis/internal/types/types.pb.go @@ -4,6 +4,7 @@ package types import ( + bytes "bytes" fmt "fmt" github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" _ "github.com/gogo/protobuf/gogoproto" @@ -94,28 +95,59 @@ func init() { } var fileDescriptor_df1c0b8e580cce76 = []byte{ - // 301 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x90, 0xcf, 0x4a, 0xfb, 0x30, - 0x00, 0x80, 0x97, 0xdf, 0x0f, 0x07, 0x16, 0x51, 0xa8, 0x38, 0xc6, 0x90, 0x74, 0x54, 0x90, 0x5d, - 0xd6, 0x30, 0xbc, 0x79, 0xdb, 0x3c, 0xed, 0x30, 0x0f, 0x45, 0x3c, 0x78, 0x29, 0x59, 0x13, 0xbb, - 0xb0, 0x25, 0x29, 0x49, 0x3a, 0xd6, 0xb7, 0xf0, 0xb1, 0x3c, 0xee, 0xe8, 0xa9, 0x48, 0xfb, 0x06, - 0x3b, 0xee, 0x24, 0xa6, 0x75, 0x03, 0xf1, 0x92, 0x84, 0x8f, 0x2f, 0x5f, 0xfe, 0x38, 0x37, 0x1b, - 0x14, 0x2b, 0xa6, 0x99, 0x46, 0x4c, 0x18, 0xaa, 0x04, 0x5e, 0x21, 0x93, 0xa7, 0x54, 0xd7, 0x63, - 0x90, 0x2a, 0x69, 0xa4, 0xdb, 0x89, 0xa5, 0xe6, 0x52, 0x47, 0x9a, 0x2c, 0x83, 0x4d, 0x50, 0xfb, - 0xc1, 0x7a, 0xd4, 0xbb, 0x35, 0x0b, 0xa6, 0x48, 0x94, 0x62, 0x65, 0x72, 0x64, 0x55, 0x94, 0xc8, - 0x44, 0x1e, 0x57, 0xf5, 0x7e, 0x7f, 0x0f, 0x1c, 0x77, 0xa6, 0x93, 0x67, 0xaa, 0xd8, 0x6b, 0x3e, - 0x15, 0x6b, 0xac, 0x18, 0x16, 0xc6, 0x9d, 0x3a, 0x6d, 0x4d, 0x05, 0xa1, 0xaa, 0x0b, 0xfa, 0x60, - 0x70, 0x36, 0x19, 0xed, 0x0b, 0x6f, 0x98, 0x30, 0xb3, 0xc8, 0xe6, 0x41, 0x2c, 0x39, 0xaa, 0x4f, - 0x6d, 0xa6, 0xa1, 0x26, 0xcb, 0xe6, 0x52, 0xe3, 0x38, 0x1e, 0x13, 0xa2, 0xa8, 0xd6, 0x61, 0x13, - 0x70, 0x9f, 0x9c, 0x2b, 0xf6, 0xd3, 0x8d, 0xb8, 0x24, 0xd9, 0x8a, 0x46, 0x02, 0x73, 0xda, 0xfd, - 0xd7, 0x07, 0x83, 0xd3, 0x49, 0x7f, 0x57, 0x78, 0xd7, 0x39, 0xe6, 0xab, 0x7b, 0xff, 0x4f, 0xcd, - 0x0f, 0x2f, 0x0f, 0x7c, 0x66, 0xf1, 0x23, 0xe6, 0xd4, 0x7d, 0x70, 0x2e, 0x8e, 0xba, 0x92, 0x99, - 0xa1, 0xdd, 0xff, 0xb6, 0xd7, 0xdb, 0x15, 0x5e, 0xe7, 0x77, 0xcf, 0x0a, 0x7e, 0x78, 0x7e, 0x20, - 0xe1, 0x37, 0x98, 0x78, 0xef, 0x25, 0x04, 0xdb, 0x12, 0x82, 0xcf, 0x12, 0x82, 0xb7, 0x0a, 0xb6, - 0xb6, 0x15, 0x6c, 0x7d, 0x54, 0xb0, 0xf5, 0x72, 0x62, 0x9f, 0x33, 0x6f, 0xdb, 0x4f, 0xba, 0xfb, - 0x0a, 0x00, 0x00, 0xff, 0xff, 0xa7, 0xed, 0x2c, 0x98, 0x8b, 0x01, 0x00, 0x00, + // 308 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0xae, 0xd0, 0x4f, 0x2e, + 0xca, 0x2c, 0xce, 0x2c, 0xd6, 0xcf, 0xcc, 0x2b, 0x49, 0x2d, 0xca, 0x4b, 0xcc, 0xd1, 0x2f, 0xa9, + 0x2c, 0x48, 0x2d, 0x86, 0x90, 0x7a, 0x05, 0x45, 0xf9, 0x25, 0xf9, 0x42, 0x62, 0xc9, 0xf9, 0xc5, + 0xb9, 0xf9, 0xc5, 0xf1, 0xc5, 0x29, 0xd9, 0x7a, 0x15, 0x7a, 0x10, 0xf5, 0x7a, 0x65, 0x86, 0x52, + 0x6a, 0x25, 0x19, 0x99, 0x45, 0x29, 0xf1, 0x05, 0x89, 0x45, 0x25, 0x95, 0xfa, 0x60, 0xa5, 0xfa, + 0xe9, 0xf9, 0xe9, 0xf9, 0x08, 0x16, 0x44, 0xbf, 0x52, 0x03, 0x13, 0x97, 0x90, 0x6f, 0x71, 0x7a, + 0x58, 0x6a, 0x51, 0x66, 0x5a, 0xa5, 0x67, 0x5e, 0x59, 0x62, 0x51, 0x66, 0x62, 0x5e, 0x89, 0x90, + 0x27, 0x17, 0x5b, 0x71, 0x6a, 0x5e, 0x4a, 0x6a, 0x91, 0x04, 0xa3, 0x02, 0xa3, 0x06, 0x8f, 0x93, + 0xe1, 0xaf, 0x7b, 0xf2, 0xba, 0xe9, 0x99, 0x25, 0x19, 0xa5, 0x49, 0x7a, 0xc9, 0xf9, 0xb9, 0xfa, + 0x10, 0x5b, 0xa1, 0x94, 0x6e, 0x71, 0x4a, 0x36, 0xd4, 0x51, 0x8e, 0xc9, 0xc9, 0x8e, 0x29, 0x29, + 0x45, 0xa9, 0xc5, 0xc5, 0x41, 0x50, 0x03, 0x84, 0x42, 0xb8, 0x44, 0x33, 0x61, 0xe6, 0xc6, 0xe7, + 0xe6, 0xa7, 0x94, 0xe6, 0xa4, 0xc6, 0xe7, 0x25, 0xe6, 0xa6, 0x4a, 0x30, 0x29, 0x30, 0x6a, 0x70, + 0x3a, 0x29, 0x7c, 0xba, 0x27, 0x2f, 0x53, 0x99, 0x98, 0x9b, 0x63, 0xa5, 0x84, 0x55, 0x99, 0x52, + 0x90, 0x30, 0x5c, 0xdc, 0x17, 0x2c, 0xec, 0x97, 0x98, 0x9b, 0x2a, 0xe4, 0xcc, 0xc5, 0x8f, 0x50, + 0x5e, 0x94, 0x5f, 0x5a, 0x92, 0x2a, 0xc1, 0x0c, 0x36, 0x4f, 0xea, 0xd3, 0x3d, 0x79, 0x31, 0x74, + 0xf3, 0xc0, 0x0a, 0x94, 0x82, 0xf8, 0xe0, 0x22, 0x41, 0x20, 0x01, 0x2b, 0x96, 0x17, 0x0b, 0xe4, + 0x19, 0x9d, 0xe4, 0x4f, 0x3c, 0x92, 0x63, 0xbc, 0xf0, 0x48, 0x8e, 0xf1, 0xc1, 0x23, 0x39, 0xc6, + 0x09, 0x8f, 0xe5, 0x18, 0x2e, 0x3c, 0x96, 0x63, 0xb8, 0xf1, 0x58, 0x8e, 0x21, 0x8a, 0x15, 0xec, + 0xa9, 0x24, 0x36, 0x70, 0x50, 0x19, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0x46, 0x5c, 0xba, 0xa4, + 0x91, 0x01, 0x00, 0x00, } +func (this *MsgVerifyInvariant) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*MsgVerifyInvariant) + if !ok { + that2, ok := that.(MsgVerifyInvariant) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !bytes.Equal(this.Sender, that1.Sender) { + return false + } + if this.InvariantModuleName != that1.InvariantModuleName { + return false + } + if this.InvariantRoute != that1.InvariantRoute { + return false + } + return true +} func (m *MsgVerifyInvariant) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) diff --git a/x/crisis/internal/types/types.proto b/x/crisis/internal/types/types.proto index 64b4c5fc60e8..c691035f92f7 100644 --- a/x/crisis/internal/types/types.proto +++ b/x/crisis/internal/types/types.proto @@ -7,6 +7,8 @@ import "third_party/proto/gogoproto/gogo.proto"; // MsgVerifyInvariant - message struct to verify a particular invariance message MsgVerifyInvariant { + option (gogoproto.equal) = true; + bytes sender = 1 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; string invariant_module_name = 2 [(gogoproto.moretags) = "yaml:\"invariant_module_name\""]; string invariant_route = 3 [(gogoproto.moretags) = "yaml:\"invariant_route\""]; diff --git a/x/distribution/types/types.pb.go b/x/distribution/types/types.pb.go index 21a6dfbee38d..0571a985cb0a 100644 --- a/x/distribution/types/types.pb.go +++ b/x/distribution/types/types.pb.go @@ -4,6 +4,7 @@ package types import ( + bytes "bytes" fmt "fmt" github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" types "github.com/cosmos/cosmos-sdk/types" @@ -746,79 +747,497 @@ func init() { func init() { proto.RegisterFile("x/distribution/types/types.proto", fileDescriptor_9fddf2a8e4a90b09) } var fileDescriptor_9fddf2a8e4a90b09 = []byte{ - // 1110 bytes of a gzipped FileDescriptorProto + // 1113 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x57, 0xcf, 0x6f, 0x1b, 0x45, - 0x1b, 0xf6, 0x38, 0x4e, 0x9a, 0x4c, 0xd3, 0xa4, 0xd9, 0xd8, 0x49, 0xe4, 0x7c, 0x9f, 0xd7, 0x1a, - 0x89, 0x2a, 0x12, 0x8a, 0xd3, 0xd0, 0x5b, 0x0e, 0x48, 0x71, 0x7e, 0x08, 0x50, 0x43, 0xa3, 0x4d, - 0x28, 0x12, 0x12, 0x5a, 0x8d, 0x77, 0x27, 0xf6, 0x28, 0xeb, 0x9d, 0xd5, 0xcc, 0xd8, 0x4e, 0x7a, - 0x41, 0xe2, 0x04, 0x82, 0x22, 0x0e, 0x08, 0x7a, 0xe0, 0xd0, 0x0b, 0x07, 0x2a, 0xfe, 0x0e, 0xd4, - 0x63, 0x6f, 0x20, 0x0e, 0x2e, 0x4a, 0x6e, 0x1c, 0x73, 0x83, 0x13, 0xda, 0x9d, 0xd9, 0x5d, 0xc7, - 0xb1, 0xa8, 0x1d, 0xa9, 0x70, 0x49, 0x32, 0xef, 0xbc, 0xf3, 0x3c, 0xcf, 0x3c, 0x33, 0xf3, 0xbe, - 0x1b, 0x58, 0x3e, 0x59, 0x73, 0xa9, 0x90, 0x9c, 0xd6, 0x5a, 0x92, 0x32, 0x7f, 0x4d, 0x9e, 0x06, - 0x44, 0xa8, 0x9f, 0x95, 0x80, 0x33, 0xc9, 0x8c, 0x65, 0x87, 0x89, 0x26, 0x13, 0xb6, 0x70, 0x8f, - 0x2b, 0x27, 0x15, 0x97, 0x26, 0xb9, 0x95, 0xf6, 0x7a, 0xf1, 0x8e, 0x6c, 0x50, 0xee, 0xda, 0x01, - 0xe6, 0xf2, 0x74, 0x2d, 0xca, 0x5f, 0xab, 0xb3, 0x3a, 0x4b, 0xff, 0x52, 0x20, 0xc5, 0xb9, 0x2b, - 0xb8, 0xe8, 0xcb, 0x2c, 0x2c, 0xec, 0x89, 0xfa, 0x01, 0x91, 0x1f, 0x52, 0xd9, 0x70, 0x39, 0xee, - 0x6c, 0xba, 0x2e, 0x27, 0x42, 0x18, 0x8f, 0xe0, 0x9c, 0x4b, 0x3c, 0x52, 0xc7, 0x92, 0x71, 0x1b, - 0xab, 0xe0, 0x12, 0x28, 0x83, 0x95, 0xe9, 0xea, 0xde, 0x45, 0xd7, 0x5c, 0x3a, 0xc5, 0x4d, 0x6f, - 0x03, 0x5d, 0x49, 0x41, 0x7f, 0x75, 0xcd, 0xd5, 0x3a, 0x95, 0x8d, 0x56, 0xad, 0xe2, 0xb0, 0xe6, - 0x9a, 0xd2, 0xad, 0x7f, 0xad, 0x0a, 0xf7, 0x58, 0xd3, 0x6f, 0x3a, 0x8e, 0x66, 0xb2, 0x6e, 0x27, - 0x20, 0x31, 0x77, 0x07, 0xde, 0xee, 0x68, 0x39, 0x09, 0x75, 0x36, 0xa2, 0xbe, 0x7f, 0xd1, 0x35, - 0x17, 0x15, 0x75, 0x7f, 0xc6, 0x35, 0x98, 0x67, 0x3b, 0x97, 0x37, 0x8d, 0xbe, 0xc9, 0xc2, 0xe2, - 0x9e, 0xa8, 0xc7, 0x5e, 0x6c, 0xc7, 0xc2, 0x2c, 0xd2, 0xc1, 0xdc, 0xfd, 0x4f, 0x3d, 0x79, 0x04, - 0xe7, 0xda, 0xd8, 0xa3, 0xee, 0x25, 0xee, 0x6c, 0x3f, 0xf7, 0x95, 0x94, 0x61, 0xb9, 0x1f, 0x62, - 0x2f, 0xe1, 0x4e, 0x40, 0x62, 0x5b, 0xbe, 0x07, 0xb0, 0xd4, 0x63, 0xcb, 0xc3, 0x78, 0x7e, 0x8b, - 0x35, 0x9b, 0x54, 0x08, 0xca, 0xfc, 0xc1, 0xf2, 0xc0, 0xbf, 0x23, 0xef, 0x67, 0x00, 0xf3, 0x7b, - 0xa2, 0xbe, 0xdb, 0xf2, 0xdd, 0x50, 0x51, 0xcb, 0xa7, 0xf2, 0x74, 0x9f, 0x31, 0xcf, 0xf8, 0x18, - 0x4e, 0xe0, 0x26, 0x6b, 0xf9, 0x72, 0x09, 0x94, 0xc7, 0x56, 0x6e, 0xbe, 0x35, 0x5f, 0xe9, 0x79, - 0x46, 0xed, 0xf5, 0xca, 0x16, 0xa3, 0x7e, 0xf5, 0xee, 0xf3, 0xae, 0x99, 0x79, 0xf6, 0xd2, 0x5c, - 0x19, 0x42, 0x46, 0xb8, 0x40, 0x58, 0x1a, 0xd4, 0x78, 0x00, 0xa7, 0x5c, 0x12, 0x30, 0x41, 0x25, - 0xe3, 0xfa, 0x28, 0xd6, 0x47, 0x3f, 0xea, 0x14, 0x03, 0xfd, 0x32, 0x06, 0x27, 0xf6, 0x31, 0xc7, - 0x4d, 0x61, 0x1c, 0xc3, 0x5b, 0x4e, 0xbc, 0x17, 0x5b, 0xe2, 0x93, 0xc8, 0xcb, 0xa9, 0xea, 0x6e, - 0x28, 0xf6, 0xb7, 0xae, 0x79, 0x67, 0x08, 0x8e, 0x6d, 0xe2, 0x5c, 0x74, 0xcd, 0xbc, 0x72, 0xfe, - 0x12, 0x18, 0xb2, 0xa6, 0x93, 0xf1, 0x21, 0x3e, 0x31, 0x3e, 0x81, 0xf9, 0x1a, 0x16, 0xc4, 0x0e, - 0x38, 0x0b, 0x98, 0x20, 0xdc, 0xe6, 0xd1, 0x7d, 0x8f, 0xf6, 0x34, 0x55, 0xdd, 0x1b, 0x99, 0x73, - 0x59, 0x71, 0x0e, 0xc2, 0x44, 0x96, 0x11, 0x86, 0xf7, 0x75, 0x54, 0x3f, 0xac, 0x4f, 0x01, 0x2c, - 0xd4, 0x98, 0xdf, 0x12, 0x57, 0x24, 0x8c, 0x45, 0x12, 0xde, 0x1f, 0x59, 0xc2, 0xff, 0xb4, 0x84, - 0x41, 0xa0, 0xc8, 0x9a, 0x8f, 0xe2, 0x7d, 0x22, 0x0e, 0x61, 0xe1, 0x52, 0x4d, 0xb1, 0x89, 0x8f, - 0x6b, 0x1e, 0x71, 0x97, 0x72, 0x65, 0xb0, 0x32, 0x59, 0x2d, 0xa7, 0xa8, 0x03, 0xd3, 0x90, 0x35, - 0xdf, 0x5b, 0x4e, 0x76, 0x54, 0x74, 0x23, 0xf7, 0xe4, 0xa9, 0x99, 0x41, 0x9f, 0x67, 0x61, 0x31, - 0x79, 0x36, 0xef, 0x50, 0x21, 0x19, 0xa7, 0x0e, 0xf6, 0x14, 0xb3, 0x30, 0x7e, 0x00, 0x70, 0xd1, - 0x69, 0x35, 0x5b, 0x1e, 0x96, 0xb4, 0x4d, 0xb4, 0x4c, 0x9b, 0x63, 0x49, 0x99, 0xbe, 0xba, 0x0b, - 0x7d, 0x57, 0x77, 0x9b, 0x38, 0xd1, 0xed, 0xfd, 0x20, 0x74, 0xe6, 0xa2, 0x6b, 0x96, 0xf4, 0x31, - 0x0f, 0x06, 0x41, 0xcf, 0x5e, 0x9a, 0x6f, 0x0e, 0xe7, 0x9d, 0xba, 0xe2, 0x85, 0x14, 0x48, 0x69, - 0xb4, 0x42, 0x18, 0x63, 0x0b, 0xce, 0x72, 0x72, 0x44, 0x38, 0xf1, 0x1d, 0x62, 0x3b, 0xd1, 0xcb, - 0x0a, 0xef, 0xc8, 0xad, 0x6a, 0xf1, 0xa2, 0x6b, 0x2e, 0x28, 0x09, 0x7d, 0x09, 0xc8, 0x9a, 0x49, - 0x22, 0x5b, 0x51, 0xe0, 0x09, 0x80, 0x8b, 0x69, 0x09, 0x69, 0x71, 0x4e, 0x7c, 0x19, 0x1b, 0x41, - 0xe0, 0x0d, 0xa5, 0x5b, 0xbc, 0x62, 0xdf, 0xf7, 0xf4, 0xab, 0x1d, 0x69, 0x57, 0x31, 0xb6, 0xb1, - 0x00, 0x27, 0x02, 0xc2, 0x29, 0x53, 0x57, 0x3c, 0x67, 0xe9, 0x11, 0x7a, 0x0c, 0x60, 0x29, 0x91, - 0xb6, 0xe9, 0x68, 0x13, 0x88, 0xdb, 0x53, 0xe8, 0x8e, 0x21, 0x74, 0x92, 0xd1, 0xeb, 0x10, 0xd9, - 0x03, 0x8f, 0xbe, 0x05, 0x70, 0x39, 0xd1, 0xf3, 0xa0, 0x25, 0x85, 0xc4, 0xbe, 0x4b, 0xfd, 0x7a, - 0x6c, 0x57, 0x67, 0x58, 0xbb, 0x76, 0xf4, 0x35, 0x99, 0x89, 0xcf, 0x28, 0x5a, 0x84, 0xae, 0x6b, - 0x20, 0xfa, 0x11, 0xc0, 0xf9, 0x44, 0xd8, 0x81, 0x87, 0x45, 0x63, 0xa7, 0x4d, 0x7c, 0x69, 0xec, - 0xc2, 0xb4, 0x3c, 0xdb, 0xda, 0xe2, 0xb0, 0x72, 0xe5, 0xaa, 0xcb, 0x69, 0xe7, 0xee, 0xcf, 0x40, - 0xd6, 0x6c, 0x12, 0xda, 0x8f, 0x22, 0xc6, 0x7b, 0x70, 0xf2, 0x88, 0x63, 0x27, 0xfc, 0xc2, 0xd1, - 0x55, 0xa8, 0x32, 0x5a, 0x09, 0xb0, 0x92, 0xf5, 0xe8, 0x27, 0x00, 0xf3, 0x03, 0xb4, 0x0a, 0xe3, - 0x31, 0x80, 0x0b, 0xa9, 0x16, 0x11, 0xce, 0xd8, 0x24, 0x9a, 0xd2, 0x6e, 0xde, 0xad, 0xfc, 0xc3, - 0x67, 0x57, 0x65, 0x00, 0x66, 0xf5, 0x0d, 0xed, 0xf3, 0xff, 0xfb, 0x77, 0xda, 0x8b, 0x8e, 0xac, - 0x7c, 0x7b, 0x80, 0x1e, 0x5d, 0x2a, 0xbe, 0x03, 0xf0, 0xc6, 0x2e, 0x21, 0x51, 0x03, 0xfb, 0x02, - 0xc0, 0x99, 0xb4, 0x72, 0x07, 0x8c, 0x79, 0xaf, 0x38, 0xe7, 0xfb, 0x9a, 0xbf, 0xd0, 0x5f, 0xf5, - 0xc3, 0xb5, 0x23, 0x1f, 0x77, 0xda, 0x82, 0x42, 0x35, 0xe8, 0xab, 0x2c, 0x2c, 0x5e, 0x6a, 0xb0, - 0x07, 0x01, 0xf1, 0x5d, 0x55, 0x45, 0xb1, 0x67, 0xe4, 0xe1, 0xb8, 0xa4, 0xd2, 0x23, 0xaa, 0x55, - 0x59, 0x6a, 0x60, 0x94, 0xe1, 0x4d, 0x97, 0x08, 0x87, 0xd3, 0x20, 0x3d, 0x4c, 0xab, 0x37, 0x14, - 0xb6, 0x51, 0x4e, 0x1c, 0x1a, 0x50, 0xe2, 0xcb, 0xa8, 0xde, 0x5f, 0xaf, 0x8d, 0x26, 0x18, 0x3d, - 0x6d, 0x3f, 0xf7, 0x1a, 0xda, 0xfe, 0xc6, 0xe4, 0x67, 0x4f, 0xcd, 0x4c, 0x74, 0x54, 0x7f, 0x02, - 0x58, 0x48, 0xbe, 0x11, 0x0f, 0x24, 0xe6, 0x92, 0xfa, 0xf5, 0x77, 0xfd, 0xa3, 0xa8, 0x50, 0x06, - 0x9c, 0xb4, 0x29, 0x0b, 0xbb, 0x4f, 0xef, 0x33, 0xe8, 0x29, 0x94, 0x7d, 0x09, 0xc8, 0x9a, 0x89, - 0x23, 0xfa, 0x11, 0x1c, 0xc2, 0x71, 0x21, 0xf1, 0x31, 0xd1, 0x2f, 0xe0, 0xed, 0x91, 0x9b, 0xe0, - 0xb4, 0x22, 0x8a, 0x40, 0x90, 0xa5, 0xc0, 0x8c, 0x1d, 0x38, 0xd1, 0x20, 0xb4, 0xde, 0x50, 0x5e, - 0xe7, 0xaa, 0xab, 0x7f, 0x74, 0xcd, 0x59, 0x87, 0x93, 0xb0, 0xc0, 0xfb, 0xb6, 0x9a, 0x4a, 0x45, - 0xf6, 0x4d, 0x20, 0x4b, 0x2f, 0xae, 0x9a, 0xcf, 0xcf, 0x4a, 0xe0, 0xc5, 0x59, 0x09, 0xfc, 0x7e, - 0x56, 0x02, 0x5f, 0x9f, 0x97, 0x32, 0x2f, 0xce, 0x4b, 0x99, 0x5f, 0xcf, 0x4b, 0x99, 0x8f, 0xc6, - 0x23, 0x09, 0xb5, 0x89, 0xe8, 0x3f, 0x8c, 0x7b, 0x7f, 0x07, 0x00, 0x00, 0xff, 0xff, 0x2c, 0xac, - 0x10, 0x4b, 0xdd, 0x0c, 0x00, 0x00, + 0x14, 0xf6, 0x38, 0x4e, 0x9a, 0x4c, 0xd3, 0xa4, 0xd9, 0xd8, 0x49, 0xe4, 0x80, 0xd7, 0x1a, 0x44, + 0x15, 0x09, 0xc5, 0x69, 0xe8, 0x2d, 0x07, 0xa4, 0x38, 0x3f, 0x04, 0xa8, 0xa1, 0xd1, 0x26, 0x14, + 0x09, 0x09, 0xad, 0xc6, 0xbb, 0x13, 0x7b, 0x94, 0xf5, 0xce, 0x6a, 0x66, 0x6c, 0x27, 0xbd, 0x20, + 0x71, 0x02, 0x41, 0x11, 0x07, 0x04, 0x3d, 0x70, 0xe8, 0x05, 0x09, 0x2a, 0xfe, 0x0e, 0xd4, 0x63, + 0x6f, 0x20, 0x0e, 0x2e, 0x4a, 0x6e, 0x1c, 0x73, 0x83, 0x13, 0xda, 0x9d, 0xd9, 0x5d, 0xc7, 0xb1, + 0x68, 0x1c, 0xa9, 0xf4, 0x92, 0x64, 0xde, 0xbc, 0xf9, 0xbe, 0x6f, 0xbe, 0x99, 0x79, 0x6f, 0x03, + 0xcb, 0x47, 0x2b, 0x2e, 0x15, 0x92, 0xd3, 0x5a, 0x4b, 0x52, 0xe6, 0xaf, 0xc8, 0xe3, 0x80, 0x08, + 0xf5, 0xb3, 0x12, 0x70, 0x26, 0x99, 0xb1, 0xe8, 0x30, 0xd1, 0x64, 0xc2, 0x16, 0xee, 0x61, 0xe5, + 0xa8, 0xe2, 0xd2, 0x24, 0xb7, 0xd2, 0x5e, 0x2d, 0xde, 0x92, 0x0d, 0xca, 0x5d, 0x3b, 0xc0, 0x5c, + 0x1e, 0xaf, 0x44, 0xf9, 0x2b, 0x75, 0x56, 0x67, 0xe9, 0x5f, 0x0a, 0xa4, 0x38, 0x73, 0x01, 0x17, + 0x7d, 0x95, 0x85, 0x85, 0x1d, 0x51, 0xdf, 0x23, 0xf2, 0x23, 0x2a, 0x1b, 0x2e, 0xc7, 0x9d, 0x75, + 0xd7, 0xe5, 0x44, 0x08, 0xe3, 0x01, 0x9c, 0x71, 0x89, 0x47, 0xea, 0x58, 0x32, 0x6e, 0x63, 0x15, + 0x5c, 0x00, 0x65, 0xb0, 0x34, 0x59, 0xdd, 0x39, 0xeb, 0x9a, 0x0b, 0xc7, 0xb8, 0xe9, 0xad, 0xa1, + 0x0b, 0x29, 0xe8, 0x9f, 0xae, 0xb9, 0x5c, 0xa7, 0xb2, 0xd1, 0xaa, 0x55, 0x1c, 0xd6, 0x5c, 0x51, + 0xba, 0xf5, 0xaf, 0x65, 0xe1, 0x1e, 0x6a, 0xfa, 0x75, 0xc7, 0xd1, 0x4c, 0xd6, 0xcd, 0x04, 0x24, + 0xe6, 0xee, 0xc0, 0x9b, 0x1d, 0x2d, 0x27, 0xa1, 0xce, 0x46, 0xd4, 0x77, 0xcf, 0xba, 0xe6, 0xbc, + 0xa2, 0xee, 0xcf, 0xb8, 0x02, 0xf3, 0x74, 0xe7, 0xfc, 0xa6, 0xd1, 0xb7, 0x59, 0x58, 0xdc, 0x11, + 0xf5, 0xd8, 0x8b, 0xcd, 0x58, 0x98, 0x45, 0x3a, 0x98, 0xbb, 0xaf, 0xd4, 0x93, 0x07, 0x70, 0xa6, + 0x8d, 0x3d, 0xea, 0x9e, 0xe3, 0xce, 0xf6, 0x73, 0x5f, 0x48, 0xb9, 0x2c, 0xf7, 0x7d, 0xec, 0x25, + 0xdc, 0x09, 0x48, 0x6c, 0xcb, 0x0f, 0x00, 0x96, 0x7a, 0x6c, 0xb9, 0x1f, 0xcf, 0x6f, 0xb0, 0x66, + 0x93, 0x0a, 0x41, 0x99, 0x3f, 0x58, 0x1e, 0xf8, 0x7f, 0xe4, 0xfd, 0x0a, 0x60, 0x7e, 0x47, 0xd4, + 0xb7, 0x5b, 0xbe, 0x1b, 0x2a, 0x6a, 0xf9, 0x54, 0x1e, 0xef, 0x32, 0xe6, 0x19, 0x9f, 0xc0, 0x31, + 0xdc, 0x64, 0x2d, 0x5f, 0x2e, 0x80, 0xf2, 0xc8, 0xd2, 0xf5, 0xb7, 0x67, 0x2b, 0x3d, 0xcf, 0xa8, + 0xbd, 0x5a, 0xd9, 0x60, 0xd4, 0xaf, 0xde, 0x7e, 0xda, 0x35, 0x33, 0x4f, 0x9e, 0x9b, 0x4b, 0x97, + 0x90, 0x11, 0x2e, 0x10, 0x96, 0x06, 0x35, 0xee, 0xc1, 0x09, 0x97, 0x04, 0x4c, 0x50, 0xc9, 0xb8, + 0x3e, 0x8a, 0xd5, 0xe1, 0x8f, 0x3a, 0xc5, 0x40, 0xbf, 0x8d, 0xc0, 0xb1, 0x5d, 0xcc, 0x71, 0x53, + 0x18, 0x87, 0xf0, 0x86, 0x13, 0xef, 0xc5, 0x96, 0xf8, 0x28, 0xf2, 0x72, 0xa2, 0xba, 0x1d, 0x8a, + 0xfd, 0xa3, 0x6b, 0xde, 0xba, 0x04, 0xc7, 0x26, 0x71, 0xce, 0xba, 0x66, 0x5e, 0x39, 0x7f, 0x0e, + 0x0c, 0x59, 0x93, 0xc9, 0x78, 0x1f, 0x1f, 0x19, 0x9f, 0xc2, 0x7c, 0x0d, 0x0b, 0x62, 0x07, 0x9c, + 0x05, 0x4c, 0x10, 0x6e, 0xf3, 0xe8, 0xbe, 0x47, 0x7b, 0x9a, 0xa8, 0xee, 0x0c, 0xcd, 0xb9, 0xa8, + 0x38, 0x07, 0x61, 0x22, 0xcb, 0x08, 0xc3, 0xbb, 0x3a, 0xaa, 0x1f, 0xd6, 0x67, 0x00, 0x16, 0x6a, + 0xcc, 0x6f, 0x89, 0x0b, 0x12, 0x46, 0x22, 0x09, 0x1f, 0x0c, 0x2d, 0xe1, 0x35, 0x2d, 0x61, 0x10, + 0x28, 0xb2, 0x66, 0xa3, 0x78, 0x9f, 0x88, 0x7d, 0x58, 0x38, 0x57, 0x53, 0x6c, 0xe2, 0xe3, 0x9a, + 0x47, 0xdc, 0x85, 0x5c, 0x19, 0x2c, 0x8d, 0x57, 0xcb, 0x29, 0xea, 0xc0, 0x34, 0x64, 0xcd, 0xf6, + 0x96, 0x93, 0x2d, 0x15, 0x5d, 0xcb, 0x3d, 0x7a, 0x6c, 0x66, 0xd0, 0x17, 0x59, 0x58, 0x4c, 0x9e, + 0xcd, 0xbb, 0x54, 0x48, 0xc6, 0xa9, 0x83, 0x3d, 0xc5, 0x2c, 0x8c, 0x1f, 0x01, 0x9c, 0x77, 0x5a, + 0xcd, 0x96, 0x87, 0x25, 0x6d, 0x13, 0x2d, 0xd3, 0xe6, 0x58, 0x52, 0xa6, 0xaf, 0xee, 0x5c, 0xdf, + 0xd5, 0xdd, 0x24, 0x4e, 0x74, 0x7b, 0x3f, 0x0c, 0x9d, 0x39, 0xeb, 0x9a, 0x25, 0x7d, 0xcc, 0x83, + 0x41, 0xd0, 0x93, 0xe7, 0xe6, 0x5b, 0x97, 0xf3, 0x4e, 0x5d, 0xf1, 0x42, 0x0a, 0xa4, 0x34, 0x5a, + 0x21, 0x8c, 0xb1, 0x01, 0xa7, 0x39, 0x39, 0x20, 0x9c, 0xf8, 0x0e, 0xb1, 0x9d, 0xe8, 0x65, 0x85, + 0x77, 0xe4, 0x46, 0xb5, 0x78, 0xd6, 0x35, 0xe7, 0x94, 0x84, 0xbe, 0x04, 0x64, 0x4d, 0x25, 0x91, + 0x8d, 0x28, 0xf0, 0x08, 0xc0, 0xf9, 0xb4, 0x84, 0xb4, 0x38, 0x27, 0xbe, 0x8c, 0x8d, 0x20, 0xf0, + 0x9a, 0xd2, 0x2d, 0x5e, 0xb0, 0xef, 0x3b, 0xfa, 0xd5, 0x0e, 0xb5, 0xab, 0x18, 0xdb, 0x98, 0x83, + 0x63, 0x01, 0xe1, 0x94, 0xa9, 0x2b, 0x9e, 0xb3, 0xf4, 0x08, 0x3d, 0x04, 0xb0, 0x94, 0x48, 0x5b, + 0x77, 0xb4, 0x09, 0xc4, 0xed, 0x29, 0x74, 0x87, 0x10, 0x3a, 0xc9, 0xe8, 0x65, 0x88, 0xec, 0x81, + 0x47, 0xdf, 0x01, 0xb8, 0x98, 0xe8, 0xb9, 0xd7, 0x92, 0x42, 0x62, 0xdf, 0xa5, 0x7e, 0x3d, 0xb6, + 0xab, 0x73, 0x59, 0xbb, 0xb6, 0xf4, 0x35, 0x99, 0x8a, 0xcf, 0x28, 0x5a, 0x84, 0xae, 0x6a, 0x20, + 0xfa, 0x19, 0xc0, 0xd9, 0x44, 0xd8, 0x9e, 0x87, 0x45, 0x63, 0xab, 0x4d, 0x7c, 0x69, 0x6c, 0xc3, + 0xb4, 0x3c, 0xdb, 0xda, 0xe2, 0xb0, 0x72, 0xe5, 0xaa, 0x8b, 0x69, 0xe7, 0xee, 0xcf, 0x40, 0xd6, + 0x74, 0x12, 0xda, 0x8d, 0x22, 0xc6, 0xfb, 0x70, 0xfc, 0x80, 0x63, 0x27, 0xfc, 0xc2, 0xd1, 0x55, + 0xa8, 0x32, 0x5c, 0x09, 0xb0, 0x92, 0xf5, 0xe8, 0x17, 0x00, 0xf3, 0x03, 0xb4, 0x0a, 0xe3, 0x21, + 0x80, 0x73, 0xa9, 0x16, 0x11, 0xce, 0xd8, 0x24, 0x9a, 0xd2, 0x6e, 0xde, 0xae, 0xfc, 0xc7, 0x67, + 0x57, 0x65, 0x00, 0x66, 0xf5, 0x4d, 0xed, 0xf3, 0xeb, 0xfd, 0x3b, 0xed, 0x45, 0x47, 0x56, 0xbe, + 0x3d, 0x40, 0x8f, 0x2e, 0x15, 0xdf, 0x03, 0x78, 0x6d, 0x9b, 0x90, 0xa8, 0x81, 0x7d, 0x09, 0xe0, + 0x54, 0x5a, 0xb9, 0x03, 0xc6, 0xbc, 0x17, 0x9c, 0xf3, 0x5d, 0xcd, 0x5f, 0xe8, 0xaf, 0xfa, 0xe1, + 0xda, 0xa1, 0x8f, 0x3b, 0x6d, 0x41, 0xa1, 0x1a, 0xf4, 0x75, 0x16, 0x16, 0xcf, 0x35, 0xd8, 0xbd, + 0x80, 0xf8, 0xae, 0xaa, 0xa2, 0xd8, 0x33, 0xf2, 0x70, 0x54, 0x52, 0xe9, 0x11, 0xd5, 0xaa, 0x2c, + 0x35, 0x30, 0xca, 0xf0, 0xba, 0x4b, 0x84, 0xc3, 0x69, 0x90, 0x1e, 0xa6, 0xd5, 0x1b, 0x0a, 0xdb, + 0x28, 0x27, 0x0e, 0x0d, 0x28, 0xf1, 0x65, 0x54, 0xef, 0xaf, 0xd6, 0x46, 0x13, 0x8c, 0x9e, 0xb6, + 0x9f, 0x7b, 0x09, 0x6d, 0x7f, 0x6d, 0xfc, 0xf3, 0xc7, 0x66, 0x26, 0x3a, 0xaa, 0xbf, 0x01, 0x2c, + 0x24, 0xdf, 0x88, 0x7b, 0x12, 0x73, 0x49, 0xfd, 0xfa, 0x7b, 0xfe, 0x41, 0x54, 0x28, 0x03, 0x4e, + 0xda, 0x94, 0x85, 0xdd, 0xa7, 0xf7, 0x19, 0xf4, 0x14, 0xca, 0xbe, 0x04, 0x64, 0x4d, 0xc5, 0x11, + 0xfd, 0x08, 0xf6, 0xe1, 0xa8, 0x90, 0xf8, 0x90, 0xe8, 0x17, 0xf0, 0xce, 0xd0, 0x4d, 0x70, 0x52, + 0x11, 0x45, 0x20, 0xc8, 0x52, 0x60, 0xc6, 0x16, 0x1c, 0x6b, 0x10, 0x5a, 0x6f, 0x28, 0xaf, 0x73, + 0xd5, 0xe5, 0xbf, 0xba, 0xe6, 0xb4, 0xc3, 0x49, 0x58, 0xe0, 0x7d, 0x5b, 0x4d, 0xa5, 0x22, 0xfb, + 0x26, 0x90, 0xa5, 0x17, 0x57, 0xdf, 0xf8, 0xe9, 0xa4, 0x04, 0x9e, 0x9e, 0x94, 0xc0, 0xb3, 0x93, + 0x12, 0xf8, 0xf3, 0xa4, 0x04, 0xbe, 0x39, 0x2d, 0x65, 0x9e, 0x9d, 0x96, 0x32, 0xbf, 0x9f, 0x96, + 0x32, 0x1f, 0x8f, 0x46, 0x32, 0x6a, 0x63, 0xd1, 0x7f, 0x19, 0x77, 0xfe, 0x0d, 0x00, 0x00, 0xff, + 0xff, 0x7b, 0x35, 0xec, 0x82, 0xe1, 0x0c, 0x00, 0x00, +} + +func (this *MsgSetWithdrawAddress) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*MsgSetWithdrawAddress) + if !ok { + that2, ok := that.(MsgSetWithdrawAddress) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !bytes.Equal(this.DelegatorAddress, that1.DelegatorAddress) { + return false + } + if !bytes.Equal(this.WithdrawAddress, that1.WithdrawAddress) { + return false + } + return true +} +func (this *MsgWithdrawDelegatorReward) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*MsgWithdrawDelegatorReward) + if !ok { + that2, ok := that.(MsgWithdrawDelegatorReward) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !bytes.Equal(this.DelegatorAddress, that1.DelegatorAddress) { + return false + } + if !bytes.Equal(this.ValidatorAddress, that1.ValidatorAddress) { + return false + } + return true +} +func (this *MsgWithdrawValidatorCommission) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*MsgWithdrawValidatorCommission) + if !ok { + that2, ok := that.(MsgWithdrawValidatorCommission) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !bytes.Equal(this.ValidatorAddress, that1.ValidatorAddress) { + return false + } + return true +} +func (this *MsgFundCommunityPool) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*MsgFundCommunityPool) + if !ok { + that2, ok := that.(MsgFundCommunityPool) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if len(this.Amount) != len(that1.Amount) { + return false + } + for i := range this.Amount { + if !this.Amount[i].Equal(&that1.Amount[i]) { + return false + } + } + if !bytes.Equal(this.Depositor, that1.Depositor) { + return false + } + return true +} +func (this *Params) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*Params) + if !ok { + that2, ok := that.(Params) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !this.CommunityTax.Equal(that1.CommunityTax) { + return false + } + if !this.BaseProposerReward.Equal(that1.BaseProposerReward) { + return false + } + if !this.BonusProposerReward.Equal(that1.BonusProposerReward) { + return false + } + if this.WithdrawAddrEnabled != that1.WithdrawAddrEnabled { + return false + } + return true +} +func (this *ValidatorHistoricalRewards) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*ValidatorHistoricalRewards) + if !ok { + that2, ok := that.(ValidatorHistoricalRewards) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if len(this.CumulativeRewardRatio) != len(that1.CumulativeRewardRatio) { + return false + } + for i := range this.CumulativeRewardRatio { + if !this.CumulativeRewardRatio[i].Equal(&that1.CumulativeRewardRatio[i]) { + return false + } + } + if this.ReferenceCount != that1.ReferenceCount { + return false + } + return true +} +func (this *ValidatorCurrentRewards) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*ValidatorCurrentRewards) + if !ok { + that2, ok := that.(ValidatorCurrentRewards) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if len(this.Rewards) != len(that1.Rewards) { + return false + } + for i := range this.Rewards { + if !this.Rewards[i].Equal(&that1.Rewards[i]) { + return false + } + } + if this.Period != that1.Period { + return false + } + return true +} +func (this *ValidatorAccumulatedCommission) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*ValidatorAccumulatedCommission) + if !ok { + that2, ok := that.(ValidatorAccumulatedCommission) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if len(this.Commission) != len(that1.Commission) { + return false + } + for i := range this.Commission { + if !this.Commission[i].Equal(&that1.Commission[i]) { + return false + } + } + return true } +func (this *ValidatorOutstandingRewards) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + that1, ok := that.(*ValidatorOutstandingRewards) + if !ok { + that2, ok := that.(ValidatorOutstandingRewards) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if len(this.Rewards) != len(that1.Rewards) { + return false + } + for i := range this.Rewards { + if !this.Rewards[i].Equal(&that1.Rewards[i]) { + return false + } + } + return true +} +func (this *ValidatorSlashEvent) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*ValidatorSlashEvent) + if !ok { + that2, ok := that.(ValidatorSlashEvent) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.ValidatorPeriod != that1.ValidatorPeriod { + return false + } + if !this.Fraction.Equal(that1.Fraction) { + return false + } + return true +} +func (this *ValidatorSlashEvents) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*ValidatorSlashEvents) + if !ok { + that2, ok := that.(ValidatorSlashEvents) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if len(this.ValidatorSlashEvents) != len(that1.ValidatorSlashEvents) { + return false + } + for i := range this.ValidatorSlashEvents { + if !this.ValidatorSlashEvents[i].Equal(&that1.ValidatorSlashEvents[i]) { + return false + } + } + return true +} +func (this *FeePool) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*FeePool) + if !ok { + that2, ok := that.(FeePool) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if len(this.CommunityPool) != len(that1.CommunityPool) { + return false + } + for i := range this.CommunityPool { + if !this.CommunityPool[i].Equal(&that1.CommunityPool[i]) { + return false + } + } + return true +} +func (this *CommunityPoolSpendProposal) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*CommunityPoolSpendProposal) + if !ok { + that2, ok := that.(CommunityPoolSpendProposal) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Title != that1.Title { + return false + } + if this.Description != that1.Description { + return false + } + if !bytes.Equal(this.Recipient, that1.Recipient) { + return false + } + if len(this.Amount) != len(that1.Amount) { + return false + } + for i := range this.Amount { + if !this.Amount[i].Equal(&that1.Amount[i]) { + return false + } + } + return true +} +func (this *DelegatorStartingInfo) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*DelegatorStartingInfo) + if !ok { + that2, ok := that.(DelegatorStartingInfo) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.PreviousPeriod != that1.PreviousPeriod { + return false + } + if !this.Stake.Equal(that1.Stake) { + return false + } + if this.Height != that1.Height { + return false + } + return true +} func (m *MsgSetWithdrawAddress) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) diff --git a/x/distribution/types/types.proto b/x/distribution/types/types.proto index be398e09126a..a783be13f557 100644 --- a/x/distribution/types/types.proto +++ b/x/distribution/types/types.proto @@ -1,7 +1,8 @@ syntax = "proto3"; package cosmos_sdk.x.ditribution.v1; -option go_package = "types"; +option go_package = "types"; +option (gogoproto.equal_all) = true; import "third_party/proto/gogoproto/gogo.proto"; import "types/types.proto"; @@ -175,8 +176,6 @@ message DelegatorStartingInfo { (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false ]; - uint64 height = 3 [ - (gogoproto.moretags) = "yaml:\"creation_height\"", - (gogoproto.jsontag) = "creation_height" - ]; + uint64 height = 3 + [(gogoproto.moretags) = "yaml:\"creation_height\"", (gogoproto.jsontag) = "creation_height"]; } diff --git a/x/params/types/proposal/types.pb.go b/x/params/types/proposal/types.pb.go index fdc33948cf25..29f95f728a8e 100644 --- a/x/params/types/proposal/types.pb.go +++ b/x/params/types/proposal/types.pb.go @@ -133,7 +133,7 @@ func init() { } var fileDescriptor_0ab50f1d22a2cb61 = []byte{ - // 313 bytes of a gzipped FileDescriptorProto + // 317 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0xae, 0xd0, 0x2f, 0x48, 0x2c, 0x4a, 0xcc, 0x2d, 0xd6, 0x2f, 0xa9, 0x2c, 0x48, 0x2d, 0xd6, 0x2f, 0x28, 0xca, 0x2f, 0xc8, 0x2f, 0x4e, 0xcc, 0x81, 0x70, 0xf5, 0x0a, 0x8a, 0xf2, 0x4b, 0xf2, 0x85, 0xc4, 0x92, 0xf3, 0x8b, @@ -149,13 +149,78 @@ var fileDescriptor_0ab50f1d22a2cb61 = []byte{ 0x28, 0x85, 0x73, 0x71, 0x23, 0xa9, 0x13, 0x92, 0xe2, 0xe2, 0x28, 0x2e, 0x4d, 0x2a, 0x2e, 0x48, 0x4c, 0x86, 0x39, 0x0c, 0xce, 0x17, 0x12, 0xe0, 0x62, 0xce, 0x4e, 0xad, 0x84, 0xba, 0x09, 0xc4, 0x04, 0xf9, 0xa1, 0x2c, 0x31, 0xa7, 0x34, 0x55, 0x82, 0x19, 0xe2, 0x07, 0x30, 0xc7, 0x8a, 0x05, - 0x64, 0xb0, 0x93, 0xdf, 0x89, 0x47, 0x72, 0x8c, 0x17, 0x1e, 0xc9, 0x31, 0x3e, 0x78, 0x24, 0xc7, - 0x38, 0xe1, 0xb1, 0x1c, 0xc3, 0x85, 0xc7, 0x72, 0x0c, 0x37, 0x1e, 0xcb, 0x31, 0x44, 0x99, 0xa4, - 0x67, 0x96, 0x64, 0x94, 0x26, 0xe9, 0x25, 0xe7, 0xe7, 0xea, 0x43, 0x9c, 0x0e, 0xa5, 0x74, 0x8b, - 0x53, 0xb2, 0xf5, 0x71, 0xc4, 0x4b, 0x12, 0x1b, 0x38, 0x48, 0x8d, 0x01, 0x01, 0x00, 0x00, 0xff, - 0xff, 0x11, 0x0a, 0x5a, 0xe0, 0xb9, 0x01, 0x00, 0x00, + 0x64, 0xb0, 0x53, 0xd0, 0x8a, 0x47, 0x72, 0x8c, 0x27, 0x1e, 0xc9, 0x31, 0x5e, 0x78, 0x24, 0xc7, + 0xf8, 0xe0, 0x91, 0x1c, 0xe3, 0x84, 0xc7, 0x72, 0x0c, 0x17, 0x1e, 0xcb, 0x31, 0xdc, 0x78, 0x2c, + 0xc7, 0x10, 0x65, 0x92, 0x9e, 0x59, 0x92, 0x51, 0x9a, 0xa4, 0x97, 0x9c, 0x9f, 0xab, 0x0f, 0x71, + 0x3e, 0x94, 0xd2, 0x2d, 0x4e, 0xc9, 0xd6, 0xc7, 0x11, 0x37, 0x49, 0x6c, 0xe0, 0x60, 0x35, 0x06, + 0x04, 0x00, 0x00, 0xff, 0xff, 0x17, 0xa9, 0xe7, 0x51, 0xbd, 0x01, 0x00, 0x00, } +func (this *ParameterChangeProposal) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*ParameterChangeProposal) + if !ok { + that2, ok := that.(ParameterChangeProposal) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Title != that1.Title { + return false + } + if this.Description != that1.Description { + return false + } + if len(this.Changes) != len(that1.Changes) { + return false + } + for i := range this.Changes { + if !this.Changes[i].Equal(&that1.Changes[i]) { + return false + } + } + return true +} +func (this *ParamChange) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*ParamChange) + if !ok { + that2, ok := that.(ParamChange) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Subspace != that1.Subspace { + return false + } + if this.Key != that1.Key { + return false + } + if this.Value != that1.Value { + return false + } + return true +} func (m *ParameterChangeProposal) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) diff --git a/x/params/types/proposal/types.proto b/x/params/types/proposal/types.proto index 2e4e18f72f4a..8563b8c82d4b 100644 --- a/x/params/types/proposal/types.proto +++ b/x/params/types/proposal/types.proto @@ -1,7 +1,8 @@ syntax = "proto3"; package cosmos_sdk.x.params.v1; -option go_package = "github.com/cosmos/cosmos-sdk/x/params/types/proposal"; +option go_package = "github.com/cosmos/cosmos-sdk/x/params/types/proposal"; +option (gogoproto.equal_all) = true; import "third_party/proto/gogoproto/gogo.proto"; diff --git a/x/slashing/types/types.pb.go b/x/slashing/types/types.pb.go index a5444def9e35..7358555a1043 100644 --- a/x/slashing/types/types.pb.go +++ b/x/slashing/types/types.pb.go @@ -171,40 +171,64 @@ func init() { func init() { proto.RegisterFile("x/slashing/types/types.proto", fileDescriptor_57cb37764f972476) } var fileDescriptor_57cb37764f972476 = []byte{ - // 488 bytes of a gzipped FileDescriptorProto + // 492 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0xbf, 0x6f, 0xd3, 0x40, 0x14, 0xc7, 0x73, 0x04, 0x4a, 0xb9, 0x84, 0x0e, 0x2e, 0x08, 0x2b, 0xaa, 0x7c, 0x91, 0x07, 0x94, - 0xa5, 0xb6, 0x28, 0x5b, 0x36, 0xdc, 0x01, 0x90, 0xf8, 0x21, 0x99, 0xb6, 0x03, 0x03, 0xd6, 0x39, - 0x77, 0x39, 0x1f, 0xb1, 0xef, 0x22, 0xdf, 0xb9, 0x4a, 0x56, 0xfe, 0x82, 0x8e, 0x8c, 0xfd, 0x43, - 0xf8, 0x03, 0x3a, 0x76, 0x64, 0x32, 0x28, 0x59, 0x10, 0x63, 0xc6, 0x4e, 0xc8, 0xbe, 0x98, 0x46, - 0x15, 0x42, 0x5d, 0xec, 0x7b, 0x9f, 0xfb, 0xbe, 0xf7, 0xbd, 0x77, 0xef, 0xe0, 0xde, 0xcc, 0x57, - 0x29, 0x56, 0x09, 0x17, 0xcc, 0xd7, 0xf3, 0x29, 0x55, 0xe6, 0xeb, 0x4d, 0x73, 0xa9, 0xa5, 0x65, - 0x8f, 0xa4, 0xca, 0xa4, 0x8a, 0x14, 0x99, 0x78, 0x33, 0xaf, 0x11, 0x7a, 0xa7, 0xcf, 0x7a, 0x4f, - 0x75, 0xc2, 0x73, 0x12, 0x4d, 0x71, 0xae, 0xe7, 0x7e, 0x2d, 0xf6, 0x99, 0x64, 0xf2, 0x7a, 0x65, - 0x2a, 0xf4, 0x10, 0x93, 0x92, 0xa5, 0xd4, 0x48, 0xe2, 0x62, 0xec, 0x6b, 0x9e, 0x51, 0xa5, 0x71, - 0x36, 0x35, 0x02, 0xf7, 0x0b, 0x80, 0x0f, 0xde, 0x2a, 0x76, 0x2c, 0x3e, 0x63, 0x9e, 0x5a, 0x05, - 0xdc, 0x39, 0xc5, 0x29, 0x27, 0x58, 0xcb, 0x3c, 0xc2, 0x84, 0xe4, 0x36, 0xe8, 0x83, 0x41, 0x37, - 0x78, 0xf7, 0xbb, 0x44, 0xf7, 0xab, 0x98, 0x2a, 0xb5, 0x2a, 0xd1, 0xce, 0x1c, 0x67, 0xe9, 0xd0, - 0x5d, 0x03, 0xf7, 0xaa, 0x44, 0xfb, 0x8c, 0xeb, 0xa4, 0x88, 0xbd, 0x91, 0xcc, 0x7c, 0x73, 0xe8, - 0xf5, 0x6f, 0x5f, 0x91, 0xc9, 0xba, 0xa7, 0x13, 0x9c, 0xbe, 0x30, 0x19, 0xe1, 0xc3, 0xbf, 0x2e, - 0x15, 0x71, 0xbf, 0xb5, 0xe1, 0xa3, 0x93, 0x86, 0x7c, 0xe0, 0x4c, 0x70, 0xc1, 0x5e, 0x8b, 0xb1, - 0xb4, 0xde, 0xc0, 0xc6, 0x75, 0x7d, 0x90, 0x83, 0xab, 0x12, 0x79, 0xb7, 0xf0, 0x3a, 0x94, 0x42, - 0x35, 0x66, 0x4d, 0x09, 0x6b, 0x08, 0xbb, 0x4a, 0xe3, 0x5c, 0x47, 0x09, 0xe5, 0x2c, 0xd1, 0xf6, - 0x9d, 0x3e, 0x18, 0xb4, 0x83, 0x27, 0xab, 0x12, 0xed, 0x9a, 0x86, 0x36, 0x77, 0xdd, 0xb0, 0x53, - 0x87, 0xaf, 0xea, 0xa8, 0xca, 0xe5, 0x82, 0xd0, 0x59, 0x24, 0xc7, 0x63, 0x45, 0xb5, 0xdd, 0xbe, - 0x99, 0xbb, 0xb9, 0xeb, 0x86, 0x9d, 0x3a, 0x7c, 0x5f, 0x47, 0xd6, 0x27, 0xd8, 0xad, 0x6e, 0x97, - 0x92, 0xa8, 0x10, 0x9a, 0xa7, 0xf6, 0xdd, 0x3e, 0x18, 0x74, 0x0e, 0x7a, 0x9e, 0x99, 0x8d, 0xd7, - 0xcc, 0xc6, 0x3b, 0x6a, 0x66, 0x13, 0xa0, 0x8b, 0x12, 0xb5, 0xae, 0x6b, 0x6f, 0x66, 0xbb, 0x67, - 0x3f, 0x10, 0x08, 0x3b, 0x06, 0x1d, 0x57, 0xc4, 0x72, 0x20, 0xd4, 0x32, 0x8b, 0x95, 0x96, 0x82, - 0x12, 0xfb, 0x5e, 0x1f, 0x0c, 0xb6, 0xc3, 0x0d, 0x62, 0x1d, 0xc1, 0xc7, 0x19, 0x57, 0x8a, 0x92, - 0x28, 0x4e, 0xe5, 0x68, 0xa2, 0xa2, 0x91, 0x2c, 0x84, 0xa6, 0xb9, 0xbd, 0x55, 0x37, 0xd1, 0x5f, - 0x95, 0x68, 0xcf, 0x18, 0xfd, 0x53, 0xe6, 0x86, 0xbb, 0x86, 0x07, 0x35, 0x3e, 0x34, 0x74, 0xb8, - 0xfd, 0xf5, 0x1c, 0xb5, 0x7e, 0x9d, 0x23, 0x10, 0xbc, 0xbc, 0x58, 0x38, 0xe0, 0x72, 0xe1, 0x80, - 0x9f, 0x0b, 0x07, 0x9c, 0x2d, 0x9d, 0xd6, 0xe5, 0xd2, 0x69, 0x7d, 0x5f, 0x3a, 0xad, 0x8f, 0xff, - 0x7f, 0x16, 0x37, 0xdf, 0x7e, 0xbc, 0x55, 0x5f, 0xc5, 0xf3, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, - 0xf7, 0x43, 0x16, 0x33, 0x16, 0x03, 0x00, 0x00, -} + 0xa5, 0xb6, 0x28, 0x5b, 0x36, 0xdc, 0x05, 0xc4, 0x2f, 0xc9, 0xb4, 0x1d, 0x18, 0xb0, 0xce, 0xb9, + 0xcb, 0xf9, 0x88, 0x7d, 0x17, 0xf9, 0xce, 0x55, 0xb2, 0xf2, 0x17, 0x74, 0x64, 0xec, 0xc8, 0x1f, + 0xc1, 0x1f, 0xd0, 0xb1, 0x23, 0x93, 0x41, 0xc9, 0x82, 0x18, 0x33, 0x76, 0x42, 0xf6, 0xc5, 0x34, + 0xaa, 0x10, 0x62, 0xb1, 0xef, 0x7d, 0xee, 0xfb, 0xde, 0xf7, 0xde, 0xbd, 0x83, 0x7b, 0x33, 0x5f, + 0xa5, 0x58, 0x25, 0x5c, 0x30, 0x5f, 0xcf, 0xa7, 0x54, 0x99, 0xaf, 0x37, 0xcd, 0xa5, 0x96, 0x96, + 0x3d, 0x92, 0x2a, 0x93, 0x2a, 0x52, 0x64, 0xe2, 0xcd, 0xbc, 0x46, 0xe8, 0x9d, 0x3e, 0xe9, 0x3d, + 0xd6, 0x09, 0xcf, 0x49, 0x34, 0xc5, 0xb9, 0x9e, 0xfb, 0xb5, 0xd8, 0x67, 0x92, 0xc9, 0xeb, 0x95, + 0xa9, 0xd0, 0x43, 0x4c, 0x4a, 0x96, 0x52, 0x23, 0x89, 0x8b, 0xb1, 0xaf, 0x79, 0x46, 0x95, 0xc6, + 0xd9, 0xd4, 0x08, 0xdc, 0x4f, 0x00, 0xde, 0x7b, 0xad, 0xd8, 0xb1, 0xf8, 0x88, 0x79, 0x6a, 0x15, + 0x70, 0xe7, 0x14, 0xa7, 0x9c, 0x60, 0x2d, 0xf3, 0x08, 0x13, 0x92, 0xdb, 0xa0, 0x0f, 0x06, 0xdd, + 0xe0, 0xcd, 0xaf, 0x12, 0xdd, 0xad, 0x62, 0xaa, 0xd4, 0xaa, 0x44, 0x3b, 0x73, 0x9c, 0xa5, 0x43, + 0x77, 0x0d, 0xdc, 0xab, 0x12, 0xed, 0x33, 0xae, 0x93, 0x22, 0xf6, 0x46, 0x32, 0xf3, 0xcd, 0xa1, + 0xd7, 0xbf, 0x7d, 0x45, 0x26, 0xeb, 0x9e, 0x4e, 0x70, 0xfa, 0xcc, 0x64, 0x84, 0xf7, 0xff, 0xb8, + 0x54, 0xc4, 0xfd, 0xda, 0x86, 0x0f, 0x4e, 0x1a, 0xf2, 0x8e, 0x33, 0xc1, 0x05, 0x7b, 0x21, 0xc6, + 0xd2, 0x7a, 0x05, 0x1b, 0xd7, 0xf5, 0x41, 0x0e, 0xae, 0x4a, 0xe4, 0xfd, 0x87, 0xd7, 0xa1, 0x14, + 0xaa, 0x31, 0x6b, 0x4a, 0x58, 0x43, 0xd8, 0x55, 0x1a, 0xe7, 0x3a, 0x4a, 0x28, 0x67, 0x89, 0xb6, + 0x6f, 0xf5, 0xc1, 0xa0, 0x1d, 0x3c, 0x5a, 0x95, 0x68, 0xd7, 0x34, 0xb4, 0xb9, 0xeb, 0x86, 0x9d, + 0x3a, 0x7c, 0x5e, 0x47, 0x55, 0x2e, 0x17, 0x84, 0xce, 0x22, 0x39, 0x1e, 0x2b, 0xaa, 0xed, 0xf6, + 0xcd, 0xdc, 0xcd, 0x5d, 0x37, 0xec, 0xd4, 0xe1, 0xdb, 0x3a, 0xb2, 0x3e, 0xc0, 0x6e, 0x75, 0xbb, + 0x94, 0x44, 0x85, 0xd0, 0x3c, 0xb5, 0x6f, 0xf7, 0xc1, 0xa0, 0x73, 0xd0, 0xf3, 0xcc, 0x6c, 0xbc, + 0x66, 0x36, 0xde, 0x51, 0x33, 0x9b, 0x00, 0x5d, 0x94, 0xa8, 0x75, 0x5d, 0x7b, 0x33, 0xdb, 0x3d, + 0xfb, 0x8e, 0x40, 0xd8, 0x31, 0xe8, 0xb8, 0x22, 0x96, 0x03, 0xa1, 0x96, 0x59, 0xac, 0xb4, 0x14, + 0x94, 0xd8, 0x77, 0xfa, 0x60, 0xb0, 0x1d, 0x6e, 0x10, 0xeb, 0x08, 0x3e, 0xcc, 0xb8, 0x52, 0x94, + 0x44, 0x71, 0x2a, 0x47, 0x13, 0x15, 0x8d, 0x64, 0x21, 0x34, 0xcd, 0xed, 0xad, 0xba, 0x89, 0xfe, + 0xaa, 0x44, 0x7b, 0xc6, 0xe8, 0xaf, 0x32, 0x37, 0xdc, 0x35, 0x3c, 0xa8, 0xf1, 0xa1, 0xa1, 0xc3, + 0xed, 0xcf, 0xe7, 0xa8, 0xf5, 0xf3, 0x1c, 0x81, 0xe0, 0xe5, 0x97, 0x85, 0x03, 0x2e, 0x16, 0x0e, + 0xb8, 0x5c, 0x38, 0xe0, 0xc7, 0xc2, 0x01, 0x67, 0x4b, 0xa7, 0x75, 0xb9, 0x74, 0x5a, 0xdf, 0x96, + 0x4e, 0xeb, 0xfd, 0xbf, 0x9f, 0xc6, 0xcd, 0xf7, 0x1f, 0x6f, 0xd5, 0xd7, 0xf1, 0xf4, 0x77, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x72, 0x9e, 0xc6, 0x73, 0x1a, 0x03, 0x00, 0x00, +} + +func (this *MsgUnjail) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + that1, ok := that.(*MsgUnjail) + if !ok { + that2, ok := that.(MsgUnjail) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !bytes.Equal(this.ValidatorAddr, that1.ValidatorAddr) { + return false + } + return true +} func (this *ValidatorSigningInfo) Equal(that interface{}) bool { if that == nil { return this == nil diff --git a/x/slashing/types/types.proto b/x/slashing/types/types.proto index dfd7cf75dbe4..d89affb62fb2 100644 --- a/x/slashing/types/types.proto +++ b/x/slashing/types/types.proto @@ -1,7 +1,8 @@ syntax = "proto3"; package cosmos_sdk.x.slashing.v1; -option go_package = "github.com/cosmos/cosmos-sdk/x/slashing/types"; +option go_package = "github.com/cosmos/cosmos-sdk/x/slashing/types"; +option (gogoproto.equal_all) = true; import "third_party/proto/gogoproto/gogo.proto"; import "google/protobuf/timestamp.proto"; diff --git a/x/staking/types/types.pb.go b/x/staking/types/types.pb.go index 78da36fae466..ca9394854763 100644 --- a/x/staking/types/types.pb.go +++ b/x/staking/types/types.pb.go @@ -1242,13 +1242,13 @@ func init() { func init() { proto.RegisterFile("x/staking/types/types.proto", fileDescriptor_c669c0a3ee1b124c) } var fileDescriptor_c669c0a3ee1b124c = []byte{ - // 1678 bytes of a gzipped FileDescriptorProto + // 1682 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x59, 0xcd, 0x6f, 0x23, 0x49, 0x15, 0x4f, 0xdb, 0x8e, 0x9d, 0x3c, 0x4f, 0xec, 0xa4, 0xa3, 0xc9, 0x78, 0xb2, 0xac, 0x3b, 0xf4, 0xa2, 0x55, 0x84, 0x58, 0x5b, 0xd9, 0x45, 0x42, 0xca, 0x5e, 0x76, 0x1c, 0x27, 0x4a, 0x50, 0x82, 0x66, 0x3b, 0xb3, 0x39, 0xf0, 0x21, 0xab, 0xdc, 0x5d, 0x69, 0x17, 0x71, 0x77, 0x9b, 0xae, 0x72, - 0xd6, 0x41, 0x5c, 0x91, 0x10, 0x12, 0x62, 0x2f, 0x48, 0x73, 0x1c, 0xf1, 0x0f, 0x70, 0x45, 0x70, - 0xe1, 0x38, 0xdc, 0x46, 0x20, 0x21, 0xc4, 0xc1, 0xa0, 0x99, 0x0b, 0xe2, 0x04, 0x3e, 0x70, 0xe0, + 0xd6, 0x41, 0x5c, 0x91, 0x10, 0x12, 0x62, 0x2f, 0x48, 0x7b, 0x1c, 0xf1, 0x0f, 0xf0, 0x1f, 0xa0, + 0xe1, 0x36, 0xdc, 0x46, 0x1c, 0x10, 0x70, 0x30, 0x68, 0xe6, 0x82, 0x38, 0x21, 0x1f, 0x40, 0xe2, 0x84, 0xba, 0xaa, 0xfa, 0x23, 0x6d, 0x7b, 0xc6, 0xc9, 0x30, 0xc3, 0x48, 0x93, 0xcb, 0x8c, 0xeb, 0xf5, 0x7b, 0xbf, 0x57, 0xf5, 0xbe, 0xab, 0x02, 0xef, 0x0c, 0xea, 0x94, 0xa1, 0x33, 0xe2, 0xda, 0x75, 0x76, 0xd1, 0xc3, 0x54, 0xfc, 0x5b, 0xeb, 0xf9, 0x1e, 0xf3, 0xd4, 0x3b, 0xa6, 0x47, 0x1d, @@ -1257,99 +1257,276 @@ var fileDescriptor_c669c0a3ee1b124c = []byte{ 0xd6, 0x3f, 0x1a, 0xe7, 0x63, 0xd8, 0xb5, 0xb0, 0xef, 0x10, 0x97, 0xd5, 0x51, 0xdb, 0x24, 0xe3, 0x5a, 0xd7, 0x35, 0xdb, 0xf3, 0xec, 0x2e, 0x16, 0xfc, 0xed, 0xfe, 0x69, 0x9d, 0x11, 0x07, 0x53, 0x86, 0x9c, 0x9e, 0x64, 0xa8, 0xa6, 0x19, 0xac, 0xbe, 0x8f, 0x18, 0xf1, 0x5c, 0xf9, 0x7d, 0x65, - 0x0c, 0x53, 0xff, 0x57, 0x0e, 0xd4, 0x23, 0x6a, 0xef, 0xf8, 0x18, 0x31, 0x7c, 0x82, 0xba, 0xc4, + 0x0c, 0x53, 0xff, 0x77, 0x0e, 0xd4, 0x23, 0x6a, 0xef, 0xf8, 0x18, 0x31, 0x7c, 0x82, 0xba, 0xc4, 0x42, 0xcc, 0xf3, 0xd5, 0x43, 0x28, 0x5a, 0x98, 0x9a, 0x3e, 0xe9, 0x05, 0xe2, 0x15, 0x65, 0x43, - 0xd9, 0x2c, 0x7e, 0xf8, 0x95, 0xda, 0x94, 0x63, 0xd7, 0x9a, 0x31, 0x6f, 0x23, 0xf7, 0x78, 0xa8, - 0xcd, 0x19, 0x49, 0x71, 0xf5, 0x5b, 0x00, 0xa6, 0xe7, 0x38, 0x84, 0xd2, 0x00, 0x2c, 0xc3, 0xc1, - 0x36, 0xa7, 0x82, 0xed, 0x44, 0xac, 0x06, 0x62, 0x98, 0x4a, 0xc0, 0x04, 0x82, 0xfa, 0x23, 0x58, + 0xd9, 0x2c, 0x7e, 0xf8, 0xb5, 0xda, 0x94, 0x63, 0xd7, 0x9a, 0x31, 0x6f, 0x23, 0xf7, 0x78, 0xa8, + 0xcd, 0x19, 0x49, 0x71, 0xf5, 0x3b, 0x00, 0xa6, 0xe7, 0x38, 0x84, 0xd2, 0x00, 0x2c, 0xc3, 0xc1, + 0x36, 0xa7, 0x82, 0xed, 0x44, 0xac, 0x06, 0x62, 0x98, 0x4a, 0xc0, 0x04, 0x82, 0xfa, 0x13, 0x58, 0x75, 0x88, 0xdb, 0xa2, 0xb8, 0x7b, 0xda, 0xb2, 0x70, 0x17, 0xdb, 0xfc, 0x90, 0x95, 0xec, 0x86, 0xb2, 0xb9, 0xd8, 0x38, 0x0c, 0xd8, 0xff, 0x32, 0xd4, 0xde, 0xb7, 0x09, 0xeb, 0xf4, 0xdb, 0x35, 0xd3, 0x73, 0xea, 0x42, 0x95, 0xfc, 0xef, 0x03, 0x6a, 0x9d, 0x49, 0x1b, 0x1c, 0xb8, 0x6c, 0x34, 0xd4, 0xd6, 0x2f, 0x90, 0xd3, 0xdd, 0xd6, 0x27, 0x40, 0xea, 0xc6, 0x8a, 0x43, 0xdc, 0x63, 0xdc, - 0x3d, 0x6d, 0x46, 0x34, 0xf5, 0x87, 0xb0, 0x22, 0x39, 0x3c, 0xbf, 0x85, 0x2c, 0xcb, 0xc7, 0x94, + 0x3d, 0x6d, 0x46, 0x34, 0xf5, 0xc7, 0xb0, 0x22, 0x39, 0x3c, 0xbf, 0x85, 0x2c, 0xcb, 0xc7, 0x94, 0x56, 0x72, 0x1b, 0xca, 0xe6, 0xad, 0xc6, 0xd1, 0x68, 0xa8, 0x55, 0x04, 0xda, 0x18, 0x8b, 0xfe, 0x9f, 0xa1, 0xf6, 0xc1, 0x0c, 0x7b, 0xba, 0x67, 0x9a, 0xf7, 0x84, 0x84, 0xb1, 0x1c, 0x81, 0x48, 0x4a, 0xa0, 0xfb, 0x3c, 0x74, 0x52, 0xa4, 0x7b, 0x3e, 0xad, 0x7b, 0x8c, 0x65, 0x56, 0xdd, 0x27, 0xa8, 0x1b, 0xe9, 0x8e, 0x40, 0x42, 0xdd, 0x6b, 0x90, 0xef, 0xf5, 0xdb, 0x67, 0xf8, 0xa2, 0x92, 0x0f, 0x0c, 0x6d, 0xc8, 0x95, 0x5a, 0x87, 0xf9, 0x73, 0xd4, 0xed, 0xe3, 0x4a, 0x81, 0x3b, 0x76, - 0x35, 0xe9, 0x58, 0xee, 0x4e, 0x12, 0x06, 0x85, 0xe0, 0xd3, 0x7f, 0x9b, 0x85, 0xe5, 0x23, 0x6a, - 0xef, 0x5a, 0x84, 0xbd, 0xaa, 0x88, 0xeb, 0x4d, 0xb2, 0x53, 0x86, 0xdb, 0x69, 0x67, 0x34, 0xd4, - 0x4a, 0xc2, 0x4e, 0xff, 0x4b, 0xeb, 0x38, 0x50, 0x8e, 0x23, 0xb4, 0xe5, 0x23, 0x86, 0x65, 0x3c, - 0x36, 0x67, 0x8c, 0xc5, 0x26, 0x36, 0x47, 0x43, 0x6d, 0x4d, 0xec, 0x2c, 0x05, 0xa5, 0x1b, 0x25, - 0xf3, 0x52, 0x56, 0xa8, 0x83, 0xc9, 0x29, 0x90, 0xe3, 0x2a, 0xf7, 0x5f, 0x61, 0xf8, 0xeb, 0xbf, - 0xce, 0x40, 0xf1, 0x88, 0xda, 0x92, 0x82, 0x27, 0xa7, 0x83, 0xf2, 0x7f, 0x4c, 0x87, 0xcc, 0xeb, - 0x49, 0x87, 0x2d, 0xc8, 0x23, 0xc7, 0xeb, 0xbb, 0x8c, 0xfb, 0xf9, 0xb9, 0x71, 0x2f, 0x19, 0xf5, - 0x3f, 0x66, 0x79, 0xb1, 0x6d, 0x60, 0x9b, 0xb8, 0x06, 0xb6, 0xde, 0x04, 0x0b, 0xfe, 0x58, 0x81, - 0xdb, 0xb1, 0x7d, 0xa8, 0x6f, 0xa6, 0xcc, 0xf8, 0xe9, 0x68, 0xa8, 0x7d, 0x29, 0x6d, 0xc6, 0x04, - 0xdb, 0x35, 0x4c, 0xb9, 0x1a, 0x01, 0x1d, 0xfb, 0xe6, 0xe4, 0x7d, 0x58, 0x94, 0x45, 0xfb, 0xc8, - 0x4e, 0xdf, 0x47, 0x82, 0xed, 0xa5, 0xf6, 0xd1, 0xa4, 0x6c, 0xdc, 0xab, 0xb9, 0x59, 0xbd, 0xfa, - 0x9b, 0x0c, 0x2c, 0x1d, 0x51, 0xfb, 0x33, 0xd7, 0xba, 0x49, 0x89, 0x2b, 0xa7, 0xc4, 0x2f, 0x14, - 0x28, 0xed, 0x13, 0xca, 0x3c, 0x9f, 0x98, 0xa8, 0x7b, 0xe0, 0x9e, 0x7a, 0xea, 0xc7, 0x90, 0xef, - 0x60, 0x64, 0x61, 0x5f, 0x36, 0x81, 0x77, 0x6b, 0xf1, 0x68, 0x54, 0x0b, 0x46, 0xa3, 0x9a, 0xd8, - 0xca, 0x3e, 0x67, 0x0a, 0xf1, 0x84, 0x88, 0xfa, 0x09, 0xe4, 0xcf, 0x51, 0x97, 0x62, 0x56, 0xc9, - 0x6c, 0x64, 0x37, 0x8b, 0x1f, 0xea, 0x53, 0x3b, 0x48, 0xd4, 0x7a, 0x42, 0x04, 0x21, 0xb7, 0x9d, - 0xfb, 0xfb, 0x23, 0x4d, 0xd1, 0x7f, 0x95, 0x81, 0x72, 0x6a, 0x10, 0x51, 0x1b, 0x90, 0xe3, 0x75, - 0x5d, 0xe1, 0x45, 0xb6, 0x76, 0x85, 0x39, 0xa3, 0x89, 0x4d, 0x83, 0xcb, 0xaa, 0xdf, 0x85, 0x05, - 0x07, 0x0d, 0x44, 0x7f, 0xc8, 0x70, 0x9c, 0x7b, 0x57, 0xc3, 0x19, 0x0d, 0xb5, 0xb2, 0x2c, 0xd8, - 0x12, 0x47, 0x37, 0x0a, 0x0e, 0x1a, 0xf0, 0xae, 0xd0, 0x83, 0x72, 0x40, 0x35, 0x3b, 0xc8, 0xb5, - 0x71, 0xb2, 0x09, 0xed, 0x5f, 0x59, 0xc9, 0x5a, 0xac, 0x24, 0x01, 0xa7, 0x1b, 0x4b, 0x0e, 0x1a, - 0xec, 0x70, 0x42, 0xa0, 0x71, 0x7b, 0xe1, 0xe1, 0x23, 0x6d, 0x8e, 0x5b, 0xec, 0x0f, 0x0a, 0x40, - 0x6c, 0x31, 0xf5, 0x7b, 0xb0, 0x9c, 0x6a, 0x62, 0x54, 0xfa, 0x73, 0xf6, 0xc9, 0x6f, 0x21, 0xd8, - 0xf5, 0x93, 0xa1, 0xa6, 0x18, 0x65, 0x33, 0xe5, 0x8b, 0xef, 0x40, 0xb1, 0xdf, 0xb3, 0x10, 0xc3, - 0xad, 0x60, 0x08, 0x96, 0x33, 0xe5, 0x7a, 0x4d, 0x0c, 0xc0, 0xb5, 0x70, 0x00, 0xae, 0x3d, 0x08, - 0x27, 0xe4, 0x46, 0x35, 0xc0, 0x1a, 0x0d, 0x35, 0x55, 0x9c, 0x2b, 0x21, 0xac, 0x7f, 0xf1, 0x57, - 0x4d, 0x31, 0x40, 0x50, 0x02, 0x81, 0xc4, 0xa1, 0x7e, 0xaf, 0x40, 0x31, 0x31, 0x6a, 0xa8, 0x15, - 0x28, 0x38, 0x9e, 0x4b, 0xce, 0x64, 0x70, 0x2e, 0x1a, 0xe1, 0x52, 0x5d, 0x87, 0x05, 0x62, 0x61, - 0x97, 0x11, 0x76, 0x21, 0x1c, 0x6b, 0x44, 0xeb, 0x40, 0xea, 0x73, 0xdc, 0xa6, 0x24, 0x74, 0x87, - 0x11, 0x2e, 0xd5, 0x3d, 0x58, 0xa6, 0xd8, 0xec, 0xfb, 0x84, 0x5d, 0xb4, 0x4c, 0xcf, 0x65, 0xc8, - 0x64, 0xb2, 0x87, 0xbf, 0x33, 0x1a, 0x6a, 0x77, 0xc4, 0x5e, 0xd3, 0x1c, 0xba, 0x51, 0x0e, 0x49, - 0x3b, 0x82, 0x12, 0x68, 0xb0, 0x30, 0x43, 0xa4, 0x2b, 0xa6, 0xc1, 0x45, 0x23, 0x5c, 0x26, 0xce, - 0xf2, 0xbb, 0x02, 0x2c, 0xc6, 0xf3, 0xd6, 0xe7, 0xb0, 0xec, 0xf5, 0xb0, 0x3f, 0xa1, 0x44, 0x1d, - 0xc6, 0x9a, 0xd3, 0x1c, 0xd7, 0xa8, 0x12, 0xe5, 0x10, 0x23, 0x2c, 0x12, 0x7b, 0x41, 0x60, 0xb8, - 0x14, 0xbb, 0xb4, 0x4f, 0x5b, 0x72, 0xa0, 0xcc, 0xa4, 0x8f, 0x9c, 0xe6, 0xd0, 0x83, 0x08, 0x90, - 0xa4, 0xfb, 0x62, 0xec, 0x5c, 0x83, 0xfc, 0xf7, 0x11, 0xe9, 0x62, 0x8b, 0xdb, 0x74, 0xc1, 0x90, - 0x2b, 0xf5, 0x00, 0xf2, 0x94, 0x21, 0xd6, 0x17, 0x33, 0xf9, 0x7c, 0x63, 0x6b, 0xc6, 0x3d, 0x37, - 0x3c, 0xd7, 0x3a, 0xe6, 0x82, 0x86, 0x04, 0x50, 0xf7, 0x20, 0xcf, 0xbc, 0x33, 0xec, 0x4a, 0xa3, - 0x5e, 0x29, 0xe5, 0x0f, 0x5c, 0x66, 0x48, 0x69, 0x95, 0x41, 0x5c, 0xa7, 0x5b, 0xb4, 0x83, 0x7c, - 0x4c, 0xc5, 0x0c, 0xdd, 0x38, 0xb8, 0x72, 0x5e, 0xde, 0x49, 0x37, 0x0f, 0x81, 0xa7, 0x1b, 0xe5, - 0x88, 0x74, 0xcc, 0x29, 0xe9, 0x89, 0xba, 0xf0, 0x72, 0x13, 0xf5, 0x1e, 0x2c, 0xf7, 0xdd, 0xb6, - 0xe7, 0x5a, 0xc4, 0xb5, 0x5b, 0x1d, 0x4c, 0xec, 0x0e, 0xab, 0x2c, 0x6c, 0x28, 0x9b, 0xd9, 0xa4, - 0xdb, 0xd2, 0x1c, 0xba, 0x51, 0x8e, 0x48, 0xfb, 0x9c, 0xa2, 0x5a, 0x50, 0x8a, 0xb9, 0x78, 0xee, - 0x2e, 0xbe, 0x30, 0x77, 0xbf, 0x2c, 0x73, 0xf7, 0x76, 0x5a, 0x4b, 0x9c, 0xbe, 0x4b, 0x11, 0x31, - 0x10, 0x53, 0x0f, 0x2e, 0xdd, 0x38, 0x81, 0x6b, 0x78, 0x6f, 0x86, 0xba, 0x33, 0xfb, 0x65, 0xb3, - 0xf8, 0x5a, 0x2e, 0x9b, 0xdb, 0xb7, 0x7e, 0xf2, 0x48, 0x9b, 0x8b, 0x52, 0xf8, 0xa7, 0x19, 0xc8, - 0x37, 0x4f, 0xee, 0x23, 0xe2, 0xbf, 0xad, 0x33, 0x46, 0xa2, 0x9e, 0xed, 0x41, 0x41, 0xd8, 0x82, - 0xaa, 0x1f, 0xc3, 0x7c, 0x2f, 0xf8, 0x51, 0x51, 0x78, 0xd3, 0xd7, 0xa6, 0x07, 0x39, 0x17, 0x08, - 0xaf, 0xa3, 0x5c, 0x46, 0xff, 0x65, 0x16, 0xa0, 0x79, 0x72, 0xf2, 0xc0, 0x27, 0xbd, 0x2e, 0x66, - 0x37, 0xd3, 0xf8, 0x9b, 0x33, 0x8d, 0x27, 0x9c, 0xfd, 0x00, 0x8a, 0xb1, 0x8f, 0xa8, 0xba, 0x0b, - 0x0b, 0x4c, 0xfe, 0x96, 0x3e, 0x7f, 0xef, 0x39, 0x3e, 0x0f, 0xe5, 0xa4, 0xdf, 0x23, 0x51, 0xfd, - 0x4f, 0x19, 0x80, 0x17, 0xbd, 0xec, 0xbc, 0x05, 0x73, 0xfb, 0x1e, 0xe4, 0x65, 0x57, 0xca, 0x5e, - 0x6b, 0xb4, 0x95, 0xd2, 0x09, 0x77, 0xfd, 0x23, 0x03, 0xab, 0x9f, 0x85, 0x15, 0xf9, 0xc6, 0xc2, - 0xea, 0xa7, 0x50, 0xc0, 0x2e, 0xf3, 0x09, 0x37, 0x71, 0x10, 0xae, 0x5b, 0x53, 0xc3, 0x75, 0x82, - 0xd9, 0x76, 0x5d, 0xe6, 0x5f, 0xc8, 0xe0, 0x0d, 0x71, 0x12, 0xc6, 0xfe, 0x79, 0x16, 0x2a, 0xd3, - 0xa4, 0xd4, 0x1d, 0x28, 0x9b, 0x3e, 0xe6, 0x84, 0xb0, 0x6d, 0x2b, 0xbc, 0x6d, 0xaf, 0x27, 0x5e, - 0x9b, 0x2e, 0x33, 0xe8, 0x46, 0x29, 0xa4, 0xc8, 0xa6, 0x6d, 0xf3, 0xc7, 0xad, 0x20, 0x67, 0x02, - 0xae, 0x19, 0x27, 0x6e, 0x5d, 0x76, 0xed, 0xf8, 0x49, 0x2b, 0x09, 0x20, 0xda, 0x76, 0x29, 0xa6, - 0xf2, 0xbe, 0xfd, 0x03, 0x28, 0x13, 0x97, 0x30, 0x82, 0xba, 0xad, 0x36, 0xea, 0x22, 0xd7, 0xbc, - 0xce, 0x05, 0x46, 0x34, 0x5a, 0xa9, 0x36, 0x05, 0xa7, 0x1b, 0x25, 0x49, 0x69, 0x08, 0x82, 0xba, - 0x0f, 0x85, 0x50, 0x55, 0xee, 0x5a, 0x53, 0x5e, 0x28, 0x9e, 0xf0, 0xc8, 0xcf, 0xb2, 0xb0, 0x12, - 0x3d, 0xf0, 0xdc, 0xb8, 0x62, 0x56, 0x57, 0x1c, 0x01, 0x88, 0x4a, 0x12, 0xf4, 0x92, 0x6b, 0x78, - 0x23, 0xa8, 0x45, 0x8b, 0x02, 0xa1, 0x49, 0x59, 0xc2, 0x1f, 0xff, 0xcc, 0xc2, 0xad, 0xa4, 0x3f, - 0x6e, 0x9a, 0xfc, 0x1b, 0xf4, 0xe4, 0xf6, 0xcd, 0xb8, 0x36, 0xe6, 0x78, 0x6d, 0xfc, 0xea, 0xd4, - 0xda, 0x38, 0x96, 0x53, 0xd3, 0x8b, 0xe2, 0xbf, 0x33, 0x90, 0xbf, 0x8f, 0x7c, 0xe4, 0x50, 0xd5, - 0x1c, 0xbb, 0x72, 0x88, 0x87, 0x88, 0xbb, 0x63, 0x19, 0xd3, 0x94, 0x7f, 0x2f, 0x7b, 0xc1, 0x8d, - 0xe3, 0xe1, 0x84, 0x1b, 0xc7, 0x27, 0x50, 0x72, 0xd0, 0xa0, 0x15, 0x1d, 0x50, 0x78, 0x73, 0xa9, - 0x71, 0x37, 0x46, 0xb9, 0xfc, 0x5d, 0x3c, 0xa5, 0x44, 0x17, 0x72, 0xaa, 0x7e, 0x03, 0x8a, 0x01, - 0x47, 0xdc, 0x27, 0x02, 0xf1, 0xb5, 0xf8, 0xc9, 0x22, 0xf1, 0x51, 0x37, 0xc0, 0x41, 0x83, 0x5d, - 0xb1, 0x50, 0x0f, 0x41, 0xed, 0x44, 0x4f, 0x68, 0xad, 0xd8, 0x96, 0x81, 0xfc, 0xbb, 0xa3, 0xa1, - 0x76, 0x57, 0xc8, 0x8f, 0xf3, 0xe8, 0xc6, 0x4a, 0x4c, 0x0c, 0xd1, 0xbe, 0x0e, 0x10, 0x9c, 0xab, - 0x65, 0x61, 0xd7, 0x73, 0xe4, 0xc5, 0xf7, 0xf6, 0x68, 0xa8, 0xad, 0x08, 0x94, 0xf8, 0x9b, 0x6e, - 0x2c, 0x06, 0x8b, 0x66, 0xf0, 0x3b, 0x36, 0x7c, 0x63, 0xef, 0xf1, 0xd3, 0xaa, 0xf2, 0xe4, 0x69, - 0x55, 0xf9, 0xdb, 0xd3, 0xaa, 0xf2, 0xc5, 0xb3, 0xea, 0xdc, 0x93, 0x67, 0xd5, 0xb9, 0x3f, 0x3f, - 0xab, 0xce, 0x7d, 0xfb, 0x6b, 0xcf, 0x0d, 0x96, 0xd4, 0xdf, 0x5b, 0xdb, 0x79, 0xee, 0x95, 0x8f, - 0xfe, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x62, 0xe9, 0xa4, 0xfa, 0x89, 0x1d, 0x00, 0x00, + 0x35, 0xe9, 0x58, 0xee, 0x4e, 0x12, 0x06, 0x85, 0xe0, 0xdb, 0xce, 0xfd, 0xfd, 0xa1, 0xa6, 0xe8, + 0xbf, 0xcb, 0xc2, 0xf2, 0x11, 0xb5, 0x77, 0x2d, 0xc2, 0x5e, 0x55, 0xdc, 0xf5, 0x26, 0x59, 0x2b, + 0xc3, 0xad, 0xb5, 0x33, 0x1a, 0x6a, 0x25, 0x61, 0xad, 0xff, 0xa5, 0x8d, 0x1c, 0x28, 0xc7, 0x71, + 0xda, 0xf2, 0x11, 0xc3, 0x32, 0x2a, 0x9b, 0x33, 0x46, 0x64, 0x13, 0x9b, 0xa3, 0xa1, 0xb6, 0x26, + 0x76, 0x96, 0x82, 0xd2, 0x8d, 0x92, 0x79, 0x29, 0x37, 0xd4, 0xc1, 0xe4, 0x44, 0xc8, 0x71, 0x95, + 0xfb, 0xaf, 0x30, 0x09, 0xa4, 0x0f, 0x7f, 0x9b, 0x81, 0xe2, 0x11, 0xb5, 0x25, 0x1d, 0x4f, 0x4e, + 0x0d, 0xe5, 0xff, 0x98, 0x1a, 0x99, 0xd7, 0x93, 0x1a, 0x5b, 0x90, 0x47, 0x8e, 0xd7, 0x77, 0x19, + 0xf7, 0xf6, 0x73, 0x73, 0x40, 0x32, 0x4a, 0x03, 0xfe, 0x39, 0xcb, 0xcb, 0x6f, 0x03, 0xdb, 0xc4, + 0x35, 0xb0, 0xf5, 0x26, 0xd8, 0xf1, 0xa7, 0x0a, 0xdc, 0x8e, 0xad, 0x44, 0x7d, 0x33, 0x65, 0xcc, + 0x4f, 0x47, 0x43, 0xed, 0x2b, 0x69, 0x63, 0x26, 0xd8, 0xae, 0x61, 0xd0, 0xd5, 0x08, 0xe8, 0xd8, + 0x37, 0x27, 0xef, 0xc3, 0xa2, 0x2c, 0xda, 0x47, 0x76, 0xfa, 0x3e, 0x12, 0x6c, 0x2f, 0xb5, 0x8f, + 0x26, 0x65, 0xe3, 0xbe, 0xcd, 0x5d, 0xcd, 0xb7, 0x8f, 0x32, 0xb0, 0x74, 0x44, 0xed, 0xcf, 0x5c, + 0xeb, 0x26, 0x3d, 0xae, 0x99, 0x1e, 0xbf, 0x52, 0xa0, 0xb4, 0x4f, 0x28, 0xf3, 0x7c, 0x62, 0xa2, + 0xee, 0x81, 0x7b, 0xea, 0xa9, 0x1f, 0x43, 0xbe, 0x83, 0x91, 0x85, 0x7d, 0xd9, 0x1c, 0xde, 0xad, + 0xc5, 0x83, 0x53, 0x2d, 0x18, 0x9c, 0x6a, 0x62, 0x43, 0xfb, 0x9c, 0x29, 0x44, 0x15, 0x22, 0xea, + 0x27, 0x90, 0x3f, 0x47, 0x5d, 0x8a, 0x59, 0x25, 0xb3, 0x91, 0xdd, 0x2c, 0x7e, 0xa8, 0x4f, 0xed, + 0x2c, 0x51, 0x4b, 0x0a, 0x11, 0x84, 0x9c, 0xdc, 0xd7, 0x6f, 0x32, 0x50, 0x4e, 0x8d, 0x29, 0x6a, + 0x03, 0x72, 0xbc, 0xde, 0x2b, 0xbc, 0xf8, 0xd6, 0xae, 0x30, 0x85, 0x34, 0xb1, 0x69, 0x70, 0x59, + 0xf5, 0xfb, 0xb0, 0xe0, 0xa0, 0x81, 0xe8, 0x1b, 0x19, 0x8e, 0x73, 0xef, 0x6a, 0x38, 0xa3, 0xa1, + 0x56, 0x96, 0x85, 0x5c, 0xe2, 0xe8, 0x46, 0xc1, 0x41, 0x03, 0xde, 0x2d, 0x7a, 0x50, 0x0e, 0xa8, + 0x66, 0x07, 0xb9, 0x36, 0x4e, 0x36, 0xa7, 0xfd, 0x2b, 0x2b, 0x59, 0x8b, 0x95, 0x24, 0xe0, 0x74, + 0x63, 0xc9, 0x41, 0x83, 0x1d, 0x4e, 0x08, 0x34, 0x6e, 0x2f, 0x7c, 0xf9, 0x50, 0x9b, 0xe3, 0x16, + 0xfb, 0x83, 0x02, 0x10, 0x5b, 0x4c, 0xfd, 0x01, 0x2c, 0xa7, 0x9a, 0x1b, 0x95, 0xfe, 0x9c, 0x7d, + 0x2e, 0x5c, 0x08, 0x76, 0xfd, 0x64, 0xa8, 0x29, 0x46, 0xd9, 0x4c, 0xf9, 0xe2, 0x7b, 0x50, 0xec, + 0xf7, 0x2c, 0xc4, 0x70, 0x2b, 0x18, 0x91, 0xe5, 0xc4, 0xb9, 0x5e, 0x13, 0xe3, 0x71, 0x2d, 0x1c, + 0x8f, 0x6b, 0x0f, 0xc2, 0xf9, 0xb9, 0x51, 0x0d, 0xb0, 0x46, 0x43, 0x4d, 0x15, 0xe7, 0x4a, 0x08, + 0xeb, 0x5f, 0xfc, 0x55, 0x53, 0x0c, 0x10, 0x94, 0x40, 0x20, 0x71, 0xa8, 0xdf, 0x2b, 0x50, 0x4c, + 0x8c, 0x20, 0x6a, 0x05, 0x0a, 0x8e, 0xe7, 0x92, 0x33, 0x19, 0x9c, 0x8b, 0x46, 0xb8, 0x54, 0xd7, + 0x61, 0x81, 0x58, 0xd8, 0x65, 0x84, 0x5d, 0x08, 0xc7, 0x1a, 0xd1, 0x3a, 0x90, 0xfa, 0x1c, 0xb7, + 0x29, 0x09, 0xdd, 0x61, 0x84, 0x4b, 0x75, 0x0f, 0x96, 0x29, 0x36, 0xfb, 0x3e, 0x61, 0x17, 0x2d, + 0xd3, 0x73, 0x19, 0x32, 0x99, 0xec, 0xed, 0xef, 0x8c, 0x86, 0xda, 0x1d, 0xb1, 0xd7, 0x34, 0x87, + 0x6e, 0x94, 0x43, 0xd2, 0x8e, 0xa0, 0x04, 0x1a, 0x2c, 0xcc, 0x10, 0xe9, 0x8a, 0x59, 0x71, 0xd1, + 0x08, 0x97, 0x89, 0xb3, 0x3c, 0x2a, 0xc0, 0x62, 0x3c, 0x87, 0x7d, 0x0e, 0xcb, 0x5e, 0x0f, 0xfb, + 0x13, 0x0a, 0xd5, 0x61, 0xac, 0x39, 0xcd, 0x71, 0x8d, 0x5a, 0x51, 0x0e, 0x31, 0xc2, 0x52, 0xb1, + 0x17, 0x04, 0x86, 0x4b, 0xb1, 0x4b, 0xfb, 0xb4, 0x25, 0xc7, 0xcd, 0x4c, 0xfa, 0xc8, 0x69, 0x0e, + 0x3d, 0x88, 0x00, 0x49, 0xba, 0x2f, 0x86, 0xd2, 0x35, 0xc8, 0xff, 0x10, 0x91, 0x2e, 0xb6, 0xb8, + 0x4d, 0x17, 0x0c, 0xb9, 0x52, 0x0f, 0x20, 0x4f, 0x19, 0x62, 0x7d, 0x31, 0xb1, 0xcf, 0x37, 0xb6, + 0x66, 0xdc, 0x73, 0xc3, 0x73, 0xad, 0x63, 0x2e, 0x68, 0x48, 0x00, 0x75, 0x0f, 0xf2, 0xcc, 0x3b, + 0xc3, 0xae, 0x34, 0xea, 0x95, 0x52, 0xfe, 0xc0, 0x65, 0x86, 0x94, 0x56, 0x19, 0xc4, 0xd5, 0xba, + 0x45, 0x3b, 0xc8, 0xc7, 0x54, 0x4c, 0xd8, 0x8d, 0x83, 0x2b, 0xe7, 0xe5, 0x9d, 0x74, 0x0b, 0x11, + 0x78, 0xba, 0x51, 0x8e, 0x48, 0xc7, 0x9c, 0x92, 0x9e, 0xb4, 0x0b, 0x2f, 0x37, 0x69, 0xef, 0xc1, + 0x72, 0xdf, 0x6d, 0x7b, 0xae, 0x45, 0x5c, 0xbb, 0xd5, 0xc1, 0xc4, 0xee, 0xb0, 0xca, 0xc2, 0x86, + 0xb2, 0x99, 0x4d, 0xba, 0x2d, 0xcd, 0xa1, 0x1b, 0xe5, 0x88, 0xb4, 0xcf, 0x29, 0xaa, 0x05, 0xa5, + 0x98, 0x8b, 0xe7, 0xee, 0xe2, 0x0b, 0x73, 0xf7, 0xab, 0x32, 0x77, 0x6f, 0xa7, 0xb5, 0xc4, 0xe9, + 0xbb, 0x14, 0x11, 0x03, 0x31, 0xf5, 0xe0, 0xd2, 0x7d, 0x14, 0xb8, 0x86, 0xf7, 0x66, 0xa8, 0x3b, + 0xb3, 0x5f, 0x45, 0x8b, 0xaf, 0xe5, 0x2a, 0xba, 0x7d, 0xeb, 0x67, 0x0f, 0xb5, 0xb9, 0x28, 0x85, + 0x7f, 0x9e, 0x81, 0x7c, 0xf3, 0xe4, 0x3e, 0x22, 0xfe, 0xdb, 0x3a, 0x69, 0x24, 0xea, 0xd9, 0x1e, + 0x14, 0x84, 0x2d, 0xa8, 0xfa, 0x31, 0xcc, 0xf7, 0x82, 0x1f, 0x15, 0x85, 0x37, 0x7d, 0x6d, 0x7a, + 0x90, 0x73, 0x81, 0xf0, 0xb2, 0xca, 0x65, 0xf4, 0x5f, 0x67, 0x01, 0x9a, 0x27, 0x27, 0x0f, 0x7c, + 0xd2, 0xeb, 0x62, 0x76, 0x33, 0x99, 0xbf, 0x39, 0x93, 0x79, 0xc2, 0xd9, 0x0f, 0xa0, 0x18, 0xfb, + 0x88, 0xaa, 0xbb, 0xb0, 0xc0, 0xe4, 0x6f, 0xe9, 0xf3, 0xf7, 0x9e, 0xe3, 0xf3, 0x50, 0x4e, 0xfa, + 0x3d, 0x12, 0xd5, 0xff, 0x98, 0x01, 0x78, 0xd1, 0xbb, 0xcf, 0x5b, 0x30, 0xbd, 0xef, 0x41, 0x5e, + 0x76, 0xa5, 0xec, 0xb5, 0x46, 0x5b, 0x29, 0x9d, 0x70, 0xd7, 0x3f, 0x32, 0xb0, 0xfa, 0x59, 0x58, + 0x91, 0x6f, 0x2c, 0xac, 0x7e, 0x0a, 0x05, 0xec, 0x32, 0x9f, 0x70, 0x13, 0x07, 0xe1, 0xba, 0x35, + 0x35, 0x5c, 0x27, 0x98, 0x6d, 0xd7, 0x65, 0xfe, 0x85, 0x0c, 0xde, 0x10, 0x27, 0x61, 0xec, 0x5f, + 0x66, 0xa1, 0x32, 0x4d, 0x4a, 0xdd, 0x81, 0xb2, 0xe9, 0x63, 0x4e, 0x08, 0xdb, 0xb6, 0xc2, 0xdb, + 0xf6, 0x7a, 0xe2, 0x15, 0xea, 0x32, 0x83, 0x6e, 0x94, 0x42, 0x8a, 0x6c, 0xda, 0x36, 0x7f, 0xf4, + 0x0a, 0x72, 0x26, 0xe0, 0x9a, 0x71, 0xe2, 0xd6, 0x65, 0xd7, 0x8e, 0x9f, 0xba, 0x92, 0x00, 0xa2, + 0x6d, 0x97, 0x62, 0x2a, 0xef, 0xdb, 0x3f, 0x82, 0x32, 0x71, 0x09, 0x23, 0xa8, 0xdb, 0x6a, 0xa3, + 0x2e, 0x72, 0xcd, 0xeb, 0x5c, 0x60, 0x44, 0xa3, 0x95, 0x6a, 0x53, 0x70, 0xba, 0x51, 0x92, 0x94, + 0x86, 0x20, 0xa8, 0xfb, 0x50, 0x08, 0x55, 0xe5, 0xae, 0x35, 0xe5, 0x85, 0xe2, 0x09, 0x8f, 0xfc, + 0x22, 0x0b, 0x2b, 0xd1, 0x63, 0xcf, 0x8d, 0x2b, 0x66, 0x75, 0xc5, 0x11, 0x80, 0xa8, 0x24, 0x41, + 0x2f, 0xb9, 0x86, 0x37, 0x82, 0x5a, 0xb4, 0x28, 0x10, 0x9a, 0x94, 0x25, 0xfc, 0xf1, 0xcf, 0x2c, + 0xdc, 0x4a, 0xfa, 0xe3, 0xa6, 0xc9, 0xbf, 0x41, 0xcf, 0x6f, 0xdf, 0x8e, 0x6b, 0x63, 0x8e, 0xd7, + 0xc6, 0xaf, 0x4f, 0xad, 0x8d, 0x63, 0x39, 0x35, 0xbd, 0x28, 0xfe, 0x2b, 0x03, 0xf9, 0xfb, 0xc8, + 0x47, 0x0e, 0x55, 0xcd, 0xb1, 0x2b, 0x87, 0x78, 0x88, 0xb8, 0x3b, 0x96, 0x31, 0x4d, 0xf9, 0xd7, + 0xb4, 0x17, 0xdc, 0x38, 0xbe, 0x9c, 0x70, 0xe3, 0xf8, 0x04, 0x4a, 0x0e, 0x1a, 0xb4, 0xa2, 0x03, + 0x0a, 0x6f, 0x2e, 0x35, 0xee, 0xc6, 0x28, 0x97, 0xbf, 0x8b, 0xa7, 0x94, 0xe8, 0x42, 0x4e, 0xd5, + 0x6f, 0x41, 0x31, 0xe0, 0x88, 0xfb, 0x44, 0x20, 0xbe, 0x16, 0x3f, 0x59, 0x24, 0x3e, 0xea, 0x06, + 0x38, 0x68, 0xb0, 0x2b, 0x16, 0xea, 0x21, 0xa8, 0x9d, 0xe8, 0x09, 0xad, 0x15, 0xdb, 0x32, 0x90, + 0x7f, 0x77, 0x34, 0xd4, 0xee, 0x0a, 0xf9, 0x71, 0x1e, 0xdd, 0x58, 0x89, 0x89, 0x21, 0xda, 0x37, + 0x01, 0x82, 0x73, 0xb5, 0x2c, 0xec, 0x7a, 0x8e, 0xbc, 0xf8, 0xde, 0x1e, 0x0d, 0xb5, 0x15, 0x81, + 0x12, 0x7f, 0xd3, 0x8d, 0xc5, 0x60, 0xd1, 0x0c, 0x7e, 0xc7, 0x86, 0x6f, 0xec, 0x3d, 0x7e, 0x5a, + 0x55, 0x9e, 0x3c, 0xad, 0x2a, 0x7f, 0x7b, 0x5a, 0x55, 0xbe, 0x78, 0x56, 0x9d, 0x7b, 0xf2, 0xac, + 0x3a, 0xf7, 0xa7, 0x67, 0xd5, 0xb9, 0xef, 0x7e, 0xe3, 0xb9, 0xc1, 0x92, 0xfa, 0x6b, 0x6c, 0x3b, + 0xcf, 0xbd, 0xf2, 0xd1, 0x7f, 0x03, 0x00, 0x00, 0xff, 0xff, 0xa9, 0x93, 0x44, 0xcc, 0xa7, 0x1d, + 0x00, 0x00, +} + +func (this *MsgCreateValidator) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*MsgCreateValidator) + if !ok { + that2, ok := that.(MsgCreateValidator) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !this.Description.Equal(&that1.Description) { + return false + } + if !this.Commission.Equal(&that1.Commission) { + return false + } + if !this.MinSelfDelegation.Equal(that1.MinSelfDelegation) { + return false + } + if !bytes.Equal(this.DelegatorAddress, that1.DelegatorAddress) { + return false + } + if !bytes.Equal(this.ValidatorAddress, that1.ValidatorAddress) { + return false + } + if this.Pubkey != that1.Pubkey { + return false + } + if !this.Value.Equal(&that1.Value) { + return false + } + return true +} +func (this *MsgEditValidator) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*MsgEditValidator) + if !ok { + that2, ok := that.(MsgEditValidator) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !this.Description.Equal(&that1.Description) { + return false + } + if !bytes.Equal(this.ValidatorAddress, that1.ValidatorAddress) { + return false + } + if that1.CommissionRate == nil { + if this.CommissionRate != nil { + return false + } + } else if !this.CommissionRate.Equal(*that1.CommissionRate) { + return false + } + if that1.MinSelfDelegation == nil { + if this.MinSelfDelegation != nil { + return false + } + } else if !this.MinSelfDelegation.Equal(*that1.MinSelfDelegation) { + return false + } + return true +} +func (this *MsgDelegate) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*MsgDelegate) + if !ok { + that2, ok := that.(MsgDelegate) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !bytes.Equal(this.DelegatorAddress, that1.DelegatorAddress) { + return false + } + if !bytes.Equal(this.ValidatorAddress, that1.ValidatorAddress) { + return false + } + if !this.Amount.Equal(&that1.Amount) { + return false + } + return true +} +func (this *MsgBeginRedelegate) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*MsgBeginRedelegate) + if !ok { + that2, ok := that.(MsgBeginRedelegate) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !bytes.Equal(this.DelegatorAddress, that1.DelegatorAddress) { + return false + } + if !bytes.Equal(this.ValidatorSrcAddress, that1.ValidatorSrcAddress) { + return false + } + if !bytes.Equal(this.ValidatorDstAddress, that1.ValidatorDstAddress) { + return false + } + if !this.Amount.Equal(&that1.Amount) { + return false + } + return true } +func (this *MsgUndelegate) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + that1, ok := that.(*MsgUndelegate) + if !ok { + that2, ok := that.(MsgUndelegate) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !bytes.Equal(this.DelegatorAddress, that1.DelegatorAddress) { + return false + } + if !bytes.Equal(this.ValidatorAddress, that1.ValidatorAddress) { + return false + } + if !this.Amount.Equal(&that1.Amount) { + return false + } + return true +} func (this *HistoricalInfo) Equal(that interface{}) bool { if that == nil { return this == nil diff --git a/x/staking/types/types.proto b/x/staking/types/types.proto index 281d1db89207..15e8733c981d 100644 --- a/x/staking/types/types.proto +++ b/x/staking/types/types.proto @@ -11,6 +11,8 @@ option go_package = "github.com/cosmos/cosmos-sdk/x/staking/types"; // MsgCreateValidator defines an SDK message for creating a new validator. message MsgCreateValidator { + option (gogoproto.equal) = true; + Description description = 1 [(gogoproto.nullable) = false]; CommissionRates commission = 2 [(gogoproto.nullable) = false]; string min_self_delegation = 3 [ @@ -32,6 +34,8 @@ message MsgCreateValidator { // MsgEditValidator defines an SDK message for editing an existing validator. message MsgEditValidator { + option (gogoproto.equal) = true; + Description description = 1 [(gogoproto.nullable) = false]; bytes validator_address = 2 [ (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.ValAddress", @@ -56,6 +60,8 @@ message MsgEditValidator { // MsgDelegate defines an SDK message for performing a delegation from a // delegate to a validator. message MsgDelegate { + option (gogoproto.equal) = true; + bytes delegator_address = 1 [ (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress", (gogoproto.moretags) = "yaml:\"delegator_address\"" @@ -70,6 +76,8 @@ message MsgDelegate { // MsgBeginRedelegate defines an SDK message for performing a redelegation from // a delegate and source validator to a destination validator. message MsgBeginRedelegate { + option (gogoproto.equal) = true; + bytes delegator_address = 1 [ (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress", (gogoproto.moretags) = "yaml:\"delegator_address\"" @@ -88,6 +96,8 @@ message MsgBeginRedelegate { // MsgUndelegate defines an SDK message for performing an undelegation from a // delegate and a validator. message MsgUndelegate { + option (gogoproto.equal) = true; + bytes delegator_address = 1 [ (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress", (gogoproto.moretags) = "yaml:\"delegator_address\"" diff --git a/x/supply/types/types.pb.go b/x/supply/types/types.pb.go index 399056115635..d94ee7669f91 100644 --- a/x/supply/types/types.pb.go +++ b/x/supply/types/types.pb.go @@ -111,7 +111,7 @@ func init() { func init() { proto.RegisterFile("x/supply/types/types.proto", fileDescriptor_e14b855c341cf347) } var fileDescriptor_e14b855c341cf347 = []byte{ - // 348 bytes of a gzipped FileDescriptorProto + // 355 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xaa, 0xd0, 0x2f, 0x2e, 0x2d, 0x28, 0xc8, 0xa9, 0xd4, 0x2f, 0xa9, 0x2c, 0x48, 0x2d, 0x86, 0x90, 0x7a, 0x05, 0x45, 0xf9, 0x25, 0xf9, 0x42, 0x62, 0xc9, 0xf9, 0xc5, 0xb9, 0xf9, 0xc5, 0xf1, 0xc5, 0x29, 0xd9, 0x7a, 0x15, @@ -125,17 +125,47 @@ var fileDescriptor_e14b855c341cf347 = []byte{ 0xac, 0x94, 0x90, 0x0d, 0x51, 0x0a, 0xe2, 0x4e, 0x42, 0xa8, 0x14, 0x12, 0xe2, 0x62, 0xc9, 0x4b, 0xcc, 0x4d, 0x95, 0x60, 0x52, 0x60, 0xd4, 0xe0, 0x0c, 0x02, 0xb3, 0x85, 0x14, 0xb8, 0xb8, 0x0b, 0x52, 0x8b, 0x72, 0x33, 0x8b, 0x8b, 0x33, 0xf3, 0xf3, 0x8a, 0x25, 0x98, 0x15, 0x98, 0x35, 0x38, - 0x83, 0x90, 0x85, 0xac, 0x38, 0x3a, 0x16, 0xc8, 0x33, 0xcc, 0x58, 0x20, 0xcf, 0xa0, 0x94, 0xcf, + 0x83, 0x90, 0x85, 0xac, 0x38, 0x3a, 0x16, 0xc8, 0x33, 0xcc, 0x58, 0x20, 0xcf, 0xa0, 0x54, 0xcc, 0xc5, 0x16, 0x0c, 0x0e, 0x16, 0xa1, 0x68, 0x2e, 0xd6, 0x92, 0xfc, 0x92, 0xc4, 0x1c, 0x09, 0x46, 0x05, 0x66, 0x0d, 0x6e, 0x23, 0x61, 0x64, 0x57, 0x96, 0x19, 0xea, 0x39, 0xe7, 0x67, 0xe6, 0x39, 0x19, 0x9c, 0xb8, 0x27, 0xcf, 0xb0, 0xea, 0xbe, 0xbc, 0x46, 0x7a, 0x66, 0x49, 0x46, 0x69, 0x92, 0x5e, 0x72, 0x7e, 0xae, 0x3e, 0x44, 0x19, 0x94, 0xd2, 0x2d, 0x4e, 0xc9, 0x86, 0x06, 0x0a, 0x48, - 0x43, 0x71, 0x10, 0xc4, 0x4c, 0x84, 0x85, 0x4e, 0xae, 0x27, 0x1e, 0xc9, 0x31, 0x5e, 0x78, 0x24, - 0xc7, 0xf8, 0xe0, 0x91, 0x1c, 0xe3, 0x84, 0xc7, 0x72, 0x0c, 0x17, 0x1e, 0xcb, 0x31, 0xdc, 0x78, - 0x2c, 0xc7, 0x10, 0xa5, 0x8d, 0xd7, 0x50, 0xd4, 0x58, 0x4e, 0x62, 0x03, 0x87, 0xb9, 0x31, 0x20, - 0x00, 0x00, 0xff, 0xff, 0x95, 0xfd, 0xe3, 0x40, 0xfe, 0x01, 0x00, 0x00, + 0x43, 0x71, 0x10, 0xc4, 0x4c, 0x2b, 0x1e, 0x98, 0x85, 0x2f, 0x16, 0xc8, 0x33, 0x3a, 0xb9, 0x9e, + 0x78, 0x24, 0xc7, 0x78, 0xe1, 0x91, 0x1c, 0xe3, 0x83, 0x47, 0x72, 0x8c, 0x13, 0x1e, 0xcb, 0x31, + 0x5c, 0x78, 0x2c, 0xc7, 0x70, 0xe3, 0xb1, 0x1c, 0x43, 0x94, 0x36, 0x5e, 0x83, 0x51, 0x63, 0x3a, + 0x89, 0x0d, 0x1c, 0xee, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x83, 0x25, 0xe2, 0x0f, 0x02, + 0x02, 0x00, 0x00, } +func (this *Supply) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*Supply) + if !ok { + that2, ok := that.(Supply) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if len(this.Total) != len(that1.Total) { + return false + } + for i := range this.Total { + if !this.Total[i].Equal(&that1.Total[i]) { + return false + } + } + return true +} func (m *ModuleAccount) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) diff --git a/x/supply/types/types.proto b/x/supply/types/types.proto index 0c14740ea29d..979e1459df05 100644 --- a/x/supply/types/types.proto +++ b/x/supply/types/types.proto @@ -21,6 +21,7 @@ message ModuleAccount { // Supply represents a struct that passively keeps track of the total supply // amounts in the network. message Supply { + option (gogoproto.equal) = true; option (gogoproto.goproto_getters) = false; option (gogoproto.goproto_stringer) = false; From e3dc0fd4a61f7771198477ef9ea247deb37ef4c2 Mon Sep 17 00:00:00 2001 From: Marko Date: Fri, 21 Feb 2020 12:17:27 +0100 Subject: [PATCH 169/529] Merge PR #5671: CORS - Add a Flag for CORS --- client/flags/flags.go | 2 ++ client/lcd/root.go | 9 ++++++++- docs/interfaces/rest.md | 33 ++++++++++++++++++++++----------- go.mod | 1 + go.sum | 2 ++ 5 files changed, 35 insertions(+), 12 deletions(-) diff --git a/client/flags/flags.go b/client/flags/flags.go index 64dc2f25a34f..746b512b0697 100644 --- a/client/flags/flags.go +++ b/client/flags/flags.go @@ -68,6 +68,7 @@ const ( FlagKeyringBackend = "keyring-backend" FlagPage = "page" FlagLimit = "limit" + FlagUnsafeCORS = "unsafe-cors" ) // LineBreak can be included in a command list to provide a blank line @@ -141,6 +142,7 @@ func RegisterRestServerFlags(cmd *cobra.Command) *cobra.Command { cmd.Flags().Uint(FlagMaxOpenConnections, 1000, "The number of maximum open connections") cmd.Flags().Uint(FlagRPCReadTimeout, 10, "The RPC read timeout (in seconds)") cmd.Flags().Uint(FlagRPCWriteTimeout, 10, "The RPC write timeout (in seconds)") + cmd.Flags().Bool(FlagUnsafeCORS, false, "Allows CORS requests from all domains. For development purposes only, use it at your own risk.") return cmd } diff --git a/client/lcd/root.go b/client/lcd/root.go index 12697944c006..29bae3ba3c05 100644 --- a/client/lcd/root.go +++ b/client/lcd/root.go @@ -7,6 +7,7 @@ import ( "os" "time" + "github.com/gorilla/handlers" "github.com/gorilla/mux" "github.com/rakyll/statik/fs" "github.com/spf13/cobra" @@ -46,7 +47,7 @@ func NewRestServer(cdc *codec.Codec) *RestServer { } // Start starts the rest server -func (rs *RestServer) Start(listenAddr string, maxOpen int, readTimeout, writeTimeout uint) (err error) { +func (rs *RestServer) Start(listenAddr string, maxOpen int, readTimeout, writeTimeout uint, cors bool) (err error) { server.TrapSignal(func() { err := rs.listener.Close() rs.log.Error("error closing listener", "err", err) @@ -68,6 +69,11 @@ func (rs *RestServer) Start(listenAddr string, maxOpen int, readTimeout, writeTi ), ) + var h http.Handler = rs.Mux + if cors { + return rpcserver.StartHTTPServer(rs.listener, handlers.CORS()(h), rs.log, cfg) + } + return rpcserver.StartHTTPServer(rs.listener, rs.Mux, rs.log, cfg) } @@ -90,6 +96,7 @@ func ServeCommand(cdc *codec.Codec, registerRoutesFn func(*RestServer)) *cobra.C viper.GetInt(flags.FlagMaxOpenConnections), uint(viper.GetInt(flags.FlagRPCReadTimeout)), uint(viper.GetInt(flags.FlagRPCWriteTimeout)), + viper.GetBool(flags.FlagUnsafeCORS), ) return err diff --git a/docs/interfaces/rest.md b/docs/interfaces/rest.md index 75e5a78dc3d8..9ba57ffb2af9 100644 --- a/docs/interfaces/rest.md +++ b/docs/interfaces/rest.md @@ -7,10 +7,10 @@ synopsis: "This document describes how to create a REST interface for an SDK **a ## Prerequisites {hide} -* [Query Lifecycle](./query-lifecycle.md) {prereq} -* [Application CLI](./cli.md) {prereq} +- [Query Lifecycle](./query-lifecycle.md) {prereq} +- [Application CLI](./cli.md) {prereq} -## Application REST Interface +## Application REST Interface Building the REST Interface for an application is done by [aggregating REST Routes](#registering-routes) defined in the application's modules. This interface is served by a REST Server [REST server](#rest-server), which route requests and output responses in the application itself. The SDK comes with its own REST Server by default. To enable it, the `rest.ServeCommand` command needs to be added as a subcommand of the `rootCmd` in the `main()` function of the [CLI interface](./cli.md): @@ -24,19 +24,19 @@ Users will then be able to use the application CLI to start a new REST server, a appcli rest-server --chain-id --trust-node ``` -Note that if `trust-node` is set to `false`, the REST server will verify the query proof against the merkle root (contained in the block header). +Note that if `trust-node` is set to `false`, the REST server will verify the query proof against the merkle root (contained in the block header). ## REST Server A REST Server is used to receive and route HTTP Requests, obtain the results from the application, and return a response to the user. The REST Server defined by the SDK `rest` package contains the following: -* **Router:** A router for HTTP requests. A new router can be instantiated for an application and used to match routes based on path, request method, headers, etc. The SDK uses the [Gorilla Mux Router](https://github.com/gorilla/mux). -* **CLIContext:** A [`CLIContext`](./query-lifecycle.md#clicontext) created for a user interaction. -* **Keybase:** A [Keybase](../basics/accounts.md#keybase) is a key manager. -* **Logger:** A logger from Tendermint `Log`, a log package structured around key-value pairs that allows logging level to be set differently for different keys. The logger takes `Debug()`, `Info()`, and `Error()`s. -* **Listener:** A [listener](https://golang.org/pkg/net/#Listener) from the net package. +- **Router:** A router for HTTP requests. A new router can be instantiated for an application and used to match routes based on path, request method, headers, etc. The SDK uses the [Gorilla Mux Router](https://github.com/gorilla/mux). +- **CLIContext:** A [`CLIContext`](./query-lifecycle.md#clicontext) created for a user interaction. +- **Keybase:** A [Keybase](../basics/accounts.md#keybase) is a key manager. +- **Logger:** A logger from Tendermint `Log`, a log package structured around key-value pairs that allows logging level to be set differently for different keys. The logger takes `Debug()`, `Info()`, and `Error()`s. +- **Listener:** A [listener](https://golang.org/pkg/net/#Listener) from the net package. -Of the five, the only attribute that application developers need interact with is the `router`: they need to add routes to it so that the REST server can properly handle queries. See the next section for more information on registering routes. +Of the five, the only attribute that application developers need interact with is the `router`: they need to add routes to it so that the REST server can properly handle queries. See the next section for more information on registering routes. In order to enable the REST Server in an SDK application, the `rest.ServeCommand` needs to be added to the application's command-line interface. See the [above section](#application-rest-interface) for more information. @@ -44,7 +44,7 @@ In order to enable the REST Server in an SDK application, the `rest.ServeCommand To include routes for each module in an application, the CLI must have some kind of function to register routes in its REST Server. This function is called `RegisterRoutes()`, and is utilized by the `ServeCommand` and must include routes for each of the application's modules. Since each module used by an SDK application implements a [`RegisterRESTRoutes`](../building-modules/module-interfaces.md#rest) function, application developers simply use the [Module Manager](../building-modules/module-manager.md) to call this function for each module (this is done in the [application's constructor](../basics/app-anatomy.md#constructor-function)). -At the bare minimum, a `RegisterRoutes()` function should use the SDK client package `RegisterRoutes()` function to be able to route RPC calls, and instruct the application Module Manager to call `RegisterRESTRoutes()` for all of its modules. This is done in the `main.go` file of the CLI (typically located in `./cmd/appcli/main.go`). +At the bare minimum, a `RegisterRoutes()` function should use the SDK client package `RegisterRoutes()` function to be able to route RPC calls, and instruct the application Module Manager to call `RegisterRESTRoutes()` for all of its modules. This is done in the `main.go` file of the CLI (typically located in `./cmd/appcli/main.go`). ```go func registerRoutes(rs *rest.RestServer) { @@ -58,3 +58,14 @@ This function is specific to the application and passed in to the `ServeCommand` ```go rootCmd.AddCommand(rest.ServeCommand(cdc, registerRoutes)) ``` + +## Cross-Origin Resource Sharing (CORS) + +[CORS policies](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) are not enabled by default to help with security. If you would like to use the rest-server in a public environment we recommend you provide a reverse proxy, this can be done with [nginx](https://www.nginx.com/). For testing and development purposes there is an `unsafe_cors` flag that can be passed to the cmd to enable accepting cors from everyone. + +```sh +gaiacli rest-server --chain-id=test \ + --laddr=tcp://localhost:1317 \ + --node tcp://localhost:26657 \ + --trust-node=true --unsafe-cors +``` diff --git a/go.mod b/go.mod index 8c99717efd62..ad82af5e20f1 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,7 @@ require ( github.com/gogo/protobuf v1.3.1 github.com/golang/mock v1.3.1-0.20190508161146-9fa652df1129 github.com/golang/protobuf v1.3.3 + github.com/gorilla/handlers v1.4.2 github.com/gorilla/mux v1.7.4 github.com/hashicorp/golang-lru v0.5.4 github.com/mattn/go-isatty v0.0.12 diff --git a/go.sum b/go.sum index a13a77447fa7..55185f3f0801 100644 --- a/go.sum +++ b/go.sum @@ -105,6 +105,8 @@ github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/handlers v1.4.2 h1:0QniY0USkHQ1RGCLfKxeNHK9bkDHGRYGNDFBCS+YARg= +github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc= github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= From 9eaa5b0e1aa128c245cd3c1f2a921e3290e739e9 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Fri, 21 Feb 2020 12:24:41 +0100 Subject: [PATCH 170/529] refactor delegation test TestUnbondDelegation to use simapp --- x/staking/keeper/delegation_test.go | 1648 ++++++++++++----------- x/staking/keeper/old_delegation_test.go | 765 +++++++++++ 2 files changed, 1600 insertions(+), 813 deletions(-) create mode 100644 x/staking/keeper/old_delegation_test.go diff --git a/x/staking/keeper/delegation_test.go b/x/staking/keeper/delegation_test.go index eda1a550cd67..798716b2c2d0 100644 --- a/x/staking/keeper/delegation_test.go +++ b/x/staking/keeper/delegation_test.go @@ -1,19 +1,25 @@ -package keeper +package keeper_test import ( "testing" "time" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/cosmos/cosmos-sdk/x/distribution" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/simapp" + abci "github.com/tendermint/tendermint/abci/types" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/staking/keeper" + "github.com/cosmos/cosmos-sdk/x/staking/types" ) // tests GetDelegation, GetDelegatorDelegations, SetDelegation, RemoveDelegation, GetDelegatorDelegations func TestDelegation(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 10) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) //construct the validators amts := []sdk.Int{sdk.NewInt(9), sdk.NewInt(8), sdk.NewInt(7)} @@ -23,28 +29,28 @@ func TestDelegation(t *testing.T) { validators[i], _ = validators[i].AddTokensFromDel(amt) } - validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], true) - validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], true) - validators[2] = TestingUpdateValidator(keeper, ctx, validators[2], true) + validators[0] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[0], true) + validators[1] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[1], true) + validators[2] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[2], true) // first add a validators[0] to delegate too bond1to1 := types.NewDelegation(addrDels[0], addrVals[0], sdk.NewDec(9)) // check the empty keeper first - _, found := keeper.GetDelegation(ctx, addrDels[0], addrVals[0]) + _, found := app.StakingKeeper.GetDelegation(ctx, addrDels[0], addrVals[0]) require.False(t, found) // set and retrieve a record - keeper.SetDelegation(ctx, bond1to1) - resBond, found := keeper.GetDelegation(ctx, addrDels[0], addrVals[0]) + app.StakingKeeper.SetDelegation(ctx, bond1to1) + resBond, found := app.StakingKeeper.GetDelegation(ctx, addrDels[0], addrVals[0]) require.True(t, found) require.True(t, bond1to1.Equal(resBond)) // modify a records, save, and retrieve bond1to1.Shares = sdk.NewDec(99) - keeper.SetDelegation(ctx, bond1to1) - resBond, found = keeper.GetDelegation(ctx, addrDels[0], addrVals[0]) + app.StakingKeeper.SetDelegation(ctx, bond1to1) + resBond, found = app.StakingKeeper.GetDelegation(ctx, addrDels[0], addrVals[0]) require.True(t, found) require.True(t, bond1to1.Equal(resBond)) @@ -54,28 +60,28 @@ func TestDelegation(t *testing.T) { bond2to1 := types.NewDelegation(addrDels[1], addrVals[0], sdk.NewDec(9)) bond2to2 := types.NewDelegation(addrDels[1], addrVals[1], sdk.NewDec(9)) bond2to3 := types.NewDelegation(addrDels[1], addrVals[2], sdk.NewDec(9)) - keeper.SetDelegation(ctx, bond1to2) - keeper.SetDelegation(ctx, bond1to3) - keeper.SetDelegation(ctx, bond2to1) - keeper.SetDelegation(ctx, bond2to2) - keeper.SetDelegation(ctx, bond2to3) + app.StakingKeeper.SetDelegation(ctx, bond1to2) + app.StakingKeeper.SetDelegation(ctx, bond1to3) + app.StakingKeeper.SetDelegation(ctx, bond2to1) + app.StakingKeeper.SetDelegation(ctx, bond2to2) + app.StakingKeeper.SetDelegation(ctx, bond2to3) // test all bond retrieve capabilities - resBonds := keeper.GetDelegatorDelegations(ctx, addrDels[0], 5) + resBonds := app.StakingKeeper.GetDelegatorDelegations(ctx, addrDels[0], 5) require.Equal(t, 3, len(resBonds)) require.True(t, bond1to1.Equal(resBonds[0])) require.True(t, bond1to2.Equal(resBonds[1])) require.True(t, bond1to3.Equal(resBonds[2])) - resBonds = keeper.GetAllDelegatorDelegations(ctx, addrDels[0]) + resBonds = app.StakingKeeper.GetAllDelegatorDelegations(ctx, addrDels[0]) require.Equal(t, 3, len(resBonds)) - resBonds = keeper.GetDelegatorDelegations(ctx, addrDels[0], 2) + resBonds = app.StakingKeeper.GetDelegatorDelegations(ctx, addrDels[0], 2) require.Equal(t, 2, len(resBonds)) - resBonds = keeper.GetDelegatorDelegations(ctx, addrDels[1], 5) + resBonds = app.StakingKeeper.GetDelegatorDelegations(ctx, addrDels[1], 5) require.Equal(t, 3, len(resBonds)) require.True(t, bond2to1.Equal(resBonds[0])) require.True(t, bond2to2.Equal(resBonds[1])) require.True(t, bond2to3.Equal(resBonds[2])) - allBonds := keeper.GetAllDelegations(ctx) + allBonds := app.StakingKeeper.GetAllDelegations(ctx) require.Equal(t, 6, len(allBonds)) require.True(t, bond1to1.Equal(allBonds[0])) require.True(t, bond1to2.Equal(allBonds[1])) @@ -84,96 +90,108 @@ func TestDelegation(t *testing.T) { require.True(t, bond2to2.Equal(allBonds[4])) require.True(t, bond2to3.Equal(allBonds[5])) - resVals := keeper.GetDelegatorValidators(ctx, addrDels[0], 3) + resVals := app.StakingKeeper.GetDelegatorValidators(ctx, addrDels[0], 3) require.Equal(t, 3, len(resVals)) - resVals = keeper.GetDelegatorValidators(ctx, addrDels[1], 4) + resVals = app.StakingKeeper.GetDelegatorValidators(ctx, addrDels[1], 4) require.Equal(t, 3, len(resVals)) for i := 0; i < 3; i++ { - resVal, err := keeper.GetDelegatorValidator(ctx, addrDels[0], addrVals[i]) + resVal, err := app.StakingKeeper.GetDelegatorValidator(ctx, addrDels[0], addrVals[i]) require.Nil(t, err) require.Equal(t, addrVals[i], resVal.GetOperator()) - resVal, err = keeper.GetDelegatorValidator(ctx, addrDels[1], addrVals[i]) + resVal, err = app.StakingKeeper.GetDelegatorValidator(ctx, addrDels[1], addrVals[i]) require.Nil(t, err) require.Equal(t, addrVals[i], resVal.GetOperator()) - resDels := keeper.GetValidatorDelegations(ctx, addrVals[i]) + resDels := app.StakingKeeper.GetValidatorDelegations(ctx, addrVals[i]) require.Len(t, resDels, 2) } // delete a record - keeper.RemoveDelegation(ctx, bond2to3) - _, found = keeper.GetDelegation(ctx, addrDels[1], addrVals[2]) + app.StakingKeeper.RemoveDelegation(ctx, bond2to3) + _, found = app.StakingKeeper.GetDelegation(ctx, addrDels[1], addrVals[2]) require.False(t, found) - resBonds = keeper.GetDelegatorDelegations(ctx, addrDels[1], 5) + resBonds = app.StakingKeeper.GetDelegatorDelegations(ctx, addrDels[1], 5) require.Equal(t, 2, len(resBonds)) require.True(t, bond2to1.Equal(resBonds[0])) require.True(t, bond2to2.Equal(resBonds[1])) - resBonds = keeper.GetAllDelegatorDelegations(ctx, addrDels[1]) + resBonds = app.StakingKeeper.GetAllDelegatorDelegations(ctx, addrDels[1]) require.Equal(t, 2, len(resBonds)) // delete all the records from delegator 2 - keeper.RemoveDelegation(ctx, bond2to1) - keeper.RemoveDelegation(ctx, bond2to2) - _, found = keeper.GetDelegation(ctx, addrDels[1], addrVals[0]) + app.StakingKeeper.RemoveDelegation(ctx, bond2to1) + app.StakingKeeper.RemoveDelegation(ctx, bond2to2) + _, found = app.StakingKeeper.GetDelegation(ctx, addrDels[1], addrVals[0]) require.False(t, found) - _, found = keeper.GetDelegation(ctx, addrDels[1], addrVals[1]) + _, found = app.StakingKeeper.GetDelegation(ctx, addrDels[1], addrVals[1]) require.False(t, found) - resBonds = keeper.GetDelegatorDelegations(ctx, addrDels[1], 5) + resBonds = app.StakingKeeper.GetDelegatorDelegations(ctx, addrDels[1], 5) require.Equal(t, 0, len(resBonds)) } // tests Get/Set/Remove UnbondingDelegation func TestUnbondingDelegation(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 0) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) - ubd := types.NewUnbondingDelegation(addrDels[0], addrVals[0], 0, - time.Unix(0, 0), sdk.NewInt(5)) + ubd := types.NewUnbondingDelegation( + addrDels[0], + addrVals[0], + 0, + time.Unix(0, 0), + sdk.NewInt(5), + ) // set and retrieve a record - keeper.SetUnbondingDelegation(ctx, ubd) - resUnbond, found := keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) + app.StakingKeeper.SetUnbondingDelegation(ctx, ubd) + resUnbond, found := app.StakingKeeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) require.True(t, found) require.True(t, ubd.Equal(resUnbond)) // modify a records, save, and retrieve ubd.Entries[0].Balance = sdk.NewInt(21) - keeper.SetUnbondingDelegation(ctx, ubd) + app.StakingKeeper.SetUnbondingDelegation(ctx, ubd) - resUnbonds := keeper.GetUnbondingDelegations(ctx, addrDels[0], 5) + resUnbonds := app.StakingKeeper.GetUnbondingDelegations(ctx, addrDels[0], 5) require.Equal(t, 1, len(resUnbonds)) - resUnbonds = keeper.GetAllUnbondingDelegations(ctx, addrDels[0]) + resUnbonds = app.StakingKeeper.GetAllUnbondingDelegations(ctx, addrDels[0]) require.Equal(t, 1, len(resUnbonds)) - resUnbond, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) + resUnbond, found = app.StakingKeeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) require.True(t, found) require.True(t, ubd.Equal(resUnbond)) // delete a record - keeper.RemoveUnbondingDelegation(ctx, ubd) - _, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) + app.StakingKeeper.RemoveUnbondingDelegation(ctx, ubd) + _, found = app.StakingKeeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) require.False(t, found) - resUnbonds = keeper.GetUnbondingDelegations(ctx, addrDels[0], 5) + resUnbonds = app.StakingKeeper.GetUnbondingDelegations(ctx, addrDels[0], 5) require.Equal(t, 0, len(resUnbonds)) - resUnbonds = keeper.GetAllUnbondingDelegations(ctx, addrDels[0]) + resUnbonds = app.StakingKeeper.GetAllUnbondingDelegations(ctx, addrDels[0]) require.Equal(t, 0, len(resUnbonds)) - } func TestUnbondDelegation(t *testing.T) { - ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) startTokens := sdk.TokensFromConsensusPower(10) - notBondedPool := keeper.GetNotBondedPool(ctx) + notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) - require.NoError(t, bk.SetBalances(ctx, notBondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), startTokens)))) - keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) + require.NoError(t, + app.BankKeeper.SetBalances( + ctx, + notBondedPool.GetAddress(), + sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), startTokens)), + ), + ) + app.SupplyKeeper.SetModuleAccount(ctx, notBondedPool) // create a validator and a delegator to that validator // note this validator starts not-bonded @@ -182,19 +200,23 @@ func TestUnbondDelegation(t *testing.T) { validator, issuedShares := validator.AddTokensFromDel(startTokens) require.Equal(t, startTokens, issuedShares.RoundInt()) - validator = TestingUpdateValidator(keeper, ctx, validator, true) + validator = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator, true) delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) - keeper.SetDelegation(ctx, delegation) + app.StakingKeeper.SetDelegation(ctx, delegation) + app.DistrKeeper.SetDelegatorStartingInfo(ctx, addrVals[0], addrDels[0], distribution.DelegatorStartingInfo{}) + app.DistrKeeper.SetValidatorHistoricalRewards(ctx, addrVals[0], 18446744073709551615, distribution.ValidatorHistoricalRewards{ReferenceCount: 1}) bondTokens := sdk.TokensFromConsensusPower(6) - amount, err := keeper.unbond(ctx, addrDels[0], addrVals[0], bondTokens.ToDec()) + _, err := app.StakingKeeper.Undelegate(ctx, addrDels[0], addrVals[0], bondTokens.ToDec()) require.NoError(t, err) - require.Equal(t, bondTokens, amount) // shares to be added to an unbonding delegation - delegation, found := keeper.GetDelegation(ctx, addrDels[0], addrVals[0]) + notBondedPoolBalance := app.BankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), app.StakingKeeper.BondDenom(ctx)) + require.Equal(t, bondTokens, notBondedPoolBalance.Amount) // shares to be added to an unbonding delegation + + delegation, found := app.StakingKeeper.GetDelegation(ctx, addrDels[0], addrVals[0]) require.True(t, found) - validator, found = keeper.GetValidator(ctx, addrVals[0]) + validator, found = app.StakingKeeper.GetValidator(ctx, addrVals[0]) require.True(t, found) remainingTokens := startTokens.Sub(bondTokens) @@ -202,755 +224,755 @@ func TestUnbondDelegation(t *testing.T) { require.Equal(t, remainingTokens, validator.BondedTokens()) } -func TestUnbondingDelegationsMaxEntries(t *testing.T) { - ctx, _, bk, keeper, _ := CreateTestInput(t, false, 1) - startTokens := sdk.TokensFromConsensusPower(10) - - bondDenom := keeper.BondDenom(ctx) - notBondedPool := keeper.GetNotBondedPool(ctx) - - err := bk.SetBalances(ctx, notBondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(bondDenom, startTokens))) - require.NoError(t, err) - keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) - - // create a validator and a delegator to that validator - validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) - - validator, issuedShares := validator.AddTokensFromDel(startTokens) - require.Equal(t, startTokens, issuedShares.RoundInt()) - - validator = TestingUpdateValidator(keeper, ctx, validator, true) - require.True(sdk.IntEq(t, startTokens, validator.BondedTokens())) - require.True(t, validator.IsBonded()) - - delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) - keeper.SetDelegation(ctx, delegation) - - maxEntries := keeper.MaxEntries(ctx) - - oldBonded := bk.GetBalance(ctx, keeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount - oldNotBonded := bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount - - // should all pass - var completionTime time.Time - for i := uint32(0); i < maxEntries; i++ { - var err error - completionTime, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], sdk.NewDec(1)) - require.NoError(t, err) - } - - newBonded := bk.GetBalance(ctx, keeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount - newNotBonded := bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount - require.True(sdk.IntEq(t, newBonded, oldBonded.SubRaw(int64(maxEntries)))) - require.True(sdk.IntEq(t, newNotBonded, oldNotBonded.AddRaw(int64(maxEntries)))) - - oldBonded = bk.GetBalance(ctx, keeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount - oldNotBonded = bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount - - // an additional unbond should fail due to max entries - _, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], sdk.NewDec(1)) - require.Error(t, err) - - newBonded = bk.GetBalance(ctx, keeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount - newNotBonded = bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount - - require.True(sdk.IntEq(t, newBonded, oldBonded)) - require.True(sdk.IntEq(t, newNotBonded, oldNotBonded)) - - // mature unbonding delegations - ctx = ctx.WithBlockTime(completionTime) - err = keeper.CompleteUnbonding(ctx, addrDels[0], addrVals[0]) - require.NoError(t, err) - - newBonded = bk.GetBalance(ctx, keeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount - newNotBonded = bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount - require.True(sdk.IntEq(t, newBonded, oldBonded)) - require.True(sdk.IntEq(t, newNotBonded, oldNotBonded.SubRaw(int64(maxEntries)))) - - oldNotBonded = bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount - - // unbonding should work again - _, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], sdk.NewDec(1)) - require.NoError(t, err) - - newBonded = bk.GetBalance(ctx, keeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount - newNotBonded = bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount - require.True(sdk.IntEq(t, newBonded, oldBonded.SubRaw(1))) - require.True(sdk.IntEq(t, newNotBonded, oldNotBonded.AddRaw(1))) -} - -// test undelegating self delegation from a validator pushing it below MinSelfDelegation -// shift it from the bonded to unbonding state and jailed -func TestUndelegateSelfDelegationBelowMinSelfDelegation(t *testing.T) { - ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) - delTokens := sdk.TokensFromConsensusPower(10) - delCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), delTokens)) - - //create a validator with a self-delegation - validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) - - validator.MinSelfDelegation = delTokens - validator, issuedShares := validator.AddTokensFromDel(delTokens) - require.Equal(t, delTokens, issuedShares.RoundInt()) - - // add bonded tokens to pool for delegations - notBondedPool := keeper.GetNotBondedPool(ctx) - oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) - err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(delCoins...)) - require.NoError(t, err) - keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) - - validator = TestingUpdateValidator(keeper, ctx, validator, true) - require.True(t, validator.IsBonded()) - - selfDelegation := types.NewDelegation(sdk.AccAddress(addrVals[0].Bytes()), addrVals[0], issuedShares) - keeper.SetDelegation(ctx, selfDelegation) - - // add bonded tokens to pool for delegations - bondedPool := keeper.GetBondedPool(ctx) - oldBonded := bk.GetAllBalances(ctx, bondedPool.GetAddress()) - err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) - require.NoError(t, err) - keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) - - // create a second delegation to this validator - keeper.DeleteValidatorByPowerIndex(ctx, validator) - validator, issuedShares = validator.AddTokensFromDel(delTokens) - require.True(t, validator.IsBonded()) - require.Equal(t, delTokens, issuedShares.RoundInt()) - - // add bonded tokens to pool for delegations - oldBonded = bk.GetAllBalances(ctx, bondedPool.GetAddress()) - err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) - require.NoError(t, err) - keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) - - validator = TestingUpdateValidator(keeper, ctx, validator, true) - delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) - keeper.SetDelegation(ctx, delegation) - - val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) - _, err = keeper.Undelegate(ctx, val0AccAddr, addrVals[0], sdk.TokensFromConsensusPower(6).ToDec()) - require.NoError(t, err) - - // end block - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 1, len(updates)) - - validator, found := keeper.GetValidator(ctx, addrVals[0]) - require.True(t, found) - require.Equal(t, sdk.TokensFromConsensusPower(14), validator.Tokens) - require.Equal(t, sdk.Unbonding, validator.Status) - require.True(t, validator.Jailed) -} - -func TestUndelegateFromUnbondingValidator(t *testing.T) { - ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) - delTokens := sdk.TokensFromConsensusPower(10) - delCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), delTokens)) - - //create a validator with a self-delegation - validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) - - validator, issuedShares := validator.AddTokensFromDel(delTokens) - require.Equal(t, delTokens, issuedShares.RoundInt()) - - // add bonded tokens to pool for delegations - notBondedPool := keeper.GetNotBondedPool(ctx) - oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) - err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(delCoins...)) - require.NoError(t, err) - keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) - - validator = TestingUpdateValidator(keeper, ctx, validator, true) - require.True(t, validator.IsBonded()) - - selfDelegation := types.NewDelegation(sdk.AccAddress(addrVals[0].Bytes()), addrVals[0], issuedShares) - keeper.SetDelegation(ctx, selfDelegation) - - bondedPool := keeper.GetBondedPool(ctx) - oldBonded := bk.GetAllBalances(ctx, bondedPool.GetAddress()) - err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) - require.NoError(t, err) - keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) - - // create a second delegation to this validator - keeper.DeleteValidatorByPowerIndex(ctx, validator) - - validator, issuedShares = validator.AddTokensFromDel(delTokens) - require.Equal(t, delTokens, issuedShares.RoundInt()) - - oldBonded = bk.GetAllBalances(ctx, bondedPool.GetAddress()) - err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) - require.NoError(t, err) - keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) - - validator = TestingUpdateValidator(keeper, ctx, validator, true) - delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) - keeper.SetDelegation(ctx, delegation) - - oldBonded = bk.GetAllBalances(ctx, bondedPool.GetAddress()) - err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) - require.NoError(t, err) - keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) - - header := ctx.BlockHeader() - blockHeight := int64(10) - header.Height = blockHeight - blockTime := time.Unix(333, 0) - header.Time = blockTime - ctx = ctx.WithBlockHeader(header) - - // unbond the all self-delegation to put validator in unbonding state - val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) - _, err = keeper.Undelegate(ctx, val0AccAddr, addrVals[0], delTokens.ToDec()) - require.NoError(t, err) - - // end block - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 1, len(updates)) - - validator, found := keeper.GetValidator(ctx, addrVals[0]) - require.True(t, found) - require.Equal(t, blockHeight, validator.UnbondingHeight) - params := keeper.GetParams(ctx) - require.True(t, blockTime.Add(params.UnbondingTime).Equal(validator.UnbondingTime)) - - blockHeight2 := int64(20) - blockTime2 := time.Unix(444, 0).UTC() - ctx = ctx.WithBlockHeight(blockHeight2) - ctx = ctx.WithBlockTime(blockTime2) - - // unbond some of the other delegation's shares - _, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], sdk.NewDec(6)) - require.NoError(t, err) - - // retrieve the unbonding delegation - ubd, found := keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) - require.True(t, found) - require.Len(t, ubd.Entries, 1) - require.True(t, ubd.Entries[0].Balance.Equal(sdk.NewInt(6))) - assert.Equal(t, blockHeight2, ubd.Entries[0].CreationHeight) - assert.True(t, blockTime2.Add(params.UnbondingTime).Equal(ubd.Entries[0].CompletionTime)) -} - -func TestUndelegateFromUnbondedValidator(t *testing.T) { - ctx, _, bk, keeper, _ := CreateTestInput(t, false, 1) - delTokens := sdk.TokensFromConsensusPower(10) - delCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), delTokens)) - - // add bonded tokens to pool for delegations - notBondedPool := keeper.GetNotBondedPool(ctx) - oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) - err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(delCoins...)) - require.NoError(t, err) - keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) - - // create a validator with a self-delegation - validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) - - valTokens := sdk.TokensFromConsensusPower(10) - validator, issuedShares := validator.AddTokensFromDel(valTokens) - require.Equal(t, valTokens, issuedShares.RoundInt()) - validator = TestingUpdateValidator(keeper, ctx, validator, true) - require.True(t, validator.IsBonded()) - - val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) - selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) - keeper.SetDelegation(ctx, selfDelegation) - - bondedPool := keeper.GetBondedPool(ctx) - oldBonded := bk.GetAllBalances(ctx, bondedPool.GetAddress()) - err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) - require.NoError(t, err) - keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) - - // create a second delegation to this validator - keeper.DeleteValidatorByPowerIndex(ctx, validator) - validator, issuedShares = validator.AddTokensFromDel(delTokens) - require.Equal(t, delTokens, issuedShares.RoundInt()) - validator = TestingUpdateValidator(keeper, ctx, validator, true) - require.True(t, validator.IsBonded()) - delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) - keeper.SetDelegation(ctx, delegation) - - ctx = ctx.WithBlockHeight(10) - ctx = ctx.WithBlockTime(time.Unix(333, 0)) - - // unbond the all self-delegation to put validator in unbonding state - _, err = keeper.Undelegate(ctx, val0AccAddr, addrVals[0], valTokens.ToDec()) - require.NoError(t, err) - - // end block - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 1, len(updates)) - - validator, found := keeper.GetValidator(ctx, addrVals[0]) - require.True(t, found) - require.Equal(t, ctx.BlockHeight(), validator.UnbondingHeight) - params := keeper.GetParams(ctx) - require.True(t, ctx.BlockHeader().Time.Add(params.UnbondingTime).Equal(validator.UnbondingTime)) - - // unbond the validator - ctx = ctx.WithBlockTime(validator.UnbondingTime) - keeper.UnbondAllMatureValidatorQueue(ctx) - - // Make sure validator is still in state because there is still an outstanding delegation - validator, found = keeper.GetValidator(ctx, addrVals[0]) - require.True(t, found) - require.Equal(t, validator.Status, sdk.Unbonded) - - // unbond some of the other delegation's shares - unbondTokens := sdk.TokensFromConsensusPower(6) - _, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], unbondTokens.ToDec()) - require.NoError(t, err) - - // unbond rest of the other delegation's shares - remainingTokens := delTokens.Sub(unbondTokens) - _, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], remainingTokens.ToDec()) - require.NoError(t, err) - - // now validator should now be deleted from state - validator, found = keeper.GetValidator(ctx, addrVals[0]) - require.False(t, found, "%v", validator) -} - -func TestUnbondingAllDelegationFromValidator(t *testing.T) { - ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) - delTokens := sdk.TokensFromConsensusPower(10) - delCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), delTokens)) - - // add bonded tokens to pool for delegations - notBondedPool := keeper.GetNotBondedPool(ctx) - oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) - err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(delCoins...)) - require.NoError(t, err) - keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) - - //create a validator with a self-delegation - validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) - - valTokens := sdk.TokensFromConsensusPower(10) - validator, issuedShares := validator.AddTokensFromDel(valTokens) - require.Equal(t, valTokens, issuedShares.RoundInt()) - - validator = TestingUpdateValidator(keeper, ctx, validator, true) - require.True(t, validator.IsBonded()) - val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) - - selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) - keeper.SetDelegation(ctx, selfDelegation) - - // create a second delegation to this validator - keeper.DeleteValidatorByPowerIndex(ctx, validator) - validator, issuedShares = validator.AddTokensFromDel(delTokens) - require.Equal(t, delTokens, issuedShares.RoundInt()) - - bondedPool := keeper.GetBondedPool(ctx) - oldBonded := bk.GetAllBalances(ctx, bondedPool.GetAddress()) - err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) - require.NoError(t, err) - keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) - - validator = TestingUpdateValidator(keeper, ctx, validator, true) - require.True(t, validator.IsBonded()) - - delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) - keeper.SetDelegation(ctx, delegation) - - ctx = ctx.WithBlockHeight(10) - ctx = ctx.WithBlockTime(time.Unix(333, 0)) - - // unbond the all self-delegation to put validator in unbonding state - _, err = keeper.Undelegate(ctx, val0AccAddr, addrVals[0], valTokens.ToDec()) - require.NoError(t, err) - - // end block - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 1, len(updates)) - - // unbond all the remaining delegation - _, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], delTokens.ToDec()) - require.NoError(t, err) - - // validator should still be in state and still be in unbonding state - validator, found := keeper.GetValidator(ctx, addrVals[0]) - require.True(t, found) - require.Equal(t, validator.Status, sdk.Unbonding) - - // unbond the validator - ctx = ctx.WithBlockTime(validator.UnbondingTime) - keeper.UnbondAllMatureValidatorQueue(ctx) - - // validator should now be deleted from state - _, found = keeper.GetValidator(ctx, addrVals[0]) - require.False(t, found) -} - -// Make sure that that the retrieving the delegations doesn't affect the state -func TestGetRedelegationsFromSrcValidator(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 0) - - rd := types.NewRedelegation(addrDels[0], addrVals[0], addrVals[1], 0, - time.Unix(0, 0), sdk.NewInt(5), - sdk.NewDec(5)) - - // set and retrieve a record - keeper.SetRedelegation(ctx, rd) - resBond, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) - require.True(t, found) - - // get the redelegations one time - redelegations := keeper.GetRedelegationsFromSrcValidator(ctx, addrVals[0]) - require.Equal(t, 1, len(redelegations)) - require.True(t, redelegations[0].Equal(resBond)) - - // get the redelegations a second time, should be exactly the same - redelegations = keeper.GetRedelegationsFromSrcValidator(ctx, addrVals[0]) - require.Equal(t, 1, len(redelegations)) - require.True(t, redelegations[0].Equal(resBond)) -} - -// tests Get/Set/Remove/Has UnbondingDelegation -func TestRedelegation(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 0) - - rd := types.NewRedelegation(addrDels[0], addrVals[0], addrVals[1], 0, - time.Unix(0, 0), sdk.NewInt(5), - sdk.NewDec(5)) - - // test shouldn't have and redelegations - has := keeper.HasReceivingRedelegation(ctx, addrDels[0], addrVals[1]) - require.False(t, has) - - // set and retrieve a record - keeper.SetRedelegation(ctx, rd) - resRed, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) - require.True(t, found) - - redelegations := keeper.GetRedelegationsFromSrcValidator(ctx, addrVals[0]) - require.Equal(t, 1, len(redelegations)) - require.True(t, redelegations[0].Equal(resRed)) - - redelegations = keeper.GetRedelegations(ctx, addrDels[0], 5) - require.Equal(t, 1, len(redelegations)) - require.True(t, redelegations[0].Equal(resRed)) - - redelegations = keeper.GetAllRedelegations(ctx, addrDels[0], nil, nil) - require.Equal(t, 1, len(redelegations)) - require.True(t, redelegations[0].Equal(resRed)) - - // check if has the redelegation - has = keeper.HasReceivingRedelegation(ctx, addrDels[0], addrVals[1]) - require.True(t, has) - - // modify a records, save, and retrieve - rd.Entries[0].SharesDst = sdk.NewDec(21) - keeper.SetRedelegation(ctx, rd) - - resRed, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) - require.True(t, found) - require.True(t, rd.Equal(resRed)) - - redelegations = keeper.GetRedelegationsFromSrcValidator(ctx, addrVals[0]) - require.Equal(t, 1, len(redelegations)) - require.True(t, redelegations[0].Equal(resRed)) - - redelegations = keeper.GetRedelegations(ctx, addrDels[0], 5) - require.Equal(t, 1, len(redelegations)) - require.True(t, redelegations[0].Equal(resRed)) - - // delete a record - keeper.RemoveRedelegation(ctx, rd) - _, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) - require.False(t, found) - - redelegations = keeper.GetRedelegations(ctx, addrDels[0], 5) - require.Equal(t, 0, len(redelegations)) - - redelegations = keeper.GetAllRedelegations(ctx, addrDels[0], nil, nil) - require.Equal(t, 0, len(redelegations)) -} - -func TestRedelegateToSameValidator(t *testing.T) { - ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) - valTokens := sdk.TokensFromConsensusPower(10) - startCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), valTokens)) - - // add bonded tokens to pool for delegations - notBondedPool := keeper.GetNotBondedPool(ctx) - oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) - err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) - require.NoError(t, err) - keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) - - // create a validator with a self-delegation - validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) - validator, issuedShares := validator.AddTokensFromDel(valTokens) - require.Equal(t, valTokens, issuedShares.RoundInt()) - validator = TestingUpdateValidator(keeper, ctx, validator, true) - require.True(t, validator.IsBonded()) - - val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) - selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) - keeper.SetDelegation(ctx, selfDelegation) - - _, err = keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[0], sdk.NewDec(5)) - require.Error(t, err) -} - -func TestRedelegationMaxEntries(t *testing.T) { - ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) - startTokens := sdk.TokensFromConsensusPower(20) - startCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), startTokens)) - - // add bonded tokens to pool for delegations - notBondedPool := keeper.GetNotBondedPool(ctx) - oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) - err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) - require.NoError(t, err) - keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) - - // create a validator with a self-delegation - validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) - valTokens := sdk.TokensFromConsensusPower(10) - validator, issuedShares := validator.AddTokensFromDel(valTokens) - require.Equal(t, valTokens, issuedShares.RoundInt()) - validator = TestingUpdateValidator(keeper, ctx, validator, true) - val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) - selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) - keeper.SetDelegation(ctx, selfDelegation) - - // create a second validator - validator2 := types.NewValidator(addrVals[1], PKs[1], types.Description{}) - validator2, issuedShares = validator2.AddTokensFromDel(valTokens) - require.Equal(t, valTokens, issuedShares.RoundInt()) - - validator2 = TestingUpdateValidator(keeper, ctx, validator2, true) - require.Equal(t, sdk.Bonded, validator2.Status) - - maxEntries := keeper.MaxEntries(ctx) - - // redelegations should pass - var completionTime time.Time - for i := uint32(0); i < maxEntries; i++ { - var err error - completionTime, err = keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1], sdk.NewDec(1)) - require.NoError(t, err) - } - - // an additional redelegation should fail due to max entries - _, err = keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1], sdk.NewDec(1)) - require.Error(t, err) - - // mature redelegations - ctx = ctx.WithBlockTime(completionTime) - err = keeper.CompleteRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1]) - require.NoError(t, err) - - // redelegation should work again - _, err = keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1], sdk.NewDec(1)) - require.NoError(t, err) -} - -func TestRedelegateSelfDelegation(t *testing.T) { - ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) - startTokens := sdk.TokensFromConsensusPower(30) - startCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), startTokens)) - - // add bonded tokens to pool for delegations - notBondedPool := keeper.GetNotBondedPool(ctx) - oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) - err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) - require.NoError(t, err) - keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) - - //create a validator with a self-delegation - validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) - valTokens := sdk.TokensFromConsensusPower(10) - validator, issuedShares := validator.AddTokensFromDel(valTokens) - require.Equal(t, valTokens, issuedShares.RoundInt()) - - validator = TestingUpdateValidator(keeper, ctx, validator, true) - - val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) - selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) - keeper.SetDelegation(ctx, selfDelegation) - - // create a second validator - validator2 := types.NewValidator(addrVals[1], PKs[1], types.Description{}) - validator2, issuedShares = validator2.AddTokensFromDel(valTokens) - require.Equal(t, valTokens, issuedShares.RoundInt()) - validator2 = TestingUpdateValidator(keeper, ctx, validator2, true) - require.Equal(t, sdk.Bonded, validator2.Status) - - // create a second delegation to validator 1 - delTokens := sdk.TokensFromConsensusPower(10) - validator, issuedShares = validator.AddTokensFromDel(delTokens) - require.Equal(t, delTokens, issuedShares.RoundInt()) - validator = TestingUpdateValidator(keeper, ctx, validator, true) - - delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) - keeper.SetDelegation(ctx, delegation) - - _, err = keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1], delTokens.ToDec()) - require.NoError(t, err) - - // end block - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 2, len(updates)) - - validator, found := keeper.GetValidator(ctx, addrVals[0]) - require.True(t, found) - require.Equal(t, valTokens, validator.Tokens) - require.Equal(t, sdk.Unbonding, validator.Status) -} - -func TestRedelegateFromUnbondingValidator(t *testing.T) { - ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) - startTokens := sdk.TokensFromConsensusPower(30) - startCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), startTokens)) - - // add bonded tokens to pool for delegations - notBondedPool := keeper.GetNotBondedPool(ctx) - oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) - err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) - require.NoError(t, err) - keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) - - //create a validator with a self-delegation - validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) - - valTokens := sdk.TokensFromConsensusPower(10) - validator, issuedShares := validator.AddTokensFromDel(valTokens) - require.Equal(t, valTokens, issuedShares.RoundInt()) - validator = TestingUpdateValidator(keeper, ctx, validator, true) - val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) - selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) - keeper.SetDelegation(ctx, selfDelegation) - - // create a second delegation to this validator - keeper.DeleteValidatorByPowerIndex(ctx, validator) - delTokens := sdk.TokensFromConsensusPower(10) - validator, issuedShares = validator.AddTokensFromDel(delTokens) - require.Equal(t, delTokens, issuedShares.RoundInt()) - validator = TestingUpdateValidator(keeper, ctx, validator, true) - delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) - keeper.SetDelegation(ctx, delegation) - - // create a second validator - validator2 := types.NewValidator(addrVals[1], PKs[1], types.Description{}) - validator2, issuedShares = validator2.AddTokensFromDel(valTokens) - require.Equal(t, valTokens, issuedShares.RoundInt()) - validator2 = TestingUpdateValidator(keeper, ctx, validator2, true) - - header := ctx.BlockHeader() - blockHeight := int64(10) - header.Height = blockHeight - blockTime := time.Unix(333, 0) - header.Time = blockTime - ctx = ctx.WithBlockHeader(header) - - // unbond the all self-delegation to put validator in unbonding state - _, err = keeper.Undelegate(ctx, val0AccAddr, addrVals[0], delTokens.ToDec()) - require.NoError(t, err) - - // end block - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 1, len(updates)) - - validator, found := keeper.GetValidator(ctx, addrVals[0]) - require.True(t, found) - require.Equal(t, blockHeight, validator.UnbondingHeight) - params := keeper.GetParams(ctx) - require.True(t, blockTime.Add(params.UnbondingTime).Equal(validator.UnbondingTime)) - - //change the context - header = ctx.BlockHeader() - blockHeight2 := int64(20) - header.Height = blockHeight2 - blockTime2 := time.Unix(444, 0) - header.Time = blockTime2 - ctx = ctx.WithBlockHeader(header) - - // unbond some of the other delegation's shares - redelegateTokens := sdk.TokensFromConsensusPower(6) - _, err = keeper.BeginRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1], redelegateTokens.ToDec()) - require.NoError(t, err) - - // retrieve the unbonding delegation - ubd, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) - require.True(t, found) - require.Len(t, ubd.Entries, 1) - assert.Equal(t, blockHeight, ubd.Entries[0].CreationHeight) - assert.True(t, blockTime.Add(params.UnbondingTime).Equal(ubd.Entries[0].CompletionTime)) -} - -func TestRedelegateFromUnbondedValidator(t *testing.T) { - ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) - startTokens := sdk.TokensFromConsensusPower(30) - startCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), startTokens)) - - // add bonded tokens to pool for delegations - notBondedPool := keeper.GetNotBondedPool(ctx) - oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) - err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) - require.NoError(t, err) - keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) - - //create a validator with a self-delegation - validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) - - valTokens := sdk.TokensFromConsensusPower(10) - validator, issuedShares := validator.AddTokensFromDel(valTokens) - require.Equal(t, valTokens, issuedShares.RoundInt()) - validator = TestingUpdateValidator(keeper, ctx, validator, true) - val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) - selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) - keeper.SetDelegation(ctx, selfDelegation) - - // create a second delegation to this validator - keeper.DeleteValidatorByPowerIndex(ctx, validator) - delTokens := sdk.TokensFromConsensusPower(10) - validator, issuedShares = validator.AddTokensFromDel(delTokens) - require.Equal(t, delTokens, issuedShares.RoundInt()) - validator = TestingUpdateValidator(keeper, ctx, validator, true) - delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) - keeper.SetDelegation(ctx, delegation) - - // create a second validator - validator2 := types.NewValidator(addrVals[1], PKs[1], types.Description{}) - validator2, issuedShares = validator2.AddTokensFromDel(valTokens) - require.Equal(t, valTokens, issuedShares.RoundInt()) - validator2 = TestingUpdateValidator(keeper, ctx, validator2, true) - require.Equal(t, sdk.Bonded, validator2.Status) - - ctx = ctx.WithBlockHeight(10) - ctx = ctx.WithBlockTime(time.Unix(333, 0)) - - // unbond the all self-delegation to put validator in unbonding state - _, err = keeper.Undelegate(ctx, val0AccAddr, addrVals[0], delTokens.ToDec()) - require.NoError(t, err) - - // end block - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 1, len(updates)) - - validator, found := keeper.GetValidator(ctx, addrVals[0]) - require.True(t, found) - require.Equal(t, ctx.BlockHeight(), validator.UnbondingHeight) - params := keeper.GetParams(ctx) - require.True(t, ctx.BlockHeader().Time.Add(params.UnbondingTime).Equal(validator.UnbondingTime)) - - // unbond the validator - keeper.unbondingToUnbonded(ctx, validator) - - // redelegate some of the delegation's shares - redelegationTokens := sdk.TokensFromConsensusPower(6) - _, err = keeper.BeginRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1], redelegationTokens.ToDec()) - require.NoError(t, err) - - // no red should have been found - red, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) - require.False(t, found, "%v", red) -} +//func TestUnbondingDelegationsMaxEntries(t *testing.T) { +// ctx, _, bk, keeper, _ := CreateTestInput(t, false, 1) +// startTokens := sdk.TokensFromConsensusPower(10) +// +// bondDenom := keeper.BondDenom(ctx) +// notBondedPool := keeper.GetNotBondedPool(ctx) +// +// err := bk.SetBalances(ctx, notBondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(bondDenom, startTokens))) +// require.NoError(t, err) +// keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) +// +// // create a validator and a delegator to that validator +// validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) +// +// validator, issuedShares := validator.AddTokensFromDel(startTokens) +// require.Equal(t, startTokens, issuedShares.RoundInt()) +// +// validator = TestingUpdateValidator(keeper, ctx, validator, true) +// require.True(sdk.IntEq(t, startTokens, validator.BondedTokens())) +// require.True(t, validator.IsBonded()) +// +// delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) +// keeper.SetDelegation(ctx, delegation) +// +// maxEntries := keeper.MaxEntries(ctx) +// +// oldBonded := bk.GetBalance(ctx, keeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount +// oldNotBonded := bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount +// +// // should all pass +// var completionTime time.Time +// for i := uint32(0); i < maxEntries; i++ { +// var err error +// completionTime, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], sdk.NewDec(1)) +// require.NoError(t, err) +// } +// +// newBonded := bk.GetBalance(ctx, keeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount +// newNotBonded := bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount +// require.True(sdk.IntEq(t, newBonded, oldBonded.SubRaw(int64(maxEntries)))) +// require.True(sdk.IntEq(t, newNotBonded, oldNotBonded.AddRaw(int64(maxEntries)))) +// +// oldBonded = bk.GetBalance(ctx, keeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount +// oldNotBonded = bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount +// +// // an additional unbond should fail due to max entries +// _, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], sdk.NewDec(1)) +// require.Error(t, err) +// +// newBonded = bk.GetBalance(ctx, keeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount +// newNotBonded = bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount +// +// require.True(sdk.IntEq(t, newBonded, oldBonded)) +// require.True(sdk.IntEq(t, newNotBonded, oldNotBonded)) +// +// // mature unbonding delegations +// ctx = ctx.WithBlockTime(completionTime) +// err = keeper.CompleteUnbonding(ctx, addrDels[0], addrVals[0]) +// require.NoError(t, err) +// +// newBonded = bk.GetBalance(ctx, keeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount +// newNotBonded = bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount +// require.True(sdk.IntEq(t, newBonded, oldBonded)) +// require.True(sdk.IntEq(t, newNotBonded, oldNotBonded.SubRaw(int64(maxEntries)))) +// +// oldNotBonded = bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount +// +// // unbonding should work again +// _, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], sdk.NewDec(1)) +// require.NoError(t, err) +// +// newBonded = bk.GetBalance(ctx, keeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount +// newNotBonded = bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount +// require.True(sdk.IntEq(t, newBonded, oldBonded.SubRaw(1))) +// require.True(sdk.IntEq(t, newNotBonded, oldNotBonded.AddRaw(1))) +//} +// +//// test undelegating self delegation from a validator pushing it below MinSelfDelegation +//// shift it from the bonded to unbonding state and jailed +//func TestUndelegateSelfDelegationBelowMinSelfDelegation(t *testing.T) { +// ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) +// delTokens := sdk.TokensFromConsensusPower(10) +// delCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), delTokens)) +// +// //create a validator with a self-delegation +// validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) +// +// validator.MinSelfDelegation = delTokens +// validator, issuedShares := validator.AddTokensFromDel(delTokens) +// require.Equal(t, delTokens, issuedShares.RoundInt()) +// +// // add bonded tokens to pool for delegations +// notBondedPool := keeper.GetNotBondedPool(ctx) +// oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) +// err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(delCoins...)) +// require.NoError(t, err) +// keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) +// +// validator = TestingUpdateValidator(keeper, ctx, validator, true) +// require.True(t, validator.IsBonded()) +// +// selfDelegation := types.NewDelegation(sdk.AccAddress(addrVals[0].Bytes()), addrVals[0], issuedShares) +// keeper.SetDelegation(ctx, selfDelegation) +// +// // add bonded tokens to pool for delegations +// bondedPool := keeper.GetBondedPool(ctx) +// oldBonded := bk.GetAllBalances(ctx, bondedPool.GetAddress()) +// err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) +// require.NoError(t, err) +// keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) +// +// // create a second delegation to this validator +// keeper.DeleteValidatorByPowerIndex(ctx, validator) +// validator, issuedShares = validator.AddTokensFromDel(delTokens) +// require.True(t, validator.IsBonded()) +// require.Equal(t, delTokens, issuedShares.RoundInt()) +// +// // add bonded tokens to pool for delegations +// oldBonded = bk.GetAllBalances(ctx, bondedPool.GetAddress()) +// err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) +// require.NoError(t, err) +// keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) +// +// validator = TestingUpdateValidator(keeper, ctx, validator, true) +// delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) +// keeper.SetDelegation(ctx, delegation) +// +// val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) +// _, err = keeper.Undelegate(ctx, val0AccAddr, addrVals[0], sdk.TokensFromConsensusPower(6).ToDec()) +// require.NoError(t, err) +// +// // end block +// updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) +// require.Equal(t, 1, len(updates)) +// +// validator, found := keeper.GetValidator(ctx, addrVals[0]) +// require.True(t, found) +// require.Equal(t, sdk.TokensFromConsensusPower(14), validator.Tokens) +// require.Equal(t, sdk.Unbonding, validator.Status) +// require.True(t, validator.Jailed) +//} +// +//func TestUndelegateFromUnbondingValidator(t *testing.T) { +// ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) +// delTokens := sdk.TokensFromConsensusPower(10) +// delCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), delTokens)) +// +// //create a validator with a self-delegation +// validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) +// +// validator, issuedShares := validator.AddTokensFromDel(delTokens) +// require.Equal(t, delTokens, issuedShares.RoundInt()) +// +// // add bonded tokens to pool for delegations +// notBondedPool := keeper.GetNotBondedPool(ctx) +// oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) +// err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(delCoins...)) +// require.NoError(t, err) +// keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) +// +// validator = TestingUpdateValidator(keeper, ctx, validator, true) +// require.True(t, validator.IsBonded()) +// +// selfDelegation := types.NewDelegation(sdk.AccAddress(addrVals[0].Bytes()), addrVals[0], issuedShares) +// keeper.SetDelegation(ctx, selfDelegation) +// +// bondedPool := keeper.GetBondedPool(ctx) +// oldBonded := bk.GetAllBalances(ctx, bondedPool.GetAddress()) +// err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) +// require.NoError(t, err) +// keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) +// +// // create a second delegation to this validator +// keeper.DeleteValidatorByPowerIndex(ctx, validator) +// +// validator, issuedShares = validator.AddTokensFromDel(delTokens) +// require.Equal(t, delTokens, issuedShares.RoundInt()) +// +// oldBonded = bk.GetAllBalances(ctx, bondedPool.GetAddress()) +// err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) +// require.NoError(t, err) +// keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) +// +// validator = TestingUpdateValidator(keeper, ctx, validator, true) +// delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) +// keeper.SetDelegation(ctx, delegation) +// +// oldBonded = bk.GetAllBalances(ctx, bondedPool.GetAddress()) +// err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) +// require.NoError(t, err) +// keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) +// +// header := ctx.BlockHeader() +// blockHeight := int64(10) +// header.Height = blockHeight +// blockTime := time.Unix(333, 0) +// header.Time = blockTime +// ctx = ctx.WithBlockHeader(header) +// +// // unbond the all self-delegation to put validator in unbonding state +// val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) +// _, err = keeper.Undelegate(ctx, val0AccAddr, addrVals[0], delTokens.ToDec()) +// require.NoError(t, err) +// +// // end block +// updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) +// require.Equal(t, 1, len(updates)) +// +// validator, found := keeper.GetValidator(ctx, addrVals[0]) +// require.True(t, found) +// require.Equal(t, blockHeight, validator.UnbondingHeight) +// params := keeper.GetParams(ctx) +// require.True(t, blockTime.Add(params.UnbondingTime).Equal(validator.UnbondingTime)) +// +// blockHeight2 := int64(20) +// blockTime2 := time.Unix(444, 0).UTC() +// ctx = ctx.WithBlockHeight(blockHeight2) +// ctx = ctx.WithBlockTime(blockTime2) +// +// // unbond some of the other delegation's shares +// _, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], sdk.NewDec(6)) +// require.NoError(t, err) +// +// // retrieve the unbonding delegation +// ubd, found := keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) +// require.True(t, found) +// require.Len(t, ubd.Entries, 1) +// require.True(t, ubd.Entries[0].Balance.Equal(sdk.NewInt(6))) +// assert.Equal(t, blockHeight2, ubd.Entries[0].CreationHeight) +// assert.True(t, blockTime2.Add(params.UnbondingTime).Equal(ubd.Entries[0].CompletionTime)) +//} +// +//func TestUndelegateFromUnbondedValidator(t *testing.T) { +// ctx, _, bk, keeper, _ := CreateTestInput(t, false, 1) +// delTokens := sdk.TokensFromConsensusPower(10) +// delCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), delTokens)) +// +// // add bonded tokens to pool for delegations +// notBondedPool := keeper.GetNotBondedPool(ctx) +// oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) +// err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(delCoins...)) +// require.NoError(t, err) +// keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) +// +// // create a validator with a self-delegation +// validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) +// +// valTokens := sdk.TokensFromConsensusPower(10) +// validator, issuedShares := validator.AddTokensFromDel(valTokens) +// require.Equal(t, valTokens, issuedShares.RoundInt()) +// validator = TestingUpdateValidator(keeper, ctx, validator, true) +// require.True(t, validator.IsBonded()) +// +// val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) +// selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) +// keeper.SetDelegation(ctx, selfDelegation) +// +// bondedPool := keeper.GetBondedPool(ctx) +// oldBonded := bk.GetAllBalances(ctx, bondedPool.GetAddress()) +// err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) +// require.NoError(t, err) +// keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) +// +// // create a second delegation to this validator +// keeper.DeleteValidatorByPowerIndex(ctx, validator) +// validator, issuedShares = validator.AddTokensFromDel(delTokens) +// require.Equal(t, delTokens, issuedShares.RoundInt()) +// validator = TestingUpdateValidator(keeper, ctx, validator, true) +// require.True(t, validator.IsBonded()) +// delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) +// keeper.SetDelegation(ctx, delegation) +// +// ctx = ctx.WithBlockHeight(10) +// ctx = ctx.WithBlockTime(time.Unix(333, 0)) +// +// // unbond the all self-delegation to put validator in unbonding state +// _, err = keeper.Undelegate(ctx, val0AccAddr, addrVals[0], valTokens.ToDec()) +// require.NoError(t, err) +// +// // end block +// updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) +// require.Equal(t, 1, len(updates)) +// +// validator, found := keeper.GetValidator(ctx, addrVals[0]) +// require.True(t, found) +// require.Equal(t, ctx.BlockHeight(), validator.UnbondingHeight) +// params := keeper.GetParams(ctx) +// require.True(t, ctx.BlockHeader().Time.Add(params.UnbondingTime).Equal(validator.UnbondingTime)) +// +// // unbond the validator +// ctx = ctx.WithBlockTime(validator.UnbondingTime) +// keeper.UnbondAllMatureValidatorQueue(ctx) +// +// // Make sure validator is still in state because there is still an outstanding delegation +// validator, found = keeper.GetValidator(ctx, addrVals[0]) +// require.True(t, found) +// require.Equal(t, validator.Status, sdk.Unbonded) +// +// // unbond some of the other delegation's shares +// unbondTokens := sdk.TokensFromConsensusPower(6) +// _, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], unbondTokens.ToDec()) +// require.NoError(t, err) +// +// // unbond rest of the other delegation's shares +// remainingTokens := delTokens.Sub(unbondTokens) +// _, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], remainingTokens.ToDec()) +// require.NoError(t, err) +// +// // now validator should now be deleted from state +// validator, found = keeper.GetValidator(ctx, addrVals[0]) +// require.False(t, found, "%v", validator) +//} +// +//func TestUnbondingAllDelegationFromValidator(t *testing.T) { +// ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) +// delTokens := sdk.TokensFromConsensusPower(10) +// delCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), delTokens)) +// +// // add bonded tokens to pool for delegations +// notBondedPool := keeper.GetNotBondedPool(ctx) +// oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) +// err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(delCoins...)) +// require.NoError(t, err) +// keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) +// +// //create a validator with a self-delegation +// validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) +// +// valTokens := sdk.TokensFromConsensusPower(10) +// validator, issuedShares := validator.AddTokensFromDel(valTokens) +// require.Equal(t, valTokens, issuedShares.RoundInt()) +// +// validator = TestingUpdateValidator(keeper, ctx, validator, true) +// require.True(t, validator.IsBonded()) +// val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) +// +// selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) +// keeper.SetDelegation(ctx, selfDelegation) +// +// // create a second delegation to this validator +// keeper.DeleteValidatorByPowerIndex(ctx, validator) +// validator, issuedShares = validator.AddTokensFromDel(delTokens) +// require.Equal(t, delTokens, issuedShares.RoundInt()) +// +// bondedPool := keeper.GetBondedPool(ctx) +// oldBonded := bk.GetAllBalances(ctx, bondedPool.GetAddress()) +// err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) +// require.NoError(t, err) +// keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) +// +// validator = TestingUpdateValidator(keeper, ctx, validator, true) +// require.True(t, validator.IsBonded()) +// +// delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) +// keeper.SetDelegation(ctx, delegation) +// +// ctx = ctx.WithBlockHeight(10) +// ctx = ctx.WithBlockTime(time.Unix(333, 0)) +// +// // unbond the all self-delegation to put validator in unbonding state +// _, err = keeper.Undelegate(ctx, val0AccAddr, addrVals[0], valTokens.ToDec()) +// require.NoError(t, err) +// +// // end block +// updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) +// require.Equal(t, 1, len(updates)) +// +// // unbond all the remaining delegation +// _, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], delTokens.ToDec()) +// require.NoError(t, err) +// +// // validator should still be in state and still be in unbonding state +// validator, found := keeper.GetValidator(ctx, addrVals[0]) +// require.True(t, found) +// require.Equal(t, validator.Status, sdk.Unbonding) +// +// // unbond the validator +// ctx = ctx.WithBlockTime(validator.UnbondingTime) +// keeper.UnbondAllMatureValidatorQueue(ctx) +// +// // validator should now be deleted from state +// _, found = keeper.GetValidator(ctx, addrVals[0]) +// require.False(t, found) +//} +// +//// Make sure that that the retrieving the delegations doesn't affect the state +//func TestGetRedelegationsFromSrcValidator(t *testing.T) { +// ctx, _, _, keeper, _ := CreateTestInput(t, false, 0) +// +// rd := types.NewRedelegation(addrDels[0], addrVals[0], addrVals[1], 0, +// time.Unix(0, 0), sdk.NewInt(5), +// sdk.NewDec(5)) +// +// // set and retrieve a record +// keeper.SetRedelegation(ctx, rd) +// resBond, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) +// require.True(t, found) +// +// // get the redelegations one time +// redelegations := keeper.GetRedelegationsFromSrcValidator(ctx, addrVals[0]) +// require.Equal(t, 1, len(redelegations)) +// require.True(t, redelegations[0].Equal(resBond)) +// +// // get the redelegations a second time, should be exactly the same +// redelegations = keeper.GetRedelegationsFromSrcValidator(ctx, addrVals[0]) +// require.Equal(t, 1, len(redelegations)) +// require.True(t, redelegations[0].Equal(resBond)) +//} +// +//// tests Get/Set/Remove/Has UnbondingDelegation +//func TestRedelegation(t *testing.T) { +// ctx, _, _, keeper, _ := CreateTestInput(t, false, 0) +// +// rd := types.NewRedelegation(addrDels[0], addrVals[0], addrVals[1], 0, +// time.Unix(0, 0), sdk.NewInt(5), +// sdk.NewDec(5)) +// +// // test shouldn't have and redelegations +// has := keeper.HasReceivingRedelegation(ctx, addrDels[0], addrVals[1]) +// require.False(t, has) +// +// // set and retrieve a record +// keeper.SetRedelegation(ctx, rd) +// resRed, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) +// require.True(t, found) +// +// redelegations := keeper.GetRedelegationsFromSrcValidator(ctx, addrVals[0]) +// require.Equal(t, 1, len(redelegations)) +// require.True(t, redelegations[0].Equal(resRed)) +// +// redelegations = keeper.GetRedelegations(ctx, addrDels[0], 5) +// require.Equal(t, 1, len(redelegations)) +// require.True(t, redelegations[0].Equal(resRed)) +// +// redelegations = keeper.GetAllRedelegations(ctx, addrDels[0], nil, nil) +// require.Equal(t, 1, len(redelegations)) +// require.True(t, redelegations[0].Equal(resRed)) +// +// // check if has the redelegation +// has = keeper.HasReceivingRedelegation(ctx, addrDels[0], addrVals[1]) +// require.True(t, has) +// +// // modify a records, save, and retrieve +// rd.Entries[0].SharesDst = sdk.NewDec(21) +// keeper.SetRedelegation(ctx, rd) +// +// resRed, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) +// require.True(t, found) +// require.True(t, rd.Equal(resRed)) +// +// redelegations = keeper.GetRedelegationsFromSrcValidator(ctx, addrVals[0]) +// require.Equal(t, 1, len(redelegations)) +// require.True(t, redelegations[0].Equal(resRed)) +// +// redelegations = keeper.GetRedelegations(ctx, addrDels[0], 5) +// require.Equal(t, 1, len(redelegations)) +// require.True(t, redelegations[0].Equal(resRed)) +// +// // delete a record +// keeper.RemoveRedelegation(ctx, rd) +// _, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) +// require.False(t, found) +// +// redelegations = keeper.GetRedelegations(ctx, addrDels[0], 5) +// require.Equal(t, 0, len(redelegations)) +// +// redelegations = keeper.GetAllRedelegations(ctx, addrDels[0], nil, nil) +// require.Equal(t, 0, len(redelegations)) +//} +// +//func TestRedelegateToSameValidator(t *testing.T) { +// ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) +// valTokens := sdk.TokensFromConsensusPower(10) +// startCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), valTokens)) +// +// // add bonded tokens to pool for delegations +// notBondedPool := keeper.GetNotBondedPool(ctx) +// oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) +// err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) +// require.NoError(t, err) +// keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) +// +// // create a validator with a self-delegation +// validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) +// validator, issuedShares := validator.AddTokensFromDel(valTokens) +// require.Equal(t, valTokens, issuedShares.RoundInt()) +// validator = TestingUpdateValidator(keeper, ctx, validator, true) +// require.True(t, validator.IsBonded()) +// +// val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) +// selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) +// keeper.SetDelegation(ctx, selfDelegation) +// +// _, err = keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[0], sdk.NewDec(5)) +// require.Error(t, err) +//} +// +//func TestRedelegationMaxEntries(t *testing.T) { +// ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) +// startTokens := sdk.TokensFromConsensusPower(20) +// startCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), startTokens)) +// +// // add bonded tokens to pool for delegations +// notBondedPool := keeper.GetNotBondedPool(ctx) +// oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) +// err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) +// require.NoError(t, err) +// keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) +// +// // create a validator with a self-delegation +// validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) +// valTokens := sdk.TokensFromConsensusPower(10) +// validator, issuedShares := validator.AddTokensFromDel(valTokens) +// require.Equal(t, valTokens, issuedShares.RoundInt()) +// validator = TestingUpdateValidator(keeper, ctx, validator, true) +// val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) +// selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) +// keeper.SetDelegation(ctx, selfDelegation) +// +// // create a second validator +// validator2 := types.NewValidator(addrVals[1], PKs[1], types.Description{}) +// validator2, issuedShares = validator2.AddTokensFromDel(valTokens) +// require.Equal(t, valTokens, issuedShares.RoundInt()) +// +// validator2 = TestingUpdateValidator(keeper, ctx, validator2, true) +// require.Equal(t, sdk.Bonded, validator2.Status) +// +// maxEntries := keeper.MaxEntries(ctx) +// +// // redelegations should pass +// var completionTime time.Time +// for i := uint32(0); i < maxEntries; i++ { +// var err error +// completionTime, err = keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1], sdk.NewDec(1)) +// require.NoError(t, err) +// } +// +// // an additional redelegation should fail due to max entries +// _, err = keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1], sdk.NewDec(1)) +// require.Error(t, err) +// +// // mature redelegations +// ctx = ctx.WithBlockTime(completionTime) +// err = keeper.CompleteRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1]) +// require.NoError(t, err) +// +// // redelegation should work again +// _, err = keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1], sdk.NewDec(1)) +// require.NoError(t, err) +//} +// +//func TestRedelegateSelfDelegation(t *testing.T) { +// ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) +// startTokens := sdk.TokensFromConsensusPower(30) +// startCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), startTokens)) +// +// // add bonded tokens to pool for delegations +// notBondedPool := keeper.GetNotBondedPool(ctx) +// oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) +// err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) +// require.NoError(t, err) +// keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) +// +// //create a validator with a self-delegation +// validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) +// valTokens := sdk.TokensFromConsensusPower(10) +// validator, issuedShares := validator.AddTokensFromDel(valTokens) +// require.Equal(t, valTokens, issuedShares.RoundInt()) +// +// validator = TestingUpdateValidator(keeper, ctx, validator, true) +// +// val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) +// selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) +// keeper.SetDelegation(ctx, selfDelegation) +// +// // create a second validator +// validator2 := types.NewValidator(addrVals[1], PKs[1], types.Description{}) +// validator2, issuedShares = validator2.AddTokensFromDel(valTokens) +// require.Equal(t, valTokens, issuedShares.RoundInt()) +// validator2 = TestingUpdateValidator(keeper, ctx, validator2, true) +// require.Equal(t, sdk.Bonded, validator2.Status) +// +// // create a second delegation to validator 1 +// delTokens := sdk.TokensFromConsensusPower(10) +// validator, issuedShares = validator.AddTokensFromDel(delTokens) +// require.Equal(t, delTokens, issuedShares.RoundInt()) +// validator = TestingUpdateValidator(keeper, ctx, validator, true) +// +// delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) +// keeper.SetDelegation(ctx, delegation) +// +// _, err = keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1], delTokens.ToDec()) +// require.NoError(t, err) +// +// // end block +// updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) +// require.Equal(t, 2, len(updates)) +// +// validator, found := keeper.GetValidator(ctx, addrVals[0]) +// require.True(t, found) +// require.Equal(t, valTokens, validator.Tokens) +// require.Equal(t, sdk.Unbonding, validator.Status) +//} +// +//func TestRedelegateFromUnbondingValidator(t *testing.T) { +// ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) +// startTokens := sdk.TokensFromConsensusPower(30) +// startCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), startTokens)) +// +// // add bonded tokens to pool for delegations +// notBondedPool := keeper.GetNotBondedPool(ctx) +// oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) +// err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) +// require.NoError(t, err) +// keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) +// +// //create a validator with a self-delegation +// validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) +// +// valTokens := sdk.TokensFromConsensusPower(10) +// validator, issuedShares := validator.AddTokensFromDel(valTokens) +// require.Equal(t, valTokens, issuedShares.RoundInt()) +// validator = TestingUpdateValidator(keeper, ctx, validator, true) +// val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) +// selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) +// keeper.SetDelegation(ctx, selfDelegation) +// +// // create a second delegation to this validator +// keeper.DeleteValidatorByPowerIndex(ctx, validator) +// delTokens := sdk.TokensFromConsensusPower(10) +// validator, issuedShares = validator.AddTokensFromDel(delTokens) +// require.Equal(t, delTokens, issuedShares.RoundInt()) +// validator = TestingUpdateValidator(keeper, ctx, validator, true) +// delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) +// keeper.SetDelegation(ctx, delegation) +// +// // create a second validator +// validator2 := types.NewValidator(addrVals[1], PKs[1], types.Description{}) +// validator2, issuedShares = validator2.AddTokensFromDel(valTokens) +// require.Equal(t, valTokens, issuedShares.RoundInt()) +// validator2 = TestingUpdateValidator(keeper, ctx, validator2, true) +// +// header := ctx.BlockHeader() +// blockHeight := int64(10) +// header.Height = blockHeight +// blockTime := time.Unix(333, 0) +// header.Time = blockTime +// ctx = ctx.WithBlockHeader(header) +// +// // unbond the all self-delegation to put validator in unbonding state +// _, err = keeper.Undelegate(ctx, val0AccAddr, addrVals[0], delTokens.ToDec()) +// require.NoError(t, err) +// +// // end block +// updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) +// require.Equal(t, 1, len(updates)) +// +// validator, found := keeper.GetValidator(ctx, addrVals[0]) +// require.True(t, found) +// require.Equal(t, blockHeight, validator.UnbondingHeight) +// params := keeper.GetParams(ctx) +// require.True(t, blockTime.Add(params.UnbondingTime).Equal(validator.UnbondingTime)) +// +// //change the context +// header = ctx.BlockHeader() +// blockHeight2 := int64(20) +// header.Height = blockHeight2 +// blockTime2 := time.Unix(444, 0) +// header.Time = blockTime2 +// ctx = ctx.WithBlockHeader(header) +// +// // unbond some of the other delegation's shares +// redelegateTokens := sdk.TokensFromConsensusPower(6) +// _, err = keeper.BeginRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1], redelegateTokens.ToDec()) +// require.NoError(t, err) +// +// // retrieve the unbonding delegation +// ubd, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) +// require.True(t, found) +// require.Len(t, ubd.Entries, 1) +// assert.Equal(t, blockHeight, ubd.Entries[0].CreationHeight) +// assert.True(t, blockTime.Add(params.UnbondingTime).Equal(ubd.Entries[0].CompletionTime)) +//} +// +//func TestRedelegateFromUnbondedValidator(t *testing.T) { +// ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) +// startTokens := sdk.TokensFromConsensusPower(30) +// startCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), startTokens)) +// +// // add bonded tokens to pool for delegations +// notBondedPool := keeper.GetNotBondedPool(ctx) +// oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) +// err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) +// require.NoError(t, err) +// keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) +// +// //create a validator with a self-delegation +// validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) +// +// valTokens := sdk.TokensFromConsensusPower(10) +// validator, issuedShares := validator.AddTokensFromDel(valTokens) +// require.Equal(t, valTokens, issuedShares.RoundInt()) +// validator = TestingUpdateValidator(keeper, ctx, validator, true) +// val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) +// selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) +// keeper.SetDelegation(ctx, selfDelegation) +// +// // create a second delegation to this validator +// keeper.DeleteValidatorByPowerIndex(ctx, validator) +// delTokens := sdk.TokensFromConsensusPower(10) +// validator, issuedShares = validator.AddTokensFromDel(delTokens) +// require.Equal(t, delTokens, issuedShares.RoundInt()) +// validator = TestingUpdateValidator(keeper, ctx, validator, true) +// delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) +// keeper.SetDelegation(ctx, delegation) +// +// // create a second validator +// validator2 := types.NewValidator(addrVals[1], PKs[1], types.Description{}) +// validator2, issuedShares = validator2.AddTokensFromDel(valTokens) +// require.Equal(t, valTokens, issuedShares.RoundInt()) +// validator2 = TestingUpdateValidator(keeper, ctx, validator2, true) +// require.Equal(t, sdk.Bonded, validator2.Status) +// +// ctx = ctx.WithBlockHeight(10) +// ctx = ctx.WithBlockTime(time.Unix(333, 0)) +// +// // unbond the all self-delegation to put validator in unbonding state +// _, err = keeper.Undelegate(ctx, val0AccAddr, addrVals[0], delTokens.ToDec()) +// require.NoError(t, err) +// +// // end block +// updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) +// require.Equal(t, 1, len(updates)) +// +// validator, found := keeper.GetValidator(ctx, addrVals[0]) +// require.True(t, found) +// require.Equal(t, ctx.BlockHeight(), validator.UnbondingHeight) +// params := keeper.GetParams(ctx) +// require.True(t, ctx.BlockHeader().Time.Add(params.UnbondingTime).Equal(validator.UnbondingTime)) +// +// // unbond the validator +// keeper.unbondingToUnbonded(ctx, validator) +// +// // redelegate some of the delegation's shares +// redelegationTokens := sdk.TokensFromConsensusPower(6) +// _, err = keeper.BeginRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1], redelegationTokens.ToDec()) +// require.NoError(t, err) +// +// // no red should have been found +// red, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) +// require.False(t, found, "%v", red) +//} diff --git a/x/staking/keeper/old_delegation_test.go b/x/staking/keeper/old_delegation_test.go new file mode 100644 index 000000000000..2c83dd757774 --- /dev/null +++ b/x/staking/keeper/old_delegation_test.go @@ -0,0 +1,765 @@ +package keeper + +import ( + "testing" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/staking/types" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestUnbondingDelegationsMaxEntries(t *testing.T) { + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 1) + startTokens := sdk.TokensFromConsensusPower(10) + + bondDenom := keeper.BondDenom(ctx) + notBondedPool := keeper.GetNotBondedPool(ctx) + + err := bk.SetBalances(ctx, notBondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(bondDenom, startTokens))) + require.NoError(t, err) + keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) + + // create a validator and a delegator to that validator + validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) + + validator, issuedShares := validator.AddTokensFromDel(startTokens) + require.Equal(t, startTokens, issuedShares.RoundInt()) + + validator = TestingUpdateValidator(keeper, ctx, validator, true) + require.True(sdk.IntEq(t, startTokens, validator.BondedTokens())) + require.True(t, validator.IsBonded()) + + delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) + keeper.SetDelegation(ctx, delegation) + + maxEntries := keeper.MaxEntries(ctx) + + oldBonded := bk.GetBalance(ctx, keeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount + oldNotBonded := bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount + + // should all pass + var completionTime time.Time + for i := uint32(0); i < maxEntries; i++ { + var err error + completionTime, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], sdk.NewDec(1)) + require.NoError(t, err) + } + + newBonded := bk.GetBalance(ctx, keeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount + newNotBonded := bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, newBonded, oldBonded.SubRaw(int64(maxEntries)))) + require.True(sdk.IntEq(t, newNotBonded, oldNotBonded.AddRaw(int64(maxEntries)))) + + oldBonded = bk.GetBalance(ctx, keeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount + oldNotBonded = bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount + + // an additional unbond should fail due to max entries + _, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], sdk.NewDec(1)) + require.Error(t, err) + + newBonded = bk.GetBalance(ctx, keeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount + newNotBonded = bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount + + require.True(sdk.IntEq(t, newBonded, oldBonded)) + require.True(sdk.IntEq(t, newNotBonded, oldNotBonded)) + + // mature unbonding delegations + ctx = ctx.WithBlockTime(completionTime) + err = keeper.CompleteUnbonding(ctx, addrDels[0], addrVals[0]) + require.NoError(t, err) + + newBonded = bk.GetBalance(ctx, keeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount + newNotBonded = bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, newBonded, oldBonded)) + require.True(sdk.IntEq(t, newNotBonded, oldNotBonded.SubRaw(int64(maxEntries)))) + + oldNotBonded = bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount + + // unbonding should work again + _, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], sdk.NewDec(1)) + require.NoError(t, err) + + newBonded = bk.GetBalance(ctx, keeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount + newNotBonded = bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, newBonded, oldBonded.SubRaw(1))) + require.True(sdk.IntEq(t, newNotBonded, oldNotBonded.AddRaw(1))) +} + +// test undelegating self delegation from a validator pushing it below MinSelfDelegation +// shift it from the bonded to unbonding state and jailed +func TestUndelegateSelfDelegationBelowMinSelfDelegation(t *testing.T) { + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) + delTokens := sdk.TokensFromConsensusPower(10) + delCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), delTokens)) + + //create a validator with a self-delegation + validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) + + validator.MinSelfDelegation = delTokens + validator, issuedShares := validator.AddTokensFromDel(delTokens) + require.Equal(t, delTokens, issuedShares.RoundInt()) + + // add bonded tokens to pool for delegations + notBondedPool := keeper.GetNotBondedPool(ctx) + oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) + err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(delCoins...)) + require.NoError(t, err) + keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) + + validator = TestingUpdateValidator(keeper, ctx, validator, true) + require.True(t, validator.IsBonded()) + + selfDelegation := types.NewDelegation(sdk.AccAddress(addrVals[0].Bytes()), addrVals[0], issuedShares) + keeper.SetDelegation(ctx, selfDelegation) + + // add bonded tokens to pool for delegations + bondedPool := keeper.GetBondedPool(ctx) + oldBonded := bk.GetAllBalances(ctx, bondedPool.GetAddress()) + err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) + require.NoError(t, err) + keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) + + // create a second delegation to this validator + keeper.DeleteValidatorByPowerIndex(ctx, validator) + validator, issuedShares = validator.AddTokensFromDel(delTokens) + require.True(t, validator.IsBonded()) + require.Equal(t, delTokens, issuedShares.RoundInt()) + + // add bonded tokens to pool for delegations + oldBonded = bk.GetAllBalances(ctx, bondedPool.GetAddress()) + err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) + require.NoError(t, err) + keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) + + validator = TestingUpdateValidator(keeper, ctx, validator, true) + delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) + keeper.SetDelegation(ctx, delegation) + + val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) + _, err = keeper.Undelegate(ctx, val0AccAddr, addrVals[0], sdk.TokensFromConsensusPower(6).ToDec()) + require.NoError(t, err) + + // end block + updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 1, len(updates)) + + validator, found := keeper.GetValidator(ctx, addrVals[0]) + require.True(t, found) + require.Equal(t, sdk.TokensFromConsensusPower(14), validator.Tokens) + require.Equal(t, sdk.Unbonding, validator.Status) + require.True(t, validator.Jailed) +} + +func TestUndelegateFromUnbondingValidator(t *testing.T) { + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) + delTokens := sdk.TokensFromConsensusPower(10) + delCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), delTokens)) + + //create a validator with a self-delegation + validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) + + validator, issuedShares := validator.AddTokensFromDel(delTokens) + require.Equal(t, delTokens, issuedShares.RoundInt()) + + // add bonded tokens to pool for delegations + notBondedPool := keeper.GetNotBondedPool(ctx) + oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) + err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(delCoins...)) + require.NoError(t, err) + keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) + + validator = TestingUpdateValidator(keeper, ctx, validator, true) + require.True(t, validator.IsBonded()) + + selfDelegation := types.NewDelegation(sdk.AccAddress(addrVals[0].Bytes()), addrVals[0], issuedShares) + keeper.SetDelegation(ctx, selfDelegation) + + bondedPool := keeper.GetBondedPool(ctx) + oldBonded := bk.GetAllBalances(ctx, bondedPool.GetAddress()) + err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) + require.NoError(t, err) + keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) + + // create a second delegation to this validator + keeper.DeleteValidatorByPowerIndex(ctx, validator) + + validator, issuedShares = validator.AddTokensFromDel(delTokens) + require.Equal(t, delTokens, issuedShares.RoundInt()) + + oldBonded = bk.GetAllBalances(ctx, bondedPool.GetAddress()) + err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) + require.NoError(t, err) + keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) + + validator = TestingUpdateValidator(keeper, ctx, validator, true) + delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) + keeper.SetDelegation(ctx, delegation) + + oldBonded = bk.GetAllBalances(ctx, bondedPool.GetAddress()) + err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) + require.NoError(t, err) + keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) + + header := ctx.BlockHeader() + blockHeight := int64(10) + header.Height = blockHeight + blockTime := time.Unix(333, 0) + header.Time = blockTime + ctx = ctx.WithBlockHeader(header) + + // unbond the all self-delegation to put validator in unbonding state + val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) + _, err = keeper.Undelegate(ctx, val0AccAddr, addrVals[0], delTokens.ToDec()) + require.NoError(t, err) + + // end block + updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 1, len(updates)) + + validator, found := keeper.GetValidator(ctx, addrVals[0]) + require.True(t, found) + require.Equal(t, blockHeight, validator.UnbondingHeight) + params := keeper.GetParams(ctx) + require.True(t, blockTime.Add(params.UnbondingTime).Equal(validator.UnbondingTime)) + + blockHeight2 := int64(20) + blockTime2 := time.Unix(444, 0).UTC() + ctx = ctx.WithBlockHeight(blockHeight2) + ctx = ctx.WithBlockTime(blockTime2) + + // unbond some of the other delegation's shares + _, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], sdk.NewDec(6)) + require.NoError(t, err) + + // retrieve the unbonding delegation + ubd, found := keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) + require.True(t, found) + require.Len(t, ubd.Entries, 1) + require.True(t, ubd.Entries[0].Balance.Equal(sdk.NewInt(6))) + assert.Equal(t, blockHeight2, ubd.Entries[0].CreationHeight) + assert.True(t, blockTime2.Add(params.UnbondingTime).Equal(ubd.Entries[0].CompletionTime)) +} + +func TestUndelegateFromUnbondedValidator(t *testing.T) { + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 1) + delTokens := sdk.TokensFromConsensusPower(10) + delCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), delTokens)) + + // add bonded tokens to pool for delegations + notBondedPool := keeper.GetNotBondedPool(ctx) + oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) + err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(delCoins...)) + require.NoError(t, err) + keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) + + // create a validator with a self-delegation + validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) + + valTokens := sdk.TokensFromConsensusPower(10) + validator, issuedShares := validator.AddTokensFromDel(valTokens) + require.Equal(t, valTokens, issuedShares.RoundInt()) + validator = TestingUpdateValidator(keeper, ctx, validator, true) + require.True(t, validator.IsBonded()) + + val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) + selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) + keeper.SetDelegation(ctx, selfDelegation) + + bondedPool := keeper.GetBondedPool(ctx) + oldBonded := bk.GetAllBalances(ctx, bondedPool.GetAddress()) + err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) + require.NoError(t, err) + keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) + + // create a second delegation to this validator + keeper.DeleteValidatorByPowerIndex(ctx, validator) + validator, issuedShares = validator.AddTokensFromDel(delTokens) + require.Equal(t, delTokens, issuedShares.RoundInt()) + validator = TestingUpdateValidator(keeper, ctx, validator, true) + require.True(t, validator.IsBonded()) + delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) + keeper.SetDelegation(ctx, delegation) + + ctx = ctx.WithBlockHeight(10) + ctx = ctx.WithBlockTime(time.Unix(333, 0)) + + // unbond the all self-delegation to put validator in unbonding state + _, err = keeper.Undelegate(ctx, val0AccAddr, addrVals[0], valTokens.ToDec()) + require.NoError(t, err) + + // end block + updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 1, len(updates)) + + validator, found := keeper.GetValidator(ctx, addrVals[0]) + require.True(t, found) + require.Equal(t, ctx.BlockHeight(), validator.UnbondingHeight) + params := keeper.GetParams(ctx) + require.True(t, ctx.BlockHeader().Time.Add(params.UnbondingTime).Equal(validator.UnbondingTime)) + + // unbond the validator + ctx = ctx.WithBlockTime(validator.UnbondingTime) + keeper.UnbondAllMatureValidatorQueue(ctx) + + // Make sure validator is still in state because there is still an outstanding delegation + validator, found = keeper.GetValidator(ctx, addrVals[0]) + require.True(t, found) + require.Equal(t, validator.Status, sdk.Unbonded) + + // unbond some of the other delegation's shares + unbondTokens := sdk.TokensFromConsensusPower(6) + _, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], unbondTokens.ToDec()) + require.NoError(t, err) + + // unbond rest of the other delegation's shares + remainingTokens := delTokens.Sub(unbondTokens) + _, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], remainingTokens.ToDec()) + require.NoError(t, err) + + // now validator should now be deleted from state + validator, found = keeper.GetValidator(ctx, addrVals[0]) + require.False(t, found, "%v", validator) +} + +func TestUnbondingAllDelegationFromValidator(t *testing.T) { + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) + delTokens := sdk.TokensFromConsensusPower(10) + delCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), delTokens)) + + // add bonded tokens to pool for delegations + notBondedPool := keeper.GetNotBondedPool(ctx) + oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) + err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(delCoins...)) + require.NoError(t, err) + keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) + + //create a validator with a self-delegation + validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) + + valTokens := sdk.TokensFromConsensusPower(10) + validator, issuedShares := validator.AddTokensFromDel(valTokens) + require.Equal(t, valTokens, issuedShares.RoundInt()) + + validator = TestingUpdateValidator(keeper, ctx, validator, true) + require.True(t, validator.IsBonded()) + val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) + + selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) + keeper.SetDelegation(ctx, selfDelegation) + + // create a second delegation to this validator + keeper.DeleteValidatorByPowerIndex(ctx, validator) + validator, issuedShares = validator.AddTokensFromDel(delTokens) + require.Equal(t, delTokens, issuedShares.RoundInt()) + + bondedPool := keeper.GetBondedPool(ctx) + oldBonded := bk.GetAllBalances(ctx, bondedPool.GetAddress()) + err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) + require.NoError(t, err) + keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) + + validator = TestingUpdateValidator(keeper, ctx, validator, true) + require.True(t, validator.IsBonded()) + + delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) + keeper.SetDelegation(ctx, delegation) + + ctx = ctx.WithBlockHeight(10) + ctx = ctx.WithBlockTime(time.Unix(333, 0)) + + // unbond the all self-delegation to put validator in unbonding state + _, err = keeper.Undelegate(ctx, val0AccAddr, addrVals[0], valTokens.ToDec()) + require.NoError(t, err) + + // end block + updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 1, len(updates)) + + // unbond all the remaining delegation + _, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], delTokens.ToDec()) + require.NoError(t, err) + + // validator should still be in state and still be in unbonding state + validator, found := keeper.GetValidator(ctx, addrVals[0]) + require.True(t, found) + require.Equal(t, validator.Status, sdk.Unbonding) + + // unbond the validator + ctx = ctx.WithBlockTime(validator.UnbondingTime) + keeper.UnbondAllMatureValidatorQueue(ctx) + + // validator should now be deleted from state + _, found = keeper.GetValidator(ctx, addrVals[0]) + require.False(t, found) +} + +// Make sure that that the retrieving the delegations doesn't affect the state +func TestGetRedelegationsFromSrcValidator(t *testing.T) { + ctx, _, _, keeper, _ := CreateTestInput(t, false, 0) + + rd := types.NewRedelegation(addrDels[0], addrVals[0], addrVals[1], 0, + time.Unix(0, 0), sdk.NewInt(5), + sdk.NewDec(5)) + + // set and retrieve a record + keeper.SetRedelegation(ctx, rd) + resBond, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) + require.True(t, found) + + // get the redelegations one time + redelegations := keeper.GetRedelegationsFromSrcValidator(ctx, addrVals[0]) + require.Equal(t, 1, len(redelegations)) + require.True(t, redelegations[0].Equal(resBond)) + + // get the redelegations a second time, should be exactly the same + redelegations = keeper.GetRedelegationsFromSrcValidator(ctx, addrVals[0]) + require.Equal(t, 1, len(redelegations)) + require.True(t, redelegations[0].Equal(resBond)) +} + +// tests Get/Set/Remove/Has UnbondingDelegation +func TestRedelegation(t *testing.T) { + ctx, _, _, keeper, _ := CreateTestInput(t, false, 0) + + rd := types.NewRedelegation(addrDels[0], addrVals[0], addrVals[1], 0, + time.Unix(0, 0), sdk.NewInt(5), + sdk.NewDec(5)) + + // test shouldn't have and redelegations + has := keeper.HasReceivingRedelegation(ctx, addrDels[0], addrVals[1]) + require.False(t, has) + + // set and retrieve a record + keeper.SetRedelegation(ctx, rd) + resRed, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) + require.True(t, found) + + redelegations := keeper.GetRedelegationsFromSrcValidator(ctx, addrVals[0]) + require.Equal(t, 1, len(redelegations)) + require.True(t, redelegations[0].Equal(resRed)) + + redelegations = keeper.GetRedelegations(ctx, addrDels[0], 5) + require.Equal(t, 1, len(redelegations)) + require.True(t, redelegations[0].Equal(resRed)) + + redelegations = keeper.GetAllRedelegations(ctx, addrDels[0], nil, nil) + require.Equal(t, 1, len(redelegations)) + require.True(t, redelegations[0].Equal(resRed)) + + // check if has the redelegation + has = keeper.HasReceivingRedelegation(ctx, addrDels[0], addrVals[1]) + require.True(t, has) + + // modify a records, save, and retrieve + rd.Entries[0].SharesDst = sdk.NewDec(21) + keeper.SetRedelegation(ctx, rd) + + resRed, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) + require.True(t, found) + require.True(t, rd.Equal(resRed)) + + redelegations = keeper.GetRedelegationsFromSrcValidator(ctx, addrVals[0]) + require.Equal(t, 1, len(redelegations)) + require.True(t, redelegations[0].Equal(resRed)) + + redelegations = keeper.GetRedelegations(ctx, addrDels[0], 5) + require.Equal(t, 1, len(redelegations)) + require.True(t, redelegations[0].Equal(resRed)) + + // delete a record + keeper.RemoveRedelegation(ctx, rd) + _, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) + require.False(t, found) + + redelegations = keeper.GetRedelegations(ctx, addrDels[0], 5) + require.Equal(t, 0, len(redelegations)) + + redelegations = keeper.GetAllRedelegations(ctx, addrDels[0], nil, nil) + require.Equal(t, 0, len(redelegations)) +} + +func TestRedelegateToSameValidator(t *testing.T) { + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) + valTokens := sdk.TokensFromConsensusPower(10) + startCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), valTokens)) + + // add bonded tokens to pool for delegations + notBondedPool := keeper.GetNotBondedPool(ctx) + oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) + err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) + require.NoError(t, err) + keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) + + // create a validator with a self-delegation + validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) + validator, issuedShares := validator.AddTokensFromDel(valTokens) + require.Equal(t, valTokens, issuedShares.RoundInt()) + validator = TestingUpdateValidator(keeper, ctx, validator, true) + require.True(t, validator.IsBonded()) + + val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) + selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) + keeper.SetDelegation(ctx, selfDelegation) + + _, err = keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[0], sdk.NewDec(5)) + require.Error(t, err) +} + +func TestRedelegationMaxEntries(t *testing.T) { + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) + startTokens := sdk.TokensFromConsensusPower(20) + startCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), startTokens)) + + // add bonded tokens to pool for delegations + notBondedPool := keeper.GetNotBondedPool(ctx) + oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) + err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) + require.NoError(t, err) + keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) + + // create a validator with a self-delegation + validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) + valTokens := sdk.TokensFromConsensusPower(10) + validator, issuedShares := validator.AddTokensFromDel(valTokens) + require.Equal(t, valTokens, issuedShares.RoundInt()) + validator = TestingUpdateValidator(keeper, ctx, validator, true) + val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) + selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) + keeper.SetDelegation(ctx, selfDelegation) + + // create a second validator + validator2 := types.NewValidator(addrVals[1], PKs[1], types.Description{}) + validator2, issuedShares = validator2.AddTokensFromDel(valTokens) + require.Equal(t, valTokens, issuedShares.RoundInt()) + + validator2 = TestingUpdateValidator(keeper, ctx, validator2, true) + require.Equal(t, sdk.Bonded, validator2.Status) + + maxEntries := keeper.MaxEntries(ctx) + + // redelegations should pass + var completionTime time.Time + for i := uint32(0); i < maxEntries; i++ { + var err error + completionTime, err = keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1], sdk.NewDec(1)) + require.NoError(t, err) + } + + // an additional redelegation should fail due to max entries + _, err = keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1], sdk.NewDec(1)) + require.Error(t, err) + + // mature redelegations + ctx = ctx.WithBlockTime(completionTime) + err = keeper.CompleteRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1]) + require.NoError(t, err) + + // redelegation should work again + _, err = keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1], sdk.NewDec(1)) + require.NoError(t, err) +} + +func TestRedelegateSelfDelegation(t *testing.T) { + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) + startTokens := sdk.TokensFromConsensusPower(30) + startCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), startTokens)) + + // add bonded tokens to pool for delegations + notBondedPool := keeper.GetNotBondedPool(ctx) + oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) + err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) + require.NoError(t, err) + keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) + + //create a validator with a self-delegation + validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) + valTokens := sdk.TokensFromConsensusPower(10) + validator, issuedShares := validator.AddTokensFromDel(valTokens) + require.Equal(t, valTokens, issuedShares.RoundInt()) + + validator = TestingUpdateValidator(keeper, ctx, validator, true) + + val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) + selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) + keeper.SetDelegation(ctx, selfDelegation) + + // create a second validator + validator2 := types.NewValidator(addrVals[1], PKs[1], types.Description{}) + validator2, issuedShares = validator2.AddTokensFromDel(valTokens) + require.Equal(t, valTokens, issuedShares.RoundInt()) + validator2 = TestingUpdateValidator(keeper, ctx, validator2, true) + require.Equal(t, sdk.Bonded, validator2.Status) + + // create a second delegation to validator 1 + delTokens := sdk.TokensFromConsensusPower(10) + validator, issuedShares = validator.AddTokensFromDel(delTokens) + require.Equal(t, delTokens, issuedShares.RoundInt()) + validator = TestingUpdateValidator(keeper, ctx, validator, true) + + delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) + keeper.SetDelegation(ctx, delegation) + + _, err = keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1], delTokens.ToDec()) + require.NoError(t, err) + + // end block + updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 2, len(updates)) + + validator, found := keeper.GetValidator(ctx, addrVals[0]) + require.True(t, found) + require.Equal(t, valTokens, validator.Tokens) + require.Equal(t, sdk.Unbonding, validator.Status) +} + +func TestRedelegateFromUnbondingValidator(t *testing.T) { + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) + startTokens := sdk.TokensFromConsensusPower(30) + startCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), startTokens)) + + // add bonded tokens to pool for delegations + notBondedPool := keeper.GetNotBondedPool(ctx) + oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) + err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) + require.NoError(t, err) + keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) + + //create a validator with a self-delegation + validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) + + valTokens := sdk.TokensFromConsensusPower(10) + validator, issuedShares := validator.AddTokensFromDel(valTokens) + require.Equal(t, valTokens, issuedShares.RoundInt()) + validator = TestingUpdateValidator(keeper, ctx, validator, true) + val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) + selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) + keeper.SetDelegation(ctx, selfDelegation) + + // create a second delegation to this validator + keeper.DeleteValidatorByPowerIndex(ctx, validator) + delTokens := sdk.TokensFromConsensusPower(10) + validator, issuedShares = validator.AddTokensFromDel(delTokens) + require.Equal(t, delTokens, issuedShares.RoundInt()) + validator = TestingUpdateValidator(keeper, ctx, validator, true) + delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) + keeper.SetDelegation(ctx, delegation) + + // create a second validator + validator2 := types.NewValidator(addrVals[1], PKs[1], types.Description{}) + validator2, issuedShares = validator2.AddTokensFromDel(valTokens) + require.Equal(t, valTokens, issuedShares.RoundInt()) + validator2 = TestingUpdateValidator(keeper, ctx, validator2, true) + + header := ctx.BlockHeader() + blockHeight := int64(10) + header.Height = blockHeight + blockTime := time.Unix(333, 0) + header.Time = blockTime + ctx = ctx.WithBlockHeader(header) + + // unbond the all self-delegation to put validator in unbonding state + _, err = keeper.Undelegate(ctx, val0AccAddr, addrVals[0], delTokens.ToDec()) + require.NoError(t, err) + + // end block + updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 1, len(updates)) + + validator, found := keeper.GetValidator(ctx, addrVals[0]) + require.True(t, found) + require.Equal(t, blockHeight, validator.UnbondingHeight) + params := keeper.GetParams(ctx) + require.True(t, blockTime.Add(params.UnbondingTime).Equal(validator.UnbondingTime)) + + //change the context + header = ctx.BlockHeader() + blockHeight2 := int64(20) + header.Height = blockHeight2 + blockTime2 := time.Unix(444, 0) + header.Time = blockTime2 + ctx = ctx.WithBlockHeader(header) + + // unbond some of the other delegation's shares + redelegateTokens := sdk.TokensFromConsensusPower(6) + _, err = keeper.BeginRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1], redelegateTokens.ToDec()) + require.NoError(t, err) + + // retrieve the unbonding delegation + ubd, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) + require.True(t, found) + require.Len(t, ubd.Entries, 1) + assert.Equal(t, blockHeight, ubd.Entries[0].CreationHeight) + assert.True(t, blockTime.Add(params.UnbondingTime).Equal(ubd.Entries[0].CompletionTime)) +} + +func TestRedelegateFromUnbondedValidator(t *testing.T) { + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) + startTokens := sdk.TokensFromConsensusPower(30) + startCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), startTokens)) + + // add bonded tokens to pool for delegations + notBondedPool := keeper.GetNotBondedPool(ctx) + oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) + err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) + require.NoError(t, err) + keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) + + //create a validator with a self-delegation + validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) + + valTokens := sdk.TokensFromConsensusPower(10) + validator, issuedShares := validator.AddTokensFromDel(valTokens) + require.Equal(t, valTokens, issuedShares.RoundInt()) + validator = TestingUpdateValidator(keeper, ctx, validator, true) + val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) + selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) + keeper.SetDelegation(ctx, selfDelegation) + + // create a second delegation to this validator + keeper.DeleteValidatorByPowerIndex(ctx, validator) + delTokens := sdk.TokensFromConsensusPower(10) + validator, issuedShares = validator.AddTokensFromDel(delTokens) + require.Equal(t, delTokens, issuedShares.RoundInt()) + validator = TestingUpdateValidator(keeper, ctx, validator, true) + delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) + keeper.SetDelegation(ctx, delegation) + + // create a second validator + validator2 := types.NewValidator(addrVals[1], PKs[1], types.Description{}) + validator2, issuedShares = validator2.AddTokensFromDel(valTokens) + require.Equal(t, valTokens, issuedShares.RoundInt()) + validator2 = TestingUpdateValidator(keeper, ctx, validator2, true) + require.Equal(t, sdk.Bonded, validator2.Status) + + ctx = ctx.WithBlockHeight(10) + ctx = ctx.WithBlockTime(time.Unix(333, 0)) + + // unbond the all self-delegation to put validator in unbonding state + _, err = keeper.Undelegate(ctx, val0AccAddr, addrVals[0], delTokens.ToDec()) + require.NoError(t, err) + + // end block + updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 1, len(updates)) + + validator, found := keeper.GetValidator(ctx, addrVals[0]) + require.True(t, found) + require.Equal(t, ctx.BlockHeight(), validator.UnbondingHeight) + params := keeper.GetParams(ctx) + require.True(t, ctx.BlockHeader().Time.Add(params.UnbondingTime).Equal(validator.UnbondingTime)) + + // unbond the validator + keeper.unbondingToUnbonded(ctx, validator) + + // redelegate some of the delegation's shares + redelegationTokens := sdk.TokensFromConsensusPower(6) + _, err = keeper.BeginRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1], redelegationTokens.ToDec()) + require.NoError(t, err) + + // no red should have been found + red, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) + require.False(t, found, "%v", red) +} From 27ff208fb878dd27673721736ecce5f8d401d3f3 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Fri, 21 Feb 2020 18:34:03 +0100 Subject: [PATCH 171/529] make all test pass temporary --- x/staking/keeper/delegation.go | 6 +- x/staking/keeper/delegation_test.go | 81 +++++++++++++++---------- x/staking/keeper/keeper.go | 5 +- x/staking/keeper/old_delegation_test.go | 77 ----------------------- x/staking/keeper/querier_test.go | 10 +++ x/staking/keeper/slash.go | 2 +- 6 files changed, 66 insertions(+), 115 deletions(-) diff --git a/x/staking/keeper/delegation.go b/x/staking/keeper/delegation.go index 9524c4feffa8..8b61f8abbd4e 100644 --- a/x/staking/keeper/delegation.go +++ b/x/staking/keeper/delegation.go @@ -548,7 +548,7 @@ func (k Keeper) Delegate( } // unbond a particular delegation and perform associated store operations -func (k Keeper) unbond( +func (k Keeper) Unbond( ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress, shares sdk.Dec, ) (amount sdk.Int, err error) { @@ -654,7 +654,7 @@ func (k Keeper) Undelegate( return time.Time{}, types.ErrMaxUnbondingDelegationEntries } - returnAmount, err := k.unbond(ctx, delAddr, valAddr, sharesAmount) + returnAmount, err := k.Unbond(ctx, delAddr, valAddr, sharesAmount) if err != nil { return time.Time{}, err } @@ -751,7 +751,7 @@ func (k Keeper) BeginRedelegation( return time.Time{}, types.ErrMaxRedelegationEntries } - returnAmount, err := k.unbond(ctx, delAddr, valSrcAddr, sharesAmount) + returnAmount, err := k.Unbond(ctx, delAddr, valSrcAddr, sharesAmount) if err != nil { return time.Time{}, err } diff --git a/x/staking/keeper/delegation_test.go b/x/staking/keeper/delegation_test.go index 798716b2c2d0..4f4b5e7beabf 100644 --- a/x/staking/keeper/delegation_test.go +++ b/x/staking/keeper/delegation_test.go @@ -4,7 +4,7 @@ import ( "testing" "time" - "github.com/cosmos/cosmos-sdk/x/distribution" + "github.com/cosmos/cosmos-sdk/x/staking" "github.com/stretchr/testify/require" @@ -34,7 +34,6 @@ func TestDelegation(t *testing.T) { validators[2] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[2], true) // first add a validators[0] to delegate too - bond1to1 := types.NewDelegation(addrDels[0], addrVals[0], sdk.NewDec(9)) // check the empty keeper first @@ -181,6 +180,15 @@ func TestUnbondDelegation(t *testing.T) { app := simapp.Setup(false) ctx := app.BaseApp.NewContext(false, abci.Header{}) + codec := simapp.NewAppCodec() + app.StakingKeeper = keeper.NewKeeper( + codec.Staking, + app.GetKey(staking.StoreKey), + app.BankKeeper, + app.SupplyKeeper, + app.GetSubspace(staking.ModuleName), + ) + startTokens := sdk.TokensFromConsensusPower(10) notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) @@ -204,15 +212,11 @@ func TestUnbondDelegation(t *testing.T) { delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) app.StakingKeeper.SetDelegation(ctx, delegation) - app.DistrKeeper.SetDelegatorStartingInfo(ctx, addrVals[0], addrDels[0], distribution.DelegatorStartingInfo{}) - app.DistrKeeper.SetValidatorHistoricalRewards(ctx, addrVals[0], 18446744073709551615, distribution.ValidatorHistoricalRewards{ReferenceCount: 1}) bondTokens := sdk.TokensFromConsensusPower(6) - _, err := app.StakingKeeper.Undelegate(ctx, addrDels[0], addrVals[0], bondTokens.ToDec()) + amount, err := app.StakingKeeper.Unbond(ctx, addrDels[0], addrVals[0], bondTokens.ToDec()) require.NoError(t, err) - - notBondedPoolBalance := app.BankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), app.StakingKeeper.BondDenom(ctx)) - require.Equal(t, bondTokens, notBondedPoolBalance.Amount) // shares to be added to an unbonding delegation + require.Equal(t, bondTokens, amount) // shares to be added to an unbonding delegation delegation, found := app.StakingKeeper.GetDelegation(ctx, addrDels[0], addrVals[0]) require.True(t, found) @@ -225,15 +229,26 @@ func TestUnbondDelegation(t *testing.T) { } //func TestUnbondingDelegationsMaxEntries(t *testing.T) { -// ctx, _, bk, keeper, _ := CreateTestInput(t, false, 1) +// app := simapp.Setup(false) +// ctx := app.BaseApp.NewContext(false, abci.Header{}) +// +// codec := simapp.NewAppCodec() +// app.StakingKeeper = keeper.NewKeeper( +// codec.Staking, +// app.GetKey(staking.StoreKey), +// app.BankKeeper, +// app.SupplyKeeper, +// app.GetSubspace(staking.ModuleName), +// ) +// // startTokens := sdk.TokensFromConsensusPower(10) // -// bondDenom := keeper.BondDenom(ctx) -// notBondedPool := keeper.GetNotBondedPool(ctx) +// bondDenom := app.StakingKeeper.BondDenom(ctx) +// notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) // -// err := bk.SetBalances(ctx, notBondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(bondDenom, startTokens))) +// err := app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(bondDenom, startTokens))) // require.NoError(t, err) -// keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) +// app.SupplyKeeper.SetModuleAccount(ctx, notBondedPool) // // // create a validator and a delegator to that validator // validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) @@ -241,62 +256,62 @@ func TestUnbondDelegation(t *testing.T) { // validator, issuedShares := validator.AddTokensFromDel(startTokens) // require.Equal(t, startTokens, issuedShares.RoundInt()) // -// validator = TestingUpdateValidator(keeper, ctx, validator, true) +// validator = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator, true) // require.True(sdk.IntEq(t, startTokens, validator.BondedTokens())) // require.True(t, validator.IsBonded()) // // delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) -// keeper.SetDelegation(ctx, delegation) +// app.StakingKeeper.SetDelegation(ctx, delegation) // -// maxEntries := keeper.MaxEntries(ctx) +// maxEntries := app.StakingKeeper.MaxEntries(ctx) // -// oldBonded := bk.GetBalance(ctx, keeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount -// oldNotBonded := bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount +// oldBonded := app.BankKeeper.GetBalance(ctx, app.StakingKeeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount +// oldNotBonded := app.BankKeeper.GetBalance(ctx, app.StakingKeeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount // // // should all pass // var completionTime time.Time // for i := uint32(0); i < maxEntries; i++ { // var err error -// completionTime, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], sdk.NewDec(1)) +// completionTime, err = app.StakingKeeper.Undelegate(ctx, addrDels[0], addrVals[0], sdk.NewDec(1)) // require.NoError(t, err) // } // -// newBonded := bk.GetBalance(ctx, keeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount -// newNotBonded := bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount +// newBonded := app.BankKeeper.GetBalance(ctx, app.StakingKeeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount +// newNotBonded := app.BankKeeper.GetBalance(ctx, app.StakingKeeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount // require.True(sdk.IntEq(t, newBonded, oldBonded.SubRaw(int64(maxEntries)))) // require.True(sdk.IntEq(t, newNotBonded, oldNotBonded.AddRaw(int64(maxEntries)))) // -// oldBonded = bk.GetBalance(ctx, keeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount -// oldNotBonded = bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount +// oldBonded = app.BankKeeper.GetBalance(ctx, app.StakingKeeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount +// oldNotBonded = app.BankKeeper.GetBalance(ctx, app.StakingKeeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount // // // an additional unbond should fail due to max entries -// _, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], sdk.NewDec(1)) +// _, err = app.StakingKeeper.Undelegate(ctx, addrDels[0], addrVals[0], sdk.NewDec(1)) // require.Error(t, err) // -// newBonded = bk.GetBalance(ctx, keeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount -// newNotBonded = bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount +// newBonded = app.BankKeeper.GetBalance(ctx, app.StakingKeeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount +// newNotBonded = app.BankKeeper.GetBalance(ctx, app.StakingKeeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount // // require.True(sdk.IntEq(t, newBonded, oldBonded)) // require.True(sdk.IntEq(t, newNotBonded, oldNotBonded)) // // // mature unbonding delegations // ctx = ctx.WithBlockTime(completionTime) -// err = keeper.CompleteUnbonding(ctx, addrDels[0], addrVals[0]) +// err = app.StakingKeeper.CompleteUnbonding(ctx, addrDels[0], addrVals[0]) // require.NoError(t, err) // -// newBonded = bk.GetBalance(ctx, keeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount -// newNotBonded = bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount +// newBonded = app.BankKeeper.GetBalance(ctx, app.StakingKeeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount +// newNotBonded = app.BankKeeper.GetBalance(ctx, app.StakingKeeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount // require.True(sdk.IntEq(t, newBonded, oldBonded)) // require.True(sdk.IntEq(t, newNotBonded, oldNotBonded.SubRaw(int64(maxEntries)))) // -// oldNotBonded = bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount +// oldNotBonded = app.BankKeeper.GetBalance(ctx, app.StakingKeeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount // // // unbonding should work again -// _, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], sdk.NewDec(1)) +// _, err = app.StakingKeeper.Undelegate(ctx, addrDels[0], addrVals[0], sdk.NewDec(1)) // require.NoError(t, err) // -// newBonded = bk.GetBalance(ctx, keeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount -// newNotBonded = bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount +// newBonded = app.BankKeeper.GetBalance(ctx, app.StakingKeeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount +// newNotBonded = app.BankKeeper.GetBalance(ctx, app.StakingKeeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount // require.True(sdk.IntEq(t, newBonded, oldBonded.SubRaw(1))) // require.True(sdk.IntEq(t, newNotBonded, oldNotBonded.AddRaw(1))) //} diff --git a/x/staking/keeper/keeper.go b/x/staking/keeper/keeper.go index ef7aab43557f..80fbf6191999 100644 --- a/x/staking/keeper/keeper.go +++ b/x/staking/keeper/keeper.go @@ -36,6 +36,9 @@ type Keeper struct { func NewKeeper( cdc codec.Marshaler, key sdk.StoreKey, bk types.BankKeeper, sk types.SupplyKeeper, ps params.Subspace, ) Keeper { + if !ps.HasKeyTable() { + ps = ps.WithKeyTable(ParamKeyTable()) + } // ensure bonded and not bonded module accounts are set if addr := sk.GetModuleAddress(types.BondedPoolName); addr == nil { @@ -51,7 +54,7 @@ func NewKeeper( cdc: cdc, bankKeeper: bk, supplyKeeper: sk, - paramstore: ps.WithKeyTable(ParamKeyTable()), + paramstore: ps, hooks: nil, validatorCache: make(map[string]cachedValidator, aminoCacheSize), validatorCacheList: list.New(), diff --git a/x/staking/keeper/old_delegation_test.go b/x/staking/keeper/old_delegation_test.go index 2c83dd757774..2e22045f707b 100644 --- a/x/staking/keeper/old_delegation_test.go +++ b/x/staking/keeper/old_delegation_test.go @@ -11,83 +11,6 @@ import ( "github.com/stretchr/testify/require" ) -func TestUnbondingDelegationsMaxEntries(t *testing.T) { - ctx, _, bk, keeper, _ := CreateTestInput(t, false, 1) - startTokens := sdk.TokensFromConsensusPower(10) - - bondDenom := keeper.BondDenom(ctx) - notBondedPool := keeper.GetNotBondedPool(ctx) - - err := bk.SetBalances(ctx, notBondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(bondDenom, startTokens))) - require.NoError(t, err) - keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) - - // create a validator and a delegator to that validator - validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) - - validator, issuedShares := validator.AddTokensFromDel(startTokens) - require.Equal(t, startTokens, issuedShares.RoundInt()) - - validator = TestingUpdateValidator(keeper, ctx, validator, true) - require.True(sdk.IntEq(t, startTokens, validator.BondedTokens())) - require.True(t, validator.IsBonded()) - - delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) - keeper.SetDelegation(ctx, delegation) - - maxEntries := keeper.MaxEntries(ctx) - - oldBonded := bk.GetBalance(ctx, keeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount - oldNotBonded := bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount - - // should all pass - var completionTime time.Time - for i := uint32(0); i < maxEntries; i++ { - var err error - completionTime, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], sdk.NewDec(1)) - require.NoError(t, err) - } - - newBonded := bk.GetBalance(ctx, keeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount - newNotBonded := bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount - require.True(sdk.IntEq(t, newBonded, oldBonded.SubRaw(int64(maxEntries)))) - require.True(sdk.IntEq(t, newNotBonded, oldNotBonded.AddRaw(int64(maxEntries)))) - - oldBonded = bk.GetBalance(ctx, keeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount - oldNotBonded = bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount - - // an additional unbond should fail due to max entries - _, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], sdk.NewDec(1)) - require.Error(t, err) - - newBonded = bk.GetBalance(ctx, keeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount - newNotBonded = bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount - - require.True(sdk.IntEq(t, newBonded, oldBonded)) - require.True(sdk.IntEq(t, newNotBonded, oldNotBonded)) - - // mature unbonding delegations - ctx = ctx.WithBlockTime(completionTime) - err = keeper.CompleteUnbonding(ctx, addrDels[0], addrVals[0]) - require.NoError(t, err) - - newBonded = bk.GetBalance(ctx, keeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount - newNotBonded = bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount - require.True(sdk.IntEq(t, newBonded, oldBonded)) - require.True(sdk.IntEq(t, newNotBonded, oldNotBonded.SubRaw(int64(maxEntries)))) - - oldNotBonded = bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount - - // unbonding should work again - _, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], sdk.NewDec(1)) - require.NoError(t, err) - - newBonded = bk.GetBalance(ctx, keeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount - newNotBonded = bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount - require.True(sdk.IntEq(t, newBonded, oldBonded.SubRaw(1))) - require.True(sdk.IntEq(t, newNotBonded, oldNotBonded.AddRaw(1))) -} - // test undelegating self delegation from a validator pushing it below MinSelfDelegation // shift it from the bonded to unbonding state and jailed func TestUndelegateSelfDelegationBelowMinSelfDelegation(t *testing.T) { diff --git a/x/staking/keeper/querier_test.go b/x/staking/keeper/querier_test.go index 19a260d531da..90269a0bc926 100644 --- a/x/staking/keeper/querier_test.go +++ b/x/staking/keeper/querier_test.go @@ -13,6 +13,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/distribution" "github.com/cosmos/cosmos-sdk/x/staking" + "github.com/cosmos/cosmos-sdk/x/staking/keeper" "github.com/cosmos/cosmos-sdk/x/staking/types" ) @@ -211,6 +212,15 @@ func TestQueryDelegation(t *testing.T) { params := app.StakingKeeper.GetParams(ctx) querier := staking.NewQuerier(app.StakingKeeper) + codec := simapp.NewAppCodec() + app.StakingKeeper = keeper.NewKeeper( + codec.Staking, + app.GetKey(staking.StoreKey), + app.BankKeeper, + app.SupplyKeeper, + app.GetSubspace(staking.ModuleName), + ) + addrs := simapp.AddTestAddrs(app, ctx, 2, sdk.TokensFromConsensusPower(10000)) addrAcc1, addrAcc2 := addrs[0], addrs[1] addrVal1, addrVal2 := sdk.ValAddress(addrAcc1), sdk.ValAddress(addrAcc2) diff --git a/x/staking/keeper/slash.go b/x/staking/keeper/slash.go index 8841d3e8e4bd..76db0c8e99ba 100644 --- a/x/staking/keeper/slash.go +++ b/x/staking/keeper/slash.go @@ -254,7 +254,7 @@ func (k Keeper) slashRedelegation(ctx sdk.Context, srcValidator types.Validator, sharesToUnbond = delegation.Shares } - tokensToBurn, err := k.unbond(ctx, redelegation.DelegatorAddress, redelegation.ValidatorDstAddress, sharesToUnbond) + tokensToBurn, err := k.Unbond(ctx, redelegation.DelegatorAddress, redelegation.ValidatorDstAddress, sharesToUnbond) if err != nil { panic(fmt.Errorf("error unbonding delegator: %v", err)) } From 594e0a6bfa00370a85d9f04a453b1c5f189b9f15 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Fri, 21 Feb 2020 18:38:28 +0100 Subject: [PATCH 172/529] avoid usage of historicals --- x/staking/keeper/querier_test.go | 34 +++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/x/staking/keeper/querier_test.go b/x/staking/keeper/querier_test.go index 90269a0bc926..9be64f1ed001 100644 --- a/x/staking/keeper/querier_test.go +++ b/x/staking/keeper/querier_test.go @@ -11,7 +11,6 @@ import ( "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/distribution" "github.com/cosmos/cosmos-sdk/x/staking" "github.com/cosmos/cosmos-sdk/x/staking/keeper" "github.com/cosmos/cosmos-sdk/x/staking/types" @@ -143,6 +142,15 @@ func TestQueryValidators(t *testing.T) { params := app.StakingKeeper.GetParams(ctx) querier := staking.NewQuerier(app.StakingKeeper) + codec := simapp.NewAppCodec() + app.StakingKeeper = keeper.NewKeeper( + codec.Staking, + app.GetKey(staking.StoreKey), + app.BankKeeper, + app.SupplyKeeper, + app.GetSubspace(staking.ModuleName), + ) + addrs := simapp.AddTestAddrs(app, ctx, 500, sdk.TokensFromConsensusPower(10000)) // Create Validators @@ -232,12 +240,10 @@ func TestQueryDelegation(t *testing.T) { val1 := types.NewValidator(addrVal1, pk1, types.Description{}) app.StakingKeeper.SetValidator(ctx, val1) app.StakingKeeper.SetValidatorByPowerIndex(ctx, val1) - app.DistrKeeper.SetValidatorHistoricalRewards(ctx, addrVal1, 18446744073709551615, distribution.ValidatorHistoricalRewards{ReferenceCount: 1}) val2 := types.NewValidator(addrVal2, pk2, types.Description{}) app.StakingKeeper.SetValidator(ctx, val2) app.StakingKeeper.SetValidatorByPowerIndex(ctx, val2) - app.DistrKeeper.SetValidatorHistoricalRewards(ctx, addrVal2, 18446744073709551615, distribution.ValidatorHistoricalRewards{ReferenceCount: 1}) delTokens := sdk.TokensFromConsensusPower(20) _, err := app.StakingKeeper.Delegate(ctx, addrAcc2, delTokens, sdk.Unbonded, val1, true) @@ -344,7 +350,6 @@ func TestQueryDelegation(t *testing.T) { require.Error(t, err) // Query validator delegations - bz, errRes = cdc.MarshalJSON(types.NewQueryValidatorParams(addrVal1)) require.NoError(t, errRes) @@ -452,6 +457,15 @@ func TestQueryRedelegations(t *testing.T) { ctx := app.BaseApp.NewContext(false, abci.Header{}) querier := staking.NewQuerier(app.StakingKeeper) + codec := simapp.NewAppCodec() + app.StakingKeeper = keeper.NewKeeper( + codec.Staking, + app.GetKey(staking.StoreKey), + app.BankKeeper, + app.SupplyKeeper, + app.GetSubspace(staking.ModuleName), + ) + addrs := simapp.AddTestAddrs(app, ctx, 2, sdk.TokensFromConsensusPower(10000)) addrAcc1, addrAcc2 := addrs[0], addrs[1] addrVal1, addrVal2 := sdk.ValAddress(addrAcc1), sdk.ValAddress(addrAcc2) @@ -461,8 +475,6 @@ func TestQueryRedelegations(t *testing.T) { val2 := types.NewValidator(addrVal2, PKs[1], types.Description{}) app.StakingKeeper.SetValidator(ctx, val1) app.StakingKeeper.SetValidator(ctx, val2) - app.DistrKeeper.SetValidatorHistoricalRewards(ctx, addrVal1, 18446744073709551615, distribution.ValidatorHistoricalRewards{ReferenceCount: 1}) - app.DistrKeeper.SetValidatorHistoricalRewards(ctx, addrVal2, 18446744073709551615, distribution.ValidatorHistoricalRewards{ReferenceCount: 1}) delAmount := sdk.TokensFromConsensusPower(100) app.StakingKeeper.Delegate(ctx, addrAcc2, delAmount, sdk.Unbonded, val1, true) @@ -525,6 +537,15 @@ func TestQueryUnbondingDelegation(t *testing.T) { ctx := app.BaseApp.NewContext(false, abci.Header{}) querier := staking.NewQuerier(app.StakingKeeper) + codec := simapp.NewAppCodec() + app.StakingKeeper = keeper.NewKeeper( + codec.Staking, + app.GetKey(staking.StoreKey), + app.BankKeeper, + app.SupplyKeeper, + app.GetSubspace(staking.ModuleName), + ) + addrs := simapp.AddTestAddrs(app, ctx, 2, sdk.TokensFromConsensusPower(10000)) addrAcc1, addrAcc2 := addrs[0], addrs[1] addrVal1 := sdk.ValAddress(addrAcc1) @@ -532,7 +553,6 @@ func TestQueryUnbondingDelegation(t *testing.T) { // Create Validators and Delegation val1 := types.NewValidator(addrVal1, PKs[0], types.Description{}) app.StakingKeeper.SetValidator(ctx, val1) - app.DistrKeeper.SetValidatorHistoricalRewards(ctx, addrVal1, 18446744073709551615, distribution.ValidatorHistoricalRewards{ReferenceCount: 1}) // delegate delAmount := sdk.TokensFromConsensusPower(100) From e155b1083df117f64775fdac88508705207859bc Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Fri, 21 Feb 2020 18:49:54 +0100 Subject: [PATCH 173/529] refactor creation of the simapp --- x/staking/keeper/querier_test.go | 67 ++++------------------------ x/staking/keeper/test_common_test.go | 24 ++++++++++ 2 files changed, 32 insertions(+), 59 deletions(-) diff --git a/x/staking/keeper/querier_test.go b/x/staking/keeper/querier_test.go index 9be64f1ed001..09a19b894f4f 100644 --- a/x/staking/keeper/querier_test.go +++ b/x/staking/keeper/querier_test.go @@ -8,18 +8,15 @@ import ( abci "github.com/tendermint/tendermint/abci/types" - "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/staking" - "github.com/cosmos/cosmos-sdk/x/staking/keeper" "github.com/cosmos/cosmos-sdk/x/staking/types" ) func TestNewQuerier(t *testing.T) { - cdc := codec.New() - app := simapp.Setup(false) - ctx := app.BaseApp.NewContext(false, abci.Header{}) + cdc, app, ctx := getBaseSimappWithCustomKeeper() + addrs := simapp.AddTestAddrs(app, ctx, 500, sdk.NewInt(10000)) _, addrAcc2 := addrs[0], addrs[1] addrVal1, _ := sdk.ValAddress(addrs[0]), sdk.ValAddress(addrs[1]) @@ -109,9 +106,7 @@ func TestNewQuerier(t *testing.T) { } func TestQueryParametersPool(t *testing.T) { - cdc := codec.New() - app := simapp.Setup(false) - ctx := app.BaseApp.NewContext(false, abci.Header{}) + cdc, app, ctx := getBaseSimappWithCustomKeeper() querier := staking.NewQuerier(app.StakingKeeper) bondDenom := sdk.DefaultBondDenom @@ -136,21 +131,10 @@ func TestQueryParametersPool(t *testing.T) { } func TestQueryValidators(t *testing.T) { - cdc := codec.New() - app := simapp.Setup(false) - ctx := app.BaseApp.NewContext(false, abci.Header{}) + cdc, app, ctx := getBaseSimappWithCustomKeeper() params := app.StakingKeeper.GetParams(ctx) querier := staking.NewQuerier(app.StakingKeeper) - codec := simapp.NewAppCodec() - app.StakingKeeper = keeper.NewKeeper( - codec.Staking, - app.GetKey(staking.StoreKey), - app.BankKeeper, - app.SupplyKeeper, - app.GetSubspace(staking.ModuleName), - ) - addrs := simapp.AddTestAddrs(app, ctx, 500, sdk.TokensFromConsensusPower(10000)) // Create Validators @@ -214,21 +198,10 @@ func TestQueryValidators(t *testing.T) { } func TestQueryDelegation(t *testing.T) { - cdc := codec.New() - app := simapp.Setup(false) - ctx := app.BaseApp.NewContext(false, abci.Header{}) + cdc, app, ctx := getBaseSimappWithCustomKeeper() params := app.StakingKeeper.GetParams(ctx) querier := staking.NewQuerier(app.StakingKeeper) - codec := simapp.NewAppCodec() - app.StakingKeeper = keeper.NewKeeper( - codec.Staking, - app.GetKey(staking.StoreKey), - app.BankKeeper, - app.SupplyKeeper, - app.GetSubspace(staking.ModuleName), - ) - addrs := simapp.AddTestAddrs(app, ctx, 2, sdk.TokensFromConsensusPower(10000)) addrAcc1, addrAcc2 := addrs[0], addrs[1] addrVal1, addrVal2 := sdk.ValAddress(addrAcc1), sdk.ValAddress(addrAcc2) @@ -452,20 +425,9 @@ func TestQueryDelegation(t *testing.T) { } func TestQueryRedelegations(t *testing.T) { - cdc := codec.New() - app := simapp.Setup(false) - ctx := app.BaseApp.NewContext(false, abci.Header{}) + cdc, app, ctx := getBaseSimappWithCustomKeeper() querier := staking.NewQuerier(app.StakingKeeper) - codec := simapp.NewAppCodec() - app.StakingKeeper = keeper.NewKeeper( - codec.Staking, - app.GetKey(staking.StoreKey), - app.BankKeeper, - app.SupplyKeeper, - app.GetSubspace(staking.ModuleName), - ) - addrs := simapp.AddTestAddrs(app, ctx, 2, sdk.TokensFromConsensusPower(10000)) addrAcc1, addrAcc2 := addrs[0], addrs[1] addrVal1, addrVal2 := sdk.ValAddress(addrAcc1), sdk.ValAddress(addrAcc2) @@ -532,20 +494,9 @@ func TestQueryRedelegations(t *testing.T) { } func TestQueryUnbondingDelegation(t *testing.T) { - cdc := codec.New() - app := simapp.Setup(false) - ctx := app.BaseApp.NewContext(false, abci.Header{}) + cdc, app, ctx := getBaseSimappWithCustomKeeper() querier := staking.NewQuerier(app.StakingKeeper) - codec := simapp.NewAppCodec() - app.StakingKeeper = keeper.NewKeeper( - codec.Staking, - app.GetKey(staking.StoreKey), - app.BankKeeper, - app.SupplyKeeper, - app.GetSubspace(staking.ModuleName), - ) - addrs := simapp.AddTestAddrs(app, ctx, 2, sdk.TokensFromConsensusPower(10000)) addrAcc1, addrAcc2 := addrs[0], addrs[1] addrVal1 := sdk.ValAddress(addrAcc1) @@ -638,9 +589,7 @@ func TestQueryUnbondingDelegation(t *testing.T) { } func TestQueryHistoricalInfo(t *testing.T) { - cdc := codec.New() - app := simapp.Setup(false) - ctx := app.BaseApp.NewContext(false, abci.Header{}) + cdc, app, ctx := getBaseSimappWithCustomKeeper() querier := staking.NewQuerier(app.StakingKeeper) addrs := simapp.AddTestAddrs(app, ctx, 2, sdk.TokensFromConsensusPower(10000)) diff --git a/x/staking/keeper/test_common_test.go b/x/staking/keeper/test_common_test.go index 936c028148d2..0f2ceb58a210 100644 --- a/x/staking/keeper/test_common_test.go +++ b/x/staking/keeper/test_common_test.go @@ -5,6 +5,12 @@ import ( "encoding/hex" "strconv" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/simapp" + "github.com/cosmos/cosmos-sdk/x/staking" + "github.com/cosmos/cosmos-sdk/x/staking/keeper" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/ed25519" @@ -96,3 +102,21 @@ func CreateTestAddr(addr string, bech string) sdk.AccAddress { return res } + +// getBaseSimappWithCustomKeeper Returns a simapp with custom StakingKeeper +// to avoid messing with the hooks. +func getBaseSimappWithCustomKeeper() (*codec.Codec, *simapp.SimApp, sdk.Context) { + cdc := codec.New() + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + app.StakingKeeper = keeper.NewKeeper( + simapp.NewAppCodec().Staking, + app.GetKey(staking.StoreKey), + app.BankKeeper, + app.SupplyKeeper, + app.GetSubspace(staking.ModuleName), + ) + + return cdc, app, ctx +} From 01aaf8446d3628ee99a11ae9897c29d88c9edea1 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Fri, 21 Feb 2020 18:54:10 +0100 Subject: [PATCH 174/529] refactor creation of simapp --- x/staking/keeper/delegation_test.go | 11 +++-------- x/staking/keeper/test_common_test.go | 9 ++++----- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/x/staking/keeper/delegation_test.go b/x/staking/keeper/delegation_test.go index 4f4b5e7beabf..31886eac1e0f 100644 --- a/x/staking/keeper/delegation_test.go +++ b/x/staking/keeper/delegation_test.go @@ -9,8 +9,6 @@ import ( "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/simapp" - abci "github.com/tendermint/tendermint/abci/types" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/staking/keeper" "github.com/cosmos/cosmos-sdk/x/staking/types" @@ -18,8 +16,7 @@ import ( // tests GetDelegation, GetDelegatorDelegations, SetDelegation, RemoveDelegation, GetDelegatorDelegations func TestDelegation(t *testing.T) { - app := simapp.Setup(false) - ctx := app.BaseApp.NewContext(false, abci.Header{}) + _, app, ctx := getBaseSimappWithCustomKeeper() //construct the validators amts := []sdk.Int{sdk.NewInt(9), sdk.NewInt(8), sdk.NewInt(7)} @@ -133,8 +130,7 @@ func TestDelegation(t *testing.T) { // tests Get/Set/Remove UnbondingDelegation func TestUnbondingDelegation(t *testing.T) { - app := simapp.Setup(false) - ctx := app.BaseApp.NewContext(false, abci.Header{}) + _, app, ctx := getBaseSimappWithCustomKeeper() ubd := types.NewUnbondingDelegation( addrDels[0], @@ -177,8 +173,7 @@ func TestUnbondingDelegation(t *testing.T) { } func TestUnbondDelegation(t *testing.T) { - app := simapp.Setup(false) - ctx := app.BaseApp.NewContext(false, abci.Header{}) + _, app, ctx := getBaseSimappWithCustomKeeper() codec := simapp.NewAppCodec() app.StakingKeeper = keeper.NewKeeper( diff --git a/x/staking/keeper/test_common_test.go b/x/staking/keeper/test_common_test.go index 0f2ceb58a210..7c6cf8f0c2f9 100644 --- a/x/staking/keeper/test_common_test.go +++ b/x/staking/keeper/test_common_test.go @@ -5,16 +5,15 @@ import ( "encoding/hex" "strconv" + "github.com/tendermint/tendermint/crypto" + "github.com/tendermint/tendermint/crypto/ed25519" + "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/simapp" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/staking" "github.com/cosmos/cosmos-sdk/x/staking/keeper" abci "github.com/tendermint/tendermint/abci/types" - - "github.com/tendermint/tendermint/crypto" - "github.com/tendermint/tendermint/crypto/ed25519" - - sdk "github.com/cosmos/cosmos-sdk/types" ) var ( From 89785765e049e6b8452108051aab765078dc290d Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Fri, 21 Feb 2020 19:19:57 +0100 Subject: [PATCH 175/529] comment before creating new way to generate accounts --- x/staking/keeper/delegation_test.go | 227 ++++++++++++++-------------- 1 file changed, 114 insertions(+), 113 deletions(-) diff --git a/x/staking/keeper/delegation_test.go b/x/staking/keeper/delegation_test.go index 31886eac1e0f..45879644be66 100644 --- a/x/staking/keeper/delegation_test.go +++ b/x/staking/keeper/delegation_test.go @@ -15,119 +15,120 @@ import ( ) // tests GetDelegation, GetDelegatorDelegations, SetDelegation, RemoveDelegation, GetDelegatorDelegations -func TestDelegation(t *testing.T) { - _, app, ctx := getBaseSimappWithCustomKeeper() - - //construct the validators - amts := []sdk.Int{sdk.NewInt(9), sdk.NewInt(8), sdk.NewInt(7)} - var validators [3]types.Validator - for i, amt := range amts { - validators[i] = types.NewValidator(addrVals[i], PKs[i], types.Description{}) - validators[i], _ = validators[i].AddTokensFromDel(amt) - } - - validators[0] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[0], true) - validators[1] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[1], true) - validators[2] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[2], true) - - // first add a validators[0] to delegate too - bond1to1 := types.NewDelegation(addrDels[0], addrVals[0], sdk.NewDec(9)) - - // check the empty keeper first - _, found := app.StakingKeeper.GetDelegation(ctx, addrDels[0], addrVals[0]) - require.False(t, found) - - // set and retrieve a record - app.StakingKeeper.SetDelegation(ctx, bond1to1) - resBond, found := app.StakingKeeper.GetDelegation(ctx, addrDels[0], addrVals[0]) - require.True(t, found) - require.True(t, bond1to1.Equal(resBond)) - - // modify a records, save, and retrieve - bond1to1.Shares = sdk.NewDec(99) - app.StakingKeeper.SetDelegation(ctx, bond1to1) - resBond, found = app.StakingKeeper.GetDelegation(ctx, addrDels[0], addrVals[0]) - require.True(t, found) - require.True(t, bond1to1.Equal(resBond)) - - // add some more records - bond1to2 := types.NewDelegation(addrDels[0], addrVals[1], sdk.NewDec(9)) - bond1to3 := types.NewDelegation(addrDels[0], addrVals[2], sdk.NewDec(9)) - bond2to1 := types.NewDelegation(addrDels[1], addrVals[0], sdk.NewDec(9)) - bond2to2 := types.NewDelegation(addrDels[1], addrVals[1], sdk.NewDec(9)) - bond2to3 := types.NewDelegation(addrDels[1], addrVals[2], sdk.NewDec(9)) - app.StakingKeeper.SetDelegation(ctx, bond1to2) - app.StakingKeeper.SetDelegation(ctx, bond1to3) - app.StakingKeeper.SetDelegation(ctx, bond2to1) - app.StakingKeeper.SetDelegation(ctx, bond2to2) - app.StakingKeeper.SetDelegation(ctx, bond2to3) - - // test all bond retrieve capabilities - resBonds := app.StakingKeeper.GetDelegatorDelegations(ctx, addrDels[0], 5) - require.Equal(t, 3, len(resBonds)) - require.True(t, bond1to1.Equal(resBonds[0])) - require.True(t, bond1to2.Equal(resBonds[1])) - require.True(t, bond1to3.Equal(resBonds[2])) - resBonds = app.StakingKeeper.GetAllDelegatorDelegations(ctx, addrDels[0]) - require.Equal(t, 3, len(resBonds)) - resBonds = app.StakingKeeper.GetDelegatorDelegations(ctx, addrDels[0], 2) - require.Equal(t, 2, len(resBonds)) - resBonds = app.StakingKeeper.GetDelegatorDelegations(ctx, addrDels[1], 5) - require.Equal(t, 3, len(resBonds)) - require.True(t, bond2to1.Equal(resBonds[0])) - require.True(t, bond2to2.Equal(resBonds[1])) - require.True(t, bond2to3.Equal(resBonds[2])) - allBonds := app.StakingKeeper.GetAllDelegations(ctx) - require.Equal(t, 6, len(allBonds)) - require.True(t, bond1to1.Equal(allBonds[0])) - require.True(t, bond1to2.Equal(allBonds[1])) - require.True(t, bond1to3.Equal(allBonds[2])) - require.True(t, bond2to1.Equal(allBonds[3])) - require.True(t, bond2to2.Equal(allBonds[4])) - require.True(t, bond2to3.Equal(allBonds[5])) - - resVals := app.StakingKeeper.GetDelegatorValidators(ctx, addrDels[0], 3) - require.Equal(t, 3, len(resVals)) - resVals = app.StakingKeeper.GetDelegatorValidators(ctx, addrDels[1], 4) - require.Equal(t, 3, len(resVals)) - - for i := 0; i < 3; i++ { - - resVal, err := app.StakingKeeper.GetDelegatorValidator(ctx, addrDels[0], addrVals[i]) - require.Nil(t, err) - require.Equal(t, addrVals[i], resVal.GetOperator()) - - resVal, err = app.StakingKeeper.GetDelegatorValidator(ctx, addrDels[1], addrVals[i]) - require.Nil(t, err) - require.Equal(t, addrVals[i], resVal.GetOperator()) - - resDels := app.StakingKeeper.GetValidatorDelegations(ctx, addrVals[i]) - require.Len(t, resDels, 2) - } - - // delete a record - app.StakingKeeper.RemoveDelegation(ctx, bond2to3) - _, found = app.StakingKeeper.GetDelegation(ctx, addrDels[1], addrVals[2]) - require.False(t, found) - resBonds = app.StakingKeeper.GetDelegatorDelegations(ctx, addrDels[1], 5) - require.Equal(t, 2, len(resBonds)) - require.True(t, bond2to1.Equal(resBonds[0])) - require.True(t, bond2to2.Equal(resBonds[1])) - - resBonds = app.StakingKeeper.GetAllDelegatorDelegations(ctx, addrDels[1]) - require.Equal(t, 2, len(resBonds)) - - // delete all the records from delegator 2 - app.StakingKeeper.RemoveDelegation(ctx, bond2to1) - app.StakingKeeper.RemoveDelegation(ctx, bond2to2) - _, found = app.StakingKeeper.GetDelegation(ctx, addrDels[1], addrVals[0]) - require.False(t, found) - _, found = app.StakingKeeper.GetDelegation(ctx, addrDels[1], addrVals[1]) - require.False(t, found) - resBonds = app.StakingKeeper.GetDelegatorDelegations(ctx, addrDels[1], 5) - require.Equal(t, 0, len(resBonds)) -} - +//func TestDelegation(t *testing.T) { +// _, app, ctx := getBaseSimappWithCustomKeeper() +// +// addrs := simapp.AddTestAddrs(app, ctx, 3, sdk.NewInt(10000)) +// +// //construct the validators +// amts := []sdk.Int{sdk.NewInt(9), sdk.NewInt(8), sdk.NewInt(7)} +// var validators [3]types.Validator +// for i, amt := range amts { +// validators[i] = types.NewValidator(sdk.ValAddress(addrs[i]), PKs[i], types.Description{}) +// validators[i], _ = validators[i].AddTokensFromDel(amt) +// } +// +// validators[0] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[0], true) +// validators[1] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[1], true) +// validators[2] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[2], true) +// +// // first add a validators[0] to delegate too +// bond1to1 := types.NewDelegation(addrs[0], sdk.ValAddress(addrs[0]), sdk.NewDec(9)) +// +// // check the empty keeper first +// _, found := app.StakingKeeper.GetDelegation(ctx, addrs[0], sdk.ValAddress(addrs[0])) +// require.False(t, found) +// +// // set and retrieve a record +// app.StakingKeeper.SetDelegation(ctx, bond1to1) +// resBond, found := app.StakingKeeper.GetDelegation(ctx, addrs[0], sdk.ValAddress(addrs[0])) +// require.True(t, found) +// require.True(t, bond1to1.Equal(resBond)) +// +// // modify a records, save, and retrieve +// bond1to1.Shares = sdk.NewDec(99) +// app.StakingKeeper.SetDelegation(ctx, bond1to1) +// resBond, found = app.StakingKeeper.GetDelegation(ctx, addrs[0], sdk.ValAddress(addrs[0])) +// require.True(t, found) +// require.True(t, bond1to1.Equal(resBond)) +// +// // add some more records +// bond1to2 := types.NewDelegation(addrs[0], sdk.ValAddress(addrs[1]), sdk.NewDec(9)) +// bond1to3 := types.NewDelegation(addrs[0], sdk.ValAddress(addrs[2]), sdk.NewDec(9)) +// bond2to1 := types.NewDelegation(addrs[1], sdk.ValAddress(addrs[0]), sdk.NewDec(9)) +// bond2to2 := types.NewDelegation(addrs[1], sdk.ValAddress(addrs[1]), sdk.NewDec(9)) +// bond2to3 := types.NewDelegation(addrs[1], sdk.ValAddress(addrs[2]), sdk.NewDec(9)) +// app.StakingKeeper.SetDelegation(ctx, bond1to2) +// app.StakingKeeper.SetDelegation(ctx, bond1to3) +// app.StakingKeeper.SetDelegation(ctx, bond2to1) +// app.StakingKeeper.SetDelegation(ctx, bond2to2) +// app.StakingKeeper.SetDelegation(ctx, bond2to3) +// +// // test all bond retrieve capabilities +// resBonds := app.StakingKeeper.GetDelegatorDelegations(ctx, addrs[0], 5) +// require.Equal(t, 3, len(resBonds)) +// require.True(t, bond1to1.Equal(resBonds[0])) +// require.True(t, bond1to2.Equal(resBonds[1])) +// require.True(t, bond1to3.Equal(resBonds[2])) +// resBonds = app.StakingKeeper.GetAllDelegatorDelegations(ctx, addrs[0]) +// require.Equal(t, 3, len(resBonds)) +// resBonds = app.StakingKeeper.GetDelegatorDelegations(ctx, addrs[0], 2) +// require.Equal(t, 2, len(resBonds)) +// resBonds = app.StakingKeeper.GetDelegatorDelegations(ctx, addrs[1], 5) +// require.Equal(t, 3, len(resBonds)) +// require.True(t, bond2to1.Equal(resBonds[0])) +// require.True(t, bond2to2.Equal(resBonds[1])) +// require.True(t, bond2to3.Equal(resBonds[2])) +// allBonds := app.StakingKeeper.GetAllDelegations(ctx) +// require.Equal(t, 6, len(allBonds)) +// require.True(t, bond1to1.Equal(allBonds[0])) +// require.True(t, bond1to2.Equal(allBonds[1])) +// require.True(t, bond1to3.Equal(allBonds[2])) +// require.True(t, bond2to1.Equal(allBonds[3])) +// require.True(t, bond2to2.Equal(allBonds[4])) +// require.True(t, bond2to3.Equal(allBonds[5])) +// +// resVals := app.StakingKeeper.GetDelegatorValidators(ctx, addrs[0], 3) +// require.Equal(t, 3, len(resVals)) +// resVals = app.StakingKeeper.GetDelegatorValidators(ctx, addrs[1], 4) +// require.Equal(t, 3, len(resVals)) +// +// for i := 0; i < 3; i++ { +// resVal, err := app.StakingKeeper.GetDelegatorValidator(ctx, addrs[0], sdk.ValAddress(addrs[i])) +// require.Nil(t, err) +// require.Equal(t, addrs[i], resVal.GetOperator()) +// +// resVal, err = app.StakingKeeper.GetDelegatorValidator(ctx, addrs[1], sdk.ValAddress(addrs[i])) +// require.Nil(t, err) +// require.Equal(t, addrs[i], resVal.GetOperator()) +// +// resDels := app.StakingKeeper.GetValidatorDelegations(ctx, sdk.ValAddress(addrs[i])) +// require.Len(t, resDels, 2) +// } +// +// // delete a record +// app.StakingKeeper.RemoveDelegation(ctx, bond2to3) +// _, found = app.StakingKeeper.GetDelegation(ctx, addrs[1], sdk.ValAddress(addrs[2])) +// require.False(t, found) +// resBonds = app.StakingKeeper.GetDelegatorDelegations(ctx, addrs[1], 5) +// require.Equal(t, 2, len(resBonds)) +// require.True(t, bond2to1.Equal(resBonds[0])) +// require.True(t, bond2to2.Equal(resBonds[1])) +// +// resBonds = app.StakingKeeper.GetAllDelegatorDelegations(ctx, addrs[1]) +// require.Equal(t, 2, len(resBonds)) +// +// // delete all the records from delegator 2 +// app.StakingKeeper.RemoveDelegation(ctx, bond2to1) +// app.StakingKeeper.RemoveDelegation(ctx, bond2to2) +// _, found = app.StakingKeeper.GetDelegation(ctx, addrs[1], sdk.ValAddress(addrs[0])) +// require.False(t, found) +// _, found = app.StakingKeeper.GetDelegation(ctx, addrs[1], sdk.ValAddress(addrs[1])) +// require.False(t, found) +// resBonds = app.StakingKeeper.GetDelegatorDelegations(ctx, addrDels[1], 5) +// require.Equal(t, 0, len(resBonds)) +//} +// // tests Get/Set/Remove UnbondingDelegation func TestUnbondingDelegation(t *testing.T) { _, app, ctx := getBaseSimappWithCustomKeeper() From ee7ccc37040862ef897a8aa32405537670cab686 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Fri, 21 Feb 2020 19:34:07 +0100 Subject: [PATCH 176/529] make TestDelegation pass with generated accounts --- simapp/test_helpers.go | 64 +++++++- x/staking/keeper/delegation_test.go | 228 ++++++++++++++-------------- 2 files changed, 175 insertions(+), 117 deletions(-) diff --git a/simapp/test_helpers.go b/simapp/test_helpers.go index 31b4db3b80cd..36237bc5ec4a 100644 --- a/simapp/test_helpers.go +++ b/simapp/test_helpers.go @@ -80,15 +80,52 @@ func SetupWithGenesisAccounts(genAccs []authexported.GenesisAccount, balances .. return app } -// AddTestAddrs constructs and returns accNum amount of accounts with an -// initial balance of accAmt -func AddTestAddrs(app *SimApp, ctx sdk.Context, accNum int, accAmt sdk.Int) []sdk.AccAddress { +type GenerateAccountStrategy func(int) []sdk.AccAddress + +func Random(accNum int) []sdk.AccAddress { testAddrs := make([]sdk.AccAddress, accNum) for i := 0; i < accNum; i++ { pk := ed25519.GenPrivKey().PubKey() testAddrs[i] = sdk.AccAddress(pk.Address()) } + return testAddrs +} + +func Incremental(accNum int) []sdk.AccAddress { + var addresses []sdk.AccAddress + var buffer bytes.Buffer + + // start at 100 so we can make up to 999 test addresses with valid test addresses + for i := 100; i < (accNum + 100); i++ { + numString := strconv.Itoa(i) + buffer.WriteString("A58856F0FD53BF058B4909A21AEC019107BA6") //base address string + + buffer.WriteString(numString) //adding on final two digits to make addresses unique + res, _ := sdk.AccAddressFromHex(buffer.String()) + bech := res.String() + addresses = append(addresses, TestAddr(buffer.String(), bech)) + buffer.Reset() + } + + return addresses +} + +// AddTestAddrs constructs and returns accNum amount of accounts with an +// initial balance of accAmt in random order +func AddTestAddrs(app *SimApp, ctx sdk.Context, accNum int, accAmt sdk.Int) []sdk.AccAddress { + return addTestAddrs(app, ctx, accNum, accAmt, Random) +} + +// AddTestAddrs constructs and returns accNum amount of accounts with an +// initial balance of accAmt in random order +func AddTestAddrsIncremental(app *SimApp, ctx sdk.Context, accNum int, accAmt sdk.Int) []sdk.AccAddress { + return addTestAddrs(app, ctx, accNum, accAmt, Incremental) +} + +func addTestAddrs(app *SimApp, ctx sdk.Context, accNum int, accAmt sdk.Int, strategy GenerateAccountStrategy) []sdk.AccAddress { + testAddrs := strategy(accNum) + initCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), accAmt)) totalSupply := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), accAmt.MulRaw(int64(len(testAddrs))))) prevSupply := app.SupplyKeeper.GetSupply(ctx) @@ -107,6 +144,27 @@ func AddTestAddrs(app *SimApp, ctx sdk.Context, accNum int, accAmt sdk.Int) []sd return testAddrs } +func TestAddr(addr string, bech string) sdk.AccAddress { + res, err := sdk.AccAddressFromHex(addr) + if err != nil { + panic(err) + } + bechexpected := res.String() + if bech != bechexpected { + panic("Bech encoding doesn't match reference") + } + + bechres, err := sdk.AccAddressFromBech32(bech) + if err != nil { + panic(err) + } + if !bytes.Equal(bechres, res) { + panic("Bech decode and hex decode don't match") + } + + return res +} + // CheckBalance checks the balance of an account. func CheckBalance(t *testing.T, app *SimApp, addr sdk.AccAddress, balances sdk.Coins) { ctxCheck := app.BaseApp.NewContext(true, abci.Header{}) diff --git a/x/staking/keeper/delegation_test.go b/x/staking/keeper/delegation_test.go index 45879644be66..7c0bac9c4bb9 100644 --- a/x/staking/keeper/delegation_test.go +++ b/x/staking/keeper/delegation_test.go @@ -15,120 +15,120 @@ import ( ) // tests GetDelegation, GetDelegatorDelegations, SetDelegation, RemoveDelegation, GetDelegatorDelegations -//func TestDelegation(t *testing.T) { -// _, app, ctx := getBaseSimappWithCustomKeeper() -// -// addrs := simapp.AddTestAddrs(app, ctx, 3, sdk.NewInt(10000)) -// -// //construct the validators -// amts := []sdk.Int{sdk.NewInt(9), sdk.NewInt(8), sdk.NewInt(7)} -// var validators [3]types.Validator -// for i, amt := range amts { -// validators[i] = types.NewValidator(sdk.ValAddress(addrs[i]), PKs[i], types.Description{}) -// validators[i], _ = validators[i].AddTokensFromDel(amt) -// } -// -// validators[0] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[0], true) -// validators[1] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[1], true) -// validators[2] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[2], true) -// -// // first add a validators[0] to delegate too -// bond1to1 := types.NewDelegation(addrs[0], sdk.ValAddress(addrs[0]), sdk.NewDec(9)) -// -// // check the empty keeper first -// _, found := app.StakingKeeper.GetDelegation(ctx, addrs[0], sdk.ValAddress(addrs[0])) -// require.False(t, found) -// -// // set and retrieve a record -// app.StakingKeeper.SetDelegation(ctx, bond1to1) -// resBond, found := app.StakingKeeper.GetDelegation(ctx, addrs[0], sdk.ValAddress(addrs[0])) -// require.True(t, found) -// require.True(t, bond1to1.Equal(resBond)) -// -// // modify a records, save, and retrieve -// bond1to1.Shares = sdk.NewDec(99) -// app.StakingKeeper.SetDelegation(ctx, bond1to1) -// resBond, found = app.StakingKeeper.GetDelegation(ctx, addrs[0], sdk.ValAddress(addrs[0])) -// require.True(t, found) -// require.True(t, bond1to1.Equal(resBond)) -// -// // add some more records -// bond1to2 := types.NewDelegation(addrs[0], sdk.ValAddress(addrs[1]), sdk.NewDec(9)) -// bond1to3 := types.NewDelegation(addrs[0], sdk.ValAddress(addrs[2]), sdk.NewDec(9)) -// bond2to1 := types.NewDelegation(addrs[1], sdk.ValAddress(addrs[0]), sdk.NewDec(9)) -// bond2to2 := types.NewDelegation(addrs[1], sdk.ValAddress(addrs[1]), sdk.NewDec(9)) -// bond2to3 := types.NewDelegation(addrs[1], sdk.ValAddress(addrs[2]), sdk.NewDec(9)) -// app.StakingKeeper.SetDelegation(ctx, bond1to2) -// app.StakingKeeper.SetDelegation(ctx, bond1to3) -// app.StakingKeeper.SetDelegation(ctx, bond2to1) -// app.StakingKeeper.SetDelegation(ctx, bond2to2) -// app.StakingKeeper.SetDelegation(ctx, bond2to3) -// -// // test all bond retrieve capabilities -// resBonds := app.StakingKeeper.GetDelegatorDelegations(ctx, addrs[0], 5) -// require.Equal(t, 3, len(resBonds)) -// require.True(t, bond1to1.Equal(resBonds[0])) -// require.True(t, bond1to2.Equal(resBonds[1])) -// require.True(t, bond1to3.Equal(resBonds[2])) -// resBonds = app.StakingKeeper.GetAllDelegatorDelegations(ctx, addrs[0]) -// require.Equal(t, 3, len(resBonds)) -// resBonds = app.StakingKeeper.GetDelegatorDelegations(ctx, addrs[0], 2) -// require.Equal(t, 2, len(resBonds)) -// resBonds = app.StakingKeeper.GetDelegatorDelegations(ctx, addrs[1], 5) -// require.Equal(t, 3, len(resBonds)) -// require.True(t, bond2to1.Equal(resBonds[0])) -// require.True(t, bond2to2.Equal(resBonds[1])) -// require.True(t, bond2to3.Equal(resBonds[2])) -// allBonds := app.StakingKeeper.GetAllDelegations(ctx) -// require.Equal(t, 6, len(allBonds)) -// require.True(t, bond1to1.Equal(allBonds[0])) -// require.True(t, bond1to2.Equal(allBonds[1])) -// require.True(t, bond1to3.Equal(allBonds[2])) -// require.True(t, bond2to1.Equal(allBonds[3])) -// require.True(t, bond2to2.Equal(allBonds[4])) -// require.True(t, bond2to3.Equal(allBonds[5])) -// -// resVals := app.StakingKeeper.GetDelegatorValidators(ctx, addrs[0], 3) -// require.Equal(t, 3, len(resVals)) -// resVals = app.StakingKeeper.GetDelegatorValidators(ctx, addrs[1], 4) -// require.Equal(t, 3, len(resVals)) -// -// for i := 0; i < 3; i++ { -// resVal, err := app.StakingKeeper.GetDelegatorValidator(ctx, addrs[0], sdk.ValAddress(addrs[i])) -// require.Nil(t, err) -// require.Equal(t, addrs[i], resVal.GetOperator()) -// -// resVal, err = app.StakingKeeper.GetDelegatorValidator(ctx, addrs[1], sdk.ValAddress(addrs[i])) -// require.Nil(t, err) -// require.Equal(t, addrs[i], resVal.GetOperator()) -// -// resDels := app.StakingKeeper.GetValidatorDelegations(ctx, sdk.ValAddress(addrs[i])) -// require.Len(t, resDels, 2) -// } -// -// // delete a record -// app.StakingKeeper.RemoveDelegation(ctx, bond2to3) -// _, found = app.StakingKeeper.GetDelegation(ctx, addrs[1], sdk.ValAddress(addrs[2])) -// require.False(t, found) -// resBonds = app.StakingKeeper.GetDelegatorDelegations(ctx, addrs[1], 5) -// require.Equal(t, 2, len(resBonds)) -// require.True(t, bond2to1.Equal(resBonds[0])) -// require.True(t, bond2to2.Equal(resBonds[1])) -// -// resBonds = app.StakingKeeper.GetAllDelegatorDelegations(ctx, addrs[1]) -// require.Equal(t, 2, len(resBonds)) -// -// // delete all the records from delegator 2 -// app.StakingKeeper.RemoveDelegation(ctx, bond2to1) -// app.StakingKeeper.RemoveDelegation(ctx, bond2to2) -// _, found = app.StakingKeeper.GetDelegation(ctx, addrs[1], sdk.ValAddress(addrs[0])) -// require.False(t, found) -// _, found = app.StakingKeeper.GetDelegation(ctx, addrs[1], sdk.ValAddress(addrs[1])) -// require.False(t, found) -// resBonds = app.StakingKeeper.GetDelegatorDelegations(ctx, addrDels[1], 5) -// require.Equal(t, 0, len(resBonds)) -//} -// +func TestDelegation(t *testing.T) { + _, app, ctx := getBaseSimappWithCustomKeeper() + + addrs := simapp.AddTestAddrsIncremental(app, ctx, 3, sdk.NewInt(10000)) + + //construct the validators + amts := []sdk.Int{sdk.NewInt(9), sdk.NewInt(8), sdk.NewInt(7)} + var validators [3]types.Validator + for i, amt := range amts { + validators[i] = types.NewValidator(sdk.ValAddress(addrs[i]), PKs[i], types.Description{}) + validators[i], _ = validators[i].AddTokensFromDel(amt) + } + + validators[0] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[0], true) + validators[1] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[1], true) + validators[2] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[2], true) + + // first add a validators[0] to delegate too + bond1to1 := types.NewDelegation(addrs[0], sdk.ValAddress(addrs[0]), sdk.NewDec(9)) + + // check the empty keeper first + _, found := app.StakingKeeper.GetDelegation(ctx, addrs[0], sdk.ValAddress(addrs[0])) + require.False(t, found) + + // set and retrieve a record + app.StakingKeeper.SetDelegation(ctx, bond1to1) + resBond, found := app.StakingKeeper.GetDelegation(ctx, addrs[0], sdk.ValAddress(addrs[0])) + require.True(t, found) + require.True(t, bond1to1.Equal(resBond)) + + // modify a records, save, and retrieve + bond1to1.Shares = sdk.NewDec(99) + app.StakingKeeper.SetDelegation(ctx, bond1to1) + resBond, found = app.StakingKeeper.GetDelegation(ctx, addrs[0], sdk.ValAddress(addrs[0])) + require.True(t, found) + require.True(t, bond1to1.Equal(resBond)) + + // add some more records + bond1to2 := types.NewDelegation(addrs[0], sdk.ValAddress(addrs[1]), sdk.NewDec(9)) + bond1to3 := types.NewDelegation(addrs[0], sdk.ValAddress(addrs[2]), sdk.NewDec(9)) + bond2to1 := types.NewDelegation(addrs[1], sdk.ValAddress(addrs[0]), sdk.NewDec(9)) + bond2to2 := types.NewDelegation(addrs[1], sdk.ValAddress(addrs[1]), sdk.NewDec(9)) + bond2to3 := types.NewDelegation(addrs[1], sdk.ValAddress(addrs[2]), sdk.NewDec(9)) + app.StakingKeeper.SetDelegation(ctx, bond1to2) + app.StakingKeeper.SetDelegation(ctx, bond1to3) + app.StakingKeeper.SetDelegation(ctx, bond2to1) + app.StakingKeeper.SetDelegation(ctx, bond2to2) + app.StakingKeeper.SetDelegation(ctx, bond2to3) + + // test all bond retrieve capabilities + resBonds := app.StakingKeeper.GetDelegatorDelegations(ctx, addrs[0], 5) + require.Equal(t, 3, len(resBonds)) + require.True(t, bond1to1.Equal(resBonds[0])) + require.True(t, bond1to2.Equal(resBonds[1])) + require.True(t, bond1to3.Equal(resBonds[2])) + resBonds = app.StakingKeeper.GetAllDelegatorDelegations(ctx, addrs[0]) + require.Equal(t, 3, len(resBonds)) + resBonds = app.StakingKeeper.GetDelegatorDelegations(ctx, addrs[0], 2) + require.Equal(t, 2, len(resBonds)) + resBonds = app.StakingKeeper.GetDelegatorDelegations(ctx, addrs[1], 5) + require.Equal(t, 3, len(resBonds)) + require.True(t, bond2to1.Equal(resBonds[0])) + require.True(t, bond2to2.Equal(resBonds[1])) + require.True(t, bond2to3.Equal(resBonds[2])) + allBonds := app.StakingKeeper.GetAllDelegations(ctx) + require.Equal(t, 6, len(allBonds)) + require.True(t, bond1to1.Equal(allBonds[0])) + require.True(t, bond1to2.Equal(allBonds[1])) + require.True(t, bond1to3.Equal(allBonds[2])) + require.True(t, bond2to1.Equal(allBonds[3])) + require.True(t, bond2to2.Equal(allBonds[4])) + require.True(t, bond2to3.Equal(allBonds[5])) + + resVals := app.StakingKeeper.GetDelegatorValidators(ctx, addrs[0], 3) + require.Equal(t, 3, len(resVals)) + resVals = app.StakingKeeper.GetDelegatorValidators(ctx, addrs[1], 4) + require.Equal(t, 3, len(resVals)) + + for i := 0; i < 3; i++ { + resVal, err := app.StakingKeeper.GetDelegatorValidator(ctx, addrs[0], sdk.ValAddress(addrs[i])) + require.Nil(t, err) + require.Equal(t, sdk.ValAddress(addrs[i]), resVal.GetOperator()) + + resVal, err = app.StakingKeeper.GetDelegatorValidator(ctx, addrs[1], sdk.ValAddress(addrs[i])) + require.Nil(t, err) + require.Equal(t, sdk.ValAddress(addrs[i]), resVal.GetOperator()) + + resDels := app.StakingKeeper.GetValidatorDelegations(ctx, sdk.ValAddress(addrs[i])) + require.Len(t, resDels, 2) + } + + // delete a record + app.StakingKeeper.RemoveDelegation(ctx, bond2to3) + _, found = app.StakingKeeper.GetDelegation(ctx, addrs[1], sdk.ValAddress(addrs[2])) + require.False(t, found) + resBonds = app.StakingKeeper.GetDelegatorDelegations(ctx, addrs[1], 5) + require.Equal(t, 2, len(resBonds)) + require.True(t, bond2to1.Equal(resBonds[0])) + require.True(t, bond2to2.Equal(resBonds[1])) + + resBonds = app.StakingKeeper.GetAllDelegatorDelegations(ctx, addrs[1]) + require.Equal(t, 2, len(resBonds)) + + // delete all the records from delegator 2 + app.StakingKeeper.RemoveDelegation(ctx, bond2to1) + app.StakingKeeper.RemoveDelegation(ctx, bond2to2) + _, found = app.StakingKeeper.GetDelegation(ctx, addrs[1], sdk.ValAddress(addrs[0])) + require.False(t, found) + _, found = app.StakingKeeper.GetDelegation(ctx, addrs[1], sdk.ValAddress(addrs[1])) + require.False(t, found) + resBonds = app.StakingKeeper.GetDelegatorDelegations(ctx, addrDels[1], 5) + require.Equal(t, 0, len(resBonds)) +} + // tests Get/Set/Remove UnbondingDelegation func TestUnbondingDelegation(t *testing.T) { _, app, ctx := getBaseSimappWithCustomKeeper() From e5b67801a3ff5ae083718c72f0c5ac9bcb448f97 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Fri, 21 Feb 2020 20:51:11 +0100 Subject: [PATCH 177/529] refactor to use accounts --- simapp/test_helpers.go | 8 ++++ x/staking/keeper/delegation_test.go | 61 +++++++++++++++-------------- 2 files changed, 40 insertions(+), 29 deletions(-) diff --git a/simapp/test_helpers.go b/simapp/test_helpers.go index 36237bc5ec4a..cfedd7d3188f 100644 --- a/simapp/test_helpers.go +++ b/simapp/test_helpers.go @@ -144,6 +144,14 @@ func addTestAddrs(app *SimApp, ctx sdk.Context, accNum int, accAmt sdk.Int, stra return testAddrs } +func ConvertAddrsToValAddrs(addrs []sdk.AccAddress) (valAddrs []sdk.ValAddress) { + for _, addr := range addrs { + valAddrs = append(valAddrs, sdk.ValAddress(addr)) + } + + return +} + func TestAddr(addr string, bech string) sdk.AccAddress { res, err := sdk.AccAddressFromHex(addr) if err != nil { diff --git a/x/staking/keeper/delegation_test.go b/x/staking/keeper/delegation_test.go index 7c0bac9c4bb9..dbf4de871ff3 100644 --- a/x/staking/keeper/delegation_test.go +++ b/x/staking/keeper/delegation_test.go @@ -4,12 +4,11 @@ import ( "testing" "time" - "github.com/cosmos/cosmos-sdk/x/staking" - "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/staking" "github.com/cosmos/cosmos-sdk/x/staking/keeper" "github.com/cosmos/cosmos-sdk/x/staking/types" ) @@ -19,12 +18,13 @@ func TestDelegation(t *testing.T) { _, app, ctx := getBaseSimappWithCustomKeeper() addrs := simapp.AddTestAddrsIncremental(app, ctx, 3, sdk.NewInt(10000)) + valAddrs := simapp.ConvertAddrsToValAddrs(addrs) //construct the validators amts := []sdk.Int{sdk.NewInt(9), sdk.NewInt(8), sdk.NewInt(7)} var validators [3]types.Validator for i, amt := range amts { - validators[i] = types.NewValidator(sdk.ValAddress(addrs[i]), PKs[i], types.Description{}) + validators[i] = types.NewValidator(valAddrs[i], PKs[i], types.Description{}) validators[i], _ = validators[i].AddTokensFromDel(amt) } @@ -33,31 +33,31 @@ func TestDelegation(t *testing.T) { validators[2] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[2], true) // first add a validators[0] to delegate too - bond1to1 := types.NewDelegation(addrs[0], sdk.ValAddress(addrs[0]), sdk.NewDec(9)) + bond1to1 := types.NewDelegation(addrs[0], valAddrs[0], sdk.NewDec(9)) // check the empty keeper first - _, found := app.StakingKeeper.GetDelegation(ctx, addrs[0], sdk.ValAddress(addrs[0])) + _, found := app.StakingKeeper.GetDelegation(ctx, addrs[0], valAddrs[0]) require.False(t, found) // set and retrieve a record app.StakingKeeper.SetDelegation(ctx, bond1to1) - resBond, found := app.StakingKeeper.GetDelegation(ctx, addrs[0], sdk.ValAddress(addrs[0])) + resBond, found := app.StakingKeeper.GetDelegation(ctx, addrs[0], valAddrs[0]) require.True(t, found) require.True(t, bond1to1.Equal(resBond)) // modify a records, save, and retrieve bond1to1.Shares = sdk.NewDec(99) app.StakingKeeper.SetDelegation(ctx, bond1to1) - resBond, found = app.StakingKeeper.GetDelegation(ctx, addrs[0], sdk.ValAddress(addrs[0])) + resBond, found = app.StakingKeeper.GetDelegation(ctx, addrs[0], valAddrs[0]) require.True(t, found) require.True(t, bond1to1.Equal(resBond)) // add some more records - bond1to2 := types.NewDelegation(addrs[0], sdk.ValAddress(addrs[1]), sdk.NewDec(9)) - bond1to3 := types.NewDelegation(addrs[0], sdk.ValAddress(addrs[2]), sdk.NewDec(9)) - bond2to1 := types.NewDelegation(addrs[1], sdk.ValAddress(addrs[0]), sdk.NewDec(9)) - bond2to2 := types.NewDelegation(addrs[1], sdk.ValAddress(addrs[1]), sdk.NewDec(9)) - bond2to3 := types.NewDelegation(addrs[1], sdk.ValAddress(addrs[2]), sdk.NewDec(9)) + bond1to2 := types.NewDelegation(addrs[0], valAddrs[1], sdk.NewDec(9)) + bond1to3 := types.NewDelegation(addrs[0], valAddrs[2], sdk.NewDec(9)) + bond2to1 := types.NewDelegation(addrs[1], valAddrs[0], sdk.NewDec(9)) + bond2to2 := types.NewDelegation(addrs[1], valAddrs[1], sdk.NewDec(9)) + bond2to3 := types.NewDelegation(addrs[1], valAddrs[2], sdk.NewDec(9)) app.StakingKeeper.SetDelegation(ctx, bond1to2) app.StakingKeeper.SetDelegation(ctx, bond1to3) app.StakingKeeper.SetDelegation(ctx, bond2to1) @@ -94,21 +94,21 @@ func TestDelegation(t *testing.T) { require.Equal(t, 3, len(resVals)) for i := 0; i < 3; i++ { - resVal, err := app.StakingKeeper.GetDelegatorValidator(ctx, addrs[0], sdk.ValAddress(addrs[i])) + resVal, err := app.StakingKeeper.GetDelegatorValidator(ctx, addrs[0], valAddrs[i]) require.Nil(t, err) - require.Equal(t, sdk.ValAddress(addrs[i]), resVal.GetOperator()) + require.Equal(t, valAddrs[i], resVal.GetOperator()) - resVal, err = app.StakingKeeper.GetDelegatorValidator(ctx, addrs[1], sdk.ValAddress(addrs[i])) + resVal, err = app.StakingKeeper.GetDelegatorValidator(ctx, addrs[1], valAddrs[i]) require.Nil(t, err) - require.Equal(t, sdk.ValAddress(addrs[i]), resVal.GetOperator()) + require.Equal(t, valAddrs[i], resVal.GetOperator()) - resDels := app.StakingKeeper.GetValidatorDelegations(ctx, sdk.ValAddress(addrs[i])) + resDels := app.StakingKeeper.GetValidatorDelegations(ctx, valAddrs[i]) require.Len(t, resDels, 2) } // delete a record app.StakingKeeper.RemoveDelegation(ctx, bond2to3) - _, found = app.StakingKeeper.GetDelegation(ctx, addrs[1], sdk.ValAddress(addrs[2])) + _, found = app.StakingKeeper.GetDelegation(ctx, addrs[1], valAddrs[2]) require.False(t, found) resBonds = app.StakingKeeper.GetDelegatorDelegations(ctx, addrs[1], 5) require.Equal(t, 2, len(resBonds)) @@ -121,9 +121,9 @@ func TestDelegation(t *testing.T) { // delete all the records from delegator 2 app.StakingKeeper.RemoveDelegation(ctx, bond2to1) app.StakingKeeper.RemoveDelegation(ctx, bond2to2) - _, found = app.StakingKeeper.GetDelegation(ctx, addrs[1], sdk.ValAddress(addrs[0])) + _, found = app.StakingKeeper.GetDelegation(ctx, addrs[1], valAddrs[0]) require.False(t, found) - _, found = app.StakingKeeper.GetDelegation(ctx, addrs[1], sdk.ValAddress(addrs[1])) + _, found = app.StakingKeeper.GetDelegation(ctx, addrs[1], valAddrs[1]) require.False(t, found) resBonds = app.StakingKeeper.GetDelegatorDelegations(ctx, addrDels[1], 5) require.Equal(t, 0, len(resBonds)) @@ -133,9 +133,12 @@ func TestDelegation(t *testing.T) { func TestUnbondingDelegation(t *testing.T) { _, app, ctx := getBaseSimappWithCustomKeeper() + delAddrs := simapp.AddTestAddrsIncremental(app, ctx, 2, sdk.NewInt(10000)) + valAddrs := simapp.ConvertAddrsToValAddrs(delAddrs) + ubd := types.NewUnbondingDelegation( - addrDels[0], - addrVals[0], + delAddrs[0], + valAddrs[0], 0, time.Unix(0, 0), sdk.NewInt(5), @@ -143,7 +146,7 @@ func TestUnbondingDelegation(t *testing.T) { // set and retrieve a record app.StakingKeeper.SetUnbondingDelegation(ctx, ubd) - resUnbond, found := app.StakingKeeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) + resUnbond, found := app.StakingKeeper.GetUnbondingDelegation(ctx, delAddrs[0], valAddrs[0]) require.True(t, found) require.True(t, ubd.Equal(resUnbond)) @@ -151,25 +154,25 @@ func TestUnbondingDelegation(t *testing.T) { ubd.Entries[0].Balance = sdk.NewInt(21) app.StakingKeeper.SetUnbondingDelegation(ctx, ubd) - resUnbonds := app.StakingKeeper.GetUnbondingDelegations(ctx, addrDels[0], 5) + resUnbonds := app.StakingKeeper.GetUnbondingDelegations(ctx, delAddrs[0], 5) require.Equal(t, 1, len(resUnbonds)) - resUnbonds = app.StakingKeeper.GetAllUnbondingDelegations(ctx, addrDels[0]) + resUnbonds = app.StakingKeeper.GetAllUnbondingDelegations(ctx, delAddrs[0]) require.Equal(t, 1, len(resUnbonds)) - resUnbond, found = app.StakingKeeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) + resUnbond, found = app.StakingKeeper.GetUnbondingDelegation(ctx, delAddrs[0], valAddrs[0]) require.True(t, found) require.True(t, ubd.Equal(resUnbond)) // delete a record app.StakingKeeper.RemoveUnbondingDelegation(ctx, ubd) - _, found = app.StakingKeeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) + _, found = app.StakingKeeper.GetUnbondingDelegation(ctx, delAddrs[0], valAddrs[0]) require.False(t, found) - resUnbonds = app.StakingKeeper.GetUnbondingDelegations(ctx, addrDels[0], 5) + resUnbonds = app.StakingKeeper.GetUnbondingDelegations(ctx, delAddrs[0], 5) require.Equal(t, 0, len(resUnbonds)) - resUnbonds = app.StakingKeeper.GetAllUnbondingDelegations(ctx, addrDels[0]) + resUnbonds = app.StakingKeeper.GetAllUnbondingDelegations(ctx, delAddrs[0]) require.Equal(t, 0, len(resUnbonds)) } From 8cf9219a53288a68847f7af0e66696c8b1c2bfd3 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Fri, 21 Feb 2020 21:05:56 +0100 Subject: [PATCH 178/529] refactor test unbondingdelegationsmax entries --- x/staking/keeper/delegation_test.go | 190 +++++++++++++--------------- 1 file changed, 88 insertions(+), 102 deletions(-) diff --git a/x/staking/keeper/delegation_test.go b/x/staking/keeper/delegation_test.go index dbf4de871ff3..9d7c2fbed31f 100644 --- a/x/staking/keeper/delegation_test.go +++ b/x/staking/keeper/delegation_test.go @@ -8,7 +8,6 @@ import ( "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/staking" "github.com/cosmos/cosmos-sdk/x/staking/keeper" "github.com/cosmos/cosmos-sdk/x/staking/types" ) @@ -179,14 +178,8 @@ func TestUnbondingDelegation(t *testing.T) { func TestUnbondDelegation(t *testing.T) { _, app, ctx := getBaseSimappWithCustomKeeper() - codec := simapp.NewAppCodec() - app.StakingKeeper = keeper.NewKeeper( - codec.Staking, - app.GetKey(staking.StoreKey), - app.BankKeeper, - app.SupplyKeeper, - app.GetSubspace(staking.ModuleName), - ) + delAddrs := simapp.AddTestAddrsIncremental(app, ctx, 1, sdk.NewInt(10000)) + valAddrs := simapp.ConvertAddrsToValAddrs(delAddrs) startTokens := sdk.TokensFromConsensusPower(10) notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) @@ -202,24 +195,24 @@ func TestUnbondDelegation(t *testing.T) { // create a validator and a delegator to that validator // note this validator starts not-bonded - validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) + validator := types.NewValidator(valAddrs[0], PKs[0], types.Description{}) validator, issuedShares := validator.AddTokensFromDel(startTokens) require.Equal(t, startTokens, issuedShares.RoundInt()) validator = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator, true) - delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) + delegation := types.NewDelegation(delAddrs[0], valAddrs[0], issuedShares) app.StakingKeeper.SetDelegation(ctx, delegation) bondTokens := sdk.TokensFromConsensusPower(6) - amount, err := app.StakingKeeper.Unbond(ctx, addrDels[0], addrVals[0], bondTokens.ToDec()) + amount, err := app.StakingKeeper.Unbond(ctx, delAddrs[0], valAddrs[0], bondTokens.ToDec()) require.NoError(t, err) require.Equal(t, bondTokens, amount) // shares to be added to an unbonding delegation - delegation, found := app.StakingKeeper.GetDelegation(ctx, addrDels[0], addrVals[0]) + delegation, found := app.StakingKeeper.GetDelegation(ctx, delAddrs[0], valAddrs[0]) require.True(t, found) - validator, found = app.StakingKeeper.GetValidator(ctx, addrVals[0]) + validator, found = app.StakingKeeper.GetValidator(ctx, valAddrs[0]) require.True(t, found) remainingTokens := startTokens.Sub(bondTokens) @@ -227,94 +220,87 @@ func TestUnbondDelegation(t *testing.T) { require.Equal(t, remainingTokens, validator.BondedTokens()) } -//func TestUnbondingDelegationsMaxEntries(t *testing.T) { -// app := simapp.Setup(false) -// ctx := app.BaseApp.NewContext(false, abci.Header{}) -// -// codec := simapp.NewAppCodec() -// app.StakingKeeper = keeper.NewKeeper( -// codec.Staking, -// app.GetKey(staking.StoreKey), -// app.BankKeeper, -// app.SupplyKeeper, -// app.GetSubspace(staking.ModuleName), -// ) -// -// startTokens := sdk.TokensFromConsensusPower(10) -// -// bondDenom := app.StakingKeeper.BondDenom(ctx) -// notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) -// -// err := app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(bondDenom, startTokens))) -// require.NoError(t, err) -// app.SupplyKeeper.SetModuleAccount(ctx, notBondedPool) -// -// // create a validator and a delegator to that validator -// validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) -// -// validator, issuedShares := validator.AddTokensFromDel(startTokens) -// require.Equal(t, startTokens, issuedShares.RoundInt()) -// -// validator = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator, true) -// require.True(sdk.IntEq(t, startTokens, validator.BondedTokens())) -// require.True(t, validator.IsBonded()) -// -// delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) -// app.StakingKeeper.SetDelegation(ctx, delegation) -// -// maxEntries := app.StakingKeeper.MaxEntries(ctx) -// -// oldBonded := app.BankKeeper.GetBalance(ctx, app.StakingKeeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount -// oldNotBonded := app.BankKeeper.GetBalance(ctx, app.StakingKeeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount -// -// // should all pass -// var completionTime time.Time -// for i := uint32(0); i < maxEntries; i++ { -// var err error -// completionTime, err = app.StakingKeeper.Undelegate(ctx, addrDels[0], addrVals[0], sdk.NewDec(1)) -// require.NoError(t, err) -// } -// -// newBonded := app.BankKeeper.GetBalance(ctx, app.StakingKeeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount -// newNotBonded := app.BankKeeper.GetBalance(ctx, app.StakingKeeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount -// require.True(sdk.IntEq(t, newBonded, oldBonded.SubRaw(int64(maxEntries)))) -// require.True(sdk.IntEq(t, newNotBonded, oldNotBonded.AddRaw(int64(maxEntries)))) -// -// oldBonded = app.BankKeeper.GetBalance(ctx, app.StakingKeeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount -// oldNotBonded = app.BankKeeper.GetBalance(ctx, app.StakingKeeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount -// -// // an additional unbond should fail due to max entries -// _, err = app.StakingKeeper.Undelegate(ctx, addrDels[0], addrVals[0], sdk.NewDec(1)) -// require.Error(t, err) -// -// newBonded = app.BankKeeper.GetBalance(ctx, app.StakingKeeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount -// newNotBonded = app.BankKeeper.GetBalance(ctx, app.StakingKeeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount -// -// require.True(sdk.IntEq(t, newBonded, oldBonded)) -// require.True(sdk.IntEq(t, newNotBonded, oldNotBonded)) -// -// // mature unbonding delegations -// ctx = ctx.WithBlockTime(completionTime) -// err = app.StakingKeeper.CompleteUnbonding(ctx, addrDels[0], addrVals[0]) -// require.NoError(t, err) -// -// newBonded = app.BankKeeper.GetBalance(ctx, app.StakingKeeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount -// newNotBonded = app.BankKeeper.GetBalance(ctx, app.StakingKeeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount -// require.True(sdk.IntEq(t, newBonded, oldBonded)) -// require.True(sdk.IntEq(t, newNotBonded, oldNotBonded.SubRaw(int64(maxEntries)))) -// -// oldNotBonded = app.BankKeeper.GetBalance(ctx, app.StakingKeeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount -// -// // unbonding should work again -// _, err = app.StakingKeeper.Undelegate(ctx, addrDels[0], addrVals[0], sdk.NewDec(1)) -// require.NoError(t, err) -// -// newBonded = app.BankKeeper.GetBalance(ctx, app.StakingKeeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount -// newNotBonded = app.BankKeeper.GetBalance(ctx, app.StakingKeeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount -// require.True(sdk.IntEq(t, newBonded, oldBonded.SubRaw(1))) -// require.True(sdk.IntEq(t, newNotBonded, oldNotBonded.AddRaw(1))) -//} -// +func TestUnbondingDelegationsMaxEntries(t *testing.T) { + _, app, ctx := getBaseSimappWithCustomKeeper() + + addrDels := simapp.AddTestAddrsIncremental(app, ctx, 1, sdk.NewInt(10000)) + addrVals := simapp.ConvertAddrsToValAddrs(addrDels) + + startTokens := sdk.TokensFromConsensusPower(10) + + bondDenom := app.StakingKeeper.BondDenom(ctx) + notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) + + err := app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(bondDenom, startTokens))) + require.NoError(t, err) + app.SupplyKeeper.SetModuleAccount(ctx, notBondedPool) + + // create a validator and a delegator to that validator + validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) + + validator, issuedShares := validator.AddTokensFromDel(startTokens) + require.Equal(t, startTokens, issuedShares.RoundInt()) + + validator = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator, true) + require.True(sdk.IntEq(t, startTokens, validator.BondedTokens())) + require.True(t, validator.IsBonded()) + + delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) + app.StakingKeeper.SetDelegation(ctx, delegation) + + maxEntries := app.StakingKeeper.MaxEntries(ctx) + + oldBonded := app.BankKeeper.GetBalance(ctx, app.StakingKeeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount + oldNotBonded := app.BankKeeper.GetBalance(ctx, app.StakingKeeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount + + // should all pass + var completionTime time.Time + for i := uint32(0); i < maxEntries; i++ { + var err error + completionTime, err = app.StakingKeeper.Undelegate(ctx, addrDels[0], addrVals[0], sdk.NewDec(1)) + require.NoError(t, err) + } + + newBonded := app.BankKeeper.GetBalance(ctx, app.StakingKeeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount + newNotBonded := app.BankKeeper.GetBalance(ctx, app.StakingKeeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, newBonded, oldBonded.SubRaw(int64(maxEntries)))) + require.True(sdk.IntEq(t, newNotBonded, oldNotBonded.AddRaw(int64(maxEntries)))) + + oldBonded = app.BankKeeper.GetBalance(ctx, app.StakingKeeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount + oldNotBonded = app.BankKeeper.GetBalance(ctx, app.StakingKeeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount + + // an additional unbond should fail due to max entries + _, err = app.StakingKeeper.Undelegate(ctx, addrDels[0], addrVals[0], sdk.NewDec(1)) + require.Error(t, err) + + newBonded = app.BankKeeper.GetBalance(ctx, app.StakingKeeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount + newNotBonded = app.BankKeeper.GetBalance(ctx, app.StakingKeeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount + + require.True(sdk.IntEq(t, newBonded, oldBonded)) + require.True(sdk.IntEq(t, newNotBonded, oldNotBonded)) + + // mature unbonding delegations + ctx = ctx.WithBlockTime(completionTime) + err = app.StakingKeeper.CompleteUnbonding(ctx, addrDels[0], addrVals[0]) + require.NoError(t, err) + + newBonded = app.BankKeeper.GetBalance(ctx, app.StakingKeeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount + newNotBonded = app.BankKeeper.GetBalance(ctx, app.StakingKeeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, newBonded, oldBonded)) + require.True(sdk.IntEq(t, newNotBonded, oldNotBonded.SubRaw(int64(maxEntries)))) + + oldNotBonded = app.BankKeeper.GetBalance(ctx, app.StakingKeeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount + + // unbonding should work again + _, err = app.StakingKeeper.Undelegate(ctx, addrDels[0], addrVals[0], sdk.NewDec(1)) + require.NoError(t, err) + + newBonded = app.BankKeeper.GetBalance(ctx, app.StakingKeeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount + newNotBonded = app.BankKeeper.GetBalance(ctx, app.StakingKeeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, newBonded, oldBonded.SubRaw(1))) + require.True(sdk.IntEq(t, newNotBonded, oldNotBonded.AddRaw(1))) +} + //// test undelegating self delegation from a validator pushing it below MinSelfDelegation //// shift it from the bonded to unbonding state and jailed //func TestUndelegateSelfDelegationBelowMinSelfDelegation(t *testing.T) { From 8378be277ce065be341a640c33e738c56a10d922 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Fri, 21 Feb 2020 21:18:24 +0100 Subject: [PATCH 179/529] refactor TestUndelegateSelfDelegationBelowMinSelfDelegation to use simapp --- x/staking/keeper/delegation_test.go | 129 ++++++++++++------------ x/staking/keeper/old_delegation_test.go | 71 +------------ 2 files changed, 69 insertions(+), 131 deletions(-) diff --git a/x/staking/keeper/delegation_test.go b/x/staking/keeper/delegation_test.go index 9d7c2fbed31f..d4004fd0385d 100644 --- a/x/staking/keeper/delegation_test.go +++ b/x/staking/keeper/delegation_test.go @@ -303,69 +303,72 @@ func TestUnbondingDelegationsMaxEntries(t *testing.T) { //// test undelegating self delegation from a validator pushing it below MinSelfDelegation //// shift it from the bonded to unbonding state and jailed -//func TestUndelegateSelfDelegationBelowMinSelfDelegation(t *testing.T) { -// ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) -// delTokens := sdk.TokensFromConsensusPower(10) -// delCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), delTokens)) -// -// //create a validator with a self-delegation -// validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) -// -// validator.MinSelfDelegation = delTokens -// validator, issuedShares := validator.AddTokensFromDel(delTokens) -// require.Equal(t, delTokens, issuedShares.RoundInt()) -// -// // add bonded tokens to pool for delegations -// notBondedPool := keeper.GetNotBondedPool(ctx) -// oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) -// err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(delCoins...)) -// require.NoError(t, err) -// keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) -// -// validator = TestingUpdateValidator(keeper, ctx, validator, true) -// require.True(t, validator.IsBonded()) -// -// selfDelegation := types.NewDelegation(sdk.AccAddress(addrVals[0].Bytes()), addrVals[0], issuedShares) -// keeper.SetDelegation(ctx, selfDelegation) -// -// // add bonded tokens to pool for delegations -// bondedPool := keeper.GetBondedPool(ctx) -// oldBonded := bk.GetAllBalances(ctx, bondedPool.GetAddress()) -// err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) -// require.NoError(t, err) -// keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) -// -// // create a second delegation to this validator -// keeper.DeleteValidatorByPowerIndex(ctx, validator) -// validator, issuedShares = validator.AddTokensFromDel(delTokens) -// require.True(t, validator.IsBonded()) -// require.Equal(t, delTokens, issuedShares.RoundInt()) -// -// // add bonded tokens to pool for delegations -// oldBonded = bk.GetAllBalances(ctx, bondedPool.GetAddress()) -// err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) -// require.NoError(t, err) -// keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) -// -// validator = TestingUpdateValidator(keeper, ctx, validator, true) -// delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) -// keeper.SetDelegation(ctx, delegation) -// -// val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) -// _, err = keeper.Undelegate(ctx, val0AccAddr, addrVals[0], sdk.TokensFromConsensusPower(6).ToDec()) -// require.NoError(t, err) -// -// // end block -// updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) -// require.Equal(t, 1, len(updates)) -// -// validator, found := keeper.GetValidator(ctx, addrVals[0]) -// require.True(t, found) -// require.Equal(t, sdk.TokensFromConsensusPower(14), validator.Tokens) -// require.Equal(t, sdk.Unbonding, validator.Status) -// require.True(t, validator.Jailed) -//} -// +func TestUndelegateSelfDelegationBelowMinSelfDelegation(t *testing.T) { + _, app, ctx := getBaseSimappWithCustomKeeper() + + addrDels := simapp.AddTestAddrsIncremental(app, ctx, 1, sdk.NewInt(10000)) + addrVals := simapp.ConvertAddrsToValAddrs(addrDels) + delTokens := sdk.TokensFromConsensusPower(10) + delCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), delTokens)) + + //create a validator with a self-delegation + validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) + + validator.MinSelfDelegation = delTokens + validator, issuedShares := validator.AddTokensFromDel(delTokens) + require.Equal(t, delTokens, issuedShares.RoundInt()) + + // add bonded tokens to pool for delegations + notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) + oldNotBonded := app.BankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) + err := app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(delCoins...)) + require.NoError(t, err) + app.SupplyKeeper.SetModuleAccount(ctx, notBondedPool) + + validator = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator, true) + require.True(t, validator.IsBonded()) + + selfDelegation := types.NewDelegation(sdk.AccAddress(addrVals[0].Bytes()), addrVals[0], issuedShares) + app.StakingKeeper.SetDelegation(ctx, selfDelegation) + + // add bonded tokens to pool for delegations + bondedPool := app.StakingKeeper.GetBondedPool(ctx) + oldBonded := app.BankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + err = app.BankKeeper.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) + require.NoError(t, err) + app.SupplyKeeper.SetModuleAccount(ctx, bondedPool) + + // create a second delegation to this validator + app.StakingKeeper.DeleteValidatorByPowerIndex(ctx, validator) + validator, issuedShares = validator.AddTokensFromDel(delTokens) + require.True(t, validator.IsBonded()) + require.Equal(t, delTokens, issuedShares.RoundInt()) + + // add bonded tokens to pool for delegations + oldBonded = app.BankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + err = app.BankKeeper.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) + require.NoError(t, err) + app.SupplyKeeper.SetModuleAccount(ctx, bondedPool) + + validator = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator, true) + delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) + app.StakingKeeper.SetDelegation(ctx, delegation) + + val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) + _, err = app.StakingKeeper.Undelegate(ctx, val0AccAddr, addrVals[0], sdk.TokensFromConsensusPower(6).ToDec()) + require.NoError(t, err) + + // end block + updates := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 1, len(updates)) + + validator, found := app.StakingKeeper.GetValidator(ctx, addrVals[0]) + require.True(t, found) + require.Equal(t, sdk.TokensFromConsensusPower(14), validator.Tokens) + require.Equal(t, sdk.Unbonding, validator.Status) + require.True(t, validator.Jailed) +} + //func TestUndelegateFromUnbondingValidator(t *testing.T) { // ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) // delTokens := sdk.TokensFromConsensusPower(10) diff --git a/x/staking/keeper/old_delegation_test.go b/x/staking/keeper/old_delegation_test.go index 2e22045f707b..00a28864da5b 100644 --- a/x/staking/keeper/old_delegation_test.go +++ b/x/staking/keeper/old_delegation_test.go @@ -4,77 +4,12 @@ import ( "testing" "time" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" -) - -// test undelegating self delegation from a validator pushing it below MinSelfDelegation -// shift it from the bonded to unbonding state and jailed -func TestUndelegateSelfDelegationBelowMinSelfDelegation(t *testing.T) { - ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) - delTokens := sdk.TokensFromConsensusPower(10) - delCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), delTokens)) - - //create a validator with a self-delegation - validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) - - validator.MinSelfDelegation = delTokens - validator, issuedShares := validator.AddTokensFromDel(delTokens) - require.Equal(t, delTokens, issuedShares.RoundInt()) - - // add bonded tokens to pool for delegations - notBondedPool := keeper.GetNotBondedPool(ctx) - oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) - err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(delCoins...)) - require.NoError(t, err) - keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) - - validator = TestingUpdateValidator(keeper, ctx, validator, true) - require.True(t, validator.IsBonded()) - - selfDelegation := types.NewDelegation(sdk.AccAddress(addrVals[0].Bytes()), addrVals[0], issuedShares) - keeper.SetDelegation(ctx, selfDelegation) - - // add bonded tokens to pool for delegations - bondedPool := keeper.GetBondedPool(ctx) - oldBonded := bk.GetAllBalances(ctx, bondedPool.GetAddress()) - err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) - require.NoError(t, err) - keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) - - // create a second delegation to this validator - keeper.DeleteValidatorByPowerIndex(ctx, validator) - validator, issuedShares = validator.AddTokensFromDel(delTokens) - require.True(t, validator.IsBonded()) - require.Equal(t, delTokens, issuedShares.RoundInt()) - - // add bonded tokens to pool for delegations - oldBonded = bk.GetAllBalances(ctx, bondedPool.GetAddress()) - err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) - require.NoError(t, err) - keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) - - validator = TestingUpdateValidator(keeper, ctx, validator, true) - delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) - keeper.SetDelegation(ctx, delegation) - - val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) - _, err = keeper.Undelegate(ctx, val0AccAddr, addrVals[0], sdk.TokensFromConsensusPower(6).ToDec()) - require.NoError(t, err) - - // end block - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 1, len(updates)) - validator, found := keeper.GetValidator(ctx, addrVals[0]) - require.True(t, found) - require.Equal(t, sdk.TokensFromConsensusPower(14), validator.Tokens) - require.Equal(t, sdk.Unbonding, validator.Status) - require.True(t, validator.Jailed) -} + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/staking/types" +) func TestUndelegateFromUnbondingValidator(t *testing.T) { ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) From bbc2b33f7d8c9cb5169de8bc618fd540e365e863 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 24 Feb 2020 12:24:25 +0100 Subject: [PATCH 180/529] update TestUndelegate from unbonding validator and fix bug --- x/staking/keeper/delegation_test.go | 184 ++++++++++++------------ x/staking/keeper/old_delegation_test.go | 90 ------------ 2 files changed, 94 insertions(+), 180 deletions(-) diff --git a/x/staking/keeper/delegation_test.go b/x/staking/keeper/delegation_test.go index d4004fd0385d..073bc1b84634 100644 --- a/x/staking/keeper/delegation_test.go +++ b/x/staking/keeper/delegation_test.go @@ -4,6 +4,7 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/simapp" @@ -369,96 +370,99 @@ func TestUndelegateSelfDelegationBelowMinSelfDelegation(t *testing.T) { require.True(t, validator.Jailed) } -//func TestUndelegateFromUnbondingValidator(t *testing.T) { -// ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) -// delTokens := sdk.TokensFromConsensusPower(10) -// delCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), delTokens)) -// -// //create a validator with a self-delegation -// validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) -// -// validator, issuedShares := validator.AddTokensFromDel(delTokens) -// require.Equal(t, delTokens, issuedShares.RoundInt()) -// -// // add bonded tokens to pool for delegations -// notBondedPool := keeper.GetNotBondedPool(ctx) -// oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) -// err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(delCoins...)) -// require.NoError(t, err) -// keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) -// -// validator = TestingUpdateValidator(keeper, ctx, validator, true) -// require.True(t, validator.IsBonded()) -// -// selfDelegation := types.NewDelegation(sdk.AccAddress(addrVals[0].Bytes()), addrVals[0], issuedShares) -// keeper.SetDelegation(ctx, selfDelegation) -// -// bondedPool := keeper.GetBondedPool(ctx) -// oldBonded := bk.GetAllBalances(ctx, bondedPool.GetAddress()) -// err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) -// require.NoError(t, err) -// keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) -// -// // create a second delegation to this validator -// keeper.DeleteValidatorByPowerIndex(ctx, validator) -// -// validator, issuedShares = validator.AddTokensFromDel(delTokens) -// require.Equal(t, delTokens, issuedShares.RoundInt()) -// -// oldBonded = bk.GetAllBalances(ctx, bondedPool.GetAddress()) -// err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) -// require.NoError(t, err) -// keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) -// -// validator = TestingUpdateValidator(keeper, ctx, validator, true) -// delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) -// keeper.SetDelegation(ctx, delegation) -// -// oldBonded = bk.GetAllBalances(ctx, bondedPool.GetAddress()) -// err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) -// require.NoError(t, err) -// keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) -// -// header := ctx.BlockHeader() -// blockHeight := int64(10) -// header.Height = blockHeight -// blockTime := time.Unix(333, 0) -// header.Time = blockTime -// ctx = ctx.WithBlockHeader(header) -// -// // unbond the all self-delegation to put validator in unbonding state -// val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) -// _, err = keeper.Undelegate(ctx, val0AccAddr, addrVals[0], delTokens.ToDec()) -// require.NoError(t, err) -// -// // end block -// updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) -// require.Equal(t, 1, len(updates)) -// -// validator, found := keeper.GetValidator(ctx, addrVals[0]) -// require.True(t, found) -// require.Equal(t, blockHeight, validator.UnbondingHeight) -// params := keeper.GetParams(ctx) -// require.True(t, blockTime.Add(params.UnbondingTime).Equal(validator.UnbondingTime)) -// -// blockHeight2 := int64(20) -// blockTime2 := time.Unix(444, 0).UTC() -// ctx = ctx.WithBlockHeight(blockHeight2) -// ctx = ctx.WithBlockTime(blockTime2) -// -// // unbond some of the other delegation's shares -// _, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], sdk.NewDec(6)) -// require.NoError(t, err) -// -// // retrieve the unbonding delegation -// ubd, found := keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) -// require.True(t, found) -// require.Len(t, ubd.Entries, 1) -// require.True(t, ubd.Entries[0].Balance.Equal(sdk.NewInt(6))) -// assert.Equal(t, blockHeight2, ubd.Entries[0].CreationHeight) -// assert.True(t, blockTime2.Add(params.UnbondingTime).Equal(ubd.Entries[0].CompletionTime)) -//} -// +func TestUndelegateFromUnbondingValidator(t *testing.T) { + _, app, ctx := getBaseSimappWithCustomKeeper() + delTokens := sdk.TokensFromConsensusPower(10) + delCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), delTokens)) + + addrDels := simapp.AddTestAddrsIncremental(app, ctx, 2, sdk.NewInt(0)) + addrVals := simapp.ConvertAddrsToValAddrs(addrDels) + + //create a validator with a self-delegation + validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) + + validator, issuedShares := validator.AddTokensFromDel(delTokens) + require.Equal(t, delTokens, issuedShares.RoundInt()) + + // add bonded tokens to pool for delegations + notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) + oldNotBonded := app.BankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) + err := app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(delCoins...)) + require.NoError(t, err) + app.SupplyKeeper.SetModuleAccount(ctx, notBondedPool) + + validator = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator, true) + require.True(t, validator.IsBonded()) + + selfDelegation := types.NewDelegation(addrVals[0].Bytes(), addrVals[0], issuedShares) + app.StakingKeeper.SetDelegation(ctx, selfDelegation) + + bondedPool := app.StakingKeeper.GetBondedPool(ctx) + oldBonded := app.BankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + err = app.BankKeeper.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) + require.NoError(t, err) + app.SupplyKeeper.SetModuleAccount(ctx, bondedPool) + + // create a second delegation to this validator + app.StakingKeeper.DeleteValidatorByPowerIndex(ctx, validator) + + validator, issuedShares = validator.AddTokensFromDel(delTokens) + require.Equal(t, delTokens, issuedShares.RoundInt()) + + oldBonded = app.BankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + err = app.BankKeeper.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) + require.NoError(t, err) + app.SupplyKeeper.SetModuleAccount(ctx, bondedPool) + + validator = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator, true) + delegation := types.NewDelegation(addrDels[1], addrVals[0], issuedShares) + app.StakingKeeper.SetDelegation(ctx, delegation) + + oldBonded = app.BankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + err = app.BankKeeper.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) + require.NoError(t, err) + app.SupplyKeeper.SetModuleAccount(ctx, bondedPool) + + header := ctx.BlockHeader() + blockHeight := int64(10) + header.Height = blockHeight + blockTime := time.Unix(333, 0) + header.Time = blockTime + ctx = ctx.WithBlockHeader(header) + + // unbond the all self-delegation to put validator in unbonding state + val0AccAddr := sdk.AccAddress(addrVals[0]) + _, err = app.StakingKeeper.Undelegate(ctx, val0AccAddr, addrVals[0], delTokens.ToDec()) + require.NoError(t, err) + + // end block + updates := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 1, len(updates)) + + validator, found := app.StakingKeeper.GetValidator(ctx, addrVals[0]) + require.True(t, found) + require.Equal(t, blockHeight, validator.UnbondingHeight) + params := app.StakingKeeper.GetParams(ctx) + require.True(t, blockTime.Add(params.UnbondingTime).Equal(validator.UnbondingTime)) + + blockHeight2 := int64(20) + blockTime2 := time.Unix(444, 0).UTC() + ctx = ctx.WithBlockHeight(blockHeight2) + ctx = ctx.WithBlockTime(blockTime2) + + // unbond some of the other delegation's shares + _, err = app.StakingKeeper.Undelegate(ctx, addrDels[1], addrVals[0], sdk.NewDec(6)) + require.NoError(t, err) + + // retrieve the unbonding delegation + ubd, found := app.StakingKeeper.GetUnbondingDelegation(ctx, addrDels[1], addrVals[0]) + require.True(t, found) + require.Len(t, ubd.Entries, 1) + require.True(t, ubd.Entries[0].Balance.Equal(sdk.NewInt(6))) + assert.Equal(t, blockHeight2, ubd.Entries[0].CreationHeight) + assert.True(t, blockTime2.Add(params.UnbondingTime).Equal(ubd.Entries[0].CompletionTime)) +} + //func TestUndelegateFromUnbondedValidator(t *testing.T) { // ctx, _, bk, keeper, _ := CreateTestInput(t, false, 1) // delTokens := sdk.TokensFromConsensusPower(10) diff --git a/x/staking/keeper/old_delegation_test.go b/x/staking/keeper/old_delegation_test.go index 00a28864da5b..e4e2026425d3 100644 --- a/x/staking/keeper/old_delegation_test.go +++ b/x/staking/keeper/old_delegation_test.go @@ -11,96 +11,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking/types" ) -func TestUndelegateFromUnbondingValidator(t *testing.T) { - ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) - delTokens := sdk.TokensFromConsensusPower(10) - delCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), delTokens)) - - //create a validator with a self-delegation - validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) - - validator, issuedShares := validator.AddTokensFromDel(delTokens) - require.Equal(t, delTokens, issuedShares.RoundInt()) - - // add bonded tokens to pool for delegations - notBondedPool := keeper.GetNotBondedPool(ctx) - oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) - err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(delCoins...)) - require.NoError(t, err) - keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) - - validator = TestingUpdateValidator(keeper, ctx, validator, true) - require.True(t, validator.IsBonded()) - - selfDelegation := types.NewDelegation(sdk.AccAddress(addrVals[0].Bytes()), addrVals[0], issuedShares) - keeper.SetDelegation(ctx, selfDelegation) - - bondedPool := keeper.GetBondedPool(ctx) - oldBonded := bk.GetAllBalances(ctx, bondedPool.GetAddress()) - err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) - require.NoError(t, err) - keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) - - // create a second delegation to this validator - keeper.DeleteValidatorByPowerIndex(ctx, validator) - - validator, issuedShares = validator.AddTokensFromDel(delTokens) - require.Equal(t, delTokens, issuedShares.RoundInt()) - - oldBonded = bk.GetAllBalances(ctx, bondedPool.GetAddress()) - err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) - require.NoError(t, err) - keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) - - validator = TestingUpdateValidator(keeper, ctx, validator, true) - delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) - keeper.SetDelegation(ctx, delegation) - - oldBonded = bk.GetAllBalances(ctx, bondedPool.GetAddress()) - err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) - require.NoError(t, err) - keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) - - header := ctx.BlockHeader() - blockHeight := int64(10) - header.Height = blockHeight - blockTime := time.Unix(333, 0) - header.Time = blockTime - ctx = ctx.WithBlockHeader(header) - - // unbond the all self-delegation to put validator in unbonding state - val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) - _, err = keeper.Undelegate(ctx, val0AccAddr, addrVals[0], delTokens.ToDec()) - require.NoError(t, err) - - // end block - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 1, len(updates)) - - validator, found := keeper.GetValidator(ctx, addrVals[0]) - require.True(t, found) - require.Equal(t, blockHeight, validator.UnbondingHeight) - params := keeper.GetParams(ctx) - require.True(t, blockTime.Add(params.UnbondingTime).Equal(validator.UnbondingTime)) - - blockHeight2 := int64(20) - blockTime2 := time.Unix(444, 0).UTC() - ctx = ctx.WithBlockHeight(blockHeight2) - ctx = ctx.WithBlockTime(blockTime2) - - // unbond some of the other delegation's shares - _, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], sdk.NewDec(6)) - require.NoError(t, err) - - // retrieve the unbonding delegation - ubd, found := keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) - require.True(t, found) - require.Len(t, ubd.Entries, 1) - require.True(t, ubd.Entries[0].Balance.Equal(sdk.NewInt(6))) - assert.Equal(t, blockHeight2, ubd.Entries[0].CreationHeight) - assert.True(t, blockTime2.Add(params.UnbondingTime).Equal(ubd.Entries[0].CompletionTime)) -} - func TestUndelegateFromUnbondedValidator(t *testing.T) { ctx, _, bk, keeper, _ := CreateTestInput(t, false, 1) delTokens := sdk.TokensFromConsensusPower(10) From 6ce12184d4621ad234187322650e87b4738a6dba Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 24 Feb 2020 12:37:32 +0100 Subject: [PATCH 181/529] refactor TestUndelegateFromUnbondedValidator to use simapp --- x/staking/keeper/delegation_test.go | 165 ++++++++++++------------ x/staking/keeper/old_delegation_test.go | 81 ------------ 2 files changed, 84 insertions(+), 162 deletions(-) diff --git a/x/staking/keeper/delegation_test.go b/x/staking/keeper/delegation_test.go index 073bc1b84634..63e8e8fd7229 100644 --- a/x/staking/keeper/delegation_test.go +++ b/x/staking/keeper/delegation_test.go @@ -463,87 +463,90 @@ func TestUndelegateFromUnbondingValidator(t *testing.T) { assert.True(t, blockTime2.Add(params.UnbondingTime).Equal(ubd.Entries[0].CompletionTime)) } -//func TestUndelegateFromUnbondedValidator(t *testing.T) { -// ctx, _, bk, keeper, _ := CreateTestInput(t, false, 1) -// delTokens := sdk.TokensFromConsensusPower(10) -// delCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), delTokens)) -// -// // add bonded tokens to pool for delegations -// notBondedPool := keeper.GetNotBondedPool(ctx) -// oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) -// err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(delCoins...)) -// require.NoError(t, err) -// keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) -// -// // create a validator with a self-delegation -// validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) -// -// valTokens := sdk.TokensFromConsensusPower(10) -// validator, issuedShares := validator.AddTokensFromDel(valTokens) -// require.Equal(t, valTokens, issuedShares.RoundInt()) -// validator = TestingUpdateValidator(keeper, ctx, validator, true) -// require.True(t, validator.IsBonded()) -// -// val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) -// selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) -// keeper.SetDelegation(ctx, selfDelegation) -// -// bondedPool := keeper.GetBondedPool(ctx) -// oldBonded := bk.GetAllBalances(ctx, bondedPool.GetAddress()) -// err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) -// require.NoError(t, err) -// keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) -// -// // create a second delegation to this validator -// keeper.DeleteValidatorByPowerIndex(ctx, validator) -// validator, issuedShares = validator.AddTokensFromDel(delTokens) -// require.Equal(t, delTokens, issuedShares.RoundInt()) -// validator = TestingUpdateValidator(keeper, ctx, validator, true) -// require.True(t, validator.IsBonded()) -// delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) -// keeper.SetDelegation(ctx, delegation) -// -// ctx = ctx.WithBlockHeight(10) -// ctx = ctx.WithBlockTime(time.Unix(333, 0)) -// -// // unbond the all self-delegation to put validator in unbonding state -// _, err = keeper.Undelegate(ctx, val0AccAddr, addrVals[0], valTokens.ToDec()) -// require.NoError(t, err) -// -// // end block -// updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) -// require.Equal(t, 1, len(updates)) -// -// validator, found := keeper.GetValidator(ctx, addrVals[0]) -// require.True(t, found) -// require.Equal(t, ctx.BlockHeight(), validator.UnbondingHeight) -// params := keeper.GetParams(ctx) -// require.True(t, ctx.BlockHeader().Time.Add(params.UnbondingTime).Equal(validator.UnbondingTime)) -// -// // unbond the validator -// ctx = ctx.WithBlockTime(validator.UnbondingTime) -// keeper.UnbondAllMatureValidatorQueue(ctx) -// -// // Make sure validator is still in state because there is still an outstanding delegation -// validator, found = keeper.GetValidator(ctx, addrVals[0]) -// require.True(t, found) -// require.Equal(t, validator.Status, sdk.Unbonded) -// -// // unbond some of the other delegation's shares -// unbondTokens := sdk.TokensFromConsensusPower(6) -// _, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], unbondTokens.ToDec()) -// require.NoError(t, err) -// -// // unbond rest of the other delegation's shares -// remainingTokens := delTokens.Sub(unbondTokens) -// _, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], remainingTokens.ToDec()) -// require.NoError(t, err) -// -// // now validator should now be deleted from state -// validator, found = keeper.GetValidator(ctx, addrVals[0]) -// require.False(t, found, "%v", validator) -//} -// +func TestUndelegateFromUnbondedValidator(t *testing.T) { + _, app, ctx := getBaseSimappWithCustomKeeper() + delTokens := sdk.TokensFromConsensusPower(10) + delCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), delTokens)) + + addrDels := simapp.AddTestAddrsIncremental(app, ctx, 2, sdk.NewInt(0)) + addrVals := simapp.ConvertAddrsToValAddrs(addrDels) + + // add bonded tokens to pool for delegations + notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) + oldNotBonded := app.BankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) + err := app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(delCoins...)) + require.NoError(t, err) + app.SupplyKeeper.SetModuleAccount(ctx, notBondedPool) + + // create a validator with a self-delegation + validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) + + valTokens := sdk.TokensFromConsensusPower(10) + validator, issuedShares := validator.AddTokensFromDel(valTokens) + require.Equal(t, valTokens, issuedShares.RoundInt()) + validator = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator, true) + require.True(t, validator.IsBonded()) + + val0AccAddr := sdk.AccAddress(addrVals[0]) + selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) + app.StakingKeeper.SetDelegation(ctx, selfDelegation) + + bondedPool := app.StakingKeeper.GetBondedPool(ctx) + oldBonded := app.BankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + err = app.BankKeeper.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) + require.NoError(t, err) + app.SupplyKeeper.SetModuleAccount(ctx, bondedPool) + + // create a second delegation to this validator + app.StakingKeeper.DeleteValidatorByPowerIndex(ctx, validator) + validator, issuedShares = validator.AddTokensFromDel(delTokens) + require.Equal(t, delTokens, issuedShares.RoundInt()) + validator = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator, true) + require.True(t, validator.IsBonded()) + delegation := types.NewDelegation(addrDels[1], addrVals[0], issuedShares) + app.StakingKeeper.SetDelegation(ctx, delegation) + + ctx = ctx.WithBlockHeight(10) + ctx = ctx.WithBlockTime(time.Unix(333, 0)) + + // unbond the all self-delegation to put validator in unbonding state + _, err = app.StakingKeeper.Undelegate(ctx, val0AccAddr, addrVals[0], valTokens.ToDec()) + require.NoError(t, err) + + // end block + updates := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 1, len(updates)) + + validator, found := app.StakingKeeper.GetValidator(ctx, addrVals[0]) + require.True(t, found) + require.Equal(t, ctx.BlockHeight(), validator.UnbondingHeight) + params := app.StakingKeeper.GetParams(ctx) + require.True(t, ctx.BlockHeader().Time.Add(params.UnbondingTime).Equal(validator.UnbondingTime)) + + // unbond the validator + ctx = ctx.WithBlockTime(validator.UnbondingTime) + app.StakingKeeper.UnbondAllMatureValidatorQueue(ctx) + + // Make sure validator is still in state because there is still an outstanding delegation + validator, found = app.StakingKeeper.GetValidator(ctx, addrVals[0]) + require.True(t, found) + require.Equal(t, validator.Status, sdk.Unbonded) + + // unbond some of the other delegation's shares + unbondTokens := sdk.TokensFromConsensusPower(6) + _, err = app.StakingKeeper.Undelegate(ctx, addrDels[1], addrVals[0], unbondTokens.ToDec()) + require.NoError(t, err) + + // unbond rest of the other delegation's shares + remainingTokens := delTokens.Sub(unbondTokens) + _, err = app.StakingKeeper.Undelegate(ctx, addrDels[1], addrVals[0], remainingTokens.ToDec()) + require.NoError(t, err) + + // now validator should now be deleted from state + validator, found = app.StakingKeeper.GetValidator(ctx, addrVals[0]) + require.False(t, found, "%v", validator) +} + //func TestUnbondingAllDelegationFromValidator(t *testing.T) { // ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) // delTokens := sdk.TokensFromConsensusPower(10) diff --git a/x/staking/keeper/old_delegation_test.go b/x/staking/keeper/old_delegation_test.go index e4e2026425d3..7b31fc5cb9a2 100644 --- a/x/staking/keeper/old_delegation_test.go +++ b/x/staking/keeper/old_delegation_test.go @@ -11,87 +11,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking/types" ) -func TestUndelegateFromUnbondedValidator(t *testing.T) { - ctx, _, bk, keeper, _ := CreateTestInput(t, false, 1) - delTokens := sdk.TokensFromConsensusPower(10) - delCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), delTokens)) - - // add bonded tokens to pool for delegations - notBondedPool := keeper.GetNotBondedPool(ctx) - oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) - err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(delCoins...)) - require.NoError(t, err) - keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) - - // create a validator with a self-delegation - validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) - - valTokens := sdk.TokensFromConsensusPower(10) - validator, issuedShares := validator.AddTokensFromDel(valTokens) - require.Equal(t, valTokens, issuedShares.RoundInt()) - validator = TestingUpdateValidator(keeper, ctx, validator, true) - require.True(t, validator.IsBonded()) - - val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) - selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) - keeper.SetDelegation(ctx, selfDelegation) - - bondedPool := keeper.GetBondedPool(ctx) - oldBonded := bk.GetAllBalances(ctx, bondedPool.GetAddress()) - err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) - require.NoError(t, err) - keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) - - // create a second delegation to this validator - keeper.DeleteValidatorByPowerIndex(ctx, validator) - validator, issuedShares = validator.AddTokensFromDel(delTokens) - require.Equal(t, delTokens, issuedShares.RoundInt()) - validator = TestingUpdateValidator(keeper, ctx, validator, true) - require.True(t, validator.IsBonded()) - delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) - keeper.SetDelegation(ctx, delegation) - - ctx = ctx.WithBlockHeight(10) - ctx = ctx.WithBlockTime(time.Unix(333, 0)) - - // unbond the all self-delegation to put validator in unbonding state - _, err = keeper.Undelegate(ctx, val0AccAddr, addrVals[0], valTokens.ToDec()) - require.NoError(t, err) - - // end block - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 1, len(updates)) - - validator, found := keeper.GetValidator(ctx, addrVals[0]) - require.True(t, found) - require.Equal(t, ctx.BlockHeight(), validator.UnbondingHeight) - params := keeper.GetParams(ctx) - require.True(t, ctx.BlockHeader().Time.Add(params.UnbondingTime).Equal(validator.UnbondingTime)) - - // unbond the validator - ctx = ctx.WithBlockTime(validator.UnbondingTime) - keeper.UnbondAllMatureValidatorQueue(ctx) - - // Make sure validator is still in state because there is still an outstanding delegation - validator, found = keeper.GetValidator(ctx, addrVals[0]) - require.True(t, found) - require.Equal(t, validator.Status, sdk.Unbonded) - - // unbond some of the other delegation's shares - unbondTokens := sdk.TokensFromConsensusPower(6) - _, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], unbondTokens.ToDec()) - require.NoError(t, err) - - // unbond rest of the other delegation's shares - remainingTokens := delTokens.Sub(unbondTokens) - _, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], remainingTokens.ToDec()) - require.NoError(t, err) - - // now validator should now be deleted from state - validator, found = keeper.GetValidator(ctx, addrVals[0]) - require.False(t, found, "%v", validator) -} - func TestUnbondingAllDelegationFromValidator(t *testing.T) { ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) delTokens := sdk.TokensFromConsensusPower(10) From 62dbd8bcee9d53d49449432e4a059db52c2ae41e Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 24 Feb 2020 12:46:14 +0100 Subject: [PATCH 182/529] TestUnbondingAllDelegationFromValidator to use simapp --- x/staking/keeper/delegation_test.go | 147 ++++++++++++------------ x/staking/keeper/old_delegation_test.go | 72 ------------ 2 files changed, 75 insertions(+), 144 deletions(-) diff --git a/x/staking/keeper/delegation_test.go b/x/staking/keeper/delegation_test.go index 63e8e8fd7229..3250b0c2196b 100644 --- a/x/staking/keeper/delegation_test.go +++ b/x/staking/keeper/delegation_test.go @@ -547,78 +547,81 @@ func TestUndelegateFromUnbondedValidator(t *testing.T) { require.False(t, found, "%v", validator) } -//func TestUnbondingAllDelegationFromValidator(t *testing.T) { -// ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) -// delTokens := sdk.TokensFromConsensusPower(10) -// delCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), delTokens)) -// -// // add bonded tokens to pool for delegations -// notBondedPool := keeper.GetNotBondedPool(ctx) -// oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) -// err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(delCoins...)) -// require.NoError(t, err) -// keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) -// -// //create a validator with a self-delegation -// validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) -// -// valTokens := sdk.TokensFromConsensusPower(10) -// validator, issuedShares := validator.AddTokensFromDel(valTokens) -// require.Equal(t, valTokens, issuedShares.RoundInt()) -// -// validator = TestingUpdateValidator(keeper, ctx, validator, true) -// require.True(t, validator.IsBonded()) -// val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) -// -// selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) -// keeper.SetDelegation(ctx, selfDelegation) -// -// // create a second delegation to this validator -// keeper.DeleteValidatorByPowerIndex(ctx, validator) -// validator, issuedShares = validator.AddTokensFromDel(delTokens) -// require.Equal(t, delTokens, issuedShares.RoundInt()) -// -// bondedPool := keeper.GetBondedPool(ctx) -// oldBonded := bk.GetAllBalances(ctx, bondedPool.GetAddress()) -// err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) -// require.NoError(t, err) -// keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) -// -// validator = TestingUpdateValidator(keeper, ctx, validator, true) -// require.True(t, validator.IsBonded()) -// -// delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) -// keeper.SetDelegation(ctx, delegation) -// -// ctx = ctx.WithBlockHeight(10) -// ctx = ctx.WithBlockTime(time.Unix(333, 0)) -// -// // unbond the all self-delegation to put validator in unbonding state -// _, err = keeper.Undelegate(ctx, val0AccAddr, addrVals[0], valTokens.ToDec()) -// require.NoError(t, err) -// -// // end block -// updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) -// require.Equal(t, 1, len(updates)) -// -// // unbond all the remaining delegation -// _, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], delTokens.ToDec()) -// require.NoError(t, err) -// -// // validator should still be in state and still be in unbonding state -// validator, found := keeper.GetValidator(ctx, addrVals[0]) -// require.True(t, found) -// require.Equal(t, validator.Status, sdk.Unbonding) -// -// // unbond the validator -// ctx = ctx.WithBlockTime(validator.UnbondingTime) -// keeper.UnbondAllMatureValidatorQueue(ctx) -// -// // validator should now be deleted from state -// _, found = keeper.GetValidator(ctx, addrVals[0]) -// require.False(t, found) -//} -// +func TestUnbondingAllDelegationFromValidator(t *testing.T) { + _, app, ctx := getBaseSimappWithCustomKeeper() + delTokens := sdk.TokensFromConsensusPower(10) + delCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), delTokens)) + + addrDels := simapp.AddTestAddrsIncremental(app, ctx, 2, sdk.NewInt(0)) + addrVals := simapp.ConvertAddrsToValAddrs(addrDels) + + // add bonded tokens to pool for delegations + notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) + oldNotBonded := app.BankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) + err := app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(delCoins...)) + require.NoError(t, err) + app.SupplyKeeper.SetModuleAccount(ctx, notBondedPool) + + //create a validator with a self-delegation + validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) + + valTokens := sdk.TokensFromConsensusPower(10) + validator, issuedShares := validator.AddTokensFromDel(valTokens) + require.Equal(t, valTokens, issuedShares.RoundInt()) + + validator = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator, true) + require.True(t, validator.IsBonded()) + val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) + + selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) + app.StakingKeeper.SetDelegation(ctx, selfDelegation) + + // create a second delegation to this validator + app.StakingKeeper.DeleteValidatorByPowerIndex(ctx, validator) + validator, issuedShares = validator.AddTokensFromDel(delTokens) + require.Equal(t, delTokens, issuedShares.RoundInt()) + + bondedPool := app.StakingKeeper.GetBondedPool(ctx) + oldBonded := app.BankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + err = app.BankKeeper.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) + require.NoError(t, err) + app.SupplyKeeper.SetModuleAccount(ctx, bondedPool) + + validator = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator, true) + require.True(t, validator.IsBonded()) + + delegation := types.NewDelegation(addrDels[1], addrVals[0], issuedShares) + app.StakingKeeper.SetDelegation(ctx, delegation) + + ctx = ctx.WithBlockHeight(10) + ctx = ctx.WithBlockTime(time.Unix(333, 0)) + + // unbond the all self-delegation to put validator in unbonding state + _, err = app.StakingKeeper.Undelegate(ctx, val0AccAddr, addrVals[0], valTokens.ToDec()) + require.NoError(t, err) + + // end block + updates := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 1, len(updates)) + + // unbond all the remaining delegation + _, err = app.StakingKeeper.Undelegate(ctx, addrDels[1], addrVals[0], delTokens.ToDec()) + require.NoError(t, err) + + // validator should still be in state and still be in unbonding state + validator, found := app.StakingKeeper.GetValidator(ctx, addrVals[0]) + require.True(t, found) + require.Equal(t, validator.Status, sdk.Unbonding) + + // unbond the validator + ctx = ctx.WithBlockTime(validator.UnbondingTime) + app.StakingKeeper.UnbondAllMatureValidatorQueue(ctx) + + // validator should now be deleted from state + _, found = app.StakingKeeper.GetValidator(ctx, addrVals[0]) + require.False(t, found) +} + //// Make sure that that the retrieving the delegations doesn't affect the state //func TestGetRedelegationsFromSrcValidator(t *testing.T) { // ctx, _, _, keeper, _ := CreateTestInput(t, false, 0) diff --git a/x/staking/keeper/old_delegation_test.go b/x/staking/keeper/old_delegation_test.go index 7b31fc5cb9a2..03ec0f233c36 100644 --- a/x/staking/keeper/old_delegation_test.go +++ b/x/staking/keeper/old_delegation_test.go @@ -11,78 +11,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking/types" ) -func TestUnbondingAllDelegationFromValidator(t *testing.T) { - ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) - delTokens := sdk.TokensFromConsensusPower(10) - delCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), delTokens)) - - // add bonded tokens to pool for delegations - notBondedPool := keeper.GetNotBondedPool(ctx) - oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) - err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(delCoins...)) - require.NoError(t, err) - keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) - - //create a validator with a self-delegation - validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) - - valTokens := sdk.TokensFromConsensusPower(10) - validator, issuedShares := validator.AddTokensFromDel(valTokens) - require.Equal(t, valTokens, issuedShares.RoundInt()) - - validator = TestingUpdateValidator(keeper, ctx, validator, true) - require.True(t, validator.IsBonded()) - val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) - - selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) - keeper.SetDelegation(ctx, selfDelegation) - - // create a second delegation to this validator - keeper.DeleteValidatorByPowerIndex(ctx, validator) - validator, issuedShares = validator.AddTokensFromDel(delTokens) - require.Equal(t, delTokens, issuedShares.RoundInt()) - - bondedPool := keeper.GetBondedPool(ctx) - oldBonded := bk.GetAllBalances(ctx, bondedPool.GetAddress()) - err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) - require.NoError(t, err) - keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) - - validator = TestingUpdateValidator(keeper, ctx, validator, true) - require.True(t, validator.IsBonded()) - - delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) - keeper.SetDelegation(ctx, delegation) - - ctx = ctx.WithBlockHeight(10) - ctx = ctx.WithBlockTime(time.Unix(333, 0)) - - // unbond the all self-delegation to put validator in unbonding state - _, err = keeper.Undelegate(ctx, val0AccAddr, addrVals[0], valTokens.ToDec()) - require.NoError(t, err) - - // end block - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 1, len(updates)) - - // unbond all the remaining delegation - _, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], delTokens.ToDec()) - require.NoError(t, err) - - // validator should still be in state and still be in unbonding state - validator, found := keeper.GetValidator(ctx, addrVals[0]) - require.True(t, found) - require.Equal(t, validator.Status, sdk.Unbonding) - - // unbond the validator - ctx = ctx.WithBlockTime(validator.UnbondingTime) - keeper.UnbondAllMatureValidatorQueue(ctx) - - // validator should now be deleted from state - _, found = keeper.GetValidator(ctx, addrVals[0]) - require.False(t, found) -} - // Make sure that that the retrieving the delegations doesn't affect the state func TestGetRedelegationsFromSrcValidator(t *testing.T) { ctx, _, _, keeper, _ := CreateTestInput(t, false, 0) From 9a5aae9f0e2ea03cee435d8d9725fd0a25b1228e Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 24 Feb 2020 12:50:02 +0100 Subject: [PATCH 183/529] refactor TestGetRedelegationsFromSrcValidator to use simapp --- x/staking/keeper/delegation_test.go | 51 +++++++++++++------------ x/staking/keeper/old_delegation_test.go | 24 ------------ 2 files changed, 27 insertions(+), 48 deletions(-) diff --git a/x/staking/keeper/delegation_test.go b/x/staking/keeper/delegation_test.go index 3250b0c2196b..bbcf4aa4d8bd 100644 --- a/x/staking/keeper/delegation_test.go +++ b/x/staking/keeper/delegation_test.go @@ -622,30 +622,33 @@ func TestUnbondingAllDelegationFromValidator(t *testing.T) { require.False(t, found) } -//// Make sure that that the retrieving the delegations doesn't affect the state -//func TestGetRedelegationsFromSrcValidator(t *testing.T) { -// ctx, _, _, keeper, _ := CreateTestInput(t, false, 0) -// -// rd := types.NewRedelegation(addrDels[0], addrVals[0], addrVals[1], 0, -// time.Unix(0, 0), sdk.NewInt(5), -// sdk.NewDec(5)) -// -// // set and retrieve a record -// keeper.SetRedelegation(ctx, rd) -// resBond, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) -// require.True(t, found) -// -// // get the redelegations one time -// redelegations := keeper.GetRedelegationsFromSrcValidator(ctx, addrVals[0]) -// require.Equal(t, 1, len(redelegations)) -// require.True(t, redelegations[0].Equal(resBond)) -// -// // get the redelegations a second time, should be exactly the same -// redelegations = keeper.GetRedelegationsFromSrcValidator(ctx, addrVals[0]) -// require.Equal(t, 1, len(redelegations)) -// require.True(t, redelegations[0].Equal(resBond)) -//} -// +// Make sure that that the retrieving the delegations doesn't affect the state +func TestGetRedelegationsFromSrcValidator(t *testing.T) { + _, app, ctx := getBaseSimappWithCustomKeeper() + + addrDels := simapp.AddTestAddrsIncremental(app, ctx, 2, sdk.NewInt(0)) + addrVals := simapp.ConvertAddrsToValAddrs(addrDels) + + rd := types.NewRedelegation(addrDels[0], addrVals[0], addrVals[1], 0, + time.Unix(0, 0), sdk.NewInt(5), + sdk.NewDec(5)) + + // set and retrieve a record + app.StakingKeeper.SetRedelegation(ctx, rd) + resBond, found := app.StakingKeeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) + require.True(t, found) + + // get the redelegations one time + redelegations := app.StakingKeeper.GetRedelegationsFromSrcValidator(ctx, addrVals[0]) + require.Equal(t, 1, len(redelegations)) + require.True(t, redelegations[0].Equal(resBond)) + + // get the redelegations a second time, should be exactly the same + redelegations = app.StakingKeeper.GetRedelegationsFromSrcValidator(ctx, addrVals[0]) + require.Equal(t, 1, len(redelegations)) + require.True(t, redelegations[0].Equal(resBond)) +} + //// tests Get/Set/Remove/Has UnbondingDelegation //func TestRedelegation(t *testing.T) { // ctx, _, _, keeper, _ := CreateTestInput(t, false, 0) diff --git a/x/staking/keeper/old_delegation_test.go b/x/staking/keeper/old_delegation_test.go index 03ec0f233c36..256c4e1928c8 100644 --- a/x/staking/keeper/old_delegation_test.go +++ b/x/staking/keeper/old_delegation_test.go @@ -11,30 +11,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking/types" ) -// Make sure that that the retrieving the delegations doesn't affect the state -func TestGetRedelegationsFromSrcValidator(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 0) - - rd := types.NewRedelegation(addrDels[0], addrVals[0], addrVals[1], 0, - time.Unix(0, 0), sdk.NewInt(5), - sdk.NewDec(5)) - - // set and retrieve a record - keeper.SetRedelegation(ctx, rd) - resBond, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) - require.True(t, found) - - // get the redelegations one time - redelegations := keeper.GetRedelegationsFromSrcValidator(ctx, addrVals[0]) - require.Equal(t, 1, len(redelegations)) - require.True(t, redelegations[0].Equal(resBond)) - - // get the redelegations a second time, should be exactly the same - redelegations = keeper.GetRedelegationsFromSrcValidator(ctx, addrVals[0]) - require.Equal(t, 1, len(redelegations)) - require.True(t, redelegations[0].Equal(resBond)) -} - // tests Get/Set/Remove/Has UnbondingDelegation func TestRedelegation(t *testing.T) { ctx, _, _, keeper, _ := CreateTestInput(t, false, 0) From e33844fa56abafdccfbff6053d64e69f109102dd Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 24 Feb 2020 13:11:18 +0100 Subject: [PATCH 184/529] refactor TestRedelegation to use simapp --- x/staking/keeper/delegation_test.go | 122 ++++++++++++------------ x/staking/keeper/old_delegation_test.go | 61 ------------ 2 files changed, 61 insertions(+), 122 deletions(-) diff --git a/x/staking/keeper/delegation_test.go b/x/staking/keeper/delegation_test.go index bbcf4aa4d8bd..b211b5543473 100644 --- a/x/staking/keeper/delegation_test.go +++ b/x/staking/keeper/delegation_test.go @@ -649,67 +649,67 @@ func TestGetRedelegationsFromSrcValidator(t *testing.T) { require.True(t, redelegations[0].Equal(resBond)) } -//// tests Get/Set/Remove/Has UnbondingDelegation -//func TestRedelegation(t *testing.T) { -// ctx, _, _, keeper, _ := CreateTestInput(t, false, 0) -// -// rd := types.NewRedelegation(addrDels[0], addrVals[0], addrVals[1], 0, -// time.Unix(0, 0), sdk.NewInt(5), -// sdk.NewDec(5)) -// -// // test shouldn't have and redelegations -// has := keeper.HasReceivingRedelegation(ctx, addrDels[0], addrVals[1]) -// require.False(t, has) -// -// // set and retrieve a record -// keeper.SetRedelegation(ctx, rd) -// resRed, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) -// require.True(t, found) -// -// redelegations := keeper.GetRedelegationsFromSrcValidator(ctx, addrVals[0]) -// require.Equal(t, 1, len(redelegations)) -// require.True(t, redelegations[0].Equal(resRed)) -// -// redelegations = keeper.GetRedelegations(ctx, addrDels[0], 5) -// require.Equal(t, 1, len(redelegations)) -// require.True(t, redelegations[0].Equal(resRed)) -// -// redelegations = keeper.GetAllRedelegations(ctx, addrDels[0], nil, nil) -// require.Equal(t, 1, len(redelegations)) -// require.True(t, redelegations[0].Equal(resRed)) -// -// // check if has the redelegation -// has = keeper.HasReceivingRedelegation(ctx, addrDels[0], addrVals[1]) -// require.True(t, has) -// -// // modify a records, save, and retrieve -// rd.Entries[0].SharesDst = sdk.NewDec(21) -// keeper.SetRedelegation(ctx, rd) -// -// resRed, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) -// require.True(t, found) -// require.True(t, rd.Equal(resRed)) -// -// redelegations = keeper.GetRedelegationsFromSrcValidator(ctx, addrVals[0]) -// require.Equal(t, 1, len(redelegations)) -// require.True(t, redelegations[0].Equal(resRed)) -// -// redelegations = keeper.GetRedelegations(ctx, addrDels[0], 5) -// require.Equal(t, 1, len(redelegations)) -// require.True(t, redelegations[0].Equal(resRed)) -// -// // delete a record -// keeper.RemoveRedelegation(ctx, rd) -// _, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) -// require.False(t, found) -// -// redelegations = keeper.GetRedelegations(ctx, addrDels[0], 5) -// require.Equal(t, 0, len(redelegations)) -// -// redelegations = keeper.GetAllRedelegations(ctx, addrDels[0], nil, nil) -// require.Equal(t, 0, len(redelegations)) -//} -// +// tests Get/Set/Remove/Has UnbondingDelegation +func TestRedelegation(t *testing.T) { + _, app, ctx := getBaseSimappWithCustomKeeper() + + rd := types.NewRedelegation(addrDels[0], addrVals[0], addrVals[1], 0, + time.Unix(0, 0), sdk.NewInt(5), + sdk.NewDec(5)) + + // test shouldn't have and redelegations + has := app.StakingKeeper.HasReceivingRedelegation(ctx, addrDels[0], addrVals[1]) + require.False(t, has) + + // set and retrieve a record + app.StakingKeeper.SetRedelegation(ctx, rd) + resRed, found := app.StakingKeeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) + require.True(t, found) + + redelegations := app.StakingKeeper.GetRedelegationsFromSrcValidator(ctx, addrVals[0]) + require.Equal(t, 1, len(redelegations)) + require.True(t, redelegations[0].Equal(resRed)) + + redelegations = app.StakingKeeper.GetRedelegations(ctx, addrDels[0], 5) + require.Equal(t, 1, len(redelegations)) + require.True(t, redelegations[0].Equal(resRed)) + + redelegations = app.StakingKeeper.GetAllRedelegations(ctx, addrDels[0], nil, nil) + require.Equal(t, 1, len(redelegations)) + require.True(t, redelegations[0].Equal(resRed)) + + // check if has the redelegation + has = app.StakingKeeper.HasReceivingRedelegation(ctx, addrDels[0], addrVals[1]) + require.True(t, has) + + // modify a records, save, and retrieve + rd.Entries[0].SharesDst = sdk.NewDec(21) + app.StakingKeeper.SetRedelegation(ctx, rd) + + resRed, found = app.StakingKeeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) + require.True(t, found) + require.True(t, rd.Equal(resRed)) + + redelegations = app.StakingKeeper.GetRedelegationsFromSrcValidator(ctx, addrVals[0]) + require.Equal(t, 1, len(redelegations)) + require.True(t, redelegations[0].Equal(resRed)) + + redelegations = app.StakingKeeper.GetRedelegations(ctx, addrDels[0], 5) + require.Equal(t, 1, len(redelegations)) + require.True(t, redelegations[0].Equal(resRed)) + + // delete a record + app.StakingKeeper.RemoveRedelegation(ctx, rd) + _, found = app.StakingKeeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) + require.False(t, found) + + redelegations = app.StakingKeeper.GetRedelegations(ctx, addrDels[0], 5) + require.Equal(t, 0, len(redelegations)) + + redelegations = app.StakingKeeper.GetAllRedelegations(ctx, addrDels[0], nil, nil) + require.Equal(t, 0, len(redelegations)) +} + //func TestRedelegateToSameValidator(t *testing.T) { // ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) // valTokens := sdk.TokensFromConsensusPower(10) diff --git a/x/staking/keeper/old_delegation_test.go b/x/staking/keeper/old_delegation_test.go index 256c4e1928c8..48ba070e16f1 100644 --- a/x/staking/keeper/old_delegation_test.go +++ b/x/staking/keeper/old_delegation_test.go @@ -11,67 +11,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking/types" ) -// tests Get/Set/Remove/Has UnbondingDelegation -func TestRedelegation(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 0) - - rd := types.NewRedelegation(addrDels[0], addrVals[0], addrVals[1], 0, - time.Unix(0, 0), sdk.NewInt(5), - sdk.NewDec(5)) - - // test shouldn't have and redelegations - has := keeper.HasReceivingRedelegation(ctx, addrDels[0], addrVals[1]) - require.False(t, has) - - // set and retrieve a record - keeper.SetRedelegation(ctx, rd) - resRed, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) - require.True(t, found) - - redelegations := keeper.GetRedelegationsFromSrcValidator(ctx, addrVals[0]) - require.Equal(t, 1, len(redelegations)) - require.True(t, redelegations[0].Equal(resRed)) - - redelegations = keeper.GetRedelegations(ctx, addrDels[0], 5) - require.Equal(t, 1, len(redelegations)) - require.True(t, redelegations[0].Equal(resRed)) - - redelegations = keeper.GetAllRedelegations(ctx, addrDels[0], nil, nil) - require.Equal(t, 1, len(redelegations)) - require.True(t, redelegations[0].Equal(resRed)) - - // check if has the redelegation - has = keeper.HasReceivingRedelegation(ctx, addrDels[0], addrVals[1]) - require.True(t, has) - - // modify a records, save, and retrieve - rd.Entries[0].SharesDst = sdk.NewDec(21) - keeper.SetRedelegation(ctx, rd) - - resRed, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) - require.True(t, found) - require.True(t, rd.Equal(resRed)) - - redelegations = keeper.GetRedelegationsFromSrcValidator(ctx, addrVals[0]) - require.Equal(t, 1, len(redelegations)) - require.True(t, redelegations[0].Equal(resRed)) - - redelegations = keeper.GetRedelegations(ctx, addrDels[0], 5) - require.Equal(t, 1, len(redelegations)) - require.True(t, redelegations[0].Equal(resRed)) - - // delete a record - keeper.RemoveRedelegation(ctx, rd) - _, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) - require.False(t, found) - - redelegations = keeper.GetRedelegations(ctx, addrDels[0], 5) - require.Equal(t, 0, len(redelegations)) - - redelegations = keeper.GetAllRedelegations(ctx, addrDels[0], nil, nil) - require.Equal(t, 0, len(redelegations)) -} - func TestRedelegateToSameValidator(t *testing.T) { ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) valTokens := sdk.TokensFromConsensusPower(10) From 27e20236a358259d788e088b570b1ff01d919be6 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 24 Feb 2020 13:16:32 +0100 Subject: [PATCH 185/529] refactor TestRedelegateToSameValidator to use simapp --- x/staking/keeper/delegation_test.go | 61 ++++++++++++++----------- x/staking/keeper/old_delegation_test.go | 27 ----------- 2 files changed, 34 insertions(+), 54 deletions(-) diff --git a/x/staking/keeper/delegation_test.go b/x/staking/keeper/delegation_test.go index b211b5543473..e340d97d464d 100644 --- a/x/staking/keeper/delegation_test.go +++ b/x/staking/keeper/delegation_test.go @@ -653,6 +653,9 @@ func TestGetRedelegationsFromSrcValidator(t *testing.T) { func TestRedelegation(t *testing.T) { _, app, ctx := getBaseSimappWithCustomKeeper() + addrDels := simapp.AddTestAddrsIncremental(app, ctx, 2, sdk.NewInt(0)) + addrVals := simapp.ConvertAddrsToValAddrs(addrDels) + rd := types.NewRedelegation(addrDels[0], addrVals[0], addrVals[1], 0, time.Unix(0, 0), sdk.NewInt(5), sdk.NewDec(5)) @@ -710,33 +713,37 @@ func TestRedelegation(t *testing.T) { require.Equal(t, 0, len(redelegations)) } -//func TestRedelegateToSameValidator(t *testing.T) { -// ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) -// valTokens := sdk.TokensFromConsensusPower(10) -// startCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), valTokens)) -// -// // add bonded tokens to pool for delegations -// notBondedPool := keeper.GetNotBondedPool(ctx) -// oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) -// err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) -// require.NoError(t, err) -// keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) -// -// // create a validator with a self-delegation -// validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) -// validator, issuedShares := validator.AddTokensFromDel(valTokens) -// require.Equal(t, valTokens, issuedShares.RoundInt()) -// validator = TestingUpdateValidator(keeper, ctx, validator, true) -// require.True(t, validator.IsBonded()) -// -// val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) -// selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) -// keeper.SetDelegation(ctx, selfDelegation) -// -// _, err = keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[0], sdk.NewDec(5)) -// require.Error(t, err) -//} -// +func TestRedelegateToSameValidator(t *testing.T) { + _, app, ctx := getBaseSimappWithCustomKeeper() + + addrDels := simapp.AddTestAddrsIncremental(app, ctx, 1, sdk.NewInt(0)) + addrVals := simapp.ConvertAddrsToValAddrs(addrDels) + + valTokens := sdk.TokensFromConsensusPower(10) + startCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), valTokens)) + + // add bonded tokens to pool for delegations + notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) + oldNotBonded := app.BankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) + err := app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) + require.NoError(t, err) + app.SupplyKeeper.SetModuleAccount(ctx, notBondedPool) + + // create a validator with a self-delegation + validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) + validator, issuedShares := validator.AddTokensFromDel(valTokens) + require.Equal(t, valTokens, issuedShares.RoundInt()) + validator = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator, true) + require.True(t, validator.IsBonded()) + + val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) + selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) + app.StakingKeeper.SetDelegation(ctx, selfDelegation) + + _, err = app.StakingKeeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[0], sdk.NewDec(5)) + require.Error(t, err) +} + //func TestRedelegationMaxEntries(t *testing.T) { // ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) // startTokens := sdk.TokensFromConsensusPower(20) diff --git a/x/staking/keeper/old_delegation_test.go b/x/staking/keeper/old_delegation_test.go index 48ba070e16f1..3e061619d559 100644 --- a/x/staking/keeper/old_delegation_test.go +++ b/x/staking/keeper/old_delegation_test.go @@ -11,33 +11,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking/types" ) -func TestRedelegateToSameValidator(t *testing.T) { - ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) - valTokens := sdk.TokensFromConsensusPower(10) - startCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), valTokens)) - - // add bonded tokens to pool for delegations - notBondedPool := keeper.GetNotBondedPool(ctx) - oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) - err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) - require.NoError(t, err) - keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) - - // create a validator with a self-delegation - validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) - validator, issuedShares := validator.AddTokensFromDel(valTokens) - require.Equal(t, valTokens, issuedShares.RoundInt()) - validator = TestingUpdateValidator(keeper, ctx, validator, true) - require.True(t, validator.IsBonded()) - - val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) - selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) - keeper.SetDelegation(ctx, selfDelegation) - - _, err = keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[0], sdk.NewDec(5)) - require.Error(t, err) -} - func TestRedelegationMaxEntries(t *testing.T) { ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) startTokens := sdk.TokensFromConsensusPower(20) From ae44324d5a9acd25dfa4cccde2b0d746889eaf9f Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 24 Feb 2020 15:06:12 +0100 Subject: [PATCH 186/529] refacotr TestRedelegationMaxEntries to use simapp --- x/staking/keeper/delegation_test.go | 58 +++++++++++++++++++++++++ x/staking/keeper/old_delegation_test.go | 54 ----------------------- 2 files changed, 58 insertions(+), 54 deletions(-) diff --git a/x/staking/keeper/delegation_test.go b/x/staking/keeper/delegation_test.go index e340d97d464d..a73447cd2b7d 100644 --- a/x/staking/keeper/delegation_test.go +++ b/x/staking/keeper/delegation_test.go @@ -744,6 +744,64 @@ func TestRedelegateToSameValidator(t *testing.T) { require.Error(t, err) } +func TestRedelegationMaxEntries(t *testing.T) { + _, app, ctx := getBaseSimappWithCustomKeeper() + + addrDels := simapp.AddTestAddrsIncremental(app, ctx, 2, sdk.NewInt(0)) + addrVals := simapp.ConvertAddrsToValAddrs(addrDels) + + startTokens := sdk.TokensFromConsensusPower(20) + startCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), startTokens)) + + // add bonded tokens to pool for delegations + notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) + oldNotBonded := app.BankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) + err := app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) + require.NoError(t, err) + app.SupplyKeeper.SetModuleAccount(ctx, notBondedPool) + + // create a validator with a self-delegation + validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) + valTokens := sdk.TokensFromConsensusPower(10) + validator, issuedShares := validator.AddTokensFromDel(valTokens) + require.Equal(t, valTokens, issuedShares.RoundInt()) + validator = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator, true) + val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) + selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) + app.StakingKeeper.SetDelegation(ctx, selfDelegation) + + // create a second validator + validator2 := types.NewValidator(addrVals[1], PKs[1], types.Description{}) + validator2, issuedShares = validator2.AddTokensFromDel(valTokens) + require.Equal(t, valTokens, issuedShares.RoundInt()) + + validator2 = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator2, true) + require.Equal(t, sdk.Bonded, validator2.Status) + + maxEntries := app.StakingKeeper.MaxEntries(ctx) + + // redelegations should pass + var completionTime time.Time + for i := uint32(0); i < maxEntries; i++ { + var err error + completionTime, err = app.StakingKeeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1], sdk.NewDec(1)) + require.NoError(t, err) + } + + // an additional redelegation should fail due to max entries + _, err = app.StakingKeeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1], sdk.NewDec(1)) + require.Error(t, err) + + // mature redelegations + ctx = ctx.WithBlockTime(completionTime) + err = app.StakingKeeper.CompleteRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1]) + require.NoError(t, err) + + // redelegation should work again + _, err = app.StakingKeeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1], sdk.NewDec(1)) + require.NoError(t, err) +} + //func TestRedelegationMaxEntries(t *testing.T) { // ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) // startTokens := sdk.TokensFromConsensusPower(20) diff --git a/x/staking/keeper/old_delegation_test.go b/x/staking/keeper/old_delegation_test.go index 3e061619d559..de600a24efdc 100644 --- a/x/staking/keeper/old_delegation_test.go +++ b/x/staking/keeper/old_delegation_test.go @@ -11,60 +11,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking/types" ) -func TestRedelegationMaxEntries(t *testing.T) { - ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) - startTokens := sdk.TokensFromConsensusPower(20) - startCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), startTokens)) - - // add bonded tokens to pool for delegations - notBondedPool := keeper.GetNotBondedPool(ctx) - oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) - err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) - require.NoError(t, err) - keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) - - // create a validator with a self-delegation - validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) - valTokens := sdk.TokensFromConsensusPower(10) - validator, issuedShares := validator.AddTokensFromDel(valTokens) - require.Equal(t, valTokens, issuedShares.RoundInt()) - validator = TestingUpdateValidator(keeper, ctx, validator, true) - val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) - selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) - keeper.SetDelegation(ctx, selfDelegation) - - // create a second validator - validator2 := types.NewValidator(addrVals[1], PKs[1], types.Description{}) - validator2, issuedShares = validator2.AddTokensFromDel(valTokens) - require.Equal(t, valTokens, issuedShares.RoundInt()) - - validator2 = TestingUpdateValidator(keeper, ctx, validator2, true) - require.Equal(t, sdk.Bonded, validator2.Status) - - maxEntries := keeper.MaxEntries(ctx) - - // redelegations should pass - var completionTime time.Time - for i := uint32(0); i < maxEntries; i++ { - var err error - completionTime, err = keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1], sdk.NewDec(1)) - require.NoError(t, err) - } - - // an additional redelegation should fail due to max entries - _, err = keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1], sdk.NewDec(1)) - require.Error(t, err) - - // mature redelegations - ctx = ctx.WithBlockTime(completionTime) - err = keeper.CompleteRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1]) - require.NoError(t, err) - - // redelegation should work again - _, err = keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1], sdk.NewDec(1)) - require.NoError(t, err) -} - func TestRedelegateSelfDelegation(t *testing.T) { ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) startTokens := sdk.TokensFromConsensusPower(30) From 5bf1fa00487aaf8369638a88013339b1638a52c5 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 24 Feb 2020 15:11:37 +0100 Subject: [PATCH 187/529] refactor delegation test --- x/staking/keeper/delegation_test.go | 239 ++++++------------------ x/staking/keeper/old_delegation_test.go | 53 ------ 2 files changed, 53 insertions(+), 239 deletions(-) diff --git a/x/staking/keeper/delegation_test.go b/x/staking/keeper/delegation_test.go index a73447cd2b7d..8b963853a697 100644 --- a/x/staking/keeper/delegation_test.go +++ b/x/staking/keeper/delegation_test.go @@ -802,192 +802,59 @@ func TestRedelegationMaxEntries(t *testing.T) { require.NoError(t, err) } -//func TestRedelegationMaxEntries(t *testing.T) { -// ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) -// startTokens := sdk.TokensFromConsensusPower(20) -// startCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), startTokens)) -// -// // add bonded tokens to pool for delegations -// notBondedPool := keeper.GetNotBondedPool(ctx) -// oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) -// err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) -// require.NoError(t, err) -// keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) -// -// // create a validator with a self-delegation -// validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) -// valTokens := sdk.TokensFromConsensusPower(10) -// validator, issuedShares := validator.AddTokensFromDel(valTokens) -// require.Equal(t, valTokens, issuedShares.RoundInt()) -// validator = TestingUpdateValidator(keeper, ctx, validator, true) -// val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) -// selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) -// keeper.SetDelegation(ctx, selfDelegation) -// -// // create a second validator -// validator2 := types.NewValidator(addrVals[1], PKs[1], types.Description{}) -// validator2, issuedShares = validator2.AddTokensFromDel(valTokens) -// require.Equal(t, valTokens, issuedShares.RoundInt()) -// -// validator2 = TestingUpdateValidator(keeper, ctx, validator2, true) -// require.Equal(t, sdk.Bonded, validator2.Status) -// -// maxEntries := keeper.MaxEntries(ctx) -// -// // redelegations should pass -// var completionTime time.Time -// for i := uint32(0); i < maxEntries; i++ { -// var err error -// completionTime, err = keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1], sdk.NewDec(1)) -// require.NoError(t, err) -// } -// -// // an additional redelegation should fail due to max entries -// _, err = keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1], sdk.NewDec(1)) -// require.Error(t, err) -// -// // mature redelegations -// ctx = ctx.WithBlockTime(completionTime) -// err = keeper.CompleteRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1]) -// require.NoError(t, err) -// -// // redelegation should work again -// _, err = keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1], sdk.NewDec(1)) -// require.NoError(t, err) -//} -// -//func TestRedelegateSelfDelegation(t *testing.T) { -// ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) -// startTokens := sdk.TokensFromConsensusPower(30) -// startCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), startTokens)) -// -// // add bonded tokens to pool for delegations -// notBondedPool := keeper.GetNotBondedPool(ctx) -// oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) -// err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) -// require.NoError(t, err) -// keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) -// -// //create a validator with a self-delegation -// validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) -// valTokens := sdk.TokensFromConsensusPower(10) -// validator, issuedShares := validator.AddTokensFromDel(valTokens) -// require.Equal(t, valTokens, issuedShares.RoundInt()) -// -// validator = TestingUpdateValidator(keeper, ctx, validator, true) -// -// val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) -// selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) -// keeper.SetDelegation(ctx, selfDelegation) -// -// // create a second validator -// validator2 := types.NewValidator(addrVals[1], PKs[1], types.Description{}) -// validator2, issuedShares = validator2.AddTokensFromDel(valTokens) -// require.Equal(t, valTokens, issuedShares.RoundInt()) -// validator2 = TestingUpdateValidator(keeper, ctx, validator2, true) -// require.Equal(t, sdk.Bonded, validator2.Status) -// -// // create a second delegation to validator 1 -// delTokens := sdk.TokensFromConsensusPower(10) -// validator, issuedShares = validator.AddTokensFromDel(delTokens) -// require.Equal(t, delTokens, issuedShares.RoundInt()) -// validator = TestingUpdateValidator(keeper, ctx, validator, true) -// -// delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) -// keeper.SetDelegation(ctx, delegation) -// -// _, err = keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1], delTokens.ToDec()) -// require.NoError(t, err) -// -// // end block -// updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) -// require.Equal(t, 2, len(updates)) -// -// validator, found := keeper.GetValidator(ctx, addrVals[0]) -// require.True(t, found) -// require.Equal(t, valTokens, validator.Tokens) -// require.Equal(t, sdk.Unbonding, validator.Status) -//} -// -//func TestRedelegateFromUnbondingValidator(t *testing.T) { -// ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) -// startTokens := sdk.TokensFromConsensusPower(30) -// startCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), startTokens)) -// -// // add bonded tokens to pool for delegations -// notBondedPool := keeper.GetNotBondedPool(ctx) -// oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) -// err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) -// require.NoError(t, err) -// keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) -// -// //create a validator with a self-delegation -// validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) -// -// valTokens := sdk.TokensFromConsensusPower(10) -// validator, issuedShares := validator.AddTokensFromDel(valTokens) -// require.Equal(t, valTokens, issuedShares.RoundInt()) -// validator = TestingUpdateValidator(keeper, ctx, validator, true) -// val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) -// selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) -// keeper.SetDelegation(ctx, selfDelegation) -// -// // create a second delegation to this validator -// keeper.DeleteValidatorByPowerIndex(ctx, validator) -// delTokens := sdk.TokensFromConsensusPower(10) -// validator, issuedShares = validator.AddTokensFromDel(delTokens) -// require.Equal(t, delTokens, issuedShares.RoundInt()) -// validator = TestingUpdateValidator(keeper, ctx, validator, true) -// delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) -// keeper.SetDelegation(ctx, delegation) -// -// // create a second validator -// validator2 := types.NewValidator(addrVals[1], PKs[1], types.Description{}) -// validator2, issuedShares = validator2.AddTokensFromDel(valTokens) -// require.Equal(t, valTokens, issuedShares.RoundInt()) -// validator2 = TestingUpdateValidator(keeper, ctx, validator2, true) -// -// header := ctx.BlockHeader() -// blockHeight := int64(10) -// header.Height = blockHeight -// blockTime := time.Unix(333, 0) -// header.Time = blockTime -// ctx = ctx.WithBlockHeader(header) -// -// // unbond the all self-delegation to put validator in unbonding state -// _, err = keeper.Undelegate(ctx, val0AccAddr, addrVals[0], delTokens.ToDec()) -// require.NoError(t, err) -// -// // end block -// updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) -// require.Equal(t, 1, len(updates)) -// -// validator, found := keeper.GetValidator(ctx, addrVals[0]) -// require.True(t, found) -// require.Equal(t, blockHeight, validator.UnbondingHeight) -// params := keeper.GetParams(ctx) -// require.True(t, blockTime.Add(params.UnbondingTime).Equal(validator.UnbondingTime)) -// -// //change the context -// header = ctx.BlockHeader() -// blockHeight2 := int64(20) -// header.Height = blockHeight2 -// blockTime2 := time.Unix(444, 0) -// header.Time = blockTime2 -// ctx = ctx.WithBlockHeader(header) -// -// // unbond some of the other delegation's shares -// redelegateTokens := sdk.TokensFromConsensusPower(6) -// _, err = keeper.BeginRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1], redelegateTokens.ToDec()) -// require.NoError(t, err) -// -// // retrieve the unbonding delegation -// ubd, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) -// require.True(t, found) -// require.Len(t, ubd.Entries, 1) -// assert.Equal(t, blockHeight, ubd.Entries[0].CreationHeight) -// assert.True(t, blockTime.Add(params.UnbondingTime).Equal(ubd.Entries[0].CompletionTime)) -//} +func TestRedelegateSelfDelegation(t *testing.T) { + _, app, ctx := getBaseSimappWithCustomKeeper() + startTokens := sdk.TokensFromConsensusPower(30) + startCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), startTokens)) + + // add bonded tokens to pool for delegations + notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) + oldNotBonded := app.BankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) + err := app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) + require.NoError(t, err) + app.SupplyKeeper.SetModuleAccount(ctx, notBondedPool) + + //create a validator with a self-delegation + validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) + valTokens := sdk.TokensFromConsensusPower(10) + validator, issuedShares := validator.AddTokensFromDel(valTokens) + require.Equal(t, valTokens, issuedShares.RoundInt()) + + validator = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator, true) + + val0AccAddr := sdk.AccAddress(addrVals[0]) + selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) + app.StakingKeeper.SetDelegation(ctx, selfDelegation) + + // create a second validator + validator2 := types.NewValidator(addrVals[1], PKs[1], types.Description{}) + validator2, issuedShares = validator2.AddTokensFromDel(valTokens) + require.Equal(t, valTokens, issuedShares.RoundInt()) + validator2 = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator2, true) + require.Equal(t, sdk.Bonded, validator2.Status) + + // create a second delegation to validator 1 + delTokens := sdk.TokensFromConsensusPower(10) + validator, issuedShares = validator.AddTokensFromDel(delTokens) + require.Equal(t, delTokens, issuedShares.RoundInt()) + validator = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator, true) + + delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) + app.StakingKeeper.SetDelegation(ctx, delegation) + + _, err = app.StakingKeeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1], delTokens.ToDec()) + require.NoError(t, err) + + // end block + updates := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 2, len(updates)) + + validator, found := app.StakingKeeper.GetValidator(ctx, addrVals[0]) + require.True(t, found) + require.Equal(t, valTokens, validator.Tokens) + require.Equal(t, sdk.Unbonding, validator.Status) +} + // //func TestRedelegateFromUnbondedValidator(t *testing.T) { // ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) diff --git a/x/staking/keeper/old_delegation_test.go b/x/staking/keeper/old_delegation_test.go index de600a24efdc..b8d233c24149 100644 --- a/x/staking/keeper/old_delegation_test.go +++ b/x/staking/keeper/old_delegation_test.go @@ -11,59 +11,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking/types" ) -func TestRedelegateSelfDelegation(t *testing.T) { - ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) - startTokens := sdk.TokensFromConsensusPower(30) - startCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), startTokens)) - - // add bonded tokens to pool for delegations - notBondedPool := keeper.GetNotBondedPool(ctx) - oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) - err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) - require.NoError(t, err) - keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) - - //create a validator with a self-delegation - validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) - valTokens := sdk.TokensFromConsensusPower(10) - validator, issuedShares := validator.AddTokensFromDel(valTokens) - require.Equal(t, valTokens, issuedShares.RoundInt()) - - validator = TestingUpdateValidator(keeper, ctx, validator, true) - - val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) - selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) - keeper.SetDelegation(ctx, selfDelegation) - - // create a second validator - validator2 := types.NewValidator(addrVals[1], PKs[1], types.Description{}) - validator2, issuedShares = validator2.AddTokensFromDel(valTokens) - require.Equal(t, valTokens, issuedShares.RoundInt()) - validator2 = TestingUpdateValidator(keeper, ctx, validator2, true) - require.Equal(t, sdk.Bonded, validator2.Status) - - // create a second delegation to validator 1 - delTokens := sdk.TokensFromConsensusPower(10) - validator, issuedShares = validator.AddTokensFromDel(delTokens) - require.Equal(t, delTokens, issuedShares.RoundInt()) - validator = TestingUpdateValidator(keeper, ctx, validator, true) - - delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) - keeper.SetDelegation(ctx, delegation) - - _, err = keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1], delTokens.ToDec()) - require.NoError(t, err) - - // end block - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 2, len(updates)) - - validator, found := keeper.GetValidator(ctx, addrVals[0]) - require.True(t, found) - require.Equal(t, valTokens, validator.Tokens) - require.Equal(t, sdk.Unbonding, validator.Status) -} - func TestRedelegateFromUnbondingValidator(t *testing.T) { ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) startTokens := sdk.TokensFromConsensusPower(30) From a1fcb07d0fa75e4d82debde577a135fcd8c9fa14 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 24 Feb 2020 15:28:25 +0100 Subject: [PATCH 188/529] refactor TestRedelegateFromUnbondingValidator to use simapp --- x/staking/keeper/delegation_test.go | 88 +++++++++++++++++++++++++ x/staking/keeper/old_delegation_test.go | 81 ----------------------- 2 files changed, 88 insertions(+), 81 deletions(-) diff --git a/x/staking/keeper/delegation_test.go b/x/staking/keeper/delegation_test.go index 8b963853a697..f886641b3f43 100644 --- a/x/staking/keeper/delegation_test.go +++ b/x/staking/keeper/delegation_test.go @@ -804,6 +804,10 @@ func TestRedelegationMaxEntries(t *testing.T) { func TestRedelegateSelfDelegation(t *testing.T) { _, app, ctx := getBaseSimappWithCustomKeeper() + + addrDels := simapp.AddTestAddrsIncremental(app, ctx, 2, sdk.NewInt(0)) + addrVals := simapp.ConvertAddrsToValAddrs(addrDels) + startTokens := sdk.TokensFromConsensusPower(30) startCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), startTokens)) @@ -855,6 +859,90 @@ func TestRedelegateSelfDelegation(t *testing.T) { require.Equal(t, sdk.Unbonding, validator.Status) } +func TestRedelegateFromUnbondingValidator(t *testing.T) { + _, app, ctx := getBaseSimappWithCustomKeeper() + + addrDels := simapp.AddTestAddrsIncremental(app, ctx, 2, sdk.NewInt(0)) + addrVals := simapp.ConvertAddrsToValAddrs(addrDels) + + startTokens := sdk.TokensFromConsensusPower(30) + startCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), startTokens)) + + // add bonded tokens to pool for delegations + notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) + oldNotBonded := app.BankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) + err := app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) + require.NoError(t, err) + app.SupplyKeeper.SetModuleAccount(ctx, notBondedPool) + + //create a validator with a self-delegation + validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) + + valTokens := sdk.TokensFromConsensusPower(10) + validator, issuedShares := validator.AddTokensFromDel(valTokens) + require.Equal(t, valTokens, issuedShares.RoundInt()) + validator = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator, true) + val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) + selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) + app.StakingKeeper.SetDelegation(ctx, selfDelegation) + + // create a second delegation to this validator + app.StakingKeeper.DeleteValidatorByPowerIndex(ctx, validator) + delTokens := sdk.TokensFromConsensusPower(10) + validator, issuedShares = validator.AddTokensFromDel(delTokens) + require.Equal(t, delTokens, issuedShares.RoundInt()) + validator = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator, true) + delegation := types.NewDelegation(addrDels[1], addrVals[0], issuedShares) + app.StakingKeeper.SetDelegation(ctx, delegation) + + // create a second validator + validator2 := types.NewValidator(addrVals[1], PKs[1], types.Description{}) + validator2, issuedShares = validator2.AddTokensFromDel(valTokens) + require.Equal(t, valTokens, issuedShares.RoundInt()) + validator2 = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator2, true) + + header := ctx.BlockHeader() + blockHeight := int64(10) + header.Height = blockHeight + blockTime := time.Unix(333, 0) + header.Time = blockTime + ctx = ctx.WithBlockHeader(header) + + // unbond the all self-delegation to put validator in unbonding state + _, err = app.StakingKeeper.Undelegate(ctx, val0AccAddr, addrVals[0], delTokens.ToDec()) + require.NoError(t, err) + + // end block + updates := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 1, len(updates)) + + validator, found := app.StakingKeeper.GetValidator(ctx, addrVals[0]) + require.True(t, found) + require.Equal(t, blockHeight, validator.UnbondingHeight) + params := app.StakingKeeper.GetParams(ctx) + require.True(t, blockTime.Add(params.UnbondingTime).Equal(validator.UnbondingTime)) + + //change the context + header = ctx.BlockHeader() + blockHeight2 := int64(20) + header.Height = blockHeight2 + blockTime2 := time.Unix(444, 0) + header.Time = blockTime2 + ctx = ctx.WithBlockHeader(header) + + // unbond some of the other delegation's shares + redelegateTokens := sdk.TokensFromConsensusPower(6) + _, err = app.StakingKeeper.BeginRedelegation(ctx, addrDels[1], addrVals[0], addrVals[1], redelegateTokens.ToDec()) + require.NoError(t, err) + + // retrieve the unbonding delegation + ubd, found := app.StakingKeeper.GetRedelegation(ctx, addrDels[1], addrVals[0], addrVals[1]) + require.True(t, found) + require.Len(t, ubd.Entries, 1) + assert.Equal(t, blockHeight, ubd.Entries[0].CreationHeight) + assert.True(t, blockTime.Add(params.UnbondingTime).Equal(ubd.Entries[0].CompletionTime)) +} + // //func TestRedelegateFromUnbondedValidator(t *testing.T) { // ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) diff --git a/x/staking/keeper/old_delegation_test.go b/x/staking/keeper/old_delegation_test.go index b8d233c24149..fc4bbabce553 100644 --- a/x/staking/keeper/old_delegation_test.go +++ b/x/staking/keeper/old_delegation_test.go @@ -4,93 +4,12 @@ import ( "testing" "time" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/staking/types" ) -func TestRedelegateFromUnbondingValidator(t *testing.T) { - ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) - startTokens := sdk.TokensFromConsensusPower(30) - startCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), startTokens)) - - // add bonded tokens to pool for delegations - notBondedPool := keeper.GetNotBondedPool(ctx) - oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) - err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) - require.NoError(t, err) - keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) - - //create a validator with a self-delegation - validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) - - valTokens := sdk.TokensFromConsensusPower(10) - validator, issuedShares := validator.AddTokensFromDel(valTokens) - require.Equal(t, valTokens, issuedShares.RoundInt()) - validator = TestingUpdateValidator(keeper, ctx, validator, true) - val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) - selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) - keeper.SetDelegation(ctx, selfDelegation) - - // create a second delegation to this validator - keeper.DeleteValidatorByPowerIndex(ctx, validator) - delTokens := sdk.TokensFromConsensusPower(10) - validator, issuedShares = validator.AddTokensFromDel(delTokens) - require.Equal(t, delTokens, issuedShares.RoundInt()) - validator = TestingUpdateValidator(keeper, ctx, validator, true) - delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) - keeper.SetDelegation(ctx, delegation) - - // create a second validator - validator2 := types.NewValidator(addrVals[1], PKs[1], types.Description{}) - validator2, issuedShares = validator2.AddTokensFromDel(valTokens) - require.Equal(t, valTokens, issuedShares.RoundInt()) - validator2 = TestingUpdateValidator(keeper, ctx, validator2, true) - - header := ctx.BlockHeader() - blockHeight := int64(10) - header.Height = blockHeight - blockTime := time.Unix(333, 0) - header.Time = blockTime - ctx = ctx.WithBlockHeader(header) - - // unbond the all self-delegation to put validator in unbonding state - _, err = keeper.Undelegate(ctx, val0AccAddr, addrVals[0], delTokens.ToDec()) - require.NoError(t, err) - - // end block - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 1, len(updates)) - - validator, found := keeper.GetValidator(ctx, addrVals[0]) - require.True(t, found) - require.Equal(t, blockHeight, validator.UnbondingHeight) - params := keeper.GetParams(ctx) - require.True(t, blockTime.Add(params.UnbondingTime).Equal(validator.UnbondingTime)) - - //change the context - header = ctx.BlockHeader() - blockHeight2 := int64(20) - header.Height = blockHeight2 - blockTime2 := time.Unix(444, 0) - header.Time = blockTime2 - ctx = ctx.WithBlockHeader(header) - - // unbond some of the other delegation's shares - redelegateTokens := sdk.TokensFromConsensusPower(6) - _, err = keeper.BeginRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1], redelegateTokens.ToDec()) - require.NoError(t, err) - - // retrieve the unbonding delegation - ubd, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) - require.True(t, found) - require.Len(t, ubd.Entries, 1) - assert.Equal(t, blockHeight, ubd.Entries[0].CreationHeight) - assert.True(t, blockTime.Add(params.UnbondingTime).Equal(ubd.Entries[0].CompletionTime)) -} - func TestRedelegateFromUnbondedValidator(t *testing.T) { ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) startTokens := sdk.TokensFromConsensusPower(30) From 17ee1f510a941bd0531e0463354ed660592bd910 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 24 Feb 2020 15:37:03 +0100 Subject: [PATCH 189/529] finish refactor delegation test --- x/staking/keeper/delegation_test.go | 141 ++++++++++++------------ x/staking/keeper/old_delegation_test.go | 80 -------------- x/staking/keeper/val_state_change.go | 2 +- x/staking/keeper/validator.go | 2 +- 4 files changed, 74 insertions(+), 151 deletions(-) delete mode 100644 x/staking/keeper/old_delegation_test.go diff --git a/x/staking/keeper/delegation_test.go b/x/staking/keeper/delegation_test.go index f886641b3f43..004314a927a9 100644 --- a/x/staking/keeper/delegation_test.go +++ b/x/staking/keeper/delegation_test.go @@ -943,72 +943,75 @@ func TestRedelegateFromUnbondingValidator(t *testing.T) { assert.True(t, blockTime.Add(params.UnbondingTime).Equal(ubd.Entries[0].CompletionTime)) } -// -//func TestRedelegateFromUnbondedValidator(t *testing.T) { -// ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) -// startTokens := sdk.TokensFromConsensusPower(30) -// startCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), startTokens)) -// -// // add bonded tokens to pool for delegations -// notBondedPool := keeper.GetNotBondedPool(ctx) -// oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) -// err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) -// require.NoError(t, err) -// keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) -// -// //create a validator with a self-delegation -// validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) -// -// valTokens := sdk.TokensFromConsensusPower(10) -// validator, issuedShares := validator.AddTokensFromDel(valTokens) -// require.Equal(t, valTokens, issuedShares.RoundInt()) -// validator = TestingUpdateValidator(keeper, ctx, validator, true) -// val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) -// selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) -// keeper.SetDelegation(ctx, selfDelegation) -// -// // create a second delegation to this validator -// keeper.DeleteValidatorByPowerIndex(ctx, validator) -// delTokens := sdk.TokensFromConsensusPower(10) -// validator, issuedShares = validator.AddTokensFromDel(delTokens) -// require.Equal(t, delTokens, issuedShares.RoundInt()) -// validator = TestingUpdateValidator(keeper, ctx, validator, true) -// delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) -// keeper.SetDelegation(ctx, delegation) -// -// // create a second validator -// validator2 := types.NewValidator(addrVals[1], PKs[1], types.Description{}) -// validator2, issuedShares = validator2.AddTokensFromDel(valTokens) -// require.Equal(t, valTokens, issuedShares.RoundInt()) -// validator2 = TestingUpdateValidator(keeper, ctx, validator2, true) -// require.Equal(t, sdk.Bonded, validator2.Status) -// -// ctx = ctx.WithBlockHeight(10) -// ctx = ctx.WithBlockTime(time.Unix(333, 0)) -// -// // unbond the all self-delegation to put validator in unbonding state -// _, err = keeper.Undelegate(ctx, val0AccAddr, addrVals[0], delTokens.ToDec()) -// require.NoError(t, err) -// -// // end block -// updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) -// require.Equal(t, 1, len(updates)) -// -// validator, found := keeper.GetValidator(ctx, addrVals[0]) -// require.True(t, found) -// require.Equal(t, ctx.BlockHeight(), validator.UnbondingHeight) -// params := keeper.GetParams(ctx) -// require.True(t, ctx.BlockHeader().Time.Add(params.UnbondingTime).Equal(validator.UnbondingTime)) -// -// // unbond the validator -// keeper.unbondingToUnbonded(ctx, validator) -// -// // redelegate some of the delegation's shares -// redelegationTokens := sdk.TokensFromConsensusPower(6) -// _, err = keeper.BeginRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1], redelegationTokens.ToDec()) -// require.NoError(t, err) -// -// // no red should have been found -// red, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) -// require.False(t, found, "%v", red) -//} +func TestRedelegateFromUnbondedValidator(t *testing.T) { + _, app, ctx := getBaseSimappWithCustomKeeper() + + addrDels := simapp.AddTestAddrsIncremental(app, ctx, 2, sdk.NewInt(0)) + addrVals := simapp.ConvertAddrsToValAddrs(addrDels) + + startTokens := sdk.TokensFromConsensusPower(30) + startCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), startTokens)) + + // add bonded tokens to pool for delegations + notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) + oldNotBonded := app.BankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) + err := app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) + require.NoError(t, err) + app.SupplyKeeper.SetModuleAccount(ctx, notBondedPool) + + //create a validator with a self-delegation + validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) + + valTokens := sdk.TokensFromConsensusPower(10) + validator, issuedShares := validator.AddTokensFromDel(valTokens) + require.Equal(t, valTokens, issuedShares.RoundInt()) + validator = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator, true) + val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) + selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) + app.StakingKeeper.SetDelegation(ctx, selfDelegation) + + // create a second delegation to this validator + app.StakingKeeper.DeleteValidatorByPowerIndex(ctx, validator) + delTokens := sdk.TokensFromConsensusPower(10) + validator, issuedShares = validator.AddTokensFromDel(delTokens) + require.Equal(t, delTokens, issuedShares.RoundInt()) + validator = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator, true) + delegation := types.NewDelegation(addrDels[1], addrVals[0], issuedShares) + app.StakingKeeper.SetDelegation(ctx, delegation) + + // create a second validator + validator2 := types.NewValidator(addrVals[1], PKs[1], types.Description{}) + validator2, issuedShares = validator2.AddTokensFromDel(valTokens) + require.Equal(t, valTokens, issuedShares.RoundInt()) + validator2 = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator2, true) + require.Equal(t, sdk.Bonded, validator2.Status) + + ctx = ctx.WithBlockHeight(10) + ctx = ctx.WithBlockTime(time.Unix(333, 0)) + + // unbond the all self-delegation to put validator in unbonding state + _, err = app.StakingKeeper.Undelegate(ctx, val0AccAddr, addrVals[0], delTokens.ToDec()) + require.NoError(t, err) + + // end block + updates := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 1, len(updates)) + + validator, found := app.StakingKeeper.GetValidator(ctx, addrVals[0]) + require.True(t, found) + require.Equal(t, ctx.BlockHeight(), validator.UnbondingHeight) + params := app.StakingKeeper.GetParams(ctx) + require.True(t, ctx.BlockHeader().Time.Add(params.UnbondingTime).Equal(validator.UnbondingTime)) + + // unbond the validator + app.StakingKeeper.UnbondingToUnbonded(ctx, validator) + + // redelegate some of the delegation's shares + redelegationTokens := sdk.TokensFromConsensusPower(6) + _, err = app.StakingKeeper.BeginRedelegation(ctx, addrDels[1], addrVals[0], addrVals[1], redelegationTokens.ToDec()) + require.NoError(t, err) + + // no red should have been found + red, found := app.StakingKeeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) + require.False(t, found, "%v", red) +} diff --git a/x/staking/keeper/old_delegation_test.go b/x/staking/keeper/old_delegation_test.go deleted file mode 100644 index fc4bbabce553..000000000000 --- a/x/staking/keeper/old_delegation_test.go +++ /dev/null @@ -1,80 +0,0 @@ -package keeper - -import ( - "testing" - "time" - - "github.com/stretchr/testify/require" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/staking/types" -) - -func TestRedelegateFromUnbondedValidator(t *testing.T) { - ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) - startTokens := sdk.TokensFromConsensusPower(30) - startCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), startTokens)) - - // add bonded tokens to pool for delegations - notBondedPool := keeper.GetNotBondedPool(ctx) - oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) - err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) - require.NoError(t, err) - keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) - - //create a validator with a self-delegation - validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) - - valTokens := sdk.TokensFromConsensusPower(10) - validator, issuedShares := validator.AddTokensFromDel(valTokens) - require.Equal(t, valTokens, issuedShares.RoundInt()) - validator = TestingUpdateValidator(keeper, ctx, validator, true) - val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) - selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) - keeper.SetDelegation(ctx, selfDelegation) - - // create a second delegation to this validator - keeper.DeleteValidatorByPowerIndex(ctx, validator) - delTokens := sdk.TokensFromConsensusPower(10) - validator, issuedShares = validator.AddTokensFromDel(delTokens) - require.Equal(t, delTokens, issuedShares.RoundInt()) - validator = TestingUpdateValidator(keeper, ctx, validator, true) - delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) - keeper.SetDelegation(ctx, delegation) - - // create a second validator - validator2 := types.NewValidator(addrVals[1], PKs[1], types.Description{}) - validator2, issuedShares = validator2.AddTokensFromDel(valTokens) - require.Equal(t, valTokens, issuedShares.RoundInt()) - validator2 = TestingUpdateValidator(keeper, ctx, validator2, true) - require.Equal(t, sdk.Bonded, validator2.Status) - - ctx = ctx.WithBlockHeight(10) - ctx = ctx.WithBlockTime(time.Unix(333, 0)) - - // unbond the all self-delegation to put validator in unbonding state - _, err = keeper.Undelegate(ctx, val0AccAddr, addrVals[0], delTokens.ToDec()) - require.NoError(t, err) - - // end block - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 1, len(updates)) - - validator, found := keeper.GetValidator(ctx, addrVals[0]) - require.True(t, found) - require.Equal(t, ctx.BlockHeight(), validator.UnbondingHeight) - params := keeper.GetParams(ctx) - require.True(t, ctx.BlockHeader().Time.Add(params.UnbondingTime).Equal(validator.UnbondingTime)) - - // unbond the validator - keeper.unbondingToUnbonded(ctx, validator) - - // redelegate some of the delegation's shares - redelegationTokens := sdk.TokensFromConsensusPower(6) - _, err = keeper.BeginRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1], redelegationTokens.ToDec()) - require.NoError(t, err) - - // no red should have been found - red, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) - require.False(t, found, "%v", red) -} diff --git a/x/staking/keeper/val_state_change.go b/x/staking/keeper/val_state_change.go index e05182e92876..b5f05cf9a00f 100644 --- a/x/staking/keeper/val_state_change.go +++ b/x/staking/keeper/val_state_change.go @@ -210,7 +210,7 @@ func (k Keeper) unbondedToBonded(ctx sdk.Context, validator types.Validator) typ } // switches a validator from unbonding state to unbonded state -func (k Keeper) unbondingToUnbonded(ctx sdk.Context, validator types.Validator) types.Validator { +func (k Keeper) UnbondingToUnbonded(ctx sdk.Context, validator types.Validator) types.Validator { if !validator.IsUnbonding() { panic(fmt.Sprintf("bad state transition unbondingToBonded, validator: %v\n", validator)) } diff --git a/x/staking/keeper/validator.go b/x/staking/keeper/validator.go index efc0ff517e9d..c8d4d597e9b3 100644 --- a/x/staking/keeper/validator.go +++ b/x/staking/keeper/validator.go @@ -441,7 +441,7 @@ func (k Keeper) UnbondAllMatureValidatorQueue(ctx sdk.Context) { panic("unexpected validator in unbonding queue; status was not unbonding") } - val = k.unbondingToUnbonded(ctx, val) + val = k.UnbondingToUnbonded(ctx, val) if val.GetDelegatorShares().IsZero() { k.RemoveValidator(ctx, val.OperatorAddress) } From 3910ec25f636717713b3a11334f4738e64712ff6 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 24 Feb 2020 16:14:16 +0100 Subject: [PATCH 190/529] refactor and remove unused code --- x/staking/keeper/delegation_test.go | 48 ++++++++++---------- x/staking/keeper/historical_info_test.go | 20 +++++---- x/staking/keeper/test_common_test.go | 56 +----------------------- 3 files changed, 37 insertions(+), 87 deletions(-) diff --git a/x/staking/keeper/delegation_test.go b/x/staking/keeper/delegation_test.go index 004314a927a9..a1b0c6841c54 100644 --- a/x/staking/keeper/delegation_test.go +++ b/x/staking/keeper/delegation_test.go @@ -17,8 +17,8 @@ import ( func TestDelegation(t *testing.T) { _, app, ctx := getBaseSimappWithCustomKeeper() - addrs := simapp.AddTestAddrsIncremental(app, ctx, 3, sdk.NewInt(10000)) - valAddrs := simapp.ConvertAddrsToValAddrs(addrs) + addrDels := simapp.AddTestAddrsIncremental(app, ctx, 3, sdk.NewInt(10000)) + valAddrs := simapp.ConvertAddrsToValAddrs(addrDels) //construct the validators amts := []sdk.Int{sdk.NewInt(9), sdk.NewInt(8), sdk.NewInt(7)} @@ -33,31 +33,31 @@ func TestDelegation(t *testing.T) { validators[2] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[2], true) // first add a validators[0] to delegate too - bond1to1 := types.NewDelegation(addrs[0], valAddrs[0], sdk.NewDec(9)) + bond1to1 := types.NewDelegation(addrDels[0], valAddrs[0], sdk.NewDec(9)) // check the empty keeper first - _, found := app.StakingKeeper.GetDelegation(ctx, addrs[0], valAddrs[0]) + _, found := app.StakingKeeper.GetDelegation(ctx, addrDels[0], valAddrs[0]) require.False(t, found) // set and retrieve a record app.StakingKeeper.SetDelegation(ctx, bond1to1) - resBond, found := app.StakingKeeper.GetDelegation(ctx, addrs[0], valAddrs[0]) + resBond, found := app.StakingKeeper.GetDelegation(ctx, addrDels[0], valAddrs[0]) require.True(t, found) require.True(t, bond1to1.Equal(resBond)) // modify a records, save, and retrieve bond1to1.Shares = sdk.NewDec(99) app.StakingKeeper.SetDelegation(ctx, bond1to1) - resBond, found = app.StakingKeeper.GetDelegation(ctx, addrs[0], valAddrs[0]) + resBond, found = app.StakingKeeper.GetDelegation(ctx, addrDels[0], valAddrs[0]) require.True(t, found) require.True(t, bond1to1.Equal(resBond)) // add some more records - bond1to2 := types.NewDelegation(addrs[0], valAddrs[1], sdk.NewDec(9)) - bond1to3 := types.NewDelegation(addrs[0], valAddrs[2], sdk.NewDec(9)) - bond2to1 := types.NewDelegation(addrs[1], valAddrs[0], sdk.NewDec(9)) - bond2to2 := types.NewDelegation(addrs[1], valAddrs[1], sdk.NewDec(9)) - bond2to3 := types.NewDelegation(addrs[1], valAddrs[2], sdk.NewDec(9)) + bond1to2 := types.NewDelegation(addrDels[0], valAddrs[1], sdk.NewDec(9)) + bond1to3 := types.NewDelegation(addrDels[0], valAddrs[2], sdk.NewDec(9)) + bond2to1 := types.NewDelegation(addrDels[1], valAddrs[0], sdk.NewDec(9)) + bond2to2 := types.NewDelegation(addrDels[1], valAddrs[1], sdk.NewDec(9)) + bond2to3 := types.NewDelegation(addrDels[1], valAddrs[2], sdk.NewDec(9)) app.StakingKeeper.SetDelegation(ctx, bond1to2) app.StakingKeeper.SetDelegation(ctx, bond1to3) app.StakingKeeper.SetDelegation(ctx, bond2to1) @@ -65,16 +65,16 @@ func TestDelegation(t *testing.T) { app.StakingKeeper.SetDelegation(ctx, bond2to3) // test all bond retrieve capabilities - resBonds := app.StakingKeeper.GetDelegatorDelegations(ctx, addrs[0], 5) + resBonds := app.StakingKeeper.GetDelegatorDelegations(ctx, addrDels[0], 5) require.Equal(t, 3, len(resBonds)) require.True(t, bond1to1.Equal(resBonds[0])) require.True(t, bond1to2.Equal(resBonds[1])) require.True(t, bond1to3.Equal(resBonds[2])) - resBonds = app.StakingKeeper.GetAllDelegatorDelegations(ctx, addrs[0]) + resBonds = app.StakingKeeper.GetAllDelegatorDelegations(ctx, addrDels[0]) require.Equal(t, 3, len(resBonds)) - resBonds = app.StakingKeeper.GetDelegatorDelegations(ctx, addrs[0], 2) + resBonds = app.StakingKeeper.GetDelegatorDelegations(ctx, addrDels[0], 2) require.Equal(t, 2, len(resBonds)) - resBonds = app.StakingKeeper.GetDelegatorDelegations(ctx, addrs[1], 5) + resBonds = app.StakingKeeper.GetDelegatorDelegations(ctx, addrDels[1], 5) require.Equal(t, 3, len(resBonds)) require.True(t, bond2to1.Equal(resBonds[0])) require.True(t, bond2to2.Equal(resBonds[1])) @@ -88,17 +88,17 @@ func TestDelegation(t *testing.T) { require.True(t, bond2to2.Equal(allBonds[4])) require.True(t, bond2to3.Equal(allBonds[5])) - resVals := app.StakingKeeper.GetDelegatorValidators(ctx, addrs[0], 3) + resVals := app.StakingKeeper.GetDelegatorValidators(ctx, addrDels[0], 3) require.Equal(t, 3, len(resVals)) - resVals = app.StakingKeeper.GetDelegatorValidators(ctx, addrs[1], 4) + resVals = app.StakingKeeper.GetDelegatorValidators(ctx, addrDels[1], 4) require.Equal(t, 3, len(resVals)) for i := 0; i < 3; i++ { - resVal, err := app.StakingKeeper.GetDelegatorValidator(ctx, addrs[0], valAddrs[i]) + resVal, err := app.StakingKeeper.GetDelegatorValidator(ctx, addrDels[0], valAddrs[i]) require.Nil(t, err) require.Equal(t, valAddrs[i], resVal.GetOperator()) - resVal, err = app.StakingKeeper.GetDelegatorValidator(ctx, addrs[1], valAddrs[i]) + resVal, err = app.StakingKeeper.GetDelegatorValidator(ctx, addrDels[1], valAddrs[i]) require.Nil(t, err) require.Equal(t, valAddrs[i], resVal.GetOperator()) @@ -108,22 +108,22 @@ func TestDelegation(t *testing.T) { // delete a record app.StakingKeeper.RemoveDelegation(ctx, bond2to3) - _, found = app.StakingKeeper.GetDelegation(ctx, addrs[1], valAddrs[2]) + _, found = app.StakingKeeper.GetDelegation(ctx, addrDels[1], valAddrs[2]) require.False(t, found) - resBonds = app.StakingKeeper.GetDelegatorDelegations(ctx, addrs[1], 5) + resBonds = app.StakingKeeper.GetDelegatorDelegations(ctx, addrDels[1], 5) require.Equal(t, 2, len(resBonds)) require.True(t, bond2to1.Equal(resBonds[0])) require.True(t, bond2to2.Equal(resBonds[1])) - resBonds = app.StakingKeeper.GetAllDelegatorDelegations(ctx, addrs[1]) + resBonds = app.StakingKeeper.GetAllDelegatorDelegations(ctx, addrDels[1]) require.Equal(t, 2, len(resBonds)) // delete all the records from delegator 2 app.StakingKeeper.RemoveDelegation(ctx, bond2to1) app.StakingKeeper.RemoveDelegation(ctx, bond2to2) - _, found = app.StakingKeeper.GetDelegation(ctx, addrs[1], valAddrs[0]) + _, found = app.StakingKeeper.GetDelegation(ctx, addrDels[1], valAddrs[0]) require.False(t, found) - _, found = app.StakingKeeper.GetDelegation(ctx, addrs[1], valAddrs[1]) + _, found = app.StakingKeeper.GetDelegation(ctx, addrDels[1], valAddrs[1]) require.False(t, found) resBonds = app.StakingKeeper.GetDelegatorDelegations(ctx, addrDels[1], 5) require.Equal(t, 0, len(resBonds)) diff --git a/x/staking/keeper/historical_info_test.go b/x/staking/keeper/historical_info_test.go index 73cc64de0f4e..d4ed693106e6 100644 --- a/x/staking/keeper/historical_info_test.go +++ b/x/staking/keeper/historical_info_test.go @@ -15,8 +15,10 @@ import ( ) func TestHistoricalInfo(t *testing.T) { - app := simapp.Setup(false) - ctx := app.BaseApp.NewContext(false, abci.Header{}) + _, app, ctx := getBaseSimappWithCustomKeeper() + + addrDels := simapp.AddTestAddrsIncremental(app, ctx, 50, sdk.NewInt(0)) + addrVals := simapp.ConvertAddrsToValAddrs(addrDels) validators := make([]types.Validator, len(addrVals)) @@ -41,8 +43,10 @@ func TestHistoricalInfo(t *testing.T) { } func TestTrackHistoricalInfo(t *testing.T) { - app := simapp.Setup(false) - ctx := app.BaseApp.NewContext(false, abci.Header{}) + _, app, ctx := getBaseSimappWithCustomKeeper() + + addrDels := simapp.AddTestAddrsIncremental(app, ctx, 50, sdk.NewInt(0)) + addrVals := simapp.ConvertAddrsToValAddrs(addrDels) // set historical entries in params to 5 params := types.DefaultParams() @@ -60,8 +64,8 @@ func TestTrackHistoricalInfo(t *testing.T) { Height: 5, } valSet := []types.Validator{ - types.NewValidator(sdk.ValAddress(Addrs[0]), PKs[0], types.Description{}), - types.NewValidator(sdk.ValAddress(Addrs[1]), PKs[1], types.Description{}), + types.NewValidator(addrVals[0], PKs[0], types.Description{}), + types.NewValidator(addrVals[1], PKs[1], types.Description{}), } hi4 := types.NewHistoricalInfo(h4, valSet) hi5 := types.NewHistoricalInfo(h5, valSet) @@ -75,10 +79,10 @@ func TestTrackHistoricalInfo(t *testing.T) { require.Equal(t, hi5, recv) // Set last validators in keeper - val1 := types.NewValidator(sdk.ValAddress(Addrs[2]), PKs[2], types.Description{}) + val1 := types.NewValidator(addrVals[2], PKs[2], types.Description{}) app.StakingKeeper.SetValidator(ctx, val1) app.StakingKeeper.SetLastValidatorPower(ctx, val1.OperatorAddress, 10) - val2 := types.NewValidator(sdk.ValAddress(Addrs[3]), PKs[3], types.Description{}) + val2 := types.NewValidator(addrVals[3], PKs[3], types.Description{}) vals := []types.Validator{val1, val2} sort.Sort(types.Validators(vals)) app.StakingKeeper.SetValidator(ctx, val2) diff --git a/x/staking/keeper/test_common_test.go b/x/staking/keeper/test_common_test.go index 7c6cf8f0c2f9..2275aff100fb 100644 --- a/x/staking/keeper/test_common_test.go +++ b/x/staking/keeper/test_common_test.go @@ -17,40 +17,9 @@ import ( ) var ( - Addrs = createTestAddrs(500) - PKs = createTestPubKeys(500) - - addrDels = []sdk.AccAddress{ - Addrs[0], - Addrs[1], - } - addrVals = []sdk.ValAddress{ - sdk.ValAddress(Addrs[2]), - sdk.ValAddress(Addrs[3]), - sdk.ValAddress(Addrs[4]), - sdk.ValAddress(Addrs[5]), - sdk.ValAddress(Addrs[6]), - } + PKs = createTestPubKeys(500) ) -func createTestAddrs(numAddrs int) []sdk.AccAddress { - var addresses []sdk.AccAddress - var buffer bytes.Buffer - - // start at 100 so we can make up to 999 test addresses with valid test addresses - for i := 100; i < (numAddrs + 100); i++ { - numString := strconv.Itoa(i) - buffer.WriteString("A58856F0FD53BF058B4909A21AEC019107BA6") //base address string - - buffer.WriteString(numString) //adding on final two digits to make addresses unique - res, _ := sdk.AccAddressFromHex(buffer.String()) - bech := res.String() - addresses = append(addresses, CreateTestAddr(buffer.String(), bech)) - buffer.Reset() - } - return addresses -} - // nolint: unparam func createTestPubKeys(numPubKeys int) []crypto.PubKey { var publicKeys []crypto.PubKey @@ -79,29 +48,6 @@ func NewPubKey(pk string) (res crypto.PubKey) { return pkEd } -// for incode address generation -func CreateTestAddr(addr string, bech string) sdk.AccAddress { - res, err := sdk.AccAddressFromHex(addr) - if err != nil { - panic(err) - } - - bechexpected := res.String() - if bech != bechexpected { - panic("Bech encoding doesn't match reference") - } - - bechres, err := sdk.AccAddressFromBech32(bech) - if err != nil { - panic(err) - } - if !bytes.Equal(bechres, res) { - panic("Bech decode and hex decode don't match") - } - - return res -} - // getBaseSimappWithCustomKeeper Returns a simapp with custom StakingKeeper // to avoid messing with the hooks. func getBaseSimappWithCustomKeeper() (*codec.Codec, *simapp.SimApp, sdk.Context) { From f7486b9395e9b8fecde4e230afa62705a57e145b Mon Sep 17 00:00:00 2001 From: Marko Date: Mon, 24 Feb 2020 17:05:21 +0100 Subject: [PATCH 191/529] Merge PR #5634: Protobuf - Migrate x/evidence --- CHANGELOG.md | 11 + .../adr-019-protobuf-state-encoding.md | 103 +- simapp/app.go | 4 +- simapp/codec/codec.go | 59 +- simapp/codec/codec.pb.go | 697 +++++++++++++- simapp/codec/codec.proto | 27 +- simapp/codec/msgs.go | 38 + x/auth/types/types.proto | 22 +- x/evidence/alias.go | 22 +- x/evidence/client/cli/query.go | 2 +- x/evidence/client/cli/tx.go | 2 +- x/evidence/client/rest/query.go | 2 +- x/evidence/exported/evidence.go | 10 + x/evidence/genesis_test.go | 59 +- x/evidence/handler.go | 19 +- x/evidence/handler_test.go | 142 +-- x/evidence/internal/keeper/params_test.go | 11 - x/evidence/internal/types/codec.go | 29 - x/evidence/internal/types/codec_test.go | 42 - x/evidence/internal/types/msgs.go | 59 -- x/evidence/internal/types/msgs_test.go | 66 -- x/evidence/internal/types/test_util.go | 135 --- .../{internal => }/keeper/infraction.go | 2 +- .../{internal => }/keeper/infraction_test.go | 8 +- x/evidence/{internal => }/keeper/keeper.go | 41 +- .../{internal => }/keeper/keeper_test.go | 143 ++- x/evidence/{internal => }/keeper/params.go | 2 +- x/evidence/keeper/params_test.go | 11 + x/evidence/{internal => }/keeper/querier.go | 2 +- .../{internal => }/keeper/querier_test.go | 21 +- x/evidence/types/codec.go | 42 + x/evidence/types/codec_test.go | 33 + x/evidence/{internal => }/types/errors.go | 0 x/evidence/{internal => }/types/events.go | 0 x/evidence/{internal => }/types/evidence.go | 11 +- .../{internal => }/types/evidence_test.go | 4 +- .../{internal => }/types/expected_keepers.go | 0 x/evidence/{internal => }/types/genesis.go | 0 .../{internal => }/types/genesis_test.go | 41 +- x/evidence/{internal => }/types/keys.go | 0 x/evidence/types/msgs.go | 48 + x/evidence/types/msgs_test.go | 60 ++ x/evidence/{internal => }/types/params.go | 5 - x/evidence/{internal => }/types/querier.go | 0 x/evidence/{internal => }/types/router.go | 0 .../{internal => }/types/router_test.go | 2 +- x/evidence/types/types.pb.go | 876 ++++++++++++++++++ x/evidence/types/types.proto | 46 + x/mint/abci.go | 2 +- x/mint/alias.go | 4 +- x/mint/client/cli/query.go | 2 +- x/mint/client/rest/query.go | 2 +- x/mint/internal/types/codec.go | 14 - .../{internal => }/keeper/integration_test.go | 2 +- x/mint/{internal => }/keeper/keeper.go | 8 +- x/mint/{internal => }/keeper/querier.go | 2 +- x/mint/{internal => }/keeper/querier_test.go | 4 +- x/mint/simulation/decoder.go | 2 +- x/mint/simulation/decoder_test.go | 2 +- x/mint/simulation/genesis.go | 2 +- x/mint/simulation/params.go | 2 +- x/mint/types/codec.go | 22 + x/mint/{internal => }/types/events.go | 0 .../{internal => }/types/expected_keepers.go | 0 x/mint/{internal => }/types/genesis.go | 0 x/mint/{internal => }/types/keys.go | 0 x/mint/{internal => }/types/minter.go | 6 - x/mint/{internal => }/types/minter_test.go | 0 x/mint/{internal => }/types/params.go | 26 +- x/mint/types/types.pb.go | 785 ++++++++++++++++ x/mint/types/types.proto | 53 ++ 71 files changed, 3143 insertions(+), 756 deletions(-) create mode 100644 simapp/codec/msgs.go delete mode 100644 x/evidence/internal/keeper/params_test.go delete mode 100644 x/evidence/internal/types/codec.go delete mode 100644 x/evidence/internal/types/codec_test.go delete mode 100644 x/evidence/internal/types/msgs.go delete mode 100644 x/evidence/internal/types/msgs_test.go delete mode 100644 x/evidence/internal/types/test_util.go rename x/evidence/{internal => }/keeper/infraction.go (98%) rename x/evidence/{internal => }/keeper/infraction_test.go (95%) rename x/evidence/{internal => }/keeper/keeper.go (82%) rename x/evidence/{internal => }/keeper/keeper_test.go (57%) rename x/evidence/{internal => }/keeper/params.go (91%) create mode 100644 x/evidence/keeper/params_test.go rename x/evidence/{internal => }/keeper/querier.go (97%) rename x/evidence/{internal => }/keeper/querier_test.go (73%) create mode 100644 x/evidence/types/codec.go create mode 100644 x/evidence/types/codec_test.go rename x/evidence/{internal => }/types/errors.go (100%) rename x/evidence/{internal => }/types/events.go (100%) rename x/evidence/{internal => }/types/evidence.go (85%) rename x/evidence/{internal => }/types/evidence_test.go (91%) rename x/evidence/{internal => }/types/expected_keepers.go (100%) rename x/evidence/{internal => }/types/genesis.go (100%) rename x/evidence/{internal => }/types/genesis_test.go (51%) rename x/evidence/{internal => }/types/keys.go (100%) create mode 100644 x/evidence/types/msgs.go create mode 100644 x/evidence/types/msgs_test.go rename x/evidence/{internal => }/types/params.go (88%) rename x/evidence/{internal => }/types/querier.go (100%) rename x/evidence/{internal => }/types/router.go (100%) rename x/evidence/{internal => }/types/router_test.go (92%) create mode 100644 x/evidence/types/types.pb.go create mode 100644 x/evidence/types/types.proto delete mode 100644 x/mint/internal/types/codec.go rename x/mint/{internal => }/keeper/integration_test.go (90%) rename x/mint/{internal => }/keeper/keeper.go (94%) rename x/mint/{internal => }/keeper/querier.go (96%) rename x/mint/{internal => }/keeper/querier_test.go (94%) create mode 100644 x/mint/types/codec.go rename x/mint/{internal => }/types/events.go (100%) rename x/mint/{internal => }/types/expected_keepers.go (100%) rename x/mint/{internal => }/types/genesis.go (100%) rename x/mint/{internal => }/types/keys.go (100%) rename x/mint/{internal => }/types/minter.go (89%) rename x/mint/{internal => }/types/minter_test.go (100%) rename x/mint/{internal => }/types/params.go (81%) create mode 100644 x/mint/types/types.pb.go create mode 100644 x/mint/types/types.proto diff --git a/CHANGELOG.md b/CHANGELOG.md index 5804dbb319d0..fa07e0f77e0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -115,6 +115,17 @@ serialization instead of Amino. requiring a concrete codec to know how to serialize `SupplyI` types. * The `SupplyI` interface has been modified to no longer return `SupplyI` on methods. Instead the concrete type's receiver should modify the type. +* (x/mint) [\#5634](https://github.com/cosmos/cosmos-sdk/pull/5634) Migrate the `x/mint` module to use Protocol Buffers for state +serialization instead of Amino. + * The `internal` sub-package has been removed in order to expose the types proto file. +* (x/evidence) [\#5634](https://github.com/cosmos/cosmos-sdk/pull/5634) Migrate the `x/evidence` module to use Protocol Buffers for state +serialization instead of Amino. + * The `internal` sub-package has been removed in order to expose the types proto file. + * The module now accepts a `Codec` interface which extends the `codec.Marshaler` interface by + requiring a concrete codec to know how to serialize `Evidence` types. + * The `MsgSubmitEvidence` message has been removed in favor of `MsgSubmitEvidenceBase`. The application-level + codec must now define the concrete `MsgSubmitEvidence` type which must implement the module's `MsgSubmitEvidence` + interface. ### Improvements diff --git a/docs/architecture/adr-019-protobuf-state-encoding.md b/docs/architecture/adr-019-protobuf-state-encoding.md index f43c53e8155c..d09052866581 100644 --- a/docs/architecture/adr-019-protobuf-state-encoding.md +++ b/docs/architecture/adr-019-protobuf-state-encoding.md @@ -3,6 +3,7 @@ ## Changelog - 2020 Feb 15: Initial Draft +- 2020 Feb 24: Updates to handle messages with interface fields ## Status @@ -143,19 +144,6 @@ message Account { ```go // app/codec/codec.go -import ( - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/supply" - authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" - // ... -) - -var ( - _ auth.Codec = (*Codec)(nil) - // ... -) - type Codec struct { codec.Marshaler @@ -192,10 +180,91 @@ about all the required types. Note, the use of `interface_type` allows us to avo amount of code boilerplate when implementing the `Codec`. A similar concept is to be applied for messages that contain interfaces fields. The module will -define a "base" concrete message type (e.g. `MsgSubmitProposalBase`) that the application-level codec -will extend via `oneof` (e.g. `MsgSubmitProposal`) that fulfills the required interface -(e.g. `MsgSubmitProposalI`). Note, however, the module's message handler must now switch on the -interface rather than the concrete type for this particular message. +define a "base" concrete message type that the application-level codec will extend via `oneof` that +fulfills the required message interface. + +Example: + +The `MsgSubmitEvidence` defined by the `x/evidence` module contains a field `Evidence` which is an +interface. + +```go +type MsgSubmitEvidence struct { + Evidence exported.Evidence + Submitter sdk.AccAddress +} +``` + +Instead, we will implement a "base" message type and an interface which the concrete message type +must implement. + +```protobuf +// x/evidence/types/types.proto + +message MsgSubmitEvidenceBase { + bytes submitter = 1 + [ + (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress" + ]; +} +``` + +```go +// x/evidence/exported/evidence.go + +type MsgSubmitEvidence interface { + sdk.Msg + + GetEvidence() Evidence + GetSubmitter() sdk.AccAddress +} +``` + +Notice the `MsgSubmitEvidence` interface extends `sdk.Msg` and allows for the `Evidence` interface +to be retrieved from the concrete message type. + +Now, the application-level codec will define the concrete `MsgSubmitEvidence` type and will have it +fulfill the `MsgSubmitEvidence` interface defined by `x/evidence`. + +```protobuf +// app/codec/codec.proto + +message Evidence { + option (gogoproto.equal) = true; + option (cosmos_proto.interface_type) = "github.com/cosmos/cosmos-sdk/x/evidence/exported.Evidence"; + + oneof sum { + cosmos_sdk.x.evidence.v1.Equivocation equivocation = 1; + } +} + +message MsgSubmitEvidence { + option (gogoproto.equal) = true; + option (gogoproto.goproto_getters) = false; + + Evidence evidence = 1; + cosmos_sdk.x.evidence.v1.MsgSubmitEvidenceBase base = 2 + [ + (gogoproto.nullable) = false, + (gogoproto.embed) = true + ]; +} +``` + +```go +// app/codec/msgs.go + +func (msg MsgSubmitEvidence) GetEvidence() eviexported.Evidence { + return msg.Evidence.GetEvidence() +} + +func (msg MsgSubmitEvidence) GetSubmitter() sdk.AccAddress { + return msg.Submitter +} +``` + +Note, however, the module's message handler must now handle the interface `MsgSubmitEvidence` in +addition to any concrete types. ### Why Wasn't X Chosen Instead diff --git a/simapp/app.go b/simapp/app.go index 049f12270837..fd8bfbb4029e 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -176,7 +176,7 @@ func NewSimApp( appCodec, keys[staking.StoreKey], app.BankKeeper, app.SupplyKeeper, app.subspaces[staking.ModuleName], ) app.MintKeeper = mint.NewKeeper( - app.cdc, keys[mint.StoreKey], app.subspaces[mint.ModuleName], &stakingKeeper, + appCodec, keys[mint.StoreKey], app.subspaces[mint.ModuleName], &stakingKeeper, app.SupplyKeeper, auth.FeeCollectorName, ) app.DistrKeeper = distr.NewKeeper( @@ -193,7 +193,7 @@ func NewSimApp( // create evidence keeper with router evidenceKeeper := evidence.NewKeeper( - app.cdc, keys[evidence.StoreKey], app.subspaces[evidence.ModuleName], &app.StakingKeeper, app.SlashingKeeper, + appCodec, keys[evidence.StoreKey], app.subspaces[evidence.ModuleName], &app.StakingKeeper, app.SlashingKeeper, ) evidenceRouter := evidence.NewRouter() // TODO: Register evidence routes. diff --git a/simapp/codec/codec.go b/simapp/codec/codec.go index 912bd355bc86..abcd8752d224 100644 --- a/simapp/codec/codec.go +++ b/simapp/codec/codec.go @@ -7,13 +7,16 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth" authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" "github.com/cosmos/cosmos-sdk/x/auth/vesting" + "github.com/cosmos/cosmos-sdk/x/evidence" + eviexported "github.com/cosmos/cosmos-sdk/x/evidence/exported" "github.com/cosmos/cosmos-sdk/x/supply" - "github.com/cosmos/cosmos-sdk/x/supply/exported" + supplyexported "github.com/cosmos/cosmos-sdk/x/supply/exported" ) var ( - _ auth.Codec = (*Codec)(nil) - _ supply.Codec = (*Codec)(nil) + _ auth.Codec = (*Codec)(nil) + _ supply.Codec = (*Codec)(nil) + _ evidence.Codec = (*Codec)(nil) ) // Codec defines the application-level codec. This codec contains all the @@ -72,7 +75,7 @@ func (c *Codec) UnmarshalAccountJSON(bz []byte) (authexported.Account, error) { // MarshalSupply marshals a SupplyI interface. If the given type implements // the Marshaler interface, it is treated as a Proto-defined message and // serialized that way. Otherwise, it falls back on the internal Amino codec. -func (c *Codec) MarshalSupply(supplyI exported.SupplyI) ([]byte, error) { +func (c *Codec) MarshalSupply(supplyI supplyexported.SupplyI) ([]byte, error) { supply := &Supply{} if err := supply.SetSupplyI(supplyI); err != nil { return nil, err @@ -83,7 +86,7 @@ func (c *Codec) MarshalSupply(supplyI exported.SupplyI) ([]byte, error) { // UnmarshalSupply returns a SupplyI interface from raw encoded account bytes // of a Proto-based SupplyI type. An error is returned upon decoding failure. -func (c *Codec) UnmarshalSupply(bz []byte) (exported.SupplyI, error) { +func (c *Codec) UnmarshalSupply(bz []byte) (supplyexported.SupplyI, error) { supply := &Supply{} if err := c.Marshaler.UnmarshalBinaryLengthPrefixed(bz, supply); err != nil { return nil, err @@ -94,12 +97,12 @@ func (c *Codec) UnmarshalSupply(bz []byte) (exported.SupplyI, error) { // MarshalSupplyJSON JSON encodes a supply object implementing the SupplyI // interface. -func (c *Codec) MarshalSupplyJSON(supply exported.SupplyI) ([]byte, error) { +func (c *Codec) MarshalSupplyJSON(supply supplyexported.SupplyI) ([]byte, error) { return c.Marshaler.MarshalJSON(supply) } // UnmarshalSupplyJSON returns a SupplyI from JSON encoded bytes. -func (c *Codec) UnmarshalSupplyJSON(bz []byte) (exported.SupplyI, error) { +func (c *Codec) UnmarshalSupplyJSON(bz []byte) (supplyexported.SupplyI, error) { supply := &Supply{} if err := c.Marshaler.UnmarshalJSON(bz, supply); err != nil { return nil, err @@ -108,9 +111,47 @@ func (c *Codec) UnmarshalSupplyJSON(bz []byte) (exported.SupplyI, error) { return supply.GetSupplyI(), nil } -// ---------------------------------------------------------------------------- +// MarshalEvidence marshals an Evidence interface. If the given type implements +// the Marshaler interface, it is treated as a Proto-defined message and +// serialized that way. Otherwise, it falls back on the internal Amino codec. +func (c *Codec) MarshalEvidence(evidenceI eviexported.Evidence) ([]byte, error) { + evidence := &Evidence{} + if err := evidence.SetEvidence(evidenceI); err != nil { + return nil, err + } -// MakeCodec creates and returns a reference to an Amino codec that has all the + return c.Marshaler.MarshalBinaryLengthPrefixed(evidence) +} + +// UnmarshalEvidence returns an Evidence interface from raw encoded evidence +// bytes of a Proto-based Evidence type. An error is returned upon decoding +// failure. +func (c *Codec) UnmarshalEvidence(bz []byte) (eviexported.Evidence, error) { + evidence := &Evidence{} + if err := c.Marshaler.UnmarshalBinaryLengthPrefixed(bz, evidence); err != nil { + return nil, err + } + + return evidence.GetEvidence(), nil +} + +// MarshalEvidenceJSON JSON encodes an evidence object implementing the Evidence +// interface. +func (c *Codec) MarshalEvidenceJSON(evidence eviexported.Evidence) ([]byte, error) { + return c.Marshaler.MarshalJSON(evidence) +} + +// UnmarshalEvidenceJSON returns an Evidence from JSON encoded bytes +func (c *Codec) UnmarshalEvidenceJSON(bz []byte) (eviexported.Evidence, error) { + evidence := &Evidence{} + if err := c.Marshaler.UnmarshalJSON(bz, evidence); err != nil { + return nil, err + } + + return evidence.GetEvidence(), nil +} + +// ---------------------------------------------------------------------------- // necessary types and interfaces registered. This codec is provided to all the // modules the application depends on. // diff --git a/simapp/codec/codec.pb.go b/simapp/codec/codec.pb.go index 775948f5a35f..b222403b46e4 100644 --- a/simapp/codec/codec.pb.go +++ b/simapp/codec/codec.pb.go @@ -8,8 +8,11 @@ import ( github_com_cosmos_cosmos_sdk_x_auth_exported "github.com/cosmos/cosmos-sdk/x/auth/exported" types "github.com/cosmos/cosmos-sdk/x/auth/types" types1 "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" + github_com_cosmos_cosmos_sdk_x_evidence_exported "github.com/cosmos/cosmos-sdk/x/evidence/exported" + types3 "github.com/cosmos/cosmos-sdk/x/evidence/types" github_com_cosmos_cosmos_sdk_x_supply_exported "github.com/cosmos/cosmos-sdk/x/supply/exported" types2 "github.com/cosmos/cosmos-sdk/x/supply/types" + _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" _ "github.com/regen-network/cosmos-proto" io "io" @@ -157,7 +160,7 @@ func (*Account) XXX_OneofWrappers() []interface{} { // Supply defines the application-level Supply type. type Supply struct { - // sum defines a list of all acceptable concrete Supply implementations. + // sum defines a set of all acceptable concrete Supply implementations. // // Types that are valid to be assigned to Sum: // *Supply_Supply @@ -199,6 +202,7 @@ var xxx_messageInfo_Supply proto.InternalMessageInfo type isSupply_Sum interface { isSupply_Sum() + Equal(interface{}) bool MarshalTo([]byte) (int, error) Size() int } @@ -230,45 +234,309 @@ func (*Supply) XXX_OneofWrappers() []interface{} { } } +// Evidence defines the application-level allowed Evidence to be submitted via a +// MsgSubmitEvidence message. +type Evidence struct { + // sum defines a set of all acceptable concrete Evidence implementations. + // + // Types that are valid to be assigned to Sum: + // *Evidence_Equivocation + Sum isEvidence_Sum `protobuf_oneof:"sum"` +} + +func (m *Evidence) Reset() { *m = Evidence{} } +func (m *Evidence) String() string { return proto.CompactTextString(m) } +func (*Evidence) ProtoMessage() {} +func (*Evidence) Descriptor() ([]byte, []int) { + return fileDescriptor_3c6d4085e4065f5a, []int{2} +} +func (m *Evidence) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Evidence) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Evidence.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 *Evidence) XXX_Merge(src proto.Message) { + xxx_messageInfo_Evidence.Merge(m, src) +} +func (m *Evidence) XXX_Size() int { + return m.Size() +} +func (m *Evidence) XXX_DiscardUnknown() { + xxx_messageInfo_Evidence.DiscardUnknown(m) +} + +var xxx_messageInfo_Evidence proto.InternalMessageInfo + +type isEvidence_Sum interface { + isEvidence_Sum() + Equal(interface{}) bool + MarshalTo([]byte) (int, error) + Size() int +} + +type Evidence_Equivocation struct { + Equivocation *types3.Equivocation `protobuf:"bytes,1,opt,name=equivocation,proto3,oneof" json:"equivocation,omitempty"` +} + +func (*Evidence_Equivocation) isEvidence_Sum() {} + +func (m *Evidence) GetSum() isEvidence_Sum { + if m != nil { + return m.Sum + } + return nil +} + +func (m *Evidence) GetEquivocation() *types3.Equivocation { + if x, ok := m.GetSum().(*Evidence_Equivocation); ok { + return x.Equivocation + } + return nil +} + +// XXX_OneofWrappers is for the internal use of the proto package. +func (*Evidence) XXX_OneofWrappers() []interface{} { + return []interface{}{ + (*Evidence_Equivocation)(nil), + } +} + +// MsgSubmitEvidence defines the application-level message type for handling +// evidence submission. +type MsgSubmitEvidence struct { + Evidence *Evidence `protobuf:"bytes,1,opt,name=evidence,proto3" json:"evidence,omitempty"` + types3.MsgSubmitEvidenceBase `protobuf:"bytes,2,opt,name=base,proto3,embedded=base" json:"base"` +} + +func (m *MsgSubmitEvidence) Reset() { *m = MsgSubmitEvidence{} } +func (m *MsgSubmitEvidence) String() string { return proto.CompactTextString(m) } +func (*MsgSubmitEvidence) ProtoMessage() {} +func (*MsgSubmitEvidence) Descriptor() ([]byte, []int) { + return fileDescriptor_3c6d4085e4065f5a, []int{3} +} +func (m *MsgSubmitEvidence) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgSubmitEvidence) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgSubmitEvidence.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 *MsgSubmitEvidence) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgSubmitEvidence.Merge(m, src) +} +func (m *MsgSubmitEvidence) XXX_Size() int { + return m.Size() +} +func (m *MsgSubmitEvidence) XXX_DiscardUnknown() { + xxx_messageInfo_MsgSubmitEvidence.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgSubmitEvidence proto.InternalMessageInfo + func init() { proto.RegisterType((*Account)(nil), "cosmos_sdk.simapp.codec.v1.Account") proto.RegisterType((*Supply)(nil), "cosmos_sdk.simapp.codec.v1.Supply") + proto.RegisterType((*Evidence)(nil), "cosmos_sdk.simapp.codec.v1.Evidence") + proto.RegisterType((*MsgSubmitEvidence)(nil), "cosmos_sdk.simapp.codec.v1.MsgSubmitEvidence") } func init() { proto.RegisterFile("simapp/codec/codec.proto", fileDescriptor_3c6d4085e4065f5a) } var fileDescriptor_3c6d4085e4065f5a = []byte{ - // 444 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x93, 0x4f, 0x8b, 0xd3, 0x40, - 0x18, 0xc6, 0x13, 0x77, 0xb7, 0xc2, 0xac, 0x7a, 0x08, 0xa8, 0x21, 0x87, 0xb0, 0x2e, 0x08, 0xfe, - 0xa1, 0x13, 0xd6, 0xf5, 0xef, 0x7a, 0xb2, 0x15, 0xa9, 0x07, 0x45, 0x2a, 0x78, 0xf0, 0x12, 0x92, - 0x99, 0xa1, 0x0d, 0x6d, 0x32, 0x43, 0x66, 0x26, 0x24, 0x5f, 0xc0, 0xb3, 0x1f, 0xa6, 0x47, 0x3f, - 0x80, 0xf4, 0xd4, 0xa3, 0x47, 0x69, 0xbf, 0x88, 0x74, 0x66, 0x6c, 0x22, 0x49, 0xeb, 0x25, 0xf0, - 0xce, 0xf3, 0xbc, 0xcf, 0xef, 0x0d, 0xf3, 0x0e, 0x70, 0x79, 0x92, 0x46, 0x8c, 0x05, 0x88, 0x62, - 0x82, 0xf4, 0x17, 0xb2, 0x9c, 0x0a, 0xea, 0x78, 0x88, 0xf2, 0x94, 0xf2, 0x90, 0xe3, 0x19, 0xd4, - 0x26, 0xa8, 0xe5, 0xe2, 0xc2, 0x7b, 0x2c, 0xa6, 0x49, 0x8e, 0x43, 0x16, 0xe5, 0xa2, 0x0a, 0x94, - 0x3d, 0xd0, 0xee, 0x7e, 0xb3, 0xd0, 0x41, 0x9e, 0x5b, 0x06, 0x91, 0x14, 0xd3, 0x40, 0x54, 0x8c, - 0x70, 0xfd, 0x35, 0xca, 0x99, 0x51, 0x0a, 0xc2, 0x45, 0x92, 0x4d, 0x3a, 0x1c, 0x5e, 0x19, 0x70, - 0xc9, 0xd8, 0xbc, 0x6a, 0x6b, 0xe7, 0x3f, 0x8e, 0xc1, 0xf5, 0x37, 0x08, 0x51, 0x99, 0x09, 0xe7, - 0x1d, 0xb8, 0x11, 0x47, 0x9c, 0x84, 0x91, 0xae, 0x5d, 0xfb, 0xcc, 0x7e, 0x70, 0xfa, 0xe4, 0x1e, - 0x6c, 0xfc, 0x43, 0x09, 0xb7, 0x2c, 0x58, 0x5c, 0xc0, 0x41, 0xc4, 0x89, 0x69, 0x1c, 0x59, 0xe3, - 0xd3, 0xb8, 0x2e, 0x9d, 0x02, 0x78, 0x88, 0x66, 0x22, 0xc9, 0x24, 0x95, 0x3c, 0x34, 0x73, 0xed, - 0x52, 0xaf, 0xa9, 0xd4, 0xe7, 0x5d, 0xa9, 0xda, 0xb9, 0x4d, 0x1f, 0xee, 0xfa, 0xbf, 0xe8, 0xc3, - 0x1a, 0xe5, 0xa2, 0x3d, 0x9a, 0x93, 0x82, 0xbb, 0x98, 0xcc, 0xa3, 0x8a, 0xe0, 0x16, 0xf4, 0x48, - 0x41, 0x2f, 0x0f, 0x43, 0xdf, 0xea, 0xe6, 0x16, 0xf1, 0x36, 0xee, 0x12, 0x1c, 0x06, 0x5c, 0x46, - 0xf2, 0x84, 0xe2, 0x04, 0xb5, 0x78, 0xc7, 0x8a, 0xf7, 0xf4, 0x30, 0xef, 0x93, 0xe9, 0x6e, 0x01, - 0xef, 0xb0, 0x4e, 0xc5, 0xf9, 0x08, 0x6e, 0xa5, 0x14, 0xcb, 0x79, 0x7d, 0x45, 0x27, 0x8a, 0x73, - 0xff, 0x5f, 0x8e, 0xbe, 0xec, 0x2d, 0xe1, 0x83, 0x72, 0xd7, 0xc1, 0x37, 0xd3, 0xe6, 0xc1, 0xd5, - 0xab, 0xe5, 0xa2, 0xff, 0xec, 0xd1, 0x24, 0x11, 0x53, 0x19, 0x43, 0x44, 0x53, 0xb3, 0x72, 0x7f, - 0xd7, 0x90, 0xe3, 0x59, 0x60, 0x96, 0x8b, 0x94, 0x8c, 0xe6, 0x82, 0x60, 0x68, 0x5a, 0x07, 0x27, - 0xe0, 0x88, 0xcb, 0xf4, 0xfc, 0x9b, 0x0d, 0x7a, 0x9f, 0x15, 0xce, 0x79, 0x09, 0x7a, 0x1a, 0x6c, - 0xf6, 0xc6, 0xdf, 0x37, 0x94, 0xf6, 0x8f, 0xac, 0xb1, 0xf1, 0x5f, 0xbd, 0x5e, 0x2e, 0xfa, 0x2f, - 0xfe, 0x37, 0x86, 0xd9, 0xe0, 0xdd, 0x20, 0x3a, 0xe5, 0xbd, 0x19, 0x64, 0x30, 0xfc, 0xb9, 0xf6, - 0xed, 0xd5, 0xda, 0xb7, 0x7f, 0xaf, 0x7d, 0xfb, 0xfb, 0xc6, 0xb7, 0x56, 0x1b, 0xdf, 0xfa, 0xb5, - 0xf1, 0xad, 0xaf, 0x0f, 0x0f, 0x06, 0x37, 0x5f, 0x6e, 0xdc, 0x53, 0x6f, 0xe2, 0xf2, 0x4f, 0x00, - 0x00, 0x00, 0xff, 0xff, 0xdc, 0xbb, 0x4f, 0xcf, 0xd0, 0x03, 0x00, 0x00, + // 593 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x54, 0x4d, 0x6f, 0xd3, 0x3e, + 0x18, 0x4f, 0xfe, 0xeb, 0xfa, 0xaf, 0xbc, 0x81, 0x44, 0x24, 0xa0, 0xaa, 0x50, 0x3a, 0x26, 0x98, + 0x78, 0x51, 0x13, 0x8d, 0xf1, 0xb6, 0x5e, 0x60, 0x1d, 0x43, 0x45, 0xa2, 0x08, 0x75, 0x12, 0x07, + 0x2e, 0x55, 0x6a, 0x5b, 0xad, 0xb5, 0x26, 0x36, 0xb5, 0x1d, 0xb5, 0xdf, 0x00, 0x71, 0xe2, 0x23, + 0x4c, 0x7c, 0x00, 0x4e, 0x3b, 0xf2, 0x01, 0xa6, 0x9d, 0x7a, 0xe4, 0x34, 0xa1, 0xf6, 0xc2, 0xc7, + 0x40, 0x89, 0x9d, 0xb4, 0x55, 0xda, 0xee, 0x12, 0xd5, 0x7e, 0x7e, 0x6f, 0x76, 0x9f, 0xc7, 0xa0, + 0xc8, 0x89, 0xef, 0x31, 0xe6, 0x42, 0x8a, 0x30, 0x54, 0x5f, 0x87, 0xf5, 0xa9, 0xa0, 0x56, 0x09, + 0x52, 0xee, 0x53, 0xde, 0xe2, 0xe8, 0xc4, 0x51, 0x20, 0x47, 0x95, 0xc3, 0xdd, 0xd2, 0x63, 0xd1, + 0x25, 0x7d, 0xd4, 0x62, 0x5e, 0x5f, 0x0c, 0xdd, 0x18, 0xee, 0x2a, 0x74, 0x65, 0x76, 0xa1, 0x84, + 0x4a, 0x3b, 0x59, 0x70, 0x87, 0x76, 0xe8, 0xf4, 0x97, 0xc6, 0x15, 0x07, 0xae, 0x27, 0x45, 0xd7, + 0x15, 0x43, 0x86, 0xb9, 0xfa, 0xea, 0xca, 0x96, 0xae, 0x84, 0x98, 0x0b, 0x12, 0x74, 0x16, 0x20, + 0x4a, 0x03, 0x97, 0x4b, 0xc6, 0x7a, 0xc3, 0x05, 0xb5, 0x3b, 0x03, 0x17, 0x87, 0x04, 0xe1, 0x00, + 0xe2, 0x6c, 0x75, 0xfb, 0x57, 0x0e, 0xfc, 0x7f, 0x00, 0x21, 0x95, 0x81, 0xb0, 0xde, 0x82, 0xcd, + 0xb6, 0xc7, 0x71, 0xcb, 0x53, 0xeb, 0xa2, 0xb9, 0x65, 0x3e, 0xd8, 0x78, 0x72, 0xd7, 0x99, 0xb9, + 0x89, 0x81, 0x13, 0x25, 0x71, 0xc2, 0x5d, 0xa7, 0xe6, 0x71, 0xac, 0x89, 0x75, 0xa3, 0xb9, 0xd1, + 0x9e, 0x2e, 0xad, 0x10, 0x94, 0x20, 0x0d, 0x04, 0x09, 0x24, 0x95, 0xbc, 0xa5, 0x53, 0xa7, 0xaa, + 0xff, 0xc5, 0xaa, 0xcf, 0x17, 0xa9, 0x2a, 0x64, 0xa4, 0x7e, 0x98, 0xf2, 0x3f, 0xa9, 0xcd, 0xa9, + 0x55, 0x11, 0x2e, 0xa9, 0x59, 0x3e, 0xb8, 0x8d, 0x70, 0xcf, 0x1b, 0x62, 0x94, 0x31, 0x5d, 0x8b, + 0x4d, 0xf7, 0x56, 0x9b, 0xbe, 0x51, 0xe4, 0x8c, 0xe3, 0x4d, 0xb4, 0xa8, 0x60, 0x31, 0x50, 0x64, + 0xb8, 0x4f, 0x28, 0x22, 0x30, 0xe3, 0x97, 0x8b, 0xfd, 0x9e, 0xae, 0xf6, 0xfb, 0xa8, 0xd9, 0x19, + 0xc3, 0x5b, 0x6c, 0x61, 0xc5, 0xfa, 0x00, 0xae, 0xfb, 0x14, 0xc9, 0xde, 0xf4, 0x2f, 0x5a, 0x8f, + 0x7d, 0xee, 0xcf, 0xfb, 0xa8, 0x56, 0x88, 0x1c, 0x1a, 0x31, 0x7a, 0x2a, 0x7c, 0xcd, 0x9f, 0xdd, + 0xa8, 0xee, 0x5f, 0x9c, 0x55, 0x9e, 0x3d, 0xea, 0x10, 0xd1, 0x95, 0x6d, 0x07, 0x52, 0x5f, 0x37, + 0x6e, 0xd2, 0xcc, 0x1c, 0x9d, 0xb8, 0xba, 0xf5, 0xf0, 0x80, 0xd1, 0xbe, 0xc0, 0xc8, 0xd1, 0xd4, + 0xda, 0x3a, 0x58, 0xe3, 0xd2, 0xdf, 0xfe, 0x66, 0x82, 0xfc, 0x71, 0x6c, 0x67, 0xbd, 0x04, 0x79, + 0x65, 0xac, 0xfb, 0xc6, 0x5e, 0x16, 0x4a, 0xe1, 0xeb, 0x46, 0x53, 0xe3, 0xab, 0xaf, 0xfe, 0x9e, + 0x96, 0xcd, 0x8b, 0xb3, 0xca, 0x8b, 0xab, 0xa2, 0xe8, 0x1e, 0x4f, 0xc3, 0x28, 0xa5, 0x77, 0x49, + 0x98, 0x1f, 0x26, 0x28, 0x1c, 0xe9, 0x56, 0xb7, 0xde, 0x83, 0x4d, 0xfc, 0x45, 0x92, 0x90, 0x42, + 0x4f, 0x10, 0x1a, 0xe8, 0x50, 0x3b, 0xf3, 0xa1, 0x92, 0xc1, 0x88, 0x62, 0x1d, 0xcd, 0xa0, 0xeb, + 0x46, 0x73, 0x8e, 0x5d, 0x3d, 0xd0, 0x11, 0xf7, 0xaf, 0x48, 0x98, 0x4e, 0x5a, 0x9a, 0x31, 0x09, + 0x94, 0x84, 0xfc, 0x69, 0x82, 0x1b, 0x0d, 0xde, 0x39, 0x96, 0x6d, 0x9f, 0x88, 0x34, 0xed, 0x6b, + 0x50, 0x48, 0xa8, 0x3a, 0xe9, 0x3d, 0x67, 0xf9, 0x03, 0x94, 0x8a, 0x36, 0x53, 0x96, 0xd5, 0x00, + 0xb9, 0x68, 0x06, 0xf5, 0x78, 0xb9, 0xcb, 0xcf, 0x99, 0x31, 0x8f, 0x26, 0xb9, 0x56, 0x38, 0xbf, + 0x2c, 0x1b, 0xa3, 0xcb, 0xb2, 0xd9, 0x8c, 0x65, 0xaa, 0x85, 0xaf, 0xa7, 0x65, 0x23, 0x3a, 0x74, + 0xed, 0xf0, 0x7c, 0x6c, 0x9b, 0xa3, 0xb1, 0x6d, 0xfe, 0x19, 0xdb, 0xe6, 0xf7, 0x89, 0x6d, 0x8c, + 0x26, 0xb6, 0xf1, 0x7b, 0x62, 0x1b, 0x9f, 0x1f, 0xae, 0xbc, 0x8c, 0xd9, 0x97, 0xb5, 0x9d, 0x8f, + 0x5f, 0x9b, 0xbd, 0x7f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x57, 0xb9, 0x47, 0x37, 0x70, 0x05, 0x00, + 0x00, } +func (this *Supply) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*Supply) + if !ok { + that2, ok := that.(Supply) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if that1.Sum == nil { + if this.Sum != nil { + return false + } + } else if this.Sum == nil { + return false + } else if !this.Sum.Equal(that1.Sum) { + return false + } + return true +} +func (this *Supply_Supply) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*Supply_Supply) + if !ok { + that2, ok := that.(Supply_Supply) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !this.Supply.Equal(that1.Supply) { + return false + } + return true +} +func (this *Evidence) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*Evidence) + if !ok { + that2, ok := that.(Evidence) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if that1.Sum == nil { + if this.Sum != nil { + return false + } + } else if this.Sum == nil { + return false + } else if !this.Sum.Equal(that1.Sum) { + return false + } + return true +} +func (this *Evidence_Equivocation) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*Evidence_Equivocation) + if !ok { + that2, ok := that.(Evidence_Equivocation) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !this.Equivocation.Equal(that1.Equivocation) { + return false + } + return true +} +func (this *MsgSubmitEvidence) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*MsgSubmitEvidence) + if !ok { + that2, ok := that.(MsgSubmitEvidence) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !this.Evidence.Equal(that1.Evidence) { + return false + } + if !this.MsgSubmitEvidenceBase.Equal(&that1.MsgSubmitEvidenceBase) { + return false + } + return true +} func (this *Account) GetAccount() github_com_cosmos_cosmos_sdk_x_auth_exported.Account { if x := this.GetBaseAccount(); x != nil { return x @@ -333,6 +601,29 @@ func (this *Supply) SetSupplyI(value github_com_cosmos_cosmos_sdk_x_supply_expor return fmt.Errorf("can't encode value of type %T as message Supply", value) } +func (this *Evidence) GetEvidence() github_com_cosmos_cosmos_sdk_x_evidence_exported.Evidence { + if x := this.GetEquivocation(); x != nil { + return x + } + return nil +} + +func (this *Evidence) SetEvidence(value github_com_cosmos_cosmos_sdk_x_evidence_exported.Evidence) error { + if value == nil { + this.Sum = nil + return nil + } + switch vt := value.(type) { + case *types3.Equivocation: + this.Sum = &Evidence_Equivocation{vt} + return nil + case types3.Equivocation: + this.Sum = &Evidence_Equivocation{&vt} + return nil + } + return fmt.Errorf("can't encode value of type %T as message Evidence", value) +} + func (m *Account) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -523,6 +814,104 @@ func (m *Supply_Supply) MarshalToSizedBuffer(dAtA []byte) (int, error) { } return len(dAtA) - i, nil } +func (m *Evidence) 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 *Evidence) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Evidence) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Sum != nil { + { + size := m.Sum.Size() + i -= size + if _, err := m.Sum.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + } + } + return len(dAtA) - i, nil +} + +func (m *Evidence_Equivocation) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Evidence_Equivocation) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.Equivocation != nil { + { + size, err := m.Equivocation.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} +func (m *MsgSubmitEvidence) 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 *MsgSubmitEvidence) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgSubmitEvidence) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.MsgSubmitEvidenceBase.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if m.Evidence != nil { + { + size, err := m.Evidence.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintCodec(dAtA []byte, offset int, v uint64) int { offset -= sovCodec(v) base := offset @@ -630,6 +1019,44 @@ func (m *Supply_Supply) Size() (n int) { } return n } +func (m *Evidence) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Sum != nil { + n += m.Sum.Size() + } + return n +} + +func (m *Evidence_Equivocation) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Equivocation != nil { + l = m.Equivocation.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *MsgSubmitEvidence) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Evidence != nil { + l = m.Evidence.Size() + n += 1 + l + sovCodec(uint64(l)) + } + l = m.MsgSubmitEvidenceBase.Size() + n += 1 + l + sovCodec(uint64(l)) + return n +} func sovCodec(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 @@ -953,6 +1380,216 @@ func (m *Supply) Unmarshal(dAtA []byte) error { } return nil } +func (m *Evidence) 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 ErrIntOverflowCodec + } + 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: Evidence: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Evidence: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Equivocation", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &types3.Equivocation{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Sum = &Evidence_Equivocation{v} + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCodec(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgSubmitEvidence) 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 ErrIntOverflowCodec + } + 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: MsgSubmitEvidence: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSubmitEvidence: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Evidence", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Evidence == nil { + m.Evidence = &Evidence{} + } + if err := m.Evidence.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MsgSubmitEvidenceBase", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.MsgSubmitEvidenceBase.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCodec(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipCodec(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/simapp/codec/codec.proto b/simapp/codec/codec.proto index 811e65d514b8..2b68c487a64b 100644 --- a/simapp/codec/codec.proto +++ b/simapp/codec/codec.proto @@ -2,9 +2,11 @@ syntax = "proto3"; package cosmos_sdk.simapp.codec.v1; import "third_party/proto/cosmos-proto/cosmos.proto"; +import "third_party/proto/gogoproto/gogo.proto"; import "x/auth/types/types.proto"; import "x/auth/vesting/types/types.proto"; import "x/supply/types/types.proto"; +import "x/evidence/types/types.proto"; option go_package = "github.com/cosmos/cosmos-sdk/simapp/codec"; @@ -24,10 +26,33 @@ message Account { // Supply defines the application-level Supply type. message Supply { + option (gogoproto.equal) = true; option (cosmos_proto.interface_type) = "*github.com/cosmos/cosmos-sdk/x/supply/exported.SupplyI"; - // sum defines a list of all acceptable concrete Supply implementations. + // sum defines a set of all acceptable concrete Supply implementations. oneof sum { cosmos_sdk.x.supply.v1.Supply supply = 1; } } + +// Evidence defines the application-level allowed Evidence to be submitted via a +// MsgSubmitEvidence message. +message Evidence { + option (gogoproto.equal) = true; + option (cosmos_proto.interface_type) = "github.com/cosmos/cosmos-sdk/x/evidence/exported.Evidence"; + + // sum defines a set of all acceptable concrete Evidence implementations. + oneof sum { + cosmos_sdk.x.evidence.v1.Equivocation equivocation = 1; + } +} + +// MsgSubmitEvidence defines the application-level message type for handling +// evidence submission. +message MsgSubmitEvidence { + option (gogoproto.equal) = true; + option (gogoproto.goproto_getters) = false; + + Evidence evidence = 1; + cosmos_sdk.x.evidence.v1.MsgSubmitEvidenceBase base = 2 [(gogoproto.nullable) = false, (gogoproto.embed) = true]; +} diff --git a/simapp/codec/msgs.go b/simapp/codec/msgs.go new file mode 100644 index 000000000000..d6390261bee4 --- /dev/null +++ b/simapp/codec/msgs.go @@ -0,0 +1,38 @@ +package codec + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/evidence" + eviexported "github.com/cosmos/cosmos-sdk/x/evidence/exported" +) + +var _ eviexported.MsgSubmitEvidence = MsgSubmitEvidence{} + +// NewMsgSubmitEvidence returns a new MsgSubmitEvidence. +func NewMsgSubmitEvidence(evidenceI eviexported.Evidence, s sdk.AccAddress) MsgSubmitEvidence { + e := &Evidence{} + e.SetEvidence(evidenceI) + + return MsgSubmitEvidence{Evidence: e, MsgSubmitEvidenceBase: evidence.NewMsgSubmitEvidenceBase(s)} +} + +// ValidateBasic performs basic (non-state-dependant) validation on a +// MsgSubmitEvidence. +func (msg MsgSubmitEvidence) ValidateBasic() error { + if err := msg.MsgSubmitEvidenceBase.ValidateBasic(); err != nil { + return nil + } + if msg.Evidence == nil { + return sdkerrors.Wrap(evidence.ErrInvalidEvidence, "missing evidence") + } + if err := msg.Evidence.GetEvidence().ValidateBasic(); err != nil { + return err + } + + return nil +} + +// nolint +func (msg MsgSubmitEvidence) GetEvidence() eviexported.Evidence { return msg.Evidence.GetEvidence() } +func (msg MsgSubmitEvidence) GetSubmitter() sdk.AccAddress { return msg.Submitter } diff --git a/x/auth/types/types.proto b/x/auth/types/types.proto index eb059f4724f2..99bf50bc8524 100644 --- a/x/auth/types/types.proto +++ b/x/auth/types/types.proto @@ -13,8 +13,8 @@ message BaseAccount { option (gogoproto.goproto_getters) = false; option (gogoproto.goproto_stringer) = false; - bytes address = 1 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; - bytes pub_key = 2 [(gogoproto.moretags) = "yaml:\"public_key\""]; + bytes address = 1 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; + bytes pub_key = 2 [(gogoproto.moretags) = "yaml:\"public_key\""]; uint64 account_number = 3 [(gogoproto.moretags) = "yaml:\"account_number\""]; uint64 sequence = 4; } @@ -25,10 +25,8 @@ message BaseAccount { message StdFee { option (gogoproto.equal) = true; - repeated cosmos_sdk.v1.Coin amount = 1 [ - (gogoproto.nullable) = false, - (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" - ]; + repeated cosmos_sdk.v1.Coin amount = 1 + [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; uint64 gas = 2; } @@ -40,12 +38,8 @@ message Params { uint64 max_memo_characters = 1 [(gogoproto.moretags) = "yaml:\"max_memo_characters\""]; uint64 tx_sig_limit = 2 [(gogoproto.moretags) = "yaml:\"tx_sig_limit\""]; uint64 tx_size_cost_per_byte = 3 [(gogoproto.moretags) = "yaml:\"tx_size_cost_per_byte\""]; - uint64 sig_verify_cost_ed25519 = 4 [ - (gogoproto.customname) = "SigVerifyCostED25519", - (gogoproto.moretags) = "yaml:\"sig_verify_cost_ed25519\"" - ]; - uint64 sig_verify_cost_secp256k1 = 5 [ - (gogoproto.customname) = "SigVerifyCostSecp256k1", - (gogoproto.moretags) = "yaml:\"sig_verify_cost_secp256k1\"" - ]; + uint64 sig_verify_cost_ed25519 = 4 + [(gogoproto.customname) = "SigVerifyCostED25519", (gogoproto.moretags) = "yaml:\"sig_verify_cost_ed25519\""]; + uint64 sig_verify_cost_secp256k1 = 5 + [(gogoproto.customname) = "SigVerifyCostSecp256k1", (gogoproto.moretags) = "yaml:\"sig_verify_cost_secp256k1\""]; } diff --git a/x/evidence/alias.go b/x/evidence/alias.go index 29b8447a365e..395d8a36616f 100644 --- a/x/evidence/alias.go +++ b/x/evidence/alias.go @@ -1,8 +1,8 @@ package evidence import ( - "github.com/cosmos/cosmos-sdk/x/evidence/internal/keeper" - "github.com/cosmos/cosmos-sdk/x/evidence/internal/types" + "github.com/cosmos/cosmos-sdk/x/evidence/keeper" + "github.com/cosmos/cosmos-sdk/x/evidence/types" ) // nolint @@ -27,12 +27,11 @@ var ( NewKeeper = keeper.NewKeeper NewQuerier = keeper.NewQuerier - NewMsgSubmitEvidence = types.NewMsgSubmitEvidence + NewMsgSubmitEvidenceBase = types.NewMsgSubmitEvidenceBase NewRouter = types.NewRouter NewQueryEvidenceParams = types.NewQueryEvidenceParams NewQueryAllEvidenceParams = types.NewQueryAllEvidenceParams RegisterCodec = types.RegisterCodec - RegisterEvidenceTypeCodec = types.RegisterEvidenceTypeCodec ModuleCdc = types.ModuleCdc NewGenesisState = types.NewGenesisState DefaultGenesisState = types.DefaultGenesisState @@ -40,14 +39,19 @@ var ( KeyMaxEvidenceAge = types.KeyMaxEvidenceAge DoubleSignJailEndTime = types.DoubleSignJailEndTime ParamKeyTable = types.ParamKeyTable + ErrNoEvidenceHandlerExists = types.ErrNoEvidenceHandlerExists + ErrInvalidEvidence = types.ErrInvalidEvidence + ErrNoEvidenceExists = types.ErrNoEvidenceExists + ErrEvidenceExists = types.ErrEvidenceExists ) type ( Keeper = keeper.Keeper - GenesisState = types.GenesisState - MsgSubmitEvidence = types.MsgSubmitEvidence - Handler = types.Handler - Router = types.Router - Equivocation = types.Equivocation + GenesisState = types.GenesisState + MsgSubmitEvidenceBase = types.MsgSubmitEvidenceBase + Handler = types.Handler + Router = types.Router + Equivocation = types.Equivocation + Codec = types.Codec ) diff --git a/x/evidence/client/cli/query.go b/x/evidence/client/cli/query.go index da09ae7b4b42..141711ab7a77 100644 --- a/x/evidence/client/cli/query.go +++ b/x/evidence/client/cli/query.go @@ -14,7 +14,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/x/evidence/exported" - "github.com/cosmos/cosmos-sdk/x/evidence/internal/types" + "github.com/cosmos/cosmos-sdk/x/evidence/types" ) // GetQueryCmd returns the CLI command with all evidence module query commands diff --git a/x/evidence/client/cli/tx.go b/x/evidence/client/cli/tx.go index b97b56c0a23d..c14c3d5d0555 100644 --- a/x/evidence/client/cli/tx.go +++ b/x/evidence/client/cli/tx.go @@ -4,7 +4,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/x/evidence/internal/types" + "github.com/cosmos/cosmos-sdk/x/evidence/types" "github.com/spf13/cobra" ) diff --git a/x/evidence/client/rest/query.go b/x/evidence/client/rest/query.go index 45b66660ac73..24fc811eb5e0 100644 --- a/x/evidence/client/rest/query.go +++ b/x/evidence/client/rest/query.go @@ -7,7 +7,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/types/rest" - "github.com/cosmos/cosmos-sdk/x/evidence/internal/types" + "github.com/cosmos/cosmos-sdk/x/evidence/types" "github.com/gorilla/mux" ) diff --git a/x/evidence/exported/evidence.go b/x/evidence/exported/evidence.go index 55b9ef1671cc..b8b6d9ef39eb 100644 --- a/x/evidence/exported/evidence.go +++ b/x/evidence/exported/evidence.go @@ -27,3 +27,13 @@ type Evidence interface { // The total validator set power at time of infraction GetTotalPower() int64 } + +// MsgSubmitEvidence defines the specific interface a concrete message must +// implement in order to process submitted evidence. The concrete MsgSubmitEvidence +// must be defined at the application-level. +type MsgSubmitEvidence interface { + sdk.Msg + + GetEvidence() Evidence + GetSubmitter() sdk.AccAddress +} diff --git a/x/evidence/genesis_test.go b/x/evidence/genesis_test.go index 10a8a2c75730..83e9e26bf202 100644 --- a/x/evidence/genesis_test.go +++ b/x/evidence/genesis_test.go @@ -3,16 +3,16 @@ package evidence_test import ( "testing" + "github.com/stretchr/testify/suite" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto/ed25519" + "github.com/tendermint/tendermint/types/time" "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/evidence" "github.com/cosmos/cosmos-sdk/x/evidence/exported" - "github.com/cosmos/cosmos-sdk/x/evidence/internal/types" - - "github.com/stretchr/testify/suite" + "github.com/cosmos/cosmos-sdk/x/evidence/types" ) type GenesisTestSuite struct { @@ -26,20 +26,8 @@ func (suite *GenesisTestSuite) SetupTest() { checkTx := false app := simapp.Setup(checkTx) - // get the app's codec and register custom testing types - cdc := app.Codec() - cdc.RegisterConcrete(types.TestEquivocationEvidence{}, "test/TestEquivocationEvidence", nil) - - // recreate keeper in order to use custom testing types - evidenceKeeper := evidence.NewKeeper( - cdc, app.GetKey(evidence.StoreKey), app.GetSubspace(evidence.ModuleName), app.StakingKeeper, app.SlashingKeeper, - ) - router := evidence.NewRouter() - router = router.AddRoute(types.TestEvidenceRouteEquivocation, types.TestEquivocationHandler(*evidenceKeeper)) - evidenceKeeper.SetRouter(router) - suite.ctx = app.BaseApp.NewContext(checkTx, abci.Header{Height: 1}) - suite.keeper = *evidenceKeeper + suite.keeper = app.EvidenceKeeper } func (suite *GenesisTestSuite) TestInitGenesis_Valid() { @@ -47,21 +35,11 @@ func (suite *GenesisTestSuite) TestInitGenesis_Valid() { testEvidence := make([]exported.Evidence, 100) for i := 0; i < 100; i++ { - sv := types.TestVote{ - ValidatorAddress: pk.PubKey().Address(), - Height: int64(i), - Round: 0, - } - sig, err := pk.Sign(sv.SignBytes("test-chain")) - suite.NoError(err) - sv.Signature = sig - - testEvidence[i] = types.TestEquivocationEvidence{ - Power: 100, - TotalPower: 100000, - PubKey: pk.PubKey(), - VoteA: sv, - VoteB: sv, + testEvidence[i] = types.Equivocation{ + Height: int64(i + 1), + Power: 100, + Time: time.Now().UTC(), + ConsensusAddress: pk.PubKey().Address().Bytes(), } } @@ -80,21 +58,10 @@ func (suite *GenesisTestSuite) TestInitGenesis_Invalid() { testEvidence := make([]exported.Evidence, 100) for i := 0; i < 100; i++ { - sv := types.TestVote{ - ValidatorAddress: pk.PubKey().Address(), - Height: int64(i), - Round: 0, - } - sig, err := pk.Sign(sv.SignBytes("test-chain")) - suite.NoError(err) - sv.Signature = sig - - testEvidence[i] = types.TestEquivocationEvidence{ - Power: 100, - TotalPower: 100000, - PubKey: pk.PubKey(), - VoteA: sv, - VoteB: types.TestVote{Height: 10, Round: 1}, + testEvidence[i] = types.Equivocation{ + Power: 100, + Time: time.Now().UTC(), + ConsensusAddress: pk.PubKey().Address().Bytes(), } } diff --git a/x/evidence/handler.go b/x/evidence/handler.go index d5af1206bc01..e7b83eb1900d 100644 --- a/x/evidence/handler.go +++ b/x/evidence/handler.go @@ -3,6 +3,7 @@ package evidence import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/evidence/exported" ) func NewHandler(k Keeper) sdk.Handler { @@ -10,17 +11,23 @@ func NewHandler(k Keeper) sdk.Handler { ctx = ctx.WithEventManager(sdk.NewEventManager()) switch msg := msg.(type) { - case MsgSubmitEvidence: - return handleMsgSubmitEvidence(ctx, k, msg) + case MsgSubmitEvidenceBase: + return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "%T must be extended to support evidence", msg) default: + msgSubEv, ok := msg.(exported.MsgSubmitEvidence) + if ok { + return handleMsgSubmitEvidence(ctx, k, msgSubEv) + } + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s message type: %T", ModuleName, msg) } } } -func handleMsgSubmitEvidence(ctx sdk.Context, k Keeper, msg MsgSubmitEvidence) (*sdk.Result, error) { - if err := k.SubmitEvidence(ctx, msg.Evidence); err != nil { +func handleMsgSubmitEvidence(ctx sdk.Context, k Keeper, msg exported.MsgSubmitEvidence) (*sdk.Result, error) { + evidence := msg.GetEvidence() + if err := k.SubmitEvidence(ctx, evidence); err != nil { return nil, err } @@ -28,12 +35,12 @@ func handleMsgSubmitEvidence(ctx sdk.Context, k Keeper, msg MsgSubmitEvidence) ( sdk.NewEvent( sdk.EventTypeMessage, sdk.NewAttribute(sdk.AttributeKeyModule, AttributeValueCategory), - sdk.NewAttribute(sdk.AttributeKeySender, msg.Submitter.String()), + sdk.NewAttribute(sdk.AttributeKeySender, msg.GetSubmitter().String()), ), ) return &sdk.Result{ - Data: msg.Evidence.Hash(), + Data: evidence.Hash(), Events: ctx.EventManager().Events(), }, nil } diff --git a/x/evidence/handler_test.go b/x/evidence/handler_test.go index e5798bd01482..2d766e9d8fa8 100644 --- a/x/evidence/handler_test.go +++ b/x/evidence/handler_test.go @@ -1,102 +1,118 @@ package evidence_test import ( + "fmt" "testing" - - "github.com/cosmos/cosmos-sdk/simapp" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/evidence" - "github.com/cosmos/cosmos-sdk/x/evidence/internal/types" + "time" "github.com/stretchr/testify/suite" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto/ed25519" + + "github.com/cosmos/cosmos-sdk/simapp" + simappcodec "github.com/cosmos/cosmos-sdk/simapp/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/evidence" + "github.com/cosmos/cosmos-sdk/x/evidence/exported" + "github.com/cosmos/cosmos-sdk/x/evidence/types" ) type HandlerTestSuite struct { suite.Suite - ctx sdk.Context handler sdk.Handler - keeper evidence.Keeper + app *simapp.SimApp +} + +func testEquivocationHandler(k interface{}) types.Handler { + return func(ctx sdk.Context, e exported.Evidence) error { + if err := e.ValidateBasic(); err != nil { + return err + } + + ee, ok := e.(*types.Equivocation) + if !ok { + return fmt.Errorf("unexpected evidence type: %T", e) + } + if ee.Height%2 == 0 { + return fmt.Errorf("unexpected even evidence height: %d", ee.Height) + } + + return nil + } } func (suite *HandlerTestSuite) SetupTest() { checkTx := false app := simapp.Setup(checkTx) - // get the app's codec and register custom testing types - cdc := app.Codec() - cdc.RegisterConcrete(types.TestEquivocationEvidence{}, "test/TestEquivocationEvidence", nil) - // recreate keeper in order to use custom testing types evidenceKeeper := evidence.NewKeeper( - cdc, app.GetKey(evidence.StoreKey), app.GetSubspace(evidence.ModuleName), app.StakingKeeper, app.SlashingKeeper, + simappcodec.NewAppCodec(app.Codec()), app.GetKey(evidence.StoreKey), + app.GetSubspace(evidence.ModuleName), app.StakingKeeper, app.SlashingKeeper, ) router := evidence.NewRouter() - router = router.AddRoute(types.TestEvidenceRouteEquivocation, types.TestEquivocationHandler(*evidenceKeeper)) + router = router.AddRoute(types.RouteEquivocation, testEquivocationHandler(*evidenceKeeper)) evidenceKeeper.SetRouter(router) - suite.ctx = app.BaseApp.NewContext(checkTx, abci.Header{Height: 1}) + app.EvidenceKeeper = *evidenceKeeper + suite.handler = evidence.NewHandler(*evidenceKeeper) - suite.keeper = *evidenceKeeper + suite.app = app } -func (suite *HandlerTestSuite) TestMsgSubmitEvidence_Valid() { +func (suite *HandlerTestSuite) TestMsgSubmitEvidence() { pk := ed25519.GenPrivKey() - sv := types.TestVote{ - ValidatorAddress: pk.PubKey().Address(), - Height: 11, - Round: 0, - } - - sig, err := pk.Sign(sv.SignBytes(suite.ctx.ChainID())) - suite.NoError(err) - sv.Signature = sig - s := sdk.AccAddress("test") - e := types.TestEquivocationEvidence{ - Power: 100, - TotalPower: 100000, - PubKey: pk.PubKey(), - VoteA: sv, - VoteB: sv, - } - ctx := suite.ctx.WithIsCheckTx(false) - msg := evidence.NewMsgSubmitEvidence(e, s) - res, err := suite.handler(ctx, msg) - suite.NoError(err) - suite.NotNil(res) - suite.Equal(e.Hash().Bytes(), res.Data) -} - -func (suite *HandlerTestSuite) TestMsgSubmitEvidence_Invalid() { - pk := ed25519.GenPrivKey() - sv := types.TestVote{ - ValidatorAddress: pk.PubKey().Address(), - Height: 11, - Round: 0, + testCases := []struct { + msg sdk.Msg + expectErr bool + }{ + { + simappcodec.NewMsgSubmitEvidence( + &types.Equivocation{ + Height: 11, + Time: time.Now().UTC(), + Power: 100, + ConsensusAddress: pk.PubKey().Address().Bytes(), + }, + s, + ), + false, + }, + { + simappcodec.NewMsgSubmitEvidence( + &types.Equivocation{ + Height: 10, + Time: time.Now().UTC(), + Power: 100, + ConsensusAddress: pk.PubKey().Address().Bytes(), + }, + s, + ), + true, + }, + { + types.NewMsgSubmitEvidenceBase(s), + true, + }, } - sig, err := pk.Sign(sv.SignBytes(suite.ctx.ChainID())) - suite.NoError(err) - sv.Signature = sig + for i, tc := range testCases { + ctx := suite.app.BaseApp.NewContext(false, abci.Header{Height: suite.app.LastBlockHeight() + 1}) - s := sdk.AccAddress("test") - e := types.TestEquivocationEvidence{ - Power: 100, - TotalPower: 100000, - PubKey: pk.PubKey(), - VoteA: sv, - VoteB: types.TestVote{Height: 10, Round: 1}, - } + res, err := suite.handler(ctx, tc.msg) + if tc.expectErr { + suite.Require().Error(err, "expected error; tc #%d", i) + } else { + suite.Require().NoError(err, "unexpected error; tc #%d", i) + suite.Require().NotNil(res, "expected non-nil result; tc #%d", i) - ctx := suite.ctx.WithIsCheckTx(false) - msg := evidence.NewMsgSubmitEvidence(e, s) - res, err := suite.handler(ctx, msg) - suite.Error(err) - suite.Nil(res) + msg := tc.msg.(simappcodec.MsgSubmitEvidence) + suite.Require().Equal(msg.GetEvidence().Hash().Bytes(), res.Data, "invalid hash; tc #%d", i) + } + } } func TestHandlerTestSuite(t *testing.T) { diff --git a/x/evidence/internal/keeper/params_test.go b/x/evidence/internal/keeper/params_test.go deleted file mode 100644 index 58d25230eec7..000000000000 --- a/x/evidence/internal/keeper/params_test.go +++ /dev/null @@ -1,11 +0,0 @@ -package keeper_test - -import ( - "github.com/cosmos/cosmos-sdk/x/evidence/internal/types" -) - -func (suite *KeeperTestSuite) TestParams() { - ctx := suite.ctx.WithIsCheckTx(false) - suite.Equal(types.DefaultParams(), suite.keeper.GetParams(ctx)) - suite.Equal(types.DefaultMaxEvidenceAge, suite.keeper.MaxEvidenceAge(ctx)) -} diff --git a/x/evidence/internal/types/codec.go b/x/evidence/internal/types/codec.go deleted file mode 100644 index 7c57bc4a71f8..000000000000 --- a/x/evidence/internal/types/codec.go +++ /dev/null @@ -1,29 +0,0 @@ -package types - -import ( - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/x/evidence/exported" -) - -// ModuleCdc defines the evidence module's codec. The codec is not sealed as to -// allow other modules to register their concrete Evidence types. -var ModuleCdc = codec.New() - -// RegisterCodec registers all the necessary types and interfaces for the -// evidence module. -func RegisterCodec(cdc *codec.Codec) { - cdc.RegisterInterface((*exported.Evidence)(nil), nil) - cdc.RegisterConcrete(MsgSubmitEvidence{}, "cosmos-sdk/MsgSubmitEvidence", nil) - cdc.RegisterConcrete(Equivocation{}, "cosmos-sdk/Equivocation", nil) -} - -// RegisterEvidenceTypeCodec registers an external concrete Evidence type defined -// in another module for the internal ModuleCdc. This allows the MsgSubmitEvidence -// to be correctly Amino encoded and decoded. -func RegisterEvidenceTypeCodec(o interface{}, name string) { - ModuleCdc.RegisterConcrete(o, name, nil) -} - -func init() { - RegisterCodec(ModuleCdc) -} diff --git a/x/evidence/internal/types/codec_test.go b/x/evidence/internal/types/codec_test.go deleted file mode 100644 index e175a7292e94..000000000000 --- a/x/evidence/internal/types/codec_test.go +++ /dev/null @@ -1,42 +0,0 @@ -package types_test - -import ( - "testing" - - "github.com/stretchr/testify/require" - tmbytes "github.com/tendermint/tendermint/libs/bytes" - - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/evidence/exported" - "github.com/cosmos/cosmos-sdk/x/evidence/internal/types" -) - -var _ exported.Evidence = (*testEvidence)(nil) - -type testEvidence struct{} - -func (te testEvidence) Route() string { return "" } -func (te testEvidence) Type() string { return "" } -func (te testEvidence) String() string { return "" } -func (te testEvidence) ValidateBasic() error { return nil } -func (te testEvidence) GetConsensusAddress() sdk.ConsAddress { return nil } -func (te testEvidence) Hash() tmbytes.HexBytes { return nil } -func (te testEvidence) GetHeight() int64 { return 0 } -func (te testEvidence) GetValidatorPower() int64 { return 0 } -func (te testEvidence) GetTotalPower() int64 { return 0 } - -func TestCodec(t *testing.T) { - cdc := codec.New() - types.RegisterCodec(cdc) - types.RegisterEvidenceTypeCodec(testEvidence{}, "cosmos-sdk/testEvidence") - - var e exported.Evidence = testEvidence{} - bz, err := cdc.MarshalBinaryBare(e) - require.NoError(t, err) - - var te testEvidence - require.NoError(t, cdc.UnmarshalBinaryBare(bz, &te)) - - require.Panics(t, func() { types.RegisterEvidenceTypeCodec(testEvidence{}, "cosmos-sdk/testEvidence") }) -} diff --git a/x/evidence/internal/types/msgs.go b/x/evidence/internal/types/msgs.go deleted file mode 100644 index 3fbb50844f57..000000000000 --- a/x/evidence/internal/types/msgs.go +++ /dev/null @@ -1,59 +0,0 @@ -package types - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/cosmos-sdk/x/evidence/exported" -) - -// Message types for the evidence module -const ( - TypeMsgSubmitEvidence = "submit_evidence" -) - -var ( - _ sdk.Msg = MsgSubmitEvidence{} -) - -// MsgSubmitEvidence defines an sdk.Msg type that supports submitting arbitrary -// Evidence. -type MsgSubmitEvidence struct { - Evidence exported.Evidence `json:"evidence" yaml:"evidence"` - Submitter sdk.AccAddress `json:"submitter" yaml:"submitter"` -} - -func NewMsgSubmitEvidence(e exported.Evidence, s sdk.AccAddress) MsgSubmitEvidence { - return MsgSubmitEvidence{Evidence: e, Submitter: s} -} - -// Route returns the MsgSubmitEvidence's route. -func (m MsgSubmitEvidence) Route() string { return RouterKey } - -// Type returns the MsgSubmitEvidence's type. -func (m MsgSubmitEvidence) Type() string { return TypeMsgSubmitEvidence } - -// ValidateBasic performs basic (non-state-dependant) validation on a MsgSubmitEvidence. -func (m MsgSubmitEvidence) ValidateBasic() error { - if m.Evidence == nil { - return sdkerrors.Wrap(ErrInvalidEvidence, "missing evidence") - } - if err := m.Evidence.ValidateBasic(); err != nil { - return err - } - if m.Submitter.Empty() { - return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, m.Submitter.String()) - } - - return nil -} - -// GetSignBytes returns the raw bytes a signer is expected to sign when submitting -// a MsgSubmitEvidence message. -func (m MsgSubmitEvidence) GetSignBytes() []byte { - return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(m)) -} - -// GetSigners returns the single expected signer for a MsgSubmitEvidence. -func (m MsgSubmitEvidence) GetSigners() []sdk.AccAddress { - return []sdk.AccAddress{m.Submitter} -} diff --git a/x/evidence/internal/types/msgs_test.go b/x/evidence/internal/types/msgs_test.go deleted file mode 100644 index 5a50ba6e7b2a..000000000000 --- a/x/evidence/internal/types/msgs_test.go +++ /dev/null @@ -1,66 +0,0 @@ -package types_test - -import ( - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/evidence/exported" - "github.com/cosmos/cosmos-sdk/x/evidence/internal/types" - - "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/crypto/ed25519" -) - -func TestMsgSubmitEvidence(t *testing.T) { - pk := ed25519.GenPrivKey() - sv := types.TestVote{ - ValidatorAddress: pk.PubKey().Address(), - Height: 11, - Round: 0, - } - sig, err := pk.Sign(sv.SignBytes("test-chain")) - require.NoError(t, err) - sv.Signature = sig - - submitter := sdk.AccAddress("test") - testCases := []struct { - evidence exported.Evidence - submitter sdk.AccAddress - expectErr bool - }{ - {nil, submitter, true}, - { - types.TestEquivocationEvidence{ - Power: 100, - TotalPower: 100000, - PubKey: pk.PubKey(), - VoteA: sv, - VoteB: sv, - }, - submitter, - false, - }, - { - types.TestEquivocationEvidence{ - Power: 100, - TotalPower: 100000, - PubKey: pk.PubKey(), - VoteA: sv, - VoteB: types.TestVote{Height: 10, Round: 1}, - }, - submitter, - true, - }, - } - - for i, tc := range testCases { - msg := types.NewMsgSubmitEvidence(tc.evidence, tc.submitter) - require.Equal(t, msg.Route(), types.RouterKey, "unexpected result for tc #%d", i) - require.Equal(t, msg.Type(), types.TypeMsgSubmitEvidence, "unexpected result for tc #%d", i) - require.Equal(t, tc.expectErr, msg.ValidateBasic() != nil, "unexpected result for tc #%d", i) - - if !tc.expectErr { - require.Equal(t, msg.GetSigners(), []sdk.AccAddress{tc.submitter}, "unexpected result for tc #%d", i) - } - } -} diff --git a/x/evidence/internal/types/test_util.go b/x/evidence/internal/types/test_util.go deleted file mode 100644 index 24500cba993c..000000000000 --- a/x/evidence/internal/types/test_util.go +++ /dev/null @@ -1,135 +0,0 @@ -/* -Common testing types and utility functions and methods to be used in unit and -integration testing of the evidence module. -*/ -// DONTCOVER -package types - -import ( - "bytes" - "errors" - "fmt" - "time" - - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/evidence/exported" - - "gopkg.in/yaml.v2" - - "github.com/tendermint/tendermint/crypto" - "github.com/tendermint/tendermint/crypto/tmhash" - tmbytes "github.com/tendermint/tendermint/libs/bytes" -) - -var ( - _ exported.Evidence = (*TestEquivocationEvidence)(nil) - - TestingCdc = codec.New() -) - -const ( - TestEvidenceRouteEquivocation = "TestEquivocationEvidence" - TestEvidenceTypeEquivocation = "equivocation" -) - -type ( - TestVote struct { - Height int64 - Round int64 - Timestamp time.Time - ValidatorAddress tmbytes.HexBytes - Signature []byte - } - - TestCanonicalVote struct { - Height int64 - Round int64 - Timestamp time.Time - ChainID string - } - - TestEquivocationEvidence struct { - Power int64 - TotalPower int64 - PubKey crypto.PubKey - VoteA TestVote - VoteB TestVote - } -) - -func init() { - RegisterCodec(TestingCdc) - codec.RegisterCrypto(TestingCdc) - TestingCdc.RegisterConcrete(TestEquivocationEvidence{}, "test/TestEquivocationEvidence", nil) -} - -func (e TestEquivocationEvidence) Route() string { return TestEvidenceRouteEquivocation } -func (e TestEquivocationEvidence) Type() string { return TestEvidenceTypeEquivocation } -func (e TestEquivocationEvidence) GetHeight() int64 { return e.VoteA.Height } -func (e TestEquivocationEvidence) GetValidatorPower() int64 { return e.Power } -func (e TestEquivocationEvidence) GetTotalPower() int64 { return e.TotalPower } - -func (e TestEquivocationEvidence) String() string { - bz, _ := yaml.Marshal(e) - return string(bz) -} - -func (e TestEquivocationEvidence) GetConsensusAddress() sdk.ConsAddress { - return sdk.ConsAddress(e.PubKey.Address()) -} - -func (e TestEquivocationEvidence) ValidateBasic() error { - if e.VoteA.Height != e.VoteB.Height || - e.VoteA.Round != e.VoteB.Round { - return fmt.Errorf("H/R/S does not match (got %v and %v)", e.VoteA, e.VoteB) - } - - if !bytes.Equal(e.VoteA.ValidatorAddress, e.VoteB.ValidatorAddress) { - return fmt.Errorf( - "validator addresses do not match (got %X and %X)", - e.VoteA.ValidatorAddress, - e.VoteB.ValidatorAddress, - ) - } - - return nil -} - -func (e TestEquivocationEvidence) Hash() tmbytes.HexBytes { - return tmhash.Sum(TestingCdc.MustMarshalBinaryBare(e)) -} - -func (v TestVote) SignBytes(chainID string) []byte { - scv := TestCanonicalVote{ - Height: v.Height, - Round: v.Round, - Timestamp: v.Timestamp, - ChainID: chainID, - } - bz, _ := TestingCdc.MarshalBinaryLengthPrefixed(scv) - return bz -} - -func TestEquivocationHandler(k interface{}) Handler { - return func(ctx sdk.Context, e exported.Evidence) error { - if err := e.ValidateBasic(); err != nil { - return err - } - - ee, ok := e.(TestEquivocationEvidence) - if !ok { - return fmt.Errorf("unexpected evidence type: %T", e) - } - if !ee.PubKey.VerifyBytes(ee.VoteA.SignBytes(ctx.ChainID()), ee.VoteA.Signature) { - return errors.New("failed to verify vote A signature") - } - if !ee.PubKey.VerifyBytes(ee.VoteB.SignBytes(ctx.ChainID()), ee.VoteB.Signature) { - return errors.New("failed to verify vote B signature") - } - - // TODO: Slashing! - - return nil - } -} diff --git a/x/evidence/internal/keeper/infraction.go b/x/evidence/keeper/infraction.go similarity index 98% rename from x/evidence/internal/keeper/infraction.go rename to x/evidence/keeper/infraction.go index fab16c833e74..17970863ba9e 100644 --- a/x/evidence/internal/keeper/infraction.go +++ b/x/evidence/keeper/infraction.go @@ -5,7 +5,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/evidence/internal/types" + "github.com/cosmos/cosmos-sdk/x/evidence/types" ) // HandleDoubleSign implements an equivocation evidence handler. Assuming the diff --git a/x/evidence/internal/keeper/infraction_test.go b/x/evidence/keeper/infraction_test.go similarity index 95% rename from x/evidence/internal/keeper/infraction_test.go rename to x/evidence/keeper/infraction_test.go index d0ae5d74239d..71177df01b9d 100644 --- a/x/evidence/internal/keeper/infraction_test.go +++ b/x/evidence/keeper/infraction_test.go @@ -4,7 +4,7 @@ import ( "time" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/evidence/internal/types" + "github.com/cosmos/cosmos-sdk/x/evidence/types" "github.com/cosmos/cosmos-sdk/x/staking" "github.com/tendermint/tendermint/crypto" @@ -51,7 +51,7 @@ func (suite *KeeperTestSuite) TestHandleDoubleSign() { Power: power, ConsensusAddress: sdk.ConsAddress(val.Address()), } - suite.keeper.HandleDoubleSign(ctx, evidence) + suite.app.EvidenceKeeper.HandleDoubleSign(ctx, evidence) // should be jailed and tombstoned suite.True(suite.app.StakingKeeper.Validator(ctx, operatorAddr).IsJailed()) @@ -62,7 +62,7 @@ func (suite *KeeperTestSuite) TestHandleDoubleSign() { suite.True(newTokens.LT(oldTokens)) // submit duplicate evidence - suite.keeper.HandleDoubleSign(ctx, evidence) + suite.app.EvidenceKeeper.HandleDoubleSign(ctx, evidence) // tokens should be the same (capped slash) suite.True(suite.app.StakingKeeper.Validator(ctx, operatorAddr).GetTokens().Equal(newTokens)) @@ -113,7 +113,7 @@ func (suite *KeeperTestSuite) TestHandleDoubleSign_TooOld() { ConsensusAddress: sdk.ConsAddress(val.Address()), } ctx = ctx.WithBlockTime(ctx.BlockTime().Add(suite.app.EvidenceKeeper.MaxEvidenceAge(ctx) + 1)) - suite.keeper.HandleDoubleSign(ctx, evidence) + suite.app.EvidenceKeeper.HandleDoubleSign(ctx, evidence) suite.False(suite.app.StakingKeeper.Validator(ctx, operatorAddr).IsJailed()) suite.False(suite.app.SlashingKeeper.IsTombstoned(ctx, sdk.ConsAddress(val.Address()))) diff --git a/x/evidence/internal/keeper/keeper.go b/x/evidence/keeper/keeper.go similarity index 82% rename from x/evidence/internal/keeper/keeper.go rename to x/evidence/keeper/keeper.go index ae6c66e623e7..93672ab0c7c4 100644 --- a/x/evidence/internal/keeper/keeper.go +++ b/x/evidence/keeper/keeper.go @@ -6,12 +6,11 @@ import ( tmbytes "github.com/tendermint/tendermint/libs/bytes" "github.com/tendermint/tendermint/libs/log" - "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/evidence/exported" - "github.com/cosmos/cosmos-sdk/x/evidence/internal/types" + "github.com/cosmos/cosmos-sdk/x/evidence/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" ) @@ -19,7 +18,7 @@ import ( // managing persistence, state transitions and query handling for the evidence // module. type Keeper struct { - cdc *codec.Codec + cdc types.Codec storeKey sdk.StoreKey paramSpace paramtypes.Subspace router types.Router @@ -28,7 +27,7 @@ type Keeper struct { } func NewKeeper( - cdc *codec.Codec, storeKey sdk.StoreKey, paramSpace paramtypes.Subspace, + cdc types.Codec, storeKey sdk.StoreKey, paramSpace paramtypes.Subspace, stakingKeeper types.StakingKeeper, slashingKeeper types.SlashingKeeper, ) *Keeper { @@ -110,13 +109,12 @@ func (k Keeper) SubmitEvidence(ctx sdk.Context, evidence exported.Evidence) erro // SetEvidence sets Evidence by hash in the module's KVStore. func (k Keeper) SetEvidence(ctx sdk.Context, evidence exported.Evidence) { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixEvidence) - bz := k.cdc.MustMarshalBinaryLengthPrefixed(evidence) - store.Set(evidence.Hash(), bz) + store.Set(evidence.Hash(), k.MustMarshalEvidence(evidence)) } // GetEvidence retrieves Evidence by hash if it exists. If no Evidence exists for // the given hash, (nil, false) is returned. -func (k Keeper) GetEvidence(ctx sdk.Context, hash tmbytes.HexBytes) (evidence exported.Evidence, found bool) { +func (k Keeper) GetEvidence(ctx sdk.Context, hash tmbytes.HexBytes) (exported.Evidence, bool) { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixEvidence) bz := store.Get(hash) @@ -124,8 +122,7 @@ func (k Keeper) GetEvidence(ctx sdk.Context, hash tmbytes.HexBytes) (evidence ex return nil, false } - k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &evidence) - return evidence, true + return k.MustUnmarshalEvidence(bz), true } // IterateEvidence provides an interator over all stored Evidence objects. For @@ -137,8 +134,7 @@ func (k Keeper) IterateEvidence(ctx sdk.Context, cb func(exported.Evidence) bool defer iterator.Close() for ; iterator.Valid(); iterator.Next() { - var evidence exported.Evidence - k.cdc.MustUnmarshalBinaryLengthPrefixed(iterator.Value(), &evidence) + evidence := k.MustUnmarshalEvidence(iterator.Value()) if cb(evidence) { break @@ -152,5 +148,28 @@ func (k Keeper) GetAllEvidence(ctx sdk.Context) (evidence []exported.Evidence) { evidence = append(evidence, e) return false }) + + return evidence +} + +// MustUnmarshalEvidence attempts to decode and return an Evidence object from +// raw encoded bytes. It panics on error. +func (k Keeper) MustUnmarshalEvidence(bz []byte) exported.Evidence { + evidence, err := k.cdc.UnmarshalEvidence(bz) + if err != nil { + panic(fmt.Errorf("failed to decode evidence: %w", err)) + } + return evidence } + +// MustMarshalEvidence attempts to encode an Evidence object and returns the +// raw encoded bytes. It panics on error. +func (k Keeper) MustMarshalEvidence(evidence exported.Evidence) []byte { + bz, err := k.cdc.MarshalEvidence(evidence) + if err != nil { + panic(fmt.Errorf("failed to encode evidence: %w", err)) + } + + return bz +} diff --git a/x/evidence/internal/keeper/keeper_test.go b/x/evidence/keeper/keeper_test.go similarity index 57% rename from x/evidence/internal/keeper/keeper_test.go rename to x/evidence/keeper/keeper_test.go index d6e35a4956a9..a28f66efead3 100644 --- a/x/evidence/internal/keeper/keeper_test.go +++ b/x/evidence/keeper/keeper_test.go @@ -2,15 +2,18 @@ package keeper_test import ( "encoding/hex" + "fmt" "testing" + "time" "github.com/cosmos/cosmos-sdk/simapp" + simappcodec "github.com/cosmos/cosmos-sdk/simapp/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/evidence" "github.com/cosmos/cosmos-sdk/x/evidence/exported" - "github.com/cosmos/cosmos-sdk/x/evidence/internal/keeper" - "github.com/cosmos/cosmos-sdk/x/evidence/internal/types" + "github.com/cosmos/cosmos-sdk/x/evidence/keeper" + "github.com/cosmos/cosmos-sdk/x/evidence/types" "github.com/cosmos/cosmos-sdk/x/supply" "github.com/stretchr/testify/suite" @@ -48,12 +51,29 @@ func newPubKey(pk string) (res crypto.PubKey) { return pubkey } +func testEquivocationHandler(k interface{}) types.Handler { + return func(ctx sdk.Context, e exported.Evidence) error { + if err := e.ValidateBasic(); err != nil { + return err + } + + ee, ok := e.(types.Equivocation) + if !ok { + return fmt.Errorf("unexpected evidence type: %T", e) + } + if ee.Height%2 == 0 { + return fmt.Errorf("unexpected even evidence height: %d", ee.Height) + } + + return nil + } +} + type KeeperTestSuite struct { suite.Suite ctx sdk.Context querier sdk.Querier - keeper keeper.Keeper app *simapp.SimApp } @@ -61,21 +81,19 @@ func (suite *KeeperTestSuite) SetupTest() { checkTx := false app := simapp.Setup(checkTx) - // get the app's codec and register custom testing types - cdc := app.Codec() - cdc.RegisterConcrete(types.TestEquivocationEvidence{}, "test/TestEquivocationEvidence", nil) - // recreate keeper in order to use custom testing types evidenceKeeper := evidence.NewKeeper( - cdc, app.GetKey(evidence.StoreKey), app.GetSubspace(evidence.ModuleName), app.StakingKeeper, app.SlashingKeeper, + simappcodec.NewAppCodec(app.Codec()), app.GetKey(evidence.StoreKey), + app.GetSubspace(evidence.ModuleName), app.StakingKeeper, app.SlashingKeeper, ) router := evidence.NewRouter() - router = router.AddRoute(types.TestEvidenceRouteEquivocation, types.TestEquivocationHandler(*evidenceKeeper)) + router = router.AddRoute(types.RouteEquivocation, testEquivocationHandler(*evidenceKeeper)) evidenceKeeper.SetRouter(router) + app.EvidenceKeeper = *evidenceKeeper + suite.ctx = app.BaseApp.NewContext(checkTx, abci.Header{Height: 1}) suite.querier = keeper.NewQuerier(*evidenceKeeper) - suite.keeper = *evidenceKeeper suite.app = app for i, addr := range valAddresses { @@ -89,25 +107,15 @@ func (suite *KeeperTestSuite) populateEvidence(ctx sdk.Context, numEvidence int) for i := 0; i < numEvidence; i++ { pk := ed25519.GenPrivKey() - sv := types.TestVote{ - ValidatorAddress: pk.PubKey().Address(), - Height: int64(i), - Round: 0, - } - sig, err := pk.Sign(sv.SignBytes(ctx.ChainID())) - suite.NoError(err) - sv.Signature = sig - - evidence[i] = types.TestEquivocationEvidence{ - Power: 100, - TotalPower: 100000, - PubKey: pk.PubKey(), - VoteA: sv, - VoteB: sv, + evidence[i] = types.Equivocation{ + Height: 11, + Power: 100, + Time: time.Now().UTC(), + ConsensusAddress: sdk.ConsAddress(pk.PubKey().Address().Bytes()), } - suite.Nil(suite.keeper.SubmitEvidence(ctx, evidence[i])) + suite.Nil(suite.app.EvidenceKeeper.SubmitEvidence(ctx, evidence[i])) } return evidence @@ -128,82 +136,53 @@ func (suite *KeeperTestSuite) populateValidators(ctx sdk.Context) { func (suite *KeeperTestSuite) TestSubmitValidEvidence() { ctx := suite.ctx.WithIsCheckTx(false) pk := ed25519.GenPrivKey() - sv := types.TestVote{ - ValidatorAddress: pk.PubKey().Address(), - Height: 11, - Round: 0, - } - sig, err := pk.Sign(sv.SignBytes(ctx.ChainID())) - suite.NoError(err) - sv.Signature = sig - - e := types.TestEquivocationEvidence{ - Power: 100, - TotalPower: 100000, - PubKey: pk.PubKey(), - VoteA: sv, - VoteB: sv, + e := types.Equivocation{ + Height: 1, + Power: 100, + Time: time.Now().UTC(), + ConsensusAddress: sdk.ConsAddress(pk.PubKey().Address().Bytes()), } - suite.Nil(suite.keeper.SubmitEvidence(ctx, e)) + suite.Nil(suite.app.EvidenceKeeper.SubmitEvidence(ctx, e)) - res, ok := suite.keeper.GetEvidence(ctx, e.Hash()) + res, ok := suite.app.EvidenceKeeper.GetEvidence(ctx, e.Hash()) suite.True(ok) - suite.Equal(e, res) + suite.Equal(&e, res) } func (suite *KeeperTestSuite) TestSubmitValidEvidence_Duplicate() { ctx := suite.ctx.WithIsCheckTx(false) pk := ed25519.GenPrivKey() - sv := types.TestVote{ - ValidatorAddress: pk.PubKey().Address(), - Height: 11, - Round: 0, - } - sig, err := pk.Sign(sv.SignBytes(ctx.ChainID())) - suite.NoError(err) - sv.Signature = sig - - e := types.TestEquivocationEvidence{ - Power: 100, - TotalPower: 100000, - PubKey: pk.PubKey(), - VoteA: sv, - VoteB: sv, + e := types.Equivocation{ + Height: 1, + Power: 100, + Time: time.Now().UTC(), + ConsensusAddress: sdk.ConsAddress(pk.PubKey().Address().Bytes()), } - suite.Nil(suite.keeper.SubmitEvidence(ctx, e)) - suite.Error(suite.keeper.SubmitEvidence(ctx, e)) + suite.Nil(suite.app.EvidenceKeeper.SubmitEvidence(ctx, e)) + suite.Error(suite.app.EvidenceKeeper.SubmitEvidence(ctx, e)) - res, ok := suite.keeper.GetEvidence(ctx, e.Hash()) + res, ok := suite.app.EvidenceKeeper.GetEvidence(ctx, e.Hash()) suite.True(ok) - suite.Equal(e, res) + suite.Equal(&e, res) } func (suite *KeeperTestSuite) TestSubmitInvalidEvidence() { ctx := suite.ctx.WithIsCheckTx(false) pk := ed25519.GenPrivKey() - e := types.TestEquivocationEvidence{ - Power: 100, - TotalPower: 100000, - PubKey: pk.PubKey(), - VoteA: types.TestVote{ - ValidatorAddress: pk.PubKey().Address(), - Height: 10, - Round: 0, - }, - VoteB: types.TestVote{ - ValidatorAddress: pk.PubKey().Address(), - Height: 11, - Round: 0, - }, + e := types.Equivocation{ + Height: 0, + Power: 100, + Time: time.Now().UTC(), + ConsensusAddress: sdk.ConsAddress(pk.PubKey().Address().Bytes()), } - suite.Error(suite.keeper.SubmitEvidence(ctx, e)) + suite.Error(suite.app.EvidenceKeeper.SubmitEvidence(ctx, e)) - res, ok := suite.keeper.GetEvidence(ctx, e.Hash()) + res, ok := suite.app.EvidenceKeeper.GetEvidence(ctx, e.Hash()) suite.False(ok) suite.Nil(res) } @@ -213,16 +192,16 @@ func (suite *KeeperTestSuite) TestIterateEvidence() { numEvidence := 100 suite.populateEvidence(ctx, numEvidence) - evidence := suite.keeper.GetAllEvidence(ctx) + evidence := suite.app.EvidenceKeeper.GetAllEvidence(ctx) suite.Len(evidence, numEvidence) } func (suite *KeeperTestSuite) TestGetEvidenceHandler() { - handler, err := suite.keeper.GetEvidenceHandler(types.TestEquivocationEvidence{}.Route()) + handler, err := suite.app.EvidenceKeeper.GetEvidenceHandler(types.Equivocation{}.Route()) suite.NoError(err) suite.NotNil(handler) - handler, err = suite.keeper.GetEvidenceHandler("invalidHandler") + handler, err = suite.app.EvidenceKeeper.GetEvidenceHandler("invalidHandler") suite.Error(err) suite.Nil(handler) } diff --git a/x/evidence/internal/keeper/params.go b/x/evidence/keeper/params.go similarity index 91% rename from x/evidence/internal/keeper/params.go rename to x/evidence/keeper/params.go index 8db4867781e7..b49512e2e553 100644 --- a/x/evidence/internal/keeper/params.go +++ b/x/evidence/keeper/params.go @@ -4,7 +4,7 @@ import ( "time" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/evidence/internal/types" + "github.com/cosmos/cosmos-sdk/x/evidence/types" ) // MaxEvidenceAge returns the maximum age for submitted evidence. diff --git a/x/evidence/keeper/params_test.go b/x/evidence/keeper/params_test.go new file mode 100644 index 000000000000..08db55e9b8ad --- /dev/null +++ b/x/evidence/keeper/params_test.go @@ -0,0 +1,11 @@ +package keeper_test + +import ( + "github.com/cosmos/cosmos-sdk/x/evidence/types" +) + +func (suite *KeeperTestSuite) TestParams() { + ctx := suite.ctx.WithIsCheckTx(false) + suite.Equal(types.DefaultParams(), suite.app.EvidenceKeeper.GetParams(ctx)) + suite.Equal(types.DefaultMaxEvidenceAge, suite.app.EvidenceKeeper.MaxEvidenceAge(ctx)) +} diff --git a/x/evidence/internal/keeper/querier.go b/x/evidence/keeper/querier.go similarity index 97% rename from x/evidence/internal/keeper/querier.go rename to x/evidence/keeper/querier.go index cbb616677e8f..064ad2cb4aae 100644 --- a/x/evidence/internal/keeper/querier.go +++ b/x/evidence/keeper/querier.go @@ -8,7 +8,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/evidence/exported" - "github.com/cosmos/cosmos-sdk/x/evidence/internal/types" + "github.com/cosmos/cosmos-sdk/x/evidence/types" abci "github.com/tendermint/tendermint/abci/types" ) diff --git a/x/evidence/internal/keeper/querier_test.go b/x/evidence/keeper/querier_test.go similarity index 73% rename from x/evidence/internal/keeper/querier_test.go rename to x/evidence/keeper/querier_test.go index 68af96640ab4..069f41c6cef6 100644 --- a/x/evidence/internal/keeper/querier_test.go +++ b/x/evidence/keeper/querier_test.go @@ -3,8 +3,9 @@ package keeper_test import ( "strings" + simappcodec "github.com/cosmos/cosmos-sdk/simapp/codec" "github.com/cosmos/cosmos-sdk/x/evidence/exported" - "github.com/cosmos/cosmos-sdk/x/evidence/internal/types" + "github.com/cosmos/cosmos-sdk/x/evidence/types" abci "github.com/tendermint/tendermint/abci/types" ) @@ -16,11 +17,12 @@ const ( func (suite *KeeperTestSuite) TestQueryEvidence_Existing() { ctx := suite.ctx.WithIsCheckTx(false) numEvidence := 100 + cdc := simappcodec.NewAppCodec(suite.app.Codec()) evidence := suite.populateEvidence(ctx, numEvidence) query := abci.RequestQuery{ Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryEvidence}, "/"), - Data: types.TestingCdc.MustMarshalJSON(types.NewQueryEvidenceParams(evidence[0].Hash().String())), + Data: cdc.MustMarshalJSON(types.NewQueryEvidenceParams(evidence[0].Hash().String())), } bz, err := suite.querier(ctx, []string{types.QueryEvidence}, query) @@ -28,18 +30,19 @@ func (suite *KeeperTestSuite) TestQueryEvidence_Existing() { suite.NotNil(bz) var e exported.Evidence - suite.Nil(types.TestingCdc.UnmarshalJSON(bz, &e)) + suite.Nil(cdc.UnmarshalJSON(bz, &e)) suite.Equal(evidence[0], e) } func (suite *KeeperTestSuite) TestQueryEvidence_NonExisting() { ctx := suite.ctx.WithIsCheckTx(false) + cdc := simappcodec.NewAppCodec(suite.app.Codec()) numEvidence := 100 suite.populateEvidence(ctx, numEvidence) query := abci.RequestQuery{ Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryEvidence}, "/"), - Data: types.TestingCdc.MustMarshalJSON(types.NewQueryEvidenceParams("0000000000000000000000000000000000000000000000000000000000000000")), + Data: cdc.MustMarshalJSON(types.NewQueryEvidenceParams("0000000000000000000000000000000000000000000000000000000000000000")), } bz, err := suite.querier(ctx, []string{types.QueryEvidence}, query) @@ -49,12 +52,13 @@ func (suite *KeeperTestSuite) TestQueryEvidence_NonExisting() { func (suite *KeeperTestSuite) TestQueryAllEvidence() { ctx := suite.ctx.WithIsCheckTx(false) + cdc := simappcodec.NewAppCodec(suite.app.Codec()) numEvidence := 100 suite.populateEvidence(ctx, numEvidence) query := abci.RequestQuery{ Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryAllEvidence}, "/"), - Data: types.TestingCdc.MustMarshalJSON(types.NewQueryAllEvidenceParams(1, numEvidence)), + Data: cdc.MustMarshalJSON(types.NewQueryAllEvidenceParams(1, numEvidence)), } bz, err := suite.querier(ctx, []string{types.QueryAllEvidence}, query) @@ -62,18 +66,19 @@ func (suite *KeeperTestSuite) TestQueryAllEvidence() { suite.NotNil(bz) var e []exported.Evidence - suite.Nil(types.TestingCdc.UnmarshalJSON(bz, &e)) + suite.Nil(cdc.UnmarshalJSON(bz, &e)) suite.Len(e, numEvidence) } func (suite *KeeperTestSuite) TestQueryAllEvidence_InvalidPagination() { ctx := suite.ctx.WithIsCheckTx(false) + cdc := simappcodec.NewAppCodec(suite.app.Codec()) numEvidence := 100 suite.populateEvidence(ctx, numEvidence) query := abci.RequestQuery{ Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryAllEvidence}, "/"), - Data: types.TestingCdc.MustMarshalJSON(types.NewQueryAllEvidenceParams(0, numEvidence)), + Data: cdc.MustMarshalJSON(types.NewQueryAllEvidenceParams(0, numEvidence)), } bz, err := suite.querier(ctx, []string{types.QueryAllEvidence}, query) @@ -81,7 +86,7 @@ func (suite *KeeperTestSuite) TestQueryAllEvidence_InvalidPagination() { suite.NotNil(bz) var e []exported.Evidence - suite.Nil(types.TestingCdc.UnmarshalJSON(bz, &e)) + suite.Nil(cdc.UnmarshalJSON(bz, &e)) suite.Len(e, 0) } diff --git a/x/evidence/types/codec.go b/x/evidence/types/codec.go new file mode 100644 index 000000000000..6cfd762c38ab --- /dev/null +++ b/x/evidence/types/codec.go @@ -0,0 +1,42 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/x/evidence/exported" +) + +// EvidenceCodec defines the interface required to serialize evidence +type Codec interface { + codec.Marshaler + + MarshalEvidence(exported.Evidence) ([]byte, error) + UnmarshalEvidence([]byte) (exported.Evidence, error) + MarshalEvidenceJSON(exported.Evidence) ([]byte, error) + UnmarshalEvidenceJSON([]byte) (exported.Evidence, error) +} + +// RegisterCodec registers all the necessary types and interfaces for the +// evidence module. +func RegisterCodec(cdc *codec.Codec) { + cdc.RegisterInterface((*exported.Evidence)(nil), nil) + cdc.RegisterConcrete(MsgSubmitEvidenceBase{}, "cosmos-sdk/MsgSubmitEvidenceBase", nil) + cdc.RegisterConcrete(Equivocation{}, "cosmos-sdk/Equivocation", nil) +} + +var ( + amino = codec.New() + + // ModuleCdc references the global x/evidence module codec. Note, the codec should + // ONLY be used in certain instances of tests and for JSON encoding as Amino is + // still used for that purpose. + // + // The actual codec used for serialization should be provided to x/evidence and + // defined at the application level. + ModuleCdc = codec.NewHybridCodec(amino) +) + +func init() { + RegisterCodec(amino) + codec.RegisterCrypto(amino) + amino.Seal() +} diff --git a/x/evidence/types/codec_test.go b/x/evidence/types/codec_test.go new file mode 100644 index 000000000000..af2656d38c8d --- /dev/null +++ b/x/evidence/types/codec_test.go @@ -0,0 +1,33 @@ +package types_test + +import ( + "testing" + "time" + + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/crypto/ed25519" + + "github.com/cosmos/cosmos-sdk/simapp" + simappcodec "github.com/cosmos/cosmos-sdk/simapp/codec" + "github.com/cosmos/cosmos-sdk/x/evidence/exported" + "github.com/cosmos/cosmos-sdk/x/evidence/types" +) + +func TestCodec(t *testing.T) { + app := simapp.Setup(false) + appCodec := simappcodec.NewAppCodec(app.Codec()) + pk := ed25519.GenPrivKey() + + var e exported.Evidence = &types.Equivocation{ + Height: 10, + Time: time.Now().UTC(), + Power: 100000, + ConsensusAddress: pk.PubKey().Address().Bytes(), + } + bz, err := appCodec.MarshalEvidence(e) + require.NoError(t, err) + + other, err := appCodec.UnmarshalEvidence(bz) + require.NoError(t, err) + require.Equal(t, e, other) +} diff --git a/x/evidence/internal/types/errors.go b/x/evidence/types/errors.go similarity index 100% rename from x/evidence/internal/types/errors.go rename to x/evidence/types/errors.go diff --git a/x/evidence/internal/types/events.go b/x/evidence/types/events.go similarity index 100% rename from x/evidence/internal/types/events.go rename to x/evidence/types/events.go diff --git a/x/evidence/internal/types/evidence.go b/x/evidence/types/evidence.go similarity index 85% rename from x/evidence/internal/types/evidence.go rename to x/evidence/types/evidence.go index 4306acbe0de7..d62023530a6a 100644 --- a/x/evidence/internal/types/evidence.go +++ b/x/evidence/types/evidence.go @@ -21,15 +21,6 @@ const ( var _ exported.Evidence = (*Equivocation)(nil) -// Equivocation implements the Evidence interface and defines evidence of double -// signing misbehavior. -type Equivocation struct { - Height int64 `json:"height" yaml:"height"` - Time time.Time `json:"time" yaml:"time"` - Power int64 `json:"power" yaml:"power"` - ConsensusAddress sdk.ConsAddress `json:"consensus_address" yaml:"consensus_address"` -} - // Route returns the Evidence Handler route for an Equivocation type. func (e Equivocation) Route() string { return RouteEquivocation } @@ -43,7 +34,7 @@ func (e Equivocation) String() string { // Hash returns the hash of an Equivocation object. func (e Equivocation) Hash() tmbytes.HexBytes { - return tmhash.Sum(ModuleCdc.MustMarshalBinaryBare(e)) + return tmhash.Sum(ModuleCdc.MustMarshalBinaryBare(&e)) } // ValidateBasic performs basic stateless validation checks on an Equivocation object. diff --git a/x/evidence/internal/types/evidence_test.go b/x/evidence/types/evidence_test.go similarity index 91% rename from x/evidence/internal/types/evidence_test.go rename to x/evidence/types/evidence_test.go index 8871f553eb7d..623af3a7cbdd 100644 --- a/x/evidence/internal/types/evidence_test.go +++ b/x/evidence/types/evidence_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/require" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/evidence/internal/types" + "github.com/cosmos/cosmos-sdk/x/evidence/types" ) func TestEquivocation_Valid(t *testing.T) { @@ -26,7 +26,7 @@ func TestEquivocation_Valid(t *testing.T) { require.Equal(t, e.GetHeight(), e.Height) require.Equal(t, e.Type(), types.TypeEquivocation) require.Equal(t, e.Route(), types.RouteEquivocation) - require.Equal(t, e.Hash().String(), "808DA679674C9C0599965D02EBC5D4DCFD5E700D03035BBCD2DECCBBF44386F7") + require.Equal(t, e.Hash().String(), "16337536D55FB6DB93360AED8FDB9B615BFACAF0440C28C46B89F167D042154A") require.Equal(t, e.String(), "height: 100\ntime: 2006-01-02T15:04:05Z\npower: 1000000\nconsensus_address: cosmosvalcons1vehk7pqt5u4\n") require.NoError(t, e.ValidateBasic()) } diff --git a/x/evidence/internal/types/expected_keepers.go b/x/evidence/types/expected_keepers.go similarity index 100% rename from x/evidence/internal/types/expected_keepers.go rename to x/evidence/types/expected_keepers.go diff --git a/x/evidence/internal/types/genesis.go b/x/evidence/types/genesis.go similarity index 100% rename from x/evidence/internal/types/genesis.go rename to x/evidence/types/genesis.go diff --git a/x/evidence/internal/types/genesis_test.go b/x/evidence/types/genesis_test.go similarity index 51% rename from x/evidence/internal/types/genesis_test.go rename to x/evidence/types/genesis_test.go index f7ef8027b25c..110838f86c98 100644 --- a/x/evidence/internal/types/genesis_test.go +++ b/x/evidence/types/genesis_test.go @@ -2,12 +2,13 @@ package types_test import ( "testing" + "time" "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/crypto/ed25519" "github.com/cosmos/cosmos-sdk/x/evidence/exported" - "github.com/cosmos/cosmos-sdk/x/evidence/internal/types" + "github.com/cosmos/cosmos-sdk/x/evidence/types" ) func TestDefaultGenesisState(t *testing.T) { @@ -21,21 +22,11 @@ func TestGenesisStateValidate_Valid(t *testing.T) { evidence := make([]exported.Evidence, 100) for i := 0; i < 100; i++ { - sv := types.TestVote{ - ValidatorAddress: pk.PubKey().Address(), - Height: int64(i), - Round: 0, - } - sig, err := pk.Sign(sv.SignBytes("test-chain")) - require.NoError(t, err) - sv.Signature = sig - - evidence[i] = types.TestEquivocationEvidence{ - Power: 100, - TotalPower: 100000, - PubKey: pk.PubKey(), - VoteA: sv, - VoteB: sv, + evidence[i] = types.Equivocation{ + Height: int64(i) + 1, + Power: 100, + Time: time.Now().UTC(), + ConsensusAddress: pk.PubKey().Address().Bytes(), } } @@ -48,21 +39,11 @@ func TestGenesisStateValidate_Invalid(t *testing.T) { evidence := make([]exported.Evidence, 100) for i := 0; i < 100; i++ { - sv := types.TestVote{ - ValidatorAddress: pk.PubKey().Address(), + evidence[i] = types.Equivocation{ Height: int64(i), - Round: 0, - } - sig, err := pk.Sign(sv.SignBytes("test-chain")) - require.NoError(t, err) - sv.Signature = sig - - evidence[i] = types.TestEquivocationEvidence{ - Power: 100, - TotalPower: 100000, - PubKey: pk.PubKey(), - VoteA: sv, - VoteB: types.TestVote{Height: 10, Round: 1}, + Power: 100, + Time: time.Now().UTC(), + ConsensusAddress: pk.PubKey().Address().Bytes(), } } diff --git a/x/evidence/internal/types/keys.go b/x/evidence/types/keys.go similarity index 100% rename from x/evidence/internal/types/keys.go rename to x/evidence/types/keys.go diff --git a/x/evidence/types/msgs.go b/x/evidence/types/msgs.go new file mode 100644 index 000000000000..eb0367b28b61 --- /dev/null +++ b/x/evidence/types/msgs.go @@ -0,0 +1,48 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +// Message types for the evidence module +const ( + TypeMsgSubmitEvidence = "submit_evidence" +) + +var ( + _ sdk.Msg = MsgSubmitEvidenceBase{} +) + +// NewMsgSubmitEvidenceBase returns a new MsgSubmitEvidenceBase with a signer/submitter. +// Note, the MsgSubmitEvidenceBase is not to be used as an actual message, but +// rather to be extended with Evidence. +func NewMsgSubmitEvidenceBase(s sdk.AccAddress) MsgSubmitEvidenceBase { + return MsgSubmitEvidenceBase{Submitter: s} +} + +// Route returns the MsgSubmitEvidenceBase's route. +func (m MsgSubmitEvidenceBase) Route() string { return RouterKey } + +// Type returns the MsgSubmitEvidenceBase's type. +func (m MsgSubmitEvidenceBase) Type() string { return TypeMsgSubmitEvidence } + +// ValidateBasic performs basic (non-state-dependant) validation on a MsgSubmitEvidenceBase. +func (m MsgSubmitEvidenceBase) ValidateBasic() error { + if m.Submitter.Empty() { + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, m.Submitter.String()) + } + + return nil +} + +// GetSignBytes returns the raw bytes a signer is expected to sign when submitting +// a MsgSubmitEvidenceBase message. +func (m MsgSubmitEvidenceBase) GetSignBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(m)) +} + +// GetSigners returns the single expected signer for a MsgSubmitEvidenceBase. +func (m MsgSubmitEvidenceBase) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{m.Submitter} +} diff --git a/x/evidence/types/msgs_test.go b/x/evidence/types/msgs_test.go new file mode 100644 index 000000000000..304f49efbfa2 --- /dev/null +++ b/x/evidence/types/msgs_test.go @@ -0,0 +1,60 @@ +package types_test + +import ( + "testing" + "time" + + simappcodec "github.com/cosmos/cosmos-sdk/simapp/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/evidence/types" + + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/crypto/ed25519" +) + +func TestMsgSubmitEvidence(t *testing.T) { + pk := ed25519.GenPrivKey() + submitter := sdk.AccAddress("test") + + testCases := []struct { + msg sdk.Msg + submitter sdk.AccAddress + expectErr bool + }{ + { + types.NewMsgSubmitEvidenceBase(submitter), + submitter, + false, + }, + { + simappcodec.NewMsgSubmitEvidence(&types.Equivocation{ + Height: 0, + Power: 100, + Time: time.Now().UTC(), + ConsensusAddress: pk.PubKey().Address().Bytes(), + }, submitter), + submitter, + true, + }, + { + simappcodec.NewMsgSubmitEvidence(&types.Equivocation{ + Height: 10, + Power: 100, + Time: time.Now().UTC(), + ConsensusAddress: pk.PubKey().Address().Bytes(), + }, submitter), + submitter, + false, + }, + } + + for i, tc := range testCases { + require.Equal(t, tc.msg.Route(), types.RouterKey, "unexpected result for tc #%d", i) + require.Equal(t, tc.msg.Type(), types.TypeMsgSubmitEvidence, "unexpected result for tc #%d", i) + require.Equal(t, tc.expectErr, tc.msg.ValidateBasic() != nil, "unexpected result for tc #%d", i) + + if !tc.expectErr { + require.Equal(t, tc.msg.GetSigners(), []sdk.AccAddress{tc.submitter}, "unexpected result for tc #%d", i) + } + } +} diff --git a/x/evidence/internal/types/params.go b/x/evidence/types/params.go similarity index 88% rename from x/evidence/internal/types/params.go rename to x/evidence/types/params.go index 73f19ea0a804..1f4bab1f419e 100644 --- a/x/evidence/internal/types/params.go +++ b/x/evidence/types/params.go @@ -26,11 +26,6 @@ var ( DoubleSignJailEndTime = time.Unix(253402300799, 0) ) -// Params defines the total set of parameters for the evidence module -type Params struct { - MaxEvidenceAge time.Duration `json:"max_evidence_age" yaml:"max_evidence_age"` -} - // ParamKeyTable returns the parameter key table. func ParamKeyTable() paramtypes.KeyTable { return paramtypes.NewKeyTable().RegisterParamSet(&Params{}) diff --git a/x/evidence/internal/types/querier.go b/x/evidence/types/querier.go similarity index 100% rename from x/evidence/internal/types/querier.go rename to x/evidence/types/querier.go diff --git a/x/evidence/internal/types/router.go b/x/evidence/types/router.go similarity index 100% rename from x/evidence/internal/types/router.go rename to x/evidence/types/router.go diff --git a/x/evidence/internal/types/router_test.go b/x/evidence/types/router_test.go similarity index 92% rename from x/evidence/internal/types/router_test.go rename to x/evidence/types/router_test.go index b8cb42d2d488..01e942e9ea52 100644 --- a/x/evidence/internal/types/router_test.go +++ b/x/evidence/types/router_test.go @@ -7,7 +7,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/evidence/exported" - "github.com/cosmos/cosmos-sdk/x/evidence/internal/types" + "github.com/cosmos/cosmos-sdk/x/evidence/types" ) func testHandler(sdk.Context, exported.Evidence) error { return nil } diff --git a/x/evidence/types/types.pb.go b/x/evidence/types/types.pb.go new file mode 100644 index 000000000000..cf70cfe6ab77 --- /dev/null +++ b/x/evidence/types/types.pb.go @@ -0,0 +1,876 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: x/evidence/types/types.proto + +package types + +import ( + bytes "bytes" + fmt "fmt" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" + _ "github.com/golang/protobuf/ptypes/duration" + _ "github.com/golang/protobuf/ptypes/timestamp" + io "io" + math "math" + math_bits "math/bits" + time "time" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf +var _ = time.Kitchen + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// MsgSubmitEvidenceBase defines an sdk.Msg type that supports submitting arbitrary +// Evidence. +// +// Note, this message type provides the basis for which a true MsgSubmitEvidence +// can be constructed. Since the evidence submitted in the message can be arbitrary, +// assuming it fulfills the Evidence interface, it must be defined at the +// application-level and extend MsgSubmitEvidenceBase. +type MsgSubmitEvidenceBase struct { + Submitter github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,1,opt,name=submitter,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"submitter,omitempty"` +} + +func (m *MsgSubmitEvidenceBase) Reset() { *m = MsgSubmitEvidenceBase{} } +func (m *MsgSubmitEvidenceBase) String() string { return proto.CompactTextString(m) } +func (*MsgSubmitEvidenceBase) ProtoMessage() {} +func (*MsgSubmitEvidenceBase) Descriptor() ([]byte, []int) { + return fileDescriptor_72113e6a7b2536ae, []int{0} +} +func (m *MsgSubmitEvidenceBase) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgSubmitEvidenceBase) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgSubmitEvidenceBase.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 *MsgSubmitEvidenceBase) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgSubmitEvidenceBase.Merge(m, src) +} +func (m *MsgSubmitEvidenceBase) XXX_Size() int { + return m.Size() +} +func (m *MsgSubmitEvidenceBase) XXX_DiscardUnknown() { + xxx_messageInfo_MsgSubmitEvidenceBase.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgSubmitEvidenceBase proto.InternalMessageInfo + +func (m *MsgSubmitEvidenceBase) GetSubmitter() github_com_cosmos_cosmos_sdk_types.AccAddress { + if m != nil { + return m.Submitter + } + return nil +} + +// Equivocation implements the Evidence interface and defines evidence of double +// signing misbehavior. +type Equivocation struct { + Height int64 `protobuf:"varint,1,opt,name=height,proto3" json:"height,omitempty"` + Time time.Time `protobuf:"bytes,2,opt,name=time,proto3,stdtime" json:"time"` + Power int64 `protobuf:"varint,3,opt,name=power,proto3" json:"power,omitempty"` + ConsensusAddress github_com_cosmos_cosmos_sdk_types.ConsAddress `protobuf:"bytes,4,opt,name=consensus_address,json=consensusAddress,proto3,casttype=github.com/cosmos/cosmos-sdk/types.ConsAddress" json:"consensus_address,omitempty" yaml:"consensus_address"` +} + +func (m *Equivocation) Reset() { *m = Equivocation{} } +func (*Equivocation) ProtoMessage() {} +func (*Equivocation) Descriptor() ([]byte, []int) { + return fileDescriptor_72113e6a7b2536ae, []int{1} +} +func (m *Equivocation) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Equivocation) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Equivocation.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 *Equivocation) XXX_Merge(src proto.Message) { + xxx_messageInfo_Equivocation.Merge(m, src) +} +func (m *Equivocation) XXX_Size() int { + return m.Size() +} +func (m *Equivocation) XXX_DiscardUnknown() { + xxx_messageInfo_Equivocation.DiscardUnknown(m) +} + +var xxx_messageInfo_Equivocation proto.InternalMessageInfo + +// Params defines the total set of parameters for the evidence module +type Params struct { + MaxEvidenceAge time.Duration `protobuf:"bytes,1,opt,name=max_evidence_age,json=maxEvidenceAge,proto3,stdduration" json:"max_evidence_age" yaml:"max_evidence_age"` +} + +func (m *Params) Reset() { *m = Params{} } +func (*Params) ProtoMessage() {} +func (*Params) Descriptor() ([]byte, []int) { + return fileDescriptor_72113e6a7b2536ae, []int{2} +} +func (m *Params) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Params) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Params.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 *Params) XXX_Merge(src proto.Message) { + xxx_messageInfo_Params.Merge(m, src) +} +func (m *Params) XXX_Size() int { + return m.Size() +} +func (m *Params) XXX_DiscardUnknown() { + xxx_messageInfo_Params.DiscardUnknown(m) +} + +var xxx_messageInfo_Params proto.InternalMessageInfo + +func (m *Params) GetMaxEvidenceAge() time.Duration { + if m != nil { + return m.MaxEvidenceAge + } + return 0 +} + +func init() { + proto.RegisterType((*MsgSubmitEvidenceBase)(nil), "cosmos_sdk.x.evidence.v1.MsgSubmitEvidenceBase") + proto.RegisterType((*Equivocation)(nil), "cosmos_sdk.x.evidence.v1.Equivocation") + proto.RegisterType((*Params)(nil), "cosmos_sdk.x.evidence.v1.Params") +} + +func init() { proto.RegisterFile("x/evidence/types/types.proto", fileDescriptor_72113e6a7b2536ae) } + +var fileDescriptor_72113e6a7b2536ae = []byte{ + // 455 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0x3d, 0x6f, 0xd4, 0x30, + 0x1c, 0xc6, 0x63, 0x7a, 0x9c, 0x8a, 0x5b, 0xa1, 0x12, 0xf1, 0x12, 0x4e, 0x28, 0xae, 0x82, 0x84, + 0xba, 0xd4, 0x51, 0xcb, 0x82, 0x6e, 0xbb, 0x40, 0x27, 0xc4, 0x8b, 0x0e, 0x26, 0x96, 0xc8, 0x97, + 0x18, 0x27, 0x6a, 0x1d, 0x07, 0xdb, 0x39, 0x72, 0xe2, 0x0b, 0x30, 0x76, 0xec, 0xd8, 0x91, 0x8f, + 0xd2, 0xb1, 0x23, 0x53, 0x40, 0x77, 0xdf, 0xa0, 0x63, 0x25, 0x24, 0x74, 0x76, 0x42, 0xa5, 0xab, + 0x84, 0xba, 0x24, 0xb1, 0xf3, 0xe4, 0xc9, 0xf3, 0xfb, 0x3f, 0x86, 0x4f, 0xea, 0x90, 0x4e, 0xf3, + 0x94, 0x16, 0x09, 0x0d, 0xf5, 0xac, 0xa4, 0xca, 0x5e, 0x71, 0x29, 0x85, 0x16, 0xae, 0x97, 0x08, + 0xc5, 0x85, 0x8a, 0x55, 0x7a, 0x88, 0x6b, 0xdc, 0x09, 0xf1, 0x74, 0x6f, 0xf0, 0x4c, 0x67, 0xb9, + 0x4c, 0xe3, 0x92, 0x48, 0x3d, 0x0b, 0x8d, 0x38, 0x64, 0x82, 0x89, 0xab, 0x27, 0xeb, 0x30, 0x40, + 0x4c, 0x08, 0x76, 0x44, 0xad, 0x64, 0x52, 0x7d, 0x0e, 0x75, 0xce, 0xa9, 0xd2, 0x84, 0x97, 0xad, + 0xc0, 0x5f, 0x15, 0xa4, 0x95, 0x24, 0x3a, 0x17, 0x85, 0x7d, 0x1f, 0x64, 0xf0, 0xc1, 0x1b, 0xc5, + 0x3e, 0x54, 0x13, 0x9e, 0xeb, 0x83, 0x36, 0x40, 0x44, 0x14, 0x75, 0xdf, 0xc1, 0x3b, 0xca, 0xec, + 0x6a, 0x2a, 0x3d, 0xb0, 0x0d, 0x76, 0x36, 0xa3, 0xbd, 0xcb, 0x06, 0xed, 0xb2, 0x5c, 0x67, 0xd5, + 0x04, 0x27, 0x82, 0x87, 0x36, 0x7d, 0x7b, 0xdb, 0x55, 0xe9, 0x61, 0x0b, 0x37, 0x4a, 0x92, 0x51, + 0x9a, 0x4a, 0xaa, 0xd4, 0xf8, 0xca, 0x23, 0xf8, 0x03, 0xe0, 0xe6, 0xc1, 0x97, 0x2a, 0x9f, 0x8a, + 0xc4, 0x04, 0x70, 0x1f, 0xc2, 0x7e, 0x46, 0x73, 0x96, 0x69, 0x63, 0xbf, 0x36, 0x6e, 0x57, 0xee, + 0x0b, 0xd8, 0x5b, 0x52, 0x78, 0xb7, 0xb6, 0xc1, 0xce, 0xc6, 0xfe, 0x00, 0x5b, 0x02, 0xdc, 0x11, + 0xe0, 0x8f, 0x1d, 0x62, 0xb4, 0x7e, 0xd6, 0x20, 0xe7, 0xf8, 0x17, 0x02, 0x63, 0xf3, 0x85, 0x7b, + 0x1f, 0xde, 0x2e, 0xc5, 0x57, 0x2a, 0xbd, 0x35, 0x63, 0x68, 0x17, 0xee, 0x37, 0x78, 0x2f, 0x11, + 0x85, 0xa2, 0x85, 0xaa, 0x54, 0x4c, 0x6c, 0x30, 0xaf, 0x67, 0x88, 0xde, 0x5e, 0x34, 0xc8, 0x9b, + 0x11, 0x7e, 0x34, 0x0c, 0xae, 0x49, 0x82, 0xcb, 0x06, 0xe1, 0x1b, 0xd0, 0xbe, 0x14, 0x85, 0xea, + 0x70, 0xb7, 0xfe, 0xb9, 0xb4, 0x3b, 0xc3, 0xf5, 0xef, 0xa7, 0xc8, 0x39, 0x39, 0x45, 0x4e, 0x50, + 0xc3, 0xfe, 0x7b, 0x22, 0x09, 0x57, 0x6e, 0x06, 0xb7, 0x38, 0xa9, 0xe3, 0xae, 0xef, 0x98, 0x30, + 0x6a, 0x46, 0xb0, 0xb1, 0xff, 0xf8, 0x1a, 0xec, 0xab, 0xb6, 0xae, 0xe8, 0xe9, 0x92, 0xf5, 0xa2, + 0x41, 0x8f, 0x6c, 0xdc, 0x55, 0x83, 0xe0, 0x64, 0x39, 0x86, 0xbb, 0x9c, 0xd4, 0x5d, 0x8b, 0x23, + 0x46, 0x87, 0xbd, 0xe5, 0x9f, 0xa3, 0xd7, 0x3f, 0xe6, 0x3e, 0x38, 0x9b, 0xfb, 0xe0, 0x7c, 0xee, + 0x83, 0xdf, 0x73, 0x1f, 0x1c, 0x2f, 0x7c, 0xe7, 0x7c, 0xe1, 0x3b, 0x3f, 0x17, 0xbe, 0xf3, 0xe9, + 0xff, 0x8d, 0xae, 0x9e, 0xdf, 0x49, 0xdf, 0x44, 0x7b, 0xfe, 0x37, 0x00, 0x00, 0xff, 0xff, 0x35, + 0xfb, 0xe6, 0x44, 0xda, 0x02, 0x00, 0x00, +} + +func (this *MsgSubmitEvidenceBase) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*MsgSubmitEvidenceBase) + if !ok { + that2, ok := that.(MsgSubmitEvidenceBase) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !bytes.Equal(this.Submitter, that1.Submitter) { + return false + } + return true +} +func (this *Equivocation) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*Equivocation) + if !ok { + that2, ok := that.(Equivocation) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Height != that1.Height { + return false + } + if !this.Time.Equal(that1.Time) { + return false + } + if this.Power != that1.Power { + return false + } + if !bytes.Equal(this.ConsensusAddress, that1.ConsensusAddress) { + return false + } + return true +} +func (this *Params) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*Params) + if !ok { + that2, ok := that.(Params) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.MaxEvidenceAge != that1.MaxEvidenceAge { + return false + } + return true +} +func (m *MsgSubmitEvidenceBase) 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 *MsgSubmitEvidenceBase) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgSubmitEvidenceBase) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Submitter) > 0 { + i -= len(m.Submitter) + copy(dAtA[i:], m.Submitter) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Submitter))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *Equivocation) 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 *Equivocation) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Equivocation) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ConsensusAddress) > 0 { + i -= len(m.ConsensusAddress) + copy(dAtA[i:], m.ConsensusAddress) + i = encodeVarintTypes(dAtA, i, uint64(len(m.ConsensusAddress))) + i-- + dAtA[i] = 0x22 + } + if m.Power != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.Power)) + 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 + } + i -= n1 + i = encodeVarintTypes(dAtA, i, uint64(n1)) + i-- + dAtA[i] = 0x12 + if m.Height != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.Height)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *Params) 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 *Params) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + n2, err2 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.MaxEvidenceAge, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.MaxEvidenceAge):]) + if err2 != nil { + return 0, err2 + } + i -= n2 + i = encodeVarintTypes(dAtA, i, uint64(n2)) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func encodeVarintTypes(dAtA []byte, offset int, v uint64) int { + offset -= sovTypes(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgSubmitEvidenceBase) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Submitter) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + +func (m *Equivocation) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Height != 0 { + n += 1 + sovTypes(uint64(m.Height)) + } + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.Time) + n += 1 + l + sovTypes(uint64(l)) + if m.Power != 0 { + n += 1 + sovTypes(uint64(m.Power)) + } + l = len(m.ConsensusAddress) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + +func (m *Params) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = github_com_gogo_protobuf_types.SizeOfStdDuration(m.MaxEvidenceAge) + n += 1 + l + sovTypes(uint64(l)) + return n +} + +func sovTypes(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTypes(x uint64) (n int) { + return sovTypes(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *MsgSubmitEvidenceBase) 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 ErrIntOverflowTypes + } + 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: MsgSubmitEvidenceBase: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSubmitEvidenceBase: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Submitter", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Submitter = append(m.Submitter[:0], dAtA[iNdEx:postIndex]...) + if m.Submitter == nil { + m.Submitter = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Equivocation) 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 ErrIntOverflowTypes + } + 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: Equivocation: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Equivocation: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Height", wireType) + } + m.Height = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Height |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Time", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.Time, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Power", wireType) + } + m.Power = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Power |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConsensusAddress", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ConsensusAddress = append(m.ConsensusAddress[:0], dAtA[iNdEx:postIndex]...) + if m.ConsensusAddress == nil { + m.ConsensusAddress = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Params) 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 ErrIntOverflowTypes + } + 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: Params: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxEvidenceAge", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_gogo_protobuf_types.StdDurationUnmarshal(&m.MaxEvidenceAge, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTypes(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthTypes + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTypes + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTypes + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTypes = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTypes = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTypes = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/evidence/types/types.proto b/x/evidence/types/types.proto new file mode 100644 index 000000000000..5000686ae626 --- /dev/null +++ b/x/evidence/types/types.proto @@ -0,0 +1,46 @@ +syntax = "proto3"; +package cosmos_sdk.x.evidence.v1; + +option go_package = "github.com/cosmos/cosmos-sdk/x/evidence/types"; +option (gogoproto.equal_all) = true; + +import "third_party/proto/gogoproto/gogo.proto"; +import "google/protobuf/timestamp.proto"; +import "google/protobuf/duration.proto"; + +// MsgSubmitEvidenceBase defines an sdk.Msg type that supports submitting arbitrary +// Evidence. +// +// Note, this message type provides the basis for which a true MsgSubmitEvidence +// can be constructed. Since the evidence submitted in the message can be arbitrary, +// assuming it fulfills the Evidence interface, it must be defined at the +// application-level and extend MsgSubmitEvidenceBase. +message MsgSubmitEvidenceBase { + bytes submitter = 1 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; +} + +// Equivocation implements the Evidence interface and defines evidence of double +// signing misbehavior. +message Equivocation { + option (gogoproto.goproto_stringer) = false; + option (gogoproto.goproto_getters) = false; + + int64 height = 1; + google.protobuf.Timestamp time = 2 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; + int64 power = 3; + bytes consensus_address = 4 [ + (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.ConsAddress", + (gogoproto.moretags) = "yaml:\"consensus_address\"" + ]; +} + +// Params defines the total set of parameters for the evidence module +message Params { + option (gogoproto.goproto_stringer) = false; + + google.protobuf.Duration max_evidence_age = 1 [ + (gogoproto.nullable) = false, + (gogoproto.stdduration) = true, + (gogoproto.moretags) = "yaml:\"max_evidence_age\"" + ]; +} diff --git a/x/mint/abci.go b/x/mint/abci.go index 07d8d84624d0..21595b466f98 100644 --- a/x/mint/abci.go +++ b/x/mint/abci.go @@ -2,7 +2,7 @@ package mint import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/mint/internal/types" + "github.com/cosmos/cosmos-sdk/x/mint/types" ) // BeginBlocker mints new tokens for the previous block. diff --git a/x/mint/alias.go b/x/mint/alias.go index c6d2330f9a8b..62c75396a878 100644 --- a/x/mint/alias.go +++ b/x/mint/alias.go @@ -3,8 +3,8 @@ package mint // nolint import ( - "github.com/cosmos/cosmos-sdk/x/mint/internal/keeper" - "github.com/cosmos/cosmos-sdk/x/mint/internal/types" + "github.com/cosmos/cosmos-sdk/x/mint/keeper" + "github.com/cosmos/cosmos-sdk/x/mint/types" ) const ( diff --git a/x/mint/client/cli/query.go b/x/mint/client/cli/query.go index ec37cde40cf6..c11f7394abf5 100644 --- a/x/mint/client/cli/query.go +++ b/x/mint/client/cli/query.go @@ -10,7 +10,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/mint/internal/types" + "github.com/cosmos/cosmos-sdk/x/mint/types" ) // GetQueryCmd returns the cli query commands for the minting module. diff --git a/x/mint/client/rest/query.go b/x/mint/client/rest/query.go index f6e79cc31dcc..f9fc7d43b167 100644 --- a/x/mint/client/rest/query.go +++ b/x/mint/client/rest/query.go @@ -8,7 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/types/rest" - "github.com/cosmos/cosmos-sdk/x/mint/internal/types" + "github.com/cosmos/cosmos-sdk/x/mint/types" ) func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router) { diff --git a/x/mint/internal/types/codec.go b/x/mint/internal/types/codec.go deleted file mode 100644 index 5787f242adfe..000000000000 --- a/x/mint/internal/types/codec.go +++ /dev/null @@ -1,14 +0,0 @@ -package types - -import ( - "github.com/cosmos/cosmos-sdk/codec" -) - -// generic sealed codec to be used throughout this module -var ModuleCdc *codec.Codec - -func init() { - ModuleCdc = codec.New() - codec.RegisterCrypto(ModuleCdc) - ModuleCdc.Seal() -} diff --git a/x/mint/internal/keeper/integration_test.go b/x/mint/keeper/integration_test.go similarity index 90% rename from x/mint/internal/keeper/integration_test.go rename to x/mint/keeper/integration_test.go index ba02e0444767..db1efaca3f12 100644 --- a/x/mint/internal/keeper/integration_test.go +++ b/x/mint/keeper/integration_test.go @@ -5,7 +5,7 @@ import ( "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/mint/internal/types" + "github.com/cosmos/cosmos-sdk/x/mint/types" ) // returns context and an app with updated mint keeper diff --git a/x/mint/internal/keeper/keeper.go b/x/mint/keeper/keeper.go similarity index 94% rename from x/mint/internal/keeper/keeper.go rename to x/mint/keeper/keeper.go index 86721d7bbcc0..9c708f6b5bff 100644 --- a/x/mint/internal/keeper/keeper.go +++ b/x/mint/keeper/keeper.go @@ -7,13 +7,13 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/mint/internal/types" + "github.com/cosmos/cosmos-sdk/x/mint/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" ) // Keeper of the mint store type Keeper struct { - cdc *codec.Codec + cdc codec.Marshaler storeKey sdk.StoreKey paramSpace paramtypes.Subspace sk types.StakingKeeper @@ -23,7 +23,7 @@ type Keeper struct { // NewKeeper creates a new mint Keeper instance func NewKeeper( - cdc *codec.Codec, key sdk.StoreKey, paramSpace paramtypes.Subspace, + cdc codec.Marshaler, key sdk.StoreKey, paramSpace paramtypes.Subspace, sk types.StakingKeeper, supplyKeeper types.SupplyKeeper, feeCollectorName string, ) Keeper { @@ -64,7 +64,7 @@ func (k Keeper) GetMinter(ctx sdk.Context) (minter types.Minter) { // set the minter func (k Keeper) SetMinter(ctx sdk.Context, minter types.Minter) { store := ctx.KVStore(k.storeKey) - b := k.cdc.MustMarshalBinaryLengthPrefixed(minter) + b := k.cdc.MustMarshalBinaryLengthPrefixed(&minter) store.Set(types.MinterKey, b) } diff --git a/x/mint/internal/keeper/querier.go b/x/mint/keeper/querier.go similarity index 96% rename from x/mint/internal/keeper/querier.go rename to x/mint/keeper/querier.go index 258d1b111ed2..7c52ef1001fd 100644 --- a/x/mint/internal/keeper/querier.go +++ b/x/mint/keeper/querier.go @@ -6,7 +6,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/cosmos-sdk/x/mint/internal/types" + "github.com/cosmos/cosmos-sdk/x/mint/types" ) // NewQuerier returns a minting Querier handler. diff --git a/x/mint/internal/keeper/querier_test.go b/x/mint/keeper/querier_test.go similarity index 94% rename from x/mint/internal/keeper/querier_test.go rename to x/mint/keeper/querier_test.go index 287afea9fa5f..07c191f1b75f 100644 --- a/x/mint/internal/keeper/querier_test.go +++ b/x/mint/keeper/querier_test.go @@ -6,8 +6,8 @@ import ( "github.com/stretchr/testify/require" sdk "github.com/cosmos/cosmos-sdk/types" - keep "github.com/cosmos/cosmos-sdk/x/mint/internal/keeper" - "github.com/cosmos/cosmos-sdk/x/mint/internal/types" + keep "github.com/cosmos/cosmos-sdk/x/mint/keeper" + "github.com/cosmos/cosmos-sdk/x/mint/types" abci "github.com/tendermint/tendermint/abci/types" ) diff --git a/x/mint/simulation/decoder.go b/x/mint/simulation/decoder.go index f1c9f6bda62d..5cdac40e88a7 100644 --- a/x/mint/simulation/decoder.go +++ b/x/mint/simulation/decoder.go @@ -7,7 +7,7 @@ import ( tmkv "github.com/tendermint/tendermint/libs/kv" "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/x/mint/internal/types" + "github.com/cosmos/cosmos-sdk/x/mint/types" ) // DecodeStore unmarshals the KVPair's Value to the corresponding mint type diff --git a/x/mint/simulation/decoder_test.go b/x/mint/simulation/decoder_test.go index f92a84f5df21..47ed9bebbed5 100644 --- a/x/mint/simulation/decoder_test.go +++ b/x/mint/simulation/decoder_test.go @@ -10,7 +10,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/mint/internal/types" + "github.com/cosmos/cosmos-sdk/x/mint/types" ) func makeTestCodec() (cdc *codec.Codec) { diff --git a/x/mint/simulation/genesis.go b/x/mint/simulation/genesis.go index 07a750d30e6d..b4b3e1534cb1 100644 --- a/x/mint/simulation/genesis.go +++ b/x/mint/simulation/genesis.go @@ -10,7 +10,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" - "github.com/cosmos/cosmos-sdk/x/mint/internal/types" + "github.com/cosmos/cosmos-sdk/x/mint/types" ) // Simulation parameter constants diff --git a/x/mint/simulation/params.go b/x/mint/simulation/params.go index 4f73183f058a..a467ac0fbf59 100644 --- a/x/mint/simulation/params.go +++ b/x/mint/simulation/params.go @@ -6,7 +6,7 @@ import ( "fmt" "math/rand" - "github.com/cosmos/cosmos-sdk/x/mint/internal/types" + "github.com/cosmos/cosmos-sdk/x/mint/types" "github.com/cosmos/cosmos-sdk/x/simulation" ) diff --git a/x/mint/types/codec.go b/x/mint/types/codec.go new file mode 100644 index 000000000000..04b22f57f2ae --- /dev/null +++ b/x/mint/types/codec.go @@ -0,0 +1,22 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" +) + +var ( + amino = codec.New() + + // ModuleCdc references the global x/mint module codec. Note, the codec + // should ONLY be used in certain instances of tests and for JSON encoding as + // Amino is still used for that purpose. + // + // The actual codec used for serialization should be provided to x/mint and + // defined at the application level. + ModuleCdc = codec.NewHybridCodec(amino) +) + +func init() { + codec.RegisterCrypto(amino) + amino.Seal() +} diff --git a/x/mint/internal/types/events.go b/x/mint/types/events.go similarity index 100% rename from x/mint/internal/types/events.go rename to x/mint/types/events.go diff --git a/x/mint/internal/types/expected_keepers.go b/x/mint/types/expected_keepers.go similarity index 100% rename from x/mint/internal/types/expected_keepers.go rename to x/mint/types/expected_keepers.go diff --git a/x/mint/internal/types/genesis.go b/x/mint/types/genesis.go similarity index 100% rename from x/mint/internal/types/genesis.go rename to x/mint/types/genesis.go diff --git a/x/mint/internal/types/keys.go b/x/mint/types/keys.go similarity index 100% rename from x/mint/internal/types/keys.go rename to x/mint/types/keys.go diff --git a/x/mint/internal/types/minter.go b/x/mint/types/minter.go similarity index 89% rename from x/mint/internal/types/minter.go rename to x/mint/types/minter.go index 3654ef7287b3..3285d6ddf0e8 100644 --- a/x/mint/internal/types/minter.go +++ b/x/mint/types/minter.go @@ -6,12 +6,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -// Minter represents the minting state. -type Minter struct { - Inflation sdk.Dec `json:"inflation" yaml:"inflation"` // current annual inflation rate - AnnualProvisions sdk.Dec `json:"annual_provisions" yaml:"annual_provisions"` // current annual expected provisions -} - // NewMinter returns a new Minter object with the given inflation and annual // provisions values. func NewMinter(inflation, annualProvisions sdk.Dec) Minter { diff --git a/x/mint/internal/types/minter_test.go b/x/mint/types/minter_test.go similarity index 100% rename from x/mint/internal/types/minter_test.go rename to x/mint/types/minter_test.go diff --git a/x/mint/internal/types/params.go b/x/mint/types/params.go similarity index 81% rename from x/mint/internal/types/params.go rename to x/mint/types/params.go index 56604621f583..674c04d48917 100644 --- a/x/mint/internal/types/params.go +++ b/x/mint/types/params.go @@ -5,6 +5,8 @@ import ( "fmt" "strings" + "gopkg.in/yaml.v2" + sdk "github.com/cosmos/cosmos-sdk/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" ) @@ -19,16 +21,6 @@ var ( KeyBlocksPerYear = []byte("BlocksPerYear") ) -// mint parameters -type Params struct { - MintDenom string `json:"mint_denom" yaml:"mint_denom"` // type of coin to mint - InflationRateChange sdk.Dec `json:"inflation_rate_change" yaml:"inflation_rate_change"` // maximum annual change in inflation rate - InflationMax sdk.Dec `json:"inflation_max" yaml:"inflation_max"` // maximum inflation rate - InflationMin sdk.Dec `json:"inflation_min" yaml:"inflation_min"` // minimum inflation rate - GoalBonded sdk.Dec `json:"goal_bonded" yaml:"goal_bonded"` // goal of percent bonded atoms - BlocksPerYear uint64 `json:"blocks_per_year" yaml:"blocks_per_year"` // expected blocks per year -} - // ParamTable for minting module. func ParamKeyTable() paramtypes.KeyTable { return paramtypes.NewKeyTable().RegisterParamSet(&Params{}) @@ -91,18 +83,10 @@ func (p Params) Validate() error { } +// String implements the Stringer interface. func (p Params) String() string { - return fmt.Sprintf(`Minting Params: - Mint Denom: %s - Inflation Rate Change: %s - Inflation Max: %s - Inflation Min: %s - Goal Bonded: %s - Blocks Per Year: %d -`, - p.MintDenom, p.InflationRateChange, p.InflationMax, - p.InflationMin, p.GoalBonded, p.BlocksPerYear, - ) + out, _ := yaml.Marshal(p) + return string(out) } // Implements params.ParamSet diff --git a/x/mint/types/types.pb.go b/x/mint/types/types.pb.go new file mode 100644 index 000000000000..039fcbe0814b --- /dev/null +++ b/x/mint/types/types.pb.go @@ -0,0 +1,785 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: x/mint/types/types.proto + +package types + +import ( + fmt "fmt" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// Minter represents the minting state. +type Minter struct { + // current annual inflation rate + Inflation github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,1,opt,name=inflation,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"inflation"` + // current annual expected provisions + AnnualProvisions github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,2,opt,name=annual_provisions,json=annualProvisions,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"annual_provisions" yaml:"annual_provisions"` +} + +func (m *Minter) Reset() { *m = Minter{} } +func (m *Minter) String() string { return proto.CompactTextString(m) } +func (*Minter) ProtoMessage() {} +func (*Minter) Descriptor() ([]byte, []int) { + return fileDescriptor_fcb8be2eaea25b48, []int{0} +} +func (m *Minter) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Minter) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Minter.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 *Minter) XXX_Merge(src proto.Message) { + xxx_messageInfo_Minter.Merge(m, src) +} +func (m *Minter) XXX_Size() int { + return m.Size() +} +func (m *Minter) XXX_DiscardUnknown() { + xxx_messageInfo_Minter.DiscardUnknown(m) +} + +var xxx_messageInfo_Minter proto.InternalMessageInfo + +// mint parameters +type Params struct { + // type of coin to mint + MintDenom string `protobuf:"bytes,1,opt,name=mint_denom,json=mintDenom,proto3" json:"mint_denom,omitempty"` + // maximum annual change in inflation rate + InflationRateChange github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,2,opt,name=inflation_rate_change,json=inflationRateChange,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"inflation_rate_change" yaml:"inflation_rate_change"` + // maximum inflation rate + InflationMax github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,3,opt,name=inflation_max,json=inflationMax,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"inflation_max" yaml:"inflation_max"` + // minimum inflation rate + InflationMin github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,4,opt,name=inflation_min,json=inflationMin,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"inflation_min" yaml:"inflation_min"` + // goal of percent bonded atoms + GoalBonded github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,5,opt,name=goal_bonded,json=goalBonded,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"goal_bonded" yaml:"goal_bonded"` + // expected blocks per year + BlocksPerYear uint64 `protobuf:"varint,6,opt,name=blocks_per_year,json=blocksPerYear,proto3" json:"blocks_per_year,omitempty" yaml:"blocks_per_year"` +} + +func (m *Params) Reset() { *m = Params{} } +func (*Params) ProtoMessage() {} +func (*Params) Descriptor() ([]byte, []int) { + return fileDescriptor_fcb8be2eaea25b48, []int{1} +} +func (m *Params) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Params) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Params.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 *Params) XXX_Merge(src proto.Message) { + xxx_messageInfo_Params.Merge(m, src) +} +func (m *Params) XXX_Size() int { + return m.Size() +} +func (m *Params) XXX_DiscardUnknown() { + xxx_messageInfo_Params.DiscardUnknown(m) +} + +var xxx_messageInfo_Params proto.InternalMessageInfo + +func (m *Params) GetMintDenom() string { + if m != nil { + return m.MintDenom + } + return "" +} + +func (m *Params) GetBlocksPerYear() uint64 { + if m != nil { + return m.BlocksPerYear + } + return 0 +} + +func init() { + proto.RegisterType((*Minter)(nil), "cosmos_sdk.x.mint.v1.Minter") + proto.RegisterType((*Params)(nil), "cosmos_sdk.x.mint.v1.Params") +} + +func init() { proto.RegisterFile("x/mint/types/types.proto", fileDescriptor_fcb8be2eaea25b48) } + +var fileDescriptor_fcb8be2eaea25b48 = []byte{ + // 439 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x93, 0xb1, 0x6e, 0xd3, 0x40, + 0x1c, 0xc6, 0x6d, 0x48, 0x23, 0xe5, 0xa0, 0x02, 0x8e, 0x82, 0xac, 0x0a, 0xec, 0xca, 0x43, 0xd5, + 0x05, 0x5b, 0x88, 0xad, 0xa3, 0x89, 0x18, 0x10, 0x45, 0x91, 0x37, 0x58, 0x4e, 0xff, 0xd8, 0x87, + 0x73, 0x8a, 0xef, 0xce, 0xba, 0xbb, 0x16, 0x67, 0xe5, 0x09, 0x18, 0x19, 0x79, 0x0b, 0x5e, 0xa1, + 0x1b, 0x1d, 0x11, 0x43, 0x84, 0x92, 0x37, 0xe8, 0x13, 0x20, 0xdf, 0x45, 0x09, 0x04, 0x96, 0x48, + 0x5d, 0x6c, 0xff, 0x3f, 0x7d, 0xff, 0xef, 0xf7, 0xf9, 0xa4, 0x43, 0x41, 0x9b, 0x72, 0x26, 0x4c, + 0x6a, 0x66, 0x0d, 0xd5, 0xee, 0x99, 0x34, 0x4a, 0x1a, 0x89, 0x0f, 0x0a, 0xa9, 0xb9, 0xd4, 0x44, + 0x97, 0xd3, 0xa4, 0x4d, 0x3a, 0x53, 0x72, 0xf1, 0xfc, 0xf0, 0xd8, 0x4c, 0x98, 0x2a, 0x49, 0x03, + 0xca, 0xcc, 0x52, 0x6b, 0x4c, 0x2b, 0x59, 0xc9, 0xcd, 0x97, 0xdb, 0x8e, 0xbf, 0xfb, 0xa8, 0x7f, + 0xc6, 0x84, 0xa1, 0x0a, 0xbf, 0x41, 0x03, 0x26, 0x3e, 0xd4, 0x60, 0x98, 0x14, 0x81, 0x7f, 0xe4, + 0x9f, 0x0c, 0xb2, 0xe4, 0x72, 0x1e, 0x79, 0x3f, 0xe7, 0xd1, 0x71, 0xc5, 0xcc, 0xe4, 0x7c, 0x9c, + 0x14, 0x92, 0xa7, 0x0e, 0xb7, 0x7a, 0x3d, 0xd3, 0xe5, 0x74, 0xd5, 0x66, 0x48, 0x8b, 0x7c, 0x13, + 0x80, 0x3f, 0xa2, 0x07, 0x20, 0xc4, 0x39, 0xd4, 0xa4, 0x51, 0xf2, 0x82, 0x69, 0x26, 0x85, 0x0e, + 0x6e, 0xd9, 0xd4, 0xd7, 0xbb, 0xa5, 0x5e, 0xcf, 0xa3, 0x60, 0x06, 0xbc, 0x3e, 0x8d, 0xff, 0x09, + 0x8c, 0xf3, 0xfb, 0x4e, 0x1b, 0x6d, 0xa4, 0x6f, 0x3d, 0xd4, 0x1f, 0x81, 0x02, 0xae, 0xf1, 0x53, + 0x84, 0xba, 0xf3, 0x20, 0x25, 0x15, 0x92, 0xbb, 0x5f, 0xca, 0x07, 0x9d, 0x32, 0xec, 0x04, 0xfc, + 0xc9, 0x47, 0x8f, 0xd6, 0x85, 0x89, 0x02, 0x43, 0x49, 0x31, 0x01, 0x51, 0xd1, 0x55, 0xcf, 0xb7, + 0x3b, 0xf7, 0x7c, 0xe2, 0x7a, 0xfe, 0x37, 0x34, 0xce, 0x1f, 0xae, 0xf5, 0x1c, 0x0c, 0x7d, 0x69, + 0x55, 0x3c, 0x45, 0xfb, 0x1b, 0x3b, 0x87, 0x36, 0xb8, 0x6d, 0xd9, 0xaf, 0x76, 0x66, 0x1f, 0x6c, + 0xb3, 0x39, 0xb4, 0x71, 0x7e, 0x77, 0x3d, 0x9f, 0x41, 0xbb, 0x05, 0x63, 0x22, 0xe8, 0xdd, 0x18, + 0x8c, 0x89, 0xbf, 0x60, 0x4c, 0x60, 0x8a, 0xee, 0x54, 0x12, 0x6a, 0x32, 0x96, 0xa2, 0xa4, 0x65, + 0xb0, 0x67, 0x51, 0xc3, 0x9d, 0x51, 0xd8, 0xa1, 0xfe, 0x88, 0x8a, 0x73, 0xd4, 0x4d, 0x99, 0x1d, + 0x70, 0x86, 0xee, 0x8d, 0x6b, 0x59, 0x4c, 0x35, 0x69, 0xa8, 0x22, 0x33, 0x0a, 0x2a, 0xe8, 0x1f, + 0xf9, 0x27, 0xbd, 0xec, 0xf0, 0x7a, 0x1e, 0x3d, 0x76, 0xcb, 0x5b, 0x86, 0x38, 0xdf, 0x77, 0xca, + 0x88, 0xaa, 0x77, 0x14, 0xd4, 0x69, 0xef, 0xcb, 0xd7, 0xc8, 0xcb, 0xa2, 0xcb, 0x45, 0xe8, 0x5f, + 0x2d, 0x42, 0xff, 0xd7, 0x22, 0xf4, 0x3f, 0x2f, 0x43, 0xef, 0x6a, 0x19, 0x7a, 0x3f, 0x96, 0xa1, + 0xf7, 0x7e, 0xcf, 0x16, 0x1a, 0xf7, 0xed, 0x9d, 0x79, 0xf1, 0x3b, 0x00, 0x00, 0xff, 0xff, 0x9e, + 0xe3, 0xbd, 0x88, 0x8d, 0x03, 0x00, 0x00, +} + +func (m *Minter) 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 *Minter) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Minter) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size := m.AnnualProvisions.Size() + i -= size + if _, err := m.AnnualProvisions.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + { + size := m.Inflation.Size() + i -= size + if _, err := m.Inflation.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *Params) 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 *Params) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.BlocksPerYear != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.BlocksPerYear)) + i-- + dAtA[i] = 0x30 + } + { + size := m.GoalBonded.Size() + i -= size + if _, err := m.GoalBonded.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + { + size := m.InflationMin.Size() + i -= size + if _, err := m.InflationMin.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + { + size := m.InflationMax.Size() + i -= size + if _, err := m.InflationMax.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + { + size := m.InflationRateChange.Size() + i -= size + if _, err := m.InflationRateChange.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.MintDenom) > 0 { + i -= len(m.MintDenom) + copy(dAtA[i:], m.MintDenom) + i = encodeVarintTypes(dAtA, i, uint64(len(m.MintDenom))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintTypes(dAtA []byte, offset int, v uint64) int { + offset -= sovTypes(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Minter) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Inflation.Size() + n += 1 + l + sovTypes(uint64(l)) + l = m.AnnualProvisions.Size() + n += 1 + l + sovTypes(uint64(l)) + return n +} + +func (m *Params) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.MintDenom) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = m.InflationRateChange.Size() + n += 1 + l + sovTypes(uint64(l)) + l = m.InflationMax.Size() + n += 1 + l + sovTypes(uint64(l)) + l = m.InflationMin.Size() + n += 1 + l + sovTypes(uint64(l)) + l = m.GoalBonded.Size() + n += 1 + l + sovTypes(uint64(l)) + if m.BlocksPerYear != 0 { + n += 1 + sovTypes(uint64(m.BlocksPerYear)) + } + return n +} + +func sovTypes(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTypes(x uint64) (n int) { + return sovTypes(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Minter) 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 ErrIntOverflowTypes + } + 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: Minter: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Minter: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Inflation", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Inflation.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AnnualProvisions", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.AnnualProvisions.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Params) 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 ErrIntOverflowTypes + } + 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: Params: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MintDenom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.MintDenom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InflationRateChange", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.InflationRateChange.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InflationMax", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.InflationMax.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InflationMin", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.InflationMin.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field GoalBonded", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.GoalBonded.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field BlocksPerYear", wireType) + } + m.BlocksPerYear = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.BlocksPerYear |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTypes(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthTypes + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTypes + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTypes + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTypes = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTypes = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTypes = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/mint/types/types.proto b/x/mint/types/types.proto new file mode 100644 index 000000000000..700e05cb1ad4 --- /dev/null +++ b/x/mint/types/types.proto @@ -0,0 +1,53 @@ +syntax = "proto3"; +package cosmos_sdk.x.mint.v1; + +option go_package = "types"; + +import "third_party/proto/gogoproto/gogo.proto"; + +// Minter represents the minting state. +message Minter { + // current annual inflation rate + string inflation = 1 + [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false]; + // current annual expected provisions + string annual_provisions = 2 [ + (gogoproto.moretags) = "yaml:\"annual_provisions\"", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; +} + +// mint parameters +message Params { + option (gogoproto.goproto_stringer) = false; + + // type of coin to mint + string mint_denom = 1; + // maximum annual change in inflation rate + string inflation_rate_change = 2 [ + (gogoproto.moretags) = "yaml:\"inflation_rate_change\"", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; + // maximum inflation rate + string inflation_max = 3 [ + (gogoproto.moretags) = "yaml:\"inflation_max\"", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; + // minimum inflation rate + string inflation_min = 4 [ + (gogoproto.moretags) = "yaml:\"inflation_min\"", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; + // goal of percent bonded atoms + string goal_bonded = 5 [ + (gogoproto.moretags) = "yaml:\"goal_bonded\"", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; + // expected blocks per year + uint64 blocks_per_year = 6 [(gogoproto.moretags) = "yaml:\"blocks_per_year\""]; +} From fe1012dc29d008650f6f550a501df094c6cd3791 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 24 Feb 2020 17:34:22 +0100 Subject: [PATCH 192/529] migrate revocation of old slash test --- x/staking/keeper/old_slash_test.go | 579 +++++++++++++++++++++++++++ x/staking/keeper/slash_test.go | 602 ++--------------------------- 2 files changed, 611 insertions(+), 570 deletions(-) create mode 100644 x/staking/keeper/old_slash_test.go diff --git a/x/staking/keeper/old_slash_test.go b/x/staking/keeper/old_slash_test.go new file mode 100644 index 000000000000..f6b442dc3c18 --- /dev/null +++ b/x/staking/keeper/old_slash_test.go @@ -0,0 +1,579 @@ +package keeper + +import ( + "testing" + "time" + + "github.com/stretchr/testify/require" + + abci "github.com/tendermint/tendermint/abci/types" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/staking/types" +) + +// TODO integrate with test_common.go helper (CreateTestInput) +// setup helper function - creates two validators +func setupHelper(t *testing.T, power int64) (sdk.Context, Keeper, types.Params) { + // setup + ctx, _, _, keeper, _ := CreateTestInput(t, false, power) + params := keeper.GetParams(ctx) + numVals := int64(3) + amt := sdk.TokensFromConsensusPower(power) + bondedCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), amt.MulRaw(numVals))) + + bondedPool := keeper.GetBondedPool(ctx) + require.NoError(t, keeper.bankKeeper.SetBalances(ctx, bondedPool.GetAddress(), bondedCoins)) + keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) + + // add numVals validators + for i := int64(0); i < numVals; i++ { + validator := types.NewValidator(addrVals[i], PKs[i], types.Description{}) + validator, _ = validator.AddTokensFromDel(amt) + validator = TestingUpdateValidator(keeper, ctx, validator, true) + keeper.SetValidatorByConsAddr(ctx, validator) + } + + return ctx, keeper, params +} + +//_________________________________________________________________________________ + +// tests slashUnbondingDelegation +func TestSlashUnbondingDelegation(t *testing.T) { + ctx, keeper, _ := setupHelper(t, 10) + fraction := sdk.NewDecWithPrec(5, 1) + + // set an unbonding delegation with expiration timestamp (beyond which the + // unbonding delegation shouldn't be slashed) + ubd := types.NewUnbondingDelegation(addrDels[0], addrVals[0], 0, + time.Unix(5, 0), sdk.NewInt(10)) + + keeper.SetUnbondingDelegation(ctx, ubd) + + // unbonding started prior to the infraction height, stakw didn't contribute + slashAmount := keeper.slashUnbondingDelegation(ctx, ubd, 1, fraction) + require.Equal(t, int64(0), slashAmount.Int64()) + + // after the expiration time, no longer eligible for slashing + ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(10, 0)}) + keeper.SetUnbondingDelegation(ctx, ubd) + slashAmount = keeper.slashUnbondingDelegation(ctx, ubd, 0, fraction) + require.Equal(t, int64(0), slashAmount.Int64()) + + // test valid slash, before expiration timestamp and to which stake contributed + notBondedPool := keeper.GetNotBondedPool(ctx) + oldUnbondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) + ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(0, 0)}) + keeper.SetUnbondingDelegation(ctx, ubd) + slashAmount = keeper.slashUnbondingDelegation(ctx, ubd, 0, fraction) + require.Equal(t, int64(5), slashAmount.Int64()) + ubd, found := keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) + require.True(t, found) + require.Len(t, ubd.Entries, 1) + + // initial balance unchanged + require.Equal(t, sdk.NewInt(10), ubd.Entries[0].InitialBalance) + + // balance decreased + require.Equal(t, sdk.NewInt(5), ubd.Entries[0].Balance) + newUnbondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) + diffTokens := oldUnbondedPoolBalances.Sub(newUnbondedPoolBalances) + require.Equal(t, int64(5), diffTokens.AmountOf(keeper.BondDenom(ctx)).Int64()) +} + +// tests slashRedelegation +func TestSlashRedelegation(t *testing.T) { + ctx, keeper, _ := setupHelper(t, 10) + fraction := sdk.NewDecWithPrec(5, 1) + + // add bonded tokens to pool for (re)delegations + startCoins := sdk.NewCoins(sdk.NewInt64Coin(keeper.BondDenom(ctx), 15)) + bondedPool := keeper.GetBondedPool(ctx) + balances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + + require.NoError(t, keeper.bankKeeper.SetBalances(ctx, bondedPool.GetAddress(), balances.Add(startCoins...))) + keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) + + // set a redelegation with an expiration timestamp beyond which the + // redelegation shouldn't be slashed + rd := types.NewRedelegation(addrDels[0], addrVals[0], addrVals[1], 0, + time.Unix(5, 0), sdk.NewInt(10), sdk.NewDec(10)) + + keeper.SetRedelegation(ctx, rd) + + // set the associated delegation + del := types.NewDelegation(addrDels[0], addrVals[1], sdk.NewDec(10)) + keeper.SetDelegation(ctx, del) + + // started redelegating prior to the current height, stake didn't contribute to infraction + validator, found := keeper.GetValidator(ctx, addrVals[1]) + require.True(t, found) + slashAmount := keeper.slashRedelegation(ctx, validator, rd, 1, fraction) + require.Equal(t, int64(0), slashAmount.Int64()) + + // after the expiration time, no longer eligible for slashing + ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(10, 0)}) + keeper.SetRedelegation(ctx, rd) + validator, found = keeper.GetValidator(ctx, addrVals[1]) + require.True(t, found) + slashAmount = keeper.slashRedelegation(ctx, validator, rd, 0, fraction) + require.Equal(t, int64(0), slashAmount.Int64()) + + balances = keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + + // test valid slash, before expiration timestamp and to which stake contributed + ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(0, 0)}) + keeper.SetRedelegation(ctx, rd) + validator, found = keeper.GetValidator(ctx, addrVals[1]) + require.True(t, found) + slashAmount = keeper.slashRedelegation(ctx, validator, rd, 0, fraction) + require.Equal(t, int64(5), slashAmount.Int64()) + rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) + require.True(t, found) + require.Len(t, rd.Entries, 1) + + // end block + updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 1, len(updates)) + + // initialbalance unchanged + require.Equal(t, sdk.NewInt(10), rd.Entries[0].InitialBalance) + + // shares decreased + del, found = keeper.GetDelegation(ctx, addrDels[0], addrVals[1]) + require.True(t, found) + require.Equal(t, int64(5), del.Shares.RoundInt64()) + + // pool bonded tokens should decrease + burnedCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), slashAmount)) + require.Equal(t, balances.Sub(burnedCoins), keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress())) +} + +// tests Slash at a future height (must panic) +func TestSlashAtFutureHeight(t *testing.T) { + ctx, keeper, _ := setupHelper(t, 10) + consAddr := sdk.ConsAddress(PKs[0].Address()) + fraction := sdk.NewDecWithPrec(5, 1) + require.Panics(t, func() { keeper.Slash(ctx, consAddr, 1, 10, fraction) }) +} + +// test slash at a negative height +// this just represents pre-genesis and should have the same effect as slashing at height 0 +func TestSlashAtNegativeHeight(t *testing.T) { + ctx, keeper, _ := setupHelper(t, 10) + consAddr := sdk.ConsAddress(PKs[0].Address()) + fraction := sdk.NewDecWithPrec(5, 1) + + bondedPool := keeper.GetBondedPool(ctx) + oldBondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + + validator, found := keeper.GetValidatorByConsAddr(ctx, consAddr) + require.True(t, found) + keeper.Slash(ctx, consAddr, -2, 10, fraction) + + // read updated state + validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) + require.True(t, found) + + // end block + updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 1, len(updates), "cons addr: %v, updates: %v", []byte(consAddr), updates) + + validator = keeper.mustGetValidator(ctx, validator.OperatorAddress) + // power decreased + require.Equal(t, int64(5), validator.GetConsensusPower()) + + // pool bonded shares decreased + newBondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + diffTokens := oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(keeper.BondDenom(ctx)) + require.Equal(t, sdk.TokensFromConsensusPower(5).String(), diffTokens.String()) +} + +// tests Slash at the current height +func TestSlashValidatorAtCurrentHeight(t *testing.T) { + ctx, keeper, _ := setupHelper(t, 10) + consAddr := sdk.ConsAddress(PKs[0].Address()) + fraction := sdk.NewDecWithPrec(5, 1) + + bondedPool := keeper.GetBondedPool(ctx) + oldBondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + + validator, found := keeper.GetValidatorByConsAddr(ctx, consAddr) + require.True(t, found) + keeper.Slash(ctx, consAddr, ctx.BlockHeight(), 10, fraction) + + // read updated state + validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) + require.True(t, found) + + // end block + updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 1, len(updates), "cons addr: %v, updates: %v", []byte(consAddr), updates) + + validator = keeper.mustGetValidator(ctx, validator.OperatorAddress) + // power decreased + require.Equal(t, int64(5), validator.GetConsensusPower()) + + // pool bonded shares decreased + newBondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + diffTokens := oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(keeper.BondDenom(ctx)) + require.Equal(t, sdk.TokensFromConsensusPower(5).String(), diffTokens.String()) +} + +// tests Slash at a previous height with an unbonding delegation +func TestSlashWithUnbondingDelegation(t *testing.T) { + ctx, keeper, _ := setupHelper(t, 10) + consAddr := sdk.ConsAddress(PKs[0].Address()) + fraction := sdk.NewDecWithPrec(5, 1) + + // set an unbonding delegation with expiration timestamp beyond which the + // unbonding delegation shouldn't be slashed + ubdTokens := sdk.TokensFromConsensusPower(4) + ubd := types.NewUnbondingDelegation(addrDels[0], addrVals[0], 11, + time.Unix(0, 0), ubdTokens) + keeper.SetUnbondingDelegation(ctx, ubd) + + // slash validator for the first time + ctx = ctx.WithBlockHeight(12) + bondedPool := keeper.GetBondedPool(ctx) + oldBondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + + validator, found := keeper.GetValidatorByConsAddr(ctx, consAddr) + require.True(t, found) + keeper.Slash(ctx, consAddr, 10, 10, fraction) + + // end block + updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 1, len(updates)) + + // read updating unbonding delegation + ubd, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) + require.True(t, found) + require.Len(t, ubd.Entries, 1) + + // balance decreased + require.Equal(t, sdk.TokensFromConsensusPower(2), ubd.Entries[0].Balance) + + // bonded tokens burned + newBondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + diffTokens := oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(keeper.BondDenom(ctx)) + require.Equal(t, sdk.TokensFromConsensusPower(3), diffTokens) + + // read updated validator + validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) + require.True(t, found) + + // power decreased by 3 - 6 stake originally bonded at the time of infraction + // was still bonded at the time of discovery and was slashed by half, 4 stake + // bonded at the time of discovery hadn't been bonded at the time of infraction + // and wasn't slashed + require.Equal(t, int64(7), validator.GetConsensusPower()) + + // slash validator again + ctx = ctx.WithBlockHeight(13) + keeper.Slash(ctx, consAddr, 9, 10, fraction) + + ubd, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) + require.True(t, found) + require.Len(t, ubd.Entries, 1) + + // balance decreased again + require.Equal(t, sdk.NewInt(0), ubd.Entries[0].Balance) + + // bonded tokens burned again + newBondedPoolBalances = keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + diffTokens = oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(keeper.BondDenom(ctx)) + require.Equal(t, sdk.TokensFromConsensusPower(6), diffTokens) + + // read updated validator + validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) + require.True(t, found) + + // power decreased by 3 again + require.Equal(t, int64(4), validator.GetConsensusPower()) + + // slash validator again + // all originally bonded stake has been slashed, so this will have no effect + // on the unbonding delegation, but it will slash stake bonded since the infraction + // this may not be the desirable behaviour, ref https://github.com/cosmos/cosmos-sdk/issues/1440 + ctx = ctx.WithBlockHeight(13) + keeper.Slash(ctx, consAddr, 9, 10, fraction) + + ubd, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) + require.True(t, found) + require.Len(t, ubd.Entries, 1) + + // balance unchanged + require.Equal(t, sdk.NewInt(0), ubd.Entries[0].Balance) + + // bonded tokens burned again + newBondedPoolBalances = keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + diffTokens = oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(keeper.BondDenom(ctx)) + require.Equal(t, sdk.TokensFromConsensusPower(9), diffTokens) + + // read updated validator + validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) + require.True(t, found) + + // power decreased by 3 again + require.Equal(t, int64(1), validator.GetConsensusPower()) + + // slash validator again + // all originally bonded stake has been slashed, so this will have no effect + // on the unbonding delegation, but it will slash stake bonded since the infraction + // this may not be the desirable behaviour, ref https://github.com/cosmos/cosmos-sdk/issues/1440 + ctx = ctx.WithBlockHeight(13) + keeper.Slash(ctx, consAddr, 9, 10, fraction) + + ubd, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) + require.True(t, found) + require.Len(t, ubd.Entries, 1) + + // balance unchanged + require.Equal(t, sdk.NewInt(0), ubd.Entries[0].Balance) + + // just 1 bonded token burned again since that's all the validator now has + newBondedPoolBalances = keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + diffTokens = oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(keeper.BondDenom(ctx)) + require.Equal(t, sdk.TokensFromConsensusPower(10), diffTokens) + + // apply TM updates + keeper.ApplyAndReturnValidatorSetUpdates(ctx) + + // read updated validator + // power decreased by 1 again, validator is out of stake + // validator should be in unbonding period + validator, _ = keeper.GetValidatorByConsAddr(ctx, consAddr) + require.Equal(t, validator.GetStatus(), sdk.Unbonding) +} + +// tests Slash at a previous height with a redelegation +func TestSlashWithRedelegation(t *testing.T) { + ctx, keeper, _ := setupHelper(t, 10) + consAddr := sdk.ConsAddress(PKs[0].Address()) + fraction := sdk.NewDecWithPrec(5, 1) + bondDenom := keeper.BondDenom(ctx) + + // set a redelegation + rdTokens := sdk.TokensFromConsensusPower(6) + rd := types.NewRedelegation(addrDels[0], addrVals[0], addrVals[1], 11, + time.Unix(0, 0), rdTokens, rdTokens.ToDec()) + keeper.SetRedelegation(ctx, rd) + + // set the associated delegation + del := types.NewDelegation(addrDels[0], addrVals[1], rdTokens.ToDec()) + keeper.SetDelegation(ctx, del) + + // update bonded tokens + bondedPool := keeper.GetBondedPool(ctx) + notBondedPool := keeper.GetNotBondedPool(ctx) + rdCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, rdTokens.MulRaw(2))) + + balances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + err := keeper.bankKeeper.SetBalances(ctx, bondedPool.GetAddress(), balances.Add(rdCoins...)) + require.NoError(t, err) + + keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) + + oldBonded := keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount + oldNotBonded := keeper.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount + + // slash validator + ctx = ctx.WithBlockHeight(12) + validator, found := keeper.GetValidatorByConsAddr(ctx, consAddr) + require.True(t, found) + + require.NotPanics(t, func() { keeper.Slash(ctx, consAddr, 10, 10, fraction) }) + burnAmount := sdk.TokensFromConsensusPower(10).ToDec().Mul(fraction).TruncateInt() + + bondedPool = keeper.GetBondedPool(ctx) + notBondedPool = keeper.GetNotBondedPool(ctx) + + // burn bonded tokens from only from delegations + bondedPoolBalance := keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldBonded.Sub(burnAmount), bondedPoolBalance)) + + notBondedPoolBalance := keeper.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldNotBonded, notBondedPoolBalance)) + oldBonded = keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount + + // read updating redelegation + rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) + require.True(t, found) + require.Len(t, rd.Entries, 1) + // read updated validator + validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) + require.True(t, found) + // power decreased by 2 - 4 stake originally bonded at the time of infraction + // was still bonded at the time of discovery and was slashed by half, 4 stake + // bonded at the time of discovery hadn't been bonded at the time of infraction + // and wasn't slashed + require.Equal(t, int64(8), validator.GetConsensusPower()) + + // slash the validator again + validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) + require.True(t, found) + + require.NotPanics(t, func() { keeper.Slash(ctx, consAddr, 10, 10, sdk.OneDec()) }) + burnAmount = sdk.TokensFromConsensusPower(7) + + // read updated pool + bondedPool = keeper.GetBondedPool(ctx) + notBondedPool = keeper.GetNotBondedPool(ctx) + + // seven bonded tokens burned + bondedPoolBalance = keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldBonded.Sub(burnAmount), bondedPoolBalance)) + require.True(sdk.IntEq(t, oldNotBonded, notBondedPoolBalance)) + + bondedPoolBalance = keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldBonded.Sub(burnAmount), bondedPoolBalance)) + + notBondedPoolBalance = keeper.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldNotBonded, notBondedPoolBalance)) + oldBonded = keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount + + // read updating redelegation + rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) + require.True(t, found) + require.Len(t, rd.Entries, 1) + // read updated validator + validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) + require.True(t, found) + // power decreased by 4 + require.Equal(t, int64(4), validator.GetConsensusPower()) + + // slash the validator again, by 100% + ctx = ctx.WithBlockHeight(12) + validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) + require.True(t, found) + + require.NotPanics(t, func() { keeper.Slash(ctx, consAddr, 10, 10, sdk.OneDec()) }) + + burnAmount = sdk.TokensFromConsensusPower(10).ToDec().Mul(sdk.OneDec()).TruncateInt() + burnAmount = burnAmount.Sub(sdk.OneDec().MulInt(rdTokens).TruncateInt()) + + // read updated pool + bondedPool = keeper.GetBondedPool(ctx) + notBondedPool = keeper.GetNotBondedPool(ctx) + + bondedPoolBalance = keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldBonded.Sub(burnAmount), bondedPoolBalance)) + notBondedPoolBalance = keeper.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldNotBonded, notBondedPoolBalance)) + oldBonded = keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount + + // read updating redelegation + rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) + require.True(t, found) + require.Len(t, rd.Entries, 1) + // apply TM updates + keeper.ApplyAndReturnValidatorSetUpdates(ctx) + // read updated validator + // validator decreased to zero power, should be in unbonding period + validator, _ = keeper.GetValidatorByConsAddr(ctx, consAddr) + require.Equal(t, validator.GetStatus(), sdk.Unbonding) + + // slash the validator again, by 100% + // no stake remains to be slashed + ctx = ctx.WithBlockHeight(12) + // validator still in unbonding period + validator, _ = keeper.GetValidatorByConsAddr(ctx, consAddr) + require.Equal(t, validator.GetStatus(), sdk.Unbonding) + + require.NotPanics(t, func() { keeper.Slash(ctx, consAddr, 10, 10, sdk.OneDec()) }) + + // read updated pool + bondedPool = keeper.GetBondedPool(ctx) + notBondedPool = keeper.GetNotBondedPool(ctx) + + bondedPoolBalance = keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldBonded, bondedPoolBalance)) + notBondedPoolBalance = keeper.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldNotBonded, notBondedPoolBalance)) + + // read updating redelegation + rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) + require.True(t, found) + require.Len(t, rd.Entries, 1) + // read updated validator + // power still zero, still in unbonding period + validator, _ = keeper.GetValidatorByConsAddr(ctx, consAddr) + require.Equal(t, validator.GetStatus(), sdk.Unbonding) +} + +// tests Slash at a previous height with both an unbonding delegation and a redelegation +func TestSlashBoth(t *testing.T) { + ctx, keeper, _ := setupHelper(t, 10) + fraction := sdk.NewDecWithPrec(5, 1) + bondDenom := keeper.BondDenom(ctx) + + // set a redelegation with expiration timestamp beyond which the + // redelegation shouldn't be slashed + rdATokens := sdk.TokensFromConsensusPower(6) + rdA := types.NewRedelegation(addrDels[0], addrVals[0], addrVals[1], 11, + time.Unix(0, 0), rdATokens, + rdATokens.ToDec()) + keeper.SetRedelegation(ctx, rdA) + + // set the associated delegation + delA := types.NewDelegation(addrDels[0], addrVals[1], rdATokens.ToDec()) + keeper.SetDelegation(ctx, delA) + + // set an unbonding delegation with expiration timestamp (beyond which the + // unbonding delegation shouldn't be slashed) + ubdATokens := sdk.TokensFromConsensusPower(4) + ubdA := types.NewUnbondingDelegation(addrDels[0], addrVals[0], 11, + time.Unix(0, 0), ubdATokens) + keeper.SetUnbondingDelegation(ctx, ubdA) + + bondedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, rdATokens.MulRaw(2))) + notBondedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, ubdATokens)) + + // update bonded tokens + bondedPool := keeper.GetBondedPool(ctx) + notBondedPool := keeper.GetNotBondedPool(ctx) + + bondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + require.NoError(t, keeper.bankKeeper.SetBalances(ctx, bondedPool.GetAddress(), bondedPoolBalances.Add(bondedCoins...))) + + notBondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) + require.NoError(t, keeper.bankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), notBondedPoolBalances.Add(notBondedCoins...))) + + keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) + keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) + + oldBonded := keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount + oldNotBonded := keeper.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount + // slash validator + ctx = ctx.WithBlockHeight(12) + validator, found := keeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(PKs[0])) + require.True(t, found) + consAddr0 := sdk.ConsAddress(PKs[0].Address()) + keeper.Slash(ctx, consAddr0, 10, 10, fraction) + + burnedNotBondedAmount := fraction.MulInt(ubdATokens).TruncateInt() + burnedBondAmount := sdk.TokensFromConsensusPower(10).ToDec().Mul(fraction).TruncateInt() + burnedBondAmount = burnedBondAmount.Sub(burnedNotBondedAmount) + + // read updated pool + bondedPool = keeper.GetBondedPool(ctx) + notBondedPool = keeper.GetNotBondedPool(ctx) + + bondedPoolBalance := keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldBonded.Sub(burnedBondAmount), bondedPoolBalance)) + + notBondedPoolBalance := keeper.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldNotBonded.Sub(burnedNotBondedAmount), notBondedPoolBalance)) + + // read updating redelegation + rdA, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) + require.True(t, found) + require.Len(t, rdA.Entries, 1) + // read updated validator + validator, found = keeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(PKs[0])) + require.True(t, found) + // power not decreased, all stake was bonded since + require.Equal(t, int64(10), validator.GetConsensusPower()) +} diff --git a/x/staking/keeper/slash_test.go b/x/staking/keeper/slash_test.go index 2127cf51e196..3f88942a5c61 100644 --- a/x/staking/keeper/slash_test.go +++ b/x/staking/keeper/slash_test.go @@ -1,604 +1,66 @@ -package keeper +package keeper_test import ( "testing" - "time" - - "github.com/stretchr/testify/require" - - abci "github.com/tendermint/tendermint/abci/types" + "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/staking/keeper" "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/stretchr/testify/require" ) -// TODO integrate with test_common.go helper (CreateTestInput) -// setup helper function - creates two validators -func setupHelper(t *testing.T, power int64) (sdk.Context, Keeper, types.Params) { - // setup - ctx, _, _, keeper, _ := CreateTestInput(t, false, power) - params := keeper.GetParams(ctx) +// initConfig creates 3 validators and bootstrap the app. +func initConfig(t *testing.T) (*simapp.SimApp, sdk.Context, []sdk.ValAddress) { + _, app, ctx := getBaseSimappWithCustomKeeper() + + addrDels := simapp.AddTestAddrsIncremental(app, ctx, 3, sdk.NewInt(10000)) + addrVals := simapp.ConvertAddrsToValAddrs(addrDels) + numVals := int64(3) - amt := sdk.TokensFromConsensusPower(power) - bondedCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), amt.MulRaw(numVals))) + amt := sdk.TokensFromConsensusPower(10) + bondedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), amt.MulRaw(numVals))) - bondedPool := keeper.GetBondedPool(ctx) - require.NoError(t, keeper.bankKeeper.SetBalances(ctx, bondedPool.GetAddress(), bondedCoins)) - keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) + notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) + err := app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), bondedCoins) + require.NoError(t, err) + app.SupplyKeeper.SetModuleAccount(ctx, notBondedPool) + + bondedPool := app.StakingKeeper.GetBondedPool(ctx) + err = app.BankKeeper.SetBalances(ctx, bondedPool.GetAddress(), bondedCoins) + require.NoError(t, err) + app.SupplyKeeper.SetModuleAccount(ctx, bondedPool) - // add numVals validators for i := int64(0); i < numVals; i++ { validator := types.NewValidator(addrVals[i], PKs[i], types.Description{}) validator, _ = validator.AddTokensFromDel(amt) - validator = TestingUpdateValidator(keeper, ctx, validator, true) - keeper.SetValidatorByConsAddr(ctx, validator) + validator = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator, true) + app.StakingKeeper.SetValidatorByConsAddr(ctx, validator) } - return ctx, keeper, params + return app, ctx, addrVals } -//_________________________________________________________________________________ - // tests Jail, Unjail func TestRevocation(t *testing.T) { - // setup - ctx, keeper, _ := setupHelper(t, 10) - addr := addrVals[0] + app, ctx, addrVals := initConfig(t) + consAddr := sdk.ConsAddress(PKs[0].Address()) // initial state - val, found := keeper.GetValidator(ctx, addr) + val, found := app.StakingKeeper.GetValidator(ctx, addrVals[0]) require.True(t, found) require.False(t, val.IsJailed()) // test jail - keeper.Jail(ctx, consAddr) - val, found = keeper.GetValidator(ctx, addr) + app.StakingKeeper.Jail(ctx, consAddr) + val, found = app.StakingKeeper.GetValidator(ctx, addrVals[0]) require.True(t, found) require.True(t, val.IsJailed()) // test unjail - keeper.Unjail(ctx, consAddr) - val, found = keeper.GetValidator(ctx, addr) + app.StakingKeeper.Unjail(ctx, consAddr) + val, found = app.StakingKeeper.GetValidator(ctx, addrVals[0]) require.True(t, found) require.False(t, val.IsJailed()) } - -// tests slashUnbondingDelegation -func TestSlashUnbondingDelegation(t *testing.T) { - ctx, keeper, _ := setupHelper(t, 10) - fraction := sdk.NewDecWithPrec(5, 1) - - // set an unbonding delegation with expiration timestamp (beyond which the - // unbonding delegation shouldn't be slashed) - ubd := types.NewUnbondingDelegation(addrDels[0], addrVals[0], 0, - time.Unix(5, 0), sdk.NewInt(10)) - - keeper.SetUnbondingDelegation(ctx, ubd) - - // unbonding started prior to the infraction height, stakw didn't contribute - slashAmount := keeper.slashUnbondingDelegation(ctx, ubd, 1, fraction) - require.Equal(t, int64(0), slashAmount.Int64()) - - // after the expiration time, no longer eligible for slashing - ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(10, 0)}) - keeper.SetUnbondingDelegation(ctx, ubd) - slashAmount = keeper.slashUnbondingDelegation(ctx, ubd, 0, fraction) - require.Equal(t, int64(0), slashAmount.Int64()) - - // test valid slash, before expiration timestamp and to which stake contributed - notBondedPool := keeper.GetNotBondedPool(ctx) - oldUnbondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) - ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(0, 0)}) - keeper.SetUnbondingDelegation(ctx, ubd) - slashAmount = keeper.slashUnbondingDelegation(ctx, ubd, 0, fraction) - require.Equal(t, int64(5), slashAmount.Int64()) - ubd, found := keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) - require.True(t, found) - require.Len(t, ubd.Entries, 1) - - // initial balance unchanged - require.Equal(t, sdk.NewInt(10), ubd.Entries[0].InitialBalance) - - // balance decreased - require.Equal(t, sdk.NewInt(5), ubd.Entries[0].Balance) - newUnbondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) - diffTokens := oldUnbondedPoolBalances.Sub(newUnbondedPoolBalances) - require.Equal(t, int64(5), diffTokens.AmountOf(keeper.BondDenom(ctx)).Int64()) -} - -// tests slashRedelegation -func TestSlashRedelegation(t *testing.T) { - ctx, keeper, _ := setupHelper(t, 10) - fraction := sdk.NewDecWithPrec(5, 1) - - // add bonded tokens to pool for (re)delegations - startCoins := sdk.NewCoins(sdk.NewInt64Coin(keeper.BondDenom(ctx), 15)) - bondedPool := keeper.GetBondedPool(ctx) - balances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) - - require.NoError(t, keeper.bankKeeper.SetBalances(ctx, bondedPool.GetAddress(), balances.Add(startCoins...))) - keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) - - // set a redelegation with an expiration timestamp beyond which the - // redelegation shouldn't be slashed - rd := types.NewRedelegation(addrDels[0], addrVals[0], addrVals[1], 0, - time.Unix(5, 0), sdk.NewInt(10), sdk.NewDec(10)) - - keeper.SetRedelegation(ctx, rd) - - // set the associated delegation - del := types.NewDelegation(addrDels[0], addrVals[1], sdk.NewDec(10)) - keeper.SetDelegation(ctx, del) - - // started redelegating prior to the current height, stake didn't contribute to infraction - validator, found := keeper.GetValidator(ctx, addrVals[1]) - require.True(t, found) - slashAmount := keeper.slashRedelegation(ctx, validator, rd, 1, fraction) - require.Equal(t, int64(0), slashAmount.Int64()) - - // after the expiration time, no longer eligible for slashing - ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(10, 0)}) - keeper.SetRedelegation(ctx, rd) - validator, found = keeper.GetValidator(ctx, addrVals[1]) - require.True(t, found) - slashAmount = keeper.slashRedelegation(ctx, validator, rd, 0, fraction) - require.Equal(t, int64(0), slashAmount.Int64()) - - balances = keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) - - // test valid slash, before expiration timestamp and to which stake contributed - ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(0, 0)}) - keeper.SetRedelegation(ctx, rd) - validator, found = keeper.GetValidator(ctx, addrVals[1]) - require.True(t, found) - slashAmount = keeper.slashRedelegation(ctx, validator, rd, 0, fraction) - require.Equal(t, int64(5), slashAmount.Int64()) - rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) - require.True(t, found) - require.Len(t, rd.Entries, 1) - - // end block - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 1, len(updates)) - - // initialbalance unchanged - require.Equal(t, sdk.NewInt(10), rd.Entries[0].InitialBalance) - - // shares decreased - del, found = keeper.GetDelegation(ctx, addrDels[0], addrVals[1]) - require.True(t, found) - require.Equal(t, int64(5), del.Shares.RoundInt64()) - - // pool bonded tokens should decrease - burnedCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), slashAmount)) - require.Equal(t, balances.Sub(burnedCoins), keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress())) -} - -// tests Slash at a future height (must panic) -func TestSlashAtFutureHeight(t *testing.T) { - ctx, keeper, _ := setupHelper(t, 10) - consAddr := sdk.ConsAddress(PKs[0].Address()) - fraction := sdk.NewDecWithPrec(5, 1) - require.Panics(t, func() { keeper.Slash(ctx, consAddr, 1, 10, fraction) }) -} - -// test slash at a negative height -// this just represents pre-genesis and should have the same effect as slashing at height 0 -func TestSlashAtNegativeHeight(t *testing.T) { - ctx, keeper, _ := setupHelper(t, 10) - consAddr := sdk.ConsAddress(PKs[0].Address()) - fraction := sdk.NewDecWithPrec(5, 1) - - bondedPool := keeper.GetBondedPool(ctx) - oldBondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) - - validator, found := keeper.GetValidatorByConsAddr(ctx, consAddr) - require.True(t, found) - keeper.Slash(ctx, consAddr, -2, 10, fraction) - - // read updated state - validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) - require.True(t, found) - - // end block - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 1, len(updates), "cons addr: %v, updates: %v", []byte(consAddr), updates) - - validator = keeper.mustGetValidator(ctx, validator.OperatorAddress) - // power decreased - require.Equal(t, int64(5), validator.GetConsensusPower()) - - // pool bonded shares decreased - newBondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) - diffTokens := oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(keeper.BondDenom(ctx)) - require.Equal(t, sdk.TokensFromConsensusPower(5).String(), diffTokens.String()) -} - -// tests Slash at the current height -func TestSlashValidatorAtCurrentHeight(t *testing.T) { - ctx, keeper, _ := setupHelper(t, 10) - consAddr := sdk.ConsAddress(PKs[0].Address()) - fraction := sdk.NewDecWithPrec(5, 1) - - bondedPool := keeper.GetBondedPool(ctx) - oldBondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) - - validator, found := keeper.GetValidatorByConsAddr(ctx, consAddr) - require.True(t, found) - keeper.Slash(ctx, consAddr, ctx.BlockHeight(), 10, fraction) - - // read updated state - validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) - require.True(t, found) - - // end block - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 1, len(updates), "cons addr: %v, updates: %v", []byte(consAddr), updates) - - validator = keeper.mustGetValidator(ctx, validator.OperatorAddress) - // power decreased - require.Equal(t, int64(5), validator.GetConsensusPower()) - - // pool bonded shares decreased - newBondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) - diffTokens := oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(keeper.BondDenom(ctx)) - require.Equal(t, sdk.TokensFromConsensusPower(5).String(), diffTokens.String()) -} - -// tests Slash at a previous height with an unbonding delegation -func TestSlashWithUnbondingDelegation(t *testing.T) { - ctx, keeper, _ := setupHelper(t, 10) - consAddr := sdk.ConsAddress(PKs[0].Address()) - fraction := sdk.NewDecWithPrec(5, 1) - - // set an unbonding delegation with expiration timestamp beyond which the - // unbonding delegation shouldn't be slashed - ubdTokens := sdk.TokensFromConsensusPower(4) - ubd := types.NewUnbondingDelegation(addrDels[0], addrVals[0], 11, - time.Unix(0, 0), ubdTokens) - keeper.SetUnbondingDelegation(ctx, ubd) - - // slash validator for the first time - ctx = ctx.WithBlockHeight(12) - bondedPool := keeper.GetBondedPool(ctx) - oldBondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) - - validator, found := keeper.GetValidatorByConsAddr(ctx, consAddr) - require.True(t, found) - keeper.Slash(ctx, consAddr, 10, 10, fraction) - - // end block - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 1, len(updates)) - - // read updating unbonding delegation - ubd, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) - require.True(t, found) - require.Len(t, ubd.Entries, 1) - - // balance decreased - require.Equal(t, sdk.TokensFromConsensusPower(2), ubd.Entries[0].Balance) - - // bonded tokens burned - newBondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) - diffTokens := oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(keeper.BondDenom(ctx)) - require.Equal(t, sdk.TokensFromConsensusPower(3), diffTokens) - - // read updated validator - validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) - require.True(t, found) - - // power decreased by 3 - 6 stake originally bonded at the time of infraction - // was still bonded at the time of discovery and was slashed by half, 4 stake - // bonded at the time of discovery hadn't been bonded at the time of infraction - // and wasn't slashed - require.Equal(t, int64(7), validator.GetConsensusPower()) - - // slash validator again - ctx = ctx.WithBlockHeight(13) - keeper.Slash(ctx, consAddr, 9, 10, fraction) - - ubd, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) - require.True(t, found) - require.Len(t, ubd.Entries, 1) - - // balance decreased again - require.Equal(t, sdk.NewInt(0), ubd.Entries[0].Balance) - - // bonded tokens burned again - newBondedPoolBalances = keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) - diffTokens = oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(keeper.BondDenom(ctx)) - require.Equal(t, sdk.TokensFromConsensusPower(6), diffTokens) - - // read updated validator - validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) - require.True(t, found) - - // power decreased by 3 again - require.Equal(t, int64(4), validator.GetConsensusPower()) - - // slash validator again - // all originally bonded stake has been slashed, so this will have no effect - // on the unbonding delegation, but it will slash stake bonded since the infraction - // this may not be the desirable behaviour, ref https://github.com/cosmos/cosmos-sdk/issues/1440 - ctx = ctx.WithBlockHeight(13) - keeper.Slash(ctx, consAddr, 9, 10, fraction) - - ubd, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) - require.True(t, found) - require.Len(t, ubd.Entries, 1) - - // balance unchanged - require.Equal(t, sdk.NewInt(0), ubd.Entries[0].Balance) - - // bonded tokens burned again - newBondedPoolBalances = keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) - diffTokens = oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(keeper.BondDenom(ctx)) - require.Equal(t, sdk.TokensFromConsensusPower(9), diffTokens) - - // read updated validator - validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) - require.True(t, found) - - // power decreased by 3 again - require.Equal(t, int64(1), validator.GetConsensusPower()) - - // slash validator again - // all originally bonded stake has been slashed, so this will have no effect - // on the unbonding delegation, but it will slash stake bonded since the infraction - // this may not be the desirable behaviour, ref https://github.com/cosmos/cosmos-sdk/issues/1440 - ctx = ctx.WithBlockHeight(13) - keeper.Slash(ctx, consAddr, 9, 10, fraction) - - ubd, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) - require.True(t, found) - require.Len(t, ubd.Entries, 1) - - // balance unchanged - require.Equal(t, sdk.NewInt(0), ubd.Entries[0].Balance) - - // just 1 bonded token burned again since that's all the validator now has - newBondedPoolBalances = keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) - diffTokens = oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(keeper.BondDenom(ctx)) - require.Equal(t, sdk.TokensFromConsensusPower(10), diffTokens) - - // apply TM updates - keeper.ApplyAndReturnValidatorSetUpdates(ctx) - - // read updated validator - // power decreased by 1 again, validator is out of stake - // validator should be in unbonding period - validator, _ = keeper.GetValidatorByConsAddr(ctx, consAddr) - require.Equal(t, validator.GetStatus(), sdk.Unbonding) -} - -// tests Slash at a previous height with a redelegation -func TestSlashWithRedelegation(t *testing.T) { - ctx, keeper, _ := setupHelper(t, 10) - consAddr := sdk.ConsAddress(PKs[0].Address()) - fraction := sdk.NewDecWithPrec(5, 1) - bondDenom := keeper.BondDenom(ctx) - - // set a redelegation - rdTokens := sdk.TokensFromConsensusPower(6) - rd := types.NewRedelegation(addrDels[0], addrVals[0], addrVals[1], 11, - time.Unix(0, 0), rdTokens, rdTokens.ToDec()) - keeper.SetRedelegation(ctx, rd) - - // set the associated delegation - del := types.NewDelegation(addrDels[0], addrVals[1], rdTokens.ToDec()) - keeper.SetDelegation(ctx, del) - - // update bonded tokens - bondedPool := keeper.GetBondedPool(ctx) - notBondedPool := keeper.GetNotBondedPool(ctx) - rdCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, rdTokens.MulRaw(2))) - - balances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) - err := keeper.bankKeeper.SetBalances(ctx, bondedPool.GetAddress(), balances.Add(rdCoins...)) - require.NoError(t, err) - - keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) - - oldBonded := keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount - oldNotBonded := keeper.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount - - // slash validator - ctx = ctx.WithBlockHeight(12) - validator, found := keeper.GetValidatorByConsAddr(ctx, consAddr) - require.True(t, found) - - require.NotPanics(t, func() { keeper.Slash(ctx, consAddr, 10, 10, fraction) }) - burnAmount := sdk.TokensFromConsensusPower(10).ToDec().Mul(fraction).TruncateInt() - - bondedPool = keeper.GetBondedPool(ctx) - notBondedPool = keeper.GetNotBondedPool(ctx) - - // burn bonded tokens from only from delegations - bondedPoolBalance := keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount - require.True(sdk.IntEq(t, oldBonded.Sub(burnAmount), bondedPoolBalance)) - - notBondedPoolBalance := keeper.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount - require.True(sdk.IntEq(t, oldNotBonded, notBondedPoolBalance)) - oldBonded = keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount - - // read updating redelegation - rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) - require.True(t, found) - require.Len(t, rd.Entries, 1) - // read updated validator - validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) - require.True(t, found) - // power decreased by 2 - 4 stake originally bonded at the time of infraction - // was still bonded at the time of discovery and was slashed by half, 4 stake - // bonded at the time of discovery hadn't been bonded at the time of infraction - // and wasn't slashed - require.Equal(t, int64(8), validator.GetConsensusPower()) - - // slash the validator again - validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) - require.True(t, found) - - require.NotPanics(t, func() { keeper.Slash(ctx, consAddr, 10, 10, sdk.OneDec()) }) - burnAmount = sdk.TokensFromConsensusPower(7) - - // read updated pool - bondedPool = keeper.GetBondedPool(ctx) - notBondedPool = keeper.GetNotBondedPool(ctx) - - // seven bonded tokens burned - bondedPoolBalance = keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount - require.True(sdk.IntEq(t, oldBonded.Sub(burnAmount), bondedPoolBalance)) - require.True(sdk.IntEq(t, oldNotBonded, notBondedPoolBalance)) - - bondedPoolBalance = keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount - require.True(sdk.IntEq(t, oldBonded.Sub(burnAmount), bondedPoolBalance)) - - notBondedPoolBalance = keeper.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount - require.True(sdk.IntEq(t, oldNotBonded, notBondedPoolBalance)) - oldBonded = keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount - - // read updating redelegation - rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) - require.True(t, found) - require.Len(t, rd.Entries, 1) - // read updated validator - validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) - require.True(t, found) - // power decreased by 4 - require.Equal(t, int64(4), validator.GetConsensusPower()) - - // slash the validator again, by 100% - ctx = ctx.WithBlockHeight(12) - validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) - require.True(t, found) - - require.NotPanics(t, func() { keeper.Slash(ctx, consAddr, 10, 10, sdk.OneDec()) }) - - burnAmount = sdk.TokensFromConsensusPower(10).ToDec().Mul(sdk.OneDec()).TruncateInt() - burnAmount = burnAmount.Sub(sdk.OneDec().MulInt(rdTokens).TruncateInt()) - - // read updated pool - bondedPool = keeper.GetBondedPool(ctx) - notBondedPool = keeper.GetNotBondedPool(ctx) - - bondedPoolBalance = keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount - require.True(sdk.IntEq(t, oldBonded.Sub(burnAmount), bondedPoolBalance)) - notBondedPoolBalance = keeper.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount - require.True(sdk.IntEq(t, oldNotBonded, notBondedPoolBalance)) - oldBonded = keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount - - // read updating redelegation - rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) - require.True(t, found) - require.Len(t, rd.Entries, 1) - // apply TM updates - keeper.ApplyAndReturnValidatorSetUpdates(ctx) - // read updated validator - // validator decreased to zero power, should be in unbonding period - validator, _ = keeper.GetValidatorByConsAddr(ctx, consAddr) - require.Equal(t, validator.GetStatus(), sdk.Unbonding) - - // slash the validator again, by 100% - // no stake remains to be slashed - ctx = ctx.WithBlockHeight(12) - // validator still in unbonding period - validator, _ = keeper.GetValidatorByConsAddr(ctx, consAddr) - require.Equal(t, validator.GetStatus(), sdk.Unbonding) - - require.NotPanics(t, func() { keeper.Slash(ctx, consAddr, 10, 10, sdk.OneDec()) }) - - // read updated pool - bondedPool = keeper.GetBondedPool(ctx) - notBondedPool = keeper.GetNotBondedPool(ctx) - - bondedPoolBalance = keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount - require.True(sdk.IntEq(t, oldBonded, bondedPoolBalance)) - notBondedPoolBalance = keeper.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount - require.True(sdk.IntEq(t, oldNotBonded, notBondedPoolBalance)) - - // read updating redelegation - rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) - require.True(t, found) - require.Len(t, rd.Entries, 1) - // read updated validator - // power still zero, still in unbonding period - validator, _ = keeper.GetValidatorByConsAddr(ctx, consAddr) - require.Equal(t, validator.GetStatus(), sdk.Unbonding) -} - -// tests Slash at a previous height with both an unbonding delegation and a redelegation -func TestSlashBoth(t *testing.T) { - ctx, keeper, _ := setupHelper(t, 10) - fraction := sdk.NewDecWithPrec(5, 1) - bondDenom := keeper.BondDenom(ctx) - - // set a redelegation with expiration timestamp beyond which the - // redelegation shouldn't be slashed - rdATokens := sdk.TokensFromConsensusPower(6) - rdA := types.NewRedelegation(addrDels[0], addrVals[0], addrVals[1], 11, - time.Unix(0, 0), rdATokens, - rdATokens.ToDec()) - keeper.SetRedelegation(ctx, rdA) - - // set the associated delegation - delA := types.NewDelegation(addrDels[0], addrVals[1], rdATokens.ToDec()) - keeper.SetDelegation(ctx, delA) - - // set an unbonding delegation with expiration timestamp (beyond which the - // unbonding delegation shouldn't be slashed) - ubdATokens := sdk.TokensFromConsensusPower(4) - ubdA := types.NewUnbondingDelegation(addrDels[0], addrVals[0], 11, - time.Unix(0, 0), ubdATokens) - keeper.SetUnbondingDelegation(ctx, ubdA) - - bondedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, rdATokens.MulRaw(2))) - notBondedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, ubdATokens)) - - // update bonded tokens - bondedPool := keeper.GetBondedPool(ctx) - notBondedPool := keeper.GetNotBondedPool(ctx) - - bondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) - require.NoError(t, keeper.bankKeeper.SetBalances(ctx, bondedPool.GetAddress(), bondedPoolBalances.Add(bondedCoins...))) - - notBondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) - require.NoError(t, keeper.bankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), notBondedPoolBalances.Add(notBondedCoins...))) - - keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) - keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) - - oldBonded := keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount - oldNotBonded := keeper.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount - // slash validator - ctx = ctx.WithBlockHeight(12) - validator, found := keeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(PKs[0])) - require.True(t, found) - consAddr0 := sdk.ConsAddress(PKs[0].Address()) - keeper.Slash(ctx, consAddr0, 10, 10, fraction) - - burnedNotBondedAmount := fraction.MulInt(ubdATokens).TruncateInt() - burnedBondAmount := sdk.TokensFromConsensusPower(10).ToDec().Mul(fraction).TruncateInt() - burnedBondAmount = burnedBondAmount.Sub(burnedNotBondedAmount) - - // read updated pool - bondedPool = keeper.GetBondedPool(ctx) - notBondedPool = keeper.GetNotBondedPool(ctx) - - bondedPoolBalance := keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount - require.True(sdk.IntEq(t, oldBonded.Sub(burnedBondAmount), bondedPoolBalance)) - - notBondedPoolBalance := keeper.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount - require.True(sdk.IntEq(t, oldNotBonded.Sub(burnedNotBondedAmount), notBondedPoolBalance)) - - // read updating redelegation - rdA, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) - require.True(t, found) - require.Len(t, rdA.Entries, 1) - // read updated validator - validator, found = keeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(PKs[0])) - require.True(t, found) - // power not decreased, all stake was bonded since - require.Equal(t, int64(10), validator.GetConsensusPower()) -} From df650166940e8f67ead11927d752e117a87848aa Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Mon, 24 Feb 2020 12:14:19 -0500 Subject: [PATCH 193/529] Merge PR #5659: Migrate upgrade module to protobuf --- CHANGELOG.md | 4 + simapp/app.go | 2 +- x/upgrade/alias.go | 4 +- x/upgrade/client/cli/query.go | 10 +- x/upgrade/client/cli/tx.go | 8 +- x/upgrade/client/rest/query.go | 10 +- x/upgrade/client/rest/tx.go | 2 +- x/upgrade/{internal => }/keeper/keeper.go | 8 +- x/upgrade/{internal => }/keeper/querier.go | 2 +- x/upgrade/{internal => }/types/codec.go | 0 x/upgrade/{internal => }/types/handler.go | 0 x/upgrade/{internal => }/types/keys.go | 0 x/upgrade/{internal => }/types/plan.go | 22 - x/upgrade/{internal => }/types/plan_test.go | 0 x/upgrade/{internal => }/types/proposal.go | 13 - .../{internal => }/types/proposal_test.go | 0 x/upgrade/{internal => }/types/querier.go | 0 x/upgrade/types/types.pb.go | 922 ++++++++++++++++++ x/upgrade/types/types.proto | 44 + 19 files changed, 993 insertions(+), 58 deletions(-) rename x/upgrade/{internal => }/keeper/keeper.go (96%) rename x/upgrade/{internal => }/keeper/querier.go (96%) rename x/upgrade/{internal => }/types/codec.go (100%) rename x/upgrade/{internal => }/types/handler.go (100%) rename x/upgrade/{internal => }/types/keys.go (100%) rename x/upgrade/{internal => }/types/plan.go (56%) rename x/upgrade/{internal => }/types/plan_test.go (100%) rename x/upgrade/{internal => }/types/proposal.go (84%) rename x/upgrade/{internal => }/types/proposal_test.go (100%) rename x/upgrade/{internal => }/types/querier.go (100%) create mode 100644 x/upgrade/types/types.pb.go create mode 100644 x/upgrade/types/types.proto diff --git a/CHANGELOG.md b/CHANGELOG.md index fa07e0f77e0a..7e9979d32608 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -126,6 +126,10 @@ serialization instead of Amino. * The `MsgSubmitEvidence` message has been removed in favor of `MsgSubmitEvidenceBase`. The application-level codec must now define the concrete `MsgSubmitEvidence` type which must implement the module's `MsgSubmitEvidence` interface. +* (x/upgrade) [\#5659](https://github.com/cosmos/cosmos-sdk/pull/5659) Migrate the `x/upgrade` module to use Protocol +Buffers for state serialization instead of Amino. + * The `internal` sub-package has been removed in order to expose the types proto file. + * The `x/upgrade` module now accepts a `codec.Marshaler` interface. ### Improvements diff --git a/simapp/app.go b/simapp/app.go index fd8bfbb4029e..e7253c9a7874 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -189,7 +189,7 @@ func NewSimApp( app.CrisisKeeper = crisis.NewKeeper( app.subspaces[crisis.ModuleName], invCheckPeriod, app.SupplyKeeper, auth.FeeCollectorName, ) - app.UpgradeKeeper = upgrade.NewKeeper(skipUpgradeHeights, keys[upgrade.StoreKey], app.cdc) + app.UpgradeKeeper = upgrade.NewKeeper(skipUpgradeHeights, keys[upgrade.StoreKey], appCodec) // create evidence keeper with router evidenceKeeper := evidence.NewKeeper( diff --git a/x/upgrade/alias.go b/x/upgrade/alias.go index d8089d35d543..c8ae7bf63157 100644 --- a/x/upgrade/alias.go +++ b/x/upgrade/alias.go @@ -3,8 +3,8 @@ package upgrade // nolint import ( - "github.com/cosmos/cosmos-sdk/x/upgrade/internal/keeper" - "github.com/cosmos/cosmos-sdk/x/upgrade/internal/types" + "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" + "github.com/cosmos/cosmos-sdk/x/upgrade/types" ) const ( diff --git a/x/upgrade/client/cli/query.go b/x/upgrade/client/cli/query.go index 0b33a012071f..c9022a4824bd 100644 --- a/x/upgrade/client/cli/query.go +++ b/x/upgrade/client/cli/query.go @@ -3,12 +3,12 @@ package cli import ( "encoding/binary" "fmt" + "github.com/cosmos/cosmos-sdk/x/upgrade/types" "github.com/spf13/cobra" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/codec" - upgrade "github.com/cosmos/cosmos-sdk/x/upgrade/internal/types" ) // GetPlanCmd returns the query upgrade plan command @@ -22,7 +22,7 @@ func GetPlanCmd(storeName string, cdc *codec.Codec) *cobra.Command { cliCtx := context.NewCLIContext().WithCodec(cdc) // ignore height for now - res, _, err := cliCtx.Query(fmt.Sprintf("custom/%s/%s", upgrade.QuerierKey, upgrade.QueryCurrent)) + res, _, err := cliCtx.Query(fmt.Sprintf("custom/%s/%s", types.QuerierKey, types.QueryCurrent)) if err != nil { return err } @@ -31,7 +31,7 @@ func GetPlanCmd(storeName string, cdc *codec.Codec) *cobra.Command { return fmt.Errorf("no upgrade scheduled") } - var plan upgrade.Plan + var plan types.Plan err = cdc.UnmarshalJSON(res, &plan) if err != nil { return err @@ -53,13 +53,13 @@ func GetAppliedHeightCmd(storeName string, cdc *codec.Codec) *cobra.Command { cliCtx := context.NewCLIContext().WithCodec(cdc) name := args[0] - params := upgrade.NewQueryAppliedParams(name) + params := types.NewQueryAppliedParams(name) bz, err := cliCtx.Codec.MarshalJSON(params) if err != nil { return err } - res, _, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/%s", upgrade.QuerierKey, upgrade.QueryApplied), bz) + res, _, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/%s", types.QuerierKey, types.QueryApplied), bz) if err != nil { return err } diff --git a/x/upgrade/client/cli/tx.go b/x/upgrade/client/cli/tx.go index a06347bc1def..6e325aa9c042 100644 --- a/x/upgrade/client/cli/tx.go +++ b/x/upgrade/client/cli/tx.go @@ -15,7 +15,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/gov" - upgrade "github.com/cosmos/cosmos-sdk/x/upgrade/internal/types" + "github.com/cosmos/cosmos-sdk/x/upgrade/types" ) const ( @@ -65,8 +65,8 @@ func parseArgsToContent(cmd *cobra.Command, name string) (gov.Content, error) { return nil, err } - plan := upgrade.Plan{Name: name, Time: upgradeTime, Height: height, Info: info} - content := upgrade.NewSoftwareUpgradeProposal(title, description, plan) + plan := types.Plan{Name: name, Time: upgradeTime, Height: height, Info: info} + content := types.NewSoftwareUpgradeProposal(title, description, plan) return content, nil } @@ -151,7 +151,7 @@ func GetCmdSubmitCancelUpgradeProposal(cdc *codec.Codec) *cobra.Command { return err } - content := upgrade.NewCancelSoftwareUpgradeProposal(title, description) + content := types.NewCancelSoftwareUpgradeProposal(title, description) msg := gov.NewMsgSubmitProposal(content, deposit, from) if err := msg.ValidateBasic(); err != nil { diff --git a/x/upgrade/client/rest/query.go b/x/upgrade/client/rest/query.go index bf9bdd341070..8c3372b2a7aa 100644 --- a/x/upgrade/client/rest/query.go +++ b/x/upgrade/client/rest/query.go @@ -9,7 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/types/rest" - upgrade "github.com/cosmos/cosmos-sdk/x/upgrade/internal/types" + "github.com/cosmos/cosmos-sdk/x/upgrade/types" ) // RegisterRoutes registers REST routes for the upgrade module under the path specified by routeName. @@ -22,7 +22,7 @@ func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router) { func getCurrentPlanHandler(cliCtx context.CLIContext) func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, request *http.Request) { // ignore height for now - res, _, err := cliCtx.Query(fmt.Sprintf("custom/%s/%s", upgrade.QuerierKey, upgrade.QueryCurrent)) + res, _, err := cliCtx.Query(fmt.Sprintf("custom/%s/%s", types.QuerierKey, types.QueryCurrent)) if err != nil { rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return @@ -32,7 +32,7 @@ func getCurrentPlanHandler(cliCtx context.CLIContext) func(http.ResponseWriter, return } - var plan upgrade.Plan + var plan types.Plan err = cliCtx.Codec.UnmarshalBinaryBare(res, &plan) if err != nil { rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) @@ -47,14 +47,14 @@ func getDonePlanHandler(cliCtx context.CLIContext) func(http.ResponseWriter, *ht return func(w http.ResponseWriter, r *http.Request) { name := mux.Vars(r)["name"] - params := upgrade.NewQueryAppliedParams(name) + params := types.NewQueryAppliedParams(name) bz, err := cliCtx.Codec.MarshalJSON(params) if err != nil { rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } - res, _, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/%s", upgrade.QuerierKey, upgrade.QueryApplied), bz) + res, _, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/%s", types.QuerierKey, types.QueryApplied), bz) if err != nil { rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return diff --git a/x/upgrade/client/rest/tx.go b/x/upgrade/client/rest/tx.go index 9354d9dd05a0..e67aa79bfc61 100644 --- a/x/upgrade/client/rest/tx.go +++ b/x/upgrade/client/rest/tx.go @@ -13,7 +13,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/rest" "github.com/cosmos/cosmos-sdk/x/gov" - "github.com/cosmos/cosmos-sdk/x/upgrade/internal/types" + "github.com/cosmos/cosmos-sdk/x/upgrade/types" ) func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router) { diff --git a/x/upgrade/internal/keeper/keeper.go b/x/upgrade/keeper/keeper.go similarity index 96% rename from x/upgrade/internal/keeper/keeper.go rename to x/upgrade/keeper/keeper.go index 7a33d7e4b66c..03802b335c5d 100644 --- a/x/upgrade/internal/keeper/keeper.go +++ b/x/upgrade/keeper/keeper.go @@ -3,6 +3,7 @@ package keeper import ( "encoding/binary" "fmt" + "github.com/cosmos/cosmos-sdk/x/upgrade/types" "github.com/tendermint/tendermint/libs/log" @@ -10,18 +11,17 @@ import ( "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/cosmos-sdk/x/upgrade/internal/types" ) type Keeper struct { skipUpgradeHeights map[int64]bool storeKey sdk.StoreKey - cdc *codec.Codec + cdc codec.Marshaler upgradeHandlers map[string]types.UpgradeHandler } // NewKeeper constructs an upgrade Keeper -func NewKeeper(skipUpgradeHeights map[int64]bool, storeKey sdk.StoreKey, cdc *codec.Codec) Keeper { +func NewKeeper(skipUpgradeHeights map[int64]bool, storeKey sdk.StoreKey, cdc codec.Marshaler) Keeper { return Keeper{ skipUpgradeHeights: skipUpgradeHeights, storeKey: storeKey, @@ -57,7 +57,7 @@ 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) + bz := k.cdc.MustMarshalBinaryBare(&plan) store := ctx.KVStore(k.storeKey) store.Set(types.PlanKey(), bz) diff --git a/x/upgrade/internal/keeper/querier.go b/x/upgrade/keeper/querier.go similarity index 96% rename from x/upgrade/internal/keeper/querier.go rename to x/upgrade/keeper/querier.go index 7bddfad34566..2a3ff8bf6dff 100644 --- a/x/upgrade/internal/keeper/querier.go +++ b/x/upgrade/keeper/querier.go @@ -2,12 +2,12 @@ package keeper import ( "encoding/binary" + "github.com/cosmos/cosmos-sdk/x/upgrade/types" abci "github.com/tendermint/tendermint/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/cosmos-sdk/x/upgrade/internal/types" ) // NewQuerier creates a querier for upgrade cli and REST endpoints diff --git a/x/upgrade/internal/types/codec.go b/x/upgrade/types/codec.go similarity index 100% rename from x/upgrade/internal/types/codec.go rename to x/upgrade/types/codec.go diff --git a/x/upgrade/internal/types/handler.go b/x/upgrade/types/handler.go similarity index 100% rename from x/upgrade/internal/types/handler.go rename to x/upgrade/types/handler.go diff --git a/x/upgrade/internal/types/keys.go b/x/upgrade/types/keys.go similarity index 100% rename from x/upgrade/internal/types/keys.go rename to x/upgrade/types/keys.go diff --git a/x/upgrade/internal/types/plan.go b/x/upgrade/types/plan.go similarity index 56% rename from x/upgrade/internal/types/plan.go rename to x/upgrade/types/plan.go index c2b88171e218..4f31063bc7bb 100644 --- a/x/upgrade/internal/types/plan.go +++ b/x/upgrade/types/plan.go @@ -9,28 +9,6 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) -// Plan specifies information about a planned upgrade and when it should occur -type Plan struct { - // Sets the name for the upgrade. This name will be used by the upgraded version of the software to apply any - // special "on-upgrade" commands during the first BeginBlock method after the upgrade is applied. It is also used - // to detect whether a software version can handle a given upgrade. If no upgrade handler with this name has been - // set in the software, it will be assumed that the software is out-of-date when the upgrade Time or Height - // is reached and the software will exit. - Name string `json:"name,omitempty"` - - // The time after which the upgrade must be performed. - // Leave set to its zero value to use a pre-defined Height instead. - Time time.Time `json:"time,omitempty"` - - // The height at which the upgrade must be performed. - // Only used if Time is not set. - Height int64 `json:"height,omitempty"` - - // Any application specific upgrade info to be included on-chain - // such as a git commit that validators could automatically upgrade to - Info string `json:"info,omitempty"` -} - func (p Plan) String() string { due := p.DueAt() dueUp := strings.ToUpper(due[0:1]) + due[1:] diff --git a/x/upgrade/internal/types/plan_test.go b/x/upgrade/types/plan_test.go similarity index 100% rename from x/upgrade/internal/types/plan_test.go rename to x/upgrade/types/plan_test.go diff --git a/x/upgrade/internal/types/proposal.go b/x/upgrade/types/proposal.go similarity index 84% rename from x/upgrade/internal/types/proposal.go rename to x/upgrade/types/proposal.go index 958c10674645..2067110e74e1 100644 --- a/x/upgrade/internal/types/proposal.go +++ b/x/upgrade/types/proposal.go @@ -11,13 +11,6 @@ const ( ProposalTypeCancelSoftwareUpgrade string = "CancelSoftwareUpgrade" ) -// Software Upgrade Proposals -type SoftwareUpgradeProposal struct { - Title string `json:"title" yaml:"title"` - Description string `json:"description" yaml:"description"` - Plan Plan `json:"plan" yaml:"plan"` -} - func NewSoftwareUpgradeProposal(title, description string, plan Plan) gov.Content { return SoftwareUpgradeProposal{title, description, plan} } @@ -51,12 +44,6 @@ func (sup SoftwareUpgradeProposal) String() string { `, sup.Title, sup.Description) } -// Cancel Software Upgrade Proposals -type CancelSoftwareUpgradeProposal struct { - Title string `json:"title" yaml:"title"` - Description string `json:"description" yaml:"description"` -} - func NewCancelSoftwareUpgradeProposal(title, description string) gov.Content { return CancelSoftwareUpgradeProposal{title, description} } diff --git a/x/upgrade/internal/types/proposal_test.go b/x/upgrade/types/proposal_test.go similarity index 100% rename from x/upgrade/internal/types/proposal_test.go rename to x/upgrade/types/proposal_test.go diff --git a/x/upgrade/internal/types/querier.go b/x/upgrade/types/querier.go similarity index 100% rename from x/upgrade/internal/types/querier.go rename to x/upgrade/types/querier.go diff --git a/x/upgrade/types/types.pb.go b/x/upgrade/types/types.pb.go new file mode 100644 index 000000000000..4e8f7cbb9895 --- /dev/null +++ b/x/upgrade/types/types.pb.go @@ -0,0 +1,922 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: x/upgrade/internal/types/types.proto + +package types + +import ( + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" + _ "github.com/golang/protobuf/ptypes/timestamp" + io "io" + math "math" + math_bits "math/bits" + time "time" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf +var _ = time.Kitchen + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// Plan specifies information about a planned upgrade and when it should occur +type Plan struct { + // Sets the name for the upgrade. This name will be used by the upgraded version of the software to apply any + // special "on-upgrade" commands during the first BeginBlock method after the upgrade is applied. It is also used + // to detect whether a software version can handle a given upgrade. If no upgrade handler with this name has been + // set in the software, it will be assumed that the software is out-of-date when the upgrade Time or Height + // is reached and the software will exit. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // The time after which the upgrade must be performed. + // Leave set to its zero value to use a pre-defined Height instead. + Time time.Time `protobuf:"bytes,2,opt,name=time,proto3,stdtime" json:"time"` + // The height at which the upgrade must be performed. + // Only used if Time is not set. + Height int64 `protobuf:"varint,3,opt,name=height,proto3" json:"height,omitempty"` + // 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"` +} + +func (m *Plan) Reset() { *m = Plan{} } +func (*Plan) ProtoMessage() {} +func (*Plan) Descriptor() ([]byte, []int) { + return fileDescriptor_6199ecc2c05edfcb, []int{0} +} +func (m *Plan) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Plan) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Plan.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 *Plan) XXX_Merge(src proto.Message) { + xxx_messageInfo_Plan.Merge(m, src) +} +func (m *Plan) XXX_Size() int { + return m.Size() +} +func (m *Plan) XXX_DiscardUnknown() { + xxx_messageInfo_Plan.DiscardUnknown(m) +} + +var xxx_messageInfo_Plan proto.InternalMessageInfo + +type SoftwareUpgradeProposal struct { + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` + Plan Plan `protobuf:"bytes,3,opt,name=plan,proto3" json:"plan"` +} + +func (m *SoftwareUpgradeProposal) Reset() { *m = SoftwareUpgradeProposal{} } +func (*SoftwareUpgradeProposal) ProtoMessage() {} +func (*SoftwareUpgradeProposal) Descriptor() ([]byte, []int) { + return fileDescriptor_6199ecc2c05edfcb, []int{1} +} +func (m *SoftwareUpgradeProposal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *SoftwareUpgradeProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_SoftwareUpgradeProposal.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 *SoftwareUpgradeProposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_SoftwareUpgradeProposal.Merge(m, src) +} +func (m *SoftwareUpgradeProposal) XXX_Size() int { + return m.Size() +} +func (m *SoftwareUpgradeProposal) XXX_DiscardUnknown() { + xxx_messageInfo_SoftwareUpgradeProposal.DiscardUnknown(m) +} + +var xxx_messageInfo_SoftwareUpgradeProposal proto.InternalMessageInfo + +type CancelSoftwareUpgradeProposal struct { + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` +} + +func (m *CancelSoftwareUpgradeProposal) Reset() { *m = CancelSoftwareUpgradeProposal{} } +func (*CancelSoftwareUpgradeProposal) ProtoMessage() {} +func (*CancelSoftwareUpgradeProposal) Descriptor() ([]byte, []int) { + return fileDescriptor_6199ecc2c05edfcb, []int{2} +} +func (m *CancelSoftwareUpgradeProposal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CancelSoftwareUpgradeProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CancelSoftwareUpgradeProposal.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 *CancelSoftwareUpgradeProposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_CancelSoftwareUpgradeProposal.Merge(m, src) +} +func (m *CancelSoftwareUpgradeProposal) XXX_Size() int { + return m.Size() +} +func (m *CancelSoftwareUpgradeProposal) XXX_DiscardUnknown() { + xxx_messageInfo_CancelSoftwareUpgradeProposal.DiscardUnknown(m) +} + +var xxx_messageInfo_CancelSoftwareUpgradeProposal proto.InternalMessageInfo + +func init() { + proto.RegisterType((*Plan)(nil), "cosmos_sdk.x.upgrade.v1.Plan") + proto.RegisterType((*SoftwareUpgradeProposal)(nil), "cosmos_sdk.x.upgrade.v1.SoftwareUpgradeProposal") + proto.RegisterType((*CancelSoftwareUpgradeProposal)(nil), "cosmos_sdk.x.upgrade.v1.CancelSoftwareUpgradeProposal") +} + +func init() { + proto.RegisterFile("x/upgrade/internal/types/types.proto", fileDescriptor_6199ecc2c05edfcb) +} + +var fileDescriptor_6199ecc2c05edfcb = []byte{ + // 371 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x52, 0x3f, 0x0f, 0x12, 0x31, + 0x14, 0xbf, 0xca, 0x49, 0xa4, 0x6c, 0x8d, 0x91, 0x0b, 0x09, 0xe5, 0x42, 0x8c, 0x21, 0x31, 0xb6, + 0x11, 0x07, 0x9d, 0x71, 0x36, 0x21, 0xa7, 0xc6, 0xc4, 0x85, 0x94, 0xbb, 0x72, 0xd7, 0x70, 0xd7, + 0x36, 0x6d, 0x51, 0xd8, 0x9c, 0x9d, 0xf8, 0x58, 0x8c, 0x8c, 0x4c, 0x2a, 0xf0, 0x45, 0xcc, 0x5d, + 0x8f, 0xe8, 0xe2, 0xe6, 0xd2, 0xbe, 0xd7, 0xfc, 0xfe, 0xbd, 0xb6, 0xf0, 0xe9, 0x8e, 0x6e, 0x75, + 0x6e, 0x58, 0xc6, 0xa9, 0x90, 0x8e, 0x1b, 0xc9, 0x4a, 0xea, 0xf6, 0x9a, 0x5b, 0xbf, 0x12, 0x6d, + 0x94, 0x53, 0x68, 0x90, 0x2a, 0x5b, 0x29, 0xbb, 0xb4, 0xd9, 0x86, 0xec, 0x48, 0x4b, 0x20, 0x5f, + 0x5e, 0x0e, 0x9f, 0xb9, 0x42, 0x98, 0x6c, 0xa9, 0x99, 0x71, 0x7b, 0xda, 0x60, 0x69, 0xae, 0x72, + 0xf5, 0xa7, 0xf2, 0x02, 0xc3, 0x71, 0xae, 0x54, 0x5e, 0x72, 0x0f, 0x59, 0x6d, 0xd7, 0xd4, 0x89, + 0x8a, 0x5b, 0xc7, 0x2a, 0xed, 0x01, 0x93, 0x6f, 0x00, 0x86, 0x8b, 0x92, 0x49, 0x84, 0x60, 0x28, + 0x59, 0xc5, 0x23, 0x10, 0x83, 0x69, 0x2f, 0x69, 0x6a, 0xf4, 0x06, 0x86, 0x35, 0x3e, 0x7a, 0x10, + 0x83, 0x69, 0x7f, 0x36, 0x24, 0x5e, 0x8c, 0xdc, 0xc5, 0xc8, 0x87, 0xbb, 0xd8, 0xfc, 0xd1, 0xf1, + 0xc7, 0x38, 0x38, 0xfc, 0x1c, 0x83, 0xa4, 0x61, 0xa0, 0x27, 0xb0, 0x5b, 0x70, 0x91, 0x17, 0x2e, + 0xea, 0xc4, 0x60, 0xda, 0x49, 0xda, 0xae, 0x76, 0x11, 0x72, 0xad, 0xa2, 0xd0, 0xbb, 0xd4, 0xf5, + 0xe4, 0x3b, 0x80, 0x83, 0xf7, 0x6a, 0xed, 0xbe, 0x32, 0xc3, 0x3f, 0xfa, 0x11, 0x17, 0x46, 0x69, + 0x65, 0x59, 0x89, 0x1e, 0xc3, 0x87, 0x4e, 0xb8, 0xf2, 0x1e, 0xcb, 0x37, 0x28, 0x86, 0xfd, 0x8c, + 0xdb, 0xd4, 0x08, 0xed, 0x84, 0x92, 0x4d, 0xbc, 0x5e, 0xf2, 0xf7, 0x11, 0x7a, 0x0d, 0x43, 0x5d, + 0x32, 0xd9, 0xb8, 0xf7, 0x67, 0x23, 0xf2, 0x8f, 0x7b, 0x24, 0xf5, 0xe8, 0xf3, 0xb0, 0x0e, 0x9f, + 0x34, 0x84, 0xc9, 0x27, 0x38, 0x7a, 0xcb, 0x64, 0xca, 0xcb, 0xff, 0x9c, 0x68, 0xfe, 0xee, 0x78, + 0xc1, 0xc1, 0xf9, 0x82, 0x83, 0xe3, 0x15, 0x83, 0xd3, 0x15, 0x83, 0x5f, 0x57, 0x0c, 0x0e, 0x37, + 0x1c, 0x9c, 0x6e, 0x38, 0x38, 0xdf, 0x70, 0xf0, 0xf9, 0x79, 0x2e, 0x5c, 0xb1, 0x5d, 0x91, 0x54, + 0x55, 0xd4, 0xe7, 0x6d, 0xb7, 0x17, 0x36, 0xdb, 0xd0, 0x1d, 0xd5, 0xcc, 0xb0, 0xaa, 0xfd, 0x1f, + 0xab, 0x6e, 0xf3, 0x08, 0xaf, 0x7e, 0x07, 0x00, 0x00, 0xff, 0xff, 0xad, 0x67, 0xed, 0x35, 0x48, + 0x02, 0x00, 0x00, +} + +func (m *Plan) 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 *Plan) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Plan) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Info) > 0 { + i -= len(m.Info) + copy(dAtA[i:], m.Info) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Info))) + i-- + dAtA[i] = 0x22 + } + if m.Height != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.Height)) + 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 + } + i -= n1 + i = encodeVarintTypes(dAtA, i, uint64(n1)) + i-- + dAtA[i] = 0x12 + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *SoftwareUpgradeProposal) 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 *SoftwareUpgradeProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *SoftwareUpgradeProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Plan.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + if len(m.Description) > 0 { + i -= len(m.Description) + copy(dAtA[i:], m.Description) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Description))) + i-- + dAtA[i] = 0x12 + } + if len(m.Title) > 0 { + i -= len(m.Title) + copy(dAtA[i:], m.Title) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Title))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *CancelSoftwareUpgradeProposal) 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 *CancelSoftwareUpgradeProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CancelSoftwareUpgradeProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Description) > 0 { + i -= len(m.Description) + copy(dAtA[i:], m.Description) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Description))) + i-- + dAtA[i] = 0x12 + } + if len(m.Title) > 0 { + i -= len(m.Title) + copy(dAtA[i:], m.Title) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Title))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintTypes(dAtA []byte, offset int, v uint64) int { + offset -= sovTypes(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Plan) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.Time) + n += 1 + l + sovTypes(uint64(l)) + if m.Height != 0 { + n += 1 + sovTypes(uint64(m.Height)) + } + l = len(m.Info) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + +func (m *SoftwareUpgradeProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Title) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.Description) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = m.Plan.Size() + n += 1 + l + sovTypes(uint64(l)) + return n +} + +func (m *CancelSoftwareUpgradeProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Title) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.Description) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + +func sovTypes(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTypes(x uint64) (n int) { + return sovTypes(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Plan) 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 ErrIntOverflowTypes + } + 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: Plan: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Plan: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Time", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.Time, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Height", wireType) + } + m.Height = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Height |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Info", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Info = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *SoftwareUpgradeProposal) 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 ErrIntOverflowTypes + } + 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: SoftwareUpgradeProposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SoftwareUpgradeProposal: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Title", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Title = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Description = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Plan", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Plan.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *CancelSoftwareUpgradeProposal) 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 ErrIntOverflowTypes + } + 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: CancelSoftwareUpgradeProposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CancelSoftwareUpgradeProposal: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Title", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Title = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Description = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTypes(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthTypes + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTypes + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTypes + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTypes = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTypes = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTypes = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/upgrade/types/types.proto b/x/upgrade/types/types.proto new file mode 100644 index 000000000000..8770158c4bdb --- /dev/null +++ b/x/upgrade/types/types.proto @@ -0,0 +1,44 @@ +syntax = "proto3"; +package cosmos_sdk.x.upgrade.v1; + +import "third_party/proto/gogoproto/gogo.proto"; +import "google/protobuf/timestamp.proto"; + +option go_package = "github.com/cosmos/cosmos-sdk/x/upgrade/types"; +option (gogoproto.goproto_stringer_all) = false; +option (gogoproto.goproto_getters_all) = false; + +// Plan specifies information about a planned upgrade and when it should occur +message Plan { + // Sets the name for the upgrade. This name will be used by the upgraded version of the software to apply any + // special "on-upgrade" commands during the first BeginBlock method after the upgrade is applied. It is also used + // to detect whether a software version can handle a given upgrade. If no upgrade handler with this name has been + // set in the software, it will be assumed that the software is out-of-date when the upgrade Time or Height + // is reached and the software will exit. + string name = 1; + + // The time after which the upgrade must be performed. + // Leave set to its zero value to use a pre-defined Height instead. + google.protobuf.Timestamp time = 2 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false]; + + // The height at which the upgrade must be performed. + // Only used if Time is not set. + int64 height = 3; + + // Any application specific upgrade info to be included on-chain + // such as a git commit that validators could automatically upgrade to + string info = 4; +} + +// SoftwareUpgradeProposal is a gov Content type for initiating a software upgrade +message SoftwareUpgradeProposal { + string title = 1; + string description = 2; + Plan plan = 3 [(gogoproto.nullable) = false]; +} + +// SoftwareUpgradeProposal is a gov Content type for cancelling a software upgrade +message CancelSoftwareUpgradeProposal { + string title = 1; + string description = 2; +} From a34575a8bbdf0ca4e4464364e22929375d51fbeb Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 24 Feb 2020 18:30:30 +0100 Subject: [PATCH 194/529] fix TestSlashUnbondingDelegation test to use simapp --- x/staking/keeper/old_slash_test.go | 43 -------------------- x/staking/keeper/slash.go | 4 +- x/staking/keeper/slash_test.go | 64 ++++++++++++++++++++++++++---- 3 files changed, 58 insertions(+), 53 deletions(-) diff --git a/x/staking/keeper/old_slash_test.go b/x/staking/keeper/old_slash_test.go index f6b442dc3c18..66023db24df2 100644 --- a/x/staking/keeper/old_slash_test.go +++ b/x/staking/keeper/old_slash_test.go @@ -39,49 +39,6 @@ func setupHelper(t *testing.T, power int64) (sdk.Context, Keeper, types.Params) //_________________________________________________________________________________ -// tests slashUnbondingDelegation -func TestSlashUnbondingDelegation(t *testing.T) { - ctx, keeper, _ := setupHelper(t, 10) - fraction := sdk.NewDecWithPrec(5, 1) - - // set an unbonding delegation with expiration timestamp (beyond which the - // unbonding delegation shouldn't be slashed) - ubd := types.NewUnbondingDelegation(addrDels[0], addrVals[0], 0, - time.Unix(5, 0), sdk.NewInt(10)) - - keeper.SetUnbondingDelegation(ctx, ubd) - - // unbonding started prior to the infraction height, stakw didn't contribute - slashAmount := keeper.slashUnbondingDelegation(ctx, ubd, 1, fraction) - require.Equal(t, int64(0), slashAmount.Int64()) - - // after the expiration time, no longer eligible for slashing - ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(10, 0)}) - keeper.SetUnbondingDelegation(ctx, ubd) - slashAmount = keeper.slashUnbondingDelegation(ctx, ubd, 0, fraction) - require.Equal(t, int64(0), slashAmount.Int64()) - - // test valid slash, before expiration timestamp and to which stake contributed - notBondedPool := keeper.GetNotBondedPool(ctx) - oldUnbondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) - ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(0, 0)}) - keeper.SetUnbondingDelegation(ctx, ubd) - slashAmount = keeper.slashUnbondingDelegation(ctx, ubd, 0, fraction) - require.Equal(t, int64(5), slashAmount.Int64()) - ubd, found := keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) - require.True(t, found) - require.Len(t, ubd.Entries, 1) - - // initial balance unchanged - require.Equal(t, sdk.NewInt(10), ubd.Entries[0].InitialBalance) - - // balance decreased - require.Equal(t, sdk.NewInt(5), ubd.Entries[0].Balance) - newUnbondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) - diffTokens := oldUnbondedPoolBalances.Sub(newUnbondedPoolBalances) - require.Equal(t, int64(5), diffTokens.AmountOf(keeper.BondDenom(ctx)).Int64()) -} - // tests slashRedelegation func TestSlashRedelegation(t *testing.T) { ctx, keeper, _ := setupHelper(t, 10) diff --git a/x/staking/keeper/slash.go b/x/staking/keeper/slash.go index 76db0c8e99ba..7f1bf5bba6bf 100644 --- a/x/staking/keeper/slash.go +++ b/x/staking/keeper/slash.go @@ -82,7 +82,7 @@ func (k Keeper) Slash(ctx sdk.Context, consAddr sdk.ConsAddress, infractionHeigh // Iterate through unbonding delegations from slashed validator unbondingDelegations := k.GetUnbondingDelegationsFromValidator(ctx, operatorAddress) for _, unbondingDelegation := range unbondingDelegations { - amountSlashed := k.slashUnbondingDelegation(ctx, unbondingDelegation, infractionHeight, slashFactor) + amountSlashed := k.SlashUnbondingDelegation(ctx, unbondingDelegation, infractionHeight, slashFactor) if amountSlashed.IsZero() { continue } @@ -160,7 +160,7 @@ func (k Keeper) Unjail(ctx sdk.Context, consAddr sdk.ConsAddress) { // the unbonding delegation had enough stake to slash // (the amount actually slashed may be less if there's // insufficient stake remaining) -func (k Keeper) slashUnbondingDelegation(ctx sdk.Context, unbondingDelegation types.UnbondingDelegation, +func (k Keeper) SlashUnbondingDelegation(ctx sdk.Context, unbondingDelegation types.UnbondingDelegation, infractionHeight int64, slashFactor sdk.Dec) (totalSlashAmount sdk.Int) { now := ctx.BlockHeader().Time diff --git a/x/staking/keeper/slash_test.go b/x/staking/keeper/slash_test.go index 3f88942a5c61..37c5c4ee2b4b 100644 --- a/x/staking/keeper/slash_test.go +++ b/x/staking/keeper/slash_test.go @@ -2,6 +2,9 @@ package keeper_test import ( "testing" + "time" + + abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" @@ -11,21 +14,22 @@ import ( ) // initConfig creates 3 validators and bootstrap the app. -func initConfig(t *testing.T) (*simapp.SimApp, sdk.Context, []sdk.ValAddress) { +func initConfig(t *testing.T, power int64) (*simapp.SimApp, sdk.Context, []sdk.AccAddress, []sdk.ValAddress) { _, app, ctx := getBaseSimappWithCustomKeeper() - addrDels := simapp.AddTestAddrsIncremental(app, ctx, 3, sdk.NewInt(10000)) + addrDels := simapp.AddTestAddrsIncremental(app, ctx, 100, sdk.NewInt(10000)) addrVals := simapp.ConvertAddrsToValAddrs(addrDels) - numVals := int64(3) - amt := sdk.TokensFromConsensusPower(10) - bondedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), amt.MulRaw(numVals))) + amt := sdk.TokensFromConsensusPower(power) + totalSupply := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), amt.MulRaw(int64(len(addrDels))))) notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) - err := app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), bondedCoins) + err := app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), totalSupply) require.NoError(t, err) app.SupplyKeeper.SetModuleAccount(ctx, notBondedPool) + numVals := int64(3) + bondedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), amt.MulRaw(numVals))) bondedPool := app.StakingKeeper.GetBondedPool(ctx) err = app.BankKeeper.SetBalances(ctx, bondedPool.GetAddress(), bondedCoins) require.NoError(t, err) @@ -38,12 +42,12 @@ func initConfig(t *testing.T) (*simapp.SimApp, sdk.Context, []sdk.ValAddress) { app.StakingKeeper.SetValidatorByConsAddr(ctx, validator) } - return app, ctx, addrVals + return app, ctx, addrDels, addrVals } // tests Jail, Unjail func TestRevocation(t *testing.T) { - app, ctx, addrVals := initConfig(t) + app, ctx, _, addrVals := initConfig(t, 5) consAddr := sdk.ConsAddress(PKs[0].Address()) @@ -64,3 +68,47 @@ func TestRevocation(t *testing.T) { require.True(t, found) require.False(t, val.IsJailed()) } + +// tests slashUnbondingDelegation +func TestSlashUnbondingDelegation(t *testing.T) { + app, ctx, addrDels, addrVals := initConfig(t, 10) + + fraction := sdk.NewDecWithPrec(5, 1) + + // set an unbonding delegation with expiration timestamp (beyond which the + // unbonding delegation shouldn't be slashed) + ubd := types.NewUnbondingDelegation(addrDels[0], addrVals[0], 0, + time.Unix(5, 0), sdk.NewInt(10)) + + app.StakingKeeper.SetUnbondingDelegation(ctx, ubd) + + // unbonding started prior to the infraction height, stakw didn't contribute + slashAmount := app.StakingKeeper.SlashUnbondingDelegation(ctx, ubd, 1, fraction) + require.Equal(t, int64(0), slashAmount.Int64()) + + // after the expiration time, no longer eligible for slashing + ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(10, 0)}) + app.StakingKeeper.SetUnbondingDelegation(ctx, ubd) + slashAmount = app.StakingKeeper.SlashUnbondingDelegation(ctx, ubd, 0, fraction) + require.Equal(t, int64(0), slashAmount.Int64()) + + // test valid slash, before expiration timestamp and to which stake contributed + notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) + oldUnbondedPoolBalances := app.BankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) + ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(0, 0)}) + app.StakingKeeper.SetUnbondingDelegation(ctx, ubd) + slashAmount = app.StakingKeeper.SlashUnbondingDelegation(ctx, ubd, 0, fraction) + require.Equal(t, int64(5), slashAmount.Int64()) + ubd, found := app.StakingKeeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) + require.True(t, found) + require.Len(t, ubd.Entries, 1) + + // initial balance unchanged + require.Equal(t, sdk.NewInt(10), ubd.Entries[0].InitialBalance) + + // balance decreased + require.Equal(t, sdk.NewInt(5), ubd.Entries[0].Balance) + newUnbondedPoolBalances := app.BankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) + diffTokens := oldUnbondedPoolBalances.Sub(newUnbondedPoolBalances) + require.Equal(t, int64(5), diffTokens.AmountOf(app.StakingKeeper.BondDenom(ctx)).Int64()) +} From 3ea53f56825e3522d2d5f02908118401897f0b15 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 24 Feb 2020 18:41:01 +0100 Subject: [PATCH 195/529] refactor TestSlashRedelegation to use simapp --- x/staking/keeper/old_slash_test.go | 70 ------------------------------ x/staking/keeper/slash.go | 4 +- x/staking/keeper/slash_test.go | 68 +++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 72 deletions(-) diff --git a/x/staking/keeper/old_slash_test.go b/x/staking/keeper/old_slash_test.go index 66023db24df2..bd311491b9f0 100644 --- a/x/staking/keeper/old_slash_test.go +++ b/x/staking/keeper/old_slash_test.go @@ -6,8 +6,6 @@ import ( "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/staking/types" ) @@ -39,74 +37,6 @@ func setupHelper(t *testing.T, power int64) (sdk.Context, Keeper, types.Params) //_________________________________________________________________________________ -// tests slashRedelegation -func TestSlashRedelegation(t *testing.T) { - ctx, keeper, _ := setupHelper(t, 10) - fraction := sdk.NewDecWithPrec(5, 1) - - // add bonded tokens to pool for (re)delegations - startCoins := sdk.NewCoins(sdk.NewInt64Coin(keeper.BondDenom(ctx), 15)) - bondedPool := keeper.GetBondedPool(ctx) - balances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) - - require.NoError(t, keeper.bankKeeper.SetBalances(ctx, bondedPool.GetAddress(), balances.Add(startCoins...))) - keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) - - // set a redelegation with an expiration timestamp beyond which the - // redelegation shouldn't be slashed - rd := types.NewRedelegation(addrDels[0], addrVals[0], addrVals[1], 0, - time.Unix(5, 0), sdk.NewInt(10), sdk.NewDec(10)) - - keeper.SetRedelegation(ctx, rd) - - // set the associated delegation - del := types.NewDelegation(addrDels[0], addrVals[1], sdk.NewDec(10)) - keeper.SetDelegation(ctx, del) - - // started redelegating prior to the current height, stake didn't contribute to infraction - validator, found := keeper.GetValidator(ctx, addrVals[1]) - require.True(t, found) - slashAmount := keeper.slashRedelegation(ctx, validator, rd, 1, fraction) - require.Equal(t, int64(0), slashAmount.Int64()) - - // after the expiration time, no longer eligible for slashing - ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(10, 0)}) - keeper.SetRedelegation(ctx, rd) - validator, found = keeper.GetValidator(ctx, addrVals[1]) - require.True(t, found) - slashAmount = keeper.slashRedelegation(ctx, validator, rd, 0, fraction) - require.Equal(t, int64(0), slashAmount.Int64()) - - balances = keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) - - // test valid slash, before expiration timestamp and to which stake contributed - ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(0, 0)}) - keeper.SetRedelegation(ctx, rd) - validator, found = keeper.GetValidator(ctx, addrVals[1]) - require.True(t, found) - slashAmount = keeper.slashRedelegation(ctx, validator, rd, 0, fraction) - require.Equal(t, int64(5), slashAmount.Int64()) - rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) - require.True(t, found) - require.Len(t, rd.Entries, 1) - - // end block - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 1, len(updates)) - - // initialbalance unchanged - require.Equal(t, sdk.NewInt(10), rd.Entries[0].InitialBalance) - - // shares decreased - del, found = keeper.GetDelegation(ctx, addrDels[0], addrVals[1]) - require.True(t, found) - require.Equal(t, int64(5), del.Shares.RoundInt64()) - - // pool bonded tokens should decrease - burnedCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), slashAmount)) - require.Equal(t, balances.Sub(burnedCoins), keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress())) -} - // tests Slash at a future height (must panic) func TestSlashAtFutureHeight(t *testing.T) { ctx, keeper, _ := setupHelper(t, 10) diff --git a/x/staking/keeper/slash.go b/x/staking/keeper/slash.go index 7f1bf5bba6bf..58e7ebee2bbe 100644 --- a/x/staking/keeper/slash.go +++ b/x/staking/keeper/slash.go @@ -92,7 +92,7 @@ func (k Keeper) Slash(ctx sdk.Context, consAddr sdk.ConsAddress, infractionHeigh // Iterate through redelegations from slashed source validator redelegations := k.GetRedelegationsFromSrcValidator(ctx, operatorAddress) for _, redelegation := range redelegations { - amountSlashed := k.slashRedelegation(ctx, validator, redelegation, infractionHeight, slashFactor) + amountSlashed := k.SlashRedelegation(ctx, validator, redelegation, infractionHeight, slashFactor) if amountSlashed.IsZero() { continue } @@ -215,7 +215,7 @@ func (k Keeper) SlashUnbondingDelegation(ctx sdk.Context, unbondingDelegation ty // (the amount actually slashed may be less if there's // insufficient stake remaining) // NOTE this is only slashing for prior infractions from the source validator -func (k Keeper) slashRedelegation(ctx sdk.Context, srcValidator types.Validator, redelegation types.Redelegation, +func (k Keeper) SlashRedelegation(ctx sdk.Context, srcValidator types.Validator, redelegation types.Redelegation, infractionHeight int64, slashFactor sdk.Dec) (totalSlashAmount sdk.Int) { now := ctx.BlockHeader().Time diff --git a/x/staking/keeper/slash_test.go b/x/staking/keeper/slash_test.go index 37c5c4ee2b4b..15d735bbe983 100644 --- a/x/staking/keeper/slash_test.go +++ b/x/staking/keeper/slash_test.go @@ -112,3 +112,71 @@ func TestSlashUnbondingDelegation(t *testing.T) { diffTokens := oldUnbondedPoolBalances.Sub(newUnbondedPoolBalances) require.Equal(t, int64(5), diffTokens.AmountOf(app.StakingKeeper.BondDenom(ctx)).Int64()) } + +// tests slashRedelegation +func TestSlashRedelegation(t *testing.T) { + app, ctx, addrDels, addrVals := initConfig(t, 10) + fraction := sdk.NewDecWithPrec(5, 1) + + // add bonded tokens to pool for (re)delegations + startCoins := sdk.NewCoins(sdk.NewInt64Coin(app.StakingKeeper.BondDenom(ctx), 15)) + bondedPool := app.StakingKeeper.GetBondedPool(ctx) + balances := app.BankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + + require.NoError(t, app.BankKeeper.SetBalances(ctx, bondedPool.GetAddress(), balances.Add(startCoins...))) + app.SupplyKeeper.SetModuleAccount(ctx, bondedPool) + + // set a redelegation with an expiration timestamp beyond which the + // redelegation shouldn't be slashed + rd := types.NewRedelegation(addrDels[0], addrVals[0], addrVals[1], 0, + time.Unix(5, 0), sdk.NewInt(10), sdk.NewDec(10)) + + app.StakingKeeper.SetRedelegation(ctx, rd) + + // set the associated delegation + del := types.NewDelegation(addrDels[0], addrVals[1], sdk.NewDec(10)) + app.StakingKeeper.SetDelegation(ctx, del) + + // started redelegating prior to the current height, stake didn't contribute to infraction + validator, found := app.StakingKeeper.GetValidator(ctx, addrVals[1]) + require.True(t, found) + slashAmount := app.StakingKeeper.SlashRedelegation(ctx, validator, rd, 1, fraction) + require.Equal(t, int64(0), slashAmount.Int64()) + + // after the expiration time, no longer eligible for slashing + ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(10, 0)}) + app.StakingKeeper.SetRedelegation(ctx, rd) + validator, found = app.StakingKeeper.GetValidator(ctx, addrVals[1]) + require.True(t, found) + slashAmount = app.StakingKeeper.SlashRedelegation(ctx, validator, rd, 0, fraction) + require.Equal(t, int64(0), slashAmount.Int64()) + + balances = app.BankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + + // test valid slash, before expiration timestamp and to which stake contributed + ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(0, 0)}) + app.StakingKeeper.SetRedelegation(ctx, rd) + validator, found = app.StakingKeeper.GetValidator(ctx, addrVals[1]) + require.True(t, found) + slashAmount = app.StakingKeeper.SlashRedelegation(ctx, validator, rd, 0, fraction) + require.Equal(t, int64(5), slashAmount.Int64()) + rd, found = app.StakingKeeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) + require.True(t, found) + require.Len(t, rd.Entries, 1) + + // end block + updates := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 1, len(updates)) + + // initialbalance unchanged + require.Equal(t, sdk.NewInt(10), rd.Entries[0].InitialBalance) + + // shares decreased + del, found = app.StakingKeeper.GetDelegation(ctx, addrDels[0], addrVals[1]) + require.True(t, found) + require.Equal(t, int64(5), del.Shares.RoundInt64()) + + // pool bonded tokens should decrease + burnedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), slashAmount)) + require.Equal(t, balances.Sub(burnedCoins), app.BankKeeper.GetAllBalances(ctx, bondedPool.GetAddress())) +} From 7ee50eacf2fee5494978b8bb316a70f37b2b8bda Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 24 Feb 2020 18:43:51 +0100 Subject: [PATCH 196/529] refactor TestSlashAtFutureHeight test --- x/staking/keeper/old_slash_test.go | 8 -------- x/staking/keeper/slash_test.go | 9 +++++++++ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/x/staking/keeper/old_slash_test.go b/x/staking/keeper/old_slash_test.go index bd311491b9f0..f59ad9f8037b 100644 --- a/x/staking/keeper/old_slash_test.go +++ b/x/staking/keeper/old_slash_test.go @@ -37,14 +37,6 @@ func setupHelper(t *testing.T, power int64) (sdk.Context, Keeper, types.Params) //_________________________________________________________________________________ -// tests Slash at a future height (must panic) -func TestSlashAtFutureHeight(t *testing.T) { - ctx, keeper, _ := setupHelper(t, 10) - consAddr := sdk.ConsAddress(PKs[0].Address()) - fraction := sdk.NewDecWithPrec(5, 1) - require.Panics(t, func() { keeper.Slash(ctx, consAddr, 1, 10, fraction) }) -} - // test slash at a negative height // this just represents pre-genesis and should have the same effect as slashing at height 0 func TestSlashAtNegativeHeight(t *testing.T) { diff --git a/x/staking/keeper/slash_test.go b/x/staking/keeper/slash_test.go index 15d735bbe983..3aed1a8e15d0 100644 --- a/x/staking/keeper/slash_test.go +++ b/x/staking/keeper/slash_test.go @@ -180,3 +180,12 @@ func TestSlashRedelegation(t *testing.T) { burnedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), slashAmount)) require.Equal(t, balances.Sub(burnedCoins), app.BankKeeper.GetAllBalances(ctx, bondedPool.GetAddress())) } + +// tests Slash at a future height (must panic) +func TestSlashAtFutureHeight(t *testing.T) { + app, ctx, _, _ := initConfig(t, 10) + + consAddr := sdk.ConsAddress(PKs[0].Address()) + fraction := sdk.NewDecWithPrec(5, 1) + require.Panics(t, func() { app.StakingKeeper.Slash(ctx, consAddr, 1, 10, fraction) }) +} From b36cdac3e3993069bf88ef594c99a52d4e17aabc Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 24 Feb 2020 19:01:55 +0100 Subject: [PATCH 197/529] test TestSlashAtNegativeHeight migrated to simapp --- x/staking/keeper/old_slash_test.go | 32 -------------------------- x/staking/keeper/slash_test.go | 37 ++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 32 deletions(-) diff --git a/x/staking/keeper/old_slash_test.go b/x/staking/keeper/old_slash_test.go index f59ad9f8037b..61fe22d04b9a 100644 --- a/x/staking/keeper/old_slash_test.go +++ b/x/staking/keeper/old_slash_test.go @@ -37,38 +37,6 @@ func setupHelper(t *testing.T, power int64) (sdk.Context, Keeper, types.Params) //_________________________________________________________________________________ -// test slash at a negative height -// this just represents pre-genesis and should have the same effect as slashing at height 0 -func TestSlashAtNegativeHeight(t *testing.T) { - ctx, keeper, _ := setupHelper(t, 10) - consAddr := sdk.ConsAddress(PKs[0].Address()) - fraction := sdk.NewDecWithPrec(5, 1) - - bondedPool := keeper.GetBondedPool(ctx) - oldBondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) - - validator, found := keeper.GetValidatorByConsAddr(ctx, consAddr) - require.True(t, found) - keeper.Slash(ctx, consAddr, -2, 10, fraction) - - // read updated state - validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) - require.True(t, found) - - // end block - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 1, len(updates), "cons addr: %v, updates: %v", []byte(consAddr), updates) - - validator = keeper.mustGetValidator(ctx, validator.OperatorAddress) - // power decreased - require.Equal(t, int64(5), validator.GetConsensusPower()) - - // pool bonded shares decreased - newBondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) - diffTokens := oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(keeper.BondDenom(ctx)) - require.Equal(t, sdk.TokensFromConsensusPower(5).String(), diffTokens.String()) -} - // tests Slash at the current height func TestSlashValidatorAtCurrentHeight(t *testing.T) { ctx, keeper, _ := setupHelper(t, 10) diff --git a/x/staking/keeper/slash_test.go b/x/staking/keeper/slash_test.go index 3aed1a8e15d0..7630824b99c5 100644 --- a/x/staking/keeper/slash_test.go +++ b/x/staking/keeper/slash_test.go @@ -4,6 +4,8 @@ import ( "testing" "time" + "github.com/cosmos/cosmos-sdk/x/supply" + abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/simapp" @@ -35,6 +37,8 @@ func initConfig(t *testing.T, power int64) (*simapp.SimApp, sdk.Context, []sdk.A require.NoError(t, err) app.SupplyKeeper.SetModuleAccount(ctx, bondedPool) + app.SupplyKeeper.SetSupply(ctx, supply.NewSupply(totalSupply)) + for i := int64(0); i < numVals; i++ { validator := types.NewValidator(addrVals[i], PKs[i], types.Description{}) validator, _ = validator.AddTokensFromDel(amt) @@ -189,3 +193,36 @@ func TestSlashAtFutureHeight(t *testing.T) { fraction := sdk.NewDecWithPrec(5, 1) require.Panics(t, func() { app.StakingKeeper.Slash(ctx, consAddr, 1, 10, fraction) }) } + +// test slash at a negative height +// this just represents pre-genesis and should have the same effect as slashing at height 0 +func TestSlashAtNegativeHeight(t *testing.T) { + app, ctx, _, _ := initConfig(t, 10) + consAddr := sdk.ConsAddress(PKs[0].Address()) + fraction := sdk.NewDecWithPrec(5, 1) + + bondedPool := app.StakingKeeper.GetBondedPool(ctx) + oldBondedPoolBalances := app.BankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + + validator, found := app.StakingKeeper.GetValidatorByConsAddr(ctx, consAddr) + require.True(t, found) + app.StakingKeeper.Slash(ctx, consAddr, -2, 10, fraction) + + // read updated state + validator, found = app.StakingKeeper.GetValidatorByConsAddr(ctx, consAddr) + require.True(t, found) + + // end block + updates := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 1, len(updates), "cons addr: %v, updates: %v", []byte(consAddr), updates) + + validator, found = app.StakingKeeper.GetValidator(ctx, validator.OperatorAddress) + require.True(t, found) + // power decreased + require.Equal(t, int64(5), validator.GetConsensusPower()) + + // pool bonded shares decreased + newBondedPoolBalances := app.BankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + diffTokens := oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(app.StakingKeeper.BondDenom(ctx)) + require.Equal(t, sdk.TokensFromConsensusPower(5).String(), diffTokens.String()) +} From a6767d31fe6b3c2e4706f8a386d587f9a5fd951e Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Tue, 25 Feb 2020 10:13:13 +0100 Subject: [PATCH 198/529] migrated two tests from slash_test to use simapp --- x/staking/keeper/old_slash_test.go | 159 ------------------------ x/staking/keeper/slash_test.go | 187 +++++++++++++++++++++++++++-- 2 files changed, 178 insertions(+), 168 deletions(-) diff --git a/x/staking/keeper/old_slash_test.go b/x/staking/keeper/old_slash_test.go index 61fe22d04b9a..a0c302c0ba68 100644 --- a/x/staking/keeper/old_slash_test.go +++ b/x/staking/keeper/old_slash_test.go @@ -36,165 +36,6 @@ func setupHelper(t *testing.T, power int64) (sdk.Context, Keeper, types.Params) } //_________________________________________________________________________________ - -// tests Slash at the current height -func TestSlashValidatorAtCurrentHeight(t *testing.T) { - ctx, keeper, _ := setupHelper(t, 10) - consAddr := sdk.ConsAddress(PKs[0].Address()) - fraction := sdk.NewDecWithPrec(5, 1) - - bondedPool := keeper.GetBondedPool(ctx) - oldBondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) - - validator, found := keeper.GetValidatorByConsAddr(ctx, consAddr) - require.True(t, found) - keeper.Slash(ctx, consAddr, ctx.BlockHeight(), 10, fraction) - - // read updated state - validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) - require.True(t, found) - - // end block - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 1, len(updates), "cons addr: %v, updates: %v", []byte(consAddr), updates) - - validator = keeper.mustGetValidator(ctx, validator.OperatorAddress) - // power decreased - require.Equal(t, int64(5), validator.GetConsensusPower()) - - // pool bonded shares decreased - newBondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) - diffTokens := oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(keeper.BondDenom(ctx)) - require.Equal(t, sdk.TokensFromConsensusPower(5).String(), diffTokens.String()) -} - -// tests Slash at a previous height with an unbonding delegation -func TestSlashWithUnbondingDelegation(t *testing.T) { - ctx, keeper, _ := setupHelper(t, 10) - consAddr := sdk.ConsAddress(PKs[0].Address()) - fraction := sdk.NewDecWithPrec(5, 1) - - // set an unbonding delegation with expiration timestamp beyond which the - // unbonding delegation shouldn't be slashed - ubdTokens := sdk.TokensFromConsensusPower(4) - ubd := types.NewUnbondingDelegation(addrDels[0], addrVals[0], 11, - time.Unix(0, 0), ubdTokens) - keeper.SetUnbondingDelegation(ctx, ubd) - - // slash validator for the first time - ctx = ctx.WithBlockHeight(12) - bondedPool := keeper.GetBondedPool(ctx) - oldBondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) - - validator, found := keeper.GetValidatorByConsAddr(ctx, consAddr) - require.True(t, found) - keeper.Slash(ctx, consAddr, 10, 10, fraction) - - // end block - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 1, len(updates)) - - // read updating unbonding delegation - ubd, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) - require.True(t, found) - require.Len(t, ubd.Entries, 1) - - // balance decreased - require.Equal(t, sdk.TokensFromConsensusPower(2), ubd.Entries[0].Balance) - - // bonded tokens burned - newBondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) - diffTokens := oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(keeper.BondDenom(ctx)) - require.Equal(t, sdk.TokensFromConsensusPower(3), diffTokens) - - // read updated validator - validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) - require.True(t, found) - - // power decreased by 3 - 6 stake originally bonded at the time of infraction - // was still bonded at the time of discovery and was slashed by half, 4 stake - // bonded at the time of discovery hadn't been bonded at the time of infraction - // and wasn't slashed - require.Equal(t, int64(7), validator.GetConsensusPower()) - - // slash validator again - ctx = ctx.WithBlockHeight(13) - keeper.Slash(ctx, consAddr, 9, 10, fraction) - - ubd, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) - require.True(t, found) - require.Len(t, ubd.Entries, 1) - - // balance decreased again - require.Equal(t, sdk.NewInt(0), ubd.Entries[0].Balance) - - // bonded tokens burned again - newBondedPoolBalances = keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) - diffTokens = oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(keeper.BondDenom(ctx)) - require.Equal(t, sdk.TokensFromConsensusPower(6), diffTokens) - - // read updated validator - validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) - require.True(t, found) - - // power decreased by 3 again - require.Equal(t, int64(4), validator.GetConsensusPower()) - - // slash validator again - // all originally bonded stake has been slashed, so this will have no effect - // on the unbonding delegation, but it will slash stake bonded since the infraction - // this may not be the desirable behaviour, ref https://github.com/cosmos/cosmos-sdk/issues/1440 - ctx = ctx.WithBlockHeight(13) - keeper.Slash(ctx, consAddr, 9, 10, fraction) - - ubd, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) - require.True(t, found) - require.Len(t, ubd.Entries, 1) - - // balance unchanged - require.Equal(t, sdk.NewInt(0), ubd.Entries[0].Balance) - - // bonded tokens burned again - newBondedPoolBalances = keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) - diffTokens = oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(keeper.BondDenom(ctx)) - require.Equal(t, sdk.TokensFromConsensusPower(9), diffTokens) - - // read updated validator - validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) - require.True(t, found) - - // power decreased by 3 again - require.Equal(t, int64(1), validator.GetConsensusPower()) - - // slash validator again - // all originally bonded stake has been slashed, so this will have no effect - // on the unbonding delegation, but it will slash stake bonded since the infraction - // this may not be the desirable behaviour, ref https://github.com/cosmos/cosmos-sdk/issues/1440 - ctx = ctx.WithBlockHeight(13) - keeper.Slash(ctx, consAddr, 9, 10, fraction) - - ubd, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) - require.True(t, found) - require.Len(t, ubd.Entries, 1) - - // balance unchanged - require.Equal(t, sdk.NewInt(0), ubd.Entries[0].Balance) - - // just 1 bonded token burned again since that's all the validator now has - newBondedPoolBalances = keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) - diffTokens = oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(keeper.BondDenom(ctx)) - require.Equal(t, sdk.TokensFromConsensusPower(10), diffTokens) - - // apply TM updates - keeper.ApplyAndReturnValidatorSetUpdates(ctx) - - // read updated validator - // power decreased by 1 again, validator is out of stake - // validator should be in unbonding period - validator, _ = keeper.GetValidatorByConsAddr(ctx, consAddr) - require.Equal(t, validator.GetStatus(), sdk.Unbonding) -} - // tests Slash at a previous height with a redelegation func TestSlashWithRedelegation(t *testing.T) { ctx, keeper, _ := setupHelper(t, 10) diff --git a/x/staking/keeper/slash_test.go b/x/staking/keeper/slash_test.go index 7630824b99c5..f8fa6dfc89e6 100644 --- a/x/staking/keeper/slash_test.go +++ b/x/staking/keeper/slash_test.go @@ -4,6 +4,8 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/cosmos/cosmos-sdk/x/supply" abci "github.com/tendermint/tendermint/abci/types" @@ -15,12 +17,11 @@ import ( "github.com/stretchr/testify/require" ) -// initConfig creates 3 validators and bootstrap the app. -func initConfig(t *testing.T, power int64) (*simapp.SimApp, sdk.Context, []sdk.AccAddress, []sdk.ValAddress) { +// bootstrapSlashTest creates 3 validators and bootstrap the app. +func bootstrapSlashTest(t *testing.T, power int64) (*simapp.SimApp, sdk.Context, []sdk.AccAddress, []sdk.ValAddress) { _, app, ctx := getBaseSimappWithCustomKeeper() - addrDels := simapp.AddTestAddrsIncremental(app, ctx, 100, sdk.NewInt(10000)) - addrVals := simapp.ConvertAddrsToValAddrs(addrDels) + addrDels, addrVals := generateAddresses(app, ctx, 100) amt := sdk.TokensFromConsensusPower(power) totalSupply := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), amt.MulRaw(int64(len(addrDels))))) @@ -49,9 +50,17 @@ func initConfig(t *testing.T, power int64) (*simapp.SimApp, sdk.Context, []sdk.A return app, ctx, addrDels, addrVals } +// generateAddresses generates numAddrs of normal AccAddrs and ValAddrs +func generateAddresses(app *simapp.SimApp, ctx sdk.Context, numAddrs int) ([]sdk.AccAddress, []sdk.ValAddress) { + addrDels := simapp.AddTestAddrsIncremental(app, ctx, numAddrs, sdk.NewInt(10000)) + addrVals := simapp.ConvertAddrsToValAddrs(addrDels) + + return addrDels, addrVals +} + // tests Jail, Unjail func TestRevocation(t *testing.T) { - app, ctx, _, addrVals := initConfig(t, 5) + app, ctx, _, addrVals := bootstrapSlashTest(t, 5) consAddr := sdk.ConsAddress(PKs[0].Address()) @@ -75,7 +84,7 @@ func TestRevocation(t *testing.T) { // tests slashUnbondingDelegation func TestSlashUnbondingDelegation(t *testing.T) { - app, ctx, addrDels, addrVals := initConfig(t, 10) + app, ctx, addrDels, addrVals := bootstrapSlashTest(t, 10) fraction := sdk.NewDecWithPrec(5, 1) @@ -119,7 +128,7 @@ func TestSlashUnbondingDelegation(t *testing.T) { // tests slashRedelegation func TestSlashRedelegation(t *testing.T) { - app, ctx, addrDels, addrVals := initConfig(t, 10) + app, ctx, addrDels, addrVals := bootstrapSlashTest(t, 10) fraction := sdk.NewDecWithPrec(5, 1) // add bonded tokens to pool for (re)delegations @@ -187,7 +196,7 @@ func TestSlashRedelegation(t *testing.T) { // tests Slash at a future height (must panic) func TestSlashAtFutureHeight(t *testing.T) { - app, ctx, _, _ := initConfig(t, 10) + app, ctx, _, _ := bootstrapSlashTest(t, 10) consAddr := sdk.ConsAddress(PKs[0].Address()) fraction := sdk.NewDecWithPrec(5, 1) @@ -197,7 +206,7 @@ func TestSlashAtFutureHeight(t *testing.T) { // test slash at a negative height // this just represents pre-genesis and should have the same effect as slashing at height 0 func TestSlashAtNegativeHeight(t *testing.T) { - app, ctx, _, _ := initConfig(t, 10) + app, ctx, _, _ := bootstrapSlashTest(t, 10) consAddr := sdk.ConsAddress(PKs[0].Address()) fraction := sdk.NewDecWithPrec(5, 1) @@ -226,3 +235,163 @@ func TestSlashAtNegativeHeight(t *testing.T) { diffTokens := oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(app.StakingKeeper.BondDenom(ctx)) require.Equal(t, sdk.TokensFromConsensusPower(5).String(), diffTokens.String()) } + +// tests Slash at the current height +func TestSlashValidatorAtCurrentHeight(t *testing.T) { + app, ctx, _, _ := bootstrapSlashTest(t, 10) + consAddr := sdk.ConsAddress(PKs[0].Address()) + fraction := sdk.NewDecWithPrec(5, 1) + + bondedPool := app.StakingKeeper.GetBondedPool(ctx) + oldBondedPoolBalances := app.BankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + + validator, found := app.StakingKeeper.GetValidatorByConsAddr(ctx, consAddr) + require.True(t, found) + app.StakingKeeper.Slash(ctx, consAddr, ctx.BlockHeight(), 10, fraction) + + // read updated state + validator, found = app.StakingKeeper.GetValidatorByConsAddr(ctx, consAddr) + require.True(t, found) + + // end block + updates := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 1, len(updates), "cons addr: %v, updates: %v", []byte(consAddr), updates) + + validator, found = app.StakingKeeper.GetValidator(ctx, validator.OperatorAddress) + assert.True(t, found) + // power decreased + require.Equal(t, int64(5), validator.GetConsensusPower()) + + // pool bonded shares decreased + newBondedPoolBalances := app.BankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + diffTokens := oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(app.StakingKeeper.BondDenom(ctx)) + require.Equal(t, sdk.TokensFromConsensusPower(5).String(), diffTokens.String()) +} + +// tests Slash at a previous height with an unbonding delegation +func TestSlashWithUnbondingDelegation(t *testing.T) { + app, ctx, addrDels, addrVals := bootstrapSlashTest(t, 10) + + consAddr := sdk.ConsAddress(PKs[0].Address()) + fraction := sdk.NewDecWithPrec(5, 1) + + // set an unbonding delegation with expiration timestamp beyond which the + // unbonding delegation shouldn't be slashed + ubdTokens := sdk.TokensFromConsensusPower(4) + ubd := types.NewUnbondingDelegation(addrDels[0], addrVals[0], 11, + time.Unix(0, 0), ubdTokens) + app.StakingKeeper.SetUnbondingDelegation(ctx, ubd) + + // slash validator for the first time + ctx = ctx.WithBlockHeight(12) + bondedPool := app.StakingKeeper.GetBondedPool(ctx) + oldBondedPoolBalances := app.BankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + + validator, found := app.StakingKeeper.GetValidatorByConsAddr(ctx, consAddr) + require.True(t, found) + app.StakingKeeper.Slash(ctx, consAddr, 10, 10, fraction) + + // end block + updates := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 1, len(updates)) + + // read updating unbonding delegation + ubd, found = app.StakingKeeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) + require.True(t, found) + require.Len(t, ubd.Entries, 1) + + // balance decreased + require.Equal(t, sdk.TokensFromConsensusPower(2), ubd.Entries[0].Balance) + + // bonded tokens burned + newBondedPoolBalances := app.BankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + diffTokens := oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(app.StakingKeeper.BondDenom(ctx)) + require.Equal(t, sdk.TokensFromConsensusPower(3), diffTokens) + + // read updated validator + validator, found = app.StakingKeeper.GetValidatorByConsAddr(ctx, consAddr) + require.True(t, found) + + // power decreased by 3 - 6 stake originally bonded at the time of infraction + // was still bonded at the time of discovery and was slashed by half, 4 stake + // bonded at the time of discovery hadn't been bonded at the time of infraction + // and wasn't slashed + require.Equal(t, int64(7), validator.GetConsensusPower()) + + // slash validator again + ctx = ctx.WithBlockHeight(13) + app.StakingKeeper.Slash(ctx, consAddr, 9, 10, fraction) + + ubd, found = app.StakingKeeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) + require.True(t, found) + require.Len(t, ubd.Entries, 1) + + // balance decreased again + require.Equal(t, sdk.NewInt(0), ubd.Entries[0].Balance) + + // bonded tokens burned again + newBondedPoolBalances = app.BankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + diffTokens = oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(app.StakingKeeper.BondDenom(ctx)) + require.Equal(t, sdk.TokensFromConsensusPower(6), diffTokens) + + // read updated validator + validator, found = app.StakingKeeper.GetValidatorByConsAddr(ctx, consAddr) + require.True(t, found) + + // power decreased by 3 again + require.Equal(t, int64(4), validator.GetConsensusPower()) + + // slash validator again + // all originally bonded stake has been slashed, so this will have no effect + // on the unbonding delegation, but it will slash stake bonded since the infraction + // this may not be the desirable behaviour, ref https://github.com/cosmos/cosmos-sdk/issues/1440 + ctx = ctx.WithBlockHeight(13) + app.StakingKeeper.Slash(ctx, consAddr, 9, 10, fraction) + + ubd, found = app.StakingKeeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) + require.True(t, found) + require.Len(t, ubd.Entries, 1) + + // balance unchanged + require.Equal(t, sdk.NewInt(0), ubd.Entries[0].Balance) + + // bonded tokens burned again + newBondedPoolBalances = app.BankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + diffTokens = oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(app.StakingKeeper.BondDenom(ctx)) + require.Equal(t, sdk.TokensFromConsensusPower(9), diffTokens) + + // read updated validator + validator, found = app.StakingKeeper.GetValidatorByConsAddr(ctx, consAddr) + require.True(t, found) + + // power decreased by 3 again + require.Equal(t, int64(1), validator.GetConsensusPower()) + + // slash validator again + // all originally bonded stake has been slashed, so this will have no effect + // on the unbonding delegation, but it will slash stake bonded since the infraction + // this may not be the desirable behaviour, ref https://github.com/cosmos/cosmos-sdk/issues/1440 + ctx = ctx.WithBlockHeight(13) + app.StakingKeeper.Slash(ctx, consAddr, 9, 10, fraction) + + ubd, found = app.StakingKeeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) + require.True(t, found) + require.Len(t, ubd.Entries, 1) + + // balance unchanged + require.Equal(t, sdk.NewInt(0), ubd.Entries[0].Balance) + + // just 1 bonded token burned again since that's all the validator now has + newBondedPoolBalances = app.BankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + diffTokens = oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(app.StakingKeeper.BondDenom(ctx)) + require.Equal(t, sdk.TokensFromConsensusPower(10), diffTokens) + + // apply TM updates + app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + + // read updated validator + // power decreased by 1 again, validator is out of stake + // validator should be in unbonding period + validator, _ = app.StakingKeeper.GetValidatorByConsAddr(ctx, consAddr) + require.Equal(t, validator.GetStatus(), sdk.Unbonding) +} From 15eaa129ee6adc2ed7522bb8608b665c9669003c Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Tue, 25 Feb 2020 10:24:58 +0100 Subject: [PATCH 199/529] refactor TestSlashWithRedelegation --- x/staking/keeper/old_slash_test.go | 156 ----------------------------- x/staking/keeper/slash_test.go | 156 +++++++++++++++++++++++++++++ 2 files changed, 156 insertions(+), 156 deletions(-) diff --git a/x/staking/keeper/old_slash_test.go b/x/staking/keeper/old_slash_test.go index a0c302c0ba68..a5e253804e44 100644 --- a/x/staking/keeper/old_slash_test.go +++ b/x/staking/keeper/old_slash_test.go @@ -35,162 +35,6 @@ func setupHelper(t *testing.T, power int64) (sdk.Context, Keeper, types.Params) return ctx, keeper, params } -//_________________________________________________________________________________ -// tests Slash at a previous height with a redelegation -func TestSlashWithRedelegation(t *testing.T) { - ctx, keeper, _ := setupHelper(t, 10) - consAddr := sdk.ConsAddress(PKs[0].Address()) - fraction := sdk.NewDecWithPrec(5, 1) - bondDenom := keeper.BondDenom(ctx) - - // set a redelegation - rdTokens := sdk.TokensFromConsensusPower(6) - rd := types.NewRedelegation(addrDels[0], addrVals[0], addrVals[1], 11, - time.Unix(0, 0), rdTokens, rdTokens.ToDec()) - keeper.SetRedelegation(ctx, rd) - - // set the associated delegation - del := types.NewDelegation(addrDels[0], addrVals[1], rdTokens.ToDec()) - keeper.SetDelegation(ctx, del) - - // update bonded tokens - bondedPool := keeper.GetBondedPool(ctx) - notBondedPool := keeper.GetNotBondedPool(ctx) - rdCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, rdTokens.MulRaw(2))) - - balances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) - err := keeper.bankKeeper.SetBalances(ctx, bondedPool.GetAddress(), balances.Add(rdCoins...)) - require.NoError(t, err) - - keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) - - oldBonded := keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount - oldNotBonded := keeper.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount - - // slash validator - ctx = ctx.WithBlockHeight(12) - validator, found := keeper.GetValidatorByConsAddr(ctx, consAddr) - require.True(t, found) - - require.NotPanics(t, func() { keeper.Slash(ctx, consAddr, 10, 10, fraction) }) - burnAmount := sdk.TokensFromConsensusPower(10).ToDec().Mul(fraction).TruncateInt() - - bondedPool = keeper.GetBondedPool(ctx) - notBondedPool = keeper.GetNotBondedPool(ctx) - - // burn bonded tokens from only from delegations - bondedPoolBalance := keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount - require.True(sdk.IntEq(t, oldBonded.Sub(burnAmount), bondedPoolBalance)) - - notBondedPoolBalance := keeper.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount - require.True(sdk.IntEq(t, oldNotBonded, notBondedPoolBalance)) - oldBonded = keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount - - // read updating redelegation - rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) - require.True(t, found) - require.Len(t, rd.Entries, 1) - // read updated validator - validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) - require.True(t, found) - // power decreased by 2 - 4 stake originally bonded at the time of infraction - // was still bonded at the time of discovery and was slashed by half, 4 stake - // bonded at the time of discovery hadn't been bonded at the time of infraction - // and wasn't slashed - require.Equal(t, int64(8), validator.GetConsensusPower()) - - // slash the validator again - validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) - require.True(t, found) - - require.NotPanics(t, func() { keeper.Slash(ctx, consAddr, 10, 10, sdk.OneDec()) }) - burnAmount = sdk.TokensFromConsensusPower(7) - - // read updated pool - bondedPool = keeper.GetBondedPool(ctx) - notBondedPool = keeper.GetNotBondedPool(ctx) - - // seven bonded tokens burned - bondedPoolBalance = keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount - require.True(sdk.IntEq(t, oldBonded.Sub(burnAmount), bondedPoolBalance)) - require.True(sdk.IntEq(t, oldNotBonded, notBondedPoolBalance)) - - bondedPoolBalance = keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount - require.True(sdk.IntEq(t, oldBonded.Sub(burnAmount), bondedPoolBalance)) - - notBondedPoolBalance = keeper.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount - require.True(sdk.IntEq(t, oldNotBonded, notBondedPoolBalance)) - oldBonded = keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount - - // read updating redelegation - rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) - require.True(t, found) - require.Len(t, rd.Entries, 1) - // read updated validator - validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) - require.True(t, found) - // power decreased by 4 - require.Equal(t, int64(4), validator.GetConsensusPower()) - - // slash the validator again, by 100% - ctx = ctx.WithBlockHeight(12) - validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) - require.True(t, found) - - require.NotPanics(t, func() { keeper.Slash(ctx, consAddr, 10, 10, sdk.OneDec()) }) - - burnAmount = sdk.TokensFromConsensusPower(10).ToDec().Mul(sdk.OneDec()).TruncateInt() - burnAmount = burnAmount.Sub(sdk.OneDec().MulInt(rdTokens).TruncateInt()) - - // read updated pool - bondedPool = keeper.GetBondedPool(ctx) - notBondedPool = keeper.GetNotBondedPool(ctx) - - bondedPoolBalance = keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount - require.True(sdk.IntEq(t, oldBonded.Sub(burnAmount), bondedPoolBalance)) - notBondedPoolBalance = keeper.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount - require.True(sdk.IntEq(t, oldNotBonded, notBondedPoolBalance)) - oldBonded = keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount - - // read updating redelegation - rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) - require.True(t, found) - require.Len(t, rd.Entries, 1) - // apply TM updates - keeper.ApplyAndReturnValidatorSetUpdates(ctx) - // read updated validator - // validator decreased to zero power, should be in unbonding period - validator, _ = keeper.GetValidatorByConsAddr(ctx, consAddr) - require.Equal(t, validator.GetStatus(), sdk.Unbonding) - - // slash the validator again, by 100% - // no stake remains to be slashed - ctx = ctx.WithBlockHeight(12) - // validator still in unbonding period - validator, _ = keeper.GetValidatorByConsAddr(ctx, consAddr) - require.Equal(t, validator.GetStatus(), sdk.Unbonding) - - require.NotPanics(t, func() { keeper.Slash(ctx, consAddr, 10, 10, sdk.OneDec()) }) - - // read updated pool - bondedPool = keeper.GetBondedPool(ctx) - notBondedPool = keeper.GetNotBondedPool(ctx) - - bondedPoolBalance = keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount - require.True(sdk.IntEq(t, oldBonded, bondedPoolBalance)) - notBondedPoolBalance = keeper.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount - require.True(sdk.IntEq(t, oldNotBonded, notBondedPoolBalance)) - - // read updating redelegation - rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) - require.True(t, found) - require.Len(t, rd.Entries, 1) - // read updated validator - // power still zero, still in unbonding period - validator, _ = keeper.GetValidatorByConsAddr(ctx, consAddr) - require.Equal(t, validator.GetStatus(), sdk.Unbonding) -} - // tests Slash at a previous height with both an unbonding delegation and a redelegation func TestSlashBoth(t *testing.T) { ctx, keeper, _ := setupHelper(t, 10) diff --git a/x/staking/keeper/slash_test.go b/x/staking/keeper/slash_test.go index f8fa6dfc89e6..19b91a1f698f 100644 --- a/x/staking/keeper/slash_test.go +++ b/x/staking/keeper/slash_test.go @@ -395,3 +395,159 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { validator, _ = app.StakingKeeper.GetValidatorByConsAddr(ctx, consAddr) require.Equal(t, validator.GetStatus(), sdk.Unbonding) } + +//_________________________________________________________________________________ +// tests Slash at a previous height with a redelegation +func TestSlashWithRedelegation(t *testing.T) { + app, ctx, addrDels, addrVals := bootstrapSlashTest(t, 10) + consAddr := sdk.ConsAddress(PKs[0].Address()) + fraction := sdk.NewDecWithPrec(5, 1) + bondDenom := app.StakingKeeper.BondDenom(ctx) + + // set a redelegation + rdTokens := sdk.TokensFromConsensusPower(6) + rd := types.NewRedelegation(addrDels[0], addrVals[0], addrVals[1], 11, + time.Unix(0, 0), rdTokens, rdTokens.ToDec()) + app.StakingKeeper.SetRedelegation(ctx, rd) + + // set the associated delegation + del := types.NewDelegation(addrDels[0], addrVals[1], rdTokens.ToDec()) + app.StakingKeeper.SetDelegation(ctx, del) + + // update bonded tokens + bondedPool := app.StakingKeeper.GetBondedPool(ctx) + notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) + rdCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, rdTokens.MulRaw(2))) + + balances := app.BankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + err := app.BankKeeper.SetBalances(ctx, bondedPool.GetAddress(), balances.Add(rdCoins...)) + require.NoError(t, err) + + app.SupplyKeeper.SetModuleAccount(ctx, bondedPool) + + oldBonded := app.BankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount + oldNotBonded := app.BankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount + + // slash validator + ctx = ctx.WithBlockHeight(12) + validator, found := app.StakingKeeper.GetValidatorByConsAddr(ctx, consAddr) + require.True(t, found) + + require.NotPanics(t, func() { app.StakingKeeper.Slash(ctx, consAddr, 10, 10, fraction) }) + burnAmount := sdk.TokensFromConsensusPower(10).ToDec().Mul(fraction).TruncateInt() + + bondedPool = app.StakingKeeper.GetBondedPool(ctx) + notBondedPool = app.StakingKeeper.GetNotBondedPool(ctx) + + // burn bonded tokens from only from delegations + bondedPoolBalance := app.BankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldBonded.Sub(burnAmount), bondedPoolBalance)) + + notBondedPoolBalance := app.BankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldNotBonded, notBondedPoolBalance)) + oldBonded = app.BankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount + + // read updating redelegation + rd, found = app.StakingKeeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) + require.True(t, found) + require.Len(t, rd.Entries, 1) + // read updated validator + validator, found = app.StakingKeeper.GetValidatorByConsAddr(ctx, consAddr) + require.True(t, found) + // power decreased by 2 - 4 stake originally bonded at the time of infraction + // was still bonded at the time of discovery and was slashed by half, 4 stake + // bonded at the time of discovery hadn't been bonded at the time of infraction + // and wasn't slashed + require.Equal(t, int64(8), validator.GetConsensusPower()) + + // slash the validator again + validator, found = app.StakingKeeper.GetValidatorByConsAddr(ctx, consAddr) + require.True(t, found) + + require.NotPanics(t, func() { app.StakingKeeper.Slash(ctx, consAddr, 10, 10, sdk.OneDec()) }) + burnAmount = sdk.TokensFromConsensusPower(7) + + // read updated pool + bondedPool = app.StakingKeeper.GetBondedPool(ctx) + notBondedPool = app.StakingKeeper.GetNotBondedPool(ctx) + + // seven bonded tokens burned + bondedPoolBalance = app.BankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldBonded.Sub(burnAmount), bondedPoolBalance)) + require.True(sdk.IntEq(t, oldNotBonded, notBondedPoolBalance)) + + bondedPoolBalance = app.BankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldBonded.Sub(burnAmount), bondedPoolBalance)) + + notBondedPoolBalance = app.BankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldNotBonded, notBondedPoolBalance)) + oldBonded = app.BankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount + + // read updating redelegation + rd, found = app.StakingKeeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) + require.True(t, found) + require.Len(t, rd.Entries, 1) + // read updated validator + validator, found = app.StakingKeeper.GetValidatorByConsAddr(ctx, consAddr) + require.True(t, found) + // power decreased by 4 + require.Equal(t, int64(4), validator.GetConsensusPower()) + + // slash the validator again, by 100% + ctx = ctx.WithBlockHeight(12) + validator, found = app.StakingKeeper.GetValidatorByConsAddr(ctx, consAddr) + require.True(t, found) + + require.NotPanics(t, func() { app.StakingKeeper.Slash(ctx, consAddr, 10, 10, sdk.OneDec()) }) + + burnAmount = sdk.TokensFromConsensusPower(10).ToDec().Mul(sdk.OneDec()).TruncateInt() + burnAmount = burnAmount.Sub(sdk.OneDec().MulInt(rdTokens).TruncateInt()) + + // read updated pool + bondedPool = app.StakingKeeper.GetBondedPool(ctx) + notBondedPool = app.StakingKeeper.GetNotBondedPool(ctx) + + bondedPoolBalance = app.BankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldBonded.Sub(burnAmount), bondedPoolBalance)) + notBondedPoolBalance = app.BankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldNotBonded, notBondedPoolBalance)) + oldBonded = app.BankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount + + // read updating redelegation + rd, found = app.StakingKeeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) + require.True(t, found) + require.Len(t, rd.Entries, 1) + // apply TM updates + app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + // read updated validator + // validator decreased to zero power, should be in unbonding period + validator, _ = app.StakingKeeper.GetValidatorByConsAddr(ctx, consAddr) + require.Equal(t, validator.GetStatus(), sdk.Unbonding) + + // slash the validator again, by 100% + // no stake remains to be slashed + ctx = ctx.WithBlockHeight(12) + // validator still in unbonding period + validator, _ = app.StakingKeeper.GetValidatorByConsAddr(ctx, consAddr) + require.Equal(t, validator.GetStatus(), sdk.Unbonding) + + require.NotPanics(t, func() { app.StakingKeeper.Slash(ctx, consAddr, 10, 10, sdk.OneDec()) }) + + // read updated pool + bondedPool = app.StakingKeeper.GetBondedPool(ctx) + notBondedPool = app.StakingKeeper.GetNotBondedPool(ctx) + + bondedPoolBalance = app.BankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldBonded, bondedPoolBalance)) + notBondedPoolBalance = app.BankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldNotBonded, notBondedPoolBalance)) + + // read updating redelegation + rd, found = app.StakingKeeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) + require.True(t, found) + require.Len(t, rd.Entries, 1) + // read updated validator + // power still zero, still in unbonding period + validator, _ = app.StakingKeeper.GetValidatorByConsAddr(ctx, consAddr) + require.Equal(t, validator.GetStatus(), sdk.Unbonding) +} From 0cddd4fff6a33a6da413b21e86073579d5c03cdd Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Tue, 25 Feb 2020 10:32:53 +0100 Subject: [PATCH 200/529] end refactoring slash_test --- x/staking/keeper/old_slash_test.go | 111 ----------------------------- x/staking/keeper/slash_test.go | 75 +++++++++++++++++++ 2 files changed, 75 insertions(+), 111 deletions(-) delete mode 100644 x/staking/keeper/old_slash_test.go diff --git a/x/staking/keeper/old_slash_test.go b/x/staking/keeper/old_slash_test.go deleted file mode 100644 index a5e253804e44..000000000000 --- a/x/staking/keeper/old_slash_test.go +++ /dev/null @@ -1,111 +0,0 @@ -package keeper - -import ( - "testing" - "time" - - "github.com/stretchr/testify/require" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/staking/types" -) - -// TODO integrate with test_common.go helper (CreateTestInput) -// setup helper function - creates two validators -func setupHelper(t *testing.T, power int64) (sdk.Context, Keeper, types.Params) { - // setup - ctx, _, _, keeper, _ := CreateTestInput(t, false, power) - params := keeper.GetParams(ctx) - numVals := int64(3) - amt := sdk.TokensFromConsensusPower(power) - bondedCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), amt.MulRaw(numVals))) - - bondedPool := keeper.GetBondedPool(ctx) - require.NoError(t, keeper.bankKeeper.SetBalances(ctx, bondedPool.GetAddress(), bondedCoins)) - keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) - - // add numVals validators - for i := int64(0); i < numVals; i++ { - validator := types.NewValidator(addrVals[i], PKs[i], types.Description{}) - validator, _ = validator.AddTokensFromDel(amt) - validator = TestingUpdateValidator(keeper, ctx, validator, true) - keeper.SetValidatorByConsAddr(ctx, validator) - } - - return ctx, keeper, params -} - -// tests Slash at a previous height with both an unbonding delegation and a redelegation -func TestSlashBoth(t *testing.T) { - ctx, keeper, _ := setupHelper(t, 10) - fraction := sdk.NewDecWithPrec(5, 1) - bondDenom := keeper.BondDenom(ctx) - - // set a redelegation with expiration timestamp beyond which the - // redelegation shouldn't be slashed - rdATokens := sdk.TokensFromConsensusPower(6) - rdA := types.NewRedelegation(addrDels[0], addrVals[0], addrVals[1], 11, - time.Unix(0, 0), rdATokens, - rdATokens.ToDec()) - keeper.SetRedelegation(ctx, rdA) - - // set the associated delegation - delA := types.NewDelegation(addrDels[0], addrVals[1], rdATokens.ToDec()) - keeper.SetDelegation(ctx, delA) - - // set an unbonding delegation with expiration timestamp (beyond which the - // unbonding delegation shouldn't be slashed) - ubdATokens := sdk.TokensFromConsensusPower(4) - ubdA := types.NewUnbondingDelegation(addrDels[0], addrVals[0], 11, - time.Unix(0, 0), ubdATokens) - keeper.SetUnbondingDelegation(ctx, ubdA) - - bondedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, rdATokens.MulRaw(2))) - notBondedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, ubdATokens)) - - // update bonded tokens - bondedPool := keeper.GetBondedPool(ctx) - notBondedPool := keeper.GetNotBondedPool(ctx) - - bondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) - require.NoError(t, keeper.bankKeeper.SetBalances(ctx, bondedPool.GetAddress(), bondedPoolBalances.Add(bondedCoins...))) - - notBondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) - require.NoError(t, keeper.bankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), notBondedPoolBalances.Add(notBondedCoins...))) - - keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) - keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) - - oldBonded := keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount - oldNotBonded := keeper.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount - // slash validator - ctx = ctx.WithBlockHeight(12) - validator, found := keeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(PKs[0])) - require.True(t, found) - consAddr0 := sdk.ConsAddress(PKs[0].Address()) - keeper.Slash(ctx, consAddr0, 10, 10, fraction) - - burnedNotBondedAmount := fraction.MulInt(ubdATokens).TruncateInt() - burnedBondAmount := sdk.TokensFromConsensusPower(10).ToDec().Mul(fraction).TruncateInt() - burnedBondAmount = burnedBondAmount.Sub(burnedNotBondedAmount) - - // read updated pool - bondedPool = keeper.GetBondedPool(ctx) - notBondedPool = keeper.GetNotBondedPool(ctx) - - bondedPoolBalance := keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount - require.True(sdk.IntEq(t, oldBonded.Sub(burnedBondAmount), bondedPoolBalance)) - - notBondedPoolBalance := keeper.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount - require.True(sdk.IntEq(t, oldNotBonded.Sub(burnedNotBondedAmount), notBondedPoolBalance)) - - // read updating redelegation - rdA, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) - require.True(t, found) - require.Len(t, rdA.Entries, 1) - // read updated validator - validator, found = keeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(PKs[0])) - require.True(t, found) - // power not decreased, all stake was bonded since - require.Equal(t, int64(10), validator.GetConsensusPower()) -} diff --git a/x/staking/keeper/slash_test.go b/x/staking/keeper/slash_test.go index 19b91a1f698f..77296c19725e 100644 --- a/x/staking/keeper/slash_test.go +++ b/x/staking/keeper/slash_test.go @@ -551,3 +551,78 @@ func TestSlashWithRedelegation(t *testing.T) { validator, _ = app.StakingKeeper.GetValidatorByConsAddr(ctx, consAddr) require.Equal(t, validator.GetStatus(), sdk.Unbonding) } + +// tests Slash at a previous height with both an unbonding delegation and a redelegation +func TestSlashBoth(t *testing.T) { + app, ctx, addrDels, addrVals := bootstrapSlashTest(t, 10) + fraction := sdk.NewDecWithPrec(5, 1) + bondDenom := app.StakingKeeper.BondDenom(ctx) + + // set a redelegation with expiration timestamp beyond which the + // redelegation shouldn't be slashed + rdATokens := sdk.TokensFromConsensusPower(6) + rdA := types.NewRedelegation(addrDels[0], addrVals[0], addrVals[1], 11, + time.Unix(0, 0), rdATokens, + rdATokens.ToDec()) + app.StakingKeeper.SetRedelegation(ctx, rdA) + + // set the associated delegation + delA := types.NewDelegation(addrDels[0], addrVals[1], rdATokens.ToDec()) + app.StakingKeeper.SetDelegation(ctx, delA) + + // set an unbonding delegation with expiration timestamp (beyond which the + // unbonding delegation shouldn't be slashed) + ubdATokens := sdk.TokensFromConsensusPower(4) + ubdA := types.NewUnbondingDelegation(addrDels[0], addrVals[0], 11, + time.Unix(0, 0), ubdATokens) + app.StakingKeeper.SetUnbondingDelegation(ctx, ubdA) + + bondedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, rdATokens.MulRaw(2))) + notBondedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, ubdATokens)) + + // update bonded tokens + bondedPool := app.StakingKeeper.GetBondedPool(ctx) + notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) + + bondedPoolBalances := app.BankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + require.NoError(t, app.BankKeeper.SetBalances(ctx, bondedPool.GetAddress(), bondedPoolBalances.Add(bondedCoins...))) + + notBondedPoolBalances := app.BankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) + require.NoError(t, app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), notBondedPoolBalances.Add(notBondedCoins...))) + + app.SupplyKeeper.SetModuleAccount(ctx, bondedPool) + app.SupplyKeeper.SetModuleAccount(ctx, notBondedPool) + + oldBonded := app.BankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount + oldNotBonded := app.BankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount + // slash validator + ctx = ctx.WithBlockHeight(12) + validator, found := app.StakingKeeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(PKs[0])) + require.True(t, found) + consAddr0 := sdk.ConsAddress(PKs[0].Address()) + app.StakingKeeper.Slash(ctx, consAddr0, 10, 10, fraction) + + burnedNotBondedAmount := fraction.MulInt(ubdATokens).TruncateInt() + burnedBondAmount := sdk.TokensFromConsensusPower(10).ToDec().Mul(fraction).TruncateInt() + burnedBondAmount = burnedBondAmount.Sub(burnedNotBondedAmount) + + // read updated pool + bondedPool = app.StakingKeeper.GetBondedPool(ctx) + notBondedPool = app.StakingKeeper.GetNotBondedPool(ctx) + + bondedPoolBalance := app.BankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldBonded.Sub(burnedBondAmount), bondedPoolBalance)) + + notBondedPoolBalance := app.BankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldNotBonded.Sub(burnedNotBondedAmount), notBondedPoolBalance)) + + // read updating redelegation + rdA, found = app.StakingKeeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) + require.True(t, found) + require.Len(t, rdA.Entries, 1) + // read updated validator + validator, found = app.StakingKeeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(PKs[0])) + require.True(t, found) + // power not decreased, all stake was bonded since + require.Equal(t, int64(10), validator.GetConsensusPower()) +} From 66abd1f19f8587ecc00144de15b1626b65fb1c12 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Tue, 25 Feb 2020 11:43:51 +0100 Subject: [PATCH 201/529] refactor first test validation to simapp --- x/staking/keeper/old_validator_test.go | 1039 +++++++++++++++++++++++ x/staking/keeper/slash_test.go | 8 - x/staking/keeper/test_common_test.go | 16 + x/staking/keeper/validator_test.go | 1073 +----------------------- 4 files changed, 1086 insertions(+), 1050 deletions(-) create mode 100644 x/staking/keeper/old_validator_test.go diff --git a/x/staking/keeper/old_validator_test.go b/x/staking/keeper/old_validator_test.go new file mode 100644 index 000000000000..c5101a3c145b --- /dev/null +++ b/x/staking/keeper/old_validator_test.go @@ -0,0 +1,1039 @@ +package keeper + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + abci "github.com/tendermint/tendermint/abci/types" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/staking/types" +) + +func TestUpdateValidatorByPowerIndex(t *testing.T) { + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) + + bondedPool := keeper.GetBondedPool(ctx) + notBondedPool := keeper.GetNotBondedPool(ctx) + bk.SetBalances(ctx, bondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), sdk.TokensFromConsensusPower(1234)))) + bk.SetBalances(ctx, notBondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), sdk.TokensFromConsensusPower(10000)))) + keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) + keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) + + // add a validator + validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) + validator, delSharesCreated := validator.AddTokensFromDel(sdk.TokensFromConsensusPower(100)) + require.Equal(t, sdk.Unbonded, validator.Status) + require.Equal(t, sdk.TokensFromConsensusPower(100), validator.Tokens) + TestingUpdateValidator(keeper, ctx, validator, true) + validator, found := keeper.GetValidator(ctx, addrVals[0]) + require.True(t, found) + require.Equal(t, sdk.TokensFromConsensusPower(100), validator.Tokens) + + power := types.GetValidatorsByPowerIndexKey(validator) + require.True(t, validatorByPowerIndexExists(keeper, ctx, power)) + + // burn half the delegator shares + keeper.DeleteValidatorByPowerIndex(ctx, validator) + validator, burned := validator.RemoveDelShares(delSharesCreated.Quo(sdk.NewDec(2))) + require.Equal(t, sdk.TokensFromConsensusPower(50), burned) + TestingUpdateValidator(keeper, ctx, validator, true) // update the validator, possibly kicking it out + require.False(t, validatorByPowerIndexExists(keeper, ctx, power)) + + validator, found = keeper.GetValidator(ctx, addrVals[0]) + require.True(t, found) + + power = types.GetValidatorsByPowerIndexKey(validator) + require.True(t, validatorByPowerIndexExists(keeper, ctx, power)) +} + +func TestUpdateBondedValidatorsDecreaseCliff(t *testing.T) { + numVals := 10 + maxVals := 5 + + // create context, keeper, and pool for tests + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) + bondedPool := keeper.GetBondedPool(ctx) + notBondedPool := keeper.GetNotBondedPool(ctx) + + // create keeper parameters + params := keeper.GetParams(ctx) + params.MaxValidators = uint32(maxVals) + keeper.SetParams(ctx, params) + + // create a random pool + bk.SetBalances(ctx, bondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), sdk.TokensFromConsensusPower(1234)))) + bk.SetBalances(ctx, notBondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), sdk.TokensFromConsensusPower(10000)))) + keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) + keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) + + validators := make([]types.Validator, numVals) + for i := 0; i < len(validators); i++ { + moniker := fmt.Sprintf("val#%d", int64(i)) + val := types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{Moniker: moniker}) + delTokens := sdk.TokensFromConsensusPower(int64((i + 1) * 10)) + val, _ = val.AddTokensFromDel(delTokens) + + val = TestingUpdateValidator(keeper, ctx, val, true) + validators[i] = val + } + + nextCliffVal := validators[numVals-maxVals+1] + + // remove enough tokens to kick out the validator below the current cliff + // validator and next in line cliff validator + keeper.DeleteValidatorByPowerIndex(ctx, nextCliffVal) + shares := sdk.TokensFromConsensusPower(21) + nextCliffVal, _ = nextCliffVal.RemoveDelShares(shares.ToDec()) + nextCliffVal = TestingUpdateValidator(keeper, ctx, nextCliffVal, true) + + expectedValStatus := map[int]sdk.BondStatus{ + 9: sdk.Bonded, 8: sdk.Bonded, 7: sdk.Bonded, 5: sdk.Bonded, 4: sdk.Bonded, + 0: sdk.Unbonding, 1: sdk.Unbonding, 2: sdk.Unbonding, 3: sdk.Unbonding, 6: sdk.Unbonding, + } + + // require all the validators have their respective statuses + for valIdx, status := range expectedValStatus { + valAddr := validators[valIdx].OperatorAddress + val, _ := keeper.GetValidator(ctx, valAddr) + + assert.Equal( + t, status, val.GetStatus(), + fmt.Sprintf("expected validator at index %v to have status: %s", valIdx, status), + ) + } +} + +func TestSlashToZeroPowerRemoved(t *testing.T) { + // initialize setup + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 100) + + // add a validator + validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) + valTokens := sdk.TokensFromConsensusPower(100) + + bondedPool := keeper.GetBondedPool(ctx) + err := bk.SetBalances(ctx, bondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), valTokens))) + require.NoError(t, err) + keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) + + validator, _ = validator.AddTokensFromDel(valTokens) + require.Equal(t, sdk.Unbonded, validator.Status) + require.Equal(t, valTokens, validator.Tokens) + keeper.SetValidatorByConsAddr(ctx, validator) + validator = TestingUpdateValidator(keeper, ctx, validator, true) + require.Equal(t, valTokens, validator.Tokens, "\nvalidator %v\npool %v", validator, valTokens) + + // slash the validator by 100% + consAddr0 := sdk.ConsAddress(PKs[0].Address()) + keeper.Slash(ctx, consAddr0, 0, 100, sdk.OneDec()) + // apply TM updates + keeper.ApplyAndReturnValidatorSetUpdates(ctx) + // validator should be unbonding + validator, _ = keeper.GetValidator(ctx, addrVals[0]) + require.Equal(t, validator.GetStatus(), sdk.Unbonding) +} + +// This function tests UpdateValidator, GetValidator, GetLastValidators, RemoveValidator +func TestValidatorBasics(t *testing.T) { + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) + + //construct the validators + var validators [3]types.Validator + powers := []int64{9, 8, 7} + for i, power := range powers { + validators[i] = types.NewValidator(addrVals[i], PKs[i], types.Description{}) + validators[i].Status = sdk.Unbonded + validators[i].Tokens = sdk.ZeroInt() + tokens := sdk.TokensFromConsensusPower(power) + + validators[i], _ = validators[i].AddTokensFromDel(tokens) + } + assert.Equal(t, sdk.TokensFromConsensusPower(9), validators[0].Tokens) + assert.Equal(t, sdk.TokensFromConsensusPower(8), validators[1].Tokens) + assert.Equal(t, sdk.TokensFromConsensusPower(7), validators[2].Tokens) + + // check the empty keeper first + _, found := keeper.GetValidator(ctx, addrVals[0]) + require.False(t, found) + resVals := keeper.GetLastValidators(ctx) + require.Zero(t, len(resVals)) + + resVals = keeper.GetValidators(ctx, 2) + require.Zero(t, len(resVals)) + + // set and retrieve a record + validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], true) + keeper.SetValidatorByConsAddr(ctx, validators[0]) + resVal, found := keeper.GetValidator(ctx, addrVals[0]) + require.True(t, found) + assert.True(ValEq(t, validators[0], resVal)) + + // retrieve from consensus + resVal, found = keeper.GetValidatorByConsAddr(ctx, sdk.ConsAddress(PKs[0].Address())) + require.True(t, found) + assert.True(ValEq(t, validators[0], resVal)) + resVal, found = keeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(PKs[0])) + require.True(t, found) + assert.True(ValEq(t, validators[0], resVal)) + + resVals = keeper.GetLastValidators(ctx) + require.Equal(t, 1, len(resVals)) + assert.True(ValEq(t, validators[0], resVals[0])) + assert.Equal(t, sdk.Bonded, validators[0].Status) + assert.True(sdk.IntEq(t, sdk.TokensFromConsensusPower(9), validators[0].BondedTokens())) + + // modify a records, save, and retrieve + validators[0].Status = sdk.Bonded + validators[0].Tokens = sdk.TokensFromConsensusPower(10) + validators[0].DelegatorShares = validators[0].Tokens.ToDec() + validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], true) + resVal, found = keeper.GetValidator(ctx, addrVals[0]) + require.True(t, found) + assert.True(ValEq(t, validators[0], resVal)) + + resVals = keeper.GetLastValidators(ctx) + require.Equal(t, 1, len(resVals)) + assert.True(ValEq(t, validators[0], resVals[0])) + + // add other validators + validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], true) + validators[2] = TestingUpdateValidator(keeper, ctx, validators[2], true) + resVal, found = keeper.GetValidator(ctx, addrVals[1]) + require.True(t, found) + assert.True(ValEq(t, validators[1], resVal)) + resVal, found = keeper.GetValidator(ctx, addrVals[2]) + require.True(t, found) + assert.True(ValEq(t, validators[2], resVal)) + + resVals = keeper.GetLastValidators(ctx) + require.Equal(t, 3, len(resVals)) + assert.True(ValEq(t, validators[0], resVals[0])) // order doesn't matter here + assert.True(ValEq(t, validators[1], resVals[1])) + assert.True(ValEq(t, validators[2], resVals[2])) + + // remove a record + + // shouldn't be able to remove if status is not unbonded + assert.PanicsWithValue(t, + "cannot call RemoveValidator on bonded or unbonding validators", + func() { keeper.RemoveValidator(ctx, validators[1].OperatorAddress) }) + + // shouldn't be able to remove if there are still tokens left + validators[1].Status = sdk.Unbonded + keeper.SetValidator(ctx, validators[1]) + assert.PanicsWithValue(t, + "attempting to remove a validator which still contains tokens", + func() { keeper.RemoveValidator(ctx, validators[1].OperatorAddress) }) + + validators[1].Tokens = sdk.ZeroInt() // ...remove all tokens + keeper.SetValidator(ctx, validators[1]) // ...set the validator + keeper.RemoveValidator(ctx, validators[1].OperatorAddress) // Now it can be removed. + _, found = keeper.GetValidator(ctx, addrVals[1]) + require.False(t, found) +} + +// test how the validators are sorted, tests GetBondedValidatorsByPower +func TestGetValidatorSortingUnmixed(t *testing.T) { + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) + + // initialize some validators into the state + amts := []int64{ + 0, + 100 * sdk.PowerReduction.Int64(), + 1 * sdk.PowerReduction.Int64(), + 400 * sdk.PowerReduction.Int64(), + 200 * sdk.PowerReduction.Int64()} + n := len(amts) + var validators [5]types.Validator + for i, amt := range amts { + validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) + validators[i].Status = sdk.Bonded + validators[i].Tokens = sdk.NewInt(amt) + validators[i].DelegatorShares = sdk.NewDec(amt) + TestingUpdateValidator(keeper, ctx, validators[i], true) + } + + // first make sure everything made it in to the gotValidator group + resValidators := keeper.GetBondedValidatorsByPower(ctx) + assert.Equal(t, n, len(resValidators)) + assert.Equal(t, sdk.NewInt(400).Mul(sdk.PowerReduction), resValidators[0].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewInt(200).Mul(sdk.PowerReduction), resValidators[1].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewInt(100).Mul(sdk.PowerReduction), resValidators[2].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewInt(1).Mul(sdk.PowerReduction), resValidators[3].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewInt(0), resValidators[4].BondedTokens(), "%v", resValidators) + assert.Equal(t, validators[3].OperatorAddress, resValidators[0].OperatorAddress, "%v", resValidators) + assert.Equal(t, validators[4].OperatorAddress, resValidators[1].OperatorAddress, "%v", resValidators) + assert.Equal(t, validators[1].OperatorAddress, resValidators[2].OperatorAddress, "%v", resValidators) + assert.Equal(t, validators[2].OperatorAddress, resValidators[3].OperatorAddress, "%v", resValidators) + assert.Equal(t, validators[0].OperatorAddress, resValidators[4].OperatorAddress, "%v", resValidators) + + // test a basic increase in voting power + validators[3].Tokens = sdk.NewInt(500).Mul(sdk.PowerReduction) + TestingUpdateValidator(keeper, ctx, validators[3], true) + resValidators = keeper.GetBondedValidatorsByPower(ctx) + require.Equal(t, len(resValidators), n) + assert.True(ValEq(t, validators[3], resValidators[0])) + + // test a decrease in voting power + validators[3].Tokens = sdk.NewInt(300).Mul(sdk.PowerReduction) + TestingUpdateValidator(keeper, ctx, validators[3], true) + resValidators = keeper.GetBondedValidatorsByPower(ctx) + require.Equal(t, len(resValidators), n) + assert.True(ValEq(t, validators[3], resValidators[0])) + assert.True(ValEq(t, validators[4], resValidators[1])) + + // test equal voting power, different age + validators[3].Tokens = sdk.NewInt(200).Mul(sdk.PowerReduction) + ctx = ctx.WithBlockHeight(10) + TestingUpdateValidator(keeper, ctx, validators[3], true) + resValidators = keeper.GetBondedValidatorsByPower(ctx) + require.Equal(t, len(resValidators), n) + assert.True(ValEq(t, validators[3], resValidators[0])) + assert.True(ValEq(t, validators[4], resValidators[1])) + + // no change in voting power - no change in sort + ctx = ctx.WithBlockHeight(20) + TestingUpdateValidator(keeper, ctx, validators[4], true) + resValidators = keeper.GetBondedValidatorsByPower(ctx) + require.Equal(t, len(resValidators), n) + assert.True(ValEq(t, validators[3], resValidators[0])) + assert.True(ValEq(t, validators[4], resValidators[1])) + + // change in voting power of both validators, both still in v-set, no age change + validators[3].Tokens = sdk.NewInt(300).Mul(sdk.PowerReduction) + validators[4].Tokens = sdk.NewInt(300).Mul(sdk.PowerReduction) + TestingUpdateValidator(keeper, ctx, validators[3], true) + resValidators = keeper.GetBondedValidatorsByPower(ctx) + require.Equal(t, len(resValidators), n) + ctx = ctx.WithBlockHeight(30) + TestingUpdateValidator(keeper, ctx, validators[4], true) + resValidators = keeper.GetBondedValidatorsByPower(ctx) + require.Equal(t, len(resValidators), n, "%v", resValidators) + assert.True(ValEq(t, validators[3], resValidators[0])) + assert.True(ValEq(t, validators[4], resValidators[1])) +} + +func TestGetValidatorSortingMixed(t *testing.T) { + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 1000) + bondedPool := keeper.GetBondedPool(ctx) + notBondedPool := keeper.GetNotBondedPool(ctx) + + bk.SetBalances(ctx, bondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), sdk.TokensFromConsensusPower(501)))) + bk.SetBalances(ctx, notBondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), sdk.TokensFromConsensusPower(0)))) + keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) + keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) + + // now 2 max resValidators + params := keeper.GetParams(ctx) + params.MaxValidators = 2 + keeper.SetParams(ctx, params) + + // initialize some validators into the state + amts := []int64{ + 0, + 100 * sdk.PowerReduction.Int64(), + 1 * sdk.PowerReduction.Int64(), + 400 * sdk.PowerReduction.Int64(), + 200 * sdk.PowerReduction.Int64()} + + var validators [5]types.Validator + for i, amt := range amts { + validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) + validators[i].DelegatorShares = sdk.NewDec(amt) + validators[i].Status = sdk.Bonded + validators[i].Tokens = sdk.NewInt(amt) + TestingUpdateValidator(keeper, ctx, validators[i], true) + } + + val0, found := keeper.GetValidator(ctx, sdk.ValAddress(Addrs[0])) + require.True(t, found) + val1, found := keeper.GetValidator(ctx, sdk.ValAddress(Addrs[1])) + require.True(t, found) + val2, found := keeper.GetValidator(ctx, sdk.ValAddress(Addrs[2])) + require.True(t, found) + val3, found := keeper.GetValidator(ctx, sdk.ValAddress(Addrs[3])) + require.True(t, found) + val4, found := keeper.GetValidator(ctx, sdk.ValAddress(Addrs[4])) + require.True(t, found) + require.Equal(t, sdk.Bonded, val0.Status) + require.Equal(t, sdk.Unbonding, val1.Status) + require.Equal(t, sdk.Unbonding, val2.Status) + require.Equal(t, sdk.Bonded, val3.Status) + require.Equal(t, sdk.Bonded, val4.Status) + + // first make sure everything made it in to the gotValidator group + resValidators := keeper.GetBondedValidatorsByPower(ctx) + // The validators returned should match the max validators + assert.Equal(t, 2, len(resValidators)) + assert.Equal(t, sdk.NewInt(400).Mul(sdk.PowerReduction), resValidators[0].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewInt(200).Mul(sdk.PowerReduction), resValidators[1].BondedTokens(), "%v", resValidators) + assert.Equal(t, validators[3].OperatorAddress, resValidators[0].OperatorAddress, "%v", resValidators) + assert.Equal(t, validators[4].OperatorAddress, resValidators[1].OperatorAddress, "%v", resValidators) +} + +// TODO separate out into multiple tests +func TestGetValidatorsEdgeCases(t *testing.T) { + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 1000) + + // set max validators to 2 + params := keeper.GetParams(ctx) + nMax := uint32(2) + params.MaxValidators = nMax + keeper.SetParams(ctx, params) + + // initialize some validators into the state + powers := []int64{0, 100, 400, 400} + var validators [4]types.Validator + for i, power := range powers { + moniker := fmt.Sprintf("val#%d", int64(i)) + validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{Moniker: moniker}) + + tokens := sdk.TokensFromConsensusPower(power) + validators[i], _ = validators[i].AddTokensFromDel(tokens) + + notBondedPool := keeper.GetNotBondedPool(ctx) + balances := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) + require.NoError(t, bk.SetBalances(ctx, notBondedPool.GetAddress(), balances.Add(sdk.NewCoin(params.BondDenom, tokens)))) + + keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) + validators[i] = TestingUpdateValidator(keeper, ctx, validators[i], true) + } + + // ensure that the first two bonded validators are the largest validators + resValidators := keeper.GetBondedValidatorsByPower(ctx) + require.Equal(t, nMax, uint32(len(resValidators))) + assert.True(ValEq(t, validators[2], resValidators[0])) + assert.True(ValEq(t, validators[3], resValidators[1])) + + // delegate 500 tokens to validator 0 + keeper.DeleteValidatorByPowerIndex(ctx, validators[0]) + delTokens := sdk.TokensFromConsensusPower(500) + validators[0], _ = validators[0].AddTokensFromDel(delTokens) + notBondedPool := keeper.GetNotBondedPool(ctx) + + newTokens := sdk.NewCoins() + balances := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) + require.NoError(t, bk.SetBalances(ctx, notBondedPool.GetAddress(), balances.Add(newTokens...))) + keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) + + // test that the two largest validators are + // a) validator 0 with 500 tokens + // b) validator 2 with 400 tokens (delegated before validator 3) + validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], true) + resValidators = keeper.GetBondedValidatorsByPower(ctx) + require.Equal(t, nMax, uint32(len(resValidators))) + assert.True(ValEq(t, validators[0], resValidators[0])) + assert.True(ValEq(t, validators[2], resValidators[1])) + + // A validator which leaves the bonded validator set due to a decrease in voting power, + // then increases to the original voting power, does not get its spot back in the + // case of a tie. + // + // Order of operations for this test: + // - validator 3 enter validator set with 1 new token + // - validator 3 removed validator set by removing 201 tokens (validator 2 enters) + // - validator 3 adds 200 tokens (equal to validator 2 now) and does not get its spot back + + // validator 3 enters bonded validator set + ctx = ctx.WithBlockHeight(40) + + validators[3] = keeper.mustGetValidator(ctx, validators[3].OperatorAddress) + keeper.DeleteValidatorByPowerIndex(ctx, validators[3]) + validators[3], _ = validators[3].AddTokensFromDel(sdk.TokensFromConsensusPower(1)) + + notBondedPool = keeper.GetNotBondedPool(ctx) + newTokens = sdk.NewCoins(sdk.NewCoin(params.BondDenom, sdk.TokensFromConsensusPower(1))) + balances = bk.GetAllBalances(ctx, notBondedPool.GetAddress()) + require.NoError(t, bk.SetBalances(ctx, notBondedPool.GetAddress(), balances.Add(newTokens...))) + keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) + + validators[3] = TestingUpdateValidator(keeper, ctx, validators[3], true) + resValidators = keeper.GetBondedValidatorsByPower(ctx) + require.Equal(t, nMax, uint32(len(resValidators))) + assert.True(ValEq(t, validators[0], resValidators[0])) + assert.True(ValEq(t, validators[3], resValidators[1])) + + // validator 3 kicked out temporarily + keeper.DeleteValidatorByPowerIndex(ctx, validators[3]) + rmTokens := validators[3].TokensFromShares(sdk.NewDec(201)).TruncateInt() + validators[3], _ = validators[3].RemoveDelShares(sdk.NewDec(201)) + + bondedPool := keeper.GetBondedPool(ctx) + balances = bk.GetAllBalances(ctx, bondedPool.GetAddress()) + require.NoError(t, bk.SetBalances(ctx, bondedPool.GetAddress(), balances.Add(sdk.NewCoin(params.BondDenom, rmTokens)))) + keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) + + validators[3] = TestingUpdateValidator(keeper, ctx, validators[3], true) + resValidators = keeper.GetBondedValidatorsByPower(ctx) + require.Equal(t, nMax, uint32(len(resValidators))) + assert.True(ValEq(t, validators[0], resValidators[0])) + assert.True(ValEq(t, validators[2], resValidators[1])) + + // validator 3 does not get spot back + keeper.DeleteValidatorByPowerIndex(ctx, validators[3]) + validators[3], _ = validators[3].AddTokensFromDel(sdk.NewInt(200)) + + notBondedPool = keeper.GetNotBondedPool(ctx) + balances = bk.GetAllBalances(ctx, notBondedPool.GetAddress()) + require.NoError(t, bk.SetBalances(ctx, notBondedPool.GetAddress(), balances.Add(sdk.NewCoin(params.BondDenom, sdk.NewInt(200))))) + keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) + + validators[3] = TestingUpdateValidator(keeper, ctx, validators[3], true) + resValidators = keeper.GetBondedValidatorsByPower(ctx) + require.Equal(t, nMax, uint32(len(resValidators))) + assert.True(ValEq(t, validators[0], resValidators[0])) + assert.True(ValEq(t, validators[2], resValidators[1])) + _, exists := keeper.GetValidator(ctx, validators[3].OperatorAddress) + require.True(t, exists) +} + +func TestValidatorBondHeight(t *testing.T) { + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) + + // now 2 max resValidators + params := keeper.GetParams(ctx) + params.MaxValidators = 2 + keeper.SetParams(ctx, params) + + // initialize some validators into the state + var validators [3]types.Validator + validators[0] = types.NewValidator(sdk.ValAddress(PKs[0].Address().Bytes()), PKs[0], types.Description{}) + validators[1] = types.NewValidator(sdk.ValAddress(Addrs[1]), PKs[1], types.Description{}) + validators[2] = types.NewValidator(sdk.ValAddress(Addrs[2]), PKs[2], types.Description{}) + + tokens0 := sdk.TokensFromConsensusPower(200) + tokens1 := sdk.TokensFromConsensusPower(100) + tokens2 := sdk.TokensFromConsensusPower(100) + validators[0], _ = validators[0].AddTokensFromDel(tokens0) + validators[1], _ = validators[1].AddTokensFromDel(tokens1) + validators[2], _ = validators[2].AddTokensFromDel(tokens2) + + validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], true) + + //////////////////////////////////////// + // If two validators both increase to the same voting power in the same block, + // the one with the first transaction should become bonded + validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], true) + validators[2] = TestingUpdateValidator(keeper, ctx, validators[2], true) + + resValidators := keeper.GetBondedValidatorsByPower(ctx) + require.Equal(t, uint32(len(resValidators)), params.MaxValidators) + + assert.True(ValEq(t, validators[0], resValidators[0])) + assert.True(ValEq(t, validators[1], resValidators[1])) + keeper.DeleteValidatorByPowerIndex(ctx, validators[1]) + keeper.DeleteValidatorByPowerIndex(ctx, validators[2]) + delTokens := sdk.TokensFromConsensusPower(50) + validators[1], _ = validators[1].AddTokensFromDel(delTokens) + validators[2], _ = validators[2].AddTokensFromDel(delTokens) + validators[2] = TestingUpdateValidator(keeper, ctx, validators[2], true) + resValidators = keeper.GetBondedValidatorsByPower(ctx) + require.Equal(t, params.MaxValidators, uint32(len(resValidators))) + validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], true) + assert.True(ValEq(t, validators[0], resValidators[0])) + assert.True(ValEq(t, validators[2], resValidators[1])) +} + +func TestFullValidatorSetPowerChange(t *testing.T) { + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) + params := keeper.GetParams(ctx) + max := 2 + params.MaxValidators = uint32(2) + keeper.SetParams(ctx, params) + + // initialize some validators into the state + powers := []int64{0, 100, 400, 400, 200} + var validators [5]types.Validator + for i, power := range powers { + validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) + tokens := sdk.TokensFromConsensusPower(power) + validators[i], _ = validators[i].AddTokensFromDel(tokens) + TestingUpdateValidator(keeper, ctx, validators[i], true) + } + for i := range powers { + var found bool + validators[i], found = keeper.GetValidator(ctx, validators[i].OperatorAddress) + require.True(t, found) + } + assert.Equal(t, sdk.Unbonded, validators[0].Status) + assert.Equal(t, sdk.Unbonding, validators[1].Status) + assert.Equal(t, sdk.Bonded, validators[2].Status) + assert.Equal(t, sdk.Bonded, validators[3].Status) + assert.Equal(t, sdk.Unbonded, validators[4].Status) + resValidators := keeper.GetBondedValidatorsByPower(ctx) + assert.Equal(t, max, len(resValidators)) + assert.True(ValEq(t, validators[2], resValidators[0])) // in the order of txs + assert.True(ValEq(t, validators[3], resValidators[1])) + + // test a swap in voting power + + tokens := sdk.TokensFromConsensusPower(600) + validators[0], _ = validators[0].AddTokensFromDel(tokens) + validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], true) + resValidators = keeper.GetBondedValidatorsByPower(ctx) + assert.Equal(t, max, len(resValidators)) + assert.True(ValEq(t, validators[0], resValidators[0])) + assert.True(ValEq(t, validators[2], resValidators[1])) +} + +func TestApplyAndReturnValidatorSetUpdatesAllNone(t *testing.T) { + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) + + powers := []int64{10, 20} + var validators [2]types.Validator + for i, power := range powers { + valPubKey := PKs[i+1] + valAddr := sdk.ValAddress(valPubKey.Address().Bytes()) + + validators[i] = types.NewValidator(valAddr, valPubKey, types.Description{}) + tokens := sdk.TokensFromConsensusPower(power) + validators[i], _ = validators[i].AddTokensFromDel(tokens) + } + + // test from nothing to something + // tendermintUpdate set: {} -> {c1, c3} + require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) + keeper.SetValidator(ctx, validators[0]) + keeper.SetValidatorByPowerIndex(ctx, validators[0]) + keeper.SetValidator(ctx, validators[1]) + keeper.SetValidatorByPowerIndex(ctx, validators[1]) + + updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) + assert.Equal(t, 2, len(updates)) + validators[0], _ = keeper.GetValidator(ctx, validators[0].OperatorAddress) + validators[1], _ = keeper.GetValidator(ctx, validators[1].OperatorAddress) + assert.Equal(t, validators[0].ABCIValidatorUpdate(), updates[1]) + assert.Equal(t, validators[1].ABCIValidatorUpdate(), updates[0]) +} + +func TestApplyAndReturnValidatorSetUpdatesIdentical(t *testing.T) { + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) + + powers := []int64{10, 20} + var validators [2]types.Validator + for i, power := range powers { + validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) + + tokens := sdk.TokensFromConsensusPower(power) + validators[i], _ = validators[i].AddTokensFromDel(tokens) + + } + validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], false) + validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], false) + require.Equal(t, 2, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) + + // test identical, + // tendermintUpdate set: {} -> {} + validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], false) + validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], false) + require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) +} + +func TestApplyAndReturnValidatorSetUpdatesSingleValueChange(t *testing.T) { + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) + + powers := []int64{10, 20} + var validators [2]types.Validator + for i, power := range powers { + + validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) + + tokens := sdk.TokensFromConsensusPower(power) + validators[i], _ = validators[i].AddTokensFromDel(tokens) + + } + validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], false) + validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], false) + require.Equal(t, 2, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) + + // test single value change + // tendermintUpdate set: {} -> {c1'} + validators[0].Status = sdk.Bonded + validators[0].Tokens = sdk.TokensFromConsensusPower(600) + validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], false) + + updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) + + require.Equal(t, 1, len(updates)) + require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[0]) +} + +func TestApplyAndReturnValidatorSetUpdatesMultipleValueChange(t *testing.T) { + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) + + powers := []int64{10, 20} + var validators [2]types.Validator + for i, power := range powers { + + validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) + + tokens := sdk.TokensFromConsensusPower(power) + validators[i], _ = validators[i].AddTokensFromDel(tokens) + + } + validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], false) + validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], false) + require.Equal(t, 2, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) + + // test multiple value change + // tendermintUpdate set: {c1, c3} -> {c1', c3'} + delTokens1 := sdk.TokensFromConsensusPower(190) + delTokens2 := sdk.TokensFromConsensusPower(80) + validators[0], _ = validators[0].AddTokensFromDel(delTokens1) + validators[1], _ = validators[1].AddTokensFromDel(delTokens2) + validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], false) + validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], false) + + updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 2, len(updates)) + require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[0]) + require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[1]) +} + +func TestApplyAndReturnValidatorSetUpdatesInserted(t *testing.T) { + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) + + powers := []int64{10, 20, 5, 15, 25} + var validators [5]types.Validator + for i, power := range powers { + + validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) + + tokens := sdk.TokensFromConsensusPower(power) + validators[i], _ = validators[i].AddTokensFromDel(tokens) + + } + + validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], false) + validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], false) + require.Equal(t, 2, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) + + // test validtor added at the beginning + // tendermintUpdate set: {} -> {c0} + keeper.SetValidator(ctx, validators[2]) + keeper.SetValidatorByPowerIndex(ctx, validators[2]) + updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) + validators[2], _ = keeper.GetValidator(ctx, validators[2].OperatorAddress) + require.Equal(t, 1, len(updates)) + require.Equal(t, validators[2].ABCIValidatorUpdate(), updates[0]) + + // test validtor added at the beginning + // tendermintUpdate set: {} -> {c0} + keeper.SetValidator(ctx, validators[3]) + keeper.SetValidatorByPowerIndex(ctx, validators[3]) + updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx) + validators[3], _ = keeper.GetValidator(ctx, validators[3].OperatorAddress) + require.Equal(t, 1, len(updates)) + require.Equal(t, validators[3].ABCIValidatorUpdate(), updates[0]) + + // test validtor added at the end + // tendermintUpdate set: {} -> {c0} + keeper.SetValidator(ctx, validators[4]) + keeper.SetValidatorByPowerIndex(ctx, validators[4]) + updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx) + validators[4], _ = keeper.GetValidator(ctx, validators[4].OperatorAddress) + require.Equal(t, 1, len(updates)) + require.Equal(t, validators[4].ABCIValidatorUpdate(), updates[0]) +} + +func TestApplyAndReturnValidatorSetUpdatesWithCliffValidator(t *testing.T) { + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) + params := types.DefaultParams() + params.MaxValidators = 2 + keeper.SetParams(ctx, params) + + powers := []int64{10, 20, 5} + var validators [5]types.Validator + for i, power := range powers { + + validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) + + tokens := sdk.TokensFromConsensusPower(power) + validators[i], _ = validators[i].AddTokensFromDel(tokens) + + } + validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], false) + validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], false) + require.Equal(t, 2, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) + + // test validator added at the end but not inserted in the valset + // tendermintUpdate set: {} -> {} + TestingUpdateValidator(keeper, ctx, validators[2], false) + updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 0, len(updates)) + + // test validator change its power and become a gotValidator (pushing out an existing) + // tendermintUpdate set: {} -> {c0, c4} + require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) + + tokens := sdk.TokensFromConsensusPower(10) + validators[2], _ = validators[2].AddTokensFromDel(tokens) + keeper.SetValidator(ctx, validators[2]) + keeper.SetValidatorByPowerIndex(ctx, validators[2]) + updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx) + validators[2], _ = keeper.GetValidator(ctx, validators[2].OperatorAddress) + require.Equal(t, 2, len(updates), "%v", updates) + require.Equal(t, validators[0].ABCIValidatorUpdateZero(), updates[1]) + require.Equal(t, validators[2].ABCIValidatorUpdate(), updates[0]) +} + +func TestApplyAndReturnValidatorSetUpdatesPowerDecrease(t *testing.T) { + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) + + powers := []int64{100, 100} + var validators [2]types.Validator + for i, power := range powers { + + validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) + + tokens := sdk.TokensFromConsensusPower(power) + validators[i], _ = validators[i].AddTokensFromDel(tokens) + + } + validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], false) + validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], false) + require.Equal(t, 2, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) + + // check initial power + require.Equal(t, int64(100), validators[0].GetConsensusPower()) + require.Equal(t, int64(100), validators[1].GetConsensusPower()) + + // test multiple value change + // tendermintUpdate set: {c1, c3} -> {c1', c3'} + delTokens1 := sdk.TokensFromConsensusPower(20) + delTokens2 := sdk.TokensFromConsensusPower(30) + validators[0], _ = validators[0].RemoveDelShares(delTokens1.ToDec()) + validators[1], _ = validators[1].RemoveDelShares(delTokens2.ToDec()) + validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], false) + validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], false) + + // power has changed + require.Equal(t, int64(80), validators[0].GetConsensusPower()) + require.Equal(t, int64(70), validators[1].GetConsensusPower()) + + // Tendermint updates should reflect power change + updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 2, len(updates)) + require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[0]) + require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[1]) +} + +func TestApplyAndReturnValidatorSetUpdatesNewValidator(t *testing.T) { + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) + params := keeper.GetParams(ctx) + params.MaxValidators = uint32(3) + + keeper.SetParams(ctx, params) + + powers := []int64{100, 100} + var validators [2]types.Validator + + // initialize some validators into the state + for i, power := range powers { + + valPubKey := PKs[i+1] + valAddr := sdk.ValAddress(valPubKey.Address().Bytes()) + + validators[i] = types.NewValidator(valAddr, valPubKey, types.Description{}) + tokens := sdk.TokensFromConsensusPower(power) + validators[i], _ = validators[i].AddTokensFromDel(tokens) + + keeper.SetValidator(ctx, validators[i]) + keeper.SetValidatorByPowerIndex(ctx, validators[i]) + } + + // verify initial Tendermint updates are correct + updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, len(validators), len(updates)) + validators[0], _ = keeper.GetValidator(ctx, validators[0].OperatorAddress) + validators[1], _ = keeper.GetValidator(ctx, validators[1].OperatorAddress) + require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[0]) + require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[1]) + + require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) + + // update initial validator set + for i, power := range powers { + + keeper.DeleteValidatorByPowerIndex(ctx, validators[i]) + tokens := sdk.TokensFromConsensusPower(power) + validators[i], _ = validators[i].AddTokensFromDel(tokens) + + keeper.SetValidator(ctx, validators[i]) + keeper.SetValidatorByPowerIndex(ctx, validators[i]) + } + + // add a new validator that goes from zero power, to non-zero power, back to + // zero power + valPubKey := PKs[len(validators)+1] + valAddr := sdk.ValAddress(valPubKey.Address().Bytes()) + amt := sdk.NewInt(100) + + validator := types.NewValidator(valAddr, valPubKey, types.Description{}) + validator, _ = validator.AddTokensFromDel(amt) + + keeper.SetValidator(ctx, validator) + + validator, _ = validator.RemoveDelShares(amt.ToDec()) + keeper.SetValidator(ctx, validator) + keeper.SetValidatorByPowerIndex(ctx, validator) + + // add a new validator that increases in power + valPubKey = PKs[len(validators)+2] + valAddr = sdk.ValAddress(valPubKey.Address().Bytes()) + + validator = types.NewValidator(valAddr, valPubKey, types.Description{}) + tokens := sdk.TokensFromConsensusPower(500) + validator, _ = validator.AddTokensFromDel(tokens) + keeper.SetValidator(ctx, validator) + keeper.SetValidatorByPowerIndex(ctx, validator) + + // verify initial Tendermint updates are correct + updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx) + validator, _ = keeper.GetValidator(ctx, validator.OperatorAddress) + validators[0], _ = keeper.GetValidator(ctx, validators[0].OperatorAddress) + validators[1], _ = keeper.GetValidator(ctx, validators[1].OperatorAddress) + require.Equal(t, len(validators)+1, len(updates)) + require.Equal(t, validator.ABCIValidatorUpdate(), updates[0]) + require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[1]) + require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[2]) +} + +func TestApplyAndReturnValidatorSetUpdatesBondTransition(t *testing.T) { + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) + params := keeper.GetParams(ctx) + params.MaxValidators = uint32(2) + + keeper.SetParams(ctx, params) + + powers := []int64{100, 200, 300} + var validators [3]types.Validator + + // initialize some validators into the state + for i, power := range powers { + moniker := fmt.Sprintf("%d", i) + valPubKey := PKs[i+1] + valAddr := sdk.ValAddress(valPubKey.Address().Bytes()) + + validators[i] = types.NewValidator(valAddr, valPubKey, types.Description{Moniker: moniker}) + tokens := sdk.TokensFromConsensusPower(power) + validators[i], _ = validators[i].AddTokensFromDel(tokens) + keeper.SetValidator(ctx, validators[i]) + keeper.SetValidatorByPowerIndex(ctx, validators[i]) + } + + // verify initial Tendermint updates are correct + updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 2, len(updates)) + validators[2], _ = keeper.GetValidator(ctx, validators[2].OperatorAddress) + validators[1], _ = keeper.GetValidator(ctx, validators[1].OperatorAddress) + require.Equal(t, validators[2].ABCIValidatorUpdate(), updates[0]) + require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[1]) + + require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) + + // delegate to validator with lowest power but not enough to bond + ctx = ctx.WithBlockHeight(1) + + var found bool + validators[0], found = keeper.GetValidator(ctx, validators[0].OperatorAddress) + require.True(t, found) + + keeper.DeleteValidatorByPowerIndex(ctx, validators[0]) + tokens := sdk.TokensFromConsensusPower(1) + validators[0], _ = validators[0].AddTokensFromDel(tokens) + keeper.SetValidator(ctx, validators[0]) + keeper.SetValidatorByPowerIndex(ctx, validators[0]) + + // verify initial Tendermint updates are correct + require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) + + // create a series of events that will bond and unbond the validator with + // lowest power in a single block context (height) + ctx = ctx.WithBlockHeight(2) + + validators[1], found = keeper.GetValidator(ctx, validators[1].OperatorAddress) + require.True(t, found) + + keeper.DeleteValidatorByPowerIndex(ctx, validators[0]) + validators[0], _ = validators[0].RemoveDelShares(validators[0].DelegatorShares) + keeper.SetValidator(ctx, validators[0]) + keeper.SetValidatorByPowerIndex(ctx, validators[0]) + updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 0, len(updates)) + + keeper.DeleteValidatorByPowerIndex(ctx, validators[1]) + tokens = sdk.TokensFromConsensusPower(250) + validators[1], _ = validators[1].AddTokensFromDel(tokens) + keeper.SetValidator(ctx, validators[1]) + keeper.SetValidatorByPowerIndex(ctx, validators[1]) + + // verify initial Tendermint updates are correct + updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 1, len(updates)) + require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[0]) + + require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) +} + +func TestUpdateValidatorCommission(t *testing.T) { + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) + ctx = ctx.WithBlockHeader(abci.Header{Time: time.Now().UTC()}) + + commission1 := types.NewCommissionWithTime( + sdk.NewDecWithPrec(1, 1), sdk.NewDecWithPrec(3, 1), + sdk.NewDecWithPrec(1, 1), time.Now().UTC().Add(time.Duration(-1)*time.Hour), + ) + commission2 := types.NewCommission(sdk.NewDecWithPrec(1, 1), sdk.NewDecWithPrec(3, 1), sdk.NewDecWithPrec(1, 1)) + + val1 := types.NewValidator(addrVals[0], PKs[0], types.Description{}) + val2 := types.NewValidator(addrVals[1], PKs[1], types.Description{}) + + val1, _ = val1.SetInitialCommission(commission1) + val2, _ = val2.SetInitialCommission(commission2) + + keeper.SetValidator(ctx, val1) + keeper.SetValidator(ctx, val2) + + testCases := []struct { + validator types.Validator + newRate sdk.Dec + expectedErr bool + }{ + {val1, sdk.ZeroDec(), true}, + {val2, sdk.NewDecWithPrec(-1, 1), true}, + {val2, sdk.NewDecWithPrec(4, 1), true}, + {val2, sdk.NewDecWithPrec(3, 1), true}, + {val2, sdk.NewDecWithPrec(2, 1), false}, + } + + for i, tc := range testCases { + commission, err := keeper.UpdateValidatorCommission(ctx, tc.validator, tc.newRate) + + if tc.expectedErr { + require.Error(t, err, "expected error for test case #%d with rate: %s", i, tc.newRate) + } else { + tc.validator.Commission = commission + keeper.SetValidator(ctx, tc.validator) + val, found := keeper.GetValidator(ctx, tc.validator.OperatorAddress) + + require.True(t, found, + "expected to find validator for test case #%d with rate: %s", i, tc.newRate, + ) + require.NoError(t, err, + "unexpected error for test case #%d with rate: %s", i, tc.newRate, + ) + require.Equal(t, tc.newRate, val.Commission.Rate, + "expected new validator commission rate for test case #%d with rate: %s", i, tc.newRate, + ) + require.Equal(t, ctx.BlockHeader().Time, val.Commission.UpdateTime, + "expected new validator commission update time for test case #%d with rate: %s", i, tc.newRate, + ) + } + } +} diff --git a/x/staking/keeper/slash_test.go b/x/staking/keeper/slash_test.go index 77296c19725e..fae13244c992 100644 --- a/x/staking/keeper/slash_test.go +++ b/x/staking/keeper/slash_test.go @@ -50,14 +50,6 @@ func bootstrapSlashTest(t *testing.T, power int64) (*simapp.SimApp, sdk.Context, return app, ctx, addrDels, addrVals } -// generateAddresses generates numAddrs of normal AccAddrs and ValAddrs -func generateAddresses(app *simapp.SimApp, ctx sdk.Context, numAddrs int) ([]sdk.AccAddress, []sdk.ValAddress) { - addrDels := simapp.AddTestAddrsIncremental(app, ctx, numAddrs, sdk.NewInt(10000)) - addrVals := simapp.ConvertAddrsToValAddrs(addrDels) - - return addrDels, addrVals -} - // tests Jail, Unjail func TestRevocation(t *testing.T) { app, ctx, _, addrVals := bootstrapSlashTest(t, 5) diff --git a/x/staking/keeper/test_common_test.go b/x/staking/keeper/test_common_test.go index 2275aff100fb..a32f3a7c0325 100644 --- a/x/staking/keeper/test_common_test.go +++ b/x/staking/keeper/test_common_test.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/hex" "strconv" + "testing" "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/ed25519" @@ -13,6 +14,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/staking" "github.com/cosmos/cosmos-sdk/x/staking/keeper" + "github.com/cosmos/cosmos-sdk/x/staking/types" abci "github.com/tendermint/tendermint/abci/types" ) @@ -65,3 +67,17 @@ func getBaseSimappWithCustomKeeper() (*codec.Codec, *simapp.SimApp, sdk.Context) return cdc, app, ctx } + +// intended to be used with require/assert: require.True(ValEq(...)) +func ValEq(t *testing.T, exp, got types.Validator) (*testing.T, bool, string, types.Validator, types.Validator) { + return t, exp.MinEqual(got), "expected:\n%v\ngot:\n%v", exp, got +} + +// generateAddresses generates numAddrs of normal AccAddrs and ValAddrs +func generateAddresses(app *simapp.SimApp, ctx sdk.Context, numAddrs int) ([]sdk.AccAddress, []sdk.ValAddress) { + addrDels := simapp.AddTestAddrsIncremental(app, ctx, numAddrs, sdk.NewInt(10000)) + addrVals := simapp.ConvertAddrsToValAddrs(addrDels) + + return addrDels, addrVals +} + diff --git a/x/staking/keeper/validator_test.go b/x/staking/keeper/validator_test.go index 1b4d8f6a5ac8..de9c84b10cc3 100644 --- a/x/staking/keeper/validator_test.go +++ b/x/staking/keeper/validator_test.go @@ -1,22 +1,35 @@ -package keeper +package keeper_test import ( - "fmt" "testing" - "time" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/cosmos/cosmos-sdk/simapp" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/staking/types" ) -//_______________________________________________________ +func bootstrapValidatorTest(t *testing.T, power int64) (*simapp.SimApp, sdk.Context, []sdk.AccAddress, []sdk.ValAddress) { + _, app, ctx := getBaseSimappWithCustomKeeper() + + addrDels, addrVals := generateAddresses(app, ctx, 100) + + amt := sdk.TokensFromConsensusPower(power) + totalSupply := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), amt.MulRaw(int64(len(addrDels))))) + + notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) + err := app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), totalSupply) + require.NoError(t, err) + app.SupplyKeeper.SetModuleAccount(ctx, notBondedPool) + + return app, ctx, addrDels, addrVals +} func TestSetValidator(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 10) + app, ctx, _, _ := bootstrapValidatorTest(t, 10) valPubKey := PKs[0] valAddr := sdk.ValAddress(valPubKey.Address().Bytes()) @@ -28,12 +41,12 @@ func TestSetValidator(t *testing.T) { require.Equal(t, sdk.Unbonded, validator.Status) assert.Equal(t, valTokens, validator.Tokens) assert.Equal(t, valTokens, validator.DelegatorShares.RoundInt()) - keeper.SetValidator(ctx, validator) - keeper.SetValidatorByPowerIndex(ctx, validator) + app.StakingKeeper.SetValidator(ctx, validator) + app.StakingKeeper.SetValidatorByPowerIndex(ctx, validator) // ensure update - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - validator, found := keeper.GetValidator(ctx, valAddr) + updates := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + validator, found := app.StakingKeeper.GetValidator(ctx, valAddr) require.True(t, found) require.Equal(t, 1, len(updates)) require.Equal(t, validator.ABCIValidatorUpdate(), updates[0]) @@ -44,1050 +57,26 @@ func TestSetValidator(t *testing.T) { assert.Equal(t, valTokens, validator.DelegatorShares.RoundInt()) // Check each store for being saved - resVal, found := keeper.GetValidator(ctx, valAddr) + resVal, found := app.StakingKeeper.GetValidator(ctx, valAddr) assert.True(ValEq(t, validator, resVal)) require.True(t, found) - resVals := keeper.GetLastValidators(ctx) + resVals := app.StakingKeeper.GetLastValidators(ctx) require.Equal(t, 1, len(resVals)) assert.True(ValEq(t, validator, resVals[0])) - resVals = keeper.GetBondedValidatorsByPower(ctx) + resVals = app.StakingKeeper.GetBondedValidatorsByPower(ctx) require.Equal(t, 1, len(resVals)) require.True(ValEq(t, validator, resVals[0])) - resVals = keeper.GetValidators(ctx, 1) + resVals = app.StakingKeeper.GetValidators(ctx, 1) require.Equal(t, 1, len(resVals)) require.True(ValEq(t, validator, resVals[0])) - resVals = keeper.GetValidators(ctx, 10) + resVals = app.StakingKeeper.GetValidators(ctx, 10) require.Equal(t, 1, len(resVals)) require.True(ValEq(t, validator, resVals[0])) - allVals := keeper.GetAllValidators(ctx) + allVals := app.StakingKeeper.GetAllValidators(ctx) require.Equal(t, 1, len(allVals)) } - -func TestUpdateValidatorByPowerIndex(t *testing.T) { - ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) - - bondedPool := keeper.GetBondedPool(ctx) - notBondedPool := keeper.GetNotBondedPool(ctx) - bk.SetBalances(ctx, bondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), sdk.TokensFromConsensusPower(1234)))) - bk.SetBalances(ctx, notBondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), sdk.TokensFromConsensusPower(10000)))) - keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) - keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) - - // add a validator - validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) - validator, delSharesCreated := validator.AddTokensFromDel(sdk.TokensFromConsensusPower(100)) - require.Equal(t, sdk.Unbonded, validator.Status) - require.Equal(t, sdk.TokensFromConsensusPower(100), validator.Tokens) - TestingUpdateValidator(keeper, ctx, validator, true) - validator, found := keeper.GetValidator(ctx, addrVals[0]) - require.True(t, found) - require.Equal(t, sdk.TokensFromConsensusPower(100), validator.Tokens) - - power := types.GetValidatorsByPowerIndexKey(validator) - require.True(t, validatorByPowerIndexExists(keeper, ctx, power)) - - // burn half the delegator shares - keeper.DeleteValidatorByPowerIndex(ctx, validator) - validator, burned := validator.RemoveDelShares(delSharesCreated.Quo(sdk.NewDec(2))) - require.Equal(t, sdk.TokensFromConsensusPower(50), burned) - TestingUpdateValidator(keeper, ctx, validator, true) // update the validator, possibly kicking it out - require.False(t, validatorByPowerIndexExists(keeper, ctx, power)) - - validator, found = keeper.GetValidator(ctx, addrVals[0]) - require.True(t, found) - - power = types.GetValidatorsByPowerIndexKey(validator) - require.True(t, validatorByPowerIndexExists(keeper, ctx, power)) -} - -func TestUpdateBondedValidatorsDecreaseCliff(t *testing.T) { - numVals := 10 - maxVals := 5 - - // create context, keeper, and pool for tests - ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) - bondedPool := keeper.GetBondedPool(ctx) - notBondedPool := keeper.GetNotBondedPool(ctx) - - // create keeper parameters - params := keeper.GetParams(ctx) - params.MaxValidators = uint32(maxVals) - keeper.SetParams(ctx, params) - - // create a random pool - bk.SetBalances(ctx, bondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), sdk.TokensFromConsensusPower(1234)))) - bk.SetBalances(ctx, notBondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), sdk.TokensFromConsensusPower(10000)))) - keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) - keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) - - validators := make([]types.Validator, numVals) - for i := 0; i < len(validators); i++ { - moniker := fmt.Sprintf("val#%d", int64(i)) - val := types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{Moniker: moniker}) - delTokens := sdk.TokensFromConsensusPower(int64((i + 1) * 10)) - val, _ = val.AddTokensFromDel(delTokens) - - val = TestingUpdateValidator(keeper, ctx, val, true) - validators[i] = val - } - - nextCliffVal := validators[numVals-maxVals+1] - - // remove enough tokens to kick out the validator below the current cliff - // validator and next in line cliff validator - keeper.DeleteValidatorByPowerIndex(ctx, nextCliffVal) - shares := sdk.TokensFromConsensusPower(21) - nextCliffVal, _ = nextCliffVal.RemoveDelShares(shares.ToDec()) - nextCliffVal = TestingUpdateValidator(keeper, ctx, nextCliffVal, true) - - expectedValStatus := map[int]sdk.BondStatus{ - 9: sdk.Bonded, 8: sdk.Bonded, 7: sdk.Bonded, 5: sdk.Bonded, 4: sdk.Bonded, - 0: sdk.Unbonding, 1: sdk.Unbonding, 2: sdk.Unbonding, 3: sdk.Unbonding, 6: sdk.Unbonding, - } - - // require all the validators have their respective statuses - for valIdx, status := range expectedValStatus { - valAddr := validators[valIdx].OperatorAddress - val, _ := keeper.GetValidator(ctx, valAddr) - - assert.Equal( - t, status, val.GetStatus(), - fmt.Sprintf("expected validator at index %v to have status: %s", valIdx, status), - ) - } -} - -func TestSlashToZeroPowerRemoved(t *testing.T) { - // initialize setup - ctx, _, bk, keeper, _ := CreateTestInput(t, false, 100) - - // add a validator - validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) - valTokens := sdk.TokensFromConsensusPower(100) - - bondedPool := keeper.GetBondedPool(ctx) - err := bk.SetBalances(ctx, bondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), valTokens))) - require.NoError(t, err) - keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) - - validator, _ = validator.AddTokensFromDel(valTokens) - require.Equal(t, sdk.Unbonded, validator.Status) - require.Equal(t, valTokens, validator.Tokens) - keeper.SetValidatorByConsAddr(ctx, validator) - validator = TestingUpdateValidator(keeper, ctx, validator, true) - require.Equal(t, valTokens, validator.Tokens, "\nvalidator %v\npool %v", validator, valTokens) - - // slash the validator by 100% - consAddr0 := sdk.ConsAddress(PKs[0].Address()) - keeper.Slash(ctx, consAddr0, 0, 100, sdk.OneDec()) - // apply TM updates - keeper.ApplyAndReturnValidatorSetUpdates(ctx) - // validator should be unbonding - validator, _ = keeper.GetValidator(ctx, addrVals[0]) - require.Equal(t, validator.GetStatus(), sdk.Unbonding) -} - -// This function tests UpdateValidator, GetValidator, GetLastValidators, RemoveValidator -func TestValidatorBasics(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - - //construct the validators - var validators [3]types.Validator - powers := []int64{9, 8, 7} - for i, power := range powers { - validators[i] = types.NewValidator(addrVals[i], PKs[i], types.Description{}) - validators[i].Status = sdk.Unbonded - validators[i].Tokens = sdk.ZeroInt() - tokens := sdk.TokensFromConsensusPower(power) - - validators[i], _ = validators[i].AddTokensFromDel(tokens) - } - assert.Equal(t, sdk.TokensFromConsensusPower(9), validators[0].Tokens) - assert.Equal(t, sdk.TokensFromConsensusPower(8), validators[1].Tokens) - assert.Equal(t, sdk.TokensFromConsensusPower(7), validators[2].Tokens) - - // check the empty keeper first - _, found := keeper.GetValidator(ctx, addrVals[0]) - require.False(t, found) - resVals := keeper.GetLastValidators(ctx) - require.Zero(t, len(resVals)) - - resVals = keeper.GetValidators(ctx, 2) - require.Zero(t, len(resVals)) - - // set and retrieve a record - validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], true) - keeper.SetValidatorByConsAddr(ctx, validators[0]) - resVal, found := keeper.GetValidator(ctx, addrVals[0]) - require.True(t, found) - assert.True(ValEq(t, validators[0], resVal)) - - // retrieve from consensus - resVal, found = keeper.GetValidatorByConsAddr(ctx, sdk.ConsAddress(PKs[0].Address())) - require.True(t, found) - assert.True(ValEq(t, validators[0], resVal)) - resVal, found = keeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(PKs[0])) - require.True(t, found) - assert.True(ValEq(t, validators[0], resVal)) - - resVals = keeper.GetLastValidators(ctx) - require.Equal(t, 1, len(resVals)) - assert.True(ValEq(t, validators[0], resVals[0])) - assert.Equal(t, sdk.Bonded, validators[0].Status) - assert.True(sdk.IntEq(t, sdk.TokensFromConsensusPower(9), validators[0].BondedTokens())) - - // modify a records, save, and retrieve - validators[0].Status = sdk.Bonded - validators[0].Tokens = sdk.TokensFromConsensusPower(10) - validators[0].DelegatorShares = validators[0].Tokens.ToDec() - validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], true) - resVal, found = keeper.GetValidator(ctx, addrVals[0]) - require.True(t, found) - assert.True(ValEq(t, validators[0], resVal)) - - resVals = keeper.GetLastValidators(ctx) - require.Equal(t, 1, len(resVals)) - assert.True(ValEq(t, validators[0], resVals[0])) - - // add other validators - validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], true) - validators[2] = TestingUpdateValidator(keeper, ctx, validators[2], true) - resVal, found = keeper.GetValidator(ctx, addrVals[1]) - require.True(t, found) - assert.True(ValEq(t, validators[1], resVal)) - resVal, found = keeper.GetValidator(ctx, addrVals[2]) - require.True(t, found) - assert.True(ValEq(t, validators[2], resVal)) - - resVals = keeper.GetLastValidators(ctx) - require.Equal(t, 3, len(resVals)) - assert.True(ValEq(t, validators[0], resVals[0])) // order doesn't matter here - assert.True(ValEq(t, validators[1], resVals[1])) - assert.True(ValEq(t, validators[2], resVals[2])) - - // remove a record - - // shouldn't be able to remove if status is not unbonded - assert.PanicsWithValue(t, - "cannot call RemoveValidator on bonded or unbonding validators", - func() { keeper.RemoveValidator(ctx, validators[1].OperatorAddress) }) - - // shouldn't be able to remove if there are still tokens left - validators[1].Status = sdk.Unbonded - keeper.SetValidator(ctx, validators[1]) - assert.PanicsWithValue(t, - "attempting to remove a validator which still contains tokens", - func() { keeper.RemoveValidator(ctx, validators[1].OperatorAddress) }) - - validators[1].Tokens = sdk.ZeroInt() // ...remove all tokens - keeper.SetValidator(ctx, validators[1]) // ...set the validator - keeper.RemoveValidator(ctx, validators[1].OperatorAddress) // Now it can be removed. - _, found = keeper.GetValidator(ctx, addrVals[1]) - require.False(t, found) -} - -// test how the validators are sorted, tests GetBondedValidatorsByPower -func TestGetValidatorSortingUnmixed(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - - // initialize some validators into the state - amts := []int64{ - 0, - 100 * sdk.PowerReduction.Int64(), - 1 * sdk.PowerReduction.Int64(), - 400 * sdk.PowerReduction.Int64(), - 200 * sdk.PowerReduction.Int64()} - n := len(amts) - var validators [5]types.Validator - for i, amt := range amts { - validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) - validators[i].Status = sdk.Bonded - validators[i].Tokens = sdk.NewInt(amt) - validators[i].DelegatorShares = sdk.NewDec(amt) - TestingUpdateValidator(keeper, ctx, validators[i], true) - } - - // first make sure everything made it in to the gotValidator group - resValidators := keeper.GetBondedValidatorsByPower(ctx) - assert.Equal(t, n, len(resValidators)) - assert.Equal(t, sdk.NewInt(400).Mul(sdk.PowerReduction), resValidators[0].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewInt(200).Mul(sdk.PowerReduction), resValidators[1].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewInt(100).Mul(sdk.PowerReduction), resValidators[2].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewInt(1).Mul(sdk.PowerReduction), resValidators[3].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewInt(0), resValidators[4].BondedTokens(), "%v", resValidators) - assert.Equal(t, validators[3].OperatorAddress, resValidators[0].OperatorAddress, "%v", resValidators) - assert.Equal(t, validators[4].OperatorAddress, resValidators[1].OperatorAddress, "%v", resValidators) - assert.Equal(t, validators[1].OperatorAddress, resValidators[2].OperatorAddress, "%v", resValidators) - assert.Equal(t, validators[2].OperatorAddress, resValidators[3].OperatorAddress, "%v", resValidators) - assert.Equal(t, validators[0].OperatorAddress, resValidators[4].OperatorAddress, "%v", resValidators) - - // test a basic increase in voting power - validators[3].Tokens = sdk.NewInt(500).Mul(sdk.PowerReduction) - TestingUpdateValidator(keeper, ctx, validators[3], true) - resValidators = keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, len(resValidators), n) - assert.True(ValEq(t, validators[3], resValidators[0])) - - // test a decrease in voting power - validators[3].Tokens = sdk.NewInt(300).Mul(sdk.PowerReduction) - TestingUpdateValidator(keeper, ctx, validators[3], true) - resValidators = keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, len(resValidators), n) - assert.True(ValEq(t, validators[3], resValidators[0])) - assert.True(ValEq(t, validators[4], resValidators[1])) - - // test equal voting power, different age - validators[3].Tokens = sdk.NewInt(200).Mul(sdk.PowerReduction) - ctx = ctx.WithBlockHeight(10) - TestingUpdateValidator(keeper, ctx, validators[3], true) - resValidators = keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, len(resValidators), n) - assert.True(ValEq(t, validators[3], resValidators[0])) - assert.True(ValEq(t, validators[4], resValidators[1])) - - // no change in voting power - no change in sort - ctx = ctx.WithBlockHeight(20) - TestingUpdateValidator(keeper, ctx, validators[4], true) - resValidators = keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, len(resValidators), n) - assert.True(ValEq(t, validators[3], resValidators[0])) - assert.True(ValEq(t, validators[4], resValidators[1])) - - // change in voting power of both validators, both still in v-set, no age change - validators[3].Tokens = sdk.NewInt(300).Mul(sdk.PowerReduction) - validators[4].Tokens = sdk.NewInt(300).Mul(sdk.PowerReduction) - TestingUpdateValidator(keeper, ctx, validators[3], true) - resValidators = keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, len(resValidators), n) - ctx = ctx.WithBlockHeight(30) - TestingUpdateValidator(keeper, ctx, validators[4], true) - resValidators = keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, len(resValidators), n, "%v", resValidators) - assert.True(ValEq(t, validators[3], resValidators[0])) - assert.True(ValEq(t, validators[4], resValidators[1])) -} - -func TestGetValidatorSortingMixed(t *testing.T) { - ctx, _, bk, keeper, _ := CreateTestInput(t, false, 1000) - bondedPool := keeper.GetBondedPool(ctx) - notBondedPool := keeper.GetNotBondedPool(ctx) - - bk.SetBalances(ctx, bondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), sdk.TokensFromConsensusPower(501)))) - bk.SetBalances(ctx, notBondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), sdk.TokensFromConsensusPower(0)))) - keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) - keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) - - // now 2 max resValidators - params := keeper.GetParams(ctx) - params.MaxValidators = 2 - keeper.SetParams(ctx, params) - - // initialize some validators into the state - amts := []int64{ - 0, - 100 * sdk.PowerReduction.Int64(), - 1 * sdk.PowerReduction.Int64(), - 400 * sdk.PowerReduction.Int64(), - 200 * sdk.PowerReduction.Int64()} - - var validators [5]types.Validator - for i, amt := range amts { - validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) - validators[i].DelegatorShares = sdk.NewDec(amt) - validators[i].Status = sdk.Bonded - validators[i].Tokens = sdk.NewInt(amt) - TestingUpdateValidator(keeper, ctx, validators[i], true) - } - - val0, found := keeper.GetValidator(ctx, sdk.ValAddress(Addrs[0])) - require.True(t, found) - val1, found := keeper.GetValidator(ctx, sdk.ValAddress(Addrs[1])) - require.True(t, found) - val2, found := keeper.GetValidator(ctx, sdk.ValAddress(Addrs[2])) - require.True(t, found) - val3, found := keeper.GetValidator(ctx, sdk.ValAddress(Addrs[3])) - require.True(t, found) - val4, found := keeper.GetValidator(ctx, sdk.ValAddress(Addrs[4])) - require.True(t, found) - require.Equal(t, sdk.Bonded, val0.Status) - require.Equal(t, sdk.Unbonding, val1.Status) - require.Equal(t, sdk.Unbonding, val2.Status) - require.Equal(t, sdk.Bonded, val3.Status) - require.Equal(t, sdk.Bonded, val4.Status) - - // first make sure everything made it in to the gotValidator group - resValidators := keeper.GetBondedValidatorsByPower(ctx) - // The validators returned should match the max validators - assert.Equal(t, 2, len(resValidators)) - assert.Equal(t, sdk.NewInt(400).Mul(sdk.PowerReduction), resValidators[0].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewInt(200).Mul(sdk.PowerReduction), resValidators[1].BondedTokens(), "%v", resValidators) - assert.Equal(t, validators[3].OperatorAddress, resValidators[0].OperatorAddress, "%v", resValidators) - assert.Equal(t, validators[4].OperatorAddress, resValidators[1].OperatorAddress, "%v", resValidators) -} - -// TODO separate out into multiple tests -func TestGetValidatorsEdgeCases(t *testing.T) { - ctx, _, bk, keeper, _ := CreateTestInput(t, false, 1000) - - // set max validators to 2 - params := keeper.GetParams(ctx) - nMax := uint32(2) - params.MaxValidators = nMax - keeper.SetParams(ctx, params) - - // initialize some validators into the state - powers := []int64{0, 100, 400, 400} - var validators [4]types.Validator - for i, power := range powers { - moniker := fmt.Sprintf("val#%d", int64(i)) - validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{Moniker: moniker}) - - tokens := sdk.TokensFromConsensusPower(power) - validators[i], _ = validators[i].AddTokensFromDel(tokens) - - notBondedPool := keeper.GetNotBondedPool(ctx) - balances := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) - require.NoError(t, bk.SetBalances(ctx, notBondedPool.GetAddress(), balances.Add(sdk.NewCoin(params.BondDenom, tokens)))) - - keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) - validators[i] = TestingUpdateValidator(keeper, ctx, validators[i], true) - } - - // ensure that the first two bonded validators are the largest validators - resValidators := keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, nMax, uint32(len(resValidators))) - assert.True(ValEq(t, validators[2], resValidators[0])) - assert.True(ValEq(t, validators[3], resValidators[1])) - - // delegate 500 tokens to validator 0 - keeper.DeleteValidatorByPowerIndex(ctx, validators[0]) - delTokens := sdk.TokensFromConsensusPower(500) - validators[0], _ = validators[0].AddTokensFromDel(delTokens) - notBondedPool := keeper.GetNotBondedPool(ctx) - - newTokens := sdk.NewCoins() - balances := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) - require.NoError(t, bk.SetBalances(ctx, notBondedPool.GetAddress(), balances.Add(newTokens...))) - keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) - - // test that the two largest validators are - // a) validator 0 with 500 tokens - // b) validator 2 with 400 tokens (delegated before validator 3) - validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], true) - resValidators = keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, nMax, uint32(len(resValidators))) - assert.True(ValEq(t, validators[0], resValidators[0])) - assert.True(ValEq(t, validators[2], resValidators[1])) - - // A validator which leaves the bonded validator set due to a decrease in voting power, - // then increases to the original voting power, does not get its spot back in the - // case of a tie. - // - // Order of operations for this test: - // - validator 3 enter validator set with 1 new token - // - validator 3 removed validator set by removing 201 tokens (validator 2 enters) - // - validator 3 adds 200 tokens (equal to validator 2 now) and does not get its spot back - - // validator 3 enters bonded validator set - ctx = ctx.WithBlockHeight(40) - - validators[3] = keeper.mustGetValidator(ctx, validators[3].OperatorAddress) - keeper.DeleteValidatorByPowerIndex(ctx, validators[3]) - validators[3], _ = validators[3].AddTokensFromDel(sdk.TokensFromConsensusPower(1)) - - notBondedPool = keeper.GetNotBondedPool(ctx) - newTokens = sdk.NewCoins(sdk.NewCoin(params.BondDenom, sdk.TokensFromConsensusPower(1))) - balances = bk.GetAllBalances(ctx, notBondedPool.GetAddress()) - require.NoError(t, bk.SetBalances(ctx, notBondedPool.GetAddress(), balances.Add(newTokens...))) - keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) - - validators[3] = TestingUpdateValidator(keeper, ctx, validators[3], true) - resValidators = keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, nMax, uint32(len(resValidators))) - assert.True(ValEq(t, validators[0], resValidators[0])) - assert.True(ValEq(t, validators[3], resValidators[1])) - - // validator 3 kicked out temporarily - keeper.DeleteValidatorByPowerIndex(ctx, validators[3]) - rmTokens := validators[3].TokensFromShares(sdk.NewDec(201)).TruncateInt() - validators[3], _ = validators[3].RemoveDelShares(sdk.NewDec(201)) - - bondedPool := keeper.GetBondedPool(ctx) - balances = bk.GetAllBalances(ctx, bondedPool.GetAddress()) - require.NoError(t, bk.SetBalances(ctx, bondedPool.GetAddress(), balances.Add(sdk.NewCoin(params.BondDenom, rmTokens)))) - keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) - - validators[3] = TestingUpdateValidator(keeper, ctx, validators[3], true) - resValidators = keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, nMax, uint32(len(resValidators))) - assert.True(ValEq(t, validators[0], resValidators[0])) - assert.True(ValEq(t, validators[2], resValidators[1])) - - // validator 3 does not get spot back - keeper.DeleteValidatorByPowerIndex(ctx, validators[3]) - validators[3], _ = validators[3].AddTokensFromDel(sdk.NewInt(200)) - - notBondedPool = keeper.GetNotBondedPool(ctx) - balances = bk.GetAllBalances(ctx, notBondedPool.GetAddress()) - require.NoError(t, bk.SetBalances(ctx, notBondedPool.GetAddress(), balances.Add(sdk.NewCoin(params.BondDenom, sdk.NewInt(200))))) - keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) - - validators[3] = TestingUpdateValidator(keeper, ctx, validators[3], true) - resValidators = keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, nMax, uint32(len(resValidators))) - assert.True(ValEq(t, validators[0], resValidators[0])) - assert.True(ValEq(t, validators[2], resValidators[1])) - _, exists := keeper.GetValidator(ctx, validators[3].OperatorAddress) - require.True(t, exists) -} - -func TestValidatorBondHeight(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - - // now 2 max resValidators - params := keeper.GetParams(ctx) - params.MaxValidators = 2 - keeper.SetParams(ctx, params) - - // initialize some validators into the state - var validators [3]types.Validator - validators[0] = types.NewValidator(sdk.ValAddress(PKs[0].Address().Bytes()), PKs[0], types.Description{}) - validators[1] = types.NewValidator(sdk.ValAddress(Addrs[1]), PKs[1], types.Description{}) - validators[2] = types.NewValidator(sdk.ValAddress(Addrs[2]), PKs[2], types.Description{}) - - tokens0 := sdk.TokensFromConsensusPower(200) - tokens1 := sdk.TokensFromConsensusPower(100) - tokens2 := sdk.TokensFromConsensusPower(100) - validators[0], _ = validators[0].AddTokensFromDel(tokens0) - validators[1], _ = validators[1].AddTokensFromDel(tokens1) - validators[2], _ = validators[2].AddTokensFromDel(tokens2) - - validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], true) - - //////////////////////////////////////// - // If two validators both increase to the same voting power in the same block, - // the one with the first transaction should become bonded - validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], true) - validators[2] = TestingUpdateValidator(keeper, ctx, validators[2], true) - - resValidators := keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, uint32(len(resValidators)), params.MaxValidators) - - assert.True(ValEq(t, validators[0], resValidators[0])) - assert.True(ValEq(t, validators[1], resValidators[1])) - keeper.DeleteValidatorByPowerIndex(ctx, validators[1]) - keeper.DeleteValidatorByPowerIndex(ctx, validators[2]) - delTokens := sdk.TokensFromConsensusPower(50) - validators[1], _ = validators[1].AddTokensFromDel(delTokens) - validators[2], _ = validators[2].AddTokensFromDel(delTokens) - validators[2] = TestingUpdateValidator(keeper, ctx, validators[2], true) - resValidators = keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, params.MaxValidators, uint32(len(resValidators))) - validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], true) - assert.True(ValEq(t, validators[0], resValidators[0])) - assert.True(ValEq(t, validators[2], resValidators[1])) -} - -func TestFullValidatorSetPowerChange(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - params := keeper.GetParams(ctx) - max := 2 - params.MaxValidators = uint32(2) - keeper.SetParams(ctx, params) - - // initialize some validators into the state - powers := []int64{0, 100, 400, 400, 200} - var validators [5]types.Validator - for i, power := range powers { - validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) - tokens := sdk.TokensFromConsensusPower(power) - validators[i], _ = validators[i].AddTokensFromDel(tokens) - TestingUpdateValidator(keeper, ctx, validators[i], true) - } - for i := range powers { - var found bool - validators[i], found = keeper.GetValidator(ctx, validators[i].OperatorAddress) - require.True(t, found) - } - assert.Equal(t, sdk.Unbonded, validators[0].Status) - assert.Equal(t, sdk.Unbonding, validators[1].Status) - assert.Equal(t, sdk.Bonded, validators[2].Status) - assert.Equal(t, sdk.Bonded, validators[3].Status) - assert.Equal(t, sdk.Unbonded, validators[4].Status) - resValidators := keeper.GetBondedValidatorsByPower(ctx) - assert.Equal(t, max, len(resValidators)) - assert.True(ValEq(t, validators[2], resValidators[0])) // in the order of txs - assert.True(ValEq(t, validators[3], resValidators[1])) - - // test a swap in voting power - - tokens := sdk.TokensFromConsensusPower(600) - validators[0], _ = validators[0].AddTokensFromDel(tokens) - validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], true) - resValidators = keeper.GetBondedValidatorsByPower(ctx) - assert.Equal(t, max, len(resValidators)) - assert.True(ValEq(t, validators[0], resValidators[0])) - assert.True(ValEq(t, validators[2], resValidators[1])) -} - -func TestApplyAndReturnValidatorSetUpdatesAllNone(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - - powers := []int64{10, 20} - var validators [2]types.Validator - for i, power := range powers { - valPubKey := PKs[i+1] - valAddr := sdk.ValAddress(valPubKey.Address().Bytes()) - - validators[i] = types.NewValidator(valAddr, valPubKey, types.Description{}) - tokens := sdk.TokensFromConsensusPower(power) - validators[i], _ = validators[i].AddTokensFromDel(tokens) - } - - // test from nothing to something - // tendermintUpdate set: {} -> {c1, c3} - require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) - keeper.SetValidator(ctx, validators[0]) - keeper.SetValidatorByPowerIndex(ctx, validators[0]) - keeper.SetValidator(ctx, validators[1]) - keeper.SetValidatorByPowerIndex(ctx, validators[1]) - - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - assert.Equal(t, 2, len(updates)) - validators[0], _ = keeper.GetValidator(ctx, validators[0].OperatorAddress) - validators[1], _ = keeper.GetValidator(ctx, validators[1].OperatorAddress) - assert.Equal(t, validators[0].ABCIValidatorUpdate(), updates[1]) - assert.Equal(t, validators[1].ABCIValidatorUpdate(), updates[0]) -} - -func TestApplyAndReturnValidatorSetUpdatesIdentical(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - - powers := []int64{10, 20} - var validators [2]types.Validator - for i, power := range powers { - validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) - - tokens := sdk.TokensFromConsensusPower(power) - validators[i], _ = validators[i].AddTokensFromDel(tokens) - - } - validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], false) - validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], false) - require.Equal(t, 2, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) - - // test identical, - // tendermintUpdate set: {} -> {} - validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], false) - validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], false) - require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) -} - -func TestApplyAndReturnValidatorSetUpdatesSingleValueChange(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - - powers := []int64{10, 20} - var validators [2]types.Validator - for i, power := range powers { - - validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) - - tokens := sdk.TokensFromConsensusPower(power) - validators[i], _ = validators[i].AddTokensFromDel(tokens) - - } - validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], false) - validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], false) - require.Equal(t, 2, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) - - // test single value change - // tendermintUpdate set: {} -> {c1'} - validators[0].Status = sdk.Bonded - validators[0].Tokens = sdk.TokensFromConsensusPower(600) - validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], false) - - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - - require.Equal(t, 1, len(updates)) - require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[0]) -} - -func TestApplyAndReturnValidatorSetUpdatesMultipleValueChange(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - - powers := []int64{10, 20} - var validators [2]types.Validator - for i, power := range powers { - - validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) - - tokens := sdk.TokensFromConsensusPower(power) - validators[i], _ = validators[i].AddTokensFromDel(tokens) - - } - validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], false) - validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], false) - require.Equal(t, 2, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) - - // test multiple value change - // tendermintUpdate set: {c1, c3} -> {c1', c3'} - delTokens1 := sdk.TokensFromConsensusPower(190) - delTokens2 := sdk.TokensFromConsensusPower(80) - validators[0], _ = validators[0].AddTokensFromDel(delTokens1) - validators[1], _ = validators[1].AddTokensFromDel(delTokens2) - validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], false) - validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], false) - - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 2, len(updates)) - require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[0]) - require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[1]) -} - -func TestApplyAndReturnValidatorSetUpdatesInserted(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - - powers := []int64{10, 20, 5, 15, 25} - var validators [5]types.Validator - for i, power := range powers { - - validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) - - tokens := sdk.TokensFromConsensusPower(power) - validators[i], _ = validators[i].AddTokensFromDel(tokens) - - } - - validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], false) - validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], false) - require.Equal(t, 2, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) - - // test validtor added at the beginning - // tendermintUpdate set: {} -> {c0} - keeper.SetValidator(ctx, validators[2]) - keeper.SetValidatorByPowerIndex(ctx, validators[2]) - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - validators[2], _ = keeper.GetValidator(ctx, validators[2].OperatorAddress) - require.Equal(t, 1, len(updates)) - require.Equal(t, validators[2].ABCIValidatorUpdate(), updates[0]) - - // test validtor added at the beginning - // tendermintUpdate set: {} -> {c0} - keeper.SetValidator(ctx, validators[3]) - keeper.SetValidatorByPowerIndex(ctx, validators[3]) - updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx) - validators[3], _ = keeper.GetValidator(ctx, validators[3].OperatorAddress) - require.Equal(t, 1, len(updates)) - require.Equal(t, validators[3].ABCIValidatorUpdate(), updates[0]) - - // test validtor added at the end - // tendermintUpdate set: {} -> {c0} - keeper.SetValidator(ctx, validators[4]) - keeper.SetValidatorByPowerIndex(ctx, validators[4]) - updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx) - validators[4], _ = keeper.GetValidator(ctx, validators[4].OperatorAddress) - require.Equal(t, 1, len(updates)) - require.Equal(t, validators[4].ABCIValidatorUpdate(), updates[0]) -} - -func TestApplyAndReturnValidatorSetUpdatesWithCliffValidator(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - params := types.DefaultParams() - params.MaxValidators = 2 - keeper.SetParams(ctx, params) - - powers := []int64{10, 20, 5} - var validators [5]types.Validator - for i, power := range powers { - - validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) - - tokens := sdk.TokensFromConsensusPower(power) - validators[i], _ = validators[i].AddTokensFromDel(tokens) - - } - validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], false) - validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], false) - require.Equal(t, 2, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) - - // test validator added at the end but not inserted in the valset - // tendermintUpdate set: {} -> {} - TestingUpdateValidator(keeper, ctx, validators[2], false) - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 0, len(updates)) - - // test validator change its power and become a gotValidator (pushing out an existing) - // tendermintUpdate set: {} -> {c0, c4} - require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) - - tokens := sdk.TokensFromConsensusPower(10) - validators[2], _ = validators[2].AddTokensFromDel(tokens) - keeper.SetValidator(ctx, validators[2]) - keeper.SetValidatorByPowerIndex(ctx, validators[2]) - updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx) - validators[2], _ = keeper.GetValidator(ctx, validators[2].OperatorAddress) - require.Equal(t, 2, len(updates), "%v", updates) - require.Equal(t, validators[0].ABCIValidatorUpdateZero(), updates[1]) - require.Equal(t, validators[2].ABCIValidatorUpdate(), updates[0]) -} - -func TestApplyAndReturnValidatorSetUpdatesPowerDecrease(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - - powers := []int64{100, 100} - var validators [2]types.Validator - for i, power := range powers { - - validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) - - tokens := sdk.TokensFromConsensusPower(power) - validators[i], _ = validators[i].AddTokensFromDel(tokens) - - } - validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], false) - validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], false) - require.Equal(t, 2, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) - - // check initial power - require.Equal(t, int64(100), validators[0].GetConsensusPower()) - require.Equal(t, int64(100), validators[1].GetConsensusPower()) - - // test multiple value change - // tendermintUpdate set: {c1, c3} -> {c1', c3'} - delTokens1 := sdk.TokensFromConsensusPower(20) - delTokens2 := sdk.TokensFromConsensusPower(30) - validators[0], _ = validators[0].RemoveDelShares(delTokens1.ToDec()) - validators[1], _ = validators[1].RemoveDelShares(delTokens2.ToDec()) - validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], false) - validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], false) - - // power has changed - require.Equal(t, int64(80), validators[0].GetConsensusPower()) - require.Equal(t, int64(70), validators[1].GetConsensusPower()) - - // Tendermint updates should reflect power change - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 2, len(updates)) - require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[0]) - require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[1]) -} - -func TestApplyAndReturnValidatorSetUpdatesNewValidator(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - params := keeper.GetParams(ctx) - params.MaxValidators = uint32(3) - - keeper.SetParams(ctx, params) - - powers := []int64{100, 100} - var validators [2]types.Validator - - // initialize some validators into the state - for i, power := range powers { - - valPubKey := PKs[i+1] - valAddr := sdk.ValAddress(valPubKey.Address().Bytes()) - - validators[i] = types.NewValidator(valAddr, valPubKey, types.Description{}) - tokens := sdk.TokensFromConsensusPower(power) - validators[i], _ = validators[i].AddTokensFromDel(tokens) - - keeper.SetValidator(ctx, validators[i]) - keeper.SetValidatorByPowerIndex(ctx, validators[i]) - } - - // verify initial Tendermint updates are correct - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, len(validators), len(updates)) - validators[0], _ = keeper.GetValidator(ctx, validators[0].OperatorAddress) - validators[1], _ = keeper.GetValidator(ctx, validators[1].OperatorAddress) - require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[0]) - require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[1]) - - require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) - - // update initial validator set - for i, power := range powers { - - keeper.DeleteValidatorByPowerIndex(ctx, validators[i]) - tokens := sdk.TokensFromConsensusPower(power) - validators[i], _ = validators[i].AddTokensFromDel(tokens) - - keeper.SetValidator(ctx, validators[i]) - keeper.SetValidatorByPowerIndex(ctx, validators[i]) - } - - // add a new validator that goes from zero power, to non-zero power, back to - // zero power - valPubKey := PKs[len(validators)+1] - valAddr := sdk.ValAddress(valPubKey.Address().Bytes()) - amt := sdk.NewInt(100) - - validator := types.NewValidator(valAddr, valPubKey, types.Description{}) - validator, _ = validator.AddTokensFromDel(amt) - - keeper.SetValidator(ctx, validator) - - validator, _ = validator.RemoveDelShares(amt.ToDec()) - keeper.SetValidator(ctx, validator) - keeper.SetValidatorByPowerIndex(ctx, validator) - - // add a new validator that increases in power - valPubKey = PKs[len(validators)+2] - valAddr = sdk.ValAddress(valPubKey.Address().Bytes()) - - validator = types.NewValidator(valAddr, valPubKey, types.Description{}) - tokens := sdk.TokensFromConsensusPower(500) - validator, _ = validator.AddTokensFromDel(tokens) - keeper.SetValidator(ctx, validator) - keeper.SetValidatorByPowerIndex(ctx, validator) - - // verify initial Tendermint updates are correct - updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx) - validator, _ = keeper.GetValidator(ctx, validator.OperatorAddress) - validators[0], _ = keeper.GetValidator(ctx, validators[0].OperatorAddress) - validators[1], _ = keeper.GetValidator(ctx, validators[1].OperatorAddress) - require.Equal(t, len(validators)+1, len(updates)) - require.Equal(t, validator.ABCIValidatorUpdate(), updates[0]) - require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[1]) - require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[2]) -} - -func TestApplyAndReturnValidatorSetUpdatesBondTransition(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - params := keeper.GetParams(ctx) - params.MaxValidators = uint32(2) - - keeper.SetParams(ctx, params) - - powers := []int64{100, 200, 300} - var validators [3]types.Validator - - // initialize some validators into the state - for i, power := range powers { - moniker := fmt.Sprintf("%d", i) - valPubKey := PKs[i+1] - valAddr := sdk.ValAddress(valPubKey.Address().Bytes()) - - validators[i] = types.NewValidator(valAddr, valPubKey, types.Description{Moniker: moniker}) - tokens := sdk.TokensFromConsensusPower(power) - validators[i], _ = validators[i].AddTokensFromDel(tokens) - keeper.SetValidator(ctx, validators[i]) - keeper.SetValidatorByPowerIndex(ctx, validators[i]) - } - - // verify initial Tendermint updates are correct - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 2, len(updates)) - validators[2], _ = keeper.GetValidator(ctx, validators[2].OperatorAddress) - validators[1], _ = keeper.GetValidator(ctx, validators[1].OperatorAddress) - require.Equal(t, validators[2].ABCIValidatorUpdate(), updates[0]) - require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[1]) - - require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) - - // delegate to validator with lowest power but not enough to bond - ctx = ctx.WithBlockHeight(1) - - var found bool - validators[0], found = keeper.GetValidator(ctx, validators[0].OperatorAddress) - require.True(t, found) - - keeper.DeleteValidatorByPowerIndex(ctx, validators[0]) - tokens := sdk.TokensFromConsensusPower(1) - validators[0], _ = validators[0].AddTokensFromDel(tokens) - keeper.SetValidator(ctx, validators[0]) - keeper.SetValidatorByPowerIndex(ctx, validators[0]) - - // verify initial Tendermint updates are correct - require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) - - // create a series of events that will bond and unbond the validator with - // lowest power in a single block context (height) - ctx = ctx.WithBlockHeight(2) - - validators[1], found = keeper.GetValidator(ctx, validators[1].OperatorAddress) - require.True(t, found) - - keeper.DeleteValidatorByPowerIndex(ctx, validators[0]) - validators[0], _ = validators[0].RemoveDelShares(validators[0].DelegatorShares) - keeper.SetValidator(ctx, validators[0]) - keeper.SetValidatorByPowerIndex(ctx, validators[0]) - updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 0, len(updates)) - - keeper.DeleteValidatorByPowerIndex(ctx, validators[1]) - tokens = sdk.TokensFromConsensusPower(250) - validators[1], _ = validators[1].AddTokensFromDel(tokens) - keeper.SetValidator(ctx, validators[1]) - keeper.SetValidatorByPowerIndex(ctx, validators[1]) - - // verify initial Tendermint updates are correct - updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 1, len(updates)) - require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[0]) - - require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) -} - -func TestUpdateValidatorCommission(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - ctx = ctx.WithBlockHeader(abci.Header{Time: time.Now().UTC()}) - - commission1 := types.NewCommissionWithTime( - sdk.NewDecWithPrec(1, 1), sdk.NewDecWithPrec(3, 1), - sdk.NewDecWithPrec(1, 1), time.Now().UTC().Add(time.Duration(-1)*time.Hour), - ) - commission2 := types.NewCommission(sdk.NewDecWithPrec(1, 1), sdk.NewDecWithPrec(3, 1), sdk.NewDecWithPrec(1, 1)) - - val1 := types.NewValidator(addrVals[0], PKs[0], types.Description{}) - val2 := types.NewValidator(addrVals[1], PKs[1], types.Description{}) - - val1, _ = val1.SetInitialCommission(commission1) - val2, _ = val2.SetInitialCommission(commission2) - - keeper.SetValidator(ctx, val1) - keeper.SetValidator(ctx, val2) - - testCases := []struct { - validator types.Validator - newRate sdk.Dec - expectedErr bool - }{ - {val1, sdk.ZeroDec(), true}, - {val2, sdk.NewDecWithPrec(-1, 1), true}, - {val2, sdk.NewDecWithPrec(4, 1), true}, - {val2, sdk.NewDecWithPrec(3, 1), true}, - {val2, sdk.NewDecWithPrec(2, 1), false}, - } - - for i, tc := range testCases { - commission, err := keeper.UpdateValidatorCommission(ctx, tc.validator, tc.newRate) - - if tc.expectedErr { - require.Error(t, err, "expected error for test case #%d with rate: %s", i, tc.newRate) - } else { - tc.validator.Commission = commission - keeper.SetValidator(ctx, tc.validator) - val, found := keeper.GetValidator(ctx, tc.validator.OperatorAddress) - - require.True(t, found, - "expected to find validator for test case #%d with rate: %s", i, tc.newRate, - ) - require.NoError(t, err, - "unexpected error for test case #%d with rate: %s", i, tc.newRate, - ) - require.Equal(t, tc.newRate, val.Commission.Rate, - "expected new validator commission rate for test case #%d with rate: %s", i, tc.newRate, - ) - require.Equal(t, ctx.BlockHeader().Time, val.Commission.UpdateTime, - "expected new validator commission update time for test case #%d with rate: %s", i, tc.newRate, - ) - } - } -} From 25681ad3ad53a94a5ef74f7f5b07beb4ec06db2d Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Tue, 25 Feb 2020 11:54:43 +0100 Subject: [PATCH 202/529] refacor TestUpdateValidatorByPowerIndex to use simapp --- x/staking/keeper/old_test_common.go | 6 ---- x/staking/keeper/old_validator_test.go | 37 ------------------------ x/staking/keeper/test_common_test.go | 1 - x/staking/keeper/validator_test.go | 40 ++++++++++++++++++++++++++ 4 files changed, 40 insertions(+), 44 deletions(-) diff --git a/x/staking/keeper/old_test_common.go b/x/staking/keeper/old_test_common.go index 8e4cd6b9aac7..82bd54a317ad 100644 --- a/x/staking/keeper/old_test_common.go +++ b/x/staking/keeper/old_test_common.go @@ -285,12 +285,6 @@ func TestingUpdateValidator(keeper Keeper, ctx sdk.Context, validator types.Vali return validator } -// nolint:deadcode, unused -func validatorByPowerIndexExists(k Keeper, ctx sdk.Context, power []byte) bool { - store := ctx.KVStore(k.storeKey) - return store.Has(power) -} - // RandomValidator returns a random validator given access to the keeper and ctx func RandomValidator(r *rand.Rand, keeper Keeper, ctx sdk.Context) (val types.Validator, ok bool) { vals := keeper.GetAllValidators(ctx) diff --git a/x/staking/keeper/old_validator_test.go b/x/staking/keeper/old_validator_test.go index c5101a3c145b..6151861f1695 100644 --- a/x/staking/keeper/old_validator_test.go +++ b/x/staking/keeper/old_validator_test.go @@ -14,43 +14,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking/types" ) -func TestUpdateValidatorByPowerIndex(t *testing.T) { - ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) - - bondedPool := keeper.GetBondedPool(ctx) - notBondedPool := keeper.GetNotBondedPool(ctx) - bk.SetBalances(ctx, bondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), sdk.TokensFromConsensusPower(1234)))) - bk.SetBalances(ctx, notBondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), sdk.TokensFromConsensusPower(10000)))) - keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) - keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) - - // add a validator - validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) - validator, delSharesCreated := validator.AddTokensFromDel(sdk.TokensFromConsensusPower(100)) - require.Equal(t, sdk.Unbonded, validator.Status) - require.Equal(t, sdk.TokensFromConsensusPower(100), validator.Tokens) - TestingUpdateValidator(keeper, ctx, validator, true) - validator, found := keeper.GetValidator(ctx, addrVals[0]) - require.True(t, found) - require.Equal(t, sdk.TokensFromConsensusPower(100), validator.Tokens) - - power := types.GetValidatorsByPowerIndexKey(validator) - require.True(t, validatorByPowerIndexExists(keeper, ctx, power)) - - // burn half the delegator shares - keeper.DeleteValidatorByPowerIndex(ctx, validator) - validator, burned := validator.RemoveDelShares(delSharesCreated.Quo(sdk.NewDec(2))) - require.Equal(t, sdk.TokensFromConsensusPower(50), burned) - TestingUpdateValidator(keeper, ctx, validator, true) // update the validator, possibly kicking it out - require.False(t, validatorByPowerIndexExists(keeper, ctx, power)) - - validator, found = keeper.GetValidator(ctx, addrVals[0]) - require.True(t, found) - - power = types.GetValidatorsByPowerIndexKey(validator) - require.True(t, validatorByPowerIndexExists(keeper, ctx, power)) -} - func TestUpdateBondedValidatorsDecreaseCliff(t *testing.T) { numVals := 10 maxVals := 5 diff --git a/x/staking/keeper/test_common_test.go b/x/staking/keeper/test_common_test.go index a32f3a7c0325..9293ed884a67 100644 --- a/x/staking/keeper/test_common_test.go +++ b/x/staking/keeper/test_common_test.go @@ -80,4 +80,3 @@ func generateAddresses(app *simapp.SimApp, ctx sdk.Context, numAddrs int) ([]sdk return addrDels, addrVals } - diff --git a/x/staking/keeper/validator_test.go b/x/staking/keeper/validator_test.go index de9c84b10cc3..c1dfc2ab6ba6 100644 --- a/x/staking/keeper/validator_test.go +++ b/x/staking/keeper/validator_test.go @@ -3,6 +3,8 @@ package keeper_test import ( "testing" + "github.com/cosmos/cosmos-sdk/x/staking/keeper" + "github.com/cosmos/cosmos-sdk/simapp" "github.com/stretchr/testify/assert" @@ -80,3 +82,41 @@ func TestSetValidator(t *testing.T) { allVals := app.StakingKeeper.GetAllValidators(ctx) require.Equal(t, 1, len(allVals)) } + +func TestUpdateValidatorByPowerIndex(t *testing.T) { + app, ctx, _, _ := bootstrapValidatorTest(t, 0) + _, addrVals := generateAddresses(app, ctx, 1) + + bondedPool := app.StakingKeeper.GetBondedPool(ctx) + notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) + app.BankKeeper.SetBalances(ctx, bondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.TokensFromConsensusPower(1234)))) + app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.TokensFromConsensusPower(10000)))) + app.SupplyKeeper.SetModuleAccount(ctx, bondedPool) + app.SupplyKeeper.SetModuleAccount(ctx, notBondedPool) + + // add a validator + validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) + validator, delSharesCreated := validator.AddTokensFromDel(sdk.TokensFromConsensusPower(100)) + require.Equal(t, sdk.Unbonded, validator.Status) + require.Equal(t, sdk.TokensFromConsensusPower(100), validator.Tokens) + keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator, true) + validator, found := app.StakingKeeper.GetValidator(ctx, addrVals[0]) + require.True(t, found) + require.Equal(t, sdk.TokensFromConsensusPower(100), validator.Tokens) + + power := types.GetValidatorsByPowerIndexKey(validator) + require.True(t, keeper.ValidatorByPowerIndexExists(ctx, app.StakingKeeper, power)) + + // burn half the delegator shares + app.StakingKeeper.DeleteValidatorByPowerIndex(ctx, validator) + validator, burned := validator.RemoveDelShares(delSharesCreated.Quo(sdk.NewDec(2))) + require.Equal(t, sdk.TokensFromConsensusPower(50), burned) + keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator, true) // update the validator, possibly kicking it out + require.False(t, keeper.ValidatorByPowerIndexExists(ctx, app.StakingKeeper, power)) + + validator, found = app.StakingKeeper.GetValidator(ctx, addrVals[0]) + require.True(t, found) + + power = types.GetValidatorsByPowerIndexKey(validator) + require.True(t, keeper.ValidatorByPowerIndexExists(ctx, app.StakingKeeper, power)) +} From 385c5c556be57a677e6c7f5b7381e4db79501f2e Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Tue, 25 Feb 2020 11:59:15 +0100 Subject: [PATCH 203/529] refactor TestUpdateBondedValidatorsDecreaseCliff to simapp --- x/staking/keeper/old_validator_test.go | 57 ------------------------ x/staking/keeper/validator_test.go | 60 ++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 57 deletions(-) diff --git a/x/staking/keeper/old_validator_test.go b/x/staking/keeper/old_validator_test.go index 6151861f1695..168f36a57a69 100644 --- a/x/staking/keeper/old_validator_test.go +++ b/x/staking/keeper/old_validator_test.go @@ -14,63 +14,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking/types" ) -func TestUpdateBondedValidatorsDecreaseCliff(t *testing.T) { - numVals := 10 - maxVals := 5 - - // create context, keeper, and pool for tests - ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) - bondedPool := keeper.GetBondedPool(ctx) - notBondedPool := keeper.GetNotBondedPool(ctx) - - // create keeper parameters - params := keeper.GetParams(ctx) - params.MaxValidators = uint32(maxVals) - keeper.SetParams(ctx, params) - - // create a random pool - bk.SetBalances(ctx, bondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), sdk.TokensFromConsensusPower(1234)))) - bk.SetBalances(ctx, notBondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), sdk.TokensFromConsensusPower(10000)))) - keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) - keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) - - validators := make([]types.Validator, numVals) - for i := 0; i < len(validators); i++ { - moniker := fmt.Sprintf("val#%d", int64(i)) - val := types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{Moniker: moniker}) - delTokens := sdk.TokensFromConsensusPower(int64((i + 1) * 10)) - val, _ = val.AddTokensFromDel(delTokens) - - val = TestingUpdateValidator(keeper, ctx, val, true) - validators[i] = val - } - - nextCliffVal := validators[numVals-maxVals+1] - - // remove enough tokens to kick out the validator below the current cliff - // validator and next in line cliff validator - keeper.DeleteValidatorByPowerIndex(ctx, nextCliffVal) - shares := sdk.TokensFromConsensusPower(21) - nextCliffVal, _ = nextCliffVal.RemoveDelShares(shares.ToDec()) - nextCliffVal = TestingUpdateValidator(keeper, ctx, nextCliffVal, true) - - expectedValStatus := map[int]sdk.BondStatus{ - 9: sdk.Bonded, 8: sdk.Bonded, 7: sdk.Bonded, 5: sdk.Bonded, 4: sdk.Bonded, - 0: sdk.Unbonding, 1: sdk.Unbonding, 2: sdk.Unbonding, 3: sdk.Unbonding, 6: sdk.Unbonding, - } - - // require all the validators have their respective statuses - for valIdx, status := range expectedValStatus { - valAddr := validators[valIdx].OperatorAddress - val, _ := keeper.GetValidator(ctx, valAddr) - - assert.Equal( - t, status, val.GetStatus(), - fmt.Sprintf("expected validator at index %v to have status: %s", valIdx, status), - ) - } -} - func TestSlashToZeroPowerRemoved(t *testing.T) { // initialize setup ctx, _, bk, keeper, _ := CreateTestInput(t, false, 100) diff --git a/x/staking/keeper/validator_test.go b/x/staking/keeper/validator_test.go index c1dfc2ab6ba6..18a52f9489b6 100644 --- a/x/staking/keeper/validator_test.go +++ b/x/staking/keeper/validator_test.go @@ -1,6 +1,7 @@ package keeper_test import ( + "fmt" "testing" "github.com/cosmos/cosmos-sdk/x/staking/keeper" @@ -120,3 +121,62 @@ func TestUpdateValidatorByPowerIndex(t *testing.T) { power = types.GetValidatorsByPowerIndexKey(validator) require.True(t, keeper.ValidatorByPowerIndexExists(ctx, app.StakingKeeper, power)) } + +func TestUpdateBondedValidatorsDecreaseCliff(t *testing.T) { + numVals := 10 + maxVals := 5 + + // create context, keeper, and pool for tests + app, ctx, _, _ := bootstrapValidatorTest(t, 0) + _, valAddrs := generateAddresses(app, ctx, 10) + + bondedPool := app.StakingKeeper.GetBondedPool(ctx) + notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) + + // create keeper parameters + params := app.StakingKeeper.GetParams(ctx) + params.MaxValidators = uint32(maxVals) + app.StakingKeeper.SetParams(ctx, params) + + // create a random pool + app.BankKeeper.SetBalances(ctx, bondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.TokensFromConsensusPower(1234)))) + app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.TokensFromConsensusPower(10000)))) + app.SupplyKeeper.SetModuleAccount(ctx, bondedPool) + app.SupplyKeeper.SetModuleAccount(ctx, notBondedPool) + + validators := make([]types.Validator, numVals) + for i := 0; i < len(validators); i++ { + moniker := fmt.Sprintf("val#%d", int64(i)) + val := types.NewValidator(valAddrs[i], PKs[i], types.Description{Moniker: moniker}) + delTokens := sdk.TokensFromConsensusPower(int64((i + 1) * 10)) + val, _ = val.AddTokensFromDel(delTokens) + + val = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, val, true) + validators[i] = val + } + + nextCliffVal := validators[numVals-maxVals+1] + + // remove enough tokens to kick out the validator below the current cliff + // validator and next in line cliff validator + app.StakingKeeper.DeleteValidatorByPowerIndex(ctx, nextCliffVal) + shares := sdk.TokensFromConsensusPower(21) + nextCliffVal, _ = nextCliffVal.RemoveDelShares(shares.ToDec()) + nextCliffVal = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, nextCliffVal, true) + + expectedValStatus := map[int]sdk.BondStatus{ + 9: sdk.Bonded, 8: sdk.Bonded, 7: sdk.Bonded, 5: sdk.Bonded, 4: sdk.Bonded, + 0: sdk.Unbonding, 1: sdk.Unbonding, 2: sdk.Unbonding, 3: sdk.Unbonding, 6: sdk.Unbonding, + } + + // require all the validators have their respective statuses + for valIdx, status := range expectedValStatus { + valAddr := validators[valIdx].OperatorAddress + val, _ := app.StakingKeeper.GetValidator(ctx, valAddr) + + assert.Equal( + t, status, val.GetStatus(), + fmt.Sprintf("expected validator at index %v to have status: %s", valIdx, status), + ) + } +} From ed401119e4353a2a32367d8842c701ad89333f03 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Tue, 25 Feb 2020 13:18:49 +0100 Subject: [PATCH 204/529] refactor TestSlashToZeroPowerRemoved --- x/staking/keeper/old_validator_test.go | 30 ------------------ x/staking/keeper/validator_test.go | 44 ++++++++++++++++++++++---- 2 files changed, 38 insertions(+), 36 deletions(-) diff --git a/x/staking/keeper/old_validator_test.go b/x/staking/keeper/old_validator_test.go index 168f36a57a69..a7187b23cfca 100644 --- a/x/staking/keeper/old_validator_test.go +++ b/x/staking/keeper/old_validator_test.go @@ -14,36 +14,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking/types" ) -func TestSlashToZeroPowerRemoved(t *testing.T) { - // initialize setup - ctx, _, bk, keeper, _ := CreateTestInput(t, false, 100) - - // add a validator - validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) - valTokens := sdk.TokensFromConsensusPower(100) - - bondedPool := keeper.GetBondedPool(ctx) - err := bk.SetBalances(ctx, bondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), valTokens))) - require.NoError(t, err) - keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) - - validator, _ = validator.AddTokensFromDel(valTokens) - require.Equal(t, sdk.Unbonded, validator.Status) - require.Equal(t, valTokens, validator.Tokens) - keeper.SetValidatorByConsAddr(ctx, validator) - validator = TestingUpdateValidator(keeper, ctx, validator, true) - require.Equal(t, valTokens, validator.Tokens, "\nvalidator %v\npool %v", validator, valTokens) - - // slash the validator by 100% - consAddr0 := sdk.ConsAddress(PKs[0].Address()) - keeper.Slash(ctx, consAddr0, 0, 100, sdk.OneDec()) - // apply TM updates - keeper.ApplyAndReturnValidatorSetUpdates(ctx) - // validator should be unbonding - validator, _ = keeper.GetValidator(ctx, addrVals[0]) - require.Equal(t, validator.GetStatus(), sdk.Unbonding) -} - // This function tests UpdateValidator, GetValidator, GetLastValidators, RemoveValidator func TestValidatorBasics(t *testing.T) { ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) diff --git a/x/staking/keeper/validator_test.go b/x/staking/keeper/validator_test.go index 18a52f9489b6..c303d2029a46 100644 --- a/x/staking/keeper/validator_test.go +++ b/x/staking/keeper/validator_test.go @@ -4,6 +4,8 @@ import ( "fmt" "testing" + "github.com/cosmos/cosmos-sdk/x/supply" + "github.com/cosmos/cosmos-sdk/x/staking/keeper" "github.com/cosmos/cosmos-sdk/simapp" @@ -15,10 +17,10 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking/types" ) -func bootstrapValidatorTest(t *testing.T, power int64) (*simapp.SimApp, sdk.Context, []sdk.AccAddress, []sdk.ValAddress) { +func bootstrapValidatorTest(t *testing.T, power int64, numAddrs int) (*simapp.SimApp, sdk.Context, []sdk.AccAddress, []sdk.ValAddress) { _, app, ctx := getBaseSimappWithCustomKeeper() - addrDels, addrVals := generateAddresses(app, ctx, 100) + addrDels, addrVals := generateAddresses(app, ctx, numAddrs) amt := sdk.TokensFromConsensusPower(power) totalSupply := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), amt.MulRaw(int64(len(addrDels))))) @@ -28,11 +30,13 @@ func bootstrapValidatorTest(t *testing.T, power int64) (*simapp.SimApp, sdk.Cont require.NoError(t, err) app.SupplyKeeper.SetModuleAccount(ctx, notBondedPool) + app.SupplyKeeper.SetSupply(ctx, supply.NewSupply(totalSupply)) + return app, ctx, addrDels, addrVals } func TestSetValidator(t *testing.T) { - app, ctx, _, _ := bootstrapValidatorTest(t, 10) + app, ctx, _, _ := bootstrapValidatorTest(t, 10, 100) valPubKey := PKs[0] valAddr := sdk.ValAddress(valPubKey.Address().Bytes()) @@ -85,7 +89,7 @@ func TestSetValidator(t *testing.T) { } func TestUpdateValidatorByPowerIndex(t *testing.T) { - app, ctx, _, _ := bootstrapValidatorTest(t, 0) + app, ctx, _, _ := bootstrapValidatorTest(t, 0, 100) _, addrVals := generateAddresses(app, ctx, 1) bondedPool := app.StakingKeeper.GetBondedPool(ctx) @@ -127,8 +131,7 @@ func TestUpdateBondedValidatorsDecreaseCliff(t *testing.T) { maxVals := 5 // create context, keeper, and pool for tests - app, ctx, _, _ := bootstrapValidatorTest(t, 0) - _, valAddrs := generateAddresses(app, ctx, 10) + app, ctx, _, valAddrs := bootstrapValidatorTest(t, 0, 100) bondedPool := app.StakingKeeper.GetBondedPool(ctx) notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) @@ -180,3 +183,32 @@ func TestUpdateBondedValidatorsDecreaseCliff(t *testing.T) { ) } } + +func TestSlashToZeroPowerRemoved(t *testing.T) { + // initialize setup + app, ctx, _, addrVals := bootstrapValidatorTest(t, 100, 20) + + // add a validator + validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) + valTokens := sdk.TokensFromConsensusPower(100) + + bondedPool := app.StakingKeeper.GetBondedPool(ctx) + err := app.BankKeeper.SetBalances(ctx, bondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), valTokens))) + require.NoError(t, err) + app.SupplyKeeper.SetModuleAccount(ctx, bondedPool) + + validator, _ = validator.AddTokensFromDel(valTokens) + require.Equal(t, sdk.Unbonded, validator.Status) + require.Equal(t, valTokens, validator.Tokens) + app.StakingKeeper.SetValidatorByConsAddr(ctx, validator) + validator = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator, true) + require.Equal(t, valTokens, validator.Tokens, "\nvalidator %v\npool %v", validator, valTokens) + + // slash the validator by 100% + app.StakingKeeper.Slash(ctx, sdk.ConsAddress(PKs[0].Address()), 0, 100, sdk.OneDec()) + // apply TM updates + app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + // validator should be unbonding + validator, _ = app.StakingKeeper.GetValidator(ctx, addrVals[0]) + require.Equal(t, validator.GetStatus(), sdk.Unbonding) +} From 9fa658c3f94712bd867f3f4b2e84ea7e543f3719 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Tue, 25 Feb 2020 13:23:22 +0100 Subject: [PATCH 205/529] TestValidatorBasics --- x/staking/keeper/old_validator_test.go | 99 -------------------------- x/staking/keeper/validator_test.go | 99 ++++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 99 deletions(-) diff --git a/x/staking/keeper/old_validator_test.go b/x/staking/keeper/old_validator_test.go index a7187b23cfca..0b4d4fc273ee 100644 --- a/x/staking/keeper/old_validator_test.go +++ b/x/staking/keeper/old_validator_test.go @@ -14,105 +14,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking/types" ) -// This function tests UpdateValidator, GetValidator, GetLastValidators, RemoveValidator -func TestValidatorBasics(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - - //construct the validators - var validators [3]types.Validator - powers := []int64{9, 8, 7} - for i, power := range powers { - validators[i] = types.NewValidator(addrVals[i], PKs[i], types.Description{}) - validators[i].Status = sdk.Unbonded - validators[i].Tokens = sdk.ZeroInt() - tokens := sdk.TokensFromConsensusPower(power) - - validators[i], _ = validators[i].AddTokensFromDel(tokens) - } - assert.Equal(t, sdk.TokensFromConsensusPower(9), validators[0].Tokens) - assert.Equal(t, sdk.TokensFromConsensusPower(8), validators[1].Tokens) - assert.Equal(t, sdk.TokensFromConsensusPower(7), validators[2].Tokens) - - // check the empty keeper first - _, found := keeper.GetValidator(ctx, addrVals[0]) - require.False(t, found) - resVals := keeper.GetLastValidators(ctx) - require.Zero(t, len(resVals)) - - resVals = keeper.GetValidators(ctx, 2) - require.Zero(t, len(resVals)) - - // set and retrieve a record - validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], true) - keeper.SetValidatorByConsAddr(ctx, validators[0]) - resVal, found := keeper.GetValidator(ctx, addrVals[0]) - require.True(t, found) - assert.True(ValEq(t, validators[0], resVal)) - - // retrieve from consensus - resVal, found = keeper.GetValidatorByConsAddr(ctx, sdk.ConsAddress(PKs[0].Address())) - require.True(t, found) - assert.True(ValEq(t, validators[0], resVal)) - resVal, found = keeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(PKs[0])) - require.True(t, found) - assert.True(ValEq(t, validators[0], resVal)) - - resVals = keeper.GetLastValidators(ctx) - require.Equal(t, 1, len(resVals)) - assert.True(ValEq(t, validators[0], resVals[0])) - assert.Equal(t, sdk.Bonded, validators[0].Status) - assert.True(sdk.IntEq(t, sdk.TokensFromConsensusPower(9), validators[0].BondedTokens())) - - // modify a records, save, and retrieve - validators[0].Status = sdk.Bonded - validators[0].Tokens = sdk.TokensFromConsensusPower(10) - validators[0].DelegatorShares = validators[0].Tokens.ToDec() - validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], true) - resVal, found = keeper.GetValidator(ctx, addrVals[0]) - require.True(t, found) - assert.True(ValEq(t, validators[0], resVal)) - - resVals = keeper.GetLastValidators(ctx) - require.Equal(t, 1, len(resVals)) - assert.True(ValEq(t, validators[0], resVals[0])) - - // add other validators - validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], true) - validators[2] = TestingUpdateValidator(keeper, ctx, validators[2], true) - resVal, found = keeper.GetValidator(ctx, addrVals[1]) - require.True(t, found) - assert.True(ValEq(t, validators[1], resVal)) - resVal, found = keeper.GetValidator(ctx, addrVals[2]) - require.True(t, found) - assert.True(ValEq(t, validators[2], resVal)) - - resVals = keeper.GetLastValidators(ctx) - require.Equal(t, 3, len(resVals)) - assert.True(ValEq(t, validators[0], resVals[0])) // order doesn't matter here - assert.True(ValEq(t, validators[1], resVals[1])) - assert.True(ValEq(t, validators[2], resVals[2])) - - // remove a record - - // shouldn't be able to remove if status is not unbonded - assert.PanicsWithValue(t, - "cannot call RemoveValidator on bonded or unbonding validators", - func() { keeper.RemoveValidator(ctx, validators[1].OperatorAddress) }) - - // shouldn't be able to remove if there are still tokens left - validators[1].Status = sdk.Unbonded - keeper.SetValidator(ctx, validators[1]) - assert.PanicsWithValue(t, - "attempting to remove a validator which still contains tokens", - func() { keeper.RemoveValidator(ctx, validators[1].OperatorAddress) }) - - validators[1].Tokens = sdk.ZeroInt() // ...remove all tokens - keeper.SetValidator(ctx, validators[1]) // ...set the validator - keeper.RemoveValidator(ctx, validators[1].OperatorAddress) // Now it can be removed. - _, found = keeper.GetValidator(ctx, addrVals[1]) - require.False(t, found) -} - // test how the validators are sorted, tests GetBondedValidatorsByPower func TestGetValidatorSortingUnmixed(t *testing.T) { ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) diff --git a/x/staking/keeper/validator_test.go b/x/staking/keeper/validator_test.go index c303d2029a46..4d866ab6868d 100644 --- a/x/staking/keeper/validator_test.go +++ b/x/staking/keeper/validator_test.go @@ -212,3 +212,102 @@ func TestSlashToZeroPowerRemoved(t *testing.T) { validator, _ = app.StakingKeeper.GetValidator(ctx, addrVals[0]) require.Equal(t, validator.GetStatus(), sdk.Unbonding) } + +// This function tests UpdateValidator, GetValidator, GetLastValidators, RemoveValidator +func TestValidatorBasics(t *testing.T) { + app, ctx, _, addrVals := bootstrapValidatorTest(t, 1000, 20) + + //construct the validators + var validators [3]types.Validator + powers := []int64{9, 8, 7} + for i, power := range powers { + validators[i] = types.NewValidator(addrVals[i], PKs[i], types.Description{}) + validators[i].Status = sdk.Unbonded + validators[i].Tokens = sdk.ZeroInt() + tokens := sdk.TokensFromConsensusPower(power) + + validators[i], _ = validators[i].AddTokensFromDel(tokens) + } + assert.Equal(t, sdk.TokensFromConsensusPower(9), validators[0].Tokens) + assert.Equal(t, sdk.TokensFromConsensusPower(8), validators[1].Tokens) + assert.Equal(t, sdk.TokensFromConsensusPower(7), validators[2].Tokens) + + // check the empty keeper first + _, found := app.StakingKeeper.GetValidator(ctx, addrVals[0]) + require.False(t, found) + resVals := app.StakingKeeper.GetLastValidators(ctx) + require.Zero(t, len(resVals)) + + resVals = app.StakingKeeper.GetValidators(ctx, 2) + require.Zero(t, len(resVals)) + + // set and retrieve a record + validators[0] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[0], true) + app.StakingKeeper.SetValidatorByConsAddr(ctx, validators[0]) + resVal, found := app.StakingKeeper.GetValidator(ctx, addrVals[0]) + require.True(t, found) + assert.True(ValEq(t, validators[0], resVal)) + + // retrieve from consensus + resVal, found = app.StakingKeeper.GetValidatorByConsAddr(ctx, sdk.ConsAddress(PKs[0].Address())) + require.True(t, found) + assert.True(ValEq(t, validators[0], resVal)) + resVal, found = app.StakingKeeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(PKs[0])) + require.True(t, found) + assert.True(ValEq(t, validators[0], resVal)) + + resVals = app.StakingKeeper.GetLastValidators(ctx) + require.Equal(t, 1, len(resVals)) + assert.True(ValEq(t, validators[0], resVals[0])) + assert.Equal(t, sdk.Bonded, validators[0].Status) + assert.True(sdk.IntEq(t, sdk.TokensFromConsensusPower(9), validators[0].BondedTokens())) + + // modify a records, save, and retrieve + validators[0].Status = sdk.Bonded + validators[0].Tokens = sdk.TokensFromConsensusPower(10) + validators[0].DelegatorShares = validators[0].Tokens.ToDec() + validators[0] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[0], true) + resVal, found = app.StakingKeeper.GetValidator(ctx, addrVals[0]) + require.True(t, found) + assert.True(ValEq(t, validators[0], resVal)) + + resVals = app.StakingKeeper.GetLastValidators(ctx) + require.Equal(t, 1, len(resVals)) + assert.True(ValEq(t, validators[0], resVals[0])) + + // add other validators + validators[1] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[1], true) + validators[2] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[2], true) + resVal, found = app.StakingKeeper.GetValidator(ctx, addrVals[1]) + require.True(t, found) + assert.True(ValEq(t, validators[1], resVal)) + resVal, found = app.StakingKeeper.GetValidator(ctx, addrVals[2]) + require.True(t, found) + assert.True(ValEq(t, validators[2], resVal)) + + resVals = app.StakingKeeper.GetLastValidators(ctx) + require.Equal(t, 3, len(resVals)) + assert.True(ValEq(t, validators[0], resVals[0])) // order doesn't matter here + assert.True(ValEq(t, validators[1], resVals[1])) + assert.True(ValEq(t, validators[2], resVals[2])) + + // remove a record + + // shouldn't be able to remove if status is not unbonded + assert.PanicsWithValue(t, + "cannot call RemoveValidator on bonded or unbonding validators", + func() { app.StakingKeeper.RemoveValidator(ctx, validators[1].OperatorAddress) }) + + // shouldn't be able to remove if there are still tokens left + validators[1].Status = sdk.Unbonded + app.StakingKeeper.SetValidator(ctx, validators[1]) + assert.PanicsWithValue(t, + "attempting to remove a validator which still contains tokens", + func() { app.StakingKeeper.RemoveValidator(ctx, validators[1].OperatorAddress) }) + + validators[1].Tokens = sdk.ZeroInt() // ...remove all tokens + app.StakingKeeper.SetValidator(ctx, validators[1]) // ...set the validator + app.StakingKeeper.RemoveValidator(ctx, validators[1].OperatorAddress) // Now it can be removed. + _, found = app.StakingKeeper.GetValidator(ctx, addrVals[1]) + require.False(t, found) +} From 460619fa29e14a85f5621d24cc2cd5eaec9dafff Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Tue, 25 Feb 2020 13:27:05 +0100 Subject: [PATCH 206/529] refactro TestGetValidatorSortingUnmixed to simapp --- x/staking/keeper/old_validator_test.go | 81 -------------------------- x/staking/keeper/validator_test.go | 81 ++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 81 deletions(-) diff --git a/x/staking/keeper/old_validator_test.go b/x/staking/keeper/old_validator_test.go index 0b4d4fc273ee..6745217a6ea5 100644 --- a/x/staking/keeper/old_validator_test.go +++ b/x/staking/keeper/old_validator_test.go @@ -14,87 +14,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking/types" ) -// test how the validators are sorted, tests GetBondedValidatorsByPower -func TestGetValidatorSortingUnmixed(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - - // initialize some validators into the state - amts := []int64{ - 0, - 100 * sdk.PowerReduction.Int64(), - 1 * sdk.PowerReduction.Int64(), - 400 * sdk.PowerReduction.Int64(), - 200 * sdk.PowerReduction.Int64()} - n := len(amts) - var validators [5]types.Validator - for i, amt := range amts { - validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) - validators[i].Status = sdk.Bonded - validators[i].Tokens = sdk.NewInt(amt) - validators[i].DelegatorShares = sdk.NewDec(amt) - TestingUpdateValidator(keeper, ctx, validators[i], true) - } - - // first make sure everything made it in to the gotValidator group - resValidators := keeper.GetBondedValidatorsByPower(ctx) - assert.Equal(t, n, len(resValidators)) - assert.Equal(t, sdk.NewInt(400).Mul(sdk.PowerReduction), resValidators[0].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewInt(200).Mul(sdk.PowerReduction), resValidators[1].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewInt(100).Mul(sdk.PowerReduction), resValidators[2].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewInt(1).Mul(sdk.PowerReduction), resValidators[3].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewInt(0), resValidators[4].BondedTokens(), "%v", resValidators) - assert.Equal(t, validators[3].OperatorAddress, resValidators[0].OperatorAddress, "%v", resValidators) - assert.Equal(t, validators[4].OperatorAddress, resValidators[1].OperatorAddress, "%v", resValidators) - assert.Equal(t, validators[1].OperatorAddress, resValidators[2].OperatorAddress, "%v", resValidators) - assert.Equal(t, validators[2].OperatorAddress, resValidators[3].OperatorAddress, "%v", resValidators) - assert.Equal(t, validators[0].OperatorAddress, resValidators[4].OperatorAddress, "%v", resValidators) - - // test a basic increase in voting power - validators[3].Tokens = sdk.NewInt(500).Mul(sdk.PowerReduction) - TestingUpdateValidator(keeper, ctx, validators[3], true) - resValidators = keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, len(resValidators), n) - assert.True(ValEq(t, validators[3], resValidators[0])) - - // test a decrease in voting power - validators[3].Tokens = sdk.NewInt(300).Mul(sdk.PowerReduction) - TestingUpdateValidator(keeper, ctx, validators[3], true) - resValidators = keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, len(resValidators), n) - assert.True(ValEq(t, validators[3], resValidators[0])) - assert.True(ValEq(t, validators[4], resValidators[1])) - - // test equal voting power, different age - validators[3].Tokens = sdk.NewInt(200).Mul(sdk.PowerReduction) - ctx = ctx.WithBlockHeight(10) - TestingUpdateValidator(keeper, ctx, validators[3], true) - resValidators = keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, len(resValidators), n) - assert.True(ValEq(t, validators[3], resValidators[0])) - assert.True(ValEq(t, validators[4], resValidators[1])) - - // no change in voting power - no change in sort - ctx = ctx.WithBlockHeight(20) - TestingUpdateValidator(keeper, ctx, validators[4], true) - resValidators = keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, len(resValidators), n) - assert.True(ValEq(t, validators[3], resValidators[0])) - assert.True(ValEq(t, validators[4], resValidators[1])) - - // change in voting power of both validators, both still in v-set, no age change - validators[3].Tokens = sdk.NewInt(300).Mul(sdk.PowerReduction) - validators[4].Tokens = sdk.NewInt(300).Mul(sdk.PowerReduction) - TestingUpdateValidator(keeper, ctx, validators[3], true) - resValidators = keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, len(resValidators), n) - ctx = ctx.WithBlockHeight(30) - TestingUpdateValidator(keeper, ctx, validators[4], true) - resValidators = keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, len(resValidators), n, "%v", resValidators) - assert.True(ValEq(t, validators[3], resValidators[0])) - assert.True(ValEq(t, validators[4], resValidators[1])) -} - func TestGetValidatorSortingMixed(t *testing.T) { ctx, _, bk, keeper, _ := CreateTestInput(t, false, 1000) bondedPool := keeper.GetBondedPool(ctx) diff --git a/x/staking/keeper/validator_test.go b/x/staking/keeper/validator_test.go index 4d866ab6868d..4a2a8a546c4b 100644 --- a/x/staking/keeper/validator_test.go +++ b/x/staking/keeper/validator_test.go @@ -311,3 +311,84 @@ func TestValidatorBasics(t *testing.T) { _, found = app.StakingKeeper.GetValidator(ctx, addrVals[1]) require.False(t, found) } + +// test how the validators are sorted, tests GetBondedValidatorsByPower +func TestGetValidatorSortingUnmixed(t *testing.T) { + app, ctx, addrs, _ := bootstrapValidatorTest(t, 1000, 20) + + // initialize some validators into the state + amts := []int64{ + 0, + 100 * sdk.PowerReduction.Int64(), + 1 * sdk.PowerReduction.Int64(), + 400 * sdk.PowerReduction.Int64(), + 200 * sdk.PowerReduction.Int64()} + n := len(amts) + var validators [5]types.Validator + for i, amt := range amts { + validators[i] = types.NewValidator(sdk.ValAddress(addrs[i]), PKs[i], types.Description{}) + validators[i].Status = sdk.Bonded + validators[i].Tokens = sdk.NewInt(amt) + validators[i].DelegatorShares = sdk.NewDec(amt) + keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[i], true) + } + + // first make sure everything made it in to the gotValidator group + resValidators := app.StakingKeeper.GetBondedValidatorsByPower(ctx) + assert.Equal(t, n, len(resValidators)) + assert.Equal(t, sdk.NewInt(400).Mul(sdk.PowerReduction), resValidators[0].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewInt(200).Mul(sdk.PowerReduction), resValidators[1].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewInt(100).Mul(sdk.PowerReduction), resValidators[2].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewInt(1).Mul(sdk.PowerReduction), resValidators[3].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewInt(0), resValidators[4].BondedTokens(), "%v", resValidators) + assert.Equal(t, validators[3].OperatorAddress, resValidators[0].OperatorAddress, "%v", resValidators) + assert.Equal(t, validators[4].OperatorAddress, resValidators[1].OperatorAddress, "%v", resValidators) + assert.Equal(t, validators[1].OperatorAddress, resValidators[2].OperatorAddress, "%v", resValidators) + assert.Equal(t, validators[2].OperatorAddress, resValidators[3].OperatorAddress, "%v", resValidators) + assert.Equal(t, validators[0].OperatorAddress, resValidators[4].OperatorAddress, "%v", resValidators) + + // test a basic increase in voting power + validators[3].Tokens = sdk.NewInt(500).Mul(sdk.PowerReduction) + keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[3], true) + resValidators = app.StakingKeeper.GetBondedValidatorsByPower(ctx) + require.Equal(t, len(resValidators), n) + assert.True(ValEq(t, validators[3], resValidators[0])) + + // test a decrease in voting power + validators[3].Tokens = sdk.NewInt(300).Mul(sdk.PowerReduction) + keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[3], true) + resValidators = app.StakingKeeper.GetBondedValidatorsByPower(ctx) + require.Equal(t, len(resValidators), n) + assert.True(ValEq(t, validators[3], resValidators[0])) + assert.True(ValEq(t, validators[4], resValidators[1])) + + // test equal voting power, different age + validators[3].Tokens = sdk.NewInt(200).Mul(sdk.PowerReduction) + ctx = ctx.WithBlockHeight(10) + keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[3], true) + resValidators = app.StakingKeeper.GetBondedValidatorsByPower(ctx) + require.Equal(t, len(resValidators), n) + assert.True(ValEq(t, validators[3], resValidators[0])) + assert.True(ValEq(t, validators[4], resValidators[1])) + + // no change in voting power - no change in sort + ctx = ctx.WithBlockHeight(20) + keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[4], true) + resValidators = app.StakingKeeper.GetBondedValidatorsByPower(ctx) + require.Equal(t, len(resValidators), n) + assert.True(ValEq(t, validators[3], resValidators[0])) + assert.True(ValEq(t, validators[4], resValidators[1])) + + // change in voting power of both validators, both still in v-set, no age change + validators[3].Tokens = sdk.NewInt(300).Mul(sdk.PowerReduction) + validators[4].Tokens = sdk.NewInt(300).Mul(sdk.PowerReduction) + keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[3], true) + resValidators = app.StakingKeeper.GetBondedValidatorsByPower(ctx) + require.Equal(t, len(resValidators), n) + ctx = ctx.WithBlockHeight(30) + keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[4], true) + resValidators = app.StakingKeeper.GetBondedValidatorsByPower(ctx) + require.Equal(t, len(resValidators), n, "%v", resValidators) + assert.True(ValEq(t, validators[3], resValidators[0])) + assert.True(ValEq(t, validators[4], resValidators[1])) +} From c7d68c59a94b876643a0a302cba10e48e8f70361 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Tue, 25 Feb 2020 13:38:27 +0100 Subject: [PATCH 207/529] refactor TestGetValidatorSortingMixed test to simap --- x/staking/keeper/old_validator_test.go | 58 -------------------------- x/staking/keeper/validator_test.go | 58 ++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 58 deletions(-) diff --git a/x/staking/keeper/old_validator_test.go b/x/staking/keeper/old_validator_test.go index 6745217a6ea5..9f7a8bd593e0 100644 --- a/x/staking/keeper/old_validator_test.go +++ b/x/staking/keeper/old_validator_test.go @@ -14,64 +14,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking/types" ) -func TestGetValidatorSortingMixed(t *testing.T) { - ctx, _, bk, keeper, _ := CreateTestInput(t, false, 1000) - bondedPool := keeper.GetBondedPool(ctx) - notBondedPool := keeper.GetNotBondedPool(ctx) - - bk.SetBalances(ctx, bondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), sdk.TokensFromConsensusPower(501)))) - bk.SetBalances(ctx, notBondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), sdk.TokensFromConsensusPower(0)))) - keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) - keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) - - // now 2 max resValidators - params := keeper.GetParams(ctx) - params.MaxValidators = 2 - keeper.SetParams(ctx, params) - - // initialize some validators into the state - amts := []int64{ - 0, - 100 * sdk.PowerReduction.Int64(), - 1 * sdk.PowerReduction.Int64(), - 400 * sdk.PowerReduction.Int64(), - 200 * sdk.PowerReduction.Int64()} - - var validators [5]types.Validator - for i, amt := range amts { - validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) - validators[i].DelegatorShares = sdk.NewDec(amt) - validators[i].Status = sdk.Bonded - validators[i].Tokens = sdk.NewInt(amt) - TestingUpdateValidator(keeper, ctx, validators[i], true) - } - - val0, found := keeper.GetValidator(ctx, sdk.ValAddress(Addrs[0])) - require.True(t, found) - val1, found := keeper.GetValidator(ctx, sdk.ValAddress(Addrs[1])) - require.True(t, found) - val2, found := keeper.GetValidator(ctx, sdk.ValAddress(Addrs[2])) - require.True(t, found) - val3, found := keeper.GetValidator(ctx, sdk.ValAddress(Addrs[3])) - require.True(t, found) - val4, found := keeper.GetValidator(ctx, sdk.ValAddress(Addrs[4])) - require.True(t, found) - require.Equal(t, sdk.Bonded, val0.Status) - require.Equal(t, sdk.Unbonding, val1.Status) - require.Equal(t, sdk.Unbonding, val2.Status) - require.Equal(t, sdk.Bonded, val3.Status) - require.Equal(t, sdk.Bonded, val4.Status) - - // first make sure everything made it in to the gotValidator group - resValidators := keeper.GetBondedValidatorsByPower(ctx) - // The validators returned should match the max validators - assert.Equal(t, 2, len(resValidators)) - assert.Equal(t, sdk.NewInt(400).Mul(sdk.PowerReduction), resValidators[0].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewInt(200).Mul(sdk.PowerReduction), resValidators[1].BondedTokens(), "%v", resValidators) - assert.Equal(t, validators[3].OperatorAddress, resValidators[0].OperatorAddress, "%v", resValidators) - assert.Equal(t, validators[4].OperatorAddress, resValidators[1].OperatorAddress, "%v", resValidators) -} - // TODO separate out into multiple tests func TestGetValidatorsEdgeCases(t *testing.T) { ctx, _, bk, keeper, _ := CreateTestInput(t, false, 1000) diff --git a/x/staking/keeper/validator_test.go b/x/staking/keeper/validator_test.go index 4a2a8a546c4b..c72f560d8fb3 100644 --- a/x/staking/keeper/validator_test.go +++ b/x/staking/keeper/validator_test.go @@ -392,3 +392,61 @@ func TestGetValidatorSortingUnmixed(t *testing.T) { assert.True(ValEq(t, validators[3], resValidators[0])) assert.True(ValEq(t, validators[4], resValidators[1])) } + +func TestGetValidatorSortingMixed(t *testing.T) { + app, ctx, addrs, _ := bootstrapValidatorTest(t, 1000, 20) + bondedPool := app.StakingKeeper.GetBondedPool(ctx) + notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) + + app.BankKeeper.SetBalances(ctx, bondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.TokensFromConsensusPower(501)))) + app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.TokensFromConsensusPower(0)))) + app.SupplyKeeper.SetModuleAccount(ctx, notBondedPool) + app.SupplyKeeper.SetModuleAccount(ctx, bondedPool) + + // now 2 max resValidators + params := app.StakingKeeper.GetParams(ctx) + params.MaxValidators = 2 + app.StakingKeeper.SetParams(ctx, params) + + // initialize some validators into the state + amts := []int64{ + 0, + 100 * sdk.PowerReduction.Int64(), + 1 * sdk.PowerReduction.Int64(), + 400 * sdk.PowerReduction.Int64(), + 200 * sdk.PowerReduction.Int64()} + + var validators [5]types.Validator + for i, amt := range amts { + validators[i] = types.NewValidator(sdk.ValAddress(addrs[i]), PKs[i], types.Description{}) + validators[i].DelegatorShares = sdk.NewDec(amt) + validators[i].Status = sdk.Bonded + validators[i].Tokens = sdk.NewInt(amt) + keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[i], true) + } + + val0, found := app.StakingKeeper.GetValidator(ctx, sdk.ValAddress(addrs[0])) + require.True(t, found) + val1, found := app.StakingKeeper.GetValidator(ctx, sdk.ValAddress(addrs[1])) + require.True(t, found) + val2, found := app.StakingKeeper.GetValidator(ctx, sdk.ValAddress(addrs[2])) + require.True(t, found) + val3, found := app.StakingKeeper.GetValidator(ctx, sdk.ValAddress(addrs[3])) + require.True(t, found) + val4, found := app.StakingKeeper.GetValidator(ctx, sdk.ValAddress(addrs[4])) + require.True(t, found) + require.Equal(t, sdk.Bonded, val0.Status) + require.Equal(t, sdk.Unbonding, val1.Status) + require.Equal(t, sdk.Unbonding, val2.Status) + require.Equal(t, sdk.Bonded, val3.Status) + require.Equal(t, sdk.Bonded, val4.Status) + + // first make sure everything made it in to the gotValidator group + resValidators := app.StakingKeeper.GetBondedValidatorsByPower(ctx) + // The validators returned should match the max validators + assert.Equal(t, 2, len(resValidators)) + assert.Equal(t, sdk.NewInt(400).Mul(sdk.PowerReduction), resValidators[0].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewInt(200).Mul(sdk.PowerReduction), resValidators[1].BondedTokens(), "%v", resValidators) + assert.Equal(t, validators[3].OperatorAddress, resValidators[0].OperatorAddress, "%v", resValidators) + assert.Equal(t, validators[4].OperatorAddress, resValidators[1].OperatorAddress, "%v", resValidators) +} From 99554926e87ebfa38b1afa83c3a52ebd578ffbf9 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Tue, 25 Feb 2020 13:45:29 +0100 Subject: [PATCH 208/529] refctor TestGetValidatorsEdgeCases to use simapp --- x/staking/keeper/old_validator_test.go | 116 ------------------------ x/staking/keeper/validator_test.go | 118 +++++++++++++++++++++++++ 2 files changed, 118 insertions(+), 116 deletions(-) diff --git a/x/staking/keeper/old_validator_test.go b/x/staking/keeper/old_validator_test.go index 9f7a8bd593e0..d959b9f4b373 100644 --- a/x/staking/keeper/old_validator_test.go +++ b/x/staking/keeper/old_validator_test.go @@ -14,122 +14,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking/types" ) -// TODO separate out into multiple tests -func TestGetValidatorsEdgeCases(t *testing.T) { - ctx, _, bk, keeper, _ := CreateTestInput(t, false, 1000) - - // set max validators to 2 - params := keeper.GetParams(ctx) - nMax := uint32(2) - params.MaxValidators = nMax - keeper.SetParams(ctx, params) - - // initialize some validators into the state - powers := []int64{0, 100, 400, 400} - var validators [4]types.Validator - for i, power := range powers { - moniker := fmt.Sprintf("val#%d", int64(i)) - validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{Moniker: moniker}) - - tokens := sdk.TokensFromConsensusPower(power) - validators[i], _ = validators[i].AddTokensFromDel(tokens) - - notBondedPool := keeper.GetNotBondedPool(ctx) - balances := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) - require.NoError(t, bk.SetBalances(ctx, notBondedPool.GetAddress(), balances.Add(sdk.NewCoin(params.BondDenom, tokens)))) - - keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) - validators[i] = TestingUpdateValidator(keeper, ctx, validators[i], true) - } - - // ensure that the first two bonded validators are the largest validators - resValidators := keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, nMax, uint32(len(resValidators))) - assert.True(ValEq(t, validators[2], resValidators[0])) - assert.True(ValEq(t, validators[3], resValidators[1])) - - // delegate 500 tokens to validator 0 - keeper.DeleteValidatorByPowerIndex(ctx, validators[0]) - delTokens := sdk.TokensFromConsensusPower(500) - validators[0], _ = validators[0].AddTokensFromDel(delTokens) - notBondedPool := keeper.GetNotBondedPool(ctx) - - newTokens := sdk.NewCoins() - balances := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) - require.NoError(t, bk.SetBalances(ctx, notBondedPool.GetAddress(), balances.Add(newTokens...))) - keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) - - // test that the two largest validators are - // a) validator 0 with 500 tokens - // b) validator 2 with 400 tokens (delegated before validator 3) - validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], true) - resValidators = keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, nMax, uint32(len(resValidators))) - assert.True(ValEq(t, validators[0], resValidators[0])) - assert.True(ValEq(t, validators[2], resValidators[1])) - - // A validator which leaves the bonded validator set due to a decrease in voting power, - // then increases to the original voting power, does not get its spot back in the - // case of a tie. - // - // Order of operations for this test: - // - validator 3 enter validator set with 1 new token - // - validator 3 removed validator set by removing 201 tokens (validator 2 enters) - // - validator 3 adds 200 tokens (equal to validator 2 now) and does not get its spot back - - // validator 3 enters bonded validator set - ctx = ctx.WithBlockHeight(40) - - validators[3] = keeper.mustGetValidator(ctx, validators[3].OperatorAddress) - keeper.DeleteValidatorByPowerIndex(ctx, validators[3]) - validators[3], _ = validators[3].AddTokensFromDel(sdk.TokensFromConsensusPower(1)) - - notBondedPool = keeper.GetNotBondedPool(ctx) - newTokens = sdk.NewCoins(sdk.NewCoin(params.BondDenom, sdk.TokensFromConsensusPower(1))) - balances = bk.GetAllBalances(ctx, notBondedPool.GetAddress()) - require.NoError(t, bk.SetBalances(ctx, notBondedPool.GetAddress(), balances.Add(newTokens...))) - keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) - - validators[3] = TestingUpdateValidator(keeper, ctx, validators[3], true) - resValidators = keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, nMax, uint32(len(resValidators))) - assert.True(ValEq(t, validators[0], resValidators[0])) - assert.True(ValEq(t, validators[3], resValidators[1])) - - // validator 3 kicked out temporarily - keeper.DeleteValidatorByPowerIndex(ctx, validators[3]) - rmTokens := validators[3].TokensFromShares(sdk.NewDec(201)).TruncateInt() - validators[3], _ = validators[3].RemoveDelShares(sdk.NewDec(201)) - - bondedPool := keeper.GetBondedPool(ctx) - balances = bk.GetAllBalances(ctx, bondedPool.GetAddress()) - require.NoError(t, bk.SetBalances(ctx, bondedPool.GetAddress(), balances.Add(sdk.NewCoin(params.BondDenom, rmTokens)))) - keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) - - validators[3] = TestingUpdateValidator(keeper, ctx, validators[3], true) - resValidators = keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, nMax, uint32(len(resValidators))) - assert.True(ValEq(t, validators[0], resValidators[0])) - assert.True(ValEq(t, validators[2], resValidators[1])) - - // validator 3 does not get spot back - keeper.DeleteValidatorByPowerIndex(ctx, validators[3]) - validators[3], _ = validators[3].AddTokensFromDel(sdk.NewInt(200)) - - notBondedPool = keeper.GetNotBondedPool(ctx) - balances = bk.GetAllBalances(ctx, notBondedPool.GetAddress()) - require.NoError(t, bk.SetBalances(ctx, notBondedPool.GetAddress(), balances.Add(sdk.NewCoin(params.BondDenom, sdk.NewInt(200))))) - keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) - - validators[3] = TestingUpdateValidator(keeper, ctx, validators[3], true) - resValidators = keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, nMax, uint32(len(resValidators))) - assert.True(ValEq(t, validators[0], resValidators[0])) - assert.True(ValEq(t, validators[2], resValidators[1])) - _, exists := keeper.GetValidator(ctx, validators[3].OperatorAddress) - require.True(t, exists) -} - func TestValidatorBondHeight(t *testing.T) { ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) diff --git a/x/staking/keeper/validator_test.go b/x/staking/keeper/validator_test.go index c72f560d8fb3..8a122c6c3748 100644 --- a/x/staking/keeper/validator_test.go +++ b/x/staking/keeper/validator_test.go @@ -450,3 +450,121 @@ func TestGetValidatorSortingMixed(t *testing.T) { assert.Equal(t, validators[3].OperatorAddress, resValidators[0].OperatorAddress, "%v", resValidators) assert.Equal(t, validators[4].OperatorAddress, resValidators[1].OperatorAddress, "%v", resValidators) } + +// TODO separate out into multiple tests +func TestGetValidatorsEdgeCases(t *testing.T) { + app, ctx, addrs, _ := bootstrapValidatorTest(t, 1000, 20) + + // set max validators to 2 + params := app.StakingKeeper.GetParams(ctx) + nMax := uint32(2) + params.MaxValidators = nMax + app.StakingKeeper.SetParams(ctx, params) + + // initialize some validators into the state + powers := []int64{0, 100, 400, 400} + var validators [4]types.Validator + for i, power := range powers { + moniker := fmt.Sprintf("val#%d", int64(i)) + validators[i] = types.NewValidator(sdk.ValAddress(addrs[i]), PKs[i], types.Description{Moniker: moniker}) + + tokens := sdk.TokensFromConsensusPower(power) + validators[i], _ = validators[i].AddTokensFromDel(tokens) + + notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) + balances := app.BankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) + require.NoError(t, app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), balances.Add(sdk.NewCoin(params.BondDenom, tokens)))) + + app.SupplyKeeper.SetModuleAccount(ctx, notBondedPool) + validators[i] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[i], true) + } + + // ensure that the first two bonded validators are the largest validators + resValidators := app.StakingKeeper.GetBondedValidatorsByPower(ctx) + require.Equal(t, nMax, uint32(len(resValidators))) + assert.True(ValEq(t, validators[2], resValidators[0])) + assert.True(ValEq(t, validators[3], resValidators[1])) + + // delegate 500 tokens to validator 0 + app.StakingKeeper.DeleteValidatorByPowerIndex(ctx, validators[0]) + delTokens := sdk.TokensFromConsensusPower(500) + validators[0], _ = validators[0].AddTokensFromDel(delTokens) + notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) + + newTokens := sdk.NewCoins() + balances := app.BankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) + require.NoError(t, app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), balances.Add(newTokens...))) + app.SupplyKeeper.SetModuleAccount(ctx, notBondedPool) + + // test that the two largest validators are + // a) validator 0 with 500 tokens + // b) validator 2 with 400 tokens (delegated before validator 3) + validators[0] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[0], true) + resValidators = app.StakingKeeper.GetBondedValidatorsByPower(ctx) + require.Equal(t, nMax, uint32(len(resValidators))) + assert.True(ValEq(t, validators[0], resValidators[0])) + assert.True(ValEq(t, validators[2], resValidators[1])) + + // A validator which leaves the bonded validator set due to a decrease in voting power, + // then increases to the original voting power, does not get its spot back in the + // case of a tie. + // + // Order of operations for this test: + // - validator 3 enter validator set with 1 new token + // - validator 3 removed validator set by removing 201 tokens (validator 2 enters) + // - validator 3 adds 200 tokens (equal to validator 2 now) and does not get its spot back + + // validator 3 enters bonded validator set + ctx = ctx.WithBlockHeight(40) + + var found bool + validators[3], found = app.StakingKeeper.GetValidator(ctx, validators[3].OperatorAddress) + assert.True(t, found) + app.StakingKeeper.DeleteValidatorByPowerIndex(ctx, validators[3]) + validators[3], _ = validators[3].AddTokensFromDel(sdk.TokensFromConsensusPower(1)) + + notBondedPool = app.StakingKeeper.GetNotBondedPool(ctx) + newTokens = sdk.NewCoins(sdk.NewCoin(params.BondDenom, sdk.TokensFromConsensusPower(1))) + balances = app.BankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) + require.NoError(t, app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), balances.Add(newTokens...))) + app.SupplyKeeper.SetModuleAccount(ctx, notBondedPool) + + validators[3] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[3], true) + resValidators = app.StakingKeeper.GetBondedValidatorsByPower(ctx) + require.Equal(t, nMax, uint32(len(resValidators))) + assert.True(ValEq(t, validators[0], resValidators[0])) + assert.True(ValEq(t, validators[3], resValidators[1])) + + // validator 3 kicked out temporarily + app.StakingKeeper.DeleteValidatorByPowerIndex(ctx, validators[3]) + rmTokens := validators[3].TokensFromShares(sdk.NewDec(201)).TruncateInt() + validators[3], _ = validators[3].RemoveDelShares(sdk.NewDec(201)) + + bondedPool := app.StakingKeeper.GetBondedPool(ctx) + balances = app.BankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + require.NoError(t, app.BankKeeper.SetBalances(ctx, bondedPool.GetAddress(), balances.Add(sdk.NewCoin(params.BondDenom, rmTokens)))) + app.SupplyKeeper.SetModuleAccount(ctx, bondedPool) + + validators[3] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[3], true) + resValidators = app.StakingKeeper.GetBondedValidatorsByPower(ctx) + require.Equal(t, nMax, uint32(len(resValidators))) + assert.True(ValEq(t, validators[0], resValidators[0])) + assert.True(ValEq(t, validators[2], resValidators[1])) + + // validator 3 does not get spot back + app.StakingKeeper.DeleteValidatorByPowerIndex(ctx, validators[3]) + validators[3], _ = validators[3].AddTokensFromDel(sdk.NewInt(200)) + + notBondedPool = app.StakingKeeper.GetNotBondedPool(ctx) + balances = app.BankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) + require.NoError(t, app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), balances.Add(sdk.NewCoin(params.BondDenom, sdk.NewInt(200))))) + app.SupplyKeeper.SetModuleAccount(ctx, notBondedPool) + + validators[3] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[3], true) + resValidators = app.StakingKeeper.GetBondedValidatorsByPower(ctx) + require.Equal(t, nMax, uint32(len(resValidators))) + assert.True(ValEq(t, validators[0], resValidators[0])) + assert.True(ValEq(t, validators[2], resValidators[1])) + _, exists := app.StakingKeeper.GetValidator(ctx, validators[3].OperatorAddress) + require.True(t, exists) +} From 96216c3dac388648cf66edf39fd626ef22703823 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Tue, 25 Feb 2020 13:51:48 +0100 Subject: [PATCH 209/529] make test TestValidatorBondHeight pass --- x/staking/keeper/old_validator_test.go | 47 -------------------------- x/staking/keeper/validator_test.go | 47 ++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 47 deletions(-) diff --git a/x/staking/keeper/old_validator_test.go b/x/staking/keeper/old_validator_test.go index d959b9f4b373..729903548d79 100644 --- a/x/staking/keeper/old_validator_test.go +++ b/x/staking/keeper/old_validator_test.go @@ -14,53 +14,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking/types" ) -func TestValidatorBondHeight(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - - // now 2 max resValidators - params := keeper.GetParams(ctx) - params.MaxValidators = 2 - keeper.SetParams(ctx, params) - - // initialize some validators into the state - var validators [3]types.Validator - validators[0] = types.NewValidator(sdk.ValAddress(PKs[0].Address().Bytes()), PKs[0], types.Description{}) - validators[1] = types.NewValidator(sdk.ValAddress(Addrs[1]), PKs[1], types.Description{}) - validators[2] = types.NewValidator(sdk.ValAddress(Addrs[2]), PKs[2], types.Description{}) - - tokens0 := sdk.TokensFromConsensusPower(200) - tokens1 := sdk.TokensFromConsensusPower(100) - tokens2 := sdk.TokensFromConsensusPower(100) - validators[0], _ = validators[0].AddTokensFromDel(tokens0) - validators[1], _ = validators[1].AddTokensFromDel(tokens1) - validators[2], _ = validators[2].AddTokensFromDel(tokens2) - - validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], true) - - //////////////////////////////////////// - // If two validators both increase to the same voting power in the same block, - // the one with the first transaction should become bonded - validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], true) - validators[2] = TestingUpdateValidator(keeper, ctx, validators[2], true) - - resValidators := keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, uint32(len(resValidators)), params.MaxValidators) - - assert.True(ValEq(t, validators[0], resValidators[0])) - assert.True(ValEq(t, validators[1], resValidators[1])) - keeper.DeleteValidatorByPowerIndex(ctx, validators[1]) - keeper.DeleteValidatorByPowerIndex(ctx, validators[2]) - delTokens := sdk.TokensFromConsensusPower(50) - validators[1], _ = validators[1].AddTokensFromDel(delTokens) - validators[2], _ = validators[2].AddTokensFromDel(delTokens) - validators[2] = TestingUpdateValidator(keeper, ctx, validators[2], true) - resValidators = keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, params.MaxValidators, uint32(len(resValidators))) - validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], true) - assert.True(ValEq(t, validators[0], resValidators[0])) - assert.True(ValEq(t, validators[2], resValidators[1])) -} - func TestFullValidatorSetPowerChange(t *testing.T) { ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) params := keeper.GetParams(ctx) diff --git a/x/staking/keeper/validator_test.go b/x/staking/keeper/validator_test.go index 8a122c6c3748..04bf52159c46 100644 --- a/x/staking/keeper/validator_test.go +++ b/x/staking/keeper/validator_test.go @@ -568,3 +568,50 @@ func TestGetValidatorsEdgeCases(t *testing.T) { _, exists := app.StakingKeeper.GetValidator(ctx, validators[3].OperatorAddress) require.True(t, exists) } + +func TestValidatorBondHeight(t *testing.T) { + app, ctx, addrs, _ := bootstrapValidatorTest(t, 1000, 20) + + // now 2 max resValidators + params := app.StakingKeeper.GetParams(ctx) + params.MaxValidators = 2 + app.StakingKeeper.SetParams(ctx, params) + + // initialize some validators into the state + var validators [3]types.Validator + validators[0] = types.NewValidator(sdk.ValAddress(PKs[0].Address().Bytes()), PKs[0], types.Description{}) + validators[1] = types.NewValidator(sdk.ValAddress(addrs[1]), PKs[1], types.Description{}) + validators[2] = types.NewValidator(sdk.ValAddress(addrs[2]), PKs[2], types.Description{}) + + tokens0 := sdk.TokensFromConsensusPower(200) + tokens1 := sdk.TokensFromConsensusPower(100) + tokens2 := sdk.TokensFromConsensusPower(100) + validators[0], _ = validators[0].AddTokensFromDel(tokens0) + validators[1], _ = validators[1].AddTokensFromDel(tokens1) + validators[2], _ = validators[2].AddTokensFromDel(tokens2) + + validators[0] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[0], true) + + //////////////////////////////////////// + // If two validators both increase to the same voting power in the same block, + // the one with the first transaction should become bonded + validators[1] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[1], true) + validators[2] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[2], true) + + resValidators := app.StakingKeeper.GetBondedValidatorsByPower(ctx) + require.Equal(t, uint32(len(resValidators)), params.MaxValidators) + + assert.True(ValEq(t, validators[0], resValidators[0])) + assert.True(ValEq(t, validators[1], resValidators[1])) + app.StakingKeeper.DeleteValidatorByPowerIndex(ctx, validators[1]) + app.StakingKeeper.DeleteValidatorByPowerIndex(ctx, validators[2]) + delTokens := sdk.TokensFromConsensusPower(50) + validators[1], _ = validators[1].AddTokensFromDel(delTokens) + validators[2], _ = validators[2].AddTokensFromDel(delTokens) + validators[2] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[2], true) + resValidators = app.StakingKeeper.GetBondedValidatorsByPower(ctx) + require.Equal(t, params.MaxValidators, uint32(len(resValidators))) + validators[1] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[1], true) + assert.True(ValEq(t, validators[0], resValidators[0])) + assert.True(ValEq(t, validators[2], resValidators[1])) +} From b4ab8e5e077c2a6dddcfd717ef5efce52b392b86 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Tue, 25 Feb 2020 13:54:55 +0100 Subject: [PATCH 210/529] refactor TestFullValidatorSetPowerChange test --- x/staking/keeper/old_validator_test.go | 42 -------------------------- x/staking/keeper/validator_test.go | 42 ++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 42 deletions(-) diff --git a/x/staking/keeper/old_validator_test.go b/x/staking/keeper/old_validator_test.go index 729903548d79..fa0884733d0b 100644 --- a/x/staking/keeper/old_validator_test.go +++ b/x/staking/keeper/old_validator_test.go @@ -14,48 +14,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking/types" ) -func TestFullValidatorSetPowerChange(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - params := keeper.GetParams(ctx) - max := 2 - params.MaxValidators = uint32(2) - keeper.SetParams(ctx, params) - - // initialize some validators into the state - powers := []int64{0, 100, 400, 400, 200} - var validators [5]types.Validator - for i, power := range powers { - validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) - tokens := sdk.TokensFromConsensusPower(power) - validators[i], _ = validators[i].AddTokensFromDel(tokens) - TestingUpdateValidator(keeper, ctx, validators[i], true) - } - for i := range powers { - var found bool - validators[i], found = keeper.GetValidator(ctx, validators[i].OperatorAddress) - require.True(t, found) - } - assert.Equal(t, sdk.Unbonded, validators[0].Status) - assert.Equal(t, sdk.Unbonding, validators[1].Status) - assert.Equal(t, sdk.Bonded, validators[2].Status) - assert.Equal(t, sdk.Bonded, validators[3].Status) - assert.Equal(t, sdk.Unbonded, validators[4].Status) - resValidators := keeper.GetBondedValidatorsByPower(ctx) - assert.Equal(t, max, len(resValidators)) - assert.True(ValEq(t, validators[2], resValidators[0])) // in the order of txs - assert.True(ValEq(t, validators[3], resValidators[1])) - - // test a swap in voting power - - tokens := sdk.TokensFromConsensusPower(600) - validators[0], _ = validators[0].AddTokensFromDel(tokens) - validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], true) - resValidators = keeper.GetBondedValidatorsByPower(ctx) - assert.Equal(t, max, len(resValidators)) - assert.True(ValEq(t, validators[0], resValidators[0])) - assert.True(ValEq(t, validators[2], resValidators[1])) -} - func TestApplyAndReturnValidatorSetUpdatesAllNone(t *testing.T) { ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) diff --git a/x/staking/keeper/validator_test.go b/x/staking/keeper/validator_test.go index 04bf52159c46..2d87b5497878 100644 --- a/x/staking/keeper/validator_test.go +++ b/x/staking/keeper/validator_test.go @@ -615,3 +615,45 @@ func TestValidatorBondHeight(t *testing.T) { assert.True(ValEq(t, validators[0], resValidators[0])) assert.True(ValEq(t, validators[2], resValidators[1])) } + +func TestFullValidatorSetPowerChange(t *testing.T) { + app, ctx, addrs, _ := bootstrapValidatorTest(t, 1000, 20) + params := app.StakingKeeper.GetParams(ctx) + max := 2 + params.MaxValidators = uint32(2) + app.StakingKeeper.SetParams(ctx, params) + + // initialize some validators into the state + powers := []int64{0, 100, 400, 400, 200} + var validators [5]types.Validator + for i, power := range powers { + validators[i] = types.NewValidator(sdk.ValAddress(addrs[i]), PKs[i], types.Description{}) + tokens := sdk.TokensFromConsensusPower(power) + validators[i], _ = validators[i].AddTokensFromDel(tokens) + keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[i], true) + } + for i := range powers { + var found bool + validators[i], found = app.StakingKeeper.GetValidator(ctx, validators[i].OperatorAddress) + require.True(t, found) + } + assert.Equal(t, sdk.Unbonded, validators[0].Status) + assert.Equal(t, sdk.Unbonding, validators[1].Status) + assert.Equal(t, sdk.Bonded, validators[2].Status) + assert.Equal(t, sdk.Bonded, validators[3].Status) + assert.Equal(t, sdk.Unbonded, validators[4].Status) + resValidators := app.StakingKeeper.GetBondedValidatorsByPower(ctx) + assert.Equal(t, max, len(resValidators)) + assert.True(ValEq(t, validators[2], resValidators[0])) // in the order of txs + assert.True(ValEq(t, validators[3], resValidators[1])) + + // test a swap in voting power + + tokens := sdk.TokensFromConsensusPower(600) + validators[0], _ = validators[0].AddTokensFromDel(tokens) + validators[0] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[0], true) + resValidators = app.StakingKeeper.GetBondedValidatorsByPower(ctx) + assert.Equal(t, max, len(resValidators)) + assert.True(ValEq(t, validators[0], resValidators[0])) + assert.True(ValEq(t, validators[2], resValidators[1])) +} From 9ae53260bff743c10f2308a90dbc8c4b72057718 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Tue, 25 Feb 2020 14:07:01 +0100 Subject: [PATCH 211/529] end refactoring validator_test --- x/staking/keeper/old_validator_test.go | 472 ------------------------- x/staking/keeper/validator_test.go | 469 +++++++++++++++++++++++- 2 files changed, 463 insertions(+), 478 deletions(-) delete mode 100644 x/staking/keeper/old_validator_test.go diff --git a/x/staking/keeper/old_validator_test.go b/x/staking/keeper/old_validator_test.go deleted file mode 100644 index fa0884733d0b..000000000000 --- a/x/staking/keeper/old_validator_test.go +++ /dev/null @@ -1,472 +0,0 @@ -package keeper - -import ( - "fmt" - "testing" - "time" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - abci "github.com/tendermint/tendermint/abci/types" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/staking/types" -) - -func TestApplyAndReturnValidatorSetUpdatesAllNone(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - - powers := []int64{10, 20} - var validators [2]types.Validator - for i, power := range powers { - valPubKey := PKs[i+1] - valAddr := sdk.ValAddress(valPubKey.Address().Bytes()) - - validators[i] = types.NewValidator(valAddr, valPubKey, types.Description{}) - tokens := sdk.TokensFromConsensusPower(power) - validators[i], _ = validators[i].AddTokensFromDel(tokens) - } - - // test from nothing to something - // tendermintUpdate set: {} -> {c1, c3} - require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) - keeper.SetValidator(ctx, validators[0]) - keeper.SetValidatorByPowerIndex(ctx, validators[0]) - keeper.SetValidator(ctx, validators[1]) - keeper.SetValidatorByPowerIndex(ctx, validators[1]) - - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - assert.Equal(t, 2, len(updates)) - validators[0], _ = keeper.GetValidator(ctx, validators[0].OperatorAddress) - validators[1], _ = keeper.GetValidator(ctx, validators[1].OperatorAddress) - assert.Equal(t, validators[0].ABCIValidatorUpdate(), updates[1]) - assert.Equal(t, validators[1].ABCIValidatorUpdate(), updates[0]) -} - -func TestApplyAndReturnValidatorSetUpdatesIdentical(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - - powers := []int64{10, 20} - var validators [2]types.Validator - for i, power := range powers { - validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) - - tokens := sdk.TokensFromConsensusPower(power) - validators[i], _ = validators[i].AddTokensFromDel(tokens) - - } - validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], false) - validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], false) - require.Equal(t, 2, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) - - // test identical, - // tendermintUpdate set: {} -> {} - validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], false) - validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], false) - require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) -} - -func TestApplyAndReturnValidatorSetUpdatesSingleValueChange(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - - powers := []int64{10, 20} - var validators [2]types.Validator - for i, power := range powers { - - validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) - - tokens := sdk.TokensFromConsensusPower(power) - validators[i], _ = validators[i].AddTokensFromDel(tokens) - - } - validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], false) - validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], false) - require.Equal(t, 2, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) - - // test single value change - // tendermintUpdate set: {} -> {c1'} - validators[0].Status = sdk.Bonded - validators[0].Tokens = sdk.TokensFromConsensusPower(600) - validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], false) - - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - - require.Equal(t, 1, len(updates)) - require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[0]) -} - -func TestApplyAndReturnValidatorSetUpdatesMultipleValueChange(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - - powers := []int64{10, 20} - var validators [2]types.Validator - for i, power := range powers { - - validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) - - tokens := sdk.TokensFromConsensusPower(power) - validators[i], _ = validators[i].AddTokensFromDel(tokens) - - } - validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], false) - validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], false) - require.Equal(t, 2, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) - - // test multiple value change - // tendermintUpdate set: {c1, c3} -> {c1', c3'} - delTokens1 := sdk.TokensFromConsensusPower(190) - delTokens2 := sdk.TokensFromConsensusPower(80) - validators[0], _ = validators[0].AddTokensFromDel(delTokens1) - validators[1], _ = validators[1].AddTokensFromDel(delTokens2) - validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], false) - validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], false) - - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 2, len(updates)) - require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[0]) - require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[1]) -} - -func TestApplyAndReturnValidatorSetUpdatesInserted(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - - powers := []int64{10, 20, 5, 15, 25} - var validators [5]types.Validator - for i, power := range powers { - - validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) - - tokens := sdk.TokensFromConsensusPower(power) - validators[i], _ = validators[i].AddTokensFromDel(tokens) - - } - - validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], false) - validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], false) - require.Equal(t, 2, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) - - // test validtor added at the beginning - // tendermintUpdate set: {} -> {c0} - keeper.SetValidator(ctx, validators[2]) - keeper.SetValidatorByPowerIndex(ctx, validators[2]) - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - validators[2], _ = keeper.GetValidator(ctx, validators[2].OperatorAddress) - require.Equal(t, 1, len(updates)) - require.Equal(t, validators[2].ABCIValidatorUpdate(), updates[0]) - - // test validtor added at the beginning - // tendermintUpdate set: {} -> {c0} - keeper.SetValidator(ctx, validators[3]) - keeper.SetValidatorByPowerIndex(ctx, validators[3]) - updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx) - validators[3], _ = keeper.GetValidator(ctx, validators[3].OperatorAddress) - require.Equal(t, 1, len(updates)) - require.Equal(t, validators[3].ABCIValidatorUpdate(), updates[0]) - - // test validtor added at the end - // tendermintUpdate set: {} -> {c0} - keeper.SetValidator(ctx, validators[4]) - keeper.SetValidatorByPowerIndex(ctx, validators[4]) - updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx) - validators[4], _ = keeper.GetValidator(ctx, validators[4].OperatorAddress) - require.Equal(t, 1, len(updates)) - require.Equal(t, validators[4].ABCIValidatorUpdate(), updates[0]) -} - -func TestApplyAndReturnValidatorSetUpdatesWithCliffValidator(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - params := types.DefaultParams() - params.MaxValidators = 2 - keeper.SetParams(ctx, params) - - powers := []int64{10, 20, 5} - var validators [5]types.Validator - for i, power := range powers { - - validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) - - tokens := sdk.TokensFromConsensusPower(power) - validators[i], _ = validators[i].AddTokensFromDel(tokens) - - } - validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], false) - validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], false) - require.Equal(t, 2, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) - - // test validator added at the end but not inserted in the valset - // tendermintUpdate set: {} -> {} - TestingUpdateValidator(keeper, ctx, validators[2], false) - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 0, len(updates)) - - // test validator change its power and become a gotValidator (pushing out an existing) - // tendermintUpdate set: {} -> {c0, c4} - require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) - - tokens := sdk.TokensFromConsensusPower(10) - validators[2], _ = validators[2].AddTokensFromDel(tokens) - keeper.SetValidator(ctx, validators[2]) - keeper.SetValidatorByPowerIndex(ctx, validators[2]) - updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx) - validators[2], _ = keeper.GetValidator(ctx, validators[2].OperatorAddress) - require.Equal(t, 2, len(updates), "%v", updates) - require.Equal(t, validators[0].ABCIValidatorUpdateZero(), updates[1]) - require.Equal(t, validators[2].ABCIValidatorUpdate(), updates[0]) -} - -func TestApplyAndReturnValidatorSetUpdatesPowerDecrease(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - - powers := []int64{100, 100} - var validators [2]types.Validator - for i, power := range powers { - - validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) - - tokens := sdk.TokensFromConsensusPower(power) - validators[i], _ = validators[i].AddTokensFromDel(tokens) - - } - validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], false) - validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], false) - require.Equal(t, 2, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) - - // check initial power - require.Equal(t, int64(100), validators[0].GetConsensusPower()) - require.Equal(t, int64(100), validators[1].GetConsensusPower()) - - // test multiple value change - // tendermintUpdate set: {c1, c3} -> {c1', c3'} - delTokens1 := sdk.TokensFromConsensusPower(20) - delTokens2 := sdk.TokensFromConsensusPower(30) - validators[0], _ = validators[0].RemoveDelShares(delTokens1.ToDec()) - validators[1], _ = validators[1].RemoveDelShares(delTokens2.ToDec()) - validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], false) - validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], false) - - // power has changed - require.Equal(t, int64(80), validators[0].GetConsensusPower()) - require.Equal(t, int64(70), validators[1].GetConsensusPower()) - - // Tendermint updates should reflect power change - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 2, len(updates)) - require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[0]) - require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[1]) -} - -func TestApplyAndReturnValidatorSetUpdatesNewValidator(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - params := keeper.GetParams(ctx) - params.MaxValidators = uint32(3) - - keeper.SetParams(ctx, params) - - powers := []int64{100, 100} - var validators [2]types.Validator - - // initialize some validators into the state - for i, power := range powers { - - valPubKey := PKs[i+1] - valAddr := sdk.ValAddress(valPubKey.Address().Bytes()) - - validators[i] = types.NewValidator(valAddr, valPubKey, types.Description{}) - tokens := sdk.TokensFromConsensusPower(power) - validators[i], _ = validators[i].AddTokensFromDel(tokens) - - keeper.SetValidator(ctx, validators[i]) - keeper.SetValidatorByPowerIndex(ctx, validators[i]) - } - - // verify initial Tendermint updates are correct - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, len(validators), len(updates)) - validators[0], _ = keeper.GetValidator(ctx, validators[0].OperatorAddress) - validators[1], _ = keeper.GetValidator(ctx, validators[1].OperatorAddress) - require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[0]) - require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[1]) - - require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) - - // update initial validator set - for i, power := range powers { - - keeper.DeleteValidatorByPowerIndex(ctx, validators[i]) - tokens := sdk.TokensFromConsensusPower(power) - validators[i], _ = validators[i].AddTokensFromDel(tokens) - - keeper.SetValidator(ctx, validators[i]) - keeper.SetValidatorByPowerIndex(ctx, validators[i]) - } - - // add a new validator that goes from zero power, to non-zero power, back to - // zero power - valPubKey := PKs[len(validators)+1] - valAddr := sdk.ValAddress(valPubKey.Address().Bytes()) - amt := sdk.NewInt(100) - - validator := types.NewValidator(valAddr, valPubKey, types.Description{}) - validator, _ = validator.AddTokensFromDel(amt) - - keeper.SetValidator(ctx, validator) - - validator, _ = validator.RemoveDelShares(amt.ToDec()) - keeper.SetValidator(ctx, validator) - keeper.SetValidatorByPowerIndex(ctx, validator) - - // add a new validator that increases in power - valPubKey = PKs[len(validators)+2] - valAddr = sdk.ValAddress(valPubKey.Address().Bytes()) - - validator = types.NewValidator(valAddr, valPubKey, types.Description{}) - tokens := sdk.TokensFromConsensusPower(500) - validator, _ = validator.AddTokensFromDel(tokens) - keeper.SetValidator(ctx, validator) - keeper.SetValidatorByPowerIndex(ctx, validator) - - // verify initial Tendermint updates are correct - updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx) - validator, _ = keeper.GetValidator(ctx, validator.OperatorAddress) - validators[0], _ = keeper.GetValidator(ctx, validators[0].OperatorAddress) - validators[1], _ = keeper.GetValidator(ctx, validators[1].OperatorAddress) - require.Equal(t, len(validators)+1, len(updates)) - require.Equal(t, validator.ABCIValidatorUpdate(), updates[0]) - require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[1]) - require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[2]) -} - -func TestApplyAndReturnValidatorSetUpdatesBondTransition(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - params := keeper.GetParams(ctx) - params.MaxValidators = uint32(2) - - keeper.SetParams(ctx, params) - - powers := []int64{100, 200, 300} - var validators [3]types.Validator - - // initialize some validators into the state - for i, power := range powers { - moniker := fmt.Sprintf("%d", i) - valPubKey := PKs[i+1] - valAddr := sdk.ValAddress(valPubKey.Address().Bytes()) - - validators[i] = types.NewValidator(valAddr, valPubKey, types.Description{Moniker: moniker}) - tokens := sdk.TokensFromConsensusPower(power) - validators[i], _ = validators[i].AddTokensFromDel(tokens) - keeper.SetValidator(ctx, validators[i]) - keeper.SetValidatorByPowerIndex(ctx, validators[i]) - } - - // verify initial Tendermint updates are correct - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 2, len(updates)) - validators[2], _ = keeper.GetValidator(ctx, validators[2].OperatorAddress) - validators[1], _ = keeper.GetValidator(ctx, validators[1].OperatorAddress) - require.Equal(t, validators[2].ABCIValidatorUpdate(), updates[0]) - require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[1]) - - require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) - - // delegate to validator with lowest power but not enough to bond - ctx = ctx.WithBlockHeight(1) - - var found bool - validators[0], found = keeper.GetValidator(ctx, validators[0].OperatorAddress) - require.True(t, found) - - keeper.DeleteValidatorByPowerIndex(ctx, validators[0]) - tokens := sdk.TokensFromConsensusPower(1) - validators[0], _ = validators[0].AddTokensFromDel(tokens) - keeper.SetValidator(ctx, validators[0]) - keeper.SetValidatorByPowerIndex(ctx, validators[0]) - - // verify initial Tendermint updates are correct - require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) - - // create a series of events that will bond and unbond the validator with - // lowest power in a single block context (height) - ctx = ctx.WithBlockHeight(2) - - validators[1], found = keeper.GetValidator(ctx, validators[1].OperatorAddress) - require.True(t, found) - - keeper.DeleteValidatorByPowerIndex(ctx, validators[0]) - validators[0], _ = validators[0].RemoveDelShares(validators[0].DelegatorShares) - keeper.SetValidator(ctx, validators[0]) - keeper.SetValidatorByPowerIndex(ctx, validators[0]) - updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 0, len(updates)) - - keeper.DeleteValidatorByPowerIndex(ctx, validators[1]) - tokens = sdk.TokensFromConsensusPower(250) - validators[1], _ = validators[1].AddTokensFromDel(tokens) - keeper.SetValidator(ctx, validators[1]) - keeper.SetValidatorByPowerIndex(ctx, validators[1]) - - // verify initial Tendermint updates are correct - updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 1, len(updates)) - require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[0]) - - require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) -} - -func TestUpdateValidatorCommission(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - ctx = ctx.WithBlockHeader(abci.Header{Time: time.Now().UTC()}) - - commission1 := types.NewCommissionWithTime( - sdk.NewDecWithPrec(1, 1), sdk.NewDecWithPrec(3, 1), - sdk.NewDecWithPrec(1, 1), time.Now().UTC().Add(time.Duration(-1)*time.Hour), - ) - commission2 := types.NewCommission(sdk.NewDecWithPrec(1, 1), sdk.NewDecWithPrec(3, 1), sdk.NewDecWithPrec(1, 1)) - - val1 := types.NewValidator(addrVals[0], PKs[0], types.Description{}) - val2 := types.NewValidator(addrVals[1], PKs[1], types.Description{}) - - val1, _ = val1.SetInitialCommission(commission1) - val2, _ = val2.SetInitialCommission(commission2) - - keeper.SetValidator(ctx, val1) - keeper.SetValidator(ctx, val2) - - testCases := []struct { - validator types.Validator - newRate sdk.Dec - expectedErr bool - }{ - {val1, sdk.ZeroDec(), true}, - {val2, sdk.NewDecWithPrec(-1, 1), true}, - {val2, sdk.NewDecWithPrec(4, 1), true}, - {val2, sdk.NewDecWithPrec(3, 1), true}, - {val2, sdk.NewDecWithPrec(2, 1), false}, - } - - for i, tc := range testCases { - commission, err := keeper.UpdateValidatorCommission(ctx, tc.validator, tc.newRate) - - if tc.expectedErr { - require.Error(t, err, "expected error for test case #%d with rate: %s", i, tc.newRate) - } else { - tc.validator.Commission = commission - keeper.SetValidator(ctx, tc.validator) - val, found := keeper.GetValidator(ctx, tc.validator.OperatorAddress) - - require.True(t, found, - "expected to find validator for test case #%d with rate: %s", i, tc.newRate, - ) - require.NoError(t, err, - "unexpected error for test case #%d with rate: %s", i, tc.newRate, - ) - require.Equal(t, tc.newRate, val.Commission.Rate, - "expected new validator commission rate for test case #%d with rate: %s", i, tc.newRate, - ) - require.Equal(t, ctx.BlockHeader().Time, val.Commission.UpdateTime, - "expected new validator commission update time for test case #%d with rate: %s", i, tc.newRate, - ) - } - } -} diff --git a/x/staking/keeper/validator_test.go b/x/staking/keeper/validator_test.go index 2d87b5497878..6f2be5472501 100644 --- a/x/staking/keeper/validator_test.go +++ b/x/staking/keeper/validator_test.go @@ -3,18 +3,18 @@ package keeper_test import ( "fmt" "testing" - - "github.com/cosmos/cosmos-sdk/x/supply" - - "github.com/cosmos/cosmos-sdk/x/staking/keeper" - - "github.com/cosmos/cosmos-sdk/simapp" + "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/staking/keeper" "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/cosmos/cosmos-sdk/x/supply" ) func bootstrapValidatorTest(t *testing.T, power int64, numAddrs int) (*simapp.SimApp, sdk.Context, []sdk.AccAddress, []sdk.ValAddress) { @@ -657,3 +657,460 @@ func TestFullValidatorSetPowerChange(t *testing.T) { assert.True(ValEq(t, validators[0], resValidators[0])) assert.True(ValEq(t, validators[2], resValidators[1])) } + +func TestApplyAndReturnValidatorSetUpdatesAllNone(t *testing.T) { + app, ctx, _, _ := bootstrapValidatorTest(t, 1000, 20) + + powers := []int64{10, 20} + var validators [2]types.Validator + for i, power := range powers { + valPubKey := PKs[i+1] + valAddr := sdk.ValAddress(valPubKey.Address().Bytes()) + + validators[i] = types.NewValidator(valAddr, valPubKey, types.Description{}) + tokens := sdk.TokensFromConsensusPower(power) + validators[i], _ = validators[i].AddTokensFromDel(tokens) + } + + // test from nothing to something + // tendermintUpdate set: {} -> {c1, c3} + require.Equal(t, 0, len(app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx))) + app.StakingKeeper.SetValidator(ctx, validators[0]) + app.StakingKeeper.SetValidatorByPowerIndex(ctx, validators[0]) + app.StakingKeeper.SetValidator(ctx, validators[1]) + app.StakingKeeper.SetValidatorByPowerIndex(ctx, validators[1]) + + updates := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + assert.Equal(t, 2, len(updates)) + validators[0], _ = app.StakingKeeper.GetValidator(ctx, validators[0].OperatorAddress) + validators[1], _ = app.StakingKeeper.GetValidator(ctx, validators[1].OperatorAddress) + assert.Equal(t, validators[0].ABCIValidatorUpdate(), updates[1]) + assert.Equal(t, validators[1].ABCIValidatorUpdate(), updates[0]) +} + +func TestApplyAndReturnValidatorSetUpdatesIdentical(t *testing.T) { + app, ctx, addrs, _ := bootstrapValidatorTest(t, 1000, 20) + + powers := []int64{10, 20} + var validators [2]types.Validator + for i, power := range powers { + validators[i] = types.NewValidator(sdk.ValAddress(addrs[i]), PKs[i], types.Description{}) + + tokens := sdk.TokensFromConsensusPower(power) + validators[i], _ = validators[i].AddTokensFromDel(tokens) + + } + validators[0] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[0], false) + validators[1] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[1], false) + require.Equal(t, 2, len(app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx))) + + // test identical, + // tendermintUpdate set: {} -> {} + validators[0] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[0], false) + validators[1] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[1], false) + require.Equal(t, 0, len(app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx))) +} + +func TestApplyAndReturnValidatorSetUpdatesSingleValueChange(t *testing.T) { + app, ctx, addrs, _ := bootstrapValidatorTest(t, 1000, 20) + + powers := []int64{10, 20} + var validators [2]types.Validator + for i, power := range powers { + + validators[i] = types.NewValidator(sdk.ValAddress(addrs[i]), PKs[i], types.Description{}) + + tokens := sdk.TokensFromConsensusPower(power) + validators[i], _ = validators[i].AddTokensFromDel(tokens) + + } + validators[0] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[0], false) + validators[1] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[1], false) + require.Equal(t, 2, len(app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx))) + + // test single value change + // tendermintUpdate set: {} -> {c1'} + validators[0].Status = sdk.Bonded + validators[0].Tokens = sdk.TokensFromConsensusPower(600) + validators[0] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[0], false) + + updates := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + + require.Equal(t, 1, len(updates)) + require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[0]) +} + +func TestApplyAndReturnValidatorSetUpdatesMultipleValueChange(t *testing.T) { + app, ctx, addrs, _ := bootstrapValidatorTest(t, 1000, 20) + + powers := []int64{10, 20} + var validators [2]types.Validator + for i, power := range powers { + + validators[i] = types.NewValidator(sdk.ValAddress(addrs[i]), PKs[i], types.Description{}) + + tokens := sdk.TokensFromConsensusPower(power) + validators[i], _ = validators[i].AddTokensFromDel(tokens) + + } + validators[0] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[0], false) + validators[1] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[1], false) + require.Equal(t, 2, len(app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx))) + + // test multiple value change + // tendermintUpdate set: {c1, c3} -> {c1', c3'} + delTokens1 := sdk.TokensFromConsensusPower(190) + delTokens2 := sdk.TokensFromConsensusPower(80) + validators[0], _ = validators[0].AddTokensFromDel(delTokens1) + validators[1], _ = validators[1].AddTokensFromDel(delTokens2) + validators[0] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[0], false) + validators[1] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[1], false) + + updates := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 2, len(updates)) + require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[0]) + require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[1]) +} + +func TestApplyAndReturnValidatorSetUpdatesInserted(t *testing.T) { + app, ctx, addrs, _ := bootstrapValidatorTest(t, 1000, 20) + + powers := []int64{10, 20, 5, 15, 25} + var validators [5]types.Validator + for i, power := range powers { + + validators[i] = types.NewValidator(sdk.ValAddress(addrs[i]), PKs[i], types.Description{}) + + tokens := sdk.TokensFromConsensusPower(power) + validators[i], _ = validators[i].AddTokensFromDel(tokens) + + } + + validators[0] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[0], false) + validators[1] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[1], false) + require.Equal(t, 2, len(app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx))) + + // test validtor added at the beginning + // tendermintUpdate set: {} -> {c0} + app.StakingKeeper.SetValidator(ctx, validators[2]) + app.StakingKeeper.SetValidatorByPowerIndex(ctx, validators[2]) + updates := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + validators[2], _ = app.StakingKeeper.GetValidator(ctx, validators[2].OperatorAddress) + require.Equal(t, 1, len(updates)) + require.Equal(t, validators[2].ABCIValidatorUpdate(), updates[0]) + + // test validtor added at the beginning + // tendermintUpdate set: {} -> {c0} + app.StakingKeeper.SetValidator(ctx, validators[3]) + app.StakingKeeper.SetValidatorByPowerIndex(ctx, validators[3]) + updates = app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + validators[3], _ = app.StakingKeeper.GetValidator(ctx, validators[3].OperatorAddress) + require.Equal(t, 1, len(updates)) + require.Equal(t, validators[3].ABCIValidatorUpdate(), updates[0]) + + // test validtor added at the end + // tendermintUpdate set: {} -> {c0} + app.StakingKeeper.SetValidator(ctx, validators[4]) + app.StakingKeeper.SetValidatorByPowerIndex(ctx, validators[4]) + updates = app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + validators[4], _ = app.StakingKeeper.GetValidator(ctx, validators[4].OperatorAddress) + require.Equal(t, 1, len(updates)) + require.Equal(t, validators[4].ABCIValidatorUpdate(), updates[0]) +} + +func TestApplyAndReturnValidatorSetUpdatesWithCliffValidator(t *testing.T) { + app, ctx, addrs, _ := bootstrapValidatorTest(t, 1000, 20) + params := types.DefaultParams() + params.MaxValidators = 2 + app.StakingKeeper.SetParams(ctx, params) + + powers := []int64{10, 20, 5} + var validators [5]types.Validator + for i, power := range powers { + + validators[i] = types.NewValidator(sdk.ValAddress(addrs[i]), PKs[i], types.Description{}) + + tokens := sdk.TokensFromConsensusPower(power) + validators[i], _ = validators[i].AddTokensFromDel(tokens) + + } + validators[0] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[0], false) + validators[1] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[1], false) + require.Equal(t, 2, len(app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx))) + + // test validator added at the end but not inserted in the valset + // tendermintUpdate set: {} -> {} + keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[2], false) + updates := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 0, len(updates)) + + // test validator change its power and become a gotValidator (pushing out an existing) + // tendermintUpdate set: {} -> {c0, c4} + require.Equal(t, 0, len(app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx))) + + tokens := sdk.TokensFromConsensusPower(10) + validators[2], _ = validators[2].AddTokensFromDel(tokens) + app.StakingKeeper.SetValidator(ctx, validators[2]) + app.StakingKeeper.SetValidatorByPowerIndex(ctx, validators[2]) + updates = app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + validators[2], _ = app.StakingKeeper.GetValidator(ctx, validators[2].OperatorAddress) + require.Equal(t, 2, len(updates), "%v", updates) + require.Equal(t, validators[0].ABCIValidatorUpdateZero(), updates[1]) + require.Equal(t, validators[2].ABCIValidatorUpdate(), updates[0]) +} + +func TestApplyAndReturnValidatorSetUpdatesPowerDecrease(t *testing.T) { + app, ctx, addrs, _ := bootstrapValidatorTest(t, 1000, 20) + + powers := []int64{100, 100} + var validators [2]types.Validator + for i, power := range powers { + + validators[i] = types.NewValidator(sdk.ValAddress(addrs[i]), PKs[i], types.Description{}) + + tokens := sdk.TokensFromConsensusPower(power) + validators[i], _ = validators[i].AddTokensFromDel(tokens) + + } + validators[0] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[0], false) + validators[1] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[1], false) + require.Equal(t, 2, len(app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx))) + + // check initial power + require.Equal(t, int64(100), validators[0].GetConsensusPower()) + require.Equal(t, int64(100), validators[1].GetConsensusPower()) + + // test multiple value change + // tendermintUpdate set: {c1, c3} -> {c1', c3'} + delTokens1 := sdk.TokensFromConsensusPower(20) + delTokens2 := sdk.TokensFromConsensusPower(30) + validators[0], _ = validators[0].RemoveDelShares(delTokens1.ToDec()) + validators[1], _ = validators[1].RemoveDelShares(delTokens2.ToDec()) + validators[0] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[0], false) + validators[1] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[1], false) + + // power has changed + require.Equal(t, int64(80), validators[0].GetConsensusPower()) + require.Equal(t, int64(70), validators[1].GetConsensusPower()) + + // Tendermint updates should reflect power change + updates := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 2, len(updates)) + require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[0]) + require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[1]) +} + +func TestApplyAndReturnValidatorSetUpdatesNewValidator(t *testing.T) { + app, ctx, _, _ := bootstrapValidatorTest(t, 1000, 20) + params := app.StakingKeeper.GetParams(ctx) + params.MaxValidators = uint32(3) + + app.StakingKeeper.SetParams(ctx, params) + + powers := []int64{100, 100} + var validators [2]types.Validator + + // initialize some validators into the state + for i, power := range powers { + + valPubKey := PKs[i+1] + valAddr := sdk.ValAddress(valPubKey.Address().Bytes()) + + validators[i] = types.NewValidator(valAddr, valPubKey, types.Description{}) + tokens := sdk.TokensFromConsensusPower(power) + validators[i], _ = validators[i].AddTokensFromDel(tokens) + + app.StakingKeeper.SetValidator(ctx, validators[i]) + app.StakingKeeper.SetValidatorByPowerIndex(ctx, validators[i]) + } + + // verify initial Tendermint updates are correct + updates := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, len(validators), len(updates)) + validators[0], _ = app.StakingKeeper.GetValidator(ctx, validators[0].OperatorAddress) + validators[1], _ = app.StakingKeeper.GetValidator(ctx, validators[1].OperatorAddress) + require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[0]) + require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[1]) + + require.Equal(t, 0, len(app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx))) + + // update initial validator set + for i, power := range powers { + + app.StakingKeeper.DeleteValidatorByPowerIndex(ctx, validators[i]) + tokens := sdk.TokensFromConsensusPower(power) + validators[i], _ = validators[i].AddTokensFromDel(tokens) + + app.StakingKeeper.SetValidator(ctx, validators[i]) + app.StakingKeeper.SetValidatorByPowerIndex(ctx, validators[i]) + } + + // add a new validator that goes from zero power, to non-zero power, back to + // zero power + valPubKey := PKs[len(validators)+1] + valAddr := sdk.ValAddress(valPubKey.Address().Bytes()) + amt := sdk.NewInt(100) + + validator := types.NewValidator(valAddr, valPubKey, types.Description{}) + validator, _ = validator.AddTokensFromDel(amt) + + app.StakingKeeper.SetValidator(ctx, validator) + + validator, _ = validator.RemoveDelShares(amt.ToDec()) + app.StakingKeeper.SetValidator(ctx, validator) + app.StakingKeeper.SetValidatorByPowerIndex(ctx, validator) + + // add a new validator that increases in power + valPubKey = PKs[len(validators)+2] + valAddr = sdk.ValAddress(valPubKey.Address().Bytes()) + + validator = types.NewValidator(valAddr, valPubKey, types.Description{}) + tokens := sdk.TokensFromConsensusPower(500) + validator, _ = validator.AddTokensFromDel(tokens) + app.StakingKeeper.SetValidator(ctx, validator) + app.StakingKeeper.SetValidatorByPowerIndex(ctx, validator) + + // verify initial Tendermint updates are correct + updates = app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + validator, _ = app.StakingKeeper.GetValidator(ctx, validator.OperatorAddress) + validators[0], _ = app.StakingKeeper.GetValidator(ctx, validators[0].OperatorAddress) + validators[1], _ = app.StakingKeeper.GetValidator(ctx, validators[1].OperatorAddress) + require.Equal(t, len(validators)+1, len(updates)) + require.Equal(t, validator.ABCIValidatorUpdate(), updates[0]) + require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[1]) + require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[2]) +} + +func TestApplyAndReturnValidatorSetUpdatesBondTransition(t *testing.T) { + app, ctx, _, _ := bootstrapValidatorTest(t, 1000, 20) + params := app.StakingKeeper.GetParams(ctx) + params.MaxValidators = uint32(2) + + app.StakingKeeper.SetParams(ctx, params) + + powers := []int64{100, 200, 300} + var validators [3]types.Validator + + // initialize some validators into the state + for i, power := range powers { + moniker := fmt.Sprintf("%d", i) + valPubKey := PKs[i+1] + valAddr := sdk.ValAddress(valPubKey.Address().Bytes()) + + validators[i] = types.NewValidator(valAddr, valPubKey, types.Description{Moniker: moniker}) + tokens := sdk.TokensFromConsensusPower(power) + validators[i], _ = validators[i].AddTokensFromDel(tokens) + app.StakingKeeper.SetValidator(ctx, validators[i]) + app.StakingKeeper.SetValidatorByPowerIndex(ctx, validators[i]) + } + + // verify initial Tendermint updates are correct + updates := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 2, len(updates)) + validators[2], _ = app.StakingKeeper.GetValidator(ctx, validators[2].OperatorAddress) + validators[1], _ = app.StakingKeeper.GetValidator(ctx, validators[1].OperatorAddress) + require.Equal(t, validators[2].ABCIValidatorUpdate(), updates[0]) + require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[1]) + + require.Equal(t, 0, len(app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx))) + + // delegate to validator with lowest power but not enough to bond + ctx = ctx.WithBlockHeight(1) + + var found bool + validators[0], found = app.StakingKeeper.GetValidator(ctx, validators[0].OperatorAddress) + require.True(t, found) + + app.StakingKeeper.DeleteValidatorByPowerIndex(ctx, validators[0]) + tokens := sdk.TokensFromConsensusPower(1) + validators[0], _ = validators[0].AddTokensFromDel(tokens) + app.StakingKeeper.SetValidator(ctx, validators[0]) + app.StakingKeeper.SetValidatorByPowerIndex(ctx, validators[0]) + + // verify initial Tendermint updates are correct + require.Equal(t, 0, len(app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx))) + + // create a series of events that will bond and unbond the validator with + // lowest power in a single block context (height) + ctx = ctx.WithBlockHeight(2) + + validators[1], found = app.StakingKeeper.GetValidator(ctx, validators[1].OperatorAddress) + require.True(t, found) + + app.StakingKeeper.DeleteValidatorByPowerIndex(ctx, validators[0]) + validators[0], _ = validators[0].RemoveDelShares(validators[0].DelegatorShares) + app.StakingKeeper.SetValidator(ctx, validators[0]) + app.StakingKeeper.SetValidatorByPowerIndex(ctx, validators[0]) + updates = app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 0, len(updates)) + + app.StakingKeeper.DeleteValidatorByPowerIndex(ctx, validators[1]) + tokens = sdk.TokensFromConsensusPower(250) + validators[1], _ = validators[1].AddTokensFromDel(tokens) + app.StakingKeeper.SetValidator(ctx, validators[1]) + app.StakingKeeper.SetValidatorByPowerIndex(ctx, validators[1]) + + // verify initial Tendermint updates are correct + updates = app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 1, len(updates)) + require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[0]) + + require.Equal(t, 0, len(app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx))) +} + +func TestUpdateValidatorCommission(t *testing.T) { + app, ctx, _, addrVals := bootstrapValidatorTest(t, 1000, 20) + ctx = ctx.WithBlockHeader(abci.Header{Time: time.Now().UTC()}) + + commission1 := types.NewCommissionWithTime( + sdk.NewDecWithPrec(1, 1), sdk.NewDecWithPrec(3, 1), + sdk.NewDecWithPrec(1, 1), time.Now().UTC().Add(time.Duration(-1)*time.Hour), + ) + commission2 := types.NewCommission(sdk.NewDecWithPrec(1, 1), sdk.NewDecWithPrec(3, 1), sdk.NewDecWithPrec(1, 1)) + + val1 := types.NewValidator(addrVals[0], PKs[0], types.Description{}) + val2 := types.NewValidator(addrVals[1], PKs[1], types.Description{}) + + val1, _ = val1.SetInitialCommission(commission1) + val2, _ = val2.SetInitialCommission(commission2) + + app.StakingKeeper.SetValidator(ctx, val1) + app.StakingKeeper.SetValidator(ctx, val2) + + testCases := []struct { + validator types.Validator + newRate sdk.Dec + expectedErr bool + }{ + {val1, sdk.ZeroDec(), true}, + {val2, sdk.NewDecWithPrec(-1, 1), true}, + {val2, sdk.NewDecWithPrec(4, 1), true}, + {val2, sdk.NewDecWithPrec(3, 1), true}, + {val2, sdk.NewDecWithPrec(2, 1), false}, + } + + for i, tc := range testCases { + commission, err := app.StakingKeeper.UpdateValidatorCommission(ctx, tc.validator, tc.newRate) + + if tc.expectedErr { + require.Error(t, err, "expected error for test case #%d with rate: %s", i, tc.newRate) + } else { + tc.validator.Commission = commission + app.StakingKeeper.SetValidator(ctx, tc.validator) + val, found := app.StakingKeeper.GetValidator(ctx, tc.validator.OperatorAddress) + + require.True(t, found, + "expected to find validator for test case #%d with rate: %s", i, tc.newRate, + ) + require.NoError(t, err, + "unexpected error for test case #%d with rate: %s", i, tc.newRate, + ) + require.Equal(t, tc.newRate, val.Commission.Rate, + "expected new validator commission rate for test case #%d with rate: %s", i, tc.newRate, + ) + require.Equal(t, ctx.BlockHeader().Time, val.Commission.UpdateTime, + "expected new validator commission update time for test case #%d with rate: %s", i, tc.newRate, + ) + } + } +} From 8f779b12b85be8a5cbeacf426459b69e6e884750 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Tue, 25 Feb 2020 15:11:52 +0100 Subject: [PATCH 212/529] clean code --- x/staking/genesis_test.go | 5 ++--- x/staking/keeper/old_test_common.go | 21 --------------------- 2 files changed, 2 insertions(+), 24 deletions(-) diff --git a/x/staking/genesis_test.go b/x/staking/genesis_test.go index 551239185fca..c58260424135 100644 --- a/x/staking/genesis_test.go +++ b/x/staking/genesis_test.go @@ -4,12 +4,11 @@ import ( "fmt" "testing" - "github.com/tendermint/tendermint/crypto/ed25519" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto/ed25519" sdk "github.com/cosmos/cosmos-sdk/types" keep "github.com/cosmos/cosmos-sdk/x/staking/keeper" diff --git a/x/staking/keeper/old_test_common.go b/x/staking/keeper/old_test_common.go index 82bd54a317ad..e1c75edeae29 100644 --- a/x/staking/keeper/old_test_common.go +++ b/x/staking/keeper/old_test_common.go @@ -31,29 +31,8 @@ import ( var ( Addrs = createTestAddrs(500) PKs = createTestPubKeys(500) - - addrDels = []sdk.AccAddress{ - Addrs[0], - Addrs[1], - } - addrVals = []sdk.ValAddress{ - sdk.ValAddress(Addrs[2]), - sdk.ValAddress(Addrs[3]), - sdk.ValAddress(Addrs[4]), - sdk.ValAddress(Addrs[5]), - sdk.ValAddress(Addrs[6]), - } ) -//_______________________________________________________________________________________ - -// intended to be used with require/assert: require.True(ValEq(...)) -func ValEq(t *testing.T, exp, got types.Validator) (*testing.T, bool, string, types.Validator, types.Validator) { - return t, exp.MinEqual(got), "expected:\n%v\ngot:\n%v", exp, got -} - -//_______________________________________________________________________________________ - // create a codec used only for testing func MakeTestCodec() *codec.Codec { var cdc = codec.New() From 632e65f575ae0874b5636b1fd5cd5121fa4a09b6 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Tue, 25 Feb 2020 15:27:51 +0100 Subject: [PATCH 213/529] move methods --- x/staking/genesis_test.go | 21 +- x/staking/handler_test.go | 367 ++++++++++++++-------------- x/staking/keeper/old_test_common.go | 208 ---------------- x/staking/test_common.go | 217 ++++++++++++++++ 4 files changed, 411 insertions(+), 402 deletions(-) create mode 100644 x/staking/test_common.go diff --git a/x/staking/genesis_test.go b/x/staking/genesis_test.go index c58260424135..730e7b0fc629 100644 --- a/x/staking/genesis_test.go +++ b/x/staking/genesis_test.go @@ -11,12 +11,11 @@ import ( "github.com/tendermint/tendermint/crypto/ed25519" sdk "github.com/cosmos/cosmos-sdk/types" - keep "github.com/cosmos/cosmos-sdk/x/staking/keeper" "github.com/cosmos/cosmos-sdk/x/staking/types" ) func TestInitGenesis(t *testing.T) { - ctx, accKeeper, bk, keeper, supplyKeeper := keep.CreateTestInput(t, false, 1000) + ctx, accKeeper, bk, keeper, supplyKeeper := CreateTestInput(t, false, 1000) valTokens := sdk.TokensFromConsensusPower(1) @@ -24,20 +23,20 @@ func TestInitGenesis(t *testing.T) { validators := make([]Validator, 2) var delegations []Delegation - pk0, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, keep.PKs[0]) + pk0, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, PKs[0]) require.NoError(t, err) - pk1, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, keep.PKs[1]) + pk1, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, PKs[1]) require.NoError(t, err) // initialize the validators - validators[0].OperatorAddress = sdk.ValAddress(keep.Addrs[0]) + validators[0].OperatorAddress = sdk.ValAddress(Addrs[0]) validators[0].ConsensusPubkey = pk0 validators[0].Description = NewDescription("hoop", "", "", "", "") validators[0].Status = sdk.Bonded validators[0].Tokens = valTokens validators[0].DelegatorShares = valTokens.ToDec() - validators[1].OperatorAddress = sdk.ValAddress(keep.Addrs[1]) + validators[1].OperatorAddress = sdk.ValAddress(Addrs[1]) validators[1].ConsensusPubkey = pk1 validators[1].Description = NewDescription("bloop", "", "", "", "") validators[1].Status = sdk.Bonded @@ -53,11 +52,11 @@ func TestInitGenesis(t *testing.T) { require.EqualValues(t, keeper.GetAllValidators(ctx), actualGenesis.Validators) // now make sure the validators are bonded and intra-tx counters are correct - resVal, found := keeper.GetValidator(ctx, sdk.ValAddress(keep.Addrs[0])) + resVal, found := keeper.GetValidator(ctx, sdk.ValAddress(Addrs[0])) require.True(t, found) require.Equal(t, sdk.Bonded, resVal.Status) - resVal, found = keeper.GetValidator(ctx, sdk.ValAddress(keep.Addrs[1])) + resVal, found = keeper.GetValidator(ctx, sdk.ValAddress(Addrs[1])) require.True(t, found) require.Equal(t, sdk.Bonded, resVal.Status) @@ -73,15 +72,15 @@ func TestInitGenesisLargeValidatorSet(t *testing.T) { size := 200 require.True(t, size > 100) - ctx, accKeeper, bk, keeper, supplyKeeper := keep.CreateTestInput(t, false, 1000) + ctx, accKeeper, bk, keeper, supplyKeeper := CreateTestInput(t, false, 1000) params := keeper.GetParams(ctx) delegations := []Delegation{} validators := make([]Validator, size) for i := range validators { - validators[i] = NewValidator(sdk.ValAddress(keep.Addrs[i]), - keep.PKs[i], NewDescription(fmt.Sprintf("#%d", i), "", "", "", "")) + validators[i] = NewValidator(sdk.ValAddress(Addrs[i]), + PKs[i], NewDescription(fmt.Sprintf("#%d", i), "", "", "", "")) validators[i].Status = sdk.Bonded diff --git a/x/staking/handler_test.go b/x/staking/handler_test.go index 51a2e61aa6c5..f18dda6ac00c 100644 --- a/x/staking/handler_test.go +++ b/x/staking/handler_test.go @@ -8,26 +8,27 @@ import ( gogotypes "github.com/gogo/protobuf/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto/secp256k1" tmtypes "github.com/tendermint/tendermint/types" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/staking" + . "github.com/cosmos/cosmos-sdk/x/staking" keep "github.com/cosmos/cosmos-sdk/x/staking/keeper" "github.com/cosmos/cosmos-sdk/x/staking/types" ) func TestValidatorByPowerIndex(t *testing.T) { - validatorAddr, validatorAddr3 := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1]) + validatorAddr, validatorAddr3 := sdk.ValAddress(Addrs[0]), sdk.ValAddress(Addrs[1]) initPower := int64(1000000) initBond := sdk.TokensFromConsensusPower(initPower) - ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, initPower) - handler := staking.NewHandler(keeper) + ctx, _, _, keeper, _ := CreateTestInput(t, false, initPower) + handler := NewHandler(keeper) // create validator - msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], initBond) + msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], initBond) res, err := handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) @@ -45,11 +46,11 @@ func TestValidatorByPowerIndex(t *testing.T) { // verify that the by power index exists validator, found := keeper.GetValidator(ctx, validatorAddr) require.True(t, found) - power := staking.GetValidatorsByPowerIndexKey(validator) + power := GetValidatorsByPowerIndexKey(validator) require.True(t, keep.ValidatorByPowerIndexExists(ctx, keeper, power)) // create a second validator keep it bonded - msgCreateValidator = NewTestMsgCreateValidator(validatorAddr3, keep.PKs[2], initBond) + msgCreateValidator = NewTestMsgCreateValidator(validatorAddr3, PKs[2], initBond) res, err = handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) @@ -59,7 +60,7 @@ func TestValidatorByPowerIndex(t *testing.T) { require.Equal(t, 1, len(updates)) // slash and jail the first validator - consAddr0 := sdk.ConsAddress(keep.PKs[0].Address()) + consAddr0 := sdk.ConsAddress(PKs[0].Address()) keeper.Slash(ctx, consAddr0, 0, initPower, sdk.NewDecWithPrec(5, 1)) keeper.Jail(ctx, consAddr0) keeper.ApplyAndReturnValidatorSetUpdates(ctx) @@ -76,17 +77,17 @@ func TestValidatorByPowerIndex(t *testing.T) { // but the new power record should have been created validator, found = keeper.GetValidator(ctx, validatorAddr) require.True(t, found) - power2 := staking.GetValidatorsByPowerIndexKey(validator) + power2 := GetValidatorsByPowerIndexKey(validator) require.True(t, keep.ValidatorByPowerIndexExists(ctx, keeper, power2)) // now the new record power index should be the same as the original record - power3 := staking.GetValidatorsByPowerIndexKey(validator) + power3 := GetValidatorsByPowerIndexKey(validator) require.Equal(t, power2, power3) // unbond self-delegation totalBond := validator.TokensFromShares(bond.GetShares()).TruncateInt() unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, totalBond) - msgUndelegate := staking.NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) + msgUndelegate := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) res, err = handler(ctx, msgUndelegate) require.NoError(t, err) @@ -99,8 +100,8 @@ func TestValidatorByPowerIndex(t *testing.T) { require.NoError(t, err) ctx = ctx.WithBlockTime(finishTime) - staking.EndBlocker(ctx, keeper) - staking.EndBlocker(ctx, keeper) + EndBlocker(ctx, keeper) + EndBlocker(ctx, keeper) // verify that by power key nolonger exists _, found = keeper.GetValidator(ctx, validatorAddr) @@ -109,11 +110,11 @@ func TestValidatorByPowerIndex(t *testing.T) { } func TestDuplicatesMsgCreateValidator(t *testing.T) { - ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) - handler := staking.NewHandler(keeper) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) + handler := NewHandler(keeper) - addr1, addr2 := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1]) - pk1, pk2 := keep.PKs[0], keep.PKs[1] + addr1, addr2 := sdk.ValAddress(Addrs[0]), sdk.ValAddress(Addrs[1]) + pk1, pk2 := PKs[0], PKs[1] valTokens := sdk.TokensFromConsensusPower(10) msgCreateValidator1 := NewTestMsgCreateValidator(addr1, pk1, valTokens) @@ -130,7 +131,7 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) { assert.Equal(t, pk1, validator.GetConsPubKey()) assert.Equal(t, valTokens, validator.BondedTokens()) assert.Equal(t, valTokens.ToDec(), validator.DelegatorShares) - assert.Equal(t, staking.Description{}, validator.Description) + assert.Equal(t, Description{}, validator.Description) // two validators can't have the same operator address msgCreateValidator2 := NewTestMsgCreateValidator(addr1, pk2, valTokens) @@ -162,14 +163,14 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) { assert.Equal(t, pk2, validator.GetConsPubKey()) assert.True(sdk.IntEq(t, valTokens, validator.Tokens)) assert.True(sdk.DecEq(t, valTokens.ToDec(), validator.DelegatorShares)) - assert.Equal(t, staking.Description{}, validator.Description) + assert.Equal(t, Description{}, validator.Description) } func TestInvalidPubKeyTypeMsgCreateValidator(t *testing.T) { - ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) - handler := staking.NewHandler(keeper) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) + handler := NewHandler(keeper) - addr := sdk.ValAddress(keep.Addrs[0]) + addr := sdk.ValAddress(Addrs[0]) invalidPk := secp256k1.GenPrivKey().PubKey() // invalid pukKey type should not be allowed @@ -188,13 +189,13 @@ func TestInvalidPubKeyTypeMsgCreateValidator(t *testing.T) { } func TestLegacyValidatorDelegations(t *testing.T) { - ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, int64(1000)) - handler := staking.NewHandler(keeper) + ctx, _, _, keeper, _ := CreateTestInput(t, false, int64(1000)) + handler := NewHandler(keeper) bondAmount := sdk.TokensFromConsensusPower(10) - valAddr := sdk.ValAddress(keep.Addrs[0]) - valConsPubKey, valConsAddr := keep.PKs[0], sdk.ConsAddress(keep.PKs[0].Address()) - delAddr := keep.Addrs[1] + valAddr := sdk.ValAddress(Addrs[0]) + valConsPubKey, valConsAddr := PKs[0], sdk.ConsAddress(PKs[0].Address()) + delAddr := Addrs[1] // create validator msgCreateVal := NewTestMsgCreateValidator(valAddr, valConsPubKey, bondAmount) @@ -227,7 +228,7 @@ func TestLegacyValidatorDelegations(t *testing.T) { // unbond validator total self-delegations (which should jail the validator) unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, bondAmount) - msgUndelegate := staking.NewMsgUndelegate(sdk.AccAddress(valAddr), valAddr, unbondAmt) + msgUndelegate := NewMsgUndelegate(sdk.AccAddress(valAddr), valAddr, unbondAmt) res, err = handler(ctx, msgUndelegate) require.NoError(t, err) @@ -240,7 +241,7 @@ func TestLegacyValidatorDelegations(t *testing.T) { require.NoError(t, err) ctx = ctx.WithBlockTime(finishTime) - staking.EndBlocker(ctx, keeper) + EndBlocker(ctx, keeper) // verify the validator record still exists, is jailed, and has correct tokens validator, found = keeper.GetValidator(ctx, valAddr) @@ -291,16 +292,16 @@ func TestLegacyValidatorDelegations(t *testing.T) { func TestIncrementsMsgDelegate(t *testing.T) { initPower := int64(1000) initBond := sdk.TokensFromConsensusPower(initPower) - ctx, _, bk, keeper, _ := keep.CreateTestInput(t, false, initPower) - handler := staking.NewHandler(keeper) + ctx, _, bk, keeper, _ := CreateTestInput(t, false, initPower) + handler := NewHandler(keeper) params := keeper.GetParams(ctx) bondAmount := sdk.TokensFromConsensusPower(10) - validatorAddr, delegatorAddr := sdk.ValAddress(keep.Addrs[0]), keep.Addrs[1] + validatorAddr, delegatorAddr := sdk.ValAddress(Addrs[0]), Addrs[1] // first create validator - msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], bondAmount) + msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], bondAmount) res, err := handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) @@ -361,15 +362,15 @@ func TestIncrementsMsgDelegate(t *testing.T) { } func TestEditValidatorDecreaseMinSelfDelegation(t *testing.T) { - validatorAddr := sdk.ValAddress(keep.Addrs[0]) + validatorAddr := sdk.ValAddress(Addrs[0]) initPower := int64(100) initBond := sdk.TokensFromConsensusPower(100) - ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, initPower) - handler := staking.NewHandler(keeper) + ctx, _, _, keeper, _ := CreateTestInput(t, false, initPower) + handler := NewHandler(keeper) // create validator - msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], initBond) + msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], initBond) msgCreateValidator.MinSelfDelegation = sdk.NewInt(2) res, err := handler(ctx, msgCreateValidator) require.NoError(t, err) @@ -388,22 +389,22 @@ func TestEditValidatorDecreaseMinSelfDelegation(t *testing.T) { initBond, gotBond, bond) newMinSelfDelegation := sdk.OneInt() - msgEditValidator := staking.NewMsgEditValidator(validatorAddr, staking.Description{}, nil, &newMinSelfDelegation) + msgEditValidator := NewMsgEditValidator(validatorAddr, Description{}, nil, &newMinSelfDelegation) res, err = handler(ctx, msgEditValidator) require.Error(t, err) require.Nil(t, res) } func TestEditValidatorIncreaseMinSelfDelegationBeyondCurrentBond(t *testing.T) { - validatorAddr := sdk.ValAddress(keep.Addrs[0]) + validatorAddr := sdk.ValAddress(Addrs[0]) initPower := int64(100) initBond := sdk.TokensFromConsensusPower(100) - ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, initPower) - handler := staking.NewHandler(keeper) + ctx, _, _, keeper, _ := CreateTestInput(t, false, initPower) + handler := NewHandler(keeper) // create validator - msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], initBond) + msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], initBond) msgCreateValidator.MinSelfDelegation = sdk.NewInt(2) res, err := handler(ctx, msgCreateValidator) require.NoError(t, err) @@ -422,7 +423,7 @@ func TestEditValidatorIncreaseMinSelfDelegationBeyondCurrentBond(t *testing.T) { initBond, gotBond, bond) newMinSelfDelegation := initBond.Add(sdk.OneInt()) - msgEditValidator := staking.NewMsgEditValidator(validatorAddr, staking.Description{}, nil, &newMinSelfDelegation) + msgEditValidator := NewMsgEditValidator(validatorAddr, Description{}, nil, &newMinSelfDelegation) res, err = handler(ctx, msgEditValidator) require.Error(t, err) require.Nil(t, res) @@ -431,16 +432,16 @@ func TestEditValidatorIncreaseMinSelfDelegationBeyondCurrentBond(t *testing.T) { func TestIncrementsMsgUnbond(t *testing.T) { initPower := int64(1000) initBond := sdk.TokensFromConsensusPower(initPower) - ctx, _, bk, keeper, _ := keep.CreateTestInput(t, false, initPower) - handler := staking.NewHandler(keeper) + ctx, _, bk, keeper, _ := CreateTestInput(t, false, initPower) + handler := NewHandler(keeper) params := keeper.GetParams(ctx) denom := params.BondDenom // create validator, delegate - validatorAddr, delegatorAddr := sdk.ValAddress(keep.Addrs[0]), keep.Addrs[1] + validatorAddr, delegatorAddr := sdk.ValAddress(Addrs[0]), Addrs[1] - msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], initBond) + msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], initBond) res, err := handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) @@ -468,7 +469,7 @@ func TestIncrementsMsgUnbond(t *testing.T) { // just send the same msgUnbond multiple times // TODO use decimals here unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) - msgUndelegate := staking.NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) + msgUndelegate := NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) numUnbonds := int64(5) for i := int64(0); i < numUnbonds; i++ { @@ -483,7 +484,7 @@ func TestIncrementsMsgUnbond(t *testing.T) { require.NoError(t, err) ctx = ctx.WithBlockTime(finishTime) - staking.EndBlocker(ctx, keeper) + EndBlocker(ctx, keeper) // check that the accounts and the bond account have the appropriate values validator, found = keeper.GetValidator(ctx, validatorAddr) @@ -521,7 +522,7 @@ func TestIncrementsMsgUnbond(t *testing.T) { for _, c := range errorCases { unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, c) - msgUndelegate := staking.NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) + msgUndelegate := NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) res, err = handler(ctx, msgUndelegate) require.Error(t, err) require.Nil(t, res) @@ -531,7 +532,7 @@ func TestIncrementsMsgUnbond(t *testing.T) { // should be able to unbond remaining unbondAmt = sdk.NewCoin(sdk.DefaultBondDenom, leftBonded) - msgUndelegate = staking.NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) + msgUndelegate = NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) res, err = handler(ctx, msgUndelegate) require.NoError(t, err, "msgUnbond: %v\nshares: %s\nleftBonded: %s\n", msgUndelegate, unbondAmt, leftBonded) require.NotNil(t, res, "msgUnbond: %v\nshares: %s\nleftBonded: %s\n", msgUndelegate, unbondAmt, leftBonded) @@ -540,28 +541,28 @@ func TestIncrementsMsgUnbond(t *testing.T) { func TestMultipleMsgCreateValidator(t *testing.T) { initPower := int64(1000) initTokens := sdk.TokensFromConsensusPower(initPower) - ctx, _, bk, keeper, _ := keep.CreateTestInput(t, false, initPower) - handler := staking.NewHandler(keeper) + ctx, _, bk, keeper, _ := CreateTestInput(t, false, initPower) + handler := NewHandler(keeper) params := keeper.GetParams(ctx) blockTime := time.Now().UTC() ctx = ctx.WithBlockTime(blockTime) validatorAddrs := []sdk.ValAddress{ - sdk.ValAddress(keep.Addrs[0]), - sdk.ValAddress(keep.Addrs[1]), - sdk.ValAddress(keep.Addrs[2]), + sdk.ValAddress(Addrs[0]), + sdk.ValAddress(Addrs[1]), + sdk.ValAddress(Addrs[2]), } delegatorAddrs := []sdk.AccAddress{ - keep.Addrs[0], - keep.Addrs[1], - keep.Addrs[2], + Addrs[0], + Addrs[1], + Addrs[2], } // bond them all for i, validatorAddr := range validatorAddrs { valTokens := sdk.TokensFromConsensusPower(10) - msgCreateValidatorOnBehalfOf := NewTestMsgCreateValidator(validatorAddr, keep.PKs[i], valTokens) + msgCreateValidatorOnBehalfOf := NewTestMsgCreateValidator(validatorAddr, PKs[i], valTokens) res, err := handler(ctx, msgCreateValidatorOnBehalfOf) require.NoError(t, err) @@ -580,7 +581,7 @@ func TestMultipleMsgCreateValidator(t *testing.T) { require.Equal(t, balanceExpd, balanceGot, "expected account to have %d, got %d", balanceExpd, balanceGot) } - staking.EndBlocker(ctx, keeper) + EndBlocker(ctx, keeper) // unbond them all by removing delegation for i, validatorAddr := range validatorAddrs { @@ -588,7 +589,7 @@ func TestMultipleMsgCreateValidator(t *testing.T) { require.True(t, found) unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(10)) - msgUndelegate := staking.NewMsgUndelegate(delegatorAddrs[i], validatorAddr, unbondAmt) // remove delegation + msgUndelegate := NewMsgUndelegate(delegatorAddrs[i], validatorAddr, unbondAmt) // remove delegation res, err := handler(ctx, msgUndelegate) require.NoError(t, err) require.NotNil(t, res) @@ -600,10 +601,10 @@ func TestMultipleMsgCreateValidator(t *testing.T) { require.NoError(t, err) // adds validator into unbonding queue - staking.EndBlocker(ctx, keeper) + EndBlocker(ctx, keeper) // removes validator from queue and set - staking.EndBlocker(ctx.WithBlockTime(blockTime.Add(params.UnbondingTime)), keeper) + EndBlocker(ctx.WithBlockTime(blockTime.Add(params.UnbondingTime)), keeper) // Check that the validator is deleted from state validators := keeper.GetValidators(ctx, 100) @@ -619,12 +620,12 @@ func TestMultipleMsgCreateValidator(t *testing.T) { } func TestMultipleMsgDelegate(t *testing.T) { - ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) - handler := staking.NewHandler(keeper) - validatorAddr, delegatorAddrs := sdk.ValAddress(keep.Addrs[0]), keep.Addrs[1:] + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) + handler := NewHandler(keeper) + validatorAddr, delegatorAddrs := sdk.ValAddress(Addrs[0]), Addrs[1:] // first make a validator - msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], sdk.NewInt(10)) + msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], sdk.NewInt(10)) res, err := handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) @@ -645,7 +646,7 @@ func TestMultipleMsgDelegate(t *testing.T) { // unbond them all for _, delegatorAddr := range delegatorAddrs { unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) - msgUndelegate := staking.NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) + msgUndelegate := NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) res, err := handler(ctx, msgUndelegate) require.NoError(t, err) @@ -658,7 +659,7 @@ func TestMultipleMsgDelegate(t *testing.T) { require.NoError(t, err) ctx = ctx.WithBlockTime(finishTime) - staking.EndBlocker(ctx, keeper) + EndBlocker(ctx, keeper) // check that the account is unbonded _, found := keeper.GetDelegation(ctx, delegatorAddr, validatorAddr) @@ -667,12 +668,12 @@ func TestMultipleMsgDelegate(t *testing.T) { } func TestJailValidator(t *testing.T) { - ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) - handler := staking.NewHandler(keeper) - validatorAddr, delegatorAddr := sdk.ValAddress(keep.Addrs[0]), keep.Addrs[1] + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) + handler := NewHandler(keeper) + validatorAddr, delegatorAddr := sdk.ValAddress(Addrs[0]), Addrs[1] // create the validator - msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], sdk.NewInt(10)) + msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], sdk.NewInt(10)) res, err := handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) @@ -685,7 +686,7 @@ func TestJailValidator(t *testing.T) { // unbond the validators bond portion unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) - msgUndelegateValidator := staking.NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) + msgUndelegateValidator := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) res, err = handler(ctx, msgUndelegateValidator) require.NoError(t, err) require.NotNil(t, res) @@ -697,14 +698,14 @@ func TestJailValidator(t *testing.T) { require.NoError(t, err) ctx = ctx.WithBlockTime(finishTime) - staking.EndBlocker(ctx, keeper) + EndBlocker(ctx, keeper) validator, found := keeper.GetValidator(ctx, validatorAddr) require.True(t, found) require.True(t, validator.Jailed, "%v", validator) // test that the delegator can still withdraw their bonds - msgUndelegateDelegator := staking.NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) + msgUndelegateDelegator := NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) res, err = handler(ctx, msgUndelegateDelegator) require.NoError(t, err) @@ -717,7 +718,7 @@ func TestJailValidator(t *testing.T) { require.NoError(t, err) ctx = ctx.WithBlockTime(finishTime) - staking.EndBlocker(ctx, keeper) + EndBlocker(ctx, keeper) // verify that the pubkey can now be reused res, err = handler(ctx, msgCreateValidator) @@ -726,9 +727,9 @@ func TestJailValidator(t *testing.T) { } func TestValidatorQueue(t *testing.T) { - ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) - handler := staking.NewHandler(keeper) - validatorAddr, delegatorAddr := sdk.ValAddress(keep.Addrs[0]), keep.Addrs[1] + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) + handler := NewHandler(keeper) + validatorAddr, delegatorAddr := sdk.ValAddress(Addrs[0]), Addrs[1] // set the unbonding time params := keeper.GetParams(ctx) @@ -737,7 +738,7 @@ func TestValidatorQueue(t *testing.T) { // create the validator valTokens := sdk.TokensFromConsensusPower(10) - msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], valTokens) + msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], valTokens) res, err := handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) @@ -749,11 +750,11 @@ func TestValidatorQueue(t *testing.T) { require.NoError(t, err) require.NotNil(t, res) - staking.EndBlocker(ctx, keeper) + EndBlocker(ctx, keeper) // unbond the all self-delegation to put validator in unbonding state unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, delTokens) - msgUndelegateValidator := staking.NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) + msgUndelegateValidator := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) res, err = handler(ctx, msgUndelegateValidator) require.NoError(t, err) require.NotNil(t, res) @@ -765,7 +766,7 @@ func TestValidatorQueue(t *testing.T) { require.NoError(t, err) ctx = ctx.WithBlockTime(finishTime) - staking.EndBlocker(ctx, keeper) + EndBlocker(ctx, keeper) origHeader := ctx.BlockHeader() @@ -775,7 +776,7 @@ func TestValidatorQueue(t *testing.T) { // should still be unbonding at time 6 seconds later ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 6)) - staking.EndBlocker(ctx, keeper) + EndBlocker(ctx, keeper) validator, found = keeper.GetValidator(ctx, validatorAddr) require.True(t, found) @@ -783,7 +784,7 @@ func TestValidatorQueue(t *testing.T) { // should be in unbonded state at time 7 seconds later ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 7)) - staking.EndBlocker(ctx, keeper) + EndBlocker(ctx, keeper) validator, found = keeper.GetValidator(ctx, validatorAddr) require.True(t, found) @@ -791,9 +792,9 @@ func TestValidatorQueue(t *testing.T) { } func TestUnbondingPeriod(t *testing.T) { - ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) - handler := staking.NewHandler(keeper) - validatorAddr := sdk.ValAddress(keep.Addrs[0]) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) + handler := NewHandler(keeper) + validatorAddr := sdk.ValAddress(Addrs[0]) // set the unbonding time params := keeper.GetParams(ctx) @@ -802,16 +803,16 @@ func TestUnbondingPeriod(t *testing.T) { // create the validator valTokens := sdk.TokensFromConsensusPower(10) - msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], valTokens) + msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], valTokens) res, err := handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) - staking.EndBlocker(ctx, keeper) + EndBlocker(ctx, keeper) // begin unbonding unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(10)) - msgUndelegate := staking.NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) + msgUndelegate := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) res, err = handler(ctx, msgUndelegate) require.NoError(t, err) require.NotNil(t, res) @@ -822,30 +823,30 @@ func TestUnbondingPeriod(t *testing.T) { require.True(t, found, "should not have unbonded") // cannot complete unbonding at same time - staking.EndBlocker(ctx, keeper) + EndBlocker(ctx, keeper) _, found = keeper.GetUnbondingDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) require.True(t, found, "should not have unbonded") // cannot complete unbonding at time 6 seconds later ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 6)) - staking.EndBlocker(ctx, keeper) + EndBlocker(ctx, keeper) _, found = keeper.GetUnbondingDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) require.True(t, found, "should not have unbonded") // can complete unbonding at time 7 seconds later ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 7)) - staking.EndBlocker(ctx, keeper) + EndBlocker(ctx, keeper) _, found = keeper.GetUnbondingDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) require.False(t, found, "should have unbonded") } func TestUnbondingFromUnbondingValidator(t *testing.T) { - ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) - handler := staking.NewHandler(keeper) - validatorAddr, delegatorAddr := sdk.ValAddress(keep.Addrs[0]), keep.Addrs[1] + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) + handler := NewHandler(keeper) + validatorAddr, delegatorAddr := sdk.ValAddress(Addrs[0]), Addrs[1] // create the validator - msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], sdk.NewInt(10)) + msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], sdk.NewInt(10)) res, err := handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) @@ -858,7 +859,7 @@ func TestUnbondingFromUnbondingValidator(t *testing.T) { // unbond the validators bond portion unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) - msgUndelegateValidator := staking.NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) + msgUndelegateValidator := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) res, err = handler(ctx, msgUndelegateValidator) require.NoError(t, err) require.NotNil(t, res) @@ -873,7 +874,7 @@ func TestUnbondingFromUnbondingValidator(t *testing.T) { ctx = ctx.WithBlockTime(finishTime.Add(time.Second * -1)) // unbond the delegator from the validator - msgUndelegateDelegator := staking.NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) + msgUndelegateDelegator := NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) res, err = handler(ctx, msgUndelegateDelegator) require.NoError(t, err) require.NotNil(t, res) @@ -881,7 +882,7 @@ func TestUnbondingFromUnbondingValidator(t *testing.T) { ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(keeper.UnbondingTime(ctx))) // Run the EndBlocker - staking.EndBlocker(ctx, keeper) + EndBlocker(ctx, keeper) // Check to make sure that the unbonding delegation is no longer in state // (meaning it was deleted in the above EndBlocker) @@ -890,9 +891,9 @@ func TestUnbondingFromUnbondingValidator(t *testing.T) { } func TestRedelegationPeriod(t *testing.T) { - ctx, _, bk, keeper, _ := keep.CreateTestInput(t, false, 1000) - handler := staking.NewHandler(keeper) - validatorAddr, validatorAddr2 := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1]) + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 1000) + handler := NewHandler(keeper) + validatorAddr, validatorAddr2 := sdk.ValAddress(Addrs[0]), sdk.ValAddress(Addrs[1]) denom := keeper.GetParams(ctx).BondDenom // set the unbonding time @@ -901,7 +902,7 @@ func TestRedelegationPeriod(t *testing.T) { keeper.SetParams(ctx, params) // create the validators - msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], sdk.NewInt(10)) + msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], sdk.NewInt(10)) // initial balance amt1 := bk.GetBalance(ctx, sdk.AccAddress(validatorAddr), denom).Amount @@ -914,7 +915,7 @@ func TestRedelegationPeriod(t *testing.T) { amt2 := bk.GetBalance(ctx, sdk.AccAddress(validatorAddr), denom).Amount require.Equal(t, amt1.Sub(sdk.NewInt(10)).Int64(), amt2.Int64(), "expected coins to be subtracted") - msgCreateValidator = NewTestMsgCreateValidator(validatorAddr2, keep.PKs[1], sdk.NewInt(10)) + msgCreateValidator = NewTestMsgCreateValidator(validatorAddr2, PKs[1], sdk.NewInt(10)) res, err = handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) @@ -923,7 +924,7 @@ func TestRedelegationPeriod(t *testing.T) { // begin redelegate redAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) - msgBeginRedelegate := staking.NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2, redAmt) + msgBeginRedelegate := NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2, redAmt) res, err = handler(ctx, msgBeginRedelegate) require.NoError(t, err) require.NotNil(t, res) @@ -935,59 +936,59 @@ func TestRedelegationPeriod(t *testing.T) { origHeader := ctx.BlockHeader() // cannot complete redelegation at same time - staking.EndBlocker(ctx, keeper) + EndBlocker(ctx, keeper) _, found := keeper.GetRedelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2) require.True(t, found, "should not have unbonded") // cannot complete redelegation at time 6 seconds later ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 6)) - staking.EndBlocker(ctx, keeper) + EndBlocker(ctx, keeper) _, found = keeper.GetRedelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2) require.True(t, found, "should not have unbonded") // can complete redelegation at time 7 seconds later ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 7)) - staking.EndBlocker(ctx, keeper) + EndBlocker(ctx, keeper) _, found = keeper.GetRedelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2) require.False(t, found, "should have unbonded") } func TestTransitiveRedelegation(t *testing.T) { - ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) - handler := staking.NewHandler(keeper) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) + handler := NewHandler(keeper) - validatorAddr := sdk.ValAddress(keep.Addrs[0]) - validatorAddr2 := sdk.ValAddress(keep.Addrs[1]) - validatorAddr3 := sdk.ValAddress(keep.Addrs[2]) + validatorAddr := sdk.ValAddress(Addrs[0]) + validatorAddr2 := sdk.ValAddress(Addrs[1]) + validatorAddr3 := sdk.ValAddress(Addrs[2]) blockTime := time.Now().UTC() ctx = ctx.WithBlockTime(blockTime) // create the validators - msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], sdk.NewInt(10)) + msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], sdk.NewInt(10)) res, err := handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) - msgCreateValidator = NewTestMsgCreateValidator(validatorAddr2, keep.PKs[1], sdk.NewInt(10)) + msgCreateValidator = NewTestMsgCreateValidator(validatorAddr2, PKs[1], sdk.NewInt(10)) res, err = handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) - msgCreateValidator = NewTestMsgCreateValidator(validatorAddr3, keep.PKs[2], sdk.NewInt(10)) + msgCreateValidator = NewTestMsgCreateValidator(validatorAddr3, PKs[2], sdk.NewInt(10)) res, err = handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) // begin redelegate redAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) - msgBeginRedelegate := staking.NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2, redAmt) + msgBeginRedelegate := NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2, redAmt) res, err = handler(ctx, msgBeginRedelegate) require.NoError(t, err) require.NotNil(t, res) // cannot redelegation to next validator while first delegation exists - msgBeginRedelegate = staking.NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr2, validatorAddr3, redAmt) + msgBeginRedelegate = NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr2, validatorAddr3, redAmt) res, err = handler(ctx, msgBeginRedelegate) require.Error(t, err) require.Nil(t, res) @@ -996,7 +997,7 @@ func TestTransitiveRedelegation(t *testing.T) { ctx = ctx.WithBlockTime(blockTime.Add(params.UnbondingTime)) // complete first redelegation - staking.EndBlocker(ctx, keeper) + EndBlocker(ctx, keeper) // now should be able to redelegate from the second validator to the third res, err = handler(ctx, msgBeginRedelegate) @@ -1005,11 +1006,11 @@ func TestTransitiveRedelegation(t *testing.T) { } func TestMultipleRedelegationAtSameTime(t *testing.T) { - ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) - handler := staking.NewHandler(keeper) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) + handler := NewHandler(keeper) - valAddr := sdk.ValAddress(keep.Addrs[0]) - valAddr2 := sdk.ValAddress(keep.Addrs[1]) + valAddr := sdk.ValAddress(Addrs[0]) + valAddr2 := sdk.ValAddress(Addrs[1]) // set the unbonding time params := keeper.GetParams(ctx) @@ -1018,23 +1019,23 @@ func TestMultipleRedelegationAtSameTime(t *testing.T) { // create the validators valTokens := sdk.TokensFromConsensusPower(10) - msgCreateValidator := NewTestMsgCreateValidator(valAddr, keep.PKs[0], valTokens) + msgCreateValidator := NewTestMsgCreateValidator(valAddr, PKs[0], valTokens) res, err := handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) - msgCreateValidator = NewTestMsgCreateValidator(valAddr2, keep.PKs[1], valTokens) + msgCreateValidator = NewTestMsgCreateValidator(valAddr2, PKs[1], valTokens) res, err = handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) // end block to bond them - staking.EndBlocker(ctx, keeper) + EndBlocker(ctx, keeper) // begin a redelegate selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) redAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens.QuoRaw(2)) - msgBeginRedelegate := staking.NewMsgBeginRedelegate(selfDelAddr, valAddr, valAddr2, redAmt) + msgBeginRedelegate := NewMsgBeginRedelegate(selfDelAddr, valAddr, valAddr2, redAmt) res, err = handler(ctx, msgBeginRedelegate) require.NoError(t, err) require.NotNil(t, res) @@ -1056,18 +1057,18 @@ func TestMultipleRedelegationAtSameTime(t *testing.T) { // move forward in time, should complete both redelegations ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(1 * time.Second)) - staking.EndBlocker(ctx, keeper) + EndBlocker(ctx, keeper) rd, found = keeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) require.False(t, found) } func TestMultipleRedelegationAtUniqueTimes(t *testing.T) { - ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) - handler := staking.NewHandler(keeper) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) + handler := NewHandler(keeper) - valAddr := sdk.ValAddress(keep.Addrs[0]) - valAddr2 := sdk.ValAddress(keep.Addrs[1]) + valAddr := sdk.ValAddress(Addrs[0]) + valAddr2 := sdk.ValAddress(Addrs[1]) // set the unbonding time params := keeper.GetParams(ctx) @@ -1076,23 +1077,23 @@ func TestMultipleRedelegationAtUniqueTimes(t *testing.T) { // create the validators valTokens := sdk.TokensFromConsensusPower(10) - msgCreateValidator := NewTestMsgCreateValidator(valAddr, keep.PKs[0], valTokens) + msgCreateValidator := NewTestMsgCreateValidator(valAddr, PKs[0], valTokens) res, err := handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) - msgCreateValidator = NewTestMsgCreateValidator(valAddr2, keep.PKs[1], valTokens) + msgCreateValidator = NewTestMsgCreateValidator(valAddr2, PKs[1], valTokens) res, err = handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) // end block to bond them - staking.EndBlocker(ctx, keeper) + EndBlocker(ctx, keeper) // begin a redelegate selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) redAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens.QuoRaw(2)) - msgBeginRedelegate := staking.NewMsgBeginRedelegate(selfDelAddr, valAddr, valAddr2, redAmt) + msgBeginRedelegate := NewMsgBeginRedelegate(selfDelAddr, valAddr, valAddr2, redAmt) res, err = handler(ctx, msgBeginRedelegate) require.NoError(t, err) require.NotNil(t, res) @@ -1110,23 +1111,23 @@ func TestMultipleRedelegationAtUniqueTimes(t *testing.T) { // move forward in time, should complete the first redelegation, but not the second ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) - staking.EndBlocker(ctx, keeper) + EndBlocker(ctx, keeper) rd, found = keeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) require.True(t, found) require.Len(t, rd.Entries, 1) // move forward in time, should complete the second redelegation ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) - staking.EndBlocker(ctx, keeper) + EndBlocker(ctx, keeper) rd, found = keeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) require.False(t, found) } func TestMultipleUnbondingDelegationAtSameTime(t *testing.T) { - ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) - handler := staking.NewHandler(keeper) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) + handler := NewHandler(keeper) - valAddr := sdk.ValAddress(keep.Addrs[0]) + valAddr := sdk.ValAddress(Addrs[0]) // set the unbonding time params := keeper.GetParams(ctx) @@ -1135,18 +1136,18 @@ func TestMultipleUnbondingDelegationAtSameTime(t *testing.T) { // create the validator valTokens := sdk.TokensFromConsensusPower(10) - msgCreateValidator := NewTestMsgCreateValidator(valAddr, keep.PKs[0], valTokens) + msgCreateValidator := NewTestMsgCreateValidator(valAddr, PKs[0], valTokens) res, err := handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) // end block to bond - staking.EndBlocker(ctx, keeper) + EndBlocker(ctx, keeper) // begin an unbonding delegation selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens.QuoRaw(2)) - msgUndelegate := staking.NewMsgUndelegate(selfDelAddr, valAddr, unbondAmt) + msgUndelegate := NewMsgUndelegate(selfDelAddr, valAddr, unbondAmt) res, err = handler(ctx, msgUndelegate) require.NoError(t, err) require.NotNil(t, res) @@ -1168,16 +1169,16 @@ func TestMultipleUnbondingDelegationAtSameTime(t *testing.T) { // move forwaubd in time, should complete both ubds ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(1 * time.Second)) - staking.EndBlocker(ctx, keeper) + EndBlocker(ctx, keeper) ubd, found = keeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) require.False(t, found) } func TestMultipleUnbondingDelegationAtUniqueTimes(t *testing.T) { - ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) - handler := staking.NewHandler(keeper) - valAddr := sdk.ValAddress(keep.Addrs[0]) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) + handler := NewHandler(keeper) + valAddr := sdk.ValAddress(Addrs[0]) // set the unbonding time params := keeper.GetParams(ctx) @@ -1186,18 +1187,18 @@ func TestMultipleUnbondingDelegationAtUniqueTimes(t *testing.T) { // create the validator valTokens := sdk.TokensFromConsensusPower(10) - msgCreateValidator := NewTestMsgCreateValidator(valAddr, keep.PKs[0], valTokens) + msgCreateValidator := NewTestMsgCreateValidator(valAddr, PKs[0], valTokens) res, err := handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) // end block to bond - staking.EndBlocker(ctx, keeper) + EndBlocker(ctx, keeper) // begin an unbonding delegation selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens.QuoRaw(2)) - msgUndelegate := staking.NewMsgUndelegate(selfDelAddr, valAddr, unbondAmt) + msgUndelegate := NewMsgUndelegate(selfDelAddr, valAddr, unbondAmt) res, err = handler(ctx, msgUndelegate) require.NoError(t, err) require.NotNil(t, res) @@ -1220,25 +1221,25 @@ func TestMultipleUnbondingDelegationAtUniqueTimes(t *testing.T) { // move forwaubd in time, should complete the first redelegation, but not the second ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) - staking.EndBlocker(ctx, keeper) + EndBlocker(ctx, keeper) ubd, found = keeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) require.True(t, found) require.Len(t, ubd.Entries, 1) // move forwaubd in time, should complete the second redelegation ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) - staking.EndBlocker(ctx, keeper) + EndBlocker(ctx, keeper) ubd, found = keeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) require.False(t, found) } func TestUnbondingWhenExcessValidators(t *testing.T) { - ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) - handler := staking.NewHandler(keeper) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) + handler := NewHandler(keeper) - validatorAddr1 := sdk.ValAddress(keep.Addrs[0]) - validatorAddr2 := sdk.ValAddress(keep.Addrs[1]) - validatorAddr3 := sdk.ValAddress(keep.Addrs[2]) + validatorAddr1 := sdk.ValAddress(Addrs[0]) + validatorAddr2 := sdk.ValAddress(Addrs[1]) + validatorAddr3 := sdk.ValAddress(Addrs[2]) // set the unbonding time params := keeper.GetParams(ctx) @@ -1247,7 +1248,7 @@ func TestUnbondingWhenExcessValidators(t *testing.T) { // add three validators valTokens1 := sdk.TokensFromConsensusPower(50) - msgCreateValidator := NewTestMsgCreateValidator(validatorAddr1, keep.PKs[0], valTokens1) + msgCreateValidator := NewTestMsgCreateValidator(validatorAddr1, PKs[0], valTokens1) res, err := handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) @@ -1257,7 +1258,7 @@ func TestUnbondingWhenExcessValidators(t *testing.T) { require.Equal(t, 1, len(keeper.GetLastValidators(ctx))) valTokens2 := sdk.TokensFromConsensusPower(30) - msgCreateValidator = NewTestMsgCreateValidator(validatorAddr2, keep.PKs[1], valTokens2) + msgCreateValidator = NewTestMsgCreateValidator(validatorAddr2, PKs[1], valTokens2) res, err = handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) @@ -1267,7 +1268,7 @@ func TestUnbondingWhenExcessValidators(t *testing.T) { require.Equal(t, 2, len(keeper.GetLastValidators(ctx))) valTokens3 := sdk.TokensFromConsensusPower(10) - msgCreateValidator = NewTestMsgCreateValidator(validatorAddr3, keep.PKs[2], valTokens3) + msgCreateValidator = NewTestMsgCreateValidator(validatorAddr3, PKs[2], valTokens3) res, err = handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) @@ -1278,7 +1279,7 @@ func TestUnbondingWhenExcessValidators(t *testing.T) { // unbond the validator-2 unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens2) - msgUndelegate := staking.NewMsgUndelegate(sdk.AccAddress(validatorAddr2), validatorAddr2, unbondAmt) + msgUndelegate := NewMsgUndelegate(sdk.AccAddress(validatorAddr2), validatorAddr2, unbondAmt) res, err = handler(ctx, msgUndelegate) require.NoError(t, err) require.NotNil(t, res) @@ -1297,19 +1298,19 @@ func TestUnbondingWhenExcessValidators(t *testing.T) { } func TestBondUnbondRedelegateSlashTwice(t *testing.T) { - ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) - handler := staking.NewHandler(keeper) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) + handler := NewHandler(keeper) - valA, valB, del := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1]), keep.Addrs[2] - consAddr0 := sdk.ConsAddress(keep.PKs[0].Address()) + valA, valB, del := sdk.ValAddress(Addrs[0]), sdk.ValAddress(Addrs[1]), Addrs[2] + consAddr0 := sdk.ConsAddress(PKs[0].Address()) valTokens := sdk.TokensFromConsensusPower(10) - msgCreateValidator := NewTestMsgCreateValidator(valA, keep.PKs[0], valTokens) + msgCreateValidator := NewTestMsgCreateValidator(valA, PKs[0], valTokens) res, err := handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) - msgCreateValidator = NewTestMsgCreateValidator(valB, keep.PKs[1], valTokens) + msgCreateValidator = NewTestMsgCreateValidator(valB, PKs[1], valTokens) res, err = handler(ctx, msgCreateValidator) require.NoError(t, err) require.NotNil(t, res) @@ -1329,14 +1330,14 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) { // begin unbonding 4 stake unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(4)) - msgUndelegate := staking.NewMsgUndelegate(del, valA, unbondAmt) + msgUndelegate := NewMsgUndelegate(del, valA, unbondAmt) res, err = handler(ctx, msgUndelegate) require.NoError(t, err) require.NotNil(t, res) // begin redelegate 6 stake redAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(6)) - msgBeginRedelegate := staking.NewMsgBeginRedelegate(del, valA, valB, redAmt) + msgBeginRedelegate := NewMsgBeginRedelegate(del, valA, valB, redAmt) res, err = handler(ctx, msgBeginRedelegate) require.NoError(t, err) require.NotNil(t, res) @@ -1395,7 +1396,7 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) { require.Equal(t, sdk.NewDecFromInt(redAmt.Amount.QuoRaw(2)), delegation.Shares) // end blocker - staking.EndBlocker(ctx, keeper) + EndBlocker(ctx, keeper) // validator power should have been reduced to zero // validator should be in unbonding state @@ -1404,8 +1405,8 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) { } func TestInvalidMsg(t *testing.T) { - k := keep.Keeper{} - h := staking.NewHandler(k) + k := Keeper{} + h := NewHandler(k) res, err := h(sdk.NewContext(nil, abci.Header{}, false, nil), sdk.NewTestMsg()) require.Error(t, err) @@ -1414,10 +1415,10 @@ func TestInvalidMsg(t *testing.T) { } func TestInvalidCoinDenom(t *testing.T) { - ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) - handler := staking.NewHandler(keeper) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) + handler := NewHandler(keeper) - valA, valB, delAddr := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1]), keep.Addrs[2] + valA, valB, delAddr := sdk.ValAddress(Addrs[0]), sdk.ValAddress(Addrs[1]), Addrs[2] valTokens := sdk.TokensFromConsensusPower(100) invalidCoin := sdk.NewCoin("churros", valTokens) @@ -1426,17 +1427,17 @@ func TestInvalidCoinDenom(t *testing.T) { commission := types.NewCommissionRates(sdk.OneDec(), sdk.OneDec(), sdk.ZeroDec()) - msgCreate := types.NewMsgCreateValidator(valA, keep.PKs[0], invalidCoin, staking.Description{}, commission, sdk.OneInt()) + msgCreate := types.NewMsgCreateValidator(valA, PKs[0], invalidCoin, Description{}, commission, sdk.OneInt()) res, err := handler(ctx, msgCreate) require.Error(t, err) require.Nil(t, res) - msgCreate = types.NewMsgCreateValidator(valA, keep.PKs[0], validCoin, staking.Description{}, commission, sdk.OneInt()) + msgCreate = types.NewMsgCreateValidator(valA, PKs[0], validCoin, Description{}, commission, sdk.OneInt()) res, err = handler(ctx, msgCreate) require.NoError(t, err) require.NotNil(t, res) - msgCreate = types.NewMsgCreateValidator(valB, keep.PKs[1], validCoin, staking.Description{}, commission, sdk.OneInt()) + msgCreate = types.NewMsgCreateValidator(valB, PKs[1], validCoin, Description{}, commission, sdk.OneInt()) res, err = handler(ctx, msgCreate) require.NoError(t, err) require.NotNil(t, res) diff --git a/x/staking/keeper/old_test_common.go b/x/staking/keeper/old_test_common.go index e1c75edeae29..80a78701c0f9 100644 --- a/x/staking/keeper/old_test_common.go +++ b/x/staking/keeper/old_test_common.go @@ -2,220 +2,12 @@ package keeper // noalias import ( "bytes" - "encoding/hex" "math/rand" - "strconv" - "testing" - "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/crypto" - "github.com/tendermint/tendermint/crypto/ed25519" - "github.com/tendermint/tendermint/libs/log" - tmtypes "github.com/tendermint/tendermint/types" - dbm "github.com/tendermint/tm-db" - - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth" - authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" - "github.com/cosmos/cosmos-sdk/x/bank" - "github.com/cosmos/cosmos-sdk/x/params" "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/cosmos/cosmos-sdk/x/supply" -) - -// dummy addresses used for testing -// nolint:unused, deadcode -var ( - Addrs = createTestAddrs(500) - PKs = createTestPubKeys(500) ) -// create a codec used only for testing -func MakeTestCodec() *codec.Codec { - var cdc = codec.New() - - // Register Msgs - cdc.RegisterInterface((*sdk.Msg)(nil), nil) - cdc.RegisterConcrete(bank.MsgSend{}, "test/staking/Send", nil) - cdc.RegisterConcrete(types.MsgCreateValidator{}, "test/staking/CreateValidator", nil) - cdc.RegisterConcrete(types.MsgEditValidator{}, "test/staking/EditValidator", nil) - cdc.RegisterConcrete(types.MsgUndelegate{}, "test/staking/Undelegate", nil) - cdc.RegisterConcrete(types.MsgBeginRedelegate{}, "test/staking/BeginRedelegate", nil) - - // Register AppAccount - cdc.RegisterInterface((*authexported.Account)(nil), nil) - cdc.RegisterConcrete(&auth.BaseAccount{}, "test/staking/BaseAccount", nil) - supply.RegisterCodec(cdc) - codec.RegisterCrypto(cdc) - - return cdc -} - -// Hogpodge of all sorts of input required for testing. -// `initPower` is converted to an amount of tokens. -// If `initPower` is 0, no addrs get created. -func CreateTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context, auth.AccountKeeper, types.BankKeeper, Keeper, types.SupplyKeeper) { - keyStaking := sdk.NewKVStoreKey(types.StoreKey) - keyAcc := sdk.NewKVStoreKey(auth.StoreKey) - bankKey := sdk.NewKVStoreKey(bank.StoreKey) - keyParams := sdk.NewKVStoreKey(params.StoreKey) - keySupply := sdk.NewKVStoreKey(supply.StoreKey) - - tkeyParams := sdk.NewTransientStoreKey(params.TStoreKey) - - db := dbm.NewMemDB() - ms := store.NewCommitMultiStore(db) - ms.MountStoreWithDB(keyStaking, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(keyAcc, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(bankKey, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(keyParams, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(tkeyParams, sdk.StoreTypeTransient, db) - ms.MountStoreWithDB(keySupply, sdk.StoreTypeIAVL, db) - err := ms.LoadLatestVersion() - require.Nil(t, err) - - ctx := sdk.NewContext(ms, abci.Header{ChainID: "foochainid"}, isCheckTx, log.NewNopLogger()) - ctx = ctx.WithConsensusParams( - &abci.ConsensusParams{ - Validator: &abci.ValidatorParams{ - PubKeyTypes: []string{tmtypes.ABCIPubKeyTypeEd25519}, - }, - }, - ) - cdc := MakeTestCodec() - - feeCollectorAcc := supply.NewEmptyModuleAccount(auth.FeeCollectorName) - notBondedPool := supply.NewEmptyModuleAccount(types.NotBondedPoolName, supply.Burner, supply.Staking) - bondPool := supply.NewEmptyModuleAccount(types.BondedPoolName, supply.Burner, supply.Staking) - - blacklistedAddrs := make(map[string]bool) - blacklistedAddrs[feeCollectorAcc.GetAddress().String()] = true - blacklistedAddrs[notBondedPool.GetAddress().String()] = true - blacklistedAddrs[bondPool.GetAddress().String()] = true - - pk := params.NewKeeper(params.ModuleCdc, keyParams, tkeyParams) - - accountKeeper := auth.NewAccountKeeper( - cdc, // amino codec - keyAcc, // target store - pk.Subspace(auth.DefaultParamspace), - auth.ProtoBaseAccount, // prototype - ) - - bk := bank.NewBaseKeeper( - cdc, - bankKey, - accountKeeper, - pk.Subspace(bank.DefaultParamspace), - blacklistedAddrs, - ) - - maccPerms := map[string][]string{ - auth.FeeCollectorName: nil, - types.NotBondedPoolName: {supply.Burner, supply.Staking}, - types.BondedPoolName: {supply.Burner, supply.Staking}, - } - supplyKeeper := supply.NewKeeper(cdc, keySupply, accountKeeper, bk, maccPerms) - - initTokens := sdk.TokensFromConsensusPower(initPower) - initCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initTokens)) - totalSupply := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initTokens.MulRaw(int64(len(Addrs))))) - - supplyKeeper.SetSupply(ctx, supply.NewSupply(totalSupply)) - - keeper := NewKeeper(types.ModuleCdc, keyStaking, bk, supplyKeeper, pk.Subspace(DefaultParamspace)) - keeper.SetParams(ctx, types.DefaultParams()) - - // set module accounts - require.NoError(t, bk.SetBalances(ctx, notBondedPool.GetAddress(), totalSupply)) - - supplyKeeper.SetModuleAccount(ctx, feeCollectorAcc) - supplyKeeper.SetModuleAccount(ctx, bondPool) - supplyKeeper.SetModuleAccount(ctx, notBondedPool) - - // fill all the addresses with some coins, set the loose pool tokens simultaneously - for i, addr := range Addrs { - accountKeeper.SetAccount(ctx, auth.NewBaseAccount(addr, PKs[i], uint64(i), 0)) - require.NoError(t, bk.SetBalances(ctx, addr, initCoins)) - } - - return ctx, accountKeeper, bk, keeper, supplyKeeper -} - -func NewPubKey(pk string) (res crypto.PubKey) { - pkBytes, err := hex.DecodeString(pk) - if err != nil { - panic(err) - } - //res, err = crypto.PubKeyFromBytes(pkBytes) - var pkEd ed25519.PubKeyEd25519 - copy(pkEd[:], pkBytes) - return pkEd -} - -// for incode address generation -func TestAddr(addr string, bech string) sdk.AccAddress { - - res, err := sdk.AccAddressFromHex(addr) - if err != nil { - panic(err) - } - bechexpected := res.String() - if bech != bechexpected { - panic("Bech encoding doesn't match reference") - } - - bechres, err := sdk.AccAddressFromBech32(bech) - if err != nil { - panic(err) - } - if !bytes.Equal(bechres, res) { - panic("Bech decode and hex decode don't match") - } - - return res -} - -// nolint: unparam -func createTestAddrs(numAddrs int) []sdk.AccAddress { - var addresses []sdk.AccAddress - var buffer bytes.Buffer - - // start at 100 so we can make up to 999 test addresses with valid test addresses - for i := 100; i < (numAddrs + 100); i++ { - numString := strconv.Itoa(i) - buffer.WriteString("A58856F0FD53BF058B4909A21AEC019107BA6") //base address string - - buffer.WriteString(numString) //adding on final two digits to make addresses unique - res, _ := sdk.AccAddressFromHex(buffer.String()) - bech := res.String() - addresses = append(addresses, TestAddr(buffer.String(), bech)) - buffer.Reset() - } - return addresses -} - -// nolint: unparam -func createTestPubKeys(numPubKeys int) []crypto.PubKey { - var publicKeys []crypto.PubKey - var buffer bytes.Buffer - - //start at 10 to avoid changing 1 to 01, 2 to 02, etc - for i := 100; i < (numPubKeys + 100); i++ { - numString := strconv.Itoa(i) - buffer.WriteString("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AF") //base pubkey string - buffer.WriteString(numString) //adding on final two digits to make pubkeys unique - publicKeys = append(publicKeys, NewPubKey(buffer.String())) - buffer.Reset() - } - return publicKeys -} - -//_____________________________________________________________________________________ - // does a certain by-power index record exist func ValidatorByPowerIndexExists(ctx sdk.Context, keeper Keeper, power []byte) bool { store := ctx.KVStore(keeper.storeKey) diff --git a/x/staking/test_common.go b/x/staking/test_common.go new file mode 100644 index 000000000000..0760ebcc575a --- /dev/null +++ b/x/staking/test_common.go @@ -0,0 +1,217 @@ +package staking + +import ( + "bytes" + "encoding/hex" + "strconv" + "testing" + + "github.com/stretchr/testify/require" + + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto" + "github.com/tendermint/tendermint/crypto/ed25519" + "github.com/tendermint/tendermint/libs/log" + tmtypes "github.com/tendermint/tendermint/types" + dbm "github.com/tendermint/tm-db" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" + authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" + "github.com/cosmos/cosmos-sdk/x/bank" + "github.com/cosmos/cosmos-sdk/x/params" + "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/cosmos/cosmos-sdk/x/supply" +) + +// dummy addresses used for testing +// nolint:unused, deadcode +var ( + Addrs = createTestAddrs(500) + PKs = createTestPubKeys(500) +) + +// nolint: unparam +func createTestAddrs(numAddrs int) []sdk.AccAddress { + var addresses []sdk.AccAddress + var buffer bytes.Buffer + + // start at 100 so we can make up to 999 test addresses with valid test addresses + for i := 100; i < (numAddrs + 100); i++ { + numString := strconv.Itoa(i) + buffer.WriteString("A58856F0FD53BF058B4909A21AEC019107BA6") //base address string + + buffer.WriteString(numString) //adding on final two digits to make addresses unique + res, _ := sdk.AccAddressFromHex(buffer.String()) + bech := res.String() + addresses = append(addresses, TestAddr(buffer.String(), bech)) + buffer.Reset() + } + return addresses +} + +// nolint: unparam +func createTestPubKeys(numPubKeys int) []crypto.PubKey { + var publicKeys []crypto.PubKey + var buffer bytes.Buffer + + //start at 10 to avoid changing 1 to 01, 2 to 02, etc + for i := 100; i < (numPubKeys + 100); i++ { + numString := strconv.Itoa(i) + buffer.WriteString("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AF") //base pubkey string + buffer.WriteString(numString) //adding on final two digits to make pubkeys unique + publicKeys = append(publicKeys, NewPubKey(buffer.String())) + buffer.Reset() + } + return publicKeys +} + +//_____________________________________________________________________________________ + +// Hogpodge of all sorts of input required for testing. +// `initPower` is converted to an amount of tokens. +// If `initPower` is 0, no addrs get created. +func CreateTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context, auth.AccountKeeper, types.BankKeeper, Keeper, types.SupplyKeeper) { + keyStaking := sdk.NewKVStoreKey(types.StoreKey) + keyAcc := sdk.NewKVStoreKey(auth.StoreKey) + bankKey := sdk.NewKVStoreKey(bank.StoreKey) + keyParams := sdk.NewKVStoreKey(params.StoreKey) + keySupply := sdk.NewKVStoreKey(supply.StoreKey) + + tkeyParams := sdk.NewTransientStoreKey(params.TStoreKey) + + db := dbm.NewMemDB() + ms := store.NewCommitMultiStore(db) + ms.MountStoreWithDB(keyStaking, sdk.StoreTypeIAVL, db) + ms.MountStoreWithDB(keyAcc, sdk.StoreTypeIAVL, db) + ms.MountStoreWithDB(bankKey, sdk.StoreTypeIAVL, db) + ms.MountStoreWithDB(keyParams, sdk.StoreTypeIAVL, db) + ms.MountStoreWithDB(tkeyParams, sdk.StoreTypeTransient, db) + ms.MountStoreWithDB(keySupply, sdk.StoreTypeIAVL, db) + err := ms.LoadLatestVersion() + require.Nil(t, err) + + ctx := sdk.NewContext(ms, abci.Header{ChainID: "foochainid"}, isCheckTx, log.NewNopLogger()) + ctx = ctx.WithConsensusParams( + &abci.ConsensusParams{ + Validator: &abci.ValidatorParams{ + PubKeyTypes: []string{tmtypes.ABCIPubKeyTypeEd25519}, + }, + }, + ) + cdc := MakeTestCodec() + + feeCollectorAcc := supply.NewEmptyModuleAccount(auth.FeeCollectorName) + notBondedPool := supply.NewEmptyModuleAccount(types.NotBondedPoolName, supply.Burner, supply.Staking) + bondPool := supply.NewEmptyModuleAccount(types.BondedPoolName, supply.Burner, supply.Staking) + + blacklistedAddrs := make(map[string]bool) + blacklistedAddrs[feeCollectorAcc.GetAddress().String()] = true + blacklistedAddrs[notBondedPool.GetAddress().String()] = true + blacklistedAddrs[bondPool.GetAddress().String()] = true + + pk := params.NewKeeper(params.ModuleCdc, keyParams, tkeyParams) + + accountKeeper := auth.NewAccountKeeper( + cdc, // amino codec + keyAcc, // target store + pk.Subspace(auth.DefaultParamspace), + auth.ProtoBaseAccount, // prototype + ) + + bk := bank.NewBaseKeeper( + cdc, + bankKey, + accountKeeper, + pk.Subspace(bank.DefaultParamspace), + blacklistedAddrs, + ) + + maccPerms := map[string][]string{ + auth.FeeCollectorName: nil, + types.NotBondedPoolName: {supply.Burner, supply.Staking}, + types.BondedPoolName: {supply.Burner, supply.Staking}, + } + supplyKeeper := supply.NewKeeper(cdc, keySupply, accountKeeper, bk, maccPerms) + + initTokens := sdk.TokensFromConsensusPower(initPower) + initCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initTokens)) + totalSupply := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initTokens.MulRaw(int64(len(Addrs))))) + + supplyKeeper.SetSupply(ctx, supply.NewSupply(totalSupply)) + + keeper := NewKeeper(types.ModuleCdc, keyStaking, bk, supplyKeeper, pk.Subspace(DefaultParamspace)) + keeper.SetParams(ctx, types.DefaultParams()) + + // set module accounts + require.NoError(t, bk.SetBalances(ctx, notBondedPool.GetAddress(), totalSupply)) + + supplyKeeper.SetModuleAccount(ctx, feeCollectorAcc) + supplyKeeper.SetModuleAccount(ctx, bondPool) + supplyKeeper.SetModuleAccount(ctx, notBondedPool) + + // fill all the addresses with some coins, set the loose pool tokens simultaneously + for i, addr := range Addrs { + accountKeeper.SetAccount(ctx, auth.NewBaseAccount(addr, PKs[i], uint64(i), 0)) + require.NoError(t, bk.SetBalances(ctx, addr, initCoins)) + } + + return ctx, accountKeeper, bk, keeper, supplyKeeper +} + +// create a codec used only for testing +func MakeTestCodec() *codec.Codec { + var cdc = codec.New() + + // Register Msgs + cdc.RegisterInterface((*sdk.Msg)(nil), nil) + cdc.RegisterConcrete(bank.MsgSend{}, "test/staking/Send", nil) + cdc.RegisterConcrete(types.MsgCreateValidator{}, "test/staking/CreateValidator", nil) + cdc.RegisterConcrete(types.MsgEditValidator{}, "test/staking/EditValidator", nil) + cdc.RegisterConcrete(types.MsgUndelegate{}, "test/staking/Undelegate", nil) + cdc.RegisterConcrete(types.MsgBeginRedelegate{}, "test/staking/BeginRedelegate", nil) + + // Register AppAccount + cdc.RegisterInterface((*authexported.Account)(nil), nil) + cdc.RegisterConcrete(&auth.BaseAccount{}, "test/staking/BaseAccount", nil) + supply.RegisterCodec(cdc) + codec.RegisterCrypto(cdc) + + return cdc +} + +// for incode address generation +func TestAddr(addr string, bech string) sdk.AccAddress { + + res, err := sdk.AccAddressFromHex(addr) + if err != nil { + panic(err) + } + bechexpected := res.String() + if bech != bechexpected { + panic("Bech encoding doesn't match reference") + } + + bechres, err := sdk.AccAddressFromBech32(bech) + if err != nil { + panic(err) + } + if !bytes.Equal(bechres, res) { + panic("Bech decode and hex decode don't match") + } + + return res +} + +func NewPubKey(pk string) (res crypto.PubKey) { + pkBytes, err := hex.DecodeString(pk) + if err != nil { + panic(err) + } + //res, err = crypto.PubKeyFromBytes(pkBytes) + var pkEd ed25519.PubKeyEd25519 + copy(pkEd[:], pkBytes) + return pkEd +} From b931c491aeddc4fb0f2824928cef9286bec21cf4 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Tue, 25 Feb 2020 15:29:53 +0100 Subject: [PATCH 214/529] rename --- x/staking/keeper/{old_test_common.go => test_common.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename x/staking/keeper/{old_test_common.go => test_common.go} (100%) diff --git a/x/staking/keeper/old_test_common.go b/x/staking/keeper/test_common.go similarity index 100% rename from x/staking/keeper/old_test_common.go rename to x/staking/keeper/test_common.go From a44bebc11cf2d2b293e298e347399e265ebd7c44 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Tue, 25 Feb 2020 15:31:22 +0100 Subject: [PATCH 215/529] rename commont test --- x/staking/keeper/{test_common_test.go => common_test.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename x/staking/keeper/{test_common_test.go => common_test.go} (100%) diff --git a/x/staking/keeper/test_common_test.go b/x/staking/keeper/common_test.go similarity index 100% rename from x/staking/keeper/test_common_test.go rename to x/staking/keeper/common_test.go From 194b97b1c1d37e6c6696923fa54b376789064fc1 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Tue, 25 Feb 2020 17:33:18 +0100 Subject: [PATCH 216/529] git remove unused vars --- x/staking/common_test.go | 9 --------- 1 file changed, 9 deletions(-) diff --git a/x/staking/common_test.go b/x/staking/common_test.go index 225832dd170f..291f5ea523ca 100644 --- a/x/staking/common_test.go +++ b/x/staking/common_test.go @@ -5,7 +5,6 @@ import ( "github.com/tendermint/tendermint/crypto/secp256k1" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/staking" "github.com/cosmos/cosmos-sdk/x/staking/types" ) @@ -16,14 +15,6 @@ var ( addr1 = sdk.AccAddress(priv1.PubKey().Address()) priv2 = secp256k1.GenPrivKey() addr2 = sdk.AccAddress(priv2.PubKey().Address()) - addr3 = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) - priv4 = secp256k1.GenPrivKey() - addr4 = sdk.AccAddress(priv4.PubKey().Address()) - coins = sdk.Coins{sdk.NewCoin("foocoin", sdk.NewInt(10))} - fee = auth.NewStdFee( - 100000, - sdk.Coins{sdk.NewCoin("foocoin", sdk.NewInt(0))}, - ) commissionRates = staking.NewCommissionRates(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()) ) From 660ffc8be5e14d41bcf7dff45ad983f02ed596a6 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Tue, 25 Feb 2020 18:01:18 +0100 Subject: [PATCH 217/529] refactor ordering functions --- simapp/test_helpers.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/simapp/test_helpers.go b/simapp/test_helpers.go index cfedd7d3188f..78f2fbc41476 100644 --- a/simapp/test_helpers.go +++ b/simapp/test_helpers.go @@ -82,7 +82,8 @@ func SetupWithGenesisAccounts(genAccs []authexported.GenesisAccount, balances .. type GenerateAccountStrategy func(int) []sdk.AccAddress -func Random(accNum int) []sdk.AccAddress { +// random is a strategy used by addTestAddrs() in order to generated addresses in random order. +func random(accNum int) []sdk.AccAddress { testAddrs := make([]sdk.AccAddress, accNum) for i := 0; i < accNum; i++ { pk := ed25519.GenPrivKey().PubKey() @@ -92,7 +93,8 @@ func Random(accNum int) []sdk.AccAddress { return testAddrs } -func Incremental(accNum int) []sdk.AccAddress { +// incremental is a strategy used by addTestAddrs() in order to generated addresses in ascending order. +func incremental(accNum int) []sdk.AccAddress { var addresses []sdk.AccAddress var buffer bytes.Buffer @@ -114,13 +116,13 @@ func Incremental(accNum int) []sdk.AccAddress { // AddTestAddrs constructs and returns accNum amount of accounts with an // initial balance of accAmt in random order func AddTestAddrs(app *SimApp, ctx sdk.Context, accNum int, accAmt sdk.Int) []sdk.AccAddress { - return addTestAddrs(app, ctx, accNum, accAmt, Random) + return addTestAddrs(app, ctx, accNum, accAmt, random) } // AddTestAddrs constructs and returns accNum amount of accounts with an // initial balance of accAmt in random order func AddTestAddrsIncremental(app *SimApp, ctx sdk.Context, accNum int, accAmt sdk.Int) []sdk.AccAddress { - return addTestAddrs(app, ctx, accNum, accAmt, Incremental) + return addTestAddrs(app, ctx, accNum, accAmt, incremental) } func addTestAddrs(app *SimApp, ctx sdk.Context, accNum int, accAmt sdk.Int, strategy GenerateAccountStrategy) []sdk.AccAddress { From ec39bb3b4274eca381cca7eefce0b45e90d84500 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Tue, 25 Feb 2020 15:22:28 -0500 Subject: [PATCH 218/529] Merge PR #5696: Fix x/auth proto json tags --- server/export.go | 10 ++--- x/auth/types/account.go | 46 ++++++++++++++++++++ x/auth/types/types.pb.go | 83 +++++++++++++++++++------------------ x/auth/types/types.proto | 4 +- x/upgrade/types/types.pb.go | 67 +++++++++++++++--------------- 5 files changed, 126 insertions(+), 84 deletions(-) diff --git a/server/export.go b/server/export.go index b4f52f639c59..81f43571b183 100644 --- a/server/export.go +++ b/server/export.go @@ -10,7 +10,6 @@ import ( "github.com/spf13/cobra" "github.com/spf13/viper" tmtypes "github.com/tendermint/tendermint/types" - dbm "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" @@ -39,8 +38,8 @@ func ExportCmd(ctx *Context, cdc codec.JSONMarshaler, appExporter AppExporter) * return err } - if isEmptyState(db) || appExporter == nil { - if _, err := fmt.Fprintln(os.Stderr, "WARNING: State is not initialized. Returning genesis file."); err != nil { + if appExporter == nil { + if _, err := fmt.Fprintln(os.Stderr, "WARNING: App exporter not defined. Returning genesis file."); err != nil { return err } @@ -88,9 +87,6 @@ func ExportCmd(ctx *Context, cdc codec.JSONMarshaler, appExporter AppExporter) * cmd.Flags().Int64(flagHeight, -1, "Export state from a particular height (-1 means latest height)") cmd.Flags().Bool(flagForZeroHeight, false, "Export state to start at height zero (perform preproccessing)") cmd.Flags().StringSlice(flagJailWhitelist, []string{}, "List of validators to not jail state export") - return cmd -} -func isEmptyState(db dbm.DB) bool { - return db.Stats()["leveldb.sstables"] == "" + return cmd } diff --git a/x/auth/types/account.go b/x/auth/types/account.go index 08b67facc3de..bae7d8f3b4fe 100644 --- a/x/auth/types/account.go +++ b/x/auth/types/account.go @@ -2,6 +2,7 @@ package types import ( "bytes" + "encoding/json" "errors" "github.com/tendermint/tendermint/crypto" @@ -143,3 +144,48 @@ func (acc BaseAccount) MarshalYAML() (interface{}, error) { return string(bz), err } + +// MarshalJSON returns the JSON representation of a BaseAccount. +func (acc BaseAccount) MarshalJSON() ([]byte, error) { + alias := baseAccountPretty{ + Address: acc.Address, + AccountNumber: acc.AccountNumber, + Sequence: acc.Sequence, + } + + if acc.PubKey != nil { + pks, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, acc.GetPubKey()) + if err != nil { + return nil, err + } + + alias.PubKey = pks + } + + return json.Marshal(alias) +} + +// UnmarshalJSON unmarshals raw JSON bytes into a BaseAccount. +func (acc *BaseAccount) UnmarshalJSON(bz []byte) error { + var alias baseAccountPretty + if err := json.Unmarshal(bz, &alias); err != nil { + return err + } + + // NOTE: This will not work for multisig-based accounts as their Bech32 + // encoding is too long. + if alias.PubKey != "" { + pk, err := sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeAccPub, alias.PubKey) + if err != nil { + return err + } + + acc.PubKey = pk.Bytes() + } + + acc.Address = alias.Address + acc.AccountNumber = alias.AccountNumber + acc.Sequence = alias.Sequence + + return nil +} diff --git a/x/auth/types/types.pb.go b/x/auth/types/types.pb.go index d4aaf520d2f1..f5fa313fb325 100644 --- a/x/auth/types/types.pb.go +++ b/x/auth/types/types.pb.go @@ -30,7 +30,7 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // type for additional functionality (e.g. vesting). type BaseAccount struct { Address github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,1,opt,name=address,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"address,omitempty"` - PubKey []byte `protobuf:"bytes,2,opt,name=pub_key,json=pubKey,proto3" json:"pub_key,omitempty" yaml:"public_key"` + PubKey []byte `protobuf:"bytes,2,opt,name=pub_key,json=pubKey,proto3" json:"public_key,omitempty" yaml:"public_key"` AccountNumber uint64 `protobuf:"varint,3,opt,name=account_number,json=accountNumber,proto3" json:"account_number,omitempty" yaml:"account_number"` Sequence uint64 `protobuf:"varint,4,opt,name=sequence,proto3" json:"sequence,omitempty"` } @@ -207,46 +207,47 @@ func init() { func init() { proto.RegisterFile("x/auth/types/types.proto", fileDescriptor_2d526fa662daab74) } var fileDescriptor_2d526fa662daab74 = []byte{ - // 613 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x53, 0xbf, 0x6f, 0xd3, 0x4e, - 0x14, 0x8f, 0xbf, 0xc9, 0x37, 0xad, 0xae, 0x05, 0x11, 0xf7, 0x97, 0x1b, 0x21, 0x5f, 0xe4, 0x01, - 0x85, 0xa1, 0x0e, 0x29, 0x2a, 0x52, 0x33, 0x20, 0xea, 0x00, 0x4b, 0xa1, 0xaa, 0x1c, 0x89, 0x01, - 0x09, 0x59, 0x67, 0xfb, 0x70, 0xac, 0xf4, 0x72, 0xae, 0xef, 0x5c, 0xd9, 0x5d, 0x58, 0x19, 0x19, - 0x19, 0x3b, 0xf3, 0x97, 0x74, 0xec, 0xc8, 0xe4, 0xa2, 0x74, 0x61, 0xf6, 0xc8, 0x84, 0xce, 0x97, - 0x96, 0xb4, 0x14, 0xc4, 0x62, 0xdf, 0x7b, 0xef, 0xf3, 0xe3, 0xee, 0xbd, 0x3b, 0xa0, 0xa5, 0x1d, - 0x94, 0xf0, 0x61, 0x87, 0x67, 0x11, 0x66, 0xf2, 0x6b, 0x46, 0x31, 0xe5, 0x54, 0x5d, 0xf6, 0x28, - 0x23, 0x94, 0x39, 0xcc, 0x1f, 0x99, 0xa9, 0x29, 0x40, 0xe6, 0x51, 0xb7, 0xf9, 0x80, 0x0f, 0xc3, - 0xd8, 0x77, 0x22, 0x14, 0xf3, 0xac, 0x53, 0x02, 0x3b, 0x01, 0x0d, 0xe8, 0xaf, 0x95, 0x64, 0x37, - 0x1b, 0xbf, 0x09, 0x1a, 0x85, 0x02, 0x16, 0x2c, 0xc4, 0xf0, 0x8e, 0xe7, 0xd1, 0x64, 0xcc, 0xd5, - 0x5d, 0x30, 0x87, 0x7c, 0x3f, 0xc6, 0x8c, 0x69, 0x4a, 0x4b, 0x69, 0x2f, 0x5a, 0xdd, 0x1f, 0x39, - 0xdc, 0x08, 0x42, 0x3e, 0x4c, 0x5c, 0xd3, 0xa3, 0xa4, 0x23, 0x37, 0x30, 0xfd, 0x6d, 0x30, 0x7f, - 0x34, 0x95, 0xdb, 0xf1, 0xbc, 0x1d, 0x49, 0xb4, 0x2f, 0x15, 0x54, 0x13, 0xcc, 0x45, 0x89, 0xeb, - 0x8c, 0x70, 0xa6, 0xfd, 0x57, 0x8a, 0xad, 0x14, 0x39, 0x6c, 0x64, 0x88, 0x1c, 0xf4, 0x8c, 0x28, - 0x71, 0x0f, 0x42, 0x4f, 0xd4, 0x0c, 0xbb, 0x1e, 0x25, 0xee, 0x2e, 0xce, 0xd4, 0x67, 0xe0, 0x2e, - 0x92, 0xfb, 0x70, 0xc6, 0x09, 0x71, 0x71, 0xac, 0x55, 0x5b, 0x4a, 0xbb, 0x66, 0xad, 0x17, 0x39, - 0x5c, 0x91, 0xb4, 0xeb, 0x75, 0xc3, 0xbe, 0x33, 0x4d, 0xec, 0x95, 0xb1, 0xda, 0x04, 0xf3, 0x0c, - 0x1f, 0x26, 0x78, 0xec, 0x61, 0xad, 0x26, 0xb8, 0xf6, 0x55, 0xdc, 0x9b, 0xff, 0x78, 0x02, 0x2b, - 0x9f, 0x4f, 0x60, 0xc5, 0xf8, 0x00, 0xea, 0x03, 0xee, 0xbf, 0xc4, 0x58, 0x7d, 0x07, 0xea, 0x88, - 0x08, 0xbe, 0xa6, 0xb4, 0xaa, 0xed, 0x85, 0xcd, 0x25, 0x73, 0xa6, 0xc1, 0x47, 0x5d, 0xb3, 0x4f, - 0xc3, 0xb1, 0xf5, 0xe8, 0x34, 0x87, 0x95, 0x2f, 0xe7, 0xb0, 0xfd, 0x0f, 0x6d, 0x10, 0x04, 0x66, - 0x4f, 0x45, 0xd5, 0x7b, 0xa0, 0x1a, 0x20, 0x56, 0x1e, 0xbe, 0x66, 0x8b, 0x65, 0xaf, 0xf6, 0xfd, - 0x04, 0x2a, 0xc6, 0x79, 0x15, 0xd4, 0xf7, 0x51, 0x8c, 0x08, 0x53, 0xf7, 0xc0, 0x12, 0x41, 0xa9, - 0x43, 0x30, 0xa1, 0x8e, 0x37, 0x44, 0x31, 0xf2, 0x38, 0x8e, 0x65, 0xf3, 0x6b, 0x96, 0x5e, 0xe4, - 0xb0, 0x29, 0x0f, 0x7e, 0x0b, 0xc8, 0xb0, 0x1b, 0x04, 0xa5, 0xaf, 0x31, 0xa1, 0xfd, 0xab, 0x9c, - 0xba, 0x0d, 0x16, 0x79, 0xea, 0xb0, 0x30, 0x70, 0x0e, 0x42, 0x12, 0x72, 0xe9, 0x6d, 0xad, 0x15, - 0x39, 0x5c, 0x92, 0x42, 0xb3, 0x55, 0xc3, 0x06, 0x3c, 0x1d, 0x84, 0xc1, 0x2b, 0x11, 0xa8, 0x36, - 0x58, 0x29, 0x8b, 0xc7, 0xd8, 0xf1, 0x28, 0xe3, 0x4e, 0x84, 0x63, 0xc7, 0xcd, 0x38, 0x9e, 0x4e, - 0xa1, 0x55, 0xe4, 0xf0, 0xfe, 0x8c, 0xc6, 0x4d, 0x98, 0x61, 0x37, 0x84, 0xd8, 0x31, 0xee, 0x53, - 0xc6, 0xf7, 0x71, 0x6c, 0x65, 0x1c, 0xab, 0x87, 0x60, 0x4d, 0xb8, 0x1d, 0xe1, 0x38, 0x7c, 0x9f, - 0x49, 0x3c, 0xf6, 0x37, 0xb7, 0xb6, 0xba, 0xdb, 0x72, 0x3e, 0x56, 0x6f, 0x92, 0xc3, 0xe5, 0x41, - 0x18, 0xbc, 0x29, 0x11, 0x82, 0xfa, 0xe2, 0x79, 0x59, 0x2f, 0x72, 0xa8, 0x4b, 0xb7, 0x3f, 0x08, - 0x18, 0xf6, 0x32, 0xbb, 0xc6, 0x93, 0x69, 0x35, 0x03, 0xeb, 0x37, 0x19, 0x0c, 0x7b, 0xd1, 0xe6, - 0xd6, 0x93, 0x51, 0x57, 0xfb, 0xbf, 0x34, 0x7d, 0x3a, 0xc9, 0xe1, 0xea, 0x35, 0xd3, 0xc1, 0x25, - 0xa2, 0xc8, 0x61, 0xeb, 0x76, 0xdb, 0x2b, 0x11, 0xc3, 0x5e, 0x65, 0xb7, 0x72, 0x7b, 0xf3, 0xe2, - 0x7a, 0x89, 0x09, 0x5b, 0xfd, 0xd3, 0x89, 0xae, 0x9c, 0x4d, 0x74, 0xe5, 0xdb, 0x44, 0x57, 0x3e, - 0x5d, 0xe8, 0x95, 0xb3, 0x0b, 0xbd, 0xf2, 0xf5, 0x42, 0xaf, 0xbc, 0x7d, 0xf8, 0xd7, 0x5b, 0x34, - 0xfb, 0xf2, 0xdd, 0x7a, 0xf9, 0x46, 0x1f, 0xff, 0x0c, 0x00, 0x00, 0xff, 0xff, 0xa8, 0xcb, 0x64, - 0x0b, 0x10, 0x04, 0x00, 0x00, + // 630 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x54, 0xbf, 0x6f, 0xd3, 0x4e, + 0x14, 0x8f, 0x9b, 0x7c, 0xd3, 0xea, 0xda, 0x2f, 0x22, 0x6e, 0xda, 0xba, 0x11, 0xf2, 0x45, 0x1e, + 0x50, 0x90, 0xa8, 0x43, 0x8a, 0x8a, 0xd4, 0x0c, 0x88, 0x3a, 0xd0, 0xa5, 0x50, 0x55, 0x8e, 0xc4, + 0x80, 0x84, 0xac, 0xb3, 0x7d, 0x38, 0x56, 0x7a, 0x39, 0xd7, 0x77, 0xae, 0xec, 0x2e, 0xac, 0x88, + 0x89, 0x91, 0xb1, 0x33, 0x7f, 0x49, 0xc7, 0x8e, 0x4c, 0x2e, 0x4a, 0x17, 0xc4, 0xe8, 0x91, 0x09, + 0xd9, 0x97, 0xb6, 0x69, 0x29, 0x88, 0xc5, 0xbe, 0xf7, 0xde, 0xe7, 0xc7, 0xf9, 0xbd, 0xf3, 0x01, + 0x25, 0x6e, 0xa3, 0x88, 0x0f, 0xda, 0x3c, 0x09, 0x30, 0x13, 0x4f, 0x3d, 0x08, 0x29, 0xa7, 0x72, + 0xdd, 0xa1, 0x8c, 0x50, 0x66, 0x31, 0x77, 0xa8, 0xc7, 0x7a, 0x0e, 0xd2, 0x0f, 0x3b, 0x8d, 0xfb, + 0x7c, 0xe0, 0x87, 0xae, 0x15, 0xa0, 0x90, 0x27, 0xed, 0x02, 0xd8, 0xf6, 0xa8, 0x47, 0xaf, 0x56, + 0x82, 0xdd, 0xa8, 0xfd, 0x26, 0xa8, 0x7d, 0x9c, 0x01, 0xf3, 0x06, 0x62, 0x78, 0xcb, 0x71, 0x68, + 0x34, 0xe2, 0xf2, 0x0e, 0x98, 0x45, 0xae, 0x1b, 0x62, 0xc6, 0x14, 0xa9, 0x29, 0xb5, 0x16, 0x8c, + 0xce, 0xcf, 0x14, 0xae, 0x79, 0x3e, 0x1f, 0x44, 0xb6, 0xee, 0x50, 0xd2, 0x16, 0x1b, 0x98, 0xbc, + 0xd6, 0x98, 0x3b, 0x9c, 0xc8, 0x6d, 0x39, 0xce, 0x96, 0x20, 0x9a, 0x17, 0x0a, 0xf2, 0x36, 0x98, + 0x0d, 0x22, 0xdb, 0x1a, 0xe2, 0x44, 0x99, 0x29, 0xc4, 0xd6, 0x7e, 0xa4, 0xb0, 0x1e, 0x44, 0xf6, + 0xbe, 0xef, 0xe4, 0xd9, 0x87, 0x94, 0xf8, 0x1c, 0x93, 0x80, 0x27, 0x59, 0x0a, 0x6b, 0x09, 0x22, + 0xfb, 0x5d, 0xed, 0xaa, 0xaa, 0x99, 0xd5, 0x20, 0xb2, 0x77, 0x70, 0x22, 0x3f, 0x03, 0x77, 0x90, + 0xd8, 0x9f, 0x35, 0x8a, 0x88, 0x8d, 0x43, 0xa5, 0xdc, 0x94, 0x5a, 0x15, 0x63, 0x35, 0x4b, 0xe1, + 0x92, 0xa0, 0x5d, 0xaf, 0x6b, 0xe6, 0xff, 0x93, 0xc4, 0x6e, 0x11, 0xcb, 0x0d, 0x30, 0xc7, 0xf0, + 0x41, 0x84, 0x47, 0x0e, 0x56, 0x2a, 0x39, 0xd7, 0xbc, 0x8c, 0xbb, 0x73, 0x1f, 0x8e, 0x61, 0xe9, + 0xf3, 0x31, 0x2c, 0x69, 0xef, 0x41, 0xb5, 0xcf, 0xdd, 0x6d, 0x8c, 0xe5, 0xb7, 0xa0, 0x8a, 0x48, + 0xce, 0x57, 0xa4, 0x66, 0xb9, 0x35, 0xbf, 0xbe, 0xa8, 0x4f, 0x35, 0xfe, 0xb0, 0xa3, 0xf7, 0xa8, + 0x3f, 0x32, 0x1e, 0x9d, 0xa4, 0xb0, 0xf4, 0xe5, 0x0c, 0xb6, 0xfe, 0xa1, 0x3d, 0x39, 0x81, 0x99, + 0x13, 0x51, 0xf9, 0x2e, 0x28, 0x7b, 0x88, 0x15, 0x4d, 0xa9, 0x98, 0xf9, 0xb2, 0x5b, 0xf9, 0x7e, + 0x0c, 0x25, 0xed, 0xac, 0x0c, 0xaa, 0x7b, 0x28, 0x44, 0x84, 0xc9, 0xbb, 0x60, 0x91, 0xa0, 0xd8, + 0x22, 0x98, 0x50, 0xcb, 0x19, 0xa0, 0x10, 0x39, 0x1c, 0x87, 0x62, 0x28, 0x15, 0x43, 0xcd, 0x52, + 0xd8, 0x10, 0x1f, 0x7e, 0x0b, 0x48, 0x33, 0x6b, 0x04, 0xc5, 0xaf, 0x30, 0xa1, 0xbd, 0xcb, 0x9c, + 0xbc, 0x09, 0x16, 0x78, 0x6c, 0x31, 0xdf, 0xb3, 0xf6, 0x7d, 0xe2, 0x73, 0xe1, 0x6d, 0xac, 0x64, + 0x29, 0x5c, 0x14, 0x42, 0xd3, 0x55, 0xcd, 0x04, 0x3c, 0xee, 0xfb, 0xde, 0xcb, 0x3c, 0x90, 0x4d, + 0xb0, 0x54, 0x14, 0x8f, 0xb0, 0xe5, 0x50, 0xc6, 0xad, 0x00, 0x87, 0x96, 0x9d, 0x70, 0x3c, 0x99, + 0x42, 0x33, 0x4b, 0xe1, 0xbd, 0x29, 0x8d, 0x9b, 0x30, 0xcd, 0xac, 0xe5, 0x62, 0x47, 0xb8, 0x47, + 0x19, 0xdf, 0xc3, 0xa1, 0x91, 0x70, 0x2c, 0x1f, 0x80, 0x95, 0xdc, 0xed, 0x10, 0x87, 0xfe, 0xbb, + 0x44, 0xe0, 0xb1, 0xbb, 0xbe, 0xb1, 0xd1, 0xd9, 0x14, 0xf3, 0x31, 0xba, 0xe3, 0x14, 0xd6, 0xfb, + 0xbe, 0xf7, 0xba, 0x40, 0xe4, 0xd4, 0x17, 0xcf, 0x8b, 0x7a, 0x96, 0x42, 0x55, 0xb8, 0xfd, 0x41, + 0x40, 0x33, 0xeb, 0xec, 0x1a, 0x4f, 0xa4, 0xe5, 0x04, 0xac, 0xde, 0x64, 0x30, 0xec, 0x04, 0xeb, + 0x1b, 0x4f, 0x86, 0x1d, 0xe5, 0xbf, 0xc2, 0xf4, 0xe9, 0x38, 0x85, 0xcb, 0xd7, 0x4c, 0xfb, 0x17, + 0x88, 0x2c, 0x85, 0xcd, 0xdb, 0x6d, 0x2f, 0x45, 0x34, 0x73, 0x99, 0xdd, 0xca, 0xed, 0xce, 0xe5, + 0xc7, 0x2b, 0x9f, 0xb0, 0xd1, 0x3b, 0x19, 0xab, 0xd2, 0xe9, 0x58, 0x95, 0xbe, 0x8d, 0x55, 0xe9, + 0xd3, 0xb9, 0x5a, 0x3a, 0x3d, 0x57, 0x4b, 0x5f, 0xcf, 0xd5, 0xd2, 0x9b, 0x07, 0x7f, 0x3d, 0x45, + 0xd3, 0x37, 0x82, 0x5d, 0x2d, 0xfe, 0xdd, 0xc7, 0xbf, 0x02, 0x00, 0x00, 0xff, 0xff, 0xce, 0x6d, + 0xf3, 0x2e, 0x28, 0x04, 0x00, 0x00, } func (this *StdFee) Equal(that interface{}) bool { diff --git a/x/auth/types/types.proto b/x/auth/types/types.proto index 99bf50bc8524..60e7a8d8b863 100644 --- a/x/auth/types/types.proto +++ b/x/auth/types/types.proto @@ -13,8 +13,8 @@ message BaseAccount { option (gogoproto.goproto_getters) = false; option (gogoproto.goproto_stringer) = false; - bytes address = 1 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; - bytes pub_key = 2 [(gogoproto.moretags) = "yaml:\"public_key\""]; + bytes address = 1 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; + bytes pub_key = 2 [(gogoproto.jsontag) = "public_key,omitempty", (gogoproto.moretags) = "yaml:\"public_key\""]; uint64 account_number = 3 [(gogoproto.moretags) = "yaml:\"account_number\""]; uint64 sequence = 4; } diff --git a/x/upgrade/types/types.pb.go b/x/upgrade/types/types.pb.go index 4e8f7cbb9895..8cc9e383bedb 100644 --- a/x/upgrade/types/types.pb.go +++ b/x/upgrade/types/types.pb.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: x/upgrade/internal/types/types.proto +// source: x/upgrade/types/types.proto package types @@ -49,7 +49,7 @@ type Plan struct { func (m *Plan) Reset() { *m = Plan{} } func (*Plan) ProtoMessage() {} func (*Plan) Descriptor() ([]byte, []int) { - return fileDescriptor_6199ecc2c05edfcb, []int{0} + return fileDescriptor_2a308fd9dd71aff8, []int{0} } func (m *Plan) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -78,6 +78,7 @@ func (m *Plan) XXX_DiscardUnknown() { var xxx_messageInfo_Plan proto.InternalMessageInfo +// SoftwareUpgradeProposal is a gov Content type for initiating a software upgrade type SoftwareUpgradeProposal struct { Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` @@ -87,7 +88,7 @@ type SoftwareUpgradeProposal struct { func (m *SoftwareUpgradeProposal) Reset() { *m = SoftwareUpgradeProposal{} } func (*SoftwareUpgradeProposal) ProtoMessage() {} func (*SoftwareUpgradeProposal) Descriptor() ([]byte, []int) { - return fileDescriptor_6199ecc2c05edfcb, []int{1} + return fileDescriptor_2a308fd9dd71aff8, []int{1} } func (m *SoftwareUpgradeProposal) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -116,6 +117,7 @@ func (m *SoftwareUpgradeProposal) XXX_DiscardUnknown() { var xxx_messageInfo_SoftwareUpgradeProposal proto.InternalMessageInfo +// SoftwareUpgradeProposal is a gov Content type for cancelling a software upgrade type CancelSoftwareUpgradeProposal struct { Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` @@ -124,7 +126,7 @@ type CancelSoftwareUpgradeProposal struct { func (m *CancelSoftwareUpgradeProposal) Reset() { *m = CancelSoftwareUpgradeProposal{} } func (*CancelSoftwareUpgradeProposal) ProtoMessage() {} func (*CancelSoftwareUpgradeProposal) Descriptor() ([]byte, []int) { - return fileDescriptor_6199ecc2c05edfcb, []int{2} + return fileDescriptor_2a308fd9dd71aff8, []int{2} } func (m *CancelSoftwareUpgradeProposal) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -159,36 +161,33 @@ func init() { proto.RegisterType((*CancelSoftwareUpgradeProposal)(nil), "cosmos_sdk.x.upgrade.v1.CancelSoftwareUpgradeProposal") } -func init() { - proto.RegisterFile("x/upgrade/internal/types/types.proto", fileDescriptor_6199ecc2c05edfcb) -} - -var fileDescriptor_6199ecc2c05edfcb = []byte{ - // 371 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x52, 0x3f, 0x0f, 0x12, 0x31, - 0x14, 0xbf, 0xca, 0x49, 0xa4, 0x6c, 0x8d, 0x91, 0x0b, 0x09, 0xe5, 0x42, 0x8c, 0x21, 0x31, 0xb6, - 0x11, 0x07, 0x9d, 0x71, 0x36, 0x21, 0xa7, 0xc6, 0xc4, 0x85, 0x94, 0xbb, 0x72, 0xd7, 0x70, 0xd7, - 0x36, 0x6d, 0x51, 0xd8, 0x9c, 0x9d, 0xf8, 0x58, 0x8c, 0x8c, 0x4c, 0x2a, 0xf0, 0x45, 0xcc, 0x5d, - 0x8f, 0xe8, 0xe2, 0xe6, 0xd2, 0xbe, 0xd7, 0xfc, 0xfe, 0xbd, 0xb6, 0xf0, 0xe9, 0x8e, 0x6e, 0x75, - 0x6e, 0x58, 0xc6, 0xa9, 0x90, 0x8e, 0x1b, 0xc9, 0x4a, 0xea, 0xf6, 0x9a, 0x5b, 0xbf, 0x12, 0x6d, - 0x94, 0x53, 0x68, 0x90, 0x2a, 0x5b, 0x29, 0xbb, 0xb4, 0xd9, 0x86, 0xec, 0x48, 0x4b, 0x20, 0x5f, - 0x5e, 0x0e, 0x9f, 0xb9, 0x42, 0x98, 0x6c, 0xa9, 0x99, 0x71, 0x7b, 0xda, 0x60, 0x69, 0xae, 0x72, - 0xf5, 0xa7, 0xf2, 0x02, 0xc3, 0x71, 0xae, 0x54, 0x5e, 0x72, 0x0f, 0x59, 0x6d, 0xd7, 0xd4, 0x89, - 0x8a, 0x5b, 0xc7, 0x2a, 0xed, 0x01, 0x93, 0x6f, 0x00, 0x86, 0x8b, 0x92, 0x49, 0x84, 0x60, 0x28, - 0x59, 0xc5, 0x23, 0x10, 0x83, 0x69, 0x2f, 0x69, 0x6a, 0xf4, 0x06, 0x86, 0x35, 0x3e, 0x7a, 0x10, - 0x83, 0x69, 0x7f, 0x36, 0x24, 0x5e, 0x8c, 0xdc, 0xc5, 0xc8, 0x87, 0xbb, 0xd8, 0xfc, 0xd1, 0xf1, - 0xc7, 0x38, 0x38, 0xfc, 0x1c, 0x83, 0xa4, 0x61, 0xa0, 0x27, 0xb0, 0x5b, 0x70, 0x91, 0x17, 0x2e, - 0xea, 0xc4, 0x60, 0xda, 0x49, 0xda, 0xae, 0x76, 0x11, 0x72, 0xad, 0xa2, 0xd0, 0xbb, 0xd4, 0xf5, - 0xe4, 0x3b, 0x80, 0x83, 0xf7, 0x6a, 0xed, 0xbe, 0x32, 0xc3, 0x3f, 0xfa, 0x11, 0x17, 0x46, 0x69, - 0x65, 0x59, 0x89, 0x1e, 0xc3, 0x87, 0x4e, 0xb8, 0xf2, 0x1e, 0xcb, 0x37, 0x28, 0x86, 0xfd, 0x8c, - 0xdb, 0xd4, 0x08, 0xed, 0x84, 0x92, 0x4d, 0xbc, 0x5e, 0xf2, 0xf7, 0x11, 0x7a, 0x0d, 0x43, 0x5d, - 0x32, 0xd9, 0xb8, 0xf7, 0x67, 0x23, 0xf2, 0x8f, 0x7b, 0x24, 0xf5, 0xe8, 0xf3, 0xb0, 0x0e, 0x9f, - 0x34, 0x84, 0xc9, 0x27, 0x38, 0x7a, 0xcb, 0x64, 0xca, 0xcb, 0xff, 0x9c, 0x68, 0xfe, 0xee, 0x78, - 0xc1, 0xc1, 0xf9, 0x82, 0x83, 0xe3, 0x15, 0x83, 0xd3, 0x15, 0x83, 0x5f, 0x57, 0x0c, 0x0e, 0x37, - 0x1c, 0x9c, 0x6e, 0x38, 0x38, 0xdf, 0x70, 0xf0, 0xf9, 0x79, 0x2e, 0x5c, 0xb1, 0x5d, 0x91, 0x54, - 0x55, 0xd4, 0xe7, 0x6d, 0xb7, 0x17, 0x36, 0xdb, 0xd0, 0x1d, 0xd5, 0xcc, 0xb0, 0xaa, 0xfd, 0x1f, - 0xab, 0x6e, 0xf3, 0x08, 0xaf, 0x7e, 0x07, 0x00, 0x00, 0xff, 0xff, 0xad, 0x67, 0xed, 0x35, 0x48, - 0x02, 0x00, 0x00, +func init() { proto.RegisterFile("x/upgrade/types/types.proto", fileDescriptor_2a308fd9dd71aff8) } + +var fileDescriptor_2a308fd9dd71aff8 = []byte{ + // 364 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x52, 0x31, 0x6f, 0xe2, 0x30, + 0x18, 0x8d, 0x8f, 0x1c, 0x3a, 0xcc, 0x66, 0x9d, 0x8e, 0x88, 0x13, 0x26, 0x62, 0xa8, 0x18, 0x5a, + 0x47, 0xa5, 0x43, 0x3b, 0xd3, 0xbd, 0x42, 0x69, 0xab, 0x4a, 0x5d, 0x90, 0x49, 0x4c, 0x62, 0x91, + 0xc4, 0x56, 0x6c, 0x5a, 0xd8, 0x3a, 0x77, 0xe2, 0x67, 0x31, 0x32, 0x32, 0xb5, 0x05, 0xfe, 0x48, + 0x95, 0x18, 0xd4, 0xaa, 0x52, 0xb7, 0x2e, 0xf6, 0xfb, 0xac, 0xf7, 0xbd, 0xf7, 0x3e, 0xdb, 0xf0, + 0xff, 0xcc, 0x9b, 0xca, 0x28, 0xa7, 0x21, 0xf3, 0xf4, 0x5c, 0x32, 0x65, 0x56, 0x22, 0x73, 0xa1, + 0x05, 0x6a, 0x04, 0x42, 0xa5, 0x42, 0x0d, 0x55, 0x38, 0x21, 0x33, 0xb2, 0xe7, 0x91, 0x87, 0xd3, + 0xe6, 0x91, 0x8e, 0x79, 0x1e, 0x0e, 0x25, 0xcd, 0xf5, 0xdc, 0x2b, 0xb9, 0x5e, 0x24, 0x22, 0xf1, + 0x81, 0x8c, 0x40, 0xb3, 0x1d, 0x09, 0x11, 0x25, 0xcc, 0x50, 0x46, 0xd3, 0xb1, 0xa7, 0x79, 0xca, + 0x94, 0xa6, 0xa9, 0x34, 0x84, 0xce, 0x13, 0x80, 0xf6, 0x20, 0xa1, 0x19, 0x42, 0xd0, 0xce, 0x68, + 0xca, 0x1c, 0xe0, 0x82, 0x6e, 0xcd, 0x2f, 0x31, 0xba, 0x80, 0x76, 0xc1, 0x77, 0x7e, 0xb9, 0xa0, + 0x5b, 0xef, 0x35, 0x89, 0x11, 0x23, 0x07, 0x31, 0x72, 0x73, 0x10, 0xeb, 0xff, 0x59, 0xbe, 0xb4, + 0xad, 0xc5, 0x6b, 0x1b, 0xf8, 0x65, 0x07, 0xfa, 0x07, 0xab, 0x31, 0xe3, 0x51, 0xac, 0x9d, 0x8a, + 0x0b, 0xba, 0x15, 0x7f, 0x5f, 0x15, 0x2e, 0x3c, 0x1b, 0x0b, 0xc7, 0x36, 0x2e, 0x05, 0xee, 0x3c, + 0x03, 0xd8, 0xb8, 0x16, 0x63, 0xfd, 0x48, 0x73, 0x76, 0x6b, 0x46, 0x1c, 0xe4, 0x42, 0x0a, 0x45, + 0x13, 0xf4, 0x17, 0xfe, 0xd6, 0x5c, 0x27, 0x87, 0x58, 0xa6, 0x40, 0x2e, 0xac, 0x87, 0x4c, 0x05, + 0x39, 0x97, 0x9a, 0x8b, 0xac, 0x8c, 0x57, 0xf3, 0x3f, 0x1f, 0xa1, 0x73, 0x68, 0xcb, 0x84, 0x66, + 0xa5, 0x7b, 0xbd, 0xd7, 0x22, 0xdf, 0xdc, 0x23, 0x29, 0x46, 0xef, 0xdb, 0x45, 0x78, 0xbf, 0x6c, + 0xe8, 0xdc, 0xc1, 0xd6, 0x25, 0xcd, 0x02, 0x96, 0xfc, 0x70, 0xa2, 0xfe, 0xd5, 0x72, 0x83, 0xad, + 0xf5, 0x06, 0x5b, 0xcb, 0x2d, 0x06, 0xab, 0x2d, 0x06, 0x6f, 0x5b, 0x0c, 0x16, 0x3b, 0x6c, 0xad, + 0x76, 0xd8, 0x5a, 0xef, 0xb0, 0x75, 0x7f, 0x1c, 0x71, 0x1d, 0x4f, 0x47, 0x24, 0x10, 0xa9, 0x67, + 0xf2, 0xee, 0xb7, 0x13, 0x15, 0x4e, 0xbc, 0x2f, 0xdf, 0x64, 0x54, 0x2d, 0x5f, 0xe1, 0xec, 0x3d, + 0x00, 0x00, 0xff, 0xff, 0x0f, 0x77, 0x53, 0x0a, 0x40, 0x02, 0x00, 0x00, } func (m *Plan) Marshal() (dAtA []byte, err error) { From 399ea763ee0a5fd28c90264a8b4ab11853a2b6e4 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Wed, 26 Feb 2020 10:47:39 +0100 Subject: [PATCH 219/529] refactor old genesis_test to use simapp --- x/staking/common_test.go | 66 + x/staking/genesis_test.go | 70 +- x/staking/handler_test.go | 2925 ++++++++++++++++++------------------- 3 files changed, 1565 insertions(+), 1496 deletions(-) diff --git a/x/staking/common_test.go b/x/staking/common_test.go index 291f5ea523ca..871894b9bbcf 100644 --- a/x/staking/common_test.go +++ b/x/staking/common_test.go @@ -1,11 +1,21 @@ package staking_test import ( + "bytes" + "encoding/hex" + "strconv" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/simapp" + cdc "github.com/cosmos/cosmos-sdk/simapp/codec" + abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" + "github.com/tendermint/tendermint/crypto/ed25519" "github.com/tendermint/tendermint/crypto/secp256k1" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/staking" + "github.com/cosmos/cosmos-sdk/x/staking/keeper" "github.com/cosmos/cosmos-sdk/x/staking/types" ) @@ -17,6 +27,8 @@ var ( addr2 = sdk.AccAddress(priv2.PubKey().Address()) commissionRates = staking.NewCommissionRates(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()) + + PKs = createTestPubKeys(500) ) func NewTestMsgCreateValidator(address sdk.ValAddress, pubKey crypto.PubKey, amt sdk.Int) staking.MsgCreateValidator { @@ -29,3 +41,57 @@ func NewTestMsgDelegate(delAddr sdk.AccAddress, valAddr sdk.ValAddress, amt sdk. amount := sdk.NewCoin(sdk.DefaultBondDenom, amt) return staking.NewMsgDelegate(delAddr, valAddr, amount) } + +// nolint: unparam +func createTestPubKeys(numPubKeys int) []crypto.PubKey { + var publicKeys []crypto.PubKey + var buffer bytes.Buffer + + //start at 10 to avoid changing 1 to 01, 2 to 02, etc + for i := 100; i < (numPubKeys + 100); i++ { + numString := strconv.Itoa(i) + buffer.WriteString("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AF") //base pubkey string + buffer.WriteString(numString) //adding on final two digits to make pubkeys unique + publicKeys = append(publicKeys, NewPubKey(buffer.String())) + buffer.Reset() + } + return publicKeys +} + +func NewPubKey(pk string) (res crypto.PubKey) { + pkBytes, err := hex.DecodeString(pk) + if err != nil { + panic(err) + } + //res, err = crypto.PubKeyFromBytes(pkBytes) + var pkEd ed25519.PubKeyEd25519 + copy(pkEd[:], pkBytes) + return pkEd +} + +// getBaseSimappWithCustomKeeper Returns a simapp with custom StakingKeeper +// to avoid messing with the hooks. +func getBaseSimappWithCustomKeeper() (*codec.Codec, *simapp.SimApp, sdk.Context) { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + appCodec := cdc.NewAppCodec(codec.New()) + + app.StakingKeeper = keeper.NewKeeper( + appCodec, + app.GetKey(staking.StoreKey), + app.BankKeeper, + app.SupplyKeeper, + app.GetSubspace(staking.ModuleName), + ) + + return codec.New(), app, ctx +} + +// generateAddresses generates numAddrs of normal AccAddrs and ValAddrs +func generateAddresses(app *simapp.SimApp, ctx sdk.Context, numAddrs int) ([]sdk.AccAddress, []sdk.ValAddress) { + addrDels := simapp.AddTestAddrsIncremental(app, ctx, numAddrs, sdk.NewInt(10000)) + addrVals := simapp.ConvertAddrsToValAddrs(addrDels) + + return addrDels, addrVals +} diff --git a/x/staking/genesis_test.go b/x/staking/genesis_test.go index 730e7b0fc629..29a6149e4bb3 100644 --- a/x/staking/genesis_test.go +++ b/x/staking/genesis_test.go @@ -1,27 +1,49 @@ -package staking +package staking_test import ( "fmt" "testing" "github.com/stretchr/testify/assert" + "github.com/tendermint/tendermint/crypto/ed25519" + "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/crypto/ed25519" + "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/staking" "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/cosmos/cosmos-sdk/x/supply" ) +func bootstrapGenesisTest(t *testing.T, power int64, numAddrs int) (*simapp.SimApp, sdk.Context, []sdk.AccAddress, []sdk.ValAddress) { + _, app, ctx := getBaseSimappWithCustomKeeper() + + addrDels, addrVals := generateAddresses(app, ctx, numAddrs) + + amt := sdk.TokensFromConsensusPower(power) + totalSupply := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), amt.MulRaw(int64(len(addrDels))))) + + notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) + err := app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), totalSupply) + require.NoError(t, err) + app.SupplyKeeper.SetModuleAccount(ctx, notBondedPool) + + app.SupplyKeeper.SetSupply(ctx, supply.NewSupply(totalSupply)) + + return app, ctx, addrDels, addrVals +} + func TestInitGenesis(t *testing.T) { - ctx, accKeeper, bk, keeper, supplyKeeper := CreateTestInput(t, false, 1000) + app, ctx, addrs, _ := bootstrapGenesisTest(t, 1000, 10) valTokens := sdk.TokensFromConsensusPower(1) - params := keeper.GetParams(ctx) - validators := make([]Validator, 2) - var delegations []Delegation + params := app.StakingKeeper.GetParams(ctx) + validators := make([]types.Validator, 2) + var delegations []types.Delegation pk0, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, PKs[0]) require.NoError(t, err) @@ -30,33 +52,33 @@ func TestInitGenesis(t *testing.T) { require.NoError(t, err) // initialize the validators - validators[0].OperatorAddress = sdk.ValAddress(Addrs[0]) + validators[0].OperatorAddress = sdk.ValAddress(addrs[0]) validators[0].ConsensusPubkey = pk0 - validators[0].Description = NewDescription("hoop", "", "", "", "") + validators[0].Description = types.NewDescription("hoop", "", "", "", "") validators[0].Status = sdk.Bonded validators[0].Tokens = valTokens validators[0].DelegatorShares = valTokens.ToDec() - validators[1].OperatorAddress = sdk.ValAddress(Addrs[1]) + validators[1].OperatorAddress = sdk.ValAddress(addrs[1]) validators[1].ConsensusPubkey = pk1 - validators[1].Description = NewDescription("bloop", "", "", "", "") + validators[1].Description = types.NewDescription("bloop", "", "", "", "") validators[1].Status = sdk.Bonded validators[1].Tokens = valTokens validators[1].DelegatorShares = valTokens.ToDec() genesisState := types.NewGenesisState(params, validators, delegations) - vals := InitGenesis(ctx, keeper, accKeeper, bk, supplyKeeper, genesisState) + vals := staking.InitGenesis(ctx, app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.SupplyKeeper, genesisState) - actualGenesis := ExportGenesis(ctx, keeper) + actualGenesis := staking.ExportGenesis(ctx, app.StakingKeeper) require.Equal(t, genesisState.Params, actualGenesis.Params) require.Equal(t, genesisState.Delegations, actualGenesis.Delegations) - require.EqualValues(t, keeper.GetAllValidators(ctx), actualGenesis.Validators) + require.EqualValues(t, app.StakingKeeper.GetAllValidators(ctx), actualGenesis.Validators) // now make sure the validators are bonded and intra-tx counters are correct - resVal, found := keeper.GetValidator(ctx, sdk.ValAddress(Addrs[0])) + resVal, found := app.StakingKeeper.GetValidator(ctx, sdk.ValAddress(addrs[0])) require.True(t, found) require.Equal(t, sdk.Bonded, resVal.Status) - resVal, found = keeper.GetValidator(ctx, sdk.ValAddress(Addrs[1])) + resVal, found = app.StakingKeeper.GetValidator(ctx, sdk.ValAddress(addrs[1])) require.True(t, found) require.Equal(t, sdk.Bonded, resVal.Status) @@ -72,15 +94,15 @@ func TestInitGenesisLargeValidatorSet(t *testing.T) { size := 200 require.True(t, size > 100) - ctx, accKeeper, bk, keeper, supplyKeeper := CreateTestInput(t, false, 1000) + app, ctx, addrs, _ := bootstrapGenesisTest(t, 1000, 200) - params := keeper.GetParams(ctx) - delegations := []Delegation{} - validators := make([]Validator, size) + params := app.StakingKeeper.GetParams(ctx) + delegations := []types.Delegation{} + validators := make([]types.Validator, size) for i := range validators { - validators[i] = NewValidator(sdk.ValAddress(Addrs[i]), - PKs[i], NewDescription(fmt.Sprintf("#%d", i), "", "", "", "")) + validators[i] = types.NewValidator(sdk.ValAddress(addrs[i]), + PKs[i], types.NewDescription(fmt.Sprintf("#%d", i), "", "", "", "")) validators[i].Status = sdk.Bonded @@ -93,7 +115,7 @@ func TestInitGenesisLargeValidatorSet(t *testing.T) { } genesisState := types.NewGenesisState(params, validators, delegations) - vals := InitGenesis(ctx, keeper, accKeeper, bk, supplyKeeper, genesisState) + vals := staking.InitGenesis(ctx, app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.SupplyKeeper, genesisState) abcivals := make([]abci.ValidatorUpdate, 100) for i, val := range validators[:100] { @@ -138,9 +160,9 @@ func TestValidateGenesis(t *testing.T) { genesisState := types.DefaultGenesisState() tt.mutate(&genesisState) if tt.wantErr { - assert.Error(t, ValidateGenesis(genesisState)) + assert.Error(t, staking.ValidateGenesis(genesisState)) } else { - assert.NoError(t, ValidateGenesis(genesisState)) + assert.NoError(t, staking.ValidateGenesis(genesisState)) } }) } diff --git a/x/staking/handler_test.go b/x/staking/handler_test.go index f18dda6ac00c..bbbb2eaa8435 100644 --- a/x/staking/handler_test.go +++ b/x/staking/handler_test.go @@ -1,1474 +1,1455 @@ package staking_test -import ( - "strings" - "testing" - "time" - - gogotypes "github.com/gogo/protobuf/types" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/crypto/secp256k1" - tmtypes "github.com/tendermint/tendermint/types" - - sdk "github.com/cosmos/cosmos-sdk/types" - . "github.com/cosmos/cosmos-sdk/x/staking" - keep "github.com/cosmos/cosmos-sdk/x/staking/keeper" - "github.com/cosmos/cosmos-sdk/x/staking/types" -) - -func TestValidatorByPowerIndex(t *testing.T) { - validatorAddr, validatorAddr3 := sdk.ValAddress(Addrs[0]), sdk.ValAddress(Addrs[1]) - - initPower := int64(1000000) - initBond := sdk.TokensFromConsensusPower(initPower) - ctx, _, _, keeper, _ := CreateTestInput(t, false, initPower) - handler := NewHandler(keeper) - - // create validator - msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], initBond) - res, err := handler(ctx, msgCreateValidator) - require.NoError(t, err) - require.NotNil(t, res) - - // must end-block - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 1, len(updates)) - - // verify the self-delegation exists - bond, found := keeper.GetDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) - require.True(t, found) - gotBond := bond.Shares.RoundInt() - require.Equal(t, initBond, gotBond) - - // verify that the by power index exists - validator, found := keeper.GetValidator(ctx, validatorAddr) - require.True(t, found) - power := GetValidatorsByPowerIndexKey(validator) - require.True(t, keep.ValidatorByPowerIndexExists(ctx, keeper, power)) - - // create a second validator keep it bonded - msgCreateValidator = NewTestMsgCreateValidator(validatorAddr3, PKs[2], initBond) - res, err = handler(ctx, msgCreateValidator) - require.NoError(t, err) - require.NotNil(t, res) - - // must end-block - updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 1, len(updates)) - - // slash and jail the first validator - consAddr0 := sdk.ConsAddress(PKs[0].Address()) - keeper.Slash(ctx, consAddr0, 0, initPower, sdk.NewDecWithPrec(5, 1)) - keeper.Jail(ctx, consAddr0) - keeper.ApplyAndReturnValidatorSetUpdates(ctx) - - validator, found = keeper.GetValidator(ctx, validatorAddr) - require.True(t, found) - require.Equal(t, sdk.Unbonding, validator.Status) // ensure is unbonding - require.Equal(t, initBond.QuoRaw(2), validator.Tokens) // ensure tokens slashed - keeper.Unjail(ctx, consAddr0) - - // the old power record should have been deleted as the power changed - require.False(t, keep.ValidatorByPowerIndexExists(ctx, keeper, power)) - - // but the new power record should have been created - validator, found = keeper.GetValidator(ctx, validatorAddr) - require.True(t, found) - power2 := GetValidatorsByPowerIndexKey(validator) - require.True(t, keep.ValidatorByPowerIndexExists(ctx, keeper, power2)) - - // now the new record power index should be the same as the original record - power3 := GetValidatorsByPowerIndexKey(validator) - require.Equal(t, power2, power3) - - // unbond self-delegation - totalBond := validator.TokensFromShares(bond.GetShares()).TruncateInt() - unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, totalBond) - msgUndelegate := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) - - res, err = handler(ctx, msgUndelegate) - require.NoError(t, err) - require.NotNil(t, res) - - ts := &gogotypes.Timestamp{} - types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) - - finishTime, err := gogotypes.TimestampFromProto(ts) - require.NoError(t, err) - - ctx = ctx.WithBlockTime(finishTime) - EndBlocker(ctx, keeper) - EndBlocker(ctx, keeper) - - // verify that by power key nolonger exists - _, found = keeper.GetValidator(ctx, validatorAddr) - require.False(t, found) - require.False(t, keep.ValidatorByPowerIndexExists(ctx, keeper, power3)) -} - -func TestDuplicatesMsgCreateValidator(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - handler := NewHandler(keeper) - - addr1, addr2 := sdk.ValAddress(Addrs[0]), sdk.ValAddress(Addrs[1]) - pk1, pk2 := PKs[0], PKs[1] - - valTokens := sdk.TokensFromConsensusPower(10) - msgCreateValidator1 := NewTestMsgCreateValidator(addr1, pk1, valTokens) - res, err := handler(ctx, msgCreateValidator1) - require.NoError(t, err) - require.NotNil(t, res) - - keeper.ApplyAndReturnValidatorSetUpdates(ctx) - - validator, found := keeper.GetValidator(ctx, addr1) - require.True(t, found) - assert.Equal(t, sdk.Bonded, validator.Status) - assert.Equal(t, addr1, validator.OperatorAddress) - assert.Equal(t, pk1, validator.GetConsPubKey()) - assert.Equal(t, valTokens, validator.BondedTokens()) - assert.Equal(t, valTokens.ToDec(), validator.DelegatorShares) - assert.Equal(t, Description{}, validator.Description) - - // two validators can't have the same operator address - msgCreateValidator2 := NewTestMsgCreateValidator(addr1, pk2, valTokens) - res, err = handler(ctx, msgCreateValidator2) - require.Error(t, err) - require.Nil(t, res) - - // two validators can't have the same pubkey - msgCreateValidator3 := NewTestMsgCreateValidator(addr2, pk1, valTokens) - res, err = handler(ctx, msgCreateValidator3) - require.Error(t, err) - require.Nil(t, res) - - // must have different pubkey and operator - msgCreateValidator4 := NewTestMsgCreateValidator(addr2, pk2, valTokens) - res, err = handler(ctx, msgCreateValidator4) - require.NoError(t, err) - require.NotNil(t, res) - - // must end-block - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 1, len(updates)) - - validator, found = keeper.GetValidator(ctx, addr2) - - require.True(t, found) - assert.Equal(t, sdk.Bonded, validator.Status) - assert.Equal(t, addr2, validator.OperatorAddress) - assert.Equal(t, pk2, validator.GetConsPubKey()) - assert.True(sdk.IntEq(t, valTokens, validator.Tokens)) - assert.True(sdk.DecEq(t, valTokens.ToDec(), validator.DelegatorShares)) - assert.Equal(t, Description{}, validator.Description) -} - -func TestInvalidPubKeyTypeMsgCreateValidator(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - handler := NewHandler(keeper) - - addr := sdk.ValAddress(Addrs[0]) - invalidPk := secp256k1.GenPrivKey().PubKey() - - // invalid pukKey type should not be allowed - msgCreateValidator := NewTestMsgCreateValidator(addr, invalidPk, sdk.NewInt(10)) - res, err := handler(ctx, msgCreateValidator) - require.Error(t, err) - require.Nil(t, res) - - ctx = ctx.WithConsensusParams(&abci.ConsensusParams{ - Validator: &abci.ValidatorParams{PubKeyTypes: []string{tmtypes.ABCIPubKeyTypeSecp256k1}}, - }) - - res, err = handler(ctx, msgCreateValidator) - require.NoError(t, err) - require.NotNil(t, res) -} - -func TestLegacyValidatorDelegations(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, int64(1000)) - handler := NewHandler(keeper) - - bondAmount := sdk.TokensFromConsensusPower(10) - valAddr := sdk.ValAddress(Addrs[0]) - valConsPubKey, valConsAddr := PKs[0], sdk.ConsAddress(PKs[0].Address()) - delAddr := Addrs[1] - - // create validator - msgCreateVal := NewTestMsgCreateValidator(valAddr, valConsPubKey, bondAmount) - res, err := handler(ctx, msgCreateVal) - require.NoError(t, err) - require.NotNil(t, res) - - // must end-block - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 1, len(updates)) - - // verify the validator exists and has the correct attributes - validator, found := keeper.GetValidator(ctx, valAddr) - require.True(t, found) - require.Equal(t, sdk.Bonded, validator.Status) - require.Equal(t, bondAmount, validator.DelegatorShares.RoundInt()) - require.Equal(t, bondAmount, validator.BondedTokens()) - - // delegate tokens to the validator - msgDelegate := NewTestMsgDelegate(delAddr, valAddr, bondAmount) - res, err = handler(ctx, msgDelegate) - require.NoError(t, err) - require.NotNil(t, res) - - // verify validator bonded shares - validator, found = keeper.GetValidator(ctx, valAddr) - require.True(t, found) - require.Equal(t, bondAmount.MulRaw(2), validator.DelegatorShares.RoundInt()) - require.Equal(t, bondAmount.MulRaw(2), validator.BondedTokens()) - - // unbond validator total self-delegations (which should jail the validator) - unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, bondAmount) - msgUndelegate := NewMsgUndelegate(sdk.AccAddress(valAddr), valAddr, unbondAmt) - - res, err = handler(ctx, msgUndelegate) - require.NoError(t, err) - require.NotNil(t, res) - - ts := &gogotypes.Timestamp{} - types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) - - finishTime, err := gogotypes.TimestampFromProto(ts) - require.NoError(t, err) - - ctx = ctx.WithBlockTime(finishTime) - EndBlocker(ctx, keeper) - - // verify the validator record still exists, is jailed, and has correct tokens - validator, found = keeper.GetValidator(ctx, valAddr) - require.True(t, found) - require.True(t, validator.Jailed) - require.Equal(t, bondAmount, validator.Tokens) - - // verify delegation still exists - bond, found := keeper.GetDelegation(ctx, delAddr, valAddr) - require.True(t, found) - require.Equal(t, bondAmount, bond.Shares.RoundInt()) - require.Equal(t, bondAmount, validator.DelegatorShares.RoundInt()) - - // verify the validator can still self-delegate - msgSelfDelegate := NewTestMsgDelegate(sdk.AccAddress(valAddr), valAddr, bondAmount) - res, err = handler(ctx, msgSelfDelegate) - require.NoError(t, err) - require.NotNil(t, res) - - // verify validator bonded shares - validator, found = keeper.GetValidator(ctx, valAddr) - require.True(t, found) - require.Equal(t, bondAmount.MulRaw(2), validator.DelegatorShares.RoundInt()) - require.Equal(t, bondAmount.MulRaw(2), validator.Tokens) - - // unjail the validator now that is has non-zero self-delegated shares - keeper.Unjail(ctx, valConsAddr) - - // verify the validator can now accept delegations - msgDelegate = NewTestMsgDelegate(delAddr, valAddr, bondAmount) - res, err = handler(ctx, msgDelegate) - require.NoError(t, err) - require.NotNil(t, res) - - // verify validator bonded shares - validator, found = keeper.GetValidator(ctx, valAddr) - require.True(t, found) - require.Equal(t, bondAmount.MulRaw(3), validator.DelegatorShares.RoundInt()) - require.Equal(t, bondAmount.MulRaw(3), validator.Tokens) - - // verify new delegation - bond, found = keeper.GetDelegation(ctx, delAddr, valAddr) - require.True(t, found) - require.Equal(t, bondAmount.MulRaw(2), bond.Shares.RoundInt()) - require.Equal(t, bondAmount.MulRaw(3), validator.DelegatorShares.RoundInt()) -} - -func TestIncrementsMsgDelegate(t *testing.T) { - initPower := int64(1000) - initBond := sdk.TokensFromConsensusPower(initPower) - ctx, _, bk, keeper, _ := CreateTestInput(t, false, initPower) - handler := NewHandler(keeper) - - params := keeper.GetParams(ctx) - - bondAmount := sdk.TokensFromConsensusPower(10) - validatorAddr, delegatorAddr := sdk.ValAddress(Addrs[0]), Addrs[1] - - // first create validator - msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], bondAmount) - res, err := handler(ctx, msgCreateValidator) - require.NoError(t, err) - require.NotNil(t, res) - - // apply TM updates - keeper.ApplyAndReturnValidatorSetUpdates(ctx) - - validator, found := keeper.GetValidator(ctx, validatorAddr) - require.True(t, found) - require.Equal(t, sdk.Bonded, validator.Status) - require.Equal(t, bondAmount, validator.DelegatorShares.RoundInt()) - require.Equal(t, bondAmount, validator.BondedTokens(), "validator: %v", validator) - - _, found = keeper.GetDelegation(ctx, delegatorAddr, validatorAddr) - require.False(t, found) - - bond, found := keeper.GetDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) - require.True(t, found) - require.Equal(t, bondAmount, bond.Shares.RoundInt()) - - bondedTokens := keeper.TotalBondedTokens(ctx) - require.Equal(t, bondAmount.Int64(), bondedTokens.Int64()) - - // just send the same msgbond multiple times - msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, bondAmount) - - for i := int64(0); i < 5; i++ { - ctx = ctx.WithBlockHeight(i) - - res, err := handler(ctx, msgDelegate) - require.NoError(t, err) - require.NotNil(t, res) - - //Check that the accounts and the bond account have the appropriate values - validator, found := keeper.GetValidator(ctx, validatorAddr) - require.True(t, found) - bond, found := keeper.GetDelegation(ctx, delegatorAddr, validatorAddr) - require.True(t, found) - - expBond := bondAmount.MulRaw(i + 1) - expDelegatorShares := bondAmount.MulRaw(i + 2) // (1 self delegation) - expDelegatorAcc := initBond.Sub(expBond) - - gotBond := bond.Shares.RoundInt() - gotDelegatorShares := validator.DelegatorShares.RoundInt() - gotDelegatorAcc := bk.GetBalance(ctx, delegatorAddr, params.BondDenom).Amount - - require.Equal(t, expBond, gotBond, - "i: %v\nexpBond: %v\ngotBond: %v\nvalidator: %v\nbond: %v\n", - i, expBond, gotBond, validator, bond) - require.Equal(t, expDelegatorShares, gotDelegatorShares, - "i: %v\nexpDelegatorShares: %v\ngotDelegatorShares: %v\nvalidator: %v\nbond: %v\n", - i, expDelegatorShares, gotDelegatorShares, validator, bond) - require.Equal(t, expDelegatorAcc, gotDelegatorAcc, - "i: %v\nexpDelegatorAcc: %v\ngotDelegatorAcc: %v\nvalidator: %v\nbond: %v\n", - i, expDelegatorAcc, gotDelegatorAcc, validator, bond) - } -} - -func TestEditValidatorDecreaseMinSelfDelegation(t *testing.T) { - validatorAddr := sdk.ValAddress(Addrs[0]) - - initPower := int64(100) - initBond := sdk.TokensFromConsensusPower(100) - ctx, _, _, keeper, _ := CreateTestInput(t, false, initPower) - handler := NewHandler(keeper) - - // create validator - msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], initBond) - msgCreateValidator.MinSelfDelegation = sdk.NewInt(2) - res, err := handler(ctx, msgCreateValidator) - require.NoError(t, err) - require.NotNil(t, res) - - // must end-block - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 1, len(updates)) - - // verify the self-delegation exists - bond, found := keeper.GetDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) - require.True(t, found) - gotBond := bond.Shares.RoundInt() - require.Equal(t, initBond, gotBond, - "initBond: %v\ngotBond: %v\nbond: %v\n", - initBond, gotBond, bond) - - newMinSelfDelegation := sdk.OneInt() - msgEditValidator := NewMsgEditValidator(validatorAddr, Description{}, nil, &newMinSelfDelegation) - res, err = handler(ctx, msgEditValidator) - require.Error(t, err) - require.Nil(t, res) -} - -func TestEditValidatorIncreaseMinSelfDelegationBeyondCurrentBond(t *testing.T) { - validatorAddr := sdk.ValAddress(Addrs[0]) - - initPower := int64(100) - initBond := sdk.TokensFromConsensusPower(100) - ctx, _, _, keeper, _ := CreateTestInput(t, false, initPower) - handler := NewHandler(keeper) - - // create validator - msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], initBond) - msgCreateValidator.MinSelfDelegation = sdk.NewInt(2) - res, err := handler(ctx, msgCreateValidator) - require.NoError(t, err) - require.NotNil(t, res) - - // must end-block - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 1, len(updates)) - - // verify the self-delegation exists - bond, found := keeper.GetDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) - require.True(t, found) - gotBond := bond.Shares.RoundInt() - require.Equal(t, initBond, gotBond, - "initBond: %v\ngotBond: %v\nbond: %v\n", - initBond, gotBond, bond) - - newMinSelfDelegation := initBond.Add(sdk.OneInt()) - msgEditValidator := NewMsgEditValidator(validatorAddr, Description{}, nil, &newMinSelfDelegation) - res, err = handler(ctx, msgEditValidator) - require.Error(t, err) - require.Nil(t, res) -} - -func TestIncrementsMsgUnbond(t *testing.T) { - initPower := int64(1000) - initBond := sdk.TokensFromConsensusPower(initPower) - ctx, _, bk, keeper, _ := CreateTestInput(t, false, initPower) - handler := NewHandler(keeper) - - params := keeper.GetParams(ctx) - denom := params.BondDenom - - // create validator, delegate - validatorAddr, delegatorAddr := sdk.ValAddress(Addrs[0]), Addrs[1] - - msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], initBond) - res, err := handler(ctx, msgCreateValidator) - require.NoError(t, err) - require.NotNil(t, res) - - // initial balance - amt1 := bk.GetBalance(ctx, delegatorAddr, denom).Amount - - msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, initBond) - res, err = handler(ctx, msgDelegate) - require.NoError(t, err) - require.NotNil(t, res) - - // balance should have been subtracted after delegation - amt2 := bk.GetBalance(ctx, delegatorAddr, denom).Amount - require.True(sdk.IntEq(t, amt1.Sub(initBond), amt2)) - - // apply TM updates - keeper.ApplyAndReturnValidatorSetUpdates(ctx) - - validator, found := keeper.GetValidator(ctx, validatorAddr) - require.True(t, found) - require.Equal(t, initBond.MulRaw(2), validator.DelegatorShares.RoundInt()) - require.Equal(t, initBond.MulRaw(2), validator.BondedTokens()) - - // just send the same msgUnbond multiple times - // TODO use decimals here - unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) - msgUndelegate := NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) - numUnbonds := int64(5) - - for i := int64(0); i < numUnbonds; i++ { - res, err := handler(ctx, msgUndelegate) - require.NoError(t, err) - require.NotNil(t, res) - - ts := &gogotypes.Timestamp{} - types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) - - finishTime, err := gogotypes.TimestampFromProto(ts) - require.NoError(t, err) - - ctx = ctx.WithBlockTime(finishTime) - EndBlocker(ctx, keeper) - - // check that the accounts and the bond account have the appropriate values - validator, found = keeper.GetValidator(ctx, validatorAddr) - require.True(t, found) - bond, found := keeper.GetDelegation(ctx, delegatorAddr, validatorAddr) - require.True(t, found) - - expBond := initBond.Sub(unbondAmt.Amount.Mul(sdk.NewInt(i + 1))) - expDelegatorShares := initBond.MulRaw(2).Sub(unbondAmt.Amount.Mul(sdk.NewInt(i + 1))) - expDelegatorAcc := initBond.Sub(expBond) - - gotBond := bond.Shares.RoundInt() - gotDelegatorShares := validator.DelegatorShares.RoundInt() - gotDelegatorAcc := bk.GetBalance(ctx, delegatorAddr, params.BondDenom).Amount - - require.Equal(t, expBond.Int64(), gotBond.Int64(), - "i: %v\nexpBond: %v\ngotBond: %v\nvalidator: %v\nbond: %v\n", - i, expBond, gotBond, validator, bond) - require.Equal(t, expDelegatorShares.Int64(), gotDelegatorShares.Int64(), - "i: %v\nexpDelegatorShares: %v\ngotDelegatorShares: %v\nvalidator: %v\nbond: %v\n", - i, expDelegatorShares, gotDelegatorShares, validator, bond) - require.Equal(t, expDelegatorAcc.Int64(), gotDelegatorAcc.Int64(), - "i: %v\nexpDelegatorAcc: %v\ngotDelegatorAcc: %v\nvalidator: %v\nbond: %v\n", - i, expDelegatorAcc, gotDelegatorAcc, validator, bond) - } - - // these are more than we have bonded now - errorCases := []sdk.Int{ - //1<<64 - 1, // more than int64 power - //1<<63 + 1, // more than int64 power - sdk.TokensFromConsensusPower(1<<63 - 1), - sdk.TokensFromConsensusPower(1 << 31), - initBond, - } - - for _, c := range errorCases { - unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, c) - msgUndelegate := NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) - res, err = handler(ctx, msgUndelegate) - require.Error(t, err) - require.Nil(t, res) - } - - leftBonded := initBond.Sub(unbondAmt.Amount.Mul(sdk.NewInt(numUnbonds))) - - // should be able to unbond remaining - unbondAmt = sdk.NewCoin(sdk.DefaultBondDenom, leftBonded) - msgUndelegate = NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) - res, err = handler(ctx, msgUndelegate) - require.NoError(t, err, "msgUnbond: %v\nshares: %s\nleftBonded: %s\n", msgUndelegate, unbondAmt, leftBonded) - require.NotNil(t, res, "msgUnbond: %v\nshares: %s\nleftBonded: %s\n", msgUndelegate, unbondAmt, leftBonded) -} - -func TestMultipleMsgCreateValidator(t *testing.T) { - initPower := int64(1000) - initTokens := sdk.TokensFromConsensusPower(initPower) - ctx, _, bk, keeper, _ := CreateTestInput(t, false, initPower) - handler := NewHandler(keeper) - - params := keeper.GetParams(ctx) - blockTime := time.Now().UTC() - ctx = ctx.WithBlockTime(blockTime) - - validatorAddrs := []sdk.ValAddress{ - sdk.ValAddress(Addrs[0]), - sdk.ValAddress(Addrs[1]), - sdk.ValAddress(Addrs[2]), - } - delegatorAddrs := []sdk.AccAddress{ - Addrs[0], - Addrs[1], - Addrs[2], - } - - // bond them all - for i, validatorAddr := range validatorAddrs { - valTokens := sdk.TokensFromConsensusPower(10) - msgCreateValidatorOnBehalfOf := NewTestMsgCreateValidator(validatorAddr, PKs[i], valTokens) - - res, err := handler(ctx, msgCreateValidatorOnBehalfOf) - require.NoError(t, err) - require.NotNil(t, res) - - // verify that the account is bonded - validators := keeper.GetValidators(ctx, 100) - require.Equal(t, (i + 1), len(validators)) - - val := validators[i] - balanceExpd := initTokens.Sub(valTokens) - balanceGot := bk.GetBalance(ctx, delegatorAddrs[i], params.BondDenom).Amount - - require.Equal(t, i+1, len(validators), "expected %d validators got %d, validators: %v", i+1, len(validators), validators) - require.Equal(t, valTokens, val.DelegatorShares.RoundInt(), "expected %d shares, got %d", 10, val.DelegatorShares) - require.Equal(t, balanceExpd, balanceGot, "expected account to have %d, got %d", balanceExpd, balanceGot) - } - - EndBlocker(ctx, keeper) - - // unbond them all by removing delegation - for i, validatorAddr := range validatorAddrs { - _, found := keeper.GetValidator(ctx, validatorAddr) - require.True(t, found) - - unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(10)) - msgUndelegate := NewMsgUndelegate(delegatorAddrs[i], validatorAddr, unbondAmt) // remove delegation - res, err := handler(ctx, msgUndelegate) - require.NoError(t, err) - require.NotNil(t, res) - - ts := &gogotypes.Timestamp{} - types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) - - _, err = gogotypes.TimestampFromProto(ts) - require.NoError(t, err) - - // adds validator into unbonding queue - EndBlocker(ctx, keeper) - - // removes validator from queue and set - EndBlocker(ctx.WithBlockTime(blockTime.Add(params.UnbondingTime)), keeper) - - // Check that the validator is deleted from state - validators := keeper.GetValidators(ctx, 100) - require.Equal(t, len(validatorAddrs)-(i+1), len(validators), - "expected %d validators got %d", len(validatorAddrs)-(i+1), len(validators)) - - _, found = keeper.GetValidator(ctx, validatorAddr) - require.False(t, found) - - gotBalance := bk.GetBalance(ctx, delegatorAddrs[i], params.BondDenom).Amount - require.Equal(t, initTokens, gotBalance, "expected account to have %d, got %d", initTokens, gotBalance) - } -} - -func TestMultipleMsgDelegate(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - handler := NewHandler(keeper) - validatorAddr, delegatorAddrs := sdk.ValAddress(Addrs[0]), Addrs[1:] - - // first make a validator - msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], sdk.NewInt(10)) - res, err := handler(ctx, msgCreateValidator) - require.NoError(t, err) - require.NotNil(t, res) - - // delegate multiple parties - for _, delegatorAddr := range delegatorAddrs { - msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, sdk.NewInt(10)) - res, err := handler(ctx, msgDelegate) - require.NoError(t, err) - require.NotNil(t, res) - - // check that the account is bonded - bond, found := keeper.GetDelegation(ctx, delegatorAddr, validatorAddr) - require.True(t, found) - require.NotNil(t, bond, "expected delegatee bond %d to exist", bond) - } - - // unbond them all - for _, delegatorAddr := range delegatorAddrs { - unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) - msgUndelegate := NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) - - res, err := handler(ctx, msgUndelegate) - require.NoError(t, err) - require.NotNil(t, res) - - ts := &gogotypes.Timestamp{} - types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) - - finishTime, err := gogotypes.TimestampFromProto(ts) - require.NoError(t, err) - - ctx = ctx.WithBlockTime(finishTime) - EndBlocker(ctx, keeper) - - // check that the account is unbonded - _, found := keeper.GetDelegation(ctx, delegatorAddr, validatorAddr) - require.False(t, found) - } -} - -func TestJailValidator(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - handler := NewHandler(keeper) - validatorAddr, delegatorAddr := sdk.ValAddress(Addrs[0]), Addrs[1] - - // create the validator - msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], sdk.NewInt(10)) - res, err := handler(ctx, msgCreateValidator) - require.NoError(t, err) - require.NotNil(t, res) - - // bond a delegator - msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, sdk.NewInt(10)) - res, err = handler(ctx, msgDelegate) - require.NoError(t, err) - require.NotNil(t, res) - - // unbond the validators bond portion - unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) - msgUndelegateValidator := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) - res, err = handler(ctx, msgUndelegateValidator) - require.NoError(t, err) - require.NotNil(t, res) - - ts := &gogotypes.Timestamp{} - types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) - - finishTime, err := gogotypes.TimestampFromProto(ts) - require.NoError(t, err) - - ctx = ctx.WithBlockTime(finishTime) - EndBlocker(ctx, keeper) - - validator, found := keeper.GetValidator(ctx, validatorAddr) - require.True(t, found) - require.True(t, validator.Jailed, "%v", validator) - - // test that the delegator can still withdraw their bonds - msgUndelegateDelegator := NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) - - res, err = handler(ctx, msgUndelegateDelegator) - require.NoError(t, err) - require.NotNil(t, res) - - ts = &gogotypes.Timestamp{} - types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) - - finishTime, err = gogotypes.TimestampFromProto(ts) - require.NoError(t, err) - - ctx = ctx.WithBlockTime(finishTime) - EndBlocker(ctx, keeper) - - // verify that the pubkey can now be reused - res, err = handler(ctx, msgCreateValidator) - require.NoError(t, err) - require.NotNil(t, res) -} - -func TestValidatorQueue(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - handler := NewHandler(keeper) - validatorAddr, delegatorAddr := sdk.ValAddress(Addrs[0]), Addrs[1] - - // set the unbonding time - params := keeper.GetParams(ctx) - params.UnbondingTime = 7 * time.Second - keeper.SetParams(ctx, params) - - // create the validator - valTokens := sdk.TokensFromConsensusPower(10) - msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], valTokens) - res, err := handler(ctx, msgCreateValidator) - require.NoError(t, err) - require.NotNil(t, res) - - // bond a delegator - delTokens := sdk.TokensFromConsensusPower(10) - msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, delTokens) - res, err = handler(ctx, msgDelegate) - require.NoError(t, err) - require.NotNil(t, res) - - EndBlocker(ctx, keeper) - - // unbond the all self-delegation to put validator in unbonding state - unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, delTokens) - msgUndelegateValidator := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) - res, err = handler(ctx, msgUndelegateValidator) - require.NoError(t, err) - require.NotNil(t, res) - - ts := &gogotypes.Timestamp{} - types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) - - finishTime, err := gogotypes.TimestampFromProto(ts) - require.NoError(t, err) - - ctx = ctx.WithBlockTime(finishTime) - EndBlocker(ctx, keeper) - - origHeader := ctx.BlockHeader() - - validator, found := keeper.GetValidator(ctx, validatorAddr) - require.True(t, found) - require.True(t, validator.IsUnbonding(), "%v", validator) - - // should still be unbonding at time 6 seconds later - ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 6)) - EndBlocker(ctx, keeper) - - validator, found = keeper.GetValidator(ctx, validatorAddr) - require.True(t, found) - require.True(t, validator.IsUnbonding(), "%v", validator) - - // should be in unbonded state at time 7 seconds later - ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 7)) - EndBlocker(ctx, keeper) - - validator, found = keeper.GetValidator(ctx, validatorAddr) - require.True(t, found) - require.True(t, validator.IsUnbonded(), "%v", validator) -} - -func TestUnbondingPeriod(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - handler := NewHandler(keeper) - validatorAddr := sdk.ValAddress(Addrs[0]) - - // set the unbonding time - params := keeper.GetParams(ctx) - params.UnbondingTime = 7 * time.Second - keeper.SetParams(ctx, params) - - // create the validator - valTokens := sdk.TokensFromConsensusPower(10) - msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], valTokens) - res, err := handler(ctx, msgCreateValidator) - require.NoError(t, err) - require.NotNil(t, res) - - EndBlocker(ctx, keeper) - - // begin unbonding - unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(10)) - msgUndelegate := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) - res, err = handler(ctx, msgUndelegate) - require.NoError(t, err) - require.NotNil(t, res) - - origHeader := ctx.BlockHeader() - - _, found := keeper.GetUnbondingDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) - require.True(t, found, "should not have unbonded") - - // cannot complete unbonding at same time - EndBlocker(ctx, keeper) - _, found = keeper.GetUnbondingDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) - require.True(t, found, "should not have unbonded") - - // cannot complete unbonding at time 6 seconds later - ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 6)) - EndBlocker(ctx, keeper) - _, found = keeper.GetUnbondingDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) - require.True(t, found, "should not have unbonded") - - // can complete unbonding at time 7 seconds later - ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 7)) - EndBlocker(ctx, keeper) - _, found = keeper.GetUnbondingDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) - require.False(t, found, "should have unbonded") -} - -func TestUnbondingFromUnbondingValidator(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - handler := NewHandler(keeper) - validatorAddr, delegatorAddr := sdk.ValAddress(Addrs[0]), Addrs[1] - - // create the validator - msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], sdk.NewInt(10)) - res, err := handler(ctx, msgCreateValidator) - require.NoError(t, err) - require.NotNil(t, res) - - // bond a delegator - msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, sdk.NewInt(10)) - res, err = handler(ctx, msgDelegate) - require.NoError(t, err) - require.NotNil(t, res) - - // unbond the validators bond portion - unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) - msgUndelegateValidator := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) - res, err = handler(ctx, msgUndelegateValidator) - require.NoError(t, err) - require.NotNil(t, res) - - // change the ctx to Block Time one second before the validator would have unbonded - ts := &gogotypes.Timestamp{} - types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) - - finishTime, err := gogotypes.TimestampFromProto(ts) - require.NoError(t, err) - - ctx = ctx.WithBlockTime(finishTime.Add(time.Second * -1)) - - // unbond the delegator from the validator - msgUndelegateDelegator := NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) - res, err = handler(ctx, msgUndelegateDelegator) - require.NoError(t, err) - require.NotNil(t, res) - - ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(keeper.UnbondingTime(ctx))) - - // Run the EndBlocker - EndBlocker(ctx, keeper) - - // Check to make sure that the unbonding delegation is no longer in state - // (meaning it was deleted in the above EndBlocker) - _, found := keeper.GetUnbondingDelegation(ctx, delegatorAddr, validatorAddr) - require.False(t, found, "should be removed from state") -} - -func TestRedelegationPeriod(t *testing.T) { - ctx, _, bk, keeper, _ := CreateTestInput(t, false, 1000) - handler := NewHandler(keeper) - validatorAddr, validatorAddr2 := sdk.ValAddress(Addrs[0]), sdk.ValAddress(Addrs[1]) - denom := keeper.GetParams(ctx).BondDenom - - // set the unbonding time - params := keeper.GetParams(ctx) - params.UnbondingTime = 7 * time.Second - keeper.SetParams(ctx, params) - - // create the validators - msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], sdk.NewInt(10)) - - // initial balance - amt1 := bk.GetBalance(ctx, sdk.AccAddress(validatorAddr), denom).Amount - - res, err := handler(ctx, msgCreateValidator) - require.NoError(t, err) - require.NotNil(t, res) - - // balance should have been subtracted after creation - amt2 := bk.GetBalance(ctx, sdk.AccAddress(validatorAddr), denom).Amount - require.Equal(t, amt1.Sub(sdk.NewInt(10)).Int64(), amt2.Int64(), "expected coins to be subtracted") - - msgCreateValidator = NewTestMsgCreateValidator(validatorAddr2, PKs[1], sdk.NewInt(10)) - res, err = handler(ctx, msgCreateValidator) - require.NoError(t, err) - require.NotNil(t, res) - - bal1 := bk.GetAllBalances(ctx, sdk.AccAddress(validatorAddr)) - - // begin redelegate - redAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) - msgBeginRedelegate := NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2, redAmt) - res, err = handler(ctx, msgBeginRedelegate) - require.NoError(t, err) - require.NotNil(t, res) - - // origin account should not lose tokens as with a regular delegation - bal2 := bk.GetAllBalances(ctx, sdk.AccAddress(validatorAddr)) - require.Equal(t, bal1, bal2) - - origHeader := ctx.BlockHeader() - - // cannot complete redelegation at same time - EndBlocker(ctx, keeper) - _, found := keeper.GetRedelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2) - require.True(t, found, "should not have unbonded") - - // cannot complete redelegation at time 6 seconds later - ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 6)) - EndBlocker(ctx, keeper) - _, found = keeper.GetRedelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2) - require.True(t, found, "should not have unbonded") - - // can complete redelegation at time 7 seconds later - ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 7)) - EndBlocker(ctx, keeper) - _, found = keeper.GetRedelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2) - require.False(t, found, "should have unbonded") -} - -func TestTransitiveRedelegation(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - handler := NewHandler(keeper) - - validatorAddr := sdk.ValAddress(Addrs[0]) - validatorAddr2 := sdk.ValAddress(Addrs[1]) - validatorAddr3 := sdk.ValAddress(Addrs[2]) - - blockTime := time.Now().UTC() - ctx = ctx.WithBlockTime(blockTime) - - // create the validators - msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], sdk.NewInt(10)) - res, err := handler(ctx, msgCreateValidator) - require.NoError(t, err) - require.NotNil(t, res) - - msgCreateValidator = NewTestMsgCreateValidator(validatorAddr2, PKs[1], sdk.NewInt(10)) - res, err = handler(ctx, msgCreateValidator) - require.NoError(t, err) - require.NotNil(t, res) - - msgCreateValidator = NewTestMsgCreateValidator(validatorAddr3, PKs[2], sdk.NewInt(10)) - res, err = handler(ctx, msgCreateValidator) - require.NoError(t, err) - require.NotNil(t, res) - - // begin redelegate - redAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) - msgBeginRedelegate := NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2, redAmt) - res, err = handler(ctx, msgBeginRedelegate) - require.NoError(t, err) - require.NotNil(t, res) - - // cannot redelegation to next validator while first delegation exists - msgBeginRedelegate = NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr2, validatorAddr3, redAmt) - res, err = handler(ctx, msgBeginRedelegate) - require.Error(t, err) - require.Nil(t, res) - - params := keeper.GetParams(ctx) - ctx = ctx.WithBlockTime(blockTime.Add(params.UnbondingTime)) - - // complete first redelegation - EndBlocker(ctx, keeper) - - // now should be able to redelegate from the second validator to the third - res, err = handler(ctx, msgBeginRedelegate) - require.NoError(t, err) - require.NotNil(t, res) -} - -func TestMultipleRedelegationAtSameTime(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - handler := NewHandler(keeper) - - valAddr := sdk.ValAddress(Addrs[0]) - valAddr2 := sdk.ValAddress(Addrs[1]) - - // set the unbonding time - params := keeper.GetParams(ctx) - params.UnbondingTime = 1 * time.Second - keeper.SetParams(ctx, params) - - // create the validators - valTokens := sdk.TokensFromConsensusPower(10) - msgCreateValidator := NewTestMsgCreateValidator(valAddr, PKs[0], valTokens) - res, err := handler(ctx, msgCreateValidator) - require.NoError(t, err) - require.NotNil(t, res) - - msgCreateValidator = NewTestMsgCreateValidator(valAddr2, PKs[1], valTokens) - res, err = handler(ctx, msgCreateValidator) - require.NoError(t, err) - require.NotNil(t, res) - - // end block to bond them - EndBlocker(ctx, keeper) - - // begin a redelegate - selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) - redAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens.QuoRaw(2)) - msgBeginRedelegate := NewMsgBeginRedelegate(selfDelAddr, valAddr, valAddr2, redAmt) - res, err = handler(ctx, msgBeginRedelegate) - require.NoError(t, err) - require.NotNil(t, res) - - // there should only be one entry in the redelegation object - rd, found := keeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) - require.True(t, found) - require.Len(t, rd.Entries, 1) - - // start a second redelegation at this same time as the first - res, err = handler(ctx, msgBeginRedelegate) - require.NoError(t, err) - require.NotNil(t, res) - - // now there should be two entries - rd, found = keeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) - require.True(t, found) - require.Len(t, rd.Entries, 2) - - // move forward in time, should complete both redelegations - ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(1 * time.Second)) - EndBlocker(ctx, keeper) - - rd, found = keeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) - require.False(t, found) -} - -func TestMultipleRedelegationAtUniqueTimes(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - handler := NewHandler(keeper) - - valAddr := sdk.ValAddress(Addrs[0]) - valAddr2 := sdk.ValAddress(Addrs[1]) - - // set the unbonding time - params := keeper.GetParams(ctx) - params.UnbondingTime = 10 * time.Second - keeper.SetParams(ctx, params) - - // create the validators - valTokens := sdk.TokensFromConsensusPower(10) - msgCreateValidator := NewTestMsgCreateValidator(valAddr, PKs[0], valTokens) - res, err := handler(ctx, msgCreateValidator) - require.NoError(t, err) - require.NotNil(t, res) - - msgCreateValidator = NewTestMsgCreateValidator(valAddr2, PKs[1], valTokens) - res, err = handler(ctx, msgCreateValidator) - require.NoError(t, err) - require.NotNil(t, res) - - // end block to bond them - EndBlocker(ctx, keeper) - - // begin a redelegate - selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) - redAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens.QuoRaw(2)) - msgBeginRedelegate := NewMsgBeginRedelegate(selfDelAddr, valAddr, valAddr2, redAmt) - res, err = handler(ctx, msgBeginRedelegate) - require.NoError(t, err) - require.NotNil(t, res) - - // move forward in time and start a second redelegation - ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) - res, err = handler(ctx, msgBeginRedelegate) - require.NoError(t, err) - require.NotNil(t, res) - - // now there should be two entries - rd, found := keeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) - require.True(t, found) - require.Len(t, rd.Entries, 2) - - // move forward in time, should complete the first redelegation, but not the second - ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) - EndBlocker(ctx, keeper) - rd, found = keeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) - require.True(t, found) - require.Len(t, rd.Entries, 1) - - // move forward in time, should complete the second redelegation - ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) - EndBlocker(ctx, keeper) - rd, found = keeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) - require.False(t, found) -} - -func TestMultipleUnbondingDelegationAtSameTime(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - handler := NewHandler(keeper) - - valAddr := sdk.ValAddress(Addrs[0]) - - // set the unbonding time - params := keeper.GetParams(ctx) - params.UnbondingTime = 1 * time.Second - keeper.SetParams(ctx, params) - - // create the validator - valTokens := sdk.TokensFromConsensusPower(10) - msgCreateValidator := NewTestMsgCreateValidator(valAddr, PKs[0], valTokens) - res, err := handler(ctx, msgCreateValidator) - require.NoError(t, err) - require.NotNil(t, res) - - // end block to bond - EndBlocker(ctx, keeper) - - // begin an unbonding delegation - selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) - unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens.QuoRaw(2)) - msgUndelegate := NewMsgUndelegate(selfDelAddr, valAddr, unbondAmt) - res, err = handler(ctx, msgUndelegate) - require.NoError(t, err) - require.NotNil(t, res) - - // there should only be one entry in the ubd object - ubd, found := keeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) - require.True(t, found) - require.Len(t, ubd.Entries, 1) - - // start a second ubd at this same time as the first - res, err = handler(ctx, msgUndelegate) - require.NoError(t, err) - require.NotNil(t, res) - - // now there should be two entries - ubd, found = keeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) - require.True(t, found) - require.Len(t, ubd.Entries, 2) - - // move forwaubd in time, should complete both ubds - ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(1 * time.Second)) - EndBlocker(ctx, keeper) - - ubd, found = keeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) - require.False(t, found) -} - -func TestMultipleUnbondingDelegationAtUniqueTimes(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - handler := NewHandler(keeper) - valAddr := sdk.ValAddress(Addrs[0]) - - // set the unbonding time - params := keeper.GetParams(ctx) - params.UnbondingTime = 10 * time.Second - keeper.SetParams(ctx, params) - - // create the validator - valTokens := sdk.TokensFromConsensusPower(10) - msgCreateValidator := NewTestMsgCreateValidator(valAddr, PKs[0], valTokens) - res, err := handler(ctx, msgCreateValidator) - require.NoError(t, err) - require.NotNil(t, res) - - // end block to bond - EndBlocker(ctx, keeper) - - // begin an unbonding delegation - selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) - unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens.QuoRaw(2)) - msgUndelegate := NewMsgUndelegate(selfDelAddr, valAddr, unbondAmt) - res, err = handler(ctx, msgUndelegate) - require.NoError(t, err) - require.NotNil(t, res) - - // there should only be one entry in the ubd object - ubd, found := keeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) - require.True(t, found) - require.Len(t, ubd.Entries, 1) - - // move forwaubd in time and start a second redelegation - ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) - res, err = handler(ctx, msgUndelegate) - require.NoError(t, err) - require.NotNil(t, res) - - // now there should be two entries - ubd, found = keeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) - require.True(t, found) - require.Len(t, ubd.Entries, 2) - - // move forwaubd in time, should complete the first redelegation, but not the second - ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) - EndBlocker(ctx, keeper) - ubd, found = keeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) - require.True(t, found) - require.Len(t, ubd.Entries, 1) - - // move forwaubd in time, should complete the second redelegation - ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) - EndBlocker(ctx, keeper) - ubd, found = keeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) - require.False(t, found) -} - -func TestUnbondingWhenExcessValidators(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - handler := NewHandler(keeper) - - validatorAddr1 := sdk.ValAddress(Addrs[0]) - validatorAddr2 := sdk.ValAddress(Addrs[1]) - validatorAddr3 := sdk.ValAddress(Addrs[2]) - - // set the unbonding time - params := keeper.GetParams(ctx) - params.MaxValidators = 2 - keeper.SetParams(ctx, params) - - // add three validators - valTokens1 := sdk.TokensFromConsensusPower(50) - msgCreateValidator := NewTestMsgCreateValidator(validatorAddr1, PKs[0], valTokens1) - res, err := handler(ctx, msgCreateValidator) - require.NoError(t, err) - require.NotNil(t, res) - - // apply TM updates - keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 1, len(keeper.GetLastValidators(ctx))) - - valTokens2 := sdk.TokensFromConsensusPower(30) - msgCreateValidator = NewTestMsgCreateValidator(validatorAddr2, PKs[1], valTokens2) - res, err = handler(ctx, msgCreateValidator) - require.NoError(t, err) - require.NotNil(t, res) - - // apply TM updates - keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 2, len(keeper.GetLastValidators(ctx))) - - valTokens3 := sdk.TokensFromConsensusPower(10) - msgCreateValidator = NewTestMsgCreateValidator(validatorAddr3, PKs[2], valTokens3) - res, err = handler(ctx, msgCreateValidator) - require.NoError(t, err) - require.NotNil(t, res) - - // apply TM updates - keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 2, len(keeper.GetLastValidators(ctx))) - - // unbond the validator-2 - unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens2) - msgUndelegate := NewMsgUndelegate(sdk.AccAddress(validatorAddr2), validatorAddr2, unbondAmt) - res, err = handler(ctx, msgUndelegate) - require.NoError(t, err) - require.NotNil(t, res) - - // apply TM updates - keeper.ApplyAndReturnValidatorSetUpdates(ctx) - - // because there are extra validators waiting to get in, the queued - // validator (aka. validator-1) should make it into the bonded group, thus - // the total number of validators should stay the same - vals := keeper.GetLastValidators(ctx) - require.Equal(t, 2, len(vals), "vals %v", vals) - val1, found := keeper.GetValidator(ctx, validatorAddr1) - require.True(t, found) - require.Equal(t, sdk.Bonded, val1.Status, "%v", val1) -} - -func TestBondUnbondRedelegateSlashTwice(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - handler := NewHandler(keeper) - - valA, valB, del := sdk.ValAddress(Addrs[0]), sdk.ValAddress(Addrs[1]), Addrs[2] - consAddr0 := sdk.ConsAddress(PKs[0].Address()) - - valTokens := sdk.TokensFromConsensusPower(10) - msgCreateValidator := NewTestMsgCreateValidator(valA, PKs[0], valTokens) - res, err := handler(ctx, msgCreateValidator) - require.NoError(t, err) - require.NotNil(t, res) - - msgCreateValidator = NewTestMsgCreateValidator(valB, PKs[1], valTokens) - res, err = handler(ctx, msgCreateValidator) - require.NoError(t, err) - require.NotNil(t, res) - - // delegate 10 stake - msgDelegate := NewTestMsgDelegate(del, valA, valTokens) - res, err = handler(ctx, msgDelegate) - require.NoError(t, err) - require.NotNil(t, res) - - // apply Tendermint updates - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 2, len(updates)) - - // a block passes - ctx = ctx.WithBlockHeight(1) - - // begin unbonding 4 stake - unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(4)) - msgUndelegate := NewMsgUndelegate(del, valA, unbondAmt) - res, err = handler(ctx, msgUndelegate) - require.NoError(t, err) - require.NotNil(t, res) - - // begin redelegate 6 stake - redAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(6)) - msgBeginRedelegate := NewMsgBeginRedelegate(del, valA, valB, redAmt) - res, err = handler(ctx, msgBeginRedelegate) - require.NoError(t, err) - require.NotNil(t, res) - - // destination delegation should have 6 shares - delegation, found := keeper.GetDelegation(ctx, del, valB) - require.True(t, found) - require.Equal(t, sdk.NewDecFromInt(redAmt.Amount), delegation.Shares) - - // must apply validator updates - updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 2, len(updates)) - - // slash the validator by half - keeper.Slash(ctx, consAddr0, 0, 20, sdk.NewDecWithPrec(5, 1)) - - // unbonding delegation should have been slashed by half - ubd, found := keeper.GetUnbondingDelegation(ctx, del, valA) - require.True(t, found) - require.Len(t, ubd.Entries, 1) - require.Equal(t, unbondAmt.Amount.QuoRaw(2), ubd.Entries[0].Balance) - - // redelegation should have been slashed by half - redelegation, found := keeper.GetRedelegation(ctx, del, valA, valB) - require.True(t, found) - require.Len(t, redelegation.Entries, 1) - - // destination delegation should have been slashed by half - delegation, found = keeper.GetDelegation(ctx, del, valB) - require.True(t, found) - require.Equal(t, sdk.NewDecFromInt(redAmt.Amount.QuoRaw(2)), delegation.Shares) - - // validator power should have been reduced by half - validator, found := keeper.GetValidator(ctx, valA) - require.True(t, found) - require.Equal(t, valTokens.QuoRaw(2), validator.GetBondedTokens()) - - // slash the validator for an infraction committed after the unbonding and redelegation begin - ctx = ctx.WithBlockHeight(3) - keeper.Slash(ctx, consAddr0, 2, 10, sdk.NewDecWithPrec(5, 1)) - - // unbonding delegation should be unchanged - ubd, found = keeper.GetUnbondingDelegation(ctx, del, valA) - require.True(t, found) - require.Len(t, ubd.Entries, 1) - require.Equal(t, unbondAmt.Amount.QuoRaw(2), ubd.Entries[0].Balance) - - // redelegation should be unchanged - redelegation, found = keeper.GetRedelegation(ctx, del, valA, valB) - require.True(t, found) - require.Len(t, redelegation.Entries, 1) - - // destination delegation should be unchanged - delegation, found = keeper.GetDelegation(ctx, del, valB) - require.True(t, found) - require.Equal(t, sdk.NewDecFromInt(redAmt.Amount.QuoRaw(2)), delegation.Shares) - - // end blocker - EndBlocker(ctx, keeper) - - // validator power should have been reduced to zero - // validator should be in unbonding state - validator, _ = keeper.GetValidator(ctx, valA) - require.Equal(t, validator.GetStatus(), sdk.Unbonding) -} - -func TestInvalidMsg(t *testing.T) { - k := Keeper{} - h := NewHandler(k) - - res, err := h(sdk.NewContext(nil, abci.Header{}, false, nil), sdk.NewTestMsg()) - require.Error(t, err) - require.Nil(t, res) - require.True(t, strings.Contains(err.Error(), "unrecognized staking message type")) -} - -func TestInvalidCoinDenom(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - handler := NewHandler(keeper) - - valA, valB, delAddr := sdk.ValAddress(Addrs[0]), sdk.ValAddress(Addrs[1]), Addrs[2] - - valTokens := sdk.TokensFromConsensusPower(100) - invalidCoin := sdk.NewCoin("churros", valTokens) - validCoin := sdk.NewCoin(sdk.DefaultBondDenom, valTokens) - oneCoin := sdk.NewCoin(sdk.DefaultBondDenom, sdk.OneInt()) - - commission := types.NewCommissionRates(sdk.OneDec(), sdk.OneDec(), sdk.ZeroDec()) - - msgCreate := types.NewMsgCreateValidator(valA, PKs[0], invalidCoin, Description{}, commission, sdk.OneInt()) - res, err := handler(ctx, msgCreate) - require.Error(t, err) - require.Nil(t, res) - - msgCreate = types.NewMsgCreateValidator(valA, PKs[0], validCoin, Description{}, commission, sdk.OneInt()) - res, err = handler(ctx, msgCreate) - require.NoError(t, err) - require.NotNil(t, res) - - msgCreate = types.NewMsgCreateValidator(valB, PKs[1], validCoin, Description{}, commission, sdk.OneInt()) - res, err = handler(ctx, msgCreate) - require.NoError(t, err) - require.NotNil(t, res) - - msgDelegate := types.NewMsgDelegate(delAddr, valA, invalidCoin) - res, err = handler(ctx, msgDelegate) - require.Error(t, err) - require.Nil(t, res) - - msgDelegate = types.NewMsgDelegate(delAddr, valA, validCoin) - res, err = handler(ctx, msgDelegate) - require.NoError(t, err) - require.NotNil(t, res) - - msgUndelegate := types.NewMsgUndelegate(delAddr, valA, invalidCoin) - res, err = handler(ctx, msgUndelegate) - require.Error(t, err) - require.Nil(t, res) - - msgUndelegate = types.NewMsgUndelegate(delAddr, valA, oneCoin) - res, err = handler(ctx, msgUndelegate) - require.NoError(t, err) - require.NotNil(t, res) - - msgRedelegate := types.NewMsgBeginRedelegate(delAddr, valA, valB, invalidCoin) - res, err = handler(ctx, msgRedelegate) - require.Error(t, err) - require.Nil(t, res) - - msgRedelegate = types.NewMsgBeginRedelegate(delAddr, valA, valB, oneCoin) - res, err = handler(ctx, msgRedelegate) - require.NoError(t, err) - require.NotNil(t, res) -} +//func TestValidatorByPowerIndex(t *testing.T) { +// validatorAddr, validatorAddr3 := sdk.ValAddress(Addrs[0]), sdk.ValAddress(Addrs[1]) +// +// initPower := int64(1000000) +// initBond := sdk.TokensFromConsensusPower(initPower) +// ctx, _, _, keeper, _ := CreateTestInput(t, false, initPower) +// handler := NewHandler(keeper) +// +// // create validator +// msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], initBond) +// res, err := handler(ctx, msgCreateValidator) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // must end-block +// updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) +// require.Equal(t, 1, len(updates)) +// +// // verify the self-delegation exists +// bond, found := keeper.GetDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) +// require.True(t, found) +// gotBond := bond.Shares.RoundInt() +// require.Equal(t, initBond, gotBond) +// +// // verify that the by power index exists +// validator, found := keeper.GetValidator(ctx, validatorAddr) +// require.True(t, found) +// power := GetValidatorsByPowerIndexKey(validator) +// require.True(t, keep.ValidatorByPowerIndexExists(ctx, keeper, power)) +// +// // create a second validator keep it bonded +// msgCreateValidator = NewTestMsgCreateValidator(validatorAddr3, PKs[2], initBond) +// res, err = handler(ctx, msgCreateValidator) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // must end-block +// updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx) +// require.Equal(t, 1, len(updates)) +// +// // slash and jail the first validator +// consAddr0 := sdk.ConsAddress(PKs[0].Address()) +// keeper.Slash(ctx, consAddr0, 0, initPower, sdk.NewDecWithPrec(5, 1)) +// keeper.Jail(ctx, consAddr0) +// keeper.ApplyAndReturnValidatorSetUpdates(ctx) +// +// validator, found = keeper.GetValidator(ctx, validatorAddr) +// require.True(t, found) +// require.Equal(t, sdk.Unbonding, validator.Status) // ensure is unbonding +// require.Equal(t, initBond.QuoRaw(2), validator.Tokens) // ensure tokens slashed +// keeper.Unjail(ctx, consAddr0) +// +// // the old power record should have been deleted as the power changed +// require.False(t, keep.ValidatorByPowerIndexExists(ctx, keeper, power)) +// +// // but the new power record should have been created +// validator, found = keeper.GetValidator(ctx, validatorAddr) +// require.True(t, found) +// power2 := GetValidatorsByPowerIndexKey(validator) +// require.True(t, keep.ValidatorByPowerIndexExists(ctx, keeper, power2)) +// +// // now the new record power index should be the same as the original record +// power3 := GetValidatorsByPowerIndexKey(validator) +// require.Equal(t, power2, power3) +// +// // unbond self-delegation +// totalBond := validator.TokensFromShares(bond.GetShares()).TruncateInt() +// unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, totalBond) +// msgUndelegate := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) +// +// res, err = handler(ctx, msgUndelegate) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// ts := &gogotypes.Timestamp{} +// types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) +// +// finishTime, err := gogotypes.TimestampFromProto(ts) +// require.NoError(t, err) +// +// ctx = ctx.WithBlockTime(finishTime) +// EndBlocker(ctx, keeper) +// EndBlocker(ctx, keeper) +// +// // verify that by power key nolonger exists +// _, found = keeper.GetValidator(ctx, validatorAddr) +// require.False(t, found) +// require.False(t, keep.ValidatorByPowerIndexExists(ctx, keeper, power3)) +//} +// +//func TestDuplicatesMsgCreateValidator(t *testing.T) { +// ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) +// handler := NewHandler(keeper) +// +// addr1, addr2 := sdk.ValAddress(Addrs[0]), sdk.ValAddress(Addrs[1]) +// pk1, pk2 := PKs[0], PKs[1] +// +// valTokens := sdk.TokensFromConsensusPower(10) +// msgCreateValidator1 := NewTestMsgCreateValidator(addr1, pk1, valTokens) +// res, err := handler(ctx, msgCreateValidator1) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// keeper.ApplyAndReturnValidatorSetUpdates(ctx) +// +// validator, found := keeper.GetValidator(ctx, addr1) +// require.True(t, found) +// assert.Equal(t, sdk.Bonded, validator.Status) +// assert.Equal(t, addr1, validator.OperatorAddress) +// assert.Equal(t, pk1, validator.GetConsPubKey()) +// assert.Equal(t, valTokens, validator.BondedTokens()) +// assert.Equal(t, valTokens.ToDec(), validator.DelegatorShares) +// assert.Equal(t, Description{}, validator.Description) +// +// // two validators can't have the same operator address +// msgCreateValidator2 := NewTestMsgCreateValidator(addr1, pk2, valTokens) +// res, err = handler(ctx, msgCreateValidator2) +// require.Error(t, err) +// require.Nil(t, res) +// +// // two validators can't have the same pubkey +// msgCreateValidator3 := NewTestMsgCreateValidator(addr2, pk1, valTokens) +// res, err = handler(ctx, msgCreateValidator3) +// require.Error(t, err) +// require.Nil(t, res) +// +// // must have different pubkey and operator +// msgCreateValidator4 := NewTestMsgCreateValidator(addr2, pk2, valTokens) +// res, err = handler(ctx, msgCreateValidator4) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // must end-block +// updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) +// require.Equal(t, 1, len(updates)) +// +// validator, found = keeper.GetValidator(ctx, addr2) +// +// require.True(t, found) +// assert.Equal(t, sdk.Bonded, validator.Status) +// assert.Equal(t, addr2, validator.OperatorAddress) +// assert.Equal(t, pk2, validator.GetConsPubKey()) +// assert.True(sdk.IntEq(t, valTokens, validator.Tokens)) +// assert.True(sdk.DecEq(t, valTokens.ToDec(), validator.DelegatorShares)) +// assert.Equal(t, Description{}, validator.Description) +//} +// +//func TestInvalidPubKeyTypeMsgCreateValidator(t *testing.T) { +// ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) +// handler := NewHandler(keeper) +// +// addr := sdk.ValAddress(Addrs[0]) +// invalidPk := secp256k1.GenPrivKey().PubKey() +// +// // invalid pukKey type should not be allowed +// msgCreateValidator := NewTestMsgCreateValidator(addr, invalidPk, sdk.NewInt(10)) +// res, err := handler(ctx, msgCreateValidator) +// require.Error(t, err) +// require.Nil(t, res) +// +// ctx = ctx.WithConsensusParams(&abci.ConsensusParams{ +// Validator: &abci.ValidatorParams{PubKeyTypes: []string{tmtypes.ABCIPubKeyTypeSecp256k1}}, +// }) +// +// res, err = handler(ctx, msgCreateValidator) +// require.NoError(t, err) +// require.NotNil(t, res) +//} +// +//func TestLegacyValidatorDelegations(t *testing.T) { +// ctx, _, _, keeper, _ := CreateTestInput(t, false, int64(1000)) +// handler := NewHandler(keeper) +// +// bondAmount := sdk.TokensFromConsensusPower(10) +// valAddr := sdk.ValAddress(Addrs[0]) +// valConsPubKey, valConsAddr := PKs[0], sdk.ConsAddress(PKs[0].Address()) +// delAddr := Addrs[1] +// +// // create validator +// msgCreateVal := NewTestMsgCreateValidator(valAddr, valConsPubKey, bondAmount) +// res, err := handler(ctx, msgCreateVal) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // must end-block +// updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) +// require.Equal(t, 1, len(updates)) +// +// // verify the validator exists and has the correct attributes +// validator, found := keeper.GetValidator(ctx, valAddr) +// require.True(t, found) +// require.Equal(t, sdk.Bonded, validator.Status) +// require.Equal(t, bondAmount, validator.DelegatorShares.RoundInt()) +// require.Equal(t, bondAmount, validator.BondedTokens()) +// +// // delegate tokens to the validator +// msgDelegate := NewTestMsgDelegate(delAddr, valAddr, bondAmount) +// res, err = handler(ctx, msgDelegate) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // verify validator bonded shares +// validator, found = keeper.GetValidator(ctx, valAddr) +// require.True(t, found) +// require.Equal(t, bondAmount.MulRaw(2), validator.DelegatorShares.RoundInt()) +// require.Equal(t, bondAmount.MulRaw(2), validator.BondedTokens()) +// +// // unbond validator total self-delegations (which should jail the validator) +// unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, bondAmount) +// msgUndelegate := NewMsgUndelegate(sdk.AccAddress(valAddr), valAddr, unbondAmt) +// +// res, err = handler(ctx, msgUndelegate) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// ts := &gogotypes.Timestamp{} +// types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) +// +// finishTime, err := gogotypes.TimestampFromProto(ts) +// require.NoError(t, err) +// +// ctx = ctx.WithBlockTime(finishTime) +// EndBlocker(ctx, keeper) +// +// // verify the validator record still exists, is jailed, and has correct tokens +// validator, found = keeper.GetValidator(ctx, valAddr) +// require.True(t, found) +// require.True(t, validator.Jailed) +// require.Equal(t, bondAmount, validator.Tokens) +// +// // verify delegation still exists +// bond, found := keeper.GetDelegation(ctx, delAddr, valAddr) +// require.True(t, found) +// require.Equal(t, bondAmount, bond.Shares.RoundInt()) +// require.Equal(t, bondAmount, validator.DelegatorShares.RoundInt()) +// +// // verify the validator can still self-delegate +// msgSelfDelegate := NewTestMsgDelegate(sdk.AccAddress(valAddr), valAddr, bondAmount) +// res, err = handler(ctx, msgSelfDelegate) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // verify validator bonded shares +// validator, found = keeper.GetValidator(ctx, valAddr) +// require.True(t, found) +// require.Equal(t, bondAmount.MulRaw(2), validator.DelegatorShares.RoundInt()) +// require.Equal(t, bondAmount.MulRaw(2), validator.Tokens) +// +// // unjail the validator now that is has non-zero self-delegated shares +// keeper.Unjail(ctx, valConsAddr) +// +// // verify the validator can now accept delegations +// msgDelegate = NewTestMsgDelegate(delAddr, valAddr, bondAmount) +// res, err = handler(ctx, msgDelegate) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // verify validator bonded shares +// validator, found = keeper.GetValidator(ctx, valAddr) +// require.True(t, found) +// require.Equal(t, bondAmount.MulRaw(3), validator.DelegatorShares.RoundInt()) +// require.Equal(t, bondAmount.MulRaw(3), validator.Tokens) +// +// // verify new delegation +// bond, found = keeper.GetDelegation(ctx, delAddr, valAddr) +// require.True(t, found) +// require.Equal(t, bondAmount.MulRaw(2), bond.Shares.RoundInt()) +// require.Equal(t, bondAmount.MulRaw(3), validator.DelegatorShares.RoundInt()) +//} +// +//func TestIncrementsMsgDelegate(t *testing.T) { +// initPower := int64(1000) +// initBond := sdk.TokensFromConsensusPower(initPower) +// ctx, _, bk, keeper, _ := CreateTestInput(t, false, initPower) +// handler := NewHandler(keeper) +// +// params := keeper.GetParams(ctx) +// +// bondAmount := sdk.TokensFromConsensusPower(10) +// validatorAddr, delegatorAddr := sdk.ValAddress(Addrs[0]), Addrs[1] +// +// // first create validator +// msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], bondAmount) +// res, err := handler(ctx, msgCreateValidator) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // apply TM updates +// keeper.ApplyAndReturnValidatorSetUpdates(ctx) +// +// validator, found := keeper.GetValidator(ctx, validatorAddr) +// require.True(t, found) +// require.Equal(t, sdk.Bonded, validator.Status) +// require.Equal(t, bondAmount, validator.DelegatorShares.RoundInt()) +// require.Equal(t, bondAmount, validator.BondedTokens(), "validator: %v", validator) +// +// _, found = keeper.GetDelegation(ctx, delegatorAddr, validatorAddr) +// require.False(t, found) +// +// bond, found := keeper.GetDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) +// require.True(t, found) +// require.Equal(t, bondAmount, bond.Shares.RoundInt()) +// +// bondedTokens := keeper.TotalBondedTokens(ctx) +// require.Equal(t, bondAmount.Int64(), bondedTokens.Int64()) +// +// // just send the same msgbond multiple times +// msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, bondAmount) +// +// for i := int64(0); i < 5; i++ { +// ctx = ctx.WithBlockHeight(i) +// +// res, err := handler(ctx, msgDelegate) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// //Check that the accounts and the bond account have the appropriate values +// validator, found := keeper.GetValidator(ctx, validatorAddr) +// require.True(t, found) +// bond, found := keeper.GetDelegation(ctx, delegatorAddr, validatorAddr) +// require.True(t, found) +// +// expBond := bondAmount.MulRaw(i + 1) +// expDelegatorShares := bondAmount.MulRaw(i + 2) // (1 self delegation) +// expDelegatorAcc := initBond.Sub(expBond) +// +// gotBond := bond.Shares.RoundInt() +// gotDelegatorShares := validator.DelegatorShares.RoundInt() +// gotDelegatorAcc := bk.GetBalance(ctx, delegatorAddr, params.BondDenom).Amount +// +// require.Equal(t, expBond, gotBond, +// "i: %v\nexpBond: %v\ngotBond: %v\nvalidator: %v\nbond: %v\n", +// i, expBond, gotBond, validator, bond) +// require.Equal(t, expDelegatorShares, gotDelegatorShares, +// "i: %v\nexpDelegatorShares: %v\ngotDelegatorShares: %v\nvalidator: %v\nbond: %v\n", +// i, expDelegatorShares, gotDelegatorShares, validator, bond) +// require.Equal(t, expDelegatorAcc, gotDelegatorAcc, +// "i: %v\nexpDelegatorAcc: %v\ngotDelegatorAcc: %v\nvalidator: %v\nbond: %v\n", +// i, expDelegatorAcc, gotDelegatorAcc, validator, bond) +// } +//} +// +//func TestEditValidatorDecreaseMinSelfDelegation(t *testing.T) { +// validatorAddr := sdk.ValAddress(Addrs[0]) +// +// initPower := int64(100) +// initBond := sdk.TokensFromConsensusPower(100) +// ctx, _, _, keeper, _ := CreateTestInput(t, false, initPower) +// handler := NewHandler(keeper) +// +// // create validator +// msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], initBond) +// msgCreateValidator.MinSelfDelegation = sdk.NewInt(2) +// res, err := handler(ctx, msgCreateValidator) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // must end-block +// updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) +// require.Equal(t, 1, len(updates)) +// +// // verify the self-delegation exists +// bond, found := keeper.GetDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) +// require.True(t, found) +// gotBond := bond.Shares.RoundInt() +// require.Equal(t, initBond, gotBond, +// "initBond: %v\ngotBond: %v\nbond: %v\n", +// initBond, gotBond, bond) +// +// newMinSelfDelegation := sdk.OneInt() +// msgEditValidator := NewMsgEditValidator(validatorAddr, Description{}, nil, &newMinSelfDelegation) +// res, err = handler(ctx, msgEditValidator) +// require.Error(t, err) +// require.Nil(t, res) +//} +// +//func TestEditValidatorIncreaseMinSelfDelegationBeyondCurrentBond(t *testing.T) { +// validatorAddr := sdk.ValAddress(Addrs[0]) +// +// initPower := int64(100) +// initBond := sdk.TokensFromConsensusPower(100) +// ctx, _, _, keeper, _ := CreateTestInput(t, false, initPower) +// handler := NewHandler(keeper) +// +// // create validator +// msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], initBond) +// msgCreateValidator.MinSelfDelegation = sdk.NewInt(2) +// res, err := handler(ctx, msgCreateValidator) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // must end-block +// updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) +// require.Equal(t, 1, len(updates)) +// +// // verify the self-delegation exists +// bond, found := keeper.GetDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) +// require.True(t, found) +// gotBond := bond.Shares.RoundInt() +// require.Equal(t, initBond, gotBond, +// "initBond: %v\ngotBond: %v\nbond: %v\n", +// initBond, gotBond, bond) +// +// newMinSelfDelegation := initBond.Add(sdk.OneInt()) +// msgEditValidator := NewMsgEditValidator(validatorAddr, Description{}, nil, &newMinSelfDelegation) +// res, err = handler(ctx, msgEditValidator) +// require.Error(t, err) +// require.Nil(t, res) +//} +// +//func TestIncrementsMsgUnbond(t *testing.T) { +// initPower := int64(1000) +// initBond := sdk.TokensFromConsensusPower(initPower) +// ctx, _, bk, keeper, _ := CreateTestInput(t, false, initPower) +// handler := NewHandler(keeper) +// +// params := keeper.GetParams(ctx) +// denom := params.BondDenom +// +// // create validator, delegate +// validatorAddr, delegatorAddr := sdk.ValAddress(Addrs[0]), Addrs[1] +// +// msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], initBond) +// res, err := handler(ctx, msgCreateValidator) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // initial balance +// amt1 := bk.GetBalance(ctx, delegatorAddr, denom).Amount +// +// msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, initBond) +// res, err = handler(ctx, msgDelegate) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // balance should have been subtracted after delegation +// amt2 := bk.GetBalance(ctx, delegatorAddr, denom).Amount +// require.True(sdk.IntEq(t, amt1.Sub(initBond), amt2)) +// +// // apply TM updates +// keeper.ApplyAndReturnValidatorSetUpdates(ctx) +// +// validator, found := keeper.GetValidator(ctx, validatorAddr) +// require.True(t, found) +// require.Equal(t, initBond.MulRaw(2), validator.DelegatorShares.RoundInt()) +// require.Equal(t, initBond.MulRaw(2), validator.BondedTokens()) +// +// // just send the same msgUnbond multiple times +// // TODO use decimals here +// unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) +// msgUndelegate := NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) +// numUnbonds := int64(5) +// +// for i := int64(0); i < numUnbonds; i++ { +// res, err := handler(ctx, msgUndelegate) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// ts := &gogotypes.Timestamp{} +// types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) +// +// finishTime, err := gogotypes.TimestampFromProto(ts) +// require.NoError(t, err) +// +// ctx = ctx.WithBlockTime(finishTime) +// EndBlocker(ctx, keeper) +// +// // check that the accounts and the bond account have the appropriate values +// validator, found = keeper.GetValidator(ctx, validatorAddr) +// require.True(t, found) +// bond, found := keeper.GetDelegation(ctx, delegatorAddr, validatorAddr) +// require.True(t, found) +// +// expBond := initBond.Sub(unbondAmt.Amount.Mul(sdk.NewInt(i + 1))) +// expDelegatorShares := initBond.MulRaw(2).Sub(unbondAmt.Amount.Mul(sdk.NewInt(i + 1))) +// expDelegatorAcc := initBond.Sub(expBond) +// +// gotBond := bond.Shares.RoundInt() +// gotDelegatorShares := validator.DelegatorShares.RoundInt() +// gotDelegatorAcc := bk.GetBalance(ctx, delegatorAddr, params.BondDenom).Amount +// +// require.Equal(t, expBond.Int64(), gotBond.Int64(), +// "i: %v\nexpBond: %v\ngotBond: %v\nvalidator: %v\nbond: %v\n", +// i, expBond, gotBond, validator, bond) +// require.Equal(t, expDelegatorShares.Int64(), gotDelegatorShares.Int64(), +// "i: %v\nexpDelegatorShares: %v\ngotDelegatorShares: %v\nvalidator: %v\nbond: %v\n", +// i, expDelegatorShares, gotDelegatorShares, validator, bond) +// require.Equal(t, expDelegatorAcc.Int64(), gotDelegatorAcc.Int64(), +// "i: %v\nexpDelegatorAcc: %v\ngotDelegatorAcc: %v\nvalidator: %v\nbond: %v\n", +// i, expDelegatorAcc, gotDelegatorAcc, validator, bond) +// } +// +// // these are more than we have bonded now +// errorCases := []sdk.Int{ +// //1<<64 - 1, // more than int64 power +// //1<<63 + 1, // more than int64 power +// sdk.TokensFromConsensusPower(1<<63 - 1), +// sdk.TokensFromConsensusPower(1 << 31), +// initBond, +// } +// +// for _, c := range errorCases { +// unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, c) +// msgUndelegate := NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) +// res, err = handler(ctx, msgUndelegate) +// require.Error(t, err) +// require.Nil(t, res) +// } +// +// leftBonded := initBond.Sub(unbondAmt.Amount.Mul(sdk.NewInt(numUnbonds))) +// +// // should be able to unbond remaining +// unbondAmt = sdk.NewCoin(sdk.DefaultBondDenom, leftBonded) +// msgUndelegate = NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) +// res, err = handler(ctx, msgUndelegate) +// require.NoError(t, err, "msgUnbond: %v\nshares: %s\nleftBonded: %s\n", msgUndelegate, unbondAmt, leftBonded) +// require.NotNil(t, res, "msgUnbond: %v\nshares: %s\nleftBonded: %s\n", msgUndelegate, unbondAmt, leftBonded) +//} +// +//func TestMultipleMsgCreateValidator(t *testing.T) { +// initPower := int64(1000) +// initTokens := sdk.TokensFromConsensusPower(initPower) +// ctx, _, bk, keeper, _ := CreateTestInput(t, false, initPower) +// handler := NewHandler(keeper) +// +// params := keeper.GetParams(ctx) +// blockTime := time.Now().UTC() +// ctx = ctx.WithBlockTime(blockTime) +// +// validatorAddrs := []sdk.ValAddress{ +// sdk.ValAddress(Addrs[0]), +// sdk.ValAddress(Addrs[1]), +// sdk.ValAddress(Addrs[2]), +// } +// delegatorAddrs := []sdk.AccAddress{ +// Addrs[0], +// Addrs[1], +// Addrs[2], +// } +// +// // bond them all +// for i, validatorAddr := range validatorAddrs { +// valTokens := sdk.TokensFromConsensusPower(10) +// msgCreateValidatorOnBehalfOf := NewTestMsgCreateValidator(validatorAddr, PKs[i], valTokens) +// +// res, err := handler(ctx, msgCreateValidatorOnBehalfOf) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // verify that the account is bonded +// validators := keeper.GetValidators(ctx, 100) +// require.Equal(t, (i + 1), len(validators)) +// +// val := validators[i] +// balanceExpd := initTokens.Sub(valTokens) +// balanceGot := bk.GetBalance(ctx, delegatorAddrs[i], params.BondDenom).Amount +// +// require.Equal(t, i+1, len(validators), "expected %d validators got %d, validators: %v", i+1, len(validators), validators) +// require.Equal(t, valTokens, val.DelegatorShares.RoundInt(), "expected %d shares, got %d", 10, val.DelegatorShares) +// require.Equal(t, balanceExpd, balanceGot, "expected account to have %d, got %d", balanceExpd, balanceGot) +// } +// +// EndBlocker(ctx, keeper) +// +// // unbond them all by removing delegation +// for i, validatorAddr := range validatorAddrs { +// _, found := keeper.GetValidator(ctx, validatorAddr) +// require.True(t, found) +// +// unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(10)) +// msgUndelegate := NewMsgUndelegate(delegatorAddrs[i], validatorAddr, unbondAmt) // remove delegation +// res, err := handler(ctx, msgUndelegate) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// ts := &gogotypes.Timestamp{} +// types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) +// +// _, err = gogotypes.TimestampFromProto(ts) +// require.NoError(t, err) +// +// // adds validator into unbonding queue +// EndBlocker(ctx, keeper) +// +// // removes validator from queue and set +// EndBlocker(ctx.WithBlockTime(blockTime.Add(params.UnbondingTime)), keeper) +// +// // Check that the validator is deleted from state +// validators := keeper.GetValidators(ctx, 100) +// require.Equal(t, len(validatorAddrs)-(i+1), len(validators), +// "expected %d validators got %d", len(validatorAddrs)-(i+1), len(validators)) +// +// _, found = keeper.GetValidator(ctx, validatorAddr) +// require.False(t, found) +// +// gotBalance := bk.GetBalance(ctx, delegatorAddrs[i], params.BondDenom).Amount +// require.Equal(t, initTokens, gotBalance, "expected account to have %d, got %d", initTokens, gotBalance) +// } +//} +// +//func TestMultipleMsgDelegate(t *testing.T) { +// ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) +// handler := NewHandler(keeper) +// validatorAddr, delegatorAddrs := sdk.ValAddress(Addrs[0]), Addrs[1:] +// +// // first make a validator +// msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], sdk.NewInt(10)) +// res, err := handler(ctx, msgCreateValidator) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // delegate multiple parties +// for _, delegatorAddr := range delegatorAddrs { +// msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, sdk.NewInt(10)) +// res, err := handler(ctx, msgDelegate) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // check that the account is bonded +// bond, found := keeper.GetDelegation(ctx, delegatorAddr, validatorAddr) +// require.True(t, found) +// require.NotNil(t, bond, "expected delegatee bond %d to exist", bond) +// } +// +// // unbond them all +// for _, delegatorAddr := range delegatorAddrs { +// unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) +// msgUndelegate := NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) +// +// res, err := handler(ctx, msgUndelegate) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// ts := &gogotypes.Timestamp{} +// types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) +// +// finishTime, err := gogotypes.TimestampFromProto(ts) +// require.NoError(t, err) +// +// ctx = ctx.WithBlockTime(finishTime) +// EndBlocker(ctx, keeper) +// +// // check that the account is unbonded +// _, found := keeper.GetDelegation(ctx, delegatorAddr, validatorAddr) +// require.False(t, found) +// } +//} +// +//func TestJailValidator(t *testing.T) { +// ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) +// handler := NewHandler(keeper) +// validatorAddr, delegatorAddr := sdk.ValAddress(Addrs[0]), Addrs[1] +// +// // create the validator +// msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], sdk.NewInt(10)) +// res, err := handler(ctx, msgCreateValidator) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // bond a delegator +// msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, sdk.NewInt(10)) +// res, err = handler(ctx, msgDelegate) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // unbond the validators bond portion +// unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) +// msgUndelegateValidator := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) +// res, err = handler(ctx, msgUndelegateValidator) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// ts := &gogotypes.Timestamp{} +// types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) +// +// finishTime, err := gogotypes.TimestampFromProto(ts) +// require.NoError(t, err) +// +// ctx = ctx.WithBlockTime(finishTime) +// EndBlocker(ctx, keeper) +// +// validator, found := keeper.GetValidator(ctx, validatorAddr) +// require.True(t, found) +// require.True(t, validator.Jailed, "%v", validator) +// +// // test that the delegator can still withdraw their bonds +// msgUndelegateDelegator := NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) +// +// res, err = handler(ctx, msgUndelegateDelegator) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// ts = &gogotypes.Timestamp{} +// types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) +// +// finishTime, err = gogotypes.TimestampFromProto(ts) +// require.NoError(t, err) +// +// ctx = ctx.WithBlockTime(finishTime) +// EndBlocker(ctx, keeper) +// +// // verify that the pubkey can now be reused +// res, err = handler(ctx, msgCreateValidator) +// require.NoError(t, err) +// require.NotNil(t, res) +//} +// +//func TestValidatorQueue(t *testing.T) { +// ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) +// handler := NewHandler(keeper) +// validatorAddr, delegatorAddr := sdk.ValAddress(Addrs[0]), Addrs[1] +// +// // set the unbonding time +// params := keeper.GetParams(ctx) +// params.UnbondingTime = 7 * time.Second +// keeper.SetParams(ctx, params) +// +// // create the validator +// valTokens := sdk.TokensFromConsensusPower(10) +// msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], valTokens) +// res, err := handler(ctx, msgCreateValidator) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // bond a delegator +// delTokens := sdk.TokensFromConsensusPower(10) +// msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, delTokens) +// res, err = handler(ctx, msgDelegate) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// EndBlocker(ctx, keeper) +// +// // unbond the all self-delegation to put validator in unbonding state +// unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, delTokens) +// msgUndelegateValidator := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) +// res, err = handler(ctx, msgUndelegateValidator) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// ts := &gogotypes.Timestamp{} +// types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) +// +// finishTime, err := gogotypes.TimestampFromProto(ts) +// require.NoError(t, err) +// +// ctx = ctx.WithBlockTime(finishTime) +// EndBlocker(ctx, keeper) +// +// origHeader := ctx.BlockHeader() +// +// validator, found := keeper.GetValidator(ctx, validatorAddr) +// require.True(t, found) +// require.True(t, validator.IsUnbonding(), "%v", validator) +// +// // should still be unbonding at time 6 seconds later +// ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 6)) +// EndBlocker(ctx, keeper) +// +// validator, found = keeper.GetValidator(ctx, validatorAddr) +// require.True(t, found) +// require.True(t, validator.IsUnbonding(), "%v", validator) +// +// // should be in unbonded state at time 7 seconds later +// ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 7)) +// EndBlocker(ctx, keeper) +// +// validator, found = keeper.GetValidator(ctx, validatorAddr) +// require.True(t, found) +// require.True(t, validator.IsUnbonded(), "%v", validator) +//} +// +//func TestUnbondingPeriod(t *testing.T) { +// ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) +// handler := NewHandler(keeper) +// validatorAddr := sdk.ValAddress(Addrs[0]) +// +// // set the unbonding time +// params := keeper.GetParams(ctx) +// params.UnbondingTime = 7 * time.Second +// keeper.SetParams(ctx, params) +// +// // create the validator +// valTokens := sdk.TokensFromConsensusPower(10) +// msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], valTokens) +// res, err := handler(ctx, msgCreateValidator) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// EndBlocker(ctx, keeper) +// +// // begin unbonding +// unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(10)) +// msgUndelegate := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) +// res, err = handler(ctx, msgUndelegate) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// origHeader := ctx.BlockHeader() +// +// _, found := keeper.GetUnbondingDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) +// require.True(t, found, "should not have unbonded") +// +// // cannot complete unbonding at same time +// EndBlocker(ctx, keeper) +// _, found = keeper.GetUnbondingDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) +// require.True(t, found, "should not have unbonded") +// +// // cannot complete unbonding at time 6 seconds later +// ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 6)) +// EndBlocker(ctx, keeper) +// _, found = keeper.GetUnbondingDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) +// require.True(t, found, "should not have unbonded") +// +// // can complete unbonding at time 7 seconds later +// ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 7)) +// EndBlocker(ctx, keeper) +// _, found = keeper.GetUnbondingDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) +// require.False(t, found, "should have unbonded") +//} +// +//func TestUnbondingFromUnbondingValidator(t *testing.T) { +// ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) +// handler := NewHandler(keeper) +// validatorAddr, delegatorAddr := sdk.ValAddress(Addrs[0]), Addrs[1] +// +// // create the validator +// msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], sdk.NewInt(10)) +// res, err := handler(ctx, msgCreateValidator) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // bond a delegator +// msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, sdk.NewInt(10)) +// res, err = handler(ctx, msgDelegate) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // unbond the validators bond portion +// unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) +// msgUndelegateValidator := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) +// res, err = handler(ctx, msgUndelegateValidator) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // change the ctx to Block Time one second before the validator would have unbonded +// ts := &gogotypes.Timestamp{} +// types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) +// +// finishTime, err := gogotypes.TimestampFromProto(ts) +// require.NoError(t, err) +// +// ctx = ctx.WithBlockTime(finishTime.Add(time.Second * -1)) +// +// // unbond the delegator from the validator +// msgUndelegateDelegator := NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) +// res, err = handler(ctx, msgUndelegateDelegator) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(keeper.UnbondingTime(ctx))) +// +// // Run the EndBlocker +// EndBlocker(ctx, keeper) +// +// // Check to make sure that the unbonding delegation is no longer in state +// // (meaning it was deleted in the above EndBlocker) +// _, found := keeper.GetUnbondingDelegation(ctx, delegatorAddr, validatorAddr) +// require.False(t, found, "should be removed from state") +//} +// +//func TestRedelegationPeriod(t *testing.T) { +// ctx, _, bk, keeper, _ := CreateTestInput(t, false, 1000) +// handler := NewHandler(keeper) +// validatorAddr, validatorAddr2 := sdk.ValAddress(Addrs[0]), sdk.ValAddress(Addrs[1]) +// denom := keeper.GetParams(ctx).BondDenom +// +// // set the unbonding time +// params := keeper.GetParams(ctx) +// params.UnbondingTime = 7 * time.Second +// keeper.SetParams(ctx, params) +// +// // create the validators +// msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], sdk.NewInt(10)) +// +// // initial balance +// amt1 := bk.GetBalance(ctx, sdk.AccAddress(validatorAddr), denom).Amount +// +// res, err := handler(ctx, msgCreateValidator) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // balance should have been subtracted after creation +// amt2 := bk.GetBalance(ctx, sdk.AccAddress(validatorAddr), denom).Amount +// require.Equal(t, amt1.Sub(sdk.NewInt(10)).Int64(), amt2.Int64(), "expected coins to be subtracted") +// +// msgCreateValidator = NewTestMsgCreateValidator(validatorAddr2, PKs[1], sdk.NewInt(10)) +// res, err = handler(ctx, msgCreateValidator) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// bal1 := bk.GetAllBalances(ctx, sdk.AccAddress(validatorAddr)) +// +// // begin redelegate +// redAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) +// msgBeginRedelegate := NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2, redAmt) +// res, err = handler(ctx, msgBeginRedelegate) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // origin account should not lose tokens as with a regular delegation +// bal2 := bk.GetAllBalances(ctx, sdk.AccAddress(validatorAddr)) +// require.Equal(t, bal1, bal2) +// +// origHeader := ctx.BlockHeader() +// +// // cannot complete redelegation at same time +// EndBlocker(ctx, keeper) +// _, found := keeper.GetRedelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2) +// require.True(t, found, "should not have unbonded") +// +// // cannot complete redelegation at time 6 seconds later +// ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 6)) +// EndBlocker(ctx, keeper) +// _, found = keeper.GetRedelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2) +// require.True(t, found, "should not have unbonded") +// +// // can complete redelegation at time 7 seconds later +// ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 7)) +// EndBlocker(ctx, keeper) +// _, found = keeper.GetRedelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2) +// require.False(t, found, "should have unbonded") +//} +// +//func TestTransitiveRedelegation(t *testing.T) { +// ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) +// handler := NewHandler(keeper) +// +// validatorAddr := sdk.ValAddress(Addrs[0]) +// validatorAddr2 := sdk.ValAddress(Addrs[1]) +// validatorAddr3 := sdk.ValAddress(Addrs[2]) +// +// blockTime := time.Now().UTC() +// ctx = ctx.WithBlockTime(blockTime) +// +// // create the validators +// msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], sdk.NewInt(10)) +// res, err := handler(ctx, msgCreateValidator) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// msgCreateValidator = NewTestMsgCreateValidator(validatorAddr2, PKs[1], sdk.NewInt(10)) +// res, err = handler(ctx, msgCreateValidator) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// msgCreateValidator = NewTestMsgCreateValidator(validatorAddr3, PKs[2], sdk.NewInt(10)) +// res, err = handler(ctx, msgCreateValidator) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // begin redelegate +// redAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) +// msgBeginRedelegate := NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2, redAmt) +// res, err = handler(ctx, msgBeginRedelegate) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // cannot redelegation to next validator while first delegation exists +// msgBeginRedelegate = NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr2, validatorAddr3, redAmt) +// res, err = handler(ctx, msgBeginRedelegate) +// require.Error(t, err) +// require.Nil(t, res) +// +// params := keeper.GetParams(ctx) +// ctx = ctx.WithBlockTime(blockTime.Add(params.UnbondingTime)) +// +// // complete first redelegation +// EndBlocker(ctx, keeper) +// +// // now should be able to redelegate from the second validator to the third +// res, err = handler(ctx, msgBeginRedelegate) +// require.NoError(t, err) +// require.NotNil(t, res) +//} +// +//func TestMultipleRedelegationAtSameTime(t *testing.T) { +// ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) +// handler := NewHandler(keeper) +// +// valAddr := sdk.ValAddress(Addrs[0]) +// valAddr2 := sdk.ValAddress(Addrs[1]) +// +// // set the unbonding time +// params := keeper.GetParams(ctx) +// params.UnbondingTime = 1 * time.Second +// keeper.SetParams(ctx, params) +// +// // create the validators +// valTokens := sdk.TokensFromConsensusPower(10) +// msgCreateValidator := NewTestMsgCreateValidator(valAddr, PKs[0], valTokens) +// res, err := handler(ctx, msgCreateValidator) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// msgCreateValidator = NewTestMsgCreateValidator(valAddr2, PKs[1], valTokens) +// res, err = handler(ctx, msgCreateValidator) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // end block to bond them +// EndBlocker(ctx, keeper) +// +// // begin a redelegate +// selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) +// redAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens.QuoRaw(2)) +// msgBeginRedelegate := NewMsgBeginRedelegate(selfDelAddr, valAddr, valAddr2, redAmt) +// res, err = handler(ctx, msgBeginRedelegate) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // there should only be one entry in the redelegation object +// rd, found := keeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) +// require.True(t, found) +// require.Len(t, rd.Entries, 1) +// +// // start a second redelegation at this same time as the first +// res, err = handler(ctx, msgBeginRedelegate) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // now there should be two entries +// rd, found = keeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) +// require.True(t, found) +// require.Len(t, rd.Entries, 2) +// +// // move forward in time, should complete both redelegations +// ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(1 * time.Second)) +// EndBlocker(ctx, keeper) +// +// rd, found = keeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) +// require.False(t, found) +//} +// +//func TestMultipleRedelegationAtUniqueTimes(t *testing.T) { +// ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) +// handler := NewHandler(keeper) +// +// valAddr := sdk.ValAddress(Addrs[0]) +// valAddr2 := sdk.ValAddress(Addrs[1]) +// +// // set the unbonding time +// params := keeper.GetParams(ctx) +// params.UnbondingTime = 10 * time.Second +// keeper.SetParams(ctx, params) +// +// // create the validators +// valTokens := sdk.TokensFromConsensusPower(10) +// msgCreateValidator := NewTestMsgCreateValidator(valAddr, PKs[0], valTokens) +// res, err := handler(ctx, msgCreateValidator) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// msgCreateValidator = NewTestMsgCreateValidator(valAddr2, PKs[1], valTokens) +// res, err = handler(ctx, msgCreateValidator) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // end block to bond them +// EndBlocker(ctx, keeper) +// +// // begin a redelegate +// selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) +// redAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens.QuoRaw(2)) +// msgBeginRedelegate := NewMsgBeginRedelegate(selfDelAddr, valAddr, valAddr2, redAmt) +// res, err = handler(ctx, msgBeginRedelegate) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // move forward in time and start a second redelegation +// ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) +// res, err = handler(ctx, msgBeginRedelegate) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // now there should be two entries +// rd, found := keeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) +// require.True(t, found) +// require.Len(t, rd.Entries, 2) +// +// // move forward in time, should complete the first redelegation, but not the second +// ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) +// EndBlocker(ctx, keeper) +// rd, found = keeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) +// require.True(t, found) +// require.Len(t, rd.Entries, 1) +// +// // move forward in time, should complete the second redelegation +// ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) +// EndBlocker(ctx, keeper) +// rd, found = keeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) +// require.False(t, found) +//} +// +//func TestMultipleUnbondingDelegationAtSameTime(t *testing.T) { +// ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) +// handler := NewHandler(keeper) +// +// valAddr := sdk.ValAddress(Addrs[0]) +// +// // set the unbonding time +// params := keeper.GetParams(ctx) +// params.UnbondingTime = 1 * time.Second +// keeper.SetParams(ctx, params) +// +// // create the validator +// valTokens := sdk.TokensFromConsensusPower(10) +// msgCreateValidator := NewTestMsgCreateValidator(valAddr, PKs[0], valTokens) +// res, err := handler(ctx, msgCreateValidator) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // end block to bond +// EndBlocker(ctx, keeper) +// +// // begin an unbonding delegation +// selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) +// unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens.QuoRaw(2)) +// msgUndelegate := NewMsgUndelegate(selfDelAddr, valAddr, unbondAmt) +// res, err = handler(ctx, msgUndelegate) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // there should only be one entry in the ubd object +// ubd, found := keeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) +// require.True(t, found) +// require.Len(t, ubd.Entries, 1) +// +// // start a second ubd at this same time as the first +// res, err = handler(ctx, msgUndelegate) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // now there should be two entries +// ubd, found = keeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) +// require.True(t, found) +// require.Len(t, ubd.Entries, 2) +// +// // move forwaubd in time, should complete both ubds +// ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(1 * time.Second)) +// EndBlocker(ctx, keeper) +// +// ubd, found = keeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) +// require.False(t, found) +//} +// +//func TestMultipleUnbondingDelegationAtUniqueTimes(t *testing.T) { +// ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) +// handler := NewHandler(keeper) +// valAddr := sdk.ValAddress(Addrs[0]) +// +// // set the unbonding time +// params := keeper.GetParams(ctx) +// params.UnbondingTime = 10 * time.Second +// keeper.SetParams(ctx, params) +// +// // create the validator +// valTokens := sdk.TokensFromConsensusPower(10) +// msgCreateValidator := NewTestMsgCreateValidator(valAddr, PKs[0], valTokens) +// res, err := handler(ctx, msgCreateValidator) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // end block to bond +// EndBlocker(ctx, keeper) +// +// // begin an unbonding delegation +// selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) +// unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens.QuoRaw(2)) +// msgUndelegate := NewMsgUndelegate(selfDelAddr, valAddr, unbondAmt) +// res, err = handler(ctx, msgUndelegate) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // there should only be one entry in the ubd object +// ubd, found := keeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) +// require.True(t, found) +// require.Len(t, ubd.Entries, 1) +// +// // move forwaubd in time and start a second redelegation +// ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) +// res, err = handler(ctx, msgUndelegate) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // now there should be two entries +// ubd, found = keeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) +// require.True(t, found) +// require.Len(t, ubd.Entries, 2) +// +// // move forwaubd in time, should complete the first redelegation, but not the second +// ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) +// EndBlocker(ctx, keeper) +// ubd, found = keeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) +// require.True(t, found) +// require.Len(t, ubd.Entries, 1) +// +// // move forwaubd in time, should complete the second redelegation +// ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) +// EndBlocker(ctx, keeper) +// ubd, found = keeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) +// require.False(t, found) +//} +// +//func TestUnbondingWhenExcessValidators(t *testing.T) { +// ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) +// handler := NewHandler(keeper) +// +// validatorAddr1 := sdk.ValAddress(Addrs[0]) +// validatorAddr2 := sdk.ValAddress(Addrs[1]) +// validatorAddr3 := sdk.ValAddress(Addrs[2]) +// +// // set the unbonding time +// params := keeper.GetParams(ctx) +// params.MaxValidators = 2 +// keeper.SetParams(ctx, params) +// +// // add three validators +// valTokens1 := sdk.TokensFromConsensusPower(50) +// msgCreateValidator := NewTestMsgCreateValidator(validatorAddr1, PKs[0], valTokens1) +// res, err := handler(ctx, msgCreateValidator) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // apply TM updates +// keeper.ApplyAndReturnValidatorSetUpdates(ctx) +// require.Equal(t, 1, len(keeper.GetLastValidators(ctx))) +// +// valTokens2 := sdk.TokensFromConsensusPower(30) +// msgCreateValidator = NewTestMsgCreateValidator(validatorAddr2, PKs[1], valTokens2) +// res, err = handler(ctx, msgCreateValidator) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // apply TM updates +// keeper.ApplyAndReturnValidatorSetUpdates(ctx) +// require.Equal(t, 2, len(keeper.GetLastValidators(ctx))) +// +// valTokens3 := sdk.TokensFromConsensusPower(10) +// msgCreateValidator = NewTestMsgCreateValidator(validatorAddr3, PKs[2], valTokens3) +// res, err = handler(ctx, msgCreateValidator) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // apply TM updates +// keeper.ApplyAndReturnValidatorSetUpdates(ctx) +// require.Equal(t, 2, len(keeper.GetLastValidators(ctx))) +// +// // unbond the validator-2 +// unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens2) +// msgUndelegate := NewMsgUndelegate(sdk.AccAddress(validatorAddr2), validatorAddr2, unbondAmt) +// res, err = handler(ctx, msgUndelegate) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // apply TM updates +// keeper.ApplyAndReturnValidatorSetUpdates(ctx) +// +// // because there are extra validators waiting to get in, the queued +// // validator (aka. validator-1) should make it into the bonded group, thus +// // the total number of validators should stay the same +// vals := keeper.GetLastValidators(ctx) +// require.Equal(t, 2, len(vals), "vals %v", vals) +// val1, found := keeper.GetValidator(ctx, validatorAddr1) +// require.True(t, found) +// require.Equal(t, sdk.Bonded, val1.Status, "%v", val1) +//} +// +//func TestBondUnbondRedelegateSlashTwice(t *testing.T) { +// ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) +// handler := NewHandler(keeper) +// +// valA, valB, del := sdk.ValAddress(Addrs[0]), sdk.ValAddress(Addrs[1]), Addrs[2] +// consAddr0 := sdk.ConsAddress(PKs[0].Address()) +// +// valTokens := sdk.TokensFromConsensusPower(10) +// msgCreateValidator := NewTestMsgCreateValidator(valA, PKs[0], valTokens) +// res, err := handler(ctx, msgCreateValidator) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// msgCreateValidator = NewTestMsgCreateValidator(valB, PKs[1], valTokens) +// res, err = handler(ctx, msgCreateValidator) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // delegate 10 stake +// msgDelegate := NewTestMsgDelegate(del, valA, valTokens) +// res, err = handler(ctx, msgDelegate) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // apply Tendermint updates +// updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) +// require.Equal(t, 2, len(updates)) +// +// // a block passes +// ctx = ctx.WithBlockHeight(1) +// +// // begin unbonding 4 stake +// unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(4)) +// msgUndelegate := NewMsgUndelegate(del, valA, unbondAmt) +// res, err = handler(ctx, msgUndelegate) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // begin redelegate 6 stake +// redAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(6)) +// msgBeginRedelegate := NewMsgBeginRedelegate(del, valA, valB, redAmt) +// res, err = handler(ctx, msgBeginRedelegate) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// // destination delegation should have 6 shares +// delegation, found := keeper.GetDelegation(ctx, del, valB) +// require.True(t, found) +// require.Equal(t, sdk.NewDecFromInt(redAmt.Amount), delegation.Shares) +// +// // must apply validator updates +// updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx) +// require.Equal(t, 2, len(updates)) +// +// // slash the validator by half +// keeper.Slash(ctx, consAddr0, 0, 20, sdk.NewDecWithPrec(5, 1)) +// +// // unbonding delegation should have been slashed by half +// ubd, found := keeper.GetUnbondingDelegation(ctx, del, valA) +// require.True(t, found) +// require.Len(t, ubd.Entries, 1) +// require.Equal(t, unbondAmt.Amount.QuoRaw(2), ubd.Entries[0].Balance) +// +// // redelegation should have been slashed by half +// redelegation, found := keeper.GetRedelegation(ctx, del, valA, valB) +// require.True(t, found) +// require.Len(t, redelegation.Entries, 1) +// +// // destination delegation should have been slashed by half +// delegation, found = keeper.GetDelegation(ctx, del, valB) +// require.True(t, found) +// require.Equal(t, sdk.NewDecFromInt(redAmt.Amount.QuoRaw(2)), delegation.Shares) +// +// // validator power should have been reduced by half +// validator, found := keeper.GetValidator(ctx, valA) +// require.True(t, found) +// require.Equal(t, valTokens.QuoRaw(2), validator.GetBondedTokens()) +// +// // slash the validator for an infraction committed after the unbonding and redelegation begin +// ctx = ctx.WithBlockHeight(3) +// keeper.Slash(ctx, consAddr0, 2, 10, sdk.NewDecWithPrec(5, 1)) +// +// // unbonding delegation should be unchanged +// ubd, found = keeper.GetUnbondingDelegation(ctx, del, valA) +// require.True(t, found) +// require.Len(t, ubd.Entries, 1) +// require.Equal(t, unbondAmt.Amount.QuoRaw(2), ubd.Entries[0].Balance) +// +// // redelegation should be unchanged +// redelegation, found = keeper.GetRedelegation(ctx, del, valA, valB) +// require.True(t, found) +// require.Len(t, redelegation.Entries, 1) +// +// // destination delegation should be unchanged +// delegation, found = keeper.GetDelegation(ctx, del, valB) +// require.True(t, found) +// require.Equal(t, sdk.NewDecFromInt(redAmt.Amount.QuoRaw(2)), delegation.Shares) +// +// // end blocker +// EndBlocker(ctx, keeper) +// +// // validator power should have been reduced to zero +// // validator should be in unbonding state +// validator, _ = keeper.GetValidator(ctx, valA) +// require.Equal(t, validator.GetStatus(), sdk.Unbonding) +//} +// +//func TestInvalidMsg(t *testing.T) { +// k := Keeper{} +// h := NewHandler(k) +// +// res, err := h(sdk.NewContext(nil, abci.Header{}, false, nil), sdk.NewTestMsg()) +// require.Error(t, err) +// require.Nil(t, res) +// require.True(t, strings.Contains(err.Error(), "unrecognized staking message type")) +//} +// +//func TestInvalidCoinDenom(t *testing.T) { +// ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) +// handler := NewHandler(keeper) +// +// valA, valB, delAddr := sdk.ValAddress(Addrs[0]), sdk.ValAddress(Addrs[1]), Addrs[2] +// +// valTokens := sdk.TokensFromConsensusPower(100) +// invalidCoin := sdk.NewCoin("churros", valTokens) +// validCoin := sdk.NewCoin(sdk.DefaultBondDenom, valTokens) +// oneCoin := sdk.NewCoin(sdk.DefaultBondDenom, sdk.OneInt()) +// +// commission := types.NewCommissionRates(sdk.OneDec(), sdk.OneDec(), sdk.ZeroDec()) +// +// msgCreate := types.NewMsgCreateValidator(valA, PKs[0], invalidCoin, Description{}, commission, sdk.OneInt()) +// res, err := handler(ctx, msgCreate) +// require.Error(t, err) +// require.Nil(t, res) +// +// msgCreate = types.NewMsgCreateValidator(valA, PKs[0], validCoin, Description{}, commission, sdk.OneInt()) +// res, err = handler(ctx, msgCreate) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// msgCreate = types.NewMsgCreateValidator(valB, PKs[1], validCoin, Description{}, commission, sdk.OneInt()) +// res, err = handler(ctx, msgCreate) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// msgDelegate := types.NewMsgDelegate(delAddr, valA, invalidCoin) +// res, err = handler(ctx, msgDelegate) +// require.Error(t, err) +// require.Nil(t, res) +// +// msgDelegate = types.NewMsgDelegate(delAddr, valA, validCoin) +// res, err = handler(ctx, msgDelegate) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// msgUndelegate := types.NewMsgUndelegate(delAddr, valA, invalidCoin) +// res, err = handler(ctx, msgUndelegate) +// require.Error(t, err) +// require.Nil(t, res) +// +// msgUndelegate = types.NewMsgUndelegate(delAddr, valA, oneCoin) +// res, err = handler(ctx, msgUndelegate) +// require.NoError(t, err) +// require.NotNil(t, res) +// +// msgRedelegate := types.NewMsgBeginRedelegate(delAddr, valA, valB, invalidCoin) +// res, err = handler(ctx, msgRedelegate) +// require.Error(t, err) +// require.Nil(t, res) +// +// msgRedelegate = types.NewMsgBeginRedelegate(delAddr, valA, valB, oneCoin) +// res, err = handler(ctx, msgRedelegate) +// require.NoError(t, err) +// require.NotNil(t, res) +//} From 315572bcd231f782a71d366c31fca99d8d0cf222 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Wed, 26 Feb 2020 11:33:25 +0100 Subject: [PATCH 220/529] refactor TestValidatorByPowerIndex --- x/staking/common_test.go | 4 +- x/staking/genesis_test.go | 2 +- x/staking/handler_test.go | 213 ++++++++++++++++++++++---------------- 3 files changed, 127 insertions(+), 92 deletions(-) diff --git a/x/staking/common_test.go b/x/staking/common_test.go index 871894b9bbcf..35f27d32c3ae 100644 --- a/x/staking/common_test.go +++ b/x/staking/common_test.go @@ -89,8 +89,8 @@ func getBaseSimappWithCustomKeeper() (*codec.Codec, *simapp.SimApp, sdk.Context) } // generateAddresses generates numAddrs of normal AccAddrs and ValAddrs -func generateAddresses(app *simapp.SimApp, ctx sdk.Context, numAddrs int) ([]sdk.AccAddress, []sdk.ValAddress) { - addrDels := simapp.AddTestAddrsIncremental(app, ctx, numAddrs, sdk.NewInt(10000)) +func generateAddresses(app *simapp.SimApp, ctx sdk.Context, numAddrs int, accAmount int64) ([]sdk.AccAddress, []sdk.ValAddress) { + addrDels := simapp.AddTestAddrsIncremental(app, ctx, numAddrs, sdk.NewInt(accAmount)) addrVals := simapp.ConvertAddrsToValAddrs(addrDels) return addrDels, addrVals diff --git a/x/staking/genesis_test.go b/x/staking/genesis_test.go index 29a6149e4bb3..c50cd63bcdf4 100644 --- a/x/staking/genesis_test.go +++ b/x/staking/genesis_test.go @@ -21,7 +21,7 @@ import ( func bootstrapGenesisTest(t *testing.T, power int64, numAddrs int) (*simapp.SimApp, sdk.Context, []sdk.AccAddress, []sdk.ValAddress) { _, app, ctx := getBaseSimappWithCustomKeeper() - addrDels, addrVals := generateAddresses(app, ctx, numAddrs) + addrDels, addrVals := generateAddresses(app, ctx, numAddrs, 10000) amt := sdk.TokensFromConsensusPower(power) totalSupply := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), amt.MulRaw(int64(len(addrDels))))) diff --git a/x/staking/handler_test.go b/x/staking/handler_test.go index bbbb2eaa8435..40d985cfeb3e 100644 --- a/x/staking/handler_test.go +++ b/x/staking/handler_test.go @@ -1,94 +1,129 @@ package staking_test -//func TestValidatorByPowerIndex(t *testing.T) { -// validatorAddr, validatorAddr3 := sdk.ValAddress(Addrs[0]), sdk.ValAddress(Addrs[1]) -// -// initPower := int64(1000000) -// initBond := sdk.TokensFromConsensusPower(initPower) -// ctx, _, _, keeper, _ := CreateTestInput(t, false, initPower) -// handler := NewHandler(keeper) -// -// // create validator -// msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], initBond) -// res, err := handler(ctx, msgCreateValidator) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // must end-block -// updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) -// require.Equal(t, 1, len(updates)) -// -// // verify the self-delegation exists -// bond, found := keeper.GetDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) -// require.True(t, found) -// gotBond := bond.Shares.RoundInt() -// require.Equal(t, initBond, gotBond) -// -// // verify that the by power index exists -// validator, found := keeper.GetValidator(ctx, validatorAddr) -// require.True(t, found) -// power := GetValidatorsByPowerIndexKey(validator) -// require.True(t, keep.ValidatorByPowerIndexExists(ctx, keeper, power)) -// -// // create a second validator keep it bonded -// msgCreateValidator = NewTestMsgCreateValidator(validatorAddr3, PKs[2], initBond) -// res, err = handler(ctx, msgCreateValidator) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // must end-block -// updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx) -// require.Equal(t, 1, len(updates)) -// -// // slash and jail the first validator -// consAddr0 := sdk.ConsAddress(PKs[0].Address()) -// keeper.Slash(ctx, consAddr0, 0, initPower, sdk.NewDecWithPrec(5, 1)) -// keeper.Jail(ctx, consAddr0) -// keeper.ApplyAndReturnValidatorSetUpdates(ctx) -// -// validator, found = keeper.GetValidator(ctx, validatorAddr) -// require.True(t, found) -// require.Equal(t, sdk.Unbonding, validator.Status) // ensure is unbonding -// require.Equal(t, initBond.QuoRaw(2), validator.Tokens) // ensure tokens slashed -// keeper.Unjail(ctx, consAddr0) -// -// // the old power record should have been deleted as the power changed -// require.False(t, keep.ValidatorByPowerIndexExists(ctx, keeper, power)) -// -// // but the new power record should have been created -// validator, found = keeper.GetValidator(ctx, validatorAddr) -// require.True(t, found) -// power2 := GetValidatorsByPowerIndexKey(validator) -// require.True(t, keep.ValidatorByPowerIndexExists(ctx, keeper, power2)) -// -// // now the new record power index should be the same as the original record -// power3 := GetValidatorsByPowerIndexKey(validator) -// require.Equal(t, power2, power3) -// -// // unbond self-delegation -// totalBond := validator.TokensFromShares(bond.GetShares()).TruncateInt() -// unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, totalBond) -// msgUndelegate := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) -// -// res, err = handler(ctx, msgUndelegate) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// ts := &gogotypes.Timestamp{} -// types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) -// -// finishTime, err := gogotypes.TimestampFromProto(ts) -// require.NoError(t, err) -// -// ctx = ctx.WithBlockTime(finishTime) -// EndBlocker(ctx, keeper) -// EndBlocker(ctx, keeper) -// -// // verify that by power key nolonger exists -// _, found = keeper.GetValidator(ctx, validatorAddr) -// require.False(t, found) -// require.False(t, keep.ValidatorByPowerIndexExists(ctx, keeper, power3)) -//} +import ( + "testing" + + gogotypes "github.com/gogo/protobuf/types" + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/simapp" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/staking" + "github.com/cosmos/cosmos-sdk/x/staking/keeper" + "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/cosmos/cosmos-sdk/x/supply" +) + +func bootstrapHandlerGenesisTest(t *testing.T, power int64, numAddrs int, accAmount int64) (*simapp.SimApp, sdk.Context, []sdk.AccAddress, []sdk.ValAddress) { + _, app, ctx := getBaseSimappWithCustomKeeper() + + addrDels, addrVals := generateAddresses(app, ctx, numAddrs, accAmount) + + amt := sdk.TokensFromConsensusPower(power) + totalSupply := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), amt.MulRaw(int64(len(addrDels))))) + + notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) + err := app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), totalSupply) + require.NoError(t, err) + app.SupplyKeeper.SetModuleAccount(ctx, notBondedPool) + + app.SupplyKeeper.SetSupply(ctx, supply.NewSupply(totalSupply)) + + return app, ctx, addrDels, addrVals +} + +func TestValidatorByPowerIndex(t *testing.T) { + initPower := int64(1000000) + initBond := sdk.TokensFromConsensusPower(initPower) + + app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 10, 10000000000000) + + validatorAddr, validatorAddr3 := valAddrs[0], valAddrs[1] + + handler := staking.NewHandler(app.StakingKeeper) + + // create validator + msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], initBond) + res, err := handler(ctx, msgCreateValidator) + require.NoError(t, err) + require.NotNil(t, res) + + // must end-block + updates := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 1, len(updates)) + + // verify the self-delegation exists + bond, found := app.StakingKeeper.GetDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) + require.True(t, found) + gotBond := bond.Shares.RoundInt() + require.Equal(t, initBond, gotBond) + + // verify that the by power index exists + validator, found := app.StakingKeeper.GetValidator(ctx, validatorAddr) + require.True(t, found) + power := staking.GetValidatorsByPowerIndexKey(validator) + require.True(t, keeper.ValidatorByPowerIndexExists(ctx, app.StakingKeeper, power)) + + // create a second validator keep it bonded + msgCreateValidator = NewTestMsgCreateValidator(validatorAddr3, PKs[2], initBond) + res, err = handler(ctx, msgCreateValidator) + require.NoError(t, err) + require.NotNil(t, res) + + // must end-block + updates = app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 1, len(updates)) + + // slash and jail the first validator + consAddr0 := sdk.ConsAddress(PKs[0].Address()) + app.StakingKeeper.Slash(ctx, consAddr0, 0, initPower, sdk.NewDecWithPrec(5, 1)) + app.StakingKeeper.Jail(ctx, consAddr0) + app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + + validator, found = app.StakingKeeper.GetValidator(ctx, validatorAddr) + require.True(t, found) + require.Equal(t, sdk.Unbonding, validator.Status) // ensure is unbonding + require.Equal(t, initBond.QuoRaw(2), validator.Tokens) // ensure tokens slashed + app.StakingKeeper.Unjail(ctx, consAddr0) + + // the old power record should have been deleted as the power changed + require.False(t, keeper.ValidatorByPowerIndexExists(ctx, app.StakingKeeper, power)) + + // but the new power record should have been created + validator, found = app.StakingKeeper.GetValidator(ctx, validatorAddr) + require.True(t, found) + power2 := staking.GetValidatorsByPowerIndexKey(validator) + require.True(t, keeper.ValidatorByPowerIndexExists(ctx, app.StakingKeeper, power2)) + + // now the new record power index should be the same as the original record + power3 := staking.GetValidatorsByPowerIndexKey(validator) + require.Equal(t, power2, power3) + + // unbond self-delegation + totalBond := validator.TokensFromShares(bond.GetShares()).TruncateInt() + unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, totalBond) + msgUndelegate := staking.NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) + + res, err = handler(ctx, msgUndelegate) + require.NoError(t, err) + require.NotNil(t, res) + + ts := &gogotypes.Timestamp{} + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) + + finishTime, err := gogotypes.TimestampFromProto(ts) + require.NoError(t, err) + + ctx = ctx.WithBlockTime(finishTime) + staking.EndBlocker(ctx, app.StakingKeeper) + staking.EndBlocker(ctx, app.StakingKeeper) + + // verify that by power key nolonger exists + _, found = app.StakingKeeper.GetValidator(ctx, validatorAddr) + require.False(t, found) + require.False(t, keeper.ValidatorByPowerIndexExists(ctx, app.StakingKeeper, power3)) +} + // //func TestDuplicatesMsgCreateValidator(t *testing.T) { // ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) From 59ecf11a12af73920e6270609ae1108174bcafd4 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Wed, 26 Feb 2020 11:36:37 +0100 Subject: [PATCH 221/529] refactor TestDuplicatesMsgCreateValidator --- x/staking/handler_test.go | 118 ++++++++++++++++++++------------------ 1 file changed, 61 insertions(+), 57 deletions(-) diff --git a/x/staking/handler_test.go b/x/staking/handler_test.go index 40d985cfeb3e..38d6c57b2b6b 100644 --- a/x/staking/handler_test.go +++ b/x/staking/handler_test.go @@ -3,6 +3,8 @@ package staking_test import ( "testing" + "github.com/stretchr/testify/assert" + gogotypes "github.com/gogo/protobuf/types" "github.com/stretchr/testify/require" @@ -124,63 +126,65 @@ func TestValidatorByPowerIndex(t *testing.T) { require.False(t, keeper.ValidatorByPowerIndexExists(ctx, app.StakingKeeper, power3)) } -// -//func TestDuplicatesMsgCreateValidator(t *testing.T) { -// ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) -// handler := NewHandler(keeper) -// -// addr1, addr2 := sdk.ValAddress(Addrs[0]), sdk.ValAddress(Addrs[1]) -// pk1, pk2 := PKs[0], PKs[1] -// -// valTokens := sdk.TokensFromConsensusPower(10) -// msgCreateValidator1 := NewTestMsgCreateValidator(addr1, pk1, valTokens) -// res, err := handler(ctx, msgCreateValidator1) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// keeper.ApplyAndReturnValidatorSetUpdates(ctx) -// -// validator, found := keeper.GetValidator(ctx, addr1) -// require.True(t, found) -// assert.Equal(t, sdk.Bonded, validator.Status) -// assert.Equal(t, addr1, validator.OperatorAddress) -// assert.Equal(t, pk1, validator.GetConsPubKey()) -// assert.Equal(t, valTokens, validator.BondedTokens()) -// assert.Equal(t, valTokens.ToDec(), validator.DelegatorShares) -// assert.Equal(t, Description{}, validator.Description) -// -// // two validators can't have the same operator address -// msgCreateValidator2 := NewTestMsgCreateValidator(addr1, pk2, valTokens) -// res, err = handler(ctx, msgCreateValidator2) -// require.Error(t, err) -// require.Nil(t, res) -// -// // two validators can't have the same pubkey -// msgCreateValidator3 := NewTestMsgCreateValidator(addr2, pk1, valTokens) -// res, err = handler(ctx, msgCreateValidator3) -// require.Error(t, err) -// require.Nil(t, res) -// -// // must have different pubkey and operator -// msgCreateValidator4 := NewTestMsgCreateValidator(addr2, pk2, valTokens) -// res, err = handler(ctx, msgCreateValidator4) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // must end-block -// updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) -// require.Equal(t, 1, len(updates)) -// -// validator, found = keeper.GetValidator(ctx, addr2) -// -// require.True(t, found) -// assert.Equal(t, sdk.Bonded, validator.Status) -// assert.Equal(t, addr2, validator.OperatorAddress) -// assert.Equal(t, pk2, validator.GetConsPubKey()) -// assert.True(sdk.IntEq(t, valTokens, validator.Tokens)) -// assert.True(sdk.DecEq(t, valTokens.ToDec(), validator.DelegatorShares)) -// assert.Equal(t, Description{}, validator.Description) -//} +func TestDuplicatesMsgCreateValidator(t *testing.T) { + initPower := int64(1000000) + app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 10, 10000000000000) + + handler := staking.NewHandler(app.StakingKeeper) + + addr1, addr2 := valAddrs[0], valAddrs[1] + pk1, pk2 := PKs[0], PKs[1] + + valTokens := sdk.TokensFromConsensusPower(10) + msgCreateValidator1 := NewTestMsgCreateValidator(addr1, pk1, valTokens) + res, err := handler(ctx, msgCreateValidator1) + require.NoError(t, err) + require.NotNil(t, res) + + app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + + validator, found := app.StakingKeeper.GetValidator(ctx, addr1) + require.True(t, found) + assert.Equal(t, sdk.Bonded, validator.Status) + assert.Equal(t, addr1, validator.OperatorAddress) + assert.Equal(t, pk1, validator.GetConsPubKey()) + assert.Equal(t, valTokens, validator.BondedTokens()) + assert.Equal(t, valTokens.ToDec(), validator.DelegatorShares) + assert.Equal(t, types.Description{}, validator.Description) + + // two validators can't have the same operator address + msgCreateValidator2 := NewTestMsgCreateValidator(addr1, pk2, valTokens) + res, err = handler(ctx, msgCreateValidator2) + require.Error(t, err) + require.Nil(t, res) + + // two validators can't have the same pubkey + msgCreateValidator3 := NewTestMsgCreateValidator(addr2, pk1, valTokens) + res, err = handler(ctx, msgCreateValidator3) + require.Error(t, err) + require.Nil(t, res) + + // must have different pubkey and operator + msgCreateValidator4 := NewTestMsgCreateValidator(addr2, pk2, valTokens) + res, err = handler(ctx, msgCreateValidator4) + require.NoError(t, err) + require.NotNil(t, res) + + // must end-block + updates := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 1, len(updates)) + + validator, found = app.StakingKeeper.GetValidator(ctx, addr2) + + require.True(t, found) + assert.Equal(t, sdk.Bonded, validator.Status) + assert.Equal(t, addr2, validator.OperatorAddress) + assert.Equal(t, pk2, validator.GetConsPubKey()) + assert.True(sdk.IntEq(t, valTokens, validator.Tokens)) + assert.True(sdk.DecEq(t, valTokens.ToDec(), validator.DelegatorShares)) + assert.Equal(t, types.Description{}, validator.Description) +} + // //func TestInvalidPubKeyTypeMsgCreateValidator(t *testing.T) { // ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) From 030f612b6c707dd3d7ac933786c23f1587b27805 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Wed, 26 Feb 2020 12:23:55 +0100 Subject: [PATCH 222/529] refactor TestInvalidPubKeyTypeMsgCreateValidator --- x/staking/handler_test.go | 51 ++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/x/staking/handler_test.go b/x/staking/handler_test.go index 38d6c57b2b6b..e4281e16b41e 100644 --- a/x/staking/handler_test.go +++ b/x/staking/handler_test.go @@ -3,6 +3,10 @@ package staking_test import ( "testing" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto/secp256k1" + tmtypes "github.com/tendermint/tendermint/types" + "github.com/stretchr/testify/assert" gogotypes "github.com/gogo/protobuf/types" @@ -185,28 +189,31 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) { assert.Equal(t, types.Description{}, validator.Description) } -// -//func TestInvalidPubKeyTypeMsgCreateValidator(t *testing.T) { -// ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) -// handler := NewHandler(keeper) -// -// addr := sdk.ValAddress(Addrs[0]) -// invalidPk := secp256k1.GenPrivKey().PubKey() -// -// // invalid pukKey type should not be allowed -// msgCreateValidator := NewTestMsgCreateValidator(addr, invalidPk, sdk.NewInt(10)) -// res, err := handler(ctx, msgCreateValidator) -// require.Error(t, err) -// require.Nil(t, res) -// -// ctx = ctx.WithConsensusParams(&abci.ConsensusParams{ -// Validator: &abci.ValidatorParams{PubKeyTypes: []string{tmtypes.ABCIPubKeyTypeSecp256k1}}, -// }) -// -// res, err = handler(ctx, msgCreateValidator) -// require.NoError(t, err) -// require.NotNil(t, res) -//} +func TestInvalidPubKeyTypeMsgCreateValidator(t *testing.T) { + app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, 1000, 1, 1000) + handler := staking.NewHandler(app.StakingKeeper) + ctx = ctx.WithConsensusParams(&abci.ConsensusParams{ + Validator: &abci.ValidatorParams{PubKeyTypes: []string{tmtypes.ABCIPubKeyTypeEd25519}}, + }) + + addr := valAddrs[0] + invalidPk := secp256k1.GenPrivKey().PubKey() + + // invalid pukKey type should not be allowed + msgCreateValidator := NewTestMsgCreateValidator(addr, invalidPk, sdk.NewInt(10)) + res, err := handler(ctx, msgCreateValidator) + require.Error(t, err) + require.Nil(t, res) + + ctx = ctx.WithConsensusParams(&abci.ConsensusParams{ + Validator: &abci.ValidatorParams{PubKeyTypes: []string{tmtypes.ABCIPubKeyTypeSecp256k1}}, + }) + + res, err = handler(ctx, msgCreateValidator) + require.NoError(t, err) + require.NotNil(t, res) +} + // //func TestLegacyValidatorDelegations(t *testing.T) { // ctx, _, _, keeper, _ := CreateTestInput(t, false, int64(1000)) From c314b93789af2206b6616010a415fdfbec91fa23 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Wed, 26 Feb 2020 13:28:18 +0100 Subject: [PATCH 223/529] temporary commit --- x/staking/common_test.go | 1 + x/staking/handler_test.go | 227 +++++++++++++++++++------------------- 2 files changed, 114 insertions(+), 114 deletions(-) diff --git a/x/staking/common_test.go b/x/staking/common_test.go index 35f27d32c3ae..9a3cfad368ea 100644 --- a/x/staking/common_test.go +++ b/x/staking/common_test.go @@ -84,6 +84,7 @@ func getBaseSimappWithCustomKeeper() (*codec.Codec, *simapp.SimApp, sdk.Context) app.SupplyKeeper, app.GetSubspace(staking.ModuleName), ) + app.StakingKeeper.SetParams(ctx, types.DefaultParams()) return codec.New(), app, ctx } diff --git a/x/staking/handler_test.go b/x/staking/handler_test.go index e4281e16b41e..2b1723f86a4a 100644 --- a/x/staking/handler_test.go +++ b/x/staking/handler_test.go @@ -214,118 +214,117 @@ func TestInvalidPubKeyTypeMsgCreateValidator(t *testing.T) { require.NotNil(t, res) } -// -//func TestLegacyValidatorDelegations(t *testing.T) { -// ctx, _, _, keeper, _ := CreateTestInput(t, false, int64(1000)) -// handler := NewHandler(keeper) -// -// bondAmount := sdk.TokensFromConsensusPower(10) -// valAddr := sdk.ValAddress(Addrs[0]) -// valConsPubKey, valConsAddr := PKs[0], sdk.ConsAddress(PKs[0].Address()) -// delAddr := Addrs[1] -// -// // create validator -// msgCreateVal := NewTestMsgCreateValidator(valAddr, valConsPubKey, bondAmount) -// res, err := handler(ctx, msgCreateVal) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // must end-block -// updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) -// require.Equal(t, 1, len(updates)) -// -// // verify the validator exists and has the correct attributes -// validator, found := keeper.GetValidator(ctx, valAddr) -// require.True(t, found) -// require.Equal(t, sdk.Bonded, validator.Status) -// require.Equal(t, bondAmount, validator.DelegatorShares.RoundInt()) -// require.Equal(t, bondAmount, validator.BondedTokens()) -// -// // delegate tokens to the validator -// msgDelegate := NewTestMsgDelegate(delAddr, valAddr, bondAmount) -// res, err = handler(ctx, msgDelegate) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // verify validator bonded shares -// validator, found = keeper.GetValidator(ctx, valAddr) -// require.True(t, found) -// require.Equal(t, bondAmount.MulRaw(2), validator.DelegatorShares.RoundInt()) -// require.Equal(t, bondAmount.MulRaw(2), validator.BondedTokens()) -// -// // unbond validator total self-delegations (which should jail the validator) -// unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, bondAmount) -// msgUndelegate := NewMsgUndelegate(sdk.AccAddress(valAddr), valAddr, unbondAmt) -// -// res, err = handler(ctx, msgUndelegate) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// ts := &gogotypes.Timestamp{} -// types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) -// -// finishTime, err := gogotypes.TimestampFromProto(ts) -// require.NoError(t, err) -// -// ctx = ctx.WithBlockTime(finishTime) -// EndBlocker(ctx, keeper) -// -// // verify the validator record still exists, is jailed, and has correct tokens -// validator, found = keeper.GetValidator(ctx, valAddr) -// require.True(t, found) -// require.True(t, validator.Jailed) -// require.Equal(t, bondAmount, validator.Tokens) -// -// // verify delegation still exists -// bond, found := keeper.GetDelegation(ctx, delAddr, valAddr) -// require.True(t, found) -// require.Equal(t, bondAmount, bond.Shares.RoundInt()) -// require.Equal(t, bondAmount, validator.DelegatorShares.RoundInt()) -// -// // verify the validator can still self-delegate -// msgSelfDelegate := NewTestMsgDelegate(sdk.AccAddress(valAddr), valAddr, bondAmount) -// res, err = handler(ctx, msgSelfDelegate) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // verify validator bonded shares -// validator, found = keeper.GetValidator(ctx, valAddr) -// require.True(t, found) -// require.Equal(t, bondAmount.MulRaw(2), validator.DelegatorShares.RoundInt()) -// require.Equal(t, bondAmount.MulRaw(2), validator.Tokens) -// -// // unjail the validator now that is has non-zero self-delegated shares -// keeper.Unjail(ctx, valConsAddr) -// -// // verify the validator can now accept delegations -// msgDelegate = NewTestMsgDelegate(delAddr, valAddr, bondAmount) -// res, err = handler(ctx, msgDelegate) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // verify validator bonded shares -// validator, found = keeper.GetValidator(ctx, valAddr) -// require.True(t, found) -// require.Equal(t, bondAmount.MulRaw(3), validator.DelegatorShares.RoundInt()) -// require.Equal(t, bondAmount.MulRaw(3), validator.Tokens) -// -// // verify new delegation -// bond, found = keeper.GetDelegation(ctx, delAddr, valAddr) -// require.True(t, found) -// require.Equal(t, bondAmount.MulRaw(2), bond.Shares.RoundInt()) -// require.Equal(t, bondAmount.MulRaw(3), validator.DelegatorShares.RoundInt()) -//} -// +func TestLegacyValidatorDelegations(t *testing.T) { + app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, 1000, 1, 100000000) + handler := staking.NewHandler(app.StakingKeeper) + + bondAmount := sdk.TokensFromConsensusPower(10) + valAddr := valAddrs[0] + valConsPubKey, valConsAddr := PKs[0], sdk.ConsAddress(PKs[0].Address()) + delAddr := delAddrs[0] + + // create validator + msgCreateVal := NewTestMsgCreateValidator(valAddr, valConsPubKey, bondAmount) + res, err := handler(ctx, msgCreateVal) + require.NoError(t, err) + require.NotNil(t, res) + + // must end-block + updates := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 1, len(updates)) + + // verify the validator exists and has the correct attributes + validator, found := app.StakingKeeper.GetValidator(ctx, valAddr) + require.True(t, found) + require.Equal(t, sdk.Bonded, validator.Status) + require.Equal(t, bondAmount, validator.DelegatorShares.RoundInt()) + require.Equal(t, bondAmount, validator.BondedTokens()) + + // delegate tokens to the validator + msgDelegate := NewTestMsgDelegate(delAddr, valAddr, bondAmount) + res, err = handler(ctx, msgDelegate) + require.NoError(t, err) + require.NotNil(t, res) + + // verify validator bonded shares + validator, found = app.StakingKeeper.GetValidator(ctx, valAddr) + require.True(t, found) + require.Equal(t, bondAmount.MulRaw(2), validator.DelegatorShares.RoundInt()) + require.Equal(t, bondAmount.MulRaw(2), validator.BondedTokens()) + + // unbond validator total self-delegations (which should jail the validator) + unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, bondAmount) + msgUndelegate := types.NewMsgUndelegate(sdk.AccAddress(valAddr), valAddr, unbondAmt) + + res, err = handler(ctx, msgUndelegate) + require.NoError(t, err) + require.NotNil(t, res) + + ts := &gogotypes.Timestamp{} + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) + + finishTime, err := gogotypes.TimestampFromProto(ts) + require.NoError(t, err) + + ctx = ctx.WithBlockTime(finishTime) + staking.EndBlocker(ctx, app.StakingKeeper) + + // verify the validator record still exists, is jailed, and has correct tokens + validator, found = app.StakingKeeper.GetValidator(ctx, valAddr) + require.True(t, found) + require.True(t, validator.Jailed) + require.Equal(t, bondAmount, validator.Tokens) + + // verify delegation still exists + bond, found := app.StakingKeeper.GetDelegation(ctx, delAddr, valAddr) + require.True(t, found) + require.Equal(t, bondAmount, bond.Shares.RoundInt()) + require.Equal(t, bondAmount, validator.DelegatorShares.RoundInt()) + + // verify the validator can still self-delegate + msgSelfDelegate := NewTestMsgDelegate(sdk.AccAddress(valAddr), valAddr, bondAmount) + res, err = handler(ctx, msgSelfDelegate) + require.NoError(t, err) + require.NotNil(t, res) + + // verify validator bonded shares + validator, found = app.StakingKeeper.GetValidator(ctx, valAddr) + require.True(t, found) + require.Equal(t, bondAmount.MulRaw(2), validator.DelegatorShares.RoundInt()) + require.Equal(t, bondAmount.MulRaw(2), validator.Tokens) + + // unjail the validator now that is has non-zero self-delegated shares + app.StakingKeeper.Unjail(ctx, valConsAddr) + + // verify the validator can now accept delegations + msgDelegate = NewTestMsgDelegate(delAddr, valAddr, bondAmount) + res, err = handler(ctx, msgDelegate) + require.NoError(t, err) + require.NotNil(t, res) + + // verify validator bonded shares + validator, found = app.StakingKeeper.GetValidator(ctx, valAddr) + require.True(t, found) + require.Equal(t, bondAmount.MulRaw(3), validator.DelegatorShares.RoundInt()) + require.Equal(t, bondAmount.MulRaw(3), validator.Tokens) + + // verify new delegation + bond, found = app.StakingKeeper.GetDelegation(ctx, delAddr, valAddr) + require.True(t, found) + require.Equal(t, bondAmount.MulRaw(2), bond.Shares.RoundInt()) + require.Equal(t, bondAmount.MulRaw(3), validator.DelegatorShares.RoundInt()) +} + //func TestIncrementsMsgDelegate(t *testing.T) { // initPower := int64(1000) // initBond := sdk.TokensFromConsensusPower(initPower) -// ctx, _, bk, keeper, _ := CreateTestInput(t, false, initPower) -// handler := NewHandler(keeper) +// app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, 10000000) +// handler := staking.NewHandler(app.StakingKeeper) // -// params := keeper.GetParams(ctx) +// params := app.StakingKeeper.GetParams(ctx) // // bondAmount := sdk.TokensFromConsensusPower(10) -// validatorAddr, delegatorAddr := sdk.ValAddress(Addrs[0]), Addrs[1] +// validatorAddr, delegatorAddr := valAddrs[0], delAddrs[1] // // // first create validator // msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], bondAmount) @@ -334,22 +333,22 @@ func TestInvalidPubKeyTypeMsgCreateValidator(t *testing.T) { // require.NotNil(t, res) // // // apply TM updates -// keeper.ApplyAndReturnValidatorSetUpdates(ctx) +// app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) // -// validator, found := keeper.GetValidator(ctx, validatorAddr) +// validator, found := app.StakingKeeper.GetValidator(ctx, validatorAddr) // require.True(t, found) // require.Equal(t, sdk.Bonded, validator.Status) // require.Equal(t, bondAmount, validator.DelegatorShares.RoundInt()) // require.Equal(t, bondAmount, validator.BondedTokens(), "validator: %v", validator) // -// _, found = keeper.GetDelegation(ctx, delegatorAddr, validatorAddr) +// _, found = app.StakingKeeper.GetDelegation(ctx, delegatorAddr, validatorAddr) // require.False(t, found) // -// bond, found := keeper.GetDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) +// bond, found := app.StakingKeeper.GetDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) // require.True(t, found) // require.Equal(t, bondAmount, bond.Shares.RoundInt()) // -// bondedTokens := keeper.TotalBondedTokens(ctx) +// bondedTokens := app.StakingKeeper.TotalBondedTokens(ctx) // require.Equal(t, bondAmount.Int64(), bondedTokens.Int64()) // // // just send the same msgbond multiple times @@ -363,9 +362,9 @@ func TestInvalidPubKeyTypeMsgCreateValidator(t *testing.T) { // require.NotNil(t, res) // // //Check that the accounts and the bond account have the appropriate values -// validator, found := keeper.GetValidator(ctx, validatorAddr) +// validator, found := app.StakingKeeper.GetValidator(ctx, validatorAddr) // require.True(t, found) -// bond, found := keeper.GetDelegation(ctx, delegatorAddr, validatorAddr) +// bond, found := app.StakingKeeper.GetDelegation(ctx, delegatorAddr, validatorAddr) // require.True(t, found) // // expBond := bondAmount.MulRaw(i + 1) @@ -374,7 +373,7 @@ func TestInvalidPubKeyTypeMsgCreateValidator(t *testing.T) { // // gotBond := bond.Shares.RoundInt() // gotDelegatorShares := validator.DelegatorShares.RoundInt() -// gotDelegatorAcc := bk.GetBalance(ctx, delegatorAddr, params.BondDenom).Amount +// gotDelegatorAcc := app.BankKeeper.GetBalance(ctx, delegatorAddr, params.BondDenom).Amount // // require.Equal(t, expBond, gotBond, // "i: %v\nexpBond: %v\ngotBond: %v\nvalidator: %v\nbond: %v\n", From b01185d34cfdec4d09386792434778b5f650613e Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 26 Feb 2020 08:39:02 -0500 Subject: [PATCH 224/529] Merge PR #5699: Bump github.com/rakyll/statik from 0.1.6 to 0.1.7 Bumps [github.com/rakyll/statik](https://github.com/rakyll/statik) from 0.1.6 to 0.1.7. - [Release notes](https://github.com/rakyll/statik/releases) - [Commits](https://github.com/rakyll/statik/compare/v0.1.6...v0.1.7) Signed-off-by: dependabot-preview[bot] --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index ad82af5e20f1..fab30fd4e3e4 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/mattn/go-isatty v0.0.12 github.com/pelletier/go-toml v1.6.0 github.com/pkg/errors v0.9.1 - github.com/rakyll/statik v0.1.6 + github.com/rakyll/statik v0.1.7 github.com/regen-network/cosmos-proto v0.1.1-0.20200213154359-02baa11ea7c2 github.com/spf13/afero v1.2.1 // indirect github.com/spf13/cobra v0.0.6 diff --git a/go.sum b/go.sum index 55185f3f0801..1a2e981e9f41 100644 --- a/go.sum +++ b/go.sum @@ -196,6 +196,8 @@ github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7z github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rakyll/statik v0.1.6 h1:uICcfUXpgqtw2VopbIncslhAmE5hwc4g20TEyEENBNs= github.com/rakyll/statik v0.1.6/go.mod h1:OEi9wJV/fMUAGx1eNjq75DKDsJVuEv1U0oYdX6GX8Zs= +github.com/rakyll/statik v0.1.7 h1:OF3QCZUuyPxuGEP7B4ypUa7sB/iHtqOTDYZXGM8KOdQ= +github.com/rakyll/statik v0.1.7/go.mod h1:AlZONWzMtEnMs7W4e/1LURLiI49pIMmp6V9Unghqrcc= github.com/rcrowley/go-metrics v0.0.0-20180503174638-e2704e165165 h1:nkcn14uNmFEuGCb2mBZbBb24RdNRL08b/wb+xBOYpuk= github.com/rcrowley/go-metrics v0.0.0-20180503174638-e2704e165165/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/regen-network/cosmos-proto v0.1.1-0.20200213154359-02baa11ea7c2 h1:jQK1YoH972Aptd22YKgtNu5jM2X2xMGkyIENOAc71to= From ee2180528222e85f95aa88bd228b41aeed703ef6 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Wed, 26 Feb 2020 14:52:34 +0100 Subject: [PATCH 225/529] refactor TestLegacyValidatorDelegations to use simapp --- x/staking/handler_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x/staking/handler_test.go b/x/staking/handler_test.go index 2b1723f86a4a..e62b07663a99 100644 --- a/x/staking/handler_test.go +++ b/x/staking/handler_test.go @@ -215,13 +215,13 @@ func TestInvalidPubKeyTypeMsgCreateValidator(t *testing.T) { } func TestLegacyValidatorDelegations(t *testing.T) { - app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, 1000, 1, 100000000) + app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, 1000, 2, 100000000) handler := staking.NewHandler(app.StakingKeeper) bondAmount := sdk.TokensFromConsensusPower(10) valAddr := valAddrs[0] valConsPubKey, valConsAddr := PKs[0], sdk.ConsAddress(PKs[0].Address()) - delAddr := delAddrs[0] + delAddr := delAddrs[1] // create validator msgCreateVal := NewTestMsgCreateValidator(valAddr, valConsPubKey, bondAmount) From 201d1cdc34aa655003404ff55d13a570e8a502a8 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 26 Feb 2020 08:56:17 -0500 Subject: [PATCH 226/529] Merge PR #5701: Bump github.com/tendermint/tm-db from 0.4.0 to 0.4.1 Bumps [github.com/tendermint/tm-db](https://github.com/tendermint/tm-db) from 0.4.0 to 0.4.1. - [Release notes](https://github.com/tendermint/tm-db/releases) - [Changelog](https://github.com/tendermint/tm-db/blob/master/CHANGELOG.md) - [Commits](https://github.com/tendermint/tm-db/compare/v0.4.0...v0.4.1) Signed-off-by: dependabot-preview[bot] Co-authored-by: Alexander Bezobchuk --- go.mod | 2 +- go.sum | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index fab30fd4e3e4..1ebba790a592 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( github.com/tendermint/go-amino v0.15.1 github.com/tendermint/iavl v0.13.0 github.com/tendermint/tendermint v0.33.1 - github.com/tendermint/tm-db v0.4.0 + github.com/tendermint/tm-db v0.4.1 gopkg.in/yaml.v2 v2.2.8 ) diff --git a/go.sum b/go.sum index 1a2e981e9f41..c4f48196d418 100644 --- a/go.sum +++ b/go.sum @@ -257,6 +257,8 @@ github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d h1:gZZadD8H+fF+ github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA= github.com/tecbot/gorocksdb v0.0.0-20191017175515-d217d93fd4c5 h1:gVwAW5OwaZlDB5/CfqcGFM9p9C+KxvQKyNOltQ8orj0= github.com/tecbot/gorocksdb v0.0.0-20191017175515-d217d93fd4c5/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8= +github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c h1:g+WoO5jjkqGAzHWCjJB1zZfXPIAaDpzXIEJ0eS6B5Ok= +github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8= github.com/tendermint/btcd v0.1.1 h1:0VcxPfflS2zZ3RiOAHkBiFUcPvbtRj5O7zHmcJWHV7s= github.com/tendermint/btcd v0.1.1/go.mod h1:DC6/m53jtQzr/NFmMNEu0rxf18/ktVoVtMrnDD5pN+U= github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 h1:hqAk8riJvK4RMWx1aInLzndwxKalgi5rTqgfXxOxbEI= @@ -271,6 +273,8 @@ github.com/tendermint/tendermint v0.33.1 h1:8f68LUBz8yhISZvaLFP4siXXrLWsWeoYfelb github.com/tendermint/tendermint v0.33.1/go.mod h1:fBOKyrlXOETqQ+heL8x/TZgSdmItON54csyabvktBp0= github.com/tendermint/tm-db v0.4.0 h1:iPbCcLbf4nwDFhS39Zo1lpdS1X/cT9CkTlUx17FHQgA= github.com/tendermint/tm-db v0.4.0/go.mod h1:+Cwhgowrf7NBGXmsqFMbwEtbo80XmyrlY5Jsk95JubQ= +github.com/tendermint/tm-db v0.4.1 h1:TvX7JWjJOVZ+N3y+I86wddrGttOdMmmBxXcu0/Y7ZJ0= +github.com/tendermint/tm-db v0.4.1/go.mod h1:JsJ6qzYkCGiGwm5GHl/H5GLI9XLb6qZX7PRe425dHAY= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= From 3f319c257829e7be66ab3671fa75ba1530434450 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Wed, 26 Feb 2020 15:04:40 +0100 Subject: [PATCH 227/529] refactor TestIncrementsMsgDelegate --- x/staking/handler_test.go | 143 +++++++++++++++++++------------------- 1 file changed, 72 insertions(+), 71 deletions(-) diff --git a/x/staking/handler_test.go b/x/staking/handler_test.go index e62b07663a99..da1c1e6845a6 100644 --- a/x/staking/handler_test.go +++ b/x/staking/handler_test.go @@ -315,77 +315,78 @@ func TestLegacyValidatorDelegations(t *testing.T) { require.Equal(t, bondAmount.MulRaw(3), validator.DelegatorShares.RoundInt()) } -//func TestIncrementsMsgDelegate(t *testing.T) { -// initPower := int64(1000) -// initBond := sdk.TokensFromConsensusPower(initPower) -// app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, 10000000) -// handler := staking.NewHandler(app.StakingKeeper) -// -// params := app.StakingKeeper.GetParams(ctx) -// -// bondAmount := sdk.TokensFromConsensusPower(10) -// validatorAddr, delegatorAddr := valAddrs[0], delAddrs[1] -// -// // first create validator -// msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], bondAmount) -// res, err := handler(ctx, msgCreateValidator) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // apply TM updates -// app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) -// -// validator, found := app.StakingKeeper.GetValidator(ctx, validatorAddr) -// require.True(t, found) -// require.Equal(t, sdk.Bonded, validator.Status) -// require.Equal(t, bondAmount, validator.DelegatorShares.RoundInt()) -// require.Equal(t, bondAmount, validator.BondedTokens(), "validator: %v", validator) -// -// _, found = app.StakingKeeper.GetDelegation(ctx, delegatorAddr, validatorAddr) -// require.False(t, found) -// -// bond, found := app.StakingKeeper.GetDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) -// require.True(t, found) -// require.Equal(t, bondAmount, bond.Shares.RoundInt()) -// -// bondedTokens := app.StakingKeeper.TotalBondedTokens(ctx) -// require.Equal(t, bondAmount.Int64(), bondedTokens.Int64()) -// -// // just send the same msgbond multiple times -// msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, bondAmount) -// -// for i := int64(0); i < 5; i++ { -// ctx = ctx.WithBlockHeight(i) -// -// res, err := handler(ctx, msgDelegate) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// //Check that the accounts and the bond account have the appropriate values -// validator, found := app.StakingKeeper.GetValidator(ctx, validatorAddr) -// require.True(t, found) -// bond, found := app.StakingKeeper.GetDelegation(ctx, delegatorAddr, validatorAddr) -// require.True(t, found) -// -// expBond := bondAmount.MulRaw(i + 1) -// expDelegatorShares := bondAmount.MulRaw(i + 2) // (1 self delegation) -// expDelegatorAcc := initBond.Sub(expBond) -// -// gotBond := bond.Shares.RoundInt() -// gotDelegatorShares := validator.DelegatorShares.RoundInt() -// gotDelegatorAcc := app.BankKeeper.GetBalance(ctx, delegatorAddr, params.BondDenom).Amount -// -// require.Equal(t, expBond, gotBond, -// "i: %v\nexpBond: %v\ngotBond: %v\nvalidator: %v\nbond: %v\n", -// i, expBond, gotBond, validator, bond) -// require.Equal(t, expDelegatorShares, gotDelegatorShares, -// "i: %v\nexpDelegatorShares: %v\ngotDelegatorShares: %v\nvalidator: %v\nbond: %v\n", -// i, expDelegatorShares, gotDelegatorShares, validator, bond) -// require.Equal(t, expDelegatorAcc, gotDelegatorAcc, -// "i: %v\nexpDelegatorAcc: %v\ngotDelegatorAcc: %v\nvalidator: %v\nbond: %v\n", -// i, expDelegatorAcc, gotDelegatorAcc, validator, bond) -// } -//} +func TestIncrementsMsgDelegate(t *testing.T) { + initPower := int64(1000) + initBond := sdk.TokensFromConsensusPower(initPower) + app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, 1000000000) + handler := staking.NewHandler(app.StakingKeeper) + + params := app.StakingKeeper.GetParams(ctx) + + bondAmount := sdk.TokensFromConsensusPower(10) + validatorAddr, delegatorAddr := valAddrs[0], delAddrs[1] + + // first create validator + msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], bondAmount) + res, err := handler(ctx, msgCreateValidator) + require.NoError(t, err) + require.NotNil(t, res) + + // apply TM updates + app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + + validator, found := app.StakingKeeper.GetValidator(ctx, validatorAddr) + require.True(t, found) + require.Equal(t, sdk.Bonded, validator.Status) + require.Equal(t, bondAmount, validator.DelegatorShares.RoundInt()) + require.Equal(t, bondAmount, validator.BondedTokens(), "validator: %v", validator) + + _, found = app.StakingKeeper.GetDelegation(ctx, delegatorAddr, validatorAddr) + require.False(t, found) + + bond, found := app.StakingKeeper.GetDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) + require.True(t, found) + require.Equal(t, bondAmount, bond.Shares.RoundInt()) + + bondedTokens := app.StakingKeeper.TotalBondedTokens(ctx) + require.Equal(t, bondAmount.Int64(), bondedTokens.Int64()) + + // just send the same msgbond multiple times + msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, bondAmount) + + for i := int64(0); i < 5; i++ { + ctx = ctx.WithBlockHeight(i) + + res, err := handler(ctx, msgDelegate) + require.NoError(t, err) + require.NotNil(t, res) + + //Check that the accounts and the bond account have the appropriate values + validator, found := app.StakingKeeper.GetValidator(ctx, validatorAddr) + require.True(t, found) + bond, found := app.StakingKeeper.GetDelegation(ctx, delegatorAddr, validatorAddr) + require.True(t, found) + + expBond := bondAmount.MulRaw(i + 1) + expDelegatorShares := bondAmount.MulRaw(i + 2) // (1 self delegation) + expDelegatorAcc := initBond.Sub(expBond) + + gotBond := bond.Shares.RoundInt() + gotDelegatorShares := validator.DelegatorShares.RoundInt() + gotDelegatorAcc := app.BankKeeper.GetBalance(ctx, delegatorAddr, params.BondDenom).Amount + + require.Equal(t, expBond, gotBond, + "i: %v\nexpBond: %v\ngotBond: %v\nvalidator: %v\nbond: %v\n", + i, expBond, gotBond, validator, bond) + require.Equal(t, expDelegatorShares, gotDelegatorShares, + "i: %v\nexpDelegatorShares: %v\ngotDelegatorShares: %v\nvalidator: %v\nbond: %v\n", + i, expDelegatorShares, gotDelegatorShares, validator, bond) + require.Equal(t, expDelegatorAcc, gotDelegatorAcc, + "i: %v\nexpDelegatorAcc: %v\ngotDelegatorAcc: %v\nvalidator: %v\nbond: %v\n", + i, expDelegatorAcc, gotDelegatorAcc, validator, bond) + } +} + // //func TestEditValidatorDecreaseMinSelfDelegation(t *testing.T) { // validatorAddr := sdk.ValAddress(Addrs[0]) From 8ecd5b895426cd27f89ada22354c66d30f0c35df Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Wed, 26 Feb 2020 15:06:52 +0100 Subject: [PATCH 228/529] refactor next --- x/staking/handler_test.go | 69 +++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/x/staking/handler_test.go b/x/staking/handler_test.go index da1c1e6845a6..c98b54d11162 100644 --- a/x/staking/handler_test.go +++ b/x/staking/handler_test.go @@ -387,41 +387,40 @@ func TestIncrementsMsgDelegate(t *testing.T) { } } -// -//func TestEditValidatorDecreaseMinSelfDelegation(t *testing.T) { -// validatorAddr := sdk.ValAddress(Addrs[0]) -// -// initPower := int64(100) -// initBond := sdk.TokensFromConsensusPower(100) -// ctx, _, _, keeper, _ := CreateTestInput(t, false, initPower) -// handler := NewHandler(keeper) -// -// // create validator -// msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], initBond) -// msgCreateValidator.MinSelfDelegation = sdk.NewInt(2) -// res, err := handler(ctx, msgCreateValidator) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // must end-block -// updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) -// require.Equal(t, 1, len(updates)) -// -// // verify the self-delegation exists -// bond, found := keeper.GetDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) -// require.True(t, found) -// gotBond := bond.Shares.RoundInt() -// require.Equal(t, initBond, gotBond, -// "initBond: %v\ngotBond: %v\nbond: %v\n", -// initBond, gotBond, bond) -// -// newMinSelfDelegation := sdk.OneInt() -// msgEditValidator := NewMsgEditValidator(validatorAddr, Description{}, nil, &newMinSelfDelegation) -// res, err = handler(ctx, msgEditValidator) -// require.Error(t, err) -// require.Nil(t, res) -//} -// +func TestEditValidatorDecreaseMinSelfDelegation(t *testing.T) { + initPower := int64(100) + initBond := sdk.TokensFromConsensusPower(100) + app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 1, 1000000000) + + validatorAddr := valAddrs[0] + handler := staking.NewHandler(app.StakingKeeper) + + // create validator + msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], initBond) + msgCreateValidator.MinSelfDelegation = sdk.NewInt(2) + res, err := handler(ctx, msgCreateValidator) + require.NoError(t, err) + require.NotNil(t, res) + + // must end-block + updates := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 1, len(updates)) + + // verify the self-delegation exists + bond, found := app.StakingKeeper.GetDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) + require.True(t, found) + gotBond := bond.Shares.RoundInt() + require.Equal(t, initBond, gotBond, + "initBond: %v\ngotBond: %v\nbond: %v\n", + initBond, gotBond, bond) + + newMinSelfDelegation := sdk.OneInt() + msgEditValidator := types.NewMsgEditValidator(validatorAddr, types.Description{}, nil, &newMinSelfDelegation) + res, err = handler(ctx, msgEditValidator) + require.Error(t, err) + require.Nil(t, res) +} + //func TestEditValidatorIncreaseMinSelfDelegationBeyondCurrentBond(t *testing.T) { // validatorAddr := sdk.ValAddress(Addrs[0]) // From a07ed83dd250aeb1fb319d356bc4767744088173 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Wed, 26 Feb 2020 15:08:43 +0100 Subject: [PATCH 229/529] refactor TestEditValidatorIncreaseMinSelfDelegationBeyondCurrentBond --- x/staking/handler_test.go | 69 ++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/x/staking/handler_test.go b/x/staking/handler_test.go index c98b54d11162..9a8d21dee009 100644 --- a/x/staking/handler_test.go +++ b/x/staking/handler_test.go @@ -421,40 +421,41 @@ func TestEditValidatorDecreaseMinSelfDelegation(t *testing.T) { require.Nil(t, res) } -//func TestEditValidatorIncreaseMinSelfDelegationBeyondCurrentBond(t *testing.T) { -// validatorAddr := sdk.ValAddress(Addrs[0]) -// -// initPower := int64(100) -// initBond := sdk.TokensFromConsensusPower(100) -// ctx, _, _, keeper, _ := CreateTestInput(t, false, initPower) -// handler := NewHandler(keeper) -// -// // create validator -// msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], initBond) -// msgCreateValidator.MinSelfDelegation = sdk.NewInt(2) -// res, err := handler(ctx, msgCreateValidator) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // must end-block -// updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) -// require.Equal(t, 1, len(updates)) -// -// // verify the self-delegation exists -// bond, found := keeper.GetDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) -// require.True(t, found) -// gotBond := bond.Shares.RoundInt() -// require.Equal(t, initBond, gotBond, -// "initBond: %v\ngotBond: %v\nbond: %v\n", -// initBond, gotBond, bond) -// -// newMinSelfDelegation := initBond.Add(sdk.OneInt()) -// msgEditValidator := NewMsgEditValidator(validatorAddr, Description{}, nil, &newMinSelfDelegation) -// res, err = handler(ctx, msgEditValidator) -// require.Error(t, err) -// require.Nil(t, res) -//} -// +func TestEditValidatorIncreaseMinSelfDelegationBeyondCurrentBond(t *testing.T) { + initPower := int64(100) + initBond := sdk.TokensFromConsensusPower(100) + + app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, 1000000000) + validatorAddr := valAddrs[0] + + handler := staking.NewHandler(app.StakingKeeper) + + // create validator + msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], initBond) + msgCreateValidator.MinSelfDelegation = sdk.NewInt(2) + res, err := handler(ctx, msgCreateValidator) + require.NoError(t, err) + require.NotNil(t, res) + + // must end-block + updates := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 1, len(updates)) + + // verify the self-delegation exists + bond, found := app.StakingKeeper.GetDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) + require.True(t, found) + gotBond := bond.Shares.RoundInt() + require.Equal(t, initBond, gotBond, + "initBond: %v\ngotBond: %v\nbond: %v\n", + initBond, gotBond, bond) + + newMinSelfDelegation := initBond.Add(sdk.OneInt()) + msgEditValidator := types.NewMsgEditValidator(validatorAddr, types.Description{}, nil, &newMinSelfDelegation) + res, err = handler(ctx, msgEditValidator) + require.Error(t, err) + require.Nil(t, res) +} + //func TestIncrementsMsgUnbond(t *testing.T) { // initPower := int64(1000) // initBond := sdk.TokensFromConsensusPower(initPower) From 46d62ebfa96ed8a292a4a33634036390c60e345e Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Wed, 26 Feb 2020 15:13:08 +0100 Subject: [PATCH 230/529] refactor TestIncrementsMsgUnbond --- x/staking/handler_test.go | 219 +++++++++++++++++++------------------- 1 file changed, 110 insertions(+), 109 deletions(-) diff --git a/x/staking/handler_test.go b/x/staking/handler_test.go index 9a8d21dee009..e15768cee4d5 100644 --- a/x/staking/handler_test.go +++ b/x/staking/handler_test.go @@ -456,115 +456,116 @@ func TestEditValidatorIncreaseMinSelfDelegationBeyondCurrentBond(t *testing.T) { require.Nil(t, res) } -//func TestIncrementsMsgUnbond(t *testing.T) { -// initPower := int64(1000) -// initBond := sdk.TokensFromConsensusPower(initPower) -// ctx, _, bk, keeper, _ := CreateTestInput(t, false, initPower) -// handler := NewHandler(keeper) -// -// params := keeper.GetParams(ctx) -// denom := params.BondDenom -// -// // create validator, delegate -// validatorAddr, delegatorAddr := sdk.ValAddress(Addrs[0]), Addrs[1] -// -// msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], initBond) -// res, err := handler(ctx, msgCreateValidator) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // initial balance -// amt1 := bk.GetBalance(ctx, delegatorAddr, denom).Amount -// -// msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, initBond) -// res, err = handler(ctx, msgDelegate) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // balance should have been subtracted after delegation -// amt2 := bk.GetBalance(ctx, delegatorAddr, denom).Amount -// require.True(sdk.IntEq(t, amt1.Sub(initBond), amt2)) -// -// // apply TM updates -// keeper.ApplyAndReturnValidatorSetUpdates(ctx) -// -// validator, found := keeper.GetValidator(ctx, validatorAddr) -// require.True(t, found) -// require.Equal(t, initBond.MulRaw(2), validator.DelegatorShares.RoundInt()) -// require.Equal(t, initBond.MulRaw(2), validator.BondedTokens()) -// -// // just send the same msgUnbond multiple times -// // TODO use decimals here -// unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) -// msgUndelegate := NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) -// numUnbonds := int64(5) -// -// for i := int64(0); i < numUnbonds; i++ { -// res, err := handler(ctx, msgUndelegate) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// ts := &gogotypes.Timestamp{} -// types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) -// -// finishTime, err := gogotypes.TimestampFromProto(ts) -// require.NoError(t, err) -// -// ctx = ctx.WithBlockTime(finishTime) -// EndBlocker(ctx, keeper) -// -// // check that the accounts and the bond account have the appropriate values -// validator, found = keeper.GetValidator(ctx, validatorAddr) -// require.True(t, found) -// bond, found := keeper.GetDelegation(ctx, delegatorAddr, validatorAddr) -// require.True(t, found) -// -// expBond := initBond.Sub(unbondAmt.Amount.Mul(sdk.NewInt(i + 1))) -// expDelegatorShares := initBond.MulRaw(2).Sub(unbondAmt.Amount.Mul(sdk.NewInt(i + 1))) -// expDelegatorAcc := initBond.Sub(expBond) -// -// gotBond := bond.Shares.RoundInt() -// gotDelegatorShares := validator.DelegatorShares.RoundInt() -// gotDelegatorAcc := bk.GetBalance(ctx, delegatorAddr, params.BondDenom).Amount -// -// require.Equal(t, expBond.Int64(), gotBond.Int64(), -// "i: %v\nexpBond: %v\ngotBond: %v\nvalidator: %v\nbond: %v\n", -// i, expBond, gotBond, validator, bond) -// require.Equal(t, expDelegatorShares.Int64(), gotDelegatorShares.Int64(), -// "i: %v\nexpDelegatorShares: %v\ngotDelegatorShares: %v\nvalidator: %v\nbond: %v\n", -// i, expDelegatorShares, gotDelegatorShares, validator, bond) -// require.Equal(t, expDelegatorAcc.Int64(), gotDelegatorAcc.Int64(), -// "i: %v\nexpDelegatorAcc: %v\ngotDelegatorAcc: %v\nvalidator: %v\nbond: %v\n", -// i, expDelegatorAcc, gotDelegatorAcc, validator, bond) -// } -// -// // these are more than we have bonded now -// errorCases := []sdk.Int{ -// //1<<64 - 1, // more than int64 power -// //1<<63 + 1, // more than int64 power -// sdk.TokensFromConsensusPower(1<<63 - 1), -// sdk.TokensFromConsensusPower(1 << 31), -// initBond, -// } -// -// for _, c := range errorCases { -// unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, c) -// msgUndelegate := NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) -// res, err = handler(ctx, msgUndelegate) -// require.Error(t, err) -// require.Nil(t, res) -// } -// -// leftBonded := initBond.Sub(unbondAmt.Amount.Mul(sdk.NewInt(numUnbonds))) -// -// // should be able to unbond remaining -// unbondAmt = sdk.NewCoin(sdk.DefaultBondDenom, leftBonded) -// msgUndelegate = NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) -// res, err = handler(ctx, msgUndelegate) -// require.NoError(t, err, "msgUnbond: %v\nshares: %s\nleftBonded: %s\n", msgUndelegate, unbondAmt, leftBonded) -// require.NotNil(t, res, "msgUnbond: %v\nshares: %s\nleftBonded: %s\n", msgUndelegate, unbondAmt, leftBonded) -//} -// +func TestIncrementsMsgUnbond(t *testing.T) { + initPower := int64(1000) + initBond := sdk.TokensFromConsensusPower(initPower) + + app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, 1000000000) + handler := staking.NewHandler(app.StakingKeeper) + + params := app.StakingKeeper.GetParams(ctx) + denom := params.BondDenom + + // create validator, delegate + validatorAddr, delegatorAddr := valAddrs[0], delAddrs[1] + + msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], initBond) + res, err := handler(ctx, msgCreateValidator) + require.NoError(t, err) + require.NotNil(t, res) + + // initial balance + amt1 := app.BankKeeper.GetBalance(ctx, delegatorAddr, denom).Amount + + msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, initBond) + res, err = handler(ctx, msgDelegate) + require.NoError(t, err) + require.NotNil(t, res) + + // balance should have been subtracted after delegation + amt2 := app.BankKeeper.GetBalance(ctx, delegatorAddr, denom).Amount + require.True(sdk.IntEq(t, amt1.Sub(initBond), amt2)) + + // apply TM updates + app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + + validator, found := app.StakingKeeper.GetValidator(ctx, validatorAddr) + require.True(t, found) + require.Equal(t, initBond.MulRaw(2), validator.DelegatorShares.RoundInt()) + require.Equal(t, initBond.MulRaw(2), validator.BondedTokens()) + + // just send the same msgUnbond multiple times + // TODO use decimals here + unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) + msgUndelegate := types.NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) + numUnbonds := int64(5) + + for i := int64(0); i < numUnbonds; i++ { + res, err := handler(ctx, msgUndelegate) + require.NoError(t, err) + require.NotNil(t, res) + + ts := &gogotypes.Timestamp{} + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) + + finishTime, err := gogotypes.TimestampFromProto(ts) + require.NoError(t, err) + + ctx = ctx.WithBlockTime(finishTime) + staking.EndBlocker(ctx, app.StakingKeeper) + + // check that the accounts and the bond account have the appropriate values + validator, found = app.StakingKeeper.GetValidator(ctx, validatorAddr) + require.True(t, found) + bond, found := app.StakingKeeper.GetDelegation(ctx, delegatorAddr, validatorAddr) + require.True(t, found) + + expBond := initBond.Sub(unbondAmt.Amount.Mul(sdk.NewInt(i + 1))) + expDelegatorShares := initBond.MulRaw(2).Sub(unbondAmt.Amount.Mul(sdk.NewInt(i + 1))) + expDelegatorAcc := initBond.Sub(expBond) + + gotBond := bond.Shares.RoundInt() + gotDelegatorShares := validator.DelegatorShares.RoundInt() + gotDelegatorAcc := app.BankKeeper.GetBalance(ctx, delegatorAddr, params.BondDenom).Amount + + require.Equal(t, expBond.Int64(), gotBond.Int64(), + "i: %v\nexpBond: %v\ngotBond: %v\nvalidator: %v\nbond: %v\n", + i, expBond, gotBond, validator, bond) + require.Equal(t, expDelegatorShares.Int64(), gotDelegatorShares.Int64(), + "i: %v\nexpDelegatorShares: %v\ngotDelegatorShares: %v\nvalidator: %v\nbond: %v\n", + i, expDelegatorShares, gotDelegatorShares, validator, bond) + require.Equal(t, expDelegatorAcc.Int64(), gotDelegatorAcc.Int64(), + "i: %v\nexpDelegatorAcc: %v\ngotDelegatorAcc: %v\nvalidator: %v\nbond: %v\n", + i, expDelegatorAcc, gotDelegatorAcc, validator, bond) + } + + // these are more than we have bonded now + errorCases := []sdk.Int{ + //1<<64 - 1, // more than int64 power + //1<<63 + 1, // more than int64 power + sdk.TokensFromConsensusPower(1<<63 - 1), + sdk.TokensFromConsensusPower(1 << 31), + initBond, + } + + for _, c := range errorCases { + unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, c) + msgUndelegate := types.NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) + res, err = handler(ctx, msgUndelegate) + require.Error(t, err) + require.Nil(t, res) + } + + leftBonded := initBond.Sub(unbondAmt.Amount.Mul(sdk.NewInt(numUnbonds))) + + // should be able to unbond remaining + unbondAmt = sdk.NewCoin(sdk.DefaultBondDenom, leftBonded) + msgUndelegate = types.NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) + res, err = handler(ctx, msgUndelegate) + require.NoError(t, err, "msgUnbond: %v\nshares: %s\nleftBonded: %s\n", msgUndelegate, unbondAmt, leftBonded) + require.NotNil(t, res, "msgUnbond: %v\nshares: %s\nleftBonded: %s\n", msgUndelegate, unbondAmt, leftBonded) +} + //func TestMultipleMsgCreateValidator(t *testing.T) { // initPower := int64(1000) // initTokens := sdk.TokensFromConsensusPower(initPower) From d251f6436ef4751a3bf1315a6886d9c6366fd44a Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Wed, 26 Feb 2020 15:17:31 +0100 Subject: [PATCH 231/529] refator TestMultipleMsgCreateValidator --- x/staking/handler_test.go | 164 +++++++++++++++++++------------------- 1 file changed, 83 insertions(+), 81 deletions(-) diff --git a/x/staking/handler_test.go b/x/staking/handler_test.go index e15768cee4d5..2a9b4bc43a06 100644 --- a/x/staking/handler_test.go +++ b/x/staking/handler_test.go @@ -2,6 +2,7 @@ package staking_test import ( "testing" + "time" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto/secp256k1" @@ -566,87 +567,88 @@ func TestIncrementsMsgUnbond(t *testing.T) { require.NotNil(t, res, "msgUnbond: %v\nshares: %s\nleftBonded: %s\n", msgUndelegate, unbondAmt, leftBonded) } -//func TestMultipleMsgCreateValidator(t *testing.T) { -// initPower := int64(1000) -// initTokens := sdk.TokensFromConsensusPower(initPower) -// ctx, _, bk, keeper, _ := CreateTestInput(t, false, initPower) -// handler := NewHandler(keeper) -// -// params := keeper.GetParams(ctx) -// blockTime := time.Now().UTC() -// ctx = ctx.WithBlockTime(blockTime) -// -// validatorAddrs := []sdk.ValAddress{ -// sdk.ValAddress(Addrs[0]), -// sdk.ValAddress(Addrs[1]), -// sdk.ValAddress(Addrs[2]), -// } -// delegatorAddrs := []sdk.AccAddress{ -// Addrs[0], -// Addrs[1], -// Addrs[2], -// } -// -// // bond them all -// for i, validatorAddr := range validatorAddrs { -// valTokens := sdk.TokensFromConsensusPower(10) -// msgCreateValidatorOnBehalfOf := NewTestMsgCreateValidator(validatorAddr, PKs[i], valTokens) -// -// res, err := handler(ctx, msgCreateValidatorOnBehalfOf) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // verify that the account is bonded -// validators := keeper.GetValidators(ctx, 100) -// require.Equal(t, (i + 1), len(validators)) -// -// val := validators[i] -// balanceExpd := initTokens.Sub(valTokens) -// balanceGot := bk.GetBalance(ctx, delegatorAddrs[i], params.BondDenom).Amount -// -// require.Equal(t, i+1, len(validators), "expected %d validators got %d, validators: %v", i+1, len(validators), validators) -// require.Equal(t, valTokens, val.DelegatorShares.RoundInt(), "expected %d shares, got %d", 10, val.DelegatorShares) -// require.Equal(t, balanceExpd, balanceGot, "expected account to have %d, got %d", balanceExpd, balanceGot) -// } -// -// EndBlocker(ctx, keeper) -// -// // unbond them all by removing delegation -// for i, validatorAddr := range validatorAddrs { -// _, found := keeper.GetValidator(ctx, validatorAddr) -// require.True(t, found) -// -// unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(10)) -// msgUndelegate := NewMsgUndelegate(delegatorAddrs[i], validatorAddr, unbondAmt) // remove delegation -// res, err := handler(ctx, msgUndelegate) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// ts := &gogotypes.Timestamp{} -// types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) -// -// _, err = gogotypes.TimestampFromProto(ts) -// require.NoError(t, err) -// -// // adds validator into unbonding queue -// EndBlocker(ctx, keeper) -// -// // removes validator from queue and set -// EndBlocker(ctx.WithBlockTime(blockTime.Add(params.UnbondingTime)), keeper) -// -// // Check that the validator is deleted from state -// validators := keeper.GetValidators(ctx, 100) -// require.Equal(t, len(validatorAddrs)-(i+1), len(validators), -// "expected %d validators got %d", len(validatorAddrs)-(i+1), len(validators)) -// -// _, found = keeper.GetValidator(ctx, validatorAddr) -// require.False(t, found) -// -// gotBalance := bk.GetBalance(ctx, delegatorAddrs[i], params.BondDenom).Amount -// require.Equal(t, initTokens, gotBalance, "expected account to have %d, got %d", initTokens, gotBalance) -// } -//} -// +func TestMultipleMsgCreateValidator(t *testing.T) { + initPower := int64(1000) + initTokens := sdk.TokensFromConsensusPower(initPower) + app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 3, 1000000000) + + handler := staking.NewHandler(app.StakingKeeper) + + params := app.StakingKeeper.GetParams(ctx) + blockTime := time.Now().UTC() + ctx = ctx.WithBlockTime(blockTime) + + validatorAddrs := []sdk.ValAddress{ + valAddrs[0], + valAddrs[1], + valAddrs[2], + } + delegatorAddrs := []sdk.AccAddress{ + delAddrs[0], + delAddrs[1], + delAddrs[2], + } + + // bond them all + for i, validatorAddr := range validatorAddrs { + valTokens := sdk.TokensFromConsensusPower(10) + msgCreateValidatorOnBehalfOf := NewTestMsgCreateValidator(validatorAddr, PKs[i], valTokens) + + res, err := handler(ctx, msgCreateValidatorOnBehalfOf) + require.NoError(t, err) + require.NotNil(t, res) + + // verify that the account is bonded + validators := app.StakingKeeper.GetValidators(ctx, 100) + require.Equal(t, (i + 1), len(validators)) + + val := validators[i] + balanceExpd := initTokens.Sub(valTokens) + balanceGot := app.BankKeeper.GetBalance(ctx, delegatorAddrs[i], params.BondDenom).Amount + + require.Equal(t, i+1, len(validators), "expected %d validators got %d, validators: %v", i+1, len(validators), validators) + require.Equal(t, valTokens, val.DelegatorShares.RoundInt(), "expected %d shares, got %d", 10, val.DelegatorShares) + require.Equal(t, balanceExpd, balanceGot, "expected account to have %d, got %d", balanceExpd, balanceGot) + } + + staking.EndBlocker(ctx, app.StakingKeeper) + + // unbond them all by removing delegation + for i, validatorAddr := range validatorAddrs { + _, found := app.StakingKeeper.GetValidator(ctx, validatorAddr) + require.True(t, found) + + unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(10)) + msgUndelegate := types.NewMsgUndelegate(delegatorAddrs[i], validatorAddr, unbondAmt) // remove delegation + res, err := handler(ctx, msgUndelegate) + require.NoError(t, err) + require.NotNil(t, res) + + ts := &gogotypes.Timestamp{} + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) + + _, err = gogotypes.TimestampFromProto(ts) + require.NoError(t, err) + + // adds validator into unbonding queue + staking.EndBlocker(ctx, app.StakingKeeper) + + // removes validator from queue and set + staking.EndBlocker(ctx.WithBlockTime(blockTime.Add(params.UnbondingTime)), app.StakingKeeper) + + // Check that the validator is deleted from state + validators := app.StakingKeeper.GetValidators(ctx, 100) + require.Equal(t, len(validatorAddrs)-(i+1), len(validators), + "expected %d validators got %d", len(validatorAddrs)-(i+1), len(validators)) + + _, found = app.StakingKeeper.GetValidator(ctx, validatorAddr) + require.False(t, found) + + gotBalance := app.BankKeeper.GetBalance(ctx, delegatorAddrs[i], params.BondDenom).Amount + require.Equal(t, initTokens, gotBalance, "expected account to have %d, got %d", initTokens, gotBalance) + } +} + //func TestMultipleMsgDelegate(t *testing.T) { // ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) // handler := NewHandler(keeper) From 0e3b95857bdce4b2f8ef81817010a64f84730b46 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Wed, 26 Feb 2020 15:19:39 +0100 Subject: [PATCH 232/529] refactor TestMultipleMsgDelegate --- x/staking/handler_test.go | 96 +++++++++++++++++++-------------------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/x/staking/handler_test.go b/x/staking/handler_test.go index 2a9b4bc43a06..a27545dc8155 100644 --- a/x/staking/handler_test.go +++ b/x/staking/handler_test.go @@ -649,54 +649,54 @@ func TestMultipleMsgCreateValidator(t *testing.T) { } } -//func TestMultipleMsgDelegate(t *testing.T) { -// ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) -// handler := NewHandler(keeper) -// validatorAddr, delegatorAddrs := sdk.ValAddress(Addrs[0]), Addrs[1:] -// -// // first make a validator -// msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], sdk.NewInt(10)) -// res, err := handler(ctx, msgCreateValidator) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // delegate multiple parties -// for _, delegatorAddr := range delegatorAddrs { -// msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, sdk.NewInt(10)) -// res, err := handler(ctx, msgDelegate) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // check that the account is bonded -// bond, found := keeper.GetDelegation(ctx, delegatorAddr, validatorAddr) -// require.True(t, found) -// require.NotNil(t, bond, "expected delegatee bond %d to exist", bond) -// } -// -// // unbond them all -// for _, delegatorAddr := range delegatorAddrs { -// unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) -// msgUndelegate := NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) -// -// res, err := handler(ctx, msgUndelegate) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// ts := &gogotypes.Timestamp{} -// types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) -// -// finishTime, err := gogotypes.TimestampFromProto(ts) -// require.NoError(t, err) -// -// ctx = ctx.WithBlockTime(finishTime) -// EndBlocker(ctx, keeper) -// -// // check that the account is unbonded -// _, found := keeper.GetDelegation(ctx, delegatorAddr, validatorAddr) -// require.False(t, found) -// } -//} -// +func TestMultipleMsgDelegate(t *testing.T) { + app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, 1000, 50, 1000000000) + handler := staking.NewHandler(app.StakingKeeper) + validatorAddr, delegatorAddrs := valAddrs[0], delAddrs[1:] + + // first make a validator + msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], sdk.NewInt(10)) + res, err := handler(ctx, msgCreateValidator) + require.NoError(t, err) + require.NotNil(t, res) + + // delegate multiple parties + for _, delegatorAddr := range delegatorAddrs { + msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, sdk.NewInt(10)) + res, err := handler(ctx, msgDelegate) + require.NoError(t, err) + require.NotNil(t, res) + + // check that the account is bonded + bond, found := app.StakingKeeper.GetDelegation(ctx, delegatorAddr, validatorAddr) + require.True(t, found) + require.NotNil(t, bond, "expected delegatee bond %d to exist", bond) + } + + // unbond them all + for _, delegatorAddr := range delegatorAddrs { + unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) + msgUndelegate := types.NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) + + res, err := handler(ctx, msgUndelegate) + require.NoError(t, err) + require.NotNil(t, res) + + ts := &gogotypes.Timestamp{} + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) + + finishTime, err := gogotypes.TimestampFromProto(ts) + require.NoError(t, err) + + ctx = ctx.WithBlockTime(finishTime) + staking.EndBlocker(ctx, app.StakingKeeper) + + // check that the account is unbonded + _, found := app.StakingKeeper.GetDelegation(ctx, delegatorAddr, validatorAddr) + require.False(t, found) + } +} + //func TestJailValidator(t *testing.T) { // ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) // handler := NewHandler(keeper) From 0fcf1e20d64bb216454a909d4c6156eea33a1308 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Wed, 26 Feb 2020 15:21:42 +0100 Subject: [PATCH 233/529] refactor TestJailValidator --- x/staking/handler_test.go | 118 +++++++++++++++++++------------------- 1 file changed, 59 insertions(+), 59 deletions(-) diff --git a/x/staking/handler_test.go b/x/staking/handler_test.go index a27545dc8155..991550bcc158 100644 --- a/x/staking/handler_test.go +++ b/x/staking/handler_test.go @@ -697,65 +697,65 @@ func TestMultipleMsgDelegate(t *testing.T) { } } -//func TestJailValidator(t *testing.T) { -// ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) -// handler := NewHandler(keeper) -// validatorAddr, delegatorAddr := sdk.ValAddress(Addrs[0]), Addrs[1] -// -// // create the validator -// msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], sdk.NewInt(10)) -// res, err := handler(ctx, msgCreateValidator) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // bond a delegator -// msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, sdk.NewInt(10)) -// res, err = handler(ctx, msgDelegate) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // unbond the validators bond portion -// unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) -// msgUndelegateValidator := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) -// res, err = handler(ctx, msgUndelegateValidator) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// ts := &gogotypes.Timestamp{} -// types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) -// -// finishTime, err := gogotypes.TimestampFromProto(ts) -// require.NoError(t, err) -// -// ctx = ctx.WithBlockTime(finishTime) -// EndBlocker(ctx, keeper) -// -// validator, found := keeper.GetValidator(ctx, validatorAddr) -// require.True(t, found) -// require.True(t, validator.Jailed, "%v", validator) -// -// // test that the delegator can still withdraw their bonds -// msgUndelegateDelegator := NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) -// -// res, err = handler(ctx, msgUndelegateDelegator) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// ts = &gogotypes.Timestamp{} -// types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) -// -// finishTime, err = gogotypes.TimestampFromProto(ts) -// require.NoError(t, err) -// -// ctx = ctx.WithBlockTime(finishTime) -// EndBlocker(ctx, keeper) -// -// // verify that the pubkey can now be reused -// res, err = handler(ctx, msgCreateValidator) -// require.NoError(t, err) -// require.NotNil(t, res) -//} -// +func TestJailValidator(t *testing.T) { + app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, 1000, 2, 1000000000) + handler := staking.NewHandler(app.StakingKeeper) + validatorAddr, delegatorAddr := valAddrs[0], delAddrs[1] + + // create the validator + msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], sdk.NewInt(10)) + res, err := handler(ctx, msgCreateValidator) + require.NoError(t, err) + require.NotNil(t, res) + + // bond a delegator + msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, sdk.NewInt(10)) + res, err = handler(ctx, msgDelegate) + require.NoError(t, err) + require.NotNil(t, res) + + // unbond the validators bond portion + unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) + msgUndelegateValidator := types.NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) + res, err = handler(ctx, msgUndelegateValidator) + require.NoError(t, err) + require.NotNil(t, res) + + ts := &gogotypes.Timestamp{} + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) + + finishTime, err := gogotypes.TimestampFromProto(ts) + require.NoError(t, err) + + ctx = ctx.WithBlockTime(finishTime) + staking.EndBlocker(ctx, app.StakingKeeper) + + validator, found := app.StakingKeeper.GetValidator(ctx, validatorAddr) + require.True(t, found) + require.True(t, validator.Jailed, "%v", validator) + + // test that the delegator can still withdraw their bonds + msgUndelegateDelegator := types.NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) + + res, err = handler(ctx, msgUndelegateDelegator) + require.NoError(t, err) + require.NotNil(t, res) + + ts = &gogotypes.Timestamp{} + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) + + finishTime, err = gogotypes.TimestampFromProto(ts) + require.NoError(t, err) + + ctx = ctx.WithBlockTime(finishTime) + staking.EndBlocker(ctx, app.StakingKeeper) + + // verify that the pubkey can now be reused + res, err = handler(ctx, msgCreateValidator) + require.NoError(t, err) + require.NotNil(t, res) +} + //func TestValidatorQueue(t *testing.T) { // ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) // handler := NewHandler(keeper) From eb26b478b4e51847c48c063f57e709a78a1b758f Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Wed, 26 Feb 2020 15:26:50 +0100 Subject: [PATCH 234/529] refactor TestUnbondingPeriod and TestValidatorQueue --- x/staking/handler_test.go | 228 +++++++++++++++++++------------------- 1 file changed, 114 insertions(+), 114 deletions(-) diff --git a/x/staking/handler_test.go b/x/staking/handler_test.go index 991550bcc158..9db8322c0337 100644 --- a/x/staking/handler_test.go +++ b/x/staking/handler_test.go @@ -756,120 +756,120 @@ func TestJailValidator(t *testing.T) { require.NotNil(t, res) } -//func TestValidatorQueue(t *testing.T) { -// ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) -// handler := NewHandler(keeper) -// validatorAddr, delegatorAddr := sdk.ValAddress(Addrs[0]), Addrs[1] -// -// // set the unbonding time -// params := keeper.GetParams(ctx) -// params.UnbondingTime = 7 * time.Second -// keeper.SetParams(ctx, params) -// -// // create the validator -// valTokens := sdk.TokensFromConsensusPower(10) -// msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], valTokens) -// res, err := handler(ctx, msgCreateValidator) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // bond a delegator -// delTokens := sdk.TokensFromConsensusPower(10) -// msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, delTokens) -// res, err = handler(ctx, msgDelegate) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// EndBlocker(ctx, keeper) -// -// // unbond the all self-delegation to put validator in unbonding state -// unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, delTokens) -// msgUndelegateValidator := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) -// res, err = handler(ctx, msgUndelegateValidator) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// ts := &gogotypes.Timestamp{} -// types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) -// -// finishTime, err := gogotypes.TimestampFromProto(ts) -// require.NoError(t, err) -// -// ctx = ctx.WithBlockTime(finishTime) -// EndBlocker(ctx, keeper) -// -// origHeader := ctx.BlockHeader() -// -// validator, found := keeper.GetValidator(ctx, validatorAddr) -// require.True(t, found) -// require.True(t, validator.IsUnbonding(), "%v", validator) -// -// // should still be unbonding at time 6 seconds later -// ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 6)) -// EndBlocker(ctx, keeper) -// -// validator, found = keeper.GetValidator(ctx, validatorAddr) -// require.True(t, found) -// require.True(t, validator.IsUnbonding(), "%v", validator) -// -// // should be in unbonded state at time 7 seconds later -// ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 7)) -// EndBlocker(ctx, keeper) -// -// validator, found = keeper.GetValidator(ctx, validatorAddr) -// require.True(t, found) -// require.True(t, validator.IsUnbonded(), "%v", validator) -//} -// -//func TestUnbondingPeriod(t *testing.T) { -// ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) -// handler := NewHandler(keeper) -// validatorAddr := sdk.ValAddress(Addrs[0]) -// -// // set the unbonding time -// params := keeper.GetParams(ctx) -// params.UnbondingTime = 7 * time.Second -// keeper.SetParams(ctx, params) -// -// // create the validator -// valTokens := sdk.TokensFromConsensusPower(10) -// msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], valTokens) -// res, err := handler(ctx, msgCreateValidator) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// EndBlocker(ctx, keeper) -// -// // begin unbonding -// unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(10)) -// msgUndelegate := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) -// res, err = handler(ctx, msgUndelegate) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// origHeader := ctx.BlockHeader() -// -// _, found := keeper.GetUnbondingDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) -// require.True(t, found, "should not have unbonded") -// -// // cannot complete unbonding at same time -// EndBlocker(ctx, keeper) -// _, found = keeper.GetUnbondingDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) -// require.True(t, found, "should not have unbonded") -// -// // cannot complete unbonding at time 6 seconds later -// ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 6)) -// EndBlocker(ctx, keeper) -// _, found = keeper.GetUnbondingDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) -// require.True(t, found, "should not have unbonded") -// -// // can complete unbonding at time 7 seconds later -// ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 7)) -// EndBlocker(ctx, keeper) -// _, found = keeper.GetUnbondingDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) -// require.False(t, found, "should have unbonded") -//} -// +func TestValidatorQueue(t *testing.T) { + app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, 1000, 2, 1000000000) + handler := staking.NewHandler(app.StakingKeeper) + validatorAddr, delegatorAddr := valAddrs[0], delAddrs[1] + + // set the unbonding time + params := app.StakingKeeper.GetParams(ctx) + params.UnbondingTime = 7 * time.Second + app.StakingKeeper.SetParams(ctx, params) + + // create the validator + valTokens := sdk.TokensFromConsensusPower(10) + msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], valTokens) + res, err := handler(ctx, msgCreateValidator) + require.NoError(t, err) + require.NotNil(t, res) + + // bond a delegator + delTokens := sdk.TokensFromConsensusPower(10) + msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, delTokens) + res, err = handler(ctx, msgDelegate) + require.NoError(t, err) + require.NotNil(t, res) + + staking.EndBlocker(ctx, app.StakingKeeper) + + // unbond the all self-delegation to put validator in unbonding state + unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, delTokens) + msgUndelegateValidator := types.NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) + res, err = handler(ctx, msgUndelegateValidator) + require.NoError(t, err) + require.NotNil(t, res) + + ts := &gogotypes.Timestamp{} + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) + + finishTime, err := gogotypes.TimestampFromProto(ts) + require.NoError(t, err) + + ctx = ctx.WithBlockTime(finishTime) + staking.EndBlocker(ctx, app.StakingKeeper) + + origHeader := ctx.BlockHeader() + + validator, found := app.StakingKeeper.GetValidator(ctx, validatorAddr) + require.True(t, found) + require.True(t, validator.IsUnbonding(), "%v", validator) + + // should still be unbonding at time 6 seconds later + ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 6)) + staking.EndBlocker(ctx, app.StakingKeeper) + + validator, found = app.StakingKeeper.GetValidator(ctx, validatorAddr) + require.True(t, found) + require.True(t, validator.IsUnbonding(), "%v", validator) + + // should be in unbonded state at time 7 seconds later + ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 7)) + staking.EndBlocker(ctx, app.StakingKeeper) + + validator, found = app.StakingKeeper.GetValidator(ctx, validatorAddr) + require.True(t, found) + require.True(t, validator.IsUnbonded(), "%v", validator) +} + +func TestUnbondingPeriod(t *testing.T) { + app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, 1000, 1, 1000000000) + handler := staking.NewHandler(app.StakingKeeper) + validatorAddr := valAddrs[0] + + // set the unbonding time + params := app.StakingKeeper.GetParams(ctx) + params.UnbondingTime = 7 * time.Second + app.StakingKeeper.SetParams(ctx, params) + + // create the validator + valTokens := sdk.TokensFromConsensusPower(10) + msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], valTokens) + res, err := handler(ctx, msgCreateValidator) + require.NoError(t, err) + require.NotNil(t, res) + + staking.EndBlocker(ctx, app.StakingKeeper) + + // begin unbonding + unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(10)) + msgUndelegate := types.NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) + res, err = handler(ctx, msgUndelegate) + require.NoError(t, err) + require.NotNil(t, res) + + origHeader := ctx.BlockHeader() + + _, found := app.StakingKeeper.GetUnbondingDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) + require.True(t, found, "should not have unbonded") + + // cannot complete unbonding at same time + staking.EndBlocker(ctx, app.StakingKeeper) + _, found = app.StakingKeeper.GetUnbondingDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) + require.True(t, found, "should not have unbonded") + + // cannot complete unbonding at time 6 seconds later + ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 6)) + staking.EndBlocker(ctx, app.StakingKeeper) + _, found = app.StakingKeeper.GetUnbondingDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) + require.True(t, found, "should not have unbonded") + + // can complete unbonding at time 7 seconds later + ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 7)) + staking.EndBlocker(ctx, app.StakingKeeper) + _, found = app.StakingKeeper.GetUnbondingDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) + require.False(t, found, "should have unbonded") +} + //func TestUnbondingFromUnbondingValidator(t *testing.T) { // ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) // handler := NewHandler(keeper) From c58ec7f7b7df22dbf3b21a02ef21e2f08a932f41 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Wed, 26 Feb 2020 15:31:16 +0100 Subject: [PATCH 235/529] refactor TestUnbondingFromUnbondingValidator and TestRedelegationPeriod --- x/staking/handler_test.go | 226 +++++++++++++++++++------------------- 1 file changed, 113 insertions(+), 113 deletions(-) diff --git a/x/staking/handler_test.go b/x/staking/handler_test.go index 9db8322c0337..06d6e2157608 100644 --- a/x/staking/handler_test.go +++ b/x/staking/handler_test.go @@ -870,119 +870,119 @@ func TestUnbondingPeriod(t *testing.T) { require.False(t, found, "should have unbonded") } -//func TestUnbondingFromUnbondingValidator(t *testing.T) { -// ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) -// handler := NewHandler(keeper) -// validatorAddr, delegatorAddr := sdk.ValAddress(Addrs[0]), Addrs[1] -// -// // create the validator -// msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], sdk.NewInt(10)) -// res, err := handler(ctx, msgCreateValidator) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // bond a delegator -// msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, sdk.NewInt(10)) -// res, err = handler(ctx, msgDelegate) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // unbond the validators bond portion -// unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) -// msgUndelegateValidator := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) -// res, err = handler(ctx, msgUndelegateValidator) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // change the ctx to Block Time one second before the validator would have unbonded -// ts := &gogotypes.Timestamp{} -// types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) -// -// finishTime, err := gogotypes.TimestampFromProto(ts) -// require.NoError(t, err) -// -// ctx = ctx.WithBlockTime(finishTime.Add(time.Second * -1)) -// -// // unbond the delegator from the validator -// msgUndelegateDelegator := NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) -// res, err = handler(ctx, msgUndelegateDelegator) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(keeper.UnbondingTime(ctx))) -// -// // Run the EndBlocker -// EndBlocker(ctx, keeper) -// -// // Check to make sure that the unbonding delegation is no longer in state -// // (meaning it was deleted in the above EndBlocker) -// _, found := keeper.GetUnbondingDelegation(ctx, delegatorAddr, validatorAddr) -// require.False(t, found, "should be removed from state") -//} -// -//func TestRedelegationPeriod(t *testing.T) { -// ctx, _, bk, keeper, _ := CreateTestInput(t, false, 1000) -// handler := NewHandler(keeper) -// validatorAddr, validatorAddr2 := sdk.ValAddress(Addrs[0]), sdk.ValAddress(Addrs[1]) -// denom := keeper.GetParams(ctx).BondDenom -// -// // set the unbonding time -// params := keeper.GetParams(ctx) -// params.UnbondingTime = 7 * time.Second -// keeper.SetParams(ctx, params) -// -// // create the validators -// msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], sdk.NewInt(10)) -// -// // initial balance -// amt1 := bk.GetBalance(ctx, sdk.AccAddress(validatorAddr), denom).Amount -// -// res, err := handler(ctx, msgCreateValidator) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // balance should have been subtracted after creation -// amt2 := bk.GetBalance(ctx, sdk.AccAddress(validatorAddr), denom).Amount -// require.Equal(t, amt1.Sub(sdk.NewInt(10)).Int64(), amt2.Int64(), "expected coins to be subtracted") -// -// msgCreateValidator = NewTestMsgCreateValidator(validatorAddr2, PKs[1], sdk.NewInt(10)) -// res, err = handler(ctx, msgCreateValidator) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// bal1 := bk.GetAllBalances(ctx, sdk.AccAddress(validatorAddr)) -// -// // begin redelegate -// redAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) -// msgBeginRedelegate := NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2, redAmt) -// res, err = handler(ctx, msgBeginRedelegate) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // origin account should not lose tokens as with a regular delegation -// bal2 := bk.GetAllBalances(ctx, sdk.AccAddress(validatorAddr)) -// require.Equal(t, bal1, bal2) -// -// origHeader := ctx.BlockHeader() -// -// // cannot complete redelegation at same time -// EndBlocker(ctx, keeper) -// _, found := keeper.GetRedelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2) -// require.True(t, found, "should not have unbonded") -// -// // cannot complete redelegation at time 6 seconds later -// ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 6)) -// EndBlocker(ctx, keeper) -// _, found = keeper.GetRedelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2) -// require.True(t, found, "should not have unbonded") -// -// // can complete redelegation at time 7 seconds later -// ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 7)) -// EndBlocker(ctx, keeper) -// _, found = keeper.GetRedelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2) -// require.False(t, found, "should have unbonded") -//} -// +func TestUnbondingFromUnbondingValidator(t *testing.T) { + app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, 1000, 2, 1000000000) + handler := staking.NewHandler(app.StakingKeeper) + validatorAddr, delegatorAddr := valAddrs[0], delAddrs[1] + + // create the validator + msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], sdk.NewInt(10)) + res, err := handler(ctx, msgCreateValidator) + require.NoError(t, err) + require.NotNil(t, res) + + // bond a delegator + msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, sdk.NewInt(10)) + res, err = handler(ctx, msgDelegate) + require.NoError(t, err) + require.NotNil(t, res) + + // unbond the validators bond portion + unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) + msgUndelegateValidator := types.NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) + res, err = handler(ctx, msgUndelegateValidator) + require.NoError(t, err) + require.NotNil(t, res) + + // change the ctx to Block Time one second before the validator would have unbonded + ts := &gogotypes.Timestamp{} + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, ts) + + finishTime, err := gogotypes.TimestampFromProto(ts) + require.NoError(t, err) + + ctx = ctx.WithBlockTime(finishTime.Add(time.Second * -1)) + + // unbond the delegator from the validator + msgUndelegateDelegator := types.NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) + res, err = handler(ctx, msgUndelegateDelegator) + require.NoError(t, err) + require.NotNil(t, res) + + ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(app.StakingKeeper.UnbondingTime(ctx))) + + // Run the EndBlocker + staking.EndBlocker(ctx, app.StakingKeeper) + + // Check to make sure that the unbonding delegation is no longer in state + // (meaning it was deleted in the above EndBlocker) + _, found := app.StakingKeeper.GetUnbondingDelegation(ctx, delegatorAddr, validatorAddr) + require.False(t, found, "should be removed from state") +} + +func TestRedelegationPeriod(t *testing.T) { + app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, 1000, 2, 1000000000) + handler := staking.NewHandler(app.StakingKeeper) + validatorAddr, validatorAddr2 := valAddrs[0], valAddrs[1] + denom := app.StakingKeeper.GetParams(ctx).BondDenom + + // set the unbonding time + params := app.StakingKeeper.GetParams(ctx) + params.UnbondingTime = 7 * time.Second + app.StakingKeeper.SetParams(ctx, params) + + // create the validators + msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], sdk.NewInt(10)) + + // initial balance + amt1 := app.BankKeeper.GetBalance(ctx, sdk.AccAddress(validatorAddr), denom).Amount + + res, err := handler(ctx, msgCreateValidator) + require.NoError(t, err) + require.NotNil(t, res) + + // balance should have been subtracted after creation + amt2 := app.BankKeeper.GetBalance(ctx, sdk.AccAddress(validatorAddr), denom).Amount + require.Equal(t, amt1.Sub(sdk.NewInt(10)).Int64(), amt2.Int64(), "expected coins to be subtracted") + + msgCreateValidator = NewTestMsgCreateValidator(validatorAddr2, PKs[1], sdk.NewInt(10)) + res, err = handler(ctx, msgCreateValidator) + require.NoError(t, err) + require.NotNil(t, res) + + bal1 := app.BankKeeper.GetAllBalances(ctx, sdk.AccAddress(validatorAddr)) + + // begin redelegate + redAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) + msgBeginRedelegate := types.NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2, redAmt) + res, err = handler(ctx, msgBeginRedelegate) + require.NoError(t, err) + require.NotNil(t, res) + + // origin account should not lose tokens as with a regular delegation + bal2 := app.BankKeeper.GetAllBalances(ctx, sdk.AccAddress(validatorAddr)) + require.Equal(t, bal1, bal2) + + origHeader := ctx.BlockHeader() + + // cannot complete redelegation at same time + staking.EndBlocker(ctx, app.StakingKeeper) + _, found := app.StakingKeeper.GetRedelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2) + require.True(t, found, "should not have unbonded") + + // cannot complete redelegation at time 6 seconds later + ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 6)) + staking.EndBlocker(ctx, app.StakingKeeper) + _, found = app.StakingKeeper.GetRedelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2) + require.True(t, found, "should not have unbonded") + + // can complete redelegation at time 7 seconds later + ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 7)) + staking.EndBlocker(ctx, app.StakingKeeper) + _, found = app.StakingKeeper.GetRedelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2) + require.False(t, found, "should have unbonded") +} + //func TestTransitiveRedelegation(t *testing.T) { // ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) // handler := NewHandler(keeper) From 4e16a0861c3acd1655d5922514a5ca164db5847e Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Wed, 26 Feb 2020 15:35:29 +0100 Subject: [PATCH 236/529] refactor TestTransitiveRedelegation and TestMultipleRedelegationAtSameTime --- x/staking/handler_test.go | 220 +++++++++++++++++++------------------- 1 file changed, 110 insertions(+), 110 deletions(-) diff --git a/x/staking/handler_test.go b/x/staking/handler_test.go index 06d6e2157608..59a1a83a903b 100644 --- a/x/staking/handler_test.go +++ b/x/staking/handler_test.go @@ -983,116 +983,116 @@ func TestRedelegationPeriod(t *testing.T) { require.False(t, found, "should have unbonded") } -//func TestTransitiveRedelegation(t *testing.T) { -// ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) -// handler := NewHandler(keeper) -// -// validatorAddr := sdk.ValAddress(Addrs[0]) -// validatorAddr2 := sdk.ValAddress(Addrs[1]) -// validatorAddr3 := sdk.ValAddress(Addrs[2]) -// -// blockTime := time.Now().UTC() -// ctx = ctx.WithBlockTime(blockTime) -// -// // create the validators -// msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], sdk.NewInt(10)) -// res, err := handler(ctx, msgCreateValidator) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// msgCreateValidator = NewTestMsgCreateValidator(validatorAddr2, PKs[1], sdk.NewInt(10)) -// res, err = handler(ctx, msgCreateValidator) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// msgCreateValidator = NewTestMsgCreateValidator(validatorAddr3, PKs[2], sdk.NewInt(10)) -// res, err = handler(ctx, msgCreateValidator) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // begin redelegate -// redAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) -// msgBeginRedelegate := NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2, redAmt) -// res, err = handler(ctx, msgBeginRedelegate) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // cannot redelegation to next validator while first delegation exists -// msgBeginRedelegate = NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr2, validatorAddr3, redAmt) -// res, err = handler(ctx, msgBeginRedelegate) -// require.Error(t, err) -// require.Nil(t, res) -// -// params := keeper.GetParams(ctx) -// ctx = ctx.WithBlockTime(blockTime.Add(params.UnbondingTime)) -// -// // complete first redelegation -// EndBlocker(ctx, keeper) -// -// // now should be able to redelegate from the second validator to the third -// res, err = handler(ctx, msgBeginRedelegate) -// require.NoError(t, err) -// require.NotNil(t, res) -//} -// -//func TestMultipleRedelegationAtSameTime(t *testing.T) { -// ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) -// handler := NewHandler(keeper) -// -// valAddr := sdk.ValAddress(Addrs[0]) -// valAddr2 := sdk.ValAddress(Addrs[1]) -// -// // set the unbonding time -// params := keeper.GetParams(ctx) -// params.UnbondingTime = 1 * time.Second -// keeper.SetParams(ctx, params) -// -// // create the validators -// valTokens := sdk.TokensFromConsensusPower(10) -// msgCreateValidator := NewTestMsgCreateValidator(valAddr, PKs[0], valTokens) -// res, err := handler(ctx, msgCreateValidator) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// msgCreateValidator = NewTestMsgCreateValidator(valAddr2, PKs[1], valTokens) -// res, err = handler(ctx, msgCreateValidator) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // end block to bond them -// EndBlocker(ctx, keeper) -// -// // begin a redelegate -// selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) -// redAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens.QuoRaw(2)) -// msgBeginRedelegate := NewMsgBeginRedelegate(selfDelAddr, valAddr, valAddr2, redAmt) -// res, err = handler(ctx, msgBeginRedelegate) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // there should only be one entry in the redelegation object -// rd, found := keeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) -// require.True(t, found) -// require.Len(t, rd.Entries, 1) -// -// // start a second redelegation at this same time as the first -// res, err = handler(ctx, msgBeginRedelegate) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // now there should be two entries -// rd, found = keeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) -// require.True(t, found) -// require.Len(t, rd.Entries, 2) -// -// // move forward in time, should complete both redelegations -// ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(1 * time.Second)) -// EndBlocker(ctx, keeper) -// -// rd, found = keeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) -// require.False(t, found) -//} -// +func TestTransitiveRedelegation(t *testing.T) { + app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, 1000, 3, 1000000000) + handler := staking.NewHandler(app.StakingKeeper) + + validatorAddr := valAddrs[0] + validatorAddr2 := valAddrs[1] + validatorAddr3 := valAddrs[2] + + blockTime := time.Now().UTC() + ctx = ctx.WithBlockTime(blockTime) + + // create the validators + msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, PKs[0], sdk.NewInt(10)) + res, err := handler(ctx, msgCreateValidator) + require.NoError(t, err) + require.NotNil(t, res) + + msgCreateValidator = NewTestMsgCreateValidator(validatorAddr2, PKs[1], sdk.NewInt(10)) + res, err = handler(ctx, msgCreateValidator) + require.NoError(t, err) + require.NotNil(t, res) + + msgCreateValidator = NewTestMsgCreateValidator(validatorAddr3, PKs[2], sdk.NewInt(10)) + res, err = handler(ctx, msgCreateValidator) + require.NoError(t, err) + require.NotNil(t, res) + + // begin redelegate + redAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) + msgBeginRedelegate := types.NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2, redAmt) + res, err = handler(ctx, msgBeginRedelegate) + require.NoError(t, err) + require.NotNil(t, res) + + // cannot redelegation to next validator while first delegation exists + msgBeginRedelegate = types.NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr2, validatorAddr3, redAmt) + res, err = handler(ctx, msgBeginRedelegate) + require.Error(t, err) + require.Nil(t, res) + + params := app.StakingKeeper.GetParams(ctx) + ctx = ctx.WithBlockTime(blockTime.Add(params.UnbondingTime)) + + // complete first redelegation + staking.EndBlocker(ctx, app.StakingKeeper) + + // now should be able to redelegate from the second validator to the third + res, err = handler(ctx, msgBeginRedelegate) + require.NoError(t, err) + require.NotNil(t, res) +} + +func TestMultipleRedelegationAtSameTime(t *testing.T) { + app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, 1000, 2, 1000000000) + handler := staking.NewHandler(app.StakingKeeper) + + valAddr := valAddrs[0] + valAddr2 := valAddrs[1] + + // set the unbonding time + params := app.StakingKeeper.GetParams(ctx) + params.UnbondingTime = 1 * time.Second + app.StakingKeeper.SetParams(ctx, params) + + // create the validators + valTokens := sdk.TokensFromConsensusPower(10) + msgCreateValidator := NewTestMsgCreateValidator(valAddr, PKs[0], valTokens) + res, err := handler(ctx, msgCreateValidator) + require.NoError(t, err) + require.NotNil(t, res) + + msgCreateValidator = NewTestMsgCreateValidator(valAddr2, PKs[1], valTokens) + res, err = handler(ctx, msgCreateValidator) + require.NoError(t, err) + require.NotNil(t, res) + + // end block to bond them + staking.EndBlocker(ctx, app.StakingKeeper) + + // begin a redelegate + selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) + redAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens.QuoRaw(2)) + msgBeginRedelegate := types.NewMsgBeginRedelegate(selfDelAddr, valAddr, valAddr2, redAmt) + res, err = handler(ctx, msgBeginRedelegate) + require.NoError(t, err) + require.NotNil(t, res) + + // there should only be one entry in the redelegation object + rd, found := app.StakingKeeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) + require.True(t, found) + require.Len(t, rd.Entries, 1) + + // start a second redelegation at this same time as the first + res, err = handler(ctx, msgBeginRedelegate) + require.NoError(t, err) + require.NotNil(t, res) + + // now there should be two entries + rd, found = app.StakingKeeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) + require.True(t, found) + require.Len(t, rd.Entries, 2) + + // move forward in time, should complete both redelegations + ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(1 * time.Second)) + staking.EndBlocker(ctx, app.StakingKeeper) + + rd, found = app.StakingKeeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) + require.False(t, found) +} + //func TestMultipleRedelegationAtUniqueTimes(t *testing.T) { // ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) // handler := NewHandler(keeper) From 9381500fbc177dd40a6595a9dfb8ca4f97391a76 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Wed, 26 Feb 2020 15:39:56 +0100 Subject: [PATCH 237/529] refactor TestMultipleRedelegationAtUniqueTimes and TestMultipleUnbondingDelegationAtSameTime --- x/staking/handler_test.go | 224 +++++++++++++++++++------------------- 1 file changed, 112 insertions(+), 112 deletions(-) diff --git a/x/staking/handler_test.go b/x/staking/handler_test.go index 59a1a83a903b..c5b9c0cb1865 100644 --- a/x/staking/handler_test.go +++ b/x/staking/handler_test.go @@ -1093,118 +1093,118 @@ func TestMultipleRedelegationAtSameTime(t *testing.T) { require.False(t, found) } -//func TestMultipleRedelegationAtUniqueTimes(t *testing.T) { -// ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) -// handler := NewHandler(keeper) -// -// valAddr := sdk.ValAddress(Addrs[0]) -// valAddr2 := sdk.ValAddress(Addrs[1]) -// -// // set the unbonding time -// params := keeper.GetParams(ctx) -// params.UnbondingTime = 10 * time.Second -// keeper.SetParams(ctx, params) -// -// // create the validators -// valTokens := sdk.TokensFromConsensusPower(10) -// msgCreateValidator := NewTestMsgCreateValidator(valAddr, PKs[0], valTokens) -// res, err := handler(ctx, msgCreateValidator) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// msgCreateValidator = NewTestMsgCreateValidator(valAddr2, PKs[1], valTokens) -// res, err = handler(ctx, msgCreateValidator) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // end block to bond them -// EndBlocker(ctx, keeper) -// -// // begin a redelegate -// selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) -// redAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens.QuoRaw(2)) -// msgBeginRedelegate := NewMsgBeginRedelegate(selfDelAddr, valAddr, valAddr2, redAmt) -// res, err = handler(ctx, msgBeginRedelegate) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // move forward in time and start a second redelegation -// ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) -// res, err = handler(ctx, msgBeginRedelegate) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // now there should be two entries -// rd, found := keeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) -// require.True(t, found) -// require.Len(t, rd.Entries, 2) -// -// // move forward in time, should complete the first redelegation, but not the second -// ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) -// EndBlocker(ctx, keeper) -// rd, found = keeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) -// require.True(t, found) -// require.Len(t, rd.Entries, 1) -// -// // move forward in time, should complete the second redelegation -// ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) -// EndBlocker(ctx, keeper) -// rd, found = keeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) -// require.False(t, found) -//} -// -//func TestMultipleUnbondingDelegationAtSameTime(t *testing.T) { -// ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) -// handler := NewHandler(keeper) -// -// valAddr := sdk.ValAddress(Addrs[0]) -// -// // set the unbonding time -// params := keeper.GetParams(ctx) -// params.UnbondingTime = 1 * time.Second -// keeper.SetParams(ctx, params) -// -// // create the validator -// valTokens := sdk.TokensFromConsensusPower(10) -// msgCreateValidator := NewTestMsgCreateValidator(valAddr, PKs[0], valTokens) -// res, err := handler(ctx, msgCreateValidator) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // end block to bond -// EndBlocker(ctx, keeper) -// -// // begin an unbonding delegation -// selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) -// unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens.QuoRaw(2)) -// msgUndelegate := NewMsgUndelegate(selfDelAddr, valAddr, unbondAmt) -// res, err = handler(ctx, msgUndelegate) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // there should only be one entry in the ubd object -// ubd, found := keeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) -// require.True(t, found) -// require.Len(t, ubd.Entries, 1) -// -// // start a second ubd at this same time as the first -// res, err = handler(ctx, msgUndelegate) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // now there should be two entries -// ubd, found = keeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) -// require.True(t, found) -// require.Len(t, ubd.Entries, 2) -// -// // move forwaubd in time, should complete both ubds -// ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(1 * time.Second)) -// EndBlocker(ctx, keeper) -// -// ubd, found = keeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) -// require.False(t, found) -//} -// +func TestMultipleRedelegationAtUniqueTimes(t *testing.T) { + app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, 1000, 2, 1000000000) + handler := staking.NewHandler(app.StakingKeeper) + + valAddr := valAddrs[0] + valAddr2 := valAddrs[1] + + // set the unbonding time + params := app.StakingKeeper.GetParams(ctx) + params.UnbondingTime = 10 * time.Second + app.StakingKeeper.SetParams(ctx, params) + + // create the validators + valTokens := sdk.TokensFromConsensusPower(10) + msgCreateValidator := NewTestMsgCreateValidator(valAddr, PKs[0], valTokens) + res, err := handler(ctx, msgCreateValidator) + require.NoError(t, err) + require.NotNil(t, res) + + msgCreateValidator = NewTestMsgCreateValidator(valAddr2, PKs[1], valTokens) + res, err = handler(ctx, msgCreateValidator) + require.NoError(t, err) + require.NotNil(t, res) + + // end block to bond them + staking.EndBlocker(ctx, app.StakingKeeper) + + // begin a redelegate + selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) + redAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens.QuoRaw(2)) + msgBeginRedelegate := types.NewMsgBeginRedelegate(selfDelAddr, valAddr, valAddr2, redAmt) + res, err = handler(ctx, msgBeginRedelegate) + require.NoError(t, err) + require.NotNil(t, res) + + // move forward in time and start a second redelegation + ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) + res, err = handler(ctx, msgBeginRedelegate) + require.NoError(t, err) + require.NotNil(t, res) + + // now there should be two entries + rd, found := app.StakingKeeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) + require.True(t, found) + require.Len(t, rd.Entries, 2) + + // move forward in time, should complete the first redelegation, but not the second + ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) + staking.EndBlocker(ctx, app.StakingKeeper) + rd, found = app.StakingKeeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) + require.True(t, found) + require.Len(t, rd.Entries, 1) + + // move forward in time, should complete the second redelegation + ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) + staking.EndBlocker(ctx, app.StakingKeeper) + rd, found = app.StakingKeeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) + require.False(t, found) +} + +func TestMultipleUnbondingDelegationAtSameTime(t *testing.T) { + app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, 1000, 1, 1000000000) + handler := staking.NewHandler(app.StakingKeeper) + + valAddr := valAddrs[0] + + // set the unbonding time + params := app.StakingKeeper.GetParams(ctx) + params.UnbondingTime = 1 * time.Second + app.StakingKeeper.SetParams(ctx, params) + + // create the validator + valTokens := sdk.TokensFromConsensusPower(10) + msgCreateValidator := NewTestMsgCreateValidator(valAddr, PKs[0], valTokens) + res, err := handler(ctx, msgCreateValidator) + require.NoError(t, err) + require.NotNil(t, res) + + // end block to bond + staking.EndBlocker(ctx, app.StakingKeeper) + + // begin an unbonding delegation + selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) + unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens.QuoRaw(2)) + msgUndelegate := types.NewMsgUndelegate(selfDelAddr, valAddr, unbondAmt) + res, err = handler(ctx, msgUndelegate) + require.NoError(t, err) + require.NotNil(t, res) + + // there should only be one entry in the ubd object + ubd, found := app.StakingKeeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) + require.True(t, found) + require.Len(t, ubd.Entries, 1) + + // start a second ubd at this same time as the first + res, err = handler(ctx, msgUndelegate) + require.NoError(t, err) + require.NotNil(t, res) + + // now there should be two entries + ubd, found = app.StakingKeeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) + require.True(t, found) + require.Len(t, ubd.Entries, 2) + + // move forwaubd in time, should complete both ubds + ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(1 * time.Second)) + staking.EndBlocker(ctx, app.StakingKeeper) + + ubd, found = app.StakingKeeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) + require.False(t, found) +} + //func TestMultipleUnbondingDelegationAtUniqueTimes(t *testing.T) { // ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) // handler := NewHandler(keeper) From 015fd43f51ce5fbcd617b2c792af371ed5b7fb06 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Wed, 26 Feb 2020 15:44:15 +0100 Subject: [PATCH 238/529] refactor TestMultipleUnbondingDelegationAtUniqueTimes and TestUnbondingWhenExcessValidators --- x/staking/handler_test.go | 244 +++++++++++++++++++------------------- 1 file changed, 122 insertions(+), 122 deletions(-) diff --git a/x/staking/handler_test.go b/x/staking/handler_test.go index c5b9c0cb1865..46d804e56812 100644 --- a/x/staking/handler_test.go +++ b/x/staking/handler_test.go @@ -1205,128 +1205,128 @@ func TestMultipleUnbondingDelegationAtSameTime(t *testing.T) { require.False(t, found) } -//func TestMultipleUnbondingDelegationAtUniqueTimes(t *testing.T) { -// ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) -// handler := NewHandler(keeper) -// valAddr := sdk.ValAddress(Addrs[0]) -// -// // set the unbonding time -// params := keeper.GetParams(ctx) -// params.UnbondingTime = 10 * time.Second -// keeper.SetParams(ctx, params) -// -// // create the validator -// valTokens := sdk.TokensFromConsensusPower(10) -// msgCreateValidator := NewTestMsgCreateValidator(valAddr, PKs[0], valTokens) -// res, err := handler(ctx, msgCreateValidator) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // end block to bond -// EndBlocker(ctx, keeper) -// -// // begin an unbonding delegation -// selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) -// unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens.QuoRaw(2)) -// msgUndelegate := NewMsgUndelegate(selfDelAddr, valAddr, unbondAmt) -// res, err = handler(ctx, msgUndelegate) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // there should only be one entry in the ubd object -// ubd, found := keeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) -// require.True(t, found) -// require.Len(t, ubd.Entries, 1) -// -// // move forwaubd in time and start a second redelegation -// ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) -// res, err = handler(ctx, msgUndelegate) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // now there should be two entries -// ubd, found = keeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) -// require.True(t, found) -// require.Len(t, ubd.Entries, 2) -// -// // move forwaubd in time, should complete the first redelegation, but not the second -// ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) -// EndBlocker(ctx, keeper) -// ubd, found = keeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) -// require.True(t, found) -// require.Len(t, ubd.Entries, 1) -// -// // move forwaubd in time, should complete the second redelegation -// ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) -// EndBlocker(ctx, keeper) -// ubd, found = keeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) -// require.False(t, found) -//} -// -//func TestUnbondingWhenExcessValidators(t *testing.T) { -// ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) -// handler := NewHandler(keeper) -// -// validatorAddr1 := sdk.ValAddress(Addrs[0]) -// validatorAddr2 := sdk.ValAddress(Addrs[1]) -// validatorAddr3 := sdk.ValAddress(Addrs[2]) -// -// // set the unbonding time -// params := keeper.GetParams(ctx) -// params.MaxValidators = 2 -// keeper.SetParams(ctx, params) -// -// // add three validators -// valTokens1 := sdk.TokensFromConsensusPower(50) -// msgCreateValidator := NewTestMsgCreateValidator(validatorAddr1, PKs[0], valTokens1) -// res, err := handler(ctx, msgCreateValidator) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // apply TM updates -// keeper.ApplyAndReturnValidatorSetUpdates(ctx) -// require.Equal(t, 1, len(keeper.GetLastValidators(ctx))) -// -// valTokens2 := sdk.TokensFromConsensusPower(30) -// msgCreateValidator = NewTestMsgCreateValidator(validatorAddr2, PKs[1], valTokens2) -// res, err = handler(ctx, msgCreateValidator) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // apply TM updates -// keeper.ApplyAndReturnValidatorSetUpdates(ctx) -// require.Equal(t, 2, len(keeper.GetLastValidators(ctx))) -// -// valTokens3 := sdk.TokensFromConsensusPower(10) -// msgCreateValidator = NewTestMsgCreateValidator(validatorAddr3, PKs[2], valTokens3) -// res, err = handler(ctx, msgCreateValidator) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // apply TM updates -// keeper.ApplyAndReturnValidatorSetUpdates(ctx) -// require.Equal(t, 2, len(keeper.GetLastValidators(ctx))) -// -// // unbond the validator-2 -// unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens2) -// msgUndelegate := NewMsgUndelegate(sdk.AccAddress(validatorAddr2), validatorAddr2, unbondAmt) -// res, err = handler(ctx, msgUndelegate) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // apply TM updates -// keeper.ApplyAndReturnValidatorSetUpdates(ctx) -// -// // because there are extra validators waiting to get in, the queued -// // validator (aka. validator-1) should make it into the bonded group, thus -// // the total number of validators should stay the same -// vals := keeper.GetLastValidators(ctx) -// require.Equal(t, 2, len(vals), "vals %v", vals) -// val1, found := keeper.GetValidator(ctx, validatorAddr1) -// require.True(t, found) -// require.Equal(t, sdk.Bonded, val1.Status, "%v", val1) -//} -// +func TestMultipleUnbondingDelegationAtUniqueTimes(t *testing.T) { + app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, 1000, 1, 1000000000) + handler := staking.NewHandler(app.StakingKeeper) + valAddr := valAddrs[0] + + // set the unbonding time + params := app.StakingKeeper.GetParams(ctx) + params.UnbondingTime = 10 * time.Second + app.StakingKeeper.SetParams(ctx, params) + + // create the validator + valTokens := sdk.TokensFromConsensusPower(10) + msgCreateValidator := NewTestMsgCreateValidator(valAddr, PKs[0], valTokens) + res, err := handler(ctx, msgCreateValidator) + require.NoError(t, err) + require.NotNil(t, res) + + // end block to bond + staking.EndBlocker(ctx, app.StakingKeeper) + + // begin an unbonding delegation + selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) + unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens.QuoRaw(2)) + msgUndelegate := staking.NewMsgUndelegate(selfDelAddr, valAddr, unbondAmt) + res, err = handler(ctx, msgUndelegate) + require.NoError(t, err) + require.NotNil(t, res) + + // there should only be one entry in the ubd object + ubd, found := app.StakingKeeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) + require.True(t, found) + require.Len(t, ubd.Entries, 1) + + // move forwaubd in time and start a second redelegation + ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) + res, err = handler(ctx, msgUndelegate) + require.NoError(t, err) + require.NotNil(t, res) + + // now there should be two entries + ubd, found = app.StakingKeeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) + require.True(t, found) + require.Len(t, ubd.Entries, 2) + + // move forwaubd in time, should complete the first redelegation, but not the second + ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) + staking.EndBlocker(ctx, app.StakingKeeper) + ubd, found = app.StakingKeeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) + require.True(t, found) + require.Len(t, ubd.Entries, 1) + + // move forwaubd in time, should complete the second redelegation + ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) + staking.EndBlocker(ctx, app.StakingKeeper) + ubd, found = app.StakingKeeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) + require.False(t, found) +} + +func TestUnbondingWhenExcessValidators(t *testing.T) { + app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, 1000, 3, 1000000000) + handler := staking.NewHandler(app.StakingKeeper) + + validatorAddr1 := valAddrs[0] + validatorAddr2 := valAddrs[1] + validatorAddr3 := valAddrs[2] + + // set the unbonding time + params := app.StakingKeeper.GetParams(ctx) + params.MaxValidators = 2 + app.StakingKeeper.SetParams(ctx, params) + + // add three validators + valTokens1 := sdk.TokensFromConsensusPower(50) + msgCreateValidator := NewTestMsgCreateValidator(validatorAddr1, PKs[0], valTokens1) + res, err := handler(ctx, msgCreateValidator) + require.NoError(t, err) + require.NotNil(t, res) + + // apply TM updates + app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 1, len(app.StakingKeeper.GetLastValidators(ctx))) + + valTokens2 := sdk.TokensFromConsensusPower(30) + msgCreateValidator = NewTestMsgCreateValidator(validatorAddr2, PKs[1], valTokens2) + res, err = handler(ctx, msgCreateValidator) + require.NoError(t, err) + require.NotNil(t, res) + + // apply TM updates + app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 2, len(app.StakingKeeper.GetLastValidators(ctx))) + + valTokens3 := sdk.TokensFromConsensusPower(10) + msgCreateValidator = NewTestMsgCreateValidator(validatorAddr3, PKs[2], valTokens3) + res, err = handler(ctx, msgCreateValidator) + require.NoError(t, err) + require.NotNil(t, res) + + // apply TM updates + app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 2, len(app.StakingKeeper.GetLastValidators(ctx))) + + // unbond the validator-2 + unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens2) + msgUndelegate := types.NewMsgUndelegate(sdk.AccAddress(validatorAddr2), validatorAddr2, unbondAmt) + res, err = handler(ctx, msgUndelegate) + require.NoError(t, err) + require.NotNil(t, res) + + // apply TM updates + app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + + // because there are extra validators waiting to get in, the queued + // validator (aka. validator-1) should make it into the bonded group, thus + // the total number of validators should stay the same + vals := app.StakingKeeper.GetLastValidators(ctx) + require.Equal(t, 2, len(vals), "vals %v", vals) + val1, found := app.StakingKeeper.GetValidator(ctx, validatorAddr1) + require.True(t, found) + require.Equal(t, sdk.Bonded, val1.Status, "%v", val1) +} + //func TestBondUnbondRedelegateSlashTwice(t *testing.T) { // ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) // handler := NewHandler(keeper) From bbbbc612763ffaca101839901df2b3c41b02c665 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Wed, 26 Feb 2020 15:48:51 +0100 Subject: [PATCH 239/529] end refactor handler_test --- x/staking/handler_test.go | 352 +++++++++++++++++++------------------- 1 file changed, 177 insertions(+), 175 deletions(-) diff --git a/x/staking/handler_test.go b/x/staking/handler_test.go index 46d804e56812..3cb050a4dd9f 100644 --- a/x/staking/handler_test.go +++ b/x/staking/handler_test.go @@ -1,6 +1,7 @@ package staking_test import ( + "strings" "testing" "time" @@ -1327,178 +1328,179 @@ func TestUnbondingWhenExcessValidators(t *testing.T) { require.Equal(t, sdk.Bonded, val1.Status, "%v", val1) } -//func TestBondUnbondRedelegateSlashTwice(t *testing.T) { -// ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) -// handler := NewHandler(keeper) -// -// valA, valB, del := sdk.ValAddress(Addrs[0]), sdk.ValAddress(Addrs[1]), Addrs[2] -// consAddr0 := sdk.ConsAddress(PKs[0].Address()) -// -// valTokens := sdk.TokensFromConsensusPower(10) -// msgCreateValidator := NewTestMsgCreateValidator(valA, PKs[0], valTokens) -// res, err := handler(ctx, msgCreateValidator) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// msgCreateValidator = NewTestMsgCreateValidator(valB, PKs[1], valTokens) -// res, err = handler(ctx, msgCreateValidator) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // delegate 10 stake -// msgDelegate := NewTestMsgDelegate(del, valA, valTokens) -// res, err = handler(ctx, msgDelegate) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // apply Tendermint updates -// updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) -// require.Equal(t, 2, len(updates)) -// -// // a block passes -// ctx = ctx.WithBlockHeight(1) -// -// // begin unbonding 4 stake -// unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(4)) -// msgUndelegate := NewMsgUndelegate(del, valA, unbondAmt) -// res, err = handler(ctx, msgUndelegate) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // begin redelegate 6 stake -// redAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(6)) -// msgBeginRedelegate := NewMsgBeginRedelegate(del, valA, valB, redAmt) -// res, err = handler(ctx, msgBeginRedelegate) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// // destination delegation should have 6 shares -// delegation, found := keeper.GetDelegation(ctx, del, valB) -// require.True(t, found) -// require.Equal(t, sdk.NewDecFromInt(redAmt.Amount), delegation.Shares) -// -// // must apply validator updates -// updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx) -// require.Equal(t, 2, len(updates)) -// -// // slash the validator by half -// keeper.Slash(ctx, consAddr0, 0, 20, sdk.NewDecWithPrec(5, 1)) -// -// // unbonding delegation should have been slashed by half -// ubd, found := keeper.GetUnbondingDelegation(ctx, del, valA) -// require.True(t, found) -// require.Len(t, ubd.Entries, 1) -// require.Equal(t, unbondAmt.Amount.QuoRaw(2), ubd.Entries[0].Balance) -// -// // redelegation should have been slashed by half -// redelegation, found := keeper.GetRedelegation(ctx, del, valA, valB) -// require.True(t, found) -// require.Len(t, redelegation.Entries, 1) -// -// // destination delegation should have been slashed by half -// delegation, found = keeper.GetDelegation(ctx, del, valB) -// require.True(t, found) -// require.Equal(t, sdk.NewDecFromInt(redAmt.Amount.QuoRaw(2)), delegation.Shares) -// -// // validator power should have been reduced by half -// validator, found := keeper.GetValidator(ctx, valA) -// require.True(t, found) -// require.Equal(t, valTokens.QuoRaw(2), validator.GetBondedTokens()) -// -// // slash the validator for an infraction committed after the unbonding and redelegation begin -// ctx = ctx.WithBlockHeight(3) -// keeper.Slash(ctx, consAddr0, 2, 10, sdk.NewDecWithPrec(5, 1)) -// -// // unbonding delegation should be unchanged -// ubd, found = keeper.GetUnbondingDelegation(ctx, del, valA) -// require.True(t, found) -// require.Len(t, ubd.Entries, 1) -// require.Equal(t, unbondAmt.Amount.QuoRaw(2), ubd.Entries[0].Balance) -// -// // redelegation should be unchanged -// redelegation, found = keeper.GetRedelegation(ctx, del, valA, valB) -// require.True(t, found) -// require.Len(t, redelegation.Entries, 1) -// -// // destination delegation should be unchanged -// delegation, found = keeper.GetDelegation(ctx, del, valB) -// require.True(t, found) -// require.Equal(t, sdk.NewDecFromInt(redAmt.Amount.QuoRaw(2)), delegation.Shares) -// -// // end blocker -// EndBlocker(ctx, keeper) -// -// // validator power should have been reduced to zero -// // validator should be in unbonding state -// validator, _ = keeper.GetValidator(ctx, valA) -// require.Equal(t, validator.GetStatus(), sdk.Unbonding) -//} -// -//func TestInvalidMsg(t *testing.T) { -// k := Keeper{} -// h := NewHandler(k) -// -// res, err := h(sdk.NewContext(nil, abci.Header{}, false, nil), sdk.NewTestMsg()) -// require.Error(t, err) -// require.Nil(t, res) -// require.True(t, strings.Contains(err.Error(), "unrecognized staking message type")) -//} -// -//func TestInvalidCoinDenom(t *testing.T) { -// ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) -// handler := NewHandler(keeper) -// -// valA, valB, delAddr := sdk.ValAddress(Addrs[0]), sdk.ValAddress(Addrs[1]), Addrs[2] -// -// valTokens := sdk.TokensFromConsensusPower(100) -// invalidCoin := sdk.NewCoin("churros", valTokens) -// validCoin := sdk.NewCoin(sdk.DefaultBondDenom, valTokens) -// oneCoin := sdk.NewCoin(sdk.DefaultBondDenom, sdk.OneInt()) -// -// commission := types.NewCommissionRates(sdk.OneDec(), sdk.OneDec(), sdk.ZeroDec()) -// -// msgCreate := types.NewMsgCreateValidator(valA, PKs[0], invalidCoin, Description{}, commission, sdk.OneInt()) -// res, err := handler(ctx, msgCreate) -// require.Error(t, err) -// require.Nil(t, res) -// -// msgCreate = types.NewMsgCreateValidator(valA, PKs[0], validCoin, Description{}, commission, sdk.OneInt()) -// res, err = handler(ctx, msgCreate) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// msgCreate = types.NewMsgCreateValidator(valB, PKs[1], validCoin, Description{}, commission, sdk.OneInt()) -// res, err = handler(ctx, msgCreate) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// msgDelegate := types.NewMsgDelegate(delAddr, valA, invalidCoin) -// res, err = handler(ctx, msgDelegate) -// require.Error(t, err) -// require.Nil(t, res) -// -// msgDelegate = types.NewMsgDelegate(delAddr, valA, validCoin) -// res, err = handler(ctx, msgDelegate) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// msgUndelegate := types.NewMsgUndelegate(delAddr, valA, invalidCoin) -// res, err = handler(ctx, msgUndelegate) -// require.Error(t, err) -// require.Nil(t, res) -// -// msgUndelegate = types.NewMsgUndelegate(delAddr, valA, oneCoin) -// res, err = handler(ctx, msgUndelegate) -// require.NoError(t, err) -// require.NotNil(t, res) -// -// msgRedelegate := types.NewMsgBeginRedelegate(delAddr, valA, valB, invalidCoin) -// res, err = handler(ctx, msgRedelegate) -// require.Error(t, err) -// require.Nil(t, res) -// -// msgRedelegate = types.NewMsgBeginRedelegate(delAddr, valA, valB, oneCoin) -// res, err = handler(ctx, msgRedelegate) -// require.NoError(t, err) -// require.NotNil(t, res) -//} +func TestBondUnbondRedelegateSlashTwice(t *testing.T) { + app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, 1000, 3, 1000000000) + + handler := staking.NewHandler(app.StakingKeeper) + + valA, valB, del := valAddrs[0], valAddrs[1], delAddrs[2] + consAddr0 := sdk.ConsAddress(PKs[0].Address()) + + valTokens := sdk.TokensFromConsensusPower(10) + msgCreateValidator := NewTestMsgCreateValidator(valA, PKs[0], valTokens) + res, err := handler(ctx, msgCreateValidator) + require.NoError(t, err) + require.NotNil(t, res) + + msgCreateValidator = NewTestMsgCreateValidator(valB, PKs[1], valTokens) + res, err = handler(ctx, msgCreateValidator) + require.NoError(t, err) + require.NotNil(t, res) + + // delegate 10 stake + msgDelegate := NewTestMsgDelegate(del, valA, valTokens) + res, err = handler(ctx, msgDelegate) + require.NoError(t, err) + require.NotNil(t, res) + + // apply Tendermint updates + updates := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 2, len(updates)) + + // a block passes + ctx = ctx.WithBlockHeight(1) + + // begin unbonding 4 stake + unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(4)) + msgUndelegate := types.NewMsgUndelegate(del, valA, unbondAmt) + res, err = handler(ctx, msgUndelegate) + require.NoError(t, err) + require.NotNil(t, res) + + // begin redelegate 6 stake + redAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(6)) + msgBeginRedelegate := types.NewMsgBeginRedelegate(del, valA, valB, redAmt) + res, err = handler(ctx, msgBeginRedelegate) + require.NoError(t, err) + require.NotNil(t, res) + + // destination delegation should have 6 shares + delegation, found := app.StakingKeeper.GetDelegation(ctx, del, valB) + require.True(t, found) + require.Equal(t, sdk.NewDecFromInt(redAmt.Amount), delegation.Shares) + + // must apply validator updates + updates = app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 2, len(updates)) + + // slash the validator by half + app.StakingKeeper.Slash(ctx, consAddr0, 0, 20, sdk.NewDecWithPrec(5, 1)) + + // unbonding delegation should have been slashed by half + ubd, found := app.StakingKeeper.GetUnbondingDelegation(ctx, del, valA) + require.True(t, found) + require.Len(t, ubd.Entries, 1) + require.Equal(t, unbondAmt.Amount.QuoRaw(2), ubd.Entries[0].Balance) + + // redelegation should have been slashed by half + redelegation, found := app.StakingKeeper.GetRedelegation(ctx, del, valA, valB) + require.True(t, found) + require.Len(t, redelegation.Entries, 1) + + // destination delegation should have been slashed by half + delegation, found = app.StakingKeeper.GetDelegation(ctx, del, valB) + require.True(t, found) + require.Equal(t, sdk.NewDecFromInt(redAmt.Amount.QuoRaw(2)), delegation.Shares) + + // validator power should have been reduced by half + validator, found := app.StakingKeeper.GetValidator(ctx, valA) + require.True(t, found) + require.Equal(t, valTokens.QuoRaw(2), validator.GetBondedTokens()) + + // slash the validator for an infraction committed after the unbonding and redelegation begin + ctx = ctx.WithBlockHeight(3) + app.StakingKeeper.Slash(ctx, consAddr0, 2, 10, sdk.NewDecWithPrec(5, 1)) + + // unbonding delegation should be unchanged + ubd, found = app.StakingKeeper.GetUnbondingDelegation(ctx, del, valA) + require.True(t, found) + require.Len(t, ubd.Entries, 1) + require.Equal(t, unbondAmt.Amount.QuoRaw(2), ubd.Entries[0].Balance) + + // redelegation should be unchanged + redelegation, found = app.StakingKeeper.GetRedelegation(ctx, del, valA, valB) + require.True(t, found) + require.Len(t, redelegation.Entries, 1) + + // destination delegation should be unchanged + delegation, found = app.StakingKeeper.GetDelegation(ctx, del, valB) + require.True(t, found) + require.Equal(t, sdk.NewDecFromInt(redAmt.Amount.QuoRaw(2)), delegation.Shares) + + // end blocker + staking.EndBlocker(ctx, app.StakingKeeper) + + // validator power should have been reduced to zero + // validator should be in unbonding state + validator, _ = app.StakingKeeper.GetValidator(ctx, valA) + require.Equal(t, validator.GetStatus(), sdk.Unbonding) +} + +func TestInvalidMsg(t *testing.T) { + k := staking.Keeper{} + h := staking.NewHandler(k) + + res, err := h(sdk.NewContext(nil, abci.Header{}, false, nil), sdk.NewTestMsg()) + require.Error(t, err) + require.Nil(t, res) + require.True(t, strings.Contains(err.Error(), "unrecognized staking message type")) +} + +func TestInvalidCoinDenom(t *testing.T) { + app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, 1000, 3, 1000000000) + handler := staking.NewHandler(app.StakingKeeper) + + valA, valB, delAddr := valAddrs[0], valAddrs[1], delAddrs[2] + + valTokens := sdk.TokensFromConsensusPower(100) + invalidCoin := sdk.NewCoin("churros", valTokens) + validCoin := sdk.NewCoin(sdk.DefaultBondDenom, valTokens) + oneCoin := sdk.NewCoin(sdk.DefaultBondDenom, sdk.OneInt()) + + commission := types.NewCommissionRates(sdk.OneDec(), sdk.OneDec(), sdk.ZeroDec()) + + msgCreate := types.NewMsgCreateValidator(valA, PKs[0], invalidCoin, types.Description{}, commission, sdk.OneInt()) + res, err := handler(ctx, msgCreate) + require.Error(t, err) + require.Nil(t, res) + + msgCreate = types.NewMsgCreateValidator(valA, PKs[0], validCoin, types.Description{}, commission, sdk.OneInt()) + res, err = handler(ctx, msgCreate) + require.NoError(t, err) + require.NotNil(t, res) + + msgCreate = types.NewMsgCreateValidator(valB, PKs[1], validCoin, types.Description{}, commission, sdk.OneInt()) + res, err = handler(ctx, msgCreate) + require.NoError(t, err) + require.NotNil(t, res) + + msgDelegate := types.NewMsgDelegate(delAddr, valA, invalidCoin) + res, err = handler(ctx, msgDelegate) + require.Error(t, err) + require.Nil(t, res) + + msgDelegate = types.NewMsgDelegate(delAddr, valA, validCoin) + res, err = handler(ctx, msgDelegate) + require.NoError(t, err) + require.NotNil(t, res) + + msgUndelegate := types.NewMsgUndelegate(delAddr, valA, invalidCoin) + res, err = handler(ctx, msgUndelegate) + require.Error(t, err) + require.Nil(t, res) + + msgUndelegate = types.NewMsgUndelegate(delAddr, valA, oneCoin) + res, err = handler(ctx, msgUndelegate) + require.NoError(t, err) + require.NotNil(t, res) + + msgRedelegate := types.NewMsgBeginRedelegate(delAddr, valA, valB, invalidCoin) + res, err = handler(ctx, msgRedelegate) + require.Error(t, err) + require.Nil(t, res) + + msgRedelegate = types.NewMsgBeginRedelegate(delAddr, valA, valB, oneCoin) + res, err = handler(ctx, msgRedelegate) + require.NoError(t, err) + require.NotNil(t, res) +} From 64c2971c6f1572e3d835bd54bd454208cb44b87b Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Wed, 26 Feb 2020 15:51:45 +0100 Subject: [PATCH 240/529] remove test_common --- x/staking/test_common.go | 220 --------------------------------------- 1 file changed, 220 deletions(-) delete mode 100644 x/staking/test_common.go diff --git a/x/staking/test_common.go b/x/staking/test_common.go deleted file mode 100644 index 1b9708e78ef8..000000000000 --- a/x/staking/test_common.go +++ /dev/null @@ -1,220 +0,0 @@ -package staking - -import ( - "bytes" - "encoding/hex" - "strconv" - "testing" - - simappcodec "github.com/cosmos/cosmos-sdk/simapp/codec" - - "github.com/stretchr/testify/require" - - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/crypto" - "github.com/tendermint/tendermint/crypto/ed25519" - "github.com/tendermint/tendermint/libs/log" - tmtypes "github.com/tendermint/tendermint/types" - dbm "github.com/tendermint/tm-db" - - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/store" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth" - authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" - "github.com/cosmos/cosmos-sdk/x/bank" - "github.com/cosmos/cosmos-sdk/x/params" - "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/cosmos/cosmos-sdk/x/supply" -) - -// dummy addresses used for testing -// nolint:unused, deadcode -var ( - Addrs = createTestAddrs(500) - PKs = createTestPubKeys(500) -) - -// nolint: unparam -func createTestAddrs(numAddrs int) []sdk.AccAddress { - var addresses []sdk.AccAddress - var buffer bytes.Buffer - - // start at 100 so we can make up to 999 test addresses with valid test addresses - for i := 100; i < (numAddrs + 100); i++ { - numString := strconv.Itoa(i) - buffer.WriteString("A58856F0FD53BF058B4909A21AEC019107BA6") //base address string - - buffer.WriteString(numString) //adding on final two digits to make addresses unique - res, _ := sdk.AccAddressFromHex(buffer.String()) - bech := res.String() - addresses = append(addresses, TestAddr(buffer.String(), bech)) - buffer.Reset() - } - return addresses -} - -// nolint: unparam -func createTestPubKeys(numPubKeys int) []crypto.PubKey { - var publicKeys []crypto.PubKey - var buffer bytes.Buffer - - //start at 10 to avoid changing 1 to 01, 2 to 02, etc - for i := 100; i < (numPubKeys + 100); i++ { - numString := strconv.Itoa(i) - buffer.WriteString("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AF") //base pubkey string - buffer.WriteString(numString) //adding on final two digits to make pubkeys unique - publicKeys = append(publicKeys, NewPubKey(buffer.String())) - buffer.Reset() - } - return publicKeys -} - -//_____________________________________________________________________________________ - -// Hogpodge of all sorts of input required for testing. -// `initPower` is converted to an amount of tokens. -// If `initPower` is 0, no addrs get created. -func CreateTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context, auth.AccountKeeper, types.BankKeeper, Keeper, types.SupplyKeeper) { - keyStaking := sdk.NewKVStoreKey(types.StoreKey) - keyAcc := sdk.NewKVStoreKey(auth.StoreKey) - bankKey := sdk.NewKVStoreKey(bank.StoreKey) - keyParams := sdk.NewKVStoreKey(params.StoreKey) - keySupply := sdk.NewKVStoreKey(supply.StoreKey) - - tkeyParams := sdk.NewTransientStoreKey(params.TStoreKey) - - db := dbm.NewMemDB() - ms := store.NewCommitMultiStore(db) - ms.MountStoreWithDB(keyStaking, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(keyAcc, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(bankKey, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(keyParams, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(tkeyParams, sdk.StoreTypeTransient, db) - ms.MountStoreWithDB(keySupply, sdk.StoreTypeIAVL, db) - err := ms.LoadLatestVersion() - require.Nil(t, err) - - ctx := sdk.NewContext(ms, abci.Header{ChainID: "foochainid"}, isCheckTx, log.NewNopLogger()) - ctx = ctx.WithConsensusParams( - &abci.ConsensusParams{ - Validator: &abci.ValidatorParams{ - PubKeyTypes: []string{tmtypes.ABCIPubKeyTypeEd25519}, - }, - }, - ) - cdc := MakeTestCodec() - appCodec := simappcodec.NewAppCodec(cdc) - - feeCollectorAcc := supply.NewEmptyModuleAccount(auth.FeeCollectorName) - notBondedPool := supply.NewEmptyModuleAccount(types.NotBondedPoolName, supply.Burner, supply.Staking) - bondPool := supply.NewEmptyModuleAccount(types.BondedPoolName, supply.Burner, supply.Staking) - - blacklistedAddrs := make(map[string]bool) - blacklistedAddrs[feeCollectorAcc.GetAddress().String()] = true - blacklistedAddrs[notBondedPool.GetAddress().String()] = true - blacklistedAddrs[bondPool.GetAddress().String()] = true - - pk := params.NewKeeper(appCodec, keyParams, tkeyParams) - - accountKeeper := auth.NewAccountKeeper( - appCodec, - keyAcc, // target store - pk.Subspace(auth.DefaultParamspace), - auth.ProtoBaseAccount, // prototype - ) - - bk := bank.NewBaseKeeper( - appCodec, - bankKey, - accountKeeper, - pk.Subspace(bank.DefaultParamspace), - blacklistedAddrs, - ) - - maccPerms := map[string][]string{ - auth.FeeCollectorName: nil, - types.NotBondedPoolName: {supply.Burner, supply.Staking}, - types.BondedPoolName: {supply.Burner, supply.Staking}, - } - supplyKeeper := supply.NewKeeper(appCodec, keySupply, accountKeeper, bk, maccPerms) - - initTokens := sdk.TokensFromConsensusPower(initPower) - initCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initTokens)) - totalSupply := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initTokens.MulRaw(int64(len(Addrs))))) - - supplyKeeper.SetSupply(ctx, supply.NewSupply(totalSupply)) - - keeper := NewKeeper(types.ModuleCdc, keyStaking, bk, supplyKeeper, pk.Subspace(DefaultParamspace)) - keeper.SetParams(ctx, types.DefaultParams()) - - // set module accounts - require.NoError(t, bk.SetBalances(ctx, notBondedPool.GetAddress(), totalSupply)) - - supplyKeeper.SetModuleAccount(ctx, feeCollectorAcc) - supplyKeeper.SetModuleAccount(ctx, bondPool) - supplyKeeper.SetModuleAccount(ctx, notBondedPool) - - // fill all the addresses with some coins, set the loose pool tokens simultaneously - for i, addr := range Addrs { - accountKeeper.SetAccount(ctx, auth.NewBaseAccount(addr, PKs[i], uint64(i), 0)) - require.NoError(t, bk.SetBalances(ctx, addr, initCoins)) - } - - return ctx, accountKeeper, bk, keeper, supplyKeeper -} - -// create a codec used only for testing -func MakeTestCodec() *codec.Codec { - var cdc = codec.New() - - // Register Msgs - cdc.RegisterInterface((*sdk.Msg)(nil), nil) - cdc.RegisterConcrete(bank.MsgSend{}, "test/staking/Send", nil) - cdc.RegisterConcrete(types.MsgCreateValidator{}, "test/staking/CreateValidator", nil) - cdc.RegisterConcrete(types.MsgEditValidator{}, "test/staking/EditValidator", nil) - cdc.RegisterConcrete(types.MsgUndelegate{}, "test/staking/Undelegate", nil) - cdc.RegisterConcrete(types.MsgBeginRedelegate{}, "test/staking/BeginRedelegate", nil) - - // Register AppAccount - cdc.RegisterInterface((*authexported.Account)(nil), nil) - cdc.RegisterConcrete(&auth.BaseAccount{}, "test/staking/BaseAccount", nil) - supply.RegisterCodec(cdc) - codec.RegisterCrypto(cdc) - - return cdc -} - -// for incode address generation -func TestAddr(addr string, bech string) sdk.AccAddress { - - res, err := sdk.AccAddressFromHex(addr) - if err != nil { - panic(err) - } - bechexpected := res.String() - if bech != bechexpected { - panic("Bech encoding doesn't match reference") - } - - bechres, err := sdk.AccAddressFromBech32(bech) - if err != nil { - panic(err) - } - if !bytes.Equal(bechres, res) { - panic("Bech decode and hex decode don't match") - } - - return res -} - -func NewPubKey(pk string) (res crypto.PubKey) { - pkBytes, err := hex.DecodeString(pk) - if err != nil { - panic(err) - } - //res, err = crypto.PubKeyFromBytes(pkBytes) - var pkEd ed25519.PubKeyEd25519 - copy(pkEd[:], pkBytes) - return pkEd -} From 1d18f8839c2ec59e1bdf512b1f594219bae369b1 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Wed, 26 Feb 2020 15:57:41 +0100 Subject: [PATCH 241/529] remove create test public keys --- x/staking/keeper/common_test.go | 40 ++---------------------- x/staking/keeper/delegation_test.go | 30 +++++++++--------- x/staking/keeper/historical_info_test.go | 4 +-- x/staking/keeper/querier_test.go | 14 ++++----- x/staking/keeper/slash_test.go | 2 +- x/staking/keeper/validator_test.go | 2 +- 6 files changed, 29 insertions(+), 63 deletions(-) diff --git a/x/staking/keeper/common_test.go b/x/staking/keeper/common_test.go index 69a168e5a404..30306adc6f6e 100644 --- a/x/staking/keeper/common_test.go +++ b/x/staking/keeper/common_test.go @@ -1,14 +1,8 @@ package keeper_test import ( - "bytes" - "encoding/hex" - "strconv" "testing" - "github.com/tendermint/tendermint/crypto" - "github.com/tendermint/tendermint/crypto/ed25519" - "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/simapp" cdc "github.com/cosmos/cosmos-sdk/simapp/codec" @@ -20,40 +14,12 @@ import ( ) var ( - PKs = createTestPubKeys(500) + PKs = simapp.CreateTestPubKeys(500) ) -// nolint: unparam -func createTestPubKeys(numPubKeys int) []crypto.PubKey { - var publicKeys []crypto.PubKey - var buffer bytes.Buffer - - //start at 10 to avoid changing 1 to 01, 2 to 02, etc - for i := 100; i < (numPubKeys + 100); i++ { - numString := strconv.Itoa(i) - buffer.WriteString("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AF") //base pubkey string - buffer.WriteString(numString) //adding on final two digits to make pubkeys unique - publicKeys = append(publicKeys, NewPubKey(buffer.String())) - buffer.Reset() - } - - return publicKeys -} - -func NewPubKey(pk string) (res crypto.PubKey) { - pkBytes, err := hex.DecodeString(pk) - if err != nil { - panic(err) - } - //res, err = crypto.PubKeyFromBytes(pkBytes) - var pkEd ed25519.PubKeyEd25519 - copy(pkEd[:], pkBytes) - return pkEd -} - -// getBaseSimappWithCustomKeeper Returns a simapp with custom StakingKeeper +// createTestInput Returns a simapp with custom StakingKeeper // to avoid messing with the hooks. -func getBaseSimappWithCustomKeeper() (*codec.Codec, *simapp.SimApp, sdk.Context) { +func createTestInput() (*codec.Codec, *simapp.SimApp, sdk.Context) { app := simapp.Setup(false) ctx := app.BaseApp.NewContext(false, abci.Header{}) diff --git a/x/staking/keeper/delegation_test.go b/x/staking/keeper/delegation_test.go index a1b0c6841c54..e1f7b7de2464 100644 --- a/x/staking/keeper/delegation_test.go +++ b/x/staking/keeper/delegation_test.go @@ -15,7 +15,7 @@ import ( // tests GetDelegation, GetDelegatorDelegations, SetDelegation, RemoveDelegation, GetDelegatorDelegations func TestDelegation(t *testing.T) { - _, app, ctx := getBaseSimappWithCustomKeeper() + _, app, ctx := createTestInput() addrDels := simapp.AddTestAddrsIncremental(app, ctx, 3, sdk.NewInt(10000)) valAddrs := simapp.ConvertAddrsToValAddrs(addrDels) @@ -131,7 +131,7 @@ func TestDelegation(t *testing.T) { // tests Get/Set/Remove UnbondingDelegation func TestUnbondingDelegation(t *testing.T) { - _, app, ctx := getBaseSimappWithCustomKeeper() + _, app, ctx := createTestInput() delAddrs := simapp.AddTestAddrsIncremental(app, ctx, 2, sdk.NewInt(10000)) valAddrs := simapp.ConvertAddrsToValAddrs(delAddrs) @@ -177,7 +177,7 @@ func TestUnbondingDelegation(t *testing.T) { } func TestUnbondDelegation(t *testing.T) { - _, app, ctx := getBaseSimappWithCustomKeeper() + _, app, ctx := createTestInput() delAddrs := simapp.AddTestAddrsIncremental(app, ctx, 1, sdk.NewInt(10000)) valAddrs := simapp.ConvertAddrsToValAddrs(delAddrs) @@ -222,7 +222,7 @@ func TestUnbondDelegation(t *testing.T) { } func TestUnbondingDelegationsMaxEntries(t *testing.T) { - _, app, ctx := getBaseSimappWithCustomKeeper() + _, app, ctx := createTestInput() addrDels := simapp.AddTestAddrsIncremental(app, ctx, 1, sdk.NewInt(10000)) addrVals := simapp.ConvertAddrsToValAddrs(addrDels) @@ -305,7 +305,7 @@ func TestUnbondingDelegationsMaxEntries(t *testing.T) { //// test undelegating self delegation from a validator pushing it below MinSelfDelegation //// shift it from the bonded to unbonding state and jailed func TestUndelegateSelfDelegationBelowMinSelfDelegation(t *testing.T) { - _, app, ctx := getBaseSimappWithCustomKeeper() + _, app, ctx := createTestInput() addrDels := simapp.AddTestAddrsIncremental(app, ctx, 1, sdk.NewInt(10000)) addrVals := simapp.ConvertAddrsToValAddrs(addrDels) @@ -371,7 +371,7 @@ func TestUndelegateSelfDelegationBelowMinSelfDelegation(t *testing.T) { } func TestUndelegateFromUnbondingValidator(t *testing.T) { - _, app, ctx := getBaseSimappWithCustomKeeper() + _, app, ctx := createTestInput() delTokens := sdk.TokensFromConsensusPower(10) delCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), delTokens)) @@ -464,7 +464,7 @@ func TestUndelegateFromUnbondingValidator(t *testing.T) { } func TestUndelegateFromUnbondedValidator(t *testing.T) { - _, app, ctx := getBaseSimappWithCustomKeeper() + _, app, ctx := createTestInput() delTokens := sdk.TokensFromConsensusPower(10) delCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), delTokens)) @@ -548,7 +548,7 @@ func TestUndelegateFromUnbondedValidator(t *testing.T) { } func TestUnbondingAllDelegationFromValidator(t *testing.T) { - _, app, ctx := getBaseSimappWithCustomKeeper() + _, app, ctx := createTestInput() delTokens := sdk.TokensFromConsensusPower(10) delCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), delTokens)) @@ -624,7 +624,7 @@ func TestUnbondingAllDelegationFromValidator(t *testing.T) { // Make sure that that the retrieving the delegations doesn't affect the state func TestGetRedelegationsFromSrcValidator(t *testing.T) { - _, app, ctx := getBaseSimappWithCustomKeeper() + _, app, ctx := createTestInput() addrDels := simapp.AddTestAddrsIncremental(app, ctx, 2, sdk.NewInt(0)) addrVals := simapp.ConvertAddrsToValAddrs(addrDels) @@ -651,7 +651,7 @@ func TestGetRedelegationsFromSrcValidator(t *testing.T) { // tests Get/Set/Remove/Has UnbondingDelegation func TestRedelegation(t *testing.T) { - _, app, ctx := getBaseSimappWithCustomKeeper() + _, app, ctx := createTestInput() addrDels := simapp.AddTestAddrsIncremental(app, ctx, 2, sdk.NewInt(0)) addrVals := simapp.ConvertAddrsToValAddrs(addrDels) @@ -714,7 +714,7 @@ func TestRedelegation(t *testing.T) { } func TestRedelegateToSameValidator(t *testing.T) { - _, app, ctx := getBaseSimappWithCustomKeeper() + _, app, ctx := createTestInput() addrDels := simapp.AddTestAddrsIncremental(app, ctx, 1, sdk.NewInt(0)) addrVals := simapp.ConvertAddrsToValAddrs(addrDels) @@ -745,7 +745,7 @@ func TestRedelegateToSameValidator(t *testing.T) { } func TestRedelegationMaxEntries(t *testing.T) { - _, app, ctx := getBaseSimappWithCustomKeeper() + _, app, ctx := createTestInput() addrDels := simapp.AddTestAddrsIncremental(app, ctx, 2, sdk.NewInt(0)) addrVals := simapp.ConvertAddrsToValAddrs(addrDels) @@ -803,7 +803,7 @@ func TestRedelegationMaxEntries(t *testing.T) { } func TestRedelegateSelfDelegation(t *testing.T) { - _, app, ctx := getBaseSimappWithCustomKeeper() + _, app, ctx := createTestInput() addrDels := simapp.AddTestAddrsIncremental(app, ctx, 2, sdk.NewInt(0)) addrVals := simapp.ConvertAddrsToValAddrs(addrDels) @@ -860,7 +860,7 @@ func TestRedelegateSelfDelegation(t *testing.T) { } func TestRedelegateFromUnbondingValidator(t *testing.T) { - _, app, ctx := getBaseSimappWithCustomKeeper() + _, app, ctx := createTestInput() addrDels := simapp.AddTestAddrsIncremental(app, ctx, 2, sdk.NewInt(0)) addrVals := simapp.ConvertAddrsToValAddrs(addrDels) @@ -944,7 +944,7 @@ func TestRedelegateFromUnbondingValidator(t *testing.T) { } func TestRedelegateFromUnbondedValidator(t *testing.T) { - _, app, ctx := getBaseSimappWithCustomKeeper() + _, app, ctx := createTestInput() addrDels := simapp.AddTestAddrsIncremental(app, ctx, 2, sdk.NewInt(0)) addrVals := simapp.ConvertAddrsToValAddrs(addrDels) diff --git a/x/staking/keeper/historical_info_test.go b/x/staking/keeper/historical_info_test.go index d4ed693106e6..3a3f1100592b 100644 --- a/x/staking/keeper/historical_info_test.go +++ b/x/staking/keeper/historical_info_test.go @@ -15,7 +15,7 @@ import ( ) func TestHistoricalInfo(t *testing.T) { - _, app, ctx := getBaseSimappWithCustomKeeper() + _, app, ctx := createTestInput() addrDels := simapp.AddTestAddrsIncremental(app, ctx, 50, sdk.NewInt(0)) addrVals := simapp.ConvertAddrsToValAddrs(addrDels) @@ -43,7 +43,7 @@ func TestHistoricalInfo(t *testing.T) { } func TestTrackHistoricalInfo(t *testing.T) { - _, app, ctx := getBaseSimappWithCustomKeeper() + _, app, ctx := createTestInput() addrDels := simapp.AddTestAddrsIncremental(app, ctx, 50, sdk.NewInt(0)) addrVals := simapp.ConvertAddrsToValAddrs(addrDels) diff --git a/x/staking/keeper/querier_test.go b/x/staking/keeper/querier_test.go index 09a19b894f4f..3ca2ba33537f 100644 --- a/x/staking/keeper/querier_test.go +++ b/x/staking/keeper/querier_test.go @@ -15,7 +15,7 @@ import ( ) func TestNewQuerier(t *testing.T) { - cdc, app, ctx := getBaseSimappWithCustomKeeper() + cdc, app, ctx := createTestInput() addrs := simapp.AddTestAddrs(app, ctx, 500, sdk.NewInt(10000)) _, addrAcc2 := addrs[0], addrs[1] @@ -106,7 +106,7 @@ func TestNewQuerier(t *testing.T) { } func TestQueryParametersPool(t *testing.T) { - cdc, app, ctx := getBaseSimappWithCustomKeeper() + cdc, app, ctx := createTestInput() querier := staking.NewQuerier(app.StakingKeeper) bondDenom := sdk.DefaultBondDenom @@ -131,7 +131,7 @@ func TestQueryParametersPool(t *testing.T) { } func TestQueryValidators(t *testing.T) { - cdc, app, ctx := getBaseSimappWithCustomKeeper() + cdc, app, ctx := createTestInput() params := app.StakingKeeper.GetParams(ctx) querier := staking.NewQuerier(app.StakingKeeper) @@ -198,7 +198,7 @@ func TestQueryValidators(t *testing.T) { } func TestQueryDelegation(t *testing.T) { - cdc, app, ctx := getBaseSimappWithCustomKeeper() + cdc, app, ctx := createTestInput() params := app.StakingKeeper.GetParams(ctx) querier := staking.NewQuerier(app.StakingKeeper) @@ -425,7 +425,7 @@ func TestQueryDelegation(t *testing.T) { } func TestQueryRedelegations(t *testing.T) { - cdc, app, ctx := getBaseSimappWithCustomKeeper() + cdc, app, ctx := createTestInput() querier := staking.NewQuerier(app.StakingKeeper) addrs := simapp.AddTestAddrs(app, ctx, 2, sdk.TokensFromConsensusPower(10000)) @@ -494,7 +494,7 @@ func TestQueryRedelegations(t *testing.T) { } func TestQueryUnbondingDelegation(t *testing.T) { - cdc, app, ctx := getBaseSimappWithCustomKeeper() + cdc, app, ctx := createTestInput() querier := staking.NewQuerier(app.StakingKeeper) addrs := simapp.AddTestAddrs(app, ctx, 2, sdk.TokensFromConsensusPower(10000)) @@ -589,7 +589,7 @@ func TestQueryUnbondingDelegation(t *testing.T) { } func TestQueryHistoricalInfo(t *testing.T) { - cdc, app, ctx := getBaseSimappWithCustomKeeper() + cdc, app, ctx := createTestInput() querier := staking.NewQuerier(app.StakingKeeper) addrs := simapp.AddTestAddrs(app, ctx, 2, sdk.TokensFromConsensusPower(10000)) diff --git a/x/staking/keeper/slash_test.go b/x/staking/keeper/slash_test.go index fae13244c992..e333967a8cf7 100644 --- a/x/staking/keeper/slash_test.go +++ b/x/staking/keeper/slash_test.go @@ -19,7 +19,7 @@ import ( // bootstrapSlashTest creates 3 validators and bootstrap the app. func bootstrapSlashTest(t *testing.T, power int64) (*simapp.SimApp, sdk.Context, []sdk.AccAddress, []sdk.ValAddress) { - _, app, ctx := getBaseSimappWithCustomKeeper() + _, app, ctx := createTestInput() addrDels, addrVals := generateAddresses(app, ctx, 100) diff --git a/x/staking/keeper/validator_test.go b/x/staking/keeper/validator_test.go index 6f2be5472501..f7295a5421de 100644 --- a/x/staking/keeper/validator_test.go +++ b/x/staking/keeper/validator_test.go @@ -18,7 +18,7 @@ import ( ) func bootstrapValidatorTest(t *testing.T, power int64, numAddrs int) (*simapp.SimApp, sdk.Context, []sdk.AccAddress, []sdk.ValAddress) { - _, app, ctx := getBaseSimappWithCustomKeeper() + _, app, ctx := createTestInput() addrDels, addrVals := generateAddresses(app, ctx, numAddrs) From c94a98f4598237fff410d605bec7107f6e60b74b Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Wed, 26 Feb 2020 16:05:12 +0100 Subject: [PATCH 242/529] fix based on PR comments --- simapp/test_helpers.go | 28 +++++++++++++++++----------- x/staking/genesis_test.go | 3 +-- x/staking/handler_test.go | 9 ++++----- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/simapp/test_helpers.go b/simapp/test_helpers.go index 78f2fbc41476..aeabbc47805e 100644 --- a/simapp/test_helpers.go +++ b/simapp/test_helpers.go @@ -3,6 +3,7 @@ package simapp import ( "bytes" "encoding/hex" + "fmt" "strconv" "testing" @@ -106,7 +107,9 @@ func incremental(accNum int) []sdk.AccAddress { buffer.WriteString(numString) //adding on final two digits to make addresses unique res, _ := sdk.AccAddressFromHex(buffer.String()) bech := res.String() - addresses = append(addresses, TestAddr(buffer.String(), bech)) + addr, _ := TestAddr(buffer.String(), bech) + + addresses = append(addresses, addr) buffer.Reset() } @@ -146,33 +149,36 @@ func addTestAddrs(app *SimApp, ctx sdk.Context, accNum int, accAmt sdk.Int, stra return testAddrs } -func ConvertAddrsToValAddrs(addrs []sdk.AccAddress) (valAddrs []sdk.ValAddress) { +//ConvertAddrsToValAddrs converts the provided addresses to +func ConvertAddrsToValAddrs(addrs []sdk.AccAddress) []sdk.ValAddress { + var valAddrs []sdk.ValAddress + for _, addr := range addrs { valAddrs = append(valAddrs, sdk.ValAddress(addr)) } - return + return valAddrs } -func TestAddr(addr string, bech string) sdk.AccAddress { +func TestAddr(addr string, bech string) (sdk.AccAddress, error) { res, err := sdk.AccAddressFromHex(addr) if err != nil { - panic(err) + return nil, err } bechexpected := res.String() if bech != bechexpected { - panic("Bech encoding doesn't match reference") + return nil, fmt.Errorf("bech encoding doesn't match reference") } bechres, err := sdk.AccAddressFromBech32(bech) if err != nil { - panic(err) + return nil, err } if !bytes.Equal(bechres, res) { - panic("Bech decode and hex decode don't match") + return nil, err } - return res + return res, nil } // CheckBalance checks the balance of an account. @@ -268,14 +274,14 @@ func CreateTestPubKeys(numPubKeys int) []crypto.PubKey { numString := strconv.Itoa(i) buffer.WriteString("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AF") //base pubkey string buffer.WriteString(numString) //adding on final two digits to make pubkeys unique - publicKeys = append(publicKeys, NewPubKey(buffer.String())) + publicKeys = append(publicKeys, NewPubKeyFromHex(buffer.String())) buffer.Reset() } return publicKeys } -func NewPubKey(pk string) (res crypto.PubKey) { +func NewPubKeyFromHex(pk string) (res crypto.PubKey) { pkBytes, err := hex.DecodeString(pk) if err != nil { panic(err) diff --git a/x/staking/genesis_test.go b/x/staking/genesis_test.go index c50cd63bcdf4..3d3419f3ba54 100644 --- a/x/staking/genesis_test.go +++ b/x/staking/genesis_test.go @@ -5,11 +5,10 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/tendermint/tendermint/crypto/ed25519" - "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto/ed25519" "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/x/staking/handler_test.go b/x/staking/handler_test.go index 3cb050a4dd9f..0f5f61edf233 100644 --- a/x/staking/handler_test.go +++ b/x/staking/handler_test.go @@ -5,15 +5,14 @@ import ( "testing" "time" + gogotypes "github.com/gogo/protobuf/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto/secp256k1" tmtypes "github.com/tendermint/tendermint/types" - "github.com/stretchr/testify/assert" - - gogotypes "github.com/gogo/protobuf/types" - "github.com/stretchr/testify/require" - "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/staking" From 1648edfc0d40bf7327c7ef322d746a9c05153c36 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Wed, 26 Feb 2020 16:16:56 +0100 Subject: [PATCH 243/529] use prealloc array for ConvertAddrsToValAddrs --- simapp/test_helpers.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/simapp/test_helpers.go b/simapp/test_helpers.go index aeabbc47805e..e07e7373220f 100644 --- a/simapp/test_helpers.go +++ b/simapp/test_helpers.go @@ -151,10 +151,10 @@ func addTestAddrs(app *SimApp, ctx sdk.Context, accNum int, accAmt sdk.Int, stra //ConvertAddrsToValAddrs converts the provided addresses to func ConvertAddrsToValAddrs(addrs []sdk.AccAddress) []sdk.ValAddress { - var valAddrs []sdk.ValAddress + valAddrs := make([]sdk.ValAddress, len(addrs)) - for _, addr := range addrs { - valAddrs = append(valAddrs, sdk.ValAddress(addr)) + for i, addr := range addrs { + valAddrs[i] = sdk.ValAddress(addr) } return valAddrs From 14469ccc74dbd534a67a7c6d47efe4ec544c5a4a Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Wed, 26 Feb 2020 16:29:48 +0100 Subject: [PATCH 244/529] fix lint errors --- x/staking/keeper/querier_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x/staking/keeper/querier_test.go b/x/staking/keeper/querier_test.go index 3ca2ba33537f..be4eab297caf 100644 --- a/x/staking/keeper/querier_test.go +++ b/x/staking/keeper/querier_test.go @@ -250,7 +250,7 @@ func TestQueryDelegation(t *testing.T) { // error unknown request query.Data = bz[:len(bz)-1] - res, err = querier(ctx, []string{types.QueryDelegatorValidators}, query) + _, err = querier(ctx, []string{types.QueryDelegatorValidators}, query) require.Error(t, err) // Query bonded validator @@ -275,7 +275,7 @@ func TestQueryDelegation(t *testing.T) { // error unknown request query.Data = bz[:len(bz)-1] - res, err = querier(ctx, []string{types.QueryDelegatorValidator}, query) + _, err = querier(ctx, []string{types.QueryDelegatorValidator}, query) require.Error(t, err) // Query delegation @@ -319,7 +319,7 @@ func TestQueryDelegation(t *testing.T) { // error unknown request query.Data = bz[:len(bz)-1] - res, err = querier(ctx, []string{types.QueryDelegation}, query) + _, err = querier(ctx, []string{types.QueryDelegation}, query) require.Error(t, err) // Query validator delegations From 8cab43c8120fec5200c3459cbf4a92017bb6f287 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Wed, 26 Feb 2020 10:33:56 -0500 Subject: [PATCH 245/529] Merge PR #5702: Add Param Querying to x/auth --- CHANGELOG.md | 5 ++-- simapp/codec/msgs.go | 8 +++--- x/auth/alias.go | 1 + x/auth/client/cli/query.go | 36 +++++++++++++++++++++++++- x/auth/client/rest/query.go | 19 ++++++++++++++ x/auth/client/rest/rest.go | 12 ++++++++- x/auth/keeper/querier.go | 27 ++++++++++++++----- x/auth/types/account_retriever_test.go | 9 ++++--- x/auth/types/keys.go | 4 +-- x/auth/types/querier.go | 1 + x/evidence/handler_test.go | 13 ++++++++-- x/evidence/types/msgs_test.go | 11 ++++++-- 12 files changed, 124 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e9979d32608..1c3a38ae1e37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,8 +41,8 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (modules) [\#5572](https://github.com/cosmos/cosmos-sdk/pull/5572) The `/bank/balances/{address}` endpoint now returns all account balances or a single balance by denom when the `denom` query parameter is present. -* (client) [\#5640](https://github.com/cosmos/cosmos-sdk/pull/5640) The rest server endpoint `/swagger-ui/` is replaced by -´/´. +* (client) [\#5640](https://github.com/cosmos/cosmos-sdk/pull/5640) The rest server endpoint `/swagger-ui/` is replaced by ´/´. +* (x/auth) [\#5702](https://github.com/cosmos/cosmos-sdk/pull/5702) The `x/auth` querier route has changed from `"acc"` to `"auth"`. ### API Breaking Changes @@ -133,6 +133,7 @@ Buffers for state serialization instead of Amino. ### Improvements +* (x/auth) [\#5702](https://github.com/cosmos/cosmos-sdk/pull/5702) Add parameter querying support for `x/auth`. * (types) [\#5581](https://github.com/cosmos/cosmos-sdk/pull/5581) Add convenience functions {,Must}Bech32ifyAddressBytes. * (staking) [\#5584](https://github.com/cosmos/cosmos-sdk/pull/5584) Add util function `ToTmValidator` that converts a `staking.Validator` type to `*tmtypes.Validator`. * (client) [\#5585](https://github.com/cosmos/cosmos-sdk/pull/5585) IBC additions: diff --git a/simapp/codec/msgs.go b/simapp/codec/msgs.go index d6390261bee4..2ea6c3a3a73d 100644 --- a/simapp/codec/msgs.go +++ b/simapp/codec/msgs.go @@ -10,11 +10,13 @@ import ( var _ eviexported.MsgSubmitEvidence = MsgSubmitEvidence{} // NewMsgSubmitEvidence returns a new MsgSubmitEvidence. -func NewMsgSubmitEvidence(evidenceI eviexported.Evidence, s sdk.AccAddress) MsgSubmitEvidence { +func NewMsgSubmitEvidence(evidenceI eviexported.Evidence, s sdk.AccAddress) (MsgSubmitEvidence, error) { e := &Evidence{} - e.SetEvidence(evidenceI) + if err := e.SetEvidence(evidenceI); err != nil { + return MsgSubmitEvidence{}, err + } - return MsgSubmitEvidence{Evidence: e, MsgSubmitEvidenceBase: evidence.NewMsgSubmitEvidenceBase(s)} + return MsgSubmitEvidence{Evidence: e, MsgSubmitEvidenceBase: evidence.NewMsgSubmitEvidenceBase(s)}, nil } // ValidateBasic performs basic (non-state-dependant) validation on a diff --git a/x/auth/alias.go b/x/auth/alias.go index b5d5516352e6..6c242caf5178 100644 --- a/x/auth/alias.go +++ b/x/auth/alias.go @@ -21,6 +21,7 @@ const ( DefaultSigVerifyCostED25519 = types.DefaultSigVerifyCostED25519 DefaultSigVerifyCostSecp256k1 = types.DefaultSigVerifyCostSecp256k1 QueryAccount = types.QueryAccount + QueryParams = types.QueryParams ) var ( diff --git a/x/auth/client/cli/query.go b/x/auth/client/cli/query.go index ebb5f3f508a8..0ef0a46e91a4 100644 --- a/x/auth/client/cli/query.go +++ b/x/auth/client/cli/query.go @@ -36,11 +36,45 @@ func GetQueryCmd(cdc *codec.Codec) *cobra.Command { RunE: client.ValidateCmd, } - cmd.AddCommand(GetAccountCmd(cdc)) + cmd.AddCommand( + flags.GetCommands( + GetAccountCmd(cdc), + QueryParamsCmd(cdc), + )..., + ) return cmd } +// QueryParamsCmd returns the command handler for evidence parameter querying. +func QueryParamsCmd(cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "params", + Short: "Query the current auth parameters", + Args: cobra.NoArgs, + Long: strings.TrimSpace(`Query the current auth parameters: + +$ query auth params +`), + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + + route := fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryParams) + res, _, err := cliCtx.QueryWithData(route, nil) + if err != nil { + return err + } + + var params types.Params + if err := cdc.UnmarshalJSON(res, ¶ms); err != nil { + return fmt.Errorf("failed to unmarshal params: %w", err) + } + + return cliCtx.PrintOutput(params) + }, + } +} + // GetAccountCmd returns a query account that will display the state of the // account at a given address. func GetAccountCmd(cdc *codec.Codec) *cobra.Command { diff --git a/x/auth/client/rest/query.go b/x/auth/client/rest/query.go index 6f245e40a2cf..8ff7f567d05b 100644 --- a/x/auth/client/rest/query.go +++ b/x/auth/client/rest/query.go @@ -138,3 +138,22 @@ func QueryTxRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { rest.PostProcessResponseBare(w, cliCtx, output) } } + +func queryParamsHandler(cliCtx context.CLIContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) + if !ok { + return + } + + route := fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryParams) + res, height, err := cliCtx.QueryWithData(route, nil) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + + cliCtx = cliCtx.WithHeight(height) + rest.PostProcessResponse(w, cliCtx, res) + } +} diff --git a/x/auth/client/rest/rest.go b/x/auth/client/rest/rest.go index 98dc8134127a..e69388dc41a4 100644 --- a/x/auth/client/rest/rest.go +++ b/x/auth/client/rest/rest.go @@ -6,11 +6,21 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" ) +// REST query and parameter values +const ( + MethodGet = "GET" +) + // RegisterRoutes registers the auth module REST routes. func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, storeName string) { r.HandleFunc( "/auth/accounts/{address}", QueryAccountRequestHandlerFn(storeName, cliCtx), - ).Methods("GET") + ).Methods(MethodGet) + + r.HandleFunc( + "/auth/params", + queryParamsHandler(cliCtx), + ).Methods(MethodGet) } // RegisterTxRoutes registers all transaction routes on the provided router. diff --git a/x/auth/keeper/querier.go b/x/auth/keeper/querier.go index 28e505970b45..eab5d3afcaa7 100644 --- a/x/auth/keeper/querier.go +++ b/x/auth/keeper/querier.go @@ -10,32 +10,47 @@ import ( ) // NewQuerier creates a querier for auth REST endpoints -func NewQuerier(keeper AccountKeeper) sdk.Querier { +func NewQuerier(k AccountKeeper) sdk.Querier { return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) { switch path[0] { case types.QueryAccount: - return queryAccount(ctx, req, keeper) + return queryAccount(ctx, req, k) + + case types.QueryParams: + return queryParams(ctx, k) + default: return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown query path: %s", path[0]) } } } -func queryAccount(ctx sdk.Context, req abci.RequestQuery, keeper AccountKeeper) ([]byte, error) { +func queryAccount(ctx sdk.Context, req abci.RequestQuery, k AccountKeeper) ([]byte, error) { var params types.QueryAccountParams - if err := keeper.cdc.UnmarshalJSON(req.Data, ¶ms); err != nil { + if err := k.cdc.UnmarshalJSON(req.Data, ¶ms); err != nil { return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } - account := keeper.GetAccount(ctx, params.Address) + account := k.GetAccount(ctx, params.Address) if account == nil { return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "account %s does not exist", params.Address) } - bz, err := codec.MarshalJSONIndent(keeper.cdc, account) + bz, err := codec.MarshalJSONIndent(k.cdc, account) if err != nil { return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return bz, nil } + +func queryParams(ctx sdk.Context, k AccountKeeper) ([]byte, error) { + params := k.GetParams(ctx) + + res, err := codec.MarshalJSONIndent(k.cdc, params) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) + } + + return res, nil +} diff --git a/x/auth/types/account_retriever_test.go b/x/auth/types/account_retriever_test.go index 0481e00b263b..99310d1170ff 100644 --- a/x/auth/types/account_retriever_test.go +++ b/x/auth/types/account_retriever_test.go @@ -2,6 +2,7 @@ package types_test import ( "errors" + "fmt" "testing" "github.com/golang/mock/gomock" @@ -23,19 +24,21 @@ func TestAccountRetriever(t *testing.T) { bs, err := appCodec.MarshalJSON(types.NewQueryAccountParams(addr)) require.NoError(t, err) - mockNodeQuerier.EXPECT().QueryWithData(gomock.Eq("custom/acc/account"), + route := fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryAccount) + + mockNodeQuerier.EXPECT().QueryWithData(gomock.Eq(route), gomock.Eq(bs)).Return(nil, int64(0), errFoo).Times(1) _, err = accRetr.GetAccount(addr) require.Error(t, err) - mockNodeQuerier.EXPECT().QueryWithData(gomock.Eq("custom/acc/account"), + mockNodeQuerier.EXPECT().QueryWithData(gomock.Eq(route), gomock.Eq(bs)).Return(nil, int64(0), errFoo).Times(1) n, s, err := accRetr.GetAccountNumberSequence(addr) require.Error(t, err) require.Equal(t, uint64(0), n) require.Equal(t, uint64(0), s) - mockNodeQuerier.EXPECT().QueryWithData(gomock.Eq("custom/acc/account"), + mockNodeQuerier.EXPECT().QueryWithData(gomock.Eq(route), gomock.Eq(bs)).Return(nil, int64(0), errFoo).Times(1) require.Error(t, accRetr.EnsureExists(addr)) } diff --git a/x/auth/types/keys.go b/x/auth/types/keys.go index 149fe2ba51f3..4cb2538f252c 100644 --- a/x/auth/types/keys.go +++ b/x/auth/types/keys.go @@ -14,8 +14,8 @@ const ( // FeeCollectorName the root string for the fee collector account address FeeCollectorName = "fee_collector" - // QuerierRoute is the querier route for acc - QuerierRoute = StoreKey + // QuerierRoute is the querier route for auth + QuerierRoute = ModuleName ) var ( diff --git a/x/auth/types/querier.go b/x/auth/types/querier.go index 84a80b1411a4..35a7e0ccf32a 100644 --- a/x/auth/types/querier.go +++ b/x/auth/types/querier.go @@ -7,6 +7,7 @@ import ( // query endpoints supported by the auth Querier const ( QueryAccount = "account" + QueryParams = "params" ) // QueryAccountParams defines the params for querying accounts. diff --git a/x/evidence/handler_test.go b/x/evidence/handler_test.go index 2d766e9d8fa8..60e883364ac3 100644 --- a/x/evidence/handler_test.go +++ b/x/evidence/handler_test.go @@ -5,6 +5,7 @@ import ( "testing" "time" + "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto/ed25519" @@ -24,6 +25,12 @@ type HandlerTestSuite struct { app *simapp.SimApp } +func testMsgSubmitEvidence(r *require.Assertions, e exported.Evidence, s sdk.AccAddress) simappcodec.MsgSubmitEvidence { + msg, err := simappcodec.NewMsgSubmitEvidence(e, s) + r.NoError(err) + return msg +} + func testEquivocationHandler(k interface{}) types.Handler { return func(ctx sdk.Context, e exported.Evidence) error { if err := e.ValidateBasic(); err != nil { @@ -70,7 +77,8 @@ func (suite *HandlerTestSuite) TestMsgSubmitEvidence() { expectErr bool }{ { - simappcodec.NewMsgSubmitEvidence( + testMsgSubmitEvidence( + suite.Require(), &types.Equivocation{ Height: 11, Time: time.Now().UTC(), @@ -82,7 +90,8 @@ func (suite *HandlerTestSuite) TestMsgSubmitEvidence() { false, }, { - simappcodec.NewMsgSubmitEvidence( + testMsgSubmitEvidence( + suite.Require(), &types.Equivocation{ Height: 10, Time: time.Now().UTC(), diff --git a/x/evidence/types/msgs_test.go b/x/evidence/types/msgs_test.go index 304f49efbfa2..127df25357fb 100644 --- a/x/evidence/types/msgs_test.go +++ b/x/evidence/types/msgs_test.go @@ -6,12 +6,19 @@ import ( simappcodec "github.com/cosmos/cosmos-sdk/simapp/codec" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/evidence/exported" "github.com/cosmos/cosmos-sdk/x/evidence/types" "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/crypto/ed25519" ) +func testMsgSubmitEvidence(t *testing.T, e exported.Evidence, s sdk.AccAddress) simappcodec.MsgSubmitEvidence { + msg, err := simappcodec.NewMsgSubmitEvidence(e, s) + require.NoError(t, err) + return msg +} + func TestMsgSubmitEvidence(t *testing.T) { pk := ed25519.GenPrivKey() submitter := sdk.AccAddress("test") @@ -27,7 +34,7 @@ func TestMsgSubmitEvidence(t *testing.T) { false, }, { - simappcodec.NewMsgSubmitEvidence(&types.Equivocation{ + testMsgSubmitEvidence(t, &types.Equivocation{ Height: 0, Power: 100, Time: time.Now().UTC(), @@ -37,7 +44,7 @@ func TestMsgSubmitEvidence(t *testing.T) { true, }, { - simappcodec.NewMsgSubmitEvidence(&types.Equivocation{ + testMsgSubmitEvidence(t, &types.Equivocation{ Height: 10, Power: 100, Time: time.Now().UTC(), From 4de26fd67a9855aa053a08410c4d56c9a502ff21 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Wed, 26 Feb 2020 16:35:04 +0100 Subject: [PATCH 246/529] fix lint errors 2 --- x/staking/keeper/querier_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/staking/keeper/querier_test.go b/x/staking/keeper/querier_test.go index be4eab297caf..e4b685836ea1 100644 --- a/x/staking/keeper/querier_test.go +++ b/x/staking/keeper/querier_test.go @@ -549,7 +549,7 @@ func TestQueryUnbondingDelegation(t *testing.T) { Path: "/custom/staking/unbondingDelegation", Data: bz, } - res, err = querier(ctx, []string{types.QueryUnbondingDelegation}, query) + _, err = querier(ctx, []string{types.QueryUnbondingDelegation}, query) require.Error(t, err) // From 56104c2961766b1d908e82ef7f42ebd041583a8c Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Wed, 26 Feb 2020 10:58:27 -0500 Subject: [PATCH 247/529] Merge PR #5703: Fix typo in distribution proto package name --- x/distribution/types/types.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/distribution/types/types.proto b/x/distribution/types/types.proto index a783be13f557..aade33d9dd0f 100644 --- a/x/distribution/types/types.proto +++ b/x/distribution/types/types.proto @@ -1,5 +1,5 @@ syntax = "proto3"; -package cosmos_sdk.x.ditribution.v1; +package cosmos_sdk.x.distribution.v1; option go_package = "types"; option (gogoproto.equal_all) = true; From e8155d67d0f8d1f2e6eb5b9e8fb95b8e58e6acd6 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Tue, 28 Jan 2020 16:30:28 -0500 Subject: [PATCH 248/529] Simple refactoring of gov to use protobuf for store encoding (for everything besides proposal) --- simapp/app.go | 3 +- x/gov/keeper/deposit.go | 2 +- x/gov/keeper/keeper.go | 5 +- x/gov/keeper/proposal.go | 15 +- x/gov/keeper/test_common.go | 2 +- x/gov/keeper/vote.go | 2 +- x/gov/types/codec.go | 25 + x/gov/types/codec.pb.go | 3412 +++++++++++++++++++++++++++++++++++ x/gov/types/codec.proto | 131 ++ x/gov/types/deposit.go | 7 - x/gov/types/msgs.go | 14 - x/gov/types/proposal.go | 19 - x/gov/types/tally.go | 8 - x/gov/types/vote.go | 19 - 14 files changed, 3587 insertions(+), 77 deletions(-) create mode 100644 x/gov/types/codec.pb.go create mode 100644 x/gov/types/codec.proto diff --git a/simapp/app.go b/simapp/app.go index e7253c9a7874..f8919cc99ae9 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -1,6 +1,7 @@ package simapp import ( + "github.com/cosmos/cosmos-sdk/x/gov/types" "io" "os" @@ -207,7 +208,7 @@ func NewSimApp( AddRoute(distr.RouterKey, distr.NewCommunityPoolSpendProposalHandler(app.DistrKeeper)). AddRoute(upgrade.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(app.UpgradeKeeper)) app.GovKeeper = gov.NewKeeper( - app.cdc, keys[gov.StoreKey], app.subspaces[gov.ModuleName], app.SupplyKeeper, + types.NewAminoGovCodec(app.cdc), keys[gov.StoreKey], app.subspaces[gov.ModuleName], app.SupplyKeeper, &stakingKeeper, govRouter, ) diff --git a/x/gov/keeper/deposit.go b/x/gov/keeper/deposit.go index 423679998b44..910ba4b8d896 100644 --- a/x/gov/keeper/deposit.go +++ b/x/gov/keeper/deposit.go @@ -23,7 +23,7 @@ func (keeper Keeper) GetDeposit(ctx sdk.Context, proposalID uint64, depositorAdd // SetDeposit sets a Deposit to the gov store func (keeper Keeper) SetDeposit(ctx sdk.Context, deposit types.Deposit) { store := ctx.KVStore(keeper.storeKey) - bz := keeper.cdc.MustMarshalBinaryLengthPrefixed(deposit) + bz := keeper.cdc.MustMarshalBinaryLengthPrefixed(&deposit) store.Set(types.DepositKey(deposit.ProposalID, deposit.Depositor), bz) } diff --git a/x/gov/keeper/keeper.go b/x/gov/keeper/keeper.go index 7a51e6e2bf29..0904a4ea2a89 100644 --- a/x/gov/keeper/keeper.go +++ b/x/gov/keeper/keeper.go @@ -4,7 +4,6 @@ import ( "fmt" "time" - "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/cosmos/cosmos-sdk/x/supply/exported" @@ -27,7 +26,7 @@ type Keeper struct { storeKey sdk.StoreKey // The codec codec for binary encoding/decoding. - cdc *codec.Codec + cdc types.GovCodec // Proposal router router types.Router @@ -41,7 +40,7 @@ type Keeper struct { // // CONTRACT: the parameter Subspace must have the param key table already initialized func NewKeeper( - cdc *codec.Codec, key sdk.StoreKey, paramSpace types.ParamSubspace, + cdc types.GovCodec, key sdk.StoreKey, paramSpace types.ParamSubspace, supplyKeeper types.SupplyKeeper, sk types.StakingKeeper, rtr types.Router, ) Keeper { diff --git a/x/gov/keeper/proposal.go b/x/gov/keeper/proposal.go index c5d569314fb2..5f795b62d2f8 100644 --- a/x/gov/keeper/proposal.go +++ b/x/gov/keeper/proposal.go @@ -55,14 +55,20 @@ func (keeper Keeper) GetProposal(ctx sdk.Context, proposalID uint64) (proposal t if bz == nil { return } - keeper.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &proposal) + err := keeper.cdc.UnmarshalProposal(bz, &proposal) + if err != nil { + panic(err) + } return proposal, true } // SetProposal set a proposal to store func (keeper Keeper) SetProposal(ctx sdk.Context, proposal types.Proposal) { store := ctx.KVStore(keeper.storeKey) - bz := keeper.cdc.MustMarshalBinaryLengthPrefixed(proposal) + bz, err := keeper.cdc.MarshalProposal(proposal) + if err != nil { + panic(err) + } store.Set(types.ProposalKey(proposal.ProposalID), bz) } @@ -86,7 +92,10 @@ func (keeper Keeper) IterateProposals(ctx sdk.Context, cb func(proposal types.Pr defer iterator.Close() for ; iterator.Valid(); iterator.Next() { var proposal types.Proposal - keeper.cdc.MustUnmarshalBinaryLengthPrefixed(iterator.Value(), &proposal) + err := keeper.cdc.UnmarshalProposal(iterator.Value(), &proposal) + if err != nil { + panic(err) + } if cb(proposal) { break diff --git a/x/gov/keeper/test_common.go b/x/gov/keeper/test_common.go index 84df63afb549..983df0579f48 100644 --- a/x/gov/keeper/test_common.go +++ b/x/gov/keeper/test_common.go @@ -161,7 +161,7 @@ func createTestInput( AddRoute(types.RouterKey, types.ProposalHandler) keeper := NewKeeper( - cdc, keyGov, pk.Subspace(types.DefaultParamspace).WithKeyTable(types.ParamKeyTable()), supplyKeeper, sk, rtr, + types.NewAminoGovCodec(cdc), keyGov, pk.Subspace(types.DefaultParamspace).WithKeyTable(types.ParamKeyTable()), supplyKeeper, sk, rtr, ) keeper.SetProposalID(ctx, types.DefaultStartingProposalID) diff --git a/x/gov/keeper/vote.go b/x/gov/keeper/vote.go index 309446714287..819130e6473b 100644 --- a/x/gov/keeper/vote.go +++ b/x/gov/keeper/vote.go @@ -69,7 +69,7 @@ func (keeper Keeper) GetVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.A // SetVote sets a Vote to the gov store func (keeper Keeper) SetVote(ctx sdk.Context, vote types.Vote) { store := ctx.KVStore(keeper.storeKey) - bz := keeper.cdc.MustMarshalBinaryLengthPrefixed(vote) + bz := keeper.cdc.MustMarshalBinaryLengthPrefixed(&vote) store.Set(types.VoteKey(vote.ProposalID, vote.Voter), bz) } diff --git a/x/gov/types/codec.go b/x/gov/types/codec.go index fc3de0e3f30c..ff7ad8a77c98 100644 --- a/x/gov/types/codec.go +++ b/x/gov/types/codec.go @@ -30,3 +30,28 @@ func RegisterProposalTypeCodec(o interface{}, name string) { func init() { RegisterCodec(ModuleCdc) } + +type GovCodec interface { + codec.Marshaler + MarshalProposal(p Proposal) ([]byte, error) + UnmarshalProposal(bz []byte, ptr *Proposal) error +} + +type AminoGovCodec struct { + codec.Marshaler + amino *codec.Codec +} + +func NewAminoGovCodec(amino *codec.Codec) AminoGovCodec { + return AminoGovCodec{Marshaler: codec.NewHybridCodec(amino), amino: amino} +} + +func (a AminoGovCodec) MarshalProposal(p Proposal) ([]byte, error) { + return a.amino.MarshalBinaryBare(p) +} + +func (a AminoGovCodec) UnmarshalProposal(bz []byte, ptr *Proposal) error { + return a.amino.UnmarshalBinaryBare(bz, ptr) +} + +var _ GovCodec = AminoGovCodec{} diff --git a/x/gov/types/codec.pb.go b/x/gov/types/codec.pb.go new file mode 100644 index 000000000000..be21d7f2c64e --- /dev/null +++ b/x/gov/types/codec.pb.go @@ -0,0 +1,3412 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: x/gov/types/codec.proto + +package types + +import ( + fmt "fmt" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/gogo/protobuf/gogoproto" + github_com_gogo_protobuf_proto "github.com/gogo/protobuf/proto" + proto "github.com/gogo/protobuf/proto" + github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" + _ "github.com/golang/protobuf/ptypes/timestamp" + _ "github.com/regen-network/cosmos-proto" + io "io" + math "math" + math_bits "math/bits" + reflect "reflect" + strings "strings" + time "time" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf +var _ = time.Kitchen + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// VoteOption defines a vote option +type VoteOption int32 + +const ( + OptionEmpty VoteOption = 0 + OptionYes VoteOption = 1 + OptionAbstain VoteOption = 2 + OptionNo VoteOption = 3 + OptionNoWithVeto VoteOption = 4 +) + +var VoteOption_name = map[int32]string{ + 0: "EMPTY", + 1: "YES", + 2: "ABSTAIN", + 3: "NO", + 4: "NO_WITH_VETO", +} + +var VoteOption_value = map[string]int32{ + "EMPTY": 0, + "YES": 1, + "ABSTAIN": 2, + "NO": 3, + "NO_WITH_VETO": 4, +} + +func (VoteOption) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_4ed4b2a5a30fa918, []int{0} +} + +// ProposalStatus is a type alias that represents a proposal status as a byte +type ProposalStatus int32 + +const ( + StatusNil ProposalStatus = 0 + StatusDepositPeriod ProposalStatus = 1 + StatusVotingPeriod ProposalStatus = 2 + StatusPassed ProposalStatus = 3 + StatusRejected ProposalStatus = 4 + StatusFailed ProposalStatus = 5 +) + +var ProposalStatus_name = map[int32]string{ + 0: "NIL", + 1: "DEPOSIT_PERIOD", + 2: "VOTING_PERIOD", + 3: "PASSED", + 4: "REJECTED", + 5: "FAILED", +} + +var ProposalStatus_value = map[string]int32{ + "NIL": 0, + "DEPOSIT_PERIOD": 1, + "VOTING_PERIOD": 2, + "PASSED": 3, + "REJECTED": 4, + "FAILED": 5, +} + +func (ProposalStatus) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_4ed4b2a5a30fa918, []int{1} +} + +type MsgCommon struct { + // Types that are valid to be assigned to Sum: + // *MsgCommon_GovDeposit + // *MsgCommon_GovVote + Sum isMsgCommon_Sum `protobuf_oneof:"sum"` +} + +func (m *MsgCommon) Reset() { *m = MsgCommon{} } +func (*MsgCommon) ProtoMessage() {} +func (*MsgCommon) Descriptor() ([]byte, []int) { + return fileDescriptor_4ed4b2a5a30fa918, []int{0} +} +func (m *MsgCommon) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgCommon) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgCommon.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 *MsgCommon) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgCommon.Merge(m, src) +} +func (m *MsgCommon) XXX_Size() int { + return m.Size() +} +func (m *MsgCommon) XXX_DiscardUnknown() { + xxx_messageInfo_MsgCommon.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgCommon proto.InternalMessageInfo + +type isMsgCommon_Sum interface { + isMsgCommon_Sum() + MarshalTo([]byte) (int, error) + Size() int +} + +type MsgCommon_GovDeposit struct { + GovDeposit *MsgDeposit `protobuf:"bytes,1,opt,name=gov_deposit,json=govDeposit,proto3,oneof" json:"gov_deposit,omitempty"` +} +type MsgCommon_GovVote struct { + GovVote *MsgVote `protobuf:"bytes,2,opt,name=gov_vote,json=govVote,proto3,oneof" json:"gov_vote,omitempty"` +} + +func (*MsgCommon_GovDeposit) isMsgCommon_Sum() {} +func (*MsgCommon_GovVote) isMsgCommon_Sum() {} + +func (m *MsgCommon) GetSum() isMsgCommon_Sum { + if m != nil { + return m.Sum + } + return nil +} + +func (m *MsgCommon) GetGovDeposit() *MsgDeposit { + if x, ok := m.GetSum().(*MsgCommon_GovDeposit); ok { + return x.GovDeposit + } + return nil +} + +func (m *MsgCommon) GetGovVote() *MsgVote { + if x, ok := m.GetSum().(*MsgCommon_GovVote); ok { + return x.GovVote + } + return nil +} + +// XXX_OneofWrappers is for the internal use of the proto package. +func (*MsgCommon) XXX_OneofWrappers() []interface{} { + return []interface{}{ + (*MsgCommon_GovDeposit)(nil), + (*MsgCommon_GovVote)(nil), + } +} + +type MsgSubmitProposalBase struct { + IntialDeposit github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,1,rep,name=intial_deposit,json=intialDeposit,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"intial_deposit" yaml:"initial_deposit"` + Proposer github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,2,opt,name=proposer,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"proposer,omitempty"` +} + +func (m *MsgSubmitProposalBase) Reset() { *m = MsgSubmitProposalBase{} } +func (*MsgSubmitProposalBase) ProtoMessage() {} +func (*MsgSubmitProposalBase) Descriptor() ([]byte, []int) { + return fileDescriptor_4ed4b2a5a30fa918, []int{1} +} +func (m *MsgSubmitProposalBase) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgSubmitProposalBase) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgSubmitProposalBase.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 *MsgSubmitProposalBase) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgSubmitProposalBase.Merge(m, src) +} +func (m *MsgSubmitProposalBase) XXX_Size() int { + return m.Size() +} +func (m *MsgSubmitProposalBase) XXX_DiscardUnknown() { + xxx_messageInfo_MsgSubmitProposalBase.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgSubmitProposalBase proto.InternalMessageInfo + +// MsgDeposit defines a message to submit a deposit to an existing proposal +type MsgDeposit struct { + ProposalID uint64 `protobuf:"varint,1,opt,name=proposal_id,json=proposalId,proto3" json:"proposal_id" yaml:"proposal_id"` + Depositor github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,2,opt,name=depositor,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"depositor,omitempty"` + Amount github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,3,rep,name=amount,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"amount"` +} + +func (m *MsgDeposit) Reset() { *m = MsgDeposit{} } +func (*MsgDeposit) ProtoMessage() {} +func (*MsgDeposit) Descriptor() ([]byte, []int) { + return fileDescriptor_4ed4b2a5a30fa918, []int{2} +} +func (m *MsgDeposit) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgDeposit) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgDeposit.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 *MsgDeposit) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgDeposit.Merge(m, src) +} +func (m *MsgDeposit) XXX_Size() int { + return m.Size() +} +func (m *MsgDeposit) XXX_DiscardUnknown() { + xxx_messageInfo_MsgDeposit.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgDeposit proto.InternalMessageInfo + +// MsgVote defines a message to cast a vote +type MsgVote struct { + ProposalID uint64 `protobuf:"varint,1,opt,name=proposal_id,json=proposalId,proto3" json:"proposal_id" yaml:"proposal_id"` + Voter github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,2,opt,name=voter,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"voter,omitempty"` + Option VoteOption `protobuf:"varint,3,opt,name=option,proto3,enum=cosmos_sdk.x.gov.v1.VoteOption" json:"option,omitempty"` +} + +func (m *MsgVote) Reset() { *m = MsgVote{} } +func (*MsgVote) ProtoMessage() {} +func (*MsgVote) Descriptor() ([]byte, []int) { + return fileDescriptor_4ed4b2a5a30fa918, []int{3} +} +func (m *MsgVote) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgVote) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgVote.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 *MsgVote) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgVote.Merge(m, src) +} +func (m *MsgVote) XXX_Size() int { + return m.Size() +} +func (m *MsgVote) XXX_DiscardUnknown() { + xxx_messageInfo_MsgVote.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgVote proto.InternalMessageInfo + +// TextProposal defines a standard text proposal whose changes need to be +// manually updated in case of approval +type TextProposal struct { + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` +} + +func (m *TextProposal) Reset() { *m = TextProposal{} } +func (*TextProposal) ProtoMessage() {} +func (*TextProposal) Descriptor() ([]byte, []int) { + return fileDescriptor_4ed4b2a5a30fa918, []int{4} +} +func (m *TextProposal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TextProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TextProposal.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 *TextProposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_TextProposal.Merge(m, src) +} +func (m *TextProposal) XXX_Size() int { + return m.Size() +} +func (m *TextProposal) XXX_DiscardUnknown() { + xxx_messageInfo_TextProposal.DiscardUnknown(m) +} + +var xxx_messageInfo_TextProposal proto.InternalMessageInfo + +// Deposit defines an amount deposited by an account address to an active proposal +type Deposit struct { + ProposalID uint64 `protobuf:"varint,1,opt,name=proposal_id,json=proposalId,proto3" json:"proposal_id,omitempty" yaml:"proposal_id"` + Depositor github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,2,opt,name=depositor,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"depositor,omitempty"` + Amount github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,3,rep,name=amount,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"amount"` +} + +func (m *Deposit) Reset() { *m = Deposit{} } +func (*Deposit) ProtoMessage() {} +func (*Deposit) Descriptor() ([]byte, []int) { + return fileDescriptor_4ed4b2a5a30fa918, []int{5} +} +func (m *Deposit) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Deposit) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Deposit.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 *Deposit) XXX_Merge(src proto.Message) { + xxx_messageInfo_Deposit.Merge(m, src) +} +func (m *Deposit) XXX_Size() int { + return m.Size() +} +func (m *Deposit) XXX_DiscardUnknown() { + xxx_messageInfo_Deposit.DiscardUnknown(m) +} + +var xxx_messageInfo_Deposit proto.InternalMessageInfo + +type ProposalBase struct { + ProposalID uint64 `protobuf:"varint,1,opt,name=proposal_id,json=proposalId,proto3" json:"proposal_id,omitempty" yaml:"proposal_id"` + Status ProposalStatus `protobuf:"varint,2,opt,name=status,proto3,enum=cosmos_sdk.x.gov.v1.ProposalStatus" json:"status,omitempty"` + FinalTallyResult TallyResult `protobuf:"bytes,3,opt,name=final_tally_result,json=finalTallyResult,proto3" json:"final_tally_result"` + SubmitTime time.Time `protobuf:"bytes,4,opt,name=submit_time,json=submitTime,proto3,stdtime" json:"submit_time"` + DepositEndTime time.Time `protobuf:"bytes,5,opt,name=deposit_end_time,json=depositEndTime,proto3,stdtime" json:"deposit_end_time"` + TotalDeposit github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,6,rep,name=total_deposit,json=totalDeposit,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"total_deposit"` + VotingStartTime time.Time `protobuf:"bytes,7,opt,name=voting_start_time,json=votingStartTime,proto3,stdtime" json:"voting_start_time"` + VotingEndTime time.Time `protobuf:"bytes,8,opt,name=voting_end_time,json=votingEndTime,proto3,stdtime" json:"voting_end_time"` +} + +func (m *ProposalBase) Reset() { *m = ProposalBase{} } +func (m *ProposalBase) String() string { return proto.CompactTextString(m) } +func (*ProposalBase) ProtoMessage() {} +func (*ProposalBase) Descriptor() ([]byte, []int) { + return fileDescriptor_4ed4b2a5a30fa918, []int{6} +} +func (m *ProposalBase) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ProposalBase) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ProposalBase.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 *ProposalBase) XXX_Merge(src proto.Message) { + xxx_messageInfo_ProposalBase.Merge(m, src) +} +func (m *ProposalBase) XXX_Size() int { + return m.Size() +} +func (m *ProposalBase) XXX_DiscardUnknown() { + xxx_messageInfo_ProposalBase.DiscardUnknown(m) +} + +var xxx_messageInfo_ProposalBase proto.InternalMessageInfo + +// TallyResult defines a standard tally for a proposal +type TallyResult struct { + Yes github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,1,opt,name=yes,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"yes"` + Abstain github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,2,opt,name=abstain,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"abstain"` + No github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,3,opt,name=no,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"no"` + NoWithVeto github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,4,opt,name=no_with_veto,json=noWithVeto,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"no_with_veto" yaml:"no_with_veto"` +} + +func (m *TallyResult) Reset() { *m = TallyResult{} } +func (*TallyResult) ProtoMessage() {} +func (*TallyResult) Descriptor() ([]byte, []int) { + return fileDescriptor_4ed4b2a5a30fa918, []int{7} +} +func (m *TallyResult) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TallyResult) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TallyResult.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 *TallyResult) XXX_Merge(src proto.Message) { + xxx_messageInfo_TallyResult.Merge(m, src) +} +func (m *TallyResult) XXX_Size() int { + return m.Size() +} +func (m *TallyResult) XXX_DiscardUnknown() { + xxx_messageInfo_TallyResult.DiscardUnknown(m) +} + +var xxx_messageInfo_TallyResult proto.InternalMessageInfo + +type Vote struct { + ProposalID uint64 `protobuf:"varint,1,opt,name=proposal_id,json=proposalId,proto3" json:"proposal_id,omitempty" yaml:"proposal_id"` + Voter github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,2,opt,name=voter,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"voter,omitempty"` + Option VoteOption `protobuf:"varint,3,opt,name=option,proto3,enum=cosmos_sdk.x.gov.v1.VoteOption" json:"option,omitempty"` +} + +func (m *Vote) Reset() { *m = Vote{} } +func (*Vote) ProtoMessage() {} +func (*Vote) Descriptor() ([]byte, []int) { + return fileDescriptor_4ed4b2a5a30fa918, []int{8} +} +func (m *Vote) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Vote) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Vote.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 *Vote) XXX_Merge(src proto.Message) { + xxx_messageInfo_Vote.Merge(m, src) +} +func (m *Vote) XXX_Size() int { + return m.Size() +} +func (m *Vote) XXX_DiscardUnknown() { + xxx_messageInfo_Vote.DiscardUnknown(m) +} + +var xxx_messageInfo_Vote proto.InternalMessageInfo + +type BasicProposal struct { + *ProposalBase `protobuf:"bytes,1,opt,name=base,proto3,embedded=base" json:"base,omitempty"` + Content *BasicContent `protobuf:"bytes,2,opt,name=content,proto3" json:"content,omitempty"` +} + +func (m *BasicProposal) Reset() { *m = BasicProposal{} } +func (*BasicProposal) ProtoMessage() {} +func (*BasicProposal) Descriptor() ([]byte, []int) { + return fileDescriptor_4ed4b2a5a30fa918, []int{9} +} +func (m *BasicProposal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *BasicProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_BasicProposal.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 *BasicProposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_BasicProposal.Merge(m, src) +} +func (m *BasicProposal) XXX_Size() int { + return m.Size() +} +func (m *BasicProposal) XXX_DiscardUnknown() { + xxx_messageInfo_BasicProposal.DiscardUnknown(m) +} + +var xxx_messageInfo_BasicProposal proto.InternalMessageInfo + +type BasicContent struct { + // Types that are valid to be assigned to Sum: + // *BasicContent_Text + Sum isBasicContent_Sum `protobuf_oneof:"sum"` +} + +func (m *BasicContent) Reset() { *m = BasicContent{} } +func (*BasicContent) ProtoMessage() {} +func (*BasicContent) Descriptor() ([]byte, []int) { + return fileDescriptor_4ed4b2a5a30fa918, []int{10} +} +func (m *BasicContent) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *BasicContent) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_BasicContent.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 *BasicContent) XXX_Merge(src proto.Message) { + xxx_messageInfo_BasicContent.Merge(m, src) +} +func (m *BasicContent) XXX_Size() int { + return m.Size() +} +func (m *BasicContent) XXX_DiscardUnknown() { + xxx_messageInfo_BasicContent.DiscardUnknown(m) +} + +var xxx_messageInfo_BasicContent proto.InternalMessageInfo + +type isBasicContent_Sum interface { + isBasicContent_Sum() + MarshalTo([]byte) (int, error) + Size() int +} + +type BasicContent_Text struct { + Text *TextProposal `protobuf:"bytes,1,opt,name=text,proto3,oneof" json:"text,omitempty"` +} + +func (*BasicContent_Text) isBasicContent_Sum() {} + +func (m *BasicContent) GetSum() isBasicContent_Sum { + if m != nil { + return m.Sum + } + return nil +} + +func (m *BasicContent) GetText() *TextProposal { + if x, ok := m.GetSum().(*BasicContent_Text); ok { + return x.Text + } + return nil +} + +// XXX_OneofWrappers is for the internal use of the proto package. +func (*BasicContent) XXX_OneofWrappers() []interface{} { + return []interface{}{ + (*BasicContent_Text)(nil), + } +} + +func init() { + proto.RegisterEnum("cosmos_sdk.x.gov.v1.VoteOption", VoteOption_name, VoteOption_value) + proto.RegisterEnum("cosmos_sdk.x.gov.v1.ProposalStatus", ProposalStatus_name, ProposalStatus_value) + proto.RegisterType((*MsgCommon)(nil), "cosmos_sdk.x.gov.v1.MsgCommon") + proto.RegisterType((*MsgSubmitProposalBase)(nil), "cosmos_sdk.x.gov.v1.MsgSubmitProposalBase") + proto.RegisterType((*MsgDeposit)(nil), "cosmos_sdk.x.gov.v1.MsgDeposit") + proto.RegisterType((*MsgVote)(nil), "cosmos_sdk.x.gov.v1.MsgVote") + proto.RegisterType((*TextProposal)(nil), "cosmos_sdk.x.gov.v1.TextProposal") + proto.RegisterType((*Deposit)(nil), "cosmos_sdk.x.gov.v1.Deposit") + proto.RegisterType((*ProposalBase)(nil), "cosmos_sdk.x.gov.v1.ProposalBase") + proto.RegisterType((*TallyResult)(nil), "cosmos_sdk.x.gov.v1.TallyResult") + proto.RegisterType((*Vote)(nil), "cosmos_sdk.x.gov.v1.Vote") + proto.RegisterType((*BasicProposal)(nil), "cosmos_sdk.x.gov.v1.BasicProposal") + proto.RegisterType((*BasicContent)(nil), "cosmos_sdk.x.gov.v1.BasicContent") +} + +func init() { proto.RegisterFile("x/gov/types/codec.proto", fileDescriptor_4ed4b2a5a30fa918) } + +var fileDescriptor_4ed4b2a5a30fa918 = []byte{ + // 1279 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x57, 0xcf, 0x6b, 0x1b, 0xc7, + 0x17, 0xdf, 0x95, 0x64, 0xcb, 0x7e, 0xfa, 0x91, 0xcd, 0x38, 0xdf, 0xc4, 0x2c, 0x41, 0xbb, 0x5f, + 0xb5, 0x04, 0x37, 0x21, 0x72, 0xe3, 0x1c, 0x42, 0x1d, 0x28, 0xd5, 0x5a, 0x9b, 0x58, 0x21, 0x96, + 0xc4, 0x4a, 0x38, 0xa4, 0x50, 0x96, 0xb5, 0x76, 0xb3, 0xde, 0x44, 0xda, 0x11, 0x9a, 0x91, 0x6a, + 0xdf, 0x72, 0x2a, 0xad, 0x4e, 0xa1, 0x50, 0xe8, 0x45, 0x10, 0x68, 0x0e, 0xa1, 0xf4, 0xd0, 0x43, + 0xff, 0x81, 0xf6, 0x14, 0x7a, 0x69, 0x8e, 0xa1, 0x14, 0xa5, 0x71, 0x6e, 0xa5, 0xa7, 0x40, 0x2f, + 0x3d, 0x95, 0x9d, 0xd9, 0x8d, 0xd7, 0xd4, 0x09, 0x11, 0x49, 0x29, 0xf4, 0x62, 0x34, 0x33, 0x9f, + 0xcf, 0x67, 0xdf, 0xfb, 0xcc, 0xdb, 0xf7, 0xd6, 0x70, 0x62, 0x67, 0xd9, 0xc5, 0xc3, 0x65, 0xba, + 0xdb, 0x73, 0xc8, 0x72, 0x1b, 0xdb, 0x4e, 0xbb, 0xd4, 0xeb, 0x63, 0x8a, 0xd1, 0x42, 0x1b, 0x93, + 0x2e, 0x26, 0x26, 0xb1, 0x6f, 0x95, 0x76, 0x4a, 0x2e, 0x1e, 0x96, 0x86, 0xe7, 0xe4, 0xa3, 0x1c, + 0xc7, 0xfe, 0x72, 0x9c, 0x7c, 0x8a, 0x6e, 0x7b, 0x7d, 0xdb, 0xec, 0x59, 0x7d, 0xba, 0xbb, 0xcc, + 0xb6, 0x96, 0x5d, 0xec, 0xe2, 0xfd, 0x5f, 0x21, 0xee, 0xcc, 0xdf, 0x71, 0xfc, 0x09, 0x67, 0xe3, + 0x8b, 0x10, 0xac, 0xb8, 0x18, 0xbb, 0x1d, 0x87, 0xe3, 0xb6, 0x06, 0x37, 0x96, 0xa9, 0xd7, 0x75, + 0x08, 0xb5, 0xba, 0x3d, 0x0e, 0x28, 0x7e, 0x2f, 0xc2, 0xfc, 0x06, 0x71, 0xd7, 0x70, 0xb7, 0x8b, + 0x7d, 0xa4, 0x41, 0xc6, 0xc5, 0x43, 0xd3, 0x76, 0x7a, 0x98, 0x78, 0x74, 0x51, 0x54, 0xc5, 0xa5, + 0xcc, 0x8a, 0x52, 0x3a, 0x24, 0x83, 0xd2, 0x06, 0x71, 0x2b, 0x1c, 0xb6, 0x2e, 0x18, 0xe0, 0xe2, + 0x61, 0xb8, 0x42, 0xef, 0xc1, 0x5c, 0xa0, 0x31, 0xc4, 0xd4, 0x59, 0x4c, 0x30, 0x81, 0x93, 0x2f, + 0x12, 0xd8, 0xc4, 0xd4, 0x59, 0x17, 0x8c, 0xb4, 0x8b, 0x87, 0xc1, 0xcf, 0xd5, 0xd2, 0xed, 0x5f, + 0x54, 0xf1, 0xc7, 0xef, 0xce, 0x9e, 0x72, 0x3d, 0xba, 0x3d, 0xd8, 0x2a, 0xb5, 0x71, 0x37, 0x4c, + 0x27, 0x4a, 0x91, 0xd8, 0xb7, 0x42, 0xd3, 0x36, 0x88, 0xab, 0xcd, 0x40, 0x92, 0x0c, 0xba, 0xc5, + 0x3f, 0x44, 0xf8, 0xdf, 0x06, 0x71, 0x9b, 0x83, 0xad, 0xae, 0x47, 0x1b, 0x7d, 0xdc, 0xc3, 0xc4, + 0xea, 0x68, 0x16, 0x71, 0xd0, 0x27, 0x22, 0xe4, 0x3d, 0x9f, 0x7a, 0x56, 0x27, 0x96, 0x53, 0x72, + 0x29, 0xb3, 0xb2, 0x10, 0x0f, 0x69, 0x78, 0xae, 0xb4, 0x86, 0x3d, 0x5f, 0xbb, 0xf2, 0x60, 0xa2, + 0x08, 0xcf, 0x26, 0xca, 0xf1, 0x5d, 0xab, 0xdb, 0x59, 0x2d, 0x7a, 0xbe, 0x17, 0x67, 0x16, 0xbf, + 0x7e, 0xac, 0x2c, 0xbd, 0x42, 0x60, 0x81, 0x14, 0x31, 0x72, 0xfc, 0xb1, 0x91, 0x29, 0x1b, 0x30, + 0xd7, 0x63, 0x81, 0x39, 0x7d, 0x66, 0x4a, 0x56, 0x3b, 0xf7, 0xe7, 0x44, 0x39, 0xfb, 0x0a, 0x72, + 0xe5, 0x76, 0xbb, 0x6c, 0xdb, 0x7d, 0x87, 0x10, 0xe3, 0xb9, 0xc4, 0x6a, 0x2a, 0x30, 0xaa, 0xf8, + 0x79, 0x02, 0x60, 0xff, 0x1a, 0x50, 0x0b, 0x32, 0xbd, 0x30, 0x79, 0xd3, 0xb3, 0xd9, 0xe5, 0xa5, + 0xb4, 0xf3, 0x7b, 0x13, 0x05, 0x22, 0x4f, 0xaa, 0x95, 0xdf, 0x26, 0x4a, 0x1c, 0xf4, 0x6c, 0xa2, + 0x20, 0x9e, 0x6c, 0x6c, 0xb3, 0x68, 0x40, 0xb4, 0xaa, 0xda, 0xa8, 0x0e, 0xf3, 0xa1, 0x01, 0xf8, + 0x35, 0x42, 0xdf, 0xd7, 0x40, 0x1f, 0xc1, 0xac, 0xd5, 0xc5, 0x03, 0x9f, 0x2e, 0x26, 0x5f, 0x7c, + 0x15, 0xef, 0x06, 0x57, 0x31, 0x95, 0xe1, 0xa1, 0x68, 0xf1, 0x89, 0x08, 0xe9, 0xb0, 0xb4, 0xfe, + 0x21, 0x47, 0x2e, 0xc3, 0x4c, 0x50, 0xdc, 0xaf, 0xe1, 0x06, 0xe7, 0xa3, 0x0b, 0x30, 0x8b, 0x7b, + 0xd4, 0xc3, 0xfe, 0x62, 0x52, 0x15, 0x97, 0xf2, 0x2f, 0x78, 0xd1, 0x82, 0x4c, 0xea, 0x0c, 0x66, + 0x84, 0xf0, 0xe2, 0x25, 0xc8, 0xb6, 0x9c, 0x9d, 0xe7, 0xa5, 0x8e, 0x8e, 0xc1, 0x0c, 0xf5, 0x68, + 0xc7, 0x61, 0x19, 0xce, 0x1b, 0x7c, 0x81, 0x54, 0xc8, 0xd8, 0x0e, 0x69, 0xf7, 0x3d, 0xfe, 0x8c, + 0x04, 0x3b, 0x8b, 0x6f, 0x15, 0x6f, 0x27, 0x20, 0x1d, 0x55, 0x8f, 0x7e, 0x98, 0x57, 0x6f, 0x1f, + 0xf4, 0xea, 0x3f, 0x58, 0x2e, 0x5f, 0xcc, 0x40, 0xf6, 0x40, 0xcb, 0x78, 0x43, 0x3e, 0x5c, 0x84, + 0x59, 0x42, 0x2d, 0x3a, 0x20, 0xcc, 0x84, 0xfc, 0xca, 0x5b, 0x87, 0xde, 0x6d, 0x24, 0xd9, 0x64, + 0x50, 0x23, 0xa4, 0xa0, 0x16, 0xa0, 0x1b, 0x9e, 0x6f, 0x75, 0x4c, 0x6a, 0x75, 0x3a, 0xbb, 0x66, + 0xdf, 0x21, 0x83, 0x0e, 0x65, 0x45, 0x92, 0x59, 0x51, 0x0f, 0x15, 0x6a, 0x05, 0x40, 0x83, 0xe1, + 0xb4, 0x54, 0x60, 0x86, 0x21, 0x31, 0x85, 0xd8, 0x7e, 0x90, 0x19, 0x61, 0x2d, 0xd2, 0x0c, 0x86, + 0xc0, 0x62, 0x8a, 0xc9, 0xc9, 0x25, 0x3e, 0x21, 0x4a, 0xd1, 0x84, 0x28, 0xb5, 0xa2, 0x09, 0xa1, + 0xcd, 0x05, 0x42, 0x77, 0x1e, 0x2b, 0xa2, 0x01, 0x9c, 0x18, 0x1c, 0xa1, 0x1a, 0x48, 0xe1, 0xed, + 0x98, 0x8e, 0x6f, 0x73, 0xad, 0x99, 0x29, 0xb4, 0xf2, 0x21, 0x5b, 0xf7, 0x6d, 0xa6, 0x77, 0x13, + 0x72, 0x14, 0xd3, 0x58, 0x87, 0x9e, 0x7d, 0x93, 0xf7, 0x9c, 0x65, 0xda, 0x51, 0x91, 0x37, 0xe0, + 0xe8, 0x10, 0x53, 0xcf, 0x77, 0x4d, 0x42, 0xad, 0x7e, 0x68, 0x44, 0x7a, 0x8a, 0xe0, 0x8f, 0x70, + 0x7a, 0x33, 0x60, 0xb3, 0xe8, 0xaf, 0x42, 0xb8, 0xb5, 0x6f, 0xc6, 0xdc, 0x14, 0x7a, 0x39, 0x4e, + 0x0e, 0xbd, 0x58, 0x9d, 0xfb, 0xf2, 0xae, 0x22, 0xde, 0xbf, 0xab, 0x88, 0xc5, 0x1f, 0x12, 0x90, + 0x89, 0x5f, 0xde, 0x07, 0x90, 0xdc, 0x75, 0x08, 0x2b, 0xc7, 0xac, 0x56, 0x0a, 0xf8, 0x3f, 0x4f, + 0x94, 0x57, 0x99, 0x93, 0x55, 0x9f, 0x1a, 0x01, 0x15, 0xad, 0x43, 0xda, 0xda, 0x22, 0xd4, 0xf2, + 0xfc, 0xf0, 0xbd, 0x9c, 0x56, 0x25, 0xa2, 0xa3, 0xf7, 0x21, 0xe1, 0x63, 0x56, 0x8e, 0xd3, 0x8b, + 0x24, 0x7c, 0x8c, 0x5c, 0xc8, 0xfa, 0xd8, 0xfc, 0xd8, 0xa3, 0xdb, 0xe6, 0xd0, 0xa1, 0x98, 0x55, + 0x62, 0x56, 0xd3, 0xa7, 0x53, 0x7a, 0x36, 0x51, 0x16, 0xf8, 0x3b, 0x18, 0xd7, 0x2a, 0x1a, 0xe0, + 0xe3, 0x6b, 0x1e, 0xdd, 0xde, 0x0c, 0x16, 0x3f, 0x89, 0x90, 0x62, 0x83, 0xe0, 0x0d, 0xbd, 0xd4, + 0xff, 0x7e, 0xe7, 0xff, 0x4c, 0x84, 0x9c, 0x66, 0x11, 0xaf, 0xfd, 0xbc, 0xf7, 0x5f, 0x84, 0xd4, + 0x96, 0x45, 0x9c, 0xf0, 0x5b, 0xed, 0xff, 0x2f, 0x6d, 0x33, 0x41, 0x83, 0xd3, 0x52, 0x0f, 0x27, + 0x8a, 0x68, 0x30, 0x12, 0xba, 0x08, 0xe9, 0x36, 0xf6, 0xa9, 0xe3, 0xd3, 0xf0, 0x53, 0xed, 0x70, + 0x3e, 0x7b, 0xe2, 0x1a, 0x07, 0x1a, 0x11, 0xa3, 0x68, 0x42, 0x36, 0x7e, 0x80, 0x2e, 0x40, 0x8a, + 0x3a, 0x3b, 0xf4, 0xa5, 0x91, 0xc4, 0xc7, 0xd6, 0xba, 0x60, 0x30, 0xc2, 0xea, 0x91, 0xf0, 0xb3, + 0x2f, 0x1d, 0x2a, 0x85, 0xdf, 0x75, 0xa7, 0xbf, 0x11, 0x01, 0xf6, 0x3d, 0x40, 0x32, 0xcc, 0xe8, + 0x1b, 0x8d, 0xd6, 0x75, 0x49, 0x90, 0x8f, 0x8c, 0xc6, 0x6a, 0x86, 0x6f, 0xeb, 0xdd, 0x1e, 0xdd, + 0x45, 0xc7, 0x21, 0x79, 0x5d, 0x6f, 0x4a, 0xa2, 0x9c, 0x1b, 0x8d, 0xd5, 0x79, 0x7e, 0x72, 0xdd, + 0x21, 0xa8, 0x00, 0xe9, 0xb2, 0xd6, 0x6c, 0x95, 0xab, 0x35, 0x29, 0x21, 0x1f, 0x1d, 0x8d, 0xd5, + 0x1c, 0x3f, 0x2b, 0x87, 0xa5, 0x7c, 0x0c, 0x12, 0xb5, 0xba, 0x94, 0x94, 0xb3, 0xa3, 0xb1, 0x3a, + 0xc7, 0x8f, 0x6a, 0x18, 0x9d, 0x82, 0x6c, 0xad, 0x6e, 0x5e, 0xab, 0xb6, 0xd6, 0xcd, 0x4d, 0xbd, + 0x55, 0x97, 0x52, 0xf2, 0xb1, 0xd1, 0x58, 0x95, 0xa2, 0xf3, 0xa8, 0xbe, 0xe4, 0xec, 0xa7, 0x5f, + 0x15, 0x84, 0xfb, 0xf7, 0x0a, 0xc2, 0xb7, 0xf7, 0x0a, 0xc2, 0xe9, 0xdf, 0x45, 0xc8, 0x1f, 0x6c, + 0xe8, 0x41, 0x58, 0xb5, 0xea, 0x55, 0x49, 0xe0, 0x61, 0xf1, 0xcd, 0x9a, 0xd7, 0x41, 0x67, 0x20, + 0x5f, 0xd1, 0x1b, 0xf5, 0x66, 0xb5, 0x65, 0x36, 0x74, 0xa3, 0x5a, 0xaf, 0x48, 0xa2, 0x7c, 0x62, + 0x34, 0x56, 0x17, 0x38, 0x24, 0x6c, 0x57, 0x0d, 0xa7, 0xef, 0x61, 0x1b, 0xbd, 0x03, 0xb9, 0xcd, + 0x7a, 0xab, 0x5a, 0xbb, 0x1c, 0x61, 0x13, 0xf2, 0xf1, 0xd1, 0x58, 0x45, 0x1c, 0xbb, 0xc9, 0x1a, + 0x48, 0x08, 0x3d, 0x09, 0xb3, 0x8d, 0x72, 0xb3, 0xa9, 0x57, 0xa4, 0xa4, 0x2c, 0x8d, 0xc6, 0x6a, + 0x96, 0x63, 0x1a, 0x16, 0x21, 0x8e, 0x8d, 0x54, 0x98, 0x33, 0xf4, 0x2b, 0xfa, 0x5a, 0x4b, 0xaf, + 0x48, 0x29, 0x19, 0x8d, 0xc6, 0x6a, 0x3e, 0x1c, 0x3c, 0xce, 0x4d, 0xa7, 0x4d, 0x1d, 0xc6, 0xbf, + 0x54, 0xae, 0x5e, 0xd5, 0x2b, 0xd2, 0x4c, 0x9c, 0x7f, 0xc9, 0xf2, 0x3a, 0x8e, 0x7d, 0x30, 0x5d, + 0xad, 0xf6, 0xe0, 0x49, 0x41, 0x78, 0xf4, 0xa4, 0x20, 0xdc, 0xde, 0x2b, 0x08, 0x0f, 0xf6, 0x0a, + 0xe2, 0xc3, 0xbd, 0x82, 0xf8, 0xeb, 0x5e, 0x41, 0xbc, 0xf3, 0xb4, 0x20, 0x3c, 0x7c, 0x5a, 0x10, + 0x1e, 0x3d, 0x2d, 0x08, 0x1f, 0xbe, 0xbc, 0x53, 0xc7, 0xfe, 0x67, 0xda, 0x9a, 0x65, 0x8d, 0xf2, + 0xfc, 0x5f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xb4, 0xd5, 0x14, 0x59, 0x49, 0x0d, 0x00, 0x00, +} + +type ProposalBaseFace interface { + Proto() github_com_gogo_protobuf_proto.Message + GetProposalID() uint64 + GetStatus() ProposalStatus + GetFinalTallyResult() TallyResult + GetSubmitTime() time.Time + GetDepositEndTime() time.Time + GetTotalDeposit() github_com_cosmos_cosmos_sdk_types.Coins + GetVotingStartTime() time.Time + GetVotingEndTime() time.Time +} + +func (this *ProposalBase) Proto() github_com_gogo_protobuf_proto.Message { + return this +} + +func (this *ProposalBase) TestProto() github_com_gogo_protobuf_proto.Message { + return NewProposalBaseFromFace(this) +} + +func (this *ProposalBase) GetProposalID() uint64 { + return this.ProposalID +} + +func (this *ProposalBase) GetStatus() ProposalStatus { + return this.Status +} + +func (this *ProposalBase) GetFinalTallyResult() TallyResult { + return this.FinalTallyResult +} + +func (this *ProposalBase) GetSubmitTime() time.Time { + return this.SubmitTime +} + +func (this *ProposalBase) GetDepositEndTime() time.Time { + return this.DepositEndTime +} + +func (this *ProposalBase) GetTotalDeposit() github_com_cosmos_cosmos_sdk_types.Coins { + return this.TotalDeposit +} + +func (this *ProposalBase) GetVotingStartTime() time.Time { + return this.VotingStartTime +} + +func (this *ProposalBase) GetVotingEndTime() time.Time { + return this.VotingEndTime +} + +func NewProposalBaseFromFace(that ProposalBaseFace) *ProposalBase { + this := &ProposalBase{} + this.ProposalID = that.GetProposalID() + this.Status = that.GetStatus() + this.FinalTallyResult = that.GetFinalTallyResult() + this.SubmitTime = that.GetSubmitTime() + this.DepositEndTime = that.GetDepositEndTime() + this.TotalDeposit = that.GetTotalDeposit() + this.VotingStartTime = that.GetVotingStartTime() + this.VotingEndTime = that.GetVotingEndTime() + return this +} + +func (this *MsgCommon) GetMsg() github_com_cosmos_cosmos_sdk_types.Msg { + if x := this.GetGovDeposit(); x != nil { + return x + } + if x := this.GetGovVote(); x != nil { + return x + } + return nil +} + +func (this *MsgCommon) SetMsg(value github_com_cosmos_cosmos_sdk_types.Msg) error { + if value == nil { + this.Sum = nil + return nil + } + switch vt := value.(type) { + case *MsgDeposit: + this.Sum = &MsgCommon_GovDeposit{vt} + return nil + case MsgDeposit: + this.Sum = &MsgCommon_GovDeposit{&vt} + return nil + case *MsgVote: + this.Sum = &MsgCommon_GovVote{vt} + return nil + case MsgVote: + this.Sum = &MsgCommon_GovVote{&vt} + return nil + } + return fmt.Errorf("can't encode value of type %T as message MsgCommon", value) +} + +func (this *BasicContent) GetContent() Content { + if x := this.GetText(); x != nil { + return x + } + return nil +} + +func (this *BasicContent) SetContent(value Content) error { + if value == nil { + this.Sum = nil + return nil + } + switch vt := value.(type) { + case *TextProposal: + this.Sum = &BasicContent_Text{vt} + return nil + case TextProposal: + this.Sum = &BasicContent_Text{&vt} + return nil + } + return fmt.Errorf("can't encode value of type %T as message BasicContent", value) +} + +func (m *MsgCommon) 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 *MsgCommon) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgCommon) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Sum != nil { + { + size := m.Sum.Size() + i -= size + if _, err := m.Sum.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + } + } + return len(dAtA) - i, nil +} + +func (m *MsgCommon_GovDeposit) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgCommon_GovDeposit) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.GovDeposit != nil { + { + size, err := m.GovDeposit.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} +func (m *MsgCommon_GovVote) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgCommon_GovVote) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.GovVote != nil { + { + size, err := m.GovVote.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + return len(dAtA) - i, nil +} +func (m *MsgSubmitProposalBase) 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 *MsgSubmitProposalBase) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgSubmitProposalBase) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Proposer) > 0 { + i -= len(m.Proposer) + copy(dAtA[i:], m.Proposer) + i = encodeVarintCodec(dAtA, i, uint64(len(m.Proposer))) + i-- + dAtA[i] = 0x12 + } + if len(m.IntialDeposit) > 0 { + for iNdEx := len(m.IntialDeposit) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.IntialDeposit[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *MsgDeposit) 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 *MsgDeposit) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgDeposit) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Amount) > 0 { + for iNdEx := len(m.Amount) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Amount[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.Depositor) > 0 { + i -= len(m.Depositor) + copy(dAtA[i:], m.Depositor) + i = encodeVarintCodec(dAtA, i, uint64(len(m.Depositor))) + i-- + dAtA[i] = 0x12 + } + if m.ProposalID != 0 { + i = encodeVarintCodec(dAtA, i, uint64(m.ProposalID)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *MsgVote) 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 *MsgVote) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgVote) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Option != 0 { + i = encodeVarintCodec(dAtA, i, uint64(m.Option)) + i-- + dAtA[i] = 0x18 + } + if len(m.Voter) > 0 { + i -= len(m.Voter) + copy(dAtA[i:], m.Voter) + i = encodeVarintCodec(dAtA, i, uint64(len(m.Voter))) + i-- + dAtA[i] = 0x12 + } + if m.ProposalID != 0 { + i = encodeVarintCodec(dAtA, i, uint64(m.ProposalID)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *TextProposal) 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 *TextProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TextProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Description) > 0 { + i -= len(m.Description) + copy(dAtA[i:], m.Description) + i = encodeVarintCodec(dAtA, i, uint64(len(m.Description))) + i-- + dAtA[i] = 0x12 + } + if len(m.Title) > 0 { + i -= len(m.Title) + copy(dAtA[i:], m.Title) + i = encodeVarintCodec(dAtA, i, uint64(len(m.Title))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *Deposit) 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 *Deposit) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Deposit) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Amount) > 0 { + for iNdEx := len(m.Amount) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Amount[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.Depositor) > 0 { + i -= len(m.Depositor) + copy(dAtA[i:], m.Depositor) + i = encodeVarintCodec(dAtA, i, uint64(len(m.Depositor))) + i-- + dAtA[i] = 0x12 + } + if m.ProposalID != 0 { + i = encodeVarintCodec(dAtA, i, uint64(m.ProposalID)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *ProposalBase) 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 *ProposalBase) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ProposalBase) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + n3, err3 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.VotingEndTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.VotingEndTime):]) + if err3 != nil { + return 0, err3 + } + i -= n3 + i = encodeVarintCodec(dAtA, i, uint64(n3)) + i-- + dAtA[i] = 0x42 + n4, err4 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.VotingStartTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.VotingStartTime):]) + if err4 != nil { + return 0, err4 + } + i -= n4 + i = encodeVarintCodec(dAtA, i, uint64(n4)) + i-- + dAtA[i] = 0x3a + if len(m.TotalDeposit) > 0 { + for iNdEx := len(m.TotalDeposit) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.TotalDeposit[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } + } + n5, err5 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.DepositEndTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.DepositEndTime):]) + if err5 != nil { + return 0, err5 + } + i -= n5 + i = encodeVarintCodec(dAtA, i, uint64(n5)) + i-- + dAtA[i] = 0x2a + n6, err6 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.SubmitTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.SubmitTime):]) + if err6 != nil { + return 0, err6 + } + i -= n6 + i = encodeVarintCodec(dAtA, i, uint64(n6)) + i-- + dAtA[i] = 0x22 + { + size, err := m.FinalTallyResult.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + if m.Status != 0 { + i = encodeVarintCodec(dAtA, i, uint64(m.Status)) + i-- + dAtA[i] = 0x10 + } + if m.ProposalID != 0 { + i = encodeVarintCodec(dAtA, i, uint64(m.ProposalID)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *TallyResult) 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 *TallyResult) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TallyResult) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size := m.NoWithVeto.Size() + i -= size + if _, err := m.NoWithVeto.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + { + size := m.No.Size() + i -= size + if _, err := m.No.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + { + size := m.Abstain.Size() + i -= size + if _, err := m.Abstain.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + { + size := m.Yes.Size() + i -= size + if _, err := m.Yes.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *Vote) 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 *Vote) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Vote) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Option != 0 { + i = encodeVarintCodec(dAtA, i, uint64(m.Option)) + i-- + dAtA[i] = 0x18 + } + if len(m.Voter) > 0 { + i -= len(m.Voter) + copy(dAtA[i:], m.Voter) + i = encodeVarintCodec(dAtA, i, uint64(len(m.Voter))) + i-- + dAtA[i] = 0x12 + } + if m.ProposalID != 0 { + i = encodeVarintCodec(dAtA, i, uint64(m.ProposalID)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *BasicProposal) 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 *BasicProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *BasicProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Content != nil { + { + size, err := m.Content.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if m.ProposalBase != nil { + { + size, err := m.ProposalBase.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *BasicContent) 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 *BasicContent) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *BasicContent) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Sum != nil { + { + size := m.Sum.Size() + i -= size + if _, err := m.Sum.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + } + } + return len(dAtA) - i, nil +} + +func (m *BasicContent_Text) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *BasicContent_Text) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.Text != nil { + { + size, err := m.Text.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} +func encodeVarintCodec(dAtA []byte, offset int, v uint64) int { + offset -= sovCodec(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgCommon) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Sum != nil { + n += m.Sum.Size() + } + return n +} + +func (m *MsgCommon_GovDeposit) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.GovDeposit != nil { + l = m.GovDeposit.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *MsgCommon_GovVote) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.GovVote != nil { + l = m.GovVote.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *MsgSubmitProposalBase) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.IntialDeposit) > 0 { + for _, e := range m.IntialDeposit { + l = e.Size() + n += 1 + l + sovCodec(uint64(l)) + } + } + l = len(m.Proposer) + if l > 0 { + n += 1 + l + sovCodec(uint64(l)) + } + return n +} + +func (m *MsgDeposit) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ProposalID != 0 { + n += 1 + sovCodec(uint64(m.ProposalID)) + } + l = len(m.Depositor) + if l > 0 { + n += 1 + l + sovCodec(uint64(l)) + } + if len(m.Amount) > 0 { + for _, e := range m.Amount { + l = e.Size() + n += 1 + l + sovCodec(uint64(l)) + } + } + return n +} + +func (m *MsgVote) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ProposalID != 0 { + n += 1 + sovCodec(uint64(m.ProposalID)) + } + l = len(m.Voter) + if l > 0 { + n += 1 + l + sovCodec(uint64(l)) + } + if m.Option != 0 { + n += 1 + sovCodec(uint64(m.Option)) + } + return n +} + +func (m *TextProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Title) + if l > 0 { + n += 1 + l + sovCodec(uint64(l)) + } + l = len(m.Description) + if l > 0 { + n += 1 + l + sovCodec(uint64(l)) + } + return n +} + +func (m *Deposit) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ProposalID != 0 { + n += 1 + sovCodec(uint64(m.ProposalID)) + } + l = len(m.Depositor) + if l > 0 { + n += 1 + l + sovCodec(uint64(l)) + } + if len(m.Amount) > 0 { + for _, e := range m.Amount { + l = e.Size() + n += 1 + l + sovCodec(uint64(l)) + } + } + return n +} + +func (m *ProposalBase) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ProposalID != 0 { + n += 1 + sovCodec(uint64(m.ProposalID)) + } + if m.Status != 0 { + n += 1 + sovCodec(uint64(m.Status)) + } + l = m.FinalTallyResult.Size() + n += 1 + l + sovCodec(uint64(l)) + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.SubmitTime) + n += 1 + l + sovCodec(uint64(l)) + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.DepositEndTime) + n += 1 + l + sovCodec(uint64(l)) + if len(m.TotalDeposit) > 0 { + for _, e := range m.TotalDeposit { + l = e.Size() + n += 1 + l + sovCodec(uint64(l)) + } + } + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.VotingStartTime) + n += 1 + l + sovCodec(uint64(l)) + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.VotingEndTime) + n += 1 + l + sovCodec(uint64(l)) + return n +} + +func (m *TallyResult) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Yes.Size() + n += 1 + l + sovCodec(uint64(l)) + l = m.Abstain.Size() + n += 1 + l + sovCodec(uint64(l)) + l = m.No.Size() + n += 1 + l + sovCodec(uint64(l)) + l = m.NoWithVeto.Size() + n += 1 + l + sovCodec(uint64(l)) + return n +} + +func (m *Vote) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ProposalID != 0 { + n += 1 + sovCodec(uint64(m.ProposalID)) + } + l = len(m.Voter) + if l > 0 { + n += 1 + l + sovCodec(uint64(l)) + } + if m.Option != 0 { + n += 1 + sovCodec(uint64(m.Option)) + } + return n +} + +func (m *BasicProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ProposalBase != nil { + l = m.ProposalBase.Size() + n += 1 + l + sovCodec(uint64(l)) + } + if m.Content != nil { + l = m.Content.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} + +func (m *BasicContent) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Sum != nil { + n += m.Sum.Size() + } + return n +} + +func (m *BasicContent_Text) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Text != nil { + l = m.Text.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} + +func sovCodec(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozCodec(x uint64) (n int) { + return sovCodec(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (this *MsgCommon) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&MsgCommon{`, + `Sum:` + fmt.Sprintf("%v", this.Sum) + `,`, + `}`, + }, "") + return s +} +func (this *MsgCommon_GovDeposit) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&MsgCommon_GovDeposit{`, + `GovDeposit:` + strings.Replace(fmt.Sprintf("%v", this.GovDeposit), "MsgDeposit", "MsgDeposit", 1) + `,`, + `}`, + }, "") + return s +} +func (this *MsgCommon_GovVote) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&MsgCommon_GovVote{`, + `GovVote:` + strings.Replace(fmt.Sprintf("%v", this.GovVote), "MsgVote", "MsgVote", 1) + `,`, + `}`, + }, "") + return s +} +func (this *MsgSubmitProposalBase) String() string { + if this == nil { + return "nil" + } + repeatedStringForIntialDeposit := "[]Coin{" + for _, f := range this.IntialDeposit { + repeatedStringForIntialDeposit += fmt.Sprintf("%v", f) + "," + } + repeatedStringForIntialDeposit += "}" + s := strings.Join([]string{`&MsgSubmitProposalBase{`, + `IntialDeposit:` + repeatedStringForIntialDeposit + `,`, + `Proposer:` + fmt.Sprintf("%v", this.Proposer) + `,`, + `}`, + }, "") + return s +} +func (this *BasicContent) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&BasicContent{`, + `Sum:` + fmt.Sprintf("%v", this.Sum) + `,`, + `}`, + }, "") + return s +} +func (this *BasicContent_Text) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&BasicContent_Text{`, + `Text:` + strings.Replace(fmt.Sprintf("%v", this.Text), "TextProposal", "TextProposal", 1) + `,`, + `}`, + }, "") + return s +} +func valueToStringCodec(v interface{}) string { + rv := reflect.ValueOf(v) + if rv.IsNil() { + return "nil" + } + pv := reflect.Indirect(rv).Interface() + return fmt.Sprintf("*%v", pv) +} +func (m *MsgCommon) 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 ErrIntOverflowCodec + } + 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: MsgCommon: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgCommon: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field GovDeposit", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &MsgDeposit{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Sum = &MsgCommon_GovDeposit{v} + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field GovVote", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &MsgVote{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Sum = &MsgCommon_GovVote{v} + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCodec(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgSubmitProposalBase) 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 ErrIntOverflowCodec + } + 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: MsgSubmitProposalBase: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSubmitProposalBase: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field IntialDeposit", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.IntialDeposit = append(m.IntialDeposit, types.Coin{}) + if err := m.IntialDeposit[len(m.IntialDeposit)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Proposer", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Proposer = append(m.Proposer[:0], dAtA[iNdEx:postIndex]...) + if m.Proposer == nil { + m.Proposer = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCodec(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgDeposit) 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 ErrIntOverflowCodec + } + 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: MsgDeposit: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgDeposit: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ProposalID", wireType) + } + m.ProposalID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ProposalID |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Depositor", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Depositor = append(m.Depositor[:0], dAtA[iNdEx:postIndex]...) + if m.Depositor == nil { + m.Depositor = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Amount = append(m.Amount, types.Coin{}) + if err := m.Amount[len(m.Amount)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCodec(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgVote) 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 ErrIntOverflowCodec + } + 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: MsgVote: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgVote: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ProposalID", wireType) + } + m.ProposalID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ProposalID |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Voter", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Voter = append(m.Voter[:0], dAtA[iNdEx:postIndex]...) + if m.Voter == nil { + m.Voter = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Option", wireType) + } + m.Option = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Option |= VoteOption(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipCodec(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *TextProposal) 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 ErrIntOverflowCodec + } + 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: TextProposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TextProposal: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Title", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + 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 ErrInvalidLengthCodec + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Title = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + 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 ErrInvalidLengthCodec + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Description = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCodec(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Deposit) 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 ErrIntOverflowCodec + } + 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: Deposit: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Deposit: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ProposalID", wireType) + } + m.ProposalID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ProposalID |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Depositor", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Depositor = append(m.Depositor[:0], dAtA[iNdEx:postIndex]...) + if m.Depositor == nil { + m.Depositor = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Amount = append(m.Amount, types.Coin{}) + if err := m.Amount[len(m.Amount)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCodec(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ProposalBase) 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 ErrIntOverflowCodec + } + 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: ProposalBase: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ProposalBase: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ProposalID", wireType) + } + m.ProposalID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ProposalID |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType) + } + m.Status = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Status |= ProposalStatus(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FinalTallyResult", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.FinalTallyResult.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SubmitTime", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.SubmitTime, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DepositEndTime", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.DepositEndTime, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TotalDeposit", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TotalDeposit = append(m.TotalDeposit, types.Coin{}) + if err := m.TotalDeposit[len(m.TotalDeposit)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field VotingStartTime", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.VotingStartTime, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field VotingEndTime", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.VotingEndTime, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCodec(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *TallyResult) 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 ErrIntOverflowCodec + } + 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: TallyResult: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TallyResult: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Yes", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Yes.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Abstain", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Abstain.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field No", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.No.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NoWithVeto", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.NoWithVeto.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCodec(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Vote) 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 ErrIntOverflowCodec + } + 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: Vote: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Vote: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ProposalID", wireType) + } + m.ProposalID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ProposalID |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Voter", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Voter = append(m.Voter[:0], dAtA[iNdEx:postIndex]...) + if m.Voter == nil { + m.Voter = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Option", wireType) + } + m.Option = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Option |= VoteOption(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipCodec(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *BasicProposal) 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 ErrIntOverflowCodec + } + 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: BasicProposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: BasicProposal: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProposalBase", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.ProposalBase == nil { + m.ProposalBase = &ProposalBase{} + } + if err := m.ProposalBase.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Content", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Content == nil { + m.Content = &BasicContent{} + } + if err := m.Content.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCodec(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *BasicContent) 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 ErrIntOverflowCodec + } + 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: BasicContent: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: BasicContent: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Text", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &TextProposal{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Sum = &BasicContent_Text{v} + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCodec(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipCodec(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowCodec + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowCodec + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowCodec + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthCodec + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupCodec + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthCodec + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthCodec = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowCodec = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupCodec = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/gov/types/codec.proto b/x/gov/types/codec.proto new file mode 100644 index 000000000000..8d2dd42acc53 --- /dev/null +++ b/x/gov/types/codec.proto @@ -0,0 +1,131 @@ +syntax = "proto3"; +package cosmos_sdk.x.gov.v1; + +import "types/types.proto"; +import "third_party/proto/gogoproto/gogo.proto"; +import "third_party/proto/cosmos-proto/cosmos.proto"; +import "google/protobuf/timestamp.proto"; + +option go_package = "github.com/cosmos/cosmos-sdk/x/gov/types"; +option (gogoproto.goproto_stringer_all) = false; +option (gogoproto.stringer_all) = false; +option (gogoproto.goproto_getters_all) = false; + +message MsgCommon { + option (cosmos_proto.interface_type) = "github.com/cosmos/cosmos-sdk/types.Msg"; + option (gogoproto.stringer) = true; + oneof sum { + MsgDeposit gov_deposit = 1; + MsgVote gov_vote = 2; + } +} + +message MsgSubmitProposalBase { + option (gogoproto.stringer) = true; + repeated cosmos_sdk.v1.Coin intial_deposit = 1 [(gogoproto.nullable) = false + ,(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + ,(gogoproto.moretags) = "yaml:\"initial_deposit\""]; + bytes proposer = 2 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; +} + +// MsgDeposit defines a message to submit a deposit to an existing proposal +message MsgDeposit { + uint64 proposal_id = 1 [(gogoproto.customname) = "ProposalID" + ,(gogoproto.moretags) = "yaml:\"proposal_id\"" + ,(gogoproto.jsontag) = "proposal_id"]; + bytes depositor = 2 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; + repeated cosmos_sdk.v1.Coin amount = 3 [(gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; +} + +// VoteOption defines a vote option +enum VoteOption { + option (gogoproto.enum_stringer) = false; + option (gogoproto.goproto_enum_stringer) = false; + option (gogoproto.goproto_enum_prefix) = false; + EMPTY = 0 [(gogoproto.enumvalue_customname) = "OptionEmpty"]; + YES = 1 [(gogoproto.enumvalue_customname) = "OptionYes"]; + ABSTAIN = 2 [(gogoproto.enumvalue_customname) = "OptionAbstain"]; + NO = 3 [(gogoproto.enumvalue_customname) = "OptionNo"]; + NO_WITH_VETO = 4 [(gogoproto.enumvalue_customname) = "OptionNoWithVeto"]; +} + +// MsgVote defines a message to cast a vote +message MsgVote { + uint64 proposal_id = 1 [(gogoproto.customname) = "ProposalID" + ,(gogoproto.moretags) = "yaml:\"proposal_id\"" + ,(gogoproto.jsontag) = "proposal_id"]; + bytes voter = 2 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; + VoteOption option = 3; +} + +// TextProposal defines a standard text proposal whose changes need to be +// manually updated in case of approval +message TextProposal { + string title = 1; + string description = 2; +} + +// Deposit defines an amount deposited by an account address to an active proposal +message Deposit { + uint64 proposal_id = 1 [(gogoproto.customname) = "ProposalID" + ,(gogoproto.moretags) = "yaml:\"proposal_id\""]; + bytes depositor = 2 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; + repeated cosmos_sdk.v1.Coin amount = 3 [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; +} + +message ProposalBase { + option (gogoproto.goproto_stringer) = true; + option (gogoproto.face) = true; + uint64 proposal_id = 1 [(gogoproto.customname) = "ProposalID" + ,(gogoproto.moretags) = "yaml:\"proposal_id\""]; + ProposalStatus status = 2; + TallyResult final_tally_result = 3 [(gogoproto.nullable) = false]; + google.protobuf.Timestamp submit_time = 4 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false]; + google.protobuf.Timestamp deposit_end_time = 5 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false]; + repeated cosmos_sdk.v1.Coin total_deposit = 6 [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; + google.protobuf.Timestamp voting_start_time = 7 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false]; + google.protobuf.Timestamp voting_end_time = 8 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false]; +} + +// ProposalStatus is a type alias that represents a proposal status as a byte +enum ProposalStatus { + option (gogoproto.enum_stringer) = false; + option (gogoproto.goproto_enum_stringer) = false; + option (gogoproto.goproto_enum_prefix) = false; + NIL = 0 [(gogoproto.enumvalue_customname) = "StatusNil"]; + DEPOSIT_PERIOD = 1 [(gogoproto.enumvalue_customname) = "StatusDepositPeriod"]; + VOTING_PERIOD = 2 [(gogoproto.enumvalue_customname) = "StatusVotingPeriod"]; + PASSED = 3 [(gogoproto.enumvalue_customname) = "StatusPassed"]; + REJECTED = 4 [(gogoproto.enumvalue_customname) = "StatusRejected"]; + FAILED = 5 [(gogoproto.enumvalue_customname) = "StatusFailed"]; +} + +// TallyResult defines a standard tally for a proposal +message TallyResult { + bytes yes = 1 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", (gogoproto.nullable) = false]; + bytes abstain = 2 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", (gogoproto.nullable) = false]; + bytes no = 3 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", (gogoproto.nullable) = false]; + bytes no_with_veto = 4 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", (gogoproto.nullable) = false + ,(gogoproto.moretags) = "yaml:\"no_with_veto\""]; +} + +message Vote { + uint64 proposal_id = 1 [(gogoproto.customname) = "ProposalID" + ,(gogoproto.moretags) = "yaml:\"proposal_id\""]; + bytes voter = 2 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; + VoteOption option = 3; +} + +message BasicProposal { + ProposalBase base = 1 [(gogoproto.embed) = true]; + BasicContent content = 2; +} + +message BasicContent { + option (cosmos_proto.interface_type) = "Content"; + option (gogoproto.stringer) = true; + oneof sum { + TextProposal text = 1; + } +} diff --git a/x/gov/types/deposit.go b/x/gov/types/deposit.go index 4d9ff9304179..098bc9b2e3a8 100644 --- a/x/gov/types/deposit.go +++ b/x/gov/types/deposit.go @@ -6,13 +6,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -// Deposit defines an amount deposited by an account address to an active proposal -type Deposit struct { - ProposalID uint64 `json:"proposal_id" yaml:"proposal_id"` // proposalID of the proposal - Depositor sdk.AccAddress `json:"depositor" yaml:"depositor"` // Address of the depositor - Amount sdk.Coins `json:"amount" yaml:"amount"` // Deposit amount -} - // NewDeposit creates a new Deposit instance func NewDeposit(proposalID uint64, depositor sdk.AccAddress, amount sdk.Coins) Deposit { return Deposit{proposalID, depositor, amount} diff --git a/x/gov/types/msgs.go b/x/gov/types/msgs.go index 882e0c560c31..56ea7614bded 100644 --- a/x/gov/types/msgs.go +++ b/x/gov/types/msgs.go @@ -75,13 +75,6 @@ func (msg MsgSubmitProposal) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.Proposer} } -// MsgDeposit defines a message to submit a deposit to an existing proposal -type MsgDeposit struct { - ProposalID uint64 `json:"proposal_id" yaml:"proposal_id"` // ID of the proposal - Depositor sdk.AccAddress `json:"depositor" yaml:"depositor"` // Address of the depositor - Amount sdk.Coins `json:"amount" yaml:"amount"` // Coins to add to the proposal's deposit -} - // NewMsgDeposit creates a new MsgDeposit instance func NewMsgDeposit(depositor sdk.AccAddress, proposalID uint64, amount sdk.Coins) MsgDeposit { return MsgDeposit{proposalID, depositor, amount} @@ -128,13 +121,6 @@ func (msg MsgDeposit) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.Depositor} } -// MsgVote defines a message to cast a vote -type MsgVote struct { - ProposalID uint64 `json:"proposal_id" yaml:"proposal_id"` // ID of the proposal - Voter sdk.AccAddress `json:"voter" yaml:"voter"` // address of the voter - Option VoteOption `json:"option" yaml:"option"` // option from OptionSet chosen by the voter -} - // NewMsgVote creates a message to cast a vote on an active proposal func NewMsgVote(voter sdk.AccAddress, proposalID uint64, option VoteOption) MsgVote { return MsgVote{proposalID, voter, option} diff --git a/x/gov/types/proposal.go b/x/gov/types/proposal.go index 945cf786687b..66658cd67063 100644 --- a/x/gov/types/proposal.go +++ b/x/gov/types/proposal.go @@ -79,18 +79,6 @@ type ( // ProposalQueue defines a queue for proposal ids ProposalQueue []uint64 - // ProposalStatus is a type alias that represents a proposal status as a byte - ProposalStatus byte -) - -// Valid Proposal statuses -const ( - StatusNil ProposalStatus = 0x00 - StatusDepositPeriod ProposalStatus = 0x01 - StatusVotingPeriod ProposalStatus = 0x02 - StatusPassed ProposalStatus = 0x03 - StatusRejected ProposalStatus = 0x04 - StatusFailed ProposalStatus = 0x05 ) // ProposalStatusFromString turns a string into a ProposalStatus @@ -205,13 +193,6 @@ const ( ProposalTypeText string = "Text" ) -// TextProposal defines a standard text proposal whose changes need to be -// manually updated in case of approval -type TextProposal struct { - Title string `json:"title" yaml:"title"` - Description string `json:"description" yaml:"description"` -} - // NewTextProposal creates a text proposal Content func NewTextProposal(title, description string) Content { return TextProposal{title, description} diff --git a/x/gov/types/tally.go b/x/gov/types/tally.go index d437816e9a9e..6020abe5b41b 100644 --- a/x/gov/types/tally.go +++ b/x/gov/types/tally.go @@ -28,14 +28,6 @@ func NewValidatorGovInfo(address sdk.ValAddress, bondedTokens sdk.Int, delegator } } -// TallyResult defines a standard tally for a proposal -type TallyResult struct { - Yes sdk.Int `json:"yes" yaml:"yes"` - Abstain sdk.Int `json:"abstain" yaml:"abstain"` - No sdk.Int `json:"no" yaml:"no"` - NoWithVeto sdk.Int `json:"no_with_veto" yaml:"no_with_veto"` -} - // NewTallyResult creates a new TallyResult instance func NewTallyResult(yes, abstain, no, noWithVeto sdk.Int) TallyResult { return TallyResult{ diff --git a/x/gov/types/vote.go b/x/gov/types/vote.go index ca49fdb6fa52..f74f27ef2156 100644 --- a/x/gov/types/vote.go +++ b/x/gov/types/vote.go @@ -7,13 +7,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -// Vote -type Vote struct { - ProposalID uint64 `json:"proposal_id" yaml:"proposal_id"` // proposalID of the proposal - Voter sdk.AccAddress `json:"voter" yaml:"voter"` // address of the voter - Option VoteOption `json:"option" yaml:"option"` // option from OptionSet chosen by the voter -} - // NewVote creates a new Vote instance func NewVote(proposalID uint64, voter sdk.AccAddress, option VoteOption) Vote { return Vote{proposalID, voter, option} @@ -49,18 +42,6 @@ func (v Vote) Empty() bool { return v.Equals(Vote{}) } -// VoteOption defines a vote option -type VoteOption byte - -// Vote options -const ( - OptionEmpty VoteOption = 0x00 - OptionYes VoteOption = 0x01 - OptionAbstain VoteOption = 0x02 - OptionNo VoteOption = 0x03 - OptionNoWithVeto VoteOption = 0x04 -) - // VoteOptionFromString returns a VoteOption from a string. It returns an error // if the string is invalid. func VoteOptionFromString(str string) (VoteOption, error) { From 3919645e8b349b9311bd9c6f68b2b2605c009e4f Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Mon, 17 Feb 2020 14:21:07 -0500 Subject: [PATCH 249/529] Rename GovCodec to gov.Codec --- x/gov/keeper/keeper.go | 4 ++-- x/gov/types/codec.go | 16 +++++++++------- x/gov/types/codec.proto | 9 --------- 3 files changed, 11 insertions(+), 18 deletions(-) diff --git a/x/gov/keeper/keeper.go b/x/gov/keeper/keeper.go index 0904a4ea2a89..d8983bd41287 100644 --- a/x/gov/keeper/keeper.go +++ b/x/gov/keeper/keeper.go @@ -26,7 +26,7 @@ type Keeper struct { storeKey sdk.StoreKey // The codec codec for binary encoding/decoding. - cdc types.GovCodec + cdc types.Codec // Proposal router router types.Router @@ -40,7 +40,7 @@ type Keeper struct { // // CONTRACT: the parameter Subspace must have the param key table already initialized func NewKeeper( - cdc types.GovCodec, key sdk.StoreKey, paramSpace types.ParamSubspace, + cdc types.Codec, key sdk.StoreKey, paramSpace types.ParamSubspace, supplyKeeper types.SupplyKeeper, sk types.StakingKeeper, rtr types.Router, ) Keeper { diff --git a/x/gov/types/codec.go b/x/gov/types/codec.go index ff7ad8a77c98..6e85045ddb96 100644 --- a/x/gov/types/codec.go +++ b/x/gov/types/codec.go @@ -4,6 +4,14 @@ import ( "github.com/cosmos/cosmos-sdk/codec" ) +type Codec interface { + codec.Marshaler + + MarshalProposal(p Proposal) ([]byte, error) + UnmarshalProposal(bz []byte, ptr *Proposal) error +} + + // module codec var ModuleCdc = codec.New() @@ -31,12 +39,6 @@ func init() { RegisterCodec(ModuleCdc) } -type GovCodec interface { - codec.Marshaler - MarshalProposal(p Proposal) ([]byte, error) - UnmarshalProposal(bz []byte, ptr *Proposal) error -} - type AminoGovCodec struct { codec.Marshaler amino *codec.Codec @@ -54,4 +56,4 @@ func (a AminoGovCodec) UnmarshalProposal(bz []byte, ptr *Proposal) error { return a.amino.UnmarshalBinaryBare(bz, ptr) } -var _ GovCodec = AminoGovCodec{} +var _ Codec = AminoGovCodec{} diff --git a/x/gov/types/codec.proto b/x/gov/types/codec.proto index 8d2dd42acc53..0eaa5c60bd4b 100644 --- a/x/gov/types/codec.proto +++ b/x/gov/types/codec.proto @@ -11,15 +11,6 @@ option (gogoproto.goproto_stringer_all) = false; option (gogoproto.stringer_all) = false; option (gogoproto.goproto_getters_all) = false; -message MsgCommon { - option (cosmos_proto.interface_type) = "github.com/cosmos/cosmos-sdk/types.Msg"; - option (gogoproto.stringer) = true; - oneof sum { - MsgDeposit gov_deposit = 1; - MsgVote gov_vote = 2; - } -} - message MsgSubmitProposalBase { option (gogoproto.stringer) = true; repeated cosmos_sdk.v1.Coin intial_deposit = 1 [(gogoproto.nullable) = false From d563248bbbd8919fe9a15e4a245ba8c073295037 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Mon, 17 Feb 2020 14:29:24 -0500 Subject: [PATCH 250/529] mv codec.proto -> types.proto --- x/gov/types/{codec.pb.go => types.pb.go} | 992 +++++++---------------- x/gov/types/{codec.proto => types.proto} | 0 2 files changed, 304 insertions(+), 688 deletions(-) rename x/gov/types/{codec.pb.go => types.pb.go} (71%) rename x/gov/types/{codec.proto => types.proto} (100%) diff --git a/x/gov/types/codec.pb.go b/x/gov/types/types.pb.go similarity index 71% rename from x/gov/types/codec.pb.go rename to x/gov/types/types.pb.go index be21d7f2c64e..3f7a18cceb59 100644 --- a/x/gov/types/codec.pb.go +++ b/x/gov/types/types.pb.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: x/gov/types/codec.proto +// source: x/gov/types/types.proto package types @@ -61,7 +61,7 @@ var VoteOption_value = map[string]int32{ } func (VoteOption) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_4ed4b2a5a30fa918, []int{0} + return fileDescriptor_a5ae5e91b5b3fb03, []int{0} } // ProposalStatus is a type alias that represents a proposal status as a byte @@ -95,91 +95,7 @@ var ProposalStatus_value = map[string]int32{ } func (ProposalStatus) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_4ed4b2a5a30fa918, []int{1} -} - -type MsgCommon struct { - // Types that are valid to be assigned to Sum: - // *MsgCommon_GovDeposit - // *MsgCommon_GovVote - Sum isMsgCommon_Sum `protobuf_oneof:"sum"` -} - -func (m *MsgCommon) Reset() { *m = MsgCommon{} } -func (*MsgCommon) ProtoMessage() {} -func (*MsgCommon) Descriptor() ([]byte, []int) { - return fileDescriptor_4ed4b2a5a30fa918, []int{0} -} -func (m *MsgCommon) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *MsgCommon) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_MsgCommon.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 *MsgCommon) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgCommon.Merge(m, src) -} -func (m *MsgCommon) XXX_Size() int { - return m.Size() -} -func (m *MsgCommon) XXX_DiscardUnknown() { - xxx_messageInfo_MsgCommon.DiscardUnknown(m) -} - -var xxx_messageInfo_MsgCommon proto.InternalMessageInfo - -type isMsgCommon_Sum interface { - isMsgCommon_Sum() - MarshalTo([]byte) (int, error) - Size() int -} - -type MsgCommon_GovDeposit struct { - GovDeposit *MsgDeposit `protobuf:"bytes,1,opt,name=gov_deposit,json=govDeposit,proto3,oneof" json:"gov_deposit,omitempty"` -} -type MsgCommon_GovVote struct { - GovVote *MsgVote `protobuf:"bytes,2,opt,name=gov_vote,json=govVote,proto3,oneof" json:"gov_vote,omitempty"` -} - -func (*MsgCommon_GovDeposit) isMsgCommon_Sum() {} -func (*MsgCommon_GovVote) isMsgCommon_Sum() {} - -func (m *MsgCommon) GetSum() isMsgCommon_Sum { - if m != nil { - return m.Sum - } - return nil -} - -func (m *MsgCommon) GetGovDeposit() *MsgDeposit { - if x, ok := m.GetSum().(*MsgCommon_GovDeposit); ok { - return x.GovDeposit - } - return nil -} - -func (m *MsgCommon) GetGovVote() *MsgVote { - if x, ok := m.GetSum().(*MsgCommon_GovVote); ok { - return x.GovVote - } - return nil -} - -// XXX_OneofWrappers is for the internal use of the proto package. -func (*MsgCommon) XXX_OneofWrappers() []interface{} { - return []interface{}{ - (*MsgCommon_GovDeposit)(nil), - (*MsgCommon_GovVote)(nil), - } + return fileDescriptor_a5ae5e91b5b3fb03, []int{1} } type MsgSubmitProposalBase struct { @@ -190,7 +106,7 @@ type MsgSubmitProposalBase struct { func (m *MsgSubmitProposalBase) Reset() { *m = MsgSubmitProposalBase{} } func (*MsgSubmitProposalBase) ProtoMessage() {} func (*MsgSubmitProposalBase) Descriptor() ([]byte, []int) { - return fileDescriptor_4ed4b2a5a30fa918, []int{1} + return fileDescriptor_a5ae5e91b5b3fb03, []int{0} } func (m *MsgSubmitProposalBase) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -229,7 +145,7 @@ type MsgDeposit struct { func (m *MsgDeposit) Reset() { *m = MsgDeposit{} } func (*MsgDeposit) ProtoMessage() {} func (*MsgDeposit) Descriptor() ([]byte, []int) { - return fileDescriptor_4ed4b2a5a30fa918, []int{2} + return fileDescriptor_a5ae5e91b5b3fb03, []int{1} } func (m *MsgDeposit) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -268,7 +184,7 @@ type MsgVote struct { func (m *MsgVote) Reset() { *m = MsgVote{} } func (*MsgVote) ProtoMessage() {} func (*MsgVote) Descriptor() ([]byte, []int) { - return fileDescriptor_4ed4b2a5a30fa918, []int{3} + return fileDescriptor_a5ae5e91b5b3fb03, []int{2} } func (m *MsgVote) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -307,7 +223,7 @@ type TextProposal struct { func (m *TextProposal) Reset() { *m = TextProposal{} } func (*TextProposal) ProtoMessage() {} func (*TextProposal) Descriptor() ([]byte, []int) { - return fileDescriptor_4ed4b2a5a30fa918, []int{4} + return fileDescriptor_a5ae5e91b5b3fb03, []int{3} } func (m *TextProposal) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -346,7 +262,7 @@ type Deposit struct { func (m *Deposit) Reset() { *m = Deposit{} } func (*Deposit) ProtoMessage() {} func (*Deposit) Descriptor() ([]byte, []int) { - return fileDescriptor_4ed4b2a5a30fa918, []int{5} + return fileDescriptor_a5ae5e91b5b3fb03, []int{4} } func (m *Deposit) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -390,7 +306,7 @@ func (m *ProposalBase) Reset() { *m = ProposalBase{} } func (m *ProposalBase) String() string { return proto.CompactTextString(m) } func (*ProposalBase) ProtoMessage() {} func (*ProposalBase) Descriptor() ([]byte, []int) { - return fileDescriptor_4ed4b2a5a30fa918, []int{6} + return fileDescriptor_a5ae5e91b5b3fb03, []int{5} } func (m *ProposalBase) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -430,7 +346,7 @@ type TallyResult struct { func (m *TallyResult) Reset() { *m = TallyResult{} } func (*TallyResult) ProtoMessage() {} func (*TallyResult) Descriptor() ([]byte, []int) { - return fileDescriptor_4ed4b2a5a30fa918, []int{7} + return fileDescriptor_a5ae5e91b5b3fb03, []int{6} } func (m *TallyResult) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -468,7 +384,7 @@ type Vote struct { func (m *Vote) Reset() { *m = Vote{} } func (*Vote) ProtoMessage() {} func (*Vote) Descriptor() ([]byte, []int) { - return fileDescriptor_4ed4b2a5a30fa918, []int{8} + return fileDescriptor_a5ae5e91b5b3fb03, []int{7} } func (m *Vote) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -505,7 +421,7 @@ type BasicProposal struct { func (m *BasicProposal) Reset() { *m = BasicProposal{} } func (*BasicProposal) ProtoMessage() {} func (*BasicProposal) Descriptor() ([]byte, []int) { - return fileDescriptor_4ed4b2a5a30fa918, []int{9} + return fileDescriptor_a5ae5e91b5b3fb03, []int{8} } func (m *BasicProposal) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -543,7 +459,7 @@ type BasicContent struct { func (m *BasicContent) Reset() { *m = BasicContent{} } func (*BasicContent) ProtoMessage() {} func (*BasicContent) Descriptor() ([]byte, []int) { - return fileDescriptor_4ed4b2a5a30fa918, []int{10} + return fileDescriptor_a5ae5e91b5b3fb03, []int{9} } func (m *BasicContent) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -608,7 +524,6 @@ func (*BasicContent) XXX_OneofWrappers() []interface{} { func init() { proto.RegisterEnum("cosmos_sdk.x.gov.v1.VoteOption", VoteOption_name, VoteOption_value) proto.RegisterEnum("cosmos_sdk.x.gov.v1.ProposalStatus", ProposalStatus_name, ProposalStatus_value) - proto.RegisterType((*MsgCommon)(nil), "cosmos_sdk.x.gov.v1.MsgCommon") proto.RegisterType((*MsgSubmitProposalBase)(nil), "cosmos_sdk.x.gov.v1.MsgSubmitProposalBase") proto.RegisterType((*MsgDeposit)(nil), "cosmos_sdk.x.gov.v1.MsgDeposit") proto.RegisterType((*MsgVote)(nil), "cosmos_sdk.x.gov.v1.MsgVote") @@ -621,90 +536,86 @@ func init() { proto.RegisterType((*BasicContent)(nil), "cosmos_sdk.x.gov.v1.BasicContent") } -func init() { proto.RegisterFile("x/gov/types/codec.proto", fileDescriptor_4ed4b2a5a30fa918) } - -var fileDescriptor_4ed4b2a5a30fa918 = []byte{ - // 1279 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x57, 0xcf, 0x6b, 0x1b, 0xc7, - 0x17, 0xdf, 0x95, 0x64, 0xcb, 0x7e, 0xfa, 0x91, 0xcd, 0x38, 0xdf, 0xc4, 0x2c, 0x41, 0xbb, 0x5f, - 0xb5, 0x04, 0x37, 0x21, 0x72, 0xe3, 0x1c, 0x42, 0x1d, 0x28, 0xd5, 0x5a, 0x9b, 0x58, 0x21, 0x96, - 0xc4, 0x4a, 0x38, 0xa4, 0x50, 0x96, 0xb5, 0x76, 0xb3, 0xde, 0x44, 0xda, 0x11, 0x9a, 0x91, 0x6a, - 0xdf, 0x72, 0x2a, 0xad, 0x4e, 0xa1, 0x50, 0xe8, 0x45, 0x10, 0x68, 0x0e, 0xa1, 0xf4, 0xd0, 0x43, - 0xff, 0x81, 0xf6, 0x14, 0x7a, 0x69, 0x8e, 0xa1, 0x14, 0xa5, 0x71, 0x6e, 0xa5, 0xa7, 0x40, 0x2f, - 0x3d, 0x95, 0x9d, 0xd9, 0x8d, 0xd7, 0xd4, 0x09, 0x11, 0x49, 0x29, 0xf4, 0x62, 0x34, 0x33, 0x9f, - 0xcf, 0x67, 0xdf, 0xfb, 0xcc, 0xdb, 0xf7, 0xd6, 0x70, 0x62, 0x67, 0xd9, 0xc5, 0xc3, 0x65, 0xba, - 0xdb, 0x73, 0xc8, 0x72, 0x1b, 0xdb, 0x4e, 0xbb, 0xd4, 0xeb, 0x63, 0x8a, 0xd1, 0x42, 0x1b, 0x93, - 0x2e, 0x26, 0x26, 0xb1, 0x6f, 0x95, 0x76, 0x4a, 0x2e, 0x1e, 0x96, 0x86, 0xe7, 0xe4, 0xa3, 0x1c, - 0xc7, 0xfe, 0x72, 0x9c, 0x7c, 0x8a, 0x6e, 0x7b, 0x7d, 0xdb, 0xec, 0x59, 0x7d, 0xba, 0xbb, 0xcc, - 0xb6, 0x96, 0x5d, 0xec, 0xe2, 0xfd, 0x5f, 0x21, 0xee, 0xcc, 0xdf, 0x71, 0xfc, 0x09, 0x67, 0xe3, - 0x8b, 0x10, 0xac, 0xb8, 0x18, 0xbb, 0x1d, 0x87, 0xe3, 0xb6, 0x06, 0x37, 0x96, 0xa9, 0xd7, 0x75, - 0x08, 0xb5, 0xba, 0x3d, 0x0e, 0x28, 0x7e, 0x2f, 0xc2, 0xfc, 0x06, 0x71, 0xd7, 0x70, 0xb7, 0x8b, - 0x7d, 0xa4, 0x41, 0xc6, 0xc5, 0x43, 0xd3, 0x76, 0x7a, 0x98, 0x78, 0x74, 0x51, 0x54, 0xc5, 0xa5, - 0xcc, 0x8a, 0x52, 0x3a, 0x24, 0x83, 0xd2, 0x06, 0x71, 0x2b, 0x1c, 0xb6, 0x2e, 0x18, 0xe0, 0xe2, - 0x61, 0xb8, 0x42, 0xef, 0xc1, 0x5c, 0xa0, 0x31, 0xc4, 0xd4, 0x59, 0x4c, 0x30, 0x81, 0x93, 0x2f, - 0x12, 0xd8, 0xc4, 0xd4, 0x59, 0x17, 0x8c, 0xb4, 0x8b, 0x87, 0xc1, 0xcf, 0xd5, 0xd2, 0xed, 0x5f, - 0x54, 0xf1, 0xc7, 0xef, 0xce, 0x9e, 0x72, 0x3d, 0xba, 0x3d, 0xd8, 0x2a, 0xb5, 0x71, 0x37, 0x4c, - 0x27, 0x4a, 0x91, 0xd8, 0xb7, 0x42, 0xd3, 0x36, 0x88, 0xab, 0xcd, 0x40, 0x92, 0x0c, 0xba, 0xc5, - 0x3f, 0x44, 0xf8, 0xdf, 0x06, 0x71, 0x9b, 0x83, 0xad, 0xae, 0x47, 0x1b, 0x7d, 0xdc, 0xc3, 0xc4, - 0xea, 0x68, 0x16, 0x71, 0xd0, 0x27, 0x22, 0xe4, 0x3d, 0x9f, 0x7a, 0x56, 0x27, 0x96, 0x53, 0x72, - 0x29, 0xb3, 0xb2, 0x10, 0x0f, 0x69, 0x78, 0xae, 0xb4, 0x86, 0x3d, 0x5f, 0xbb, 0xf2, 0x60, 0xa2, - 0x08, 0xcf, 0x26, 0xca, 0xf1, 0x5d, 0xab, 0xdb, 0x59, 0x2d, 0x7a, 0xbe, 0x17, 0x67, 0x16, 0xbf, - 0x7e, 0xac, 0x2c, 0xbd, 0x42, 0x60, 0x81, 0x14, 0x31, 0x72, 0xfc, 0xb1, 0x91, 0x29, 0x1b, 0x30, - 0xd7, 0x63, 0x81, 0x39, 0x7d, 0x66, 0x4a, 0x56, 0x3b, 0xf7, 0xe7, 0x44, 0x39, 0xfb, 0x0a, 0x72, - 0xe5, 0x76, 0xbb, 0x6c, 0xdb, 0x7d, 0x87, 0x10, 0xe3, 0xb9, 0xc4, 0x6a, 0x2a, 0x30, 0xaa, 0xf8, - 0x79, 0x02, 0x60, 0xff, 0x1a, 0x50, 0x0b, 0x32, 0xbd, 0x30, 0x79, 0xd3, 0xb3, 0xd9, 0xe5, 0xa5, - 0xb4, 0xf3, 0x7b, 0x13, 0x05, 0x22, 0x4f, 0xaa, 0x95, 0xdf, 0x26, 0x4a, 0x1c, 0xf4, 0x6c, 0xa2, - 0x20, 0x9e, 0x6c, 0x6c, 0xb3, 0x68, 0x40, 0xb4, 0xaa, 0xda, 0xa8, 0x0e, 0xf3, 0xa1, 0x01, 0xf8, - 0x35, 0x42, 0xdf, 0xd7, 0x40, 0x1f, 0xc1, 0xac, 0xd5, 0xc5, 0x03, 0x9f, 0x2e, 0x26, 0x5f, 0x7c, - 0x15, 0xef, 0x06, 0x57, 0x31, 0x95, 0xe1, 0xa1, 0x68, 0xf1, 0x89, 0x08, 0xe9, 0xb0, 0xb4, 0xfe, - 0x21, 0x47, 0x2e, 0xc3, 0x4c, 0x50, 0xdc, 0xaf, 0xe1, 0x06, 0xe7, 0xa3, 0x0b, 0x30, 0x8b, 0x7b, - 0xd4, 0xc3, 0xfe, 0x62, 0x52, 0x15, 0x97, 0xf2, 0x2f, 0x78, 0xd1, 0x82, 0x4c, 0xea, 0x0c, 0x66, - 0x84, 0xf0, 0xe2, 0x25, 0xc8, 0xb6, 0x9c, 0x9d, 0xe7, 0xa5, 0x8e, 0x8e, 0xc1, 0x0c, 0xf5, 0x68, - 0xc7, 0x61, 0x19, 0xce, 0x1b, 0x7c, 0x81, 0x54, 0xc8, 0xd8, 0x0e, 0x69, 0xf7, 0x3d, 0xfe, 0x8c, - 0x04, 0x3b, 0x8b, 0x6f, 0x15, 0x6f, 0x27, 0x20, 0x1d, 0x55, 0x8f, 0x7e, 0x98, 0x57, 0x6f, 0x1f, - 0xf4, 0xea, 0x3f, 0x58, 0x2e, 0x5f, 0xcc, 0x40, 0xf6, 0x40, 0xcb, 0x78, 0x43, 0x3e, 0x5c, 0x84, - 0x59, 0x42, 0x2d, 0x3a, 0x20, 0xcc, 0x84, 0xfc, 0xca, 0x5b, 0x87, 0xde, 0x6d, 0x24, 0xd9, 0x64, - 0x50, 0x23, 0xa4, 0xa0, 0x16, 0xa0, 0x1b, 0x9e, 0x6f, 0x75, 0x4c, 0x6a, 0x75, 0x3a, 0xbb, 0x66, - 0xdf, 0x21, 0x83, 0x0e, 0x65, 0x45, 0x92, 0x59, 0x51, 0x0f, 0x15, 0x6a, 0x05, 0x40, 0x83, 0xe1, - 0xb4, 0x54, 0x60, 0x86, 0x21, 0x31, 0x85, 0xd8, 0x7e, 0x90, 0x19, 0x61, 0x2d, 0xd2, 0x0c, 0x86, - 0xc0, 0x62, 0x8a, 0xc9, 0xc9, 0x25, 0x3e, 0x21, 0x4a, 0xd1, 0x84, 0x28, 0xb5, 0xa2, 0x09, 0xa1, - 0xcd, 0x05, 0x42, 0x77, 0x1e, 0x2b, 0xa2, 0x01, 0x9c, 0x18, 0x1c, 0xa1, 0x1a, 0x48, 0xe1, 0xed, - 0x98, 0x8e, 0x6f, 0x73, 0xad, 0x99, 0x29, 0xb4, 0xf2, 0x21, 0x5b, 0xf7, 0x6d, 0xa6, 0x77, 0x13, - 0x72, 0x14, 0xd3, 0x58, 0x87, 0x9e, 0x7d, 0x93, 0xf7, 0x9c, 0x65, 0xda, 0x51, 0x91, 0x37, 0xe0, - 0xe8, 0x10, 0x53, 0xcf, 0x77, 0x4d, 0x42, 0xad, 0x7e, 0x68, 0x44, 0x7a, 0x8a, 0xe0, 0x8f, 0x70, - 0x7a, 0x33, 0x60, 0xb3, 0xe8, 0xaf, 0x42, 0xb8, 0xb5, 0x6f, 0xc6, 0xdc, 0x14, 0x7a, 0x39, 0x4e, - 0x0e, 0xbd, 0x58, 0x9d, 0xfb, 0xf2, 0xae, 0x22, 0xde, 0xbf, 0xab, 0x88, 0xc5, 0x1f, 0x12, 0x90, - 0x89, 0x5f, 0xde, 0x07, 0x90, 0xdc, 0x75, 0x08, 0x2b, 0xc7, 0xac, 0x56, 0x0a, 0xf8, 0x3f, 0x4f, - 0x94, 0x57, 0x99, 0x93, 0x55, 0x9f, 0x1a, 0x01, 0x15, 0xad, 0x43, 0xda, 0xda, 0x22, 0xd4, 0xf2, - 0xfc, 0xf0, 0xbd, 0x9c, 0x56, 0x25, 0xa2, 0xa3, 0xf7, 0x21, 0xe1, 0x63, 0x56, 0x8e, 0xd3, 0x8b, - 0x24, 0x7c, 0x8c, 0x5c, 0xc8, 0xfa, 0xd8, 0xfc, 0xd8, 0xa3, 0xdb, 0xe6, 0xd0, 0xa1, 0x98, 0x55, - 0x62, 0x56, 0xd3, 0xa7, 0x53, 0x7a, 0x36, 0x51, 0x16, 0xf8, 0x3b, 0x18, 0xd7, 0x2a, 0x1a, 0xe0, - 0xe3, 0x6b, 0x1e, 0xdd, 0xde, 0x0c, 0x16, 0x3f, 0x89, 0x90, 0x62, 0x83, 0xe0, 0x0d, 0xbd, 0xd4, - 0xff, 0x7e, 0xe7, 0xff, 0x4c, 0x84, 0x9c, 0x66, 0x11, 0xaf, 0xfd, 0xbc, 0xf7, 0x5f, 0x84, 0xd4, - 0x96, 0x45, 0x9c, 0xf0, 0x5b, 0xed, 0xff, 0x2f, 0x6d, 0x33, 0x41, 0x83, 0xd3, 0x52, 0x0f, 0x27, - 0x8a, 0x68, 0x30, 0x12, 0xba, 0x08, 0xe9, 0x36, 0xf6, 0xa9, 0xe3, 0xd3, 0xf0, 0x53, 0xed, 0x70, - 0x3e, 0x7b, 0xe2, 0x1a, 0x07, 0x1a, 0x11, 0xa3, 0x68, 0x42, 0x36, 0x7e, 0x80, 0x2e, 0x40, 0x8a, - 0x3a, 0x3b, 0xf4, 0xa5, 0x91, 0xc4, 0xc7, 0xd6, 0xba, 0x60, 0x30, 0xc2, 0xea, 0x91, 0xf0, 0xb3, - 0x2f, 0x1d, 0x2a, 0x85, 0xdf, 0x75, 0xa7, 0xbf, 0x11, 0x01, 0xf6, 0x3d, 0x40, 0x32, 0xcc, 0xe8, - 0x1b, 0x8d, 0xd6, 0x75, 0x49, 0x90, 0x8f, 0x8c, 0xc6, 0x6a, 0x86, 0x6f, 0xeb, 0xdd, 0x1e, 0xdd, - 0x45, 0xc7, 0x21, 0x79, 0x5d, 0x6f, 0x4a, 0xa2, 0x9c, 0x1b, 0x8d, 0xd5, 0x79, 0x7e, 0x72, 0xdd, - 0x21, 0xa8, 0x00, 0xe9, 0xb2, 0xd6, 0x6c, 0x95, 0xab, 0x35, 0x29, 0x21, 0x1f, 0x1d, 0x8d, 0xd5, - 0x1c, 0x3f, 0x2b, 0x87, 0xa5, 0x7c, 0x0c, 0x12, 0xb5, 0xba, 0x94, 0x94, 0xb3, 0xa3, 0xb1, 0x3a, - 0xc7, 0x8f, 0x6a, 0x18, 0x9d, 0x82, 0x6c, 0xad, 0x6e, 0x5e, 0xab, 0xb6, 0xd6, 0xcd, 0x4d, 0xbd, - 0x55, 0x97, 0x52, 0xf2, 0xb1, 0xd1, 0x58, 0x95, 0xa2, 0xf3, 0xa8, 0xbe, 0xe4, 0xec, 0xa7, 0x5f, - 0x15, 0x84, 0xfb, 0xf7, 0x0a, 0xc2, 0xb7, 0xf7, 0x0a, 0xc2, 0xe9, 0xdf, 0x45, 0xc8, 0x1f, 0x6c, - 0xe8, 0x41, 0x58, 0xb5, 0xea, 0x55, 0x49, 0xe0, 0x61, 0xf1, 0xcd, 0x9a, 0xd7, 0x41, 0x67, 0x20, - 0x5f, 0xd1, 0x1b, 0xf5, 0x66, 0xb5, 0x65, 0x36, 0x74, 0xa3, 0x5a, 0xaf, 0x48, 0xa2, 0x7c, 0x62, - 0x34, 0x56, 0x17, 0x38, 0x24, 0x6c, 0x57, 0x0d, 0xa7, 0xef, 0x61, 0x1b, 0xbd, 0x03, 0xb9, 0xcd, - 0x7a, 0xab, 0x5a, 0xbb, 0x1c, 0x61, 0x13, 0xf2, 0xf1, 0xd1, 0x58, 0x45, 0x1c, 0xbb, 0xc9, 0x1a, - 0x48, 0x08, 0x3d, 0x09, 0xb3, 0x8d, 0x72, 0xb3, 0xa9, 0x57, 0xa4, 0xa4, 0x2c, 0x8d, 0xc6, 0x6a, - 0x96, 0x63, 0x1a, 0x16, 0x21, 0x8e, 0x8d, 0x54, 0x98, 0x33, 0xf4, 0x2b, 0xfa, 0x5a, 0x4b, 0xaf, - 0x48, 0x29, 0x19, 0x8d, 0xc6, 0x6a, 0x3e, 0x1c, 0x3c, 0xce, 0x4d, 0xa7, 0x4d, 0x1d, 0xc6, 0xbf, - 0x54, 0xae, 0x5e, 0xd5, 0x2b, 0xd2, 0x4c, 0x9c, 0x7f, 0xc9, 0xf2, 0x3a, 0x8e, 0x7d, 0x30, 0x5d, - 0xad, 0xf6, 0xe0, 0x49, 0x41, 0x78, 0xf4, 0xa4, 0x20, 0xdc, 0xde, 0x2b, 0x08, 0x0f, 0xf6, 0x0a, - 0xe2, 0xc3, 0xbd, 0x82, 0xf8, 0xeb, 0x5e, 0x41, 0xbc, 0xf3, 0xb4, 0x20, 0x3c, 0x7c, 0x5a, 0x10, - 0x1e, 0x3d, 0x2d, 0x08, 0x1f, 0xbe, 0xbc, 0x53, 0xc7, 0xfe, 0x67, 0xda, 0x9a, 0x65, 0x8d, 0xf2, - 0xfc, 0x5f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xb4, 0xd5, 0x14, 0x59, 0x49, 0x0d, 0x00, 0x00, +func init() { proto.RegisterFile("x/gov/types/types.proto", fileDescriptor_a5ae5e91b5b3fb03) } + +var fileDescriptor_a5ae5e91b5b3fb03 = []byte{ + // 1208 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x57, 0xcf, 0x8b, 0xdb, 0x46, + 0x1b, 0x96, 0x6c, 0xef, 0x7a, 0xf3, 0xfa, 0x47, 0x94, 0xd9, 0x7c, 0xc9, 0x22, 0x3e, 0x24, 0xd5, + 0x2d, 0x61, 0x9b, 0x10, 0x6d, 0xb3, 0x39, 0x04, 0x36, 0x50, 0x6a, 0xc5, 0x4a, 0xe2, 0x90, 0xb5, + 0x8d, 0x6c, 0x36, 0xa4, 0x50, 0x84, 0xd6, 0x52, 0xbc, 0x4a, 0x6c, 0x8d, 0xf1, 0x8c, 0xdd, 0xdd, + 0x5b, 0x4e, 0xa5, 0xf5, 0x29, 0x14, 0x0a, 0xbd, 0x18, 0x02, 0xcd, 0x21, 0x94, 0x1e, 0x7a, 0xe8, + 0x5f, 0xd0, 0x53, 0xe8, 0xa5, 0x39, 0x86, 0x52, 0x9c, 0x66, 0x73, 0x2b, 0x3d, 0x05, 0x7a, 0xe9, + 0xa9, 0x68, 0x46, 0xca, 0x6a, 0xc9, 0x26, 0xc4, 0x24, 0xa5, 0xd0, 0xcb, 0xb2, 0x9a, 0x79, 0x9e, + 0x67, 0xde, 0xf7, 0x99, 0x57, 0x8f, 0x76, 0xe1, 0xf8, 0xf6, 0x4a, 0x07, 0x8f, 0x56, 0xe8, 0x4e, + 0xdf, 0x23, 0xfc, 0xa7, 0xde, 0x1f, 0x60, 0x8a, 0xd1, 0x62, 0x1b, 0x93, 0x1e, 0x26, 0x36, 0x71, + 0x6f, 0xe9, 0xdb, 0x7a, 0x07, 0x8f, 0xf4, 0xd1, 0x19, 0xf9, 0xc8, 0x0b, 0x38, 0xf9, 0x04, 0xdd, + 0xf2, 0x07, 0xae, 0xdd, 0x77, 0x06, 0x74, 0x67, 0x85, 0x2d, 0xad, 0x74, 0x70, 0x07, 0xef, 0xfd, + 0x16, 0xe1, 0x4e, 0xbd, 0x88, 0xe3, 0x27, 0x9c, 0x4e, 0x3e, 0x44, 0x60, 0xb5, 0x83, 0x71, 0xa7, + 0xeb, 0x71, 0xdc, 0xe6, 0xf0, 0xc6, 0x0a, 0xf5, 0x7b, 0x1e, 0xa1, 0x4e, 0xaf, 0xcf, 0x01, 0xa5, + 0x3f, 0x45, 0xf8, 0xdf, 0x3a, 0xe9, 0x34, 0x87, 0x9b, 0x3d, 0x9f, 0x36, 0x06, 0xb8, 0x8f, 0x89, + 0xd3, 0x35, 0x1c, 0xe2, 0xa1, 0xcf, 0x44, 0x28, 0xfa, 0x01, 0xf5, 0x9d, 0xae, 0xed, 0x7a, 0x7d, + 0x4c, 0x7c, 0xba, 0x24, 0x6a, 0xe9, 0xe5, 0xdc, 0xea, 0xa2, 0x9e, 0xe8, 0x68, 0x74, 0x46, 0xbf, + 0x80, 0xfd, 0xc0, 0xb8, 0xf2, 0x60, 0xaa, 0x0a, 0xcf, 0xa6, 0xea, 0xb1, 0x1d, 0xa7, 0xd7, 0x5d, + 0x2b, 0xf9, 0x81, 0x9f, 0x64, 0x96, 0xbe, 0x7d, 0xac, 0x2e, 0x77, 0x7c, 0xba, 0x35, 0xdc, 0xd4, + 0xdb, 0xb8, 0x17, 0xd5, 0x18, 0xd7, 0x4d, 0xdc, 0x5b, 0x91, 0x13, 0xa1, 0x14, 0xb1, 0x0a, 0xfc, + 0xd8, 0x0a, 0xe7, 0xa2, 0x75, 0x58, 0xe8, 0xb3, 0xc2, 0xbc, 0xc1, 0x52, 0x4a, 0x13, 0x97, 0xf3, + 0xc6, 0x99, 0xbf, 0xa6, 0xea, 0xe9, 0xd7, 0x90, 0x2b, 0xb7, 0xdb, 0x65, 0xd7, 0x1d, 0x78, 0x84, + 0x58, 0xcf, 0x25, 0xd6, 0x32, 0xb7, 0x7f, 0xd5, 0xc4, 0xd2, 0x97, 0x29, 0x80, 0x75, 0xd2, 0x89, + 0xcf, 0x68, 0x41, 0xae, 0x1f, 0x35, 0x6f, 0xfb, 0xee, 0x92, 0xa8, 0x89, 0xcb, 0x19, 0xe3, 0xec, + 0xee, 0x54, 0x85, 0xd8, 0x93, 0x6a, 0xe5, 0xf7, 0xa9, 0x9a, 0x04, 0x3d, 0x9b, 0xaa, 0x88, 0x37, + 0x9b, 0x58, 0x2c, 0x59, 0x10, 0x3f, 0x55, 0x5d, 0x54, 0x87, 0x43, 0x91, 0x01, 0xf8, 0x0d, 0x4a, + 0xdf, 0xd3, 0x40, 0x9f, 0xc0, 0xbc, 0xd3, 0xc3, 0xc3, 0x80, 0x2e, 0xa5, 0x5f, 0x7e, 0x15, 0x1f, + 0x84, 0x57, 0x31, 0x93, 0xe1, 0x91, 0x68, 0xe9, 0x89, 0x08, 0xd9, 0x75, 0xd2, 0xd9, 0xc0, 0xd4, + 0xfb, 0x87, 0x1c, 0xb9, 0x04, 0x73, 0x23, 0x4c, 0xdf, 0xe4, 0x22, 0x39, 0x1f, 0x9d, 0x83, 0x79, + 0xdc, 0xa7, 0x3e, 0x0e, 0x96, 0xd2, 0x9a, 0xb8, 0x5c, 0x5c, 0x55, 0xf5, 0x03, 0x5e, 0x33, 0x3d, + 0xec, 0xa4, 0xce, 0x60, 0x56, 0x04, 0x2f, 0x5d, 0x84, 0x7c, 0xcb, 0xdb, 0x7e, 0x3e, 0xea, 0xe8, + 0x28, 0xcc, 0x51, 0x9f, 0x76, 0x3d, 0xd6, 0xe1, 0x21, 0x8b, 0x3f, 0x20, 0x0d, 0x72, 0xae, 0x47, + 0xda, 0x03, 0x9f, 0x9f, 0x91, 0x62, 0x7b, 0xc9, 0xa5, 0xd2, 0xed, 0x14, 0x64, 0xe3, 0xe9, 0x31, + 0x0f, 0xf2, 0xea, 0xbd, 0xfd, 0x5e, 0xfd, 0x07, 0xc7, 0xe5, 0xab, 0x39, 0xc8, 0xef, 0x8b, 0x8c, + 0xb7, 0xe4, 0xc3, 0x79, 0x98, 0x27, 0xd4, 0xa1, 0x43, 0xc2, 0x4c, 0x28, 0xae, 0xbe, 0x7b, 0xe0, + 0xdd, 0xc6, 0x92, 0x4d, 0x06, 0xb5, 0x22, 0x0a, 0x6a, 0x01, 0xba, 0xe1, 0x07, 0x4e, 0xd7, 0xa6, + 0x4e, 0xb7, 0xbb, 0x63, 0x0f, 0x3c, 0x32, 0xec, 0x52, 0x36, 0x24, 0xb9, 0x55, 0xed, 0x40, 0xa1, + 0x56, 0x08, 0xb4, 0x18, 0xce, 0xc8, 0x84, 0x66, 0x58, 0x12, 0x53, 0x48, 0xac, 0x87, 0x9d, 0x11, + 0x16, 0x91, 0x76, 0x18, 0xa0, 0x4b, 0x19, 0x26, 0x27, 0xeb, 0x3c, 0x5d, 0xf5, 0x38, 0x5d, 0xf5, + 0x56, 0x9c, 0xae, 0xc6, 0x42, 0x28, 0x74, 0xe7, 0xb1, 0x2a, 0x5a, 0xc0, 0x89, 0xe1, 0x16, 0xaa, + 0x81, 0x14, 0xdd, 0x8e, 0xed, 0x05, 0x2e, 0xd7, 0x9a, 0x9b, 0x41, 0xab, 0x18, 0xb1, 0xcd, 0xc0, + 0x65, 0x7a, 0x37, 0xa1, 0x40, 0x31, 0x4d, 0x24, 0xf4, 0xfc, 0xdb, 0xbc, 0xe7, 0x3c, 0xd3, 0x8e, + 0x87, 0xbc, 0x01, 0x47, 0x46, 0x98, 0xfa, 0x41, 0xc7, 0x26, 0xd4, 0x19, 0x44, 0x46, 0x64, 0x67, + 0x28, 0xfe, 0x30, 0xa7, 0x37, 0x43, 0x36, 0xab, 0xfe, 0x2a, 0x44, 0x4b, 0x7b, 0x66, 0x2c, 0xcc, + 0xa0, 0x57, 0xe0, 0xe4, 0xc8, 0x8b, 0xb5, 0x85, 0xaf, 0xef, 0xaa, 0xe2, 0xfd, 0xbb, 0xaa, 0x58, + 0xfa, 0x31, 0x05, 0xb9, 0xe4, 0xe5, 0x7d, 0x04, 0xe9, 0x1d, 0x8f, 0xb0, 0x71, 0xcc, 0x1b, 0x7a, + 0xc8, 0xff, 0x65, 0xaa, 0x9e, 0x78, 0x0d, 0x1b, 0xaa, 0x01, 0xb5, 0x42, 0x2a, 0xba, 0x0c, 0x59, + 0x67, 0x93, 0x50, 0xc7, 0x0f, 0xa2, 0xf7, 0x72, 0x56, 0x95, 0x98, 0x8e, 0x3e, 0x84, 0x54, 0x80, + 0xd9, 0x38, 0xce, 0x2e, 0x92, 0x0a, 0x30, 0xea, 0x40, 0x3e, 0xc0, 0xf6, 0xa7, 0x3e, 0xdd, 0xb2, + 0x47, 0x1e, 0xc5, 0x6c, 0x12, 0xf3, 0x86, 0x39, 0x9b, 0xd2, 0xb3, 0xa9, 0xba, 0xc8, 0xdf, 0xc1, + 0xa4, 0x56, 0xc9, 0x82, 0x00, 0x5f, 0xf3, 0xe9, 0xd6, 0x46, 0xf8, 0xf0, 0xb3, 0x08, 0x19, 0xf6, + 0x21, 0x78, 0x4b, 0x2f, 0xf5, 0xbf, 0x9f, 0xfc, 0x5f, 0x88, 0x50, 0x30, 0x1c, 0xe2, 0xb7, 0x9f, + 0x67, 0xff, 0x79, 0xc8, 0x6c, 0x3a, 0x84, 0x47, 0x7f, 0x6e, 0xf5, 0x9d, 0x57, 0xc6, 0x4c, 0x18, + 0x70, 0x46, 0xe6, 0xe1, 0x54, 0x15, 0x2d, 0x46, 0x42, 0xe7, 0x21, 0xdb, 0xc6, 0x01, 0xf5, 0x02, + 0xca, 0x5a, 0x7a, 0x19, 0x9f, 0x9d, 0x78, 0x81, 0x03, 0xad, 0x98, 0x51, 0xb2, 0x21, 0x9f, 0xdc, + 0x40, 0xe7, 0x20, 0x43, 0xbd, 0x6d, 0xfa, 0xca, 0x4a, 0x92, 0x9f, 0xad, 0xcb, 0x82, 0xc5, 0x08, + 0x6b, 0x87, 0xc3, 0xbf, 0x66, 0x7e, 0xfa, 0xe1, 0x74, 0x36, 0x52, 0x32, 0xe6, 0x20, 0x4d, 0x86, + 0xbd, 0x93, 0xdf, 0x89, 0x00, 0x7b, 0x1e, 0x20, 0x19, 0xe6, 0xcc, 0xf5, 0x46, 0xeb, 0xba, 0x24, + 0xc8, 0x87, 0xc7, 0x13, 0x2d, 0xc7, 0x97, 0xcd, 0x5e, 0x9f, 0xee, 0xa0, 0x63, 0x90, 0xbe, 0x6e, + 0x36, 0x25, 0x51, 0x2e, 0x8c, 0x27, 0xda, 0x21, 0xbe, 0x73, 0xdd, 0x23, 0x48, 0x81, 0x6c, 0xd9, + 0x68, 0xb6, 0xca, 0xd5, 0x9a, 0x94, 0x92, 0x8f, 0x8c, 0x27, 0x5a, 0x81, 0xef, 0x95, 0xa3, 0x51, + 0x3e, 0x0a, 0xa9, 0x5a, 0x5d, 0x4a, 0xcb, 0xf9, 0xf1, 0x44, 0x5b, 0xe0, 0x5b, 0x35, 0x8c, 0x4e, + 0x40, 0xbe, 0x56, 0xb7, 0xaf, 0x55, 0x5b, 0x97, 0xed, 0x0d, 0xb3, 0x55, 0x97, 0x32, 0xf2, 0xd1, + 0xf1, 0x44, 0x93, 0xe2, 0xfd, 0x78, 0xbe, 0xe4, 0xfc, 0xe7, 0xdf, 0x28, 0xc2, 0xfd, 0x7b, 0x8a, + 0xf0, 0xfd, 0x3d, 0x45, 0x38, 0xf9, 0x87, 0x08, 0xc5, 0xfd, 0x81, 0x1e, 0x96, 0x55, 0xab, 0x5e, + 0x95, 0x04, 0x5e, 0x16, 0x5f, 0xac, 0xf9, 0x5d, 0x74, 0x0a, 0x8a, 0x15, 0xb3, 0x51, 0x6f, 0x56, + 0x5b, 0x76, 0xc3, 0xb4, 0xaa, 0xf5, 0x8a, 0x24, 0xca, 0xc7, 0xc7, 0x13, 0x6d, 0x91, 0x43, 0xa2, + 0xb8, 0x6a, 0x78, 0x03, 0x1f, 0xbb, 0xe8, 0x7d, 0x28, 0x6c, 0xd4, 0x5b, 0xd5, 0xda, 0xa5, 0x18, + 0x9b, 0x92, 0x8f, 0x8d, 0x27, 0x1a, 0xe2, 0xd8, 0x0d, 0x16, 0x20, 0x11, 0xf4, 0xff, 0x30, 0xdf, + 0x28, 0x37, 0x9b, 0x66, 0x45, 0x4a, 0xcb, 0xd2, 0x78, 0xa2, 0xe5, 0x39, 0xa6, 0xe1, 0x10, 0xe2, + 0xb9, 0x48, 0x83, 0x05, 0xcb, 0xbc, 0x62, 0x5e, 0x68, 0x99, 0x15, 0x29, 0x23, 0xa3, 0xf1, 0x44, + 0x2b, 0x46, 0x1f, 0x1e, 0xef, 0xa6, 0xd7, 0xa6, 0x1e, 0xe3, 0x5f, 0x2c, 0x57, 0xaf, 0x9a, 0x15, + 0x69, 0x2e, 0xc9, 0xbf, 0xe8, 0xf8, 0x5d, 0xcf, 0xdd, 0xdf, 0xae, 0x51, 0x7b, 0xf0, 0x44, 0x11, + 0x1e, 0x3d, 0x51, 0x84, 0xdb, 0xbb, 0x8a, 0xf0, 0x60, 0x57, 0x11, 0x1f, 0xee, 0x2a, 0xe2, 0x6f, + 0xbb, 0x8a, 0x78, 0xe7, 0xa9, 0x22, 0x3c, 0x7c, 0xaa, 0x08, 0x8f, 0x9e, 0x2a, 0xc2, 0xc7, 0xaf, + 0x4e, 0xea, 0xc4, 0xff, 0x1b, 0x9b, 0xf3, 0x2c, 0x28, 0xcf, 0xfe, 0x1d, 0x00, 0x00, 0xff, 0xff, + 0xaa, 0x0c, 0xd1, 0xcc, 0x85, 0x0c, 0x00, 0x00, } type ProposalBaseFace interface { @@ -772,38 +683,6 @@ func NewProposalBaseFromFace(that ProposalBaseFace) *ProposalBase { return this } -func (this *MsgCommon) GetMsg() github_com_cosmos_cosmos_sdk_types.Msg { - if x := this.GetGovDeposit(); x != nil { - return x - } - if x := this.GetGovVote(); x != nil { - return x - } - return nil -} - -func (this *MsgCommon) SetMsg(value github_com_cosmos_cosmos_sdk_types.Msg) error { - if value == nil { - this.Sum = nil - return nil - } - switch vt := value.(type) { - case *MsgDeposit: - this.Sum = &MsgCommon_GovDeposit{vt} - return nil - case MsgDeposit: - this.Sum = &MsgCommon_GovDeposit{&vt} - return nil - case *MsgVote: - this.Sum = &MsgCommon_GovVote{vt} - return nil - case MsgVote: - this.Sum = &MsgCommon_GovVote{&vt} - return nil - } - return fmt.Errorf("can't encode value of type %T as message MsgCommon", value) -} - func (this *BasicContent) GetContent() Content { if x := this.GetText(); x != nil { return x @@ -827,80 +706,6 @@ func (this *BasicContent) SetContent(value Content) error { return fmt.Errorf("can't encode value of type %T as message BasicContent", value) } -func (m *MsgCommon) 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 *MsgCommon) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MsgCommon) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Sum != nil { - { - size := m.Sum.Size() - i -= size - if _, err := m.Sum.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - } - } - return len(dAtA) - i, nil -} - -func (m *MsgCommon_GovDeposit) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MsgCommon_GovDeposit) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - if m.GovDeposit != nil { - { - size, err := m.GovDeposit.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintCodec(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} -func (m *MsgCommon_GovVote) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MsgCommon_GovVote) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - if m.GovVote != nil { - { - size, err := m.GovVote.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintCodec(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - } - return len(dAtA) - i, nil -} func (m *MsgSubmitProposalBase) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -924,7 +729,7 @@ func (m *MsgSubmitProposalBase) MarshalToSizedBuffer(dAtA []byte) (int, error) { if len(m.Proposer) > 0 { i -= len(m.Proposer) copy(dAtA[i:], m.Proposer) - i = encodeVarintCodec(dAtA, i, uint64(len(m.Proposer))) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Proposer))) i-- dAtA[i] = 0x12 } @@ -936,7 +741,7 @@ func (m *MsgSubmitProposalBase) MarshalToSizedBuffer(dAtA []byte) (int, error) { return 0, err } i -= size - i = encodeVarintCodec(dAtA, i, uint64(size)) + i = encodeVarintTypes(dAtA, i, uint64(size)) } i-- dAtA[i] = 0xa @@ -973,7 +778,7 @@ func (m *MsgDeposit) MarshalToSizedBuffer(dAtA []byte) (int, error) { return 0, err } i -= size - i = encodeVarintCodec(dAtA, i, uint64(size)) + i = encodeVarintTypes(dAtA, i, uint64(size)) } i-- dAtA[i] = 0x1a @@ -982,12 +787,12 @@ func (m *MsgDeposit) MarshalToSizedBuffer(dAtA []byte) (int, error) { if len(m.Depositor) > 0 { i -= len(m.Depositor) copy(dAtA[i:], m.Depositor) - i = encodeVarintCodec(dAtA, i, uint64(len(m.Depositor))) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Depositor))) i-- dAtA[i] = 0x12 } if m.ProposalID != 0 { - i = encodeVarintCodec(dAtA, i, uint64(m.ProposalID)) + i = encodeVarintTypes(dAtA, i, uint64(m.ProposalID)) i-- dAtA[i] = 0x8 } @@ -1015,19 +820,19 @@ func (m *MsgVote) MarshalToSizedBuffer(dAtA []byte) (int, error) { var l int _ = l if m.Option != 0 { - i = encodeVarintCodec(dAtA, i, uint64(m.Option)) + i = encodeVarintTypes(dAtA, i, uint64(m.Option)) i-- dAtA[i] = 0x18 } if len(m.Voter) > 0 { i -= len(m.Voter) copy(dAtA[i:], m.Voter) - i = encodeVarintCodec(dAtA, i, uint64(len(m.Voter))) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Voter))) i-- dAtA[i] = 0x12 } if m.ProposalID != 0 { - i = encodeVarintCodec(dAtA, i, uint64(m.ProposalID)) + i = encodeVarintTypes(dAtA, i, uint64(m.ProposalID)) i-- dAtA[i] = 0x8 } @@ -1057,14 +862,14 @@ func (m *TextProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { if len(m.Description) > 0 { i -= len(m.Description) copy(dAtA[i:], m.Description) - i = encodeVarintCodec(dAtA, i, uint64(len(m.Description))) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Description))) i-- dAtA[i] = 0x12 } if len(m.Title) > 0 { i -= len(m.Title) copy(dAtA[i:], m.Title) - i = encodeVarintCodec(dAtA, i, uint64(len(m.Title))) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Title))) i-- dAtA[i] = 0xa } @@ -1099,7 +904,7 @@ func (m *Deposit) MarshalToSizedBuffer(dAtA []byte) (int, error) { return 0, err } i -= size - i = encodeVarintCodec(dAtA, i, uint64(size)) + i = encodeVarintTypes(dAtA, i, uint64(size)) } i-- dAtA[i] = 0x1a @@ -1108,12 +913,12 @@ func (m *Deposit) MarshalToSizedBuffer(dAtA []byte) (int, error) { if len(m.Depositor) > 0 { i -= len(m.Depositor) copy(dAtA[i:], m.Depositor) - i = encodeVarintCodec(dAtA, i, uint64(len(m.Depositor))) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Depositor))) i-- dAtA[i] = 0x12 } if m.ProposalID != 0 { - i = encodeVarintCodec(dAtA, i, uint64(m.ProposalID)) + i = encodeVarintTypes(dAtA, i, uint64(m.ProposalID)) i-- dAtA[i] = 0x8 } @@ -1140,20 +945,20 @@ func (m *ProposalBase) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - n3, err3 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.VotingEndTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.VotingEndTime):]) - if err3 != nil { - return 0, err3 + n1, err1 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.VotingEndTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.VotingEndTime):]) + if err1 != nil { + return 0, err1 } - i -= n3 - i = encodeVarintCodec(dAtA, i, uint64(n3)) + i -= n1 + i = encodeVarintTypes(dAtA, i, uint64(n1)) i-- dAtA[i] = 0x42 - n4, err4 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.VotingStartTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.VotingStartTime):]) - if err4 != nil { - return 0, err4 + n2, err2 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.VotingStartTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.VotingStartTime):]) + if err2 != nil { + return 0, err2 } - i -= n4 - i = encodeVarintCodec(dAtA, i, uint64(n4)) + i -= n2 + i = encodeVarintTypes(dAtA, i, uint64(n2)) i-- dAtA[i] = 0x3a if len(m.TotalDeposit) > 0 { @@ -1164,26 +969,26 @@ func (m *ProposalBase) MarshalToSizedBuffer(dAtA []byte) (int, error) { return 0, err } i -= size - i = encodeVarintCodec(dAtA, i, uint64(size)) + i = encodeVarintTypes(dAtA, i, uint64(size)) } i-- dAtA[i] = 0x32 } } - n5, err5 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.DepositEndTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.DepositEndTime):]) - if err5 != nil { - return 0, err5 + n3, err3 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.DepositEndTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.DepositEndTime):]) + if err3 != nil { + return 0, err3 } - i -= n5 - i = encodeVarintCodec(dAtA, i, uint64(n5)) + i -= n3 + i = encodeVarintTypes(dAtA, i, uint64(n3)) i-- dAtA[i] = 0x2a - n6, err6 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.SubmitTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.SubmitTime):]) - if err6 != nil { - return 0, err6 + n4, err4 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.SubmitTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.SubmitTime):]) + if err4 != nil { + return 0, err4 } - i -= n6 - i = encodeVarintCodec(dAtA, i, uint64(n6)) + i -= n4 + i = encodeVarintTypes(dAtA, i, uint64(n4)) i-- dAtA[i] = 0x22 { @@ -1192,17 +997,17 @@ func (m *ProposalBase) MarshalToSizedBuffer(dAtA []byte) (int, error) { return 0, err } i -= size - i = encodeVarintCodec(dAtA, i, uint64(size)) + i = encodeVarintTypes(dAtA, i, uint64(size)) } i-- dAtA[i] = 0x1a if m.Status != 0 { - i = encodeVarintCodec(dAtA, i, uint64(m.Status)) + i = encodeVarintTypes(dAtA, i, uint64(m.Status)) i-- dAtA[i] = 0x10 } if m.ProposalID != 0 { - i = encodeVarintCodec(dAtA, i, uint64(m.ProposalID)) + i = encodeVarintTypes(dAtA, i, uint64(m.ProposalID)) i-- dAtA[i] = 0x8 } @@ -1235,7 +1040,7 @@ func (m *TallyResult) MarshalToSizedBuffer(dAtA []byte) (int, error) { if _, err := m.NoWithVeto.MarshalTo(dAtA[i:]); err != nil { return 0, err } - i = encodeVarintCodec(dAtA, i, uint64(size)) + i = encodeVarintTypes(dAtA, i, uint64(size)) } i-- dAtA[i] = 0x22 @@ -1245,7 +1050,7 @@ func (m *TallyResult) MarshalToSizedBuffer(dAtA []byte) (int, error) { if _, err := m.No.MarshalTo(dAtA[i:]); err != nil { return 0, err } - i = encodeVarintCodec(dAtA, i, uint64(size)) + i = encodeVarintTypes(dAtA, i, uint64(size)) } i-- dAtA[i] = 0x1a @@ -1255,7 +1060,7 @@ func (m *TallyResult) MarshalToSizedBuffer(dAtA []byte) (int, error) { if _, err := m.Abstain.MarshalTo(dAtA[i:]); err != nil { return 0, err } - i = encodeVarintCodec(dAtA, i, uint64(size)) + i = encodeVarintTypes(dAtA, i, uint64(size)) } i-- dAtA[i] = 0x12 @@ -1265,7 +1070,7 @@ func (m *TallyResult) MarshalToSizedBuffer(dAtA []byte) (int, error) { if _, err := m.Yes.MarshalTo(dAtA[i:]); err != nil { return 0, err } - i = encodeVarintCodec(dAtA, i, uint64(size)) + i = encodeVarintTypes(dAtA, i, uint64(size)) } i-- dAtA[i] = 0xa @@ -1293,19 +1098,19 @@ func (m *Vote) MarshalToSizedBuffer(dAtA []byte) (int, error) { var l int _ = l if m.Option != 0 { - i = encodeVarintCodec(dAtA, i, uint64(m.Option)) + i = encodeVarintTypes(dAtA, i, uint64(m.Option)) i-- dAtA[i] = 0x18 } if len(m.Voter) > 0 { i -= len(m.Voter) copy(dAtA[i:], m.Voter) - i = encodeVarintCodec(dAtA, i, uint64(len(m.Voter))) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Voter))) i-- dAtA[i] = 0x12 } if m.ProposalID != 0 { - i = encodeVarintCodec(dAtA, i, uint64(m.ProposalID)) + i = encodeVarintTypes(dAtA, i, uint64(m.ProposalID)) i-- dAtA[i] = 0x8 } @@ -1339,7 +1144,7 @@ func (m *BasicProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { return 0, err } i -= size - i = encodeVarintCodec(dAtA, i, uint64(size)) + i = encodeVarintTypes(dAtA, i, uint64(size)) } i-- dAtA[i] = 0x12 @@ -1351,7 +1156,7 @@ func (m *BasicProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { return 0, err } i -= size - i = encodeVarintCodec(dAtA, i, uint64(size)) + i = encodeVarintTypes(dAtA, i, uint64(size)) } i-- dAtA[i] = 0xa @@ -1405,15 +1210,15 @@ func (m *BasicContent_Text) MarshalToSizedBuffer(dAtA []byte) (int, error) { return 0, err } i -= size - i = encodeVarintCodec(dAtA, i, uint64(size)) + i = encodeVarintTypes(dAtA, i, uint64(size)) } i-- dAtA[i] = 0xa } return len(dAtA) - i, nil } -func encodeVarintCodec(dAtA []byte, offset int, v uint64) int { - offset -= sovCodec(v) +func encodeVarintTypes(dAtA []byte, offset int, v uint64) int { + offset -= sovTypes(v) base := offset for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) @@ -1423,42 +1228,6 @@ func encodeVarintCodec(dAtA []byte, offset int, v uint64) int { dAtA[offset] = uint8(v) return base } -func (m *MsgCommon) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Sum != nil { - n += m.Sum.Size() - } - return n -} - -func (m *MsgCommon_GovDeposit) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.GovDeposit != nil { - l = m.GovDeposit.Size() - n += 1 + l + sovCodec(uint64(l)) - } - return n -} -func (m *MsgCommon_GovVote) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.GovVote != nil { - l = m.GovVote.Size() - n += 1 + l + sovCodec(uint64(l)) - } - return n -} func (m *MsgSubmitProposalBase) Size() (n int) { if m == nil { return 0 @@ -1468,12 +1237,12 @@ func (m *MsgSubmitProposalBase) Size() (n int) { if len(m.IntialDeposit) > 0 { for _, e := range m.IntialDeposit { l = e.Size() - n += 1 + l + sovCodec(uint64(l)) + n += 1 + l + sovTypes(uint64(l)) } } l = len(m.Proposer) if l > 0 { - n += 1 + l + sovCodec(uint64(l)) + n += 1 + l + sovTypes(uint64(l)) } return n } @@ -1485,16 +1254,16 @@ func (m *MsgDeposit) Size() (n int) { var l int _ = l if m.ProposalID != 0 { - n += 1 + sovCodec(uint64(m.ProposalID)) + n += 1 + sovTypes(uint64(m.ProposalID)) } l = len(m.Depositor) if l > 0 { - n += 1 + l + sovCodec(uint64(l)) + n += 1 + l + sovTypes(uint64(l)) } if len(m.Amount) > 0 { for _, e := range m.Amount { l = e.Size() - n += 1 + l + sovCodec(uint64(l)) + n += 1 + l + sovTypes(uint64(l)) } } return n @@ -1507,14 +1276,14 @@ func (m *MsgVote) Size() (n int) { var l int _ = l if m.ProposalID != 0 { - n += 1 + sovCodec(uint64(m.ProposalID)) + n += 1 + sovTypes(uint64(m.ProposalID)) } l = len(m.Voter) if l > 0 { - n += 1 + l + sovCodec(uint64(l)) + n += 1 + l + sovTypes(uint64(l)) } if m.Option != 0 { - n += 1 + sovCodec(uint64(m.Option)) + n += 1 + sovTypes(uint64(m.Option)) } return n } @@ -1527,11 +1296,11 @@ func (m *TextProposal) Size() (n int) { _ = l l = len(m.Title) if l > 0 { - n += 1 + l + sovCodec(uint64(l)) + n += 1 + l + sovTypes(uint64(l)) } l = len(m.Description) if l > 0 { - n += 1 + l + sovCodec(uint64(l)) + n += 1 + l + sovTypes(uint64(l)) } return n } @@ -1543,16 +1312,16 @@ func (m *Deposit) Size() (n int) { var l int _ = l if m.ProposalID != 0 { - n += 1 + sovCodec(uint64(m.ProposalID)) + n += 1 + sovTypes(uint64(m.ProposalID)) } l = len(m.Depositor) if l > 0 { - n += 1 + l + sovCodec(uint64(l)) + n += 1 + l + sovTypes(uint64(l)) } if len(m.Amount) > 0 { for _, e := range m.Amount { l = e.Size() - n += 1 + l + sovCodec(uint64(l)) + n += 1 + l + sovTypes(uint64(l)) } } return n @@ -1565,27 +1334,27 @@ func (m *ProposalBase) Size() (n int) { var l int _ = l if m.ProposalID != 0 { - n += 1 + sovCodec(uint64(m.ProposalID)) + n += 1 + sovTypes(uint64(m.ProposalID)) } if m.Status != 0 { - n += 1 + sovCodec(uint64(m.Status)) + n += 1 + sovTypes(uint64(m.Status)) } l = m.FinalTallyResult.Size() - n += 1 + l + sovCodec(uint64(l)) + n += 1 + l + sovTypes(uint64(l)) l = github_com_gogo_protobuf_types.SizeOfStdTime(m.SubmitTime) - n += 1 + l + sovCodec(uint64(l)) + n += 1 + l + sovTypes(uint64(l)) l = github_com_gogo_protobuf_types.SizeOfStdTime(m.DepositEndTime) - n += 1 + l + sovCodec(uint64(l)) + n += 1 + l + sovTypes(uint64(l)) if len(m.TotalDeposit) > 0 { for _, e := range m.TotalDeposit { l = e.Size() - n += 1 + l + sovCodec(uint64(l)) + n += 1 + l + sovTypes(uint64(l)) } } l = github_com_gogo_protobuf_types.SizeOfStdTime(m.VotingStartTime) - n += 1 + l + sovCodec(uint64(l)) + n += 1 + l + sovTypes(uint64(l)) l = github_com_gogo_protobuf_types.SizeOfStdTime(m.VotingEndTime) - n += 1 + l + sovCodec(uint64(l)) + n += 1 + l + sovTypes(uint64(l)) return n } @@ -1596,13 +1365,13 @@ func (m *TallyResult) Size() (n int) { var l int _ = l l = m.Yes.Size() - n += 1 + l + sovCodec(uint64(l)) + n += 1 + l + sovTypes(uint64(l)) l = m.Abstain.Size() - n += 1 + l + sovCodec(uint64(l)) + n += 1 + l + sovTypes(uint64(l)) l = m.No.Size() - n += 1 + l + sovCodec(uint64(l)) + n += 1 + l + sovTypes(uint64(l)) l = m.NoWithVeto.Size() - n += 1 + l + sovCodec(uint64(l)) + n += 1 + l + sovTypes(uint64(l)) return n } @@ -1613,14 +1382,14 @@ func (m *Vote) Size() (n int) { var l int _ = l if m.ProposalID != 0 { - n += 1 + sovCodec(uint64(m.ProposalID)) + n += 1 + sovTypes(uint64(m.ProposalID)) } l = len(m.Voter) if l > 0 { - n += 1 + l + sovCodec(uint64(l)) + n += 1 + l + sovTypes(uint64(l)) } if m.Option != 0 { - n += 1 + sovCodec(uint64(m.Option)) + n += 1 + sovTypes(uint64(m.Option)) } return n } @@ -1633,11 +1402,11 @@ func (m *BasicProposal) Size() (n int) { _ = l if m.ProposalBase != nil { l = m.ProposalBase.Size() - n += 1 + l + sovCodec(uint64(l)) + n += 1 + l + sovTypes(uint64(l)) } if m.Content != nil { l = m.Content.Size() - n += 1 + l + sovCodec(uint64(l)) + n += 1 + l + sovTypes(uint64(l)) } return n } @@ -1662,46 +1431,16 @@ func (m *BasicContent_Text) Size() (n int) { _ = l if m.Text != nil { l = m.Text.Size() - n += 1 + l + sovCodec(uint64(l)) + n += 1 + l + sovTypes(uint64(l)) } return n } -func sovCodec(x uint64) (n int) { +func sovTypes(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } -func sozCodec(x uint64) (n int) { - return sovCodec(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (this *MsgCommon) String() string { - if this == nil { - return "nil" - } - s := strings.Join([]string{`&MsgCommon{`, - `Sum:` + fmt.Sprintf("%v", this.Sum) + `,`, - `}`, - }, "") - return s -} -func (this *MsgCommon_GovDeposit) String() string { - if this == nil { - return "nil" - } - s := strings.Join([]string{`&MsgCommon_GovDeposit{`, - `GovDeposit:` + strings.Replace(fmt.Sprintf("%v", this.GovDeposit), "MsgDeposit", "MsgDeposit", 1) + `,`, - `}`, - }, "") - return s -} -func (this *MsgCommon_GovVote) String() string { - if this == nil { - return "nil" - } - s := strings.Join([]string{`&MsgCommon_GovVote{`, - `GovVote:` + strings.Replace(fmt.Sprintf("%v", this.GovVote), "MsgVote", "MsgVote", 1) + `,`, - `}`, - }, "") - return s +func sozTypes(x uint64) (n int) { + return sovTypes(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } func (this *MsgSubmitProposalBase) String() string { if this == nil { @@ -1739,7 +1478,7 @@ func (this *BasicContent_Text) String() string { }, "") return s } -func valueToStringCodec(v interface{}) string { +func valueToStringTypes(v interface{}) string { rv := reflect.ValueOf(v) if rv.IsNil() { return "nil" @@ -1747,129 +1486,6 @@ func valueToStringCodec(v interface{}) string { pv := reflect.Indirect(rv).Interface() return fmt.Sprintf("*%v", pv) } -func (m *MsgCommon) 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 ErrIntOverflowCodec - } - 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: MsgCommon: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgCommon: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field GovDeposit", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCodec - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthCodec - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthCodec - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - v := &MsgDeposit{} - if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - m.Sum = &MsgCommon_GovDeposit{v} - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field GovVote", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCodec - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthCodec - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthCodec - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - v := &MsgVote{} - if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - m.Sum = &MsgCommon_GovVote{v} - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipCodec(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthCodec - } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthCodec - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} func (m *MsgSubmitProposalBase) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -1878,7 +1494,7 @@ func (m *MsgSubmitProposalBase) Unmarshal(dAtA []byte) error { var wire uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCodec + return ErrIntOverflowTypes } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -1906,7 +1522,7 @@ func (m *MsgSubmitProposalBase) Unmarshal(dAtA []byte) error { var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCodec + return ErrIntOverflowTypes } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -1919,11 +1535,11 @@ func (m *MsgSubmitProposalBase) Unmarshal(dAtA []byte) error { } } if msglen < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } postIndex := iNdEx + msglen if postIndex < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if postIndex > l { return io.ErrUnexpectedEOF @@ -1940,7 +1556,7 @@ func (m *MsgSubmitProposalBase) Unmarshal(dAtA []byte) error { var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCodec + return ErrIntOverflowTypes } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -1953,11 +1569,11 @@ func (m *MsgSubmitProposalBase) Unmarshal(dAtA []byte) error { } } if byteLen < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } postIndex := iNdEx + byteLen if postIndex < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if postIndex > l { return io.ErrUnexpectedEOF @@ -1969,15 +1585,15 @@ func (m *MsgSubmitProposalBase) Unmarshal(dAtA []byte) error { iNdEx = postIndex default: iNdEx = preIndex - skippy, err := skipCodec(dAtA[iNdEx:]) + skippy, err := skipTypes(dAtA[iNdEx:]) if err != nil { return err } if skippy < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if (iNdEx + skippy) < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF @@ -1999,7 +1615,7 @@ func (m *MsgDeposit) Unmarshal(dAtA []byte) error { var wire uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCodec + return ErrIntOverflowTypes } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -2027,7 +1643,7 @@ func (m *MsgDeposit) Unmarshal(dAtA []byte) error { m.ProposalID = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCodec + return ErrIntOverflowTypes } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -2046,7 +1662,7 @@ func (m *MsgDeposit) Unmarshal(dAtA []byte) error { var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCodec + return ErrIntOverflowTypes } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -2059,11 +1675,11 @@ func (m *MsgDeposit) Unmarshal(dAtA []byte) error { } } if byteLen < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } postIndex := iNdEx + byteLen if postIndex < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if postIndex > l { return io.ErrUnexpectedEOF @@ -2080,7 +1696,7 @@ func (m *MsgDeposit) Unmarshal(dAtA []byte) error { var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCodec + return ErrIntOverflowTypes } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -2093,11 +1709,11 @@ func (m *MsgDeposit) Unmarshal(dAtA []byte) error { } } if msglen < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } postIndex := iNdEx + msglen if postIndex < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if postIndex > l { return io.ErrUnexpectedEOF @@ -2109,15 +1725,15 @@ func (m *MsgDeposit) Unmarshal(dAtA []byte) error { iNdEx = postIndex default: iNdEx = preIndex - skippy, err := skipCodec(dAtA[iNdEx:]) + skippy, err := skipTypes(dAtA[iNdEx:]) if err != nil { return err } if skippy < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if (iNdEx + skippy) < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF @@ -2139,7 +1755,7 @@ func (m *MsgVote) Unmarshal(dAtA []byte) error { var wire uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCodec + return ErrIntOverflowTypes } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -2167,7 +1783,7 @@ func (m *MsgVote) Unmarshal(dAtA []byte) error { m.ProposalID = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCodec + return ErrIntOverflowTypes } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -2186,7 +1802,7 @@ func (m *MsgVote) Unmarshal(dAtA []byte) error { var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCodec + return ErrIntOverflowTypes } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -2199,11 +1815,11 @@ func (m *MsgVote) Unmarshal(dAtA []byte) error { } } if byteLen < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } postIndex := iNdEx + byteLen if postIndex < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if postIndex > l { return io.ErrUnexpectedEOF @@ -2220,7 +1836,7 @@ func (m *MsgVote) Unmarshal(dAtA []byte) error { m.Option = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCodec + return ErrIntOverflowTypes } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -2234,15 +1850,15 @@ func (m *MsgVote) Unmarshal(dAtA []byte) error { } default: iNdEx = preIndex - skippy, err := skipCodec(dAtA[iNdEx:]) + skippy, err := skipTypes(dAtA[iNdEx:]) if err != nil { return err } if skippy < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if (iNdEx + skippy) < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF @@ -2264,7 +1880,7 @@ func (m *TextProposal) Unmarshal(dAtA []byte) error { var wire uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCodec + return ErrIntOverflowTypes } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -2292,7 +1908,7 @@ func (m *TextProposal) Unmarshal(dAtA []byte) error { var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCodec + return ErrIntOverflowTypes } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -2306,11 +1922,11 @@ func (m *TextProposal) Unmarshal(dAtA []byte) error { } intStringLen := int(stringLen) if intStringLen < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } postIndex := iNdEx + intStringLen if postIndex < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if postIndex > l { return io.ErrUnexpectedEOF @@ -2324,7 +1940,7 @@ func (m *TextProposal) Unmarshal(dAtA []byte) error { var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCodec + return ErrIntOverflowTypes } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -2338,11 +1954,11 @@ func (m *TextProposal) Unmarshal(dAtA []byte) error { } intStringLen := int(stringLen) if intStringLen < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } postIndex := iNdEx + intStringLen if postIndex < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if postIndex > l { return io.ErrUnexpectedEOF @@ -2351,15 +1967,15 @@ func (m *TextProposal) Unmarshal(dAtA []byte) error { iNdEx = postIndex default: iNdEx = preIndex - skippy, err := skipCodec(dAtA[iNdEx:]) + skippy, err := skipTypes(dAtA[iNdEx:]) if err != nil { return err } if skippy < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if (iNdEx + skippy) < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF @@ -2381,7 +1997,7 @@ func (m *Deposit) Unmarshal(dAtA []byte) error { var wire uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCodec + return ErrIntOverflowTypes } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -2409,7 +2025,7 @@ func (m *Deposit) Unmarshal(dAtA []byte) error { m.ProposalID = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCodec + return ErrIntOverflowTypes } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -2428,7 +2044,7 @@ func (m *Deposit) Unmarshal(dAtA []byte) error { var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCodec + return ErrIntOverflowTypes } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -2441,11 +2057,11 @@ func (m *Deposit) Unmarshal(dAtA []byte) error { } } if byteLen < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } postIndex := iNdEx + byteLen if postIndex < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if postIndex > l { return io.ErrUnexpectedEOF @@ -2462,7 +2078,7 @@ func (m *Deposit) Unmarshal(dAtA []byte) error { var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCodec + return ErrIntOverflowTypes } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -2475,11 +2091,11 @@ func (m *Deposit) Unmarshal(dAtA []byte) error { } } if msglen < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } postIndex := iNdEx + msglen if postIndex < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if postIndex > l { return io.ErrUnexpectedEOF @@ -2491,15 +2107,15 @@ func (m *Deposit) Unmarshal(dAtA []byte) error { iNdEx = postIndex default: iNdEx = preIndex - skippy, err := skipCodec(dAtA[iNdEx:]) + skippy, err := skipTypes(dAtA[iNdEx:]) if err != nil { return err } if skippy < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if (iNdEx + skippy) < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF @@ -2521,7 +2137,7 @@ func (m *ProposalBase) Unmarshal(dAtA []byte) error { var wire uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCodec + return ErrIntOverflowTypes } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -2549,7 +2165,7 @@ func (m *ProposalBase) Unmarshal(dAtA []byte) error { m.ProposalID = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCodec + return ErrIntOverflowTypes } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -2568,7 +2184,7 @@ func (m *ProposalBase) Unmarshal(dAtA []byte) error { m.Status = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCodec + return ErrIntOverflowTypes } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -2587,7 +2203,7 @@ func (m *ProposalBase) Unmarshal(dAtA []byte) error { var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCodec + return ErrIntOverflowTypes } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -2600,11 +2216,11 @@ func (m *ProposalBase) Unmarshal(dAtA []byte) error { } } if msglen < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } postIndex := iNdEx + msglen if postIndex < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if postIndex > l { return io.ErrUnexpectedEOF @@ -2620,7 +2236,7 @@ func (m *ProposalBase) Unmarshal(dAtA []byte) error { var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCodec + return ErrIntOverflowTypes } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -2633,11 +2249,11 @@ func (m *ProposalBase) Unmarshal(dAtA []byte) error { } } if msglen < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } postIndex := iNdEx + msglen if postIndex < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if postIndex > l { return io.ErrUnexpectedEOF @@ -2653,7 +2269,7 @@ func (m *ProposalBase) Unmarshal(dAtA []byte) error { var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCodec + return ErrIntOverflowTypes } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -2666,11 +2282,11 @@ func (m *ProposalBase) Unmarshal(dAtA []byte) error { } } if msglen < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } postIndex := iNdEx + msglen if postIndex < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if postIndex > l { return io.ErrUnexpectedEOF @@ -2686,7 +2302,7 @@ func (m *ProposalBase) Unmarshal(dAtA []byte) error { var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCodec + return ErrIntOverflowTypes } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -2699,11 +2315,11 @@ func (m *ProposalBase) Unmarshal(dAtA []byte) error { } } if msglen < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } postIndex := iNdEx + msglen if postIndex < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if postIndex > l { return io.ErrUnexpectedEOF @@ -2720,7 +2336,7 @@ func (m *ProposalBase) Unmarshal(dAtA []byte) error { var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCodec + return ErrIntOverflowTypes } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -2733,11 +2349,11 @@ func (m *ProposalBase) Unmarshal(dAtA []byte) error { } } if msglen < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } postIndex := iNdEx + msglen if postIndex < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if postIndex > l { return io.ErrUnexpectedEOF @@ -2753,7 +2369,7 @@ func (m *ProposalBase) Unmarshal(dAtA []byte) error { var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCodec + return ErrIntOverflowTypes } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -2766,11 +2382,11 @@ func (m *ProposalBase) Unmarshal(dAtA []byte) error { } } if msglen < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } postIndex := iNdEx + msglen if postIndex < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if postIndex > l { return io.ErrUnexpectedEOF @@ -2781,15 +2397,15 @@ func (m *ProposalBase) Unmarshal(dAtA []byte) error { iNdEx = postIndex default: iNdEx = preIndex - skippy, err := skipCodec(dAtA[iNdEx:]) + skippy, err := skipTypes(dAtA[iNdEx:]) if err != nil { return err } if skippy < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if (iNdEx + skippy) < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF @@ -2811,7 +2427,7 @@ func (m *TallyResult) Unmarshal(dAtA []byte) error { var wire uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCodec + return ErrIntOverflowTypes } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -2839,7 +2455,7 @@ func (m *TallyResult) Unmarshal(dAtA []byte) error { var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCodec + return ErrIntOverflowTypes } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -2852,11 +2468,11 @@ func (m *TallyResult) Unmarshal(dAtA []byte) error { } } if byteLen < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } postIndex := iNdEx + byteLen if postIndex < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if postIndex > l { return io.ErrUnexpectedEOF @@ -2872,7 +2488,7 @@ func (m *TallyResult) Unmarshal(dAtA []byte) error { var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCodec + return ErrIntOverflowTypes } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -2885,11 +2501,11 @@ func (m *TallyResult) Unmarshal(dAtA []byte) error { } } if byteLen < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } postIndex := iNdEx + byteLen if postIndex < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if postIndex > l { return io.ErrUnexpectedEOF @@ -2905,7 +2521,7 @@ func (m *TallyResult) Unmarshal(dAtA []byte) error { var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCodec + return ErrIntOverflowTypes } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -2918,11 +2534,11 @@ func (m *TallyResult) Unmarshal(dAtA []byte) error { } } if byteLen < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } postIndex := iNdEx + byteLen if postIndex < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if postIndex > l { return io.ErrUnexpectedEOF @@ -2938,7 +2554,7 @@ func (m *TallyResult) Unmarshal(dAtA []byte) error { var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCodec + return ErrIntOverflowTypes } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -2951,11 +2567,11 @@ func (m *TallyResult) Unmarshal(dAtA []byte) error { } } if byteLen < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } postIndex := iNdEx + byteLen if postIndex < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if postIndex > l { return io.ErrUnexpectedEOF @@ -2966,15 +2582,15 @@ func (m *TallyResult) Unmarshal(dAtA []byte) error { iNdEx = postIndex default: iNdEx = preIndex - skippy, err := skipCodec(dAtA[iNdEx:]) + skippy, err := skipTypes(dAtA[iNdEx:]) if err != nil { return err } if skippy < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if (iNdEx + skippy) < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF @@ -2996,7 +2612,7 @@ func (m *Vote) Unmarshal(dAtA []byte) error { var wire uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCodec + return ErrIntOverflowTypes } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -3024,7 +2640,7 @@ func (m *Vote) Unmarshal(dAtA []byte) error { m.ProposalID = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCodec + return ErrIntOverflowTypes } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -3043,7 +2659,7 @@ func (m *Vote) Unmarshal(dAtA []byte) error { var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCodec + return ErrIntOverflowTypes } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -3056,11 +2672,11 @@ func (m *Vote) Unmarshal(dAtA []byte) error { } } if byteLen < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } postIndex := iNdEx + byteLen if postIndex < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if postIndex > l { return io.ErrUnexpectedEOF @@ -3077,7 +2693,7 @@ func (m *Vote) Unmarshal(dAtA []byte) error { m.Option = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCodec + return ErrIntOverflowTypes } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -3091,15 +2707,15 @@ func (m *Vote) Unmarshal(dAtA []byte) error { } default: iNdEx = preIndex - skippy, err := skipCodec(dAtA[iNdEx:]) + skippy, err := skipTypes(dAtA[iNdEx:]) if err != nil { return err } if skippy < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if (iNdEx + skippy) < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF @@ -3121,7 +2737,7 @@ func (m *BasicProposal) Unmarshal(dAtA []byte) error { var wire uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCodec + return ErrIntOverflowTypes } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -3149,7 +2765,7 @@ func (m *BasicProposal) Unmarshal(dAtA []byte) error { var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCodec + return ErrIntOverflowTypes } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -3162,11 +2778,11 @@ func (m *BasicProposal) Unmarshal(dAtA []byte) error { } } if msglen < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } postIndex := iNdEx + msglen if postIndex < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if postIndex > l { return io.ErrUnexpectedEOF @@ -3185,7 +2801,7 @@ func (m *BasicProposal) Unmarshal(dAtA []byte) error { var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCodec + return ErrIntOverflowTypes } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -3198,11 +2814,11 @@ func (m *BasicProposal) Unmarshal(dAtA []byte) error { } } if msglen < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } postIndex := iNdEx + msglen if postIndex < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if postIndex > l { return io.ErrUnexpectedEOF @@ -3216,15 +2832,15 @@ func (m *BasicProposal) Unmarshal(dAtA []byte) error { iNdEx = postIndex default: iNdEx = preIndex - skippy, err := skipCodec(dAtA[iNdEx:]) + skippy, err := skipTypes(dAtA[iNdEx:]) if err != nil { return err } if skippy < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if (iNdEx + skippy) < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF @@ -3246,7 +2862,7 @@ func (m *BasicContent) Unmarshal(dAtA []byte) error { var wire uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCodec + return ErrIntOverflowTypes } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -3274,7 +2890,7 @@ func (m *BasicContent) Unmarshal(dAtA []byte) error { var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCodec + return ErrIntOverflowTypes } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -3287,11 +2903,11 @@ func (m *BasicContent) Unmarshal(dAtA []byte) error { } } if msglen < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } postIndex := iNdEx + msglen if postIndex < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if postIndex > l { return io.ErrUnexpectedEOF @@ -3304,15 +2920,15 @@ func (m *BasicContent) Unmarshal(dAtA []byte) error { iNdEx = postIndex default: iNdEx = preIndex - skippy, err := skipCodec(dAtA[iNdEx:]) + skippy, err := skipTypes(dAtA[iNdEx:]) if err != nil { return err } if skippy < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if (iNdEx + skippy) < 0 { - return ErrInvalidLengthCodec + return ErrInvalidLengthTypes } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF @@ -3326,7 +2942,7 @@ func (m *BasicContent) Unmarshal(dAtA []byte) error { } return nil } -func skipCodec(dAtA []byte) (n int, err error) { +func skipTypes(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 depth := 0 @@ -3334,7 +2950,7 @@ func skipCodec(dAtA []byte) (n int, err error) { var wire uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return 0, ErrIntOverflowCodec + return 0, ErrIntOverflowTypes } if iNdEx >= l { return 0, io.ErrUnexpectedEOF @@ -3351,7 +2967,7 @@ func skipCodec(dAtA []byte) (n int, err error) { case 0: for shift := uint(0); ; shift += 7 { if shift >= 64 { - return 0, ErrIntOverflowCodec + return 0, ErrIntOverflowTypes } if iNdEx >= l { return 0, io.ErrUnexpectedEOF @@ -3367,7 +2983,7 @@ func skipCodec(dAtA []byte) (n int, err error) { var length int for shift := uint(0); ; shift += 7 { if shift >= 64 { - return 0, ErrIntOverflowCodec + return 0, ErrIntOverflowTypes } if iNdEx >= l { return 0, io.ErrUnexpectedEOF @@ -3380,14 +2996,14 @@ func skipCodec(dAtA []byte) (n int, err error) { } } if length < 0 { - return 0, ErrInvalidLengthCodec + return 0, ErrInvalidLengthTypes } iNdEx += length case 3: depth++ case 4: if depth == 0 { - return 0, ErrUnexpectedEndOfGroupCodec + return 0, ErrUnexpectedEndOfGroupTypes } depth-- case 5: @@ -3396,7 +3012,7 @@ func skipCodec(dAtA []byte) (n int, err error) { return 0, fmt.Errorf("proto: illegal wireType %d", wireType) } if iNdEx < 0 { - return 0, ErrInvalidLengthCodec + return 0, ErrInvalidLengthTypes } if depth == 0 { return iNdEx, nil @@ -3406,7 +3022,7 @@ func skipCodec(dAtA []byte) (n int, err error) { } var ( - ErrInvalidLengthCodec = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowCodec = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupCodec = fmt.Errorf("proto: unexpected end of group") + ErrInvalidLengthTypes = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTypes = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTypes = fmt.Errorf("proto: unexpected end of group") ) diff --git a/x/gov/types/codec.proto b/x/gov/types/types.proto similarity index 100% rename from x/gov/types/codec.proto rename to x/gov/types/types.proto From 38d44e839e1fdd465b579eab8365ace63ff71c34 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Mon, 17 Feb 2020 14:57:14 -0500 Subject: [PATCH 251/529] WIP on fixing tests --- x/gov/keeper/keeper_test.go | 6 ++++-- x/gov/keeper/proposal_test.go | 4 +++- x/gov/keeper/querier_test.go | 12 ++++++------ 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/x/gov/keeper/keeper_test.go b/x/gov/keeper/keeper_test.go index 9cd2a0559e65..7e288ef82701 100644 --- a/x/gov/keeper/keeper_test.go +++ b/x/gov/keeper/keeper_test.go @@ -1,6 +1,7 @@ package keeper import ( + proto "github.com/gogo/protobuf/types" "testing" "github.com/stretchr/testify/require" @@ -45,7 +46,8 @@ func TestProposalQueues(t *testing.T) { activeIterator := keeper.ActiveProposalQueueIterator(ctx, proposal.VotingEndTime) require.True(t, activeIterator.Valid()) - keeper.cdc.UnmarshalBinaryLengthPrefixed(activeIterator.Value(), &proposalID) - require.Equal(t, proposalID, proposal.ProposalID) + var proposalIdWrapper proto.UInt64Value + keeper.cdc.UnmarshalBinaryLengthPrefixed(activeIterator.Value(), &proposalIdWrapper) + require.Equal(t, proposalIdWrapper.Value, proposal.ProposalID) activeIterator.Close() } diff --git a/x/gov/keeper/proposal_test.go b/x/gov/keeper/proposal_test.go index 5848e0d753e9..ef43de3658c6 100644 --- a/x/gov/keeper/proposal_test.go +++ b/x/gov/keeper/proposal_test.go @@ -99,7 +99,9 @@ func registerTestCodec(cdc *codec.Codec) { func TestSubmitProposal(t *testing.T) { ctx, _, _, keeper, _, _ := createTestInput(t, false, 100) // nolint: dogsled - registerTestCodec(keeper.cdc) + cdc := codec.New() + + registerTestCodec(cdc) testCases := []struct { content types.Content diff --git a/x/gov/keeper/querier_test.go b/x/gov/keeper/querier_test.go index 54aeae6fe7a5..a33be5128a8a 100644 --- a/x/gov/keeper/querier_test.go +++ b/x/gov/keeper/querier_test.go @@ -16,7 +16,7 @@ import ( const custom = "custom" -func getQueriedParams(t *testing.T, ctx sdk.Context, cdc *codec.Codec, querier sdk.Querier) (types.DepositParams, types.VotingParams, types.TallyParams) { +func getQueriedParams(t *testing.T, ctx sdk.Context, cdc codec.Marshaler, querier sdk.Querier) (types.DepositParams, types.VotingParams, types.TallyParams) { query := abci.RequestQuery{ Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryParams, types.ParamDeposit}, "/"), Data: []byte{}, @@ -57,7 +57,7 @@ func getQueriedParams(t *testing.T, ctx sdk.Context, cdc *codec.Codec, querier s } func getQueriedProposals( - t *testing.T, ctx sdk.Context, cdc *codec.Codec, querier sdk.Querier, + t *testing.T, ctx sdk.Context, cdc codec.Marshaler, querier sdk.Querier, depositor, voter sdk.AccAddress, status types.ProposalStatus, page, limit int, ) []types.Proposal { @@ -76,7 +76,7 @@ func getQueriedProposals( return proposals } -func getQueriedDeposit(t *testing.T, ctx sdk.Context, cdc *codec.Codec, querier sdk.Querier, proposalID uint64, depositor sdk.AccAddress) types.Deposit { +func getQueriedDeposit(t *testing.T, ctx sdk.Context, cdc codec.Marshaler, querier sdk.Querier, proposalID uint64, depositor sdk.AccAddress) types.Deposit { query := abci.RequestQuery{ Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryDeposit}, "/"), Data: cdc.MustMarshalJSON(types.NewQueryDepositParams(proposalID, depositor)), @@ -92,7 +92,7 @@ func getQueriedDeposit(t *testing.T, ctx sdk.Context, cdc *codec.Codec, querier return deposit } -func getQueriedDeposits(t *testing.T, ctx sdk.Context, cdc *codec.Codec, querier sdk.Querier, proposalID uint64) []types.Deposit { +func getQueriedDeposits(t *testing.T, ctx sdk.Context, cdc codec.Marshaler, querier sdk.Querier, proposalID uint64) []types.Deposit { query := abci.RequestQuery{ Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryDeposits}, "/"), Data: cdc.MustMarshalJSON(types.NewQueryProposalParams(proposalID)), @@ -108,7 +108,7 @@ func getQueriedDeposits(t *testing.T, ctx sdk.Context, cdc *codec.Codec, querier return deposits } -func getQueriedVote(t *testing.T, ctx sdk.Context, cdc *codec.Codec, querier sdk.Querier, proposalID uint64, voter sdk.AccAddress) types.Vote { +func getQueriedVote(t *testing.T, ctx sdk.Context, cdc codec.Marshaler, querier sdk.Querier, proposalID uint64, voter sdk.AccAddress) types.Vote { query := abci.RequestQuery{ Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryVote}, "/"), Data: cdc.MustMarshalJSON(types.NewQueryVoteParams(proposalID, voter)), @@ -124,7 +124,7 @@ func getQueriedVote(t *testing.T, ctx sdk.Context, cdc *codec.Codec, querier sdk return vote } -func getQueriedVotes(t *testing.T, ctx sdk.Context, cdc *codec.Codec, querier sdk.Querier, +func getQueriedVotes(t *testing.T, ctx sdk.Context, cdc codec.Marshaler, querier sdk.Querier, proposalID uint64, page, limit int) []types.Vote { query := abci.RequestQuery{ Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryVote}, "/"), From 2e0033afcf0c03f65e87f18e3af3ae0b7c3c9e29 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Mon, 17 Feb 2020 16:53:24 -0500 Subject: [PATCH 252/529] Update x/gov/types/codec.go Co-Authored-By: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com> --- x/gov/types/codec.go | 1 - 1 file changed, 1 deletion(-) diff --git a/x/gov/types/codec.go b/x/gov/types/codec.go index 6e85045ddb96..5226877f97f4 100644 --- a/x/gov/types/codec.go +++ b/x/gov/types/codec.go @@ -11,7 +11,6 @@ type Codec interface { UnmarshalProposal(bz []byte, ptr *Proposal) error } - // module codec var ModuleCdc = codec.New() From 830ada0fa4dd7eb7ad8b203276e89e0d66f0cc6d Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Tue, 25 Feb 2020 15:58:31 -0500 Subject: [PATCH 253/529] WIP on StdProposal --- x/std.proto | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 x/std.proto diff --git a/x/std.proto b/x/std.proto new file mode 100644 index 000000000000..07c87b301781 --- /dev/null +++ b/x/std.proto @@ -0,0 +1,15 @@ +syntax = "proto3"; +package cosmos_sdk.x.v1; + +import "gov/types/types.proto"; +import "params/types/proposal/types.proto"; +import "upgrade/types/types.proto"; + +message StdProposal { + oneof sum { + cosmos_sdk.x.gov.v1.TextProposal text = 1; + cosmos_sdk.x.params.v1.ParameterChangeProposal parameter_change = 2; + cosmos_sdk.x.upgrade.v1.SoftwareUpgradeProposal software_upgrade = 3; + cosmos_sdk.x.upgrade.v1.CancelSoftwareUpgradeProposal cancel_software_upgrade = 4; + } +} From 2cf8a5e955ff7a89a5d903f013d53c1548a87ac1 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Wed, 26 Feb 2020 10:41:35 -0500 Subject: [PATCH 254/529] WIP on proposal proto --- {x => codec/std}/std.proto | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) rename {x => codec/std}/std.proto (60%) diff --git a/x/std.proto b/codec/std/std.proto similarity index 60% rename from x/std.proto rename to codec/std/std.proto index 07c87b301781..359580d30ef5 100644 --- a/x/std.proto +++ b/codec/std/std.proto @@ -1,9 +1,10 @@ syntax = "proto3"; package cosmos_sdk.x.v1; -import "gov/types/types.proto"; -import "params/types/proposal/types.proto"; -import "upgrade/types/types.proto"; +import "x/gov/types/types.proto"; +import "x/params/types/proposal/types.proto"; +import "x/upgrade/types/types.proto"; +import "x/distribution/types/types.proto"; message StdProposal { oneof sum { @@ -11,5 +12,6 @@ message StdProposal { cosmos_sdk.x.params.v1.ParameterChangeProposal parameter_change = 2; cosmos_sdk.x.upgrade.v1.SoftwareUpgradeProposal software_upgrade = 3; cosmos_sdk.x.upgrade.v1.CancelSoftwareUpgradeProposal cancel_software_upgrade = 4; + cosmos_sdk.x.distribution.v1.CommunityPoolSpendProposal community_pool_spend = 5; } } From 8bd648eef19112c0c89b3fa4420b29ff5954d1cc Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Wed, 26 Feb 2020 20:14:08 -0500 Subject: [PATCH 255/529] WIP on std codec --- codec/std/std.pb.go | 1015 +++++++++++++++++++++++++++++++++++++++++ codec/std/std.proto | 23 +- simapp/app.go | 3 +- simapp/codec/codec.go | 22 + 4 files changed, 1055 insertions(+), 8 deletions(-) create mode 100644 codec/std/std.pb.go diff --git a/codec/std/std.pb.go b/codec/std/std.pb.go new file mode 100644 index 000000000000..985a5f8b5ff4 --- /dev/null +++ b/codec/std/std.pb.go @@ -0,0 +1,1015 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: codec/std/std.proto + +package std + +import ( + fmt "fmt" + types2 "github.com/cosmos/cosmos-sdk/x/distribution/types" + github_com_cosmos_cosmos_sdk_x_gov_types "github.com/cosmos/cosmos-sdk/x/gov/types" + types "github.com/cosmos/cosmos-sdk/x/gov/types" + proposal "github.com/cosmos/cosmos-sdk/x/params/types/proposal" + types1 "github.com/cosmos/cosmos-sdk/x/upgrade/types" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + _ "github.com/regen-network/cosmos-proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type StdProposal struct { + types.ProposalBase `protobuf:"bytes,1,opt,name=base,proto3,embedded=base" json:"base"` + Content StdProposal_Content `protobuf:"bytes,2,opt,name=content,proto3" json:"content"` +} + +func (m *StdProposal) Reset() { *m = StdProposal{} } +func (m *StdProposal) String() string { return proto.CompactTextString(m) } +func (*StdProposal) ProtoMessage() {} +func (*StdProposal) Descriptor() ([]byte, []int) { + return fileDescriptor_bfdf2c6f71a73b14, []int{0} +} +func (m *StdProposal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StdProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_StdProposal.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 *StdProposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_StdProposal.Merge(m, src) +} +func (m *StdProposal) XXX_Size() int { + return m.Size() +} +func (m *StdProposal) XXX_DiscardUnknown() { + xxx_messageInfo_StdProposal.DiscardUnknown(m) +} + +var xxx_messageInfo_StdProposal proto.InternalMessageInfo + +func (m *StdProposal) GetContent() StdProposal_Content { + if m != nil { + return m.Content + } + return StdProposal_Content{} +} + +type StdProposal_Content struct { + // Types that are valid to be assigned to Sum: + // *StdProposal_Content_Text + // *StdProposal_Content_ParameterChange + // *StdProposal_Content_SoftwareUpgrade + // *StdProposal_Content_CancelSoftwareUpgrade + // *StdProposal_Content_CommunityPoolSpend + Sum isStdProposal_Content_Sum `protobuf_oneof:"sum"` +} + +func (m *StdProposal_Content) Reset() { *m = StdProposal_Content{} } +func (m *StdProposal_Content) String() string { return proto.CompactTextString(m) } +func (*StdProposal_Content) ProtoMessage() {} +func (*StdProposal_Content) Descriptor() ([]byte, []int) { + return fileDescriptor_bfdf2c6f71a73b14, []int{0, 0} +} +func (m *StdProposal_Content) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StdProposal_Content) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_StdProposal_Content.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 *StdProposal_Content) XXX_Merge(src proto.Message) { + xxx_messageInfo_StdProposal_Content.Merge(m, src) +} +func (m *StdProposal_Content) XXX_Size() int { + return m.Size() +} +func (m *StdProposal_Content) XXX_DiscardUnknown() { + xxx_messageInfo_StdProposal_Content.DiscardUnknown(m) +} + +var xxx_messageInfo_StdProposal_Content proto.InternalMessageInfo + +type isStdProposal_Content_Sum interface { + isStdProposal_Content_Sum() + MarshalTo([]byte) (int, error) + Size() int +} + +type StdProposal_Content_Text struct { + Text *types.TextProposal `protobuf:"bytes,1,opt,name=text,proto3,oneof" json:"text,omitempty"` +} +type StdProposal_Content_ParameterChange struct { + ParameterChange *proposal.ParameterChangeProposal `protobuf:"bytes,2,opt,name=parameter_change,json=parameterChange,proto3,oneof" json:"parameter_change,omitempty"` +} +type StdProposal_Content_SoftwareUpgrade struct { + SoftwareUpgrade *types1.SoftwareUpgradeProposal `protobuf:"bytes,3,opt,name=software_upgrade,json=softwareUpgrade,proto3,oneof" json:"software_upgrade,omitempty"` +} +type StdProposal_Content_CancelSoftwareUpgrade struct { + CancelSoftwareUpgrade *types1.CancelSoftwareUpgradeProposal `protobuf:"bytes,4,opt,name=cancel_software_upgrade,json=cancelSoftwareUpgrade,proto3,oneof" json:"cancel_software_upgrade,omitempty"` +} +type StdProposal_Content_CommunityPoolSpend struct { + CommunityPoolSpend *types2.CommunityPoolSpendProposal `protobuf:"bytes,5,opt,name=community_pool_spend,json=communityPoolSpend,proto3,oneof" json:"community_pool_spend,omitempty"` +} + +func (*StdProposal_Content_Text) isStdProposal_Content_Sum() {} +func (*StdProposal_Content_ParameterChange) isStdProposal_Content_Sum() {} +func (*StdProposal_Content_SoftwareUpgrade) isStdProposal_Content_Sum() {} +func (*StdProposal_Content_CancelSoftwareUpgrade) isStdProposal_Content_Sum() {} +func (*StdProposal_Content_CommunityPoolSpend) isStdProposal_Content_Sum() {} + +func (m *StdProposal_Content) GetSum() isStdProposal_Content_Sum { + if m != nil { + return m.Sum + } + return nil +} + +func (m *StdProposal_Content) GetText() *types.TextProposal { + if x, ok := m.GetSum().(*StdProposal_Content_Text); ok { + return x.Text + } + return nil +} + +func (m *StdProposal_Content) GetParameterChange() *proposal.ParameterChangeProposal { + if x, ok := m.GetSum().(*StdProposal_Content_ParameterChange); ok { + return x.ParameterChange + } + return nil +} + +func (m *StdProposal_Content) GetSoftwareUpgrade() *types1.SoftwareUpgradeProposal { + if x, ok := m.GetSum().(*StdProposal_Content_SoftwareUpgrade); ok { + return x.SoftwareUpgrade + } + return nil +} + +func (m *StdProposal_Content) GetCancelSoftwareUpgrade() *types1.CancelSoftwareUpgradeProposal { + if x, ok := m.GetSum().(*StdProposal_Content_CancelSoftwareUpgrade); ok { + return x.CancelSoftwareUpgrade + } + return nil +} + +func (m *StdProposal_Content) GetCommunityPoolSpend() *types2.CommunityPoolSpendProposal { + if x, ok := m.GetSum().(*StdProposal_Content_CommunityPoolSpend); ok { + return x.CommunityPoolSpend + } + return nil +} + +// XXX_OneofWrappers is for the internal use of the proto package. +func (*StdProposal_Content) XXX_OneofWrappers() []interface{} { + return []interface{}{ + (*StdProposal_Content_Text)(nil), + (*StdProposal_Content_ParameterChange)(nil), + (*StdProposal_Content_SoftwareUpgrade)(nil), + (*StdProposal_Content_CancelSoftwareUpgrade)(nil), + (*StdProposal_Content_CommunityPoolSpend)(nil), + } +} + +func init() { + proto.RegisterType((*StdProposal)(nil), "cosmos_sdk.x.v1.StdProposal") + proto.RegisterType((*StdProposal_Content)(nil), "cosmos_sdk.x.v1.StdProposal.Content") +} + +func init() { proto.RegisterFile("codec/std/std.proto", fileDescriptor_bfdf2c6f71a73b14) } + +var fileDescriptor_bfdf2c6f71a73b14 = []byte{ + // 492 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x93, 0x4f, 0x6f, 0xd3, 0x30, + 0x18, 0xc6, 0x13, 0x96, 0x32, 0xe4, 0x1d, 0x36, 0x05, 0xd0, 0xaa, 0x22, 0x65, 0xe3, 0x8f, 0x26, + 0x24, 0x34, 0x7b, 0x03, 0x04, 0x88, 0x0b, 0xa8, 0xe5, 0xc0, 0x71, 0xea, 0xe0, 0x82, 0x40, 0x91, + 0x6b, 0x9b, 0x34, 0x5a, 0x92, 0xd7, 0x8a, 0x9d, 0x92, 0x7e, 0x0b, 0x3e, 0x00, 0xdf, 0x02, 0x3e, + 0xc4, 0xc4, 0xa9, 0x47, 0x4e, 0x13, 0x6a, 0xbf, 0x08, 0xaa, 0xe3, 0x8c, 0x64, 0xdd, 0x76, 0x68, + 0x95, 0xf8, 0x7d, 0x9e, 0xdf, 0x63, 0xbf, 0xf1, 0x8b, 0x6e, 0x33, 0xe0, 0x82, 0x11, 0xa5, 0xf9, + 0xf2, 0x87, 0x65, 0x0e, 0x1a, 0xfc, 0x4d, 0x06, 0x2a, 0x05, 0x15, 0x2a, 0x7e, 0x82, 0x4b, 0x3c, + 0x39, 0xec, 0x3d, 0xd1, 0xe3, 0x38, 0xe7, 0xa1, 0xa4, 0xb9, 0x9e, 0x12, 0xa3, 0x21, 0x95, 0x64, + 0xbf, 0xf9, 0x52, 0xb9, 0x7b, 0x7b, 0xab, 0xe2, 0x08, 0x22, 0xf8, 0xff, 0x64, 0x75, 0xdb, 0x25, + 0x89, 0x60, 0x42, 0xf4, 0x54, 0x0a, 0x55, 0xfd, 0xdb, 0xc2, 0xc3, 0x92, 0x48, 0x9a, 0xd3, 0xd4, + 0xae, 0x2e, 0x19, 0x12, 0x14, 0x4d, 0x5a, 0xa2, 0x7b, 0x25, 0x29, 0x64, 0x94, 0x53, 0x2e, 0x2e, + 0x21, 0xec, 0x96, 0x84, 0xc7, 0x4a, 0xe7, 0xf1, 0xa8, 0xd0, 0x31, 0x64, 0xab, 0x8a, 0x07, 0x3f, + 0x3b, 0x68, 0xe3, 0x58, 0xf3, 0x23, 0x8b, 0xf6, 0xdf, 0x20, 0x6f, 0x44, 0x95, 0xe8, 0xba, 0xbb, + 0xee, 0xe3, 0x8d, 0xa7, 0xf7, 0x71, 0xab, 0x03, 0x11, 0x4c, 0xf0, 0xe4, 0x10, 0xd7, 0xe2, 0x3e, + 0x55, 0xa2, 0x7f, 0xeb, 0xf4, 0x6c, 0xc7, 0x99, 0x9d, 0xed, 0xb8, 0x43, 0x63, 0xf4, 0xdf, 0xa1, + 0x75, 0x06, 0x99, 0x16, 0x99, 0xee, 0xde, 0x30, 0x8c, 0x47, 0xf8, 0x42, 0x17, 0x71, 0x23, 0x0f, + 0x0f, 0x2a, 0x6d, 0xdf, 0x5b, 0x62, 0x86, 0xb5, 0xb5, 0xf7, 0xc3, 0x43, 0xeb, 0xb6, 0xe4, 0xbf, + 0x44, 0x9e, 0x16, 0xa5, 0xbe, 0x76, 0x4b, 0x1f, 0x44, 0xa9, 0x6b, 0xe6, 0x7b, 0x67, 0x68, 0x0c, + 0xfe, 0x67, 0xb4, 0x65, 0xfa, 0x27, 0xb4, 0xc8, 0x43, 0x36, 0xa6, 0x59, 0x24, 0xec, 0x9e, 0x48, + 0x1b, 0x52, 0x75, 0xd9, 0x1c, 0xad, 0xd6, 0x0f, 0x8c, 0xbc, 0x81, 0xdc, 0x94, 0xed, 0x92, 0xff, + 0x05, 0x6d, 0x29, 0xf8, 0xaa, 0xbf, 0xd1, 0x5c, 0x84, 0xf6, 0x0b, 0x74, 0xd7, 0x0c, 0xfd, 0xa0, + 0x4d, 0xb7, 0x45, 0x73, 0x72, 0x6b, 0xf8, 0x58, 0x2d, 0x35, 0xf1, 0xaa, 0x5d, 0xf2, 0x25, 0xda, + 0x66, 0x34, 0x63, 0x22, 0x09, 0x57, 0x52, 0x3c, 0x93, 0xf2, 0xe2, 0xca, 0x94, 0x81, 0xf1, 0x5d, + 0x9d, 0x75, 0x97, 0x5d, 0x26, 0xf0, 0x13, 0x74, 0x87, 0x41, 0x9a, 0x16, 0x59, 0xac, 0xa7, 0xa1, + 0x04, 0x48, 0x42, 0x25, 0x45, 0xc6, 0xbb, 0x1d, 0x13, 0xf7, 0xaa, 0x1d, 0xd7, 0xbc, 0x56, 0x26, + 0xb3, 0x76, 0x1e, 0x01, 0x24, 0xc7, 0x4b, 0x5f, 0x23, 0xd0, 0x67, 0x2b, 0xd5, 0xd7, 0xcf, 0x7f, + 0xff, 0xda, 0x3f, 0x88, 0x62, 0x3d, 0x2e, 0x46, 0x98, 0x41, 0x6a, 0x47, 0xa7, 0x1e, 0x27, 0xc5, + 0x4f, 0x48, 0x63, 0x2c, 0xce, 0xaf, 0x49, 0x07, 0xad, 0xa9, 0x22, 0xed, 0xbf, 0x3d, 0x9d, 0x07, + 0xee, 0x6c, 0x1e, 0xb8, 0x7f, 0xe7, 0x81, 0xfb, 0x7d, 0x11, 0x38, 0xb3, 0x45, 0xe0, 0xfc, 0x59, + 0x04, 0xce, 0xa7, 0xbd, 0x6b, 0x91, 0xe7, 0x43, 0x3e, 0xba, 0x69, 0xae, 0xff, 0xb3, 0x7f, 0x01, + 0x00, 0x00, 0xff, 0xff, 0x30, 0x48, 0xf7, 0x0e, 0xf8, 0x03, 0x00, 0x00, +} + +func (this *StdProposal_Content) GetContent() github_com_cosmos_cosmos_sdk_x_gov_types.Content { + if x := this.GetText(); x != nil { + return x + } + if x := this.GetParameterChange(); x != nil { + return x + } + if x := this.GetSoftwareUpgrade(); x != nil { + return x + } + if x := this.GetCancelSoftwareUpgrade(); x != nil { + return x + } + if x := this.GetCommunityPoolSpend(); x != nil { + return x + } + return nil +} + +func (this *StdProposal_Content) SetContent(value github_com_cosmos_cosmos_sdk_x_gov_types.Content) error { + if value == nil { + this.Sum = nil + return nil + } + switch vt := value.(type) { + case *types.TextProposal: + this.Sum = &StdProposal_Content_Text{vt} + return nil + case types.TextProposal: + this.Sum = &StdProposal_Content_Text{&vt} + return nil + case *proposal.ParameterChangeProposal: + this.Sum = &StdProposal_Content_ParameterChange{vt} + return nil + case proposal.ParameterChangeProposal: + this.Sum = &StdProposal_Content_ParameterChange{&vt} + return nil + case *types1.SoftwareUpgradeProposal: + this.Sum = &StdProposal_Content_SoftwareUpgrade{vt} + return nil + case types1.SoftwareUpgradeProposal: + this.Sum = &StdProposal_Content_SoftwareUpgrade{&vt} + return nil + case *types1.CancelSoftwareUpgradeProposal: + this.Sum = &StdProposal_Content_CancelSoftwareUpgrade{vt} + return nil + case types1.CancelSoftwareUpgradeProposal: + this.Sum = &StdProposal_Content_CancelSoftwareUpgrade{&vt} + return nil + case *types2.CommunityPoolSpendProposal: + this.Sum = &StdProposal_Content_CommunityPoolSpend{vt} + return nil + case types2.CommunityPoolSpendProposal: + this.Sum = &StdProposal_Content_CommunityPoolSpend{&vt} + return nil + } + return fmt.Errorf("can't encode value of type %T as message StdProposal_Content", value) +} + +func (m *StdProposal) 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 *StdProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StdProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Content.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintStd(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + { + size, err := m.ProposalBase.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintStd(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *StdProposal_Content) 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 *StdProposal_Content) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StdProposal_Content) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Sum != nil { + { + size := m.Sum.Size() + i -= size + if _, err := m.Sum.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + } + } + return len(dAtA) - i, nil +} + +func (m *StdProposal_Content_Text) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StdProposal_Content_Text) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.Text != nil { + { + size, err := m.Text.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintStd(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} +func (m *StdProposal_Content_ParameterChange) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StdProposal_Content_ParameterChange) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.ParameterChange != nil { + { + size, err := m.ParameterChange.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintStd(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + return len(dAtA) - i, nil +} +func (m *StdProposal_Content_SoftwareUpgrade) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StdProposal_Content_SoftwareUpgrade) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.SoftwareUpgrade != nil { + { + size, err := m.SoftwareUpgrade.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintStd(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + return len(dAtA) - i, nil +} +func (m *StdProposal_Content_CancelSoftwareUpgrade) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StdProposal_Content_CancelSoftwareUpgrade) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.CancelSoftwareUpgrade != nil { + { + size, err := m.CancelSoftwareUpgrade.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintStd(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + return len(dAtA) - i, nil +} +func (m *StdProposal_Content_CommunityPoolSpend) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StdProposal_Content_CommunityPoolSpend) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.CommunityPoolSpend != nil { + { + size, err := m.CommunityPoolSpend.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintStd(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + return len(dAtA) - i, nil +} +func encodeVarintStd(dAtA []byte, offset int, v uint64) int { + offset -= sovStd(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *StdProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.ProposalBase.Size() + n += 1 + l + sovStd(uint64(l)) + l = m.Content.Size() + n += 1 + l + sovStd(uint64(l)) + return n +} + +func (m *StdProposal_Content) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Sum != nil { + n += m.Sum.Size() + } + return n +} + +func (m *StdProposal_Content_Text) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Text != nil { + l = m.Text.Size() + n += 1 + l + sovStd(uint64(l)) + } + return n +} +func (m *StdProposal_Content_ParameterChange) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ParameterChange != nil { + l = m.ParameterChange.Size() + n += 1 + l + sovStd(uint64(l)) + } + return n +} +func (m *StdProposal_Content_SoftwareUpgrade) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.SoftwareUpgrade != nil { + l = m.SoftwareUpgrade.Size() + n += 1 + l + sovStd(uint64(l)) + } + return n +} +func (m *StdProposal_Content_CancelSoftwareUpgrade) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.CancelSoftwareUpgrade != nil { + l = m.CancelSoftwareUpgrade.Size() + n += 1 + l + sovStd(uint64(l)) + } + return n +} +func (m *StdProposal_Content_CommunityPoolSpend) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.CommunityPoolSpend != nil { + l = m.CommunityPoolSpend.Size() + n += 1 + l + sovStd(uint64(l)) + } + return n +} + +func sovStd(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozStd(x uint64) (n int) { + return sovStd(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *StdProposal) 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 ErrIntOverflowStd + } + 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: StdProposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: StdProposal: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProposalBase", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStd + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthStd + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthStd + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.ProposalBase.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Content", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStd + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthStd + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthStd + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Content.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipStd(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthStd + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthStd + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *StdProposal_Content) 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 ErrIntOverflowStd + } + 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: Content: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Content: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Text", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStd + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthStd + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthStd + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &types.TextProposal{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Sum = &StdProposal_Content_Text{v} + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ParameterChange", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStd + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthStd + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthStd + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &proposal.ParameterChangeProposal{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Sum = &StdProposal_Content_ParameterChange{v} + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SoftwareUpgrade", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStd + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthStd + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthStd + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &types1.SoftwareUpgradeProposal{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Sum = &StdProposal_Content_SoftwareUpgrade{v} + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CancelSoftwareUpgrade", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStd + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthStd + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthStd + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &types1.CancelSoftwareUpgradeProposal{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Sum = &StdProposal_Content_CancelSoftwareUpgrade{v} + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CommunityPoolSpend", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStd + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthStd + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthStd + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &types2.CommunityPoolSpendProposal{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Sum = &StdProposal_Content_CommunityPoolSpend{v} + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipStd(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthStd + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthStd + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipStd(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowStd + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowStd + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowStd + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthStd + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupStd + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthStd + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthStd = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowStd = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupStd = fmt.Errorf("proto: unexpected end of group") +) diff --git a/codec/std/std.proto b/codec/std/std.proto index 359580d30ef5..a99d35fb4676 100644 --- a/codec/std/std.proto +++ b/codec/std/std.proto @@ -1,17 +1,28 @@ syntax = "proto3"; package cosmos_sdk.x.v1; +import "third_party/proto/cosmos-proto/cosmos.proto"; +import "third_party/proto/gogoproto/gogo.proto"; import "x/gov/types/types.proto"; import "x/params/types/proposal/types.proto"; import "x/upgrade/types/types.proto"; import "x/distribution/types/types.proto"; +option go_package = "github.com/cosmos/cosmos-sdk/codec/std"; + message StdProposal { - oneof sum { - cosmos_sdk.x.gov.v1.TextProposal text = 1; - cosmos_sdk.x.params.v1.ParameterChangeProposal parameter_change = 2; - cosmos_sdk.x.upgrade.v1.SoftwareUpgradeProposal software_upgrade = 3; - cosmos_sdk.x.upgrade.v1.CancelSoftwareUpgradeProposal cancel_software_upgrade = 4; - cosmos_sdk.x.distribution.v1.CommunityPoolSpendProposal community_pool_spend = 5; + cosmos_sdk.x.gov.v1.ProposalBase base = 1 [(gogoproto.embed) = true, (gogoproto.nullable) = false]; + Content content = 2 [(gogoproto.nullable) = false]; + + message Content { + option (cosmos_proto.interface_type) = "github.com/cosmos/cosmos-sdk/x/gov/types.Content"; + oneof sum { + cosmos_sdk.x.gov.v1.TextProposal text = 1; + cosmos_sdk.x.params.v1.ParameterChangeProposal parameter_change = 2; + cosmos_sdk.x.upgrade.v1.SoftwareUpgradeProposal software_upgrade = 3; + cosmos_sdk.x.upgrade.v1.CancelSoftwareUpgradeProposal cancel_software_upgrade = 4; + cosmos_sdk.x.distribution.v1.CommunityPoolSpendProposal community_pool_spend = 5; + } } } + diff --git a/simapp/app.go b/simapp/app.go index f8919cc99ae9..bee46cb724cf 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -1,7 +1,6 @@ package simapp import ( - "github.com/cosmos/cosmos-sdk/x/gov/types" "io" "os" @@ -208,7 +207,7 @@ func NewSimApp( AddRoute(distr.RouterKey, distr.NewCommunityPoolSpendProposalHandler(app.DistrKeeper)). AddRoute(upgrade.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(app.UpgradeKeeper)) app.GovKeeper = gov.NewKeeper( - types.NewAminoGovCodec(app.cdc), keys[gov.StoreKey], app.subspaces[gov.ModuleName], app.SupplyKeeper, + appCodec, keys[gov.StoreKey], app.subspaces[gov.ModuleName], app.SupplyKeeper, &stakingKeeper, govRouter, ) diff --git a/simapp/codec/codec.go b/simapp/codec/codec.go index abcd8752d224..0c9f910e6f65 100644 --- a/simapp/codec/codec.go +++ b/simapp/codec/codec.go @@ -2,6 +2,7 @@ package codec import ( "github.com/cosmos/cosmos-sdk/codec" + cosmos_sdk_x_v1 "github.com/cosmos/cosmos-sdk/codec/std" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/x/auth" @@ -9,6 +10,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth/vesting" "github.com/cosmos/cosmos-sdk/x/evidence" eviexported "github.com/cosmos/cosmos-sdk/x/evidence/exported" + "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/cosmos/cosmos-sdk/x/supply" supplyexported "github.com/cosmos/cosmos-sdk/x/supply/exported" ) @@ -151,6 +153,26 @@ func (c *Codec) UnmarshalEvidenceJSON(bz []byte) (eviexported.Evidence, error) { return evidence.GetEvidence(), nil } +func (c *Codec) MarshalProposal(p types.Proposal) ([]byte, error) { + stdProposal := &cosmos_sdk_x_v1.StdProposal{ProposalBase: p.ProposalBase} + if err := stdProposal.Content.SetContent(p.Content); err != nil { + return nil, err + } + return c.Marshaler.MarshalBinaryBare(stdProposal) +} + +func (c *Codec) UnmarshalProposal(bz []byte) (types.Proposal, error) { + stdProposal := &cosmos_sdk_x_v1.StdProposal{} + if err := c.Marshaler.UnmarshalBinaryLengthPrefixed(bz, stdProposal); err != nil { + return nil, err + } + + return types.Proposal{ + //Content: stdProposal.Content.GetContent(), + ProposalBase: stdProposal.ProposalBase, + }, nil +} + // ---------------------------------------------------------------------------- // necessary types and interfaces registered. This codec is provided to all the // modules the application depends on. From feb8b0d4c382af83928aa5a8f8240b456f339de4 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Wed, 26 Feb 2020 20:15:32 -0500 Subject: [PATCH 256/529] Protogen fix --- codec/std/std.pb.go | 2 +- x/distribution/types/types.pb.go | 162 +++++++++++++++---------------- 2 files changed, 82 insertions(+), 82 deletions(-) diff --git a/codec/std/std.pb.go b/codec/std/std.pb.go index 985a5f8b5ff4..f60238c77060 100644 --- a/codec/std/std.pb.go +++ b/codec/std/std.pb.go @@ -5,7 +5,6 @@ package std import ( fmt "fmt" - types2 "github.com/cosmos/cosmos-sdk/x/distribution/types" github_com_cosmos_cosmos_sdk_x_gov_types "github.com/cosmos/cosmos-sdk/x/gov/types" types "github.com/cosmos/cosmos-sdk/x/gov/types" proposal "github.com/cosmos/cosmos-sdk/x/params/types/proposal" @@ -16,6 +15,7 @@ import ( io "io" math "math" math_bits "math/bits" + types2 "x/distribution/types" ) // Reference imports to suppress errors if they are not otherwise used. diff --git a/x/distribution/types/types.pb.go b/x/distribution/types/types.pb.go index 0571a985cb0a..4bb5f55383e8 100644 --- a/x/distribution/types/types.pb.go +++ b/x/distribution/types/types.pb.go @@ -728,20 +728,20 @@ func (m *DelegatorStartingInfo) GetHeight() uint64 { } func init() { - proto.RegisterType((*MsgSetWithdrawAddress)(nil), "cosmos_sdk.x.ditribution.v1.MsgSetWithdrawAddress") - proto.RegisterType((*MsgWithdrawDelegatorReward)(nil), "cosmos_sdk.x.ditribution.v1.MsgWithdrawDelegatorReward") - proto.RegisterType((*MsgWithdrawValidatorCommission)(nil), "cosmos_sdk.x.ditribution.v1.MsgWithdrawValidatorCommission") - proto.RegisterType((*MsgFundCommunityPool)(nil), "cosmos_sdk.x.ditribution.v1.MsgFundCommunityPool") - proto.RegisterType((*Params)(nil), "cosmos_sdk.x.ditribution.v1.Params") - proto.RegisterType((*ValidatorHistoricalRewards)(nil), "cosmos_sdk.x.ditribution.v1.ValidatorHistoricalRewards") - proto.RegisterType((*ValidatorCurrentRewards)(nil), "cosmos_sdk.x.ditribution.v1.ValidatorCurrentRewards") - proto.RegisterType((*ValidatorAccumulatedCommission)(nil), "cosmos_sdk.x.ditribution.v1.ValidatorAccumulatedCommission") - proto.RegisterType((*ValidatorOutstandingRewards)(nil), "cosmos_sdk.x.ditribution.v1.ValidatorOutstandingRewards") - proto.RegisterType((*ValidatorSlashEvent)(nil), "cosmos_sdk.x.ditribution.v1.ValidatorSlashEvent") - proto.RegisterType((*ValidatorSlashEvents)(nil), "cosmos_sdk.x.ditribution.v1.ValidatorSlashEvents") - proto.RegisterType((*FeePool)(nil), "cosmos_sdk.x.ditribution.v1.FeePool") - proto.RegisterType((*CommunityPoolSpendProposal)(nil), "cosmos_sdk.x.ditribution.v1.CommunityPoolSpendProposal") - proto.RegisterType((*DelegatorStartingInfo)(nil), "cosmos_sdk.x.ditribution.v1.DelegatorStartingInfo") + proto.RegisterType((*MsgSetWithdrawAddress)(nil), "cosmos_sdk.x.distribution.v1.MsgSetWithdrawAddress") + proto.RegisterType((*MsgWithdrawDelegatorReward)(nil), "cosmos_sdk.x.distribution.v1.MsgWithdrawDelegatorReward") + proto.RegisterType((*MsgWithdrawValidatorCommission)(nil), "cosmos_sdk.x.distribution.v1.MsgWithdrawValidatorCommission") + proto.RegisterType((*MsgFundCommunityPool)(nil), "cosmos_sdk.x.distribution.v1.MsgFundCommunityPool") + proto.RegisterType((*Params)(nil), "cosmos_sdk.x.distribution.v1.Params") + proto.RegisterType((*ValidatorHistoricalRewards)(nil), "cosmos_sdk.x.distribution.v1.ValidatorHistoricalRewards") + proto.RegisterType((*ValidatorCurrentRewards)(nil), "cosmos_sdk.x.distribution.v1.ValidatorCurrentRewards") + proto.RegisterType((*ValidatorAccumulatedCommission)(nil), "cosmos_sdk.x.distribution.v1.ValidatorAccumulatedCommission") + proto.RegisterType((*ValidatorOutstandingRewards)(nil), "cosmos_sdk.x.distribution.v1.ValidatorOutstandingRewards") + proto.RegisterType((*ValidatorSlashEvent)(nil), "cosmos_sdk.x.distribution.v1.ValidatorSlashEvent") + proto.RegisterType((*ValidatorSlashEvents)(nil), "cosmos_sdk.x.distribution.v1.ValidatorSlashEvents") + proto.RegisterType((*FeePool)(nil), "cosmos_sdk.x.distribution.v1.FeePool") + proto.RegisterType((*CommunityPoolSpendProposal)(nil), "cosmos_sdk.x.distribution.v1.CommunityPoolSpendProposal") + proto.RegisterType((*DelegatorStartingInfo)(nil), "cosmos_sdk.x.distribution.v1.DelegatorStartingInfo") } func init() { proto.RegisterFile("x/distribution/types/types.proto", fileDescriptor_9fddf2a8e4a90b09) } @@ -749,75 +749,75 @@ func init() { proto.RegisterFile("x/distribution/types/types.proto", fileDescrip var fileDescriptor_9fddf2a8e4a90b09 = []byte{ // 1113 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x57, 0xcf, 0x6f, 0x1b, 0x45, - 0x14, 0xf6, 0x38, 0x4e, 0x9a, 0x4c, 0xd3, 0xa4, 0xd9, 0xd8, 0x49, 0xe4, 0x80, 0xd7, 0x1a, 0x44, - 0x15, 0x09, 0xc5, 0x69, 0xe8, 0x2d, 0x07, 0xa4, 0x38, 0x3f, 0x04, 0xa8, 0xa1, 0xd1, 0x26, 0x14, + 0x14, 0xf6, 0x38, 0x4e, 0x9a, 0x4c, 0xd3, 0xa4, 0xd9, 0xd8, 0x49, 0xe4, 0x14, 0xaf, 0x35, 0x88, + 0x2a, 0x12, 0x8a, 0x43, 0xe8, 0x2d, 0x07, 0xa4, 0x38, 0x3f, 0x04, 0xa8, 0xa1, 0xd1, 0x26, 0x14, 0x09, 0x09, 0xad, 0xc6, 0xbb, 0x13, 0x7b, 0x94, 0xf5, 0xce, 0x6a, 0x66, 0x6c, 0x27, 0xbd, 0x20, - 0x71, 0x02, 0x41, 0x11, 0x07, 0x04, 0x3d, 0x70, 0xe8, 0x05, 0x09, 0x2a, 0xfe, 0x0e, 0xd4, 0x63, - 0x6f, 0x20, 0x0e, 0x2e, 0x4a, 0x6e, 0x1c, 0x73, 0x83, 0x13, 0xda, 0x9d, 0xd9, 0x5d, 0xc7, 0xb1, - 0x68, 0x1c, 0xa9, 0xf4, 0x92, 0x64, 0xde, 0xbc, 0xf9, 0xbe, 0x6f, 0xbe, 0x99, 0x79, 0x6f, 0x03, - 0xcb, 0x47, 0x2b, 0x2e, 0x15, 0x92, 0xd3, 0x5a, 0x4b, 0x52, 0xe6, 0xaf, 0xc8, 0xe3, 0x80, 0x08, - 0xf5, 0xb3, 0x12, 0x70, 0x26, 0x99, 0xb1, 0xe8, 0x30, 0xd1, 0x64, 0xc2, 0x16, 0xee, 0x61, 0xe5, - 0xa8, 0xe2, 0xd2, 0x24, 0xb7, 0xd2, 0x5e, 0x2d, 0xde, 0x92, 0x0d, 0xca, 0x5d, 0x3b, 0xc0, 0x5c, - 0x1e, 0xaf, 0x44, 0xf9, 0x2b, 0x75, 0x56, 0x67, 0xe9, 0x5f, 0x0a, 0xa4, 0x38, 0x73, 0x01, 0x17, - 0x7d, 0x95, 0x85, 0x85, 0x1d, 0x51, 0xdf, 0x23, 0xf2, 0x23, 0x2a, 0x1b, 0x2e, 0xc7, 0x9d, 0x75, - 0xd7, 0xe5, 0x44, 0x08, 0xe3, 0x01, 0x9c, 0x71, 0x89, 0x47, 0xea, 0x58, 0x32, 0x6e, 0x63, 0x15, - 0x5c, 0x00, 0x65, 0xb0, 0x34, 0x59, 0xdd, 0x39, 0xeb, 0x9a, 0x0b, 0xc7, 0xb8, 0xe9, 0xad, 0xa1, - 0x0b, 0x29, 0xe8, 0x9f, 0xae, 0xb9, 0x5c, 0xa7, 0xb2, 0xd1, 0xaa, 0x55, 0x1c, 0xd6, 0x5c, 0x51, - 0xba, 0xf5, 0xaf, 0x65, 0xe1, 0x1e, 0x6a, 0xfa, 0x75, 0xc7, 0xd1, 0x4c, 0xd6, 0xcd, 0x04, 0x24, - 0xe6, 0xee, 0xc0, 0x9b, 0x1d, 0x2d, 0x27, 0xa1, 0xce, 0x46, 0xd4, 0x77, 0xcf, 0xba, 0xe6, 0xbc, - 0xa2, 0xee, 0xcf, 0xb8, 0x02, 0xf3, 0x74, 0xe7, 0xfc, 0xa6, 0xd1, 0xb7, 0x59, 0x58, 0xdc, 0x11, - 0xf5, 0xd8, 0x8b, 0xcd, 0x58, 0x98, 0x45, 0x3a, 0x98, 0xbb, 0xaf, 0xd4, 0x93, 0x07, 0x70, 0xa6, - 0x8d, 0x3d, 0xea, 0x9e, 0xe3, 0xce, 0xf6, 0x73, 0x5f, 0x48, 0xb9, 0x2c, 0xf7, 0x7d, 0xec, 0x25, - 0xdc, 0x09, 0x48, 0x6c, 0xcb, 0x0f, 0x00, 0x96, 0x7a, 0x6c, 0xb9, 0x1f, 0xcf, 0x6f, 0xb0, 0x66, - 0x93, 0x0a, 0x41, 0x99, 0x3f, 0x58, 0x1e, 0xf8, 0x7f, 0xe4, 0xfd, 0x0a, 0x60, 0x7e, 0x47, 0xd4, - 0xb7, 0x5b, 0xbe, 0x1b, 0x2a, 0x6a, 0xf9, 0x54, 0x1e, 0xef, 0x32, 0xe6, 0x19, 0x9f, 0xc0, 0x31, - 0xdc, 0x64, 0x2d, 0x5f, 0x2e, 0x80, 0xf2, 0xc8, 0xd2, 0xf5, 0xb7, 0x67, 0x2b, 0x3d, 0xcf, 0xa8, - 0xbd, 0x5a, 0xd9, 0x60, 0xd4, 0xaf, 0xde, 0x7e, 0xda, 0x35, 0x33, 0x4f, 0x9e, 0x9b, 0x4b, 0x97, - 0x90, 0x11, 0x2e, 0x10, 0x96, 0x06, 0x35, 0xee, 0xc1, 0x09, 0x97, 0x04, 0x4c, 0x50, 0xc9, 0xb8, - 0x3e, 0x8a, 0xd5, 0xe1, 0x8f, 0x3a, 0xc5, 0x40, 0xbf, 0x8d, 0xc0, 0xb1, 0x5d, 0xcc, 0x71, 0x53, - 0x18, 0x87, 0xf0, 0x86, 0x13, 0xef, 0xc5, 0x96, 0xf8, 0x28, 0xf2, 0x72, 0xa2, 0xba, 0x1d, 0x8a, - 0xfd, 0xa3, 0x6b, 0xde, 0xba, 0x04, 0xc7, 0x26, 0x71, 0xce, 0xba, 0x66, 0x5e, 0x39, 0x7f, 0x0e, - 0x0c, 0x59, 0x93, 0xc9, 0x78, 0x1f, 0x1f, 0x19, 0x9f, 0xc2, 0x7c, 0x0d, 0x0b, 0x62, 0x07, 0x9c, - 0x05, 0x4c, 0x10, 0x6e, 0xf3, 0xe8, 0xbe, 0x47, 0x7b, 0x9a, 0xa8, 0xee, 0x0c, 0xcd, 0xb9, 0xa8, - 0x38, 0x07, 0x61, 0x22, 0xcb, 0x08, 0xc3, 0xbb, 0x3a, 0xaa, 0x1f, 0xd6, 0x67, 0x00, 0x16, 0x6a, - 0xcc, 0x6f, 0x89, 0x0b, 0x12, 0x46, 0x22, 0x09, 0x1f, 0x0c, 0x2d, 0xe1, 0x35, 0x2d, 0x61, 0x10, - 0x28, 0xb2, 0x66, 0xa3, 0x78, 0x9f, 0x88, 0x7d, 0x58, 0x38, 0x57, 0x53, 0x6c, 0xe2, 0xe3, 0x9a, - 0x47, 0xdc, 0x85, 0x5c, 0x19, 0x2c, 0x8d, 0x57, 0xcb, 0x29, 0xea, 0xc0, 0x34, 0x64, 0xcd, 0xf6, - 0x96, 0x93, 0x2d, 0x15, 0x5d, 0xcb, 0x3d, 0x7a, 0x6c, 0x66, 0xd0, 0x17, 0x59, 0x58, 0x4c, 0x9e, + 0x71, 0x02, 0x01, 0x15, 0x07, 0x04, 0x3d, 0x70, 0xe8, 0x05, 0x09, 0x2a, 0xf1, 0x6f, 0xa0, 0x1e, + 0x7b, 0x03, 0x71, 0x70, 0x51, 0x72, 0xe3, 0x98, 0x1b, 0x9c, 0xd0, 0xee, 0x8c, 0x77, 0x37, 0x8e, + 0x45, 0xe3, 0x48, 0xa5, 0x97, 0x24, 0xf3, 0x66, 0xe6, 0xfb, 0xbe, 0xf9, 0x66, 0xde, 0x7b, 0x1b, + 0x58, 0x3e, 0x5a, 0x71, 0xa9, 0x90, 0x9c, 0xd6, 0x5a, 0x92, 0x32, 0x7f, 0x45, 0x1e, 0x07, 0x44, + 0xa8, 0x9f, 0x95, 0x80, 0x33, 0xc9, 0x8c, 0x5b, 0x0e, 0x13, 0x4d, 0x26, 0x6c, 0xe1, 0x1e, 0x56, + 0x8e, 0x2a, 0xe9, 0xc5, 0x95, 0xf6, 0x6a, 0xf1, 0xb6, 0x6c, 0x50, 0xee, 0xda, 0x01, 0xe6, 0xf2, + 0x78, 0x25, 0xda, 0xb0, 0x52, 0x67, 0x75, 0x96, 0xfc, 0xa5, 0x50, 0x8a, 0x33, 0x17, 0x80, 0xd1, + 0x57, 0x59, 0x58, 0xd8, 0x11, 0xf5, 0x3d, 0x22, 0x3f, 0xa2, 0xb2, 0xe1, 0x72, 0xdc, 0x59, 0x77, + 0x5d, 0x4e, 0x84, 0x30, 0x1e, 0xc0, 0x19, 0x97, 0x78, 0xa4, 0x8e, 0x25, 0xe3, 0x36, 0x56, 0xc1, + 0x05, 0x50, 0x06, 0x4b, 0x93, 0xd5, 0x9d, 0xb3, 0xae, 0xb9, 0x70, 0x8c, 0x9b, 0xde, 0x1a, 0xba, + 0xb0, 0x04, 0xfd, 0xd3, 0x35, 0x97, 0xeb, 0x54, 0x36, 0x5a, 0xb5, 0x8a, 0xc3, 0x9a, 0x2b, 0x4a, + 0xb8, 0xfe, 0xb5, 0x2c, 0xdc, 0x43, 0x4d, 0xbf, 0xee, 0x38, 0x9a, 0xc9, 0xba, 0x19, 0x83, 0xf4, + 0xb8, 0x3b, 0xf0, 0x66, 0x47, 0xcb, 0x89, 0xa9, 0xb3, 0x11, 0xf5, 0xdd, 0xb3, 0xae, 0x39, 0xaf, + 0xa8, 0xfb, 0x57, 0x5c, 0x81, 0x79, 0xba, 0x73, 0xfe, 0xd0, 0xe8, 0xdb, 0x2c, 0x2c, 0xee, 0x88, + 0x7a, 0xcf, 0x8b, 0xcd, 0x9e, 0x30, 0x8b, 0x74, 0x30, 0x77, 0x5f, 0xa9, 0x27, 0x0f, 0xe0, 0x4c, + 0x1b, 0x7b, 0xd4, 0x3d, 0xc7, 0x9d, 0xed, 0xe7, 0xbe, 0xb0, 0xe4, 0xb2, 0xdc, 0xf7, 0xb1, 0x17, + 0x73, 0xc7, 0x20, 0x3d, 0x5b, 0x7e, 0x00, 0xb0, 0x94, 0xb2, 0xe5, 0x7e, 0x6f, 0x7e, 0x83, 0x35, + 0x9b, 0x54, 0x08, 0xca, 0xfc, 0xc1, 0xf2, 0xc0, 0xff, 0x23, 0xef, 0x57, 0x00, 0xf3, 0x3b, 0xa2, + 0xbe, 0xdd, 0xf2, 0xdd, 0x50, 0x51, 0xcb, 0xa7, 0xf2, 0x78, 0x97, 0x31, 0xcf, 0xf8, 0x04, 0x8e, + 0xe1, 0x26, 0x6b, 0xf9, 0x72, 0x01, 0x94, 0x47, 0x96, 0xae, 0xbf, 0x3d, 0x5b, 0x49, 0xe5, 0x51, + 0x7b, 0xb5, 0xb2, 0xc1, 0xa8, 0x5f, 0x7d, 0xeb, 0x69, 0xd7, 0xcc, 0x3c, 0x79, 0x6e, 0x2e, 0x5d, + 0x42, 0x46, 0xb8, 0x41, 0x58, 0x1a, 0xd4, 0xb8, 0x07, 0x27, 0x5c, 0x12, 0x30, 0x41, 0x25, 0xe3, + 0xfa, 0x2a, 0x56, 0x87, 0xbf, 0xea, 0x04, 0x03, 0xfd, 0x36, 0x02, 0xc7, 0x76, 0x31, 0xc7, 0x4d, + 0x61, 0x1c, 0xc2, 0x1b, 0x4e, 0xef, 0x2c, 0xb6, 0xc4, 0x47, 0x91, 0x97, 0x13, 0xd5, 0xed, 0x50, + 0xec, 0x1f, 0x5d, 0xf3, 0xf6, 0x25, 0x38, 0x36, 0x89, 0x73, 0xd6, 0x35, 0xf3, 0xca, 0xf9, 0x73, + 0x60, 0xc8, 0x9a, 0x8c, 0xc7, 0xfb, 0xf8, 0xc8, 0xf8, 0x14, 0xe6, 0x6b, 0x58, 0x10, 0x3b, 0xe0, + 0x2c, 0x60, 0x82, 0x70, 0x9b, 0x47, 0xef, 0x3d, 0x3a, 0xd3, 0x44, 0x75, 0x67, 0x68, 0xce, 0x45, + 0xc5, 0x39, 0x08, 0x13, 0x59, 0x46, 0x18, 0xde, 0xd5, 0x51, 0x9d, 0x58, 0x9f, 0x01, 0x58, 0xa8, + 0x31, 0xbf, 0x25, 0x2e, 0x48, 0x18, 0x89, 0x24, 0x7c, 0x30, 0xb4, 0x84, 0x5b, 0x5a, 0xc2, 0x20, + 0x50, 0x64, 0xcd, 0x46, 0xf1, 0x3e, 0x11, 0xfb, 0xb0, 0x70, 0xae, 0xa6, 0xd8, 0xc4, 0xc7, 0x35, + 0x8f, 0xb8, 0x0b, 0xb9, 0x32, 0x58, 0x1a, 0xaf, 0x96, 0x13, 0xd4, 0x81, 0xcb, 0x90, 0x35, 0x9b, + 0x2e, 0x27, 0x5b, 0x2a, 0xba, 0x96, 0x7b, 0xf4, 0xd8, 0xcc, 0xa0, 0x2f, 0xb2, 0xb0, 0x18, 0xa7, 0xcd, 0xbb, 0x54, 0x48, 0xc6, 0xa9, 0x83, 0x3d, 0xc5, 0x2c, 0x8c, 0x1f, 0x01, 0x9c, 0x77, 0x5a, - 0xcd, 0x96, 0x87, 0x25, 0x6d, 0x13, 0x2d, 0xd3, 0xe6, 0x58, 0x52, 0xa6, 0xaf, 0xee, 0x5c, 0xdf, - 0xd5, 0xdd, 0x24, 0x4e, 0x74, 0x7b, 0x3f, 0x0c, 0x9d, 0x39, 0xeb, 0x9a, 0x25, 0x7d, 0xcc, 0x83, - 0x41, 0xd0, 0x93, 0xe7, 0xe6, 0x5b, 0x97, 0xf3, 0x4e, 0x5d, 0xf1, 0x42, 0x0a, 0xa4, 0x34, 0x5a, - 0x21, 0x8c, 0xb1, 0x01, 0xa7, 0x39, 0x39, 0x20, 0x9c, 0xf8, 0x0e, 0xb1, 0x9d, 0xe8, 0x65, 0x85, - 0x77, 0xe4, 0x46, 0xb5, 0x78, 0xd6, 0x35, 0xe7, 0x94, 0x84, 0xbe, 0x04, 0x64, 0x4d, 0x25, 0x91, - 0x8d, 0x28, 0xf0, 0x08, 0xc0, 0xf9, 0xb4, 0x84, 0xb4, 0x38, 0x27, 0xbe, 0x8c, 0x8d, 0x20, 0xf0, - 0x9a, 0xd2, 0x2d, 0x5e, 0xb0, 0xef, 0x3b, 0xfa, 0xd5, 0x0e, 0xb5, 0xab, 0x18, 0xdb, 0x98, 0x83, - 0x63, 0x01, 0xe1, 0x94, 0xa9, 0x2b, 0x9e, 0xb3, 0xf4, 0x08, 0x3d, 0x04, 0xb0, 0x94, 0x48, 0x5b, - 0x77, 0xb4, 0x09, 0xc4, 0xed, 0x29, 0x74, 0x87, 0x10, 0x3a, 0xc9, 0xe8, 0x65, 0x88, 0xec, 0x81, - 0x47, 0xdf, 0x01, 0xb8, 0x98, 0xe8, 0xb9, 0xd7, 0x92, 0x42, 0x62, 0xdf, 0xa5, 0x7e, 0x3d, 0xb6, - 0xab, 0x73, 0x59, 0xbb, 0xb6, 0xf4, 0x35, 0x99, 0x8a, 0xcf, 0x28, 0x5a, 0x84, 0xae, 0x6a, 0x20, - 0xfa, 0x19, 0xc0, 0xd9, 0x44, 0xd8, 0x9e, 0x87, 0x45, 0x63, 0xab, 0x4d, 0x7c, 0x69, 0x6c, 0xc3, - 0xb4, 0x3c, 0xdb, 0xda, 0xe2, 0xb0, 0x72, 0xe5, 0xaa, 0x8b, 0x69, 0xe7, 0xee, 0xcf, 0x40, 0xd6, - 0x74, 0x12, 0xda, 0x8d, 0x22, 0xc6, 0xfb, 0x70, 0xfc, 0x80, 0x63, 0x27, 0xfc, 0xc2, 0xd1, 0x55, - 0xa8, 0x32, 0x5c, 0x09, 0xb0, 0x92, 0xf5, 0xe8, 0x17, 0x00, 0xf3, 0x03, 0xb4, 0x0a, 0xe3, 0x21, - 0x80, 0x73, 0xa9, 0x16, 0x11, 0xce, 0xd8, 0x24, 0x9a, 0xd2, 0x6e, 0xde, 0xae, 0xfc, 0xc7, 0x67, - 0x57, 0x65, 0x00, 0x66, 0xf5, 0x4d, 0xed, 0xf3, 0xeb, 0xfd, 0x3b, 0xed, 0x45, 0x47, 0x56, 0xbe, - 0x3d, 0x40, 0x8f, 0x2e, 0x15, 0xdf, 0x03, 0x78, 0x6d, 0x9b, 0x90, 0xa8, 0x81, 0x7d, 0x09, 0xe0, - 0x54, 0x5a, 0xb9, 0x03, 0xc6, 0xbc, 0x17, 0x9c, 0xf3, 0x5d, 0xcd, 0x5f, 0xe8, 0xaf, 0xfa, 0xe1, - 0xda, 0xa1, 0x8f, 0x3b, 0x6d, 0x41, 0xa1, 0x1a, 0xf4, 0x75, 0x16, 0x16, 0xcf, 0x35, 0xd8, 0xbd, - 0x80, 0xf8, 0xae, 0xaa, 0xa2, 0xd8, 0x33, 0xf2, 0x70, 0x54, 0x52, 0xe9, 0x11, 0xd5, 0xaa, 0x2c, - 0x35, 0x30, 0xca, 0xf0, 0xba, 0x4b, 0x84, 0xc3, 0x69, 0x90, 0x1e, 0xa6, 0xd5, 0x1b, 0x0a, 0xdb, - 0x28, 0x27, 0x0e, 0x0d, 0x28, 0xf1, 0x65, 0x54, 0xef, 0xaf, 0xd6, 0x46, 0x13, 0x8c, 0x9e, 0xb6, - 0x9f, 0x7b, 0x09, 0x6d, 0x7f, 0x6d, 0xfc, 0xf3, 0xc7, 0x66, 0x26, 0x3a, 0xaa, 0xbf, 0x01, 0x2c, - 0x24, 0xdf, 0x88, 0x7b, 0x12, 0x73, 0x49, 0xfd, 0xfa, 0x7b, 0xfe, 0x41, 0x54, 0x28, 0x03, 0x4e, - 0xda, 0x94, 0x85, 0xdd, 0xa7, 0xf7, 0x19, 0xf4, 0x14, 0xca, 0xbe, 0x04, 0x64, 0x4d, 0xc5, 0x11, - 0xfd, 0x08, 0xf6, 0xe1, 0xa8, 0x90, 0xf8, 0x90, 0xe8, 0x17, 0xf0, 0xce, 0xd0, 0x4d, 0x70, 0x52, - 0x11, 0x45, 0x20, 0xc8, 0x52, 0x60, 0xc6, 0x16, 0x1c, 0x6b, 0x10, 0x5a, 0x6f, 0x28, 0xaf, 0x73, - 0xd5, 0xe5, 0xbf, 0xba, 0xe6, 0xb4, 0xc3, 0x49, 0x58, 0xe0, 0x7d, 0x5b, 0x4d, 0xa5, 0x22, 0xfb, - 0x26, 0x90, 0xa5, 0x17, 0x57, 0xdf, 0xf8, 0xe9, 0xa4, 0x04, 0x9e, 0x9e, 0x94, 0xc0, 0xb3, 0x93, - 0x12, 0xf8, 0xf3, 0xa4, 0x04, 0xbe, 0x39, 0x2d, 0x65, 0x9e, 0x9d, 0x96, 0x32, 0xbf, 0x9f, 0x96, - 0x32, 0x1f, 0x8f, 0x46, 0x32, 0x6a, 0x63, 0xd1, 0x7f, 0x19, 0x77, 0xfe, 0x0d, 0x00, 0x00, 0xff, - 0xff, 0x7b, 0x35, 0xec, 0x82, 0xe1, 0x0c, 0x00, 0x00, + 0xcd, 0x96, 0x87, 0x25, 0x6d, 0x13, 0x2d, 0xd3, 0xe6, 0x58, 0x52, 0xa6, 0x9f, 0xee, 0x5c, 0xdf, + 0xd3, 0xdd, 0x24, 0x4e, 0xf4, 0x7a, 0x3f, 0x0c, 0x9d, 0x39, 0xeb, 0x9a, 0x25, 0x7d, 0xcd, 0x83, + 0x41, 0xd0, 0x93, 0xe7, 0xe6, 0x9b, 0x97, 0xf3, 0x4e, 0x3d, 0xf1, 0x42, 0x02, 0xa4, 0x34, 0x5a, + 0x21, 0x8c, 0xb1, 0x01, 0xa7, 0x39, 0x39, 0x20, 0x9c, 0xf8, 0x0e, 0xb1, 0x9d, 0x28, 0xb3, 0xc2, + 0x37, 0x72, 0xa3, 0x5a, 0x3c, 0xeb, 0x9a, 0x73, 0x4a, 0x42, 0xdf, 0x02, 0x64, 0x4d, 0xc5, 0x91, + 0x8d, 0x28, 0xf0, 0x08, 0xc0, 0xf9, 0xa4, 0x84, 0xb4, 0x38, 0x27, 0xbe, 0xec, 0x19, 0x41, 0xe0, + 0x35, 0xa5, 0x5b, 0xbc, 0xe0, 0xdc, 0x77, 0x74, 0xd6, 0x0e, 0x75, 0xaa, 0x1e, 0xb6, 0x31, 0x07, + 0xc7, 0x02, 0xc2, 0x29, 0x53, 0x4f, 0x3c, 0x67, 0xe9, 0x11, 0xfa, 0x1a, 0xc0, 0x52, 0x2c, 0x6d, + 0xdd, 0xd1, 0x26, 0x10, 0x37, 0x55, 0xe8, 0x0e, 0x21, 0x74, 0xe2, 0xd1, 0xcb, 0x10, 0x99, 0x82, + 0x47, 0xdf, 0x01, 0xb8, 0x18, 0xeb, 0xb9, 0xd7, 0x92, 0x42, 0x62, 0xdf, 0xa5, 0x7e, 0xbd, 0x67, + 0x57, 0xe7, 0xb2, 0x76, 0x6d, 0xe9, 0x67, 0x32, 0xd5, 0xbb, 0xa3, 0x68, 0x13, 0xba, 0xaa, 0x81, + 0xe8, 0x67, 0x00, 0x67, 0x63, 0x61, 0x7b, 0x1e, 0x16, 0x8d, 0xad, 0x36, 0xf1, 0xa5, 0xb1, 0x0d, + 0x93, 0xf2, 0x6c, 0x6b, 0x8b, 0xc3, 0xca, 0x95, 0xab, 0x2e, 0x26, 0x9d, 0xbb, 0x7f, 0x05, 0xb2, + 0xa6, 0xe3, 0xd0, 0x6e, 0x14, 0x31, 0xde, 0x87, 0xe3, 0x07, 0x1c, 0x3b, 0xe1, 0x17, 0x8e, 0xae, + 0x42, 0x95, 0xe1, 0x4a, 0x80, 0x15, 0xef, 0x47, 0xbf, 0x00, 0x98, 0x1f, 0xa0, 0x55, 0x18, 0x0f, + 0x01, 0x9c, 0x4b, 0xb4, 0x88, 0x70, 0xc6, 0x26, 0xd1, 0x94, 0x76, 0x73, 0xb5, 0xf2, 0x5f, 0xdf, + 0x5d, 0x95, 0x01, 0xa0, 0xd5, 0x37, 0xb4, 0xd1, 0xaf, 0xf5, 0x1f, 0x35, 0x0d, 0x8f, 0xac, 0x7c, + 0x7b, 0x80, 0x20, 0x5d, 0x2b, 0xbe, 0x07, 0xf0, 0xda, 0x36, 0x21, 0x51, 0x07, 0xfb, 0x12, 0xc0, + 0xa9, 0xa4, 0x74, 0x07, 0x8c, 0x79, 0x2f, 0xb8, 0xe8, 0xbb, 0x9a, 0xbf, 0xd0, 0x5f, 0xf6, 0xc3, + 0xbd, 0x43, 0xdf, 0x77, 0xd2, 0x83, 0x42, 0x35, 0xe8, 0x61, 0x16, 0x16, 0xcf, 0x75, 0xd8, 0xbd, + 0x80, 0xf8, 0xae, 0x2a, 0xa3, 0xd8, 0x33, 0xf2, 0x70, 0x54, 0x52, 0xe9, 0x11, 0xd5, 0xab, 0x2c, + 0x35, 0x30, 0xca, 0xf0, 0xba, 0x4b, 0x84, 0xc3, 0x69, 0x90, 0xdc, 0xa6, 0x95, 0x0e, 0x85, 0x7d, + 0x94, 0x13, 0x87, 0x06, 0x94, 0xf8, 0x32, 0x2a, 0xf8, 0x57, 0xeb, 0xa3, 0x31, 0x46, 0xaa, 0xef, + 0xe7, 0x5e, 0x42, 0xdf, 0x5f, 0x1b, 0xff, 0xfc, 0xb1, 0x99, 0x89, 0xae, 0xea, 0x6f, 0x00, 0x0b, + 0xf1, 0x47, 0xe2, 0x9e, 0xc4, 0x5c, 0x52, 0xbf, 0xfe, 0x9e, 0x7f, 0x10, 0x55, 0xca, 0x80, 0x93, + 0x36, 0x65, 0x61, 0xfb, 0x49, 0xe7, 0x41, 0xaa, 0x52, 0xf6, 0x2d, 0x40, 0xd6, 0x54, 0x2f, 0xa2, + 0xb3, 0x60, 0x1f, 0x8e, 0x0a, 0x89, 0x0f, 0x89, 0x4e, 0x81, 0x77, 0x86, 0xee, 0x82, 0x93, 0x8a, + 0x28, 0x02, 0x41, 0x96, 0x02, 0x33, 0xb6, 0xe0, 0x58, 0x83, 0xd0, 0x7a, 0x43, 0x79, 0x9d, 0xab, + 0x2e, 0xff, 0xd5, 0x35, 0xa7, 0x1d, 0x4e, 0xc2, 0x0a, 0xef, 0xdb, 0x6a, 0x2a, 0x11, 0xd9, 0x37, + 0x81, 0x2c, 0xbd, 0xb9, 0xfa, 0xfa, 0x4f, 0x27, 0x25, 0xf0, 0xf4, 0xa4, 0x04, 0x9e, 0x9d, 0x94, + 0xc0, 0x9f, 0x27, 0x25, 0xf0, 0xcd, 0x69, 0x29, 0xf3, 0xec, 0xb4, 0x94, 0xf9, 0xfd, 0xb4, 0x94, + 0xf9, 0x78, 0x34, 0x92, 0x51, 0x1b, 0x8b, 0xfe, 0xcd, 0xb8, 0xf3, 0x6f, 0x00, 0x00, 0x00, 0xff, + 0xff, 0x9c, 0x88, 0x6a, 0xf1, 0xe3, 0x0c, 0x00, 0x00, } func (this *MsgSetWithdrawAddress) Equal(that interface{}) bool { From 333066efa8045edf0b844e891743490f0b4e1e66 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Wed, 26 Feb 2020 20:16:48 -0500 Subject: [PATCH 257/529] Fix distribution proto package --- codec/std/std.pb.go | 2 +- x/distribution/types/types.pb.go | 140 +++++++++++++++---------------- x/distribution/types/types.proto | 2 +- 3 files changed, 72 insertions(+), 72 deletions(-) diff --git a/codec/std/std.pb.go b/codec/std/std.pb.go index f60238c77060..985a5f8b5ff4 100644 --- a/codec/std/std.pb.go +++ b/codec/std/std.pb.go @@ -5,6 +5,7 @@ package std import ( fmt "fmt" + types2 "github.com/cosmos/cosmos-sdk/x/distribution/types" github_com_cosmos_cosmos_sdk_x_gov_types "github.com/cosmos/cosmos-sdk/x/gov/types" types "github.com/cosmos/cosmos-sdk/x/gov/types" proposal "github.com/cosmos/cosmos-sdk/x/params/types/proposal" @@ -15,7 +16,6 @@ import ( io "io" math "math" math_bits "math/bits" - types2 "x/distribution/types" ) // Reference imports to suppress errors if they are not otherwise used. diff --git a/x/distribution/types/types.pb.go b/x/distribution/types/types.pb.go index 4bb5f55383e8..e8e131f3a572 100644 --- a/x/distribution/types/types.pb.go +++ b/x/distribution/types/types.pb.go @@ -747,77 +747,77 @@ func init() { func init() { proto.RegisterFile("x/distribution/types/types.proto", fileDescriptor_9fddf2a8e4a90b09) } var fileDescriptor_9fddf2a8e4a90b09 = []byte{ - // 1113 bytes of a gzipped FileDescriptorProto + // 1116 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x57, 0xcf, 0x6f, 0x1b, 0x45, - 0x14, 0xf6, 0x38, 0x4e, 0x9a, 0x4c, 0xd3, 0xa4, 0xd9, 0xd8, 0x49, 0xe4, 0x14, 0xaf, 0x35, 0x88, - 0x2a, 0x12, 0x8a, 0x43, 0xe8, 0x2d, 0x07, 0xa4, 0x38, 0x3f, 0x04, 0xa8, 0xa1, 0xd1, 0x26, 0x14, - 0x09, 0x09, 0xad, 0xc6, 0xbb, 0x13, 0x7b, 0x94, 0xf5, 0xce, 0x6a, 0x66, 0x6c, 0x27, 0xbd, 0x20, - 0x71, 0x02, 0x01, 0x15, 0x07, 0x04, 0x3d, 0x70, 0xe8, 0x05, 0x09, 0x2a, 0xf1, 0x6f, 0xa0, 0x1e, - 0x7b, 0x03, 0x71, 0x70, 0x51, 0x72, 0xe3, 0x98, 0x1b, 0x9c, 0xd0, 0xee, 0x8c, 0x77, 0x37, 0x8e, - 0x45, 0xe3, 0x48, 0xa5, 0x97, 0x24, 0xf3, 0x66, 0xe6, 0xfb, 0xbe, 0xf9, 0x66, 0xde, 0x7b, 0x1b, - 0x58, 0x3e, 0x5a, 0x71, 0xa9, 0x90, 0x9c, 0xd6, 0x5a, 0x92, 0x32, 0x7f, 0x45, 0x1e, 0x07, 0x44, - 0xa8, 0x9f, 0x95, 0x80, 0x33, 0xc9, 0x8c, 0x5b, 0x0e, 0x13, 0x4d, 0x26, 0x6c, 0xe1, 0x1e, 0x56, - 0x8e, 0x2a, 0xe9, 0xc5, 0x95, 0xf6, 0x6a, 0xf1, 0xb6, 0x6c, 0x50, 0xee, 0xda, 0x01, 0xe6, 0xf2, - 0x78, 0x25, 0xda, 0xb0, 0x52, 0x67, 0x75, 0x96, 0xfc, 0xa5, 0x50, 0x8a, 0x33, 0x17, 0x80, 0xd1, - 0x57, 0x59, 0x58, 0xd8, 0x11, 0xf5, 0x3d, 0x22, 0x3f, 0xa2, 0xb2, 0xe1, 0x72, 0xdc, 0x59, 0x77, - 0x5d, 0x4e, 0x84, 0x30, 0x1e, 0xc0, 0x19, 0x97, 0x78, 0xa4, 0x8e, 0x25, 0xe3, 0x36, 0x56, 0xc1, - 0x05, 0x50, 0x06, 0x4b, 0x93, 0xd5, 0x9d, 0xb3, 0xae, 0xb9, 0x70, 0x8c, 0x9b, 0xde, 0x1a, 0xba, - 0xb0, 0x04, 0xfd, 0xd3, 0x35, 0x97, 0xeb, 0x54, 0x36, 0x5a, 0xb5, 0x8a, 0xc3, 0x9a, 0x2b, 0x4a, - 0xb8, 0xfe, 0xb5, 0x2c, 0xdc, 0x43, 0x4d, 0xbf, 0xee, 0x38, 0x9a, 0xc9, 0xba, 0x19, 0x83, 0xf4, - 0xb8, 0x3b, 0xf0, 0x66, 0x47, 0xcb, 0x89, 0xa9, 0xb3, 0x11, 0xf5, 0xdd, 0xb3, 0xae, 0x39, 0xaf, - 0xa8, 0xfb, 0x57, 0x5c, 0x81, 0x79, 0xba, 0x73, 0xfe, 0xd0, 0xe8, 0xdb, 0x2c, 0x2c, 0xee, 0x88, - 0x7a, 0xcf, 0x8b, 0xcd, 0x9e, 0x30, 0x8b, 0x74, 0x30, 0x77, 0x5f, 0xa9, 0x27, 0x0f, 0xe0, 0x4c, - 0x1b, 0x7b, 0xd4, 0x3d, 0xc7, 0x9d, 0xed, 0xe7, 0xbe, 0xb0, 0xe4, 0xb2, 0xdc, 0xf7, 0xb1, 0x17, - 0x73, 0xc7, 0x20, 0x3d, 0x5b, 0x7e, 0x00, 0xb0, 0x94, 0xb2, 0xe5, 0x7e, 0x6f, 0x7e, 0x83, 0x35, - 0x9b, 0x54, 0x08, 0xca, 0xfc, 0xc1, 0xf2, 0xc0, 0xff, 0x23, 0xef, 0x57, 0x00, 0xf3, 0x3b, 0xa2, - 0xbe, 0xdd, 0xf2, 0xdd, 0x50, 0x51, 0xcb, 0xa7, 0xf2, 0x78, 0x97, 0x31, 0xcf, 0xf8, 0x04, 0x8e, - 0xe1, 0x26, 0x6b, 0xf9, 0x72, 0x01, 0x94, 0x47, 0x96, 0xae, 0xbf, 0x3d, 0x5b, 0x49, 0xe5, 0x51, - 0x7b, 0xb5, 0xb2, 0xc1, 0xa8, 0x5f, 0x7d, 0xeb, 0x69, 0xd7, 0xcc, 0x3c, 0x79, 0x6e, 0x2e, 0x5d, - 0x42, 0x46, 0xb8, 0x41, 0x58, 0x1a, 0xd4, 0xb8, 0x07, 0x27, 0x5c, 0x12, 0x30, 0x41, 0x25, 0xe3, - 0xfa, 0x2a, 0x56, 0x87, 0xbf, 0xea, 0x04, 0x03, 0xfd, 0x36, 0x02, 0xc7, 0x76, 0x31, 0xc7, 0x4d, - 0x61, 0x1c, 0xc2, 0x1b, 0x4e, 0xef, 0x2c, 0xb6, 0xc4, 0x47, 0x91, 0x97, 0x13, 0xd5, 0xed, 0x50, - 0xec, 0x1f, 0x5d, 0xf3, 0xf6, 0x25, 0x38, 0x36, 0x89, 0x73, 0xd6, 0x35, 0xf3, 0xca, 0xf9, 0x73, - 0x60, 0xc8, 0x9a, 0x8c, 0xc7, 0xfb, 0xf8, 0xc8, 0xf8, 0x14, 0xe6, 0x6b, 0x58, 0x10, 0x3b, 0xe0, - 0x2c, 0x60, 0x82, 0x70, 0x9b, 0x47, 0xef, 0x3d, 0x3a, 0xd3, 0x44, 0x75, 0x67, 0x68, 0xce, 0x45, - 0xc5, 0x39, 0x08, 0x13, 0x59, 0x46, 0x18, 0xde, 0xd5, 0x51, 0x9d, 0x58, 0x9f, 0x01, 0x58, 0xa8, - 0x31, 0xbf, 0x25, 0x2e, 0x48, 0x18, 0x89, 0x24, 0x7c, 0x30, 0xb4, 0x84, 0x5b, 0x5a, 0xc2, 0x20, - 0x50, 0x64, 0xcd, 0x46, 0xf1, 0x3e, 0x11, 0xfb, 0xb0, 0x70, 0xae, 0xa6, 0xd8, 0xc4, 0xc7, 0x35, - 0x8f, 0xb8, 0x0b, 0xb9, 0x32, 0x58, 0x1a, 0xaf, 0x96, 0x13, 0xd4, 0x81, 0xcb, 0x90, 0x35, 0x9b, - 0x2e, 0x27, 0x5b, 0x2a, 0xba, 0x96, 0x7b, 0xf4, 0xd8, 0xcc, 0xa0, 0x2f, 0xb2, 0xb0, 0x18, 0xa7, - 0xcd, 0xbb, 0x54, 0x48, 0xc6, 0xa9, 0x83, 0x3d, 0xc5, 0x2c, 0x8c, 0x1f, 0x01, 0x9c, 0x77, 0x5a, - 0xcd, 0x96, 0x87, 0x25, 0x6d, 0x13, 0x2d, 0xd3, 0xe6, 0x58, 0x52, 0xa6, 0x9f, 0xee, 0x5c, 0xdf, - 0xd3, 0xdd, 0x24, 0x4e, 0xf4, 0x7a, 0x3f, 0x0c, 0x9d, 0x39, 0xeb, 0x9a, 0x25, 0x7d, 0xcd, 0x83, - 0x41, 0xd0, 0x93, 0xe7, 0xe6, 0x9b, 0x97, 0xf3, 0x4e, 0x3d, 0xf1, 0x42, 0x02, 0xa4, 0x34, 0x5a, - 0x21, 0x8c, 0xb1, 0x01, 0xa7, 0x39, 0x39, 0x20, 0x9c, 0xf8, 0x0e, 0xb1, 0x9d, 0x28, 0xb3, 0xc2, - 0x37, 0x72, 0xa3, 0x5a, 0x3c, 0xeb, 0x9a, 0x73, 0x4a, 0x42, 0xdf, 0x02, 0x64, 0x4d, 0xc5, 0x91, - 0x8d, 0x28, 0xf0, 0x08, 0xc0, 0xf9, 0xa4, 0x84, 0xb4, 0x38, 0x27, 0xbe, 0xec, 0x19, 0x41, 0xe0, - 0x35, 0xa5, 0x5b, 0xbc, 0xe0, 0xdc, 0x77, 0x74, 0xd6, 0x0e, 0x75, 0xaa, 0x1e, 0xb6, 0x31, 0x07, - 0xc7, 0x02, 0xc2, 0x29, 0x53, 0x4f, 0x3c, 0x67, 0xe9, 0x11, 0xfa, 0x1a, 0xc0, 0x52, 0x2c, 0x6d, - 0xdd, 0xd1, 0x26, 0x10, 0x37, 0x55, 0xe8, 0x0e, 0x21, 0x74, 0xe2, 0xd1, 0xcb, 0x10, 0x99, 0x82, - 0x47, 0xdf, 0x01, 0xb8, 0x18, 0xeb, 0xb9, 0xd7, 0x92, 0x42, 0x62, 0xdf, 0xa5, 0x7e, 0xbd, 0x67, - 0x57, 0xe7, 0xb2, 0x76, 0x6d, 0xe9, 0x67, 0x32, 0xd5, 0xbb, 0xa3, 0x68, 0x13, 0xba, 0xaa, 0x81, - 0xe8, 0x67, 0x00, 0x67, 0x63, 0x61, 0x7b, 0x1e, 0x16, 0x8d, 0xad, 0x36, 0xf1, 0xa5, 0xb1, 0x0d, - 0x93, 0xf2, 0x6c, 0x6b, 0x8b, 0xc3, 0xca, 0x95, 0xab, 0x2e, 0x26, 0x9d, 0xbb, 0x7f, 0x05, 0xb2, - 0xa6, 0xe3, 0xd0, 0x6e, 0x14, 0x31, 0xde, 0x87, 0xe3, 0x07, 0x1c, 0x3b, 0xe1, 0x17, 0x8e, 0xae, - 0x42, 0x95, 0xe1, 0x4a, 0x80, 0x15, 0xef, 0x47, 0xbf, 0x00, 0x98, 0x1f, 0xa0, 0x55, 0x18, 0x0f, - 0x01, 0x9c, 0x4b, 0xb4, 0x88, 0x70, 0xc6, 0x26, 0xd1, 0x94, 0x76, 0x73, 0xb5, 0xf2, 0x5f, 0xdf, - 0x5d, 0x95, 0x01, 0xa0, 0xd5, 0x37, 0xb4, 0xd1, 0xaf, 0xf5, 0x1f, 0x35, 0x0d, 0x8f, 0xac, 0x7c, - 0x7b, 0x80, 0x20, 0x5d, 0x2b, 0xbe, 0x07, 0xf0, 0xda, 0x36, 0x21, 0x51, 0x07, 0xfb, 0x12, 0xc0, - 0xa9, 0xa4, 0x74, 0x07, 0x8c, 0x79, 0x2f, 0xb8, 0xe8, 0xbb, 0x9a, 0xbf, 0xd0, 0x5f, 0xf6, 0xc3, - 0xbd, 0x43, 0xdf, 0x77, 0xd2, 0x83, 0x42, 0x35, 0xe8, 0x61, 0x16, 0x16, 0xcf, 0x75, 0xd8, 0xbd, - 0x80, 0xf8, 0xae, 0x2a, 0xa3, 0xd8, 0x33, 0xf2, 0x70, 0x54, 0x52, 0xe9, 0x11, 0xd5, 0xab, 0x2c, - 0x35, 0x30, 0xca, 0xf0, 0xba, 0x4b, 0x84, 0xc3, 0x69, 0x90, 0xdc, 0xa6, 0x95, 0x0e, 0x85, 0x7d, - 0x94, 0x13, 0x87, 0x06, 0x94, 0xf8, 0x32, 0x2a, 0xf8, 0x57, 0xeb, 0xa3, 0x31, 0x46, 0xaa, 0xef, - 0xe7, 0x5e, 0x42, 0xdf, 0x5f, 0x1b, 0xff, 0xfc, 0xb1, 0x99, 0x89, 0xae, 0xea, 0x6f, 0x00, 0x0b, - 0xf1, 0x47, 0xe2, 0x9e, 0xc4, 0x5c, 0x52, 0xbf, 0xfe, 0x9e, 0x7f, 0x10, 0x55, 0xca, 0x80, 0x93, - 0x36, 0x65, 0x61, 0xfb, 0x49, 0xe7, 0x41, 0xaa, 0x52, 0xf6, 0x2d, 0x40, 0xd6, 0x54, 0x2f, 0xa2, - 0xb3, 0x60, 0x1f, 0x8e, 0x0a, 0x89, 0x0f, 0x89, 0x4e, 0x81, 0x77, 0x86, 0xee, 0x82, 0x93, 0x8a, - 0x28, 0x02, 0x41, 0x96, 0x02, 0x33, 0xb6, 0xe0, 0x58, 0x83, 0xd0, 0x7a, 0x43, 0x79, 0x9d, 0xab, - 0x2e, 0xff, 0xd5, 0x35, 0xa7, 0x1d, 0x4e, 0xc2, 0x0a, 0xef, 0xdb, 0x6a, 0x2a, 0x11, 0xd9, 0x37, - 0x81, 0x2c, 0xbd, 0xb9, 0xfa, 0xfa, 0x4f, 0x27, 0x25, 0xf0, 0xf4, 0xa4, 0x04, 0x9e, 0x9d, 0x94, - 0xc0, 0x9f, 0x27, 0x25, 0xf0, 0xcd, 0x69, 0x29, 0xf3, 0xec, 0xb4, 0x94, 0xf9, 0xfd, 0xb4, 0x94, - 0xf9, 0x78, 0x34, 0x92, 0x51, 0x1b, 0x8b, 0xfe, 0xcd, 0xb8, 0xf3, 0x6f, 0x00, 0x00, 0x00, 0xff, - 0xff, 0x9c, 0x88, 0x6a, 0xf1, 0xe3, 0x0c, 0x00, 0x00, + 0x14, 0xf6, 0x38, 0x6e, 0x9a, 0x4c, 0xd3, 0xa4, 0xd9, 0xd8, 0x49, 0xe4, 0x14, 0xaf, 0x35, 0x12, + 0x55, 0x24, 0x14, 0x87, 0xd0, 0x5b, 0x0e, 0x48, 0x71, 0x7e, 0x08, 0x50, 0x43, 0xa2, 0x4d, 0x28, + 0x12, 0x12, 0x5a, 0x8d, 0x77, 0x27, 0xf6, 0x28, 0xeb, 0x9d, 0xd5, 0xcc, 0xd8, 0x4e, 0x7a, 0x41, + 0xe2, 0x04, 0x02, 0x2a, 0x0e, 0x08, 0x7a, 0xe0, 0xd0, 0x0b, 0x12, 0x54, 0xe2, 0xdf, 0x40, 0x3d, + 0xf6, 0x06, 0xe2, 0xe0, 0xa2, 0xe4, 0xc6, 0x31, 0x37, 0x38, 0xa1, 0xdd, 0x19, 0xef, 0x6e, 0x1c, + 0xab, 0x8d, 0x23, 0x95, 0x5e, 0x12, 0xef, 0x9b, 0x99, 0xef, 0xfb, 0xe6, 0x9b, 0x79, 0xef, 0xed, + 0xc2, 0xf2, 0xd1, 0xb2, 0x4b, 0x85, 0xe4, 0xb4, 0xd6, 0x92, 0x94, 0xf9, 0xcb, 0xf2, 0x38, 0x20, + 0x42, 0xfd, 0xad, 0x04, 0x9c, 0x49, 0x66, 0xdc, 0x76, 0x98, 0x68, 0x32, 0x61, 0x0b, 0xf7, 0xb0, + 0x72, 0x54, 0x49, 0x4f, 0xae, 0xb4, 0x57, 0x8a, 0x77, 0x64, 0x83, 0x72, 0xd7, 0x0e, 0x30, 0x97, + 0xc7, 0xcb, 0xd1, 0x82, 0xe5, 0x3a, 0xab, 0xb3, 0xe4, 0x97, 0x42, 0x29, 0x4e, 0x5f, 0x00, 0x46, + 0x5f, 0x67, 0x61, 0x61, 0x5b, 0xd4, 0xf7, 0x88, 0xfc, 0x98, 0xca, 0x86, 0xcb, 0x71, 0x67, 0xcd, + 0x75, 0x39, 0x11, 0xc2, 0x78, 0x00, 0xa7, 0x5d, 0xe2, 0x91, 0x3a, 0x96, 0x8c, 0xdb, 0x58, 0x05, + 0xe7, 0x41, 0x19, 0x2c, 0x4e, 0x54, 0xb7, 0xcf, 0xba, 0xe6, 0xfc, 0x31, 0x6e, 0x7a, 0xab, 0xe8, + 0xc2, 0x14, 0xf4, 0x6f, 0xd7, 0x5c, 0xaa, 0x53, 0xd9, 0x68, 0xd5, 0x2a, 0x0e, 0x6b, 0x2e, 0x2b, + 0xe1, 0xfa, 0xdf, 0x92, 0x70, 0x0f, 0x35, 0xfd, 0x9a, 0xe3, 0x68, 0x26, 0xeb, 0x56, 0x0c, 0xd2, + 0xe3, 0xee, 0xc0, 0x5b, 0x1d, 0x2d, 0x27, 0xa6, 0xce, 0x46, 0xd4, 0xf7, 0xce, 0xba, 0xe6, 0x9c, + 0xa2, 0xee, 0x9f, 0x71, 0x05, 0xe6, 0xa9, 0xce, 0xf9, 0x4d, 0xa3, 0xef, 0xb2, 0xb0, 0xb8, 0x2d, + 0xea, 0x3d, 0x2f, 0x36, 0x7a, 0xc2, 0x2c, 0xd2, 0xc1, 0xdc, 0x7d, 0xad, 0x9e, 0x3c, 0x80, 0xd3, + 0x6d, 0xec, 0x51, 0xf7, 0x1c, 0x77, 0xb6, 0x9f, 0xfb, 0xc2, 0x94, 0xcb, 0x72, 0xdf, 0xc7, 0x5e, + 0xcc, 0x1d, 0x83, 0xf4, 0x6c, 0xf9, 0x11, 0xc0, 0x52, 0xca, 0x96, 0xfb, 0xbd, 0xf1, 0x75, 0xd6, + 0x6c, 0x52, 0x21, 0x28, 0xf3, 0x07, 0xcb, 0x03, 0xff, 0x8f, 0xbc, 0xdf, 0x00, 0xcc, 0x6f, 0x8b, + 0xfa, 0x56, 0xcb, 0x77, 0x43, 0x45, 0x2d, 0x9f, 0xca, 0xe3, 0x5d, 0xc6, 0x3c, 0xe3, 0x53, 0x38, + 0x8a, 0x9b, 0xac, 0xe5, 0xcb, 0x79, 0x50, 0x1e, 0x59, 0xbc, 0xf1, 0xce, 0x4c, 0x25, 0x95, 0x47, + 0xed, 0x95, 0xca, 0x3a, 0xa3, 0x7e, 0xf5, 0xed, 0xa7, 0x5d, 0x33, 0xf3, 0xe4, 0xb9, 0xb9, 0x78, + 0x09, 0x19, 0xe1, 0x02, 0x61, 0x69, 0x50, 0x63, 0x07, 0x8e, 0xbb, 0x24, 0x60, 0x82, 0x4a, 0xc6, + 0xf5, 0x51, 0xac, 0x0c, 0x7f, 0xd4, 0x09, 0x06, 0xfa, 0x7d, 0x04, 0x8e, 0xee, 0x62, 0x8e, 0x9b, + 0xc2, 0x38, 0x84, 0x37, 0x9d, 0xde, 0x5e, 0x6c, 0x89, 0x8f, 0x22, 0x2f, 0xc7, 0xab, 0x5b, 0xa1, + 0xd8, 0x3f, 0xbb, 0xe6, 0x9d, 0x4b, 0x70, 0x6c, 0x10, 0xe7, 0xac, 0x6b, 0xe6, 0x95, 0xf3, 0xe7, + 0xc0, 0x90, 0x35, 0x11, 0x3f, 0xef, 0xe3, 0x23, 0xe3, 0x33, 0x98, 0xaf, 0x61, 0x41, 0xec, 0x80, + 0xb3, 0x80, 0x09, 0xc2, 0x6d, 0x1e, 0xdd, 0xf7, 0x68, 0x4f, 0xe3, 0xd5, 0xed, 0xa1, 0x39, 0x17, + 0x14, 0xe7, 0x20, 0x4c, 0x64, 0x19, 0x61, 0x78, 0x57, 0x47, 0x75, 0x62, 0x7d, 0x0e, 0x60, 0xa1, + 0xc6, 0xfc, 0x96, 0xb8, 0x20, 0x61, 0x24, 0x92, 0xf0, 0xe1, 0xd0, 0x12, 0x6e, 0x6b, 0x09, 0x83, + 0x40, 0x91, 0x35, 0x13, 0xc5, 0xfb, 0x44, 0xec, 0xc3, 0xc2, 0xb9, 0x9a, 0x62, 0x13, 0x1f, 0xd7, + 0x3c, 0xe2, 0xce, 0xe7, 0xca, 0x60, 0x71, 0xac, 0x5a, 0x4e, 0x50, 0x07, 0x4e, 0x43, 0xd6, 0x4c, + 0xba, 0x9c, 0x6c, 0xaa, 0xe8, 0x6a, 0xee, 0xd1, 0x63, 0x33, 0x83, 0xbe, 0xcc, 0xc2, 0x62, 0x9c, + 0x36, 0xef, 0x51, 0x21, 0x19, 0xa7, 0x0e, 0xf6, 0x14, 0xb3, 0x30, 0x7e, 0x02, 0x70, 0xce, 0x69, + 0x35, 0x5b, 0x1e, 0x96, 0xb4, 0x4d, 0xb4, 0x4c, 0x9b, 0x63, 0x49, 0x99, 0xbe, 0xba, 0xb3, 0x7d, + 0x57, 0x77, 0x83, 0x38, 0xd1, 0xed, 0xfd, 0x28, 0x74, 0xe6, 0xac, 0x6b, 0x96, 0xf4, 0x31, 0x0f, + 0x06, 0x41, 0x4f, 0x9e, 0x9b, 0x6f, 0x5d, 0xce, 0x3b, 0x75, 0xc5, 0x0b, 0x09, 0x90, 0xd2, 0x68, + 0x85, 0x30, 0xc6, 0x3a, 0x9c, 0xe2, 0xe4, 0x80, 0x70, 0xe2, 0x3b, 0xc4, 0x76, 0xa2, 0xcc, 0x0a, + 0xef, 0xc8, 0xcd, 0x6a, 0xf1, 0xac, 0x6b, 0xce, 0x2a, 0x09, 0x7d, 0x13, 0x90, 0x35, 0x19, 0x47, + 0xd6, 0xa3, 0xc0, 0x23, 0x00, 0xe7, 0x92, 0x12, 0xd2, 0xe2, 0x9c, 0xf8, 0xb2, 0x67, 0x04, 0x81, + 0xd7, 0x95, 0x6e, 0xf1, 0x92, 0x7d, 0xdf, 0xd5, 0x59, 0x3b, 0xd4, 0xae, 0x7a, 0xd8, 0xc6, 0x2c, + 0x1c, 0x0d, 0x08, 0xa7, 0x4c, 0x5d, 0xf1, 0x9c, 0xa5, 0x9f, 0xd0, 0x37, 0x00, 0x96, 0x62, 0x69, + 0x6b, 0x8e, 0x36, 0x81, 0xb8, 0xa9, 0x42, 0x77, 0x08, 0xa1, 0x13, 0x3f, 0xbd, 0x0a, 0x91, 0x29, + 0x78, 0xf4, 0x3d, 0x80, 0x0b, 0xb1, 0x9e, 0x9d, 0x96, 0x14, 0x12, 0xfb, 0x2e, 0xf5, 0xeb, 0x3d, + 0xbb, 0x3a, 0x97, 0xb5, 0x6b, 0x53, 0x5f, 0x93, 0xc9, 0xde, 0x19, 0x45, 0x8b, 0xd0, 0x55, 0x0d, + 0x44, 0xbf, 0x00, 0x38, 0x13, 0x0b, 0xdb, 0xf3, 0xb0, 0x68, 0x6c, 0xb6, 0x89, 0x2f, 0x8d, 0x2d, + 0x98, 0x94, 0x67, 0x5b, 0x5b, 0x1c, 0x56, 0xae, 0x5c, 0x75, 0x21, 0xe9, 0xdc, 0xfd, 0x33, 0x90, + 0x35, 0x15, 0x87, 0x76, 0xa3, 0x88, 0xf1, 0x01, 0x1c, 0x3b, 0xe0, 0xd8, 0x09, 0xdf, 0x70, 0x74, + 0x15, 0xaa, 0x0c, 0x57, 0x02, 0xac, 0x78, 0x3d, 0xfa, 0x15, 0xc0, 0xfc, 0x00, 0xad, 0xc2, 0x78, + 0x08, 0xe0, 0x6c, 0xa2, 0x45, 0x84, 0x23, 0x36, 0x89, 0x86, 0xb4, 0x9b, 0x2b, 0x95, 0x17, 0xbd, + 0x77, 0x55, 0x06, 0x80, 0x56, 0xdf, 0xd4, 0x46, 0xbf, 0xd1, 0xbf, 0xd5, 0x34, 0x3c, 0xb2, 0xf2, + 0xed, 0x01, 0x82, 0x74, 0xad, 0xf8, 0x01, 0xc0, 0xeb, 0x5b, 0x84, 0x44, 0x1d, 0xec, 0x2b, 0x00, + 0x27, 0x93, 0xd2, 0x1d, 0x30, 0xe6, 0xbd, 0xe4, 0xa0, 0xef, 0x69, 0xfe, 0x42, 0x7f, 0xd9, 0x0f, + 0xd7, 0x0e, 0x7d, 0xde, 0x49, 0x0f, 0x0a, 0xd5, 0xa0, 0x87, 0x59, 0x58, 0x3c, 0xd7, 0x61, 0xf7, + 0x02, 0xe2, 0xbb, 0xaa, 0x8c, 0x62, 0xcf, 0xc8, 0xc3, 0x6b, 0x92, 0x4a, 0x8f, 0xa8, 0x5e, 0x65, + 0xa9, 0x07, 0xa3, 0x0c, 0x6f, 0xb8, 0x44, 0x38, 0x9c, 0x06, 0xc9, 0x69, 0x5a, 0xe9, 0x50, 0xd8, + 0x47, 0x39, 0x71, 0x68, 0x40, 0x89, 0x2f, 0xa3, 0x82, 0x7f, 0xb5, 0x3e, 0x1a, 0x63, 0xa4, 0xfa, + 0x7e, 0xee, 0x15, 0xf4, 0xfd, 0xd5, 0xb1, 0x2f, 0x1e, 0x9b, 0x99, 0xe8, 0xa8, 0xfe, 0x01, 0xb0, + 0x10, 0xbf, 0x24, 0xee, 0x49, 0xcc, 0x25, 0xf5, 0xeb, 0xef, 0xfb, 0x07, 0x51, 0xa5, 0x0c, 0x38, + 0x69, 0x53, 0x16, 0xb6, 0x9f, 0x74, 0x1e, 0xa4, 0x2a, 0x65, 0xdf, 0x04, 0x64, 0x4d, 0xf6, 0x22, + 0x3a, 0x0b, 0xf6, 0xe1, 0x35, 0x21, 0xf1, 0x21, 0xd1, 0x29, 0xf0, 0xee, 0xd0, 0x5d, 0x70, 0x42, + 0x11, 0x45, 0x20, 0xc8, 0x52, 0x60, 0xc6, 0x26, 0x1c, 0x6d, 0x10, 0x5a, 0x6f, 0x28, 0xaf, 0x73, + 0xd5, 0xa5, 0xbf, 0xbb, 0xe6, 0x94, 0xc3, 0x49, 0x58, 0xe1, 0x7d, 0x5b, 0x0d, 0x25, 0x22, 0xfb, + 0x06, 0x90, 0xa5, 0x17, 0x57, 0x77, 0x7e, 0x3e, 0x29, 0x81, 0xa7, 0x27, 0x25, 0xf0, 0xec, 0xa4, + 0x04, 0xfe, 0x3a, 0x29, 0x81, 0x6f, 0x4f, 0x4b, 0x99, 0x67, 0xa7, 0xa5, 0xcc, 0x1f, 0xa7, 0xa5, + 0xcc, 0x27, 0x2b, 0x2f, 0xd4, 0x38, 0xe8, 0x83, 0xa7, 0x36, 0x1a, 0x7d, 0x92, 0xdc, 0xfd, 0x2f, + 0x00, 0x00, 0xff, 0xff, 0x34, 0x5a, 0x18, 0x60, 0x0f, 0x0d, 0x00, 0x00, } func (this *MsgSetWithdrawAddress) Equal(that interface{}) bool { diff --git a/x/distribution/types/types.proto b/x/distribution/types/types.proto index aade33d9dd0f..db6c4e907a00 100644 --- a/x/distribution/types/types.proto +++ b/x/distribution/types/types.proto @@ -1,7 +1,7 @@ syntax = "proto3"; package cosmos_sdk.x.distribution.v1; -option go_package = "types"; +option go_package = "github.com/cosmos/cosmos-sdk/x/distribution/types"; option (gogoproto.equal_all) = true; import "third_party/proto/gogoproto/gogo.proto"; From 81735debe58322dd4e5515d3fc63d1ec7a74fd7c Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Wed, 26 Feb 2020 20:47:45 -0500 Subject: [PATCH 258/529] Fix proposal marshaling, make Proposal extend ProposalBase --- simapp/codec/codec.go | 11 ++++++----- x/gov/types/proposal.go | 29 ++++++++++------------------- x/gov/types/types.proto | 27 +++++++++++++++++++-------- 3 files changed, 35 insertions(+), 32 deletions(-) diff --git a/simapp/codec/codec.go b/simapp/codec/codec.go index 0c9f910e6f65..284e934e9e69 100644 --- a/simapp/codec/codec.go +++ b/simapp/codec/codec.go @@ -161,16 +161,17 @@ func (c *Codec) MarshalProposal(p types.Proposal) ([]byte, error) { return c.Marshaler.MarshalBinaryBare(stdProposal) } -func (c *Codec) UnmarshalProposal(bz []byte) (types.Proposal, error) { +func (c *Codec) UnmarshalProposal(bz []byte, p *types.Proposal) error { stdProposal := &cosmos_sdk_x_v1.StdProposal{} if err := c.Marshaler.UnmarshalBinaryLengthPrefixed(bz, stdProposal); err != nil { - return nil, err + return err } - return types.Proposal{ - //Content: stdProposal.Content.GetContent(), + *p = types.Proposal{ + Content: stdProposal.Content.GetContent(), ProposalBase: stdProposal.ProposalBase, - }, nil + } + return nil } // ---------------------------------------------------------------------------- diff --git a/x/gov/types/proposal.go b/x/gov/types/proposal.go index 66658cd67063..15d23ddf7651 100644 --- a/x/gov/types/proposal.go +++ b/x/gov/types/proposal.go @@ -17,29 +17,21 @@ const DefaultStartingProposalID uint64 = 1 // on network changes. type Proposal struct { Content `json:"content" yaml:"content"` // Proposal content interface - - ProposalID uint64 `json:"id" yaml:"id"` // ID of the proposal - Status ProposalStatus `json:"proposal_status" yaml:"proposal_status"` // Status of the Proposal {Pending, Active, Passed, Rejected} - FinalTallyResult TallyResult `json:"final_tally_result" yaml:"final_tally_result"` // Result of Tallys - - SubmitTime time.Time `json:"submit_time" yaml:"submit_time"` // Time of the block where TxGovSubmitProposal was included - DepositEndTime time.Time `json:"deposit_end_time" yaml:"deposit_end_time"` // Time that the Proposal would expire if deposit amount isn't met - TotalDeposit sdk.Coins `json:"total_deposit" yaml:"total_deposit"` // Current deposit on this proposal. Initial value is set at InitialDeposit - - VotingStartTime time.Time `json:"voting_start_time" yaml:"voting_start_time"` // Time of the block where MinDeposit was reached. -1 if MinDeposit is not reached - VotingEndTime time.Time `json:"voting_end_time" yaml:"voting_end_time"` // Time that the VotingPeriod for this proposal will end and votes will be tallied + ProposalBase } // NewProposal creates a new Proposal instance func NewProposal(content Content, id uint64, submitTime, depositEndTime time.Time) Proposal { return Proposal{ - Content: content, - ProposalID: id, - Status: StatusDepositPeriod, - FinalTallyResult: EmptyTallyResult(), - TotalDeposit: sdk.NewCoins(), - SubmitTime: submitTime, - DepositEndTime: depositEndTime, + Content: content, + ProposalBase: ProposalBase{ + ProposalID: id, + Status: StatusDepositPeriod, + FinalTallyResult: EmptyTallyResult(), + TotalDeposit: sdk.NewCoins(), + SubmitTime: submitTime, + DepositEndTime: depositEndTime, + }, } } @@ -78,7 +70,6 @@ func (p Proposals) String() string { type ( // ProposalQueue defines a queue for proposal ids ProposalQueue []uint64 - ) // ProposalStatusFromString turns a string into a ProposalStatus diff --git a/x/gov/types/types.proto b/x/gov/types/types.proto index 0eaa5c60bd4b..967b847d56af 100644 --- a/x/gov/types/types.proto +++ b/x/gov/types/types.proto @@ -69,14 +69,25 @@ message ProposalBase { option (gogoproto.goproto_stringer) = true; option (gogoproto.face) = true; uint64 proposal_id = 1 [(gogoproto.customname) = "ProposalID" - ,(gogoproto.moretags) = "yaml:\"proposal_id\""]; - ProposalStatus status = 2; - TallyResult final_tally_result = 3 [(gogoproto.nullable) = false]; - google.protobuf.Timestamp submit_time = 4 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false]; - google.protobuf.Timestamp deposit_end_time = 5 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false]; - repeated cosmos_sdk.v1.Coin total_deposit = 6 [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; - google.protobuf.Timestamp voting_start_time = 7 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false]; - google.protobuf.Timestamp voting_end_time = 8 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false]; + ,(gogoproto.moretags) = "yaml:\"id\""]; + ProposalStatus status = 2 [(gogoproto.moretags) = "yaml:\"proposal_status\""]; + TallyResult final_tally_result = 3 [(gogoproto.nullable) = false + ,(gogoproto.moretags) = "yaml:\"final_tally_result\""]; + google.protobuf.Timestamp submit_time = 4 [(gogoproto.stdtime) = true + ,(gogoproto.nullable) = false + ,(gogoproto.moretags) = "yaml:\"submit_time\""]; + google.protobuf.Timestamp deposit_end_time = 5 [(gogoproto.stdtime) = true + ,(gogoproto.nullable) = false + ,(gogoproto.moretags) = "yaml:\"deposit_end_time\""]; + repeated cosmos_sdk.v1.Coin total_deposit = 6 [(gogoproto.nullable) = false + ,(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + ,(gogoproto.moretags) = "yaml:\"total_deposit\""]; + google.protobuf.Timestamp voting_start_time = 7 [(gogoproto.stdtime) = true + ,(gogoproto.nullable) = false + ,(gogoproto.moretags) = "yaml:\"voting_start_time\""]; + google.protobuf.Timestamp voting_end_time = 8 [(gogoproto.stdtime) = true + ,(gogoproto.nullable) = false + ,(gogoproto.moretags) = "yaml:\"voting_end_time\""]; } // ProposalStatus is a type alias that represents a proposal status as a byte From 2b75f506044665e682dbec9138bfac88e51f4079 Mon Sep 17 00:00:00 2001 From: Anthony Date: Thu, 27 Feb 2020 14:37:16 +0700 Subject: [PATCH 259/529] Merge PR #5708: fix type for the event documentation --- docs/core/events.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/core/events.md b/docs/core/events.md index 359e2b94a40e..d5ac5893f062 100644 --- a/docs/core/events.md +++ b/docs/core/events.md @@ -16,7 +16,7 @@ various messages and index transactions." Events are implemented in the Cosmos SDK as an alias of the ABCI `Event` type and take the form of: `{eventType}.{eventAttribute}={value}`. -+++ https://github.com/tendermint/tendermint/blob/bc572217c07b90ad9cee851f193aaa8e9557cbc7/abci/types/types.pb.go#L2661-L2667 ++++ https://github.com/tendermint/tendermint/blob/bc572217c07b90ad9cee851f193aaa8e9557cbc7/abci/types/types.pb.go#L2187-L2193 Events contain: From 8227d9e376e0bbedb2a3d3f3933e012cbe3cf709 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 26 Feb 2020 23:47:05 -0800 Subject: [PATCH 260/529] Bump github.com/golang/protobuf from 1.3.3 to 1.3.4 (#5707) Bumps [github.com/golang/protobuf](https://github.com/golang/protobuf) from 1.3.3 to 1.3.4. - [Release notes](https://github.com/golang/protobuf/releases) - [Commits](https://github.com/golang/protobuf/compare/v1.3.3...v1.3.4) Signed-off-by: dependabot-preview[bot] Co-authored-by: Alexander Bezobchuk --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 1ebba790a592..d9debb5a73c0 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/cosmos/ledger-cosmos-go v0.11.1 github.com/gogo/protobuf v1.3.1 github.com/golang/mock v1.3.1-0.20190508161146-9fa652df1129 - github.com/golang/protobuf v1.3.3 + github.com/golang/protobuf v1.3.4 github.com/gorilla/handlers v1.4.2 github.com/gorilla/mux v1.7.4 github.com/hashicorp/golang-lru v0.5.4 diff --git a/go.sum b/go.sum index c4f48196d418..7eeaf96559e5 100644 --- a/go.sum +++ b/go.sum @@ -95,6 +95,8 @@ github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4 h1:87PNWwrRvUSnqS4dlcBU/ftvOIBep4sYuBLlh6rX2wk= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= From 5a2e59ebb23d1d23546f1145d8814a457655935a Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Thu, 27 Feb 2020 10:53:22 +0000 Subject: [PATCH 261/529] Exclude proto files from format (#5706) * Don't change proto files on make format The format target does not need to depend on tools. Thus remove dependency. * Run make format Co-authored-by: Alexander Bezobchuk --- Makefile | 8 ++++---- client/cmd_test.go | 6 +++--- codec/amino_codec_test.go | 5 +++-- codec/hybrid_codec_test.go | 3 ++- codec/proto_codec_test.go | 3 ++- types/address_bench_test.go | 3 ++- types/decimal_test.go | 3 ++- x/bank/client/rest/rest.go | 3 ++- x/bank/types/key_test.go | 3 ++- x/params/keeper/common_test.go | 7 ++++--- x/params/keeper/keeper_test.go | 3 ++- x/params/types/table_test.go | 3 ++- x/staking/types/commission.go | 3 ++- x/staking/types/delegation.go | 3 ++- x/staking/types/params.go | 3 ++- x/upgrade/client/cli/query.go | 1 + x/upgrade/keeper/keeper.go | 1 + x/upgrade/keeper/querier.go | 1 + 18 files changed, 39 insertions(+), 23 deletions(-) diff --git a/Makefile b/Makefile index 96f04d16a8f6..68d7a359abca 100644 --- a/Makefile +++ b/Makefile @@ -191,10 +191,10 @@ lint: go mod verify .PHONY: lint -format: tools - find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" -not -path "./client/lcd/statik/statik.go" | xargs gofmt -w -s - find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" -not -path "./client/lcd/statik/statik.go" | xargs misspell -w - find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" -not -path "./client/lcd/statik/statik.go" | xargs goimports -w -local github.com/cosmos/cosmos-sdk +format: + find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" -not -path "./client/lcd/statik/statik.go" -not -name '*.pb.go' | xargs gofmt -w -s + find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" -not -path "./client/lcd/statik/statik.go" -not -name '*.pb.go' | xargs misspell -w + find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" -not -path "./client/lcd/statik/statik.go" -not -name '*.pb.go' | xargs goimports -w -local github.com/cosmos/cosmos-sdk .PHONY: format ############################################################################### diff --git a/client/cmd_test.go b/client/cmd_test.go index 675cc296aeb4..554d39953730 100644 --- a/client/cmd_test.go +++ b/client/cmd_test.go @@ -37,10 +37,10 @@ func TestValidateCmd(t *testing.T) { args []string wantErr bool }{ - {"misspelled command", []string{"comission"}, true}, // nolint: misspell + {"misspelled command", []string{"commission"}, true}, // nolint: misspell {"no command provided", []string{}, false}, - {"help flag", []string{"comission", "--help"}, false}, // nolint: misspell - {"shorthand help flag", []string{"comission", "-h"}, false}, // nolint: misspell + {"help flag", []string{"commission", "--help"}, false}, // nolint: misspell + {"shorthand help flag", []string{"commission", "-h"}, false}, // nolint: misspell } for _, tt := range tests { diff --git a/codec/amino_codec_test.go b/codec/amino_codec_test.go index 31eeb413e828..3836b22d38a6 100644 --- a/codec/amino_codec_test.go +++ b/codec/amino_codec_test.go @@ -3,10 +3,11 @@ package codec_test import ( "testing" - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/codec/testdata" "github.com/stretchr/testify/require" amino "github.com/tendermint/go-amino" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/testdata" ) func createTestCodec() *amino.Codec { diff --git a/codec/hybrid_codec_test.go b/codec/hybrid_codec_test.go index 353f0c389643..911ae8c9d9f6 100644 --- a/codec/hybrid_codec_test.go +++ b/codec/hybrid_codec_test.go @@ -3,9 +3,10 @@ package codec_test import ( "testing" + "github.com/stretchr/testify/require" + "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec/testdata" - "github.com/stretchr/testify/require" ) func TestHybridCodec(t *testing.T) { diff --git a/codec/proto_codec_test.go b/codec/proto_codec_test.go index c49544e060f1..aae71b4dfd18 100644 --- a/codec/proto_codec_test.go +++ b/codec/proto_codec_test.go @@ -3,9 +3,10 @@ package codec_test import ( "testing" + "github.com/stretchr/testify/require" + "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec/testdata" - "github.com/stretchr/testify/require" ) func TestProtoCodec(t *testing.T) { diff --git a/types/address_bench_test.go b/types/address_bench_test.go index 8e438a81dacd..1bb0d15f6153 100644 --- a/types/address_bench_test.go +++ b/types/address_bench_test.go @@ -5,9 +5,10 @@ import ( "testing" "time" - "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" + "github.com/cosmos/cosmos-sdk/types" + "github.com/tendermint/tendermint/crypto/ed25519" ) diff --git a/types/decimal_test.go b/types/decimal_test.go index c56d303ee1e4..33ca99d49835 100644 --- a/types/decimal_test.go +++ b/types/decimal_test.go @@ -6,10 +6,11 @@ import ( "math/big" "testing" - "github.com/cosmos/cosmos-sdk/codec" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" yaml "gopkg.in/yaml.v2" + + "github.com/cosmos/cosmos-sdk/codec" ) // create a decimal from a decimal string (ex. "1234.5678") diff --git a/x/bank/client/rest/rest.go b/x/bank/client/rest/rest.go index b2b1ff84c894..578e41c06712 100644 --- a/x/bank/client/rest/rest.go +++ b/x/bank/client/rest/rest.go @@ -1,8 +1,9 @@ package rest import ( - "github.com/cosmos/cosmos-sdk/client/context" "github.com/gorilla/mux" + + "github.com/cosmos/cosmos-sdk/client/context" ) // RegisterRoutes - Central function to define routes that get registered by the main application diff --git a/x/bank/types/key_test.go b/x/bank/types/key_test.go index b1e5a7614106..f3b5717fbecb 100644 --- a/x/bank/types/key_test.go +++ b/x/bank/types/key_test.go @@ -3,9 +3,10 @@ package types_test import ( "testing" + "github.com/stretchr/testify/require" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/bank/types" - "github.com/stretchr/testify/require" ) func cloneAppend(bz []byte, tail []byte) (res []byte) { diff --git a/x/params/keeper/common_test.go b/x/params/keeper/common_test.go index 92d9f1ee5660..c6c151809c37 100644 --- a/x/params/keeper/common_test.go +++ b/x/params/keeper/common_test.go @@ -1,14 +1,15 @@ package keeper_test import ( + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/libs/log" + dbm "github.com/tendermint/tm-db" + "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper" "github.com/cosmos/cosmos-sdk/x/params/types/proposal" - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/libs/log" - dbm "github.com/tendermint/tm-db" ) func testComponents() (codec.Marshaler, sdk.Context, sdk.StoreKey, sdk.StoreKey, paramskeeper.Keeper) { diff --git a/x/params/keeper/keeper_test.go b/x/params/keeper/keeper_test.go index 0c34558e9ff8..de83f1f344c8 100644 --- a/x/params/keeper/keeper_test.go +++ b/x/params/keeper/keeper_test.go @@ -4,10 +4,11 @@ import ( "reflect" "testing" + "github.com/stretchr/testify/require" + "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/params/types" - "github.com/stretchr/testify/require" ) func validateNoOp(_ interface{}) error { return nil } diff --git a/x/params/types/table_test.go b/x/params/types/table_test.go index db2c9d321544..0baff40f8c6c 100644 --- a/x/params/types/table_test.go +++ b/x/params/types/table_test.go @@ -4,8 +4,9 @@ import ( "testing" "time" - "github.com/cosmos/cosmos-sdk/x/params/types" "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/x/params/types" ) func TestKeyTable(t *testing.T) { diff --git a/x/staking/types/commission.go b/x/staking/types/commission.go index 9a58210f612e..54891b5dcac3 100644 --- a/x/staking/types/commission.go +++ b/x/staking/types/commission.go @@ -3,8 +3,9 @@ package types import ( "time" - sdk "github.com/cosmos/cosmos-sdk/types" yaml "gopkg.in/yaml.v2" + + sdk "github.com/cosmos/cosmos-sdk/types" ) // NewCommissionRates returns an initialized validator commission rates. diff --git a/x/staking/types/delegation.go b/x/staking/types/delegation.go index f25aaac7b22a..51fca1d38e48 100644 --- a/x/staking/types/delegation.go +++ b/x/staking/types/delegation.go @@ -6,10 +6,11 @@ import ( "strings" "time" + yaml "gopkg.in/yaml.v2" + "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/staking/exported" - yaml "gopkg.in/yaml.v2" ) // Implements Delegation interface diff --git a/x/staking/types/params.go b/x/staking/types/params.go index b738f1b06ea6..8d2b14ec694e 100644 --- a/x/staking/types/params.go +++ b/x/staking/types/params.go @@ -6,10 +6,11 @@ import ( "strings" "time" + yaml "gopkg.in/yaml.v2" + "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" - yaml "gopkg.in/yaml.v2" ) // Staking params default values diff --git a/x/upgrade/client/cli/query.go b/x/upgrade/client/cli/query.go index c9022a4824bd..390ed9e5de68 100644 --- a/x/upgrade/client/cli/query.go +++ b/x/upgrade/client/cli/query.go @@ -3,6 +3,7 @@ package cli import ( "encoding/binary" "fmt" + "github.com/cosmos/cosmos-sdk/x/upgrade/types" "github.com/spf13/cobra" diff --git a/x/upgrade/keeper/keeper.go b/x/upgrade/keeper/keeper.go index 03802b335c5d..ba789aeb7b77 100644 --- a/x/upgrade/keeper/keeper.go +++ b/x/upgrade/keeper/keeper.go @@ -3,6 +3,7 @@ package keeper import ( "encoding/binary" "fmt" + "github.com/cosmos/cosmos-sdk/x/upgrade/types" "github.com/tendermint/tendermint/libs/log" diff --git a/x/upgrade/keeper/querier.go b/x/upgrade/keeper/querier.go index 2a3ff8bf6dff..2aebceeac0f8 100644 --- a/x/upgrade/keeper/querier.go +++ b/x/upgrade/keeper/querier.go @@ -2,6 +2,7 @@ package keeper import ( "encoding/binary" + "github.com/cosmos/cosmos-sdk/x/upgrade/types" abci "github.com/tendermint/tendermint/abci/types" From ae14edc90089497efd194feaa5c037913b11b2bc Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Thu, 27 Feb 2020 12:01:27 +0100 Subject: [PATCH 262/529] add pre run command to check for prunning options --- server/start.go | 40 ++++++++++++++----- server/start_test.go | 94 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+), 10 deletions(-) create mode 100644 server/start_test.go diff --git a/server/start.go b/server/start.go index 5a9cd0500884..7d7b40e46a00 100644 --- a/server/start.go +++ b/server/start.go @@ -20,18 +20,23 @@ import ( // Tendermint full-node start flags const ( - flagWithTendermint = "with-tendermint" - flagAddress = "address" - flagTraceStore = "trace-store" - flagPruning = "pruning" - flagCPUProfile = "cpu-profile" - FlagMinGasPrices = "minimum-gas-prices" - FlagHaltHeight = "halt-height" - FlagHaltTime = "halt-time" - FlagInterBlockCache = "inter-block-cache" - FlagUnsafeSkipUpgrades = "unsafe-skip-upgrades" + flagWithTendermint = "with-tendermint" + flagAddress = "address" + flagTraceStore = "trace-store" + flagPruning = "pruning" + flagPruningKeepEvery = "pruning-keep-every" + flagPruningSnapshotEvery = "pruning-snapshot-every" + flagCPUProfile = "cpu-profile" + FlagMinGasPrices = "minimum-gas-prices" + FlagHaltHeight = "halt-height" + FlagHaltTime = "halt-time" + FlagInterBlockCache = "inter-block-cache" + FlagUnsafeSkipUpgrades = "unsafe-skip-upgrades" ) +var errPruningWithGranularOptions = fmt.Errorf("%s flag is not compatible with granular options as %s or %s", flagPruning, flagPruningKeepEvery, flagPruningSnapshotEvery) +var errPruningGranularOptions = fmt.Errorf("%s and %s must be set together", flagPruningSnapshotEvery, flagPruningKeepEvery) + // StartCmd runs the service passed in, either stand-alone or in-process with // Tendermint. func StartCmd(ctx *Context, appCreator AppCreator) *cobra.Command { @@ -56,6 +61,21 @@ will not be able to commit subsequent blocks. For profiling and benchmarking purposes, CPU profiling can be enabled via the '--cpu-profile' flag which accepts a path for the resulting pprof file. `, + PreRunE: func(cmd *cobra.Command, args []string) error { + if viper.IsSet(flagPruning) { + if viper.IsSet(flagPruningKeepEvery) || viper.IsSet(flagPruningSnapshotEvery) { + return errPruningWithGranularOptions + } + + return nil + } + + if !(viper.IsSet(flagPruningKeepEvery) && viper.IsSet(flagPruningSnapshotEvery)) { + return errPruningGranularOptions + } + + return nil + }, RunE: func(cmd *cobra.Command, args []string) error { if !viper.GetBool(flagWithTendermint) { ctx.Logger.Info("starting ABCI without Tendermint") diff --git a/server/start_test.go b/server/start_test.go new file mode 100644 index 000000000000..cd7c6b6ae14b --- /dev/null +++ b/server/start_test.go @@ -0,0 +1,94 @@ +package server + +import ( + "testing" + + "github.com/spf13/viper" + "github.com/stretchr/testify/require" +) + +func TestPruningOptions(t *testing.T) { + startCommand := StartCmd(nil, nil) + + tests := []struct { + name string + paramInit func() + returnsErr bool + expectedErr error + }{ + { + name: "only keep-every provided", + paramInit: func() { + viper.Set(flagPruningKeepEvery, 12345) + }, + returnsErr: true, + expectedErr: errPruningGranularOptions, + }, + { + name: "only snapshot-every provided", + paramInit: func() { + viper.Set(flagPruningSnapshotEvery, 12345) + }, + returnsErr: true, + expectedErr: errPruningGranularOptions, + }, + { + name: "pruning flag with other granular options 1", + paramInit: func() { + viper.Set(flagPruning, "set") + viper.Set(flagPruningSnapshotEvery, 1234) + }, + returnsErr: true, + expectedErr: errPruningWithGranularOptions, + }, + { + name: "pruning flag with other granular options 2", + paramInit: func() { + viper.Set(flagPruning, "set") + viper.Set(flagPruningKeepEvery, 1234) + }, + returnsErr: true, + expectedErr: errPruningWithGranularOptions, + }, + { + name: "pruning flag with other granular options 3", + paramInit: func() { + viper.Set(flagPruning, "set") + viper.Set(flagPruningKeepEvery, 1234) + viper.Set(flagPruningSnapshotEvery, 1234) + }, + returnsErr: true, + expectedErr: errPruningWithGranularOptions, + }, + { + name: "only prunning set", + paramInit: func() { + viper.Set(flagPruning, "set") + }, + returnsErr: false, + expectedErr: nil, + }, + { + name: "only granular set", + paramInit: func() { + viper.Set(flagPruningSnapshotEvery, 12345) + viper.Set(flagPruningKeepEvery, 12345) + }, + returnsErr: false, + expectedErr: nil, + }, + } + + for _, tt := range tests { + viper.Reset() + tt.paramInit() + + err := startCommand.PreRunE(nil, nil) + + if tt.returnsErr { + require.EqualError(t, err, tt.expectedErr.Error()) + } else { + require.NoError(t, err) + } + } +} From 0d8dade5e2172ff52f4b6a0cdbbbc8433a683645 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Thu, 27 Feb 2020 12:18:21 +0100 Subject: [PATCH 263/529] add case for none set --- server/start.go | 5 +++++ server/start_test.go | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/server/start.go b/server/start.go index 7d7b40e46a00..f3e8253e7bf7 100644 --- a/server/start.go +++ b/server/start.go @@ -36,6 +36,7 @@ const ( var errPruningWithGranularOptions = fmt.Errorf("%s flag is not compatible with granular options as %s or %s", flagPruning, flagPruningKeepEvery, flagPruningSnapshotEvery) var errPruningGranularOptions = fmt.Errorf("%s and %s must be set together", flagPruningSnapshotEvery, flagPruningKeepEvery) +var errPruningOptionsRequired = fmt.Errorf("pruning options required") // StartCmd runs the service passed in, either stand-alone or in-process with // Tendermint. @@ -62,6 +63,10 @@ For profiling and benchmarking purposes, CPU profiling can be enabled via the '- which accepts a path for the resulting pprof file. `, PreRunE: func(cmd *cobra.Command, args []string) error { + if !viper.IsSet(flagPruning) && !viper.IsSet(flagPruningKeepEvery) && !viper.IsSet(flagPruningSnapshotEvery) { + return errPruningOptionsRequired + } + if viper.IsSet(flagPruning) { if viper.IsSet(flagPruningKeepEvery) || viper.IsSet(flagPruningSnapshotEvery) { return errPruningWithGranularOptions diff --git a/server/start_test.go b/server/start_test.go index cd7c6b6ae14b..a61a31852b4a 100644 --- a/server/start_test.go +++ b/server/start_test.go @@ -16,6 +16,12 @@ func TestPruningOptions(t *testing.T) { returnsErr bool expectedErr error }{ + { + name: "none set", + paramInit: func() {}, + returnsErr: true, + expectedErr: errPruningOptionsRequired, + }, { name: "only keep-every provided", paramInit: func() { From a6cd6554ecb4966eafdf77654b4899a0e773a914 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Thu, 27 Feb 2020 12:30:24 +0100 Subject: [PATCH 264/529] extract to function logic to check pruning params --- server/start.go | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/server/start.go b/server/start.go index f3e8253e7bf7..4749edf63378 100644 --- a/server/start.go +++ b/server/start.go @@ -63,23 +63,7 @@ For profiling and benchmarking purposes, CPU profiling can be enabled via the '- which accepts a path for the resulting pprof file. `, PreRunE: func(cmd *cobra.Command, args []string) error { - if !viper.IsSet(flagPruning) && !viper.IsSet(flagPruningKeepEvery) && !viper.IsSet(flagPruningSnapshotEvery) { - return errPruningOptionsRequired - } - - if viper.IsSet(flagPruning) { - if viper.IsSet(flagPruningKeepEvery) || viper.IsSet(flagPruningSnapshotEvery) { - return errPruningWithGranularOptions - } - - return nil - } - - if !(viper.IsSet(flagPruningKeepEvery) && viper.IsSet(flagPruningSnapshotEvery)) { - return errPruningGranularOptions - } - - return nil + return checkPruningParams() }, RunE: func(cmd *cobra.Command, args []string) error { if !viper.GetBool(flagWithTendermint) { @@ -114,6 +98,27 @@ which accepts a path for the resulting pprof file. return cmd } +// checkPruningParams checks that the provided pruning params are correct +func checkPruningParams() error { + if !viper.IsSet(flagPruning) && !viper.IsSet(flagPruningKeepEvery) && !viper.IsSet(flagPruningSnapshotEvery) { + return errPruningOptionsRequired + } + + if viper.IsSet(flagPruning) { + if viper.IsSet(flagPruningKeepEvery) || viper.IsSet(flagPruningSnapshotEvery) { + return errPruningWithGranularOptions + } + + return nil + } + + if !(viper.IsSet(flagPruningKeepEvery) && viper.IsSet(flagPruningSnapshotEvery)) { + return errPruningGranularOptions + } + + return nil +} + func startStandAlone(ctx *Context, appCreator AppCreator) error { addr := viper.GetString(flagAddress) home := viper.GetString("home") From cfb3819183b01e7c209ef5e9ea405b0a45cd85cb Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Thu, 27 Feb 2020 13:40:01 +0100 Subject: [PATCH 265/529] add function to get pruning options from flags --- server/pruning.go | 21 ++++++++++++++++++ server/pruning_test.go | 50 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 server/pruning.go create mode 100644 server/pruning_test.go diff --git a/server/pruning.go b/server/pruning.go new file mode 100644 index 000000000000..d3fa8a102203 --- /dev/null +++ b/server/pruning.go @@ -0,0 +1,21 @@ +package server + +import ( + "github.com/cosmos/cosmos-sdk/store" + "github.com/spf13/viper" +) + +func GetPruningOptionsFromFlags() store.PruningOptions { + if viper.IsSet(flagPruning) { + return store.NewPruningOptionsFromString(viper.GetString(flagPruning)) + } + + if viper.IsSet(flagPruningKeepEvery) && viper.IsSet(flagPruningSnapshotEvery) { + return store.PruningOptions{ + KeepEvery: viper.GetInt64(flagPruningKeepEvery), + SnapshotEvery: viper.GetInt64(flagPruningSnapshotEvery), + } + } + + return store.PruneSyncable +} diff --git a/server/pruning_test.go b/server/pruning_test.go new file mode 100644 index 000000000000..0d4d0bc6ca48 --- /dev/null +++ b/server/pruning_test.go @@ -0,0 +1,50 @@ +package server + +import ( + "testing" + + "github.com/spf13/viper" + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/store" +) + +func TestGetPruningOptionsFromFlags(t *testing.T) { + tests := []struct { + name string + initParams func() + expectedOptions store.PruningOptions + }{ + { + name: "pruning", + initParams: func() { + viper.Set(flagPruning, store.PruningStrategyNothing) + }, + expectedOptions: store.PruneNothing, + }, + { + name: "granular pruning", + initParams: func() { + viper.Set(flagPruningSnapshotEvery, 1234) + viper.Set(flagPruningKeepEvery, 4321) + }, + expectedOptions: store.PruningOptions{ + SnapshotEvery: 1234, + KeepEvery: 4321, + }, + }, + { + name: "default", + initParams: func() {}, + expectedOptions: store.PruneSyncable, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(j *testing.T) { + viper.Reset() + tt.initParams() + require.Equal(t, tt.expectedOptions, GetPruningOptionsFromFlags()) + }) + } +} From 2f55b9d25549dd240a3e5710e7b491e5d7ef1eaf Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Thu, 27 Feb 2020 15:56:07 +0100 Subject: [PATCH 266/529] change default and fix test --- server/start.go | 4 +++- server/start_test.go | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/server/start.go b/server/start.go index 4749edf63378..68bd9e55efe4 100644 --- a/server/start.go +++ b/server/start.go @@ -83,6 +83,8 @@ which accepts a path for the resulting pprof file. cmd.Flags().String(flagAddress, "tcp://0.0.0.0:26658", "Listen address") cmd.Flags().String(flagTraceStore, "", "Enable KVStore tracing to an output file") cmd.Flags().String(flagPruning, "syncable", "Pruning strategy: syncable, nothing, everything") + cmd.Flags().Int64(flagPruningKeepEvery, 0, "Define the state number that will be kept") + cmd.Flags().Int64(flagPruningSnapshotEvery, 0, "Defines the state that will be snapshot for pruning") cmd.Flags().String( FlagMinGasPrices, "", "Minimum gas prices to accept for transactions; Any fee in a tx must meet this minimum (e.g. 0.01photino;0.0001stake)", @@ -101,7 +103,7 @@ which accepts a path for the resulting pprof file. // checkPruningParams checks that the provided pruning params are correct func checkPruningParams() error { if !viper.IsSet(flagPruning) && !viper.IsSet(flagPruningKeepEvery) && !viper.IsSet(flagPruningSnapshotEvery) { - return errPruningOptionsRequired + return nil // Use default } if viper.IsSet(flagPruning) { diff --git a/server/start_test.go b/server/start_test.go index a61a31852b4a..169a6fb5ae7c 100644 --- a/server/start_test.go +++ b/server/start_test.go @@ -17,10 +17,10 @@ func TestPruningOptions(t *testing.T) { expectedErr error }{ { - name: "none set", + name: "none set, returns nil and will use default from flags", paramInit: func() {}, - returnsErr: true, - expectedErr: errPruningOptionsRequired, + returnsErr: false, + expectedErr: nil, }, { name: "only keep-every provided", From 93e3f33461167e47deafe494667d760675309b39 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Thu, 27 Feb 2020 16:02:29 +0100 Subject: [PATCH 267/529] remove unused error --- server/start.go | 1 - 1 file changed, 1 deletion(-) diff --git a/server/start.go b/server/start.go index 68bd9e55efe4..6fd9c2f35a61 100644 --- a/server/start.go +++ b/server/start.go @@ -36,7 +36,6 @@ const ( var errPruningWithGranularOptions = fmt.Errorf("%s flag is not compatible with granular options as %s or %s", flagPruning, flagPruningKeepEvery, flagPruningSnapshotEvery) var errPruningGranularOptions = fmt.Errorf("%s and %s must be set together", flagPruningSnapshotEvery, flagPruningKeepEvery) -var errPruningOptionsRequired = fmt.Errorf("pruning options required") // StartCmd runs the service passed in, either stand-alone or in-process with // Tendermint. From 9aeefa77d316b43b86e105ac13d69711cf3e901b Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Thu, 27 Feb 2020 16:05:10 +0100 Subject: [PATCH 268/529] update command doc --- server/start.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/server/start.go b/server/start.go index 6fd9c2f35a61..0e29cc5d6854 100644 --- a/server/start.go +++ b/server/start.go @@ -46,7 +46,9 @@ func StartCmd(ctx *Context, appCreator AppCreator) *cobra.Command { Long: `Run the full node application with Tendermint in or out of process. By default, the application will run with Tendermint in process. -Pruning options can be provided via the '--pruning' flag. The options are as follows: +Pruning options can be provided via the '--pruning' flag or with '--pruning-snapshot-every' and 'pruning-keep-every' together. + +For '--pruning' the options are as follows: syncable: only those states not needed for state syncing will be deleted (flushes every 100th to disk and keeps every 10000th) nothing: all historic states will be saved, nothing will be deleted (i.e. archiving node) From 0c3117b3c75e1ede94abfd4f18560a120fb8d7ab Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Thu, 27 Feb 2020 16:07:24 +0100 Subject: [PATCH 269/529] add godoc into GetPruningOptionsFromFlags --- server/pruning.go | 1 + 1 file changed, 1 insertion(+) diff --git a/server/pruning.go b/server/pruning.go index d3fa8a102203..3cfa8f05d122 100644 --- a/server/pruning.go +++ b/server/pruning.go @@ -5,6 +5,7 @@ import ( "github.com/spf13/viper" ) +//GetPruningOptionsFromFlags parses start command flags and returns the correct PruningOptions. func GetPruningOptionsFromFlags() store.PruningOptions { if viper.IsSet(flagPruning) { return store.NewPruningOptionsFromString(viper.GetString(flagPruning)) From 2dbd364d3ba762f380489b17c199606d19f04c17 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Thu, 27 Feb 2020 16:16:08 +0100 Subject: [PATCH 270/529] update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c3a38ae1e37..5ff37df3a448 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,8 @@ Ref: https://keepachangelog.com/en/1.0.0/ balances or a single balance by denom when the `denom` query parameter is present. * (client) [\#5640](https://github.com/cosmos/cosmos-sdk/pull/5640) The rest server endpoint `/swagger-ui/` is replaced by ´/´. * (x/auth) [\#5702](https://github.com/cosmos/cosmos-sdk/pull/5702) The `x/auth` querier route has changed from `"acc"` to `"auth"`. +* (server) [\#5702](https://github.com/cosmos/cosmos-sdk/pull/5709) There are two new flags for pruning, `--pruning-keep-every` +and `--pruning-snapshot-every` as an alternative to `--pruning`. They allow to fine tune the strategy for pruning the state. ### API Breaking Changes From 0a3fcf6d2d30f74ca2113f4f37e2b1e5a1610db1 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Thu, 27 Feb 2020 16:23:15 +0100 Subject: [PATCH 271/529] change section in changelog --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ff37df3a448..0d0b80762013 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,8 +43,6 @@ Ref: https://keepachangelog.com/en/1.0.0/ balances or a single balance by denom when the `denom` query parameter is present. * (client) [\#5640](https://github.com/cosmos/cosmos-sdk/pull/5640) The rest server endpoint `/swagger-ui/` is replaced by ´/´. * (x/auth) [\#5702](https://github.com/cosmos/cosmos-sdk/pull/5702) The `x/auth` querier route has changed from `"acc"` to `"auth"`. -* (server) [\#5702](https://github.com/cosmos/cosmos-sdk/pull/5709) There are two new flags for pruning, `--pruning-keep-every` -and `--pruning-snapshot-every` as an alternative to `--pruning`. They allow to fine tune the strategy for pruning the state. ### API Breaking Changes @@ -147,6 +145,8 @@ Buffers for state serialization instead of Amino. * (rest) [\#5648](https://github.com/cosmos/cosmos-sdk/pull/5648) Enhance /txs usability: * Add `tx.minheight` key to filter transaction with an inclusive minimum block height * Add `tx.maxheight` key to filter transaction with an inclusive maximum block height +* (server) [\#5702](https://github.com/cosmos/cosmos-sdk/pull/5709) There are two new flags for pruning, `--pruning-keep-every` +and `--pruning-snapshot-every` as an alternative to `--pruning`. They allow to fine tune the strategy for pruning the state. ## [v0.38.1] - 2020-02-11 From a21a7faebcf2e20dad2d2b909514e386f88d04f2 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Thu, 27 Feb 2020 16:33:30 +0100 Subject: [PATCH 272/529] update test error lint --- server/pruning_test.go | 1 + server/start_test.go | 20 ++++++++++++-------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/server/pruning_test.go b/server/pruning_test.go index 0d4d0bc6ca48..41fab48ec0f3 100644 --- a/server/pruning_test.go +++ b/server/pruning_test.go @@ -42,6 +42,7 @@ func TestGetPruningOptionsFromFlags(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(j *testing.T) { + tt := tt viper.Reset() tt.initParams() require.Equal(t, tt.expectedOptions, GetPruningOptionsFromFlags()) diff --git a/server/start_test.go b/server/start_test.go index 169a6fb5ae7c..a9ef4b88e1f1 100644 --- a/server/start_test.go +++ b/server/start_test.go @@ -86,15 +86,19 @@ func TestPruningOptions(t *testing.T) { } for _, tt := range tests { - viper.Reset() - tt.paramInit() + t.Run(tt.name, func(t *testing.T) { + tt := tt - err := startCommand.PreRunE(nil, nil) + viper.Reset() + tt.paramInit() - if tt.returnsErr { - require.EqualError(t, err, tt.expectedErr.Error()) - } else { - require.NoError(t, err) - } + err := startCommand.PreRunE(nil, nil) + + if tt.returnsErr { + require.EqualError(t, err, tt.expectedErr.Error()) + } else { + require.NoError(t, err) + } + }) } } From fa3572e300359c6a29f68f4c971307ccb9664b26 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Thu, 27 Feb 2020 16:35:13 +0100 Subject: [PATCH 273/529] update start cmd desc --- server/start.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/start.go b/server/start.go index 0e29cc5d6854..06b4f9b8f0f1 100644 --- a/server/start.go +++ b/server/start.go @@ -46,7 +46,7 @@ func StartCmd(ctx *Context, appCreator AppCreator) *cobra.Command { Long: `Run the full node application with Tendermint in or out of process. By default, the application will run with Tendermint in process. -Pruning options can be provided via the '--pruning' flag or with '--pruning-snapshot-every' and 'pruning-keep-every' together. +Pruning options can be provided via the '--pruning' flag or alternatively with '--pruning-snapshot-every' and 'pruning-keep-every' together. For '--pruning' the options are as follows: From d279066285edfde41480fc5ddec3290b5cf41c8f Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Thu, 27 Feb 2020 16:47:59 +0100 Subject: [PATCH 274/529] remove duplicated func --- x/staking/common_test.go | 40 ++++------------------------------------ 1 file changed, 4 insertions(+), 36 deletions(-) diff --git a/x/staking/common_test.go b/x/staking/common_test.go index 9a3cfad368ea..e55baa0f0a90 100644 --- a/x/staking/common_test.go +++ b/x/staking/common_test.go @@ -1,18 +1,13 @@ package staking_test import ( - "bytes" - "encoding/hex" - "strconv" - - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/simapp" - cdc "github.com/cosmos/cosmos-sdk/simapp/codec" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" - "github.com/tendermint/tendermint/crypto/ed25519" "github.com/tendermint/tendermint/crypto/secp256k1" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/simapp" + cdc "github.com/cosmos/cosmos-sdk/simapp/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/staking" "github.com/cosmos/cosmos-sdk/x/staking/keeper" @@ -28,7 +23,7 @@ var ( commissionRates = staking.NewCommissionRates(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()) - PKs = createTestPubKeys(500) + PKs = simapp.CreateTestPubKeys(500) ) func NewTestMsgCreateValidator(address sdk.ValAddress, pubKey crypto.PubKey, amt sdk.Int) staking.MsgCreateValidator { @@ -42,33 +37,6 @@ func NewTestMsgDelegate(delAddr sdk.AccAddress, valAddr sdk.ValAddress, amt sdk. return staking.NewMsgDelegate(delAddr, valAddr, amount) } -// nolint: unparam -func createTestPubKeys(numPubKeys int) []crypto.PubKey { - var publicKeys []crypto.PubKey - var buffer bytes.Buffer - - //start at 10 to avoid changing 1 to 01, 2 to 02, etc - for i := 100; i < (numPubKeys + 100); i++ { - numString := strconv.Itoa(i) - buffer.WriteString("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AF") //base pubkey string - buffer.WriteString(numString) //adding on final two digits to make pubkeys unique - publicKeys = append(publicKeys, NewPubKey(buffer.String())) - buffer.Reset() - } - return publicKeys -} - -func NewPubKey(pk string) (res crypto.PubKey) { - pkBytes, err := hex.DecodeString(pk) - if err != nil { - panic(err) - } - //res, err = crypto.PubKeyFromBytes(pkBytes) - var pkEd ed25519.PubKeyEd25519 - copy(pkEd[:], pkBytes) - return pkEd -} - // getBaseSimappWithCustomKeeper Returns a simapp with custom StakingKeeper // to avoid messing with the hooks. func getBaseSimappWithCustomKeeper() (*codec.Codec, *simapp.SimApp, sdk.Context) { From ce4693930840e74f3342a99ca7bc3d4779644790 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Thu, 27 Feb 2020 16:49:53 +0100 Subject: [PATCH 275/529] rename function names --- simapp/test_helpers.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/simapp/test_helpers.go b/simapp/test_helpers.go index e07e7373220f..180d57479e7e 100644 --- a/simapp/test_helpers.go +++ b/simapp/test_helpers.go @@ -83,8 +83,8 @@ func SetupWithGenesisAccounts(genAccs []authexported.GenesisAccount, balances .. type GenerateAccountStrategy func(int) []sdk.AccAddress -// random is a strategy used by addTestAddrs() in order to generated addresses in random order. -func random(accNum int) []sdk.AccAddress { +// createRandomAccounts is a strategy used by addTestAddrs() in order to generated addresses in random order. +func createRandomAccounts(accNum int) []sdk.AccAddress { testAddrs := make([]sdk.AccAddress, accNum) for i := 0; i < accNum; i++ { pk := ed25519.GenPrivKey().PubKey() @@ -94,8 +94,8 @@ func random(accNum int) []sdk.AccAddress { return testAddrs } -// incremental is a strategy used by addTestAddrs() in order to generated addresses in ascending order. -func incremental(accNum int) []sdk.AccAddress { +// createIncrementalAccounts is a strategy used by addTestAddrs() in order to generated addresses in ascending order. +func createIncrementalAccounts(accNum int) []sdk.AccAddress { var addresses []sdk.AccAddress var buffer bytes.Buffer @@ -119,13 +119,13 @@ func incremental(accNum int) []sdk.AccAddress { // AddTestAddrs constructs and returns accNum amount of accounts with an // initial balance of accAmt in random order func AddTestAddrs(app *SimApp, ctx sdk.Context, accNum int, accAmt sdk.Int) []sdk.AccAddress { - return addTestAddrs(app, ctx, accNum, accAmt, random) + return addTestAddrs(app, ctx, accNum, accAmt, createRandomAccounts) } // AddTestAddrs constructs and returns accNum amount of accounts with an // initial balance of accAmt in random order func AddTestAddrsIncremental(app *SimApp, ctx sdk.Context, accNum int, accAmt sdk.Int) []sdk.AccAddress { - return addTestAddrs(app, ctx, accNum, accAmt, incremental) + return addTestAddrs(app, ctx, accNum, accAmt, createIncrementalAccounts) } func addTestAddrs(app *SimApp, ctx sdk.Context, accNum int, accAmt sdk.Int, strategy GenerateAccountStrategy) []sdk.AccAddress { From 191664bb30c926df3b4135fe7746d8aaa358f0c5 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Thu, 27 Feb 2020 17:22:47 +0100 Subject: [PATCH 276/529] fix issue number --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d0b80762013..494533cd10a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -145,7 +145,7 @@ Buffers for state serialization instead of Amino. * (rest) [\#5648](https://github.com/cosmos/cosmos-sdk/pull/5648) Enhance /txs usability: * Add `tx.minheight` key to filter transaction with an inclusive minimum block height * Add `tx.maxheight` key to filter transaction with an inclusive maximum block height -* (server) [\#5702](https://github.com/cosmos/cosmos-sdk/pull/5709) There are two new flags for pruning, `--pruning-keep-every` +* (server) [\#5709](https://github.com/cosmos/cosmos-sdk/pull/5709) There are two new flags for pruning, `--pruning-keep-every` and `--pruning-snapshot-every` as an alternative to `--pruning`. They allow to fine tune the strategy for pruning the state. ## [v0.38.1] - 2020-02-11 From 0027111db49e064f3df68393b86628dbc21f8434 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Thu, 27 Feb 2020 17:29:13 +0100 Subject: [PATCH 277/529] fix linter test --- server/pruning_test.go | 2 +- server/start_test.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/server/pruning_test.go b/server/pruning_test.go index 41fab48ec0f3..916f4e07dfba 100644 --- a/server/pruning_test.go +++ b/server/pruning_test.go @@ -41,8 +41,8 @@ func TestGetPruningOptionsFromFlags(t *testing.T) { } for _, tt := range tests { + tt := tt t.Run(tt.name, func(j *testing.T) { - tt := tt viper.Reset() tt.initParams() require.Equal(t, tt.expectedOptions, GetPruningOptionsFromFlags()) diff --git a/server/start_test.go b/server/start_test.go index a9ef4b88e1f1..c9c4f61ef640 100644 --- a/server/start_test.go +++ b/server/start_test.go @@ -86,9 +86,9 @@ func TestPruningOptions(t *testing.T) { } for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tt := tt + tt := tt + t.Run(tt.name, func(t *testing.T) { viper.Reset() tt.paramInit() From de0f1a9e40eb36ddbd2c7ce844caa8599acd4f9a Mon Sep 17 00:00:00 2001 From: Marko Date: Fri, 28 Feb 2020 06:36:42 +0100 Subject: [PATCH 278/529] Merge PR #5714: tools: add mergify --- .mergify.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .mergify.yml diff --git a/.mergify.yml b/.mergify.yml new file mode 100644 index 000000000000..f827f6554232 --- /dev/null +++ b/.mergify.yml @@ -0,0 +1,10 @@ +pull_request_rules: + - name: automatic merge for master when CI passes, has 1 review and has the label automerge + conditions: + - "#approved-reviews-by>=1" + - "status-success=ci/circleci - Pull Request" + - base=master + - label=automerge + actions: + merge: + method: squash From 0b7449129af3268c1d0e4d3fef4741beb2b4aa30 Mon Sep 17 00:00:00 2001 From: Anil Kumar Kammari Date: Fri, 28 Feb 2020 11:56:04 +0530 Subject: [PATCH 279/529] Merge PR #5500: Regen network/multistore upgrades --- baseapp/baseapp.go | 60 -------- baseapp/baseapp_test.go | 50 ------- simapp/app.go | 4 +- simapp/app_test.go | 6 +- simapp/sim_bench_test.go | 4 +- simapp/sim_test.go | 12 +- simapp/test_helpers.go | 4 +- store/types/store.go | 7 + x/crisis/handler_test.go | 2 +- x/crisis/internal/keeper/integration_test.go | 2 +- x/gov/genesis_test.go | 2 +- x/upgrade/abci.go | 8 ++ x/upgrade/abci_test.go | 34 ++++- x/upgrade/alias.go | 1 + x/upgrade/doc.go | 21 +++ x/upgrade/keeper/keeper.go | 70 ++++++++- x/upgrade/spec/01_concepts.md | 27 ++++ x/upgrade/types/storeloader.go | 23 +++ x/upgrade/types/storeloader_test.go | 144 +++++++++++++++++++ 19 files changed, 351 insertions(+), 130 deletions(-) create mode 100644 x/upgrade/types/storeloader.go create mode 100644 x/upgrade/types/storeloader_test.go diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 3837a34ccc9a..4fe7d0ba803b 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -1,11 +1,8 @@ package baseapp import ( - "encoding/json" "errors" "fmt" - "io/ioutil" - "os" "reflect" "runtime/debug" "strings" @@ -17,7 +14,6 @@ import ( dbm "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/store" - storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) @@ -226,62 +222,6 @@ func DefaultStoreLoader(ms sdk.CommitMultiStore) error { return ms.LoadLatestVersion() } -// StoreLoaderWithUpgrade is used to prepare baseapp with a fixed StoreLoader -// pattern. This is useful in test cases, or with custom upgrade loading logic. -func StoreLoaderWithUpgrade(upgrades *storetypes.StoreUpgrades) StoreLoader { - return func(ms sdk.CommitMultiStore) error { - return ms.LoadLatestVersionAndUpgrade(upgrades) - } -} - -// UpgradeableStoreLoader can be configured by SetStoreLoader() to check for the -// existence of a given upgrade file - json encoded StoreUpgrades data. -// -// If not file is present, it will peform the default load (no upgrades to store). -// -// If the file is present, it will parse the file and execute those upgrades -// (rename or delete stores), while loading the data. It will also delete the -// upgrade file upon successful load, so that the upgrade is only applied once, -// and not re-applied on next restart -// -// This is useful for in place migrations when a store key is renamed between -// two versions of the software. (TODO: this code will move to x/upgrades -// when PR #4233 is merged, here mainly to help test the design) -func UpgradeableStoreLoader(upgradeInfoPath string) StoreLoader { - return func(ms sdk.CommitMultiStore) error { - _, err := os.Stat(upgradeInfoPath) - if os.IsNotExist(err) { - return DefaultStoreLoader(ms) - } else if err != nil { - return err - } - - // there is a migration file, let's execute - data, err := ioutil.ReadFile(upgradeInfoPath) - if err != nil { - return fmt.Errorf("cannot read upgrade file %s: %v", upgradeInfoPath, err) - } - - var upgrades storetypes.StoreUpgrades - err = json.Unmarshal(data, &upgrades) - if err != nil { - return fmt.Errorf("cannot parse upgrade file: %v", err) - } - - err = ms.LoadLatestVersionAndUpgrade(&upgrades) - if err != nil { - return fmt.Errorf("load and upgrade database: %v", err) - } - - // if we have a successful load, we delete the file - err = os.Remove(upgradeInfoPath) - if err != nil { - return fmt.Errorf("deleting upgrade file %s: %v", upgradeInfoPath, err) - } - return nil - } -} - // LoadVersion loads the BaseApp application version. It will panic if called // more than once on a running baseapp. func (app *BaseApp) LoadVersion(version int64, baseKey *sdk.KVStoreKey) error { diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index 6ee5aabbb0a8..840531865d31 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/binary" "fmt" - "io/ioutil" "os" "sync" "testing" @@ -137,18 +136,6 @@ func useDefaultLoader(app *BaseApp) { app.SetStoreLoader(DefaultStoreLoader) } -func useUpgradeLoader(upgrades *store.StoreUpgrades) func(*BaseApp) { - return func(app *BaseApp) { - app.SetStoreLoader(StoreLoaderWithUpgrade(upgrades)) - } -} - -func useFileUpgradeLoader(upgradeInfoPath string) func(*BaseApp) { - return func(app *BaseApp) { - app.SetStoreLoader(UpgradeableStoreLoader(upgradeInfoPath)) - } -} - func initStore(t *testing.T, db dbm.DB, storeKey string, k, v []byte) { rs := rootmulti.NewStore(db) rs.SetPruning(store.PruneNothing) @@ -184,19 +171,6 @@ func checkStore(t *testing.T, db dbm.DB, ver int64, storeKey string, k, v []byte // Test that we can make commits and then reload old versions. // Test that LoadLatestVersion actually does. func TestSetLoader(t *testing.T) { - // write a renamer to a file - f, err := ioutil.TempFile("", "upgrade-*.json") - require.NoError(t, err) - data := []byte(`{"renamed":[{"old_key": "bnk", "new_key": "banker"}]}`) - _, err = f.Write(data) - require.NoError(t, err) - configName := f.Name() - require.NoError(t, f.Close()) - - // make sure it exists before running everything - _, err = os.Stat(configName) - require.NoError(t, err) - cases := map[string]struct { setLoader func(*BaseApp) origStoreKey string @@ -211,26 +185,6 @@ func TestSetLoader(t *testing.T) { origStoreKey: "foo", loadStoreKey: "foo", }, - "rename with inline opts": { - setLoader: useUpgradeLoader(&store.StoreUpgrades{ - Renamed: []store.StoreRename{{ - OldKey: "foo", - NewKey: "bar", - }}, - }), - origStoreKey: "foo", - loadStoreKey: "bar", - }, - "file loader with missing file": { - setLoader: useFileUpgradeLoader(configName + "randomchars"), - origStoreKey: "bnk", - loadStoreKey: "bnk", - }, - "file loader with existing file": { - setLoader: useFileUpgradeLoader(configName), - origStoreKey: "bnk", - loadStoreKey: "banker", - }, } k := []byte("key") @@ -265,10 +219,6 @@ func TestSetLoader(t *testing.T) { checkStore(t, db, 2, tc.loadStoreKey, []byte("foo"), nil) }) } - - // ensure config file was deleted - _, err = os.Stat(configName) - require.True(t, os.IsNotExist(err)) } func TestAppVersionSetterGetter(t *testing.T) { diff --git a/simapp/app.go b/simapp/app.go index e7253c9a7874..67b6d9e119f1 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -122,7 +122,7 @@ type SimApp struct { // NewSimApp returns a reference to an initialized SimApp. func NewSimApp( logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool, skipUpgradeHeights map[int64]bool, - invCheckPeriod uint, baseAppOptions ...func(*bam.BaseApp), + homePath string, invCheckPeriod uint, baseAppOptions ...func(*bam.BaseApp), ) *SimApp { // TODO: Remove cdc in favor of appCodec once all modules are migrated. @@ -189,7 +189,7 @@ func NewSimApp( app.CrisisKeeper = crisis.NewKeeper( app.subspaces[crisis.ModuleName], invCheckPeriod, app.SupplyKeeper, auth.FeeCollectorName, ) - app.UpgradeKeeper = upgrade.NewKeeper(skipUpgradeHeights, keys[upgrade.StoreKey], appCodec) + app.UpgradeKeeper = upgrade.NewKeeper(skipUpgradeHeights, keys[upgrade.StoreKey], appCodec, homePath) // create evidence keeper with router evidenceKeeper := evidence.NewKeeper( diff --git a/simapp/app_test.go b/simapp/app_test.go index 9cf211a94176..17b6b3c28644 100644 --- a/simapp/app_test.go +++ b/simapp/app_test.go @@ -15,7 +15,7 @@ import ( func TestSimAppExport(t *testing.T) { db := dbm.NewMemDB() - app := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, 0) + app := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0) genesisState := NewDefaultGenesisState() stateBytes, err := codec.MarshalJSONIndent(app.Codec(), genesisState) @@ -31,7 +31,7 @@ func TestSimAppExport(t *testing.T) { app.Commit() // Making a new app object with the db, so that initchain hasn't been called - app2 := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, 0) + app2 := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0) _, _, err = app2.ExportAppStateAndValidators(false, []string{}) require.NoError(t, err, "ExportAppStateAndValidators should not have an error") } @@ -39,7 +39,7 @@ func TestSimAppExport(t *testing.T) { // ensure that black listed addresses are properly set in bank keeper func TestBlackListedAddrs(t *testing.T) { db := dbm.NewMemDB() - app := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, 0) + app := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0) for acc := range maccPerms { require.Equal(t, !allowedReceivingModAcc[acc], app.BankKeeper.BlacklistedAddr(app.SupplyKeeper.GetModuleAddress(acc))) diff --git a/simapp/sim_bench_test.go b/simapp/sim_bench_test.go index b09a3a9090fb..6d8ee05dbf77 100644 --- a/simapp/sim_bench_test.go +++ b/simapp/sim_bench_test.go @@ -26,7 +26,7 @@ func BenchmarkFullAppSimulation(b *testing.B) { } }() - app := NewSimApp(logger, db, nil, true, map[int64]bool{}, FlagPeriodValue, interBlockCacheOpt()) + app := NewSimApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, interBlockCacheOpt()) // run randomized simulation _, simParams, simErr := simulation.SimulateFromSeed( @@ -65,7 +65,7 @@ func BenchmarkInvariants(b *testing.B) { } }() - app := NewSimApp(logger, db, nil, true, map[int64]bool{}, FlagPeriodValue, interBlockCacheOpt()) + app := NewSimApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, interBlockCacheOpt()) // run randomized simulation _, simParams, simErr := simulation.SimulateFromSeed( diff --git a/simapp/sim_test.go b/simapp/sim_test.go index 18cb24a89484..6053ff83cc75 100644 --- a/simapp/sim_test.go +++ b/simapp/sim_test.go @@ -63,7 +63,7 @@ func TestFullAppSimulation(t *testing.T) { require.NoError(t, os.RemoveAll(dir)) }() - app := NewSimApp(logger, db, nil, true, map[int64]bool{}, FlagPeriodValue, fauxMerkleModeOpt) + app := NewSimApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, fauxMerkleModeOpt) require.Equal(t, "SimApp", app.Name()) // run randomized simulation @@ -95,7 +95,7 @@ func TestAppImportExport(t *testing.T) { require.NoError(t, os.RemoveAll(dir)) }() - app := NewSimApp(logger, db, nil, true, map[int64]bool{}, FlagPeriodValue, fauxMerkleModeOpt) + app := NewSimApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, fauxMerkleModeOpt) require.Equal(t, "SimApp", app.Name()) // Run randomized simulation @@ -129,7 +129,7 @@ func TestAppImportExport(t *testing.T) { require.NoError(t, os.RemoveAll(newDir)) }() - newApp := NewSimApp(log.NewNopLogger(), newDB, nil, true, map[int64]bool{}, FlagPeriodValue, fauxMerkleModeOpt) + newApp := NewSimApp(log.NewNopLogger(), newDB, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, fauxMerkleModeOpt) require.Equal(t, "SimApp", newApp.Name()) var genesisState GenesisState @@ -181,7 +181,7 @@ func TestAppSimulationAfterImport(t *testing.T) { require.NoError(t, os.RemoveAll(dir)) }() - app := NewSimApp(logger, db, nil, true, map[int64]bool{}, FlagPeriodValue, fauxMerkleModeOpt) + app := NewSimApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, fauxMerkleModeOpt) require.Equal(t, "SimApp", app.Name()) // Run randomized simulation @@ -220,7 +220,7 @@ func TestAppSimulationAfterImport(t *testing.T) { require.NoError(t, os.RemoveAll(newDir)) }() - newApp := NewSimApp(log.NewNopLogger(), newDB, nil, true, map[int64]bool{}, FlagPeriodValue, fauxMerkleModeOpt) + newApp := NewSimApp(log.NewNopLogger(), newDB, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, fauxMerkleModeOpt) require.Equal(t, "SimApp", newApp.Name()) newApp.InitChain(abci.RequestInitChain{ @@ -266,7 +266,7 @@ func TestAppStateDeterminism(t *testing.T) { db := dbm.NewMemDB() - app := NewSimApp(logger, db, nil, true, map[int64]bool{}, FlagPeriodValue, interBlockCacheOpt()) + app := NewSimApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, interBlockCacheOpt()) fmt.Printf( "running non-determinism simulation; seed %d: %d/%d, attempt: %d/%d\n", diff --git a/simapp/test_helpers.go b/simapp/test_helpers.go index abc87ed635cc..234995a19bbb 100644 --- a/simapp/test_helpers.go +++ b/simapp/test_helpers.go @@ -23,7 +23,7 @@ import ( // Setup initializes a new SimApp. A Nop logger is set in SimApp. func Setup(isCheckTx bool) *SimApp { db := dbm.NewMemDB() - app := NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, 0) + app := NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0) if !isCheckTx { // init chain must be called to stop deliverState from being nil genesisState := NewDefaultGenesisState() @@ -48,7 +48,7 @@ func Setup(isCheckTx bool) *SimApp { // accounts and possible balances. func SetupWithGenesisAccounts(genAccs []authexported.GenesisAccount, balances ...bank.Balance) *SimApp { db := dbm.NewMemDB() - app := NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, 0) + app := NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0) // initialize the chain with the passed in genesis accounts genesisState := NewDefaultGenesisState() diff --git a/store/types/store.go b/store/types/store.go index d48585f8fce2..72575baa6a89 100644 --- a/store/types/store.go +++ b/store/types/store.go @@ -44,6 +44,13 @@ type StoreUpgrades struct { Deleted []string `json:"deleted"` } +// UpgradeInfo defines height and name of the upgrade +// to ensure multistore upgrades happen only at matching height. +type UpgradeInfo struct { + Name string `json:"name"` + Height int64 `json:"height"` +} + // StoreRename defines a name change of a sub-store. // All data previously under a PrefixStore with OldKey will be copied // to a PrefixStore with NewKey, then deleted from OldKey store. diff --git a/x/crisis/handler_test.go b/x/crisis/handler_test.go index 2db4012d2f70..83907543f2a1 100644 --- a/x/crisis/handler_test.go +++ b/x/crisis/handler_test.go @@ -25,7 +25,7 @@ var ( func createTestApp() (*simapp.SimApp, sdk.Context, []sdk.AccAddress) { db := dbm.NewMemDB() - app := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, 1) + app := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, simapp.DefaultNodeHome, 1) ctx := app.NewContext(true, abci.Header{}) constantFee := sdk.NewInt64Coin(sdk.DefaultBondDenom, 10) diff --git a/x/crisis/internal/keeper/integration_test.go b/x/crisis/internal/keeper/integration_test.go index a98a0b44533c..4dc123fda458 100644 --- a/x/crisis/internal/keeper/integration_test.go +++ b/x/crisis/internal/keeper/integration_test.go @@ -11,7 +11,7 @@ import ( func createTestApp() *simapp.SimApp { db := dbm.NewMemDB() - app := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, 5) + app := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, simapp.DefaultNodeHome, 5) // init chain must be called to stop deliverState from being nil genesisState := simapp.NewDefaultGenesisState() stateBytes, err := codec.MarshalJSONIndent(app.Codec(), genesisState) diff --git a/x/gov/genesis_test.go b/x/gov/genesis_test.go index 133c7c4f3ab3..d9f8857b168f 100644 --- a/x/gov/genesis_test.go +++ b/x/gov/genesis_test.go @@ -63,7 +63,7 @@ func TestImportExportQueues(t *testing.T) { } db := dbm.NewMemDB() - app2 := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, 0) + app2 := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, simapp.DefaultNodeHome, 0) app2.InitChain( abci.RequestInitChain{ diff --git a/x/upgrade/abci.go b/x/upgrade/abci.go index 11edf7fbbc0c..f5c6d6a348d9 100644 --- a/x/upgrade/abci.go +++ b/x/upgrade/abci.go @@ -38,6 +38,14 @@ func BeginBlocker(k Keeper, ctx sdk.Context, _ abci.RequestBeginBlock) { upgradeMsg := fmt.Sprintf("UPGRADE \"%s\" NEEDED at %s: %s", plan.Name, plan.DueAt(), plan.Info) // We don't have an upgrade handler for this upgrade name, meaning this software is out of date so shutdown ctx.Logger().Error(upgradeMsg) + + // Write the upgrade info to disk. The UpgradeStoreLoader uses this info to perform or skip + // store migrations. + err := k.DumpUpgradeInfoToDisk(ctx.BlockHeight(), plan.Name) + if err != nil { + panic(fmt.Errorf("unable to write upgrade info to filesystem: %s", err.Error())) + } + panic(upgradeMsg) } // We have an upgrade handler for this upgrade name, so apply the upgrade diff --git a/x/upgrade/abci_test.go b/x/upgrade/abci_test.go index c82fe757a5e5..aa2bf33cfbb4 100644 --- a/x/upgrade/abci_test.go +++ b/x/upgrade/abci_test.go @@ -1,10 +1,15 @@ package upgrade_test import ( + "encoding/json" "errors" + "io/ioutil" + "os" "testing" "time" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" @@ -31,7 +36,7 @@ var s TestSuite func setupTest(height int64, skip map[int64]bool) TestSuite { db := dbm.NewMemDB() - app := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, skip, 0) + app := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, skip, simapp.DefaultNodeHome, 0) genesisState := simapp.NewDefaultGenesisState() stateBytes, err := codec.MarshalJSONIndent(app.Codec(), genesisState) if err != nil { @@ -393,3 +398,30 @@ func TestUpgradeWithoutSkip(t *testing.T) { VerifyDoUpgrade(t) VerifyDone(t, s.ctx, "test") } + +func TestDumpUpgradeInfoToFile(t *testing.T) { + s := setupTest(10, map[int64]bool{}) + + planHeight := s.ctx.BlockHeight() + 1 + name := "test" + t.Log("verify if upgrade height is dumped to file") + err := s.keeper.DumpUpgradeInfoToDisk(planHeight, name) + require.Nil(t, err) + + upgradeInfoFilePath, err := s.keeper.GetUpgradeInfoPath() + require.Nil(t, err) + + data, err := ioutil.ReadFile(upgradeInfoFilePath) + require.NoError(t, err) + + var upgradeInfo storetypes.UpgradeInfo + err = json.Unmarshal(data, &upgradeInfo) + require.Nil(t, err) + + t.Log("Verify upgrade height from file matches ") + require.Equal(t, upgradeInfo.Height, planHeight) + + // clear the test file + err = os.Remove(upgradeInfoFilePath) + require.Nil(t, err) +} diff --git a/x/upgrade/alias.go b/x/upgrade/alias.go index c8ae7bf63157..784eb681b1f4 100644 --- a/x/upgrade/alias.go +++ b/x/upgrade/alias.go @@ -27,6 +27,7 @@ var ( NewSoftwareUpgradeProposal = types.NewSoftwareUpgradeProposal NewCancelSoftwareUpgradeProposal = types.NewCancelSoftwareUpgradeProposal NewQueryAppliedParams = types.NewQueryAppliedParams + UpgradeStoreLoader = types.UpgradeStoreLoader NewKeeper = keeper.NewKeeper NewQuerier = keeper.NewQuerier ) diff --git a/x/upgrade/doc.go b/x/upgrade/doc.go index 160580d5c79c..79867f7a8e42 100644 --- a/x/upgrade/doc.go +++ b/x/upgrade/doc.go @@ -68,6 +68,27 @@ as well as providing the opportunity for the upgraded software to perform any ne (with the old binary) and applying the migration (with the new binary) are enforced in the state machine. Actually switching the binaries is an ops task and not handled inside the sdk / abci app. +Here is a sample code to set store migrations with an upgrade: + + // this configures a no-op upgrade handler for the "my-fancy-upgrade" upgrade + app.UpgradeKeeper.SetUpgradeHandler("my-fancy-upgrade", func(ctx sdk.Context, plan upgrade.Plan) { + // upgrade changes here + }) + + upgradeInfo := app.UpgradeKeeper.ReadUpgradeInfoFromDisk() + if upgradeInfo.Name == "my-fancy-upgrade" && !app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Height) { + storeUpgrades := store.StoreUpgrades{ + Renamed: []store.StoreRename{{ + OldKey: "foo", + NewKey: "bar", + }}, + Deleted: []string{}, + } + + // configure store loader that checks if version == upgradeHeight and applies store upgrades + app.SetStoreLoader(upgrade.UpgradeStoreLoader(upgradeInfo.Height, &storeUpgrades)) + } + Halt Behavior Before halting the ABCI state machine in the BeginBlocker method, the upgrade module will log an error diff --git a/x/upgrade/keeper/keeper.go b/x/upgrade/keeper/keeper.go index ba789aeb7b77..a5bed9e36015 100644 --- a/x/upgrade/keeper/keeper.go +++ b/x/upgrade/keeper/keeper.go @@ -2,19 +2,30 @@ package keeper import ( "encoding/binary" + "encoding/json" "fmt" + "io/ioutil" + "os" + "path" + "path/filepath" "github.com/cosmos/cosmos-sdk/x/upgrade/types" "github.com/tendermint/tendermint/libs/log" + tmos "github.com/tendermint/tendermint/libs/os" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/prefix" + store "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) +// UpgradeInfoFileName file to store upgrade information +const UpgradeInfoFileName string = "upgrade-info.json" + type Keeper struct { + homePath string skipUpgradeHeights map[int64]bool storeKey sdk.StoreKey cdc codec.Marshaler @@ -22,8 +33,9 @@ type Keeper struct { } // NewKeeper constructs an upgrade Keeper -func NewKeeper(skipUpgradeHeights map[int64]bool, storeKey sdk.StoreKey, cdc codec.Marshaler) Keeper { +func NewKeeper(skipUpgradeHeights map[int64]bool, storeKey sdk.StoreKey, cdc codec.Marshaler, homePath string) Keeper { return Keeper{ + homePath: homePath, skipUpgradeHeights: skipUpgradeHeights, storeKey: storeKey, cdc: cdc, @@ -131,3 +143,59 @@ func (k Keeper) ApplyUpgrade(ctx sdk.Context, plan types.Plan) { func (k Keeper) IsSkipHeight(height int64) bool { return k.skipUpgradeHeights[height] } + +// DumpUpgradeInfoToDisk writes upgrade information to UpgradeInfoFileName. +func (k Keeper) DumpUpgradeInfoToDisk(height int64, name string) error { + upgradeInfoFilePath, err := k.GetUpgradeInfoPath() + if err != nil { + return err + } + + upgradeInfo := store.UpgradeInfo{ + Name: name, + Height: height, + } + info, err := json.Marshal(upgradeInfo) + if err != nil { + return err + } + + return ioutil.WriteFile(upgradeInfoFilePath, info, 0644) +} + +// GetUpgradeInfoPath returns the upgrade info file path +func (k Keeper) GetUpgradeInfoPath() (string, error) { + upgradeInfoFileDir := path.Join(k.getHomeDir(), "data") + err := tmos.EnsureDir(upgradeInfoFileDir, os.ModePerm) + if err != nil { + return "", err + } + + return filepath.Join(upgradeInfoFileDir, UpgradeInfoFileName), nil +} + +// getHomeDir returns the height at which the given upgrade was executed +func (k Keeper) getHomeDir() string { + return k.homePath +} + +// ReadUpgradeInfoFromDisk returns the name and height of the upgrade +// which is written to disk by the old binary when panic'ing +// if there's an error in reading the info, +// it assumes that the upgrade info is not available +func (k Keeper) ReadUpgradeInfoFromDisk() (upgradeInfo store.UpgradeInfo) { + upgradeInfoPath, err := k.GetUpgradeInfoPath() + // if error in reading the path, assume there are no upgrades + if err != nil { + return upgradeInfo + } + + data, err := ioutil.ReadFile(upgradeInfoPath) + // if error in reading the file, assume there are no upgrades + if err != nil { + return upgradeInfo + } + + json.Unmarshal(data, &upgradeInfo) + return +} diff --git a/x/upgrade/spec/01_concepts.md b/x/upgrade/spec/01_concepts.md index 19205591fc15..54147f8b5ebd 100644 --- a/x/upgrade/spec/01_concepts.md +++ b/x/upgrade/spec/01_concepts.md @@ -56,6 +56,33 @@ During each `EndBlock` execution, the `x/upgrade` module checks if there exists `Handler` is executed. If the `Plan` is expected to execute but no `Handler` is registered or if the binary was upgraded too early, the node will gracefully panic and exit. +## StoreLoader + + +The `x/upgrade` module also facilitates store migrations as part of the upgrade. The +`StoreLoader` sets the migrations that need to occur before the new binary can +successfully run the chain. This `StoreLoader` is also application specific and +not defined on a per-module basis. Registering this `StoreLoader` is done via +`app#SetStoreLoader` in the application. + +```go +func UpgradeStoreLoader (upgradeHeight int64, storeUpgrades *store.StoreUpgrades) baseapp.StoreLoader +``` + +If there's a planned upgrade and the upgrade height is reached, the old binary writes `UpgradeInfo` to the disk before panic'ing. + +```go +type UpgradeInfo struct { + Name string + Height int64 +} +``` + +This information is critical to ensure the `StoreUpgrades` happens smoothly at correct height and +expected upgrade. It eliminiates the chances for the new binary to execute `StoreUpgrades` multiple +times everytime on restart. Also if there are multiple upgrades planned on same height, the `Name` +will ensure these `StoreUpgrades` takes place only in planned upgrade handler. + ## Proposal Typically, a `Plan` is proposed and submitted through governance via a `SoftwareUpgradeProposal`. diff --git a/x/upgrade/types/storeloader.go b/x/upgrade/types/storeloader.go new file mode 100644 index 000000000000..0ff168dcc343 --- /dev/null +++ b/x/upgrade/types/storeloader.go @@ -0,0 +1,23 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/baseapp" + store "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// UpgradeStoreLoader is used to prepare baseapp with a fixed StoreLoader +// pattern. This is useful for custom upgrade loading logic. +func UpgradeStoreLoader(upgradeHeight int64, storeUpgrades *store.StoreUpgrades) baseapp.StoreLoader { + return func(ms sdk.CommitMultiStore) error { + if upgradeHeight == ms.LastCommitID().Version { + // Check if the current commit version and upgrade height matches + if len(storeUpgrades.Renamed) > 0 || len(storeUpgrades.Deleted) > 0 { + return ms.LoadLatestVersionAndUpgrade(storeUpgrades) + } + } + + // Otherwise load default store loader + return baseapp.DefaultStoreLoader(ms) + } +} diff --git a/x/upgrade/types/storeloader_test.go b/x/upgrade/types/storeloader_test.go new file mode 100644 index 000000000000..955ab07cdfc3 --- /dev/null +++ b/x/upgrade/types/storeloader_test.go @@ -0,0 +1,144 @@ +package types + +import ( + "encoding/json" + "io/ioutil" + "os" + "path/filepath" + "testing" + + "github.com/spf13/viper" + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/libs/log" + dbm "github.com/tendermint/tm-db" + + "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/store/rootmulti" + store "github.com/cosmos/cosmos-sdk/store/types" + "github.com/cosmos/cosmos-sdk/tests" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func useUpgradeLoader(height int64, upgrades *store.StoreUpgrades) func(*baseapp.BaseApp) { + return func(app *baseapp.BaseApp) { + app.SetStoreLoader(UpgradeStoreLoader(height, upgrades)) + } +} + +func defaultLogger() log.Logger { + return log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "sdk/app") +} + +func initStore(t *testing.T, db dbm.DB, storeKey string, k, v []byte) { + rs := rootmulti.NewStore(db) + rs.SetPruning(store.PruneNothing) + key := sdk.NewKVStoreKey(storeKey) + rs.MountStoreWithDB(key, store.StoreTypeIAVL, nil) + err := rs.LoadLatestVersion() + require.Nil(t, err) + require.Equal(t, int64(0), rs.LastCommitID().Version) + + // write some data in substore + kv, _ := rs.GetStore(key).(store.KVStore) + require.NotNil(t, kv) + kv.Set(k, v) + commitID := rs.Commit() + require.Equal(t, int64(1), commitID.Version) +} + +func checkStore(t *testing.T, db dbm.DB, ver int64, storeKey string, k, v []byte) { + rs := rootmulti.NewStore(db) + rs.SetPruning(store.PruneNothing) + key := sdk.NewKVStoreKey(storeKey) + rs.MountStoreWithDB(key, store.StoreTypeIAVL, nil) + err := rs.LoadLatestVersion() + require.Nil(t, err) + require.Equal(t, ver, rs.LastCommitID().Version) + + // query data in substore + kv, _ := rs.GetStore(key).(store.KVStore) + + require.NotNil(t, kv) + require.Equal(t, v, kv.Get(k)) +} + +// Test that we can make commits and then reload old versions. +// Test that LoadLatestVersion actually does. +func TestSetLoader(t *testing.T) { + // set a temporary home dir + homeDir, cleanUp := tests.NewTestCaseDir(t) + defer cleanUp() + // TODO cleanup viper + viper.Set(flags.FlagHome, homeDir) + + upgradeInfoFilePath := filepath.Join(homeDir, "upgrade-info.json") + upgradeInfo := &store.UpgradeInfo{ + Name: "test", Height: 0, + } + data, err := json.Marshal(upgradeInfo) + require.NoError(t, err) + err = ioutil.WriteFile(upgradeInfoFilePath, data, 0644) + require.NoError(t, err) + + // make sure it exists before running everything + _, err = os.Stat(upgradeInfoFilePath) + require.NoError(t, err) + + cases := map[string]struct { + setLoader func(*baseapp.BaseApp) + origStoreKey string + loadStoreKey string + }{ + "don't set loader": { + origStoreKey: "foo", + loadStoreKey: "foo", + }, + "rename with inline opts": { + setLoader: useUpgradeLoader(0, &store.StoreUpgrades{ + Renamed: []store.StoreRename{{ + OldKey: "foo", + NewKey: "bar", + }}, + }), + origStoreKey: "foo", + loadStoreKey: "bar", + }, + } + + k := []byte("key") + v := []byte("value") + + for name, tc := range cases { + tc := tc + t.Run(name, func(t *testing.T) { + // prepare a db with some data + db := dbm.NewMemDB() + + initStore(t, db, tc.origStoreKey, k, v) + + // load the app with the existing db + opts := []func(*baseapp.BaseApp){baseapp.SetPruning(store.PruneNothing)} + if tc.setLoader != nil { + opts = append(opts, tc.setLoader) + } + + app := baseapp.NewBaseApp(t.Name(), defaultLogger(), db, nil, opts...) + capKey := sdk.NewKVStoreKey(baseapp.MainStoreKey) + app.MountStores(capKey) + app.MountStores(sdk.NewKVStoreKey(tc.loadStoreKey)) + err := app.LoadLatestVersion(capKey) + require.Nil(t, err) + + // "execute" one block + app.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: 2}}) + res := app.Commit() + require.NotNil(t, res.Data) + + // check db is properly updated + checkStore(t, db, 2, tc.loadStoreKey, k, v) + checkStore(t, db, 2, tc.loadStoreKey, []byte("foo"), nil) + }) + } +} From 3c262306fa943f22c033ea7e34fefa10bd17feb2 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Fri, 28 Feb 2020 10:48:34 +0100 Subject: [PATCH 280/529] add more information into GetPruningOptionsFromFlags --- server/pruning.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/server/pruning.go b/server/pruning.go index 3cfa8f05d122..07730f36ad8a 100644 --- a/server/pruning.go +++ b/server/pruning.go @@ -5,7 +5,9 @@ import ( "github.com/spf13/viper" ) -//GetPruningOptionsFromFlags parses start command flags and returns the correct PruningOptions. +// GetPruningOptionsFromFlags parses start command flags and returns the correct PruningOptions. +// flagPruning prevails over flagPruningKeepEvery and flagPruningSnapshotEvery. +// Default option is PruneSyncable. func GetPruningOptionsFromFlags() store.PruningOptions { if viper.IsSet(flagPruning) { return store.NewPruningOptionsFromString(viper.GetString(flagPruning)) From 60970baf201a743d4e3d8951ab0e40ccae991d48 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Fri, 28 Feb 2020 10:53:56 +0100 Subject: [PATCH 281/529] update from PR comments --- server/start.go | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/server/start.go b/server/start.go index 06b4f9b8f0f1..c5bee58e8f1a 100644 --- a/server/start.go +++ b/server/start.go @@ -34,8 +34,16 @@ const ( FlagUnsafeSkipUpgrades = "unsafe-skip-upgrades" ) -var errPruningWithGranularOptions = fmt.Errorf("%s flag is not compatible with granular options as %s or %s", flagPruning, flagPruningKeepEvery, flagPruningSnapshotEvery) -var errPruningGranularOptions = fmt.Errorf("%s and %s must be set together", flagPruningSnapshotEvery, flagPruningKeepEvery) +var ( + errPruningWithGranularOptions = fmt.Errorf( + "'--%s' flag is not compatible with granular options '--%s' or '--%s'", + flagPruning, flagPruningKeepEvery, flagPruningSnapshotEvery, + ) + errPruningGranularOptions = fmt.Errorf( + "'--%s' and '--%s' must be set together", + flagPruningSnapshotEvery, flagPruningKeepEvery, + ) +) // StartCmd runs the service passed in, either stand-alone or in-process with // Tendermint. @@ -104,7 +112,7 @@ which accepts a path for the resulting pprof file. // checkPruningParams checks that the provided pruning params are correct func checkPruningParams() error { if !viper.IsSet(flagPruning) && !viper.IsSet(flagPruningKeepEvery) && !viper.IsSet(flagPruningSnapshotEvery) { - return nil // Use default + return nil } if viper.IsSet(flagPruning) { From 66f8e35b90286cc89eb26f98c0cd8f78f47bce8e Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Fri, 28 Feb 2020 12:26:11 +0000 Subject: [PATCH 282/529] Build with go1.14 (#5719) --- .circleci/config.yml | 2 +- CHANGELOG.md | 1 + README.md | 2 +- go.mod | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 04ec877e3f9f..15b9578e28df 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -3,7 +3,7 @@ version: 2.1 executors: golang: docker: - - image: circleci/golang:1.13 + - image: circleci/golang:1.14 docs: docker: - image: tendermintdev/docker-website-deployment diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c3a38ae1e37..138724a6cbab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,7 @@ balances or a single balance by denom when the `denom` query parameter is presen ### API Breaking Changes +* [\#5719](https://github.com/cosmos/cosmos-sdk/pull/5719) Bump Go requirement to 1.14+ * (x/params) [\#5619](https://github.com/cosmos/cosmos-sdk/pull/5619) The `x/params` keeper now accepts a `codec.Marshaller` instead of a reference to an amino codec. Amino is still used for JSON serialization. * (types) [\#5579](https://github.com/cosmos/cosmos-sdk/pull/5579) The `keepRecent` field has been removed from the `PruningOptions` type. diff --git a/README.md b/README.md index d1ee3d585a01..c783fc279efe 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ It is being used to build [`Gaia`](https://github.com/cosmos/gaia), the first im **WARNING**: The SDK has mostly stabilized, but we are still making some breaking changes. -**Note**: Requires [Go 1.13+](https://golang.org/dl/) +**Note**: Requires [Go 1.14+](https://golang.org/dl/) ## Quick Start diff --git a/go.mod b/go.mod index d9debb5a73c0..1599418dc4d0 100644 --- a/go.mod +++ b/go.mod @@ -35,4 +35,4 @@ require ( replace github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.2-alpha.regen.1 -go 1.13 +go 1.14 From 1b78457135a4104bc3af97f20654d49e2ea87454 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Fri, 28 Feb 2020 13:19:00 +0000 Subject: [PATCH 283/529] Run go mod tidy (#5721) --- go.sum | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/go.sum b/go.sum index 7eeaf96559e5..5ad52215962c 100644 --- a/go.sum +++ b/go.sum @@ -35,7 +35,6 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= @@ -45,7 +44,6 @@ github.com/cosmos/ledger-cosmos-go v0.11.1 h1:9JIYsGnXP613pb2vPjFeMMjBI5lEDsEaF6 github.com/cosmos/ledger-cosmos-go v0.11.1/go.mod h1:J8//BsAGTo3OC/vDLjMRFLW6q0WAaXvHnVc7ZmE8iUY= github.com/cosmos/ledger-go v0.9.2 h1:Nnao/dLwaVTk1Q5U9THldpUMMXU94BOTWPddSmVB6pI= github.com/cosmos/ledger-go v0.9.2/go.mod h1:oZJ2hHAZROdlHiwTg4t7kP+GKIIkBT+o6c9QWFanOyI= -github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/danieljoos/wincred v1.0.2 h1:zf4bhty2iLuwgjgpraD2E9UbvO+fe54XXGJbOwe23fU= github.com/danieljoos/wincred v1.0.2/go.mod h1:SnuYRW9lp1oJrZX/dXJqr0cPK5gYXqx3EJbmjhLdK9U= @@ -196,8 +194,6 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084 h1:sofwID9zm4tzrgykg80hfFph1mryUeLRsUfoocVVmRY= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/rakyll/statik v0.1.6 h1:uICcfUXpgqtw2VopbIncslhAmE5hwc4g20TEyEENBNs= -github.com/rakyll/statik v0.1.6/go.mod h1:OEi9wJV/fMUAGx1eNjq75DKDsJVuEv1U0oYdX6GX8Zs= github.com/rakyll/statik v0.1.7 h1:OF3QCZUuyPxuGEP7B4ypUa7sB/iHtqOTDYZXGM8KOdQ= github.com/rakyll/statik v0.1.7/go.mod h1:AlZONWzMtEnMs7W4e/1LURLiI49pIMmp6V9Unghqrcc= github.com/rcrowley/go-metrics v0.0.0-20180503174638-e2704e165165 h1:nkcn14uNmFEuGCb2mBZbBb24RdNRL08b/wb+xBOYpuk= @@ -209,7 +205,6 @@ github.com/regen-network/protobuf v1.3.2-alpha.regen.1/go.mod h1:lye6mqhOn/GCw1z github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= @@ -226,8 +221,6 @@ github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTd github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.1/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s= -github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v0.0.6 h1:breEStsVwemnKh2/s6gMvSdMEkwW0sK8vGStnlVBMCs= github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= @@ -236,7 +229,6 @@ github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0 github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.6.1/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k= github.com/spf13/viper v1.6.2 h1:7aKfF+e8/k68gda3LOjo5RxiUqddoFxVq4BKBPrxk5E= @@ -249,8 +241,6 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.0 h1:DMOzIV76tmoDNE9pX6RSN0aDtCYeCg5VueieJaAo1uw= -github.com/stretchr/testify v1.5.0/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= @@ -279,7 +269,6 @@ github.com/tendermint/tm-db v0.4.1 h1:TvX7JWjJOVZ+N3y+I86wddrGttOdMmmBxXcu0/Y7ZJ github.com/tendermint/tm-db v0.4.1/go.mod h1:JsJ6qzYkCGiGwm5GHl/H5GLI9XLb6qZX7PRe425dHAY= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/zondax/hid v0.9.0 h1:eiT3P6vNxAEVxXMw66eZUAAnU2zD33JBkfG/EnfAKl8= @@ -292,7 +281,6 @@ go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/ go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -327,7 +315,6 @@ golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= From a5fd4705edf66e3fc94c5d5d7a74f05fb41d0a76 Mon Sep 17 00:00:00 2001 From: Marko Date: Fri, 28 Feb 2020 18:36:26 +0100 Subject: [PATCH 284/529] Merge PR #5723: fix config file --- .mergify.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.mergify.yml b/.mergify.yml index f827f6554232..6e153d510b61 100644 --- a/.mergify.yml +++ b/.mergify.yml @@ -1,10 +1,10 @@ pull_request_rules: - - name: automatic merge for master when CI passes, has 1 review and has the label automerge + - name: automerge to master with label automerge and branch protection passing conditions: - "#approved-reviews-by>=1" - - "status-success=ci/circleci - Pull Request" - base=master - label=automerge actions: merge: method: squash + strict: true From 5c1c64bfae95e62dd71960465e54ce05552110a1 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Fri, 28 Feb 2020 09:51:00 -0800 Subject: [PATCH 285/529] Merge PR #5718: Return Empty GasInfo on Failed Msg Validation --- CHANGELOG.md | 2 ++ baseapp/baseapp.go | 3 +-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 138724a6cbab..be120952faf0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -67,6 +67,8 @@ to now accept a `codec.JSONMarshaler` for modular serialization of genesis state ### Bug Fixes +* (baseapp) [\#5718](https://github.com/cosmos/cosmos-sdk/pull/5718) Remove call to `ctx.BlockGasMeter` during failed message validation which +resulted in a panic when the tx execution mode was `CheckTx`. * (client) [\#5618](https://github.com/cosmos/cosmos-sdk/pull/5618) Fix crash on the client when the verifier is not set. * (x/distribution) [\#5620](https://github.com/cosmos/cosmos-sdk/pull/5620) Fix nil pointer deref in distribution tax/rewward validation helpers. * (genesis) [\#5086](https://github.com/cosmos/cosmos-sdk/issues/5086) Ensure `gentxs` are always an empty array instead of `nil` diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 4fe7d0ba803b..0373a199cf07 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -521,8 +521,7 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (gInfo sdk. msgs := tx.GetMsgs() if err := validateBasicTxMsgs(msgs); err != nil { - gInfo = sdk.GasInfo{GasUsed: ctx.BlockGasMeter().GasConsumed()} - return gInfo, nil, err + return sdk.GasInfo{}, nil, err } if app.anteHandler != nil { From 256e5fc863b85f67b53acbf4391281fd3bee4ea6 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Fri, 28 Feb 2020 09:58:55 -0800 Subject: [PATCH 286/529] Update simapp/test_helpers.go --- simapp/test_helpers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simapp/test_helpers.go b/simapp/test_helpers.go index a653a16dc9c6..5bd478eb2d53 100644 --- a/simapp/test_helpers.go +++ b/simapp/test_helpers.go @@ -269,7 +269,7 @@ func CreateTestPubKeys(numPubKeys int) []crypto.PubKey { var publicKeys []crypto.PubKey var buffer bytes.Buffer - //start at 10 to avoid changing 1 to 01, 2 to 02, etc + // start at 10 to avoid changing 1 to 01, 2 to 02, etc for i := 100; i < (numPubKeys + 100); i++ { numString := strconv.Itoa(i) buffer.WriteString("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AF") //base pubkey string From 9aa2088c23b4225e350cd832db534f78c76412dc Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Fri, 28 Feb 2020 09:59:06 -0800 Subject: [PATCH 287/529] Update x/staking/keeper/keeper.go --- x/staking/keeper/keeper.go | 1 + 1 file changed, 1 insertion(+) diff --git a/x/staking/keeper/keeper.go b/x/staking/keeper/keeper.go index 451065b3c2ba..b809e070ca95 100644 --- a/x/staking/keeper/keeper.go +++ b/x/staking/keeper/keeper.go @@ -36,6 +36,7 @@ type Keeper struct { func NewKeeper( cdc codec.Marshaler, key sdk.StoreKey, bk types.BankKeeper, sk types.SupplyKeeper, ps paramtypes.Subspace, ) Keeper { + if !ps.HasKeyTable() { ps = ps.WithKeyTable(ParamKeyTable()) } From 03af49bda292cfa8b550a07da982f968462cf328 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Fri, 28 Feb 2020 09:59:17 -0800 Subject: [PATCH 288/529] Update simapp/test_helpers.go --- simapp/test_helpers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simapp/test_helpers.go b/simapp/test_helpers.go index 5bd478eb2d53..b4ef5dbe022b 100644 --- a/simapp/test_helpers.go +++ b/simapp/test_helpers.go @@ -149,7 +149,7 @@ func addTestAddrs(app *SimApp, ctx sdk.Context, accNum int, accAmt sdk.Int, stra return testAddrs } -//ConvertAddrsToValAddrs converts the provided addresses to +// ConvertAddrsToValAddrs converts the provided addresses to ValAddress. func ConvertAddrsToValAddrs(addrs []sdk.AccAddress) []sdk.ValAddress { valAddrs := make([]sdk.ValAddress, len(addrs)) From 19546f21979485c79366c2847d1a8a4b154b6257 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Fri, 28 Feb 2020 09:59:26 -0800 Subject: [PATCH 289/529] Update simapp/test_helpers.go --- simapp/test_helpers.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/simapp/test_helpers.go b/simapp/test_helpers.go index b4ef5dbe022b..4232e7e8d190 100644 --- a/simapp/test_helpers.go +++ b/simapp/test_helpers.go @@ -272,8 +272,8 @@ func CreateTestPubKeys(numPubKeys int) []crypto.PubKey { // start at 10 to avoid changing 1 to 01, 2 to 02, etc for i := 100; i < (numPubKeys + 100); i++ { numString := strconv.Itoa(i) - buffer.WriteString("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AF") //base pubkey string - buffer.WriteString(numString) //adding on final two digits to make pubkeys unique + buffer.WriteString("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AF") // base pubkey string + buffer.WriteString(numString) // adding on final two digits to make pubkeys unique publicKeys = append(publicKeys, NewPubKeyFromHex(buffer.String())) buffer.Reset() } From f8442bb46f90f5a44658ac28921ec56abf1a5991 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Fri, 28 Feb 2020 19:06:03 +0100 Subject: [PATCH 290/529] add last touches to the PR --- simapp/test_helpers.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/simapp/test_helpers.go b/simapp/test_helpers.go index 4232e7e8d190..3838b26952fb 100644 --- a/simapp/test_helpers.go +++ b/simapp/test_helpers.go @@ -265,6 +265,7 @@ func incrementAllSequenceNumbers(initSeqNums []uint64) { } } +// CreateTestPubKeys generates crypto.PubKeys in ascending order. func CreateTestPubKeys(numPubKeys int) []crypto.PubKey { var publicKeys []crypto.PubKey var buffer bytes.Buffer @@ -281,12 +282,12 @@ func CreateTestPubKeys(numPubKeys int) []crypto.PubKey { return publicKeys } +// NewPubKeyFromHex returns a PubKey from a hex string. func NewPubKeyFromHex(pk string) (res crypto.PubKey) { pkBytes, err := hex.DecodeString(pk) if err != nil { panic(err) } - //res, err = crypto.PubKeyFromBytes(pkBytes) var pkEd ed25519.PubKeyEd25519 copy(pkEd[:], pkBytes) return pkEd From f090da2100fd969d660dd609c1f8298fe368a390 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Fri, 28 Feb 2020 19:07:10 +0100 Subject: [PATCH 291/529] edit text --- simapp/test_helpers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simapp/test_helpers.go b/simapp/test_helpers.go index 3838b26952fb..a557e7f5d397 100644 --- a/simapp/test_helpers.go +++ b/simapp/test_helpers.go @@ -265,7 +265,7 @@ func incrementAllSequenceNumbers(initSeqNums []uint64) { } } -// CreateTestPubKeys generates crypto.PubKeys in ascending order. +// CreateTestPubKeys returns a total of numPubKeys public keys in ascending order. func CreateTestPubKeys(numPubKeys int) []crypto.PubKey { var publicKeys []crypto.PubKey var buffer bytes.Buffer From d0941838954e0ce2d8c8849313da2cbdc3a7736d Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Fri, 28 Feb 2020 18:14:01 +0000 Subject: [PATCH 292/529] Increase code coverage of version up to 100% (#5726) --- version/command.go | 41 ++++++++++++++-------------- version/version_test.go | 60 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 20 deletions(-) create mode 100644 version/version_test.go diff --git a/version/command.go b/version/command.go index 9c3b0cfda285..80163db2d47f 100644 --- a/version/command.go +++ b/version/command.go @@ -2,7 +2,6 @@ package version import ( "encoding/json" - "fmt" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -21,29 +20,31 @@ func init() { var Cmd = &cobra.Command{ Use: "version", Short: "Print the app version", - RunE: func(_ *cobra.Command, _ []string) error { - verInfo := NewInfo() + RunE: runVersionCmd, +} - if !viper.GetBool(flagLong) { - fmt.Println(verInfo.Version) - return nil - } +func runVersionCmd(cmd *cobra.Command, args []string) error { + verInfo := NewInfo() - var bz []byte - var err error + if !viper.GetBool(flagLong) { + cmd.Println(verInfo.Version) + return nil + } - switch viper.GetString(cli.OutputFlag) { - case "json": - bz, err = json.Marshal(verInfo) - default: - bz, err = yaml.Marshal(&verInfo) - } + var bz []byte + var err error - if err != nil { - return err - } + switch viper.GetString(cli.OutputFlag) { + case "json": + bz, err = json.Marshal(verInfo) + default: + bz, err = yaml.Marshal(&verInfo) + } - _, err = fmt.Println(string(bz)) + if err != nil { return err - }, + } + + cmd.Println(string(bz)) + return nil } diff --git a/version/version_test.go b/version/version_test.go new file mode 100644 index 000000000000..d125b9946907 --- /dev/null +++ b/version/version_test.go @@ -0,0 +1,60 @@ +package version + +import ( + "encoding/json" + "fmt" + "runtime" + "testing" + + "github.com/spf13/viper" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/libs/cli" + + "github.com/cosmos/cosmos-sdk/tests" +) + +func TestNewInfo(t *testing.T) { + info := NewInfo() + want := fmt.Sprintf(`: +git commit: +build tags: +%s`, fmt.Sprintf("go version %s %s/%s", runtime.Version(), runtime.GOOS, runtime.GOARCH)) + require.Equal(t, want, info.String()) +} + +func TestInfo_String(t *testing.T) { + info := Info{ + Name: "testapp", + ServerName: "testappd", + ClientName: "testappcli", + Version: "1.0.0", + GitCommit: "1b78457135a4104bc3af97f20654d49e2ea87454", + BuildTags: "netgo,ledger", + GoVersion: "go version go1.14 linux/amd64", + } + want := fmt.Sprintf(`testapp: 1.0.0 +git commit: 1b78457135a4104bc3af97f20654d49e2ea87454 +build tags: netgo,ledger +go version go1.14 linux/amd64`) + require.Equal(t, want, info.String()) +} + +func Test_runVersionCmd(t *testing.T) { + require.NotNil(t, Cmd) + _, mockOut, _ := tests.ApplyMockIO(Cmd) + + viper.Set(cli.OutputFlag, "") + viper.Set(flagLong, false) + require.NoError(t, runVersionCmd(Cmd, nil)) + assert.Equal(t, "\n", mockOut.String()) + mockOut.Reset() + + viper.Set(cli.OutputFlag, "json") + viper.Set(flagLong, true) + info := NewInfo() + stringInfo, err := json.Marshal(info) + require.NoError(t, err) + require.NoError(t, runVersionCmd(Cmd, nil)) + assert.Equal(t, string(stringInfo)+"\n", mockOut.String()) +} From 7080949f4e3f79c21c445bc3eb3fac99820ca709 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Fri, 28 Feb 2020 18:27:42 +0000 Subject: [PATCH 293/529] Update CODEOWNERS as per @jaekwon's directives (#5728) --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index ca82ba88da02..a5519d4ce565 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,4 +1,4 @@ # CODEOWNERS: https://help.github.com/articles/about-codeowners/ # Primary repo maintainers -* @alexanderbez @jackzampolin @alessio @fedekunze +* @alexanderbez @alessio @fedekunze @nylira @hschoenburg From 5f14dc2e4214151064069779233c47939aab9412 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Fri, 28 Feb 2020 23:05:28 +0000 Subject: [PATCH 294/529] Increase coverage across the store package (#5727) --- Makefile | 1 + store/dbadapter/store_test.go | 70 ++++++++++ store/transient/store_test.go | 15 ++- store/types/pruning_test.go | 79 +++++++++++ tests/mocks/account_retriever.go | 13 +- tests/mocks/tendermint_tm_db_DB.go | 206 +++++++++++++++++++++++++++++ 6 files changed, 380 insertions(+), 4 deletions(-) create mode 100644 store/dbadapter/store_test.go create mode 100644 store/types/pruning_test.go create mode 100644 tests/mocks/tendermint_tm_db_DB.go diff --git a/Makefile b/Makefile index 68d7a359abca..a634915bfe0a 100644 --- a/Makefile +++ b/Makefile @@ -26,6 +26,7 @@ build: go.sum mocks: $(MOCKS_DIR) mockgen -source=x/auth/types/account_retriever.go -package mocks -destination tests/mocks/account_retriever.go + mockgen -package mocks -destination tests/mocks/tendermint_tm_db_DB.go github.com/tendermint/tm-db DB .PHONY: mocks $(MOCKS_DIR): diff --git a/store/dbadapter/store_test.go b/store/dbadapter/store_test.go new file mode 100644 index 000000000000..a29e3f6c8d87 --- /dev/null +++ b/store/dbadapter/store_test.go @@ -0,0 +1,70 @@ +package dbadapter_test + +import ( + "bytes" + "errors" + "testing" + + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/store/dbadapter" + "github.com/cosmos/cosmos-sdk/store/types" + "github.com/cosmos/cosmos-sdk/tests/mocks" +) + +var errFoo = errors.New("dummy") + +func TestAccessors(t *testing.T) { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + mockDB := mocks.NewMockDB(mockCtrl) + store := dbadapter.Store{mockDB} + key := []byte("test") + value := []byte("testvalue") + + require.Equal(t, types.StoreTypeDB, store.GetStoreType()) + store.GetStoreType() + + retFoo := []byte("xxx") + mockDB.EXPECT().Get(gomock.Eq(key)).Times(1).Return(retFoo, nil) + require.True(t, bytes.Equal(retFoo, store.Get(key))) + + mockDB.EXPECT().Get(gomock.Eq(key)).Times(1).Return(nil, errFoo) + require.Panics(t, func() { store.Get(key) }) + + mockDB.EXPECT().Has(gomock.Eq(key)).Times(1).Return(true, nil) + require.True(t, store.Has(key)) + + mockDB.EXPECT().Has(gomock.Eq(key)).Times(1).Return(false, nil) + require.False(t, store.Has(key)) + + mockDB.EXPECT().Has(gomock.Eq(key)).Times(1).Return(false, errFoo) + require.Panics(t, func() { store.Has(key) }) + + mockDB.EXPECT().Set(gomock.Eq(key), gomock.Eq(value)).Times(1).Return(nil) + require.NotPanics(t, func() { store.Set(key, value) }) + + mockDB.EXPECT().Set(gomock.Eq(key), gomock.Eq(value)).Times(1).Return(errFoo) + require.Panics(t, func() { store.Set(key, value) }) + + mockDB.EXPECT().Delete(gomock.Eq(key)).Times(1).Return(nil) + require.NotPanics(t, func() { store.Delete(key) }) + + mockDB.EXPECT().Delete(gomock.Eq(key)).Times(1).Return(errFoo) + require.Panics(t, func() { store.Delete(key) }) + + start, end := []byte("start"), []byte("end") + mockDB.EXPECT().Iterator(gomock.Eq(start), gomock.Eq(end)).Times(1).Return(nil, nil) + require.NotPanics(t, func() { store.Iterator(start, end) }) + + mockDB.EXPECT().Iterator(gomock.Eq(start), gomock.Eq(end)).Times(1).Return(nil, errFoo) + require.Panics(t, func() { store.Iterator(start, end) }) + + mockDB.EXPECT().ReverseIterator(gomock.Eq(start), gomock.Eq(end)).Times(1).Return(nil, nil) + require.NotPanics(t, func() { store.ReverseIterator(start, end) }) + + mockDB.EXPECT().ReverseIterator(gomock.Eq(start), gomock.Eq(end)).Times(1).Return(nil, errFoo) + require.Panics(t, func() { store.ReverseIterator(start, end) }) +} diff --git a/store/transient/store_test.go b/store/transient/store_test.go index 846c8a3a43ca..113d95be867b 100644 --- a/store/transient/store_test.go +++ b/store/transient/store_test.go @@ -1,15 +1,18 @@ -package transient +package transient_test import ( + "bytes" "testing" + "github.com/cosmos/cosmos-sdk/store/transient" + "github.com/cosmos/cosmos-sdk/store/types" "github.com/stretchr/testify/require" ) var k, v = []byte("hello"), []byte("world") func TestTransientStore(t *testing.T) { - tstore := NewStore() + tstore := transient.NewStore() require.Nil(t, tstore.Get(k)) @@ -20,4 +23,12 @@ func TestTransientStore(t *testing.T) { tstore.Commit() require.Nil(t, tstore.Get(k)) + + // no-op + tstore.SetPruning(types.PruningOptions{}) + + emptyCommitID := tstore.LastCommitID() + require.Equal(t, emptyCommitID.Version, int64(0)) + require.True(t, bytes.Equal(emptyCommitID.Hash, nil)) + require.Equal(t, types.StoreTypeTransient, tstore.GetStoreType()) } diff --git a/store/types/pruning_test.go b/store/types/pruning_test.go new file mode 100644 index 000000000000..4187d16a4cff --- /dev/null +++ b/store/types/pruning_test.go @@ -0,0 +1,79 @@ +package types_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/store/types" +) + +func TestPruningOptions_FlushVersion(t *testing.T) { + t.Parallel() + require.True(t, types.PruneEverything.FlushVersion(-1)) + require.True(t, types.PruneEverything.FlushVersion(0)) + require.True(t, types.PruneEverything.FlushVersion(1)) + require.True(t, types.PruneEverything.FlushVersion(2)) + + require.True(t, types.PruneNothing.FlushVersion(-1)) + require.True(t, types.PruneNothing.FlushVersion(0)) + require.True(t, types.PruneNothing.FlushVersion(1)) + require.True(t, types.PruneNothing.FlushVersion(2)) + + require.False(t, types.PruneSyncable.FlushVersion(-1)) + require.True(t, types.PruneSyncable.FlushVersion(0)) + require.False(t, types.PruneSyncable.FlushVersion(1)) + require.True(t, types.PruneSyncable.FlushVersion(100)) + require.False(t, types.PruneSyncable.FlushVersion(101)) +} + +func TestPruningOptions_SnapshotVersion(t *testing.T) { + t.Parallel() + require.False(t, types.PruneEverything.SnapshotVersion(-1)) + require.False(t, types.PruneEverything.SnapshotVersion(0)) + require.False(t, types.PruneEverything.SnapshotVersion(1)) + require.False(t, types.PruneEverything.SnapshotVersion(2)) + + require.True(t, types.PruneNothing.SnapshotVersion(-1)) + require.True(t, types.PruneNothing.SnapshotVersion(0)) + require.True(t, types.PruneNothing.SnapshotVersion(1)) + require.True(t, types.PruneNothing.SnapshotVersion(2)) + + require.False(t, types.PruneSyncable.SnapshotVersion(-1)) + require.True(t, types.PruneSyncable.SnapshotVersion(0)) + require.False(t, types.PruneSyncable.SnapshotVersion(1)) + require.True(t, types.PruneSyncable.SnapshotVersion(10000)) + require.False(t, types.PruneSyncable.SnapshotVersion(10001)) +} + +func TestPruningOptions_IsValid(t *testing.T) { + t.Parallel() + type fields struct { + KeepEvery int64 + SnapshotEvery int64 + } + tests := []struct { + name string + fields fields + want bool + }{ + {"PruneEverything", fields{types.PruneEverything.KeepEvery, types.PruneEverything.SnapshotEvery}, true}, + {"PruneNothing", fields{types.PruneNothing.KeepEvery, types.PruneNothing.SnapshotEvery}, true}, + {"PruneSyncable", fields{types.PruneSyncable.KeepEvery, types.PruneSyncable.SnapshotEvery}, true}, + {"KeepEvery=0", fields{0, 0}, false}, + {"KeepEvery<0", fields{-1, 0}, false}, + {"SnapshotEvery<0", fields{1, -1}, false}, + {"SnapshotEvery%KeepEvery!=0", fields{15, 30}, true}, + {"SnapshotEvery%KeepEvery!=0", fields{15, 20}, false}, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + po := types.PruningOptions{ + KeepEvery: tt.fields.KeepEvery, + SnapshotEvery: tt.fields.SnapshotEvery, + } + require.Equal(t, tt.want, po.IsValid(), "IsValid() = %v, want %v", po.IsValid(), tt.want) + }) + } +} diff --git a/tests/mocks/account_retriever.go b/tests/mocks/account_retriever.go index 9f8ee69282a2..a3086c77bdca 100644 --- a/tests/mocks/account_retriever.go +++ b/tests/mocks/account_retriever.go @@ -1,30 +1,38 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: x/auth/types/account_retriever.go + +// Package mocks is a generated GoMock package. package mocks import ( - reflect "reflect" - gomock "github.com/golang/mock/gomock" + reflect "reflect" ) +// MockNodeQuerier is a mock of NodeQuerier interface type MockNodeQuerier struct { ctrl *gomock.Controller recorder *MockNodeQuerierMockRecorder } +// MockNodeQuerierMockRecorder is the mock recorder for MockNodeQuerier type MockNodeQuerierMockRecorder struct { mock *MockNodeQuerier } +// NewMockNodeQuerier creates a new mock instance func NewMockNodeQuerier(ctrl *gomock.Controller) *MockNodeQuerier { mock := &MockNodeQuerier{ctrl: ctrl} mock.recorder = &MockNodeQuerierMockRecorder{mock} return mock } +// EXPECT returns an object that allows the caller to indicate expected use func (m *MockNodeQuerier) EXPECT() *MockNodeQuerierMockRecorder { return m.recorder } +// QueryWithData mocks base method func (m *MockNodeQuerier) QueryWithData(path string, data []byte) ([]byte, int64, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "QueryWithData", path, data) @@ -34,6 +42,7 @@ func (m *MockNodeQuerier) QueryWithData(path string, data []byte) ([]byte, int64 return ret0, ret1, ret2 } +// QueryWithData indicates an expected call of QueryWithData func (mr *MockNodeQuerierMockRecorder) QueryWithData(path, data interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryWithData", reflect.TypeOf((*MockNodeQuerier)(nil).QueryWithData), path, data) diff --git a/tests/mocks/tendermint_tm_db_DB.go b/tests/mocks/tendermint_tm_db_DB.go new file mode 100644 index 000000000000..bed59a498d03 --- /dev/null +++ b/tests/mocks/tendermint_tm_db_DB.go @@ -0,0 +1,206 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/tendermint/tm-db (interfaces: DB) + +// Package mocks is a generated GoMock package. +package mocks + +import ( + gomock "github.com/golang/mock/gomock" + tm_db "github.com/tendermint/tm-db" + reflect "reflect" +) + +// MockDB is a mock of DB interface +type MockDB struct { + ctrl *gomock.Controller + recorder *MockDBMockRecorder +} + +// MockDBMockRecorder is the mock recorder for MockDB +type MockDBMockRecorder struct { + mock *MockDB +} + +// NewMockDB creates a new mock instance +func NewMockDB(ctrl *gomock.Controller) *MockDB { + mock := &MockDB{ctrl: ctrl} + mock.recorder = &MockDBMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockDB) EXPECT() *MockDBMockRecorder { + return m.recorder +} + +// Close mocks base method +func (m *MockDB) Close() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Close") + ret0, _ := ret[0].(error) + return ret0 +} + +// Close indicates an expected call of Close +func (mr *MockDBMockRecorder) Close() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockDB)(nil).Close)) +} + +// Delete mocks base method +func (m *MockDB) Delete(arg0 []byte) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Delete", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// Delete indicates an expected call of Delete +func (mr *MockDBMockRecorder) Delete(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockDB)(nil).Delete), arg0) +} + +// DeleteSync mocks base method +func (m *MockDB) DeleteSync(arg0 []byte) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteSync", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteSync indicates an expected call of DeleteSync +func (mr *MockDBMockRecorder) DeleteSync(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteSync", reflect.TypeOf((*MockDB)(nil).DeleteSync), arg0) +} + +// Get mocks base method +func (m *MockDB) Get(arg0 []byte) ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Get", arg0) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Get indicates an expected call of Get +func (mr *MockDBMockRecorder) Get(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockDB)(nil).Get), arg0) +} + +// Has mocks base method +func (m *MockDB) Has(arg0 []byte) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Has", arg0) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Has indicates an expected call of Has +func (mr *MockDBMockRecorder) Has(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Has", reflect.TypeOf((*MockDB)(nil).Has), arg0) +} + +// Iterator mocks base method +func (m *MockDB) Iterator(arg0, arg1 []byte) (tm_db.Iterator, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Iterator", arg0, arg1) + ret0, _ := ret[0].(tm_db.Iterator) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Iterator indicates an expected call of Iterator +func (mr *MockDBMockRecorder) Iterator(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Iterator", reflect.TypeOf((*MockDB)(nil).Iterator), arg0, arg1) +} + +// NewBatch mocks base method +func (m *MockDB) NewBatch() tm_db.Batch { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NewBatch") + ret0, _ := ret[0].(tm_db.Batch) + return ret0 +} + +// NewBatch indicates an expected call of NewBatch +func (mr *MockDBMockRecorder) NewBatch() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewBatch", reflect.TypeOf((*MockDB)(nil).NewBatch)) +} + +// Print mocks base method +func (m *MockDB) Print() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Print") + ret0, _ := ret[0].(error) + return ret0 +} + +// Print indicates an expected call of Print +func (mr *MockDBMockRecorder) Print() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Print", reflect.TypeOf((*MockDB)(nil).Print)) +} + +// ReverseIterator mocks base method +func (m *MockDB) ReverseIterator(arg0, arg1 []byte) (tm_db.Iterator, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ReverseIterator", arg0, arg1) + ret0, _ := ret[0].(tm_db.Iterator) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ReverseIterator indicates an expected call of ReverseIterator +func (mr *MockDBMockRecorder) ReverseIterator(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReverseIterator", reflect.TypeOf((*MockDB)(nil).ReverseIterator), arg0, arg1) +} + +// Set mocks base method +func (m *MockDB) Set(arg0, arg1 []byte) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Set", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// Set indicates an expected call of Set +func (mr *MockDBMockRecorder) Set(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Set", reflect.TypeOf((*MockDB)(nil).Set), arg0, arg1) +} + +// SetSync mocks base method +func (m *MockDB) SetSync(arg0, arg1 []byte) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetSync", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// SetSync indicates an expected call of SetSync +func (mr *MockDBMockRecorder) SetSync(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetSync", reflect.TypeOf((*MockDB)(nil).SetSync), arg0, arg1) +} + +// Stats mocks base method +func (m *MockDB) Stats() map[string]string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Stats") + ret0, _ := ret[0].(map[string]string) + return ret0 +} + +// Stats indicates an expected call of Stats +func (mr *MockDBMockRecorder) Stats() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stats", reflect.TypeOf((*MockDB)(nil).Stats)) +} From 2ae25caa74e43870bb44bf629909e38c3613dfe8 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Sun, 1 Mar 2020 15:38:57 +0000 Subject: [PATCH 295/529] linter fixes (#5733) * make .golangcy.yml work with Goland's Golint plugin Explicitly disable all linters. Whitelist of enabled plugins is already provided. This would enable Goland users to user Golint plugin. * fix deadcode warnings * fix gocritic error unslice: could simplify pkBytes[:] to pkBytes --- .golangci.yml | 3 +-- x/gov/keeper/test_common.go | 6 +----- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 8e5c493b49b2..d109df4a6ee2 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -3,6 +3,7 @@ # timeout: 5m linters: + disable-all: true enable: - bodyclose - deadcode @@ -30,8 +31,6 @@ linters: - unconvert - unused - misspell - disable: - - errcheck issues: exclude-rules: diff --git a/x/gov/keeper/test_common.go b/x/gov/keeper/test_common.go index 84df63afb549..d8620b1a8cd9 100644 --- a/x/gov/keeper/test_common.go +++ b/x/gov/keeper/test_common.go @@ -56,10 +56,6 @@ var ( pubkeys = []crypto.PubKey{ delPk1, delPk2, delPk3, valOpPk1, valOpPk2, valOpPk3, } - - emptyDelAddr sdk.AccAddress - emptyValAddr sdk.ValAddress - emptyPubkey crypto.PubKey ) // TODO: remove dependency with staking @@ -76,7 +72,7 @@ func newPubKey(pk string) (res crypto.PubKey) { panic(err) } var pkEd ed25519.PubKeyEd25519 - copy(pkEd[:], pkBytes[:]) + copy(pkEd[:], pkBytes) return pkEd } From 8fd85e16a55edf0dc797dcd260a9c7759a5bef89 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Sun, 1 Mar 2020 16:18:22 +0000 Subject: [PATCH 296/529] Tweak mergify config Set minimum approvers number to be strictly greater than 1. --- .mergify.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mergify.yml b/.mergify.yml index 6e153d510b61..fbf9d7015ae8 100644 --- a/.mergify.yml +++ b/.mergify.yml @@ -1,7 +1,7 @@ pull_request_rules: - name: automerge to master with label automerge and branch protection passing conditions: - - "#approved-reviews-by>=1" + - "#approved-reviews-by>1" - base=master - label=automerge actions: From d7fd5b6a42abeacc093766068a7b642c25817f12 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Mon, 2 Mar 2020 00:16:23 +0000 Subject: [PATCH 297/529] Replace defer with testing.T.Cleanup() (#5732) --- client/keys/add_ledger_test.go | 12 ++++++------ client/keys/add_test.go | 6 +++--- client/keys/delete_test.go | 6 +++--- client/keys/export_test.go | 6 +++--- client/keys/import_test.go | 6 +++--- client/keys/list_test.go | 8 ++++---- client/keys/migrate_test.go | 5 ++--- client/keys/mnemonic_test.go | 12 ++++-------- client/keys/show_test.go | 6 +++--- client/keys/types_test.go | 29 ++++++++++++++++++++++++++++ client/keys/update_test.go | 5 ++--- crypto/keys/keyring_test.go | 14 +++++++------- crypto/keys/lazy_keybase_test.go | 24 +++++++++++------------ server/constructors_test.go | 4 ++-- server/init_test.go | 4 ++-- x/genutil/client/cli/init_test.go | 18 ++++++++--------- x/genutil/client/cli/migrate_test.go | 3 +-- x/genutil/utils_test.go | 2 +- x/upgrade/types/storeloader_test.go | 4 ++-- 19 files changed, 98 insertions(+), 76 deletions(-) create mode 100644 client/keys/types_test.go diff --git a/client/keys/add_ledger_test.go b/client/keys/add_ledger_test.go index 0b8efe8e66de..d69dae252a67 100644 --- a/client/keys/add_ledger_test.go +++ b/client/keys/add_ledger_test.go @@ -39,7 +39,7 @@ func Test_runAddCmdLedgerWithCustomCoinType(t *testing.T) { // Prepare a keybase kbHome, kbCleanUp := tests.NewTestCaseDir(t) require.NotNil(t, kbHome) - defer kbCleanUp() + t.Cleanup(kbCleanUp) viper.Set(flags.FlagHome, kbHome) viper.Set(flags.FlagUseLedger, true) @@ -54,9 +54,9 @@ func Test_runAddCmdLedgerWithCustomCoinType(t *testing.T) { kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) require.NoError(t, err) require.NotNil(t, kb) - defer func() { + t.Cleanup(func() { kb.Delete("keyname1", "", false) - }() + }) mockIn.Reset("test1234\n") if runningUnattended { mockIn.Reset("test1234\ntest1234\n") @@ -87,7 +87,7 @@ func Test_runAddCmdLedger(t *testing.T) { // Prepare a keybase kbHome, kbCleanUp := tests.NewTestCaseDir(t) require.NotNil(t, kbHome) - defer kbCleanUp() + t.Cleanup(kbCleanUp) viper.Set(flags.FlagHome, kbHome) viper.Set(flags.FlagUseLedger, true) @@ -101,9 +101,9 @@ func Test_runAddCmdLedger(t *testing.T) { kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), kbHome, mockIn) require.NoError(t, err) require.NotNil(t, kb) - defer func() { + t.Cleanup(func() { kb.Delete("keyname1", "", false) - }() + }) mockIn.Reset("test1234\n") if runningUnattended { mockIn.Reset("test1234\ntest1234\n") diff --git a/client/keys/add_test.go b/client/keys/add_test.go index b1ebee331684..5d2eb8ddf0da 100644 --- a/client/keys/add_test.go +++ b/client/keys/add_test.go @@ -23,7 +23,7 @@ func Test_runAddCmdBasic(t *testing.T) { kbHome, kbCleanUp := tests.NewTestCaseDir(t) assert.NotNil(t, kbHome) - defer kbCleanUp() + t.Cleanup(kbCleanUp) viper.Set(flags.FlagHome, kbHome) viper.Set(cli.OutputFlag, OutputFormatText) @@ -33,10 +33,10 @@ func Test_runAddCmdBasic(t *testing.T) { mockIn.Reset("y\n") kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), kbHome, mockIn) require.NoError(t, err) - defer func() { + t.Cleanup(func() { kb.Delete("keyname1", "", false) kb.Delete("keyname2", "", false) - }() + }) } assert.NoError(t, runAddCmd(cmd, []string{"keyname1"})) diff --git a/client/keys/delete_test.go b/client/keys/delete_test.go index b2df8684dffe..5c4c1a5b70a9 100644 --- a/client/keys/delete_test.go +++ b/client/keys/delete_test.go @@ -29,15 +29,15 @@ func Test_runDeleteCmd(t *testing.T) { if !runningUnattended { kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) require.NoError(t, err) - defer func() { + t.Cleanup(func() { kb.Delete("runDeleteCmd_Key1", "", false) kb.Delete("runDeleteCmd_Key2", "", false) - }() + }) } // Now add a temporary keybase kbHome, cleanUp := tests.NewTestCaseDir(t) - defer cleanUp() + t.Cleanup(cleanUp) viper.Set(flags.FlagHome, kbHome) // Now diff --git a/client/keys/export_test.go b/client/keys/export_test.go index 4d0236cdd05a..dff9d344cc14 100644 --- a/client/keys/export_test.go +++ b/client/keys/export_test.go @@ -19,16 +19,16 @@ func Test_runExportCmd(t *testing.T) { // Now add a temporary keybase kbHome, cleanUp := tests.NewTestCaseDir(t) - defer cleanUp() + t.Cleanup(cleanUp) viper.Set(flags.FlagHome, kbHome) // create a key kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) require.NoError(t, err) if !runningUnattended { - defer func() { + t.Cleanup(func() { kb.Delete("keyname1", "", false) - }() + }) } if runningUnattended { diff --git a/client/keys/import_test.go b/client/keys/import_test.go index faac935179bb..3ccb606ee955 100644 --- a/client/keys/import_test.go +++ b/client/keys/import_test.go @@ -21,15 +21,15 @@ func Test_runImportCmd(t *testing.T) { // Now add a temporary keybase kbHome, cleanUp := tests.NewTestCaseDir(t) - defer cleanUp() + t.Cleanup(cleanUp) viper.Set(flags.FlagHome, kbHome) if !runningUnattended { kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) require.NoError(t, err) - defer func() { + t.Cleanup(func() { kb.Delete("keyname1", "", false) - }() + }) } keyfile := filepath.Join(kbHome, "key.asc") diff --git a/client/keys/list_test.go b/client/keys/list_test.go index ac8ca97d0fb5..94997e86c015 100644 --- a/client/keys/list_test.go +++ b/client/keys/list_test.go @@ -24,11 +24,11 @@ func Test_runListCmd(t *testing.T) { // Prepare some keybases kbHome1, cleanUp1 := tests.NewTestCaseDir(t) - defer cleanUp1() + t.Cleanup(cleanUp1) // Do nothing, leave home1 empty kbHome2, cleanUp2 := tests.NewTestCaseDir(t) - defer cleanUp2() + t.Cleanup(cleanUp2) viper.Set(flags.FlagHome, kbHome2) mockIn, _, _ := tests.ApplyMockIO(cmdBasic) @@ -41,9 +41,9 @@ func Test_runListCmd(t *testing.T) { _, err = kb.CreateAccount("something", tests.TestMnemonic, "", "", "", keys.Secp256k1) require.NoError(t, err) - defer func() { + t.Cleanup(func() { kb.Delete("something", "", false) - }() + }) testData := []struct { name string kbDir string diff --git a/client/keys/migrate_test.go b/client/keys/migrate_test.go index 0ad9226d309d..aec085ecc1d2 100644 --- a/client/keys/migrate_test.go +++ b/client/keys/migrate_test.go @@ -19,14 +19,13 @@ func Test_runMigrateCmd(t *testing.T) { kbHome, kbCleanUp := tests.NewTestCaseDir(t) assert.NotNil(t, kbHome) - defer kbCleanUp() + t.Cleanup(kbCleanUp) viper.Set(flags.FlagHome, kbHome) viper.Set(cli.OutputFlag, OutputFormatText) mockIn.Reset("test1234\ntest1234\n") - err := runAddCmd(cmd, []string{"keyname1"}) - assert.NoError(t, err) + assert.NoError(t, runAddCmd(cmd, []string{"keyname1"})) viper.Set(flags.FlagDryRun, true) cmd = MigrateCommand() diff --git a/client/keys/mnemonic_test.go b/client/keys/mnemonic_test.go index 7097ef0a3ca5..a3e84e7182d6 100644 --- a/client/keys/mnemonic_test.go +++ b/client/keys/mnemonic_test.go @@ -12,8 +12,7 @@ import ( func Test_RunMnemonicCmdNormal(t *testing.T) { cmdBasic := MnemonicKeyCommand() - err := runMnemonicCmd(cmdBasic, []string{}) - require.NoError(t, err) + require.NoError(t, runMnemonicCmd(cmdBasic, []string{})) } func Test_RunMnemonicCmdUser(t *testing.T) { @@ -37,18 +36,15 @@ func Test_RunMnemonicCmdUser(t *testing.T) { // Now provide "good" entropy :) fakeEntropy := strings.Repeat(":)", 40) + "\ny\n" // entropy + accept count mockIn.Reset(fakeEntropy) - err = runMnemonicCmd(cmdUser, []string{}) - require.NoError(t, err) + require.NoError(t, runMnemonicCmd(cmdUser, []string{})) // Now provide "good" entropy but no answer fakeEntropy = strings.Repeat(":)", 40) + "\n" // entropy + accept count mockIn.Reset(fakeEntropy) - err = runMnemonicCmd(cmdUser, []string{}) - require.Error(t, err) + require.Error(t, runMnemonicCmd(cmdUser, []string{})) // Now provide "good" entropy but say no fakeEntropy = strings.Repeat(":)", 40) + "\nn\n" // entropy + accept count mockIn.Reset(fakeEntropy) - err = runMnemonicCmd(cmdUser, []string{}) - require.NoError(t, err) + require.NoError(t, runMnemonicCmd(cmdUser, []string{})) } diff --git a/client/keys/show_test.go b/client/keys/show_test.go index ec84eea49ef6..80bb86505928 100644 --- a/client/keys/show_test.go +++ b/client/keys/show_test.go @@ -44,17 +44,17 @@ func Test_runShowCmd(t *testing.T) { // Prepare a key base // Now add a temporary keybase kbHome, cleanUp := tests.NewTestCaseDir(t) - defer cleanUp() + t.Cleanup(cleanUp) viper.Set(flags.FlagHome, kbHome) fakeKeyName1 := "runShowCmd_Key1" fakeKeyName2 := "runShowCmd_Key2" kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) require.NoError(t, err) - defer func() { + t.Cleanup(func() { kb.Delete("runShowCmd_Key1", "", false) kb.Delete("runShowCmd_Key2", "", false) - }() + }) if runningUnattended { mockIn.Reset("testpass1\ntestpass1\n") } diff --git a/client/keys/types_test.go b/client/keys/types_test.go new file mode 100644 index 000000000000..24428a5b9261 --- /dev/null +++ b/client/keys/types_test.go @@ -0,0 +1,29 @@ +package keys_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/client/keys" +) + +func TestConstructors(t *testing.T) { + require.Equal(t, keys.AddNewKey{ + Name: "name", + Password: "password", + Mnemonic: "mnemonic", + Account: 1, + Index: 1, + }, keys.NewAddNewKey("name", "password", "mnemonic", 1, 1)) + + require.Equal(t, keys.RecoverKey{ + Password: "password", + Mnemonic: "mnemonic", + Account: 1, + Index: 1, + }, keys.NewRecoverKey("password", "mnemonic", 1, 1)) + + require.Equal(t, keys.UpdateKeyReq{OldPassword: "old", NewPassword: "new"}, keys.NewUpdateKeyReq("old", "new")) + require.Equal(t, keys.DeleteKeyReq{Password: "password"}, keys.NewDeleteKeyReq("password")) +} diff --git a/client/keys/update_test.go b/client/keys/update_test.go index 351cedd578ce..d763e9e7646d 100644 --- a/client/keys/update_test.go +++ b/client/keys/update_test.go @@ -12,8 +12,7 @@ import ( ) func Test_updateKeyCommand(t *testing.T) { - cmd := UpdateKeyCommand() - assert.NotNil(t, cmd) + assert.NotNil(t, UpdateKeyCommand()) // No flags or defaults to validate } @@ -34,7 +33,7 @@ func Test_runUpdateCmd(t *testing.T) { // Prepare a key base // Now add a temporary keybase kbHome, cleanUp1 := tests.NewTestCaseDir(t) - defer cleanUp1() + t.Cleanup(cleanUp1) viper.Set(flags.FlagHome, kbHome) kb, err := NewKeyBaseFromDir(viper.GetString(flags.FlagHome)) diff --git a/crypto/keys/keyring_test.go b/crypto/keys/keyring_test.go index 066f438e030f..4c024fab9574 100644 --- a/crypto/keys/keyring_test.go +++ b/crypto/keys/keyring_test.go @@ -16,7 +16,7 @@ import ( func TestLazyKeyManagementKeyRing(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) - defer cleanup() + t.Cleanup(cleanup) kb, err := NewKeyring("keybasename", "test", dir, nil) require.NoError(t, err) @@ -100,7 +100,7 @@ func TestLazyKeyManagementKeyRing(t *testing.T) { func TestLazySignVerifyKeyRing(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) - defer cleanup() + t.Cleanup(cleanup) kb, err := NewKeyring("keybasename", "test", dir, nil) require.NoError(t, err) algo := Secp256k1 @@ -176,7 +176,7 @@ func TestLazySignVerifyKeyRing(t *testing.T) { func TestLazyExportImportKeyRing(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) - defer cleanup() + t.Cleanup(cleanup) kb, err := NewKeyring("keybasename", "test", dir, nil) require.NoError(t, err) @@ -205,7 +205,7 @@ func TestLazyExportImportKeyRing(t *testing.T) { func TestLazyExportImportPubKeyKeyRing(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) - defer cleanup() + t.Cleanup(cleanup) kb, err := NewKeyring("keybasename", "test", dir, nil) require.NoError(t, err) algo := Secp256k1 @@ -246,7 +246,7 @@ func TestLazyExportImportPubKeyKeyRing(t *testing.T) { func TestLazyExportPrivateKeyObjectKeyRing(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) - defer cleanup() + t.Cleanup(cleanup) kb, err := NewKeyring("keybasename", "test", dir, nil) require.NoError(t, err) @@ -262,7 +262,7 @@ func TestLazyExportPrivateKeyObjectKeyRing(t *testing.T) { func TestLazyAdvancedKeyManagementKeyRing(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) - defer cleanup() + t.Cleanup(cleanup) kb, err := NewKeyring("keybasename", "test", dir, nil) require.NoError(t, err) @@ -296,7 +296,7 @@ func TestLazyAdvancedKeyManagementKeyRing(t *testing.T) { func TestLazySeedPhraseKeyRing(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) - defer cleanup() + t.Cleanup(cleanup) kb, err := NewKeyring("keybasename", "test", dir, nil) require.NoError(t, err) diff --git a/crypto/keys/lazy_keybase_test.go b/crypto/keys/lazy_keybase_test.go index 19d5445297f2..bd5b742acdfd 100644 --- a/crypto/keys/lazy_keybase_test.go +++ b/crypto/keys/lazy_keybase_test.go @@ -18,7 +18,7 @@ import ( func TestNew(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) - defer cleanup() + t.Cleanup(cleanup) kb := New("keybasename", dir) lazykb, ok := kb.(lazyKeybase) require.True(t, ok) @@ -28,7 +28,7 @@ func TestNew(t *testing.T) { func TestLazyKeyManagement(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) - defer cleanup() + t.Cleanup(cleanup) kb := New("keybasename", dir) algo := Secp256k1 @@ -111,7 +111,7 @@ func TestLazyKeyManagement(t *testing.T) { func TestLazySignVerify(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) - defer cleanup() + t.Cleanup(cleanup) kb := New("keybasename", dir) algo := Secp256k1 @@ -186,7 +186,7 @@ func TestLazySignVerify(t *testing.T) { func TestLazyExportImport(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) - defer cleanup() + t.Cleanup(cleanup) kb := New("keybasename", dir) info, _, err := kb.CreateMnemonic("john", English, "secretcpw", Secp256k1) @@ -214,7 +214,7 @@ func TestLazyExportImport(t *testing.T) { func TestLazyExportImportPrivKey(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) - defer cleanup() + t.Cleanup(cleanup) kb := New("keybasename", dir) info, _, err := kb.CreateMnemonic("john", English, "secretcpw", Secp256k1) @@ -243,7 +243,7 @@ func TestLazyExportImportPrivKey(t *testing.T) { func TestLazyExportImportPubKey(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) - defer cleanup() + t.Cleanup(cleanup) kb := New("keybasename", dir) algo := Secp256k1 @@ -283,7 +283,7 @@ func TestLazyExportImportPubKey(t *testing.T) { func TestLazyExportPrivateKeyObject(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) - defer cleanup() + t.Cleanup(cleanup) kb := New("keybasename", dir) info, _, err := kb.CreateMnemonic("john", English, "secretcpw", Secp256k1) @@ -300,7 +300,7 @@ func TestLazyExportPrivateKeyObject(t *testing.T) { func TestLazyAdvancedKeyManagement(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) - defer cleanup() + t.Cleanup(cleanup) kb := New("keybasename", dir) algo := Secp256k1 @@ -348,7 +348,7 @@ func TestLazyAdvancedKeyManagement(t *testing.T) { // TestSeedPhrase verifies restoring from a seed phrase func TestLazySeedPhrase(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) - defer cleanup() + t.Cleanup(cleanup) kb := New("keybasename", dir) algo := Secp256k1 @@ -401,13 +401,13 @@ func (key testPub) Equals(other crypto.PubKey) bool { return true } func TestKeygenOverride(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) - defer cleanup() + t.Cleanup(cleanup) // Save existing codec and reset after test cryptoCdc := CryptoCdc - defer func() { + t.Cleanup(func() { CryptoCdc = cryptoCdc - }() + }) // Setup testCdc encoding and decoding new key type testCdc = codec.New() diff --git a/server/constructors_test.go b/server/constructors_test.go index e1da004a63f9..e11520fe5826 100644 --- a/server/constructors_test.go +++ b/server/constructors_test.go @@ -12,7 +12,7 @@ import ( func Test_openDB(t *testing.T) { t.Parallel() dir, cleanup := tests.NewTestCaseDir(t) - defer cleanup() + t.Cleanup(cleanup) _, err := openDB(dir) require.NoError(t, err) } @@ -20,7 +20,7 @@ func Test_openDB(t *testing.T) { func Test_openTraceWriter(t *testing.T) { t.Parallel() dir, cleanup := tests.NewTestCaseDir(t) - defer cleanup() + t.Cleanup(cleanup) fname := filepath.Join(dir, "logfile") w, err := openTraceWriter(fname) require.NoError(t, err) diff --git a/server/init_test.go b/server/init_test.go index 5d353ddd3540..349a9c169624 100644 --- a/server/init_test.go +++ b/server/init_test.go @@ -25,7 +25,7 @@ func TestGenerateCoinKey(t *testing.T) { func TestGenerateSaveCoinKey(t *testing.T) { t.Parallel() dir, cleanup := tests.NewTestCaseDir(t) - defer cleanup() // clean after itself + t.Cleanup(cleanup) kb, err := crkeys.NewKeyring(t.Name(), "test", dir, nil) require.NoError(t, err) @@ -47,7 +47,7 @@ func TestGenerateSaveCoinKey(t *testing.T) { func TestGenerateSaveCoinKeyOverwriteFlag(t *testing.T) { t.Parallel() dir, cleanup := tests.NewTestCaseDir(t) - defer cleanup() // clean after itself + t.Cleanup(cleanup) kb, err := crkeys.NewKeyring(t.Name(), "test", dir, nil) require.NoError(t, err) diff --git a/x/genutil/client/cli/init_test.go b/x/genutil/client/cli/init_test.go index 6ab1ef208abe..9bf2e3b1469c 100644 --- a/x/genutil/client/cli/init_test.go +++ b/x/genutil/client/cli/init_test.go @@ -27,10 +27,10 @@ import ( var testMbm = module.NewBasicManager(genutil.AppModuleBasic{}) func TestInitCmd(t *testing.T) { - defer server.SetupViper(t)() - defer setupClientHome(t)() + t.Cleanup(server.SetupViper(t)) + t.Cleanup(server.SetupViper(t)) home, cleanup := tests.NewTestCaseDir(t) - defer cleanup() + t.Cleanup(cleanup) logger := log.NewNopLogger() cfg, err := tcmd.ParseConfig() @@ -50,11 +50,11 @@ func setupClientHome(t *testing.T) func() { } func TestEmptyState(t *testing.T) { - defer server.SetupViper(t)() - defer setupClientHome(t)() + t.Cleanup(server.SetupViper(t)) + t.Cleanup(setupClientHome(t)) home, cleanup := tests.NewTestCaseDir(t) - defer cleanup() + t.Cleanup(cleanup) logger := log.NewNopLogger() cfg, err := tcmd.ParseConfig() @@ -94,9 +94,9 @@ func TestEmptyState(t *testing.T) { func TestStartStandAlone(t *testing.T) { home, cleanup := tests.NewTestCaseDir(t) - defer cleanup() + t.Cleanup(cleanup) viper.Set(cli.HomeFlag, home) - defer setupClientHome(t)() + t.Cleanup(setupClientHome(t)) logger := log.NewNopLogger() cfg, err := tcmd.ParseConfig() @@ -124,7 +124,7 @@ func TestStartStandAlone(t *testing.T) { func TestInitNodeValidatorFiles(t *testing.T) { home, cleanup := tests.NewTestCaseDir(t) - defer cleanup() + t.Cleanup(cleanup) viper.Set(cli.HomeFlag, home) viper.Set(flags.FlagName, "moniker") cfg, err := tcmd.ParseConfig() diff --git a/x/genutil/client/cli/migrate_test.go b/x/genutil/client/cli/migrate_test.go index 423629efcb13..d7ea942500cf 100644 --- a/x/genutil/client/cli/migrate_test.go +++ b/x/genutil/client/cli/migrate_test.go @@ -38,6 +38,7 @@ func TestGetMigrationCallback(t *testing.T) { func TestMigrateGenesis(t *testing.T) { home, cleanup := tests.NewTestCaseDir(t) + t.Cleanup(cleanup) viper.Set(cli.HomeFlag, home) viper.Set(flags.FlagName, "moniker") logger := log.NewNopLogger() @@ -49,8 +50,6 @@ func TestMigrateGenesis(t *testing.T) { genesisPath := path.Join(home, "genesis.json") target := "v0.36" - defer cleanup() - // Reject if we dont' have the right parameters or genesis does not exists require.Error(t, MigrateGenesisCmd(ctx, cdc).RunE(nil, []string{target, genesisPath})) diff --git a/x/genutil/utils_test.go b/x/genutil/utils_test.go index cb04c8f866b1..4c93fbd925a2 100644 --- a/x/genutil/utils_test.go +++ b/x/genutil/utils_test.go @@ -14,7 +14,7 @@ import ( func TestExportGenesisFileWithTime(t *testing.T) { t.Parallel() dir, cleanup := tests.NewTestCaseDir(t) - defer cleanup() + t.Cleanup(cleanup) fname := filepath.Join(dir, "genesis.json") require.NoError(t, ExportGenesisFileWithTime(fname, "test", nil, json.RawMessage(""), time.Now())) diff --git a/x/upgrade/types/storeloader_test.go b/x/upgrade/types/storeloader_test.go index 955ab07cdfc3..019b26bffbaf 100644 --- a/x/upgrade/types/storeloader_test.go +++ b/x/upgrade/types/storeloader_test.go @@ -68,8 +68,8 @@ func checkStore(t *testing.T, db dbm.DB, ver int64, storeKey string, k, v []byte // Test that LoadLatestVersion actually does. func TestSetLoader(t *testing.T) { // set a temporary home dir - homeDir, cleanUp := tests.NewTestCaseDir(t) - defer cleanUp() + homeDir, cleanup := tests.NewTestCaseDir(t) + t.Cleanup(cleanup) // TODO cleanup viper viper.Set(flags.FlagHome, homeDir) From e0d029388df204fcb265e9704846d4937115e582 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Mon, 2 Mar 2020 00:27:03 +0000 Subject: [PATCH 298/529] fix DiffKVStores(), store/types gets 100% coverage (#5730) * fix DiffKVStores(), store/types gets 100% coverage DiffKVStores() used to return duplicated entries in some cases. Add test cases, aiming to reach 100% coverage for store package. Remove duplicate Cp function from the store package. Same functionality is provided by types.CopyBytes(). * More test cases Co-authored-by: Alexander Bezobchuk --- CHANGELOG.md | 1 + store/firstlast.go | 4 +- store/gaskv/store_test.go | 27 ++++++++++- store/iavl/store.go | 5 +- store/iavl/tree_test.go | 37 +++++++++++++++ store/types/gas_test.go | 35 +++++++++++++- store/types/store_test.go | 27 +++++++++++ store/types/utils.go | 32 ++++++------- store/types/utils_test.go | 88 ++++++++++++++++++++++++++++++++++++ store/types/validity_test.go | 23 ++++++++++ types/bytes.go | 11 ----- types/utils.go | 10 ++++ types/utils_test.go | 10 ++++ 13 files changed, 274 insertions(+), 36 deletions(-) create mode 100644 store/iavl/tree_test.go create mode 100644 store/types/utils_test.go create mode 100644 store/types/validity_test.go delete mode 100644 types/bytes.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ca4f41b5349..8499de7178b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ balances or a single balance by denom when the `denom` query parameter is present. * (client) [\#5640](https://github.com/cosmos/cosmos-sdk/pull/5640) The rest server endpoint `/swagger-ui/` is replaced by ´/´. * (x/auth) [\#5702](https://github.com/cosmos/cosmos-sdk/pull/5702) The `x/auth` querier route has changed from `"acc"` to `"auth"`. +* (store/types) [\#5730](https://github.com/cosmos/cosmos-sdk/pull/5730) store.types.Cp() is removed in favour of types.CopyBytes(). ### API Breaking Changes diff --git a/store/firstlast.go b/store/firstlast.go index 05a9a5fd85e2..0aab0a53ab9c 100644 --- a/store/firstlast.go +++ b/store/firstlast.go @@ -5,7 +5,7 @@ import ( tmkv "github.com/tendermint/tendermint/libs/kv" - "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" ) // Gets the first item. @@ -24,7 +24,7 @@ func Last(st KVStore, start, end []byte) (kv tmkv.Pair, ok bool) { iter := st.ReverseIterator(end, start) if !iter.Valid() { if v := st.Get(start); v != nil { - return tmkv.Pair{Key: types.Cp(start), Value: types.Cp(v)}, true + return tmkv.Pair{Key: sdk.CopyBytes(start), Value: sdk.CopyBytes(v)}, true } return kv, false } diff --git a/store/gaskv/store_test.go b/store/gaskv/store_test.go index 6fab9ebf835b..ec0d42be8500 100644 --- a/store/gaskv/store_test.go +++ b/store/gaskv/store_test.go @@ -22,6 +22,11 @@ func TestGasKVStoreBasic(t *testing.T) { mem := dbadapter.Store{DB: dbm.NewMemDB()} meter := types.NewGasMeter(10000) st := gaskv.NewStore(mem, meter, types.KVGasConfig()) + + require.Equal(t, types.StoreTypeDB, st.GetStoreType()) + require.Panics(t, func() { st.CacheWrap() }) + require.Panics(t, func() { st.CacheWrapWithTrace(nil, nil) }) + require.Empty(t, st.Get(keyFmt(1)), "Expected `key1` to be empty") st.Set(keyFmt(1), valFmt(1)) require.Equal(t, valFmt(1), st.Get(keyFmt(1))) @@ -34,11 +39,20 @@ func TestGasKVStoreIterator(t *testing.T) { mem := dbadapter.Store{DB: dbm.NewMemDB()} meter := types.NewGasMeter(10000) st := gaskv.NewStore(mem, meter, types.KVGasConfig()) + require.False(t, st.Has(keyFmt(1))) require.Empty(t, st.Get(keyFmt(1)), "Expected `key1` to be empty") require.Empty(t, st.Get(keyFmt(2)), "Expected `key2` to be empty") st.Set(keyFmt(1), valFmt(1)) + require.True(t, st.Has(keyFmt(1))) st.Set(keyFmt(2), valFmt(2)) + iterator := st.Iterator(nil, nil) + start, end := iterator.Domain() + require.Nil(t, start) + require.Nil(t, end) + require.NoError(t, iterator.Error()) + + t.Cleanup(iterator.Close) ka := iterator.Key() require.Equal(t, ka, keyFmt(1)) va := iterator.Value() @@ -51,7 +65,18 @@ func TestGasKVStoreIterator(t *testing.T) { iterator.Next() require.False(t, iterator.Valid()) require.Panics(t, iterator.Next) - require.Equal(t, meter.GasConsumed(), types.Gas(6987)) + require.NoError(t, iterator.Error()) + + reverseIterator := st.ReverseIterator(nil, nil) + t.Cleanup(reverseIterator.Close) + require.Equal(t, reverseIterator.Key(), keyFmt(2)) + reverseIterator.Next() + require.Equal(t, reverseIterator.Key(), keyFmt(1)) + reverseIterator.Next() + require.False(t, reverseIterator.Valid()) + require.Panics(t, reverseIterator.Next) + + require.Equal(t, types.Gas(9194), meter.GasConsumed()) } func TestGasKVStoreOutOfGasSet(t *testing.T) { diff --git a/store/iavl/store.go b/store/iavl/store.go index d1e1d9c4cae0..311d0f887a66 100644 --- a/store/iavl/store.go +++ b/store/iavl/store.go @@ -15,6 +15,7 @@ import ( "github.com/cosmos/cosmos-sdk/store/cachekv" "github.com/cosmos/cosmos-sdk/store/tracekv" "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) @@ -357,8 +358,8 @@ var _ types.Iterator = (*iavlIterator)(nil) func newIAVLIterator(tree *iavl.ImmutableTree, start, end []byte, ascending bool) *iavlIterator { iter := &iavlIterator{ tree: tree, - start: types.Cp(start), - end: types.Cp(end), + start: sdk.CopyBytes(start), + end: sdk.CopyBytes(end), ascending: ascending, iterCh: make(chan tmkv.Pair), // Set capacity > 0? quitCh: make(chan struct{}), diff --git a/store/iavl/tree_test.go b/store/iavl/tree_test.go new file mode 100644 index 000000000000..7a1eef30234c --- /dev/null +++ b/store/iavl/tree_test.go @@ -0,0 +1,37 @@ +package iavl + +import ( + "testing" + + "github.com/stretchr/testify/require" + "github.com/tendermint/iavl" + dbm "github.com/tendermint/tm-db" +) + +func TestImmutableTreePanics(t *testing.T) { + t.Parallel() + immTree := iavl.NewImmutableTree(dbm.NewMemDB(), 100) + it := &immutableTree{immTree} + require.Panics(t, func() { it.Set([]byte{}, []byte{}) }) + require.Panics(t, func() { it.Remove([]byte{}) }) + require.Panics(t, func() { it.SaveVersion() }) + require.Panics(t, func() { it.DeleteVersion(int64(1)) }) + v, _ := it.GetVersioned([]byte{0x01}, 1) + require.Equal(t, int64(-1), v) + v, _ = it.GetVersioned([]byte{0x01}, 0) + require.Equal(t, int64(0), v) + + val, proof, err := it.GetVersionedWithProof(nil, 1) + require.Error(t, err) + require.Nil(t, val) + require.Nil(t, proof) + + imm, err := it.GetImmutable(1) + require.Error(t, err) + require.Nil(t, imm) + + imm, err = it.GetImmutable(0) + require.NoError(t, err) + require.NotNil(t, imm) + require.Equal(t, immTree, imm) +} diff --git a/store/types/gas_test.go b/store/types/gas_test.go index 00d3d834db2d..bd62d463cd67 100644 --- a/store/types/gas_test.go +++ b/store/types/gas_test.go @@ -7,7 +7,23 @@ import ( "github.com/stretchr/testify/require" ) +func TestInfiniteGasMeter(t *testing.T) { + t.Parallel() + meter := NewInfiniteGasMeter() + require.Equal(t, uint64(0), meter.Limit()) + require.Equal(t, uint64(0), meter.GasConsumed()) + require.Equal(t, uint64(0), meter.GasConsumedToLimit()) + meter.ConsumeGas(10, "consume 10") + require.Equal(t, uint64(10), meter.GasConsumed()) + require.Equal(t, uint64(10), meter.GasConsumedToLimit()) + require.False(t, meter.IsPastLimit()) + require.False(t, meter.IsOutOfGas()) + meter.ConsumeGas(Gas(math.MaxUint64/2), "consume half max uint64") + require.Panics(t, func() { meter.ConsumeGas(Gas(math.MaxUint64/2)+2, "panic") }) +} + func TestGasMeter(t *testing.T) { + t.Parallel() cases := []struct { limit Gas usage []Gas @@ -41,11 +57,14 @@ func TestGasMeter(t *testing.T) { require.Panics(t, func() { meter.ConsumeGas(1, "") }, "Exceeded but not panicked. tc #%d", tcnum) require.Equal(t, meter.GasConsumedToLimit(), meter.Limit(), "Gas consumption (to limit) not match limit") require.Equal(t, meter.GasConsumed(), meter.Limit()+1, "Gas consumption not match limit+1") - + meter2 := NewGasMeter(math.MaxUint64) + meter2.ConsumeGas(Gas(math.MaxUint64/2), "consume half max uint64") + require.Panics(t, func() { meter2.ConsumeGas(Gas(math.MaxUint64/2)+2, "panic") }) } } func TestAddUint64Overflow(t *testing.T) { + t.Parallel() testCases := []struct { a, b uint64 result uint64 @@ -69,3 +88,17 @@ func TestAddUint64Overflow(t *testing.T) { ) } } + +func TestTransientGasConfig(t *testing.T) { + t.Parallel() + config := TransientGasConfig() + require.Equal(t, config, GasConfig{ + HasCost: 1000, + DeleteCost: 1000, + ReadCostFlat: 1000, + ReadCostPerByte: 3, + WriteCostFlat: 2000, + WriteCostPerByte: 30, + IterNextCostFlat: 30, + }) +} diff --git a/store/types/store_test.go b/store/types/store_test.go index 7ef1d6e8896f..bf70af1bb6e0 100644 --- a/store/types/store_test.go +++ b/store/types/store_test.go @@ -1,12 +1,15 @@ package types import ( + "fmt" "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestStoreUpgrades(t *testing.T) { + t.Parallel() type toDelete struct { key string delete bool @@ -55,3 +58,27 @@ func TestStoreUpgrades(t *testing.T) { }) } } + +func TestCommitID(t *testing.T) { + t.Parallel() + require.True(t, CommitID{}.IsZero()) + require.False(t, CommitID{Version: int64(1)}.IsZero()) + require.False(t, CommitID{Hash: []byte("x")}.IsZero()) + require.Equal(t, "CommitID{[120 120 120 120]:64}", CommitID{Version: int64(100), Hash: []byte("xxxx")}.String()) +} + +func TestKVStoreKey(t *testing.T) { + t.Parallel() + key := NewKVStoreKey("test") + require.Equal(t, "test", key.name) + require.Equal(t, key.name, key.Name()) + require.Equal(t, fmt.Sprintf("KVStoreKey{%p, test}", key), key.String()) +} + +func TestTransientStoreKey(t *testing.T) { + t.Parallel() + key := NewTransientStoreKey("test") + require.Equal(t, "test", key.name) + require.Equal(t, key.name, key.Name()) + require.Equal(t, fmt.Sprintf("TransientStoreKey{%p, test}", key), key.String()) +} diff --git a/store/types/utils.go b/store/types/utils.go index 3149c07fb61a..8d4c83735460 100644 --- a/store/types/utils.go +++ b/store/types/utils.go @@ -17,15 +17,18 @@ func KVStoreReversePrefixIterator(kvs KVStore, prefix []byte) Iterator { } // DiffKVStores compares two KVstores and returns all the key/value pairs -// that differ from one another. It also skips value comparison for a set of provided prefixes +// that differ from one another. It also skips value comparison for a set of provided prefixes. func DiffKVStores(a KVStore, b KVStore, prefixesToSkip [][]byte) (kvAs, kvBs []tmkv.Pair) { iterA := a.Iterator(nil, nil) + defer iterA.Close() iterB := b.Iterator(nil, nil) + defer iterB.Close() for { if !iterA.Valid() && !iterB.Valid() { - break + return kvAs, kvBs } + var kvA, kvB tmkv.Pair if iterA.Valid() { kvA = tmkv.Pair{Key: iterA.Key(), Value: iterA.Value()} @@ -38,7 +41,9 @@ func DiffKVStores(a KVStore, b KVStore, prefixesToSkip [][]byte) (kvAs, kvBs []t if !bytes.Equal(kvA.Key, kvB.Key) { kvAs = append(kvAs, kvA) kvBs = append(kvBs, kvB) + continue // no need to compare the value } + compareValue := true for _, prefix := range prefixesToSkip { // Skip value comparison if we matched a prefix @@ -51,7 +56,6 @@ func DiffKVStores(a KVStore, b KVStore, prefixesToSkip [][]byte) (kvAs, kvBs []t kvBs = append(kvBs, kvB) } } - return kvAs, kvBs } // PrefixEndBytes returns the []byte that would end a @@ -69,13 +73,13 @@ func PrefixEndBytes(prefix []byte) []byte { if end[len(end)-1] != byte(255) { end[len(end)-1]++ break - } else { - end = end[:len(end)-1] - if len(end) == 0 { - end = nil - break - } } + end = end[:len(end)-1] + if len(end) == 0 { + end = nil + break + } + } return end } @@ -85,13 +89,3 @@ func PrefixEndBytes(prefix []byte) []byte { func InclusiveEndBytes(inclusiveBytes []byte) []byte { return append(inclusiveBytes, byte(0x00)) } - -//---------------------------------------- -func Cp(bz []byte) (ret []byte) { - if bz == nil { - return nil - } - ret = make([]byte, len(bz)) - copy(ret, bz) - return ret -} diff --git a/store/types/utils_test.go b/store/types/utils_test.go new file mode 100644 index 000000000000..32064d7e1821 --- /dev/null +++ b/store/types/utils_test.go @@ -0,0 +1,88 @@ +package types_test + +import ( + "bytes" + "testing" + + "github.com/stretchr/testify/require" + dbm "github.com/tendermint/tm-db" + + "github.com/cosmos/cosmos-sdk/store/rootmulti" + "github.com/cosmos/cosmos-sdk/store/types" +) + +func initTestStores(t *testing.T) (types.KVStore, types.KVStore) { + db := dbm.NewMemDB() + ms := rootmulti.NewStore(db) + + key1 := types.NewKVStoreKey("store1") + key2 := types.NewKVStoreKey("store2") + require.NotPanics(t, func() { ms.MountStoreWithDB(key1, types.StoreTypeIAVL, db) }) + require.NotPanics(t, func() { ms.MountStoreWithDB(key2, types.StoreTypeIAVL, db) }) + require.NoError(t, ms.LoadLatestVersion()) + return ms.GetKVStore(key1), ms.GetKVStore(key2) +} + +func TestDiffKVStores(t *testing.T) { + t.Parallel() + store1, store2 := initTestStores(t) + // Two equal stores + k1, v1 := []byte("k1"), []byte("v1") + store1.Set(k1, v1) + store2.Set(k1, v1) + + kvAs, kvBs := types.DiffKVStores(store1, store2, nil) + require.Equal(t, 0, len(kvAs)) + require.Equal(t, len(kvAs), len(kvBs)) + + // delete k1 from store2, which is now empty + store2.Delete(k1) + kvAs, kvBs = types.DiffKVStores(store1, store2, nil) + require.Equal(t, 1, len(kvAs)) + require.Equal(t, len(kvAs), len(kvBs)) + + // set k1 in store2, different value than what store1 holds for k1 + v2 := []byte("v2") + store2.Set(k1, v2) + kvAs, kvBs = types.DiffKVStores(store1, store2, nil) + require.Equal(t, 1, len(kvAs)) + require.Equal(t, len(kvAs), len(kvBs)) + + // add k2 to store2 + k2 := []byte("k2") + store2.Set(k2, v2) + kvAs, kvBs = types.DiffKVStores(store1, store2, nil) + require.Equal(t, 2, len(kvAs)) + require.Equal(t, len(kvAs), len(kvBs)) + + // Reset stores + store1.Delete(k1) + store2.Delete(k1) + store2.Delete(k2) + + // Same keys, different value. Comparisons will be nil as prefixes are skipped. + prefix := []byte("prefix:") + k1Prefixed := append(prefix, k1...) + store1.Set(k1Prefixed, v1) + store2.Set(k1Prefixed, v2) + kvAs, kvBs = types.DiffKVStores(store1, store2, [][]byte{prefix}) + require.Equal(t, 0, len(kvAs)) + require.Equal(t, len(kvAs), len(kvBs)) +} + +func TestPrefixEndBytes(t *testing.T) { + t.Parallel() + bs1 := []byte{0x23, 0xA5, 0x06} + require.True(t, bytes.Equal([]byte{0x23, 0xA5, 0x07}, types.PrefixEndBytes(bs1))) + bs2 := []byte{0x23, 0xA5, 0xFF} + require.True(t, bytes.Equal([]byte{0x23, 0xA6}, types.PrefixEndBytes(bs2))) + require.Nil(t, types.PrefixEndBytes([]byte{0xFF})) + require.Nil(t, types.PrefixEndBytes(nil)) +} + +func TestInclusiveEndBytes(t *testing.T) { + t.Parallel() + require.True(t, bytes.Equal([]byte{0x00}, types.InclusiveEndBytes(nil))) + bs := []byte("test") + require.True(t, bytes.Equal(append(bs, byte(0x00)), types.InclusiveEndBytes(bs))) +} diff --git a/store/types/validity_test.go b/store/types/validity_test.go new file mode 100644 index 000000000000..e2adcd19c43a --- /dev/null +++ b/store/types/validity_test.go @@ -0,0 +1,23 @@ +package types_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/store/types" +) + +func TestAssertValidKey(t *testing.T) { + t.Parallel() + require.NotPanics(t, func() { types.AssertValidKey([]byte{}) }) + require.NotPanics(t, func() { types.AssertValidKey([]byte{0x01}) }) + require.Panics(t, func() { types.AssertValidKey(nil) }) +} + +func TestAssertValidValue(t *testing.T) { + t.Parallel() + require.NotPanics(t, func() { types.AssertValidValue([]byte{}) }) + require.NotPanics(t, func() { types.AssertValidValue([]byte{0x01}) }) + require.Panics(t, func() { types.AssertValidValue(nil) }) +} diff --git a/types/bytes.go b/types/bytes.go deleted file mode 100644 index 600af9f04c39..000000000000 --- a/types/bytes.go +++ /dev/null @@ -1,11 +0,0 @@ -package types - -// copy bytes -func CopyBytes(bz []byte) (ret []byte) { - if bz == nil { - return nil - } - ret = make([]byte, len(bz)) - copy(ret, bz) - return ret -} diff --git a/types/utils.go b/types/utils.go index 2a6add6b45b4..be33160261d5 100644 --- a/types/utils.go +++ b/types/utils.go @@ -80,3 +80,13 @@ func NewLevelDB(name, dir string) (db dbm.DB, err error) { }() return dbm.NewDB(name, backend, dir), err } + +// copy bytes +func CopyBytes(bz []byte) (ret []byte) { + if bz == nil { + return nil + } + ret = make([]byte, len(bz)) + copy(ret, bz) + return ret +} diff --git a/types/utils_test.go b/types/utils_test.go index 352beccd4259..6aa652220e55 100644 --- a/types/utils_test.go +++ b/types/utils_test.go @@ -1,6 +1,7 @@ package types import ( + "bytes" "testing" "time" @@ -66,3 +67,12 @@ func TestTimeFormatAndParse(t *testing.T) { require.Equal(t, timeFromRFC.Format(SortableTimeFormat), tc.SDKSortableTimeStr) } } + +func TestCopyBytes(t *testing.T) { + t.Parallel() + require.Nil(t, CopyBytes(nil)) + require.Equal(t, 0, len(CopyBytes([]byte{}))) + bs := []byte("test") + bsCopy := CopyBytes(bs) + require.True(t, bytes.Equal(bs, bsCopy)) +} From 9bd603ae882c28c3f084db79d8e6a79e30c29ab7 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Sun, 1 Mar 2020 17:16:22 +0000 Subject: [PATCH 299/529] crypto: cleanup, more testing crypto.LedgerShowAddress() is a ledger specific function and should takes acc address prefix instead of depending on a sdk.Config singleton. crypto/keys/mintkey: - decryptPrivKey() return error instead of os.Exit()ing. - encryptPrivKey() should panic instead of os.Exit() when bcrypt.GenerateFromPassword() call fails so that the caller is given a chance to recover(). crypto/keys: - SignWithLedger() does not need to be method of baseKeybase. Method receiver is unused. - ledgerInfo objecta may be pointers, type switch should handle both to avoid panics. - keyringKeybase should not provide Update() at all. More test cases are added to increase package crypto and subpackages overall coverage. --- CHANGELOG.md | 1 + client/keys/show.go | 2 +- crypto/keys/keybase.go | 2 +- crypto/keys/keybase_base.go | 45 +++++++----- crypto/keys/keybase_test.go | 4 +- crypto/keys/keyerror/errors_test.go | 24 +++++++ crypto/keys/keyring.go | 27 +------ crypto/keys/keyring_test.go | 88 ++++++++++++++++++++++- crypto/keys/mintkey/mintkey.go | 9 ++- crypto/keys/mintkey/mintkey_test.go | 108 ++++++++++++++++++++++++++-- crypto/ledger_secp256k1.go | 8 +-- crypto/ledger_test.go | 2 + 12 files changed, 259 insertions(+), 61 deletions(-) create mode 100644 crypto/keys/keyerror/errors_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 8499de7178b8..972723cbf15f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -61,6 +61,7 @@ and provided directly the IAVL store. * (modules) [\#5572](https://github.com/cosmos/cosmos-sdk/pull/5572) Move account balance logic and APIs from `x/auth` to `x/bank`. * (types) [\#5533](https://github.com/cosmos/cosmos-sdk/pull/5533) Refactored `AppModuleBasic` and `AppModuleGenesis` to now accept a `codec.JSONMarshaler` for modular serialization of genesis state. +* (crypto/keys) [\#5735](https://github.com/cosmos/cosmos-sdk/pull/5735) Keyring's Update() function is now no-op. ### Features diff --git a/client/keys/show.go b/client/keys/show.go index 539fb111e55f..c959ff157750 100644 --- a/client/keys/show.go +++ b/client/keys/show.go @@ -136,7 +136,7 @@ func runShowCmd(cmd *cobra.Command, args []string) (err error) { return nil } - return crypto.LedgerShowAddress(*hdpath, info.GetPubKey()) + return crypto.LedgerShowAddress(*hdpath, info.GetPubKey(), sdk.GetConfig().GetBech32AccountAddrPrefix()) } return nil diff --git a/crypto/keys/keybase.go b/crypto/keys/keybase.go index 9d95a5ccda2b..b55c7b68b542 100644 --- a/crypto/keys/keybase.go +++ b/crypto/keys/keybase.go @@ -212,7 +212,7 @@ func (kb dbKeybase) Sign(name, passphrase string, msg []byte) (sig []byte, pub t } case ledgerInfo: - return kb.base.SignWithLedger(info, msg) + return SignWithLedger(info, msg) case offlineInfo, multiInfo: return kb.base.DecodeSignature(info, msg) diff --git a/crypto/keys/keybase_base.go b/crypto/keys/keybase_base.go index 3003b08828ce..47c7e60d729a 100644 --- a/crypto/keys/keybase_base.go +++ b/crypto/keys/keybase_base.go @@ -104,24 +104,6 @@ func SecpPrivKeyGen(bz []byte) tmcrypto.PrivKey { return secp256k1.PrivKeySecp256k1(bzArr) } -// SignWithLedger signs a binary message with the ledger device referenced by an Info object -// and returns the signed bytes and the public key. It returns an error if the device could -// not be queried or it returned an error. -func (kb baseKeybase) SignWithLedger(info Info, msg []byte) (sig []byte, pub tmcrypto.PubKey, err error) { - i := info.(ledgerInfo) - priv, err := crypto.NewPrivKeyLedgerSecp256k1Unsafe(i.Path) - if err != nil { - return - } - - sig, err = priv.Sign(msg) - if err != nil { - return nil, nil, err - } - - return sig, priv.PubKey(), nil -} - // DecodeSignature decodes a an length-prefixed binary signature from standard input // and return it as a byte slice. func (kb baseKeybase) DecodeSignature(info Info, msg []byte) (sig []byte, pub tmcrypto.PubKey, err error) { @@ -296,3 +278,30 @@ func IsSupportedAlgorithm(supported []SigningAlgo, algo SigningAlgo) bool { } return false } + +// SignWithLedger signs a binary message with the ledger device referenced by an Info object +// and returns the signed bytes and the public key. It returns an error if the device could +// not be queried or it returned an error. +func SignWithLedger(info Info, msg []byte) (sig []byte, pub tmcrypto.PubKey, err error) { + switch info.(type) { + case *ledgerInfo, ledgerInfo: + default: + return nil, nil, errors.New("not a ledger object") + } + path, err := info.GetPath() + if err != nil { + return + } + + priv, err := crypto.NewPrivKeyLedgerSecp256k1Unsafe(*path) + if err != nil { + return + } + + sig, err = priv.Sign(msg) + if err != nil { + return nil, nil, err + } + + return sig, priv.PubKey(), nil +} diff --git a/crypto/keys/keybase_test.go b/crypto/keys/keybase_test.go index 0c2396afbf9c..cbd212a755db 100644 --- a/crypto/keys/keybase_test.go +++ b/crypto/keys/keybase_test.go @@ -2,7 +2,9 @@ package keys import ( + "errors" "fmt" + "io" "testing" "github.com/stretchr/testify/assert" @@ -278,7 +280,7 @@ func TestSignVerify(t *testing.T) { // Now try to sign data with a secret-less key _, _, err = cstore.Sign(n3, p3, d3) - require.NotNil(t, err) + require.True(t, errors.Is(io.EOF, err)) } func assertPassword(t *testing.T, cstore Keybase, name, pass, badpass string) { diff --git a/crypto/keys/keyerror/errors_test.go b/crypto/keys/keyerror/errors_test.go new file mode 100644 index 000000000000..80aaf9a69b9f --- /dev/null +++ b/crypto/keys/keyerror/errors_test.go @@ -0,0 +1,24 @@ +package keyerror_test + +import ( + "errors" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/crypto/keys/keyerror" +) + +func TestErrors(t *testing.T) { + err := keyerror.NewErrKeyNotFound("test") + require.True(t, keyerror.IsErrKeyNotFound(err)) + require.Equal(t, "Key test not found", err.Error()) + require.False(t, keyerror.IsErrKeyNotFound(errors.New("test"))) + require.False(t, keyerror.IsErrKeyNotFound(nil)) + + err = keyerror.NewErrWrongPassword() + require.True(t, keyerror.IsErrWrongPassword(err)) + require.Equal(t, "invalid account password", err.Error()) + require.False(t, keyerror.IsErrWrongPassword(errors.New("test"))) + require.False(t, keyerror.IsErrWrongPassword(nil)) +} diff --git a/crypto/keys/keyring.go b/crypto/keys/keyring.go index 3e79c796bdbf..d21e557435aa 100644 --- a/crypto/keys/keyring.go +++ b/crypto/keys/keyring.go @@ -7,7 +7,6 @@ import ( "io/ioutil" "os" "path/filepath" - "reflect" "sort" "strings" @@ -218,7 +217,7 @@ func (kb keyringKeybase) Sign(name, passphrase string, msg []byte) (sig []byte, } case ledgerInfo: - return kb.base.SignWithLedger(info, msg) + return SignWithLedger(info, msg) case offlineInfo, multiInfo: return kb.base.DecodeSignature(info, msg) @@ -419,29 +418,7 @@ func (kb keyringKeybase) Delete(name, _ string, _ bool) error { // The oldpass must be the current passphrase used for encryption, getNewpass is // a function to get the passphrase to permanently replace the current passphrase. func (kb keyringKeybase) Update(name, oldpass string, getNewpass func() (string, error)) error { - info, err := kb.Get(name) - if err != nil { - return err - } - - switch linfo := info.(type) { - case localInfo: - key, _, err := mintkey.UnarmorDecryptPrivKey(linfo.PrivKeyArmor, oldpass) - if err != nil { - return err - } - - newpass, err := getNewpass() - if err != nil { - return err - } - - kb.writeLocalKey(name, key, newpass, linfo.GetAlgo()) - return nil - - default: - return fmt.Errorf("locally stored key required; received: %v", reflect.TypeOf(info).String()) - } + return errors.New("unsupported operation") } // SupportedAlgos returns a list of supported signing algorithms. diff --git a/crypto/keys/keyring_test.go b/crypto/keys/keyring_test.go index 4c024fab9574..dd179a0c12a3 100644 --- a/crypto/keys/keyring_test.go +++ b/crypto/keys/keyring_test.go @@ -2,6 +2,7 @@ package keys import ( + "bytes" "testing" "github.com/stretchr/testify/assert" @@ -94,8 +95,46 @@ func TestLazyKeyManagementKeyRing(t *testing.T) { require.Equal(t, 1, len(keyS)) // addr cache gets nuked - and test skip flag - err = kb.Delete(n2, "", true) + require.NoError(t, kb.Delete(n2, "", true)) + + require.NotPanics(t, kb.CloseDB) +} + +// TestSignVerify does some detailed checks on how we sign and validate +// signatures +func TestLazySignVerifyKeyRingWithLedger(t *testing.T) { + dir, cleanup := tests.NewTestCaseDir(t) + t.Cleanup(cleanup) + kb, err := NewKeyring("keybasename", "test", dir, nil) + require.NoError(t, err) + + i1, err := kb.CreateLedger("key", Secp256k1, "cosmos", 0, 0) + if err != nil { + require.Equal(t, "ledger nano S: support for ledger devices is not available in this executable", err.Error()) + t.Skip("ledger nano S: support for ledger devices is not available in this executable") + return + } + require.Equal(t, "key", i1.GetName()) + + p1 := "1234" + d1 := []byte("my first message") + s1, pub1, err := kb.Sign("key", p1, d1) + require.NoError(t, err) + + s2, pub2, err := SignWithLedger(i1, d1) require.NoError(t, err) + + require.Equal(t, i1.GetPubKey(), pub1) + require.Equal(t, i1.GetPubKey(), pub2) + require.True(t, pub1.VerifyBytes(d1, s1)) + require.True(t, i1.GetPubKey().VerifyBytes(d1, s1)) + require.True(t, bytes.Equal(s1, s2)) + + localInfo, _, err := kb.CreateMnemonic("test", English, p1, Secp256k1) + require.NoError(t, err) + _, _, err = SignWithLedger(localInfo, d1) + require.Error(t, err) + require.Equal(t, "not a ledger object", err.Error()) } func TestLazySignVerifyKeyRing(t *testing.T) { @@ -325,3 +364,50 @@ func TestLazySeedPhraseKeyRing(t *testing.T) { require.Equal(t, info.GetPubKey().Address(), newInfo.GetPubKey().Address()) require.Equal(t, info.GetPubKey(), newInfo.GetPubKey()) } + +func TestKeyringKeybaseExportImportPrivKey(t *testing.T) { + dir, cleanup := tests.NewTestCaseDir(t) + t.Cleanup(cleanup) + kb, err := NewKeyring("keybasename", "test", dir, nil) + require.NoError(t, err) + _, _, err = kb.CreateMnemonic("john", English, "password", Secp256k1) + require.NoError(t, err) + + // no error, password is irrelevant, keystr cointains ASCII armored private key + keystr, err := kb.ExportPrivKey("john", "wrongpassword", "password") + require.NoError(t, err) + require.NotEmpty(t, keystr) + + // try import the key - wrong password + err = kb.ImportPrivKey("john2", keystr, "somepassword") + require.Equal(t, "failed to decrypt private key: ciphertext decryption failed", err.Error()) + + // try import the key with the correct password + require.NoError(t, kb.ImportPrivKey("john2", keystr, "password")) + + // overwrite is not allowed + err = kb.ImportPrivKey("john2", keystr, "password") + require.Equal(t, "cannot overwrite key: john2", err.Error()) + + // try export non existing key + _, err = kb.ExportPrivKey("john3", "wrongpassword", "password") + require.Equal(t, "The specified item could not be found in the keyring", err.Error()) +} + +func TestKeyringKeybaseUpdate(t *testing.T) { + dir, cleanup := tests.NewTestCaseDir(t) + t.Cleanup(cleanup) + kb, err := NewKeyring("keybasename", "test", dir, nil) + require.NoError(t, err) + require.Equal(t, "unsupported operation", kb.Update("john", "oldpassword", + func() (string, error) { return "", nil }).Error()) +} + +func TestSupportedAlgos(t *testing.T) { + dir, cleanup := tests.NewTestCaseDir(t) + t.Cleanup(cleanup) + kb, err := NewKeyring("keybasename", "test", dir, nil) + require.NoError(t, err) + require.Equal(t, []SigningAlgo([]SigningAlgo{"secp256k1"}), kb.SupportedAlgos()) + require.Equal(t, []SigningAlgo([]SigningAlgo{"secp256k1"}), kb.SupportedAlgosLedger()) +} diff --git a/crypto/keys/mintkey/mintkey.go b/crypto/keys/mintkey/mintkey.go index 8b458849833d..7ce836d68baf 100644 --- a/crypto/keys/mintkey/mintkey.go +++ b/crypto/keys/mintkey/mintkey.go @@ -11,9 +11,8 @@ import ( cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino" "github.com/tendermint/tendermint/crypto/xsalsa20symmetric" - tmos "github.com/tendermint/tendermint/libs/os" - "github.com/cosmos/cosmos-sdk/crypto/keys/keyerror" + "github.com/cosmos/cosmos-sdk/types/errors" ) const ( @@ -134,7 +133,7 @@ func encryptPrivKey(privKey crypto.PrivKey, passphrase string) (saltBytes []byte saltBytes = crypto.CRandBytes(16) key, err := bcrypt.GenerateFromPassword(saltBytes, []byte(passphrase), BcryptSecurityParameter) if err != nil { - tmos.Exit("Error generating bcrypt key from passphrase: " + err.Error()) + panic(errors.Wrap(err, "error generating bcrypt key from passphrase")) } key = crypto.Sha256(key) // get 32 bytes privKeyBytes := privKey.Bytes() @@ -151,7 +150,7 @@ func UnarmorDecryptPrivKey(armorStr string, passphrase string) (privKey crypto.P return privKey, "", fmt.Errorf("unrecognized armor type: %v", blockType) } if header["kdf"] != "bcrypt" { - return privKey, "", fmt.Errorf("unrecognized KDF type: %v", header["KDF"]) + return privKey, "", fmt.Errorf("unrecognized KDF type: %v", header["kdf"]) } if header["salt"] == "" { return privKey, "", fmt.Errorf("missing salt bytes") @@ -171,7 +170,7 @@ func UnarmorDecryptPrivKey(armorStr string, passphrase string) (privKey crypto.P func decryptPrivKey(saltBytes []byte, encBytes []byte, passphrase string) (privKey crypto.PrivKey, err error) { key, err := bcrypt.GenerateFromPassword(saltBytes, []byte(passphrase), BcryptSecurityParameter) if err != nil { - tmos.Exit("error generating bcrypt key from passphrase: " + err.Error()) + return privKey, errors.Wrap(err, "error generating bcrypt key from passphrase") } key = crypto.Sha256(key) // Get 32 bytes privKeyBytes, err := xsalsa20symmetric.DecryptSymmetric(encBytes, key) diff --git a/crypto/keys/mintkey/mintkey_test.go b/crypto/keys/mintkey/mintkey_test.go index ef5f77d3372e..79c158344dea 100644 --- a/crypto/keys/mintkey/mintkey_test.go +++ b/crypto/keys/mintkey/mintkey_test.go @@ -1,11 +1,19 @@ package mintkey_test import ( + "bytes" + "errors" + "fmt" + "io" "testing" "github.com/stretchr/testify/require" + "github.com/tendermint/crypto/bcrypt" + "github.com/tendermint/tendermint/crypto" + "github.com/tendermint/tendermint/crypto/armor" cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino" "github.com/tendermint/tendermint/crypto/secp256k1" + "github.com/tendermint/tendermint/crypto/xsalsa20symmetric" "github.com/cosmos/cosmos-sdk/crypto/keys" "github.com/cosmos/cosmos-sdk/crypto/keys/mintkey" @@ -13,13 +21,48 @@ import ( func TestArmorUnarmorPrivKey(t *testing.T) { priv := secp256k1.GenPrivKey() - armor := mintkey.EncryptArmorPrivKey(priv, "passphrase", "") - _, _, err := mintkey.UnarmorDecryptPrivKey(armor, "wrongpassphrase") + armored := mintkey.EncryptArmorPrivKey(priv, "passphrase", "") + _, _, err := mintkey.UnarmorDecryptPrivKey(armored, "wrongpassphrase") require.Error(t, err) - decrypted, algo, err := mintkey.UnarmorDecryptPrivKey(armor, "passphrase") + decrypted, algo, err := mintkey.UnarmorDecryptPrivKey(armored, "passphrase") require.NoError(t, err) require.Equal(t, string(keys.Secp256k1), algo) require.True(t, priv.Equals(decrypted)) + + // empty string + decrypted, algo, err = mintkey.UnarmorDecryptPrivKey("", "passphrase") + require.Error(t, err) + require.True(t, errors.Is(io.EOF, err)) + require.Nil(t, decrypted) + require.Empty(t, algo) + + // wrong key type + armored = mintkey.ArmorPubKeyBytes(priv.PubKey().Bytes(), "") + decrypted, algo, err = mintkey.UnarmorDecryptPrivKey(armored, "passphrase") + require.Error(t, err) + require.Contains(t, err.Error(), "unrecognized armor type") + + // armor key manually + encryptPrivKeyFn := func(privKey crypto.PrivKey, passphrase string) (saltBytes []byte, encBytes []byte) { + saltBytes = crypto.CRandBytes(16) + key, err := bcrypt.GenerateFromPassword(saltBytes, []byte(passphrase), mintkey.BcryptSecurityParameter) + require.NoError(t, err) + key = crypto.Sha256(key) // get 32 bytes + privKeyBytes := privKey.Bytes() + return saltBytes, xsalsa20symmetric.EncryptSymmetric(privKeyBytes, key) + } + saltBytes, encBytes := encryptPrivKeyFn(priv, "passphrase") + + // wrong kdf header + headerWrongKdf := map[string]string{ + "kdf": "wrong", + "salt": fmt.Sprintf("%X", saltBytes), + "type": "secp256k", + } + armored = armor.EncodeArmor("TENDERMINT PRIVATE KEY", headerWrongKdf, encBytes) + _, _, err = mintkey.UnarmorDecryptPrivKey(armored, "passphrase") + require.Error(t, err) + require.Equal(t, "unrecognized KDF type: wrong", err.Error()) } func TestArmorUnarmorPubKey(t *testing.T) { @@ -29,11 +72,66 @@ func TestArmorUnarmorPubKey(t *testing.T) { // Add keys and see they return in alphabetical order info, _, err := cstore.CreateMnemonic("Bob", keys.English, "passphrase", keys.Secp256k1) require.NoError(t, err) - armor := mintkey.ArmorPubKeyBytes(info.GetPubKey().Bytes(), "") - pubBytes, algo, err := mintkey.UnarmorPubKeyBytes(armor) + armored := mintkey.ArmorPubKeyBytes(info.GetPubKey().Bytes(), "") + pubBytes, algo, err := mintkey.UnarmorPubKeyBytes(armored) require.NoError(t, err) pub, err := cryptoAmino.PubKeyFromBytes(pubBytes) require.NoError(t, err) require.Equal(t, string(keys.Secp256k1), algo) require.True(t, pub.Equals(info.GetPubKey())) + + armored = mintkey.ArmorPubKeyBytes(info.GetPubKey().Bytes(), "unknown") + pubBytes, algo, err = mintkey.UnarmorPubKeyBytes(armored) + require.NoError(t, err) + pub, err = cryptoAmino.PubKeyFromBytes(pubBytes) + require.NoError(t, err) + require.Equal(t, "unknown", algo) + require.True(t, pub.Equals(info.GetPubKey())) + + // armor pubkey manually + header := map[string]string{ + "version": "0.0.0", + "type": "unknown", + } + armored = armor.EncodeArmor("TENDERMINT PUBLIC KEY", header, pubBytes) + _, algo, err = mintkey.UnarmorPubKeyBytes(armored) + require.NoError(t, err) + // return secp256k1 if version is 0.0.0 + require.Equal(t, "secp256k1", algo) + + // missing version header + header = map[string]string{ + "type": "unknown", + } + armored = armor.EncodeArmor("TENDERMINT PUBLIC KEY", header, pubBytes) + bz, algo, err := mintkey.UnarmorPubKeyBytes(armored) + require.Nil(t, bz) + require.Empty(t, algo) + require.Error(t, err) + require.Contains(t, err.Error(), "unrecognized version") +} + +func TestArmorInfoBytes(t *testing.T) { + bs := []byte("test") + armoredString := mintkey.ArmorInfoBytes(bs) + unarmoredBytes, err := mintkey.UnarmorInfoBytes(armoredString) + require.NoError(t, err) + require.True(t, bytes.Equal(bs, unarmoredBytes)) +} + +func TestUnarmorInfoBytesErrors(t *testing.T) { + unarmoredBytes, err := mintkey.UnarmorInfoBytes("") + require.Error(t, err) + require.True(t, errors.Is(io.EOF, err)) + require.Nil(t, unarmoredBytes) + + header := map[string]string{ + "type": "Info", + "version": "0.0.1", + } + unarmoredBytes, err = mintkey.UnarmorInfoBytes(armor.EncodeArmor( + "TENDERMINT KEY INFO", header, []byte("plain-text"))) + require.Error(t, err) + require.Equal(t, "unrecognized version: 0.0.1", err.Error()) + require.Nil(t, unarmoredBytes) } diff --git a/crypto/ledger_secp256k1.go b/crypto/ledger_secp256k1.go index eb1c9efe51a6..2c346d4355a4 100644 --- a/crypto/ledger_secp256k1.go +++ b/crypto/ledger_secp256k1.go @@ -12,7 +12,6 @@ import ( tmsecp256k1 "github.com/tendermint/tendermint/crypto/secp256k1" "github.com/cosmos/cosmos-sdk/crypto/keys/hd" - sdk "github.com/cosmos/cosmos-sdk/types" ) var ( @@ -103,7 +102,9 @@ func (pkl PrivKeyLedgerSecp256k1) Sign(message []byte) ([]byte, error) { } // LedgerShowAddress triggers a ledger device to show the corresponding address. -func LedgerShowAddress(path hd.BIP44Params, expectedPubKey tmcrypto.PubKey) error { +func LedgerShowAddress(path hd.BIP44Params, expectedPubKey tmcrypto.PubKey, + accountAddressPrefix string) error { + device, err := getLedgerDevice() if err != nil { return err @@ -119,8 +120,7 @@ func LedgerShowAddress(path hd.BIP44Params, expectedPubKey tmcrypto.PubKey) erro return fmt.Errorf("the key's pubkey does not match with the one retrieved from Ledger. Check that the HD path and device are the correct ones") } - config := sdk.GetConfig() - pubKey2, _, err := getPubKeyAddrSafe(device, path, config.GetBech32AccountAddrPrefix()) + pubKey2, _, err := getPubKeyAddrSafe(device, path, accountAddressPrefix) if err != nil { return err } diff --git a/crypto/ledger_test.go b/crypto/ledger_test.go index 0f6c4572ad9d..fbcf9239b49d 100644 --- a/crypto/ledger_test.go +++ b/crypto/ledger_test.go @@ -104,6 +104,8 @@ func TestPublicKeySafe(t *testing.T) { require.Nil(t, err, "%s", err) require.NotNil(t, priv) + require.Nil(t, LedgerShowAddress(path, priv.PubKey(), sdk.GetConfig().GetBech32AccountAddrPrefix())) + require.Equal(t, "eb5ae98721034fef9cd7c4c63588d3b03feb5281b9d232cba34d6f3d71aee59211ffbfe1fe87", fmt.Sprintf("%x", priv.PubKey().Bytes()), "Is your device using test mnemonic: %s ?", tests.TestMnemonic) From 8f131e2e0c8d0ef346b12e528fce45eae0cb1cef Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Mon, 2 Mar 2020 09:14:17 -0500 Subject: [PATCH 300/529] Fix and updates gov proto types --- x/gov/types/types.pb.go | 718 ++++++---------------------------------- x/gov/types/types.proto | 185 ++++++----- 2 files changed, 208 insertions(+), 695 deletions(-) diff --git a/x/gov/types/types.pb.go b/x/gov/types/types.pb.go index 3f7a18cceb59..56bba9adf9cd 100644 --- a/x/gov/types/types.pb.go +++ b/x/gov/types/types.pb.go @@ -12,7 +12,6 @@ import ( proto "github.com/gogo/protobuf/proto" github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" _ "github.com/golang/protobuf/ptypes/timestamp" - _ "github.com/regen-network/cosmos-proto" io "io" math "math" math_bits "math/bits" @@ -291,15 +290,18 @@ func (m *Deposit) XXX_DiscardUnknown() { var xxx_messageInfo_Deposit proto.InternalMessageInfo +// ProposalBase defines the core field members of a governance proposal. It includes +// all static fields (i.e fields excluding the dynamic Content). A full proposal +// extends the ProposalBase with Content. type ProposalBase struct { - ProposalID uint64 `protobuf:"varint,1,opt,name=proposal_id,json=proposalId,proto3" json:"proposal_id,omitempty" yaml:"proposal_id"` - Status ProposalStatus `protobuf:"varint,2,opt,name=status,proto3,enum=cosmos_sdk.x.gov.v1.ProposalStatus" json:"status,omitempty"` - FinalTallyResult TallyResult `protobuf:"bytes,3,opt,name=final_tally_result,json=finalTallyResult,proto3" json:"final_tally_result"` - SubmitTime time.Time `protobuf:"bytes,4,opt,name=submit_time,json=submitTime,proto3,stdtime" json:"submit_time"` - DepositEndTime time.Time `protobuf:"bytes,5,opt,name=deposit_end_time,json=depositEndTime,proto3,stdtime" json:"deposit_end_time"` - TotalDeposit github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,6,rep,name=total_deposit,json=totalDeposit,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"total_deposit"` - VotingStartTime time.Time `protobuf:"bytes,7,opt,name=voting_start_time,json=votingStartTime,proto3,stdtime" json:"voting_start_time"` - VotingEndTime time.Time `protobuf:"bytes,8,opt,name=voting_end_time,json=votingEndTime,proto3,stdtime" json:"voting_end_time"` + ProposalID uint64 `protobuf:"varint,1,opt,name=proposal_id,json=proposalId,proto3" json:"id" yaml:"id"` + Status ProposalStatus `protobuf:"varint,2,opt,name=status,proto3,enum=cosmos_sdk.x.gov.v1.ProposalStatus" json:"status,omitempty" yaml:"proposal_status"` + FinalTallyResult TallyResult `protobuf:"bytes,3,opt,name=final_tally_result,json=finalTallyResult,proto3" json:"final_tally_result" yaml:"final_tally_result"` + SubmitTime time.Time `protobuf:"bytes,4,opt,name=submit_time,json=submitTime,proto3,stdtime" json:"submit_time" yaml:"submit_time"` + DepositEndTime time.Time `protobuf:"bytes,5,opt,name=deposit_end_time,json=depositEndTime,proto3,stdtime" json:"deposit_end_time" yaml:"deposit_end_time"` + TotalDeposit github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,6,rep,name=total_deposit,json=totalDeposit,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"total_deposit" yaml:"total_deposit"` + VotingStartTime time.Time `protobuf:"bytes,7,opt,name=voting_start_time,json=votingStartTime,proto3,stdtime" json:"voting_start_time" yaml:"voting_start_time"` + VotingEndTime time.Time `protobuf:"bytes,8,opt,name=voting_end_time,json=votingEndTime,proto3,stdtime" json:"voting_end_time" yaml:"voting_end_time"` } func (m *ProposalBase) Reset() { *m = ProposalBase{} } @@ -375,6 +377,8 @@ func (m *TallyResult) XXX_DiscardUnknown() { var xxx_messageInfo_TallyResult proto.InternalMessageInfo +// Vote defines a vote on a governance proposal. A vote corresponds to a proposal +// ID, the voter, and the vote option. type Vote struct { ProposalID uint64 `protobuf:"varint,1,opt,name=proposal_id,json=proposalId,proto3" json:"proposal_id,omitempty" yaml:"proposal_id"` Voter github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,2,opt,name=voter,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"voter,omitempty"` @@ -413,114 +417,6 @@ func (m *Vote) XXX_DiscardUnknown() { var xxx_messageInfo_Vote proto.InternalMessageInfo -type BasicProposal struct { - *ProposalBase `protobuf:"bytes,1,opt,name=base,proto3,embedded=base" json:"base,omitempty"` - Content *BasicContent `protobuf:"bytes,2,opt,name=content,proto3" json:"content,omitempty"` -} - -func (m *BasicProposal) Reset() { *m = BasicProposal{} } -func (*BasicProposal) ProtoMessage() {} -func (*BasicProposal) Descriptor() ([]byte, []int) { - return fileDescriptor_a5ae5e91b5b3fb03, []int{8} -} -func (m *BasicProposal) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *BasicProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_BasicProposal.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 *BasicProposal) XXX_Merge(src proto.Message) { - xxx_messageInfo_BasicProposal.Merge(m, src) -} -func (m *BasicProposal) XXX_Size() int { - return m.Size() -} -func (m *BasicProposal) XXX_DiscardUnknown() { - xxx_messageInfo_BasicProposal.DiscardUnknown(m) -} - -var xxx_messageInfo_BasicProposal proto.InternalMessageInfo - -type BasicContent struct { - // Types that are valid to be assigned to Sum: - // *BasicContent_Text - Sum isBasicContent_Sum `protobuf_oneof:"sum"` -} - -func (m *BasicContent) Reset() { *m = BasicContent{} } -func (*BasicContent) ProtoMessage() {} -func (*BasicContent) Descriptor() ([]byte, []int) { - return fileDescriptor_a5ae5e91b5b3fb03, []int{9} -} -func (m *BasicContent) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *BasicContent) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_BasicContent.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 *BasicContent) XXX_Merge(src proto.Message) { - xxx_messageInfo_BasicContent.Merge(m, src) -} -func (m *BasicContent) XXX_Size() int { - return m.Size() -} -func (m *BasicContent) XXX_DiscardUnknown() { - xxx_messageInfo_BasicContent.DiscardUnknown(m) -} - -var xxx_messageInfo_BasicContent proto.InternalMessageInfo - -type isBasicContent_Sum interface { - isBasicContent_Sum() - MarshalTo([]byte) (int, error) - Size() int -} - -type BasicContent_Text struct { - Text *TextProposal `protobuf:"bytes,1,opt,name=text,proto3,oneof" json:"text,omitempty"` -} - -func (*BasicContent_Text) isBasicContent_Sum() {} - -func (m *BasicContent) GetSum() isBasicContent_Sum { - if m != nil { - return m.Sum - } - return nil -} - -func (m *BasicContent) GetText() *TextProposal { - if x, ok := m.GetSum().(*BasicContent_Text); ok { - return x.Text - } - return nil -} - -// XXX_OneofWrappers is for the internal use of the proto package. -func (*BasicContent) XXX_OneofWrappers() []interface{} { - return []interface{}{ - (*BasicContent_Text)(nil), - } -} - func init() { proto.RegisterEnum("cosmos_sdk.x.gov.v1.VoteOption", VoteOption_name, VoteOption_value) proto.RegisterEnum("cosmos_sdk.x.gov.v1.ProposalStatus", ProposalStatus_name, ProposalStatus_value) @@ -532,90 +428,86 @@ func init() { proto.RegisterType((*ProposalBase)(nil), "cosmos_sdk.x.gov.v1.ProposalBase") proto.RegisterType((*TallyResult)(nil), "cosmos_sdk.x.gov.v1.TallyResult") proto.RegisterType((*Vote)(nil), "cosmos_sdk.x.gov.v1.Vote") - proto.RegisterType((*BasicProposal)(nil), "cosmos_sdk.x.gov.v1.BasicProposal") - proto.RegisterType((*BasicContent)(nil), "cosmos_sdk.x.gov.v1.BasicContent") } func init() { proto.RegisterFile("x/gov/types/types.proto", fileDescriptor_a5ae5e91b5b3fb03) } var fileDescriptor_a5ae5e91b5b3fb03 = []byte{ - // 1208 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x57, 0xcf, 0x8b, 0xdb, 0x46, - 0x1b, 0x96, 0x6c, 0xef, 0x7a, 0xf3, 0xfa, 0x47, 0x94, 0xd9, 0x7c, 0xc9, 0x22, 0x3e, 0x24, 0xd5, - 0x2d, 0x61, 0x9b, 0x10, 0x6d, 0xb3, 0x39, 0x04, 0x36, 0x50, 0x6a, 0xc5, 0x4a, 0xe2, 0x90, 0xb5, - 0x8d, 0x6c, 0x36, 0xa4, 0x50, 0x84, 0xd6, 0x52, 0xbc, 0x4a, 0x6c, 0x8d, 0xf1, 0x8c, 0xdd, 0xdd, - 0x5b, 0x4e, 0xa5, 0xf5, 0x29, 0x14, 0x0a, 0xbd, 0x18, 0x02, 0xcd, 0x21, 0x94, 0x1e, 0x7a, 0xe8, - 0x5f, 0xd0, 0x53, 0xe8, 0xa5, 0x39, 0x86, 0x52, 0x9c, 0x66, 0x73, 0x2b, 0x3d, 0x05, 0x7a, 0xe9, - 0xa9, 0x68, 0x46, 0xca, 0x6a, 0xc9, 0x26, 0xc4, 0x24, 0xa5, 0xd0, 0xcb, 0xb2, 0x9a, 0x79, 0x9e, - 0x67, 0xde, 0xf7, 0x99, 0x57, 0x8f, 0x76, 0xe1, 0xf8, 0xf6, 0x4a, 0x07, 0x8f, 0x56, 0xe8, 0x4e, - 0xdf, 0x23, 0xfc, 0xa7, 0xde, 0x1f, 0x60, 0x8a, 0xd1, 0x62, 0x1b, 0x93, 0x1e, 0x26, 0x36, 0x71, - 0x6f, 0xe9, 0xdb, 0x7a, 0x07, 0x8f, 0xf4, 0xd1, 0x19, 0xf9, 0xc8, 0x0b, 0x38, 0xf9, 0x04, 0xdd, - 0xf2, 0x07, 0xae, 0xdd, 0x77, 0x06, 0x74, 0x67, 0x85, 0x2d, 0xad, 0x74, 0x70, 0x07, 0xef, 0xfd, - 0x16, 0xe1, 0x4e, 0xbd, 0x88, 0xe3, 0x27, 0x9c, 0x4e, 0x3e, 0x44, 0x60, 0xb5, 0x83, 0x71, 0xa7, - 0xeb, 0x71, 0xdc, 0xe6, 0xf0, 0xc6, 0x0a, 0xf5, 0x7b, 0x1e, 0xa1, 0x4e, 0xaf, 0xcf, 0x01, 0xa5, - 0x3f, 0x45, 0xf8, 0xdf, 0x3a, 0xe9, 0x34, 0x87, 0x9b, 0x3d, 0x9f, 0x36, 0x06, 0xb8, 0x8f, 0x89, - 0xd3, 0x35, 0x1c, 0xe2, 0xa1, 0xcf, 0x44, 0x28, 0xfa, 0x01, 0xf5, 0x9d, 0xae, 0xed, 0x7a, 0x7d, - 0x4c, 0x7c, 0xba, 0x24, 0x6a, 0xe9, 0xe5, 0xdc, 0xea, 0xa2, 0x9e, 0xe8, 0x68, 0x74, 0x46, 0xbf, - 0x80, 0xfd, 0xc0, 0xb8, 0xf2, 0x60, 0xaa, 0x0a, 0xcf, 0xa6, 0xea, 0xb1, 0x1d, 0xa7, 0xd7, 0x5d, - 0x2b, 0xf9, 0x81, 0x9f, 0x64, 0x96, 0xbe, 0x7d, 0xac, 0x2e, 0x77, 0x7c, 0xba, 0x35, 0xdc, 0xd4, - 0xdb, 0xb8, 0x17, 0xd5, 0x18, 0xd7, 0x4d, 0xdc, 0x5b, 0x91, 0x13, 0xa1, 0x14, 0xb1, 0x0a, 0xfc, - 0xd8, 0x0a, 0xe7, 0xa2, 0x75, 0x58, 0xe8, 0xb3, 0xc2, 0xbc, 0xc1, 0x52, 0x4a, 0x13, 0x97, 0xf3, - 0xc6, 0x99, 0xbf, 0xa6, 0xea, 0xe9, 0xd7, 0x90, 0x2b, 0xb7, 0xdb, 0x65, 0xd7, 0x1d, 0x78, 0x84, - 0x58, 0xcf, 0x25, 0xd6, 0x32, 0xb7, 0x7f, 0xd5, 0xc4, 0xd2, 0x97, 0x29, 0x80, 0x75, 0xd2, 0x89, - 0xcf, 0x68, 0x41, 0xae, 0x1f, 0x35, 0x6f, 0xfb, 0xee, 0x92, 0xa8, 0x89, 0xcb, 0x19, 0xe3, 0xec, - 0xee, 0x54, 0x85, 0xd8, 0x93, 0x6a, 0xe5, 0xf7, 0xa9, 0x9a, 0x04, 0x3d, 0x9b, 0xaa, 0x88, 0x37, - 0x9b, 0x58, 0x2c, 0x59, 0x10, 0x3f, 0x55, 0x5d, 0x54, 0x87, 0x43, 0x91, 0x01, 0xf8, 0x0d, 0x4a, - 0xdf, 0xd3, 0x40, 0x9f, 0xc0, 0xbc, 0xd3, 0xc3, 0xc3, 0x80, 0x2e, 0xa5, 0x5f, 0x7e, 0x15, 0x1f, - 0x84, 0x57, 0x31, 0x93, 0xe1, 0x91, 0x68, 0xe9, 0x89, 0x08, 0xd9, 0x75, 0xd2, 0xd9, 0xc0, 0xd4, - 0xfb, 0x87, 0x1c, 0xb9, 0x04, 0x73, 0x23, 0x4c, 0xdf, 0xe4, 0x22, 0x39, 0x1f, 0x9d, 0x83, 0x79, - 0xdc, 0xa7, 0x3e, 0x0e, 0x96, 0xd2, 0x9a, 0xb8, 0x5c, 0x5c, 0x55, 0xf5, 0x03, 0x5e, 0x33, 0x3d, - 0xec, 0xa4, 0xce, 0x60, 0x56, 0x04, 0x2f, 0x5d, 0x84, 0x7c, 0xcb, 0xdb, 0x7e, 0x3e, 0xea, 0xe8, - 0x28, 0xcc, 0x51, 0x9f, 0x76, 0x3d, 0xd6, 0xe1, 0x21, 0x8b, 0x3f, 0x20, 0x0d, 0x72, 0xae, 0x47, - 0xda, 0x03, 0x9f, 0x9f, 0x91, 0x62, 0x7b, 0xc9, 0xa5, 0xd2, 0xed, 0x14, 0x64, 0xe3, 0xe9, 0x31, - 0x0f, 0xf2, 0xea, 0xbd, 0xfd, 0x5e, 0xfd, 0x07, 0xc7, 0xe5, 0xab, 0x39, 0xc8, 0xef, 0x8b, 0x8c, - 0xb7, 0xe4, 0xc3, 0x79, 0x98, 0x27, 0xd4, 0xa1, 0x43, 0xc2, 0x4c, 0x28, 0xae, 0xbe, 0x7b, 0xe0, - 0xdd, 0xc6, 0x92, 0x4d, 0x06, 0xb5, 0x22, 0x0a, 0x6a, 0x01, 0xba, 0xe1, 0x07, 0x4e, 0xd7, 0xa6, - 0x4e, 0xb7, 0xbb, 0x63, 0x0f, 0x3c, 0x32, 0xec, 0x52, 0x36, 0x24, 0xb9, 0x55, 0xed, 0x40, 0xa1, - 0x56, 0x08, 0xb4, 0x18, 0xce, 0xc8, 0x84, 0x66, 0x58, 0x12, 0x53, 0x48, 0xac, 0x87, 0x9d, 0x11, - 0x16, 0x91, 0x76, 0x18, 0xa0, 0x4b, 0x19, 0x26, 0x27, 0xeb, 0x3c, 0x5d, 0xf5, 0x38, 0x5d, 0xf5, - 0x56, 0x9c, 0xae, 0xc6, 0x42, 0x28, 0x74, 0xe7, 0xb1, 0x2a, 0x5a, 0xc0, 0x89, 0xe1, 0x16, 0xaa, - 0x81, 0x14, 0xdd, 0x8e, 0xed, 0x05, 0x2e, 0xd7, 0x9a, 0x9b, 0x41, 0xab, 0x18, 0xb1, 0xcd, 0xc0, - 0x65, 0x7a, 0x37, 0xa1, 0x40, 0x31, 0x4d, 0x24, 0xf4, 0xfc, 0xdb, 0xbc, 0xe7, 0x3c, 0xd3, 0x8e, - 0x87, 0xbc, 0x01, 0x47, 0x46, 0x98, 0xfa, 0x41, 0xc7, 0x26, 0xd4, 0x19, 0x44, 0x46, 0x64, 0x67, - 0x28, 0xfe, 0x30, 0xa7, 0x37, 0x43, 0x36, 0xab, 0xfe, 0x2a, 0x44, 0x4b, 0x7b, 0x66, 0x2c, 0xcc, - 0xa0, 0x57, 0xe0, 0xe4, 0xc8, 0x8b, 0xb5, 0x85, 0xaf, 0xef, 0xaa, 0xe2, 0xfd, 0xbb, 0xaa, 0x58, - 0xfa, 0x31, 0x05, 0xb9, 0xe4, 0xe5, 0x7d, 0x04, 0xe9, 0x1d, 0x8f, 0xb0, 0x71, 0xcc, 0x1b, 0x7a, - 0xc8, 0xff, 0x65, 0xaa, 0x9e, 0x78, 0x0d, 0x1b, 0xaa, 0x01, 0xb5, 0x42, 0x2a, 0xba, 0x0c, 0x59, - 0x67, 0x93, 0x50, 0xc7, 0x0f, 0xa2, 0xf7, 0x72, 0x56, 0x95, 0x98, 0x8e, 0x3e, 0x84, 0x54, 0x80, - 0xd9, 0x38, 0xce, 0x2e, 0x92, 0x0a, 0x30, 0xea, 0x40, 0x3e, 0xc0, 0xf6, 0xa7, 0x3e, 0xdd, 0xb2, - 0x47, 0x1e, 0xc5, 0x6c, 0x12, 0xf3, 0x86, 0x39, 0x9b, 0xd2, 0xb3, 0xa9, 0xba, 0xc8, 0xdf, 0xc1, - 0xa4, 0x56, 0xc9, 0x82, 0x00, 0x5f, 0xf3, 0xe9, 0xd6, 0x46, 0xf8, 0xf0, 0xb3, 0x08, 0x19, 0xf6, - 0x21, 0x78, 0x4b, 0x2f, 0xf5, 0xbf, 0x9f, 0xfc, 0x5f, 0x88, 0x50, 0x30, 0x1c, 0xe2, 0xb7, 0x9f, - 0x67, 0xff, 0x79, 0xc8, 0x6c, 0x3a, 0x84, 0x47, 0x7f, 0x6e, 0xf5, 0x9d, 0x57, 0xc6, 0x4c, 0x18, - 0x70, 0x46, 0xe6, 0xe1, 0x54, 0x15, 0x2d, 0x46, 0x42, 0xe7, 0x21, 0xdb, 0xc6, 0x01, 0xf5, 0x02, - 0xca, 0x5a, 0x7a, 0x19, 0x9f, 0x9d, 0x78, 0x81, 0x03, 0xad, 0x98, 0x51, 0xb2, 0x21, 0x9f, 0xdc, - 0x40, 0xe7, 0x20, 0x43, 0xbd, 0x6d, 0xfa, 0xca, 0x4a, 0x92, 0x9f, 0xad, 0xcb, 0x82, 0xc5, 0x08, - 0x6b, 0x87, 0xc3, 0xbf, 0x66, 0x7e, 0xfa, 0xe1, 0x74, 0x36, 0x52, 0x32, 0xe6, 0x20, 0x4d, 0x86, - 0xbd, 0x93, 0xdf, 0x89, 0x00, 0x7b, 0x1e, 0x20, 0x19, 0xe6, 0xcc, 0xf5, 0x46, 0xeb, 0xba, 0x24, - 0xc8, 0x87, 0xc7, 0x13, 0x2d, 0xc7, 0x97, 0xcd, 0x5e, 0x9f, 0xee, 0xa0, 0x63, 0x90, 0xbe, 0x6e, - 0x36, 0x25, 0x51, 0x2e, 0x8c, 0x27, 0xda, 0x21, 0xbe, 0x73, 0xdd, 0x23, 0x48, 0x81, 0x6c, 0xd9, - 0x68, 0xb6, 0xca, 0xd5, 0x9a, 0x94, 0x92, 0x8f, 0x8c, 0x27, 0x5a, 0x81, 0xef, 0x95, 0xa3, 0x51, - 0x3e, 0x0a, 0xa9, 0x5a, 0x5d, 0x4a, 0xcb, 0xf9, 0xf1, 0x44, 0x5b, 0xe0, 0x5b, 0x35, 0x8c, 0x4e, - 0x40, 0xbe, 0x56, 0xb7, 0xaf, 0x55, 0x5b, 0x97, 0xed, 0x0d, 0xb3, 0x55, 0x97, 0x32, 0xf2, 0xd1, - 0xf1, 0x44, 0x93, 0xe2, 0xfd, 0x78, 0xbe, 0xe4, 0xfc, 0xe7, 0xdf, 0x28, 0xc2, 0xfd, 0x7b, 0x8a, - 0xf0, 0xfd, 0x3d, 0x45, 0x38, 0xf9, 0x87, 0x08, 0xc5, 0xfd, 0x81, 0x1e, 0x96, 0x55, 0xab, 0x5e, - 0x95, 0x04, 0x5e, 0x16, 0x5f, 0xac, 0xf9, 0x5d, 0x74, 0x0a, 0x8a, 0x15, 0xb3, 0x51, 0x6f, 0x56, - 0x5b, 0x76, 0xc3, 0xb4, 0xaa, 0xf5, 0x8a, 0x24, 0xca, 0xc7, 0xc7, 0x13, 0x6d, 0x91, 0x43, 0xa2, - 0xb8, 0x6a, 0x78, 0x03, 0x1f, 0xbb, 0xe8, 0x7d, 0x28, 0x6c, 0xd4, 0x5b, 0xd5, 0xda, 0xa5, 0x18, - 0x9b, 0x92, 0x8f, 0x8d, 0x27, 0x1a, 0xe2, 0xd8, 0x0d, 0x16, 0x20, 0x11, 0xf4, 0xff, 0x30, 0xdf, - 0x28, 0x37, 0x9b, 0x66, 0x45, 0x4a, 0xcb, 0xd2, 0x78, 0xa2, 0xe5, 0x39, 0xa6, 0xe1, 0x10, 0xe2, - 0xb9, 0x48, 0x83, 0x05, 0xcb, 0xbc, 0x62, 0x5e, 0x68, 0x99, 0x15, 0x29, 0x23, 0xa3, 0xf1, 0x44, - 0x2b, 0x46, 0x1f, 0x1e, 0xef, 0xa6, 0xd7, 0xa6, 0x1e, 0xe3, 0x5f, 0x2c, 0x57, 0xaf, 0x9a, 0x15, - 0x69, 0x2e, 0xc9, 0xbf, 0xe8, 0xf8, 0x5d, 0xcf, 0xdd, 0xdf, 0xae, 0x51, 0x7b, 0xf0, 0x44, 0x11, - 0x1e, 0x3d, 0x51, 0x84, 0xdb, 0xbb, 0x8a, 0xf0, 0x60, 0x57, 0x11, 0x1f, 0xee, 0x2a, 0xe2, 0x6f, - 0xbb, 0x8a, 0x78, 0xe7, 0xa9, 0x22, 0x3c, 0x7c, 0xaa, 0x08, 0x8f, 0x9e, 0x2a, 0xc2, 0xc7, 0xaf, - 0x4e, 0xea, 0xc4, 0xff, 0x1b, 0x9b, 0xf3, 0x2c, 0x28, 0xcf, 0xfe, 0x1d, 0x00, 0x00, 0xff, 0xff, - 0xaa, 0x0c, 0xd1, 0xcc, 0x85, 0x0c, 0x00, 0x00, + // 1181 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x57, 0xc1, 0x6f, 0xd3, 0x56, + 0x18, 0xb7, 0x93, 0x36, 0x6d, 0x5f, 0xd2, 0x60, 0x5e, 0x3b, 0xc8, 0xac, 0xc9, 0x36, 0x06, 0xa1, + 0x8e, 0x09, 0x67, 0x94, 0xc3, 0x24, 0x0e, 0xd3, 0x62, 0x62, 0x20, 0x88, 0x26, 0x91, 0x13, 0x15, + 0xb1, 0x69, 0xb2, 0xdc, 0xd8, 0xb8, 0x1e, 0x8e, 0x5f, 0x96, 0xf7, 0x92, 0x91, 0x1b, 0xda, 0x61, + 0x9a, 0x72, 0x42, 0x3b, 0xed, 0x12, 0x09, 0x69, 0x1c, 0xd0, 0xb4, 0xc3, 0xfe, 0x86, 0x9d, 0x90, + 0x76, 0x18, 0x47, 0x34, 0x4d, 0x61, 0x94, 0xdb, 0xb4, 0x13, 0xd2, 0x2e, 0x3b, 0x4d, 0xf6, 0x7b, + 0xa6, 0x0e, 0x2d, 0x83, 0x8a, 0x4d, 0x93, 0x76, 0x69, 0xeb, 0xef, 0x7d, 0xdf, 0xef, 0xf7, 0xbe, + 0xdf, 0xfb, 0xde, 0xef, 0xa9, 0xe0, 0xe8, 0xcd, 0xb2, 0x87, 0x86, 0x65, 0x32, 0xea, 0xb9, 0x98, + 0xfe, 0xd4, 0x7a, 0x7d, 0x44, 0x10, 0x5c, 0xe9, 0x20, 0xdc, 0x45, 0xd8, 0xc2, 0xce, 0x0d, 0xed, + 0xa6, 0xe6, 0xa1, 0xa1, 0x36, 0x3c, 0x23, 0x1e, 0xde, 0x93, 0x27, 0x9e, 0x24, 0xdb, 0x7e, 0xdf, + 0xb1, 0x7a, 0x76, 0x9f, 0x8c, 0xca, 0x71, 0xa8, 0xec, 0x21, 0x0f, 0xed, 0xfe, 0xc5, 0xf2, 0x64, + 0x0f, 0x21, 0x2f, 0x70, 0x69, 0xca, 0xd6, 0xe0, 0x7a, 0x99, 0xf8, 0x5d, 0x17, 0x13, 0xbb, 0xdb, + 0xa3, 0x09, 0xea, 0x1f, 0x3c, 0x78, 0x63, 0x03, 0x7b, 0xad, 0xc1, 0x56, 0xd7, 0x27, 0xcd, 0x3e, + 0xea, 0x21, 0x6c, 0x07, 0xba, 0x8d, 0x5d, 0xf8, 0x05, 0x0f, 0x8a, 0x7e, 0x48, 0x7c, 0x3b, 0xb0, + 0x1c, 0xb7, 0x87, 0xb0, 0x4f, 0x4a, 0xbc, 0x92, 0x5d, 0xcb, 0xaf, 0xaf, 0x68, 0xa9, 0x4d, 0x0e, + 0xcf, 0x68, 0xe7, 0x91, 0x1f, 0xea, 0x97, 0xef, 0x4f, 0x65, 0xee, 0xe9, 0x54, 0x3e, 0x32, 0xb2, + 0xbb, 0xc1, 0x39, 0xd5, 0x0f, 0xfd, 0x74, 0xa5, 0xfa, 0xed, 0x23, 0x79, 0xcd, 0xf3, 0xc9, 0xf6, + 0x60, 0x4b, 0xeb, 0xa0, 0x6e, 0x99, 0x02, 0xb0, 0x5f, 0xa7, 0xb1, 0x73, 0x83, 0x35, 0x17, 0x41, + 0x61, 0x73, 0x99, 0xd2, 0x56, 0x69, 0x2d, 0xdc, 0x00, 0x8b, 0xbd, 0x78, 0x63, 0x6e, 0xbf, 0x94, + 0x51, 0xf8, 0xb5, 0x82, 0x7e, 0xe6, 0xcf, 0xa9, 0x7c, 0xfa, 0x15, 0xe0, 0x2a, 0x9d, 0x4e, 0xc5, + 0x71, 0xfa, 0x2e, 0xc6, 0xe6, 0x33, 0x88, 0x73, 0x73, 0xb7, 0x7e, 0x51, 0x78, 0xf5, 0xab, 0x0c, + 0x00, 0x1b, 0xd8, 0x4b, 0x38, 0xda, 0x20, 0xdf, 0x63, 0xcd, 0x5b, 0xbe, 0x53, 0xe2, 0x15, 0x7e, + 0x6d, 0x4e, 0x3f, 0xbb, 0x33, 0x95, 0x41, 0xa2, 0x49, 0xad, 0xfa, 0xdb, 0x54, 0x4e, 0x27, 0x3d, + 0x9d, 0xca, 0x90, 0x36, 0x9b, 0x0a, 0xaa, 0x26, 0x48, 0xbe, 0x6a, 0x0e, 0x6c, 0x80, 0x25, 0x26, + 0x00, 0x7a, 0x8d, 0xad, 0xef, 0x62, 0xc0, 0x8f, 0x41, 0xce, 0xee, 0xa2, 0x41, 0x48, 0x4a, 0xd9, + 0x17, 0x1f, 0xc5, 0xbb, 0xd1, 0x51, 0x1c, 0x48, 0x70, 0x06, 0xaa, 0x3e, 0xe6, 0xc1, 0xc2, 0x06, + 0xf6, 0x36, 0x11, 0x71, 0xff, 0x25, 0x45, 0x2e, 0x82, 0xf9, 0x21, 0x22, 0xaf, 0x73, 0x90, 0xb4, + 0x1e, 0xbe, 0x07, 0x72, 0xa8, 0x47, 0x7c, 0x14, 0x96, 0xb2, 0x0a, 0xbf, 0x56, 0x5c, 0x97, 0xb5, + 0x7d, 0x6e, 0x8e, 0x16, 0x75, 0xd2, 0x88, 0xd3, 0x4c, 0x96, 0xae, 0x5e, 0x00, 0x85, 0xb6, 0x7b, + 0xf3, 0xd9, 0xa8, 0xc3, 0x55, 0x30, 0x4f, 0x7c, 0x12, 0xb8, 0x71, 0x87, 0x4b, 0x26, 0xfd, 0x80, + 0x0a, 0xc8, 0x3b, 0x2e, 0xee, 0xf4, 0x7d, 0xca, 0x91, 0x89, 0xd7, 0xd2, 0x21, 0xf5, 0x56, 0x06, + 0x2c, 0x24, 0xd3, 0x63, 0xec, 0xa7, 0xd5, 0x89, 0x59, 0xad, 0xfe, 0x87, 0xe3, 0xf2, 0x63, 0x0e, + 0x14, 0x66, 0x2c, 0x43, 0xdf, 0x4f, 0x87, 0x63, 0x7b, 0x66, 0x26, 0x13, 0x8f, 0xca, 0x12, 0x73, + 0x8a, 0xe7, 0x44, 0xb8, 0x0a, 0x72, 0x98, 0xd8, 0x64, 0x80, 0x63, 0x05, 0x8a, 0xeb, 0xc7, 0xf7, + 0x3d, 0xd8, 0x04, 0xaf, 0x15, 0xa7, 0xea, 0xe2, 0xae, 0xf3, 0x3c, 0xdb, 0x00, 0x45, 0x51, 0x4d, + 0x06, 0x07, 0x3f, 0x05, 0xf0, 0xba, 0x1f, 0xda, 0x81, 0x45, 0xec, 0x20, 0x18, 0x59, 0x7d, 0x17, + 0x0f, 0x02, 0x12, 0x4f, 0x4f, 0x7e, 0x5d, 0xd9, 0x97, 0xa4, 0x1d, 0x25, 0x9a, 0x71, 0x9e, 0x7e, + 0x8c, 0xf9, 0xdb, 0x9b, 0x94, 0x65, 0x2f, 0x92, 0x6a, 0x0a, 0x71, 0x30, 0x55, 0x04, 0x3f, 0x02, + 0x79, 0x1c, 0x1b, 0xab, 0x15, 0xd9, 0x6e, 0x69, 0x2e, 0xe6, 0x12, 0x35, 0xea, 0xc9, 0x5a, 0xe2, + 0xc9, 0x5a, 0x3b, 0xf1, 0x64, 0x5d, 0x62, 0x2c, 0x6c, 0x52, 0x52, 0xc5, 0xea, 0xed, 0x47, 0x32, + 0x6f, 0x02, 0x1a, 0x89, 0x0a, 0xa0, 0x0f, 0x04, 0x76, 0xd2, 0x96, 0x1b, 0x3a, 0x94, 0x61, 0xfe, + 0xa5, 0x0c, 0xc7, 0x19, 0xc3, 0x51, 0xca, 0xf0, 0x3c, 0x02, 0xa5, 0x29, 0xb2, 0xb0, 0x11, 0x3a, + 0x31, 0xd5, 0xe7, 0x3c, 0x58, 0x26, 0x88, 0xa4, 0x5e, 0x82, 0xdc, 0x8b, 0xe7, 0xe9, 0x12, 0x63, + 0x58, 0xa5, 0x0c, 0x33, 0x75, 0x07, 0x7b, 0x07, 0x0a, 0x71, 0x6d, 0x72, 0xc9, 0x02, 0x70, 0x78, + 0x88, 0x88, 0x1f, 0x7a, 0xd1, 0xc9, 0xf6, 0x99, 0xa4, 0x0b, 0x2f, 0x6d, 0xf8, 0x04, 0xdb, 0x4e, + 0x89, 0x6e, 0x67, 0x0f, 0x04, 0xed, 0xf8, 0x10, 0x8d, 0xb7, 0xa2, 0x70, 0xdc, 0xf2, 0x75, 0xc0, + 0x42, 0xbb, 0xe2, 0x2e, 0xbe, 0x94, 0x4b, 0x9d, 0x7d, 0x04, 0x9f, 0x03, 0xa0, 0x4c, 0xcb, 0x34, + 0xca, 0xa4, 0x3d, 0xb7, 0xf8, 0xf5, 0x1d, 0x99, 0xbf, 0x77, 0x47, 0xe6, 0xd5, 0x1f, 0x32, 0x20, + 0x9f, 0x1e, 0x9e, 0x0f, 0x40, 0x76, 0xe4, 0x62, 0x6a, 0x4b, 0xba, 0x16, 0x21, 0xff, 0x3c, 0x95, + 0x4f, 0xbe, 0x82, 0x78, 0xb5, 0x90, 0x98, 0x51, 0x29, 0xbc, 0x04, 0x16, 0xec, 0x2d, 0x4c, 0x6c, + 0x9f, 0x19, 0xd8, 0x81, 0x51, 0x92, 0x72, 0xf8, 0x3e, 0xc8, 0x84, 0x28, 0xbe, 0x2b, 0x07, 0x07, + 0xc9, 0x84, 0x08, 0x7a, 0xa0, 0x10, 0x22, 0xeb, 0x33, 0x9f, 0x6c, 0x5b, 0x43, 0x97, 0xa0, 0xf8, + 0x26, 0x2c, 0xe9, 0xc6, 0xc1, 0x90, 0x9e, 0x4e, 0xe5, 0x15, 0x2a, 0x6c, 0x1a, 0x4b, 0x35, 0x41, + 0x88, 0xae, 0xfa, 0x64, 0x7b, 0x33, 0xfa, 0xf8, 0x89, 0x07, 0x73, 0xf1, 0xf3, 0xf5, 0x0f, 0x59, + 0xf2, 0x7f, 0xfe, 0x5e, 0x9d, 0xfa, 0x8e, 0x07, 0x60, 0x37, 0x0c, 0x45, 0x30, 0x6f, 0x6c, 0x34, + 0xdb, 0xd7, 0x04, 0x4e, 0x3c, 0x34, 0x9e, 0x28, 0x79, 0x1a, 0x36, 0xba, 0x3d, 0x32, 0x82, 0x47, + 0x40, 0xf6, 0x9a, 0xd1, 0x12, 0x78, 0x71, 0x79, 0x3c, 0x51, 0x96, 0xe8, 0xca, 0x35, 0x17, 0x43, + 0x09, 0x2c, 0x54, 0xf4, 0x56, 0xbb, 0x52, 0xab, 0x0b, 0x19, 0xf1, 0xf0, 0x78, 0xa2, 0x2c, 0xd3, + 0xb5, 0x0a, 0x3b, 0xdd, 0x55, 0x90, 0xa9, 0x37, 0x84, 0xac, 0x58, 0x18, 0x4f, 0x94, 0x45, 0xba, + 0x54, 0x47, 0xf0, 0x24, 0x28, 0xd4, 0x1b, 0xd6, 0xd5, 0x5a, 0xfb, 0x92, 0xb5, 0x69, 0xb4, 0x1b, + 0xc2, 0x9c, 0xb8, 0x3a, 0x9e, 0x28, 0x42, 0xb2, 0x9e, 0x48, 0x2e, 0x16, 0xbe, 0xfc, 0x46, 0xe2, + 0xee, 0xdd, 0x95, 0xb8, 0xef, 0xef, 0x4a, 0xdc, 0xa9, 0xdf, 0x79, 0x50, 0x9c, 0x35, 0xe7, 0x68, + 0x5b, 0xf5, 0xda, 0x15, 0x81, 0xa3, 0xdb, 0xa2, 0xc1, 0xba, 0x1f, 0xc0, 0x77, 0x40, 0xb1, 0x6a, + 0x34, 0x1b, 0xad, 0x5a, 0xdb, 0x6a, 0x1a, 0x66, 0xad, 0x51, 0x15, 0x78, 0xf1, 0xe8, 0x78, 0xa2, + 0xac, 0xd0, 0x14, 0x76, 0xef, 0x9b, 0x6e, 0xdf, 0x47, 0x0e, 0x7c, 0x1b, 0x2c, 0x6f, 0x36, 0xda, + 0xb5, 0xfa, 0xc5, 0x24, 0x37, 0x23, 0x1e, 0x19, 0x4f, 0x14, 0x48, 0x73, 0x37, 0xe3, 0x3b, 0xc5, + 0x52, 0xdf, 0x02, 0xb9, 0x66, 0xa5, 0xd5, 0x32, 0xaa, 0x42, 0x56, 0x14, 0xc6, 0x13, 0xa5, 0x40, + 0x73, 0x9a, 0x36, 0xc6, 0xae, 0x03, 0x15, 0xb0, 0x68, 0x1a, 0x97, 0x8d, 0xf3, 0x6d, 0xa3, 0x2a, + 0xcc, 0x89, 0x70, 0x3c, 0x51, 0x8a, 0x74, 0xdd, 0x74, 0x3f, 0x71, 0x3b, 0xc4, 0x8d, 0xeb, 0x2f, + 0x54, 0x6a, 0x57, 0x8c, 0xaa, 0x30, 0x9f, 0xae, 0xbf, 0x60, 0xfb, 0x81, 0xeb, 0xcc, 0xb6, 0xab, + 0xd7, 0xef, 0x3f, 0x96, 0xb8, 0x87, 0x8f, 0x25, 0xee, 0xd6, 0x8e, 0xc4, 0xdd, 0xdf, 0x91, 0xf8, + 0x07, 0x3b, 0x12, 0xff, 0xeb, 0x8e, 0xc4, 0xdf, 0x7e, 0x22, 0x71, 0x0f, 0x9e, 0x48, 0xdc, 0xc3, + 0x27, 0x12, 0xf7, 0xe1, 0xdf, 0x5b, 0x5e, 0xea, 0x7f, 0x81, 0xad, 0x5c, 0xec, 0x2a, 0x67, 0xff, + 0x0a, 0x00, 0x00, 0xff, 0xff, 0x48, 0xe7, 0x6e, 0x7f, 0x21, 0x0c, 0x00, 0x00, } type ProposalBaseFace interface { @@ -683,29 +575,6 @@ func NewProposalBaseFromFace(that ProposalBaseFace) *ProposalBase { return this } -func (this *BasicContent) GetContent() Content { - if x := this.GetText(); x != nil { - return x - } - return nil -} - -func (this *BasicContent) SetContent(value Content) error { - if value == nil { - this.Sum = nil - return nil - } - switch vt := value.(type) { - case *TextProposal: - this.Sum = &BasicContent_Text{vt} - return nil - case TextProposal: - this.Sum = &BasicContent_Text{&vt} - return nil - } - return fmt.Errorf("can't encode value of type %T as message BasicContent", value) -} - func (m *MsgSubmitProposalBase) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -1117,106 +986,6 @@ func (m *Vote) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *BasicProposal) 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 *BasicProposal) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *BasicProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Content != nil { - { - size, err := m.Content.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTypes(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - } - if m.ProposalBase != nil { - { - size, err := m.ProposalBase.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTypes(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *BasicContent) 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 *BasicContent) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *BasicContent) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Sum != nil { - { - size := m.Sum.Size() - i -= size - if _, err := m.Sum.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - } - } - return len(dAtA) - i, nil -} - -func (m *BasicContent_Text) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *BasicContent_Text) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - if m.Text != nil { - { - size, err := m.Text.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTypes(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} func encodeVarintTypes(dAtA []byte, offset int, v uint64) int { offset -= sovTypes(v) base := offset @@ -1394,48 +1163,6 @@ func (m *Vote) Size() (n int) { return n } -func (m *BasicProposal) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.ProposalBase != nil { - l = m.ProposalBase.Size() - n += 1 + l + sovTypes(uint64(l)) - } - if m.Content != nil { - l = m.Content.Size() - n += 1 + l + sovTypes(uint64(l)) - } - return n -} - -func (m *BasicContent) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Sum != nil { - n += m.Sum.Size() - } - return n -} - -func (m *BasicContent_Text) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Text != nil { - l = m.Text.Size() - n += 1 + l + sovTypes(uint64(l)) - } - return n -} - func sovTypes(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -1458,26 +1185,6 @@ func (this *MsgSubmitProposalBase) String() string { }, "") return s } -func (this *BasicContent) String() string { - if this == nil { - return "nil" - } - s := strings.Join([]string{`&BasicContent{`, - `Sum:` + fmt.Sprintf("%v", this.Sum) + `,`, - `}`, - }, "") - return s -} -func (this *BasicContent_Text) String() string { - if this == nil { - return "nil" - } - s := strings.Join([]string{`&BasicContent_Text{`, - `Text:` + strings.Replace(fmt.Sprintf("%v", this.Text), "TextProposal", "TextProposal", 1) + `,`, - `}`, - }, "") - return s -} func valueToStringTypes(v interface{}) string { rv := reflect.ValueOf(v) if rv.IsNil() { @@ -2452,7 +2159,7 @@ func (m *TallyResult) Unmarshal(dAtA []byte) error { if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Yes", wireType) } - var byteLen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTypes @@ -2462,15 +2169,16 @@ func (m *TallyResult) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - byteLen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if byteLen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthTypes } - postIndex := iNdEx + byteLen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthTypes } @@ -2485,7 +2193,7 @@ func (m *TallyResult) Unmarshal(dAtA []byte) error { if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Abstain", wireType) } - var byteLen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTypes @@ -2495,15 +2203,16 @@ func (m *TallyResult) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - byteLen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if byteLen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthTypes } - postIndex := iNdEx + byteLen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthTypes } @@ -2518,7 +2227,7 @@ func (m *TallyResult) Unmarshal(dAtA []byte) error { if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field No", wireType) } - var byteLen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTypes @@ -2528,15 +2237,16 @@ func (m *TallyResult) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - byteLen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if byteLen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthTypes } - postIndex := iNdEx + byteLen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthTypes } @@ -2551,7 +2261,7 @@ func (m *TallyResult) Unmarshal(dAtA []byte) error { if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field NoWithVeto", wireType) } - var byteLen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTypes @@ -2561,15 +2271,16 @@ func (m *TallyResult) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - byteLen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if byteLen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthTypes } - postIndex := iNdEx + byteLen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthTypes } @@ -2729,219 +2440,6 @@ func (m *Vote) Unmarshal(dAtA []byte) error { } return nil } -func (m *BasicProposal) 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 ErrIntOverflowTypes - } - 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: BasicProposal: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: BasicProposal: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ProposalBase", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTypes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthTypes - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthTypes - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.ProposalBase == nil { - m.ProposalBase = &ProposalBase{} - } - if err := m.ProposalBase.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Content", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTypes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthTypes - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthTypes - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.Content == nil { - m.Content = &BasicContent{} - } - if err := m.Content.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipTypes(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthTypes - } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthTypes - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *BasicContent) 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 ErrIntOverflowTypes - } - 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: BasicContent: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: BasicContent: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Text", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTypes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthTypes - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthTypes - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - v := &TextProposal{} - if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - m.Sum = &BasicContent_Text{v} - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipTypes(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthTypes - } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthTypes - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} func skipTypes(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/gov/types/types.proto b/x/gov/types/types.proto index 967b847d56af..d590397ca9f0 100644 --- a/x/gov/types/types.proto +++ b/x/gov/types/types.proto @@ -3,131 +3,146 @@ package cosmos_sdk.x.gov.v1; import "types/types.proto"; import "third_party/proto/gogoproto/gogo.proto"; -import "third_party/proto/cosmos-proto/cosmos.proto"; +// import "third_party/proto/cosmos-proto/cosmos.proto"; import "google/protobuf/timestamp.proto"; -option go_package = "github.com/cosmos/cosmos-sdk/x/gov/types"; +option go_package = "github.com/cosmos/cosmos-sdk/x/gov/types"; option (gogoproto.goproto_stringer_all) = false; -option (gogoproto.stringer_all) = false; -option (gogoproto.goproto_getters_all) = false; +option (gogoproto.stringer_all) = false; +option (gogoproto.goproto_getters_all) = false; message MsgSubmitProposalBase { - option (gogoproto.stringer) = true; - repeated cosmos_sdk.v1.Coin intial_deposit = 1 [(gogoproto.nullable) = false - ,(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" - ,(gogoproto.moretags) = "yaml:\"initial_deposit\""]; - bytes proposer = 2 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; + option (gogoproto.stringer) = true; + + repeated cosmos_sdk.v1.Coin intial_deposit = 1 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", + (gogoproto.moretags) = "yaml:\"initial_deposit\"" + ]; + bytes proposer = 2 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; } // MsgDeposit defines a message to submit a deposit to an existing proposal message MsgDeposit { - uint64 proposal_id = 1 [(gogoproto.customname) = "ProposalID" - ,(gogoproto.moretags) = "yaml:\"proposal_id\"" - ,(gogoproto.jsontag) = "proposal_id"]; - bytes depositor = 2 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; - repeated cosmos_sdk.v1.Coin amount = 3 [(gogoproto.nullable) = false, - (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; + uint64 proposal_id = 1 [ + (gogoproto.customname) = "ProposalID", + (gogoproto.moretags) = "yaml:\"proposal_id\"", + (gogoproto.jsontag) = "proposal_id" + ]; + bytes depositor = 2 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; + repeated cosmos_sdk.v1.Coin amount = 3 + [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; } // VoteOption defines a vote option enum VoteOption { - option (gogoproto.enum_stringer) = false; - option (gogoproto.goproto_enum_stringer) = false; - option (gogoproto.goproto_enum_prefix) = false; - EMPTY = 0 [(gogoproto.enumvalue_customname) = "OptionEmpty"]; - YES = 1 [(gogoproto.enumvalue_customname) = "OptionYes"]; - ABSTAIN = 2 [(gogoproto.enumvalue_customname) = "OptionAbstain"]; - NO = 3 [(gogoproto.enumvalue_customname) = "OptionNo"]; - NO_WITH_VETO = 4 [(gogoproto.enumvalue_customname) = "OptionNoWithVeto"]; + option (gogoproto.enum_stringer) = false; + option (gogoproto.goproto_enum_stringer) = false; + option (gogoproto.goproto_enum_prefix) = false; + + EMPTY = 0 [(gogoproto.enumvalue_customname) = "OptionEmpty"]; + YES = 1 [(gogoproto.enumvalue_customname) = "OptionYes"]; + ABSTAIN = 2 [(gogoproto.enumvalue_customname) = "OptionAbstain"]; + NO = 3 [(gogoproto.enumvalue_customname) = "OptionNo"]; + NO_WITH_VETO = 4 [(gogoproto.enumvalue_customname) = "OptionNoWithVeto"]; } // MsgVote defines a message to cast a vote message MsgVote { - uint64 proposal_id = 1 [(gogoproto.customname) = "ProposalID" - ,(gogoproto.moretags) = "yaml:\"proposal_id\"" - ,(gogoproto.jsontag) = "proposal_id"]; - bytes voter = 2 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; - VoteOption option = 3; + uint64 proposal_id = 1 [ + (gogoproto.customname) = "ProposalID", + (gogoproto.moretags) = "yaml:\"proposal_id\"", + (gogoproto.jsontag) = "proposal_id" + ]; + bytes voter = 2 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; + VoteOption option = 3; } // TextProposal defines a standard text proposal whose changes need to be // manually updated in case of approval message TextProposal { - string title = 1; - string description = 2; + string title = 1; + string description = 2; } // Deposit defines an amount deposited by an account address to an active proposal message Deposit { - uint64 proposal_id = 1 [(gogoproto.customname) = "ProposalID" - ,(gogoproto.moretags) = "yaml:\"proposal_id\""]; - bytes depositor = 2 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; - repeated cosmos_sdk.v1.Coin amount = 3 [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; + uint64 proposal_id = 1 [(gogoproto.customname) = "ProposalID", (gogoproto.moretags) = "yaml:\"proposal_id\""]; + bytes depositor = 2 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; + repeated cosmos_sdk.v1.Coin amount = 3 + [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; } +// ProposalBase defines the core field members of a governance proposal. It includes +// all static fields (i.e fields excluding the dynamic Content). A full proposal +// extends the ProposalBase with Content. message ProposalBase { - option (gogoproto.goproto_stringer) = true; - option (gogoproto.face) = true; - uint64 proposal_id = 1 [(gogoproto.customname) = "ProposalID" - ,(gogoproto.moretags) = "yaml:\"id\""]; - ProposalStatus status = 2 [(gogoproto.moretags) = "yaml:\"proposal_status\""]; - TallyResult final_tally_result = 3 [(gogoproto.nullable) = false - ,(gogoproto.moretags) = "yaml:\"final_tally_result\""]; - google.protobuf.Timestamp submit_time = 4 [(gogoproto.stdtime) = true - ,(gogoproto.nullable) = false - ,(gogoproto.moretags) = "yaml:\"submit_time\""]; - google.protobuf.Timestamp deposit_end_time = 5 [(gogoproto.stdtime) = true - ,(gogoproto.nullable) = false - ,(gogoproto.moretags) = "yaml:\"deposit_end_time\""]; - repeated cosmos_sdk.v1.Coin total_deposit = 6 [(gogoproto.nullable) = false - ,(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" - ,(gogoproto.moretags) = "yaml:\"total_deposit\""]; - google.protobuf.Timestamp voting_start_time = 7 [(gogoproto.stdtime) = true - ,(gogoproto.nullable) = false - ,(gogoproto.moretags) = "yaml:\"voting_start_time\""]; - google.protobuf.Timestamp voting_end_time = 8 [(gogoproto.stdtime) = true - ,(gogoproto.nullable) = false - ,(gogoproto.moretags) = "yaml:\"voting_end_time\""]; + option (gogoproto.goproto_stringer) = true; + option (gogoproto.face) = true; + + uint64 proposal_id = 1 + [(gogoproto.customname) = "ProposalID", (gogoproto.jsontag) = "id", (gogoproto.moretags) = "yaml:\"id\""]; + ProposalStatus status = 2 [(gogoproto.moretags) = "yaml:\"proposal_status\""]; + TallyResult final_tally_result = 3 + [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"final_tally_result\""]; + google.protobuf.Timestamp submit_time = 4 + [(gogoproto.stdtime) = true, (gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"submit_time\""]; + google.protobuf.Timestamp deposit_end_time = 5 + [(gogoproto.stdtime) = true, (gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"deposit_end_time\""]; + repeated cosmos_sdk.v1.Coin total_deposit = 6 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", + (gogoproto.moretags) = "yaml:\"total_deposit\"" + ]; + google.protobuf.Timestamp voting_start_time = 7 + [(gogoproto.stdtime) = true, (gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"voting_start_time\""]; + google.protobuf.Timestamp voting_end_time = 8 + [(gogoproto.stdtime) = true, (gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"voting_end_time\""]; } // ProposalStatus is a type alias that represents a proposal status as a byte enum ProposalStatus { - option (gogoproto.enum_stringer) = false; - option (gogoproto.goproto_enum_stringer) = false; - option (gogoproto.goproto_enum_prefix) = false; - NIL = 0 [(gogoproto.enumvalue_customname) = "StatusNil"]; - DEPOSIT_PERIOD = 1 [(gogoproto.enumvalue_customname) = "StatusDepositPeriod"]; - VOTING_PERIOD = 2 [(gogoproto.enumvalue_customname) = "StatusVotingPeriod"]; - PASSED = 3 [(gogoproto.enumvalue_customname) = "StatusPassed"]; - REJECTED = 4 [(gogoproto.enumvalue_customname) = "StatusRejected"]; - FAILED = 5 [(gogoproto.enumvalue_customname) = "StatusFailed"]; + option (gogoproto.enum_stringer) = false; + option (gogoproto.goproto_enum_stringer) = false; + option (gogoproto.goproto_enum_prefix) = false; + + NIL = 0 [(gogoproto.enumvalue_customname) = "StatusNil"]; + DEPOSIT_PERIOD = 1 [(gogoproto.enumvalue_customname) = "StatusDepositPeriod"]; + VOTING_PERIOD = 2 [(gogoproto.enumvalue_customname) = "StatusVotingPeriod"]; + PASSED = 3 [(gogoproto.enumvalue_customname) = "StatusPassed"]; + REJECTED = 4 [(gogoproto.enumvalue_customname) = "StatusRejected"]; + FAILED = 5 [(gogoproto.enumvalue_customname) = "StatusFailed"]; } // TallyResult defines a standard tally for a proposal message TallyResult { - bytes yes = 1 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", (gogoproto.nullable) = false]; - bytes abstain = 2 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", (gogoproto.nullable) = false]; - bytes no = 3 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", (gogoproto.nullable) = false]; - bytes no_with_veto = 4 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", (gogoproto.nullable) = false - ,(gogoproto.moretags) = "yaml:\"no_with_veto\""]; + string yes = 1 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", (gogoproto.nullable) = false]; + string abstain = 2 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", (gogoproto.nullable) = false]; + string no = 3 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", (gogoproto.nullable) = false]; + string no_with_veto = 4 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false, + (gogoproto.moretags) = "yaml:\"no_with_veto\"" + ]; } +// Vote defines a vote on a governance proposal. A vote corresponds to a proposal +// ID, the voter, and the vote option. message Vote { - uint64 proposal_id = 1 [(gogoproto.customname) = "ProposalID" - ,(gogoproto.moretags) = "yaml:\"proposal_id\""]; - bytes voter = 2 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; - VoteOption option = 3; + uint64 proposal_id = 1 [(gogoproto.customname) = "ProposalID", (gogoproto.moretags) = "yaml:\"proposal_id\""]; + bytes voter = 2 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; + VoteOption option = 3; } -message BasicProposal { - ProposalBase base = 1 [(gogoproto.embed) = true]; - BasicContent content = 2; -} +// message BasicProposal { +// ProposalBase base = 1 [(gogoproto.embed) = true]; +// BasicContent content = 2; +// } -message BasicContent { - option (cosmos_proto.interface_type) = "Content"; - option (gogoproto.stringer) = true; - oneof sum { - TextProposal text = 1; - } -} +// message BasicContent { +// option (cosmos_proto.interface_type) = "Content"; +// option (gogoproto.stringer) = true; +// oneof sum { +// TextProposal text = 1; +// } +// } From 3fa47df519d3a5d4fb4b3b8599f7182bb8147d78 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 2 Mar 2020 15:52:43 +0100 Subject: [PATCH 301/529] migrate test TestDeposits from gov to simapp --- x/gov/keeper/common_test.go | 7 +++ x/gov/keeper/deposit_test.go | 60 ++++++++++--------- .../{test_common.go => old_test_common.go} | 0 3 files changed, 40 insertions(+), 27 deletions(-) create mode 100644 x/gov/keeper/common_test.go rename x/gov/keeper/{test_common.go => old_test_common.go} (100%) diff --git a/x/gov/keeper/common_test.go b/x/gov/keeper/common_test.go new file mode 100644 index 000000000000..66ab6db7d536 --- /dev/null +++ b/x/gov/keeper/common_test.go @@ -0,0 +1,7 @@ +package keeper_test + +import "github.com/cosmos/cosmos-sdk/x/gov/types" + +var ( + TestProposal = types.NewTextProposal("Test", "description") +) diff --git a/x/gov/keeper/deposit_test.go b/x/gov/keeper/deposit_test.go index ed17d4481551..12e152c0a0bd 100644 --- a/x/gov/keeper/deposit_test.go +++ b/x/gov/keeper/deposit_test.go @@ -1,4 +1,4 @@ -package keeper +package keeper_test import ( "testing" @@ -6,93 +6,99 @@ import ( "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" ) func TestDeposits(t *testing.T) { - ctx, _, bk, keeper, _, _ := createTestInput(t, false, 100) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + TestAddrs := simapp.AddTestAddrsIncremental(app, ctx, 2, sdk.NewInt(10000000)) tp := TestProposal - proposal, err := keeper.SubmitProposal(ctx, tp) + proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) require.NoError(t, err) proposalID := proposal.ProposalID fourStake := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(4))) fiveStake := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(5))) - addr0Initial := bk.GetAllBalances(ctx, TestAddrs[0]) - addr1Initial := bk.GetAllBalances(ctx, TestAddrs[1]) + addr0Initial := app.BankKeeper.GetAllBalances(ctx, TestAddrs[0]) + addr1Initial := app.BankKeeper.GetAllBalances(ctx, TestAddrs[1]) require.True(t, proposal.TotalDeposit.IsEqual(sdk.NewCoins())) // Check no deposits at beginning - deposit, found := keeper.GetDeposit(ctx, proposalID, TestAddrs[1]) + deposit, found := app.GovKeeper.GetDeposit(ctx, proposalID, TestAddrs[1]) require.False(t, found) - proposal, ok := keeper.GetProposal(ctx, proposalID) + proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID) require.True(t, ok) require.True(t, proposal.VotingStartTime.Equal(time.Time{})) // Check first deposit - votingStarted, err := keeper.AddDeposit(ctx, proposalID, TestAddrs[0], fourStake) + votingStarted, err := app.GovKeeper.AddDeposit(ctx, proposalID, TestAddrs[0], fourStake) require.NoError(t, err) require.False(t, votingStarted) - deposit, found = keeper.GetDeposit(ctx, proposalID, TestAddrs[0]) + deposit, found = app.GovKeeper.GetDeposit(ctx, proposalID, TestAddrs[0]) require.True(t, found) require.Equal(t, fourStake, deposit.Amount) require.Equal(t, TestAddrs[0], deposit.Depositor) - proposal, ok = keeper.GetProposal(ctx, proposalID) + proposal, ok = app.GovKeeper.GetProposal(ctx, proposalID) require.True(t, ok) require.Equal(t, fourStake, proposal.TotalDeposit) - require.Equal(t, addr0Initial.Sub(fourStake), bk.GetAllBalances(ctx, TestAddrs[0])) + require.Equal(t, addr0Initial.Sub(fourStake), app.BankKeeper.GetAllBalances(ctx, TestAddrs[0])) // Check a second deposit from same address - votingStarted, err = keeper.AddDeposit(ctx, proposalID, TestAddrs[0], fiveStake) + votingStarted, err = app.GovKeeper.AddDeposit(ctx, proposalID, TestAddrs[0], fiveStake) require.NoError(t, err) require.False(t, votingStarted) - deposit, found = keeper.GetDeposit(ctx, proposalID, TestAddrs[0]) + deposit, found = app.GovKeeper.GetDeposit(ctx, proposalID, TestAddrs[0]) require.True(t, found) require.Equal(t, fourStake.Add(fiveStake...), deposit.Amount) require.Equal(t, TestAddrs[0], deposit.Depositor) - proposal, ok = keeper.GetProposal(ctx, proposalID) + proposal, ok = app.GovKeeper.GetProposal(ctx, proposalID) require.True(t, ok) require.Equal(t, fourStake.Add(fiveStake...), proposal.TotalDeposit) - require.Equal(t, addr0Initial.Sub(fourStake).Sub(fiveStake), bk.GetAllBalances(ctx, TestAddrs[0])) + require.Equal(t, addr0Initial.Sub(fourStake).Sub(fiveStake), app.BankKeeper.GetAllBalances(ctx, TestAddrs[0])) // Check third deposit from a new address - votingStarted, err = keeper.AddDeposit(ctx, proposalID, TestAddrs[1], fourStake) + votingStarted, err = app.GovKeeper.AddDeposit(ctx, proposalID, TestAddrs[1], fourStake) require.NoError(t, err) require.True(t, votingStarted) - deposit, found = keeper.GetDeposit(ctx, proposalID, TestAddrs[1]) + deposit, found = app.GovKeeper.GetDeposit(ctx, proposalID, TestAddrs[1]) require.True(t, found) require.Equal(t, TestAddrs[1], deposit.Depositor) require.Equal(t, fourStake, deposit.Amount) - proposal, ok = keeper.GetProposal(ctx, proposalID) + proposal, ok = app.GovKeeper.GetProposal(ctx, proposalID) require.True(t, ok) require.Equal(t, fourStake.Add(fiveStake...).Add(fourStake...), proposal.TotalDeposit) - require.Equal(t, addr1Initial.Sub(fourStake), bk.GetAllBalances(ctx, TestAddrs[1])) + require.Equal(t, addr1Initial.Sub(fourStake), app.BankKeeper.GetAllBalances(ctx, TestAddrs[1])) // Check that proposal moved to voting period - proposal, ok = keeper.GetProposal(ctx, proposalID) + proposal, ok = app.GovKeeper.GetProposal(ctx, proposalID) require.True(t, ok) require.True(t, proposal.VotingStartTime.Equal(ctx.BlockHeader().Time)) // Test deposit iterator // NOTE order of deposits is determined by the addresses - deposits := keeper.GetAllDeposits(ctx) + deposits := app.GovKeeper.GetAllDeposits(ctx) require.Len(t, deposits, 2) - require.Equal(t, deposits, keeper.GetDeposits(ctx, proposalID)) + require.Equal(t, deposits, app.GovKeeper.GetDeposits(ctx, proposalID)) require.Equal(t, TestAddrs[0], deposits[0].Depositor) require.Equal(t, fourStake.Add(fiveStake...), deposits[0].Amount) require.Equal(t, TestAddrs[1], deposits[1].Depositor) require.Equal(t, fourStake, deposits[1].Amount) // Test Refund Deposits - deposit, found = keeper.GetDeposit(ctx, proposalID, TestAddrs[1]) + deposit, found = app.GovKeeper.GetDeposit(ctx, proposalID, TestAddrs[1]) require.True(t, found) require.Equal(t, fourStake, deposit.Amount) - keeper.RefundDeposits(ctx, proposalID) - deposit, found = keeper.GetDeposit(ctx, proposalID, TestAddrs[1]) + app.GovKeeper.RefundDeposits(ctx, proposalID) + deposit, found = app.GovKeeper.GetDeposit(ctx, proposalID, TestAddrs[1]) require.False(t, found) - require.Equal(t, addr0Initial, bk.GetAllBalances(ctx, TestAddrs[0])) - require.Equal(t, addr1Initial, bk.GetAllBalances(ctx, TestAddrs[1])) + require.Equal(t, addr0Initial, app.BankKeeper.GetAllBalances(ctx, TestAddrs[0])) + require.Equal(t, addr1Initial, app.BankKeeper.GetAllBalances(ctx, TestAddrs[1])) } diff --git a/x/gov/keeper/test_common.go b/x/gov/keeper/old_test_common.go similarity index 100% rename from x/gov/keeper/test_common.go rename to x/gov/keeper/old_test_common.go From 0c938123d93071b9de22c215d8e15a19f7c81234 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 2 Mar 2020 15:56:26 +0100 Subject: [PATCH 302/529] migrate TestIncrementProposalNumber to simap --- x/gov/keeper/keeper_test.go | 49 ++++++++------------------------- x/gov/keeper/old_keeper_test.go | 36 ++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 37 deletions(-) create mode 100644 x/gov/keeper/old_keeper_test.go diff --git a/x/gov/keeper/keeper_test.go b/x/gov/keeper/keeper_test.go index 9cd2a0559e65..e824760d1cc0 100644 --- a/x/gov/keeper/keeper_test.go +++ b/x/gov/keeper/keeper_test.go @@ -1,51 +1,26 @@ -package keeper +package keeper_test import ( "testing" - "github.com/stretchr/testify/require" + "github.com/cosmos/cosmos-sdk/simapp" + abci "github.com/tendermint/tendermint/abci/types" - "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/stretchr/testify/require" ) func TestIncrementProposalNumber(t *testing.T) { - ctx, _, _, keeper, _, _ := createTestInput(t, false, 100) // nolint: dogsled + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) tp := TestProposal - keeper.SubmitProposal(ctx, tp) - keeper.SubmitProposal(ctx, tp) - keeper.SubmitProposal(ctx, tp) - keeper.SubmitProposal(ctx, tp) - keeper.SubmitProposal(ctx, tp) - proposal6, err := keeper.SubmitProposal(ctx, tp) + app.GovKeeper.SubmitProposal(ctx, tp) + app.GovKeeper.SubmitProposal(ctx, tp) + app.GovKeeper.SubmitProposal(ctx, tp) + app.GovKeeper.SubmitProposal(ctx, tp) + app.GovKeeper.SubmitProposal(ctx, tp) + proposal6, err := app.GovKeeper.SubmitProposal(ctx, tp) require.NoError(t, err) require.Equal(t, uint64(6), proposal6.ProposalID) } - -func TestProposalQueues(t *testing.T) { - ctx, _, _, keeper, _, _ := createTestInput(t, false, 100) // nolint: dogsled - - // create test proposals - tp := TestProposal - proposal, err := keeper.SubmitProposal(ctx, tp) - require.NoError(t, err) - - inactiveIterator := keeper.InactiveProposalQueueIterator(ctx, proposal.DepositEndTime) - require.True(t, inactiveIterator.Valid()) - - proposalID := types.GetProposalIDFromBytes(inactiveIterator.Value()) - require.Equal(t, proposalID, proposal.ProposalID) - inactiveIterator.Close() - - keeper.activateVotingPeriod(ctx, proposal) - - proposal, ok := keeper.GetProposal(ctx, proposal.ProposalID) - require.True(t, ok) - - activeIterator := keeper.ActiveProposalQueueIterator(ctx, proposal.VotingEndTime) - require.True(t, activeIterator.Valid()) - keeper.cdc.UnmarshalBinaryLengthPrefixed(activeIterator.Value(), &proposalID) - require.Equal(t, proposalID, proposal.ProposalID) - activeIterator.Close() -} diff --git a/x/gov/keeper/old_keeper_test.go b/x/gov/keeper/old_keeper_test.go new file mode 100644 index 000000000000..4b21f3eac600 --- /dev/null +++ b/x/gov/keeper/old_keeper_test.go @@ -0,0 +1,36 @@ +package keeper + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/x/gov/types" +) + +func TestProposalQueues(t *testing.T) { + ctx, _, _, keeper, _, _ := createTestInput(t, false, 100) // nolint: dogsled + + // create test proposals + tp := TestProposal + proposal, err := keeper.SubmitProposal(ctx, tp) + require.NoError(t, err) + + inactiveIterator := keeper.InactiveProposalQueueIterator(ctx, proposal.DepositEndTime) + require.True(t, inactiveIterator.Valid()) + + proposalID := types.GetProposalIDFromBytes(inactiveIterator.Value()) + require.Equal(t, proposalID, proposal.ProposalID) + inactiveIterator.Close() + + keeper.activateVotingPeriod(ctx, proposal) + + proposal, ok := keeper.GetProposal(ctx, proposal.ProposalID) + require.True(t, ok) + + activeIterator := keeper.ActiveProposalQueueIterator(ctx, proposal.VotingEndTime) + require.True(t, activeIterator.Valid()) + keeper.cdc.UnmarshalBinaryLengthPrefixed(activeIterator.Value(), &proposalID) + require.Equal(t, proposalID, proposal.ProposalID) + activeIterator.Close() +} From 2afd22f37ec48f0e95d585835acd1a91a129fd0a Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 2 Mar 2020 15:59:55 +0100 Subject: [PATCH 303/529] migrate TestProposalQueues to use simapp --- x/gov/keeper/deposit.go | 2 +- x/gov/keeper/keeper_test.go | 30 +++++++++++++++++++++++++++ x/gov/keeper/old_keeper_test.go | 36 --------------------------------- x/gov/keeper/proposal.go | 2 +- x/gov/keeper/proposal_test.go | 2 +- 5 files changed, 33 insertions(+), 39 deletions(-) delete mode 100644 x/gov/keeper/old_keeper_test.go diff --git a/x/gov/keeper/deposit.go b/x/gov/keeper/deposit.go index 423679998b44..4fcf2639048d 100644 --- a/x/gov/keeper/deposit.go +++ b/x/gov/keeper/deposit.go @@ -119,7 +119,7 @@ func (keeper Keeper) AddDeposit(ctx sdk.Context, proposalID uint64, depositorAdd // Check if deposit has provided sufficient total funds to transition the proposal into the voting period activatedVotingPeriod := false if proposal.Status == types.StatusDepositPeriod && proposal.TotalDeposit.IsAllGTE(keeper.GetDepositParams(ctx).MinDeposit) { - keeper.activateVotingPeriod(ctx, proposal) + keeper.ActivateVotingPeriod(ctx, proposal) activatedVotingPeriod = true } diff --git a/x/gov/keeper/keeper_test.go b/x/gov/keeper/keeper_test.go index e824760d1cc0..0d2f424dd168 100644 --- a/x/gov/keeper/keeper_test.go +++ b/x/gov/keeper/keeper_test.go @@ -3,6 +3,8 @@ package keeper_test import ( "testing" + "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/cosmos/cosmos-sdk/simapp" abci "github.com/tendermint/tendermint/abci/types" @@ -24,3 +26,31 @@ func TestIncrementProposalNumber(t *testing.T) { require.Equal(t, uint64(6), proposal6.ProposalID) } + +func TestProposalQueues(t *testing.T) { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + // create test proposals + tp := TestProposal + proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) + require.NoError(t, err) + + inactiveIterator := app.GovKeeper.InactiveProposalQueueIterator(ctx, proposal.DepositEndTime) + require.True(t, inactiveIterator.Valid()) + + proposalID := types.GetProposalIDFromBytes(inactiveIterator.Value()) + require.Equal(t, proposalID, proposal.ProposalID) + inactiveIterator.Close() + + app.GovKeeper.ActivateVotingPeriod(ctx, proposal) + + proposal, ok := app.GovKeeper.GetProposal(ctx, proposal.ProposalID) + require.True(t, ok) + + activeIterator := app.GovKeeper.ActiveProposalQueueIterator(ctx, proposal.VotingEndTime) + require.True(t, activeIterator.Valid()) + app.Codec().UnmarshalBinaryLengthPrefixed(activeIterator.Value(), &proposalID) + require.Equal(t, proposalID, proposal.ProposalID) + activeIterator.Close() +} diff --git a/x/gov/keeper/old_keeper_test.go b/x/gov/keeper/old_keeper_test.go deleted file mode 100644 index 4b21f3eac600..000000000000 --- a/x/gov/keeper/old_keeper_test.go +++ /dev/null @@ -1,36 +0,0 @@ -package keeper - -import ( - "testing" - - "github.com/stretchr/testify/require" - - "github.com/cosmos/cosmos-sdk/x/gov/types" -) - -func TestProposalQueues(t *testing.T) { - ctx, _, _, keeper, _, _ := createTestInput(t, false, 100) // nolint: dogsled - - // create test proposals - tp := TestProposal - proposal, err := keeper.SubmitProposal(ctx, tp) - require.NoError(t, err) - - inactiveIterator := keeper.InactiveProposalQueueIterator(ctx, proposal.DepositEndTime) - require.True(t, inactiveIterator.Valid()) - - proposalID := types.GetProposalIDFromBytes(inactiveIterator.Value()) - require.Equal(t, proposalID, proposal.ProposalID) - inactiveIterator.Close() - - keeper.activateVotingPeriod(ctx, proposal) - - proposal, ok := keeper.GetProposal(ctx, proposal.ProposalID) - require.True(t, ok) - - activeIterator := keeper.ActiveProposalQueueIterator(ctx, proposal.VotingEndTime) - require.True(t, activeIterator.Valid()) - keeper.cdc.UnmarshalBinaryLengthPrefixed(activeIterator.Value(), &proposalID) - require.Equal(t, proposalID, proposal.ProposalID) - activeIterator.Close() -} diff --git a/x/gov/keeper/proposal.go b/x/gov/keeper/proposal.go index c5d569314fb2..70435ea58357 100644 --- a/x/gov/keeper/proposal.go +++ b/x/gov/keeper/proposal.go @@ -167,7 +167,7 @@ func (keeper Keeper) SetProposalID(ctx sdk.Context, proposalID uint64) { store.Set(types.ProposalIDKey, types.GetProposalIDBytes(proposalID)) } -func (keeper Keeper) activateVotingPeriod(ctx sdk.Context, proposal types.Proposal) { +func (keeper Keeper) ActivateVotingPeriod(ctx sdk.Context, proposal types.Proposal) { proposal.VotingStartTime = ctx.BlockHeader().Time votingPeriod := keeper.GetVotingParams(ctx).VotingPeriod proposal.VotingEndTime = proposal.VotingStartTime.Add(votingPeriod) diff --git a/x/gov/keeper/proposal_test.go b/x/gov/keeper/proposal_test.go index 5848e0d753e9..ca345ad9f6fd 100644 --- a/x/gov/keeper/proposal_test.go +++ b/x/gov/keeper/proposal_test.go @@ -36,7 +36,7 @@ func TestActivateVotingPeriod(t *testing.T) { require.True(t, proposal.VotingStartTime.Equal(time.Time{})) - keeper.activateVotingPeriod(ctx, proposal) + keeper.ActivateVotingPeriod(ctx, proposal) require.True(t, proposal.VotingStartTime.Equal(ctx.BlockHeader().Time)) From eedd2b2341562e1ae83ac67d478bd93d676e4f29 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 2 Mar 2020 16:04:49 +0100 Subject: [PATCH 304/529] migrate part of proposal to simapp --- x/gov/keeper/common_test.go | 12 ++- x/gov/keeper/keeper_test.go | 6 +- x/gov/keeper/old_proposal_test.go | 164 ++++++++++++++++++++++++++++ x/gov/keeper/proposal_test.go | 170 ++---------------------------- 4 files changed, 187 insertions(+), 165 deletions(-) create mode 100644 x/gov/keeper/old_proposal_test.go diff --git a/x/gov/keeper/common_test.go b/x/gov/keeper/common_test.go index 66ab6db7d536..e4c48463f51d 100644 --- a/x/gov/keeper/common_test.go +++ b/x/gov/keeper/common_test.go @@ -1,7 +1,17 @@ package keeper_test -import "github.com/cosmos/cosmos-sdk/x/gov/types" +import ( + "bytes" + + "github.com/cosmos/cosmos-sdk/x/gov/types" +) var ( TestProposal = types.NewTextProposal("Test", "description") ) + +// ProposalEqual checks if two proposals are equal (note: slow, for tests only) +func ProposalEqual(proposalA types.Proposal, proposalB types.Proposal) bool { + return bytes.Equal(types.ModuleCdc.MustMarshalBinaryBare(proposalA), + types.ModuleCdc.MustMarshalBinaryBare(proposalB)) +} diff --git a/x/gov/keeper/keeper_test.go b/x/gov/keeper/keeper_test.go index 0d2f424dd168..b03bd1d117e7 100644 --- a/x/gov/keeper/keeper_test.go +++ b/x/gov/keeper/keeper_test.go @@ -3,12 +3,12 @@ package keeper_test import ( "testing" - "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/stretchr/testify/require" - "github.com/cosmos/cosmos-sdk/simapp" abci "github.com/tendermint/tendermint/abci/types" - "github.com/stretchr/testify/require" + "github.com/cosmos/cosmos-sdk/simapp" + "github.com/cosmos/cosmos-sdk/x/gov/types" ) func TestIncrementProposalNumber(t *testing.T) { diff --git a/x/gov/keeper/old_proposal_test.go b/x/gov/keeper/old_proposal_test.go new file mode 100644 index 000000000000..e65126df5d27 --- /dev/null +++ b/x/gov/keeper/old_proposal_test.go @@ -0,0 +1,164 @@ +package keeper + +import ( + "errors" + "strings" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/gov/types" +) + +func TestActivateVotingPeriod(t *testing.T) { + ctx, _, _, keeper, _, _ := createTestInput(t, false, 100) // nolint: dogsled + + tp := TestProposal + proposal, err := keeper.SubmitProposal(ctx, tp) + require.NoError(t, err) + + require.True(t, proposal.VotingStartTime.Equal(time.Time{})) + + keeper.ActivateVotingPeriod(ctx, proposal) + + require.True(t, proposal.VotingStartTime.Equal(ctx.BlockHeader().Time)) + + proposal, ok := keeper.GetProposal(ctx, proposal.ProposalID) + require.True(t, ok) + + activeIterator := keeper.ActiveProposalQueueIterator(ctx, proposal.VotingEndTime) + require.True(t, activeIterator.Valid()) + + proposalID := types.GetProposalIDFromBytes(activeIterator.Value()) + require.Equal(t, proposalID, proposal.ProposalID) + activeIterator.Close() +} + +type validProposal struct{} + +func (validProposal) GetTitle() string { return "title" } +func (validProposal) GetDescription() string { return "description" } +func (validProposal) ProposalRoute() string { return types.RouterKey } +func (validProposal) ProposalType() string { return types.ProposalTypeText } +func (validProposal) String() string { return "" } +func (validProposal) ValidateBasic() error { return nil } + +type invalidProposalTitle1 struct{ validProposal } + +func (invalidProposalTitle1) GetTitle() string { return "" } + +type invalidProposalTitle2 struct{ validProposal } + +func (invalidProposalTitle2) GetTitle() string { return strings.Repeat("1234567890", 100) } + +type invalidProposalDesc1 struct{ validProposal } + +func (invalidProposalDesc1) GetDescription() string { return "" } + +type invalidProposalDesc2 struct{ validProposal } + +func (invalidProposalDesc2) GetDescription() string { return strings.Repeat("1234567890", 1000) } + +type invalidProposalRoute struct{ validProposal } + +func (invalidProposalRoute) ProposalRoute() string { return "nonexistingroute" } + +type invalidProposalValidation struct{ validProposal } + +func (invalidProposalValidation) ValidateBasic() error { + return errors.New("invalid proposal") +} + +func registerTestCodec(cdc *codec.Codec) { + cdc.RegisterConcrete(validProposal{}, "test/validproposal", nil) + cdc.RegisterConcrete(invalidProposalTitle1{}, "test/invalidproposalt1", nil) + cdc.RegisterConcrete(invalidProposalTitle2{}, "test/invalidproposalt2", nil) + cdc.RegisterConcrete(invalidProposalDesc1{}, "test/invalidproposald1", nil) + cdc.RegisterConcrete(invalidProposalDesc2{}, "test/invalidproposald2", nil) + cdc.RegisterConcrete(invalidProposalRoute{}, "test/invalidproposalr", nil) + cdc.RegisterConcrete(invalidProposalValidation{}, "test/invalidproposalv", nil) +} + +func TestSubmitProposal(t *testing.T) { + ctx, _, _, keeper, _, _ := createTestInput(t, false, 100) // nolint: dogsled + + registerTestCodec(keeper.cdc) + + testCases := []struct { + content types.Content + expectedErr error + }{ + {validProposal{}, nil}, + // Keeper does not check the validity of title and description, no error + {invalidProposalTitle1{}, nil}, + {invalidProposalTitle2{}, nil}, + {invalidProposalDesc1{}, nil}, + {invalidProposalDesc2{}, nil}, + // error only when invalid route + {invalidProposalRoute{}, types.ErrNoProposalHandlerExists}, + // Keeper does not call ValidateBasic, msg.ValidateBasic does + {invalidProposalValidation{}, nil}, + } + + for i, tc := range testCases { + _, err := keeper.SubmitProposal(ctx, tc.content) + require.True(t, errors.Is(tc.expectedErr, err), "tc #%d; got: %v, expected: %v", i, err, tc.expectedErr) + } +} + +func TestGetProposalsFiltered(t *testing.T) { + proposalID := uint64(1) + ctx, _, _, keeper, _, _ := createTestInput(t, false, 100) // nolint: dogsled + status := []types.ProposalStatus{types.StatusDepositPeriod, types.StatusVotingPeriod} + + addr1 := sdk.AccAddress("foo") + + for _, s := range status { + for i := 0; i < 50; i++ { + p := types.NewProposal(TestProposal, proposalID, time.Now(), time.Now()) + p.Status = s + + if i%2 == 0 { + d := types.NewDeposit(proposalID, addr1, nil) + v := types.NewVote(proposalID, addr1, types.OptionYes) + keeper.SetDeposit(ctx, d) + keeper.SetVote(ctx, v) + } + + keeper.SetProposal(ctx, p) + proposalID++ + } + } + + testCases := []struct { + params types.QueryProposalsParams + expectedNumResults int + }{ + {types.NewQueryProposalsParams(1, 50, types.StatusNil, nil, nil), 50}, + {types.NewQueryProposalsParams(1, 50, types.StatusDepositPeriod, nil, nil), 50}, + {types.NewQueryProposalsParams(1, 50, types.StatusVotingPeriod, nil, nil), 50}, + {types.NewQueryProposalsParams(1, 25, types.StatusNil, nil, nil), 25}, + {types.NewQueryProposalsParams(2, 25, types.StatusNil, nil, nil), 25}, + {types.NewQueryProposalsParams(1, 50, types.StatusRejected, nil, nil), 0}, + {types.NewQueryProposalsParams(1, 50, types.StatusNil, addr1, nil), 50}, + {types.NewQueryProposalsParams(1, 50, types.StatusNil, nil, addr1), 50}, + {types.NewQueryProposalsParams(1, 50, types.StatusNil, addr1, addr1), 50}, + {types.NewQueryProposalsParams(1, 50, types.StatusDepositPeriod, addr1, addr1), 25}, + {types.NewQueryProposalsParams(1, 50, types.StatusDepositPeriod, nil, nil), 50}, + {types.NewQueryProposalsParams(1, 50, types.StatusVotingPeriod, nil, nil), 50}, + } + + for _, tc := range testCases { + proposals := keeper.GetProposalsFiltered(ctx, tc.params) + require.Len(t, proposals, tc.expectedNumResults) + + for _, p := range proposals { + if len(tc.params.ProposalStatus.String()) != 0 { + require.Equal(t, tc.params.ProposalStatus, p.Status) + } + } + } +} diff --git a/x/gov/keeper/proposal_test.go b/x/gov/keeper/proposal_test.go index ca345ad9f6fd..1158e54dc3f4 100644 --- a/x/gov/keeper/proposal_test.go +++ b/x/gov/keeper/proposal_test.go @@ -1,178 +1,26 @@ -package keeper +package keeper_test import ( - "errors" - "strings" "testing" - "time" "github.com/stretchr/testify/require" - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/gov/types" + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/simapp" ) func TestGetSetProposal(t *testing.T) { - ctx, _, _, keeper, _, _ := createTestInput(t, false, 100) // nolint: dogsled + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) tp := TestProposal - proposal, err := keeper.SubmitProposal(ctx, tp) + proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) require.NoError(t, err) proposalID := proposal.ProposalID - keeper.SetProposal(ctx, proposal) + app.GovKeeper.SetProposal(ctx, proposal) - gotProposal, ok := keeper.GetProposal(ctx, proposalID) + gotProposal, ok := app.GovKeeper.GetProposal(ctx, proposalID) require.True(t, ok) require.True(t, ProposalEqual(proposal, gotProposal)) } - -func TestActivateVotingPeriod(t *testing.T) { - ctx, _, _, keeper, _, _ := createTestInput(t, false, 100) // nolint: dogsled - - tp := TestProposal - proposal, err := keeper.SubmitProposal(ctx, tp) - require.NoError(t, err) - - require.True(t, proposal.VotingStartTime.Equal(time.Time{})) - - keeper.ActivateVotingPeriod(ctx, proposal) - - require.True(t, proposal.VotingStartTime.Equal(ctx.BlockHeader().Time)) - - proposal, ok := keeper.GetProposal(ctx, proposal.ProposalID) - require.True(t, ok) - - activeIterator := keeper.ActiveProposalQueueIterator(ctx, proposal.VotingEndTime) - require.True(t, activeIterator.Valid()) - - proposalID := types.GetProposalIDFromBytes(activeIterator.Value()) - require.Equal(t, proposalID, proposal.ProposalID) - activeIterator.Close() -} - -type validProposal struct{} - -func (validProposal) GetTitle() string { return "title" } -func (validProposal) GetDescription() string { return "description" } -func (validProposal) ProposalRoute() string { return types.RouterKey } -func (validProposal) ProposalType() string { return types.ProposalTypeText } -func (validProposal) String() string { return "" } -func (validProposal) ValidateBasic() error { return nil } - -type invalidProposalTitle1 struct{ validProposal } - -func (invalidProposalTitle1) GetTitle() string { return "" } - -type invalidProposalTitle2 struct{ validProposal } - -func (invalidProposalTitle2) GetTitle() string { return strings.Repeat("1234567890", 100) } - -type invalidProposalDesc1 struct{ validProposal } - -func (invalidProposalDesc1) GetDescription() string { return "" } - -type invalidProposalDesc2 struct{ validProposal } - -func (invalidProposalDesc2) GetDescription() string { return strings.Repeat("1234567890", 1000) } - -type invalidProposalRoute struct{ validProposal } - -func (invalidProposalRoute) ProposalRoute() string { return "nonexistingroute" } - -type invalidProposalValidation struct{ validProposal } - -func (invalidProposalValidation) ValidateBasic() error { - return errors.New("invalid proposal") -} - -func registerTestCodec(cdc *codec.Codec) { - cdc.RegisterConcrete(validProposal{}, "test/validproposal", nil) - cdc.RegisterConcrete(invalidProposalTitle1{}, "test/invalidproposalt1", nil) - cdc.RegisterConcrete(invalidProposalTitle2{}, "test/invalidproposalt2", nil) - cdc.RegisterConcrete(invalidProposalDesc1{}, "test/invalidproposald1", nil) - cdc.RegisterConcrete(invalidProposalDesc2{}, "test/invalidproposald2", nil) - cdc.RegisterConcrete(invalidProposalRoute{}, "test/invalidproposalr", nil) - cdc.RegisterConcrete(invalidProposalValidation{}, "test/invalidproposalv", nil) -} - -func TestSubmitProposal(t *testing.T) { - ctx, _, _, keeper, _, _ := createTestInput(t, false, 100) // nolint: dogsled - - registerTestCodec(keeper.cdc) - - testCases := []struct { - content types.Content - expectedErr error - }{ - {validProposal{}, nil}, - // Keeper does not check the validity of title and description, no error - {invalidProposalTitle1{}, nil}, - {invalidProposalTitle2{}, nil}, - {invalidProposalDesc1{}, nil}, - {invalidProposalDesc2{}, nil}, - // error only when invalid route - {invalidProposalRoute{}, types.ErrNoProposalHandlerExists}, - // Keeper does not call ValidateBasic, msg.ValidateBasic does - {invalidProposalValidation{}, nil}, - } - - for i, tc := range testCases { - _, err := keeper.SubmitProposal(ctx, tc.content) - require.True(t, errors.Is(tc.expectedErr, err), "tc #%d; got: %v, expected: %v", i, err, tc.expectedErr) - } -} - -func TestGetProposalsFiltered(t *testing.T) { - proposalID := uint64(1) - ctx, _, _, keeper, _, _ := createTestInput(t, false, 100) // nolint: dogsled - status := []types.ProposalStatus{types.StatusDepositPeriod, types.StatusVotingPeriod} - - addr1 := sdk.AccAddress("foo") - - for _, s := range status { - for i := 0; i < 50; i++ { - p := types.NewProposal(TestProposal, proposalID, time.Now(), time.Now()) - p.Status = s - - if i%2 == 0 { - d := types.NewDeposit(proposalID, addr1, nil) - v := types.NewVote(proposalID, addr1, types.OptionYes) - keeper.SetDeposit(ctx, d) - keeper.SetVote(ctx, v) - } - - keeper.SetProposal(ctx, p) - proposalID++ - } - } - - testCases := []struct { - params types.QueryProposalsParams - expectedNumResults int - }{ - {types.NewQueryProposalsParams(1, 50, types.StatusNil, nil, nil), 50}, - {types.NewQueryProposalsParams(1, 50, types.StatusDepositPeriod, nil, nil), 50}, - {types.NewQueryProposalsParams(1, 50, types.StatusVotingPeriod, nil, nil), 50}, - {types.NewQueryProposalsParams(1, 25, types.StatusNil, nil, nil), 25}, - {types.NewQueryProposalsParams(2, 25, types.StatusNil, nil, nil), 25}, - {types.NewQueryProposalsParams(1, 50, types.StatusRejected, nil, nil), 0}, - {types.NewQueryProposalsParams(1, 50, types.StatusNil, addr1, nil), 50}, - {types.NewQueryProposalsParams(1, 50, types.StatusNil, nil, addr1), 50}, - {types.NewQueryProposalsParams(1, 50, types.StatusNil, addr1, addr1), 50}, - {types.NewQueryProposalsParams(1, 50, types.StatusDepositPeriod, addr1, addr1), 25}, - {types.NewQueryProposalsParams(1, 50, types.StatusDepositPeriod, nil, nil), 50}, - {types.NewQueryProposalsParams(1, 50, types.StatusVotingPeriod, nil, nil), 50}, - } - - for _, tc := range testCases { - proposals := keeper.GetProposalsFiltered(ctx, tc.params) - require.Len(t, proposals, tc.expectedNumResults) - - for _, p := range proposals { - if len(tc.params.ProposalStatus.String()) != 0 { - require.Equal(t, tc.params.ProposalStatus, p.Status) - } - } - } -} From 00396145d518646f3d72824be00ad54b424f0263 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 2 Mar 2020 16:07:23 +0100 Subject: [PATCH 305/529] migrate TestActivateVotingPeriod to simapp --- x/gov/keeper/old_proposal_test.go | 24 ------------------------ x/gov/keeper/proposal_test.go | 27 +++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 24 deletions(-) diff --git a/x/gov/keeper/old_proposal_test.go b/x/gov/keeper/old_proposal_test.go index e65126df5d27..1ddfa916d694 100644 --- a/x/gov/keeper/old_proposal_test.go +++ b/x/gov/keeper/old_proposal_test.go @@ -13,30 +13,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/gov/types" ) -func TestActivateVotingPeriod(t *testing.T) { - ctx, _, _, keeper, _, _ := createTestInput(t, false, 100) // nolint: dogsled - - tp := TestProposal - proposal, err := keeper.SubmitProposal(ctx, tp) - require.NoError(t, err) - - require.True(t, proposal.VotingStartTime.Equal(time.Time{})) - - keeper.ActivateVotingPeriod(ctx, proposal) - - require.True(t, proposal.VotingStartTime.Equal(ctx.BlockHeader().Time)) - - proposal, ok := keeper.GetProposal(ctx, proposal.ProposalID) - require.True(t, ok) - - activeIterator := keeper.ActiveProposalQueueIterator(ctx, proposal.VotingEndTime) - require.True(t, activeIterator.Valid()) - - proposalID := types.GetProposalIDFromBytes(activeIterator.Value()) - require.Equal(t, proposalID, proposal.ProposalID) - activeIterator.Close() -} - type validProposal struct{} func (validProposal) GetTitle() string { return "title" } diff --git a/x/gov/keeper/proposal_test.go b/x/gov/keeper/proposal_test.go index 1158e54dc3f4..4b6df06e5922 100644 --- a/x/gov/keeper/proposal_test.go +++ b/x/gov/keeper/proposal_test.go @@ -2,12 +2,14 @@ package keeper_test import ( "testing" + "time" "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/simapp" + "github.com/cosmos/cosmos-sdk/x/gov/types" ) func TestGetSetProposal(t *testing.T) { @@ -24,3 +26,28 @@ func TestGetSetProposal(t *testing.T) { require.True(t, ok) require.True(t, ProposalEqual(proposal, gotProposal)) } + +func TestActivateVotingPeriod(t *testing.T) { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + tp := TestProposal + proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) + require.NoError(t, err) + + require.True(t, proposal.VotingStartTime.Equal(time.Time{})) + + app.GovKeeper.ActivateVotingPeriod(ctx, proposal) + + require.True(t, proposal.VotingStartTime.Equal(ctx.BlockHeader().Time)) + + proposal, ok := app.GovKeeper.GetProposal(ctx, proposal.ProposalID) + require.True(t, ok) + + activeIterator := app.GovKeeper.ActiveProposalQueueIterator(ctx, proposal.VotingEndTime) + require.True(t, activeIterator.Valid()) + + proposalID := types.GetProposalIDFromBytes(activeIterator.Value()) + require.Equal(t, proposalID, proposal.ProposalID) + activeIterator.Close() +} From 2c231e2fa0011379035bcccafa57a248c09828fc Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 2 Mar 2020 16:10:19 +0100 Subject: [PATCH 306/529] TestGetProposalsFiltered migrate to simapp --- x/gov/keeper/old_proposal_test.go | 140 ------------------------------ x/gov/keeper/proposal_test.go | 134 ++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+), 140 deletions(-) delete mode 100644 x/gov/keeper/old_proposal_test.go diff --git a/x/gov/keeper/old_proposal_test.go b/x/gov/keeper/old_proposal_test.go deleted file mode 100644 index 1ddfa916d694..000000000000 --- a/x/gov/keeper/old_proposal_test.go +++ /dev/null @@ -1,140 +0,0 @@ -package keeper - -import ( - "errors" - "strings" - "testing" - "time" - - "github.com/stretchr/testify/require" - - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/gov/types" -) - -type validProposal struct{} - -func (validProposal) GetTitle() string { return "title" } -func (validProposal) GetDescription() string { return "description" } -func (validProposal) ProposalRoute() string { return types.RouterKey } -func (validProposal) ProposalType() string { return types.ProposalTypeText } -func (validProposal) String() string { return "" } -func (validProposal) ValidateBasic() error { return nil } - -type invalidProposalTitle1 struct{ validProposal } - -func (invalidProposalTitle1) GetTitle() string { return "" } - -type invalidProposalTitle2 struct{ validProposal } - -func (invalidProposalTitle2) GetTitle() string { return strings.Repeat("1234567890", 100) } - -type invalidProposalDesc1 struct{ validProposal } - -func (invalidProposalDesc1) GetDescription() string { return "" } - -type invalidProposalDesc2 struct{ validProposal } - -func (invalidProposalDesc2) GetDescription() string { return strings.Repeat("1234567890", 1000) } - -type invalidProposalRoute struct{ validProposal } - -func (invalidProposalRoute) ProposalRoute() string { return "nonexistingroute" } - -type invalidProposalValidation struct{ validProposal } - -func (invalidProposalValidation) ValidateBasic() error { - return errors.New("invalid proposal") -} - -func registerTestCodec(cdc *codec.Codec) { - cdc.RegisterConcrete(validProposal{}, "test/validproposal", nil) - cdc.RegisterConcrete(invalidProposalTitle1{}, "test/invalidproposalt1", nil) - cdc.RegisterConcrete(invalidProposalTitle2{}, "test/invalidproposalt2", nil) - cdc.RegisterConcrete(invalidProposalDesc1{}, "test/invalidproposald1", nil) - cdc.RegisterConcrete(invalidProposalDesc2{}, "test/invalidproposald2", nil) - cdc.RegisterConcrete(invalidProposalRoute{}, "test/invalidproposalr", nil) - cdc.RegisterConcrete(invalidProposalValidation{}, "test/invalidproposalv", nil) -} - -func TestSubmitProposal(t *testing.T) { - ctx, _, _, keeper, _, _ := createTestInput(t, false, 100) // nolint: dogsled - - registerTestCodec(keeper.cdc) - - testCases := []struct { - content types.Content - expectedErr error - }{ - {validProposal{}, nil}, - // Keeper does not check the validity of title and description, no error - {invalidProposalTitle1{}, nil}, - {invalidProposalTitle2{}, nil}, - {invalidProposalDesc1{}, nil}, - {invalidProposalDesc2{}, nil}, - // error only when invalid route - {invalidProposalRoute{}, types.ErrNoProposalHandlerExists}, - // Keeper does not call ValidateBasic, msg.ValidateBasic does - {invalidProposalValidation{}, nil}, - } - - for i, tc := range testCases { - _, err := keeper.SubmitProposal(ctx, tc.content) - require.True(t, errors.Is(tc.expectedErr, err), "tc #%d; got: %v, expected: %v", i, err, tc.expectedErr) - } -} - -func TestGetProposalsFiltered(t *testing.T) { - proposalID := uint64(1) - ctx, _, _, keeper, _, _ := createTestInput(t, false, 100) // nolint: dogsled - status := []types.ProposalStatus{types.StatusDepositPeriod, types.StatusVotingPeriod} - - addr1 := sdk.AccAddress("foo") - - for _, s := range status { - for i := 0; i < 50; i++ { - p := types.NewProposal(TestProposal, proposalID, time.Now(), time.Now()) - p.Status = s - - if i%2 == 0 { - d := types.NewDeposit(proposalID, addr1, nil) - v := types.NewVote(proposalID, addr1, types.OptionYes) - keeper.SetDeposit(ctx, d) - keeper.SetVote(ctx, v) - } - - keeper.SetProposal(ctx, p) - proposalID++ - } - } - - testCases := []struct { - params types.QueryProposalsParams - expectedNumResults int - }{ - {types.NewQueryProposalsParams(1, 50, types.StatusNil, nil, nil), 50}, - {types.NewQueryProposalsParams(1, 50, types.StatusDepositPeriod, nil, nil), 50}, - {types.NewQueryProposalsParams(1, 50, types.StatusVotingPeriod, nil, nil), 50}, - {types.NewQueryProposalsParams(1, 25, types.StatusNil, nil, nil), 25}, - {types.NewQueryProposalsParams(2, 25, types.StatusNil, nil, nil), 25}, - {types.NewQueryProposalsParams(1, 50, types.StatusRejected, nil, nil), 0}, - {types.NewQueryProposalsParams(1, 50, types.StatusNil, addr1, nil), 50}, - {types.NewQueryProposalsParams(1, 50, types.StatusNil, nil, addr1), 50}, - {types.NewQueryProposalsParams(1, 50, types.StatusNil, addr1, addr1), 50}, - {types.NewQueryProposalsParams(1, 50, types.StatusDepositPeriod, addr1, addr1), 25}, - {types.NewQueryProposalsParams(1, 50, types.StatusDepositPeriod, nil, nil), 50}, - {types.NewQueryProposalsParams(1, 50, types.StatusVotingPeriod, nil, nil), 50}, - } - - for _, tc := range testCases { - proposals := keeper.GetProposalsFiltered(ctx, tc.params) - require.Len(t, proposals, tc.expectedNumResults) - - for _, p := range proposals { - if len(tc.params.ProposalStatus.String()) != 0 { - require.Equal(t, tc.params.ProposalStatus, p.Status) - } - } - } -} diff --git a/x/gov/keeper/proposal_test.go b/x/gov/keeper/proposal_test.go index 4b6df06e5922..41bc35aabdec 100644 --- a/x/gov/keeper/proposal_test.go +++ b/x/gov/keeper/proposal_test.go @@ -1,13 +1,18 @@ package keeper_test import ( + "errors" + "strings" "testing" "time" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" + "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/simapp" "github.com/cosmos/cosmos-sdk/x/gov/types" ) @@ -51,3 +56,132 @@ func TestActivateVotingPeriod(t *testing.T) { require.Equal(t, proposalID, proposal.ProposalID) activeIterator.Close() } + +type validProposal struct{} + +func (validProposal) GetTitle() string { return "title" } +func (validProposal) GetDescription() string { return "description" } +func (validProposal) ProposalRoute() string { return types.RouterKey } +func (validProposal) ProposalType() string { return types.ProposalTypeText } +func (validProposal) String() string { return "" } +func (validProposal) ValidateBasic() error { return nil } + +type invalidProposalTitle1 struct{ validProposal } + +func (invalidProposalTitle1) GetTitle() string { return "" } + +type invalidProposalTitle2 struct{ validProposal } + +func (invalidProposalTitle2) GetTitle() string { return strings.Repeat("1234567890", 100) } + +type invalidProposalDesc1 struct{ validProposal } + +func (invalidProposalDesc1) GetDescription() string { return "" } + +type invalidProposalDesc2 struct{ validProposal } + +func (invalidProposalDesc2) GetDescription() string { return strings.Repeat("1234567890", 1000) } + +type invalidProposalRoute struct{ validProposal } + +func (invalidProposalRoute) ProposalRoute() string { return "nonexistingroute" } + +type invalidProposalValidation struct{ validProposal } + +func (invalidProposalValidation) ValidateBasic() error { + return errors.New("invalid proposal") +} + +func registerTestCodec(cdc *codec.Codec) { + cdc.RegisterConcrete(validProposal{}, "test/validproposal", nil) + cdc.RegisterConcrete(invalidProposalTitle1{}, "test/invalidproposalt1", nil) + cdc.RegisterConcrete(invalidProposalTitle2{}, "test/invalidproposalt2", nil) + cdc.RegisterConcrete(invalidProposalDesc1{}, "test/invalidproposald1", nil) + cdc.RegisterConcrete(invalidProposalDesc2{}, "test/invalidproposald2", nil) + cdc.RegisterConcrete(invalidProposalRoute{}, "test/invalidproposalr", nil) + cdc.RegisterConcrete(invalidProposalValidation{}, "test/invalidproposalv", nil) +} + +func TestSubmitProposal(t *testing.T) { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + registerTestCodec(app.Codec()) + + testCases := []struct { + content types.Content + expectedErr error + }{ + {validProposal{}, nil}, + // Keeper does not check the validity of title and description, no error + {invalidProposalTitle1{}, nil}, + {invalidProposalTitle2{}, nil}, + {invalidProposalDesc1{}, nil}, + {invalidProposalDesc2{}, nil}, + // error only when invalid route + {invalidProposalRoute{}, types.ErrNoProposalHandlerExists}, + // Keeper does not call ValidateBasic, msg.ValidateBasic does + {invalidProposalValidation{}, nil}, + } + + for i, tc := range testCases { + _, err := app.GovKeeper.SubmitProposal(ctx, tc.content) + require.True(t, errors.Is(tc.expectedErr, err), "tc #%d; got: %v, expected: %v", i, err, tc.expectedErr) + } +} + +func TestGetProposalsFiltered(t *testing.T) { + proposalID := uint64(1) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + status := []types.ProposalStatus{types.StatusDepositPeriod, types.StatusVotingPeriod} + + addr1 := sdk.AccAddress("foo") + + for _, s := range status { + for i := 0; i < 50; i++ { + p := types.NewProposal(TestProposal, proposalID, time.Now(), time.Now()) + p.Status = s + + if i%2 == 0 { + d := types.NewDeposit(proposalID, addr1, nil) + v := types.NewVote(proposalID, addr1, types.OptionYes) + app.GovKeeper.SetDeposit(ctx, d) + app.GovKeeper.SetVote(ctx, v) + } + + app.GovKeeper.SetProposal(ctx, p) + proposalID++ + } + } + + testCases := []struct { + params types.QueryProposalsParams + expectedNumResults int + }{ + {types.NewQueryProposalsParams(1, 50, types.StatusNil, nil, nil), 50}, + {types.NewQueryProposalsParams(1, 50, types.StatusDepositPeriod, nil, nil), 50}, + {types.NewQueryProposalsParams(1, 50, types.StatusVotingPeriod, nil, nil), 50}, + {types.NewQueryProposalsParams(1, 25, types.StatusNil, nil, nil), 25}, + {types.NewQueryProposalsParams(2, 25, types.StatusNil, nil, nil), 25}, + {types.NewQueryProposalsParams(1, 50, types.StatusRejected, nil, nil), 0}, + {types.NewQueryProposalsParams(1, 50, types.StatusNil, addr1, nil), 50}, + {types.NewQueryProposalsParams(1, 50, types.StatusNil, nil, addr1), 50}, + {types.NewQueryProposalsParams(1, 50, types.StatusNil, addr1, addr1), 50}, + {types.NewQueryProposalsParams(1, 50, types.StatusDepositPeriod, addr1, addr1), 25}, + {types.NewQueryProposalsParams(1, 50, types.StatusDepositPeriod, nil, nil), 50}, + {types.NewQueryProposalsParams(1, 50, types.StatusVotingPeriod, nil, nil), 50}, + } + + for _, tc := range testCases { + proposals := app.GovKeeper.GetProposalsFiltered(ctx, tc.params) + require.Len(t, proposals, tc.expectedNumResults) + + for _, p := range proposals { + if len(tc.params.ProposalStatus.String()) != 0 { + require.Equal(t, tc.params.ProposalStatus, p.Status) + } + } + } +} From 80bfd0d2dcabeb0353b345fbb0f7fe66d0680d8e Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 2 Mar 2020 16:22:36 +0100 Subject: [PATCH 307/529] migrate TestQueries to new test simapp --- x/gov/keeper/old_querier_test.go | 1 + x/gov/keeper/querier_test.go | 82 ++++++++++++++++++-------------- 2 files changed, 46 insertions(+), 37 deletions(-) create mode 100644 x/gov/keeper/old_querier_test.go diff --git a/x/gov/keeper/old_querier_test.go b/x/gov/keeper/old_querier_test.go new file mode 100644 index 000000000000..b55569d4a442 --- /dev/null +++ b/x/gov/keeper/old_querier_test.go @@ -0,0 +1 @@ +package keeper diff --git a/x/gov/keeper/querier_test.go b/x/gov/keeper/querier_test.go index 54aeae6fe7a5..368b51e67299 100644 --- a/x/gov/keeper/querier_test.go +++ b/x/gov/keeper/querier_test.go @@ -1,4 +1,4 @@ -package keeper +package keeper_test import ( "math/rand" @@ -7,10 +7,13 @@ import ( "time" "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/gov/keeper" "github.com/cosmos/cosmos-sdk/x/gov/types" ) @@ -142,45 +145,49 @@ func getQueriedVotes(t *testing.T, ctx sdk.Context, cdc *codec.Codec, querier sd } func TestQueries(t *testing.T) { - ctx, _, _, keeper, _, _ := createTestInput(t, false, 1000) // nolint: dogsled - querier := NewQuerier(keeper) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + querier := keeper.NewQuerier(app.GovKeeper) + + TestAddrs := simapp.AddTestAddrsIncremental(app, ctx, 2, sdk.NewInt(20000001)) oneCoins := sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 1)) consCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(10))) tp := TestProposal - depositParams, _, _ := getQueriedParams(t, ctx, keeper.cdc, querier) + depositParams, _, _ := getQueriedParams(t, ctx, app.Codec(), querier) // TestAddrs[0] proposes (and deposits) proposals #1 and #2 - proposal1, err := keeper.SubmitProposal(ctx, tp) + proposal1, err := app.GovKeeper.SubmitProposal(ctx, tp) require.NoError(t, err) deposit1 := types.NewDeposit(proposal1.ProposalID, TestAddrs[0], oneCoins) - _, err = keeper.AddDeposit(ctx, deposit1.ProposalID, deposit1.Depositor, deposit1.Amount) + _, err = app.GovKeeper.AddDeposit(ctx, deposit1.ProposalID, deposit1.Depositor, deposit1.Amount) require.NoError(t, err) proposal1.TotalDeposit = proposal1.TotalDeposit.Add(deposit1.Amount...) - proposal2, err := keeper.SubmitProposal(ctx, tp) + proposal2, err := app.GovKeeper.SubmitProposal(ctx, tp) require.NoError(t, err) deposit2 := types.NewDeposit(proposal2.ProposalID, TestAddrs[0], consCoins) - _, err = keeper.AddDeposit(ctx, deposit2.ProposalID, deposit2.Depositor, deposit2.Amount) + _, err = app.GovKeeper.AddDeposit(ctx, deposit2.ProposalID, deposit2.Depositor, deposit2.Amount) require.NoError(t, err) proposal2.TotalDeposit = proposal2.TotalDeposit.Add(deposit2.Amount...) // TestAddrs[1] proposes (and deposits) on proposal #3 - proposal3, err := keeper.SubmitProposal(ctx, tp) + proposal3, err := app.GovKeeper.SubmitProposal(ctx, tp) require.NoError(t, err) deposit3 := types.NewDeposit(proposal3.ProposalID, TestAddrs[1], oneCoins) - _, err = keeper.AddDeposit(ctx, deposit3.ProposalID, deposit3.Depositor, deposit3.Amount) + _, err = app.GovKeeper.AddDeposit(ctx, deposit3.ProposalID, deposit3.Depositor, deposit3.Amount) require.NoError(t, err) proposal3.TotalDeposit = proposal3.TotalDeposit.Add(deposit3.Amount...) // TestAddrs[1] deposits on proposals #2 & #3 deposit4 := types.NewDeposit(proposal2.ProposalID, TestAddrs[1], depositParams.MinDeposit) - _, err = keeper.AddDeposit(ctx, deposit4.ProposalID, deposit4.Depositor, deposit4.Amount) + _, err = app.GovKeeper.AddDeposit(ctx, deposit4.ProposalID, deposit4.Depositor, deposit4.Amount) require.NoError(t, err) proposal2.TotalDeposit = proposal2.TotalDeposit.Add(deposit4.Amount...) @@ -188,7 +195,7 @@ func TestQueries(t *testing.T) { proposal2.VotingEndTime = proposal2.VotingEndTime.Add(types.DefaultPeriod) deposit5 := types.NewDeposit(proposal3.ProposalID, TestAddrs[1], depositParams.MinDeposit) - _, err = keeper.AddDeposit(ctx, deposit5.ProposalID, deposit5.Depositor, deposit5.Amount) + _, err = app.GovKeeper.AddDeposit(ctx, deposit5.ProposalID, deposit5.Depositor, deposit5.Amount) require.NoError(t, err) proposal3.TotalDeposit = proposal3.TotalDeposit.Add(deposit5.Amount...) @@ -198,35 +205,35 @@ func TestQueries(t *testing.T) { deposit5.Amount = deposit5.Amount.Add(deposit3.Amount...) // check deposits on proposal1 match individual deposits - deposits := getQueriedDeposits(t, ctx, keeper.cdc, querier, proposal1.ProposalID) + deposits := getQueriedDeposits(t, ctx, app.Codec(), querier, proposal1.ProposalID) require.Len(t, deposits, 1) require.Equal(t, deposit1, deposits[0]) - deposit := getQueriedDeposit(t, ctx, keeper.cdc, querier, proposal1.ProposalID, TestAddrs[0]) + deposit := getQueriedDeposit(t, ctx, app.Codec(), querier, proposal1.ProposalID, TestAddrs[0]) require.Equal(t, deposit1, deposit) // check deposits on proposal2 match individual deposits - deposits = getQueriedDeposits(t, ctx, keeper.cdc, querier, proposal2.ProposalID) + deposits = getQueriedDeposits(t, ctx, app.Codec(), querier, proposal2.ProposalID) require.Len(t, deposits, 2) // NOTE order of deposits is determined by the addresses require.Equal(t, deposit2, deposits[0]) require.Equal(t, deposit4, deposits[1]) // check deposits on proposal3 match individual deposits - deposits = getQueriedDeposits(t, ctx, keeper.cdc, querier, proposal3.ProposalID) + deposits = getQueriedDeposits(t, ctx, app.Codec(), querier, proposal3.ProposalID) require.Len(t, deposits, 1) require.Equal(t, deposit5, deposits[0]) - deposit = getQueriedDeposit(t, ctx, keeper.cdc, querier, proposal3.ProposalID, TestAddrs[1]) + deposit = getQueriedDeposit(t, ctx, app.Codec(), querier, proposal3.ProposalID, TestAddrs[1]) require.Equal(t, deposit5, deposit) // Only proposal #1 should be in types.Deposit Period - proposals := getQueriedProposals(t, ctx, keeper.cdc, querier, nil, nil, types.StatusDepositPeriod, 1, 0) + proposals := getQueriedProposals(t, ctx, app.Codec(), querier, nil, nil, types.StatusDepositPeriod, 1, 0) require.Len(t, proposals, 1) require.Equal(t, proposal1, proposals[0]) // Only proposals #2 and #3 should be in Voting Period - proposals = getQueriedProposals(t, ctx, keeper.cdc, querier, nil, nil, types.StatusVotingPeriod, 1, 0) + proposals = getQueriedProposals(t, ctx, app.Codec(), querier, nil, nil, types.StatusVotingPeriod, 1, 0) require.Len(t, proposals, 2) require.Equal(t, proposal2, proposals[0]) require.Equal(t, proposal3, proposals[1]) @@ -234,64 +241,65 @@ func TestQueries(t *testing.T) { // Addrs[0] votes on proposals #2 & #3 vote1 := types.NewVote(proposal2.ProposalID, TestAddrs[0], types.OptionYes) vote2 := types.NewVote(proposal3.ProposalID, TestAddrs[0], types.OptionYes) - keeper.SetVote(ctx, vote1) - keeper.SetVote(ctx, vote2) + app.GovKeeper.SetVote(ctx, vote1) + app.GovKeeper.SetVote(ctx, vote2) // Addrs[1] votes on proposal #3 vote3 := types.NewVote(proposal3.ProposalID, TestAddrs[1], types.OptionYes) - keeper.SetVote(ctx, vote3) + app.GovKeeper.SetVote(ctx, vote3) // Test query voted by TestAddrs[0] - proposals = getQueriedProposals(t, ctx, keeper.cdc, querier, nil, TestAddrs[0], types.StatusNil, 1, 0) + proposals = getQueriedProposals(t, ctx, app.Codec(), querier, nil, TestAddrs[0], types.StatusNil, 1, 0) require.Equal(t, proposal2, proposals[0]) require.Equal(t, proposal3, proposals[1]) // Test query votes on types.Proposal 2 - votes := getQueriedVotes(t, ctx, keeper.cdc, querier, proposal2.ProposalID, 1, 0) + votes := getQueriedVotes(t, ctx, app.Codec(), querier, proposal2.ProposalID, 1, 0) require.Len(t, votes, 1) require.Equal(t, vote1, votes[0]) - vote := getQueriedVote(t, ctx, keeper.cdc, querier, proposal2.ProposalID, TestAddrs[0]) + vote := getQueriedVote(t, ctx, app.Codec(), querier, proposal2.ProposalID, TestAddrs[0]) require.Equal(t, vote1, vote) // Test query votes on types.Proposal 3 - votes = getQueriedVotes(t, ctx, keeper.cdc, querier, proposal3.ProposalID, 1, 0) + votes = getQueriedVotes(t, ctx, app.Codec(), querier, proposal3.ProposalID, 1, 0) require.Len(t, votes, 2) require.Equal(t, vote2, votes[0]) require.Equal(t, vote3, votes[1]) // Test query all proposals - proposals = getQueriedProposals(t, ctx, keeper.cdc, querier, nil, nil, types.StatusNil, 1, 0) + proposals = getQueriedProposals(t, ctx, app.Codec(), querier, nil, nil, types.StatusNil, 1, 0) require.Equal(t, proposal1, proposals[0]) require.Equal(t, proposal2, proposals[1]) require.Equal(t, proposal3, proposals[2]) // Test query voted by TestAddrs[1] - proposals = getQueriedProposals(t, ctx, keeper.cdc, querier, nil, TestAddrs[1], types.StatusNil, 1, 0) + proposals = getQueriedProposals(t, ctx, app.Codec(), querier, nil, TestAddrs[1], types.StatusNil, 1, 0) require.Equal(t, proposal3.ProposalID, proposals[0].ProposalID) // Test query deposited by TestAddrs[0] - proposals = getQueriedProposals(t, ctx, keeper.cdc, querier, TestAddrs[0], nil, types.StatusNil, 1, 0) + proposals = getQueriedProposals(t, ctx, app.Codec(), querier, TestAddrs[0], nil, types.StatusNil, 1, 0) require.Equal(t, proposal1.ProposalID, proposals[0].ProposalID) // Test query deposited by addr2 - proposals = getQueriedProposals(t, ctx, keeper.cdc, querier, TestAddrs[1], nil, types.StatusNil, 1, 0) + proposals = getQueriedProposals(t, ctx, app.Codec(), querier, TestAddrs[1], nil, types.StatusNil, 1, 0) require.Equal(t, proposal2.ProposalID, proposals[0].ProposalID) require.Equal(t, proposal3.ProposalID, proposals[1].ProposalID) // Test query voted AND deposited by addr1 - proposals = getQueriedProposals(t, ctx, keeper.cdc, querier, TestAddrs[0], TestAddrs[0], types.StatusNil, 1, 0) + proposals = getQueriedProposals(t, ctx, app.Codec(), querier, TestAddrs[0], TestAddrs[0], types.StatusNil, 1, 0) require.Equal(t, proposal2.ProposalID, proposals[0].ProposalID) } func TestPaginatedVotesQuery(t *testing.T) { - ctx, _, _, keeper, _, _ := createTestInput(t, false, 1000) // nolint: dogsled + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) proposal := types.Proposal{ ProposalID: 100, Status: types.StatusVotingPeriod, } - keeper.SetProposal(ctx, proposal) + app.GovKeeper.SetProposal(ctx, proposal) votes := make([]types.Vote, 20) rand := rand.New(rand.NewSource(time.Now().UnixNano())) @@ -304,13 +312,13 @@ func TestPaginatedVotesQuery(t *testing.T) { Option: types.OptionYes, } votes[i] = vote - keeper.SetVote(ctx, vote) + app.GovKeeper.SetVote(ctx, vote) } - querier := NewQuerier(keeper) + querier := keeper.NewQuerier(app.GovKeeper) // keeper preserves consistent order for each query, but this is not the insertion order - all := getQueriedVotes(t, ctx, keeper.cdc, querier, proposal.ProposalID, 1, 0) + all := getQueriedVotes(t, ctx, app.Codec(), querier, proposal.ProposalID, 1, 0) require.Equal(t, len(all), len(votes)) type testCase struct { @@ -344,7 +352,7 @@ func TestPaginatedVotesQuery(t *testing.T) { } { tc := tc t.Run(tc.description, func(t *testing.T) { - votes := getQueriedVotes(t, ctx, keeper.cdc, querier, proposal.ProposalID, tc.page, tc.limit) + votes := getQueriedVotes(t, ctx, app.Codec(), querier, proposal.ProposalID, tc.page, tc.limit) require.Equal(t, len(tc.votes), len(votes)) for i := range votes { require.Equal(t, tc.votes[i], votes[i]) From 8c0d32c8a8bf9cb9dba851876c2a6452b98beacd Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 2 Mar 2020 16:38:24 +0100 Subject: [PATCH 308/529] migrate TestTallyNoOneVotes to use simapp --- x/gov/keeper/common_test.go | 42 +++ x/gov/keeper/old_querier_test.go | 1 - x/gov/keeper/old_tally_test.go | 416 ++++++++++++++++++++++++++++++ x/gov/keeper/tally_test.go | 426 +------------------------------ 4 files changed, 470 insertions(+), 415 deletions(-) delete mode 100644 x/gov/keeper/old_querier_test.go create mode 100644 x/gov/keeper/old_tally_test.go diff --git a/x/gov/keeper/common_test.go b/x/gov/keeper/common_test.go index e4c48463f51d..bf21f71c4786 100644 --- a/x/gov/keeper/common_test.go +++ b/x/gov/keeper/common_test.go @@ -3,6 +3,13 @@ package keeper_test import ( "bytes" + "github.com/cosmos/cosmos-sdk/simapp/codec" + + "github.com/cosmos/cosmos-sdk/simapp" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/staking" + "github.com/cosmos/cosmos-sdk/x/gov/types" ) @@ -15,3 +22,38 @@ func ProposalEqual(proposalA types.Proposal, proposalB types.Proposal) bool { return bytes.Equal(types.ModuleCdc.MustMarshalBinaryBare(proposalA), types.ModuleCdc.MustMarshalBinaryBare(proposalB)) } + +func createValidators(ctx sdk.Context, app *simapp.SimApp, powers []int64) { + addrs := simapp.AddTestAddrsIncremental(app, ctx, 3, sdk.NewInt(10000000)) + valAddrs := simapp.ConvertAddrsToValAddrs(addrs) + pks := simapp.CreateTestPubKeys(3) + + appCodec := codec.NewAppCodec(app.Codec()) + app.StakingKeeper = staking.NewKeeper( + appCodec, + app.GetKey(staking.StoreKey), + app.BankKeeper, + app.SupplyKeeper, + app.GetSubspace(staking.ModuleName), + ) + + val1 := staking.NewValidator(valAddrs[0], pks[0], staking.Description{}) + val2 := staking.NewValidator(valAddrs[1], pks[1], staking.Description{}) + val3 := staking.NewValidator(valAddrs[2], pks[2], staking.Description{}) + + app.StakingKeeper.SetValidator(ctx, val1) + app.StakingKeeper.SetValidator(ctx, val2) + app.StakingKeeper.SetValidator(ctx, val3) + app.StakingKeeper.SetValidatorByConsAddr(ctx, val1) + app.StakingKeeper.SetValidatorByConsAddr(ctx, val2) + app.StakingKeeper.SetValidatorByConsAddr(ctx, val3) + app.StakingKeeper.SetNewValidatorByPowerIndex(ctx, val1) + app.StakingKeeper.SetNewValidatorByPowerIndex(ctx, val2) + app.StakingKeeper.SetNewValidatorByPowerIndex(ctx, val3) + + _, _ = app.StakingKeeper.Delegate(ctx, addrs[0], sdk.TokensFromConsensusPower(powers[0]), sdk.Unbonded, val1, true) + _, _ = app.StakingKeeper.Delegate(ctx, addrs[1], sdk.TokensFromConsensusPower(powers[1]), sdk.Unbonded, val2, true) + _, _ = app.StakingKeeper.Delegate(ctx, addrs[2], sdk.TokensFromConsensusPower(powers[2]), sdk.Unbonded, val3, true) + + _ = staking.EndBlocker(ctx, app.StakingKeeper) +} diff --git a/x/gov/keeper/old_querier_test.go b/x/gov/keeper/old_querier_test.go deleted file mode 100644 index b55569d4a442..000000000000 --- a/x/gov/keeper/old_querier_test.go +++ /dev/null @@ -1 +0,0 @@ -package keeper diff --git a/x/gov/keeper/old_tally_test.go b/x/gov/keeper/old_tally_test.go new file mode 100644 index 000000000000..e81e84874463 --- /dev/null +++ b/x/gov/keeper/old_tally_test.go @@ -0,0 +1,416 @@ +package keeper + +import ( + "testing" + + "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/cosmos/cosmos-sdk/x/staking" +) + +func TestTallyNoQuorum(t *testing.T) { + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) + createValidators(ctx, sk, []int64{2, 5, 0}) + + tp := TestProposal + proposal, err := keeper.SubmitProposal(ctx, tp) + require.NoError(t, err) + proposalID := proposal.ProposalID + proposal.Status = types.StatusVotingPeriod + keeper.SetProposal(ctx, proposal) + + err = keeper.AddVote(ctx, proposalID, TestAddrs[0], types.OptionYes) + require.Nil(t, err) + + proposal, ok := keeper.GetProposal(ctx, proposalID) + require.True(t, ok) + passes, burnDeposits, _ := keeper.Tally(ctx, proposal) + require.False(t, passes) + require.True(t, burnDeposits) +} + +func TestTallyOnlyValidatorsAllYes(t *testing.T) { + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) + createValidators(ctx, sk, []int64{5, 5, 5}) + + tp := TestProposal + proposal, err := keeper.SubmitProposal(ctx, tp) + require.NoError(t, err) + proposalID := proposal.ProposalID + proposal.Status = types.StatusVotingPeriod + keeper.SetProposal(ctx, proposal) + + require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionYes)) + require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionYes)) + require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr3, types.OptionYes)) + + proposal, ok := keeper.GetProposal(ctx, proposalID) + require.True(t, ok) + passes, burnDeposits, tallyResults := keeper.Tally(ctx, proposal) + + require.True(t, passes) + require.False(t, burnDeposits) + require.False(t, tallyResults.Equals(types.EmptyTallyResult())) +} + +func TestTallyOnlyValidators51No(t *testing.T) { + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) + createValidators(ctx, sk, []int64{5, 6, 0}) + + tp := TestProposal + proposal, err := keeper.SubmitProposal(ctx, tp) + require.NoError(t, err) + proposalID := proposal.ProposalID + proposal.Status = types.StatusVotingPeriod + keeper.SetProposal(ctx, proposal) + + require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionYes)) + require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionNo)) + + proposal, ok := keeper.GetProposal(ctx, proposalID) + require.True(t, ok) + passes, burnDeposits, _ := keeper.Tally(ctx, proposal) + + require.False(t, passes) + require.False(t, burnDeposits) +} + +func TestTallyOnlyValidators51Yes(t *testing.T) { + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) + createValidators(ctx, sk, []int64{5, 6, 0}) + + tp := TestProposal + proposal, err := keeper.SubmitProposal(ctx, tp) + require.NoError(t, err) + proposalID := proposal.ProposalID + proposal.Status = types.StatusVotingPeriod + keeper.SetProposal(ctx, proposal) + + require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionNo)) + require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionYes)) + + proposal, ok := keeper.GetProposal(ctx, proposalID) + require.True(t, ok) + passes, burnDeposits, tallyResults := keeper.Tally(ctx, proposal) + + require.True(t, passes) + require.False(t, burnDeposits) + require.False(t, tallyResults.Equals(types.EmptyTallyResult())) +} + +func TestTallyOnlyValidatorsVetoed(t *testing.T) { + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) + createValidators(ctx, sk, []int64{6, 6, 7}) + + tp := TestProposal + proposal, err := keeper.SubmitProposal(ctx, tp) + require.NoError(t, err) + proposalID := proposal.ProposalID + proposal.Status = types.StatusVotingPeriod + keeper.SetProposal(ctx, proposal) + + require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionYes)) + require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionYes)) + require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr3, types.OptionNoWithVeto)) + + proposal, ok := keeper.GetProposal(ctx, proposalID) + require.True(t, ok) + passes, burnDeposits, tallyResults := keeper.Tally(ctx, proposal) + + require.False(t, passes) + require.True(t, burnDeposits) + require.False(t, tallyResults.Equals(types.EmptyTallyResult())) + +} + +func TestTallyOnlyValidatorsAbstainPasses(t *testing.T) { + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) + createValidators(ctx, sk, []int64{6, 6, 7}) + + tp := TestProposal + proposal, err := keeper.SubmitProposal(ctx, tp) + require.NoError(t, err) + proposalID := proposal.ProposalID + proposal.Status = types.StatusVotingPeriod + keeper.SetProposal(ctx, proposal) + + require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionAbstain)) + require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionNo)) + require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr3, types.OptionYes)) + + proposal, ok := keeper.GetProposal(ctx, proposalID) + require.True(t, ok) + passes, burnDeposits, tallyResults := keeper.Tally(ctx, proposal) + + require.True(t, passes) + require.False(t, burnDeposits) + require.False(t, tallyResults.Equals(types.EmptyTallyResult())) +} + +func TestTallyOnlyValidatorsAbstainFails(t *testing.T) { + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) + createValidators(ctx, sk, []int64{6, 6, 7}) + + tp := TestProposal + proposal, err := keeper.SubmitProposal(ctx, tp) + require.NoError(t, err) + proposalID := proposal.ProposalID + proposal.Status = types.StatusVotingPeriod + keeper.SetProposal(ctx, proposal) + + require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionAbstain)) + require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionYes)) + require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr3, types.OptionNo)) + + proposal, ok := keeper.GetProposal(ctx, proposalID) + require.True(t, ok) + passes, burnDeposits, tallyResults := keeper.Tally(ctx, proposal) + + require.False(t, passes) + require.False(t, burnDeposits) + require.False(t, tallyResults.Equals(types.EmptyTallyResult())) +} + +func TestTallyOnlyValidatorsNonVoter(t *testing.T) { + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) + createValidators(ctx, sk, []int64{5, 6, 7}) + + tp := TestProposal + proposal, err := keeper.SubmitProposal(ctx, tp) + require.NoError(t, err) + proposalID := proposal.ProposalID + proposal.Status = types.StatusVotingPeriod + keeper.SetProposal(ctx, proposal) + + require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionYes)) + require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionNo)) + + proposal, ok := keeper.GetProposal(ctx, proposalID) + require.True(t, ok) + passes, burnDeposits, tallyResults := keeper.Tally(ctx, proposal) + + require.False(t, passes) + require.False(t, burnDeposits) + require.False(t, tallyResults.Equals(types.EmptyTallyResult())) +} + +func TestTallyDelgatorOverride(t *testing.T) { + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) + createValidators(ctx, sk, []int64{5, 6, 7}) + + delTokens := sdk.TokensFromConsensusPower(30) + val1, found := sk.GetValidator(ctx, valOpAddr1) + require.True(t, found) + + _, err := sk.Delegate(ctx, TestAddrs[0], delTokens, sdk.Unbonded, val1, true) + require.NoError(t, err) + + _ = staking.EndBlocker(ctx, sk) + + tp := TestProposal + proposal, err := keeper.SubmitProposal(ctx, tp) + require.NoError(t, err) + proposalID := proposal.ProposalID + proposal.Status = types.StatusVotingPeriod + keeper.SetProposal(ctx, proposal) + + require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionYes)) + require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionYes)) + require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr3, types.OptionYes)) + require.NoError(t, keeper.AddVote(ctx, proposalID, TestAddrs[0], types.OptionNo)) + + proposal, ok := keeper.GetProposal(ctx, proposalID) + require.True(t, ok) + passes, burnDeposits, tallyResults := keeper.Tally(ctx, proposal) + + require.False(t, passes) + require.False(t, burnDeposits) + require.False(t, tallyResults.Equals(types.EmptyTallyResult())) +} + +func TestTallyDelgatorInherit(t *testing.T) { + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) + createValidators(ctx, sk, []int64{5, 6, 7}) + + delTokens := sdk.TokensFromConsensusPower(30) + val3, found := sk.GetValidator(ctx, valOpAddr3) + require.True(t, found) + + _, err := sk.Delegate(ctx, TestAddrs[0], delTokens, sdk.Unbonded, val3, true) + require.NoError(t, err) + + _ = staking.EndBlocker(ctx, sk) + + tp := TestProposal + proposal, err := keeper.SubmitProposal(ctx, tp) + require.NoError(t, err) + proposalID := proposal.ProposalID + proposal.Status = types.StatusVotingPeriod + keeper.SetProposal(ctx, proposal) + + require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionNo)) + require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionNo)) + require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr3, types.OptionYes)) + + proposal, ok := keeper.GetProposal(ctx, proposalID) + require.True(t, ok) + passes, burnDeposits, tallyResults := keeper.Tally(ctx, proposal) + + require.True(t, passes) + require.False(t, burnDeposits) + require.False(t, tallyResults.Equals(types.EmptyTallyResult())) +} + +func TestTallyDelgatorMultipleOverride(t *testing.T) { + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) + createValidators(ctx, sk, []int64{5, 6, 7}) + + delTokens := sdk.TokensFromConsensusPower(10) + val1, found := sk.GetValidator(ctx, valOpAddr1) + require.True(t, found) + val2, found := sk.GetValidator(ctx, valOpAddr2) + require.True(t, found) + + _, err := sk.Delegate(ctx, TestAddrs[0], delTokens, sdk.Unbonded, val1, true) + require.NoError(t, err) + _, err = sk.Delegate(ctx, TestAddrs[0], delTokens, sdk.Unbonded, val2, true) + require.NoError(t, err) + + _ = staking.EndBlocker(ctx, sk) + + tp := TestProposal + proposal, err := keeper.SubmitProposal(ctx, tp) + require.NoError(t, err) + proposalID := proposal.ProposalID + proposal.Status = types.StatusVotingPeriod + keeper.SetProposal(ctx, proposal) + + require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionYes)) + require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionYes)) + require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr3, types.OptionYes)) + require.NoError(t, keeper.AddVote(ctx, proposalID, TestAddrs[0], types.OptionNo)) + + proposal, ok := keeper.GetProposal(ctx, proposalID) + require.True(t, ok) + passes, burnDeposits, tallyResults := keeper.Tally(ctx, proposal) + + require.False(t, passes) + require.False(t, burnDeposits) + require.False(t, tallyResults.Equals(types.EmptyTallyResult())) +} + +func TestTallyDelgatorMultipleInherit(t *testing.T) { + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) + createValidators(ctx, sk, []int64{25, 6, 7}) + + delTokens := sdk.TokensFromConsensusPower(10) + val2, found := sk.GetValidator(ctx, valOpAddr2) + require.True(t, found) + val3, found := sk.GetValidator(ctx, valOpAddr3) + require.True(t, found) + + _, err := sk.Delegate(ctx, TestAddrs[0], delTokens, sdk.Unbonded, val2, true) + require.NoError(t, err) + _, err = sk.Delegate(ctx, TestAddrs[0], delTokens, sdk.Unbonded, val3, true) + require.NoError(t, err) + + _ = staking.EndBlocker(ctx, sk) + + tp := TestProposal + proposal, err := keeper.SubmitProposal(ctx, tp) + require.NoError(t, err) + proposalID := proposal.ProposalID + proposal.Status = types.StatusVotingPeriod + keeper.SetProposal(ctx, proposal) + + require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionYes)) + require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionNo)) + require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr3, types.OptionNo)) + + proposal, ok := keeper.GetProposal(ctx, proposalID) + require.True(t, ok) + passes, burnDeposits, tallyResults := keeper.Tally(ctx, proposal) + + require.False(t, passes) + require.False(t, burnDeposits) + require.False(t, tallyResults.Equals(types.EmptyTallyResult())) +} + +func TestTallyJailedValidator(t *testing.T) { + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) + createValidators(ctx, sk, []int64{25, 6, 7}) + + delTokens := sdk.TokensFromConsensusPower(10) + val2, found := sk.GetValidator(ctx, valOpAddr2) + require.True(t, found) + val3, found := sk.GetValidator(ctx, valOpAddr3) + require.True(t, found) + + _, err := sk.Delegate(ctx, TestAddrs[0], delTokens, sdk.Unbonded, val2, true) + require.NoError(t, err) + _, err = sk.Delegate(ctx, TestAddrs[0], delTokens, sdk.Unbonded, val3, true) + require.NoError(t, err) + + _ = staking.EndBlocker(ctx, sk) + + sk.Jail(ctx, sdk.ConsAddress(val2.GetConsPubKey().Address())) + + tp := TestProposal + proposal, err := keeper.SubmitProposal(ctx, tp) + require.NoError(t, err) + proposalID := proposal.ProposalID + proposal.Status = types.StatusVotingPeriod + keeper.SetProposal(ctx, proposal) + + require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionYes)) + require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionNo)) + require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr3, types.OptionNo)) + + proposal, ok := keeper.GetProposal(ctx, proposalID) + require.True(t, ok) + passes, burnDeposits, tallyResults := keeper.Tally(ctx, proposal) + + require.True(t, passes) + require.False(t, burnDeposits) + require.False(t, tallyResults.Equals(types.EmptyTallyResult())) +} + +func TestTallyValidatorMultipleDelegations(t *testing.T) { + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) + createValidators(ctx, sk, []int64{10, 10, 10}) + + delTokens := sdk.TokensFromConsensusPower(10) + val2, found := sk.GetValidator(ctx, valOpAddr2) + require.True(t, found) + + _, err := sk.Delegate(ctx, valAccAddr1, delTokens, sdk.Unbonded, val2, true) + require.NoError(t, err) + + tp := TestProposal + proposal, err := keeper.SubmitProposal(ctx, tp) + require.NoError(t, err) + proposalID := proposal.ProposalID + proposal.Status = types.StatusVotingPeriod + keeper.SetProposal(ctx, proposal) + + require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionYes)) + require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionNo)) + require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr3, types.OptionYes)) + + proposal, ok := keeper.GetProposal(ctx, proposalID) + require.True(t, ok) + passes, burnDeposits, tallyResults := keeper.Tally(ctx, proposal) + + require.True(t, passes) + require.False(t, burnDeposits) + + expectedYes := sdk.TokensFromConsensusPower(30) + expectedAbstain := sdk.TokensFromConsensusPower(0) + expectedNo := sdk.TokensFromConsensusPower(10) + expectedNoWithVeto := sdk.TokensFromConsensusPower(0) + expectedTallyResult := types.NewTallyResult(expectedYes, expectedAbstain, expectedNo, expectedNoWithVeto) + + require.True(t, tallyResults.Equals(expectedTallyResult)) +} diff --git a/x/gov/keeper/tally_test.go b/x/gov/keeper/tally_test.go index e93f6b387e6b..f86871b55069 100644 --- a/x/gov/keeper/tally_test.go +++ b/x/gov/keeper/tally_test.go @@ -1,436 +1,34 @@ -package keeper +package keeper_test import ( "testing" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/stretchr/testify/require" - sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/simapp" "github.com/cosmos/cosmos-sdk/x/gov/types" - "github.com/cosmos/cosmos-sdk/x/staking" ) func TestTallyNoOneVotes(t *testing.T) { - ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) - createValidators(ctx, sk, []int64{5, 5, 5}) - - tp := TestProposal - proposal, err := keeper.SubmitProposal(ctx, tp) - require.NoError(t, err) - proposalID := proposal.ProposalID - proposal.Status = types.StatusVotingPeriod - keeper.SetProposal(ctx, proposal) - - proposal, ok := keeper.GetProposal(ctx, proposalID) - require.True(t, ok) - passes, burnDeposits, tallyResults := keeper.Tally(ctx, proposal) - - require.False(t, passes) - require.True(t, burnDeposits) - require.True(t, tallyResults.Equals(types.EmptyTallyResult())) -} - -func TestTallyNoQuorum(t *testing.T) { - ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) - createValidators(ctx, sk, []int64{2, 5, 0}) - - tp := TestProposal - proposal, err := keeper.SubmitProposal(ctx, tp) - require.NoError(t, err) - proposalID := proposal.ProposalID - proposal.Status = types.StatusVotingPeriod - keeper.SetProposal(ctx, proposal) - - err = keeper.AddVote(ctx, proposalID, TestAddrs[0], types.OptionYes) - require.Nil(t, err) - - proposal, ok := keeper.GetProposal(ctx, proposalID) - require.True(t, ok) - passes, burnDeposits, _ := keeper.Tally(ctx, proposal) - require.False(t, passes) - require.True(t, burnDeposits) -} - -func TestTallyOnlyValidatorsAllYes(t *testing.T) { - ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) - createValidators(ctx, sk, []int64{5, 5, 5}) - - tp := TestProposal - proposal, err := keeper.SubmitProposal(ctx, tp) - require.NoError(t, err) - proposalID := proposal.ProposalID - proposal.Status = types.StatusVotingPeriod - keeper.SetProposal(ctx, proposal) - - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionYes)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionYes)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr3, types.OptionYes)) - - proposal, ok := keeper.GetProposal(ctx, proposalID) - require.True(t, ok) - passes, burnDeposits, tallyResults := keeper.Tally(ctx, proposal) - - require.True(t, passes) - require.False(t, burnDeposits) - require.False(t, tallyResults.Equals(types.EmptyTallyResult())) -} - -func TestTallyOnlyValidators51No(t *testing.T) { - ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) - createValidators(ctx, sk, []int64{5, 6, 0}) - - tp := TestProposal - proposal, err := keeper.SubmitProposal(ctx, tp) - require.NoError(t, err) - proposalID := proposal.ProposalID - proposal.Status = types.StatusVotingPeriod - keeper.SetProposal(ctx, proposal) - - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionYes)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionNo)) - - proposal, ok := keeper.GetProposal(ctx, proposalID) - require.True(t, ok) - passes, burnDeposits, _ := keeper.Tally(ctx, proposal) - - require.False(t, passes) - require.False(t, burnDeposits) -} - -func TestTallyOnlyValidators51Yes(t *testing.T) { - ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) - createValidators(ctx, sk, []int64{5, 6, 0}) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) - tp := TestProposal - proposal, err := keeper.SubmitProposal(ctx, tp) - require.NoError(t, err) - proposalID := proposal.ProposalID - proposal.Status = types.StatusVotingPeriod - keeper.SetProposal(ctx, proposal) - - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionNo)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionYes)) - - proposal, ok := keeper.GetProposal(ctx, proposalID) - require.True(t, ok) - passes, burnDeposits, tallyResults := keeper.Tally(ctx, proposal) - - require.True(t, passes) - require.False(t, burnDeposits) - require.False(t, tallyResults.Equals(types.EmptyTallyResult())) -} - -func TestTallyOnlyValidatorsVetoed(t *testing.T) { - ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) - createValidators(ctx, sk, []int64{6, 6, 7}) + createValidators(ctx, app, []int64{5, 5, 5}) tp := TestProposal - proposal, err := keeper.SubmitProposal(ctx, tp) + proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) require.NoError(t, err) proposalID := proposal.ProposalID proposal.Status = types.StatusVotingPeriod - keeper.SetProposal(ctx, proposal) + app.GovKeeper.SetProposal(ctx, proposal) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionYes)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionYes)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr3, types.OptionNoWithVeto)) - - proposal, ok := keeper.GetProposal(ctx, proposalID) + proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID) require.True(t, ok) - passes, burnDeposits, tallyResults := keeper.Tally(ctx, proposal) + passes, burnDeposits, tallyResults := app.GovKeeper.Tally(ctx, proposal) require.False(t, passes) require.True(t, burnDeposits) - require.False(t, tallyResults.Equals(types.EmptyTallyResult())) - -} - -func TestTallyOnlyValidatorsAbstainPasses(t *testing.T) { - ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) - createValidators(ctx, sk, []int64{6, 6, 7}) - - tp := TestProposal - proposal, err := keeper.SubmitProposal(ctx, tp) - require.NoError(t, err) - proposalID := proposal.ProposalID - proposal.Status = types.StatusVotingPeriod - keeper.SetProposal(ctx, proposal) - - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionAbstain)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionNo)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr3, types.OptionYes)) - - proposal, ok := keeper.GetProposal(ctx, proposalID) - require.True(t, ok) - passes, burnDeposits, tallyResults := keeper.Tally(ctx, proposal) - - require.True(t, passes) - require.False(t, burnDeposits) - require.False(t, tallyResults.Equals(types.EmptyTallyResult())) -} - -func TestTallyOnlyValidatorsAbstainFails(t *testing.T) { - ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) - createValidators(ctx, sk, []int64{6, 6, 7}) - - tp := TestProposal - proposal, err := keeper.SubmitProposal(ctx, tp) - require.NoError(t, err) - proposalID := proposal.ProposalID - proposal.Status = types.StatusVotingPeriod - keeper.SetProposal(ctx, proposal) - - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionAbstain)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionYes)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr3, types.OptionNo)) - - proposal, ok := keeper.GetProposal(ctx, proposalID) - require.True(t, ok) - passes, burnDeposits, tallyResults := keeper.Tally(ctx, proposal) - - require.False(t, passes) - require.False(t, burnDeposits) - require.False(t, tallyResults.Equals(types.EmptyTallyResult())) -} - -func TestTallyOnlyValidatorsNonVoter(t *testing.T) { - ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) - createValidators(ctx, sk, []int64{5, 6, 7}) - - tp := TestProposal - proposal, err := keeper.SubmitProposal(ctx, tp) - require.NoError(t, err) - proposalID := proposal.ProposalID - proposal.Status = types.StatusVotingPeriod - keeper.SetProposal(ctx, proposal) - - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionYes)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionNo)) - - proposal, ok := keeper.GetProposal(ctx, proposalID) - require.True(t, ok) - passes, burnDeposits, tallyResults := keeper.Tally(ctx, proposal) - - require.False(t, passes) - require.False(t, burnDeposits) - require.False(t, tallyResults.Equals(types.EmptyTallyResult())) -} - -func TestTallyDelgatorOverride(t *testing.T) { - ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) - createValidators(ctx, sk, []int64{5, 6, 7}) - - delTokens := sdk.TokensFromConsensusPower(30) - val1, found := sk.GetValidator(ctx, valOpAddr1) - require.True(t, found) - - _, err := sk.Delegate(ctx, TestAddrs[0], delTokens, sdk.Unbonded, val1, true) - require.NoError(t, err) - - _ = staking.EndBlocker(ctx, sk) - - tp := TestProposal - proposal, err := keeper.SubmitProposal(ctx, tp) - require.NoError(t, err) - proposalID := proposal.ProposalID - proposal.Status = types.StatusVotingPeriod - keeper.SetProposal(ctx, proposal) - - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionYes)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionYes)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr3, types.OptionYes)) - require.NoError(t, keeper.AddVote(ctx, proposalID, TestAddrs[0], types.OptionNo)) - - proposal, ok := keeper.GetProposal(ctx, proposalID) - require.True(t, ok) - passes, burnDeposits, tallyResults := keeper.Tally(ctx, proposal) - - require.False(t, passes) - require.False(t, burnDeposits) - require.False(t, tallyResults.Equals(types.EmptyTallyResult())) -} - -func TestTallyDelgatorInherit(t *testing.T) { - ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) - createValidators(ctx, sk, []int64{5, 6, 7}) - - delTokens := sdk.TokensFromConsensusPower(30) - val3, found := sk.GetValidator(ctx, valOpAddr3) - require.True(t, found) - - _, err := sk.Delegate(ctx, TestAddrs[0], delTokens, sdk.Unbonded, val3, true) - require.NoError(t, err) - - _ = staking.EndBlocker(ctx, sk) - - tp := TestProposal - proposal, err := keeper.SubmitProposal(ctx, tp) - require.NoError(t, err) - proposalID := proposal.ProposalID - proposal.Status = types.StatusVotingPeriod - keeper.SetProposal(ctx, proposal) - - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionNo)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionNo)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr3, types.OptionYes)) - - proposal, ok := keeper.GetProposal(ctx, proposalID) - require.True(t, ok) - passes, burnDeposits, tallyResults := keeper.Tally(ctx, proposal) - - require.True(t, passes) - require.False(t, burnDeposits) - require.False(t, tallyResults.Equals(types.EmptyTallyResult())) -} - -func TestTallyDelgatorMultipleOverride(t *testing.T) { - ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) - createValidators(ctx, sk, []int64{5, 6, 7}) - - delTokens := sdk.TokensFromConsensusPower(10) - val1, found := sk.GetValidator(ctx, valOpAddr1) - require.True(t, found) - val2, found := sk.GetValidator(ctx, valOpAddr2) - require.True(t, found) - - _, err := sk.Delegate(ctx, TestAddrs[0], delTokens, sdk.Unbonded, val1, true) - require.NoError(t, err) - _, err = sk.Delegate(ctx, TestAddrs[0], delTokens, sdk.Unbonded, val2, true) - require.NoError(t, err) - - _ = staking.EndBlocker(ctx, sk) - - tp := TestProposal - proposal, err := keeper.SubmitProposal(ctx, tp) - require.NoError(t, err) - proposalID := proposal.ProposalID - proposal.Status = types.StatusVotingPeriod - keeper.SetProposal(ctx, proposal) - - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionYes)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionYes)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr3, types.OptionYes)) - require.NoError(t, keeper.AddVote(ctx, proposalID, TestAddrs[0], types.OptionNo)) - - proposal, ok := keeper.GetProposal(ctx, proposalID) - require.True(t, ok) - passes, burnDeposits, tallyResults := keeper.Tally(ctx, proposal) - - require.False(t, passes) - require.False(t, burnDeposits) - require.False(t, tallyResults.Equals(types.EmptyTallyResult())) -} - -func TestTallyDelgatorMultipleInherit(t *testing.T) { - ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) - createValidators(ctx, sk, []int64{25, 6, 7}) - - delTokens := sdk.TokensFromConsensusPower(10) - val2, found := sk.GetValidator(ctx, valOpAddr2) - require.True(t, found) - val3, found := sk.GetValidator(ctx, valOpAddr3) - require.True(t, found) - - _, err := sk.Delegate(ctx, TestAddrs[0], delTokens, sdk.Unbonded, val2, true) - require.NoError(t, err) - _, err = sk.Delegate(ctx, TestAddrs[0], delTokens, sdk.Unbonded, val3, true) - require.NoError(t, err) - - _ = staking.EndBlocker(ctx, sk) - - tp := TestProposal - proposal, err := keeper.SubmitProposal(ctx, tp) - require.NoError(t, err) - proposalID := proposal.ProposalID - proposal.Status = types.StatusVotingPeriod - keeper.SetProposal(ctx, proposal) - - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionYes)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionNo)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr3, types.OptionNo)) - - proposal, ok := keeper.GetProposal(ctx, proposalID) - require.True(t, ok) - passes, burnDeposits, tallyResults := keeper.Tally(ctx, proposal) - - require.False(t, passes) - require.False(t, burnDeposits) - require.False(t, tallyResults.Equals(types.EmptyTallyResult())) -} - -func TestTallyJailedValidator(t *testing.T) { - ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) - createValidators(ctx, sk, []int64{25, 6, 7}) - - delTokens := sdk.TokensFromConsensusPower(10) - val2, found := sk.GetValidator(ctx, valOpAddr2) - require.True(t, found) - val3, found := sk.GetValidator(ctx, valOpAddr3) - require.True(t, found) - - _, err := sk.Delegate(ctx, TestAddrs[0], delTokens, sdk.Unbonded, val2, true) - require.NoError(t, err) - _, err = sk.Delegate(ctx, TestAddrs[0], delTokens, sdk.Unbonded, val3, true) - require.NoError(t, err) - - _ = staking.EndBlocker(ctx, sk) - - sk.Jail(ctx, sdk.ConsAddress(val2.GetConsPubKey().Address())) - - tp := TestProposal - proposal, err := keeper.SubmitProposal(ctx, tp) - require.NoError(t, err) - proposalID := proposal.ProposalID - proposal.Status = types.StatusVotingPeriod - keeper.SetProposal(ctx, proposal) - - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionYes)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionNo)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr3, types.OptionNo)) - - proposal, ok := keeper.GetProposal(ctx, proposalID) - require.True(t, ok) - passes, burnDeposits, tallyResults := keeper.Tally(ctx, proposal) - - require.True(t, passes) - require.False(t, burnDeposits) - require.False(t, tallyResults.Equals(types.EmptyTallyResult())) -} - -func TestTallyValidatorMultipleDelegations(t *testing.T) { - ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) - createValidators(ctx, sk, []int64{10, 10, 10}) - - delTokens := sdk.TokensFromConsensusPower(10) - val2, found := sk.GetValidator(ctx, valOpAddr2) - require.True(t, found) - - _, err := sk.Delegate(ctx, valAccAddr1, delTokens, sdk.Unbonded, val2, true) - require.NoError(t, err) - - tp := TestProposal - proposal, err := keeper.SubmitProposal(ctx, tp) - require.NoError(t, err) - proposalID := proposal.ProposalID - proposal.Status = types.StatusVotingPeriod - keeper.SetProposal(ctx, proposal) - - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionYes)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionNo)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr3, types.OptionYes)) - - proposal, ok := keeper.GetProposal(ctx, proposalID) - require.True(t, ok) - passes, burnDeposits, tallyResults := keeper.Tally(ctx, proposal) - - require.True(t, passes) - require.False(t, burnDeposits) - - expectedYes := sdk.TokensFromConsensusPower(30) - expectedAbstain := sdk.TokensFromConsensusPower(0) - expectedNo := sdk.TokensFromConsensusPower(10) - expectedNoWithVeto := sdk.TokensFromConsensusPower(0) - expectedTallyResult := types.NewTallyResult(expectedYes, expectedAbstain, expectedNo, expectedNoWithVeto) - - require.True(t, tallyResults.Equals(expectedTallyResult)) + require.True(t, tallyResults.Equals(types.EmptyTallyResult())) } From e24734f72e313da7b560f40e5aba905aff3b4357 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 2 Mar 2020 16:41:41 +0100 Subject: [PATCH 309/529] migrate TestTallyNoQuorum to use simapp --- x/gov/keeper/old_tally_test.go | 21 --------------------- x/gov/keeper/tally_test.go | 27 +++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/x/gov/keeper/old_tally_test.go b/x/gov/keeper/old_tally_test.go index e81e84874463..2fe3b1f89af3 100644 --- a/x/gov/keeper/old_tally_test.go +++ b/x/gov/keeper/old_tally_test.go @@ -10,27 +10,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking" ) -func TestTallyNoQuorum(t *testing.T) { - ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) - createValidators(ctx, sk, []int64{2, 5, 0}) - - tp := TestProposal - proposal, err := keeper.SubmitProposal(ctx, tp) - require.NoError(t, err) - proposalID := proposal.ProposalID - proposal.Status = types.StatusVotingPeriod - keeper.SetProposal(ctx, proposal) - - err = keeper.AddVote(ctx, proposalID, TestAddrs[0], types.OptionYes) - require.Nil(t, err) - - proposal, ok := keeper.GetProposal(ctx, proposalID) - require.True(t, ok) - passes, burnDeposits, _ := keeper.Tally(ctx, proposal) - require.False(t, passes) - require.True(t, burnDeposits) -} - func TestTallyOnlyValidatorsAllYes(t *testing.T) { ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{5, 5, 5}) diff --git a/x/gov/keeper/tally_test.go b/x/gov/keeper/tally_test.go index f86871b55069..a72a3908e1f8 100644 --- a/x/gov/keeper/tally_test.go +++ b/x/gov/keeper/tally_test.go @@ -3,6 +3,8 @@ package keeper_test import ( "testing" + sdk "github.com/cosmos/cosmos-sdk/types" + abci "github.com/tendermint/tendermint/abci/types" "github.com/stretchr/testify/require" @@ -32,3 +34,28 @@ func TestTallyNoOneVotes(t *testing.T) { require.True(t, burnDeposits) require.True(t, tallyResults.Equals(types.EmptyTallyResult())) } + +func TestTallyNoQuorum(t *testing.T) { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + createValidators(ctx, app, []int64{2, 5, 0}) + + addrs := simapp.AddTestAddrsIncremental(app, ctx, 1, sdk.NewInt(10000000)) + + tp := TestProposal + proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) + require.NoError(t, err) + proposalID := proposal.ProposalID + proposal.Status = types.StatusVotingPeriod + app.GovKeeper.SetProposal(ctx, proposal) + + err = app.GovKeeper.AddVote(ctx, proposalID, addrs[0], types.OptionYes) + require.Nil(t, err) + + proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID) + require.True(t, ok) + passes, burnDeposits, _ := app.GovKeeper.Tally(ctx, proposal) + require.False(t, passes) + require.True(t, burnDeposits) +} From 88e3a22fc41288e6f9aec1610f3bf5a982881040 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 2 Mar 2020 16:47:06 +0100 Subject: [PATCH 310/529] migrate TestTallyOnlyValidatorsAllYes to simapp --- x/gov/keeper/common_test.go | 4 +++- x/gov/keeper/old_tally_test.go | 24 ------------------------ x/gov/keeper/tally_test.go | 32 +++++++++++++++++++++++++++++--- 3 files changed, 32 insertions(+), 28 deletions(-) diff --git a/x/gov/keeper/common_test.go b/x/gov/keeper/common_test.go index bf21f71c4786..81b859973fd4 100644 --- a/x/gov/keeper/common_test.go +++ b/x/gov/keeper/common_test.go @@ -23,7 +23,7 @@ func ProposalEqual(proposalA types.Proposal, proposalB types.Proposal) bool { types.ModuleCdc.MustMarshalBinaryBare(proposalB)) } -func createValidators(ctx sdk.Context, app *simapp.SimApp, powers []int64) { +func createValidators(ctx sdk.Context, app *simapp.SimApp, powers []int64) ([]sdk.AccAddress, []sdk.ValAddress) { addrs := simapp.AddTestAddrsIncremental(app, ctx, 3, sdk.NewInt(10000000)) valAddrs := simapp.ConvertAddrsToValAddrs(addrs) pks := simapp.CreateTestPubKeys(3) @@ -56,4 +56,6 @@ func createValidators(ctx sdk.Context, app *simapp.SimApp, powers []int64) { _, _ = app.StakingKeeper.Delegate(ctx, addrs[2], sdk.TokensFromConsensusPower(powers[2]), sdk.Unbonded, val3, true) _ = staking.EndBlocker(ctx, app.StakingKeeper) + + return addrs, valAddrs } diff --git a/x/gov/keeper/old_tally_test.go b/x/gov/keeper/old_tally_test.go index 2fe3b1f89af3..05c0439709cf 100644 --- a/x/gov/keeper/old_tally_test.go +++ b/x/gov/keeper/old_tally_test.go @@ -10,30 +10,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking" ) -func TestTallyOnlyValidatorsAllYes(t *testing.T) { - ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) - createValidators(ctx, sk, []int64{5, 5, 5}) - - tp := TestProposal - proposal, err := keeper.SubmitProposal(ctx, tp) - require.NoError(t, err) - proposalID := proposal.ProposalID - proposal.Status = types.StatusVotingPeriod - keeper.SetProposal(ctx, proposal) - - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionYes)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionYes)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr3, types.OptionYes)) - - proposal, ok := keeper.GetProposal(ctx, proposalID) - require.True(t, ok) - passes, burnDeposits, tallyResults := keeper.Tally(ctx, proposal) - - require.True(t, passes) - require.False(t, burnDeposits) - require.False(t, tallyResults.Equals(types.EmptyTallyResult())) -} - func TestTallyOnlyValidators51No(t *testing.T) { ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{5, 6, 0}) diff --git a/x/gov/keeper/tally_test.go b/x/gov/keeper/tally_test.go index a72a3908e1f8..9f607df8d184 100644 --- a/x/gov/keeper/tally_test.go +++ b/x/gov/keeper/tally_test.go @@ -3,13 +3,12 @@ package keeper_test import ( "testing" - sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" - "github.com/stretchr/testify/require" - "github.com/cosmos/cosmos-sdk/simapp" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/gov/types" ) @@ -59,3 +58,30 @@ func TestTallyNoQuorum(t *testing.T) { require.False(t, passes) require.True(t, burnDeposits) } + +func TestTallyOnlyValidatorsAllYes(t *testing.T) { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + addrs, _ := createValidators(ctx, app, []int64{5, 5, 5}) + valAccAddr1, valAccAddr2, valAccAddr3 := addrs[0], addrs[1], addrs[2] + + tp := TestProposal + proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) + require.NoError(t, err) + proposalID := proposal.ProposalID + proposal.Status = types.StatusVotingPeriod + app.GovKeeper.SetProposal(ctx, proposal) + + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionYes)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionYes)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr3, types.OptionYes)) + + proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID) + require.True(t, ok) + passes, burnDeposits, tallyResults := app.GovKeeper.Tally(ctx, proposal) + + require.True(t, passes) + require.False(t, burnDeposits) + require.False(t, tallyResults.Equals(types.EmptyTallyResult())) +} From 1cf4a7e33048cd0d7350c493ed27e61d7681b972 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 2 Mar 2020 16:50:39 +0100 Subject: [PATCH 311/529] migrate TestTallyOnlyValidators51No to use simapp --- x/gov/keeper/old_tally_test.go | 22 ---------------------- x/gov/keeper/tally_test.go | 33 ++++++++++++++++++++++++++++----- 2 files changed, 28 insertions(+), 27 deletions(-) diff --git a/x/gov/keeper/old_tally_test.go b/x/gov/keeper/old_tally_test.go index 05c0439709cf..6cfd0be78eea 100644 --- a/x/gov/keeper/old_tally_test.go +++ b/x/gov/keeper/old_tally_test.go @@ -10,28 +10,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking" ) -func TestTallyOnlyValidators51No(t *testing.T) { - ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) - createValidators(ctx, sk, []int64{5, 6, 0}) - - tp := TestProposal - proposal, err := keeper.SubmitProposal(ctx, tp) - require.NoError(t, err) - proposalID := proposal.ProposalID - proposal.Status = types.StatusVotingPeriod - keeper.SetProposal(ctx, proposal) - - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionYes)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionNo)) - - proposal, ok := keeper.GetProposal(ctx, proposalID) - require.True(t, ok) - passes, burnDeposits, _ := keeper.Tally(ctx, proposal) - - require.False(t, passes) - require.False(t, burnDeposits) -} - func TestTallyOnlyValidators51Yes(t *testing.T) { ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{5, 6, 0}) diff --git a/x/gov/keeper/tally_test.go b/x/gov/keeper/tally_test.go index 9f607df8d184..b29f13a1ffbf 100644 --- a/x/gov/keeper/tally_test.go +++ b/x/gov/keeper/tally_test.go @@ -64,18 +64,17 @@ func TestTallyOnlyValidatorsAllYes(t *testing.T) { ctx := app.BaseApp.NewContext(false, abci.Header{}) addrs, _ := createValidators(ctx, app, []int64{5, 5, 5}) - valAccAddr1, valAccAddr2, valAccAddr3 := addrs[0], addrs[1], addrs[2] - tp := TestProposal + proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) require.NoError(t, err) proposalID := proposal.ProposalID proposal.Status = types.StatusVotingPeriod app.GovKeeper.SetProposal(ctx, proposal) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionYes)) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionYes)) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr3, types.OptionYes)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[0], types.OptionYes)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[1], types.OptionYes)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[2], types.OptionYes)) proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID) require.True(t, ok) @@ -85,3 +84,27 @@ func TestTallyOnlyValidatorsAllYes(t *testing.T) { require.False(t, burnDeposits) require.False(t, tallyResults.Equals(types.EmptyTallyResult())) } + +func TestTallyOnlyValidators51No(t *testing.T) { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + valAccAddrs, _ := createValidators(ctx, app, []int64{5, 6, 0}) + + tp := TestProposal + proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) + require.NoError(t, err) + proposalID := proposal.ProposalID + proposal.Status = types.StatusVotingPeriod + app.GovKeeper.SetProposal(ctx, proposal) + + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[0], types.OptionYes)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[1], types.OptionNo)) + + proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID) + require.True(t, ok) + passes, burnDeposits, _ := app.GovKeeper.Tally(ctx, proposal) + + require.False(t, passes) + require.False(t, burnDeposits) +} From 84b7fe5bfa30393613bcbe95e6a0ed00c4039f5f Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 2 Mar 2020 16:53:06 +0100 Subject: [PATCH 312/529] migrate TestTallyOnlyValidators51Yes to use simapp --- x/gov/keeper/old_tally_test.go | 23 ----------------------- x/gov/keeper/tally_test.go | 26 ++++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/x/gov/keeper/old_tally_test.go b/x/gov/keeper/old_tally_test.go index 6cfd0be78eea..a30f9848f97c 100644 --- a/x/gov/keeper/old_tally_test.go +++ b/x/gov/keeper/old_tally_test.go @@ -10,29 +10,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking" ) -func TestTallyOnlyValidators51Yes(t *testing.T) { - ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) - createValidators(ctx, sk, []int64{5, 6, 0}) - - tp := TestProposal - proposal, err := keeper.SubmitProposal(ctx, tp) - require.NoError(t, err) - proposalID := proposal.ProposalID - proposal.Status = types.StatusVotingPeriod - keeper.SetProposal(ctx, proposal) - - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionNo)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionYes)) - - proposal, ok := keeper.GetProposal(ctx, proposalID) - require.True(t, ok) - passes, burnDeposits, tallyResults := keeper.Tally(ctx, proposal) - - require.True(t, passes) - require.False(t, burnDeposits) - require.False(t, tallyResults.Equals(types.EmptyTallyResult())) -} - func TestTallyOnlyValidatorsVetoed(t *testing.T) { ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{6, 6, 7}) diff --git a/x/gov/keeper/tally_test.go b/x/gov/keeper/tally_test.go index b29f13a1ffbf..eb5f7a96246d 100644 --- a/x/gov/keeper/tally_test.go +++ b/x/gov/keeper/tally_test.go @@ -108,3 +108,29 @@ func TestTallyOnlyValidators51No(t *testing.T) { require.False(t, passes) require.False(t, burnDeposits) } + +func TestTallyOnlyValidators51Yes(t *testing.T) { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + valAccAddrs, _ := createValidators(ctx, app, []int64{5, 6, 0}) + valAccAddr1, valAccAddr2 := valAccAddrs[0], valAccAddrs[1] + + tp := TestProposal + proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) + require.NoError(t, err) + proposalID := proposal.ProposalID + proposal.Status = types.StatusVotingPeriod + app.GovKeeper.SetProposal(ctx, proposal) + + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionNo)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionYes)) + + proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID) + require.True(t, ok) + passes, burnDeposits, tallyResults := app.GovKeeper.Tally(ctx, proposal) + + require.True(t, passes) + require.False(t, burnDeposits) + require.False(t, tallyResults.Equals(types.EmptyTallyResult())) +} From 081e62cb2d25da06f2ba30e5a3ca1d77f97d63ee Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Mon, 2 Mar 2020 11:54:43 -0500 Subject: [PATCH 313/529] Update codec --- x/evidence/types/codec.go | 2 +- x/gov/types/codec.go | 48 ++++++++++++++++----------------------- 2 files changed, 21 insertions(+), 29 deletions(-) diff --git a/x/evidence/types/codec.go b/x/evidence/types/codec.go index 6cfd762c38ab..d0a9d1a5e1a8 100644 --- a/x/evidence/types/codec.go +++ b/x/evidence/types/codec.go @@ -5,7 +5,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/evidence/exported" ) -// EvidenceCodec defines the interface required to serialize evidence +// Codec defines the interface required to serialize evidence type Codec interface { codec.Marshaler diff --git a/x/gov/types/codec.go b/x/gov/types/codec.go index 5226877f97f4..a02491a12b12 100644 --- a/x/gov/types/codec.go +++ b/x/gov/types/codec.go @@ -4,6 +4,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" ) +// Codec defines the interface required to serialize custom x/gov types. type Codec interface { codec.Marshaler @@ -11,48 +12,39 @@ type Codec interface { UnmarshalProposal(bz []byte, ptr *Proposal) error } -// module codec -var ModuleCdc = codec.New() - -// RegisterCodec registers all the necessary types and interfaces for -// governance. +// RegisterCodec registers all the necessary types and interfaces for the +// governance module. func RegisterCodec(cdc *codec.Codec) { cdc.RegisterInterface((*Content)(nil), nil) - cdc.RegisterConcrete(MsgSubmitProposal{}, "cosmos-sdk/MsgSubmitProposal", nil) cdc.RegisterConcrete(MsgDeposit{}, "cosmos-sdk/MsgDeposit", nil) cdc.RegisterConcrete(MsgVote{}, "cosmos-sdk/MsgVote", nil) - cdc.RegisterConcrete(TextProposal{}, "cosmos-sdk/TextProposal", nil) } // RegisterProposalTypeCodec registers an external proposal content type defined // in another module for the internal ModuleCdc. This allows the MsgSubmitProposal // to be correctly Amino encoded and decoded. +// +// NOTE: This should only be used for applications that are still using a concrete +// Amino codec for serialization. func RegisterProposalTypeCodec(o interface{}, name string) { - ModuleCdc.RegisterConcrete(o, name, nil) -} - -// TODO determine a good place to seal this codec -func init() { - RegisterCodec(ModuleCdc) -} - -type AminoGovCodec struct { - codec.Marshaler - amino *codec.Codec + amino.RegisterConcrete(o, name, nil) } -func NewAminoGovCodec(amino *codec.Codec) AminoGovCodec { - return AminoGovCodec{Marshaler: codec.NewHybridCodec(amino), amino: amino} -} +var ( + amino = codec.New() -func (a AminoGovCodec) MarshalProposal(p Proposal) ([]byte, error) { - return a.amino.MarshalBinaryBare(p) -} + // ModuleCdc references the global x/gov module codec. Note, the codec should + // ONLY be used in certain instances of tests and for JSON encoding as Amino is + // still used for that purpose. + // + // The actual codec used for serialization should be provided to x/gov and + // defined at the application level. + ModuleCdc = codec.NewHybridCodec(amino) +) -func (a AminoGovCodec) UnmarshalProposal(bz []byte, ptr *Proposal) error { - return a.amino.UnmarshalBinaryBare(bz, ptr) +func init() { + RegisterCodec(amino) + codec.RegisterCrypto(amino) } - -var _ Codec = AminoGovCodec{} From c3b18dfb2f544006b56101e83dffbe29a03d8a28 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 2 Mar 2020 17:55:31 +0100 Subject: [PATCH 314/529] migrate TestTallyOnlyValidatorsVetoed test --- x/gov/keeper/old_tally_test.go | 25 ------------------------- x/gov/keeper/tally_test.go | 32 +++++++++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/x/gov/keeper/old_tally_test.go b/x/gov/keeper/old_tally_test.go index a30f9848f97c..79795c860184 100644 --- a/x/gov/keeper/old_tally_test.go +++ b/x/gov/keeper/old_tally_test.go @@ -10,31 +10,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking" ) -func TestTallyOnlyValidatorsVetoed(t *testing.T) { - ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) - createValidators(ctx, sk, []int64{6, 6, 7}) - - tp := TestProposal - proposal, err := keeper.SubmitProposal(ctx, tp) - require.NoError(t, err) - proposalID := proposal.ProposalID - proposal.Status = types.StatusVotingPeriod - keeper.SetProposal(ctx, proposal) - - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionYes)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionYes)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr3, types.OptionNoWithVeto)) - - proposal, ok := keeper.GetProposal(ctx, proposalID) - require.True(t, ok) - passes, burnDeposits, tallyResults := keeper.Tally(ctx, proposal) - - require.False(t, passes) - require.True(t, burnDeposits) - require.False(t, tallyResults.Equals(types.EmptyTallyResult())) - -} - func TestTallyOnlyValidatorsAbstainPasses(t *testing.T) { ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{6, 6, 7}) diff --git a/x/gov/keeper/tally_test.go b/x/gov/keeper/tally_test.go index eb5f7a96246d..674d504ce844 100644 --- a/x/gov/keeper/tally_test.go +++ b/x/gov/keeper/tally_test.go @@ -114,7 +114,6 @@ func TestTallyOnlyValidators51Yes(t *testing.T) { ctx := app.BaseApp.NewContext(false, abci.Header{}) valAccAddrs, _ := createValidators(ctx, app, []int64{5, 6, 0}) - valAccAddr1, valAccAddr2 := valAccAddrs[0], valAccAddrs[1] tp := TestProposal proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) @@ -123,8 +122,8 @@ func TestTallyOnlyValidators51Yes(t *testing.T) { proposal.Status = types.StatusVotingPeriod app.GovKeeper.SetProposal(ctx, proposal) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionNo)) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionYes)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[0], types.OptionNo)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[1], types.OptionYes)) proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID) require.True(t, ok) @@ -134,3 +133,30 @@ func TestTallyOnlyValidators51Yes(t *testing.T) { require.False(t, burnDeposits) require.False(t, tallyResults.Equals(types.EmptyTallyResult())) } + +func TestTallyOnlyValidatorsVetoed(t *testing.T) { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + valAccAddrs, _ := createValidators(ctx, app, []int64{6, 6, 7}) + valAccAddr1, valAccAddr2, valAccAddr3 := valAccAddrs[0], valAccAddrs[1], valAccAddrs[2] + + tp := TestProposal + proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) + require.NoError(t, err) + proposalID := proposal.ProposalID + proposal.Status = types.StatusVotingPeriod + app.GovKeeper.SetProposal(ctx, proposal) + + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionYes)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionYes)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr3, types.OptionNoWithVeto)) + + proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID) + require.True(t, ok) + passes, burnDeposits, tallyResults := app.GovKeeper.Tally(ctx, proposal) + + require.False(t, passes) + require.True(t, burnDeposits) + require.False(t, tallyResults.Equals(types.EmptyTallyResult())) +} From b83755fc1df09e865cfc228fc3cbf022d84a8bef Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 2 Mar 2020 17:57:39 +0100 Subject: [PATCH 315/529] migrate TestTallyOnlyValidatorsAbstainPasses to simapp --- x/gov/keeper/old_tally_test.go | 24 ------------------------ x/gov/keeper/tally_test.go | 27 +++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 24 deletions(-) diff --git a/x/gov/keeper/old_tally_test.go b/x/gov/keeper/old_tally_test.go index 79795c860184..16b2d4995aac 100644 --- a/x/gov/keeper/old_tally_test.go +++ b/x/gov/keeper/old_tally_test.go @@ -10,30 +10,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking" ) -func TestTallyOnlyValidatorsAbstainPasses(t *testing.T) { - ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) - createValidators(ctx, sk, []int64{6, 6, 7}) - - tp := TestProposal - proposal, err := keeper.SubmitProposal(ctx, tp) - require.NoError(t, err) - proposalID := proposal.ProposalID - proposal.Status = types.StatusVotingPeriod - keeper.SetProposal(ctx, proposal) - - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionAbstain)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionNo)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr3, types.OptionYes)) - - proposal, ok := keeper.GetProposal(ctx, proposalID) - require.True(t, ok) - passes, burnDeposits, tallyResults := keeper.Tally(ctx, proposal) - - require.True(t, passes) - require.False(t, burnDeposits) - require.False(t, tallyResults.Equals(types.EmptyTallyResult())) -} - func TestTallyOnlyValidatorsAbstainFails(t *testing.T) { ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{6, 6, 7}) diff --git a/x/gov/keeper/tally_test.go b/x/gov/keeper/tally_test.go index 674d504ce844..23c9f6b2bd8c 100644 --- a/x/gov/keeper/tally_test.go +++ b/x/gov/keeper/tally_test.go @@ -160,3 +160,30 @@ func TestTallyOnlyValidatorsVetoed(t *testing.T) { require.True(t, burnDeposits) require.False(t, tallyResults.Equals(types.EmptyTallyResult())) } + +func TestTallyOnlyValidatorsAbstainPasses(t *testing.T) { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + valAccAddrs, _ := createValidators(ctx, app, []int64{6, 6, 7}) + valAccAddr1, valAccAddr2, valAccAddr3 := valAccAddrs[0], valAccAddrs[1], valAccAddrs[2] + + tp := TestProposal + proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) + require.NoError(t, err) + proposalID := proposal.ProposalID + proposal.Status = types.StatusVotingPeriod + app.GovKeeper.SetProposal(ctx, proposal) + + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionAbstain)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionNo)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr3, types.OptionYes)) + + proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID) + require.True(t, ok) + passes, burnDeposits, tallyResults := app.GovKeeper.Tally(ctx, proposal) + + require.True(t, passes) + require.False(t, burnDeposits) + require.False(t, tallyResults.Equals(types.EmptyTallyResult())) +} From 759181c2ccb85de91f34217855165e2ef3ef2a0d Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 2 Mar 2020 17:59:24 +0100 Subject: [PATCH 316/529] migrate TestTallyOnlyValidatorsAbstainFails into simapp --- x/gov/keeper/old_tally_test.go | 24 --------------------- x/gov/keeper/tally_test.go | 39 ++++++++++++++++++++++++++++------ 2 files changed, 32 insertions(+), 31 deletions(-) diff --git a/x/gov/keeper/old_tally_test.go b/x/gov/keeper/old_tally_test.go index 16b2d4995aac..e68f182a1d06 100644 --- a/x/gov/keeper/old_tally_test.go +++ b/x/gov/keeper/old_tally_test.go @@ -10,30 +10,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking" ) -func TestTallyOnlyValidatorsAbstainFails(t *testing.T) { - ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) - createValidators(ctx, sk, []int64{6, 6, 7}) - - tp := TestProposal - proposal, err := keeper.SubmitProposal(ctx, tp) - require.NoError(t, err) - proposalID := proposal.ProposalID - proposal.Status = types.StatusVotingPeriod - keeper.SetProposal(ctx, proposal) - - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionAbstain)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionYes)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr3, types.OptionNo)) - - proposal, ok := keeper.GetProposal(ctx, proposalID) - require.True(t, ok) - passes, burnDeposits, tallyResults := keeper.Tally(ctx, proposal) - - require.False(t, passes) - require.False(t, burnDeposits) - require.False(t, tallyResults.Equals(types.EmptyTallyResult())) -} - func TestTallyOnlyValidatorsNonVoter(t *testing.T) { ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{5, 6, 7}) diff --git a/x/gov/keeper/tally_test.go b/x/gov/keeper/tally_test.go index 23c9f6b2bd8c..099659f22d51 100644 --- a/x/gov/keeper/tally_test.go +++ b/x/gov/keeper/tally_test.go @@ -139,7 +139,6 @@ func TestTallyOnlyValidatorsVetoed(t *testing.T) { ctx := app.BaseApp.NewContext(false, abci.Header{}) valAccAddrs, _ := createValidators(ctx, app, []int64{6, 6, 7}) - valAccAddr1, valAccAddr2, valAccAddr3 := valAccAddrs[0], valAccAddrs[1], valAccAddrs[2] tp := TestProposal proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) @@ -148,9 +147,9 @@ func TestTallyOnlyValidatorsVetoed(t *testing.T) { proposal.Status = types.StatusVotingPeriod app.GovKeeper.SetProposal(ctx, proposal) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionYes)) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionYes)) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr3, types.OptionNoWithVeto)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[0], types.OptionYes)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[1], types.OptionYes)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[2], types.OptionNoWithVeto)) proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID) require.True(t, ok) @@ -165,6 +164,32 @@ func TestTallyOnlyValidatorsAbstainPasses(t *testing.T) { app := simapp.Setup(false) ctx := app.BaseApp.NewContext(false, abci.Header{}) + valAccAddrs, _ := createValidators(ctx, app, []int64{6, 6, 7}) + + tp := TestProposal + proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) + require.NoError(t, err) + proposalID := proposal.ProposalID + proposal.Status = types.StatusVotingPeriod + app.GovKeeper.SetProposal(ctx, proposal) + + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[0], types.OptionAbstain)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[1], types.OptionNo)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[2], types.OptionYes)) + + proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID) + require.True(t, ok) + passes, burnDeposits, tallyResults := app.GovKeeper.Tally(ctx, proposal) + + require.True(t, passes) + require.False(t, burnDeposits) + require.False(t, tallyResults.Equals(types.EmptyTallyResult())) +} + +func TestTallyOnlyValidatorsAbstainFails(t *testing.T) { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + valAccAddrs, _ := createValidators(ctx, app, []int64{6, 6, 7}) valAccAddr1, valAccAddr2, valAccAddr3 := valAccAddrs[0], valAccAddrs[1], valAccAddrs[2] @@ -176,14 +201,14 @@ func TestTallyOnlyValidatorsAbstainPasses(t *testing.T) { app.GovKeeper.SetProposal(ctx, proposal) require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionAbstain)) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionNo)) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr3, types.OptionYes)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionYes)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr3, types.OptionNo)) proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID) require.True(t, ok) passes, burnDeposits, tallyResults := app.GovKeeper.Tally(ctx, proposal) - require.True(t, passes) + require.False(t, passes) require.False(t, burnDeposits) require.False(t, tallyResults.Equals(types.EmptyTallyResult())) } From 46a70d58fab1ed5467d7761bccd80b26aa35ac4e Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 2 Mar 2020 18:01:10 +0100 Subject: [PATCH 317/529] migrate TestTallyOnlyValidatorsNonVoter to simapp --- x/gov/keeper/old_tally_test.go | 23 ----------------------- x/gov/keeper/tally_test.go | 26 ++++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/x/gov/keeper/old_tally_test.go b/x/gov/keeper/old_tally_test.go index e68f182a1d06..ab324dfcb597 100644 --- a/x/gov/keeper/old_tally_test.go +++ b/x/gov/keeper/old_tally_test.go @@ -10,29 +10,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking" ) -func TestTallyOnlyValidatorsNonVoter(t *testing.T) { - ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) - createValidators(ctx, sk, []int64{5, 6, 7}) - - tp := TestProposal - proposal, err := keeper.SubmitProposal(ctx, tp) - require.NoError(t, err) - proposalID := proposal.ProposalID - proposal.Status = types.StatusVotingPeriod - keeper.SetProposal(ctx, proposal) - - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionYes)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionNo)) - - proposal, ok := keeper.GetProposal(ctx, proposalID) - require.True(t, ok) - passes, burnDeposits, tallyResults := keeper.Tally(ctx, proposal) - - require.False(t, passes) - require.False(t, burnDeposits) - require.False(t, tallyResults.Equals(types.EmptyTallyResult())) -} - func TestTallyDelgatorOverride(t *testing.T) { ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{5, 6, 7}) diff --git a/x/gov/keeper/tally_test.go b/x/gov/keeper/tally_test.go index 099659f22d51..920f66c5831b 100644 --- a/x/gov/keeper/tally_test.go +++ b/x/gov/keeper/tally_test.go @@ -212,3 +212,29 @@ func TestTallyOnlyValidatorsAbstainFails(t *testing.T) { require.False(t, burnDeposits) require.False(t, tallyResults.Equals(types.EmptyTallyResult())) } + +func TestTallyOnlyValidatorsNonVoter(t *testing.T) { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + valAccAddrs, _ := createValidators(ctx, app, []int64{5, 6, 7}) + valAccAddr1, valAccAddr2 := valAccAddrs[0], valAccAddrs[1] + + tp := TestProposal + proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) + require.NoError(t, err) + proposalID := proposal.ProposalID + proposal.Status = types.StatusVotingPeriod + app.GovKeeper.SetProposal(ctx, proposal) + + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionYes)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionNo)) + + proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID) + require.True(t, ok) + passes, burnDeposits, tallyResults := app.GovKeeper.Tally(ctx, proposal) + + require.False(t, passes) + require.False(t, burnDeposits) + require.False(t, tallyResults.Equals(types.EmptyTallyResult())) +} From 9f251885f1a5754b6048b24a0d773d5e76f77d55 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 2 Mar 2020 18:08:40 +0100 Subject: [PATCH 318/529] migreate TestTallyDelgatorOverride to simapp --- x/gov/keeper/common_test.go | 4 +-- x/gov/keeper/old_tally_test.go | 34 ------------------------ x/gov/keeper/tally_test.go | 47 +++++++++++++++++++++++++++++++--- 3 files changed, 45 insertions(+), 40 deletions(-) diff --git a/x/gov/keeper/common_test.go b/x/gov/keeper/common_test.go index 81b859973fd4..3796596127ed 100644 --- a/x/gov/keeper/common_test.go +++ b/x/gov/keeper/common_test.go @@ -24,9 +24,9 @@ func ProposalEqual(proposalA types.Proposal, proposalB types.Proposal) bool { } func createValidators(ctx sdk.Context, app *simapp.SimApp, powers []int64) ([]sdk.AccAddress, []sdk.ValAddress) { - addrs := simapp.AddTestAddrsIncremental(app, ctx, 3, sdk.NewInt(10000000)) + addrs := simapp.AddTestAddrsIncremental(app, ctx, 5, sdk.NewInt(30000000)) valAddrs := simapp.ConvertAddrsToValAddrs(addrs) - pks := simapp.CreateTestPubKeys(3) + pks := simapp.CreateTestPubKeys(5) appCodec := codec.NewAppCodec(app.Codec()) app.StakingKeeper = staking.NewKeeper( diff --git a/x/gov/keeper/old_tally_test.go b/x/gov/keeper/old_tally_test.go index ab324dfcb597..f3b23eea639a 100644 --- a/x/gov/keeper/old_tally_test.go +++ b/x/gov/keeper/old_tally_test.go @@ -10,40 +10,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking" ) -func TestTallyDelgatorOverride(t *testing.T) { - ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) - createValidators(ctx, sk, []int64{5, 6, 7}) - - delTokens := sdk.TokensFromConsensusPower(30) - val1, found := sk.GetValidator(ctx, valOpAddr1) - require.True(t, found) - - _, err := sk.Delegate(ctx, TestAddrs[0], delTokens, sdk.Unbonded, val1, true) - require.NoError(t, err) - - _ = staking.EndBlocker(ctx, sk) - - tp := TestProposal - proposal, err := keeper.SubmitProposal(ctx, tp) - require.NoError(t, err) - proposalID := proposal.ProposalID - proposal.Status = types.StatusVotingPeriod - keeper.SetProposal(ctx, proposal) - - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionYes)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionYes)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr3, types.OptionYes)) - require.NoError(t, keeper.AddVote(ctx, proposalID, TestAddrs[0], types.OptionNo)) - - proposal, ok := keeper.GetProposal(ctx, proposalID) - require.True(t, ok) - passes, burnDeposits, tallyResults := keeper.Tally(ctx, proposal) - - require.False(t, passes) - require.False(t, burnDeposits) - require.False(t, tallyResults.Equals(types.EmptyTallyResult())) -} - func TestTallyDelgatorInherit(t *testing.T) { ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{5, 6, 7}) diff --git a/x/gov/keeper/tally_test.go b/x/gov/keeper/tally_test.go index 920f66c5831b..cee137b5bfe0 100644 --- a/x/gov/keeper/tally_test.go +++ b/x/gov/keeper/tally_test.go @@ -3,6 +3,8 @@ package keeper_test import ( "testing" + "github.com/cosmos/cosmos-sdk/x/staking" + "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" @@ -191,7 +193,6 @@ func TestTallyOnlyValidatorsAbstainFails(t *testing.T) { ctx := app.BaseApp.NewContext(false, abci.Header{}) valAccAddrs, _ := createValidators(ctx, app, []int64{6, 6, 7}) - valAccAddr1, valAccAddr2, valAccAddr3 := valAccAddrs[0], valAccAddrs[1], valAccAddrs[2] tp := TestProposal proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) @@ -200,9 +201,9 @@ func TestTallyOnlyValidatorsAbstainFails(t *testing.T) { proposal.Status = types.StatusVotingPeriod app.GovKeeper.SetProposal(ctx, proposal) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionAbstain)) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionYes)) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr3, types.OptionNo)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[0], types.OptionAbstain)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[1], types.OptionYes)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[2], types.OptionNo)) proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID) require.True(t, ok) @@ -238,3 +239,41 @@ func TestTallyOnlyValidatorsNonVoter(t *testing.T) { require.False(t, burnDeposits) require.False(t, tallyResults.Equals(types.EmptyTallyResult())) } + +func TestTallyDelgatorOverride(t *testing.T) { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + addrs, valAddrs := createValidators(ctx, app, []int64{5, 6, 7}) + valOpAddr1 := valAddrs[0] + valAccAddr1, valAccAddr2, valAccAddr3, valAccAddr4 := addrs[1], addrs[2], addrs[3], addrs[4] + + delTokens := sdk.TokensFromConsensusPower(30) + val1, found := app.StakingKeeper.GetValidator(ctx, valOpAddr1) + require.True(t, found) + + _, err := app.StakingKeeper.Delegate(ctx, valAccAddr4, delTokens, sdk.Unbonded, val1, true) + require.NoError(t, err) + + _ = staking.EndBlocker(ctx, app.StakingKeeper) + + tp := TestProposal + proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) + require.NoError(t, err) + proposalID := proposal.ProposalID + proposal.Status = types.StatusVotingPeriod + app.GovKeeper.SetProposal(ctx, proposal) + + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionYes)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionYes)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr3, types.OptionYes)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr4, types.OptionNo)) + + proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID) + require.True(t, ok) + passes, burnDeposits, tallyResults := app.GovKeeper.Tally(ctx, proposal) + + require.False(t, passes) + require.False(t, burnDeposits) + require.False(t, tallyResults.Equals(types.EmptyTallyResult())) +} From 725e2dc2b45ca3f8dba51f305837836147371f10 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Mon, 2 Mar 2020 12:44:55 -0500 Subject: [PATCH 319/529] Update gov codec interface --- codec/std/std.pb.go | 1015 -------------------------- codec/std/std.proto | 28 - simapp/codec/codec.go | 36 +- simapp/codec/codec.pb.go | 1460 ++++++++++++++++++++++++++++++-------- simapp/codec/codec.proto | 25 + x/gov/alias.go | 1 + x/gov/types/codec.go | 4 +- x/gov/types/proposal.go | 18 +- x/gov/types/types.proto | 14 - 9 files changed, 1217 insertions(+), 1384 deletions(-) delete mode 100644 codec/std/std.pb.go delete mode 100644 codec/std/std.proto diff --git a/codec/std/std.pb.go b/codec/std/std.pb.go deleted file mode 100644 index 985a5f8b5ff4..000000000000 --- a/codec/std/std.pb.go +++ /dev/null @@ -1,1015 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: codec/std/std.proto - -package std - -import ( - fmt "fmt" - types2 "github.com/cosmos/cosmos-sdk/x/distribution/types" - github_com_cosmos_cosmos_sdk_x_gov_types "github.com/cosmos/cosmos-sdk/x/gov/types" - types "github.com/cosmos/cosmos-sdk/x/gov/types" - proposal "github.com/cosmos/cosmos-sdk/x/params/types/proposal" - types1 "github.com/cosmos/cosmos-sdk/x/upgrade/types" - _ "github.com/gogo/protobuf/gogoproto" - proto "github.com/gogo/protobuf/proto" - _ "github.com/regen-network/cosmos-proto" - io "io" - math "math" - math_bits "math/bits" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package - -type StdProposal struct { - types.ProposalBase `protobuf:"bytes,1,opt,name=base,proto3,embedded=base" json:"base"` - Content StdProposal_Content `protobuf:"bytes,2,opt,name=content,proto3" json:"content"` -} - -func (m *StdProposal) Reset() { *m = StdProposal{} } -func (m *StdProposal) String() string { return proto.CompactTextString(m) } -func (*StdProposal) ProtoMessage() {} -func (*StdProposal) Descriptor() ([]byte, []int) { - return fileDescriptor_bfdf2c6f71a73b14, []int{0} -} -func (m *StdProposal) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *StdProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_StdProposal.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 *StdProposal) XXX_Merge(src proto.Message) { - xxx_messageInfo_StdProposal.Merge(m, src) -} -func (m *StdProposal) XXX_Size() int { - return m.Size() -} -func (m *StdProposal) XXX_DiscardUnknown() { - xxx_messageInfo_StdProposal.DiscardUnknown(m) -} - -var xxx_messageInfo_StdProposal proto.InternalMessageInfo - -func (m *StdProposal) GetContent() StdProposal_Content { - if m != nil { - return m.Content - } - return StdProposal_Content{} -} - -type StdProposal_Content struct { - // Types that are valid to be assigned to Sum: - // *StdProposal_Content_Text - // *StdProposal_Content_ParameterChange - // *StdProposal_Content_SoftwareUpgrade - // *StdProposal_Content_CancelSoftwareUpgrade - // *StdProposal_Content_CommunityPoolSpend - Sum isStdProposal_Content_Sum `protobuf_oneof:"sum"` -} - -func (m *StdProposal_Content) Reset() { *m = StdProposal_Content{} } -func (m *StdProposal_Content) String() string { return proto.CompactTextString(m) } -func (*StdProposal_Content) ProtoMessage() {} -func (*StdProposal_Content) Descriptor() ([]byte, []int) { - return fileDescriptor_bfdf2c6f71a73b14, []int{0, 0} -} -func (m *StdProposal_Content) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *StdProposal_Content) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_StdProposal_Content.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 *StdProposal_Content) XXX_Merge(src proto.Message) { - xxx_messageInfo_StdProposal_Content.Merge(m, src) -} -func (m *StdProposal_Content) XXX_Size() int { - return m.Size() -} -func (m *StdProposal_Content) XXX_DiscardUnknown() { - xxx_messageInfo_StdProposal_Content.DiscardUnknown(m) -} - -var xxx_messageInfo_StdProposal_Content proto.InternalMessageInfo - -type isStdProposal_Content_Sum interface { - isStdProposal_Content_Sum() - MarshalTo([]byte) (int, error) - Size() int -} - -type StdProposal_Content_Text struct { - Text *types.TextProposal `protobuf:"bytes,1,opt,name=text,proto3,oneof" json:"text,omitempty"` -} -type StdProposal_Content_ParameterChange struct { - ParameterChange *proposal.ParameterChangeProposal `protobuf:"bytes,2,opt,name=parameter_change,json=parameterChange,proto3,oneof" json:"parameter_change,omitempty"` -} -type StdProposal_Content_SoftwareUpgrade struct { - SoftwareUpgrade *types1.SoftwareUpgradeProposal `protobuf:"bytes,3,opt,name=software_upgrade,json=softwareUpgrade,proto3,oneof" json:"software_upgrade,omitempty"` -} -type StdProposal_Content_CancelSoftwareUpgrade struct { - CancelSoftwareUpgrade *types1.CancelSoftwareUpgradeProposal `protobuf:"bytes,4,opt,name=cancel_software_upgrade,json=cancelSoftwareUpgrade,proto3,oneof" json:"cancel_software_upgrade,omitempty"` -} -type StdProposal_Content_CommunityPoolSpend struct { - CommunityPoolSpend *types2.CommunityPoolSpendProposal `protobuf:"bytes,5,opt,name=community_pool_spend,json=communityPoolSpend,proto3,oneof" json:"community_pool_spend,omitempty"` -} - -func (*StdProposal_Content_Text) isStdProposal_Content_Sum() {} -func (*StdProposal_Content_ParameterChange) isStdProposal_Content_Sum() {} -func (*StdProposal_Content_SoftwareUpgrade) isStdProposal_Content_Sum() {} -func (*StdProposal_Content_CancelSoftwareUpgrade) isStdProposal_Content_Sum() {} -func (*StdProposal_Content_CommunityPoolSpend) isStdProposal_Content_Sum() {} - -func (m *StdProposal_Content) GetSum() isStdProposal_Content_Sum { - if m != nil { - return m.Sum - } - return nil -} - -func (m *StdProposal_Content) GetText() *types.TextProposal { - if x, ok := m.GetSum().(*StdProposal_Content_Text); ok { - return x.Text - } - return nil -} - -func (m *StdProposal_Content) GetParameterChange() *proposal.ParameterChangeProposal { - if x, ok := m.GetSum().(*StdProposal_Content_ParameterChange); ok { - return x.ParameterChange - } - return nil -} - -func (m *StdProposal_Content) GetSoftwareUpgrade() *types1.SoftwareUpgradeProposal { - if x, ok := m.GetSum().(*StdProposal_Content_SoftwareUpgrade); ok { - return x.SoftwareUpgrade - } - return nil -} - -func (m *StdProposal_Content) GetCancelSoftwareUpgrade() *types1.CancelSoftwareUpgradeProposal { - if x, ok := m.GetSum().(*StdProposal_Content_CancelSoftwareUpgrade); ok { - return x.CancelSoftwareUpgrade - } - return nil -} - -func (m *StdProposal_Content) GetCommunityPoolSpend() *types2.CommunityPoolSpendProposal { - if x, ok := m.GetSum().(*StdProposal_Content_CommunityPoolSpend); ok { - return x.CommunityPoolSpend - } - return nil -} - -// XXX_OneofWrappers is for the internal use of the proto package. -func (*StdProposal_Content) XXX_OneofWrappers() []interface{} { - return []interface{}{ - (*StdProposal_Content_Text)(nil), - (*StdProposal_Content_ParameterChange)(nil), - (*StdProposal_Content_SoftwareUpgrade)(nil), - (*StdProposal_Content_CancelSoftwareUpgrade)(nil), - (*StdProposal_Content_CommunityPoolSpend)(nil), - } -} - -func init() { - proto.RegisterType((*StdProposal)(nil), "cosmos_sdk.x.v1.StdProposal") - proto.RegisterType((*StdProposal_Content)(nil), "cosmos_sdk.x.v1.StdProposal.Content") -} - -func init() { proto.RegisterFile("codec/std/std.proto", fileDescriptor_bfdf2c6f71a73b14) } - -var fileDescriptor_bfdf2c6f71a73b14 = []byte{ - // 492 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x93, 0x4f, 0x6f, 0xd3, 0x30, - 0x18, 0xc6, 0x13, 0x96, 0x32, 0xe4, 0x1d, 0x36, 0x05, 0xd0, 0xaa, 0x22, 0x65, 0xe3, 0x8f, 0x26, - 0x24, 0x34, 0x7b, 0x03, 0x04, 0x88, 0x0b, 0xa8, 0xe5, 0xc0, 0x71, 0xea, 0xe0, 0x82, 0x40, 0x91, - 0x6b, 0x9b, 0x34, 0x5a, 0x92, 0xd7, 0x8a, 0x9d, 0x92, 0x7e, 0x0b, 0x3e, 0x00, 0xdf, 0x02, 0x3e, - 0xc4, 0xc4, 0xa9, 0x47, 0x4e, 0x13, 0x6a, 0xbf, 0x08, 0xaa, 0xe3, 0x8c, 0x64, 0xdd, 0x76, 0x68, - 0x95, 0xf8, 0x7d, 0x9e, 0xdf, 0x63, 0xbf, 0xf1, 0x8b, 0x6e, 0x33, 0xe0, 0x82, 0x11, 0xa5, 0xf9, - 0xf2, 0x87, 0x65, 0x0e, 0x1a, 0xfc, 0x4d, 0x06, 0x2a, 0x05, 0x15, 0x2a, 0x7e, 0x82, 0x4b, 0x3c, - 0x39, 0xec, 0x3d, 0xd1, 0xe3, 0x38, 0xe7, 0xa1, 0xa4, 0xb9, 0x9e, 0x12, 0xa3, 0x21, 0x95, 0x64, - 0xbf, 0xf9, 0x52, 0xb9, 0x7b, 0x7b, 0xab, 0xe2, 0x08, 0x22, 0xf8, 0xff, 0x64, 0x75, 0xdb, 0x25, - 0x89, 0x60, 0x42, 0xf4, 0x54, 0x0a, 0x55, 0xfd, 0xdb, 0xc2, 0xc3, 0x92, 0x48, 0x9a, 0xd3, 0xd4, - 0xae, 0x2e, 0x19, 0x12, 0x14, 0x4d, 0x5a, 0xa2, 0x7b, 0x25, 0x29, 0x64, 0x94, 0x53, 0x2e, 0x2e, - 0x21, 0xec, 0x96, 0x84, 0xc7, 0x4a, 0xe7, 0xf1, 0xa8, 0xd0, 0x31, 0x64, 0xab, 0x8a, 0x07, 0x3f, - 0x3b, 0x68, 0xe3, 0x58, 0xf3, 0x23, 0x8b, 0xf6, 0xdf, 0x20, 0x6f, 0x44, 0x95, 0xe8, 0xba, 0xbb, - 0xee, 0xe3, 0x8d, 0xa7, 0xf7, 0x71, 0xab, 0x03, 0x11, 0x4c, 0xf0, 0xe4, 0x10, 0xd7, 0xe2, 0x3e, - 0x55, 0xa2, 0x7f, 0xeb, 0xf4, 0x6c, 0xc7, 0x99, 0x9d, 0xed, 0xb8, 0x43, 0x63, 0xf4, 0xdf, 0xa1, - 0x75, 0x06, 0x99, 0x16, 0x99, 0xee, 0xde, 0x30, 0x8c, 0x47, 0xf8, 0x42, 0x17, 0x71, 0x23, 0x0f, - 0x0f, 0x2a, 0x6d, 0xdf, 0x5b, 0x62, 0x86, 0xb5, 0xb5, 0xf7, 0xc3, 0x43, 0xeb, 0xb6, 0xe4, 0xbf, - 0x44, 0x9e, 0x16, 0xa5, 0xbe, 0x76, 0x4b, 0x1f, 0x44, 0xa9, 0x6b, 0xe6, 0x7b, 0x67, 0x68, 0x0c, - 0xfe, 0x67, 0xb4, 0x65, 0xfa, 0x27, 0xb4, 0xc8, 0x43, 0x36, 0xa6, 0x59, 0x24, 0xec, 0x9e, 0x48, - 0x1b, 0x52, 0x75, 0xd9, 0x1c, 0xad, 0xd6, 0x0f, 0x8c, 0xbc, 0x81, 0xdc, 0x94, 0xed, 0x92, 0xff, - 0x05, 0x6d, 0x29, 0xf8, 0xaa, 0xbf, 0xd1, 0x5c, 0x84, 0xf6, 0x0b, 0x74, 0xd7, 0x0c, 0xfd, 0xa0, - 0x4d, 0xb7, 0x45, 0x73, 0x72, 0x6b, 0xf8, 0x58, 0x2d, 0x35, 0xf1, 0xaa, 0x5d, 0xf2, 0x25, 0xda, - 0x66, 0x34, 0x63, 0x22, 0x09, 0x57, 0x52, 0x3c, 0x93, 0xf2, 0xe2, 0xca, 0x94, 0x81, 0xf1, 0x5d, - 0x9d, 0x75, 0x97, 0x5d, 0x26, 0xf0, 0x13, 0x74, 0x87, 0x41, 0x9a, 0x16, 0x59, 0xac, 0xa7, 0xa1, - 0x04, 0x48, 0x42, 0x25, 0x45, 0xc6, 0xbb, 0x1d, 0x13, 0xf7, 0xaa, 0x1d, 0xd7, 0xbc, 0x56, 0x26, - 0xb3, 0x76, 0x1e, 0x01, 0x24, 0xc7, 0x4b, 0x5f, 0x23, 0xd0, 0x67, 0x2b, 0xd5, 0xd7, 0xcf, 0x7f, - 0xff, 0xda, 0x3f, 0x88, 0x62, 0x3d, 0x2e, 0x46, 0x98, 0x41, 0x6a, 0x47, 0xa7, 0x1e, 0x27, 0xc5, - 0x4f, 0x48, 0x63, 0x2c, 0xce, 0xaf, 0x49, 0x07, 0xad, 0xa9, 0x22, 0xed, 0xbf, 0x3d, 0x9d, 0x07, - 0xee, 0x6c, 0x1e, 0xb8, 0x7f, 0xe7, 0x81, 0xfb, 0x7d, 0x11, 0x38, 0xb3, 0x45, 0xe0, 0xfc, 0x59, - 0x04, 0xce, 0xa7, 0xbd, 0x6b, 0x91, 0xe7, 0x43, 0x3e, 0xba, 0x69, 0xae, 0xff, 0xb3, 0x7f, 0x01, - 0x00, 0x00, 0xff, 0xff, 0x30, 0x48, 0xf7, 0x0e, 0xf8, 0x03, 0x00, 0x00, -} - -func (this *StdProposal_Content) GetContent() github_com_cosmos_cosmos_sdk_x_gov_types.Content { - if x := this.GetText(); x != nil { - return x - } - if x := this.GetParameterChange(); x != nil { - return x - } - if x := this.GetSoftwareUpgrade(); x != nil { - return x - } - if x := this.GetCancelSoftwareUpgrade(); x != nil { - return x - } - if x := this.GetCommunityPoolSpend(); x != nil { - return x - } - return nil -} - -func (this *StdProposal_Content) SetContent(value github_com_cosmos_cosmos_sdk_x_gov_types.Content) error { - if value == nil { - this.Sum = nil - return nil - } - switch vt := value.(type) { - case *types.TextProposal: - this.Sum = &StdProposal_Content_Text{vt} - return nil - case types.TextProposal: - this.Sum = &StdProposal_Content_Text{&vt} - return nil - case *proposal.ParameterChangeProposal: - this.Sum = &StdProposal_Content_ParameterChange{vt} - return nil - case proposal.ParameterChangeProposal: - this.Sum = &StdProposal_Content_ParameterChange{&vt} - return nil - case *types1.SoftwareUpgradeProposal: - this.Sum = &StdProposal_Content_SoftwareUpgrade{vt} - return nil - case types1.SoftwareUpgradeProposal: - this.Sum = &StdProposal_Content_SoftwareUpgrade{&vt} - return nil - case *types1.CancelSoftwareUpgradeProposal: - this.Sum = &StdProposal_Content_CancelSoftwareUpgrade{vt} - return nil - case types1.CancelSoftwareUpgradeProposal: - this.Sum = &StdProposal_Content_CancelSoftwareUpgrade{&vt} - return nil - case *types2.CommunityPoolSpendProposal: - this.Sum = &StdProposal_Content_CommunityPoolSpend{vt} - return nil - case types2.CommunityPoolSpendProposal: - this.Sum = &StdProposal_Content_CommunityPoolSpend{&vt} - return nil - } - return fmt.Errorf("can't encode value of type %T as message StdProposal_Content", value) -} - -func (m *StdProposal) 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 *StdProposal) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *StdProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - { - size, err := m.Content.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintStd(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - { - size, err := m.ProposalBase.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintStd(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil -} - -func (m *StdProposal_Content) 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 *StdProposal_Content) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *StdProposal_Content) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Sum != nil { - { - size := m.Sum.Size() - i -= size - if _, err := m.Sum.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - } - } - return len(dAtA) - i, nil -} - -func (m *StdProposal_Content_Text) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *StdProposal_Content_Text) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - if m.Text != nil { - { - size, err := m.Text.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintStd(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} -func (m *StdProposal_Content_ParameterChange) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *StdProposal_Content_ParameterChange) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - if m.ParameterChange != nil { - { - size, err := m.ParameterChange.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintStd(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - } - return len(dAtA) - i, nil -} -func (m *StdProposal_Content_SoftwareUpgrade) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *StdProposal_Content_SoftwareUpgrade) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - if m.SoftwareUpgrade != nil { - { - size, err := m.SoftwareUpgrade.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintStd(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x1a - } - return len(dAtA) - i, nil -} -func (m *StdProposal_Content_CancelSoftwareUpgrade) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *StdProposal_Content_CancelSoftwareUpgrade) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - if m.CancelSoftwareUpgrade != nil { - { - size, err := m.CancelSoftwareUpgrade.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintStd(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x22 - } - return len(dAtA) - i, nil -} -func (m *StdProposal_Content_CommunityPoolSpend) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *StdProposal_Content_CommunityPoolSpend) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - if m.CommunityPoolSpend != nil { - { - size, err := m.CommunityPoolSpend.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintStd(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x2a - } - return len(dAtA) - i, nil -} -func encodeVarintStd(dAtA []byte, offset int, v uint64) int { - offset -= sovStd(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *StdProposal) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = m.ProposalBase.Size() - n += 1 + l + sovStd(uint64(l)) - l = m.Content.Size() - n += 1 + l + sovStd(uint64(l)) - return n -} - -func (m *StdProposal_Content) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Sum != nil { - n += m.Sum.Size() - } - return n -} - -func (m *StdProposal_Content_Text) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Text != nil { - l = m.Text.Size() - n += 1 + l + sovStd(uint64(l)) - } - return n -} -func (m *StdProposal_Content_ParameterChange) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.ParameterChange != nil { - l = m.ParameterChange.Size() - n += 1 + l + sovStd(uint64(l)) - } - return n -} -func (m *StdProposal_Content_SoftwareUpgrade) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.SoftwareUpgrade != nil { - l = m.SoftwareUpgrade.Size() - n += 1 + l + sovStd(uint64(l)) - } - return n -} -func (m *StdProposal_Content_CancelSoftwareUpgrade) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.CancelSoftwareUpgrade != nil { - l = m.CancelSoftwareUpgrade.Size() - n += 1 + l + sovStd(uint64(l)) - } - return n -} -func (m *StdProposal_Content_CommunityPoolSpend) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.CommunityPoolSpend != nil { - l = m.CommunityPoolSpend.Size() - n += 1 + l + sovStd(uint64(l)) - } - return n -} - -func sovStd(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozStd(x uint64) (n int) { - return sovStd(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *StdProposal) 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 ErrIntOverflowStd - } - 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: StdProposal: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: StdProposal: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ProposalBase", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowStd - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthStd - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthStd - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.ProposalBase.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Content", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowStd - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthStd - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthStd - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.Content.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipStd(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthStd - } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthStd - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *StdProposal_Content) 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 ErrIntOverflowStd - } - 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: Content: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: Content: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Text", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowStd - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthStd - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthStd - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - v := &types.TextProposal{} - if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - m.Sum = &StdProposal_Content_Text{v} - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ParameterChange", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowStd - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthStd - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthStd - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - v := &proposal.ParameterChangeProposal{} - if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - m.Sum = &StdProposal_Content_ParameterChange{v} - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field SoftwareUpgrade", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowStd - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthStd - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthStd - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - v := &types1.SoftwareUpgradeProposal{} - if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - m.Sum = &StdProposal_Content_SoftwareUpgrade{v} - iNdEx = postIndex - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field CancelSoftwareUpgrade", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowStd - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthStd - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthStd - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - v := &types1.CancelSoftwareUpgradeProposal{} - if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - m.Sum = &StdProposal_Content_CancelSoftwareUpgrade{v} - iNdEx = postIndex - case 5: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field CommunityPoolSpend", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowStd - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthStd - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthStd - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - v := &types2.CommunityPoolSpendProposal{} - if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - m.Sum = &StdProposal_Content_CommunityPoolSpend{v} - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipStd(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthStd - } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthStd - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func skipStd(dAtA []byte) (n int, err error) { - l := len(dAtA) - iNdEx := 0 - depth := 0 - for iNdEx < l { - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowStd - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - wireType := int(wire & 0x7) - switch wireType { - case 0: - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowStd - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - iNdEx++ - if dAtA[iNdEx-1] < 0x80 { - break - } - } - case 1: - iNdEx += 8 - case 2: - var length int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowStd - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - length |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if length < 0 { - return 0, ErrInvalidLengthStd - } - iNdEx += length - case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupStd - } - depth-- - case 5: - iNdEx += 4 - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - if iNdEx < 0 { - return 0, ErrInvalidLengthStd - } - if depth == 0 { - return iNdEx, nil - } - } - return 0, io.ErrUnexpectedEOF -} - -var ( - ErrInvalidLengthStd = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowStd = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupStd = fmt.Errorf("proto: unexpected end of group") -) diff --git a/codec/std/std.proto b/codec/std/std.proto deleted file mode 100644 index a99d35fb4676..000000000000 --- a/codec/std/std.proto +++ /dev/null @@ -1,28 +0,0 @@ -syntax = "proto3"; -package cosmos_sdk.x.v1; - -import "third_party/proto/cosmos-proto/cosmos.proto"; -import "third_party/proto/gogoproto/gogo.proto"; -import "x/gov/types/types.proto"; -import "x/params/types/proposal/types.proto"; -import "x/upgrade/types/types.proto"; -import "x/distribution/types/types.proto"; - -option go_package = "github.com/cosmos/cosmos-sdk/codec/std"; - -message StdProposal { - cosmos_sdk.x.gov.v1.ProposalBase base = 1 [(gogoproto.embed) = true, (gogoproto.nullable) = false]; - Content content = 2 [(gogoproto.nullable) = false]; - - message Content { - option (cosmos_proto.interface_type) = "github.com/cosmos/cosmos-sdk/x/gov/types.Content"; - oneof sum { - cosmos_sdk.x.gov.v1.TextProposal text = 1; - cosmos_sdk.x.params.v1.ParameterChangeProposal parameter_change = 2; - cosmos_sdk.x.upgrade.v1.SoftwareUpgradeProposal software_upgrade = 3; - cosmos_sdk.x.upgrade.v1.CancelSoftwareUpgradeProposal cancel_software_upgrade = 4; - cosmos_sdk.x.distribution.v1.CommunityPoolSpendProposal community_pool_spend = 5; - } - } -} - diff --git a/simapp/codec/codec.go b/simapp/codec/codec.go index 284e934e9e69..75dd59fb3512 100644 --- a/simapp/codec/codec.go +++ b/simapp/codec/codec.go @@ -2,7 +2,6 @@ package codec import ( "github.com/cosmos/cosmos-sdk/codec" - cosmos_sdk_x_v1 "github.com/cosmos/cosmos-sdk/codec/std" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/x/auth" @@ -10,7 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth/vesting" "github.com/cosmos/cosmos-sdk/x/evidence" eviexported "github.com/cosmos/cosmos-sdk/x/evidence/exported" - "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/cosmos/cosmos-sdk/x/gov" "github.com/cosmos/cosmos-sdk/x/supply" supplyexported "github.com/cosmos/cosmos-sdk/x/supply/exported" ) @@ -19,6 +18,7 @@ var ( _ auth.Codec = (*Codec)(nil) _ supply.Codec = (*Codec)(nil) _ evidence.Codec = (*Codec)(nil) + _ gov.Codec = (*Codec)(nil) ) // Codec defines the application-level codec. This codec contains all the @@ -153,25 +153,31 @@ func (c *Codec) UnmarshalEvidenceJSON(bz []byte) (eviexported.Evidence, error) { return evidence.GetEvidence(), nil } -func (c *Codec) MarshalProposal(p types.Proposal) ([]byte, error) { - stdProposal := &cosmos_sdk_x_v1.StdProposal{ProposalBase: p.ProposalBase} - if err := stdProposal.Content.SetContent(p.Content); err != nil { +// MarshalProposal marshals a Proposal. It accepts a Proposal defined by the x/gov +// module and uses the application-level Proposal type which has the concrete +// Content implementation to serialize. +func (c *Codec) MarshalProposal(p gov.Proposal) ([]byte, error) { + proposal := &Proposal{ProposalBase: p.ProposalBase} + if err := proposal.Content.SetContent(p.Content); err != nil { return nil, err } - return c.Marshaler.MarshalBinaryBare(stdProposal) + + return c.Marshaler.MarshalBinaryLengthPrefixed(proposal) } -func (c *Codec) UnmarshalProposal(bz []byte, p *types.Proposal) error { - stdProposal := &cosmos_sdk_x_v1.StdProposal{} - if err := c.Marshaler.UnmarshalBinaryLengthPrefixed(bz, stdProposal); err != nil { - return err +// UnmarshalProposal decodes a Proposal defined by the x/gov module and uses the +// application-level Proposal type which has the concrete Content implementation +// to deserialize. +func (c *Codec) UnmarshalProposal(bz []byte) (gov.Proposal, error) { + proposal := &Proposal{} + if err := c.Marshaler.UnmarshalBinaryLengthPrefixed(bz, proposal); err != nil { + return gov.Proposal{}, err } - *p = types.Proposal{ - Content: stdProposal.Content.GetContent(), - ProposalBase: stdProposal.ProposalBase, - } - return nil + return gov.Proposal{ + Content: proposal.Content.GetContent(), + ProposalBase: proposal.ProposalBase, + }, nil } // ---------------------------------------------------------------------------- diff --git a/simapp/codec/codec.pb.go b/simapp/codec/codec.pb.go index b222403b46e4..d58635ad89d8 100644 --- a/simapp/codec/codec.pb.go +++ b/simapp/codec/codec.pb.go @@ -8,10 +8,15 @@ import ( github_com_cosmos_cosmos_sdk_x_auth_exported "github.com/cosmos/cosmos-sdk/x/auth/exported" types "github.com/cosmos/cosmos-sdk/x/auth/types" types1 "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" + types6 "github.com/cosmos/cosmos-sdk/x/distribution/types" github_com_cosmos_cosmos_sdk_x_evidence_exported "github.com/cosmos/cosmos-sdk/x/evidence/exported" types3 "github.com/cosmos/cosmos-sdk/x/evidence/types" + github_com_cosmos_cosmos_sdk_x_gov_types "github.com/cosmos/cosmos-sdk/x/gov/types" + types4 "github.com/cosmos/cosmos-sdk/x/gov/types" + proposal "github.com/cosmos/cosmos-sdk/x/params/types/proposal" github_com_cosmos_cosmos_sdk_x_supply_exported "github.com/cosmos/cosmos-sdk/x/supply/exported" types2 "github.com/cosmos/cosmos-sdk/x/supply/types" + types5 "github.com/cosmos/cosmos-sdk/x/upgrade/types" _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" _ "github.com/regen-network/cosmos-proto" @@ -351,55 +356,246 @@ func (m *MsgSubmitEvidence) XXX_DiscardUnknown() { var xxx_messageInfo_MsgSubmitEvidence proto.InternalMessageInfo +// Proposal defines the application-level concrete proposal type used in governance +// proposals. +type Proposal struct { + types4.ProposalBase `protobuf:"bytes,1,opt,name=base,proto3,embedded=base" json:"base"` + Content Content `protobuf:"bytes,2,opt,name=content,proto3" json:"content"` +} + +func (m *Proposal) Reset() { *m = Proposal{} } +func (m *Proposal) String() string { return proto.CompactTextString(m) } +func (*Proposal) ProtoMessage() {} +func (*Proposal) Descriptor() ([]byte, []int) { + return fileDescriptor_3c6d4085e4065f5a, []int{4} +} +func (m *Proposal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Proposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Proposal.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 *Proposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_Proposal.Merge(m, src) +} +func (m *Proposal) XXX_Size() int { + return m.Size() +} +func (m *Proposal) XXX_DiscardUnknown() { + xxx_messageInfo_Proposal.DiscardUnknown(m) +} + +var xxx_messageInfo_Proposal proto.InternalMessageInfo + +func (m *Proposal) GetContent() Content { + if m != nil { + return m.Content + } + return Content{} +} + +// Content defines the application-level allowed Content to be included in a +// governance proposal. +type Content struct { + // Types that are valid to be assigned to Sum: + // *Content_Text + // *Content_ParameterChange + // *Content_SoftwareUpgrade + // *Content_CancelSoftwareUpgrade + // *Content_CommunityPoolSpend + Sum isContent_Sum `protobuf_oneof:"sum"` +} + +func (m *Content) Reset() { *m = Content{} } +func (m *Content) String() string { return proto.CompactTextString(m) } +func (*Content) ProtoMessage() {} +func (*Content) Descriptor() ([]byte, []int) { + return fileDescriptor_3c6d4085e4065f5a, []int{5} +} +func (m *Content) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Content) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Content.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 *Content) XXX_Merge(src proto.Message) { + xxx_messageInfo_Content.Merge(m, src) +} +func (m *Content) XXX_Size() int { + return m.Size() +} +func (m *Content) XXX_DiscardUnknown() { + xxx_messageInfo_Content.DiscardUnknown(m) +} + +var xxx_messageInfo_Content proto.InternalMessageInfo + +type isContent_Sum interface { + isContent_Sum() + MarshalTo([]byte) (int, error) + Size() int +} + +type Content_Text struct { + Text *types4.TextProposal `protobuf:"bytes,1,opt,name=text,proto3,oneof" json:"text,omitempty"` +} +type Content_ParameterChange struct { + ParameterChange *proposal.ParameterChangeProposal `protobuf:"bytes,2,opt,name=parameter_change,json=parameterChange,proto3,oneof" json:"parameter_change,omitempty"` +} +type Content_SoftwareUpgrade struct { + SoftwareUpgrade *types5.SoftwareUpgradeProposal `protobuf:"bytes,3,opt,name=software_upgrade,json=softwareUpgrade,proto3,oneof" json:"software_upgrade,omitempty"` +} +type Content_CancelSoftwareUpgrade struct { + CancelSoftwareUpgrade *types5.CancelSoftwareUpgradeProposal `protobuf:"bytes,4,opt,name=cancel_software_upgrade,json=cancelSoftwareUpgrade,proto3,oneof" json:"cancel_software_upgrade,omitempty"` +} +type Content_CommunityPoolSpend struct { + CommunityPoolSpend *types6.CommunityPoolSpendProposal `protobuf:"bytes,5,opt,name=community_pool_spend,json=communityPoolSpend,proto3,oneof" json:"community_pool_spend,omitempty"` +} + +func (*Content_Text) isContent_Sum() {} +func (*Content_ParameterChange) isContent_Sum() {} +func (*Content_SoftwareUpgrade) isContent_Sum() {} +func (*Content_CancelSoftwareUpgrade) isContent_Sum() {} +func (*Content_CommunityPoolSpend) isContent_Sum() {} + +func (m *Content) GetSum() isContent_Sum { + if m != nil { + return m.Sum + } + return nil +} + +func (m *Content) GetText() *types4.TextProposal { + if x, ok := m.GetSum().(*Content_Text); ok { + return x.Text + } + return nil +} + +func (m *Content) GetParameterChange() *proposal.ParameterChangeProposal { + if x, ok := m.GetSum().(*Content_ParameterChange); ok { + return x.ParameterChange + } + return nil +} + +func (m *Content) GetSoftwareUpgrade() *types5.SoftwareUpgradeProposal { + if x, ok := m.GetSum().(*Content_SoftwareUpgrade); ok { + return x.SoftwareUpgrade + } + return nil +} + +func (m *Content) GetCancelSoftwareUpgrade() *types5.CancelSoftwareUpgradeProposal { + if x, ok := m.GetSum().(*Content_CancelSoftwareUpgrade); ok { + return x.CancelSoftwareUpgrade + } + return nil +} + +func (m *Content) GetCommunityPoolSpend() *types6.CommunityPoolSpendProposal { + if x, ok := m.GetSum().(*Content_CommunityPoolSpend); ok { + return x.CommunityPoolSpend + } + return nil +} + +// XXX_OneofWrappers is for the internal use of the proto package. +func (*Content) XXX_OneofWrappers() []interface{} { + return []interface{}{ + (*Content_Text)(nil), + (*Content_ParameterChange)(nil), + (*Content_SoftwareUpgrade)(nil), + (*Content_CancelSoftwareUpgrade)(nil), + (*Content_CommunityPoolSpend)(nil), + } +} + func init() { proto.RegisterType((*Account)(nil), "cosmos_sdk.simapp.codec.v1.Account") proto.RegisterType((*Supply)(nil), "cosmos_sdk.simapp.codec.v1.Supply") proto.RegisterType((*Evidence)(nil), "cosmos_sdk.simapp.codec.v1.Evidence") proto.RegisterType((*MsgSubmitEvidence)(nil), "cosmos_sdk.simapp.codec.v1.MsgSubmitEvidence") + proto.RegisterType((*Proposal)(nil), "cosmos_sdk.simapp.codec.v1.Proposal") + proto.RegisterType((*Content)(nil), "cosmos_sdk.simapp.codec.v1.Content") } func init() { proto.RegisterFile("simapp/codec/codec.proto", fileDescriptor_3c6d4085e4065f5a) } var fileDescriptor_3c6d4085e4065f5a = []byte{ - // 593 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x54, 0x4d, 0x6f, 0xd3, 0x3e, - 0x18, 0x4f, 0xfe, 0xeb, 0xfa, 0xaf, 0xbc, 0x81, 0x44, 0x24, 0xa0, 0xaa, 0x50, 0x3a, 0x26, 0x98, - 0x78, 0x51, 0x13, 0x8d, 0xf1, 0xb6, 0x5e, 0x60, 0x1d, 0x43, 0x45, 0xa2, 0x08, 0x75, 0x12, 0x07, - 0x2e, 0x55, 0x6a, 0x5b, 0xad, 0xb5, 0x26, 0x36, 0xb5, 0x1d, 0xb5, 0xdf, 0x00, 0x71, 0xe2, 0x23, - 0x4c, 0x7c, 0x00, 0x4e, 0x3b, 0xf2, 0x01, 0xa6, 0x9d, 0x7a, 0xe4, 0x34, 0xa1, 0xf6, 0xc2, 0xc7, - 0x40, 0x89, 0x9d, 0xb4, 0x55, 0xda, 0xee, 0x12, 0xd5, 0x7e, 0x7e, 0x6f, 0x76, 0x9f, 0xc7, 0xa0, - 0xc8, 0x89, 0xef, 0x31, 0xe6, 0x42, 0x8a, 0x30, 0x54, 0x5f, 0x87, 0xf5, 0xa9, 0xa0, 0x56, 0x09, - 0x52, 0xee, 0x53, 0xde, 0xe2, 0xe8, 0xc4, 0x51, 0x20, 0x47, 0x95, 0xc3, 0xdd, 0xd2, 0x63, 0xd1, - 0x25, 0x7d, 0xd4, 0x62, 0x5e, 0x5f, 0x0c, 0xdd, 0x18, 0xee, 0x2a, 0x74, 0x65, 0x76, 0xa1, 0x84, - 0x4a, 0x3b, 0x59, 0x70, 0x87, 0x76, 0xe8, 0xf4, 0x97, 0xc6, 0x15, 0x07, 0xae, 0x27, 0x45, 0xd7, - 0x15, 0x43, 0x86, 0xb9, 0xfa, 0xea, 0xca, 0x96, 0xae, 0x84, 0x98, 0x0b, 0x12, 0x74, 0x16, 0x20, - 0x4a, 0x03, 0x97, 0x4b, 0xc6, 0x7a, 0xc3, 0x05, 0xb5, 0x3b, 0x03, 0x17, 0x87, 0x04, 0xe1, 0x00, - 0xe2, 0x6c, 0x75, 0xfb, 0x57, 0x0e, 0xfc, 0x7f, 0x00, 0x21, 0x95, 0x81, 0xb0, 0xde, 0x82, 0xcd, - 0xb6, 0xc7, 0x71, 0xcb, 0x53, 0xeb, 0xa2, 0xb9, 0x65, 0x3e, 0xd8, 0x78, 0x72, 0xd7, 0x99, 0xb9, - 0x89, 0x81, 0x13, 0x25, 0x71, 0xc2, 0x5d, 0xa7, 0xe6, 0x71, 0xac, 0x89, 0x75, 0xa3, 0xb9, 0xd1, - 0x9e, 0x2e, 0xad, 0x10, 0x94, 0x20, 0x0d, 0x04, 0x09, 0x24, 0x95, 0xbc, 0xa5, 0x53, 0xa7, 0xaa, - 0xff, 0xc5, 0xaa, 0xcf, 0x17, 0xa9, 0x2a, 0x64, 0xa4, 0x7e, 0x98, 0xf2, 0x3f, 0xa9, 0xcd, 0xa9, - 0x55, 0x11, 0x2e, 0xa9, 0x59, 0x3e, 0xb8, 0x8d, 0x70, 0xcf, 0x1b, 0x62, 0x94, 0x31, 0x5d, 0x8b, - 0x4d, 0xf7, 0x56, 0x9b, 0xbe, 0x51, 0xe4, 0x8c, 0xe3, 0x4d, 0xb4, 0xa8, 0x60, 0x31, 0x50, 0x64, - 0xb8, 0x4f, 0x28, 0x22, 0x30, 0xe3, 0x97, 0x8b, 0xfd, 0x9e, 0xae, 0xf6, 0xfb, 0xa8, 0xd9, 0x19, - 0xc3, 0x5b, 0x6c, 0x61, 0xc5, 0xfa, 0x00, 0xae, 0xfb, 0x14, 0xc9, 0xde, 0xf4, 0x2f, 0x5a, 0x8f, - 0x7d, 0xee, 0xcf, 0xfb, 0xa8, 0x56, 0x88, 0x1c, 0x1a, 0x31, 0x7a, 0x2a, 0x7c, 0xcd, 0x9f, 0xdd, - 0xa8, 0xee, 0x5f, 0x9c, 0x55, 0x9e, 0x3d, 0xea, 0x10, 0xd1, 0x95, 0x6d, 0x07, 0x52, 0x5f, 0x37, - 0x6e, 0xd2, 0xcc, 0x1c, 0x9d, 0xb8, 0xba, 0xf5, 0xf0, 0x80, 0xd1, 0xbe, 0xc0, 0xc8, 0xd1, 0xd4, - 0xda, 0x3a, 0x58, 0xe3, 0xd2, 0xdf, 0xfe, 0x66, 0x82, 0xfc, 0x71, 0x6c, 0x67, 0xbd, 0x04, 0x79, - 0x65, 0xac, 0xfb, 0xc6, 0x5e, 0x16, 0x4a, 0xe1, 0xeb, 0x46, 0x53, 0xe3, 0xab, 0xaf, 0xfe, 0x9e, - 0x96, 0xcd, 0x8b, 0xb3, 0xca, 0x8b, 0xab, 0xa2, 0xe8, 0x1e, 0x4f, 0xc3, 0x28, 0xa5, 0x77, 0x49, - 0x98, 0x1f, 0x26, 0x28, 0x1c, 0xe9, 0x56, 0xb7, 0xde, 0x83, 0x4d, 0xfc, 0x45, 0x92, 0x90, 0x42, - 0x4f, 0x10, 0x1a, 0xe8, 0x50, 0x3b, 0xf3, 0xa1, 0x92, 0xc1, 0x88, 0x62, 0x1d, 0xcd, 0xa0, 0xeb, - 0x46, 0x73, 0x8e, 0x5d, 0x3d, 0xd0, 0x11, 0xf7, 0xaf, 0x48, 0x98, 0x4e, 0x5a, 0x9a, 0x31, 0x09, - 0x94, 0x84, 0xfc, 0x69, 0x82, 0x1b, 0x0d, 0xde, 0x39, 0x96, 0x6d, 0x9f, 0x88, 0x34, 0xed, 0x6b, - 0x50, 0x48, 0xa8, 0x3a, 0xe9, 0x3d, 0x67, 0xf9, 0x03, 0x94, 0x8a, 0x36, 0x53, 0x96, 0xd5, 0x00, - 0xb9, 0x68, 0x06, 0xf5, 0x78, 0xb9, 0xcb, 0xcf, 0x99, 0x31, 0x8f, 0x26, 0xb9, 0x56, 0x38, 0xbf, - 0x2c, 0x1b, 0xa3, 0xcb, 0xb2, 0xd9, 0x8c, 0x65, 0xaa, 0x85, 0xaf, 0xa7, 0x65, 0x23, 0x3a, 0x74, - 0xed, 0xf0, 0x7c, 0x6c, 0x9b, 0xa3, 0xb1, 0x6d, 0xfe, 0x19, 0xdb, 0xe6, 0xf7, 0x89, 0x6d, 0x8c, - 0x26, 0xb6, 0xf1, 0x7b, 0x62, 0x1b, 0x9f, 0x1f, 0xae, 0xbc, 0x8c, 0xd9, 0x97, 0xb5, 0x9d, 0x8f, - 0x5f, 0x9b, 0xbd, 0x7f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x57, 0xb9, 0x47, 0x37, 0x70, 0x05, 0x00, - 0x00, + // 850 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x56, 0xcf, 0x8e, 0xdb, 0x44, + 0x18, 0xb7, 0x69, 0xba, 0x1b, 0x4d, 0x0b, 0x94, 0x11, 0x65, 0xa3, 0x80, 0x92, 0x92, 0x42, 0xc5, + 0x1f, 0xc5, 0x6e, 0x69, 0xa1, 0x6d, 0x2e, 0xa5, 0x09, 0x8b, 0x82, 0xc4, 0xa2, 0x55, 0x16, 0x38, + 0x20, 0x90, 0xe5, 0x8c, 0x07, 0xc7, 0x5a, 0xdb, 0x33, 0x78, 0xc6, 0xc6, 0x79, 0x03, 0xc4, 0x69, + 0x1f, 0x80, 0xc3, 0x8a, 0x07, 0xe0, 0xb4, 0x47, 0x1e, 0x60, 0xb5, 0xa7, 0x3d, 0x72, 0x5a, 0xa1, + 0xdd, 0x0b, 0x8f, 0x81, 0x3c, 0x33, 0x76, 0x6c, 0xd9, 0xc9, 0x5e, 0xac, 0x78, 0xbe, 0xdf, 0xbf, + 0xb1, 0xe7, 0xfb, 0x1c, 0xd0, 0x61, 0x5e, 0x60, 0x53, 0x6a, 0x22, 0xe2, 0x60, 0x24, 0xaf, 0x06, + 0x8d, 0x08, 0x27, 0xb0, 0x8b, 0x08, 0x0b, 0x08, 0xb3, 0x98, 0x73, 0x68, 0x48, 0x90, 0x21, 0xcb, + 0xc9, 0xa3, 0xee, 0xc7, 0x7c, 0xe1, 0x45, 0x8e, 0x45, 0xed, 0x88, 0x2f, 0x4d, 0x01, 0x37, 0x25, + 0x7a, 0x58, 0xbe, 0x91, 0x42, 0xdd, 0x07, 0x75, 0xb0, 0x4b, 0x5c, 0xb2, 0xfa, 0xa5, 0x70, 0x9d, + 0xd4, 0xb4, 0x63, 0xbe, 0x30, 0xf9, 0x92, 0x62, 0x26, 0xaf, 0xaa, 0x72, 0x4f, 0x55, 0x12, 0xcc, + 0xb8, 0x17, 0xba, 0x0d, 0x88, 0x6e, 0x6a, 0xb2, 0x98, 0x52, 0x7f, 0xd9, 0x50, 0x7b, 0x27, 0x35, + 0x71, 0xe2, 0x39, 0x38, 0x44, 0xb8, 0xa1, 0xba, 0x93, 0x9a, 0x2e, 0x49, 0x1a, 0x0a, 0xf7, 0x53, + 0x93, 0xda, 0x91, 0x1d, 0xa8, 0xd5, 0x2c, 0x39, 0x25, 0xcc, 0xf6, 0x2b, 0xa0, 0xb7, 0x53, 0x33, + 0xa6, 0x6e, 0x64, 0x3b, 0xb8, 0x39, 0xb6, 0xe3, 0x31, 0x1e, 0x79, 0xf3, 0x98, 0x7b, 0x24, 0xac, + 0x23, 0x06, 0x7f, 0xb7, 0xc0, 0xf6, 0x4b, 0x84, 0x48, 0x1c, 0x72, 0xf8, 0x25, 0xb8, 0x3d, 0xb7, + 0x19, 0xb6, 0x6c, 0x79, 0xdf, 0xd1, 0xef, 0xe9, 0x1f, 0xdc, 0xfa, 0xe4, 0x5d, 0xa3, 0xf4, 0x1a, + 0x52, 0x23, 0x7b, 0x0c, 0x46, 0xf2, 0xc8, 0x18, 0xdb, 0x0c, 0x2b, 0xe2, 0x54, 0x9b, 0xdd, 0x9a, + 0xaf, 0x6e, 0x61, 0x02, 0xba, 0x88, 0x84, 0xdc, 0x0b, 0x63, 0x12, 0x33, 0x4b, 0x3d, 0xb2, 0x42, + 0xf5, 0x15, 0xa1, 0xfa, 0x59, 0x93, 0xaa, 0x44, 0x66, 0xea, 0x93, 0x82, 0xff, 0xbd, 0x5c, 0x5c, + 0x59, 0x75, 0xd0, 0x9a, 0x1a, 0x0c, 0xc0, 0x8e, 0x83, 0x7d, 0x7b, 0x89, 0x9d, 0x9a, 0xe9, 0x0d, + 0x61, 0xfa, 0x78, 0xb3, 0xe9, 0x17, 0x92, 0x5c, 0x73, 0xbc, 0xeb, 0x34, 0x15, 0x20, 0x05, 0x1d, + 0x8a, 0x23, 0x8f, 0x38, 0x1e, 0xaa, 0xf9, 0xb5, 0x84, 0xdf, 0x93, 0xcd, 0x7e, 0xfb, 0x8a, 0x5d, + 0x33, 0x7c, 0x8b, 0x36, 0x56, 0xe0, 0x37, 0xe0, 0xb5, 0x80, 0x38, 0xb1, 0xbf, 0x7a, 0x45, 0x37, + 0x85, 0xcf, 0xfb, 0x55, 0x1f, 0x79, 0x0e, 0x33, 0x87, 0x3d, 0x81, 0x5e, 0x09, 0xbf, 0x1a, 0x94, + 0x17, 0x46, 0xcf, 0xcf, 0x4e, 0x86, 0x9f, 0x7e, 0xe4, 0x7a, 0x7c, 0x11, 0xcf, 0x0d, 0x44, 0x02, + 0xd5, 0x35, 0x79, 0x27, 0x31, 0xe7, 0xd0, 0x54, 0xe7, 0x1e, 0xa7, 0x94, 0x44, 0x1c, 0x3b, 0x86, + 0xa2, 0x8e, 0x6f, 0x82, 0x1b, 0x2c, 0x0e, 0x06, 0xbf, 0xeb, 0x60, 0xeb, 0x40, 0xd8, 0xc1, 0x67, + 0x60, 0x4b, 0x1a, 0xab, 0x73, 0xd3, 0x5b, 0x17, 0x4a, 0xe2, 0xa7, 0xda, 0x4c, 0xe1, 0x47, 0x2f, + 0xfe, 0x3b, 0xee, 0xeb, 0x67, 0x27, 0xc3, 0xa7, 0xd7, 0x45, 0x51, 0x0d, 0x56, 0x84, 0x91, 0x4a, + 0x5f, 0xe5, 0x61, 0xfe, 0xd4, 0x41, 0x7b, 0x57, 0xf5, 0x19, 0xfc, 0x1a, 0xdc, 0xc6, 0xbf, 0xc4, + 0x5e, 0x42, 0x90, 0x9d, 0x1d, 0x7d, 0x15, 0xea, 0x41, 0x35, 0x54, 0xde, 0x95, 0x59, 0xac, 0xdd, + 0x12, 0x7a, 0xaa, 0xcd, 0x2a, 0xec, 0xd1, 0x4b, 0x15, 0xf1, 0xf9, 0x35, 0x09, 0x8b, 0x36, 0x2f, + 0x32, 0xe6, 0x81, 0xf2, 0x90, 0x7f, 0xe9, 0xe0, 0x8d, 0x3d, 0xe6, 0x1e, 0xc4, 0xf3, 0xc0, 0xe3, + 0x45, 0xda, 0xcf, 0x41, 0x3b, 0xa7, 0xaa, 0xa4, 0xef, 0x19, 0xeb, 0xa7, 0x5f, 0x21, 0x3a, 0x2b, + 0x58, 0x70, 0x0f, 0xb4, 0xb2, 0x1e, 0x54, 0xed, 0x65, 0xae, 0xdf, 0x67, 0xcd, 0x3c, 0xeb, 0xe4, + 0x71, 0xfb, 0xf4, 0xa2, 0xaf, 0x9d, 0x5f, 0xf4, 0xf5, 0x99, 0x90, 0x19, 0xb5, 0x7f, 0x3b, 0xee, + 0x6b, 0xd9, 0xa6, 0x07, 0x47, 0x3a, 0x68, 0xef, 0xab, 0xc9, 0x03, 0x5f, 0x28, 0x97, 0xc6, 0xd1, + 0xe0, 0x92, 0x44, 0x1c, 0x6b, 0x05, 0x6e, 0xd2, 0x85, 0x13, 0xb0, 0x9d, 0xf5, 0x2f, 0x2e, 0x06, + 0xc1, 0xfd, 0x4d, 0xfb, 0x9c, 0x48, 0xe8, 0xb8, 0x95, 0xa9, 0xcc, 0x72, 0xe6, 0xe0, 0x8f, 0x16, + 0xd8, 0x56, 0x25, 0xf8, 0x14, 0xb4, 0x38, 0x4e, 0xf9, 0xc6, 0x44, 0xdf, 0xe2, 0x94, 0xe7, 0xa9, + 0xa6, 0xda, 0x4c, 0x10, 0xe0, 0x8f, 0xe0, 0x8e, 0x98, 0xae, 0x98, 0xe3, 0xc8, 0x42, 0x0b, 0x3b, + 0x74, 0xd7, 0x3c, 0x3c, 0x39, 0x83, 0xc5, 0xce, 0x72, 0xfc, 0x44, 0xc0, 0x4b, 0x92, 0xaf, 0xd3, + 0x6a, 0x09, 0xfe, 0x04, 0xee, 0x30, 0xf2, 0x33, 0xff, 0xd5, 0x8e, 0xb0, 0xa5, 0xe6, 0xb3, 0x1a, + 0x42, 0x0f, 0xab, 0xea, 0xaa, 0x28, 0x1a, 0x43, 0x11, 0xbe, 0x93, 0x4b, 0x65, 0x79, 0x56, 0x2d, + 0x41, 0x0a, 0x76, 0x90, 0x1d, 0x22, 0xec, 0x5b, 0x35, 0x97, 0x56, 0xd3, 0x7c, 0x2d, 0xb9, 0x4c, + 0x04, 0x6f, 0xbd, 0xd7, 0x5d, 0xd4, 0x04, 0x80, 0x3e, 0x78, 0x13, 0x91, 0x20, 0x88, 0x43, 0x8f, + 0x2f, 0x2d, 0x4a, 0x88, 0x6f, 0x31, 0x8a, 0x43, 0x47, 0x4d, 0xa0, 0x67, 0x55, 0xbb, 0xf2, 0x47, + 0x47, 0xbe, 0x47, 0xc5, 0xdc, 0x27, 0xc4, 0x3f, 0xc8, 0x78, 0x25, 0x43, 0x88, 0x6a, 0xd5, 0xd1, + 0x93, 0xb3, 0x93, 0xe1, 0xc3, 0x6b, 0x7a, 0xad, 0xf8, 0x68, 0x16, 0xc7, 0x44, 0xb6, 0xd8, 0x78, + 0x72, 0x7a, 0xd9, 0xd3, 0xcf, 0x2f, 0x7b, 0xfa, 0xbf, 0x97, 0x3d, 0xfd, 0xe8, 0xaa, 0xa7, 0x9d, + 0x5f, 0xf5, 0xb4, 0x7f, 0xae, 0x7a, 0xda, 0x0f, 0x1f, 0x6e, 0x94, 0x2c, 0xff, 0x11, 0x99, 0x6f, + 0x89, 0xef, 0xe3, 0xe3, 0xff, 0x03, 0x00, 0x00, 0xff, 0xff, 0x17, 0x2b, 0x3f, 0x40, 0x9f, 0x08, + 0x00, 0x00, } func (this *Supply) Equal(that interface{}) bool { @@ -624,6 +820,65 @@ func (this *Evidence) SetEvidence(value github_com_cosmos_cosmos_sdk_x_evidence_ return fmt.Errorf("can't encode value of type %T as message Evidence", value) } +func (this *Content) GetContent() github_com_cosmos_cosmos_sdk_x_gov_types.Content { + if x := this.GetText(); x != nil { + return x + } + if x := this.GetParameterChange(); x != nil { + return x + } + if x := this.GetSoftwareUpgrade(); x != nil { + return x + } + if x := this.GetCancelSoftwareUpgrade(); x != nil { + return x + } + if x := this.GetCommunityPoolSpend(); x != nil { + return x + } + return nil +} + +func (this *Content) SetContent(value github_com_cosmos_cosmos_sdk_x_gov_types.Content) error { + if value == nil { + this.Sum = nil + return nil + } + switch vt := value.(type) { + case *types4.TextProposal: + this.Sum = &Content_Text{vt} + return nil + case types4.TextProposal: + this.Sum = &Content_Text{&vt} + return nil + case *proposal.ParameterChangeProposal: + this.Sum = &Content_ParameterChange{vt} + return nil + case proposal.ParameterChangeProposal: + this.Sum = &Content_ParameterChange{&vt} + return nil + case *types5.SoftwareUpgradeProposal: + this.Sum = &Content_SoftwareUpgrade{vt} + return nil + case types5.SoftwareUpgradeProposal: + this.Sum = &Content_SoftwareUpgrade{&vt} + return nil + case *types5.CancelSoftwareUpgradeProposal: + this.Sum = &Content_CancelSoftwareUpgrade{vt} + return nil + case types5.CancelSoftwareUpgradeProposal: + this.Sum = &Content_CancelSoftwareUpgrade{&vt} + return nil + case *types6.CommunityPoolSpendProposal: + this.Sum = &Content_CommunityPoolSpend{vt} + return nil + case types6.CommunityPoolSpendProposal: + this.Sum = &Content_CommunityPoolSpend{&vt} + return nil + } + return fmt.Errorf("can't encode value of type %T as message Content", value) +} + func (m *Account) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -912,112 +1167,292 @@ func (m *MsgSubmitEvidence) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func encodeVarintCodec(dAtA []byte, offset int, v uint64) int { - offset -= sovCodec(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *Account) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Sum != nil { - n += m.Sum.Size() +func (m *Proposal) 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 n + return dAtA[:n], nil } -func (m *Account_BaseAccount) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.BaseAccount != nil { - l = m.BaseAccount.Size() - n += 1 + l + sovCodec(uint64(l)) - } - return n +func (m *Proposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *Account_ContinuousVestingAccount) Size() (n int) { - if m == nil { - return 0 - } + +func (m *Proposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i var l int _ = l - if m.ContinuousVestingAccount != nil { - l = m.ContinuousVestingAccount.Size() - n += 1 + l + sovCodec(uint64(l)) - } - return n -} -func (m *Account_DelayedVestingAccount) Size() (n int) { - if m == nil { - return 0 + { + size, err := m.Content.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) } - var l int - _ = l - if m.DelayedVestingAccount != nil { - l = m.DelayedVestingAccount.Size() - n += 1 + l + sovCodec(uint64(l)) + i-- + dAtA[i] = 0x12 + { + size, err := m.ProposalBase.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) } - return n + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil } -func (m *Account_PeriodicVestingAccount) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.PeriodicVestingAccount != nil { - l = m.PeriodicVestingAccount.Size() - n += 1 + l + sovCodec(uint64(l)) + +func (m *Content) 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 n + return dAtA[:n], nil } -func (m *Account_ModuleAccount) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.ModuleAccount != nil { - l = m.ModuleAccount.Size() - n += 1 + l + sovCodec(uint64(l)) - } - return n + +func (m *Content) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *Supply) Size() (n int) { - if m == nil { - return 0 - } + +func (m *Content) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i var l int _ = l if m.Sum != nil { - n += m.Sum.Size() + { + size := m.Sum.Size() + i -= size + if _, err := m.Sum.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + } } - return n + return len(dAtA) - i, nil } -func (m *Supply_Supply) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Supply != nil { - l = m.Supply.Size() - n += 1 + l + sovCodec(uint64(l)) - } - return n +func (m *Content_Text) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Content_Text) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.Text != nil { + { + size, err := m.Text.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} +func (m *Content_ParameterChange) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Content_ParameterChange) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.ParameterChange != nil { + { + size, err := m.ParameterChange.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + return len(dAtA) - i, nil +} +func (m *Content_SoftwareUpgrade) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Content_SoftwareUpgrade) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.SoftwareUpgrade != nil { + { + size, err := m.SoftwareUpgrade.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + return len(dAtA) - i, nil +} +func (m *Content_CancelSoftwareUpgrade) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Content_CancelSoftwareUpgrade) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.CancelSoftwareUpgrade != nil { + { + size, err := m.CancelSoftwareUpgrade.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + return len(dAtA) - i, nil +} +func (m *Content_CommunityPoolSpend) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Content_CommunityPoolSpend) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.CommunityPoolSpend != nil { + { + size, err := m.CommunityPoolSpend.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + return len(dAtA) - i, nil +} +func encodeVarintCodec(dAtA []byte, offset int, v uint64) int { + offset -= sovCodec(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Account) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Sum != nil { + n += m.Sum.Size() + } + return n +} + +func (m *Account_BaseAccount) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.BaseAccount != nil { + l = m.BaseAccount.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *Account_ContinuousVestingAccount) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ContinuousVestingAccount != nil { + l = m.ContinuousVestingAccount.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *Account_DelayedVestingAccount) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.DelayedVestingAccount != nil { + l = m.DelayedVestingAccount.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *Account_PeriodicVestingAccount) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.PeriodicVestingAccount != nil { + l = m.PeriodicVestingAccount.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *Account_ModuleAccount) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ModuleAccount != nil { + l = m.ModuleAccount.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *Supply) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Sum != nil { + n += m.Sum.Size() + } + return n +} + +func (m *Supply_Supply) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Supply != nil { + l = m.Supply.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n } func (m *Evidence) Size() (n int) { if m == nil { @@ -1058,13 +1493,503 @@ func (m *MsgSubmitEvidence) Size() (n int) { return n } -func sovCodec(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 +func (m *Proposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.ProposalBase.Size() + n += 1 + l + sovCodec(uint64(l)) + l = m.Content.Size() + n += 1 + l + sovCodec(uint64(l)) + return n } -func sozCodec(x uint64) (n int) { - return sovCodec(uint64((x << 1) ^ uint64((int64(x) >> 63)))) + +func (m *Content) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Sum != nil { + n += m.Sum.Size() + } + return n +} + +func (m *Content_Text) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Text != nil { + l = m.Text.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *Content_ParameterChange) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ParameterChange != nil { + l = m.ParameterChange.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *Content_SoftwareUpgrade) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.SoftwareUpgrade != nil { + l = m.SoftwareUpgrade.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *Content_CancelSoftwareUpgrade) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.CancelSoftwareUpgrade != nil { + l = m.CancelSoftwareUpgrade.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *Content_CommunityPoolSpend) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.CommunityPoolSpend != nil { + l = m.CommunityPoolSpend.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} + +func sovCodec(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozCodec(x uint64) (n int) { + return sovCodec(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Account) 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 ErrIntOverflowCodec + } + 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: Account: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Account: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BaseAccount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &types.BaseAccount{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Sum = &Account_BaseAccount{v} + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ContinuousVestingAccount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &types1.ContinuousVestingAccount{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Sum = &Account_ContinuousVestingAccount{v} + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DelayedVestingAccount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &types1.DelayedVestingAccount{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Sum = &Account_DelayedVestingAccount{v} + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PeriodicVestingAccount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &types1.PeriodicVestingAccount{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Sum = &Account_PeriodicVestingAccount{v} + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ModuleAccount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &types2.ModuleAccount{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Sum = &Account_ModuleAccount{v} + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCodec(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Supply) 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 ErrIntOverflowCodec + } + 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: Supply: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Supply: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Supply", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &types2.Supply{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Sum = &Supply_Supply{v} + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCodec(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Evidence) 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 ErrIntOverflowCodec + } + 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: Evidence: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Evidence: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Equivocation", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &types3.Equivocation{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Sum = &Evidence_Equivocation{v} + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCodec(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil } -func (m *Account) Unmarshal(dAtA []byte) error { +func (m *MsgSubmitEvidence) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1087,15 +2012,15 @@ func (m *Account) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: Account: wiretype end group for non-group") + return fmt.Errorf("proto: MsgSubmitEvidence: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: Account: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgSubmitEvidence: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field BaseAccount", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Evidence", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -1122,15 +2047,16 @@ func (m *Account) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - v := &types.BaseAccount{} - if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if m.Evidence == nil { + m.Evidence = &Evidence{} + } + if err := m.Evidence.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } - m.Sum = &Account_BaseAccount{v} iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ContinuousVestingAccount", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field MsgSubmitEvidenceBase", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -1157,50 +2083,66 @@ func (m *Account) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - v := &types1.ContinuousVestingAccount{} - if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.MsgSubmitEvidenceBase.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } - m.Sum = &Account_ContinuousVestingAccount{v} iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field DelayedVestingAccount", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCodec - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } + default: + iNdEx = preIndex + skippy, err := skipCodec(dAtA[iNdEx:]) + if err != nil { + return err } - if msglen < 0 { + if skippy < 0 { return ErrInvalidLengthCodec } - postIndex := iNdEx + msglen - if postIndex < 0 { + if (iNdEx + skippy) < 0 { return ErrInvalidLengthCodec } - if postIndex > l { + if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } - v := &types1.DelayedVestingAccount{} - if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Proposal) 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 ErrIntOverflowCodec } - m.Sum = &Account_DelayedVestingAccount{v} - iNdEx = postIndex - case 4: + 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: Proposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Proposal: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field PeriodicVestingAccount", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ProposalBase", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -1227,15 +2169,13 @@ func (m *Account) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - v := &types1.PeriodicVestingAccount{} - if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.ProposalBase.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } - m.Sum = &Account_PeriodicVestingAccount{v} iNdEx = postIndex - case 5: + case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ModuleAccount", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Content", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -1262,11 +2202,9 @@ func (m *Account) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - v := &types2.ModuleAccount{} - if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.Content.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } - m.Sum = &Account_ModuleAccount{v} iNdEx = postIndex default: iNdEx = preIndex @@ -1292,7 +2230,7 @@ func (m *Account) Unmarshal(dAtA []byte) error { } return nil } -func (m *Supply) Unmarshal(dAtA []byte) error { +func (m *Content) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1315,15 +2253,15 @@ func (m *Supply) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: Supply: wiretype end group for non-group") + return fmt.Errorf("proto: Content: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: Supply: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: Content: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Supply", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Text", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -1350,68 +2288,15 @@ func (m *Supply) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - v := &types2.Supply{} + v := &types4.TextProposal{} if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } - m.Sum = &Supply_Supply{v} + m.Sum = &Content_Text{v} iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipCodec(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthCodec - } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthCodec - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *Evidence) 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 ErrIntOverflowCodec - } - 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: Evidence: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: Evidence: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: + case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Equivocation", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ParameterChange", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -1438,68 +2323,50 @@ func (m *Evidence) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - v := &types3.Equivocation{} + v := &proposal.ParameterChangeProposal{} if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } - m.Sum = &Evidence_Equivocation{v} + m.Sum = &Content_ParameterChange{v} iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipCodec(dAtA[iNdEx:]) - if err != nil { - return err + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SoftwareUpgrade", wireType) } - if skippy < 0 { - return ErrInvalidLengthCodec + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } } - if (iNdEx + skippy) < 0 { + if msglen < 0 { return ErrInvalidLengthCodec } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *MsgSubmitEvidence) 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 ErrIntOverflowCodec + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec } - if iNdEx >= l { + if postIndex > l { return io.ErrUnexpectedEOF } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break + v := &types5.SoftwareUpgradeProposal{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MsgSubmitEvidence: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgSubmitEvidence: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: + m.Sum = &Content_SoftwareUpgrade{v} + iNdEx = postIndex + case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Evidence", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field CancelSoftwareUpgrade", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -1526,16 +2393,15 @@ func (m *MsgSubmitEvidence) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.Evidence == nil { - m.Evidence = &Evidence{} - } - if err := m.Evidence.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + v := &types5.CancelSoftwareUpgradeProposal{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } + m.Sum = &Content_CancelSoftwareUpgrade{v} iNdEx = postIndex - case 2: + case 5: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field MsgSubmitEvidenceBase", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field CommunityPoolSpend", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -1562,9 +2428,11 @@ func (m *MsgSubmitEvidence) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.MsgSubmitEvidenceBase.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + v := &types6.CommunityPoolSpendProposal{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } + m.Sum = &Content_CommunityPoolSpend{v} iNdEx = postIndex default: iNdEx = preIndex diff --git a/simapp/codec/codec.proto b/simapp/codec/codec.proto index 2b68c487a64b..bfa55600471c 100644 --- a/simapp/codec/codec.proto +++ b/simapp/codec/codec.proto @@ -7,6 +7,10 @@ import "x/auth/types/types.proto"; import "x/auth/vesting/types/types.proto"; import "x/supply/types/types.proto"; import "x/evidence/types/types.proto"; +import "x/gov/types/types.proto"; +import "x/params/types/proposal/types.proto"; +import "x/upgrade/types/types.proto"; +import "x/distribution/types/types.proto"; option go_package = "github.com/cosmos/cosmos-sdk/simapp/codec"; @@ -56,3 +60,24 @@ message MsgSubmitEvidence { Evidence evidence = 1; cosmos_sdk.x.evidence.v1.MsgSubmitEvidenceBase base = 2 [(gogoproto.nullable) = false, (gogoproto.embed) = true]; } + +// Proposal defines the application-level concrete proposal type used in governance +// proposals. +message Proposal { + cosmos_sdk.x.gov.v1.ProposalBase base = 1 [(gogoproto.embed) = true, (gogoproto.nullable) = false]; + Content content = 2 [(gogoproto.nullable) = false]; +} + +// Content defines the application-level allowed Content to be included in a +// governance proposal. +message Content { + option (cosmos_proto.interface_type) = "github.com/cosmos/cosmos-sdk/x/gov/types.Content"; + + oneof sum { + cosmos_sdk.x.gov.v1.TextProposal text = 1; + cosmos_sdk.x.params.v1.ParameterChangeProposal parameter_change = 2; + cosmos_sdk.x.upgrade.v1.SoftwareUpgradeProposal software_upgrade = 3; + cosmos_sdk.x.upgrade.v1.CancelSoftwareUpgradeProposal cancel_software_upgrade = 4; + cosmos_sdk.x.distribution.v1.CommunityPoolSpendProposal community_pool_spend = 5; + } +} diff --git a/x/gov/alias.go b/x/gov/alias.go index df5f2cb9ce77..c1f0a98086eb 100644 --- a/x/gov/alias.go +++ b/x/gov/alias.go @@ -152,4 +152,5 @@ type ( Vote = types.Vote Votes = types.Votes VoteOption = types.VoteOption + Codec = types.Codec ) diff --git a/x/gov/types/codec.go b/x/gov/types/codec.go index a02491a12b12..a892ddecd75a 100644 --- a/x/gov/types/codec.go +++ b/x/gov/types/codec.go @@ -8,8 +8,8 @@ import ( type Codec interface { codec.Marshaler - MarshalProposal(p Proposal) ([]byte, error) - UnmarshalProposal(bz []byte, ptr *Proposal) error + MarshalProposal(Proposal) ([]byte, error) + UnmarshalProposal([]byte) (Proposal, error) } // RegisterCodec registers all the necessary types and interfaces for the diff --git a/x/gov/types/proposal.go b/x/gov/types/proposal.go index 15d23ddf7651..c67363f93a87 100644 --- a/x/gov/types/proposal.go +++ b/x/gov/types/proposal.go @@ -6,6 +6,8 @@ import ( "strings" "time" + "gopkg.in/yaml.v2" + sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) @@ -37,20 +39,8 @@ func NewProposal(content Content, id uint64, submitTime, depositEndTime time.Tim // String implements stringer interface func (p Proposal) String() string { - return fmt.Sprintf(`Proposal %d: - Title: %s - Type: %s - Status: %s - Submit Time: %s - Deposit End Time: %s - Total Deposit: %s - Voting Start Time: %s - Voting End Time: %s - Description: %s`, - p.ProposalID, p.GetTitle(), p.ProposalType(), - p.Status, p.SubmitTime, p.DepositEndTime, - p.TotalDeposit, p.VotingStartTime, p.VotingEndTime, p.GetDescription(), - ) + out, _ := yaml.Marshal(p) + return string(out) } // Proposals is an array of proposal diff --git a/x/gov/types/types.proto b/x/gov/types/types.proto index d590397ca9f0..b22abea1ec9e 100644 --- a/x/gov/types/types.proto +++ b/x/gov/types/types.proto @@ -3,7 +3,6 @@ package cosmos_sdk.x.gov.v1; import "types/types.proto"; import "third_party/proto/gogoproto/gogo.proto"; -// import "third_party/proto/cosmos-proto/cosmos.proto"; import "google/protobuf/timestamp.proto"; option go_package = "github.com/cosmos/cosmos-sdk/x/gov/types"; @@ -133,16 +132,3 @@ message Vote { bytes voter = 2 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; VoteOption option = 3; } - -// message BasicProposal { -// ProposalBase base = 1 [(gogoproto.embed) = true]; -// BasicContent content = 2; -// } - -// message BasicContent { -// option (cosmos_proto.interface_type) = "Content"; -// option (gogoproto.stringer) = true; -// oneof sum { -// TextProposal text = 1; -// } -// } From 73e1e3a354aba17b540277df082e2243b6b9f20f Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 2 Mar 2020 18:49:14 +0100 Subject: [PATCH 320/529] refactor TestTallyDelgatorInherit to use simapp --- x/gov/keeper/old_tally_test.go | 33 ----------------------- x/gov/keeper/tally_test.go | 49 ++++++++++++++++++++++++++++------ 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/x/gov/keeper/old_tally_test.go b/x/gov/keeper/old_tally_test.go index f3b23eea639a..22ef47e8c4f2 100644 --- a/x/gov/keeper/old_tally_test.go +++ b/x/gov/keeper/old_tally_test.go @@ -10,39 +10,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking" ) -func TestTallyDelgatorInherit(t *testing.T) { - ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) - createValidators(ctx, sk, []int64{5, 6, 7}) - - delTokens := sdk.TokensFromConsensusPower(30) - val3, found := sk.GetValidator(ctx, valOpAddr3) - require.True(t, found) - - _, err := sk.Delegate(ctx, TestAddrs[0], delTokens, sdk.Unbonded, val3, true) - require.NoError(t, err) - - _ = staking.EndBlocker(ctx, sk) - - tp := TestProposal - proposal, err := keeper.SubmitProposal(ctx, tp) - require.NoError(t, err) - proposalID := proposal.ProposalID - proposal.Status = types.StatusVotingPeriod - keeper.SetProposal(ctx, proposal) - - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionNo)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionNo)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr3, types.OptionYes)) - - proposal, ok := keeper.GetProposal(ctx, proposalID) - require.True(t, ok) - passes, burnDeposits, tallyResults := keeper.Tally(ctx, proposal) - - require.True(t, passes) - require.False(t, burnDeposits) - require.False(t, tallyResults.Equals(types.EmptyTallyResult())) -} - func TestTallyDelgatorMultipleOverride(t *testing.T) { ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{5, 6, 7}) diff --git a/x/gov/keeper/tally_test.go b/x/gov/keeper/tally_test.go index cee137b5bfe0..e7575d55f8b0 100644 --- a/x/gov/keeper/tally_test.go +++ b/x/gov/keeper/tally_test.go @@ -245,14 +245,12 @@ func TestTallyDelgatorOverride(t *testing.T) { ctx := app.BaseApp.NewContext(false, abci.Header{}) addrs, valAddrs := createValidators(ctx, app, []int64{5, 6, 7}) - valOpAddr1 := valAddrs[0] - valAccAddr1, valAccAddr2, valAccAddr3, valAccAddr4 := addrs[1], addrs[2], addrs[3], addrs[4] delTokens := sdk.TokensFromConsensusPower(30) - val1, found := app.StakingKeeper.GetValidator(ctx, valOpAddr1) + val1, found := app.StakingKeeper.GetValidator(ctx, valAddrs[0]) require.True(t, found) - _, err := app.StakingKeeper.Delegate(ctx, valAccAddr4, delTokens, sdk.Unbonded, val1, true) + _, err := app.StakingKeeper.Delegate(ctx, addrs[4], delTokens, sdk.Unbonded, val1, true) require.NoError(t, err) _ = staking.EndBlocker(ctx, app.StakingKeeper) @@ -264,10 +262,10 @@ func TestTallyDelgatorOverride(t *testing.T) { proposal.Status = types.StatusVotingPeriod app.GovKeeper.SetProposal(ctx, proposal) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionYes)) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionYes)) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr3, types.OptionYes)) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr4, types.OptionNo)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[1], types.OptionYes)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[2], types.OptionYes)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[3], types.OptionYes)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[4], types.OptionNo)) proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID) require.True(t, ok) @@ -277,3 +275,38 @@ func TestTallyDelgatorOverride(t *testing.T) { require.False(t, burnDeposits) require.False(t, tallyResults.Equals(types.EmptyTallyResult())) } + +func TestTallyDelgatorInherit(t *testing.T) { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + addrs, vals := createValidators(ctx, app, []int64{5, 6, 7}) + + delTokens := sdk.TokensFromConsensusPower(30) + val3, found := app.StakingKeeper.GetValidator(ctx, vals[2]) + require.True(t, found) + + _, err := app.StakingKeeper.Delegate(ctx, addrs[3], delTokens, sdk.Unbonded, val3, true) + require.NoError(t, err) + + _ = staking.EndBlocker(ctx, app.StakingKeeper) + + tp := TestProposal + proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) + require.NoError(t, err) + proposalID := proposal.ProposalID + proposal.Status = types.StatusVotingPeriod + app.GovKeeper.SetProposal(ctx, proposal) + + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[0], types.OptionNo)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[1], types.OptionNo)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[2], types.OptionYes)) + + proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID) + require.True(t, ok) + passes, burnDeposits, tallyResults := app.GovKeeper.Tally(ctx, proposal) + + require.True(t, passes) + require.False(t, burnDeposits) + require.False(t, tallyResults.Equals(types.EmptyTallyResult())) +} From e2b72141bf0cbdfd3e71f2669a9ae3c367d5f550 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Mon, 2 Mar 2020 12:49:32 -0500 Subject: [PATCH 321/529] Update keeper --- x/gov/keeper/proposal.go | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/x/gov/keeper/proposal.go b/x/gov/keeper/proposal.go index 5f795b62d2f8..ca7826ad7b5c 100644 --- a/x/gov/keeper/proposal.go +++ b/x/gov/keeper/proposal.go @@ -51,24 +51,29 @@ func (keeper Keeper) SubmitProposal(ctx sdk.Context, content types.Content) (typ // GetProposal get proposal from store by ProposalID func (keeper Keeper) GetProposal(ctx sdk.Context, proposalID uint64) (proposal types.Proposal, ok bool) { store := ctx.KVStore(keeper.storeKey) + bz := store.Get(types.ProposalKey(proposalID)) if bz == nil { - return + return types.Proposal{}, false } - err := keeper.cdc.UnmarshalProposal(bz, &proposal) + + proposal, err := keeper.cdc.UnmarshalProposal(bz) if err != nil { panic(err) } + return proposal, true } // SetProposal set a proposal to store func (keeper Keeper) SetProposal(ctx sdk.Context, proposal types.Proposal) { store := ctx.KVStore(keeper.storeKey) + bz, err := keeper.cdc.MarshalProposal(proposal) if err != nil { panic(err) } + store.Set(types.ProposalKey(proposal.ProposalID), bz) } @@ -87,12 +92,12 @@ func (keeper Keeper) DeleteProposal(ctx sdk.Context, proposalID uint64) { // IterateProposals iterates over the all the proposals and performs a callback function func (keeper Keeper) IterateProposals(ctx sdk.Context, cb func(proposal types.Proposal) (stop bool)) { store := ctx.KVStore(keeper.storeKey) - iterator := sdk.KVStorePrefixIterator(store, types.ProposalsKeyPrefix) + iterator := sdk.KVStorePrefixIterator(store, types.ProposalsKeyPrefix) defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { - var proposal types.Proposal - err := keeper.cdc.UnmarshalProposal(iterator.Value(), &proposal) + proposal, err := keeper.cdc.UnmarshalProposal(iterator.Value()) if err != nil { panic(err) } From 8d4d10d27f363a4f4a809fc8be28951925e985ed Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 2 Mar 2020 18:52:45 +0100 Subject: [PATCH 322/529] refactor TestTallyDelgatorMultipleOverride to use simapp --- x/gov/keeper/old_tally_test.go | 38 -------------------------------- x/gov/keeper/tally_test.go | 40 ++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 38 deletions(-) diff --git a/x/gov/keeper/old_tally_test.go b/x/gov/keeper/old_tally_test.go index 22ef47e8c4f2..f7ce7c2f8547 100644 --- a/x/gov/keeper/old_tally_test.go +++ b/x/gov/keeper/old_tally_test.go @@ -10,44 +10,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking" ) -func TestTallyDelgatorMultipleOverride(t *testing.T) { - ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) - createValidators(ctx, sk, []int64{5, 6, 7}) - - delTokens := sdk.TokensFromConsensusPower(10) - val1, found := sk.GetValidator(ctx, valOpAddr1) - require.True(t, found) - val2, found := sk.GetValidator(ctx, valOpAddr2) - require.True(t, found) - - _, err := sk.Delegate(ctx, TestAddrs[0], delTokens, sdk.Unbonded, val1, true) - require.NoError(t, err) - _, err = sk.Delegate(ctx, TestAddrs[0], delTokens, sdk.Unbonded, val2, true) - require.NoError(t, err) - - _ = staking.EndBlocker(ctx, sk) - - tp := TestProposal - proposal, err := keeper.SubmitProposal(ctx, tp) - require.NoError(t, err) - proposalID := proposal.ProposalID - proposal.Status = types.StatusVotingPeriod - keeper.SetProposal(ctx, proposal) - - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionYes)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionYes)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr3, types.OptionYes)) - require.NoError(t, keeper.AddVote(ctx, proposalID, TestAddrs[0], types.OptionNo)) - - proposal, ok := keeper.GetProposal(ctx, proposalID) - require.True(t, ok) - passes, burnDeposits, tallyResults := keeper.Tally(ctx, proposal) - - require.False(t, passes) - require.False(t, burnDeposits) - require.False(t, tallyResults.Equals(types.EmptyTallyResult())) -} - func TestTallyDelgatorMultipleInherit(t *testing.T) { ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{25, 6, 7}) diff --git a/x/gov/keeper/tally_test.go b/x/gov/keeper/tally_test.go index e7575d55f8b0..69a5ca71ce92 100644 --- a/x/gov/keeper/tally_test.go +++ b/x/gov/keeper/tally_test.go @@ -310,3 +310,43 @@ func TestTallyDelgatorInherit(t *testing.T) { require.False(t, burnDeposits) require.False(t, tallyResults.Equals(types.EmptyTallyResult())) } + +func TestTallyDelgatorMultipleOverride(t *testing.T) { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + addrs, vals := createValidators(ctx, app, []int64{5, 6, 7}) + + delTokens := sdk.TokensFromConsensusPower(10) + val1, found := app.StakingKeeper.GetValidator(ctx, vals[0]) + require.True(t, found) + val2, found := app.StakingKeeper.GetValidator(ctx, vals[1]) + require.True(t, found) + + _, err := app.StakingKeeper.Delegate(ctx, addrs[3], delTokens, sdk.Unbonded, val1, true) + require.NoError(t, err) + _, err = app.StakingKeeper.Delegate(ctx, addrs[3], delTokens, sdk.Unbonded, val2, true) + require.NoError(t, err) + + _ = staking.EndBlocker(ctx, app.StakingKeeper) + + tp := TestProposal + proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) + require.NoError(t, err) + proposalID := proposal.ProposalID + proposal.Status = types.StatusVotingPeriod + app.GovKeeper.SetProposal(ctx, proposal) + + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[0], types.OptionYes)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[1], types.OptionYes)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[2], types.OptionYes)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[3], types.OptionNo)) + + proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID) + require.True(t, ok) + passes, burnDeposits, tallyResults := app.GovKeeper.Tally(ctx, proposal) + + require.False(t, passes) + require.False(t, burnDeposits) + require.False(t, tallyResults.Equals(types.EmptyTallyResult())) +} From 7d3430673ecdf7b57e81f5e01fb9b5b1cbd355bc Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 2 Mar 2020 19:17:31 +0100 Subject: [PATCH 323/529] add tally test TestTallyDelgatorMultipleInherit --- x/gov/keeper/old_tally_test.go | 37 ------------------------------ x/gov/keeper/tally_test.go | 41 ++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 37 deletions(-) diff --git a/x/gov/keeper/old_tally_test.go b/x/gov/keeper/old_tally_test.go index f7ce7c2f8547..b9ceb73b0dd6 100644 --- a/x/gov/keeper/old_tally_test.go +++ b/x/gov/keeper/old_tally_test.go @@ -10,43 +10,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking" ) -func TestTallyDelgatorMultipleInherit(t *testing.T) { - ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) - createValidators(ctx, sk, []int64{25, 6, 7}) - - delTokens := sdk.TokensFromConsensusPower(10) - val2, found := sk.GetValidator(ctx, valOpAddr2) - require.True(t, found) - val3, found := sk.GetValidator(ctx, valOpAddr3) - require.True(t, found) - - _, err := sk.Delegate(ctx, TestAddrs[0], delTokens, sdk.Unbonded, val2, true) - require.NoError(t, err) - _, err = sk.Delegate(ctx, TestAddrs[0], delTokens, sdk.Unbonded, val3, true) - require.NoError(t, err) - - _ = staking.EndBlocker(ctx, sk) - - tp := TestProposal - proposal, err := keeper.SubmitProposal(ctx, tp) - require.NoError(t, err) - proposalID := proposal.ProposalID - proposal.Status = types.StatusVotingPeriod - keeper.SetProposal(ctx, proposal) - - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionYes)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionNo)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr3, types.OptionNo)) - - proposal, ok := keeper.GetProposal(ctx, proposalID) - require.True(t, ok) - passes, burnDeposits, tallyResults := keeper.Tally(ctx, proposal) - - require.False(t, passes) - require.False(t, burnDeposits) - require.False(t, tallyResults.Equals(types.EmptyTallyResult())) -} - func TestTallyJailedValidator(t *testing.T) { ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{25, 6, 7}) diff --git a/x/gov/keeper/tally_test.go b/x/gov/keeper/tally_test.go index 69a5ca71ce92..bc411019b7b0 100644 --- a/x/gov/keeper/tally_test.go +++ b/x/gov/keeper/tally_test.go @@ -350,3 +350,44 @@ func TestTallyDelgatorMultipleOverride(t *testing.T) { require.False(t, burnDeposits) require.False(t, tallyResults.Equals(types.EmptyTallyResult())) } + +func TestTallyDelgatorMultipleInherit(t *testing.T) { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + createValidators(ctx, app, []int64{25, 6, 7}) + + addrs, vals := createValidators(ctx, app, []int64{5, 6, 7}) + + delTokens := sdk.TokensFromConsensusPower(10) + val2, found := app.StakingKeeper.GetValidator(ctx, vals[1]) + require.True(t, found) + val3, found := app.StakingKeeper.GetValidator(ctx, vals[2]) + require.True(t, found) + + _, err := app.StakingKeeper.Delegate(ctx, addrs[3], delTokens, sdk.Unbonded, val2, true) + require.NoError(t, err) + _, err = app.StakingKeeper.Delegate(ctx, addrs[3], delTokens, sdk.Unbonded, val3, true) + require.NoError(t, err) + + _ = staking.EndBlocker(ctx, app.StakingKeeper) + + tp := TestProposal + proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) + require.NoError(t, err) + proposalID := proposal.ProposalID + proposal.Status = types.StatusVotingPeriod + app.GovKeeper.SetProposal(ctx, proposal) + + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[0], types.OptionYes)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[1], types.OptionNo)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[2], types.OptionNo)) + + proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID) + require.True(t, ok) + passes, burnDeposits, tallyResults := app.GovKeeper.Tally(ctx, proposal) + + require.False(t, passes) + require.False(t, burnDeposits) + require.False(t, tallyResults.Equals(types.EmptyTallyResult())) +} From 275b78f1c3d4e1dc95a71f1c202487c69bbd33e8 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 2 Mar 2020 19:25:05 +0100 Subject: [PATCH 324/529] add TestTallyJailedValidator to simapp --- x/gov/keeper/old_tally_test.go | 40 --------------------------------- x/gov/keeper/tally_test.go | 41 ++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 40 deletions(-) diff --git a/x/gov/keeper/old_tally_test.go b/x/gov/keeper/old_tally_test.go index b9ceb73b0dd6..9c08935e113a 100644 --- a/x/gov/keeper/old_tally_test.go +++ b/x/gov/keeper/old_tally_test.go @@ -7,48 +7,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/gov/types" - "github.com/cosmos/cosmos-sdk/x/staking" ) -func TestTallyJailedValidator(t *testing.T) { - ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) - createValidators(ctx, sk, []int64{25, 6, 7}) - - delTokens := sdk.TokensFromConsensusPower(10) - val2, found := sk.GetValidator(ctx, valOpAddr2) - require.True(t, found) - val3, found := sk.GetValidator(ctx, valOpAddr3) - require.True(t, found) - - _, err := sk.Delegate(ctx, TestAddrs[0], delTokens, sdk.Unbonded, val2, true) - require.NoError(t, err) - _, err = sk.Delegate(ctx, TestAddrs[0], delTokens, sdk.Unbonded, val3, true) - require.NoError(t, err) - - _ = staking.EndBlocker(ctx, sk) - - sk.Jail(ctx, sdk.ConsAddress(val2.GetConsPubKey().Address())) - - tp := TestProposal - proposal, err := keeper.SubmitProposal(ctx, tp) - require.NoError(t, err) - proposalID := proposal.ProposalID - proposal.Status = types.StatusVotingPeriod - keeper.SetProposal(ctx, proposal) - - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionYes)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionNo)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr3, types.OptionNo)) - - proposal, ok := keeper.GetProposal(ctx, proposalID) - require.True(t, ok) - passes, burnDeposits, tallyResults := keeper.Tally(ctx, proposal) - - require.True(t, passes) - require.False(t, burnDeposits) - require.False(t, tallyResults.Equals(types.EmptyTallyResult())) -} - func TestTallyValidatorMultipleDelegations(t *testing.T) { ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{10, 10, 10}) diff --git a/x/gov/keeper/tally_test.go b/x/gov/keeper/tally_test.go index bc411019b7b0..cab33140dc5c 100644 --- a/x/gov/keeper/tally_test.go +++ b/x/gov/keeper/tally_test.go @@ -391,3 +391,44 @@ func TestTallyDelgatorMultipleInherit(t *testing.T) { require.False(t, burnDeposits) require.False(t, tallyResults.Equals(types.EmptyTallyResult())) } + +func TestTallyJailedValidator(t *testing.T) { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + addrs, valAddrs := createValidators(ctx, app, []int64{25, 6, 7}) + + delTokens := sdk.TokensFromConsensusPower(10) + val2, found := app.StakingKeeper.GetValidator(ctx, valAddrs[1]) + require.True(t, found) + val3, found := app.StakingKeeper.GetValidator(ctx, valAddrs[2]) + require.True(t, found) + + _, err := app.StakingKeeper.Delegate(ctx, addrs[3], delTokens, sdk.Unbonded, val2, true) + require.NoError(t, err) + _, err = app.StakingKeeper.Delegate(ctx, addrs[3], delTokens, sdk.Unbonded, val3, true) + require.NoError(t, err) + + _ = staking.EndBlocker(ctx, app.StakingKeeper) + + app.StakingKeeper.Jail(ctx, sdk.ConsAddress(val2.GetConsPubKey().Address())) + + tp := TestProposal + proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) + require.NoError(t, err) + proposalID := proposal.ProposalID + proposal.Status = types.StatusVotingPeriod + app.GovKeeper.SetProposal(ctx, proposal) + + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[0], types.OptionYes)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[1], types.OptionNo)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[2], types.OptionNo)) + + proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID) + require.True(t, ok) + passes, burnDeposits, tallyResults := app.GovKeeper.Tally(ctx, proposal) + + require.True(t, passes) + require.False(t, burnDeposits) + require.False(t, tallyResults.Equals(types.EmptyTallyResult())) +} From 894b2e58974fcdecb681d903582c2305f9e36d26 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 2 Mar 2020 19:46:39 +0100 Subject: [PATCH 325/529] refactor old tally test --- x/gov/keeper/old_tally_test.go | 48 ---------------------------------- x/gov/keeper/tally_test.go | 40 ++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 48 deletions(-) delete mode 100644 x/gov/keeper/old_tally_test.go diff --git a/x/gov/keeper/old_tally_test.go b/x/gov/keeper/old_tally_test.go deleted file mode 100644 index 9c08935e113a..000000000000 --- a/x/gov/keeper/old_tally_test.go +++ /dev/null @@ -1,48 +0,0 @@ -package keeper - -import ( - "testing" - - "github.com/stretchr/testify/require" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/gov/types" -) - -func TestTallyValidatorMultipleDelegations(t *testing.T) { - ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) - createValidators(ctx, sk, []int64{10, 10, 10}) - - delTokens := sdk.TokensFromConsensusPower(10) - val2, found := sk.GetValidator(ctx, valOpAddr2) - require.True(t, found) - - _, err := sk.Delegate(ctx, valAccAddr1, delTokens, sdk.Unbonded, val2, true) - require.NoError(t, err) - - tp := TestProposal - proposal, err := keeper.SubmitProposal(ctx, tp) - require.NoError(t, err) - proposalID := proposal.ProposalID - proposal.Status = types.StatusVotingPeriod - keeper.SetProposal(ctx, proposal) - - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionYes)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionNo)) - require.NoError(t, keeper.AddVote(ctx, proposalID, valAccAddr3, types.OptionYes)) - - proposal, ok := keeper.GetProposal(ctx, proposalID) - require.True(t, ok) - passes, burnDeposits, tallyResults := keeper.Tally(ctx, proposal) - - require.True(t, passes) - require.False(t, burnDeposits) - - expectedYes := sdk.TokensFromConsensusPower(30) - expectedAbstain := sdk.TokensFromConsensusPower(0) - expectedNo := sdk.TokensFromConsensusPower(10) - expectedNoWithVeto := sdk.TokensFromConsensusPower(0) - expectedTallyResult := types.NewTallyResult(expectedYes, expectedAbstain, expectedNo, expectedNoWithVeto) - - require.True(t, tallyResults.Equals(expectedTallyResult)) -} diff --git a/x/gov/keeper/tally_test.go b/x/gov/keeper/tally_test.go index cab33140dc5c..3b7ff6958769 100644 --- a/x/gov/keeper/tally_test.go +++ b/x/gov/keeper/tally_test.go @@ -432,3 +432,43 @@ func TestTallyJailedValidator(t *testing.T) { require.False(t, burnDeposits) require.False(t, tallyResults.Equals(types.EmptyTallyResult())) } + +func TestTallyValidatorMultipleDelegations(t *testing.T) { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + addrs, valAddrs := createValidators(ctx, app, []int64{10, 10, 10}) + + delTokens := sdk.TokensFromConsensusPower(10) + val2, found := app.StakingKeeper.GetValidator(ctx, valAddrs[1]) + require.True(t, found) + + _, err := app.StakingKeeper.Delegate(ctx, addrs[0], delTokens, sdk.Unbonded, val2, true) + require.NoError(t, err) + + tp := TestProposal + proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) + require.NoError(t, err) + proposalID := proposal.ProposalID + proposal.Status = types.StatusVotingPeriod + app.GovKeeper.SetProposal(ctx, proposal) + + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[0], types.OptionYes)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[1], types.OptionNo)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[2], types.OptionYes)) + + proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID) + require.True(t, ok) + passes, burnDeposits, tallyResults := app.GovKeeper.Tally(ctx, proposal) + + require.True(t, passes) + require.False(t, burnDeposits) + + expectedYes := sdk.TokensFromConsensusPower(30) + expectedAbstain := sdk.TokensFromConsensusPower(0) + expectedNo := sdk.TokensFromConsensusPower(10) + expectedNoWithVeto := sdk.TokensFromConsensusPower(0) + expectedTallyResult := types.NewTallyResult(expectedYes, expectedAbstain, expectedNo, expectedNoWithVeto) + + require.True(t, tallyResults.Equals(expectedTallyResult)) +} From e266c40ce12d45b851cb954e76761c78dbefe3ed Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 2 Mar 2020 19:50:39 +0100 Subject: [PATCH 326/529] refactor vote test --- x/gov/keeper/vote_test.go | 49 ++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/x/gov/keeper/vote_test.go b/x/gov/keeper/vote_test.go index ae25c7fcc230..8a87cdad6900 100644 --- a/x/gov/keeper/vote_test.go +++ b/x/gov/keeper/vote_test.go @@ -1,64 +1,71 @@ -package keeper +package keeper_test import ( "testing" - "github.com/stretchr/testify/require" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/cosmos-sdk/simapp" + abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/stretchr/testify/require" ) func TestVotes(t *testing.T) { - ctx, _, _, keeper, _, _ := createTestInput(t, false, 100) // nolint: dogsled + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + addrs := simapp.AddTestAddrsIncremental(app, ctx, 5, sdk.NewInt(30000000)) tp := TestProposal - proposal, err := keeper.SubmitProposal(ctx, tp) + proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) require.NoError(t, err) proposalID := proposal.ProposalID var invalidOption types.VoteOption = 0x10 - require.Error(t, keeper.AddVote(ctx, proposalID, TestAddrs[0], types.OptionYes), "proposal not on voting period") - require.Error(t, keeper.AddVote(ctx, 10, TestAddrs[0], types.OptionYes), "invalid proposal ID") + require.Error(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[0], types.OptionYes), "proposal not on voting period") + require.Error(t, app.GovKeeper.AddVote(ctx, 10, addrs[0], types.OptionYes), "invalid proposal ID") proposal.Status = types.StatusVotingPeriod - keeper.SetProposal(ctx, proposal) + app.GovKeeper.SetProposal(ctx, proposal) - require.Error(t, keeper.AddVote(ctx, proposalID, TestAddrs[0], invalidOption), "invalid option") + require.Error(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[0], invalidOption), "invalid option") // Test first vote - require.NoError(t, keeper.AddVote(ctx, proposalID, TestAddrs[0], types.OptionAbstain)) - vote, found := keeper.GetVote(ctx, proposalID, TestAddrs[0]) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[0], types.OptionAbstain)) + vote, found := app.GovKeeper.GetVote(ctx, proposalID, addrs[0]) require.True(t, found) - require.Equal(t, TestAddrs[0], vote.Voter) + require.Equal(t, addrs[0], vote.Voter) require.Equal(t, proposalID, vote.ProposalID) require.Equal(t, types.OptionAbstain, vote.Option) // Test change of vote - require.NoError(t, keeper.AddVote(ctx, proposalID, TestAddrs[0], types.OptionYes)) - vote, found = keeper.GetVote(ctx, proposalID, TestAddrs[0]) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[0], types.OptionYes)) + vote, found = app.GovKeeper.GetVote(ctx, proposalID, addrs[0]) require.True(t, found) - require.Equal(t, TestAddrs[0], vote.Voter) + require.Equal(t, addrs[0], vote.Voter) require.Equal(t, proposalID, vote.ProposalID) require.Equal(t, types.OptionYes, vote.Option) // Test second vote - require.NoError(t, keeper.AddVote(ctx, proposalID, TestAddrs[1], types.OptionNoWithVeto)) - vote, found = keeper.GetVote(ctx, proposalID, TestAddrs[1]) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[1], types.OptionNoWithVeto)) + vote, found = app.GovKeeper.GetVote(ctx, proposalID, addrs[1]) require.True(t, found) - require.Equal(t, TestAddrs[1], vote.Voter) + require.Equal(t, addrs[1], vote.Voter) require.Equal(t, proposalID, vote.ProposalID) require.Equal(t, types.OptionNoWithVeto, vote.Option) // Test vote iterator // NOTE order of deposits is determined by the addresses - votes := keeper.GetAllVotes(ctx) + votes := app.GovKeeper.GetAllVotes(ctx) require.Len(t, votes, 2) - require.Equal(t, votes, keeper.GetVotes(ctx, proposalID)) - require.Equal(t, TestAddrs[0], votes[0].Voter) + require.Equal(t, votes, app.GovKeeper.GetVotes(ctx, proposalID)) + require.Equal(t, addrs[0], votes[0].Voter) require.Equal(t, proposalID, votes[0].ProposalID) require.Equal(t, types.OptionYes, votes[0].Option) - require.Equal(t, TestAddrs[1], votes[1].Voter) + require.Equal(t, addrs[1], votes[1].Voter) require.Equal(t, proposalID, votes[1].ProposalID) require.Equal(t, types.OptionNoWithVeto, votes[1].Option) } From eba38af83d55da594cb89e3b02bb6f4bd02c96d9 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 2 Mar 2020 19:56:29 +0100 Subject: [PATCH 327/529] end of gov refactoring --- x/gov/abci_test.go | 7 +- x/gov/common_test.go | 15 ++- x/gov/genesis_test.go | 9 +- x/gov/keeper/old_test_common.go | 211 -------------------------------- 4 files changed, 19 insertions(+), 223 deletions(-) delete mode 100644 x/gov/keeper/old_test_common.go diff --git a/x/gov/abci_test.go b/x/gov/abci_test.go index 3e87d44e56a7..79db8f81af87 100644 --- a/x/gov/abci_test.go +++ b/x/gov/abci_test.go @@ -10,7 +10,6 @@ import ( "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/gov" - keep "github.com/cosmos/cosmos-sdk/x/gov/keeper" "github.com/cosmos/cosmos-sdk/x/staking" ) @@ -212,7 +211,7 @@ func TestTickPassedVotingPeriod(t *testing.T) { activeQueue.Close() proposalCoins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(5))} - newProposalMsg := gov.NewMsgSubmitProposal(keep.TestProposal, proposalCoins, addrs[0]) + newProposalMsg := gov.NewMsgSubmitProposal(TestProposal, proposalCoins, addrs[0]) res, err := govHandler(ctx, newProposalMsg) require.NoError(t, err) @@ -277,7 +276,7 @@ func TestProposalPassedEndblocker(t *testing.T) { require.NotNil(t, macc) initialModuleAccCoins := app.BankKeeper.GetAllBalances(ctx, macc.GetAddress()) - proposal, err := app.GovKeeper.SubmitProposal(ctx, keep.TestProposal) + proposal, err := app.GovKeeper.SubmitProposal(ctx, TestProposal) require.NoError(t, err) proposalCoins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(10))} @@ -329,7 +328,7 @@ func TestEndBlockerProposalHandlerFailed(t *testing.T) { // Create a proposal where the handler will pass for the test proposal // because the value of contextKeyBadProposal is true. ctx = ctx.WithValue(contextKeyBadProposal, true) - proposal, err := app.GovKeeper.SubmitProposal(ctx, keep.TestProposal) + proposal, err := app.GovKeeper.SubmitProposal(ctx, TestProposal) require.NoError(t, err) proposalCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(10))) diff --git a/x/gov/common_test.go b/x/gov/common_test.go index 79e927fd50de..31d4dd168f3a 100644 --- a/x/gov/common_test.go +++ b/x/gov/common_test.go @@ -11,12 +11,15 @@ import ( "github.com/tendermint/tendermint/crypto/ed25519" sdk "github.com/cosmos/cosmos-sdk/types" - keep "github.com/cosmos/cosmos-sdk/x/gov/keeper" + "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/cosmos/cosmos-sdk/x/staking" ) var ( - valTokens = sdk.TokensFromConsensusPower(42) + valTokens = sdk.TokensFromConsensusPower(42) + TestProposal = types.NewTextProposal("Test", "description") + TestDescription = staking.NewDescription("T", "E", "S", "T", "Z") + TestCommissionRates = staking.NewCommissionRates(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()) ) // SortAddresses - Sorts Addresses @@ -83,7 +86,7 @@ func createValidators(t *testing.T, stakingHandler sdk.Handler, ctx sdk.Context, valTokens := sdk.TokensFromConsensusPower(powerAmt[i]) valCreateMsg := staking.NewMsgCreateValidator( addrs[i], pubkeys[i], sdk.NewCoin(sdk.DefaultBondDenom, valTokens), - keep.TestDescription, keep.TestCommissionRates, sdk.OneInt(), + TestDescription, TestCommissionRates, sdk.OneInt(), ) res, err := stakingHandler(ctx, valCreateMsg) @@ -91,3 +94,9 @@ func createValidators(t *testing.T, stakingHandler sdk.Handler, ctx sdk.Context, require.NotNil(t, res) } } + +// ProposalEqual checks if two proposals are equal (note: slow, for tests only) +func ProposalEqual(proposalA types.Proposal, proposalB types.Proposal) bool { + return bytes.Equal(types.ModuleCdc.MustMarshalBinaryBare(proposalA), + types.ModuleCdc.MustMarshalBinaryBare(proposalB)) +} diff --git a/x/gov/genesis_test.go b/x/gov/genesis_test.go index d9f8857b168f..52ee0c0e1868 100644 --- a/x/gov/genesis_test.go +++ b/x/gov/genesis_test.go @@ -12,7 +12,6 @@ import ( "github.com/cosmos/cosmos-sdk/simapp" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/gov" - keep "github.com/cosmos/cosmos-sdk/x/gov/keeper" ) func TestImportExportQueues(t *testing.T) { @@ -28,7 +27,7 @@ func TestImportExportQueues(t *testing.T) { ctx = app.BaseApp.NewContext(false, abci.Header{}) // Create two proposals, put the second into the voting period - proposal := keep.TestProposal + proposal := TestProposal proposal1, err := app.GovKeeper.SubmitProposal(ctx, proposal) require.NoError(t, err) proposalID1 := proposal1.ProposalID @@ -116,7 +115,7 @@ func TestEqualProposals(t *testing.T) { app.BeginBlock(abci.RequestBeginBlock{Header: header}) // Submit two proposals - proposal := keep.TestProposal + proposal := TestProposal proposal1, err := app.GovKeeper.SubmitProposal(ctx, proposal) require.NoError(t, err) @@ -125,7 +124,7 @@ func TestEqualProposals(t *testing.T) { // They are similar but their IDs should be different require.NotEqual(t, proposal1, proposal2) - require.False(t, keep.ProposalEqual(proposal1, proposal2)) + require.False(t, ProposalEqual(proposal1, proposal2)) // Now create two genesis blocks state1 := gov.GenesisState{Proposals: []gov.Proposal{proposal1}} @@ -137,7 +136,7 @@ func TestEqualProposals(t *testing.T) { proposal1.ProposalID = 55 proposal2.ProposalID = 55 require.Equal(t, proposal1, proposal1) - require.True(t, keep.ProposalEqual(proposal1, proposal2)) + require.True(t, ProposalEqual(proposal1, proposal2)) // Reassign proposals into state state1.Proposals[0] = proposal1 diff --git a/x/gov/keeper/old_test_common.go b/x/gov/keeper/old_test_common.go deleted file mode 100644 index d8620b1a8cd9..000000000000 --- a/x/gov/keeper/old_test_common.go +++ /dev/null @@ -1,211 +0,0 @@ -package keeper - -// noalias -// nolint -// DONTCOVER - -import ( - "bytes" - "encoding/hex" - "testing" - - "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/crypto" - "github.com/tendermint/tendermint/crypto/ed25519" - "github.com/tendermint/tendermint/libs/log" - tmtypes "github.com/tendermint/tendermint/types" - dbm "github.com/tendermint/tm-db" - - "github.com/cosmos/cosmos-sdk/codec" - simappcodec "github.com/cosmos/cosmos-sdk/simapp/codec" - "github.com/cosmos/cosmos-sdk/store" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/bank" - "github.com/cosmos/cosmos-sdk/x/gov/types" - "github.com/cosmos/cosmos-sdk/x/params/keeper" - paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" - "github.com/cosmos/cosmos-sdk/x/staking" - "github.com/cosmos/cosmos-sdk/x/supply" -) - -// dummy addresses used for testing -var ( - delPk1 = newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB51") - delPk2 = newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB50") - delPk3 = newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB52") - delAddr1 = sdk.AccAddress(delPk1.Address()) - delAddr2 = sdk.AccAddress(delPk2.Address()) - delAddr3 = sdk.AccAddress(delPk3.Address()) - - valOpPk1 = newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB53") - valOpPk2 = newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB54") - valOpPk3 = newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB55") - valOpAddr1 = sdk.ValAddress(valOpPk1.Address()) - valOpAddr2 = sdk.ValAddress(valOpPk2.Address()) - valOpAddr3 = sdk.ValAddress(valOpPk3.Address()) - valAccAddr1 = sdk.AccAddress(valOpPk1.Address()) - valAccAddr2 = sdk.AccAddress(valOpPk2.Address()) - valAccAddr3 = sdk.AccAddress(valOpPk3.Address()) - - TestAddrs = []sdk.AccAddress{ - delAddr1, delAddr2, delAddr3, - valAccAddr1, valAccAddr2, valAccAddr3, - } - pubkeys = []crypto.PubKey{ - delPk1, delPk2, delPk3, valOpPk1, valOpPk2, valOpPk3, - } -) - -// TODO: remove dependency with staking -var ( - TestProposal = types.NewTextProposal("Test", "description") - TestDescription = staking.NewDescription("T", "E", "S", "T", "Z") - TestCommissionRates = staking.NewCommissionRates(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()) -) - -// TODO move to common testing framework -func newPubKey(pk string) (res crypto.PubKey) { - pkBytes, err := hex.DecodeString(pk) - if err != nil { - panic(err) - } - var pkEd ed25519.PubKeyEd25519 - copy(pkEd[:], pkBytes) - return pkEd -} - -func makeTestCodec() *codec.Codec { - var cdc = codec.New() - auth.RegisterCodec(cdc) - types.RegisterCodec(cdc) - supply.RegisterCodec(cdc) - staking.RegisterCodec(cdc) - sdk.RegisterCodec(cdc) - codec.RegisterCrypto(cdc) - - return cdc -} - -func createTestInput( - t *testing.T, isCheckTx bool, initPower int64, -) (sdk.Context, auth.AccountKeeper, bank.Keeper, Keeper, staking.Keeper, types.SupplyKeeper, -) { - - initTokens := sdk.TokensFromConsensusPower(initPower) - keyAcc := sdk.NewKVStoreKey(auth.StoreKey) - keyBank := sdk.NewKVStoreKey(bank.StoreKey) - keyGov := sdk.NewKVStoreKey(types.StoreKey) - keyStaking := sdk.NewKVStoreKey(staking.StoreKey) - keySupply := sdk.NewKVStoreKey(supply.StoreKey) - keyParams := sdk.NewKVStoreKey(paramtypes.StoreKey) - tkeyParams := sdk.NewTransientStoreKey(paramtypes.TStoreKey) - - db := dbm.NewMemDB() - ms := store.NewCommitMultiStore(db) - - ms.MountStoreWithDB(keyAcc, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(keySupply, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(keyBank, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(keyGov, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(keyStaking, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(keyParams, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(tkeyParams, sdk.StoreTypeTransient, db) - require.Nil(t, ms.LoadLatestVersion()) - - ctx := sdk.NewContext(ms, abci.Header{ChainID: "gov-chain"}, isCheckTx, log.NewNopLogger()) - ctx = ctx.WithConsensusParams( - &abci.ConsensusParams{ - Validator: &abci.ValidatorParams{ - PubKeyTypes: []string{tmtypes.ABCIPubKeyTypeEd25519}, - }, - }, - ) - - cdc := makeTestCodec() - appCodec := simappcodec.NewAppCodec(cdc) - - maccPerms := map[string][]string{ - auth.FeeCollectorName: nil, - types.ModuleName: nil, - staking.NotBondedPoolName: {supply.Burner, supply.Staking}, - staking.BondedPoolName: {supply.Burner, supply.Staking}, - } - - // create module accounts - feeCollectorAcc := supply.NewEmptyModuleAccount(auth.FeeCollectorName) - govAcc := supply.NewEmptyModuleAccount(types.ModuleName, supply.Burner) - notBondedPool := supply.NewEmptyModuleAccount(staking.NotBondedPoolName, supply.Burner, supply.Staking) - bondPool := supply.NewEmptyModuleAccount(staking.BondedPoolName, supply.Burner, supply.Staking) - - blacklistedAddrs := make(map[string]bool) - blacklistedAddrs[feeCollectorAcc.GetAddress().String()] = true - blacklistedAddrs[govAcc.GetAddress().String()] = true - blacklistedAddrs[notBondedPool.GetAddress().String()] = true - blacklistedAddrs[bondPool.GetAddress().String()] = true - - pk := keeper.NewKeeper(appCodec, keyParams, tkeyParams) - accountKeeper := auth.NewAccountKeeper(appCodec, keyAcc, pk.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount) - bankKeeper := bank.NewBaseKeeper(appCodec, keyBank, accountKeeper, pk.Subspace(bank.DefaultParamspace), blacklistedAddrs) - supplyKeeper := supply.NewKeeper(appCodec, keySupply, accountKeeper, bankKeeper, maccPerms) - - sk := staking.NewKeeper(staking.ModuleCdc, keyStaking, bankKeeper, supplyKeeper, pk.Subspace(staking.DefaultParamspace)) - sk.SetParams(ctx, staking.DefaultParams()) - - rtr := types.NewRouter(). - AddRoute(types.RouterKey, types.ProposalHandler) - - keeper := NewKeeper( - cdc, keyGov, pk.Subspace(types.DefaultParamspace).WithKeyTable(types.ParamKeyTable()), supplyKeeper, sk, rtr, - ) - - keeper.SetProposalID(ctx, types.DefaultStartingProposalID) - keeper.SetDepositParams(ctx, types.DefaultDepositParams()) - keeper.SetVotingParams(ctx, types.DefaultVotingParams()) - keeper.SetTallyParams(ctx, types.DefaultTallyParams()) - - initCoins := sdk.NewCoins(sdk.NewCoin(sk.BondDenom(ctx), initTokens)) - totalSupply := sdk.NewCoins(sdk.NewCoin(sk.BondDenom(ctx), initTokens.MulRaw(int64(len(TestAddrs))))) - supplyKeeper.SetSupply(ctx, supply.NewSupply(totalSupply)) - - for i, addr := range TestAddrs { - accountKeeper.SetAccount(ctx, auth.NewBaseAccount(addr, pubkeys[i], uint64(i), 0)) - require.NoError(t, bankKeeper.SetBalances(ctx, addr, initCoins)) - } - - keeper.supplyKeeper.SetModuleAccount(ctx, feeCollectorAcc) - keeper.supplyKeeper.SetModuleAccount(ctx, govAcc) - keeper.supplyKeeper.SetModuleAccount(ctx, bondPool) - keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) - - return ctx, accountKeeper, bankKeeper, keeper, sk, supplyKeeper -} - -// ProposalEqual checks if two proposals are equal (note: slow, for tests only) -func ProposalEqual(proposalA types.Proposal, proposalB types.Proposal) bool { - return bytes.Equal(types.ModuleCdc.MustMarshalBinaryBare(proposalA), - types.ModuleCdc.MustMarshalBinaryBare(proposalB)) -} - -func createValidators(ctx sdk.Context, sk staking.Keeper, powers []int64) { - val1 := staking.NewValidator(valOpAddr1, valOpPk1, staking.Description{}) - val2 := staking.NewValidator(valOpAddr2, valOpPk2, staking.Description{}) - val3 := staking.NewValidator(valOpAddr3, valOpPk3, staking.Description{}) - - sk.SetValidator(ctx, val1) - sk.SetValidator(ctx, val2) - sk.SetValidator(ctx, val3) - sk.SetValidatorByConsAddr(ctx, val1) - sk.SetValidatorByConsAddr(ctx, val2) - sk.SetValidatorByConsAddr(ctx, val3) - sk.SetNewValidatorByPowerIndex(ctx, val1) - sk.SetNewValidatorByPowerIndex(ctx, val2) - sk.SetNewValidatorByPowerIndex(ctx, val3) - - _, _ = sk.Delegate(ctx, valAccAddr1, sdk.TokensFromConsensusPower(powers[0]), sdk.Unbonded, val1, true) - _, _ = sk.Delegate(ctx, valAccAddr2, sdk.TokensFromConsensusPower(powers[1]), sdk.Unbonded, val2, true) - _, _ = sk.Delegate(ctx, valAccAddr3, sdk.TokensFromConsensusPower(powers[2]), sdk.Unbonded, val3, true) - - _ = staking.EndBlocker(ctx, sk) -} From a89eb7784110c77c0ffed2fcdd1cfcc66ce82b8d Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Mon, 2 Mar 2020 14:10:27 -0500 Subject: [PATCH 328/529] Add equal option to upgrade proto types --- x/upgrade/types/types.pb.go | 104 ++++++++++++++++++++++++++++-------- x/upgrade/types/types.proto | 54 ++++++++++--------- 2 files changed, 110 insertions(+), 48 deletions(-) diff --git a/x/upgrade/types/types.pb.go b/x/upgrade/types/types.pb.go index 8cc9e383bedb..e6c317700c82 100644 --- a/x/upgrade/types/types.pb.go +++ b/x/upgrade/types/types.pb.go @@ -164,32 +164,90 @@ func init() { func init() { proto.RegisterFile("x/upgrade/types/types.proto", fileDescriptor_2a308fd9dd71aff8) } var fileDescriptor_2a308fd9dd71aff8 = []byte{ - // 364 bytes of a gzipped FileDescriptorProto + // 376 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x52, 0x31, 0x6f, 0xe2, 0x30, - 0x18, 0x8d, 0x8f, 0x1c, 0x3a, 0xcc, 0x66, 0x9d, 0x8e, 0x88, 0x13, 0x26, 0x62, 0xa8, 0x18, 0x5a, - 0x47, 0xa5, 0x43, 0x3b, 0xd3, 0xbd, 0x42, 0x69, 0xab, 0x4a, 0x5d, 0x90, 0x49, 0x4c, 0x62, 0x91, - 0xc4, 0x56, 0x6c, 0x5a, 0xd8, 0x3a, 0x77, 0xe2, 0x67, 0x31, 0x32, 0x32, 0xb5, 0x05, 0xfe, 0x48, - 0x95, 0x18, 0xd4, 0xaa, 0x52, 0xb7, 0x2e, 0xf6, 0xfb, 0xac, 0xf7, 0xbd, 0xf7, 0x3e, 0xdb, 0xf0, - 0xff, 0xcc, 0x9b, 0xca, 0x28, 0xa7, 0x21, 0xf3, 0xf4, 0x5c, 0x32, 0x65, 0x56, 0x22, 0x73, 0xa1, - 0x05, 0x6a, 0x04, 0x42, 0xa5, 0x42, 0x0d, 0x55, 0x38, 0x21, 0x33, 0xb2, 0xe7, 0x91, 0x87, 0xd3, - 0xe6, 0x91, 0x8e, 0x79, 0x1e, 0x0e, 0x25, 0xcd, 0xf5, 0xdc, 0x2b, 0xb9, 0x5e, 0x24, 0x22, 0xf1, - 0x81, 0x8c, 0x40, 0xb3, 0x1d, 0x09, 0x11, 0x25, 0xcc, 0x50, 0x46, 0xd3, 0xb1, 0xa7, 0x79, 0xca, - 0x94, 0xa6, 0xa9, 0x34, 0x84, 0xce, 0x13, 0x80, 0xf6, 0x20, 0xa1, 0x19, 0x42, 0xd0, 0xce, 0x68, - 0xca, 0x1c, 0xe0, 0x82, 0x6e, 0xcd, 0x2f, 0x31, 0xba, 0x80, 0x76, 0xc1, 0x77, 0x7e, 0xb9, 0xa0, - 0x5b, 0xef, 0x35, 0x89, 0x11, 0x23, 0x07, 0x31, 0x72, 0x73, 0x10, 0xeb, 0xff, 0x59, 0xbe, 0xb4, - 0xad, 0xc5, 0x6b, 0x1b, 0xf8, 0x65, 0x07, 0xfa, 0x07, 0xab, 0x31, 0xe3, 0x51, 0xac, 0x9d, 0x8a, - 0x0b, 0xba, 0x15, 0x7f, 0x5f, 0x15, 0x2e, 0x3c, 0x1b, 0x0b, 0xc7, 0x36, 0x2e, 0x05, 0xee, 0x3c, - 0x03, 0xd8, 0xb8, 0x16, 0x63, 0xfd, 0x48, 0x73, 0x76, 0x6b, 0x46, 0x1c, 0xe4, 0x42, 0x0a, 0x45, - 0x13, 0xf4, 0x17, 0xfe, 0xd6, 0x5c, 0x27, 0x87, 0x58, 0xa6, 0x40, 0x2e, 0xac, 0x87, 0x4c, 0x05, - 0x39, 0x97, 0x9a, 0x8b, 0xac, 0x8c, 0x57, 0xf3, 0x3f, 0x1f, 0xa1, 0x73, 0x68, 0xcb, 0x84, 0x66, - 0xa5, 0x7b, 0xbd, 0xd7, 0x22, 0xdf, 0xdc, 0x23, 0x29, 0x46, 0xef, 0xdb, 0x45, 0x78, 0xbf, 0x6c, - 0xe8, 0xdc, 0xc1, 0xd6, 0x25, 0xcd, 0x02, 0x96, 0xfc, 0x70, 0xa2, 0xfe, 0xd5, 0x72, 0x83, 0xad, - 0xf5, 0x06, 0x5b, 0xcb, 0x2d, 0x06, 0xab, 0x2d, 0x06, 0x6f, 0x5b, 0x0c, 0x16, 0x3b, 0x6c, 0xad, - 0x76, 0xd8, 0x5a, 0xef, 0xb0, 0x75, 0x7f, 0x1c, 0x71, 0x1d, 0x4f, 0x47, 0x24, 0x10, 0xa9, 0x67, - 0xf2, 0xee, 0xb7, 0x13, 0x15, 0x4e, 0xbc, 0x2f, 0xdf, 0x64, 0x54, 0x2d, 0x5f, 0xe1, 0xec, 0x3d, - 0x00, 0x00, 0xff, 0xff, 0x0f, 0x77, 0x53, 0x0a, 0x40, 0x02, 0x00, 0x00, + 0x18, 0x8d, 0x8f, 0x1c, 0x3a, 0xcc, 0x66, 0x9d, 0x8e, 0x88, 0x13, 0x4e, 0xc4, 0x70, 0x62, 0xb8, + 0x73, 0x74, 0xdc, 0x70, 0xa7, 0x1b, 0xe9, 0x5e, 0xa1, 0xb4, 0x5d, 0x2a, 0x55, 0xc8, 0x24, 0x26, + 0xb1, 0x48, 0x62, 0x2b, 0x36, 0x2d, 0x6c, 0xfd, 0x09, 0xfc, 0x84, 0xfe, 0x1c, 0x46, 0x46, 0xa6, + 0xb6, 0xc0, 0xd2, 0x9f, 0x51, 0x25, 0x06, 0xb5, 0xaa, 0xd4, 0xad, 0x8b, 0xfd, 0x3e, 0xeb, 0x7d, + 0xef, 0xbd, 0xcf, 0x36, 0xfc, 0x3e, 0xf7, 0x67, 0x32, 0x2e, 0x68, 0xc4, 0x7c, 0xbd, 0x90, 0x4c, + 0x99, 0x95, 0xc8, 0x42, 0x68, 0x81, 0x5a, 0xa1, 0x50, 0x99, 0x50, 0x23, 0x15, 0x4d, 0xc9, 0x9c, + 0x1c, 0x78, 0xe4, 0xfa, 0x77, 0xfb, 0x87, 0x4e, 0x78, 0x11, 0x8d, 0x24, 0x2d, 0xf4, 0xc2, 0xaf, + 0xb8, 0x7e, 0x2c, 0x62, 0xf1, 0x82, 0x8c, 0x40, 0xdb, 0x8d, 0x85, 0x88, 0x53, 0x66, 0x28, 0xe3, + 0xd9, 0xc4, 0xd7, 0x3c, 0x63, 0x4a, 0xd3, 0x4c, 0x1a, 0x42, 0xf7, 0x16, 0x40, 0x7b, 0x98, 0xd2, + 0x1c, 0x21, 0x68, 0xe7, 0x34, 0x63, 0x0e, 0xf0, 0x40, 0xaf, 0x11, 0x54, 0x18, 0xfd, 0x83, 0x76, + 0xc9, 0x77, 0x3e, 0x79, 0xa0, 0xd7, 0xec, 0xb7, 0x89, 0x11, 0x23, 0x47, 0x31, 0x72, 0x7e, 0x14, + 0x1b, 0x7c, 0x59, 0xdd, 0xbb, 0xd6, 0xf2, 0xc1, 0x05, 0x41, 0xd5, 0x81, 0xbe, 0xc1, 0x7a, 0xc2, + 0x78, 0x9c, 0x68, 0xa7, 0xe6, 0x81, 0x5e, 0x2d, 0x38, 0x54, 0xa5, 0x0b, 0xcf, 0x27, 0xc2, 0xb1, + 0x8d, 0x4b, 0x89, 0xbb, 0x4b, 0x00, 0x5b, 0x67, 0x62, 0xa2, 0x6f, 0x68, 0xc1, 0x2e, 0xcc, 0x88, + 0xc3, 0x42, 0x48, 0xa1, 0x68, 0x8a, 0xbe, 0xc2, 0xcf, 0x9a, 0xeb, 0xf4, 0x18, 0xcb, 0x14, 0xc8, + 0x83, 0xcd, 0x88, 0xa9, 0xb0, 0xe0, 0x52, 0x73, 0x91, 0x57, 0xf1, 0x1a, 0xc1, 0xeb, 0x23, 0xf4, + 0x17, 0xda, 0x32, 0xa5, 0x79, 0xe5, 0xde, 0xec, 0x77, 0xc8, 0x3b, 0xf7, 0x48, 0xca, 0xd1, 0x07, + 0x76, 0x19, 0x3e, 0xa8, 0x1a, 0xfe, 0xdb, 0x4f, 0x77, 0x2e, 0xe8, 0x5e, 0xc1, 0xce, 0x09, 0xcd, + 0x43, 0x96, 0x7e, 0x70, 0x2e, 0x23, 0x3f, 0x38, 0x5d, 0x6d, 0xb1, 0xb5, 0xd9, 0x62, 0x6b, 0xb5, + 0xc3, 0x60, 0xbd, 0xc3, 0xe0, 0x71, 0x87, 0xc1, 0x72, 0x8f, 0xad, 0xf5, 0x1e, 0x5b, 0x9b, 0x3d, + 0xb6, 0x2e, 0x7f, 0xc6, 0x5c, 0x27, 0xb3, 0x31, 0x09, 0x45, 0xe6, 0x9b, 0xec, 0x87, 0xed, 0x97, + 0x8a, 0xa6, 0xfe, 0x9b, 0x2f, 0x33, 0xae, 0x57, 0x2f, 0xf2, 0xe7, 0x39, 0x00, 0x00, 0xff, 0xff, + 0x4f, 0x2c, 0xc2, 0xac, 0x4c, 0x02, 0x00, 0x00, +} + +func (this *SoftwareUpgradeProposal) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*SoftwareUpgradeProposal) + if !ok { + that2, ok := that.(SoftwareUpgradeProposal) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Title != that1.Title { + return false + } + if this.Description != that1.Description { + return false + } + if !this.Plan.Equal(&that1.Plan) { + return false + } + return true } +func (this *CancelSoftwareUpgradeProposal) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + that1, ok := that.(*CancelSoftwareUpgradeProposal) + if !ok { + that2, ok := that.(CancelSoftwareUpgradeProposal) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Title != that1.Title { + return false + } + if this.Description != that1.Description { + return false + } + return true +} func (m *Plan) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) diff --git a/x/upgrade/types/types.proto b/x/upgrade/types/types.proto index 8770158c4bdb..d020f4401eac 100644 --- a/x/upgrade/types/types.proto +++ b/x/upgrade/types/types.proto @@ -4,41 +4,45 @@ package cosmos_sdk.x.upgrade.v1; import "third_party/proto/gogoproto/gogo.proto"; import "google/protobuf/timestamp.proto"; -option go_package = "github.com/cosmos/cosmos-sdk/x/upgrade/types"; +option go_package = "github.com/cosmos/cosmos-sdk/x/upgrade/types"; option (gogoproto.goproto_stringer_all) = false; -option (gogoproto.goproto_getters_all) = false; +option (gogoproto.goproto_getters_all) = false; // Plan specifies information about a planned upgrade and when it should occur message Plan { - // Sets the name for the upgrade. This name will be used by the upgraded version of the software to apply any - // special "on-upgrade" commands during the first BeginBlock method after the upgrade is applied. It is also used - // to detect whether a software version can handle a given upgrade. If no upgrade handler with this name has been - // set in the software, it will be assumed that the software is out-of-date when the upgrade Time or Height - // is reached and the software will exit. - string name = 1; - - // The time after which the upgrade must be performed. - // Leave set to its zero value to use a pre-defined Height instead. - google.protobuf.Timestamp time = 2 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false]; - - // The height at which the upgrade must be performed. - // Only used if Time is not set. - int64 height = 3; - - // Any application specific upgrade info to be included on-chain - // such as a git commit that validators could automatically upgrade to - string info = 4; + // Sets the name for the upgrade. This name will be used by the upgraded version of the software to apply any + // special "on-upgrade" commands during the first BeginBlock method after the upgrade is applied. It is also used + // to detect whether a software version can handle a given upgrade. If no upgrade handler with this name has been + // set in the software, it will be assumed that the software is out-of-date when the upgrade Time or Height + // is reached and the software will exit. + string name = 1; + + // The time after which the upgrade must be performed. + // Leave set to its zero value to use a pre-defined Height instead. + google.protobuf.Timestamp time = 2 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false]; + + // The height at which the upgrade must be performed. + // Only used if Time is not set. + int64 height = 3; + + // Any application specific upgrade info to be included on-chain + // such as a git commit that validators could automatically upgrade to + string info = 4; } // SoftwareUpgradeProposal is a gov Content type for initiating a software upgrade message SoftwareUpgradeProposal { - string title = 1; - string description = 2; - Plan plan = 3 [(gogoproto.nullable) = false]; + option (gogoproto.equal) = true; + + string title = 1; + string description = 2; + Plan plan = 3 [(gogoproto.nullable) = false]; } // SoftwareUpgradeProposal is a gov Content type for cancelling a software upgrade message CancelSoftwareUpgradeProposal { - string title = 1; - string description = 2; + option (gogoproto.equal) = true; + + string title = 1; + string description = 2; } From 7562c2765a34d18f4216852a1d29f135f9fad7c2 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Mon, 2 Mar 2020 14:13:42 -0500 Subject: [PATCH 329/529] Update gov types --- simapp/codec/codec.pb.go | 516 +++++++++++++++++++++++++++---- simapp/codec/codec.proto | 11 + simapp/codec/msgs.go | 48 ++- x/gov/alias.go | 59 ++-- x/gov/types/codec.go | 2 +- x/gov/types/deposit.go | 6 +- x/gov/types/genesis.go | 15 +- x/gov/types/msgs.go | 73 ++--- x/gov/types/params.go | 28 +- x/gov/types/proposal.go | 6 +- x/gov/types/tally.go | 9 +- x/gov/types/types.pb.go | 652 ++++++++++++++++++++++++++------------- x/gov/types/types.proto | 45 ++- x/gov/types/vote.go | 5 +- 14 files changed, 1078 insertions(+), 397 deletions(-) diff --git a/simapp/codec/codec.pb.go b/simapp/codec/codec.pb.go index d58635ad89d8..17b25255637c 100644 --- a/simapp/codec/codec.pb.go +++ b/simapp/codec/codec.pb.go @@ -356,6 +356,46 @@ func (m *MsgSubmitEvidence) XXX_DiscardUnknown() { var xxx_messageInfo_MsgSubmitEvidence proto.InternalMessageInfo +// MsgSubmitProposal defines the application-level message type for handling +// governance proposals. +type MsgSubmitProposal struct { + Content *Content `protobuf:"bytes,1,opt,name=content,proto3" json:"content,omitempty"` + types4.MsgSubmitProposalBase `protobuf:"bytes,2,opt,name=base,proto3,embedded=base" json:"base"` +} + +func (m *MsgSubmitProposal) Reset() { *m = MsgSubmitProposal{} } +func (m *MsgSubmitProposal) String() string { return proto.CompactTextString(m) } +func (*MsgSubmitProposal) ProtoMessage() {} +func (*MsgSubmitProposal) Descriptor() ([]byte, []int) { + return fileDescriptor_3c6d4085e4065f5a, []int{4} +} +func (m *MsgSubmitProposal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgSubmitProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgSubmitProposal.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 *MsgSubmitProposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgSubmitProposal.Merge(m, src) +} +func (m *MsgSubmitProposal) XXX_Size() int { + return m.Size() +} +func (m *MsgSubmitProposal) XXX_DiscardUnknown() { + xxx_messageInfo_MsgSubmitProposal.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgSubmitProposal proto.InternalMessageInfo + // Proposal defines the application-level concrete proposal type used in governance // proposals. type Proposal struct { @@ -367,7 +407,7 @@ func (m *Proposal) Reset() { *m = Proposal{} } func (m *Proposal) String() string { return proto.CompactTextString(m) } func (*Proposal) ProtoMessage() {} func (*Proposal) Descriptor() ([]byte, []int) { - return fileDescriptor_3c6d4085e4065f5a, []int{4} + return fileDescriptor_3c6d4085e4065f5a, []int{5} } func (m *Proposal) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -419,7 +459,7 @@ func (m *Content) Reset() { *m = Content{} } func (m *Content) String() string { return proto.CompactTextString(m) } func (*Content) ProtoMessage() {} func (*Content) Descriptor() ([]byte, []int) { - return fileDescriptor_3c6d4085e4065f5a, []int{5} + return fileDescriptor_3c6d4085e4065f5a, []int{6} } func (m *Content) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -450,6 +490,7 @@ var xxx_messageInfo_Content proto.InternalMessageInfo type isContent_Sum interface { isContent_Sum() + Equal(interface{}) bool MarshalTo([]byte) (int, error) Size() int } @@ -534,6 +575,7 @@ func init() { proto.RegisterType((*Supply)(nil), "cosmos_sdk.simapp.codec.v1.Supply") proto.RegisterType((*Evidence)(nil), "cosmos_sdk.simapp.codec.v1.Evidence") proto.RegisterType((*MsgSubmitEvidence)(nil), "cosmos_sdk.simapp.codec.v1.MsgSubmitEvidence") + proto.RegisterType((*MsgSubmitProposal)(nil), "cosmos_sdk.simapp.codec.v1.MsgSubmitProposal") proto.RegisterType((*Proposal)(nil), "cosmos_sdk.simapp.codec.v1.Proposal") proto.RegisterType((*Content)(nil), "cosmos_sdk.simapp.codec.v1.Content") } @@ -541,61 +583,62 @@ func init() { func init() { proto.RegisterFile("simapp/codec/codec.proto", fileDescriptor_3c6d4085e4065f5a) } var fileDescriptor_3c6d4085e4065f5a = []byte{ - // 850 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x56, 0xcf, 0x8e, 0xdb, 0x44, - 0x18, 0xb7, 0x69, 0xba, 0x1b, 0x4d, 0x0b, 0x94, 0x11, 0x65, 0xa3, 0x80, 0x92, 0x92, 0x42, 0xc5, - 0x1f, 0xc5, 0x6e, 0x69, 0xa1, 0x6d, 0x2e, 0xa5, 0x09, 0x8b, 0x82, 0xc4, 0xa2, 0x55, 0x16, 0x38, - 0x20, 0x90, 0xe5, 0x8c, 0x07, 0xc7, 0x5a, 0xdb, 0x33, 0x78, 0xc6, 0xc6, 0x79, 0x03, 0xc4, 0x69, - 0x1f, 0x80, 0xc3, 0x8a, 0x07, 0xe0, 0xb4, 0x47, 0x1e, 0x60, 0xb5, 0xa7, 0x3d, 0x72, 0x5a, 0xa1, - 0xdd, 0x0b, 0x8f, 0x81, 0x3c, 0x33, 0x76, 0x6c, 0xd9, 0xc9, 0x5e, 0xac, 0x78, 0xbe, 0xdf, 0xbf, - 0xb1, 0xe7, 0xfb, 0x1c, 0xd0, 0x61, 0x5e, 0x60, 0x53, 0x6a, 0x22, 0xe2, 0x60, 0x24, 0xaf, 0x06, - 0x8d, 0x08, 0x27, 0xb0, 0x8b, 0x08, 0x0b, 0x08, 0xb3, 0x98, 0x73, 0x68, 0x48, 0x90, 0x21, 0xcb, - 0xc9, 0xa3, 0xee, 0xc7, 0x7c, 0xe1, 0x45, 0x8e, 0x45, 0xed, 0x88, 0x2f, 0x4d, 0x01, 0x37, 0x25, - 0x7a, 0x58, 0xbe, 0x91, 0x42, 0xdd, 0x07, 0x75, 0xb0, 0x4b, 0x5c, 0xb2, 0xfa, 0xa5, 0x70, 0x9d, - 0xd4, 0xb4, 0x63, 0xbe, 0x30, 0xf9, 0x92, 0x62, 0x26, 0xaf, 0xaa, 0x72, 0x4f, 0x55, 0x12, 0xcc, - 0xb8, 0x17, 0xba, 0x0d, 0x88, 0x6e, 0x6a, 0xb2, 0x98, 0x52, 0x7f, 0xd9, 0x50, 0x7b, 0x27, 0x35, - 0x71, 0xe2, 0x39, 0x38, 0x44, 0xb8, 0xa1, 0xba, 0x93, 0x9a, 0x2e, 0x49, 0x1a, 0x0a, 0xf7, 0x53, - 0x93, 0xda, 0x91, 0x1d, 0xa8, 0xd5, 0x2c, 0x39, 0x25, 0xcc, 0xf6, 0x2b, 0xa0, 0xb7, 0x53, 0x33, - 0xa6, 0x6e, 0x64, 0x3b, 0xb8, 0x39, 0xb6, 0xe3, 0x31, 0x1e, 0x79, 0xf3, 0x98, 0x7b, 0x24, 0xac, - 0x23, 0x06, 0x7f, 0xb7, 0xc0, 0xf6, 0x4b, 0x84, 0x48, 0x1c, 0x72, 0xf8, 0x25, 0xb8, 0x3d, 0xb7, - 0x19, 0xb6, 0x6c, 0x79, 0xdf, 0xd1, 0xef, 0xe9, 0x1f, 0xdc, 0xfa, 0xe4, 0x5d, 0xa3, 0xf4, 0x1a, - 0x52, 0x23, 0x7b, 0x0c, 0x46, 0xf2, 0xc8, 0x18, 0xdb, 0x0c, 0x2b, 0xe2, 0x54, 0x9b, 0xdd, 0x9a, - 0xaf, 0x6e, 0x61, 0x02, 0xba, 0x88, 0x84, 0xdc, 0x0b, 0x63, 0x12, 0x33, 0x4b, 0x3d, 0xb2, 0x42, - 0xf5, 0x15, 0xa1, 0xfa, 0x59, 0x93, 0xaa, 0x44, 0x66, 0xea, 0x93, 0x82, 0xff, 0xbd, 0x5c, 0x5c, - 0x59, 0x75, 0xd0, 0x9a, 0x1a, 0x0c, 0xc0, 0x8e, 0x83, 0x7d, 0x7b, 0x89, 0x9d, 0x9a, 0xe9, 0x0d, - 0x61, 0xfa, 0x78, 0xb3, 0xe9, 0x17, 0x92, 0x5c, 0x73, 0xbc, 0xeb, 0x34, 0x15, 0x20, 0x05, 0x1d, - 0x8a, 0x23, 0x8f, 0x38, 0x1e, 0xaa, 0xf9, 0xb5, 0x84, 0xdf, 0x93, 0xcd, 0x7e, 0xfb, 0x8a, 0x5d, - 0x33, 0x7c, 0x8b, 0x36, 0x56, 0xe0, 0x37, 0xe0, 0xb5, 0x80, 0x38, 0xb1, 0xbf, 0x7a, 0x45, 0x37, - 0x85, 0xcf, 0xfb, 0x55, 0x1f, 0x79, 0x0e, 0x33, 0x87, 0x3d, 0x81, 0x5e, 0x09, 0xbf, 0x1a, 0x94, - 0x17, 0x46, 0xcf, 0xcf, 0x4e, 0x86, 0x9f, 0x7e, 0xe4, 0x7a, 0x7c, 0x11, 0xcf, 0x0d, 0x44, 0x02, - 0xd5, 0x35, 0x79, 0x27, 0x31, 0xe7, 0xd0, 0x54, 0xe7, 0x1e, 0xa7, 0x94, 0x44, 0x1c, 0x3b, 0x86, - 0xa2, 0x8e, 0x6f, 0x82, 0x1b, 0x2c, 0x0e, 0x06, 0xbf, 0xeb, 0x60, 0xeb, 0x40, 0xd8, 0xc1, 0x67, - 0x60, 0x4b, 0x1a, 0xab, 0x73, 0xd3, 0x5b, 0x17, 0x4a, 0xe2, 0xa7, 0xda, 0x4c, 0xe1, 0x47, 0x2f, - 0xfe, 0x3b, 0xee, 0xeb, 0x67, 0x27, 0xc3, 0xa7, 0xd7, 0x45, 0x51, 0x0d, 0x56, 0x84, 0x91, 0x4a, - 0x5f, 0xe5, 0x61, 0xfe, 0xd4, 0x41, 0x7b, 0x57, 0xf5, 0x19, 0xfc, 0x1a, 0xdc, 0xc6, 0xbf, 0xc4, - 0x5e, 0x42, 0x90, 0x9d, 0x1d, 0x7d, 0x15, 0xea, 0x41, 0x35, 0x54, 0xde, 0x95, 0x59, 0xac, 0xdd, - 0x12, 0x7a, 0xaa, 0xcd, 0x2a, 0xec, 0xd1, 0x4b, 0x15, 0xf1, 0xf9, 0x35, 0x09, 0x8b, 0x36, 0x2f, - 0x32, 0xe6, 0x81, 0xf2, 0x90, 0x7f, 0xe9, 0xe0, 0x8d, 0x3d, 0xe6, 0x1e, 0xc4, 0xf3, 0xc0, 0xe3, - 0x45, 0xda, 0xcf, 0x41, 0x3b, 0xa7, 0xaa, 0xa4, 0xef, 0x19, 0xeb, 0xa7, 0x5f, 0x21, 0x3a, 0x2b, - 0x58, 0x70, 0x0f, 0xb4, 0xb2, 0x1e, 0x54, 0xed, 0x65, 0xae, 0xdf, 0x67, 0xcd, 0x3c, 0xeb, 0xe4, - 0x71, 0xfb, 0xf4, 0xa2, 0xaf, 0x9d, 0x5f, 0xf4, 0xf5, 0x99, 0x90, 0x19, 0xb5, 0x7f, 0x3b, 0xee, - 0x6b, 0xd9, 0xa6, 0x07, 0x47, 0x3a, 0x68, 0xef, 0xab, 0xc9, 0x03, 0x5f, 0x28, 0x97, 0xc6, 0xd1, - 0xe0, 0x92, 0x44, 0x1c, 0x6b, 0x05, 0x6e, 0xd2, 0x85, 0x13, 0xb0, 0x9d, 0xf5, 0x2f, 0x2e, 0x06, - 0xc1, 0xfd, 0x4d, 0xfb, 0x9c, 0x48, 0xe8, 0xb8, 0x95, 0xa9, 0xcc, 0x72, 0xe6, 0xe0, 0x8f, 0x16, - 0xd8, 0x56, 0x25, 0xf8, 0x14, 0xb4, 0x38, 0x4e, 0xf9, 0xc6, 0x44, 0xdf, 0xe2, 0x94, 0xe7, 0xa9, - 0xa6, 0xda, 0x4c, 0x10, 0xe0, 0x8f, 0xe0, 0x8e, 0x98, 0xae, 0x98, 0xe3, 0xc8, 0x42, 0x0b, 0x3b, - 0x74, 0xd7, 0x3c, 0x3c, 0x39, 0x83, 0xc5, 0xce, 0x72, 0xfc, 0x44, 0xc0, 0x4b, 0x92, 0xaf, 0xd3, - 0x6a, 0x09, 0xfe, 0x04, 0xee, 0x30, 0xf2, 0x33, 0xff, 0xd5, 0x8e, 0xb0, 0xa5, 0xe6, 0xb3, 0x1a, - 0x42, 0x0f, 0xab, 0xea, 0xaa, 0x28, 0x1a, 0x43, 0x11, 0xbe, 0x93, 0x4b, 0x65, 0x79, 0x56, 0x2d, - 0x41, 0x0a, 0x76, 0x90, 0x1d, 0x22, 0xec, 0x5b, 0x35, 0x97, 0x56, 0xd3, 0x7c, 0x2d, 0xb9, 0x4c, - 0x04, 0x6f, 0xbd, 0xd7, 0x5d, 0xd4, 0x04, 0x80, 0x3e, 0x78, 0x13, 0x91, 0x20, 0x88, 0x43, 0x8f, - 0x2f, 0x2d, 0x4a, 0x88, 0x6f, 0x31, 0x8a, 0x43, 0x47, 0x4d, 0xa0, 0x67, 0x55, 0xbb, 0xf2, 0x47, - 0x47, 0xbe, 0x47, 0xc5, 0xdc, 0x27, 0xc4, 0x3f, 0xc8, 0x78, 0x25, 0x43, 0x88, 0x6a, 0xd5, 0xd1, - 0x93, 0xb3, 0x93, 0xe1, 0xc3, 0x6b, 0x7a, 0xad, 0xf8, 0x68, 0x16, 0xc7, 0x44, 0xb6, 0xd8, 0x78, - 0x72, 0x7a, 0xd9, 0xd3, 0xcf, 0x2f, 0x7b, 0xfa, 0xbf, 0x97, 0x3d, 0xfd, 0xe8, 0xaa, 0xa7, 0x9d, - 0x5f, 0xf5, 0xb4, 0x7f, 0xae, 0x7a, 0xda, 0x0f, 0x1f, 0x6e, 0x94, 0x2c, 0xff, 0x11, 0x99, 0x6f, - 0x89, 0xef, 0xe3, 0xe3, 0xff, 0x03, 0x00, 0x00, 0xff, 0xff, 0x17, 0x2b, 0x3f, 0x40, 0x9f, 0x08, - 0x00, 0x00, + // 876 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x56, 0x41, 0x6f, 0xe3, 0x44, + 0x14, 0xb6, 0x77, 0xb3, 0x6d, 0x34, 0xbb, 0xc0, 0x32, 0x62, 0x69, 0x14, 0x50, 0xb2, 0x64, 0x61, + 0x05, 0x8b, 0x6a, 0xef, 0x52, 0xa0, 0x6d, 0x24, 0x54, 0x9a, 0x50, 0x14, 0x24, 0x8a, 0xaa, 0x14, + 0x38, 0x20, 0x90, 0xe5, 0x8c, 0x07, 0xc7, 0xaa, 0xed, 0x19, 0x3c, 0x63, 0xe3, 0xfc, 0x03, 0xc4, + 0xa9, 0x3f, 0xa1, 0xe2, 0xc0, 0x91, 0x53, 0x8f, 0xfc, 0x80, 0xaa, 0xa7, 0x1e, 0x39, 0x55, 0xa8, + 0xbd, 0xf0, 0x33, 0x90, 0x3d, 0x63, 0xc7, 0x96, 0x9d, 0x64, 0x2f, 0x56, 0x3c, 0xef, 0x7b, 0xdf, + 0xf7, 0x8d, 0x67, 0xde, 0x7b, 0x01, 0x2d, 0xe6, 0x78, 0x26, 0xa5, 0x3a, 0x22, 0x16, 0x46, 0xe2, + 0xa9, 0xd1, 0x80, 0x70, 0x02, 0xdb, 0x88, 0x30, 0x8f, 0x30, 0x83, 0x59, 0x27, 0x9a, 0x00, 0x69, + 0x22, 0x1c, 0xbd, 0x68, 0x7f, 0xc8, 0xa7, 0x4e, 0x60, 0x19, 0xd4, 0x0c, 0xf8, 0x4c, 0x4f, 0xe1, + 0xba, 0x40, 0x6f, 0x16, 0x5f, 0x04, 0x51, 0xfb, 0x69, 0x15, 0x6c, 0x13, 0x9b, 0xcc, 0x7f, 0x49, + 0x5c, 0x2b, 0xd6, 0xcd, 0x90, 0x4f, 0x75, 0x3e, 0xa3, 0x98, 0x89, 0xa7, 0x8c, 0x3c, 0x96, 0x91, + 0x08, 0x33, 0xee, 0xf8, 0x76, 0x0d, 0xa2, 0x1d, 0xeb, 0x2c, 0xa4, 0xd4, 0x9d, 0xd5, 0xc4, 0xde, + 0x8e, 0x75, 0x1c, 0x39, 0x16, 0xf6, 0x11, 0xae, 0x89, 0x6e, 0xc4, 0xba, 0x4d, 0xa2, 0x9a, 0xc0, + 0x93, 0x58, 0xa7, 0x66, 0x60, 0x7a, 0x72, 0x35, 0x71, 0x4e, 0x09, 0x33, 0xdd, 0x12, 0xe8, 0xad, + 0x58, 0x0f, 0xa9, 0x1d, 0x98, 0x16, 0xae, 0xb7, 0x6d, 0x39, 0x8c, 0x07, 0xce, 0x24, 0xe4, 0x0e, + 0xf1, 0xab, 0x88, 0xde, 0xdf, 0x0d, 0xb0, 0xbe, 0x8f, 0x10, 0x09, 0x7d, 0x0e, 0xbf, 0x04, 0x0f, + 0x26, 0x26, 0xc3, 0x86, 0x29, 0xde, 0x5b, 0xea, 0x63, 0xf5, 0xfd, 0xfb, 0x1f, 0xbd, 0xa3, 0x15, + 0x8e, 0x21, 0xd6, 0x92, 0xcf, 0xa0, 0x45, 0x2f, 0xb4, 0x81, 0xc9, 0xb0, 0x4c, 0x1c, 0x29, 0xe3, + 0xfb, 0x93, 0xf9, 0x2b, 0x8c, 0x40, 0x1b, 0x11, 0x9f, 0x3b, 0x7e, 0x48, 0x42, 0x66, 0xc8, 0x4f, + 0x96, 0xb3, 0xde, 0x49, 0x59, 0x3f, 0xad, 0x63, 0x15, 0xc8, 0x84, 0x7d, 0x98, 0xe7, 0x7f, 0x2f, + 0x16, 0xe7, 0x52, 0x2d, 0xb4, 0x20, 0x06, 0x3d, 0xb0, 0x61, 0x61, 0xd7, 0x9c, 0x61, 0xab, 0x22, + 0x7a, 0x37, 0x15, 0xdd, 0x5a, 0x2e, 0xfa, 0x85, 0x48, 0xae, 0x28, 0x3e, 0xb2, 0xea, 0x02, 0x90, + 0x82, 0x16, 0xc5, 0x81, 0x43, 0x2c, 0x07, 0x55, 0xf4, 0x1a, 0xa9, 0xde, 0xc7, 0xcb, 0xf5, 0x8e, + 0x64, 0x76, 0x45, 0xf0, 0x4d, 0x5a, 0x1b, 0x81, 0xdf, 0x80, 0x57, 0x3d, 0x62, 0x85, 0xee, 0xfc, + 0x88, 0xee, 0xa5, 0x3a, 0xef, 0x95, 0x75, 0xc4, 0x3d, 0x4c, 0x14, 0x0e, 0x53, 0xf4, 0x9c, 0xf8, + 0x15, 0xaf, 0xb8, 0xd0, 0xdf, 0xbd, 0x3c, 0xdf, 0xfc, 0xe4, 0x99, 0xed, 0xf0, 0x69, 0x38, 0xd1, + 0x10, 0xf1, 0x64, 0xd5, 0x64, 0x95, 0xc4, 0xac, 0x13, 0x5d, 0xde, 0x7b, 0x1c, 0x53, 0x12, 0x70, + 0x6c, 0x69, 0x32, 0x75, 0x70, 0x0f, 0xdc, 0x65, 0xa1, 0xd7, 0xfb, 0x5d, 0x05, 0x6b, 0xc7, 0xa9, + 0x1c, 0xdc, 0x01, 0x6b, 0x42, 0x58, 0xde, 0x9b, 0xce, 0x22, 0x53, 0x02, 0x3f, 0x52, 0xc6, 0x12, + 0xdf, 0xdf, 0xfb, 0xef, 0xac, 0xab, 0x5e, 0x9e, 0x6f, 0x6e, 0xaf, 0xb2, 0x22, 0x0b, 0x2c, 0x37, + 0x23, 0x98, 0xbe, 0xca, 0xcc, 0xfc, 0xa1, 0x82, 0xe6, 0x81, 0xac, 0x33, 0xf8, 0x35, 0x78, 0x80, + 0x7f, 0x09, 0x9d, 0x88, 0x20, 0x33, 0xb9, 0xfa, 0xd2, 0xd4, 0xd3, 0xb2, 0xa9, 0xac, 0x2a, 0x13, + 0x5b, 0x07, 0x05, 0xf4, 0x48, 0x19, 0x97, 0xb2, 0xfb, 0xfb, 0xd2, 0xe2, 0xee, 0x0a, 0x87, 0x79, + 0x99, 0xe7, 0x1e, 0x33, 0x43, 0x99, 0xc9, 0xbf, 0x54, 0xf0, 0xfa, 0x21, 0xb3, 0x8f, 0xc3, 0x89, + 0xe7, 0xf0, 0xdc, 0xed, 0xe7, 0xa0, 0x99, 0xa5, 0x4a, 0xa7, 0xef, 0x6a, 0x8b, 0xbb, 0x5f, 0x4e, + 0x3a, 0xce, 0xb3, 0xe0, 0x21, 0x68, 0x24, 0x35, 0x28, 0xcb, 0x4b, 0x5f, 0xbc, 0xcf, 0x8a, 0x78, + 0x52, 0xc9, 0x83, 0xe6, 0xc5, 0x75, 0x57, 0xb9, 0xba, 0xee, 0xaa, 0xe3, 0x94, 0xa6, 0xdf, 0xfc, + 0xed, 0xac, 0xab, 0x24, 0x9b, 0xee, 0xfd, 0x59, 0x34, 0x7c, 0x24, 0x5b, 0x10, 0xfc, 0x0c, 0xac, + 0x27, 0x75, 0x88, 0xf3, 0x36, 0xf1, 0x64, 0x99, 0xdf, 0xa1, 0x80, 0x8e, 0xb3, 0x1c, 0x38, 0x2a, + 0xb9, 0x7d, 0x56, 0x76, 0x6b, 0x93, 0xa8, 0x64, 0x34, 0x13, 0x5d, 0x61, 0xf4, 0x54, 0x05, 0xcd, + 0xdc, 0xdf, 0x9e, 0x14, 0xa8, 0xed, 0x61, 0x52, 0x60, 0x19, 0x2f, 0x1c, 0xce, 0x37, 0x78, 0xe7, + 0xa5, 0x37, 0x38, 0x68, 0x24, 0x2c, 0xf9, 0x36, 0x7b, 0x67, 0x0d, 0xb0, 0x2e, 0x43, 0x70, 0x1b, + 0x34, 0x38, 0x8e, 0xf9, 0x52, 0x47, 0xdf, 0xe2, 0x38, 0xdf, 0xed, 0x48, 0x19, 0xa7, 0x09, 0xf0, + 0x47, 0xf0, 0x30, 0x1d, 0x03, 0x98, 0xe3, 0xc0, 0x40, 0x53, 0xd3, 0xb7, 0x17, 0x9c, 0xb2, 0x18, + 0x16, 0xe9, 0xce, 0x32, 0xfc, 0x30, 0x85, 0x17, 0x28, 0x5f, 0xa3, 0xe5, 0x10, 0xfc, 0x09, 0x3c, + 0x64, 0xe4, 0x67, 0xfe, 0xab, 0x19, 0x60, 0x43, 0x0e, 0x12, 0xd9, 0x2d, 0x9f, 0x97, 0xd9, 0x65, + 0x30, 0xad, 0x60, 0x99, 0xf0, 0x9d, 0x58, 0x2a, 0xd2, 0xb3, 0x72, 0x08, 0x52, 0xb0, 0x81, 0x4c, + 0x1f, 0x61, 0xd7, 0xa8, 0xa8, 0x34, 0xea, 0x06, 0x41, 0x41, 0x65, 0x98, 0xe6, 0x2d, 0xd6, 0x7a, + 0x84, 0xea, 0x00, 0xd0, 0x05, 0x6f, 0x20, 0xe2, 0x79, 0xa1, 0xef, 0xf0, 0x99, 0x41, 0x09, 0x71, + 0x0d, 0x46, 0xb1, 0x6f, 0xc9, 0x56, 0xb9, 0x53, 0x96, 0x2b, 0x4e, 0x47, 0x71, 0x8e, 0x32, 0xf3, + 0x88, 0x10, 0xf7, 0x38, 0xc9, 0x2b, 0x08, 0x42, 0x54, 0x89, 0xf6, 0x77, 0x64, 0x63, 0x78, 0xbe, + 0xa2, 0x31, 0xe4, 0x13, 0x3e, 0xbf, 0x2a, 0xa2, 0x1f, 0x0c, 0x86, 0x17, 0x37, 0x1d, 0xf5, 0xea, + 0xa6, 0xa3, 0xfe, 0x7b, 0xd3, 0x51, 0x4f, 0x6f, 0x3b, 0xca, 0xd5, 0x6d, 0x47, 0xf9, 0xe7, 0xb6, + 0xa3, 0xfc, 0xf0, 0xc1, 0x52, 0xca, 0xe2, 0xbf, 0xa6, 0xc9, 0x5a, 0x3a, 0xcc, 0xb7, 0xfe, 0x0f, + 0x00, 0x00, 0xff, 0xff, 0x22, 0x64, 0xee, 0x71, 0x4c, 0x09, 0x00, 0x00, } func (this *Supply) Equal(that interface{}) bool { @@ -733,6 +776,183 @@ func (this *MsgSubmitEvidence) Equal(that interface{}) bool { } return true } +func (this *MsgSubmitProposal) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*MsgSubmitProposal) + if !ok { + that2, ok := that.(MsgSubmitProposal) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !this.Content.Equal(that1.Content) { + return false + } + if !this.MsgSubmitProposalBase.Equal(&that1.MsgSubmitProposalBase) { + return false + } + return true +} +func (this *Content) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*Content) + if !ok { + that2, ok := that.(Content) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if that1.Sum == nil { + if this.Sum != nil { + return false + } + } else if this.Sum == nil { + return false + } else if !this.Sum.Equal(that1.Sum) { + return false + } + return true +} +func (this *Content_Text) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*Content_Text) + if !ok { + that2, ok := that.(Content_Text) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !this.Text.Equal(that1.Text) { + return false + } + return true +} +func (this *Content_ParameterChange) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*Content_ParameterChange) + if !ok { + that2, ok := that.(Content_ParameterChange) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !this.ParameterChange.Equal(that1.ParameterChange) { + return false + } + return true +} +func (this *Content_SoftwareUpgrade) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*Content_SoftwareUpgrade) + if !ok { + that2, ok := that.(Content_SoftwareUpgrade) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !this.SoftwareUpgrade.Equal(that1.SoftwareUpgrade) { + return false + } + return true +} +func (this *Content_CancelSoftwareUpgrade) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*Content_CancelSoftwareUpgrade) + if !ok { + that2, ok := that.(Content_CancelSoftwareUpgrade) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !this.CancelSoftwareUpgrade.Equal(that1.CancelSoftwareUpgrade) { + return false + } + return true +} +func (this *Content_CommunityPoolSpend) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*Content_CommunityPoolSpend) + if !ok { + that2, ok := that.(Content_CommunityPoolSpend) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !this.CommunityPoolSpend.Equal(that1.CommunityPoolSpend) { + return false + } + return true +} func (this *Account) GetAccount() github_com_cosmos_cosmos_sdk_x_auth_exported.Account { if x := this.GetBaseAccount(); x != nil { return x @@ -1167,6 +1387,51 @@ func (m *MsgSubmitEvidence) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *MsgSubmitProposal) 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 *MsgSubmitProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgSubmitProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.MsgSubmitProposalBase.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if m.Content != nil { + { + size, err := m.Content.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *Proposal) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -1493,6 +1758,21 @@ func (m *MsgSubmitEvidence) Size() (n int) { return n } +func (m *MsgSubmitProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Content != nil { + l = m.Content.Size() + n += 1 + l + sovCodec(uint64(l)) + } + l = m.MsgSubmitProposalBase.Size() + n += 1 + l + sovCodec(uint64(l)) + return n +} + func (m *Proposal) Size() (n int) { if m == nil { return 0 @@ -2111,6 +2391,128 @@ func (m *MsgSubmitEvidence) Unmarshal(dAtA []byte) error { } return nil } +func (m *MsgSubmitProposal) 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 ErrIntOverflowCodec + } + 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: MsgSubmitProposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSubmitProposal: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Content", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Content == nil { + m.Content = &Content{} + } + if err := m.Content.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MsgSubmitProposalBase", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.MsgSubmitProposalBase.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCodec(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *Proposal) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/simapp/codec/codec.proto b/simapp/codec/codec.proto index bfa55600471c..9b5d94991e2e 100644 --- a/simapp/codec/codec.proto +++ b/simapp/codec/codec.proto @@ -61,6 +61,16 @@ message MsgSubmitEvidence { cosmos_sdk.x.evidence.v1.MsgSubmitEvidenceBase base = 2 [(gogoproto.nullable) = false, (gogoproto.embed) = true]; } +// MsgSubmitProposal defines the application-level message type for handling +// governance proposals. +message MsgSubmitProposal { + option (gogoproto.equal) = true; + option (gogoproto.goproto_getters) = false; + + Content content = 1; + cosmos_sdk.x.gov.v1.MsgSubmitProposalBase base = 2 [(gogoproto.nullable) = false, (gogoproto.embed) = true]; +} + // Proposal defines the application-level concrete proposal type used in governance // proposals. message Proposal { @@ -71,6 +81,7 @@ message Proposal { // Content defines the application-level allowed Content to be included in a // governance proposal. message Content { + option (gogoproto.equal) = true; option (cosmos_proto.interface_type) = "github.com/cosmos/cosmos-sdk/x/gov/types.Content"; oneof sum { diff --git a/simapp/codec/msgs.go b/simapp/codec/msgs.go index 2ea6c3a3a73d..d34a07becbaa 100644 --- a/simapp/codec/msgs.go +++ b/simapp/codec/msgs.go @@ -5,9 +5,13 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/evidence" eviexported "github.com/cosmos/cosmos-sdk/x/evidence/exported" + "github.com/cosmos/cosmos-sdk/x/gov" ) -var _ eviexported.MsgSubmitEvidence = MsgSubmitEvidence{} +var ( + _ eviexported.MsgSubmitEvidence = MsgSubmitEvidence{} + _ gov.MsgSubmitProposal = MsgSubmitProposal{} +) // NewMsgSubmitEvidence returns a new MsgSubmitEvidence. func NewMsgSubmitEvidence(evidenceI eviexported.Evidence, s sdk.AccAddress) (MsgSubmitEvidence, error) { @@ -16,7 +20,10 @@ func NewMsgSubmitEvidence(evidenceI eviexported.Evidence, s sdk.AccAddress) (Msg return MsgSubmitEvidence{}, err } - return MsgSubmitEvidence{Evidence: e, MsgSubmitEvidenceBase: evidence.NewMsgSubmitEvidenceBase(s)}, nil + return MsgSubmitEvidence{ + Evidence: e, + MsgSubmitEvidenceBase: evidence.NewMsgSubmitEvidenceBase(s), + }, nil } // ValidateBasic performs basic (non-state-dependant) validation on a @@ -38,3 +45,40 @@ func (msg MsgSubmitEvidence) ValidateBasic() error { // nolint func (msg MsgSubmitEvidence) GetEvidence() eviexported.Evidence { return msg.Evidence.GetEvidence() } func (msg MsgSubmitEvidence) GetSubmitter() sdk.AccAddress { return msg.Submitter } + +// NewMsgSubmitProposal returns a new MsgSubmitProposal. +func NewMsgSubmitProposal(c gov.Content, d sdk.Coins, p sdk.AccAddress) (MsgSubmitProposal, error) { + content := &Content{} + if err := content.SetContent(c); err != nil { + return MsgSubmitProposal{}, err + } + + return MsgSubmitProposal{ + Content: content, + MsgSubmitProposalBase: gov.NewMsgSubmitProposalBase(d, p), + }, nil +} + +// ValidateBasic performs basic (non-state-dependant) validation on a +// MsgSubmitProposal. +func (msg MsgSubmitProposal) ValidateBasic() error { + if err := msg.MsgSubmitProposalBase.ValidateBasic(); err != nil { + return nil + } + if msg.Content == nil { + return sdkerrors.Wrap(gov.ErrInvalidProposalContent, "missing content") + } + if !gov.IsValidProposalType(msg.Content.GetContent().ProposalType()) { + return sdkerrors.Wrap(gov.ErrInvalidProposalType, msg.Content.GetContent().ProposalType()) + } + if err := msg.Content.GetContent().ValidateBasic(); err != nil { + return err + } + + return nil +} + +// nolint +func (msg MsgSubmitProposal) GetContent() gov.Content { return msg.Content.GetContent() } +func (msg MsgSubmitProposal) GetInitialDeposit() sdk.Coins { return msg.InitialDeposit } +func (msg MsgSubmitProposal) GetProposer() sdk.AccAddress { return msg.Proposer } diff --git a/x/gov/alias.go b/x/gov/alias.go index c1f0a98086eb..86828db77580 100644 --- a/x/gov/alias.go +++ b/x/gov/alias.go @@ -82,7 +82,7 @@ var ( SplitInactiveProposalQueueKey = types.SplitInactiveProposalQueueKey SplitKeyDeposit = types.SplitKeyDeposit SplitKeyVote = types.SplitKeyVote - NewMsgSubmitProposal = types.NewMsgSubmitProposal + NewMsgSubmitProposalBase = types.NewMsgSubmitProposalBase NewMsgDeposit = types.NewMsgDeposit NewMsgVote = types.NewMsgVote ParamKeyTable = types.ParamKeyTable @@ -125,32 +125,33 @@ var ( ) type ( - Keeper = keeper.Keeper - Content = types.Content - Handler = types.Handler - Deposit = types.Deposit - Deposits = types.Deposits - GenesisState = types.GenesisState - MsgSubmitProposal = types.MsgSubmitProposal - MsgDeposit = types.MsgDeposit - MsgVote = types.MsgVote - DepositParams = types.DepositParams - TallyParams = types.TallyParams - VotingParams = types.VotingParams - Params = types.Params - Proposal = types.Proposal - Proposals = types.Proposals - ProposalQueue = types.ProposalQueue - ProposalStatus = types.ProposalStatus - TextProposal = types.TextProposal - QueryProposalParams = types.QueryProposalParams - QueryDepositParams = types.QueryDepositParams - QueryVoteParams = types.QueryVoteParams - QueryProposalsParams = types.QueryProposalsParams - ValidatorGovInfo = types.ValidatorGovInfo - TallyResult = types.TallyResult - Vote = types.Vote - Votes = types.Votes - VoteOption = types.VoteOption - Codec = types.Codec + Keeper = keeper.Keeper + Content = types.Content + Handler = types.Handler + Deposit = types.Deposit + Deposits = types.Deposits + GenesisState = types.GenesisState + MsgSubmitProposal = types.MsgSubmitProposal + MsgSubmitProposalBase = types.MsgSubmitProposalBase + MsgDeposit = types.MsgDeposit + MsgVote = types.MsgVote + DepositParams = types.DepositParams + TallyParams = types.TallyParams + VotingParams = types.VotingParams + Params = types.Params + Proposal = types.Proposal + Proposals = types.Proposals + ProposalQueue = types.ProposalQueue + ProposalStatus = types.ProposalStatus + TextProposal = types.TextProposal + QueryProposalParams = types.QueryProposalParams + QueryDepositParams = types.QueryDepositParams + QueryVoteParams = types.QueryVoteParams + QueryProposalsParams = types.QueryProposalsParams + ValidatorGovInfo = types.ValidatorGovInfo + TallyResult = types.TallyResult + Vote = types.Vote + Votes = types.Votes + VoteOption = types.VoteOption + Codec = types.Codec ) diff --git a/x/gov/types/codec.go b/x/gov/types/codec.go index a892ddecd75a..ba9e6827c39a 100644 --- a/x/gov/types/codec.go +++ b/x/gov/types/codec.go @@ -16,7 +16,7 @@ type Codec interface { // governance module. func RegisterCodec(cdc *codec.Codec) { cdc.RegisterInterface((*Content)(nil), nil) - cdc.RegisterConcrete(MsgSubmitProposal{}, "cosmos-sdk/MsgSubmitProposal", nil) + cdc.RegisterConcrete(MsgSubmitProposalBase{}, "cosmos-sdk/MsgSubmitProposalBase", nil) cdc.RegisterConcrete(MsgDeposit{}, "cosmos-sdk/MsgDeposit", nil) cdc.RegisterConcrete(MsgVote{}, "cosmos-sdk/MsgVote", nil) cdc.RegisterConcrete(TextProposal{}, "cosmos-sdk/TextProposal", nil) diff --git a/x/gov/types/deposit.go b/x/gov/types/deposit.go index 098bc9b2e3a8..58d2540eca86 100644 --- a/x/gov/types/deposit.go +++ b/x/gov/types/deposit.go @@ -3,6 +3,8 @@ package types import ( "fmt" + "gopkg.in/yaml.v2" + sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -12,8 +14,8 @@ func NewDeposit(proposalID uint64, depositor sdk.AccAddress, amount sdk.Coins) D } func (d Deposit) String() string { - return fmt.Sprintf("deposit by %s on Proposal %d is for the amount %s", - d.Depositor, d.ProposalID, d.Amount) + out, _ := yaml.Marshal(d) + return string(out) } // Deposits is a collection of Deposit objects diff --git a/x/gov/types/genesis.go b/x/gov/types/genesis.go index 69f49fa68bb2..858bc85f867f 100644 --- a/x/gov/types/genesis.go +++ b/x/gov/types/genesis.go @@ -1,7 +1,6 @@ package types import ( - "bytes" "fmt" sdk "github.com/cosmos/cosmos-sdk/types" @@ -38,16 +37,14 @@ func DefaultGenesisState() GenesisState { ) } -// Equal checks whether two gov GenesisState structs are equivalent -func (data GenesisState) Equal(data2 GenesisState) bool { - b1 := ModuleCdc.MustMarshalBinaryBare(data) - b2 := ModuleCdc.MustMarshalBinaryBare(data2) - return bytes.Equal(b1, b2) -} - // IsEmpty returns true if a GenesisState is empty func (data GenesisState) IsEmpty() bool { - return data.Equal(GenesisState{}) + return data.Deposits == nil && + data.Votes == nil && + data.Proposals == nil && + data.DepositParams.Equal(DepositParams{}) && + data.TallyParams.Equal(TallyParams{}) && + data.VotingParams.Equal(VotingParams{}) } // ValidateGenesis checks if parameters are within valid ranges diff --git a/x/gov/types/msgs.go b/x/gov/types/msgs.go index 56ea7614bded..eb0343902303 100644 --- a/x/gov/types/msgs.go +++ b/x/gov/types/msgs.go @@ -1,7 +1,7 @@ package types import ( - "fmt" + "gopkg.in/yaml.v2" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" @@ -14,32 +14,35 @@ const ( TypeMsgSubmitProposal = "submit_proposal" ) -var _, _, _ sdk.Msg = MsgSubmitProposal{}, MsgDeposit{}, MsgVote{} +var _, _, _ sdk.Msg = MsgSubmitProposalBase{}, MsgDeposit{}, MsgVote{} -// MsgSubmitProposal defines a message to create a governance proposal with a -// given content and initial deposit -type MsgSubmitProposal struct { - Content Content `json:"content" yaml:"content"` - InitialDeposit sdk.Coins `json:"initial_deposit" yaml:"initial_deposit"` // Initial deposit paid by sender. Must be strictly positive - Proposer sdk.AccAddress `json:"proposer" yaml:"proposer"` // Address of the proposer +// MsgSubmitProposal defines the specific interface a concrete message must +// implement in order to process governance proposals. The concrete MsgSubmitProposal +// must be defined at the application-level. +type MsgSubmitProposal interface { + sdk.Msg + + GetContent() Content + GetInitialDeposit() sdk.Coins + GetProposer() sdk.AccAddress } -// NewMsgSubmitProposal creates a new MsgSubmitProposal instance -func NewMsgSubmitProposal(content Content, initialDeposit sdk.Coins, proposer sdk.AccAddress) MsgSubmitProposal { - return MsgSubmitProposal{content, initialDeposit, proposer} +// NewMsgSubmitProposalBase creates a new MsgSubmitProposalBase. +func NewMsgSubmitProposalBase(initialDeposit sdk.Coins, proposer sdk.AccAddress) MsgSubmitProposalBase { + return MsgSubmitProposalBase{ + InitialDeposit: initialDeposit, + Proposer: proposer, + } } // Route implements Msg -func (msg MsgSubmitProposal) Route() string { return RouterKey } +func (msg MsgSubmitProposalBase) Route() string { return RouterKey } // Type implements Msg -func (msg MsgSubmitProposal) Type() string { return TypeMsgSubmitProposal } +func (msg MsgSubmitProposalBase) Type() string { return TypeMsgSubmitProposal } // ValidateBasic implements Msg -func (msg MsgSubmitProposal) ValidateBasic() error { - if msg.Content == nil { - return sdkerrors.Wrap(ErrInvalidProposalContent, "missing content") - } +func (msg MsgSubmitProposalBase) ValidateBasic() error { if msg.Proposer.Empty() { return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Proposer.String()) } @@ -49,32 +52,27 @@ func (msg MsgSubmitProposal) ValidateBasic() error { if msg.InitialDeposit.IsAnyNegative() { return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, msg.InitialDeposit.String()) } - if !IsValidProposalType(msg.Content.ProposalType()) { - return sdkerrors.Wrap(ErrInvalidProposalType, msg.Content.ProposalType()) - } - - return msg.Content.ValidateBasic() -} -// String implements the Stringer interface -func (msg MsgSubmitProposal) String() string { - return fmt.Sprintf(`Submit Proposal Message: - Content: %s - Initial Deposit: %s -`, msg.Content.String(), msg.InitialDeposit) + return nil } // GetSignBytes implements Msg -func (msg MsgSubmitProposal) GetSignBytes() []byte { +func (msg MsgSubmitProposalBase) GetSignBytes() []byte { bz := ModuleCdc.MustMarshalJSON(msg) return sdk.MustSortJSON(bz) } // GetSigners implements Msg -func (msg MsgSubmitProposal) GetSigners() []sdk.AccAddress { +func (msg MsgSubmitProposalBase) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.Proposer} } +// String implements the Stringer interface +func (msg MsgSubmitProposalBase) String() string { + out, _ := yaml.Marshal(msg) + return string(out) +} + // NewMsgDeposit creates a new MsgDeposit instance func NewMsgDeposit(depositor sdk.AccAddress, proposalID uint64, amount sdk.Coins) MsgDeposit { return MsgDeposit{proposalID, depositor, amount} @@ -103,11 +101,8 @@ func (msg MsgDeposit) ValidateBasic() error { // String implements the Stringer interface func (msg MsgDeposit) String() string { - return fmt.Sprintf(`Deposit Message: - Depositer: %s - Proposal ID: %d - Amount: %s -`, msg.Depositor, msg.ProposalID, msg.Amount) + out, _ := yaml.Marshal(msg) + return string(out) } // GetSignBytes implements Msg @@ -146,10 +141,8 @@ func (msg MsgVote) ValidateBasic() error { // String implements the Stringer interface func (msg MsgVote) String() string { - return fmt.Sprintf(`Vote Message: - Proposal ID: %d - Option: %s -`, msg.ProposalID, msg.Option) + out, _ := yaml.Marshal(msg) + return string(out) } // GetSignBytes implements Msg diff --git a/x/gov/types/params.go b/x/gov/types/params.go index d15ae88b8548..511485bfa1eb 100644 --- a/x/gov/types/params.go +++ b/x/gov/types/params.go @@ -4,6 +4,8 @@ import ( "fmt" "time" + "gopkg.in/yaml.v2" + sdk "github.com/cosmos/cosmos-sdk/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" ) @@ -61,9 +63,8 @@ func DefaultDepositParams() DepositParams { // String implements stringer insterface func (dp DepositParams) String() string { - return fmt.Sprintf(`Deposit Params: - Min Deposit: %s - Max Deposit Period: %s`, dp.MinDeposit, dp.MaxDepositPeriod) + out, _ := yaml.Marshal(dp) + return string(out) } // Equal checks equality of DepositParams @@ -108,13 +109,15 @@ func DefaultTallyParams() TallyParams { return NewTallyParams(DefaultQuorum, DefaultThreshold, DefaultVeto) } +// Equal checks equality of TallyParams +func (tp TallyParams) Equal(other TallyParams) bool { + return tp.Quorum.Equal(other.Quorum) && tp.Threshold.Equal(other.Threshold) && tp.Veto.Equal(other.Veto) +} + // String implements stringer insterface func (tp TallyParams) String() string { - return fmt.Sprintf(`Tally Params: - Quorum: %s - Threshold: %s - Veto: %s`, - tp.Quorum, tp.Threshold, tp.Veto) + out, _ := yaml.Marshal(tp) + return string(out) } func validateTallyParams(i interface{}) error { @@ -162,10 +165,15 @@ func DefaultVotingParams() VotingParams { return NewVotingParams(DefaultPeriod) } +// Equal checks equality of TallyParams +func (vp VotingParams) Equal(other VotingParams) bool { + return vp.VotingPeriod == other.VotingPeriod +} + // String implements stringer interface func (vp VotingParams) String() string { - return fmt.Sprintf(`Voting Params: - Voting Period: %s`, vp.VotingPeriod) + out, _ := yaml.Marshal(vp) + return string(out) } func validateVotingParams(i interface{}) error { diff --git a/x/gov/types/proposal.go b/x/gov/types/proposal.go index c67363f93a87..e734ad59ac7d 100644 --- a/x/gov/types/proposal.go +++ b/x/gov/types/proposal.go @@ -199,10 +199,8 @@ func (tp TextProposal) ValidateBasic() error { return ValidateAbstract(tp) } // String implements Stringer interface func (tp TextProposal) String() string { - return fmt.Sprintf(`Text Proposal: - Title: %s - Description: %s -`, tp.Title, tp.Description) + out, _ := yaml.Marshal(tp) + return string(out) } var validProposalTypes = map[string]struct{}{ diff --git a/x/gov/types/tally.go b/x/gov/types/tally.go index 6020abe5b41b..d8acbeacd6b8 100644 --- a/x/gov/types/tally.go +++ b/x/gov/types/tally.go @@ -1,7 +1,7 @@ package types import ( - "fmt" + "gopkg.in/yaml.v2" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -63,9 +63,6 @@ func (tr TallyResult) Equals(comp TallyResult) bool { // String implements stringer interface func (tr TallyResult) String() string { - return fmt.Sprintf(`Tally Result: - Yes: %s - Abstain: %s - No: %s - NoWithVeto: %s`, tr.Yes, tr.Abstain, tr.No, tr.NoWithVeto) + out, _ := yaml.Marshal(tr) + return string(out) } diff --git a/x/gov/types/types.pb.go b/x/gov/types/types.pb.go index 56bba9adf9cd..607ac5e8eb79 100644 --- a/x/gov/types/types.pb.go +++ b/x/gov/types/types.pb.go @@ -4,6 +4,7 @@ package types import ( + bytes "bytes" fmt "fmt" github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" types "github.com/cosmos/cosmos-sdk/types" @@ -15,8 +16,6 @@ import ( io "io" math "math" math_bits "math/bits" - reflect "reflect" - strings "strings" time "time" ) @@ -97,9 +96,16 @@ func (ProposalStatus) EnumDescriptor() ([]byte, []int) { return fileDescriptor_a5ae5e91b5b3fb03, []int{1} } +// MsgSubmitProposalBase defines an sdk.Msg type that supports submitting arbitrary +// proposal Content. +// +// Note, this message type provides the basis for which a true MsgSubmitProposal +// can be constructed. Since the Content submitted in the message can be arbitrary, +// assuming it fulfills the Content interface, it must be defined at the +// application-level and extend MsgSubmitProposalBase. type MsgSubmitProposalBase struct { - IntialDeposit github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,1,rep,name=intial_deposit,json=intialDeposit,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"intial_deposit" yaml:"initial_deposit"` - Proposer github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,2,opt,name=proposer,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"proposer,omitempty"` + InitialDeposit github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,1,rep,name=initial_deposit,json=initialDeposit,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"initial_deposit" yaml:"initial_deposit"` + Proposer github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,2,opt,name=proposer,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"proposer,omitempty"` } func (m *MsgSubmitProposalBase) Reset() { *m = MsgSubmitProposalBase{} } @@ -134,24 +140,24 @@ func (m *MsgSubmitProposalBase) XXX_DiscardUnknown() { var xxx_messageInfo_MsgSubmitProposalBase proto.InternalMessageInfo -// MsgDeposit defines a message to submit a deposit to an existing proposal -type MsgDeposit struct { +// MsgVote defines a message to cast a vote +type MsgVote struct { ProposalID uint64 `protobuf:"varint,1,opt,name=proposal_id,json=proposalId,proto3" json:"proposal_id" yaml:"proposal_id"` - Depositor github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,2,opt,name=depositor,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"depositor,omitempty"` - Amount github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,3,rep,name=amount,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"amount"` + Voter github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,2,opt,name=voter,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"voter,omitempty"` + Option VoteOption `protobuf:"varint,3,opt,name=option,proto3,enum=cosmos_sdk.x.gov.v1.VoteOption" json:"option,omitempty"` } -func (m *MsgDeposit) Reset() { *m = MsgDeposit{} } -func (*MsgDeposit) ProtoMessage() {} -func (*MsgDeposit) Descriptor() ([]byte, []int) { +func (m *MsgVote) Reset() { *m = MsgVote{} } +func (*MsgVote) ProtoMessage() {} +func (*MsgVote) Descriptor() ([]byte, []int) { return fileDescriptor_a5ae5e91b5b3fb03, []int{1} } -func (m *MsgDeposit) XXX_Unmarshal(b []byte) error { +func (m *MsgVote) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *MsgDeposit) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *MsgVote) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_MsgDeposit.Marshal(b, m, deterministic) + return xxx_messageInfo_MsgVote.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -161,36 +167,36 @@ func (m *MsgDeposit) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return b[:n], nil } } -func (m *MsgDeposit) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgDeposit.Merge(m, src) +func (m *MsgVote) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgVote.Merge(m, src) } -func (m *MsgDeposit) XXX_Size() int { +func (m *MsgVote) XXX_Size() int { return m.Size() } -func (m *MsgDeposit) XXX_DiscardUnknown() { - xxx_messageInfo_MsgDeposit.DiscardUnknown(m) +func (m *MsgVote) XXX_DiscardUnknown() { + xxx_messageInfo_MsgVote.DiscardUnknown(m) } -var xxx_messageInfo_MsgDeposit proto.InternalMessageInfo +var xxx_messageInfo_MsgVote proto.InternalMessageInfo -// MsgVote defines a message to cast a vote -type MsgVote struct { +// MsgDeposit defines a message to submit a deposit to an existing proposal +type MsgDeposit struct { ProposalID uint64 `protobuf:"varint,1,opt,name=proposal_id,json=proposalId,proto3" json:"proposal_id" yaml:"proposal_id"` - Voter github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,2,opt,name=voter,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"voter,omitempty"` - Option VoteOption `protobuf:"varint,3,opt,name=option,proto3,enum=cosmos_sdk.x.gov.v1.VoteOption" json:"option,omitempty"` + Depositor github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,2,opt,name=depositor,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"depositor,omitempty"` + Amount github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,3,rep,name=amount,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"amount"` } -func (m *MsgVote) Reset() { *m = MsgVote{} } -func (*MsgVote) ProtoMessage() {} -func (*MsgVote) Descriptor() ([]byte, []int) { +func (m *MsgDeposit) Reset() { *m = MsgDeposit{} } +func (*MsgDeposit) ProtoMessage() {} +func (*MsgDeposit) Descriptor() ([]byte, []int) { return fileDescriptor_a5ae5e91b5b3fb03, []int{2} } -func (m *MsgVote) XXX_Unmarshal(b []byte) error { +func (m *MsgDeposit) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *MsgVote) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *MsgDeposit) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_MsgVote.Marshal(b, m, deterministic) + return xxx_messageInfo_MsgDeposit.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -200,17 +206,17 @@ func (m *MsgVote) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return b[:n], nil } } -func (m *MsgVote) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgVote.Merge(m, src) +func (m *MsgDeposit) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgDeposit.Merge(m, src) } -func (m *MsgVote) XXX_Size() int { +func (m *MsgDeposit) XXX_Size() int { return m.Size() } -func (m *MsgVote) XXX_DiscardUnknown() { - xxx_messageInfo_MsgVote.DiscardUnknown(m) +func (m *MsgDeposit) XXX_DiscardUnknown() { + xxx_messageInfo_MsgDeposit.DiscardUnknown(m) } -var xxx_messageInfo_MsgVote proto.InternalMessageInfo +var xxx_messageInfo_MsgDeposit proto.InternalMessageInfo // TextProposal defines a standard text proposal whose changes need to be // manually updated in case of approval @@ -421,8 +427,8 @@ func init() { proto.RegisterEnum("cosmos_sdk.x.gov.v1.VoteOption", VoteOption_name, VoteOption_value) proto.RegisterEnum("cosmos_sdk.x.gov.v1.ProposalStatus", ProposalStatus_name, ProposalStatus_value) proto.RegisterType((*MsgSubmitProposalBase)(nil), "cosmos_sdk.x.gov.v1.MsgSubmitProposalBase") - proto.RegisterType((*MsgDeposit)(nil), "cosmos_sdk.x.gov.v1.MsgDeposit") proto.RegisterType((*MsgVote)(nil), "cosmos_sdk.x.gov.v1.MsgVote") + proto.RegisterType((*MsgDeposit)(nil), "cosmos_sdk.x.gov.v1.MsgDeposit") proto.RegisterType((*TextProposal)(nil), "cosmos_sdk.x.gov.v1.TextProposal") proto.RegisterType((*Deposit)(nil), "cosmos_sdk.x.gov.v1.Deposit") proto.RegisterType((*ProposalBase)(nil), "cosmos_sdk.x.gov.v1.ProposalBase") @@ -433,81 +439,305 @@ func init() { func init() { proto.RegisterFile("x/gov/types/types.proto", fileDescriptor_a5ae5e91b5b3fb03) } var fileDescriptor_a5ae5e91b5b3fb03 = []byte{ - // 1181 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x57, 0xc1, 0x6f, 0xd3, 0x56, - 0x18, 0xb7, 0x93, 0x36, 0x6d, 0x5f, 0xd2, 0x60, 0x5e, 0x3b, 0xc8, 0xac, 0xc9, 0x36, 0x06, 0xa1, - 0x8e, 0x09, 0x67, 0x94, 0xc3, 0x24, 0x0e, 0xd3, 0x62, 0x62, 0x20, 0x88, 0x26, 0x91, 0x13, 0x15, - 0xb1, 0x69, 0xb2, 0xdc, 0xd8, 0xb8, 0x1e, 0x8e, 0x5f, 0x96, 0xf7, 0x92, 0x91, 0x1b, 0xda, 0x61, - 0x9a, 0x72, 0x42, 0x3b, 0xed, 0x12, 0x09, 0x69, 0x1c, 0xd0, 0xb4, 0xc3, 0xfe, 0x86, 0x9d, 0x90, - 0x76, 0x18, 0x47, 0x34, 0x4d, 0x61, 0x94, 0xdb, 0xb4, 0x13, 0xd2, 0x2e, 0x3b, 0x4d, 0xf6, 0x7b, - 0xa6, 0x0e, 0x2d, 0x83, 0x8a, 0x4d, 0x93, 0x76, 0x69, 0xeb, 0xef, 0x7d, 0xdf, 0xef, 0xf7, 0xbe, - 0xdf, 0xfb, 0xde, 0xef, 0xa9, 0xe0, 0xe8, 0xcd, 0xb2, 0x87, 0x86, 0x65, 0x32, 0xea, 0xb9, 0x98, - 0xfe, 0xd4, 0x7a, 0x7d, 0x44, 0x10, 0x5c, 0xe9, 0x20, 0xdc, 0x45, 0xd8, 0xc2, 0xce, 0x0d, 0xed, - 0xa6, 0xe6, 0xa1, 0xa1, 0x36, 0x3c, 0x23, 0x1e, 0xde, 0x93, 0x27, 0x9e, 0x24, 0xdb, 0x7e, 0xdf, - 0xb1, 0x7a, 0x76, 0x9f, 0x8c, 0xca, 0x71, 0xa8, 0xec, 0x21, 0x0f, 0xed, 0xfe, 0xc5, 0xf2, 0x64, - 0x0f, 0x21, 0x2f, 0x70, 0x69, 0xca, 0xd6, 0xe0, 0x7a, 0x99, 0xf8, 0x5d, 0x17, 0x13, 0xbb, 0xdb, - 0xa3, 0x09, 0xea, 0x1f, 0x3c, 0x78, 0x63, 0x03, 0x7b, 0xad, 0xc1, 0x56, 0xd7, 0x27, 0xcd, 0x3e, - 0xea, 0x21, 0x6c, 0x07, 0xba, 0x8d, 0x5d, 0xf8, 0x05, 0x0f, 0x8a, 0x7e, 0x48, 0x7c, 0x3b, 0xb0, - 0x1c, 0xb7, 0x87, 0xb0, 0x4f, 0x4a, 0xbc, 0x92, 0x5d, 0xcb, 0xaf, 0xaf, 0x68, 0xa9, 0x4d, 0x0e, - 0xcf, 0x68, 0xe7, 0x91, 0x1f, 0xea, 0x97, 0xef, 0x4f, 0x65, 0xee, 0xe9, 0x54, 0x3e, 0x32, 0xb2, - 0xbb, 0xc1, 0x39, 0xd5, 0x0f, 0xfd, 0x74, 0xa5, 0xfa, 0xed, 0x23, 0x79, 0xcd, 0xf3, 0xc9, 0xf6, - 0x60, 0x4b, 0xeb, 0xa0, 0x6e, 0x99, 0x02, 0xb0, 0x5f, 0xa7, 0xb1, 0x73, 0x83, 0x35, 0x17, 0x41, - 0x61, 0x73, 0x99, 0xd2, 0x56, 0x69, 0x2d, 0xdc, 0x00, 0x8b, 0xbd, 0x78, 0x63, 0x6e, 0xbf, 0x94, - 0x51, 0xf8, 0xb5, 0x82, 0x7e, 0xe6, 0xcf, 0xa9, 0x7c, 0xfa, 0x15, 0xe0, 0x2a, 0x9d, 0x4e, 0xc5, - 0x71, 0xfa, 0x2e, 0xc6, 0xe6, 0x33, 0x88, 0x73, 0x73, 0xb7, 0x7e, 0x51, 0x78, 0xf5, 0xab, 0x0c, - 0x00, 0x1b, 0xd8, 0x4b, 0x38, 0xda, 0x20, 0xdf, 0x63, 0xcd, 0x5b, 0xbe, 0x53, 0xe2, 0x15, 0x7e, - 0x6d, 0x4e, 0x3f, 0xbb, 0x33, 0x95, 0x41, 0xa2, 0x49, 0xad, 0xfa, 0xdb, 0x54, 0x4e, 0x27, 0x3d, - 0x9d, 0xca, 0x90, 0x36, 0x9b, 0x0a, 0xaa, 0x26, 0x48, 0xbe, 0x6a, 0x0e, 0x6c, 0x80, 0x25, 0x26, - 0x00, 0x7a, 0x8d, 0xad, 0xef, 0x62, 0xc0, 0x8f, 0x41, 0xce, 0xee, 0xa2, 0x41, 0x48, 0x4a, 0xd9, - 0x17, 0x1f, 0xc5, 0xbb, 0xd1, 0x51, 0x1c, 0x48, 0x70, 0x06, 0xaa, 0x3e, 0xe6, 0xc1, 0xc2, 0x06, - 0xf6, 0x36, 0x11, 0x71, 0xff, 0x25, 0x45, 0x2e, 0x82, 0xf9, 0x21, 0x22, 0xaf, 0x73, 0x90, 0xb4, - 0x1e, 0xbe, 0x07, 0x72, 0xa8, 0x47, 0x7c, 0x14, 0x96, 0xb2, 0x0a, 0xbf, 0x56, 0x5c, 0x97, 0xb5, - 0x7d, 0x6e, 0x8e, 0x16, 0x75, 0xd2, 0x88, 0xd3, 0x4c, 0x96, 0xae, 0x5e, 0x00, 0x85, 0xb6, 0x7b, - 0xf3, 0xd9, 0xa8, 0xc3, 0x55, 0x30, 0x4f, 0x7c, 0x12, 0xb8, 0x71, 0x87, 0x4b, 0x26, 0xfd, 0x80, - 0x0a, 0xc8, 0x3b, 0x2e, 0xee, 0xf4, 0x7d, 0xca, 0x91, 0x89, 0xd7, 0xd2, 0x21, 0xf5, 0x56, 0x06, - 0x2c, 0x24, 0xd3, 0x63, 0xec, 0xa7, 0xd5, 0x89, 0x59, 0xad, 0xfe, 0x87, 0xe3, 0xf2, 0x63, 0x0e, - 0x14, 0x66, 0x2c, 0x43, 0xdf, 0x4f, 0x87, 0x63, 0x7b, 0x66, 0x26, 0x13, 0x8f, 0xca, 0x12, 0x73, - 0x8a, 0xe7, 0x44, 0xb8, 0x0a, 0x72, 0x98, 0xd8, 0x64, 0x80, 0x63, 0x05, 0x8a, 0xeb, 0xc7, 0xf7, - 0x3d, 0xd8, 0x04, 0xaf, 0x15, 0xa7, 0xea, 0xe2, 0xae, 0xf3, 0x3c, 0xdb, 0x00, 0x45, 0x51, 0x4d, - 0x06, 0x07, 0x3f, 0x05, 0xf0, 0xba, 0x1f, 0xda, 0x81, 0x45, 0xec, 0x20, 0x18, 0x59, 0x7d, 0x17, - 0x0f, 0x02, 0x12, 0x4f, 0x4f, 0x7e, 0x5d, 0xd9, 0x97, 0xa4, 0x1d, 0x25, 0x9a, 0x71, 0x9e, 0x7e, - 0x8c, 0xf9, 0xdb, 0x9b, 0x94, 0x65, 0x2f, 0x92, 0x6a, 0x0a, 0x71, 0x30, 0x55, 0x04, 0x3f, 0x02, - 0x79, 0x1c, 0x1b, 0xab, 0x15, 0xd9, 0x6e, 0x69, 0x2e, 0xe6, 0x12, 0x35, 0xea, 0xc9, 0x5a, 0xe2, - 0xc9, 0x5a, 0x3b, 0xf1, 0x64, 0x5d, 0x62, 0x2c, 0x6c, 0x52, 0x52, 0xc5, 0xea, 0xed, 0x47, 0x32, - 0x6f, 0x02, 0x1a, 0x89, 0x0a, 0xa0, 0x0f, 0x04, 0x76, 0xd2, 0x96, 0x1b, 0x3a, 0x94, 0x61, 0xfe, - 0xa5, 0x0c, 0xc7, 0x19, 0xc3, 0x51, 0xca, 0xf0, 0x3c, 0x02, 0xa5, 0x29, 0xb2, 0xb0, 0x11, 0x3a, - 0x31, 0xd5, 0xe7, 0x3c, 0x58, 0x26, 0x88, 0xa4, 0x5e, 0x82, 0xdc, 0x8b, 0xe7, 0xe9, 0x12, 0x63, - 0x58, 0xa5, 0x0c, 0x33, 0x75, 0x07, 0x7b, 0x07, 0x0a, 0x71, 0x6d, 0x72, 0xc9, 0x02, 0x70, 0x78, - 0x88, 0x88, 0x1f, 0x7a, 0xd1, 0xc9, 0xf6, 0x99, 0xa4, 0x0b, 0x2f, 0x6d, 0xf8, 0x04, 0xdb, 0x4e, - 0x89, 0x6e, 0x67, 0x0f, 0x04, 0xed, 0xf8, 0x10, 0x8d, 0xb7, 0xa2, 0x70, 0xdc, 0xf2, 0x75, 0xc0, - 0x42, 0xbb, 0xe2, 0x2e, 0xbe, 0x94, 0x4b, 0x9d, 0x7d, 0x04, 0x9f, 0x03, 0xa0, 0x4c, 0xcb, 0x34, - 0xca, 0xa4, 0x3d, 0xb7, 0xf8, 0xf5, 0x1d, 0x99, 0xbf, 0x77, 0x47, 0xe6, 0xd5, 0x1f, 0x32, 0x20, - 0x9f, 0x1e, 0x9e, 0x0f, 0x40, 0x76, 0xe4, 0x62, 0x6a, 0x4b, 0xba, 0x16, 0x21, 0xff, 0x3c, 0x95, - 0x4f, 0xbe, 0x82, 0x78, 0xb5, 0x90, 0x98, 0x51, 0x29, 0xbc, 0x04, 0x16, 0xec, 0x2d, 0x4c, 0x6c, - 0x9f, 0x19, 0xd8, 0x81, 0x51, 0x92, 0x72, 0xf8, 0x3e, 0xc8, 0x84, 0x28, 0xbe, 0x2b, 0x07, 0x07, - 0xc9, 0x84, 0x08, 0x7a, 0xa0, 0x10, 0x22, 0xeb, 0x33, 0x9f, 0x6c, 0x5b, 0x43, 0x97, 0xa0, 0xf8, - 0x26, 0x2c, 0xe9, 0xc6, 0xc1, 0x90, 0x9e, 0x4e, 0xe5, 0x15, 0x2a, 0x6c, 0x1a, 0x4b, 0x35, 0x41, - 0x88, 0xae, 0xfa, 0x64, 0x7b, 0x33, 0xfa, 0xf8, 0x89, 0x07, 0x73, 0xf1, 0xf3, 0xf5, 0x0f, 0x59, - 0xf2, 0x7f, 0xfe, 0x5e, 0x9d, 0xfa, 0x8e, 0x07, 0x60, 0x37, 0x0c, 0x45, 0x30, 0x6f, 0x6c, 0x34, - 0xdb, 0xd7, 0x04, 0x4e, 0x3c, 0x34, 0x9e, 0x28, 0x79, 0x1a, 0x36, 0xba, 0x3d, 0x32, 0x82, 0x47, - 0x40, 0xf6, 0x9a, 0xd1, 0x12, 0x78, 0x71, 0x79, 0x3c, 0x51, 0x96, 0xe8, 0xca, 0x35, 0x17, 0x43, - 0x09, 0x2c, 0x54, 0xf4, 0x56, 0xbb, 0x52, 0xab, 0x0b, 0x19, 0xf1, 0xf0, 0x78, 0xa2, 0x2c, 0xd3, - 0xb5, 0x0a, 0x3b, 0xdd, 0x55, 0x90, 0xa9, 0x37, 0x84, 0xac, 0x58, 0x18, 0x4f, 0x94, 0x45, 0xba, - 0x54, 0x47, 0xf0, 0x24, 0x28, 0xd4, 0x1b, 0xd6, 0xd5, 0x5a, 0xfb, 0x92, 0xb5, 0x69, 0xb4, 0x1b, - 0xc2, 0x9c, 0xb8, 0x3a, 0x9e, 0x28, 0x42, 0xb2, 0x9e, 0x48, 0x2e, 0x16, 0xbe, 0xfc, 0x46, 0xe2, - 0xee, 0xdd, 0x95, 0xb8, 0xef, 0xef, 0x4a, 0xdc, 0xa9, 0xdf, 0x79, 0x50, 0x9c, 0x35, 0xe7, 0x68, - 0x5b, 0xf5, 0xda, 0x15, 0x81, 0xa3, 0xdb, 0xa2, 0xc1, 0xba, 0x1f, 0xc0, 0x77, 0x40, 0xb1, 0x6a, - 0x34, 0x1b, 0xad, 0x5a, 0xdb, 0x6a, 0x1a, 0x66, 0xad, 0x51, 0x15, 0x78, 0xf1, 0xe8, 0x78, 0xa2, - 0xac, 0xd0, 0x14, 0x76, 0xef, 0x9b, 0x6e, 0xdf, 0x47, 0x0e, 0x7c, 0x1b, 0x2c, 0x6f, 0x36, 0xda, - 0xb5, 0xfa, 0xc5, 0x24, 0x37, 0x23, 0x1e, 0x19, 0x4f, 0x14, 0x48, 0x73, 0x37, 0xe3, 0x3b, 0xc5, - 0x52, 0xdf, 0x02, 0xb9, 0x66, 0xa5, 0xd5, 0x32, 0xaa, 0x42, 0x56, 0x14, 0xc6, 0x13, 0xa5, 0x40, - 0x73, 0x9a, 0x36, 0xc6, 0xae, 0x03, 0x15, 0xb0, 0x68, 0x1a, 0x97, 0x8d, 0xf3, 0x6d, 0xa3, 0x2a, - 0xcc, 0x89, 0x70, 0x3c, 0x51, 0x8a, 0x74, 0xdd, 0x74, 0x3f, 0x71, 0x3b, 0xc4, 0x8d, 0xeb, 0x2f, - 0x54, 0x6a, 0x57, 0x8c, 0xaa, 0x30, 0x9f, 0xae, 0xbf, 0x60, 0xfb, 0x81, 0xeb, 0xcc, 0xb6, 0xab, - 0xd7, 0xef, 0x3f, 0x96, 0xb8, 0x87, 0x8f, 0x25, 0xee, 0xd6, 0x8e, 0xc4, 0xdd, 0xdf, 0x91, 0xf8, - 0x07, 0x3b, 0x12, 0xff, 0xeb, 0x8e, 0xc4, 0xdf, 0x7e, 0x22, 0x71, 0x0f, 0x9e, 0x48, 0xdc, 0xc3, - 0x27, 0x12, 0xf7, 0xe1, 0xdf, 0x5b, 0x5e, 0xea, 0x7f, 0x81, 0xad, 0x5c, 0xec, 0x2a, 0x67, 0xff, - 0x0a, 0x00, 0x00, 0xff, 0xff, 0x48, 0xe7, 0x6e, 0x7f, 0x21, 0x0c, 0x00, 0x00, + // 1185 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x57, 0xc1, 0x6b, 0xdb, 0x56, + 0x18, 0x97, 0x6c, 0xc7, 0x49, 0x9e, 0x1d, 0x57, 0x7d, 0xc9, 0x5a, 0x4f, 0x0c, 0x49, 0x75, 0x4b, + 0xc9, 0x3a, 0x2a, 0xaf, 0xe9, 0x61, 0xd0, 0xc3, 0x98, 0x55, 0xab, 0xad, 0x4b, 0x63, 0x1b, 0xd9, + 0xa4, 0x74, 0x63, 0x08, 0xc5, 0x52, 0x15, 0xad, 0xb2, 0x9e, 0xe7, 0xf7, 0xec, 0xd5, 0xb7, 0xb1, + 0xc3, 0x28, 0x3e, 0xf5, 0xd8, 0x8b, 0xa1, 0xb0, 0x1e, 0xca, 0xd8, 0x61, 0x7f, 0x46, 0x60, 0x97, + 0x5e, 0x06, 0x65, 0x07, 0x77, 0x4d, 0x0e, 0x1b, 0x63, 0xa7, 0x5c, 0x06, 0x3b, 0x0d, 0xe9, 0x3d, + 0x25, 0x76, 0x92, 0x2e, 0x0d, 0xdd, 0x60, 0xec, 0x92, 0x44, 0xdf, 0xfb, 0x7d, 0xbf, 0xef, 0x7d, + 0xbf, 0xf7, 0xbd, 0xdf, 0x23, 0xe0, 0xf4, 0xfd, 0xa2, 0x8b, 0xfa, 0x45, 0x32, 0xe8, 0x38, 0x98, + 0xfe, 0x54, 0x3b, 0x5d, 0x44, 0x10, 0x5c, 0x6c, 0x21, 0xdc, 0x46, 0xd8, 0xc4, 0xf6, 0x3d, 0xf5, + 0xbe, 0xea, 0xa2, 0xbe, 0xda, 0xbf, 0x24, 0x9e, 0x3c, 0x80, 0x13, 0xcf, 0x93, 0x0d, 0xaf, 0x6b, + 0x9b, 0x1d, 0xab, 0x4b, 0x06, 0xc5, 0x28, 0x54, 0x74, 0x91, 0x8b, 0xf6, 0xfe, 0x62, 0x38, 0xd9, + 0x45, 0xc8, 0xf5, 0x1d, 0x0a, 0x59, 0xef, 0xdd, 0x2d, 0x12, 0xaf, 0xed, 0x60, 0x62, 0xb5, 0x3b, + 0x14, 0x50, 0xf8, 0x83, 0x07, 0x6f, 0xad, 0x62, 0xb7, 0xd1, 0x5b, 0x6f, 0x7b, 0xa4, 0xde, 0x45, + 0x1d, 0x84, 0x2d, 0x5f, 0xb3, 0xb0, 0x03, 0x1f, 0xf0, 0xe0, 0x84, 0x17, 0x78, 0xc4, 0xb3, 0x7c, + 0xd3, 0x76, 0x3a, 0x08, 0x7b, 0x24, 0xcf, 0x2b, 0xc9, 0xe5, 0xcc, 0xca, 0xa2, 0x3a, 0xb1, 0xcb, + 0xfe, 0x25, 0xf5, 0x2a, 0xf2, 0x02, 0xed, 0xe6, 0xe6, 0x58, 0xe6, 0x76, 0xc6, 0xf2, 0xa9, 0x81, + 0xd5, 0xf6, 0xaf, 0x14, 0xf6, 0x65, 0x16, 0xbe, 0x7d, 0x21, 0x2f, 0xbb, 0x1e, 0xd9, 0xe8, 0xad, + 0xab, 0x2d, 0xd4, 0x2e, 0x52, 0x02, 0xf6, 0xeb, 0x22, 0xb6, 0xef, 0xb1, 0xee, 0x42, 0x2a, 0x6c, + 0xe4, 0x58, 0x76, 0x99, 0x26, 0xc3, 0x55, 0x30, 0xd7, 0x89, 0xb6, 0xe6, 0x74, 0xf3, 0x09, 0x85, + 0x5f, 0xce, 0x6a, 0x97, 0xfe, 0x1c, 0xcb, 0x17, 0x5f, 0x83, 0xaf, 0xd4, 0x6a, 0x95, 0x6c, 0xbb, + 0xeb, 0x60, 0x6c, 0xec, 0x52, 0x5c, 0x49, 0xfd, 0xfa, 0x58, 0xe6, 0x0b, 0xbf, 0xf0, 0x60, 0x76, + 0x15, 0xbb, 0x6b, 0x88, 0x38, 0xb0, 0x09, 0x32, 0x1d, 0xd6, 0xbb, 0xe9, 0xd9, 0x79, 0x5e, 0xe1, + 0x97, 0x53, 0xda, 0xe5, 0xad, 0xb1, 0x0c, 0x62, 0x49, 0x2a, 0xe5, 0xdf, 0xc6, 0xf2, 0x24, 0x68, + 0x67, 0x2c, 0x43, 0xda, 0xea, 0x44, 0xb0, 0x60, 0x80, 0xf8, 0xab, 0x62, 0xc3, 0xeb, 0x60, 0xa6, + 0x8f, 0xc8, 0x9b, 0xec, 0x99, 0xe6, 0xc3, 0x0f, 0x40, 0x1a, 0x75, 0x88, 0x87, 0x82, 0x7c, 0x52, + 0xe1, 0x97, 0x73, 0x2b, 0xb2, 0x7a, 0xc8, 0x98, 0xa8, 0x61, 0x27, 0xb5, 0x08, 0x66, 0x30, 0x38, + 0xeb, 0xf4, 0x51, 0x02, 0x80, 0x55, 0xec, 0xc6, 0x6a, 0xfe, 0x3b, 0xcd, 0xd6, 0xc0, 0x3c, 0x3b, + 0x6b, 0xf4, 0x06, 0x0d, 0xef, 0x71, 0xc0, 0x4f, 0x41, 0xda, 0x6a, 0xa3, 0x5e, 0x40, 0xf2, 0xc9, + 0x57, 0x4f, 0xdd, 0xfb, 0xe1, 0xd4, 0x1d, 0x6b, 0xb6, 0x18, 0x29, 0x93, 0xe6, 0x16, 0xc8, 0x36, + 0x9d, 0xfb, 0xbb, 0x83, 0x0f, 0x97, 0xc0, 0x0c, 0xf1, 0x88, 0xef, 0x44, 0xaa, 0xcc, 0x1b, 0xf4, + 0x03, 0x2a, 0x20, 0x63, 0x3b, 0xb8, 0xd5, 0xf5, 0xe8, 0x21, 0x24, 0xa2, 0xb5, 0xc9, 0x10, 0x63, + 0xfb, 0x3a, 0x01, 0x66, 0x63, 0x95, 0xf5, 0xc3, 0x54, 0x3e, 0x37, 0xad, 0xf2, 0xff, 0x56, 0xd6, + 0x1f, 0xd2, 0x20, 0x3b, 0x65, 0x26, 0xda, 0x61, 0x6a, 0x9c, 0x39, 0x30, 0x73, 0x89, 0x68, 0xd4, + 0xe6, 0x99, 0x85, 0xec, 0x93, 0xe2, 0x36, 0x48, 0x63, 0x62, 0x91, 0x1e, 0x8e, 0x74, 0xc8, 0xad, + 0x9c, 0x3d, 0xf4, 0x16, 0xc4, 0x7c, 0x8d, 0x08, 0xaa, 0x89, 0x7b, 0x96, 0xb4, 0xbb, 0x01, 0xca, + 0x52, 0x30, 0x18, 0x1d, 0xfc, 0x1c, 0xc0, 0xbb, 0x5e, 0x60, 0xf9, 0x26, 0xb1, 0x7c, 0x7f, 0x60, + 0x76, 0x1d, 0xdc, 0xf3, 0x49, 0x74, 0xd5, 0x32, 0x2b, 0xca, 0xa1, 0x45, 0x9a, 0x21, 0xd0, 0x88, + 0x70, 0xda, 0x19, 0x66, 0x7c, 0x6f, 0xd3, 0x2a, 0x07, 0x99, 0x0a, 0x86, 0x10, 0x05, 0x27, 0x92, + 0xe0, 0x27, 0x20, 0x83, 0x23, 0xcb, 0x35, 0x43, 0x43, 0xce, 0xa7, 0xa2, 0x5a, 0xa2, 0x4a, 0xdd, + 0x5a, 0x8d, 0xdd, 0x5a, 0x6d, 0xc6, 0x6e, 0xad, 0x49, 0xac, 0x0a, 0x9b, 0x97, 0x89, 0xe4, 0xc2, + 0xc3, 0x17, 0x32, 0x6f, 0x00, 0x1a, 0x09, 0x13, 0xa0, 0x07, 0x04, 0x76, 0xde, 0xa6, 0x13, 0xd8, + 0xb4, 0xc2, 0xcc, 0x91, 0x15, 0xce, 0xb2, 0x0a, 0xa7, 0x69, 0x85, 0xfd, 0x0c, 0xb4, 0x4c, 0x8e, + 0x85, 0xf5, 0xc0, 0x8e, 0x4a, 0x7d, 0xc5, 0x83, 0x05, 0x82, 0xc8, 0xc4, 0x13, 0x91, 0x7e, 0xf5, + 0x54, 0xdd, 0x60, 0x15, 0x96, 0x68, 0x85, 0xa9, 0xbc, 0xe3, 0x3d, 0x10, 0xd9, 0x28, 0x37, 0xbe, + 0x6a, 0x3e, 0x38, 0xd9, 0x47, 0xc4, 0x0b, 0xdc, 0xf0, 0x64, 0xbb, 0x4c, 0xd2, 0xd9, 0x23, 0x1b, + 0x3e, 0xc7, 0xb6, 0x93, 0xa7, 0xdb, 0x39, 0x40, 0x41, 0x3b, 0x3e, 0x41, 0xe3, 0x8d, 0x30, 0x1c, + 0xb5, 0x7c, 0x17, 0xb0, 0xd0, 0x9e, 0xb8, 0x73, 0x47, 0xd6, 0x2a, 0x4c, 0xbf, 0x8e, 0xfb, 0x08, + 0x68, 0xa5, 0x05, 0x1a, 0x65, 0xd2, 0x5e, 0x99, 0x7b, 0xf4, 0x58, 0xe6, 0x9f, 0x86, 0xb7, 0x69, + 0x33, 0x01, 0x32, 0x93, 0xc3, 0xf3, 0x11, 0x48, 0x0e, 0x1c, 0x4c, 0x2d, 0x4a, 0x53, 0x43, 0xe6, + 0x9f, 0xc6, 0xf2, 0xf9, 0xd7, 0x10, 0xaf, 0x12, 0x10, 0x23, 0x4c, 0x85, 0x37, 0xc0, 0xac, 0xb5, + 0x8e, 0x89, 0xe5, 0x31, 0x33, 0x3b, 0x36, 0x4b, 0x9c, 0x0e, 0x3f, 0x04, 0x89, 0x00, 0x45, 0x77, + 0xe5, 0xf8, 0x24, 0x89, 0x00, 0x41, 0x17, 0x64, 0x03, 0x64, 0x7e, 0xe1, 0x91, 0x0d, 0xb3, 0xef, + 0x10, 0x14, 0xdd, 0x84, 0x79, 0x4d, 0x3f, 0x1e, 0xd3, 0xce, 0x58, 0x5e, 0xa4, 0xc2, 0x4e, 0x72, + 0x15, 0x0c, 0x10, 0xa0, 0xdb, 0x1e, 0xd9, 0x58, 0x73, 0x08, 0x62, 0xc6, 0xf4, 0x23, 0x0f, 0x52, + 0xd1, 0x8b, 0xff, 0x0f, 0xd9, 0xf3, 0x7f, 0xe4, 0x89, 0xbf, 0xf0, 0x1d, 0x0f, 0xc0, 0xde, 0x22, + 0x14, 0xc1, 0x8c, 0xbe, 0x5a, 0x6f, 0xde, 0x11, 0x38, 0xf1, 0xc4, 0x70, 0xa4, 0x64, 0x68, 0x58, + 0x6f, 0x77, 0xc8, 0x00, 0x9e, 0x02, 0xc9, 0x3b, 0x7a, 0x43, 0xe0, 0xc5, 0x85, 0xe1, 0x48, 0x99, + 0xa7, 0x2b, 0x77, 0x1c, 0x0c, 0x25, 0x30, 0x5b, 0xd2, 0x1a, 0xcd, 0x52, 0xa5, 0x2a, 0x24, 0xc4, + 0x93, 0xc3, 0x91, 0xb2, 0x40, 0xd7, 0x4a, 0xec, 0xa4, 0x97, 0x40, 0xa2, 0x5a, 0x13, 0x92, 0x62, + 0x76, 0x38, 0x52, 0xe6, 0xe8, 0x52, 0x15, 0xc1, 0xf3, 0x20, 0x5b, 0xad, 0x99, 0xb7, 0x2b, 0xcd, + 0x1b, 0xe6, 0x9a, 0xde, 0xac, 0x09, 0x29, 0x71, 0x69, 0x38, 0x52, 0x84, 0x78, 0x3d, 0x96, 0x5f, + 0xcc, 0x3e, 0xf8, 0x46, 0xe2, 0x9e, 0x3e, 0x91, 0xb8, 0xef, 0x9f, 0x48, 0xdc, 0x85, 0xdf, 0x79, + 0x90, 0x9b, 0x36, 0xea, 0x70, 0x5b, 0xd5, 0xca, 0x2d, 0x81, 0xa3, 0xdb, 0xa2, 0xc1, 0xaa, 0xe7, + 0xc3, 0xf7, 0x40, 0xae, 0xac, 0xd7, 0x6b, 0x8d, 0x4a, 0xd3, 0xac, 0xeb, 0x46, 0xa5, 0x56, 0x16, + 0x78, 0xf1, 0xf4, 0x70, 0xa4, 0x2c, 0x52, 0x08, 0xf3, 0x80, 0xba, 0xd3, 0xf5, 0x90, 0x0d, 0xdf, + 0x05, 0x0b, 0x6b, 0xb5, 0x66, 0xa5, 0x7a, 0x3d, 0xc6, 0x26, 0xc4, 0x53, 0xc3, 0x91, 0x02, 0x29, + 0x76, 0x2d, 0xba, 0x5f, 0x0c, 0xfa, 0x0e, 0x48, 0xd7, 0x4b, 0x8d, 0x86, 0x5e, 0x16, 0x92, 0xa2, + 0x30, 0x1c, 0x29, 0x59, 0x8a, 0xa9, 0x5b, 0x18, 0x3b, 0x36, 0x54, 0xc0, 0x9c, 0xa1, 0xdf, 0xd4, + 0xaf, 0x36, 0xf5, 0xb2, 0x90, 0x12, 0xe1, 0x70, 0xa4, 0xe4, 0xe8, 0xba, 0xe1, 0x7c, 0xe6, 0xb4, + 0x88, 0x13, 0xe5, 0x5f, 0x2b, 0x55, 0x6e, 0xe9, 0x65, 0x61, 0x66, 0x32, 0xff, 0x9a, 0xe5, 0xf9, + 0x8e, 0x3d, 0xdd, 0xae, 0x56, 0xdd, 0x7c, 0x29, 0x71, 0xcf, 0x5f, 0x4a, 0xdc, 0x97, 0x5b, 0x12, + 0xb7, 0xb9, 0x25, 0xf1, 0xcf, 0xb6, 0x24, 0xfe, 0xe7, 0x2d, 0x89, 0x7f, 0xb8, 0x2d, 0x71, 0xcf, + 0xb6, 0x25, 0xee, 0xf9, 0xb6, 0xc4, 0x7d, 0xfc, 0xf7, 0xf6, 0x37, 0xf1, 0x1f, 0xc3, 0x7a, 0x3a, + 0x72, 0x98, 0xcb, 0x7f, 0x05, 0x00, 0x00, 0xff, 0xff, 0x41, 0x42, 0x32, 0xc2, 0x47, 0x0c, 0x00, + 0x00, +} + +func (this *MsgSubmitProposalBase) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*MsgSubmitProposalBase) + if !ok { + that2, ok := that.(MsgSubmitProposalBase) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if len(this.InitialDeposit) != len(that1.InitialDeposit) { + return false + } + for i := range this.InitialDeposit { + if !this.InitialDeposit[i].Equal(&that1.InitialDeposit[i]) { + return false + } + } + if !bytes.Equal(this.Proposer, that1.Proposer) { + return false + } + return true +} +func (this *MsgVote) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*MsgVote) + if !ok { + that2, ok := that.(MsgVote) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.ProposalID != that1.ProposalID { + return false + } + if !bytes.Equal(this.Voter, that1.Voter) { + return false + } + if this.Option != that1.Option { + return false + } + return true +} +func (this *MsgDeposit) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*MsgDeposit) + if !ok { + that2, ok := that.(MsgDeposit) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.ProposalID != that1.ProposalID { + return false + } + if !bytes.Equal(this.Depositor, that1.Depositor) { + return false + } + if len(this.Amount) != len(that1.Amount) { + return false + } + for i := range this.Amount { + if !this.Amount[i].Equal(&that1.Amount[i]) { + return false + } + } + return true +} +func (this *TextProposal) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*TextProposal) + if !ok { + that2, ok := that.(TextProposal) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Title != that1.Title { + return false + } + if this.Description != that1.Description { + return false + } + return true +} +func (this *Deposit) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*Deposit) + if !ok { + that2, ok := that.(Deposit) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.ProposalID != that1.ProposalID { + return false + } + if !bytes.Equal(this.Depositor, that1.Depositor) { + return false + } + if len(this.Amount) != len(that1.Amount) { + return false + } + for i := range this.Amount { + if !this.Amount[i].Equal(&that1.Amount[i]) { + return false + } + } + return true +} +func (this *TallyResult) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*TallyResult) + if !ok { + that2, ok := that.(TallyResult) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !this.Yes.Equal(that1.Yes) { + return false + } + if !this.Abstain.Equal(that1.Abstain) { + return false + } + if !this.No.Equal(that1.No) { + return false + } + if !this.NoWithVeto.Equal(that1.NoWithVeto) { + return false + } + return true +} +func (this *Vote) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*Vote) + if !ok { + that2, ok := that.(Vote) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.ProposalID != that1.ProposalID { + return false + } + if !bytes.Equal(this.Voter, that1.Voter) { + return false + } + if this.Option != that1.Option { + return false + } + return true } type ProposalBaseFace interface { @@ -602,10 +832,10 @@ func (m *MsgSubmitProposalBase) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x12 } - if len(m.IntialDeposit) > 0 { - for iNdEx := len(m.IntialDeposit) - 1; iNdEx >= 0; iNdEx-- { + if len(m.InitialDeposit) > 0 { + for iNdEx := len(m.InitialDeposit) - 1; iNdEx >= 0; iNdEx-- { { - size, err := m.IntialDeposit[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + size, err := m.InitialDeposit[iNdEx].MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -619,7 +849,7 @@ func (m *MsgSubmitProposalBase) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *MsgDeposit) Marshal() (dAtA []byte, err error) { +func (m *MsgVote) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -629,34 +859,25 @@ func (m *MsgDeposit) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *MsgDeposit) MarshalTo(dAtA []byte) (int, error) { +func (m *MsgVote) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *MsgDeposit) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *MsgVote) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l - if len(m.Amount) > 0 { - for iNdEx := len(m.Amount) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Amount[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTypes(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x1a - } + if m.Option != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.Option)) + i-- + dAtA[i] = 0x18 } - if len(m.Depositor) > 0 { - i -= len(m.Depositor) - copy(dAtA[i:], m.Depositor) - i = encodeVarintTypes(dAtA, i, uint64(len(m.Depositor))) + if len(m.Voter) > 0 { + i -= len(m.Voter) + copy(dAtA[i:], m.Voter) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Voter))) i-- dAtA[i] = 0x12 } @@ -668,7 +889,7 @@ func (m *MsgDeposit) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *MsgVote) Marshal() (dAtA []byte, err error) { +func (m *MsgDeposit) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -678,25 +899,34 @@ func (m *MsgVote) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *MsgVote) MarshalTo(dAtA []byte) (int, error) { +func (m *MsgDeposit) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *MsgVote) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *MsgDeposit) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l - if m.Option != 0 { - i = encodeVarintTypes(dAtA, i, uint64(m.Option)) - i-- - dAtA[i] = 0x18 + if len(m.Amount) > 0 { + for iNdEx := len(m.Amount) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Amount[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } } - if len(m.Voter) > 0 { - i -= len(m.Voter) - copy(dAtA[i:], m.Voter) - i = encodeVarintTypes(dAtA, i, uint64(len(m.Voter))) + if len(m.Depositor) > 0 { + i -= len(m.Depositor) + copy(dAtA[i:], m.Depositor) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Depositor))) i-- dAtA[i] = 0x12 } @@ -1003,8 +1233,8 @@ func (m *MsgSubmitProposalBase) Size() (n int) { } var l int _ = l - if len(m.IntialDeposit) > 0 { - for _, e := range m.IntialDeposit { + if len(m.InitialDeposit) > 0 { + for _, e := range m.InitialDeposit { l = e.Size() n += 1 + l + sovTypes(uint64(l)) } @@ -1016,7 +1246,7 @@ func (m *MsgSubmitProposalBase) Size() (n int) { return n } -func (m *MsgDeposit) Size() (n int) { +func (m *MsgVote) Size() (n int) { if m == nil { return 0 } @@ -1025,20 +1255,17 @@ func (m *MsgDeposit) Size() (n int) { if m.ProposalID != 0 { n += 1 + sovTypes(uint64(m.ProposalID)) } - l = len(m.Depositor) + l = len(m.Voter) if l > 0 { n += 1 + l + sovTypes(uint64(l)) } - if len(m.Amount) > 0 { - for _, e := range m.Amount { - l = e.Size() - n += 1 + l + sovTypes(uint64(l)) - } + if m.Option != 0 { + n += 1 + sovTypes(uint64(m.Option)) } return n } -func (m *MsgVote) Size() (n int) { +func (m *MsgDeposit) Size() (n int) { if m == nil { return 0 } @@ -1047,12 +1274,15 @@ func (m *MsgVote) Size() (n int) { if m.ProposalID != 0 { n += 1 + sovTypes(uint64(m.ProposalID)) } - l = len(m.Voter) + l = len(m.Depositor) if l > 0 { n += 1 + l + sovTypes(uint64(l)) } - if m.Option != 0 { - n += 1 + sovTypes(uint64(m.Option)) + if len(m.Amount) > 0 { + for _, e := range m.Amount { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } } return n } @@ -1169,30 +1399,6 @@ func sovTypes(x uint64) (n int) { func sozTypes(x uint64) (n int) { return sovTypes(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } -func (this *MsgSubmitProposalBase) String() string { - if this == nil { - return "nil" - } - repeatedStringForIntialDeposit := "[]Coin{" - for _, f := range this.IntialDeposit { - repeatedStringForIntialDeposit += fmt.Sprintf("%v", f) + "," - } - repeatedStringForIntialDeposit += "}" - s := strings.Join([]string{`&MsgSubmitProposalBase{`, - `IntialDeposit:` + repeatedStringForIntialDeposit + `,`, - `Proposer:` + fmt.Sprintf("%v", this.Proposer) + `,`, - `}`, - }, "") - return s -} -func valueToStringTypes(v interface{}) string { - rv := reflect.ValueOf(v) - if rv.IsNil() { - return "nil" - } - pv := reflect.Indirect(rv).Interface() - return fmt.Sprintf("*%v", pv) -} func (m *MsgSubmitProposalBase) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -1224,7 +1430,7 @@ func (m *MsgSubmitProposalBase) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field IntialDeposit", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field InitialDeposit", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -1251,8 +1457,8 @@ func (m *MsgSubmitProposalBase) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.IntialDeposit = append(m.IntialDeposit, types.Coin{}) - if err := m.IntialDeposit[len(m.IntialDeposit)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + m.InitialDeposit = append(m.InitialDeposit, types.Coin{}) + if err := m.InitialDeposit[len(m.InitialDeposit)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -1314,7 +1520,7 @@ func (m *MsgSubmitProposalBase) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgDeposit) Unmarshal(dAtA []byte) error { +func (m *MsgVote) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1337,10 +1543,10 @@ func (m *MsgDeposit) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgDeposit: wiretype end group for non-group") + return fmt.Errorf("proto: MsgVote: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgDeposit: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgVote: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -1364,7 +1570,7 @@ func (m *MsgDeposit) Unmarshal(dAtA []byte) error { } case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Depositor", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Voter", wireType) } var byteLen int for shift := uint(0); ; shift += 7 { @@ -1391,16 +1597,16 @@ func (m *MsgDeposit) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Depositor = append(m.Depositor[:0], dAtA[iNdEx:postIndex]...) - if m.Depositor == nil { - m.Depositor = []byte{} + m.Voter = append(m.Voter[:0], dAtA[iNdEx:postIndex]...) + if m.Voter == nil { + m.Voter = []byte{} } iNdEx = postIndex case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Option", wireType) } - var msglen int + m.Option = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTypes @@ -1410,26 +1616,11 @@ func (m *MsgDeposit) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + m.Option |= VoteOption(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { - return ErrInvalidLengthTypes - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthTypes - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Amount = append(m.Amount, types.Coin{}) - if err := m.Amount[len(m.Amount)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTypes(dAtA[iNdEx:]) @@ -1454,7 +1645,7 @@ func (m *MsgDeposit) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgVote) Unmarshal(dAtA []byte) error { +func (m *MsgDeposit) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1477,10 +1668,10 @@ func (m *MsgVote) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgVote: wiretype end group for non-group") + return fmt.Errorf("proto: MsgDeposit: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgVote: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgDeposit: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -1504,7 +1695,7 @@ func (m *MsgVote) Unmarshal(dAtA []byte) error { } case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Voter", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Depositor", wireType) } var byteLen int for shift := uint(0); ; shift += 7 { @@ -1531,16 +1722,16 @@ func (m *MsgVote) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Voter = append(m.Voter[:0], dAtA[iNdEx:postIndex]...) - if m.Voter == nil { - m.Voter = []byte{} + m.Depositor = append(m.Depositor[:0], dAtA[iNdEx:postIndex]...) + if m.Depositor == nil { + m.Depositor = []byte{} } iNdEx = postIndex case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Option", wireType) + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) } - m.Option = 0 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTypes @@ -1550,11 +1741,26 @@ func (m *MsgVote) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.Option |= VoteOption(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Amount = append(m.Amount, types.Coin{}) + if err := m.Amount[len(m.Amount)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTypes(dAtA[iNdEx:]) diff --git a/x/gov/types/types.proto b/x/gov/types/types.proto index b22abea1ec9e..6b8b50944133 100644 --- a/x/gov/types/types.proto +++ b/x/gov/types/types.proto @@ -10,10 +10,17 @@ option (gogoproto.goproto_stringer_all) = false; option (gogoproto.stringer_all) = false; option (gogoproto.goproto_getters_all) = false; +// MsgSubmitProposalBase defines an sdk.Msg type that supports submitting arbitrary +// proposal Content. +// +// Note, this message type provides the basis for which a true MsgSubmitProposal +// can be constructed. Since the Content submitted in the message can be arbitrary, +// assuming it fulfills the Content interface, it must be defined at the +// application-level and extend MsgSubmitProposalBase. message MsgSubmitProposalBase { - option (gogoproto.stringer) = true; + option (gogoproto.equal) = true; - repeated cosmos_sdk.v1.Coin intial_deposit = 1 [ + repeated cosmos_sdk.v1.Coin initial_deposit = 1 [ (gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", (gogoproto.moretags) = "yaml:\"initial_deposit\"" @@ -21,8 +28,23 @@ message MsgSubmitProposalBase { bytes proposer = 2 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; } +// MsgVote defines a message to cast a vote +message MsgVote { + option (gogoproto.equal) = true; + + uint64 proposal_id = 1 [ + (gogoproto.customname) = "ProposalID", + (gogoproto.moretags) = "yaml:\"proposal_id\"", + (gogoproto.jsontag) = "proposal_id" + ]; + bytes voter = 2 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; + VoteOption option = 3; +} + // MsgDeposit defines a message to submit a deposit to an existing proposal message MsgDeposit { + option (gogoproto.equal) = true; + uint64 proposal_id = 1 [ (gogoproto.customname) = "ProposalID", (gogoproto.moretags) = "yaml:\"proposal_id\"", @@ -46,26 +68,19 @@ enum VoteOption { NO_WITH_VETO = 4 [(gogoproto.enumvalue_customname) = "OptionNoWithVeto"]; } -// MsgVote defines a message to cast a vote -message MsgVote { - uint64 proposal_id = 1 [ - (gogoproto.customname) = "ProposalID", - (gogoproto.moretags) = "yaml:\"proposal_id\"", - (gogoproto.jsontag) = "proposal_id" - ]; - bytes voter = 2 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; - VoteOption option = 3; -} - // TextProposal defines a standard text proposal whose changes need to be // manually updated in case of approval message TextProposal { + option (gogoproto.equal) = true; + string title = 1; string description = 2; } // Deposit defines an amount deposited by an account address to an active proposal message Deposit { + option (gogoproto.equal) = true; + uint64 proposal_id = 1 [(gogoproto.customname) = "ProposalID", (gogoproto.moretags) = "yaml:\"proposal_id\""]; bytes depositor = 2 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; repeated cosmos_sdk.v1.Coin amount = 3 @@ -115,6 +130,8 @@ enum ProposalStatus { // TallyResult defines a standard tally for a proposal message TallyResult { + option (gogoproto.equal) = true; + string yes = 1 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", (gogoproto.nullable) = false]; string abstain = 2 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", (gogoproto.nullable) = false]; string no = 3 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", (gogoproto.nullable) = false]; @@ -128,6 +145,8 @@ message TallyResult { // Vote defines a vote on a governance proposal. A vote corresponds to a proposal // ID, the voter, and the vote option. message Vote { + option (gogoproto.equal) = true; + uint64 proposal_id = 1 [(gogoproto.customname) = "ProposalID", (gogoproto.moretags) = "yaml:\"proposal_id\""]; bytes voter = 2 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; VoteOption option = 3; diff --git a/x/gov/types/vote.go b/x/gov/types/vote.go index f74f27ef2156..8a2f0df71cad 100644 --- a/x/gov/types/vote.go +++ b/x/gov/types/vote.go @@ -4,6 +4,8 @@ import ( "encoding/json" "fmt" + "gopkg.in/yaml.v2" + sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -13,7 +15,8 @@ func NewVote(proposalID uint64, voter sdk.AccAddress, option VoteOption) Vote { } func (v Vote) String() string { - return fmt.Sprintf("voter %s voted with option %s on proposal %d", v.Voter, v.Option, v.ProposalID) + out, _ := yaml.Marshal(v) + return string(out) } // Votes is a collection of Vote objects From a016524468000c4eb9696ff6f69314b987e6d1dc Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 2 Mar 2020 21:19:46 +0100 Subject: [PATCH 330/529] migrate TestHandleNewValidator to new simapp --- x/slashing/keeper/common_test.go | 7 + x/slashing/keeper/keeper_test.go | 214 ++++--------------------- x/slashing/keeper/old_keeper_test.go | 223 +++++++++++++++++++++++++++ 3 files changed, 258 insertions(+), 186 deletions(-) create mode 100644 x/slashing/keeper/common_test.go create mode 100644 x/slashing/keeper/old_keeper_test.go diff --git a/x/slashing/keeper/common_test.go b/x/slashing/keeper/common_test.go new file mode 100644 index 000000000000..940d995cacc7 --- /dev/null +++ b/x/slashing/keeper/common_test.go @@ -0,0 +1,7 @@ +package keeper_test + +import sdk "github.com/cosmos/cosmos-sdk/types" + +var ( + InitTokens = sdk.TokensFromConsensusPower(200) +) diff --git a/x/slashing/keeper/keeper_test.go b/x/slashing/keeper/keeper_test.go index 4f4f555bbffc..785682995af5 100644 --- a/x/slashing/keeper/keeper_test.go +++ b/x/slashing/keeper/keeper_test.go @@ -1,13 +1,16 @@ -package keeper +package keeper_test import ( "testing" "time" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/stretchr/testify/require" + "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/slashing/types" + "github.com/cosmos/cosmos-sdk/x/slashing/keeper" "github.com/cosmos/cosmos-sdk/x/staking" ) @@ -15,209 +18,48 @@ import ( // Ensure that SigningInfo.StartHeight is set correctly // and that they are not immediately jailed func TestHandleNewValidator(t *testing.T) { - // initial setup - ctx, bk, sk, _, keeper := CreateTestInput(t, TestParams()) - addr, val := Addrs[0], Pks[0] + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + addrDels := simapp.AddTestAddrsIncremental(app, ctx, 1, sdk.TokensFromConsensusPower(200)) + valAddrs := simapp.ConvertAddrsToValAddrs(addrDels) + pks := simapp.CreateTestPubKeys(1) + + addr, val := valAddrs[0], pks[0] amt := sdk.TokensFromConsensusPower(100) - sh := staking.NewHandler(sk) + sh := staking.NewHandler(app.StakingKeeper) - // 1000 first blocks not a validator - ctx = ctx.WithBlockHeight(keeper.SignedBlocksWindow(ctx) + 1) + ctx = ctx.WithBlockHeight(app.SlashingKeeper.SignedBlocksWindow(ctx) + 1) // Validator created - res, err := sh(ctx, NewTestMsgCreateValidator(addr, val, amt)) + res, err := sh(ctx, keeper.NewTestMsgCreateValidator(addr, val, amt)) require.NoError(t, err) require.NotNil(t, res) - staking.EndBlocker(ctx, sk) + staking.EndBlocker(ctx, app.StakingKeeper) require.Equal( - t, bk.GetAllBalances(ctx, sdk.AccAddress(addr)), - sdk.NewCoins(sdk.NewCoin(sk.GetParams(ctx).BondDenom, InitTokens.Sub(amt))), + t, app.BankKeeper.GetAllBalances(ctx, sdk.AccAddress(addr)), + sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.GetParams(ctx).BondDenom, InitTokens.Sub(amt))), ) - require.Equal(t, amt, sk.Validator(ctx, addr).GetBondedTokens()) + require.Equal(t, amt, app.StakingKeeper.Validator(ctx, addr).GetBondedTokens()) // Now a validator, for two blocks - keeper.HandleValidatorSignature(ctx, val.Address(), 100, true) - ctx = ctx.WithBlockHeight(keeper.SignedBlocksWindow(ctx) + 2) - keeper.HandleValidatorSignature(ctx, val.Address(), 100, false) + app.SlashingKeeper.HandleValidatorSignature(ctx, val.Address(), 100, true) + ctx = ctx.WithBlockHeight(app.SlashingKeeper.SignedBlocksWindow(ctx) + 2) + app.SlashingKeeper.HandleValidatorSignature(ctx, val.Address(), 100, false) - info, found := keeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) + info, found := app.SlashingKeeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) require.True(t, found) - require.Equal(t, keeper.SignedBlocksWindow(ctx)+1, info.StartHeight) + require.Equal(t, app.SlashingKeeper.SignedBlocksWindow(ctx)+1, info.StartHeight) require.Equal(t, int64(2), info.IndexOffset) require.Equal(t, int64(1), info.MissedBlocksCounter) require.Equal(t, time.Unix(0, 0).UTC(), info.JailedUntil) // validator should be bonded still, should not have been jailed or slashed - validator, _ := sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) + validator, _ := app.StakingKeeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) require.Equal(t, sdk.Bonded, validator.GetStatus()) - bondPool := sk.GetBondedPool(ctx) + bondPool := app.StakingKeeper.GetBondedPool(ctx) expTokens := sdk.TokensFromConsensusPower(100) - require.Equal(t, expTokens.Int64(), bk.GetBalance(ctx, bondPool.GetAddress(), sk.BondDenom(ctx)).Amount.Int64()) -} - -// Test a jailed validator being "down" twice -// Ensure that they're only slashed once -func TestHandleAlreadyJailed(t *testing.T) { - - // initial setup - ctx, _, sk, _, keeper := CreateTestInput(t, types.DefaultParams()) - power := int64(100) - amt := sdk.TokensFromConsensusPower(power) - addr, val := Addrs[0], Pks[0] - sh := staking.NewHandler(sk) - res, err := sh(ctx, NewTestMsgCreateValidator(addr, val, amt)) - require.NoError(t, err) - require.NotNil(t, res) - - staking.EndBlocker(ctx, sk) - - // 1000 first blocks OK - height := int64(0) - for ; height < keeper.SignedBlocksWindow(ctx); height++ { - ctx = ctx.WithBlockHeight(height) - keeper.HandleValidatorSignature(ctx, val.Address(), power, true) - } - - // 501 blocks missed - for ; height < keeper.SignedBlocksWindow(ctx)+(keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx))+1; height++ { - ctx = ctx.WithBlockHeight(height) - keeper.HandleValidatorSignature(ctx, val.Address(), power, false) - } - - // end block - staking.EndBlocker(ctx, sk) - - // validator should have been jailed and slashed - validator, _ := sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) - require.Equal(t, sdk.Unbonding, validator.GetStatus()) - - // validator should have been slashed - resultingTokens := amt.Sub(sdk.TokensFromConsensusPower(1)) - require.Equal(t, resultingTokens, validator.GetTokens()) - - // another block missed - ctx = ctx.WithBlockHeight(height) - keeper.HandleValidatorSignature(ctx, val.Address(), power, false) - - // validator should not have been slashed twice - validator, _ = sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) - require.Equal(t, resultingTokens, validator.GetTokens()) - -} - -// Test a validator dipping in and out of the validator set -// Ensure that missed blocks are tracked correctly and that -// the start height of the signing info is reset correctly -func TestValidatorDippingInAndOut(t *testing.T) { - - // initial setup - // TestParams set the SignedBlocksWindow to 1000 and MaxMissedBlocksPerWindow to 500 - ctx, _, sk, _, keeper := CreateTestInput(t, TestParams()) - params := sk.GetParams(ctx) - params.MaxValidators = 1 - sk.SetParams(ctx, params) - power := int64(100) - amt := sdk.TokensFromConsensusPower(power) - addr, val := Addrs[0], Pks[0] - consAddr := sdk.ConsAddress(addr) - sh := staking.NewHandler(sk) - res, err := sh(ctx, NewTestMsgCreateValidator(addr, val, amt)) - require.NoError(t, err) - require.NotNil(t, res) - - staking.EndBlocker(ctx, sk) - - // 100 first blocks OK - height := int64(0) - for ; height < int64(100); height++ { - ctx = ctx.WithBlockHeight(height) - keeper.HandleValidatorSignature(ctx, val.Address(), power, true) - } - - // kick first validator out of validator set - newAmt := sdk.TokensFromConsensusPower(101) - res, err = sh(ctx, NewTestMsgCreateValidator(Addrs[1], Pks[1], newAmt)) - require.NoError(t, err) - require.NotNil(t, res) - - validatorUpdates := staking.EndBlocker(ctx, sk) - require.Equal(t, 2, len(validatorUpdates)) - validator, _ := sk.GetValidator(ctx, addr) - require.Equal(t, sdk.Unbonding, validator.Status) - - // 600 more blocks happened - height = int64(700) - ctx = ctx.WithBlockHeight(height) - - // validator added back in - delTokens := sdk.TokensFromConsensusPower(50) - res, err = sh(ctx, NewTestMsgDelegate(sdk.AccAddress(Addrs[2]), Addrs[0], delTokens)) - require.NoError(t, err) - require.NotNil(t, res) - - validatorUpdates = staking.EndBlocker(ctx, sk) - require.Equal(t, 2, len(validatorUpdates)) - validator, _ = sk.GetValidator(ctx, addr) - require.Equal(t, sdk.Bonded, validator.Status) - newPower := int64(150) - - // validator misses a block - keeper.HandleValidatorSignature(ctx, val.Address(), newPower, false) - height++ - - // shouldn't be jailed/kicked yet - validator, _ = sk.GetValidator(ctx, addr) - require.Equal(t, sdk.Bonded, validator.Status) - - // validator misses 500 more blocks, 501 total - latest := height - for ; height < latest+500; height++ { - ctx = ctx.WithBlockHeight(height) - keeper.HandleValidatorSignature(ctx, val.Address(), newPower, false) - } - - // should now be jailed & kicked - staking.EndBlocker(ctx, sk) - validator, _ = sk.GetValidator(ctx, addr) - require.Equal(t, sdk.Unbonding, validator.Status) - - // check all the signing information - signInfo, found := keeper.GetValidatorSigningInfo(ctx, consAddr) - require.True(t, found) - require.Equal(t, int64(0), signInfo.MissedBlocksCounter) - require.Equal(t, int64(0), signInfo.IndexOffset) - // array should be cleared - for offset := int64(0); offset < keeper.SignedBlocksWindow(ctx); offset++ { - missed := keeper.GetValidatorMissedBlockBitArray(ctx, consAddr, offset) - require.False(t, missed) - } - - // some blocks pass - height = int64(5000) - ctx = ctx.WithBlockHeight(height) - - // validator rejoins and starts signing again - sk.Unjail(ctx, consAddr) - keeper.HandleValidatorSignature(ctx, val.Address(), newPower, true) - height++ - - // validator should not be kicked since we reset counter/array when it was jailed - staking.EndBlocker(ctx, sk) - validator, _ = sk.GetValidator(ctx, addr) - require.Equal(t, sdk.Bonded, validator.Status) - - // validator misses 501 blocks - latest = height - for ; height < latest+501; height++ { - ctx = ctx.WithBlockHeight(height) - keeper.HandleValidatorSignature(ctx, val.Address(), newPower, false) - } - - // validator should now be jailed & kicked - staking.EndBlocker(ctx, sk) - validator, _ = sk.GetValidator(ctx, addr) - require.Equal(t, sdk.Unbonding, validator.Status) - + require.Equal(t, expTokens.Int64(), app.BankKeeper.GetBalance(ctx, bondPool.GetAddress(), app.StakingKeeper.BondDenom(ctx)).Amount.Int64()) } diff --git a/x/slashing/keeper/old_keeper_test.go b/x/slashing/keeper/old_keeper_test.go new file mode 100644 index 000000000000..4f4f555bbffc --- /dev/null +++ b/x/slashing/keeper/old_keeper_test.go @@ -0,0 +1,223 @@ +package keeper + +import ( + "testing" + "time" + + "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/slashing/types" + "github.com/cosmos/cosmos-sdk/x/staking" +) + +// Test a new validator entering the validator set +// Ensure that SigningInfo.StartHeight is set correctly +// and that they are not immediately jailed +func TestHandleNewValidator(t *testing.T) { + // initial setup + ctx, bk, sk, _, keeper := CreateTestInput(t, TestParams()) + addr, val := Addrs[0], Pks[0] + amt := sdk.TokensFromConsensusPower(100) + sh := staking.NewHandler(sk) + + // 1000 first blocks not a validator + ctx = ctx.WithBlockHeight(keeper.SignedBlocksWindow(ctx) + 1) + + // Validator created + res, err := sh(ctx, NewTestMsgCreateValidator(addr, val, amt)) + require.NoError(t, err) + require.NotNil(t, res) + + staking.EndBlocker(ctx, sk) + + require.Equal( + t, bk.GetAllBalances(ctx, sdk.AccAddress(addr)), + sdk.NewCoins(sdk.NewCoin(sk.GetParams(ctx).BondDenom, InitTokens.Sub(amt))), + ) + require.Equal(t, amt, sk.Validator(ctx, addr).GetBondedTokens()) + + // Now a validator, for two blocks + keeper.HandleValidatorSignature(ctx, val.Address(), 100, true) + ctx = ctx.WithBlockHeight(keeper.SignedBlocksWindow(ctx) + 2) + keeper.HandleValidatorSignature(ctx, val.Address(), 100, false) + + info, found := keeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) + require.True(t, found) + require.Equal(t, keeper.SignedBlocksWindow(ctx)+1, info.StartHeight) + require.Equal(t, int64(2), info.IndexOffset) + require.Equal(t, int64(1), info.MissedBlocksCounter) + require.Equal(t, time.Unix(0, 0).UTC(), info.JailedUntil) + + // validator should be bonded still, should not have been jailed or slashed + validator, _ := sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) + require.Equal(t, sdk.Bonded, validator.GetStatus()) + bondPool := sk.GetBondedPool(ctx) + expTokens := sdk.TokensFromConsensusPower(100) + require.Equal(t, expTokens.Int64(), bk.GetBalance(ctx, bondPool.GetAddress(), sk.BondDenom(ctx)).Amount.Int64()) +} + +// Test a jailed validator being "down" twice +// Ensure that they're only slashed once +func TestHandleAlreadyJailed(t *testing.T) { + + // initial setup + ctx, _, sk, _, keeper := CreateTestInput(t, types.DefaultParams()) + power := int64(100) + amt := sdk.TokensFromConsensusPower(power) + addr, val := Addrs[0], Pks[0] + sh := staking.NewHandler(sk) + res, err := sh(ctx, NewTestMsgCreateValidator(addr, val, amt)) + require.NoError(t, err) + require.NotNil(t, res) + + staking.EndBlocker(ctx, sk) + + // 1000 first blocks OK + height := int64(0) + for ; height < keeper.SignedBlocksWindow(ctx); height++ { + ctx = ctx.WithBlockHeight(height) + keeper.HandleValidatorSignature(ctx, val.Address(), power, true) + } + + // 501 blocks missed + for ; height < keeper.SignedBlocksWindow(ctx)+(keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx))+1; height++ { + ctx = ctx.WithBlockHeight(height) + keeper.HandleValidatorSignature(ctx, val.Address(), power, false) + } + + // end block + staking.EndBlocker(ctx, sk) + + // validator should have been jailed and slashed + validator, _ := sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) + require.Equal(t, sdk.Unbonding, validator.GetStatus()) + + // validator should have been slashed + resultingTokens := amt.Sub(sdk.TokensFromConsensusPower(1)) + require.Equal(t, resultingTokens, validator.GetTokens()) + + // another block missed + ctx = ctx.WithBlockHeight(height) + keeper.HandleValidatorSignature(ctx, val.Address(), power, false) + + // validator should not have been slashed twice + validator, _ = sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) + require.Equal(t, resultingTokens, validator.GetTokens()) + +} + +// Test a validator dipping in and out of the validator set +// Ensure that missed blocks are tracked correctly and that +// the start height of the signing info is reset correctly +func TestValidatorDippingInAndOut(t *testing.T) { + + // initial setup + // TestParams set the SignedBlocksWindow to 1000 and MaxMissedBlocksPerWindow to 500 + ctx, _, sk, _, keeper := CreateTestInput(t, TestParams()) + params := sk.GetParams(ctx) + params.MaxValidators = 1 + sk.SetParams(ctx, params) + power := int64(100) + amt := sdk.TokensFromConsensusPower(power) + addr, val := Addrs[0], Pks[0] + consAddr := sdk.ConsAddress(addr) + sh := staking.NewHandler(sk) + res, err := sh(ctx, NewTestMsgCreateValidator(addr, val, amt)) + require.NoError(t, err) + require.NotNil(t, res) + + staking.EndBlocker(ctx, sk) + + // 100 first blocks OK + height := int64(0) + for ; height < int64(100); height++ { + ctx = ctx.WithBlockHeight(height) + keeper.HandleValidatorSignature(ctx, val.Address(), power, true) + } + + // kick first validator out of validator set + newAmt := sdk.TokensFromConsensusPower(101) + res, err = sh(ctx, NewTestMsgCreateValidator(Addrs[1], Pks[1], newAmt)) + require.NoError(t, err) + require.NotNil(t, res) + + validatorUpdates := staking.EndBlocker(ctx, sk) + require.Equal(t, 2, len(validatorUpdates)) + validator, _ := sk.GetValidator(ctx, addr) + require.Equal(t, sdk.Unbonding, validator.Status) + + // 600 more blocks happened + height = int64(700) + ctx = ctx.WithBlockHeight(height) + + // validator added back in + delTokens := sdk.TokensFromConsensusPower(50) + res, err = sh(ctx, NewTestMsgDelegate(sdk.AccAddress(Addrs[2]), Addrs[0], delTokens)) + require.NoError(t, err) + require.NotNil(t, res) + + validatorUpdates = staking.EndBlocker(ctx, sk) + require.Equal(t, 2, len(validatorUpdates)) + validator, _ = sk.GetValidator(ctx, addr) + require.Equal(t, sdk.Bonded, validator.Status) + newPower := int64(150) + + // validator misses a block + keeper.HandleValidatorSignature(ctx, val.Address(), newPower, false) + height++ + + // shouldn't be jailed/kicked yet + validator, _ = sk.GetValidator(ctx, addr) + require.Equal(t, sdk.Bonded, validator.Status) + + // validator misses 500 more blocks, 501 total + latest := height + for ; height < latest+500; height++ { + ctx = ctx.WithBlockHeight(height) + keeper.HandleValidatorSignature(ctx, val.Address(), newPower, false) + } + + // should now be jailed & kicked + staking.EndBlocker(ctx, sk) + validator, _ = sk.GetValidator(ctx, addr) + require.Equal(t, sdk.Unbonding, validator.Status) + + // check all the signing information + signInfo, found := keeper.GetValidatorSigningInfo(ctx, consAddr) + require.True(t, found) + require.Equal(t, int64(0), signInfo.MissedBlocksCounter) + require.Equal(t, int64(0), signInfo.IndexOffset) + // array should be cleared + for offset := int64(0); offset < keeper.SignedBlocksWindow(ctx); offset++ { + missed := keeper.GetValidatorMissedBlockBitArray(ctx, consAddr, offset) + require.False(t, missed) + } + + // some blocks pass + height = int64(5000) + ctx = ctx.WithBlockHeight(height) + + // validator rejoins and starts signing again + sk.Unjail(ctx, consAddr) + keeper.HandleValidatorSignature(ctx, val.Address(), newPower, true) + height++ + + // validator should not be kicked since we reset counter/array when it was jailed + staking.EndBlocker(ctx, sk) + validator, _ = sk.GetValidator(ctx, addr) + require.Equal(t, sdk.Bonded, validator.Status) + + // validator misses 501 blocks + latest = height + for ; height < latest+501; height++ { + ctx = ctx.WithBlockHeight(height) + keeper.HandleValidatorSignature(ctx, val.Address(), newPower, false) + } + + // validator should now be jailed & kicked + staking.EndBlocker(ctx, sk) + validator, _ = sk.GetValidator(ctx, addr) + require.Equal(t, sdk.Unbonding, validator.Status) + +} From fb42f8b2a0f4e787e51dd6b7dfb1beb7131667c6 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Mon, 2 Mar 2020 15:50:20 -0500 Subject: [PATCH 331/529] types updates --- x/gov/common_test.go | 6 ----- x/gov/genesis_test.go | 4 +-- x/gov/keeper/common_test.go | 12 ++------- x/gov/keeper/proposal_test.go | 23 +++++++--------- x/gov/keeper/querier_test.go | 50 ++++++++++++++++++++--------------- x/gov/types/deposit.go | 22 ++++++++++----- x/gov/types/genesis.go | 16 ++++++----- x/gov/types/proposal.go | 15 +++++++++++ x/gov/types/vote.go | 24 +++++++++++------ 9 files changed, 99 insertions(+), 73 deletions(-) diff --git a/x/gov/common_test.go b/x/gov/common_test.go index 31d4dd168f3a..acb8e8cec4cb 100644 --- a/x/gov/common_test.go +++ b/x/gov/common_test.go @@ -94,9 +94,3 @@ func createValidators(t *testing.T, stakingHandler sdk.Handler, ctx sdk.Context, require.NotNil(t, res) } } - -// ProposalEqual checks if two proposals are equal (note: slow, for tests only) -func ProposalEqual(proposalA types.Proposal, proposalB types.Proposal) bool { - return bytes.Equal(types.ModuleCdc.MustMarshalBinaryBare(proposalA), - types.ModuleCdc.MustMarshalBinaryBare(proposalB)) -} diff --git a/x/gov/genesis_test.go b/x/gov/genesis_test.go index 52ee0c0e1868..91cddf7954d3 100644 --- a/x/gov/genesis_test.go +++ b/x/gov/genesis_test.go @@ -124,7 +124,7 @@ func TestEqualProposals(t *testing.T) { // They are similar but their IDs should be different require.NotEqual(t, proposal1, proposal2) - require.False(t, ProposalEqual(proposal1, proposal2)) + require.NotEqual(t, proposal1, proposal2) // Now create two genesis blocks state1 := gov.GenesisState{Proposals: []gov.Proposal{proposal1}} @@ -136,7 +136,7 @@ func TestEqualProposals(t *testing.T) { proposal1.ProposalID = 55 proposal2.ProposalID = 55 require.Equal(t, proposal1, proposal1) - require.True(t, ProposalEqual(proposal1, proposal2)) + require.Equal(t, proposal1, proposal2) // Reassign proposals into state state1.Proposals[0] = proposal1 diff --git a/x/gov/keeper/common_test.go b/x/gov/keeper/common_test.go index 24ae48992f35..e7e9747a07ac 100644 --- a/x/gov/keeper/common_test.go +++ b/x/gov/keeper/common_test.go @@ -1,10 +1,8 @@ package keeper_test import ( - "bytes" - "github.com/cosmos/cosmos-sdk/simapp" - "github.com/cosmos/cosmos-sdk/simapp/codec" + simappcodec "github.com/cosmos/cosmos-sdk/simapp/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/cosmos/cosmos-sdk/x/staking" @@ -14,18 +12,12 @@ var ( TestProposal = types.NewTextProposal("Test", "description") ) -// ProposalEqual checks if two proposals are equal (note: slow, for tests only) -func ProposalEqual(proposalA types.Proposal, proposalB types.Proposal) bool { - return bytes.Equal(types.ModuleCdc.MustMarshalBinaryBare(proposalA), - types.ModuleCdc.MustMarshalBinaryBare(proposalB)) -} - func createValidators(ctx sdk.Context, app *simapp.SimApp, powers []int64) ([]sdk.AccAddress, []sdk.ValAddress) { addrs := simapp.AddTestAddrsIncremental(app, ctx, 5, sdk.NewInt(30000000)) valAddrs := simapp.ConvertAddrsToValAddrs(addrs) pks := simapp.CreateTestPubKeys(5) - appCodec := codec.NewAppCodec(app.Codec()) + appCodec := simappcodec.NewAppCodec(app.Codec()) app.StakingKeeper = staking.NewKeeper( appCodec, app.GetKey(staking.StoreKey), diff --git a/x/gov/keeper/proposal_test.go b/x/gov/keeper/proposal_test.go index 0ae4c50a2115..54ef390c84d5 100644 --- a/x/gov/keeper/proposal_test.go +++ b/x/gov/keeper/proposal_test.go @@ -9,7 +9,6 @@ import ( "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" - "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/gov/types" @@ -27,7 +26,7 @@ func TestGetSetProposal(t *testing.T) { gotProposal, ok := app.GovKeeper.GetProposal(ctx, proposalID) require.True(t, ok) - require.True(t, ProposalEqual(proposal, gotProposal)) + require.Equal(t, proposal.String(), gotProposal.String()) } func TestActivateVotingPeriod(t *testing.T) { @@ -90,22 +89,20 @@ func (invalidProposalValidation) ValidateBasic() error { return errors.New("invalid proposal") } -func registerTestCodec(cdc *codec.Codec) { - cdc.RegisterConcrete(validProposal{}, "test/validproposal", nil) - cdc.RegisterConcrete(invalidProposalTitle1{}, "test/invalidproposalt1", nil) - cdc.RegisterConcrete(invalidProposalTitle2{}, "test/invalidproposalt2", nil) - cdc.RegisterConcrete(invalidProposalDesc1{}, "test/invalidproposald1", nil) - cdc.RegisterConcrete(invalidProposalDesc2{}, "test/invalidproposald2", nil) - cdc.RegisterConcrete(invalidProposalRoute{}, "test/invalidproposalr", nil) - cdc.RegisterConcrete(invalidProposalValidation{}, "test/invalidproposalv", nil) -} +// func registerTestCodec(cdc *codec.Codec) { +// cdc.RegisterConcrete(validProposal{}, "test/validproposal", nil) +// cdc.RegisterConcrete(invalidProposalTitle1{}, "test/invalidproposalt1", nil) +// cdc.RegisterConcrete(invalidProposalTitle2{}, "test/invalidproposalt2", nil) +// cdc.RegisterConcrete(invalidProposalDesc1{}, "test/invalidproposald1", nil) +// cdc.RegisterConcrete(invalidProposalDesc2{}, "test/invalidproposald2", nil) +// cdc.RegisterConcrete(invalidProposalRoute{}, "test/invalidproposalr", nil) +// cdc.RegisterConcrete(invalidProposalValidation{}, "test/invalidproposalv", nil) +// } func TestSubmitProposal(t *testing.T) { app := simapp.Setup(false) ctx := app.BaseApp.NewContext(false, abci.Header{}) - registerTestCodec(app.Codec()) - testCases := []struct { content types.Content expectedErr error diff --git a/x/gov/keeper/querier_test.go b/x/gov/keeper/querier_test.go index c4745b1eac84..27a1e7275cc8 100644 --- a/x/gov/keeper/querier_test.go +++ b/x/gov/keeper/querier_test.go @@ -7,10 +7,11 @@ import ( "time" "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermit/abci/types" + abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/simapp" + simappcodec "github.com/cosmos/cosmos-sdk/simapp/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/gov/keeper" "github.com/cosmos/cosmos-sdk/x/gov/types" @@ -146,6 +147,7 @@ func getQueriedVotes(t *testing.T, ctx sdk.Context, cdc codec.Marshaler, querier func TestQueries(t *testing.T) { app := simapp.Setup(false) ctx := app.BaseApp.NewContext(false, abci.Header{}) + appCodec := simappcodec.NewAppCodec(app.Codec()) querier := keeper.NewQuerier(app.GovKeeper) @@ -156,7 +158,7 @@ func TestQueries(t *testing.T) { tp := TestProposal - depositParams, _, _ := getQueriedParams(t, ctx, app.Codec(), querier) + depositParams, _, _ := getQueriedParams(t, ctx, appCodec, querier) // TestAddrs[0] proposes (and deposits) proposals #1 and #2 proposal1, err := app.GovKeeper.SubmitProposal(ctx, tp) @@ -204,35 +206,35 @@ func TestQueries(t *testing.T) { deposit5.Amount = deposit5.Amount.Add(deposit3.Amount...) // check deposits on proposal1 match individual deposits - deposits := getQueriedDeposits(t, ctx, app.Codec(), querier, proposal1.ProposalID) + deposits := getQueriedDeposits(t, ctx, appCodec, querier, proposal1.ProposalID) require.Len(t, deposits, 1) require.Equal(t, deposit1, deposits[0]) - deposit := getQueriedDeposit(t, ctx, app.Codec(), querier, proposal1.ProposalID, TestAddrs[0]) + deposit := getQueriedDeposit(t, ctx, appCodec, querier, proposal1.ProposalID, TestAddrs[0]) require.Equal(t, deposit1, deposit) // check deposits on proposal2 match individual deposits - deposits = getQueriedDeposits(t, ctx, app.Codec(), querier, proposal2.ProposalID) + deposits = getQueriedDeposits(t, ctx, appCodec, querier, proposal2.ProposalID) require.Len(t, deposits, 2) // NOTE order of deposits is determined by the addresses require.Equal(t, deposit2, deposits[0]) require.Equal(t, deposit4, deposits[1]) // check deposits on proposal3 match individual deposits - deposits = getQueriedDeposits(t, ctx, app.Codec(), querier, proposal3.ProposalID) + deposits = getQueriedDeposits(t, ctx, appCodec, querier, proposal3.ProposalID) require.Len(t, deposits, 1) require.Equal(t, deposit5, deposits[0]) - deposit = getQueriedDeposit(t, ctx, app.Codec(), querier, proposal3.ProposalID, TestAddrs[1]) + deposit = getQueriedDeposit(t, ctx, appCodec, querier, proposal3.ProposalID, TestAddrs[1]) require.Equal(t, deposit5, deposit) // Only proposal #1 should be in types.Deposit Period - proposals := getQueriedProposals(t, ctx, app.Codec(), querier, nil, nil, types.StatusDepositPeriod, 1, 0) + proposals := getQueriedProposals(t, ctx, appCodec, querier, nil, nil, types.StatusDepositPeriod, 1, 0) require.Len(t, proposals, 1) require.Equal(t, proposal1, proposals[0]) // Only proposals #2 and #3 should be in Voting Period - proposals = getQueriedProposals(t, ctx, app.Codec(), querier, nil, nil, types.StatusVotingPeriod, 1, 0) + proposals = getQueriedProposals(t, ctx, appCodec, querier, nil, nil, types.StatusVotingPeriod, 1, 0) require.Len(t, proposals, 2) require.Equal(t, proposal2, proposals[0]) require.Equal(t, proposal3, proposals[1]) @@ -248,56 +250,60 @@ func TestQueries(t *testing.T) { app.GovKeeper.SetVote(ctx, vote3) // Test query voted by TestAddrs[0] - proposals = getQueriedProposals(t, ctx, app.Codec(), querier, nil, TestAddrs[0], types.StatusNil, 1, 0) + proposals = getQueriedProposals(t, ctx, appCodec, querier, nil, TestAddrs[0], types.StatusNil, 1, 0) require.Equal(t, proposal2, proposals[0]) require.Equal(t, proposal3, proposals[1]) // Test query votes on types.Proposal 2 - votes := getQueriedVotes(t, ctx, app.Codec(), querier, proposal2.ProposalID, 1, 0) + votes := getQueriedVotes(t, ctx, appCodec, querier, proposal2.ProposalID, 1, 0) require.Len(t, votes, 1) require.Equal(t, vote1, votes[0]) - vote := getQueriedVote(t, ctx, app.Codec(), querier, proposal2.ProposalID, TestAddrs[0]) + vote := getQueriedVote(t, ctx, appCodec, querier, proposal2.ProposalID, TestAddrs[0]) require.Equal(t, vote1, vote) // Test query votes on types.Proposal 3 - votes = getQueriedVotes(t, ctx, app.Codec(), querier, proposal3.ProposalID, 1, 0) + votes = getQueriedVotes(t, ctx, appCodec, querier, proposal3.ProposalID, 1, 0) require.Len(t, votes, 2) require.Equal(t, vote2, votes[0]) require.Equal(t, vote3, votes[1]) // Test query all proposals - proposals = getQueriedProposals(t, ctx, app.Codec(), querier, nil, nil, types.StatusNil, 1, 0) + proposals = getQueriedProposals(t, ctx, appCodec, querier, nil, nil, types.StatusNil, 1, 0) require.Equal(t, proposal1, proposals[0]) require.Equal(t, proposal2, proposals[1]) require.Equal(t, proposal3, proposals[2]) // Test query voted by TestAddrs[1] - proposals = getQueriedProposals(t, ctx, app.Codec(), querier, nil, TestAddrs[1], types.StatusNil, 1, 0) + proposals = getQueriedProposals(t, ctx, appCodec, querier, nil, TestAddrs[1], types.StatusNil, 1, 0) require.Equal(t, proposal3.ProposalID, proposals[0].ProposalID) // Test query deposited by TestAddrs[0] - proposals = getQueriedProposals(t, ctx, app.Codec(), querier, TestAddrs[0], nil, types.StatusNil, 1, 0) + proposals = getQueriedProposals(t, ctx, appCodec, querier, TestAddrs[0], nil, types.StatusNil, 1, 0) require.Equal(t, proposal1.ProposalID, proposals[0].ProposalID) // Test query deposited by addr2 - proposals = getQueriedProposals(t, ctx, app.Codec(), querier, TestAddrs[1], nil, types.StatusNil, 1, 0) + proposals = getQueriedProposals(t, ctx, appCodec, querier, TestAddrs[1], nil, types.StatusNil, 1, 0) require.Equal(t, proposal2.ProposalID, proposals[0].ProposalID) require.Equal(t, proposal3.ProposalID, proposals[1].ProposalID) // Test query voted AND deposited by addr1 - proposals = getQueriedProposals(t, ctx, app.Codec(), querier, TestAddrs[0], TestAddrs[0], types.StatusNil, 1, 0) + proposals = getQueriedProposals(t, ctx, appCodec, querier, TestAddrs[0], TestAddrs[0], types.StatusNil, 1, 0) require.Equal(t, proposal2.ProposalID, proposals[0].ProposalID) } func TestPaginatedVotesQuery(t *testing.T) { app := simapp.Setup(false) ctx := app.BaseApp.NewContext(false, abci.Header{}) + appCodec := simappcodec.NewAppCodec(app.Codec()) proposal := types.Proposal{ - ProposalID: 100, - Status: types.StatusVotingPeriod, + ProposalBase: types.ProposalBase{ + ProposalID: 100, + Status: types.StatusVotingPeriod, + }, } + app.GovKeeper.SetProposal(ctx, proposal) votes := make([]types.Vote, 20) @@ -317,7 +323,7 @@ func TestPaginatedVotesQuery(t *testing.T) { querier := keeper.NewQuerier(app.GovKeeper) // keeper preserves consistent order for each query, but this is not the insertion order - all := getQueriedVotes(t, ctx, app.Codec(), querier, proposal.ProposalID, 1, 0) + all := getQueriedVotes(t, ctx, appCodec, querier, proposal.ProposalID, 1, 0) require.Equal(t, len(all), len(votes)) type testCase struct { @@ -351,7 +357,7 @@ func TestPaginatedVotesQuery(t *testing.T) { } { tc := tc t.Run(tc.description, func(t *testing.T) { - votes := getQueriedVotes(t, ctx, app.Codec(), querier, proposal.ProposalID, tc.page, tc.limit) + votes := getQueriedVotes(t, ctx, appCodec, querier, proposal.ProposalID, tc.page, tc.limit) require.Equal(t, len(tc.votes), len(votes)) for i := range votes { require.Equal(t, tc.votes[i], votes[i]) diff --git a/x/gov/types/deposit.go b/x/gov/types/deposit.go index 58d2540eca86..d9f72a83fd25 100644 --- a/x/gov/types/deposit.go +++ b/x/gov/types/deposit.go @@ -21,6 +21,21 @@ func (d Deposit) String() string { // Deposits is a collection of Deposit objects type Deposits []Deposit +// Equal returns true if two slices (order-dependant) of deposits are equal. +func (d Deposits) Equal(other Deposits) bool { + if len(d) != len(other) { + return false + } + + for i, deposit := range d { + if !deposit.Equal(other[i]) { + return false + } + } + + return true +} + func (d Deposits) String() string { if len(d) == 0 { return "[]" @@ -32,12 +47,7 @@ func (d Deposits) String() string { return out } -// Equals returns whether two deposits are equal. -func (d Deposit) Equals(comp Deposit) bool { - return d.Depositor.Equals(comp.Depositor) && d.ProposalID == comp.ProposalID && d.Amount.IsEqual(comp.Amount) -} - // Empty returns whether a deposit is empty. func (d Deposit) Empty() bool { - return d.Equals(Deposit{}) + return d.Equal(Deposit{}) } diff --git a/x/gov/types/genesis.go b/x/gov/types/genesis.go index 858bc85f867f..e38b0213eeda 100644 --- a/x/gov/types/genesis.go +++ b/x/gov/types/genesis.go @@ -37,14 +37,18 @@ func DefaultGenesisState() GenesisState { ) } +func (data GenesisState) Equal(other GenesisState) bool { + return data.Deposits.Equal(other.Deposits) && + data.Votes.Equal(other.Votes) && + data.Proposals.Equal(other.Proposals) && + data.DepositParams.Equal(other.DepositParams) && + data.TallyParams.Equal(other.TallyParams) && + data.VotingParams.Equal(other.VotingParams) +} + // IsEmpty returns true if a GenesisState is empty func (data GenesisState) IsEmpty() bool { - return data.Deposits == nil && - data.Votes == nil && - data.Proposals == nil && - data.DepositParams.Equal(DepositParams{}) && - data.TallyParams.Equal(TallyParams{}) && - data.VotingParams.Equal(VotingParams{}) + return data.Equal(GenesisState{}) } // ValidateGenesis checks if parameters are within valid ranges diff --git a/x/gov/types/proposal.go b/x/gov/types/proposal.go index e734ad59ac7d..2ba08980ebd3 100644 --- a/x/gov/types/proposal.go +++ b/x/gov/types/proposal.go @@ -46,6 +46,21 @@ func (p Proposal) String() string { // Proposals is an array of proposal type Proposals []Proposal +// Equal returns true if two slices (order-dependant) of proposals are equal. +func (p Proposals) Equal(other Proposals) bool { + if len(p) != len(other) { + return false + } + + for i, proposal := range p { + if !proposal.Equal(other[i]) { + return false + } + } + + return true +} + // String implements stringer interface func (p Proposals) String() string { out := "ID - (Status) [Type] Title\n" diff --git a/x/gov/types/vote.go b/x/gov/types/vote.go index 8a2f0df71cad..13eb41f75d74 100644 --- a/x/gov/types/vote.go +++ b/x/gov/types/vote.go @@ -22,6 +22,21 @@ func (v Vote) String() string { // Votes is a collection of Vote objects type Votes []Vote +// Equal returns true if two slices (order-dependant) of votes are equal. +func (v Votes) Equal(other Votes) bool { + if len(v) != len(other) { + return false + } + + for i, vote := range v { + if !vote.Equal(other[i]) { + return false + } + } + + return true +} + func (v Votes) String() string { if len(v) == 0 { return "[]" @@ -33,16 +48,9 @@ func (v Votes) String() string { return out } -// Equals returns whether two votes are equal. -func (v Vote) Equals(comp Vote) bool { - return v.Voter.Equals(comp.Voter) && - v.ProposalID == comp.ProposalID && - v.Option == comp.Option -} - // Empty returns whether a vote is empty. func (v Vote) Empty() bool { - return v.Equals(Vote{}) + return v.Equal(Vote{}) } // VoteOptionFromString returns a VoteOption from a string. It returns an error From fe7b02231e4ad95f9e39e7ac04a8dca98df7fb4f Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Mon, 2 Mar 2020 16:06:35 -0500 Subject: [PATCH 332/529] Update handler --- x/gov/abci_test.go | 16 +++++++++++----- x/gov/handler.go | 8 ++++---- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/x/gov/abci_test.go b/x/gov/abci_test.go index 79db8f81af87..c82019be7705 100644 --- a/x/gov/abci_test.go +++ b/x/gov/abci_test.go @@ -8,6 +8,7 @@ import ( abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/simapp" + simappcodec "github.com/cosmos/cosmos-sdk/simapp/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/gov" "github.com/cosmos/cosmos-sdk/x/staking" @@ -27,11 +28,12 @@ func TestTickExpiredDepositPeriod(t *testing.T) { require.False(t, inactiveQueue.Valid()) inactiveQueue.Close() - newProposalMsg := gov.NewMsgSubmitProposal( + newProposalMsg, err := simappcodec.NewMsgSubmitProposal( gov.ContentFromProposalType("test", "test", gov.ProposalTypeText), sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 5)}, addrs[0], ) + require.NoError(t, err) res, err := govHandler(ctx, newProposalMsg) require.NoError(t, err) @@ -78,11 +80,12 @@ func TestTickMultipleExpiredDepositPeriod(t *testing.T) { require.False(t, inactiveQueue.Valid()) inactiveQueue.Close() - newProposalMsg := gov.NewMsgSubmitProposal( + newProposalMsg, err := simappcodec.NewMsgSubmitProposal( gov.ContentFromProposalType("test", "test", gov.ProposalTypeText), sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 5)}, addrs[0], ) + require.NoError(t, err) res, err := govHandler(ctx, newProposalMsg) require.NoError(t, err) @@ -100,11 +103,12 @@ func TestTickMultipleExpiredDepositPeriod(t *testing.T) { require.False(t, inactiveQueue.Valid()) inactiveQueue.Close() - newProposalMsg2 := gov.NewMsgSubmitProposal( + newProposalMsg2, err := simappcodec.NewMsgSubmitProposal( gov.ContentFromProposalType("test2", "test2", gov.ProposalTypeText), sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 5)}, addrs[0], ) + require.NoError(t, err) res, err = govHandler(ctx, newProposalMsg2) require.NoError(t, err) @@ -156,11 +160,12 @@ func TestTickPassedDepositPeriod(t *testing.T) { require.False(t, activeQueue.Valid()) activeQueue.Close() - newProposalMsg := gov.NewMsgSubmitProposal( + newProposalMsg, err := simappcodec.NewMsgSubmitProposal( gov.ContentFromProposalType("test2", "test2", gov.ProposalTypeText), sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 5)}, addrs[0], ) + require.NoError(t, err) res, err := govHandler(ctx, newProposalMsg) require.NoError(t, err) @@ -211,7 +216,8 @@ func TestTickPassedVotingPeriod(t *testing.T) { activeQueue.Close() proposalCoins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(5))} - newProposalMsg := gov.NewMsgSubmitProposal(TestProposal, proposalCoins, addrs[0]) + newProposalMsg, err := simappcodec.NewMsgSubmitProposal(TestProposal, proposalCoins, addrs[0]) + require.NoError(t, err) res, err := govHandler(ctx, newProposalMsg) require.NoError(t, err) diff --git a/x/gov/handler.go b/x/gov/handler.go index 4e4aee2c5334..27945d928de8 100644 --- a/x/gov/handler.go +++ b/x/gov/handler.go @@ -30,12 +30,12 @@ func NewHandler(keeper Keeper) sdk.Handler { } func handleMsgSubmitProposal(ctx sdk.Context, keeper Keeper, msg MsgSubmitProposal) (*sdk.Result, error) { - proposal, err := keeper.SubmitProposal(ctx, msg.Content) + proposal, err := keeper.SubmitProposal(ctx, msg.GetContent()) if err != nil { return nil, err } - votingStarted, err := keeper.AddDeposit(ctx, proposal.ProposalID, msg.Proposer, msg.InitialDeposit) + votingStarted, err := keeper.AddDeposit(ctx, proposal.ProposalID, msg.GetProposer(), msg.GetInitialDeposit()) if err != nil { return nil, err } @@ -44,11 +44,11 @@ func handleMsgSubmitProposal(ctx sdk.Context, keeper Keeper, msg MsgSubmitPropos sdk.NewEvent( sdk.EventTypeMessage, sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), - sdk.NewAttribute(sdk.AttributeKeySender, msg.Proposer.String()), + sdk.NewAttribute(sdk.AttributeKeySender, msg.GetProposer().String()), ), ) - submitEvent := sdk.NewEvent(types.EventTypeSubmitProposal, sdk.NewAttribute(types.AttributeKeyProposalType, msg.Content.ProposalType())) + submitEvent := sdk.NewEvent(types.EventTypeSubmitProposal, sdk.NewAttribute(types.AttributeKeyProposalType, msg.GetContent().ProposalType())) if votingStarted { submitEvent = submitEvent.AppendAttributes( sdk.NewAttribute(types.AttributeKeyVotingPeriodStart, fmt.Sprintf("%d", proposal.ProposalID)), From 833368cc7484bf8d40153181429e28f074ae2011 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Mon, 2 Mar 2020 16:29:10 -0500 Subject: [PATCH 333/529] reintroduce old MsgSubmitProposal type --- x/gov/alias.go | 2 + x/gov/handler.go | 4 +- x/gov/keeper/querier_test.go | 12 ++--- x/gov/types/msgs.go | 63 +++++++++++++++++++++++++- x/upgrade/types/types.pb.go | 85 +++++++++++++++++++++++++----------- x/upgrade/types/types.proto | 2 + 6 files changed, 132 insertions(+), 36 deletions(-) diff --git a/x/gov/alias.go b/x/gov/alias.go index 86828db77580..aad984c2c1f0 100644 --- a/x/gov/alias.go +++ b/x/gov/alias.go @@ -83,6 +83,7 @@ var ( SplitKeyDeposit = types.SplitKeyDeposit SplitKeyVote = types.SplitKeyVote NewMsgSubmitProposalBase = types.NewMsgSubmitProposalBase + NewMsgSubmitProposal = types.NewMsgSubmitProposal NewMsgDeposit = types.NewMsgDeposit NewMsgVote = types.NewMsgVote ParamKeyTable = types.ParamKeyTable @@ -131,6 +132,7 @@ type ( Deposit = types.Deposit Deposits = types.Deposits GenesisState = types.GenesisState + MsgSubmitProposalI = types.MsgSubmitProposalI MsgSubmitProposal = types.MsgSubmitProposal MsgSubmitProposalBase = types.MsgSubmitProposalBase MsgDeposit = types.MsgDeposit diff --git a/x/gov/handler.go b/x/gov/handler.go index 27945d928de8..21693d943884 100644 --- a/x/gov/handler.go +++ b/x/gov/handler.go @@ -17,7 +17,7 @@ func NewHandler(keeper Keeper) sdk.Handler { case MsgDeposit: return handleMsgDeposit(ctx, keeper, msg) - case MsgSubmitProposal: + case MsgSubmitProposalI: return handleMsgSubmitProposal(ctx, keeper, msg) case MsgVote: @@ -29,7 +29,7 @@ func NewHandler(keeper Keeper) sdk.Handler { } } -func handleMsgSubmitProposal(ctx sdk.Context, keeper Keeper, msg MsgSubmitProposal) (*sdk.Result, error) { +func handleMsgSubmitProposal(ctx sdk.Context, keeper Keeper, msg MsgSubmitProposalI) (*sdk.Result, error) { proposal, err := keeper.SubmitProposal(ctx, msg.GetContent()) if err != nil { return nil, err diff --git a/x/gov/keeper/querier_test.go b/x/gov/keeper/querier_test.go index 27a1e7275cc8..918f054a754d 100644 --- a/x/gov/keeper/querier_test.go +++ b/x/gov/keeper/querier_test.go @@ -19,7 +19,7 @@ import ( const custom = "custom" -func getQueriedParams(t *testing.T, ctx sdk.Context, cdc codec.Marshaler, querier sdk.Querier) (types.DepositParams, types.VotingParams, types.TallyParams) { +func getQueriedParams(t *testing.T, ctx sdk.Context, cdc codec.JSONMarshaler, querier sdk.Querier) (types.DepositParams, types.VotingParams, types.TallyParams) { query := abci.RequestQuery{ Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryParams, types.ParamDeposit}, "/"), Data: []byte{}, @@ -60,7 +60,7 @@ func getQueriedParams(t *testing.T, ctx sdk.Context, cdc codec.Marshaler, querie } func getQueriedProposals( - t *testing.T, ctx sdk.Context, cdc codec.Marshaler, querier sdk.Querier, + t *testing.T, ctx sdk.Context, cdc codec.JSONMarshaler, querier sdk.Querier, depositor, voter sdk.AccAddress, status types.ProposalStatus, page, limit int, ) []types.Proposal { @@ -79,7 +79,7 @@ func getQueriedProposals( return proposals } -func getQueriedDeposit(t *testing.T, ctx sdk.Context, cdc codec.Marshaler, querier sdk.Querier, proposalID uint64, depositor sdk.AccAddress) types.Deposit { +func getQueriedDeposit(t *testing.T, ctx sdk.Context, cdc codec.JSONMarshaler, querier sdk.Querier, proposalID uint64, depositor sdk.AccAddress) types.Deposit { query := abci.RequestQuery{ Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryDeposit}, "/"), Data: cdc.MustMarshalJSON(types.NewQueryDepositParams(proposalID, depositor)), @@ -95,7 +95,7 @@ func getQueriedDeposit(t *testing.T, ctx sdk.Context, cdc codec.Marshaler, queri return deposit } -func getQueriedDeposits(t *testing.T, ctx sdk.Context, cdc codec.Marshaler, querier sdk.Querier, proposalID uint64) []types.Deposit { +func getQueriedDeposits(t *testing.T, ctx sdk.Context, cdc codec.JSONMarshaler, querier sdk.Querier, proposalID uint64) []types.Deposit { query := abci.RequestQuery{ Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryDeposits}, "/"), Data: cdc.MustMarshalJSON(types.NewQueryProposalParams(proposalID)), @@ -111,7 +111,7 @@ func getQueriedDeposits(t *testing.T, ctx sdk.Context, cdc codec.Marshaler, quer return deposits } -func getQueriedVote(t *testing.T, ctx sdk.Context, cdc codec.Marshaler, querier sdk.Querier, proposalID uint64, voter sdk.AccAddress) types.Vote { +func getQueriedVote(t *testing.T, ctx sdk.Context, cdc codec.JSONMarshaler, querier sdk.Querier, proposalID uint64, voter sdk.AccAddress) types.Vote { query := abci.RequestQuery{ Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryVote}, "/"), Data: cdc.MustMarshalJSON(types.NewQueryVoteParams(proposalID, voter)), @@ -127,7 +127,7 @@ func getQueriedVote(t *testing.T, ctx sdk.Context, cdc codec.Marshaler, querier return vote } -func getQueriedVotes(t *testing.T, ctx sdk.Context, cdc codec.Marshaler, querier sdk.Querier, +func getQueriedVotes(t *testing.T, ctx sdk.Context, cdc codec.JSONMarshaler, querier sdk.Querier, proposalID uint64, page, limit int) []types.Vote { query := abci.RequestQuery{ Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryVote}, "/"), diff --git a/x/gov/types/msgs.go b/x/gov/types/msgs.go index eb0343902303..55e19e675e3f 100644 --- a/x/gov/types/msgs.go +++ b/x/gov/types/msgs.go @@ -16,10 +16,10 @@ const ( var _, _, _ sdk.Msg = MsgSubmitProposalBase{}, MsgDeposit{}, MsgVote{} -// MsgSubmitProposal defines the specific interface a concrete message must +// MsgSubmitProposalI defines the specific interface a concrete message must // implement in order to process governance proposals. The concrete MsgSubmitProposal // must be defined at the application-level. -type MsgSubmitProposal interface { +type MsgSubmitProposalI interface { sdk.Msg GetContent() Content @@ -155,3 +155,62 @@ func (msg MsgVote) GetSignBytes() []byte { func (msg MsgVote) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.Voter} } + +// --------------------------------------------------------------------------- +// Deprecated +// +// TODO: Remove once client-side Protobuf migration has been completed. +// --------------------------------------------------------------------------- + +// MsgSubmitProposal defines a (deprecated) message to create/submit a governance +// proposal. +// +// TODO: Remove once client-side Protobuf migration has been completed. +type MsgSubmitProposal struct { + Content Content `json:"content" yaml:"content"` + InitialDeposit sdk.Coins `json:"initial_deposit" yaml:"initial_deposit"` // Initial deposit paid by sender. Must be strictly positive + Proposer sdk.AccAddress `json:"proposer" yaml:"proposer"` // Address of the proposer +} + +// NewMsgSubmitProposal returns a (deprecated) MsgSubmitProposal message. +// +// TODO: Remove once client-side Protobuf migration has been completed. +func NewMsgSubmitProposal(content Content, initialDeposit sdk.Coins, proposer sdk.AccAddress) MsgSubmitProposal { + return MsgSubmitProposal{content, initialDeposit, proposer} +} + +// ValidateBasic implements Msg +func (msg MsgSubmitProposal) ValidateBasic() error { + if msg.Content == nil { + return sdkerrors.Wrap(ErrInvalidProposalContent, "missing content") + } + if msg.Proposer.Empty() { + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Proposer.String()) + } + if !msg.InitialDeposit.IsValid() { + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, msg.InitialDeposit.String()) + } + if msg.InitialDeposit.IsAnyNegative() { + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, msg.InitialDeposit.String()) + } + if !IsValidProposalType(msg.Content.ProposalType()) { + return sdkerrors.Wrap(ErrInvalidProposalType, msg.Content.ProposalType()) + } + + return msg.Content.ValidateBasic() +} + +// GetSignBytes implements Msg +func (msg MsgSubmitProposal) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(msg) + return sdk.MustSortJSON(bz) +} + +// GetSigners implements Msg +func (msg MsgSubmitProposal) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Proposer} +} + +// nolint +func (msg MsgSubmitProposal) Route() string { return RouterKey } +func (msg MsgSubmitProposal) Type() string { return TypeMsgSubmitProposal } diff --git a/x/upgrade/types/types.pb.go b/x/upgrade/types/types.pb.go index e6c317700c82..f8c8f1ffd974 100644 --- a/x/upgrade/types/types.pb.go +++ b/x/upgrade/types/types.pb.go @@ -164,33 +164,66 @@ func init() { func init() { proto.RegisterFile("x/upgrade/types/types.proto", fileDescriptor_2a308fd9dd71aff8) } var fileDescriptor_2a308fd9dd71aff8 = []byte{ - // 376 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x52, 0x31, 0x6f, 0xe2, 0x30, - 0x18, 0x8d, 0x8f, 0x1c, 0x3a, 0xcc, 0x66, 0x9d, 0x8e, 0x88, 0x13, 0x4e, 0xc4, 0x70, 0x62, 0xb8, - 0x73, 0x74, 0xdc, 0x70, 0xa7, 0x1b, 0xe9, 0x5e, 0xa1, 0xb4, 0x5d, 0x2a, 0x55, 0xc8, 0x24, 0x26, - 0xb1, 0x48, 0x62, 0x2b, 0x36, 0x2d, 0x6c, 0xfd, 0x09, 0xfc, 0x84, 0xfe, 0x1c, 0x46, 0x46, 0xa6, - 0xb6, 0xc0, 0xd2, 0x9f, 0x51, 0x25, 0x06, 0xb5, 0xaa, 0xd4, 0xad, 0x8b, 0xfd, 0x3e, 0xeb, 0x7d, - 0xef, 0xbd, 0xcf, 0x36, 0xfc, 0x3e, 0xf7, 0x67, 0x32, 0x2e, 0x68, 0xc4, 0x7c, 0xbd, 0x90, 0x4c, - 0x99, 0x95, 0xc8, 0x42, 0x68, 0x81, 0x5a, 0xa1, 0x50, 0x99, 0x50, 0x23, 0x15, 0x4d, 0xc9, 0x9c, - 0x1c, 0x78, 0xe4, 0xfa, 0x77, 0xfb, 0x87, 0x4e, 0x78, 0x11, 0x8d, 0x24, 0x2d, 0xf4, 0xc2, 0xaf, - 0xb8, 0x7e, 0x2c, 0x62, 0xf1, 0x82, 0x8c, 0x40, 0xdb, 0x8d, 0x85, 0x88, 0x53, 0x66, 0x28, 0xe3, - 0xd9, 0xc4, 0xd7, 0x3c, 0x63, 0x4a, 0xd3, 0x4c, 0x1a, 0x42, 0xf7, 0x16, 0x40, 0x7b, 0x98, 0xd2, - 0x1c, 0x21, 0x68, 0xe7, 0x34, 0x63, 0x0e, 0xf0, 0x40, 0xaf, 0x11, 0x54, 0x18, 0xfd, 0x83, 0x76, - 0xc9, 0x77, 0x3e, 0x79, 0xa0, 0xd7, 0xec, 0xb7, 0x89, 0x11, 0x23, 0x47, 0x31, 0x72, 0x7e, 0x14, - 0x1b, 0x7c, 0x59, 0xdd, 0xbb, 0xd6, 0xf2, 0xc1, 0x05, 0x41, 0xd5, 0x81, 0xbe, 0xc1, 0x7a, 0xc2, - 0x78, 0x9c, 0x68, 0xa7, 0xe6, 0x81, 0x5e, 0x2d, 0x38, 0x54, 0xa5, 0x0b, 0xcf, 0x27, 0xc2, 0xb1, - 0x8d, 0x4b, 0x89, 0xbb, 0x4b, 0x00, 0x5b, 0x67, 0x62, 0xa2, 0x6f, 0x68, 0xc1, 0x2e, 0xcc, 0x88, - 0xc3, 0x42, 0x48, 0xa1, 0x68, 0x8a, 0xbe, 0xc2, 0xcf, 0x9a, 0xeb, 0xf4, 0x18, 0xcb, 0x14, 0xc8, - 0x83, 0xcd, 0x88, 0xa9, 0xb0, 0xe0, 0x52, 0x73, 0x91, 0x57, 0xf1, 0x1a, 0xc1, 0xeb, 0x23, 0xf4, - 0x17, 0xda, 0x32, 0xa5, 0x79, 0xe5, 0xde, 0xec, 0x77, 0xc8, 0x3b, 0xf7, 0x48, 0xca, 0xd1, 0x07, - 0x76, 0x19, 0x3e, 0xa8, 0x1a, 0xfe, 0xdb, 0x4f, 0x77, 0x2e, 0xe8, 0x5e, 0xc1, 0xce, 0x09, 0xcd, - 0x43, 0x96, 0x7e, 0x70, 0x2e, 0x23, 0x3f, 0x38, 0x5d, 0x6d, 0xb1, 0xb5, 0xd9, 0x62, 0x6b, 0xb5, - 0xc3, 0x60, 0xbd, 0xc3, 0xe0, 0x71, 0x87, 0xc1, 0x72, 0x8f, 0xad, 0xf5, 0x1e, 0x5b, 0x9b, 0x3d, - 0xb6, 0x2e, 0x7f, 0xc6, 0x5c, 0x27, 0xb3, 0x31, 0x09, 0x45, 0xe6, 0x9b, 0xec, 0x87, 0xed, 0x97, - 0x8a, 0xa6, 0xfe, 0x9b, 0x2f, 0x33, 0xae, 0x57, 0x2f, 0xf2, 0xe7, 0x39, 0x00, 0x00, 0xff, 0xff, - 0x4f, 0x2c, 0xc2, 0xac, 0x4c, 0x02, 0x00, 0x00, -} + // 379 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x92, 0x41, 0x6f, 0xda, 0x30, + 0x14, 0xc7, 0xe3, 0x91, 0xa1, 0x61, 0x6e, 0xd6, 0x34, 0x22, 0x26, 0x9c, 0x88, 0xc3, 0xc4, 0x61, + 0x73, 0x34, 0x76, 0xd8, 0xb4, 0x23, 0xbb, 0x4f, 0x28, 0x5b, 0x2f, 0x95, 0x2a, 0x64, 0x12, 0x93, + 0x58, 0x24, 0xb1, 0x15, 0x9b, 0x16, 0xbe, 0x40, 0xcf, 0x7c, 0x84, 0x7e, 0x1c, 0x8e, 0x1c, 0x39, + 0xb5, 0x05, 0x2e, 0xfd, 0x18, 0x55, 0xe2, 0xa0, 0x56, 0x95, 0x7a, 0xeb, 0x25, 0x79, 0xcf, 0xfa, + 0xbf, 0xff, 0xfb, 0xbd, 0x67, 0xc3, 0xcf, 0x4b, 0x7f, 0x21, 0xe3, 0x82, 0x46, 0xcc, 0xd7, 0x2b, + 0xc9, 0x94, 0xf9, 0x12, 0x59, 0x08, 0x2d, 0x50, 0x27, 0x14, 0x2a, 0x13, 0x6a, 0xa2, 0xa2, 0x39, + 0x59, 0x92, 0x5a, 0x47, 0x2e, 0xbf, 0x77, 0xbf, 0xe8, 0x84, 0x17, 0xd1, 0x44, 0xd2, 0x42, 0xaf, + 0xfc, 0x4a, 0xeb, 0xc7, 0x22, 0x16, 0x4f, 0x91, 0x31, 0xe8, 0xba, 0xb1, 0x10, 0x71, 0xca, 0x8c, + 0x64, 0xba, 0x98, 0xf9, 0x9a, 0x67, 0x4c, 0x69, 0x9a, 0x49, 0x23, 0xe8, 0x5f, 0x03, 0x68, 0x8f, + 0x53, 0x9a, 0x23, 0x04, 0xed, 0x9c, 0x66, 0xcc, 0x01, 0x1e, 0x18, 0xb4, 0x82, 0x2a, 0x46, 0xbf, + 0xa0, 0x5d, 0xea, 0x9d, 0x77, 0x1e, 0x18, 0xb4, 0x87, 0x5d, 0x62, 0xcc, 0xc8, 0xc9, 0x8c, 0xfc, + 0x3f, 0x99, 0x8d, 0x3e, 0x6c, 0x6e, 0x5d, 0x6b, 0x7d, 0xe7, 0x82, 0xa0, 0xaa, 0x40, 0x9f, 0x60, + 0x33, 0x61, 0x3c, 0x4e, 0xb4, 0xd3, 0xf0, 0xc0, 0xa0, 0x11, 0xd4, 0x59, 0xd9, 0x85, 0xe7, 0x33, + 0xe1, 0xd8, 0xa6, 0x4b, 0x19, 0xff, 0xb6, 0x1f, 0x6e, 0x5c, 0xd0, 0x5f, 0x03, 0xd8, 0xf9, 0x27, + 0x66, 0xfa, 0x8a, 0x16, 0xec, 0xcc, 0x0c, 0x3a, 0x2e, 0x84, 0x14, 0x8a, 0xa6, 0xe8, 0x23, 0x7c, + 0xaf, 0xb9, 0x4e, 0x4f, 0x70, 0x26, 0x41, 0x1e, 0x6c, 0x47, 0x4c, 0x85, 0x05, 0x97, 0x9a, 0x8b, + 0xbc, 0x82, 0x6c, 0x05, 0xcf, 0x8f, 0xd0, 0x4f, 0x68, 0xcb, 0x94, 0xe6, 0x15, 0x43, 0x7b, 0xd8, + 0x23, 0xaf, 0x6c, 0x93, 0x94, 0x0b, 0x18, 0xd9, 0xe5, 0x08, 0x41, 0x55, 0x50, 0x23, 0x5d, 0xc0, + 0xde, 0x1f, 0x9a, 0x87, 0x2c, 0x7d, 0x63, 0x2e, 0x63, 0x3f, 0xfa, 0xbb, 0xd9, 0x63, 0x6b, 0xb7, + 0xc7, 0xd6, 0xe6, 0x80, 0xc1, 0xf6, 0x80, 0xc1, 0xfd, 0x01, 0x83, 0xf5, 0x11, 0x5b, 0xdb, 0x23, + 0xb6, 0x76, 0x47, 0x6c, 0x9d, 0x7f, 0x8d, 0xb9, 0x4e, 0x16, 0x53, 0x12, 0x8a, 0xcc, 0x37, 0xec, + 0xf5, 0xef, 0x9b, 0x8a, 0xe6, 0xfe, 0x8b, 0x87, 0x33, 0x6d, 0x56, 0xf7, 0xf2, 0xe3, 0x31, 0x00, + 0x00, 0xff, 0xff, 0x45, 0x05, 0x01, 0x90, 0x52, 0x02, 0x00, 0x00, +} + +func (this *Plan) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + that1, ok := that.(*Plan) + if !ok { + that2, ok := that.(Plan) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Name != that1.Name { + return false + } + if !this.Time.Equal(that1.Time) { + return false + } + if this.Height != that1.Height { + return false + } + if this.Info != that1.Info { + return false + } + return true +} func (this *SoftwareUpgradeProposal) Equal(that interface{}) bool { if that == nil { return this == nil diff --git a/x/upgrade/types/types.proto b/x/upgrade/types/types.proto index d020f4401eac..3b0fffb8f1e6 100644 --- a/x/upgrade/types/types.proto +++ b/x/upgrade/types/types.proto @@ -10,6 +10,8 @@ option (gogoproto.goproto_getters_all) = false; // Plan specifies information about a planned upgrade and when it should occur message Plan { + option (gogoproto.equal) = true; + // Sets the name for the upgrade. This name will be used by the upgraded version of the software to apply any // special "on-upgrade" commands during the first BeginBlock method after the upgrade is applied. It is also used // to detect whether a software version can handle a given upgrade. If no upgrade handler with this name has been From 5f0c53da174c507baf668c695c5bc9a8a8c440c9 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Mon, 2 Mar 2020 16:46:28 -0500 Subject: [PATCH 334/529] update tests --- simapp/codec/codec.pb.go | 139 +++++++++++++---------- simapp/codec/codec.proto | 2 + simapp/codec/msgs.go | 2 +- x/gov/keeper/keeper_test.go | 8 +- x/gov/keeper/proposal_test.go | 55 +-------- x/gov/types/genesis.go | 3 +- x/gov/types/types.pb.go | 202 +++++++++++++++++++++------------- x/gov/types/types.proto | 1 + 8 files changed, 223 insertions(+), 189 deletions(-) diff --git a/simapp/codec/codec.pb.go b/simapp/codec/codec.pb.go index 17b25255637c..7ef14c916972 100644 --- a/simapp/codec/codec.pb.go +++ b/simapp/codec/codec.pb.go @@ -583,62 +583,62 @@ func init() { func init() { proto.RegisterFile("simapp/codec/codec.proto", fileDescriptor_3c6d4085e4065f5a) } var fileDescriptor_3c6d4085e4065f5a = []byte{ - // 876 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x56, 0x41, 0x6f, 0xe3, 0x44, - 0x14, 0xb6, 0x77, 0xb3, 0x6d, 0x34, 0xbb, 0xc0, 0x32, 0x62, 0x69, 0x14, 0x50, 0xb2, 0x64, 0x61, - 0x05, 0x8b, 0x6a, 0xef, 0x52, 0xa0, 0x6d, 0x24, 0x54, 0x9a, 0x50, 0x14, 0x24, 0x8a, 0xaa, 0x14, - 0x38, 0x20, 0x90, 0xe5, 0x8c, 0x07, 0xc7, 0xaa, 0xed, 0x19, 0x3c, 0x63, 0xe3, 0xfc, 0x03, 0xc4, - 0xa9, 0x3f, 0xa1, 0xe2, 0xc0, 0x91, 0x53, 0x8f, 0xfc, 0x80, 0xaa, 0xa7, 0x1e, 0x39, 0x55, 0xa8, - 0xbd, 0xf0, 0x33, 0x90, 0x3d, 0x63, 0xc7, 0x96, 0x9d, 0x64, 0x2f, 0x56, 0x3c, 0xef, 0x7b, 0xdf, - 0xf7, 0x8d, 0x67, 0xde, 0x7b, 0x01, 0x2d, 0xe6, 0x78, 0x26, 0xa5, 0x3a, 0x22, 0x16, 0x46, 0xe2, - 0xa9, 0xd1, 0x80, 0x70, 0x02, 0xdb, 0x88, 0x30, 0x8f, 0x30, 0x83, 0x59, 0x27, 0x9a, 0x00, 0x69, - 0x22, 0x1c, 0xbd, 0x68, 0x7f, 0xc8, 0xa7, 0x4e, 0x60, 0x19, 0xd4, 0x0c, 0xf8, 0x4c, 0x4f, 0xe1, - 0xba, 0x40, 0x6f, 0x16, 0x5f, 0x04, 0x51, 0xfb, 0x69, 0x15, 0x6c, 0x13, 0x9b, 0xcc, 0x7f, 0x49, - 0x5c, 0x2b, 0xd6, 0xcd, 0x90, 0x4f, 0x75, 0x3e, 0xa3, 0x98, 0x89, 0xa7, 0x8c, 0x3c, 0x96, 0x91, - 0x08, 0x33, 0xee, 0xf8, 0x76, 0x0d, 0xa2, 0x1d, 0xeb, 0x2c, 0xa4, 0xd4, 0x9d, 0xd5, 0xc4, 0xde, - 0x8e, 0x75, 0x1c, 0x39, 0x16, 0xf6, 0x11, 0xae, 0x89, 0x6e, 0xc4, 0xba, 0x4d, 0xa2, 0x9a, 0xc0, - 0x93, 0x58, 0xa7, 0x66, 0x60, 0x7a, 0x72, 0x35, 0x71, 0x4e, 0x09, 0x33, 0xdd, 0x12, 0xe8, 0xad, - 0x58, 0x0f, 0xa9, 0x1d, 0x98, 0x16, 0xae, 0xb7, 0x6d, 0x39, 0x8c, 0x07, 0xce, 0x24, 0xe4, 0x0e, - 0xf1, 0xab, 0x88, 0xde, 0xdf, 0x0d, 0xb0, 0xbe, 0x8f, 0x10, 0x09, 0x7d, 0x0e, 0xbf, 0x04, 0x0f, - 0x26, 0x26, 0xc3, 0x86, 0x29, 0xde, 0x5b, 0xea, 0x63, 0xf5, 0xfd, 0xfb, 0x1f, 0xbd, 0xa3, 0x15, - 0x8e, 0x21, 0xd6, 0x92, 0xcf, 0xa0, 0x45, 0x2f, 0xb4, 0x81, 0xc9, 0xb0, 0x4c, 0x1c, 0x29, 0xe3, - 0xfb, 0x93, 0xf9, 0x2b, 0x8c, 0x40, 0x1b, 0x11, 0x9f, 0x3b, 0x7e, 0x48, 0x42, 0x66, 0xc8, 0x4f, - 0x96, 0xb3, 0xde, 0x49, 0x59, 0x3f, 0xad, 0x63, 0x15, 0xc8, 0x84, 0x7d, 0x98, 0xe7, 0x7f, 0x2f, - 0x16, 0xe7, 0x52, 0x2d, 0xb4, 0x20, 0x06, 0x3d, 0xb0, 0x61, 0x61, 0xd7, 0x9c, 0x61, 0xab, 0x22, - 0x7a, 0x37, 0x15, 0xdd, 0x5a, 0x2e, 0xfa, 0x85, 0x48, 0xae, 0x28, 0x3e, 0xb2, 0xea, 0x02, 0x90, - 0x82, 0x16, 0xc5, 0x81, 0x43, 0x2c, 0x07, 0x55, 0xf4, 0x1a, 0xa9, 0xde, 0xc7, 0xcb, 0xf5, 0x8e, - 0x64, 0x76, 0x45, 0xf0, 0x4d, 0x5a, 0x1b, 0x81, 0xdf, 0x80, 0x57, 0x3d, 0x62, 0x85, 0xee, 0xfc, - 0x88, 0xee, 0xa5, 0x3a, 0xef, 0x95, 0x75, 0xc4, 0x3d, 0x4c, 0x14, 0x0e, 0x53, 0xf4, 0x9c, 0xf8, - 0x15, 0xaf, 0xb8, 0xd0, 0xdf, 0xbd, 0x3c, 0xdf, 0xfc, 0xe4, 0x99, 0xed, 0xf0, 0x69, 0x38, 0xd1, - 0x10, 0xf1, 0x64, 0xd5, 0x64, 0x95, 0xc4, 0xac, 0x13, 0x5d, 0xde, 0x7b, 0x1c, 0x53, 0x12, 0x70, - 0x6c, 0x69, 0x32, 0x75, 0x70, 0x0f, 0xdc, 0x65, 0xa1, 0xd7, 0xfb, 0x5d, 0x05, 0x6b, 0xc7, 0xa9, - 0x1c, 0xdc, 0x01, 0x6b, 0x42, 0x58, 0xde, 0x9b, 0xce, 0x22, 0x53, 0x02, 0x3f, 0x52, 0xc6, 0x12, - 0xdf, 0xdf, 0xfb, 0xef, 0xac, 0xab, 0x5e, 0x9e, 0x6f, 0x6e, 0xaf, 0xb2, 0x22, 0x0b, 0x2c, 0x37, - 0x23, 0x98, 0xbe, 0xca, 0xcc, 0xfc, 0xa1, 0x82, 0xe6, 0x81, 0xac, 0x33, 0xf8, 0x35, 0x78, 0x80, - 0x7f, 0x09, 0x9d, 0x88, 0x20, 0x33, 0xb9, 0xfa, 0xd2, 0xd4, 0xd3, 0xb2, 0xa9, 0xac, 0x2a, 0x13, - 0x5b, 0x07, 0x05, 0xf4, 0x48, 0x19, 0x97, 0xb2, 0xfb, 0xfb, 0xd2, 0xe2, 0xee, 0x0a, 0x87, 0x79, - 0x99, 0xe7, 0x1e, 0x33, 0x43, 0x99, 0xc9, 0xbf, 0x54, 0xf0, 0xfa, 0x21, 0xb3, 0x8f, 0xc3, 0x89, - 0xe7, 0xf0, 0xdc, 0xed, 0xe7, 0xa0, 0x99, 0xa5, 0x4a, 0xa7, 0xef, 0x6a, 0x8b, 0xbb, 0x5f, 0x4e, - 0x3a, 0xce, 0xb3, 0xe0, 0x21, 0x68, 0x24, 0x35, 0x28, 0xcb, 0x4b, 0x5f, 0xbc, 0xcf, 0x8a, 0x78, - 0x52, 0xc9, 0x83, 0xe6, 0xc5, 0x75, 0x57, 0xb9, 0xba, 0xee, 0xaa, 0xe3, 0x94, 0xa6, 0xdf, 0xfc, - 0xed, 0xac, 0xab, 0x24, 0x9b, 0xee, 0xfd, 0x59, 0x34, 0x7c, 0x24, 0x5b, 0x10, 0xfc, 0x0c, 0xac, - 0x27, 0x75, 0x88, 0xf3, 0x36, 0xf1, 0x64, 0x99, 0xdf, 0xa1, 0x80, 0x8e, 0xb3, 0x1c, 0x38, 0x2a, - 0xb9, 0x7d, 0x56, 0x76, 0x6b, 0x93, 0xa8, 0x64, 0x34, 0x13, 0x5d, 0x61, 0xf4, 0x54, 0x05, 0xcd, - 0xdc, 0xdf, 0x9e, 0x14, 0xa8, 0xed, 0x61, 0x52, 0x60, 0x19, 0x2f, 0x1c, 0xce, 0x37, 0x78, 0xe7, - 0xa5, 0x37, 0x38, 0x68, 0x24, 0x2c, 0xf9, 0x36, 0x7b, 0x67, 0x0d, 0xb0, 0x2e, 0x43, 0x70, 0x1b, - 0x34, 0x38, 0x8e, 0xf9, 0x52, 0x47, 0xdf, 0xe2, 0x38, 0xdf, 0xed, 0x48, 0x19, 0xa7, 0x09, 0xf0, - 0x47, 0xf0, 0x30, 0x1d, 0x03, 0x98, 0xe3, 0xc0, 0x40, 0x53, 0xd3, 0xb7, 0x17, 0x9c, 0xb2, 0x18, - 0x16, 0xe9, 0xce, 0x32, 0xfc, 0x30, 0x85, 0x17, 0x28, 0x5f, 0xa3, 0xe5, 0x10, 0xfc, 0x09, 0x3c, - 0x64, 0xe4, 0x67, 0xfe, 0xab, 0x19, 0x60, 0x43, 0x0e, 0x12, 0xd9, 0x2d, 0x9f, 0x97, 0xd9, 0x65, - 0x30, 0xad, 0x60, 0x99, 0xf0, 0x9d, 0x58, 0x2a, 0xd2, 0xb3, 0x72, 0x08, 0x52, 0xb0, 0x81, 0x4c, - 0x1f, 0x61, 0xd7, 0xa8, 0xa8, 0x34, 0xea, 0x06, 0x41, 0x41, 0x65, 0x98, 0xe6, 0x2d, 0xd6, 0x7a, - 0x84, 0xea, 0x00, 0xd0, 0x05, 0x6f, 0x20, 0xe2, 0x79, 0xa1, 0xef, 0xf0, 0x99, 0x41, 0x09, 0x71, - 0x0d, 0x46, 0xb1, 0x6f, 0xc9, 0x56, 0xb9, 0x53, 0x96, 0x2b, 0x4e, 0x47, 0x71, 0x8e, 0x32, 0xf3, - 0x88, 0x10, 0xf7, 0x38, 0xc9, 0x2b, 0x08, 0x42, 0x54, 0x89, 0xf6, 0x77, 0x64, 0x63, 0x78, 0xbe, - 0xa2, 0x31, 0xe4, 0x13, 0x3e, 0xbf, 0x2a, 0xa2, 0x1f, 0x0c, 0x86, 0x17, 0x37, 0x1d, 0xf5, 0xea, - 0xa6, 0xa3, 0xfe, 0x7b, 0xd3, 0x51, 0x4f, 0x6f, 0x3b, 0xca, 0xd5, 0x6d, 0x47, 0xf9, 0xe7, 0xb6, - 0xa3, 0xfc, 0xf0, 0xc1, 0x52, 0xca, 0xe2, 0xbf, 0xa6, 0xc9, 0x5a, 0x3a, 0xcc, 0xb7, 0xfe, 0x0f, - 0x00, 0x00, 0xff, 0xff, 0x22, 0x64, 0xee, 0x71, 0x4c, 0x09, 0x00, 0x00, + // 880 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x56, 0x41, 0x8f, 0xdb, 0x44, + 0x14, 0xb6, 0x5b, 0x77, 0x37, 0x9a, 0x16, 0x28, 0x23, 0xca, 0x46, 0x01, 0x25, 0x65, 0x0b, 0x15, + 0x14, 0xad, 0xdd, 0x52, 0xa0, 0xdb, 0x48, 0xa8, 0x34, 0xa1, 0x28, 0x48, 0x2c, 0x5a, 0x65, 0x81, + 0x03, 0x02, 0x59, 0xce, 0x78, 0x70, 0xac, 0xda, 0x9e, 0xc1, 0x33, 0x36, 0xce, 0x3f, 0x40, 0x9c, + 0x38, 0x71, 0x5e, 0x71, 0xe0, 0xc8, 0xa9, 0x47, 0x7e, 0x40, 0xb5, 0xa7, 0x3d, 0x72, 0x5a, 0xa1, + 0xdd, 0x0b, 0x3f, 0x03, 0x79, 0x66, 0xec, 0xd8, 0xb2, 0x93, 0xf4, 0x62, 0xc5, 0xf3, 0xbe, 0xf7, + 0x7d, 0xdf, 0x78, 0xe6, 0xbd, 0x17, 0xd0, 0x65, 0x7e, 0xe8, 0x50, 0x6a, 0x21, 0xe2, 0x62, 0x24, + 0x9f, 0x26, 0x8d, 0x09, 0x27, 0xb0, 0x87, 0x08, 0x0b, 0x09, 0xb3, 0x99, 0xfb, 0xd4, 0x94, 0x20, + 0x53, 0x86, 0xd3, 0x7b, 0xbd, 0xf7, 0xf9, 0xdc, 0x8f, 0x5d, 0x9b, 0x3a, 0x31, 0x5f, 0x58, 0x02, + 0x6e, 0x49, 0xf4, 0x5e, 0xf5, 0x45, 0x12, 0xf5, 0x6e, 0x37, 0xc1, 0x1e, 0xf1, 0xc8, 0xf2, 0x97, + 0xc2, 0x75, 0x33, 0xcb, 0x49, 0xf8, 0xdc, 0xe2, 0x0b, 0x8a, 0x99, 0x7c, 0xaa, 0xc8, 0x4d, 0x15, + 0x49, 0x31, 0xe3, 0x7e, 0xe4, 0xb5, 0x20, 0x7a, 0x99, 0xc5, 0x12, 0x4a, 0x83, 0x45, 0x4b, 0xec, + 0xcd, 0xcc, 0xc2, 0xa9, 0xef, 0xe2, 0x08, 0xe1, 0x96, 0xe8, 0x4e, 0x66, 0x79, 0x24, 0x6d, 0x09, + 0xdc, 0xca, 0x2c, 0xea, 0xc4, 0x4e, 0xa8, 0x56, 0x73, 0xe7, 0x94, 0x30, 0x27, 0xa8, 0x81, 0xde, + 0xc8, 0xac, 0x84, 0x7a, 0xb1, 0xe3, 0xe2, 0x76, 0xdb, 0xae, 0xcf, 0x78, 0xec, 0xcf, 0x12, 0xee, + 0x93, 0xa8, 0x89, 0xd8, 0xfd, 0xdb, 0x00, 0xdb, 0x8f, 0x11, 0x22, 0x49, 0xc4, 0xe1, 0xe7, 0xe0, + 0xda, 0xcc, 0x61, 0xd8, 0x76, 0xe4, 0x7b, 0x57, 0xbf, 0xa9, 0xbf, 0x7b, 0xf5, 0x83, 0xb7, 0xcc, + 0xca, 0x31, 0x64, 0x66, 0xfe, 0x19, 0xcc, 0xf4, 0x9e, 0x39, 0x72, 0x18, 0x56, 0x89, 0x13, 0x6d, + 0x7a, 0x75, 0xb6, 0x7c, 0x85, 0x29, 0xe8, 0x21, 0x12, 0x71, 0x3f, 0x4a, 0x48, 0xc2, 0x6c, 0xf5, + 0xc9, 0x4a, 0xd6, 0x4b, 0x82, 0xf5, 0xe3, 0x36, 0x56, 0x89, 0xcc, 0xd9, 0xc7, 0x65, 0xfe, 0xb7, + 0x72, 0x71, 0x29, 0xd5, 0x45, 0x2b, 0x62, 0x30, 0x04, 0x3b, 0x2e, 0x0e, 0x9c, 0x05, 0x76, 0x1b, + 0xa2, 0x97, 0x85, 0xe8, 0xfd, 0xf5, 0xa2, 0x9f, 0xc9, 0xe4, 0x86, 0xe2, 0x0d, 0xb7, 0x2d, 0x00, + 0x29, 0xe8, 0x52, 0x1c, 0xfb, 0xc4, 0xf5, 0x51, 0x43, 0xcf, 0x10, 0x7a, 0x1f, 0xae, 0xd7, 0x3b, + 0x54, 0xd9, 0x0d, 0xc1, 0xd7, 0x69, 0x6b, 0x04, 0x7e, 0x05, 0x5e, 0x0e, 0x89, 0x9b, 0x04, 0xcb, + 0x23, 0xba, 0x22, 0x74, 0xde, 0xa9, 0xeb, 0xc8, 0x7b, 0x98, 0x2b, 0x1c, 0x08, 0xf4, 0x92, 0xf8, + 0xa5, 0xb0, 0xba, 0x30, 0x7c, 0x78, 0xf2, 0x6c, 0xef, 0xa3, 0x3b, 0x9e, 0xcf, 0xe7, 0xc9, 0xcc, + 0x44, 0x24, 0x54, 0x55, 0x53, 0x54, 0x12, 0x73, 0x9f, 0x5a, 0xea, 0xde, 0xe3, 0x8c, 0x92, 0x98, + 0x63, 0xd7, 0x54, 0xa9, 0xa3, 0x2b, 0xe0, 0x32, 0x4b, 0xc2, 0xdd, 0x5f, 0x75, 0xb0, 0x75, 0x24, + 0xe4, 0xe0, 0x3e, 0xd8, 0x92, 0xc2, 0xea, 0xde, 0xf4, 0x57, 0x99, 0x92, 0xf8, 0x89, 0x36, 0x55, + 0xf8, 0xe1, 0xa3, 0xff, 0x8e, 0x07, 0xfa, 0xc9, 0xb3, 0xbd, 0x07, 0x9b, 0xac, 0xa8, 0x02, 0x2b, + 0xcd, 0x48, 0xa6, 0x2f, 0x0a, 0x33, 0x7f, 0xe8, 0xa0, 0xf3, 0x44, 0xd5, 0x19, 0xfc, 0x12, 0x5c, + 0xc3, 0x3f, 0x25, 0x7e, 0x4a, 0x90, 0x93, 0x5f, 0x7d, 0x65, 0xea, 0x76, 0xdd, 0x54, 0x51, 0x95, + 0xb9, 0xad, 0x27, 0x15, 0xf4, 0x44, 0x9b, 0xd6, 0xb2, 0x87, 0x8f, 0x95, 0xc5, 0x87, 0x1b, 0x1c, + 0x96, 0x65, 0x5e, 0x7a, 0x2c, 0x0c, 0x15, 0x26, 0xff, 0xd2, 0xc1, 0xab, 0x07, 0xcc, 0x3b, 0x4a, + 0x66, 0xa1, 0xcf, 0x4b, 0xb7, 0x9f, 0x82, 0x4e, 0x91, 0xaa, 0x9c, 0xbe, 0x6d, 0xae, 0xee, 0x7e, + 0x25, 0xe9, 0xb4, 0xcc, 0x82, 0x07, 0xc0, 0xc8, 0x6b, 0x50, 0x95, 0x97, 0xb5, 0x7a, 0x9f, 0x0d, + 0xf1, 0xbc, 0x92, 0x47, 0x9d, 0xe7, 0x67, 0x03, 0xed, 0xf4, 0x6c, 0xa0, 0x4f, 0x05, 0xcd, 0xb0, + 0xf3, 0xcb, 0xf1, 0x40, 0xcb, 0x37, 0xbd, 0xfb, 0x67, 0xd5, 0xf0, 0xa1, 0x6a, 0x41, 0xf0, 0x13, + 0xb0, 0x9d, 0xd7, 0x21, 0x2e, 0xdb, 0xc4, 0xad, 0x75, 0x7e, 0xc7, 0x12, 0x3a, 0x2d, 0x72, 0xe0, + 0xa4, 0xe6, 0xf6, 0x4e, 0xdd, 0xad, 0x47, 0xd2, 0x9a, 0xd1, 0x42, 0x74, 0x83, 0xd1, 0xdf, 0x75, + 0xd0, 0x29, 0xfd, 0x3d, 0x52, 0x02, 0xad, 0x3d, 0x4c, 0x09, 0xac, 0xe3, 0x85, 0xe3, 0xe5, 0x06, + 0x2f, 0xbd, 0xf0, 0x06, 0x47, 0x46, 0xce, 0x52, 0x6e, 0x73, 0x68, 0x08, 0x63, 0xc7, 0x06, 0xd8, + 0x56, 0x00, 0xf8, 0x00, 0x18, 0x1c, 0x67, 0x7c, 0xad, 0xaf, 0xaf, 0x71, 0x56, 0xee, 0x79, 0xa2, + 0x4d, 0x45, 0x02, 0xfc, 0x1e, 0x5c, 0x17, 0xc3, 0x00, 0x73, 0x1c, 0xdb, 0x68, 0xee, 0x44, 0xde, + 0x8a, 0xb3, 0x96, 0x23, 0x43, 0xec, 0xaf, 0xc0, 0x8f, 0x05, 0xbc, 0x42, 0xf9, 0x0a, 0xad, 0x87, + 0xe0, 0x0f, 0xe0, 0x3a, 0x23, 0x3f, 0xf2, 0x9f, 0x9d, 0x18, 0xdb, 0x6a, 0x9c, 0xa8, 0x9e, 0x79, + 0xb7, 0xce, 0xae, 0x82, 0xa2, 0x8e, 0x55, 0xc2, 0x37, 0x72, 0xa9, 0x4a, 0xcf, 0xea, 0x21, 0x48, + 0xc1, 0x0e, 0x72, 0x22, 0x84, 0x03, 0xbb, 0xa1, 0x62, 0xb4, 0x8d, 0x83, 0x8a, 0xca, 0x58, 0xe4, + 0xad, 0xd6, 0xba, 0x81, 0xda, 0x00, 0x30, 0x00, 0xaf, 0x21, 0x12, 0x86, 0x49, 0xe4, 0xf3, 0x85, + 0x4d, 0x09, 0x09, 0x6c, 0x46, 0x71, 0xe4, 0xaa, 0x86, 0xb9, 0x5f, 0x97, 0xab, 0xce, 0x48, 0x79, + 0x9a, 0x2a, 0xf3, 0x90, 0x90, 0xe0, 0x28, 0xcf, 0xab, 0x08, 0x42, 0xd4, 0x88, 0x0e, 0xf7, 0x55, + 0x7b, 0xb8, 0xbb, 0xa1, 0x3d, 0x94, 0x73, 0xbe, 0xbc, 0x30, 0xb2, 0x2b, 0x8c, 0xc6, 0xcf, 0xcf, + 0xfb, 0xfa, 0xe9, 0x79, 0x5f, 0xff, 0xf7, 0xbc, 0xaf, 0xff, 0x76, 0xd1, 0xd7, 0x4e, 0x2f, 0xfa, + 0xda, 0x3f, 0x17, 0x7d, 0xed, 0xbb, 0xf7, 0xd6, 0x52, 0x56, 0xff, 0x3b, 0xcd, 0xb6, 0xc4, 0x48, + 0xbf, 0xff, 0x7f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x44, 0x7b, 0x22, 0xdc, 0x52, 0x09, 0x00, 0x00, } func (this *Supply) Equal(that interface{}) bool { @@ -803,6 +803,33 @@ func (this *MsgSubmitProposal) Equal(that interface{}) bool { } return true } +func (this *Proposal) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*Proposal) + if !ok { + that2, ok := that.(Proposal) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !this.ProposalBase.Equal(&that1.ProposalBase) { + return false + } + if !this.Content.Equal(&that1.Content) { + return false + } + return true +} func (this *Content) Equal(that interface{}) bool { if that == nil { return this == nil diff --git a/simapp/codec/codec.proto b/simapp/codec/codec.proto index 9b5d94991e2e..c59061ab714d 100644 --- a/simapp/codec/codec.proto +++ b/simapp/codec/codec.proto @@ -74,6 +74,8 @@ message MsgSubmitProposal { // Proposal defines the application-level concrete proposal type used in governance // proposals. message Proposal { + option (gogoproto.equal) = true; + cosmos_sdk.x.gov.v1.ProposalBase base = 1 [(gogoproto.embed) = true, (gogoproto.nullable) = false]; Content content = 2 [(gogoproto.nullable) = false]; } diff --git a/simapp/codec/msgs.go b/simapp/codec/msgs.go index d34a07becbaa..5c4599d8d5fc 100644 --- a/simapp/codec/msgs.go +++ b/simapp/codec/msgs.go @@ -10,7 +10,7 @@ import ( var ( _ eviexported.MsgSubmitEvidence = MsgSubmitEvidence{} - _ gov.MsgSubmitProposal = MsgSubmitProposal{} + _ gov.MsgSubmitProposalI = MsgSubmitProposal{} ) // NewMsgSubmitEvidence returns a new MsgSubmitEvidence. diff --git a/x/gov/keeper/keeper_test.go b/x/gov/keeper/keeper_test.go index ec1a696791bf..7bf2899c3d09 100644 --- a/x/gov/keeper/keeper_test.go +++ b/x/gov/keeper/keeper_test.go @@ -3,12 +3,10 @@ package keeper_test import ( "testing" - proto "github.com/gogo/protobuf/types" "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/simapp" - simappcodec "github.com/cosmos/cosmos-sdk/simapp/codec" "github.com/cosmos/cosmos-sdk/x/gov/types" ) @@ -31,7 +29,6 @@ func TestIncrementProposalNumber(t *testing.T) { func TestProposalQueues(t *testing.T) { app := simapp.Setup(false) ctx := app.BaseApp.NewContext(false, abci.Header{}) - appCodec := simappcodec.NewAppCodec(app.Codec()) // create test proposals tp := TestProposal @@ -53,9 +50,8 @@ func TestProposalQueues(t *testing.T) { activeIterator := app.GovKeeper.ActiveProposalQueueIterator(ctx, proposal.VotingEndTime) require.True(t, activeIterator.Valid()) - var propIDValue proto.UInt64Value - appCodec.UnmarshalBinaryLengthPrefixed(activeIterator.Value(), &propIDValue) + proposalID, _ = types.SplitActiveProposalQueueKey(activeIterator.Key()) + require.Equal(t, proposalID, proposal.ProposalID) - require.Equal(t, propIDValue.Value, proposal.ProposalID) activeIterator.Close() } diff --git a/x/gov/keeper/proposal_test.go b/x/gov/keeper/proposal_test.go index 54ef390c84d5..99169d176946 100644 --- a/x/gov/keeper/proposal_test.go +++ b/x/gov/keeper/proposal_test.go @@ -54,51 +54,10 @@ func TestActivateVotingPeriod(t *testing.T) { activeIterator.Close() } -type validProposal struct{} - -func (validProposal) GetTitle() string { return "title" } -func (validProposal) GetDescription() string { return "description" } -func (validProposal) ProposalRoute() string { return types.RouterKey } -func (validProposal) ProposalType() string { return types.ProposalTypeText } -func (validProposal) String() string { return "" } -func (validProposal) ValidateBasic() error { return nil } - -type invalidProposalTitle1 struct{ validProposal } - -func (invalidProposalTitle1) GetTitle() string { return "" } - -type invalidProposalTitle2 struct{ validProposal } - -func (invalidProposalTitle2) GetTitle() string { return strings.Repeat("1234567890", 100) } - -type invalidProposalDesc1 struct{ validProposal } - -func (invalidProposalDesc1) GetDescription() string { return "" } - -type invalidProposalDesc2 struct{ validProposal } - -func (invalidProposalDesc2) GetDescription() string { return strings.Repeat("1234567890", 1000) } - -type invalidProposalRoute struct{ validProposal } +type invalidProposalRoute struct{ types.TextProposal } func (invalidProposalRoute) ProposalRoute() string { return "nonexistingroute" } -type invalidProposalValidation struct{ validProposal } - -func (invalidProposalValidation) ValidateBasic() error { - return errors.New("invalid proposal") -} - -// func registerTestCodec(cdc *codec.Codec) { -// cdc.RegisterConcrete(validProposal{}, "test/validproposal", nil) -// cdc.RegisterConcrete(invalidProposalTitle1{}, "test/invalidproposalt1", nil) -// cdc.RegisterConcrete(invalidProposalTitle2{}, "test/invalidproposalt2", nil) -// cdc.RegisterConcrete(invalidProposalDesc1{}, "test/invalidproposald1", nil) -// cdc.RegisterConcrete(invalidProposalDesc2{}, "test/invalidproposald2", nil) -// cdc.RegisterConcrete(invalidProposalRoute{}, "test/invalidproposalr", nil) -// cdc.RegisterConcrete(invalidProposalValidation{}, "test/invalidproposalv", nil) -// } - func TestSubmitProposal(t *testing.T) { app := simapp.Setup(false) ctx := app.BaseApp.NewContext(false, abci.Header{}) @@ -107,16 +66,14 @@ func TestSubmitProposal(t *testing.T) { content types.Content expectedErr error }{ - {validProposal{}, nil}, + {types.TextProposal{Title: "title", Description: "description"}, nil}, // Keeper does not check the validity of title and description, no error - {invalidProposalTitle1{}, nil}, - {invalidProposalTitle2{}, nil}, - {invalidProposalDesc1{}, nil}, - {invalidProposalDesc2{}, nil}, + {types.TextProposal{Title: "", Description: "description"}, nil}, + {types.TextProposal{Title: strings.Repeat("1234567890", 100), Description: "description"}, nil}, + {types.TextProposal{Title: "title", Description: ""}, nil}, + {types.TextProposal{Title: "title", Description: strings.Repeat("1234567890", 1000)}, nil}, // error only when invalid route {invalidProposalRoute{}, types.ErrNoProposalHandlerExists}, - // Keeper does not call ValidateBasic, msg.ValidateBasic does - {invalidProposalValidation{}, nil}, } for i, tc := range testCases { diff --git a/x/gov/types/genesis.go b/x/gov/types/genesis.go index e38b0213eeda..7099cb9590b7 100644 --- a/x/gov/types/genesis.go +++ b/x/gov/types/genesis.go @@ -38,7 +38,8 @@ func DefaultGenesisState() GenesisState { } func (data GenesisState) Equal(other GenesisState) bool { - return data.Deposits.Equal(other.Deposits) && + return data.StartingProposalID == other.StartingProposalID && + data.Deposits.Equal(other.Deposits) && data.Votes.Equal(other.Votes) && data.Proposals.Equal(other.Proposals) && data.DepositParams.Equal(other.DepositParams) && diff --git a/x/gov/types/types.pb.go b/x/gov/types/types.pb.go index 607ac5e8eb79..f97a1c0dd530 100644 --- a/x/gov/types/types.pb.go +++ b/x/gov/types/types.pb.go @@ -439,82 +439,82 @@ func init() { func init() { proto.RegisterFile("x/gov/types/types.proto", fileDescriptor_a5ae5e91b5b3fb03) } var fileDescriptor_a5ae5e91b5b3fb03 = []byte{ - // 1185 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x57, 0xc1, 0x6b, 0xdb, 0x56, - 0x18, 0x97, 0x6c, 0xc7, 0x49, 0x9e, 0x1d, 0x57, 0x7d, 0xc9, 0x5a, 0x4f, 0x0c, 0x49, 0x75, 0x4b, - 0xc9, 0x3a, 0x2a, 0xaf, 0xe9, 0x61, 0xd0, 0xc3, 0x98, 0x55, 0xab, 0xad, 0x4b, 0x63, 0x1b, 0xd9, - 0xa4, 0x74, 0x63, 0x08, 0xc5, 0x52, 0x15, 0xad, 0xb2, 0x9e, 0xe7, 0xf7, 0xec, 0xd5, 0xb7, 0xb1, - 0xc3, 0x28, 0x3e, 0xf5, 0xd8, 0x8b, 0xa1, 0xb0, 0x1e, 0xca, 0xd8, 0x61, 0x7f, 0x46, 0x60, 0x97, - 0x5e, 0x06, 0x65, 0x07, 0x77, 0x4d, 0x0e, 0x1b, 0x63, 0xa7, 0x5c, 0x06, 0x3b, 0x0d, 0xe9, 0x3d, - 0x25, 0x76, 0x92, 0x2e, 0x0d, 0xdd, 0x60, 0xec, 0x92, 0x44, 0xdf, 0xfb, 0x7d, 0xbf, 0xef, 0x7d, - 0xbf, 0xf7, 0xbd, 0xdf, 0x23, 0xe0, 0xf4, 0xfd, 0xa2, 0x8b, 0xfa, 0x45, 0x32, 0xe8, 0x38, 0x98, - 0xfe, 0x54, 0x3b, 0x5d, 0x44, 0x10, 0x5c, 0x6c, 0x21, 0xdc, 0x46, 0xd8, 0xc4, 0xf6, 0x3d, 0xf5, - 0xbe, 0xea, 0xa2, 0xbe, 0xda, 0xbf, 0x24, 0x9e, 0x3c, 0x80, 0x13, 0xcf, 0x93, 0x0d, 0xaf, 0x6b, - 0x9b, 0x1d, 0xab, 0x4b, 0x06, 0xc5, 0x28, 0x54, 0x74, 0x91, 0x8b, 0xf6, 0xfe, 0x62, 0x38, 0xd9, - 0x45, 0xc8, 0xf5, 0x1d, 0x0a, 0x59, 0xef, 0xdd, 0x2d, 0x12, 0xaf, 0xed, 0x60, 0x62, 0xb5, 0x3b, - 0x14, 0x50, 0xf8, 0x83, 0x07, 0x6f, 0xad, 0x62, 0xb7, 0xd1, 0x5b, 0x6f, 0x7b, 0xa4, 0xde, 0x45, - 0x1d, 0x84, 0x2d, 0x5f, 0xb3, 0xb0, 0x03, 0x1f, 0xf0, 0xe0, 0x84, 0x17, 0x78, 0xc4, 0xb3, 0x7c, - 0xd3, 0x76, 0x3a, 0x08, 0x7b, 0x24, 0xcf, 0x2b, 0xc9, 0xe5, 0xcc, 0xca, 0xa2, 0x3a, 0xb1, 0xcb, - 0xfe, 0x25, 0xf5, 0x2a, 0xf2, 0x02, 0xed, 0xe6, 0xe6, 0x58, 0xe6, 0x76, 0xc6, 0xf2, 0xa9, 0x81, - 0xd5, 0xf6, 0xaf, 0x14, 0xf6, 0x65, 0x16, 0xbe, 0x7d, 0x21, 0x2f, 0xbb, 0x1e, 0xd9, 0xe8, 0xad, - 0xab, 0x2d, 0xd4, 0x2e, 0x52, 0x02, 0xf6, 0xeb, 0x22, 0xb6, 0xef, 0xb1, 0xee, 0x42, 0x2a, 0x6c, - 0xe4, 0x58, 0x76, 0x99, 0x26, 0xc3, 0x55, 0x30, 0xd7, 0x89, 0xb6, 0xe6, 0x74, 0xf3, 0x09, 0x85, - 0x5f, 0xce, 0x6a, 0x97, 0xfe, 0x1c, 0xcb, 0x17, 0x5f, 0x83, 0xaf, 0xd4, 0x6a, 0x95, 0x6c, 0xbb, - 0xeb, 0x60, 0x6c, 0xec, 0x52, 0x5c, 0x49, 0xfd, 0xfa, 0x58, 0xe6, 0x0b, 0xbf, 0xf0, 0x60, 0x76, - 0x15, 0xbb, 0x6b, 0x88, 0x38, 0xb0, 0x09, 0x32, 0x1d, 0xd6, 0xbb, 0xe9, 0xd9, 0x79, 0x5e, 0xe1, - 0x97, 0x53, 0xda, 0xe5, 0xad, 0xb1, 0x0c, 0x62, 0x49, 0x2a, 0xe5, 0xdf, 0xc6, 0xf2, 0x24, 0x68, - 0x67, 0x2c, 0x43, 0xda, 0xea, 0x44, 0xb0, 0x60, 0x80, 0xf8, 0xab, 0x62, 0xc3, 0xeb, 0x60, 0xa6, - 0x8f, 0xc8, 0x9b, 0xec, 0x99, 0xe6, 0xc3, 0x0f, 0x40, 0x1a, 0x75, 0x88, 0x87, 0x82, 0x7c, 0x52, - 0xe1, 0x97, 0x73, 0x2b, 0xb2, 0x7a, 0xc8, 0x98, 0xa8, 0x61, 0x27, 0xb5, 0x08, 0x66, 0x30, 0x38, - 0xeb, 0xf4, 0x51, 0x02, 0x80, 0x55, 0xec, 0xc6, 0x6a, 0xfe, 0x3b, 0xcd, 0xd6, 0xc0, 0x3c, 0x3b, - 0x6b, 0xf4, 0x06, 0x0d, 0xef, 0x71, 0xc0, 0x4f, 0x41, 0xda, 0x6a, 0xa3, 0x5e, 0x40, 0xf2, 0xc9, - 0x57, 0x4f, 0xdd, 0xfb, 0xe1, 0xd4, 0x1d, 0x6b, 0xb6, 0x18, 0x29, 0x93, 0xe6, 0x16, 0xc8, 0x36, - 0x9d, 0xfb, 0xbb, 0x83, 0x0f, 0x97, 0xc0, 0x0c, 0xf1, 0x88, 0xef, 0x44, 0xaa, 0xcc, 0x1b, 0xf4, - 0x03, 0x2a, 0x20, 0x63, 0x3b, 0xb8, 0xd5, 0xf5, 0xe8, 0x21, 0x24, 0xa2, 0xb5, 0xc9, 0x10, 0x63, - 0xfb, 0x3a, 0x01, 0x66, 0x63, 0x95, 0xf5, 0xc3, 0x54, 0x3e, 0x37, 0xad, 0xf2, 0xff, 0x56, 0xd6, - 0x1f, 0xd2, 0x20, 0x3b, 0x65, 0x26, 0xda, 0x61, 0x6a, 0x9c, 0x39, 0x30, 0x73, 0x89, 0x68, 0xd4, - 0xe6, 0x99, 0x85, 0xec, 0x93, 0xe2, 0x36, 0x48, 0x63, 0x62, 0x91, 0x1e, 0x8e, 0x74, 0xc8, 0xad, - 0x9c, 0x3d, 0xf4, 0x16, 0xc4, 0x7c, 0x8d, 0x08, 0xaa, 0x89, 0x7b, 0x96, 0xb4, 0xbb, 0x01, 0xca, - 0x52, 0x30, 0x18, 0x1d, 0xfc, 0x1c, 0xc0, 0xbb, 0x5e, 0x60, 0xf9, 0x26, 0xb1, 0x7c, 0x7f, 0x60, - 0x76, 0x1d, 0xdc, 0xf3, 0x49, 0x74, 0xd5, 0x32, 0x2b, 0xca, 0xa1, 0x45, 0x9a, 0x21, 0xd0, 0x88, - 0x70, 0xda, 0x19, 0x66, 0x7c, 0x6f, 0xd3, 0x2a, 0x07, 0x99, 0x0a, 0x86, 0x10, 0x05, 0x27, 0x92, - 0xe0, 0x27, 0x20, 0x83, 0x23, 0xcb, 0x35, 0x43, 0x43, 0xce, 0xa7, 0xa2, 0x5a, 0xa2, 0x4a, 0xdd, - 0x5a, 0x8d, 0xdd, 0x5a, 0x6d, 0xc6, 0x6e, 0xad, 0x49, 0xac, 0x0a, 0x9b, 0x97, 0x89, 0xe4, 0xc2, - 0xc3, 0x17, 0x32, 0x6f, 0x00, 0x1a, 0x09, 0x13, 0xa0, 0x07, 0x04, 0x76, 0xde, 0xa6, 0x13, 0xd8, - 0xb4, 0xc2, 0xcc, 0x91, 0x15, 0xce, 0xb2, 0x0a, 0xa7, 0x69, 0x85, 0xfd, 0x0c, 0xb4, 0x4c, 0x8e, - 0x85, 0xf5, 0xc0, 0x8e, 0x4a, 0x7d, 0xc5, 0x83, 0x05, 0x82, 0xc8, 0xc4, 0x13, 0x91, 0x7e, 0xf5, - 0x54, 0xdd, 0x60, 0x15, 0x96, 0x68, 0x85, 0xa9, 0xbc, 0xe3, 0x3d, 0x10, 0xd9, 0x28, 0x37, 0xbe, - 0x6a, 0x3e, 0x38, 0xd9, 0x47, 0xc4, 0x0b, 0xdc, 0xf0, 0x64, 0xbb, 0x4c, 0xd2, 0xd9, 0x23, 0x1b, - 0x3e, 0xc7, 0xb6, 0x93, 0xa7, 0xdb, 0x39, 0x40, 0x41, 0x3b, 0x3e, 0x41, 0xe3, 0x8d, 0x30, 0x1c, - 0xb5, 0x7c, 0x17, 0xb0, 0xd0, 0x9e, 0xb8, 0x73, 0x47, 0xd6, 0x2a, 0x4c, 0xbf, 0x8e, 0xfb, 0x08, - 0x68, 0xa5, 0x05, 0x1a, 0x65, 0xd2, 0x5e, 0x99, 0x7b, 0xf4, 0x58, 0xe6, 0x9f, 0x86, 0xb7, 0x69, - 0x33, 0x01, 0x32, 0x93, 0xc3, 0xf3, 0x11, 0x48, 0x0e, 0x1c, 0x4c, 0x2d, 0x4a, 0x53, 0x43, 0xe6, - 0x9f, 0xc6, 0xf2, 0xf9, 0xd7, 0x10, 0xaf, 0x12, 0x10, 0x23, 0x4c, 0x85, 0x37, 0xc0, 0xac, 0xb5, - 0x8e, 0x89, 0xe5, 0x31, 0x33, 0x3b, 0x36, 0x4b, 0x9c, 0x0e, 0x3f, 0x04, 0x89, 0x00, 0x45, 0x77, - 0xe5, 0xf8, 0x24, 0x89, 0x00, 0x41, 0x17, 0x64, 0x03, 0x64, 0x7e, 0xe1, 0x91, 0x0d, 0xb3, 0xef, - 0x10, 0x14, 0xdd, 0x84, 0x79, 0x4d, 0x3f, 0x1e, 0xd3, 0xce, 0x58, 0x5e, 0xa4, 0xc2, 0x4e, 0x72, - 0x15, 0x0c, 0x10, 0xa0, 0xdb, 0x1e, 0xd9, 0x58, 0x73, 0x08, 0x62, 0xc6, 0xf4, 0x23, 0x0f, 0x52, - 0xd1, 0x8b, 0xff, 0x0f, 0xd9, 0xf3, 0x7f, 0xe4, 0x89, 0xbf, 0xf0, 0x1d, 0x0f, 0xc0, 0xde, 0x22, - 0x14, 0xc1, 0x8c, 0xbe, 0x5a, 0x6f, 0xde, 0x11, 0x38, 0xf1, 0xc4, 0x70, 0xa4, 0x64, 0x68, 0x58, - 0x6f, 0x77, 0xc8, 0x00, 0x9e, 0x02, 0xc9, 0x3b, 0x7a, 0x43, 0xe0, 0xc5, 0x85, 0xe1, 0x48, 0x99, - 0xa7, 0x2b, 0x77, 0x1c, 0x0c, 0x25, 0x30, 0x5b, 0xd2, 0x1a, 0xcd, 0x52, 0xa5, 0x2a, 0x24, 0xc4, - 0x93, 0xc3, 0x91, 0xb2, 0x40, 0xd7, 0x4a, 0xec, 0xa4, 0x97, 0x40, 0xa2, 0x5a, 0x13, 0x92, 0x62, - 0x76, 0x38, 0x52, 0xe6, 0xe8, 0x52, 0x15, 0xc1, 0xf3, 0x20, 0x5b, 0xad, 0x99, 0xb7, 0x2b, 0xcd, - 0x1b, 0xe6, 0x9a, 0xde, 0xac, 0x09, 0x29, 0x71, 0x69, 0x38, 0x52, 0x84, 0x78, 0x3d, 0x96, 0x5f, - 0xcc, 0x3e, 0xf8, 0x46, 0xe2, 0x9e, 0x3e, 0x91, 0xb8, 0xef, 0x9f, 0x48, 0xdc, 0x85, 0xdf, 0x79, - 0x90, 0x9b, 0x36, 0xea, 0x70, 0x5b, 0xd5, 0xca, 0x2d, 0x81, 0xa3, 0xdb, 0xa2, 0xc1, 0xaa, 0xe7, - 0xc3, 0xf7, 0x40, 0xae, 0xac, 0xd7, 0x6b, 0x8d, 0x4a, 0xd3, 0xac, 0xeb, 0x46, 0xa5, 0x56, 0x16, - 0x78, 0xf1, 0xf4, 0x70, 0xa4, 0x2c, 0x52, 0x08, 0xf3, 0x80, 0xba, 0xd3, 0xf5, 0x90, 0x0d, 0xdf, - 0x05, 0x0b, 0x6b, 0xb5, 0x66, 0xa5, 0x7a, 0x3d, 0xc6, 0x26, 0xc4, 0x53, 0xc3, 0x91, 0x02, 0x29, - 0x76, 0x2d, 0xba, 0x5f, 0x0c, 0xfa, 0x0e, 0x48, 0xd7, 0x4b, 0x8d, 0x86, 0x5e, 0x16, 0x92, 0xa2, - 0x30, 0x1c, 0x29, 0x59, 0x8a, 0xa9, 0x5b, 0x18, 0x3b, 0x36, 0x54, 0xc0, 0x9c, 0xa1, 0xdf, 0xd4, - 0xaf, 0x36, 0xf5, 0xb2, 0x90, 0x12, 0xe1, 0x70, 0xa4, 0xe4, 0xe8, 0xba, 0xe1, 0x7c, 0xe6, 0xb4, - 0x88, 0x13, 0xe5, 0x5f, 0x2b, 0x55, 0x6e, 0xe9, 0x65, 0x61, 0x66, 0x32, 0xff, 0x9a, 0xe5, 0xf9, - 0x8e, 0x3d, 0xdd, 0xae, 0x56, 0xdd, 0x7c, 0x29, 0x71, 0xcf, 0x5f, 0x4a, 0xdc, 0x97, 0x5b, 0x12, - 0xb7, 0xb9, 0x25, 0xf1, 0xcf, 0xb6, 0x24, 0xfe, 0xe7, 0x2d, 0x89, 0x7f, 0xb8, 0x2d, 0x71, 0xcf, - 0xb6, 0x25, 0xee, 0xf9, 0xb6, 0xc4, 0x7d, 0xfc, 0xf7, 0xf6, 0x37, 0xf1, 0x1f, 0xc3, 0x7a, 0x3a, - 0x72, 0x98, 0xcb, 0x7f, 0x05, 0x00, 0x00, 0xff, 0xff, 0x41, 0x42, 0x32, 0xc2, 0x47, 0x0c, 0x00, - 0x00, + // 1187 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x57, 0x31, 0x6f, 0xdb, 0x46, + 0x14, 0x26, 0x25, 0x59, 0xb6, 0x4f, 0xb2, 0xc2, 0x9c, 0xdd, 0x44, 0x25, 0x0a, 0x92, 0x51, 0x82, + 0xc0, 0x4d, 0x11, 0xaa, 0x71, 0x86, 0x02, 0x19, 0x8a, 0x8a, 0x11, 0x93, 0x28, 0x88, 0x25, 0x81, + 0x12, 0x1c, 0xb8, 0x45, 0x41, 0xd0, 0x22, 0x4d, 0xb3, 0xa1, 0x78, 0xaa, 0xee, 0xa4, 0x5a, 0x5b, + 0xd1, 0xa1, 0x08, 0x34, 0x65, 0xcc, 0x22, 0xc0, 0x40, 0x33, 0x04, 0x45, 0x87, 0xfe, 0x0c, 0x6f, + 0xcd, 0x52, 0x20, 0xe8, 0xa0, 0x34, 0xf6, 0xd0, 0xa2, 0xe8, 0xe4, 0xa5, 0x40, 0xa7, 0x42, 0xbc, + 0xa3, 0x2d, 0xd9, 0x4e, 0x1d, 0x23, 0x2d, 0x50, 0x74, 0xb1, 0xcd, 0x77, 0xdf, 0xfb, 0xde, 0xbd, + 0xef, 0xde, 0x7d, 0x07, 0x83, 0xf3, 0x9b, 0x79, 0x17, 0x75, 0xf3, 0xa4, 0xd7, 0x72, 0x30, 0xfd, + 0xa9, 0xb6, 0xda, 0x88, 0x20, 0x38, 0xdf, 0x40, 0xb8, 0x89, 0xb0, 0x89, 0xed, 0x07, 0xea, 0xa6, + 0xea, 0xa2, 0xae, 0xda, 0xbd, 0x26, 0x9e, 0x3d, 0x82, 0x13, 0x2f, 0x93, 0x0d, 0xaf, 0x6d, 0x9b, + 0x2d, 0xab, 0x4d, 0x7a, 0xf9, 0x30, 0x94, 0x77, 0x91, 0x8b, 0x0e, 0xfe, 0x62, 0x38, 0xd9, 0x45, + 0xc8, 0xf5, 0x1d, 0x0a, 0x59, 0xeb, 0xac, 0xe7, 0x89, 0xd7, 0x74, 0x30, 0xb1, 0x9a, 0x2d, 0x0a, + 0xc8, 0xfd, 0xc1, 0x83, 0xb7, 0x96, 0xb1, 0x5b, 0xeb, 0xac, 0x35, 0x3d, 0x52, 0x6d, 0xa3, 0x16, + 0xc2, 0x96, 0xaf, 0x59, 0xd8, 0x81, 0x0f, 0x79, 0x70, 0xc6, 0x0b, 0x3c, 0xe2, 0x59, 0xbe, 0x69, + 0x3b, 0x2d, 0x84, 0x3d, 0x92, 0xe5, 0x95, 0xf8, 0x62, 0x6a, 0x69, 0x5e, 0x1d, 0xdb, 0x65, 0xf7, + 0x9a, 0x7a, 0x13, 0x79, 0x81, 0x76, 0x77, 0x7b, 0x28, 0x73, 0x7b, 0x43, 0xf9, 0x5c, 0xcf, 0x6a, + 0xfa, 0x37, 0x72, 0x87, 0x32, 0x73, 0xdf, 0xbe, 0x90, 0x17, 0x5d, 0x8f, 0x6c, 0x74, 0xd6, 0xd4, + 0x06, 0x6a, 0xe6, 0x29, 0x01, 0xfb, 0x75, 0x15, 0xdb, 0x0f, 0x58, 0x77, 0x23, 0x2a, 0x6c, 0x64, + 0x58, 0x76, 0x91, 0x26, 0xc3, 0x65, 0x30, 0xd3, 0x0a, 0xb7, 0xe6, 0xb4, 0xb3, 0x31, 0x85, 0x5f, + 0x4c, 0x6b, 0xd7, 0xfe, 0x1c, 0xca, 0x57, 0x5f, 0x83, 0xaf, 0xd0, 0x68, 0x14, 0x6c, 0xbb, 0xed, + 0x60, 0x6c, 0xec, 0x53, 0xdc, 0x48, 0xfc, 0xba, 0x25, 0xf3, 0xb9, 0x5f, 0x78, 0x30, 0xbd, 0x8c, + 0xdd, 0x15, 0x44, 0x1c, 0x58, 0x07, 0xa9, 0x16, 0xeb, 0xdd, 0xf4, 0xec, 0x2c, 0xaf, 0xf0, 0x8b, + 0x09, 0xed, 0xfa, 0xce, 0x50, 0x06, 0x91, 0x24, 0xa5, 0xe2, 0x6f, 0x43, 0x79, 0x1c, 0xb4, 0x37, + 0x94, 0x21, 0x6d, 0x75, 0x2c, 0x98, 0x33, 0x40, 0xf4, 0x55, 0xb2, 0xe1, 0x6d, 0x30, 0xd5, 0x45, + 0xe4, 0x4d, 0xf6, 0x4c, 0xf3, 0xe1, 0x07, 0x20, 0x89, 0x5a, 0xc4, 0x43, 0x41, 0x36, 0xae, 0xf0, + 0x8b, 0x99, 0x25, 0x59, 0x3d, 0x66, 0x4c, 0xd4, 0x51, 0x27, 0x95, 0x10, 0x66, 0x30, 0x38, 0xeb, + 0xf4, 0x71, 0x0c, 0x80, 0x65, 0xec, 0x46, 0x6a, 0xfe, 0x3b, 0xcd, 0x56, 0xc0, 0x2c, 0x3b, 0x6b, + 0xf4, 0x06, 0x0d, 0x1f, 0x70, 0xc0, 0x4f, 0x41, 0xd2, 0x6a, 0xa2, 0x4e, 0x40, 0xb2, 0xf1, 0x57, + 0x4f, 0xdd, 0xfb, 0xa3, 0xa9, 0x3b, 0xd5, 0x6c, 0x31, 0x52, 0x26, 0xcd, 0x3d, 0x90, 0xae, 0x3b, + 0x9b, 0xfb, 0x83, 0x0f, 0x17, 0xc0, 0x14, 0xf1, 0x88, 0xef, 0x84, 0xaa, 0xcc, 0x1a, 0xf4, 0x03, + 0x2a, 0x20, 0x65, 0x3b, 0xb8, 0xd1, 0xf6, 0xe8, 0x21, 0xc4, 0xc2, 0xb5, 0xf1, 0x10, 0x63, 0xfb, + 0x3a, 0x06, 0xa6, 0x23, 0x95, 0xf5, 0xe3, 0x54, 0xbe, 0x34, 0xa9, 0xf2, 0xff, 0x56, 0xd6, 0x1f, + 0x92, 0x20, 0x3d, 0x61, 0x26, 0xda, 0x71, 0x6a, 0x5c, 0x38, 0x32, 0x73, 0xb1, 0x70, 0xd4, 0x66, + 0x99, 0x85, 0x1c, 0x92, 0xe2, 0x3e, 0x48, 0x62, 0x62, 0x91, 0x0e, 0x0e, 0x75, 0xc8, 0x2c, 0x5d, + 0x3c, 0xf6, 0x16, 0x44, 0x7c, 0xb5, 0x10, 0xaa, 0x89, 0x07, 0x96, 0xb4, 0xbf, 0x01, 0xca, 0x92, + 0x33, 0x18, 0x1d, 0xfc, 0x1c, 0xc0, 0x75, 0x2f, 0xb0, 0x7c, 0x93, 0x58, 0xbe, 0xdf, 0x33, 0xdb, + 0x0e, 0xee, 0xf8, 0x24, 0xbc, 0x6a, 0xa9, 0x25, 0xe5, 0xd8, 0x22, 0xf5, 0x11, 0xd0, 0x08, 0x71, + 0xda, 0x05, 0x66, 0x7c, 0x6f, 0xd3, 0x2a, 0x47, 0x99, 0x72, 0x86, 0x10, 0x06, 0xc7, 0x92, 0xe0, + 0x27, 0x20, 0x85, 0x43, 0xcb, 0x35, 0x47, 0x86, 0x9c, 0x4d, 0x84, 0xb5, 0x44, 0x95, 0xba, 0xb5, + 0x1a, 0xb9, 0xb5, 0x5a, 0x8f, 0xdc, 0x5a, 0x93, 0x58, 0x15, 0x36, 0x2f, 0x63, 0xc9, 0xb9, 0x47, + 0x2f, 0x64, 0xde, 0x00, 0x34, 0x32, 0x4a, 0x80, 0x1e, 0x10, 0xd8, 0x79, 0x9b, 0x4e, 0x60, 0xd3, + 0x0a, 0x53, 0x27, 0x56, 0xb8, 0xc8, 0x2a, 0x9c, 0xa7, 0x15, 0x0e, 0x33, 0xd0, 0x32, 0x19, 0x16, + 0xd6, 0x03, 0x3b, 0x2c, 0xf5, 0x15, 0x0f, 0xe6, 0x08, 0x22, 0x63, 0x4f, 0x44, 0xf2, 0xd5, 0x53, + 0x75, 0x87, 0x55, 0x58, 0xa0, 0x15, 0x26, 0xf2, 0x4e, 0xf7, 0x40, 0xa4, 0xc3, 0xdc, 0xe8, 0xaa, + 0xf9, 0xe0, 0x6c, 0x17, 0x11, 0x2f, 0x70, 0x47, 0x27, 0xdb, 0x66, 0x92, 0x4e, 0x9f, 0xd8, 0xf0, + 0x25, 0xb6, 0x9d, 0x2c, 0xdd, 0xce, 0x11, 0x0a, 0xda, 0xf1, 0x19, 0x1a, 0xaf, 0x8d, 0xc2, 0x61, + 0xcb, 0xeb, 0x80, 0x85, 0x0e, 0xc4, 0x9d, 0x39, 0xb1, 0x56, 0x6e, 0xf2, 0x75, 0x3c, 0x44, 0x40, + 0x2b, 0xcd, 0xd1, 0x28, 0x93, 0xf6, 0x46, 0xfa, 0xf1, 0x96, 0xcc, 0x3f, 0xdd, 0x92, 0xf9, 0xf0, + 0x46, 0x6d, 0xc7, 0x40, 0x6a, 0x7c, 0x80, 0x3e, 0x02, 0xf1, 0x9e, 0x83, 0xa9, 0x4d, 0x69, 0xea, + 0x88, 0xfd, 0xa7, 0xa1, 0x7c, 0xf9, 0x35, 0x04, 0x2c, 0x05, 0xc4, 0x18, 0xa5, 0xc2, 0x3b, 0x60, + 0xda, 0x5a, 0xc3, 0xc4, 0xf2, 0x98, 0xa1, 0x9d, 0x9a, 0x25, 0x4a, 0x87, 0x1f, 0x82, 0x58, 0x80, + 0xc2, 0xfb, 0x72, 0x7a, 0x92, 0x58, 0x80, 0xa0, 0x0b, 0xd2, 0x01, 0x32, 0xbf, 0xf0, 0xc8, 0x86, + 0xd9, 0x75, 0x08, 0x0a, 0x6f, 0xc3, 0xac, 0xa6, 0x9f, 0x8e, 0x69, 0x6f, 0x28, 0xcf, 0x53, 0x71, + 0xc7, 0xb9, 0x72, 0x06, 0x08, 0xd0, 0x7d, 0x8f, 0x6c, 0xac, 0x38, 0x04, 0x31, 0x73, 0xfa, 0x91, + 0x07, 0x89, 0xf0, 0xd5, 0xff, 0x87, 0x2c, 0xfa, 0x3f, 0xf2, 0xcc, 0x5f, 0xf9, 0x8e, 0x07, 0xe0, + 0x60, 0x11, 0x8a, 0x60, 0x4a, 0x5f, 0xae, 0xd6, 0x57, 0x05, 0x4e, 0x3c, 0xd3, 0x1f, 0x28, 0x29, + 0x1a, 0xd6, 0x9b, 0x2d, 0xd2, 0x83, 0xe7, 0x40, 0x7c, 0x55, 0xaf, 0x09, 0xbc, 0x38, 0xd7, 0x1f, + 0x28, 0xb3, 0x74, 0x65, 0xd5, 0xc1, 0x50, 0x02, 0xd3, 0x05, 0xad, 0x56, 0x2f, 0x94, 0xca, 0x42, + 0x4c, 0x3c, 0xdb, 0x1f, 0x28, 0x73, 0x74, 0xad, 0xc0, 0x4e, 0x7a, 0x01, 0xc4, 0xca, 0x15, 0x21, + 0x2e, 0xa6, 0xfb, 0x03, 0x65, 0x86, 0x2e, 0x95, 0x11, 0xbc, 0x0c, 0xd2, 0xe5, 0x8a, 0x79, 0xbf, + 0x54, 0xbf, 0x63, 0xae, 0xe8, 0xf5, 0x8a, 0x90, 0x10, 0x17, 0xfa, 0x03, 0x45, 0x88, 0xd6, 0x23, + 0xf9, 0xc5, 0xf4, 0xc3, 0x6f, 0x24, 0xee, 0xe9, 0x13, 0x89, 0xfb, 0xfe, 0x89, 0xc4, 0x5d, 0xf9, + 0x9d, 0x07, 0x99, 0x49, 0xb3, 0x1e, 0x6d, 0xab, 0x5c, 0xba, 0x27, 0x70, 0x74, 0x5b, 0x34, 0x58, + 0xf6, 0x7c, 0xf8, 0x1e, 0xc8, 0x14, 0xf5, 0x6a, 0xa5, 0x56, 0xaa, 0x9b, 0x55, 0xdd, 0x28, 0x55, + 0x8a, 0x02, 0x2f, 0x9e, 0xef, 0x0f, 0x94, 0x79, 0x0a, 0x61, 0x3e, 0x50, 0x75, 0xda, 0x1e, 0xb2, + 0xe1, 0xbb, 0x60, 0x6e, 0xa5, 0x52, 0x2f, 0x95, 0x6f, 0x47, 0xd8, 0x98, 0x78, 0xae, 0x3f, 0x50, + 0x20, 0xc5, 0xae, 0x84, 0x77, 0x8c, 0x41, 0xdf, 0x01, 0xc9, 0x6a, 0xa1, 0x56, 0xd3, 0x8b, 0x42, + 0x5c, 0x14, 0xfa, 0x03, 0x25, 0x4d, 0x31, 0x55, 0x0b, 0x63, 0xc7, 0x86, 0x0a, 0x98, 0x31, 0xf4, + 0xbb, 0xfa, 0xcd, 0xba, 0x5e, 0x14, 0x12, 0x22, 0xec, 0x0f, 0x94, 0x0c, 0x5d, 0x37, 0x9c, 0xcf, + 0x9c, 0x06, 0x71, 0xc2, 0xfc, 0x5b, 0x85, 0xd2, 0x3d, 0xbd, 0x28, 0x4c, 0x8d, 0xe7, 0xdf, 0xb2, + 0x3c, 0xdf, 0xb1, 0x27, 0xdb, 0xd5, 0xca, 0xdb, 0x2f, 0x25, 0xee, 0xf9, 0x4b, 0x89, 0xfb, 0x72, + 0x47, 0xe2, 0xb6, 0x77, 0x24, 0xfe, 0xd9, 0x8e, 0xc4, 0xff, 0xbc, 0x23, 0xf1, 0x8f, 0x76, 0x25, + 0xee, 0xd9, 0xae, 0xc4, 0x3d, 0xdf, 0x95, 0xb8, 0x8f, 0xff, 0xde, 0x02, 0xc7, 0xfe, 0x6b, 0x58, + 0x4b, 0x86, 0x2e, 0x73, 0xfd, 0xaf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xe0, 0x2e, 0x55, 0x4b, + 0x0c, 0x00, 0x00, } func (this *MsgSubmitProposalBase) Equal(that interface{}) bool { @@ -676,6 +676,56 @@ func (this *Deposit) Equal(that interface{}) bool { } return true } +func (this *ProposalBase) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*ProposalBase) + if !ok { + that2, ok := that.(ProposalBase) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.ProposalID != that1.ProposalID { + return false + } + if this.Status != that1.Status { + return false + } + if !this.FinalTallyResult.Equal(&that1.FinalTallyResult) { + return false + } + if !this.SubmitTime.Equal(that1.SubmitTime) { + return false + } + if !this.DepositEndTime.Equal(that1.DepositEndTime) { + return false + } + if len(this.TotalDeposit) != len(that1.TotalDeposit) { + return false + } + for i := range this.TotalDeposit { + if !this.TotalDeposit[i].Equal(&that1.TotalDeposit[i]) { + return false + } + } + if !this.VotingStartTime.Equal(that1.VotingStartTime) { + return false + } + if !this.VotingEndTime.Equal(that1.VotingEndTime) { + return false + } + return true +} func (this *TallyResult) Equal(that interface{}) bool { if that == nil { return this == nil diff --git a/x/gov/types/types.proto b/x/gov/types/types.proto index 6b8b50944133..855826516a99 100644 --- a/x/gov/types/types.proto +++ b/x/gov/types/types.proto @@ -91,6 +91,7 @@ message Deposit { // all static fields (i.e fields excluding the dynamic Content). A full proposal // extends the ProposalBase with Content. message ProposalBase { + option (gogoproto.equal) = true; option (gogoproto.goproto_stringer) = true; option (gogoproto.face) = true; From 2706854efffcbce5180871a78240c77ddae80ca4 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 2 Mar 2020 22:54:38 +0100 Subject: [PATCH 335/529] refactor TestHandleAlreadyJailed to simapp --- x/slashing/keeper/keeper_test.go | 54 ++++++++++++++ x/slashing/keeper/old_keeper_test.go | 101 +-------------------------- 2 files changed, 55 insertions(+), 100 deletions(-) diff --git a/x/slashing/keeper/keeper_test.go b/x/slashing/keeper/keeper_test.go index 785682995af5..b1b3e5eeac92 100644 --- a/x/slashing/keeper/keeper_test.go +++ b/x/slashing/keeper/keeper_test.go @@ -63,3 +63,57 @@ func TestHandleNewValidator(t *testing.T) { expTokens := sdk.TokensFromConsensusPower(100) require.Equal(t, expTokens.Int64(), app.BankKeeper.GetBalance(ctx, bondPool.GetAddress(), app.StakingKeeper.BondDenom(ctx)).Amount.Int64()) } + +// Test a jailed validator being "down" twice +// Ensure that they're only slashed once +func TestHandleAlreadyJailed(t *testing.T) { + // initial setup + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + power := int64(100) + + amt := sdk.TokensFromConsensusPower(power) + addrDels := simapp.AddTestAddrsIncremental(app, ctx, 1, sdk.TokensFromConsensusPower(200)) + valAddrs := simapp.ConvertAddrsToValAddrs(addrDels) + pks := simapp.CreateTestPubKeys(1) + + addr, val := valAddrs[0], pks[0] + sh := staking.NewHandler(app.StakingKeeper) + res, err := sh(ctx, keeper.NewTestMsgCreateValidator(addr, val, amt)) + require.NoError(t, err) + require.NotNil(t, res) + + staking.EndBlocker(ctx, app.StakingKeeper) + + // 1000 first blocks OK + height := int64(0) + for ; height < app.SlashingKeeper.SignedBlocksWindow(ctx); height++ { + ctx = ctx.WithBlockHeight(height) + app.SlashingKeeper.HandleValidatorSignature(ctx, val.Address(), power, true) + } + + // 501 blocks missed + for ; height < app.SlashingKeeper.SignedBlocksWindow(ctx)+(app.SlashingKeeper.SignedBlocksWindow(ctx)-app.SlashingKeeper.MinSignedPerWindow(ctx))+1; height++ { + ctx = ctx.WithBlockHeight(height) + app.SlashingKeeper.HandleValidatorSignature(ctx, val.Address(), power, false) + } + + // end block + staking.EndBlocker(ctx, app.StakingKeeper) + + // validator should have been jailed and slashed + validator, _ := app.StakingKeeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) + require.Equal(t, sdk.Unbonding, validator.GetStatus()) + + // validator should have been slashed + resultingTokens := amt.Sub(sdk.TokensFromConsensusPower(1)) + require.Equal(t, resultingTokens, validator.GetTokens()) + + // another block missed + ctx = ctx.WithBlockHeight(height) + app.SlashingKeeper.HandleValidatorSignature(ctx, val.Address(), power, false) + + // validator should not have been slashed twice + validator, _ = app.StakingKeeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) + require.Equal(t, resultingTokens, validator.GetTokens()) +} diff --git a/x/slashing/keeper/old_keeper_test.go b/x/slashing/keeper/old_keeper_test.go index 4f4f555bbffc..6deb483936a1 100644 --- a/x/slashing/keeper/old_keeper_test.go +++ b/x/slashing/keeper/old_keeper_test.go @@ -1,112 +1,13 @@ package keeper import ( - "testing" - "time" - "github.com/stretchr/testify/require" + "testing" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/slashing/types" "github.com/cosmos/cosmos-sdk/x/staking" ) -// Test a new validator entering the validator set -// Ensure that SigningInfo.StartHeight is set correctly -// and that they are not immediately jailed -func TestHandleNewValidator(t *testing.T) { - // initial setup - ctx, bk, sk, _, keeper := CreateTestInput(t, TestParams()) - addr, val := Addrs[0], Pks[0] - amt := sdk.TokensFromConsensusPower(100) - sh := staking.NewHandler(sk) - - // 1000 first blocks not a validator - ctx = ctx.WithBlockHeight(keeper.SignedBlocksWindow(ctx) + 1) - - // Validator created - res, err := sh(ctx, NewTestMsgCreateValidator(addr, val, amt)) - require.NoError(t, err) - require.NotNil(t, res) - - staking.EndBlocker(ctx, sk) - - require.Equal( - t, bk.GetAllBalances(ctx, sdk.AccAddress(addr)), - sdk.NewCoins(sdk.NewCoin(sk.GetParams(ctx).BondDenom, InitTokens.Sub(amt))), - ) - require.Equal(t, amt, sk.Validator(ctx, addr).GetBondedTokens()) - - // Now a validator, for two blocks - keeper.HandleValidatorSignature(ctx, val.Address(), 100, true) - ctx = ctx.WithBlockHeight(keeper.SignedBlocksWindow(ctx) + 2) - keeper.HandleValidatorSignature(ctx, val.Address(), 100, false) - - info, found := keeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) - require.True(t, found) - require.Equal(t, keeper.SignedBlocksWindow(ctx)+1, info.StartHeight) - require.Equal(t, int64(2), info.IndexOffset) - require.Equal(t, int64(1), info.MissedBlocksCounter) - require.Equal(t, time.Unix(0, 0).UTC(), info.JailedUntil) - - // validator should be bonded still, should not have been jailed or slashed - validator, _ := sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) - require.Equal(t, sdk.Bonded, validator.GetStatus()) - bondPool := sk.GetBondedPool(ctx) - expTokens := sdk.TokensFromConsensusPower(100) - require.Equal(t, expTokens.Int64(), bk.GetBalance(ctx, bondPool.GetAddress(), sk.BondDenom(ctx)).Amount.Int64()) -} - -// Test a jailed validator being "down" twice -// Ensure that they're only slashed once -func TestHandleAlreadyJailed(t *testing.T) { - - // initial setup - ctx, _, sk, _, keeper := CreateTestInput(t, types.DefaultParams()) - power := int64(100) - amt := sdk.TokensFromConsensusPower(power) - addr, val := Addrs[0], Pks[0] - sh := staking.NewHandler(sk) - res, err := sh(ctx, NewTestMsgCreateValidator(addr, val, amt)) - require.NoError(t, err) - require.NotNil(t, res) - - staking.EndBlocker(ctx, sk) - - // 1000 first blocks OK - height := int64(0) - for ; height < keeper.SignedBlocksWindow(ctx); height++ { - ctx = ctx.WithBlockHeight(height) - keeper.HandleValidatorSignature(ctx, val.Address(), power, true) - } - - // 501 blocks missed - for ; height < keeper.SignedBlocksWindow(ctx)+(keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx))+1; height++ { - ctx = ctx.WithBlockHeight(height) - keeper.HandleValidatorSignature(ctx, val.Address(), power, false) - } - - // end block - staking.EndBlocker(ctx, sk) - - // validator should have been jailed and slashed - validator, _ := sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) - require.Equal(t, sdk.Unbonding, validator.GetStatus()) - - // validator should have been slashed - resultingTokens := amt.Sub(sdk.TokensFromConsensusPower(1)) - require.Equal(t, resultingTokens, validator.GetTokens()) - - // another block missed - ctx = ctx.WithBlockHeight(height) - keeper.HandleValidatorSignature(ctx, val.Address(), power, false) - - // validator should not have been slashed twice - validator, _ = sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) - require.Equal(t, resultingTokens, validator.GetTokens()) - -} - // Test a validator dipping in and out of the validator set // Ensure that missed blocks are tracked correctly and that // the start height of the signing info is reset correctly From 1a25cdae6f9e035876b1509009ab9e708f9901bc Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Mon, 2 Mar 2020 17:21:00 -0500 Subject: [PATCH 336/529] Update tests --- x/gov/keeper/proposal_test.go | 2 +- x/gov/types/proposal.go | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/x/gov/keeper/proposal_test.go b/x/gov/keeper/proposal_test.go index 99169d176946..a02b6da72a97 100644 --- a/x/gov/keeper/proposal_test.go +++ b/x/gov/keeper/proposal_test.go @@ -26,7 +26,7 @@ func TestGetSetProposal(t *testing.T) { gotProposal, ok := app.GovKeeper.GetProposal(ctx, proposalID) require.True(t, ok) - require.Equal(t, proposal.String(), gotProposal.String()) + require.True(t, proposal.Equal(gotProposal)) } func TestActivateVotingPeriod(t *testing.T) { diff --git a/x/gov/types/proposal.go b/x/gov/types/proposal.go index 2ba08980ebd3..9e65ec3c9054 100644 --- a/x/gov/types/proposal.go +++ b/x/gov/types/proposal.go @@ -37,6 +37,11 @@ func NewProposal(content Content, id uint64, submitTime, depositEndTime time.Tim } } +// Equal returns true if two Proposal types are equal. +func (p Proposal) Equal(other Proposal) bool { + return p.ProposalBase.Equal(other.ProposalBase) && p.Content.String() == other.Content.String() +} + // String implements stringer interface func (p Proposal) String() string { out, _ := yaml.Marshal(p) @@ -189,14 +194,14 @@ const ( ProposalTypeText string = "Text" ) +// Implements Content Interface +var _ Content = TextProposal{} + // NewTextProposal creates a text proposal Content func NewTextProposal(title, description string) Content { return TextProposal{title, description} } -// Implements Content Interface -var _ Content = TextProposal{} - // GetTitle returns the proposal title func (tp TextProposal) GetTitle() string { return tp.Title } From 05cef02b4d98d6aacc20796296ec375adb172c28 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Mon, 2 Mar 2020 17:24:10 -0500 Subject: [PATCH 337/529] Add MsgSubmitProposal back to codec --- x/gov/types/codec.go | 1 + 1 file changed, 1 insertion(+) diff --git a/x/gov/types/codec.go b/x/gov/types/codec.go index ba9e6827c39a..e4d7e16a32a4 100644 --- a/x/gov/types/codec.go +++ b/x/gov/types/codec.go @@ -17,6 +17,7 @@ type Codec interface { func RegisterCodec(cdc *codec.Codec) { cdc.RegisterInterface((*Content)(nil), nil) cdc.RegisterConcrete(MsgSubmitProposalBase{}, "cosmos-sdk/MsgSubmitProposalBase", nil) + cdc.RegisterConcrete(MsgSubmitProposal{}, "cosmos-sdk/MsgSubmitProposal", nil) cdc.RegisterConcrete(MsgDeposit{}, "cosmos-sdk/MsgDeposit", nil) cdc.RegisterConcrete(MsgVote{}, "cosmos-sdk/MsgVote", nil) cdc.RegisterConcrete(TextProposal{}, "cosmos-sdk/TextProposal", nil) From 863dc1484e1fdee09f57f30d946236ed1630c5e9 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Tue, 3 Mar 2020 10:51:06 +0100 Subject: [PATCH 338/529] make test pass --- simapp/test_helpers.go | 19 +++++ x/slashing/keeper/keeper_test.go | 122 ++++++++++++++++++++++++++ x/slashing/keeper/old_keeper_test.go | 123 --------------------------- 3 files changed, 141 insertions(+), 123 deletions(-) diff --git a/simapp/test_helpers.go b/simapp/test_helpers.go index a557e7f5d397..99cee407040c 100644 --- a/simapp/test_helpers.go +++ b/simapp/test_helpers.go @@ -116,6 +116,25 @@ func createIncrementalAccounts(accNum int) []sdk.AccAddress { return addresses } +func AddTestAddrsFromPubKeys(app *SimApp, ctx sdk.Context, pubKeys []crypto.PubKey, accAmt sdk.Int) { + initCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), accAmt)) + totalSupply := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), accAmt.MulRaw(int64(len(pubKeys))))) + prevSupply := app.SupplyKeeper.GetSupply(ctx) + app.SupplyKeeper.SetSupply(ctx, supply.NewSupply(prevSupply.GetTotal().Add(totalSupply...))) + + // fill all the addresses with some coins, set the loose pool tokens simultaneously + for _, pubKey := range pubKeys { + acc := app.AccountKeeper.NewAccountWithAddress(ctx, sdk.AccAddress(pubKey.Address())) + app.AccountKeeper.SetAccount(ctx, acc) + + _, err := app.BankKeeper.AddCoins(ctx, sdk.AccAddress(pubKey.Address()), initCoins) + if err != nil { + panic(err) + } + } + return +} + // AddTestAddrs constructs and returns accNum amount of accounts with an // initial balance of accAmt in random order func AddTestAddrs(app *SimApp, ctx sdk.Context, accNum int, accAmt sdk.Int) []sdk.AccAddress { diff --git a/x/slashing/keeper/keeper_test.go b/x/slashing/keeper/keeper_test.go index b1b3e5eeac92..ce28a5607b23 100644 --- a/x/slashing/keeper/keeper_test.go +++ b/x/slashing/keeper/keeper_test.go @@ -117,3 +117,125 @@ func TestHandleAlreadyJailed(t *testing.T) { validator, _ = app.StakingKeeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) require.Equal(t, resultingTokens, validator.GetTokens()) } + +// Test a validator dipping in and out of the validator set +// Ensure that missed blocks are tracked correctly and that +// the start height of the signing info is reset correctly +func TestValidatorDippingInAndOut(t *testing.T) { + + // initial setup + // TestParams set the SignedBlocksWindow to 1000 and MaxMissedBlocksPerWindow to 500 + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + app.SlashingKeeper.SetParams(ctx, keeper.TestParams()) + + params := app.StakingKeeper.GetParams(ctx) + params.MaxValidators = 1 + app.StakingKeeper.SetParams(ctx, params) + power := int64(100) + + pks := simapp.CreateTestPubKeys(3) + simapp.AddTestAddrsFromPubKeys(app, ctx, pks, sdk.TokensFromConsensusPower(200)) + + amt := sdk.TokensFromConsensusPower(power) + addr, val := pks[0].Address(), pks[0] + consAddr := sdk.ConsAddress(addr) + sh := staking.NewHandler(app.StakingKeeper) + res, err := sh(ctx, keeper.NewTestMsgCreateValidator(sdk.ValAddress(addr), val, amt)) + require.NoError(t, err) + require.NotNil(t, res) + + staking.EndBlocker(ctx, app.StakingKeeper) + + // 100 first blocks OK + height := int64(0) + for ; height < int64(100); height++ { + ctx = ctx.WithBlockHeight(height) + app.SlashingKeeper.HandleValidatorSignature(ctx, val.Address(), power, true) + } + + // kick first validator out of validator set + newAmt := sdk.TokensFromConsensusPower(101) + res, err = sh(ctx, keeper.NewTestMsgCreateValidator(sdk.ValAddress(pks[1].Address()), pks[1], newAmt)) + require.NoError(t, err) + require.NotNil(t, res) + + validatorUpdates := staking.EndBlocker(ctx, app.StakingKeeper) + require.Equal(t, 2, len(validatorUpdates)) + validator, _ := app.StakingKeeper.GetValidator(ctx, sdk.ValAddress(addr)) + require.Equal(t, sdk.Unbonding, validator.Status) + + // 600 more blocks happened + height = int64(700) + ctx = ctx.WithBlockHeight(height) + + // validator added back in + delTokens := sdk.TokensFromConsensusPower(50) + res, err = sh(ctx, keeper.NewTestMsgDelegate(sdk.AccAddress(pks[2].Address()), sdk.ValAddress(pks[0].Address()), delTokens)) + require.NoError(t, err) + require.NotNil(t, res) + + validatorUpdates = staking.EndBlocker(ctx, app.StakingKeeper) + require.Equal(t, 2, len(validatorUpdates)) + validator, _ = app.StakingKeeper.GetValidator(ctx, sdk.ValAddress(addr)) + require.Equal(t, sdk.Bonded, validator.Status) + newPower := int64(150) + + // validator misses a block + app.SlashingKeeper.HandleValidatorSignature(ctx, val.Address(), newPower, false) + height++ + + // shouldn't be jailed/kicked yet + validator, _ = app.StakingKeeper.GetValidator(ctx, sdk.ValAddress(addr)) + require.Equal(t, sdk.Bonded, validator.Status) + + // validator misses 500 more blocks, 501 total + latest := height + for ; height < latest+500; height++ { + ctx = ctx.WithBlockHeight(height) + app.SlashingKeeper.HandleValidatorSignature(ctx, val.Address(), newPower, false) + } + + // should now be jailed & kicked + staking.EndBlocker(ctx, app.StakingKeeper) + validator, _ = app.StakingKeeper.GetValidator(ctx, sdk.ValAddress(addr)) + require.Equal(t, sdk.Unbonding, validator.Status) + + // check all the signing information + signInfo, found := app.SlashingKeeper.GetValidatorSigningInfo(ctx, consAddr) + require.True(t, found) + require.Equal(t, int64(0), signInfo.MissedBlocksCounter) + require.Equal(t, int64(0), signInfo.IndexOffset) + // array should be cleared + for offset := int64(0); offset < app.SlashingKeeper.SignedBlocksWindow(ctx); offset++ { + missed := app.SlashingKeeper.GetValidatorMissedBlockBitArray(ctx, consAddr, offset) + require.False(t, missed) + } + + // some blocks pass + height = int64(5000) + ctx = ctx.WithBlockHeight(height) + + // validator rejoins and starts signing again + app.StakingKeeper.Unjail(ctx, consAddr) + app.SlashingKeeper.HandleValidatorSignature(ctx, val.Address(), newPower, true) + height++ + + // validator should not be kicked since we reset counter/array when it was jailed + staking.EndBlocker(ctx, app.StakingKeeper) + validator, _ = app.StakingKeeper.GetValidator(ctx, sdk.ValAddress(addr)) + require.Equal(t, sdk.Bonded, validator.Status) + + // validator misses 501 blocks + latest = height + for ; height < latest+501; height++ { + ctx = ctx.WithBlockHeight(height) + app.SlashingKeeper.HandleValidatorSignature(ctx, val.Address(), newPower, false) + } + + // validator should now be jailed & kicked + staking.EndBlocker(ctx, app.StakingKeeper) + validator, _ = app.StakingKeeper.GetValidator(ctx, sdk.ValAddress(addr)) + require.Equal(t, sdk.Unbonding, validator.Status) + +} diff --git a/x/slashing/keeper/old_keeper_test.go b/x/slashing/keeper/old_keeper_test.go index 6deb483936a1..b55569d4a442 100644 --- a/x/slashing/keeper/old_keeper_test.go +++ b/x/slashing/keeper/old_keeper_test.go @@ -1,124 +1 @@ package keeper - -import ( - "github.com/stretchr/testify/require" - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/staking" -) - -// Test a validator dipping in and out of the validator set -// Ensure that missed blocks are tracked correctly and that -// the start height of the signing info is reset correctly -func TestValidatorDippingInAndOut(t *testing.T) { - - // initial setup - // TestParams set the SignedBlocksWindow to 1000 and MaxMissedBlocksPerWindow to 500 - ctx, _, sk, _, keeper := CreateTestInput(t, TestParams()) - params := sk.GetParams(ctx) - params.MaxValidators = 1 - sk.SetParams(ctx, params) - power := int64(100) - amt := sdk.TokensFromConsensusPower(power) - addr, val := Addrs[0], Pks[0] - consAddr := sdk.ConsAddress(addr) - sh := staking.NewHandler(sk) - res, err := sh(ctx, NewTestMsgCreateValidator(addr, val, amt)) - require.NoError(t, err) - require.NotNil(t, res) - - staking.EndBlocker(ctx, sk) - - // 100 first blocks OK - height := int64(0) - for ; height < int64(100); height++ { - ctx = ctx.WithBlockHeight(height) - keeper.HandleValidatorSignature(ctx, val.Address(), power, true) - } - - // kick first validator out of validator set - newAmt := sdk.TokensFromConsensusPower(101) - res, err = sh(ctx, NewTestMsgCreateValidator(Addrs[1], Pks[1], newAmt)) - require.NoError(t, err) - require.NotNil(t, res) - - validatorUpdates := staking.EndBlocker(ctx, sk) - require.Equal(t, 2, len(validatorUpdates)) - validator, _ := sk.GetValidator(ctx, addr) - require.Equal(t, sdk.Unbonding, validator.Status) - - // 600 more blocks happened - height = int64(700) - ctx = ctx.WithBlockHeight(height) - - // validator added back in - delTokens := sdk.TokensFromConsensusPower(50) - res, err = sh(ctx, NewTestMsgDelegate(sdk.AccAddress(Addrs[2]), Addrs[0], delTokens)) - require.NoError(t, err) - require.NotNil(t, res) - - validatorUpdates = staking.EndBlocker(ctx, sk) - require.Equal(t, 2, len(validatorUpdates)) - validator, _ = sk.GetValidator(ctx, addr) - require.Equal(t, sdk.Bonded, validator.Status) - newPower := int64(150) - - // validator misses a block - keeper.HandleValidatorSignature(ctx, val.Address(), newPower, false) - height++ - - // shouldn't be jailed/kicked yet - validator, _ = sk.GetValidator(ctx, addr) - require.Equal(t, sdk.Bonded, validator.Status) - - // validator misses 500 more blocks, 501 total - latest := height - for ; height < latest+500; height++ { - ctx = ctx.WithBlockHeight(height) - keeper.HandleValidatorSignature(ctx, val.Address(), newPower, false) - } - - // should now be jailed & kicked - staking.EndBlocker(ctx, sk) - validator, _ = sk.GetValidator(ctx, addr) - require.Equal(t, sdk.Unbonding, validator.Status) - - // check all the signing information - signInfo, found := keeper.GetValidatorSigningInfo(ctx, consAddr) - require.True(t, found) - require.Equal(t, int64(0), signInfo.MissedBlocksCounter) - require.Equal(t, int64(0), signInfo.IndexOffset) - // array should be cleared - for offset := int64(0); offset < keeper.SignedBlocksWindow(ctx); offset++ { - missed := keeper.GetValidatorMissedBlockBitArray(ctx, consAddr, offset) - require.False(t, missed) - } - - // some blocks pass - height = int64(5000) - ctx = ctx.WithBlockHeight(height) - - // validator rejoins and starts signing again - sk.Unjail(ctx, consAddr) - keeper.HandleValidatorSignature(ctx, val.Address(), newPower, true) - height++ - - // validator should not be kicked since we reset counter/array when it was jailed - staking.EndBlocker(ctx, sk) - validator, _ = sk.GetValidator(ctx, addr) - require.Equal(t, sdk.Bonded, validator.Status) - - // validator misses 501 blocks - latest = height - for ; height < latest+501; height++ { - ctx = ctx.WithBlockHeight(height) - keeper.HandleValidatorSignature(ctx, val.Address(), newPower, false) - } - - // validator should now be jailed & kicked - staking.EndBlocker(ctx, sk) - validator, _ = sk.GetValidator(ctx, addr) - require.Equal(t, sdk.Unbonding, validator.Status) - -} From 0a5f64b64f083447e757a2cea104897b3ba4897f Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Tue, 3 Mar 2020 11:05:20 +0100 Subject: [PATCH 339/529] clean some code --- simapp/test_helpers.go | 45 +++++++++++++++------------- x/slashing/keeper/old_keeper_test.go | 1 - 2 files changed, 24 insertions(+), 22 deletions(-) delete mode 100644 x/slashing/keeper/old_keeper_test.go diff --git a/simapp/test_helpers.go b/simapp/test_helpers.go index 99cee407040c..300235fe1c59 100644 --- a/simapp/test_helpers.go +++ b/simapp/test_helpers.go @@ -116,23 +116,23 @@ func createIncrementalAccounts(accNum int) []sdk.AccAddress { return addresses } +// AddTestAddrsFromPubKeys adds the addresses into the SimApp providing only the public keys. func AddTestAddrsFromPubKeys(app *SimApp, ctx sdk.Context, pubKeys []crypto.PubKey, accAmt sdk.Int) { initCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), accAmt)) - totalSupply := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), accAmt.MulRaw(int64(len(pubKeys))))) - prevSupply := app.SupplyKeeper.GetSupply(ctx) - app.SupplyKeeper.SetSupply(ctx, supply.NewSupply(prevSupply.GetTotal().Add(totalSupply...))) + + setTotalSupply(app, ctx, accAmt, len(pubKeys)) // fill all the addresses with some coins, set the loose pool tokens simultaneously for _, pubKey := range pubKeys { - acc := app.AccountKeeper.NewAccountWithAddress(ctx, sdk.AccAddress(pubKey.Address())) - app.AccountKeeper.SetAccount(ctx, acc) - - _, err := app.BankKeeper.AddCoins(ctx, sdk.AccAddress(pubKey.Address()), initCoins) - if err != nil { - panic(err) - } + saveAccount(app, ctx, sdk.AccAddress(pubKey.Address()), initCoins) } - return +} + +// setTotalSupply provides the total supply based on accAmt * totalAccounts. +func setTotalSupply(app *SimApp, ctx sdk.Context, accAmt sdk.Int, totalAccounts int) { + totalSupply := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), accAmt.MulRaw(int64(totalAccounts)))) + prevSupply := app.SupplyKeeper.GetSupply(ctx) + app.SupplyKeeper.SetSupply(ctx, supply.NewSupply(prevSupply.GetTotal().Add(totalSupply...))) } // AddTestAddrs constructs and returns accNum amount of accounts with an @@ -151,23 +151,26 @@ func addTestAddrs(app *SimApp, ctx sdk.Context, accNum int, accAmt sdk.Int, stra testAddrs := strategy(accNum) initCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), accAmt)) - totalSupply := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), accAmt.MulRaw(int64(len(testAddrs))))) - prevSupply := app.SupplyKeeper.GetSupply(ctx) - app.SupplyKeeper.SetSupply(ctx, supply.NewSupply(prevSupply.GetTotal().Add(totalSupply...))) + setTotalSupply(app, ctx, accAmt, accNum) // fill all the addresses with some coins, set the loose pool tokens simultaneously for _, addr := range testAddrs { - acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr) - app.AccountKeeper.SetAccount(ctx, acc) - - _, err := app.BankKeeper.AddCoins(ctx, addr, initCoins) - if err != nil { - panic(err) - } + saveAccount(app, ctx, addr, initCoins) } + return testAddrs } +// saveAccount saves the provided account into the simapp with balance based on initCoins. +func saveAccount(app *SimApp, ctx sdk.Context, addr sdk.AccAddress, initCoins sdk.Coins) { + acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr) + app.AccountKeeper.SetAccount(ctx, acc) + _, err := app.BankKeeper.AddCoins(ctx, addr, initCoins) + if err != nil { + panic(err) + } +} + // ConvertAddrsToValAddrs converts the provided addresses to ValAddress. func ConvertAddrsToValAddrs(addrs []sdk.AccAddress) []sdk.ValAddress { valAddrs := make([]sdk.ValAddress, len(addrs)) diff --git a/x/slashing/keeper/old_keeper_test.go b/x/slashing/keeper/old_keeper_test.go deleted file mode 100644 index b55569d4a442..000000000000 --- a/x/slashing/keeper/old_keeper_test.go +++ /dev/null @@ -1 +0,0 @@ -package keeper From 416f0147f707e5a90b9ac11d570465cda4368581 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Tue, 3 Mar 2020 11:14:22 +0100 Subject: [PATCH 340/529] refactor querier test --- x/slashing/keeper/querier_test.go | 33 ++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/x/slashing/keeper/querier_test.go b/x/slashing/keeper/querier_test.go index fd924bc8e823..5413ba59949b 100644 --- a/x/slashing/keeper/querier_test.go +++ b/x/slashing/keeper/querier_test.go @@ -1,38 +1,53 @@ -package keeper +package keeper_test import ( "testing" "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/simapp" + "github.com/cosmos/cosmos-sdk/x/slashing/keeper" "github.com/cosmos/cosmos-sdk/x/slashing/types" ) func TestNewQuerier(t *testing.T) { - ctx, _, _, _, keeper := CreateTestInput(t, TestParams()) - querier := NewQuerier(keeper) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + app.SlashingKeeper.SetParams(ctx, keeper.TestParams()) + + querier := keeper.NewQuerier(app.SlashingKeeper) query := abci.RequestQuery{ Path: "", Data: []byte{}, } - _, err := querier(ctx, []string{"parameters"}, query) + _, err := querier(ctx, []string{types.QueryParameters}, query) require.NoError(t, err) } func TestQueryParams(t *testing.T) { cdc := codec.New() - ctx, _, _, _, keeper := CreateTestInput(t, TestParams()) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + app.SlashingKeeper.SetParams(ctx, keeper.TestParams()) + + querier := keeper.NewQuerier(app.SlashingKeeper) + + query := abci.RequestQuery{ + Path: "", + Data: []byte{}, + } var params types.Params - res, errRes := queryParams(ctx, keeper) - require.NoError(t, errRes) + res, err := querier(ctx, []string{types.QueryParameters}, query) + require.NoError(t, err) - err := cdc.UnmarshalJSON(res, ¶ms) + err = cdc.UnmarshalJSON(res, ¶ms) require.NoError(t, err) - require.Equal(t, keeper.GetParams(ctx), params) + require.Equal(t, app.SlashingKeeper.GetParams(ctx), params) } From c2cc84950b5f617a9c6f6167ba9d801718814894 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Tue, 3 Mar 2020 11:16:31 +0100 Subject: [PATCH 341/529] refactor TestGetSetValidatorSigningInfo test --- x/slashing/keeper/old_signing_info_test.go | 61 +++++++++++++++++++ x/slashing/keeper/signing_info_test.go | 68 ++++------------------ 2 files changed, 73 insertions(+), 56 deletions(-) create mode 100644 x/slashing/keeper/old_signing_info_test.go diff --git a/x/slashing/keeper/old_signing_info_test.go b/x/slashing/keeper/old_signing_info_test.go new file mode 100644 index 000000000000..1e4347b22006 --- /dev/null +++ b/x/slashing/keeper/old_signing_info_test.go @@ -0,0 +1,61 @@ +package keeper + +import ( + "testing" + "time" + + "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/slashing/types" +) + +func TestGetSetValidatorMissedBlockBitArray(t *testing.T) { + ctx, _, _, _, keeper := CreateTestInput(t, types.DefaultParams()) + missed := keeper.GetValidatorMissedBlockBitArray(ctx, sdk.ConsAddress(Addrs[0]), 0) + require.False(t, missed) // treat empty key as not missed + keeper.SetValidatorMissedBlockBitArray(ctx, sdk.ConsAddress(Addrs[0]), 0, true) + missed = keeper.GetValidatorMissedBlockBitArray(ctx, sdk.ConsAddress(Addrs[0]), 0) + require.True(t, missed) // now should be missed +} + +func TestTombstoned(t *testing.T) { + ctx, _, _, _, keeper := CreateTestInput(t, types.DefaultParams()) + require.Panics(t, func() { keeper.Tombstone(ctx, sdk.ConsAddress(Addrs[0])) }) + require.False(t, keeper.IsTombstoned(ctx, sdk.ConsAddress(Addrs[0]))) + + newInfo := types.NewValidatorSigningInfo( + sdk.ConsAddress(Addrs[0]), + int64(4), + int64(3), + time.Unix(2, 0), + false, + int64(10), + ) + keeper.SetValidatorSigningInfo(ctx, sdk.ConsAddress(Addrs[0]), newInfo) + + require.False(t, keeper.IsTombstoned(ctx, sdk.ConsAddress(Addrs[0]))) + keeper.Tombstone(ctx, sdk.ConsAddress(Addrs[0])) + require.True(t, keeper.IsTombstoned(ctx, sdk.ConsAddress(Addrs[0]))) + require.Panics(t, func() { keeper.Tombstone(ctx, sdk.ConsAddress(Addrs[0])) }) +} + +func TestJailUntil(t *testing.T) { + ctx, _, _, _, keeper := CreateTestInput(t, types.DefaultParams()) + require.Panics(t, func() { keeper.JailUntil(ctx, sdk.ConsAddress(Addrs[0]), time.Now()) }) + + newInfo := types.NewValidatorSigningInfo( + sdk.ConsAddress(Addrs[0]), + int64(4), + int64(3), + time.Unix(2, 0), + false, + int64(10), + ) + keeper.SetValidatorSigningInfo(ctx, sdk.ConsAddress(Addrs[0]), newInfo) + keeper.JailUntil(ctx, sdk.ConsAddress(Addrs[0]), time.Unix(253402300799, 0).UTC()) + + info, ok := keeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(Addrs[0])) + require.True(t, ok) + require.Equal(t, time.Unix(253402300799, 0).UTC(), info.JailedUntil) +} diff --git a/x/slashing/keeper/signing_info_test.go b/x/slashing/keeper/signing_info_test.go index ac8c5075276f..c58f4f900d30 100644 --- a/x/slashing/keeper/signing_info_test.go +++ b/x/slashing/keeper/signing_info_test.go @@ -1,4 +1,4 @@ -package keeper +package keeper_test import ( "testing" @@ -6,77 +6,33 @@ import ( "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/slashing/types" ) func TestGetSetValidatorSigningInfo(t *testing.T) { - ctx, _, _, _, keeper := CreateTestInput(t, types.DefaultParams()) - info, found := keeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(Addrs[0])) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + addrDels := simapp.AddTestAddrsIncremental(app, ctx, 1, sdk.TokensFromConsensusPower(200)) + + info, found := app.SlashingKeeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(addrDels[0])) require.False(t, found) newInfo := types.NewValidatorSigningInfo( - sdk.ConsAddress(Addrs[0]), + sdk.ConsAddress(addrDels[0]), int64(4), int64(3), time.Unix(2, 0), false, int64(10), ) - keeper.SetValidatorSigningInfo(ctx, sdk.ConsAddress(Addrs[0]), newInfo) - info, found = keeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(Addrs[0])) + app.SlashingKeeper.SetValidatorSigningInfo(ctx, sdk.ConsAddress(addrDels[0]), newInfo) + info, found = app.SlashingKeeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(addrDels[0])) require.True(t, found) require.Equal(t, info.StartHeight, int64(4)) require.Equal(t, info.IndexOffset, int64(3)) require.Equal(t, info.JailedUntil, time.Unix(2, 0).UTC()) require.Equal(t, info.MissedBlocksCounter, int64(10)) } - -func TestGetSetValidatorMissedBlockBitArray(t *testing.T) { - ctx, _, _, _, keeper := CreateTestInput(t, types.DefaultParams()) - missed := keeper.GetValidatorMissedBlockBitArray(ctx, sdk.ConsAddress(Addrs[0]), 0) - require.False(t, missed) // treat empty key as not missed - keeper.SetValidatorMissedBlockBitArray(ctx, sdk.ConsAddress(Addrs[0]), 0, true) - missed = keeper.GetValidatorMissedBlockBitArray(ctx, sdk.ConsAddress(Addrs[0]), 0) - require.True(t, missed) // now should be missed -} - -func TestTombstoned(t *testing.T) { - ctx, _, _, _, keeper := CreateTestInput(t, types.DefaultParams()) - require.Panics(t, func() { keeper.Tombstone(ctx, sdk.ConsAddress(Addrs[0])) }) - require.False(t, keeper.IsTombstoned(ctx, sdk.ConsAddress(Addrs[0]))) - - newInfo := types.NewValidatorSigningInfo( - sdk.ConsAddress(Addrs[0]), - int64(4), - int64(3), - time.Unix(2, 0), - false, - int64(10), - ) - keeper.SetValidatorSigningInfo(ctx, sdk.ConsAddress(Addrs[0]), newInfo) - - require.False(t, keeper.IsTombstoned(ctx, sdk.ConsAddress(Addrs[0]))) - keeper.Tombstone(ctx, sdk.ConsAddress(Addrs[0])) - require.True(t, keeper.IsTombstoned(ctx, sdk.ConsAddress(Addrs[0]))) - require.Panics(t, func() { keeper.Tombstone(ctx, sdk.ConsAddress(Addrs[0])) }) -} - -func TestJailUntil(t *testing.T) { - ctx, _, _, _, keeper := CreateTestInput(t, types.DefaultParams()) - require.Panics(t, func() { keeper.JailUntil(ctx, sdk.ConsAddress(Addrs[0]), time.Now()) }) - - newInfo := types.NewValidatorSigningInfo( - sdk.ConsAddress(Addrs[0]), - int64(4), - int64(3), - time.Unix(2, 0), - false, - int64(10), - ) - keeper.SetValidatorSigningInfo(ctx, sdk.ConsAddress(Addrs[0]), newInfo) - keeper.JailUntil(ctx, sdk.ConsAddress(Addrs[0]), time.Unix(253402300799, 0).UTC()) - - info, ok := keeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(Addrs[0])) - require.True(t, ok) - require.Equal(t, time.Unix(253402300799, 0).UTC(), info.JailedUntil) -} From 2b95d5317e3a244af7ffcd57e80be190fb438edf Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Tue, 3 Mar 2020 11:20:18 +0100 Subject: [PATCH 342/529] refactor signing info test --- x/slashing/keeper/old_signing_info_test.go | 61 ---------------------- x/slashing/keeper/signing_info_test.go | 59 +++++++++++++++++++++ 2 files changed, 59 insertions(+), 61 deletions(-) delete mode 100644 x/slashing/keeper/old_signing_info_test.go diff --git a/x/slashing/keeper/old_signing_info_test.go b/x/slashing/keeper/old_signing_info_test.go deleted file mode 100644 index 1e4347b22006..000000000000 --- a/x/slashing/keeper/old_signing_info_test.go +++ /dev/null @@ -1,61 +0,0 @@ -package keeper - -import ( - "testing" - "time" - - "github.com/stretchr/testify/require" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/slashing/types" -) - -func TestGetSetValidatorMissedBlockBitArray(t *testing.T) { - ctx, _, _, _, keeper := CreateTestInput(t, types.DefaultParams()) - missed := keeper.GetValidatorMissedBlockBitArray(ctx, sdk.ConsAddress(Addrs[0]), 0) - require.False(t, missed) // treat empty key as not missed - keeper.SetValidatorMissedBlockBitArray(ctx, sdk.ConsAddress(Addrs[0]), 0, true) - missed = keeper.GetValidatorMissedBlockBitArray(ctx, sdk.ConsAddress(Addrs[0]), 0) - require.True(t, missed) // now should be missed -} - -func TestTombstoned(t *testing.T) { - ctx, _, _, _, keeper := CreateTestInput(t, types.DefaultParams()) - require.Panics(t, func() { keeper.Tombstone(ctx, sdk.ConsAddress(Addrs[0])) }) - require.False(t, keeper.IsTombstoned(ctx, sdk.ConsAddress(Addrs[0]))) - - newInfo := types.NewValidatorSigningInfo( - sdk.ConsAddress(Addrs[0]), - int64(4), - int64(3), - time.Unix(2, 0), - false, - int64(10), - ) - keeper.SetValidatorSigningInfo(ctx, sdk.ConsAddress(Addrs[0]), newInfo) - - require.False(t, keeper.IsTombstoned(ctx, sdk.ConsAddress(Addrs[0]))) - keeper.Tombstone(ctx, sdk.ConsAddress(Addrs[0])) - require.True(t, keeper.IsTombstoned(ctx, sdk.ConsAddress(Addrs[0]))) - require.Panics(t, func() { keeper.Tombstone(ctx, sdk.ConsAddress(Addrs[0])) }) -} - -func TestJailUntil(t *testing.T) { - ctx, _, _, _, keeper := CreateTestInput(t, types.DefaultParams()) - require.Panics(t, func() { keeper.JailUntil(ctx, sdk.ConsAddress(Addrs[0]), time.Now()) }) - - newInfo := types.NewValidatorSigningInfo( - sdk.ConsAddress(Addrs[0]), - int64(4), - int64(3), - time.Unix(2, 0), - false, - int64(10), - ) - keeper.SetValidatorSigningInfo(ctx, sdk.ConsAddress(Addrs[0]), newInfo) - keeper.JailUntil(ctx, sdk.ConsAddress(Addrs[0]), time.Unix(253402300799, 0).UTC()) - - info, ok := keeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(Addrs[0])) - require.True(t, ok) - require.Equal(t, time.Unix(253402300799, 0).UTC(), info.JailedUntil) -} diff --git a/x/slashing/keeper/signing_info_test.go b/x/slashing/keeper/signing_info_test.go index c58f4f900d30..e10df926c605 100644 --- a/x/slashing/keeper/signing_info_test.go +++ b/x/slashing/keeper/signing_info_test.go @@ -36,3 +36,62 @@ func TestGetSetValidatorSigningInfo(t *testing.T) { require.Equal(t, info.JailedUntil, time.Unix(2, 0).UTC()) require.Equal(t, info.MissedBlocksCounter, int64(10)) } + +func TestGetSetValidatorMissedBlockBitArray(t *testing.T) { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + addrDels := simapp.AddTestAddrsIncremental(app, ctx, 1, sdk.TokensFromConsensusPower(200)) + + missed := app.SlashingKeeper.GetValidatorMissedBlockBitArray(ctx, sdk.ConsAddress(addrDels[0]), 0) + require.False(t, missed) // treat empty key as not missed + app.SlashingKeeper.SetValidatorMissedBlockBitArray(ctx, sdk.ConsAddress(addrDels[0]), 0, true) + missed = app.SlashingKeeper.GetValidatorMissedBlockBitArray(ctx, sdk.ConsAddress(addrDels[0]), 0) + require.True(t, missed) // now should be missed +} + +func TestTombstoned(t *testing.T) { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + addrDels := simapp.AddTestAddrsIncremental(app, ctx, 1, sdk.TokensFromConsensusPower(200)) + + require.Panics(t, func() { app.SlashingKeeper.Tombstone(ctx, sdk.ConsAddress(addrDels[0])) }) + require.False(t, app.SlashingKeeper.IsTombstoned(ctx, sdk.ConsAddress(addrDels[0]))) + + newInfo := types.NewValidatorSigningInfo( + sdk.ConsAddress(addrDels[0]), + int64(4), + int64(3), + time.Unix(2, 0), + false, + int64(10), + ) + app.SlashingKeeper.SetValidatorSigningInfo(ctx, sdk.ConsAddress(addrDels[0]), newInfo) + + require.False(t, app.SlashingKeeper.IsTombstoned(ctx, sdk.ConsAddress(addrDels[0]))) + app.SlashingKeeper.Tombstone(ctx, sdk.ConsAddress(addrDels[0])) + require.True(t, app.SlashingKeeper.IsTombstoned(ctx, sdk.ConsAddress(addrDels[0]))) + require.Panics(t, func() { app.SlashingKeeper.Tombstone(ctx, sdk.ConsAddress(addrDels[0])) }) +} + +func TestJailUntil(t *testing.T) { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + addrDels := simapp.AddTestAddrsIncremental(app, ctx, 1, sdk.TokensFromConsensusPower(200)) + + require.Panics(t, func() { app.SlashingKeeper.JailUntil(ctx, sdk.ConsAddress(addrDels[0]), time.Now()) }) + + newInfo := types.NewValidatorSigningInfo( + sdk.ConsAddress(addrDels[0]), + int64(4), + int64(3), + time.Unix(2, 0), + false, + int64(10), + ) + app.SlashingKeeper.SetValidatorSigningInfo(ctx, sdk.ConsAddress(addrDels[0]), newInfo) + app.SlashingKeeper.JailUntil(ctx, sdk.ConsAddress(addrDels[0]), time.Unix(253402300799, 0).UTC()) + + info, ok := app.SlashingKeeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(addrDels[0])) + require.True(t, ok) + require.Equal(t, time.Unix(253402300799, 0).UTC(), info.JailedUntil) +} From 24d25fa207841bd87e786a8bc7f5bae72edfbc1e Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Tue, 3 Mar 2020 11:25:32 +0100 Subject: [PATCH 343/529] refactor abci test to use simapp --- x/slashing/abci_test.go | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/x/slashing/abci_test.go b/x/slashing/abci_test.go index c1b0f62fffb4..cd9efc5537f8 100644 --- a/x/slashing/abci_test.go +++ b/x/slashing/abci_test.go @@ -4,32 +4,37 @@ import ( "testing" "time" - "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" - + "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/slashing" slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" "github.com/cosmos/cosmos-sdk/x/staking" + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" ) func TestBeginBlocker(t *testing.T) { - ctx, bk, sk, _, keeper := slashingkeeper.CreateTestInput(t, slashing.DefaultParams()) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + pks := simapp.CreateTestPubKeys(1) + simapp.AddTestAddrsFromPubKeys(app, ctx, pks, sdk.TokensFromConsensusPower(200)) + power := int64(100) amt := sdk.TokensFromConsensusPower(power) - addr, pk := slashingkeeper.Addrs[2], slashingkeeper.Pks[2] + addr, pk := sdk.ValAddress(pks[0].Address()), pks[0] // bond the validator - res, err := staking.NewHandler(sk)(ctx, slashingkeeper.NewTestMsgCreateValidator(addr, pk, amt)) + res, err := staking.NewHandler(app.StakingKeeper)(ctx, slashingkeeper.NewTestMsgCreateValidator(addr, pk, amt)) require.NoError(t, err) require.NotNil(t, res) - staking.EndBlocker(ctx, sk) + staking.EndBlocker(ctx, app.StakingKeeper) require.Equal( - t, bk.GetAllBalances(ctx, sdk.AccAddress(addr)), - sdk.NewCoins(sdk.NewCoin(sk.GetParams(ctx).BondDenom, slashingkeeper.InitTokens.Sub(amt))), + t, app.BankKeeper.GetAllBalances(ctx, sdk.AccAddress(addr)), + sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.GetParams(ctx).BondDenom, slashingkeeper.InitTokens.Sub(amt))), ) - require.Equal(t, amt, sk.Validator(ctx, addr).GetBondedTokens()) + require.Equal(t, amt, app.StakingKeeper.Validator(ctx, addr).GetBondedTokens()) val := abci.Validator{ Address: pk.Address(), @@ -46,9 +51,9 @@ func TestBeginBlocker(t *testing.T) { }, } - slashing.BeginBlocker(ctx, req, keeper) + slashing.BeginBlocker(ctx, req, app.SlashingKeeper) - info, found := keeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(pk.Address())) + info, found := app.SlashingKeeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(pk.Address())) require.True(t, found) require.Equal(t, ctx.BlockHeight(), info.StartHeight) require.Equal(t, int64(1), info.IndexOffset) @@ -58,7 +63,7 @@ func TestBeginBlocker(t *testing.T) { height := int64(0) // for 1000 blocks, mark the validator as having signed - for ; height < keeper.SignedBlocksWindow(ctx); height++ { + for ; height < app.SlashingKeeper.SignedBlocksWindow(ctx); height++ { ctx = ctx.WithBlockHeight(height) req = abci.RequestBeginBlock{ LastCommitInfo: abci.LastCommitInfo{ @@ -69,11 +74,11 @@ func TestBeginBlocker(t *testing.T) { }, } - slashing.BeginBlocker(ctx, req, keeper) + slashing.BeginBlocker(ctx, req, app.SlashingKeeper) } // for 500 blocks, mark the validator as having not signed - for ; height < ((keeper.SignedBlocksWindow(ctx) * 2) - keeper.MinSignedPerWindow(ctx) + 1); height++ { + for ; height < ((app.SlashingKeeper.SignedBlocksWindow(ctx) * 2) - app.SlashingKeeper.MinSignedPerWindow(ctx) + 1); height++ { ctx = ctx.WithBlockHeight(height) req = abci.RequestBeginBlock{ LastCommitInfo: abci.LastCommitInfo{ @@ -84,14 +89,14 @@ func TestBeginBlocker(t *testing.T) { }, } - slashing.BeginBlocker(ctx, req, keeper) + slashing.BeginBlocker(ctx, req, app.SlashingKeeper) } // end block - staking.EndBlocker(ctx, sk) + staking.EndBlocker(ctx, app.StakingKeeper) // validator should be jailed - validator, found := sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(pk)) + validator, found := app.StakingKeeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(pk)) require.True(t, found) require.Equal(t, sdk.Unbonding, validator.GetStatus()) } From 1da6f3c86e097b0ed7c375dd025923ccf45d27f7 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Tue, 3 Mar 2020 11:28:22 +0100 Subject: [PATCH 344/529] refactor TestCannotUnjailUnlessJailed to use simapp --- x/slashing/handler_test.go | 290 ++------------------------------- x/slashing/old_handler_test.go | 280 +++++++++++++++++++++++++++++++ 2 files changed, 295 insertions(+), 275 deletions(-) create mode 100644 x/slashing/old_handler_test.go diff --git a/x/slashing/handler_test.go b/x/slashing/handler_test.go index abd5e52559fd..f4538a2e20f4 100644 --- a/x/slashing/handler_test.go +++ b/x/slashing/handler_test.go @@ -2,306 +2,46 @@ package slashing_test import ( "errors" - "strings" "testing" - "time" - "github.com/stretchr/testify/require" + "github.com/cosmos/cosmos-sdk/simapp" abci "github.com/tendermint/tendermint/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/slashing" slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" - "github.com/cosmos/cosmos-sdk/x/slashing/types" "github.com/cosmos/cosmos-sdk/x/staking" + "github.com/stretchr/testify/require" ) func TestCannotUnjailUnlessJailed(t *testing.T) { // initial setup - ctx, bk, sk, _, keeper := slashingkeeper.CreateTestInput(t, slashing.DefaultParams()) - slh := slashing.NewHandler(keeper) - amt := sdk.TokensFromConsensusPower(100) - addr, val := slashingkeeper.Addrs[0], slashingkeeper.Pks[0] - - msg := slashingkeeper.NewTestMsgCreateValidator(addr, val, amt) - res, err := staking.NewHandler(sk)(ctx, msg) - require.NoError(t, err) - require.NotNil(t, res) - - staking.EndBlocker(ctx, sk) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) - require.Equal( - t, bk.GetAllBalances(ctx, sdk.AccAddress(addr)), - sdk.Coins{sdk.NewCoin(sk.GetParams(ctx).BondDenom, slashingkeeper.InitTokens.Sub(amt))}, - ) - require.Equal(t, amt, sk.Validator(ctx, addr).GetBondedTokens()) + pks := simapp.CreateTestPubKeys(1) + simapp.AddTestAddrsFromPubKeys(app, ctx, pks, sdk.TokensFromConsensusPower(200)) - // assert non-jailed validator can't be unjailed - res, err = slh(ctx, slashing.NewMsgUnjail(addr)) - require.Error(t, err) - require.Nil(t, res) - require.True(t, errors.Is(slashing.ErrValidatorNotJailed, err)) -} + slh := slashing.NewHandler(app.SlashingKeeper) + amt := sdk.TokensFromConsensusPower(100) + addr, val := sdk.ValAddress(pks[0].Address()), pks[0] -func TestCannotUnjailUnlessMeetMinSelfDelegation(t *testing.T) { - // initial setup - ctx, bk, sk, _, keeper := slashingkeeper.CreateTestInput(t, slashing.DefaultParams()) - slh := slashing.NewHandler(keeper) - amtInt := int64(100) - addr, val, amt := slashingkeeper.Addrs[0], slashingkeeper.Pks[0], sdk.TokensFromConsensusPower(amtInt) msg := slashingkeeper.NewTestMsgCreateValidator(addr, val, amt) - msg.MinSelfDelegation = amt - - res, err := staking.NewHandler(sk)(ctx, msg) + res, err := staking.NewHandler(app.StakingKeeper)(ctx, msg) require.NoError(t, err) require.NotNil(t, res) - staking.EndBlocker(ctx, sk) + staking.EndBlocker(ctx, app.StakingKeeper) require.Equal( - t, bk.GetAllBalances(ctx, sdk.AccAddress(addr)), - sdk.Coins{sdk.NewCoin(sk.GetParams(ctx).BondDenom, slashingkeeper.InitTokens.Sub(amt))}, + t, app.BankKeeper.GetAllBalances(ctx, sdk.AccAddress(addr)), + sdk.Coins{sdk.NewCoin(app.StakingKeeper.GetParams(ctx).BondDenom, slashingkeeper.InitTokens.Sub(amt))}, ) - - unbondAmt := sdk.NewCoin(sk.GetParams(ctx).BondDenom, sdk.OneInt()) - undelegateMsg := staking.NewMsgUndelegate(sdk.AccAddress(addr), addr, unbondAmt) - res, err = staking.NewHandler(sk)(ctx, undelegateMsg) - require.NoError(t, err) - require.NotNil(t, res) - - require.True(t, sk.Validator(ctx, addr).IsJailed()) + require.Equal(t, amt, app.StakingKeeper.Validator(ctx, addr).GetBondedTokens()) // assert non-jailed validator can't be unjailed res, err = slh(ctx, slashing.NewMsgUnjail(addr)) require.Error(t, err) require.Nil(t, res) - require.True(t, errors.Is(slashing.ErrSelfDelegationTooLowToUnjail, err)) -} - -func TestJailedValidatorDelegations(t *testing.T) { - ctx, _, stakingKeeper, _, slashingKeeper := slashingkeeper.CreateTestInput(t, slashing.DefaultParams()) - - stakingParams := stakingKeeper.GetParams(ctx) - stakingKeeper.SetParams(ctx, stakingParams) - - // create a validator - bondAmount := sdk.TokensFromConsensusPower(10) - valPubKey := slashingkeeper.Pks[0] - valAddr, consAddr := slashingkeeper.Addrs[1], sdk.ConsAddress(slashingkeeper.Addrs[0]) - - msgCreateVal := slashingkeeper.NewTestMsgCreateValidator(valAddr, valPubKey, bondAmount) - res, err := staking.NewHandler(stakingKeeper)(ctx, msgCreateVal) - require.NoError(t, err) - require.NotNil(t, res) - - // end block - staking.EndBlocker(ctx, stakingKeeper) - - // set dummy signing info - newInfo := slashing.NewValidatorSigningInfo(consAddr, 0, 0, time.Unix(0, 0), false, 0) - slashingKeeper.SetValidatorSigningInfo(ctx, consAddr, newInfo) - - // delegate tokens to the validator - delAddr := sdk.AccAddress(slashingkeeper.Addrs[2]) - msgDelegate := slashingkeeper.NewTestMsgDelegate(delAddr, valAddr, bondAmount) - res, err = staking.NewHandler(stakingKeeper)(ctx, msgDelegate) - require.NoError(t, err) - require.NotNil(t, res) - - unbondAmt := sdk.NewCoin(stakingKeeper.GetParams(ctx).BondDenom, bondAmount) - - // unbond validator total self-delegations (which should jail the validator) - msgUndelegate := staking.NewMsgUndelegate(sdk.AccAddress(valAddr), valAddr, unbondAmt) - res, err = staking.NewHandler(stakingKeeper)(ctx, msgUndelegate) - require.NoError(t, err) - require.NotNil(t, res) - - err = stakingKeeper.CompleteUnbonding(ctx, sdk.AccAddress(valAddr), valAddr) - require.Nil(t, err, "expected complete unbonding validator to be ok, got: %v", err) - - // verify validator still exists and is jailed - validator, found := stakingKeeper.GetValidator(ctx, valAddr) - require.True(t, found) - require.True(t, validator.IsJailed()) - - // verify the validator cannot unjail itself - res, err = slashing.NewHandler(slashingKeeper)(ctx, slashing.NewMsgUnjail(valAddr)) - require.Error(t, err) - require.Nil(t, res) - - // self-delegate to validator - msgSelfDelegate := slashingkeeper.NewTestMsgDelegate(sdk.AccAddress(valAddr), valAddr, bondAmount) - res, err = staking.NewHandler(stakingKeeper)(ctx, msgSelfDelegate) - require.NoError(t, err) - require.NotNil(t, res) - - // verify the validator can now unjail itself - res, err = slashing.NewHandler(slashingKeeper)(ctx, slashing.NewMsgUnjail(valAddr)) - require.NoError(t, err) - require.NotNil(t, res) -} - -func TestInvalidMsg(t *testing.T) { - k := slashing.Keeper{} - h := slashing.NewHandler(k) - - res, err := h(sdk.NewContext(nil, abci.Header{}, false, nil), sdk.NewTestMsg()) - require.Error(t, err) - require.Nil(t, res) - require.True(t, strings.Contains(err.Error(), "unrecognized slashing message type")) -} - -// Test a validator through uptime, downtime, revocation, -// unrevocation, starting height reset, and revocation again -func TestHandleAbsentValidator(t *testing.T) { - // initial setup - ctx, bk, sk, _, keeper := slashingkeeper.CreateTestInput(t, slashingkeeper.TestParams()) - power := int64(100) - amt := sdk.TokensFromConsensusPower(power) - addr, val := slashingkeeper.Addrs[0], slashingkeeper.Pks[0] - sh := staking.NewHandler(sk) - slh := slashing.NewHandler(keeper) - - res, err := sh(ctx, slashingkeeper.NewTestMsgCreateValidator(addr, val, amt)) - require.NoError(t, err) - require.NotNil(t, res) - - staking.EndBlocker(ctx, sk) - - require.Equal( - t, bk.GetAllBalances(ctx, sdk.AccAddress(addr)), - sdk.NewCoins(sdk.NewCoin(sk.GetParams(ctx).BondDenom, slashingkeeper.InitTokens.Sub(amt))), - ) - require.Equal(t, amt, sk.Validator(ctx, addr).GetBondedTokens()) - - // will exist since the validator has been bonded - info, found := keeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) - require.True(t, found) - require.Equal(t, int64(0), info.StartHeight) - require.Equal(t, int64(0), info.IndexOffset) - require.Equal(t, int64(0), info.MissedBlocksCounter) - require.Equal(t, time.Unix(0, 0).UTC(), info.JailedUntil) - height := int64(0) - - // 1000 first blocks OK - for ; height < keeper.SignedBlocksWindow(ctx); height++ { - ctx = ctx.WithBlockHeight(height) - keeper.HandleValidatorSignature(ctx, val.Address(), power, true) - } - info, found = keeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) - require.True(t, found) - require.Equal(t, int64(0), info.StartHeight) - require.Equal(t, int64(0), info.MissedBlocksCounter) - - // 500 blocks missed - for ; height < keeper.SignedBlocksWindow(ctx)+(keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx)); height++ { - ctx = ctx.WithBlockHeight(height) - keeper.HandleValidatorSignature(ctx, val.Address(), power, false) - } - info, found = keeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) - require.True(t, found) - require.Equal(t, int64(0), info.StartHeight) - require.Equal(t, keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx), info.MissedBlocksCounter) - - // validator should be bonded still - validator, _ := sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) - require.Equal(t, sdk.Bonded, validator.GetStatus()) - - bondPool := sk.GetBondedPool(ctx) - require.True(sdk.IntEq(t, amt, bk.GetBalance(ctx, bondPool.GetAddress(), sk.BondDenom(ctx)).Amount)) - - // 501st block missed - ctx = ctx.WithBlockHeight(height) - keeper.HandleValidatorSignature(ctx, val.Address(), power, false) - info, found = keeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) - require.True(t, found) - require.Equal(t, int64(0), info.StartHeight) - // counter now reset to zero - require.Equal(t, int64(0), info.MissedBlocksCounter) - - // end block - staking.EndBlocker(ctx, sk) - - // validator should have been jailed - validator, _ = sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) - require.Equal(t, sdk.Unbonding, validator.GetStatus()) - - slashAmt := amt.ToDec().Mul(keeper.SlashFractionDowntime(ctx)).RoundInt64() - - // validator should have been slashed - require.Equal(t, amt.Int64()-slashAmt, validator.GetTokens().Int64()) - - // 502nd block *also* missed (since the LastCommit would have still included the just-unbonded validator) - height++ - ctx = ctx.WithBlockHeight(height) - keeper.HandleValidatorSignature(ctx, val.Address(), power, false) - info, found = keeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) - require.True(t, found) - require.Equal(t, int64(0), info.StartHeight) - require.Equal(t, int64(1), info.MissedBlocksCounter) - - // end block - staking.EndBlocker(ctx, sk) - - // validator should not have been slashed any more, since it was already jailed - validator, _ = sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) - require.Equal(t, amt.Int64()-slashAmt, validator.GetTokens().Int64()) - - // unrevocation should fail prior to jail expiration - res, err = slh(ctx, types.NewMsgUnjail(addr)) - require.Error(t, err) - require.Nil(t, res) - - // unrevocation should succeed after jail expiration - ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(1, 0).Add(keeper.DowntimeJailDuration(ctx))}) - res, err = slh(ctx, types.NewMsgUnjail(addr)) - require.NoError(t, err) - require.NotNil(t, res) - - // end block - staking.EndBlocker(ctx, sk) - - // validator should be rebonded now - validator, _ = sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) - require.Equal(t, sdk.Bonded, validator.GetStatus()) - - // validator should have been slashed - require.Equal(t, amt.Int64()-slashAmt, bk.GetBalance(ctx, bondPool.GetAddress(), sk.BondDenom(ctx)).Amount.Int64()) - - // Validator start height should not have been changed - info, found = keeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) - require.True(t, found) - require.Equal(t, int64(0), info.StartHeight) - // we've missed 2 blocks more than the maximum, so the counter was reset to 0 at 1 block more and is now 1 - require.Equal(t, int64(1), info.MissedBlocksCounter) - - // validator should not be immediately jailed again - height++ - ctx = ctx.WithBlockHeight(height) - keeper.HandleValidatorSignature(ctx, val.Address(), power, false) - validator, _ = sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) - require.Equal(t, sdk.Bonded, validator.GetStatus()) - - // 500 signed blocks - nextHeight := height + keeper.MinSignedPerWindow(ctx) + 1 - for ; height < nextHeight; height++ { - ctx = ctx.WithBlockHeight(height) - keeper.HandleValidatorSignature(ctx, val.Address(), power, false) - } - - // end block - staking.EndBlocker(ctx, sk) - - // validator should be jailed again after 500 unsigned blocks - nextHeight = height + keeper.MinSignedPerWindow(ctx) + 1 - for ; height <= nextHeight; height++ { - ctx = ctx.WithBlockHeight(height) - keeper.HandleValidatorSignature(ctx, val.Address(), power, false) - } - - // end block - staking.EndBlocker(ctx, sk) - - validator, _ = sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) - require.Equal(t, sdk.Unbonding, validator.GetStatus()) + require.True(t, errors.Is(slashing.ErrValidatorNotJailed, err)) } diff --git a/x/slashing/old_handler_test.go b/x/slashing/old_handler_test.go new file mode 100644 index 000000000000..be126e6a4ccb --- /dev/null +++ b/x/slashing/old_handler_test.go @@ -0,0 +1,280 @@ +package slashing_test + +import ( + "errors" + "strings" + "testing" + "time" + + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/slashing" + slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" + "github.com/cosmos/cosmos-sdk/x/slashing/types" + "github.com/cosmos/cosmos-sdk/x/staking" +) + +func TestCannotUnjailUnlessMeetMinSelfDelegation(t *testing.T) { + // initial setup + ctx, bk, sk, _, keeper := slashingkeeper.CreateTestInput(t, slashing.DefaultParams()) + slh := slashing.NewHandler(keeper) + amtInt := int64(100) + addr, val, amt := slashingkeeper.Addrs[0], slashingkeeper.Pks[0], sdk.TokensFromConsensusPower(amtInt) + msg := slashingkeeper.NewTestMsgCreateValidator(addr, val, amt) + msg.MinSelfDelegation = amt + + res, err := staking.NewHandler(sk)(ctx, msg) + require.NoError(t, err) + require.NotNil(t, res) + + staking.EndBlocker(ctx, sk) + + require.Equal( + t, bk.GetAllBalances(ctx, sdk.AccAddress(addr)), + sdk.Coins{sdk.NewCoin(sk.GetParams(ctx).BondDenom, slashingkeeper.InitTokens.Sub(amt))}, + ) + + unbondAmt := sdk.NewCoin(sk.GetParams(ctx).BondDenom, sdk.OneInt()) + undelegateMsg := staking.NewMsgUndelegate(sdk.AccAddress(addr), addr, unbondAmt) + res, err = staking.NewHandler(sk)(ctx, undelegateMsg) + require.NoError(t, err) + require.NotNil(t, res) + + require.True(t, sk.Validator(ctx, addr).IsJailed()) + + // assert non-jailed validator can't be unjailed + res, err = slh(ctx, slashing.NewMsgUnjail(addr)) + require.Error(t, err) + require.Nil(t, res) + require.True(t, errors.Is(slashing.ErrSelfDelegationTooLowToUnjail, err)) +} + +func TestJailedValidatorDelegations(t *testing.T) { + ctx, _, stakingKeeper, _, slashingKeeper := slashingkeeper.CreateTestInput(t, slashing.DefaultParams()) + + stakingParams := stakingKeeper.GetParams(ctx) + stakingKeeper.SetParams(ctx, stakingParams) + + // create a validator + bondAmount := sdk.TokensFromConsensusPower(10) + valPubKey := slashingkeeper.Pks[0] + valAddr, consAddr := slashingkeeper.Addrs[1], sdk.ConsAddress(slashingkeeper.Addrs[0]) + + msgCreateVal := slashingkeeper.NewTestMsgCreateValidator(valAddr, valPubKey, bondAmount) + res, err := staking.NewHandler(stakingKeeper)(ctx, msgCreateVal) + require.NoError(t, err) + require.NotNil(t, res) + + // end block + staking.EndBlocker(ctx, stakingKeeper) + + // set dummy signing info + newInfo := slashing.NewValidatorSigningInfo(consAddr, 0, 0, time.Unix(0, 0), false, 0) + slashingKeeper.SetValidatorSigningInfo(ctx, consAddr, newInfo) + + // delegate tokens to the validator + delAddr := sdk.AccAddress(slashingkeeper.Addrs[2]) + msgDelegate := slashingkeeper.NewTestMsgDelegate(delAddr, valAddr, bondAmount) + res, err = staking.NewHandler(stakingKeeper)(ctx, msgDelegate) + require.NoError(t, err) + require.NotNil(t, res) + + unbondAmt := sdk.NewCoin(stakingKeeper.GetParams(ctx).BondDenom, bondAmount) + + // unbond validator total self-delegations (which should jail the validator) + msgUndelegate := staking.NewMsgUndelegate(sdk.AccAddress(valAddr), valAddr, unbondAmt) + res, err = staking.NewHandler(stakingKeeper)(ctx, msgUndelegate) + require.NoError(t, err) + require.NotNil(t, res) + + err = stakingKeeper.CompleteUnbonding(ctx, sdk.AccAddress(valAddr), valAddr) + require.Nil(t, err, "expected complete unbonding validator to be ok, got: %v", err) + + // verify validator still exists and is jailed + validator, found := stakingKeeper.GetValidator(ctx, valAddr) + require.True(t, found) + require.True(t, validator.IsJailed()) + + // verify the validator cannot unjail itself + res, err = slashing.NewHandler(slashingKeeper)(ctx, slashing.NewMsgUnjail(valAddr)) + require.Error(t, err) + require.Nil(t, res) + + // self-delegate to validator + msgSelfDelegate := slashingkeeper.NewTestMsgDelegate(sdk.AccAddress(valAddr), valAddr, bondAmount) + res, err = staking.NewHandler(stakingKeeper)(ctx, msgSelfDelegate) + require.NoError(t, err) + require.NotNil(t, res) + + // verify the validator can now unjail itself + res, err = slashing.NewHandler(slashingKeeper)(ctx, slashing.NewMsgUnjail(valAddr)) + require.NoError(t, err) + require.NotNil(t, res) +} + +func TestInvalidMsg(t *testing.T) { + k := slashing.Keeper{} + h := slashing.NewHandler(k) + + res, err := h(sdk.NewContext(nil, abci.Header{}, false, nil), sdk.NewTestMsg()) + require.Error(t, err) + require.Nil(t, res) + require.True(t, strings.Contains(err.Error(), "unrecognized slashing message type")) +} + +// Test a validator through uptime, downtime, revocation, +// unrevocation, starting height reset, and revocation again +func TestHandleAbsentValidator(t *testing.T) { + // initial setup + ctx, bk, sk, _, keeper := slashingkeeper.CreateTestInput(t, slashingkeeper.TestParams()) + power := int64(100) + amt := sdk.TokensFromConsensusPower(power) + addr, val := slashingkeeper.Addrs[0], slashingkeeper.Pks[0] + sh := staking.NewHandler(sk) + slh := slashing.NewHandler(keeper) + + res, err := sh(ctx, slashingkeeper.NewTestMsgCreateValidator(addr, val, amt)) + require.NoError(t, err) + require.NotNil(t, res) + + staking.EndBlocker(ctx, sk) + + require.Equal( + t, bk.GetAllBalances(ctx, sdk.AccAddress(addr)), + sdk.NewCoins(sdk.NewCoin(sk.GetParams(ctx).BondDenom, slashingkeeper.InitTokens.Sub(amt))), + ) + require.Equal(t, amt, sk.Validator(ctx, addr).GetBondedTokens()) + + // will exist since the validator has been bonded + info, found := keeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) + require.True(t, found) + require.Equal(t, int64(0), info.StartHeight) + require.Equal(t, int64(0), info.IndexOffset) + require.Equal(t, int64(0), info.MissedBlocksCounter) + require.Equal(t, time.Unix(0, 0).UTC(), info.JailedUntil) + height := int64(0) + + // 1000 first blocks OK + for ; height < keeper.SignedBlocksWindow(ctx); height++ { + ctx = ctx.WithBlockHeight(height) + keeper.HandleValidatorSignature(ctx, val.Address(), power, true) + } + info, found = keeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) + require.True(t, found) + require.Equal(t, int64(0), info.StartHeight) + require.Equal(t, int64(0), info.MissedBlocksCounter) + + // 500 blocks missed + for ; height < keeper.SignedBlocksWindow(ctx)+(keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx)); height++ { + ctx = ctx.WithBlockHeight(height) + keeper.HandleValidatorSignature(ctx, val.Address(), power, false) + } + info, found = keeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) + require.True(t, found) + require.Equal(t, int64(0), info.StartHeight) + require.Equal(t, keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx), info.MissedBlocksCounter) + + // validator should be bonded still + validator, _ := sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) + require.Equal(t, sdk.Bonded, validator.GetStatus()) + + bondPool := sk.GetBondedPool(ctx) + require.True(sdk.IntEq(t, amt, bk.GetBalance(ctx, bondPool.GetAddress(), sk.BondDenom(ctx)).Amount)) + + // 501st block missed + ctx = ctx.WithBlockHeight(height) + keeper.HandleValidatorSignature(ctx, val.Address(), power, false) + info, found = keeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) + require.True(t, found) + require.Equal(t, int64(0), info.StartHeight) + // counter now reset to zero + require.Equal(t, int64(0), info.MissedBlocksCounter) + + // end block + staking.EndBlocker(ctx, sk) + + // validator should have been jailed + validator, _ = sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) + require.Equal(t, sdk.Unbonding, validator.GetStatus()) + + slashAmt := amt.ToDec().Mul(keeper.SlashFractionDowntime(ctx)).RoundInt64() + + // validator should have been slashed + require.Equal(t, amt.Int64()-slashAmt, validator.GetTokens().Int64()) + + // 502nd block *also* missed (since the LastCommit would have still included the just-unbonded validator) + height++ + ctx = ctx.WithBlockHeight(height) + keeper.HandleValidatorSignature(ctx, val.Address(), power, false) + info, found = keeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) + require.True(t, found) + require.Equal(t, int64(0), info.StartHeight) + require.Equal(t, int64(1), info.MissedBlocksCounter) + + // end block + staking.EndBlocker(ctx, sk) + + // validator should not have been slashed any more, since it was already jailed + validator, _ = sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) + require.Equal(t, amt.Int64()-slashAmt, validator.GetTokens().Int64()) + + // unrevocation should fail prior to jail expiration + res, err = slh(ctx, types.NewMsgUnjail(addr)) + require.Error(t, err) + require.Nil(t, res) + + // unrevocation should succeed after jail expiration + ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(1, 0).Add(keeper.DowntimeJailDuration(ctx))}) + res, err = slh(ctx, types.NewMsgUnjail(addr)) + require.NoError(t, err) + require.NotNil(t, res) + + // end block + staking.EndBlocker(ctx, sk) + + // validator should be rebonded now + validator, _ = sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) + require.Equal(t, sdk.Bonded, validator.GetStatus()) + + // validator should have been slashed + require.Equal(t, amt.Int64()-slashAmt, bk.GetBalance(ctx, bondPool.GetAddress(), sk.BondDenom(ctx)).Amount.Int64()) + + // Validator start height should not have been changed + info, found = keeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) + require.True(t, found) + require.Equal(t, int64(0), info.StartHeight) + // we've missed 2 blocks more than the maximum, so the counter was reset to 0 at 1 block more and is now 1 + require.Equal(t, int64(1), info.MissedBlocksCounter) + + // validator should not be immediately jailed again + height++ + ctx = ctx.WithBlockHeight(height) + keeper.HandleValidatorSignature(ctx, val.Address(), power, false) + validator, _ = sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) + require.Equal(t, sdk.Bonded, validator.GetStatus()) + + // 500 signed blocks + nextHeight := height + keeper.MinSignedPerWindow(ctx) + 1 + for ; height < nextHeight; height++ { + ctx = ctx.WithBlockHeight(height) + keeper.HandleValidatorSignature(ctx, val.Address(), power, false) + } + + // end block + staking.EndBlocker(ctx, sk) + + // validator should be jailed again after 500 unsigned blocks + nextHeight = height + keeper.MinSignedPerWindow(ctx) + 1 + for ; height <= nextHeight; height++ { + ctx = ctx.WithBlockHeight(height) + keeper.HandleValidatorSignature(ctx, val.Address(), power, false) + } + + // end block + staking.EndBlocker(ctx, sk) + + validator, _ = sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) + require.Equal(t, sdk.Unbonding, validator.GetStatus()) +} From 210d78b54d342572986eebdf95526e6a254a70e3 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Tue, 3 Mar 2020 11:43:18 +0100 Subject: [PATCH 345/529] refactor TestCannotUnjailUnlessMeetMinSelfDelegation to use simapp --- x/slashing/handler_test.go | 39 ++++++++++++++++++++++++++++++++++ x/slashing/old_handler_test.go | 36 ------------------------------- 2 files changed, 39 insertions(+), 36 deletions(-) diff --git a/x/slashing/handler_test.go b/x/slashing/handler_test.go index f4538a2e20f4..134a10deb90f 100644 --- a/x/slashing/handler_test.go +++ b/x/slashing/handler_test.go @@ -45,3 +45,42 @@ func TestCannotUnjailUnlessJailed(t *testing.T) { require.Nil(t, res) require.True(t, errors.Is(slashing.ErrValidatorNotJailed, err)) } + +func TestCannotUnjailUnlessMeetMinSelfDelegation(t *testing.T) { + // initial setup + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + pks := simapp.CreateTestPubKeys(1) + simapp.AddTestAddrsFromPubKeys(app, ctx, pks, sdk.TokensFromConsensusPower(200)) + + slh := slashing.NewHandler(app.SlashingKeeper) + amtInt := int64(100) + addr, val, amt := sdk.ValAddress(pks[0].Address()), pks[0], sdk.TokensFromConsensusPower(amtInt) + msg := slashingkeeper.NewTestMsgCreateValidator(addr, val, amt) + msg.MinSelfDelegation = amt + + res, err := staking.NewHandler(app.StakingKeeper)(ctx, msg) + require.NoError(t, err) + require.NotNil(t, res) + + staking.EndBlocker(ctx, app.StakingKeeper) + + require.Equal( + t, app.BankKeeper.GetAllBalances(ctx, sdk.AccAddress(addr)), + sdk.Coins{sdk.NewCoin(app.StakingKeeper.GetParams(ctx).BondDenom, slashingkeeper.InitTokens.Sub(amt))}, + ) + + unbondAmt := sdk.NewCoin(app.StakingKeeper.GetParams(ctx).BondDenom, sdk.OneInt()) + undelegateMsg := staking.NewMsgUndelegate(sdk.AccAddress(addr), addr, unbondAmt) + res, err = staking.NewHandler(app.StakingKeeper)(ctx, undelegateMsg) + require.NoError(t, err) + require.NotNil(t, res) + + require.True(t, app.StakingKeeper.Validator(ctx, addr).IsJailed()) + + // assert non-jailed validator can't be unjailed + res, err = slh(ctx, slashing.NewMsgUnjail(addr)) + require.Error(t, err) + require.Nil(t, res) + require.True(t, errors.Is(slashing.ErrSelfDelegationTooLowToUnjail, err)) +} diff --git a/x/slashing/old_handler_test.go b/x/slashing/old_handler_test.go index be126e6a4ccb..470acb7a8e5e 100644 --- a/x/slashing/old_handler_test.go +++ b/x/slashing/old_handler_test.go @@ -1,7 +1,6 @@ package slashing_test import ( - "errors" "strings" "testing" "time" @@ -16,41 +15,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking" ) -func TestCannotUnjailUnlessMeetMinSelfDelegation(t *testing.T) { - // initial setup - ctx, bk, sk, _, keeper := slashingkeeper.CreateTestInput(t, slashing.DefaultParams()) - slh := slashing.NewHandler(keeper) - amtInt := int64(100) - addr, val, amt := slashingkeeper.Addrs[0], slashingkeeper.Pks[0], sdk.TokensFromConsensusPower(amtInt) - msg := slashingkeeper.NewTestMsgCreateValidator(addr, val, amt) - msg.MinSelfDelegation = amt - - res, err := staking.NewHandler(sk)(ctx, msg) - require.NoError(t, err) - require.NotNil(t, res) - - staking.EndBlocker(ctx, sk) - - require.Equal( - t, bk.GetAllBalances(ctx, sdk.AccAddress(addr)), - sdk.Coins{sdk.NewCoin(sk.GetParams(ctx).BondDenom, slashingkeeper.InitTokens.Sub(amt))}, - ) - - unbondAmt := sdk.NewCoin(sk.GetParams(ctx).BondDenom, sdk.OneInt()) - undelegateMsg := staking.NewMsgUndelegate(sdk.AccAddress(addr), addr, unbondAmt) - res, err = staking.NewHandler(sk)(ctx, undelegateMsg) - require.NoError(t, err) - require.NotNil(t, res) - - require.True(t, sk.Validator(ctx, addr).IsJailed()) - - // assert non-jailed validator can't be unjailed - res, err = slh(ctx, slashing.NewMsgUnjail(addr)) - require.Error(t, err) - require.Nil(t, res) - require.True(t, errors.Is(slashing.ErrSelfDelegationTooLowToUnjail, err)) -} - func TestJailedValidatorDelegations(t *testing.T) { ctx, _, stakingKeeper, _, slashingKeeper := slashingkeeper.CreateTestInput(t, slashing.DefaultParams()) From 70e829949c08c8926d3607eb8e582024410f7642 Mon Sep 17 00:00:00 2001 From: seungyeon-hwang Date: Tue, 3 Mar 2020 22:32:52 +0900 Subject: [PATCH 346/529] crypto: print an error message if the password input failed (#5739) --- CHANGELOG.md | 1 + crypto/keys/keyring.go | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 972723cbf15f..5f2efc89f107 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -152,6 +152,7 @@ Buffers for state serialization instead of Amino. * Add `tx.maxheight` key to filter transaction with an inclusive maximum block height * (server) [\#5709](https://github.com/cosmos/cosmos-sdk/pull/5709) There are two new flags for pruning, `--pruning-keep-every` and `--pruning-snapshot-every` as an alternative to `--pruning`. They allow to fine tune the strategy for pruning the state. +* (crypto/keys) [\#5739](https://github.com/cosmos/cosmos-sdk/pull/5739) Print an error message if the password input failed. ## [v0.38.1] - 2020-02-11 diff --git a/crypto/keys/keyring.go b/crypto/keys/keyring.go index d21e557435aa..450b0d32bb42 100644 --- a/crypto/keys/keyring.go +++ b/crypto/keys/keyring.go @@ -546,6 +546,7 @@ func newRealPrompt(dir string, buf io.Reader) func(string) (string, error) { buf := bufio.NewReader(buf) pass, err := input.GetPassword("Enter keyring passphrase:", buf) if err != nil { + fmt.Fprintln(os.Stderr, err) continue } From 3349c971aeccc79f910e139397d470d1fdbca679 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Tue, 3 Mar 2020 13:38:46 +0000 Subject: [PATCH 347/529] increase types/module coverage up to 80% (#5740) Co-authored-by: Alexander Bezobchuk --- .codecov.yml | 2 + Makefile | 4 + tests/mocks/types_handler.go | 49 +++ tests/mocks/types_invariant.go | 46 +++ tests/mocks/types_module_module.go | 518 +++++++++++++++++++++++++++++ tests/mocks/types_router.go | 113 +++++++ types/module/module_test.go | 272 ++++++++++++++- 7 files changed, 996 insertions(+), 8 deletions(-) create mode 100644 tests/mocks/types_handler.go create mode 100644 tests/mocks/types_invariant.go create mode 100644 tests/mocks/types_module_module.go create mode 100644 tests/mocks/types_router.go diff --git a/.codecov.yml b/.codecov.yml index c10133afd9e5..f4d6cef61f60 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -47,6 +47,8 @@ ignore: - "*.md" - "*.rst" - "**/*.pb.go" + - "tests/*" + - "tests/**/*" - "x/**/*.pb.go" - "x/**/test_common.go" - "scripts/" diff --git a/Makefile b/Makefile index a634915bfe0a..56eb4fa458ea 100644 --- a/Makefile +++ b/Makefile @@ -27,6 +27,10 @@ build: go.sum mocks: $(MOCKS_DIR) mockgen -source=x/auth/types/account_retriever.go -package mocks -destination tests/mocks/account_retriever.go mockgen -package mocks -destination tests/mocks/tendermint_tm_db_DB.go github.com/tendermint/tm-db DB + mockgen -source=types/module/module.go -package mocks -destination tests/mocks/types_module_module.go + mockgen -source=types/invariant.go -package mocks -destination tests/mocks/types_invariant.go + mockgen -source=types/router.go -package mocks -destination tests/mocks/types_router.go + mockgen -source=types/handler.go -package mocks -destination tests/mocks/types_handler.go .PHONY: mocks $(MOCKS_DIR): diff --git a/tests/mocks/types_handler.go b/tests/mocks/types_handler.go new file mode 100644 index 000000000000..da80614ae884 --- /dev/null +++ b/tests/mocks/types_handler.go @@ -0,0 +1,49 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: types/handler.go + +// Package mocks is a generated GoMock package. +package mocks + +import ( + types "github.com/cosmos/cosmos-sdk/types" + gomock "github.com/golang/mock/gomock" + reflect "reflect" +) + +// MockAnteDecorator is a mock of AnteDecorator interface +type MockAnteDecorator struct { + ctrl *gomock.Controller + recorder *MockAnteDecoratorMockRecorder +} + +// MockAnteDecoratorMockRecorder is the mock recorder for MockAnteDecorator +type MockAnteDecoratorMockRecorder struct { + mock *MockAnteDecorator +} + +// NewMockAnteDecorator creates a new mock instance +func NewMockAnteDecorator(ctrl *gomock.Controller) *MockAnteDecorator { + mock := &MockAnteDecorator{ctrl: ctrl} + mock.recorder = &MockAnteDecoratorMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockAnteDecorator) EXPECT() *MockAnteDecoratorMockRecorder { + return m.recorder +} + +// AnteHandle mocks base method +func (m *MockAnteDecorator) AnteHandle(ctx types.Context, tx types.Tx, simulate bool, next types.AnteHandler) (types.Context, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AnteHandle", ctx, tx, simulate, next) + ret0, _ := ret[0].(types.Context) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// AnteHandle indicates an expected call of AnteHandle +func (mr *MockAnteDecoratorMockRecorder) AnteHandle(ctx, tx, simulate, next interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AnteHandle", reflect.TypeOf((*MockAnteDecorator)(nil).AnteHandle), ctx, tx, simulate, next) +} diff --git a/tests/mocks/types_invariant.go b/tests/mocks/types_invariant.go new file mode 100644 index 000000000000..325b108b20bb --- /dev/null +++ b/tests/mocks/types_invariant.go @@ -0,0 +1,46 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: types/invariant.go + +// Package mocks is a generated GoMock package. +package mocks + +import ( + types "github.com/cosmos/cosmos-sdk/types" + gomock "github.com/golang/mock/gomock" + reflect "reflect" +) + +// MockInvariantRegistry is a mock of InvariantRegistry interface +type MockInvariantRegistry struct { + ctrl *gomock.Controller + recorder *MockInvariantRegistryMockRecorder +} + +// MockInvariantRegistryMockRecorder is the mock recorder for MockInvariantRegistry +type MockInvariantRegistryMockRecorder struct { + mock *MockInvariantRegistry +} + +// NewMockInvariantRegistry creates a new mock instance +func NewMockInvariantRegistry(ctrl *gomock.Controller) *MockInvariantRegistry { + mock := &MockInvariantRegistry{ctrl: ctrl} + mock.recorder = &MockInvariantRegistryMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockInvariantRegistry) EXPECT() *MockInvariantRegistryMockRecorder { + return m.recorder +} + +// RegisterRoute mocks base method +func (m *MockInvariantRegistry) RegisterRoute(moduleName, route string, invar types.Invariant) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "RegisterRoute", moduleName, route, invar) +} + +// RegisterRoute indicates an expected call of RegisterRoute +func (mr *MockInvariantRegistryMockRecorder) RegisterRoute(moduleName, route, invar interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterRoute", reflect.TypeOf((*MockInvariantRegistry)(nil).RegisterRoute), moduleName, route, invar) +} diff --git a/tests/mocks/types_module_module.go b/tests/mocks/types_module_module.go new file mode 100644 index 000000000000..274ac5c0636b --- /dev/null +++ b/tests/mocks/types_module_module.go @@ -0,0 +1,518 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: types/module/module.go + +// Package mocks is a generated GoMock package. +package mocks + +import ( + json "encoding/json" + context "github.com/cosmos/cosmos-sdk/client/context" + codec "github.com/cosmos/cosmos-sdk/codec" + types "github.com/cosmos/cosmos-sdk/types" + gomock "github.com/golang/mock/gomock" + mux "github.com/gorilla/mux" + cobra "github.com/spf13/cobra" + types0 "github.com/tendermint/tendermint/abci/types" + reflect "reflect" +) + +// MockAppModuleBasic is a mock of AppModuleBasic interface +type MockAppModuleBasic struct { + ctrl *gomock.Controller + recorder *MockAppModuleBasicMockRecorder +} + +// MockAppModuleBasicMockRecorder is the mock recorder for MockAppModuleBasic +type MockAppModuleBasicMockRecorder struct { + mock *MockAppModuleBasic +} + +// NewMockAppModuleBasic creates a new mock instance +func NewMockAppModuleBasic(ctrl *gomock.Controller) *MockAppModuleBasic { + mock := &MockAppModuleBasic{ctrl: ctrl} + mock.recorder = &MockAppModuleBasicMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockAppModuleBasic) EXPECT() *MockAppModuleBasicMockRecorder { + return m.recorder +} + +// Name mocks base method +func (m *MockAppModuleBasic) Name() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Name") + ret0, _ := ret[0].(string) + return ret0 +} + +// Name indicates an expected call of Name +func (mr *MockAppModuleBasicMockRecorder) Name() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockAppModuleBasic)(nil).Name)) +} + +// RegisterCodec mocks base method +func (m *MockAppModuleBasic) RegisterCodec(arg0 *codec.Codec) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "RegisterCodec", arg0) +} + +// RegisterCodec indicates an expected call of RegisterCodec +func (mr *MockAppModuleBasicMockRecorder) RegisterCodec(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterCodec", reflect.TypeOf((*MockAppModuleBasic)(nil).RegisterCodec), arg0) +} + +// DefaultGenesis mocks base method +func (m *MockAppModuleBasic) DefaultGenesis(arg0 codec.JSONMarshaler) json.RawMessage { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultGenesis", arg0) + ret0, _ := ret[0].(json.RawMessage) + return ret0 +} + +// DefaultGenesis indicates an expected call of DefaultGenesis +func (mr *MockAppModuleBasicMockRecorder) DefaultGenesis(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultGenesis", reflect.TypeOf((*MockAppModuleBasic)(nil).DefaultGenesis), arg0) +} + +// ValidateGenesis mocks base method +func (m *MockAppModuleBasic) ValidateGenesis(arg0 codec.JSONMarshaler, arg1 json.RawMessage) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ValidateGenesis", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// ValidateGenesis indicates an expected call of ValidateGenesis +func (mr *MockAppModuleBasicMockRecorder) ValidateGenesis(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateGenesis", reflect.TypeOf((*MockAppModuleBasic)(nil).ValidateGenesis), arg0, arg1) +} + +// RegisterRESTRoutes mocks base method +func (m *MockAppModuleBasic) RegisterRESTRoutes(arg0 context.CLIContext, arg1 *mux.Router) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "RegisterRESTRoutes", arg0, arg1) +} + +// RegisterRESTRoutes indicates an expected call of RegisterRESTRoutes +func (mr *MockAppModuleBasicMockRecorder) RegisterRESTRoutes(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterRESTRoutes", reflect.TypeOf((*MockAppModuleBasic)(nil).RegisterRESTRoutes), arg0, arg1) +} + +// GetTxCmd mocks base method +func (m *MockAppModuleBasic) GetTxCmd(arg0 *codec.Codec) *cobra.Command { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTxCmd", arg0) + ret0, _ := ret[0].(*cobra.Command) + return ret0 +} + +// GetTxCmd indicates an expected call of GetTxCmd +func (mr *MockAppModuleBasicMockRecorder) GetTxCmd(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTxCmd", reflect.TypeOf((*MockAppModuleBasic)(nil).GetTxCmd), arg0) +} + +// GetQueryCmd mocks base method +func (m *MockAppModuleBasic) GetQueryCmd(arg0 *codec.Codec) *cobra.Command { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetQueryCmd", arg0) + ret0, _ := ret[0].(*cobra.Command) + return ret0 +} + +// GetQueryCmd indicates an expected call of GetQueryCmd +func (mr *MockAppModuleBasicMockRecorder) GetQueryCmd(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetQueryCmd", reflect.TypeOf((*MockAppModuleBasic)(nil).GetQueryCmd), arg0) +} + +// MockAppModuleGenesis is a mock of AppModuleGenesis interface +type MockAppModuleGenesis struct { + ctrl *gomock.Controller + recorder *MockAppModuleGenesisMockRecorder +} + +// MockAppModuleGenesisMockRecorder is the mock recorder for MockAppModuleGenesis +type MockAppModuleGenesisMockRecorder struct { + mock *MockAppModuleGenesis +} + +// NewMockAppModuleGenesis creates a new mock instance +func NewMockAppModuleGenesis(ctrl *gomock.Controller) *MockAppModuleGenesis { + mock := &MockAppModuleGenesis{ctrl: ctrl} + mock.recorder = &MockAppModuleGenesisMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockAppModuleGenesis) EXPECT() *MockAppModuleGenesisMockRecorder { + return m.recorder +} + +// Name mocks base method +func (m *MockAppModuleGenesis) Name() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Name") + ret0, _ := ret[0].(string) + return ret0 +} + +// Name indicates an expected call of Name +func (mr *MockAppModuleGenesisMockRecorder) Name() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockAppModuleGenesis)(nil).Name)) +} + +// RegisterCodec mocks base method +func (m *MockAppModuleGenesis) RegisterCodec(arg0 *codec.Codec) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "RegisterCodec", arg0) +} + +// RegisterCodec indicates an expected call of RegisterCodec +func (mr *MockAppModuleGenesisMockRecorder) RegisterCodec(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterCodec", reflect.TypeOf((*MockAppModuleGenesis)(nil).RegisterCodec), arg0) +} + +// DefaultGenesis mocks base method +func (m *MockAppModuleGenesis) DefaultGenesis(arg0 codec.JSONMarshaler) json.RawMessage { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultGenesis", arg0) + ret0, _ := ret[0].(json.RawMessage) + return ret0 +} + +// DefaultGenesis indicates an expected call of DefaultGenesis +func (mr *MockAppModuleGenesisMockRecorder) DefaultGenesis(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultGenesis", reflect.TypeOf((*MockAppModuleGenesis)(nil).DefaultGenesis), arg0) +} + +// ValidateGenesis mocks base method +func (m *MockAppModuleGenesis) ValidateGenesis(arg0 codec.JSONMarshaler, arg1 json.RawMessage) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ValidateGenesis", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// ValidateGenesis indicates an expected call of ValidateGenesis +func (mr *MockAppModuleGenesisMockRecorder) ValidateGenesis(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateGenesis", reflect.TypeOf((*MockAppModuleGenesis)(nil).ValidateGenesis), arg0, arg1) +} + +// RegisterRESTRoutes mocks base method +func (m *MockAppModuleGenesis) RegisterRESTRoutes(arg0 context.CLIContext, arg1 *mux.Router) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "RegisterRESTRoutes", arg0, arg1) +} + +// RegisterRESTRoutes indicates an expected call of RegisterRESTRoutes +func (mr *MockAppModuleGenesisMockRecorder) RegisterRESTRoutes(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterRESTRoutes", reflect.TypeOf((*MockAppModuleGenesis)(nil).RegisterRESTRoutes), arg0, arg1) +} + +// GetTxCmd mocks base method +func (m *MockAppModuleGenesis) GetTxCmd(arg0 *codec.Codec) *cobra.Command { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTxCmd", arg0) + ret0, _ := ret[0].(*cobra.Command) + return ret0 +} + +// GetTxCmd indicates an expected call of GetTxCmd +func (mr *MockAppModuleGenesisMockRecorder) GetTxCmd(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTxCmd", reflect.TypeOf((*MockAppModuleGenesis)(nil).GetTxCmd), arg0) +} + +// GetQueryCmd mocks base method +func (m *MockAppModuleGenesis) GetQueryCmd(arg0 *codec.Codec) *cobra.Command { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetQueryCmd", arg0) + ret0, _ := ret[0].(*cobra.Command) + return ret0 +} + +// GetQueryCmd indicates an expected call of GetQueryCmd +func (mr *MockAppModuleGenesisMockRecorder) GetQueryCmd(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetQueryCmd", reflect.TypeOf((*MockAppModuleGenesis)(nil).GetQueryCmd), arg0) +} + +// InitGenesis mocks base method +func (m *MockAppModuleGenesis) InitGenesis(arg0 types.Context, arg1 codec.JSONMarshaler, arg2 json.RawMessage) []types0.ValidatorUpdate { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InitGenesis", arg0, arg1, arg2) + ret0, _ := ret[0].([]types0.ValidatorUpdate) + return ret0 +} + +// InitGenesis indicates an expected call of InitGenesis +func (mr *MockAppModuleGenesisMockRecorder) InitGenesis(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InitGenesis", reflect.TypeOf((*MockAppModuleGenesis)(nil).InitGenesis), arg0, arg1, arg2) +} + +// ExportGenesis mocks base method +func (m *MockAppModuleGenesis) ExportGenesis(arg0 types.Context, arg1 codec.JSONMarshaler) json.RawMessage { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ExportGenesis", arg0, arg1) + ret0, _ := ret[0].(json.RawMessage) + return ret0 +} + +// ExportGenesis indicates an expected call of ExportGenesis +func (mr *MockAppModuleGenesisMockRecorder) ExportGenesis(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExportGenesis", reflect.TypeOf((*MockAppModuleGenesis)(nil).ExportGenesis), arg0, arg1) +} + +// MockAppModule is a mock of AppModule interface +type MockAppModule struct { + ctrl *gomock.Controller + recorder *MockAppModuleMockRecorder +} + +// MockAppModuleMockRecorder is the mock recorder for MockAppModule +type MockAppModuleMockRecorder struct { + mock *MockAppModule +} + +// NewMockAppModule creates a new mock instance +func NewMockAppModule(ctrl *gomock.Controller) *MockAppModule { + mock := &MockAppModule{ctrl: ctrl} + mock.recorder = &MockAppModuleMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockAppModule) EXPECT() *MockAppModuleMockRecorder { + return m.recorder +} + +// Name mocks base method +func (m *MockAppModule) Name() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Name") + ret0, _ := ret[0].(string) + return ret0 +} + +// Name indicates an expected call of Name +func (mr *MockAppModuleMockRecorder) Name() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockAppModule)(nil).Name)) +} + +// RegisterCodec mocks base method +func (m *MockAppModule) RegisterCodec(arg0 *codec.Codec) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "RegisterCodec", arg0) +} + +// RegisterCodec indicates an expected call of RegisterCodec +func (mr *MockAppModuleMockRecorder) RegisterCodec(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterCodec", reflect.TypeOf((*MockAppModule)(nil).RegisterCodec), arg0) +} + +// DefaultGenesis mocks base method +func (m *MockAppModule) DefaultGenesis(arg0 codec.JSONMarshaler) json.RawMessage { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultGenesis", arg0) + ret0, _ := ret[0].(json.RawMessage) + return ret0 +} + +// DefaultGenesis indicates an expected call of DefaultGenesis +func (mr *MockAppModuleMockRecorder) DefaultGenesis(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultGenesis", reflect.TypeOf((*MockAppModule)(nil).DefaultGenesis), arg0) +} + +// ValidateGenesis mocks base method +func (m *MockAppModule) ValidateGenesis(arg0 codec.JSONMarshaler, arg1 json.RawMessage) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ValidateGenesis", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// ValidateGenesis indicates an expected call of ValidateGenesis +func (mr *MockAppModuleMockRecorder) ValidateGenesis(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateGenesis", reflect.TypeOf((*MockAppModule)(nil).ValidateGenesis), arg0, arg1) +} + +// RegisterRESTRoutes mocks base method +func (m *MockAppModule) RegisterRESTRoutes(arg0 context.CLIContext, arg1 *mux.Router) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "RegisterRESTRoutes", arg0, arg1) +} + +// RegisterRESTRoutes indicates an expected call of RegisterRESTRoutes +func (mr *MockAppModuleMockRecorder) RegisterRESTRoutes(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterRESTRoutes", reflect.TypeOf((*MockAppModule)(nil).RegisterRESTRoutes), arg0, arg1) +} + +// GetTxCmd mocks base method +func (m *MockAppModule) GetTxCmd(arg0 *codec.Codec) *cobra.Command { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTxCmd", arg0) + ret0, _ := ret[0].(*cobra.Command) + return ret0 +} + +// GetTxCmd indicates an expected call of GetTxCmd +func (mr *MockAppModuleMockRecorder) GetTxCmd(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTxCmd", reflect.TypeOf((*MockAppModule)(nil).GetTxCmd), arg0) +} + +// GetQueryCmd mocks base method +func (m *MockAppModule) GetQueryCmd(arg0 *codec.Codec) *cobra.Command { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetQueryCmd", arg0) + ret0, _ := ret[0].(*cobra.Command) + return ret0 +} + +// GetQueryCmd indicates an expected call of GetQueryCmd +func (mr *MockAppModuleMockRecorder) GetQueryCmd(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetQueryCmd", reflect.TypeOf((*MockAppModule)(nil).GetQueryCmd), arg0) +} + +// InitGenesis mocks base method +func (m *MockAppModule) InitGenesis(arg0 types.Context, arg1 codec.JSONMarshaler, arg2 json.RawMessage) []types0.ValidatorUpdate { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InitGenesis", arg0, arg1, arg2) + ret0, _ := ret[0].([]types0.ValidatorUpdate) + return ret0 +} + +// InitGenesis indicates an expected call of InitGenesis +func (mr *MockAppModuleMockRecorder) InitGenesis(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InitGenesis", reflect.TypeOf((*MockAppModule)(nil).InitGenesis), arg0, arg1, arg2) +} + +// ExportGenesis mocks base method +func (m *MockAppModule) ExportGenesis(arg0 types.Context, arg1 codec.JSONMarshaler) json.RawMessage { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ExportGenesis", arg0, arg1) + ret0, _ := ret[0].(json.RawMessage) + return ret0 +} + +// ExportGenesis indicates an expected call of ExportGenesis +func (mr *MockAppModuleMockRecorder) ExportGenesis(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExportGenesis", reflect.TypeOf((*MockAppModule)(nil).ExportGenesis), arg0, arg1) +} + +// RegisterInvariants mocks base method +func (m *MockAppModule) RegisterInvariants(arg0 types.InvariantRegistry) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "RegisterInvariants", arg0) +} + +// RegisterInvariants indicates an expected call of RegisterInvariants +func (mr *MockAppModuleMockRecorder) RegisterInvariants(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterInvariants", reflect.TypeOf((*MockAppModule)(nil).RegisterInvariants), arg0) +} + +// Route mocks base method +func (m *MockAppModule) Route() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Route") + ret0, _ := ret[0].(string) + return ret0 +} + +// Route indicates an expected call of Route +func (mr *MockAppModuleMockRecorder) Route() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Route", reflect.TypeOf((*MockAppModule)(nil).Route)) +} + +// NewHandler mocks base method +func (m *MockAppModule) NewHandler() types.Handler { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NewHandler") + ret0, _ := ret[0].(types.Handler) + return ret0 +} + +// NewHandler indicates an expected call of NewHandler +func (mr *MockAppModuleMockRecorder) NewHandler() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewHandler", reflect.TypeOf((*MockAppModule)(nil).NewHandler)) +} + +// QuerierRoute mocks base method +func (m *MockAppModule) QuerierRoute() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QuerierRoute") + ret0, _ := ret[0].(string) + return ret0 +} + +// QuerierRoute indicates an expected call of QuerierRoute +func (mr *MockAppModuleMockRecorder) QuerierRoute() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QuerierRoute", reflect.TypeOf((*MockAppModule)(nil).QuerierRoute)) +} + +// NewQuerierHandler mocks base method +func (m *MockAppModule) NewQuerierHandler() types.Querier { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NewQuerierHandler") + ret0, _ := ret[0].(types.Querier) + return ret0 +} + +// NewQuerierHandler indicates an expected call of NewQuerierHandler +func (mr *MockAppModuleMockRecorder) NewQuerierHandler() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewQuerierHandler", reflect.TypeOf((*MockAppModule)(nil).NewQuerierHandler)) +} + +// BeginBlock mocks base method +func (m *MockAppModule) BeginBlock(arg0 types.Context, arg1 types0.RequestBeginBlock) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "BeginBlock", arg0, arg1) +} + +// BeginBlock indicates an expected call of BeginBlock +func (mr *MockAppModuleMockRecorder) BeginBlock(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BeginBlock", reflect.TypeOf((*MockAppModule)(nil).BeginBlock), arg0, arg1) +} + +// EndBlock mocks base method +func (m *MockAppModule) EndBlock(arg0 types.Context, arg1 types0.RequestEndBlock) []types0.ValidatorUpdate { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EndBlock", arg0, arg1) + ret0, _ := ret[0].([]types0.ValidatorUpdate) + return ret0 +} + +// EndBlock indicates an expected call of EndBlock +func (mr *MockAppModuleMockRecorder) EndBlock(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EndBlock", reflect.TypeOf((*MockAppModule)(nil).EndBlock), arg0, arg1) +} diff --git a/tests/mocks/types_router.go b/tests/mocks/types_router.go new file mode 100644 index 000000000000..924d95146eda --- /dev/null +++ b/tests/mocks/types_router.go @@ -0,0 +1,113 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: types/router.go + +// Package mocks is a generated GoMock package. +package mocks + +import ( + types "github.com/cosmos/cosmos-sdk/types" + gomock "github.com/golang/mock/gomock" + reflect "reflect" +) + +// MockRouter is a mock of Router interface +type MockRouter struct { + ctrl *gomock.Controller + recorder *MockRouterMockRecorder +} + +// MockRouterMockRecorder is the mock recorder for MockRouter +type MockRouterMockRecorder struct { + mock *MockRouter +} + +// NewMockRouter creates a new mock instance +func NewMockRouter(ctrl *gomock.Controller) *MockRouter { + mock := &MockRouter{ctrl: ctrl} + mock.recorder = &MockRouterMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockRouter) EXPECT() *MockRouterMockRecorder { + return m.recorder +} + +// AddRoute mocks base method +func (m *MockRouter) AddRoute(r string, h types.Handler) types.Router { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddRoute", r, h) + ret0, _ := ret[0].(types.Router) + return ret0 +} + +// AddRoute indicates an expected call of AddRoute +func (mr *MockRouterMockRecorder) AddRoute(r, h interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddRoute", reflect.TypeOf((*MockRouter)(nil).AddRoute), r, h) +} + +// Route mocks base method +func (m *MockRouter) Route(ctx types.Context, path string) types.Handler { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Route", ctx, path) + ret0, _ := ret[0].(types.Handler) + return ret0 +} + +// Route indicates an expected call of Route +func (mr *MockRouterMockRecorder) Route(ctx, path interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Route", reflect.TypeOf((*MockRouter)(nil).Route), ctx, path) +} + +// MockQueryRouter is a mock of QueryRouter interface +type MockQueryRouter struct { + ctrl *gomock.Controller + recorder *MockQueryRouterMockRecorder +} + +// MockQueryRouterMockRecorder is the mock recorder for MockQueryRouter +type MockQueryRouterMockRecorder struct { + mock *MockQueryRouter +} + +// NewMockQueryRouter creates a new mock instance +func NewMockQueryRouter(ctrl *gomock.Controller) *MockQueryRouter { + mock := &MockQueryRouter{ctrl: ctrl} + mock.recorder = &MockQueryRouterMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockQueryRouter) EXPECT() *MockQueryRouterMockRecorder { + return m.recorder +} + +// AddRoute mocks base method +func (m *MockQueryRouter) AddRoute(r string, h types.Querier) types.QueryRouter { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddRoute", r, h) + ret0, _ := ret[0].(types.QueryRouter) + return ret0 +} + +// AddRoute indicates an expected call of AddRoute +func (mr *MockQueryRouterMockRecorder) AddRoute(r, h interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddRoute", reflect.TypeOf((*MockQueryRouter)(nil).AddRoute), r, h) +} + +// Route mocks base method +func (m *MockQueryRouter) Route(path string) types.Querier { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Route", path) + ret0, _ := ret[0].(types.Querier) + return ret0 +} + +// Route indicates an expected call of Route +func (mr *MockQueryRouterMockRecorder) Route(path interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Route", reflect.TypeOf((*MockQueryRouter)(nil).Route), path) +} diff --git a/types/module/module_test.go b/types/module/module_test.go index 4f24de5a185a..bc875cffc533 100644 --- a/types/module/module_test.go +++ b/types/module/module_test.go @@ -1,16 +1,272 @@ -package module +package module_test import ( + "encoding/json" + "errors" "testing" - "github.com/stretchr/testify/assert" + "github.com/golang/mock/gomock" + "github.com/gorilla/mux" + "github.com/spf13/cobra" "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/tests/mocks" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" ) -func TestSetOrderBeginBlockers(t *testing.T) { - mm := NewManager() - mm.SetOrderBeginBlockers("a", "b", "c") - obb := mm.OrderBeginBlockers - require.Equal(t, 3, len(obb)) - assert.Equal(t, []string{"a", "b", "c"}, obb) +var errFoo = errors.New("dummy") + +func TestBasicManager(t *testing.T) { + t.Parallel() + mockCtrl := gomock.NewController(t) + t.Cleanup(mockCtrl.Finish) + + mockAppModuleBasic1 := mocks.NewMockAppModuleBasic(mockCtrl) + mockAppModuleBasic2 := mocks.NewMockAppModuleBasic(mockCtrl) + + mockAppModuleBasic1.EXPECT().Name().Times(1).Return("mockAppModuleBasic1") + mockAppModuleBasic2.EXPECT().Name().Times(1).Return("mockAppModuleBasic2") + + mm := module.NewBasicManager(mockAppModuleBasic1, mockAppModuleBasic2) + require.Equal(t, mm["mockAppModuleBasic1"], mockAppModuleBasic1) + + cdc := codec.New() + mockAppModuleBasic1.EXPECT().RegisterCodec(gomock.Eq(cdc)).Times(1) + mockAppModuleBasic2.EXPECT().RegisterCodec(gomock.Eq(cdc)).Times(1) + mm.RegisterCodec(cdc) + + mockAppModuleBasic1.EXPECT().Name().Times(1).Return("mockAppModuleBasic1") + mockAppModuleBasic2.EXPECT().Name().Times(1).Return("mockAppModuleBasic2") + mockAppModuleBasic1.EXPECT().DefaultGenesis(gomock.Eq(cdc)).Times(1).Return(json.RawMessage(``)) + mockAppModuleBasic2.EXPECT().DefaultGenesis(gomock.Eq(cdc)).Times(1).Return(json.RawMessage(`{"key":"value"}`)) + defaultGenesis := mm.DefaultGenesis(cdc) + require.Equal(t, 2, len(defaultGenesis)) + require.Equal(t, json.RawMessage(``), defaultGenesis["mockAppModuleBasic1"]) + + var data map[string]string + require.NoError(t, json.Unmarshal(defaultGenesis["mockAppModuleBasic2"], &data)) + require.Equal(t, map[string]string{"key": "value"}, data) + + mockAppModuleBasic1.EXPECT().Name().Times(1).Return("mockAppModuleBasic1") + mockAppModuleBasic1.EXPECT().ValidateGenesis(gomock.Eq(cdc), gomock.Eq(defaultGenesis["mockAppModuleBasic1"])).Times(1).Return(errFoo) + require.True(t, errors.Is(errFoo, mm.ValidateGenesis(cdc, defaultGenesis))) + + mockAppModuleBasic1.EXPECT().RegisterRESTRoutes(gomock.Eq(context.CLIContext{}), gomock.Eq(&mux.Router{})).Times(1) + mockAppModuleBasic2.EXPECT().RegisterRESTRoutes(gomock.Eq(context.CLIContext{}), gomock.Eq(&mux.Router{})).Times(1) + mm.RegisterRESTRoutes(context.CLIContext{}, &mux.Router{}) + + mockCmd := &cobra.Command{Use: "root"} + mockAppModuleBasic1.EXPECT().GetTxCmd(cdc).Times(1).Return(nil) + mockAppModuleBasic2.EXPECT().GetTxCmd(cdc).Times(1).Return(&cobra.Command{}) + mm.AddTxCommands(mockCmd, cdc) + + mockAppModuleBasic1.EXPECT().GetQueryCmd(cdc).Times(1).Return(nil) + mockAppModuleBasic2.EXPECT().GetQueryCmd(cdc).Times(1).Return(&cobra.Command{}) + mm.AddQueryCommands(mockCmd, cdc) + + // validate genesis returns nil + require.Nil(t, module.NewBasicManager().ValidateGenesis(cdc, defaultGenesis)) +} + +func TestGenesisOnlyAppModule(t *testing.T) { + t.Parallel() + mockCtrl := gomock.NewController(t) + t.Cleanup(mockCtrl.Finish) + + mockModule := mocks.NewMockAppModuleGenesis(mockCtrl) + mockInvariantRegistry := mocks.NewMockInvariantRegistry(mockCtrl) + goam := module.NewGenesisOnlyAppModule(mockModule) + + require.Empty(t, goam.Route()) + require.Empty(t, goam.QuerierRoute()) + require.Nil(t, goam.NewHandler()) + require.Nil(t, goam.NewQuerierHandler()) + + // no-op + goam.RegisterInvariants(mockInvariantRegistry) + goam.BeginBlock(sdk.Context{}, abci.RequestBeginBlock{}) + require.Equal(t, []abci.ValidatorUpdate{}, goam.EndBlock(sdk.Context{}, abci.RequestEndBlock{})) +} + +func TestManagerOrderSetters(t *testing.T) { + t.Parallel() + mockCtrl := gomock.NewController(t) + t.Cleanup(mockCtrl.Finish) + mockAppModule1 := mocks.NewMockAppModule(mockCtrl) + mockAppModule2 := mocks.NewMockAppModule(mockCtrl) + + mockAppModule1.EXPECT().Name().Times(2).Return("module1") + mockAppModule2.EXPECT().Name().Times(2).Return("module2") + mm := module.NewManager(mockAppModule1, mockAppModule2) + require.NotNil(t, mm) + require.Equal(t, 2, len(mm.Modules)) + + require.Equal(t, []string{"module1", "module2"}, mm.OrderInitGenesis) + mm.SetOrderInitGenesis("module2", "module1") + require.Equal(t, []string{"module2", "module1"}, mm.OrderInitGenesis) + + require.Equal(t, []string{"module1", "module2"}, mm.OrderExportGenesis) + mm.SetOrderExportGenesis("module2", "module1") + require.Equal(t, []string{"module2", "module1"}, mm.OrderExportGenesis) + + require.Equal(t, []string{"module1", "module2"}, mm.OrderBeginBlockers) + mm.SetOrderBeginBlockers("module2", "module1") + require.Equal(t, []string{"module2", "module1"}, mm.OrderBeginBlockers) + + require.Equal(t, []string{"module1", "module2"}, mm.OrderEndBlockers) + mm.SetOrderEndBlockers("module2", "module1") + require.Equal(t, []string{"module2", "module1"}, mm.OrderEndBlockers) +} + +func TestManager_RegisterInvariants(t *testing.T) { + t.Parallel() + mockCtrl := gomock.NewController(t) + t.Cleanup(mockCtrl.Finish) + + mockAppModule1 := mocks.NewMockAppModule(mockCtrl) + mockAppModule2 := mocks.NewMockAppModule(mockCtrl) + mockAppModule1.EXPECT().Name().Times(2).Return("module1") + mockAppModule2.EXPECT().Name().Times(2).Return("module2") + mm := module.NewManager(mockAppModule1, mockAppModule2) + require.NotNil(t, mm) + require.Equal(t, 2, len(mm.Modules)) + + // test RegisterInvariants + mockInvariantRegistry := mocks.NewMockInvariantRegistry(mockCtrl) + mockAppModule1.EXPECT().RegisterInvariants(gomock.Eq(mockInvariantRegistry)).Times(1) + mockAppModule2.EXPECT().RegisterInvariants(gomock.Eq(mockInvariantRegistry)).Times(1) + mm.RegisterInvariants(mockInvariantRegistry) +} + +func TestManager_RegisterRoutes(t *testing.T) { + t.Parallel() + mockCtrl := gomock.NewController(t) + t.Cleanup(mockCtrl.Finish) + + mockAppModule1 := mocks.NewMockAppModule(mockCtrl) + mockAppModule2 := mocks.NewMockAppModule(mockCtrl) + mockAppModule1.EXPECT().Name().Times(2).Return("module1") + mockAppModule2.EXPECT().Name().Times(2).Return("module2") + mm := module.NewManager(mockAppModule1, mockAppModule2) + require.NotNil(t, mm) + require.Equal(t, 2, len(mm.Modules)) + + router := mocks.NewMockRouter(mockCtrl) + handler1, handler2 := sdk.Handler(nil), sdk.Handler(nil) + mockAppModule1.EXPECT().Route().Times(2).Return("route1") + mockAppModule2.EXPECT().Route().Times(2).Return("route2") + mockAppModule1.EXPECT().NewHandler().Times(1).Return(handler1) + mockAppModule2.EXPECT().NewHandler().Times(1).Return(handler2) + router.EXPECT().AddRoute(gomock.Eq("route1"), gomock.Eq(handler1)).Times(1) + router.EXPECT().AddRoute(gomock.Eq("route2"), gomock.Eq(handler2)).Times(1) + + queryRouter := mocks.NewMockQueryRouter(mockCtrl) + mockAppModule1.EXPECT().QuerierRoute().Times(2).Return("querierRoute1") + mockAppModule2.EXPECT().QuerierRoute().Times(1).Return("") + handler3 := sdk.Querier(nil) + mockAppModule1.EXPECT().NewQuerierHandler().Times(1).Return(handler3) + queryRouter.EXPECT().AddRoute(gomock.Eq("querierRoute1"), gomock.Eq(handler3)).Times(1) + + mm.RegisterRoutes(router, queryRouter) +} + +func TestManager_InitGenesis(t *testing.T) { + t.Parallel() + mockCtrl := gomock.NewController(t) + t.Cleanup(mockCtrl.Finish) + + mockAppModule1 := mocks.NewMockAppModule(mockCtrl) + mockAppModule2 := mocks.NewMockAppModule(mockCtrl) + mockAppModule1.EXPECT().Name().Times(2).Return("module1") + mockAppModule2.EXPECT().Name().Times(2).Return("module2") + mm := module.NewManager(mockAppModule1, mockAppModule2) + require.NotNil(t, mm) + require.Equal(t, 2, len(mm.Modules)) + + cdc, ctx := codec.New(), sdk.Context{} + genesisData := map[string]json.RawMessage{"module1": json.RawMessage(`{"key": "value"}`)} + + mockAppModule1.EXPECT().InitGenesis(gomock.Eq(ctx), gomock.Eq(cdc), gomock.Eq(genesisData["module1"])).Times(1).Return(nil) + require.Equal(t, abci.ResponseInitChain{Validators: []abci.ValidatorUpdate(nil)}, mm.InitGenesis(ctx, cdc, genesisData)) + + // test panic + genesisData = map[string]json.RawMessage{ + "module1": json.RawMessage(`{"key": "value"}`), + "module2": json.RawMessage(`{"key": "value"}`)} + mockAppModule1.EXPECT().InitGenesis(gomock.Eq(ctx), gomock.Eq(cdc), gomock.Eq(genesisData["module1"])).Times(1).Return([]abci.ValidatorUpdate{abci.ValidatorUpdate{}}) + mockAppModule2.EXPECT().InitGenesis(gomock.Eq(ctx), gomock.Eq(cdc), gomock.Eq(genesisData["module2"])).Times(1).Return([]abci.ValidatorUpdate{abci.ValidatorUpdate{}}) + require.Panics(t, func() { mm.InitGenesis(ctx, cdc, genesisData) }) +} + +func TestManager_ExportGenesis(t *testing.T) { + t.Parallel() + mockCtrl := gomock.NewController(t) + t.Cleanup(mockCtrl.Finish) + + mockAppModule1 := mocks.NewMockAppModule(mockCtrl) + mockAppModule2 := mocks.NewMockAppModule(mockCtrl) + mockAppModule1.EXPECT().Name().Times(2).Return("module1") + mockAppModule2.EXPECT().Name().Times(2).Return("module2") + mm := module.NewManager(mockAppModule1, mockAppModule2) + require.NotNil(t, mm) + require.Equal(t, 2, len(mm.Modules)) + + cdc, ctx := codec.New(), sdk.Context{} + mockAppModule1.EXPECT().ExportGenesis(gomock.Eq(ctx), gomock.Eq(cdc)).Times(1).Return(json.RawMessage(`{"key1": "value1"}`)) + mockAppModule2.EXPECT().ExportGenesis(gomock.Eq(ctx), gomock.Eq(cdc)).Times(1).Return(json.RawMessage(`{"key2": "value2"}`)) + + want := map[string]json.RawMessage{ + "module1": json.RawMessage(`{"key1": "value1"}`), + "module2": json.RawMessage(`{"key2": "value2"}`)} + require.Equal(t, want, mm.ExportGenesis(ctx, cdc)) +} + +func TestManager_BeginBlock(t *testing.T) { + t.Parallel() + mockCtrl := gomock.NewController(t) + t.Cleanup(mockCtrl.Finish) + + mockAppModule1 := mocks.NewMockAppModule(mockCtrl) + mockAppModule2 := mocks.NewMockAppModule(mockCtrl) + mockAppModule1.EXPECT().Name().Times(2).Return("module1") + mockAppModule2.EXPECT().Name().Times(2).Return("module2") + mm := module.NewManager(mockAppModule1, mockAppModule2) + require.NotNil(t, mm) + require.Equal(t, 2, len(mm.Modules)) + + req := abci.RequestBeginBlock{Hash: []byte("test")} + + mockAppModule1.EXPECT().BeginBlock(gomock.Any(), gomock.Eq(req)).Times(1) + mockAppModule2.EXPECT().BeginBlock(gomock.Any(), gomock.Eq(req)).Times(1) + mm.BeginBlock(sdk.Context{}, req) +} + +func TestManager_EndBlock(t *testing.T) { + t.Parallel() + mockCtrl := gomock.NewController(t) + t.Cleanup(mockCtrl.Finish) + + mockAppModule1 := mocks.NewMockAppModule(mockCtrl) + mockAppModule2 := mocks.NewMockAppModule(mockCtrl) + mockAppModule1.EXPECT().Name().Times(2).Return("module1") + mockAppModule2.EXPECT().Name().Times(2).Return("module2") + mm := module.NewManager(mockAppModule1, mockAppModule2) + require.NotNil(t, mm) + require.Equal(t, 2, len(mm.Modules)) + + req := abci.RequestEndBlock{Height: 10} + + mockAppModule1.EXPECT().EndBlock(gomock.Any(), gomock.Eq(req)).Times(1).Return([]abci.ValidatorUpdate{abci.ValidatorUpdate{}}) + mockAppModule2.EXPECT().EndBlock(gomock.Any(), gomock.Eq(req)).Times(1) + ret := mm.EndBlock(sdk.Context{}, req) + require.Equal(t, []abci.ValidatorUpdate{abci.ValidatorUpdate{}}, ret.ValidatorUpdates) + + // test panic + mockAppModule1.EXPECT().EndBlock(gomock.Any(), gomock.Eq(req)).Times(1).Return([]abci.ValidatorUpdate{abci.ValidatorUpdate{}}) + mockAppModule2.EXPECT().EndBlock(gomock.Any(), gomock.Eq(req)).Times(1).Return([]abci.ValidatorUpdate{abci.ValidatorUpdate{}}) + require.Panics(t, func() { mm.EndBlock(sdk.Context{}, req) }) } From eedc6f61903fa9464f6d6ba45446ea2f55765e93 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Tue, 3 Mar 2020 09:40:11 -0500 Subject: [PATCH 348/529] Fulfill MsgSubmitProposalI interface --- x/gov/handler.go | 1 + x/gov/types/msgs.go | 13 ++++++------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/x/gov/handler.go b/x/gov/handler.go index 21693d943884..b50644a519ad 100644 --- a/x/gov/handler.go +++ b/x/gov/handler.go @@ -54,6 +54,7 @@ func handleMsgSubmitProposal(ctx sdk.Context, keeper Keeper, msg MsgSubmitPropos sdk.NewAttribute(types.AttributeKeyVotingPeriodStart, fmt.Sprintf("%d", proposal.ProposalID)), ) } + ctx.EventManager().EmitEvent(submitEvent) return &sdk.Result{ diff --git a/x/gov/types/msgs.go b/x/gov/types/msgs.go index 55e19e675e3f..559a343e5755 100644 --- a/x/gov/types/msgs.go +++ b/x/gov/types/msgs.go @@ -206,11 +206,10 @@ func (msg MsgSubmitProposal) GetSignBytes() []byte { return sdk.MustSortJSON(bz) } -// GetSigners implements Msg -func (msg MsgSubmitProposal) GetSigners() []sdk.AccAddress { - return []sdk.AccAddress{msg.Proposer} -} - // nolint -func (msg MsgSubmitProposal) Route() string { return RouterKey } -func (msg MsgSubmitProposal) Type() string { return TypeMsgSubmitProposal } +func (msg MsgSubmitProposal) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.Proposer} } +func (msg MsgSubmitProposal) Route() string { return RouterKey } +func (msg MsgSubmitProposal) Type() string { return TypeMsgSubmitProposal } +func (msg MsgSubmitProposal) GetContent() Content { return msg.Content } +func (msg MsgSubmitProposal) GetInitialDeposit() sdk.Coins { return msg.InitialDeposit } +func (msg MsgSubmitProposal) GetProposer() sdk.AccAddress { return msg.Proposer } From 00180faa151713015a71e8aad96bfb1ac39964c6 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Tue, 3 Mar 2020 09:59:05 -0500 Subject: [PATCH 349/529] Proto lint & gen --- simapp/codec/codec.pb.go | 2 + simapp/codec/codec.proto | 1 + x/gov/types/types.pb.go | 227 +++++++++++++++++++++------------------ x/gov/types/types.proto | 33 ++++-- 4 files changed, 145 insertions(+), 118 deletions(-) diff --git a/simapp/codec/codec.pb.go b/simapp/codec/codec.pb.go index 7ef14c916972..cb065e4e1b5d 100644 --- a/simapp/codec/codec.pb.go +++ b/simapp/codec/codec.pb.go @@ -446,6 +446,8 @@ func (m *Proposal) GetContent() Content { // Content defines the application-level allowed Content to be included in a // governance proposal. type Content struct { + // sum defines a set of all acceptable concrete governance proposal Content types. + // // Types that are valid to be assigned to Sum: // *Content_Text // *Content_ParameterChange diff --git a/simapp/codec/codec.proto b/simapp/codec/codec.proto index c59061ab714d..4383fc02988b 100644 --- a/simapp/codec/codec.proto +++ b/simapp/codec/codec.proto @@ -86,6 +86,7 @@ message Content { option (gogoproto.equal) = true; option (cosmos_proto.interface_type) = "github.com/cosmos/cosmos-sdk/x/gov/types.Content"; + // sum defines a set of all acceptable concrete governance proposal Content types. oneof sum { cosmos_sdk.x.gov.v1.TextProposal text = 1; cosmos_sdk.x.params.v1.ParameterChangeProposal parameter_change = 2; diff --git a/x/gov/types/types.pb.go b/x/gov/types/types.pb.go index f97a1c0dd530..038f3297d785 100644 --- a/x/gov/types/types.pb.go +++ b/x/gov/types/types.pb.go @@ -35,27 +35,32 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type VoteOption int32 const ( - OptionEmpty VoteOption = 0 - OptionYes VoteOption = 1 - OptionAbstain VoteOption = 2 - OptionNo VoteOption = 3 + // VOTE_OPTION_UNSPECIFIED defines a no-op vote option. + OptionEmpty VoteOption = 0 + // VOTE_OPTION_YES defines a yes vote option. + OptionYes VoteOption = 1 + // VOTE_OPTION_ABSTAIN defines an abstain vote option. + OptionAbstain VoteOption = 2 + // VOTE_OPTION_NO defines a no vote option. + OptionNo VoteOption = 3 + // VOTE_OPTION_NO_WITH_VETO defines a no with veto vote option. OptionNoWithVeto VoteOption = 4 ) var VoteOption_name = map[int32]string{ - 0: "EMPTY", - 1: "YES", - 2: "ABSTAIN", - 3: "NO", - 4: "NO_WITH_VETO", + 0: "VOTE_OPTION_UNSPECIFIED", + 1: "VOTE_OPTION_YES", + 2: "VOTE_OPTION_ABSTAIN", + 3: "VOTE_OPTION_NO", + 4: "VOTE_OPTION_NO_WITH_VETO", } var VoteOption_value = map[string]int32{ - "EMPTY": 0, - "YES": 1, - "ABSTAIN": 2, - "NO": 3, - "NO_WITH_VETO": 4, + "VOTE_OPTION_UNSPECIFIED": 0, + "VOTE_OPTION_YES": 1, + "VOTE_OPTION_ABSTAIN": 2, + "VOTE_OPTION_NO": 3, + "VOTE_OPTION_NO_WITH_VETO": 4, } func (VoteOption) EnumDescriptor() ([]byte, []int) { @@ -66,30 +71,36 @@ func (VoteOption) EnumDescriptor() ([]byte, []int) { type ProposalStatus int32 const ( - StatusNil ProposalStatus = 0 + // PROPOSAL_STATUS_UNSPECIFIED defines the default propopsal status. + StatusNil ProposalStatus = 0 + // PROPOSAL_STATUS_DEPOSIT_PERIOD defines a proposal status during the deposit period. StatusDepositPeriod ProposalStatus = 1 - StatusVotingPeriod ProposalStatus = 2 - StatusPassed ProposalStatus = 3 - StatusRejected ProposalStatus = 4 - StatusFailed ProposalStatus = 5 + // PROPOSAL_STATUS_VOTING_PERIOD defines a proposal status during the voting period. + StatusVotingPeriod ProposalStatus = 2 + // PROPOSAL_STATUS_PASSED defines a proposal status of a proposal that has passed. + StatusPassed ProposalStatus = 3 + // PROPOSAL_STATUS_REJECTED defines a proposal status of a proposal that has been rejected. + StatusRejected ProposalStatus = 4 + // PROPOSAL_STATUS_FAILED defines a proposal status of a proposal that has failed. + StatusFailed ProposalStatus = 5 ) var ProposalStatus_name = map[int32]string{ - 0: "NIL", - 1: "DEPOSIT_PERIOD", - 2: "VOTING_PERIOD", - 3: "PASSED", - 4: "REJECTED", - 5: "FAILED", + 0: "PROPOSAL_STATUS_UNSPECIFIED", + 1: "PROPOSAL_STATUS_DEPOSIT_PERIOD", + 2: "PROPOSAL_STATUS_VOTING_PERIOD", + 3: "PROPOSAL_STATUS_PASSED", + 4: "PROPOSAL_STATUS_REJECTED", + 5: "PROPOSAL_STATUS_FAILED", } var ProposalStatus_value = map[string]int32{ - "NIL": 0, - "DEPOSIT_PERIOD": 1, - "VOTING_PERIOD": 2, - "PASSED": 3, - "REJECTED": 4, - "FAILED": 5, + "PROPOSAL_STATUS_UNSPECIFIED": 0, + "PROPOSAL_STATUS_DEPOSIT_PERIOD": 1, + "PROPOSAL_STATUS_VOTING_PERIOD": 2, + "PROPOSAL_STATUS_PASSED": 3, + "PROPOSAL_STATUS_REJECTED": 4, + "PROPOSAL_STATUS_FAILED": 5, } func (ProposalStatus) EnumDescriptor() ([]byte, []int) { @@ -439,82 +450,84 @@ func init() { func init() { proto.RegisterFile("x/gov/types/types.proto", fileDescriptor_a5ae5e91b5b3fb03) } var fileDescriptor_a5ae5e91b5b3fb03 = []byte{ - // 1187 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x57, 0x31, 0x6f, 0xdb, 0x46, - 0x14, 0x26, 0x25, 0x59, 0xb6, 0x4f, 0xb2, 0xc2, 0x9c, 0xdd, 0x44, 0x25, 0x0a, 0x92, 0x51, 0x82, - 0xc0, 0x4d, 0x11, 0xaa, 0x71, 0x86, 0x02, 0x19, 0x8a, 0x8a, 0x11, 0x93, 0x28, 0x88, 0x25, 0x81, - 0x12, 0x1c, 0xb8, 0x45, 0x41, 0xd0, 0x22, 0x4d, 0xb3, 0xa1, 0x78, 0xaa, 0xee, 0xa4, 0x5a, 0x5b, - 0xd1, 0xa1, 0x08, 0x34, 0x65, 0xcc, 0x22, 0xc0, 0x40, 0x33, 0x04, 0x45, 0x87, 0xfe, 0x0c, 0x6f, - 0xcd, 0x52, 0x20, 0xe8, 0xa0, 0x34, 0xf6, 0xd0, 0xa2, 0xe8, 0xe4, 0xa5, 0x40, 0xa7, 0x42, 0xbc, - 0xa3, 0x2d, 0xd9, 0x4e, 0x1d, 0x23, 0x2d, 0x50, 0x74, 0xb1, 0xcd, 0x77, 0xdf, 0xfb, 0xde, 0xbd, - 0xef, 0xde, 0x7d, 0x07, 0x83, 0xf3, 0x9b, 0x79, 0x17, 0x75, 0xf3, 0xa4, 0xd7, 0x72, 0x30, 0xfd, - 0xa9, 0xb6, 0xda, 0x88, 0x20, 0x38, 0xdf, 0x40, 0xb8, 0x89, 0xb0, 0x89, 0xed, 0x07, 0xea, 0xa6, - 0xea, 0xa2, 0xae, 0xda, 0xbd, 0x26, 0x9e, 0x3d, 0x82, 0x13, 0x2f, 0x93, 0x0d, 0xaf, 0x6d, 0x9b, - 0x2d, 0xab, 0x4d, 0x7a, 0xf9, 0x30, 0x94, 0x77, 0x91, 0x8b, 0x0e, 0xfe, 0x62, 0x38, 0xd9, 0x45, - 0xc8, 0xf5, 0x1d, 0x0a, 0x59, 0xeb, 0xac, 0xe7, 0x89, 0xd7, 0x74, 0x30, 0xb1, 0x9a, 0x2d, 0x0a, - 0xc8, 0xfd, 0xc1, 0x83, 0xb7, 0x96, 0xb1, 0x5b, 0xeb, 0xac, 0x35, 0x3d, 0x52, 0x6d, 0xa3, 0x16, - 0xc2, 0x96, 0xaf, 0x59, 0xd8, 0x81, 0x0f, 0x79, 0x70, 0xc6, 0x0b, 0x3c, 0xe2, 0x59, 0xbe, 0x69, - 0x3b, 0x2d, 0x84, 0x3d, 0x92, 0xe5, 0x95, 0xf8, 0x62, 0x6a, 0x69, 0x5e, 0x1d, 0xdb, 0x65, 0xf7, - 0x9a, 0x7a, 0x13, 0x79, 0x81, 0x76, 0x77, 0x7b, 0x28, 0x73, 0x7b, 0x43, 0xf9, 0x5c, 0xcf, 0x6a, - 0xfa, 0x37, 0x72, 0x87, 0x32, 0x73, 0xdf, 0xbe, 0x90, 0x17, 0x5d, 0x8f, 0x6c, 0x74, 0xd6, 0xd4, - 0x06, 0x6a, 0xe6, 0x29, 0x01, 0xfb, 0x75, 0x15, 0xdb, 0x0f, 0x58, 0x77, 0x23, 0x2a, 0x6c, 0x64, - 0x58, 0x76, 0x91, 0x26, 0xc3, 0x65, 0x30, 0xd3, 0x0a, 0xb7, 0xe6, 0xb4, 0xb3, 0x31, 0x85, 0x5f, - 0x4c, 0x6b, 0xd7, 0xfe, 0x1c, 0xca, 0x57, 0x5f, 0x83, 0xaf, 0xd0, 0x68, 0x14, 0x6c, 0xbb, 0xed, - 0x60, 0x6c, 0xec, 0x53, 0xdc, 0x48, 0xfc, 0xba, 0x25, 0xf3, 0xb9, 0x5f, 0x78, 0x30, 0xbd, 0x8c, - 0xdd, 0x15, 0x44, 0x1c, 0x58, 0x07, 0xa9, 0x16, 0xeb, 0xdd, 0xf4, 0xec, 0x2c, 0xaf, 0xf0, 0x8b, - 0x09, 0xed, 0xfa, 0xce, 0x50, 0x06, 0x91, 0x24, 0xa5, 0xe2, 0x6f, 0x43, 0x79, 0x1c, 0xb4, 0x37, - 0x94, 0x21, 0x6d, 0x75, 0x2c, 0x98, 0x33, 0x40, 0xf4, 0x55, 0xb2, 0xe1, 0x6d, 0x30, 0xd5, 0x45, - 0xe4, 0x4d, 0xf6, 0x4c, 0xf3, 0xe1, 0x07, 0x20, 0x89, 0x5a, 0xc4, 0x43, 0x41, 0x36, 0xae, 0xf0, - 0x8b, 0x99, 0x25, 0x59, 0x3d, 0x66, 0x4c, 0xd4, 0x51, 0x27, 0x95, 0x10, 0x66, 0x30, 0x38, 0xeb, - 0xf4, 0x71, 0x0c, 0x80, 0x65, 0xec, 0x46, 0x6a, 0xfe, 0x3b, 0xcd, 0x56, 0xc0, 0x2c, 0x3b, 0x6b, - 0xf4, 0x06, 0x0d, 0x1f, 0x70, 0xc0, 0x4f, 0x41, 0xd2, 0x6a, 0xa2, 0x4e, 0x40, 0xb2, 0xf1, 0x57, - 0x4f, 0xdd, 0xfb, 0xa3, 0xa9, 0x3b, 0xd5, 0x6c, 0x31, 0x52, 0x26, 0xcd, 0x3d, 0x90, 0xae, 0x3b, - 0x9b, 0xfb, 0x83, 0x0f, 0x17, 0xc0, 0x14, 0xf1, 0x88, 0xef, 0x84, 0xaa, 0xcc, 0x1a, 0xf4, 0x03, - 0x2a, 0x20, 0x65, 0x3b, 0xb8, 0xd1, 0xf6, 0xe8, 0x21, 0xc4, 0xc2, 0xb5, 0xf1, 0x10, 0x63, 0xfb, - 0x3a, 0x06, 0xa6, 0x23, 0x95, 0xf5, 0xe3, 0x54, 0xbe, 0x34, 0xa9, 0xf2, 0xff, 0x56, 0xd6, 0x1f, - 0x92, 0x20, 0x3d, 0x61, 0x26, 0xda, 0x71, 0x6a, 0x5c, 0x38, 0x32, 0x73, 0xb1, 0x70, 0xd4, 0x66, - 0x99, 0x85, 0x1c, 0x92, 0xe2, 0x3e, 0x48, 0x62, 0x62, 0x91, 0x0e, 0x0e, 0x75, 0xc8, 0x2c, 0x5d, - 0x3c, 0xf6, 0x16, 0x44, 0x7c, 0xb5, 0x10, 0xaa, 0x89, 0x07, 0x96, 0xb4, 0xbf, 0x01, 0xca, 0x92, - 0x33, 0x18, 0x1d, 0xfc, 0x1c, 0xc0, 0x75, 0x2f, 0xb0, 0x7c, 0x93, 0x58, 0xbe, 0xdf, 0x33, 0xdb, - 0x0e, 0xee, 0xf8, 0x24, 0xbc, 0x6a, 0xa9, 0x25, 0xe5, 0xd8, 0x22, 0xf5, 0x11, 0xd0, 0x08, 0x71, - 0xda, 0x05, 0x66, 0x7c, 0x6f, 0xd3, 0x2a, 0x47, 0x99, 0x72, 0x86, 0x10, 0x06, 0xc7, 0x92, 0xe0, - 0x27, 0x20, 0x85, 0x43, 0xcb, 0x35, 0x47, 0x86, 0x9c, 0x4d, 0x84, 0xb5, 0x44, 0x95, 0xba, 0xb5, - 0x1a, 0xb9, 0xb5, 0x5a, 0x8f, 0xdc, 0x5a, 0x93, 0x58, 0x15, 0x36, 0x2f, 0x63, 0xc9, 0xb9, 0x47, - 0x2f, 0x64, 0xde, 0x00, 0x34, 0x32, 0x4a, 0x80, 0x1e, 0x10, 0xd8, 0x79, 0x9b, 0x4e, 0x60, 0xd3, - 0x0a, 0x53, 0x27, 0x56, 0xb8, 0xc8, 0x2a, 0x9c, 0xa7, 0x15, 0x0e, 0x33, 0xd0, 0x32, 0x19, 0x16, - 0xd6, 0x03, 0x3b, 0x2c, 0xf5, 0x15, 0x0f, 0xe6, 0x08, 0x22, 0x63, 0x4f, 0x44, 0xf2, 0xd5, 0x53, - 0x75, 0x87, 0x55, 0x58, 0xa0, 0x15, 0x26, 0xf2, 0x4e, 0xf7, 0x40, 0xa4, 0xc3, 0xdc, 0xe8, 0xaa, - 0xf9, 0xe0, 0x6c, 0x17, 0x11, 0x2f, 0x70, 0x47, 0x27, 0xdb, 0x66, 0x92, 0x4e, 0x9f, 0xd8, 0xf0, - 0x25, 0xb6, 0x9d, 0x2c, 0xdd, 0xce, 0x11, 0x0a, 0xda, 0xf1, 0x19, 0x1a, 0xaf, 0x8d, 0xc2, 0x61, - 0xcb, 0xeb, 0x80, 0x85, 0x0e, 0xc4, 0x9d, 0x39, 0xb1, 0x56, 0x6e, 0xf2, 0x75, 0x3c, 0x44, 0x40, - 0x2b, 0xcd, 0xd1, 0x28, 0x93, 0xf6, 0x46, 0xfa, 0xf1, 0x96, 0xcc, 0x3f, 0xdd, 0x92, 0xf9, 0xf0, - 0x46, 0x6d, 0xc7, 0x40, 0x6a, 0x7c, 0x80, 0x3e, 0x02, 0xf1, 0x9e, 0x83, 0xa9, 0x4d, 0x69, 0xea, - 0x88, 0xfd, 0xa7, 0xa1, 0x7c, 0xf9, 0x35, 0x04, 0x2c, 0x05, 0xc4, 0x18, 0xa5, 0xc2, 0x3b, 0x60, - 0xda, 0x5a, 0xc3, 0xc4, 0xf2, 0x98, 0xa1, 0x9d, 0x9a, 0x25, 0x4a, 0x87, 0x1f, 0x82, 0x58, 0x80, - 0xc2, 0xfb, 0x72, 0x7a, 0x92, 0x58, 0x80, 0xa0, 0x0b, 0xd2, 0x01, 0x32, 0xbf, 0xf0, 0xc8, 0x86, - 0xd9, 0x75, 0x08, 0x0a, 0x6f, 0xc3, 0xac, 0xa6, 0x9f, 0x8e, 0x69, 0x6f, 0x28, 0xcf, 0x53, 0x71, - 0xc7, 0xb9, 0x72, 0x06, 0x08, 0xd0, 0x7d, 0x8f, 0x6c, 0xac, 0x38, 0x04, 0x31, 0x73, 0xfa, 0x91, - 0x07, 0x89, 0xf0, 0xd5, 0xff, 0x87, 0x2c, 0xfa, 0x3f, 0xf2, 0xcc, 0x5f, 0xf9, 0x8e, 0x07, 0xe0, - 0x60, 0x11, 0x8a, 0x60, 0x4a, 0x5f, 0xae, 0xd6, 0x57, 0x05, 0x4e, 0x3c, 0xd3, 0x1f, 0x28, 0x29, - 0x1a, 0xd6, 0x9b, 0x2d, 0xd2, 0x83, 0xe7, 0x40, 0x7c, 0x55, 0xaf, 0x09, 0xbc, 0x38, 0xd7, 0x1f, - 0x28, 0xb3, 0x74, 0x65, 0xd5, 0xc1, 0x50, 0x02, 0xd3, 0x05, 0xad, 0x56, 0x2f, 0x94, 0xca, 0x42, - 0x4c, 0x3c, 0xdb, 0x1f, 0x28, 0x73, 0x74, 0xad, 0xc0, 0x4e, 0x7a, 0x01, 0xc4, 0xca, 0x15, 0x21, - 0x2e, 0xa6, 0xfb, 0x03, 0x65, 0x86, 0x2e, 0x95, 0x11, 0xbc, 0x0c, 0xd2, 0xe5, 0x8a, 0x79, 0xbf, - 0x54, 0xbf, 0x63, 0xae, 0xe8, 0xf5, 0x8a, 0x90, 0x10, 0x17, 0xfa, 0x03, 0x45, 0x88, 0xd6, 0x23, - 0xf9, 0xc5, 0xf4, 0xc3, 0x6f, 0x24, 0xee, 0xe9, 0x13, 0x89, 0xfb, 0xfe, 0x89, 0xc4, 0x5d, 0xf9, - 0x9d, 0x07, 0x99, 0x49, 0xb3, 0x1e, 0x6d, 0xab, 0x5c, 0xba, 0x27, 0x70, 0x74, 0x5b, 0x34, 0x58, - 0xf6, 0x7c, 0xf8, 0x1e, 0xc8, 0x14, 0xf5, 0x6a, 0xa5, 0x56, 0xaa, 0x9b, 0x55, 0xdd, 0x28, 0x55, - 0x8a, 0x02, 0x2f, 0x9e, 0xef, 0x0f, 0x94, 0x79, 0x0a, 0x61, 0x3e, 0x50, 0x75, 0xda, 0x1e, 0xb2, - 0xe1, 0xbb, 0x60, 0x6e, 0xa5, 0x52, 0x2f, 0x95, 0x6f, 0x47, 0xd8, 0x98, 0x78, 0xae, 0x3f, 0x50, - 0x20, 0xc5, 0xae, 0x84, 0x77, 0x8c, 0x41, 0xdf, 0x01, 0xc9, 0x6a, 0xa1, 0x56, 0xd3, 0x8b, 0x42, - 0x5c, 0x14, 0xfa, 0x03, 0x25, 0x4d, 0x31, 0x55, 0x0b, 0x63, 0xc7, 0x86, 0x0a, 0x98, 0x31, 0xf4, - 0xbb, 0xfa, 0xcd, 0xba, 0x5e, 0x14, 0x12, 0x22, 0xec, 0x0f, 0x94, 0x0c, 0x5d, 0x37, 0x9c, 0xcf, - 0x9c, 0x06, 0x71, 0xc2, 0xfc, 0x5b, 0x85, 0xd2, 0x3d, 0xbd, 0x28, 0x4c, 0x8d, 0xe7, 0xdf, 0xb2, - 0x3c, 0xdf, 0xb1, 0x27, 0xdb, 0xd5, 0xca, 0xdb, 0x2f, 0x25, 0xee, 0xf9, 0x4b, 0x89, 0xfb, 0x72, - 0x47, 0xe2, 0xb6, 0x77, 0x24, 0xfe, 0xd9, 0x8e, 0xc4, 0xff, 0xbc, 0x23, 0xf1, 0x8f, 0x76, 0x25, - 0xee, 0xd9, 0xae, 0xc4, 0x3d, 0xdf, 0x95, 0xb8, 0x8f, 0xff, 0xde, 0x02, 0xc7, 0xfe, 0x6b, 0x58, - 0x4b, 0x86, 0x2e, 0x73, 0xfd, 0xaf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xe0, 0x2e, 0x55, 0x4b, - 0x0c, 0x00, 0x00, + // 1230 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x57, 0xcf, 0x8f, 0xd3, 0x46, + 0x14, 0x8e, 0xb3, 0xbf, 0xd8, 0x49, 0x36, 0x6b, 0x66, 0x29, 0x9b, 0xba, 0xaa, 0x6d, 0x02, 0x42, + 0x2b, 0x04, 0x5e, 0x58, 0x0e, 0x55, 0xa9, 0x54, 0x35, 0x26, 0x06, 0x8c, 0xd8, 0x38, 0xb2, 0xcd, + 0x22, 0x5a, 0x55, 0x96, 0x77, 0x6d, 0xbc, 0x2e, 0x8e, 0x27, 0xcd, 0xcc, 0xa6, 0xec, 0xad, 0xea, + 0xa1, 0x42, 0x39, 0x71, 0xe4, 0x12, 0x09, 0xa9, 0x1c, 0x50, 0x4f, 0xfd, 0x33, 0xf6, 0x56, 0x0e, + 0xad, 0x84, 0x7a, 0x08, 0x65, 0x39, 0xb4, 0xea, 0xa1, 0x07, 0x2e, 0x95, 0x7a, 0xaa, 0xe2, 0x19, + 0xb3, 0x4e, 0x76, 0xe9, 0xb2, 0xa2, 0x95, 0xaa, 0x5e, 0x92, 0xf8, 0xf9, 0xfb, 0xbe, 0x37, 0xef, + 0xcd, 0x9b, 0x6f, 0x14, 0x30, 0x7f, 0x67, 0x31, 0x40, 0x9d, 0x45, 0xb2, 0xd9, 0xf2, 0x31, 0xfd, + 0x54, 0x5a, 0x6d, 0x44, 0x10, 0x9c, 0x5b, 0x43, 0xb8, 0x89, 0xb0, 0x83, 0xbd, 0xdb, 0xca, 0x1d, + 0x25, 0x40, 0x1d, 0xa5, 0x73, 0x4e, 0x38, 0xbc, 0x0b, 0x27, 0x9c, 0x24, 0xeb, 0x61, 0xdb, 0x73, + 0x5a, 0x6e, 0x9b, 0x6c, 0x2e, 0x26, 0xa1, 0xc5, 0x00, 0x05, 0x68, 0xe7, 0x17, 0xc3, 0x49, 0x01, + 0x42, 0x41, 0xe4, 0x53, 0xc8, 0xea, 0xc6, 0xad, 0x45, 0x12, 0x36, 0x7d, 0x4c, 0xdc, 0x66, 0x8b, + 0x02, 0x2a, 0x7f, 0x70, 0xe0, 0xad, 0x65, 0x1c, 0x58, 0x1b, 0xab, 0xcd, 0x90, 0x34, 0xda, 0xa8, + 0x85, 0xb0, 0x1b, 0xa9, 0x2e, 0xf6, 0xe1, 0x5d, 0x0e, 0xcc, 0x86, 0x71, 0x48, 0x42, 0x37, 0x72, + 0x3c, 0xbf, 0x85, 0x70, 0x48, 0xca, 0x9c, 0x3c, 0xb6, 0x50, 0x58, 0x9a, 0x53, 0x32, 0xab, 0xec, + 0x9c, 0x53, 0x2e, 0xa2, 0x30, 0x56, 0xaf, 0x6e, 0xf5, 0xa5, 0xdc, 0x8b, 0xbe, 0x74, 0x74, 0xd3, + 0x6d, 0x46, 0x17, 0x2a, 0x23, 0xcc, 0xca, 0xb7, 0x4f, 0xa5, 0x85, 0x20, 0x24, 0xeb, 0x1b, 0xab, + 0xca, 0x1a, 0x6a, 0x2e, 0x52, 0x01, 0xf6, 0x75, 0x06, 0x7b, 0xb7, 0x59, 0x75, 0x03, 0x29, 0x6c, + 0x96, 0x18, 0xbb, 0x46, 0xc9, 0x70, 0x19, 0x1c, 0x6a, 0x25, 0x4b, 0xf3, 0xdb, 0xe5, 0xbc, 0xcc, + 0x2d, 0x14, 0xd5, 0x73, 0x7f, 0xf6, 0xa5, 0x33, 0xaf, 0xa1, 0x57, 0x5d, 0x5b, 0xab, 0x7a, 0x5e, + 0xdb, 0xc7, 0xd8, 0x7c, 0x29, 0x71, 0x61, 0xfc, 0xd7, 0x07, 0x12, 0x57, 0xf9, 0x85, 0x03, 0x53, + 0xcb, 0x38, 0x58, 0x41, 0xc4, 0x87, 0x36, 0x28, 0xb4, 0x58, 0xed, 0x4e, 0xe8, 0x95, 0x39, 0x99, + 0x5b, 0x18, 0x57, 0xcf, 0x6f, 0xf7, 0x25, 0x90, 0xb6, 0x44, 0xaf, 0xfd, 0xd6, 0x97, 0xb2, 0xa0, + 0x17, 0x7d, 0x09, 0xd2, 0x52, 0x33, 0xc1, 0x8a, 0x09, 0xd2, 0x27, 0xdd, 0x83, 0x97, 0xc1, 0x44, + 0x07, 0x91, 0x37, 0x59, 0x33, 0xe5, 0xc3, 0xf7, 0xc0, 0x24, 0x6a, 0x91, 0x10, 0xc5, 0xe5, 0x31, + 0x99, 0x5b, 0x28, 0x2d, 0x49, 0xca, 0x1e, 0x63, 0xa2, 0x0c, 0x2a, 0x31, 0x12, 0x98, 0xc9, 0xe0, + 0xac, 0xd2, 0xfb, 0x79, 0x00, 0x96, 0x71, 0x90, 0x76, 0xf3, 0xdf, 0x29, 0xd6, 0x00, 0xd3, 0x6c, + 0xaf, 0xd1, 0x1b, 0x14, 0xbc, 0xa3, 0x01, 0x3f, 0x05, 0x93, 0x6e, 0x13, 0x6d, 0xc4, 0xa4, 0x3c, + 0xf6, 0xea, 0xa9, 0x3b, 0x3b, 0x98, 0xba, 0x03, 0xcd, 0x16, 0x13, 0x65, 0xad, 0xb9, 0x06, 0x8a, + 0xb6, 0x7f, 0xe7, 0xe5, 0xe0, 0xc3, 0x23, 0x60, 0x82, 0x84, 0x24, 0xf2, 0x93, 0xae, 0x4c, 0x9b, + 0xf4, 0x01, 0xca, 0xa0, 0xe0, 0xf9, 0x78, 0xad, 0x1d, 0xd2, 0x4d, 0xc8, 0x27, 0xef, 0xb2, 0x21, + 0xa6, 0xf6, 0x75, 0x1e, 0x4c, 0xa5, 0x5d, 0xd6, 0xf6, 0xea, 0xf2, 0x89, 0xe1, 0x2e, 0xff, 0x6f, + 0xdb, 0xfa, 0xfd, 0x24, 0x28, 0x0e, 0x99, 0x89, 0xba, 0x57, 0x37, 0x8e, 0xed, 0x9a, 0xb9, 0x7c, + 0x32, 0x6a, 0xd3, 0xcc, 0x42, 0x46, 0x5a, 0x71, 0x03, 0x4c, 0x62, 0xe2, 0x92, 0x0d, 0x9c, 0xf4, + 0xa1, 0xb4, 0x74, 0x7c, 0xcf, 0x53, 0x90, 0xea, 0x59, 0x09, 0x54, 0x15, 0x76, 0x2c, 0xe9, 0xe5, + 0x02, 0xa8, 0x4a, 0xc5, 0x64, 0x72, 0xf0, 0x73, 0x00, 0x6f, 0x85, 0xb1, 0x1b, 0x39, 0xc4, 0x8d, + 0xa2, 0x4d, 0xa7, 0xed, 0xe3, 0x8d, 0x88, 0x24, 0x47, 0xad, 0xb0, 0x24, 0xef, 0x99, 0xc4, 0x1e, + 0x00, 0xcd, 0x04, 0xa7, 0x1e, 0x63, 0xc6, 0xf7, 0x36, 0xcd, 0xb2, 0x5b, 0xa9, 0x62, 0xf2, 0x49, + 0x30, 0x43, 0x82, 0x9f, 0x80, 0x02, 0x4e, 0x2c, 0xd7, 0x19, 0x18, 0x72, 0x79, 0x3c, 0xc9, 0x25, + 0x28, 0xd4, 0xad, 0x95, 0xd4, 0xad, 0x15, 0x3b, 0x75, 0x6b, 0x55, 0x64, 0x59, 0xd8, 0xbc, 0x64, + 0xc8, 0x95, 0x7b, 0x4f, 0x25, 0xce, 0x04, 0x34, 0x32, 0x20, 0xc0, 0x10, 0xf0, 0x6c, 0xbf, 0x1d, + 0x3f, 0xf6, 0x68, 0x86, 0x89, 0x7d, 0x33, 0x1c, 0x67, 0x19, 0xe6, 0x69, 0x86, 0x51, 0x05, 0x9a, + 0xa6, 0xc4, 0xc2, 0x5a, 0xec, 0x25, 0xa9, 0xbe, 0xe2, 0xc0, 0x0c, 0x41, 0x24, 0x73, 0x45, 0x4c, + 0xbe, 0x7a, 0xaa, 0xae, 0xb0, 0x0c, 0x47, 0x68, 0x86, 0x21, 0xde, 0xc1, 0x2e, 0x88, 0x62, 0xc2, + 0x4d, 0x8f, 0x5a, 0x04, 0x0e, 0x77, 0x10, 0x09, 0xe3, 0x60, 0xb0, 0xb3, 0x6d, 0xd6, 0xd2, 0xa9, + 0x7d, 0x0b, 0x3e, 0xc1, 0x96, 0x53, 0xa6, 0xcb, 0xd9, 0x25, 0x41, 0x2b, 0x9e, 0xa5, 0x71, 0x6b, + 0x10, 0x4e, 0x4a, 0xbe, 0x05, 0x58, 0x68, 0xa7, 0xb9, 0x87, 0xf6, 0xcd, 0x55, 0x19, 0xbe, 0x1d, + 0x47, 0x04, 0x68, 0xa6, 0x19, 0x1a, 0x65, 0xad, 0xbd, 0x50, 0xbc, 0xff, 0x40, 0xe2, 0x1e, 0x3d, + 0x90, 0xb8, 0xe4, 0x44, 0x6d, 0xe5, 0x41, 0x21, 0x3b, 0x40, 0x1f, 0x81, 0xb1, 0x4d, 0x1f, 0x53, + 0x9b, 0x52, 0x95, 0x81, 0xfa, 0x4f, 0x7d, 0xe9, 0xe4, 0x6b, 0x34, 0x50, 0x8f, 0x89, 0x39, 0xa0, + 0xc2, 0x2b, 0x60, 0xca, 0x5d, 0xc5, 0xc4, 0x0d, 0x99, 0xa1, 0x1d, 0x58, 0x25, 0xa5, 0xc3, 0x0f, + 0x41, 0x3e, 0x46, 0xc9, 0x79, 0x39, 0xb8, 0x48, 0x3e, 0x46, 0x30, 0x00, 0xc5, 0x18, 0x39, 0x5f, + 0x84, 0x64, 0xdd, 0xe9, 0xf8, 0x04, 0x25, 0xa7, 0x61, 0x5a, 0xd5, 0x0e, 0xa6, 0xf4, 0xa2, 0x2f, + 0xcd, 0xd1, 0xe6, 0x66, 0xb5, 0x2a, 0x26, 0x88, 0xd1, 0x8d, 0x90, 0xac, 0xaf, 0xf8, 0x04, 0x31, + 0x73, 0xfa, 0x91, 0x03, 0xe3, 0xc9, 0xad, 0xff, 0x0f, 0x59, 0xf4, 0x7f, 0xe4, 0x9a, 0x3f, 0xf5, + 0x3b, 0x07, 0xc0, 0xce, 0x4b, 0x78, 0x1a, 0xcc, 0xaf, 0x18, 0xb6, 0xe6, 0x18, 0x0d, 0x5b, 0x37, + 0xea, 0xce, 0xf5, 0xba, 0xd5, 0xd0, 0x2e, 0xea, 0x97, 0x74, 0xad, 0xc6, 0xe7, 0x84, 0xd9, 0x6e, + 0x4f, 0x2e, 0x50, 0xa0, 0xd6, 0x6c, 0x91, 0x4d, 0x58, 0x01, 0xb3, 0x59, 0xf4, 0x4d, 0xcd, 0xe2, + 0x39, 0x61, 0xa6, 0xdb, 0x93, 0xa7, 0x29, 0xea, 0xa6, 0x8f, 0xe1, 0x29, 0x30, 0x97, 0xc5, 0x54, + 0x55, 0xcb, 0xae, 0xea, 0x75, 0x3e, 0x2f, 0x1c, 0xee, 0xf6, 0xe4, 0x19, 0x8a, 0xab, 0xb2, 0x99, + 0x90, 0x41, 0x29, 0x8b, 0xad, 0x1b, 0xfc, 0x98, 0x50, 0xec, 0xf6, 0xe4, 0x43, 0x14, 0x56, 0x47, + 0x70, 0x09, 0x94, 0x87, 0x11, 0xce, 0x0d, 0xdd, 0xbe, 0xe2, 0xac, 0x68, 0xb6, 0xc1, 0x8f, 0x0b, + 0x47, 0xba, 0x3d, 0x99, 0x4f, 0xb1, 0xe9, 0x06, 0x0a, 0xc5, 0xbb, 0xdf, 0x88, 0xb9, 0x47, 0x0f, + 0xc5, 0xdc, 0x77, 0x0f, 0xc5, 0xdc, 0xa9, 0x1f, 0xf2, 0xa0, 0x34, 0x6c, 0xf7, 0x50, 0x01, 0xef, + 0x34, 0x4c, 0xa3, 0x61, 0x58, 0xd5, 0x6b, 0x8e, 0x65, 0x57, 0xed, 0xeb, 0xd6, 0x48, 0xe1, 0x49, + 0x49, 0x14, 0x5c, 0x0f, 0x23, 0xf8, 0x01, 0x10, 0x47, 0xf1, 0x35, 0xad, 0x61, 0x58, 0xba, 0xed, + 0x34, 0x34, 0x53, 0x37, 0x6a, 0x3c, 0x27, 0xcc, 0x77, 0x7b, 0xf2, 0x1c, 0xa5, 0x30, 0xc7, 0x69, + 0xf8, 0xed, 0x10, 0x79, 0xf0, 0x7d, 0xf0, 0xee, 0x28, 0x79, 0xc5, 0xb0, 0xf5, 0xfa, 0xe5, 0x94, + 0x9b, 0x17, 0x8e, 0x76, 0x7b, 0x32, 0xa4, 0xdc, 0x95, 0xe4, 0x74, 0x33, 0xea, 0x69, 0x70, 0x74, + 0x94, 0xda, 0xa8, 0x5a, 0x96, 0x56, 0xe3, 0xc7, 0x04, 0xbe, 0xdb, 0x93, 0x8b, 0x94, 0xd3, 0x70, + 0x31, 0xf6, 0x3d, 0x78, 0x16, 0x94, 0x47, 0xd1, 0xa6, 0x76, 0x55, 0xbb, 0x68, 0x6b, 0x35, 0x7e, + 0x5c, 0x80, 0xdd, 0x9e, 0x5c, 0xa2, 0x78, 0xd3, 0xff, 0xcc, 0x5f, 0x23, 0xfe, 0x9e, 0xfa, 0x97, + 0xaa, 0xfa, 0x35, 0xad, 0xc6, 0x4f, 0x64, 0xf5, 0x2f, 0xb9, 0x61, 0xe4, 0x7b, 0xc3, 0x6d, 0x55, + 0xeb, 0x5b, 0xcf, 0xc4, 0xdc, 0x93, 0x67, 0x62, 0xee, 0xcb, 0x6d, 0x31, 0xb7, 0xb5, 0x2d, 0x72, + 0x8f, 0xb7, 0x45, 0xee, 0xe7, 0x6d, 0x91, 0xbb, 0xf7, 0x5c, 0xcc, 0x3d, 0x7e, 0x2e, 0xe6, 0x9e, + 0x3c, 0x17, 0x73, 0x1f, 0xff, 0xbd, 0x59, 0x67, 0xfe, 0xdf, 0xac, 0x4e, 0x26, 0x7e, 0x78, 0xfe, + 0xaf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc7, 0x53, 0x05, 0xd1, 0xf5, 0x0c, 0x00, 0x00, } func (this *MsgSubmitProposalBase) Equal(that interface{}) bool { diff --git a/x/gov/types/types.proto b/x/gov/types/types.proto index 855826516a99..ea6da041a193 100644 --- a/x/gov/types/types.proto +++ b/x/gov/types/types.proto @@ -61,11 +61,16 @@ enum VoteOption { option (gogoproto.goproto_enum_stringer) = false; option (gogoproto.goproto_enum_prefix) = false; - EMPTY = 0 [(gogoproto.enumvalue_customname) = "OptionEmpty"]; - YES = 1 [(gogoproto.enumvalue_customname) = "OptionYes"]; - ABSTAIN = 2 [(gogoproto.enumvalue_customname) = "OptionAbstain"]; - NO = 3 [(gogoproto.enumvalue_customname) = "OptionNo"]; - NO_WITH_VETO = 4 [(gogoproto.enumvalue_customname) = "OptionNoWithVeto"]; + // VOTE_OPTION_UNSPECIFIED defines a no-op vote option. + VOTE_OPTION_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "OptionEmpty"]; + // VOTE_OPTION_YES defines a yes vote option. + VOTE_OPTION_YES = 1 [(gogoproto.enumvalue_customname) = "OptionYes"]; + // VOTE_OPTION_ABSTAIN defines an abstain vote option. + VOTE_OPTION_ABSTAIN = 2 [(gogoproto.enumvalue_customname) = "OptionAbstain"]; + // VOTE_OPTION_NO defines a no vote option. + VOTE_OPTION_NO = 3 [(gogoproto.enumvalue_customname) = "OptionNo"]; + // VOTE_OPTION_NO_WITH_VETO defines a no with veto vote option. + VOTE_OPTION_NO_WITH_VETO = 4 [(gogoproto.enumvalue_customname) = "OptionNoWithVeto"]; } // TextProposal defines a standard text proposal whose changes need to be @@ -121,12 +126,18 @@ enum ProposalStatus { option (gogoproto.goproto_enum_stringer) = false; option (gogoproto.goproto_enum_prefix) = false; - NIL = 0 [(gogoproto.enumvalue_customname) = "StatusNil"]; - DEPOSIT_PERIOD = 1 [(gogoproto.enumvalue_customname) = "StatusDepositPeriod"]; - VOTING_PERIOD = 2 [(gogoproto.enumvalue_customname) = "StatusVotingPeriod"]; - PASSED = 3 [(gogoproto.enumvalue_customname) = "StatusPassed"]; - REJECTED = 4 [(gogoproto.enumvalue_customname) = "StatusRejected"]; - FAILED = 5 [(gogoproto.enumvalue_customname) = "StatusFailed"]; + // PROPOSAL_STATUS_UNSPECIFIED defines the default propopsal status. + PROPOSAL_STATUS_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "StatusNil"]; + // PROPOSAL_STATUS_DEPOSIT_PERIOD defines a proposal status during the deposit period. + PROPOSAL_STATUS_DEPOSIT_PERIOD = 1 [(gogoproto.enumvalue_customname) = "StatusDepositPeriod"]; + // PROPOSAL_STATUS_VOTING_PERIOD defines a proposal status during the voting period. + PROPOSAL_STATUS_VOTING_PERIOD = 2 [(gogoproto.enumvalue_customname) = "StatusVotingPeriod"]; + // PROPOSAL_STATUS_PASSED defines a proposal status of a proposal that has passed. + PROPOSAL_STATUS_PASSED = 3 [(gogoproto.enumvalue_customname) = "StatusPassed"]; + // PROPOSAL_STATUS_REJECTED defines a proposal status of a proposal that has been rejected. + PROPOSAL_STATUS_REJECTED = 4 [(gogoproto.enumvalue_customname) = "StatusRejected"]; + // PROPOSAL_STATUS_FAILED defines a proposal status of a proposal that has failed. + PROPOSAL_STATUS_FAILED = 5 [(gogoproto.enumvalue_customname) = "StatusFailed"]; } // TallyResult defines a standard tally for a proposal From 04cf635c72c1fad30caf12c3530e29964896b930 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Tue, 3 Mar 2020 10:32:43 -0500 Subject: [PATCH 350/529] Add changelog entries --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f2efc89f107..8d5b7b5ced1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -135,6 +135,13 @@ serialization instead of Amino. Buffers for state serialization instead of Amino. * The `internal` sub-package has been removed in order to expose the types proto file. * The `x/upgrade` module now accepts a `codec.Marshaler` interface. +* (x/upgrade) [\#5737](https://github.com/cosmos/cosmos-sdk/pull/5737) Migrate the `x/gov` module to use Protocol +Buffers for state serialization instead of Amino. + * `MsgSubmitProposal` will be removed in favor of the application-level proto-defined `MsgSubmitProposal` which + implements the `MsgSubmitProposalI` interface. Applications should extend the `NewMsgSubmitProposalBase` type + to define their own concrete `MsgSubmitProposal` types. + * The module now accepts a `Codec` interface which extends the `codec.Marshaler` interface by + requiring a concrete codec to know how to serialize `Proposal` types. ### Improvements From c97a1b66ca8610cdcb5e37885e5cd864a4b284c3 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Tue, 3 Mar 2020 17:13:49 +0100 Subject: [PATCH 351/529] migrate TestJailedValidatorDelegations to simapp --- x/slashing/handler_test.go | 81 ++++++++++++++++++++++++++++++++++ x/slashing/old_handler_test.go | 74 ------------------------------- 2 files changed, 81 insertions(+), 74 deletions(-) diff --git a/x/slashing/handler_test.go b/x/slashing/handler_test.go index 134a10deb90f..8113acd299b8 100644 --- a/x/slashing/handler_test.go +++ b/x/slashing/handler_test.go @@ -2,7 +2,9 @@ package slashing_test import ( "errors" + "strings" "testing" + "time" "github.com/cosmos/cosmos-sdk/simapp" abci "github.com/tendermint/tendermint/abci/types" @@ -84,3 +86,82 @@ func TestCannotUnjailUnlessMeetMinSelfDelegation(t *testing.T) { require.Nil(t, res) require.True(t, errors.Is(slashing.ErrSelfDelegationTooLowToUnjail, err)) } + +func TestJailedValidatorDelegations(t *testing.T) { + // initial setup + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{Time: time.Unix(0, 0)}) + + pks := simapp.CreateTestPubKeys(3) + simapp.AddTestAddrsFromPubKeys(app, ctx, pks, sdk.TokensFromConsensusPower(20)) + app.SlashingKeeper.SetParams(ctx, slashingkeeper.TestParams()) + + stakingParams := app.StakingKeeper.GetParams(ctx) + app.StakingKeeper.SetParams(ctx, stakingParams) + + // create a validator + bondAmount := sdk.TokensFromConsensusPower(10) + valPubKey := pks[1] + valAddr, consAddr := sdk.ValAddress(pks[1].Address()), sdk.ConsAddress(pks[0].Address()) + + msgCreateVal := slashingkeeper.NewTestMsgCreateValidator(valAddr, valPubKey, bondAmount) + res, err := staking.NewHandler(app.StakingKeeper)(ctx, msgCreateVal) + require.NoError(t, err) + require.NotNil(t, res) + + // end block + staking.EndBlocker(ctx, app.StakingKeeper) + + // set dummy signing info + newInfo := slashing.NewValidatorSigningInfo(consAddr, 0, 0, time.Unix(0, 0), false, 0) + app.SlashingKeeper.SetValidatorSigningInfo(ctx, consAddr, newInfo) + + // delegate tokens to the validator + delAddr := sdk.AccAddress(pks[2].Address()) + msgDelegate := slashingkeeper.NewTestMsgDelegate(delAddr, valAddr, bondAmount) + res, err = staking.NewHandler(app.StakingKeeper)(ctx, msgDelegate) + require.NoError(t, err) + require.NotNil(t, res) + + unbondAmt := sdk.NewCoin(app.StakingKeeper.GetParams(ctx).BondDenom, bondAmount) + + // unbond validator total self-delegations (which should jail the validator) + msgUndelegate := staking.NewMsgUndelegate(sdk.AccAddress(valAddr), valAddr, unbondAmt) + res, err = staking.NewHandler(app.StakingKeeper)(ctx, msgUndelegate) + require.NoError(t, err) + require.NotNil(t, res) + + err = app.StakingKeeper.CompleteUnbonding(ctx, sdk.AccAddress(valAddr), valAddr) + require.Nil(t, err, "expected complete unbonding validator to be ok, got: %v", err) + + // verify validator still exists and is jailed + validator, found := app.StakingKeeper.GetValidator(ctx, valAddr) + require.True(t, found) + require.True(t, validator.IsJailed()) + + // verify the validator cannot unjail itself + res, err = slashing.NewHandler(app.SlashingKeeper)(ctx, slashing.NewMsgUnjail(valAddr)) + require.Error(t, err) + require.Nil(t, res) + + // self-delegate to validator + msgSelfDelegate := slashingkeeper.NewTestMsgDelegate(sdk.AccAddress(valAddr), valAddr, bondAmount) + res, err = staking.NewHandler(app.StakingKeeper)(ctx, msgSelfDelegate) + require.NoError(t, err) + require.NotNil(t, res) + + // verify the validator can now unjail itself + res, err = slashing.NewHandler(app.SlashingKeeper)(ctx, slashing.NewMsgUnjail(valAddr)) + require.NoError(t, err) + require.NotNil(t, res) +} + +func TestInvalidMsg(t *testing.T) { + k := slashing.Keeper{} + h := slashing.NewHandler(k) + + res, err := h(sdk.NewContext(nil, abci.Header{}, false, nil), sdk.NewTestMsg()) + require.Error(t, err) + require.Nil(t, res) + require.True(t, strings.Contains(err.Error(), "unrecognized slashing message type")) +} diff --git a/x/slashing/old_handler_test.go b/x/slashing/old_handler_test.go index 470acb7a8e5e..c8c66821c847 100644 --- a/x/slashing/old_handler_test.go +++ b/x/slashing/old_handler_test.go @@ -1,7 +1,6 @@ package slashing_test import ( - "strings" "testing" "time" @@ -15,79 +14,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking" ) -func TestJailedValidatorDelegations(t *testing.T) { - ctx, _, stakingKeeper, _, slashingKeeper := slashingkeeper.CreateTestInput(t, slashing.DefaultParams()) - - stakingParams := stakingKeeper.GetParams(ctx) - stakingKeeper.SetParams(ctx, stakingParams) - - // create a validator - bondAmount := sdk.TokensFromConsensusPower(10) - valPubKey := slashingkeeper.Pks[0] - valAddr, consAddr := slashingkeeper.Addrs[1], sdk.ConsAddress(slashingkeeper.Addrs[0]) - - msgCreateVal := slashingkeeper.NewTestMsgCreateValidator(valAddr, valPubKey, bondAmount) - res, err := staking.NewHandler(stakingKeeper)(ctx, msgCreateVal) - require.NoError(t, err) - require.NotNil(t, res) - - // end block - staking.EndBlocker(ctx, stakingKeeper) - - // set dummy signing info - newInfo := slashing.NewValidatorSigningInfo(consAddr, 0, 0, time.Unix(0, 0), false, 0) - slashingKeeper.SetValidatorSigningInfo(ctx, consAddr, newInfo) - - // delegate tokens to the validator - delAddr := sdk.AccAddress(slashingkeeper.Addrs[2]) - msgDelegate := slashingkeeper.NewTestMsgDelegate(delAddr, valAddr, bondAmount) - res, err = staking.NewHandler(stakingKeeper)(ctx, msgDelegate) - require.NoError(t, err) - require.NotNil(t, res) - - unbondAmt := sdk.NewCoin(stakingKeeper.GetParams(ctx).BondDenom, bondAmount) - - // unbond validator total self-delegations (which should jail the validator) - msgUndelegate := staking.NewMsgUndelegate(sdk.AccAddress(valAddr), valAddr, unbondAmt) - res, err = staking.NewHandler(stakingKeeper)(ctx, msgUndelegate) - require.NoError(t, err) - require.NotNil(t, res) - - err = stakingKeeper.CompleteUnbonding(ctx, sdk.AccAddress(valAddr), valAddr) - require.Nil(t, err, "expected complete unbonding validator to be ok, got: %v", err) - - // verify validator still exists and is jailed - validator, found := stakingKeeper.GetValidator(ctx, valAddr) - require.True(t, found) - require.True(t, validator.IsJailed()) - - // verify the validator cannot unjail itself - res, err = slashing.NewHandler(slashingKeeper)(ctx, slashing.NewMsgUnjail(valAddr)) - require.Error(t, err) - require.Nil(t, res) - - // self-delegate to validator - msgSelfDelegate := slashingkeeper.NewTestMsgDelegate(sdk.AccAddress(valAddr), valAddr, bondAmount) - res, err = staking.NewHandler(stakingKeeper)(ctx, msgSelfDelegate) - require.NoError(t, err) - require.NotNil(t, res) - - // verify the validator can now unjail itself - res, err = slashing.NewHandler(slashingKeeper)(ctx, slashing.NewMsgUnjail(valAddr)) - require.NoError(t, err) - require.NotNil(t, res) -} - -func TestInvalidMsg(t *testing.T) { - k := slashing.Keeper{} - h := slashing.NewHandler(k) - - res, err := h(sdk.NewContext(nil, abci.Header{}, false, nil), sdk.NewTestMsg()) - require.Error(t, err) - require.Nil(t, res) - require.True(t, strings.Contains(err.Error(), "unrecognized slashing message type")) -} - // Test a validator through uptime, downtime, revocation, // unrevocation, starting height reset, and revocation again func TestHandleAbsentValidator(t *testing.T) { From 78791f3c4e1611892a4fc9d4d131f950a422a2b2 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Tue, 3 Mar 2020 17:21:17 +0100 Subject: [PATCH 352/529] clean part of the code --- x/slashing/handler_test.go | 163 +++++++++++++++++++++++++++++ x/slashing/keeper/test_common.go | 127 +---------------------- x/slashing/old_handler_test.go | 170 ------------------------------- 3 files changed, 164 insertions(+), 296 deletions(-) delete mode 100644 x/slashing/old_handler_test.go diff --git a/x/slashing/handler_test.go b/x/slashing/handler_test.go index 8113acd299b8..955eeadb8e5c 100644 --- a/x/slashing/handler_test.go +++ b/x/slashing/handler_test.go @@ -6,6 +6,8 @@ import ( "testing" "time" + "github.com/cosmos/cosmos-sdk/x/slashing/types" + "github.com/cosmos/cosmos-sdk/simapp" abci "github.com/tendermint/tendermint/abci/types" @@ -165,3 +167,164 @@ func TestInvalidMsg(t *testing.T) { require.Nil(t, res) require.True(t, strings.Contains(err.Error(), "unrecognized slashing message type")) } + +// Test a validator through uptime, downtime, revocation, +// unrevocation, starting height reset, and revocation again +func TestHandleAbsentValidator(t *testing.T) { + // initial setup + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{Time: time.Unix(0, 0)}) + + pks := simapp.CreateTestPubKeys(1) + simapp.AddTestAddrsFromPubKeys(app, ctx, pks, sdk.TokensFromConsensusPower(200)) + app.SlashingKeeper.SetParams(ctx, slashingkeeper.TestParams()) + + power := int64(100) + amt := sdk.TokensFromConsensusPower(power) + addr, val := sdk.ValAddress(pks[0].Address()), pks[0] + sh := staking.NewHandler(app.StakingKeeper) + slh := slashing.NewHandler(app.SlashingKeeper) + + res, err := sh(ctx, slashingkeeper.NewTestMsgCreateValidator(addr, val, amt)) + require.NoError(t, err) + require.NotNil(t, res) + + staking.EndBlocker(ctx, app.StakingKeeper) + + require.Equal( + t, app.BankKeeper.GetAllBalances(ctx, sdk.AccAddress(addr)), + sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.GetParams(ctx).BondDenom, slashingkeeper.InitTokens.Sub(amt))), + ) + require.Equal(t, amt, app.StakingKeeper.Validator(ctx, addr).GetBondedTokens()) + + // will exist since the validator has been bonded + info, found := app.SlashingKeeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) + require.True(t, found) + require.Equal(t, int64(0), info.StartHeight) + require.Equal(t, int64(0), info.IndexOffset) + require.Equal(t, int64(0), info.MissedBlocksCounter) + require.Equal(t, time.Unix(0, 0).UTC(), info.JailedUntil) + height := int64(0) + + // 1000 first blocks OK + for ; height < app.SlashingKeeper.SignedBlocksWindow(ctx); height++ { + ctx = ctx.WithBlockHeight(height) + app.SlashingKeeper.HandleValidatorSignature(ctx, val.Address(), power, true) + } + info, found = app.SlashingKeeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) + require.True(t, found) + require.Equal(t, int64(0), info.StartHeight) + require.Equal(t, int64(0), info.MissedBlocksCounter) + + // 500 blocks missed + for ; height < app.SlashingKeeper.SignedBlocksWindow(ctx)+(app.SlashingKeeper.SignedBlocksWindow(ctx)-app.SlashingKeeper.MinSignedPerWindow(ctx)); height++ { + ctx = ctx.WithBlockHeight(height) + app.SlashingKeeper.HandleValidatorSignature(ctx, val.Address(), power, false) + } + info, found = app.SlashingKeeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) + require.True(t, found) + require.Equal(t, int64(0), info.StartHeight) + require.Equal(t, app.SlashingKeeper.SignedBlocksWindow(ctx)-app.SlashingKeeper.MinSignedPerWindow(ctx), info.MissedBlocksCounter) + + // validator should be bonded still + validator, _ := app.StakingKeeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) + require.Equal(t, sdk.Bonded, validator.GetStatus()) + + bondPool := app.StakingKeeper.GetBondedPool(ctx) + require.True(sdk.IntEq(t, amt, app.BankKeeper.GetBalance(ctx, bondPool.GetAddress(), app.StakingKeeper.BondDenom(ctx)).Amount)) + + // 501st block missed + ctx = ctx.WithBlockHeight(height) + app.SlashingKeeper.HandleValidatorSignature(ctx, val.Address(), power, false) + info, found = app.SlashingKeeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) + require.True(t, found) + require.Equal(t, int64(0), info.StartHeight) + // counter now reset to zero + require.Equal(t, int64(0), info.MissedBlocksCounter) + + // end block + staking.EndBlocker(ctx, app.StakingKeeper) + + // validator should have been jailed + validator, _ = app.StakingKeeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) + require.Equal(t, sdk.Unbonding, validator.GetStatus()) + + slashAmt := amt.ToDec().Mul(app.SlashingKeeper.SlashFractionDowntime(ctx)).RoundInt64() + + // validator should have been slashed + require.Equal(t, amt.Int64()-slashAmt, validator.GetTokens().Int64()) + + // 502nd block *also* missed (since the LastCommit would have still included the just-unbonded validator) + height++ + ctx = ctx.WithBlockHeight(height) + app.SlashingKeeper.HandleValidatorSignature(ctx, val.Address(), power, false) + info, found = app.SlashingKeeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) + require.True(t, found) + require.Equal(t, int64(0), info.StartHeight) + require.Equal(t, int64(1), info.MissedBlocksCounter) + + // end block + staking.EndBlocker(ctx, app.StakingKeeper) + + // validator should not have been slashed any more, since it was already jailed + validator, _ = app.StakingKeeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) + require.Equal(t, amt.Int64()-slashAmt, validator.GetTokens().Int64()) + + // unrevocation should fail prior to jail expiration + res, err = slh(ctx, types.NewMsgUnjail(addr)) + require.Error(t, err) + require.Nil(t, res) + + // unrevocation should succeed after jail expiration + ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(1, 0).Add(app.SlashingKeeper.DowntimeJailDuration(ctx))}) + res, err = slh(ctx, types.NewMsgUnjail(addr)) + require.NoError(t, err) + require.NotNil(t, res) + + // end block + staking.EndBlocker(ctx, app.StakingKeeper) + + // validator should be rebonded now + validator, _ = app.StakingKeeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) + require.Equal(t, sdk.Bonded, validator.GetStatus()) + + // validator should have been slashed + require.Equal(t, amt.Int64()-slashAmt, app.BankKeeper.GetBalance(ctx, bondPool.GetAddress(), app.StakingKeeper.BondDenom(ctx)).Amount.Int64()) + + // Validator start height should not have been changed + info, found = app.SlashingKeeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) + require.True(t, found) + require.Equal(t, int64(0), info.StartHeight) + // we've missed 2 blocks more than the maximum, so the counter was reset to 0 at 1 block more and is now 1 + require.Equal(t, int64(1), info.MissedBlocksCounter) + + // validator should not be immediately jailed again + height++ + ctx = ctx.WithBlockHeight(height) + app.SlashingKeeper.HandleValidatorSignature(ctx, val.Address(), power, false) + validator, _ = app.StakingKeeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) + require.Equal(t, sdk.Bonded, validator.GetStatus()) + + // 500 signed blocks + nextHeight := height + app.SlashingKeeper.MinSignedPerWindow(ctx) + 1 + for ; height < nextHeight; height++ { + ctx = ctx.WithBlockHeight(height) + app.SlashingKeeper.HandleValidatorSignature(ctx, val.Address(), power, false) + } + + // end block + staking.EndBlocker(ctx, app.StakingKeeper) + + // validator should be jailed again after 500 unsigned blocks + nextHeight = height + app.SlashingKeeper.MinSignedPerWindow(ctx) + 1 + for ; height <= nextHeight; height++ { + ctx = ctx.WithBlockHeight(height) + app.SlashingKeeper.HandleValidatorSignature(ctx, val.Address(), power, false) + } + + // end block + staking.EndBlocker(ctx, app.StakingKeeper) + + validator, _ = app.StakingKeeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) + require.Equal(t, sdk.Unbonding, validator.GetStatus()) +} diff --git a/x/slashing/keeper/test_common.go b/x/slashing/keeper/test_common.go index d80c68b7ed9e..20eb8eda643f 100644 --- a/x/slashing/keeper/test_common.go +++ b/x/slashing/keeper/test_common.go @@ -5,143 +5,18 @@ package keeper // noalias import ( - "encoding/hex" - "testing" - "time" - - "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/crypto" - "github.com/tendermint/tendermint/crypto/ed25519" - "github.com/tendermint/tendermint/libs/log" - dbm "github.com/tendermint/tm-db" - - "github.com/cosmos/cosmos-sdk/codec" - simappcodec "github.com/cosmos/cosmos-sdk/simapp/codec" - "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/bank" - "github.com/cosmos/cosmos-sdk/x/params/keeper" - paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" "github.com/cosmos/cosmos-sdk/x/slashing/types" "github.com/cosmos/cosmos-sdk/x/staking" - "github.com/cosmos/cosmos-sdk/x/supply" + "github.com/tendermint/tendermint/crypto" ) // TODO remove dependencies on staking (should only refer to validator set type from sdk) var ( - Pks = []crypto.PubKey{ - newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB50"), - newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB51"), - newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB52"), - } - Addrs = []sdk.ValAddress{ - sdk.ValAddress(Pks[0].Address()), - sdk.ValAddress(Pks[1].Address()), - sdk.ValAddress(Pks[2].Address()), - } InitTokens = sdk.TokensFromConsensusPower(200) - initCoins = sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, InitTokens)) ) -func createTestCodec() *codec.Codec { - cdc := codec.New() - sdk.RegisterCodec(cdc) - auth.RegisterCodec(cdc) - supply.RegisterCodec(cdc) - bank.RegisterCodec(cdc) - staking.RegisterCodec(cdc) - codec.RegisterCrypto(cdc) - return cdc -} - -func CreateTestInput(t *testing.T, defaults types.Params) (sdk.Context, bank.Keeper, staking.Keeper, paramtypes.Subspace, Keeper) { - keyAcc := sdk.NewKVStoreKey(auth.StoreKey) - keyBank := sdk.NewKVStoreKey(bank.StoreKey) - keyStaking := sdk.NewKVStoreKey(staking.StoreKey) - keySlashing := sdk.NewKVStoreKey(types.StoreKey) - keySupply := sdk.NewKVStoreKey(supply.StoreKey) - keyParams := sdk.NewKVStoreKey(paramtypes.StoreKey) - tkeyParams := sdk.NewTransientStoreKey(paramtypes.TStoreKey) - - db := dbm.NewMemDB() - - ms := store.NewCommitMultiStore(db) - ms.MountStoreWithDB(keyAcc, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(keyBank, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(keyStaking, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(keySupply, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(keySlashing, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(keyParams, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(tkeyParams, sdk.StoreTypeTransient, db) - - err := ms.LoadLatestVersion() - require.Nil(t, err) - - ctx := sdk.NewContext(ms, abci.Header{Time: time.Unix(0, 0)}, false, log.NewNopLogger()) - cdc := createTestCodec() - appCodec := simappcodec.NewAppCodec(cdc) - - feeCollectorAcc := supply.NewEmptyModuleAccount(auth.FeeCollectorName) - notBondedPool := supply.NewEmptyModuleAccount(staking.NotBondedPoolName, supply.Burner, supply.Staking) - bondPool := supply.NewEmptyModuleAccount(staking.BondedPoolName, supply.Burner, supply.Staking) - - blacklistedAddrs := make(map[string]bool) - blacklistedAddrs[feeCollectorAcc.GetAddress().String()] = true - blacklistedAddrs[notBondedPool.GetAddress().String()] = true - blacklistedAddrs[bondPool.GetAddress().String()] = true - - paramsKeeper := keeper.NewKeeper(appCodec, keyParams, tkeyParams) - accountKeeper := auth.NewAccountKeeper(appCodec, keyAcc, paramsKeeper.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount) - - bk := bank.NewBaseKeeper(appCodec, keyBank, accountKeeper, paramsKeeper.Subspace(bank.DefaultParamspace), blacklistedAddrs) - maccPerms := map[string][]string{ - auth.FeeCollectorName: nil, - staking.NotBondedPoolName: {supply.Burner, supply.Staking}, - staking.BondedPoolName: {supply.Burner, supply.Staking}, - } - supplyKeeper := supply.NewKeeper(appCodec, keySupply, accountKeeper, bk, maccPerms) - - totalSupply := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, InitTokens.MulRaw(int64(len(Addrs))))) - supplyKeeper.SetSupply(ctx, supply.NewSupply(totalSupply)) - - sk := staking.NewKeeper(staking.ModuleCdc, keyStaking, bk, supplyKeeper, paramsKeeper.Subspace(staking.DefaultParamspace)) - genesis := staking.DefaultGenesisState() - - // set module accounts - supplyKeeper.SetModuleAccount(ctx, feeCollectorAcc) - supplyKeeper.SetModuleAccount(ctx, bondPool) - supplyKeeper.SetModuleAccount(ctx, notBondedPool) - - _ = staking.InitGenesis(ctx, sk, accountKeeper, bk, supplyKeeper, genesis) - - for i, addr := range Addrs { - addr := sdk.AccAddress(addr) - accountKeeper.SetAccount(ctx, auth.NewBaseAccount(addr, Pks[i], uint64(i), 0)) - require.NoError(t, bk.SetBalances(ctx, addr, initCoins)) - } - - paramstore := paramsKeeper.Subspace(types.DefaultParamspace) - keeper := NewKeeper(types.ModuleCdc, keySlashing, &sk, paramstore) - - keeper.SetParams(ctx, defaults) - sk.SetHooks(keeper.Hooks()) - - return ctx, bk, sk, paramstore, keeper -} - -func newPubKey(pk string) (res crypto.PubKey) { - pkBytes, err := hex.DecodeString(pk) - if err != nil { - panic(err) - } - var pkEd ed25519.PubKeyEd25519 - copy(pkEd[:], pkBytes) - return pkEd -} - // Have to change these parameters for tests // lest the tests take forever func TestParams() types.Params { diff --git a/x/slashing/old_handler_test.go b/x/slashing/old_handler_test.go deleted file mode 100644 index c8c66821c847..000000000000 --- a/x/slashing/old_handler_test.go +++ /dev/null @@ -1,170 +0,0 @@ -package slashing_test - -import ( - "testing" - "time" - - "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/slashing" - slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" - "github.com/cosmos/cosmos-sdk/x/slashing/types" - "github.com/cosmos/cosmos-sdk/x/staking" -) - -// Test a validator through uptime, downtime, revocation, -// unrevocation, starting height reset, and revocation again -func TestHandleAbsentValidator(t *testing.T) { - // initial setup - ctx, bk, sk, _, keeper := slashingkeeper.CreateTestInput(t, slashingkeeper.TestParams()) - power := int64(100) - amt := sdk.TokensFromConsensusPower(power) - addr, val := slashingkeeper.Addrs[0], slashingkeeper.Pks[0] - sh := staking.NewHandler(sk) - slh := slashing.NewHandler(keeper) - - res, err := sh(ctx, slashingkeeper.NewTestMsgCreateValidator(addr, val, amt)) - require.NoError(t, err) - require.NotNil(t, res) - - staking.EndBlocker(ctx, sk) - - require.Equal( - t, bk.GetAllBalances(ctx, sdk.AccAddress(addr)), - sdk.NewCoins(sdk.NewCoin(sk.GetParams(ctx).BondDenom, slashingkeeper.InitTokens.Sub(amt))), - ) - require.Equal(t, amt, sk.Validator(ctx, addr).GetBondedTokens()) - - // will exist since the validator has been bonded - info, found := keeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) - require.True(t, found) - require.Equal(t, int64(0), info.StartHeight) - require.Equal(t, int64(0), info.IndexOffset) - require.Equal(t, int64(0), info.MissedBlocksCounter) - require.Equal(t, time.Unix(0, 0).UTC(), info.JailedUntil) - height := int64(0) - - // 1000 first blocks OK - for ; height < keeper.SignedBlocksWindow(ctx); height++ { - ctx = ctx.WithBlockHeight(height) - keeper.HandleValidatorSignature(ctx, val.Address(), power, true) - } - info, found = keeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) - require.True(t, found) - require.Equal(t, int64(0), info.StartHeight) - require.Equal(t, int64(0), info.MissedBlocksCounter) - - // 500 blocks missed - for ; height < keeper.SignedBlocksWindow(ctx)+(keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx)); height++ { - ctx = ctx.WithBlockHeight(height) - keeper.HandleValidatorSignature(ctx, val.Address(), power, false) - } - info, found = keeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) - require.True(t, found) - require.Equal(t, int64(0), info.StartHeight) - require.Equal(t, keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx), info.MissedBlocksCounter) - - // validator should be bonded still - validator, _ := sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) - require.Equal(t, sdk.Bonded, validator.GetStatus()) - - bondPool := sk.GetBondedPool(ctx) - require.True(sdk.IntEq(t, amt, bk.GetBalance(ctx, bondPool.GetAddress(), sk.BondDenom(ctx)).Amount)) - - // 501st block missed - ctx = ctx.WithBlockHeight(height) - keeper.HandleValidatorSignature(ctx, val.Address(), power, false) - info, found = keeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) - require.True(t, found) - require.Equal(t, int64(0), info.StartHeight) - // counter now reset to zero - require.Equal(t, int64(0), info.MissedBlocksCounter) - - // end block - staking.EndBlocker(ctx, sk) - - // validator should have been jailed - validator, _ = sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) - require.Equal(t, sdk.Unbonding, validator.GetStatus()) - - slashAmt := amt.ToDec().Mul(keeper.SlashFractionDowntime(ctx)).RoundInt64() - - // validator should have been slashed - require.Equal(t, amt.Int64()-slashAmt, validator.GetTokens().Int64()) - - // 502nd block *also* missed (since the LastCommit would have still included the just-unbonded validator) - height++ - ctx = ctx.WithBlockHeight(height) - keeper.HandleValidatorSignature(ctx, val.Address(), power, false) - info, found = keeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) - require.True(t, found) - require.Equal(t, int64(0), info.StartHeight) - require.Equal(t, int64(1), info.MissedBlocksCounter) - - // end block - staking.EndBlocker(ctx, sk) - - // validator should not have been slashed any more, since it was already jailed - validator, _ = sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) - require.Equal(t, amt.Int64()-slashAmt, validator.GetTokens().Int64()) - - // unrevocation should fail prior to jail expiration - res, err = slh(ctx, types.NewMsgUnjail(addr)) - require.Error(t, err) - require.Nil(t, res) - - // unrevocation should succeed after jail expiration - ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(1, 0).Add(keeper.DowntimeJailDuration(ctx))}) - res, err = slh(ctx, types.NewMsgUnjail(addr)) - require.NoError(t, err) - require.NotNil(t, res) - - // end block - staking.EndBlocker(ctx, sk) - - // validator should be rebonded now - validator, _ = sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) - require.Equal(t, sdk.Bonded, validator.GetStatus()) - - // validator should have been slashed - require.Equal(t, amt.Int64()-slashAmt, bk.GetBalance(ctx, bondPool.GetAddress(), sk.BondDenom(ctx)).Amount.Int64()) - - // Validator start height should not have been changed - info, found = keeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) - require.True(t, found) - require.Equal(t, int64(0), info.StartHeight) - // we've missed 2 blocks more than the maximum, so the counter was reset to 0 at 1 block more and is now 1 - require.Equal(t, int64(1), info.MissedBlocksCounter) - - // validator should not be immediately jailed again - height++ - ctx = ctx.WithBlockHeight(height) - keeper.HandleValidatorSignature(ctx, val.Address(), power, false) - validator, _ = sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) - require.Equal(t, sdk.Bonded, validator.GetStatus()) - - // 500 signed blocks - nextHeight := height + keeper.MinSignedPerWindow(ctx) + 1 - for ; height < nextHeight; height++ { - ctx = ctx.WithBlockHeight(height) - keeper.HandleValidatorSignature(ctx, val.Address(), power, false) - } - - // end block - staking.EndBlocker(ctx, sk) - - // validator should be jailed again after 500 unsigned blocks - nextHeight = height + keeper.MinSignedPerWindow(ctx) + 1 - for ; height <= nextHeight; height++ { - ctx = ctx.WithBlockHeight(height) - keeper.HandleValidatorSignature(ctx, val.Address(), power, false) - } - - // end block - staking.EndBlocker(ctx, sk) - - validator, _ = sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) - require.Equal(t, sdk.Unbonding, validator.GetStatus()) -} From 3517ebad4c123d8590065274fa192a5c68e0fde7 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Tue, 3 Mar 2020 17:45:02 +0100 Subject: [PATCH 353/529] remove internal package folder --- x/crisis/alias.go | 4 ++-- x/crisis/client/cli/tx.go | 2 +- x/crisis/genesis.go | 4 ++-- x/crisis/handler.go | 4 ++-- x/crisis/{internal => }/keeper/integration_test.go | 0 x/crisis/{internal => }/keeper/keeper.go | 2 +- x/crisis/{internal => }/keeper/keeper_test.go | 0 x/crisis/{internal => }/keeper/params.go | 2 +- x/crisis/module.go | 4 ++-- x/crisis/{internal => }/types/codec.go | 0 x/crisis/{internal => }/types/errors.go | 0 x/crisis/{internal => }/types/events.go | 0 x/crisis/{internal => }/types/expected_keepers.go | 0 x/crisis/{internal => }/types/genesis.go | 0 x/crisis/{internal => }/types/keys.go | 0 x/crisis/{internal => }/types/msgs.go | 0 x/crisis/{internal => }/types/params.go | 0 x/crisis/{internal => }/types/route.go | 0 x/crisis/{internal => }/types/types.pb.go | 0 x/crisis/{internal => }/types/types.proto | 0 20 files changed, 11 insertions(+), 11 deletions(-) rename x/crisis/{internal => }/keeper/integration_test.go (100%) rename x/crisis/{internal => }/keeper/keeper.go (98%) rename x/crisis/{internal => }/keeper/keeper_test.go (100%) rename x/crisis/{internal => }/keeper/params.go (89%) rename x/crisis/{internal => }/types/codec.go (100%) rename x/crisis/{internal => }/types/errors.go (100%) rename x/crisis/{internal => }/types/events.go (100%) rename x/crisis/{internal => }/types/expected_keepers.go (100%) rename x/crisis/{internal => }/types/genesis.go (100%) rename x/crisis/{internal => }/types/keys.go (100%) rename x/crisis/{internal => }/types/msgs.go (100%) rename x/crisis/{internal => }/types/params.go (100%) rename x/crisis/{internal => }/types/route.go (100%) rename x/crisis/{internal => }/types/types.pb.go (100%) rename x/crisis/{internal => }/types/types.proto (100%) diff --git a/x/crisis/alias.go b/x/crisis/alias.go index 1b05371f376b..8e831527dbfa 100644 --- a/x/crisis/alias.go +++ b/x/crisis/alias.go @@ -3,8 +3,8 @@ package crisis // nolint import ( - "github.com/cosmos/cosmos-sdk/x/crisis/internal/keeper" - "github.com/cosmos/cosmos-sdk/x/crisis/internal/types" + "github.com/cosmos/cosmos-sdk/x/crisis/keeper" + "github.com/cosmos/cosmos-sdk/x/crisis/types" ) const ( diff --git a/x/crisis/client/cli/tx.go b/x/crisis/client/cli/tx.go index d54153b8f6fb..47c421a0d15f 100644 --- a/x/crisis/client/cli/tx.go +++ b/x/crisis/client/cli/tx.go @@ -13,7 +13,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" authclient "github.com/cosmos/cosmos-sdk/x/auth/client" - "github.com/cosmos/cosmos-sdk/x/crisis/internal/types" + "github.com/cosmos/cosmos-sdk/x/crisis/types" ) // command to replace a delegator's withdrawal address diff --git a/x/crisis/genesis.go b/x/crisis/genesis.go index dede2ab89154..4d9ea3568542 100644 --- a/x/crisis/genesis.go +++ b/x/crisis/genesis.go @@ -2,8 +2,8 @@ package crisis import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/crisis/internal/keeper" - "github.com/cosmos/cosmos-sdk/x/crisis/internal/types" + "github.com/cosmos/cosmos-sdk/x/crisis/keeper" + "github.com/cosmos/cosmos-sdk/x/crisis/types" ) // new crisis genesis diff --git a/x/crisis/handler.go b/x/crisis/handler.go index c7e58b6861be..cd94db85a5b1 100644 --- a/x/crisis/handler.go +++ b/x/crisis/handler.go @@ -3,8 +3,8 @@ package crisis import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/cosmos-sdk/x/crisis/internal/keeper" - "github.com/cosmos/cosmos-sdk/x/crisis/internal/types" + "github.com/cosmos/cosmos-sdk/x/crisis/keeper" + "github.com/cosmos/cosmos-sdk/x/crisis/types" ) // RouterKey diff --git a/x/crisis/internal/keeper/integration_test.go b/x/crisis/keeper/integration_test.go similarity index 100% rename from x/crisis/internal/keeper/integration_test.go rename to x/crisis/keeper/integration_test.go diff --git a/x/crisis/internal/keeper/keeper.go b/x/crisis/keeper/keeper.go similarity index 98% rename from x/crisis/internal/keeper/keeper.go rename to x/crisis/keeper/keeper.go index d57030ed6c1f..1a29064dde95 100644 --- a/x/crisis/internal/keeper/keeper.go +++ b/x/crisis/keeper/keeper.go @@ -7,7 +7,7 @@ import ( "github.com/tendermint/tendermint/libs/log" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/crisis/internal/types" + "github.com/cosmos/cosmos-sdk/x/crisis/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" ) diff --git a/x/crisis/internal/keeper/keeper_test.go b/x/crisis/keeper/keeper_test.go similarity index 100% rename from x/crisis/internal/keeper/keeper_test.go rename to x/crisis/keeper/keeper_test.go diff --git a/x/crisis/internal/keeper/params.go b/x/crisis/keeper/params.go similarity index 89% rename from x/crisis/internal/keeper/params.go rename to x/crisis/keeper/params.go index cdf7169af07a..d44efa4ebf11 100644 --- a/x/crisis/internal/keeper/params.go +++ b/x/crisis/keeper/params.go @@ -2,7 +2,7 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/crisis/internal/types" + "github.com/cosmos/cosmos-sdk/x/crisis/types" ) // GetConstantFee get's the constant fee from the paramSpace diff --git a/x/crisis/module.go b/x/crisis/module.go index dd7ae3677217..93d30ee360e8 100644 --- a/x/crisis/module.go +++ b/x/crisis/module.go @@ -14,8 +14,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/x/crisis/client/cli" - "github.com/cosmos/cosmos-sdk/x/crisis/internal/keeper" - "github.com/cosmos/cosmos-sdk/x/crisis/internal/types" + "github.com/cosmos/cosmos-sdk/x/crisis/keeper" + "github.com/cosmos/cosmos-sdk/x/crisis/types" ) var ( diff --git a/x/crisis/internal/types/codec.go b/x/crisis/types/codec.go similarity index 100% rename from x/crisis/internal/types/codec.go rename to x/crisis/types/codec.go diff --git a/x/crisis/internal/types/errors.go b/x/crisis/types/errors.go similarity index 100% rename from x/crisis/internal/types/errors.go rename to x/crisis/types/errors.go diff --git a/x/crisis/internal/types/events.go b/x/crisis/types/events.go similarity index 100% rename from x/crisis/internal/types/events.go rename to x/crisis/types/events.go diff --git a/x/crisis/internal/types/expected_keepers.go b/x/crisis/types/expected_keepers.go similarity index 100% rename from x/crisis/internal/types/expected_keepers.go rename to x/crisis/types/expected_keepers.go diff --git a/x/crisis/internal/types/genesis.go b/x/crisis/types/genesis.go similarity index 100% rename from x/crisis/internal/types/genesis.go rename to x/crisis/types/genesis.go diff --git a/x/crisis/internal/types/keys.go b/x/crisis/types/keys.go similarity index 100% rename from x/crisis/internal/types/keys.go rename to x/crisis/types/keys.go diff --git a/x/crisis/internal/types/msgs.go b/x/crisis/types/msgs.go similarity index 100% rename from x/crisis/internal/types/msgs.go rename to x/crisis/types/msgs.go diff --git a/x/crisis/internal/types/params.go b/x/crisis/types/params.go similarity index 100% rename from x/crisis/internal/types/params.go rename to x/crisis/types/params.go diff --git a/x/crisis/internal/types/route.go b/x/crisis/types/route.go similarity index 100% rename from x/crisis/internal/types/route.go rename to x/crisis/types/route.go diff --git a/x/crisis/internal/types/types.pb.go b/x/crisis/types/types.pb.go similarity index 100% rename from x/crisis/internal/types/types.pb.go rename to x/crisis/types/types.pb.go diff --git a/x/crisis/internal/types/types.proto b/x/crisis/types/types.proto similarity index 100% rename from x/crisis/internal/types/types.proto rename to x/crisis/types/types.proto From bfac2a93423129fdd89eabfffb810d84cde75cdd Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Tue, 3 Mar 2020 16:57:33 +0000 Subject: [PATCH 354/529] fix types.ChainAnteDecorators() panic (#5742) * fix types.ChainAnteDecorators() panic ChainAnteDecorators() panics when no arguments are supplied. This change its behaviour and the function now returns a nil AnteHandler in case no AnteDecorator instances are supplied. Closes: #5741 * Append Terminator to non-terminated chains. * Fix test case --- CHANGELOG.md | 1 + types/handler.go | 12 ++++++------ types/handler_test.go | 28 ++++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 6 deletions(-) create mode 100644 types/handler_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f2efc89f107..9c98d0ea795c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -74,6 +74,7 @@ resulted in a panic when the tx execution mode was `CheckTx`. * (client) [\#5618](https://github.com/cosmos/cosmos-sdk/pull/5618) Fix crash on the client when the verifier is not set. * (x/distribution) [\#5620](https://github.com/cosmos/cosmos-sdk/pull/5620) Fix nil pointer deref in distribution tax/rewward validation helpers. * (genesis) [\#5086](https://github.com/cosmos/cosmos-sdk/issues/5086) Ensure `gentxs` are always an empty array instead of `nil` +* (types) [\#5741](https://github.com/cosmos/cosmos-sdk/issues/5741) Prevent ChainAnteDecorators() from panicking when empty AnteDecorator slice is supplied. ### State Machine Breaking diff --git a/types/handler.go b/types/handler.go index 6815230a861f..03d1f02d5806 100644 --- a/types/handler.go +++ b/types/handler.go @@ -25,15 +25,15 @@ type AnteDecorator interface { // MUST set GasMeter with the FIRST AnteDecorator. Failing to do so will cause // transactions to be processed with an infinite gasmeter and open a DOS attack vector. // Use `ante.SetUpContextDecorator` or a custom Decorator with similar functionality. +// Returns nil when no AnteDecorator are supplied. func ChainAnteDecorators(chain ...AnteDecorator) AnteHandler { - if (chain[len(chain)-1] != Terminator{}) { - chain = append(chain, Terminator{}) + if len(chain) == 0 { + return nil } - if len(chain) == 1 { - return func(ctx Context, tx Tx, simulate bool) (Context, error) { - return chain[0].AnteHandle(ctx, tx, simulate, nil) - } + // handle non-terminated decorators chain + if (chain[len(chain)-1] != Terminator{}) { + chain = append(chain, Terminator{}) } return func(ctx Context, tx Tx, simulate bool) (Context, error) { diff --git a/types/handler_test.go b/types/handler_test.go new file mode 100644 index 000000000000..4847a113137a --- /dev/null +++ b/types/handler_test.go @@ -0,0 +1,28 @@ +package types_test + +import ( + "testing" + + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/tests/mocks" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func TestChainAnteDecorators(t *testing.T) { + t.Parallel() + // test panic + require.Nil(t, sdk.ChainAnteDecorators([]sdk.AnteDecorator{}...)) + + ctx, tx := sdk.Context{}, sdk.Tx(nil) + mockCtrl := gomock.NewController(t) + mockAnteDecorator1 := mocks.NewMockAnteDecorator(mockCtrl) + mockAnteDecorator1.EXPECT().AnteHandle(gomock.Eq(ctx), gomock.Eq(tx), true, gomock.Any()).Times(1) + sdk.ChainAnteDecorators(mockAnteDecorator1)(ctx, tx, true) + + mockAnteDecorator2 := mocks.NewMockAnteDecorator(mockCtrl) + mockAnteDecorator1.EXPECT().AnteHandle(gomock.Eq(ctx), gomock.Eq(tx), true, mockAnteDecorator2).Times(1) + mockAnteDecorator2.EXPECT().AnteHandle(gomock.Eq(ctx), gomock.Eq(tx), true, nil).Times(1) + sdk.ChainAnteDecorators(mockAnteDecorator1, mockAnteDecorator2) +} From 9aa2581dc5461170a337d1d3e58f19b789f07466 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Tue, 3 Mar 2020 13:22:29 -0500 Subject: [PATCH 355/529] Update CHANGELOG.md Co-Authored-By: Aaron Craelius --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c4a97d2a1a4..19934bee5193 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -136,7 +136,7 @@ serialization instead of Amino. Buffers for state serialization instead of Amino. * The `internal` sub-package has been removed in order to expose the types proto file. * The `x/upgrade` module now accepts a `codec.Marshaler` interface. -* (x/upgrade) [\#5737](https://github.com/cosmos/cosmos-sdk/pull/5737) Migrate the `x/gov` module to use Protocol +* (x/gov) [\#5737](https://github.com/cosmos/cosmos-sdk/pull/5737) Migrate the `x/gov` module to use Protocol Buffers for state serialization instead of Amino. * `MsgSubmitProposal` will be removed in favor of the application-level proto-defined `MsgSubmitProposal` which implements the `MsgSubmitProposalI` interface. Applications should extend the `NewMsgSubmitProposalBase` type From 3b8772725f4acba13a449b9bf34dc22bbe924832 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Tue, 3 Mar 2020 13:24:54 -0500 Subject: [PATCH 356/529] Address feedback --- simapp/codec/codec.pb.go | 157 +++++++++++++++++++-------------------- simapp/codec/codec.proto | 4 +- 2 files changed, 77 insertions(+), 84 deletions(-) diff --git a/simapp/codec/codec.pb.go b/simapp/codec/codec.pb.go index cb065e4e1b5d..d0c66f7bdec9 100644 --- a/simapp/codec/codec.pb.go +++ b/simapp/codec/codec.pb.go @@ -359,8 +359,8 @@ var xxx_messageInfo_MsgSubmitEvidence proto.InternalMessageInfo // MsgSubmitProposal defines the application-level message type for handling // governance proposals. type MsgSubmitProposal struct { - Content *Content `protobuf:"bytes,1,opt,name=content,proto3" json:"content,omitempty"` - types4.MsgSubmitProposalBase `protobuf:"bytes,2,opt,name=base,proto3,embedded=base" json:"base"` + types4.MsgSubmitProposalBase `protobuf:"bytes,1,opt,name=base,proto3,embedded=base" json:"base"` + Content Content `protobuf:"bytes,2,opt,name=content,proto3" json:"content"` } func (m *MsgSubmitProposal) Reset() { *m = MsgSubmitProposal{} } @@ -585,62 +585,62 @@ func init() { func init() { proto.RegisterFile("simapp/codec/codec.proto", fileDescriptor_3c6d4085e4065f5a) } var fileDescriptor_3c6d4085e4065f5a = []byte{ - // 880 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x56, 0x41, 0x8f, 0xdb, 0x44, - 0x14, 0xb6, 0x5b, 0x77, 0x37, 0x9a, 0x16, 0x28, 0x23, 0xca, 0x46, 0x01, 0x25, 0x65, 0x0b, 0x15, - 0x14, 0xad, 0xdd, 0x52, 0xa0, 0xdb, 0x48, 0xa8, 0x34, 0xa1, 0x28, 0x48, 0x2c, 0x5a, 0x65, 0x81, - 0x03, 0x02, 0x59, 0xce, 0x78, 0x70, 0xac, 0xda, 0x9e, 0xc1, 0x33, 0x36, 0xce, 0x3f, 0x40, 0x9c, - 0x38, 0x71, 0x5e, 0x71, 0xe0, 0xc8, 0xa9, 0x47, 0x7e, 0x40, 0xb5, 0xa7, 0x3d, 0x72, 0x5a, 0xa1, - 0xdd, 0x0b, 0x3f, 0x03, 0x79, 0x66, 0xec, 0xd8, 0xb2, 0x93, 0xf4, 0x62, 0xc5, 0xf3, 0xbe, 0xf7, - 0x7d, 0xdf, 0x78, 0xe6, 0xbd, 0x17, 0xd0, 0x65, 0x7e, 0xe8, 0x50, 0x6a, 0x21, 0xe2, 0x62, 0x24, - 0x9f, 0x26, 0x8d, 0x09, 0x27, 0xb0, 0x87, 0x08, 0x0b, 0x09, 0xb3, 0x99, 0xfb, 0xd4, 0x94, 0x20, - 0x53, 0x86, 0xd3, 0x7b, 0xbd, 0xf7, 0xf9, 0xdc, 0x8f, 0x5d, 0x9b, 0x3a, 0x31, 0x5f, 0x58, 0x02, - 0x6e, 0x49, 0xf4, 0x5e, 0xf5, 0x45, 0x12, 0xf5, 0x6e, 0x37, 0xc1, 0x1e, 0xf1, 0xc8, 0xf2, 0x97, - 0xc2, 0x75, 0x33, 0xcb, 0x49, 0xf8, 0xdc, 0xe2, 0x0b, 0x8a, 0x99, 0x7c, 0xaa, 0xc8, 0x4d, 0x15, - 0x49, 0x31, 0xe3, 0x7e, 0xe4, 0xb5, 0x20, 0x7a, 0x99, 0xc5, 0x12, 0x4a, 0x83, 0x45, 0x4b, 0xec, - 0xcd, 0xcc, 0xc2, 0xa9, 0xef, 0xe2, 0x08, 0xe1, 0x96, 0xe8, 0x4e, 0x66, 0x79, 0x24, 0x6d, 0x09, - 0xdc, 0xca, 0x2c, 0xea, 0xc4, 0x4e, 0xa8, 0x56, 0x73, 0xe7, 0x94, 0x30, 0x27, 0xa8, 0x81, 0xde, - 0xc8, 0xac, 0x84, 0x7a, 0xb1, 0xe3, 0xe2, 0x76, 0xdb, 0xae, 0xcf, 0x78, 0xec, 0xcf, 0x12, 0xee, - 0x93, 0xa8, 0x89, 0xd8, 0xfd, 0xdb, 0x00, 0xdb, 0x8f, 0x11, 0x22, 0x49, 0xc4, 0xe1, 0xe7, 0xe0, - 0xda, 0xcc, 0x61, 0xd8, 0x76, 0xe4, 0x7b, 0x57, 0xbf, 0xa9, 0xbf, 0x7b, 0xf5, 0x83, 0xb7, 0xcc, - 0xca, 0x31, 0x64, 0x66, 0xfe, 0x19, 0xcc, 0xf4, 0x9e, 0x39, 0x72, 0x18, 0x56, 0x89, 0x13, 0x6d, - 0x7a, 0x75, 0xb6, 0x7c, 0x85, 0x29, 0xe8, 0x21, 0x12, 0x71, 0x3f, 0x4a, 0x48, 0xc2, 0x6c, 0xf5, - 0xc9, 0x4a, 0xd6, 0x4b, 0x82, 0xf5, 0xe3, 0x36, 0x56, 0x89, 0xcc, 0xd9, 0xc7, 0x65, 0xfe, 0xb7, - 0x72, 0x71, 0x29, 0xd5, 0x45, 0x2b, 0x62, 0x30, 0x04, 0x3b, 0x2e, 0x0e, 0x9c, 0x05, 0x76, 0x1b, - 0xa2, 0x97, 0x85, 0xe8, 0xfd, 0xf5, 0xa2, 0x9f, 0xc9, 0xe4, 0x86, 0xe2, 0x0d, 0xb7, 0x2d, 0x00, - 0x29, 0xe8, 0x52, 0x1c, 0xfb, 0xc4, 0xf5, 0x51, 0x43, 0xcf, 0x10, 0x7a, 0x1f, 0xae, 0xd7, 0x3b, - 0x54, 0xd9, 0x0d, 0xc1, 0xd7, 0x69, 0x6b, 0x04, 0x7e, 0x05, 0x5e, 0x0e, 0x89, 0x9b, 0x04, 0xcb, - 0x23, 0xba, 0x22, 0x74, 0xde, 0xa9, 0xeb, 0xc8, 0x7b, 0x98, 0x2b, 0x1c, 0x08, 0xf4, 0x92, 0xf8, - 0xa5, 0xb0, 0xba, 0x30, 0x7c, 0x78, 0xf2, 0x6c, 0xef, 0xa3, 0x3b, 0x9e, 0xcf, 0xe7, 0xc9, 0xcc, - 0x44, 0x24, 0x54, 0x55, 0x53, 0x54, 0x12, 0x73, 0x9f, 0x5a, 0xea, 0xde, 0xe3, 0x8c, 0x92, 0x98, - 0x63, 0xd7, 0x54, 0xa9, 0xa3, 0x2b, 0xe0, 0x32, 0x4b, 0xc2, 0xdd, 0x5f, 0x75, 0xb0, 0x75, 0x24, - 0xe4, 0xe0, 0x3e, 0xd8, 0x92, 0xc2, 0xea, 0xde, 0xf4, 0x57, 0x99, 0x92, 0xf8, 0x89, 0x36, 0x55, - 0xf8, 0xe1, 0xa3, 0xff, 0x8e, 0x07, 0xfa, 0xc9, 0xb3, 0xbd, 0x07, 0x9b, 0xac, 0xa8, 0x02, 0x2b, - 0xcd, 0x48, 0xa6, 0x2f, 0x0a, 0x33, 0x7f, 0xe8, 0xa0, 0xf3, 0x44, 0xd5, 0x19, 0xfc, 0x12, 0x5c, - 0xc3, 0x3f, 0x25, 0x7e, 0x4a, 0x90, 0x93, 0x5f, 0x7d, 0x65, 0xea, 0x76, 0xdd, 0x54, 0x51, 0x95, - 0xb9, 0xad, 0x27, 0x15, 0xf4, 0x44, 0x9b, 0xd6, 0xb2, 0x87, 0x8f, 0x95, 0xc5, 0x87, 0x1b, 0x1c, - 0x96, 0x65, 0x5e, 0x7a, 0x2c, 0x0c, 0x15, 0x26, 0xff, 0xd2, 0xc1, 0xab, 0x07, 0xcc, 0x3b, 0x4a, - 0x66, 0xa1, 0xcf, 0x4b, 0xb7, 0x9f, 0x82, 0x4e, 0x91, 0xaa, 0x9c, 0xbe, 0x6d, 0xae, 0xee, 0x7e, - 0x25, 0xe9, 0xb4, 0xcc, 0x82, 0x07, 0xc0, 0xc8, 0x6b, 0x50, 0x95, 0x97, 0xb5, 0x7a, 0x9f, 0x0d, - 0xf1, 0xbc, 0x92, 0x47, 0x9d, 0xe7, 0x67, 0x03, 0xed, 0xf4, 0x6c, 0xa0, 0x4f, 0x05, 0xcd, 0xb0, - 0xf3, 0xcb, 0xf1, 0x40, 0xcb, 0x37, 0xbd, 0xfb, 0x67, 0xd5, 0xf0, 0xa1, 0x6a, 0x41, 0xf0, 0x13, - 0xb0, 0x9d, 0xd7, 0x21, 0x2e, 0xdb, 0xc4, 0xad, 0x75, 0x7e, 0xc7, 0x12, 0x3a, 0x2d, 0x72, 0xe0, - 0xa4, 0xe6, 0xf6, 0x4e, 0xdd, 0xad, 0x47, 0xd2, 0x9a, 0xd1, 0x42, 0x74, 0x83, 0xd1, 0xdf, 0x75, - 0xd0, 0x29, 0xfd, 0x3d, 0x52, 0x02, 0xad, 0x3d, 0x4c, 0x09, 0xac, 0xe3, 0x85, 0xe3, 0xe5, 0x06, - 0x2f, 0xbd, 0xf0, 0x06, 0x47, 0x46, 0xce, 0x52, 0x6e, 0x73, 0x68, 0x08, 0x63, 0xc7, 0x06, 0xd8, - 0x56, 0x00, 0xf8, 0x00, 0x18, 0x1c, 0x67, 0x7c, 0xad, 0xaf, 0xaf, 0x71, 0x56, 0xee, 0x79, 0xa2, - 0x4d, 0x45, 0x02, 0xfc, 0x1e, 0x5c, 0x17, 0xc3, 0x00, 0x73, 0x1c, 0xdb, 0x68, 0xee, 0x44, 0xde, - 0x8a, 0xb3, 0x96, 0x23, 0x43, 0xec, 0xaf, 0xc0, 0x8f, 0x05, 0xbc, 0x42, 0xf9, 0x0a, 0xad, 0x87, - 0xe0, 0x0f, 0xe0, 0x3a, 0x23, 0x3f, 0xf2, 0x9f, 0x9d, 0x18, 0xdb, 0x6a, 0x9c, 0xa8, 0x9e, 0x79, - 0xb7, 0xce, 0xae, 0x82, 0xa2, 0x8e, 0x55, 0xc2, 0x37, 0x72, 0xa9, 0x4a, 0xcf, 0xea, 0x21, 0x48, - 0xc1, 0x0e, 0x72, 0x22, 0x84, 0x03, 0xbb, 0xa1, 0x62, 0xb4, 0x8d, 0x83, 0x8a, 0xca, 0x58, 0xe4, - 0xad, 0xd6, 0xba, 0x81, 0xda, 0x00, 0x30, 0x00, 0xaf, 0x21, 0x12, 0x86, 0x49, 0xe4, 0xf3, 0x85, - 0x4d, 0x09, 0x09, 0x6c, 0x46, 0x71, 0xe4, 0xaa, 0x86, 0xb9, 0x5f, 0x97, 0xab, 0xce, 0x48, 0x79, - 0x9a, 0x2a, 0xf3, 0x90, 0x90, 0xe0, 0x28, 0xcf, 0xab, 0x08, 0x42, 0xd4, 0x88, 0x0e, 0xf7, 0x55, - 0x7b, 0xb8, 0xbb, 0xa1, 0x3d, 0x94, 0x73, 0xbe, 0xbc, 0x30, 0xb2, 0x2b, 0x8c, 0xc6, 0xcf, 0xcf, - 0xfb, 0xfa, 0xe9, 0x79, 0x5f, 0xff, 0xf7, 0xbc, 0xaf, 0xff, 0x76, 0xd1, 0xd7, 0x4e, 0x2f, 0xfa, - 0xda, 0x3f, 0x17, 0x7d, 0xed, 0xbb, 0xf7, 0xd6, 0x52, 0x56, 0xff, 0x3b, 0xcd, 0xb6, 0xc4, 0x48, - 0xbf, 0xff, 0x7f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x44, 0x7b, 0x22, 0xdc, 0x52, 0x09, 0x00, 0x00, + // 872 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0x41, 0x6f, 0xdc, 0x44, + 0x14, 0xb6, 0xa9, 0x9b, 0xac, 0xa6, 0x05, 0xca, 0x88, 0x92, 0xd5, 0x82, 0x76, 0xdb, 0x14, 0x2a, + 0x28, 0x8a, 0xdd, 0x52, 0xa0, 0xe9, 0x5e, 0x4a, 0x77, 0x29, 0x5a, 0x24, 0x82, 0xa2, 0x0d, 0x70, + 0x40, 0x20, 0xcb, 0x3b, 0x1e, 0xbc, 0x56, 0x6c, 0xcf, 0xe0, 0x19, 0x1b, 0xef, 0x3f, 0x40, 0x9c, + 0x38, 0x71, 0x8e, 0x38, 0x23, 0x4e, 0x39, 0xf2, 0x03, 0xa2, 0x9c, 0x72, 0xe4, 0x14, 0xa1, 0xe4, + 0xc2, 0xcf, 0x40, 0x9e, 0x19, 0x7b, 0x6d, 0xd9, 0xbb, 0x39, 0x71, 0xb1, 0xd6, 0xf3, 0xbe, 0xef, + 0x7d, 0xdf, 0x78, 0xe6, 0xbd, 0xb7, 0xa0, 0xcb, 0xfc, 0xd0, 0xa1, 0xd4, 0x42, 0xc4, 0xc5, 0x48, + 0x3e, 0x4d, 0x1a, 0x13, 0x4e, 0x60, 0x0f, 0x11, 0x16, 0x12, 0x66, 0x33, 0xf7, 0xd0, 0x94, 0x20, + 0x53, 0x86, 0xd3, 0x47, 0xbd, 0xf7, 0xf9, 0xdc, 0x8f, 0x5d, 0x9b, 0x3a, 0x31, 0x5f, 0x58, 0x02, + 0x6e, 0x49, 0xf4, 0x4e, 0xf5, 0x45, 0x26, 0xea, 0xdd, 0x6f, 0x82, 0x3d, 0xe2, 0x91, 0xe5, 0x2f, + 0x85, 0xeb, 0x66, 0x96, 0x93, 0xf0, 0xb9, 0xc5, 0x17, 0x14, 0x33, 0xf9, 0x54, 0x91, 0x3b, 0x2a, + 0x92, 0x62, 0xc6, 0xfd, 0xc8, 0x6b, 0x41, 0xf4, 0x32, 0x8b, 0x25, 0x94, 0x06, 0x8b, 0x96, 0xd8, + 0x5b, 0x99, 0x85, 0x53, 0xdf, 0xc5, 0x11, 0xc2, 0x2d, 0xd1, 0xad, 0xcc, 0xf2, 0x48, 0xda, 0x12, + 0xb8, 0x97, 0x59, 0xd4, 0x89, 0x9d, 0x50, 0xad, 0xe6, 0xce, 0x29, 0x61, 0x4e, 0x50, 0x03, 0xbd, + 0x99, 0x59, 0x09, 0xf5, 0x62, 0xc7, 0xc5, 0xed, 0xb6, 0x5d, 0x9f, 0xf1, 0xd8, 0x9f, 0x25, 0xdc, + 0x27, 0x51, 0x13, 0xb1, 0xfd, 0x97, 0x01, 0x36, 0x9f, 0x23, 0x44, 0x92, 0x88, 0xc3, 0xcf, 0xc0, + 0xcd, 0x99, 0xc3, 0xb0, 0xed, 0xc8, 0xf7, 0xae, 0x7e, 0x47, 0x7f, 0xf7, 0xc6, 0x07, 0x77, 0xcd, + 0xca, 0x31, 0x64, 0x66, 0xfe, 0x19, 0xcc, 0xf4, 0x91, 0x39, 0x72, 0x18, 0x56, 0xc4, 0x89, 0x36, + 0xbd, 0x31, 0x5b, 0xbe, 0xc2, 0x14, 0xf4, 0x10, 0x89, 0xb8, 0x1f, 0x25, 0x24, 0x61, 0xb6, 0xfa, + 0x64, 0x65, 0xd6, 0x97, 0x44, 0xd6, 0x8f, 0xdb, 0xb2, 0x4a, 0x64, 0x9e, 0x7d, 0x5c, 0xf2, 0xbf, + 0x91, 0x8b, 0x4b, 0xa9, 0x2e, 0x5a, 0x11, 0x83, 0x21, 0xd8, 0x72, 0x71, 0xe0, 0x2c, 0xb0, 0xdb, + 0x10, 0xbd, 0x26, 0x44, 0x1f, 0xaf, 0x17, 0xfd, 0x54, 0x92, 0x1b, 0x8a, 0xb7, 0xdd, 0xb6, 0x00, + 0xa4, 0xa0, 0x4b, 0x71, 0xec, 0x13, 0xd7, 0x47, 0x0d, 0x3d, 0x43, 0xe8, 0x7d, 0xb8, 0x5e, 0x6f, + 0x5f, 0xb1, 0x1b, 0x82, 0x6f, 0xd0, 0xd6, 0x08, 0xfc, 0x12, 0xbc, 0x12, 0x12, 0x37, 0x09, 0x96, + 0x47, 0x74, 0x5d, 0xe8, 0xbc, 0x53, 0xd7, 0x91, 0xf7, 0x30, 0x57, 0xd8, 0x13, 0xe8, 0x65, 0xe2, + 0x97, 0xc3, 0xea, 0xc2, 0xf0, 0xe9, 0xe9, 0xf1, 0xce, 0x47, 0x0f, 0x3c, 0x9f, 0xcf, 0x93, 0x99, + 0x89, 0x48, 0xa8, 0xaa, 0xa6, 0xa8, 0x24, 0xe6, 0x1e, 0x5a, 0xea, 0xde, 0xe3, 0x8c, 0x92, 0x98, + 0x63, 0xd7, 0x54, 0xd4, 0xd1, 0x75, 0x70, 0x8d, 0x25, 0xe1, 0xf6, 0x2f, 0x3a, 0xd8, 0x38, 0x10, + 0x72, 0x70, 0x17, 0x6c, 0x48, 0x61, 0x75, 0x6f, 0xfa, 0xab, 0x4c, 0x49, 0xfc, 0x44, 0x9b, 0x2a, + 0xfc, 0xf0, 0xd9, 0xbf, 0x47, 0x03, 0xfd, 0xf4, 0x78, 0xe7, 0xc9, 0x55, 0x56, 0x54, 0x81, 0x95, + 0x66, 0x64, 0xa6, 0xcf, 0x0b, 0x33, 0xbf, 0xeb, 0xa0, 0xf3, 0x42, 0xd5, 0x19, 0xfc, 0x02, 0xdc, + 0xc4, 0x3f, 0x26, 0x7e, 0x4a, 0x90, 0x93, 0x5f, 0x7d, 0x65, 0xea, 0x7e, 0xdd, 0x54, 0x51, 0x95, + 0xb9, 0xad, 0x17, 0x15, 0xf4, 0x44, 0x9b, 0xd6, 0xd8, 0xc3, 0xe7, 0xca, 0xe2, 0xd3, 0x2b, 0x1c, + 0x96, 0x65, 0x5e, 0x7a, 0x2c, 0x0c, 0x15, 0x26, 0xff, 0xd4, 0xc1, 0x6b, 0x7b, 0xcc, 0x3b, 0x48, + 0x66, 0xa1, 0xcf, 0x4b, 0xb7, 0x9f, 0x80, 0x4e, 0x41, 0x55, 0x4e, 0xdf, 0x36, 0x57, 0x77, 0xbf, + 0x32, 0xe9, 0xb4, 0x64, 0xc1, 0x3d, 0x60, 0xe4, 0x35, 0xa8, 0xca, 0xcb, 0x5a, 0xbd, 0xcf, 0x86, + 0x78, 0x5e, 0xc9, 0xa3, 0xce, 0xc9, 0xf9, 0x40, 0x3b, 0x3b, 0x1f, 0xe8, 0x53, 0x91, 0x66, 0xd8, + 0xf9, 0xf9, 0x68, 0xa0, 0xe5, 0x9b, 0xde, 0xfe, 0xa3, 0x6a, 0x78, 0x5f, 0xb5, 0x20, 0x38, 0x51, + 0x72, 0xd2, 0xec, 0x83, 0xba, 0x9c, 0x47, 0xd2, 0x9a, 0x52, 0xc1, 0x6a, 0x53, 0x82, 0x63, 0xb0, + 0x99, 0x57, 0x34, 0x2e, 0x5b, 0xc3, 0xbd, 0x75, 0x3b, 0x1f, 0x4b, 0xe8, 0xc8, 0xc8, 0xb3, 0x4c, + 0x0b, 0x66, 0xc5, 0xee, 0x6f, 0x3a, 0xe8, 0x94, 0x2e, 0x9f, 0xd5, 0x5c, 0xde, 0x6d, 0x75, 0xf9, + 0xff, 0x9b, 0x33, 0x84, 0xb1, 0x23, 0x03, 0x6c, 0x2a, 0x00, 0x7c, 0x02, 0x0c, 0x8e, 0x33, 0xbe, + 0xd6, 0xd7, 0x57, 0x38, 0x2b, 0x3f, 0xdc, 0x44, 0x9b, 0x0a, 0x02, 0xfc, 0x0e, 0xdc, 0x12, 0x23, + 0x01, 0x73, 0x1c, 0xdb, 0x68, 0xee, 0x44, 0xde, 0x8a, 0x13, 0x97, 0x83, 0x43, 0xec, 0xaf, 0xc0, + 0x8f, 0x05, 0xbc, 0x92, 0xf2, 0x55, 0x5a, 0x0f, 0xc1, 0xef, 0xc1, 0x2d, 0x46, 0x7e, 0xe0, 0x3f, + 0x39, 0x31, 0xb6, 0xd5, 0x50, 0x51, 0x9d, 0xf3, 0x61, 0x3d, 0xbb, 0x0a, 0x8a, 0x6a, 0x56, 0x84, + 0xaf, 0xe5, 0x52, 0x35, 0x3d, 0xab, 0x87, 0x20, 0x05, 0x5b, 0xc8, 0x89, 0x10, 0x0e, 0xec, 0x86, + 0x8a, 0xd1, 0x36, 0x14, 0x2a, 0x2a, 0x63, 0xc1, 0x5b, 0xad, 0x75, 0x1b, 0xb5, 0x01, 0x60, 0x00, + 0x5e, 0x47, 0x24, 0x0c, 0x93, 0xc8, 0xe7, 0x0b, 0x9b, 0x12, 0x12, 0xd8, 0x8c, 0xe2, 0xc8, 0x55, + 0x6d, 0x73, 0xb7, 0x2e, 0x57, 0x9d, 0x94, 0xf2, 0x34, 0x15, 0x73, 0x9f, 0x90, 0xe0, 0x20, 0xe7, + 0x55, 0x04, 0x21, 0x6a, 0x44, 0x87, 0xbb, 0xaa, 0x49, 0x3c, 0xbc, 0xa2, 0x49, 0x94, 0xd3, 0xbe, + 0xbc, 0x30, 0xb2, 0x37, 0x8c, 0xc6, 0x27, 0x17, 0x7d, 0xfd, 0xec, 0xa2, 0xaf, 0xff, 0x73, 0xd1, + 0xd7, 0x7f, 0xbd, 0xec, 0x6b, 0x67, 0x97, 0x7d, 0xed, 0xef, 0xcb, 0xbe, 0xf6, 0xed, 0x7b, 0x6b, + 0x53, 0x56, 0xff, 0x41, 0xcd, 0x36, 0xc4, 0x60, 0x7f, 0xfc, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xd0, 0xbe, 0x24, 0xd5, 0x58, 0x09, 0x00, 0x00, } func (this *Supply) Equal(that interface{}) bool { @@ -797,10 +797,10 @@ func (this *MsgSubmitProposal) Equal(that interface{}) bool { } else if this == nil { return false } - if !this.Content.Equal(that1.Content) { + if !this.MsgSubmitProposalBase.Equal(&that1.MsgSubmitProposalBase) { return false } - if !this.MsgSubmitProposalBase.Equal(&that1.MsgSubmitProposalBase) { + if !this.Content.Equal(&that1.Content) { return false } return true @@ -1437,7 +1437,7 @@ func (m *MsgSubmitProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { var l int _ = l { - size, err := m.MsgSubmitProposalBase.MarshalToSizedBuffer(dAtA[:i]) + size, err := m.Content.MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -1446,18 +1446,16 @@ func (m *MsgSubmitProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { } i-- dAtA[i] = 0x12 - if m.Content != nil { - { - size, err := m.Content.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintCodec(dAtA, i, uint64(size)) + { + size, err := m.MsgSubmitProposalBase.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err } - i-- - dAtA[i] = 0xa + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) } + i-- + dAtA[i] = 0xa return len(dAtA) - i, nil } @@ -1793,12 +1791,10 @@ func (m *MsgSubmitProposal) Size() (n int) { } var l int _ = l - if m.Content != nil { - l = m.Content.Size() - n += 1 + l + sovCodec(uint64(l)) - } l = m.MsgSubmitProposalBase.Size() n += 1 + l + sovCodec(uint64(l)) + l = m.Content.Size() + n += 1 + l + sovCodec(uint64(l)) return n } @@ -2451,7 +2447,7 @@ func (m *MsgSubmitProposal) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Content", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field MsgSubmitProposalBase", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -2478,16 +2474,13 @@ func (m *MsgSubmitProposal) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.Content == nil { - m.Content = &Content{} - } - if err := m.Content.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.MsgSubmitProposalBase.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field MsgSubmitProposalBase", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Content", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -2514,7 +2507,7 @@ func (m *MsgSubmitProposal) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.MsgSubmitProposalBase.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.Content.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex diff --git a/simapp/codec/codec.proto b/simapp/codec/codec.proto index 4383fc02988b..27142c18be5d 100644 --- a/simapp/codec/codec.proto +++ b/simapp/codec/codec.proto @@ -67,8 +67,8 @@ message MsgSubmitProposal { option (gogoproto.equal) = true; option (gogoproto.goproto_getters) = false; - Content content = 1; - cosmos_sdk.x.gov.v1.MsgSubmitProposalBase base = 2 [(gogoproto.nullable) = false, (gogoproto.embed) = true]; + cosmos_sdk.x.gov.v1.MsgSubmitProposalBase base = 1 [(gogoproto.nullable) = false, (gogoproto.embed) = true]; + Content content = 2 [(gogoproto.nullable) = false]; } // Proposal defines the application-level concrete proposal type used in governance From d256e5a56f267a74510b80604f819545a43d8401 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Tue, 3 Mar 2020 13:30:21 -0500 Subject: [PATCH 357/529] Address feedback --- simapp/codec/codec.pb.go | 141 ++++++++++++++++++++------------------- simapp/codec/codec.proto | 2 +- 2 files changed, 75 insertions(+), 68 deletions(-) diff --git a/simapp/codec/codec.pb.go b/simapp/codec/codec.pb.go index d0c66f7bdec9..1fff6fa8143e 100644 --- a/simapp/codec/codec.pb.go +++ b/simapp/codec/codec.pb.go @@ -360,7 +360,7 @@ var xxx_messageInfo_MsgSubmitEvidence proto.InternalMessageInfo // governance proposals. type MsgSubmitProposal struct { types4.MsgSubmitProposalBase `protobuf:"bytes,1,opt,name=base,proto3,embedded=base" json:"base"` - Content Content `protobuf:"bytes,2,opt,name=content,proto3" json:"content"` + Content *Content `protobuf:"bytes,2,opt,name=content,proto3" json:"content,omitempty"` } func (m *MsgSubmitProposal) Reset() { *m = MsgSubmitProposal{} } @@ -585,62 +585,62 @@ func init() { func init() { proto.RegisterFile("simapp/codec/codec.proto", fileDescriptor_3c6d4085e4065f5a) } var fileDescriptor_3c6d4085e4065f5a = []byte{ - // 872 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0x41, 0x6f, 0xdc, 0x44, + // 878 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0x41, 0x6f, 0xdc, 0x44, 0x14, 0xb6, 0xa9, 0x9b, 0xac, 0xa6, 0x05, 0xca, 0x88, 0x92, 0xd5, 0x82, 0x76, 0xdb, 0x14, 0x2a, - 0x28, 0x8a, 0xdd, 0x52, 0xa0, 0xe9, 0x5e, 0x4a, 0x77, 0x29, 0x5a, 0x24, 0x82, 0xa2, 0x0d, 0x70, - 0x40, 0x20, 0xcb, 0x3b, 0x1e, 0xbc, 0x56, 0x6c, 0xcf, 0xe0, 0x19, 0x1b, 0xef, 0x3f, 0x40, 0x9c, - 0x38, 0x71, 0x8e, 0x38, 0x23, 0x4e, 0x39, 0xf2, 0x03, 0xa2, 0x9c, 0x72, 0xe4, 0x14, 0xa1, 0xe4, - 0xc2, 0xcf, 0x40, 0x9e, 0x19, 0x7b, 0x6d, 0xd9, 0xbb, 0x39, 0x71, 0xb1, 0xd6, 0xf3, 0xbe, 0xef, - 0x7d, 0xdf, 0x78, 0xe6, 0xbd, 0xb7, 0xa0, 0xcb, 0xfc, 0xd0, 0xa1, 0xd4, 0x42, 0xc4, 0xc5, 0x48, - 0x3e, 0x4d, 0x1a, 0x13, 0x4e, 0x60, 0x0f, 0x11, 0x16, 0x12, 0x66, 0x33, 0xf7, 0xd0, 0x94, 0x20, - 0x53, 0x86, 0xd3, 0x47, 0xbd, 0xf7, 0xf9, 0xdc, 0x8f, 0x5d, 0x9b, 0x3a, 0x31, 0x5f, 0x58, 0x02, - 0x6e, 0x49, 0xf4, 0x4e, 0xf5, 0x45, 0x26, 0xea, 0xdd, 0x6f, 0x82, 0x3d, 0xe2, 0x91, 0xe5, 0x2f, - 0x85, 0xeb, 0x66, 0x96, 0x93, 0xf0, 0xb9, 0xc5, 0x17, 0x14, 0x33, 0xf9, 0x54, 0x91, 0x3b, 0x2a, - 0x92, 0x62, 0xc6, 0xfd, 0xc8, 0x6b, 0x41, 0xf4, 0x32, 0x8b, 0x25, 0x94, 0x06, 0x8b, 0x96, 0xd8, - 0x5b, 0x99, 0x85, 0x53, 0xdf, 0xc5, 0x11, 0xc2, 0x2d, 0xd1, 0xad, 0xcc, 0xf2, 0x48, 0xda, 0x12, - 0xb8, 0x97, 0x59, 0xd4, 0x89, 0x9d, 0x50, 0xad, 0xe6, 0xce, 0x29, 0x61, 0x4e, 0x50, 0x03, 0xbd, - 0x99, 0x59, 0x09, 0xf5, 0x62, 0xc7, 0xc5, 0xed, 0xb6, 0x5d, 0x9f, 0xf1, 0xd8, 0x9f, 0x25, 0xdc, - 0x27, 0x51, 0x13, 0xb1, 0xfd, 0x97, 0x01, 0x36, 0x9f, 0x23, 0x44, 0x92, 0x88, 0xc3, 0xcf, 0xc0, - 0xcd, 0x99, 0xc3, 0xb0, 0xed, 0xc8, 0xf7, 0xae, 0x7e, 0x47, 0x7f, 0xf7, 0xc6, 0x07, 0x77, 0xcd, - 0xca, 0x31, 0x64, 0x66, 0xfe, 0x19, 0xcc, 0xf4, 0x91, 0x39, 0x72, 0x18, 0x56, 0xc4, 0x89, 0x36, - 0xbd, 0x31, 0x5b, 0xbe, 0xc2, 0x14, 0xf4, 0x10, 0x89, 0xb8, 0x1f, 0x25, 0x24, 0x61, 0xb6, 0xfa, - 0x64, 0x65, 0xd6, 0x97, 0x44, 0xd6, 0x8f, 0xdb, 0xb2, 0x4a, 0x64, 0x9e, 0x7d, 0x5c, 0xf2, 0xbf, - 0x91, 0x8b, 0x4b, 0xa9, 0x2e, 0x5a, 0x11, 0x83, 0x21, 0xd8, 0x72, 0x71, 0xe0, 0x2c, 0xb0, 0xdb, - 0x10, 0xbd, 0x26, 0x44, 0x1f, 0xaf, 0x17, 0xfd, 0x54, 0x92, 0x1b, 0x8a, 0xb7, 0xdd, 0xb6, 0x00, - 0xa4, 0xa0, 0x4b, 0x71, 0xec, 0x13, 0xd7, 0x47, 0x0d, 0x3d, 0x43, 0xe8, 0x7d, 0xb8, 0x5e, 0x6f, - 0x5f, 0xb1, 0x1b, 0x82, 0x6f, 0xd0, 0xd6, 0x08, 0xfc, 0x12, 0xbc, 0x12, 0x12, 0x37, 0x09, 0x96, - 0x47, 0x74, 0x5d, 0xe8, 0xbc, 0x53, 0xd7, 0x91, 0xf7, 0x30, 0x57, 0xd8, 0x13, 0xe8, 0x65, 0xe2, - 0x97, 0xc3, 0xea, 0xc2, 0xf0, 0xe9, 0xe9, 0xf1, 0xce, 0x47, 0x0f, 0x3c, 0x9f, 0xcf, 0x93, 0x99, - 0x89, 0x48, 0xa8, 0xaa, 0xa6, 0xa8, 0x24, 0xe6, 0x1e, 0x5a, 0xea, 0xde, 0xe3, 0x8c, 0x92, 0x98, - 0x63, 0xd7, 0x54, 0xd4, 0xd1, 0x75, 0x70, 0x8d, 0x25, 0xe1, 0xf6, 0x2f, 0x3a, 0xd8, 0x38, 0x10, - 0x72, 0x70, 0x17, 0x6c, 0x48, 0x61, 0x75, 0x6f, 0xfa, 0xab, 0x4c, 0x49, 0xfc, 0x44, 0x9b, 0x2a, - 0xfc, 0xf0, 0xd9, 0xbf, 0x47, 0x03, 0xfd, 0xf4, 0x78, 0xe7, 0xc9, 0x55, 0x56, 0x54, 0x81, 0x95, - 0x66, 0x64, 0xa6, 0xcf, 0x0b, 0x33, 0xbf, 0xeb, 0xa0, 0xf3, 0x42, 0xd5, 0x19, 0xfc, 0x02, 0xdc, - 0xc4, 0x3f, 0x26, 0x7e, 0x4a, 0x90, 0x93, 0x5f, 0x7d, 0x65, 0xea, 0x7e, 0xdd, 0x54, 0x51, 0x95, - 0xb9, 0xad, 0x17, 0x15, 0xf4, 0x44, 0x9b, 0xd6, 0xd8, 0xc3, 0xe7, 0xca, 0xe2, 0xd3, 0x2b, 0x1c, - 0x96, 0x65, 0x5e, 0x7a, 0x2c, 0x0c, 0x15, 0x26, 0xff, 0xd4, 0xc1, 0x6b, 0x7b, 0xcc, 0x3b, 0x48, - 0x66, 0xa1, 0xcf, 0x4b, 0xb7, 0x9f, 0x80, 0x4e, 0x41, 0x55, 0x4e, 0xdf, 0x36, 0x57, 0x77, 0xbf, - 0x32, 0xe9, 0xb4, 0x64, 0xc1, 0x3d, 0x60, 0xe4, 0x35, 0xa8, 0xca, 0xcb, 0x5a, 0xbd, 0xcf, 0x86, - 0x78, 0x5e, 0xc9, 0xa3, 0xce, 0xc9, 0xf9, 0x40, 0x3b, 0x3b, 0x1f, 0xe8, 0x53, 0x91, 0x66, 0xd8, - 0xf9, 0xf9, 0x68, 0xa0, 0xe5, 0x9b, 0xde, 0xfe, 0xa3, 0x6a, 0x78, 0x5f, 0xb5, 0x20, 0x38, 0x51, - 0x72, 0xd2, 0xec, 0x83, 0xba, 0x9c, 0x47, 0xd2, 0x9a, 0x52, 0xc1, 0x6a, 0x53, 0x82, 0x63, 0xb0, - 0x99, 0x57, 0x34, 0x2e, 0x5b, 0xc3, 0xbd, 0x75, 0x3b, 0x1f, 0x4b, 0xe8, 0xc8, 0xc8, 0xb3, 0x4c, - 0x0b, 0x66, 0xc5, 0xee, 0x6f, 0x3a, 0xe8, 0x94, 0x2e, 0x9f, 0xd5, 0x5c, 0xde, 0x6d, 0x75, 0xf9, - 0xff, 0x9b, 0x33, 0x84, 0xb1, 0x23, 0x03, 0x6c, 0x2a, 0x00, 0x7c, 0x02, 0x0c, 0x8e, 0x33, 0xbe, - 0xd6, 0xd7, 0x57, 0x38, 0x2b, 0x3f, 0xdc, 0x44, 0x9b, 0x0a, 0x02, 0xfc, 0x0e, 0xdc, 0x12, 0x23, - 0x01, 0x73, 0x1c, 0xdb, 0x68, 0xee, 0x44, 0xde, 0x8a, 0x13, 0x97, 0x83, 0x43, 0xec, 0xaf, 0xc0, - 0x8f, 0x05, 0xbc, 0x92, 0xf2, 0x55, 0x5a, 0x0f, 0xc1, 0xef, 0xc1, 0x2d, 0x46, 0x7e, 0xe0, 0x3f, - 0x39, 0x31, 0xb6, 0xd5, 0x50, 0x51, 0x9d, 0xf3, 0x61, 0x3d, 0xbb, 0x0a, 0x8a, 0x6a, 0x56, 0x84, - 0xaf, 0xe5, 0x52, 0x35, 0x3d, 0xab, 0x87, 0x20, 0x05, 0x5b, 0xc8, 0x89, 0x10, 0x0e, 0xec, 0x86, - 0x8a, 0xd1, 0x36, 0x14, 0x2a, 0x2a, 0x63, 0xc1, 0x5b, 0xad, 0x75, 0x1b, 0xb5, 0x01, 0x60, 0x00, - 0x5e, 0x47, 0x24, 0x0c, 0x93, 0xc8, 0xe7, 0x0b, 0x9b, 0x12, 0x12, 0xd8, 0x8c, 0xe2, 0xc8, 0x55, - 0x6d, 0x73, 0xb7, 0x2e, 0x57, 0x9d, 0x94, 0xf2, 0x34, 0x15, 0x73, 0x9f, 0x90, 0xe0, 0x20, 0xe7, - 0x55, 0x04, 0x21, 0x6a, 0x44, 0x87, 0xbb, 0xaa, 0x49, 0x3c, 0xbc, 0xa2, 0x49, 0x94, 0xd3, 0xbe, - 0xbc, 0x30, 0xb2, 0x37, 0x8c, 0xc6, 0x27, 0x17, 0x7d, 0xfd, 0xec, 0xa2, 0xaf, 0xff, 0x73, 0xd1, - 0xd7, 0x7f, 0xbd, 0xec, 0x6b, 0x67, 0x97, 0x7d, 0xed, 0xef, 0xcb, 0xbe, 0xf6, 0xed, 0x7b, 0x6b, - 0x53, 0x56, 0xff, 0x41, 0xcd, 0x36, 0xc4, 0x60, 0x7f, 0xfc, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xd0, 0xbe, 0x24, 0xd5, 0x58, 0x09, 0x00, 0x00, + 0x28, 0x8a, 0xdd, 0x52, 0xa0, 0xe9, 0x4a, 0xa8, 0x74, 0x97, 0xa2, 0x45, 0x22, 0x28, 0xda, 0x00, + 0x07, 0x04, 0xb2, 0xbc, 0xe3, 0xc1, 0x6b, 0xd5, 0xf6, 0x0c, 0x9e, 0xb1, 0xf1, 0xfe, 0x03, 0xc4, + 0x89, 0x13, 0xe7, 0x88, 0x03, 0x47, 0x4e, 0x39, 0xf2, 0x03, 0xa2, 0x9c, 0x72, 0xe4, 0x14, 0xa1, + 0xe4, 0xc2, 0xcf, 0x40, 0x9e, 0x19, 0x7b, 0x6d, 0xd9, 0xbb, 0x91, 0x7a, 0xb1, 0xd6, 0xf3, 0xbe, + 0xef, 0x7d, 0xdf, 0x78, 0xe6, 0xbd, 0xb7, 0xa0, 0xcb, 0xfc, 0xd0, 0xa1, 0xd4, 0x42, 0xc4, 0xc5, + 0x48, 0x3e, 0x4d, 0x1a, 0x13, 0x4e, 0x60, 0x0f, 0x11, 0x16, 0x12, 0x66, 0x33, 0xf7, 0xb9, 0x29, + 0x41, 0xa6, 0x0c, 0xa7, 0x0f, 0x7a, 0xef, 0xf3, 0xb9, 0x1f, 0xbb, 0x36, 0x75, 0x62, 0xbe, 0xb0, + 0x04, 0xdc, 0x92, 0xe8, 0x9d, 0xea, 0x8b, 0x4c, 0xd4, 0xbb, 0xdb, 0x04, 0x7b, 0xc4, 0x23, 0xcb, + 0x5f, 0x0a, 0xd7, 0xcd, 0x2c, 0x27, 0xe1, 0x73, 0x8b, 0x2f, 0x28, 0x66, 0xf2, 0xa9, 0x22, 0xb7, + 0x54, 0x24, 0xc5, 0x8c, 0xfb, 0x91, 0xd7, 0x82, 0xe8, 0x65, 0x16, 0x4b, 0x28, 0x0d, 0x16, 0x2d, + 0xb1, 0xb7, 0x32, 0x0b, 0xa7, 0xbe, 0x8b, 0x23, 0x84, 0x5b, 0xa2, 0x5b, 0x99, 0xe5, 0x91, 0xb4, + 0x25, 0x70, 0x27, 0xb3, 0xa8, 0x13, 0x3b, 0xa1, 0x5a, 0xcd, 0x9d, 0x53, 0xc2, 0x9c, 0xa0, 0x06, + 0x7a, 0x33, 0xb3, 0x12, 0xea, 0xc5, 0x8e, 0x8b, 0xdb, 0x6d, 0xbb, 0x3e, 0xe3, 0xb1, 0x3f, 0x4b, + 0xb8, 0x4f, 0xa2, 0x26, 0x62, 0xfb, 0x6f, 0x03, 0x6c, 0x3e, 0x45, 0x88, 0x24, 0x11, 0x87, 0x9f, + 0x83, 0xeb, 0x33, 0x87, 0x61, 0xdb, 0x91, 0xef, 0x5d, 0xfd, 0x96, 0xfe, 0xee, 0xb5, 0x0f, 0x6e, + 0x9b, 0x95, 0x63, 0xc8, 0xcc, 0xfc, 0x33, 0x98, 0xe9, 0x03, 0x73, 0xe4, 0x30, 0xac, 0x88, 0x13, + 0x6d, 0x7a, 0x6d, 0xb6, 0x7c, 0x85, 0x29, 0xe8, 0x21, 0x12, 0x71, 0x3f, 0x4a, 0x48, 0xc2, 0x6c, + 0xf5, 0xc9, 0xca, 0xac, 0x2f, 0x89, 0xac, 0x1f, 0xb7, 0x65, 0x95, 0xc8, 0x3c, 0xfb, 0xb8, 0xe4, + 0x7f, 0x2b, 0x17, 0x97, 0x52, 0x5d, 0xb4, 0x22, 0x06, 0x43, 0xb0, 0xe5, 0xe2, 0xc0, 0x59, 0x60, + 0xb7, 0x21, 0x7a, 0x45, 0x88, 0x3e, 0x5c, 0x2f, 0xfa, 0x99, 0x24, 0x37, 0x14, 0x6f, 0xba, 0x6d, + 0x01, 0x48, 0x41, 0x97, 0xe2, 0xd8, 0x27, 0xae, 0x8f, 0x1a, 0x7a, 0x86, 0xd0, 0xfb, 0x70, 0xbd, + 0xde, 0xbe, 0x62, 0x37, 0x04, 0xdf, 0xa0, 0xad, 0x11, 0xf8, 0x15, 0x78, 0x25, 0x24, 0x6e, 0x12, + 0x2c, 0x8f, 0xe8, 0xaa, 0xd0, 0x79, 0xa7, 0xae, 0x23, 0xef, 0x61, 0xae, 0xb0, 0x27, 0xd0, 0xcb, + 0xc4, 0x2f, 0x87, 0xd5, 0x85, 0xe1, 0xe3, 0x93, 0xa3, 0x9d, 0x8f, 0xee, 0x79, 0x3e, 0x9f, 0x27, + 0x33, 0x13, 0x91, 0x50, 0x55, 0x4d, 0x51, 0x49, 0xcc, 0x7d, 0x6e, 0xa9, 0x7b, 0x8f, 0x33, 0x4a, + 0x62, 0x8e, 0x5d, 0x53, 0x51, 0x47, 0x57, 0xc1, 0x15, 0x96, 0x84, 0xdb, 0xbf, 0xea, 0x60, 0xe3, + 0x40, 0xc8, 0xc1, 0x5d, 0xb0, 0x21, 0x85, 0xd5, 0xbd, 0xe9, 0xaf, 0x32, 0x25, 0xf1, 0x13, 0x6d, + 0xaa, 0xf0, 0xc3, 0x27, 0xff, 0x1d, 0x0e, 0xf4, 0x93, 0xa3, 0x9d, 0x47, 0x97, 0x59, 0x51, 0x05, + 0x56, 0x9a, 0x91, 0x99, 0xbe, 0x28, 0xcc, 0xfc, 0xa1, 0x83, 0xce, 0x33, 0x55, 0x67, 0xf0, 0x4b, + 0x70, 0x1d, 0xff, 0x94, 0xf8, 0x29, 0x41, 0x4e, 0x7e, 0xf5, 0x95, 0xa9, 0xbb, 0x75, 0x53, 0x45, + 0x55, 0xe6, 0xb6, 0x9e, 0x55, 0xd0, 0x13, 0x6d, 0x5a, 0x63, 0x0f, 0x9f, 0x2a, 0x8b, 0x8f, 0x2f, + 0x71, 0x58, 0x96, 0x79, 0xe9, 0xb1, 0x30, 0x54, 0x98, 0xfc, 0x4b, 0x07, 0xaf, 0xed, 0x31, 0xef, + 0x20, 0x99, 0x85, 0x3e, 0x2f, 0xdd, 0x7e, 0x0a, 0x3a, 0x05, 0x55, 0x39, 0x7d, 0xdb, 0x5c, 0xdd, + 0xfd, 0xca, 0xa4, 0xd3, 0x92, 0x05, 0xf7, 0x80, 0x91, 0xd7, 0xa0, 0x2a, 0x2f, 0x6b, 0xf5, 0x3e, + 0x1b, 0xe2, 0x79, 0x25, 0x8f, 0x3a, 0xc7, 0x67, 0x03, 0xed, 0xf4, 0x6c, 0xa0, 0x4f, 0x45, 0x9a, + 0x61, 0xe7, 0x97, 0xc3, 0x81, 0x96, 0x6f, 0x7a, 0xfb, 0xcf, 0xaa, 0xe1, 0x7d, 0xd5, 0x82, 0xe0, + 0x44, 0xc9, 0x49, 0xb3, 0xf7, 0xea, 0x72, 0x1e, 0x49, 0x6b, 0x4a, 0x05, 0xab, 0x4d, 0x09, 0x7e, + 0x02, 0x36, 0xf3, 0x8a, 0xc6, 0x65, 0x6b, 0xb8, 0xb3, 0x6e, 0xe7, 0x63, 0x09, 0x9d, 0x16, 0x9c, + 0x8a, 0xd1, 0xdf, 0x75, 0xd0, 0x29, 0xfd, 0x3d, 0xa9, 0xf9, 0xbb, 0xdd, 0xea, 0x6f, 0xad, 0xad, + 0xf1, 0x8b, 0xd8, 0x1a, 0x19, 0x79, 0x96, 0xa5, 0x39, 0x43, 0x18, 0x3b, 0x34, 0xc0, 0xa6, 0x02, + 0xc0, 0x47, 0xc0, 0xe0, 0x38, 0xe3, 0x6b, 0x7d, 0x7d, 0x8d, 0xb3, 0xf2, 0x93, 0x4d, 0xb4, 0xa9, + 0x20, 0xc0, 0xef, 0xc1, 0x0d, 0x31, 0x0c, 0x30, 0xc7, 0xb1, 0x8d, 0xe6, 0x4e, 0xe4, 0xad, 0x38, + 0x6b, 0x39, 0x32, 0xc4, 0xfe, 0x0a, 0xfc, 0x58, 0xc0, 0x2b, 0x29, 0x5f, 0xa5, 0xf5, 0x10, 0xfc, + 0x01, 0xdc, 0x60, 0xe4, 0x47, 0xfe, 0xb3, 0x13, 0x63, 0x5b, 0x8d, 0x13, 0xd5, 0x33, 0xef, 0xd7, + 0xb3, 0xab, 0xa0, 0xa8, 0x63, 0x45, 0xf8, 0x46, 0x2e, 0x55, 0xd3, 0xb3, 0x7a, 0x08, 0x52, 0xb0, + 0x85, 0x9c, 0x08, 0xe1, 0xc0, 0x6e, 0xa8, 0x18, 0x6d, 0xe3, 0xa0, 0xa2, 0x32, 0x16, 0xbc, 0xd5, + 0x5a, 0x37, 0x51, 0x1b, 0x00, 0x06, 0xe0, 0x75, 0x44, 0xc2, 0x30, 0x89, 0x7c, 0xbe, 0xb0, 0x29, + 0x21, 0x81, 0xcd, 0x28, 0x8e, 0x5c, 0xd5, 0x30, 0x77, 0xeb, 0x72, 0xd5, 0x19, 0x29, 0x4f, 0x53, + 0x31, 0xf7, 0x09, 0x09, 0x0e, 0x72, 0x5e, 0x45, 0x10, 0xa2, 0x46, 0x74, 0xb8, 0xab, 0xda, 0xc3, + 0xfd, 0x4b, 0xda, 0x43, 0x39, 0xe7, 0xcb, 0x0b, 0x23, 0xbb, 0xc2, 0x68, 0x7c, 0x7c, 0xde, 0xd7, + 0x4f, 0xcf, 0xfb, 0xfa, 0xbf, 0xe7, 0x7d, 0xfd, 0xb7, 0x8b, 0xbe, 0x76, 0x7a, 0xd1, 0xd7, 0xfe, + 0xb9, 0xe8, 0x6b, 0xdf, 0xbd, 0xb7, 0x36, 0x65, 0xf5, 0xbf, 0xd3, 0x6c, 0x43, 0x8c, 0xf4, 0x87, + 0xff, 0x07, 0x00, 0x00, 0xff, 0xff, 0x70, 0x52, 0xf3, 0x25, 0x52, 0x09, 0x00, 0x00, } func (this *Supply) Equal(that interface{}) bool { @@ -800,7 +800,7 @@ func (this *MsgSubmitProposal) Equal(that interface{}) bool { if !this.MsgSubmitProposalBase.Equal(&that1.MsgSubmitProposalBase) { return false } - if !this.Content.Equal(&that1.Content) { + if !this.Content.Equal(that1.Content) { return false } return true @@ -1436,16 +1436,18 @@ func (m *MsgSubmitProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - { - size, err := m.Content.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err + if m.Content != nil { + { + size, err := m.Content.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) } - i -= size - i = encodeVarintCodec(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x12 } - i-- - dAtA[i] = 0x12 { size, err := m.MsgSubmitProposalBase.MarshalToSizedBuffer(dAtA[:i]) if err != nil { @@ -1793,8 +1795,10 @@ func (m *MsgSubmitProposal) Size() (n int) { _ = l l = m.MsgSubmitProposalBase.Size() n += 1 + l + sovCodec(uint64(l)) - l = m.Content.Size() - n += 1 + l + sovCodec(uint64(l)) + if m.Content != nil { + l = m.Content.Size() + n += 1 + l + sovCodec(uint64(l)) + } return n } @@ -2507,6 +2511,9 @@ func (m *MsgSubmitProposal) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } + if m.Content == nil { + m.Content = &Content{} + } if err := m.Content.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } diff --git a/simapp/codec/codec.proto b/simapp/codec/codec.proto index 27142c18be5d..620370d3429e 100644 --- a/simapp/codec/codec.proto +++ b/simapp/codec/codec.proto @@ -68,7 +68,7 @@ message MsgSubmitProposal { option (gogoproto.goproto_getters) = false; cosmos_sdk.x.gov.v1.MsgSubmitProposalBase base = 1 [(gogoproto.nullable) = false, (gogoproto.embed) = true]; - Content content = 2 [(gogoproto.nullable) = false]; + Content content = 2; } // Proposal defines the application-level concrete proposal type used in governance From f3607833c10094555e718ba2fde53bd78e83f3ab Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Tue, 3 Mar 2020 20:06:55 +0100 Subject: [PATCH 358/529] update proto file --- x/crisis/types/types.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/crisis/types/types.proto b/x/crisis/types/types.proto index c691035f92f7..8298aa0b0af9 100644 --- a/x/crisis/types/types.proto +++ b/x/crisis/types/types.proto @@ -1,7 +1,7 @@ syntax = "proto3"; package cosmos_sdk.x.crisis.v1; -option go_package = "types"; +option go_package = "github.com/cosmos/cosmos-sdk/x/crisis/types"; import "third_party/proto/gogoproto/gogo.proto"; From cd2febac28d04eacc532883e633b3bd5e5454118 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Tue, 3 Mar 2020 14:36:02 -0500 Subject: [PATCH 359/529] Fix proto --- x/crisis/types/types.pb.go | 51 +++++----- x/distribution/types/types.pb.go | 162 +++++++++++++++---------------- 2 files changed, 105 insertions(+), 108 deletions(-) diff --git a/x/crisis/types/types.pb.go b/x/crisis/types/types.pb.go index 6e9507e1ac41..c98ec52dfde0 100644 --- a/x/crisis/types/types.pb.go +++ b/x/crisis/types/types.pb.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: x/crisis/internal/types/types.proto +// source: x/crisis/types/types.proto package types @@ -36,7 +36,7 @@ func (m *MsgVerifyInvariant) Reset() { *m = MsgVerifyInvariant{} } func (m *MsgVerifyInvariant) String() string { return proto.CompactTextString(m) } func (*MsgVerifyInvariant) ProtoMessage() {} func (*MsgVerifyInvariant) Descriptor() ([]byte, []int) { - return fileDescriptor_df1c0b8e580cce76, []int{0} + return fileDescriptor_d15f5abb7502dad7, []int{0} } func (m *MsgVerifyInvariant) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -90,32 +90,29 @@ func init() { proto.RegisterType((*MsgVerifyInvariant)(nil), "cosmos_sdk.x.crisis.v1.MsgVerifyInvariant") } -func init() { - proto.RegisterFile("x/crisis/internal/types/types.proto", fileDescriptor_df1c0b8e580cce76) -} +func init() { proto.RegisterFile("x/crisis/types/types.proto", fileDescriptor_d15f5abb7502dad7) } -var fileDescriptor_df1c0b8e580cce76 = []byte{ - // 308 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0xae, 0xd0, 0x4f, 0x2e, - 0xca, 0x2c, 0xce, 0x2c, 0xd6, 0xcf, 0xcc, 0x2b, 0x49, 0x2d, 0xca, 0x4b, 0xcc, 0xd1, 0x2f, 0xa9, - 0x2c, 0x48, 0x2d, 0x86, 0x90, 0x7a, 0x05, 0x45, 0xf9, 0x25, 0xf9, 0x42, 0x62, 0xc9, 0xf9, 0xc5, - 0xb9, 0xf9, 0xc5, 0xf1, 0xc5, 0x29, 0xd9, 0x7a, 0x15, 0x7a, 0x10, 0xf5, 0x7a, 0x65, 0x86, 0x52, - 0x6a, 0x25, 0x19, 0x99, 0x45, 0x29, 0xf1, 0x05, 0x89, 0x45, 0x25, 0x95, 0xfa, 0x60, 0xa5, 0xfa, - 0xe9, 0xf9, 0xe9, 0xf9, 0x08, 0x16, 0x44, 0xbf, 0x52, 0x03, 0x13, 0x97, 0x90, 0x6f, 0x71, 0x7a, - 0x58, 0x6a, 0x51, 0x66, 0x5a, 0xa5, 0x67, 0x5e, 0x59, 0x62, 0x51, 0x66, 0x62, 0x5e, 0x89, 0x90, - 0x27, 0x17, 0x5b, 0x71, 0x6a, 0x5e, 0x4a, 0x6a, 0x91, 0x04, 0xa3, 0x02, 0xa3, 0x06, 0x8f, 0x93, - 0xe1, 0xaf, 0x7b, 0xf2, 0xba, 0xe9, 0x99, 0x25, 0x19, 0xa5, 0x49, 0x7a, 0xc9, 0xf9, 0xb9, 0xfa, - 0x10, 0x5b, 0xa1, 0x94, 0x6e, 0x71, 0x4a, 0x36, 0xd4, 0x51, 0x8e, 0xc9, 0xc9, 0x8e, 0x29, 0x29, - 0x45, 0xa9, 0xc5, 0xc5, 0x41, 0x50, 0x03, 0x84, 0x42, 0xb8, 0x44, 0x33, 0x61, 0xe6, 0xc6, 0xe7, - 0xe6, 0xa7, 0x94, 0xe6, 0xa4, 0xc6, 0xe7, 0x25, 0xe6, 0xa6, 0x4a, 0x30, 0x29, 0x30, 0x6a, 0x70, - 0x3a, 0x29, 0x7c, 0xba, 0x27, 0x2f, 0x53, 0x99, 0x98, 0x9b, 0x63, 0xa5, 0x84, 0x55, 0x99, 0x52, - 0x90, 0x30, 0x5c, 0xdc, 0x17, 0x2c, 0xec, 0x97, 0x98, 0x9b, 0x2a, 0xe4, 0xcc, 0xc5, 0x8f, 0x50, - 0x5e, 0x94, 0x5f, 0x5a, 0x92, 0x2a, 0xc1, 0x0c, 0x36, 0x4f, 0xea, 0xd3, 0x3d, 0x79, 0x31, 0x74, - 0xf3, 0xc0, 0x0a, 0x94, 0x82, 0xf8, 0xe0, 0x22, 0x41, 0x20, 0x01, 0x2b, 0x96, 0x17, 0x0b, 0xe4, - 0x19, 0x9d, 0xe4, 0x4f, 0x3c, 0x92, 0x63, 0xbc, 0xf0, 0x48, 0x8e, 0xf1, 0xc1, 0x23, 0x39, 0xc6, - 0x09, 0x8f, 0xe5, 0x18, 0x2e, 0x3c, 0x96, 0x63, 0xb8, 0xf1, 0x58, 0x8e, 0x21, 0x8a, 0x15, 0xec, - 0xa9, 0x24, 0x36, 0x70, 0x50, 0x19, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0x46, 0x5c, 0xba, 0xa4, - 0x91, 0x01, 0x00, 0x00, +var fileDescriptor_d15f5abb7502dad7 = []byte{ + // 301 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xaa, 0xd0, 0x4f, 0x2e, + 0xca, 0x2c, 0xce, 0x2c, 0xd6, 0x2f, 0xa9, 0x2c, 0x48, 0x85, 0x92, 0x7a, 0x05, 0x45, 0xf9, 0x25, + 0xf9, 0x42, 0x62, 0xc9, 0xf9, 0xc5, 0xb9, 0xf9, 0xc5, 0xf1, 0xc5, 0x29, 0xd9, 0x7a, 0x15, 0x7a, + 0x10, 0x65, 0x7a, 0x65, 0x86, 0x52, 0x6a, 0x25, 0x19, 0x99, 0x45, 0x29, 0xf1, 0x05, 0x89, 0x45, + 0x25, 0x95, 0xfa, 0x60, 0xa5, 0xfa, 0xe9, 0xf9, 0xe9, 0xf9, 0x08, 0x16, 0x44, 0xbf, 0x52, 0x03, + 0x13, 0x97, 0x90, 0x6f, 0x71, 0x7a, 0x58, 0x6a, 0x51, 0x66, 0x5a, 0xa5, 0x67, 0x5e, 0x59, 0x62, + 0x51, 0x66, 0x62, 0x5e, 0x89, 0x90, 0x27, 0x17, 0x5b, 0x71, 0x6a, 0x5e, 0x4a, 0x6a, 0x91, 0x04, + 0xa3, 0x02, 0xa3, 0x06, 0x8f, 0x93, 0xe1, 0xaf, 0x7b, 0xf2, 0xba, 0xe9, 0x99, 0x25, 0x19, 0xa5, + 0x49, 0x7a, 0xc9, 0xf9, 0xb9, 0xfa, 0x10, 0x5b, 0xa1, 0x94, 0x6e, 0x71, 0x4a, 0x36, 0xd4, 0x51, + 0x8e, 0xc9, 0xc9, 0x8e, 0x29, 0x29, 0x45, 0xa9, 0xc5, 0xc5, 0x41, 0x50, 0x03, 0x84, 0x42, 0xb8, + 0x44, 0x33, 0x61, 0xe6, 0xc6, 0xe7, 0xe6, 0xa7, 0x94, 0xe6, 0xa4, 0xc6, 0xe7, 0x25, 0xe6, 0xa6, + 0x4a, 0x30, 0x29, 0x30, 0x6a, 0x70, 0x3a, 0x29, 0x7c, 0xba, 0x27, 0x2f, 0x53, 0x99, 0x98, 0x9b, + 0x63, 0xa5, 0x84, 0x55, 0x99, 0x52, 0x90, 0x30, 0x5c, 0xdc, 0x17, 0x2c, 0xec, 0x97, 0x98, 0x9b, + 0x2a, 0xe4, 0xcc, 0xc5, 0x8f, 0x50, 0x5e, 0x94, 0x5f, 0x5a, 0x92, 0x2a, 0xc1, 0x0c, 0x36, 0x4f, + 0xea, 0xd3, 0x3d, 0x79, 0x31, 0x74, 0xf3, 0xc0, 0x0a, 0x94, 0x82, 0xf8, 0xe0, 0x22, 0x41, 0x20, + 0x01, 0x2b, 0x96, 0x17, 0x0b, 0xe4, 0x19, 0x9d, 0x5c, 0x4f, 0x3c, 0x92, 0x63, 0xbc, 0xf0, 0x48, + 0x8e, 0xf1, 0xc1, 0x23, 0x39, 0xc6, 0x09, 0x8f, 0xe5, 0x18, 0x2e, 0x3c, 0x96, 0x63, 0xb8, 0xf1, + 0x58, 0x8e, 0x21, 0x4a, 0x1b, 0xaf, 0x8f, 0x51, 0x63, 0x25, 0x89, 0x0d, 0x1c, 0xa0, 0xc6, 0x80, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xfa, 0x65, 0xef, 0x2c, 0xae, 0x01, 0x00, 0x00, } func (this *MsgVerifyInvariant) Equal(that interface{}) bool { diff --git a/x/distribution/types/types.pb.go b/x/distribution/types/types.pb.go index 0571a985cb0a..4bb5f55383e8 100644 --- a/x/distribution/types/types.pb.go +++ b/x/distribution/types/types.pb.go @@ -728,20 +728,20 @@ func (m *DelegatorStartingInfo) GetHeight() uint64 { } func init() { - proto.RegisterType((*MsgSetWithdrawAddress)(nil), "cosmos_sdk.x.ditribution.v1.MsgSetWithdrawAddress") - proto.RegisterType((*MsgWithdrawDelegatorReward)(nil), "cosmos_sdk.x.ditribution.v1.MsgWithdrawDelegatorReward") - proto.RegisterType((*MsgWithdrawValidatorCommission)(nil), "cosmos_sdk.x.ditribution.v1.MsgWithdrawValidatorCommission") - proto.RegisterType((*MsgFundCommunityPool)(nil), "cosmos_sdk.x.ditribution.v1.MsgFundCommunityPool") - proto.RegisterType((*Params)(nil), "cosmos_sdk.x.ditribution.v1.Params") - proto.RegisterType((*ValidatorHistoricalRewards)(nil), "cosmos_sdk.x.ditribution.v1.ValidatorHistoricalRewards") - proto.RegisterType((*ValidatorCurrentRewards)(nil), "cosmos_sdk.x.ditribution.v1.ValidatorCurrentRewards") - proto.RegisterType((*ValidatorAccumulatedCommission)(nil), "cosmos_sdk.x.ditribution.v1.ValidatorAccumulatedCommission") - proto.RegisterType((*ValidatorOutstandingRewards)(nil), "cosmos_sdk.x.ditribution.v1.ValidatorOutstandingRewards") - proto.RegisterType((*ValidatorSlashEvent)(nil), "cosmos_sdk.x.ditribution.v1.ValidatorSlashEvent") - proto.RegisterType((*ValidatorSlashEvents)(nil), "cosmos_sdk.x.ditribution.v1.ValidatorSlashEvents") - proto.RegisterType((*FeePool)(nil), "cosmos_sdk.x.ditribution.v1.FeePool") - proto.RegisterType((*CommunityPoolSpendProposal)(nil), "cosmos_sdk.x.ditribution.v1.CommunityPoolSpendProposal") - proto.RegisterType((*DelegatorStartingInfo)(nil), "cosmos_sdk.x.ditribution.v1.DelegatorStartingInfo") + proto.RegisterType((*MsgSetWithdrawAddress)(nil), "cosmos_sdk.x.distribution.v1.MsgSetWithdrawAddress") + proto.RegisterType((*MsgWithdrawDelegatorReward)(nil), "cosmos_sdk.x.distribution.v1.MsgWithdrawDelegatorReward") + proto.RegisterType((*MsgWithdrawValidatorCommission)(nil), "cosmos_sdk.x.distribution.v1.MsgWithdrawValidatorCommission") + proto.RegisterType((*MsgFundCommunityPool)(nil), "cosmos_sdk.x.distribution.v1.MsgFundCommunityPool") + proto.RegisterType((*Params)(nil), "cosmos_sdk.x.distribution.v1.Params") + proto.RegisterType((*ValidatorHistoricalRewards)(nil), "cosmos_sdk.x.distribution.v1.ValidatorHistoricalRewards") + proto.RegisterType((*ValidatorCurrentRewards)(nil), "cosmos_sdk.x.distribution.v1.ValidatorCurrentRewards") + proto.RegisterType((*ValidatorAccumulatedCommission)(nil), "cosmos_sdk.x.distribution.v1.ValidatorAccumulatedCommission") + proto.RegisterType((*ValidatorOutstandingRewards)(nil), "cosmos_sdk.x.distribution.v1.ValidatorOutstandingRewards") + proto.RegisterType((*ValidatorSlashEvent)(nil), "cosmos_sdk.x.distribution.v1.ValidatorSlashEvent") + proto.RegisterType((*ValidatorSlashEvents)(nil), "cosmos_sdk.x.distribution.v1.ValidatorSlashEvents") + proto.RegisterType((*FeePool)(nil), "cosmos_sdk.x.distribution.v1.FeePool") + proto.RegisterType((*CommunityPoolSpendProposal)(nil), "cosmos_sdk.x.distribution.v1.CommunityPoolSpendProposal") + proto.RegisterType((*DelegatorStartingInfo)(nil), "cosmos_sdk.x.distribution.v1.DelegatorStartingInfo") } func init() { proto.RegisterFile("x/distribution/types/types.proto", fileDescriptor_9fddf2a8e4a90b09) } @@ -749,75 +749,75 @@ func init() { proto.RegisterFile("x/distribution/types/types.proto", fileDescrip var fileDescriptor_9fddf2a8e4a90b09 = []byte{ // 1113 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x57, 0xcf, 0x6f, 0x1b, 0x45, - 0x14, 0xf6, 0x38, 0x4e, 0x9a, 0x4c, 0xd3, 0xa4, 0xd9, 0xd8, 0x49, 0xe4, 0x80, 0xd7, 0x1a, 0x44, - 0x15, 0x09, 0xc5, 0x69, 0xe8, 0x2d, 0x07, 0xa4, 0x38, 0x3f, 0x04, 0xa8, 0xa1, 0xd1, 0x26, 0x14, + 0x14, 0xf6, 0x38, 0x4e, 0x9a, 0x4c, 0xd3, 0xa4, 0xd9, 0xd8, 0x49, 0xe4, 0x14, 0xaf, 0x35, 0x88, + 0x2a, 0x12, 0x8a, 0x43, 0xe8, 0x2d, 0x07, 0xa4, 0x38, 0x3f, 0x04, 0xa8, 0xa1, 0xd1, 0x26, 0x14, 0x09, 0x09, 0xad, 0xc6, 0xbb, 0x13, 0x7b, 0x94, 0xf5, 0xce, 0x6a, 0x66, 0x6c, 0x27, 0xbd, 0x20, - 0x71, 0x02, 0x41, 0x11, 0x07, 0x04, 0x3d, 0x70, 0xe8, 0x05, 0x09, 0x2a, 0xfe, 0x0e, 0xd4, 0x63, - 0x6f, 0x20, 0x0e, 0x2e, 0x4a, 0x6e, 0x1c, 0x73, 0x83, 0x13, 0xda, 0x9d, 0xd9, 0x5d, 0xc7, 0xb1, - 0x68, 0x1c, 0xa9, 0xf4, 0x92, 0x64, 0xde, 0xbc, 0xf9, 0xbe, 0x6f, 0xbe, 0x99, 0x79, 0x6f, 0x03, - 0xcb, 0x47, 0x2b, 0x2e, 0x15, 0x92, 0xd3, 0x5a, 0x4b, 0x52, 0xe6, 0xaf, 0xc8, 0xe3, 0x80, 0x08, - 0xf5, 0xb3, 0x12, 0x70, 0x26, 0x99, 0xb1, 0xe8, 0x30, 0xd1, 0x64, 0xc2, 0x16, 0xee, 0x61, 0xe5, - 0xa8, 0xe2, 0xd2, 0x24, 0xb7, 0xd2, 0x5e, 0x2d, 0xde, 0x92, 0x0d, 0xca, 0x5d, 0x3b, 0xc0, 0x5c, - 0x1e, 0xaf, 0x44, 0xf9, 0x2b, 0x75, 0x56, 0x67, 0xe9, 0x5f, 0x0a, 0xa4, 0x38, 0x73, 0x01, 0x17, - 0x7d, 0x95, 0x85, 0x85, 0x1d, 0x51, 0xdf, 0x23, 0xf2, 0x23, 0x2a, 0x1b, 0x2e, 0xc7, 0x9d, 0x75, - 0xd7, 0xe5, 0x44, 0x08, 0xe3, 0x01, 0x9c, 0x71, 0x89, 0x47, 0xea, 0x58, 0x32, 0x6e, 0x63, 0x15, - 0x5c, 0x00, 0x65, 0xb0, 0x34, 0x59, 0xdd, 0x39, 0xeb, 0x9a, 0x0b, 0xc7, 0xb8, 0xe9, 0xad, 0xa1, - 0x0b, 0x29, 0xe8, 0x9f, 0xae, 0xb9, 0x5c, 0xa7, 0xb2, 0xd1, 0xaa, 0x55, 0x1c, 0xd6, 0x5c, 0x51, - 0xba, 0xf5, 0xaf, 0x65, 0xe1, 0x1e, 0x6a, 0xfa, 0x75, 0xc7, 0xd1, 0x4c, 0xd6, 0xcd, 0x04, 0x24, - 0xe6, 0xee, 0xc0, 0x9b, 0x1d, 0x2d, 0x27, 0xa1, 0xce, 0x46, 0xd4, 0x77, 0xcf, 0xba, 0xe6, 0xbc, - 0xa2, 0xee, 0xcf, 0xb8, 0x02, 0xf3, 0x74, 0xe7, 0xfc, 0xa6, 0xd1, 0xb7, 0x59, 0x58, 0xdc, 0x11, - 0xf5, 0xd8, 0x8b, 0xcd, 0x58, 0x98, 0x45, 0x3a, 0x98, 0xbb, 0xaf, 0xd4, 0x93, 0x07, 0x70, 0xa6, - 0x8d, 0x3d, 0xea, 0x9e, 0xe3, 0xce, 0xf6, 0x73, 0x5f, 0x48, 0xb9, 0x2c, 0xf7, 0x7d, 0xec, 0x25, - 0xdc, 0x09, 0x48, 0x6c, 0xcb, 0x0f, 0x00, 0x96, 0x7a, 0x6c, 0xb9, 0x1f, 0xcf, 0x6f, 0xb0, 0x66, - 0x93, 0x0a, 0x41, 0x99, 0x3f, 0x58, 0x1e, 0xf8, 0x7f, 0xe4, 0xfd, 0x0a, 0x60, 0x7e, 0x47, 0xd4, - 0xb7, 0x5b, 0xbe, 0x1b, 0x2a, 0x6a, 0xf9, 0x54, 0x1e, 0xef, 0x32, 0xe6, 0x19, 0x9f, 0xc0, 0x31, - 0xdc, 0x64, 0x2d, 0x5f, 0x2e, 0x80, 0xf2, 0xc8, 0xd2, 0xf5, 0xb7, 0x67, 0x2b, 0x3d, 0xcf, 0xa8, - 0xbd, 0x5a, 0xd9, 0x60, 0xd4, 0xaf, 0xde, 0x7e, 0xda, 0x35, 0x33, 0x4f, 0x9e, 0x9b, 0x4b, 0x97, - 0x90, 0x11, 0x2e, 0x10, 0x96, 0x06, 0x35, 0xee, 0xc1, 0x09, 0x97, 0x04, 0x4c, 0x50, 0xc9, 0xb8, - 0x3e, 0x8a, 0xd5, 0xe1, 0x8f, 0x3a, 0xc5, 0x40, 0xbf, 0x8d, 0xc0, 0xb1, 0x5d, 0xcc, 0x71, 0x53, - 0x18, 0x87, 0xf0, 0x86, 0x13, 0xef, 0xc5, 0x96, 0xf8, 0x28, 0xf2, 0x72, 0xa2, 0xba, 0x1d, 0x8a, - 0xfd, 0xa3, 0x6b, 0xde, 0xba, 0x04, 0xc7, 0x26, 0x71, 0xce, 0xba, 0x66, 0x5e, 0x39, 0x7f, 0x0e, - 0x0c, 0x59, 0x93, 0xc9, 0x78, 0x1f, 0x1f, 0x19, 0x9f, 0xc2, 0x7c, 0x0d, 0x0b, 0x62, 0x07, 0x9c, - 0x05, 0x4c, 0x10, 0x6e, 0xf3, 0xe8, 0xbe, 0x47, 0x7b, 0x9a, 0xa8, 0xee, 0x0c, 0xcd, 0xb9, 0xa8, - 0x38, 0x07, 0x61, 0x22, 0xcb, 0x08, 0xc3, 0xbb, 0x3a, 0xaa, 0x1f, 0xd6, 0x67, 0x00, 0x16, 0x6a, - 0xcc, 0x6f, 0x89, 0x0b, 0x12, 0x46, 0x22, 0x09, 0x1f, 0x0c, 0x2d, 0xe1, 0x35, 0x2d, 0x61, 0x10, - 0x28, 0xb2, 0x66, 0xa3, 0x78, 0x9f, 0x88, 0x7d, 0x58, 0x38, 0x57, 0x53, 0x6c, 0xe2, 0xe3, 0x9a, - 0x47, 0xdc, 0x85, 0x5c, 0x19, 0x2c, 0x8d, 0x57, 0xcb, 0x29, 0xea, 0xc0, 0x34, 0x64, 0xcd, 0xf6, - 0x96, 0x93, 0x2d, 0x15, 0x5d, 0xcb, 0x3d, 0x7a, 0x6c, 0x66, 0xd0, 0x17, 0x59, 0x58, 0x4c, 0x9e, + 0x71, 0x02, 0x01, 0x15, 0x07, 0x04, 0x3d, 0x70, 0xe8, 0x05, 0x09, 0x2a, 0xf1, 0x6f, 0xa0, 0x1e, + 0x7b, 0x03, 0x71, 0x70, 0x51, 0x72, 0xe3, 0x98, 0x1b, 0x9c, 0xd0, 0xee, 0x8c, 0x77, 0x37, 0x8e, + 0x45, 0xe3, 0x48, 0xa5, 0x97, 0x24, 0xf3, 0x66, 0xe6, 0xfb, 0xbe, 0xf9, 0x66, 0xde, 0x7b, 0x1b, + 0x58, 0x3e, 0x5a, 0x71, 0xa9, 0x90, 0x9c, 0xd6, 0x5a, 0x92, 0x32, 0x7f, 0x45, 0x1e, 0x07, 0x44, + 0xa8, 0x9f, 0x95, 0x80, 0x33, 0xc9, 0x8c, 0x5b, 0x0e, 0x13, 0x4d, 0x26, 0x6c, 0xe1, 0x1e, 0x56, + 0x8e, 0x2a, 0xe9, 0xc5, 0x95, 0xf6, 0x6a, 0xf1, 0xb6, 0x6c, 0x50, 0xee, 0xda, 0x01, 0xe6, 0xf2, + 0x78, 0x25, 0xda, 0xb0, 0x52, 0x67, 0x75, 0x96, 0xfc, 0xa5, 0x50, 0x8a, 0x33, 0x17, 0x80, 0xd1, + 0x57, 0x59, 0x58, 0xd8, 0x11, 0xf5, 0x3d, 0x22, 0x3f, 0xa2, 0xb2, 0xe1, 0x72, 0xdc, 0x59, 0x77, + 0x5d, 0x4e, 0x84, 0x30, 0x1e, 0xc0, 0x19, 0x97, 0x78, 0xa4, 0x8e, 0x25, 0xe3, 0x36, 0x56, 0xc1, + 0x05, 0x50, 0x06, 0x4b, 0x93, 0xd5, 0x9d, 0xb3, 0xae, 0xb9, 0x70, 0x8c, 0x9b, 0xde, 0x1a, 0xba, + 0xb0, 0x04, 0xfd, 0xd3, 0x35, 0x97, 0xeb, 0x54, 0x36, 0x5a, 0xb5, 0x8a, 0xc3, 0x9a, 0x2b, 0x4a, + 0xb8, 0xfe, 0xb5, 0x2c, 0xdc, 0x43, 0x4d, 0xbf, 0xee, 0x38, 0x9a, 0xc9, 0xba, 0x19, 0x83, 0xf4, + 0xb8, 0x3b, 0xf0, 0x66, 0x47, 0xcb, 0x89, 0xa9, 0xb3, 0x11, 0xf5, 0xdd, 0xb3, 0xae, 0x39, 0xaf, + 0xa8, 0xfb, 0x57, 0x5c, 0x81, 0x79, 0xba, 0x73, 0xfe, 0xd0, 0xe8, 0xdb, 0x2c, 0x2c, 0xee, 0x88, + 0x7a, 0xcf, 0x8b, 0xcd, 0x9e, 0x30, 0x8b, 0x74, 0x30, 0x77, 0x5f, 0xa9, 0x27, 0x0f, 0xe0, 0x4c, + 0x1b, 0x7b, 0xd4, 0x3d, 0xc7, 0x9d, 0xed, 0xe7, 0xbe, 0xb0, 0xe4, 0xb2, 0xdc, 0xf7, 0xb1, 0x17, + 0x73, 0xc7, 0x20, 0x3d, 0x5b, 0x7e, 0x00, 0xb0, 0x94, 0xb2, 0xe5, 0x7e, 0x6f, 0x7e, 0x83, 0x35, + 0x9b, 0x54, 0x08, 0xca, 0xfc, 0xc1, 0xf2, 0xc0, 0xff, 0x23, 0xef, 0x57, 0x00, 0xf3, 0x3b, 0xa2, + 0xbe, 0xdd, 0xf2, 0xdd, 0x50, 0x51, 0xcb, 0xa7, 0xf2, 0x78, 0x97, 0x31, 0xcf, 0xf8, 0x04, 0x8e, + 0xe1, 0x26, 0x6b, 0xf9, 0x72, 0x01, 0x94, 0x47, 0x96, 0xae, 0xbf, 0x3d, 0x5b, 0x49, 0xe5, 0x51, + 0x7b, 0xb5, 0xb2, 0xc1, 0xa8, 0x5f, 0x7d, 0xeb, 0x69, 0xd7, 0xcc, 0x3c, 0x79, 0x6e, 0x2e, 0x5d, + 0x42, 0x46, 0xb8, 0x41, 0x58, 0x1a, 0xd4, 0xb8, 0x07, 0x27, 0x5c, 0x12, 0x30, 0x41, 0x25, 0xe3, + 0xfa, 0x2a, 0x56, 0x87, 0xbf, 0xea, 0x04, 0x03, 0xfd, 0x36, 0x02, 0xc7, 0x76, 0x31, 0xc7, 0x4d, + 0x61, 0x1c, 0xc2, 0x1b, 0x4e, 0xef, 0x2c, 0xb6, 0xc4, 0x47, 0x91, 0x97, 0x13, 0xd5, 0xed, 0x50, + 0xec, 0x1f, 0x5d, 0xf3, 0xf6, 0x25, 0x38, 0x36, 0x89, 0x73, 0xd6, 0x35, 0xf3, 0xca, 0xf9, 0x73, + 0x60, 0xc8, 0x9a, 0x8c, 0xc7, 0xfb, 0xf8, 0xc8, 0xf8, 0x14, 0xe6, 0x6b, 0x58, 0x10, 0x3b, 0xe0, + 0x2c, 0x60, 0x82, 0x70, 0x9b, 0x47, 0xef, 0x3d, 0x3a, 0xd3, 0x44, 0x75, 0x67, 0x68, 0xce, 0x45, + 0xc5, 0x39, 0x08, 0x13, 0x59, 0x46, 0x18, 0xde, 0xd5, 0x51, 0x9d, 0x58, 0x9f, 0x01, 0x58, 0xa8, + 0x31, 0xbf, 0x25, 0x2e, 0x48, 0x18, 0x89, 0x24, 0x7c, 0x30, 0xb4, 0x84, 0x5b, 0x5a, 0xc2, 0x20, + 0x50, 0x64, 0xcd, 0x46, 0xf1, 0x3e, 0x11, 0xfb, 0xb0, 0x70, 0xae, 0xa6, 0xd8, 0xc4, 0xc7, 0x35, + 0x8f, 0xb8, 0x0b, 0xb9, 0x32, 0x58, 0x1a, 0xaf, 0x96, 0x13, 0xd4, 0x81, 0xcb, 0x90, 0x35, 0x9b, + 0x2e, 0x27, 0x5b, 0x2a, 0xba, 0x96, 0x7b, 0xf4, 0xd8, 0xcc, 0xa0, 0x2f, 0xb2, 0xb0, 0x18, 0xa7, 0xcd, 0xbb, 0x54, 0x48, 0xc6, 0xa9, 0x83, 0x3d, 0xc5, 0x2c, 0x8c, 0x1f, 0x01, 0x9c, 0x77, 0x5a, - 0xcd, 0x96, 0x87, 0x25, 0x6d, 0x13, 0x2d, 0xd3, 0xe6, 0x58, 0x52, 0xa6, 0xaf, 0xee, 0x5c, 0xdf, - 0xd5, 0xdd, 0x24, 0x4e, 0x74, 0x7b, 0x3f, 0x0c, 0x9d, 0x39, 0xeb, 0x9a, 0x25, 0x7d, 0xcc, 0x83, - 0x41, 0xd0, 0x93, 0xe7, 0xe6, 0x5b, 0x97, 0xf3, 0x4e, 0x5d, 0xf1, 0x42, 0x0a, 0xa4, 0x34, 0x5a, - 0x21, 0x8c, 0xb1, 0x01, 0xa7, 0x39, 0x39, 0x20, 0x9c, 0xf8, 0x0e, 0xb1, 0x9d, 0xe8, 0x65, 0x85, - 0x77, 0xe4, 0x46, 0xb5, 0x78, 0xd6, 0x35, 0xe7, 0x94, 0x84, 0xbe, 0x04, 0x64, 0x4d, 0x25, 0x91, - 0x8d, 0x28, 0xf0, 0x08, 0xc0, 0xf9, 0xb4, 0x84, 0xb4, 0x38, 0x27, 0xbe, 0x8c, 0x8d, 0x20, 0xf0, - 0x9a, 0xd2, 0x2d, 0x5e, 0xb0, 0xef, 0x3b, 0xfa, 0xd5, 0x0e, 0xb5, 0xab, 0x18, 0xdb, 0x98, 0x83, - 0x63, 0x01, 0xe1, 0x94, 0xa9, 0x2b, 0x9e, 0xb3, 0xf4, 0x08, 0x3d, 0x04, 0xb0, 0x94, 0x48, 0x5b, - 0x77, 0xb4, 0x09, 0xc4, 0xed, 0x29, 0x74, 0x87, 0x10, 0x3a, 0xc9, 0xe8, 0x65, 0x88, 0xec, 0x81, - 0x47, 0xdf, 0x01, 0xb8, 0x98, 0xe8, 0xb9, 0xd7, 0x92, 0x42, 0x62, 0xdf, 0xa5, 0x7e, 0x3d, 0xb6, - 0xab, 0x73, 0x59, 0xbb, 0xb6, 0xf4, 0x35, 0x99, 0x8a, 0xcf, 0x28, 0x5a, 0x84, 0xae, 0x6a, 0x20, - 0xfa, 0x19, 0xc0, 0xd9, 0x44, 0xd8, 0x9e, 0x87, 0x45, 0x63, 0xab, 0x4d, 0x7c, 0x69, 0x6c, 0xc3, - 0xb4, 0x3c, 0xdb, 0xda, 0xe2, 0xb0, 0x72, 0xe5, 0xaa, 0x8b, 0x69, 0xe7, 0xee, 0xcf, 0x40, 0xd6, - 0x74, 0x12, 0xda, 0x8d, 0x22, 0xc6, 0xfb, 0x70, 0xfc, 0x80, 0x63, 0x27, 0xfc, 0xc2, 0xd1, 0x55, - 0xa8, 0x32, 0x5c, 0x09, 0xb0, 0x92, 0xf5, 0xe8, 0x17, 0x00, 0xf3, 0x03, 0xb4, 0x0a, 0xe3, 0x21, - 0x80, 0x73, 0xa9, 0x16, 0x11, 0xce, 0xd8, 0x24, 0x9a, 0xd2, 0x6e, 0xde, 0xae, 0xfc, 0xc7, 0x67, - 0x57, 0x65, 0x00, 0x66, 0xf5, 0x4d, 0xed, 0xf3, 0xeb, 0xfd, 0x3b, 0xed, 0x45, 0x47, 0x56, 0xbe, - 0x3d, 0x40, 0x8f, 0x2e, 0x15, 0xdf, 0x03, 0x78, 0x6d, 0x9b, 0x90, 0xa8, 0x81, 0x7d, 0x09, 0xe0, - 0x54, 0x5a, 0xb9, 0x03, 0xc6, 0xbc, 0x17, 0x9c, 0xf3, 0x5d, 0xcd, 0x5f, 0xe8, 0xaf, 0xfa, 0xe1, - 0xda, 0xa1, 0x8f, 0x3b, 0x6d, 0x41, 0xa1, 0x1a, 0xf4, 0x75, 0x16, 0x16, 0xcf, 0x35, 0xd8, 0xbd, - 0x80, 0xf8, 0xae, 0xaa, 0xa2, 0xd8, 0x33, 0xf2, 0x70, 0x54, 0x52, 0xe9, 0x11, 0xd5, 0xaa, 0x2c, - 0x35, 0x30, 0xca, 0xf0, 0xba, 0x4b, 0x84, 0xc3, 0x69, 0x90, 0x1e, 0xa6, 0xd5, 0x1b, 0x0a, 0xdb, - 0x28, 0x27, 0x0e, 0x0d, 0x28, 0xf1, 0x65, 0x54, 0xef, 0xaf, 0xd6, 0x46, 0x13, 0x8c, 0x9e, 0xb6, - 0x9f, 0x7b, 0x09, 0x6d, 0x7f, 0x6d, 0xfc, 0xf3, 0xc7, 0x66, 0x26, 0x3a, 0xaa, 0xbf, 0x01, 0x2c, - 0x24, 0xdf, 0x88, 0x7b, 0x12, 0x73, 0x49, 0xfd, 0xfa, 0x7b, 0xfe, 0x41, 0x54, 0x28, 0x03, 0x4e, - 0xda, 0x94, 0x85, 0xdd, 0xa7, 0xf7, 0x19, 0xf4, 0x14, 0xca, 0xbe, 0x04, 0x64, 0x4d, 0xc5, 0x11, - 0xfd, 0x08, 0xf6, 0xe1, 0xa8, 0x90, 0xf8, 0x90, 0xe8, 0x17, 0xf0, 0xce, 0xd0, 0x4d, 0x70, 0x52, - 0x11, 0x45, 0x20, 0xc8, 0x52, 0x60, 0xc6, 0x16, 0x1c, 0x6b, 0x10, 0x5a, 0x6f, 0x28, 0xaf, 0x73, - 0xd5, 0xe5, 0xbf, 0xba, 0xe6, 0xb4, 0xc3, 0x49, 0x58, 0xe0, 0x7d, 0x5b, 0x4d, 0xa5, 0x22, 0xfb, - 0x26, 0x90, 0xa5, 0x17, 0x57, 0xdf, 0xf8, 0xe9, 0xa4, 0x04, 0x9e, 0x9e, 0x94, 0xc0, 0xb3, 0x93, - 0x12, 0xf8, 0xf3, 0xa4, 0x04, 0xbe, 0x39, 0x2d, 0x65, 0x9e, 0x9d, 0x96, 0x32, 0xbf, 0x9f, 0x96, - 0x32, 0x1f, 0x8f, 0x46, 0x32, 0x6a, 0x63, 0xd1, 0x7f, 0x19, 0x77, 0xfe, 0x0d, 0x00, 0x00, 0xff, - 0xff, 0x7b, 0x35, 0xec, 0x82, 0xe1, 0x0c, 0x00, 0x00, + 0xcd, 0x96, 0x87, 0x25, 0x6d, 0x13, 0x2d, 0xd3, 0xe6, 0x58, 0x52, 0xa6, 0x9f, 0xee, 0x5c, 0xdf, + 0xd3, 0xdd, 0x24, 0x4e, 0xf4, 0x7a, 0x3f, 0x0c, 0x9d, 0x39, 0xeb, 0x9a, 0x25, 0x7d, 0xcd, 0x83, + 0x41, 0xd0, 0x93, 0xe7, 0xe6, 0x9b, 0x97, 0xf3, 0x4e, 0x3d, 0xf1, 0x42, 0x02, 0xa4, 0x34, 0x5a, + 0x21, 0x8c, 0xb1, 0x01, 0xa7, 0x39, 0x39, 0x20, 0x9c, 0xf8, 0x0e, 0xb1, 0x9d, 0x28, 0xb3, 0xc2, + 0x37, 0x72, 0xa3, 0x5a, 0x3c, 0xeb, 0x9a, 0x73, 0x4a, 0x42, 0xdf, 0x02, 0x64, 0x4d, 0xc5, 0x91, + 0x8d, 0x28, 0xf0, 0x08, 0xc0, 0xf9, 0xa4, 0x84, 0xb4, 0x38, 0x27, 0xbe, 0xec, 0x19, 0x41, 0xe0, + 0x35, 0xa5, 0x5b, 0xbc, 0xe0, 0xdc, 0x77, 0x74, 0xd6, 0x0e, 0x75, 0xaa, 0x1e, 0xb6, 0x31, 0x07, + 0xc7, 0x02, 0xc2, 0x29, 0x53, 0x4f, 0x3c, 0x67, 0xe9, 0x11, 0xfa, 0x1a, 0xc0, 0x52, 0x2c, 0x6d, + 0xdd, 0xd1, 0x26, 0x10, 0x37, 0x55, 0xe8, 0x0e, 0x21, 0x74, 0xe2, 0xd1, 0xcb, 0x10, 0x99, 0x82, + 0x47, 0xdf, 0x01, 0xb8, 0x18, 0xeb, 0xb9, 0xd7, 0x92, 0x42, 0x62, 0xdf, 0xa5, 0x7e, 0xbd, 0x67, + 0x57, 0xe7, 0xb2, 0x76, 0x6d, 0xe9, 0x67, 0x32, 0xd5, 0xbb, 0xa3, 0x68, 0x13, 0xba, 0xaa, 0x81, + 0xe8, 0x67, 0x00, 0x67, 0x63, 0x61, 0x7b, 0x1e, 0x16, 0x8d, 0xad, 0x36, 0xf1, 0xa5, 0xb1, 0x0d, + 0x93, 0xf2, 0x6c, 0x6b, 0x8b, 0xc3, 0xca, 0x95, 0xab, 0x2e, 0x26, 0x9d, 0xbb, 0x7f, 0x05, 0xb2, + 0xa6, 0xe3, 0xd0, 0x6e, 0x14, 0x31, 0xde, 0x87, 0xe3, 0x07, 0x1c, 0x3b, 0xe1, 0x17, 0x8e, 0xae, + 0x42, 0x95, 0xe1, 0x4a, 0x80, 0x15, 0xef, 0x47, 0xbf, 0x00, 0x98, 0x1f, 0xa0, 0x55, 0x18, 0x0f, + 0x01, 0x9c, 0x4b, 0xb4, 0x88, 0x70, 0xc6, 0x26, 0xd1, 0x94, 0x76, 0x73, 0xb5, 0xf2, 0x5f, 0xdf, + 0x5d, 0x95, 0x01, 0xa0, 0xd5, 0x37, 0xb4, 0xd1, 0xaf, 0xf5, 0x1f, 0x35, 0x0d, 0x8f, 0xac, 0x7c, + 0x7b, 0x80, 0x20, 0x5d, 0x2b, 0xbe, 0x07, 0xf0, 0xda, 0x36, 0x21, 0x51, 0x07, 0xfb, 0x12, 0xc0, + 0xa9, 0xa4, 0x74, 0x07, 0x8c, 0x79, 0x2f, 0xb8, 0xe8, 0xbb, 0x9a, 0xbf, 0xd0, 0x5f, 0xf6, 0xc3, + 0xbd, 0x43, 0xdf, 0x77, 0xd2, 0x83, 0x42, 0x35, 0xe8, 0x61, 0x16, 0x16, 0xcf, 0x75, 0xd8, 0xbd, + 0x80, 0xf8, 0xae, 0x2a, 0xa3, 0xd8, 0x33, 0xf2, 0x70, 0x54, 0x52, 0xe9, 0x11, 0xd5, 0xab, 0x2c, + 0x35, 0x30, 0xca, 0xf0, 0xba, 0x4b, 0x84, 0xc3, 0x69, 0x90, 0xdc, 0xa6, 0x95, 0x0e, 0x85, 0x7d, + 0x94, 0x13, 0x87, 0x06, 0x94, 0xf8, 0x32, 0x2a, 0xf8, 0x57, 0xeb, 0xa3, 0x31, 0x46, 0xaa, 0xef, + 0xe7, 0x5e, 0x42, 0xdf, 0x5f, 0x1b, 0xff, 0xfc, 0xb1, 0x99, 0x89, 0xae, 0xea, 0x6f, 0x00, 0x0b, + 0xf1, 0x47, 0xe2, 0x9e, 0xc4, 0x5c, 0x52, 0xbf, 0xfe, 0x9e, 0x7f, 0x10, 0x55, 0xca, 0x80, 0x93, + 0x36, 0x65, 0x61, 0xfb, 0x49, 0xe7, 0x41, 0xaa, 0x52, 0xf6, 0x2d, 0x40, 0xd6, 0x54, 0x2f, 0xa2, + 0xb3, 0x60, 0x1f, 0x8e, 0x0a, 0x89, 0x0f, 0x89, 0x4e, 0x81, 0x77, 0x86, 0xee, 0x82, 0x93, 0x8a, + 0x28, 0x02, 0x41, 0x96, 0x02, 0x33, 0xb6, 0xe0, 0x58, 0x83, 0xd0, 0x7a, 0x43, 0x79, 0x9d, 0xab, + 0x2e, 0xff, 0xd5, 0x35, 0xa7, 0x1d, 0x4e, 0xc2, 0x0a, 0xef, 0xdb, 0x6a, 0x2a, 0x11, 0xd9, 0x37, + 0x81, 0x2c, 0xbd, 0xb9, 0xfa, 0xfa, 0x4f, 0x27, 0x25, 0xf0, 0xf4, 0xa4, 0x04, 0x9e, 0x9d, 0x94, + 0xc0, 0x9f, 0x27, 0x25, 0xf0, 0xcd, 0x69, 0x29, 0xf3, 0xec, 0xb4, 0x94, 0xf9, 0xfd, 0xb4, 0x94, + 0xf9, 0x78, 0x34, 0x92, 0x51, 0x1b, 0x8b, 0xfe, 0xcd, 0xb8, 0xf3, 0x6f, 0x00, 0x00, 0x00, 0xff, + 0xff, 0x9c, 0x88, 0x6a, 0xf1, 0xe3, 0x0c, 0x00, 0x00, } func (this *MsgSetWithdrawAddress) Equal(that interface{}) bool { From 430739c2b8e3050e4e3f89d0e5a765dfda4f7890 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Tue, 3 Mar 2020 20:29:34 -0500 Subject: [PATCH 360/529] Remove named return --- x/gov/keeper/proposal.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/gov/keeper/proposal.go b/x/gov/keeper/proposal.go index 020ec08a3f6f..3055af875024 100644 --- a/x/gov/keeper/proposal.go +++ b/x/gov/keeper/proposal.go @@ -49,7 +49,7 @@ func (keeper Keeper) SubmitProposal(ctx sdk.Context, content types.Content) (typ } // GetProposal get proposal from store by ProposalID -func (keeper Keeper) GetProposal(ctx sdk.Context, proposalID uint64) (proposal types.Proposal, ok bool) { +func (keeper Keeper) GetProposal(ctx sdk.Context, proposalID uint64) (types.Proposal, bool) { store := ctx.KVStore(keeper.storeKey) bz := store.Get(types.ProposalKey(proposalID)) From 0cbe4e55324b247ddf0d549340de7a0e45216b12 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Wed, 4 Mar 2020 09:27:50 -0500 Subject: [PATCH 361/529] Update x/upgrade/types/types.proto Co-Authored-By: Anil Kumar Kammari --- x/upgrade/types/types.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/upgrade/types/types.proto b/x/upgrade/types/types.proto index 3b0fffb8f1e6..ba1191773fb6 100644 --- a/x/upgrade/types/types.proto +++ b/x/upgrade/types/types.proto @@ -41,7 +41,7 @@ message SoftwareUpgradeProposal { Plan plan = 3 [(gogoproto.nullable) = false]; } -// SoftwareUpgradeProposal is a gov Content type for cancelling a software upgrade +// CancelSoftwareUpgradeProposal is a gov Content type for cancelling a software upgrade message CancelSoftwareUpgradeProposal { option (gogoproto.equal) = true; From da5c6ced1dc0a3925f26653c24ba0934cce51f22 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Wed, 4 Mar 2020 17:49:59 +0000 Subject: [PATCH 362/529] types: add test cases (#5747) Upgrade gomock dependency. --- .codecov.yml | 1 + go.mod | 2 +- go.sum | 9 ++- types/address.go | 44 ++++------- types/address_test.go | 80 +++++++++++++++++++ types/config_test.go | 47 +++++++++++ types/context_test.go | 24 +++++- types/errors/abci_test.go | 32 ++++++++ types/int_test.go | 46 +++++++++++ types/invariant_test.go | 15 ++++ types/result_test.go | 161 ++++++++++++++++++++++++++++++++++++-- types/staking_test.go | 24 ++++++ types/store_test.go | 94 +++++++++++++++++++++- types/tx_msg_test.go | 23 ++++++ types/uint_test.go | 12 +++ types/utils_test.go | 45 ++++++++--- 16 files changed, 606 insertions(+), 53 deletions(-) create mode 100644 types/config_test.go create mode 100644 types/invariant_test.go create mode 100644 types/staking_test.go create mode 100644 types/tx_msg_test.go diff --git a/.codecov.yml b/.codecov.yml index f4d6cef61f60..e17633a5d388 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -47,6 +47,7 @@ ignore: - "*.md" - "*.rst" - "**/*.pb.go" + - "types/*.pb.go" - "tests/*" - "tests/**/*" - "x/**/*.pb.go" diff --git a/go.mod b/go.mod index 1599418dc4d0..c010e24ab730 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d github.com/cosmos/ledger-cosmos-go v0.11.1 github.com/gogo/protobuf v1.3.1 - github.com/golang/mock v1.3.1-0.20190508161146-9fa652df1129 + github.com/golang/mock v1.4.1 github.com/golang/protobuf v1.3.4 github.com/gorilla/handlers v1.4.2 github.com/gorilla/mux v1.7.4 diff --git a/go.sum b/go.sum index 5ad52215962c..ae529cbb3acf 100644 --- a/go.sum +++ b/go.sum @@ -85,8 +85,8 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekf github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1-0.20190508161146-9fa652df1129 h1:tT8iWCYw4uOem71yYA3htfH+LNopJvcqZQshm56G5L4= -github.com/golang/mock v1.3.1-0.20190508161146-9fa652df1129/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.1 h1:ocYkMQY5RrXTYgXl7ICpV0IXwlEQGwKIsery4gyXa1U= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -322,6 +322,7 @@ golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -368,3 +369,7 @@ gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +rsc.io/quote/v3 v3.1.0 h1:9JKUTTIUgS6kzR9mK1YuGKv6Nl+DijDNIc0ghT58FaY= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/types/address.go b/types/address.go index 839af224d01f..c2a645b3077a 100644 --- a/types/address.go +++ b/types/address.go @@ -98,16 +98,8 @@ type AccAddress []byte // AccAddressFromHex creates an AccAddress from a hex string. func AccAddressFromHex(address string) (addr AccAddress, err error) { - if len(address) == 0 { - return addr, errors.New("decoding Bech32 address failed: must provide an address") - } - - bz, err := hex.DecodeString(address) - if err != nil { - return nil, err - } - - return AccAddress(bz), nil + bz, err := addressBytesFromHexString(address) + return AccAddress(bz), err } // VerifyAddressFormat verifies that the provided bytes form a valid address @@ -265,16 +257,8 @@ type ValAddress []byte // ValAddressFromHex creates a ValAddress from a hex string. func ValAddressFromHex(address string) (addr ValAddress, err error) { - if len(address) == 0 { - return addr, errors.New("decoding Bech32 address failed: must provide an address") - } - - bz, err := hex.DecodeString(address) - if err != nil { - return nil, err - } - - return ValAddress(bz), nil + bz, err := addressBytesFromHexString(address) + return ValAddress(bz), err } // ValAddressFromBech32 creates a ValAddress from a Bech32 string. @@ -420,16 +404,8 @@ type ConsAddress []byte // ConsAddressFromHex creates a ConsAddress from a hex string. func ConsAddressFromHex(address string) (addr ConsAddress, err error) { - if len(address) == 0 { - return addr, errors.New("decoding Bech32 address failed: must provide an address") - } - - bz, err := hex.DecodeString(address) - if err != nil { - return nil, err - } - - return ConsAddress(bz), nil + bz, err := addressBytesFromHexString(address) + return ConsAddress(bz), err } // ConsAddressFromBech32 creates a ConsAddress from a Bech32 string. @@ -695,3 +671,11 @@ func GetFromBech32(bech32str, prefix string) ([]byte, error) { return bz, nil } + +func addressBytesFromHexString(address string) ([]byte, error) { + if len(address) == 0 { + return nil, errors.New("decoding Bech32 address failed: must provide an address") + } + + return hex.DecodeString(address) +} diff --git a/types/address_test.go b/types/address_test.go index 5193404d093f..8a928a43c923 100644 --- a/types/address_test.go +++ b/types/address_test.go @@ -1,6 +1,7 @@ package types_test import ( + "bytes" "encoding/hex" "fmt" "math/rand" @@ -8,6 +9,7 @@ import ( "testing" "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/crypto" yaml "gopkg.in/yaml.v2" "github.com/tendermint/tendermint/crypto/ed25519" @@ -37,6 +39,7 @@ func testMarshal(t *testing.T, original interface{}, res interface{}, marshal fu } func TestEmptyAddresses(t *testing.T) { + t.Parallel() require.Equal(t, (types.AccAddress{}).String(), "") require.Equal(t, (types.ValAddress{}).String(), "") require.Equal(t, (types.ConsAddress{}).String(), "") @@ -145,6 +148,9 @@ func TestRandBech32AccAddrConsistency(t *testing.T) { err = (*types.AccAddress)(nil).UnmarshalJSON([]byte("\"" + str + "\"")) require.NotNil(t, err) } + + _, err := types.AccAddressFromHex("") + require.Equal(t, "decoding Bech32 address failed: must provide an address", err.Error()) } func TestValAddr(t *testing.T) { @@ -168,6 +174,7 @@ func TestValAddr(t *testing.T) { res, err = types.ValAddressFromHex(str) require.Nil(t, err) require.Equal(t, acc, res) + } for _, str := range invalidStrs { @@ -180,6 +187,10 @@ func TestValAddr(t *testing.T) { err = (*types.ValAddress)(nil).UnmarshalJSON([]byte("\"" + str + "\"")) require.NotNil(t, err) } + + // test empty string + _, err := types.ValAddressFromHex("") + require.Equal(t, "decoding Bech32 address failed: must provide an address", err.Error()) } func TestConsAddress(t *testing.T) { @@ -215,6 +226,10 @@ func TestConsAddress(t *testing.T) { err = (*types.ConsAddress)(nil).UnmarshalJSON([]byte("\"" + str + "\"")) require.NotNil(t, err) } + + // test empty string + _, err := types.ConsAddressFromHex("") + require.Equal(t, "decoding Bech32 address failed: must provide an address", err.Error()) } const letterBytes = "abcdefghijklmnopqrstuvwxyz" @@ -410,3 +425,68 @@ func TestMustBech32ifyAddressBytes(t *testing.T) { }) } } + +func TestAddressTypesEquals(t *testing.T) { + t.Parallel() + addr1 := secp256k1.GenPrivKey().PubKey().Address() + accAddr1 := types.AccAddress(addr1) + consAddr1 := types.ConsAddress(addr1) + valAddr1 := types.ValAddress(addr1) + + addr2 := secp256k1.GenPrivKey().PubKey().Address() + accAddr2 := types.AccAddress(addr2) + consAddr2 := types.ConsAddress(addr2) + valAddr2 := types.ValAddress(addr2) + + // equality + require.True(t, accAddr1.Equals(accAddr1)) + require.True(t, consAddr1.Equals(consAddr1)) + require.True(t, valAddr1.Equals(valAddr1)) + + // emptiness + require.True(t, types.AccAddress{}.Equals(types.AccAddress{})) + require.True(t, types.AccAddress{}.Equals(types.AccAddress(nil))) + require.True(t, types.AccAddress(nil).Equals(types.AccAddress{})) + require.True(t, types.AccAddress(nil).Equals(types.AccAddress(nil))) + + require.True(t, types.ConsAddress{}.Equals(types.ConsAddress{})) + require.True(t, types.ConsAddress{}.Equals(types.ConsAddress(nil))) + require.True(t, types.ConsAddress(nil).Equals(types.ConsAddress{})) + require.True(t, types.ConsAddress(nil).Equals(types.ConsAddress(nil))) + + require.True(t, types.ValAddress{}.Equals(types.ValAddress{})) + require.True(t, types.ValAddress{}.Equals(types.ValAddress(nil))) + require.True(t, types.ValAddress(nil).Equals(types.ValAddress{})) + require.True(t, types.ValAddress(nil).Equals(types.ValAddress(nil))) + + require.False(t, accAddr1.Equals(accAddr2)) + require.Equal(t, accAddr1.Equals(accAddr2), accAddr2.Equals(accAddr1)) + require.False(t, consAddr1.Equals(consAddr2)) + require.Equal(t, consAddr1.Equals(consAddr2), consAddr2.Equals(consAddr1)) + require.False(t, valAddr1.Equals(valAddr2)) + require.Equal(t, valAddr1.Equals(valAddr2), valAddr2.Equals(valAddr1)) +} + +func TestNilAddressTypesEmpty(t *testing.T) { + t.Parallel() + require.True(t, types.AccAddress(nil).Empty()) + require.True(t, types.ConsAddress(nil).Empty()) + require.True(t, types.ValAddress(nil).Empty()) +} + +func TestGetConsAddress(t *testing.T) { + t.Parallel() + pk := secp256k1.GenPrivKey().PubKey() + require.NotEqual(t, types.GetConsAddress(pk), pk.Address()) + require.True(t, bytes.Equal(types.GetConsAddress(pk).Bytes(), pk.Address().Bytes())) + require.Panics(t, func() { types.GetConsAddress(crypto.PubKey(nil)) }) +} + +func TestGetFromBech32(t *testing.T) { + _, err := types.GetFromBech32("", "prefix") + require.Error(t, err) + require.Equal(t, "decoding Bech32 address failed: must provide an address", err.Error()) + _, err = types.GetFromBech32("cosmos1qqqsyqcyq5rqwzqfys8f67", "x") + require.Error(t, err) + require.Equal(t, "invalid Bech32 prefix; expected x, got cosmos", err.Error()) +} diff --git a/types/config_test.go b/types/config_test.go new file mode 100644 index 000000000000..7c902c1962fb --- /dev/null +++ b/types/config_test.go @@ -0,0 +1,47 @@ +package types_test + +import ( + "errors" + "testing" + + "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func TestConfig_SetCoinType(t *testing.T) { + config := &sdk.Config{} + require.Equal(t, uint32(0), config.GetCoinType()) + config.SetCoinType(99) + require.Equal(t, uint32(99), config.GetCoinType()) + + config.Seal() + require.Panics(t, func() { config.SetCoinType(99) }) +} + +func TestConfig_SetTxEncoder(t *testing.T) { + mockErr := errors.New("test") + config := &sdk.Config{} + require.Nil(t, config.GetTxEncoder()) + encFunc := sdk.TxEncoder(func(tx sdk.Tx) ([]byte, error) { return nil, nil }) + config.SetTxEncoder(encFunc) + _, err := config.GetTxEncoder()(sdk.Tx(nil)) + require.Error(t, mockErr, err) + + config.Seal() + require.Panics(t, func() { config.SetTxEncoder(encFunc) }) +} + +func TestConfig_SetFullFundraiserPath(t *testing.T) { + config := &sdk.Config{} + require.Equal(t, "", config.GetFullFundraiserPath()) + config.SetFullFundraiserPath("test/path") + require.Equal(t, "test/path", config.GetFullFundraiserPath()) + + config.Seal() + require.Panics(t, func() { config.SetFullFundraiserPath("x/test/path") }) +} + +func TestKeyringServiceName(t *testing.T) { + require.Equal(t, sdk.DefaultKeyringServiceName, sdk.KeyringServiceName()) +} diff --git a/types/context_test.go b/types/context_test.go index d8e893364d7d..9f08178624d3 100644 --- a/types/context_test.go +++ b/types/context_test.go @@ -1,6 +1,7 @@ package types_test import ( + "context" "testing" "time" @@ -110,6 +111,7 @@ func TestContextWithCustom(t *testing.T) { logger := NewMockLogger() voteinfos := []abci.VoteInfo{{}} meter := types.NewGasMeter(10000) + blockGasMeter := types.NewGasMeter(20000) minGasPrices := types.DecCoins{types.NewInt64DecCoin("feetoken", 1)} ctx = types.NewContext(nil, header, ischeck, logger) @@ -121,7 +123,8 @@ func TestContextWithCustom(t *testing.T) { WithTxBytes(txbytes). WithVoteInfos(voteinfos). WithGasMeter(meter). - WithMinGasPrices(minGasPrices) + WithMinGasPrices(minGasPrices). + WithBlockGasMeter(blockGasMeter) require.Equal(t, height, ctx.BlockHeight()) require.Equal(t, chainid, ctx.ChainID()) require.Equal(t, ischeck, ctx.IsCheckTx()) @@ -130,6 +133,25 @@ func TestContextWithCustom(t *testing.T) { require.Equal(t, voteinfos, ctx.VoteInfos()) require.Equal(t, meter, ctx.GasMeter()) require.Equal(t, minGasPrices, ctx.MinGasPrices()) + require.Equal(t, blockGasMeter, ctx.BlockGasMeter()) + + require.False(t, ctx.WithIsCheckTx(false).IsCheckTx()) + + // test IsReCheckTx + require.False(t, ctx.IsReCheckTx()) + ctx = ctx.WithIsCheckTx(false) + ctx = ctx.WithIsReCheckTx(true) + require.True(t, ctx.IsCheckTx()) + require.True(t, ctx.IsReCheckTx()) + + // test consensus param + require.Nil(t, ctx.ConsensusParams()) + cp := &abci.ConsensusParams{} + require.Equal(t, cp, ctx.WithConsensusParams(cp).ConsensusParams()) + + // test inner context + newContext := context.WithValue(ctx.Context(), "key", "value") + require.NotEqual(t, ctx.Context(), ctx.WithContext(newContext).Context()) } // Testing saving/loading of header fields to/from the context diff --git a/types/errors/abci_test.go b/types/errors/abci_test.go index c098811ea474..9b9e8280aac7 100644 --- a/types/errors/abci_test.go +++ b/types/errors/abci_test.go @@ -5,6 +5,9 @@ import ( "io" "strings" "testing" + + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" ) func TestABCInfo(t *testing.T) { @@ -185,6 +188,8 @@ func TestRedact(t *testing.T) { if err := Redact(serr); err == serr { t.Error("reduct must not pass through a stdlib error") } + + require.Nil(t, Redact(nil)) } func TestABCIInfoSerializeErr(t *testing.T) { @@ -271,3 +276,30 @@ func (customErr) Codespace() string { return "extern" } func (customErr) ABCICode() uint32 { return 999 } func (customErr) Error() string { return "custom" } + +func TestResponseCheckDeliverTx(t *testing.T) { + t.Parallel() + require.Equal(t, abci.ResponseCheckTx{ + Codespace: "extern", + Code: 999, + Log: "custom", + GasWanted: int64(1), + GasUsed: int64(2), + }, ResponseCheckTx(customErr{}, 1, 2)) + require.Equal(t, abci.ResponseDeliverTx{ + Codespace: "extern", + Code: 999, + Log: "custom", + GasWanted: int64(1), + GasUsed: int64(2), + }, ResponseDeliverTx(customErr{}, 1, 2)) +} + +func TestQueryResult(t *testing.T) { + t.Parallel() + require.Equal(t, abci.ResponseQuery{ + Codespace: "extern", + Code: 999, + Log: "custom", + }, QueryResult(customErr{})) +} diff --git a/types/int_test.go b/types/int_test.go index 7a8ceade1748..aa55ee659ebd 100644 --- a/types/int_test.go +++ b/types/int_test.go @@ -10,6 +10,7 @@ import ( ) func TestFromInt64(t *testing.T) { + t.Parallel() for n := 0; n < 20; n++ { r := rand.Int63() require.Equal(t, r, NewInt(r).Int64()) @@ -17,6 +18,7 @@ func TestFromInt64(t *testing.T) { } func TestFromUint64(t *testing.T) { + t.Parallel() for n := 0; n < 20; n++ { r := rand.Uint64() require.True(t, NewIntFromUint64(r).IsUint64()) @@ -25,6 +27,7 @@ func TestFromUint64(t *testing.T) { } func TestIntPanic(t *testing.T) { + t.Parallel() // Max Int = 2^255-1 = 5.789e+76 // Min Int = -(2^255-1) = -5.789e+76 require.NotPanics(t, func() { NewIntWithDecimal(1, 76) }) @@ -85,6 +88,7 @@ func TestIntPanic(t *testing.T) { // and (U/)Int is immutable value(see TestImmutability(U/)Int) // it is safe to use randomness in the tests func TestIdentInt(t *testing.T) { + t.Parallel() for d := 0; d < 1000; d++ { n := rand.Int63() i := NewInt(n) @@ -121,6 +125,7 @@ func maxint(i1, i2 int64) int64 { } func TestArithInt(t *testing.T) { + t.Parallel() for d := 0; d < 1000; d++ { n1 := int64(rand.Int31()) i1 := NewInt(n1) @@ -152,6 +157,7 @@ func TestArithInt(t *testing.T) { } func TestCompInt(t *testing.T) { + t.Parallel() for d := 0; d < 1000; d++ { n1 := int64(rand.Int31()) i1 := NewInt(n1) @@ -165,6 +171,7 @@ func TestCompInt(t *testing.T) { {i1.Equal(i2), n1 == n2}, {i1.GT(i2), n1 > n2}, {i1.LT(i2), n1 < n2}, + {i1.LTE(i2), n1 <= n2}, } for tcnum, tc := range cases { @@ -192,6 +199,7 @@ func randint() Int { } func TestImmutabilityAllInt(t *testing.T) { + t.Parallel() ops := []func(*Int){ func(i *Int) { _ = i.Add(randint()) }, func(i *Int) { _ = i.Sub(randint()) }, @@ -242,6 +250,7 @@ func intarithraw(uifn func(Int, int64) Int, bifn func(*big.Int, *big.Int, *big.I } func TestImmutabilityArithInt(t *testing.T) { + t.Parallel() size := 500 ops := []intop{ @@ -323,6 +332,7 @@ func TestEncodingRandom(t *testing.T) { } func TestEncodingTableInt(t *testing.T) { + t.Parallel() var i Int cases := []struct { @@ -397,6 +407,7 @@ func TestEncodingTableInt(t *testing.T) { } func TestEncodingTableUint(t *testing.T) { + t.Parallel() var i Uint cases := []struct { @@ -451,6 +462,7 @@ func TestEncodingTableUint(t *testing.T) { } func TestSerializationOverflow(t *testing.T) { + t.Parallel() bx, _ := new(big.Int).SetString("91888242871839275229946405745257275988696311157297823662689937894645226298583", 10) x := Int{bx} y := new(Int) @@ -469,3 +481,37 @@ func TestSerializationOverflow(t *testing.T) { err = y.UnmarshalJSON(bz) require.Error(t, err) } + +func TestIntMod(t *testing.T) { + t.Parallel() + tests := []struct { + name string + x int64 + y int64 + ret int64 + wantPanic bool + }{ + {"3 % 10", 3, 10, 3, false}, + {"10 % 3", 10, 3, 1, false}, + {"4 % 2", 4, 2, 0, false}, + {"2 % 0", 2, 0, 0, true}, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + if tt.wantPanic { + require.Panics(t, func() { NewInt(tt.x).Mod(NewInt(tt.y)) }) + require.Panics(t, func() { NewInt(tt.x).ModRaw(tt.y) }) + return + } + require.True(t, NewInt(tt.x).Mod(NewInt(tt.y)).Equal(NewInt(tt.ret))) + require.True(t, NewInt(tt.x).ModRaw(tt.y).Equal(NewInt(tt.ret))) + }) + } +} + +func TestIntEq(t *testing.T) { + require.True(IntEq(t, ZeroInt(), ZeroInt())) + require.False(IntEq(t, OneInt(), ZeroInt())) +} diff --git a/types/invariant_test.go b/types/invariant_test.go new file mode 100644 index 000000000000..fe5965011532 --- /dev/null +++ b/types/invariant_test.go @@ -0,0 +1,15 @@ +package types_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func TestFormatInvariant(t *testing.T) { + t.Parallel() + require.Equal(t, ": invariant\n\n", sdk.FormatInvariant("", "", "")) + require.Equal(t, "module: name invariant\nmsg\n", sdk.FormatInvariant("module", "name", "msg")) +} diff --git a/types/result_test.go b/types/result_test.go index 992045778654..08e260d400b0 100644 --- a/types/result_test.go +++ b/types/result_test.go @@ -1,17 +1,24 @@ -package types +package types_test import ( + "encoding/hex" + "strings" "testing" "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/libs/bytes" + ctypes "github.com/tendermint/tendermint/rpc/core/types" "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" ) func TestParseABCILog(t *testing.T) { + t.Parallel() logs := `[{"log":"","msg_index":1,"success":true}]` - res, err := ParseABCILogs(logs) + res, err := sdk.ParseABCILogs(logs) require.NoError(t, err) require.Len(t, res, 1) require.Equal(t, res[0].Log, "") @@ -19,11 +26,155 @@ func TestParseABCILog(t *testing.T) { } func TestABCIMessageLog(t *testing.T) { - events := Events{NewEvent("transfer", NewAttribute("sender", "foo"))} - msgLog := NewABCIMessageLog(0, "", events) + t.Parallel() + events := sdk.Events{sdk.NewEvent("transfer", sdk.NewAttribute("sender", "foo"))} + msgLog := sdk.NewABCIMessageLog(0, "", events) - msgLogs := ABCIMessageLogs{msgLog} + msgLogs := sdk.ABCIMessageLogs{msgLog} bz, err := codec.Cdc.MarshalJSON(msgLogs) require.NoError(t, err) require.Equal(t, string(bz), msgLogs.String()) } + +func TestNewSearchTxsResult(t *testing.T) { + t.Parallel() + got := sdk.NewSearchTxsResult(150, 20, 2, 20, []sdk.TxResponse{}) + require.Equal(t, sdk.SearchTxsResult{ + TotalCount: 150, + Count: 20, + PageNumber: 2, + PageTotal: 8, + Limit: 20, + Txs: []sdk.TxResponse{}, + }, got) +} + +/* + Codespace: res.TxResult.Codespace, + Code: res.TxResult.Code, + Data: strings.ToUpper(hex.EncodeToString(res.TxResult.Data)), + RawLog: res.TxResult.Log, + Logs: parsedLogs, + Info: res.TxResult.Info, + GasWanted: res.TxResult.GasWanted, + GasUsed: res.TxResult.GasUsed, + Tx: tx, + Timestamp: timestamp, +*/ + +func TestResponseResultTx(t *testing.T) { + t.Parallel() + deliverTxResult := abci.ResponseDeliverTx{ + Codespace: "codespace", + Code: 1, + Data: []byte("data"), + Log: `[]`, + Info: "info", + GasWanted: 100, + GasUsed: 90, + } + resultTx := &ctypes.ResultTx{ + Hash: bytes.HexBytes([]byte("test")), + Height: 10, + TxResult: deliverTxResult, + } + logs, err := sdk.ParseABCILogs(`[]`) + require.NoError(t, err) + want := sdk.TxResponse{ + TxHash: "74657374", + Height: 10, + Codespace: "codespace", + Code: 1, + Data: strings.ToUpper(hex.EncodeToString([]byte("data"))), + RawLog: `[]`, + Logs: logs, + Info: "info", + GasWanted: 100, + GasUsed: 90, + Tx: sdk.Tx(nil), + Timestamp: "timestamp", + } + + require.Equal(t, want, sdk.NewResponseResultTx(resultTx, sdk.Tx(nil), "timestamp")) + require.Equal(t, sdk.TxResponse{}, sdk.NewResponseResultTx(nil, sdk.Tx(nil), "timestamp")) + require.Equal(t, `Response: + Height: 10 + TxHash: 74657374 + Code: 1 + Data: 64617461 + Raw Log: [] + Logs: [] + Info: info + GasWanted: 100 + GasUsed: 90 + Codespace: codespace + Timestamp: timestamp`, sdk.NewResponseResultTx(resultTx, sdk.Tx(nil), "timestamp").String()) + require.True(t, sdk.TxResponse{}.Empty()) + require.False(t, want.Empty()) + + resultBroadcastTx := &ctypes.ResultBroadcastTx{ + Code: 1, + Data: []byte("data"), + Log: `[]`, + Hash: bytes.HexBytes([]byte("test")), + } + require.Equal(t, sdk.TxResponse{ + Code: 1, + Data: "64617461", + RawLog: `[]`, + Logs: logs, + TxHash: "74657374", + }, sdk.NewResponseFormatBroadcastTx(resultBroadcastTx)) + require.Equal(t, sdk.TxResponse{}, sdk.NewResponseFormatBroadcastTx(nil)) +} + +func TestResponseFormatBroadcastTxCommit(t *testing.T) { + // test nil + require.Equal(t, sdk.TxResponse{}, sdk.NewResponseFormatBroadcastTxCommit(nil)) + + logs, err := sdk.ParseABCILogs(`[]`) + require.NoError(t, err) + + // test checkTx + checkTxResult := &ctypes.ResultBroadcastTxCommit{ + Height: 10, + Hash: bytes.HexBytes([]byte("test")), + CheckTx: abci.ResponseCheckTx{ + Code: 90, + Data: nil, + Log: `[]`, + Info: "info", + GasWanted: 99, + GasUsed: 100, + Codespace: "codespace", + }, + } + deliverTxResult := &ctypes.ResultBroadcastTxCommit{ + Height: 10, + Hash: bytes.HexBytes([]byte("test")), + DeliverTx: abci.ResponseDeliverTx{ + Code: 90, + Data: nil, + Log: `[]`, + Info: "info", + GasWanted: 99, + GasUsed: 100, + Codespace: "codespace", + }, + } + + want := sdk.TxResponse{ + Height: 10, + TxHash: "74657374", + Codespace: "codespace", + Code: 90, + Data: "", + RawLog: `[]`, + Logs: logs, + Info: "info", + GasWanted: 99, + GasUsed: 100, + } + require.Equal(t, want, sdk.NewResponseFormatBroadcastTxCommit(checkTxResult)) + require.Equal(t, want, sdk.NewResponseFormatBroadcastTxCommit(deliverTxResult)) +} diff --git a/types/staking_test.go b/types/staking_test.go new file mode 100644 index 000000000000..ddeab0d07036 --- /dev/null +++ b/types/staking_test.go @@ -0,0 +1,24 @@ +package types_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func TestBondStatus(t *testing.T) { + require.False(t, sdk.Unbonded.Equal(sdk.Bonded)) + require.False(t, sdk.Unbonded.Equal(sdk.Unbonding)) + require.False(t, sdk.Bonded.Equal(sdk.Unbonding)) + require.Panicsf(t, func() { sdk.BondStatus(0).String() }, "invalid bond status") + require.Equal(t, sdk.BondStatusUnbonded, sdk.BondStatus(sdk.Unbonded).String()) + require.Equal(t, sdk.BondStatusBonded, sdk.BondStatus(sdk.Bonded).String()) + require.Equal(t, sdk.BondStatusUnbonding, sdk.BondStatus(sdk.Unbonding).String()) +} + +func TestTokensToConsensusPower(t *testing.T) { + require.Equal(t, int64(0), sdk.TokensToConsensusPower(sdk.NewInt(999_999))) + require.Equal(t, int64(1), sdk.TokensToConsensusPower(sdk.NewInt(1_000_000))) +} diff --git a/types/store_test.go b/types/store_test.go index 06f609d17471..a4af3a663f65 100644 --- a/types/store_test.go +++ b/types/store_test.go @@ -1,9 +1,14 @@ -package types +package types_test import ( "testing" "github.com/stretchr/testify/require" + dbm "github.com/tendermint/tm-db" + + "github.com/cosmos/cosmos-sdk/store/rootmulti" + "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" ) func TestPrefixEndBytes(t *testing.T) { @@ -21,18 +26,99 @@ func TestPrefixEndBytes(t *testing.T) { } for _, test := range testCases { - end := PrefixEndBytes(test.prefix) + end := sdk.PrefixEndBytes(test.prefix) require.Equal(t, test.expected, end) } } func TestCommitID(t *testing.T) { - var empty CommitID + var empty sdk.CommitID require.True(t, empty.IsZero()) - var nonempty = CommitID{ + var nonempty = sdk.CommitID{ Version: 1, Hash: []byte("testhash"), } require.False(t, nonempty.IsZero()) } + +func TestNewKVStoreKeys(t *testing.T) { + t.Parallel() + require.Equal(t, map[string]*sdk.KVStoreKey{}, sdk.NewKVStoreKeys()) + require.Equal(t, 1, len(sdk.NewKVStoreKeys("one"))) +} + +func TestNewTransientStoreKeys(t *testing.T) { + t.Parallel() + require.Equal(t, map[string]*sdk.TransientStoreKey{}, sdk.NewTransientStoreKeys()) + require.Equal(t, 1, len(sdk.NewTransientStoreKeys("one"))) +} + +func TestNewInfiniteGasMeter(t *testing.T) { + t.Parallel() + gm := sdk.NewInfiniteGasMeter() + require.NotNil(t, gm) + _, ok := gm.(types.GasMeter) + require.True(t, ok) +} + +func TestStoreTypes(t *testing.T) { + t.Parallel() + require.Equal(t, sdk.InclusiveEndBytes([]byte("endbytes")), types.InclusiveEndBytes([]byte("endbytes"))) +} + +func TestDiffKVStores(t *testing.T) { + t.Parallel() + store1, store2 := initTestStores(t) + // Two equal stores + k1, v1 := []byte("k1"), []byte("v1") + store1.Set(k1, v1) + store2.Set(k1, v1) + + checkDiffResults(t, store1, store2) + + // delete k1 from store2, which is now empty + store2.Delete(k1) + checkDiffResults(t, store1, store2) + + // set k1 in store2, different value than what store1 holds for k1 + v2 := []byte("v2") + store2.Set(k1, v2) + checkDiffResults(t, store1, store2) + + // add k2 to store2 + k2 := []byte("k2") + store2.Set(k2, v2) + checkDiffResults(t, store1, store2) + + // Reset stores + store1.Delete(k1) + store2.Delete(k1) + store2.Delete(k2) + + // Same keys, different value. Comparisons will be nil as prefixes are skipped. + prefix := []byte("prefix:") + k1Prefixed := append(prefix, k1...) + store1.Set(k1Prefixed, v1) + store2.Set(k1Prefixed, v2) + checkDiffResults(t, store1, store2) +} + +func initTestStores(t *testing.T) (types.KVStore, types.KVStore) { + db := dbm.NewMemDB() + ms := rootmulti.NewStore(db) + + key1 := types.NewKVStoreKey("store1") + key2 := types.NewKVStoreKey("store2") + require.NotPanics(t, func() { ms.MountStoreWithDB(key1, types.StoreTypeIAVL, db) }) + require.NotPanics(t, func() { ms.MountStoreWithDB(key2, types.StoreTypeIAVL, db) }) + require.NoError(t, ms.LoadLatestVersion()) + return ms.GetKVStore(key1), ms.GetKVStore(key2) +} + +func checkDiffResults(t *testing.T, store1, store2 types.KVStore) { + kvAs1, kvBs1 := sdk.DiffKVStores(store1, store2, nil) + kvAs2, kvBs2 := types.DiffKVStores(store1, store2, nil) + require.Equal(t, kvAs1, kvAs2) + require.Equal(t, kvBs1, kvBs2) +} diff --git a/types/tx_msg_test.go b/types/tx_msg_test.go new file mode 100644 index 000000000000..5023cbec575a --- /dev/null +++ b/types/tx_msg_test.go @@ -0,0 +1,23 @@ +package types_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func TestTestMsg(t *testing.T) { + t.Parallel() + addr := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} + accAddr := sdk.AccAddress(addr) + + msg := sdk.NewTestMsg(accAddr) + require.NotNil(t, msg) + require.Equal(t, "TestMsg", msg.Route()) + require.Equal(t, "Test message", msg.Type()) + require.Nil(t, msg.ValidateBasic()) + require.NotPanics(t, func() { msg.GetSignBytes() }) + require.Equal(t, []sdk.AccAddress{accAddr}, msg.GetSigners()) +} diff --git a/types/uint_test.go b/types/uint_test.go index 548dea5064eb..5f496b5c83d2 100644 --- a/types/uint_test.go +++ b/types/uint_test.go @@ -287,3 +287,15 @@ func TestRelativePow(t *testing.T) { require.Equal(t, tc.want, res, "unexpected result for test case %d, input: %v, got: %v", i, tc.args, res) } } + +func TestUintSize(t *testing.T) { + x := Uint{i: nil} + require.Equal(t, 1, x.Size()) + x = NewUint(0) + require.Equal(t, 1, x.Size()) + x = NewUint(10) + require.Equal(t, 2, x.Size()) + x = NewUint(100) + require.Equal(t, 3, x.Size()) + +} diff --git a/types/utils_test.go b/types/utils_test.go index 6aa652220e55..4ffc67c6101c 100644 --- a/types/utils_test.go +++ b/types/utils_test.go @@ -1,4 +1,4 @@ -package types +package types_test import ( "bytes" @@ -6,6 +6,8 @@ import ( "time" "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" ) func TestSortJSON(t *testing.T) { @@ -33,14 +35,14 @@ func TestSortJSON(t *testing.T) { for tcIndex, tc := range cases { tc := tc - got, err := SortJSON([]byte(tc.unsortedJSON)) + got, err := sdk.SortJSON([]byte(tc.unsortedJSON)) if tc.wantErr { require.NotNil(t, err, "tc #%d", tcIndex) - require.Panics(t, func() { MustSortJSON([]byte(tc.unsortedJSON)) }) + require.Panics(t, func() { sdk.MustSortJSON([]byte(tc.unsortedJSON)) }) } else { require.Nil(t, err, "tc #%d, err=%s", tcIndex, err) - require.NotPanics(t, func() { MustSortJSON([]byte(tc.unsortedJSON)) }) - require.Equal(t, got, MustSortJSON([]byte(tc.unsortedJSON))) + require.NotPanics(t, func() { sdk.MustSortJSON([]byte(tc.unsortedJSON)) }) + require.Equal(t, got, sdk.MustSortJSON([]byte(tc.unsortedJSON))) } require.Equal(t, string(got), tc.want) @@ -60,19 +62,42 @@ func TestTimeFormatAndParse(t *testing.T) { tc := tc timeFromRFC, err := time.Parse(time.RFC3339Nano, tc.RFC3339NanoStr) require.Nil(t, err) - timeFromSDKFormat, err := time.Parse(SortableTimeFormat, tc.SDKSortableTimeStr) + timeFromSDKFormat, err := time.Parse(sdk.SortableTimeFormat, tc.SDKSortableTimeStr) require.Nil(t, err) require.True(t, timeFromRFC.Equal(timeFromSDKFormat)) - require.Equal(t, timeFromRFC.Format(SortableTimeFormat), tc.SDKSortableTimeStr) + require.Equal(t, timeFromRFC.Format(sdk.SortableTimeFormat), tc.SDKSortableTimeStr) } } func TestCopyBytes(t *testing.T) { t.Parallel() - require.Nil(t, CopyBytes(nil)) - require.Equal(t, 0, len(CopyBytes([]byte{}))) + require.Nil(t, sdk.CopyBytes(nil)) + require.Equal(t, 0, len(sdk.CopyBytes([]byte{}))) bs := []byte("test") - bsCopy := CopyBytes(bs) + bsCopy := sdk.CopyBytes(bs) require.True(t, bytes.Equal(bs, bsCopy)) } + +func TestUint64ToBigEndian(t *testing.T) { + t.Parallel() + require.Equal(t, []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, sdk.Uint64ToBigEndian(uint64(0))) + require.Equal(t, []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa}, sdk.Uint64ToBigEndian(uint64(10))) +} + +func TestFormatTimeBytes(t *testing.T) { + t.Parallel() + tm, err := time.Parse("Jan 2, 2006 at 3:04pm (MST)", "Mar 3, 2020 at 7:54pm (PST)") + require.NoError(t, err) + require.Equal(t, "2020-03-03T19:54:00.000000000", string(sdk.FormatTimeBytes(tm))) +} + +func TestParseTimeBytes(t *testing.T) { + t.Parallel() + tm, err := sdk.ParseTimeBytes([]byte("2020-03-03T19:54:00.000000000")) + require.NoError(t, err) + require.True(t, tm.Equal(time.Date(2020, 3, 3, 19, 54, 0, 0, time.UTC))) + + _, err = sdk.ParseTimeBytes([]byte{}) + require.Error(t, err) +} From e01c99d0199f950fc33ee6c7454cc5d5563ff0f2 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Thu, 5 Mar 2020 11:45:51 +0100 Subject: [PATCH 363/529] now it creates the module account on InitChain --- simapp/app.go | 4 ++-- x/mint/genesis.go | 5 ++++- x/mint/module.go | 12 +++++++++--- x/mint/module_test.go | 29 +++++++++++++++++++++++++++++ x/mint/types/expected_keepers.go | 1 + 5 files changed, 45 insertions(+), 6 deletions(-) create mode 100644 x/mint/module_test.go diff --git a/simapp/app.go b/simapp/app.go index 5408bcfe919e..56aaae8d8459 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -226,7 +226,7 @@ func NewSimApp( crisis.NewAppModule(&app.CrisisKeeper), supply.NewAppModule(app.SupplyKeeper, app.BankKeeper, app.AccountKeeper), gov.NewAppModule(app.GovKeeper, app.AccountKeeper, app.BankKeeper, app.SupplyKeeper), - mint.NewAppModule(app.MintKeeper), + mint.NewAppModule(app.MintKeeper, app.SupplyKeeper), slashing.NewAppModule(app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper), distr.NewAppModule(app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.SupplyKeeper, app.StakingKeeper), staking.NewAppModule(app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.SupplyKeeper), @@ -260,7 +260,7 @@ func NewSimApp( bank.NewAppModule(app.BankKeeper, app.AccountKeeper), supply.NewAppModule(app.SupplyKeeper, app.BankKeeper, app.AccountKeeper), gov.NewAppModule(app.GovKeeper, app.AccountKeeper, app.BankKeeper, app.SupplyKeeper), - mint.NewAppModule(app.MintKeeper), + mint.NewAppModule(app.MintKeeper, app.SupplyKeeper), staking.NewAppModule(app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.SupplyKeeper), distr.NewAppModule(app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.SupplyKeeper, app.StakingKeeper), slashing.NewAppModule(app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper), diff --git a/x/mint/genesis.go b/x/mint/genesis.go index 331852b43550..44e0a5ee130f 100644 --- a/x/mint/genesis.go +++ b/x/mint/genesis.go @@ -2,12 +2,15 @@ package mint import ( sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/mint/types" ) // InitGenesis new mint genesis -func InitGenesis(ctx sdk.Context, keeper Keeper, data GenesisState) { +func InitGenesis(ctx sdk.Context, keeper Keeper, supplyKeeper types.SupplyKeeper, data GenesisState) { keeper.SetMinter(ctx, data.Minter) keeper.SetParams(ctx, data.Params) + + supplyKeeper.GetModuleAccount(ctx, ModuleName) } // ExportGenesis returns a GenesisState for a given context and keeper. diff --git a/x/mint/module.go b/x/mint/module.go index 53bd8fff13a6..88c03dfea20d 100644 --- a/x/mint/module.go +++ b/x/mint/module.go @@ -5,6 +5,8 @@ import ( "fmt" "math/rand" + "github.com/cosmos/cosmos-sdk/x/mint/types" + "github.com/gorilla/mux" "github.com/spf13/cobra" @@ -74,14 +76,16 @@ func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command { type AppModule struct { AppModuleBasic - keeper Keeper + keeper Keeper + supplyKeeper types.SupplyKeeper } // NewAppModule creates a new AppModule object -func NewAppModule(keeper Keeper) AppModule { +func NewAppModule(keeper Keeper, supplyKeeper types.SupplyKeeper) AppModule { return AppModule{ AppModuleBasic: AppModuleBasic{}, keeper: keeper, + supplyKeeper: supplyKeeper, } } @@ -114,7 +118,9 @@ func (am AppModule) NewQuerierHandler() sdk.Querier { func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data json.RawMessage) []abci.ValidatorUpdate { var genesisState GenesisState cdc.MustUnmarshalJSON(data, &genesisState) - InitGenesis(ctx, am.keeper, genesisState) + + InitGenesis(ctx, am.keeper, am.supplyKeeper, genesisState) + return []abci.ValidatorUpdate{} } diff --git a/x/mint/module_test.go b/x/mint/module_test.go new file mode 100644 index 000000000000..448d2f6b0d95 --- /dev/null +++ b/x/mint/module_test.go @@ -0,0 +1,29 @@ +package mint_test + +import ( + "testing" + + "github.com/cosmos/cosmos-sdk/x/mint" + "github.com/cosmos/cosmos-sdk/x/supply" + "github.com/stretchr/testify/assert" + + "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/simapp" +) + +func TestItCreatesModuleAccountOnInitBlock(t *testing.T) { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, types.Header{}) + + app.InitChain( + types.RequestInitChain{ + AppStateBytes: []byte("{}"), + ChainId: "test-chain-id", + }, + ) + + acc := app.AccountKeeper.GetAccount(ctx, supply.NewModuleAddress(mint.ModuleName)) + + assert.NotNil(t, acc) +} diff --git a/x/mint/types/expected_keepers.go b/x/mint/types/expected_keepers.go index ea20619164d3..104a2860298d 100644 --- a/x/mint/types/expected_keepers.go +++ b/x/mint/types/expected_keepers.go @@ -17,6 +17,7 @@ type SupplyKeeper interface { // TODO remove with genesis 2-phases refactor https://github.com/cosmos/cosmos-sdk/issues/2862 SetModuleAccount(sdk.Context, exported.ModuleAccountI) + GetModuleAccount(ctx sdk.Context, moduleName string) exported.ModuleAccountI SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error SendCoinsFromModuleToModule(ctx sdk.Context, senderModule, recipientModule string, amt sdk.Coins) error From 29abc244eb9a8c7407871b0b5481fda8c7f7464f Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Thu, 5 Mar 2020 11:56:39 +0100 Subject: [PATCH 364/529] make private methods that does not need to be exported --- x/mint/abci.go | 2 +- x/mint/genesis.go | 8 ++++---- x/mint/module.go | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/x/mint/abci.go b/x/mint/abci.go index 21595b466f98..6d77dcc023b3 100644 --- a/x/mint/abci.go +++ b/x/mint/abci.go @@ -6,7 +6,7 @@ import ( ) // BeginBlocker mints new tokens for the previous block. -func BeginBlocker(ctx sdk.Context, k Keeper) { +func beginBlocker(ctx sdk.Context, k Keeper) { // fetch stored minter & params minter := k.GetMinter(ctx) params := k.GetParams(ctx) diff --git a/x/mint/genesis.go b/x/mint/genesis.go index 44e0a5ee130f..fb07680d33cb 100644 --- a/x/mint/genesis.go +++ b/x/mint/genesis.go @@ -5,16 +5,16 @@ import ( "github.com/cosmos/cosmos-sdk/x/mint/types" ) -// InitGenesis new mint genesis -func InitGenesis(ctx sdk.Context, keeper Keeper, supplyKeeper types.SupplyKeeper, data GenesisState) { +// initGenesis new mint genesis +func initGenesis(ctx sdk.Context, keeper Keeper, supplyKeeper types.SupplyKeeper, data GenesisState) { keeper.SetMinter(ctx, data.Minter) keeper.SetParams(ctx, data.Params) supplyKeeper.GetModuleAccount(ctx, ModuleName) } -// ExportGenesis returns a GenesisState for a given context and keeper. -func ExportGenesis(ctx sdk.Context, keeper Keeper) GenesisState { +// exportGenesis returns a GenesisState for a given context and keeper. +func exportGenesis(ctx sdk.Context, keeper Keeper) GenesisState { minter := keeper.GetMinter(ctx) params := keeper.GetParams(ctx) return NewGenesisState(minter, params) diff --git a/x/mint/module.go b/x/mint/module.go index 88c03dfea20d..8e9ca590c3d2 100644 --- a/x/mint/module.go +++ b/x/mint/module.go @@ -119,7 +119,7 @@ func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data j var genesisState GenesisState cdc.MustUnmarshalJSON(data, &genesisState) - InitGenesis(ctx, am.keeper, am.supplyKeeper, genesisState) + initGenesis(ctx, am.keeper, am.supplyKeeper, genesisState) return []abci.ValidatorUpdate{} } @@ -127,13 +127,13 @@ func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data j // ExportGenesis returns the exported genesis state as raw bytes for the mint // module. func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json.RawMessage { - gs := ExportGenesis(ctx, am.keeper) + gs := exportGenesis(ctx, am.keeper) return cdc.MustMarshalJSON(gs) } // BeginBlock returns the begin blocker for the mint module. func (am AppModule) BeginBlock(ctx sdk.Context, _ abci.RequestBeginBlock) { - BeginBlocker(ctx, am.keeper) + beginBlocker(ctx, am.keeper) } // EndBlock returns the end blocker for the mint module. It returns no validator From 626cc1973d7f4a0f92c737d173c087c73044c165 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Thu, 5 Mar 2020 12:17:18 +0100 Subject: [PATCH 365/529] update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 19934bee5193..856528154a21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -62,6 +62,8 @@ and provided directly the IAVL store. * (types) [\#5533](https://github.com/cosmos/cosmos-sdk/pull/5533) Refactored `AppModuleBasic` and `AppModuleGenesis` to now accept a `codec.JSONMarshaler` for modular serialization of genesis state. * (crypto/keys) [\#5735](https://github.com/cosmos/cosmos-sdk/pull/5735) Keyring's Update() function is now no-op. +* (x/mint) [\#5569](https://github.com/cosmos/cosmos-sdk/issues/5569) `AppModule` now requires SupplyKeeper in its constructor to create +module account on `InitGenesis`. ### Features From ccb0062560e737bec3c1d83b45726ea0c688c88f Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Thu, 5 Mar 2020 12:18:04 +0100 Subject: [PATCH 366/529] update changelog --- x/mint/abci.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/mint/abci.go b/x/mint/abci.go index 6d77dcc023b3..c87f8ef2d661 100644 --- a/x/mint/abci.go +++ b/x/mint/abci.go @@ -5,7 +5,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/mint/types" ) -// BeginBlocker mints new tokens for the previous block. +// beginBlocker mints new tokens for the previous block. func beginBlocker(ctx sdk.Context, k Keeper) { // fetch stored minter & params minter := k.GetMinter(ctx) From 9acd722db2ccd41e6a5c9fa75c037d21b9f84b76 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Thu, 5 Mar 2020 14:00:45 +0000 Subject: [PATCH 367/529] x/distribution: simapp for testing (#5725) * migrate first distribution test to use simapp * refactor test TestAllocateTokensTruncation * migrate allocation test for distribution * migrate TestCalculateRewardsBasic to simapp in distribution * migrate TestCalculateRewardsAfterSlash to simapp in distribution * migrate TestCalculateRewardsAfterManySlashes to use simapp * migrate TestCalculateRewardsMultiDelegator to use ssimapp * migrate TestWithdrawDelegationRewardsBasic to simapp * migrate TestCalculateRewardsAfterManySlashesInSameBlock to simapp * migrate TestCalculateRewardsMultiDelegatorMultiSlash * migrate old delegation test * migrate keeper test to simapp * refactor all distribution to use simapp Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> --- x/distribution/alias.go | 3 - x/distribution/keeper/allocation_test.go | 117 ++++---- x/distribution/keeper/common_test.go | 21 ++ x/distribution/keeper/delegation.go | 6 +- x/distribution/keeper/delegation_test.go | 341 +++++++++++++---------- x/distribution/keeper/hooks.go | 2 +- x/distribution/keeper/keeper_test.go | 76 ++--- x/distribution/keeper/querier.go | 8 +- x/distribution/keeper/querier_test.go | 39 +-- x/distribution/keeper/test_common.go | 178 ------------ x/distribution/keeper/validator.go | 4 +- x/distribution/proposal_handler_test.go | 47 ++-- 12 files changed, 384 insertions(+), 458 deletions(-) create mode 100644 x/distribution/keeper/common_test.go delete mode 100644 x/distribution/keeper/test_common.go diff --git a/x/distribution/alias.go b/x/distribution/alias.go index 47143d995cbb..838bcc63397a 100644 --- a/x/distribution/alias.go +++ b/x/distribution/alias.go @@ -55,9 +55,6 @@ var ( GetValidatorSlashEventKey = types.GetValidatorSlashEventKey HandleCommunityPoolSpendProposal = keeper.HandleCommunityPoolSpendProposal NewQuerier = keeper.NewQuerier - MakeTestCodec = keeper.MakeTestCodec - CreateTestInputDefault = keeper.CreateTestInputDefault - CreateTestInputAdvanced = keeper.CreateTestInputAdvanced ParamKeyTable = types.ParamKeyTable DefaultParams = types.DefaultParams RegisterCodec = types.RegisterCodec diff --git a/x/distribution/keeper/allocation_test.go b/x/distribution/keeper/allocation_test.go index 9628b74597fa..df49fcd7b269 100644 --- a/x/distribution/keeper/allocation_test.go +++ b/x/distribution/keeper/allocation_test.go @@ -1,23 +1,31 @@ -package keeper +package keeper_test import ( "testing" "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/cosmos/cosmos-sdk/x/staking" ) func TestAllocateTokensToValidatorWithCommission(t *testing.T) { - ctx, _, _, k, sk, _ := CreateTestInputDefault(t, false, 1000) - sh := staking.NewHandler(sk) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + addrs := simapp.AddTestAddrs(app, ctx, 3, sdk.NewInt(1234)) + valAddrs := simapp.ConvertAddrsToValAddrs(addrs) + + sh := staking.NewHandler(app.StakingKeeper) // create validator with 50% commission commission := staking.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0)) msg := staking.NewMsgCreateValidator( - valOpAddr1, valConsPk1, + sdk.ValAddress(addrs[0]), valConsPk1, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), staking.Description{}, commission, sdk.OneInt(), ) @@ -25,31 +33,35 @@ func TestAllocateTokensToValidatorWithCommission(t *testing.T) { require.NoError(t, err) require.NotNil(t, res) - val := sk.Validator(ctx, valOpAddr1) + val := app.StakingKeeper.Validator(ctx, valAddrs[0]) // allocate tokens tokens := sdk.DecCoins{ {Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(10)}, } - k.AllocateTokensToValidator(ctx, val, tokens) + app.DistrKeeper.AllocateTokensToValidator(ctx, val, tokens) // check commission expected := sdk.DecCoins{ {Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(5)}, } - require.Equal(t, expected, k.GetValidatorAccumulatedCommission(ctx, val.GetOperator()).Commission) + require.Equal(t, expected, app.DistrKeeper.GetValidatorAccumulatedCommission(ctx, val.GetOperator()).Commission) // check current rewards - require.Equal(t, expected, k.GetValidatorCurrentRewards(ctx, val.GetOperator()).Rewards) + require.Equal(t, expected, app.DistrKeeper.GetValidatorCurrentRewards(ctx, val.GetOperator()).Rewards) } func TestAllocateTokensToManyValidators(t *testing.T) { - ctx, ak, bk, k, sk, supplyKeeper := CreateTestInputDefault(t, false, 1000) - sh := staking.NewHandler(sk) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + sh := staking.NewHandler(app.StakingKeeper) + addrs := simapp.AddTestAddrs(app, ctx, 2, sdk.NewInt(1234)) + valAddrs := simapp.ConvertAddrsToValAddrs(addrs) // create validator with 50% commission commission := staking.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0)) - msg := staking.NewMsgCreateValidator(valOpAddr1, valConsPk1, + msg := staking.NewMsgCreateValidator(valAddrs[0], valConsPk1, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), staking.Description{}, commission, sdk.OneInt()) res, err := sh(ctx, msg) @@ -58,7 +70,7 @@ func TestAllocateTokensToManyValidators(t *testing.T) { // create second validator with 0% commission commission = staking.NewCommissionRates(sdk.NewDec(0), sdk.NewDec(0), sdk.NewDec(0)) - msg = staking.NewMsgCreateValidator(valOpAddr2, valConsPk2, + msg = staking.NewMsgCreateValidator(valAddrs[1], valConsPk2, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), staking.Description{}, commission, sdk.OneInt()) res, err = sh(ctx, msg) @@ -75,22 +87,22 @@ func TestAllocateTokensToManyValidators(t *testing.T) { } // assert initial state: zero outstanding rewards, zero community pool, zero commission, zero current rewards - require.True(t, k.GetValidatorOutstandingRewards(ctx, valOpAddr1).Rewards.IsZero()) - require.True(t, k.GetValidatorOutstandingRewards(ctx, valOpAddr2).Rewards.IsZero()) - require.True(t, k.GetFeePool(ctx).CommunityPool.IsZero()) - require.True(t, k.GetValidatorAccumulatedCommission(ctx, valOpAddr1).Commission.IsZero()) - require.True(t, k.GetValidatorAccumulatedCommission(ctx, valOpAddr2).Commission.IsZero()) - require.True(t, k.GetValidatorCurrentRewards(ctx, valOpAddr1).Rewards.IsZero()) - require.True(t, k.GetValidatorCurrentRewards(ctx, valOpAddr2).Rewards.IsZero()) + require.True(t, app.DistrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[0]).Rewards.IsZero()) + require.True(t, app.DistrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[1]).Rewards.IsZero()) + require.True(t, app.DistrKeeper.GetFeePool(ctx).CommunityPool.IsZero()) + require.True(t, app.DistrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission.IsZero()) + require.True(t, app.DistrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[1]).Commission.IsZero()) + require.True(t, app.DistrKeeper.GetValidatorCurrentRewards(ctx, valAddrs[0]).Rewards.IsZero()) + require.True(t, app.DistrKeeper.GetValidatorCurrentRewards(ctx, valAddrs[1]).Rewards.IsZero()) // allocate tokens as if both had voted and second was proposer fees := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))) - feeCollector := supplyKeeper.GetModuleAccount(ctx, k.feeCollectorName) + feeCollector := app.SupplyKeeper.GetModuleAccount(ctx, types.FeeCollectorName) require.NotNil(t, feeCollector) - err = bk.SetBalances(ctx, feeCollector.GetAddress(), fees) + err = app.BankKeeper.SetBalances(ctx, feeCollector.GetAddress(), fees) require.NoError(t, err) - ak.SetAccount(ctx, feeCollector) + app.AccountKeeper.SetAccount(ctx, feeCollector) votes := []abci.VoteInfo{ { @@ -102,31 +114,34 @@ func TestAllocateTokensToManyValidators(t *testing.T) { SignedLastBlock: true, }, } - k.AllocateTokens(ctx, 200, 200, valConsAddr2, votes) + app.DistrKeeper.AllocateTokens(ctx, 200, 200, valConsAddr2, votes) // 98 outstanding rewards (100 less 2 to community pool) - require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecWithPrec(465, 1)}}, k.GetValidatorOutstandingRewards(ctx, valOpAddr1).Rewards) - require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecWithPrec(515, 1)}}, k.GetValidatorOutstandingRewards(ctx, valOpAddr2).Rewards) + require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecWithPrec(465, 1)}}, app.DistrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[0]).Rewards) + require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecWithPrec(515, 1)}}, app.DistrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[1]).Rewards) // 2 community pool coins - require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(2)}}, k.GetFeePool(ctx).CommunityPool) + require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(2)}}, app.DistrKeeper.GetFeePool(ctx).CommunityPool) // 50% commission for first proposer, (0.5 * 93%) * 100 / 2 = 23.25 - require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecWithPrec(2325, 2)}}, k.GetValidatorAccumulatedCommission(ctx, valOpAddr1).Commission) + require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecWithPrec(2325, 2)}}, app.DistrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission) // zero commission for second proposer - require.True(t, k.GetValidatorAccumulatedCommission(ctx, valOpAddr2).Commission.IsZero()) + require.True(t, app.DistrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[1]).Commission.IsZero()) // just staking.proportional for first proposer less commission = (0.5 * 93%) * 100 / 2 = 23.25 - require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecWithPrec(2325, 2)}}, k.GetValidatorCurrentRewards(ctx, valOpAddr1).Rewards) + require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecWithPrec(2325, 2)}}, app.DistrKeeper.GetValidatorCurrentRewards(ctx, valAddrs[0]).Rewards) // proposer reward + staking.proportional for second proposer = (5 % + 0.5 * (93%)) * 100 = 51.5 - require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecWithPrec(515, 1)}}, k.GetValidatorCurrentRewards(ctx, valOpAddr2).Rewards) + require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecWithPrec(515, 1)}}, app.DistrKeeper.GetValidatorCurrentRewards(ctx, valAddrs[1]).Rewards) } func TestAllocateTokensTruncation(t *testing.T) { - communityTax := sdk.NewDec(0) - ctx, ak, bk, k, sk, _, supplyKeeper := CreateTestInputAdvanced(t, false, 1000000, communityTax) - sh := staking.NewHandler(sk) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + addrs := simapp.AddTestAddrs(app, ctx, 3, sdk.NewInt(1234)) + valAddrs := simapp.ConvertAddrsToValAddrs(addrs) + sh := staking.NewHandler(app.StakingKeeper) // create validator with 10% commission commission := staking.NewCommissionRates(sdk.NewDecWithPrec(1, 1), sdk.NewDecWithPrec(1, 1), sdk.NewDec(0)) - msg := staking.NewMsgCreateValidator(valOpAddr1, valConsPk1, + msg := staking.NewMsgCreateValidator(valAddrs[0], valConsPk1, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(110)), staking.Description{}, commission, sdk.OneInt()) res, err := sh(ctx, msg) require.NoError(t, err) @@ -134,7 +149,7 @@ func TestAllocateTokensTruncation(t *testing.T) { // create second validator with 10% commission commission = staking.NewCommissionRates(sdk.NewDecWithPrec(1, 1), sdk.NewDecWithPrec(1, 1), sdk.NewDec(0)) - msg = staking.NewMsgCreateValidator(valOpAddr2, valConsPk2, + msg = staking.NewMsgCreateValidator(valAddrs[1], valConsPk2, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), staking.Description{}, commission, sdk.OneInt()) res, err = sh(ctx, msg) require.NoError(t, err) @@ -142,7 +157,7 @@ func TestAllocateTokensTruncation(t *testing.T) { // create third validator with 10% commission commission = staking.NewCommissionRates(sdk.NewDecWithPrec(1, 1), sdk.NewDecWithPrec(1, 1), sdk.NewDec(0)) - msg = staking.NewMsgCreateValidator(valOpAddr3, valConsPk3, + msg = staking.NewMsgCreateValidator(valAddrs[2], valConsPk3, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), staking.Description{}, commission, sdk.OneInt()) res, err = sh(ctx, msg) require.NoError(t, err) @@ -162,25 +177,25 @@ func TestAllocateTokensTruncation(t *testing.T) { } // assert initial state: zero outstanding rewards, zero community pool, zero commission, zero current rewards - require.True(t, k.GetValidatorOutstandingRewards(ctx, valOpAddr1).Rewards.IsZero()) - require.True(t, k.GetValidatorOutstandingRewards(ctx, valOpAddr2).Rewards.IsZero()) - require.True(t, k.GetValidatorOutstandingRewards(ctx, valOpAddr3).Rewards.IsZero()) - require.True(t, k.GetFeePool(ctx).CommunityPool.IsZero()) - require.True(t, k.GetValidatorAccumulatedCommission(ctx, valOpAddr1).Commission.IsZero()) - require.True(t, k.GetValidatorAccumulatedCommission(ctx, valOpAddr2).Commission.IsZero()) - require.True(t, k.GetValidatorCurrentRewards(ctx, valOpAddr1).Rewards.IsZero()) - require.True(t, k.GetValidatorCurrentRewards(ctx, valOpAddr2).Rewards.IsZero()) + require.True(t, app.DistrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[0]).Rewards.IsZero()) + require.True(t, app.DistrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[1]).Rewards.IsZero()) + require.True(t, app.DistrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[1]).Rewards.IsZero()) + require.True(t, app.DistrKeeper.GetFeePool(ctx).CommunityPool.IsZero()) + require.True(t, app.DistrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission.IsZero()) + require.True(t, app.DistrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[1]).Commission.IsZero()) + require.True(t, app.DistrKeeper.GetValidatorCurrentRewards(ctx, valAddrs[0]).Rewards.IsZero()) + require.True(t, app.DistrKeeper.GetValidatorCurrentRewards(ctx, valAddrs[1]).Rewards.IsZero()) // allocate tokens as if both had voted and second was proposer fees := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(634195840))) - feeCollector := supplyKeeper.GetModuleAccount(ctx, k.feeCollectorName) + feeCollector := app.SupplyKeeper.GetModuleAccount(ctx, types.FeeCollectorName) require.NotNil(t, feeCollector) - err = bk.SetBalances(ctx, feeCollector.GetAddress(), fees) + err = app.BankKeeper.SetBalances(ctx, feeCollector.GetAddress(), fees) require.NoError(t, err) - ak.SetAccount(ctx, feeCollector) + app.AccountKeeper.SetAccount(ctx, feeCollector) votes := []abci.VoteInfo{ { @@ -196,9 +211,9 @@ func TestAllocateTokensTruncation(t *testing.T) { SignedLastBlock: true, }, } - k.AllocateTokens(ctx, 31, 31, valConsAddr2, votes) + app.DistrKeeper.AllocateTokens(ctx, 31, 31, sdk.ConsAddress(valConsPk2.Address()), votes) - require.True(t, k.GetValidatorOutstandingRewards(ctx, valOpAddr1).Rewards.IsValid()) - require.True(t, k.GetValidatorOutstandingRewards(ctx, valOpAddr2).Rewards.IsValid()) - require.True(t, k.GetValidatorOutstandingRewards(ctx, valOpAddr3).Rewards.IsValid()) + require.True(t, app.DistrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[0]).Rewards.IsValid()) + require.True(t, app.DistrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[1]).Rewards.IsValid()) + require.True(t, app.DistrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[2]).Rewards.IsValid()) } diff --git a/x/distribution/keeper/common_test.go b/x/distribution/keeper/common_test.go new file mode 100644 index 000000000000..c27d7adf8d57 --- /dev/null +++ b/x/distribution/keeper/common_test.go @@ -0,0 +1,21 @@ +package keeper_test + +import ( + "github.com/cosmos/cosmos-sdk/simapp" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/distribution/types" + "github.com/cosmos/cosmos-sdk/x/supply" +) + +var ( + PKS = simapp.CreateTestPubKeys(5) + + valConsPk1 = PKS[0] + valConsPk2 = PKS[1] + valConsPk3 = PKS[2] + + valConsAddr1 = sdk.ConsAddress(valConsPk1.Address()) + valConsAddr2 = sdk.ConsAddress(valConsPk2.Address()) + + distrAcc = supply.NewEmptyModuleAccount(types.ModuleName) +) diff --git a/x/distribution/keeper/delegation.go b/x/distribution/keeper/delegation.go index 48f474e5c570..132165742c08 100644 --- a/x/distribution/keeper/delegation.go +++ b/x/distribution/keeper/delegation.go @@ -53,7 +53,7 @@ func (k Keeper) calculateDelegationRewardsBetween(ctx sdk.Context, val exported. } // calculate the total rewards accrued by a delegation -func (k Keeper) calculateDelegationRewards(ctx sdk.Context, val exported.ValidatorI, del exported.DelegationI, endingPeriod uint64) (rewards sdk.DecCoins) { +func (k Keeper) CalculateDelegationRewards(ctx sdk.Context, val exported.ValidatorI, del exported.DelegationI, endingPeriod uint64) (rewards sdk.DecCoins) { // fetch starting info for delegation startingInfo := k.GetDelegatorStartingInfo(ctx, del.GetValidatorAddr(), del.GetDelegatorAddr()) @@ -143,8 +143,8 @@ func (k Keeper) withdrawDelegationRewards(ctx sdk.Context, val exported.Validato } // end current period and calculate rewards - endingPeriod := k.incrementValidatorPeriod(ctx, val) - rewardsRaw := k.calculateDelegationRewards(ctx, val, del, endingPeriod) + endingPeriod := k.IncrementValidatorPeriod(ctx, val) + rewardsRaw := k.CalculateDelegationRewards(ctx, val, del, endingPeriod) outstanding := k.GetValidatorOutstandingRewardsCoins(ctx, del.GetValidatorAddr()) // defensive edge case may happen on the very final digits diff --git a/x/distribution/keeper/delegation_test.go b/x/distribution/keeper/delegation_test.go index a297eb5ba3a1..149a14913203 100644 --- a/x/distribution/keeper/delegation_test.go +++ b/x/distribution/keeper/delegation_test.go @@ -1,22 +1,29 @@ -package keeper +package keeper_test import ( "testing" - "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/staking" + "github.com/stretchr/testify/require" ) func TestCalculateRewardsBasic(t *testing.T) { - ctx, _, _, k, sk, _ := CreateTestInputDefault(t, false, 1000) - sh := staking.NewHandler(sk) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + sh := staking.NewHandler(app.StakingKeeper) + + addr := simapp.AddTestAddrs(app, ctx, 2, sdk.NewInt(1000)) + valAddrs := simapp.ConvertAddrsToValAddrs(addr) // create validator with 50% commission commission := staking.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0)) msg := staking.NewMsgCreateValidator( - valOpAddr1, valConsPk1, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), staking.Description{}, commission, sdk.OneInt(), + valAddrs[0], valConsPk1, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), staking.Description{}, commission, sdk.OneInt(), ) res, err := sh(ctx, msg) @@ -24,26 +31,26 @@ func TestCalculateRewardsBasic(t *testing.T) { require.NotNil(t, res) // end block to bond validator - staking.EndBlocker(ctx, sk) + staking.EndBlocker(ctx, app.StakingKeeper) // next block ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) // fetch validator and delegation - val := sk.Validator(ctx, valOpAddr1) - del := sk.Delegation(ctx, sdk.AccAddress(valOpAddr1), valOpAddr1) + val := app.StakingKeeper.Validator(ctx, valAddrs[0]) + del := app.StakingKeeper.Delegation(ctx, sdk.AccAddress(valAddrs[0]), valAddrs[0]) // historical count should be 2 (once for validator init, once for delegation init) - require.Equal(t, uint64(2), k.GetValidatorHistoricalReferenceCount(ctx)) + require.Equal(t, uint64(2), app.DistrKeeper.GetValidatorHistoricalReferenceCount(ctx)) // end period - endingPeriod := k.incrementValidatorPeriod(ctx, val) + endingPeriod := app.DistrKeeper.IncrementValidatorPeriod(ctx, val) // historical count should be 2 still - require.Equal(t, uint64(2), k.GetValidatorHistoricalReferenceCount(ctx)) + require.Equal(t, uint64(2), app.DistrKeeper.GetValidatorHistoricalReferenceCount(ctx)) // calculate delegation rewards - rewards := k.calculateDelegationRewards(ctx, val, del, endingPeriod) + rewards := app.DistrKeeper.CalculateDelegationRewards(ctx, val, del, endingPeriod) // rewards should be zero require.True(t, rewards.IsZero()) @@ -51,30 +58,35 @@ func TestCalculateRewardsBasic(t *testing.T) { // allocate some rewards initial := int64(10) tokens := sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(initial)}} - k.AllocateTokensToValidator(ctx, val, tokens) + app.DistrKeeper.AllocateTokensToValidator(ctx, val, tokens) // end period - endingPeriod = k.incrementValidatorPeriod(ctx, val) + endingPeriod = app.DistrKeeper.IncrementValidatorPeriod(ctx, val) // calculate delegation rewards - rewards = k.calculateDelegationRewards(ctx, val, del, endingPeriod) + rewards = app.DistrKeeper.CalculateDelegationRewards(ctx, val, del, endingPeriod) // rewards should be half the tokens require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(initial / 2)}}, rewards) // commission should be the other half - require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(initial / 2)}}, k.GetValidatorAccumulatedCommission(ctx, valOpAddr1).Commission) + require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(initial / 2)}}, app.DistrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission) } func TestCalculateRewardsAfterSlash(t *testing.T) { - ctx, _, _, k, sk, _ := CreateTestInputDefault(t, false, 1000) - sh := staking.NewHandler(sk) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + addr := simapp.AddTestAddrs(app, ctx, 2, sdk.NewInt(100000000)) + valAddrs := simapp.ConvertAddrsToValAddrs(addr) + + sh := staking.NewHandler(app.StakingKeeper) // create validator with 50% commission commission := staking.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0)) valPower := int64(100) valTokens := sdk.TokensFromConsensusPower(valPower) - msg := staking.NewMsgCreateValidator(valOpAddr1, valConsPk1, + msg := staking.NewMsgCreateValidator(valAddrs[0], valConsPk1, sdk.NewCoin(sdk.DefaultBondDenom, valTokens), staking.Description{}, commission, sdk.OneInt()) res, err := sh(ctx, msg) @@ -82,20 +94,20 @@ func TestCalculateRewardsAfterSlash(t *testing.T) { require.NotNil(t, res) // end block to bond validator - staking.EndBlocker(ctx, sk) + staking.EndBlocker(ctx, app.StakingKeeper) // next block ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) // fetch validator and delegation - val := sk.Validator(ctx, valOpAddr1) - del := sk.Delegation(ctx, sdk.AccAddress(valOpAddr1), valOpAddr1) + val := app.StakingKeeper.Validator(ctx, valAddrs[0]) + del := app.StakingKeeper.Delegation(ctx, sdk.AccAddress(valAddrs[0]), valAddrs[0]) // end period - endingPeriod := k.incrementValidatorPeriod(ctx, val) + endingPeriod := app.DistrKeeper.IncrementValidatorPeriod(ctx, val) // calculate delegation rewards - rewards := k.calculateDelegationRewards(ctx, val, del, endingPeriod) + rewards := app.DistrKeeper.CalculateDelegationRewards(ctx, val, del, endingPeriod) // rewards should be zero require.True(t, rewards.IsZero()) @@ -104,10 +116,10 @@ func TestCalculateRewardsAfterSlash(t *testing.T) { ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3) // slash the validator by 50% - sk.Slash(ctx, valConsAddr1, ctx.BlockHeight(), valPower, sdk.NewDecWithPrec(5, 1)) + app.StakingKeeper.Slash(ctx, valConsAddr1, ctx.BlockHeight(), valPower, sdk.NewDecWithPrec(5, 1)) // retrieve validator - val = sk.Validator(ctx, valOpAddr1) + val = app.StakingKeeper.Validator(ctx, valAddrs[0]) // increase block height ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3) @@ -115,31 +127,35 @@ func TestCalculateRewardsAfterSlash(t *testing.T) { // allocate some rewards initial := sdk.TokensFromConsensusPower(10) tokens := sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial.ToDec()}} - k.AllocateTokensToValidator(ctx, val, tokens) + app.DistrKeeper.AllocateTokensToValidator(ctx, val, tokens) // end period - endingPeriod = k.incrementValidatorPeriod(ctx, val) + endingPeriod = app.DistrKeeper.IncrementValidatorPeriod(ctx, val) // calculate delegation rewards - rewards = k.calculateDelegationRewards(ctx, val, del, endingPeriod) + rewards = app.DistrKeeper.CalculateDelegationRewards(ctx, val, del, endingPeriod) // rewards should be half the tokens require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial.QuoRaw(2).ToDec()}}, rewards) // commission should be the other half require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial.QuoRaw(2).ToDec()}}, - k.GetValidatorAccumulatedCommission(ctx, valOpAddr1).Commission) + app.DistrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission) } func TestCalculateRewardsAfterManySlashes(t *testing.T) { - ctx, _, _, k, sk, _ := CreateTestInputDefault(t, false, 1000) - sh := staking.NewHandler(sk) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + sh := staking.NewHandler(app.StakingKeeper) + addr := simapp.AddTestAddrs(app, ctx, 2, sdk.NewInt(100000000)) + valAddrs := simapp.ConvertAddrsToValAddrs(addr) // create validator with 50% commission power := int64(100) valTokens := sdk.TokensFromConsensusPower(power) commission := staking.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0)) - msg := staking.NewMsgCreateValidator(valOpAddr1, valConsPk1, + msg := staking.NewMsgCreateValidator(valAddrs[0], valConsPk1, sdk.NewCoin(sdk.DefaultBondDenom, valTokens), staking.Description{}, commission, sdk.OneInt()) res, err := sh(ctx, msg) @@ -147,20 +163,20 @@ func TestCalculateRewardsAfterManySlashes(t *testing.T) { require.NotNil(t, res) // end block to bond validator - staking.EndBlocker(ctx, sk) + staking.EndBlocker(ctx, app.StakingKeeper) // next block ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) // fetch validator and delegation - val := sk.Validator(ctx, valOpAddr1) - del := sk.Delegation(ctx, sdk.AccAddress(valOpAddr1), valOpAddr1) + val := app.StakingKeeper.Validator(ctx, valAddrs[0]) + del := app.StakingKeeper.Delegation(ctx, sdk.AccAddress(valAddrs[0]), valAddrs[0]) // end period - endingPeriod := k.incrementValidatorPeriod(ctx, val) + endingPeriod := app.DistrKeeper.IncrementValidatorPeriod(ctx, val) // calculate delegation rewards - rewards := k.calculateDelegationRewards(ctx, val, del, endingPeriod) + rewards := app.DistrKeeper.CalculateDelegationRewards(ctx, val, del, endingPeriod) // rewards should be zero require.True(t, rewards.IsZero()) @@ -169,10 +185,10 @@ func TestCalculateRewardsAfterManySlashes(t *testing.T) { ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3) // slash the validator by 50% - sk.Slash(ctx, valConsAddr1, ctx.BlockHeight(), power, sdk.NewDecWithPrec(5, 1)) + app.StakingKeeper.Slash(ctx, valConsAddr1, ctx.BlockHeight(), power, sdk.NewDecWithPrec(5, 1)) // fetch the validator again - val = sk.Validator(ctx, valOpAddr1) + val = app.StakingKeeper.Validator(ctx, valAddrs[0]) // increase block height ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3) @@ -180,41 +196,46 @@ func TestCalculateRewardsAfterManySlashes(t *testing.T) { // allocate some rewards initial := sdk.TokensFromConsensusPower(10) tokens := sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial.ToDec()}} - k.AllocateTokensToValidator(ctx, val, tokens) + app.DistrKeeper.AllocateTokensToValidator(ctx, val, tokens) // slash the validator by 50% again - sk.Slash(ctx, valConsAddr1, ctx.BlockHeight(), power/2, sdk.NewDecWithPrec(5, 1)) + app.StakingKeeper.Slash(ctx, valConsAddr1, ctx.BlockHeight(), power/2, sdk.NewDecWithPrec(5, 1)) // fetch the validator again - val = sk.Validator(ctx, valOpAddr1) + val = app.StakingKeeper.Validator(ctx, valAddrs[0]) // increase block height ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3) // allocate some more rewards - k.AllocateTokensToValidator(ctx, val, tokens) + app.DistrKeeper.AllocateTokensToValidator(ctx, val, tokens) // end period - endingPeriod = k.incrementValidatorPeriod(ctx, val) + endingPeriod = app.DistrKeeper.IncrementValidatorPeriod(ctx, val) // calculate delegation rewards - rewards = k.calculateDelegationRewards(ctx, val, del, endingPeriod) + rewards = app.DistrKeeper.CalculateDelegationRewards(ctx, val, del, endingPeriod) // rewards should be half the tokens require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial.ToDec()}}, rewards) // commission should be the other half require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial.ToDec()}}, - k.GetValidatorAccumulatedCommission(ctx, valOpAddr1).Commission) + app.DistrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission) } func TestCalculateRewardsMultiDelegator(t *testing.T) { - ctx, _, _, k, sk, _ := CreateTestInputDefault(t, false, 1000) - sh := staking.NewHandler(sk) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + sh := staking.NewHandler(app.StakingKeeper) + + addr := simapp.AddTestAddrs(app, ctx, 2, sdk.NewInt(100000000)) + valAddrs := simapp.ConvertAddrsToValAddrs(addr) // create validator with 50% commission commission := staking.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0)) - msg := staking.NewMsgCreateValidator(valOpAddr1, valConsPk1, + msg := staking.NewMsgCreateValidator(valAddrs[0], valConsPk1, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), staking.Description{}, commission, sdk.OneInt()) res, err := sh(ctx, msg) @@ -222,77 +243,82 @@ func TestCalculateRewardsMultiDelegator(t *testing.T) { require.NotNil(t, res) // end block to bond validator - staking.EndBlocker(ctx, sk) + staking.EndBlocker(ctx, app.StakingKeeper) // next block ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) // fetch validator and delegation - val := sk.Validator(ctx, valOpAddr1) - del1 := sk.Delegation(ctx, sdk.AccAddress(valOpAddr1), valOpAddr1) + val := app.StakingKeeper.Validator(ctx, valAddrs[0]) + del1 := app.StakingKeeper.Delegation(ctx, sdk.AccAddress(valAddrs[0]), valAddrs[0]) // allocate some rewards initial := int64(20) tokens := sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(initial)}} - k.AllocateTokensToValidator(ctx, val, tokens) + app.DistrKeeper.AllocateTokensToValidator(ctx, val, tokens) // second delegation - msg2 := staking.NewMsgDelegate(sdk.AccAddress(valOpAddr2), valOpAddr1, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))) + msg2 := staking.NewMsgDelegate(sdk.AccAddress(valAddrs[1]), valAddrs[0], sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))) res, err = sh(ctx, msg2) require.NoError(t, err) require.NotNil(t, res) - del2 := sk.Delegation(ctx, sdk.AccAddress(valOpAddr2), valOpAddr1) + del2 := app.StakingKeeper.Delegation(ctx, sdk.AccAddress(valAddrs[1]), valAddrs[0]) // fetch updated validator - val = sk.Validator(ctx, valOpAddr1) + val = app.StakingKeeper.Validator(ctx, valAddrs[0]) // end block - staking.EndBlocker(ctx, sk) + staking.EndBlocker(ctx, app.StakingKeeper) // next block ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) // allocate some more rewards - k.AllocateTokensToValidator(ctx, val, tokens) + app.DistrKeeper.AllocateTokensToValidator(ctx, val, tokens) // end period - endingPeriod := k.incrementValidatorPeriod(ctx, val) + endingPeriod := app.DistrKeeper.IncrementValidatorPeriod(ctx, val) // calculate delegation rewards for del1 - rewards := k.calculateDelegationRewards(ctx, val, del1, endingPeriod) + rewards := app.DistrKeeper.CalculateDelegationRewards(ctx, val, del1, endingPeriod) // rewards for del1 should be 3/4 initial require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(initial * 3 / 4)}}, rewards) // calculate delegation rewards for del2 - rewards = k.calculateDelegationRewards(ctx, val, del2, endingPeriod) + rewards = app.DistrKeeper.CalculateDelegationRewards(ctx, val, del2, endingPeriod) // rewards for del2 should be 1/4 initial require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(initial * 1 / 4)}}, rewards) // commission should be equal to initial (50% twice) - require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(initial)}}, k.GetValidatorAccumulatedCommission(ctx, valOpAddr1).Commission) + require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(initial)}}, app.DistrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission) } func TestWithdrawDelegationRewardsBasic(t *testing.T) { balancePower := int64(1000) balanceTokens := sdk.TokensFromConsensusPower(balancePower) - ctx, _, bk, k, sk, _ := CreateTestInputDefault(t, false, balancePower) - sh := staking.NewHandler(sk) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + addr := simapp.AddTestAddrs(app, ctx, 1, sdk.NewInt(1000000000)) + valAddrs := simapp.ConvertAddrsToValAddrs(addr) + + sh := staking.NewHandler(app.StakingKeeper) // set module account coins - distrAcc := k.GetDistributionAccount(ctx) - require.NoError(t, bk.SetBalances(ctx, distrAcc.GetAddress(), sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, balanceTokens)))) - k.supplyKeeper.SetModuleAccount(ctx, distrAcc) + distrAcc := app.DistrKeeper.GetDistributionAccount(ctx) + require.NoError(t, app.BankKeeper.SetBalances(ctx, distrAcc.GetAddress(), sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, balanceTokens)))) + app.SupplyKeeper.SetModuleAccount(ctx, distrAcc) // create validator with 50% commission power := int64(100) valTokens := sdk.TokensFromConsensusPower(power) commission := staking.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0)) msg := staking.NewMsgCreateValidator( - valOpAddr1, valConsPk1, + valAddrs[0], valConsPk1, sdk.NewCoin(sdk.DefaultBondDenom, valTokens), staking.Description{}, commission, sdk.OneInt(), ) @@ -305,62 +331,67 @@ func TestWithdrawDelegationRewardsBasic(t *testing.T) { expTokens := balanceTokens.Sub(valTokens) require.Equal(t, sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, expTokens)}, - bk.GetAllBalances(ctx, sdk.AccAddress(valOpAddr1)), + app.BankKeeper.GetAllBalances(ctx, sdk.AccAddress(valAddrs[0])), ) // end block to bond validator - staking.EndBlocker(ctx, sk) + staking.EndBlocker(ctx, app.StakingKeeper) // next block ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) // fetch validator and delegation - val := sk.Validator(ctx, valOpAddr1) + val := app.StakingKeeper.Validator(ctx, valAddrs[0]) // allocate some rewards initial := sdk.TokensFromConsensusPower(10) tokens := sdk.DecCoins{sdk.NewDecCoin(sdk.DefaultBondDenom, initial)} - k.AllocateTokensToValidator(ctx, val, tokens) + app.DistrKeeper.AllocateTokensToValidator(ctx, val, tokens) // historical count should be 2 (initial + latest for delegation) - require.Equal(t, uint64(2), k.GetValidatorHistoricalReferenceCount(ctx)) + require.Equal(t, uint64(2), app.DistrKeeper.GetValidatorHistoricalReferenceCount(ctx)) // withdraw rewards - _, err = k.WithdrawDelegationRewards(ctx, sdk.AccAddress(valOpAddr1), valOpAddr1) + _, err = app.DistrKeeper.WithdrawDelegationRewards(ctx, sdk.AccAddress(valAddrs[0]), valAddrs[0]) require.Nil(t, err) // historical count should still be 2 (added one record, cleared one) - require.Equal(t, uint64(2), k.GetValidatorHistoricalReferenceCount(ctx)) + require.Equal(t, uint64(2), app.DistrKeeper.GetValidatorHistoricalReferenceCount(ctx)) // assert correct balance exp := balanceTokens.Sub(valTokens).Add(initial.QuoRaw(2)) require.Equal(t, sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, exp)}, - bk.GetAllBalances(ctx, sdk.AccAddress(valOpAddr1)), + app.BankKeeper.GetAllBalances(ctx, sdk.AccAddress(valAddrs[0])), ) // withdraw commission - _, err = k.WithdrawValidatorCommission(ctx, valOpAddr1) + _, err = app.DistrKeeper.WithdrawValidatorCommission(ctx, valAddrs[0]) require.Nil(t, err) // assert correct balance exp = balanceTokens.Sub(valTokens).Add(initial) require.Equal(t, sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, exp)}, - bk.GetAllBalances(ctx, sdk.AccAddress(valOpAddr1)), + app.BankKeeper.GetAllBalances(ctx, sdk.AccAddress(valAddrs[0])), ) } func TestCalculateRewardsAfterManySlashesInSameBlock(t *testing.T) { - ctx, _, _, k, sk, _ := CreateTestInputDefault(t, false, 1000) - sh := staking.NewHandler(sk) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + addr := simapp.AddTestAddrs(app, ctx, 1, sdk.NewInt(1000000000)) + valAddrs := simapp.ConvertAddrsToValAddrs(addr) + + sh := staking.NewHandler(app.StakingKeeper) // create validator with 50% commission power := int64(100) valTokens := sdk.TokensFromConsensusPower(power) commission := staking.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0)) - msg := staking.NewMsgCreateValidator(valOpAddr1, valConsPk1, + msg := staking.NewMsgCreateValidator(valAddrs[0], valConsPk1, sdk.NewCoin(sdk.DefaultBondDenom, valTokens), staking.Description{}, commission, sdk.OneInt()) res, err := sh(ctx, msg) @@ -368,20 +399,20 @@ func TestCalculateRewardsAfterManySlashesInSameBlock(t *testing.T) { require.NotNil(t, res) // end block to bond validator - staking.EndBlocker(ctx, sk) + staking.EndBlocker(ctx, app.StakingKeeper) // next block ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) // fetch validator and delegation - val := sk.Validator(ctx, valOpAddr1) - del := sk.Delegation(ctx, sdk.AccAddress(valOpAddr1), valOpAddr1) + val := app.StakingKeeper.Validator(ctx, valAddrs[0]) + del := app.StakingKeeper.Delegation(ctx, sdk.AccAddress(valAddrs[0]), valAddrs[0]) // end period - endingPeriod := k.incrementValidatorPeriod(ctx, val) + endingPeriod := app.DistrKeeper.IncrementValidatorPeriod(ctx, val) // calculate delegation rewards - rewards := k.calculateDelegationRewards(ctx, val, del, endingPeriod) + rewards := app.DistrKeeper.CalculateDelegationRewards(ctx, val, del, endingPeriod) // rewards should be zero require.True(t, rewards.IsZero()) @@ -392,45 +423,49 @@ func TestCalculateRewardsAfterManySlashesInSameBlock(t *testing.T) { // allocate some rewards initial := sdk.TokensFromConsensusPower(10).ToDec() tokens := sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial}} - k.AllocateTokensToValidator(ctx, val, tokens) + app.DistrKeeper.AllocateTokensToValidator(ctx, val, tokens) // slash the validator by 50% - sk.Slash(ctx, valConsAddr1, ctx.BlockHeight(), power, sdk.NewDecWithPrec(5, 1)) + app.StakingKeeper.Slash(ctx, valConsAddr1, ctx.BlockHeight(), power, sdk.NewDecWithPrec(5, 1)) // slash the validator by 50% again - sk.Slash(ctx, valConsAddr1, ctx.BlockHeight(), power/2, sdk.NewDecWithPrec(5, 1)) + app.StakingKeeper.Slash(ctx, valConsAddr1, ctx.BlockHeight(), power/2, sdk.NewDecWithPrec(5, 1)) // fetch the validator again - val = sk.Validator(ctx, valOpAddr1) + val = app.StakingKeeper.Validator(ctx, valAddrs[0]) // increase block height ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3) // allocate some more rewards - k.AllocateTokensToValidator(ctx, val, tokens) + app.DistrKeeper.AllocateTokensToValidator(ctx, val, tokens) // end period - endingPeriod = k.incrementValidatorPeriod(ctx, val) + endingPeriod = app.DistrKeeper.IncrementValidatorPeriod(ctx, val) // calculate delegation rewards - rewards = k.calculateDelegationRewards(ctx, val, del, endingPeriod) + rewards = app.DistrKeeper.CalculateDelegationRewards(ctx, val, del, endingPeriod) // rewards should be half the tokens require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial}}, rewards) // commission should be the other half - require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial}}, k.GetValidatorAccumulatedCommission(ctx, valOpAddr1).Commission) + require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial}}, app.DistrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission) } func TestCalculateRewardsMultiDelegatorMultiSlash(t *testing.T) { - ctx, _, _, k, sk, _ := CreateTestInputDefault(t, false, 1000) - sh := staking.NewHandler(sk) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + sh := staking.NewHandler(app.StakingKeeper) + + addr := simapp.AddTestAddrs(app, ctx, 2, sdk.NewInt(1000000000)) + valAddrs := simapp.ConvertAddrsToValAddrs(addr) // create validator with 50% commission commission := staking.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0)) power := int64(100) valTokens := sdk.TokensFromConsensusPower(power) - msg := staking.NewMsgCreateValidator(valOpAddr1, valConsPk1, + msg := staking.NewMsgCreateValidator(valAddrs[0], valConsPk1, sdk.NewCoin(sdk.DefaultBondDenom, valTokens), staking.Description{}, commission, sdk.OneInt()) res, err := sh(ctx, msg) @@ -438,88 +473,94 @@ func TestCalculateRewardsMultiDelegatorMultiSlash(t *testing.T) { require.NotNil(t, res) // end block to bond validator - staking.EndBlocker(ctx, sk) + staking.EndBlocker(ctx, app.StakingKeeper) // next block ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) // fetch validator and delegation - val := sk.Validator(ctx, valOpAddr1) - del1 := sk.Delegation(ctx, sdk.AccAddress(valOpAddr1), valOpAddr1) + val := app.StakingKeeper.Validator(ctx, valAddrs[0]) + del1 := app.StakingKeeper.Delegation(ctx, sdk.AccAddress(valAddrs[0]), valAddrs[0]) // allocate some rewards initial := sdk.TokensFromConsensusPower(30).ToDec() tokens := sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial}} - k.AllocateTokensToValidator(ctx, val, tokens) + app.DistrKeeper.AllocateTokensToValidator(ctx, val, tokens) // slash the validator ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3) - sk.Slash(ctx, valConsAddr1, ctx.BlockHeight(), power, sdk.NewDecWithPrec(5, 1)) + app.StakingKeeper.Slash(ctx, valConsAddr1, ctx.BlockHeight(), power, sdk.NewDecWithPrec(5, 1)) ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3) // second delegation delTokens := sdk.TokensFromConsensusPower(100) - msg2 := staking.NewMsgDelegate(sdk.AccAddress(valOpAddr2), valOpAddr1, + msg2 := staking.NewMsgDelegate(sdk.AccAddress(valAddrs[1]), valAddrs[0], sdk.NewCoin(sdk.DefaultBondDenom, delTokens)) res, err = sh(ctx, msg2) require.NoError(t, err) require.NotNil(t, res) - del2 := sk.Delegation(ctx, sdk.AccAddress(valOpAddr2), valOpAddr1) + del2 := app.StakingKeeper.Delegation(ctx, sdk.AccAddress(valAddrs[1]), valAddrs[0]) // end block - staking.EndBlocker(ctx, sk) + staking.EndBlocker(ctx, app.StakingKeeper) // next block ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) // allocate some more rewards - k.AllocateTokensToValidator(ctx, val, tokens) + app.DistrKeeper.AllocateTokensToValidator(ctx, val, tokens) // slash the validator again ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3) - sk.Slash(ctx, valConsAddr1, ctx.BlockHeight(), power, sdk.NewDecWithPrec(5, 1)) + app.StakingKeeper.Slash(ctx, valConsAddr1, ctx.BlockHeight(), power, sdk.NewDecWithPrec(5, 1)) ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3) // fetch updated validator - val = sk.Validator(ctx, valOpAddr1) + val = app.StakingKeeper.Validator(ctx, valAddrs[0]) // end period - endingPeriod := k.incrementValidatorPeriod(ctx, val) + endingPeriod := app.DistrKeeper.IncrementValidatorPeriod(ctx, val) // calculate delegation rewards for del1 - rewards := k.calculateDelegationRewards(ctx, val, del1, endingPeriod) + rewards := app.DistrKeeper.CalculateDelegationRewards(ctx, val, del1, endingPeriod) // rewards for del1 should be 2/3 initial (half initial first period, 1/6 initial second period) require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial.QuoInt64(2).Add(initial.QuoInt64(6))}}, rewards) // calculate delegation rewards for del2 - rewards = k.calculateDelegationRewards(ctx, val, del2, endingPeriod) + rewards = app.DistrKeeper.CalculateDelegationRewards(ctx, val, del2, endingPeriod) // rewards for del2 should be initial / 3 require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial.QuoInt64(3)}}, rewards) // commission should be equal to initial (twice 50% commission, unaffected by slashing) - require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial}}, k.GetValidatorAccumulatedCommission(ctx, valOpAddr1).Commission) + require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial}}, app.DistrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission) } func TestCalculateRewardsMultiDelegatorMultWithdraw(t *testing.T) { - ctx, _, bk, k, sk, _ := CreateTestInputDefault(t, false, 1000) - sh := staking.NewHandler(sk) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + sh := staking.NewHandler(app.StakingKeeper) + + addr := simapp.AddTestAddrs(app, ctx, 2, sdk.NewInt(1000000000)) + valAddrs := simapp.ConvertAddrsToValAddrs(addr) + initial := int64(20) // set module account coins - distrAcc := k.GetDistributionAccount(ctx) - err := bk.SetBalances(ctx, distrAcc.GetAddress(), sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(1000)))) + distrAcc := app.DistrKeeper.GetDistributionAccount(ctx) + err := app.BankKeeper.SetBalances(ctx, distrAcc.GetAddress(), sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(1000)))) require.NoError(t, err) - k.supplyKeeper.SetModuleAccount(ctx, distrAcc) + app.SupplyKeeper.SetModuleAccount(ctx, distrAcc) tokens := sdk.DecCoins{sdk.NewDecCoinFromDec(sdk.DefaultBondDenom, sdk.NewDec(initial))} // create validator with 50% commission commission := staking.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0)) - msg := staking.NewMsgCreateValidator(valOpAddr1, valConsPk1, + msg := staking.NewMsgCreateValidator(valAddrs[0], valConsPk1, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), staking.Description{}, commission, sdk.OneInt()) res, err := sh(ctx, msg) @@ -527,124 +568,124 @@ func TestCalculateRewardsMultiDelegatorMultWithdraw(t *testing.T) { require.NotNil(t, res) // end block to bond validator - staking.EndBlocker(ctx, sk) + staking.EndBlocker(ctx, app.StakingKeeper) // next block ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) // fetch validator and delegation - val := sk.Validator(ctx, valOpAddr1) - del1 := sk.Delegation(ctx, sdk.AccAddress(valOpAddr1), valOpAddr1) + val := app.StakingKeeper.Validator(ctx, valAddrs[0]) + del1 := app.StakingKeeper.Delegation(ctx, sdk.AccAddress(valAddrs[0]), valAddrs[0]) // allocate some rewards - k.AllocateTokensToValidator(ctx, val, tokens) + app.DistrKeeper.AllocateTokensToValidator(ctx, val, tokens) // historical count should be 2 (validator init, delegation init) - require.Equal(t, uint64(2), k.GetValidatorHistoricalReferenceCount(ctx)) + require.Equal(t, uint64(2), app.DistrKeeper.GetValidatorHistoricalReferenceCount(ctx)) // second delegation - msg2 := staking.NewMsgDelegate(sdk.AccAddress(valOpAddr2), valOpAddr1, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))) + msg2 := staking.NewMsgDelegate(sdk.AccAddress(valAddrs[1]), valAddrs[0], sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))) res, err = sh(ctx, msg2) require.NoError(t, err) require.NotNil(t, res) // historical count should be 3 (second delegation init) - require.Equal(t, uint64(3), k.GetValidatorHistoricalReferenceCount(ctx)) + require.Equal(t, uint64(3), app.DistrKeeper.GetValidatorHistoricalReferenceCount(ctx)) // fetch updated validator - val = sk.Validator(ctx, valOpAddr1) - del2 := sk.Delegation(ctx, sdk.AccAddress(valOpAddr2), valOpAddr1) + val = app.StakingKeeper.Validator(ctx, valAddrs[0]) + del2 := app.StakingKeeper.Delegation(ctx, sdk.AccAddress(valAddrs[1]), valAddrs[0]) // end block - staking.EndBlocker(ctx, sk) + staking.EndBlocker(ctx, app.StakingKeeper) // next block ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) // allocate some more rewards - k.AllocateTokensToValidator(ctx, val, tokens) + app.DistrKeeper.AllocateTokensToValidator(ctx, val, tokens) // first delegator withdraws - k.WithdrawDelegationRewards(ctx, sdk.AccAddress(valOpAddr1), valOpAddr1) + app.DistrKeeper.WithdrawDelegationRewards(ctx, sdk.AccAddress(valAddrs[0]), valAddrs[0]) // second delegator withdraws - k.WithdrawDelegationRewards(ctx, sdk.AccAddress(valOpAddr2), valOpAddr1) + app.DistrKeeper.WithdrawDelegationRewards(ctx, sdk.AccAddress(valAddrs[1]), valAddrs[0]) // historical count should be 3 (validator init + two delegations) - require.Equal(t, uint64(3), k.GetValidatorHistoricalReferenceCount(ctx)) + require.Equal(t, uint64(3), app.DistrKeeper.GetValidatorHistoricalReferenceCount(ctx)) // validator withdraws commission - k.WithdrawValidatorCommission(ctx, valOpAddr1) + app.DistrKeeper.WithdrawValidatorCommission(ctx, valAddrs[0]) // end period - endingPeriod := k.incrementValidatorPeriod(ctx, val) + endingPeriod := app.DistrKeeper.IncrementValidatorPeriod(ctx, val) // calculate delegation rewards for del1 - rewards := k.calculateDelegationRewards(ctx, val, del1, endingPeriod) + rewards := app.DistrKeeper.CalculateDelegationRewards(ctx, val, del1, endingPeriod) // rewards for del1 should be zero require.True(t, rewards.IsZero()) // calculate delegation rewards for del2 - rewards = k.calculateDelegationRewards(ctx, val, del2, endingPeriod) + rewards = app.DistrKeeper.CalculateDelegationRewards(ctx, val, del2, endingPeriod) // rewards for del2 should be zero require.True(t, rewards.IsZero()) // commission should be zero - require.True(t, k.GetValidatorAccumulatedCommission(ctx, valOpAddr1).Commission.IsZero()) + require.True(t, app.DistrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission.IsZero()) // next block ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) // allocate some more rewards - k.AllocateTokensToValidator(ctx, val, tokens) + app.DistrKeeper.AllocateTokensToValidator(ctx, val, tokens) // first delegator withdraws again - k.WithdrawDelegationRewards(ctx, sdk.AccAddress(valOpAddr1), valOpAddr1) + app.DistrKeeper.WithdrawDelegationRewards(ctx, sdk.AccAddress(valAddrs[0]), valAddrs[0]) // end period - endingPeriod = k.incrementValidatorPeriod(ctx, val) + endingPeriod = app.DistrKeeper.IncrementValidatorPeriod(ctx, val) // calculate delegation rewards for del1 - rewards = k.calculateDelegationRewards(ctx, val, del1, endingPeriod) + rewards = app.DistrKeeper.CalculateDelegationRewards(ctx, val, del1, endingPeriod) // rewards for del1 should be zero require.True(t, rewards.IsZero()) // calculate delegation rewards for del2 - rewards = k.calculateDelegationRewards(ctx, val, del2, endingPeriod) + rewards = app.DistrKeeper.CalculateDelegationRewards(ctx, val, del2, endingPeriod) // rewards for del2 should be 1/4 initial require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(initial / 4)}}, rewards) // commission should be half initial - require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(initial / 2)}}, k.GetValidatorAccumulatedCommission(ctx, valOpAddr1).Commission) + require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(initial / 2)}}, app.DistrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission) // next block ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) // allocate some more rewards - k.AllocateTokensToValidator(ctx, val, tokens) + app.DistrKeeper.AllocateTokensToValidator(ctx, val, tokens) // withdraw commission - k.WithdrawValidatorCommission(ctx, valOpAddr1) + app.DistrKeeper.WithdrawValidatorCommission(ctx, valAddrs[0]) // end period - endingPeriod = k.incrementValidatorPeriod(ctx, val) + endingPeriod = app.DistrKeeper.IncrementValidatorPeriod(ctx, val) // calculate delegation rewards for del1 - rewards = k.calculateDelegationRewards(ctx, val, del1, endingPeriod) + rewards = app.DistrKeeper.CalculateDelegationRewards(ctx, val, del1, endingPeriod) // rewards for del1 should be 1/4 initial require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(initial / 4)}}, rewards) // calculate delegation rewards for del2 - rewards = k.calculateDelegationRewards(ctx, val, del2, endingPeriod) + rewards = app.DistrKeeper.CalculateDelegationRewards(ctx, val, del2, endingPeriod) // rewards for del2 should be 1/2 initial require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(initial / 2)}}, rewards) // commission should be zero - require.True(t, k.GetValidatorAccumulatedCommission(ctx, valOpAddr1).Commission.IsZero()) + require.True(t, app.DistrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission.IsZero()) } diff --git a/x/distribution/keeper/hooks.go b/x/distribution/keeper/hooks.go index c68b5909f734..58055468d158 100644 --- a/x/distribution/keeper/hooks.go +++ b/x/distribution/keeper/hooks.go @@ -77,7 +77,7 @@ func (h Hooks) AfterValidatorRemoved(ctx sdk.Context, _ sdk.ConsAddress, valAddr // increment period func (h Hooks) BeforeDelegationCreated(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) { val := h.k.stakingKeeper.Validator(ctx, valAddr) - h.k.incrementValidatorPeriod(ctx, val) + h.k.IncrementValidatorPeriod(ctx, val) } // withdraw delegation rewards (which also increments period) diff --git a/x/distribution/keeper/keeper_test.go b/x/distribution/keeper/keeper_test.go index f4846e61e2fa..8376899d8613 100644 --- a/x/distribution/keeper/keeper_test.go +++ b/x/distribution/keeper/keeper_test.go @@ -1,76 +1,84 @@ -package keeper +package keeper_test import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/distribution/types" ) func TestSetWithdrawAddr(t *testing.T) { - ctx, _, _, keeper, _, _ := CreateTestInputDefault(t, false, 1000) // nolint: dogsled + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + addr := simapp.AddTestAddrs(app, ctx, 2, sdk.NewInt(1000000000)) - params := keeper.GetParams(ctx) + params := app.DistrKeeper.GetParams(ctx) params.WithdrawAddrEnabled = false - keeper.SetParams(ctx, params) + app.DistrKeeper.SetParams(ctx, params) - err := keeper.SetWithdrawAddr(ctx, delAddr1, delAddr2) + err := app.DistrKeeper.SetWithdrawAddr(ctx, addr[0], addr[1]) require.NotNil(t, err) params.WithdrawAddrEnabled = true - keeper.SetParams(ctx, params) + app.DistrKeeper.SetParams(ctx, params) - err = keeper.SetWithdrawAddr(ctx, delAddr1, delAddr2) + err = app.DistrKeeper.SetWithdrawAddr(ctx, addr[0], addr[1]) require.Nil(t, err) - keeper.blacklistedAddrs[distrAcc.GetAddress().String()] = true - require.Error(t, keeper.SetWithdrawAddr(ctx, delAddr1, distrAcc.GetAddress())) + require.Error(t, app.DistrKeeper.SetWithdrawAddr(ctx, addr[0], distrAcc.GetAddress())) } func TestWithdrawValidatorCommission(t *testing.T) { - ctx, _, bk, keeper, _, _ := CreateTestInputDefault(t, false, 1000) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) valCommission := sdk.DecCoins{ sdk.NewDecCoinFromDec("mytoken", sdk.NewDec(5).Quo(sdk.NewDec(4))), sdk.NewDecCoinFromDec("stake", sdk.NewDec(3).Quo(sdk.NewDec(2))), } + addr := simapp.AddTestAddrs(app, ctx, 1, sdk.NewInt(1000000000)) + valAddrs := simapp.ConvertAddrsToValAddrs(addr) + // set module account coins - distrAcc := keeper.GetDistributionAccount(ctx) - bk.SetBalances(ctx, distrAcc.GetAddress(), sdk.NewCoins( + distrAcc := app.DistrKeeper.GetDistributionAccount(ctx) + app.BankKeeper.SetBalances(ctx, distrAcc.GetAddress(), sdk.NewCoins( sdk.NewCoin("mytoken", sdk.NewInt(2)), sdk.NewCoin("stake", sdk.NewInt(2)), )) - keeper.supplyKeeper.SetModuleAccount(ctx, distrAcc) + app.SupplyKeeper.SetModuleAccount(ctx, distrAcc) // check initial balance - balance := bk.GetAllBalances(ctx, sdk.AccAddress(valOpAddr3)) + balance := app.BankKeeper.GetAllBalances(ctx, sdk.AccAddress(valAddrs[0])) expTokens := sdk.TokensFromConsensusPower(1000) expCoins := sdk.NewCoins(sdk.NewCoin("stake", expTokens)) require.Equal(t, expCoins, balance) // set outstanding rewards - keeper.SetValidatorOutstandingRewards(ctx, valOpAddr3, types.ValidatorOutstandingRewards{Rewards: valCommission}) + app.DistrKeeper.SetValidatorOutstandingRewards(ctx, valAddrs[0], types.ValidatorOutstandingRewards{Rewards: valCommission}) // set commission - keeper.SetValidatorAccumulatedCommission(ctx, valOpAddr3, types.ValidatorAccumulatedCommission{Commission: valCommission}) + app.DistrKeeper.SetValidatorAccumulatedCommission(ctx, valAddrs[0], types.ValidatorAccumulatedCommission{Commission: valCommission}) // withdraw commission - keeper.WithdrawValidatorCommission(ctx, valOpAddr3) + app.DistrKeeper.WithdrawValidatorCommission(ctx, valAddrs[0]) // check balance increase - balance = bk.GetAllBalances(ctx, sdk.AccAddress(valOpAddr3)) + balance = app.BankKeeper.GetAllBalances(ctx, sdk.AccAddress(valAddrs[0])) require.Equal(t, sdk.NewCoins( sdk.NewCoin("mytoken", sdk.NewInt(1)), sdk.NewCoin("stake", expTokens.AddRaw(1)), ), balance) // check remainder - remainder := keeper.GetValidatorAccumulatedCommission(ctx, valOpAddr3).Commission + remainder := app.DistrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission require.Equal(t, sdk.DecCoins{ sdk.NewDecCoinFromDec("mytoken", sdk.NewDec(1).Quo(sdk.NewDec(4))), sdk.NewDecCoinFromDec("stake", sdk.NewDec(1).Quo(sdk.NewDec(2))), @@ -80,35 +88,41 @@ func TestWithdrawValidatorCommission(t *testing.T) { } func TestGetTotalRewards(t *testing.T) { - ctx, _, _, keeper, _, _ := CreateTestInputDefault(t, false, 1000) // nolint: dogsled + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) valCommission := sdk.DecCoins{ sdk.NewDecCoinFromDec("mytoken", sdk.NewDec(5).Quo(sdk.NewDec(4))), sdk.NewDecCoinFromDec("stake", sdk.NewDec(3).Quo(sdk.NewDec(2))), } - keeper.SetValidatorOutstandingRewards(ctx, valOpAddr1, types.ValidatorOutstandingRewards{Rewards: valCommission}) - keeper.SetValidatorOutstandingRewards(ctx, valOpAddr2, types.ValidatorOutstandingRewards{Rewards: valCommission}) + addr := simapp.AddTestAddrs(app, ctx, 2, sdk.NewInt(1000000000)) + valAddrs := simapp.ConvertAddrsToValAddrs(addr) + + app.DistrKeeper.SetValidatorOutstandingRewards(ctx, valAddrs[0], types.ValidatorOutstandingRewards{Rewards: valCommission}) + app.DistrKeeper.SetValidatorOutstandingRewards(ctx, valAddrs[1], types.ValidatorOutstandingRewards{Rewards: valCommission}) expectedRewards := valCommission.MulDec(sdk.NewDec(2)) - totalRewards := keeper.GetTotalRewards(ctx) + totalRewards := app.DistrKeeper.GetTotalRewards(ctx) require.Equal(t, expectedRewards, totalRewards) } func TestFundCommunityPool(t *testing.T) { - // nolint dogsled - ctx, _, bk, keeper, _, _, _ := CreateTestInputAdvanced(t, false, 1000, sdk.NewDecWithPrec(2, 2)) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + addr := simapp.AddTestAddrs(app, ctx, 2, sdk.NewInt(1000000000)) amount := sdk.NewCoins(sdk.NewInt64Coin("stake", 100)) - require.NoError(t, bk.SetBalances(ctx, delAddr1, amount)) + require.NoError(t, app.BankKeeper.SetBalances(ctx, addr[0], amount)) - initPool := keeper.GetFeePool(ctx) + initPool := app.DistrKeeper.GetFeePool(ctx) assert.Empty(t, initPool.CommunityPool) - err := keeper.FundCommunityPool(ctx, amount, delAddr1) + err := app.DistrKeeper.FundCommunityPool(ctx, amount, addr[0]) assert.Nil(t, err) - assert.Equal(t, initPool.CommunityPool.Add(sdk.NewDecCoinsFromCoins(amount...)...), keeper.GetFeePool(ctx).CommunityPool) - assert.Empty(t, bk.GetAllBalances(ctx, delAddr1)) + assert.Equal(t, initPool.CommunityPool.Add(sdk.NewDecCoinsFromCoins(amount...)...), app.DistrKeeper.GetFeePool(ctx).CommunityPool) + assert.Empty(t, app.BankKeeper.GetAllBalances(ctx, addr[0])) } diff --git a/x/distribution/keeper/querier.go b/x/distribution/keeper/querier.go index 77d4c6520971..fc1c15f34b22 100644 --- a/x/distribution/keeper/querier.go +++ b/x/distribution/keeper/querier.go @@ -142,8 +142,8 @@ func queryDelegationRewards(ctx sdk.Context, _ []string, req abci.RequestQuery, return nil, types.ErrNoDelegationExists } - endingPeriod := k.incrementValidatorPeriod(ctx, val) - rewards := k.calculateDelegationRewards(ctx, val, del, endingPeriod) + endingPeriod := k.IncrementValidatorPeriod(ctx, val) + rewards := k.CalculateDelegationRewards(ctx, val, del, endingPeriod) if rewards == nil { rewards = sdk.DecCoins{} } @@ -174,8 +174,8 @@ func queryDelegatorTotalRewards(ctx sdk.Context, _ []string, req abci.RequestQue func(_ int64, del exported.DelegationI) (stop bool) { valAddr := del.GetValidatorAddr() val := k.stakingKeeper.Validator(ctx, valAddr) - endingPeriod := k.incrementValidatorPeriod(ctx, val) - delReward := k.calculateDelegationRewards(ctx, val, del, endingPeriod) + endingPeriod := k.IncrementValidatorPeriod(ctx, val) + delReward := k.CalculateDelegationRewards(ctx, val, del, endingPeriod) delRewards = append(delRewards, types.NewDelegationDelegatorReward(valAddr, delReward)) total = total.Add(delReward...) diff --git a/x/distribution/keeper/querier_test.go b/x/distribution/keeper/querier_test.go index 7d032a6ccd95..307084b28d02 100644 --- a/x/distribution/keeper/querier_test.go +++ b/x/distribution/keeper/querier_test.go @@ -1,18 +1,18 @@ -package keeper +package keeper_test import ( "strings" "testing" - "github.com/stretchr/testify/require" - - abci "github.com/tendermint/tendermint/abci/types" - "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/distribution/keeper" "github.com/cosmos/cosmos-sdk/x/distribution/types" "github.com/cosmos/cosmos-sdk/x/staking" "github.com/cosmos/cosmos-sdk/x/supply" + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" ) const custom = "custom" @@ -111,8 +111,15 @@ func TestQueries(t *testing.T) { cdc := codec.New() types.RegisterCodec(cdc) supply.RegisterCodec(cdc) - ctx, _, _, keeper, sk, _ := CreateTestInputDefault(t, false, 100) - querier := NewQuerier(keeper) + + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + addr := simapp.AddTestAddrs(app, ctx, 1, sdk.NewInt(1000000000)) + valAddrs := simapp.ConvertAddrsToValAddrs(addr) + valOpAddr1 := valAddrs[0] + + querier := keeper.NewQuerier(app.DistrKeeper) // test param queries params := types.Params{ @@ -122,7 +129,7 @@ func TestQueries(t *testing.T) { WithdrawAddrEnabled: true, } - keeper.SetParams(ctx, params) + app.DistrKeeper.SetParams(ctx, params) paramsRes := getQueriedParams(t, ctx, cdc, querier) require.Equal(t, params.CommunityTax, paramsRes.CommunityTax) @@ -132,13 +139,13 @@ func TestQueries(t *testing.T) { // test outstanding rewards query outstandingRewards := sdk.DecCoins{{Denom: "mytoken", Amount: sdk.NewDec(3)}, {Denom: "myothertoken", Amount: sdk.NewDecWithPrec(3, 7)}} - keeper.SetValidatorOutstandingRewards(ctx, valOpAddr1, types.ValidatorOutstandingRewards{Rewards: outstandingRewards}) + app.DistrKeeper.SetValidatorOutstandingRewards(ctx, valOpAddr1, types.ValidatorOutstandingRewards{Rewards: outstandingRewards}) retOutstandingRewards := getQueriedValidatorOutstandingRewards(t, ctx, cdc, querier, valOpAddr1) require.Equal(t, outstandingRewards, retOutstandingRewards) // test validator commission query commission := sdk.DecCoins{{Denom: "token1", Amount: sdk.NewDec(4)}, {Denom: "token2", Amount: sdk.NewDec(2)}} - keeper.SetValidatorAccumulatedCommission(ctx, valOpAddr1, types.ValidatorAccumulatedCommission{Commission: commission}) + app.DistrKeeper.SetValidatorAccumulatedCommission(ctx, valOpAddr1, types.ValidatorAccumulatedCommission{Commission: commission}) retCommission := getQueriedValidatorCommission(t, ctx, cdc, querier, valOpAddr1) require.Equal(t, commission, retCommission) @@ -149,8 +156,8 @@ func TestQueries(t *testing.T) { // test validator slashes query with height range slashOne := types.NewValidatorSlashEvent(3, sdk.NewDecWithPrec(5, 1)) slashTwo := types.NewValidatorSlashEvent(7, sdk.NewDecWithPrec(6, 1)) - keeper.SetValidatorSlashEvent(ctx, valOpAddr1, 3, 0, slashOne) - keeper.SetValidatorSlashEvent(ctx, valOpAddr1, 7, 0, slashTwo) + app.DistrKeeper.SetValidatorSlashEvent(ctx, valOpAddr1, 3, 0, slashOne) + app.DistrKeeper.SetValidatorSlashEvent(ctx, valOpAddr1, 7, 0, slashTwo) slashes := getQueriedValidatorSlashes(t, ctx, cdc, querier, valOpAddr1, 0, 2) require.Equal(t, 0, len(slashes)) slashes = getQueriedValidatorSlashes(t, ctx, cdc, querier, valOpAddr1, 0, 5) @@ -159,7 +166,7 @@ func TestQueries(t *testing.T) { require.Equal(t, []types.ValidatorSlashEvent{slashOne, slashTwo}, slashes) // test delegation rewards query - sh := staking.NewHandler(sk) + sh := staking.NewHandler(app.StakingKeeper) comm := staking.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0)) msg := staking.NewMsgCreateValidator( valOpAddr1, valConsPk1, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), staking.Description{}, comm, sdk.OneInt(), @@ -169,15 +176,15 @@ func TestQueries(t *testing.T) { require.NoError(t, err) require.NotNil(t, res) - staking.EndBlocker(ctx, sk) + staking.EndBlocker(ctx, app.StakingKeeper) - val := sk.Validator(ctx, valOpAddr1) + val := app.StakingKeeper.Validator(ctx, valOpAddr1) rewards := getQueriedDelegationRewards(t, ctx, cdc, querier, sdk.AccAddress(valOpAddr1), valOpAddr1) require.True(t, rewards.IsZero()) initial := int64(10) ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) tokens := sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(initial)}} - keeper.AllocateTokensToValidator(ctx, val, tokens) + app.DistrKeeper.AllocateTokensToValidator(ctx, val, tokens) rewards = getQueriedDelegationRewards(t, ctx, cdc, querier, sdk.AccAddress(valOpAddr1), valOpAddr1) require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(initial / 2)}}, rewards) diff --git a/x/distribution/keeper/test_common.go b/x/distribution/keeper/test_common.go deleted file mode 100644 index 0c18e9249525..000000000000 --- a/x/distribution/keeper/test_common.go +++ /dev/null @@ -1,178 +0,0 @@ -package keeper - -import ( - "testing" - - "github.com/stretchr/testify/require" - - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/crypto" - "github.com/tendermint/tendermint/crypto/ed25519" - "github.com/tendermint/tendermint/libs/log" - dbm "github.com/tendermint/tm-db" - - "github.com/cosmos/cosmos-sdk/codec" - simappcodec "github.com/cosmos/cosmos-sdk/simapp/codec" - "github.com/cosmos/cosmos-sdk/store" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/bank" - "github.com/cosmos/cosmos-sdk/x/distribution/types" - "github.com/cosmos/cosmos-sdk/x/params/keeper" - paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" - "github.com/cosmos/cosmos-sdk/x/staking" - "github.com/cosmos/cosmos-sdk/x/supply" -) - -//nolint:deadcode,unused -var ( - delPk1 = ed25519.GenPrivKey().PubKey() - delPk2 = ed25519.GenPrivKey().PubKey() - delPk3 = ed25519.GenPrivKey().PubKey() - delAddr1 = sdk.AccAddress(delPk1.Address()) - delAddr2 = sdk.AccAddress(delPk2.Address()) - delAddr3 = sdk.AccAddress(delPk3.Address()) - - valOpPk1 = ed25519.GenPrivKey().PubKey() - valOpPk2 = ed25519.GenPrivKey().PubKey() - valOpPk3 = ed25519.GenPrivKey().PubKey() - valOpAddr1 = sdk.ValAddress(valOpPk1.Address()) - valOpAddr2 = sdk.ValAddress(valOpPk2.Address()) - valOpAddr3 = sdk.ValAddress(valOpPk3.Address()) - valAccAddr1 = sdk.AccAddress(valOpPk1.Address()) // generate acc addresses for these validator keys too - valAccAddr2 = sdk.AccAddress(valOpPk2.Address()) - valAccAddr3 = sdk.AccAddress(valOpPk3.Address()) - - valConsPk1 = ed25519.GenPrivKey().PubKey() - valConsPk2 = ed25519.GenPrivKey().PubKey() - valConsPk3 = ed25519.GenPrivKey().PubKey() - valConsAddr1 = sdk.ConsAddress(valConsPk1.Address()) - valConsAddr2 = sdk.ConsAddress(valConsPk2.Address()) - - // TODO move to common testing package for all modules - // test addresses - TestAddrs = []sdk.AccAddress{ - delAddr1, delAddr2, delAddr3, - valAccAddr1, valAccAddr2, valAccAddr3, - } - pubkeys = []crypto.PubKey{ - delPk1, delPk2, delPk3, valOpPk1, valOpPk2, valOpPk3, - } - - distrAcc = supply.NewEmptyModuleAccount(types.ModuleName) -) - -// create a codec used only for testing -func MakeTestCodec() *codec.Codec { - var cdc = codec.New() - bank.RegisterCodec(cdc) - staking.RegisterCodec(cdc) - auth.RegisterCodec(cdc) - supply.RegisterCodec(cdc) - sdk.RegisterCodec(cdc) - codec.RegisterCrypto(cdc) - - types.RegisterCodec(cdc) // distr - return cdc -} - -// test input with default values -func CreateTestInputDefault(t *testing.T, isCheckTx bool, initPower int64) ( - sdk.Context, auth.AccountKeeper, bank.Keeper, Keeper, staking.Keeper, types.SupplyKeeper) { - - communityTax := sdk.NewDecWithPrec(2, 2) - - ctx, ak, bk, dk, sk, _, supplyKeeper := CreateTestInputAdvanced(t, isCheckTx, initPower, communityTax) - return ctx, ak, bk, dk, sk, supplyKeeper -} - -// hogpodge of all sorts of input required for testing -func CreateTestInputAdvanced( - t *testing.T, isCheckTx bool, initPower int64, communityTax sdk.Dec, -) (sdk.Context, auth.AccountKeeper, bank.Keeper, Keeper, staking.Keeper, keeper.Keeper, types.SupplyKeeper, -) { - - initTokens := sdk.TokensFromConsensusPower(initPower) - - keyBank := sdk.NewKVStoreKey(bank.StoreKey) - keyDistr := sdk.NewKVStoreKey(types.StoreKey) - keyStaking := sdk.NewKVStoreKey(staking.StoreKey) - keyAcc := sdk.NewKVStoreKey(auth.StoreKey) - keySupply := sdk.NewKVStoreKey(supply.StoreKey) - keyParams := sdk.NewKVStoreKey(paramtypes.StoreKey) - tkeyParams := sdk.NewTransientStoreKey(paramtypes.TStoreKey) - - db := dbm.NewMemDB() - ms := store.NewCommitMultiStore(db) - - ms.MountStoreWithDB(keyBank, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(keyDistr, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(keyStaking, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(keySupply, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(keyAcc, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(keyParams, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(tkeyParams, sdk.StoreTypeTransient, db) - - err := ms.LoadLatestVersion() - require.Nil(t, err) - - feeCollectorAcc := supply.NewEmptyModuleAccount(auth.FeeCollectorName) - notBondedPool := supply.NewEmptyModuleAccount(staking.NotBondedPoolName, supply.Burner, supply.Staking) - bondPool := supply.NewEmptyModuleAccount(staking.BondedPoolName, supply.Burner, supply.Staking) - - blacklistedAddrs := make(map[string]bool) - blacklistedAddrs[feeCollectorAcc.GetAddress().String()] = true - blacklistedAddrs[notBondedPool.GetAddress().String()] = true - blacklistedAddrs[bondPool.GetAddress().String()] = true - blacklistedAddrs[distrAcc.GetAddress().String()] = true - - cdc := MakeTestCodec() - appCodec := simappcodec.NewAppCodec(cdc) - pk := keeper.NewKeeper(appCodec, keyParams, tkeyParams) - - ctx := sdk.NewContext(ms, abci.Header{ChainID: "foochainid"}, isCheckTx, log.NewNopLogger()) - accountKeeper := auth.NewAccountKeeper(appCodec, keyAcc, pk.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount) - bankKeeper := bank.NewBaseKeeper(appCodec, keyBank, accountKeeper, pk.Subspace(bank.DefaultParamspace), blacklistedAddrs) - maccPerms := map[string][]string{ - auth.FeeCollectorName: nil, - types.ModuleName: nil, - staking.NotBondedPoolName: {supply.Burner, supply.Staking}, - staking.BondedPoolName: {supply.Burner, supply.Staking}, - } - supplyKeeper := supply.NewKeeper(appCodec, keySupply, accountKeeper, bankKeeper, maccPerms) - - sk := staking.NewKeeper(staking.ModuleCdc, keyStaking, bankKeeper, supplyKeeper, pk.Subspace(staking.DefaultParamspace)) - sk.SetParams(ctx, staking.DefaultParams()) - - keeper := NewKeeper(types.ModuleCdc, keyDistr, pk.Subspace(types.DefaultParamspace), bankKeeper, sk, supplyKeeper, auth.FeeCollectorName, blacklistedAddrs) - - initCoins := sdk.NewCoins(sdk.NewCoin(sk.BondDenom(ctx), initTokens)) - totalSupply := sdk.NewCoins(sdk.NewCoin(sk.BondDenom(ctx), initTokens.MulRaw(int64(len(TestAddrs))))) - supplyKeeper.SetSupply(ctx, supply.NewSupply(totalSupply)) - - // fill all the addresses with some coins, set the loose pool tokens simultaneously - for i, addr := range TestAddrs { - accountKeeper.SetAccount(ctx, auth.NewBaseAccount(addr, pubkeys[i], uint64(i), 0)) - require.NoError(t, bankKeeper.SetBalances(ctx, addr, initCoins)) - } - - // set module accounts - keeper.supplyKeeper.SetModuleAccount(ctx, feeCollectorAcc) - keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) - keeper.supplyKeeper.SetModuleAccount(ctx, bondPool) - keeper.supplyKeeper.SetModuleAccount(ctx, distrAcc) - - // set the distribution hooks on staking - sk.SetHooks(keeper.Hooks()) - - // set genesis items required for distribution - keeper.SetFeePool(ctx, types.InitialFeePool()) - - params := types.DefaultParams() - params.CommunityTax = communityTax - params.BaseProposerReward = sdk.NewDecWithPrec(1, 2) - params.BonusProposerReward = sdk.NewDecWithPrec(4, 2) - keeper.SetParams(ctx, params) - - return ctx, accountKeeper, bankKeeper, keeper, sk, pk, supplyKeeper -} diff --git a/x/distribution/keeper/validator.go b/x/distribution/keeper/validator.go index 6b9711a76443..3ebd6c8c6c6f 100644 --- a/x/distribution/keeper/validator.go +++ b/x/distribution/keeper/validator.go @@ -25,7 +25,7 @@ func (k Keeper) initializeValidator(ctx sdk.Context, val exported.ValidatorI) { } // increment validator period, returning the period just ended -func (k Keeper) incrementValidatorPeriod(ctx sdk.Context, val exported.ValidatorI) uint64 { +func (k Keeper) IncrementValidatorPeriod(ctx sdk.Context, val exported.ValidatorI) uint64 { // fetch current rewards rewards := k.GetValidatorCurrentRewards(ctx, val.GetOperator()) @@ -95,7 +95,7 @@ func (k Keeper) updateValidatorSlashFraction(ctx sdk.Context, valAddr sdk.ValAdd val := k.stakingKeeper.Validator(ctx, valAddr) // increment current period - newPeriod := k.incrementValidatorPeriod(ctx, val) + newPeriod := k.IncrementValidatorPeriod(ctx, val) // increment reference count on period we need to track k.incrementReferenceCount(ctx, valAddr, newPeriod) diff --git a/x/distribution/proposal_handler_test.go b/x/distribution/proposal_handler_test.go index 1f13f15d5240..158c275a9989 100644 --- a/x/distribution/proposal_handler_test.go +++ b/x/distribution/proposal_handler_test.go @@ -1,8 +1,13 @@ -package distribution +package distribution_test import ( "testing" + "github.com/cosmos/cosmos-sdk/x/distribution" + + "github.com/cosmos/cosmos-sdk/simapp" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto/ed25519" "github.com/stretchr/testify/require" @@ -23,45 +28,49 @@ func testProposal(recipient sdk.AccAddress, amount sdk.Coins) types.CommunityPoo } func TestProposalHandlerPassed(t *testing.T) { - ctx, ak, bk, keeper, _, supplyKeeper := CreateTestInputDefault(t, false, 10) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + recipient := delAddr1 // add coins to the module account - macc := keeper.GetDistributionAccount(ctx) - balances := bk.GetAllBalances(ctx, macc.GetAddress()) - err := bk.SetBalances(ctx, macc.GetAddress(), balances.Add(amount...)) + macc := app.DistrKeeper.GetDistributionAccount(ctx) + balances := app.BankKeeper.GetAllBalances(ctx, macc.GetAddress()) + err := app.BankKeeper.SetBalances(ctx, macc.GetAddress(), balances.Add(amount...)) require.NoError(t, err) - supplyKeeper.SetModuleAccount(ctx, macc) + app.SupplyKeeper.SetModuleAccount(ctx, macc) - account := ak.NewAccountWithAddress(ctx, recipient) - ak.SetAccount(ctx, account) - require.True(t, bk.GetAllBalances(ctx, account.GetAddress()).IsZero()) + account := app.AccountKeeper.NewAccountWithAddress(ctx, recipient) + app.AccountKeeper.SetAccount(ctx, account) + require.True(t, app.BankKeeper.GetAllBalances(ctx, account.GetAddress()).IsZero()) - feePool := keeper.GetFeePool(ctx) + feePool := app.DistrKeeper.GetFeePool(ctx) feePool.CommunityPool = sdk.NewDecCoinsFromCoins(amount...) - keeper.SetFeePool(ctx, feePool) + app.DistrKeeper.SetFeePool(ctx, feePool) tp := testProposal(recipient, amount) - hdlr := NewCommunityPoolSpendProposalHandler(keeper) + hdlr := distribution.NewCommunityPoolSpendProposalHandler(app.DistrKeeper) require.NoError(t, hdlr(ctx, tp)) - balances = bk.GetAllBalances(ctx, recipient) + balances = app.BankKeeper.GetAllBalances(ctx, recipient) require.Equal(t, balances, amount) } func TestProposalHandlerFailed(t *testing.T) { - ctx, ak, bk, keeper, _, _ := CreateTestInputDefault(t, false, 10) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + recipient := delAddr1 - account := ak.NewAccountWithAddress(ctx, recipient) - ak.SetAccount(ctx, account) - require.True(t, bk.GetAllBalances(ctx, account.GetAddress()).IsZero()) + account := app.AccountKeeper.NewAccountWithAddress(ctx, recipient) + app.AccountKeeper.SetAccount(ctx, account) + require.True(t, app.BankKeeper.GetAllBalances(ctx, account.GetAddress()).IsZero()) tp := testProposal(recipient, amount) - hdlr := NewCommunityPoolSpendProposalHandler(keeper) + hdlr := distribution.NewCommunityPoolSpendProposalHandler(app.DistrKeeper) require.Error(t, hdlr(ctx, tp)) - balances := bk.GetAllBalances(ctx, recipient) + balances := app.BankKeeper.GetAllBalances(ctx, recipient) require.True(t, balances.IsZero()) } From 3f2f4b984e33d44bf3867f6cc9cba03ff37f0501 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Thu, 5 Mar 2020 09:32:43 -0500 Subject: [PATCH 368/529] Move pkg to std/ --- {simapp/codec => codec/std}/codec.go | 2 +- {simapp/codec => codec/std}/codec.pb.go | 154 ++++++++++++------------ {simapp/codec => codec/std}/codec.proto | 4 +- {simapp/codec => codec/std}/msgs.go | 2 +- x/upgrade/types/types.pb.go | 2 +- 5 files changed, 82 insertions(+), 82 deletions(-) rename {simapp/codec => codec/std}/codec.go (99%) rename {simapp/codec => codec/std}/codec.pb.go (91%) rename {simapp/codec => codec/std}/codec.proto (97%) rename {simapp/codec => codec/std}/msgs.go (99%) diff --git a/simapp/codec/codec.go b/codec/std/codec.go similarity index 99% rename from simapp/codec/codec.go rename to codec/std/codec.go index 75dd59fb3512..ce56ee61bca8 100644 --- a/simapp/codec/codec.go +++ b/codec/std/codec.go @@ -1,4 +1,4 @@ -package codec +package std import ( "github.com/cosmos/cosmos-sdk/codec" diff --git a/simapp/codec/codec.pb.go b/codec/std/codec.pb.go similarity index 91% rename from simapp/codec/codec.pb.go rename to codec/std/codec.pb.go index 1fff6fa8143e..ef4c65543df1 100644 --- a/simapp/codec/codec.pb.go +++ b/codec/std/codec.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: simapp/codec/codec.proto +// source: codec/std/codec.proto -package codec +package std import ( fmt "fmt" @@ -53,7 +53,7 @@ func (m *Account) Reset() { *m = Account{} } func (m *Account) String() string { return proto.CompactTextString(m) } func (*Account) ProtoMessage() {} func (*Account) Descriptor() ([]byte, []int) { - return fileDescriptor_3c6d4085e4065f5a, []int{0} + return fileDescriptor_daf09dc2dfa19bb4, []int{0} } func (m *Account) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -176,7 +176,7 @@ func (m *Supply) Reset() { *m = Supply{} } func (m *Supply) String() string { return proto.CompactTextString(m) } func (*Supply) ProtoMessage() {} func (*Supply) Descriptor() ([]byte, []int) { - return fileDescriptor_3c6d4085e4065f5a, []int{1} + return fileDescriptor_daf09dc2dfa19bb4, []int{1} } func (m *Supply) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -253,7 +253,7 @@ func (m *Evidence) Reset() { *m = Evidence{} } func (m *Evidence) String() string { return proto.CompactTextString(m) } func (*Evidence) ProtoMessage() {} func (*Evidence) Descriptor() ([]byte, []int) { - return fileDescriptor_3c6d4085e4065f5a, []int{2} + return fileDescriptor_daf09dc2dfa19bb4, []int{2} } func (m *Evidence) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -327,7 +327,7 @@ func (m *MsgSubmitEvidence) Reset() { *m = MsgSubmitEvidence{} } func (m *MsgSubmitEvidence) String() string { return proto.CompactTextString(m) } func (*MsgSubmitEvidence) ProtoMessage() {} func (*MsgSubmitEvidence) Descriptor() ([]byte, []int) { - return fileDescriptor_3c6d4085e4065f5a, []int{3} + return fileDescriptor_daf09dc2dfa19bb4, []int{3} } func (m *MsgSubmitEvidence) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -367,7 +367,7 @@ func (m *MsgSubmitProposal) Reset() { *m = MsgSubmitProposal{} } func (m *MsgSubmitProposal) String() string { return proto.CompactTextString(m) } func (*MsgSubmitProposal) ProtoMessage() {} func (*MsgSubmitProposal) Descriptor() ([]byte, []int) { - return fileDescriptor_3c6d4085e4065f5a, []int{4} + return fileDescriptor_daf09dc2dfa19bb4, []int{4} } func (m *MsgSubmitProposal) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -407,7 +407,7 @@ func (m *Proposal) Reset() { *m = Proposal{} } func (m *Proposal) String() string { return proto.CompactTextString(m) } func (*Proposal) ProtoMessage() {} func (*Proposal) Descriptor() ([]byte, []int) { - return fileDescriptor_3c6d4085e4065f5a, []int{5} + return fileDescriptor_daf09dc2dfa19bb4, []int{5} } func (m *Proposal) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -461,7 +461,7 @@ func (m *Content) Reset() { *m = Content{} } func (m *Content) String() string { return proto.CompactTextString(m) } func (*Content) ProtoMessage() {} func (*Content) Descriptor() ([]byte, []int) { - return fileDescriptor_3c6d4085e4065f5a, []int{6} + return fileDescriptor_daf09dc2dfa19bb4, []int{6} } func (m *Content) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -573,74 +573,74 @@ func (*Content) XXX_OneofWrappers() []interface{} { } func init() { - proto.RegisterType((*Account)(nil), "cosmos_sdk.simapp.codec.v1.Account") - proto.RegisterType((*Supply)(nil), "cosmos_sdk.simapp.codec.v1.Supply") - proto.RegisterType((*Evidence)(nil), "cosmos_sdk.simapp.codec.v1.Evidence") - proto.RegisterType((*MsgSubmitEvidence)(nil), "cosmos_sdk.simapp.codec.v1.MsgSubmitEvidence") - proto.RegisterType((*MsgSubmitProposal)(nil), "cosmos_sdk.simapp.codec.v1.MsgSubmitProposal") - proto.RegisterType((*Proposal)(nil), "cosmos_sdk.simapp.codec.v1.Proposal") - proto.RegisterType((*Content)(nil), "cosmos_sdk.simapp.codec.v1.Content") -} - -func init() { proto.RegisterFile("simapp/codec/codec.proto", fileDescriptor_3c6d4085e4065f5a) } - -var fileDescriptor_3c6d4085e4065f5a = []byte{ - // 878 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0x41, 0x6f, 0xdc, 0x44, - 0x14, 0xb6, 0xa9, 0x9b, 0xac, 0xa6, 0x05, 0xca, 0x88, 0x92, 0xd5, 0x82, 0x76, 0xdb, 0x14, 0x2a, - 0x28, 0x8a, 0xdd, 0x52, 0xa0, 0xe9, 0x4a, 0xa8, 0x74, 0x97, 0xa2, 0x45, 0x22, 0x28, 0xda, 0x00, - 0x07, 0x04, 0xb2, 0xbc, 0xe3, 0xc1, 0x6b, 0xd5, 0xf6, 0x0c, 0x9e, 0xb1, 0xf1, 0xfe, 0x03, 0xc4, - 0x89, 0x13, 0xe7, 0x88, 0x03, 0x47, 0x4e, 0x39, 0xf2, 0x03, 0xa2, 0x9c, 0x72, 0xe4, 0x14, 0xa1, - 0xe4, 0xc2, 0xcf, 0x40, 0x9e, 0x19, 0x7b, 0x6d, 0xd9, 0xbb, 0x91, 0x7a, 0xb1, 0xd6, 0xf3, 0xbe, - 0xef, 0x7d, 0xdf, 0x78, 0xe6, 0xbd, 0xb7, 0xa0, 0xcb, 0xfc, 0xd0, 0xa1, 0xd4, 0x42, 0xc4, 0xc5, - 0x48, 0x3e, 0x4d, 0x1a, 0x13, 0x4e, 0x60, 0x0f, 0x11, 0x16, 0x12, 0x66, 0x33, 0xf7, 0xb9, 0x29, - 0x41, 0xa6, 0x0c, 0xa7, 0x0f, 0x7a, 0xef, 0xf3, 0xb9, 0x1f, 0xbb, 0x36, 0x75, 0x62, 0xbe, 0xb0, - 0x04, 0xdc, 0x92, 0xe8, 0x9d, 0xea, 0x8b, 0x4c, 0xd4, 0xbb, 0xdb, 0x04, 0x7b, 0xc4, 0x23, 0xcb, - 0x5f, 0x0a, 0xd7, 0xcd, 0x2c, 0x27, 0xe1, 0x73, 0x8b, 0x2f, 0x28, 0x66, 0xf2, 0xa9, 0x22, 0xb7, - 0x54, 0x24, 0xc5, 0x8c, 0xfb, 0x91, 0xd7, 0x82, 0xe8, 0x65, 0x16, 0x4b, 0x28, 0x0d, 0x16, 0x2d, - 0xb1, 0xb7, 0x32, 0x0b, 0xa7, 0xbe, 0x8b, 0x23, 0x84, 0x5b, 0xa2, 0x5b, 0x99, 0xe5, 0x91, 0xb4, - 0x25, 0x70, 0x27, 0xb3, 0xa8, 0x13, 0x3b, 0xa1, 0x5a, 0xcd, 0x9d, 0x53, 0xc2, 0x9c, 0xa0, 0x06, - 0x7a, 0x33, 0xb3, 0x12, 0xea, 0xc5, 0x8e, 0x8b, 0xdb, 0x6d, 0xbb, 0x3e, 0xe3, 0xb1, 0x3f, 0x4b, - 0xb8, 0x4f, 0xa2, 0x26, 0x62, 0xfb, 0x6f, 0x03, 0x6c, 0x3e, 0x45, 0x88, 0x24, 0x11, 0x87, 0x9f, - 0x83, 0xeb, 0x33, 0x87, 0x61, 0xdb, 0x91, 0xef, 0x5d, 0xfd, 0x96, 0xfe, 0xee, 0xb5, 0x0f, 0x6e, - 0x9b, 0x95, 0x63, 0xc8, 0xcc, 0xfc, 0x33, 0x98, 0xe9, 0x03, 0x73, 0xe4, 0x30, 0xac, 0x88, 0x13, - 0x6d, 0x7a, 0x6d, 0xb6, 0x7c, 0x85, 0x29, 0xe8, 0x21, 0x12, 0x71, 0x3f, 0x4a, 0x48, 0xc2, 0x6c, - 0xf5, 0xc9, 0xca, 0xac, 0x2f, 0x89, 0xac, 0x1f, 0xb7, 0x65, 0x95, 0xc8, 0x3c, 0xfb, 0xb8, 0xe4, - 0x7f, 0x2b, 0x17, 0x97, 0x52, 0x5d, 0xb4, 0x22, 0x06, 0x43, 0xb0, 0xe5, 0xe2, 0xc0, 0x59, 0x60, - 0xb7, 0x21, 0x7a, 0x45, 0x88, 0x3e, 0x5c, 0x2f, 0xfa, 0x99, 0x24, 0x37, 0x14, 0x6f, 0xba, 0x6d, - 0x01, 0x48, 0x41, 0x97, 0xe2, 0xd8, 0x27, 0xae, 0x8f, 0x1a, 0x7a, 0x86, 0xd0, 0xfb, 0x70, 0xbd, - 0xde, 0xbe, 0x62, 0x37, 0x04, 0xdf, 0xa0, 0xad, 0x11, 0xf8, 0x15, 0x78, 0x25, 0x24, 0x6e, 0x12, - 0x2c, 0x8f, 0xe8, 0xaa, 0xd0, 0x79, 0xa7, 0xae, 0x23, 0xef, 0x61, 0xae, 0xb0, 0x27, 0xd0, 0xcb, - 0xc4, 0x2f, 0x87, 0xd5, 0x85, 0xe1, 0xe3, 0x93, 0xa3, 0x9d, 0x8f, 0xee, 0x79, 0x3e, 0x9f, 0x27, - 0x33, 0x13, 0x91, 0x50, 0x55, 0x4d, 0x51, 0x49, 0xcc, 0x7d, 0x6e, 0xa9, 0x7b, 0x8f, 0x33, 0x4a, - 0x62, 0x8e, 0x5d, 0x53, 0x51, 0x47, 0x57, 0xc1, 0x15, 0x96, 0x84, 0xdb, 0xbf, 0xea, 0x60, 0xe3, - 0x40, 0xc8, 0xc1, 0x5d, 0xb0, 0x21, 0x85, 0xd5, 0xbd, 0xe9, 0xaf, 0x32, 0x25, 0xf1, 0x13, 0x6d, - 0xaa, 0xf0, 0xc3, 0x27, 0xff, 0x1d, 0x0e, 0xf4, 0x93, 0xa3, 0x9d, 0x47, 0x97, 0x59, 0x51, 0x05, - 0x56, 0x9a, 0x91, 0x99, 0xbe, 0x28, 0xcc, 0xfc, 0xa1, 0x83, 0xce, 0x33, 0x55, 0x67, 0xf0, 0x4b, - 0x70, 0x1d, 0xff, 0x94, 0xf8, 0x29, 0x41, 0x4e, 0x7e, 0xf5, 0x95, 0xa9, 0xbb, 0x75, 0x53, 0x45, - 0x55, 0xe6, 0xb6, 0x9e, 0x55, 0xd0, 0x13, 0x6d, 0x5a, 0x63, 0x0f, 0x9f, 0x2a, 0x8b, 0x8f, 0x2f, - 0x71, 0x58, 0x96, 0x79, 0xe9, 0xb1, 0x30, 0x54, 0x98, 0xfc, 0x4b, 0x07, 0xaf, 0xed, 0x31, 0xef, - 0x20, 0x99, 0x85, 0x3e, 0x2f, 0xdd, 0x7e, 0x0a, 0x3a, 0x05, 0x55, 0x39, 0x7d, 0xdb, 0x5c, 0xdd, - 0xfd, 0xca, 0xa4, 0xd3, 0x92, 0x05, 0xf7, 0x80, 0x91, 0xd7, 0xa0, 0x2a, 0x2f, 0x6b, 0xf5, 0x3e, - 0x1b, 0xe2, 0x79, 0x25, 0x8f, 0x3a, 0xc7, 0x67, 0x03, 0xed, 0xf4, 0x6c, 0xa0, 0x4f, 0x45, 0x9a, - 0x61, 0xe7, 0x97, 0xc3, 0x81, 0x96, 0x6f, 0x7a, 0xfb, 0xcf, 0xaa, 0xe1, 0x7d, 0xd5, 0x82, 0xe0, - 0x44, 0xc9, 0x49, 0xb3, 0xf7, 0xea, 0x72, 0x1e, 0x49, 0x6b, 0x4a, 0x05, 0xab, 0x4d, 0x09, 0x7e, - 0x02, 0x36, 0xf3, 0x8a, 0xc6, 0x65, 0x6b, 0xb8, 0xb3, 0x6e, 0xe7, 0x63, 0x09, 0x9d, 0x16, 0x9c, - 0x8a, 0xd1, 0xdf, 0x75, 0xd0, 0x29, 0xfd, 0x3d, 0xa9, 0xf9, 0xbb, 0xdd, 0xea, 0x6f, 0xad, 0xad, - 0xf1, 0x8b, 0xd8, 0x1a, 0x19, 0x79, 0x96, 0xa5, 0x39, 0x43, 0x18, 0x3b, 0x34, 0xc0, 0xa6, 0x02, - 0xc0, 0x47, 0xc0, 0xe0, 0x38, 0xe3, 0x6b, 0x7d, 0x7d, 0x8d, 0xb3, 0xf2, 0x93, 0x4d, 0xb4, 0xa9, - 0x20, 0xc0, 0xef, 0xc1, 0x0d, 0x31, 0x0c, 0x30, 0xc7, 0xb1, 0x8d, 0xe6, 0x4e, 0xe4, 0xad, 0x38, - 0x6b, 0x39, 0x32, 0xc4, 0xfe, 0x0a, 0xfc, 0x58, 0xc0, 0x2b, 0x29, 0x5f, 0xa5, 0xf5, 0x10, 0xfc, - 0x01, 0xdc, 0x60, 0xe4, 0x47, 0xfe, 0xb3, 0x13, 0x63, 0x5b, 0x8d, 0x13, 0xd5, 0x33, 0xef, 0xd7, - 0xb3, 0xab, 0xa0, 0xa8, 0x63, 0x45, 0xf8, 0x46, 0x2e, 0x55, 0xd3, 0xb3, 0x7a, 0x08, 0x52, 0xb0, - 0x85, 0x9c, 0x08, 0xe1, 0xc0, 0x6e, 0xa8, 0x18, 0x6d, 0xe3, 0xa0, 0xa2, 0x32, 0x16, 0xbc, 0xd5, - 0x5a, 0x37, 0x51, 0x1b, 0x00, 0x06, 0xe0, 0x75, 0x44, 0xc2, 0x30, 0x89, 0x7c, 0xbe, 0xb0, 0x29, - 0x21, 0x81, 0xcd, 0x28, 0x8e, 0x5c, 0xd5, 0x30, 0x77, 0xeb, 0x72, 0xd5, 0x19, 0x29, 0x4f, 0x53, - 0x31, 0xf7, 0x09, 0x09, 0x0e, 0x72, 0x5e, 0x45, 0x10, 0xa2, 0x46, 0x74, 0xb8, 0xab, 0xda, 0xc3, - 0xfd, 0x4b, 0xda, 0x43, 0x39, 0xe7, 0xcb, 0x0b, 0x23, 0xbb, 0xc2, 0x68, 0x7c, 0x7c, 0xde, 0xd7, - 0x4f, 0xcf, 0xfb, 0xfa, 0xbf, 0xe7, 0x7d, 0xfd, 0xb7, 0x8b, 0xbe, 0x76, 0x7a, 0xd1, 0xd7, 0xfe, - 0xb9, 0xe8, 0x6b, 0xdf, 0xbd, 0xb7, 0x36, 0x65, 0xf5, 0xbf, 0xd3, 0x6c, 0x43, 0x8c, 0xf4, 0x87, - 0xff, 0x07, 0x00, 0x00, 0xff, 0xff, 0x70, 0x52, 0xf3, 0x25, 0x52, 0x09, 0x00, 0x00, + proto.RegisterType((*Account)(nil), "cosmos_sdk.codec.std.v1.Account") + proto.RegisterType((*Supply)(nil), "cosmos_sdk.codec.std.v1.Supply") + proto.RegisterType((*Evidence)(nil), "cosmos_sdk.codec.std.v1.Evidence") + proto.RegisterType((*MsgSubmitEvidence)(nil), "cosmos_sdk.codec.std.v1.MsgSubmitEvidence") + proto.RegisterType((*MsgSubmitProposal)(nil), "cosmos_sdk.codec.std.v1.MsgSubmitProposal") + proto.RegisterType((*Proposal)(nil), "cosmos_sdk.codec.std.v1.Proposal") + proto.RegisterType((*Content)(nil), "cosmos_sdk.codec.std.v1.Content") +} + +func init() { proto.RegisterFile("codec/std/codec.proto", fileDescriptor_daf09dc2dfa19bb4) } + +var fileDescriptor_daf09dc2dfa19bb4 = []byte{ + // 875 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x56, 0x41, 0x6f, 0xdc, 0x44, + 0x14, 0xb6, 0xa9, 0x9b, 0xac, 0xa6, 0x05, 0xca, 0x88, 0x90, 0x28, 0xa0, 0x4d, 0x1a, 0x44, 0x84, + 0x8a, 0x62, 0xb7, 0x14, 0x68, 0xba, 0x12, 0x6a, 0xbb, 0x4b, 0xd1, 0x22, 0x11, 0x14, 0x6d, 0x80, + 0x03, 0x02, 0x59, 0xde, 0x99, 0xc1, 0x6b, 0xd5, 0xf6, 0x0c, 0x9e, 0xb1, 0xf1, 0xfe, 0x03, 0xc4, + 0x09, 0x89, 0x3f, 0x10, 0xc1, 0x91, 0x6b, 0x8f, 0xfc, 0x80, 0xaa, 0xa7, 0x1c, 0x39, 0x55, 0x28, + 0xb9, 0xf0, 0x33, 0x90, 0x67, 0xc6, 0x5e, 0x5b, 0xf6, 0x6e, 0xd4, 0xcb, 0xca, 0x9e, 0xf7, 0x7d, + 0xef, 0xfb, 0xc6, 0x33, 0xef, 0xbd, 0x05, 0x1b, 0x88, 0x62, 0x82, 0x1c, 0x2e, 0xb0, 0x23, 0x9f, + 0x6c, 0x96, 0x50, 0x41, 0xe1, 0x26, 0xa2, 0x3c, 0xa2, 0xdc, 0xe5, 0xf8, 0x89, 0xad, 0xd6, 0xb9, + 0xc0, 0x76, 0x76, 0x67, 0xfb, 0x03, 0x31, 0x0b, 0x12, 0xec, 0x32, 0x2f, 0x11, 0x73, 0x47, 0x62, + 0x1d, 0x05, 0x3d, 0xa8, 0xbf, 0xa8, 0x2c, 0xdb, 0xfb, 0x6d, 0xb0, 0x4f, 0x7d, 0xba, 0x78, 0xd2, + 0xb8, 0xad, 0xdc, 0xf1, 0x52, 0x31, 0x73, 0xc4, 0x9c, 0x11, 0xae, 0x7e, 0x75, 0x64, 0x57, 0x47, + 0x32, 0xc2, 0x45, 0x10, 0xfb, 0x1d, 0x88, 0xed, 0xdc, 0xe1, 0x29, 0x63, 0xe1, 0xbc, 0x23, 0xf6, + 0x4e, 0xee, 0x90, 0x2c, 0xc0, 0x24, 0x46, 0xa4, 0x23, 0xba, 0x99, 0x3b, 0x3e, 0xcd, 0x3a, 0x02, + 0xef, 0xe6, 0x0e, 0xf3, 0x12, 0x2f, 0xd2, 0xab, 0x85, 0x73, 0x46, 0xb9, 0x17, 0x36, 0x40, 0x6f, + 0xe7, 0x4e, 0xca, 0xfc, 0xc4, 0xc3, 0xa4, 0xdb, 0x36, 0x0e, 0xb8, 0x48, 0x82, 0x69, 0x2a, 0x02, + 0x1a, 0xb7, 0x11, 0x7b, 0x7f, 0x5b, 0x60, 0xfd, 0x11, 0x42, 0x34, 0x8d, 0x05, 0xfc, 0x1c, 0x5c, + 0x9f, 0x7a, 0x9c, 0xb8, 0x9e, 0x7a, 0xdf, 0x32, 0x77, 0xcd, 0xf7, 0xaf, 0x7d, 0x78, 0xd3, 0xae, + 0x9d, 0x41, 0x6e, 0x17, 0x9f, 0xc1, 0xce, 0xee, 0xd8, 0x43, 0x8f, 0x13, 0x4d, 0x1c, 0x1b, 0x93, + 0x6b, 0xd3, 0xc5, 0x2b, 0xcc, 0xc0, 0x36, 0xa2, 0xb1, 0x08, 0xe2, 0x94, 0xa6, 0xdc, 0xd5, 0x9f, + 0xac, 0xca, 0xfa, 0x8a, 0xcc, 0xfa, 0x49, 0x57, 0x56, 0x85, 0x2c, 0xb2, 0x8f, 0x2a, 0xfe, 0xb7, + 0x6a, 0x71, 0x21, 0xb5, 0x85, 0x96, 0xc4, 0x60, 0x04, 0x36, 0x31, 0x09, 0xbd, 0x39, 0xc1, 0x2d, + 0xd1, 0x2b, 0x52, 0xf4, 0xee, 0x6a, 0xd1, 0xcf, 0x14, 0xb9, 0xa5, 0xb8, 0x81, 0xbb, 0x02, 0x90, + 0x81, 0x2d, 0x46, 0x92, 0x80, 0xe2, 0x00, 0xb5, 0xf4, 0x2c, 0xa9, 0xf7, 0xd1, 0x6a, 0xbd, 0x63, + 0xcd, 0x6e, 0x09, 0xbe, 0xc5, 0x3a, 0x23, 0xf0, 0x2b, 0xf0, 0x5a, 0x44, 0x71, 0x1a, 0x2e, 0x8e, + 0xe8, 0xaa, 0xd4, 0x79, 0xaf, 0xa9, 0xa3, 0xee, 0x61, 0xa1, 0x70, 0x24, 0xd1, 0x8b, 0xc4, 0xaf, + 0x46, 0xf5, 0x85, 0xc1, 0xfd, 0xe7, 0x4f, 0x0f, 0x3e, 0xbe, 0xe5, 0x07, 0x62, 0x96, 0x4e, 0x6d, + 0x44, 0x23, 0x5d, 0x35, 0x65, 0x25, 0x71, 0xfc, 0xc4, 0xd1, 0xf7, 0x9e, 0xe4, 0x8c, 0x26, 0x82, + 0x60, 0x5b, 0x53, 0x87, 0x57, 0xc1, 0x15, 0x9e, 0x46, 0x7b, 0xbf, 0x9a, 0x60, 0xed, 0x44, 0xca, + 0xc1, 0x43, 0xb0, 0xa6, 0x84, 0xf5, 0xbd, 0xe9, 0x2f, 0x33, 0xa5, 0xf0, 0x63, 0x63, 0xa2, 0xf1, + 0x83, 0x07, 0xff, 0x9d, 0xee, 0x98, 0xcf, 0x9f, 0x1e, 0xdc, 0xbb, 0xcc, 0x8a, 0x2e, 0xb0, 0xca, + 0x8c, 0xca, 0xf4, 0x45, 0x69, 0xe6, 0x0f, 0x13, 0xf4, 0x1e, 0xeb, 0x3a, 0x83, 0x5f, 0x82, 0xeb, + 0xe4, 0xa7, 0x34, 0xc8, 0x28, 0xf2, 0x8a, 0xab, 0xaf, 0x4d, 0xed, 0x37, 0x4d, 0x95, 0x55, 0x59, + 0xd8, 0x7a, 0x5c, 0x43, 0x8f, 0x8d, 0x49, 0x83, 0x3d, 0x78, 0xa4, 0x2d, 0xde, 0xbf, 0xc4, 0x61, + 0x55, 0xe6, 0x95, 0xc7, 0xd2, 0x50, 0x69, 0xf2, 0x2f, 0x13, 0xbc, 0x71, 0xc4, 0xfd, 0x93, 0x74, + 0x1a, 0x05, 0xa2, 0x72, 0xfb, 0x29, 0xe8, 0x95, 0xd4, 0xae, 0xb2, 0xab, 0xb7, 0xbe, 0x2a, 0xe3, + 0xa4, 0xa2, 0xc0, 0x23, 0x60, 0x15, 0x05, 0xa8, 0x6b, 0xcb, 0x59, 0xbe, 0xc9, 0x96, 0x72, 0x51, + 0xc6, 0xc3, 0xde, 0xb3, 0x17, 0x3b, 0xc6, 0xd9, 0x8b, 0x1d, 0x73, 0x22, 0xd3, 0x0c, 0x7a, 0xbf, + 0x9c, 0xee, 0x18, 0xc5, 0x8e, 0xf7, 0xfe, 0xac, 0xbb, 0x3d, 0xd6, 0xfd, 0x07, 0x8e, 0xb5, 0x9c, + 0x72, 0x7a, 0xab, 0x29, 0xe7, 0xd3, 0xac, 0xa1, 0x54, 0xb2, 0xba, 0x94, 0xe0, 0x00, 0xac, 0x17, + 0xe5, 0x4c, 0xaa, 0xbe, 0xb0, 0xbb, 0x74, 0xdb, 0x23, 0x85, 0x9b, 0x94, 0x84, 0x9a, 0xcb, 0xdf, + 0x4d, 0xd0, 0xab, 0xcc, 0x3d, 0x68, 0x98, 0xbb, 0xd9, 0x69, 0x6e, 0xa5, 0xa7, 0x87, 0x2f, 0xed, + 0x69, 0x68, 0x15, 0x29, 0x16, 0xce, 0x2c, 0xe9, 0xea, 0xd4, 0x02, 0xeb, 0x1a, 0x00, 0xef, 0x01, + 0x4b, 0x90, 0x5c, 0xac, 0x34, 0xf5, 0x35, 0xc9, 0xab, 0x8f, 0x35, 0x36, 0x26, 0x92, 0x00, 0xbf, + 0x07, 0x37, 0xe4, 0x0c, 0x20, 0x82, 0x24, 0x2e, 0x9a, 0x79, 0xb1, 0xbf, 0xe4, 0x94, 0xd5, 0xa4, + 0x90, 0x9b, 0x2b, 0xf1, 0x23, 0x09, 0xaf, 0xa5, 0x7c, 0x9d, 0x35, 0x43, 0xf0, 0x07, 0x70, 0x83, + 0xd3, 0x1f, 0xc5, 0xcf, 0x5e, 0x42, 0x5c, 0x3d, 0x45, 0x74, 0xab, 0xbc, 0xdd, 0xcc, 0xae, 0x83, + 0xb2, 0x7c, 0x35, 0xe1, 0x1b, 0xb5, 0x54, 0x4f, 0xcf, 0x9b, 0x21, 0xc8, 0xc0, 0x26, 0xf2, 0x62, + 0x44, 0x42, 0xb7, 0xa5, 0x62, 0x75, 0x4d, 0x81, 0x9a, 0xca, 0x48, 0xf2, 0x96, 0x6b, 0x6d, 0xa0, + 0x2e, 0x00, 0x0c, 0xc1, 0x9b, 0x88, 0x46, 0x51, 0x1a, 0x07, 0x62, 0xee, 0x32, 0x4a, 0x43, 0x97, + 0x33, 0x12, 0x63, 0xdd, 0x27, 0x0f, 0x9b, 0x72, 0xf5, 0xd1, 0xa8, 0x4e, 0x53, 0x33, 0x8f, 0x29, + 0x0d, 0x4f, 0x0a, 0x5e, 0x4d, 0x10, 0xa2, 0x56, 0x74, 0x70, 0xa8, 0xbb, 0xc2, 0xed, 0x4b, 0xba, + 0x42, 0x35, 0xde, 0xab, 0x0b, 0xa3, 0x9a, 0xc1, 0xf0, 0xe1, 0xb3, 0xf3, 0xbe, 0x79, 0x76, 0xde, + 0x37, 0xff, 0x3d, 0xef, 0x9b, 0xbf, 0x5d, 0xf4, 0x8d, 0xb3, 0x8b, 0xbe, 0xf1, 0xcf, 0x45, 0xdf, + 0xf8, 0x6e, 0x7f, 0x65, 0xca, 0xea, 0xcf, 0xd2, 0x74, 0x4d, 0x8e, 0xf1, 0xbb, 0xff, 0x07, 0x00, + 0x00, 0xff, 0xff, 0xf7, 0xf2, 0xb6, 0xa2, 0x40, 0x09, 0x00, 0x00, } func (this *Supply) Equal(that interface{}) bool { diff --git a/simapp/codec/codec.proto b/codec/std/codec.proto similarity index 97% rename from simapp/codec/codec.proto rename to codec/std/codec.proto index 620370d3429e..94297308ac73 100644 --- a/simapp/codec/codec.proto +++ b/codec/std/codec.proto @@ -1,5 +1,5 @@ syntax = "proto3"; -package cosmos_sdk.simapp.codec.v1; +package cosmos_sdk.codec.std.v1; import "third_party/proto/cosmos-proto/cosmos.proto"; import "third_party/proto/gogoproto/gogo.proto"; @@ -12,7 +12,7 @@ import "x/params/types/proposal/types.proto"; import "x/upgrade/types/types.proto"; import "x/distribution/types/types.proto"; -option go_package = "github.com/cosmos/cosmos-sdk/simapp/codec"; +option go_package = "github.com/cosmos/cosmos-sdk/codec/std"; // Account defines the application-level Account type. message Account { diff --git a/simapp/codec/msgs.go b/codec/std/msgs.go similarity index 99% rename from simapp/codec/msgs.go rename to codec/std/msgs.go index 5c4599d8d5fc..4d15d8143c55 100644 --- a/simapp/codec/msgs.go +++ b/codec/std/msgs.go @@ -1,4 +1,4 @@ -package codec +package std import ( sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/x/upgrade/types/types.pb.go b/x/upgrade/types/types.pb.go index f8c8f1ffd974..c0cb0cf18de7 100644 --- a/x/upgrade/types/types.pb.go +++ b/x/upgrade/types/types.pb.go @@ -117,7 +117,7 @@ func (m *SoftwareUpgradeProposal) XXX_DiscardUnknown() { var xxx_messageInfo_SoftwareUpgradeProposal proto.InternalMessageInfo -// SoftwareUpgradeProposal is a gov Content type for cancelling a software upgrade +// CancelSoftwareUpgradeProposal is a gov Content type for cancelling a software upgrade type CancelSoftwareUpgradeProposal struct { Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` From 4dac1abebf5d1c20ef3603c71c095296cf149827 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Thu, 5 Mar 2020 09:40:43 -0500 Subject: [PATCH 369/529] Update imports --- simapp/app.go | 7 +++---- simapp/genesis.go | 5 ++--- simapp/utils_test.go | 4 ++-- x/auth/types/common_test.go | 4 ++-- x/auth/vesting/types/common_test.go | 4 ++-- x/evidence/handler_test.go | 10 +++++----- x/evidence/keeper/keeper_test.go | 4 ++-- x/evidence/keeper/querier_test.go | 10 +++++----- x/evidence/types/codec_test.go | 4 ++-- x/evidence/types/msgs_test.go | 6 +++--- x/gov/abci_test.go | 12 ++++++------ x/gov/keeper/common_test.go | 4 ++-- x/gov/keeper/querier_test.go | 6 +++--- x/staking/common_test.go | 4 ++-- x/staking/keeper/common_test.go | 4 ++-- x/supply/keeper/bank_test.go | 8 ++++---- x/supply/keeper/keeper_test.go | 4 ++-- 17 files changed, 49 insertions(+), 51 deletions(-) diff --git a/simapp/app.go b/simapp/app.go index 5408bcfe919e..f6ee16948413 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -11,7 +11,7 @@ import ( bam "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/codec" - simappcodec "github.com/cosmos/cosmos-sdk/simapp/codec" + codecstd "github.com/cosmos/cosmos-sdk/codec/std" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/version" @@ -126,9 +126,8 @@ func NewSimApp( ) *SimApp { // TODO: Remove cdc in favor of appCodec once all modules are migrated. - cdc := simappcodec.MakeCodec(ModuleBasics) - - appCodec := simappcodec.NewAppCodec(cdc) + cdc := codecstd.MakeCodec(ModuleBasics) + appCodec := codecstd.NewAppCodec(cdc) bApp := bam.NewBaseApp(appName, logger, db, auth.DefaultTxDecoder(cdc), baseAppOptions...) bApp.SetCommitMultiStoreTracer(traceStore) diff --git a/simapp/genesis.go b/simapp/genesis.go index 1a760e3e49a6..c7432aab1f4f 100644 --- a/simapp/genesis.go +++ b/simapp/genesis.go @@ -3,7 +3,7 @@ package simapp import ( "encoding/json" - simappcodec "github.com/cosmos/cosmos-sdk/simapp/codec" + codecstd "github.com/cosmos/cosmos-sdk/codec/std" ) // The genesis state of the blockchain is represented here as a map of raw json @@ -17,7 +17,6 @@ type GenesisState map[string]json.RawMessage // NewDefaultGenesisState generates the default state for the application. func NewDefaultGenesisState() GenesisState { - cdc := simappcodec.MakeCodec(ModuleBasics) - + cdc := codecstd.MakeCodec(ModuleBasics) return ModuleBasics.DefaultGenesis(cdc) } diff --git a/simapp/utils_test.go b/simapp/utils_test.go index b6d5fa1f358a..710c2b9d4863 100644 --- a/simapp/utils_test.go +++ b/simapp/utils_test.go @@ -8,13 +8,13 @@ import ( tmkv "github.com/tendermint/tendermint/libs/kv" "github.com/cosmos/cosmos-sdk/codec" - simappcodec "github.com/cosmos/cosmos-sdk/simapp/codec" + codecstd "github.com/cosmos/cosmos-sdk/codec/std" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" ) func TestGetSimulationLog(t *testing.T) { - cdc := simappcodec.MakeCodec(ModuleBasics) + cdc := codecstd.MakeCodec(ModuleBasics) decoders := make(sdk.StoreDecoderRegistry) decoders[auth.StoreKey] = func(cdc *codec.Codec, kvAs, kvBs tmkv.Pair) string { return "10" } diff --git a/x/auth/types/common_test.go b/x/auth/types/common_test.go index 02b80ac6aa6d..70214acb3795 100644 --- a/x/auth/types/common_test.go +++ b/x/auth/types/common_test.go @@ -1,11 +1,11 @@ package types_test import ( + codecstd "github.com/cosmos/cosmos-sdk/codec/std" "github.com/cosmos/cosmos-sdk/simapp" - simappcodec "github.com/cosmos/cosmos-sdk/simapp/codec" ) var ( app = simapp.Setup(false) - appCodec = simappcodec.NewAppCodec(app.Codec()) + appCodec = codecstd.NewAppCodec(app.Codec()) ) diff --git a/x/auth/vesting/types/common_test.go b/x/auth/vesting/types/common_test.go index 02b80ac6aa6d..70214acb3795 100644 --- a/x/auth/vesting/types/common_test.go +++ b/x/auth/vesting/types/common_test.go @@ -1,11 +1,11 @@ package types_test import ( + codecstd "github.com/cosmos/cosmos-sdk/codec/std" "github.com/cosmos/cosmos-sdk/simapp" - simappcodec "github.com/cosmos/cosmos-sdk/simapp/codec" ) var ( app = simapp.Setup(false) - appCodec = simappcodec.NewAppCodec(app.Codec()) + appCodec = codecstd.NewAppCodec(app.Codec()) ) diff --git a/x/evidence/handler_test.go b/x/evidence/handler_test.go index 60e883364ac3..9f7cc11918ec 100644 --- a/x/evidence/handler_test.go +++ b/x/evidence/handler_test.go @@ -10,8 +10,8 @@ import ( abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto/ed25519" + codecstd "github.com/cosmos/cosmos-sdk/codec/std" "github.com/cosmos/cosmos-sdk/simapp" - simappcodec "github.com/cosmos/cosmos-sdk/simapp/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/evidence" "github.com/cosmos/cosmos-sdk/x/evidence/exported" @@ -25,8 +25,8 @@ type HandlerTestSuite struct { app *simapp.SimApp } -func testMsgSubmitEvidence(r *require.Assertions, e exported.Evidence, s sdk.AccAddress) simappcodec.MsgSubmitEvidence { - msg, err := simappcodec.NewMsgSubmitEvidence(e, s) +func testMsgSubmitEvidence(r *require.Assertions, e exported.Evidence, s sdk.AccAddress) codecstd.MsgSubmitEvidence { + msg, err := codecstd.NewMsgSubmitEvidence(e, s) r.NoError(err) return msg } @@ -55,7 +55,7 @@ func (suite *HandlerTestSuite) SetupTest() { // recreate keeper in order to use custom testing types evidenceKeeper := evidence.NewKeeper( - simappcodec.NewAppCodec(app.Codec()), app.GetKey(evidence.StoreKey), + codecstd.NewAppCodec(app.Codec()), app.GetKey(evidence.StoreKey), app.GetSubspace(evidence.ModuleName), app.StakingKeeper, app.SlashingKeeper, ) router := evidence.NewRouter() @@ -118,7 +118,7 @@ func (suite *HandlerTestSuite) TestMsgSubmitEvidence() { suite.Require().NoError(err, "unexpected error; tc #%d", i) suite.Require().NotNil(res, "expected non-nil result; tc #%d", i) - msg := tc.msg.(simappcodec.MsgSubmitEvidence) + msg := tc.msg.(codecstd.MsgSubmitEvidence) suite.Require().Equal(msg.GetEvidence().Hash().Bytes(), res.Data, "invalid hash; tc #%d", i) } } diff --git a/x/evidence/keeper/keeper_test.go b/x/evidence/keeper/keeper_test.go index a28f66efead3..49a2b39bef16 100644 --- a/x/evidence/keeper/keeper_test.go +++ b/x/evidence/keeper/keeper_test.go @@ -6,8 +6,8 @@ import ( "testing" "time" + codecstd "github.com/cosmos/cosmos-sdk/codec/std" "github.com/cosmos/cosmos-sdk/simapp" - simappcodec "github.com/cosmos/cosmos-sdk/simapp/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/evidence" @@ -83,7 +83,7 @@ func (suite *KeeperTestSuite) SetupTest() { // recreate keeper in order to use custom testing types evidenceKeeper := evidence.NewKeeper( - simappcodec.NewAppCodec(app.Codec()), app.GetKey(evidence.StoreKey), + codecstd.NewAppCodec(app.Codec()), app.GetKey(evidence.StoreKey), app.GetSubspace(evidence.ModuleName), app.StakingKeeper, app.SlashingKeeper, ) router := evidence.NewRouter() diff --git a/x/evidence/keeper/querier_test.go b/x/evidence/keeper/querier_test.go index 069f41c6cef6..9b99fd4a8c9f 100644 --- a/x/evidence/keeper/querier_test.go +++ b/x/evidence/keeper/querier_test.go @@ -3,7 +3,7 @@ package keeper_test import ( "strings" - simappcodec "github.com/cosmos/cosmos-sdk/simapp/codec" + codecstd "github.com/cosmos/cosmos-sdk/codec/std" "github.com/cosmos/cosmos-sdk/x/evidence/exported" "github.com/cosmos/cosmos-sdk/x/evidence/types" @@ -17,7 +17,7 @@ const ( func (suite *KeeperTestSuite) TestQueryEvidence_Existing() { ctx := suite.ctx.WithIsCheckTx(false) numEvidence := 100 - cdc := simappcodec.NewAppCodec(suite.app.Codec()) + cdc := codecstd.NewAppCodec(suite.app.Codec()) evidence := suite.populateEvidence(ctx, numEvidence) query := abci.RequestQuery{ @@ -36,7 +36,7 @@ func (suite *KeeperTestSuite) TestQueryEvidence_Existing() { func (suite *KeeperTestSuite) TestQueryEvidence_NonExisting() { ctx := suite.ctx.WithIsCheckTx(false) - cdc := simappcodec.NewAppCodec(suite.app.Codec()) + cdc := codecstd.NewAppCodec(suite.app.Codec()) numEvidence := 100 suite.populateEvidence(ctx, numEvidence) @@ -52,7 +52,7 @@ func (suite *KeeperTestSuite) TestQueryEvidence_NonExisting() { func (suite *KeeperTestSuite) TestQueryAllEvidence() { ctx := suite.ctx.WithIsCheckTx(false) - cdc := simappcodec.NewAppCodec(suite.app.Codec()) + cdc := codecstd.NewAppCodec(suite.app.Codec()) numEvidence := 100 suite.populateEvidence(ctx, numEvidence) @@ -72,7 +72,7 @@ func (suite *KeeperTestSuite) TestQueryAllEvidence() { func (suite *KeeperTestSuite) TestQueryAllEvidence_InvalidPagination() { ctx := suite.ctx.WithIsCheckTx(false) - cdc := simappcodec.NewAppCodec(suite.app.Codec()) + cdc := codecstd.NewAppCodec(suite.app.Codec()) numEvidence := 100 suite.populateEvidence(ctx, numEvidence) diff --git a/x/evidence/types/codec_test.go b/x/evidence/types/codec_test.go index af2656d38c8d..cfe2a64831a2 100644 --- a/x/evidence/types/codec_test.go +++ b/x/evidence/types/codec_test.go @@ -7,15 +7,15 @@ import ( "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/crypto/ed25519" + codecstd "github.com/cosmos/cosmos-sdk/codec/std" "github.com/cosmos/cosmos-sdk/simapp" - simappcodec "github.com/cosmos/cosmos-sdk/simapp/codec" "github.com/cosmos/cosmos-sdk/x/evidence/exported" "github.com/cosmos/cosmos-sdk/x/evidence/types" ) func TestCodec(t *testing.T) { app := simapp.Setup(false) - appCodec := simappcodec.NewAppCodec(app.Codec()) + appCodec := codecstd.NewAppCodec(app.Codec()) pk := ed25519.GenPrivKey() var e exported.Evidence = &types.Equivocation{ diff --git a/x/evidence/types/msgs_test.go b/x/evidence/types/msgs_test.go index 127df25357fb..73d4ef67eae3 100644 --- a/x/evidence/types/msgs_test.go +++ b/x/evidence/types/msgs_test.go @@ -4,7 +4,7 @@ import ( "testing" "time" - simappcodec "github.com/cosmos/cosmos-sdk/simapp/codec" + codecstd "github.com/cosmos/cosmos-sdk/codec/std" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/evidence/exported" "github.com/cosmos/cosmos-sdk/x/evidence/types" @@ -13,8 +13,8 @@ import ( "github.com/tendermint/tendermint/crypto/ed25519" ) -func testMsgSubmitEvidence(t *testing.T, e exported.Evidence, s sdk.AccAddress) simappcodec.MsgSubmitEvidence { - msg, err := simappcodec.NewMsgSubmitEvidence(e, s) +func testMsgSubmitEvidence(t *testing.T, e exported.Evidence, s sdk.AccAddress) codecstd.MsgSubmitEvidence { + msg, err := codecstd.NewMsgSubmitEvidence(e, s) require.NoError(t, err) return msg } diff --git a/x/gov/abci_test.go b/x/gov/abci_test.go index c82019be7705..4774f45084d6 100644 --- a/x/gov/abci_test.go +++ b/x/gov/abci_test.go @@ -7,8 +7,8 @@ import ( "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" + codecstd "github.com/cosmos/cosmos-sdk/codec/std" "github.com/cosmos/cosmos-sdk/simapp" - simappcodec "github.com/cosmos/cosmos-sdk/simapp/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/gov" "github.com/cosmos/cosmos-sdk/x/staking" @@ -28,7 +28,7 @@ func TestTickExpiredDepositPeriod(t *testing.T) { require.False(t, inactiveQueue.Valid()) inactiveQueue.Close() - newProposalMsg, err := simappcodec.NewMsgSubmitProposal( + newProposalMsg, err := codecstd.NewMsgSubmitProposal( gov.ContentFromProposalType("test", "test", gov.ProposalTypeText), sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 5)}, addrs[0], @@ -80,7 +80,7 @@ func TestTickMultipleExpiredDepositPeriod(t *testing.T) { require.False(t, inactiveQueue.Valid()) inactiveQueue.Close() - newProposalMsg, err := simappcodec.NewMsgSubmitProposal( + newProposalMsg, err := codecstd.NewMsgSubmitProposal( gov.ContentFromProposalType("test", "test", gov.ProposalTypeText), sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 5)}, addrs[0], @@ -103,7 +103,7 @@ func TestTickMultipleExpiredDepositPeriod(t *testing.T) { require.False(t, inactiveQueue.Valid()) inactiveQueue.Close() - newProposalMsg2, err := simappcodec.NewMsgSubmitProposal( + newProposalMsg2, err := codecstd.NewMsgSubmitProposal( gov.ContentFromProposalType("test2", "test2", gov.ProposalTypeText), sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 5)}, addrs[0], @@ -160,7 +160,7 @@ func TestTickPassedDepositPeriod(t *testing.T) { require.False(t, activeQueue.Valid()) activeQueue.Close() - newProposalMsg, err := simappcodec.NewMsgSubmitProposal( + newProposalMsg, err := codecstd.NewMsgSubmitProposal( gov.ContentFromProposalType("test2", "test2", gov.ProposalTypeText), sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 5)}, addrs[0], @@ -216,7 +216,7 @@ func TestTickPassedVotingPeriod(t *testing.T) { activeQueue.Close() proposalCoins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(5))} - newProposalMsg, err := simappcodec.NewMsgSubmitProposal(TestProposal, proposalCoins, addrs[0]) + newProposalMsg, err := codecstd.NewMsgSubmitProposal(TestProposal, proposalCoins, addrs[0]) require.NoError(t, err) res, err := govHandler(ctx, newProposalMsg) diff --git a/x/gov/keeper/common_test.go b/x/gov/keeper/common_test.go index e7e9747a07ac..a61171e246b9 100644 --- a/x/gov/keeper/common_test.go +++ b/x/gov/keeper/common_test.go @@ -1,8 +1,8 @@ package keeper_test import ( + codecstd "github.com/cosmos/cosmos-sdk/codec/std" "github.com/cosmos/cosmos-sdk/simapp" - simappcodec "github.com/cosmos/cosmos-sdk/simapp/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/cosmos/cosmos-sdk/x/staking" @@ -17,7 +17,7 @@ func createValidators(ctx sdk.Context, app *simapp.SimApp, powers []int64) ([]sd valAddrs := simapp.ConvertAddrsToValAddrs(addrs) pks := simapp.CreateTestPubKeys(5) - appCodec := simappcodec.NewAppCodec(app.Codec()) + appCodec := codecstd.NewAppCodec(app.Codec()) app.StakingKeeper = staking.NewKeeper( appCodec, app.GetKey(staking.StoreKey), diff --git a/x/gov/keeper/querier_test.go b/x/gov/keeper/querier_test.go index 918f054a754d..f0377d2f2a53 100644 --- a/x/gov/keeper/querier_test.go +++ b/x/gov/keeper/querier_test.go @@ -10,8 +10,8 @@ import ( abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/codec" + codecstd "github.com/cosmos/cosmos-sdk/codec/std" "github.com/cosmos/cosmos-sdk/simapp" - simappcodec "github.com/cosmos/cosmos-sdk/simapp/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/gov/keeper" "github.com/cosmos/cosmos-sdk/x/gov/types" @@ -147,7 +147,7 @@ func getQueriedVotes(t *testing.T, ctx sdk.Context, cdc codec.JSONMarshaler, que func TestQueries(t *testing.T) { app := simapp.Setup(false) ctx := app.BaseApp.NewContext(false, abci.Header{}) - appCodec := simappcodec.NewAppCodec(app.Codec()) + appCodec := codecstd.NewAppCodec(app.Codec()) querier := keeper.NewQuerier(app.GovKeeper) @@ -295,7 +295,7 @@ func TestQueries(t *testing.T) { func TestPaginatedVotesQuery(t *testing.T) { app := simapp.Setup(false) ctx := app.BaseApp.NewContext(false, abci.Header{}) - appCodec := simappcodec.NewAppCodec(app.Codec()) + appCodec := codecstd.NewAppCodec(app.Codec()) proposal := types.Proposal{ ProposalBase: types.ProposalBase{ diff --git a/x/staking/common_test.go b/x/staking/common_test.go index e55baa0f0a90..22f388ed087c 100644 --- a/x/staking/common_test.go +++ b/x/staking/common_test.go @@ -6,8 +6,8 @@ import ( "github.com/tendermint/tendermint/crypto/secp256k1" "github.com/cosmos/cosmos-sdk/codec" + codecstd "github.com/cosmos/cosmos-sdk/codec/std" "github.com/cosmos/cosmos-sdk/simapp" - cdc "github.com/cosmos/cosmos-sdk/simapp/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/staking" "github.com/cosmos/cosmos-sdk/x/staking/keeper" @@ -43,7 +43,7 @@ func getBaseSimappWithCustomKeeper() (*codec.Codec, *simapp.SimApp, sdk.Context) app := simapp.Setup(false) ctx := app.BaseApp.NewContext(false, abci.Header{}) - appCodec := cdc.NewAppCodec(codec.New()) + appCodec := codecstd.NewAppCodec(codec.New()) app.StakingKeeper = keeper.NewKeeper( appCodec, diff --git a/x/staking/keeper/common_test.go b/x/staking/keeper/common_test.go index d71737ddcf71..01cb1a75d55f 100644 --- a/x/staking/keeper/common_test.go +++ b/x/staking/keeper/common_test.go @@ -6,8 +6,8 @@ import ( abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/codec" + codecstd "github.com/cosmos/cosmos-sdk/codec/std" "github.com/cosmos/cosmos-sdk/simapp" - simappcodec "github.com/cosmos/cosmos-sdk/simapp/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/staking" "github.com/cosmos/cosmos-sdk/x/staking/keeper" @@ -24,7 +24,7 @@ func createTestInput() (*codec.Codec, *simapp.SimApp, sdk.Context) { app := simapp.Setup(false) ctx := app.BaseApp.NewContext(false, abci.Header{}) - appCodec := simappcodec.NewAppCodec(codec.New()) + appCodec := codecstd.NewAppCodec(codec.New()) app.StakingKeeper = keeper.NewKeeper( appCodec, diff --git a/x/supply/keeper/bank_test.go b/x/supply/keeper/bank_test.go index cb6237147864..3a4e8a15c107 100644 --- a/x/supply/keeper/bank_test.go +++ b/x/supply/keeper/bank_test.go @@ -6,8 +6,8 @@ import ( "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" + codecstd "github.com/cosmos/cosmos-sdk/codec/std" "github.com/cosmos/cosmos-sdk/simapp" - simappcodec "github.com/cosmos/cosmos-sdk/simapp/codec" sdk "github.com/cosmos/cosmos-sdk/types" keep "github.com/cosmos/cosmos-sdk/x/supply/keeper" "github.com/cosmos/cosmos-sdk/x/supply/types" @@ -55,7 +55,7 @@ func TestSendCoins(t *testing.T) { maccPerms[multiPerm] = []string{types.Burner, types.Minter, types.Staking} maccPerms[randomPerm] = []string{"random"} - appCodec := simappcodec.NewAppCodec(app.Codec()) + appCodec := codecstd.NewAppCodec(app.Codec()) keeper := keep.NewKeeper(appCodec, app.GetKey(types.StoreKey), app.AccountKeeper, app.BankKeeper, maccPerms) ak := app.AccountKeeper @@ -116,7 +116,7 @@ func TestMintCoins(t *testing.T) { maccPerms[multiPerm] = []string{types.Burner, types.Minter, types.Staking} maccPerms[randomPerm] = []string{"random"} - appCodec := simappcodec.NewAppCodec(app.Codec()) + appCodec := codecstd.NewAppCodec(app.Codec()) keeper := keep.NewKeeper(appCodec, app.GetKey(types.StoreKey), app.AccountKeeper, app.BankKeeper, maccPerms) ak := app.AccountKeeper @@ -164,7 +164,7 @@ func TestBurnCoins(t *testing.T) { maccPerms[multiPerm] = []string{types.Burner, types.Minter, types.Staking} maccPerms[randomPerm] = []string{"random"} - appCodec := simappcodec.NewAppCodec(app.Codec()) + appCodec := codecstd.NewAppCodec(app.Codec()) keeper := keep.NewKeeper(appCodec, app.GetKey(types.StoreKey), app.AccountKeeper, app.BankKeeper, maccPerms) ak := app.AccountKeeper diff --git a/x/supply/keeper/keeper_test.go b/x/supply/keeper/keeper_test.go index a81575914abc..d43b140d0f11 100644 --- a/x/supply/keeper/keeper_test.go +++ b/x/supply/keeper/keeper_test.go @@ -6,8 +6,8 @@ import ( "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" + codecstd "github.com/cosmos/cosmos-sdk/codec/std" "github.com/cosmos/cosmos-sdk/simapp" - simappcodec "github.com/cosmos/cosmos-sdk/simapp/codec" sdk "github.com/cosmos/cosmos-sdk/types" keep "github.com/cosmos/cosmos-sdk/x/supply/keeper" "github.com/cosmos/cosmos-sdk/x/supply/types" @@ -39,7 +39,7 @@ func TestValidatePermissions(t *testing.T) { maccPerms[multiPerm] = []string{types.Burner, types.Minter, types.Staking} maccPerms[randomPerm] = []string{"random"} - appCodec := simappcodec.NewAppCodec(app.Codec()) + appCodec := codecstd.NewAppCodec(app.Codec()) keeper := keep.NewKeeper(appCodec, app.GetKey(types.StoreKey), app.AccountKeeper, app.BankKeeper, maccPerms) err := keeper.ValidatePermissions(multiPermAcc) From 69ba71c28da603721a5a8c607d83843039da2353 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Thu, 5 Mar 2020 09:44:11 -0500 Subject: [PATCH 370/529] Add pkg doc --- codec/std/doc.go | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 codec/std/doc.go diff --git a/codec/std/doc.go b/codec/std/doc.go new file mode 100644 index 000000000000..9b57bd5916b2 --- /dev/null +++ b/codec/std/doc.go @@ -0,0 +1,10 @@ +/* +Package std defines all the common and standard Cosmos SDK Protocol Buffer +message definitions and type implementations. The std package defines and exposes +a single concrete Codec type that implements all the necessary module codec +interfaces along with all the types necessary to use those modules. + +Applications can choose to either use the codec directly or even extend it without +having the need to redefine all the message and type implementations. +*/ +package std From 643b10982620cb7ce0151d6297f3b7d72da11219 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Thu, 5 Mar 2020 16:15:53 +0100 Subject: [PATCH 371/529] change assert by require --- x/mint/module_test.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/x/mint/module_test.go b/x/mint/module_test.go index 448d2f6b0d95..8b283b0326cf 100644 --- a/x/mint/module_test.go +++ b/x/mint/module_test.go @@ -3,13 +3,13 @@ package mint_test import ( "testing" - "github.com/cosmos/cosmos-sdk/x/mint" - "github.com/cosmos/cosmos-sdk/x/supply" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/simapp" + "github.com/cosmos/cosmos-sdk/x/mint" + "github.com/cosmos/cosmos-sdk/x/supply" ) func TestItCreatesModuleAccountOnInitBlock(t *testing.T) { @@ -24,6 +24,5 @@ func TestItCreatesModuleAccountOnInitBlock(t *testing.T) { ) acc := app.AccountKeeper.GetAccount(ctx, supply.NewModuleAddress(mint.ModuleName)) - - assert.NotNil(t, acc) + require.NotNil(t, acc) } From 60031bbc9b9738b6a4fdb69e67a3c44ac123cc01 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Thu, 5 Mar 2020 16:19:36 +0100 Subject: [PATCH 372/529] re-public methods --- x/mint/abci.go | 4 ++-- x/mint/genesis.go | 8 ++++---- x/mint/module.go | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/x/mint/abci.go b/x/mint/abci.go index c87f8ef2d661..21595b466f98 100644 --- a/x/mint/abci.go +++ b/x/mint/abci.go @@ -5,8 +5,8 @@ import ( "github.com/cosmos/cosmos-sdk/x/mint/types" ) -// beginBlocker mints new tokens for the previous block. -func beginBlocker(ctx sdk.Context, k Keeper) { +// BeginBlocker mints new tokens for the previous block. +func BeginBlocker(ctx sdk.Context, k Keeper) { // fetch stored minter & params minter := k.GetMinter(ctx) params := k.GetParams(ctx) diff --git a/x/mint/genesis.go b/x/mint/genesis.go index fb07680d33cb..44e0a5ee130f 100644 --- a/x/mint/genesis.go +++ b/x/mint/genesis.go @@ -5,16 +5,16 @@ import ( "github.com/cosmos/cosmos-sdk/x/mint/types" ) -// initGenesis new mint genesis -func initGenesis(ctx sdk.Context, keeper Keeper, supplyKeeper types.SupplyKeeper, data GenesisState) { +// InitGenesis new mint genesis +func InitGenesis(ctx sdk.Context, keeper Keeper, supplyKeeper types.SupplyKeeper, data GenesisState) { keeper.SetMinter(ctx, data.Minter) keeper.SetParams(ctx, data.Params) supplyKeeper.GetModuleAccount(ctx, ModuleName) } -// exportGenesis returns a GenesisState for a given context and keeper. -func exportGenesis(ctx sdk.Context, keeper Keeper) GenesisState { +// ExportGenesis returns a GenesisState for a given context and keeper. +func ExportGenesis(ctx sdk.Context, keeper Keeper) GenesisState { minter := keeper.GetMinter(ctx) params := keeper.GetParams(ctx) return NewGenesisState(minter, params) diff --git a/x/mint/module.go b/x/mint/module.go index 8e9ca590c3d2..88c03dfea20d 100644 --- a/x/mint/module.go +++ b/x/mint/module.go @@ -119,7 +119,7 @@ func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data j var genesisState GenesisState cdc.MustUnmarshalJSON(data, &genesisState) - initGenesis(ctx, am.keeper, am.supplyKeeper, genesisState) + InitGenesis(ctx, am.keeper, am.supplyKeeper, genesisState) return []abci.ValidatorUpdate{} } @@ -127,13 +127,13 @@ func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data j // ExportGenesis returns the exported genesis state as raw bytes for the mint // module. func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json.RawMessage { - gs := exportGenesis(ctx, am.keeper) + gs := ExportGenesis(ctx, am.keeper) return cdc.MustMarshalJSON(gs) } // BeginBlock returns the begin blocker for the mint module. func (am AppModule) BeginBlock(ctx sdk.Context, _ abci.RequestBeginBlock) { - beginBlocker(ctx, am.keeper) + BeginBlocker(ctx, am.keeper) } // EndBlock returns the end blocker for the mint module. It returns no validator From ba099998f6e564f38a0b0018e48f7e7cab6bfc06 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Thu, 5 Mar 2020 16:36:36 +0100 Subject: [PATCH 373/529] Clarify what happens with GetModuleAccount method. --- x/supply/keeper/account.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x/supply/keeper/account.go b/x/supply/keeper/account.go index 685308cf6102..fdf8f9afff49 100644 --- a/x/supply/keeper/account.go +++ b/x/supply/keeper/account.go @@ -49,7 +49,8 @@ func (k Keeper) GetModuleAccountAndPermissions(ctx sdk.Context, moduleName strin return maccI, perms } -// GetModuleAccount gets the module account from the auth account store +// GetModuleAccount gets the module account from the auth account store, if the account does not +// exist in the AccountKeeper, then it is created. func (k Keeper) GetModuleAccount(ctx sdk.Context, moduleName string) exported.ModuleAccountI { acc, _ := k.GetModuleAccountAndPermissions(ctx, moduleName) return acc From bc863c921202cb13eff9f07f7fed9816c253e42e Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Thu, 5 Mar 2020 15:40:25 +0000 Subject: [PATCH 374/529] Update module spec (#5751) --- docs/building-modules/structure.md | 58 ++++++++++++++---------------- 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/docs/building-modules/structure.md b/docs/building-modules/structure.md index bb20c9945ed5..5f7315f91bd8 100644 --- a/docs/building-modules/structure.md +++ b/docs/building-modules/structure.md @@ -1,6 +1,8 @@ # Recommended Folder Structure @@ -20,23 +22,24 @@ x/{module} │   └── tx.go ├── exported │   └── exported.go -├── internal -│   ├── keeper -│   │   ├── invariants.go -│   │   ├── keeper.go -│   │   ├── ... -│   │   └── querier.go -│   └── types -│   ├── codec.go -│   ├── errors.go -│   ├── events.go -│   ├── expected_keepers.go -│   ├── genesis.go -│   ├── keys.go -│   ├── msgs.go -│   ├── params.go -│   ├── ... -│   └── querier.go +├── keeper +│   ├── invariants.go +│   ├── keeper.go +│   ├── ... +│   └── querier.go +├── types +│ ├── codec.go +│ ├── errors.go +│ ├── events.go +│ ├── expected_keepers.go +│ ├── genesis.go +│ ├── keys.go +│ ├── msgs.go +│ ├── params.go +│ ├── types.pb.go +│ ├── types.proto +│ ├── ... +│ └── querier.go ├── simulation │   ├── decoder.go │   ├── genesis.go @@ -55,9 +58,8 @@ x/{module} - `alias.go`: The module's exported types, constants, and variables. These are mainly to improve developer ergonomics by only needing to import a single package. Note, there is nothing preventing developers from importing other packages from the module -(excluding`internal/`) but it is recommended that `alias.go` have everything -exposed that other modules may need. The majority of the exported values here will -typically come from `internal/` (see below). +but it is recommended that `alias.go` have everything exposed that other modules +may need. - `client/`: The module's CLI and REST client functionality implementation and testing. - `exported/`: The module's exported types -- typically type interfaces. If a module @@ -72,16 +74,10 @@ DRY and also alleviates import cycle chaos. - `genesis.go`: The module's genesis related business logic (e.g. `InitGenesis`). Note, genesis types are defined in `internal/types`. - `handler.go`: The module's message handlers. -- `internal/`: The module's internal types and implementations. The purpose of -this package is mainly two fold. First, it signals that this package is not -intended to be used or imported anywhere outside the defining module. Secondly, -it goes hand-in-hand with `alias.go` in that it allows public types and functions -to be used internally while not being exposed outside to the outside world. This -allows for greater freedom of development while maintaining API stability. - - `internal/types`: The module's type definitions such as messages, `KVStore` - keys, parameter types, and `expected_keepers.go` contracts. - - `internal/keeper`: The module's keeper implementation along with any auxiliary - implementations such as the querier and invariants. +- `keeper/`: The module's keeper implementation along with any auxiliary +implementations such as the querier and invariants. +- `types/`: The module's type definitions such as messages, `KVStore` keys, +parameter types, Protocol Buffer definitions, and `expected_keepers.go` contracts. - `module.go`: The module's implementation of the `AppModule` and `AppModuleBasic` interfaces. - `simulation/`: The module's simulation package defines all the required functions From 6c1e3e53e3bc4ed2ddc54d3bb4cf10ce3c6d9cee Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Thu, 5 Mar 2020 16:02:17 +0000 Subject: [PATCH 375/529] [ADR: 013] Observability (#5188) * [ADR: 013] Metrics - Inital ADR for metrics with in the SDK - extending metrics to be module specific as well Signed-off-by: Marko Baricevic * add some metrics * update adr-013 to Observability * Update docs/architecture/README.MD Co-Authored-By: Jack Zampolin * change wording * minor wording change * add more things * undo module work * Fix formatting and added more info * Address comments * Address comments Co-authored-by: Alexander Bezobchuk Co-authored-by: Jack Zampolin Co-authored-by: Timothy Chen Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> --- docs/architecture/README.md | 1 + docs/architecture/adr-013-metrics.md | 97 ++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 docs/architecture/adr-013-metrics.md diff --git a/docs/architecture/README.md b/docs/architecture/README.md index 09632c114eb6..e327a5b642d5 100644 --- a/docs/architecture/README.md +++ b/docs/architecture/README.md @@ -39,6 +39,7 @@ Please add a entry below in your Pull Request for an ADR. - [ADR 010: Modular AnteHandler](./adr-010-modular-antehandler.md) - [ADR 011: Generalize Genesis Accounts](./adr-011-generalize-genesis-accounts.md) - [ADR 012: State Accessors](./adr-012-state-accessors.md) +- [ADR 013: Observability](./adr-013-observability.md) - [ADR 015: IBC Packet Receiver](./adr-015-ibc-packet-receiver.md) - [ADR 016: Validator Consensus Key Rotation](./adr-016-validator-consensus-key-rotation.md) - [ADR 017: Historical Header Module](./adr-017-historical-header-module.md) diff --git a/docs/architecture/adr-013-metrics.md b/docs/architecture/adr-013-metrics.md new file mode 100644 index 000000000000..bb2b2b8d6230 --- /dev/null +++ b/docs/architecture/adr-013-metrics.md @@ -0,0 +1,97 @@ +# ADR 013: Observability + +## Changelog + +- 20-01-2020: Initial Draft + +## Status + +Proposed + +## Context + +There has been discussion around exposing more metrics to users and node operators about the application. Currently there is only a way to expose metrics from Tendermint and not the application itself. To bring more visibility into applications, I would like to propose reporting of metrics through [Prometheus](https://prometheus.io/). + +Extending `AppModuleBasic` to support registering of metrics would enable developers to see more information about individual modules. + +```go +type AppModuleBasic interface { + Name() string + RegisterCodec(*codec.Codec) + RegisterMetrics(namespace string, labelsAndValues... string) *Metrics + + // genesis + DefaultGenesis() json.RawMessage + ValidateGenesis(json.RawMessage) error + + // client functionality + RegisterRESTRoutes(context.CLIContext, *mux.Router) + GetTxCmd(*codec.Codec) *cobra.Command + GetQueryCmd(*codec.Codec) *cobra.Command +} +// ..... + +func (bm BasicManager) RegisterMetrics(appName string, labelsAndValues... string) MetricsProvider { + for _, b := range bm { + b.CreateMetrics(appName, labelsAndValues) + } +} +``` + +Each module can define its own `Metrics` type and`CreateMetrics` function in the x//observability/metrics.go file: + +```go +type Metrics struct { + Size metrics.Guage + + Transactions metrics.Counter +} + +func CreateMetrics(namespace string, labelsAndValues... string) *Metrics { + labels := make([]string, len(labelsAndValues/2)) + for i := 0; i < len(labelsAndValues); i += 2 { + labels[i/2] = labelsAndValues[i] + } + return &Metrics{ + Size: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{ + Namespace: namespace, + Subsystem: "subsystem", + Name: "size", + Help: "Size of the custom metric", + }, labels).With(labelsAndValues...), + Transactions: prometheus.NewCounterFrom(stdprometheus.CounterOpts{ + Namespace: namespace, + Subsystem: "subsystem", + Name: "transactions", + Help: "Number of transactions processed", + }, labels).With(labelsAndValues...), + } + +``` + +To get the correct namespace for the modules changing `BasicManager` to consist of the app name is needed. + +```go +type BasicManager struct { + appName string + modules map[string]AppModuleBasic +} +``` + +## Decision + +- Use Prometheus for metric gathering. +- Add a method to register metrics to the `AppModuleBasic` interface +- Modules create a observability/metrics.go that defines the metrics and create the metrics object. + +## Consequences + +### Positive + +- Add more visibility into SDK based application and modules + +### Negative + +### Neutral + +## References From e4209bd1f1b3d936c5e7e87339dfa36ec368ef5d Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Thu, 5 Mar 2020 16:37:27 +0000 Subject: [PATCH 376/529] Attempt to fix flaky tests --- types/module/module_test.go | 49 +++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/types/module/module_test.go b/types/module/module_test.go index bc875cffc533..5cafaf10939e 100644 --- a/types/module/module_test.go +++ b/types/module/module_test.go @@ -21,55 +21,53 @@ import ( var errFoo = errors.New("dummy") func TestBasicManager(t *testing.T) { - t.Parallel() mockCtrl := gomock.NewController(t) t.Cleanup(mockCtrl.Finish) + cdc := codec.New() + wantDefaultGenesis := map[string]json.RawMessage{ + "mockAppModuleBasic1": json.RawMessage(``), + "mockAppModuleBasic2": json.RawMessage(`{"key":"value"}`), + } mockAppModuleBasic1 := mocks.NewMockAppModuleBasic(mockCtrl) mockAppModuleBasic2 := mocks.NewMockAppModuleBasic(mockCtrl) - mockAppModuleBasic1.EXPECT().Name().Times(1).Return("mockAppModuleBasic1") - mockAppModuleBasic2.EXPECT().Name().Times(1).Return("mockAppModuleBasic2") + mockAppModuleBasic1.EXPECT().Name().Times(3).Return("mockAppModuleBasic1") + mockAppModuleBasic2.EXPECT().Name().Times(2).Return("mockAppModuleBasic2") + mockAppModuleBasic1.EXPECT().DefaultGenesis(gomock.Eq(cdc)).Times(1).Return(json.RawMessage(``)) + mockAppModuleBasic2.EXPECT().DefaultGenesis(gomock.Eq(cdc)).Times(1).Return(json.RawMessage(`{"key":"value"}`)) + mockAppModuleBasic1.EXPECT().ValidateGenesis(gomock.Eq(cdc), gomock.Eq(wantDefaultGenesis["mockAppModuleBasic1"])).Times(1).Return(errFoo) + mockAppModuleBasic1.EXPECT().RegisterRESTRoutes(gomock.Eq(context.CLIContext{}), gomock.Eq(&mux.Router{})).Times(1) + mockAppModuleBasic2.EXPECT().RegisterRESTRoutes(gomock.Eq(context.CLIContext{}), gomock.Eq(&mux.Router{})).Times(1) + mockAppModuleBasic1.EXPECT().RegisterCodec(gomock.Eq(cdc)).Times(1) + mockAppModuleBasic2.EXPECT().RegisterCodec(gomock.Eq(cdc)).Times(1) + mockAppModuleBasic1.EXPECT().GetTxCmd(cdc).Times(1).Return(nil) + mockAppModuleBasic2.EXPECT().GetTxCmd(cdc).Times(1).Return(&cobra.Command{}) + mockAppModuleBasic1.EXPECT().GetQueryCmd(cdc).Times(1).Return(nil) + mockAppModuleBasic2.EXPECT().GetQueryCmd(cdc).Times(1).Return(&cobra.Command{}) mm := module.NewBasicManager(mockAppModuleBasic1, mockAppModuleBasic2) require.Equal(t, mm["mockAppModuleBasic1"], mockAppModuleBasic1) - cdc := codec.New() - mockAppModuleBasic1.EXPECT().RegisterCodec(gomock.Eq(cdc)).Times(1) - mockAppModuleBasic2.EXPECT().RegisterCodec(gomock.Eq(cdc)).Times(1) mm.RegisterCodec(cdc) - mockAppModuleBasic1.EXPECT().Name().Times(1).Return("mockAppModuleBasic1") - mockAppModuleBasic2.EXPECT().Name().Times(1).Return("mockAppModuleBasic2") - mockAppModuleBasic1.EXPECT().DefaultGenesis(gomock.Eq(cdc)).Times(1).Return(json.RawMessage(``)) - mockAppModuleBasic2.EXPECT().DefaultGenesis(gomock.Eq(cdc)).Times(1).Return(json.RawMessage(`{"key":"value"}`)) - defaultGenesis := mm.DefaultGenesis(cdc) - require.Equal(t, 2, len(defaultGenesis)) - require.Equal(t, json.RawMessage(``), defaultGenesis["mockAppModuleBasic1"]) + require.Equal(t, wantDefaultGenesis, mm.DefaultGenesis(cdc)) var data map[string]string - require.NoError(t, json.Unmarshal(defaultGenesis["mockAppModuleBasic2"], &data)) + require.NoError(t, json.Unmarshal(wantDefaultGenesis["mockAppModuleBasic2"], &data)) require.Equal(t, map[string]string{"key": "value"}, data) - mockAppModuleBasic1.EXPECT().Name().Times(1).Return("mockAppModuleBasic1") - mockAppModuleBasic1.EXPECT().ValidateGenesis(gomock.Eq(cdc), gomock.Eq(defaultGenesis["mockAppModuleBasic1"])).Times(1).Return(errFoo) - require.True(t, errors.Is(errFoo, mm.ValidateGenesis(cdc, defaultGenesis))) + require.True(t, errors.Is(errFoo, mm.ValidateGenesis(cdc, wantDefaultGenesis))) - mockAppModuleBasic1.EXPECT().RegisterRESTRoutes(gomock.Eq(context.CLIContext{}), gomock.Eq(&mux.Router{})).Times(1) - mockAppModuleBasic2.EXPECT().RegisterRESTRoutes(gomock.Eq(context.CLIContext{}), gomock.Eq(&mux.Router{})).Times(1) mm.RegisterRESTRoutes(context.CLIContext{}, &mux.Router{}) mockCmd := &cobra.Command{Use: "root"} - mockAppModuleBasic1.EXPECT().GetTxCmd(cdc).Times(1).Return(nil) - mockAppModuleBasic2.EXPECT().GetTxCmd(cdc).Times(1).Return(&cobra.Command{}) mm.AddTxCommands(mockCmd, cdc) - mockAppModuleBasic1.EXPECT().GetQueryCmd(cdc).Times(1).Return(nil) - mockAppModuleBasic2.EXPECT().GetQueryCmd(cdc).Times(1).Return(&cobra.Command{}) mm.AddQueryCommands(mockCmd, cdc) // validate genesis returns nil - require.Nil(t, module.NewBasicManager().ValidateGenesis(cdc, defaultGenesis)) + require.Nil(t, module.NewBasicManager().ValidateGenesis(cdc, wantDefaultGenesis)) } func TestGenesisOnlyAppModule(t *testing.T) { @@ -203,7 +201,6 @@ func TestManager_InitGenesis(t *testing.T) { } func TestManager_ExportGenesis(t *testing.T) { - t.Parallel() mockCtrl := gomock.NewController(t) t.Cleanup(mockCtrl.Finish) @@ -226,7 +223,6 @@ func TestManager_ExportGenesis(t *testing.T) { } func TestManager_BeginBlock(t *testing.T) { - t.Parallel() mockCtrl := gomock.NewController(t) t.Cleanup(mockCtrl.Finish) @@ -246,7 +242,6 @@ func TestManager_BeginBlock(t *testing.T) { } func TestManager_EndBlock(t *testing.T) { - t.Parallel() mockCtrl := gomock.NewController(t) t.Cleanup(mockCtrl.Finish) From e45be08eb1a6e834c73728f40940777323bb195a Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Thu, 5 Mar 2020 22:11:05 +0100 Subject: [PATCH 377/529] create module account on init for FeeCollectorName and tests for other module accounts --- CHANGELOG.md | 6 ++++-- simapp/app.go | 4 ++-- x/auth/genesis.go | 5 ++++- x/auth/module.go | 6 ++++-- x/auth/module_test.go | 27 +++++++++++++++++++++++++++ x/distribution/module_test.go | 27 +++++++++++++++++++++++++++ x/gov/module_test.go | 29 +++++++++++++++++++++++++++++ x/staking/module_test.go | 31 +++++++++++++++++++++++++++++++ 8 files changed, 128 insertions(+), 7 deletions(-) create mode 100644 x/auth/module_test.go create mode 100644 x/distribution/module_test.go create mode 100644 x/gov/module_test.go create mode 100644 x/staking/module_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 856528154a21..aaf108ce66f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -62,8 +62,6 @@ and provided directly the IAVL store. * (types) [\#5533](https://github.com/cosmos/cosmos-sdk/pull/5533) Refactored `AppModuleBasic` and `AppModuleGenesis` to now accept a `codec.JSONMarshaler` for modular serialization of genesis state. * (crypto/keys) [\#5735](https://github.com/cosmos/cosmos-sdk/pull/5735) Keyring's Update() function is now no-op. -* (x/mint) [\#5569](https://github.com/cosmos/cosmos-sdk/issues/5569) `AppModule` now requires SupplyKeeper in its constructor to create -module account on `InitGenesis`. ### Features @@ -77,6 +75,10 @@ resulted in a panic when the tx execution mode was `CheckTx`. * (x/distribution) [\#5620](https://github.com/cosmos/cosmos-sdk/pull/5620) Fix nil pointer deref in distribution tax/rewward validation helpers. * (genesis) [\#5086](https://github.com/cosmos/cosmos-sdk/issues/5086) Ensure `gentxs` are always an empty array instead of `nil` * (types) [\#5741](https://github.com/cosmos/cosmos-sdk/issues/5741) Prevent ChainAnteDecorators() from panicking when empty AnteDecorator slice is supplied. +* (x/mint) [\#5569](https://github.com/cosmos/cosmos-sdk/issues/5569) Create Mint Module account on InitGenesis. `AppModule` now requires SupplyKeeper in its constructor to create +module account on `InitGenesis`. +* (x/auth) [\#5569](https://github.com/cosmos/cosmos-sdk/issues/5569) Create FeeCollectorName Module account on InitGenesis. `AppModule` now requires SupplyKeeper in its constructor to create +module account on `InitGenesis`. ### State Machine Breaking diff --git a/simapp/app.go b/simapp/app.go index 56aaae8d8459..f7d9f30d7f5f 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -221,7 +221,7 @@ func NewSimApp( // must be passed by reference here. app.mm = module.NewManager( genutil.NewAppModule(app.AccountKeeper, app.StakingKeeper, app.BaseApp.DeliverTx), - auth.NewAppModule(app.AccountKeeper), + auth.NewAppModule(app.AccountKeeper, app.SupplyKeeper), bank.NewAppModule(app.BankKeeper, app.AccountKeeper), crisis.NewAppModule(&app.CrisisKeeper), supply.NewAppModule(app.SupplyKeeper, app.BankKeeper, app.AccountKeeper), @@ -256,7 +256,7 @@ func NewSimApp( // NOTE: this is not required apps that don't use the simulator for fuzz testing // transactions app.sm = module.NewSimulationManager( - auth.NewAppModule(app.AccountKeeper), + auth.NewAppModule(app.AccountKeeper, app.SupplyKeeper), bank.NewAppModule(app.BankKeeper, app.AccountKeeper), supply.NewAppModule(app.SupplyKeeper, app.BankKeeper, app.AccountKeeper), gov.NewAppModule(app.GovKeeper, app.AccountKeeper, app.BankKeeper, app.SupplyKeeper), diff --git a/x/auth/genesis.go b/x/auth/genesis.go index 22db3557d7f7..420bdba09de5 100644 --- a/x/auth/genesis.go +++ b/x/auth/genesis.go @@ -3,13 +3,14 @@ package auth import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth/exported" + "github.com/cosmos/cosmos-sdk/x/auth/types" ) // InitGenesis - Init store state from genesis data // // CONTRACT: old coins from the FeeCollectionKeeper need to be transferred through // a genesis port script to the new fee collector account -func InitGenesis(ctx sdk.Context, ak AccountKeeper, data GenesisState) { +func InitGenesis(ctx sdk.Context, ak AccountKeeper, sk types.SupplyKeeper, data GenesisState) { ak.SetParams(ctx, data.Params) data.Accounts = SanitizeGenesisAccounts(data.Accounts) @@ -17,6 +18,8 @@ func InitGenesis(ctx sdk.Context, ak AccountKeeper, data GenesisState) { acc := ak.NewAccount(ctx, a) ak.SetAccount(ctx, acc) } + + sk.GetModuleAccount(ctx, FeeCollectorName) } // ExportGenesis returns a GenesisState for a given context and keeper diff --git a/x/auth/module.go b/x/auth/module.go index c5adc5811328..910a54a2b951 100644 --- a/x/auth/module.go +++ b/x/auth/module.go @@ -77,13 +77,15 @@ type AppModule struct { AppModuleBasic accountKeeper AccountKeeper + supplyKeeper types.SupplyKeeper } // NewAppModule creates a new AppModule object -func NewAppModule(accountKeeper AccountKeeper) AppModule { +func NewAppModule(accountKeeper AccountKeeper, supplyKeeper types.SupplyKeeper) AppModule { return AppModule{ AppModuleBasic: AppModuleBasic{}, accountKeeper: accountKeeper, + supplyKeeper: supplyKeeper, } } @@ -116,7 +118,7 @@ func (am AppModule) NewQuerierHandler() sdk.Querier { func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data json.RawMessage) []abci.ValidatorUpdate { var genesisState GenesisState cdc.MustUnmarshalJSON(data, &genesisState) - InitGenesis(ctx, am.accountKeeper, genesisState) + InitGenesis(ctx, am.accountKeeper, am.supplyKeeper, genesisState) return []abci.ValidatorUpdate{} } diff --git a/x/auth/module_test.go b/x/auth/module_test.go new file mode 100644 index 000000000000..b49c407b9cb9 --- /dev/null +++ b/x/auth/module_test.go @@ -0,0 +1,27 @@ +package auth_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/simapp" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/supply" +) + +func TestItCreatesModuleAccountOnInitBlock(t *testing.T) { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, types.Header{}) + + app.InitChain( + types.RequestInitChain{ + AppStateBytes: []byte("{}"), + ChainId: "test-chain-id", + }, + ) + + acc := app.AccountKeeper.GetAccount(ctx, supply.NewModuleAddress(auth.FeeCollectorName)) + require.NotNil(t, acc) +} diff --git a/x/distribution/module_test.go b/x/distribution/module_test.go new file mode 100644 index 000000000000..83bf1b0ef67e --- /dev/null +++ b/x/distribution/module_test.go @@ -0,0 +1,27 @@ +package distribution_test + +import ( + "testing" + + "github.com/cosmos/cosmos-sdk/x/distribution" + + "github.com/cosmos/cosmos-sdk/simapp" + "github.com/cosmos/cosmos-sdk/x/supply" + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/abci/types" +) + +func TestItCreatesModuleAccountOnInitBlock(t *testing.T) { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, types.Header{}) + + app.InitChain( + types.RequestInitChain{ + AppStateBytes: []byte("{}"), + ChainId: "test-chain-id", + }, + ) + + acc := app.AccountKeeper.GetAccount(ctx, supply.NewModuleAddress(distribution.ModuleName)) + require.NotNil(t, acc) +} diff --git a/x/gov/module_test.go b/x/gov/module_test.go new file mode 100644 index 000000000000..59794489fc6f --- /dev/null +++ b/x/gov/module_test.go @@ -0,0 +1,29 @@ +package gov_test + +import ( + "testing" + + "github.com/cosmos/cosmos-sdk/x/gov" + + "github.com/stretchr/testify/require" + + "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/simapp" + "github.com/cosmos/cosmos-sdk/x/supply" +) + +func TestItCreatesModuleAccountOnInitBlock(t *testing.T) { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, types.Header{}) + + app.InitChain( + types.RequestInitChain{ + AppStateBytes: []byte("{}"), + ChainId: "test-chain-id", + }, + ) + + acc := app.AccountKeeper.GetAccount(ctx, supply.NewModuleAddress(gov.ModuleName)) + require.NotNil(t, acc) +} diff --git a/x/staking/module_test.go b/x/staking/module_test.go new file mode 100644 index 000000000000..512d96e5a17e --- /dev/null +++ b/x/staking/module_test.go @@ -0,0 +1,31 @@ +package staking_test + +import ( + "testing" + + "github.com/cosmos/cosmos-sdk/x/staking" + + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/simapp" + "github.com/cosmos/cosmos-sdk/x/supply" +) + +func TestItCreatesModuleAccountOnInitBlock(t *testing.T) { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, types.Header{}) + + app.InitChain( + types.RequestInitChain{ + AppStateBytes: []byte("{}"), + ChainId: "test-chain-id", + }, + ) + + acc := app.AccountKeeper.GetAccount(ctx, supply.NewModuleAddress(staking.BondedPoolName)) + require.NotNil(t, acc) + + acc = app.AccountKeeper.GetAccount(ctx, supply.NewModuleAddress(staking.NotBondedPoolName)) + require.NotNil(t, acc) +} From 2d5711ff14dd840dacadcc4b79ea8f9b4ef312c7 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Thu, 5 Mar 2020 23:31:30 -0500 Subject: [PATCH 378/529] Edit changelog entry --- CHANGELOG.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aaf108ce66f3..403d420cedea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -75,10 +75,7 @@ resulted in a panic when the tx execution mode was `CheckTx`. * (x/distribution) [\#5620](https://github.com/cosmos/cosmos-sdk/pull/5620) Fix nil pointer deref in distribution tax/rewward validation helpers. * (genesis) [\#5086](https://github.com/cosmos/cosmos-sdk/issues/5086) Ensure `gentxs` are always an empty array instead of `nil` * (types) [\#5741](https://github.com/cosmos/cosmos-sdk/issues/5741) Prevent ChainAnteDecorators() from panicking when empty AnteDecorator slice is supplied. -* (x/mint) [\#5569](https://github.com/cosmos/cosmos-sdk/issues/5569) Create Mint Module account on InitGenesis. `AppModule` now requires SupplyKeeper in its constructor to create -module account on `InitGenesis`. -* (x/auth) [\#5569](https://github.com/cosmos/cosmos-sdk/issues/5569) Create FeeCollectorName Module account on InitGenesis. `AppModule` now requires SupplyKeeper in its constructor to create -module account on `InitGenesis`. +* (modules) [\#5569](https://github.com/cosmos/cosmos-sdk/issues/5569) `InitGenesis`, for the relevant modules, now ensures module accounts exist. ### State Machine Breaking From c5b2abd8140e8fd7732bc89383d179316e93be97 Mon Sep 17 00:00:00 2001 From: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Date: Fri, 6 Mar 2020 09:28:19 -0300 Subject: [PATCH 379/529] store: cleanup (#5753) * store: cleanup * minor change Co-authored-by: Alexander Bezobchuk --- store/list/list.go | 105 ---------------------------------- store/list/list_test.go | 98 ------------------------------- store/prefix/store.go | 52 +++++++++-------- store/queue/queue.go | 93 ------------------------------ store/rootmulti/proof.go | 1 - store/rootmulti/store.go | 33 ++++++----- store/rootmulti/store_test.go | 1 + store/rootmulti/wire.go | 7 --- store/tracekv/store.go | 6 +- 9 files changed, 50 insertions(+), 346 deletions(-) delete mode 100644 store/list/list.go delete mode 100644 store/list/list_test.go delete mode 100644 store/queue/queue.go delete mode 100644 store/rootmulti/wire.go diff --git a/store/list/list.go b/store/list/list.go deleted file mode 100644 index 96193adf85d9..000000000000 --- a/store/list/list.go +++ /dev/null @@ -1,105 +0,0 @@ -package list - -import ( - "fmt" - "strconv" - - "github.com/cosmos/cosmos-sdk/codec" - - "github.com/cosmos/cosmos-sdk/store/types" -) - -// Key for the length of the list -func LengthKey() []byte { - return []byte{0x00} -} - -// Key for the elements of the list -func ElemKey(index uint64) []byte { - return append([]byte{0x01}, []byte(fmt.Sprintf("%020d", index))...) -} - -// List defines an integer indexable mapper -// It panics when the element type cannot be (un/)marshalled by the codec -type List struct { - cdc *codec.Codec - store types.KVStore -} - -// NewList constructs new List -func NewList(cdc *codec.Codec, store types.KVStore) List { - return List{ - cdc: cdc, - store: store, - } -} - -// Len() returns the length of the list -// The length is only increased by Push() and not decreased -// List dosen't check if an index is in bounds -// The user should check Len() before doing any actions -func (m List) Len() (res uint64) { - bz := m.store.Get(LengthKey()) - if bz == nil { - return 0 - } - - m.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &res) - return -} - -// Get() returns the element by its index -func (m List) Get(index uint64, ptr interface{}) error { - bz := m.store.Get(ElemKey(index)) - return m.cdc.UnmarshalBinaryLengthPrefixed(bz, ptr) -} - -// Set() stores the element to the given position -// Setting element out of range will break length counting -// Use Push() instead of Set() to append a new element -func (m List) Set(index uint64, value interface{}) { - bz := m.cdc.MustMarshalBinaryLengthPrefixed(value) - m.store.Set(ElemKey(index), bz) -} - -// Delete() deletes the element in the given position -// Other elements' indices are preserved after deletion -// Panics when the index is out of range -func (m List) Delete(index uint64) { - m.store.Delete(ElemKey(index)) -} - -// Push() inserts the element to the end of the list -// It will increase the length when it is called -func (m List) Push(value interface{}) { - length := m.Len() - m.Set(length, value) - m.store.Set(LengthKey(), m.cdc.MustMarshalBinaryLengthPrefixed(length+1)) -} - -// Iterate() is used to iterate over all existing elements in the list -// Return true in the continuation to break -// The second element of the continuation will indicate the position of the element -// Using it with Get() will return the same one with the provided element - -// CONTRACT: No writes may happen within a domain while iterating over it. -func (m List) Iterate(ptr interface{}, fn func(uint64) bool) { - iter := types.KVStorePrefixIterator(m.store, []byte{0x01}) - defer iter.Close() - for ; iter.Valid(); iter.Next() { - v := iter.Value() - m.cdc.MustUnmarshalBinaryLengthPrefixed(v, ptr) - - k := iter.Key() - s := string(k[len(k)-20:]) - - index, err := strconv.ParseUint(s, 10, 64) - if err != nil { - panic(err) - } - - if fn(index) { - break - } - } -} diff --git a/store/list/list_test.go b/store/list/list_test.go deleted file mode 100644 index 88eccd6c144b..000000000000 --- a/store/list/list_test.go +++ /dev/null @@ -1,98 +0,0 @@ -package list - -import ( - "math/rand" - "testing" - - "github.com/tendermint/tendermint/libs/log" - dbm "github.com/tendermint/tm-db" - - abci "github.com/tendermint/tendermint/abci/types" - - "github.com/stretchr/testify/require" - - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/store/rootmulti" - sdk "github.com/cosmos/cosmos-sdk/types" -) - -type TestStruct struct { - I uint64 - B bool -} - -func defaultComponents(key sdk.StoreKey) (sdk.Context, *codec.Codec) { - db := dbm.NewMemDB() - cms := rootmulti.NewStore(db) - cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db) - cms.LoadLatestVersion() - ctx := sdk.NewContext(cms, abci.Header{}, false, log.NewNopLogger()) - cdc := codec.New() - return ctx, cdc -} -func TestList(t *testing.T) { - key := sdk.NewKVStoreKey("test") - ctx, cdc := defaultComponents(key) - store := ctx.KVStore(key) - lm := NewList(cdc, store) - - val := TestStruct{1, true} - var res TestStruct - - lm.Push(val) - require.Equal(t, uint64(1), lm.Len()) - lm.Get(uint64(0), &res) - require.Equal(t, val, res) - - val = TestStruct{2, false} - lm.Set(uint64(0), val) - lm.Get(uint64(0), &res) - require.Equal(t, val, res) - - val = TestStruct{100, false} - lm.Push(val) - require.Equal(t, uint64(2), lm.Len()) - lm.Get(uint64(1), &res) - require.Equal(t, val, res) - - lm.Delete(uint64(1)) - require.Equal(t, uint64(2), lm.Len()) - - lm.Iterate(&res, func(index uint64) (brk bool) { - var temp TestStruct - lm.Get(index, &temp) - require.Equal(t, temp, res) - - require.True(t, index != 1) - return - }) - - lm.Iterate(&res, func(index uint64) (brk bool) { - lm.Set(index, TestStruct{res.I + 1, !res.B}) - return - }) - - lm.Get(uint64(0), &res) - require.Equal(t, TestStruct{3, true}, res) -} - -func TestListRandom(t *testing.T) { - key := sdk.NewKVStoreKey("test") - ctx, cdc := defaultComponents(key) - store := ctx.KVStore(key) - list := NewList(cdc, store) - mocklist := []uint32{} - - for i := 0; i < 100; i++ { - item := rand.Uint32() - list.Push(item) - mocklist = append(mocklist, item) - } - - for k, v := range mocklist { - k := k - var i uint32 - require.NotPanics(t, func() { list.Get(uint64(k), &i) }) - require.Equal(t, v, i) - } -} diff --git a/store/prefix/store.go b/store/prefix/store.go index 81a42e42f003..b6c8c6317eb7 100644 --- a/store/prefix/store.go +++ b/store/prefix/store.go @@ -97,7 +97,7 @@ func (s Store) Iterator(start, end []byte) types.Iterator { return newPrefixIterator(s.prefix, start, end, iter) } -// Implements KVStore +// ReverseIterator implements KVStore // Check https://github.com/tendermint/tendermint/blob/master/libs/db/prefix_db.go#L129 func (s Store) ReverseIterator(start, end []byte) types.Iterator { newstart := cloneAppend(s.prefix, start) @@ -117,10 +117,11 @@ func (s Store) ReverseIterator(start, end []byte) types.Iterator { var _ types.Iterator = (*prefixIterator)(nil) type prefixIterator struct { - prefix []byte - start, end []byte - iter types.Iterator - valid bool + prefix []byte + start []byte + end []byte + iter types.Iterator + valid bool } func newPrefixIterator(prefix, start, end []byte, parent types.Iterator) *prefixIterator { @@ -134,53 +135,54 @@ func newPrefixIterator(prefix, start, end []byte, parent types.Iterator) *prefix } // Implements Iterator -func (iter *prefixIterator) Domain() ([]byte, []byte) { - return iter.start, iter.end +func (pi *prefixIterator) Domain() ([]byte, []byte) { + return pi.start, pi.end } // Implements Iterator -func (iter *prefixIterator) Valid() bool { - return iter.valid && iter.iter.Valid() +func (pi *prefixIterator) Valid() bool { + return pi.valid && pi.iter.Valid() } // Implements Iterator -func (iter *prefixIterator) Next() { - if !iter.valid { +func (pi *prefixIterator) Next() { + if !pi.valid { panic("prefixIterator invalid, cannot call Next()") } - iter.iter.Next() - if !iter.iter.Valid() || !bytes.HasPrefix(iter.iter.Key(), iter.prefix) { - iter.valid = false + pi.iter.Next() + if !pi.iter.Valid() || !bytes.HasPrefix(pi.iter.Key(), pi.prefix) { + // TODO: shouldn't pi be set to nil instead? + pi.valid = false } } // Implements Iterator -func (iter *prefixIterator) Key() (key []byte) { - if !iter.valid { +func (pi *prefixIterator) Key() (key []byte) { + if !pi.valid { panic("prefixIterator invalid, cannot call Key()") } - key = iter.iter.Key() - key = stripPrefix(key, iter.prefix) + key = pi.iter.Key() + key = stripPrefix(key, pi.prefix) return } // Implements Iterator -func (iter *prefixIterator) Value() []byte { - if !iter.valid { +func (pi *prefixIterator) Value() []byte { + if !pi.valid { panic("prefixIterator invalid, cannot call Value()") } - return iter.iter.Value() + return pi.iter.Value() } // Implements Iterator -func (iter *prefixIterator) Close() { - iter.iter.Close() +func (pi *prefixIterator) Close() { + pi.iter.Close() } // Error returns an error if the prefixIterator is invalid defined by the Valid // method. -func (iter *prefixIterator) Error() error { - if !iter.Valid() { +func (pi *prefixIterator) Error() error { + if !pi.Valid() { return errors.New("invalid prefixIterator") } diff --git a/store/queue/queue.go b/store/queue/queue.go deleted file mode 100644 index 0f65d0375ba3..000000000000 --- a/store/queue/queue.go +++ /dev/null @@ -1,93 +0,0 @@ -package store - -// TODO: make it independent from list -/* -import ( - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/cosmos/cosmos-sdk/store/list" -) - -// Key for the top element position in the queue -func TopKey() []byte { - return []byte{0x02} -} - -// Queue is a List wrapper that provides queue-like functions -// It panics when the element type cannot be (un/)marshalled by the codec -type Queue struct { - List list.List -} - -// NewQueue constructs new Queue -func NewQueue(cdc *codec.Codec, store sdk.KVStore) Queue { - return Queue{NewList(cdc, store)} -} - -func (m Queue) getTop() (res uint64) { - bz := m.List.store.Get(TopKey()) - if bz == nil { - return 0 - } - - m.List.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &res) - return -} - -func (m Queue) setTop(top uint64) { - bz := m.List.cdc.MustMarshalBinaryLengthPrefixed(top) - m.List.store.Set(TopKey(), bz) -} - -// Push() inserts the elements to the rear of the queue -func (m Queue) Push(value interface{}) { - m.List.Push(value) -} - -// Popping/Peeking on an empty queue will cause panic -// The user should check IsEmpty() before doing any actions -// Peek() returns the element at the front of the queue without removing it -func (m Queue) Peek(ptr interface{}) error { - top := m.getTop() - return m.List.Get(top, ptr) -} - -// Pop() returns the element at the front of the queue and removes it -func (m Queue) Pop() { - top := m.getTop() - m.List.Delete(top) - m.setTop(top + 1) -} - -// IsEmpty() checks if the queue is empty -func (m Queue) IsEmpty() bool { - top := m.getTop() - length := m.List.Len() - return top >= length -} - -// Flush() removes elements it processed -// Return true in the continuation to break -// The interface{} is unmarshalled before the continuation is called -// Starts from the top(head) of the queue -// CONTRACT: Pop() or Push() should not be performed while flushing -func (m Queue) Flush(ptr interface{}, fn func() bool) { - top := m.getTop() - length := m.List.Len() - - var i uint64 - for i = top; i < length; i++ { - err := m.List.Get(i, ptr) - if err != nil { - // TODO: Handle with #870 - panic(err) - } - m.List.Delete(i) - if fn() { - break - } - } - m.setTop(i) -} -*/ diff --git a/store/rootmulti/proof.go b/store/rootmulti/proof.go index ad090b706a63..a2fef8ae3ce9 100644 --- a/store/rootmulti/proof.go +++ b/store/rootmulti/proof.go @@ -21,7 +21,6 @@ func NewMultiStoreProof(storeInfos []storeInfo) *MultiStoreProof { // ComputeRootHash returns the root hash for a given multi-store proof. func (proof *MultiStoreProof) ComputeRootHash() []byte { ci := commitInfo{ - Version: -1, // TODO: Not needed; improve code. StoreInfos: proof.StoreInfos, } return ci.Hash() diff --git a/store/rootmulti/store.go b/store/rootmulti/store.go index 42c7b05ab589..c88657741617 100644 --- a/store/rootmulti/store.go +++ b/store/rootmulti/store.go @@ -5,11 +5,14 @@ import ( "io" "strings" + "github.com/pkg/errors" + abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto/merkle" "github.com/tendermint/tendermint/crypto/tmhash" dbm "github.com/tendermint/tm-db" + "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/cachemulti" "github.com/cosmos/cosmos-sdk/store/dbadapter" "github.com/cosmos/cosmos-sdk/store/iavl" @@ -24,6 +27,8 @@ const ( commitInfoKeyFmt = "s/%d" // s/ ) +var cdc = codec.New() + // Store is composed of many CommitStores. Name contrasts with // cacheMultiStore which is for cache-wrapping other MultiStores. It implements // the CommitMultiStore interface. @@ -77,21 +82,21 @@ func (rs *Store) SetLazyLoading(lazyLoading bool) { rs.lazyLoading = lazyLoading } -// Implements Store. +// GetStoreType implements Store. func (rs *Store) GetStoreType() types.StoreType { return types.StoreTypeMulti } -// Implements CommitMultiStore. +// MountStoreWithDB implements CommitMultiStore. func (rs *Store) MountStoreWithDB(key types.StoreKey, typ types.StoreType, db dbm.DB) { if key == nil { panic("MountIAVLStore() key cannot be nil") } if _, ok := rs.storesParams[key]; ok { - panic(fmt.Sprintf("Store duplicate store key %v", key)) + panic(fmt.Sprintf("store duplicate store key %v", key)) } if _, ok := rs.keysByName[key.Name()]; ok { - panic(fmt.Sprintf("Store duplicate store key name %v", key)) + panic(fmt.Sprintf("store duplicate store key name %v", key)) } rs.storesParams[key] = storeParams{ key: key, @@ -168,14 +173,14 @@ func (rs *Store) loadVersion(ver int64, upgrades *types.StoreUpgrades) error { // Load it store, err := rs.loadCommitStoreFromParams(key, rs.getCommitID(infos, key.Name()), storeParams) if err != nil { - return fmt.Errorf("failed to load Store: %v", err) + return errors.Wrap(err, "failed to load store") } newStores[key] = store // If it was deleted, remove all data if upgrades.IsDeleted(key.Name()) { if err := deleteKVStore(store.(types.KVStore)); err != nil { - return fmt.Errorf("failed to delete store %s: %v", key.Name(), err) + return errors.Wrapf(err, "failed to delete store %s", key.Name()) } } else if oldName := upgrades.RenamedFrom(key.Name()); oldName != "" { // handle renames specially @@ -187,12 +192,12 @@ func (rs *Store) loadVersion(ver int64, upgrades *types.StoreUpgrades) error { // load from the old name oldStore, err := rs.loadCommitStoreFromParams(oldKey, rs.getCommitID(infos, oldName), oldParams) if err != nil { - return fmt.Errorf("failed to load old Store '%s': %v", oldName, err) + return errors.Wrapf(err, "failed to load old store %s", oldName) } // move all data if err := moveKVStoreData(oldStore.(types.KVStore), store.(types.KVStore)); err != nil { - return fmt.Errorf("failed to move store %s -> %s: %v", oldName, key.Name(), err) + return errors.Wrapf(err, "failed to move store %s -> %s", oldName, key.Name()) } } } @@ -279,12 +284,12 @@ func (rs *Store) TracingEnabled() bool { //---------------------------------------- // +CommitStore -// Implements Committer/CommitStore. +// LastCommitID implements Committer/CommitStore. func (rs *Store) LastCommitID() types.CommitID { return rs.lastCommitInfo.CommitID() } -// Implements Committer/CommitStore. +// Commit implements Committer/CommitStore. func (rs *Store) Commit() types.CommitID { // Commit stores. @@ -304,7 +309,7 @@ func (rs *Store) Commit() types.CommitID { return commitID } -// Implements CacheWrapper/Store/CommitStore. +// CacheWrap implements CacheWrapper/Store/CommitStore. func (rs *Store) CacheWrap() types.CacheWrap { return rs.CacheMultiStore().(types.CacheWrap) } @@ -656,16 +661,16 @@ func getCommitInfo(db dbm.DB, ver int64) (commitInfo, error) { cInfoKey := fmt.Sprintf(commitInfoKeyFmt, ver) cInfoBytes, err := db.Get([]byte(cInfoKey)) if err != nil { - return commitInfo{}, fmt.Errorf("failed to get commit info: %v", err) + return commitInfo{}, errors.Wrap(err, "failed to get commit info") } else if cInfoBytes == nil { - return commitInfo{}, fmt.Errorf("failed to get commit info: no data") + return commitInfo{}, errors.New("failed to get commit info: no data") } var cInfo commitInfo err = cdc.UnmarshalBinaryLengthPrefixed(cInfoBytes, &cInfo) if err != nil { - return commitInfo{}, fmt.Errorf("failed to get Store: %v", err) + return commitInfo{}, errors.Wrap(err, "failed to get store") } return cInfo, nil diff --git a/store/rootmulti/store_test.go b/store/rootmulti/store_test.go index 164f231a2ac2..f798c4c76d27 100644 --- a/store/rootmulti/store_test.go +++ b/store/rootmulti/store_test.go @@ -49,6 +49,7 @@ func TestStoreMount(t *testing.T) { require.NotPanics(t, func() { store.MountStoreWithDB(key2, types.StoreTypeIAVL, db) }) require.Panics(t, func() { store.MountStoreWithDB(key1, types.StoreTypeIAVL, db) }) + require.Panics(t, func() { store.MountStoreWithDB(nil, types.StoreTypeIAVL, db) }) require.Panics(t, func() { store.MountStoreWithDB(dup1, types.StoreTypeIAVL, db) }) } diff --git a/store/rootmulti/wire.go b/store/rootmulti/wire.go deleted file mode 100644 index 8d6d936160ff..000000000000 --- a/store/rootmulti/wire.go +++ /dev/null @@ -1,7 +0,0 @@ -package rootmulti - -import ( - "github.com/cosmos/cosmos-sdk/codec" -) - -var cdc = codec.New() diff --git a/store/tracekv/store.go b/store/tracekv/store.go index ef891526fc23..b23a97c3ec19 100644 --- a/store/tracekv/store.go +++ b/store/tracekv/store.go @@ -3,10 +3,10 @@ package tracekv import ( "encoding/base64" "encoding/json" - "fmt" "io" "github.com/cosmos/cosmos-sdk/store/types" + "github.com/cosmos/cosmos-sdk/types/errors" ) const ( @@ -187,11 +187,11 @@ func writeOperation(w io.Writer, op operation, tc types.TraceContext, key, value raw, err := json.Marshal(traceOp) if err != nil { - panic(fmt.Sprintf("failed to serialize trace operation: %v", err)) + panic(errors.Wrap(err, "failed to serialize trace operation")) } if _, err := w.Write(raw); err != nil { - panic(fmt.Sprintf("failed to write trace operation: %v", err)) + panic(errors.Wrap(err, "failed to write trace operation")) } io.WriteString(w, "\n") From 88d01a986974b8bac818e195b55b8b9006b111d1 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Fri, 6 Mar 2020 08:40:50 -0500 Subject: [PATCH 380/529] Remove redundant staking APIs (#5755) --- x/slashing/handler_test.go | 9 ++++----- x/staking/keeper/delegation.go | 29 ++++++---------------------- x/staking/keeper/delegation_test.go | 4 ++-- x/staking/keeper/val_state_change.go | 4 ++-- 4 files changed, 14 insertions(+), 32 deletions(-) diff --git a/x/slashing/handler_test.go b/x/slashing/handler_test.go index 955eeadb8e5c..0759dfdf9109 100644 --- a/x/slashing/handler_test.go +++ b/x/slashing/handler_test.go @@ -6,16 +6,15 @@ import ( "testing" "time" - "github.com/cosmos/cosmos-sdk/x/slashing/types" - - "github.com/cosmos/cosmos-sdk/simapp" + "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" + "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/slashing" slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" + "github.com/cosmos/cosmos-sdk/x/slashing/types" "github.com/cosmos/cosmos-sdk/x/staking" - "github.com/stretchr/testify/require" ) func TestCannotUnjailUnlessJailed(t *testing.T) { @@ -133,7 +132,7 @@ func TestJailedValidatorDelegations(t *testing.T) { require.NoError(t, err) require.NotNil(t, res) - err = app.StakingKeeper.CompleteUnbonding(ctx, sdk.AccAddress(valAddr), valAddr) + _, err = app.StakingKeeper.CompleteUnbonding(ctx, sdk.AccAddress(valAddr), valAddr) require.Nil(t, err, "expected complete unbonding validator to be ok, got: %v", err) // verify validator still exists and is jailed diff --git a/x/staking/keeper/delegation.go b/x/staking/keeper/delegation.go index 8b61f8abbd4e..e5c1912daf36 100644 --- a/x/staking/keeper/delegation.go +++ b/x/staking/keeper/delegation.go @@ -671,10 +671,10 @@ func (k Keeper) Undelegate( return completionTime, nil } -// CompleteUnbondingWithAmount completes the unbonding of all mature entries in -// the retrieved unbonding delegation object and returns the total unbonding -// balance or an error upon failure. -func (k Keeper) CompleteUnbondingWithAmount(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) (sdk.Coins, error) { +// CompleteUnbonding completes the unbonding of all mature entries in the +// retrieved unbonding delegation object and returns the total unbonding balance +// or an error upon failure. +func (k Keeper) CompleteUnbonding(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) (sdk.Coins, error) { ubd, found := k.GetUnbondingDelegation(ctx, delAddr, valAddr) if !found { return nil, types.ErrNoUnbondingDelegation @@ -716,13 +716,6 @@ func (k Keeper) CompleteUnbondingWithAmount(ctx sdk.Context, delAddr sdk.AccAddr return balances, nil } -// CompleteUnbonding performs the same logic as CompleteUnbondingWithAmount except -// it does not return the total unbonding amount. -func (k Keeper) CompleteUnbonding(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) error { - _, err := k.CompleteUnbondingWithAmount(ctx, delAddr, valAddr) - return err -} - // begin unbonding / redelegation; create a redelegation record func (k Keeper) BeginRedelegation( ctx sdk.Context, delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress, sharesAmount sdk.Dec, @@ -780,10 +773,10 @@ func (k Keeper) BeginRedelegation( return completionTime, nil } -// CompleteRedelegationWithAmount completes the redelegations of all mature entries in the +// CompleteRedelegation completes the redelegations of all mature entries in the // retrieved redelegation object and returns the total redelegation (initial) // balance or an error upon failure. -func (k Keeper) CompleteRedelegationWithAmount( +func (k Keeper) CompleteRedelegation( ctx sdk.Context, delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress, ) (sdk.Coins, error) { @@ -819,16 +812,6 @@ func (k Keeper) CompleteRedelegationWithAmount( return balances, nil } -// CompleteRedelegation performs the same logic as CompleteRedelegationWithAmount -// except it does not return the total redelegation amount. -func (k Keeper) CompleteRedelegation( - ctx sdk.Context, delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress, -) error { - - _, err := k.CompleteRedelegationWithAmount(ctx, delAddr, valSrcAddr, valDstAddr) - return err -} - // ValidateUnbondAmount validates that a given unbond or redelegation amount is // valied based on upon the converted shares. If the amount is valid, the total // amount of respective shares is returned, otherwise an error is returned. diff --git a/x/staking/keeper/delegation_test.go b/x/staking/keeper/delegation_test.go index e1f7b7de2464..b89d8353672e 100644 --- a/x/staking/keeper/delegation_test.go +++ b/x/staking/keeper/delegation_test.go @@ -282,7 +282,7 @@ func TestUnbondingDelegationsMaxEntries(t *testing.T) { // mature unbonding delegations ctx = ctx.WithBlockTime(completionTime) - err = app.StakingKeeper.CompleteUnbonding(ctx, addrDels[0], addrVals[0]) + _, err = app.StakingKeeper.CompleteUnbonding(ctx, addrDels[0], addrVals[0]) require.NoError(t, err) newBonded = app.BankKeeper.GetBalance(ctx, app.StakingKeeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount @@ -794,7 +794,7 @@ func TestRedelegationMaxEntries(t *testing.T) { // mature redelegations ctx = ctx.WithBlockTime(completionTime) - err = app.StakingKeeper.CompleteRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1]) + _, err = app.StakingKeeper.CompleteRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1]) require.NoError(t, err) // redelegation should work again diff --git a/x/staking/keeper/val_state_change.go b/x/staking/keeper/val_state_change.go index b5f05cf9a00f..9927d6ed2329 100644 --- a/x/staking/keeper/val_state_change.go +++ b/x/staking/keeper/val_state_change.go @@ -32,7 +32,7 @@ func (k Keeper) BlockValidatorUpdates(ctx sdk.Context) []abci.ValidatorUpdate { // Remove all mature unbonding delegations from the ubd queue. matureUnbonds := k.DequeueAllMatureUBDQueue(ctx, ctx.BlockHeader().Time) for _, dvPair := range matureUnbonds { - balances, err := k.CompleteUnbondingWithAmount(ctx, dvPair.DelegatorAddress, dvPair.ValidatorAddress) + balances, err := k.CompleteUnbonding(ctx, dvPair.DelegatorAddress, dvPair.ValidatorAddress) if err != nil { continue } @@ -50,7 +50,7 @@ func (k Keeper) BlockValidatorUpdates(ctx sdk.Context) []abci.ValidatorUpdate { // Remove all mature redelegations from the red queue. matureRedelegations := k.DequeueAllMatureRedelegationQueue(ctx, ctx.BlockHeader().Time) for _, dvvTriplet := range matureRedelegations { - balances, err := k.CompleteRedelegationWithAmount( + balances, err := k.CompleteRedelegation( ctx, dvvTriplet.DelegatorAddress, dvvTriplet.ValidatorSrcAddress, From 3753d969afe0c148da38ece2c649b902158ac77f Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Fri, 6 Mar 2020 10:05:01 -0500 Subject: [PATCH 381/529] ADR 020 skeleton --- docs/architecture/README.md | 1 + .../adr-019-protobuf-state-encoding.md | 2 -- .../adr-020-protobuf-client-encoding.md | 23 +++++++++++++++++++ 3 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 docs/architecture/adr-020-protobuf-client-encoding.md diff --git a/docs/architecture/README.md b/docs/architecture/README.md index e327a5b642d5..6476ccab601f 100644 --- a/docs/architecture/README.md +++ b/docs/architecture/README.md @@ -45,3 +45,4 @@ Please add a entry below in your Pull Request for an ADR. - [ADR 017: Historical Header Module](./adr-017-historical-header-module.md) - [ADR 018: Extendable Voting Periods](./adr-018-extendable-voting-period.md) - [ADR 019: Protocol Buffer State Encoding](./adr-019-protobuf-state-encoding.md) +- [ADR 020: Protocol Buffer Client Encoding](./adr-020-protobuf-client-encoding.md) diff --git a/docs/architecture/adr-019-protobuf-state-encoding.md b/docs/architecture/adr-019-protobuf-state-encoding.md index d09052866581..78a338cccb12 100644 --- a/docs/architecture/adr-019-protobuf-state-encoding.md +++ b/docs/architecture/adr-019-protobuf-state-encoding.md @@ -309,8 +309,6 @@ at the application-level. ### Neutral -{neutral consequences} - ## References 1. https://github.com/cosmos/cosmos-sdk/issues/4977 diff --git a/docs/architecture/adr-020-protobuf-client-encoding.md b/docs/architecture/adr-020-protobuf-client-encoding.md new file mode 100644 index 000000000000..8e20ff6e9878 --- /dev/null +++ b/docs/architecture/adr-020-protobuf-client-encoding.md @@ -0,0 +1,23 @@ +# ADR 020: Protocol Buffer Client Encoding + +## Changelog + +- 2020 March 06: Initial Draft + +## Status + +Proposed + +## Context + +## Decision + +## Consequences + +### Positive + +### Negative + +### Neutral + +## References From b064e1841cfc448c8ee031ceb1db51e1e8a97988 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Fri, 6 Mar 2020 10:16:29 -0500 Subject: [PATCH 382/529] Update context --- docs/architecture/adr-020-protobuf-client-encoding.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/architecture/adr-020-protobuf-client-encoding.md b/docs/architecture/adr-020-protobuf-client-encoding.md index 8e20ff6e9878..ab28ad4d5828 100644 --- a/docs/architecture/adr-020-protobuf-client-encoding.md +++ b/docs/architecture/adr-020-protobuf-client-encoding.md @@ -10,6 +10,17 @@ Proposed ## Context +This ADR is a continuation of the motivation, design, and context established in +[ADR 019](./adr-019-protobuf-state-encoding.md), namely, we aim to design the +Protocol Buffer migration path for the client-side of the Cosmos SDK. + +Specifically, the client-side migration path primarily includes tx generation and +signing, message construction and routing, in addition to CLI & REST handlers and +business logic (i.e. queriers). + +With this in mind, we will tackle the migration path via two main areas, txs and +querying. + ## Decision ## Consequences From 1b51a043e20af9f83fd065db9ece6aec8ad182d2 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Fri, 6 Mar 2020 10:16:30 -0500 Subject: [PATCH 383/529] Fix x/auth GET commands (#5756) Fix x/auth GET commands. Fix QueryParamsCmd. --- x/auth/client/cli/query.go | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/x/auth/client/cli/query.go b/x/auth/client/cli/query.go index 0ef0a46e91a4..1d7e60639aa9 100644 --- a/x/auth/client/cli/query.go +++ b/x/auth/client/cli/query.go @@ -6,6 +6,7 @@ import ( "github.com/spf13/cobra" "github.com/spf13/viper" + tmtypes "github.com/tendermint/tendermint/types" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" @@ -16,8 +17,6 @@ import ( "github.com/cosmos/cosmos-sdk/version" authclient "github.com/cosmos/cosmos-sdk/x/auth/client" "github.com/cosmos/cosmos-sdk/x/auth/types" - - tmtypes "github.com/tendermint/tendermint/types" ) const ( @@ -37,10 +36,8 @@ func GetQueryCmd(cdc *codec.Codec) *cobra.Command { } cmd.AddCommand( - flags.GetCommands( - GetAccountCmd(cdc), - QueryParamsCmd(cdc), - )..., + GetAccountCmd(cdc), + QueryParamsCmd(cdc), ) return cmd @@ -48,7 +45,7 @@ func GetQueryCmd(cdc *codec.Codec) *cobra.Command { // QueryParamsCmd returns the command handler for evidence parameter querying. func QueryParamsCmd(cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ + cmd := &cobra.Command{ Use: "params", Short: "Query the current auth parameters", Args: cobra.NoArgs, @@ -73,6 +70,8 @@ $ query auth params return cliCtx.PrintOutput(params) }, } + + return flags.GetCommands(cmd)[0] } // GetAccountCmd returns a query account that will display the state of the From 812ed54239fb4d21491c22faa1c2853a08189ea5 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Fri, 6 Mar 2020 10:54:29 -0500 Subject: [PATCH 384/529] Update transactions section --- .../adr-020-protobuf-client-encoding.md | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/docs/architecture/adr-020-protobuf-client-encoding.md b/docs/architecture/adr-020-protobuf-client-encoding.md index ab28ad4d5828..9c928ef0ed93 100644 --- a/docs/architecture/adr-020-protobuf-client-encoding.md +++ b/docs/architecture/adr-020-protobuf-client-encoding.md @@ -23,6 +23,59 @@ querying. ## Decision +### Transactions + +Since the messages that an application is known and allowed to handle are specific +to the application itself, so must the transactions be specific to the application +itself. Similar to how we described in [ADR 019](./adr-019-protobuf-state-encoding.md), +the concrete types will be defined at the application level via Protobuf `oneof`. + +The application will define a single canonical `Message` Protobuf message +with a single `oneof` that implements the SDK's `Msg` interface. + +Example: + +```protobuf +// app/codec/codec.proto + +message Message { + option (cosmos_proto.interface_type) = "github.com/cosmos/cosmos-sdk/types.Msg"; + + oneof sum { + bank.MsgSend = 1; + staking.MsgCreateValidator = 2; + staking.MsgDelegate = 3; + // ... + } +} +``` + +Because an application needs to define it's unique `Message` Protobuf message, it +will by proxy have to define a `Transaction` Protobuf message that encapsulates this +`Message` type. The `Transaction` message type must implement the SDK's `Tx` interface. + +Example: + +```protobuf +// app/codec/codec.proto + +message Transaction { + option (cosmos_proto.interface_type) = "github.com/cosmos/cosmos-sdk/types.Tx"; + + StdTxBase base = 1; + repeated Message msgs = 2; +} +``` + +Note, the `Transaction` type includes `StdTxBase` which will be defined by the SDK +and includes all the core field members that are common across all transaction types. +Developers do not have to include `StdTxBase` if they wish, so it is meant to be +used as an auxiliary type. + +### Signing + +### CLI, REST, & Querying + ## Consequences ### Positive From aaa2bcc79364258beb8dc3f3f6610727ee52cc79 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Fri, 6 Mar 2020 11:28:24 -0500 Subject: [PATCH 385/529] Add section on signing --- .../adr-020-protobuf-client-encoding.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/architecture/adr-020-protobuf-client-encoding.md b/docs/architecture/adr-020-protobuf-client-encoding.md index 9c928ef0ed93..a70099eba6fb 100644 --- a/docs/architecture/adr-020-protobuf-client-encoding.md +++ b/docs/architecture/adr-020-protobuf-client-encoding.md @@ -74,6 +74,24 @@ used as an auxiliary type. ### Signing +Signing of a `Transaction` must be canonical across clients and binaries. In order +to provide canonical representation of a `Transaction` to sign over, clients must +obey the following rules: + +- Encode `StdSignDoc` (see below) via [Protobuf's canonical JSON encoding](https://developers.google.com/protocol-buffers/docs/proto3#json). + - Default and zero values must be stripped from the output (`0`, `“”`, `null`, `false`, `[]`, and `{}`). +- Generate canonical JSON to sign via the [JSON Canonical Form Spec](https://gibson042.github.io/canonicaljson-spec/). + - This spec should be trivial to interpret and implement in any language. + +```Protobuf +// app/codec/codec.proto + +message StdSignDoc { + StdSignDocBase base = 1; + repeated Message msgs = 2; +} +``` + ### CLI, REST, & Querying ## Consequences From c56915d5a5669521040cc70683031ebe9215e28b Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Fri, 6 Mar 2020 12:29:44 -0500 Subject: [PATCH 386/529] Add remaining sections --- .../adr-020-protobuf-client-encoding.md | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/docs/architecture/adr-020-protobuf-client-encoding.md b/docs/architecture/adr-020-protobuf-client-encoding.md index a70099eba6fb..08845faedaea 100644 --- a/docs/architecture/adr-020-protobuf-client-encoding.md +++ b/docs/architecture/adr-020-protobuf-client-encoding.md @@ -94,12 +94,79 @@ message StdSignDoc { ### CLI, REST, & Querying +Currently, the queriers, REST, CLI and handlers encode and decode types via Amino +JSON encoding using a concrete Amino codec. Being that some of the types dealt with +in the client can be interfaces, similar to how we described in [ADR 019](./adr-019-protobuf-state-encoding.md), +the client logic will now need to take a codec interface that knows not only how +to handle all the types, but also knows how to generate transactions, signatures, +and messages. + +```go +type TxGenerator interface { + sdk.Tx + + NewTx() sdk.Tx + SetMsgs(...sdk.Msg) error + GetSignatures() []StdSignature + SetSignatures(...StdSignature) error +} +``` + +We then extend `codec.Marshaler` to also require fulfillment of `TxGenerator`. + +```go +type ClientMarshaler interface { + TxGenerator + codec.Marshaler +} +``` + +Then, each module will at the minimum accept a `ClientMarshaler` instead of a concrete +Amino codec. If the module needs to work with any interface types, it will use +the `Codec` interface defined by the module which now also includes `ClientMarshaler`. + +## Future Improvements + +Requiring application developers to have to redefine their `Message` Protobuf types +can be extremely tedious and may increase the surface area of bugs by potentially +missing one or more messages in the `oneof`. + +To circumvent this, an optional strategy can be taken that has each module define +it's own `oneof` and then the application-level `Message` simply imports each module's +`oneof`. However, this requires additional tooling and the use of reflection. + +Example: + +```protobuf +// app/codec/codec.proto + +message Message { + option (cosmos_proto.interface_type) = "github.com/cosmos/cosmos-sdk/types.Msg"; + + oneof sum { + bank.Msg = 1; + staking.Msg = 2; + // ... + } +} +``` + ## Consequences ### Positive +- Significant performance gains. +- Supports backward and forward type compatibility. +- Better support for cross-language clients. + ### Negative +- Learning curve required to understand and implement Protobuf messages. +- Less flexibility in cross-module type registration. We now need to define types +at the application-level. +- Client business logic and tx generation become a bit more complex as developers +have to define more types and implement more interfaces. + ### Neutral ## References From 9a78fc3b19b54038357e86ff03bd5a1baba7de9d Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Mon, 9 Mar 2020 09:49:30 -0400 Subject: [PATCH 387/529] Address review --- docs/architecture/README.md | 2 +- ... adr-020-protobuf-transaction-encoding.md} | 26 +++++++++++++------ 2 files changed, 19 insertions(+), 9 deletions(-) rename docs/architecture/{adr-020-protobuf-client-encoding.md => adr-020-protobuf-transaction-encoding.md} (86%) diff --git a/docs/architecture/README.md b/docs/architecture/README.md index 6476ccab601f..737217bb20a3 100644 --- a/docs/architecture/README.md +++ b/docs/architecture/README.md @@ -45,4 +45,4 @@ Please add a entry below in your Pull Request for an ADR. - [ADR 017: Historical Header Module](./adr-017-historical-header-module.md) - [ADR 018: Extendable Voting Periods](./adr-018-extendable-voting-period.md) - [ADR 019: Protocol Buffer State Encoding](./adr-019-protobuf-state-encoding.md) -- [ADR 020: Protocol Buffer Client Encoding](./adr-020-protobuf-client-encoding.md) +- [ADR 020: Protocol Buffer Transaction Encoding](./adr-020-protobuf-transaction-encoding.md) diff --git a/docs/architecture/adr-020-protobuf-client-encoding.md b/docs/architecture/adr-020-protobuf-transaction-encoding.md similarity index 86% rename from docs/architecture/adr-020-protobuf-client-encoding.md rename to docs/architecture/adr-020-protobuf-transaction-encoding.md index 08845faedaea..39d3b1421be5 100644 --- a/docs/architecture/adr-020-protobuf-client-encoding.md +++ b/docs/architecture/adr-020-protobuf-transaction-encoding.md @@ -1,4 +1,4 @@ -# ADR 020: Protocol Buffer Client Encoding +# ADR 020: Protocol Buffer Transaction Encoding ## Changelog @@ -19,7 +19,8 @@ signing, message construction and routing, in addition to CLI & REST handlers an business logic (i.e. queriers). With this in mind, we will tackle the migration path via two main areas, txs and -querying. +querying. However, this ADR solely focuses on transactions. Querying should be +addressed in a future ADR, but it should build off of these proposals. ## Decision @@ -78,7 +79,7 @@ Signing of a `Transaction` must be canonical across clients and binaries. In ord to provide canonical representation of a `Transaction` to sign over, clients must obey the following rules: -- Encode `StdSignDoc` (see below) via [Protobuf's canonical JSON encoding](https://developers.google.com/protocol-buffers/docs/proto3#json). +- Encode `SignDoc` (see below) via [Protobuf's canonical JSON encoding](https://developers.google.com/protocol-buffers/docs/proto3#json). - Default and zero values must be stripped from the output (`0`, `“”`, `null`, `false`, `[]`, and `{}`). - Generate canonical JSON to sign via the [JSON Canonical Form Spec](https://gibson042.github.io/canonicaljson-spec/). - This spec should be trivial to interpret and implement in any language. @@ -86,15 +87,15 @@ obey the following rules: ```Protobuf // app/codec/codec.proto -message StdSignDoc { +message SignDoc { StdSignDocBase base = 1; repeated Message msgs = 2; } ``` -### CLI, REST, & Querying +### CLI & REST -Currently, the queriers, REST, CLI and handlers encode and decode types via Amino +Currently, the REST and CLI handlers encode and decode types and txs via Amino JSON encoding using a concrete Amino codec. Being that some of the types dealt with in the client can be interfaces, similar to how we described in [ADR 019](./adr-019-protobuf-state-encoding.md), the client logic will now need to take a codec interface that knows not only how @@ -103,12 +104,21 @@ and messages. ```go type TxGenerator interface { + NewTx() ClientTx + SignBytes func(chainID string, num, seq uint64, fee StdFee, msgs []sdk.Msg, memo string) ([]byte, error) +} + +type ClientTx interface { sdk.Tx + codec.ProtoMarshaler - NewTx() sdk.Tx SetMsgs(...sdk.Msg) error GetSignatures() []StdSignature SetSignatures(...StdSignature) error + GetFee() StdFee + SetFee(StdFee) + GetMemo() string + SetMemo(string) } ``` @@ -123,7 +133,7 @@ type ClientMarshaler interface { Then, each module will at the minimum accept a `ClientMarshaler` instead of a concrete Amino codec. If the module needs to work with any interface types, it will use -the `Codec` interface defined by the module which now also includes `ClientMarshaler`. +the `Codec` interface defined by the module which also extends `ClientMarshaler`. ## Future Improvements From f218e4c42dc8d875460afac7130d5a2917397991 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Tue, 10 Mar 2020 09:41:37 -0400 Subject: [PATCH 388/529] Fix x/genutil ExportGenesis --- x/genutil/module.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x/genutil/module.go b/x/genutil/module.go index cedf7171f564..5853274f3bf2 100644 --- a/x/genutil/module.go +++ b/x/genutil/module.go @@ -90,6 +90,6 @@ func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data j // ExportGenesis returns the exported genesis state as raw bytes for the genutil // module. -func (am AppModule) ExportGenesis(_ sdk.Context, _ codec.JSONMarshaler) json.RawMessage { - return nil +func (am AppModule) ExportGenesis(_ sdk.Context, cdc codec.JSONMarshaler) json.RawMessage { + return am.DefaultGenesis(cdc) } From ca93d575a929e170dbb14f808a83fda03e23441b Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Tue, 10 Mar 2020 09:43:57 -0400 Subject: [PATCH 389/529] Add changelog entries --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 403d420cedea..d198aa7bb015 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -69,6 +69,7 @@ to now accept a `codec.JSONMarshaler` for modular serialization of genesis state ### Bug Fixes +* (x/genutil) [\#5775](https://github.com/cosmos/cosmos-sdk/pull/5775) Fix `ExportGenesis` in `x/genutil` to export default genesis state (`[]`) instead of `null`. * (baseapp) [\#5718](https://github.com/cosmos/cosmos-sdk/pull/5718) Remove call to `ctx.BlockGasMeter` during failed message validation which resulted in a panic when the tx execution mode was `CheckTx`. * (client) [\#5618](https://github.com/cosmos/cosmos-sdk/pull/5618) Fix crash on the client when the verifier is not set. From 2de4775a2561ebfab4ac0b7b0acc5a9b628bb969 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Tue, 10 Mar 2020 19:53:25 +0100 Subject: [PATCH 390/529] types/rest: add unit tests (#5779) * types/rest: add unit tests Drop unused functions: - ParseQueryParamBool() - ParseInt64OrReturnBadRequest() * Fix test * Disable parallelism * Reintroduce @fedekunze ParseQueryParamBool * Don't count Name() calls to fix flaky tests --- CHANGELOG.md | 1 + types/module/module_test.go | 4 +- types/rest/rest.go | 22 +---- types/rest/rest_test.go | 172 +++++++++++++++++++++++++++++++++++- 4 files changed, 175 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d198aa7bb015..ad2a9a102562 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -62,6 +62,7 @@ and provided directly the IAVL store. * (types) [\#5533](https://github.com/cosmos/cosmos-sdk/pull/5533) Refactored `AppModuleBasic` and `AppModuleGenesis` to now accept a `codec.JSONMarshaler` for modular serialization of genesis state. * (crypto/keys) [\#5735](https://github.com/cosmos/cosmos-sdk/pull/5735) Keyring's Update() function is now no-op. +* (types/rest) [\#5779](https://github.com/cosmos/cosmos-sdk/pull/5779) Drop unused Parse{Int64OrReturnBadRequest,QueryParamBool}() functions. ### Features diff --git a/types/module/module_test.go b/types/module/module_test.go index 5cafaf10939e..db2334696292 100644 --- a/types/module/module_test.go +++ b/types/module/module_test.go @@ -32,8 +32,8 @@ func TestBasicManager(t *testing.T) { mockAppModuleBasic1 := mocks.NewMockAppModuleBasic(mockCtrl) mockAppModuleBasic2 := mocks.NewMockAppModuleBasic(mockCtrl) - mockAppModuleBasic1.EXPECT().Name().Times(3).Return("mockAppModuleBasic1") - mockAppModuleBasic2.EXPECT().Name().Times(2).Return("mockAppModuleBasic2") + mockAppModuleBasic1.EXPECT().Name().AnyTimes().Return("mockAppModuleBasic1") + mockAppModuleBasic2.EXPECT().Name().AnyTimes().Return("mockAppModuleBasic2") mockAppModuleBasic1.EXPECT().DefaultGenesis(gomock.Eq(cdc)).Times(1).Return(json.RawMessage(``)) mockAppModuleBasic2.EXPECT().DefaultGenesis(gomock.Eq(cdc)).Times(1).Return(json.RawMessage(`{"key":"value"}`)) mockAppModuleBasic1.EXPECT().ValidateGenesis(gomock.Eq(cdc), gomock.Eq(wantDefaultGenesis["mockAppModuleBasic1"])).Times(1).Return(errFoo) diff --git a/types/rest/rest.go b/types/rest/rest.go index a6339097e765..258917586248 100644 --- a/types/rest/rest.go +++ b/types/rest/rest.go @@ -171,20 +171,6 @@ func WriteSimulationResponse(w http.ResponseWriter, cdc *codec.Codec, gas uint64 _, _ = w.Write(resp) } -// ParseInt64OrReturnBadRequest converts s to a int64 value. -func ParseInt64OrReturnBadRequest(w http.ResponseWriter, s string) (n int64, ok bool) { - var err error - - n, err = strconv.ParseInt(s, 10, 64) - if err != nil { - err := fmt.Errorf("'%s' is not a valid int64", s) - WriteErrorResponse(w, http.StatusBadRequest, err.Error()) - return n, false - } - - return n, true -} - // ParseUint64OrReturnBadRequest converts s to a uint64 value. func ParseUint64OrReturnBadRequest(w http.ResponseWriter, s string) (n uint64, ok bool) { var err error @@ -386,10 +372,8 @@ func ParseHTTPArgs(r *http.Request) (tags []string, page, limit int, err error) // ParseQueryParamBool parses the given param to a boolean. It returns false by // default if the string is not parseable to bool. func ParseQueryParamBool(r *http.Request, param string) bool { - valueStr := r.FormValue(param) - value := false - if ok, err := strconv.ParseBool(valueStr); err == nil { - value = ok + if value, err := strconv.ParseBool(r.FormValue(param)); err == nil { + return value } - return value + return false } diff --git a/types/rest/rest_test.go b/types/rest/rest_test.go index 6088569c8f09..e760627b4d4a 100644 --- a/types/rest/rest_test.go +++ b/types/rest/rest_test.go @@ -3,11 +3,13 @@ package rest import ( + "errors" "io" "io/ioutil" "net/http" "net/http/httptest" "sort" + "strings" "testing" "github.com/stretchr/testify/require" @@ -19,7 +21,23 @@ import ( "github.com/cosmos/cosmos-sdk/types" ) -func TestBaseReqValidateBasic(t *testing.T) { +func TestBaseReq_Sanitize(t *testing.T) { + t.Parallel() + sanitized := BaseReq{ChainID: " test", + Memo: "memo ", + From: " cosmos1cq0sxam6x4l0sv9yz3a2vlqhdhvt2k6jtgcse0 ", + Gas: " ", + GasAdjustment: " 0.3", + }.Sanitize() + require.Equal(t, BaseReq{ChainID: "test", + Memo: "memo", + From: "cosmos1cq0sxam6x4l0sv9yz3a2vlqhdhvt2k6jtgcse0", + Gas: "", + GasAdjustment: "0.3", + }, sanitized) +} + +func TestBaseReq_ValidateBasic(t *testing.T) { fromAddr := "cosmos1cq0sxam6x4l0sv9yz3a2vlqhdhvt2k6jtgcse0" tenstakes, err := types.ParseCoins("10stake") require.NoError(t, err) @@ -63,6 +81,7 @@ func TestBaseReqValidateBasic(t *testing.T) { } func TestParseHTTPArgs(t *testing.T) { + t.Parallel() req0 := mustNewRequest(t, "", "/", nil) req1 := mustNewRequest(t, "", "/?limit=5", nil) req2 := mustNewRequest(t, "", "/?page=5", nil) @@ -114,6 +133,7 @@ func TestParseHTTPArgs(t *testing.T) { } func TestParseQueryHeight(t *testing.T) { + t.Parallel() var emptyHeight int64 height := int64(1256756) @@ -155,6 +175,7 @@ func TestProcessPostResponse(t *testing.T) { // PubKey field ensures amino encoding is used first since standard // JSON encoding will panic on crypto.PubKey + t.Parallel() type mockAccount struct { Address types.AccAddress `json:"address"` Coins types.Coins `json:"coins"` @@ -205,6 +226,151 @@ func TestProcessPostResponse(t *testing.T) { runPostProcessResponse(t, ctx, acc, expectedWithIndent, true) } +func TestReadRESTReq(t *testing.T) { + t.Parallel() + reqBody := ioutil.NopCloser(strings.NewReader(`{"chain_id":"alessio","memo":"text"}`)) + req := &http.Request{Body: reqBody} + w := httptest.NewRecorder() + var br BaseReq + + // test OK + ReadRESTReq(w, req, codec.New(), &br) + require.Equal(t, BaseReq{ChainID: "alessio", Memo: "text"}, br) + res := w.Result() + require.Equal(t, http.StatusOK, res.StatusCode) + + // test non valid JSON + reqBody = ioutil.NopCloser(strings.NewReader(`MALFORMED`)) + req = &http.Request{Body: reqBody} + br = BaseReq{} + w = httptest.NewRecorder() + ReadRESTReq(w, req, codec.New(), &br) + require.Equal(t, br, br) + res = w.Result() + require.Equal(t, http.StatusBadRequest, res.StatusCode) +} + +func TestWriteSimulationResponse(t *testing.T) { + t.Parallel() + w := httptest.NewRecorder() + WriteSimulationResponse(w, codec.New(), 10) + res := w.Result() + require.Equal(t, http.StatusOK, res.StatusCode) + bs, err := ioutil.ReadAll(res.Body) + require.NoError(t, err) + t.Cleanup(func() { res.Body.Close() }) + require.Equal(t, `{"gas_estimate":"10"}`, string(bs)) +} + +func TestParseUint64OrReturnBadRequest(t *testing.T) { + t.Parallel() + w := httptest.NewRecorder() + _, ok := ParseUint64OrReturnBadRequest(w, "100") + require.True(t, ok) + require.Equal(t, http.StatusOK, w.Result().StatusCode) + + w = httptest.NewRecorder() + _, ok = ParseUint64OrReturnBadRequest(w, "-100") + require.False(t, ok) + require.Equal(t, http.StatusBadRequest, w.Result().StatusCode) +} + +func TestParseFloat64OrReturnBadRequest(t *testing.T) { + t.Parallel() + w := httptest.NewRecorder() + _, ok := ParseFloat64OrReturnBadRequest(w, "100", 0) + require.True(t, ok) + require.Equal(t, http.StatusOK, w.Result().StatusCode) + + w = httptest.NewRecorder() + _, ok = ParseFloat64OrReturnBadRequest(w, "bad request", 0) + require.False(t, ok) + require.Equal(t, http.StatusBadRequest, w.Result().StatusCode) + + w = httptest.NewRecorder() + ret, ok := ParseFloat64OrReturnBadRequest(w, "", 9.0) + require.Equal(t, float64(9), ret) + require.True(t, ok) + require.Equal(t, http.StatusOK, w.Result().StatusCode) +} + +func TestParseQueryParamBool(t *testing.T) { + req := httptest.NewRequest("GET", "/target?boolean=true", nil) + require.True(t, ParseQueryParamBool(req, "boolean")) + require.False(t, ParseQueryParamBool(req, "nokey")) + req = httptest.NewRequest("GET", "/target?boolean=false", nil) + require.False(t, ParseQueryParamBool(req, "boolean")) + require.False(t, ParseQueryParamBool(req, "")) +} + +func TestPostProcessResponseBare(t *testing.T) { + t.Parallel() + + // write bytes + ctx := context.CLIContext{} + w := httptest.NewRecorder() + bs := []byte("text string") + PostProcessResponseBare(w, ctx, bs) + res := w.Result() + require.Equal(t, http.StatusOK, res.StatusCode) + got, err := ioutil.ReadAll(res.Body) + require.NoError(t, err) + t.Cleanup(func() { res.Body.Close() }) + require.Equal(t, "text string", string(got)) + + // write struct and indent response + ctx = context.CLIContext{Indent: true}.WithCodec(codec.New()) + w = httptest.NewRecorder() + data := struct { + X int `json:"x"` + S string `json:"s"` + }{X: 10, S: "test"} + PostProcessResponseBare(w, ctx, data) + res = w.Result() + require.Equal(t, http.StatusOK, res.StatusCode) + got, err = ioutil.ReadAll(res.Body) + require.NoError(t, err) + t.Cleanup(func() { res.Body.Close() }) + require.Equal(t, `{ + "x": "10", + "s": "test" +}`, string(got)) + + // write struct, don't indent response + ctx = context.CLIContext{Indent: false}.WithCodec(codec.New()) + w = httptest.NewRecorder() + data = struct { + X int `json:"x"` + S string `json:"s"` + }{X: 10, S: "test"} + PostProcessResponseBare(w, ctx, data) + res = w.Result() + require.Equal(t, http.StatusOK, res.StatusCode) + got, err = ioutil.ReadAll(res.Body) + require.NoError(t, err) + t.Cleanup(func() { res.Body.Close() }) + require.Equal(t, `{"x":"10","s":"test"}`, string(got)) + + // test marshalling failure + ctx = context.CLIContext{Indent: false}.WithCodec(codec.New()) + w = httptest.NewRecorder() + data2 := badJSONMarshaller{} + PostProcessResponseBare(w, ctx, data2) + res = w.Result() + require.Equal(t, http.StatusInternalServerError, res.StatusCode) + got, err = ioutil.ReadAll(res.Body) + require.NoError(t, err) + t.Cleanup(func() { res.Body.Close() }) + require.Equal(t, []string([]string{"application/json"}), res.Header["Content-Type"]) + require.Equal(t, `{"error":"couldn't marshal"}`, string(got)) +} + +type badJSONMarshaller struct{} + +func (_ badJSONMarshaller) MarshalJSON() ([]byte, error) { + return nil, errors.New("couldn't marshal") +} + // asserts that ResponseRecorder returns the expected code and body // runs PostProcessResponse on the objects regular interface and on // the marshalled struct. @@ -218,7 +384,7 @@ func runPostProcessResponse(t *testing.T, ctx context.CLIContext, obj interface{ PostProcessResponse(w, ctx, obj) require.Equal(t, http.StatusOK, w.Code, w.Body) resp := w.Result() - defer resp.Body.Close() + t.Cleanup(func() { resp.Body.Close() }) body, err := ioutil.ReadAll(resp.Body) require.Nil(t, err) require.Equal(t, expectedBody, body) @@ -236,7 +402,7 @@ func runPostProcessResponse(t *testing.T, ctx context.CLIContext, obj interface{ PostProcessResponse(w, ctx, marshalled) require.Equal(t, http.StatusOK, w.Code, w.Body) resp = w.Result() - defer resp.Body.Close() + t.Cleanup(func() { resp.Body.Close() }) body, err = ioutil.ReadAll(resp.Body) require.Nil(t, err) require.Equal(t, expectedBody, body) From 8ef4a3dad069ceb3a7d2d393676a0eb2bf39aad6 Mon Sep 17 00:00:00 2001 From: Sunny Aggarwal Date: Tue, 10 Mar 2020 15:27:53 -0400 Subject: [PATCH 391/529] Rename adt-014-proportional-slashing.md to adr-014-proportional-slashing.md --- ...-proportional-slashing.md => adr-014-proportional-slashing.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/architecture/{adt-014-proportional-slashing.md => adr-014-proportional-slashing.md} (100%) diff --git a/docs/architecture/adt-014-proportional-slashing.md b/docs/architecture/adr-014-proportional-slashing.md similarity index 100% rename from docs/architecture/adt-014-proportional-slashing.md rename to docs/architecture/adr-014-proportional-slashing.md From 43c0d0061afb318ad1c19553fe1f4d0066660ea0 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 11 Mar 2020 10:08:15 -0400 Subject: [PATCH 392/529] Update changelog --- CHANGELOG.md | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad2a9a102562..e5054c8883d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -70,12 +70,10 @@ to now accept a `codec.JSONMarshaler` for modular serialization of genesis state ### Bug Fixes -* (x/genutil) [\#5775](https://github.com/cosmos/cosmos-sdk/pull/5775) Fix `ExportGenesis` in `x/genutil` to export default genesis state (`[]`) instead of `null`. * (baseapp) [\#5718](https://github.com/cosmos/cosmos-sdk/pull/5718) Remove call to `ctx.BlockGasMeter` during failed message validation which resulted in a panic when the tx execution mode was `CheckTx`. * (client) [\#5618](https://github.com/cosmos/cosmos-sdk/pull/5618) Fix crash on the client when the verifier is not set. * (x/distribution) [\#5620](https://github.com/cosmos/cosmos-sdk/pull/5620) Fix nil pointer deref in distribution tax/rewward validation helpers. -* (genesis) [\#5086](https://github.com/cosmos/cosmos-sdk/issues/5086) Ensure `gentxs` are always an empty array instead of `nil` * (types) [\#5741](https://github.com/cosmos/cosmos-sdk/issues/5741) Prevent ChainAnteDecorators() from panicking when empty AnteDecorator slice is supplied. * (modules) [\#5569](https://github.com/cosmos/cosmos-sdk/issues/5569) `InitGenesis`, for the relevant modules, now ensures module accounts exist. @@ -158,9 +156,6 @@ Buffers for state serialization instead of Amino. * (types) [\#5585](https://github.com/cosmos/cosmos-sdk/pull/5585) IBC additions: * `Coin` denomination max lenght has been increased to 32. * Added `CapabilityKey` alias for `StoreKey` to match IBC spec. -* (rest) [\#5648](https://github.com/cosmos/cosmos-sdk/pull/5648) Enhance /txs usability: - * Add `tx.minheight` key to filter transaction with an inclusive minimum block height - * Add `tx.maxheight` key to filter transaction with an inclusive maximum block height * (server) [\#5709](https://github.com/cosmos/cosmos-sdk/pull/5709) There are two new flags for pruning, `--pruning-keep-every` and `--pruning-snapshot-every` as an alternative to `--pruning`. They allow to fine tune the strategy for pruning the state. * (crypto/keys) [\#5739](https://github.com/cosmos/cosmos-sdk/pull/5739) Print an error message if the password input failed. @@ -409,14 +404,27 @@ to detail this new feature and how state transitions occur. ### Bug Fixes -* (rest) [\#5508](https://github.com/cosmos/cosmos-sdk/pull/5508) Fix `x/distribution` endpoints to properly return height in the response. -* (x/genutil) [\#5499](https://github.com/cosmos/cosmos-sdk/pull/) Ensure `DefaultGenesis` returns valid and non-nil default genesis state. * (client) [\#5303](https://github.com/cosmos/cosmos-sdk/issues/5303) Fix ignored error in tx generate only mode. * (cli) [\#4763](https://github.com/cosmos/cosmos-sdk/issues/4763) Fix flag `--min-self-delegation` for staking `EditValidator` * (keys) Fix ledger custom coin type support bug. * (x/gov) [\#5107](https://github.com/cosmos/cosmos-sdk/pull/5107) Sum validator operator's all voting power when tally votes * (rest) [\#5212](https://github.com/cosmos/cosmos-sdk/issues/5212) Fix pagination in the `/gov/proposals` handler. +## [v0.37.8] - 2020-03-11 + +### Bug Fixes + +* (rest) [\#5508](https://github.com/cosmos/cosmos-sdk/pull/5508) Fix `x/distribution` endpoints to properly return height in the response. +* (x/genutil) [\#5499](https://github.com/cosmos/cosmos-sdk/pull/) Ensure `DefaultGenesis` returns valid and non-nil default genesis state. +* (x/genutil) [\#5775](https://github.com/cosmos/cosmos-sdk/pull/5775) Fix `ExportGenesis` in `x/genutil` to export default genesis state (`[]`) instead of `null`. +* (genesis) [\#5086](https://github.com/cosmos/cosmos-sdk/issues/5086) Ensure `gentxs` are always an empty array instead of `nil`. + +### Improvements + +* (rest) [\#5648](https://github.com/cosmos/cosmos-sdk/pull/5648) Enhance /txs usability: + * Add `tx.minheight` key to filter transaction with an inclusive minimum block height + * Add `tx.maxheight` key to filter transaction with an inclusive maximum block height + ## [v0.37.7] - 2020-02-10 ### Improvements @@ -3024,6 +3032,7 @@ BUG FIXES: [Unreleased]: https://github.com/cosmos/cosmos-sdk/compare/v0.38.1...HEAD [v0.38.1]: https://github.com/cosmos/cosmos-sdk/releases/tag/v0.38.1 [v0.38.0]: https://github.com/cosmos/cosmos-sdk/releases/tag/v0.38.0 +[v0.37.8]: https://github.com/cosmos/cosmos-sdk/releases/tag/v0.37.8 [v0.37.7]: https://github.com/cosmos/cosmos-sdk/releases/tag/v0.37.7 [v0.37.6]: https://github.com/cosmos/cosmos-sdk/releases/tag/v0.37.6 [v0.37.5]: https://github.com/cosmos/cosmos-sdk/releases/tag/v0.37.5 From 34e22fbcb8859b18381a6c9e6704227c7ac5d5d3 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Wed, 11 Mar 2020 17:45:02 +0100 Subject: [PATCH 393/529] refactor parsing to use unified version --- x/gov/client/cli/parse.go | 3 ++- x/params/client/cli/tx.go | 7 +++++- x/params/client/cli/tx_test.go | 45 ++++++++++++++++++++++++++++++++++ x/params/client/utils/utils.go | 2 +- 4 files changed, 54 insertions(+), 3 deletions(-) create mode 100644 x/params/client/cli/tx_test.go diff --git a/x/gov/client/cli/parse.go b/x/gov/client/cli/parse.go index dd9415f18d19..e29840db7463 100644 --- a/x/gov/client/cli/parse.go +++ b/x/gov/client/cli/parse.go @@ -24,7 +24,8 @@ func parseSubmitProposalFlags() (*proposal, error) { for _, flag := range ProposalFlags { if viper.GetString(flag) != "" { - return nil, fmt.Errorf("--%s flag provided alongside --proposal, which is a noop", flag) + return nil, fmt.Errorf( + "--%s flag provided alongside --proposal, which is a noop", flag) } } diff --git a/x/params/client/cli/tx.go b/x/params/client/cli/tx.go index 67a890a51e96..6f5624083539 100644 --- a/x/params/client/cli/tx.go +++ b/x/params/client/cli/tx.go @@ -77,7 +77,12 @@ Where proposal.json contains: from := cliCtx.GetFromAddress() content := paramproposal.NewParameterChangeProposal(proposal.Title, proposal.Description, proposal.Changes.ToParamChanges()) - msg := govtypes.NewMsgSubmitProposal(content, proposal.Deposit, from) + deposit, err := sdk.ParseCoins(proposal.Deposit) + if err != nil { + return err + } + + msg := govtypes.NewMsgSubmitProposal(content, deposit, from) if err := msg.ValidateBasic(); err != nil { return err } diff --git a/x/params/client/cli/tx_test.go b/x/params/client/cli/tx_test.go new file mode 100644 index 000000000000..0f3cb5c499a3 --- /dev/null +++ b/x/params/client/cli/tx_test.go @@ -0,0 +1,45 @@ +package cli + +import ( + "io/ioutil" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/x/params/client/utils" +) + +func TestParseProposal(t *testing.T) { + cdc := codec.New() + okJSON, err := ioutil.TempFile("", "proposal") + require.Nil(t, err, "unexpected error") + okJSON.WriteString(` +{ + "title": "Staking Param Change", + "description": "Update max validators", + "changes": [ + { + "subspace": "staking", + "key": "MaxValidators", + "value": 1 + } + ], + "deposit": "1000stake" +} +`) + + proposal, err := utils.ParseParamChangeProposalJSON(cdc, okJSON.Name()) + require.NoError(t, err) + + require.Equal(t, "Staking Param Change", proposal.Title) + require.Equal(t, "Update max validators", proposal.Description) + require.Equal(t, "1000stake", proposal.Deposit) + require.Equal(t, utils.ParamChangesJSON{ + { + Subspace: "staking", + Key: "MaxValidators", + Value: []byte{0x31}, + }, + }, proposal.Changes) +} diff --git a/x/params/client/utils/utils.go b/x/params/client/utils/utils.go index 231c5e2b0605..2cac0b21a839 100644 --- a/x/params/client/utils/utils.go +++ b/x/params/client/utils/utils.go @@ -29,7 +29,7 @@ type ( Title string `json:"title" yaml:"title"` Description string `json:"description" yaml:"description"` Changes ParamChangesJSON `json:"changes" yaml:"changes"` - Deposit sdk.Coins `json:"deposit" yaml:"deposit"` + Deposit string `json:"deposit" yaml:"deposit"` } // ParamChangeProposalReq defines a parameter change proposal request body. From 36554e73e22206dbee0c7f5f031b6319c4a669df Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Wed, 11 Mar 2020 18:03:47 +0100 Subject: [PATCH 394/529] refactor cli tx for distribution param change request --- x/distribution/client/cli/tx.go | 13 ++++++++++-- x/distribution/client/cli/tx_test.go | 30 ++++++++++++++++++++++++++++ x/distribution/client/cli/utils.go | 4 ++-- 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/x/distribution/client/cli/tx.go b/x/distribution/client/cli/tx.go index a033fd28dc1c..12baebcf07fe 100644 --- a/x/distribution/client/cli/tx.go +++ b/x/distribution/client/cli/tx.go @@ -248,9 +248,18 @@ Where proposal.json contains: } from := cliCtx.GetFromAddress() - content := types.NewCommunityPoolSpendProposal(proposal.Title, proposal.Description, proposal.Recipient, proposal.Amount) - msg := gov.NewMsgSubmitProposal(content, proposal.Deposit, from) + amount, err := sdk.ParseCoins(proposal.Amount) + if err != nil { + return err + } + content := types.NewCommunityPoolSpendProposal(proposal.Title, proposal.Description, proposal.Recipient, amount) + + deposit, err := sdk.ParseCoins(proposal.Deposit) + if err != nil { + return err + } + msg := gov.NewMsgSubmitProposal(content, deposit, from) if err := msg.ValidateBasic(); err != nil { return err } diff --git a/x/distribution/client/cli/tx_test.go b/x/distribution/client/cli/tx_test.go index 860b31fa634c..d8f8b3921c1b 100644 --- a/x/distribution/client/cli/tx_test.go +++ b/x/distribution/client/cli/tx_test.go @@ -1,8 +1,11 @@ package cli import ( + "io/ioutil" "testing" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/assert" "github.com/tendermint/tendermint/crypto/secp256k1" @@ -77,3 +80,30 @@ func Test_splitAndCall_Splitting(t *testing.T) { assert.NoError(t, err, "") assert.Equal(t, 3, callCount) } + +func TestParseProposal(t *testing.T) { + cdc := codec.New() + okJSON, err := ioutil.TempFile("", "proposal") + require.Nil(t, err, "unexpected error") + okJSON.WriteString(` +{ + "title": "Community Pool Spend", + "description": "Pay me some Atoms!", + "recipient": "cosmos1s5afhd6gxevu37mkqcvvsj8qeylhn0rz46zdlq", + "amount": "1000stake", + "deposit": "1000stake" +} +`) + + proposal, err := ParseCommunityPoolSpendProposalJSON(cdc, okJSON.Name()) + require.NoError(t, err) + + addr, err := sdk.AccAddressFromBech32("cosmos1s5afhd6gxevu37mkqcvvsj8qeylhn0rz46zdlq") + require.NoError(t, err) + + require.Equal(t, "Community Pool Spend", proposal.Title) + require.Equal(t, "Pay me some Atoms!", proposal.Description) + require.Equal(t, addr, proposal.Recipient) + require.Equal(t, "1000stake", proposal.Deposit) + require.Equal(t, "1000stake", proposal.Amount) +} diff --git a/x/distribution/client/cli/utils.go b/x/distribution/client/cli/utils.go index 286016250228..4d4169a7fad0 100644 --- a/x/distribution/client/cli/utils.go +++ b/x/distribution/client/cli/utils.go @@ -13,8 +13,8 @@ type ( Title string `json:"title" yaml:"title"` Description string `json:"description" yaml:"description"` Recipient sdk.AccAddress `json:"recipient" yaml:"recipient"` - Amount sdk.Coins `json:"amount" yaml:"amount"` - Deposit sdk.Coins `json:"deposit" yaml:"deposit"` + Amount string `json:"amount" yaml:"amount"` + Deposit string `json:"deposit" yaml:"deposit"` } ) From 382e5021b24c2dd3faeefef30959d8db7b087e8a Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Wed, 11 Mar 2020 18:06:39 +0100 Subject: [PATCH 395/529] update cli documentation distribution --- x/distribution/client/cli/tx.go | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/x/distribution/client/cli/tx.go b/x/distribution/client/cli/tx.go index 12baebcf07fe..35d12391d057 100644 --- a/x/distribution/client/cli/tx.go +++ b/x/distribution/client/cli/tx.go @@ -220,18 +220,8 @@ Where proposal.json contains: "title": "Community Pool Spend", "description": "Pay me some Atoms!", "recipient": "cosmos1s5afhd6gxevu37mkqcvvsj8qeylhn0rz46zdlq", - "amount": [ - { - "denom": "stake", - "amount": "10000" - } - ], - "deposit": [ - { - "denom": "stake", - "amount": "10000" - } - ] + "amount": "1000stake", + "deposit": "1000stake" } `, version.ClientName, From 1c7ec9e3391b0f02e1984a9628e76d25f7238446 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Wed, 11 Mar 2020 18:07:49 +0100 Subject: [PATCH 396/529] update params cli msg --- x/params/client/cli/tx.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/x/params/client/cli/tx.go b/x/params/client/cli/tx.go index 6f5624083539..969d9052ea56 100644 --- a/x/params/client/cli/tx.go +++ b/x/params/client/cli/tx.go @@ -53,12 +53,7 @@ Where proposal.json contains: "value": 105 } ], - "deposit": [ - { - "denom": "stake", - "amount": "10000" - } - ] + "deposit": "1000stake" } `, version.ClientName, From 520b397dc2157bd5dd29d97357d1c4ffb1c383eb Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Wed, 11 Mar 2020 18:12:10 +0100 Subject: [PATCH 397/529] update cli --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad2a9a102562..c00a127ee293 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ balances or a single balance by denom when the `denom` query parameter is presen * (client) [\#5640](https://github.com/cosmos/cosmos-sdk/pull/5640) The rest server endpoint `/swagger-ui/` is replaced by ´/´. * (x/auth) [\#5702](https://github.com/cosmos/cosmos-sdk/pull/5702) The `x/auth` querier route has changed from `"acc"` to `"auth"`. * (store/types) [\#5730](https://github.com/cosmos/cosmos-sdk/pull/5730) store.types.Cp() is removed in favour of types.CopyBytes(). +* (client) [\#5640](https://github.com/cosmos/cosmos-sdk/issues/5783) Unify all coins representations on json client requests. ### API Breaking Changes From f8897308d64b268a8543e748e90651f8ae7a498a Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Thu, 12 Mar 2020 01:29:38 +0100 Subject: [PATCH 398/529] fix error's raw log messages ugly encoding Closes: #5785 --- CHANGELOG.md | 3 +++ x/bank/keeper/keeper.go | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5054c8883d8..22a94af27293 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,9 @@ balances or a single balance by denom when the `denom` query parameter is presen * (client) [\#5640](https://github.com/cosmos/cosmos-sdk/pull/5640) The rest server endpoint `/swagger-ui/` is replaced by ´/´. * (x/auth) [\#5702](https://github.com/cosmos/cosmos-sdk/pull/5702) The `x/auth` querier route has changed from `"acc"` to `"auth"`. * (store/types) [\#5730](https://github.com/cosmos/cosmos-sdk/pull/5730) store.types.Cp() is removed in favour of types.CopyBytes(). +* [\#5785](https://github.com/cosmos/cosmos-sdk/issues/5785) JSON strings coerced to valid UTF-8 bytes at JSON marshalling time +are now replaced by human-readable expressions. This change can potentially break compatibility with all those client side tools +that parse log messages. ### API Breaking Changes diff --git a/x/bank/keeper/keeper.go b/x/bank/keeper/keeper.go index b1b2bdfa7a4e..330ab201f57e 100644 --- a/x/bank/keeper/keeper.go +++ b/x/bank/keeper/keeper.go @@ -67,7 +67,7 @@ func (k BaseKeeper) DelegateCoins(ctx sdk.Context, delegatorAddr, moduleAccAddr balance := k.GetBalance(ctx, delegatorAddr, coin.Denom) if balance.IsLT(coin) { return sdkerrors.Wrapf( - sdkerrors.ErrInsufficientFunds, "failed to delegate; %s < %s", balance, amt, + sdkerrors.ErrInsufficientFunds, "failed to delegate; %s is smaller than %s", balance, amt, ) } @@ -265,7 +265,7 @@ func (k BaseSendKeeper) SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, amt _, hasNeg := sdk.Coins{spendable}.SafeSub(sdk.Coins{coin}) if hasNeg { - return nil, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, "%s < %s", spendable, coin) + return nil, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, "%s is smaller than %s", spendable, coin) } newBalance := balance.Sub(coin) From 02ade535b77a7f6e4354fa316d5edfddee2e23e3 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 12 Mar 2020 13:48:09 +0100 Subject: [PATCH 399/529] Bump github.com/tendermint/tendermint from 0.33.1 to 0.33.2 (#5788) --- go.mod | 2 +- go.sum | 237 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 234 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index c010e24ab730..446acc15d813 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,7 @@ require ( github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 github.com/tendermint/go-amino v0.15.1 github.com/tendermint/iavl v0.13.0 - github.com/tendermint/tendermint v0.33.1 + github.com/tendermint/tendermint v0.33.2 github.com/tendermint/tm-db v0.4.1 gopkg.in/yaml.v2 v2.2.8 ) diff --git a/go.sum b/go.sum index ae529cbb3acf..a1723495d767 100644 --- a/go.sum +++ b/go.sum @@ -1,23 +1,42 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/99designs/keyring v1.1.4 h1:x0g0zQ9bQKgNsLo0XSXAy1H8Q1RG/td+5OXJt+Ci8b8= github.com/99designs/keyring v1.1.4/go.mod h1:657DQuMrBZRtuL/voxVyiyb6zpMehlm5vLB9Qwrv904= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/ChainSafe/go-schnorrkel v0.0.0-20200102211924-4bcbc698314f h1:4O1om+UVU+Hfcihr1timk8YNXHxzZWgCo7ofnrZRApw= github.com/ChainSafe/go-schnorrkel v0.0.0-20200102211924-4bcbc698314f/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4= +github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/Workiva/go-datastructures v1.0.50/go.mod h1:Z+F2Rca0qCsVYDS8z7bAGm8f3UkzuWYS/oBZz5a7VVA= +github.com/Workiva/go-datastructures v1.0.52/go.mod h1:Z+F2Rca0qCsVYDS8z7bAGm8f3UkzuWYS/oBZz5a7VVA= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/bartekn/go-bip39 v0.0.0-20171116152956-a05967ea095d h1:1aAija9gr0Hyv4KfQcRcwlmFIrhkDmIj2dz5bkg/s/8= github.com/bartekn/go-bip39 v0.0.0-20171116152956-a05967ea095d/go.mod h1:icNx/6QdFblhsEjZehARqbNumymUT/ydwlLojFdv7Sk= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/btcsuite/btcd v0.0.0-20190115013929-ed77733ec07d h1:xG8Pj6Y6J760xwETNmMzmlt38QSwz0BLp1cZ09g27uw= @@ -30,13 +49,23 @@ github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVa github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= +github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d h1:49RLWk1j44Xu4fjHb6JFYmeUnDORVwHNkDxaQ0ctCVU= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= @@ -44,7 +73,9 @@ github.com/cosmos/ledger-cosmos-go v0.11.1 h1:9JIYsGnXP613pb2vPjFeMMjBI5lEDsEaF6 github.com/cosmos/ledger-cosmos-go v0.11.1/go.mod h1:J8//BsAGTo3OC/vDLjMRFLW6q0WAaXvHnVc7ZmE8iUY= github.com/cosmos/ledger-go v0.9.2 h1:Nnao/dLwaVTk1Q5U9THldpUMMXU94BOTWPddSmVB6pI= github.com/cosmos/ledger-go v0.9.2/go.mod h1:oZJ2hHAZROdlHiwTg4t7kP+GKIIkBT+o6c9QWFanOyI= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/danieljoos/wincred v1.0.2 h1:zf4bhty2iLuwgjgpraD2E9UbvO+fe54XXGJbOwe23fU= github.com/danieljoos/wincred v1.0.2/go.mod h1:SnuYRW9lp1oJrZX/dXJqr0cPK5gYXqx3EJbmjhLdK9U= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -53,8 +84,14 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dvsekhvalnov/jose2go v0.0.0-20180829124132-7f401d37b68a h1:mq+R6XEM6lJX5VlLyZIrUSP8tSuJp82xTK89hvBwJbU= github.com/dvsekhvalnov/jose2go v0.0.0-20180829124132-7f401d37b68a/go.mod h1:7BvyPhdbLxMXIYTFPLsyJRFMsKmOZnQmzh6Gb+uquuM= +github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/etcd-io/bbolt v1.3.3 h1:gSJmxrs37LgTqR/oyJBWok6k6SvXEUerFTbltIhXkBM= @@ -65,25 +102,34 @@ github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojt github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 h1:E2s37DuLxFhQDg5gKsWoLBOB0n+ZW8s599zru8FJ2/Y= github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= +github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0 h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.10.0 h1:dXFJfIHVvUcpSgDOV+Ne6t7jXri8Tfv2uOLHUZ2XNuo= +github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= +github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.4.1 h1:ocYkMQY5RrXTYgXl7ICpV0IXwlEQGwKIsery4gyXa1U= github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= @@ -91,49 +137,88 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.4 h1:87PNWwrRvUSnqS4dlcBU/ftvOIBep4sYuBLlh6rX2wk= github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/handlers v1.4.2 h1:0QniY0USkHQ1RGCLfKxeNHK9bkDHGRYGNDFBCS+YARg= github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc= github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= github.com/gtank/merlin v0.1.1-0.20191105220539-8318aed1a79f h1:8N8XWLZelZNibkhM1FuF+3Ad3YIbgirjdMiVA0eUkaM= github.com/gtank/merlin v0.1.1-0.20191105220539-8318aed1a79f/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uMzcc= github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o= +github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= +github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U= github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= @@ -151,69 +236,140 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs= github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= +github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= +github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= +github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643 h1:hLDRPB66XQT/8+wG9WsDpiCvZf1yKO7sz7scAjSlBa0= github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= +github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= +github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= +github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= +github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= +github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= +github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= +github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= +github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= +github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.6.0 h1:aetoXYr0Tv7xRU/V4B4IZJ2QcbtMUFoNb3ORp7TzIK4= github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys= +github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= +github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v0.9.3 h1:9iH4JKXLzFbOAdtqv/a+j8aewx2Y8lAjAydhbaScPF8= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= +github.com/prometheus/client_golang v1.5.0 h1:Ctq0iGpCmr3jeP77kbF2UxgvRwzWWz+4Bh9/vJTyg1A= +github.com/prometheus/client_golang v1.5.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.0 h1:7etb9YClo3a6HjLzfl6rIQaU+FDfi0VSX39io3aQ+DM= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= +github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084 h1:sofwID9zm4tzrgykg80hfFph1mryUeLRsUfoocVVmRY= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rakyll/statik v0.1.7 h1:OF3QCZUuyPxuGEP7B4ypUa7sB/iHtqOTDYZXGM8KOdQ= github.com/rakyll/statik v0.1.7/go.mod h1:AlZONWzMtEnMs7W4e/1LURLiI49pIMmp6V9Unghqrcc= github.com/rcrowley/go-metrics v0.0.0-20180503174638-e2704e165165 h1:nkcn14uNmFEuGCb2mBZbBb24RdNRL08b/wb+xBOYpuk= github.com/rcrowley/go-metrics v0.0.0-20180503174638-e2704e165165/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a h1:9ZKAASQSHhDYGoxY8uLVpewe1GDZ2vu2Tr/vTdVAkFQ= +github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/regen-network/cosmos-proto v0.1.1-0.20200213154359-02baa11ea7c2 h1:jQK1YoH972Aptd22YKgtNu5jM2X2xMGkyIENOAc71to= github.com/regen-network/cosmos-proto v0.1.1-0.20200213154359-02baa11ea7c2/go.mod h1:+r7jN10xXCypD4yBgzKOa+vgLz0riqYMHeDcKekxPvA= github.com/regen-network/protobuf v1.3.2-alpha.regen.1 h1:YdeZbBS0lG1D13COb7b57+nM/RGgIs8WF9DwitU6EBM= github.com/regen-network/protobuf v1.3.2-alpha.regen.1/go.mod h1:lye6mqhOn/GCw1zRl3uPD5VP8rC+LPMyTyPAyQV872U= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/snikch/goodman v0.0.0-20171125024755-10e37e294daa/go.mod h1:oJyF+mSPHbB5mVY2iO9KV3pTt/QbIkGaO8gQ2WrDbP4= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.1 h1:qgMbHoJbPbw579P+1zVY+6n4nIFuIchaIjzZ/I/Yq8M= @@ -221,11 +377,13 @@ github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTd github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.1/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.6 h1:breEStsVwemnKh2/s6gMvSdMEkwW0sK8vGStnlVBMCs= github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= @@ -233,6 +391,9 @@ github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/y github.com/spf13/viper v1.6.1/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k= github.com/spf13/viper v1.6.2 h1:7aKfF+e8/k68gda3LOjo5RxiUqddoFxVq4BKBPrxk5E= github.com/spf13/viper v1.6.2/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k= +github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= @@ -261,14 +422,17 @@ github.com/tendermint/go-amino v0.15.1/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoM github.com/tendermint/iavl v0.13.0 h1:r2sINvNFlJsLlLhGoqlqPlREWYkuK26BvMfkBt+XQnA= github.com/tendermint/iavl v0.13.0/go.mod h1:7nSUPdrsHEZ2nNZa+9gaIrcJciWd1jCQZXtcyARU82k= github.com/tendermint/tendermint v0.33.0/go.mod h1:s5UoymnPIY+GcA3mMte4P9gpMP8vS7UH7HBXikT1pHI= -github.com/tendermint/tendermint v0.33.1 h1:8f68LUBz8yhISZvaLFP4siXXrLWsWeoYfelbdNtmvm4= -github.com/tendermint/tendermint v0.33.1/go.mod h1:fBOKyrlXOETqQ+heL8x/TZgSdmItON54csyabvktBp0= +github.com/tendermint/tendermint v0.33.2 h1:NzvRMTuXJxqSsFed2J7uHmMU5N1CVzSpfi3nCc882KY= +github.com/tendermint/tendermint v0.33.2/go.mod h1:25DqB7YvV1tN3tHsjWoc2vFtlwICfrub9XO6UBO+4xk= github.com/tendermint/tm-db v0.4.0 h1:iPbCcLbf4nwDFhS39Zo1lpdS1X/cT9CkTlUx17FHQgA= github.com/tendermint/tm-db v0.4.0/go.mod h1:+Cwhgowrf7NBGXmsqFMbwEtbo80XmyrlY5Jsk95JubQ= github.com/tendermint/tm-db v0.4.1 h1:TvX7JWjJOVZ+N3y+I86wddrGttOdMmmBxXcu0/Y7ZJ0= github.com/tendermint/tm-db v0.4.1/go.mod h1:JsJ6qzYkCGiGwm5GHl/H5GLI9XLb6qZX7PRe425dHAY= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/zondax/hid v0.9.0 h1:eiT3P6vNxAEVxXMw66eZUAAnU2zD33JBkfG/EnfAKl8= @@ -276,12 +440,23 @@ github.com/zondax/hid v0.9.0/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWp go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413 h1:ULYEB3JvPRE/IfO+9uO7vKV/xzVTO7XPAwm8xbf4w2g= @@ -289,64 +464,107 @@ golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82 h1:ywK/j/KkyTHcdyYSZNXGjMwgmDSfjglYZ3vStQ/gSCU= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200110213125-a7a6caa82ab2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f h1:2wh8dWY8959cBGQvk1RD+/eQBgRYYDaZ+hT0/zsARoA= google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= @@ -354,22 +572,33 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= rsc.io/quote/v3 v3.1.0 h1:9JKUTTIUgS6kzR9mK1YuGKv6Nl+DijDNIc0ghT58FaY= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= From 810a37802c66f15ba28be0ddfb8a99ce3d55cccc Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Thu, 12 Mar 2020 14:17:16 +0100 Subject: [PATCH 400/529] Update CHANGELOG.md Co-Authored-By: Alexander Bezobchuk --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e659229a266..c5c2d3ff6d58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,7 +44,7 @@ balances or a single balance by denom when the `denom` query parameter is presen * (client) [\#5640](https://github.com/cosmos/cosmos-sdk/pull/5640) The rest server endpoint `/swagger-ui/` is replaced by ´/´. * (x/auth) [\#5702](https://github.com/cosmos/cosmos-sdk/pull/5702) The `x/auth` querier route has changed from `"acc"` to `"auth"`. * (store/types) [\#5730](https://github.com/cosmos/cosmos-sdk/pull/5730) store.types.Cp() is removed in favour of types.CopyBytes(). -* (client) [\#5640](https://github.com/cosmos/cosmos-sdk/issues/5783) Unify all coins representations on json client requests. +* (client) [\#5640](https://github.com/cosmos/cosmos-sdk/issues/5783) Unify all coins representations on JSON client requests for governance proposals. ### API Breaking Changes From ee0e0aeaff8b47edfaad8b4ad7df61f202ffe802 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Thu, 12 Mar 2020 14:27:19 +0100 Subject: [PATCH 401/529] undo change --- x/gov/client/cli/parse.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/x/gov/client/cli/parse.go b/x/gov/client/cli/parse.go index e29840db7463..dd9415f18d19 100644 --- a/x/gov/client/cli/parse.go +++ b/x/gov/client/cli/parse.go @@ -24,8 +24,7 @@ func parseSubmitProposalFlags() (*proposal, error) { for _, flag := range ProposalFlags { if viper.GetString(flag) != "" { - return nil, fmt.Errorf( - "--%s flag provided alongside --proposal, which is a noop", flag) + return nil, fmt.Errorf("--%s flag provided alongside --proposal, which is a noop", flag) } } From 615fcd7645f9434505d255433f06a7fde859627b Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Thu, 12 Mar 2020 09:30:05 -0400 Subject: [PATCH 402/529] Define message proto --- codec/std/codec.pb.go | 2897 +++++++++++++++++++++++++++++++++-------- codec/std/codec.proto | 33 +- 2 files changed, 2354 insertions(+), 576 deletions(-) diff --git a/codec/std/codec.pb.go b/codec/std/codec.pb.go index ef4c65543df1..e330bd97edab 100644 --- a/codec/std/codec.pb.go +++ b/codec/std/codec.pb.go @@ -5,15 +5,20 @@ package std import ( fmt "fmt" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" github_com_cosmos_cosmos_sdk_x_auth_exported "github.com/cosmos/cosmos-sdk/x/auth/exported" types "github.com/cosmos/cosmos-sdk/x/auth/types" types1 "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" + types7 "github.com/cosmos/cosmos-sdk/x/bank/types" + types8 "github.com/cosmos/cosmos-sdk/x/crisis/types" types6 "github.com/cosmos/cosmos-sdk/x/distribution/types" github_com_cosmos_cosmos_sdk_x_evidence_exported "github.com/cosmos/cosmos-sdk/x/evidence/exported" types3 "github.com/cosmos/cosmos-sdk/x/evidence/types" github_com_cosmos_cosmos_sdk_x_gov_types "github.com/cosmos/cosmos-sdk/x/gov/types" types4 "github.com/cosmos/cosmos-sdk/x/gov/types" proposal "github.com/cosmos/cosmos-sdk/x/params/types/proposal" + types9 "github.com/cosmos/cosmos-sdk/x/slashing/types" + types10 "github.com/cosmos/cosmos-sdk/x/staking/types" github_com_cosmos_cosmos_sdk_x_supply_exported "github.com/cosmos/cosmos-sdk/x/supply/exported" types2 "github.com/cosmos/cosmos-sdk/x/supply/types" types5 "github.com/cosmos/cosmos-sdk/x/upgrade/types" @@ -572,6 +577,290 @@ func (*Content) XXX_OneofWrappers() []interface{} { } } +// Message defines the set of valid concrete message types that can be used to +// construct a transaction. +type Message struct { + // sum defines the set of all allowed valid messages defined in modules. + // + // Types that are valid to be assigned to Sum: + // *Message_MsgSend + // *Message_MsgMultiSend + // *Message_MsgVerifyInvariant + // *Message_MsgSetWithdrawAddress + // *Message_MsgWithdrawDelegatorReward + // *Message_MsgWithdrawValidatorCommission + // *Message_MsgFundCommunityPool + // *Message_MsgSubmitEvidence + // *Message_MsgSubmitProposal + // *Message_MsgVote + // *Message_MsgDeposit + // *Message_MsgUnjail + // *Message_MsgCreateValidator + // *Message_MsgEditValidator + // *Message_MsgDelegate + // *Message_MsgBeginRedelegate + // *Message_MsgUndelegate + Sum isMessage_Sum `protobuf_oneof:"sum"` +} + +func (m *Message) Reset() { *m = Message{} } +func (m *Message) String() string { return proto.CompactTextString(m) } +func (*Message) ProtoMessage() {} +func (*Message) Descriptor() ([]byte, []int) { + return fileDescriptor_daf09dc2dfa19bb4, []int{7} +} +func (m *Message) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Message) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Message.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 *Message) XXX_Merge(src proto.Message) { + xxx_messageInfo_Message.Merge(m, src) +} +func (m *Message) XXX_Size() int { + return m.Size() +} +func (m *Message) XXX_DiscardUnknown() { + xxx_messageInfo_Message.DiscardUnknown(m) +} + +var xxx_messageInfo_Message proto.InternalMessageInfo + +type isMessage_Sum interface { + isMessage_Sum() + MarshalTo([]byte) (int, error) + Size() int +} + +type Message_MsgSend struct { + MsgSend *types7.MsgSend `protobuf:"bytes,1,opt,name=msg_send,json=msgSend,proto3,oneof" json:"msg_send,omitempty"` +} +type Message_MsgMultiSend struct { + MsgMultiSend *types7.MsgMultiSend `protobuf:"bytes,2,opt,name=msg_multi_send,json=msgMultiSend,proto3,oneof" json:"msg_multi_send,omitempty"` +} +type Message_MsgVerifyInvariant struct { + MsgVerifyInvariant *types8.MsgVerifyInvariant `protobuf:"bytes,3,opt,name=msg_verify_invariant,json=msgVerifyInvariant,proto3,oneof" json:"msg_verify_invariant,omitempty"` +} +type Message_MsgSetWithdrawAddress struct { + MsgSetWithdrawAddress *types6.MsgSetWithdrawAddress `protobuf:"bytes,4,opt,name=msg_set_withdraw_address,json=msgSetWithdrawAddress,proto3,oneof" json:"msg_set_withdraw_address,omitempty"` +} +type Message_MsgWithdrawDelegatorReward struct { + MsgWithdrawDelegatorReward *types6.MsgWithdrawDelegatorReward `protobuf:"bytes,5,opt,name=msg_withdraw_delegator_reward,json=msgWithdrawDelegatorReward,proto3,oneof" json:"msg_withdraw_delegator_reward,omitempty"` +} +type Message_MsgWithdrawValidatorCommission struct { + MsgWithdrawValidatorCommission *types6.MsgWithdrawValidatorCommission `protobuf:"bytes,6,opt,name=msg_withdraw_validator_commission,json=msgWithdrawValidatorCommission,proto3,oneof" json:"msg_withdraw_validator_commission,omitempty"` +} +type Message_MsgFundCommunityPool struct { + MsgFundCommunityPool *types6.MsgFundCommunityPool `protobuf:"bytes,7,opt,name=msg_fund_community_pool,json=msgFundCommunityPool,proto3,oneof" json:"msg_fund_community_pool,omitempty"` +} +type Message_MsgSubmitEvidence struct { + MsgSubmitEvidence *MsgSubmitEvidence `protobuf:"bytes,8,opt,name=msg_submit_evidence,json=msgSubmitEvidence,proto3,oneof" json:"msg_submit_evidence,omitempty"` +} +type Message_MsgSubmitProposal struct { + MsgSubmitProposal *MsgSubmitProposal `protobuf:"bytes,9,opt,name=msg_submit_proposal,json=msgSubmitProposal,proto3,oneof" json:"msg_submit_proposal,omitempty"` +} +type Message_MsgVote struct { + MsgVote *types4.MsgVote `protobuf:"bytes,10,opt,name=msg_vote,json=msgVote,proto3,oneof" json:"msg_vote,omitempty"` +} +type Message_MsgDeposit struct { + MsgDeposit *types4.MsgDeposit `protobuf:"bytes,11,opt,name=msg_deposit,json=msgDeposit,proto3,oneof" json:"msg_deposit,omitempty"` +} +type Message_MsgUnjail struct { + MsgUnjail *types9.MsgUnjail `protobuf:"bytes,12,opt,name=msg_unjail,json=msgUnjail,proto3,oneof" json:"msg_unjail,omitempty"` +} +type Message_MsgCreateValidator struct { + MsgCreateValidator *types10.MsgCreateValidator `protobuf:"bytes,13,opt,name=msg_create_validator,json=msgCreateValidator,proto3,oneof" json:"msg_create_validator,omitempty"` +} +type Message_MsgEditValidator struct { + MsgEditValidator *types10.MsgEditValidator `protobuf:"bytes,14,opt,name=msg_edit_validator,json=msgEditValidator,proto3,oneof" json:"msg_edit_validator,omitempty"` +} +type Message_MsgDelegate struct { + MsgDelegate *types10.MsgDelegate `protobuf:"bytes,15,opt,name=msg_delegate,json=msgDelegate,proto3,oneof" json:"msg_delegate,omitempty"` +} +type Message_MsgBeginRedelegate struct { + MsgBeginRedelegate *types10.MsgBeginRedelegate `protobuf:"bytes,16,opt,name=msg_begin_redelegate,json=msgBeginRedelegate,proto3,oneof" json:"msg_begin_redelegate,omitempty"` +} +type Message_MsgUndelegate struct { + MsgUndelegate *types10.MsgUndelegate `protobuf:"bytes,17,opt,name=msg_undelegate,json=msgUndelegate,proto3,oneof" json:"msg_undelegate,omitempty"` +} + +func (*Message_MsgSend) isMessage_Sum() {} +func (*Message_MsgMultiSend) isMessage_Sum() {} +func (*Message_MsgVerifyInvariant) isMessage_Sum() {} +func (*Message_MsgSetWithdrawAddress) isMessage_Sum() {} +func (*Message_MsgWithdrawDelegatorReward) isMessage_Sum() {} +func (*Message_MsgWithdrawValidatorCommission) isMessage_Sum() {} +func (*Message_MsgFundCommunityPool) isMessage_Sum() {} +func (*Message_MsgSubmitEvidence) isMessage_Sum() {} +func (*Message_MsgSubmitProposal) isMessage_Sum() {} +func (*Message_MsgVote) isMessage_Sum() {} +func (*Message_MsgDeposit) isMessage_Sum() {} +func (*Message_MsgUnjail) isMessage_Sum() {} +func (*Message_MsgCreateValidator) isMessage_Sum() {} +func (*Message_MsgEditValidator) isMessage_Sum() {} +func (*Message_MsgDelegate) isMessage_Sum() {} +func (*Message_MsgBeginRedelegate) isMessage_Sum() {} +func (*Message_MsgUndelegate) isMessage_Sum() {} + +func (m *Message) GetSum() isMessage_Sum { + if m != nil { + return m.Sum + } + return nil +} + +func (m *Message) GetMsgSend() *types7.MsgSend { + if x, ok := m.GetSum().(*Message_MsgSend); ok { + return x.MsgSend + } + return nil +} + +func (m *Message) GetMsgMultiSend() *types7.MsgMultiSend { + if x, ok := m.GetSum().(*Message_MsgMultiSend); ok { + return x.MsgMultiSend + } + return nil +} + +func (m *Message) GetMsgVerifyInvariant() *types8.MsgVerifyInvariant { + if x, ok := m.GetSum().(*Message_MsgVerifyInvariant); ok { + return x.MsgVerifyInvariant + } + return nil +} + +func (m *Message) GetMsgSetWithdrawAddress() *types6.MsgSetWithdrawAddress { + if x, ok := m.GetSum().(*Message_MsgSetWithdrawAddress); ok { + return x.MsgSetWithdrawAddress + } + return nil +} + +func (m *Message) GetMsgWithdrawDelegatorReward() *types6.MsgWithdrawDelegatorReward { + if x, ok := m.GetSum().(*Message_MsgWithdrawDelegatorReward); ok { + return x.MsgWithdrawDelegatorReward + } + return nil +} + +func (m *Message) GetMsgWithdrawValidatorCommission() *types6.MsgWithdrawValidatorCommission { + if x, ok := m.GetSum().(*Message_MsgWithdrawValidatorCommission); ok { + return x.MsgWithdrawValidatorCommission + } + return nil +} + +func (m *Message) GetMsgFundCommunityPool() *types6.MsgFundCommunityPool { + if x, ok := m.GetSum().(*Message_MsgFundCommunityPool); ok { + return x.MsgFundCommunityPool + } + return nil +} + +func (m *Message) GetMsgSubmitEvidence() *MsgSubmitEvidence { + if x, ok := m.GetSum().(*Message_MsgSubmitEvidence); ok { + return x.MsgSubmitEvidence + } + return nil +} + +func (m *Message) GetMsgSubmitProposal() *MsgSubmitProposal { + if x, ok := m.GetSum().(*Message_MsgSubmitProposal); ok { + return x.MsgSubmitProposal + } + return nil +} + +func (m *Message) GetMsgVote() *types4.MsgVote { + if x, ok := m.GetSum().(*Message_MsgVote); ok { + return x.MsgVote + } + return nil +} + +func (m *Message) GetMsgDeposit() *types4.MsgDeposit { + if x, ok := m.GetSum().(*Message_MsgDeposit); ok { + return x.MsgDeposit + } + return nil +} + +func (m *Message) GetMsgUnjail() *types9.MsgUnjail { + if x, ok := m.GetSum().(*Message_MsgUnjail); ok { + return x.MsgUnjail + } + return nil +} + +func (m *Message) GetMsgCreateValidator() *types10.MsgCreateValidator { + if x, ok := m.GetSum().(*Message_MsgCreateValidator); ok { + return x.MsgCreateValidator + } + return nil +} + +func (m *Message) GetMsgEditValidator() *types10.MsgEditValidator { + if x, ok := m.GetSum().(*Message_MsgEditValidator); ok { + return x.MsgEditValidator + } + return nil +} + +func (m *Message) GetMsgDelegate() *types10.MsgDelegate { + if x, ok := m.GetSum().(*Message_MsgDelegate); ok { + return x.MsgDelegate + } + return nil +} + +func (m *Message) GetMsgBeginRedelegate() *types10.MsgBeginRedelegate { + if x, ok := m.GetSum().(*Message_MsgBeginRedelegate); ok { + return x.MsgBeginRedelegate + } + return nil +} + +func (m *Message) GetMsgUndelegate() *types10.MsgUndelegate { + if x, ok := m.GetSum().(*Message_MsgUndelegate); ok { + return x.MsgUndelegate + } + return nil +} + +// XXX_OneofWrappers is for the internal use of the proto package. +func (*Message) XXX_OneofWrappers() []interface{} { + return []interface{}{ + (*Message_MsgSend)(nil), + (*Message_MsgMultiSend)(nil), + (*Message_MsgVerifyInvariant)(nil), + (*Message_MsgSetWithdrawAddress)(nil), + (*Message_MsgWithdrawDelegatorReward)(nil), + (*Message_MsgWithdrawValidatorCommission)(nil), + (*Message_MsgFundCommunityPool)(nil), + (*Message_MsgSubmitEvidence)(nil), + (*Message_MsgSubmitProposal)(nil), + (*Message_MsgVote)(nil), + (*Message_MsgDeposit)(nil), + (*Message_MsgUnjail)(nil), + (*Message_MsgCreateValidator)(nil), + (*Message_MsgEditValidator)(nil), + (*Message_MsgDelegate)(nil), + (*Message_MsgBeginRedelegate)(nil), + (*Message_MsgUndelegate)(nil), + } +} + func init() { proto.RegisterType((*Account)(nil), "cosmos_sdk.codec.std.v1.Account") proto.RegisterType((*Supply)(nil), "cosmos_sdk.codec.std.v1.Supply") @@ -580,67 +869,101 @@ func init() { proto.RegisterType((*MsgSubmitProposal)(nil), "cosmos_sdk.codec.std.v1.MsgSubmitProposal") proto.RegisterType((*Proposal)(nil), "cosmos_sdk.codec.std.v1.Proposal") proto.RegisterType((*Content)(nil), "cosmos_sdk.codec.std.v1.Content") + proto.RegisterType((*Message)(nil), "cosmos_sdk.codec.std.v1.Message") } func init() { proto.RegisterFile("codec/std/codec.proto", fileDescriptor_daf09dc2dfa19bb4) } var fileDescriptor_daf09dc2dfa19bb4 = []byte{ - // 875 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x56, 0x41, 0x6f, 0xdc, 0x44, - 0x14, 0xb6, 0xa9, 0x9b, 0xac, 0xa6, 0x05, 0xca, 0x88, 0x90, 0x28, 0xa0, 0x4d, 0x1a, 0x44, 0x84, - 0x8a, 0x62, 0xb7, 0x14, 0x68, 0xba, 0x12, 0x6a, 0xbb, 0x4b, 0xd1, 0x22, 0x11, 0x14, 0x6d, 0x80, - 0x03, 0x02, 0x59, 0xde, 0x99, 0xc1, 0x6b, 0xd5, 0xf6, 0x0c, 0x9e, 0xb1, 0xf1, 0xfe, 0x03, 0xc4, - 0x09, 0x89, 0x3f, 0x10, 0xc1, 0x91, 0x6b, 0x8f, 0xfc, 0x80, 0xaa, 0xa7, 0x1c, 0x39, 0x55, 0x28, - 0xb9, 0xf0, 0x33, 0x90, 0x67, 0xc6, 0x5e, 0x5b, 0xf6, 0x6e, 0xd4, 0xcb, 0xca, 0x9e, 0xf7, 0x7d, - 0xef, 0xfb, 0xc6, 0x33, 0xef, 0xbd, 0x05, 0x1b, 0x88, 0x62, 0x82, 0x1c, 0x2e, 0xb0, 0x23, 0x9f, - 0x6c, 0x96, 0x50, 0x41, 0xe1, 0x26, 0xa2, 0x3c, 0xa2, 0xdc, 0xe5, 0xf8, 0x89, 0xad, 0xd6, 0xb9, - 0xc0, 0x76, 0x76, 0x67, 0xfb, 0x03, 0x31, 0x0b, 0x12, 0xec, 0x32, 0x2f, 0x11, 0x73, 0x47, 0x62, - 0x1d, 0x05, 0x3d, 0xa8, 0xbf, 0xa8, 0x2c, 0xdb, 0xfb, 0x6d, 0xb0, 0x4f, 0x7d, 0xba, 0x78, 0xd2, - 0xb8, 0xad, 0xdc, 0xf1, 0x52, 0x31, 0x73, 0xc4, 0x9c, 0x11, 0xae, 0x7e, 0x75, 0x64, 0x57, 0x47, - 0x32, 0xc2, 0x45, 0x10, 0xfb, 0x1d, 0x88, 0xed, 0xdc, 0xe1, 0x29, 0x63, 0xe1, 0xbc, 0x23, 0xf6, - 0x4e, 0xee, 0x90, 0x2c, 0xc0, 0x24, 0x46, 0xa4, 0x23, 0xba, 0x99, 0x3b, 0x3e, 0xcd, 0x3a, 0x02, - 0xef, 0xe6, 0x0e, 0xf3, 0x12, 0x2f, 0xd2, 0xab, 0x85, 0x73, 0x46, 0xb9, 0x17, 0x36, 0x40, 0x6f, - 0xe7, 0x4e, 0xca, 0xfc, 0xc4, 0xc3, 0xa4, 0xdb, 0x36, 0x0e, 0xb8, 0x48, 0x82, 0x69, 0x2a, 0x02, - 0x1a, 0xb7, 0x11, 0x7b, 0x7f, 0x5b, 0x60, 0xfd, 0x11, 0x42, 0x34, 0x8d, 0x05, 0xfc, 0x1c, 0x5c, - 0x9f, 0x7a, 0x9c, 0xb8, 0x9e, 0x7a, 0xdf, 0x32, 0x77, 0xcd, 0xf7, 0xaf, 0x7d, 0x78, 0xd3, 0xae, - 0x9d, 0x41, 0x6e, 0x17, 0x9f, 0xc1, 0xce, 0xee, 0xd8, 0x43, 0x8f, 0x13, 0x4d, 0x1c, 0x1b, 0x93, - 0x6b, 0xd3, 0xc5, 0x2b, 0xcc, 0xc0, 0x36, 0xa2, 0xb1, 0x08, 0xe2, 0x94, 0xa6, 0xdc, 0xd5, 0x9f, - 0xac, 0xca, 0xfa, 0x8a, 0xcc, 0xfa, 0x49, 0x57, 0x56, 0x85, 0x2c, 0xb2, 0x8f, 0x2a, 0xfe, 0xb7, - 0x6a, 0x71, 0x21, 0xb5, 0x85, 0x96, 0xc4, 0x60, 0x04, 0x36, 0x31, 0x09, 0xbd, 0x39, 0xc1, 0x2d, - 0xd1, 0x2b, 0x52, 0xf4, 0xee, 0x6a, 0xd1, 0xcf, 0x14, 0xb9, 0xa5, 0xb8, 0x81, 0xbb, 0x02, 0x90, - 0x81, 0x2d, 0x46, 0x92, 0x80, 0xe2, 0x00, 0xb5, 0xf4, 0x2c, 0xa9, 0xf7, 0xd1, 0x6a, 0xbd, 0x63, - 0xcd, 0x6e, 0x09, 0xbe, 0xc5, 0x3a, 0x23, 0xf0, 0x2b, 0xf0, 0x5a, 0x44, 0x71, 0x1a, 0x2e, 0x8e, - 0xe8, 0xaa, 0xd4, 0x79, 0xaf, 0xa9, 0xa3, 0xee, 0x61, 0xa1, 0x70, 0x24, 0xd1, 0x8b, 0xc4, 0xaf, - 0x46, 0xf5, 0x85, 0xc1, 0xfd, 0xe7, 0x4f, 0x0f, 0x3e, 0xbe, 0xe5, 0x07, 0x62, 0x96, 0x4e, 0x6d, - 0x44, 0x23, 0x5d, 0x35, 0x65, 0x25, 0x71, 0xfc, 0xc4, 0xd1, 0xf7, 0x9e, 0xe4, 0x8c, 0x26, 0x82, - 0x60, 0x5b, 0x53, 0x87, 0x57, 0xc1, 0x15, 0x9e, 0x46, 0x7b, 0xbf, 0x9a, 0x60, 0xed, 0x44, 0xca, - 0xc1, 0x43, 0xb0, 0xa6, 0x84, 0xf5, 0xbd, 0xe9, 0x2f, 0x33, 0xa5, 0xf0, 0x63, 0x63, 0xa2, 0xf1, - 0x83, 0x07, 0xff, 0x9d, 0xee, 0x98, 0xcf, 0x9f, 0x1e, 0xdc, 0xbb, 0xcc, 0x8a, 0x2e, 0xb0, 0xca, - 0x8c, 0xca, 0xf4, 0x45, 0x69, 0xe6, 0x0f, 0x13, 0xf4, 0x1e, 0xeb, 0x3a, 0x83, 0x5f, 0x82, 0xeb, - 0xe4, 0xa7, 0x34, 0xc8, 0x28, 0xf2, 0x8a, 0xab, 0xaf, 0x4d, 0xed, 0x37, 0x4d, 0x95, 0x55, 0x59, - 0xd8, 0x7a, 0x5c, 0x43, 0x8f, 0x8d, 0x49, 0x83, 0x3d, 0x78, 0xa4, 0x2d, 0xde, 0xbf, 0xc4, 0x61, - 0x55, 0xe6, 0x95, 0xc7, 0xd2, 0x50, 0x69, 0xf2, 0x2f, 0x13, 0xbc, 0x71, 0xc4, 0xfd, 0x93, 0x74, - 0x1a, 0x05, 0xa2, 0x72, 0xfb, 0x29, 0xe8, 0x95, 0xd4, 0xae, 0xb2, 0xab, 0xb7, 0xbe, 0x2a, 0xe3, - 0xa4, 0xa2, 0xc0, 0x23, 0x60, 0x15, 0x05, 0xa8, 0x6b, 0xcb, 0x59, 0xbe, 0xc9, 0x96, 0x72, 0x51, - 0xc6, 0xc3, 0xde, 0xb3, 0x17, 0x3b, 0xc6, 0xd9, 0x8b, 0x1d, 0x73, 0x22, 0xd3, 0x0c, 0x7a, 0xbf, - 0x9c, 0xee, 0x18, 0xc5, 0x8e, 0xf7, 0xfe, 0xac, 0xbb, 0x3d, 0xd6, 0xfd, 0x07, 0x8e, 0xb5, 0x9c, - 0x72, 0x7a, 0xab, 0x29, 0xe7, 0xd3, 0xac, 0xa1, 0x54, 0xb2, 0xba, 0x94, 0xe0, 0x00, 0xac, 0x17, - 0xe5, 0x4c, 0xaa, 0xbe, 0xb0, 0xbb, 0x74, 0xdb, 0x23, 0x85, 0x9b, 0x94, 0x84, 0x9a, 0xcb, 0xdf, - 0x4d, 0xd0, 0xab, 0xcc, 0x3d, 0x68, 0x98, 0xbb, 0xd9, 0x69, 0x6e, 0xa5, 0xa7, 0x87, 0x2f, 0xed, - 0x69, 0x68, 0x15, 0x29, 0x16, 0xce, 0x2c, 0xe9, 0xea, 0xd4, 0x02, 0xeb, 0x1a, 0x00, 0xef, 0x01, - 0x4b, 0x90, 0x5c, 0xac, 0x34, 0xf5, 0x35, 0xc9, 0xab, 0x8f, 0x35, 0x36, 0x26, 0x92, 0x00, 0xbf, - 0x07, 0x37, 0xe4, 0x0c, 0x20, 0x82, 0x24, 0x2e, 0x9a, 0x79, 0xb1, 0xbf, 0xe4, 0x94, 0xd5, 0xa4, - 0x90, 0x9b, 0x2b, 0xf1, 0x23, 0x09, 0xaf, 0xa5, 0x7c, 0x9d, 0x35, 0x43, 0xf0, 0x07, 0x70, 0x83, - 0xd3, 0x1f, 0xc5, 0xcf, 0x5e, 0x42, 0x5c, 0x3d, 0x45, 0x74, 0xab, 0xbc, 0xdd, 0xcc, 0xae, 0x83, - 0xb2, 0x7c, 0x35, 0xe1, 0x1b, 0xb5, 0x54, 0x4f, 0xcf, 0x9b, 0x21, 0xc8, 0xc0, 0x26, 0xf2, 0x62, - 0x44, 0x42, 0xb7, 0xa5, 0x62, 0x75, 0x4d, 0x81, 0x9a, 0xca, 0x48, 0xf2, 0x96, 0x6b, 0x6d, 0xa0, - 0x2e, 0x00, 0x0c, 0xc1, 0x9b, 0x88, 0x46, 0x51, 0x1a, 0x07, 0x62, 0xee, 0x32, 0x4a, 0x43, 0x97, - 0x33, 0x12, 0x63, 0xdd, 0x27, 0x0f, 0x9b, 0x72, 0xf5, 0xd1, 0xa8, 0x4e, 0x53, 0x33, 0x8f, 0x29, - 0x0d, 0x4f, 0x0a, 0x5e, 0x4d, 0x10, 0xa2, 0x56, 0x74, 0x70, 0xa8, 0xbb, 0xc2, 0xed, 0x4b, 0xba, - 0x42, 0x35, 0xde, 0xab, 0x0b, 0xa3, 0x9a, 0xc1, 0xf0, 0xe1, 0xb3, 0xf3, 0xbe, 0x79, 0x76, 0xde, - 0x37, 0xff, 0x3d, 0xef, 0x9b, 0xbf, 0x5d, 0xf4, 0x8d, 0xb3, 0x8b, 0xbe, 0xf1, 0xcf, 0x45, 0xdf, - 0xf8, 0x6e, 0x7f, 0x65, 0xca, 0xea, 0xcf, 0xd2, 0x74, 0x4d, 0x8e, 0xf1, 0xbb, 0xff, 0x07, 0x00, - 0x00, 0xff, 0xff, 0xf7, 0xf2, 0xb6, 0xa2, 0x40, 0x09, 0x00, 0x00, + // 1394 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x57, 0x4d, 0x6f, 0xd4, 0xc6, + 0x1b, 0xf7, 0xfe, 0x59, 0x92, 0x30, 0x09, 0x10, 0xe6, 0x0f, 0xcd, 0x2a, 0x85, 0x0d, 0x84, 0x16, + 0xb5, 0xa0, 0xac, 0x79, 0x69, 0x0b, 0xac, 0x5a, 0x01, 0x9b, 0x80, 0x96, 0xaa, 0x69, 0x91, 0x29, + 0xa9, 0x5a, 0xd1, 0x5a, 0xb3, 0x9e, 0xc1, 0x99, 0x66, 0xed, 0x71, 0x3d, 0xe3, 0xcd, 0xe6, 0xd0, + 0x7b, 0xdb, 0x53, 0xa5, 0x7e, 0x01, 0xd4, 0x1e, 0x7b, 0xe5, 0xd8, 0x73, 0x85, 0x38, 0x71, 0xec, + 0x09, 0x55, 0x70, 0xe9, 0xc7, 0xa8, 0xe6, 0xc5, 0x5e, 0x7b, 0xed, 0xdd, 0xd0, 0xcb, 0x6a, 0x67, + 0x9e, 0xe7, 0xf7, 0x32, 0x9e, 0x79, 0xe6, 0xb1, 0xc1, 0x09, 0x8f, 0x61, 0xe2, 0xd9, 0x5c, 0x60, + 0x5b, 0xfd, 0x6b, 0x45, 0x31, 0x13, 0x0c, 0x2e, 0x79, 0x8c, 0x07, 0x8c, 0xbb, 0x1c, 0xef, 0xb4, + 0xf4, 0x3c, 0x17, 0xb8, 0x35, 0xb8, 0xb4, 0x7c, 0x41, 0x6c, 0xd3, 0x18, 0xbb, 0x11, 0x8a, 0xc5, + 0x9e, 0xad, 0x72, 0x6d, 0x9d, 0xba, 0x96, 0x1f, 0x68, 0x96, 0xe5, 0x73, 0xe5, 0x64, 0x9f, 0xf9, + 0x6c, 0xf4, 0xcf, 0xe4, 0x35, 0x86, 0x36, 0x4a, 0xc4, 0xb6, 0x2d, 0xf6, 0x22, 0xc2, 0xf5, 0xaf, + 0x89, 0x9c, 0x36, 0x91, 0x01, 0xe1, 0x82, 0x86, 0x7e, 0x45, 0x46, 0x63, 0x68, 0xf7, 0x50, 0xb8, + 0x53, 0x11, 0x59, 0x1e, 0xda, 0x5e, 0x4c, 0x39, 0xe5, 0xd5, 0xbc, 0x98, 0x72, 0x11, 0xd3, 0x5e, + 0x22, 0x28, 0x0b, 0xab, 0xd1, 0x3c, 0x89, 0xa2, 0xfe, 0x5e, 0x45, 0xec, 0xe4, 0xd0, 0x26, 0x03, + 0x8a, 0x49, 0xe8, 0x91, 0x8a, 0xe8, 0xd2, 0xd0, 0xf6, 0xd9, 0xa0, 0x1a, 0xc6, 0xfb, 0x88, 0x6f, + 0x57, 0x2f, 0xe4, 0xcd, 0xa1, 0xcd, 0x05, 0xda, 0xa9, 0x0e, 0x9e, 0x1d, 0xda, 0x11, 0x8a, 0x51, + 0x90, 0xae, 0x25, 0x8a, 0x59, 0xc4, 0x38, 0xea, 0x8f, 0x33, 0x24, 0x91, 0x1f, 0x23, 0x5c, 0xe1, + 0x6a, 0xf5, 0x8f, 0x3a, 0x98, 0xbd, 0xe5, 0x79, 0x2c, 0x09, 0x05, 0xbc, 0x03, 0x16, 0x7a, 0x88, + 0x13, 0x17, 0xe9, 0x71, 0xa3, 0x76, 0xba, 0xf6, 0xce, 0xfc, 0xe5, 0x33, 0xad, 0xdc, 0xa6, 0x0f, + 0x5b, 0xf2, 0xb9, 0xb7, 0x06, 0x97, 0x5a, 0x1d, 0xc4, 0x89, 0x01, 0x76, 0x2d, 0x67, 0xbe, 0x37, + 0x1a, 0xc2, 0x01, 0x58, 0xf6, 0x58, 0x28, 0x68, 0x98, 0xb0, 0x84, 0xbb, 0x66, 0x8f, 0x32, 0xd6, + 0xff, 0x29, 0xd6, 0x0f, 0xaa, 0x58, 0x75, 0xa6, 0x64, 0x5f, 0xcf, 0xf0, 0x5b, 0x7a, 0x72, 0x24, + 0xd5, 0xf0, 0x26, 0xc4, 0x60, 0x00, 0x96, 0x30, 0xe9, 0xa3, 0x3d, 0x82, 0x4b, 0xa2, 0x07, 0x94, + 0xe8, 0x95, 0xe9, 0xa2, 0x1b, 0x1a, 0x5c, 0x52, 0x3c, 0x81, 0xab, 0x02, 0x30, 0x02, 0x8d, 0x88, + 0xc4, 0x94, 0x61, 0xea, 0x95, 0xf4, 0xea, 0x4a, 0xef, 0xbd, 0xe9, 0x7a, 0xf7, 0x0c, 0xba, 0x24, + 0xf8, 0x46, 0x54, 0x19, 0x81, 0x9f, 0x82, 0x23, 0x01, 0xc3, 0x49, 0x7f, 0xb4, 0x45, 0x07, 0x95, + 0xce, 0xdb, 0x45, 0x1d, 0x7d, 0x40, 0xa5, 0xc2, 0xa6, 0xca, 0x1e, 0x11, 0x1f, 0x0e, 0xf2, 0x13, + 0xed, 0xeb, 0xcf, 0x9e, 0xac, 0xbd, 0x7f, 0xde, 0xa7, 0x62, 0x3b, 0xe9, 0xb5, 0x3c, 0x16, 0x98, + 0x32, 0x4d, 0x4b, 0x97, 0xe3, 0x1d, 0xdb, 0x14, 0x1a, 0x19, 0x46, 0x2c, 0x16, 0x04, 0xb7, 0x0c, + 0xb4, 0x73, 0x10, 0x1c, 0xe0, 0x49, 0xb0, 0xfa, 0x53, 0x0d, 0xcc, 0xdc, 0x57, 0x72, 0xf0, 0x1a, + 0x98, 0xd1, 0xc2, 0xe6, 0xdc, 0x34, 0x27, 0x99, 0xd2, 0xf9, 0x5d, 0xcb, 0x31, 0xf9, 0xed, 0x1b, + 0xff, 0x3c, 0x5e, 0xa9, 0x3d, 0x7b, 0xb2, 0x76, 0x75, 0x3f, 0x2b, 0xa6, 0xf2, 0x32, 0x33, 0x9a, + 0xe9, 0x6e, 0x6a, 0xe6, 0xd7, 0x1a, 0x98, 0xbb, 0x6d, 0x0a, 0x10, 0x7e, 0x02, 0x16, 0xc8, 0x77, + 0x09, 0x1d, 0x30, 0x0f, 0xc9, 0x52, 0x36, 0xa6, 0xce, 0x15, 0x4d, 0xa5, 0xe5, 0x2a, 0x6d, 0xdd, + 0xce, 0x65, 0x77, 0x2d, 0xa7, 0x80, 0x6e, 0xdf, 0x32, 0x16, 0xaf, 0xef, 0xe3, 0x30, 0xab, 0xff, + 0xcc, 0x63, 0x6a, 0x28, 0x35, 0xf9, 0x7b, 0x0d, 0x1c, 0xdb, 0xe4, 0xfe, 0xfd, 0xa4, 0x17, 0x50, + 0x91, 0xb9, 0xfd, 0x08, 0xcc, 0xa5, 0xd0, 0xaa, 0xb2, 0xcb, 0xdf, 0xb5, 0x19, 0xa3, 0x93, 0x41, + 0xe0, 0x26, 0xa8, 0xcb, 0x02, 0x34, 0xb5, 0x65, 0x4f, 0x5e, 0x64, 0x49, 0x59, 0x96, 0x71, 0x67, + 0xee, 0xe9, 0x8b, 0x15, 0xeb, 0xf9, 0x8b, 0x95, 0x9a, 0xa3, 0x68, 0xda, 0x73, 0x3f, 0x3c, 0x5e, + 0xb1, 0xe4, 0x8a, 0x57, 0x7f, 0xcb, 0xbb, 0xbd, 0x67, 0x6e, 0x17, 0xd8, 0x35, 0x72, 0xda, 0xe9, + 0xf9, 0xa2, 0x9c, 0xcf, 0x06, 0x05, 0xa5, 0x14, 0x55, 0xa5, 0x04, 0xdb, 0x60, 0x56, 0x96, 0x33, + 0xc9, 0xee, 0x85, 0xd3, 0x13, 0x97, 0xbd, 0xae, 0xf3, 0x9c, 0x14, 0x90, 0x73, 0xf9, 0x4b, 0x0d, + 0xcc, 0x65, 0xe6, 0x6e, 0x14, 0xcc, 0x9d, 0xa9, 0x34, 0x37, 0xd5, 0xd3, 0xcd, 0xff, 0xec, 0xa9, + 0x53, 0x97, 0x14, 0x23, 0x67, 0x75, 0xe5, 0xea, 0x71, 0x1d, 0xcc, 0x9a, 0x04, 0x78, 0x15, 0xd4, + 0x05, 0x19, 0x8a, 0xa9, 0xa6, 0x3e, 0x27, 0xc3, 0xec, 0x61, 0x75, 0x2d, 0x47, 0x01, 0xe0, 0x43, + 0xb0, 0xa8, 0x6e, 0x78, 0x22, 0x48, 0xec, 0x7a, 0xdb, 0x28, 0xf4, 0x27, 0xec, 0xb2, 0xee, 0x03, + 0x6a, 0x71, 0x69, 0xfe, 0xba, 0x4a, 0xcf, 0x51, 0x1e, 0x8d, 0x8a, 0x21, 0xf8, 0x35, 0x58, 0xe4, + 0xec, 0x91, 0xd8, 0x45, 0x31, 0x71, 0x4d, 0x8f, 0x30, 0x57, 0xe5, 0xc5, 0x22, 0xbb, 0x09, 0xaa, + 0xf2, 0x35, 0x80, 0x07, 0x7a, 0x2a, 0x4f, 0xcf, 0x8b, 0x21, 0x18, 0x81, 0x25, 0x0f, 0x85, 0x1e, + 0xe9, 0xbb, 0x25, 0x95, 0x7a, 0x55, 0x17, 0xc8, 0xa9, 0xac, 0x2b, 0xdc, 0x64, 0xad, 0x13, 0x5e, + 0x55, 0x02, 0xec, 0x83, 0xe3, 0x1e, 0x0b, 0x82, 0x24, 0xa4, 0x62, 0xcf, 0x8d, 0x18, 0xeb, 0xbb, + 0x3c, 0x22, 0x21, 0x36, 0xf7, 0xe4, 0xb5, 0xa2, 0x5c, 0xbe, 0xd5, 0xeb, 0xdd, 0x34, 0xc8, 0x7b, + 0x8c, 0xf5, 0xef, 0x4b, 0x5c, 0x4e, 0x10, 0x7a, 0xa5, 0x68, 0xfb, 0x9a, 0xb9, 0x15, 0x2e, 0xee, + 0x73, 0x2b, 0x64, 0x7d, 0x3f, 0x3b, 0x30, 0xe6, 0x32, 0xf8, 0x73, 0x01, 0xcc, 0x6e, 0x12, 0xce, + 0x91, 0x2f, 0x4b, 0x61, 0x2e, 0xe0, 0xbe, 0xcb, 0xa5, 0x5d, 0x7d, 0x4c, 0x4e, 0x15, 0xed, 0xca, + 0xf7, 0x99, 0xb4, 0xb2, 0x48, 0x88, 0xbb, 0x96, 0x33, 0x1b, 0xe8, 0xbf, 0xf0, 0x63, 0x70, 0x44, + 0x62, 0x83, 0xa4, 0x2f, 0xa8, 0x66, 0xd0, 0x67, 0x64, 0x75, 0x22, 0xc3, 0xa6, 0x4c, 0x35, 0x34, + 0x0b, 0x41, 0x6e, 0x0c, 0xbf, 0x01, 0xc7, 0x25, 0xd7, 0x80, 0xc4, 0xf4, 0xd1, 0x9e, 0x4b, 0xc3, + 0x01, 0x8a, 0x29, 0xca, 0x5a, 0xe8, 0x58, 0xb1, 0xeb, 0x37, 0x29, 0xc3, 0xb9, 0xa5, 0x20, 0x77, + 0x53, 0x84, 0x7c, 0x68, 0x41, 0x69, 0x16, 0x86, 0xa0, 0xa1, 0xd7, 0x29, 0xdc, 0x5d, 0x2a, 0xb6, + 0x71, 0x8c, 0x76, 0x5d, 0x84, 0x71, 0x4c, 0x38, 0x37, 0xa7, 0xe2, 0xca, 0xf4, 0x6d, 0x52, 0xeb, + 0x17, 0x5f, 0x18, 0xec, 0x2d, 0x0d, 0x95, 0x47, 0x22, 0xa8, 0x0a, 0xc0, 0xef, 0xc1, 0x29, 0xa9, + 0x97, 0x69, 0x61, 0xd2, 0x27, 0x3e, 0x12, 0x2c, 0x76, 0x63, 0xb2, 0x8b, 0xe2, 0xd7, 0x3c, 0x1b, + 0x9b, 0xdc, 0x4f, 0x89, 0x37, 0x52, 0x02, 0x47, 0xe1, 0xbb, 0x96, 0xb3, 0x1c, 0x4c, 0x8c, 0xc2, + 0x1f, 0x6b, 0xe0, 0x4c, 0x41, 0x7f, 0x80, 0xfa, 0x14, 0x2b, 0x7d, 0x79, 0xa2, 0x28, 0xe7, 0xb2, + 0x3b, 0xcd, 0x28, 0x0f, 0x1f, 0xbe, 0xb6, 0x87, 0xad, 0x94, 0x64, 0x3d, 0xe3, 0xe8, 0x5a, 0x4e, + 0x33, 0x98, 0x9a, 0x01, 0x77, 0xc0, 0x92, 0xb4, 0xf2, 0x28, 0x09, 0xb1, 0x5b, 0x2c, 0x93, 0xc6, + 0xac, 0x32, 0x70, 0x79, 0x5f, 0x03, 0x77, 0x92, 0x10, 0x17, 0xea, 0xa4, 0x6b, 0x39, 0xf2, 0xbc, + 0x94, 0xe6, 0xe1, 0x43, 0xf0, 0x7f, 0xb5, 0xcf, 0xaa, 0x09, 0xb8, 0x59, 0x77, 0x9b, 0x2b, 0x1f, + 0xa3, 0xc2, 0x95, 0x5a, 0xea, 0x50, 0x5d, 0xcb, 0x39, 0x16, 0x94, 0x1a, 0x66, 0x91, 0x3d, 0x7d, + 0xef, 0x6d, 0x1c, 0x7a, 0x5d, 0xf6, 0x5c, 0x65, 0x8f, 0xd8, 0xb3, 0x1e, 0x72, 0x5d, 0xd7, 0xe2, + 0x80, 0x09, 0xd2, 0x00, 0x8a, 0xf2, 0xe4, 0xa4, 0x26, 0xb7, 0xc5, 0x04, 0x31, 0xa5, 0x28, 0xff, + 0xc2, 0x0e, 0x98, 0x97, 0x50, 0x4c, 0x22, 0xc6, 0xa9, 0x68, 0xcc, 0x2b, 0xf4, 0xca, 0x24, 0xf4, + 0x86, 0x4e, 0xeb, 0x5a, 0x0e, 0x08, 0xb2, 0x11, 0xdc, 0x00, 0x72, 0xe4, 0x26, 0xe1, 0xb7, 0x88, + 0xf6, 0x1b, 0x0b, 0x8a, 0xe2, 0xec, 0xd8, 0xeb, 0x94, 0xf9, 0x62, 0x30, 0x3c, 0x0f, 0x54, 0x6a, + 0xd7, 0x72, 0x0e, 0x05, 0xe9, 0x00, 0xba, 0xba, 0x90, 0xbd, 0x98, 0x20, 0x41, 0x46, 0xc7, 0xae, + 0x71, 0x58, 0xf1, 0x5d, 0x18, 0xe3, 0xd3, 0xdf, 0x18, 0x86, 0x6e, 0x5d, 0x61, 0xb2, 0x23, 0x64, + 0x2a, 0x79, 0x6c, 0x16, 0x7e, 0x09, 0xe4, 0xac, 0x4b, 0x30, 0x15, 0x39, 0xfa, 0x23, 0x8a, 0xfe, + 0xdd, 0x69, 0xf4, 0xb7, 0x31, 0x15, 0x79, 0xf2, 0xc5, 0x60, 0x6c, 0x0e, 0xde, 0x05, 0x0b, 0xfa, + 0x29, 0xaa, 0x62, 0x22, 0x8d, 0xa3, 0x8a, 0xf4, 0xad, 0x69, 0xa4, 0xa6, 0xf0, 0xe4, 0x66, 0xcc, + 0x07, 0xa3, 0x61, 0xfa, 0x18, 0x7a, 0xc4, 0xa7, 0xa1, 0x1b, 0x93, 0x8c, 0x72, 0x71, 0xff, 0xc7, + 0xd0, 0x91, 0x18, 0x27, 0x83, 0x98, 0xc7, 0x30, 0x36, 0x0b, 0x3f, 0xd3, 0x97, 0x6f, 0x12, 0x66, + 0xd4, 0xc7, 0xaa, 0xde, 0x35, 0x8b, 0xd4, 0x0f, 0xc2, 0x1c, 0xeb, 0xe1, 0x20, 0x3f, 0xd1, 0x3e, + 0xff, 0xec, 0xc9, 0xda, 0xb9, 0xa9, 0x2d, 0x45, 0x37, 0x13, 0xe9, 0x50, 0x37, 0x92, 0xce, 0xcd, + 0xa7, 0x2f, 0x9b, 0xb5, 0xe7, 0x2f, 0x9b, 0xb5, 0xbf, 0x5f, 0x36, 0x6b, 0x3f, 0xbf, 0x6a, 0x5a, + 0xcf, 0x5f, 0x35, 0xad, 0xbf, 0x5e, 0x35, 0xad, 0xaf, 0xa6, 0x13, 0x65, 0x9f, 0xf9, 0xbd, 0x19, + 0xf5, 0x3d, 0x78, 0xe5, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x3d, 0x1a, 0xad, 0x47, 0xfa, 0x0f, + 0x00, 0x00, } func (this *Supply) Equal(that interface{}) bool { @@ -1128,6 +1451,173 @@ func (this *Content) SetContent(value github_com_cosmos_cosmos_sdk_x_gov_types.C return fmt.Errorf("can't encode value of type %T as message Content", value) } +func (this *Message) GetMsg() github_com_cosmos_cosmos_sdk_types.Msg { + if x := this.GetMsgSend(); x != nil { + return x + } + if x := this.GetMsgMultiSend(); x != nil { + return x + } + if x := this.GetMsgVerifyInvariant(); x != nil { + return x + } + if x := this.GetMsgSetWithdrawAddress(); x != nil { + return x + } + if x := this.GetMsgWithdrawDelegatorReward(); x != nil { + return x + } + if x := this.GetMsgWithdrawValidatorCommission(); x != nil { + return x + } + if x := this.GetMsgFundCommunityPool(); x != nil { + return x + } + if x := this.GetMsgSubmitEvidence(); x != nil { + return x + } + if x := this.GetMsgSubmitProposal(); x != nil { + return x + } + if x := this.GetMsgVote(); x != nil { + return x + } + if x := this.GetMsgDeposit(); x != nil { + return x + } + if x := this.GetMsgUnjail(); x != nil { + return x + } + if x := this.GetMsgCreateValidator(); x != nil { + return x + } + if x := this.GetMsgEditValidator(); x != nil { + return x + } + if x := this.GetMsgDelegate(); x != nil { + return x + } + if x := this.GetMsgBeginRedelegate(); x != nil { + return x + } + if x := this.GetMsgUndelegate(); x != nil { + return x + } + return nil +} + +func (this *Message) SetMsg(value github_com_cosmos_cosmos_sdk_types.Msg) error { + if value == nil { + this.Sum = nil + return nil + } + switch vt := value.(type) { + case *types7.MsgSend: + this.Sum = &Message_MsgSend{vt} + return nil + case types7.MsgSend: + this.Sum = &Message_MsgSend{&vt} + return nil + case *types7.MsgMultiSend: + this.Sum = &Message_MsgMultiSend{vt} + return nil + case types7.MsgMultiSend: + this.Sum = &Message_MsgMultiSend{&vt} + return nil + case *types8.MsgVerifyInvariant: + this.Sum = &Message_MsgVerifyInvariant{vt} + return nil + case types8.MsgVerifyInvariant: + this.Sum = &Message_MsgVerifyInvariant{&vt} + return nil + case *types6.MsgSetWithdrawAddress: + this.Sum = &Message_MsgSetWithdrawAddress{vt} + return nil + case types6.MsgSetWithdrawAddress: + this.Sum = &Message_MsgSetWithdrawAddress{&vt} + return nil + case *types6.MsgWithdrawDelegatorReward: + this.Sum = &Message_MsgWithdrawDelegatorReward{vt} + return nil + case types6.MsgWithdrawDelegatorReward: + this.Sum = &Message_MsgWithdrawDelegatorReward{&vt} + return nil + case *types6.MsgWithdrawValidatorCommission: + this.Sum = &Message_MsgWithdrawValidatorCommission{vt} + return nil + case types6.MsgWithdrawValidatorCommission: + this.Sum = &Message_MsgWithdrawValidatorCommission{&vt} + return nil + case *types6.MsgFundCommunityPool: + this.Sum = &Message_MsgFundCommunityPool{vt} + return nil + case types6.MsgFundCommunityPool: + this.Sum = &Message_MsgFundCommunityPool{&vt} + return nil + case *MsgSubmitEvidence: + this.Sum = &Message_MsgSubmitEvidence{vt} + return nil + case MsgSubmitEvidence: + this.Sum = &Message_MsgSubmitEvidence{&vt} + return nil + case *MsgSubmitProposal: + this.Sum = &Message_MsgSubmitProposal{vt} + return nil + case MsgSubmitProposal: + this.Sum = &Message_MsgSubmitProposal{&vt} + return nil + case *types4.MsgVote: + this.Sum = &Message_MsgVote{vt} + return nil + case types4.MsgVote: + this.Sum = &Message_MsgVote{&vt} + return nil + case *types4.MsgDeposit: + this.Sum = &Message_MsgDeposit{vt} + return nil + case types4.MsgDeposit: + this.Sum = &Message_MsgDeposit{&vt} + return nil + case *types9.MsgUnjail: + this.Sum = &Message_MsgUnjail{vt} + return nil + case types9.MsgUnjail: + this.Sum = &Message_MsgUnjail{&vt} + return nil + case *types10.MsgCreateValidator: + this.Sum = &Message_MsgCreateValidator{vt} + return nil + case types10.MsgCreateValidator: + this.Sum = &Message_MsgCreateValidator{&vt} + return nil + case *types10.MsgEditValidator: + this.Sum = &Message_MsgEditValidator{vt} + return nil + case types10.MsgEditValidator: + this.Sum = &Message_MsgEditValidator{&vt} + return nil + case *types10.MsgDelegate: + this.Sum = &Message_MsgDelegate{vt} + return nil + case types10.MsgDelegate: + this.Sum = &Message_MsgDelegate{&vt} + return nil + case *types10.MsgBeginRedelegate: + this.Sum = &Message_MsgBeginRedelegate{vt} + return nil + case types10.MsgBeginRedelegate: + this.Sum = &Message_MsgBeginRedelegate{&vt} + return nil + case *types10.MsgUndelegate: + this.Sum = &Message_MsgUndelegate{vt} + return nil + case types10.MsgUndelegate: + this.Sum = &Message_MsgUndelegate{&vt} + return nil + } + return fmt.Errorf("can't encode value of type %T as message Message", value) +} + func (m *Account) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -1641,260 +2131,1636 @@ func (m *Content_CommunityPoolSpend) MarshalToSizedBuffer(dAtA []byte) (int, err } return len(dAtA) - i, nil } -func encodeVarintCodec(dAtA []byte, offset int, v uint64) int { - offset -= sovCodec(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ +func (m *Message) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err } - dAtA[offset] = uint8(v) - return base + return dAtA[:n], nil } -func (m *Account) Size() (n int) { - if m == nil { - return 0 - } + +func (m *Message) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Message) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i var l int _ = l if m.Sum != nil { - n += m.Sum.Size() + { + size := m.Sum.Size() + i -= size + if _, err := m.Sum.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + } } - return n + return len(dAtA) - i, nil } -func (m *Account_BaseAccount) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.BaseAccount != nil { - l = m.BaseAccount.Size() - n += 1 + l + sovCodec(uint64(l)) - } - return n +func (m *Message_MsgSend) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *Account_ContinuousVestingAccount) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.ContinuousVestingAccount != nil { - l = m.ContinuousVestingAccount.Size() - n += 1 + l + sovCodec(uint64(l)) + +func (m *Message_MsgSend) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.MsgSend != nil { + { + size, err := m.MsgSend.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa } - return n + return len(dAtA) - i, nil } -func (m *Account_DelayedVestingAccount) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.DelayedVestingAccount != nil { - l = m.DelayedVestingAccount.Size() - n += 1 + l + sovCodec(uint64(l)) - } - return n +func (m *Message_MsgMultiSend) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *Account_PeriodicVestingAccount) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.PeriodicVestingAccount != nil { - l = m.PeriodicVestingAccount.Size() - n += 1 + l + sovCodec(uint64(l)) + +func (m *Message_MsgMultiSend) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.MsgMultiSend != nil { + { + size, err := m.MsgMultiSend.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 } - return n + return len(dAtA) - i, nil } -func (m *Account_ModuleAccount) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.ModuleAccount != nil { - l = m.ModuleAccount.Size() - n += 1 + l + sovCodec(uint64(l)) - } - return n +func (m *Message_MsgVerifyInvariant) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *Supply) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Sum != nil { - n += m.Sum.Size() + +func (m *Message_MsgVerifyInvariant) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.MsgVerifyInvariant != nil { + { + size, err := m.MsgVerifyInvariant.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a } - return n + return len(dAtA) - i, nil +} +func (m *Message_MsgSetWithdrawAddress) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *Supply_Supply) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Supply != nil { - l = m.Supply.Size() - n += 1 + l + sovCodec(uint64(l)) +func (m *Message_MsgSetWithdrawAddress) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.MsgSetWithdrawAddress != nil { + { + size, err := m.MsgSetWithdrawAddress.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 } - return n + return len(dAtA) - i, nil } -func (m *Evidence) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Sum != nil { - n += m.Sum.Size() - } - return n +func (m *Message_MsgWithdrawDelegatorReward) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *Evidence_Equivocation) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Equivocation != nil { - l = m.Equivocation.Size() - n += 1 + l + sovCodec(uint64(l)) +func (m *Message_MsgWithdrawDelegatorReward) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.MsgWithdrawDelegatorReward != nil { + { + size, err := m.MsgWithdrawDelegatorReward.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a } - return n + return len(dAtA) - i, nil } -func (m *MsgSubmitEvidence) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Evidence != nil { - l = m.Evidence.Size() - n += 1 + l + sovCodec(uint64(l)) +func (m *Message_MsgWithdrawValidatorCommission) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Message_MsgWithdrawValidatorCommission) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.MsgWithdrawValidatorCommission != nil { + { + size, err := m.MsgWithdrawValidatorCommission.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 } - l = m.MsgSubmitEvidenceBase.Size() - n += 1 + l + sovCodec(uint64(l)) - return n + return len(dAtA) - i, nil +} +func (m *Message_MsgFundCommunityPool) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *MsgSubmitProposal) Size() (n int) { - if m == nil { - return 0 +func (m *Message_MsgFundCommunityPool) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.MsgFundCommunityPool != nil { + { + size, err := m.MsgFundCommunityPool.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a } - var l int - _ = l - l = m.MsgSubmitProposalBase.Size() - n += 1 + l + sovCodec(uint64(l)) - if m.Content != nil { - l = m.Content.Size() - n += 1 + l + sovCodec(uint64(l)) + return len(dAtA) - i, nil +} +func (m *Message_MsgSubmitEvidence) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Message_MsgSubmitEvidence) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.MsgSubmitEvidence != nil { + { + size, err := m.MsgSubmitEvidence.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x42 } - return n + return len(dAtA) - i, nil +} +func (m *Message_MsgSubmitProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *Proposal) Size() (n int) { - if m == nil { - return 0 +func (m *Message_MsgSubmitProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.MsgSubmitProposal != nil { + { + size, err := m.MsgSubmitProposal.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x4a } - var l int - _ = l - l = m.ProposalBase.Size() - n += 1 + l + sovCodec(uint64(l)) - l = m.Content.Size() - n += 1 + l + sovCodec(uint64(l)) - return n + return len(dAtA) - i, nil +} +func (m *Message_MsgVote) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *Content) Size() (n int) { - if m == nil { - return 0 +func (m *Message_MsgVote) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.MsgVote != nil { + { + size, err := m.MsgVote.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x52 } - var l int - _ = l - if m.Sum != nil { - n += m.Sum.Size() + return len(dAtA) - i, nil +} +func (m *Message_MsgDeposit) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Message_MsgDeposit) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.MsgDeposit != nil { + { + size, err := m.MsgDeposit.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x5a + } + return len(dAtA) - i, nil +} +func (m *Message_MsgUnjail) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Message_MsgUnjail) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.MsgUnjail != nil { + { + size, err := m.MsgUnjail.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x62 + } + return len(dAtA) - i, nil +} +func (m *Message_MsgCreateValidator) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Message_MsgCreateValidator) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.MsgCreateValidator != nil { + { + size, err := m.MsgCreateValidator.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x6a + } + return len(dAtA) - i, nil +} +func (m *Message_MsgEditValidator) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Message_MsgEditValidator) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.MsgEditValidator != nil { + { + size, err := m.MsgEditValidator.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x72 + } + return len(dAtA) - i, nil +} +func (m *Message_MsgDelegate) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Message_MsgDelegate) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.MsgDelegate != nil { + { + size, err := m.MsgDelegate.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x7a + } + return len(dAtA) - i, nil +} +func (m *Message_MsgBeginRedelegate) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Message_MsgBeginRedelegate) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.MsgBeginRedelegate != nil { + { + size, err := m.MsgBeginRedelegate.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x82 + } + return len(dAtA) - i, nil +} +func (m *Message_MsgUndelegate) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Message_MsgUndelegate) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.MsgUndelegate != nil { + { + size, err := m.MsgUndelegate.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x8a + } + return len(dAtA) - i, nil +} +func encodeVarintCodec(dAtA []byte, offset int, v uint64) int { + offset -= sovCodec(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Account) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Sum != nil { + n += m.Sum.Size() + } + return n +} + +func (m *Account_BaseAccount) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.BaseAccount != nil { + l = m.BaseAccount.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *Account_ContinuousVestingAccount) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ContinuousVestingAccount != nil { + l = m.ContinuousVestingAccount.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *Account_DelayedVestingAccount) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.DelayedVestingAccount != nil { + l = m.DelayedVestingAccount.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *Account_PeriodicVestingAccount) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.PeriodicVestingAccount != nil { + l = m.PeriodicVestingAccount.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *Account_ModuleAccount) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ModuleAccount != nil { + l = m.ModuleAccount.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *Supply) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Sum != nil { + n += m.Sum.Size() + } + return n +} + +func (m *Supply_Supply) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Supply != nil { + l = m.Supply.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *Evidence) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Sum != nil { + n += m.Sum.Size() + } + return n +} + +func (m *Evidence_Equivocation) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Equivocation != nil { + l = m.Equivocation.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *MsgSubmitEvidence) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Evidence != nil { + l = m.Evidence.Size() + n += 1 + l + sovCodec(uint64(l)) + } + l = m.MsgSubmitEvidenceBase.Size() + n += 1 + l + sovCodec(uint64(l)) + return n +} + +func (m *MsgSubmitProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.MsgSubmitProposalBase.Size() + n += 1 + l + sovCodec(uint64(l)) + if m.Content != nil { + l = m.Content.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} + +func (m *Proposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.ProposalBase.Size() + n += 1 + l + sovCodec(uint64(l)) + l = m.Content.Size() + n += 1 + l + sovCodec(uint64(l)) + return n +} + +func (m *Content) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Sum != nil { + n += m.Sum.Size() + } + return n +} + +func (m *Content_Text) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Text != nil { + l = m.Text.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *Content_ParameterChange) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ParameterChange != nil { + l = m.ParameterChange.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *Content_SoftwareUpgrade) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.SoftwareUpgrade != nil { + l = m.SoftwareUpgrade.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *Content_CancelSoftwareUpgrade) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.CancelSoftwareUpgrade != nil { + l = m.CancelSoftwareUpgrade.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *Content_CommunityPoolSpend) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.CommunityPoolSpend != nil { + l = m.CommunityPoolSpend.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *Message) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Sum != nil { + n += m.Sum.Size() + } + return n +} + +func (m *Message_MsgSend) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.MsgSend != nil { + l = m.MsgSend.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *Message_MsgMultiSend) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.MsgMultiSend != nil { + l = m.MsgMultiSend.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *Message_MsgVerifyInvariant) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.MsgVerifyInvariant != nil { + l = m.MsgVerifyInvariant.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *Message_MsgSetWithdrawAddress) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.MsgSetWithdrawAddress != nil { + l = m.MsgSetWithdrawAddress.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *Message_MsgWithdrawDelegatorReward) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.MsgWithdrawDelegatorReward != nil { + l = m.MsgWithdrawDelegatorReward.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *Message_MsgWithdrawValidatorCommission) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.MsgWithdrawValidatorCommission != nil { + l = m.MsgWithdrawValidatorCommission.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *Message_MsgFundCommunityPool) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.MsgFundCommunityPool != nil { + l = m.MsgFundCommunityPool.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *Message_MsgSubmitEvidence) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.MsgSubmitEvidence != nil { + l = m.MsgSubmitEvidence.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *Message_MsgSubmitProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.MsgSubmitProposal != nil { + l = m.MsgSubmitProposal.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *Message_MsgVote) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.MsgVote != nil { + l = m.MsgVote.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *Message_MsgDeposit) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.MsgDeposit != nil { + l = m.MsgDeposit.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *Message_MsgUnjail) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.MsgUnjail != nil { + l = m.MsgUnjail.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *Message_MsgCreateValidator) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.MsgCreateValidator != nil { + l = m.MsgCreateValidator.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *Message_MsgEditValidator) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.MsgEditValidator != nil { + l = m.MsgEditValidator.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *Message_MsgDelegate) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.MsgDelegate != nil { + l = m.MsgDelegate.Size() + n += 1 + l + sovCodec(uint64(l)) + } + return n +} +func (m *Message_MsgBeginRedelegate) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.MsgBeginRedelegate != nil { + l = m.MsgBeginRedelegate.Size() + n += 2 + l + sovCodec(uint64(l)) + } + return n +} +func (m *Message_MsgUndelegate) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.MsgUndelegate != nil { + l = m.MsgUndelegate.Size() + n += 2 + l + sovCodec(uint64(l)) + } + return n +} + +func sovCodec(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozCodec(x uint64) (n int) { + return sovCodec(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Account) 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 ErrIntOverflowCodec + } + 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: Account: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Account: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BaseAccount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &types.BaseAccount{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Sum = &Account_BaseAccount{v} + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ContinuousVestingAccount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &types1.ContinuousVestingAccount{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Sum = &Account_ContinuousVestingAccount{v} + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DelayedVestingAccount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &types1.DelayedVestingAccount{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Sum = &Account_DelayedVestingAccount{v} + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PeriodicVestingAccount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &types1.PeriodicVestingAccount{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Sum = &Account_PeriodicVestingAccount{v} + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ModuleAccount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &types2.ModuleAccount{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Sum = &Account_ModuleAccount{v} + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCodec(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Supply) 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 ErrIntOverflowCodec + } + 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: Supply: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Supply: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Supply", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &types2.Supply{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Sum = &Supply_Supply{v} + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCodec(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Evidence) 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 ErrIntOverflowCodec + } + 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: Evidence: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Evidence: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Equivocation", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &types3.Equivocation{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Sum = &Evidence_Equivocation{v} + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCodec(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgSubmitEvidence) 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 ErrIntOverflowCodec + } + 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: MsgSubmitEvidence: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSubmitEvidence: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Evidence", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Evidence == nil { + m.Evidence = &Evidence{} + } + if err := m.Evidence.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MsgSubmitEvidenceBase", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.MsgSubmitEvidenceBase.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCodec(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgSubmitProposal) 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 ErrIntOverflowCodec + } + 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: MsgSubmitProposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSubmitProposal: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MsgSubmitProposalBase", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.MsgSubmitProposalBase.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Content", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Content == nil { + m.Content = &Content{} + } + if err := m.Content.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCodec(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Proposal) 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 ErrIntOverflowCodec + } + 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: Proposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Proposal: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProposalBase", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.ProposalBase.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Content", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Content.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCodec(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } } - return n -} -func (m *Content_Text) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Text != nil { - l = m.Text.Size() - n += 1 + l + sovCodec(uint64(l)) - } - return n -} -func (m *Content_ParameterChange) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.ParameterChange != nil { - l = m.ParameterChange.Size() - n += 1 + l + sovCodec(uint64(l)) - } - return n -} -func (m *Content_SoftwareUpgrade) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.SoftwareUpgrade != nil { - l = m.SoftwareUpgrade.Size() - n += 1 + l + sovCodec(uint64(l)) - } - return n -} -func (m *Content_CancelSoftwareUpgrade) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.CancelSoftwareUpgrade != nil { - l = m.CancelSoftwareUpgrade.Size() - n += 1 + l + sovCodec(uint64(l)) - } - return n -} -func (m *Content_CommunityPoolSpend) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.CommunityPoolSpend != nil { - l = m.CommunityPoolSpend.Size() - n += 1 + l + sovCodec(uint64(l)) + if iNdEx > l { + return io.ErrUnexpectedEOF } - return n -} - -func sovCodec(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozCodec(x uint64) (n int) { - return sovCodec(uint64((x << 1) ^ uint64((int64(x) >> 63)))) + return nil } -func (m *Account) Unmarshal(dAtA []byte) error { +func (m *Content) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1917,15 +3783,15 @@ func (m *Account) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: Account: wiretype end group for non-group") + return fmt.Errorf("proto: Content: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: Account: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: Content: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field BaseAccount", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Text", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -1952,15 +3818,15 @@ func (m *Account) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - v := &types.BaseAccount{} + v := &types4.TextProposal{} if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } - m.Sum = &Account_BaseAccount{v} + m.Sum = &Content_Text{v} iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ContinuousVestingAccount", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ParameterChange", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -1987,15 +3853,15 @@ func (m *Account) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - v := &types1.ContinuousVestingAccount{} + v := &proposal.ParameterChangeProposal{} if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } - m.Sum = &Account_ContinuousVestingAccount{v} + m.Sum = &Content_ParameterChange{v} iNdEx = postIndex case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field DelayedVestingAccount", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field SoftwareUpgrade", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -2022,15 +3888,15 @@ func (m *Account) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - v := &types1.DelayedVestingAccount{} + v := &types5.SoftwareUpgradeProposal{} if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } - m.Sum = &Account_DelayedVestingAccount{v} + m.Sum = &Content_SoftwareUpgrade{v} iNdEx = postIndex case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field PeriodicVestingAccount", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field CancelSoftwareUpgrade", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -2057,15 +3923,15 @@ func (m *Account) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - v := &types1.PeriodicVestingAccount{} + v := &types5.CancelSoftwareUpgradeProposal{} if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } - m.Sum = &Account_PeriodicVestingAccount{v} + m.Sum = &Content_CancelSoftwareUpgrade{v} iNdEx = postIndex case 5: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ModuleAccount", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field CommunityPoolSpend", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -2092,11 +3958,11 @@ func (m *Account) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - v := &types2.ModuleAccount{} + v := &types6.CommunityPoolSpendProposal{} if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } - m.Sum = &Account_ModuleAccount{v} + m.Sum = &Content_CommunityPoolSpend{v} iNdEx = postIndex default: iNdEx = preIndex @@ -2122,7 +3988,7 @@ func (m *Account) Unmarshal(dAtA []byte) error { } return nil } -func (m *Supply) Unmarshal(dAtA []byte) error { +func (m *Message) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -2145,15 +4011,15 @@ func (m *Supply) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: Supply: wiretype end group for non-group") + return fmt.Errorf("proto: Message: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: Supply: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: Message: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Supply", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field MsgSend", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -2180,68 +4046,15 @@ func (m *Supply) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - v := &types2.Supply{} + v := &types7.MsgSend{} if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } - m.Sum = &Supply_Supply{v} + m.Sum = &Message_MsgSend{v} iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipCodec(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthCodec - } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthCodec - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *Evidence) 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 ErrIntOverflowCodec - } - 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: Evidence: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: Evidence: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: + case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Equivocation", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field MsgMultiSend", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -2268,68 +4081,50 @@ func (m *Evidence) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - v := &types3.Equivocation{} + v := &types7.MsgMultiSend{} if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } - m.Sum = &Evidence_Equivocation{v} + m.Sum = &Message_MsgMultiSend{v} iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipCodec(dAtA[iNdEx:]) - if err != nil { - return err + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MsgVerifyInvariant", wireType) } - if skippy < 0 { - return ErrInvalidLengthCodec + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } } - if (iNdEx + skippy) < 0 { + if msglen < 0 { return ErrInvalidLengthCodec } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *MsgSubmitEvidence) 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 ErrIntOverflowCodec + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec } - if iNdEx >= l { + if postIndex > l { return io.ErrUnexpectedEOF } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break + v := &types8.MsgVerifyInvariant{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MsgSubmitEvidence: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgSubmitEvidence: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: + m.Sum = &Message_MsgVerifyInvariant{v} + iNdEx = postIndex + case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Evidence", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field MsgSetWithdrawAddress", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -2356,16 +4151,15 @@ func (m *MsgSubmitEvidence) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.Evidence == nil { - m.Evidence = &Evidence{} - } - if err := m.Evidence.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + v := &types6.MsgSetWithdrawAddress{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } + m.Sum = &Message_MsgSetWithdrawAddress{v} iNdEx = postIndex - case 2: + case 5: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field MsgSubmitEvidenceBase", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field MsgWithdrawDelegatorReward", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -2392,66 +4186,50 @@ func (m *MsgSubmitEvidence) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.MsgSubmitEvidenceBase.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + v := &types6.MsgWithdrawDelegatorReward{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } + m.Sum = &Message_MsgWithdrawDelegatorReward{v} iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipCodec(dAtA[iNdEx:]) - if err != nil { - return err + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MsgWithdrawValidatorCommission", wireType) } - if skippy < 0 { - return ErrInvalidLengthCodec + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } } - if (iNdEx + skippy) < 0 { + if msglen < 0 { return ErrInvalidLengthCodec } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *MsgSubmitProposal) 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 ErrIntOverflowCodec + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec } - if iNdEx >= l { + if postIndex > l { return io.ErrUnexpectedEOF } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break + v := &types6.MsgWithdrawValidatorCommission{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MsgSubmitProposal: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgSubmitProposal: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: + m.Sum = &Message_MsgWithdrawValidatorCommission{v} + iNdEx = postIndex + case 7: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field MsgSubmitProposalBase", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field MsgFundCommunityPool", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -2478,13 +4256,15 @@ func (m *MsgSubmitProposal) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.MsgSubmitProposalBase.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + v := &types6.MsgFundCommunityPool{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } + m.Sum = &Message_MsgFundCommunityPool{v} iNdEx = postIndex - case 2: + case 8: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Content", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field MsgSubmitEvidence", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -2511,69 +4291,50 @@ func (m *MsgSubmitProposal) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.Content == nil { - m.Content = &Content{} - } - if err := m.Content.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + v := &MsgSubmitEvidence{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } + m.Sum = &Message_MsgSubmitEvidence{v} iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipCodec(dAtA[iNdEx:]) - if err != nil { - return err + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MsgSubmitProposal", wireType) } - if skippy < 0 { - return ErrInvalidLengthCodec + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } } - if (iNdEx + skippy) < 0 { + if msglen < 0 { return ErrInvalidLengthCodec } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *Proposal) 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 ErrIntOverflowCodec + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec } - if iNdEx >= l { + if postIndex > l { return io.ErrUnexpectedEOF } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break + v := &MsgSubmitProposal{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: Proposal: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: Proposal: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: + m.Sum = &Message_MsgSubmitProposal{v} + iNdEx = postIndex + case 10: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ProposalBase", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field MsgVote", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -2600,13 +4361,15 @@ func (m *Proposal) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.ProposalBase.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + v := &types4.MsgVote{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } + m.Sum = &Message_MsgVote{v} iNdEx = postIndex - case 2: + case 11: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Content", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field MsgDeposit", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -2633,66 +4396,50 @@ func (m *Proposal) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Content.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + v := &types4.MsgDeposit{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } + m.Sum = &Message_MsgDeposit{v} iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipCodec(dAtA[iNdEx:]) - if err != nil { - return err + case 12: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MsgUnjail", wireType) } - if skippy < 0 { - return ErrInvalidLengthCodec + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } } - if (iNdEx + skippy) < 0 { + if msglen < 0 { return ErrInvalidLengthCodec } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *Content) 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 ErrIntOverflowCodec + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec } - if iNdEx >= l { + if postIndex > l { return io.ErrUnexpectedEOF } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break + v := &types9.MsgUnjail{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: Content: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: Content: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: + m.Sum = &Message_MsgUnjail{v} + iNdEx = postIndex + case 13: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Text", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field MsgCreateValidator", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -2719,15 +4466,15 @@ func (m *Content) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - v := &types4.TextProposal{} + v := &types10.MsgCreateValidator{} if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } - m.Sum = &Content_Text{v} + m.Sum = &Message_MsgCreateValidator{v} iNdEx = postIndex - case 2: + case 14: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ParameterChange", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field MsgEditValidator", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -2754,15 +4501,15 @@ func (m *Content) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - v := &proposal.ParameterChangeProposal{} + v := &types10.MsgEditValidator{} if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } - m.Sum = &Content_ParameterChange{v} + m.Sum = &Message_MsgEditValidator{v} iNdEx = postIndex - case 3: + case 15: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field SoftwareUpgrade", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field MsgDelegate", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -2789,15 +4536,15 @@ func (m *Content) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - v := &types5.SoftwareUpgradeProposal{} + v := &types10.MsgDelegate{} if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } - m.Sum = &Content_SoftwareUpgrade{v} + m.Sum = &Message_MsgDelegate{v} iNdEx = postIndex - case 4: + case 16: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field CancelSoftwareUpgrade", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field MsgBeginRedelegate", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -2824,15 +4571,15 @@ func (m *Content) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - v := &types5.CancelSoftwareUpgradeProposal{} + v := &types10.MsgBeginRedelegate{} if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } - m.Sum = &Content_CancelSoftwareUpgrade{v} + m.Sum = &Message_MsgBeginRedelegate{v} iNdEx = postIndex - case 5: + case 17: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field CommunityPoolSpend", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field MsgUndelegate", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -2859,11 +4606,11 @@ func (m *Content) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - v := &types6.CommunityPoolSpendProposal{} + v := &types10.MsgUndelegate{} if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } - m.Sum = &Content_CommunityPoolSpend{v} + m.Sum = &Message_MsgUndelegate{v} iNdEx = postIndex default: iNdEx = preIndex diff --git a/codec/std/codec.proto b/codec/std/codec.proto index 94297308ac73..612709a9bb3c 100644 --- a/codec/std/codec.proto +++ b/codec/std/codec.proto @@ -5,12 +5,16 @@ import "third_party/proto/cosmos-proto/cosmos.proto"; import "third_party/proto/gogoproto/gogo.proto"; import "x/auth/types/types.proto"; import "x/auth/vesting/types/types.proto"; +import "x/bank/types/types.proto"; +import "x/crisis/types/types.proto"; +import "x/distribution/types/types.proto"; import "x/supply/types/types.proto"; import "x/evidence/types/types.proto"; import "x/gov/types/types.proto"; +import "x/slashing/types/types.proto"; +import "x/staking/types/types.proto"; import "x/params/types/proposal/types.proto"; import "x/upgrade/types/types.proto"; -import "x/distribution/types/types.proto"; option go_package = "github.com/cosmos/cosmos-sdk/codec/std"; @@ -95,3 +99,30 @@ message Content { cosmos_sdk.x.distribution.v1.CommunityPoolSpendProposal community_pool_spend = 5; } } + +// Message defines the set of valid concrete message types that can be used to +// construct a transaction. +message Message { + option (cosmos_proto.interface_type) = "github.com/cosmos/cosmos-sdk/types.Msg"; + + // sum defines the set of all allowed valid messages defined in modules. + oneof sum { + cosmos_sdk.x.bank.v1.MsgSend msg_send = 1; + cosmos_sdk.x.bank.v1.MsgMultiSend msg_multi_send = 2; + cosmos_sdk.x.crisis.v1.MsgVerifyInvariant msg_verify_invariant = 3; + cosmos_sdk.x.distribution.v1.MsgSetWithdrawAddress msg_set_withdraw_address = 4; + cosmos_sdk.x.distribution.v1.MsgWithdrawDelegatorReward msg_withdraw_delegator_reward = 5; + cosmos_sdk.x.distribution.v1.MsgWithdrawValidatorCommission msg_withdraw_validator_commission = 6; + cosmos_sdk.x.distribution.v1.MsgFundCommunityPool msg_fund_community_pool = 7; + MsgSubmitEvidence msg_submit_evidence = 8; + MsgSubmitProposal msg_submit_proposal = 9; + cosmos_sdk.x.gov.v1.MsgVote msg_vote = 10; + cosmos_sdk.x.gov.v1.MsgDeposit msg_deposit = 11; + cosmos_sdk.x.slashing.v1.MsgUnjail msg_unjail = 12; + cosmos_sdk.x.staking.v1.MsgCreateValidator msg_create_validator = 13; + cosmos_sdk.x.staking.v1.MsgEditValidator msg_edit_validator = 14; + cosmos_sdk.x.staking.v1.MsgDelegate msg_delegate = 15; + cosmos_sdk.x.staking.v1.MsgBeginRedelegate msg_begin_redelegate = 16; + cosmos_sdk.x.staking.v1.MsgUndelegate msg_undelegate = 17; + } +} From 39f416faa3fa1c4cb3cc5a1ade14a3430f6bca80 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Thu, 12 Mar 2020 15:46:55 +0100 Subject: [PATCH 403/529] Simplify flaky test case and disable parallelism (#5793) * Simplify flaky test casea and disable parallelism * Fix failing test Co-authored-by: Alexander Bezobchuk Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> --- types/module/module_test.go | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/types/module/module_test.go b/types/module/module_test.go index db2334696292..65df4e8ea218 100644 --- a/types/module/module_test.go +++ b/types/module/module_test.go @@ -24,29 +24,19 @@ func TestBasicManager(t *testing.T) { mockCtrl := gomock.NewController(t) t.Cleanup(mockCtrl.Finish) cdc := codec.New() - wantDefaultGenesis := map[string]json.RawMessage{ - "mockAppModuleBasic1": json.RawMessage(``), - "mockAppModuleBasic2": json.RawMessage(`{"key":"value"}`), - } + wantDefaultGenesis := map[string]json.RawMessage{"mockAppModuleBasic1": json.RawMessage(``)} mockAppModuleBasic1 := mocks.NewMockAppModuleBasic(mockCtrl) - mockAppModuleBasic2 := mocks.NewMockAppModuleBasic(mockCtrl) mockAppModuleBasic1.EXPECT().Name().AnyTimes().Return("mockAppModuleBasic1") - mockAppModuleBasic2.EXPECT().Name().AnyTimes().Return("mockAppModuleBasic2") mockAppModuleBasic1.EXPECT().DefaultGenesis(gomock.Eq(cdc)).Times(1).Return(json.RawMessage(``)) - mockAppModuleBasic2.EXPECT().DefaultGenesis(gomock.Eq(cdc)).Times(1).Return(json.RawMessage(`{"key":"value"}`)) mockAppModuleBasic1.EXPECT().ValidateGenesis(gomock.Eq(cdc), gomock.Eq(wantDefaultGenesis["mockAppModuleBasic1"])).Times(1).Return(errFoo) mockAppModuleBasic1.EXPECT().RegisterRESTRoutes(gomock.Eq(context.CLIContext{}), gomock.Eq(&mux.Router{})).Times(1) - mockAppModuleBasic2.EXPECT().RegisterRESTRoutes(gomock.Eq(context.CLIContext{}), gomock.Eq(&mux.Router{})).Times(1) mockAppModuleBasic1.EXPECT().RegisterCodec(gomock.Eq(cdc)).Times(1) - mockAppModuleBasic2.EXPECT().RegisterCodec(gomock.Eq(cdc)).Times(1) mockAppModuleBasic1.EXPECT().GetTxCmd(cdc).Times(1).Return(nil) - mockAppModuleBasic2.EXPECT().GetTxCmd(cdc).Times(1).Return(&cobra.Command{}) mockAppModuleBasic1.EXPECT().GetQueryCmd(cdc).Times(1).Return(nil) - mockAppModuleBasic2.EXPECT().GetQueryCmd(cdc).Times(1).Return(&cobra.Command{}) - mm := module.NewBasicManager(mockAppModuleBasic1, mockAppModuleBasic2) + mm := module.NewBasicManager(mockAppModuleBasic1) require.Equal(t, mm["mockAppModuleBasic1"], mockAppModuleBasic1) mm.RegisterCodec(cdc) @@ -54,8 +44,7 @@ func TestBasicManager(t *testing.T) { require.Equal(t, wantDefaultGenesis, mm.DefaultGenesis(cdc)) var data map[string]string - require.NoError(t, json.Unmarshal(wantDefaultGenesis["mockAppModuleBasic2"], &data)) - require.Equal(t, map[string]string{"key": "value"}, data) + require.Equal(t, map[string]string(nil), data) require.True(t, errors.Is(errFoo, mm.ValidateGenesis(cdc, wantDefaultGenesis))) @@ -71,7 +60,6 @@ func TestBasicManager(t *testing.T) { } func TestGenesisOnlyAppModule(t *testing.T) { - t.Parallel() mockCtrl := gomock.NewController(t) t.Cleanup(mockCtrl.Finish) @@ -91,7 +79,6 @@ func TestGenesisOnlyAppModule(t *testing.T) { } func TestManagerOrderSetters(t *testing.T) { - t.Parallel() mockCtrl := gomock.NewController(t) t.Cleanup(mockCtrl.Finish) mockAppModule1 := mocks.NewMockAppModule(mockCtrl) @@ -121,7 +108,6 @@ func TestManagerOrderSetters(t *testing.T) { } func TestManager_RegisterInvariants(t *testing.T) { - t.Parallel() mockCtrl := gomock.NewController(t) t.Cleanup(mockCtrl.Finish) @@ -141,7 +127,6 @@ func TestManager_RegisterInvariants(t *testing.T) { } func TestManager_RegisterRoutes(t *testing.T) { - t.Parallel() mockCtrl := gomock.NewController(t) t.Cleanup(mockCtrl.Finish) @@ -173,7 +158,6 @@ func TestManager_RegisterRoutes(t *testing.T) { } func TestManager_InitGenesis(t *testing.T) { - t.Parallel() mockCtrl := gomock.NewController(t) t.Cleanup(mockCtrl.Finish) From 3a94f42e119354e0cfca2dd67ab678625f507581 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Thu, 12 Mar 2020 10:53:27 -0400 Subject: [PATCH 404/529] Implement app-level tx --- codec/std/codec.pb.go | 416 +++++++++--- codec/std/codec.proto | 10 + codec/std/tx.go | 67 ++ .../adr-020-protobuf-transaction-encoding.md | 12 +- simapp/helpers/test_helpers.go | 2 +- x/auth/alias.go | 1 + x/auth/ante/basic.go | 2 +- x/auth/client/cli/tx_multisign.go | 6 +- x/auth/client/cli/tx_sign.go | 6 +- x/auth/types/stdtx.go | 40 +- x/auth/types/stdtx_test.go | 4 +- x/auth/types/test_utils.go | 6 +- x/auth/types/txbuilder.go | 3 +- x/auth/types/types.pb.go | 603 ++++++++++++++++-- x/auth/types/types.proto | 17 + 15 files changed, 1026 insertions(+), 169 deletions(-) create mode 100644 codec/std/tx.go diff --git a/codec/std/codec.pb.go b/codec/std/codec.pb.go index e330bd97edab..13998ffad89a 100644 --- a/codec/std/codec.pb.go +++ b/codec/std/codec.pb.go @@ -577,6 +577,47 @@ func (*Content) XXX_OneofWrappers() []interface{} { } } +// Transaction defines the application-level transaction that can be signed and +// processed by the state-machine. It contains a base of common fields and +// repeated set of Message types. +type Transaction struct { + Base *types.StdTxBase `protobuf:"bytes,1,opt,name=base,proto3" json:"base,omitempty"` + Msgs []*Message `protobuf:"bytes,2,rep,name=msgs,proto3" json:"msgs,omitempty"` +} + +func (m *Transaction) Reset() { *m = Transaction{} } +func (m *Transaction) String() string { return proto.CompactTextString(m) } +func (*Transaction) ProtoMessage() {} +func (*Transaction) Descriptor() ([]byte, []int) { + return fileDescriptor_daf09dc2dfa19bb4, []int{7} +} +func (m *Transaction) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Transaction) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Transaction.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 *Transaction) XXX_Merge(src proto.Message) { + xxx_messageInfo_Transaction.Merge(m, src) +} +func (m *Transaction) XXX_Size() int { + return m.Size() +} +func (m *Transaction) XXX_DiscardUnknown() { + xxx_messageInfo_Transaction.DiscardUnknown(m) +} + +var xxx_messageInfo_Transaction proto.InternalMessageInfo + // Message defines the set of valid concrete message types that can be used to // construct a transaction. type Message struct { @@ -607,7 +648,7 @@ func (m *Message) Reset() { *m = Message{} } func (m *Message) String() string { return proto.CompactTextString(m) } func (*Message) ProtoMessage() {} func (*Message) Descriptor() ([]byte, []int) { - return fileDescriptor_daf09dc2dfa19bb4, []int{7} + return fileDescriptor_daf09dc2dfa19bb4, []int{8} } func (m *Message) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -869,101 +910,105 @@ func init() { proto.RegisterType((*MsgSubmitProposal)(nil), "cosmos_sdk.codec.std.v1.MsgSubmitProposal") proto.RegisterType((*Proposal)(nil), "cosmos_sdk.codec.std.v1.Proposal") proto.RegisterType((*Content)(nil), "cosmos_sdk.codec.std.v1.Content") + proto.RegisterType((*Transaction)(nil), "cosmos_sdk.codec.std.v1.Transaction") proto.RegisterType((*Message)(nil), "cosmos_sdk.codec.std.v1.Message") } func init() { proto.RegisterFile("codec/std/codec.proto", fileDescriptor_daf09dc2dfa19bb4) } var fileDescriptor_daf09dc2dfa19bb4 = []byte{ - // 1394 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x57, 0x4d, 0x6f, 0xd4, 0xc6, - 0x1b, 0xf7, 0xfe, 0x59, 0x92, 0x30, 0x09, 0x10, 0xe6, 0x0f, 0xcd, 0x2a, 0x85, 0x0d, 0x84, 0x16, - 0xb5, 0xa0, 0xac, 0x79, 0x69, 0x0b, 0xac, 0x5a, 0x01, 0x9b, 0x80, 0x96, 0xaa, 0x69, 0x91, 0x29, - 0xa9, 0x5a, 0xd1, 0x5a, 0xb3, 0x9e, 0xc1, 0x99, 0x66, 0xed, 0x71, 0x3d, 0xe3, 0xcd, 0xe6, 0xd0, - 0x7b, 0xdb, 0x53, 0xa5, 0x7e, 0x01, 0xd4, 0x1e, 0x7b, 0xe5, 0xd8, 0x73, 0x85, 0x38, 0x71, 0xec, - 0x09, 0x55, 0x70, 0xe9, 0xc7, 0xa8, 0xe6, 0xc5, 0x5e, 0x7b, 0xed, 0xdd, 0xd0, 0xcb, 0x6a, 0x67, - 0x9e, 0xe7, 0xf7, 0x32, 0x9e, 0x79, 0xe6, 0xb1, 0xc1, 0x09, 0x8f, 0x61, 0xe2, 0xd9, 0x5c, 0x60, - 0x5b, 0xfd, 0x6b, 0x45, 0x31, 0x13, 0x0c, 0x2e, 0x79, 0x8c, 0x07, 0x8c, 0xbb, 0x1c, 0xef, 0xb4, - 0xf4, 0x3c, 0x17, 0xb8, 0x35, 0xb8, 0xb4, 0x7c, 0x41, 0x6c, 0xd3, 0x18, 0xbb, 0x11, 0x8a, 0xc5, - 0x9e, 0xad, 0x72, 0x6d, 0x9d, 0xba, 0x96, 0x1f, 0x68, 0x96, 0xe5, 0x73, 0xe5, 0x64, 0x9f, 0xf9, - 0x6c, 0xf4, 0xcf, 0xe4, 0x35, 0x86, 0x36, 0x4a, 0xc4, 0xb6, 0x2d, 0xf6, 0x22, 0xc2, 0xf5, 0xaf, - 0x89, 0x9c, 0x36, 0x91, 0x01, 0xe1, 0x82, 0x86, 0x7e, 0x45, 0x46, 0x63, 0x68, 0xf7, 0x50, 0xb8, - 0x53, 0x11, 0x59, 0x1e, 0xda, 0x5e, 0x4c, 0x39, 0xe5, 0xd5, 0xbc, 0x98, 0x72, 0x11, 0xd3, 0x5e, - 0x22, 0x28, 0x0b, 0xab, 0xd1, 0x3c, 0x89, 0xa2, 0xfe, 0x5e, 0x45, 0xec, 0xe4, 0xd0, 0x26, 0x03, - 0x8a, 0x49, 0xe8, 0x91, 0x8a, 0xe8, 0xd2, 0xd0, 0xf6, 0xd9, 0xa0, 0x1a, 0xc6, 0xfb, 0x88, 0x6f, - 0x57, 0x2f, 0xe4, 0xcd, 0xa1, 0xcd, 0x05, 0xda, 0xa9, 0x0e, 0x9e, 0x1d, 0xda, 0x11, 0x8a, 0x51, - 0x90, 0xae, 0x25, 0x8a, 0x59, 0xc4, 0x38, 0xea, 0x8f, 0x33, 0x24, 0x91, 0x1f, 0x23, 0x5c, 0xe1, - 0x6a, 0xf5, 0x8f, 0x3a, 0x98, 0xbd, 0xe5, 0x79, 0x2c, 0x09, 0x05, 0xbc, 0x03, 0x16, 0x7a, 0x88, - 0x13, 0x17, 0xe9, 0x71, 0xa3, 0x76, 0xba, 0xf6, 0xce, 0xfc, 0xe5, 0x33, 0xad, 0xdc, 0xa6, 0x0f, - 0x5b, 0xf2, 0xb9, 0xb7, 0x06, 0x97, 0x5a, 0x1d, 0xc4, 0x89, 0x01, 0x76, 0x2d, 0x67, 0xbe, 0x37, - 0x1a, 0xc2, 0x01, 0x58, 0xf6, 0x58, 0x28, 0x68, 0x98, 0xb0, 0x84, 0xbb, 0x66, 0x8f, 0x32, 0xd6, - 0xff, 0x29, 0xd6, 0x0f, 0xaa, 0x58, 0x75, 0xa6, 0x64, 0x5f, 0xcf, 0xf0, 0x5b, 0x7a, 0x72, 0x24, - 0xd5, 0xf0, 0x26, 0xc4, 0x60, 0x00, 0x96, 0x30, 0xe9, 0xa3, 0x3d, 0x82, 0x4b, 0xa2, 0x07, 0x94, - 0xe8, 0x95, 0xe9, 0xa2, 0x1b, 0x1a, 0x5c, 0x52, 0x3c, 0x81, 0xab, 0x02, 0x30, 0x02, 0x8d, 0x88, - 0xc4, 0x94, 0x61, 0xea, 0x95, 0xf4, 0xea, 0x4a, 0xef, 0xbd, 0xe9, 0x7a, 0xf7, 0x0c, 0xba, 0x24, - 0xf8, 0x46, 0x54, 0x19, 0x81, 0x9f, 0x82, 0x23, 0x01, 0xc3, 0x49, 0x7f, 0xb4, 0x45, 0x07, 0x95, - 0xce, 0xdb, 0x45, 0x1d, 0x7d, 0x40, 0xa5, 0xc2, 0xa6, 0xca, 0x1e, 0x11, 0x1f, 0x0e, 0xf2, 0x13, - 0xed, 0xeb, 0xcf, 0x9e, 0xac, 0xbd, 0x7f, 0xde, 0xa7, 0x62, 0x3b, 0xe9, 0xb5, 0x3c, 0x16, 0x98, - 0x32, 0x4d, 0x4b, 0x97, 0xe3, 0x1d, 0xdb, 0x14, 0x1a, 0x19, 0x46, 0x2c, 0x16, 0x04, 0xb7, 0x0c, - 0xb4, 0x73, 0x10, 0x1c, 0xe0, 0x49, 0xb0, 0xfa, 0x53, 0x0d, 0xcc, 0xdc, 0x57, 0x72, 0xf0, 0x1a, - 0x98, 0xd1, 0xc2, 0xe6, 0xdc, 0x34, 0x27, 0x99, 0xd2, 0xf9, 0x5d, 0xcb, 0x31, 0xf9, 0xed, 0x1b, - 0xff, 0x3c, 0x5e, 0xa9, 0x3d, 0x7b, 0xb2, 0x76, 0x75, 0x3f, 0x2b, 0xa6, 0xf2, 0x32, 0x33, 0x9a, - 0xe9, 0x6e, 0x6a, 0xe6, 0xd7, 0x1a, 0x98, 0xbb, 0x6d, 0x0a, 0x10, 0x7e, 0x02, 0x16, 0xc8, 0x77, - 0x09, 0x1d, 0x30, 0x0f, 0xc9, 0x52, 0x36, 0xa6, 0xce, 0x15, 0x4d, 0xa5, 0xe5, 0x2a, 0x6d, 0xdd, - 0xce, 0x65, 0x77, 0x2d, 0xa7, 0x80, 0x6e, 0xdf, 0x32, 0x16, 0xaf, 0xef, 0xe3, 0x30, 0xab, 0xff, - 0xcc, 0x63, 0x6a, 0x28, 0x35, 0xf9, 0x7b, 0x0d, 0x1c, 0xdb, 0xe4, 0xfe, 0xfd, 0xa4, 0x17, 0x50, - 0x91, 0xb9, 0xfd, 0x08, 0xcc, 0xa5, 0xd0, 0xaa, 0xb2, 0xcb, 0xdf, 0xb5, 0x19, 0xa3, 0x93, 0x41, - 0xe0, 0x26, 0xa8, 0xcb, 0x02, 0x34, 0xb5, 0x65, 0x4f, 0x5e, 0x64, 0x49, 0x59, 0x96, 0x71, 0x67, - 0xee, 0xe9, 0x8b, 0x15, 0xeb, 0xf9, 0x8b, 0x95, 0x9a, 0xa3, 0x68, 0xda, 0x73, 0x3f, 0x3c, 0x5e, - 0xb1, 0xe4, 0x8a, 0x57, 0x7f, 0xcb, 0xbb, 0xbd, 0x67, 0x6e, 0x17, 0xd8, 0x35, 0x72, 0xda, 0xe9, - 0xf9, 0xa2, 0x9c, 0xcf, 0x06, 0x05, 0xa5, 0x14, 0x55, 0xa5, 0x04, 0xdb, 0x60, 0x56, 0x96, 0x33, - 0xc9, 0xee, 0x85, 0xd3, 0x13, 0x97, 0xbd, 0xae, 0xf3, 0x9c, 0x14, 0x90, 0x73, 0xf9, 0x4b, 0x0d, - 0xcc, 0x65, 0xe6, 0x6e, 0x14, 0xcc, 0x9d, 0xa9, 0x34, 0x37, 0xd5, 0xd3, 0xcd, 0xff, 0xec, 0xa9, - 0x53, 0x97, 0x14, 0x23, 0x67, 0x75, 0xe5, 0xea, 0x71, 0x1d, 0xcc, 0x9a, 0x04, 0x78, 0x15, 0xd4, - 0x05, 0x19, 0x8a, 0xa9, 0xa6, 0x3e, 0x27, 0xc3, 0xec, 0x61, 0x75, 0x2d, 0x47, 0x01, 0xe0, 0x43, - 0xb0, 0xa8, 0x6e, 0x78, 0x22, 0x48, 0xec, 0x7a, 0xdb, 0x28, 0xf4, 0x27, 0xec, 0xb2, 0xee, 0x03, - 0x6a, 0x71, 0x69, 0xfe, 0xba, 0x4a, 0xcf, 0x51, 0x1e, 0x8d, 0x8a, 0x21, 0xf8, 0x35, 0x58, 0xe4, - 0xec, 0x91, 0xd8, 0x45, 0x31, 0x71, 0x4d, 0x8f, 0x30, 0x57, 0xe5, 0xc5, 0x22, 0xbb, 0x09, 0xaa, - 0xf2, 0x35, 0x80, 0x07, 0x7a, 0x2a, 0x4f, 0xcf, 0x8b, 0x21, 0x18, 0x81, 0x25, 0x0f, 0x85, 0x1e, - 0xe9, 0xbb, 0x25, 0x95, 0x7a, 0x55, 0x17, 0xc8, 0xa9, 0xac, 0x2b, 0xdc, 0x64, 0xad, 0x13, 0x5e, - 0x55, 0x02, 0xec, 0x83, 0xe3, 0x1e, 0x0b, 0x82, 0x24, 0xa4, 0x62, 0xcf, 0x8d, 0x18, 0xeb, 0xbb, - 0x3c, 0x22, 0x21, 0x36, 0xf7, 0xe4, 0xb5, 0xa2, 0x5c, 0xbe, 0xd5, 0xeb, 0xdd, 0x34, 0xc8, 0x7b, - 0x8c, 0xf5, 0xef, 0x4b, 0x5c, 0x4e, 0x10, 0x7a, 0xa5, 0x68, 0xfb, 0x9a, 0xb9, 0x15, 0x2e, 0xee, - 0x73, 0x2b, 0x64, 0x7d, 0x3f, 0x3b, 0x30, 0xe6, 0x32, 0xf8, 0x73, 0x01, 0xcc, 0x6e, 0x12, 0xce, - 0x91, 0x2f, 0x4b, 0x61, 0x2e, 0xe0, 0xbe, 0xcb, 0xa5, 0x5d, 0x7d, 0x4c, 0x4e, 0x15, 0xed, 0xca, - 0xf7, 0x99, 0xb4, 0xb2, 0x48, 0x88, 0xbb, 0x96, 0x33, 0x1b, 0xe8, 0xbf, 0xf0, 0x63, 0x70, 0x44, - 0x62, 0x83, 0xa4, 0x2f, 0xa8, 0x66, 0xd0, 0x67, 0x64, 0x75, 0x22, 0xc3, 0xa6, 0x4c, 0x35, 0x34, - 0x0b, 0x41, 0x6e, 0x0c, 0xbf, 0x01, 0xc7, 0x25, 0xd7, 0x80, 0xc4, 0xf4, 0xd1, 0x9e, 0x4b, 0xc3, - 0x01, 0x8a, 0x29, 0xca, 0x5a, 0xe8, 0x58, 0xb1, 0xeb, 0x37, 0x29, 0xc3, 0xb9, 0xa5, 0x20, 0x77, - 0x53, 0x84, 0x7c, 0x68, 0x41, 0x69, 0x16, 0x86, 0xa0, 0xa1, 0xd7, 0x29, 0xdc, 0x5d, 0x2a, 0xb6, - 0x71, 0x8c, 0x76, 0x5d, 0x84, 0x71, 0x4c, 0x38, 0x37, 0xa7, 0xe2, 0xca, 0xf4, 0x6d, 0x52, 0xeb, - 0x17, 0x5f, 0x18, 0xec, 0x2d, 0x0d, 0x95, 0x47, 0x22, 0xa8, 0x0a, 0xc0, 0xef, 0xc1, 0x29, 0xa9, - 0x97, 0x69, 0x61, 0xd2, 0x27, 0x3e, 0x12, 0x2c, 0x76, 0x63, 0xb2, 0x8b, 0xe2, 0xd7, 0x3c, 0x1b, - 0x9b, 0xdc, 0x4f, 0x89, 0x37, 0x52, 0x02, 0x47, 0xe1, 0xbb, 0x96, 0xb3, 0x1c, 0x4c, 0x8c, 0xc2, - 0x1f, 0x6b, 0xe0, 0x4c, 0x41, 0x7f, 0x80, 0xfa, 0x14, 0x2b, 0x7d, 0x79, 0xa2, 0x28, 0xe7, 0xb2, - 0x3b, 0xcd, 0x28, 0x0f, 0x1f, 0xbe, 0xb6, 0x87, 0xad, 0x94, 0x64, 0x3d, 0xe3, 0xe8, 0x5a, 0x4e, - 0x33, 0x98, 0x9a, 0x01, 0x77, 0xc0, 0x92, 0xb4, 0xf2, 0x28, 0x09, 0xb1, 0x5b, 0x2c, 0x93, 0xc6, - 0xac, 0x32, 0x70, 0x79, 0x5f, 0x03, 0x77, 0x92, 0x10, 0x17, 0xea, 0xa4, 0x6b, 0x39, 0xf2, 0xbc, - 0x94, 0xe6, 0xe1, 0x43, 0xf0, 0x7f, 0xb5, 0xcf, 0xaa, 0x09, 0xb8, 0x59, 0x77, 0x9b, 0x2b, 0x1f, - 0xa3, 0xc2, 0x95, 0x5a, 0xea, 0x50, 0x5d, 0xcb, 0x39, 0x16, 0x94, 0x1a, 0x66, 0x91, 0x3d, 0x7d, - 0xef, 0x6d, 0x1c, 0x7a, 0x5d, 0xf6, 0x5c, 0x65, 0x8f, 0xd8, 0xb3, 0x1e, 0x72, 0x5d, 0xd7, 0xe2, - 0x80, 0x09, 0xd2, 0x00, 0x8a, 0xf2, 0xe4, 0xa4, 0x26, 0xb7, 0xc5, 0x04, 0x31, 0xa5, 0x28, 0xff, - 0xc2, 0x0e, 0x98, 0x97, 0x50, 0x4c, 0x22, 0xc6, 0xa9, 0x68, 0xcc, 0x2b, 0xf4, 0xca, 0x24, 0xf4, - 0x86, 0x4e, 0xeb, 0x5a, 0x0e, 0x08, 0xb2, 0x11, 0xdc, 0x00, 0x72, 0xe4, 0x26, 0xe1, 0xb7, 0x88, - 0xf6, 0x1b, 0x0b, 0x8a, 0xe2, 0xec, 0xd8, 0xeb, 0x94, 0xf9, 0x62, 0x30, 0x3c, 0x0f, 0x54, 0x6a, - 0xd7, 0x72, 0x0e, 0x05, 0xe9, 0x00, 0xba, 0xba, 0x90, 0xbd, 0x98, 0x20, 0x41, 0x46, 0xc7, 0xae, - 0x71, 0x58, 0xf1, 0x5d, 0x18, 0xe3, 0xd3, 0xdf, 0x18, 0x86, 0x6e, 0x5d, 0x61, 0xb2, 0x23, 0x64, - 0x2a, 0x79, 0x6c, 0x16, 0x7e, 0x09, 0xe4, 0xac, 0x4b, 0x30, 0x15, 0x39, 0xfa, 0x23, 0x8a, 0xfe, - 0xdd, 0x69, 0xf4, 0xb7, 0x31, 0x15, 0x79, 0xf2, 0xc5, 0x60, 0x6c, 0x0e, 0xde, 0x05, 0x0b, 0xfa, - 0x29, 0xaa, 0x62, 0x22, 0x8d, 0xa3, 0x8a, 0xf4, 0xad, 0x69, 0xa4, 0xa6, 0xf0, 0xe4, 0x66, 0xcc, - 0x07, 0xa3, 0x61, 0xfa, 0x18, 0x7a, 0xc4, 0xa7, 0xa1, 0x1b, 0x93, 0x8c, 0x72, 0x71, 0xff, 0xc7, - 0xd0, 0x91, 0x18, 0x27, 0x83, 0x98, 0xc7, 0x30, 0x36, 0x0b, 0x3f, 0xd3, 0x97, 0x6f, 0x12, 0x66, - 0xd4, 0xc7, 0xaa, 0xde, 0x35, 0x8b, 0xd4, 0x0f, 0xc2, 0x1c, 0xeb, 0xe1, 0x20, 0x3f, 0xd1, 0x3e, - 0xff, 0xec, 0xc9, 0xda, 0xb9, 0xa9, 0x2d, 0x45, 0x37, 0x13, 0xe9, 0x50, 0x37, 0x92, 0xce, 0xcd, - 0xa7, 0x2f, 0x9b, 0xb5, 0xe7, 0x2f, 0x9b, 0xb5, 0xbf, 0x5f, 0x36, 0x6b, 0x3f, 0xbf, 0x6a, 0x5a, - 0xcf, 0x5f, 0x35, 0xad, 0xbf, 0x5e, 0x35, 0xad, 0xaf, 0xa6, 0x13, 0x65, 0x9f, 0xf9, 0xbd, 0x19, - 0xf5, 0x3d, 0x78, 0xe5, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x3d, 0x1a, 0xad, 0x47, 0xfa, 0x0f, - 0x00, 0x00, + // 1443 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x58, 0xcf, 0x6f, 0xd4, 0xc6, + 0x17, 0xf7, 0xc2, 0x92, 0x2c, 0x93, 0x00, 0x61, 0xbe, 0xf0, 0x8d, 0x95, 0xc2, 0x26, 0x84, 0x16, + 0xb5, 0xa0, 0xac, 0x81, 0xd0, 0x02, 0xab, 0x56, 0xc0, 0x26, 0xa0, 0xa5, 0x6a, 0x5a, 0xe4, 0x40, + 0xaa, 0x56, 0xb4, 0xd6, 0xac, 0x67, 0x70, 0xdc, 0xac, 0x3d, 0xae, 0x67, 0xbc, 0xd9, 0x1c, 0xda, + 0x73, 0xdb, 0x53, 0xa5, 0xfe, 0x03, 0xa8, 0x3d, 0xf6, 0xca, 0xb1, 0xe7, 0x0a, 0x71, 0xe2, 0xd8, + 0x13, 0xaa, 0xe0, 0xd2, 0x3f, 0xa3, 0x9a, 0x1f, 0xf6, 0xda, 0xbb, 0xde, 0x4d, 0x7a, 0x89, 0x3c, + 0x33, 0xef, 0xf3, 0x63, 0x3c, 0xef, 0xcd, 0xf3, 0x06, 0x9c, 0x76, 0x29, 0x26, 0xae, 0xc5, 0x38, + 0xb6, 0xe4, 0x53, 0x23, 0x8a, 0x29, 0xa7, 0x70, 0xde, 0xa5, 0x2c, 0xa0, 0xcc, 0x61, 0x78, 0xa7, + 0xa1, 0xe6, 0x19, 0xc7, 0x8d, 0xde, 0x95, 0x85, 0x4b, 0x7c, 0xdb, 0x8f, 0xb1, 0x13, 0xa1, 0x98, + 0xef, 0x59, 0x32, 0xd6, 0x52, 0xa1, 0x2b, 0xf9, 0x81, 0x62, 0x59, 0xb8, 0x30, 0x1a, 0xec, 0x51, + 0x8f, 0x0e, 0x9e, 0x74, 0x9c, 0xd9, 0xb7, 0x50, 0xc2, 0xb7, 0x2d, 0xbe, 0x17, 0x11, 0xa6, 0xfe, + 0xea, 0x95, 0x25, 0xbd, 0xd2, 0x23, 0x8c, 0xfb, 0xa1, 0x57, 0x12, 0x61, 0xf6, 0xad, 0x0e, 0x0a, + 0x77, 0x4a, 0x56, 0x16, 0xfa, 0x96, 0x1b, 0xfb, 0xcc, 0x67, 0xe5, 0xbc, 0xd8, 0x67, 0x3c, 0xf6, + 0x3b, 0x09, 0xf7, 0x69, 0x58, 0x8e, 0x66, 0x49, 0x14, 0x75, 0xf7, 0x4a, 0xd6, 0xce, 0xf4, 0x2d, + 0xd2, 0xf3, 0x31, 0x09, 0x5d, 0x52, 0xb2, 0x3a, 0xdf, 0xb7, 0x3c, 0xda, 0x2b, 0x87, 0xb1, 0x2e, + 0x62, 0xdb, 0xe5, 0x1b, 0x79, 0xab, 0x6f, 0x31, 0x8e, 0x76, 0xca, 0x17, 0xcf, 0xf7, 0xad, 0x08, + 0xc5, 0x28, 0x48, 0xf7, 0x12, 0xc5, 0x34, 0xa2, 0x0c, 0x75, 0x87, 0x19, 0x92, 0xc8, 0x8b, 0x11, + 0x2e, 0x71, 0xb5, 0xfc, 0x47, 0x15, 0x4c, 0xdf, 0x71, 0x5d, 0x9a, 0x84, 0x1c, 0xde, 0x03, 0xb3, + 0x1d, 0xc4, 0x88, 0x83, 0xd4, 0xd8, 0xac, 0x2c, 0x55, 0xde, 0x9d, 0xb9, 0x7a, 0xae, 0x91, 0x3b, + 0xf4, 0x7e, 0x43, 0xbc, 0xf7, 0x46, 0xef, 0x4a, 0xa3, 0x85, 0x18, 0xd1, 0xc0, 0xb6, 0x61, 0xcf, + 0x74, 0x06, 0x43, 0xd8, 0x03, 0x0b, 0x2e, 0x0d, 0xb9, 0x1f, 0x26, 0x34, 0x61, 0x8e, 0x3e, 0xa3, + 0x8c, 0xf5, 0x90, 0x64, 0xfd, 0xa0, 0x8c, 0x55, 0x45, 0x0a, 0xf6, 0xb5, 0x0c, 0xbf, 0xa5, 0x26, + 0x07, 0x52, 0xa6, 0x3b, 0x66, 0x0d, 0x06, 0x60, 0x1e, 0x93, 0x2e, 0xda, 0x23, 0x78, 0x44, 0xf4, + 0xb0, 0x14, 0x5d, 0x9d, 0x2c, 0xba, 0xae, 0xc0, 0x23, 0x8a, 0xa7, 0x71, 0xd9, 0x02, 0x8c, 0x80, + 0x19, 0x91, 0xd8, 0xa7, 0xd8, 0x77, 0x47, 0xf4, 0xaa, 0x52, 0xef, 0xda, 0x64, 0xbd, 0x07, 0x1a, + 0x3d, 0x22, 0xf8, 0xff, 0xa8, 0x74, 0x05, 0x7e, 0x0a, 0x8e, 0x07, 0x14, 0x27, 0xdd, 0xc1, 0x11, + 0x1d, 0x91, 0x3a, 0xef, 0x14, 0x75, 0x54, 0x82, 0x0a, 0x85, 0x0d, 0x19, 0x3d, 0x20, 0x3e, 0x16, + 0xe4, 0x27, 0x9a, 0x37, 0x5f, 0x3c, 0x5b, 0x79, 0xff, 0xa2, 0xe7, 0xf3, 0xed, 0xa4, 0xd3, 0x70, + 0x69, 0xa0, 0xcb, 0x34, 0x2d, 0x5d, 0x86, 0x77, 0x2c, 0x5d, 0x68, 0xa4, 0x1f, 0xd1, 0x98, 0x13, + 0xdc, 0xd0, 0xd0, 0xd6, 0x11, 0x70, 0x98, 0x25, 0xc1, 0xf2, 0x4f, 0x15, 0x30, 0xb5, 0x29, 0xe5, + 0xe0, 0x0d, 0x30, 0xa5, 0x84, 0x75, 0xde, 0xd4, 0xc7, 0x99, 0x52, 0xf1, 0x6d, 0xc3, 0xd6, 0xf1, + 0xcd, 0x5b, 0xff, 0x3c, 0x5d, 0xac, 0xbc, 0x78, 0xb6, 0x72, 0x7d, 0x3f, 0x2b, 0xba, 0xf2, 0x32, + 0x33, 0x8a, 0xe9, 0x7e, 0x6a, 0xe6, 0xd7, 0x0a, 0xa8, 0xdd, 0xd5, 0x05, 0x08, 0x3f, 0x01, 0xb3, + 0xe4, 0xdb, 0xc4, 0xef, 0x51, 0x17, 0x89, 0x52, 0xd6, 0xa6, 0x2e, 0x14, 0x4d, 0xa5, 0xe5, 0x2a, + 0x6c, 0xdd, 0xcd, 0x45, 0xb7, 0x0d, 0xbb, 0x80, 0x6e, 0xde, 0xd1, 0x16, 0x6f, 0xee, 0xe3, 0x30, + 0xab, 0xff, 0xcc, 0x63, 0x6a, 0x28, 0x35, 0xf9, 0x7b, 0x05, 0x9c, 0xdc, 0x60, 0xde, 0x66, 0xd2, + 0x09, 0x7c, 0x9e, 0xb9, 0xfd, 0x08, 0xd4, 0x52, 0x68, 0x59, 0xd9, 0xe5, 0xef, 0xda, 0x8c, 0xd1, + 0xce, 0x20, 0x70, 0x03, 0x54, 0x45, 0x01, 0xea, 0xda, 0xb2, 0xc6, 0x6f, 0x72, 0x44, 0x59, 0x94, + 0x71, 0xab, 0xf6, 0xfc, 0xd5, 0xa2, 0xf1, 0xf2, 0xd5, 0x62, 0xc5, 0x96, 0x34, 0xcd, 0xda, 0x0f, + 0x4f, 0x17, 0x0d, 0xb1, 0xe3, 0xe5, 0xdf, 0xf2, 0x6e, 0x1f, 0xe8, 0xdb, 0x05, 0xb6, 0xb5, 0x9c, + 0x72, 0x7a, 0xb1, 0x28, 0xe7, 0xd1, 0x5e, 0x41, 0x29, 0x45, 0x95, 0x29, 0xc1, 0x26, 0x98, 0x16, + 0xe5, 0x4c, 0xb2, 0x7b, 0x61, 0x69, 0xec, 0xb6, 0xd7, 0x54, 0x9c, 0x9d, 0x02, 0x72, 0x2e, 0x7f, + 0xa9, 0x80, 0x5a, 0x66, 0xee, 0x56, 0xc1, 0xdc, 0xb9, 0x52, 0x73, 0x13, 0x3d, 0xdd, 0xfe, 0xcf, + 0x9e, 0x5a, 0x55, 0x41, 0x31, 0x70, 0x56, 0x95, 0xae, 0x9e, 0x56, 0xc1, 0xb4, 0x0e, 0x80, 0xd7, + 0x41, 0x95, 0x93, 0x3e, 0x9f, 0x68, 0xea, 0x21, 0xe9, 0x67, 0x2f, 0xab, 0x6d, 0xd8, 0x12, 0x00, + 0x1f, 0x83, 0x39, 0x79, 0xc3, 0x13, 0x4e, 0x62, 0xc7, 0xdd, 0x46, 0xa1, 0x37, 0xe6, 0x94, 0x55, + 0x1f, 0x90, 0x9b, 0x4b, 0xe3, 0xd7, 0x64, 0x78, 0x8e, 0xf2, 0x44, 0x54, 0x5c, 0x82, 0x5f, 0x81, + 0x39, 0x46, 0x9f, 0xf0, 0x5d, 0x14, 0x13, 0x47, 0xf7, 0x08, 0x7d, 0x55, 0x5e, 0x2e, 0xb2, 0xeb, + 0x45, 0x59, 0xbe, 0x1a, 0xf0, 0x48, 0x4d, 0xe5, 0xe9, 0x59, 0x71, 0x09, 0x46, 0x60, 0xde, 0x45, + 0xa1, 0x4b, 0xba, 0xce, 0x88, 0x4a, 0xb5, 0xac, 0x0b, 0xe4, 0x54, 0xd6, 0x24, 0x6e, 0xbc, 0xd6, + 0x69, 0xb7, 0x2c, 0x00, 0x76, 0xc1, 0x29, 0x97, 0x06, 0x41, 0x12, 0xfa, 0x7c, 0xcf, 0x89, 0x28, + 0xed, 0x3a, 0x2c, 0x22, 0x21, 0xd6, 0xf7, 0xe4, 0x8d, 0xa2, 0x5c, 0xbe, 0xd5, 0xab, 0xd3, 0xd4, + 0xc8, 0x07, 0x94, 0x76, 0x37, 0x05, 0x2e, 0x27, 0x08, 0xdd, 0x91, 0xd5, 0xe6, 0x0d, 0x7d, 0x2b, + 0x5c, 0xde, 0xe7, 0x56, 0xc8, 0xfa, 0x7e, 0x96, 0x30, 0xfa, 0x32, 0xf8, 0x1e, 0xcc, 0x3c, 0x8c, + 0x51, 0xc8, 0x90, 0x2b, 0x3c, 0xc0, 0xd5, 0x42, 0xea, 0x2e, 0x96, 0x37, 0xde, 0x4d, 0x8e, 0x1f, + 0xf6, 0x45, 0xe2, 0xea, 0x74, 0xbd, 0x06, 0xaa, 0x01, 0xf3, 0x98, 0x79, 0x68, 0xe9, 0xf0, 0xc4, + 0x5c, 0xdd, 0x20, 0x8c, 0x21, 0x8f, 0xd8, 0x32, 0xba, 0x59, 0x15, 0xc5, 0xb3, 0xfc, 0xe7, 0x2c, + 0x98, 0xd6, 0xf3, 0xb0, 0x09, 0x6a, 0x01, 0xf3, 0x1c, 0x26, 0x5e, 0x97, 0x32, 0x70, 0xb6, 0x68, + 0x40, 0x7c, 0x4f, 0xa5, 0x95, 0x4d, 0x42, 0xdc, 0x36, 0xec, 0xe9, 0x40, 0x3d, 0xc2, 0x8f, 0xc1, + 0x71, 0x81, 0x0d, 0x92, 0x2e, 0xf7, 0x15, 0x83, 0xca, 0xd1, 0xe5, 0xb1, 0x0c, 0x1b, 0x22, 0x54, + 0xd3, 0xcc, 0x06, 0xb9, 0x31, 0xfc, 0x1a, 0x9c, 0x12, 0x5c, 0x3d, 0x12, 0xfb, 0x4f, 0xf6, 0x1c, + 0x3f, 0xec, 0xa1, 0xd8, 0x47, 0x59, 0x0b, 0x1f, 0xba, 0x6c, 0xd4, 0x97, 0x9c, 0xe6, 0xdc, 0x92, + 0x90, 0xfb, 0x29, 0x42, 0x1c, 0x5a, 0x30, 0x32, 0x0b, 0x43, 0x60, 0xaa, 0x7d, 0x72, 0x67, 0xd7, + 0xe7, 0xdb, 0x38, 0x46, 0xbb, 0x0e, 0xc2, 0x38, 0x26, 0x8c, 0xe9, 0xac, 0x5c, 0x9d, 0x9c, 0x26, + 0x72, 0xff, 0xfc, 0x73, 0x8d, 0xbd, 0xa3, 0xa0, 0x22, 0x25, 0x83, 0xb2, 0x05, 0xf8, 0x1d, 0x38, + 0x2b, 0xf4, 0x32, 0x2d, 0x4c, 0xba, 0xc4, 0x43, 0x9c, 0xc6, 0x4e, 0x4c, 0x76, 0x51, 0x7c, 0xc0, + 0xdc, 0xdc, 0x60, 0x5e, 0x4a, 0xbc, 0x9e, 0x12, 0xd8, 0x12, 0xdf, 0x36, 0xec, 0x85, 0x60, 0xec, + 0x2a, 0xfc, 0xb1, 0x02, 0xce, 0x15, 0xf4, 0x7b, 0xa8, 0xeb, 0x63, 0xa9, 0x2f, 0x32, 0xda, 0x67, + 0x4c, 0x74, 0xc7, 0x29, 0xe9, 0xe1, 0xc3, 0x03, 0x7b, 0xd8, 0x4a, 0x49, 0xd6, 0x32, 0x8e, 0xb6, + 0x61, 0xd7, 0x83, 0x89, 0x11, 0x70, 0x07, 0xcc, 0x0b, 0x2b, 0x4f, 0x92, 0x10, 0x3b, 0xc5, 0x32, + 0x35, 0xa7, 0xa5, 0x81, 0xab, 0xfb, 0x1a, 0xb8, 0x97, 0x84, 0xb8, 0x50, 0xa7, 0x6d, 0xc3, 0x16, + 0xf9, 0x32, 0x32, 0x0f, 0x1f, 0x83, 0xff, 0xc9, 0x73, 0x96, 0x4d, 0xc8, 0xc9, 0xba, 0x6b, 0x6d, + 0x34, 0x8d, 0x8a, 0x65, 0x32, 0xdc, 0x21, 0xdb, 0x86, 0x7d, 0x32, 0x18, 0x69, 0xd8, 0x45, 0xf6, + 0xf4, 0xbb, 0xdb, 0x3c, 0x7a, 0x50, 0xf6, 0xdc, 0xcd, 0x32, 0x60, 0xcf, 0x7a, 0xd8, 0x4d, 0x55, + 0x8b, 0x3d, 0xca, 0x89, 0x09, 0x24, 0xe5, 0x99, 0x71, 0x4d, 0x76, 0x8b, 0x72, 0xa2, 0x4b, 0x51, + 0x3c, 0xc2, 0x16, 0x98, 0x11, 0x50, 0x4c, 0x22, 0xca, 0x7c, 0x6e, 0xce, 0x94, 0x5d, 0x25, 0x03, + 0xf4, 0xba, 0x0a, 0x6b, 0x1b, 0x36, 0x08, 0xb2, 0x11, 0x5c, 0x07, 0x62, 0xe4, 0x24, 0xe1, 0x37, + 0xc8, 0xef, 0x9a, 0xb3, 0x92, 0xe2, 0xfc, 0xd0, 0xe7, 0x9c, 0xfe, 0xc5, 0xa2, 0x79, 0x1e, 0xc9, + 0xd0, 0xb6, 0x61, 0x1f, 0x0d, 0xd2, 0x01, 0x74, 0x54, 0x21, 0xbb, 0x31, 0x41, 0x9c, 0x0c, 0xd2, + 0xce, 0x3c, 0x26, 0xf9, 0x2e, 0x0d, 0xf1, 0xa9, 0xdf, 0x38, 0x9a, 0x6e, 0x4d, 0x62, 0xb2, 0x14, + 0xd2, 0x95, 0x3c, 0x34, 0x0b, 0xbf, 0x00, 0x62, 0xd6, 0x21, 0xd8, 0xe7, 0x39, 0xfa, 0xe3, 0x92, + 0xfe, 0xbd, 0x49, 0xf4, 0x77, 0xb1, 0xcf, 0xf3, 0xe4, 0x73, 0xc1, 0xd0, 0x1c, 0xbc, 0x0f, 0x66, + 0xd5, 0x5b, 0x94, 0xc5, 0x44, 0xcc, 0x13, 0x92, 0xf4, 0xed, 0x49, 0xa4, 0xba, 0xf0, 0xc4, 0x61, + 0xcc, 0x04, 0x83, 0x61, 0xfa, 0x1a, 0x3a, 0xc4, 0xf3, 0x43, 0x27, 0x26, 0x19, 0xe5, 0xdc, 0xfe, + 0xaf, 0xa1, 0x25, 0x30, 0x76, 0x06, 0xd1, 0xaf, 0x61, 0x68, 0x16, 0x7e, 0xa6, 0x2e, 0xdf, 0x24, + 0xcc, 0xa8, 0x4f, 0x96, 0x7d, 0xeb, 0x16, 0xa9, 0x1f, 0x85, 0x39, 0xd6, 0x63, 0x41, 0x7e, 0xa2, + 0x79, 0xf1, 0xc5, 0xb3, 0x95, 0x0b, 0x13, 0x5b, 0x9a, 0x6a, 0x66, 0xc2, 0xa1, 0x6a, 0x64, 0xad, + 0xdb, 0xcf, 0x5f, 0xd7, 0x2b, 0x2f, 0x5f, 0xd7, 0x2b, 0x7f, 0xbf, 0xae, 0x57, 0x7e, 0x7e, 0x53, + 0x37, 0x5e, 0xbe, 0xa9, 0x1b, 0x7f, 0xbd, 0xa9, 0x1b, 0x5f, 0x4e, 0x26, 0xca, 0xfe, 0xcd, 0xd0, + 0x99, 0x92, 0xbf, 0x47, 0x57, 0xff, 0x0d, 0x00, 0x00, 0xff, 0xff, 0xed, 0xa0, 0xda, 0x1d, 0x7a, + 0x10, 0x00, 0x00, } func (this *Supply) Equal(that interface{}) bool { @@ -2131,6 +2176,55 @@ func (m *Content_CommunityPoolSpend) MarshalToSizedBuffer(dAtA []byte) (int, err } return len(dAtA) - i, nil } +func (m *Transaction) 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 *Transaction) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Transaction) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Msgs) > 0 { + for iNdEx := len(m.Msgs) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Msgs[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if m.Base != nil { + { + size, err := m.Base.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *Message) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -2770,6 +2864,25 @@ func (m *Content_CommunityPoolSpend) Size() (n int) { } return n } +func (m *Transaction) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Base != nil { + l = m.Base.Size() + n += 1 + l + sovCodec(uint64(l)) + } + if len(m.Msgs) > 0 { + for _, e := range m.Msgs { + l = e.Size() + n += 1 + l + sovCodec(uint64(l)) + } + } + return n +} + func (m *Message) Size() (n int) { if m == nil { return 0 @@ -3988,6 +4101,129 @@ func (m *Content) Unmarshal(dAtA []byte) error { } return nil } +func (m *Transaction) 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 ErrIntOverflowCodec + } + 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: Transaction: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Transaction: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Base", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Base == nil { + m.Base = &types.StdTxBase{} + } + if err := m.Base.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Msgs", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Msgs = append(m.Msgs, &Message{}) + if err := m.Msgs[len(m.Msgs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCodec(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *Message) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/codec/std/codec.proto b/codec/std/codec.proto index 612709a9bb3c..545597db7849 100644 --- a/codec/std/codec.proto +++ b/codec/std/codec.proto @@ -100,6 +100,16 @@ message Content { } } +// Transaction defines the application-level transaction that can be signed and +// processed by the state-machine. It contains a base of common fields and +// repeated set of Message types. +message Transaction { + option (gogoproto.goproto_getters) = false; + + cosmos_sdk.x.auth.v1.StdTxBase base = 1; + repeated Message msgs = 2; +} + // Message defines the set of valid concrete message types that can be used to // construct a transaction. message Message { diff --git a/codec/std/tx.go b/codec/std/tx.go new file mode 100644 index 000000000000..b261726719e4 --- /dev/null +++ b/codec/std/tx.go @@ -0,0 +1,67 @@ +package std + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/auth" +) + +var _ sdk.Tx = Transaction{} + +// GetMsgs returns all the messages in a Transaction as a slice of sdk.Msg. +func (tx Transaction) GetMsgs() []sdk.Msg { + msgs := make([]sdk.Msg, len(tx.Msgs)) + + for i, m := range tx.Msgs { + msgs[i] = m.GetMsg() + } + + return msgs +} + +// GetSigners returns the addresses that must sign the transaction. Addresses are +// returned in a deterministic order. They are accumulated from the GetSigners +// method for each Msg in the order they appear in tx.GetMsgs(). Duplicate addresses +// will be omitted. +func (tx Transaction) GetSigners() []sdk.AccAddress { + var signers []sdk.AccAddress + seen := map[string]bool{} + + for _, msg := range tx.GetMsgs() { + for _, addr := range msg.GetSigners() { + if !seen[addr.String()] { + signers = append(signers, addr) + seen[addr.String()] = true + } + } + } + + return signers +} + +// ValidateBasic does a simple and lightweight validation check that doesn't +// require access to any other information. +func (tx Transaction) ValidateBasic() error { + stdSigs := tx.Base.GetSignatures() + + if tx.Base.Fee.Gas > auth.MaxGasWanted { + return sdkerrors.Wrapf( + sdkerrors.ErrInvalidRequest, "invalid gas supplied; %d > %d", tx.Base.Fee.Gas, auth.MaxGasWanted, + ) + } + if tx.Base.Fee.Amount.IsAnyNegative() { + return sdkerrors.Wrapf( + sdkerrors.ErrInsufficientFee, "invalid fee provided: %s", tx.Base.Fee.Amount, + ) + } + if len(stdSigs) == 0 { + return sdkerrors.ErrNoSignatures + } + if len(stdSigs) != len(tx.GetSigners()) { + return sdkerrors.Wrapf( + sdkerrors.ErrUnauthorized, "wrong number of signers; expected %d, got %d", tx.GetSigners(), len(stdSigs), + ) + } + + return nil +} diff --git a/docs/architecture/adr-020-protobuf-transaction-encoding.md b/docs/architecture/adr-020-protobuf-transaction-encoding.md index 39d3b1421be5..d61d65ade761 100644 --- a/docs/architecture/adr-020-protobuf-transaction-encoding.md +++ b/docs/architecture/adr-020-protobuf-transaction-encoding.md @@ -43,9 +43,9 @@ message Message { option (cosmos_proto.interface_type) = "github.com/cosmos/cosmos-sdk/types.Msg"; oneof sum { - bank.MsgSend = 1; - staking.MsgCreateValidator = 2; - staking.MsgDelegate = 3; + cosmos_sdk.x.bank.v1.MsgSend msg_send = 1; + cosmos_sdk.x.bank.v1.MsgMultiSend msg_multi_send = 2; + cosmos_sdk.x.crisis.v1.MsgVerifyInvariant msg_verify_invariant = 3; // ... } } @@ -61,10 +61,8 @@ Example: // app/codec/codec.proto message Transaction { - option (cosmos_proto.interface_type) = "github.com/cosmos/cosmos-sdk/types.Tx"; - - StdTxBase base = 1; - repeated Message msgs = 2; + cosmos_sdk.x.auth.v1.StdTxBase base = 1; + repeated Message msgs = 2; } ``` diff --git a/simapp/helpers/test_helpers.go b/simapp/helpers/test_helpers.go index 2341635eeea8..ef265c8237e4 100644 --- a/simapp/helpers/test_helpers.go +++ b/simapp/helpers/test_helpers.go @@ -39,7 +39,7 @@ func GenTx(msgs []sdk.Msg, feeAmt sdk.Coins, gas uint64, chainID string, accnums } sigs[i] = auth.StdSignature{ - PubKey: p.PubKey(), + PubKey: p.PubKey().Bytes(), Signature: sig, } } diff --git a/x/auth/alias.go b/x/auth/alias.go index 6c242caf5178..f21e285cc3cd 100644 --- a/x/auth/alias.go +++ b/x/auth/alias.go @@ -22,6 +22,7 @@ const ( DefaultSigVerifyCostSecp256k1 = types.DefaultSigVerifyCostSecp256k1 QueryAccount = types.QueryAccount QueryParams = types.QueryParams + MaxGasWanted = types.MaxGasWanted ) var ( diff --git a/x/auth/ante/basic.go b/x/auth/ante/basic.go index 05e570ca2854..d8abf8c9d0d5 100644 --- a/x/auth/ante/basic.go +++ b/x/auth/ante/basic.go @@ -127,7 +127,7 @@ func (cgts ConsumeTxSizeGasDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, sim // use stdsignature to mock the size of a full signature simSig := types.StdSignature{ Signature: simSecp256k1Sig[:], - PubKey: pubkey, + PubKey: pubkey.Bytes(), } sigBz := codec.Cdc.MustMarshalBinaryLengthPrefixed(simSig) diff --git a/x/auth/client/cli/tx_multisign.go b/x/auth/client/cli/tx_multisign.go index f1ea091d0b1e..f5bf16ca279e 100644 --- a/x/auth/client/cli/tx_multisign.go +++ b/x/auth/client/cli/tx_multisign.go @@ -106,15 +106,15 @@ func makeMultiSignCmd(cdc *codec.Codec) func(cmd *cobra.Command, args []string) txBldr.ChainID(), txBldr.AccountNumber(), txBldr.Sequence(), stdTx.Fee, stdTx.GetMsgs(), stdTx.GetMemo(), ) - if ok := stdSig.PubKey.VerifyBytes(sigBytes, stdSig.Signature); !ok { + if ok := stdSig.GetPubKey().VerifyBytes(sigBytes, stdSig.Signature); !ok { return fmt.Errorf("couldn't verify signature") } - if err := multisigSig.AddSignatureFromPubKey(stdSig.Signature, stdSig.PubKey, multisigPub.PubKeys); err != nil { + if err := multisigSig.AddSignatureFromPubKey(stdSig.Signature, stdSig.GetPubKey(), multisigPub.PubKeys); err != nil { return err } } - newStdSig := types.StdSignature{Signature: cdc.MustMarshalBinaryBare(multisigSig), PubKey: multisigPub} + newStdSig := types.StdSignature{Signature: cdc.MustMarshalBinaryBare(multisigSig), PubKey: multisigPub.Bytes()} newTx := types.NewStdTx(stdTx.GetMsgs(), stdTx.Fee, []types.StdSignature{newStdSig}, stdTx.GetMemo()) sigOnly := viper.GetBool(flagSigOnly) diff --git a/x/auth/client/cli/tx_sign.go b/x/auth/client/cli/tx_sign.go index a6434be7ef92..6d95c47ef4ce 100644 --- a/x/auth/client/cli/tx_sign.go +++ b/x/auth/client/cli/tx_sign.go @@ -208,7 +208,7 @@ func printAndValidateSigs( } for i, sig := range sigs { - sigAddr := sdk.AccAddress(sig.Address()) + sigAddr := sdk.AccAddress(sig.GetPubKey().Address()) sigSanity := "OK" var ( @@ -235,13 +235,13 @@ func printAndValidateSigs( stdTx.Fee, stdTx.GetMsgs(), stdTx.GetMemo(), ) - if ok := sig.VerifyBytes(sigBytes, sig.Signature); !ok { + if ok := sig.GetPubKey().VerifyBytes(sigBytes, sig.Signature); !ok { sigSanity = "ERROR: signature invalid" success = false } } - multiPK, ok := sig.PubKey.(multisig.PubKeyMultisigThreshold) + multiPK, ok := sig.GetPubKey().(multisig.PubKeyMultisigThreshold) if ok { var multiSig multisig.Multisignature cliCtx.Codec.MustUnmarshalBinaryBare(sig.Signature, &multiSig) diff --git a/x/auth/types/stdtx.go b/x/auth/types/stdtx.go index a9a6cd3e9daf..e784f48ae52d 100644 --- a/x/auth/types/stdtx.go +++ b/x/auth/types/stdtx.go @@ -14,11 +14,10 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth/exported" ) -var ( - _ sdk.Tx = (*StdTx)(nil) +// MaxGasWanted defines the max gas allowed. +const MaxGasWanted = uint64((1 << 63) - 1) - maxGasWanted = uint64((1 << 63) - 1) -) +var _ sdk.Tx = (*StdTx)(nil) // StdTx is a standard way to wrap a Msg with Fee and Signatures. // NOTE: the first signature is the fee payer (Signatures must not be nil). @@ -46,10 +45,10 @@ func (tx StdTx) GetMsgs() []sdk.Msg { return tx.Msgs } func (tx StdTx) ValidateBasic() error { stdSigs := tx.GetSignatures() - if tx.Fee.Gas > maxGasWanted { + if tx.Fee.Gas > MaxGasWanted { return sdkerrors.Wrapf( sdkerrors.ErrInvalidRequest, - "invalid gas supplied; %d > %d", tx.Fee.Gas, maxGasWanted, + "invalid gas supplied; %d > %d", tx.Fee.Gas, MaxGasWanted, ) } if tx.Fee.Amount.IsAnyNegative() { @@ -92,8 +91,9 @@ func CountSubKeys(pub crypto.PubKey) int { // in the order they appear in tx.GetMsgs(). // Duplicate addresses will be omitted. func (tx StdTx) GetSigners() []sdk.AccAddress { - seen := map[string]bool{} var signers []sdk.AccAddress + seen := map[string]bool{} + for _, msg := range tx.GetMsgs() { for _, addr := range msg.GetSigners() { if !seen[addr.String()] { @@ -102,6 +102,7 @@ func (tx StdTx) GetSigners() []sdk.AccAddress { } } } + return signers } @@ -127,9 +128,11 @@ func (tx StdTx) GetSignatures() [][]byte { // If pubkey is not included in the signature, then nil is in the slice instead func (tx StdTx) GetPubKeys() []crypto.PubKey { pks := make([]crypto.PubKey, len(tx.Signatures)) + for i, stdSig := range tx.Signatures { - pks[i] = stdSig.PubKey + pks[i] = stdSig.GetPubKey() } + return pks } @@ -237,12 +240,6 @@ func StdSignBytes(chainID string, accnum uint64, sequence uint64, fee StdFee, ms return sdk.MustSortJSON(bz) } -// StdSignature represents a sig -type StdSignature struct { - crypto.PubKey `json:"pub_key" yaml:"pub_key"` // optional - Signature []byte `json:"signature" yaml:"signature"` -} - // DefaultTxDecoder logic for standard transaction decoding func DefaultTxDecoder(cdc *codec.Codec) sdk.TxDecoder { return func(txBytes []byte) (sdk.Tx, error) { @@ -270,6 +267,17 @@ func DefaultTxEncoder(cdc *codec.Codec) sdk.TxEncoder { } } +// GetPubKey returns the public key of a signature as a crypto.PubKey using the +// Amino codec. +func (ss StdSignature) GetPubKey() (pk crypto.PubKey) { + if len(ss.PubKey) == 0 { + return nil + } + + codec.Cdc.MustUnmarshalBinaryBare(ss.PubKey, &pk) + return pk +} + // MarshalYAML returns the YAML representation of the signature. func (ss StdSignature) MarshalYAML() (interface{}, error) { var ( @@ -279,7 +287,7 @@ func (ss StdSignature) MarshalYAML() (interface{}, error) { ) if ss.PubKey != nil { - pubkey, err = sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, ss.PubKey) + pubkey, err = sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, ss.GetPubKey()) if err != nil { return nil, err } @@ -290,7 +298,7 @@ func (ss StdSignature) MarshalYAML() (interface{}, error) { Signature string }{ PubKey: pubkey, - Signature: fmt.Sprintf("%s", ss.Signature), + Signature: fmt.Sprintf("%X", ss.Signature), }) if err != nil { return nil, err diff --git a/x/auth/types/stdtx_test.go b/x/auth/types/stdtx_test.go index a8ce9d721076..38e1a3348b1f 100644 --- a/x/auth/types/stdtx_test.go +++ b/x/auth/types/stdtx_test.go @@ -152,11 +152,11 @@ func TestStdSignatureMarshalYAML(t *testing.T) { "|\n pubkey: \"\"\n signature: \"\"\n", }, { - StdSignature{PubKey: pubKey, Signature: []byte("dummySig")}, + StdSignature{PubKey: pubKey.Bytes(), Signature: []byte("dummySig")}, fmt.Sprintf("|\n pubkey: %s\n signature: dummySig\n", sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pubKey)), }, { - StdSignature{PubKey: pubKey, Signature: nil}, + StdSignature{PubKey: pubKey.Bytes(), Signature: nil}, fmt.Sprintf("|\n pubkey: %s\n signature: \"\"\n", sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pubKey)), }, } diff --git a/x/auth/types/test_utils.go b/x/auth/types/test_utils.go index 9e2ba20e98d2..a5024e7f8bd8 100644 --- a/x/auth/types/test_utils.go +++ b/x/auth/types/test_utils.go @@ -42,7 +42,7 @@ func NewTestTx(ctx sdk.Context, msgs []sdk.Msg, privs []crypto.PrivKey, accNums panic(err) } - sigs[i] = StdSignature{PubKey: priv.PubKey(), Signature: sig} + sigs[i] = StdSignature{PubKey: priv.PubKey().Bytes(), Signature: sig} } tx := NewStdTx(msgs, fee, sigs, "") @@ -59,7 +59,7 @@ func NewTestTxWithMemo(ctx sdk.Context, msgs []sdk.Msg, privs []crypto.PrivKey, panic(err) } - sigs[i] = StdSignature{PubKey: priv.PubKey(), Signature: sig} + sigs[i] = StdSignature{PubKey: priv.PubKey().Bytes(), Signature: sig} } tx := NewStdTx(msgs, fee, sigs, memo) @@ -74,7 +74,7 @@ func NewTestTxWithSignBytes(msgs []sdk.Msg, privs []crypto.PrivKey, accNums []ui panic(err) } - sigs[i] = StdSignature{PubKey: priv.PubKey(), Signature: sig} + sigs[i] = StdSignature{PubKey: priv.PubKey().Bytes(), Signature: sig} } tx := NewStdTx(msgs, fee, sigs, memo) diff --git a/x/auth/types/txbuilder.go b/x/auth/types/txbuilder.go index 4ffd327d66a7..47c79d39009b 100644 --- a/x/auth/types/txbuilder.go +++ b/x/auth/types/txbuilder.go @@ -286,8 +286,9 @@ func MakeSignature(keybase keys.Keybase, name, passphrase string, if err != nil { return } + return StdSignature{ - PubKey: pubkey, + PubKey: pubkey.Bytes(), Signature: sigBytes, }, nil } diff --git a/x/auth/types/types.pb.go b/x/auth/types/types.pb.go index f5fa313fb325..cc3837b4db3d 100644 --- a/x/auth/types/types.pb.go +++ b/x/auth/types/types.pb.go @@ -122,6 +122,46 @@ func (m *StdFee) GetGas() uint64 { return 0 } +// StdSignature defines a signature structure that contains the signature of a +// transaction and an optional public key. +type StdSignature struct { + PubKey []byte `protobuf:"bytes,1,opt,name=pub_key,json=pubKey,proto3" json:"public_key,omitempty" yaml:"public_key"` + Signature []byte `protobuf:"bytes,2,opt,name=signature,proto3" json:"signature,omitempty"` +} + +func (m *StdSignature) Reset() { *m = StdSignature{} } +func (m *StdSignature) String() string { return proto.CompactTextString(m) } +func (*StdSignature) ProtoMessage() {} +func (*StdSignature) Descriptor() ([]byte, []int) { + return fileDescriptor_2d526fa662daab74, []int{2} +} +func (m *StdSignature) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StdSignature) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_StdSignature.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 *StdSignature) XXX_Merge(src proto.Message) { + xxx_messageInfo_StdSignature.Merge(m, src) +} +func (m *StdSignature) XXX_Size() int { + return m.Size() +} +func (m *StdSignature) XXX_DiscardUnknown() { + xxx_messageInfo_StdSignature.DiscardUnknown(m) +} + +var xxx_messageInfo_StdSignature proto.InternalMessageInfo + // Params defines the parameters for the auth module. type Params struct { MaxMemoCharacters uint64 `protobuf:"varint,1,opt,name=max_memo_characters,json=maxMemoCharacters,proto3" json:"max_memo_characters,omitempty" yaml:"max_memo_characters"` @@ -134,7 +174,7 @@ type Params struct { func (m *Params) Reset() { *m = Params{} } func (*Params) ProtoMessage() {} func (*Params) Descriptor() ([]byte, []int) { - return fileDescriptor_2d526fa662daab74, []int{2} + return fileDescriptor_2d526fa662daab74, []int{3} } func (m *Params) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -198,56 +238,126 @@ func (m *Params) GetSigVerifyCostSecp256k1() uint64 { return 0 } +// StdTxBase defines a transaction base which application-level concrete transaction +// types can extend. +type StdTxBase struct { + Fee *StdFee `protobuf:"bytes,1,opt,name=fee,proto3" json:"fee,omitempty"` + Signatures []*StdSignature `protobuf:"bytes,2,rep,name=signatures,proto3" json:"signatures,omitempty"` + Memo string `protobuf:"bytes,3,opt,name=memo,proto3" json:"memo,omitempty"` +} + +func (m *StdTxBase) Reset() { *m = StdTxBase{} } +func (m *StdTxBase) String() string { return proto.CompactTextString(m) } +func (*StdTxBase) ProtoMessage() {} +func (*StdTxBase) Descriptor() ([]byte, []int) { + return fileDescriptor_2d526fa662daab74, []int{4} +} +func (m *StdTxBase) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StdTxBase) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_StdTxBase.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 *StdTxBase) XXX_Merge(src proto.Message) { + xxx_messageInfo_StdTxBase.Merge(m, src) +} +func (m *StdTxBase) XXX_Size() int { + return m.Size() +} +func (m *StdTxBase) XXX_DiscardUnknown() { + xxx_messageInfo_StdTxBase.DiscardUnknown(m) +} + +var xxx_messageInfo_StdTxBase proto.InternalMessageInfo + +func (m *StdTxBase) GetFee() *StdFee { + if m != nil { + return m.Fee + } + return nil +} + +func (m *StdTxBase) GetSignatures() []*StdSignature { + if m != nil { + return m.Signatures + } + return nil +} + +func (m *StdTxBase) GetMemo() string { + if m != nil { + return m.Memo + } + return "" +} + func init() { proto.RegisterType((*BaseAccount)(nil), "cosmos_sdk.x.auth.v1.BaseAccount") proto.RegisterType((*StdFee)(nil), "cosmos_sdk.x.auth.v1.StdFee") + proto.RegisterType((*StdSignature)(nil), "cosmos_sdk.x.auth.v1.StdSignature") proto.RegisterType((*Params)(nil), "cosmos_sdk.x.auth.v1.Params") + proto.RegisterType((*StdTxBase)(nil), "cosmos_sdk.x.auth.v1.StdTxBase") } func init() { proto.RegisterFile("x/auth/types/types.proto", fileDescriptor_2d526fa662daab74) } var fileDescriptor_2d526fa662daab74 = []byte{ - // 630 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x54, 0xbf, 0x6f, 0xd3, 0x4e, - 0x14, 0x8f, 0x9b, 0x7c, 0xd3, 0xea, 0xda, 0x2f, 0x22, 0x6e, 0xda, 0xba, 0x11, 0xf2, 0x45, 0x1e, - 0x50, 0x90, 0xa8, 0x43, 0x8a, 0x8a, 0xd4, 0x0c, 0x88, 0x3a, 0xd0, 0xa5, 0x50, 0x55, 0x8e, 0xc4, - 0x80, 0x84, 0xac, 0xb3, 0x7d, 0x38, 0x56, 0x7a, 0x39, 0xd7, 0x77, 0xae, 0xec, 0x2e, 0xac, 0x88, - 0x89, 0x91, 0xb1, 0x33, 0x7f, 0x49, 0xc7, 0x8e, 0x4c, 0x2e, 0x4a, 0x17, 0xc4, 0xe8, 0x91, 0x09, - 0xd9, 0x97, 0xb6, 0x69, 0x29, 0x88, 0xc5, 0xbe, 0xf7, 0xde, 0xe7, 0xc7, 0xf9, 0xbd, 0xf3, 0x01, - 0x25, 0x6e, 0xa3, 0x88, 0x0f, 0xda, 0x3c, 0x09, 0x30, 0x13, 0x4f, 0x3d, 0x08, 0x29, 0xa7, 0x72, - 0xdd, 0xa1, 0x8c, 0x50, 0x66, 0x31, 0x77, 0xa8, 0xc7, 0x7a, 0x0e, 0xd2, 0x0f, 0x3b, 0x8d, 0xfb, - 0x7c, 0xe0, 0x87, 0xae, 0x15, 0xa0, 0x90, 0x27, 0xed, 0x02, 0xd8, 0xf6, 0xa8, 0x47, 0xaf, 0x56, - 0x82, 0xdd, 0xa8, 0xfd, 0x26, 0xa8, 0x7d, 0x9c, 0x01, 0xf3, 0x06, 0x62, 0x78, 0xcb, 0x71, 0x68, - 0x34, 0xe2, 0xf2, 0x0e, 0x98, 0x45, 0xae, 0x1b, 0x62, 0xc6, 0x14, 0xa9, 0x29, 0xb5, 0x16, 0x8c, - 0xce, 0xcf, 0x14, 0xae, 0x79, 0x3e, 0x1f, 0x44, 0xb6, 0xee, 0x50, 0xd2, 0x16, 0x1b, 0x98, 0xbc, - 0xd6, 0x98, 0x3b, 0x9c, 0xc8, 0x6d, 0x39, 0xce, 0x96, 0x20, 0x9a, 0x17, 0x0a, 0xf2, 0x36, 0x98, - 0x0d, 0x22, 0xdb, 0x1a, 0xe2, 0x44, 0x99, 0x29, 0xc4, 0xd6, 0x7e, 0xa4, 0xb0, 0x1e, 0x44, 0xf6, - 0xbe, 0xef, 0xe4, 0xd9, 0x87, 0x94, 0xf8, 0x1c, 0x93, 0x80, 0x27, 0x59, 0x0a, 0x6b, 0x09, 0x22, - 0xfb, 0x5d, 0xed, 0xaa, 0xaa, 0x99, 0xd5, 0x20, 0xb2, 0x77, 0x70, 0x22, 0x3f, 0x03, 0x77, 0x90, - 0xd8, 0x9f, 0x35, 0x8a, 0x88, 0x8d, 0x43, 0xa5, 0xdc, 0x94, 0x5a, 0x15, 0x63, 0x35, 0x4b, 0xe1, - 0x92, 0xa0, 0x5d, 0xaf, 0x6b, 0xe6, 0xff, 0x93, 0xc4, 0x6e, 0x11, 0xcb, 0x0d, 0x30, 0xc7, 0xf0, - 0x41, 0x84, 0x47, 0x0e, 0x56, 0x2a, 0x39, 0xd7, 0xbc, 0x8c, 0xbb, 0x73, 0x1f, 0x8e, 0x61, 0xe9, - 0xf3, 0x31, 0x2c, 0x69, 0xef, 0x41, 0xb5, 0xcf, 0xdd, 0x6d, 0x8c, 0xe5, 0xb7, 0xa0, 0x8a, 0x48, - 0xce, 0x57, 0xa4, 0x66, 0xb9, 0x35, 0xbf, 0xbe, 0xa8, 0x4f, 0x35, 0xfe, 0xb0, 0xa3, 0xf7, 0xa8, - 0x3f, 0x32, 0x1e, 0x9d, 0xa4, 0xb0, 0xf4, 0xe5, 0x0c, 0xb6, 0xfe, 0xa1, 0x3d, 0x39, 0x81, 0x99, - 0x13, 0x51, 0xf9, 0x2e, 0x28, 0x7b, 0x88, 0x15, 0x4d, 0xa9, 0x98, 0xf9, 0xb2, 0x5b, 0xf9, 0x7e, - 0x0c, 0x25, 0xed, 0xac, 0x0c, 0xaa, 0x7b, 0x28, 0x44, 0x84, 0xc9, 0xbb, 0x60, 0x91, 0xa0, 0xd8, - 0x22, 0x98, 0x50, 0xcb, 0x19, 0xa0, 0x10, 0x39, 0x1c, 0x87, 0x62, 0x28, 0x15, 0x43, 0xcd, 0x52, - 0xd8, 0x10, 0x1f, 0x7e, 0x0b, 0x48, 0x33, 0x6b, 0x04, 0xc5, 0xaf, 0x30, 0xa1, 0xbd, 0xcb, 0x9c, - 0xbc, 0x09, 0x16, 0x78, 0x6c, 0x31, 0xdf, 0xb3, 0xf6, 0x7d, 0xe2, 0x73, 0xe1, 0x6d, 0xac, 0x64, - 0x29, 0x5c, 0x14, 0x42, 0xd3, 0x55, 0xcd, 0x04, 0x3c, 0xee, 0xfb, 0xde, 0xcb, 0x3c, 0x90, 0x4d, - 0xb0, 0x54, 0x14, 0x8f, 0xb0, 0xe5, 0x50, 0xc6, 0xad, 0x00, 0x87, 0x96, 0x9d, 0x70, 0x3c, 0x99, - 0x42, 0x33, 0x4b, 0xe1, 0xbd, 0x29, 0x8d, 0x9b, 0x30, 0xcd, 0xac, 0xe5, 0x62, 0x47, 0xb8, 0x47, - 0x19, 0xdf, 0xc3, 0xa1, 0x91, 0x70, 0x2c, 0x1f, 0x80, 0x95, 0xdc, 0xed, 0x10, 0x87, 0xfe, 0xbb, - 0x44, 0xe0, 0xb1, 0xbb, 0xbe, 0xb1, 0xd1, 0xd9, 0x14, 0xf3, 0x31, 0xba, 0xe3, 0x14, 0xd6, 0xfb, - 0xbe, 0xf7, 0xba, 0x40, 0xe4, 0xd4, 0x17, 0xcf, 0x8b, 0x7a, 0x96, 0x42, 0x55, 0xb8, 0xfd, 0x41, - 0x40, 0x33, 0xeb, 0xec, 0x1a, 0x4f, 0xa4, 0xe5, 0x04, 0xac, 0xde, 0x64, 0x30, 0xec, 0x04, 0xeb, - 0x1b, 0x4f, 0x86, 0x1d, 0xe5, 0xbf, 0xc2, 0xf4, 0xe9, 0x38, 0x85, 0xcb, 0xd7, 0x4c, 0xfb, 0x17, - 0x88, 0x2c, 0x85, 0xcd, 0xdb, 0x6d, 0x2f, 0x45, 0x34, 0x73, 0x99, 0xdd, 0xca, 0xed, 0xce, 0xe5, - 0xc7, 0x2b, 0x9f, 0xb0, 0xd1, 0x3b, 0x19, 0xab, 0xd2, 0xe9, 0x58, 0x95, 0xbe, 0x8d, 0x55, 0xe9, - 0xd3, 0xb9, 0x5a, 0x3a, 0x3d, 0x57, 0x4b, 0x5f, 0xcf, 0xd5, 0xd2, 0x9b, 0x07, 0x7f, 0x3d, 0x45, - 0xd3, 0x37, 0x82, 0x5d, 0x2d, 0xfe, 0xdd, 0xc7, 0xbf, 0x02, 0x00, 0x00, 0xff, 0xff, 0xce, 0x6d, - 0xf3, 0x2e, 0x28, 0x04, 0x00, 0x00, + // 727 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x54, 0x41, 0x4f, 0xdb, 0x48, + 0x14, 0x8e, 0x49, 0x36, 0xc0, 0xc0, 0xae, 0x36, 0x43, 0x80, 0x10, 0x21, 0x4f, 0xe4, 0xc3, 0x2a, + 0x2b, 0x2d, 0xce, 0x26, 0x2b, 0x56, 0x22, 0x87, 0xd5, 0xe2, 0xec, 0x72, 0xa1, 0x45, 0x68, 0x52, + 0xf5, 0x50, 0xa9, 0xb2, 0x26, 0xf6, 0xe0, 0x58, 0xc1, 0xb1, 0xf1, 0x8c, 0x51, 0xcc, 0xa5, 0xd7, + 0xaa, 0xa7, 0x4a, 0xbd, 0xf4, 0xc8, 0xb9, 0xbf, 0x84, 0x23, 0xc7, 0x9e, 0x4c, 0x15, 0x2e, 0x55, + 0x8f, 0x39, 0xf6, 0x54, 0x8d, 0x27, 0x84, 0x40, 0x43, 0x55, 0xa9, 0x97, 0x64, 0xe6, 0xbd, 0xef, + 0xfb, 0xde, 0xf8, 0xcd, 0xf7, 0x06, 0x94, 0x06, 0x35, 0x12, 0xf1, 0x6e, 0x8d, 0xc7, 0x01, 0x65, + 0xf2, 0x57, 0x0f, 0x42, 0x9f, 0xfb, 0xb0, 0x68, 0xf9, 0xcc, 0xf3, 0x99, 0xc9, 0xec, 0x9e, 0x3e, + 0xd0, 0x05, 0x48, 0x3f, 0xad, 0x97, 0x7f, 0xe3, 0x5d, 0x37, 0xb4, 0xcd, 0x80, 0x84, 0x3c, 0xae, + 0xa5, 0xc0, 0x9a, 0xe3, 0x3b, 0xfe, 0xed, 0x4a, 0xb2, 0xcb, 0x85, 0xaf, 0x04, 0xb5, 0x57, 0x73, + 0x60, 0xc9, 0x20, 0x8c, 0xee, 0x5a, 0x96, 0x1f, 0xf5, 0x39, 0xdc, 0x07, 0xf3, 0xc4, 0xb6, 0x43, + 0xca, 0x58, 0x49, 0xa9, 0x28, 0xd5, 0x65, 0xa3, 0xfe, 0x39, 0x41, 0x5b, 0x8e, 0xcb, 0xbb, 0x51, + 0x47, 0xb7, 0x7c, 0xaf, 0x26, 0x0f, 0x30, 0xfe, 0xdb, 0x62, 0x76, 0x6f, 0x2c, 0xb7, 0x6b, 0x59, + 0xbb, 0x92, 0x88, 0x6f, 0x14, 0xe0, 0x1e, 0x98, 0x0f, 0xa2, 0x8e, 0xd9, 0xa3, 0x71, 0x69, 0x2e, + 0x15, 0xdb, 0xfa, 0x94, 0xa0, 0x62, 0x10, 0x75, 0x8e, 0x5d, 0x4b, 0x44, 0xff, 0xf0, 0x3d, 0x97, + 0x53, 0x2f, 0xe0, 0xf1, 0x28, 0x41, 0x85, 0x98, 0x78, 0xc7, 0x4d, 0xed, 0x36, 0xab, 0xe1, 0x7c, + 0x10, 0x75, 0xf6, 0x69, 0x0c, 0xff, 0x05, 0xbf, 0x10, 0x79, 0x3e, 0xb3, 0x1f, 0x79, 0x1d, 0x1a, + 0x96, 0xb2, 0x15, 0xa5, 0x9a, 0x33, 0x36, 0x46, 0x09, 0x5a, 0x95, 0xb4, 0xbb, 0x79, 0x0d, 0xff, + 0x3c, 0x0e, 0x1c, 0xa4, 0x7b, 0x58, 0x06, 0x0b, 0x8c, 0x9e, 0x44, 0xb4, 0x6f, 0xd1, 0x52, 0x4e, + 0x70, 0xf1, 0x64, 0xdf, 0x5c, 0x78, 0x79, 0x8e, 0x32, 0x6f, 0xcf, 0x51, 0x46, 0x7b, 0x01, 0xf2, + 0x6d, 0x6e, 0xef, 0x51, 0x0a, 0x9f, 0x83, 0x3c, 0xf1, 0x04, 0xbf, 0xa4, 0x54, 0xb2, 0xd5, 0xa5, + 0xc6, 0x8a, 0x3e, 0xd5, 0xf8, 0xd3, 0xba, 0xde, 0xf2, 0xdd, 0xbe, 0xf1, 0xe7, 0x45, 0x82, 0x32, + 0xef, 0xae, 0x50, 0xf5, 0x3b, 0xda, 0x23, 0x08, 0x0c, 0x8f, 0x45, 0xe1, 0xaf, 0x20, 0xeb, 0x10, + 0x96, 0x36, 0x25, 0x87, 0xc5, 0xb2, 0x99, 0xfb, 0x78, 0x8e, 0x14, 0xed, 0x0c, 0x2c, 0xb7, 0xb9, + 0xdd, 0x76, 0x9d, 0x3e, 0xe1, 0x51, 0x48, 0xa7, 0x1b, 0xa8, 0xfc, 0x48, 0x03, 0x37, 0xc1, 0x22, + 0xbb, 0x11, 0x95, 0x57, 0x81, 0x6f, 0x03, 0xcd, 0x9c, 0x68, 0x80, 0x76, 0x95, 0x05, 0xf9, 0x43, + 0x12, 0x12, 0x8f, 0xc1, 0x03, 0xb0, 0xe2, 0x91, 0x81, 0xe9, 0x51, 0xcf, 0x37, 0xad, 0x2e, 0x09, + 0x89, 0xc5, 0x69, 0x28, 0x0d, 0x91, 0x33, 0xd4, 0x51, 0x82, 0xca, 0xb2, 0xd4, 0x0c, 0x90, 0x86, + 0x0b, 0x1e, 0x19, 0x3c, 0xa6, 0x9e, 0xdf, 0x9a, 0xc4, 0xe0, 0x0e, 0x58, 0xe6, 0x03, 0x93, 0xb9, + 0x8e, 0x79, 0xec, 0x7a, 0x2e, 0x97, 0xdf, 0x6d, 0xac, 0x8f, 0x12, 0xb4, 0x22, 0x85, 0xa6, 0xb3, + 0x1a, 0x06, 0x7c, 0xd0, 0x76, 0x9d, 0x47, 0x62, 0x03, 0x31, 0x58, 0x4d, 0x93, 0x67, 0xd4, 0xb4, + 0x7c, 0xc6, 0xcd, 0x80, 0x86, 0x66, 0x27, 0xe6, 0x74, 0xec, 0x80, 0xca, 0x28, 0x41, 0x9b, 0x53, + 0x1a, 0xf7, 0x61, 0x1a, 0x2e, 0x08, 0xb1, 0x33, 0xda, 0xf2, 0x19, 0x3f, 0xa4, 0xa1, 0x11, 0x73, + 0x0a, 0x4f, 0xc0, 0xba, 0xa8, 0x76, 0x4a, 0x43, 0xf7, 0x28, 0x96, 0x78, 0x6a, 0x37, 0xb6, 0xb7, + 0xeb, 0x3b, 0xd2, 0x1b, 0x46, 0x73, 0x98, 0xa0, 0x62, 0xdb, 0x75, 0x9e, 0xa6, 0x08, 0x41, 0xfd, + 0xff, 0xbf, 0x34, 0x3f, 0x4a, 0x90, 0x2a, 0xab, 0x3d, 0x20, 0xa0, 0xe1, 0x22, 0xbb, 0xc3, 0x93, + 0x61, 0x18, 0x83, 0x8d, 0xfb, 0x0c, 0x46, 0xad, 0xa0, 0xb1, 0xfd, 0x77, 0xaf, 0x5e, 0xfa, 0x29, + 0x2d, 0xfa, 0xcf, 0x30, 0x41, 0x6b, 0x77, 0x8a, 0xb6, 0x6f, 0x10, 0xa3, 0x04, 0x55, 0x66, 0x97, + 0x9d, 0x88, 0x68, 0x78, 0x8d, 0xcd, 0xe4, 0x36, 0x17, 0x84, 0xb5, 0x53, 0x77, 0xbd, 0x51, 0xc0, + 0x62, 0x9b, 0xdb, 0x4f, 0x06, 0x62, 0xe0, 0xa1, 0x0e, 0xb2, 0x47, 0x94, 0xa6, 0x97, 0xba, 0xd4, + 0xd8, 0xd4, 0x67, 0x3d, 0x2c, 0xba, 0x9c, 0x06, 0x2c, 0x80, 0xd0, 0x00, 0x60, 0x62, 0x19, 0x61, + 0x5d, 0x31, 0x16, 0xda, 0x83, 0xb4, 0x89, 0x87, 0xf1, 0x14, 0x0b, 0x42, 0x90, 0x13, 0x7e, 0x49, + 0x2f, 0x6f, 0x11, 0xa7, 0x6b, 0xa3, 0x75, 0x31, 0x54, 0x95, 0xcb, 0xa1, 0xaa, 0x7c, 0x18, 0xaa, + 0xca, 0xeb, 0x6b, 0x35, 0x73, 0x79, 0xad, 0x66, 0xde, 0x5f, 0xab, 0x99, 0x67, 0xbf, 0x7f, 0x73, + 0xae, 0xa6, 0xdf, 0xc8, 0x4e, 0x3e, 0x7d, 0xcd, 0xfe, 0xfa, 0x12, 0x00, 0x00, 0xff, 0xff, 0xf4, + 0x66, 0x9d, 0x7a, 0x3a, 0x05, 0x00, 0x00, } func (this *StdFee) Equal(that interface{}) bool { @@ -407,6 +517,43 @@ func (m *StdFee) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *StdSignature) 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 *StdSignature) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StdSignature) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Signature) > 0 { + i -= len(m.Signature) + copy(dAtA[i:], m.Signature) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Signature))) + i-- + dAtA[i] = 0x12 + } + if len(m.PubKey) > 0 { + i -= len(m.PubKey) + copy(dAtA[i:], m.PubKey) + i = encodeVarintTypes(dAtA, i, uint64(len(m.PubKey))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *Params) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -455,6 +602,62 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *StdTxBase) 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 *StdTxBase) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StdTxBase) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Memo) > 0 { + i -= len(m.Memo) + copy(dAtA[i:], m.Memo) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Memo))) + i-- + dAtA[i] = 0x1a + } + if len(m.Signatures) > 0 { + for iNdEx := len(m.Signatures) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Signatures[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if m.Fee != nil { + { + size, err := m.Fee.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintTypes(dAtA []byte, offset int, v uint64) int { offset -= sovTypes(v) base := offset @@ -507,6 +710,23 @@ func (m *StdFee) Size() (n int) { return n } +func (m *StdSignature) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.PubKey) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.Signature) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + func (m *Params) Size() (n int) { if m == nil { return 0 @@ -531,6 +751,29 @@ func (m *Params) Size() (n int) { return n } +func (m *StdTxBase) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Fee != nil { + l = m.Fee.Size() + n += 1 + l + sovTypes(uint64(l)) + } + if len(m.Signatures) > 0 { + for _, e := range m.Signatures { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + l = len(m.Memo) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + func sovTypes(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -802,6 +1045,127 @@ func (m *StdFee) Unmarshal(dAtA []byte) error { } return nil } +func (m *StdSignature) 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 ErrIntOverflowTypes + } + 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: StdSignature: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: StdSignature: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PubKey", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PubKey = append(m.PubKey[:0], dAtA[iNdEx:postIndex]...) + if m.PubKey == nil { + m.PubKey = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Signature", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Signature = append(m.Signature[:0], dAtA[iNdEx:postIndex]...) + if m.Signature == nil { + m.Signature = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *Params) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -950,6 +1314,161 @@ func (m *Params) Unmarshal(dAtA []byte) error { } return nil } +func (m *StdTxBase) 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 ErrIntOverflowTypes + } + 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: StdTxBase: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: StdTxBase: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Fee", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Fee == nil { + m.Fee = &StdFee{} + } + if err := m.Fee.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Signatures", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Signatures = append(m.Signatures, &StdSignature{}) + if err := m.Signatures[len(m.Signatures)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Memo", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Memo = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipTypes(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/auth/types/types.proto b/x/auth/types/types.proto index 60e7a8d8b863..9cc76719ff53 100644 --- a/x/auth/types/types.proto +++ b/x/auth/types/types.proto @@ -30,6 +30,15 @@ message StdFee { uint64 gas = 2; } +// StdSignature defines a signature structure that contains the signature of a +// transaction and an optional public key. +message StdSignature { + option (gogoproto.goproto_getters) = false; + + bytes pub_key = 1 [(gogoproto.jsontag) = "public_key,omitempty", (gogoproto.moretags) = "yaml:\"public_key\""]; + bytes signature = 2; +} + // Params defines the parameters for the auth module. message Params { option (gogoproto.equal) = true; @@ -43,3 +52,11 @@ message Params { uint64 sig_verify_cost_secp256k1 = 5 [(gogoproto.customname) = "SigVerifyCostSecp256k1", (gogoproto.moretags) = "yaml:\"sig_verify_cost_secp256k1\""]; } + +// StdTxBase defines a transaction base which application-level concrete transaction +// types can extend. +message StdTxBase { + StdFee fee = 1; + repeated StdSignature signatures = 2; + string memo = 3; +} From 34f9fc439a5f35922991330918d9c7c563a31c58 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Thu, 12 Mar 2020 13:32:03 -0400 Subject: [PATCH 405/529] Implement canonical signing --- codec/std/codec.pb.go | 450 ++++++++++++---- codec/std/codec.proto | 12 +- codec/std/tx.go | 50 ++ .../adr-020-protobuf-transaction-encoding.md | 3 +- go.mod | 4 +- go.sum | 13 + x/auth/alias.go | 1 + x/auth/types/stdtx.go | 182 ++++--- x/auth/types/types.pb.go | 485 +++++++++++++++--- x/auth/types/types.proto | 14 +- 10 files changed, 935 insertions(+), 279 deletions(-) diff --git a/codec/std/codec.pb.go b/codec/std/codec.pb.go index 13998ffad89a..d5e09db4dc64 100644 --- a/codec/std/codec.pb.go +++ b/codec/std/codec.pb.go @@ -581,8 +581,8 @@ func (*Content) XXX_OneofWrappers() []interface{} { // processed by the state-machine. It contains a base of common fields and // repeated set of Message types. type Transaction struct { - Base *types.StdTxBase `protobuf:"bytes,1,opt,name=base,proto3" json:"base,omitempty"` - Msgs []*Message `protobuf:"bytes,2,rep,name=msgs,proto3" json:"msgs,omitempty"` + Base types.StdTxBase `protobuf:"bytes,1,opt,name=base,proto3" json:"base"` + Msgs []Message `protobuf:"bytes,2,rep,name=msgs,proto3" json:"msgs"` } func (m *Transaction) Reset() { *m = Transaction{} } @@ -902,6 +902,53 @@ func (*Message) XXX_OneofWrappers() []interface{} { } } +// SignDoc defines a standard application-level signing document to compose +// signatures for a Transaction. +type SignDoc struct { + types.StdSignDocBase `protobuf:"bytes,1,opt,name=base,proto3,embedded=base" json:""` + Msgs []Message `protobuf:"bytes,2,rep,name=msgs,proto3" json:"msgs"` +} + +func (m *SignDoc) Reset() { *m = SignDoc{} } +func (m *SignDoc) String() string { return proto.CompactTextString(m) } +func (*SignDoc) ProtoMessage() {} +func (*SignDoc) Descriptor() ([]byte, []int) { + return fileDescriptor_daf09dc2dfa19bb4, []int{9} +} +func (m *SignDoc) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *SignDoc) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_SignDoc.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 *SignDoc) XXX_Merge(src proto.Message) { + xxx_messageInfo_SignDoc.Merge(m, src) +} +func (m *SignDoc) XXX_Size() int { + return m.Size() +} +func (m *SignDoc) XXX_DiscardUnknown() { + xxx_messageInfo_SignDoc.DiscardUnknown(m) +} + +var xxx_messageInfo_SignDoc proto.InternalMessageInfo + +func (m *SignDoc) GetMsgs() []Message { + if m != nil { + return m.Msgs + } + return nil +} + func init() { proto.RegisterType((*Account)(nil), "cosmos_sdk.codec.std.v1.Account") proto.RegisterType((*Supply)(nil), "cosmos_sdk.codec.std.v1.Supply") @@ -912,103 +959,106 @@ func init() { proto.RegisterType((*Content)(nil), "cosmos_sdk.codec.std.v1.Content") proto.RegisterType((*Transaction)(nil), "cosmos_sdk.codec.std.v1.Transaction") proto.RegisterType((*Message)(nil), "cosmos_sdk.codec.std.v1.Message") + proto.RegisterType((*SignDoc)(nil), "cosmos_sdk.codec.std.v1.SignDoc") } func init() { proto.RegisterFile("codec/std/codec.proto", fileDescriptor_daf09dc2dfa19bb4) } var fileDescriptor_daf09dc2dfa19bb4 = []byte{ - // 1443 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x58, 0xcf, 0x6f, 0xd4, 0xc6, - 0x17, 0xf7, 0xc2, 0x92, 0x2c, 0x93, 0x00, 0x61, 0xbe, 0xf0, 0x8d, 0x95, 0xc2, 0x26, 0x84, 0x16, - 0xb5, 0xa0, 0xac, 0x81, 0xd0, 0x02, 0xab, 0x56, 0xc0, 0x26, 0xa0, 0xa5, 0x6a, 0x5a, 0xe4, 0x40, - 0xaa, 0x56, 0xb4, 0xd6, 0xac, 0x67, 0x70, 0xdc, 0xac, 0x3d, 0xae, 0x67, 0xbc, 0xd9, 0x1c, 0xda, - 0x73, 0xdb, 0x53, 0xa5, 0xfe, 0x03, 0xa8, 0x3d, 0xf6, 0xca, 0xb1, 0xe7, 0x0a, 0x71, 0xe2, 0xd8, - 0x13, 0xaa, 0xe0, 0xd2, 0x3f, 0xa3, 0x9a, 0x1f, 0xf6, 0xda, 0xbb, 0xde, 0x4d, 0x7a, 0x89, 0x3c, - 0x33, 0xef, 0xf3, 0x63, 0x3c, 0xef, 0xcd, 0xf3, 0x06, 0x9c, 0x76, 0x29, 0x26, 0xae, 0xc5, 0x38, - 0xb6, 0xe4, 0x53, 0x23, 0x8a, 0x29, 0xa7, 0x70, 0xde, 0xa5, 0x2c, 0xa0, 0xcc, 0x61, 0x78, 0xa7, - 0xa1, 0xe6, 0x19, 0xc7, 0x8d, 0xde, 0x95, 0x85, 0x4b, 0x7c, 0xdb, 0x8f, 0xb1, 0x13, 0xa1, 0x98, - 0xef, 0x59, 0x32, 0xd6, 0x52, 0xa1, 0x2b, 0xf9, 0x81, 0x62, 0x59, 0xb8, 0x30, 0x1a, 0xec, 0x51, - 0x8f, 0x0e, 0x9e, 0x74, 0x9c, 0xd9, 0xb7, 0x50, 0xc2, 0xb7, 0x2d, 0xbe, 0x17, 0x11, 0xa6, 0xfe, - 0xea, 0x95, 0x25, 0xbd, 0xd2, 0x23, 0x8c, 0xfb, 0xa1, 0x57, 0x12, 0x61, 0xf6, 0xad, 0x0e, 0x0a, - 0x77, 0x4a, 0x56, 0x16, 0xfa, 0x96, 0x1b, 0xfb, 0xcc, 0x67, 0xe5, 0xbc, 0xd8, 0x67, 0x3c, 0xf6, - 0x3b, 0x09, 0xf7, 0x69, 0x58, 0x8e, 0x66, 0x49, 0x14, 0x75, 0xf7, 0x4a, 0xd6, 0xce, 0xf4, 0x2d, - 0xd2, 0xf3, 0x31, 0x09, 0x5d, 0x52, 0xb2, 0x3a, 0xdf, 0xb7, 0x3c, 0xda, 0x2b, 0x87, 0xb1, 0x2e, - 0x62, 0xdb, 0xe5, 0x1b, 0x79, 0xab, 0x6f, 0x31, 0x8e, 0x76, 0xca, 0x17, 0xcf, 0xf7, 0xad, 0x08, - 0xc5, 0x28, 0x48, 0xf7, 0x12, 0xc5, 0x34, 0xa2, 0x0c, 0x75, 0x87, 0x19, 0x92, 0xc8, 0x8b, 0x11, - 0x2e, 0x71, 0xb5, 0xfc, 0x47, 0x15, 0x4c, 0xdf, 0x71, 0x5d, 0x9a, 0x84, 0x1c, 0xde, 0x03, 0xb3, - 0x1d, 0xc4, 0x88, 0x83, 0xd4, 0xd8, 0xac, 0x2c, 0x55, 0xde, 0x9d, 0xb9, 0x7a, 0xae, 0x91, 0x3b, - 0xf4, 0x7e, 0x43, 0xbc, 0xf7, 0x46, 0xef, 0x4a, 0xa3, 0x85, 0x18, 0xd1, 0xc0, 0xb6, 0x61, 0xcf, - 0x74, 0x06, 0x43, 0xd8, 0x03, 0x0b, 0x2e, 0x0d, 0xb9, 0x1f, 0x26, 0x34, 0x61, 0x8e, 0x3e, 0xa3, - 0x8c, 0xf5, 0x90, 0x64, 0xfd, 0xa0, 0x8c, 0x55, 0x45, 0x0a, 0xf6, 0xb5, 0x0c, 0xbf, 0xa5, 0x26, - 0x07, 0x52, 0xa6, 0x3b, 0x66, 0x0d, 0x06, 0x60, 0x1e, 0x93, 0x2e, 0xda, 0x23, 0x78, 0x44, 0xf4, - 0xb0, 0x14, 0x5d, 0x9d, 0x2c, 0xba, 0xae, 0xc0, 0x23, 0x8a, 0xa7, 0x71, 0xd9, 0x02, 0x8c, 0x80, - 0x19, 0x91, 0xd8, 0xa7, 0xd8, 0x77, 0x47, 0xf4, 0xaa, 0x52, 0xef, 0xda, 0x64, 0xbd, 0x07, 0x1a, - 0x3d, 0x22, 0xf8, 0xff, 0xa8, 0x74, 0x05, 0x7e, 0x0a, 0x8e, 0x07, 0x14, 0x27, 0xdd, 0xc1, 0x11, - 0x1d, 0x91, 0x3a, 0xef, 0x14, 0x75, 0x54, 0x82, 0x0a, 0x85, 0x0d, 0x19, 0x3d, 0x20, 0x3e, 0x16, - 0xe4, 0x27, 0x9a, 0x37, 0x5f, 0x3c, 0x5b, 0x79, 0xff, 0xa2, 0xe7, 0xf3, 0xed, 0xa4, 0xd3, 0x70, - 0x69, 0xa0, 0xcb, 0x34, 0x2d, 0x5d, 0x86, 0x77, 0x2c, 0x5d, 0x68, 0xa4, 0x1f, 0xd1, 0x98, 0x13, - 0xdc, 0xd0, 0xd0, 0xd6, 0x11, 0x70, 0x98, 0x25, 0xc1, 0xf2, 0x4f, 0x15, 0x30, 0xb5, 0x29, 0xe5, - 0xe0, 0x0d, 0x30, 0xa5, 0x84, 0x75, 0xde, 0xd4, 0xc7, 0x99, 0x52, 0xf1, 0x6d, 0xc3, 0xd6, 0xf1, - 0xcd, 0x5b, 0xff, 0x3c, 0x5d, 0xac, 0xbc, 0x78, 0xb6, 0x72, 0x7d, 0x3f, 0x2b, 0xba, 0xf2, 0x32, - 0x33, 0x8a, 0xe9, 0x7e, 0x6a, 0xe6, 0xd7, 0x0a, 0xa8, 0xdd, 0xd5, 0x05, 0x08, 0x3f, 0x01, 0xb3, - 0xe4, 0xdb, 0xc4, 0xef, 0x51, 0x17, 0x89, 0x52, 0xd6, 0xa6, 0x2e, 0x14, 0x4d, 0xa5, 0xe5, 0x2a, - 0x6c, 0xdd, 0xcd, 0x45, 0xb7, 0x0d, 0xbb, 0x80, 0x6e, 0xde, 0xd1, 0x16, 0x6f, 0xee, 0xe3, 0x30, - 0xab, 0xff, 0xcc, 0x63, 0x6a, 0x28, 0x35, 0xf9, 0x7b, 0x05, 0x9c, 0xdc, 0x60, 0xde, 0x66, 0xd2, - 0x09, 0x7c, 0x9e, 0xb9, 0xfd, 0x08, 0xd4, 0x52, 0x68, 0x59, 0xd9, 0xe5, 0xef, 0xda, 0x8c, 0xd1, - 0xce, 0x20, 0x70, 0x03, 0x54, 0x45, 0x01, 0xea, 0xda, 0xb2, 0xc6, 0x6f, 0x72, 0x44, 0x59, 0x94, - 0x71, 0xab, 0xf6, 0xfc, 0xd5, 0xa2, 0xf1, 0xf2, 0xd5, 0x62, 0xc5, 0x96, 0x34, 0xcd, 0xda, 0x0f, - 0x4f, 0x17, 0x0d, 0xb1, 0xe3, 0xe5, 0xdf, 0xf2, 0x6e, 0x1f, 0xe8, 0xdb, 0x05, 0xb6, 0xb5, 0x9c, - 0x72, 0x7a, 0xb1, 0x28, 0xe7, 0xd1, 0x5e, 0x41, 0x29, 0x45, 0x95, 0x29, 0xc1, 0x26, 0x98, 0x16, - 0xe5, 0x4c, 0xb2, 0x7b, 0x61, 0x69, 0xec, 0xb6, 0xd7, 0x54, 0x9c, 0x9d, 0x02, 0x72, 0x2e, 0x7f, - 0xa9, 0x80, 0x5a, 0x66, 0xee, 0x56, 0xc1, 0xdc, 0xb9, 0x52, 0x73, 0x13, 0x3d, 0xdd, 0xfe, 0xcf, - 0x9e, 0x5a, 0x55, 0x41, 0x31, 0x70, 0x56, 0x95, 0xae, 0x9e, 0x56, 0xc1, 0xb4, 0x0e, 0x80, 0xd7, - 0x41, 0x95, 0x93, 0x3e, 0x9f, 0x68, 0xea, 0x21, 0xe9, 0x67, 0x2f, 0xab, 0x6d, 0xd8, 0x12, 0x00, - 0x1f, 0x83, 0x39, 0x79, 0xc3, 0x13, 0x4e, 0x62, 0xc7, 0xdd, 0x46, 0xa1, 0x37, 0xe6, 0x94, 0x55, - 0x1f, 0x90, 0x9b, 0x4b, 0xe3, 0xd7, 0x64, 0x78, 0x8e, 0xf2, 0x44, 0x54, 0x5c, 0x82, 0x5f, 0x81, - 0x39, 0x46, 0x9f, 0xf0, 0x5d, 0x14, 0x13, 0x47, 0xf7, 0x08, 0x7d, 0x55, 0x5e, 0x2e, 0xb2, 0xeb, - 0x45, 0x59, 0xbe, 0x1a, 0xf0, 0x48, 0x4d, 0xe5, 0xe9, 0x59, 0x71, 0x09, 0x46, 0x60, 0xde, 0x45, - 0xa1, 0x4b, 0xba, 0xce, 0x88, 0x4a, 0xb5, 0xac, 0x0b, 0xe4, 0x54, 0xd6, 0x24, 0x6e, 0xbc, 0xd6, - 0x69, 0xb7, 0x2c, 0x00, 0x76, 0xc1, 0x29, 0x97, 0x06, 0x41, 0x12, 0xfa, 0x7c, 0xcf, 0x89, 0x28, - 0xed, 0x3a, 0x2c, 0x22, 0x21, 0xd6, 0xf7, 0xe4, 0x8d, 0xa2, 0x5c, 0xbe, 0xd5, 0xab, 0xd3, 0xd4, - 0xc8, 0x07, 0x94, 0x76, 0x37, 0x05, 0x2e, 0x27, 0x08, 0xdd, 0x91, 0xd5, 0xe6, 0x0d, 0x7d, 0x2b, - 0x5c, 0xde, 0xe7, 0x56, 0xc8, 0xfa, 0x7e, 0x96, 0x30, 0xfa, 0x32, 0xf8, 0x1e, 0xcc, 0x3c, 0x8c, - 0x51, 0xc8, 0x90, 0x2b, 0x3c, 0xc0, 0xd5, 0x42, 0xea, 0x2e, 0x96, 0x37, 0xde, 0x4d, 0x8e, 0x1f, - 0xf6, 0x45, 0xe2, 0xea, 0x74, 0xbd, 0x06, 0xaa, 0x01, 0xf3, 0x98, 0x79, 0x68, 0xe9, 0xf0, 0xc4, - 0x5c, 0xdd, 0x20, 0x8c, 0x21, 0x8f, 0xd8, 0x32, 0xba, 0x59, 0x15, 0xc5, 0xb3, 0xfc, 0xe7, 0x2c, - 0x98, 0xd6, 0xf3, 0xb0, 0x09, 0x6a, 0x01, 0xf3, 0x1c, 0x26, 0x5e, 0x97, 0x32, 0x70, 0xb6, 0x68, - 0x40, 0x7c, 0x4f, 0xa5, 0x95, 0x4d, 0x42, 0xdc, 0x36, 0xec, 0xe9, 0x40, 0x3d, 0xc2, 0x8f, 0xc1, - 0x71, 0x81, 0x0d, 0x92, 0x2e, 0xf7, 0x15, 0x83, 0xca, 0xd1, 0xe5, 0xb1, 0x0c, 0x1b, 0x22, 0x54, - 0xd3, 0xcc, 0x06, 0xb9, 0x31, 0xfc, 0x1a, 0x9c, 0x12, 0x5c, 0x3d, 0x12, 0xfb, 0x4f, 0xf6, 0x1c, - 0x3f, 0xec, 0xa1, 0xd8, 0x47, 0x59, 0x0b, 0x1f, 0xba, 0x6c, 0xd4, 0x97, 0x9c, 0xe6, 0xdc, 0x92, - 0x90, 0xfb, 0x29, 0x42, 0x1c, 0x5a, 0x30, 0x32, 0x0b, 0x43, 0x60, 0xaa, 0x7d, 0x72, 0x67, 0xd7, - 0xe7, 0xdb, 0x38, 0x46, 0xbb, 0x0e, 0xc2, 0x38, 0x26, 0x8c, 0xe9, 0xac, 0x5c, 0x9d, 0x9c, 0x26, - 0x72, 0xff, 0xfc, 0x73, 0x8d, 0xbd, 0xa3, 0xa0, 0x22, 0x25, 0x83, 0xb2, 0x05, 0xf8, 0x1d, 0x38, - 0x2b, 0xf4, 0x32, 0x2d, 0x4c, 0xba, 0xc4, 0x43, 0x9c, 0xc6, 0x4e, 0x4c, 0x76, 0x51, 0x7c, 0xc0, - 0xdc, 0xdc, 0x60, 0x5e, 0x4a, 0xbc, 0x9e, 0x12, 0xd8, 0x12, 0xdf, 0x36, 0xec, 0x85, 0x60, 0xec, - 0x2a, 0xfc, 0xb1, 0x02, 0xce, 0x15, 0xf4, 0x7b, 0xa8, 0xeb, 0x63, 0xa9, 0x2f, 0x32, 0xda, 0x67, - 0x4c, 0x74, 0xc7, 0x29, 0xe9, 0xe1, 0xc3, 0x03, 0x7b, 0xd8, 0x4a, 0x49, 0xd6, 0x32, 0x8e, 0xb6, - 0x61, 0xd7, 0x83, 0x89, 0x11, 0x70, 0x07, 0xcc, 0x0b, 0x2b, 0x4f, 0x92, 0x10, 0x3b, 0xc5, 0x32, - 0x35, 0xa7, 0xa5, 0x81, 0xab, 0xfb, 0x1a, 0xb8, 0x97, 0x84, 0xb8, 0x50, 0xa7, 0x6d, 0xc3, 0x16, - 0xf9, 0x32, 0x32, 0x0f, 0x1f, 0x83, 0xff, 0xc9, 0x73, 0x96, 0x4d, 0xc8, 0xc9, 0xba, 0x6b, 0x6d, - 0x34, 0x8d, 0x8a, 0x65, 0x32, 0xdc, 0x21, 0xdb, 0x86, 0x7d, 0x32, 0x18, 0x69, 0xd8, 0x45, 0xf6, - 0xf4, 0xbb, 0xdb, 0x3c, 0x7a, 0x50, 0xf6, 0xdc, 0xcd, 0x32, 0x60, 0xcf, 0x7a, 0xd8, 0x4d, 0x55, - 0x8b, 0x3d, 0xca, 0x89, 0x09, 0x24, 0xe5, 0x99, 0x71, 0x4d, 0x76, 0x8b, 0x72, 0xa2, 0x4b, 0x51, - 0x3c, 0xc2, 0x16, 0x98, 0x11, 0x50, 0x4c, 0x22, 0xca, 0x7c, 0x6e, 0xce, 0x94, 0x5d, 0x25, 0x03, - 0xf4, 0xba, 0x0a, 0x6b, 0x1b, 0x36, 0x08, 0xb2, 0x11, 0x5c, 0x07, 0x62, 0xe4, 0x24, 0xe1, 0x37, - 0xc8, 0xef, 0x9a, 0xb3, 0x92, 0xe2, 0xfc, 0xd0, 0xe7, 0x9c, 0xfe, 0xc5, 0xa2, 0x79, 0x1e, 0xc9, - 0xd0, 0xb6, 0x61, 0x1f, 0x0d, 0xd2, 0x01, 0x74, 0x54, 0x21, 0xbb, 0x31, 0x41, 0x9c, 0x0c, 0xd2, - 0xce, 0x3c, 0x26, 0xf9, 0x2e, 0x0d, 0xf1, 0xa9, 0xdf, 0x38, 0x9a, 0x6e, 0x4d, 0x62, 0xb2, 0x14, - 0xd2, 0x95, 0x3c, 0x34, 0x0b, 0xbf, 0x00, 0x62, 0xd6, 0x21, 0xd8, 0xe7, 0x39, 0xfa, 0xe3, 0x92, - 0xfe, 0xbd, 0x49, 0xf4, 0x77, 0xb1, 0xcf, 0xf3, 0xe4, 0x73, 0xc1, 0xd0, 0x1c, 0xbc, 0x0f, 0x66, - 0xd5, 0x5b, 0x94, 0xc5, 0x44, 0xcc, 0x13, 0x92, 0xf4, 0xed, 0x49, 0xa4, 0xba, 0xf0, 0xc4, 0x61, - 0xcc, 0x04, 0x83, 0x61, 0xfa, 0x1a, 0x3a, 0xc4, 0xf3, 0x43, 0x27, 0x26, 0x19, 0xe5, 0xdc, 0xfe, - 0xaf, 0xa1, 0x25, 0x30, 0x76, 0x06, 0xd1, 0xaf, 0x61, 0x68, 0x16, 0x7e, 0xa6, 0x2e, 0xdf, 0x24, - 0xcc, 0xa8, 0x4f, 0x96, 0x7d, 0xeb, 0x16, 0xa9, 0x1f, 0x85, 0x39, 0xd6, 0x63, 0x41, 0x7e, 0xa2, - 0x79, 0xf1, 0xc5, 0xb3, 0x95, 0x0b, 0x13, 0x5b, 0x9a, 0x6a, 0x66, 0xc2, 0xa1, 0x6a, 0x64, 0xad, - 0xdb, 0xcf, 0x5f, 0xd7, 0x2b, 0x2f, 0x5f, 0xd7, 0x2b, 0x7f, 0xbf, 0xae, 0x57, 0x7e, 0x7e, 0x53, - 0x37, 0x5e, 0xbe, 0xa9, 0x1b, 0x7f, 0xbd, 0xa9, 0x1b, 0x5f, 0x4e, 0x26, 0xca, 0xfe, 0xcd, 0xd0, - 0x99, 0x92, 0xbf, 0x47, 0x57, 0xff, 0x0d, 0x00, 0x00, 0xff, 0xff, 0xed, 0xa0, 0xda, 0x1d, 0x7a, - 0x10, 0x00, 0x00, + // 1476 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x58, 0xcd, 0x6f, 0xd4, 0xc6, + 0x1b, 0xf6, 0xc2, 0x92, 0x84, 0x49, 0x80, 0x30, 0x3f, 0xf8, 0x65, 0x95, 0xc2, 0x26, 0x04, 0x8a, + 0x5a, 0x50, 0xd6, 0x7c, 0xb4, 0x85, 0xac, 0x5a, 0x01, 0x49, 0x40, 0x4b, 0xd5, 0xb4, 0xc8, 0x81, + 0x54, 0xad, 0x68, 0xad, 0x59, 0xcf, 0xe0, 0x4c, 0xb3, 0xf6, 0xb8, 0x9e, 0xf1, 0x66, 0x73, 0xe8, + 0xbd, 0xad, 0x54, 0xa9, 0x52, 0xff, 0x01, 0xd4, 0x1e, 0x7b, 0xe5, 0xd8, 0x73, 0x85, 0x38, 0x71, + 0xec, 0x09, 0x55, 0x70, 0xa9, 0xfa, 0x57, 0x54, 0xf3, 0x61, 0xaf, 0xbd, 0xeb, 0xdd, 0x50, 0xa9, + 0x97, 0xc8, 0x33, 0xef, 0xfb, 0x3c, 0xef, 0x33, 0x9e, 0xf7, 0xc3, 0x1b, 0x70, 0xd2, 0x63, 0x98, + 0x78, 0x36, 0x17, 0xd8, 0x56, 0x4f, 0x8d, 0x28, 0x66, 0x82, 0xc1, 0x39, 0x8f, 0xf1, 0x80, 0x71, + 0x97, 0xe3, 0x9d, 0x86, 0xde, 0xe7, 0x02, 0x37, 0xba, 0x97, 0xe7, 0x2f, 0x8a, 0x6d, 0x1a, 0x63, + 0x37, 0x42, 0xb1, 0xd8, 0xb3, 0x95, 0xaf, 0xad, 0x5d, 0x97, 0xf3, 0x0b, 0xcd, 0x32, 0x7f, 0x7e, + 0xd8, 0xd9, 0x67, 0x3e, 0xeb, 0x3f, 0x19, 0xbf, 0x5a, 0xcf, 0x46, 0x89, 0xd8, 0xb6, 0xc5, 0x5e, + 0x44, 0xb8, 0xfe, 0x6b, 0x2c, 0x8b, 0xc6, 0xd2, 0x25, 0x5c, 0xd0, 0xd0, 0x2f, 0xf1, 0xa8, 0xf5, + 0xec, 0x36, 0x0a, 0x77, 0x4a, 0x2c, 0xf3, 0x3d, 0xdb, 0x8b, 0x29, 0xa7, 0xbc, 0x9c, 0x17, 0x53, + 0x2e, 0x62, 0xda, 0x4e, 0x04, 0x65, 0x61, 0x39, 0x9a, 0x27, 0x51, 0xd4, 0xd9, 0x2b, 0xb1, 0x9d, + 0xea, 0xd9, 0xa4, 0x4b, 0x31, 0x09, 0x3d, 0x52, 0x62, 0x9d, 0xeb, 0xd9, 0x3e, 0xeb, 0x96, 0xc3, + 0x78, 0x07, 0xf1, 0xed, 0xf2, 0x83, 0xbc, 0xd1, 0xb3, 0xb9, 0x40, 0x3b, 0xe5, 0xc6, 0xb3, 0x3d, + 0x3b, 0x42, 0x31, 0x0a, 0xd2, 0xb3, 0x44, 0x31, 0x8b, 0x18, 0x47, 0x9d, 0x41, 0x86, 0x24, 0xf2, + 0x63, 0x84, 0x4b, 0x54, 0x2d, 0xfd, 0x56, 0x05, 0x93, 0xb7, 0x3c, 0x8f, 0x25, 0xa1, 0x80, 0x77, + 0xc0, 0x4c, 0x1b, 0x71, 0xe2, 0x22, 0xbd, 0xae, 0x55, 0x16, 0x2b, 0x6f, 0x4d, 0x5f, 0x39, 0xd3, + 0xc8, 0x5d, 0x7a, 0xaf, 0x21, 0xdf, 0x7b, 0xa3, 0x7b, 0xb9, 0xb1, 0x8a, 0x38, 0x31, 0xc0, 0x96, + 0xe5, 0x4c, 0xb7, 0xfb, 0x4b, 0xd8, 0x05, 0xf3, 0x1e, 0x0b, 0x05, 0x0d, 0x13, 0x96, 0x70, 0xd7, + 0xdc, 0x51, 0xc6, 0x7a, 0x40, 0xb1, 0xbe, 0x57, 0xc6, 0xaa, 0x3d, 0x25, 0xfb, 0x5a, 0x86, 0xdf, + 0xd2, 0x9b, 0xfd, 0x50, 0x35, 0x6f, 0x84, 0x0d, 0x06, 0x60, 0x0e, 0x93, 0x0e, 0xda, 0x23, 0x78, + 0x28, 0xe8, 0x41, 0x15, 0xf4, 0xea, 0xf8, 0xa0, 0xeb, 0x1a, 0x3c, 0x14, 0xf1, 0x24, 0x2e, 0x33, + 0xc0, 0x08, 0xd4, 0x22, 0x12, 0x53, 0x86, 0xa9, 0x37, 0x14, 0xaf, 0xaa, 0xe2, 0xbd, 0x33, 0x3e, + 0xde, 0x3d, 0x83, 0x1e, 0x0a, 0xf8, 0xff, 0xa8, 0xd4, 0x02, 0x3f, 0x06, 0x47, 0x03, 0x86, 0x93, + 0x4e, 0xff, 0x8a, 0x0e, 0xa9, 0x38, 0x6f, 0x16, 0xe3, 0xe8, 0x04, 0x95, 0x11, 0x36, 0x94, 0x77, + 0x9f, 0xf8, 0x48, 0x90, 0xdf, 0x68, 0xae, 0x3c, 0x7b, 0xb2, 0xfc, 0xee, 0x05, 0x9f, 0x8a, 0xed, + 0xa4, 0xdd, 0xf0, 0x58, 0x60, 0xca, 0x34, 0x2d, 0x5d, 0x8e, 0x77, 0x6c, 0x53, 0x68, 0xa4, 0x17, + 0xb1, 0x58, 0x10, 0xdc, 0x30, 0xd0, 0xd5, 0x43, 0xe0, 0x20, 0x4f, 0x82, 0xa5, 0xef, 0x2b, 0x60, + 0x62, 0x53, 0x85, 0x83, 0xd7, 0xc1, 0x84, 0x0e, 0x6c, 0xf2, 0xa6, 0x3e, 0x4a, 0x94, 0xf6, 0x6f, + 0x59, 0x8e, 0xf1, 0x6f, 0xde, 0xf8, 0xeb, 0xf1, 0x42, 0xe5, 0xd9, 0x93, 0xe5, 0x6b, 0xfb, 0x49, + 0x31, 0x95, 0x97, 0x89, 0xd1, 0x4c, 0x77, 0x53, 0x31, 0x3f, 0x57, 0xc0, 0xd4, 0x6d, 0x53, 0x80, + 0xf0, 0x23, 0x30, 0x43, 0xbe, 0x4e, 0x68, 0x97, 0x79, 0x48, 0x96, 0xb2, 0x11, 0x75, 0xbe, 0x28, + 0x2a, 0x2d, 0x57, 0x29, 0xeb, 0x76, 0xce, 0xbb, 0x65, 0x39, 0x05, 0x74, 0xf3, 0x96, 0x91, 0xb8, + 0xb2, 0x8f, 0xc2, 0xac, 0xfe, 0x33, 0x8d, 0xa9, 0xa0, 0x54, 0xe4, 0xaf, 0x15, 0x70, 0x7c, 0x83, + 0xfb, 0x9b, 0x49, 0x3b, 0xa0, 0x22, 0x53, 0xfb, 0x01, 0x98, 0x4a, 0xa1, 0x65, 0x65, 0x97, 0xef, + 0xb5, 0x19, 0xa3, 0x93, 0x41, 0xe0, 0x06, 0xa8, 0xca, 0x02, 0x34, 0xb5, 0x65, 0x8f, 0x3e, 0xe4, + 0x50, 0x64, 0x59, 0xc6, 0xab, 0x53, 0x4f, 0x5f, 0x2c, 0x58, 0xcf, 0x5f, 0x2c, 0x54, 0x1c, 0x45, + 0xd3, 0x9c, 0xfa, 0xf6, 0xf1, 0x82, 0x25, 0x4f, 0xbc, 0xf4, 0x4b, 0x5e, 0xed, 0x3d, 0xd3, 0x5d, + 0x60, 0xcb, 0x84, 0xd3, 0x4a, 0x2f, 0x14, 0xc3, 0xf9, 0xac, 0x5b, 0x88, 0x94, 0xa2, 0xca, 0x22, + 0xc1, 0x26, 0x98, 0x94, 0xe5, 0x4c, 0xb2, 0xbe, 0xb0, 0x38, 0xf2, 0xd8, 0x6b, 0xda, 0xcf, 0x49, + 0x01, 0x39, 0x95, 0x3f, 0x55, 0xc0, 0x54, 0x26, 0xee, 0x46, 0x41, 0xdc, 0x99, 0x52, 0x71, 0x63, + 0x35, 0xdd, 0xfc, 0xd7, 0x9a, 0x56, 0xab, 0x92, 0xa2, 0xaf, 0xac, 0xaa, 0x54, 0x3d, 0xae, 0x82, + 0x49, 0xe3, 0x00, 0xaf, 0x81, 0xaa, 0x20, 0x3d, 0x31, 0x56, 0xd4, 0x7d, 0xd2, 0xcb, 0x5e, 0x56, + 0xcb, 0x72, 0x14, 0x00, 0x3e, 0x04, 0xb3, 0xaa, 0xc3, 0x13, 0x41, 0x62, 0xd7, 0xdb, 0x46, 0xa1, + 0x3f, 0xe2, 0x96, 0xf5, 0x1c, 0x50, 0x87, 0x4b, 0xfd, 0xd7, 0x94, 0x7b, 0x8e, 0xf2, 0x58, 0x54, + 0x34, 0xc1, 0x2f, 0xc0, 0x2c, 0x67, 0x8f, 0xc4, 0x2e, 0x8a, 0x89, 0x6b, 0x66, 0x84, 0x69, 0x95, + 0x97, 0x8a, 0xec, 0xc6, 0xa8, 0xca, 0xd7, 0x00, 0x1e, 0xe8, 0xad, 0x3c, 0x3d, 0x2f, 0x9a, 0x60, + 0x04, 0xe6, 0x3c, 0x14, 0x7a, 0xa4, 0xe3, 0x0e, 0x45, 0xa9, 0x96, 0x4d, 0x81, 0x5c, 0x94, 0x35, + 0x85, 0x1b, 0x1d, 0xeb, 0xa4, 0x57, 0xe6, 0x00, 0x3b, 0xe0, 0x84, 0xc7, 0x82, 0x20, 0x09, 0xa9, + 0xd8, 0x73, 0x23, 0xc6, 0x3a, 0x2e, 0x8f, 0x48, 0x88, 0x4d, 0x9f, 0xbc, 0x5e, 0x0c, 0x97, 0x1f, + 0xf5, 0xfa, 0x36, 0x0d, 0xf2, 0x1e, 0x63, 0x9d, 0x4d, 0x89, 0xcb, 0x05, 0x84, 0xde, 0x90, 0xb5, + 0x79, 0xdd, 0x74, 0x85, 0x4b, 0xfb, 0x74, 0x85, 0x6c, 0xee, 0x67, 0x09, 0xd3, 0x6f, 0x9f, 0xd3, + 0xf7, 0x63, 0x14, 0x72, 0xe4, 0x49, 0x11, 0x70, 0xa5, 0x90, 0xbb, 0x0b, 0xe5, 0x93, 0x77, 0x53, + 0xe0, 0xfb, 0x3d, 0x95, 0xb9, 0x3a, 0xed, 0xd2, 0x4a, 0xaa, 0x06, 0xdc, 0xe7, 0xb5, 0x03, 0x8b, + 0x07, 0xc7, 0xa6, 0xec, 0x06, 0xe1, 0x1c, 0xf9, 0x19, 0x56, 0x62, 0x9a, 0x55, 0x59, 0x49, 0x4b, + 0xbf, 0xcf, 0x80, 0x49, 0x63, 0x85, 0x4d, 0x30, 0x15, 0x70, 0xdf, 0xe5, 0xf2, 0xdd, 0x69, 0x31, + 0xa7, 0x8b, 0x62, 0xe4, 0xc7, 0x55, 0x5a, 0xe6, 0x24, 0xc4, 0x2d, 0xcb, 0x99, 0x0c, 0xf4, 0x23, + 0xfc, 0x10, 0x1c, 0x95, 0xd8, 0x20, 0xe9, 0x08, 0xaa, 0x19, 0x74, 0xc2, 0x2e, 0x8d, 0x64, 0xd8, + 0x90, 0xae, 0x86, 0x66, 0x26, 0xc8, 0xad, 0xe1, 0x97, 0xe0, 0x84, 0xe4, 0xea, 0x92, 0x98, 0x3e, + 0xda, 0x73, 0x69, 0xd8, 0x45, 0x31, 0x45, 0xd9, 0x3c, 0x1f, 0xe8, 0x3c, 0xfa, 0xb3, 0xce, 0x70, + 0x6e, 0x29, 0xc8, 0xdd, 0x14, 0x21, 0x6f, 0x30, 0x18, 0xda, 0x85, 0x21, 0xa8, 0xe9, 0x73, 0x0a, + 0x77, 0x97, 0x8a, 0x6d, 0x1c, 0xa3, 0x5d, 0x17, 0x61, 0x1c, 0x13, 0xce, 0x4d, 0x8a, 0x5e, 0x1d, + 0x9f, 0x33, 0xea, 0xfc, 0xe2, 0x53, 0x83, 0xbd, 0xa5, 0xa1, 0x32, 0x3f, 0x83, 0x32, 0x03, 0xfc, + 0x06, 0x9c, 0x96, 0xf1, 0xb2, 0x58, 0x98, 0x74, 0x88, 0x8f, 0x04, 0x8b, 0xdd, 0x98, 0xec, 0xa2, + 0xf8, 0x35, 0x13, 0x75, 0x83, 0xfb, 0x29, 0xf1, 0x7a, 0x4a, 0xe0, 0x28, 0x7c, 0xcb, 0x72, 0xe6, + 0x83, 0x91, 0x56, 0xf8, 0x5d, 0x05, 0x9c, 0x29, 0xc4, 0xef, 0xa2, 0x0e, 0xc5, 0x2a, 0xbe, 0x4c, + 0x6f, 0xca, 0xb9, 0x1c, 0x95, 0x13, 0x4a, 0xc3, 0xfb, 0xaf, 0xad, 0x61, 0x2b, 0x25, 0x59, 0xcb, + 0x38, 0x5a, 0x96, 0x53, 0x0f, 0xc6, 0x7a, 0xc0, 0x1d, 0x30, 0x27, 0xa5, 0x3c, 0x4a, 0x42, 0xec, + 0x16, 0x6b, 0xb6, 0x36, 0xa9, 0x04, 0x5c, 0xd9, 0x57, 0xc0, 0x9d, 0x24, 0xc4, 0x85, 0xa2, 0x6d, + 0x59, 0x8e, 0xcc, 0x97, 0xa1, 0x7d, 0xf8, 0x10, 0xfc, 0x4f, 0xdd, 0xb3, 0x9a, 0x48, 0x6e, 0x36, + 0x6a, 0xa7, 0x86, 0xd3, 0xa8, 0x58, 0x2c, 0x83, 0xe3, 0xb2, 0x65, 0x39, 0xc7, 0x83, 0xa1, 0xe9, + 0x5d, 0x64, 0x4f, 0x3f, 0xc2, 0x6b, 0x87, 0x5f, 0x97, 0x3d, 0xd7, 0x66, 0xfa, 0xec, 0xd9, 0x40, + 0x5b, 0xd1, 0xb5, 0xd8, 0x65, 0x82, 0xd4, 0x80, 0xa2, 0x3c, 0x35, 0x6a, 0xe2, 0x6e, 0x31, 0x41, + 0x4c, 0x29, 0xca, 0x47, 0xb8, 0x0a, 0xa6, 0x25, 0x14, 0x93, 0x88, 0x71, 0x2a, 0x6a, 0xd3, 0x65, + 0x6d, 0xa5, 0x8f, 0x5e, 0xd7, 0x6e, 0x2d, 0xcb, 0x01, 0x41, 0xb6, 0x82, 0xeb, 0x40, 0xae, 0xdc, + 0x24, 0xfc, 0x0a, 0xd1, 0x4e, 0x6d, 0x46, 0x51, 0x9c, 0x1d, 0xf8, 0xb6, 0x33, 0x3f, 0x5f, 0x0c, + 0xcf, 0x03, 0xe5, 0xda, 0xb2, 0x9c, 0xc3, 0x41, 0xba, 0x80, 0xae, 0x2e, 0x64, 0x2f, 0x26, 0x48, + 0x90, 0x7e, 0xda, 0xd5, 0x8e, 0x28, 0xbe, 0x8b, 0x03, 0x7c, 0xfa, 0x07, 0x8f, 0xa1, 0x5b, 0x53, + 0x98, 0x2c, 0x85, 0x4c, 0x25, 0x0f, 0xec, 0xc2, 0xcf, 0x80, 0xdc, 0x75, 0x09, 0xa6, 0x22, 0x47, + 0x7f, 0x54, 0xd1, 0xbf, 0x3d, 0x8e, 0xfe, 0x36, 0xa6, 0x22, 0x4f, 0x3e, 0x1b, 0x0c, 0xec, 0xc1, + 0xbb, 0x60, 0x46, 0xbf, 0x45, 0x55, 0x4c, 0xa4, 0x76, 0x4c, 0x91, 0x9e, 0x1b, 0x47, 0x6a, 0x0a, + 0x4f, 0x5e, 0xc6, 0x74, 0xd0, 0x5f, 0xa6, 0xaf, 0xa1, 0x4d, 0x7c, 0x1a, 0xba, 0x31, 0xc9, 0x28, + 0x67, 0xf7, 0x7f, 0x0d, 0xab, 0x12, 0xe3, 0x64, 0x10, 0xf3, 0x1a, 0x06, 0x76, 0xe1, 0x27, 0xba, + 0xf9, 0x26, 0x61, 0x46, 0x7d, 0xbc, 0xec, 0xc3, 0xb7, 0x48, 0xfd, 0x20, 0xcc, 0xb1, 0x1e, 0x09, + 0xf2, 0x1b, 0xcd, 0x0b, 0xcf, 0x9e, 0x2c, 0x9f, 0x1f, 0x3b, 0xdf, 0xf4, 0x64, 0x93, 0x0a, 0xcd, + 0x54, 0xfb, 0xa1, 0x02, 0x26, 0x37, 0xa9, 0x1f, 0xae, 0x33, 0x0f, 0xde, 0x29, 0x4c, 0xb4, 0x73, + 0x23, 0x27, 0x9a, 0xf1, 0x57, 0x63, 0x6d, 0x26, 0xfd, 0x20, 0xfb, 0xfb, 0x3f, 0x19, 0x6f, 0xab, + 0x37, 0x9f, 0xbe, 0xac, 0x57, 0x9e, 0xbf, 0xac, 0x57, 0xfe, 0x7c, 0x59, 0xaf, 0xfc, 0xf8, 0xaa, + 0x6e, 0x3d, 0x7f, 0x55, 0xb7, 0xfe, 0x78, 0x55, 0xb7, 0x3e, 0x1f, 0x7f, 0xb0, 0xec, 0x7f, 0x20, + 0xed, 0x09, 0xf5, 0x63, 0xf9, 0xea, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x8c, 0xf7, 0xe4, 0x03, + 0x17, 0x11, 0x00, 0x00, } func (this *Supply) Equal(that interface{}) bool { @@ -2210,18 +2260,16 @@ func (m *Transaction) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0x12 } } - if m.Base != nil { - { - size, err := m.Base.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintCodec(dAtA, i, uint64(size)) + { + size, err := m.Base.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err } - i-- - dAtA[i] = 0xa + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) } + i-- + dAtA[i] = 0xa return len(dAtA) - i, nil } @@ -2618,6 +2666,53 @@ func (m *Message_MsgUndelegate) MarshalToSizedBuffer(dAtA []byte) (int, error) { } return len(dAtA) - i, nil } +func (m *SignDoc) 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 *SignDoc) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *SignDoc) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Msgs) > 0 { + for iNdEx := len(m.Msgs) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Msgs[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + { + size, err := m.StdSignDocBase.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func encodeVarintCodec(dAtA []byte, offset int, v uint64) int { offset -= sovCodec(v) base := offset @@ -2870,10 +2965,8 @@ func (m *Transaction) Size() (n int) { } var l int _ = l - if m.Base != nil { - l = m.Base.Size() - n += 1 + l + sovCodec(uint64(l)) - } + l = m.Base.Size() + n += 1 + l + sovCodec(uint64(l)) if len(m.Msgs) > 0 { for _, e := range m.Msgs { l = e.Size() @@ -3099,6 +3192,22 @@ func (m *Message_MsgUndelegate) Size() (n int) { } return n } +func (m *SignDoc) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.StdSignDocBase.Size() + n += 1 + l + sovCodec(uint64(l)) + if len(m.Msgs) > 0 { + for _, e := range m.Msgs { + l = e.Size() + n += 1 + l + sovCodec(uint64(l)) + } + } + return n +} func sovCodec(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 @@ -4159,9 +4268,6 @@ func (m *Transaction) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.Base == nil { - m.Base = &types.StdTxBase{} - } if err := m.Base.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } @@ -4195,7 +4301,7 @@ func (m *Transaction) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Msgs = append(m.Msgs, &Message{}) + m.Msgs = append(m.Msgs, Message{}) if err := m.Msgs[len(m.Msgs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } @@ -4872,6 +4978,126 @@ func (m *Message) Unmarshal(dAtA []byte) error { } return nil } +func (m *SignDoc) 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 ErrIntOverflowCodec + } + 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: SignDoc: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SignDoc: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StdSignDocBase", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.StdSignDocBase.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Msgs", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCodec + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCodec + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCodec + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Msgs = append(m.Msgs, Message{}) + if err := m.Msgs[len(m.Msgs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCodec(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthCodec + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipCodec(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/codec/std/codec.proto b/codec/std/codec.proto index 545597db7849..f5ec7b9878a4 100644 --- a/codec/std/codec.proto +++ b/codec/std/codec.proto @@ -106,8 +106,8 @@ message Content { message Transaction { option (gogoproto.goproto_getters) = false; - cosmos_sdk.x.auth.v1.StdTxBase base = 1; - repeated Message msgs = 2; + cosmos_sdk.x.auth.v1.StdTxBase base = 1 [(gogoproto.nullable) = false]; + repeated Message msgs = 2 [(gogoproto.nullable) = false]; } // Message defines the set of valid concrete message types that can be used to @@ -136,3 +136,11 @@ message Message { cosmos_sdk.x.staking.v1.MsgUndelegate msg_undelegate = 17; } } + +// SignDoc defines a standard application-level signing document to compose +// signatures for a Transaction. +message SignDoc { + cosmos_sdk.x.auth.v1.StdSignDocBase base = 1 + [(gogoproto.jsontag) = "", (gogoproto.embed) = true, (gogoproto.nullable) = false]; + repeated Message msgs = 2 [(gogoproto.nullable) = false]; +} diff --git a/codec/std/tx.go b/codec/std/tx.go index b261726719e4..0437eef92abd 100644 --- a/codec/std/tx.go +++ b/codec/std/tx.go @@ -1,6 +1,11 @@ package std import ( + "bytes" + + jsonc "github.com/gibson042/canonicaljson-go" + "github.com/gogo/protobuf/jsonpb" + sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/auth" @@ -65,3 +70,48 @@ func (tx Transaction) ValidateBasic() error { return nil } + +// CanonicalSignBytes returns the canonical JSON bytes to sign over for the +// Transaction given a chain ID, account sequence and account number. The JSON +// encoding ensures all field names adhere to their proto definition, default +// values are omitted, and follows the JSON Canonical Form. +func (tx Transaction) CanonicalSignBytes(cid string, a, s uint64) ([]byte, error) { + return NewSignDoc(a, s, cid, tx.Base.Memo, tx.Base.Fee, tx.Msgs...).SignBytes() +} + +func NewSignDoc(a, s uint64, cid, m string, f auth.StdFee, msgs ...Message) *SignDoc { + return &SignDoc{ + StdSignDocBase: auth.StdSignDocBase{ + ChainID: cid, + AccountNumber: a, + Sequence: s, + Memo: m, + Fee: f, + }, + Msgs: msgs, + } +} + +// CanonicalSignBytes returns the canonical JSON bytes to sign over, where the +// SignDoc is derived from a Transaction. The JSON encoding ensures all field +// names adhere to their proto definition, default values are omitted, and follows +// the JSON Canonical Form. +func (sd *SignDoc) CanonicalSignBytes() ([]byte, error) { + jm := &jsonpb.Marshaler{EmitDefaults: false, OrigName: false} + buf := new(bytes.Buffer) + + // first, encode via canonical Protocol Buffer JSON + if err := jm.Marshal(buf, sd); err != nil { + return nil, err + } + + genericJSON := make(map[string]interface{}) + + // decode canonical proto encoding into a generic map + if err := jsonc.Unmarshal(buf.Bytes(), &genericJSON); err != nil { + return nil, err + } + + // finally, return the canonical JSON encoding via JSON Canonical Form + return jsonc.Marshal(genericJSON) +} diff --git a/docs/architecture/adr-020-protobuf-transaction-encoding.md b/docs/architecture/adr-020-protobuf-transaction-encoding.md index d61d65ade761..1244cf24d2bd 100644 --- a/docs/architecture/adr-020-protobuf-transaction-encoding.md +++ b/docs/architecture/adr-020-protobuf-transaction-encoding.md @@ -78,7 +78,8 @@ to provide canonical representation of a `Transaction` to sign over, clients mus obey the following rules: - Encode `SignDoc` (see below) via [Protobuf's canonical JSON encoding](https://developers.google.com/protocol-buffers/docs/proto3#json). - - Default and zero values must be stripped from the output (`0`, `“”`, `null`, `false`, `[]`, and `{}`). + - Default must be stripped from the output! + - JSON keys adhere to their Proto-defined field names. - Generate canonical JSON to sign via the [JSON Canonical Form Spec](https://gibson042.github.io/canonicaljson-spec/). - This spec should be trivial to interpret and implement in any language. diff --git a/go.mod b/go.mod index 446acc15d813..d9fe6d045c95 100644 --- a/go.mod +++ b/go.mod @@ -7,9 +7,10 @@ require ( github.com/btcsuite/btcd v0.0.0-20190115013929-ed77733ec07d github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d github.com/cosmos/ledger-cosmos-go v0.11.1 + github.com/gibson042/canonicaljson-go v1.0.3 github.com/gogo/protobuf v1.3.1 github.com/golang/mock v1.4.1 - github.com/golang/protobuf v1.3.4 + github.com/golang/protobuf v1.4.0-rc.4 github.com/gorilla/handlers v1.4.2 github.com/gorilla/mux v1.7.4 github.com/hashicorp/golang-lru v0.5.4 @@ -30,6 +31,7 @@ require ( github.com/tendermint/iavl v0.13.0 github.com/tendermint/tendermint v0.33.2 github.com/tendermint/tm-db v0.4.1 + google.golang.org/protobuf v1.20.1 gopkg.in/yaml.v2 v2.2.8 ) diff --git a/go.sum b/go.sum index a1723495d767..3eeefa41668e 100644 --- a/go.sum +++ b/go.sum @@ -110,6 +110,8 @@ github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2 github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gibson042/canonicaljson-go v1.0.3 h1:EAyF8L74AWabkyUmrvEFHEt/AGFQeD6RfwbAuf0j1bI= +github.com/gibson042/canonicaljson-go v1.0.3/go.mod h1:DsLpJTThXyGNO+KZlI85C1/KDcImpP67k/RKVjcaEqo= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0 h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= @@ -139,6 +141,11 @@ github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.4 h1:87PNWwrRvUSnqS4dlcBU/ftvOIBep4sYuBLlh6rX2wk= github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4 h1:+EOh4OY6tjM6ZueeUKinl1f0U2820HzQOuf1iqMnsks= +github.com/golang/protobuf v1.4.0-rc.4/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -568,6 +575,12 @@ google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.20.1 h1:ESRXHgpUBG5D2I5mmsQIyYxB/tQIZfSZ8wLyFDf/N/U= +google.golang.org/protobuf v1.20.1/go.mod h1:KqelGeouBkcbcuB3HCk4/YH2tmNLk6YSWA5LIWeI/lY= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= diff --git a/x/auth/alias.go b/x/auth/alias.go index f21e285cc3cd..ce005797b3be 100644 --- a/x/auth/alias.go +++ b/x/auth/alias.go @@ -88,4 +88,5 @@ type ( TxBuilder = types.TxBuilder GenesisAccountIterator = types.GenesisAccountIterator Codec = types.Codec + StdSignDocBase = types.StdSignDocBase ) diff --git a/x/auth/types/stdtx.go b/x/auth/types/stdtx.go index e784f48ae52d..a6a5e79c31f3 100644 --- a/x/auth/types/stdtx.go +++ b/x/auth/types/stdtx.go @@ -17,6 +17,96 @@ import ( // MaxGasWanted defines the max gas allowed. const MaxGasWanted = uint64((1 << 63) - 1) +// NewStdFee returns a new instance of StdFee +func NewStdFee(gas uint64, amount sdk.Coins) StdFee { + return StdFee{ + Amount: amount, + Gas: gas, + } +} + +// Bytes returns the encoded bytes of a StdFee. +func (fee StdFee) Bytes() []byte { + if len(fee.Amount) == 0 { + fee.Amount = sdk.NewCoins() + } + + bz, err := codec.Cdc.MarshalJSON(fee) + if err != nil { + panic(err) + } + + return bz +} + +// GasPrices returns the gas prices for a StdFee. +// +// NOTE: The gas prices returned are not the true gas prices that were +// originally part of the submitted transaction because the fee is computed +// as fee = ceil(gasWanted * gasPrices). +func (fee StdFee) GasPrices() sdk.DecCoins { + return sdk.NewDecCoinsFromCoins(fee.Amount...).QuoDec(sdk.NewDec(int64(fee.Gas))) +} + +// GetPubKey returns the public key of a signature as a crypto.PubKey using the +// Amino codec. +func (ss StdSignature) GetPubKey() (pk crypto.PubKey) { + if len(ss.PubKey) == 0 { + return nil + } + + codec.Cdc.MustUnmarshalBinaryBare(ss.PubKey, &pk) + return pk +} + +// MarshalYAML returns the YAML representation of the signature. +func (ss StdSignature) MarshalYAML() (interface{}, error) { + var ( + bz []byte + pubkey string + err error + ) + + if ss.PubKey != nil { + pubkey, err = sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, ss.GetPubKey()) + if err != nil { + return nil, err + } + } + + bz, err = yaml.Marshal(struct { + PubKey string + Signature string + }{ + PubKey: pubkey, + Signature: fmt.Sprintf("%X", ss.Signature), + }) + if err != nil { + return nil, err + } + + return string(bz), err +} + +// CountSubKeys counts the total number of keys for a multi-sig public key. +func CountSubKeys(pub crypto.PubKey) int { + v, ok := pub.(multisig.PubKeyMultisigThreshold) + if !ok { + return 1 + } + + numKeys := 0 + for _, subkey := range v.PubKeys { + numKeys += CountSubKeys(subkey) + } + + return numKeys +} + +// --------------------------------------------------------------------------- +// DEPRECATED +// --------------------------------------------------------------------------- + var _ sdk.Tx = (*StdTx)(nil) // StdTx is a standard way to wrap a Msg with Fee and Signatures. @@ -70,21 +160,6 @@ func (tx StdTx) ValidateBasic() error { return nil } -// CountSubKeys counts the total number of keys for a multi-sig public key. -func CountSubKeys(pub crypto.PubKey) int { - v, ok := pub.(multisig.PubKeyMultisigThreshold) - if !ok { - return 1 - } - - numKeys := 0 - for _, subkey := range v.PubKeys { - numKeys += CountSubKeys(subkey) - } - - return numKeys -} - // GetSigners returns the addresses that must sign the transaction. // Addresses are returned in a deterministic order. // They are accumulated from the GetSigners method for each Msg @@ -166,43 +241,6 @@ func (tx StdTx) FeePayer() sdk.AccAddress { return sdk.AccAddress{} } -// NewStdFee returns a new instance of StdFee -func NewStdFee(gas uint64, amount sdk.Coins) StdFee { - return StdFee{ - Amount: amount, - Gas: gas, - } -} - -// Bytes for signing later -func (fee StdFee) Bytes() []byte { - // normalize. XXX - // this is a sign of something ugly - // (in the lcd_test, client side its null, - // server side its []) - if len(fee.Amount) == 0 { - fee.Amount = sdk.NewCoins() - } - - bz, err := codec.Cdc.MarshalJSON(fee) // TODO - if err != nil { - panic(err) - } - - return bz -} - -// GasPrices returns the gas prices for a StdFee. -// -// NOTE: The gas prices returned are not the true gas prices that were -// originally part of the submitted transaction because the fee is computed -// as fee = ceil(gasWanted * gasPrices). -func (fee StdFee) GasPrices() sdk.DecCoins { - return sdk.NewDecCoinsFromCoins(fee.Amount...).QuoDec(sdk.NewDec(int64(fee.Gas))) -} - -//__________________________________________________________ - // StdSignDoc is replay-prevention structure. // It includes the result of msg.GetSignBytes(), // as well as the ChainID (prevent cross chain replay) @@ -266,43 +304,3 @@ func DefaultTxEncoder(cdc *codec.Codec) sdk.TxEncoder { return cdc.MarshalBinaryLengthPrefixed(tx) } } - -// GetPubKey returns the public key of a signature as a crypto.PubKey using the -// Amino codec. -func (ss StdSignature) GetPubKey() (pk crypto.PubKey) { - if len(ss.PubKey) == 0 { - return nil - } - - codec.Cdc.MustUnmarshalBinaryBare(ss.PubKey, &pk) - return pk -} - -// MarshalYAML returns the YAML representation of the signature. -func (ss StdSignature) MarshalYAML() (interface{}, error) { - var ( - bz []byte - pubkey string - err error - ) - - if ss.PubKey != nil { - pubkey, err = sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, ss.GetPubKey()) - if err != nil { - return nil, err - } - } - - bz, err = yaml.Marshal(struct { - PubKey string - Signature string - }{ - PubKey: pubkey, - Signature: fmt.Sprintf("%X", ss.Signature), - }) - if err != nil { - return nil, err - } - - return string(bz), err -} diff --git a/x/auth/types/types.pb.go b/x/auth/types/types.pb.go index cc3837b4db3d..699182bc8db3 100644 --- a/x/auth/types/types.pb.go +++ b/x/auth/types/types.pb.go @@ -241,9 +241,9 @@ func (m *Params) GetSigVerifyCostSecp256k1() uint64 { // StdTxBase defines a transaction base which application-level concrete transaction // types can extend. type StdTxBase struct { - Fee *StdFee `protobuf:"bytes,1,opt,name=fee,proto3" json:"fee,omitempty"` - Signatures []*StdSignature `protobuf:"bytes,2,rep,name=signatures,proto3" json:"signatures,omitempty"` - Memo string `protobuf:"bytes,3,opt,name=memo,proto3" json:"memo,omitempty"` + Fee StdFee `protobuf:"bytes,1,opt,name=fee,proto3" json:"fee"` + Signatures []StdSignature `protobuf:"bytes,2,rep,name=signatures,proto3" json:"signatures"` + Memo string `protobuf:"bytes,3,opt,name=memo,proto3" json:"memo,omitempty"` } func (m *StdTxBase) Reset() { *m = StdTxBase{} } @@ -279,14 +279,14 @@ func (m *StdTxBase) XXX_DiscardUnknown() { var xxx_messageInfo_StdTxBase proto.InternalMessageInfo -func (m *StdTxBase) GetFee() *StdFee { +func (m *StdTxBase) GetFee() StdFee { if m != nil { return m.Fee } - return nil + return StdFee{} } -func (m *StdTxBase) GetSignatures() []*StdSignature { +func (m *StdTxBase) GetSignatures() []StdSignature { if m != nil { return m.Signatures } @@ -300,64 +300,148 @@ func (m *StdTxBase) GetMemo() string { return "" } +// StdSignDocBase defines the base structure for which applications can extend +// to define the concrete structure that signers sign over. +type StdSignDocBase struct { + ChainID string `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty" yaml:"chain_id"` + AccountNumber uint64 `protobuf:"varint,2,opt,name=account_number,json=accountNumber,proto3" json:"account_number,omitempty" yaml:"account_number"` + Sequence uint64 `protobuf:"varint,3,opt,name=sequence,proto3" json:"sequence,omitempty"` + Memo string `protobuf:"bytes,4,opt,name=memo,proto3" json:"memo,omitempty"` + Fee StdFee `protobuf:"bytes,5,opt,name=fee,proto3" json:"fee"` +} + +func (m *StdSignDocBase) Reset() { *m = StdSignDocBase{} } +func (m *StdSignDocBase) String() string { return proto.CompactTextString(m) } +func (*StdSignDocBase) ProtoMessage() {} +func (*StdSignDocBase) Descriptor() ([]byte, []int) { + return fileDescriptor_2d526fa662daab74, []int{5} +} +func (m *StdSignDocBase) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StdSignDocBase) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_StdSignDocBase.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 *StdSignDocBase) XXX_Merge(src proto.Message) { + xxx_messageInfo_StdSignDocBase.Merge(m, src) +} +func (m *StdSignDocBase) XXX_Size() int { + return m.Size() +} +func (m *StdSignDocBase) XXX_DiscardUnknown() { + xxx_messageInfo_StdSignDocBase.DiscardUnknown(m) +} + +var xxx_messageInfo_StdSignDocBase proto.InternalMessageInfo + +func (m *StdSignDocBase) GetChainID() string { + if m != nil { + return m.ChainID + } + return "" +} + +func (m *StdSignDocBase) GetAccountNumber() uint64 { + if m != nil { + return m.AccountNumber + } + return 0 +} + +func (m *StdSignDocBase) GetSequence() uint64 { + if m != nil { + return m.Sequence + } + return 0 +} + +func (m *StdSignDocBase) GetMemo() string { + if m != nil { + return m.Memo + } + return "" +} + +func (m *StdSignDocBase) GetFee() StdFee { + if m != nil { + return m.Fee + } + return StdFee{} +} + func init() { proto.RegisterType((*BaseAccount)(nil), "cosmos_sdk.x.auth.v1.BaseAccount") proto.RegisterType((*StdFee)(nil), "cosmos_sdk.x.auth.v1.StdFee") proto.RegisterType((*StdSignature)(nil), "cosmos_sdk.x.auth.v1.StdSignature") proto.RegisterType((*Params)(nil), "cosmos_sdk.x.auth.v1.Params") proto.RegisterType((*StdTxBase)(nil), "cosmos_sdk.x.auth.v1.StdTxBase") + proto.RegisterType((*StdSignDocBase)(nil), "cosmos_sdk.x.auth.v1.StdSignDocBase") } func init() { proto.RegisterFile("x/auth/types/types.proto", fileDescriptor_2d526fa662daab74) } var fileDescriptor_2d526fa662daab74 = []byte{ - // 727 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x54, 0x41, 0x4f, 0xdb, 0x48, - 0x14, 0x8e, 0x49, 0x36, 0xc0, 0xc0, 0xae, 0x36, 0x43, 0x80, 0x10, 0x21, 0x4f, 0xe4, 0xc3, 0x2a, - 0x2b, 0x2d, 0xce, 0x26, 0x2b, 0x56, 0x22, 0x87, 0xd5, 0xe2, 0xec, 0x72, 0xa1, 0x45, 0x68, 0x52, - 0xf5, 0x50, 0xa9, 0xb2, 0x26, 0xf6, 0xe0, 0x58, 0xc1, 0xb1, 0xf1, 0x8c, 0x51, 0xcc, 0xa5, 0xd7, - 0xaa, 0xa7, 0x4a, 0xbd, 0xf4, 0xc8, 0xb9, 0xbf, 0x84, 0x23, 0xc7, 0x9e, 0x4c, 0x15, 0x2e, 0x55, - 0x8f, 0x39, 0xf6, 0x54, 0x8d, 0x27, 0x84, 0x40, 0x43, 0x55, 0xa9, 0x97, 0x64, 0xe6, 0xbd, 0xef, - 0xfb, 0xde, 0xf8, 0xcd, 0xf7, 0x06, 0x94, 0x06, 0x35, 0x12, 0xf1, 0x6e, 0x8d, 0xc7, 0x01, 0x65, - 0xf2, 0x57, 0x0f, 0x42, 0x9f, 0xfb, 0xb0, 0x68, 0xf9, 0xcc, 0xf3, 0x99, 0xc9, 0xec, 0x9e, 0x3e, - 0xd0, 0x05, 0x48, 0x3f, 0xad, 0x97, 0x7f, 0xe3, 0x5d, 0x37, 0xb4, 0xcd, 0x80, 0x84, 0x3c, 0xae, - 0xa5, 0xc0, 0x9a, 0xe3, 0x3b, 0xfe, 0xed, 0x4a, 0xb2, 0xcb, 0x85, 0xaf, 0x04, 0xb5, 0x57, 0x73, - 0x60, 0xc9, 0x20, 0x8c, 0xee, 0x5a, 0x96, 0x1f, 0xf5, 0x39, 0xdc, 0x07, 0xf3, 0xc4, 0xb6, 0x43, - 0xca, 0x58, 0x49, 0xa9, 0x28, 0xd5, 0x65, 0xa3, 0xfe, 0x39, 0x41, 0x5b, 0x8e, 0xcb, 0xbb, 0x51, - 0x47, 0xb7, 0x7c, 0xaf, 0x26, 0x0f, 0x30, 0xfe, 0xdb, 0x62, 0x76, 0x6f, 0x2c, 0xb7, 0x6b, 0x59, - 0xbb, 0x92, 0x88, 0x6f, 0x14, 0xe0, 0x1e, 0x98, 0x0f, 0xa2, 0x8e, 0xd9, 0xa3, 0x71, 0x69, 0x2e, - 0x15, 0xdb, 0xfa, 0x94, 0xa0, 0x62, 0x10, 0x75, 0x8e, 0x5d, 0x4b, 0x44, 0xff, 0xf0, 0x3d, 0x97, - 0x53, 0x2f, 0xe0, 0xf1, 0x28, 0x41, 0x85, 0x98, 0x78, 0xc7, 0x4d, 0xed, 0x36, 0xab, 0xe1, 0x7c, - 0x10, 0x75, 0xf6, 0x69, 0x0c, 0xff, 0x05, 0xbf, 0x10, 0x79, 0x3e, 0xb3, 0x1f, 0x79, 0x1d, 0x1a, - 0x96, 0xb2, 0x15, 0xa5, 0x9a, 0x33, 0x36, 0x46, 0x09, 0x5a, 0x95, 0xb4, 0xbb, 0x79, 0x0d, 0xff, - 0x3c, 0x0e, 0x1c, 0xa4, 0x7b, 0x58, 0x06, 0x0b, 0x8c, 0x9e, 0x44, 0xb4, 0x6f, 0xd1, 0x52, 0x4e, - 0x70, 0xf1, 0x64, 0xdf, 0x5c, 0x78, 0x79, 0x8e, 0x32, 0x6f, 0xcf, 0x51, 0x46, 0x7b, 0x01, 0xf2, - 0x6d, 0x6e, 0xef, 0x51, 0x0a, 0x9f, 0x83, 0x3c, 0xf1, 0x04, 0xbf, 0xa4, 0x54, 0xb2, 0xd5, 0xa5, - 0xc6, 0x8a, 0x3e, 0xd5, 0xf8, 0xd3, 0xba, 0xde, 0xf2, 0xdd, 0xbe, 0xf1, 0xe7, 0x45, 0x82, 0x32, - 0xef, 0xae, 0x50, 0xf5, 0x3b, 0xda, 0x23, 0x08, 0x0c, 0x8f, 0x45, 0xe1, 0xaf, 0x20, 0xeb, 0x10, - 0x96, 0x36, 0x25, 0x87, 0xc5, 0xb2, 0x99, 0xfb, 0x78, 0x8e, 0x14, 0xed, 0x0c, 0x2c, 0xb7, 0xb9, - 0xdd, 0x76, 0x9d, 0x3e, 0xe1, 0x51, 0x48, 0xa7, 0x1b, 0xa8, 0xfc, 0x48, 0x03, 0x37, 0xc1, 0x22, - 0xbb, 0x11, 0x95, 0x57, 0x81, 0x6f, 0x03, 0xcd, 0x9c, 0x68, 0x80, 0x76, 0x95, 0x05, 0xf9, 0x43, - 0x12, 0x12, 0x8f, 0xc1, 0x03, 0xb0, 0xe2, 0x91, 0x81, 0xe9, 0x51, 0xcf, 0x37, 0xad, 0x2e, 0x09, - 0x89, 0xc5, 0x69, 0x28, 0x0d, 0x91, 0x33, 0xd4, 0x51, 0x82, 0xca, 0xb2, 0xd4, 0x0c, 0x90, 0x86, - 0x0b, 0x1e, 0x19, 0x3c, 0xa6, 0x9e, 0xdf, 0x9a, 0xc4, 0xe0, 0x0e, 0x58, 0xe6, 0x03, 0x93, 0xb9, - 0x8e, 0x79, 0xec, 0x7a, 0x2e, 0x97, 0xdf, 0x6d, 0xac, 0x8f, 0x12, 0xb4, 0x22, 0x85, 0xa6, 0xb3, - 0x1a, 0x06, 0x7c, 0xd0, 0x76, 0x9d, 0x47, 0x62, 0x03, 0x31, 0x58, 0x4d, 0x93, 0x67, 0xd4, 0xb4, - 0x7c, 0xc6, 0xcd, 0x80, 0x86, 0x66, 0x27, 0xe6, 0x74, 0xec, 0x80, 0xca, 0x28, 0x41, 0x9b, 0x53, - 0x1a, 0xf7, 0x61, 0x1a, 0x2e, 0x08, 0xb1, 0x33, 0xda, 0xf2, 0x19, 0x3f, 0xa4, 0xa1, 0x11, 0x73, - 0x0a, 0x4f, 0xc0, 0xba, 0xa8, 0x76, 0x4a, 0x43, 0xf7, 0x28, 0x96, 0x78, 0x6a, 0x37, 0xb6, 0xb7, - 0xeb, 0x3b, 0xd2, 0x1b, 0x46, 0x73, 0x98, 0xa0, 0x62, 0xdb, 0x75, 0x9e, 0xa6, 0x08, 0x41, 0xfd, - 0xff, 0xbf, 0x34, 0x3f, 0x4a, 0x90, 0x2a, 0xab, 0x3d, 0x20, 0xa0, 0xe1, 0x22, 0xbb, 0xc3, 0x93, - 0x61, 0x18, 0x83, 0x8d, 0xfb, 0x0c, 0x46, 0xad, 0xa0, 0xb1, 0xfd, 0x77, 0xaf, 0x5e, 0xfa, 0x29, - 0x2d, 0xfa, 0xcf, 0x30, 0x41, 0x6b, 0x77, 0x8a, 0xb6, 0x6f, 0x10, 0xa3, 0x04, 0x55, 0x66, 0x97, - 0x9d, 0x88, 0x68, 0x78, 0x8d, 0xcd, 0xe4, 0x36, 0x17, 0x84, 0xb5, 0x53, 0x77, 0xbd, 0x51, 0xc0, - 0x62, 0x9b, 0xdb, 0x4f, 0x06, 0x62, 0xe0, 0xa1, 0x0e, 0xb2, 0x47, 0x94, 0xa6, 0x97, 0xba, 0xd4, - 0xd8, 0xd4, 0x67, 0x3d, 0x2c, 0xba, 0x9c, 0x06, 0x2c, 0x80, 0xd0, 0x00, 0x60, 0x62, 0x19, 0x61, - 0x5d, 0x31, 0x16, 0xda, 0x83, 0xb4, 0x89, 0x87, 0xf1, 0x14, 0x0b, 0x42, 0x90, 0x13, 0x7e, 0x49, - 0x2f, 0x6f, 0x11, 0xa7, 0x6b, 0xa3, 0x75, 0x31, 0x54, 0x95, 0xcb, 0xa1, 0xaa, 0x7c, 0x18, 0xaa, - 0xca, 0xeb, 0x6b, 0x35, 0x73, 0x79, 0xad, 0x66, 0xde, 0x5f, 0xab, 0x99, 0x67, 0xbf, 0x7f, 0x73, - 0xae, 0xa6, 0xdf, 0xc8, 0x4e, 0x3e, 0x7d, 0xcd, 0xfe, 0xfa, 0x12, 0x00, 0x00, 0xff, 0xff, 0xf4, - 0x66, 0x9d, 0x7a, 0x3a, 0x05, 0x00, 0x00, + // 803 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x55, 0xcf, 0x6f, 0x1b, 0x45, + 0x14, 0xf6, 0xc6, 0x5b, 0x27, 0x99, 0x84, 0x42, 0x26, 0x6e, 0xeb, 0x5a, 0xd1, 0x8e, 0xb5, 0x07, + 0x64, 0x24, 0xb2, 0xc6, 0x86, 0x20, 0xc5, 0x07, 0x44, 0xd6, 0xa1, 0xa2, 0x2a, 0x54, 0xd5, 0x18, + 0x71, 0x40, 0x42, 0xab, 0xf1, 0xee, 0x74, 0xbd, 0x72, 0xd6, 0xbb, 0xdd, 0x99, 0x8d, 0xbc, 0xb9, + 0x70, 0x45, 0x9c, 0x38, 0x72, 0x23, 0x67, 0xfe, 0x92, 0x1e, 0x7b, 0xe4, 0xb4, 0x45, 0xce, 0x05, + 0x71, 0x5c, 0x6e, 0x9c, 0xd0, 0xcc, 0xf8, 0x67, 0x71, 0x11, 0xa8, 0x17, 0x7b, 0xe6, 0xcd, 0xfb, + 0xbe, 0xf7, 0xfc, 0xcd, 0x37, 0xcf, 0xa0, 0x36, 0x69, 0x91, 0x94, 0x0f, 0x5b, 0x3c, 0x8b, 0x29, + 0x53, 0x9f, 0x56, 0x9c, 0x44, 0x3c, 0x82, 0x55, 0x37, 0x62, 0x61, 0xc4, 0x1c, 0xe6, 0x8d, 0xac, + 0x89, 0x25, 0x92, 0xac, 0xcb, 0x76, 0xfd, 0x5d, 0x3e, 0x0c, 0x12, 0xcf, 0x89, 0x49, 0xc2, 0xb3, + 0x96, 0x4c, 0x6c, 0xf9, 0x91, 0x1f, 0x2d, 0x57, 0x0a, 0x5d, 0x3f, 0xf8, 0x07, 0xa1, 0xf9, 0xc3, + 0x16, 0xd8, 0xb3, 0x09, 0xa3, 0x67, 0xae, 0x1b, 0xa5, 0x63, 0x0e, 0x1f, 0x81, 0x6d, 0xe2, 0x79, + 0x09, 0x65, 0xac, 0xa6, 0x35, 0xb4, 0xe6, 0xbe, 0xdd, 0xfe, 0x2b, 0x47, 0xc7, 0x7e, 0xc0, 0x87, + 0xe9, 0xc0, 0x72, 0xa3, 0xb0, 0xa5, 0x1a, 0x98, 0x7d, 0x1d, 0x33, 0x6f, 0x34, 0xa3, 0x3b, 0x73, + 0xdd, 0x33, 0x05, 0xc4, 0x73, 0x06, 0xf8, 0x00, 0x6c, 0xc7, 0xe9, 0xc0, 0x19, 0xd1, 0xac, 0xb6, + 0x25, 0xc9, 0x8e, 0xff, 0xc8, 0x51, 0x35, 0x4e, 0x07, 0x17, 0x81, 0x2b, 0xa2, 0xef, 0x47, 0x61, + 0xc0, 0x69, 0x18, 0xf3, 0xac, 0xc8, 0xd1, 0x41, 0x46, 0xc2, 0x8b, 0xae, 0xb9, 0x3c, 0x35, 0x71, + 0x25, 0x4e, 0x07, 0x8f, 0x68, 0x06, 0x3f, 0x05, 0xb7, 0x89, 0xea, 0xcf, 0x19, 0xa7, 0xe1, 0x80, + 0x26, 0xb5, 0x72, 0x43, 0x6b, 0xea, 0xf6, 0xfd, 0x22, 0x47, 0x77, 0x14, 0x6c, 0xfd, 0xdc, 0xc4, + 0x6f, 0xcd, 0x02, 0x8f, 0xe5, 0x1e, 0xd6, 0xc1, 0x0e, 0xa3, 0xcf, 0x52, 0x3a, 0x76, 0x69, 0x4d, + 0x17, 0x58, 0xbc, 0xd8, 0x77, 0x77, 0xbe, 0xbf, 0x46, 0xa5, 0x9f, 0xae, 0x51, 0xc9, 0xfc, 0x0e, + 0x54, 0xfa, 0xdc, 0x7b, 0x40, 0x29, 0xfc, 0x16, 0x54, 0x48, 0x28, 0xf0, 0x35, 0xad, 0x51, 0x6e, + 0xee, 0x75, 0x0e, 0xad, 0x15, 0xe1, 0x2f, 0xdb, 0x56, 0x2f, 0x0a, 0xc6, 0xf6, 0x07, 0xcf, 0x73, + 0x54, 0xfa, 0xe5, 0x25, 0x6a, 0xfe, 0x07, 0x79, 0x04, 0x80, 0xe1, 0x19, 0x29, 0x7c, 0x07, 0x94, + 0x7d, 0xc2, 0xa4, 0x28, 0x3a, 0x16, 0xcb, 0xae, 0xfe, 0xfb, 0x35, 0xd2, 0xcc, 0x2b, 0xb0, 0xdf, + 0xe7, 0x5e, 0x3f, 0xf0, 0xc7, 0x84, 0xa7, 0x09, 0x5d, 0x15, 0x50, 0x7b, 0x13, 0x01, 0x8f, 0xc0, + 0x2e, 0x9b, 0x93, 0xaa, 0xab, 0xc0, 0xcb, 0x40, 0x57, 0x17, 0x02, 0x98, 0x2f, 0xcb, 0xa0, 0xf2, + 0x84, 0x24, 0x24, 0x64, 0xf0, 0x31, 0x38, 0x0c, 0xc9, 0xc4, 0x09, 0x69, 0x18, 0x39, 0xee, 0x90, + 0x24, 0xc4, 0xe5, 0x34, 0x51, 0x86, 0xd0, 0x6d, 0xa3, 0xc8, 0x51, 0x5d, 0x95, 0xda, 0x90, 0x64, + 0xe2, 0x83, 0x90, 0x4c, 0xbe, 0xa4, 0x61, 0xd4, 0x5b, 0xc4, 0xe0, 0x29, 0xd8, 0xe7, 0x13, 0x87, + 0x05, 0xbe, 0x73, 0x11, 0x84, 0x01, 0x57, 0xbf, 0xdb, 0xbe, 0x57, 0xe4, 0xe8, 0x50, 0x11, 0xad, + 0x9e, 0x9a, 0x18, 0xf0, 0x49, 0x3f, 0xf0, 0xbf, 0x10, 0x1b, 0x88, 0xc1, 0x1d, 0x79, 0x78, 0x45, + 0x1d, 0x37, 0x62, 0xdc, 0x89, 0x69, 0xe2, 0x0c, 0x32, 0x4e, 0x67, 0x0e, 0x68, 0x14, 0x39, 0x3a, + 0x5a, 0xe1, 0x78, 0x35, 0xcd, 0xc4, 0x07, 0x82, 0xec, 0x8a, 0xf6, 0x22, 0xc6, 0x9f, 0xd0, 0xc4, + 0xce, 0x38, 0x85, 0xcf, 0xc0, 0x3d, 0x51, 0xed, 0x92, 0x26, 0xc1, 0xd3, 0x4c, 0xe5, 0x53, 0xaf, + 0x73, 0x72, 0xd2, 0x3e, 0x55, 0xde, 0xb0, 0xbb, 0xd3, 0x1c, 0x55, 0xfb, 0x81, 0xff, 0xb5, 0xcc, + 0x10, 0xd0, 0xcf, 0xce, 0xe5, 0x79, 0x91, 0x23, 0x43, 0x55, 0x7b, 0x0d, 0x81, 0x89, 0xab, 0x6c, + 0x0d, 0xa7, 0xc2, 0x30, 0x03, 0xf7, 0x5f, 0x45, 0x30, 0xea, 0xc6, 0x9d, 0x93, 0x8f, 0x47, 0xed, + 0xda, 0x2d, 0x59, 0xf4, 0x93, 0x69, 0x8e, 0xee, 0xae, 0x15, 0xed, 0xcf, 0x33, 0x8a, 0x1c, 0x35, + 0x36, 0x97, 0x5d, 0x90, 0x98, 0xf8, 0x2e, 0xdb, 0x88, 0xed, 0xee, 0x08, 0x6b, 0x4b, 0x77, 0xfd, + 0xac, 0x81, 0xdd, 0x3e, 0xf7, 0xbe, 0x9a, 0x88, 0x07, 0x0f, 0x3f, 0x02, 0xe5, 0xa7, 0x94, 0xca, + 0x4b, 0xdd, 0xeb, 0x1c, 0x59, 0x9b, 0x06, 0x8b, 0xa5, 0x5e, 0x83, 0xad, 0x0b, 0xa3, 0x63, 0x91, + 0x0e, 0x3f, 0x07, 0x60, 0x61, 0x1c, 0x61, 0x60, 0xf1, 0x38, 0xcc, 0xd7, 0x82, 0x17, 0x4e, 0x9e, + 0x51, 0xac, 0x60, 0x21, 0x04, 0xba, 0xf0, 0x8e, 0xbc, 0xc8, 0x5d, 0x2c, 0xd7, 0xe6, 0x9f, 0x1a, + 0xb8, 0x3d, 0x83, 0x9d, 0x47, 0xae, 0x6c, 0xf3, 0x14, 0xec, 0xb8, 0x43, 0x12, 0x8c, 0x9d, 0xc0, + 0x93, 0xbd, 0xee, 0xda, 0xc6, 0x34, 0x47, 0xdb, 0x3d, 0x11, 0x7b, 0x78, 0x5e, 0xe4, 0xe8, 0x6d, + 0xa5, 0xcc, 0x3c, 0xc9, 0xc4, 0xdb, 0x72, 0xf9, 0xd0, 0xdb, 0x30, 0x36, 0xb6, 0xde, 0x60, 0x6c, + 0x94, 0xd7, 0xc7, 0xc6, 0xa2, 0x7f, 0x7d, 0xd9, 0xff, 0x5c, 0xd3, 0x5b, 0xff, 0x4b, 0x53, 0xbb, + 0xf7, 0x7c, 0x6a, 0x68, 0x2f, 0xa6, 0x86, 0xf6, 0xdb, 0xd4, 0xd0, 0x7e, 0xbc, 0x31, 0x4a, 0x2f, + 0x6e, 0x8c, 0xd2, 0xaf, 0x37, 0x46, 0xe9, 0x9b, 0xf7, 0xfe, 0x75, 0xb2, 0xac, 0xfe, 0x4b, 0x0c, + 0x2a, 0x72, 0x9e, 0x7f, 0xf8, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc2, 0xcf, 0xcb, 0xc3, 0x3c, + 0x06, 0x00, 0x00, } func (this *StdFee) Equal(that interface{}) bool { @@ -643,15 +727,70 @@ func (m *StdTxBase) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0x12 } } - if m.Fee != nil { - { - size, err := m.Fee.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTypes(dAtA, i, uint64(size)) + { + size, err := m.Fee.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *StdSignDocBase) 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 *StdSignDocBase) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StdSignDocBase) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Fee.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + if len(m.Memo) > 0 { + i -= len(m.Memo) + copy(dAtA[i:], m.Memo) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Memo))) + i-- + dAtA[i] = 0x22 + } + if m.Sequence != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.Sequence)) + i-- + dAtA[i] = 0x18 + } + if m.AccountNumber != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.AccountNumber)) + i-- + dAtA[i] = 0x10 + } + if len(m.ChainID) > 0 { + i -= len(m.ChainID) + copy(dAtA[i:], m.ChainID) + i = encodeVarintTypes(dAtA, i, uint64(len(m.ChainID))) i-- dAtA[i] = 0xa } @@ -757,10 +896,8 @@ func (m *StdTxBase) Size() (n int) { } var l int _ = l - if m.Fee != nil { - l = m.Fee.Size() - n += 1 + l + sovTypes(uint64(l)) - } + l = m.Fee.Size() + n += 1 + l + sovTypes(uint64(l)) if len(m.Signatures) > 0 { for _, e := range m.Signatures { l = e.Size() @@ -774,6 +911,31 @@ func (m *StdTxBase) Size() (n int) { return n } +func (m *StdSignDocBase) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ChainID) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + if m.AccountNumber != 0 { + n += 1 + sovTypes(uint64(m.AccountNumber)) + } + if m.Sequence != 0 { + n += 1 + sovTypes(uint64(m.Sequence)) + } + l = len(m.Memo) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = m.Fee.Size() + n += 1 + l + sovTypes(uint64(l)) + return n +} + func sovTypes(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -1372,9 +1534,6 @@ func (m *StdTxBase) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.Fee == nil { - m.Fee = &StdFee{} - } if err := m.Fee.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } @@ -1408,7 +1567,7 @@ func (m *StdTxBase) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Signatures = append(m.Signatures, &StdSignature{}) + m.Signatures = append(m.Signatures, StdSignature{}) if err := m.Signatures[len(m.Signatures)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } @@ -1469,6 +1628,194 @@ func (m *StdTxBase) Unmarshal(dAtA []byte) error { } return nil } +func (m *StdSignDocBase) 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 ErrIntOverflowTypes + } + 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: StdSignDocBase: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: StdSignDocBase: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChainID = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field AccountNumber", wireType) + } + m.AccountNumber = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.AccountNumber |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Sequence", wireType) + } + m.Sequence = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Sequence |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Memo", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Memo = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Fee", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Fee.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipTypes(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/auth/types/types.proto b/x/auth/types/types.proto index 9cc76719ff53..e15e0342f1f9 100644 --- a/x/auth/types/types.proto +++ b/x/auth/types/types.proto @@ -56,7 +56,17 @@ message Params { // StdTxBase defines a transaction base which application-level concrete transaction // types can extend. message StdTxBase { - StdFee fee = 1; - repeated StdSignature signatures = 2; + StdFee fee = 1 [(gogoproto.nullable) = false]; + repeated StdSignature signatures = 2 [(gogoproto.nullable) = false]; string memo = 3; } + +// StdSignDocBase defines the base structure for which applications can extend +// to define the concrete structure that signers sign over. +message StdSignDocBase { + string chain_id = 1 [(gogoproto.customname) = "ChainID", (gogoproto.moretags) = "yaml:\"chain_id\""]; + uint64 account_number = 2 [(gogoproto.moretags) = "yaml:\"account_number\""]; + uint64 sequence = 3; + string memo = 4; + StdFee fee = 5 [(gogoproto.nullable) = false]; +} From 53a43dc2a14279d78c465ac3ae213ab83dac8645 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Thu, 12 Mar 2020 13:46:35 -0400 Subject: [PATCH 406/529] Fix API --- codec/std/tx.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codec/std/tx.go b/codec/std/tx.go index 0437eef92abd..595fbd848c10 100644 --- a/codec/std/tx.go +++ b/codec/std/tx.go @@ -76,7 +76,7 @@ func (tx Transaction) ValidateBasic() error { // encoding ensures all field names adhere to their proto definition, default // values are omitted, and follows the JSON Canonical Form. func (tx Transaction) CanonicalSignBytes(cid string, a, s uint64) ([]byte, error) { - return NewSignDoc(a, s, cid, tx.Base.Memo, tx.Base.Fee, tx.Msgs...).SignBytes() + return NewSignDoc(a, s, cid, tx.Base.Memo, tx.Base.Fee, tx.Msgs...).CanonicalSignBytes() } func NewSignDoc(a, s uint64, cid, m string, f auth.StdFee, msgs ...Message) *SignDoc { From 55139277784784713273a6316be4700c07adf672 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Thu, 12 Mar 2020 13:52:55 -0400 Subject: [PATCH 407/529] Fix TestStdSignatureMarshalYAML --- x/auth/types/stdtx_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/auth/types/stdtx_test.go b/x/auth/types/stdtx_test.go index 38e1a3348b1f..7c269e419697 100644 --- a/x/auth/types/stdtx_test.go +++ b/x/auth/types/stdtx_test.go @@ -153,7 +153,7 @@ func TestStdSignatureMarshalYAML(t *testing.T) { }, { StdSignature{PubKey: pubKey.Bytes(), Signature: []byte("dummySig")}, - fmt.Sprintf("|\n pubkey: %s\n signature: dummySig\n", sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pubKey)), + fmt.Sprintf("|\n pubkey: %s\n signature: 64756D6D79536967\n", sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pubKey)), }, { StdSignature{PubKey: pubKey.Bytes(), Signature: nil}, From b38d3ae69afe64b74d8513af2b38b8f2008db884 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Thu, 12 Mar 2020 15:35:22 -0400 Subject: [PATCH 408/529] Update ADR and types --- client/tx.go | 42 ++++ codec/std/codec.pb.go | 200 +++++++++--------- codec/std/codec.proto | 5 +- .../adr-020-protobuf-transaction-encoding.md | 11 +- types/tx_msg.go | 71 ++++--- x/auth/alias.go | 4 + x/auth/types/types.pb.go | 114 +++++----- x/auth/types/types.proto | 3 +- 8 files changed, 250 insertions(+), 200 deletions(-) create mode 100644 client/tx.go diff --git a/client/tx.go b/client/tx.go new file mode 100644 index 000000000000..d7fdb82981d4 --- /dev/null +++ b/client/tx.go @@ -0,0 +1,42 @@ +package client + +import ( + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +type ( + // ClientMarshaler defines an interface that REST and CLI handler will use to + // create application-specific transactions and be able to serialize types + // specific to the application including transactions. + ClientMarshaler interface { + TxGenerator + codec.Marshaler + } + + // TxGenerator defines an interface a client can utilize to generate an + // application-defined concrete transaction type. The type returned must + // implement ClientTx. + TxGenerator interface { + NewTx() ClientTx + } + + // ClientTx defines an interface which an application-defined concrete transaction + // type must implement. Namely, it must be able to set messages, generate + // signatures, and provide canonical bytes to sign over. The transaction must + // also know how to encode itself. + ClientTx interface { + sdk.Tx + codec.ProtoMarshaler + + SetMsgs(...sdk.Msg) error + GetSignatures() []sdk.Signature + SetSignatures(...sdk.Signature) + GetFee() sdk.Fee + SetFee(sdk.Fee) + GetMemo() string + SetMemo(string) + + CanonicalSignBytes(cid string, num, seq uint64) ([]byte, error) + } +) diff --git a/codec/std/codec.pb.go b/codec/std/codec.pb.go index d5e09db4dc64..4330171f9de1 100644 --- a/codec/std/codec.pb.go +++ b/codec/std/codec.pb.go @@ -581,8 +581,8 @@ func (*Content) XXX_OneofWrappers() []interface{} { // processed by the state-machine. It contains a base of common fields and // repeated set of Message types. type Transaction struct { - Base types.StdTxBase `protobuf:"bytes,1,opt,name=base,proto3" json:"base"` - Msgs []Message `protobuf:"bytes,2,rep,name=msgs,proto3" json:"msgs"` + types.StdTxBase `protobuf:"bytes,1,opt,name=base,proto3,embedded=base" json:""` + Msgs []Message `protobuf:"bytes,2,rep,name=msgs,proto3" json:"msgs"` } func (m *Transaction) Reset() { *m = Transaction{} } @@ -965,100 +965,100 @@ func init() { func init() { proto.RegisterFile("codec/std/codec.proto", fileDescriptor_daf09dc2dfa19bb4) } var fileDescriptor_daf09dc2dfa19bb4 = []byte{ - // 1476 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x58, 0xcd, 0x6f, 0xd4, 0xc6, - 0x1b, 0xf6, 0xc2, 0x92, 0x84, 0x49, 0x80, 0x30, 0x3f, 0xf8, 0x65, 0x95, 0xc2, 0x26, 0x04, 0x8a, - 0x5a, 0x50, 0xd6, 0x7c, 0xb4, 0x85, 0xac, 0x5a, 0x01, 0x49, 0x40, 0x4b, 0xd5, 0xb4, 0xc8, 0x81, - 0x54, 0xad, 0x68, 0xad, 0x59, 0xcf, 0xe0, 0x4c, 0xb3, 0xf6, 0xb8, 0x9e, 0xf1, 0x66, 0x73, 0xe8, - 0xbd, 0xad, 0x54, 0xa9, 0x52, 0xff, 0x01, 0xd4, 0x1e, 0x7b, 0xe5, 0xd8, 0x73, 0x85, 0x38, 0x71, - 0xec, 0x09, 0x55, 0x70, 0xa9, 0xfa, 0x57, 0x54, 0xf3, 0x61, 0xaf, 0xbd, 0xeb, 0xdd, 0x50, 0xa9, - 0x97, 0xc8, 0x33, 0xef, 0xfb, 0x3c, 0xef, 0x33, 0x9e, 0xf7, 0xc3, 0x1b, 0x70, 0xd2, 0x63, 0x98, - 0x78, 0x36, 0x17, 0xd8, 0x56, 0x4f, 0x8d, 0x28, 0x66, 0x82, 0xc1, 0x39, 0x8f, 0xf1, 0x80, 0x71, - 0x97, 0xe3, 0x9d, 0x86, 0xde, 0xe7, 0x02, 0x37, 0xba, 0x97, 0xe7, 0x2f, 0x8a, 0x6d, 0x1a, 0x63, - 0x37, 0x42, 0xb1, 0xd8, 0xb3, 0x95, 0xaf, 0xad, 0x5d, 0x97, 0xf3, 0x0b, 0xcd, 0x32, 0x7f, 0x7e, - 0xd8, 0xd9, 0x67, 0x3e, 0xeb, 0x3f, 0x19, 0xbf, 0x5a, 0xcf, 0x46, 0x89, 0xd8, 0xb6, 0xc5, 0x5e, - 0x44, 0xb8, 0xfe, 0x6b, 0x2c, 0x8b, 0xc6, 0xd2, 0x25, 0x5c, 0xd0, 0xd0, 0x2f, 0xf1, 0xa8, 0xf5, - 0xec, 0x36, 0x0a, 0x77, 0x4a, 0x2c, 0xf3, 0x3d, 0xdb, 0x8b, 0x29, 0xa7, 0xbc, 0x9c, 0x17, 0x53, - 0x2e, 0x62, 0xda, 0x4e, 0x04, 0x65, 0x61, 0x39, 0x9a, 0x27, 0x51, 0xd4, 0xd9, 0x2b, 0xb1, 0x9d, - 0xea, 0xd9, 0xa4, 0x4b, 0x31, 0x09, 0x3d, 0x52, 0x62, 0x9d, 0xeb, 0xd9, 0x3e, 0xeb, 0x96, 0xc3, - 0x78, 0x07, 0xf1, 0xed, 0xf2, 0x83, 0xbc, 0xd1, 0xb3, 0xb9, 0x40, 0x3b, 0xe5, 0xc6, 0xb3, 0x3d, - 0x3b, 0x42, 0x31, 0x0a, 0xd2, 0xb3, 0x44, 0x31, 0x8b, 0x18, 0x47, 0x9d, 0x41, 0x86, 0x24, 0xf2, - 0x63, 0x84, 0x4b, 0x54, 0x2d, 0xfd, 0x56, 0x05, 0x93, 0xb7, 0x3c, 0x8f, 0x25, 0xa1, 0x80, 0x77, - 0xc0, 0x4c, 0x1b, 0x71, 0xe2, 0x22, 0xbd, 0xae, 0x55, 0x16, 0x2b, 0x6f, 0x4d, 0x5f, 0x39, 0xd3, - 0xc8, 0x5d, 0x7a, 0xaf, 0x21, 0xdf, 0x7b, 0xa3, 0x7b, 0xb9, 0xb1, 0x8a, 0x38, 0x31, 0xc0, 0x96, - 0xe5, 0x4c, 0xb7, 0xfb, 0x4b, 0xd8, 0x05, 0xf3, 0x1e, 0x0b, 0x05, 0x0d, 0x13, 0x96, 0x70, 0xd7, - 0xdc, 0x51, 0xc6, 0x7a, 0x40, 0xb1, 0xbe, 0x57, 0xc6, 0xaa, 0x3d, 0x25, 0xfb, 0x5a, 0x86, 0xdf, - 0xd2, 0x9b, 0xfd, 0x50, 0x35, 0x6f, 0x84, 0x0d, 0x06, 0x60, 0x0e, 0x93, 0x0e, 0xda, 0x23, 0x78, - 0x28, 0xe8, 0x41, 0x15, 0xf4, 0xea, 0xf8, 0xa0, 0xeb, 0x1a, 0x3c, 0x14, 0xf1, 0x24, 0x2e, 0x33, - 0xc0, 0x08, 0xd4, 0x22, 0x12, 0x53, 0x86, 0xa9, 0x37, 0x14, 0xaf, 0xaa, 0xe2, 0xbd, 0x33, 0x3e, - 0xde, 0x3d, 0x83, 0x1e, 0x0a, 0xf8, 0xff, 0xa8, 0xd4, 0x02, 0x3f, 0x06, 0x47, 0x03, 0x86, 0x93, - 0x4e, 0xff, 0x8a, 0x0e, 0xa9, 0x38, 0x6f, 0x16, 0xe3, 0xe8, 0x04, 0x95, 0x11, 0x36, 0x94, 0x77, - 0x9f, 0xf8, 0x48, 0x90, 0xdf, 0x68, 0xae, 0x3c, 0x7b, 0xb2, 0xfc, 0xee, 0x05, 0x9f, 0x8a, 0xed, - 0xa4, 0xdd, 0xf0, 0x58, 0x60, 0xca, 0x34, 0x2d, 0x5d, 0x8e, 0x77, 0x6c, 0x53, 0x68, 0xa4, 0x17, - 0xb1, 0x58, 0x10, 0xdc, 0x30, 0xd0, 0xd5, 0x43, 0xe0, 0x20, 0x4f, 0x82, 0xa5, 0xef, 0x2b, 0x60, - 0x62, 0x53, 0x85, 0x83, 0xd7, 0xc1, 0x84, 0x0e, 0x6c, 0xf2, 0xa6, 0x3e, 0x4a, 0x94, 0xf6, 0x6f, - 0x59, 0x8e, 0xf1, 0x6f, 0xde, 0xf8, 0xeb, 0xf1, 0x42, 0xe5, 0xd9, 0x93, 0xe5, 0x6b, 0xfb, 0x49, - 0x31, 0x95, 0x97, 0x89, 0xd1, 0x4c, 0x77, 0x53, 0x31, 0x3f, 0x57, 0xc0, 0xd4, 0x6d, 0x53, 0x80, - 0xf0, 0x23, 0x30, 0x43, 0xbe, 0x4e, 0x68, 0x97, 0x79, 0x48, 0x96, 0xb2, 0x11, 0x75, 0xbe, 0x28, - 0x2a, 0x2d, 0x57, 0x29, 0xeb, 0x76, 0xce, 0xbb, 0x65, 0x39, 0x05, 0x74, 0xf3, 0x96, 0x91, 0xb8, - 0xb2, 0x8f, 0xc2, 0xac, 0xfe, 0x33, 0x8d, 0xa9, 0xa0, 0x54, 0xe4, 0xaf, 0x15, 0x70, 0x7c, 0x83, - 0xfb, 0x9b, 0x49, 0x3b, 0xa0, 0x22, 0x53, 0xfb, 0x01, 0x98, 0x4a, 0xa1, 0x65, 0x65, 0x97, 0xef, - 0xb5, 0x19, 0xa3, 0x93, 0x41, 0xe0, 0x06, 0xa8, 0xca, 0x02, 0x34, 0xb5, 0x65, 0x8f, 0x3e, 0xe4, - 0x50, 0x64, 0x59, 0xc6, 0xab, 0x53, 0x4f, 0x5f, 0x2c, 0x58, 0xcf, 0x5f, 0x2c, 0x54, 0x1c, 0x45, - 0xd3, 0x9c, 0xfa, 0xf6, 0xf1, 0x82, 0x25, 0x4f, 0xbc, 0xf4, 0x4b, 0x5e, 0xed, 0x3d, 0xd3, 0x5d, - 0x60, 0xcb, 0x84, 0xd3, 0x4a, 0x2f, 0x14, 0xc3, 0xf9, 0xac, 0x5b, 0x88, 0x94, 0xa2, 0xca, 0x22, - 0xc1, 0x26, 0x98, 0x94, 0xe5, 0x4c, 0xb2, 0xbe, 0xb0, 0x38, 0xf2, 0xd8, 0x6b, 0xda, 0xcf, 0x49, - 0x01, 0x39, 0x95, 0x3f, 0x55, 0xc0, 0x54, 0x26, 0xee, 0x46, 0x41, 0xdc, 0x99, 0x52, 0x71, 0x63, - 0x35, 0xdd, 0xfc, 0xd7, 0x9a, 0x56, 0xab, 0x92, 0xa2, 0xaf, 0xac, 0xaa, 0x54, 0x3d, 0xae, 0x82, - 0x49, 0xe3, 0x00, 0xaf, 0x81, 0xaa, 0x20, 0x3d, 0x31, 0x56, 0xd4, 0x7d, 0xd2, 0xcb, 0x5e, 0x56, - 0xcb, 0x72, 0x14, 0x00, 0x3e, 0x04, 0xb3, 0xaa, 0xc3, 0x13, 0x41, 0x62, 0xd7, 0xdb, 0x46, 0xa1, - 0x3f, 0xe2, 0x96, 0xf5, 0x1c, 0x50, 0x87, 0x4b, 0xfd, 0xd7, 0x94, 0x7b, 0x8e, 0xf2, 0x58, 0x54, - 0x34, 0xc1, 0x2f, 0xc0, 0x2c, 0x67, 0x8f, 0xc4, 0x2e, 0x8a, 0x89, 0x6b, 0x66, 0x84, 0x69, 0x95, - 0x97, 0x8a, 0xec, 0xc6, 0xa8, 0xca, 0xd7, 0x00, 0x1e, 0xe8, 0xad, 0x3c, 0x3d, 0x2f, 0x9a, 0x60, - 0x04, 0xe6, 0x3c, 0x14, 0x7a, 0xa4, 0xe3, 0x0e, 0x45, 0xa9, 0x96, 0x4d, 0x81, 0x5c, 0x94, 0x35, - 0x85, 0x1b, 0x1d, 0xeb, 0xa4, 0x57, 0xe6, 0x00, 0x3b, 0xe0, 0x84, 0xc7, 0x82, 0x20, 0x09, 0xa9, - 0xd8, 0x73, 0x23, 0xc6, 0x3a, 0x2e, 0x8f, 0x48, 0x88, 0x4d, 0x9f, 0xbc, 0x5e, 0x0c, 0x97, 0x1f, - 0xf5, 0xfa, 0x36, 0x0d, 0xf2, 0x1e, 0x63, 0x9d, 0x4d, 0x89, 0xcb, 0x05, 0x84, 0xde, 0x90, 0xb5, - 0x79, 0xdd, 0x74, 0x85, 0x4b, 0xfb, 0x74, 0x85, 0x6c, 0xee, 0x67, 0x09, 0xd3, 0x6f, 0x9f, 0xd3, - 0xf7, 0x63, 0x14, 0x72, 0xe4, 0x49, 0x11, 0x70, 0xa5, 0x90, 0xbb, 0x0b, 0xe5, 0x93, 0x77, 0x53, - 0xe0, 0xfb, 0x3d, 0x95, 0xb9, 0x3a, 0xed, 0xd2, 0x4a, 0xaa, 0x06, 0xdc, 0xe7, 0xb5, 0x03, 0x8b, - 0x07, 0xc7, 0xa6, 0xec, 0x06, 0xe1, 0x1c, 0xf9, 0x19, 0x56, 0x62, 0x9a, 0x55, 0x59, 0x49, 0x4b, - 0xbf, 0xcf, 0x80, 0x49, 0x63, 0x85, 0x4d, 0x30, 0x15, 0x70, 0xdf, 0xe5, 0xf2, 0xdd, 0x69, 0x31, - 0xa7, 0x8b, 0x62, 0xe4, 0xc7, 0x55, 0x5a, 0xe6, 0x24, 0xc4, 0x2d, 0xcb, 0x99, 0x0c, 0xf4, 0x23, - 0xfc, 0x10, 0x1c, 0x95, 0xd8, 0x20, 0xe9, 0x08, 0xaa, 0x19, 0x74, 0xc2, 0x2e, 0x8d, 0x64, 0xd8, - 0x90, 0xae, 0x86, 0x66, 0x26, 0xc8, 0xad, 0xe1, 0x97, 0xe0, 0x84, 0xe4, 0xea, 0x92, 0x98, 0x3e, - 0xda, 0x73, 0x69, 0xd8, 0x45, 0x31, 0x45, 0xd9, 0x3c, 0x1f, 0xe8, 0x3c, 0xfa, 0xb3, 0xce, 0x70, - 0x6e, 0x29, 0xc8, 0xdd, 0x14, 0x21, 0x6f, 0x30, 0x18, 0xda, 0x85, 0x21, 0xa8, 0xe9, 0x73, 0x0a, - 0x77, 0x97, 0x8a, 0x6d, 0x1c, 0xa3, 0x5d, 0x17, 0x61, 0x1c, 0x13, 0xce, 0x4d, 0x8a, 0x5e, 0x1d, - 0x9f, 0x33, 0xea, 0xfc, 0xe2, 0x53, 0x83, 0xbd, 0xa5, 0xa1, 0x32, 0x3f, 0x83, 0x32, 0x03, 0xfc, - 0x06, 0x9c, 0x96, 0xf1, 0xb2, 0x58, 0x98, 0x74, 0x88, 0x8f, 0x04, 0x8b, 0xdd, 0x98, 0xec, 0xa2, - 0xf8, 0x35, 0x13, 0x75, 0x83, 0xfb, 0x29, 0xf1, 0x7a, 0x4a, 0xe0, 0x28, 0x7c, 0xcb, 0x72, 0xe6, - 0x83, 0x91, 0x56, 0xf8, 0x5d, 0x05, 0x9c, 0x29, 0xc4, 0xef, 0xa2, 0x0e, 0xc5, 0x2a, 0xbe, 0x4c, - 0x6f, 0xca, 0xb9, 0x1c, 0x95, 0x13, 0x4a, 0xc3, 0xfb, 0xaf, 0xad, 0x61, 0x2b, 0x25, 0x59, 0xcb, - 0x38, 0x5a, 0x96, 0x53, 0x0f, 0xc6, 0x7a, 0xc0, 0x1d, 0x30, 0x27, 0xa5, 0x3c, 0x4a, 0x42, 0xec, - 0x16, 0x6b, 0xb6, 0x36, 0xa9, 0x04, 0x5c, 0xd9, 0x57, 0xc0, 0x9d, 0x24, 0xc4, 0x85, 0xa2, 0x6d, - 0x59, 0x8e, 0xcc, 0x97, 0xa1, 0x7d, 0xf8, 0x10, 0xfc, 0x4f, 0xdd, 0xb3, 0x9a, 0x48, 0x6e, 0x36, - 0x6a, 0xa7, 0x86, 0xd3, 0xa8, 0x58, 0x2c, 0x83, 0xe3, 0xb2, 0x65, 0x39, 0xc7, 0x83, 0xa1, 0xe9, - 0x5d, 0x64, 0x4f, 0x3f, 0xc2, 0x6b, 0x87, 0x5f, 0x97, 0x3d, 0xd7, 0x66, 0xfa, 0xec, 0xd9, 0x40, - 0x5b, 0xd1, 0xb5, 0xd8, 0x65, 0x82, 0xd4, 0x80, 0xa2, 0x3c, 0x35, 0x6a, 0xe2, 0x6e, 0x31, 0x41, - 0x4c, 0x29, 0xca, 0x47, 0xb8, 0x0a, 0xa6, 0x25, 0x14, 0x93, 0x88, 0x71, 0x2a, 0x6a, 0xd3, 0x65, - 0x6d, 0xa5, 0x8f, 0x5e, 0xd7, 0x6e, 0x2d, 0xcb, 0x01, 0x41, 0xb6, 0x82, 0xeb, 0x40, 0xae, 0xdc, - 0x24, 0xfc, 0x0a, 0xd1, 0x4e, 0x6d, 0x46, 0x51, 0x9c, 0x1d, 0xf8, 0xb6, 0x33, 0x3f, 0x5f, 0x0c, - 0xcf, 0x03, 0xe5, 0xda, 0xb2, 0x9c, 0xc3, 0x41, 0xba, 0x80, 0xae, 0x2e, 0x64, 0x2f, 0x26, 0x48, - 0x90, 0x7e, 0xda, 0xd5, 0x8e, 0x28, 0xbe, 0x8b, 0x03, 0x7c, 0xfa, 0x07, 0x8f, 0xa1, 0x5b, 0x53, - 0x98, 0x2c, 0x85, 0x4c, 0x25, 0x0f, 0xec, 0xc2, 0xcf, 0x80, 0xdc, 0x75, 0x09, 0xa6, 0x22, 0x47, - 0x7f, 0x54, 0xd1, 0xbf, 0x3d, 0x8e, 0xfe, 0x36, 0xa6, 0x22, 0x4f, 0x3e, 0x1b, 0x0c, 0xec, 0xc1, - 0xbb, 0x60, 0x46, 0xbf, 0x45, 0x55, 0x4c, 0xa4, 0x76, 0x4c, 0x91, 0x9e, 0x1b, 0x47, 0x6a, 0x0a, - 0x4f, 0x5e, 0xc6, 0x74, 0xd0, 0x5f, 0xa6, 0xaf, 0xa1, 0x4d, 0x7c, 0x1a, 0xba, 0x31, 0xc9, 0x28, - 0x67, 0xf7, 0x7f, 0x0d, 0xab, 0x12, 0xe3, 0x64, 0x10, 0xf3, 0x1a, 0x06, 0x76, 0xe1, 0x27, 0xba, - 0xf9, 0x26, 0x61, 0x46, 0x7d, 0xbc, 0xec, 0xc3, 0xb7, 0x48, 0xfd, 0x20, 0xcc, 0xb1, 0x1e, 0x09, - 0xf2, 0x1b, 0xcd, 0x0b, 0xcf, 0x9e, 0x2c, 0x9f, 0x1f, 0x3b, 0xdf, 0xf4, 0x64, 0x93, 0x0a, 0xcd, - 0x54, 0xfb, 0xa1, 0x02, 0x26, 0x37, 0xa9, 0x1f, 0xae, 0x33, 0x0f, 0xde, 0x29, 0x4c, 0xb4, 0x73, - 0x23, 0x27, 0x9a, 0xf1, 0x57, 0x63, 0x6d, 0x26, 0xfd, 0x20, 0xfb, 0xfb, 0x3f, 0x19, 0x6f, 0xab, - 0x37, 0x9f, 0xbe, 0xac, 0x57, 0x9e, 0xbf, 0xac, 0x57, 0xfe, 0x7c, 0x59, 0xaf, 0xfc, 0xf8, 0xaa, - 0x6e, 0x3d, 0x7f, 0x55, 0xb7, 0xfe, 0x78, 0x55, 0xb7, 0x3e, 0x1f, 0x7f, 0xb0, 0xec, 0x7f, 0x20, - 0xed, 0x09, 0xf5, 0x63, 0xf9, 0xea, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x8c, 0xf7, 0xe4, 0x03, - 0x17, 0x11, 0x00, 0x00, + // 1478 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0xcd, 0x6f, 0xd4, 0x46, + 0x1b, 0xf7, 0xc2, 0x92, 0x84, 0x49, 0x80, 0x30, 0x2f, 0xbc, 0x59, 0xe5, 0x85, 0x4d, 0x08, 0xbc, + 0xa8, 0x05, 0x65, 0xcd, 0x47, 0x5b, 0x60, 0xd5, 0x0a, 0xf2, 0x01, 0x5a, 0xaa, 0xa6, 0x45, 0x0e, + 0xa4, 0x6a, 0x45, 0x6b, 0xcd, 0x7a, 0x06, 0x67, 0x9a, 0xb5, 0xc7, 0xf5, 0x8c, 0x37, 0x9b, 0x43, + 0xef, 0x6d, 0xa5, 0x4a, 0x55, 0xfb, 0x0f, 0xa0, 0xf6, 0xd8, 0x2b, 0xc7, 0x9e, 0x2b, 0xc4, 0x89, + 0x63, 0x4f, 0xa8, 0x82, 0x4b, 0xd5, 0xbf, 0xa2, 0x9a, 0x0f, 0x7b, 0xed, 0x5d, 0xef, 0x86, 0x1e, + 0x7a, 0x89, 0x3c, 0xf3, 0x3c, 0xbf, 0xdf, 0xf3, 0x1b, 0xcf, 0xf3, 0xe1, 0x0d, 0x38, 0xe9, 0x31, + 0x4c, 0x3c, 0x9b, 0x0b, 0x6c, 0xab, 0xa7, 0x46, 0x14, 0x33, 0xc1, 0xe0, 0x9c, 0xc7, 0x78, 0xc0, + 0xb8, 0xcb, 0xf1, 0x4e, 0x43, 0xef, 0x73, 0x81, 0x1b, 0xdd, 0xcb, 0xf3, 0x17, 0xc5, 0x36, 0x8d, + 0xb1, 0x1b, 0xa1, 0x58, 0xec, 0xd9, 0xca, 0xd7, 0xd6, 0xae, 0xcb, 0xf9, 0x85, 0x66, 0x99, 0x3f, + 0x3f, 0xec, 0xec, 0x33, 0x9f, 0xf5, 0x9f, 0x8c, 0x5f, 0xad, 0x67, 0xa3, 0x44, 0x6c, 0xdb, 0x62, + 0x2f, 0x22, 0x5c, 0xff, 0x35, 0x96, 0x45, 0x63, 0xe9, 0x12, 0x2e, 0x68, 0xe8, 0x97, 0x78, 0xd4, + 0x7a, 0x76, 0x1b, 0x85, 0x3b, 0x25, 0x96, 0xf9, 0x9e, 0xed, 0xc5, 0x94, 0x53, 0x5e, 0xce, 0x8b, + 0x29, 0x17, 0x31, 0x6d, 0x27, 0x82, 0xb2, 0xb0, 0x1c, 0xcd, 0x93, 0x28, 0xea, 0xec, 0x95, 0xd8, + 0x4e, 0xf5, 0x6c, 0xd2, 0xa5, 0x98, 0x84, 0x1e, 0x29, 0xb1, 0xce, 0xf5, 0x6c, 0x9f, 0x75, 0xcb, + 0x61, 0xbc, 0x83, 0xf8, 0x76, 0xf9, 0x41, 0xfe, 0xd7, 0xb3, 0xb9, 0x40, 0x3b, 0xe5, 0xc6, 0xb3, + 0x3d, 0x3b, 0x42, 0x31, 0x0a, 0xd2, 0xb3, 0x44, 0x31, 0x8b, 0x18, 0x47, 0x9d, 0x41, 0x86, 0x24, + 0xf2, 0x63, 0x84, 0x4b, 0x54, 0x2d, 0xfd, 0x5a, 0x05, 0x93, 0x2b, 0x9e, 0xc7, 0x92, 0x50, 0xc0, + 0x3b, 0x60, 0xa6, 0x8d, 0x38, 0x71, 0x91, 0x5e, 0xd7, 0x2a, 0x8b, 0x95, 0x37, 0xa6, 0xaf, 0x9c, + 0x69, 0xe4, 0x2e, 0xbd, 0xd7, 0x90, 0xef, 0xbd, 0xd1, 0xbd, 0xdc, 0x58, 0x45, 0x9c, 0x18, 0x60, + 0xcb, 0x72, 0xa6, 0xdb, 0xfd, 0x25, 0xec, 0x82, 0x79, 0x8f, 0x85, 0x82, 0x86, 0x09, 0x4b, 0xb8, + 0x6b, 0xee, 0x28, 0x63, 0x3d, 0xa0, 0x58, 0xdf, 0x29, 0x63, 0xd5, 0x9e, 0x92, 0x7d, 0x2d, 0xc3, + 0x6f, 0xe9, 0xcd, 0x7e, 0xa8, 0x9a, 0x37, 0xc2, 0x06, 0x03, 0x30, 0x87, 0x49, 0x07, 0xed, 0x11, + 0x3c, 0x14, 0xf4, 0xa0, 0x0a, 0x7a, 0x75, 0x7c, 0xd0, 0x75, 0x0d, 0x1e, 0x8a, 0x78, 0x12, 0x97, + 0x19, 0x60, 0x04, 0x6a, 0x11, 0x89, 0x29, 0xc3, 0xd4, 0x1b, 0x8a, 0x57, 0x55, 0xf1, 0xde, 0x1a, + 0x1f, 0xef, 0x9e, 0x41, 0x0f, 0x05, 0xfc, 0x6f, 0x54, 0x6a, 0x81, 0x1f, 0x82, 0xa3, 0x01, 0xc3, + 0x49, 0xa7, 0x7f, 0x45, 0x87, 0x54, 0x9c, 0xff, 0x17, 0xe3, 0xe8, 0x04, 0x95, 0x11, 0x36, 0x94, + 0x77, 0x9f, 0xf8, 0x48, 0x90, 0xdf, 0x68, 0xde, 0x78, 0xf6, 0x64, 0xf9, 0xed, 0x0b, 0x3e, 0x15, + 0xdb, 0x49, 0xbb, 0xe1, 0xb1, 0xc0, 0x94, 0x69, 0x5a, 0xba, 0x1c, 0xef, 0xd8, 0xa6, 0xd0, 0x48, + 0x2f, 0x62, 0xb1, 0x20, 0xb8, 0x61, 0xa0, 0xab, 0x87, 0xc0, 0x41, 0x9e, 0x04, 0x4b, 0xdf, 0x56, + 0xc0, 0xc4, 0xa6, 0x0a, 0x07, 0xaf, 0x83, 0x09, 0x1d, 0xd8, 0xe4, 0x4d, 0x7d, 0x94, 0x28, 0xed, + 0xdf, 0xb2, 0x1c, 0xe3, 0xdf, 0xbc, 0xf9, 0xe7, 0xe3, 0x85, 0xca, 0xb3, 0x27, 0xcb, 0xd7, 0xf6, + 0x93, 0x62, 0x2a, 0x2f, 0x13, 0xa3, 0x99, 0xee, 0xa6, 0x62, 0x7e, 0xaa, 0x80, 0xa9, 0xdb, 0xa6, + 0x00, 0xe1, 0x07, 0x60, 0x86, 0x7c, 0x99, 0xd0, 0x2e, 0xf3, 0x90, 0x2c, 0x65, 0x23, 0xea, 0x7c, + 0x51, 0x54, 0x5a, 0xae, 0x52, 0xd6, 0xed, 0x9c, 0x77, 0xcb, 0x72, 0x0a, 0xe8, 0xe6, 0x8a, 0x91, + 0x78, 0x63, 0x1f, 0x85, 0x59, 0xfd, 0x67, 0x1a, 0x53, 0x41, 0xa9, 0xc8, 0x5f, 0x2a, 0xe0, 0xf8, + 0x06, 0xf7, 0x37, 0x93, 0x76, 0x40, 0x45, 0xa6, 0xf6, 0x3d, 0x30, 0x95, 0x42, 0xcb, 0xca, 0x2e, + 0xdf, 0x6b, 0x33, 0x46, 0x27, 0x83, 0xc0, 0x0d, 0x50, 0x95, 0x05, 0x68, 0x6a, 0xcb, 0x1e, 0x7d, + 0xc8, 0xa1, 0xc8, 0xb2, 0x8c, 0x57, 0xa7, 0x9e, 0xbe, 0x58, 0xb0, 0x9e, 0xbf, 0x58, 0xa8, 0x38, + 0x8a, 0xa6, 0x39, 0xf5, 0xf5, 0xe3, 0x05, 0x4b, 0x9e, 0x78, 0xe9, 0xe7, 0xbc, 0xda, 0x7b, 0xa6, + 0xbb, 0xc0, 0x96, 0x09, 0xa7, 0x95, 0x5e, 0x28, 0x86, 0xf3, 0x59, 0xb7, 0x10, 0x29, 0x45, 0x95, + 0x45, 0x82, 0x4d, 0x30, 0x29, 0xcb, 0x99, 0x64, 0x7d, 0x61, 0x71, 0xe4, 0xb1, 0xd7, 0xb4, 0x9f, + 0x93, 0x02, 0x72, 0x2a, 0x7f, 0xac, 0x80, 0xa9, 0x4c, 0xdc, 0xcd, 0x82, 0xb8, 0x33, 0xa5, 0xe2, + 0xc6, 0x6a, 0xba, 0xf5, 0x8f, 0x35, 0xad, 0x56, 0x25, 0x45, 0x5f, 0x59, 0x55, 0xa9, 0x7a, 0x5c, + 0x05, 0x93, 0xc6, 0x01, 0x5e, 0x03, 0x55, 0x41, 0x7a, 0x62, 0xac, 0xa8, 0xfb, 0xa4, 0x97, 0xbd, + 0xac, 0x96, 0xe5, 0x28, 0x00, 0x7c, 0x08, 0x66, 0x55, 0x87, 0x27, 0x82, 0xc4, 0xae, 0xb7, 0x8d, + 0x42, 0x7f, 0xc4, 0x2d, 0xeb, 0x39, 0xa0, 0x0e, 0x97, 0xfa, 0xaf, 0x29, 0xf7, 0x1c, 0xe5, 0xb1, + 0xa8, 0x68, 0x82, 0x9f, 0x81, 0x59, 0xce, 0x1e, 0x89, 0x5d, 0x14, 0x13, 0xd7, 0xcc, 0x08, 0xd3, + 0x2a, 0x2f, 0x15, 0xd9, 0x8d, 0x51, 0x95, 0xaf, 0x01, 0x3c, 0xd0, 0x5b, 0x79, 0x7a, 0x5e, 0x34, + 0xc1, 0x08, 0xcc, 0x79, 0x28, 0xf4, 0x48, 0xc7, 0x1d, 0x8a, 0x52, 0x2d, 0x9b, 0x02, 0xb9, 0x28, + 0x6b, 0x0a, 0x37, 0x3a, 0xd6, 0x49, 0xaf, 0xcc, 0x01, 0x76, 0xc0, 0x09, 0x8f, 0x05, 0x41, 0x12, + 0x52, 0xb1, 0xe7, 0x46, 0x8c, 0x75, 0x5c, 0x1e, 0x91, 0x10, 0x9b, 0x3e, 0x79, 0xbd, 0x18, 0x2e, + 0x3f, 0xea, 0xf5, 0x6d, 0x1a, 0xe4, 0x3d, 0xc6, 0x3a, 0x9b, 0x12, 0x97, 0x0b, 0x08, 0xbd, 0x21, + 0x6b, 0xf3, 0xba, 0xe9, 0x0a, 0x97, 0xf6, 0xe9, 0x0a, 0xd9, 0xdc, 0xcf, 0x12, 0xc6, 0x34, 0x83, + 0x1f, 0x2a, 0x60, 0xfa, 0x7e, 0x8c, 0x42, 0x8e, 0x3c, 0x29, 0x02, 0xae, 0x14, 0x72, 0x77, 0xa1, + 0x7c, 0xf2, 0x6e, 0x0a, 0x7c, 0xbf, 0xa7, 0x32, 0x77, 0x26, 0xcd, 0xdc, 0xbf, 0x64, 0xfa, 0xa5, + 0x15, 0x55, 0x0d, 0xb8, 0xcf, 0x6b, 0x07, 0x16, 0x0f, 0x8e, 0x4d, 0xdd, 0x0d, 0xc2, 0x39, 0xf2, + 0x89, 0x49, 0x5d, 0x85, 0x69, 0x56, 0x65, 0x45, 0x2d, 0xfd, 0x36, 0x03, 0x26, 0x8d, 0x15, 0x36, + 0xc1, 0x54, 0xc0, 0x7d, 0x97, 0xcb, 0x77, 0xa8, 0x45, 0x9d, 0x2e, 0x8a, 0x92, 0x1f, 0x59, 0x69, + 0xb9, 0x93, 0x10, 0xb7, 0x2c, 0x67, 0x32, 0xd0, 0x8f, 0xf0, 0x7d, 0x70, 0x54, 0x62, 0x83, 0xa4, + 0x23, 0xa8, 0x66, 0xd0, 0x89, 0xbb, 0x34, 0x92, 0x61, 0x43, 0xba, 0x1a, 0x9a, 0x99, 0x20, 0xb7, + 0x86, 0x9f, 0x83, 0x13, 0x92, 0xab, 0x4b, 0x62, 0xfa, 0x68, 0xcf, 0xa5, 0x61, 0x17, 0xc5, 0x14, + 0x65, 0x73, 0x7d, 0xa0, 0x03, 0xe9, 0xcf, 0x3b, 0xc3, 0xb9, 0xa5, 0x20, 0x77, 0x53, 0x84, 0xbc, + 0xc9, 0x60, 0x68, 0x17, 0x86, 0xa0, 0xa6, 0xcf, 0x29, 0xdc, 0x5d, 0x2a, 0xb6, 0x71, 0x8c, 0x76, + 0x5d, 0x84, 0x71, 0x4c, 0x38, 0x37, 0xa9, 0x7a, 0x75, 0x7c, 0xee, 0xa8, 0xf3, 0x8b, 0x8f, 0x0d, + 0x76, 0x45, 0x43, 0x65, 0x9e, 0x06, 0x65, 0x06, 0xf8, 0x15, 0x38, 0x2d, 0xe3, 0x65, 0xb1, 0x30, + 0xe9, 0x10, 0x1f, 0x09, 0x16, 0xbb, 0x31, 0xd9, 0x45, 0xf1, 0x6b, 0x26, 0xec, 0x06, 0xf7, 0x53, + 0xe2, 0xf5, 0x94, 0xc0, 0x51, 0xf8, 0x96, 0xe5, 0xcc, 0x07, 0x23, 0xad, 0xf0, 0x9b, 0x0a, 0x38, + 0x53, 0x88, 0xdf, 0x45, 0x1d, 0x8a, 0x55, 0x7c, 0x99, 0xe6, 0x94, 0x73, 0x39, 0x32, 0x27, 0x94, + 0x86, 0x77, 0x5f, 0x5b, 0xc3, 0x56, 0x4a, 0xb2, 0x96, 0x71, 0xb4, 0x2c, 0xa7, 0x1e, 0x8c, 0xf5, + 0x80, 0x3b, 0x60, 0x4e, 0x4a, 0x79, 0x94, 0x84, 0xd8, 0x2d, 0xd6, 0x6e, 0x6d, 0x52, 0x09, 0xb8, + 0xb2, 0xaf, 0x80, 0x3b, 0x49, 0x88, 0x0b, 0xc5, 0xdb, 0xb2, 0x1c, 0x99, 0x2f, 0x43, 0xfb, 0xf0, + 0x21, 0xf8, 0x8f, 0xba, 0x67, 0x35, 0x99, 0xdc, 0x6c, 0xe4, 0x4e, 0x0d, 0xa7, 0x51, 0xb1, 0x58, + 0x06, 0xc7, 0x66, 0xcb, 0x72, 0x8e, 0x07, 0x43, 0x53, 0xbc, 0xc8, 0x9e, 0x7e, 0x8c, 0xd7, 0x0e, + 0xbf, 0x2e, 0x7b, 0xae, 0xdd, 0xf4, 0xd9, 0xb3, 0xc1, 0x76, 0x43, 0xd7, 0x62, 0x97, 0x09, 0x52, + 0x03, 0x8a, 0xf2, 0xd4, 0xa8, 0xc9, 0xbb, 0xc5, 0x04, 0x31, 0xa5, 0x28, 0x1f, 0xe1, 0x2a, 0x98, + 0x96, 0x50, 0x4c, 0x22, 0xc6, 0xa9, 0xa8, 0x4d, 0x97, 0xb5, 0x97, 0x3e, 0x7a, 0x5d, 0xbb, 0xb5, + 0x2c, 0x07, 0x04, 0xd9, 0x0a, 0xae, 0x03, 0xb9, 0x72, 0x93, 0xf0, 0x0b, 0x44, 0x3b, 0xb5, 0x19, + 0x45, 0x71, 0x76, 0xe0, 0x1b, 0xcf, 0xfc, 0x8c, 0x31, 0x3c, 0x0f, 0x94, 0x6b, 0xcb, 0x72, 0x0e, + 0x07, 0xe9, 0x02, 0xba, 0xba, 0x90, 0xbd, 0x98, 0x20, 0x41, 0xfa, 0x69, 0x57, 0x3b, 0xa2, 0xf8, + 0x2e, 0x0e, 0xf0, 0xe9, 0x1f, 0x3e, 0x86, 0x6e, 0x4d, 0x61, 0xb2, 0x14, 0x32, 0x95, 0x3c, 0xb0, + 0x0b, 0x3f, 0x01, 0x72, 0xd7, 0x25, 0x98, 0x8a, 0x1c, 0xfd, 0x51, 0x45, 0xff, 0xe6, 0x38, 0xfa, + 0xdb, 0x98, 0x8a, 0x3c, 0xf9, 0x6c, 0x30, 0xb0, 0x07, 0xef, 0x82, 0x19, 0xfd, 0x16, 0x55, 0x31, + 0x91, 0xda, 0x31, 0x45, 0x7a, 0x6e, 0x1c, 0xa9, 0x29, 0x3c, 0x79, 0x19, 0xd3, 0x41, 0x7f, 0x99, + 0xbe, 0x86, 0x36, 0xf1, 0x69, 0xe8, 0xc6, 0x24, 0xa3, 0x9c, 0xdd, 0xff, 0x35, 0xac, 0x4a, 0x8c, + 0x93, 0x41, 0xcc, 0x6b, 0x18, 0xd8, 0x85, 0x1f, 0xe9, 0xe6, 0x9b, 0x84, 0x19, 0xf5, 0xf1, 0xb2, + 0x0f, 0xe0, 0x22, 0xf5, 0x83, 0x30, 0xc7, 0x7a, 0x24, 0xc8, 0x6f, 0x34, 0x2f, 0x3c, 0x7b, 0xb2, + 0x7c, 0x7e, 0xec, 0x9c, 0xd3, 0x13, 0x4e, 0x2a, 0x34, 0xd3, 0xed, 0xbb, 0x0a, 0x98, 0xdc, 0xa4, + 0x7e, 0xb8, 0xce, 0x3c, 0x78, 0xa7, 0x30, 0xd9, 0xce, 0x8d, 0x9c, 0x6c, 0xc6, 0xff, 0xdf, 0x18, + 0x6f, 0xab, 0xb7, 0x9e, 0xbe, 0xac, 0x57, 0x9e, 0xbf, 0xac, 0x57, 0xfe, 0x78, 0x59, 0xaf, 0x7c, + 0xff, 0xaa, 0x6e, 0x3d, 0x7f, 0x55, 0xb7, 0x7e, 0x7f, 0x55, 0xb7, 0x3e, 0x1d, 0x7f, 0xb0, 0xec, + 0x7f, 0x21, 0xed, 0x09, 0xf5, 0xa3, 0xf9, 0xea, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x54, 0x48, + 0xa8, 0xb7, 0x1f, 0x11, 0x00, 0x00, } func (this *Supply) Equal(that interface{}) bool { @@ -2261,7 +2261,7 @@ func (m *Transaction) MarshalToSizedBuffer(dAtA []byte) (int, error) { } } { - size, err := m.Base.MarshalToSizedBuffer(dAtA[:i]) + size, err := m.StdTxBase.MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -2965,7 +2965,7 @@ func (m *Transaction) Size() (n int) { } var l int _ = l - l = m.Base.Size() + l = m.StdTxBase.Size() n += 1 + l + sovCodec(uint64(l)) if len(m.Msgs) > 0 { for _, e := range m.Msgs { @@ -4241,7 +4241,7 @@ func (m *Transaction) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Base", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field StdTxBase", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -4268,7 +4268,7 @@ func (m *Transaction) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Base.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.StdTxBase.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex diff --git a/codec/std/codec.proto b/codec/std/codec.proto index f5ec7b9878a4..4f3f8034ad4d 100644 --- a/codec/std/codec.proto +++ b/codec/std/codec.proto @@ -106,8 +106,9 @@ message Content { message Transaction { option (gogoproto.goproto_getters) = false; - cosmos_sdk.x.auth.v1.StdTxBase base = 1 [(gogoproto.nullable) = false]; - repeated Message msgs = 2 [(gogoproto.nullable) = false]; + cosmos_sdk.x.auth.v1.StdTxBase base = 1 + [(gogoproto.jsontag) = "", (gogoproto.embed) = true, (gogoproto.nullable) = false]; + repeated Message msgs = 2 [(gogoproto.nullable) = false]; } // Message defines the set of valid concrete message types that can be used to diff --git a/docs/architecture/adr-020-protobuf-transaction-encoding.md b/docs/architecture/adr-020-protobuf-transaction-encoding.md index 1244cf24d2bd..6fd37bda8c32 100644 --- a/docs/architecture/adr-020-protobuf-transaction-encoding.md +++ b/docs/architecture/adr-020-protobuf-transaction-encoding.md @@ -104,7 +104,6 @@ and messages. ```go type TxGenerator interface { NewTx() ClientTx - SignBytes func(chainID string, num, seq uint64, fee StdFee, msgs []sdk.Msg, memo string) ([]byte, error) } type ClientTx interface { @@ -112,12 +111,14 @@ type ClientTx interface { codec.ProtoMarshaler SetMsgs(...sdk.Msg) error - GetSignatures() []StdSignature - SetSignatures(...StdSignature) error - GetFee() StdFee - SetFee(StdFee) + GetSignatures() []sdk.Signature + SetSignatures(...sdk.Signature) + GetFee() sdk.Fee + SetFee(sdk.Fee) GetMemo() string SetMemo(string) + + CanonicalSignBytes(cid string, num, seq uint64) ([]byte, error) } ``` diff --git a/types/tx_msg.go b/types/tx_msg.go index 1b0da612b736..20ead7db1945 100644 --- a/types/tx_msg.go +++ b/types/tx_msg.go @@ -2,45 +2,60 @@ package types import ( "encoding/json" + + "github.com/tendermint/tendermint/crypto" ) -// Transactions messages must fulfill the Msg -type Msg interface { +type ( +// Msg defines the interface a transaction message must fulfill. + Msg interface { - // Return the message type. - // Must be alphanumeric or empty. - Route() string + // Return the message type. + // Must be alphanumeric or empty. + Route() string - // Returns a human-readable string for the message, intended for utilization - // within tags - Type() string + // Returns a human-readable string for the message, intended for utilization + // within tags + Type() string - // ValidateBasic does a simple validation check that - // doesn't require access to any other information. - ValidateBasic() error + // ValidateBasic does a simple validation check that + // doesn't require access to any other information. + ValidateBasic() error - // Get the canonical byte representation of the Msg. - GetSignBytes() []byte + // Get the canonical byte representation of the Msg. + GetSignBytes() []byte - // Signers returns the addrs of signers that must sign. - // CONTRACT: All signatures must be present to be valid. - // CONTRACT: Returns addrs in some deterministic order. - GetSigners() []AccAddress -} + // Signers returns the addrs of signers that must sign. + // CONTRACT: All signatures must be present to be valid. + // CONTRACT: Returns addrs in some deterministic order. + GetSigners() []AccAddress + } -//__________________________________________________________ + // Fee defines an interface for an application application-defined concrete + // transaction type to be able to set and return the transaction fee. + Fee interface { + GetGas() uint64 + GetAmount() Coins + } -// Transactions objects must fulfill the Tx -type Tx interface { - // Gets the all the transaction's messages. - GetMsgs() []Msg + // Signature defines an interface for an application application-defined + // concrete transaction type to be able to set and return transaction signatures. + Signature interface { + GetPubKey() crypto.PubKey + GetSignature() []byte + } - // ValidateBasic does a simple and lightweight validation check that doesn't - // require access to any other information. - ValidateBasic() error -} +// Tx defines the interface a transaction must fulfill. + Tx interface { + // Gets the all the transaction's messages. + GetMsgs() []Msg + + // ValidateBasic does a simple and lightweight validation check that doesn't + // require access to any other information. + ValidateBasic() error + } +) -//__________________________________________________________ // TxDecoder unmarshals transaction bytes type TxDecoder func(txBytes []byte) (Tx, error) diff --git a/x/auth/alias.go b/x/auth/alias.go index ce005797b3be..e34b9ec68d3c 100644 --- a/x/auth/alias.go +++ b/x/auth/alias.go @@ -59,6 +59,9 @@ var ( MakeSignature = types.MakeSignature ValidateGenAccounts = types.ValidateGenAccounts GetGenesisStateFromAppState = types.GetGenesisStateFromAppState + NewStdSignature = types.NewStdSignature + NewStdTxBase = types.NewStdTxBase + NewStdSignDocBase = types.NewStdSignDocBase // variable aliases ModuleCdc = types.ModuleCdc @@ -89,4 +92,5 @@ type ( GenesisAccountIterator = types.GenesisAccountIterator Codec = types.Codec StdSignDocBase = types.StdSignDocBase + StdTxBase = types.StdTxBase ) diff --git a/x/auth/types/types.pb.go b/x/auth/types/types.pb.go index 699182bc8db3..69e8d5a86018 100644 --- a/x/auth/types/types.pb.go +++ b/x/auth/types/types.pb.go @@ -108,20 +108,6 @@ func (m *StdFee) XXX_DiscardUnknown() { var xxx_messageInfo_StdFee proto.InternalMessageInfo -func (m *StdFee) GetAmount() github_com_cosmos_cosmos_sdk_types.Coins { - if m != nil { - return m.Amount - } - return nil -} - -func (m *StdFee) GetGas() uint64 { - if m != nil { - return m.Gas - } - return 0 -} - // StdSignature defines a signature structure that contains the signature of a // transaction and an optional public key. type StdSignature struct { @@ -391,56 +377,56 @@ func init() { proto.RegisterFile("x/auth/types/types.proto", fileDescriptor_2d52 var fileDescriptor_2d526fa662daab74 = []byte{ // 803 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x55, 0xcf, 0x6f, 0x1b, 0x45, - 0x14, 0xf6, 0xc6, 0x5b, 0x27, 0x99, 0x84, 0x42, 0x26, 0x6e, 0xeb, 0x5a, 0xd1, 0x8e, 0xb5, 0x07, - 0x64, 0x24, 0xb2, 0xc6, 0x86, 0x20, 0xc5, 0x07, 0x44, 0xd6, 0xa1, 0xa2, 0x2a, 0x54, 0xd5, 0x18, - 0x71, 0x40, 0x42, 0xab, 0xf1, 0xee, 0x74, 0xbd, 0x72, 0xd6, 0xbb, 0xdd, 0x99, 0x8d, 0xbc, 0xb9, - 0x70, 0x45, 0x9c, 0x38, 0x72, 0x23, 0x67, 0xfe, 0x92, 0x1e, 0x7b, 0xe4, 0xb4, 0x45, 0xce, 0x05, - 0x71, 0x5c, 0x6e, 0x9c, 0xd0, 0xcc, 0xf8, 0x67, 0x71, 0x11, 0xa8, 0x17, 0x7b, 0xe6, 0xcd, 0xfb, - 0xbe, 0xf7, 0xfc, 0xcd, 0x37, 0xcf, 0xa0, 0x36, 0x69, 0x91, 0x94, 0x0f, 0x5b, 0x3c, 0x8b, 0x29, - 0x53, 0x9f, 0x56, 0x9c, 0x44, 0x3c, 0x82, 0x55, 0x37, 0x62, 0x61, 0xc4, 0x1c, 0xe6, 0x8d, 0xac, - 0x89, 0x25, 0x92, 0xac, 0xcb, 0x76, 0xfd, 0x5d, 0x3e, 0x0c, 0x12, 0xcf, 0x89, 0x49, 0xc2, 0xb3, - 0x96, 0x4c, 0x6c, 0xf9, 0x91, 0x1f, 0x2d, 0x57, 0x0a, 0x5d, 0x3f, 0xf8, 0x07, 0xa1, 0xf9, 0xc3, - 0x16, 0xd8, 0xb3, 0x09, 0xa3, 0x67, 0xae, 0x1b, 0xa5, 0x63, 0x0e, 0x1f, 0x81, 0x6d, 0xe2, 0x79, - 0x09, 0x65, 0xac, 0xa6, 0x35, 0xb4, 0xe6, 0xbe, 0xdd, 0xfe, 0x2b, 0x47, 0xc7, 0x7e, 0xc0, 0x87, - 0xe9, 0xc0, 0x72, 0xa3, 0xb0, 0xa5, 0x1a, 0x98, 0x7d, 0x1d, 0x33, 0x6f, 0x34, 0xa3, 0x3b, 0x73, - 0xdd, 0x33, 0x05, 0xc4, 0x73, 0x06, 0xf8, 0x00, 0x6c, 0xc7, 0xe9, 0xc0, 0x19, 0xd1, 0xac, 0xb6, - 0x25, 0xc9, 0x8e, 0xff, 0xc8, 0x51, 0x35, 0x4e, 0x07, 0x17, 0x81, 0x2b, 0xa2, 0xef, 0x47, 0x61, - 0xc0, 0x69, 0x18, 0xf3, 0xac, 0xc8, 0xd1, 0x41, 0x46, 0xc2, 0x8b, 0xae, 0xb9, 0x3c, 0x35, 0x71, - 0x25, 0x4e, 0x07, 0x8f, 0x68, 0x06, 0x3f, 0x05, 0xb7, 0x89, 0xea, 0xcf, 0x19, 0xa7, 0xe1, 0x80, - 0x26, 0xb5, 0x72, 0x43, 0x6b, 0xea, 0xf6, 0xfd, 0x22, 0x47, 0x77, 0x14, 0x6c, 0xfd, 0xdc, 0xc4, - 0x6f, 0xcd, 0x02, 0x8f, 0xe5, 0x1e, 0xd6, 0xc1, 0x0e, 0xa3, 0xcf, 0x52, 0x3a, 0x76, 0x69, 0x4d, - 0x17, 0x58, 0xbc, 0xd8, 0x77, 0x77, 0xbe, 0xbf, 0x46, 0xa5, 0x9f, 0xae, 0x51, 0xc9, 0xfc, 0x0e, - 0x54, 0xfa, 0xdc, 0x7b, 0x40, 0x29, 0xfc, 0x16, 0x54, 0x48, 0x28, 0xf0, 0x35, 0xad, 0x51, 0x6e, - 0xee, 0x75, 0x0e, 0xad, 0x15, 0xe1, 0x2f, 0xdb, 0x56, 0x2f, 0x0a, 0xc6, 0xf6, 0x07, 0xcf, 0x73, - 0x54, 0xfa, 0xe5, 0x25, 0x6a, 0xfe, 0x07, 0x79, 0x04, 0x80, 0xe1, 0x19, 0x29, 0x7c, 0x07, 0x94, - 0x7d, 0xc2, 0xa4, 0x28, 0x3a, 0x16, 0xcb, 0xae, 0xfe, 0xfb, 0x35, 0xd2, 0xcc, 0x2b, 0xb0, 0xdf, - 0xe7, 0x5e, 0x3f, 0xf0, 0xc7, 0x84, 0xa7, 0x09, 0x5d, 0x15, 0x50, 0x7b, 0x13, 0x01, 0x8f, 0xc0, - 0x2e, 0x9b, 0x93, 0xaa, 0xab, 0xc0, 0xcb, 0x40, 0x57, 0x17, 0x02, 0x98, 0x2f, 0xcb, 0xa0, 0xf2, - 0x84, 0x24, 0x24, 0x64, 0xf0, 0x31, 0x38, 0x0c, 0xc9, 0xc4, 0x09, 0x69, 0x18, 0x39, 0xee, 0x90, - 0x24, 0xc4, 0xe5, 0x34, 0x51, 0x86, 0xd0, 0x6d, 0xa3, 0xc8, 0x51, 0x5d, 0x95, 0xda, 0x90, 0x64, - 0xe2, 0x83, 0x90, 0x4c, 0xbe, 0xa4, 0x61, 0xd4, 0x5b, 0xc4, 0xe0, 0x29, 0xd8, 0xe7, 0x13, 0x87, - 0x05, 0xbe, 0x73, 0x11, 0x84, 0x01, 0x57, 0xbf, 0xdb, 0xbe, 0x57, 0xe4, 0xe8, 0x50, 0x11, 0xad, - 0x9e, 0x9a, 0x18, 0xf0, 0x49, 0x3f, 0xf0, 0xbf, 0x10, 0x1b, 0x88, 0xc1, 0x1d, 0x79, 0x78, 0x45, - 0x1d, 0x37, 0x62, 0xdc, 0x89, 0x69, 0xe2, 0x0c, 0x32, 0x4e, 0x67, 0x0e, 0x68, 0x14, 0x39, 0x3a, - 0x5a, 0xe1, 0x78, 0x35, 0xcd, 0xc4, 0x07, 0x82, 0xec, 0x8a, 0xf6, 0x22, 0xc6, 0x9f, 0xd0, 0xc4, - 0xce, 0x38, 0x85, 0xcf, 0xc0, 0x3d, 0x51, 0xed, 0x92, 0x26, 0xc1, 0xd3, 0x4c, 0xe5, 0x53, 0xaf, - 0x73, 0x72, 0xd2, 0x3e, 0x55, 0xde, 0xb0, 0xbb, 0xd3, 0x1c, 0x55, 0xfb, 0x81, 0xff, 0xb5, 0xcc, - 0x10, 0xd0, 0xcf, 0xce, 0xe5, 0x79, 0x91, 0x23, 0x43, 0x55, 0x7b, 0x0d, 0x81, 0x89, 0xab, 0x6c, - 0x0d, 0xa7, 0xc2, 0x30, 0x03, 0xf7, 0x5f, 0x45, 0x30, 0xea, 0xc6, 0x9d, 0x93, 0x8f, 0x47, 0xed, - 0xda, 0x2d, 0x59, 0xf4, 0x93, 0x69, 0x8e, 0xee, 0xae, 0x15, 0xed, 0xcf, 0x33, 0x8a, 0x1c, 0x35, - 0x36, 0x97, 0x5d, 0x90, 0x98, 0xf8, 0x2e, 0xdb, 0x88, 0xed, 0xee, 0x08, 0x6b, 0x4b, 0x77, 0xfd, - 0xac, 0x81, 0xdd, 0x3e, 0xf7, 0xbe, 0x9a, 0x88, 0x07, 0x0f, 0x3f, 0x02, 0xe5, 0xa7, 0x94, 0xca, - 0x4b, 0xdd, 0xeb, 0x1c, 0x59, 0x9b, 0x06, 0x8b, 0xa5, 0x5e, 0x83, 0xad, 0x0b, 0xa3, 0x63, 0x91, - 0x0e, 0x3f, 0x07, 0x60, 0x61, 0x1c, 0x61, 0x60, 0xf1, 0x38, 0xcc, 0xd7, 0x82, 0x17, 0x4e, 0x9e, - 0x51, 0xac, 0x60, 0x21, 0x04, 0xba, 0xf0, 0x8e, 0xbc, 0xc8, 0x5d, 0x2c, 0xd7, 0xe6, 0x9f, 0x1a, - 0xb8, 0x3d, 0x83, 0x9d, 0x47, 0xae, 0x6c, 0xf3, 0x14, 0xec, 0xb8, 0x43, 0x12, 0x8c, 0x9d, 0xc0, - 0x93, 0xbd, 0xee, 0xda, 0xc6, 0x34, 0x47, 0xdb, 0x3d, 0x11, 0x7b, 0x78, 0x5e, 0xe4, 0xe8, 0x6d, - 0xa5, 0xcc, 0x3c, 0xc9, 0xc4, 0xdb, 0x72, 0xf9, 0xd0, 0xdb, 0x30, 0x36, 0xb6, 0xde, 0x60, 0x6c, - 0x94, 0xd7, 0xc7, 0xc6, 0xa2, 0x7f, 0x7d, 0xd9, 0xff, 0x5c, 0xd3, 0x5b, 0xff, 0x4b, 0x53, 0xbb, - 0xf7, 0x7c, 0x6a, 0x68, 0x2f, 0xa6, 0x86, 0xf6, 0xdb, 0xd4, 0xd0, 0x7e, 0xbc, 0x31, 0x4a, 0x2f, - 0x6e, 0x8c, 0xd2, 0xaf, 0x37, 0x46, 0xe9, 0x9b, 0xf7, 0xfe, 0x75, 0xb2, 0xac, 0xfe, 0x4b, 0x0c, - 0x2a, 0x72, 0x9e, 0x7f, 0xf8, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc2, 0xcf, 0xcb, 0xc3, 0x3c, + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x55, 0xcf, 0x8f, 0xdb, 0x44, + 0x14, 0x8e, 0x37, 0x6e, 0x36, 0x99, 0x5d, 0x0a, 0x99, 0x4d, 0xdb, 0x34, 0x5a, 0x79, 0x22, 0x1f, + 0x50, 0x90, 0x58, 0x87, 0x04, 0x16, 0x69, 0x73, 0x40, 0xac, 0xb3, 0x54, 0x54, 0x85, 0xaa, 0x9a, + 0x20, 0x0e, 0x48, 0xc8, 0x9a, 0xd8, 0x53, 0xc7, 0xca, 0x3a, 0x76, 0x3d, 0xe3, 0x55, 0xbc, 0x57, + 0x2e, 0x88, 0x13, 0xc7, 0xde, 0xd8, 0x33, 0x7f, 0x49, 0x8f, 0x3d, 0x72, 0x72, 0x51, 0xf6, 0x82, + 0x38, 0x9a, 0x1b, 0x27, 0x34, 0x9e, 0xfc, 0x2c, 0x29, 0xa2, 0xda, 0x4b, 0x32, 0xf3, 0xe6, 0xfb, + 0xbe, 0xf7, 0xf2, 0xe6, 0x9b, 0x17, 0x50, 0x9f, 0xb6, 0x49, 0xcc, 0x47, 0x6d, 0x9e, 0x84, 0x94, + 0xc9, 0x4f, 0x23, 0x8c, 0x02, 0x1e, 0xc0, 0x9a, 0x1d, 0x30, 0x3f, 0x60, 0x16, 0x73, 0xc6, 0xc6, + 0xd4, 0x10, 0x20, 0xe3, 0xa2, 0xd3, 0x78, 0x9f, 0x8f, 0xbc, 0xc8, 0xb1, 0x42, 0x12, 0xf1, 0xa4, + 0x9d, 0x03, 0xdb, 0x6e, 0xe0, 0x06, 0xab, 0x95, 0x64, 0x37, 0xaa, 0xff, 0x12, 0xd4, 0x7f, 0xda, + 0x01, 0x7b, 0x26, 0x61, 0xf4, 0xd4, 0xb6, 0x83, 0x78, 0xc2, 0xe1, 0x23, 0xb0, 0x4b, 0x1c, 0x27, + 0xa2, 0x8c, 0xd5, 0x95, 0xa6, 0xd2, 0xda, 0x37, 0x3b, 0x7f, 0xa7, 0xe8, 0xc8, 0xf5, 0xf8, 0x28, + 0x1e, 0x1a, 0x76, 0xe0, 0xb7, 0x65, 0x01, 0xf3, 0xaf, 0x23, 0xe6, 0x8c, 0xe7, 0x72, 0xa7, 0xb6, + 0x7d, 0x2a, 0x89, 0x78, 0xa1, 0x00, 0x1f, 0x80, 0xdd, 0x30, 0x1e, 0x5a, 0x63, 0x9a, 0xd4, 0x77, + 0x72, 0xb1, 0xa3, 0x3f, 0x53, 0x54, 0x0b, 0xe3, 0xe1, 0xb9, 0x67, 0x8b, 0xe8, 0x87, 0x81, 0xef, + 0x71, 0xea, 0x87, 0x3c, 0xc9, 0x52, 0x54, 0x4d, 0x88, 0x7f, 0xde, 0xd3, 0x57, 0xa7, 0x3a, 0x2e, + 0x85, 0xf1, 0xf0, 0x11, 0x4d, 0xe0, 0xe7, 0xe0, 0x36, 0x91, 0xf5, 0x59, 0x93, 0xd8, 0x1f, 0xd2, + 0xa8, 0x5e, 0x6c, 0x2a, 0x2d, 0xd5, 0xbc, 0x9f, 0xa5, 0xe8, 0x8e, 0xa4, 0x6d, 0x9e, 0xeb, 0xf8, + 0x9d, 0x79, 0xe0, 0x71, 0xbe, 0x87, 0x0d, 0x50, 0x66, 0xf4, 0x59, 0x4c, 0x27, 0x36, 0xad, 0xab, + 0x82, 0x8b, 0x97, 0xfb, 0x5e, 0xf9, 0xc7, 0x2b, 0x54, 0x78, 0x7e, 0x85, 0x0a, 0xfa, 0x0f, 0x0a, + 0x28, 0x0d, 0xb8, 0xf3, 0x80, 0x52, 0xf8, 0x3d, 0x28, 0x11, 0x5f, 0x08, 0xd4, 0x95, 0x66, 0xb1, + 0xb5, 0xd7, 0x3d, 0x30, 0xd6, 0x3a, 0x7f, 0xd1, 0x31, 0xfa, 0x81, 0x37, 0x31, 0x3f, 0x7a, 0x91, + 0xa2, 0xc2, 0xaf, 0xaf, 0x50, 0xeb, 0x7f, 0xf4, 0x47, 0x10, 0x18, 0x9e, 0x8b, 0xc2, 0xf7, 0x40, + 0xd1, 0x25, 0x2c, 0xef, 0x8a, 0x8a, 0xc5, 0x52, 0x56, 0xf1, 0xc7, 0x15, 0x52, 0xf4, 0x4b, 0xb0, + 0x3f, 0xe0, 0xce, 0xc0, 0x73, 0x27, 0x84, 0xc7, 0x11, 0x5d, 0xef, 0xa2, 0x72, 0x93, 0x2e, 0x1e, + 0x82, 0x0a, 0x5b, 0x88, 0xca, 0xfb, 0xc0, 0xab, 0x40, 0x4f, 0x15, 0xf9, 0xf5, 0x57, 0x45, 0x50, + 0x7a, 0x42, 0x22, 0xe2, 0x33, 0xf8, 0x18, 0x1c, 0xf8, 0x64, 0x6a, 0xf9, 0xd4, 0x0f, 0x2c, 0x7b, + 0x44, 0x22, 0x62, 0x73, 0x1a, 0x49, 0x57, 0xa8, 0xa6, 0x96, 0xa5, 0xa8, 0x21, 0x53, 0x6d, 0x01, + 0xe9, 0xb8, 0xea, 0x93, 0xe9, 0xd7, 0xd4, 0x0f, 0xfa, 0xcb, 0x18, 0x3c, 0x01, 0xfb, 0x7c, 0x6a, + 0x31, 0xcf, 0xb5, 0xce, 0x3d, 0xdf, 0xe3, 0xf2, 0xb7, 0x9b, 0xf7, 0xb2, 0x14, 0x1d, 0x48, 0xa1, + 0xf5, 0x53, 0x1d, 0x03, 0x3e, 0x1d, 0x78, 0xee, 0x57, 0x62, 0x03, 0x31, 0xb8, 0x93, 0x1f, 0x5e, + 0x52, 0xcb, 0x0e, 0x18, 0xb7, 0x42, 0x1a, 0x59, 0xc3, 0x84, 0xd3, 0xb9, 0x0d, 0x9a, 0x59, 0x8a, + 0x0e, 0xd7, 0x34, 0x5e, 0x87, 0xe9, 0xb8, 0x2a, 0xc4, 0x2e, 0x69, 0x3f, 0x60, 0xfc, 0x09, 0x8d, + 0xcc, 0x84, 0x53, 0xf8, 0x0c, 0xdc, 0x13, 0xd9, 0x2e, 0x68, 0xe4, 0x3d, 0x4d, 0x24, 0x9e, 0x3a, + 0xdd, 0xe3, 0xe3, 0xce, 0x89, 0x34, 0x88, 0xd9, 0x9b, 0xa5, 0xa8, 0x36, 0xf0, 0xdc, 0x6f, 0x73, + 0x84, 0xa0, 0x7e, 0x71, 0x96, 0x9f, 0x67, 0x29, 0xd2, 0x64, 0xb6, 0x37, 0x08, 0xe8, 0xb8, 0xc6, + 0x36, 0x78, 0x32, 0x0c, 0x13, 0x70, 0xff, 0x75, 0x06, 0xa3, 0x76, 0xd8, 0x3d, 0xfe, 0x74, 0xdc, + 0xa9, 0xdf, 0xca, 0x93, 0x7e, 0x36, 0x4b, 0xd1, 0xdd, 0x8d, 0xa4, 0x83, 0x05, 0x22, 0x4b, 0x51, + 0x73, 0x7b, 0xda, 0xa5, 0x88, 0x8e, 0xef, 0xb2, 0xad, 0xdc, 0x5e, 0xf9, 0xf9, 0xc2, 0x5d, 0xbf, + 0x28, 0xa0, 0x32, 0xe0, 0xce, 0x37, 0x53, 0xf1, 0xea, 0xe1, 0x27, 0xa0, 0xf8, 0x94, 0xd2, 0xfc, + 0x52, 0xf7, 0xba, 0x87, 0xc6, 0xb6, 0xe9, 0x62, 0xc8, 0x17, 0x61, 0xaa, 0xc2, 0xec, 0x58, 0xc0, + 0xe1, 0x97, 0x00, 0x2c, 0x8d, 0x23, 0x4c, 0x2c, 0x1e, 0x88, 0xfe, 0x46, 0xf2, 0xd2, 0xc9, 0x73, + 0x89, 0x35, 0x2e, 0x84, 0x40, 0x15, 0xde, 0xc9, 0x2f, 0xb2, 0x82, 0xf3, 0xb5, 0xfe, 0x97, 0x02, + 0x6e, 0xcf, 0x69, 0x67, 0x81, 0x9d, 0x97, 0x79, 0x02, 0xca, 0xf6, 0x88, 0x78, 0x13, 0xcb, 0x73, + 0xf2, 0x5a, 0x2b, 0xa6, 0x36, 0x4b, 0xd1, 0x6e, 0x5f, 0xc4, 0x1e, 0x9e, 0x65, 0x29, 0x7a, 0x57, + 0x76, 0x66, 0x01, 0xd2, 0xf1, 0x6e, 0xbe, 0x7c, 0xe8, 0x6c, 0x99, 0x1d, 0x3b, 0x37, 0x98, 0x1d, + 0xc5, 0xcd, 0xd9, 0xb1, 0xac, 0x5f, 0x5d, 0xd5, 0xbf, 0xe8, 0xe9, 0xad, 0xb7, 0xea, 0xa9, 0xd9, + 0x7f, 0x31, 0xd3, 0x94, 0x97, 0x33, 0x4d, 0xf9, 0x7d, 0xa6, 0x29, 0x3f, 0x5f, 0x6b, 0x85, 0x97, + 0xd7, 0x5a, 0xe1, 0xb7, 0x6b, 0xad, 0xf0, 0xdd, 0x07, 0xff, 0x39, 0x5d, 0xd6, 0xff, 0x2a, 0x86, + 0xa5, 0x7c, 0xa8, 0x7f, 0xfc, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, 0xb1, 0x78, 0x7e, 0x41, 0x06, 0x00, 0x00, } diff --git a/x/auth/types/types.proto b/x/auth/types/types.proto index e15e0342f1f9..305b5368ffb6 100644 --- a/x/auth/types/types.proto +++ b/x/auth/types/types.proto @@ -23,7 +23,8 @@ message BaseAccount { // gas to be used by the transaction. The ratio yields an effective "gasprice", // which must be above some miminum to be accepted into the mempool. message StdFee { - option (gogoproto.equal) = true; + option (gogoproto.goproto_getters) = false; + option (gogoproto.equal) = true; repeated cosmos_sdk.v1.Coin amount = 1 [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; From fe999c4201cca5d5eab0187fb42ec0d0497e2666 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 13 Mar 2020 06:24:56 +0000 Subject: [PATCH 409/529] Bump github.com/golang/protobuf from 1.3.4 to 1.3.5 Bumps [github.com/golang/protobuf](https://github.com/golang/protobuf) from 1.3.4 to 1.3.5. - [Release notes](https://github.com/golang/protobuf/releases) - [Commits](https://github.com/golang/protobuf/compare/v1.3.4...v1.3.5) Signed-off-by: dependabot-preview[bot] --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 446acc15d813..c29e55729b78 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/cosmos/ledger-cosmos-go v0.11.1 github.com/gogo/protobuf v1.3.1 github.com/golang/mock v1.4.1 - github.com/golang/protobuf v1.3.4 + github.com/golang/protobuf v1.3.5 github.com/gorilla/handlers v1.4.2 github.com/gorilla/mux v1.7.4 github.com/hashicorp/golang-lru v0.5.4 diff --git a/go.sum b/go.sum index a1723495d767..e65186753232 100644 --- a/go.sum +++ b/go.sum @@ -139,6 +139,8 @@ github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.4 h1:87PNWwrRvUSnqS4dlcBU/ftvOIBep4sYuBLlh6rX2wk= github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= From edb0927c53a06423f5d53c854bec03f6169cb154 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Fri, 13 Mar 2020 09:34:55 -0400 Subject: [PATCH 410/529] reorder fields --- codec/std/codec.pb.go | 208 +++++++++++++++++++++--------------------- codec/std/codec.proto | 4 +- 2 files changed, 106 insertions(+), 106 deletions(-) diff --git a/codec/std/codec.pb.go b/codec/std/codec.pb.go index 4330171f9de1..2d1c5b23250e 100644 --- a/codec/std/codec.pb.go +++ b/codec/std/codec.pb.go @@ -324,8 +324,8 @@ func (*Evidence) XXX_OneofWrappers() []interface{} { // MsgSubmitEvidence defines the application-level message type for handling // evidence submission. type MsgSubmitEvidence struct { - Evidence *Evidence `protobuf:"bytes,1,opt,name=evidence,proto3" json:"evidence,omitempty"` - types3.MsgSubmitEvidenceBase `protobuf:"bytes,2,opt,name=base,proto3,embedded=base" json:"base"` + types3.MsgSubmitEvidenceBase `protobuf:"bytes,1,opt,name=base,proto3,embedded=base" json:"base"` + Evidence *Evidence `protobuf:"bytes,2,opt,name=evidence,proto3" json:"evidence,omitempty"` } func (m *MsgSubmitEvidence) Reset() { *m = MsgSubmitEvidence{} } @@ -965,14 +965,14 @@ func init() { func init() { proto.RegisterFile("codec/std/codec.proto", fileDescriptor_daf09dc2dfa19bb4) } var fileDescriptor_daf09dc2dfa19bb4 = []byte{ - // 1478 bytes of a gzipped FileDescriptorProto + // 1479 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0xcd, 0x6f, 0xd4, 0x46, 0x1b, 0xf7, 0xc2, 0x92, 0x84, 0x49, 0x80, 0x30, 0x2f, 0xbc, 0x59, 0xe5, 0x85, 0x4d, 0x08, 0xbc, 0xa8, 0x05, 0x65, 0xcd, 0x47, 0x5b, 0x60, 0xd5, 0x0a, 0xf2, 0x01, 0x5a, 0xaa, 0xa6, 0x45, 0x0e, 0xa4, 0x6a, 0x45, 0x6b, 0xcd, 0x7a, 0x06, 0x67, 0x9a, 0xb5, 0xc7, 0xf5, 0x8c, 0x37, 0x9b, 0x43, 0xef, 0x6d, 0xa5, 0x4a, 0x55, 0xfb, 0x0f, 0xa0, 0xf6, 0xd8, 0x2b, 0xc7, 0x9e, 0x2b, 0xc4, 0x89, 0x63, 0x4f, 0xa8, 0x82, 0x4b, 0xd5, 0xbf, 0xa2, 0x9a, 0x0f, 0x7b, 0xed, 0x5d, 0xef, 0x86, 0x1e, - 0x7a, 0x89, 0x3c, 0xf3, 0x3c, 0xbf, 0xdf, 0xf3, 0x1b, 0xcf, 0xf3, 0xe1, 0x0d, 0x38, 0xe9, 0x31, + 0x7a, 0x89, 0x3c, 0xf3, 0x3c, 0xbf, 0xdf, 0xf3, 0xf3, 0xcc, 0xf3, 0xe1, 0x0d, 0x38, 0xe9, 0x31, 0x4c, 0x3c, 0x9b, 0x0b, 0x6c, 0xab, 0xa7, 0x46, 0x14, 0x33, 0xc1, 0xe0, 0x9c, 0xc7, 0x78, 0xc0, 0xb8, 0xcb, 0xf1, 0x4e, 0x43, 0xef, 0x73, 0x81, 0x1b, 0xdd, 0xcb, 0xf3, 0x17, 0xc5, 0x36, 0x8d, 0xb1, 0x1b, 0xa1, 0x58, 0xec, 0xd9, 0xca, 0xd7, 0xd6, 0xae, 0xcb, 0xf9, 0x85, 0x66, 0x99, 0x3f, @@ -981,84 +981,84 @@ var fileDescriptor_daf09dc2dfa19bb4 = []byte{ 0x7a, 0x76, 0x1b, 0x85, 0x3b, 0x25, 0x96, 0xf9, 0x9e, 0xed, 0xc5, 0x94, 0x53, 0x5e, 0xce, 0x8b, 0x29, 0x17, 0x31, 0x6d, 0x27, 0x82, 0xb2, 0xb0, 0x1c, 0xcd, 0x93, 0x28, 0xea, 0xec, 0x95, 0xd8, 0x4e, 0xf5, 0x6c, 0xd2, 0xa5, 0x98, 0x84, 0x1e, 0x29, 0xb1, 0xce, 0xf5, 0x6c, 0x9f, 0x75, 0xcb, - 0x61, 0xbc, 0x83, 0xf8, 0x76, 0xf9, 0x41, 0xfe, 0xd7, 0xb3, 0xb9, 0x40, 0x3b, 0xe5, 0xc6, 0xb3, - 0x3d, 0x3b, 0x42, 0x31, 0x0a, 0xd2, 0xb3, 0x44, 0x31, 0x8b, 0x18, 0x47, 0x9d, 0x41, 0x86, 0x24, - 0xf2, 0x63, 0x84, 0x4b, 0x54, 0x2d, 0xfd, 0x5a, 0x05, 0x93, 0x2b, 0x9e, 0xc7, 0x92, 0x50, 0xc0, - 0x3b, 0x60, 0xa6, 0x8d, 0x38, 0x71, 0x91, 0x5e, 0xd7, 0x2a, 0x8b, 0x95, 0x37, 0xa6, 0xaf, 0x9c, - 0x69, 0xe4, 0x2e, 0xbd, 0xd7, 0x90, 0xef, 0xbd, 0xd1, 0xbd, 0xdc, 0x58, 0x45, 0x9c, 0x18, 0x60, - 0xcb, 0x72, 0xa6, 0xdb, 0xfd, 0x25, 0xec, 0x82, 0x79, 0x8f, 0x85, 0x82, 0x86, 0x09, 0x4b, 0xb8, - 0x6b, 0xee, 0x28, 0x63, 0x3d, 0xa0, 0x58, 0xdf, 0x29, 0x63, 0xd5, 0x9e, 0x92, 0x7d, 0x2d, 0xc3, - 0x6f, 0xe9, 0xcd, 0x7e, 0xa8, 0x9a, 0x37, 0xc2, 0x06, 0x03, 0x30, 0x87, 0x49, 0x07, 0xed, 0x11, - 0x3c, 0x14, 0xf4, 0xa0, 0x0a, 0x7a, 0x75, 0x7c, 0xd0, 0x75, 0x0d, 0x1e, 0x8a, 0x78, 0x12, 0x97, - 0x19, 0x60, 0x04, 0x6a, 0x11, 0x89, 0x29, 0xc3, 0xd4, 0x1b, 0x8a, 0x57, 0x55, 0xf1, 0xde, 0x1a, - 0x1f, 0xef, 0x9e, 0x41, 0x0f, 0x05, 0xfc, 0x6f, 0x54, 0x6a, 0x81, 0x1f, 0x82, 0xa3, 0x01, 0xc3, - 0x49, 0xa7, 0x7f, 0x45, 0x87, 0x54, 0x9c, 0xff, 0x17, 0xe3, 0xe8, 0x04, 0x95, 0x11, 0x36, 0x94, - 0x77, 0x9f, 0xf8, 0x48, 0x90, 0xdf, 0x68, 0xde, 0x78, 0xf6, 0x64, 0xf9, 0xed, 0x0b, 0x3e, 0x15, - 0xdb, 0x49, 0xbb, 0xe1, 0xb1, 0xc0, 0x94, 0x69, 0x5a, 0xba, 0x1c, 0xef, 0xd8, 0xa6, 0xd0, 0x48, - 0x2f, 0x62, 0xb1, 0x20, 0xb8, 0x61, 0xa0, 0xab, 0x87, 0xc0, 0x41, 0x9e, 0x04, 0x4b, 0xdf, 0x56, - 0xc0, 0xc4, 0xa6, 0x0a, 0x07, 0xaf, 0x83, 0x09, 0x1d, 0xd8, 0xe4, 0x4d, 0x7d, 0x94, 0x28, 0xed, - 0xdf, 0xb2, 0x1c, 0xe3, 0xdf, 0xbc, 0xf9, 0xe7, 0xe3, 0x85, 0xca, 0xb3, 0x27, 0xcb, 0xd7, 0xf6, - 0x93, 0x62, 0x2a, 0x2f, 0x13, 0xa3, 0x99, 0xee, 0xa6, 0x62, 0x7e, 0xaa, 0x80, 0xa9, 0xdb, 0xa6, - 0x00, 0xe1, 0x07, 0x60, 0x86, 0x7c, 0x99, 0xd0, 0x2e, 0xf3, 0x90, 0x2c, 0x65, 0x23, 0xea, 0x7c, - 0x51, 0x54, 0x5a, 0xae, 0x52, 0xd6, 0xed, 0x9c, 0x77, 0xcb, 0x72, 0x0a, 0xe8, 0xe6, 0x8a, 0x91, - 0x78, 0x63, 0x1f, 0x85, 0x59, 0xfd, 0x67, 0x1a, 0x53, 0x41, 0xa9, 0xc8, 0x5f, 0x2a, 0xe0, 0xf8, - 0x06, 0xf7, 0x37, 0x93, 0x76, 0x40, 0x45, 0xa6, 0xf6, 0x3d, 0x30, 0x95, 0x42, 0xcb, 0xca, 0x2e, - 0xdf, 0x6b, 0x33, 0x46, 0x27, 0x83, 0xc0, 0x0d, 0x50, 0x95, 0x05, 0x68, 0x6a, 0xcb, 0x1e, 0x7d, - 0xc8, 0xa1, 0xc8, 0xb2, 0x8c, 0x57, 0xa7, 0x9e, 0xbe, 0x58, 0xb0, 0x9e, 0xbf, 0x58, 0xa8, 0x38, - 0x8a, 0xa6, 0x39, 0xf5, 0xf5, 0xe3, 0x05, 0x4b, 0x9e, 0x78, 0xe9, 0xe7, 0xbc, 0xda, 0x7b, 0xa6, - 0xbb, 0xc0, 0x96, 0x09, 0xa7, 0x95, 0x5e, 0x28, 0x86, 0xf3, 0x59, 0xb7, 0x10, 0x29, 0x45, 0x95, - 0x45, 0x82, 0x4d, 0x30, 0x29, 0xcb, 0x99, 0x64, 0x7d, 0x61, 0x71, 0xe4, 0xb1, 0xd7, 0xb4, 0x9f, - 0x93, 0x02, 0x72, 0x2a, 0x7f, 0xac, 0x80, 0xa9, 0x4c, 0xdc, 0xcd, 0x82, 0xb8, 0x33, 0xa5, 0xe2, - 0xc6, 0x6a, 0xba, 0xf5, 0x8f, 0x35, 0xad, 0x56, 0x25, 0x45, 0x5f, 0x59, 0x55, 0xa9, 0x7a, 0x5c, - 0x05, 0x93, 0xc6, 0x01, 0x5e, 0x03, 0x55, 0x41, 0x7a, 0x62, 0xac, 0xa8, 0xfb, 0xa4, 0x97, 0xbd, - 0xac, 0x96, 0xe5, 0x28, 0x00, 0x7c, 0x08, 0x66, 0x55, 0x87, 0x27, 0x82, 0xc4, 0xae, 0xb7, 0x8d, - 0x42, 0x7f, 0xc4, 0x2d, 0xeb, 0x39, 0xa0, 0x0e, 0x97, 0xfa, 0xaf, 0x29, 0xf7, 0x1c, 0xe5, 0xb1, - 0xa8, 0x68, 0x82, 0x9f, 0x81, 0x59, 0xce, 0x1e, 0x89, 0x5d, 0x14, 0x13, 0xd7, 0xcc, 0x08, 0xd3, - 0x2a, 0x2f, 0x15, 0xd9, 0x8d, 0x51, 0x95, 0xaf, 0x01, 0x3c, 0xd0, 0x5b, 0x79, 0x7a, 0x5e, 0x34, - 0xc1, 0x08, 0xcc, 0x79, 0x28, 0xf4, 0x48, 0xc7, 0x1d, 0x8a, 0x52, 0x2d, 0x9b, 0x02, 0xb9, 0x28, - 0x6b, 0x0a, 0x37, 0x3a, 0xd6, 0x49, 0xaf, 0xcc, 0x01, 0x76, 0xc0, 0x09, 0x8f, 0x05, 0x41, 0x12, - 0x52, 0xb1, 0xe7, 0x46, 0x8c, 0x75, 0x5c, 0x1e, 0x91, 0x10, 0x9b, 0x3e, 0x79, 0xbd, 0x18, 0x2e, - 0x3f, 0xea, 0xf5, 0x6d, 0x1a, 0xe4, 0x3d, 0xc6, 0x3a, 0x9b, 0x12, 0x97, 0x0b, 0x08, 0xbd, 0x21, - 0x6b, 0xf3, 0xba, 0xe9, 0x0a, 0x97, 0xf6, 0xe9, 0x0a, 0xd9, 0xdc, 0xcf, 0x12, 0xc6, 0x34, 0x83, - 0x1f, 0x2a, 0x60, 0xfa, 0x7e, 0x8c, 0x42, 0x8e, 0x3c, 0x29, 0x02, 0xae, 0x14, 0x72, 0x77, 0xa1, - 0x7c, 0xf2, 0x6e, 0x0a, 0x7c, 0xbf, 0xa7, 0x32, 0x77, 0x26, 0xcd, 0xdc, 0xbf, 0x64, 0xfa, 0xa5, - 0x15, 0x55, 0x0d, 0xb8, 0xcf, 0x6b, 0x07, 0x16, 0x0f, 0x8e, 0x4d, 0xdd, 0x0d, 0xc2, 0x39, 0xf2, - 0x89, 0x49, 0x5d, 0x85, 0x69, 0x56, 0x65, 0x45, 0x2d, 0xfd, 0x36, 0x03, 0x26, 0x8d, 0x15, 0x36, - 0xc1, 0x54, 0xc0, 0x7d, 0x97, 0xcb, 0x77, 0xa8, 0x45, 0x9d, 0x2e, 0x8a, 0x92, 0x1f, 0x59, 0x69, - 0xb9, 0x93, 0x10, 0xb7, 0x2c, 0x67, 0x32, 0xd0, 0x8f, 0xf0, 0x7d, 0x70, 0x54, 0x62, 0x83, 0xa4, - 0x23, 0xa8, 0x66, 0xd0, 0x89, 0xbb, 0x34, 0x92, 0x61, 0x43, 0xba, 0x1a, 0x9a, 0x99, 0x20, 0xb7, - 0x86, 0x9f, 0x83, 0x13, 0x92, 0xab, 0x4b, 0x62, 0xfa, 0x68, 0xcf, 0xa5, 0x61, 0x17, 0xc5, 0x14, - 0x65, 0x73, 0x7d, 0xa0, 0x03, 0xe9, 0xcf, 0x3b, 0xc3, 0xb9, 0xa5, 0x20, 0x77, 0x53, 0x84, 0xbc, - 0xc9, 0x60, 0x68, 0x17, 0x86, 0xa0, 0xa6, 0xcf, 0x29, 0xdc, 0x5d, 0x2a, 0xb6, 0x71, 0x8c, 0x76, - 0x5d, 0x84, 0x71, 0x4c, 0x38, 0x37, 0xa9, 0x7a, 0x75, 0x7c, 0xee, 0xa8, 0xf3, 0x8b, 0x8f, 0x0d, - 0x76, 0x45, 0x43, 0x65, 0x9e, 0x06, 0x65, 0x06, 0xf8, 0x15, 0x38, 0x2d, 0xe3, 0x65, 0xb1, 0x30, - 0xe9, 0x10, 0x1f, 0x09, 0x16, 0xbb, 0x31, 0xd9, 0x45, 0xf1, 0x6b, 0x26, 0xec, 0x06, 0xf7, 0x53, - 0xe2, 0xf5, 0x94, 0xc0, 0x51, 0xf8, 0x96, 0xe5, 0xcc, 0x07, 0x23, 0xad, 0xf0, 0x9b, 0x0a, 0x38, - 0x53, 0x88, 0xdf, 0x45, 0x1d, 0x8a, 0x55, 0x7c, 0x99, 0xe6, 0x94, 0x73, 0x39, 0x32, 0x27, 0x94, - 0x86, 0x77, 0x5f, 0x5b, 0xc3, 0x56, 0x4a, 0xb2, 0x96, 0x71, 0xb4, 0x2c, 0xa7, 0x1e, 0x8c, 0xf5, - 0x80, 0x3b, 0x60, 0x4e, 0x4a, 0x79, 0x94, 0x84, 0xd8, 0x2d, 0xd6, 0x6e, 0x6d, 0x52, 0x09, 0xb8, - 0xb2, 0xaf, 0x80, 0x3b, 0x49, 0x88, 0x0b, 0xc5, 0xdb, 0xb2, 0x1c, 0x99, 0x2f, 0x43, 0xfb, 0xf0, - 0x21, 0xf8, 0x8f, 0xba, 0x67, 0x35, 0x99, 0xdc, 0x6c, 0xe4, 0x4e, 0x0d, 0xa7, 0x51, 0xb1, 0x58, - 0x06, 0xc7, 0x66, 0xcb, 0x72, 0x8e, 0x07, 0x43, 0x53, 0xbc, 0xc8, 0x9e, 0x7e, 0x8c, 0xd7, 0x0e, - 0xbf, 0x2e, 0x7b, 0xae, 0xdd, 0xf4, 0xd9, 0xb3, 0xc1, 0x76, 0x43, 0xd7, 0x62, 0x97, 0x09, 0x52, - 0x03, 0x8a, 0xf2, 0xd4, 0xa8, 0xc9, 0xbb, 0xc5, 0x04, 0x31, 0xa5, 0x28, 0x1f, 0xe1, 0x2a, 0x98, - 0x96, 0x50, 0x4c, 0x22, 0xc6, 0xa9, 0xa8, 0x4d, 0x97, 0xb5, 0x97, 0x3e, 0x7a, 0x5d, 0xbb, 0xb5, - 0x2c, 0x07, 0x04, 0xd9, 0x0a, 0xae, 0x03, 0xb9, 0x72, 0x93, 0xf0, 0x0b, 0x44, 0x3b, 0xb5, 0x19, - 0x45, 0x71, 0x76, 0xe0, 0x1b, 0xcf, 0xfc, 0x8c, 0x31, 0x3c, 0x0f, 0x94, 0x6b, 0xcb, 0x72, 0x0e, - 0x07, 0xe9, 0x02, 0xba, 0xba, 0x90, 0xbd, 0x98, 0x20, 0x41, 0xfa, 0x69, 0x57, 0x3b, 0xa2, 0xf8, - 0x2e, 0x0e, 0xf0, 0xe9, 0x1f, 0x3e, 0x86, 0x6e, 0x4d, 0x61, 0xb2, 0x14, 0x32, 0x95, 0x3c, 0xb0, - 0x0b, 0x3f, 0x01, 0x72, 0xd7, 0x25, 0x98, 0x8a, 0x1c, 0xfd, 0x51, 0x45, 0xff, 0xe6, 0x38, 0xfa, - 0xdb, 0x98, 0x8a, 0x3c, 0xf9, 0x6c, 0x30, 0xb0, 0x07, 0xef, 0x82, 0x19, 0xfd, 0x16, 0x55, 0x31, - 0x91, 0xda, 0x31, 0x45, 0x7a, 0x6e, 0x1c, 0xa9, 0x29, 0x3c, 0x79, 0x19, 0xd3, 0x41, 0x7f, 0x99, - 0xbe, 0x86, 0x36, 0xf1, 0x69, 0xe8, 0xc6, 0x24, 0xa3, 0x9c, 0xdd, 0xff, 0x35, 0xac, 0x4a, 0x8c, - 0x93, 0x41, 0xcc, 0x6b, 0x18, 0xd8, 0x85, 0x1f, 0xe9, 0xe6, 0x9b, 0x84, 0x19, 0xf5, 0xf1, 0xb2, - 0x0f, 0xe0, 0x22, 0xf5, 0x83, 0x30, 0xc7, 0x7a, 0x24, 0xc8, 0x6f, 0x34, 0x2f, 0x3c, 0x7b, 0xb2, - 0x7c, 0x7e, 0xec, 0x9c, 0xd3, 0x13, 0x4e, 0x2a, 0x34, 0xd3, 0xed, 0xbb, 0x0a, 0x98, 0xdc, 0xa4, - 0x7e, 0xb8, 0xce, 0x3c, 0x78, 0xa7, 0x30, 0xd9, 0xce, 0x8d, 0x9c, 0x6c, 0xc6, 0xff, 0xdf, 0x18, - 0x6f, 0xab, 0xb7, 0x9e, 0xbe, 0xac, 0x57, 0x9e, 0xbf, 0xac, 0x57, 0xfe, 0x78, 0x59, 0xaf, 0x7c, - 0xff, 0xaa, 0x6e, 0x3d, 0x7f, 0x55, 0xb7, 0x7e, 0x7f, 0x55, 0xb7, 0x3e, 0x1d, 0x7f, 0xb0, 0xec, - 0x7f, 0x21, 0xed, 0x09, 0xf5, 0xa3, 0xf9, 0xea, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x54, 0x48, - 0xa8, 0xb7, 0x1f, 0x11, 0x00, 0x00, + 0x61, 0xbc, 0x83, 0xf8, 0x76, 0xf9, 0x8b, 0xfc, 0xaf, 0x67, 0x73, 0x81, 0x76, 0xca, 0x8d, 0x67, + 0x7b, 0x76, 0x84, 0x62, 0x14, 0xa4, 0xef, 0x12, 0xc5, 0x2c, 0x62, 0x1c, 0x75, 0x06, 0x19, 0x92, + 0xc8, 0x8f, 0x11, 0x2e, 0x51, 0xb5, 0xf4, 0x6b, 0x15, 0x4c, 0xae, 0x78, 0x1e, 0x4b, 0x42, 0x01, + 0xef, 0x80, 0x99, 0x36, 0xe2, 0xc4, 0x45, 0x7a, 0x5d, 0xab, 0x2c, 0x56, 0xde, 0x98, 0xbe, 0x72, + 0xa6, 0x91, 0xbb, 0xf4, 0x5e, 0x43, 0x9e, 0x7b, 0xa3, 0x7b, 0xb9, 0xb1, 0x8a, 0x38, 0x31, 0xc0, + 0x96, 0xe5, 0x4c, 0xb7, 0xfb, 0x4b, 0xd8, 0x05, 0xf3, 0x1e, 0x0b, 0x05, 0x0d, 0x13, 0x96, 0x70, + 0xd7, 0xdc, 0x51, 0xc6, 0x7a, 0x40, 0xb1, 0xbe, 0x53, 0xc6, 0xaa, 0x3d, 0x25, 0xfb, 0x5a, 0x86, + 0xdf, 0xd2, 0x9b, 0xfd, 0x50, 0x35, 0x6f, 0x84, 0x0d, 0x06, 0x60, 0x0e, 0x93, 0x0e, 0xda, 0x23, + 0x78, 0x28, 0xe8, 0x41, 0x15, 0xf4, 0xea, 0xf8, 0xa0, 0xeb, 0x1a, 0x3c, 0x14, 0xf1, 0x24, 0x2e, + 0x33, 0xc0, 0x08, 0xd4, 0x22, 0x12, 0x53, 0x86, 0xa9, 0x37, 0x14, 0xaf, 0xaa, 0xe2, 0xbd, 0x35, + 0x3e, 0xde, 0x3d, 0x83, 0x1e, 0x0a, 0xf8, 0xdf, 0xa8, 0xd4, 0x02, 0x3f, 0x04, 0x47, 0x03, 0x86, + 0x93, 0x4e, 0xff, 0x8a, 0x0e, 0xa9, 0x38, 0xff, 0x2f, 0xc6, 0xd1, 0x09, 0x2a, 0x23, 0x6c, 0x28, + 0xef, 0x3e, 0xf1, 0x91, 0x20, 0xbf, 0xd1, 0xbc, 0xf1, 0xec, 0xc9, 0xf2, 0xdb, 0x17, 0x7c, 0x2a, + 0xb6, 0x93, 0x76, 0xc3, 0x63, 0x81, 0x29, 0xd3, 0xb4, 0x74, 0x39, 0xde, 0xb1, 0x4d, 0xa1, 0x91, + 0x5e, 0xc4, 0x62, 0x41, 0x70, 0xc3, 0x40, 0x57, 0x0f, 0x81, 0x83, 0x3c, 0x09, 0x96, 0xbe, 0xad, + 0x80, 0x89, 0x4d, 0x15, 0x0e, 0x5e, 0x07, 0x13, 0x3a, 0xb0, 0xc9, 0x9b, 0xfa, 0x28, 0x51, 0xda, + 0xbf, 0x65, 0x39, 0xc6, 0xbf, 0x79, 0xf3, 0xcf, 0xc7, 0x0b, 0x95, 0x67, 0x4f, 0x96, 0xaf, 0xed, + 0x27, 0xc5, 0x54, 0x5e, 0x26, 0x46, 0x33, 0xdd, 0x4d, 0xc5, 0xfc, 0x54, 0x01, 0x53, 0xb7, 0x4d, + 0x01, 0xc2, 0x0f, 0xc0, 0x0c, 0xf9, 0x32, 0xa1, 0x5d, 0xe6, 0x21, 0x59, 0xca, 0x46, 0xd4, 0xf9, + 0xa2, 0xa8, 0xb4, 0x5c, 0xa5, 0xac, 0xdb, 0x39, 0xef, 0x96, 0xe5, 0x14, 0xd0, 0xcd, 0x15, 0x23, + 0xf1, 0xc6, 0x3e, 0x0a, 0xb3, 0xfa, 0xcf, 0x34, 0xa6, 0x82, 0x52, 0x91, 0xbf, 0x54, 0xc0, 0xf1, + 0x0d, 0xee, 0x6f, 0x26, 0xed, 0x80, 0x8a, 0x4c, 0xed, 0x06, 0xa8, 0xca, 0x0a, 0x32, 0x2a, 0xed, + 0xd1, 0x2a, 0x87, 0xa0, 0xb2, 0x0e, 0x57, 0xa7, 0x9e, 0xbe, 0x58, 0xb0, 0x9e, 0xbf, 0x58, 0xa8, + 0x38, 0x8a, 0x06, 0xbe, 0x07, 0xa6, 0x52, 0x90, 0xa9, 0xb7, 0x42, 0x15, 0xe7, 0x5b, 0x77, 0x26, + 0xd0, 0xc9, 0x20, 0xcd, 0xa9, 0xaf, 0x1f, 0x2f, 0x58, 0xf2, 0x8d, 0x97, 0x7e, 0xce, 0xab, 0xbd, + 0x67, 0xba, 0x0b, 0x6c, 0x15, 0xd4, 0x5e, 0x28, 0xaa, 0xf5, 0x59, 0xb7, 0x20, 0x34, 0x45, 0x95, + 0x0a, 0x6d, 0x82, 0x49, 0x59, 0xce, 0x24, 0xeb, 0x0b, 0x8b, 0x23, 0x75, 0xae, 0x69, 0x3f, 0x27, + 0x05, 0xe4, 0x54, 0xfe, 0x58, 0x01, 0x53, 0x99, 0xb8, 0x9b, 0x05, 0x71, 0x67, 0x4a, 0xc5, 0x8d, + 0xd5, 0x74, 0xeb, 0x1f, 0x6b, 0x5a, 0xad, 0x4a, 0x8a, 0xbe, 0xb2, 0xaa, 0x52, 0xf5, 0xb8, 0x0a, + 0x26, 0x8d, 0x03, 0xbc, 0x06, 0xaa, 0x82, 0xf4, 0xc4, 0x58, 0x51, 0xf7, 0x49, 0x2f, 0x3b, 0xac, + 0x96, 0xe5, 0x28, 0x00, 0x7c, 0x08, 0x66, 0x55, 0x87, 0x27, 0x82, 0xc4, 0xae, 0xb7, 0x8d, 0x42, + 0x3f, 0xbd, 0xd1, 0x81, 0x24, 0xd1, 0x73, 0x40, 0xbd, 0x5c, 0xea, 0xbf, 0xa6, 0xdc, 0x73, 0x94, + 0xc7, 0xa2, 0xa2, 0x09, 0x7e, 0x06, 0x66, 0x39, 0x7b, 0x24, 0x76, 0x51, 0x4c, 0x5c, 0x33, 0x23, + 0x4c, 0xab, 0xbc, 0x54, 0x64, 0x37, 0x46, 0x55, 0xbe, 0x06, 0xf0, 0x40, 0x6f, 0xe5, 0xe9, 0x79, + 0xd1, 0x04, 0x23, 0x30, 0xe7, 0xa1, 0xd0, 0x23, 0x1d, 0x77, 0x28, 0x4a, 0xb5, 0x6c, 0x0a, 0xe4, + 0xa2, 0xac, 0x29, 0xdc, 0xe8, 0x58, 0x27, 0xbd, 0x32, 0x07, 0xd8, 0x01, 0x27, 0x3c, 0x16, 0x04, + 0x49, 0x48, 0xc5, 0x9e, 0x1b, 0x31, 0xd6, 0x71, 0x79, 0x44, 0x42, 0x6c, 0xfa, 0xe4, 0xf5, 0x62, + 0xb8, 0xfc, 0xa8, 0xd7, 0xb7, 0x69, 0x90, 0xf7, 0x18, 0xeb, 0x6c, 0x4a, 0x5c, 0x2e, 0x20, 0xf4, + 0x86, 0xac, 0xcd, 0xeb, 0xa6, 0x2b, 0x5c, 0xda, 0xa7, 0x2b, 0x64, 0x73, 0x3f, 0x4b, 0x18, 0xd3, + 0x0c, 0x7e, 0xa8, 0x80, 0xe9, 0xfb, 0x31, 0x0a, 0x39, 0xf2, 0xa4, 0x08, 0xb8, 0x52, 0xc8, 0xdd, + 0x85, 0xf2, 0xc9, 0xbb, 0x29, 0xf0, 0xfd, 0x9e, 0xca, 0xdc, 0x99, 0x34, 0x73, 0xff, 0x92, 0xe9, + 0x97, 0x56, 0x54, 0x35, 0xe0, 0x3e, 0xaf, 0x1d, 0x58, 0x3c, 0x38, 0x36, 0x75, 0x37, 0x08, 0xe7, + 0xc8, 0x27, 0x26, 0x75, 0x15, 0xa6, 0x59, 0x95, 0x15, 0xb5, 0xf4, 0xdb, 0x0c, 0x98, 0x34, 0x56, + 0xd8, 0x04, 0x53, 0x01, 0xf7, 0x5d, 0x2e, 0xcf, 0x50, 0x8b, 0x3a, 0x5d, 0x14, 0x25, 0x3f, 0xb2, + 0xd2, 0x72, 0x27, 0x21, 0x6e, 0x59, 0xce, 0x64, 0xa0, 0x1f, 0xe1, 0xfb, 0xe0, 0xa8, 0xc4, 0x06, + 0x49, 0x47, 0x50, 0xcd, 0xa0, 0x13, 0x77, 0x69, 0x24, 0xc3, 0x86, 0x74, 0x35, 0x34, 0x33, 0x41, + 0x6e, 0x0d, 0x3f, 0x07, 0x27, 0x24, 0x57, 0x97, 0xc4, 0xf4, 0xd1, 0x9e, 0x4b, 0xc3, 0x2e, 0x8a, + 0x29, 0xca, 0xe6, 0xfa, 0x40, 0x07, 0xd2, 0x9f, 0x77, 0x86, 0x73, 0x4b, 0x41, 0xee, 0xa6, 0x08, + 0x79, 0x93, 0xc1, 0xd0, 0x2e, 0x0c, 0x41, 0x4d, 0xbf, 0xa7, 0x70, 0x77, 0xa9, 0xd8, 0xc6, 0x31, + 0xda, 0x75, 0x11, 0xc6, 0x31, 0xe1, 0xdc, 0xa4, 0xea, 0xd5, 0xf1, 0xb9, 0xa3, 0xde, 0x5f, 0x7c, + 0x6c, 0xb0, 0x2b, 0x1a, 0x2a, 0xf3, 0x34, 0x28, 0x33, 0xc0, 0xaf, 0xc0, 0x69, 0x19, 0x2f, 0x8b, + 0x85, 0x49, 0x87, 0xf8, 0x48, 0xb0, 0xd8, 0x8d, 0xc9, 0x2e, 0x8a, 0x5f, 0x33, 0x61, 0x37, 0xb8, + 0x9f, 0x12, 0xaf, 0xa7, 0x04, 0x8e, 0xc2, 0xb7, 0x2c, 0x67, 0x3e, 0x18, 0x69, 0x85, 0xdf, 0x54, + 0xc0, 0x99, 0x42, 0xfc, 0x2e, 0xea, 0x50, 0xac, 0xe2, 0xcb, 0x34, 0xa7, 0x9c, 0xcb, 0x91, 0x39, + 0xa1, 0x34, 0xbc, 0xfb, 0xda, 0x1a, 0xb6, 0x52, 0x92, 0xb5, 0x8c, 0xa3, 0x65, 0x39, 0xf5, 0x60, + 0xac, 0x07, 0xdc, 0x01, 0x73, 0x52, 0xca, 0xa3, 0x24, 0xc4, 0x6e, 0xb1, 0x76, 0x6b, 0x93, 0x4a, + 0xc0, 0x95, 0x7d, 0x05, 0xdc, 0x49, 0x42, 0x5c, 0x28, 0xde, 0x96, 0xe5, 0xc8, 0x7c, 0x19, 0xda, + 0x87, 0x0f, 0xc1, 0x7f, 0xd4, 0x3d, 0xab, 0xc9, 0xe4, 0x66, 0x33, 0x72, 0x6a, 0x38, 0x8d, 0x8a, + 0xc5, 0x32, 0x38, 0x75, 0x5b, 0x96, 0x73, 0x3c, 0x18, 0x9a, 0xe2, 0x45, 0xf6, 0xf4, 0x63, 0xbc, + 0x76, 0xf8, 0x75, 0xd9, 0x73, 0xed, 0xa6, 0xcf, 0x9e, 0x0d, 0xb6, 0x1b, 0xba, 0x16, 0xbb, 0x4c, + 0x90, 0x1a, 0x50, 0x94, 0xa7, 0x46, 0x4d, 0xde, 0x2d, 0x26, 0x88, 0x29, 0x45, 0xf9, 0x08, 0x57, + 0xc1, 0xb4, 0x84, 0x62, 0x12, 0x31, 0x4e, 0x45, 0x6d, 0xba, 0xac, 0xbd, 0xf4, 0xd1, 0xeb, 0xda, + 0xad, 0x65, 0x39, 0x20, 0xc8, 0x56, 0x70, 0x1d, 0xc8, 0x95, 0x9b, 0x84, 0x5f, 0x20, 0xda, 0xa9, + 0xcd, 0x28, 0x8a, 0xb3, 0x03, 0xdf, 0x78, 0xe6, 0x67, 0x8c, 0xe1, 0x79, 0xa0, 0x5c, 0x5b, 0x96, + 0x73, 0x38, 0x48, 0x17, 0xd0, 0xd5, 0x85, 0xec, 0xc5, 0x04, 0x09, 0xd2, 0x4f, 0xbb, 0xda, 0x11, + 0xc5, 0x77, 0x71, 0x80, 0x4f, 0xff, 0xf0, 0x31, 0x74, 0x6b, 0x0a, 0x93, 0xa5, 0x90, 0xa9, 0xe4, + 0x81, 0x5d, 0xf8, 0x09, 0x90, 0xbb, 0x2e, 0xc1, 0x54, 0xe4, 0xe8, 0x8f, 0x2a, 0xfa, 0x37, 0xc7, + 0xd1, 0xdf, 0xc6, 0x54, 0xe4, 0xc9, 0x67, 0x83, 0x81, 0x3d, 0x78, 0x17, 0xcc, 0xe8, 0x53, 0x54, + 0xc5, 0x44, 0x6a, 0xc7, 0x14, 0xe9, 0xb9, 0x71, 0xa4, 0xa6, 0xf0, 0xe4, 0x65, 0x4c, 0x07, 0xfd, + 0x65, 0x7a, 0x0c, 0x6d, 0xe2, 0xd3, 0xd0, 0x8d, 0x49, 0x46, 0x39, 0xbb, 0xff, 0x31, 0xac, 0x4a, + 0x8c, 0x93, 0x41, 0xcc, 0x31, 0x0c, 0xec, 0xc2, 0x8f, 0x74, 0xf3, 0x4d, 0xc2, 0x8c, 0xfa, 0x78, + 0xd9, 0x07, 0x70, 0x91, 0xfa, 0x41, 0x98, 0x63, 0x3d, 0x12, 0xe4, 0x37, 0x9a, 0x17, 0x9e, 0x3d, + 0x59, 0x3e, 0x3f, 0x76, 0xce, 0xe9, 0x09, 0x27, 0x15, 0x9a, 0xe9, 0xf6, 0x5d, 0x05, 0x4c, 0x6e, + 0x52, 0x3f, 0x5c, 0x67, 0x1e, 0xbc, 0x53, 0x98, 0x6c, 0xe7, 0x46, 0x4e, 0x36, 0xe3, 0xff, 0x6f, + 0x8c, 0xb7, 0xd5, 0x5b, 0x4f, 0x5f, 0xd6, 0x2b, 0xcf, 0x5f, 0xd6, 0x2b, 0x7f, 0xbc, 0xac, 0x57, + 0xbe, 0x7f, 0x55, 0xb7, 0x9e, 0xbf, 0xaa, 0x5b, 0xbf, 0xbf, 0xaa, 0x5b, 0x9f, 0x8e, 0x7f, 0xb1, + 0xec, 0x7f, 0x21, 0xed, 0x09, 0xf5, 0xa3, 0xf9, 0xea, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xb6, + 0xc7, 0x0e, 0x8b, 0x1f, 0x11, 0x00, 0x00, } func (this *Supply) Equal(that interface{}) bool { @@ -1188,10 +1188,10 @@ func (this *MsgSubmitEvidence) Equal(that interface{}) bool { } else if this == nil { return false } - if !this.Evidence.Equal(that1.Evidence) { + if !this.MsgSubmitEvidenceBase.Equal(&that1.MsgSubmitEvidenceBase) { return false } - if !this.MsgSubmitEvidenceBase.Equal(&that1.MsgSubmitEvidenceBase) { + if !this.Evidence.Equal(that1.Evidence) { return false } return true @@ -1976,16 +1976,6 @@ func (m *MsgSubmitEvidence) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - { - size, err := m.MsgSubmitEvidenceBase.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintCodec(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 if m.Evidence != nil { { size, err := m.Evidence.MarshalToSizedBuffer(dAtA[:i]) @@ -1996,8 +1986,18 @@ func (m *MsgSubmitEvidence) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintCodec(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0xa + dAtA[i] = 0x12 + } + { + size, err := m.MsgSubmitEvidenceBase.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCodec(dAtA, i, uint64(size)) } + i-- + dAtA[i] = 0xa return len(dAtA) - i, nil } @@ -2850,12 +2850,12 @@ func (m *MsgSubmitEvidence) Size() (n int) { } var l int _ = l + l = m.MsgSubmitEvidenceBase.Size() + n += 1 + l + sovCodec(uint64(l)) if m.Evidence != nil { l = m.Evidence.Size() n += 1 + l + sovCodec(uint64(l)) } - l = m.MsgSubmitEvidenceBase.Size() - n += 1 + l + sovCodec(uint64(l)) return n } @@ -3650,7 +3650,7 @@ func (m *MsgSubmitEvidence) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Evidence", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field MsgSubmitEvidenceBase", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -3677,16 +3677,13 @@ func (m *MsgSubmitEvidence) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.Evidence == nil { - m.Evidence = &Evidence{} - } - if err := m.Evidence.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.MsgSubmitEvidenceBase.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field MsgSubmitEvidenceBase", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Evidence", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -3713,7 +3710,10 @@ func (m *MsgSubmitEvidence) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.MsgSubmitEvidenceBase.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if m.Evidence == nil { + m.Evidence = &Evidence{} + } + if err := m.Evidence.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex diff --git a/codec/std/codec.proto b/codec/std/codec.proto index 4f3f8034ad4d..c7246a69cdd9 100644 --- a/codec/std/codec.proto +++ b/codec/std/codec.proto @@ -61,8 +61,8 @@ message MsgSubmitEvidence { option (gogoproto.equal) = true; option (gogoproto.goproto_getters) = false; - Evidence evidence = 1; - cosmos_sdk.x.evidence.v1.MsgSubmitEvidenceBase base = 2 [(gogoproto.nullable) = false, (gogoproto.embed) = true]; + cosmos_sdk.x.evidence.v1.MsgSubmitEvidenceBase base = 1 [(gogoproto.nullable) = false, (gogoproto.embed) = true]; + Evidence evidence = 2; } // MsgSubmitProposal defines the application-level message type for handling From d635de4c47cc7abd0cba368be27101e6b1a7aee4 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Fri, 13 Mar 2020 09:35:03 -0400 Subject: [PATCH 411/529] Msgs tests --- codec/std/msgs_test.go | 46 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 codec/std/msgs_test.go diff --git a/codec/std/msgs_test.go b/codec/std/msgs_test.go new file mode 100644 index 000000000000..bd3063ecba1f --- /dev/null +++ b/codec/std/msgs_test.go @@ -0,0 +1,46 @@ +package std_test + +import ( + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/codec/std" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/evidence" + "github.com/cosmos/cosmos-sdk/x/gov" +) + +type BadEvidence struct { + *std.Evidence_Equivocation +} + +func TestNewMsgSubmitEvidence(t *testing.T) { + s := sdk.AccAddress("foo") + e := evidence.Equivocation{ + Height: 100, + Time: time.Now().UTC(), + Power: 40000000000, + ConsensusAddress: sdk.ConsAddress("test"), + } + + msg, err := std.NewMsgSubmitEvidence(e, s) + require.NoError(t, err) + require.Equal(t, msg.GetEvidence(), &e) + require.Equal(t, msg.GetSubmitter(), s) + require.NoError(t, msg.ValidateBasic()) +} + +func TestNewNewMsgSubmitProposal(t *testing.T) { + p := sdk.AccAddress("foo") + d := sdk.NewCoins(sdk.NewInt64Coin("stake", 1000)) + c := gov.TextProposal{Title: "title", Description: "description"} + + msg, err := std.NewMsgSubmitProposal(c, d, p) + require.NoError(t, err) + require.Equal(t, msg.GetContent(), &c) + require.Equal(t, msg.GetProposer(), p) + require.Equal(t, msg.GetInitialDeposit(), d) + require.NoError(t, msg.ValidateBasic()) +} From 690f6290c8d3201f13456109aa8d62b78289c57a Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Fri, 13 Mar 2020 09:35:14 -0400 Subject: [PATCH 412/529] Update ADR --- docs/architecture/adr-020-protobuf-transaction-encoding.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/architecture/adr-020-protobuf-transaction-encoding.md b/docs/architecture/adr-020-protobuf-transaction-encoding.md index 6fd37bda8c32..75cc85e32d44 100644 --- a/docs/architecture/adr-020-protobuf-transaction-encoding.md +++ b/docs/architecture/adr-020-protobuf-transaction-encoding.md @@ -3,6 +3,7 @@ ## Changelog - 2020 March 06: Initial Draft +- 2020 March 12: API Updates ## Status From 0b76411469b15b006df370f1207cac1793d98163 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Fri, 13 Mar 2020 09:36:29 -0400 Subject: [PATCH 413/529] Update StdTx --- x/auth/types/stdtx.go | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/x/auth/types/stdtx.go b/x/auth/types/stdtx.go index a6a5e79c31f3..7d30c87af55f 100644 --- a/x/auth/types/stdtx.go +++ b/x/auth/types/stdtx.go @@ -25,6 +25,16 @@ func NewStdFee(gas uint64, amount sdk.Coins) StdFee { } } +// GetGas returns the fee's (wanted) gas. +func (fee StdFee) GetGas() uint64 { + return fee.Gas +} + +// GetAmount returns the fee's amount. +func (fee StdFee) GetAmount() sdk.Coins { + return fee.Amount +} + // Bytes returns the encoded bytes of a StdFee. func (fee StdFee) Bytes() []byte { if len(fee.Amount) == 0 { @@ -48,6 +58,15 @@ func (fee StdFee) GasPrices() sdk.DecCoins { return sdk.NewDecCoinsFromCoins(fee.Amount...).QuoDec(sdk.NewDec(int64(fee.Gas))) } +func NewStdSignature(pk crypto.PubKey, sig []byte) StdSignature { + return StdSignature{PubKey: pk.Bytes(), Signature: sig} +} + +// GetSignature returns the raw signature bytes. +func (ss StdSignature) GetSignature() []byte { + return ss.Signature +} + // GetPubKey returns the public key of a signature as a crypto.PubKey using the // Amino codec. func (ss StdSignature) GetPubKey() (pk crypto.PubKey) { @@ -88,6 +107,24 @@ func (ss StdSignature) MarshalYAML() (interface{}, error) { return string(bz), err } +func NewStdTxBase(fee StdFee, sigs []StdSignature, memo string) StdTxBase { + return StdTxBase{ + Fee: fee, + Signatures: sigs, + Memo: memo, + } +} + +func NewStdSignDocBase(num, seq uint64, cid, memo string, fee StdFee) StdSignDocBase { + return StdSignDocBase{ + ChainID: cid, + AccountNumber: num, + Sequence: seq, + Memo: memo, + Fee: fee, + } +} + // CountSubKeys counts the total number of keys for a multi-sig public key. func CountSubKeys(pub crypto.PubKey) int { v, ok := pub.(multisig.PubKeyMultisigThreshold) From 0a79849d6e1ecd539c625478919bdc40bb8b0586 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Fri, 13 Mar 2020 09:51:11 -0400 Subject: [PATCH 414/529] Test tx --- codec/std/tx.go | 102 +++++++++++++++++++++++++++++++++++-------- codec/std/tx_test.go | 38 ++++++++++++++++ 2 files changed, 123 insertions(+), 17 deletions(-) create mode 100644 codec/std/tx_test.go diff --git a/codec/std/tx.go b/codec/std/tx.go index 595fbd848c10..b370945232e7 100644 --- a/codec/std/tx.go +++ b/codec/std/tx.go @@ -6,12 +6,28 @@ import ( jsonc "github.com/gibson042/canonicaljson-go" "github.com/gogo/protobuf/jsonpb" + "github.com/cosmos/cosmos-sdk/client" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/auth" ) -var _ sdk.Tx = Transaction{} +var ( + _ sdk.Tx = (*Transaction)(nil) + _ client.ClientTx = (*Transaction)(nil) +) + +func NewTransaction(fee auth.StdFee, memo string, sdkMsgs []sdk.Msg) (*Transaction, error) { + tx := &Transaction{ + StdTxBase: auth.NewStdTxBase(fee, nil, memo), + } + + if err := tx.SetMsgs(sdkMsgs...); err != nil { + return nil, err + } + + return tx, nil +} // GetMsgs returns all the messages in a Transaction as a slice of sdk.Msg. func (tx Transaction) GetMsgs() []sdk.Msg { @@ -47,16 +63,16 @@ func (tx Transaction) GetSigners() []sdk.AccAddress { // ValidateBasic does a simple and lightweight validation check that doesn't // require access to any other information. func (tx Transaction) ValidateBasic() error { - stdSigs := tx.Base.GetSignatures() + stdSigs := tx.GetSignatures() - if tx.Base.Fee.Gas > auth.MaxGasWanted { + if tx.Fee.Gas > auth.MaxGasWanted { return sdkerrors.Wrapf( - sdkerrors.ErrInvalidRequest, "invalid gas supplied; %d > %d", tx.Base.Fee.Gas, auth.MaxGasWanted, + sdkerrors.ErrInvalidRequest, "invalid gas supplied; %d > %d", tx.Fee.Gas, auth.MaxGasWanted, ) } - if tx.Base.Fee.Amount.IsAnyNegative() { + if tx.Fee.Amount.IsAnyNegative() { return sdkerrors.Wrapf( - sdkerrors.ErrInsufficientFee, "invalid fee provided: %s", tx.Base.Fee.Amount, + sdkerrors.ErrInsufficientFee, "invalid fee provided: %s", tx.Fee.Amount, ) } if len(stdSigs) == 0 { @@ -71,24 +87,76 @@ func (tx Transaction) ValidateBasic() error { return nil } +// SetMsgs sets the messages for a Transaction. It will overwrite any existing +// messages set. +func (tx *Transaction) SetMsgs(sdkMsgs ...sdk.Msg) error { + msgs := make([]Message, len(sdkMsgs)) + for i, msg := range sdkMsgs { + m := &Message{} + if err := m.SetMsg(msg); err != nil { + return err + } + + msgs[i] = *m + } + + tx.Msgs = msgs + return nil +} + +// GetSignatures returns all the transaction's signatures. +func (tx Transaction) GetSignatures() []sdk.Signature { + sdkSigs := make([]sdk.Signature, len(tx.Signatures)) + for i, sig := range tx.Signatures { + sdkSigs[i] = sig + } + + return sdkSigs +} + +// SetSignatures sets the transaction's signatures. It will overwrite any +// existing signatures set. +func (tx *Transaction) SetSignatures(sdkSigs ...sdk.Signature) { + sigs := make([]auth.StdSignature, len(tx.Signatures)) + for i, sig := range sdkSigs { + sigs[i] = auth.NewStdSignature(sig.GetPubKey(), sig.GetSignature()) + } + + tx.Signatures = sigs +} + +// GetFee returns the transaction's fee. +func (tx Transaction) GetFee() sdk.Fee { + return tx.Fee +} + +// SetFee sets the transaction's fee. It will overwrite any existing fee set. +func (tx *Transaction) SetFee(fee sdk.Fee) { + tx.Fee = auth.NewStdFee(fee.GetGas(), fee.GetAmount()) +} + +// GetMemo returns the transaction's memo. +func (tx Transaction) GetMemo() string { + return tx.Memo +} + +// SetMemo sets the transaction's memo. It will overwrite any existing memo set. +func (tx *Transaction) SetMemo(memo string) { + tx.Memo = memo +} + // CanonicalSignBytes returns the canonical JSON bytes to sign over for the // Transaction given a chain ID, account sequence and account number. The JSON // encoding ensures all field names adhere to their proto definition, default // values are omitted, and follows the JSON Canonical Form. -func (tx Transaction) CanonicalSignBytes(cid string, a, s uint64) ([]byte, error) { - return NewSignDoc(a, s, cid, tx.Base.Memo, tx.Base.Fee, tx.Msgs...).CanonicalSignBytes() +func (tx Transaction) CanonicalSignBytes(cid string, num, seq uint64) ([]byte, error) { + return NewSignDoc(num, seq, cid, tx.Memo, tx.Fee, tx.Msgs...).CanonicalSignBytes() } -func NewSignDoc(a, s uint64, cid, m string, f auth.StdFee, msgs ...Message) *SignDoc { +func NewSignDoc(num, seq uint64, cid, memo string, fee auth.StdFee, msgs ...Message) *SignDoc { return &SignDoc{ - StdSignDocBase: auth.StdSignDocBase{ - ChainID: cid, - AccountNumber: a, - Sequence: s, - Memo: m, - Fee: f, - }, - Msgs: msgs, + StdSignDocBase: auth.NewStdSignDocBase(num, seq, cid, memo, fee), + Msgs: msgs, } } diff --git a/codec/std/tx_test.go b/codec/std/tx_test.go new file mode 100644 index 000000000000..5fce75a67e92 --- /dev/null +++ b/codec/std/tx_test.go @@ -0,0 +1,38 @@ +package std_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/codec/std" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/bank" +) + +func TestTransaction(t *testing.T) { + f := auth.NewStdFee(100, sdk.NewCoins(sdk.NewInt64Coin("stake", 50))) + m := "hello world" + acc1 := sdk.AccAddress("from") + acc2 := sdk.AccAddress("to") + msg1 := bank.NewMsgSend(acc1, acc2, sdk.NewCoins(sdk.NewInt64Coin("stake", 100000))) + sdkMsgs := []sdk.Msg{&msg1} + + tx, err := std.NewTransaction(f, m, sdkMsgs) + require.NoError(t, err) + require.NotNil(t, tx) + require.Equal(t, tx.GetMsgs(), sdkMsgs) + require.Equal(t, tx.GetSigners(), []sdk.AccAddress{acc1}) + require.Equal(t, tx.GetFee(), f) + require.Equal(t, tx.GetMemo(), m) + + // no signatures; validation should fail + require.Empty(t, tx.GetSignatures()) + require.Error(t, tx.ValidateBasic()) + + signDocJSON := `{"base":{"accountNumber":"1","chainId":"chain-test","fee":{"amount":[{"amount":"50","denom":"stake"}],"gas":"100"},"memo":"hello world","sequence":"21"},"msgs":[{"msgSend":{"amount":[{"amount":"100000","denom":"stake"}],"fromAddress":"cosmos1veex7mgzt83cu","toAddress":"cosmos1w3hsjttrfq"}}]}` + bz, err := tx.CanonicalSignBytes("chain-test", 1, 21) + require.NoError(t, err) + require.Equal(t, signDocJSON, string(bz)) +} From 217cae2021d7e02e52bf43c3c704940940f612a1 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Fri, 13 Mar 2020 09:57:15 -0400 Subject: [PATCH 415/529] DRY code --- codec/std/tx.go | 23 +---------------------- types/codec.go | 27 +++++++++++++++++++++++++++ types/tx_msg.go | 5 ++--- 3 files changed, 30 insertions(+), 25 deletions(-) diff --git a/codec/std/tx.go b/codec/std/tx.go index b370945232e7..a8aadf0899b6 100644 --- a/codec/std/tx.go +++ b/codec/std/tx.go @@ -1,11 +1,6 @@ package std import ( - "bytes" - - jsonc "github.com/gibson042/canonicaljson-go" - "github.com/gogo/protobuf/jsonpb" - "github.com/cosmos/cosmos-sdk/client" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" @@ -165,21 +160,5 @@ func NewSignDoc(num, seq uint64, cid, memo string, fee auth.StdFee, msgs ...Mess // names adhere to their proto definition, default values are omitted, and follows // the JSON Canonical Form. func (sd *SignDoc) CanonicalSignBytes() ([]byte, error) { - jm := &jsonpb.Marshaler{EmitDefaults: false, OrigName: false} - buf := new(bytes.Buffer) - - // first, encode via canonical Protocol Buffer JSON - if err := jm.Marshal(buf, sd); err != nil { - return nil, err - } - - genericJSON := make(map[string]interface{}) - - // decode canonical proto encoding into a generic map - if err := jsonc.Unmarshal(buf.Bytes(), &genericJSON); err != nil { - return nil, err - } - - // finally, return the canonical JSON encoding via JSON Canonical Form - return jsonc.Marshal(genericJSON) + return sdk.CanonicalSignBytes(sd) } diff --git a/types/codec.go b/types/codec.go index fdd884bd5f84..6f7d03e5c91b 100644 --- a/types/codec.go +++ b/types/codec.go @@ -1,6 +1,11 @@ package types import ( + "bytes" + + jsonc "github.com/gibson042/canonicaljson-go" + "github.com/gogo/protobuf/jsonpb" + "github.com/cosmos/cosmos-sdk/codec" ) @@ -9,3 +14,25 @@ func RegisterCodec(cdc *codec.Codec) { cdc.RegisterInterface((*Msg)(nil), nil) cdc.RegisterInterface((*Tx)(nil), nil) } + +// CanonicalSignBytes returns a canonical JSON encoding of a message that can be +// signed over. +func CanonicalSignBytes(m codec.ProtoMarshaler) ([]byte, error) { + jm := &jsonpb.Marshaler{EmitDefaults: false, OrigName: false} + buf := new(bytes.Buffer) + + // first, encode via canonical Protocol Buffer JSON + if err := jm.Marshal(buf, m); err != nil { + return nil, err + } + + genericJSON := make(map[string]interface{}) + + // decode canonical proto encoding into a generic map + if err := jsonc.Unmarshal(buf.Bytes(), &genericJSON); err != nil { + return nil, err + } + + // finally, return the canonical JSON encoding via JSON Canonical Form + return jsonc.Marshal(genericJSON) +} diff --git a/types/tx_msg.go b/types/tx_msg.go index 20ead7db1945..b81eb26f5855 100644 --- a/types/tx_msg.go +++ b/types/tx_msg.go @@ -7,7 +7,7 @@ import ( ) type ( -// Msg defines the interface a transaction message must fulfill. + // Msg defines the interface a transaction message must fulfill. Msg interface { // Return the message type. @@ -45,7 +45,7 @@ type ( GetSignature() []byte } -// Tx defines the interface a transaction must fulfill. + // Tx defines the interface a transaction must fulfill. Tx interface { // Gets the all the transaction's messages. GetMsgs() []Msg @@ -56,7 +56,6 @@ type ( } ) - // TxDecoder unmarshals transaction bytes type TxDecoder func(txBytes []byte) (Tx, error) From 7838d750e10bc1d1a21835a4f31cb935115e85cf Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Fri, 13 Mar 2020 09:58:53 -0400 Subject: [PATCH 416/529] Update godoc --- types/codec.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/types/codec.go b/types/codec.go index 6f7d03e5c91b..21cd269043a0 100644 --- a/types/codec.go +++ b/types/codec.go @@ -15,8 +15,10 @@ func RegisterCodec(cdc *codec.Codec) { cdc.RegisterInterface((*Tx)(nil), nil) } -// CanonicalSignBytes returns a canonical JSON encoding of a message that can be -// signed over. +// CanonicalSignBytes returns a canonical JSON encoding of a Proto message that +// can be signed over. The JSON encoding ensures all field names adhere to their +// Proto definition, default values are omitted, and follows the JSON Canonical +// Form. func CanonicalSignBytes(m codec.ProtoMarshaler) ([]byte, error) { jm := &jsonpb.Marshaler{EmitDefaults: false, OrigName: false} buf := new(bytes.Buffer) From c49af0b8dd1db91dfa3a79a749ca8f287922ab7d Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Fri, 13 Mar 2020 13:59:14 -0400 Subject: [PATCH 417/529] Update context --- client/context/context.go | 20 ++++++++++++++++++- client/{ => tx}/tx.go | 10 +--------- codec/std/tx.go | 16 ++++++++++++--- .../adr-020-protobuf-transaction-encoding.md | 13 +++--------- 4 files changed, 36 insertions(+), 23 deletions(-) rename client/{ => tx}/tx.go (75%) diff --git a/client/context/context.go b/client/context/context.go index 28bfe8e830b0..eec74e7febaf 100644 --- a/client/context/context.go +++ b/client/context/context.go @@ -14,6 +14,7 @@ import ( rpcclient "github.com/tendermint/tendermint/rpc/client" "github.com/cosmos/cosmos-sdk/client/flags" + clientx "github.com/cosmos/cosmos-sdk/client/tx" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/crypto/keys" sdk "github.com/cosmos/cosmos-sdk/types" @@ -25,6 +26,8 @@ type CLIContext struct { FromAddress sdk.AccAddress Client rpcclient.Client ChainID string + TxGenerator clientx.TxGenerator + Marshaler codec.Marshaler Keybase keys.Keybase Input io.Reader Output io.Writer @@ -36,13 +39,15 @@ type CLIContext struct { BroadcastMode string Verifier tmlite.Verifier FromName string - Codec *codec.Codec TrustNode bool UseLedger bool Simulate bool GenerateOnly bool Indent bool SkipConfirm bool + + // TODO: Deprecated (remove). + Codec *codec.Codec } // NewCLIContextWithInputAndFrom returns a new initialized CLIContext with parameters from the @@ -130,7 +135,20 @@ func (ctx CLIContext) WithInput(r io.Reader) CLIContext { return ctx } +// WithTxGenerator returns a copy of the CLIContext with an updated TxGenerator. +func (ctx CLIContext) WithTxGenerator(txg clientx.TxGenerator) CLIContext { + ctx.TxGenerator = txg + return ctx +} + +// WithMarshaler returns a copy of the CLIContext with an updated Marshaler. +func (ctx CLIContext) WithMarshaler(m codec.Marshaler) CLIContext { + ctx.Marshaler = m + return ctx +} + // WithCodec returns a copy of the context with an updated codec. +// TODO: Deprecated (remove). func (ctx CLIContext) WithCodec(cdc *codec.Codec) CLIContext { ctx.Codec = cdc return ctx diff --git a/client/tx.go b/client/tx/tx.go similarity index 75% rename from client/tx.go rename to client/tx/tx.go index d7fdb82981d4..ead819f33472 100644 --- a/client/tx.go +++ b/client/tx/tx.go @@ -1,4 +1,4 @@ -package client +package tx import ( "github.com/cosmos/cosmos-sdk/codec" @@ -6,14 +6,6 @@ import ( ) type ( - // ClientMarshaler defines an interface that REST and CLI handler will use to - // create application-specific transactions and be able to serialize types - // specific to the application including transactions. - ClientMarshaler interface { - TxGenerator - codec.Marshaler - } - // TxGenerator defines an interface a client can utilize to generate an // application-defined concrete transaction type. The type returned must // implement ClientTx. diff --git a/codec/std/tx.go b/codec/std/tx.go index a8aadf0899b6..2a9b9af29b82 100644 --- a/codec/std/tx.go +++ b/codec/std/tx.go @@ -1,17 +1,27 @@ package std import ( - "github.com/cosmos/cosmos-sdk/client" + clientx "github.com/cosmos/cosmos-sdk/client/tx" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/auth" ) var ( - _ sdk.Tx = (*Transaction)(nil) - _ client.ClientTx = (*Transaction)(nil) + _ sdk.Tx = (*Transaction)(nil) + _ clientx.ClientTx = (*Transaction)(nil) + _ clientx.TxGenerator = TxGenerator{} ) +// TxGenerator defines a transaction generator that allows clients to construct +// transactions. +type TxGenerator struct{} + +// NewTx returns a reference to an empty Transaction type. +func (TxGenerator) NewTx() clientx.ClientTx { + return &Transaction{} +} + func NewTransaction(fee auth.StdFee, memo string, sdkMsgs []sdk.Msg) (*Transaction, error) { tx := &Transaction{ StdTxBase: auth.NewStdTxBase(fee, nil, memo), diff --git a/docs/architecture/adr-020-protobuf-transaction-encoding.md b/docs/architecture/adr-020-protobuf-transaction-encoding.md index 75cc85e32d44..d5a72f3afbe5 100644 --- a/docs/architecture/adr-020-protobuf-transaction-encoding.md +++ b/docs/architecture/adr-020-protobuf-transaction-encoding.md @@ -123,18 +123,11 @@ type ClientTx interface { } ``` -We then extend `codec.Marshaler` to also require fulfillment of `TxGenerator`. +We then update `CLIContext` to have two new fields: `TxGenerator` and `TxGenerator`. -```go -type ClientMarshaler interface { - TxGenerator - codec.Marshaler -} -``` - -Then, each module will at the minimum accept a `ClientMarshaler` instead of a concrete +Then, each module will at the minimum accept a `Marshaler` instead of a concrete Amino codec. If the module needs to work with any interface types, it will use -the `Codec` interface defined by the module which also extends `ClientMarshaler`. +the `Codec` interface defined by the module which also extends `Marshaler`. ## Future Improvements From 2e42f9cb745aaa4c1a52ee730a969a5eaa938360 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Fri, 13 Mar 2020 20:58:43 +0100 Subject: [PATCH 418/529] Favor marshal unmashal binare bare (#5799) * change abci file to use BinaryBare * change all calls to EncodeLengthPrefixed to BinaryBare in distribution keeper store. * change all calls to EncodeLengthPrefixed to BinaryBare in mint keeper store. * change all calls to EncodeLengthPrefixed to BinaryBare in auth keeper store. * change all calls to EncodeLengthPrefixed to BinaryBare in distribution keeper store. * change all calls to EncodeLengthPrefixed to BinaryBare in staking keeper store. * change all calls to EncodeLengthPrefixed to BinaryBare in staking keeper store. * change all calls to EncodeLengthPrefixed to BinaryBare in gov keeper store. * change all calls to EncodeLengthPrefixed to BinaryBare in slashing keeper store. * update decoder test * migrate decoder * migrate gov simulation decoder * migrate baseapp_test * refactor QuerySubspace * refactor coedc std codec * migrate keybase * migrate iavl store * migrate root multi * migrate ante basic * migrate tx type to bare * migrate auth client * update auth types * update decoder * migrate supply decoder * migrate stake encoding * migrate staking simulation * migrate genutil * migrate simapp test helpers * migrate docs * upgrade changelog * Update CHANGELOG.md Co-Authored-By: Alexander Bezobchuk Co-authored-by: Alexander Bezobchuk --- CHANGELOG.md | 1 + baseapp/abci.go | 2 +- baseapp/baseapp_test.go | 30 +++++------ client/context/query.go | 2 +- codec/std/codec.go | 16 +++--- crypto/keys/keybase_base.go | 2 +- crypto/keys/types.go | 4 +- .../adr-019-protobuf-state-encoding.md | 6 +-- docs/core/store.md | 2 +- simapp/test_helpers.go | 2 +- simapp/utils_test.go | 2 +- store/iavl/store.go | 2 +- store/iavl/store_test.go | 6 +-- store/rootmulti/proof.go | 4 +- store/rootmulti/store.go | 8 +-- x/auth/ante/basic.go | 2 +- x/auth/client/cli/broadcast.go | 2 +- x/auth/client/cli/decode.go | 2 +- x/auth/client/cli/encode.go | 2 +- x/auth/client/query.go | 2 +- x/auth/client/rest/broadcast.go | 2 +- x/auth/client/rest/decode.go | 2 +- x/auth/client/rest/encode.go | 2 +- x/auth/client/tx.go | 2 +- x/auth/client/tx_test.go | 4 +- x/auth/keeper/keeper.go | 4 +- x/auth/simulation/decoder.go | 4 +- x/auth/simulation/decoder_test.go | 2 +- x/auth/types/stdtx.go | 4 +- x/auth/types/stdtx_test.go | 2 +- x/distribution/keeper/store.go | 52 +++++++++---------- x/distribution/simulation/decoder.go | 28 +++++----- x/distribution/simulation/decoder_test.go | 14 ++--- x/genutil/gentx.go | 2 +- x/gov/client/utils/query_test.go | 4 +- x/gov/keeper/deposit.go | 8 +-- x/gov/keeper/vote.go | 8 +-- x/gov/simulation/decoder.go | 12 ++--- x/gov/simulation/decoder_test.go | 6 +-- x/mint/keeper/keeper.go | 4 +- x/mint/simulation/decoder.go | 4 +- x/mint/simulation/decoder_test.go | 2 +- x/slashing/keeper/keeper.go | 4 +- x/slashing/keeper/signing_info.go | 12 ++--- x/slashing/simulation/decoder.go | 12 ++--- x/slashing/simulation/decoder_test.go | 6 +-- x/slashing/types/signing_info.go | 2 +- x/staking/keeper/delegation.go | 12 ++--- x/staking/keeper/keeper.go | 4 +- x/staking/keeper/val_state_change.go | 2 +- x/staking/keeper/validator.go | 14 ++--- x/staking/keeper/validator_test.go | 1 - x/staking/simulation/decoder.go | 20 +++---- x/staking/simulation/decoder_test.go | 10 ++-- x/staking/types/delegation.go | 12 ++--- x/staking/types/historical_info.go | 4 +- x/staking/types/params.go | 2 +- x/staking/types/validator.go | 4 +- x/supply/simulation/decoder.go | 4 +- x/supply/simulation/decoder_test.go | 2 +- 60 files changed, 199 insertions(+), 199 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0345af7539d8..1a19fb7b3961 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -148,6 +148,7 @@ Buffers for state serialization instead of Amino. to define their own concrete `MsgSubmitProposal` types. * The module now accepts a `Codec` interface which extends the `codec.Marshaler` interface by requiring a concrete codec to know how to serialize `Proposal` types. +* (codec) [\#5799](https://github.com/cosmos/cosmos-sdk/pull/5799) Now we favor the use of MarshalBinaryBare instead of LengthPrefixed in all cases that is not needed. ### Improvements diff --git a/baseapp/abci.go b/baseapp/abci.go index 57bcec661eff..834930196df5 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -331,7 +331,7 @@ func handleQueryApp(app *BaseApp, path []string, req abci.RequestQuery) abci.Res return abci.ResponseQuery{ Codespace: sdkerrors.RootCodespace, Height: req.Height, - Value: codec.Cdc.MustMarshalBinaryLengthPrefixed(gInfo.GasUsed), + Value: codec.Cdc.MustMarshalBinaryBare(gInfo.GasUsed), } case "version": diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index 840531865d31..2350ba64ceeb 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -386,7 +386,7 @@ func TestTxDecoder(t *testing.T) { app := newBaseApp(t.Name()) tx := newTxCounter(1, 0) - txBytes := codec.MustMarshalBinaryLengthPrefixed(tx) + txBytes := codec.MustMarshalBinaryBare(tx) dTx, err := app.txDecoder(txBytes) require.NoError(t, err) @@ -625,7 +625,7 @@ func testTxDecoder(cdc *codec.Codec) sdk.TxDecoder { return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "tx bytes are empty") } - err := cdc.UnmarshalBinaryLengthPrefixed(txBytes, &tx) + err := cdc.UnmarshalBinaryBare(txBytes, &tx) if err != nil { return nil, sdkerrors.ErrTxDecode } @@ -733,7 +733,7 @@ func TestCheckTx(t *testing.T) { for i := int64(0); i < nTxs; i++ { tx := newTxCounter(i, 0) - txBytes, err := codec.MarshalBinaryLengthPrefixed(tx) + txBytes, err := codec.MarshalBinaryBare(tx) require.NoError(t, err) r := app.CheckTx(abci.RequestCheckTx{Tx: txBytes}) assert.True(t, r.IsOK(), fmt.Sprintf("%v", r)) @@ -787,7 +787,7 @@ func TestDeliverTx(t *testing.T) { counter := int64(blockN*txPerHeight + i) tx := newTxCounter(counter, counter) - txBytes, err := codec.MarshalBinaryLengthPrefixed(tx) + txBytes, err := codec.MarshalBinaryBare(tx) require.NoError(t, err) res := app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) @@ -831,7 +831,7 @@ func TestMultiMsgDeliverTx(t *testing.T) { header := abci.Header{Height: 1} app.BeginBlock(abci.RequestBeginBlock{Header: header}) tx := newTxCounter(0, 0, 1, 2) - txBytes, err := codec.MarshalBinaryLengthPrefixed(tx) + txBytes, err := codec.MarshalBinaryBare(tx) require.NoError(t, err) res := app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) require.True(t, res.IsOK(), fmt.Sprintf("%v", res)) @@ -851,7 +851,7 @@ func TestMultiMsgDeliverTx(t *testing.T) { tx = newTxCounter(1, 3) tx.Msgs = append(tx.Msgs, msgCounter2{0}) tx.Msgs = append(tx.Msgs, msgCounter2{1}) - txBytes, err = codec.MarshalBinaryLengthPrefixed(tx) + txBytes, err = codec.MarshalBinaryBare(tx) require.NoError(t, err) res = app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) require.True(t, res.IsOK(), fmt.Sprintf("%v", res)) @@ -912,7 +912,7 @@ func TestSimulateTx(t *testing.T) { app.BeginBlock(abci.RequestBeginBlock{Header: header}) tx := newTxCounter(count, count) - txBytes, err := cdc.MarshalBinaryLengthPrefixed(tx) + txBytes, err := cdc.MarshalBinaryBare(tx) require.Nil(t, err) // simulate a message, check gas reported @@ -936,7 +936,7 @@ func TestSimulateTx(t *testing.T) { require.True(t, queryResult.IsOK(), queryResult.Log) var res uint64 - err = codec.Cdc.UnmarshalBinaryLengthPrefixed(queryResult.Value, &res) + err = codec.Cdc.UnmarshalBinaryBare(queryResult.Value, &res) require.NoError(t, err) require.Equal(t, gasConsumed, res) app.EndBlock(abci.RequestEndBlock{}) @@ -1036,7 +1036,7 @@ func TestRunInvalidTransaction(t *testing.T) { registerTestCodec(newCdc) newCdc.RegisterConcrete(&msgNoDecode{}, "cosmos-sdk/baseapp/msgNoDecode", nil) - txBytes, err := newCdc.MarshalBinaryLengthPrefixed(tx) + txBytes, err := newCdc.MarshalBinaryBare(tx) require.NoError(t, err) res := app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) @@ -1259,7 +1259,7 @@ func TestBaseAppAnteHandler(t *testing.T) { // the next txs ante handler execution (anteHandlerTxTest). tx := newTxCounter(0, 0) tx.setFailOnAnte(true) - txBytes, err := cdc.MarshalBinaryLengthPrefixed(tx) + txBytes, err := cdc.MarshalBinaryBare(tx) require.NoError(t, err) res := app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) require.False(t, res.IsOK(), fmt.Sprintf("%v", res)) @@ -1273,7 +1273,7 @@ func TestBaseAppAnteHandler(t *testing.T) { tx = newTxCounter(0, 0) tx.setFailOnHandler(true) - txBytes, err = cdc.MarshalBinaryLengthPrefixed(tx) + txBytes, err = cdc.MarshalBinaryBare(tx) require.NoError(t, err) res = app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) @@ -1288,7 +1288,7 @@ func TestBaseAppAnteHandler(t *testing.T) { // implicitly checked by previous tx executions tx = newTxCounter(1, 0) - txBytes, err = cdc.MarshalBinaryLengthPrefixed(tx) + txBytes, err = cdc.MarshalBinaryBare(tx) require.NoError(t, err) res = app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) @@ -1359,7 +1359,7 @@ func TestGasConsumptionBadTx(t *testing.T) { tx := newTxCounter(5, 0) tx.setFailOnAnte(true) - txBytes, err := cdc.MarshalBinaryLengthPrefixed(tx) + txBytes, err := cdc.MarshalBinaryBare(tx) require.NoError(t, err) res := app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) @@ -1367,7 +1367,7 @@ func TestGasConsumptionBadTx(t *testing.T) { // require next tx to fail due to black gas limit tx = newTxCounter(5, 0) - txBytes, err = cdc.MarshalBinaryLengthPrefixed(tx) + txBytes, err = cdc.MarshalBinaryBare(tx) require.NoError(t, err) res = app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) @@ -1529,7 +1529,7 @@ func TestWithRouter(t *testing.T) { counter := int64(blockN*txPerHeight + i) tx := newTxCounter(counter, counter) - txBytes, err := codec.MarshalBinaryLengthPrefixed(tx) + txBytes, err := codec.MarshalBinaryBare(tx) require.NoError(t, err) res := app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) diff --git a/client/context/query.go b/client/context/query.go index c0c45a226fb7..cfe08969f285 100644 --- a/client/context/query.go +++ b/client/context/query.go @@ -64,7 +64,7 @@ func (ctx CLIContext) QuerySubspace(subspace []byte, storeName string) (res []sd return res, height, err } - ctx.Codec.MustUnmarshalBinaryLengthPrefixed(resRaw, &res) + ctx.Codec.MustUnmarshalBinaryBare(resRaw, &res) return } diff --git a/codec/std/codec.go b/codec/std/codec.go index ce56ee61bca8..03f12020da24 100644 --- a/codec/std/codec.go +++ b/codec/std/codec.go @@ -44,14 +44,14 @@ func (c *Codec) MarshalAccount(accI authexported.Account) ([]byte, error) { return nil, err } - return c.Marshaler.MarshalBinaryLengthPrefixed(acc) + return c.Marshaler.MarshalBinaryBare(acc) } // UnmarshalAccount returns an Account interface from raw encoded account bytes // of a Proto-based Account type. An error is returned upon decoding failure. func (c *Codec) UnmarshalAccount(bz []byte) (authexported.Account, error) { acc := &Account{} - if err := c.Marshaler.UnmarshalBinaryLengthPrefixed(bz, acc); err != nil { + if err := c.Marshaler.UnmarshalBinaryBare(bz, acc); err != nil { return nil, err } @@ -83,14 +83,14 @@ func (c *Codec) MarshalSupply(supplyI supplyexported.SupplyI) ([]byte, error) { return nil, err } - return c.Marshaler.MarshalBinaryLengthPrefixed(supply) + return c.Marshaler.MarshalBinaryBare(supply) } // UnmarshalSupply returns a SupplyI interface from raw encoded account bytes // of a Proto-based SupplyI type. An error is returned upon decoding failure. func (c *Codec) UnmarshalSupply(bz []byte) (supplyexported.SupplyI, error) { supply := &Supply{} - if err := c.Marshaler.UnmarshalBinaryLengthPrefixed(bz, supply); err != nil { + if err := c.Marshaler.UnmarshalBinaryBare(bz, supply); err != nil { return nil, err } @@ -122,7 +122,7 @@ func (c *Codec) MarshalEvidence(evidenceI eviexported.Evidence) ([]byte, error) return nil, err } - return c.Marshaler.MarshalBinaryLengthPrefixed(evidence) + return c.Marshaler.MarshalBinaryBare(evidence) } // UnmarshalEvidence returns an Evidence interface from raw encoded evidence @@ -130,7 +130,7 @@ func (c *Codec) MarshalEvidence(evidenceI eviexported.Evidence) ([]byte, error) // failure. func (c *Codec) UnmarshalEvidence(bz []byte) (eviexported.Evidence, error) { evidence := &Evidence{} - if err := c.Marshaler.UnmarshalBinaryLengthPrefixed(bz, evidence); err != nil { + if err := c.Marshaler.UnmarshalBinaryBare(bz, evidence); err != nil { return nil, err } @@ -162,7 +162,7 @@ func (c *Codec) MarshalProposal(p gov.Proposal) ([]byte, error) { return nil, err } - return c.Marshaler.MarshalBinaryLengthPrefixed(proposal) + return c.Marshaler.MarshalBinaryBare(proposal) } // UnmarshalProposal decodes a Proposal defined by the x/gov module and uses the @@ -170,7 +170,7 @@ func (c *Codec) MarshalProposal(p gov.Proposal) ([]byte, error) { // to deserialize. func (c *Codec) UnmarshalProposal(bz []byte) (gov.Proposal, error) { proposal := &Proposal{} - if err := c.Marshaler.UnmarshalBinaryLengthPrefixed(bz, proposal); err != nil { + if err := c.Marshaler.UnmarshalBinaryBare(bz, proposal); err != nil { return gov.Proposal{}, err } diff --git a/crypto/keys/keybase_base.go b/crypto/keys/keybase_base.go index 47c7e60d729a..86ed00677d25 100644 --- a/crypto/keys/keybase_base.go +++ b/crypto/keys/keybase_base.go @@ -124,7 +124,7 @@ func (kb baseKeybase) DecodeSignature(info Info, msg []byte) (sig []byte, pub tm return nil, nil, err } - if err := CryptoCdc.UnmarshalBinaryLengthPrefixed([]byte(signed), sig); err != nil { + if err := CryptoCdc.UnmarshalBinaryBare([]byte(signed), sig); err != nil { return nil, nil, errors.Wrap(err, "failed to decode signature") } diff --git a/crypto/keys/types.go b/crypto/keys/types.go index 89f5cb2d539b..c91f2905b24e 100644 --- a/crypto/keys/types.go +++ b/crypto/keys/types.go @@ -337,12 +337,12 @@ func (i multiInfo) GetPath() (*hd.BIP44Params, error) { // encoding info func marshalInfo(i Info) []byte { - return CryptoCdc.MustMarshalBinaryLengthPrefixed(i) + return CryptoCdc.MustMarshalBinaryBare(i) } // decoding info func unmarshalInfo(bz []byte) (info Info, err error) { - err = CryptoCdc.UnmarshalBinaryLengthPrefixed(bz, &info) + err = CryptoCdc.UnmarshalBinaryBare(bz, &info) return } diff --git a/docs/architecture/adr-019-protobuf-state-encoding.md b/docs/architecture/adr-019-protobuf-state-encoding.md index 78a338cccb12..3f6a85b2af12 100644 --- a/docs/architecture/adr-019-protobuf-state-encoding.md +++ b/docs/architecture/adr-019-protobuf-state-encoding.md @@ -86,7 +86,7 @@ Example: // ... } - bz := cdc.MustMarshalBinaryLengthPrefixed(ts) + bz := cdc.MustMarshalBinaryBare(ts) ``` However, modules can vary greatly in purpose and design and so we must support the ability for modules @@ -161,12 +161,12 @@ func (c *Codec) MarshalAccount(accI authexported.Account) ([]byte, error) { return nil, err } - return c.Marshaler.MarshalBinaryLengthPrefixed(acc) + return c.Marshaler.MarshalBinaryBare(acc) } func (c *Codec) UnmarshalAccount(bz []byte) (authexported.Account, error) { acc := &Account{} - if err := c.Marshaler.UnmarshalBinaryLengthPrefixed(bz, acc); err != nil { + if err := c.Marshaler.UnmarshalBinaryBare(bz, acc); err != nil { return nil, err } diff --git a/docs/core/store.md b/docs/core/store.md index 35b3d0f2a2e1..31a8db919a0a 100644 --- a/docs/core/store.md +++ b/docs/core/store.md @@ -130,7 +130,7 @@ iterator := sdk.KVStorePrefixIterator(store, prefix) // proxy for store.Iterator defer iterator.Close() for ; iterator.Valid(); iterator.Next() { var object types.Object - keeper.cdc.MustUnmarshalBinaryLengthPrefixed(iterator.Value(), &object) + keeper.cdc.MustUnmarshalBinaryBare(iterator.Value(), &object) if cb(object) { break diff --git a/simapp/test_helpers.go b/simapp/test_helpers.go index 300235fe1c59..cf6dc8164efc 100644 --- a/simapp/test_helpers.go +++ b/simapp/test_helpers.go @@ -228,7 +228,7 @@ func SignCheckDeliver( priv..., ) - txBytes, err := cdc.MarshalBinaryLengthPrefixed(tx) + txBytes, err := cdc.MarshalBinaryBare(tx) require.Nil(t, err) // Must simulate now as CheckTx doesn't run Msgs anymore diff --git a/simapp/utils_test.go b/simapp/utils_test.go index 710c2b9d4863..729ceddc286a 100644 --- a/simapp/utils_test.go +++ b/simapp/utils_test.go @@ -31,7 +31,7 @@ func TestGetSimulationLog(t *testing.T) { }, { auth.StoreKey, - []tmkv.Pair{{Key: auth.GlobalAccountNumberKey, Value: cdc.MustMarshalBinaryLengthPrefixed(uint64(10))}}, + []tmkv.Pair{{Key: auth.GlobalAccountNumberKey, Value: cdc.MustMarshalBinaryBare(uint64(10))}}, "10", }, { diff --git a/store/iavl/store.go b/store/iavl/store.go index 311d0f887a66..3cc2a83b5ce1 100644 --- a/store/iavl/store.go +++ b/store/iavl/store.go @@ -312,7 +312,7 @@ func (st *Store) Query(req abci.RequestQuery) (res abci.ResponseQuery) { } iterator.Close() - res.Value = cdc.MustMarshalBinaryLengthPrefixed(KVs) + res.Value = cdc.MustMarshalBinaryBare(KVs) default: return sdkerrors.QueryResult(sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unexpected query path: %v", req.Path)) diff --git a/store/iavl/store_test.go b/store/iavl/store_test.go index ed138c84964f..ebfb32938fab 100644 --- a/store/iavl/store_test.go +++ b/store/iavl/store_test.go @@ -521,9 +521,9 @@ func TestIAVLStoreQuery(t *testing.T) { {Key: k1, Value: v3}, {Key: k2, Value: v2}, } - valExpSubEmpty := cdc.MustMarshalBinaryLengthPrefixed(KVs0) - valExpSub1 := cdc.MustMarshalBinaryLengthPrefixed(KVs1) - valExpSub2 := cdc.MustMarshalBinaryLengthPrefixed(KVs2) + valExpSubEmpty := cdc.MustMarshalBinaryBare(KVs0) + valExpSub1 := cdc.MustMarshalBinaryBare(KVs1) + valExpSub2 := cdc.MustMarshalBinaryBare(KVs2) cid := iavlStore.Commit() ver := cid.Version diff --git a/store/rootmulti/proof.go b/store/rootmulti/proof.go index a2fef8ae3ce9..af0f919c367b 100644 --- a/store/rootmulti/proof.go +++ b/store/rootmulti/proof.go @@ -68,7 +68,7 @@ func MultiStoreProofOpDecoder(pop merkle.ProofOp) (merkle.ProofOperator, error) // XXX: a bit strange as we'll discard this, but it works var op MultiStoreProofOp - err := cdc.UnmarshalBinaryLengthPrefixed(pop.Data, &op) + err := cdc.UnmarshalBinaryBare(pop.Data, &op) if err != nil { return nil, fmt.Errorf("decoding ProofOp.Data into MultiStoreProofOp: %w", err) } @@ -79,7 +79,7 @@ func MultiStoreProofOpDecoder(pop merkle.ProofOp) (merkle.ProofOperator, error) // ProofOp return a merkle proof operation from a given multi-store proof // operation. func (op MultiStoreProofOp) ProofOp() merkle.ProofOp { - bz := cdc.MustMarshalBinaryLengthPrefixed(op) + bz := cdc.MustMarshalBinaryBare(op) return merkle.ProofOp{ Type: ProofOpMultiStore, Key: op.key, diff --git a/store/rootmulti/store.go b/store/rootmulti/store.go index c88657741617..6b1cfde815ea 100644 --- a/store/rootmulti/store.go +++ b/store/rootmulti/store.go @@ -617,7 +617,7 @@ func getLatestVersion(db dbm.DB) int64 { return 0 } - err = cdc.UnmarshalBinaryLengthPrefixed(latestBytes, &latest) + err = cdc.UnmarshalBinaryBare(latestBytes, &latest) if err != nil { panic(err) } @@ -627,7 +627,7 @@ func getLatestVersion(db dbm.DB) int64 { // Set the latest version. func setLatestVersion(batch dbm.Batch, version int64) { - latestBytes, _ := cdc.MarshalBinaryLengthPrefixed(version) + latestBytes, _ := cdc.MarshalBinaryBare(version) batch.Set([]byte(latestVersionKey), latestBytes) } @@ -668,7 +668,7 @@ func getCommitInfo(db dbm.DB, ver int64) (commitInfo, error) { var cInfo commitInfo - err = cdc.UnmarshalBinaryLengthPrefixed(cInfoBytes, &cInfo) + err = cdc.UnmarshalBinaryBare(cInfoBytes, &cInfo) if err != nil { return commitInfo{}, errors.Wrap(err, "failed to get store") } @@ -678,7 +678,7 @@ func getCommitInfo(db dbm.DB, ver int64) (commitInfo, error) { // Set a commitInfo for given version. func setCommitInfo(batch dbm.Batch, version int64, cInfo commitInfo) { - cInfoBytes := cdc.MustMarshalBinaryLengthPrefixed(cInfo) + cInfoBytes := cdc.MustMarshalBinaryBare(cInfo) cInfoKey := fmt.Sprintf(commitInfoKeyFmt, version) batch.Set([]byte(cInfoKey), cInfoBytes) } diff --git a/x/auth/ante/basic.go b/x/auth/ante/basic.go index 05e570ca2854..37bc4f1c0f2a 100644 --- a/x/auth/ante/basic.go +++ b/x/auth/ante/basic.go @@ -130,7 +130,7 @@ func (cgts ConsumeTxSizeGasDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, sim PubKey: pubkey, } - sigBz := codec.Cdc.MustMarshalBinaryLengthPrefixed(simSig) + sigBz := codec.Cdc.MustMarshalBinaryBare(simSig) cost := sdk.Gas(len(sigBz) + 6) // If the pubkey is a multi-signature pubkey, then we estimate for the maximum diff --git a/x/auth/client/cli/broadcast.go b/x/auth/client/cli/broadcast.go index e5a62e388ed4..288b7c7de911 100644 --- a/x/auth/client/cli/broadcast.go +++ b/x/auth/client/cli/broadcast.go @@ -31,7 +31,7 @@ $ tx broadcast ./mytxn.json return } - txBytes, err := cliCtx.Codec.MarshalBinaryLengthPrefixed(stdTx) + txBytes, err := cliCtx.Codec.MarshalBinaryBare(stdTx) if err != nil { return } diff --git a/x/auth/client/cli/decode.go b/x/auth/client/cli/decode.go index c9253d8fb4a3..f4eb7e954fb1 100644 --- a/x/auth/client/cli/decode.go +++ b/x/auth/client/cli/decode.go @@ -44,7 +44,7 @@ func runDecodeTxString(codec *amino.Codec) func(cmd *cobra.Command, args []strin } var stdTx authtypes.StdTx - err = cliCtx.Codec.UnmarshalBinaryLengthPrefixed(txBytes, &stdTx) + err = cliCtx.Codec.UnmarshalBinaryBare(txBytes, &stdTx) if err != nil { return err } diff --git a/x/auth/client/cli/encode.go b/x/auth/client/cli/encode.go index fa39a58cab93..245bb0e0f675 100644 --- a/x/auth/client/cli/encode.go +++ b/x/auth/client/cli/encode.go @@ -37,7 +37,7 @@ If you supply a dash (-) argument in place of an input filename, the command rea } // re-encode it via the Amino wire protocol - txBytes, err := cliCtx.Codec.MarshalBinaryLengthPrefixed(stdTx) + txBytes, err := cliCtx.Codec.MarshalBinaryBare(stdTx) if err != nil { return err } diff --git a/x/auth/client/query.go b/x/auth/client/query.go index ad00ca740371..85bd747bc3c5 100644 --- a/x/auth/client/query.go +++ b/x/auth/client/query.go @@ -172,7 +172,7 @@ func formatTxResult(cdc *codec.Codec, resTx *ctypes.ResultTx, resBlock *ctypes.R func parseTx(cdc *codec.Codec, txBytes []byte) (sdk.Tx, error) { var tx types.StdTx - err := cdc.UnmarshalBinaryLengthPrefixed(txBytes, &tx) + err := cdc.UnmarshalBinaryBare(txBytes, &tx) if err != nil { return nil, err } diff --git a/x/auth/client/rest/broadcast.go b/x/auth/client/rest/broadcast.go index e7609194c390..92a94eefccd5 100644 --- a/x/auth/client/rest/broadcast.go +++ b/x/auth/client/rest/broadcast.go @@ -34,7 +34,7 @@ func BroadcastTxRequest(cliCtx context.CLIContext) http.HandlerFunc { return } - txBytes, err := cliCtx.Codec.MarshalBinaryLengthPrefixed(req.Tx) + txBytes, err := cliCtx.Codec.MarshalBinaryBare(req.Tx) if err != nil { rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return diff --git a/x/auth/client/rest/decode.go b/x/auth/client/rest/decode.go index 98c4f0c6da04..dfe7436b8e72 100644 --- a/x/auth/client/rest/decode.go +++ b/x/auth/client/rest/decode.go @@ -46,7 +46,7 @@ func DecodeTxRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { } var stdTx authtypes.StdTx - err = cliCtx.Codec.UnmarshalBinaryLengthPrefixed(txBytes, &stdTx) + err = cliCtx.Codec.UnmarshalBinaryBare(txBytes, &stdTx) if err != nil { rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return diff --git a/x/auth/client/rest/encode.go b/x/auth/client/rest/encode.go index e2d9f4fea319..b2fe6681e10e 100644 --- a/x/auth/client/rest/encode.go +++ b/x/auth/client/rest/encode.go @@ -35,7 +35,7 @@ func EncodeTxRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { } // re-encode it via the Amino wire protocol - txBytes, err := cliCtx.Codec.MarshalBinaryLengthPrefixed(req) + txBytes, err := cliCtx.Codec.MarshalBinaryBare(req) if err != nil { rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return diff --git a/x/auth/client/tx.go b/x/auth/client/tx.go index 3c35aebe61c0..d9212bed5fbe 100644 --- a/x/auth/client/tx.go +++ b/x/auth/client/tx.go @@ -289,7 +289,7 @@ func adjustGasEstimate(estimate uint64, adjustment float64) uint64 { func parseQueryResponse(cdc *codec.Codec, rawRes []byte) (uint64, error) { var gasUsed uint64 - if err := cdc.UnmarshalBinaryLengthPrefixed(rawRes, &gasUsed); err != nil { + if err := cdc.UnmarshalBinaryBare(rawRes, &gasUsed); err != nil { return 0, err } diff --git a/x/auth/client/tx_test.go b/x/auth/client/tx_test.go index 1fb4ca3d22d6..643f253a21f8 100644 --- a/x/auth/client/tx_test.go +++ b/x/auth/client/tx_test.go @@ -23,7 +23,7 @@ var ( func TestParseQueryResponse(t *testing.T) { cdc := makeCodec() - sdkResBytes := cdc.MustMarshalBinaryLengthPrefixed(uint64(10)) + sdkResBytes := cdc.MustMarshalBinaryBare(uint64(10)) gas, err := parseQueryResponse(cdc, sdkResBytes) assert.Equal(t, gas, uint64(10)) assert.Nil(t, err) @@ -39,7 +39,7 @@ func TestCalculateGas(t *testing.T) { if wantErr { return nil, 0, errors.New("") } - return cdc.MustMarshalBinaryLengthPrefixed(gasUsed), 0, nil + return cdc.MustMarshalBinaryBare(gasUsed), 0, nil } } diff --git a/x/auth/keeper/keeper.go b/x/auth/keeper/keeper.go index df5228fa7f03..e07e9dfba902 100644 --- a/x/auth/keeper/keeper.go +++ b/x/auth/keeper/keeper.go @@ -77,7 +77,7 @@ func (ak AccountKeeper) GetNextAccountNumber(ctx sdk.Context) uint64 { } else { val := gogotypes.UInt64Value{} - err := ak.cdc.UnmarshalBinaryLengthPrefixed(bz, &val) + err := ak.cdc.UnmarshalBinaryBare(bz, &val) if err != nil { panic(err) } @@ -85,7 +85,7 @@ func (ak AccountKeeper) GetNextAccountNumber(ctx sdk.Context) uint64 { accNumber = val.GetValue() } - bz = ak.cdc.MustMarshalBinaryLengthPrefixed(&gogotypes.UInt64Value{Value: accNumber + 1}) + bz = ak.cdc.MustMarshalBinaryBare(&gogotypes.UInt64Value{Value: accNumber + 1}) store.Set(types.GlobalAccountNumberKey, bz) return accNumber diff --git a/x/auth/simulation/decoder.go b/x/auth/simulation/decoder.go index d157aab94349..7d5d0d7b52cc 100644 --- a/x/auth/simulation/decoder.go +++ b/x/auth/simulation/decoder.go @@ -22,8 +22,8 @@ func DecodeStore(cdc *codec.Codec, kvA, kvB tmkv.Pair) string { case bytes.Equal(kvA.Key, types.GlobalAccountNumberKey): var globalAccNumberA, globalAccNumberB uint64 - cdc.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &globalAccNumberA) - cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &globalAccNumberB) + cdc.MustUnmarshalBinaryBare(kvA.Value, &globalAccNumberA) + cdc.MustUnmarshalBinaryBare(kvB.Value, &globalAccNumberB) return fmt.Sprintf("GlobalAccNumberA: %d\nGlobalAccNumberB: %d", globalAccNumberA, globalAccNumberB) default: diff --git a/x/auth/simulation/decoder_test.go b/x/auth/simulation/decoder_test.go index 2ef143f15ef9..729ca9d79320 100644 --- a/x/auth/simulation/decoder_test.go +++ b/x/auth/simulation/decoder_test.go @@ -34,7 +34,7 @@ func TestDecodeStore(t *testing.T) { kvPairs := tmkv.Pairs{ tmkv.Pair{Key: types.AddressStoreKey(delAddr1), Value: cdc.MustMarshalBinaryBare(acc)}, - tmkv.Pair{Key: types.GlobalAccountNumberKey, Value: cdc.MustMarshalBinaryLengthPrefixed(globalAccNumber)}, + tmkv.Pair{Key: types.GlobalAccountNumberKey, Value: cdc.MustMarshalBinaryBare(globalAccNumber)}, tmkv.Pair{Key: []byte{0x99}, Value: []byte{0x99}}, } tests := []struct { diff --git a/x/auth/types/stdtx.go b/x/auth/types/stdtx.go index a9a6cd3e9daf..6c5d38c1bf37 100644 --- a/x/auth/types/stdtx.go +++ b/x/auth/types/stdtx.go @@ -254,7 +254,7 @@ func DefaultTxDecoder(cdc *codec.Codec) sdk.TxDecoder { // StdTx.Msg is an interface. The concrete types // are registered by MakeTxCodec - err := cdc.UnmarshalBinaryLengthPrefixed(txBytes, &tx) + err := cdc.UnmarshalBinaryBare(txBytes, &tx) if err != nil { return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error()) } @@ -266,7 +266,7 @@ func DefaultTxDecoder(cdc *codec.Codec) sdk.TxDecoder { // DefaultTxEncoder logic for standard transaction encoding func DefaultTxEncoder(cdc *codec.Codec) sdk.TxEncoder { return func(tx sdk.Tx) ([]byte, error) { - return cdc.MarshalBinaryLengthPrefixed(tx) + return cdc.MarshalBinaryBare(tx) } } diff --git a/x/auth/types/stdtx_test.go b/x/auth/types/stdtx_test.go index a8ce9d721076..676a6bef7142 100644 --- a/x/auth/types/stdtx_test.go +++ b/x/auth/types/stdtx_test.go @@ -131,7 +131,7 @@ func TestDefaultTxEncoder(t *testing.T) { tx := NewStdTx(msgs, fee, sigs, "") - cdcBytes, err := cdc.MarshalBinaryLengthPrefixed(tx) + cdcBytes, err := cdc.MarshalBinaryBare(tx) require.NoError(t, err) encoderBytes, err := encoder(tx) diff --git a/x/distribution/keeper/store.go b/x/distribution/keeper/store.go index ffdd807163ed..302e2ee81e92 100644 --- a/x/distribution/keeper/store.go +++ b/x/distribution/keeper/store.go @@ -50,14 +50,14 @@ func (k Keeper) GetFeePool(ctx sdk.Context) (feePool types.FeePool) { if b == nil { panic("Stored fee pool should not have been nil") } - k.cdc.MustUnmarshalBinaryLengthPrefixed(b, &feePool) + k.cdc.MustUnmarshalBinaryBare(b, &feePool) return } // set the global fee pool distribution info func (k Keeper) SetFeePool(ctx sdk.Context, feePool types.FeePool) { store := ctx.KVStore(k.storeKey) - b := k.cdc.MustMarshalBinaryLengthPrefixed(&feePool) + b := k.cdc.MustMarshalBinaryBare(&feePool) store.Set(types.FeePoolKey, b) } @@ -71,14 +71,14 @@ func (k Keeper) GetPreviousProposerConsAddr(ctx sdk.Context) sdk.ConsAddress { } addrValue := gogotypes.BytesValue{} - k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &addrValue) - return sdk.ConsAddress(addrValue.GetValue()) + k.cdc.MustUnmarshalBinaryBare(bz, &addrValue) + return addrValue.GetValue() } // set the proposer public key for this block func (k Keeper) SetPreviousProposerConsAddr(ctx sdk.Context, consAddr sdk.ConsAddress) { store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinaryLengthPrefixed(&gogotypes.BytesValue{Value: consAddr}) + bz := k.cdc.MustMarshalBinaryBare(&gogotypes.BytesValue{Value: consAddr}) store.Set(types.ProposerKey, bz) } @@ -86,14 +86,14 @@ func (k Keeper) SetPreviousProposerConsAddr(ctx sdk.Context, consAddr sdk.ConsAd func (k Keeper) GetDelegatorStartingInfo(ctx sdk.Context, val sdk.ValAddress, del sdk.AccAddress) (period types.DelegatorStartingInfo) { store := ctx.KVStore(k.storeKey) b := store.Get(types.GetDelegatorStartingInfoKey(val, del)) - k.cdc.MustUnmarshalBinaryLengthPrefixed(b, &period) + k.cdc.MustUnmarshalBinaryBare(b, &period) return } // set the starting info associated with a delegator func (k Keeper) SetDelegatorStartingInfo(ctx sdk.Context, val sdk.ValAddress, del sdk.AccAddress, period types.DelegatorStartingInfo) { store := ctx.KVStore(k.storeKey) - b := k.cdc.MustMarshalBinaryLengthPrefixed(&period) + b := k.cdc.MustMarshalBinaryBare(&period) store.Set(types.GetDelegatorStartingInfoKey(val, del), b) } @@ -116,7 +116,7 @@ func (k Keeper) IterateDelegatorStartingInfos(ctx sdk.Context, handler func(val defer iter.Close() for ; iter.Valid(); iter.Next() { var info types.DelegatorStartingInfo - k.cdc.MustUnmarshalBinaryLengthPrefixed(iter.Value(), &info) + k.cdc.MustUnmarshalBinaryBare(iter.Value(), &info) val, del := types.GetDelegatorStartingInfoAddresses(iter.Key()) if handler(val, del, info) { break @@ -128,14 +128,14 @@ func (k Keeper) IterateDelegatorStartingInfos(ctx sdk.Context, handler func(val func (k Keeper) GetValidatorHistoricalRewards(ctx sdk.Context, val sdk.ValAddress, period uint64) (rewards types.ValidatorHistoricalRewards) { store := ctx.KVStore(k.storeKey) b := store.Get(types.GetValidatorHistoricalRewardsKey(val, period)) - k.cdc.MustUnmarshalBinaryLengthPrefixed(b, &rewards) + k.cdc.MustUnmarshalBinaryBare(b, &rewards) return } // set historical rewards for a particular period func (k Keeper) SetValidatorHistoricalRewards(ctx sdk.Context, val sdk.ValAddress, period uint64, rewards types.ValidatorHistoricalRewards) { store := ctx.KVStore(k.storeKey) - b := k.cdc.MustMarshalBinaryLengthPrefixed(&rewards) + b := k.cdc.MustMarshalBinaryBare(&rewards) store.Set(types.GetValidatorHistoricalRewardsKey(val, period), b) } @@ -146,7 +146,7 @@ func (k Keeper) IterateValidatorHistoricalRewards(ctx sdk.Context, handler func( defer iter.Close() for ; iter.Valid(); iter.Next() { var rewards types.ValidatorHistoricalRewards - k.cdc.MustUnmarshalBinaryLengthPrefixed(iter.Value(), &rewards) + k.cdc.MustUnmarshalBinaryBare(iter.Value(), &rewards) addr, period := types.GetValidatorHistoricalRewardsAddressPeriod(iter.Key()) if handler(addr, period, rewards) { break @@ -187,7 +187,7 @@ func (k Keeper) GetValidatorHistoricalReferenceCount(ctx sdk.Context) (count uin defer iter.Close() for ; iter.Valid(); iter.Next() { var rewards types.ValidatorHistoricalRewards - k.cdc.MustUnmarshalBinaryLengthPrefixed(iter.Value(), &rewards) + k.cdc.MustUnmarshalBinaryBare(iter.Value(), &rewards) count += uint64(rewards.ReferenceCount) } return @@ -197,14 +197,14 @@ func (k Keeper) GetValidatorHistoricalReferenceCount(ctx sdk.Context) (count uin func (k Keeper) GetValidatorCurrentRewards(ctx sdk.Context, val sdk.ValAddress) (rewards types.ValidatorCurrentRewards) { store := ctx.KVStore(k.storeKey) b := store.Get(types.GetValidatorCurrentRewardsKey(val)) - k.cdc.MustUnmarshalBinaryLengthPrefixed(b, &rewards) + k.cdc.MustUnmarshalBinaryBare(b, &rewards) return } // set current rewards for a validator func (k Keeper) SetValidatorCurrentRewards(ctx sdk.Context, val sdk.ValAddress, rewards types.ValidatorCurrentRewards) { store := ctx.KVStore(k.storeKey) - b := k.cdc.MustMarshalBinaryLengthPrefixed(&rewards) + b := k.cdc.MustMarshalBinaryBare(&rewards) store.Set(types.GetValidatorCurrentRewardsKey(val), b) } @@ -221,7 +221,7 @@ func (k Keeper) IterateValidatorCurrentRewards(ctx sdk.Context, handler func(val defer iter.Close() for ; iter.Valid(); iter.Next() { var rewards types.ValidatorCurrentRewards - k.cdc.MustUnmarshalBinaryLengthPrefixed(iter.Value(), &rewards) + k.cdc.MustUnmarshalBinaryBare(iter.Value(), &rewards) addr := types.GetValidatorCurrentRewardsAddress(iter.Key()) if handler(addr, rewards) { break @@ -236,7 +236,7 @@ func (k Keeper) GetValidatorAccumulatedCommission(ctx sdk.Context, val sdk.ValAd if b == nil { return types.ValidatorAccumulatedCommission{} } - k.cdc.MustUnmarshalBinaryLengthPrefixed(b, &commission) + k.cdc.MustUnmarshalBinaryBare(b, &commission) return } @@ -246,9 +246,9 @@ func (k Keeper) SetValidatorAccumulatedCommission(ctx sdk.Context, val sdk.ValAd store := ctx.KVStore(k.storeKey) if commission.Commission.IsZero() { - bz = k.cdc.MustMarshalBinaryLengthPrefixed(&types.ValidatorAccumulatedCommission{}) + bz = k.cdc.MustMarshalBinaryBare(&types.ValidatorAccumulatedCommission{}) } else { - bz = k.cdc.MustMarshalBinaryLengthPrefixed(&commission) + bz = k.cdc.MustMarshalBinaryBare(&commission) } store.Set(types.GetValidatorAccumulatedCommissionKey(val), bz) @@ -267,7 +267,7 @@ func (k Keeper) IterateValidatorAccumulatedCommissions(ctx sdk.Context, handler defer iter.Close() for ; iter.Valid(); iter.Next() { var commission types.ValidatorAccumulatedCommission - k.cdc.MustUnmarshalBinaryLengthPrefixed(iter.Value(), &commission) + k.cdc.MustUnmarshalBinaryBare(iter.Value(), &commission) addr := types.GetValidatorAccumulatedCommissionAddress(iter.Key()) if handler(addr, commission) { break @@ -279,14 +279,14 @@ func (k Keeper) IterateValidatorAccumulatedCommissions(ctx sdk.Context, handler func (k Keeper) GetValidatorOutstandingRewards(ctx sdk.Context, val sdk.ValAddress) (rewards types.ValidatorOutstandingRewards) { store := ctx.KVStore(k.storeKey) bz := store.Get(types.GetValidatorOutstandingRewardsKey(val)) - k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &rewards) + k.cdc.MustUnmarshalBinaryBare(bz, &rewards) return } // set validator outstanding rewards func (k Keeper) SetValidatorOutstandingRewards(ctx sdk.Context, val sdk.ValAddress, rewards types.ValidatorOutstandingRewards) { store := ctx.KVStore(k.storeKey) - b := k.cdc.MustMarshalBinaryLengthPrefixed(&rewards) + b := k.cdc.MustMarshalBinaryBare(&rewards) store.Set(types.GetValidatorOutstandingRewardsKey(val), b) } @@ -303,7 +303,7 @@ func (k Keeper) IterateValidatorOutstandingRewards(ctx sdk.Context, handler func defer iter.Close() for ; iter.Valid(); iter.Next() { rewards := types.ValidatorOutstandingRewards{} - k.cdc.MustUnmarshalBinaryLengthPrefixed(iter.Value(), &rewards) + k.cdc.MustUnmarshalBinaryBare(iter.Value(), &rewards) addr := types.GetValidatorOutstandingRewardsAddress(iter.Key()) if handler(addr, rewards) { break @@ -318,14 +318,14 @@ func (k Keeper) GetValidatorSlashEvent(ctx sdk.Context, val sdk.ValAddress, heig if b == nil { return types.ValidatorSlashEvent{}, false } - k.cdc.MustUnmarshalBinaryLengthPrefixed(b, &event) + k.cdc.MustUnmarshalBinaryBare(b, &event) return event, true } // set slash event for height func (k Keeper) SetValidatorSlashEvent(ctx sdk.Context, val sdk.ValAddress, height, period uint64, event types.ValidatorSlashEvent) { store := ctx.KVStore(k.storeKey) - b := k.cdc.MustMarshalBinaryLengthPrefixed(&event) + b := k.cdc.MustMarshalBinaryBare(&event) store.Set(types.GetValidatorSlashEventKey(val, height, period), b) } @@ -340,7 +340,7 @@ func (k Keeper) IterateValidatorSlashEventsBetween(ctx sdk.Context, val sdk.ValA defer iter.Close() for ; iter.Valid(); iter.Next() { var event types.ValidatorSlashEvent - k.cdc.MustUnmarshalBinaryLengthPrefixed(iter.Value(), &event) + k.cdc.MustUnmarshalBinaryBare(iter.Value(), &event) _, height := types.GetValidatorSlashEventAddressHeight(iter.Key()) if handler(height, event) { break @@ -355,7 +355,7 @@ func (k Keeper) IterateValidatorSlashEvents(ctx sdk.Context, handler func(val sd defer iter.Close() for ; iter.Valid(); iter.Next() { var event types.ValidatorSlashEvent - k.cdc.MustUnmarshalBinaryLengthPrefixed(iter.Value(), &event) + k.cdc.MustUnmarshalBinaryBare(iter.Value(), &event) val, height := types.GetValidatorSlashEventAddressHeight(iter.Key()) if handler(val, height, event) { break diff --git a/x/distribution/simulation/decoder.go b/x/distribution/simulation/decoder.go index 79298073a94d..ce991efca431 100644 --- a/x/distribution/simulation/decoder.go +++ b/x/distribution/simulation/decoder.go @@ -16,8 +16,8 @@ func DecodeStore(cdc *codec.Codec, kvA, kvB tmkv.Pair) string { switch { case bytes.Equal(kvA.Key[:1], types.FeePoolKey): var feePoolA, feePoolB types.FeePool - cdc.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &feePoolA) - cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &feePoolB) + cdc.MustUnmarshalBinaryBare(kvA.Value, &feePoolA) + cdc.MustUnmarshalBinaryBare(kvB.Value, &feePoolB) return fmt.Sprintf("%v\n%v", feePoolA, feePoolB) case bytes.Equal(kvA.Key[:1], types.ProposerKey): @@ -25,8 +25,8 @@ func DecodeStore(cdc *codec.Codec, kvA, kvB tmkv.Pair) string { case bytes.Equal(kvA.Key[:1], types.ValidatorOutstandingRewardsPrefix): var rewardsA, rewardsB types.ValidatorOutstandingRewards - cdc.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &rewardsA) - cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &rewardsB) + cdc.MustUnmarshalBinaryBare(kvA.Value, &rewardsA) + cdc.MustUnmarshalBinaryBare(kvB.Value, &rewardsB) return fmt.Sprintf("%v\n%v", rewardsA, rewardsB) case bytes.Equal(kvA.Key[:1], types.DelegatorWithdrawAddrPrefix): @@ -34,32 +34,32 @@ func DecodeStore(cdc *codec.Codec, kvA, kvB tmkv.Pair) string { case bytes.Equal(kvA.Key[:1], types.DelegatorStartingInfoPrefix): var infoA, infoB types.DelegatorStartingInfo - cdc.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &infoA) - cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &infoB) + cdc.MustUnmarshalBinaryBare(kvA.Value, &infoA) + cdc.MustUnmarshalBinaryBare(kvB.Value, &infoB) return fmt.Sprintf("%v\n%v", infoA, infoB) case bytes.Equal(kvA.Key[:1], types.ValidatorHistoricalRewardsPrefix): var rewardsA, rewardsB types.ValidatorHistoricalRewards - cdc.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &rewardsA) - cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &rewardsB) + cdc.MustUnmarshalBinaryBare(kvA.Value, &rewardsA) + cdc.MustUnmarshalBinaryBare(kvB.Value, &rewardsB) return fmt.Sprintf("%v\n%v", rewardsA, rewardsB) case bytes.Equal(kvA.Key[:1], types.ValidatorCurrentRewardsPrefix): var rewardsA, rewardsB types.ValidatorCurrentRewards - cdc.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &rewardsA) - cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &rewardsB) + cdc.MustUnmarshalBinaryBare(kvA.Value, &rewardsA) + cdc.MustUnmarshalBinaryBare(kvB.Value, &rewardsB) return fmt.Sprintf("%v\n%v", rewardsA, rewardsB) case bytes.Equal(kvA.Key[:1], types.ValidatorAccumulatedCommissionPrefix): var commissionA, commissionB types.ValidatorAccumulatedCommission - cdc.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &commissionA) - cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &commissionB) + cdc.MustUnmarshalBinaryBare(kvA.Value, &commissionA) + cdc.MustUnmarshalBinaryBare(kvB.Value, &commissionB) return fmt.Sprintf("%v\n%v", commissionA, commissionB) case bytes.Equal(kvA.Key[:1], types.ValidatorSlashEventPrefix): var eventA, eventB types.ValidatorSlashEvent - cdc.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &eventA) - cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &eventB) + cdc.MustUnmarshalBinaryBare(kvA.Value, &eventA) + cdc.MustUnmarshalBinaryBare(kvB.Value, &eventB) return fmt.Sprintf("%v\n%v", eventA, eventB) default: diff --git a/x/distribution/simulation/decoder_test.go b/x/distribution/simulation/decoder_test.go index 059c2d625afd..8eb1c00d44f1 100644 --- a/x/distribution/simulation/decoder_test.go +++ b/x/distribution/simulation/decoder_test.go @@ -43,15 +43,15 @@ func TestDecodeDistributionStore(t *testing.T) { slashEvent := types.NewValidatorSlashEvent(10, sdk.OneDec()) kvPairs := tmkv.Pairs{ - tmkv.Pair{Key: types.FeePoolKey, Value: cdc.MustMarshalBinaryLengthPrefixed(feePool)}, + tmkv.Pair{Key: types.FeePoolKey, Value: cdc.MustMarshalBinaryBare(feePool)}, tmkv.Pair{Key: types.ProposerKey, Value: consAddr1.Bytes()}, - tmkv.Pair{Key: types.GetValidatorOutstandingRewardsKey(valAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(outstanding)}, + tmkv.Pair{Key: types.GetValidatorOutstandingRewardsKey(valAddr1), Value: cdc.MustMarshalBinaryBare(outstanding)}, tmkv.Pair{Key: types.GetDelegatorWithdrawAddrKey(delAddr1), Value: delAddr1.Bytes()}, - tmkv.Pair{Key: types.GetDelegatorStartingInfoKey(valAddr1, delAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(info)}, - tmkv.Pair{Key: types.GetValidatorHistoricalRewardsKey(valAddr1, 100), Value: cdc.MustMarshalBinaryLengthPrefixed(historicalRewards)}, - tmkv.Pair{Key: types.GetValidatorCurrentRewardsKey(valAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(currentRewards)}, - tmkv.Pair{Key: types.GetValidatorAccumulatedCommissionKey(valAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(commission)}, - tmkv.Pair{Key: types.GetValidatorSlashEventKeyPrefix(valAddr1, 13), Value: cdc.MustMarshalBinaryLengthPrefixed(slashEvent)}, + tmkv.Pair{Key: types.GetDelegatorStartingInfoKey(valAddr1, delAddr1), Value: cdc.MustMarshalBinaryBare(info)}, + tmkv.Pair{Key: types.GetValidatorHistoricalRewardsKey(valAddr1, 100), Value: cdc.MustMarshalBinaryBare(historicalRewards)}, + tmkv.Pair{Key: types.GetValidatorCurrentRewardsKey(valAddr1), Value: cdc.MustMarshalBinaryBare(currentRewards)}, + tmkv.Pair{Key: types.GetValidatorAccumulatedCommissionKey(valAddr1), Value: cdc.MustMarshalBinaryBare(commission)}, + tmkv.Pair{Key: types.GetValidatorSlashEventKeyPrefix(valAddr1, 13), Value: cdc.MustMarshalBinaryBare(slashEvent)}, tmkv.Pair{Key: []byte{0x99}, Value: []byte{0x99}}, } diff --git a/x/genutil/gentx.go b/x/genutil/gentx.go index 577fedcef6a9..064a67387b8b 100644 --- a/x/genutil/gentx.go +++ b/x/genutil/gentx.go @@ -102,7 +102,7 @@ func DeliverGenTxs( var tx authtypes.StdTx cdc.MustUnmarshalJSON(genTx, &tx) - bz := cdc.MustMarshalBinaryLengthPrefixed(tx) + bz := cdc.MustMarshalBinaryBare(tx) res := deliverTx(abci.RequestDeliverTx{Tx: bz}) if !res.IsOK() { diff --git a/x/gov/client/utils/query_test.go b/x/gov/client/utils/query_test.go index eb4d71e0b061..adc83eb48a80 100644 --- a/x/gov/client/utils/query_test.go +++ b/x/gov/client/utils/query_test.go @@ -137,9 +137,9 @@ func TestGetPaginatedVotes(t *testing.T) { cdc = newTestCodec() ) for i := range tc.txs { - tx, err := cdc.MarshalBinaryLengthPrefixed(&tc.txs[i]) + tx, err := cdc.MarshalBinaryBare(&tc.txs[i]) require.NoError(t, err) - marshalled[i] = tmtypes.Tx(tx) + marshalled[i] = tx } client := TxSearchMock{txs: marshalled} ctx := context.CLIContext{}.WithCodec(cdc).WithTrustNode(true).WithClient(client) diff --git a/x/gov/keeper/deposit.go b/x/gov/keeper/deposit.go index d1a55140d590..28783f59cb63 100644 --- a/x/gov/keeper/deposit.go +++ b/x/gov/keeper/deposit.go @@ -16,14 +16,14 @@ func (keeper Keeper) GetDeposit(ctx sdk.Context, proposalID uint64, depositorAdd return deposit, false } - keeper.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &deposit) + keeper.cdc.MustUnmarshalBinaryBare(bz, &deposit) return deposit, true } // SetDeposit sets a Deposit to the gov store func (keeper Keeper) SetDeposit(ctx sdk.Context, deposit types.Deposit) { store := ctx.KVStore(keeper.storeKey) - bz := keeper.cdc.MustMarshalBinaryLengthPrefixed(&deposit) + bz := keeper.cdc.MustMarshalBinaryBare(&deposit) store.Set(types.DepositKey(deposit.ProposalID, deposit.Depositor), bz) } @@ -68,7 +68,7 @@ func (keeper Keeper) IterateAllDeposits(ctx sdk.Context, cb func(deposit types.D defer iterator.Close() for ; iterator.Valid(); iterator.Next() { var deposit types.Deposit - keeper.cdc.MustUnmarshalBinaryLengthPrefixed(iterator.Value(), &deposit) + keeper.cdc.MustUnmarshalBinaryBare(iterator.Value(), &deposit) if cb(deposit) { break @@ -84,7 +84,7 @@ func (keeper Keeper) IterateDeposits(ctx sdk.Context, proposalID uint64, cb func defer iterator.Close() for ; iterator.Valid(); iterator.Next() { var deposit types.Deposit - keeper.cdc.MustUnmarshalBinaryLengthPrefixed(iterator.Value(), &deposit) + keeper.cdc.MustUnmarshalBinaryBare(iterator.Value(), &deposit) if cb(deposit) { break diff --git a/x/gov/keeper/vote.go b/x/gov/keeper/vote.go index 819130e6473b..2abd6ca713a9 100644 --- a/x/gov/keeper/vote.go +++ b/x/gov/keeper/vote.go @@ -62,14 +62,14 @@ func (keeper Keeper) GetVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.A return vote, false } - keeper.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &vote) + keeper.cdc.MustUnmarshalBinaryBare(bz, &vote) return vote, true } // SetVote sets a Vote to the gov store func (keeper Keeper) SetVote(ctx sdk.Context, vote types.Vote) { store := ctx.KVStore(keeper.storeKey) - bz := keeper.cdc.MustMarshalBinaryLengthPrefixed(&vote) + bz := keeper.cdc.MustMarshalBinaryBare(&vote) store.Set(types.VoteKey(vote.ProposalID, vote.Voter), bz) } @@ -81,7 +81,7 @@ func (keeper Keeper) IterateAllVotes(ctx sdk.Context, cb func(vote types.Vote) ( defer iterator.Close() for ; iterator.Valid(); iterator.Next() { var vote types.Vote - keeper.cdc.MustUnmarshalBinaryLengthPrefixed(iterator.Value(), &vote) + keeper.cdc.MustUnmarshalBinaryBare(iterator.Value(), &vote) if cb(vote) { break @@ -97,7 +97,7 @@ func (keeper Keeper) IterateVotes(ctx sdk.Context, proposalID uint64, cb func(vo defer iterator.Close() for ; iterator.Valid(); iterator.Next() { var vote types.Vote - keeper.cdc.MustUnmarshalBinaryLengthPrefixed(iterator.Value(), &vote) + keeper.cdc.MustUnmarshalBinaryBare(iterator.Value(), &vote) if cb(vote) { break diff --git a/x/gov/simulation/decoder.go b/x/gov/simulation/decoder.go index 6e4c3169ac1f..c415117aa485 100644 --- a/x/gov/simulation/decoder.go +++ b/x/gov/simulation/decoder.go @@ -16,8 +16,8 @@ func DecodeStore(cdc *codec.Codec, kvA, kvB tmkv.Pair) string { switch { case bytes.Equal(kvA.Key[:1], types.ProposalsKeyPrefix): var proposalA, proposalB types.Proposal - cdc.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &proposalA) - cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &proposalB) + cdc.MustUnmarshalBinaryBare(kvA.Value, &proposalA) + cdc.MustUnmarshalBinaryBare(kvB.Value, &proposalB) return fmt.Sprintf("%v\n%v", proposalA, proposalB) case bytes.Equal(kvA.Key[:1], types.ActiveProposalQueuePrefix), @@ -29,14 +29,14 @@ func DecodeStore(cdc *codec.Codec, kvA, kvB tmkv.Pair) string { case bytes.Equal(kvA.Key[:1], types.DepositsKeyPrefix): var depositA, depositB types.Deposit - cdc.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &depositA) - cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &depositB) + cdc.MustUnmarshalBinaryBare(kvA.Value, &depositA) + cdc.MustUnmarshalBinaryBare(kvB.Value, &depositB) return fmt.Sprintf("%v\n%v", depositA, depositB) case bytes.Equal(kvA.Key[:1], types.VotesKeyPrefix): var voteA, voteB types.Vote - cdc.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &voteA) - cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &voteB) + cdc.MustUnmarshalBinaryBare(kvA.Value, &voteA) + cdc.MustUnmarshalBinaryBare(kvB.Value, &voteB) return fmt.Sprintf("%v\n%v", voteA, voteB) default: diff --git a/x/gov/simulation/decoder_test.go b/x/gov/simulation/decoder_test.go index 025dbeedc71c..5ae3cab53a60 100644 --- a/x/gov/simulation/decoder_test.go +++ b/x/gov/simulation/decoder_test.go @@ -42,10 +42,10 @@ func TestDecodeStore(t *testing.T) { vote := types.NewVote(1, delAddr1, types.OptionYes) kvPairs := tmkv.Pairs{ - tmkv.Pair{Key: types.ProposalKey(1), Value: cdc.MustMarshalBinaryLengthPrefixed(proposal)}, + tmkv.Pair{Key: types.ProposalKey(1), Value: cdc.MustMarshalBinaryBare(proposal)}, tmkv.Pair{Key: types.InactiveProposalQueueKey(1, endTime), Value: proposalIDBz}, - tmkv.Pair{Key: types.DepositKey(1, delAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(deposit)}, - tmkv.Pair{Key: types.VoteKey(1, delAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(vote)}, + tmkv.Pair{Key: types.DepositKey(1, delAddr1), Value: cdc.MustMarshalBinaryBare(deposit)}, + tmkv.Pair{Key: types.VoteKey(1, delAddr1), Value: cdc.MustMarshalBinaryBare(vote)}, tmkv.Pair{Key: []byte{0x99}, Value: []byte{0x99}}, } diff --git a/x/mint/keeper/keeper.go b/x/mint/keeper/keeper.go index 9c708f6b5bff..73652e41c88b 100644 --- a/x/mint/keeper/keeper.go +++ b/x/mint/keeper/keeper.go @@ -57,14 +57,14 @@ func (k Keeper) GetMinter(ctx sdk.Context) (minter types.Minter) { panic("stored minter should not have been nil") } - k.cdc.MustUnmarshalBinaryLengthPrefixed(b, &minter) + k.cdc.MustUnmarshalBinaryBare(b, &minter) return } // set the minter func (k Keeper) SetMinter(ctx sdk.Context, minter types.Minter) { store := ctx.KVStore(k.storeKey) - b := k.cdc.MustMarshalBinaryLengthPrefixed(&minter) + b := k.cdc.MustMarshalBinaryBare(&minter) store.Set(types.MinterKey, b) } diff --git a/x/mint/simulation/decoder.go b/x/mint/simulation/decoder.go index 5cdac40e88a7..8ff2baeb0e19 100644 --- a/x/mint/simulation/decoder.go +++ b/x/mint/simulation/decoder.go @@ -15,8 +15,8 @@ func DecodeStore(cdc *codec.Codec, kvA, kvB tmkv.Pair) string { switch { case bytes.Equal(kvA.Key, types.MinterKey): var minterA, minterB types.Minter - cdc.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &minterA) - cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &minterB) + cdc.MustUnmarshalBinaryBare(kvA.Value, &minterA) + cdc.MustUnmarshalBinaryBare(kvB.Value, &minterB) return fmt.Sprintf("%v\n%v", minterA, minterB) default: panic(fmt.Sprintf("invalid mint key %X", kvA.Key)) diff --git a/x/mint/simulation/decoder_test.go b/x/mint/simulation/decoder_test.go index 47ed9bebbed5..48dfa62bb384 100644 --- a/x/mint/simulation/decoder_test.go +++ b/x/mint/simulation/decoder_test.go @@ -24,7 +24,7 @@ func TestDecodeStore(t *testing.T) { minter := types.NewMinter(sdk.OneDec(), sdk.NewDec(15)) kvPairs := tmkv.Pairs{ - tmkv.Pair{Key: types.MinterKey, Value: cdc.MustMarshalBinaryLengthPrefixed(minter)}, + tmkv.Pair{Key: types.MinterKey, Value: cdc.MustMarshalBinaryBare(minter)}, tmkv.Pair{Key: []byte{0x99}, Value: []byte{0x99}}, } tests := []struct { diff --git a/x/slashing/keeper/keeper.go b/x/slashing/keeper/keeper.go index 43f21a516edb..f34756afc853 100644 --- a/x/slashing/keeper/keeper.go +++ b/x/slashing/keeper/keeper.go @@ -53,7 +53,7 @@ func (k Keeper) GetPubkey(ctx sdk.Context, address crypto.Address) (crypto.PubKe store := ctx.KVStore(k.storeKey) var pubkey gogotypes.StringValue - err := k.cdc.UnmarshalBinaryLengthPrefixed(store.Get(types.GetAddrPubkeyRelationKey(address)), &pubkey) + err := k.cdc.UnmarshalBinaryBare(store.Get(types.GetAddrPubkeyRelationKey(address)), &pubkey) if err != nil { return nil, fmt.Errorf("address %s not found", sdk.ConsAddress(address)) } @@ -97,7 +97,7 @@ func (k Keeper) Jail(ctx sdk.Context, consAddr sdk.ConsAddress) { func (k Keeper) setAddrPubkeyRelation(ctx sdk.Context, addr crypto.Address, pubkey string) { store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinaryLengthPrefixed(&gogotypes.StringValue{Value: pubkey}) + bz := k.cdc.MustMarshalBinaryBare(&gogotypes.StringValue{Value: pubkey}) store.Set(types.GetAddrPubkeyRelationKey(addr), bz) } diff --git a/x/slashing/keeper/signing_info.go b/x/slashing/keeper/signing_info.go index 0e1a82c62fa2..860b3e1315cd 100644 --- a/x/slashing/keeper/signing_info.go +++ b/x/slashing/keeper/signing_info.go @@ -18,7 +18,7 @@ func (k Keeper) GetValidatorSigningInfo(ctx sdk.Context, address sdk.ConsAddress found = false return } - k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &info) + k.cdc.MustUnmarshalBinaryBare(bz, &info) found = true return } @@ -33,7 +33,7 @@ func (k Keeper) HasValidatorSigningInfo(ctx sdk.Context, consAddr sdk.ConsAddres // SetValidatorSigningInfo sets the validator signing info to a consensus address key func (k Keeper) SetValidatorSigningInfo(ctx sdk.Context, address sdk.ConsAddress, info types.ValidatorSigningInfo) { store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinaryLengthPrefixed(&info) + bz := k.cdc.MustMarshalBinaryBare(&info) store.Set(types.GetValidatorSigningInfoKey(address), bz) } @@ -47,7 +47,7 @@ func (k Keeper) IterateValidatorSigningInfos(ctx sdk.Context, for ; iter.Valid(); iter.Next() { address := types.GetValidatorSigningInfoAddress(iter.Key()) var info types.ValidatorSigningInfo - k.cdc.MustUnmarshalBinaryLengthPrefixed(iter.Value(), &info) + k.cdc.MustUnmarshalBinaryBare(iter.Value(), &info) if handler(address, info) { break } @@ -63,7 +63,7 @@ func (k Keeper) GetValidatorMissedBlockBitArray(ctx sdk.Context, address sdk.Con // lazy: treat empty key as not missed return false } - k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &missed) + k.cdc.MustUnmarshalBinaryBare(bz, &missed) return missed.Value } @@ -83,7 +83,7 @@ func (k Keeper) IterateValidatorMissedBlockBitArray(ctx sdk.Context, continue } - k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &missed) + k.cdc.MustUnmarshalBinaryBare(bz, &missed) if handler(index, missed.Value) { break } @@ -132,7 +132,7 @@ func (k Keeper) IsTombstoned(ctx sdk.Context, consAddr sdk.ConsAddress) bool { // missed a block in the current window func (k Keeper) SetValidatorMissedBlockBitArray(ctx sdk.Context, address sdk.ConsAddress, index int64, missed bool) { store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinaryLengthPrefixed(&gogotypes.BoolValue{Value: missed}) + bz := k.cdc.MustMarshalBinaryBare(&gogotypes.BoolValue{Value: missed}) store.Set(types.GetValidatorMissedBlockBitArrayKey(address, index), bz) } diff --git a/x/slashing/simulation/decoder.go b/x/slashing/simulation/decoder.go index 48a12705a780..9555737d889c 100644 --- a/x/slashing/simulation/decoder.go +++ b/x/slashing/simulation/decoder.go @@ -18,20 +18,20 @@ func DecodeStore(cdc *codec.Codec, kvA, kvB tmkv.Pair) string { switch { case bytes.Equal(kvA.Key[:1], types.ValidatorSigningInfoKey): var infoA, infoB types.ValidatorSigningInfo - cdc.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &infoA) - cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &infoB) + cdc.MustUnmarshalBinaryBare(kvA.Value, &infoA) + cdc.MustUnmarshalBinaryBare(kvB.Value, &infoB) return fmt.Sprintf("%v\n%v", infoA, infoB) case bytes.Equal(kvA.Key[:1], types.ValidatorMissedBlockBitArrayKey): var missedA, missedB gogotypes.BoolValue - cdc.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &missedA) - cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &missedB) + cdc.MustUnmarshalBinaryBare(kvA.Value, &missedA) + cdc.MustUnmarshalBinaryBare(kvB.Value, &missedB) return fmt.Sprintf("missedA: %v\nmissedB: %v", missedA.Value, missedB.Value) case bytes.Equal(kvA.Key[:1], types.AddrPubkeyRelationKey): var pubKeyA, pubKeyB crypto.PubKey - cdc.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &pubKeyA) - cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &pubKeyB) + cdc.MustUnmarshalBinaryBare(kvA.Value, &pubKeyA) + cdc.MustUnmarshalBinaryBare(kvB.Value, &pubKeyB) bechPKA := sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pubKeyA) bechPKB := sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pubKeyB) return fmt.Sprintf("PubKeyA: %s\nPubKeyB: %s", bechPKA, bechPKB) diff --git a/x/slashing/simulation/decoder_test.go b/x/slashing/simulation/decoder_test.go index 522bff74750d..8d0c8b41e562 100644 --- a/x/slashing/simulation/decoder_test.go +++ b/x/slashing/simulation/decoder_test.go @@ -41,9 +41,9 @@ func TestDecodeStore(t *testing.T) { missed := gogotypes.BoolValue{Value: true} kvPairs := tmkv.Pairs{ - tmkv.Pair{Key: types.GetValidatorSigningInfoKey(consAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(info)}, - tmkv.Pair{Key: types.GetValidatorMissedBlockBitArrayKey(consAddr1, 6), Value: cdc.MustMarshalBinaryLengthPrefixed(&missed)}, - tmkv.Pair{Key: types.GetAddrPubkeyRelationKey(delAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(delPk1)}, + tmkv.Pair{Key: types.GetValidatorSigningInfoKey(consAddr1), Value: cdc.MustMarshalBinaryBare(info)}, + tmkv.Pair{Key: types.GetValidatorMissedBlockBitArrayKey(consAddr1, 6), Value: cdc.MustMarshalBinaryBare(&missed)}, + tmkv.Pair{Key: types.GetAddrPubkeyRelationKey(delAddr1), Value: cdc.MustMarshalBinaryBare(delPk1)}, tmkv.Pair{Key: []byte{0x99}, Value: []byte{0x99}}, } diff --git a/x/slashing/types/signing_info.go b/x/slashing/types/signing_info.go index 315cac792c56..a9cc15f6ec0e 100644 --- a/x/slashing/types/signing_info.go +++ b/x/slashing/types/signing_info.go @@ -40,6 +40,6 @@ func (i ValidatorSigningInfo) String() string { // unmarshal a validator signing info from a store value func UnmarshalValSigningInfo(cdc codec.Marshaler, value []byte) (signingInfo ValidatorSigningInfo, err error) { - err = cdc.UnmarshalBinaryLengthPrefixed(value, &signingInfo) + err = cdc.UnmarshalBinaryBare(value, &signingInfo) return signingInfo, err } diff --git a/x/staking/keeper/delegation.go b/x/staking/keeper/delegation.go index e5c1912daf36..469bb5eaba04 100644 --- a/x/staking/keeper/delegation.go +++ b/x/staking/keeper/delegation.go @@ -223,14 +223,14 @@ func (k Keeper) GetUBDQueueTimeSlice(ctx sdk.Context, timestamp time.Time) (dvPa } pairs := types.DVPairs{} - k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &pairs) + k.cdc.MustUnmarshalBinaryBare(bz, &pairs) return pairs.Pairs } // Sets a specific unbonding queue timeslice. func (k Keeper) SetUBDQueueTimeSlice(ctx sdk.Context, timestamp time.Time, keys []types.DVPair) { store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinaryLengthPrefixed(&types.DVPairs{Pairs: keys}) + bz := k.cdc.MustMarshalBinaryBare(&types.DVPairs{Pairs: keys}) store.Set(types.GetUnbondingDelegationTimeKey(timestamp), bz) } @@ -265,7 +265,7 @@ func (k Keeper) DequeueAllMatureUBDQueue(ctx sdk.Context, currTime time.Time) (m for ; unbondingTimesliceIterator.Valid(); unbondingTimesliceIterator.Next() { timeslice := types.DVPairs{} value := unbondingTimesliceIterator.Value() - k.cdc.MustUnmarshalBinaryLengthPrefixed(value, ×lice) + k.cdc.MustUnmarshalBinaryBare(value, ×lice) matureUnbonds = append(matureUnbonds, timeslice.Pairs...) store.Delete(unbondingTimesliceIterator.Key()) @@ -412,14 +412,14 @@ func (k Keeper) GetRedelegationQueueTimeSlice(ctx sdk.Context, timestamp time.Ti } triplets := types.DVVTriplets{} - k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &triplets) + k.cdc.MustUnmarshalBinaryBare(bz, &triplets) return triplets.Triplets } // Sets a specific redelegation queue timeslice. func (k Keeper) SetRedelegationQueueTimeSlice(ctx sdk.Context, timestamp time.Time, keys []types.DVVTriplet) { store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinaryLengthPrefixed(&types.DVVTriplets{Triplets: keys}) + bz := k.cdc.MustMarshalBinaryBare(&types.DVVTriplets{Triplets: keys}) store.Set(types.GetRedelegationTimeKey(timestamp), bz) } @@ -457,7 +457,7 @@ func (k Keeper) DequeueAllMatureRedelegationQueue(ctx sdk.Context, currTime time for ; redelegationTimesliceIterator.Valid(); redelegationTimesliceIterator.Next() { timeslice := types.DVVTriplets{} value := redelegationTimesliceIterator.Value() - k.cdc.MustUnmarshalBinaryLengthPrefixed(value, ×lice) + k.cdc.MustUnmarshalBinaryBare(value, ×lice) matureRedelegations = append(matureRedelegations, timeslice.Triplets...) store.Delete(redelegationTimesliceIterator.Key()) diff --git a/x/staking/keeper/keeper.go b/x/staking/keeper/keeper.go index b809e070ca95..feddaf3b96f8 100644 --- a/x/staking/keeper/keeper.go +++ b/x/staking/keeper/keeper.go @@ -85,13 +85,13 @@ func (k Keeper) GetLastTotalPower(ctx sdk.Context) sdk.Int { } ip := sdk.IntProto{} - k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &ip) + k.cdc.MustUnmarshalBinaryBare(bz, &ip) return ip.Int } // Set the last total validator power. func (k Keeper) SetLastTotalPower(ctx sdk.Context, power sdk.Int) { store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinaryLengthPrefixed(&sdk.IntProto{Int: power}) + bz := k.cdc.MustMarshalBinaryBare(&sdk.IntProto{Int: power}) store.Set(types.LastTotalPowerKey, bz) } diff --git a/x/staking/keeper/val_state_change.go b/x/staking/keeper/val_state_change.go index 9927d6ed2329..34325024069b 100644 --- a/x/staking/keeper/val_state_change.go +++ b/x/staking/keeper/val_state_change.go @@ -138,7 +138,7 @@ func (k Keeper) ApplyAndReturnValidatorSetUpdates(ctx sdk.Context) (updates []ab oldPowerBytes, found := last[valAddrBytes] newPower := validator.ConsensusPower() - newPowerBytes := k.cdc.MustMarshalBinaryLengthPrefixed(&gogotypes.Int64Value{Value: newPower}) + newPowerBytes := k.cdc.MustMarshalBinaryBare(&gogotypes.Int64Value{Value: newPower}) // update the validator set if power has changed if !found || !bytes.Equal(oldPowerBytes, newPowerBytes) { diff --git a/x/staking/keeper/validator.go b/x/staking/keeper/validator.go index c8d4d597e9b3..3e3e635df014 100644 --- a/x/staking/keeper/validator.go +++ b/x/staking/keeper/validator.go @@ -278,14 +278,14 @@ func (k Keeper) GetLastValidatorPower(ctx sdk.Context, operator sdk.ValAddress) } intV := gogotypes.Int64Value{} - k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &intV) + k.cdc.MustUnmarshalBinaryBare(bz, &intV) return intV.GetValue() } // Set the last validator power. func (k Keeper) SetLastValidatorPower(ctx sdk.Context, operator sdk.ValAddress, power int64) { store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinaryLengthPrefixed(&gogotypes.Int64Value{Value: power}) + bz := k.cdc.MustMarshalBinaryBare(&gogotypes.Int64Value{Value: power}) store.Set(types.GetLastValidatorPowerKey(operator), bz) } @@ -311,7 +311,7 @@ func (k Keeper) IterateLastValidatorPowers(ctx sdk.Context, handler func(operato addr := sdk.ValAddress(iter.Key()[len(types.LastValidatorPowerKey):]) intV := &gogotypes.Int64Value{} - k.cdc.MustUnmarshalBinaryLengthPrefixed(iter.Value(), intV) + k.cdc.MustUnmarshalBinaryBare(iter.Value(), intV) if handler(addr, intV.GetValue()) { break } @@ -358,14 +358,14 @@ func (k Keeper) GetValidatorQueueTimeSlice(ctx sdk.Context, timestamp time.Time) } va := sdk.ValAddresses{} - k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &va) + k.cdc.MustUnmarshalBinaryBare(bz, &va) return va.Addresses } // Sets a specific validator queue timeslice. func (k Keeper) SetValidatorQueueTimeSlice(ctx sdk.Context, timestamp time.Time, keys []sdk.ValAddress) { store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinaryLengthPrefixed(&sdk.ValAddresses{Addresses: keys}) + bz := k.cdc.MustMarshalBinaryBare(&sdk.ValAddresses{Addresses: keys}) store.Set(types.GetValidatorQueueTimeKey(timestamp), bz) } @@ -413,7 +413,7 @@ func (k Keeper) GetAllMatureValidatorQueue(ctx sdk.Context, currTime time.Time) for ; validatorTimesliceIterator.Valid(); validatorTimesliceIterator.Next() { timeslice := sdk.ValAddresses{} - k.cdc.MustUnmarshalBinaryLengthPrefixed(validatorTimesliceIterator.Value(), ×lice) + k.cdc.MustUnmarshalBinaryBare(validatorTimesliceIterator.Value(), ×lice) matureValsAddrs = append(matureValsAddrs, timeslice.Addresses...) } @@ -429,7 +429,7 @@ func (k Keeper) UnbondAllMatureValidatorQueue(ctx sdk.Context) { for ; validatorTimesliceIterator.Valid(); validatorTimesliceIterator.Next() { timeslice := sdk.ValAddresses{} - k.cdc.MustUnmarshalBinaryLengthPrefixed(validatorTimesliceIterator.Value(), ×lice) + k.cdc.MustUnmarshalBinaryBare(validatorTimesliceIterator.Value(), ×lice) for _, valAddr := range timeslice.Addresses { val, found := k.GetValidator(ctx, valAddr) diff --git a/x/staking/keeper/validator_test.go b/x/staking/keeper/validator_test.go index f7295a5421de..d6518c722df4 100644 --- a/x/staking/keeper/validator_test.go +++ b/x/staking/keeper/validator_test.go @@ -7,7 +7,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/simapp" diff --git a/x/staking/simulation/decoder.go b/x/staking/simulation/decoder.go index de5d50de9f7d..86f1cecc9e00 100644 --- a/x/staking/simulation/decoder.go +++ b/x/staking/simulation/decoder.go @@ -16,14 +16,14 @@ func DecodeStore(cdc *codec.Codec, kvA, kvB tmkv.Pair) string { switch { case bytes.Equal(kvA.Key[:1], types.LastTotalPowerKey): var powerA, powerB sdk.Int - cdc.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &powerA) - cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &powerB) + cdc.MustUnmarshalBinaryBare(kvA.Value, &powerA) + cdc.MustUnmarshalBinaryBare(kvB.Value, &powerB) return fmt.Sprintf("%v\n%v", powerA, powerB) case bytes.Equal(kvA.Key[:1], types.ValidatorsKey): var validatorA, validatorB types.Validator - cdc.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &validatorA) - cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &validatorB) + cdc.MustUnmarshalBinaryBare(kvA.Value, &validatorA) + cdc.MustUnmarshalBinaryBare(kvB.Value, &validatorB) return fmt.Sprintf("%v\n%v", validatorA, validatorB) case bytes.Equal(kvA.Key[:1], types.LastValidatorPowerKey), @@ -33,22 +33,22 @@ func DecodeStore(cdc *codec.Codec, kvA, kvB tmkv.Pair) string { case bytes.Equal(kvA.Key[:1], types.DelegationKey): var delegationA, delegationB types.Delegation - cdc.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &delegationA) - cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &delegationB) + cdc.MustUnmarshalBinaryBare(kvA.Value, &delegationA) + cdc.MustUnmarshalBinaryBare(kvB.Value, &delegationB) return fmt.Sprintf("%v\n%v", delegationA, delegationB) case bytes.Equal(kvA.Key[:1], types.UnbondingDelegationKey), bytes.Equal(kvA.Key[:1], types.UnbondingDelegationByValIndexKey): var ubdA, ubdB types.UnbondingDelegation - cdc.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &ubdA) - cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &ubdB) + cdc.MustUnmarshalBinaryBare(kvA.Value, &ubdA) + cdc.MustUnmarshalBinaryBare(kvB.Value, &ubdB) return fmt.Sprintf("%v\n%v", ubdA, ubdB) case bytes.Equal(kvA.Key[:1], types.RedelegationKey), bytes.Equal(kvA.Key[:1], types.RedelegationByValSrcIndexKey): var redA, redB types.Redelegation - cdc.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &redA) - cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &redB) + cdc.MustUnmarshalBinaryBare(kvA.Value, &redA) + cdc.MustUnmarshalBinaryBare(kvB.Value, &redB) return fmt.Sprintf("%v\n%v", redA, redB) default: diff --git a/x/staking/simulation/decoder_test.go b/x/staking/simulation/decoder_test.go index 5e0407c59c07..40dd39710e84 100644 --- a/x/staking/simulation/decoder_test.go +++ b/x/staking/simulation/decoder_test.go @@ -40,12 +40,12 @@ func TestDecodeStore(t *testing.T) { red := types.NewRedelegation(delAddr1, valAddr1, valAddr1, 12, bondTime, sdk.OneInt(), sdk.OneDec()) kvPairs := tmkv.Pairs{ - tmkv.Pair{Key: types.LastTotalPowerKey, Value: cdc.MustMarshalBinaryLengthPrefixed(sdk.OneInt())}, - tmkv.Pair{Key: types.GetValidatorKey(valAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(val)}, + tmkv.Pair{Key: types.LastTotalPowerKey, Value: cdc.MustMarshalBinaryBare(sdk.OneInt())}, + tmkv.Pair{Key: types.GetValidatorKey(valAddr1), Value: cdc.MustMarshalBinaryBare(val)}, tmkv.Pair{Key: types.LastValidatorPowerKey, Value: valAddr1.Bytes()}, - tmkv.Pair{Key: types.GetDelegationKey(delAddr1, valAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(del)}, - tmkv.Pair{Key: types.GetUBDKey(delAddr1, valAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(ubd)}, - tmkv.Pair{Key: types.GetREDKey(delAddr1, valAddr1, valAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(red)}, + tmkv.Pair{Key: types.GetDelegationKey(delAddr1, valAddr1), Value: cdc.MustMarshalBinaryBare(del)}, + tmkv.Pair{Key: types.GetUBDKey(delAddr1, valAddr1), Value: cdc.MustMarshalBinaryBare(ubd)}, + tmkv.Pair{Key: types.GetREDKey(delAddr1, valAddr1, valAddr1), Value: cdc.MustMarshalBinaryBare(red)}, tmkv.Pair{Key: []byte{0x99}, Value: []byte{0x99}}, } diff --git a/x/staking/types/delegation.go b/x/staking/types/delegation.go index 51fca1d38e48..34852d73d9f4 100644 --- a/x/staking/types/delegation.go +++ b/x/staking/types/delegation.go @@ -39,7 +39,7 @@ func NewDelegation(delegatorAddr sdk.AccAddress, validatorAddr sdk.ValAddress, s // MustMarshalDelegation returns the delegation bytes. Panics if fails func MustMarshalDelegation(cdc codec.Marshaler, delegation Delegation) []byte { - return cdc.MustMarshalBinaryLengthPrefixed(&delegation) + return cdc.MustMarshalBinaryBare(&delegation) } // MustUnmarshalDelegation return the unmarshaled delegation from bytes. @@ -54,7 +54,7 @@ func MustUnmarshalDelegation(cdc codec.Marshaler, value []byte) Delegation { // return the delegation func UnmarshalDelegation(cdc codec.Marshaler, value []byte) (delegation Delegation, err error) { - err = cdc.UnmarshalBinaryLengthPrefixed(value, &delegation) + err = cdc.UnmarshalBinaryBare(value, &delegation) return delegation, err } @@ -127,7 +127,7 @@ func (ubd *UnbondingDelegation) RemoveEntry(i int64) { // return the unbonding delegation func MustMarshalUBD(cdc codec.Marshaler, ubd UnbondingDelegation) []byte { - return cdc.MustMarshalBinaryLengthPrefixed(&ubd) + return cdc.MustMarshalBinaryBare(&ubd) } // unmarshal a unbonding delegation from a store value @@ -141,7 +141,7 @@ func MustUnmarshalUBD(cdc codec.Marshaler, value []byte) UnbondingDelegation { // unmarshal a unbonding delegation from a store value func UnmarshalUBD(cdc codec.Marshaler, value []byte) (ubd UnbondingDelegation, err error) { - err = cdc.UnmarshalBinaryLengthPrefixed(value, &ubd) + err = cdc.UnmarshalBinaryBare(value, &ubd) return ubd, err } @@ -219,7 +219,7 @@ func (red *Redelegation) RemoveEntry(i int64) { // MustMarshalRED returns the Redelegation bytes. Panics if fails. func MustMarshalRED(cdc codec.Marshaler, red Redelegation) []byte { - return cdc.MustMarshalBinaryLengthPrefixed(&red) + return cdc.MustMarshalBinaryBare(&red) } // MustUnmarshalRED unmarshals a redelegation from a store value. Panics if fails. @@ -233,7 +233,7 @@ func MustUnmarshalRED(cdc codec.Marshaler, value []byte) Redelegation { // UnmarshalRED unmarshals a redelegation from a store value func UnmarshalRED(cdc codec.Marshaler, value []byte) (red Redelegation, err error) { - err = cdc.UnmarshalBinaryLengthPrefixed(value, &red) + err = cdc.UnmarshalBinaryBare(value, &red) return red, err } diff --git a/x/staking/types/historical_info.go b/x/staking/types/historical_info.go index 98f2ea86a5cd..002a53a85410 100644 --- a/x/staking/types/historical_info.go +++ b/x/staking/types/historical_info.go @@ -21,7 +21,7 @@ func NewHistoricalInfo(header abci.Header, valSet Validators) HistoricalInfo { // MustMarshalHistoricalInfo wll marshal historical info and panic on error func MustMarshalHistoricalInfo(cdc codec.Marshaler, hi HistoricalInfo) []byte { - return cdc.MustMarshalBinaryLengthPrefixed(&hi) + return cdc.MustMarshalBinaryBare(&hi) } // MustUnmarshalHistoricalInfo wll unmarshal historical info and panic on error @@ -35,7 +35,7 @@ func MustUnmarshalHistoricalInfo(cdc codec.Marshaler, value []byte) HistoricalIn // UnmarshalHistoricalInfo will unmarshal historical info and return any error func UnmarshalHistoricalInfo(cdc codec.Marshaler, value []byte) (hi HistoricalInfo, err error) { - err = cdc.UnmarshalBinaryLengthPrefixed(value, &hi) + err = cdc.UnmarshalBinaryBare(value, &hi) return hi, err } diff --git a/x/staking/types/params.go b/x/staking/types/params.go index 8d2b14ec694e..ac21113d7ec7 100644 --- a/x/staking/types/params.go +++ b/x/staking/types/params.go @@ -95,7 +95,7 @@ func MustUnmarshalParams(cdc *codec.Codec, value []byte) Params { // unmarshal the current staking params value from store key func UnmarshalParams(cdc *codec.Codec, value []byte) (params Params, err error) { - err = cdc.UnmarshalBinaryLengthPrefixed(value, ¶ms) + err = cdc.UnmarshalBinaryBare(value, ¶ms) if err != nil { return } diff --git a/x/staking/types/validator.go b/x/staking/types/validator.go index 2304596ae2b9..52dfdc33f77d 100644 --- a/x/staking/types/validator.go +++ b/x/staking/types/validator.go @@ -108,7 +108,7 @@ func (v Validators) Swap(i, j int) { // return the redelegation func MustMarshalValidator(cdc codec.Marshaler, validator Validator) []byte { - return cdc.MustMarshalBinaryLengthPrefixed(&validator) + return cdc.MustMarshalBinaryBare(&validator) } // unmarshal a redelegation from a store value @@ -122,7 +122,7 @@ func MustUnmarshalValidator(cdc codec.Marshaler, value []byte) Validator { // unmarshal a redelegation from a store value func UnmarshalValidator(cdc codec.Marshaler, value []byte) (v Validator, err error) { - err = cdc.UnmarshalBinaryLengthPrefixed(value, &v) + err = cdc.UnmarshalBinaryBare(value, &v) return v, err } diff --git a/x/supply/simulation/decoder.go b/x/supply/simulation/decoder.go index b67e07651be4..f025b50464e2 100644 --- a/x/supply/simulation/decoder.go +++ b/x/supply/simulation/decoder.go @@ -16,8 +16,8 @@ func DecodeStore(cdc *codec.Codec, kvA, kvB tmkv.Pair) string { switch { case bytes.Equal(kvA.Key[:1], keeper.SupplyKey): var supplyA, supplyB types.Supply - cdc.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &supplyA) - cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &supplyB) + cdc.MustUnmarshalBinaryBare(kvA.Value, &supplyA) + cdc.MustUnmarshalBinaryBare(kvB.Value, &supplyB) return fmt.Sprintf("%v\n%v", supplyB, supplyB) default: diff --git a/x/supply/simulation/decoder_test.go b/x/supply/simulation/decoder_test.go index 413e0a930e9d..d5e196ed41f1 100644 --- a/x/supply/simulation/decoder_test.go +++ b/x/supply/simulation/decoder_test.go @@ -27,7 +27,7 @@ func TestDecodeStore(t *testing.T) { totalSupply := types.NewSupply(sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 1000))) kvPairs := tmkv.Pairs{ - tmkv.Pair{Key: keeper.SupplyKey, Value: cdc.MustMarshalBinaryLengthPrefixed(totalSupply)}, + tmkv.Pair{Key: keeper.SupplyKey, Value: cdc.MustMarshalBinaryBare(totalSupply)}, tmkv.Pair{Key: []byte{0x99}, Value: []byte{0x99}}, } From 45870eb23cf3b7220b44ec66583241a13068f8fd Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 13 Mar 2020 20:57:12 +0000 Subject: [PATCH 419/529] Bump github.com/tendermint/iavl from 0.13.0 to 0.13.1 Bumps [github.com/tendermint/iavl](https://github.com/tendermint/iavl) from 0.13.0 to 0.13.1. - [Release notes](https://github.com/tendermint/iavl/releases) - [Changelog](https://github.com/tendermint/iavl/blob/master/CHANGELOG.md) - [Commits](https://github.com/tendermint/iavl/compare/v0.13.0...v0.13.1) Signed-off-by: dependabot-preview[bot] --- go.mod | 2 +- go.sum | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index c29e55729b78..771e8f81da83 100644 --- a/go.mod +++ b/go.mod @@ -27,7 +27,7 @@ require ( github.com/tendermint/btcd v0.1.1 github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 github.com/tendermint/go-amino v0.15.1 - github.com/tendermint/iavl v0.13.0 + github.com/tendermint/iavl v0.13.1 github.com/tendermint/tendermint v0.33.2 github.com/tendermint/tm-db v0.4.1 gopkg.in/yaml.v2 v2.2.8 diff --git a/go.sum b/go.sum index e65186753232..d8678d57121e 100644 --- a/go.sum +++ b/go.sum @@ -58,6 +58,7 @@ github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= @@ -92,7 +93,9 @@ github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1 github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/etcd-io/bbolt v1.3.3 h1:gSJmxrs37LgTqR/oyJBWok6k6SvXEUerFTbltIhXkBM= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= @@ -137,6 +140,7 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.4 h1:87PNWwrRvUSnqS4dlcBU/ftvOIBep4sYuBLlh6rX2wk= github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls= @@ -145,6 +149,7 @@ github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8l github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -423,6 +428,8 @@ github.com/tendermint/go-amino v0.15.1 h1:D2uk35eT4iTsvJd9jWIetzthE5C0/k2QmMFkCN github.com/tendermint/go-amino v0.15.1/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= github.com/tendermint/iavl v0.13.0 h1:r2sINvNFlJsLlLhGoqlqPlREWYkuK26BvMfkBt+XQnA= github.com/tendermint/iavl v0.13.0/go.mod h1:7nSUPdrsHEZ2nNZa+9gaIrcJciWd1jCQZXtcyARU82k= +github.com/tendermint/iavl v0.13.1 h1:KWg3NVqOZLJFCLKpUJjUprdWAgIYdC9GDJLN8PBmKbI= +github.com/tendermint/iavl v0.13.1/go.mod h1:vE1u0XAGXYjHykd4BLp8p/yivrw2PF1TuoljBcsQoGA= github.com/tendermint/tendermint v0.33.0/go.mod h1:s5UoymnPIY+GcA3mMte4P9gpMP8vS7UH7HBXikT1pHI= github.com/tendermint/tendermint v0.33.2 h1:NzvRMTuXJxqSsFed2J7uHmMU5N1CVzSpfi3nCc882KY= github.com/tendermint/tendermint v0.33.2/go.mod h1:25DqB7YvV1tN3tHsjWoc2vFtlwICfrub9XO6UBO+4xk= @@ -430,6 +437,8 @@ github.com/tendermint/tm-db v0.4.0 h1:iPbCcLbf4nwDFhS39Zo1lpdS1X/cT9CkTlUx17FHQg github.com/tendermint/tm-db v0.4.0/go.mod h1:+Cwhgowrf7NBGXmsqFMbwEtbo80XmyrlY5Jsk95JubQ= github.com/tendermint/tm-db v0.4.1 h1:TvX7JWjJOVZ+N3y+I86wddrGttOdMmmBxXcu0/Y7ZJ0= github.com/tendermint/tm-db v0.4.1/go.mod h1:JsJ6qzYkCGiGwm5GHl/H5GLI9XLb6qZX7PRe425dHAY= +github.com/tendermint/tm-db v0.5.0 h1:qtM5UTr1dlRnHtDY6y7MZO5Di8XAE2j3lc/pCnKJ5hQ= +github.com/tendermint/tm-db v0.5.0/go.mod h1:lSq7q5WRR/njf1LnhiZ/lIJHk2S8Y1Zyq5oP/3o9C2U= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= @@ -567,9 +576,11 @@ google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ij google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= From 54f7dbfbab1e825f434767635b5cff933d140478 Mon Sep 17 00:00:00 2001 From: Marko Baricevic Date: Fri, 13 Mar 2020 22:31:40 +0100 Subject: [PATCH 420/529] fix go.sum --- go.mod | 2 +- go.sum | 14 +------------- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/go.mod b/go.mod index 771e8f81da83..15d092de1eb1 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( github.com/tendermint/go-amino v0.15.1 github.com/tendermint/iavl v0.13.1 github.com/tendermint/tendermint v0.33.2 - github.com/tendermint/tm-db v0.4.1 + github.com/tendermint/tm-db v0.5.0 gopkg.in/yaml.v2 v2.2.8 ) diff --git a/go.sum b/go.sum index d8678d57121e..0b88b0f01b99 100644 --- a/go.sum +++ b/go.sum @@ -12,7 +12,6 @@ github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWX github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= -github.com/Workiva/go-datastructures v1.0.50/go.mod h1:Z+F2Rca0qCsVYDS8z7bAGm8f3UkzuWYS/oBZz5a7VVA= github.com/Workiva/go-datastructures v1.0.52/go.mod h1:Z+F2Rca0qCsVYDS8z7bAGm8f3UkzuWYS/oBZz5a7VVA= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= @@ -351,8 +350,6 @@ github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+Gx github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rakyll/statik v0.1.7 h1:OF3QCZUuyPxuGEP7B4ypUa7sB/iHtqOTDYZXGM8KOdQ= github.com/rakyll/statik v0.1.7/go.mod h1:AlZONWzMtEnMs7W4e/1LURLiI49pIMmp6V9Unghqrcc= -github.com/rcrowley/go-metrics v0.0.0-20180503174638-e2704e165165 h1:nkcn14uNmFEuGCb2mBZbBb24RdNRL08b/wb+xBOYpuk= -github.com/rcrowley/go-metrics v0.0.0-20180503174638-e2704e165165/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a h1:9ZKAASQSHhDYGoxY8uLVpewe1GDZ2vu2Tr/vTdVAkFQ= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/regen-network/cosmos-proto v0.1.1-0.20200213154359-02baa11ea7c2 h1:jQK1YoH972Aptd22YKgtNu5jM2X2xMGkyIENOAc71to= @@ -383,7 +380,6 @@ github.com/spf13/afero v1.2.1 h1:qgMbHoJbPbw579P+1zVY+6n4nIFuIchaIjzZ/I/Yq8M= github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.1/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.6 h1:breEStsVwemnKh2/s6gMvSdMEkwW0sK8vGStnlVBMCs= github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= @@ -395,7 +391,6 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= -github.com/spf13/viper v1.6.1/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k= github.com/spf13/viper v1.6.2 h1:7aKfF+e8/k68gda3LOjo5RxiUqddoFxVq4BKBPrxk5E= github.com/spf13/viper v1.6.2/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= @@ -415,8 +410,6 @@ github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d h1:gZZadD8H+fF+n9CmNhYL1Y0dJB+kLOmKd7FbPJLeGHs= github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA= -github.com/tecbot/gorocksdb v0.0.0-20191017175515-d217d93fd4c5 h1:gVwAW5OwaZlDB5/CfqcGFM9p9C+KxvQKyNOltQ8orj0= -github.com/tecbot/gorocksdb v0.0.0-20191017175515-d217d93fd4c5/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8= github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c h1:g+WoO5jjkqGAzHWCjJB1zZfXPIAaDpzXIEJ0eS6B5Ok= github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8= github.com/tendermint/btcd v0.1.1 h1:0VcxPfflS2zZ3RiOAHkBiFUcPvbtRj5O7zHmcJWHV7s= @@ -426,15 +419,10 @@ github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15/go.mod h1:z4YtwM github.com/tendermint/go-amino v0.14.1/go.mod h1:i/UKE5Uocn+argJJBb12qTZsCDBcAYMbR92AaJVmKso= github.com/tendermint/go-amino v0.15.1 h1:D2uk35eT4iTsvJd9jWIetzthE5C0/k2QmMFkCN+4JgQ= github.com/tendermint/go-amino v0.15.1/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= -github.com/tendermint/iavl v0.13.0 h1:r2sINvNFlJsLlLhGoqlqPlREWYkuK26BvMfkBt+XQnA= -github.com/tendermint/iavl v0.13.0/go.mod h1:7nSUPdrsHEZ2nNZa+9gaIrcJciWd1jCQZXtcyARU82k= github.com/tendermint/iavl v0.13.1 h1:KWg3NVqOZLJFCLKpUJjUprdWAgIYdC9GDJLN8PBmKbI= github.com/tendermint/iavl v0.13.1/go.mod h1:vE1u0XAGXYjHykd4BLp8p/yivrw2PF1TuoljBcsQoGA= -github.com/tendermint/tendermint v0.33.0/go.mod h1:s5UoymnPIY+GcA3mMte4P9gpMP8vS7UH7HBXikT1pHI= github.com/tendermint/tendermint v0.33.2 h1:NzvRMTuXJxqSsFed2J7uHmMU5N1CVzSpfi3nCc882KY= github.com/tendermint/tendermint v0.33.2/go.mod h1:25DqB7YvV1tN3tHsjWoc2vFtlwICfrub9XO6UBO+4xk= -github.com/tendermint/tm-db v0.4.0 h1:iPbCcLbf4nwDFhS39Zo1lpdS1X/cT9CkTlUx17FHQgA= -github.com/tendermint/tm-db v0.4.0/go.mod h1:+Cwhgowrf7NBGXmsqFMbwEtbo80XmyrlY5Jsk95JubQ= github.com/tendermint/tm-db v0.4.1 h1:TvX7JWjJOVZ+N3y+I86wddrGttOdMmmBxXcu0/Y7ZJ0= github.com/tendermint/tm-db v0.4.1/go.mod h1:JsJ6qzYkCGiGwm5GHl/H5GLI9XLb6qZX7PRe425dHAY= github.com/tendermint/tm-db v0.5.0 h1:qtM5UTr1dlRnHtDY6y7MZO5Di8XAE2j3lc/pCnKJ5hQ= @@ -522,7 +510,6 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -580,6 +567,7 @@ google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQ google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0 h1:bO/TA4OxCOummhSf10siHuG7vJOiwh7SpRpFZDkOgl4= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 98f62db2427531476039375ea77beaf141e616f3 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Sun, 15 Mar 2020 14:10:15 -0400 Subject: [PATCH 421/529] Fix linting --- client/context/context.go | 4 ++-- client/tx/tx.go | 4 ++-- codec/std/msgs_test.go | 4 ---- codec/std/tx.go | 6 +++--- docs/architecture/adr-020-protobuf-transaction-encoding.md | 4 ++-- 5 files changed, 9 insertions(+), 13 deletions(-) diff --git a/client/context/context.go b/client/context/context.go index eec74e7febaf..ae0576122602 100644 --- a/client/context/context.go +++ b/client/context/context.go @@ -26,7 +26,7 @@ type CLIContext struct { FromAddress sdk.AccAddress Client rpcclient.Client ChainID string - TxGenerator clientx.TxGenerator + TxGenerator clientx.Generator Marshaler codec.Marshaler Keybase keys.Keybase Input io.Reader @@ -136,7 +136,7 @@ func (ctx CLIContext) WithInput(r io.Reader) CLIContext { } // WithTxGenerator returns a copy of the CLIContext with an updated TxGenerator. -func (ctx CLIContext) WithTxGenerator(txg clientx.TxGenerator) CLIContext { +func (ctx CLIContext) WithTxGenerator(txg clientx.Generator) CLIContext { ctx.TxGenerator = txg return ctx } diff --git a/client/tx/tx.go b/client/tx/tx.go index ead819f33472..84c918832ecf 100644 --- a/client/tx/tx.go +++ b/client/tx/tx.go @@ -6,10 +6,10 @@ import ( ) type ( - // TxGenerator defines an interface a client can utilize to generate an + // Generator defines an interface a client can utilize to generate an // application-defined concrete transaction type. The type returned must // implement ClientTx. - TxGenerator interface { + Generator interface { NewTx() ClientTx } diff --git a/codec/std/msgs_test.go b/codec/std/msgs_test.go index bd3063ecba1f..f0bd00efae25 100644 --- a/codec/std/msgs_test.go +++ b/codec/std/msgs_test.go @@ -12,10 +12,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/gov" ) -type BadEvidence struct { - *std.Evidence_Equivocation -} - func TestNewMsgSubmitEvidence(t *testing.T) { s := sdk.AccAddress("foo") e := evidence.Equivocation{ diff --git a/codec/std/tx.go b/codec/std/tx.go index 2a9b9af29b82..eca3553f306d 100644 --- a/codec/std/tx.go +++ b/codec/std/tx.go @@ -8,9 +8,9 @@ import ( ) var ( - _ sdk.Tx = (*Transaction)(nil) - _ clientx.ClientTx = (*Transaction)(nil) - _ clientx.TxGenerator = TxGenerator{} + _ sdk.Tx = (*Transaction)(nil) + _ clientx.ClientTx = (*Transaction)(nil) + _ clientx.Generator = TxGenerator{} ) // TxGenerator defines a transaction generator that allows clients to construct diff --git a/docs/architecture/adr-020-protobuf-transaction-encoding.md b/docs/architecture/adr-020-protobuf-transaction-encoding.md index d5a72f3afbe5..8038cea80f8b 100644 --- a/docs/architecture/adr-020-protobuf-transaction-encoding.md +++ b/docs/architecture/adr-020-protobuf-transaction-encoding.md @@ -103,7 +103,7 @@ to handle all the types, but also knows how to generate transactions, signatures and messages. ```go -type TxGenerator interface { +type Generator interface { NewTx() ClientTx } @@ -123,7 +123,7 @@ type ClientTx interface { } ``` -We then update `CLIContext` to have two new fields: `TxGenerator` and `TxGenerator`. +We then update `CLIContext` to have two new fields: `Generator` and `Generator`. Then, each module will at the minimum accept a `Marshaler` instead of a concrete Amino codec. If the module needs to work with any interface types, it will use From e31757cfa712e34af66c6970527aae875de0f5fb Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 16 Mar 2020 06:40:15 +0000 Subject: [PATCH 422/529] Bump github.com/golang/mock from 1.4.1 to 1.4.2 Bumps [github.com/golang/mock](https://github.com/golang/mock) from 1.4.1 to 1.4.2. - [Release notes](https://github.com/golang/mock/releases) - [Changelog](https://github.com/golang/mock/blob/master/.goreleaser.yml) - [Commits](https://github.com/golang/mock/compare/v1.4.1...v1.4.2) Signed-off-by: dependabot-preview[bot] --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 15d092de1eb1..746d86496d5e 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d github.com/cosmos/ledger-cosmos-go v0.11.1 github.com/gogo/protobuf v1.3.1 - github.com/golang/mock v1.4.1 + github.com/golang/mock v1.4.2 github.com/golang/protobuf v1.3.5 github.com/gorilla/handlers v1.4.2 github.com/gorilla/mux v1.7.4 diff --git a/go.sum b/go.sum index 0b88b0f01b99..71517be1440d 100644 --- a/go.sum +++ b/go.sum @@ -135,6 +135,8 @@ github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4er github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.4.1 h1:ocYkMQY5RrXTYgXl7ICpV0IXwlEQGwKIsery4gyXa1U= github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.2 h1:fXIkPzOBCwDUPvYmOPzETABgbqpYlYNigQ2o64eMr5c= +github.com/golang/mock v1.4.2/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= From e0021ad409bf7acf8a5fc4b8953d3e56ea0e0722 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Mon, 16 Mar 2020 10:48:37 -0400 Subject: [PATCH 423/529] Update docs/architecture/adr-020-protobuf-transaction-encoding.md Co-Authored-By: Marko --- docs/architecture/adr-020-protobuf-transaction-encoding.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture/adr-020-protobuf-transaction-encoding.md b/docs/architecture/adr-020-protobuf-transaction-encoding.md index 8038cea80f8b..6689f29e2356 100644 --- a/docs/architecture/adr-020-protobuf-transaction-encoding.md +++ b/docs/architecture/adr-020-protobuf-transaction-encoding.md @@ -123,7 +123,7 @@ type ClientTx interface { } ``` -We then update `CLIContext` to have two new fields: `Generator` and `Generator`. +We then update `CLIContext` to have two new fields: `Generator` and `Marshler`. Then, each module will at the minimum accept a `Marshaler` instead of a concrete Amino codec. If the module needs to work with any interface types, it will use From b557d4278f71282c09ad89d436564bc1a41e384b Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Mon, 16 Mar 2020 11:52:07 -0400 Subject: [PATCH 424/529] Update CanonicalSignBytes godoc --- client/tx/tx.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/client/tx/tx.go b/client/tx/tx.go index 84c918832ecf..be25ec7541c7 100644 --- a/client/tx/tx.go +++ b/client/tx/tx.go @@ -29,6 +29,10 @@ type ( GetMemo() string SetMemo(string) + // CanonicalSignBytes returns the canonical JSON bytes to sign over, given a + // chain ID, along with an account and sequence number. The JSON encoding + // ensures all field names adhere to their proto definition, default values + // are omitted, and follows the JSON Canonical Form. CanonicalSignBytes(cid string, num, seq uint64) ([]byte, error) } ) From 25f036f248c7441578d5a03d561dc40ae2acd03d Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Mon, 16 Mar 2020 19:02:55 -0400 Subject: [PATCH 425/529] Update params doc with restrictions --- go.mod | 2 +- go.sum | 4 ++-- x/distribution/spec/07_params.md | 16 ++++++++++------ 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 15d092de1eb1..746d86496d5e 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d github.com/cosmos/ledger-cosmos-go v0.11.1 github.com/gogo/protobuf v1.3.1 - github.com/golang/mock v1.4.1 + github.com/golang/mock v1.4.2 github.com/golang/protobuf v1.3.5 github.com/gorilla/handlers v1.4.2 github.com/gorilla/mux v1.7.4 diff --git a/go.sum b/go.sum index 0b88b0f01b99..27c8f005d649 100644 --- a/go.sum +++ b/go.sum @@ -133,8 +133,8 @@ github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4er github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.4.1 h1:ocYkMQY5RrXTYgXl7ICpV0IXwlEQGwKIsery4gyXa1U= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.2 h1:fXIkPzOBCwDUPvYmOPzETABgbqpYlYNigQ2o64eMr5c= +github.com/golang/mock v1.4.2/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= diff --git a/x/distribution/spec/07_params.md b/x/distribution/spec/07_params.md index 5a933e923a6b..2bcefd0c3ffa 100644 --- a/x/distribution/spec/07_params.md +++ b/x/distribution/spec/07_params.md @@ -6,9 +6,13 @@ order: 7 The distribution module contains the following parameters: -| Key | Type | Example | -|---------------------|--------------|------------------------| -| communitytax | string (dec) | "0.020000000000000000" | -| baseproposerreward | string (dec) | "0.010000000000000000" | -| bonusproposerreward | string (dec) | "0.040000000000000000" | -| withdrawaddrenabled | bool | true | +| Key | Type | Example | +| ------------------- | ------------ | -------------------------- | +| communitytax | string (dec) | "0.020000000000000000" [0] | +| baseproposerreward | string (dec) | "0.010000000000000000" [1] | +| bonusproposerreward | string (dec) | "0.040000000000000000" [1] | +| withdrawaddrenabled | bool | true | + +* [0] The value of `communitytax` must be positive and cannot exceed 1%. +* [1] The sum of `baseproposerreward` and `bonusproposerreward` cannot exceed 1%. +Both values must be positive. From 1c7da830c22a144fd176f18e4eaa0448bc55aa5b Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Tue, 17 Mar 2020 01:36:05 +0100 Subject: [PATCH 426/529] Revert changes for keybase encoding (#5814) --- CHANGELOG.md | 4 +++- crypto/keys/keybase_base.go | 2 +- crypto/keys/types.go | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a19fb7b3961..88549940f629 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,8 @@ balances or a single balance by denom when the `denom` query parameter is presen * [\#5785](https://github.com/cosmos/cosmos-sdk/issues/5785) JSON strings coerced to valid UTF-8 bytes at JSON marshalling time are now replaced by human-readable expressions. This change can potentially break compatibility with all those client side tools that parse log messages. +* (client) [\#5799](https://github.com/cosmos/cosmos-sdk/pull/5799) The `tx encode/decode` commands, due to change on encoding break compatibility with +older clients. ### API Breaking Changes @@ -148,7 +150,7 @@ Buffers for state serialization instead of Amino. to define their own concrete `MsgSubmitProposal` types. * The module now accepts a `Codec` interface which extends the `codec.Marshaler` interface by requiring a concrete codec to know how to serialize `Proposal` types. -* (codec) [\#5799](https://github.com/cosmos/cosmos-sdk/pull/5799) Now we favor the use of MarshalBinaryBare instead of LengthPrefixed in all cases that is not needed. +* (codec) [\#5799](https://github.com/cosmos/cosmos-sdk/pull/5799) Now we favor the use of `(Un)MarshalBinaryBare` instead of `(Un)MarshalBinaryLengthPrefixed` in all cases that are not needed. ### Improvements diff --git a/crypto/keys/keybase_base.go b/crypto/keys/keybase_base.go index 86ed00677d25..47c7e60d729a 100644 --- a/crypto/keys/keybase_base.go +++ b/crypto/keys/keybase_base.go @@ -124,7 +124,7 @@ func (kb baseKeybase) DecodeSignature(info Info, msg []byte) (sig []byte, pub tm return nil, nil, err } - if err := CryptoCdc.UnmarshalBinaryBare([]byte(signed), sig); err != nil { + if err := CryptoCdc.UnmarshalBinaryLengthPrefixed([]byte(signed), sig); err != nil { return nil, nil, errors.Wrap(err, "failed to decode signature") } diff --git a/crypto/keys/types.go b/crypto/keys/types.go index c91f2905b24e..89f5cb2d539b 100644 --- a/crypto/keys/types.go +++ b/crypto/keys/types.go @@ -337,12 +337,12 @@ func (i multiInfo) GetPath() (*hd.BIP44Params, error) { // encoding info func marshalInfo(i Info) []byte { - return CryptoCdc.MustMarshalBinaryBare(i) + return CryptoCdc.MustMarshalBinaryLengthPrefixed(i) } // decoding info func unmarshalInfo(bz []byte) (info Info, err error) { - err = CryptoCdc.UnmarshalBinaryBare(bz, &info) + err = CryptoCdc.UnmarshalBinaryLengthPrefixed(bz, &info) return } From b7f2f310a1c3ca3a52c78a4b1eb3cf5139671c02 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 17 Mar 2020 09:30:05 -0300 Subject: [PATCH 427/529] Bump github.com/golang/mock from 1.4.2 to 1.4.3 (#5816) Bumps [github.com/golang/mock](https://github.com/golang/mock) from 1.4.2 to 1.4.3. - [Release notes](https://github.com/golang/mock/releases) - [Changelog](https://github.com/golang/mock/blob/master/.goreleaser.yml) - [Commits](https://github.com/golang/mock/compare/v1.4.2...v1.4.3) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 746d86496d5e..9b7561d2dd53 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d github.com/cosmos/ledger-cosmos-go v0.11.1 github.com/gogo/protobuf v1.3.1 - github.com/golang/mock v1.4.2 + github.com/golang/mock v1.4.3 github.com/golang/protobuf v1.3.5 github.com/gorilla/handlers v1.4.2 github.com/gorilla/mux v1.7.4 diff --git a/go.sum b/go.sum index 6e482a1dd207..7e8f83f0a78b 100644 --- a/go.sum +++ b/go.sum @@ -132,6 +132,8 @@ github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4er github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.4.2 h1:fXIkPzOBCwDUPvYmOPzETABgbqpYlYNigQ2o64eMr5c= github.com/golang/mock v1.4.2/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3 h1:GV+pQPG/EUUbkh47niozDcADz6go/dUwhVzdUQHIVRw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -583,7 +585,9 @@ honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +rsc.io/quote/v3 v3.1.0 h1:9JKUTTIUgS6kzR9mK1YuGKv6Nl+DijDNIc0ghT58FaY= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= From e0280bf2d51a539500d59b66be5243b73a311b55 Mon Sep 17 00:00:00 2001 From: Gavin <13985253+gavinly@users.noreply.github.com> Date: Tue, 17 Mar 2020 11:30:24 -0400 Subject: [PATCH 428/529] Update 07_params.md --- x/distribution/spec/07_params.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/x/distribution/spec/07_params.md b/x/distribution/spec/07_params.md index 2bcefd0c3ffa..432a4e5a9695 100644 --- a/x/distribution/spec/07_params.md +++ b/x/distribution/spec/07_params.md @@ -13,6 +13,5 @@ The distribution module contains the following parameters: | bonusproposerreward | string (dec) | "0.040000000000000000" [1] | | withdrawaddrenabled | bool | true | -* [0] The value of `communitytax` must be positive and cannot exceed 1%. -* [1] The sum of `baseproposerreward` and `bonusproposerreward` cannot exceed 1%. -Both values must be positive. +* [0] The value of `communitytax` must be positive and cannot exceed 1.00. +* [1] `baseproposerreward` and `bonusproposerreward` must be positive and their sum cannot exceed 1.00. From a84e02f390c0c2e650c120940ce1d4f799f9f4d3 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Wed, 18 Mar 2020 11:33:28 +0100 Subject: [PATCH 429/529] crypto/keys/mintkey: fix errors handling in UnarmorPubKeyBytes (#5823) Check error returned by internal call to unarmorBytes() and handle accordingly. Handle header's empty version field adequately. --- CHANGELOG.md | 2 ++ crypto/keys/mintkey/mintkey.go | 6 ++++++ crypto/keys/mintkey/mintkey_test.go | 19 ++++++++++++++++++- 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 88549940f629..fa2958e11b18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -82,6 +82,8 @@ resulted in a panic when the tx execution mode was `CheckTx`. * (x/distribution) [\#5620](https://github.com/cosmos/cosmos-sdk/pull/5620) Fix nil pointer deref in distribution tax/rewward validation helpers. * (types) [\#5741](https://github.com/cosmos/cosmos-sdk/issues/5741) Prevent ChainAnteDecorators() from panicking when empty AnteDecorator slice is supplied. * (modules) [\#5569](https://github.com/cosmos/cosmos-sdk/issues/5569) `InitGenesis`, for the relevant modules, now ensures module accounts exist. +* (crypto/keys/mintkey) [\#5823](https://github.com/cosmos/cosmos-sdk/pull/5823) fix errors handling in UnarmorPubKeyBytes (underlying armoring function's +return error was not being checked). ### State Machine Breaking diff --git a/crypto/keys/mintkey/mintkey.go b/crypto/keys/mintkey/mintkey.go index 7ce836d68baf..184be9b35e94 100644 --- a/crypto/keys/mintkey/mintkey.go +++ b/crypto/keys/mintkey/mintkey.go @@ -83,6 +83,10 @@ func UnarmorInfoBytes(armorStr string) ([]byte, error) { // UnarmorPubKeyBytes returns the pubkey byte slice, a string of the algo type, and an error func UnarmorPubKeyBytes(armorStr string) (bz []byte, algo string, err error) { bz, header, err := unarmorBytes(armorStr, blockTypePubKey) + if err != nil { + return nil, "", fmt.Errorf("couldn't unarmor bytes: %v", err) + } + switch header[headerVersion] { case "0.0.0": return bz, defaultAlgo, err @@ -91,6 +95,8 @@ func UnarmorPubKeyBytes(armorStr string) (bz []byte, algo string, err error) { header[headerType] = defaultAlgo } return bz, header[headerType], err + case "": + return nil, "", fmt.Errorf("header's version field is empty") default: err = fmt.Errorf("unrecognized version: %v", header[headerVersion]) return nil, "", err diff --git a/crypto/keys/mintkey/mintkey_test.go b/crypto/keys/mintkey/mintkey_test.go index 79c158344dea..dd978c13ec2a 100644 --- a/crypto/keys/mintkey/mintkey_test.go +++ b/crypto/keys/mintkey/mintkey_test.go @@ -88,6 +88,11 @@ func TestArmorUnarmorPubKey(t *testing.T) { require.Equal(t, "unknown", algo) require.True(t, pub.Equals(info.GetPubKey())) + armored, err = cstore.ExportPrivKey("Bob", "passphrase", "alessio") + require.NoError(t, err) + _, _, err = mintkey.UnarmorPubKeyBytes(armored) + require.Equal(t, `couldn't unarmor bytes: unrecognized armor type "TENDERMINT PRIVATE KEY", expected: "TENDERMINT PUBLIC KEY"`, err.Error()) + // armor pubkey manually header := map[string]string{ "version": "0.0.0", @@ -108,7 +113,19 @@ func TestArmorUnarmorPubKey(t *testing.T) { require.Nil(t, bz) require.Empty(t, algo) require.Error(t, err) - require.Contains(t, err.Error(), "unrecognized version") + require.Equal(t, "header's version field is empty", err.Error()) + + // unknown version header + header = map[string]string{ + "type": "unknown", + "version": "unknown", + } + armored = armor.EncodeArmor("TENDERMINT PUBLIC KEY", header, pubBytes) + bz, algo, err = mintkey.UnarmorPubKeyBytes(armored) + require.Nil(t, bz) + require.Empty(t, algo) + require.Error(t, err) + require.Equal(t, "unrecognized version: unknown", err.Error()) } func TestArmorInfoBytes(t *testing.T) { From 3db39cda3c913176c526ef0abddfe6a7d479fc56 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Wed, 18 Mar 2020 13:59:08 +0100 Subject: [PATCH 430/529] Fix various linter warnings (#5824) --- client/input/input.go | 2 +- crypto/keys/keyring.go | 3 +-- crypto/keys/keyring_test.go | 4 ++-- crypto/keys/mintkey/mintkey_test.go | 3 ++- crypto/keys/types_test.go | 5 ++--- store/reexport.go | 5 ++--- types/module/module_test.go | 12 ++++++------ types/rest/rest_test.go | 9 ++++++--- types/staking_test.go | 8 ++++---- version/version_test.go | 4 ++-- x/auth/ante/basic.go | 3 +-- 11 files changed, 29 insertions(+), 29 deletions(-) diff --git a/client/input/input.go b/client/input/input.go index 95f32281edd5..73dd822fd369 100644 --- a/client/input/input.go +++ b/client/input/input.go @@ -66,7 +66,7 @@ func GetCheckPassword(prompt, prompt2 string, buf *bufio.Reader) (string, error) // If the input is not recognized, it returns false and a nil error. func GetConfirmation(prompt string, buf *bufio.Reader) (bool, error) { if inputIsTty() { - fmt.Print(fmt.Sprintf("%s [y/N]: ", prompt)) + fmt.Printf("%s [y/N]: ", prompt) } response, err := readLineFromBuf(buf) diff --git a/crypto/keys/keyring.go b/crypto/keys/keyring.go index 450b0d32bb42..0a76c96062d5 100644 --- a/crypto/keys/keyring.go +++ b/crypto/keys/keyring.go @@ -14,7 +14,6 @@ import ( "github.com/pkg/errors" "github.com/tendermint/crypto/bcrypt" - "github.com/tendermint/tendermint/crypto" tmcrypto "github.com/tendermint/tendermint/crypto" cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino" @@ -569,7 +568,7 @@ func newRealPrompt(dir string, buf io.Reader) func(string) (string, error) { continue } - saltBytes := crypto.CRandBytes(16) + saltBytes := tmcrypto.CRandBytes(16) passwordHash, err := bcrypt.GenerateFromPassword(saltBytes, []byte(pass), 2) if err != nil { fmt.Fprintln(os.Stderr, err) diff --git a/crypto/keys/keyring_test.go b/crypto/keys/keyring_test.go index dd179a0c12a3..f52140965790 100644 --- a/crypto/keys/keyring_test.go +++ b/crypto/keys/keyring_test.go @@ -408,6 +408,6 @@ func TestSupportedAlgos(t *testing.T) { t.Cleanup(cleanup) kb, err := NewKeyring("keybasename", "test", dir, nil) require.NoError(t, err) - require.Equal(t, []SigningAlgo([]SigningAlgo{"secp256k1"}), kb.SupportedAlgos()) - require.Equal(t, []SigningAlgo([]SigningAlgo{"secp256k1"}), kb.SupportedAlgosLedger()) + require.Equal(t, []SigningAlgo{"secp256k1"}, kb.SupportedAlgos()) + require.Equal(t, []SigningAlgo{"secp256k1"}, kb.SupportedAlgosLedger()) } diff --git a/crypto/keys/mintkey/mintkey_test.go b/crypto/keys/mintkey/mintkey_test.go index dd978c13ec2a..ffeea07c4f88 100644 --- a/crypto/keys/mintkey/mintkey_test.go +++ b/crypto/keys/mintkey/mintkey_test.go @@ -38,7 +38,7 @@ func TestArmorUnarmorPrivKey(t *testing.T) { // wrong key type armored = mintkey.ArmorPubKeyBytes(priv.PubKey().Bytes(), "") - decrypted, algo, err = mintkey.UnarmorDecryptPrivKey(armored, "passphrase") + _, _, err = mintkey.UnarmorDecryptPrivKey(armored, "passphrase") require.Error(t, err) require.Contains(t, err.Error(), "unrecognized armor type") @@ -91,6 +91,7 @@ func TestArmorUnarmorPubKey(t *testing.T) { armored, err = cstore.ExportPrivKey("Bob", "passphrase", "alessio") require.NoError(t, err) _, _, err = mintkey.UnarmorPubKeyBytes(armored) + require.Error(t, err) require.Equal(t, `couldn't unarmor bytes: unrecognized armor type "TENDERMINT PRIVATE KEY", expected: "TENDERMINT PUBLIC KEY"`, err.Error()) // armor pubkey manually diff --git a/crypto/keys/types_test.go b/crypto/keys/types_test.go index 1376c3bbb70f..3c18f4cf10ad 100644 --- a/crypto/keys/types_test.go +++ b/crypto/keys/types_test.go @@ -8,7 +8,6 @@ import ( "github.com/tendermint/tendermint/crypto/secp256k1" "github.com/cosmos/cosmos-sdk/crypto/keys/hd" - "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -17,7 +16,7 @@ func Test_writeReadLedgerInfo(t *testing.T) { bz, _ := hex.DecodeString("035AD6810A47F073553FF30D2FCC7E0D3B1C0B74B61A1AAA2582344037151E143A") copy(tmpKey[:], bz) - lInfo := newLedgerInfo("some_name", tmpKey, *hd.NewFundraiserParams(5, types.CoinType, 1), Secp256k1) + lInfo := newLedgerInfo("some_name", tmpKey, *hd.NewFundraiserParams(5, sdk.CoinType, 1), Secp256k1) assert.Equal(t, TypeLedger, lInfo.GetType()) path, err := lInfo.GetPath() @@ -25,7 +24,7 @@ func Test_writeReadLedgerInfo(t *testing.T) { assert.Equal(t, "44'/118'/5'/0/1", path.String()) assert.Equal(t, "cosmospub1addwnpepqddddqg2glc8x4fl7vxjlnr7p5a3czm5kcdp4239sg6yqdc4rc2r5wmxv8p", - types.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, lInfo.GetPubKey())) + sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, lInfo.GetPubKey())) // Serialize and restore serialized := marshalInfo(lInfo) diff --git a/store/reexport.go b/store/reexport.go index 913a8c55a8b3..9e4dba0ed5f6 100644 --- a/store/reexport.go +++ b/store/reexport.go @@ -2,7 +2,6 @@ package store import ( "github.com/cosmos/cosmos-sdk/store/types" - stypes "github.com/cosmos/cosmos-sdk/store/types" ) // Import cosmos-sdk/types/store.go for convenience. @@ -27,9 +26,9 @@ type ( StoreType = types.StoreType Queryable = types.Queryable TraceContext = types.TraceContext - Gas = stypes.Gas + Gas = types.Gas GasMeter = types.GasMeter - GasConfig = stypes.GasConfig + GasConfig = types.GasConfig ) // nolint - reexport diff --git a/types/module/module_test.go b/types/module/module_test.go index 65df4e8ea218..fa5b17ab35e0 100644 --- a/types/module/module_test.go +++ b/types/module/module_test.go @@ -179,8 +179,8 @@ func TestManager_InitGenesis(t *testing.T) { genesisData = map[string]json.RawMessage{ "module1": json.RawMessage(`{"key": "value"}`), "module2": json.RawMessage(`{"key": "value"}`)} - mockAppModule1.EXPECT().InitGenesis(gomock.Eq(ctx), gomock.Eq(cdc), gomock.Eq(genesisData["module1"])).Times(1).Return([]abci.ValidatorUpdate{abci.ValidatorUpdate{}}) - mockAppModule2.EXPECT().InitGenesis(gomock.Eq(ctx), gomock.Eq(cdc), gomock.Eq(genesisData["module2"])).Times(1).Return([]abci.ValidatorUpdate{abci.ValidatorUpdate{}}) + mockAppModule1.EXPECT().InitGenesis(gomock.Eq(ctx), gomock.Eq(cdc), gomock.Eq(genesisData["module1"])).Times(1).Return([]abci.ValidatorUpdate{{}}) + mockAppModule2.EXPECT().InitGenesis(gomock.Eq(ctx), gomock.Eq(cdc), gomock.Eq(genesisData["module2"])).Times(1).Return([]abci.ValidatorUpdate{{}}) require.Panics(t, func() { mm.InitGenesis(ctx, cdc, genesisData) }) } @@ -239,13 +239,13 @@ func TestManager_EndBlock(t *testing.T) { req := abci.RequestEndBlock{Height: 10} - mockAppModule1.EXPECT().EndBlock(gomock.Any(), gomock.Eq(req)).Times(1).Return([]abci.ValidatorUpdate{abci.ValidatorUpdate{}}) + mockAppModule1.EXPECT().EndBlock(gomock.Any(), gomock.Eq(req)).Times(1).Return([]abci.ValidatorUpdate{{}}) mockAppModule2.EXPECT().EndBlock(gomock.Any(), gomock.Eq(req)).Times(1) ret := mm.EndBlock(sdk.Context{}, req) - require.Equal(t, []abci.ValidatorUpdate{abci.ValidatorUpdate{}}, ret.ValidatorUpdates) + require.Equal(t, []abci.ValidatorUpdate{{}}, ret.ValidatorUpdates) // test panic - mockAppModule1.EXPECT().EndBlock(gomock.Any(), gomock.Eq(req)).Times(1).Return([]abci.ValidatorUpdate{abci.ValidatorUpdate{}}) - mockAppModule2.EXPECT().EndBlock(gomock.Any(), gomock.Eq(req)).Times(1).Return([]abci.ValidatorUpdate{abci.ValidatorUpdate{}}) + mockAppModule1.EXPECT().EndBlock(gomock.Any(), gomock.Eq(req)).Times(1).Return([]abci.ValidatorUpdate{{}}) + mockAppModule2.EXPECT().EndBlock(gomock.Any(), gomock.Eq(req)).Times(1).Return([]abci.ValidatorUpdate{{}}) require.Panics(t, func() { mm.EndBlock(sdk.Context{}, req) }) } diff --git a/types/rest/rest_test.go b/types/rest/rest_test.go index e760627b4d4a..db842696eeaf 100644 --- a/types/rest/rest_test.go +++ b/types/rest/rest_test.go @@ -235,8 +235,9 @@ func TestReadRESTReq(t *testing.T) { // test OK ReadRESTReq(w, req, codec.New(), &br) - require.Equal(t, BaseReq{ChainID: "alessio", Memo: "text"}, br) res := w.Result() + t.Cleanup(func() { res.Body.Close() }) + require.Equal(t, BaseReq{ChainID: "alessio", Memo: "text"}, br) require.Equal(t, http.StatusOK, res.StatusCode) // test non valid JSON @@ -247,6 +248,7 @@ func TestReadRESTReq(t *testing.T) { ReadRESTReq(w, req, codec.New(), &br) require.Equal(t, br, br) res = w.Result() + t.Cleanup(func() { res.Body.Close() }) require.Equal(t, http.StatusBadRequest, res.StatusCode) } @@ -255,6 +257,7 @@ func TestWriteSimulationResponse(t *testing.T) { w := httptest.NewRecorder() WriteSimulationResponse(w, codec.New(), 10) res := w.Result() + t.Cleanup(func() { res.Body.Close() }) require.Equal(t, http.StatusOK, res.StatusCode) bs, err := ioutil.ReadAll(res.Body) require.NoError(t, err) @@ -361,13 +364,13 @@ func TestPostProcessResponseBare(t *testing.T) { got, err = ioutil.ReadAll(res.Body) require.NoError(t, err) t.Cleanup(func() { res.Body.Close() }) - require.Equal(t, []string([]string{"application/json"}), res.Header["Content-Type"]) + require.Equal(t, []string{"application/json"}, res.Header["Content-Type"]) require.Equal(t, `{"error":"couldn't marshal"}`, string(got)) } type badJSONMarshaller struct{} -func (_ badJSONMarshaller) MarshalJSON() ([]byte, error) { +func (badJSONMarshaller) MarshalJSON() ([]byte, error) { return nil, errors.New("couldn't marshal") } diff --git a/types/staking_test.go b/types/staking_test.go index ddeab0d07036..34c165a67ff9 100644 --- a/types/staking_test.go +++ b/types/staking_test.go @@ -12,10 +12,10 @@ func TestBondStatus(t *testing.T) { require.False(t, sdk.Unbonded.Equal(sdk.Bonded)) require.False(t, sdk.Unbonded.Equal(sdk.Unbonding)) require.False(t, sdk.Bonded.Equal(sdk.Unbonding)) - require.Panicsf(t, func() { sdk.BondStatus(0).String() }, "invalid bond status") - require.Equal(t, sdk.BondStatusUnbonded, sdk.BondStatus(sdk.Unbonded).String()) - require.Equal(t, sdk.BondStatusBonded, sdk.BondStatus(sdk.Bonded).String()) - require.Equal(t, sdk.BondStatusUnbonding, sdk.BondStatus(sdk.Unbonding).String()) + require.Panicsf(t, func() { _ = sdk.BondStatus(0).String() }, "invalid bond status") + require.Equal(t, sdk.BondStatusUnbonded, sdk.Unbonded.String()) + require.Equal(t, sdk.BondStatusBonded, sdk.Bonded.String()) + require.Equal(t, sdk.BondStatusUnbonding, sdk.Unbonding.String()) } func TestTokensToConsensusPower(t *testing.T) { diff --git a/version/version_test.go b/version/version_test.go index d125b9946907..25616b5f3b9a 100644 --- a/version/version_test.go +++ b/version/version_test.go @@ -33,10 +33,10 @@ func TestInfo_String(t *testing.T) { BuildTags: "netgo,ledger", GoVersion: "go version go1.14 linux/amd64", } - want := fmt.Sprintf(`testapp: 1.0.0 + want := `testapp: 1.0.0 git commit: 1b78457135a4104bc3af97f20654d49e2ea87454 build tags: netgo,ledger -go version go1.14 linux/amd64`) +go version go1.14 linux/amd64` require.Equal(t, want, info.String()) } diff --git a/x/auth/ante/basic.go b/x/auth/ante/basic.go index f4a60a87e21e..57eceaea68f7 100644 --- a/x/auth/ante/basic.go +++ b/x/auth/ante/basic.go @@ -3,7 +3,6 @@ package ante import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - err "github.com/cosmos/cosmos-sdk/types/errors" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/tendermint/tendermint/crypto" @@ -68,7 +67,7 @@ func (vmd ValidateMemoDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate memoLength := len(memoTx.GetMemo()) if uint64(memoLength) > params.MaxMemoCharacters { - return ctx, err.Wrapf(err.ErrMemoTooLarge, + return ctx, sdkerrors.Wrapf(sdkerrors.ErrMemoTooLarge, "maximum number of characters is %d but received %d characters", params.MaxMemoCharacters, memoLength, ) From a5899bace022d251a7621d90b0640f4bdd2f3b18 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Wed, 18 Mar 2020 17:19:22 +0100 Subject: [PATCH 431/529] Remove CloseDB method from Keybase interface (#5820) * remove old method closeDb from Keybase interface * add changelog * move to api breaking changes Co-authored-by: Alexander Bezobchuk --- CHANGELOG.md | 1 + crypto/keys/keybase.go | 5 ----- crypto/keys/keyring.go | 3 --- crypto/keys/keyring_test.go | 2 -- crypto/keys/lazy_keybase.go | 2 -- crypto/keys/types.go | 3 --- 6 files changed, 1 insertion(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa2958e11b18..7945d661057c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -69,6 +69,7 @@ and provided directly the IAVL store. to now accept a `codec.JSONMarshaler` for modular serialization of genesis state. * (crypto/keys) [\#5735](https://github.com/cosmos/cosmos-sdk/pull/5735) Keyring's Update() function is now no-op. * (types/rest) [\#5779](https://github.com/cosmos/cosmos-sdk/pull/5779) Drop unused Parse{Int64OrReturnBadRequest,QueryParamBool}() functions. +* (keys) [\#5820](https://github.com/cosmos/cosmos-sdk/pull/5820/) Removed method CloseDB from Keybase interface. ### Features diff --git a/crypto/keys/keybase.go b/crypto/keys/keybase.go index b55c7b68b542..2d7e79710f5b 100644 --- a/crypto/keys/keybase.go +++ b/crypto/keys/keybase.go @@ -428,11 +428,6 @@ func (kb dbKeybase) Update(name, oldpass string, getNewpass func() (string, erro } } -// CloseDB releases the lock and closes the storage backend. -func (kb dbKeybase) CloseDB() { - kb.db.Close() -} - // SupportedAlgos returns a list of supported signing algorithms. func (kb dbKeybase) SupportedAlgos() []SigningAlgo { return kb.base.SupportedAlgos() diff --git a/crypto/keys/keyring.go b/crypto/keys/keyring.go index 0a76c96062d5..c67413987d6a 100644 --- a/crypto/keys/keyring.go +++ b/crypto/keys/keyring.go @@ -430,9 +430,6 @@ func (kb keyringKeybase) SupportedAlgosLedger() []SigningAlgo { return kb.base.SupportedAlgosLedger() } -// CloseDB releases the lock and closes the storage backend. -func (kb keyringKeybase) CloseDB() {} - func (kb keyringKeybase) writeLocalKey(name string, priv tmcrypto.PrivKey, _ string, algo SigningAlgo) Info { // encrypt private key using keyring pub := priv.PubKey() diff --git a/crypto/keys/keyring_test.go b/crypto/keys/keyring_test.go index f52140965790..afa726321de0 100644 --- a/crypto/keys/keyring_test.go +++ b/crypto/keys/keyring_test.go @@ -96,8 +96,6 @@ func TestLazyKeyManagementKeyRing(t *testing.T) { // addr cache gets nuked - and test skip flag require.NoError(t, kb.Delete(n2, "", true)) - - require.NotPanics(t, kb.CloseDB) } // TestSignVerify does some detailed checks on how we sign and validate diff --git a/crypto/keys/lazy_keybase.go b/crypto/keys/lazy_keybase.go index 2a92ecd304ce..3ee7e2c16b2b 100644 --- a/crypto/keys/lazy_keybase.go +++ b/crypto/keys/lazy_keybase.go @@ -219,5 +219,3 @@ func (lkb lazyKeybase) SupportedAlgos() []SigningAlgo { func (lkb lazyKeybase) SupportedAlgosLedger() []SigningAlgo { return newBaseKeybase(lkb.options...).SupportedAlgosLedger() } - -func (lkb lazyKeybase) CloseDB() {} diff --git a/crypto/keys/types.go b/crypto/keys/types.go index 89f5cb2d539b..5149d1c582a0 100644 --- a/crypto/keys/types.go +++ b/crypto/keys/types.go @@ -80,9 +80,6 @@ type Keybase interface { // SupportedAlgosLedger returns a list of signing algorithms supported by the keybase's ledger integration SupportedAlgosLedger() []SigningAlgo - - // CloseDB closes the database. - CloseDB() } // KeyType reflects a human-readable type for key listing. From b47e4096fc362a9e62a3890b7120466a3de794c0 Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Wed, 18 Mar 2020 22:27:01 +0500 Subject: [PATCH 432/529] Use docs-staging branch (#5797) Co-authored-by: Alexander Bezobchuk --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 15b9578e28df..635bf9b0a94a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -230,7 +230,7 @@ workflows: filters: branches: only: - - docs-theme-latest + - docs-staging - build-docs: context: docs-deployment-release filters: From 8c7bb895493314405064d5ac71f0d8df7f9e8f17 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Thu, 19 Mar 2020 02:49:33 +0100 Subject: [PATCH 433/529] Implementing --offline flag (#5810) Closes: #5448 --- CHANGELOG.md | 4 ++ client/context/context.go | 7 ++- client/context/context_test.go | 68 +++++++++++++++++++++++++++++ client/context/query.go | 2 +- client/flags/flags.go | 4 +- x/auth/client/cli/broadcast.go | 6 +++ x/auth/client/cli/broadcast_test.go | 45 +++++++++++++++++++ x/auth/client/cli/tx_multisign.go | 3 +- x/auth/client/cli/tx_sign.go | 16 ++----- x/auth/client/tx.go | 4 +- x/distribution/client/cli/tx.go | 4 +- 11 files changed, 141 insertions(+), 22 deletions(-) create mode 100644 client/context/context_test.go create mode 100644 x/auth/client/cli/broadcast_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 7945d661057c..1b505678d5ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -169,6 +169,10 @@ Buffers for state serialization instead of Amino. * (server) [\#5709](https://github.com/cosmos/cosmos-sdk/pull/5709) There are two new flags for pruning, `--pruning-keep-every` and `--pruning-snapshot-every` as an alternative to `--pruning`. They allow to fine tune the strategy for pruning the state. * (crypto/keys) [\#5739](https://github.com/cosmos/cosmos-sdk/pull/5739) Print an error message if the password input failed. +* (client) [\#5810](https://github.com/cosmos/cosmos-sdk/pull/5810) Added a new `--offline` flag that allows commands to +be executed without an internet connection. Previously, `--generate-only` served this purpose in addition to only allowing +txs to be generated. Now, `--generate-only` solely allows txs to be generated without being broadcasted and disallows +Keybase use and `--offline` allows the use of Keybase but does not allow any functionality that requires an online connection. ## [v0.38.1] - 2020-02-11 diff --git a/client/context/context.go b/client/context/context.go index ae0576122602..80813b7655cd 100644 --- a/client/context/context.go +++ b/client/context/context.go @@ -43,6 +43,7 @@ type CLIContext struct { UseLedger bool Simulate bool GenerateOnly bool + Offline bool Indent bool SkipConfirm bool @@ -67,7 +68,8 @@ func NewCLIContextWithInputAndFrom(input io.Reader, from string) CLIContext { os.Exit(1) } - if !genOnly { + offline := viper.GetBool(flags.FlagOffline) + if !offline { nodeURI = viper.GetString(flags.FlagNode) if nodeURI != "" { rpc, err = rpcclient.NewHTTP(nodeURI, "/websocket") @@ -93,6 +95,7 @@ func NewCLIContextWithInputAndFrom(input io.Reader, from string) CLIContext { BroadcastMode: viper.GetString(flags.FlagBroadcastMode), Simulate: viper.GetBool(flags.FlagDryRun), GenerateOnly: genOnly, + Offline: offline, FromAddress: fromAddress, FromName: fromName, Indent: viper.GetBool(flags.FlagIndentResponse), @@ -286,7 +289,7 @@ func GetFromFields(input io.Reader, from string, genOnly bool) (sdk.AccAddress, if genOnly { addr, err := sdk.AccAddressFromBech32(from) if err != nil { - return nil, "", errors.Wrap(err, "must provide a valid Bech32 address for generate-only") + return nil, "", errors.Wrap(err, "must provide a valid Bech32 address in generate-only mode") } return addr, "", nil diff --git a/client/context/context_test.go b/client/context/context_test.go new file mode 100644 index 000000000000..3b6ea0e71af5 --- /dev/null +++ b/client/context/context_test.go @@ -0,0 +1,68 @@ +package context + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/spf13/viper" + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/client/flags" +) + +func TestCLIContext_WithOffline(t *testing.T) { + viper.Set(flags.FlagOffline, true) + viper.Set(flags.FlagNode, "tcp://localhost:26657") + + ctx := NewCLIContext() + require.True(t, ctx.Offline) + require.Nil(t, ctx.Client) + + viper.Reset() + + viper.Set(flags.FlagOffline, false) + viper.Set(flags.FlagNode, "tcp://localhost:26657") + + ctx = NewCLIContext() + require.False(t, ctx.Offline) + require.NotNil(t, ctx.Client) +} + +func TestCLIContext_WithGenOnly(t *testing.T) { + viper.Set(flags.FlagGenerateOnly, true) + + validFromAddr := "cosmos1q7380u26f7ntke3facjmynajs4umlr329vr4ja" + fromAddr, err := sdk.AccAddressFromBech32(validFromAddr) + require.NoError(t, err) + + tests := []struct { + name string + from string + expectedFromAddr sdk.AccAddress + expectedFromName string + }{ + { + name: "valid from", + from: validFromAddr, + expectedFromAddr: fromAddr, + expectedFromName: "", + }, + { + name: "empty from", + from: "", + expectedFromAddr: nil, + expectedFromName: "", + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + ctx := NewCLIContextWithFrom(tt.from) + + require.Equal(t, tt.expectedFromAddr, ctx.FromAddress) + require.Equal(t, tt.expectedFromName, ctx.FromName) + }) + } +} diff --git a/client/context/query.go b/client/context/query.go index cfe08969f285..4d335c85d512 100644 --- a/client/context/query.go +++ b/client/context/query.go @@ -22,7 +22,7 @@ import ( // error is returned. func (ctx CLIContext) GetNode() (rpcclient.Client, error) { if ctx.Client == nil { - return nil, errors.New("no RPC client defined") + return nil, errors.New("no RPC client is defined in offline mode") } return ctx.Client, nil diff --git a/client/flags/flags.go b/client/flags/flags.go index 746b512b0697..d331a44bbcb6 100644 --- a/client/flags/flags.go +++ b/client/flags/flags.go @@ -57,6 +57,7 @@ const ( FlagBroadcastMode = "broadcast-mode" FlagDryRun = "dry-run" FlagGenerateOnly = "generate-only" + FlagOffline = "offline" FlagIndentResponse = "indent" FlagListenAddr = "laddr" FlagMaxOpenConnections = "max-open" @@ -114,7 +115,8 @@ func PostCommands(cmds ...*cobra.Command) []*cobra.Command { c.Flags().StringP(FlagBroadcastMode, "b", BroadcastSync, "Transaction broadcasting mode (sync|async|block)") c.Flags().Bool(FlagTrustNode, true, "Trust connected full node (don't verify proofs for responses)") c.Flags().Bool(FlagDryRun, false, "ignore the --gas flag and perform a simulation of a transaction, but don't broadcast it") - c.Flags().Bool(FlagGenerateOnly, false, "Build an unsigned transaction and write it to STDOUT (when enabled, the local Keybase is not accessible and the node operates offline)") + c.Flags().Bool(FlagGenerateOnly, false, "Build an unsigned transaction and write it to STDOUT (when enabled, the local Keybase is not accessible)") + c.Flags().Bool(FlagOffline, false, "Offline mode (does not allow any online functionality") c.Flags().BoolP(FlagSkipConfirmation, "y", false, "Skip tx broadcasting prompt confirmation") c.Flags().String(FlagKeyringBackend, DefaultKeyringBackend, "Select keyring's backend (os|file|test)") diff --git a/x/auth/client/cli/broadcast.go b/x/auth/client/cli/broadcast.go index 288b7c7de911..5f1e4757d1d7 100644 --- a/x/auth/client/cli/broadcast.go +++ b/x/auth/client/cli/broadcast.go @@ -1,6 +1,7 @@ package cli import ( + "errors" "strings" "github.com/spf13/cobra" @@ -26,6 +27,11 @@ $ tx broadcast ./mytxn.json Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) (err error) { cliCtx := context.NewCLIContext().WithCodec(cdc) + + if cliCtx.Offline { + return errors.New("cannot broadcast tx during offline mode") + } + stdTx, err := client.ReadStdTxFromFile(cliCtx.Codec, args[0]) if err != nil { return diff --git a/x/auth/client/cli/broadcast_test.go b/x/auth/client/cli/broadcast_test.go new file mode 100644 index 000000000000..d75a0b0c8908 --- /dev/null +++ b/x/auth/client/cli/broadcast_test.go @@ -0,0 +1,45 @@ +package cli + +import ( + "io/ioutil" + "path/filepath" + "testing" + + "github.com/spf13/viper" + "github.com/stretchr/testify/require" + "github.com/tendermint/go-amino" + + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/tests" +) + +func TestGetBroadcastCommand_OfflineFlag(t *testing.T) { + codec := amino.NewCodec() + cmd := GetBroadcastCommand(codec) + + viper.Set(flags.FlagOffline, true) + + err := cmd.RunE(nil, []string{}) + require.EqualError(t, err, "cannot broadcast tx during offline mode") +} + +func TestGetBroadcastCommand_WithoutOfflineFlag(t *testing.T) { + codec := amino.NewCodec() + cmd := GetBroadcastCommand(codec) + + viper.Set(flags.FlagOffline, false) + + testDir, cleanFunc := tests.NewTestCaseDir(t) + t.Cleanup(cleanFunc) + + // Create new file with tx + txContents := []byte("{\"type\":\"cosmos-sdk/StdTx\",\"value\":{\"msg\":[{\"type\":\"cosmos-sdk/MsgSend\",\"value\":{\"from_address\":\"cosmos1cxlt8kznps92fwu3j6npahx4mjfutydyene2qw\",\"to_address\":\"cosmos1wc8mpr8m3sy3ap3j7fsgqfzx36um05pystems4\",\"amount\":[{\"denom\":\"stake\",\"amount\":\"10000\"}]}}],\"fee\":{\"amount\":[],\"gas\":\"200000\"},\"signatures\":null,\"memo\":\"\"}}") + txFileName := filepath.Join(testDir, "tx.json") + err := ioutil.WriteFile(txFileName, txContents, 0644) + require.NoError(t, err) + + err = cmd.RunE(cmd, []string{txFileName}) + + // We test it tries to broadcast but we set unsupported tx to get the error. + require.EqualError(t, err, "unsupported return type ; supported types: sync, async, block") +} diff --git a/x/auth/client/cli/tx_multisign.go b/x/auth/client/cli/tx_multisign.go index f5bf16ca279e..6018ce2a7a4f 100644 --- a/x/auth/client/cli/tx_multisign.go +++ b/x/auth/client/cli/tx_multisign.go @@ -51,7 +51,6 @@ recommended to set such parameters manually. } cmd.Flags().Bool(flagSigOnly, false, "Print only the generated signature, then exit") - cmd.Flags().Bool(flagOffline, false, "Offline mode. Do not query a full node") cmd.Flags().String(flagOutfile, "", "The document will be written to the given file instead of STDOUT") // Add the flags here and return the command @@ -85,7 +84,7 @@ func makeMultiSignCmd(cdc *codec.Codec) func(cmd *cobra.Command, args []string) cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) txBldr := types.NewTxBuilderFromCLI(inBuf) - if !viper.GetBool(flagOffline) { + if !cliCtx.Offline { accnum, seq, err := types.NewAccountRetriever(client.Codec, cliCtx).GetAccountNumberSequence(multisigInfo.GetAddress()) if err != nil { return err diff --git a/x/auth/client/cli/tx_sign.go b/x/auth/client/cli/tx_sign.go index 6d95c47ef4ce..62100b02335f 100644 --- a/x/auth/client/cli/tx_sign.go +++ b/x/auth/client/cli/tx_sign.go @@ -22,7 +22,6 @@ const ( flagMultisig = "multisig" flagAppend = "append" flagValidateSigs = "validate-signatures" - flagOffline = "offline" flagSigOnly = "signature-only" flagOutfile = "output-document" ) @@ -71,12 +70,7 @@ be generated via the 'multisign' command. "Print the addresses that must sign the transaction, those who have already signed it, and make sure that signatures are in the correct order", ) cmd.Flags().Bool(flagSigOnly, false, "Print only the generated signature, then exit") - cmd.Flags().Bool( - flagOffline, false, - "Offline mode; Do not query a full node. --account and --sequence options would be required if offline is set", - ) cmd.Flags().String(flagOutfile, "", "The document will be written to the given file instead of STDOUT") - cmd = flags.PostCommands(cmd)[0] cmd.MarkFlagRequired(flags.FlagFrom) @@ -86,7 +80,7 @@ be generated via the 'multisign' command. func preSignCmd(cmd *cobra.Command, _ []string) { // Conditionally mark the account and sequence numbers required as no RPC // query will be done. - if viper.GetBool(flagOffline) { + if viper.GetBool(flags.FlagOffline) { cmd.MarkFlagRequired(flags.FlagAccountNumber) cmd.MarkFlagRequired(flags.FlagSequence) } @@ -100,12 +94,11 @@ func makeSignCmd(cdc *codec.Codec) func(cmd *cobra.Command, args []string) error } inBuf := bufio.NewReader(cmd.InOrStdin()) - offline := viper.GetBool(flagOffline) cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) txBldr := types.NewTxBuilderFromCLI(inBuf) if viper.GetBool(flagValidateSigs) { - if !printAndValidateSigs(cliCtx, txBldr.ChainID(), stdTx, offline) { + if !printAndValidateSigs(cliCtx, txBldr.ChainID(), stdTx, cliCtx.Offline) { return fmt.Errorf("signatures validation failed") } @@ -124,14 +117,13 @@ func makeSignCmd(cdc *codec.Codec) func(cmd *cobra.Command, args []string) error if err != nil { return err } - newTx, err = client.SignStdTxWithSignerAddress( - txBldr, cliCtx, multisigAddr, cliCtx.GetFromName(), stdTx, offline, + txBldr, cliCtx, multisigAddr, cliCtx.GetFromName(), stdTx, cliCtx.Offline, ) generateSignatureOnly = true } else { appendSig := viper.GetBool(flagAppend) && !generateSignatureOnly - newTx, err = client.SignStdTx(txBldr, cliCtx, cliCtx.GetFromName(), stdTx, appendSig, offline) + newTx, err = client.SignStdTx(txBldr, cliCtx, cliCtx.GetFromName(), stdTx, appendSig, cliCtx.Offline) } if err != nil { diff --git a/x/auth/client/tx.go b/x/auth/client/tx.go index d9212bed5fbe..9036d7444d9f 100644 --- a/x/auth/client/tx.go +++ b/x/auth/client/tx.go @@ -327,8 +327,8 @@ func PrepareTxBuilder(txBldr authtypes.TxBuilder, cliCtx context.CLIContext) (au func buildUnsignedStdTxOffline(txBldr authtypes.TxBuilder, cliCtx context.CLIContext, msgs []sdk.Msg) (stdTx authtypes.StdTx, err error) { if txBldr.SimulateAndExecute() { - if cliCtx.GenerateOnly { - return stdTx, errors.New("cannot estimate gas with generate-only") + if cliCtx.Offline { + return stdTx, errors.New("cannot estimate gas in offline mode") } txBldr, err = EnrichWithGas(txBldr, cliCtx, msgs) diff --git a/x/distribution/client/cli/tx.go b/x/distribution/client/cli/tx.go index 35d12391d057..892058f6b38b 100644 --- a/x/distribution/client/cli/tx.go +++ b/x/distribution/client/cli/tx.go @@ -150,8 +150,8 @@ $ %s tx distribution withdraw-all-rewards --from mykey // The transaction cannot be generated offline since it requires a query // to get all the validators. - if cliCtx.GenerateOnly { - return fmt.Errorf("command disabled with the provided flag: %s", flags.FlagGenerateOnly) + if cliCtx.Offline { + return fmt.Errorf("cannot generate tx in offline mode") } msgs, err := common.WithdrawAllDelegatorRewards(cliCtx, queryRoute, delAddr) From e042b351027eac411284894e187e28d4b142733f Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 19 Mar 2020 06:31:39 +0000 Subject: [PATCH 434/529] Bump github.com/tendermint/iavl from 0.13.1 to 0.13.2 Bumps [github.com/tendermint/iavl](https://github.com/tendermint/iavl) from 0.13.1 to 0.13.2. - [Release notes](https://github.com/tendermint/iavl/releases) - [Changelog](https://github.com/tendermint/iavl/blob/master/CHANGELOG.md) - [Commits](https://github.com/tendermint/iavl/compare/v0.13.1...v0.13.2) Signed-off-by: dependabot-preview[bot] --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 76a69ba2ed39..8780987da431 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,7 @@ require ( github.com/tendermint/btcd v0.1.1 github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 github.com/tendermint/go-amino v0.15.1 - github.com/tendermint/iavl v0.13.1 + github.com/tendermint/iavl v0.13.2 github.com/tendermint/tendermint v0.33.2 github.com/tendermint/tm-db v0.5.0 google.golang.org/protobuf v1.20.1 // indirect diff --git a/go.sum b/go.sum index 83bf29675b26..27c01d225f4c 100644 --- a/go.sum +++ b/go.sum @@ -416,6 +416,8 @@ github.com/tendermint/go-amino v0.15.1 h1:D2uk35eT4iTsvJd9jWIetzthE5C0/k2QmMFkCN github.com/tendermint/go-amino v0.15.1/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= github.com/tendermint/iavl v0.13.1 h1:KWg3NVqOZLJFCLKpUJjUprdWAgIYdC9GDJLN8PBmKbI= github.com/tendermint/iavl v0.13.1/go.mod h1:vE1u0XAGXYjHykd4BLp8p/yivrw2PF1TuoljBcsQoGA= +github.com/tendermint/iavl v0.13.2 h1:O1m08/Ciy53l9IYmf75uIRVvrNsfjEbre8u/yCu/oqk= +github.com/tendermint/iavl v0.13.2/go.mod h1:vE1u0XAGXYjHykd4BLp8p/yivrw2PF1TuoljBcsQoGA= github.com/tendermint/tendermint v0.33.2 h1:NzvRMTuXJxqSsFed2J7uHmMU5N1CVzSpfi3nCc882KY= github.com/tendermint/tendermint v0.33.2/go.mod h1:25DqB7YvV1tN3tHsjWoc2vFtlwICfrub9XO6UBO+4xk= github.com/tendermint/tm-db v0.4.1/go.mod h1:JsJ6qzYkCGiGwm5GHl/H5GLI9XLb6qZX7PRe425dHAY= From 230a1e8ba3840471a8c0c48f0f918560ae1abfc6 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Thu, 19 Mar 2020 17:58:14 +0100 Subject: [PATCH 435/529] crypto/keys: improve documentation (#5833) * crypto/keys: improve documentation Remove out of date crypto/keys README.md file. Populate client keys commands help screen with more information regarding keyring backends. * Fix formatting * Fix lint warning --- client/flags/flags.go | 2 +- client/keys/root.go | 27 +++++++++++++++++++----- crypto/keys/README.md | 47 ------------------------------------------ crypto/keys/doc.go | 45 ++++++++++++++++++++++++++++++++++++++++ crypto/keys/keyring.go | 2 +- 5 files changed, 69 insertions(+), 54 deletions(-) delete mode 100644 crypto/keys/README.md create mode 100644 crypto/keys/doc.go diff --git a/client/flags/flags.go b/client/flags/flags.go index d331a44bbcb6..b4c501d99ccf 100644 --- a/client/flags/flags.go +++ b/client/flags/flags.go @@ -118,7 +118,7 @@ func PostCommands(cmds ...*cobra.Command) []*cobra.Command { c.Flags().Bool(FlagGenerateOnly, false, "Build an unsigned transaction and write it to STDOUT (when enabled, the local Keybase is not accessible)") c.Flags().Bool(FlagOffline, false, "Offline mode (does not allow any online functionality") c.Flags().BoolP(FlagSkipConfirmation, "y", false, "Skip tx broadcasting prompt confirmation") - c.Flags().String(FlagKeyringBackend, DefaultKeyringBackend, "Select keyring's backend (os|file|test)") + c.Flags().String(FlagKeyringBackend, DefaultKeyringBackend, "Select keyring's backend (os|file|kwallet|pass|test)") // --gas can accept integers and "simulate" c.Flags().Var(&GasFlagVar, "gas", fmt.Sprintf( diff --git a/client/keys/root.go b/client/keys/root.go index b7f70059c015..d3df8e046868 100644 --- a/client/keys/root.go +++ b/client/keys/root.go @@ -12,12 +12,29 @@ import ( func Commands() *cobra.Command { cmd := &cobra.Command{ Use: "keys", - Short: "Add or view local private keys", - Long: `Keys allows you to manage your local keystore for tendermint. + Short: "Manage your application's keys", + Long: `Keyring management commands. These keys may be in any format supported by the +Tendermint crypto library and can be used by light-clients, full nodes, or any other application +that needs to sign with a private key. - These keys may be in any format supported by go-crypto and can be - used by light-clients, full nodes, or any other application that - needs to sign with a private key.`, +The keyring supports the following backends: + + os Uses the operating system's default credentials store. + file Uses encrypted file-based keystore within the app's configuration directory. + This keyring will request a password each time it is accessed, which may occur + multiple times in a single command resulting in repeated password prompts. + kwallet Uses KDE Wallet Manager as a credentials management application. + pass Uses the pass command line utility to store and retrieve keys. + test Stores keys insecurely to disk. It does not prompt for a password to be unlocked + and it should be use only for testing purposes. + +kwallet and pass backends depend on external tools. Refer to their respective documentation for more +information: + KWallet https://github.com/KDE/kwallet + pass https://www.passwordstore.org/ + +The pass backend requires GnuPG: https://gnupg.org/ +`, } cmd.AddCommand( MnemonicKeyCommand(), diff --git a/crypto/keys/README.md b/crypto/keys/README.md deleted file mode 100644 index df690636bc2a..000000000000 --- a/crypto/keys/README.md +++ /dev/null @@ -1,47 +0,0 @@ -# Keys API - -[![API Reference](https://godoc.org/github.com/cosmos/cosmos-sdk/crypto/keys?status.svg)](https://godoc.org/github.com/cosmos/cosmos-sdk/crypto/keys) - - -## The Keybase interface - -The [Keybase](https://godoc.org/github.com/cosmos/cosmos-sdk/crypto/keys#Keybase) interface defines -the methods that a type needs to implement to be used as key storage backend. This package provides -few implementations out-of-the-box. - -## Constructors - -### New - -The [New](https://godoc.org/github.com/cosmos/cosmos-sdk/crypto/keys#New) constructor returns -an on-disk implementation backed by LevelDB storage that has been the default implementation used by the SDK until v0.38.0. -Due to [security concerns](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-006-secret-store-replacement.md), we recommend to drop -it in favor of the `NewKeyring` or `NewKeyringFile` constructors. We strongly advise to migrate away from this function as **it may be removed in a future -release**. - -### NewInMemory - -The [NewInMemory](https://godoc.org/github.com/cosmos/cosmos-sdk/crypto/keys#NewInMemory) constructor returns -an implementation backed by an in-memory, goroutine-safe map that we've historically used for testing purposes or on-the-fly -key generation and we consider safe for the aforementioned use cases since the generated keys are discarded when the process -terminates or the type instance is garbage collected. - -### NewKeyring - -The [NewKeyring](https://godoc.org/github.com/cosmos/cosmos-sdk/crypto/keys#NewKeyring) constructor returns -an implementation backed by the [Keyring](https://github.com/99designs/keyring) library, whose aim is to provide a common -abstraction and uniform interface between secret stores available for Windows, macOS, and most GNU/Linux distributions. -The instance returned by this constructor will use the operating system's default credentials store, which will then handle -keys storage operations securely. - -### NewKeyringFile, NewTestKeyring - -Both [NewKeyringFile](https://godoc.org/github.com/cosmos/cosmos-sdk/crypto/keys#NewKeyringFile) and -[NewTestKeyring](https://godoc.org/github.com/cosmos/cosmos-sdk/crypto/keys#NewTestKeyring) constructors return -on-disk implementations backed by the [Keyring](https://github.com/99designs/keyring) `file` backend. -Whilst `NewKeyringFile` returns a secure, encrypted file-based type that requires user's password in order to -function correctly, the implementation returned by `NewTestKeyring` stores keys information in clear text and **must be used -only for testing purposes**. - -`NewKeyringFile` and `NewTestKeyring` store key files in the client home directory's `keyring` -and `keyring-test` subdirectories respectively. diff --git a/crypto/keys/doc.go b/crypto/keys/doc.go new file mode 100644 index 000000000000..30a086941810 --- /dev/null +++ b/crypto/keys/doc.go @@ -0,0 +1,45 @@ +// Package keys provides common key management API. +// +// +// The Keybase interface +// +// The Keybase interface defines the methods that a type needs to implement to be used +// as key storage backend. This package provides few implementations out-of-the-box. +// +// New +// +// The New constructor returns an on-disk implementation backed by LevelDB storage that has been +// the default implementation used by the SDK until v0.38.0. Due to security concerns, it is +// recommended to drop it in favor of the NewKeyring or NewKeyringFile constructors as it will be +// removed in future releases. +// +// NewInMemory +// +// The NewInMemory constructor returns an implementation backed by an in-memory, goroutine-safe +// map that has historically been used for testing purposes or on-the-fly key generation as the +// generated keys are discarded when the process terminates or the type instance is garbage +// collected. +// +// NewKeyring +// +// The NewKeyring constructor returns an implementation backed by a keyring library +// (https://github.com/99designs/keyring), whose aim is to provide a common abstraction and uniform +// interface between secret stores available for Windows, macOS, and most GNU/Linux distributions +// as well as operating system-agnostic encrypted file-based backends. +// +// The backends: +// os The instance returned by this constructor uses the operating system's default +// credentials store to handle keys storage operations securely. It should be noted +// that the keyring keyring may be kept unlocked for the whole duration of the user +// session. +// file This backend more closely resembles the previous keyring storage used prior to +// v0.38.1. It stores the keyring encrypted within the apps configuration directory. +// This keyring will request a password each time it is accessed, which may occur +// multiple times in a single command resulting in repeated password prompts. +// kwallet This backend uses KDE Wallet Manager as a credentials management application: +// https://github.com/KDE/kwallet +// pass This backend uses the pass command line utility to store and retrieve keys: +// https://www.passwordstore.org/ +// test This backend stores keys insecurely to disk. It does not prompt for a password to +// be unlocked and it should be use only for testing purposes. +package keys diff --git a/crypto/keys/keyring.go b/crypto/keys/keyring.go index c67413987d6a..726b44e781f2 100644 --- a/crypto/keys/keyring.go +++ b/crypto/keys/keyring.go @@ -56,7 +56,7 @@ func newKeyringKeybase(db keyring.Keyring, opts ...KeybaseOption) Keybase { // NewKeyring creates a new instance of a keyring. Keybase // options can be applied when generating this new Keybase. -// Available backends are "os", "file", "test". +// Available backends are "os", "file", "kwallet", "pass", "test". func NewKeyring( appName, backend, rootDir string, userInput io.Reader, opts ...KeybaseOption, ) (Keybase, error) { From eeea5ebf89d3101e38cb67ac4688407e2ef97fe0 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Thu, 19 Mar 2020 20:03:49 -0300 Subject: [PATCH 436/529] baseapp: add sdk.Result to simulation response --- CHANGELOG.md | 2 ++ baseapp/abci.go | 12 ++++++++++-- baseapp/baseapp_test.go | 9 ++++++--- types/result.go | 9 ++++++++- 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b505678d5ad..4f008aaec1d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -70,6 +70,8 @@ to now accept a `codec.JSONMarshaler` for modular serialization of genesis state * (crypto/keys) [\#5735](https://github.com/cosmos/cosmos-sdk/pull/5735) Keyring's Update() function is now no-op. * (types/rest) [\#5779](https://github.com/cosmos/cosmos-sdk/pull/5779) Drop unused Parse{Int64OrReturnBadRequest,QueryParamBool}() functions. * (keys) [\#5820](https://github.com/cosmos/cosmos-sdk/pull/5820/) Removed method CloseDB from Keybase interface. +* (baseapp) [\#5837](https://github.com/cosmos/cosmos-sdk/issues/5837) Transaction simulation now returns a `SimulationResponse` which contains the `GasInfo` and +`Result` from the execution. ### Features diff --git a/baseapp/abci.go b/baseapp/abci.go index 834930196df5..e984fe0edf24 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -326,12 +326,20 @@ func handleQueryApp(app *BaseApp, path []string, req abci.RequestQuery) abci.Res return sdkerrors.QueryResult(sdkerrors.Wrap(err, "failed to decode tx")) } - gInfo, _, _ := app.Simulate(txBytes, tx) + gInfo, res, err := app.Simulate(txBytes, tx) + if err != nil { + return sdkerrors.QueryResult(sdkerrors.Wrap(err, "failed to simulate tx")) + } + + simRes := sdk.SimulationResponse{ + GasInfo: gInfo, + Result: res, + } return abci.ResponseQuery{ Codespace: sdkerrors.RootCodespace, Height: req.Height, - Value: codec.Cdc.MustMarshalBinaryBare(gInfo.GasUsed), + Value: codec.Cdc.MustMarshalBinaryBare(simRes), } case "version": diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index 2350ba64ceeb..2da5b95f6f00 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -935,10 +935,13 @@ func TestSimulateTx(t *testing.T) { queryResult := app.Query(query) require.True(t, queryResult.IsOK(), queryResult.Log) - var res uint64 - err = codec.Cdc.UnmarshalBinaryBare(queryResult.Value, &res) + var simRes sdk.SimulationResponse + err = codec.Cdc.UnmarshalBinaryBare(queryResult.Value, &simRes) require.NoError(t, err) - require.Equal(t, gasConsumed, res) + require.Equal(t, gInfo, simRes.GasInfo) + require.Equal(t, result.Log, simRes.Result.Log) + require.Equal(t, result.Events, simRes.Result.Events) + require.True(t, bytes.Equal(result.Data, simRes.Result.Data)) app.EndBlock(abci.RequestEndBlock{}) app.Commit() } diff --git a/types/result.go b/types/result.go index 9530be01d25c..54cc0e05330b 100644 --- a/types/result.go +++ b/types/result.go @@ -17,7 +17,7 @@ type GasInfo struct { // GasWanted is the maximum units of work we allow this tx to perform. GasWanted uint64 - // GasUsed is the amount of gas actually consumed. NOTE: unimplemented + // GasUsed is the amount of gas actually consumed. GasUsed uint64 } @@ -35,6 +35,13 @@ type Result struct { Events Events } +// SimulationResponse defines the response generated when a transaction is successfully +// simulated by the Baseapp. +type SimulationResponse struct { + GasInfo + Result *Result +} + // ABCIMessageLogs represents a slice of ABCIMessageLog. type ABCIMessageLogs []ABCIMessageLog From 3d2746434f04903c6b539769fbc25626fd72dad7 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Thu, 19 Mar 2020 22:40:07 -0300 Subject: [PATCH 437/529] authclient: update txBuilder to return sdk.SimulationResponse --- x/auth/client/tx.go | 33 ++++++++++++++------------- x/auth/client/tx_test.go | 48 ++++++++++++++++++++++++++-------------- 2 files changed, 47 insertions(+), 34 deletions(-) diff --git a/x/auth/client/tx.go b/x/auth/client/tx.go index 9036d7444d9f..3bd61a8e11fe 100644 --- a/x/auth/client/tx.go +++ b/x/auth/client/tx.go @@ -129,26 +129,26 @@ func EnrichWithGas(txBldr authtypes.TxBuilder, cliCtx context.CLIContext, msgs [ } // CalculateGas simulates the execution of a transaction and returns -// both the estimate obtained by the query and the adjusted amount. +// the simulation response obtained by the query and the adjusted amount. func CalculateGas( queryFunc func(string, []byte) ([]byte, int64, error), cdc *codec.Codec, txBytes []byte, adjustment float64, -) (estimate, adjusted uint64, err error) { +) (sdk.SimulationResponse, uint64, error) { // run a simulation (via /app/simulate query) to // estimate gas and update TxBuilder accordingly rawRes, _, err := queryFunc("/app/simulate", txBytes) if err != nil { - return estimate, adjusted, err + return sdk.SimulationResponse{}, 0, err } - estimate, err = parseQueryResponse(cdc, rawRes) + simRes, err := parseQueryResponse(cdc, rawRes) if err != nil { - return + return sdk.SimulationResponse{}, 0, err } - adjusted = adjustGasEstimate(estimate, adjustment) - return estimate, adjusted, nil + adjusted := adjustGasEstimate(simRes.GasUsed, adjustment) + return simRes, adjusted, nil } // PrintUnsignedStdTx builds an unsigned StdTx and prints it to os.Stdout. @@ -272,28 +272,27 @@ func GetTxEncoder(cdc *codec.Codec) (encoder sdk.TxEncoder) { } // nolint -// SimulateMsgs simulates the transaction and returns the gas estimate and the adjusted value. -func simulateMsgs(txBldr authtypes.TxBuilder, cliCtx context.CLIContext, msgs []sdk.Msg) (estimated, adjusted uint64, err error) { +// SimulateMsgs simulates the transaction and returns the simulation response and the adjusted value. +func simulateMsgs(txBldr authtypes.TxBuilder, cliCtx context.CLIContext, msgs []sdk.Msg) (sdk.SimulationResponse, uint64, error) { txBytes, err := txBldr.BuildTxForSim(msgs) if err != nil { - return + return sdk.SimulationResponse{}, 0, err } - estimated, adjusted, err = CalculateGas(cliCtx.QueryWithData, cliCtx.Codec, txBytes, txBldr.GasAdjustment()) - return + return CalculateGas(cliCtx.QueryWithData, cliCtx.Codec, txBytes, txBldr.GasAdjustment()) } func adjustGasEstimate(estimate uint64, adjustment float64) uint64 { return uint64(adjustment * float64(estimate)) } -func parseQueryResponse(cdc *codec.Codec, rawRes []byte) (uint64, error) { - var gasUsed uint64 - if err := cdc.UnmarshalBinaryBare(rawRes, &gasUsed); err != nil { - return 0, err +func parseQueryResponse(cdc *codec.Codec, rawRes []byte) (sdk.SimulationResponse, error) { + var simRes sdk.SimulationResponse + if err := cdc.UnmarshalBinaryBare(rawRes, &simRes); err != nil { + return sdk.SimulationResponse{}, err } - return gasUsed, nil + return simRes, nil } // PrepareTxBuilder populates a TxBuilder in preparation for the build of a Tx. diff --git a/x/auth/client/tx_test.go b/x/auth/client/tx_test.go index 643f253a21f8..682868555b5b 100644 --- a/x/auth/client/tx_test.go +++ b/x/auth/client/tx_test.go @@ -7,8 +7,8 @@ import ( "os" "testing" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/crypto/ed25519" "github.com/cosmos/cosmos-sdk/codec" @@ -23,13 +23,18 @@ var ( func TestParseQueryResponse(t *testing.T) { cdc := makeCodec() - sdkResBytes := cdc.MustMarshalBinaryBare(uint64(10)) - gas, err := parseQueryResponse(cdc, sdkResBytes) - assert.Equal(t, gas, uint64(10)) - assert.Nil(t, err) - gas, err = parseQueryResponse(cdc, []byte("fuzzy")) - assert.Equal(t, gas, uint64(0)) - assert.Error(t, err) + simRes := sdk.SimulationResponse{ + GasInfo: sdk.GasInfo{GasUsed: 10, GasWanted: 20}, + Result: nil, + } + + bz := cdc.MustMarshalBinaryBare(simRes) + res, err := parseQueryResponse(cdc, bz) + require.NoError(t, err) + require.Equal(t, 10, int(res.GasInfo.GasUsed)) + + res, err = parseQueryResponse(cdc, []byte("fuzzy")) + require.Error(t, err) } func TestCalculateGas(t *testing.T) { @@ -37,9 +42,14 @@ func TestCalculateGas(t *testing.T) { makeQueryFunc := func(gasUsed uint64, wantErr bool) func(string, []byte) ([]byte, int64, error) { return func(string, []byte) ([]byte, int64, error) { if wantErr { - return nil, 0, errors.New("") + return nil, 0, errors.New("query failed") + } + simRes := sdk.SimulationResponse{ + GasInfo: sdk.GasInfo{GasUsed: gasUsed, GasWanted: gasUsed}, + Result: nil, } - return cdc.MustMarshalBinaryBare(gasUsed), 0, nil + + return cdc.MustMarshalBinaryBare(simRes), 0, nil } } @@ -54,20 +64,24 @@ func TestCalculateGas(t *testing.T) { args args wantEstimate uint64 wantAdjusted uint64 - wantErr bool + expPass bool }{ - {"error", args{0, true, 1.2}, 0, 0, true}, - {"adjusted gas", args{10, false, 1.2}, 10, 12, false}, + {"error", args{0, true, 1.2}, 0, 0, false}, + {"adjusted gas", args{10, false, 1.2}, 10, 12, true}, } for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { queryFunc := makeQueryFunc(tt.args.queryFuncGasUsed, tt.args.queryFuncWantErr) - gotEstimate, gotAdjusted, err := CalculateGas(queryFunc, cdc, []byte(""), tt.args.adjustment) - assert.Equal(t, err != nil, tt.wantErr) - assert.Equal(t, gotEstimate, tt.wantEstimate) - assert.Equal(t, gotAdjusted, tt.wantAdjusted) + simRes, gotAdjusted, err := CalculateGas(queryFunc, cdc, []byte(""), tt.args.adjustment) + if tt.expPass { + require.NoError(t, err) + } else { + require.Error(t, err) + require.Equal(t, simRes.GasInfo.GasUsed, tt.wantEstimate) + require.Equal(t, gotAdjusted, tt.wantAdjusted) + } }) } } From 38f4b084c1c0187d4d957cb452b67a41a6b224f0 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Thu, 19 Mar 2020 22:42:34 -0300 Subject: [PATCH 438/529] authclient: update godoc for gas adjusted --- x/auth/client/tx.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x/auth/client/tx.go b/x/auth/client/tx.go index 3bd61a8e11fe..09f3146e7cdf 100644 --- a/x/auth/client/tx.go +++ b/x/auth/client/tx.go @@ -129,7 +129,7 @@ func EnrichWithGas(txBldr authtypes.TxBuilder, cliCtx context.CLIContext, msgs [ } // CalculateGas simulates the execution of a transaction and returns -// the simulation response obtained by the query and the adjusted amount. +// the simulation response obtained by the query and the adjusted gas amount. func CalculateGas( queryFunc func(string, []byte) ([]byte, int64, error), cdc *codec.Codec, txBytes []byte, adjustment float64, @@ -271,8 +271,8 @@ func GetTxEncoder(cdc *codec.Codec) (encoder sdk.TxEncoder) { return encoder } -// nolint -// SimulateMsgs simulates the transaction and returns the simulation response and the adjusted value. +// simulateMsgs simulates the transaction and returns the simulation response and +// the adjusted gas value. func simulateMsgs(txBldr authtypes.TxBuilder, cliCtx context.CLIContext, msgs []sdk.Msg) (sdk.SimulationResponse, uint64, error) { txBytes, err := txBldr.BuildTxForSim(msgs) if err != nil { From 51d90451524403d0a6bb8fd2c3df775e7a6253ce Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Thu, 19 Mar 2020 22:46:35 -0300 Subject: [PATCH 439/529] authclient: fix tests --- x/auth/client/tx_test.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/x/auth/client/tx_test.go b/x/auth/client/tx_test.go index 682868555b5b..29d49a71738e 100644 --- a/x/auth/client/tx_test.go +++ b/x/auth/client/tx_test.go @@ -46,7 +46,7 @@ func TestCalculateGas(t *testing.T) { } simRes := sdk.SimulationResponse{ GasInfo: sdk.GasInfo{GasUsed: gasUsed, GasWanted: gasUsed}, - Result: nil, + Result: &sdk.Result{Data: []byte("tx data"), Log: "log"}, } return cdc.MustMarshalBinaryBare(simRes), 0, nil @@ -77,10 +77,12 @@ func TestCalculateGas(t *testing.T) { simRes, gotAdjusted, err := CalculateGas(queryFunc, cdc, []byte(""), tt.args.adjustment) if tt.expPass { require.NoError(t, err) - } else { - require.Error(t, err) require.Equal(t, simRes.GasInfo.GasUsed, tt.wantEstimate) require.Equal(t, gotAdjusted, tt.wantAdjusted) + require.NotNil(t, simRes.Result) + } else { + require.Error(t, err) + require.Nil(t, simRes.Result) } }) } From 2cf816d4575be1e2adcc6834dcd65b85e2903a59 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Thu, 19 Mar 2020 22:48:20 -0300 Subject: [PATCH 440/529] minor test change --- x/auth/client/tx_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x/auth/client/tx_test.go b/x/auth/client/tx_test.go index 29d49a71738e..22e9586d76e6 100644 --- a/x/auth/client/tx_test.go +++ b/x/auth/client/tx_test.go @@ -25,13 +25,14 @@ func TestParseQueryResponse(t *testing.T) { cdc := makeCodec() simRes := sdk.SimulationResponse{ GasInfo: sdk.GasInfo{GasUsed: 10, GasWanted: 20}, - Result: nil, + Result: &sdk.Result{Data: []byte("tx data"), Log: "log"}, } bz := cdc.MustMarshalBinaryBare(simRes) res, err := parseQueryResponse(cdc, bz) require.NoError(t, err) require.Equal(t, 10, int(res.GasInfo.GasUsed)) + require.NotNil(t, res.Result) res, err = parseQueryResponse(cdc, []byte("fuzzy")) require.Error(t, err) From 75a375b6c6b9f97a444aab24aa2d77c1df9bc964 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Fri, 20 Mar 2020 16:00:12 +0100 Subject: [PATCH 441/529] crypto/keys: remove DecodeSignature from baseKeybase (#5844) Keybase implementations should return errors when signature generation is attempted with offline/multisig keys since theyr lack private keys. This is a change in Keyring/Keybase.Sign() methods semantics that have been broken for long time. --- CHANGELOG.md | 3 +++ crypto/keys/keybase.go | 2 +- crypto/keys/keybase_base.go | 31 ------------------------------- crypto/keys/keybase_test.go | 5 ++--- crypto/keys/keyring.go | 2 +- crypto/keys/keyring_test.go | 3 ++- 6 files changed, 9 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f008aaec1d9..18f1b0f79ceb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,7 @@ are now replaced by human-readable expressions. This change can potentially brea that parse log messages. * (client) [\#5799](https://github.com/cosmos/cosmos-sdk/pull/5799) The `tx encode/decode` commands, due to change on encoding break compatibility with older clients. +* (x/auth) [\#5844](https://github.com/cosmos/cosmos-sdk/pull/5844) `tx sign` command now returns an error when signing is attempted with offline/multisig keys. ### API Breaking Changes @@ -87,6 +88,8 @@ resulted in a panic when the tx execution mode was `CheckTx`. * (modules) [\#5569](https://github.com/cosmos/cosmos-sdk/issues/5569) `InitGenesis`, for the relevant modules, now ensures module accounts exist. * (crypto/keys/mintkey) [\#5823](https://github.com/cosmos/cosmos-sdk/pull/5823) fix errors handling in UnarmorPubKeyBytes (underlying armoring function's return error was not being checked). +* (crypto/keys) [\#5844](https://github.com/cosmos/cosmos-sdk/pull/5844) Keybase/Keyring `Sign()` methods no longer decode amino signatures +when method receivers are offline/multisig keys. ### State Machine Breaking diff --git a/crypto/keys/keybase.go b/crypto/keys/keybase.go index 2d7e79710f5b..c273e288b765 100644 --- a/crypto/keys/keybase.go +++ b/crypto/keys/keybase.go @@ -215,7 +215,7 @@ func (kb dbKeybase) Sign(name, passphrase string, msg []byte) (sig []byte, pub t return SignWithLedger(info, msg) case offlineInfo, multiInfo: - return kb.base.DecodeSignature(info, msg) + return nil, info.GetPubKey(), errors.New("cannot sign with offline keys") } sig, err = priv.Sign(msg) diff --git a/crypto/keys/keybase_base.go b/crypto/keys/keybase_base.go index 47c7e60d729a..2947949e273b 100644 --- a/crypto/keys/keybase_base.go +++ b/crypto/keys/keybase_base.go @@ -1,10 +1,6 @@ package keys import ( - "bufio" - "fmt" - "os" - "github.com/cosmos/go-bip39" "github.com/pkg/errors" tmcrypto "github.com/tendermint/tendermint/crypto" @@ -104,33 +100,6 @@ func SecpPrivKeyGen(bz []byte) tmcrypto.PrivKey { return secp256k1.PrivKeySecp256k1(bzArr) } -// DecodeSignature decodes a an length-prefixed binary signature from standard input -// and return it as a byte slice. -func (kb baseKeybase) DecodeSignature(info Info, msg []byte) (sig []byte, pub tmcrypto.PubKey, err error) { - _, err = fmt.Fprintf(os.Stderr, "Message to sign:\n\n%s\n", msg) - if err != nil { - return nil, nil, err - } - - buf := bufio.NewReader(os.Stdin) - _, err = fmt.Fprintf(os.Stderr, "\nEnter Amino-encoded signature:\n") - if err != nil { - return nil, nil, err - } - - // will block until user inputs the signature - signed, err := buf.ReadString('\n') - if err != nil { - return nil, nil, err - } - - if err := CryptoCdc.UnmarshalBinaryLengthPrefixed([]byte(signed), sig); err != nil { - return nil, nil, errors.Wrap(err, "failed to decode signature") - } - - return sig, info.GetPubKey(), nil -} - // CreateAccount creates an account Info object. func (kb baseKeybase) CreateAccount( keyWriter keyWriter, name, mnemonic, bip39Passphrase, encryptPasswd, hdPath string, algo SigningAlgo, diff --git a/crypto/keys/keybase_test.go b/crypto/keys/keybase_test.go index cbd212a755db..a669a83deba2 100644 --- a/crypto/keys/keybase_test.go +++ b/crypto/keys/keybase_test.go @@ -2,9 +2,7 @@ package keys import ( - "errors" "fmt" - "io" "testing" "github.com/stretchr/testify/assert" @@ -280,7 +278,8 @@ func TestSignVerify(t *testing.T) { // Now try to sign data with a secret-less key _, _, err = cstore.Sign(n3, p3, d3) - require.True(t, errors.Is(io.EOF, err)) + require.Error(t, err) + require.Equal(t, "cannot sign with offline keys", err.Error()) } func assertPassword(t *testing.T, cstore Keybase, name, pass, badpass string) { diff --git a/crypto/keys/keyring.go b/crypto/keys/keyring.go index 726b44e781f2..e664b1d2d13b 100644 --- a/crypto/keys/keyring.go +++ b/crypto/keys/keyring.go @@ -219,7 +219,7 @@ func (kb keyringKeybase) Sign(name, passphrase string, msg []byte) (sig []byte, return SignWithLedger(info, msg) case offlineInfo, multiInfo: - return kb.base.DecodeSignature(info, msg) + return nil, info.GetPubKey(), errors.New("cannot sign with offline keys") } sig, err = priv.Sign(msg) diff --git a/crypto/keys/keyring_test.go b/crypto/keys/keyring_test.go index afa726321de0..0415236be971 100644 --- a/crypto/keys/keyring_test.go +++ b/crypto/keys/keyring_test.go @@ -208,7 +208,8 @@ func TestLazySignVerifyKeyRing(t *testing.T) { // Now try to sign data with a secret-less key _, _, err = kb.Sign(n3, p3, d3) - require.NotNil(t, err) + require.Error(t, err) + require.Equal(t, "cannot sign with offline keys", err.Error()) } func TestLazyExportImportKeyRing(t *testing.T) { From 1d0967c32a76f33574748355541d8c7238d09983 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Fri, 20 Mar 2020 18:14:14 +0100 Subject: [PATCH 442/529] run go mod tidy && make format (#5847) --- go.sum | 2 -- server/pruning.go | 3 ++- store/transient/store_test.go | 3 ++- tests/mocks/account_retriever.go | 3 ++- tests/mocks/tendermint_tm_db_DB.go | 3 ++- tests/mocks/types_handler.go | 6 ++++-- tests/mocks/types_invariant.go | 6 ++++-- tests/mocks/types_module_module.go | 10 ++++++---- tests/mocks/types_router.go | 6 ++++-- x/distribution/keeper/delegation_test.go | 3 ++- x/distribution/keeper/querier_test.go | 5 +++-- x/distribution/module_test.go | 5 +++-- x/distribution/proposal_handler_test.go | 3 ++- x/slashing/abci_test.go | 5 +++-- x/slashing/keeper/test_common.go | 3 ++- x/staking/keeper/keeper_test.go | 3 ++- x/staking/keeper/slash_test.go | 3 ++- 17 files changed, 45 insertions(+), 27 deletions(-) diff --git a/go.sum b/go.sum index 27c01d225f4c..620da8f5397f 100644 --- a/go.sum +++ b/go.sum @@ -414,8 +414,6 @@ github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15/go.mod h1:z4YtwM github.com/tendermint/go-amino v0.14.1/go.mod h1:i/UKE5Uocn+argJJBb12qTZsCDBcAYMbR92AaJVmKso= github.com/tendermint/go-amino v0.15.1 h1:D2uk35eT4iTsvJd9jWIetzthE5C0/k2QmMFkCN+4JgQ= github.com/tendermint/go-amino v0.15.1/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= -github.com/tendermint/iavl v0.13.1 h1:KWg3NVqOZLJFCLKpUJjUprdWAgIYdC9GDJLN8PBmKbI= -github.com/tendermint/iavl v0.13.1/go.mod h1:vE1u0XAGXYjHykd4BLp8p/yivrw2PF1TuoljBcsQoGA= github.com/tendermint/iavl v0.13.2 h1:O1m08/Ciy53l9IYmf75uIRVvrNsfjEbre8u/yCu/oqk= github.com/tendermint/iavl v0.13.2/go.mod h1:vE1u0XAGXYjHykd4BLp8p/yivrw2PF1TuoljBcsQoGA= github.com/tendermint/tendermint v0.33.2 h1:NzvRMTuXJxqSsFed2J7uHmMU5N1CVzSpfi3nCc882KY= diff --git a/server/pruning.go b/server/pruning.go index 07730f36ad8a..712ed2a34c37 100644 --- a/server/pruning.go +++ b/server/pruning.go @@ -1,8 +1,9 @@ package server import ( - "github.com/cosmos/cosmos-sdk/store" "github.com/spf13/viper" + + "github.com/cosmos/cosmos-sdk/store" ) // GetPruningOptionsFromFlags parses start command flags and returns the correct PruningOptions. diff --git a/store/transient/store_test.go b/store/transient/store_test.go index 113d95be867b..632b561b618a 100644 --- a/store/transient/store_test.go +++ b/store/transient/store_test.go @@ -4,9 +4,10 @@ import ( "bytes" "testing" + "github.com/stretchr/testify/require" + "github.com/cosmos/cosmos-sdk/store/transient" "github.com/cosmos/cosmos-sdk/store/types" - "github.com/stretchr/testify/require" ) var k, v = []byte("hello"), []byte("world") diff --git a/tests/mocks/account_retriever.go b/tests/mocks/account_retriever.go index a3086c77bdca..5fa7807c8f69 100644 --- a/tests/mocks/account_retriever.go +++ b/tests/mocks/account_retriever.go @@ -5,8 +5,9 @@ package mocks import ( - gomock "github.com/golang/mock/gomock" reflect "reflect" + + gomock "github.com/golang/mock/gomock" ) // MockNodeQuerier is a mock of NodeQuerier interface diff --git a/tests/mocks/tendermint_tm_db_DB.go b/tests/mocks/tendermint_tm_db_DB.go index bed59a498d03..ccfc26909b71 100644 --- a/tests/mocks/tendermint_tm_db_DB.go +++ b/tests/mocks/tendermint_tm_db_DB.go @@ -5,9 +5,10 @@ package mocks import ( + reflect "reflect" + gomock "github.com/golang/mock/gomock" tm_db "github.com/tendermint/tm-db" - reflect "reflect" ) // MockDB is a mock of DB interface diff --git a/tests/mocks/types_handler.go b/tests/mocks/types_handler.go index da80614ae884..c16f5d595301 100644 --- a/tests/mocks/types_handler.go +++ b/tests/mocks/types_handler.go @@ -5,9 +5,11 @@ package mocks import ( - types "github.com/cosmos/cosmos-sdk/types" - gomock "github.com/golang/mock/gomock" reflect "reflect" + + gomock "github.com/golang/mock/gomock" + + types "github.com/cosmos/cosmos-sdk/types" ) // MockAnteDecorator is a mock of AnteDecorator interface diff --git a/tests/mocks/types_invariant.go b/tests/mocks/types_invariant.go index 325b108b20bb..974099c52b4d 100644 --- a/tests/mocks/types_invariant.go +++ b/tests/mocks/types_invariant.go @@ -5,9 +5,11 @@ package mocks import ( - types "github.com/cosmos/cosmos-sdk/types" - gomock "github.com/golang/mock/gomock" reflect "reflect" + + gomock "github.com/golang/mock/gomock" + + types "github.com/cosmos/cosmos-sdk/types" ) // MockInvariantRegistry is a mock of InvariantRegistry interface diff --git a/tests/mocks/types_module_module.go b/tests/mocks/types_module_module.go index 274ac5c0636b..94fcc2384e41 100644 --- a/tests/mocks/types_module_module.go +++ b/tests/mocks/types_module_module.go @@ -6,14 +6,16 @@ package mocks import ( json "encoding/json" - context "github.com/cosmos/cosmos-sdk/client/context" - codec "github.com/cosmos/cosmos-sdk/codec" - types "github.com/cosmos/cosmos-sdk/types" + reflect "reflect" + gomock "github.com/golang/mock/gomock" mux "github.com/gorilla/mux" cobra "github.com/spf13/cobra" types0 "github.com/tendermint/tendermint/abci/types" - reflect "reflect" + + context "github.com/cosmos/cosmos-sdk/client/context" + codec "github.com/cosmos/cosmos-sdk/codec" + types "github.com/cosmos/cosmos-sdk/types" ) // MockAppModuleBasic is a mock of AppModuleBasic interface diff --git a/tests/mocks/types_router.go b/tests/mocks/types_router.go index 924d95146eda..5a73d5c909d2 100644 --- a/tests/mocks/types_router.go +++ b/tests/mocks/types_router.go @@ -5,9 +5,11 @@ package mocks import ( - types "github.com/cosmos/cosmos-sdk/types" - gomock "github.com/golang/mock/gomock" reflect "reflect" + + gomock "github.com/golang/mock/gomock" + + types "github.com/cosmos/cosmos-sdk/types" ) // MockRouter is a mock of Router interface diff --git a/x/distribution/keeper/delegation_test.go b/x/distribution/keeper/delegation_test.go index 149a14913203..44b2bf71f918 100644 --- a/x/distribution/keeper/delegation_test.go +++ b/x/distribution/keeper/delegation_test.go @@ -5,10 +5,11 @@ import ( abci "github.com/tendermint/tendermint/abci/types" + "github.com/stretchr/testify/require" + "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/staking" - "github.com/stretchr/testify/require" ) func TestCalculateRewardsBasic(t *testing.T) { diff --git a/x/distribution/keeper/querier_test.go b/x/distribution/keeper/querier_test.go index 307084b28d02..c07a6b29e471 100644 --- a/x/distribution/keeper/querier_test.go +++ b/x/distribution/keeper/querier_test.go @@ -4,6 +4,9 @@ import ( "strings" "testing" + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" @@ -11,8 +14,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/distribution/types" "github.com/cosmos/cosmos-sdk/x/staking" "github.com/cosmos/cosmos-sdk/x/supply" - "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" ) const custom = "custom" diff --git a/x/distribution/module_test.go b/x/distribution/module_test.go index 83bf1b0ef67e..2fe6cb58a884 100644 --- a/x/distribution/module_test.go +++ b/x/distribution/module_test.go @@ -5,10 +5,11 @@ import ( "github.com/cosmos/cosmos-sdk/x/distribution" - "github.com/cosmos/cosmos-sdk/simapp" - "github.com/cosmos/cosmos-sdk/x/supply" "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/simapp" + "github.com/cosmos/cosmos-sdk/x/supply" ) func TestItCreatesModuleAccountOnInitBlock(t *testing.T) { diff --git a/x/distribution/proposal_handler_test.go b/x/distribution/proposal_handler_test.go index 158c275a9989..0fcb9c843e05 100644 --- a/x/distribution/proposal_handler_test.go +++ b/x/distribution/proposal_handler_test.go @@ -5,9 +5,10 @@ import ( "github.com/cosmos/cosmos-sdk/x/distribution" - "github.com/cosmos/cosmos-sdk/simapp" abci "github.com/tendermint/tendermint/abci/types" + "github.com/cosmos/cosmos-sdk/simapp" + "github.com/tendermint/tendermint/crypto/ed25519" "github.com/stretchr/testify/require" diff --git a/x/slashing/abci_test.go b/x/slashing/abci_test.go index cd9efc5537f8..fcff517deba9 100644 --- a/x/slashing/abci_test.go +++ b/x/slashing/abci_test.go @@ -4,13 +4,14 @@ import ( "testing" "time" + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/slashing" slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" "github.com/cosmos/cosmos-sdk/x/staking" - "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" ) func TestBeginBlocker(t *testing.T) { diff --git a/x/slashing/keeper/test_common.go b/x/slashing/keeper/test_common.go index 20eb8eda643f..d65fda6bc6a1 100644 --- a/x/slashing/keeper/test_common.go +++ b/x/slashing/keeper/test_common.go @@ -5,10 +5,11 @@ package keeper // noalias import ( + "github.com/tendermint/tendermint/crypto" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/slashing/types" "github.com/cosmos/cosmos-sdk/x/staking" - "github.com/tendermint/tendermint/crypto" ) // TODO remove dependencies on staking (should only refer to validator set type from sdk) diff --git a/x/staking/keeper/keeper_test.go b/x/staking/keeper/keeper_test.go index 8b59555e6554..10fd2253b716 100644 --- a/x/staking/keeper/keeper_test.go +++ b/x/staking/keeper/keeper_test.go @@ -5,9 +5,10 @@ import ( "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/cosmos/cosmos-sdk/simapp" "github.com/cosmos/cosmos-sdk/x/staking/types" - abci "github.com/tendermint/tendermint/abci/types" ) func TestParams(t *testing.T) { diff --git a/x/staking/keeper/slash_test.go b/x/staking/keeper/slash_test.go index e333967a8cf7..b5ea1b8195d2 100644 --- a/x/staking/keeper/slash_test.go +++ b/x/staking/keeper/slash_test.go @@ -10,11 +10,12 @@ import ( abci "github.com/tendermint/tendermint/abci/types" + "github.com/stretchr/testify/require" + "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/staking/keeper" "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/stretchr/testify/require" ) // bootstrapSlashTest creates 3 validators and bootstrap the app. From 22f377a858c2df857ebe370057dbcc22dc43c04c Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Fri, 20 Mar 2020 19:14:53 +0100 Subject: [PATCH 443/529] regenerate mocks, don't format autogenered files on make format (#5848) --- Makefile | 6 +++--- tests/mocks/account_retriever.go | 3 +-- tests/mocks/tendermint_tm_db_DB.go | 3 +-- tests/mocks/types_handler.go | 6 ++---- tests/mocks/types_invariant.go | 6 ++---- tests/mocks/types_module_module.go | 10 ++++------ tests/mocks/types_router.go | 6 ++---- 7 files changed, 15 insertions(+), 25 deletions(-) diff --git a/Makefile b/Makefile index 56eb4fa458ea..25ef7ea375b1 100644 --- a/Makefile +++ b/Makefile @@ -197,9 +197,9 @@ lint: .PHONY: lint format: - find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" -not -path "./client/lcd/statik/statik.go" -not -name '*.pb.go' | xargs gofmt -w -s - find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" -not -path "./client/lcd/statik/statik.go" -not -name '*.pb.go' | xargs misspell -w - find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" -not -path "./client/lcd/statik/statik.go" -not -name '*.pb.go' | xargs goimports -w -local github.com/cosmos/cosmos-sdk + find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" -not -path "./client/lcd/statik/statik.go" -not -path "./tests/mocks/*" -not -name '*.pb.go' | xargs gofmt -w -s + find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" -not -path "./client/lcd/statik/statik.go" -not -path "./tests/mocks/*" -not -name '*.pb.go' | xargs misspell -w + find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" -not -path "./client/lcd/statik/statik.go" -not -path "./tests/mocks/*" -not -name '*.pb.go' | xargs goimports -w -local github.com/cosmos/cosmos-sdk .PHONY: format ############################################################################### diff --git a/tests/mocks/account_retriever.go b/tests/mocks/account_retriever.go index 5fa7807c8f69..a3086c77bdca 100644 --- a/tests/mocks/account_retriever.go +++ b/tests/mocks/account_retriever.go @@ -5,9 +5,8 @@ package mocks import ( - reflect "reflect" - gomock "github.com/golang/mock/gomock" + reflect "reflect" ) // MockNodeQuerier is a mock of NodeQuerier interface diff --git a/tests/mocks/tendermint_tm_db_DB.go b/tests/mocks/tendermint_tm_db_DB.go index ccfc26909b71..bed59a498d03 100644 --- a/tests/mocks/tendermint_tm_db_DB.go +++ b/tests/mocks/tendermint_tm_db_DB.go @@ -5,10 +5,9 @@ package mocks import ( - reflect "reflect" - gomock "github.com/golang/mock/gomock" tm_db "github.com/tendermint/tm-db" + reflect "reflect" ) // MockDB is a mock of DB interface diff --git a/tests/mocks/types_handler.go b/tests/mocks/types_handler.go index c16f5d595301..da80614ae884 100644 --- a/tests/mocks/types_handler.go +++ b/tests/mocks/types_handler.go @@ -5,11 +5,9 @@ package mocks import ( - reflect "reflect" - - gomock "github.com/golang/mock/gomock" - types "github.com/cosmos/cosmos-sdk/types" + gomock "github.com/golang/mock/gomock" + reflect "reflect" ) // MockAnteDecorator is a mock of AnteDecorator interface diff --git a/tests/mocks/types_invariant.go b/tests/mocks/types_invariant.go index 974099c52b4d..325b108b20bb 100644 --- a/tests/mocks/types_invariant.go +++ b/tests/mocks/types_invariant.go @@ -5,11 +5,9 @@ package mocks import ( - reflect "reflect" - - gomock "github.com/golang/mock/gomock" - types "github.com/cosmos/cosmos-sdk/types" + gomock "github.com/golang/mock/gomock" + reflect "reflect" ) // MockInvariantRegistry is a mock of InvariantRegistry interface diff --git a/tests/mocks/types_module_module.go b/tests/mocks/types_module_module.go index 94fcc2384e41..274ac5c0636b 100644 --- a/tests/mocks/types_module_module.go +++ b/tests/mocks/types_module_module.go @@ -6,16 +6,14 @@ package mocks import ( json "encoding/json" - reflect "reflect" - + context "github.com/cosmos/cosmos-sdk/client/context" + codec "github.com/cosmos/cosmos-sdk/codec" + types "github.com/cosmos/cosmos-sdk/types" gomock "github.com/golang/mock/gomock" mux "github.com/gorilla/mux" cobra "github.com/spf13/cobra" types0 "github.com/tendermint/tendermint/abci/types" - - context "github.com/cosmos/cosmos-sdk/client/context" - codec "github.com/cosmos/cosmos-sdk/codec" - types "github.com/cosmos/cosmos-sdk/types" + reflect "reflect" ) // MockAppModuleBasic is a mock of AppModuleBasic interface diff --git a/tests/mocks/types_router.go b/tests/mocks/types_router.go index 5a73d5c909d2..924d95146eda 100644 --- a/tests/mocks/types_router.go +++ b/tests/mocks/types_router.go @@ -5,11 +5,9 @@ package mocks import ( - reflect "reflect" - - gomock "github.com/golang/mock/gomock" - types "github.com/cosmos/cosmos-sdk/types" + gomock "github.com/golang/mock/gomock" + reflect "reflect" ) // MockRouter is a mock of Router interface From d6575137414caf80c140814b7386c269fd106605 Mon Sep 17 00:00:00 2001 From: Marko Date: Fri, 20 Mar 2020 20:24:18 +0100 Subject: [PATCH 444/529] lint: various linting fixs (#5825) * lint: various linting fixs Signed-off-by: Marko Baricevic * more linting * more linting fixes * more errchecking * comment out errcheck for now * undo error check * address some comments * remore require error * change delete to batch delete Co-authored-by: Alexander Bezobchuk --- .golangci.yml | 1 + client/keys/add_test.go | 4 +- client/keys/delete_test.go | 4 +- client/keys/export_test.go | 2 +- client/keys/import_test.go | 2 +- client/keys/list_test.go | 3 +- crypto/keys/keybase.go | 12 +++-- crypto/keys/keybase_test.go | 3 +- crypto/keys/keyring_test.go | 3 +- crypto/keys/lazy_keybase_test.go | 3 +- store/cachekv/store_test.go | 62 +++++++++++++----------- store/iavl/tree_test.go | 4 +- store/prefix/store_test.go | 6 ++- store/rootmulti/proof_test.go | 10 ++-- store/rootmulti/store.go | 5 +- types/context_test.go | 9 ++-- types/decimal_test.go | 3 +- types/handler_test.go | 2 +- types/staking_test.go | 2 +- x/auth/ante/ante_test.go | 27 +++++++---- x/auth/ante/setup_test.go | 2 +- x/auth/ante/sigverify_test.go | 3 +- x/auth/client/cli/broadcast.go | 12 +++-- x/auth/keeper/keeper_test.go | 9 ++-- x/auth/types/genesis_test.go | 3 +- x/bank/app_test.go | 26 +++++++--- x/bank/bench_test.go | 6 ++- x/bank/genesis.go | 4 +- x/bank/keeper/keeper.go | 15 ++++-- x/crisis/handler_test.go | 2 +- x/distribution/client/cli/tx_test.go | 3 +- x/distribution/keeper/delegation_test.go | 15 ++++-- x/distribution/keeper/keeper_test.go | 6 ++- x/genutil/client/cli/init_test.go | 6 ++- x/genutil/client/cli/validate_genesis.go | 2 +- x/gov/client/cli/parse_test.go | 3 +- x/gov/keeper/keeper_test.go | 15 ++++-- x/params/client/cli/tx_test.go | 3 +- x/params/keeper/keeper_test.go | 12 +++-- x/params/types/subspace_test.go | 2 +- x/slashing/app_test.go | 3 +- x/staking/app_test.go | 13 +++-- x/staking/keeper/querier_test.go | 6 ++- x/staking/keeper/validator_test.go | 18 ++++--- x/supply/keeper/bank_test.go | 20 ++++---- 45 files changed, 238 insertions(+), 138 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index d109df4a6ee2..f2a7c5522273 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -9,6 +9,7 @@ linters: - deadcode - depguard - dogsled + # - errcheck - goconst - gocritic - gofmt diff --git a/client/keys/add_test.go b/client/keys/add_test.go index 5d2eb8ddf0da..fe72f0e0eb01 100644 --- a/client/keys/add_test.go +++ b/client/keys/add_test.go @@ -34,8 +34,8 @@ func Test_runAddCmdBasic(t *testing.T) { kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), kbHome, mockIn) require.NoError(t, err) t.Cleanup(func() { - kb.Delete("keyname1", "", false) - kb.Delete("keyname2", "", false) + kb.Delete("keyname1", "", false) // nolint:errcheck + kb.Delete("keyname2", "", false) // nolint:errcheck }) } assert.NoError(t, runAddCmd(cmd, []string{"keyname1"})) diff --git a/client/keys/delete_test.go b/client/keys/delete_test.go index 5c4c1a5b70a9..e897f5aadbef 100644 --- a/client/keys/delete_test.go +++ b/client/keys/delete_test.go @@ -30,8 +30,8 @@ func Test_runDeleteCmd(t *testing.T) { kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) require.NoError(t, err) t.Cleanup(func() { - kb.Delete("runDeleteCmd_Key1", "", false) - kb.Delete("runDeleteCmd_Key2", "", false) + kb.Delete("runDeleteCmd_Key1", "", false) // nolint:errcheck + kb.Delete("runDeleteCmd_Key2", "", false) // nolint:errcheck }) } diff --git a/client/keys/export_test.go b/client/keys/export_test.go index dff9d344cc14..f83c428cfc87 100644 --- a/client/keys/export_test.go +++ b/client/keys/export_test.go @@ -27,7 +27,7 @@ func Test_runExportCmd(t *testing.T) { require.NoError(t, err) if !runningUnattended { t.Cleanup(func() { - kb.Delete("keyname1", "", false) + kb.Delete("keyname1", "", false) // nolint:errcheck }) } diff --git a/client/keys/import_test.go b/client/keys/import_test.go index 3ccb606ee955..d0325677bc81 100644 --- a/client/keys/import_test.go +++ b/client/keys/import_test.go @@ -28,7 +28,7 @@ func Test_runImportCmd(t *testing.T) { kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) require.NoError(t, err) t.Cleanup(func() { - kb.Delete("keyname1", "", false) + kb.Delete("keyname1", "", false) // nolint:errcheck }) } diff --git a/client/keys/list_test.go b/client/keys/list_test.go index 94997e86c015..9770346dd984 100644 --- a/client/keys/list_test.go +++ b/client/keys/list_test.go @@ -42,7 +42,8 @@ func Test_runListCmd(t *testing.T) { require.NoError(t, err) t.Cleanup(func() { - kb.Delete("something", "", false) + kb.Delete("something", "", false) // nolint:errcheck + }) testData := []struct { name string diff --git a/crypto/keys/keybase.go b/crypto/keys/keybase.go index c273e288b765..268778b0e947 100644 --- a/crypto/keys/keybase.go +++ b/crypto/keys/keybase.go @@ -340,8 +340,7 @@ func (kb dbKeybase) Import(name string, armor string) (err error) { return } - kb.db.Set(infoKey(name), infoBytes) - return nil + return kb.db.Set(infoKey(name), infoBytes) } // ImportPubKey imports ASCII-armored public keys. Store a new Info object holding @@ -388,10 +387,13 @@ func (kb dbKeybase) Delete(name, passphrase string, skipPass bool) error { } } - kb.db.DeleteSync(addrKey(info.GetAddress())) - kb.db.DeleteSync(infoKey(name)) + batch := kb.db.NewBatch() + defer batch.Close() - return nil + batch.Delete(addrKey(info.GetAddress())) + batch.Delete(infoKey(name)) + + return batch.WriteSync() } // Update changes the passphrase with which an already stored key is diff --git a/crypto/keys/keybase_test.go b/crypto/keys/keybase_test.go index a669a83deba2..eabce8f07df0 100644 --- a/crypto/keys/keybase_test.go +++ b/crypto/keys/keybase_test.go @@ -225,7 +225,8 @@ func TestSignVerify(t *testing.T) { // Import a public key armor, err := cstore.ExportPubKey(n2) require.Nil(t, err) - cstore.ImportPubKey(n3, armor) + err = cstore.ImportPubKey(n3, armor) + require.NoError(t, err) i3, err := cstore.Get(n3) require.NoError(t, err) require.Equal(t, i3.GetName(), n3) diff --git a/crypto/keys/keyring_test.go b/crypto/keys/keyring_test.go index 0415236be971..072c07acdf9f 100644 --- a/crypto/keys/keyring_test.go +++ b/crypto/keys/keyring_test.go @@ -155,7 +155,8 @@ func TestLazySignVerifyKeyRing(t *testing.T) { // Import a public key armor, err := kb.ExportPubKey(n2) require.Nil(t, err) - kb.ImportPubKey(n3, armor) + err = kb.ImportPubKey(n3, armor) + require.NoError(t, err) i3, err := kb.Get(n3) require.NoError(t, err) require.Equal(t, i3.GetName(), n3) diff --git a/crypto/keys/lazy_keybase_test.go b/crypto/keys/lazy_keybase_test.go index bd5b742acdfd..cf61e67702d6 100644 --- a/crypto/keys/lazy_keybase_test.go +++ b/crypto/keys/lazy_keybase_test.go @@ -128,7 +128,8 @@ func TestLazySignVerify(t *testing.T) { // Import a public key armor, err := kb.ExportPubKey(n2) require.Nil(t, err) - kb.ImportPubKey(n3, armor) + err = kb.ImportPubKey(n3, armor) + require.NoError(t, err) i3, err := kb.Get(n3) require.NoError(t, err) require.Equal(t, i3.GetName(), n3) diff --git a/store/cachekv/store_test.go b/store/cachekv/store_test.go index f53940d9c47a..4a115d3cb2e1 100644 --- a/store/cachekv/store_test.go +++ b/store/cachekv/store_test.go @@ -231,13 +231,13 @@ func TestCacheKVMergeIteratorDeletes(t *testing.T) { // set some items and write them nItems := 10 for i := 0; i < nItems; i++ { - doOp(st, truth, opSet, i) + doOp(t, st, truth, opSet, i) } st.Write() // delete every other item, starting from 0 for i := 0; i < nItems; i += 2 { - doOp(st, truth, opDel, i) + doOp(t, st, truth, opDel, i) assertIterateDomainCompare(t, st, truth) } @@ -247,13 +247,13 @@ func TestCacheKVMergeIteratorDeletes(t *testing.T) { // set some items and write them for i := 0; i < nItems; i++ { - doOp(st, truth, opSet, i) + doOp(t, st, truth, opSet, i) } st.Write() // delete every other item, starting from 1 for i := 1; i < nItems; i += 2 { - doOp(st, truth, opDel, i) + doOp(t, st, truth, opDel, i) assertIterateDomainCompare(t, st, truth) } } @@ -265,27 +265,27 @@ func TestCacheKVMergeIteratorChunks(t *testing.T) { truth := dbm.NewMemDB() // sets to the parent - setRange(st, truth, 0, 20) - setRange(st, truth, 40, 60) + setRange(t, st, truth, 0, 20) + setRange(t, st, truth, 40, 60) st.Write() // sets to the cache - setRange(st, truth, 20, 40) - setRange(st, truth, 60, 80) + setRange(t, st, truth, 20, 40) + setRange(t, st, truth, 60, 80) assertIterateDomainCheck(t, st, truth, []keyRange{{0, 80}}) // remove some parents and some cache - deleteRange(st, truth, 15, 25) + deleteRange(t, st, truth, 15, 25) assertIterateDomainCheck(t, st, truth, []keyRange{{0, 15}, {25, 80}}) // remove some parents and some cache - deleteRange(st, truth, 35, 45) + deleteRange(t, st, truth, 35, 45) assertIterateDomainCheck(t, st, truth, []keyRange{{0, 15}, {25, 35}, {45, 80}}) // write, add more to the cache, and delete some cache st.Write() - setRange(st, truth, 38, 42) - deleteRange(st, truth, 40, 43) + setRange(t, st, truth, 38, 42) + deleteRange(t, st, truth, 40, 43) assertIterateDomainCheck(t, st, truth, []keyRange{{0, 15}, {25, 35}, {38, 40}, {45, 80}}) } @@ -295,11 +295,11 @@ func TestCacheKVMergeIteratorRandom(t *testing.T) { start, end := 25, 975 max := 1000 - setRange(st, truth, start, end) + setRange(t, st, truth, start, end) // do an op, test the iterator for i := 0; i < 2000; i++ { - doRandomOp(st, truth, max) + doRandomOp(t, st, truth, max) assertIterateDomainCompare(t, st, truth) } } @@ -322,48 +322,52 @@ func randInt(n int) int { } // useful for replaying a error case if we find one -func doOp(st types.CacheKVStore, truth dbm.DB, op int, args ...int) { +func doOp(t *testing.T, st types.CacheKVStore, truth dbm.DB, op int, args ...int) { switch op { case opSet: k := args[0] st.Set(keyFmt(k), valFmt(k)) - truth.Set(keyFmt(k), valFmt(k)) + err := truth.Set(keyFmt(k), valFmt(k)) + require.NoError(t, err) case opSetRange: start := args[0] end := args[1] - setRange(st, truth, start, end) + setRange(t, st, truth, start, end) case opDel: k := args[0] st.Delete(keyFmt(k)) - truth.Delete(keyFmt(k)) + err := truth.Delete(keyFmt(k)) + require.NoError(t, err) case opDelRange: start := args[0] end := args[1] - deleteRange(st, truth, start, end) + deleteRange(t, st, truth, start, end) case opWrite: st.Write() } } -func doRandomOp(st types.CacheKVStore, truth dbm.DB, maxKey int) { +func doRandomOp(t *testing.T, st types.CacheKVStore, truth dbm.DB, maxKey int) { r := randInt(totalOps) switch r { case opSet: k := randInt(maxKey) st.Set(keyFmt(k), valFmt(k)) - truth.Set(keyFmt(k), valFmt(k)) + err := truth.Set(keyFmt(k), valFmt(k)) + require.NoError(t, err) case opSetRange: start := randInt(maxKey - 2) end := randInt(maxKey-start) + start - setRange(st, truth, start, end) + setRange(t, st, truth, start, end) case opDel: k := randInt(maxKey) st.Delete(keyFmt(k)) - truth.Delete(keyFmt(k)) + err := truth.Delete(keyFmt(k)) + require.NoError(t, err) case opDelRange: start := randInt(maxKey - 2) end := randInt(maxKey-start) + start - deleteRange(st, truth, start, end) + deleteRange(t, st, truth, start, end) case opWrite: st.Write() } @@ -439,17 +443,19 @@ func checkIterators(t *testing.T, itr, itr2 types.Iterator) { //-------------------------------------------------------- -func setRange(st types.KVStore, mem dbm.DB, start, end int) { +func setRange(t *testing.T, st types.KVStore, mem dbm.DB, start, end int) { for i := start; i < end; i++ { st.Set(keyFmt(i), valFmt(i)) - mem.Set(keyFmt(i), valFmt(i)) + err := mem.Set(keyFmt(i), valFmt(i)) + require.NoError(t, err) } } -func deleteRange(st types.KVStore, mem dbm.DB, start, end int) { +func deleteRange(t *testing.T, st types.KVStore, mem dbm.DB, start, end int) { for i := start; i < end; i++ { st.Delete(keyFmt(i)) - mem.Delete(keyFmt(i)) + err := mem.Delete(keyFmt(i)) + require.NoError(t, err) } } diff --git a/store/iavl/tree_test.go b/store/iavl/tree_test.go index 7a1eef30234c..bf67088300d4 100644 --- a/store/iavl/tree_test.go +++ b/store/iavl/tree_test.go @@ -14,8 +14,8 @@ func TestImmutableTreePanics(t *testing.T) { it := &immutableTree{immTree} require.Panics(t, func() { it.Set([]byte{}, []byte{}) }) require.Panics(t, func() { it.Remove([]byte{}) }) - require.Panics(t, func() { it.SaveVersion() }) - require.Panics(t, func() { it.DeleteVersion(int64(1)) }) + require.Panics(t, func() { it.SaveVersion() }) // nolint:errcheck + require.Panics(t, func() { it.DeleteVersion(int64(1)) }) // nolint:errcheck v, _ := it.GetVersioned([]byte{0x01}, 1) require.Equal(t, int64(-1), v) v, _ = it.GetVersioned([]byte{0x01}, 0) diff --git a/store/prefix/store_test.go b/store/prefix/store_test.go index 40540f44571d..dc5bef2b19bc 100644 --- a/store/prefix/store_test.go +++ b/store/prefix/store_test.go @@ -33,9 +33,11 @@ func genRandomKVPairs(t *testing.T) []kvpair { for i := 0; i < 20; i++ { kvps[i].key = make([]byte, 32) - rand.Read(kvps[i].key) + _, err := rand.Read(kvps[i].key) + require.NoError(t, err) kvps[i].value = make([]byte, 32) - rand.Read(kvps[i].value) + _, err = rand.Read(kvps[i].value) + require.NoError(t, err) } return kvps diff --git a/store/rootmulti/proof_test.go b/store/rootmulti/proof_test.go index 4d316f2c85aa..d78886a88f22 100644 --- a/store/rootmulti/proof_test.go +++ b/store/rootmulti/proof_test.go @@ -116,7 +116,8 @@ func TestVerifyMultiStoreQueryProofEmptyStore(t *testing.T) { iavlStoreKey := types.NewKVStoreKey("iavlStoreKey") store.MountStoreWithDB(iavlStoreKey, types.StoreTypeIAVL, nil) - store.LoadVersion(0) + err := store.LoadVersion(0) + require.NoError(t, err) cid := store.Commit() // Commit with empty iavl store. // Get Proof @@ -129,7 +130,7 @@ func TestVerifyMultiStoreQueryProofEmptyStore(t *testing.T) { // Verify proof. prt := DefaultProofRuntime() - err := prt.VerifyAbsence(res.Proof, cid.Hash, "/iavlStoreKey/MYKEY") + err = prt.VerifyAbsence(res.Proof, cid.Hash, "/iavlStoreKey/MYKEY") require.Nil(t, err) // Verify (bad) proof. @@ -145,7 +146,8 @@ func TestVerifyMultiStoreQueryProofAbsence(t *testing.T) { iavlStoreKey := types.NewKVStoreKey("iavlStoreKey") store.MountStoreWithDB(iavlStoreKey, types.StoreTypeIAVL, nil) - store.LoadVersion(0) + err := store.LoadVersion(0) + require.NoError(t, err) iavlStore := store.GetCommitStore(iavlStoreKey).(*iavl.Store) iavlStore.Set([]byte("MYKEY"), []byte("MYVALUE")) @@ -161,7 +163,7 @@ func TestVerifyMultiStoreQueryProofAbsence(t *testing.T) { // Verify proof. prt := DefaultProofRuntime() - err := prt.VerifyAbsence(res.Proof, cid.Hash, "/iavlStoreKey/MYABSENTKEY") + err = prt.VerifyAbsence(res.Proof, cid.Hash, "/iavlStoreKey/MYABSENTKEY") require.Nil(t, err) // Verify (bad) proof. diff --git a/store/rootmulti/store.go b/store/rootmulti/store.go index 6b1cfde815ea..a4dfbb71abfe 100644 --- a/store/rootmulti/store.go +++ b/store/rootmulti/store.go @@ -691,5 +691,8 @@ func flushCommitInfo(db dbm.DB, version int64, cInfo commitInfo) { setCommitInfo(batch, version, cInfo) setLatestVersion(batch, version) - batch.Write() + err := batch.Write() + if err != nil { + panic(fmt.Errorf("error on batch write %w", err)) + } } diff --git a/types/context_test.go b/types/context_test.go index 9f08178624d3..225d5e1adec9 100644 --- a/types/context_test.go +++ b/types/context_test.go @@ -45,11 +45,12 @@ func (l MockLogger) With(kvs ...interface{}) log.Logger { panic("not implemented") } -func defaultContext(key types.StoreKey) types.Context { +func defaultContext(t *testing.T, key types.StoreKey) types.Context { db := dbm.NewMemDB() cms := store.NewCommitMultiStore(db) cms.MountStoreWithDB(key, types.StoreTypeIAVL, db) - cms.LoadLatestVersion() + err := cms.LoadLatestVersion() + require.NoError(t, err) ctx := types.NewContext(cms, abci.Header{}, false, log.NewNopLogger()) return ctx } @@ -61,7 +62,7 @@ func TestCacheContext(t *testing.T) { k2 := []byte("key") v2 := []byte("value") - ctx := defaultContext(key) + ctx := defaultContext(t, key) store := ctx.KVStore(key) store.Set(k1, v1) require.Equal(t, v1, store.Get(k1)) @@ -83,7 +84,7 @@ func TestCacheContext(t *testing.T) { func TestLogContext(t *testing.T) { key := types.NewKVStoreKey(t.Name()) - ctx := defaultContext(key) + ctx := defaultContext(t, key) logger := NewMockLogger() ctx = ctx.WithLogger(logger) ctx.Logger().Debug("debug") diff --git a/types/decimal_test.go b/types/decimal_test.go index 33ca99d49835..c58777783764 100644 --- a/types/decimal_test.go +++ b/types/decimal_test.go @@ -304,7 +304,8 @@ func TestDecMarshalJSON(t *testing.T) { if !tt.wantErr { assert.Equal(t, tt.want, string(got), "incorrect marshalled value") unmarshalledDec := NewDec(0) - unmarshalledDec.UnmarshalJSON(got) + err := unmarshalledDec.UnmarshalJSON(got) + assert.NoError(t, err) assert.Equal(t, tt.d, unmarshalledDec, "incorrect unmarshalled value") } }) diff --git a/types/handler_test.go b/types/handler_test.go index 4847a113137a..670da2fccb55 100644 --- a/types/handler_test.go +++ b/types/handler_test.go @@ -19,7 +19,7 @@ func TestChainAnteDecorators(t *testing.T) { mockCtrl := gomock.NewController(t) mockAnteDecorator1 := mocks.NewMockAnteDecorator(mockCtrl) mockAnteDecorator1.EXPECT().AnteHandle(gomock.Eq(ctx), gomock.Eq(tx), true, gomock.Any()).Times(1) - sdk.ChainAnteDecorators(mockAnteDecorator1)(ctx, tx, true) + sdk.ChainAnteDecorators(mockAnteDecorator1)(ctx, tx, true) //nolint:errcheck mockAnteDecorator2 := mocks.NewMockAnteDecorator(mockCtrl) mockAnteDecorator1.EXPECT().AnteHandle(gomock.Eq(ctx), gomock.Eq(tx), true, mockAnteDecorator2).Times(1) diff --git a/types/staking_test.go b/types/staking_test.go index 34c165a67ff9..537137971d52 100644 --- a/types/staking_test.go +++ b/types/staking_test.go @@ -12,7 +12,7 @@ func TestBondStatus(t *testing.T) { require.False(t, sdk.Unbonded.Equal(sdk.Bonded)) require.False(t, sdk.Unbonded.Equal(sdk.Unbonding)) require.False(t, sdk.Bonded.Equal(sdk.Unbonding)) - require.Panicsf(t, func() { _ = sdk.BondStatus(0).String() }, "invalid bond status") + require.Panicsf(t, func() { sdk.BondStatus(0).String() }, "invalid bond status") // nolint:govet require.Equal(t, sdk.BondStatusUnbonded, sdk.Unbonded.String()) require.Equal(t, sdk.BondStatusBonded, sdk.Bonded.String()) require.Equal(t, sdk.BondStatusUnbonding, sdk.Unbonding.String()) diff --git a/x/auth/ante/ante_test.go b/x/auth/ante/ante_test.go index 752895456970..23318f2d6d35 100644 --- a/x/auth/ante/ante_test.go +++ b/x/auth/ante/ante_test.go @@ -49,15 +49,18 @@ func TestSimulateGasCost(t *testing.T) { acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) require.NoError(t, acc1.SetAccountNumber(0)) app.AccountKeeper.SetAccount(ctx, acc1) - app.BankKeeper.SetBalances(ctx, acc1.GetAddress(), types.NewTestCoins()) + err := app.BankKeeper.SetBalances(ctx, acc1.GetAddress(), types.NewTestCoins()) + require.NoError(t, err) acc2 := app.AccountKeeper.NewAccountWithAddress(ctx, addr2) require.NoError(t, acc2.SetAccountNumber(1)) app.AccountKeeper.SetAccount(ctx, acc2) - app.BankKeeper.SetBalances(ctx, acc2.GetAddress(), types.NewTestCoins()) + err = app.BankKeeper.SetBalances(ctx, acc2.GetAddress(), types.NewTestCoins()) + require.NoError(t, err) acc3 := app.AccountKeeper.NewAccountWithAddress(ctx, addr3) require.NoError(t, acc3.SetAccountNumber(2)) app.AccountKeeper.SetAccount(ctx, acc3) - app.BankKeeper.SetBalances(ctx, acc3.GetAddress(), types.NewTestCoins()) + err = app.BankKeeper.SetBalances(ctx, acc3.GetAddress(), types.NewTestCoins()) + require.NoError(t, err) // set up msgs and fee var tx sdk.Tx @@ -129,7 +132,8 @@ func TestAnteHandlerSigErrors(t *testing.T) { // save the first account, but second is still unrecognized acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) app.AccountKeeper.SetAccount(ctx, acc1) - app.BankKeeper.SetBalances(ctx, addr1, fee.Amount) + err := app.BankKeeper.SetBalances(ctx, addr1, fee.Amount) + require.NoError(t, err) checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrUnknownAddress) } @@ -148,11 +152,13 @@ func TestAnteHandlerAccountNumbers(t *testing.T) { acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) require.NoError(t, acc1.SetAccountNumber(0)) app.AccountKeeper.SetAccount(ctx, acc1) - app.BankKeeper.SetBalances(ctx, addr1, types.NewTestCoins()) + err := app.BankKeeper.SetBalances(ctx, addr1, types.NewTestCoins()) + require.NoError(t, err) acc2 := app.AccountKeeper.NewAccountWithAddress(ctx, addr2) require.NoError(t, acc2.SetAccountNumber(1)) app.AccountKeeper.SetAccount(ctx, acc2) - app.BankKeeper.SetBalances(ctx, addr2, types.NewTestCoins()) + err = app.BankKeeper.SetBalances(ctx, addr2, types.NewTestCoins()) + require.NoError(t, err) // msg and signatures var tx sdk.Tx @@ -204,11 +210,13 @@ func TestAnteHandlerAccountNumbersAtBlockHeightZero(t *testing.T) { // set the accounts, we don't need the acc numbers as it is in the genesis block acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) app.AccountKeeper.SetAccount(ctx, acc1) - app.BankKeeper.SetBalances(ctx, addr1, types.NewTestCoins()) + err := app.BankKeeper.SetBalances(ctx, addr1, types.NewTestCoins()) + require.NoError(t, err) acc2 := app.AccountKeeper.NewAccountWithAddress(ctx, addr2) require.NoError(t, acc2.SetAccountNumber(1)) app.AccountKeeper.SetAccount(ctx, acc2) - app.BankKeeper.SetBalances(ctx, addr2, types.NewTestCoins()) + err = app.BankKeeper.SetBalances(ctx, addr2, types.NewTestCoins()) + require.NoError(t, err) // msg and signatures var tx sdk.Tx @@ -671,7 +679,8 @@ func TestAnteHandlerSigLimitExceeded(t *testing.T) { // set the accounts for i, addr := range addrs { acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr) - acc.SetAccountNumber(uint64(i)) + err := acc.SetAccountNumber(uint64(i)) + require.NoError(t, err) app.AccountKeeper.SetAccount(ctx, acc) app.BankKeeper.SetBalances(ctx, addr, types.NewTestCoins()) } diff --git a/x/auth/ante/setup_test.go b/x/auth/ante/setup_test.go index 7b7352dbbd26..698a0ecedbd1 100644 --- a/x/auth/ante/setup_test.go +++ b/x/auth/ante/setup_test.go @@ -74,7 +74,7 @@ func TestRecoverPanic(t *testing.T) { require.Equal(t, fee.Gas, newCtx.GasMeter().Limit()) antehandler = sdk.ChainAnteDecorators(sud, PanicDecorator{}) - require.Panics(t, func() { antehandler(ctx, tx, false) }, "Recovered from non-Out-of-Gas panic") + require.Panics(t, func() { antehandler(ctx, tx, false) }, "Recovered from non-Out-of-Gas panic") // nolint:errcheck } type OutOfGasDecorator struct{} diff --git a/x/auth/ante/sigverify_test.go b/x/auth/ante/sigverify_test.go index 58bcef1e2811..35aaa8c9f806 100644 --- a/x/auth/ante/sigverify_test.go +++ b/x/auth/ante/sigverify_test.go @@ -64,7 +64,8 @@ func TestConsumeSignatureVerificationGas(t *testing.T) { multisignature1 := multisig.NewMultisig(len(pkSet1)) expectedCost1 := expectedGasCostByKeys(pkSet1) for i := 0; i < len(pkSet1); i++ { - multisignature1.AddSignatureFromPubKey(sigSet1[i], pkSet1[i], pkSet1) + err := multisignature1.AddSignatureFromPubKey(sigSet1[i], pkSet1[i], pkSet1) + require.NoError(t, err) } type args struct { diff --git a/x/auth/client/cli/broadcast.go b/x/auth/client/cli/broadcast.go index 5f1e4757d1d7..f948dbdd9b8b 100644 --- a/x/auth/client/cli/broadcast.go +++ b/x/auth/client/cli/broadcast.go @@ -25,7 +25,7 @@ filename, the command reads from standard input. $ tx broadcast ./mytxn.json `), Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) (err error) { + RunE: func(cmd *cobra.Command, args []string) error { cliCtx := context.NewCLIContext().WithCodec(cdc) if cliCtx.Offline { @@ -34,18 +34,20 @@ $ tx broadcast ./mytxn.json stdTx, err := client.ReadStdTxFromFile(cliCtx.Codec, args[0]) if err != nil { - return + return err } txBytes, err := cliCtx.Codec.MarshalBinaryBare(stdTx) if err != nil { - return + return err } res, err := cliCtx.BroadcastTx(txBytes) - cliCtx.PrintOutput(res) + if err != nil { + return err + } - return err + return cliCtx.PrintOutput(res) }, } diff --git a/x/auth/keeper/keeper_test.go b/x/auth/keeper/keeper_test.go index 8f15f3d93668..73e1a9ef6e76 100644 --- a/x/auth/keeper/keeper_test.go +++ b/x/auth/keeper/keeper_test.go @@ -29,7 +29,8 @@ func TestAccountMapperGetSet(t *testing.T) { // set some values on the account and save it newSequence := uint64(20) - acc.SetSequence(newSequence) + err := acc.SetSequence(newSequence) + require.NoError(t, err) app.AccountKeeper.SetAccount(ctx, acc) // check the new values @@ -50,8 +51,10 @@ func TestAccountMapperRemoveAccount(t *testing.T) { accSeq1 := uint64(20) accSeq2 := uint64(40) - acc1.SetSequence(accSeq1) - acc2.SetSequence(accSeq2) + err := acc1.SetSequence(accSeq1) + require.NoError(t, err) + err = acc2.SetSequence(accSeq2) + require.NoError(t, err) app.AccountKeeper.SetAccount(ctx, acc1) app.AccountKeeper.SetAccount(ctx, acc2) diff --git a/x/auth/types/genesis_test.go b/x/auth/types/genesis_test.go index c5e482cf0356..f0733a2af210 100644 --- a/x/auth/types/genesis_test.go +++ b/x/auth/types/genesis_test.go @@ -15,7 +15,8 @@ import ( func TestSanitize(t *testing.T) { addr1 := sdk.AccAddress(ed25519.GenPrivKey().PubKey().Address()) authAcc1 := types.NewBaseAccountWithAddress(addr1) - authAcc1.SetAccountNumber(1) + err := authAcc1.SetAccountNumber(1) + require.NoError(t, err) addr2 := sdk.AccAddress(ed25519.GenPrivKey().PubKey().Address()) authAcc2 := types.NewBaseAccountWithAddress(addr2) diff --git a/x/bank/app_test.go b/x/bank/app_test.go index 4a36d2d8af77..250a10a8ed03 100644 --- a/x/bank/app_test.go +++ b/x/bank/app_test.go @@ -112,7 +112,8 @@ func TestSendNotEnoughBalance(t *testing.T) { sendMsg := types.NewMsgSend(addr1, addr2, sdk.Coins{sdk.NewInt64Coin("foocoin", 100)}) header := abci.Header{Height: app.LastBlockHeight() + 1} - simapp.SignCheckDeliver(t, app.Codec(), app.BaseApp, header, []sdk.Msg{sendMsg}, []uint64{origAccNum}, []uint64{origSeq}, false, false, priv1) + _, _, err = simapp.SignCheckDeliver(t, app.Codec(), app.BaseApp, header, []sdk.Msg{sendMsg}, []uint64{origAccNum}, []uint64{origSeq}, false, false, priv1) + require.Error(t, err) simapp.CheckBalance(t, app, addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 67)}) @@ -178,7 +179,12 @@ func TestSendToModuleAcc(t *testing.T) { origSeq := res1.GetSequence() header := abci.Header{Height: app.LastBlockHeight() + 1} - simapp.SignCheckDeliver(t, app.Codec(), app.BaseApp, header, []sdk.Msg{test.msg}, []uint64{origAccNum}, []uint64{origSeq}, test.expSimPass, test.expPass, priv1) + _, _, err = simapp.SignCheckDeliver(t, app.Codec(), app.BaseApp, header, []sdk.Msg{test.msg}, []uint64{origAccNum}, []uint64{origSeq}, test.expSimPass, test.expPass, priv1) + if test.expPass { + require.NoError(t, err) + } else { + require.Error(t, err) + } simapp.CheckBalance(t, app, test.msg.FromAddress, test.expFromBalance) simapp.CheckBalance(t, app, test.msg.ToAddress, test.expToBalance) @@ -243,7 +249,12 @@ func TestMsgMultiSendWithAccounts(t *testing.T) { for _, tc := range testCases { header := abci.Header{Height: app.LastBlockHeight() + 1} - simapp.SignCheckDeliver(t, app.Codec(), app.BaseApp, header, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...) + _, _, err := simapp.SignCheckDeliver(t, app.Codec(), app.BaseApp, header, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...) + if tc.expPass { + require.NoError(t, err) + } else { + require.Error(t, err) + } for _, eb := range tc.expectedBalances { simapp.CheckBalance(t, app, eb.addr, eb.coins) @@ -289,7 +300,8 @@ func TestMsgMultiSendMultipleOut(t *testing.T) { for _, tc := range testCases { header := abci.Header{Height: app.LastBlockHeight() + 1} - simapp.SignCheckDeliver(t, app.Codec(), app.BaseApp, header, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...) + _, _, err := simapp.SignCheckDeliver(t, app.Codec(), app.BaseApp, header, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...) + require.NoError(t, err) for _, eb := range tc.expectedBalances { simapp.CheckBalance(t, app, eb.addr, eb.coins) @@ -342,7 +354,8 @@ func TestMsgMultiSendMultipleInOut(t *testing.T) { for _, tc := range testCases { header := abci.Header{Height: app.LastBlockHeight() + 1} - simapp.SignCheckDeliver(t, app.Codec(), app.BaseApp, header, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...) + _, _, err := simapp.SignCheckDeliver(t, app.Codec(), app.BaseApp, header, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...) + require.NoError(t, err) for _, eb := range tc.expectedBalances { simapp.CheckBalance(t, app, eb.addr, eb.coins) @@ -393,7 +406,8 @@ func TestMsgMultiSendDependent(t *testing.T) { for _, tc := range testCases { header := abci.Header{Height: app.LastBlockHeight() + 1} - simapp.SignCheckDeliver(t, app.Codec(), app.BaseApp, header, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...) + _, _, err := simapp.SignCheckDeliver(t, app.Codec(), app.BaseApp, header, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...) + require.NoError(t, err) for _, eb := range tc.expectedBalances { simapp.CheckBalance(t, app, eb.addr, eb.coins) diff --git a/x/bank/bench_test.go b/x/bank/bench_test.go index d9ccdc5702a0..1fdd2ecc0b89 100644 --- a/x/bank/bench_test.go +++ b/x/bank/bench_test.go @@ -48,7 +48,8 @@ func BenchmarkOneBankSendTxPerBlock(b *testing.B) { panic("something is broken in checking transaction") } - benchmarkApp.Deliver(txs[i]) + _, _, err = benchmarkApp.Deliver(txs[i]) + require.NoError(b, err) benchmarkApp.EndBlock(abci.RequestEndBlock{Height: height}) benchmarkApp.Commit() height++ @@ -87,7 +88,8 @@ func BenchmarkOneBankMultiSendTxPerBlock(b *testing.B) { panic("something is broken in checking transaction") } - benchmarkApp.Deliver(txs[i]) + _, _, err = benchmarkApp.Deliver(txs[i]) + require.NoError(b, err) benchmarkApp.EndBlock(abci.RequestEndBlock{Height: height}) benchmarkApp.Commit() height++ diff --git a/x/bank/genesis.go b/x/bank/genesis.go index 7f68e94cff8e..b4e5096fe211 100644 --- a/x/bank/genesis.go +++ b/x/bank/genesis.go @@ -16,7 +16,9 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, genState GenesisState) { panic(err) } - keeper.SetBalances(ctx, balance.Address, balance.Coins) + if err := keeper.SetBalances(ctx, balance.Address, balance.Coins); err != nil { + panic(fmt.Errorf("error on setting balances %w", err)) + } } } diff --git a/x/bank/keeper/keeper.go b/x/bank/keeper/keeper.go index 330ab201f57e..5cfdd7187908 100644 --- a/x/bank/keeper/keeper.go +++ b/x/bank/keeper/keeper.go @@ -72,7 +72,10 @@ func (k BaseKeeper) DelegateCoins(ctx sdk.Context, delegatorAddr, moduleAccAddr } balances = balances.Add(balance) - k.SetBalance(ctx, delegatorAddr, balance.Sub(coin)) + err := k.SetBalance(ctx, delegatorAddr, balance.Sub(coin)) + if err != nil { + return err + } } if err := k.trackDelegation(ctx, delegatorAddr, ctx.BlockHeader().Time, balances, amt); err != nil { @@ -271,7 +274,10 @@ func (k BaseSendKeeper) SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, amt newBalance := balance.Sub(coin) resultCoins = resultCoins.Add(newBalance) - k.SetBalance(ctx, addr, newBalance) + err := k.SetBalance(ctx, addr, newBalance) + if err != nil { + return nil, err + } } return resultCoins, nil @@ -292,7 +298,10 @@ func (k BaseSendKeeper) AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.C newBalance := balance.Add(coin) resultCoins = resultCoins.Add(newBalance) - k.SetBalance(ctx, addr, newBalance) + err := k.SetBalance(ctx, addr, newBalance) + if err != nil { + return nil, err + } } return resultCoins, nil diff --git a/x/crisis/handler_test.go b/x/crisis/handler_test.go index 83907543f2a1..37e337fc9cce 100644 --- a/x/crisis/handler_test.go +++ b/x/crisis/handler_test.go @@ -80,7 +80,7 @@ func TestHandleMsgVerifyInvariant(t *testing.T) { case "panic": require.Panics(t, func() { - h(ctx, tc.msg) + h(ctx, tc.msg) // nolint:errcheck }) } }) diff --git a/x/distribution/client/cli/tx_test.go b/x/distribution/client/cli/tx_test.go index d8f8b3921c1b..d75f44836773 100644 --- a/x/distribution/client/cli/tx_test.go +++ b/x/distribution/client/cli/tx_test.go @@ -85,7 +85,7 @@ func TestParseProposal(t *testing.T) { cdc := codec.New() okJSON, err := ioutil.TempFile("", "proposal") require.Nil(t, err, "unexpected error") - okJSON.WriteString(` + _, err = okJSON.WriteString(` { "title": "Community Pool Spend", "description": "Pay me some Atoms!", @@ -94,6 +94,7 @@ func TestParseProposal(t *testing.T) { "deposit": "1000stake" } `) + require.NoError(t, err) proposal, err := ParseCommunityPoolSpendProposalJSON(cdc, okJSON.Name()) require.NoError(t, err) diff --git a/x/distribution/keeper/delegation_test.go b/x/distribution/keeper/delegation_test.go index 44b2bf71f918..9a57955f3e31 100644 --- a/x/distribution/keeper/delegation_test.go +++ b/x/distribution/keeper/delegation_test.go @@ -607,16 +607,19 @@ func TestCalculateRewardsMultiDelegatorMultWithdraw(t *testing.T) { app.DistrKeeper.AllocateTokensToValidator(ctx, val, tokens) // first delegator withdraws - app.DistrKeeper.WithdrawDelegationRewards(ctx, sdk.AccAddress(valAddrs[0]), valAddrs[0]) + _, err = app.DistrKeeper.WithdrawDelegationRewards(ctx, sdk.AccAddress(valAddrs[0]), valAddrs[0]) + require.NoError(t, err) // second delegator withdraws - app.DistrKeeper.WithdrawDelegationRewards(ctx, sdk.AccAddress(valAddrs[1]), valAddrs[0]) + _, err = app.DistrKeeper.WithdrawDelegationRewards(ctx, sdk.AccAddress(valAddrs[1]), valAddrs[0]) + require.NoError(t, err) // historical count should be 3 (validator init + two delegations) require.Equal(t, uint64(3), app.DistrKeeper.GetValidatorHistoricalReferenceCount(ctx)) // validator withdraws commission - app.DistrKeeper.WithdrawValidatorCommission(ctx, valAddrs[0]) + _, err = app.DistrKeeper.WithdrawValidatorCommission(ctx, valAddrs[0]) + require.NoError(t, err) // end period endingPeriod := app.DistrKeeper.IncrementValidatorPeriod(ctx, val) @@ -643,7 +646,8 @@ func TestCalculateRewardsMultiDelegatorMultWithdraw(t *testing.T) { app.DistrKeeper.AllocateTokensToValidator(ctx, val, tokens) // first delegator withdraws again - app.DistrKeeper.WithdrawDelegationRewards(ctx, sdk.AccAddress(valAddrs[0]), valAddrs[0]) + _, err = app.DistrKeeper.WithdrawDelegationRewards(ctx, sdk.AccAddress(valAddrs[0]), valAddrs[0]) + require.NoError(t, err) // end period endingPeriod = app.DistrKeeper.IncrementValidatorPeriod(ctx, val) @@ -670,7 +674,8 @@ func TestCalculateRewardsMultiDelegatorMultWithdraw(t *testing.T) { app.DistrKeeper.AllocateTokensToValidator(ctx, val, tokens) // withdraw commission - app.DistrKeeper.WithdrawValidatorCommission(ctx, valAddrs[0]) + _, err = app.DistrKeeper.WithdrawValidatorCommission(ctx, valAddrs[0]) + require.NoError(t, err) // end period endingPeriod = app.DistrKeeper.IncrementValidatorPeriod(ctx, val) diff --git a/x/distribution/keeper/keeper_test.go b/x/distribution/keeper/keeper_test.go index 8376899d8613..7cd22dfebae9 100644 --- a/x/distribution/keeper/keeper_test.go +++ b/x/distribution/keeper/keeper_test.go @@ -49,10 +49,11 @@ func TestWithdrawValidatorCommission(t *testing.T) { // set module account coins distrAcc := app.DistrKeeper.GetDistributionAccount(ctx) - app.BankKeeper.SetBalances(ctx, distrAcc.GetAddress(), sdk.NewCoins( + err := app.BankKeeper.SetBalances(ctx, distrAcc.GetAddress(), sdk.NewCoins( sdk.NewCoin("mytoken", sdk.NewInt(2)), sdk.NewCoin("stake", sdk.NewInt(2)), )) + require.NoError(t, err) app.SupplyKeeper.SetModuleAccount(ctx, distrAcc) // check initial balance @@ -68,7 +69,8 @@ func TestWithdrawValidatorCommission(t *testing.T) { app.DistrKeeper.SetValidatorAccumulatedCommission(ctx, valAddrs[0], types.ValidatorAccumulatedCommission{Commission: valCommission}) // withdraw commission - app.DistrKeeper.WithdrawValidatorCommission(ctx, valAddrs[0]) + _, err = app.DistrKeeper.WithdrawValidatorCommission(ctx, valAddrs[0]) + require.NoError(t, err) // check balance increase balance = app.BankKeeper.GetAllBalances(ctx, sdk.AccAddress(valAddrs[0])) diff --git a/x/genutil/client/cli/init_test.go b/x/genutil/client/cli/init_test.go index 9bf2e3b1469c..70b20ccc4068 100644 --- a/x/genutil/client/cli/init_test.go +++ b/x/genutil/client/cli/init_test.go @@ -113,11 +113,13 @@ func TestStartStandAlone(t *testing.T) { svr, err := abciServer.NewServer(svrAddr, "socket", app) require.Nil(t, err, "error creating listener") svr.SetLogger(logger.With("module", "abci-server")) - svr.Start() + err = svr.Start() + require.NoError(t, err) timer := time.NewTimer(time.Duration(2) * time.Second) for range timer.C { - svr.Stop() + err = svr.Stop() + require.NoError(t, err) break } } diff --git a/x/genutil/client/cli/validate_genesis.go b/x/genutil/client/cli/validate_genesis.go index 70e26f01ebbb..1e9ffb74896d 100644 --- a/x/genutil/client/cli/validate_genesis.go +++ b/x/genutil/client/cli/validate_genesis.go @@ -14,7 +14,7 @@ import ( ) // Validate genesis command takes -func ValidateGenesisCmd(ctx *server.Context, cdc *codec.Codec, mbm module.BasicManager) *cobra.Command { +func ValidateGenesisCmd(ctx *server.Context, cdc codec.JSONMarshaler, mbm module.BasicManager) *cobra.Command { return &cobra.Command{ Use: "validate-genesis [file]", Args: cobra.RangeArgs(0, 1), diff --git a/x/gov/client/cli/parse_test.go b/x/gov/client/cli/parse_test.go index 2b5cfbffd98d..cfd12534abdd 100644 --- a/x/gov/client/cli/parse_test.go +++ b/x/gov/client/cli/parse_test.go @@ -11,7 +11,7 @@ import ( func TestParseSubmitProposalFlags(t *testing.T) { okJSON, err := ioutil.TempFile("", "proposal") require.Nil(t, err, "unexpected error") - okJSON.WriteString(` + _, err = okJSON.WriteString(` { "title": "Test Proposal", "description": "My awesome proposal", @@ -19,6 +19,7 @@ func TestParseSubmitProposalFlags(t *testing.T) { "deposit": "1000test" } `) + require.NoError(t, err) badJSON, err := ioutil.TempFile("", "proposal") require.Nil(t, err, "unexpected error") diff --git a/x/gov/keeper/keeper_test.go b/x/gov/keeper/keeper_test.go index 7bf2899c3d09..3e367226478a 100644 --- a/x/gov/keeper/keeper_test.go +++ b/x/gov/keeper/keeper_test.go @@ -15,11 +15,16 @@ func TestIncrementProposalNumber(t *testing.T) { ctx := app.BaseApp.NewContext(false, abci.Header{}) tp := TestProposal - app.GovKeeper.SubmitProposal(ctx, tp) - app.GovKeeper.SubmitProposal(ctx, tp) - app.GovKeeper.SubmitProposal(ctx, tp) - app.GovKeeper.SubmitProposal(ctx, tp) - app.GovKeeper.SubmitProposal(ctx, tp) + _, err := app.GovKeeper.SubmitProposal(ctx, tp) + require.NoError(t, err) + _, err = app.GovKeeper.SubmitProposal(ctx, tp) + require.NoError(t, err) + _, err = app.GovKeeper.SubmitProposal(ctx, tp) + require.NoError(t, err) + _, err = app.GovKeeper.SubmitProposal(ctx, tp) + require.NoError(t, err) + _, err = app.GovKeeper.SubmitProposal(ctx, tp) + require.NoError(t, err) proposal6, err := app.GovKeeper.SubmitProposal(ctx, tp) require.NoError(t, err) diff --git a/x/params/client/cli/tx_test.go b/x/params/client/cli/tx_test.go index 0f3cb5c499a3..e8973b6ea77e 100644 --- a/x/params/client/cli/tx_test.go +++ b/x/params/client/cli/tx_test.go @@ -14,7 +14,7 @@ func TestParseProposal(t *testing.T) { cdc := codec.New() okJSON, err := ioutil.TempFile("", "proposal") require.Nil(t, err, "unexpected error") - okJSON.WriteString(` + _, err = okJSON.WriteString(` { "title": "Staking Param Change", "description": "Update max validators", @@ -28,6 +28,7 @@ func TestParseProposal(t *testing.T) { "deposit": "1000stake" } `) + require.NoError(t, err) proposal, err := utils.ParseParamChangeProposalJSON(cdc, okJSON.Name()) require.NoError(t, err) diff --git a/x/params/keeper/keeper_test.go b/x/params/keeper/keeper_test.go index de83f1f344c8..c2b3162a9999 100644 --- a/x/params/keeper/keeper_test.go +++ b/x/params/keeper/keeper_test.go @@ -207,19 +207,23 @@ func TestJSONUpdate(t *testing.T) { var param paramJSON - space.Update(ctx, key, []byte(`{"param1": "10241024"}`)) + err := space.Update(ctx, key, []byte(`{"param1": "10241024"}`)) + require.NoError(t, err) space.Get(ctx, key, ¶m) require.Equal(t, paramJSON{10241024, ""}, param) - space.Update(ctx, key, []byte(`{"param2": "helloworld"}`)) + err = space.Update(ctx, key, []byte(`{"param2": "helloworld"}`)) + require.NoError(t, err) space.Get(ctx, key, ¶m) require.Equal(t, paramJSON{10241024, "helloworld"}, param) - space.Update(ctx, key, []byte(`{"param1": "20482048"}`)) + err = space.Update(ctx, key, []byte(`{"param1": "20482048"}`)) + require.NoError(t, err) space.Get(ctx, key, ¶m) require.Equal(t, paramJSON{20482048, "helloworld"}, param) - space.Update(ctx, key, []byte(`{"param1": "40964096", "param2": "goodbyeworld"}`)) + err = space.Update(ctx, key, []byte(`{"param1": "40964096", "param2": "goodbyeworld"}`)) + require.NoError(t, err) space.Get(ctx, key, ¶m) require.Equal(t, paramJSON{40964096, "goodbyeworld"}, param) } diff --git a/x/params/types/subspace_test.go b/x/params/types/subspace_test.go index a4c4f74d4cc8..d7c30ba18f65 100644 --- a/x/params/types/subspace_test.go +++ b/x/params/types/subspace_test.go @@ -112,7 +112,7 @@ func (suite *SubspaceTestSuite) TestModified() { func (suite *SubspaceTestSuite) TestUpdate() { suite.Require().Panics(func() { - suite.ss.Update(suite.ctx, []byte("invalid_key"), nil) + suite.ss.Update(suite.ctx, []byte("invalid_key"), nil) // nolint:errcheck }) t := time.Hour * 48 diff --git a/x/slashing/app_test.go b/x/slashing/app_test.go index 262e0227f196..3241980e4c32 100644 --- a/x/slashing/app_test.go +++ b/x/slashing/app_test.go @@ -64,7 +64,8 @@ func TestSlashingMsgs(t *testing.T) { ) header := abci.Header{Height: app.LastBlockHeight() + 1} - simapp.SignCheckDeliver(t, app.Codec(), app.BaseApp, header, []sdk.Msg{createValidatorMsg}, []uint64{0}, []uint64{0}, true, true, priv1) + _, _, err := simapp.SignCheckDeliver(t, app.Codec(), app.BaseApp, header, []sdk.Msg{createValidatorMsg}, []uint64{0}, []uint64{0}, true, true, priv1) + require.NoError(t, err) simapp.CheckBalance(t, app, addr1, sdk.Coins{genCoin.Sub(bondCoin)}) header = abci.Header{Height: app.LastBlockHeight() + 1} diff --git a/x/staking/app_test.go b/x/staking/app_test.go index f013e6323b48..c3330788409f 100644 --- a/x/staking/app_test.go +++ b/x/staking/app_test.go @@ -70,7 +70,8 @@ func TestStakingMsgs(t *testing.T) { ) header := abci.Header{Height: app.LastBlockHeight() + 1} - simapp.SignCheckDeliver(t, app.Codec(), app.BaseApp, header, []sdk.Msg{createValidatorMsg}, []uint64{0}, []uint64{0}, true, true, priv1) + _, _, err := simapp.SignCheckDeliver(t, app.Codec(), app.BaseApp, header, []sdk.Msg{createValidatorMsg}, []uint64{0}, []uint64{0}, true, true, priv1) + require.NoError(t, err) simapp.CheckBalance(t, app, addr1, sdk.Coins{genCoin.Sub(bondCoin)}) header = abci.Header{Height: app.LastBlockHeight() + 1} @@ -89,7 +90,8 @@ func TestStakingMsgs(t *testing.T) { editValidatorMsg := staking.NewMsgEditValidator(sdk.ValAddress(addr1), description, nil, nil) header = abci.Header{Height: app.LastBlockHeight() + 1} - simapp.SignCheckDeliver(t, app.Codec(), app.BaseApp, header, []sdk.Msg{editValidatorMsg}, []uint64{0}, []uint64{1}, true, true, priv1) + _, _, err = simapp.SignCheckDeliver(t, app.Codec(), app.BaseApp, header, []sdk.Msg{editValidatorMsg}, []uint64{0}, []uint64{1}, true, true, priv1) + require.NoError(t, err) validator = checkValidator(t, app, sdk.ValAddress(addr1), true) require.Equal(t, description, validator.Description) @@ -99,14 +101,17 @@ func TestStakingMsgs(t *testing.T) { delegateMsg := staking.NewMsgDelegate(addr2, sdk.ValAddress(addr1), bondCoin) header = abci.Header{Height: app.LastBlockHeight() + 1} - simapp.SignCheckDeliver(t, app.Codec(), app.BaseApp, header, []sdk.Msg{delegateMsg}, []uint64{1}, []uint64{0}, true, true, priv2) + _, _, err = simapp.SignCheckDeliver(t, app.Codec(), app.BaseApp, header, []sdk.Msg{delegateMsg}, []uint64{1}, []uint64{0}, true, true, priv2) + require.NoError(t, err) + simapp.CheckBalance(t, app, addr2, sdk.Coins{genCoin.Sub(bondCoin)}) checkDelegation(t, app, addr2, sdk.ValAddress(addr1), true, bondTokens.ToDec()) // begin unbonding beginUnbondingMsg := staking.NewMsgUndelegate(addr2, sdk.ValAddress(addr1), bondCoin) header = abci.Header{Height: app.LastBlockHeight() + 1} - simapp.SignCheckDeliver(t, app.Codec(), app.BaseApp, header, []sdk.Msg{beginUnbondingMsg}, []uint64{1}, []uint64{1}, true, true, priv2) + _, _, err = simapp.SignCheckDeliver(t, app.Codec(), app.BaseApp, header, []sdk.Msg{beginUnbondingMsg}, []uint64{1}, []uint64{1}, true, true, priv2) + require.NoError(t, err) // delegation should exist anymore checkDelegation(t, app, addr2, sdk.ValAddress(addr1), false, sdk.Dec{}) diff --git a/x/staking/keeper/querier_test.go b/x/staking/keeper/querier_test.go index e4b685836ea1..5e395e3bd9b2 100644 --- a/x/staking/keeper/querier_test.go +++ b/x/staking/keeper/querier_test.go @@ -439,11 +439,13 @@ func TestQueryRedelegations(t *testing.T) { app.StakingKeeper.SetValidator(ctx, val2) delAmount := sdk.TokensFromConsensusPower(100) - app.StakingKeeper.Delegate(ctx, addrAcc2, delAmount, sdk.Unbonded, val1, true) + _, err := app.StakingKeeper.Delegate(ctx, addrAcc2, delAmount, sdk.Unbonded, val1, true) + require.NoError(t, err) _ = app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) rdAmount := sdk.TokensFromConsensusPower(20) - app.StakingKeeper.BeginRedelegation(ctx, addrAcc2, val1.GetOperator(), val2.GetOperator(), rdAmount.ToDec()) + _, err = app.StakingKeeper.BeginRedelegation(ctx, addrAcc2, val1.GetOperator(), val2.GetOperator(), rdAmount.ToDec()) + require.NoError(t, err) app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) redel, found := app.StakingKeeper.GetRedelegation(ctx, addrAcc2, val1.OperatorAddress, val2.OperatorAddress) diff --git a/x/staking/keeper/validator_test.go b/x/staking/keeper/validator_test.go index d6518c722df4..7b7222ea260f 100644 --- a/x/staking/keeper/validator_test.go +++ b/x/staking/keeper/validator_test.go @@ -93,8 +93,10 @@ func TestUpdateValidatorByPowerIndex(t *testing.T) { bondedPool := app.StakingKeeper.GetBondedPool(ctx) notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) - app.BankKeeper.SetBalances(ctx, bondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.TokensFromConsensusPower(1234)))) - app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.TokensFromConsensusPower(10000)))) + err := app.BankKeeper.SetBalances(ctx, bondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.TokensFromConsensusPower(1234)))) + require.NoError(t, err) + err = app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.TokensFromConsensusPower(10000)))) + require.NoError(t, err) app.SupplyKeeper.SetModuleAccount(ctx, bondedPool) app.SupplyKeeper.SetModuleAccount(ctx, notBondedPool) @@ -141,8 +143,10 @@ func TestUpdateBondedValidatorsDecreaseCliff(t *testing.T) { app.StakingKeeper.SetParams(ctx, params) // create a random pool - app.BankKeeper.SetBalances(ctx, bondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.TokensFromConsensusPower(1234)))) - app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.TokensFromConsensusPower(10000)))) + err := app.BankKeeper.SetBalances(ctx, bondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.TokensFromConsensusPower(1234)))) + require.NoError(t, err) + err = app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.TokensFromConsensusPower(10000)))) + require.NoError(t, err) app.SupplyKeeper.SetModuleAccount(ctx, bondedPool) app.SupplyKeeper.SetModuleAccount(ctx, notBondedPool) @@ -397,8 +401,10 @@ func TestGetValidatorSortingMixed(t *testing.T) { bondedPool := app.StakingKeeper.GetBondedPool(ctx) notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) - app.BankKeeper.SetBalances(ctx, bondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.TokensFromConsensusPower(501)))) - app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.TokensFromConsensusPower(0)))) + err := app.BankKeeper.SetBalances(ctx, bondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.TokensFromConsensusPower(501)))) + require.NoError(t, err) + err = app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.TokensFromConsensusPower(0)))) + require.NoError(t, err) app.SupplyKeeper.SetModuleAccount(ctx, notBondedPool) app.SupplyKeeper.SetModuleAccount(ctx, bondedPool) diff --git a/x/supply/keeper/bank_test.go b/x/supply/keeper/bank_test.go index 3a4e8a15c107..15c70ee37b6a 100644 --- a/x/supply/keeper/bank_test.go +++ b/x/supply/keeper/bank_test.go @@ -71,15 +71,15 @@ func TestSendCoins(t *testing.T) { ak.SetAccount(ctx, baseAcc) require.Panics(t, func() { - keeper.SendCoinsFromModuleToModule(ctx, "", holderAcc.GetName(), initCoins) + keeper.SendCoinsFromModuleToModule(ctx, "", holderAcc.GetName(), initCoins) // nolint:errcheck }) require.Panics(t, func() { - keeper.SendCoinsFromModuleToModule(ctx, types.Burner, "", initCoins) + keeper.SendCoinsFromModuleToModule(ctx, types.Burner, "", initCoins) // nolint:errcheck }) require.Panics(t, func() { - keeper.SendCoinsFromModuleToAccount(ctx, "", baseAcc.GetAddress(), initCoins) + keeper.SendCoinsFromModuleToAccount(ctx, "", baseAcc.GetAddress(), initCoins) // nolint:errcheck }) require.Error( @@ -129,12 +129,12 @@ func TestMintCoins(t *testing.T) { initialSupply := keeper.GetSupply(ctx) - require.Panics(t, func() { keeper.MintCoins(ctx, "", initCoins) }, "no module account") - require.Panics(t, func() { keeper.MintCoins(ctx, types.Burner, initCoins) }, "invalid permission") + require.Panics(t, func() { keeper.MintCoins(ctx, "", initCoins) }, "no module account") // nolint:errcheck + require.Panics(t, func() { keeper.MintCoins(ctx, types.Burner, initCoins) }, "invalid permission") // nolint:errcheck err := keeper.MintCoins(ctx, types.Minter, sdk.Coins{sdk.Coin{Denom: "denom", Amount: sdk.NewInt(-10)}}) require.Error(t, err, "insufficient coins") - require.Panics(t, func() { keeper.MintCoins(ctx, randomPerm, initCoins) }) + require.Panics(t, func() { keeper.MintCoins(ctx, randomPerm, initCoins) }) // nolint:errcheck err = keeper.MintCoins(ctx, types.Minter, initCoins) require.NoError(t, err) @@ -149,7 +149,7 @@ func TestMintCoins(t *testing.T) { require.Equal(t, initCoins, getCoinsByName(ctx, keeper, ak, bk, multiPermAcc.GetName())) require.Equal(t, initialSupply.GetTotal().Add(initCoins...), keeper.GetSupply(ctx).GetTotal()) - require.Panics(t, func() { keeper.MintCoins(ctx, types.Burner, initCoins) }) + require.Panics(t, func() { keeper.MintCoins(ctx, types.Burner, initCoins) }) // nolint:errcheck } func TestBurnCoins(t *testing.T) { @@ -178,9 +178,9 @@ func TestBurnCoins(t *testing.T) { initialSupply.Inflate(initCoins) keeper.SetSupply(ctx, initialSupply) - require.Panics(t, func() { keeper.BurnCoins(ctx, "", initCoins) }, "no module account") - require.Panics(t, func() { keeper.BurnCoins(ctx, types.Minter, initCoins) }, "invalid permission") - require.Panics(t, func() { keeper.BurnCoins(ctx, randomPerm, initialSupply.GetTotal()) }, "random permission") + require.Panics(t, func() { keeper.BurnCoins(ctx, "", initCoins) }, "no module account") // nolint:errcheck + require.Panics(t, func() { keeper.BurnCoins(ctx, types.Minter, initCoins) }, "invalid permission") // nolint:errcheck + require.Panics(t, func() { keeper.BurnCoins(ctx, randomPerm, initialSupply.GetTotal()) }, "random permission") // nolint:errcheck err := keeper.BurnCoins(ctx, types.Burner, initialSupply.GetTotal()) require.Error(t, err, "insufficient coins") From 49102b1d988f542c4293af7a85e403d858f348a8 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 23 Mar 2020 12:55:44 +0100 Subject: [PATCH 445/529] Remove dependency of types/module package on x/simulation (#5835) Closes: #5724 --- CHANGELOG.md | 1 + simapp/config.go | 2 +- simapp/helpers/test_helpers.go | 2 +- simapp/state.go | 24 +-- simapp/utils.go | 16 +- types/module/module.go | 1 - types/module/simulation.go | 2 +- {x => types}/simulation/account.go | 0 {x => types}/simulation/account_test.go | 2 +- {x => types}/simulation/config.go | 0 {x => types}/simulation/rand_util.go | 0 {x => types}/simulation/rand_util_test.go | 2 +- types/simulation/transition_matrix.go | 12 ++ types/simulation/types.go | 160 ++++++++++++++++++++ x/auth/module.go | 8 +- x/auth/simulation/genesis.go | 2 +- x/auth/simulation/params.go | 8 +- x/bank/module.go | 9 +- x/bank/simulation/operations.go | 55 +++---- x/bank/simulation/params.go | 8 +- x/distribution/module.go | 9 +- x/distribution/simulation/operations.go | 85 +++++------ x/distribution/simulation/params.go | 8 +- x/distribution/simulation/proposals.go | 28 ++-- x/gov/module.go | 8 +- x/gov/simulation/genesis.go | 2 +- x/gov/simulation/operations.go | 91 +++++------ x/gov/simulation/params.go | 7 +- x/gov/simulation/proposals.go | 21 +-- x/gov/types/content.go | 2 + x/mint/module.go | 8 +- x/mint/simulation/params.go | 8 +- x/params/module.go | 8 +- x/params/simulation/operations.go | 7 +- x/params/simulation/proposals.go | 15 +- x/simulation/mock_tendermint.go | 10 +- x/simulation/operation.go | 134 ++++------------- x/simulation/params.go | 127 +++++++++------- x/simulation/params_test.go | 55 +++++++ x/simulation/simulate.go | 43 +++--- x/simulation/transition_matrix.go | 4 +- x/simulation/util.go | 2 +- x/slashing/module.go | 8 +- x/slashing/simulation/genesis.go | 2 +- x/slashing/simulation/operations.go | 37 ++--- x/slashing/simulation/params.go | 5 +- x/staking/module.go | 8 +- x/staking/simulation/genesis.go | 2 +- x/staking/simulation/operations.go | 175 +++++++++++----------- x/staking/simulation/params.go | 6 +- x/supply/module.go | 9 +- 51 files changed, 716 insertions(+), 532 deletions(-) rename {x => types}/simulation/account.go (100%) rename {x => types}/simulation/account_test.go (97%) rename {x => types}/simulation/config.go (100%) rename {x => types}/simulation/rand_util.go (100%) rename {x => types}/simulation/rand_util_test.go (96%) create mode 100644 types/simulation/transition_matrix.go create mode 100644 types/simulation/types.go create mode 100644 x/simulation/params_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 18f1b0f79ceb..3f855ade9fe6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -178,6 +178,7 @@ and `--pruning-snapshot-every` as an alternative to `--pruning`. They allow to f be executed without an internet connection. Previously, `--generate-only` served this purpose in addition to only allowing txs to be generated. Now, `--generate-only` solely allows txs to be generated without being broadcasted and disallows Keybase use and `--offline` allows the use of Keybase but does not allow any functionality that requires an online connection. +* (types/module) [\#5724](https://github.com/cosmos/cosmos-sdk/issues/5724) The `types/module` package does no longer depend on `x/simulation`. ## [v0.38.1] - 2020-02-11 diff --git a/simapp/config.go b/simapp/config.go index d42527d3dc6f..98df982bd304 100644 --- a/simapp/config.go +++ b/simapp/config.go @@ -3,7 +3,7 @@ package simapp import ( "flag" - "github.com/cosmos/cosmos-sdk/x/simulation" + "github.com/cosmos/cosmos-sdk/types/simulation" ) // List of available flags for the simulator diff --git a/simapp/helpers/test_helpers.go b/simapp/helpers/test_helpers.go index ef265c8237e4..ff807ff29ece 100644 --- a/simapp/helpers/test_helpers.go +++ b/simapp/helpers/test_helpers.go @@ -7,8 +7,8 @@ import ( "github.com/tendermint/tendermint/crypto" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/simulation" ) // SimAppChainID hardcoded chainID for simulation diff --git a/simapp/state.go b/simapp/state.go index 942ec784681d..b4e1b789a015 100644 --- a/simapp/state.go +++ b/simapp/state.go @@ -14,19 +14,19 @@ import ( "github.com/cosmos/cosmos-sdk/codec" simapparams "github.com/cosmos/cosmos-sdk/simapp/params" "github.com/cosmos/cosmos-sdk/types/module" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/simulation" ) // AppStateFn returns the initial application state using a genesis or the simulation parameters. // It panics if the user provides files for both of them. // If a file is not given for the genesis or the sim params, it creates a randomized one. -func AppStateFn(cdc *codec.Codec, simManager *module.SimulationManager) simulation.AppStateFn { - return func(r *rand.Rand, accs []simulation.Account, config simulation.Config, - ) (appState json.RawMessage, simAccs []simulation.Account, chainID string, genesisTimestamp time.Time) { +func AppStateFn(cdc *codec.Codec, simManager *module.SimulationManager) simtypes.AppStateFn { + return func(r *rand.Rand, accs []simtypes.Account, config simtypes.Config, + ) (appState json.RawMessage, simAccs []simtypes.Account, chainID string, genesisTimestamp time.Time) { if FlagGenesisTimeValue == 0 { - genesisTimestamp = simulation.RandTimestamp(r) + genesisTimestamp = simtypes.RandTimestamp(r) } else { genesisTimestamp = time.Unix(FlagGenesisTimeValue, 0) } @@ -50,7 +50,7 @@ func AppStateFn(cdc *codec.Codec, simManager *module.SimulationManager) simulati simAccs = accounts case config.ParamsFile != "": - appParams := make(simulation.AppParams) + appParams := make(simtypes.AppParams) bz, err := ioutil.ReadFile(config.ParamsFile) if err != nil { panic(err) @@ -60,7 +60,7 @@ func AppStateFn(cdc *codec.Codec, simManager *module.SimulationManager) simulati appState, simAccs = AppStateRandomizedFn(simManager, r, cdc, accs, genesisTimestamp, appParams) default: - appParams := make(simulation.AppParams) + appParams := make(simtypes.AppParams) appState, simAccs = AppStateRandomizedFn(simManager, r, cdc, accs, genesisTimestamp, appParams) } @@ -72,8 +72,8 @@ func AppStateFn(cdc *codec.Codec, simManager *module.SimulationManager) simulati // and creates the simulation params func AppStateRandomizedFn( simManager *module.SimulationManager, r *rand.Rand, cdc *codec.Codec, - accs []simulation.Account, genesisTimestamp time.Time, appParams simulation.AppParams, -) (json.RawMessage, []simulation.Account) { + accs []simtypes.Account, genesisTimestamp time.Time, appParams simtypes.AppParams, +) (json.RawMessage, []simtypes.Account) { numAccs := int64(len(accs)) genesisState := NewDefaultGenesisState() @@ -125,7 +125,7 @@ func AppStateRandomizedFn( // AppStateFromGenesisFileFn util function to generate the genesis AppState // from a genesis.json file. -func AppStateFromGenesisFileFn(r io.Reader, cdc *codec.Codec, genesisFile string) (tmtypes.GenesisDoc, []simulation.Account) { +func AppStateFromGenesisFileFn(r io.Reader, cdc *codec.Codec, genesisFile string) (tmtypes.GenesisDoc, []simtypes.Account) { bytes, err := ioutil.ReadFile(genesisFile) if err != nil { panic(err) @@ -142,7 +142,7 @@ func AppStateFromGenesisFileFn(r io.Reader, cdc *codec.Codec, genesisFile string cdc.MustUnmarshalJSON(appState[auth.ModuleName], &authGenesis) } - newAccs := make([]simulation.Account, len(authGenesis.Accounts)) + newAccs := make([]simtypes.Account, len(authGenesis.Accounts)) for i, acc := range authGenesis.Accounts { // Pick a random private key, since we don't know the actual key // This should be fine as it's only used for mock Tendermint validators @@ -155,7 +155,7 @@ func AppStateFromGenesisFileFn(r io.Reader, cdc *codec.Codec, genesisFile string privKey := secp256k1.GenPrivKeySecp256k1(privkeySeed) // create simulator accounts - simAcc := simulation.Account{PrivKey: privKey, PubKey: privKey.PubKey(), Address: acc.GetAddress()} + simAcc := simtypes.Account{PrivKey: privKey, PubKey: privKey.PubKey(), Address: acc.GetAddress()} newAccs[i] = simAcc } diff --git a/simapp/utils.go b/simapp/utils.go index bc3e889fe68c..d023040d753d 100644 --- a/simapp/utils.go +++ b/simapp/utils.go @@ -13,15 +13,15 @@ import ( "github.com/cosmos/cosmos-sdk/simapp/helpers" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" - "github.com/cosmos/cosmos-sdk/x/simulation" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" ) // SetupSimulation creates the config, db (levelDB), temporary directory and logger for // the simulation tests. If `FlagEnabledValue` is false it skips the current test. // Returns error on an invalid db intantiation or temp dir creation. -func SetupSimulation(dirPrefix, dbName string) (simulation.Config, dbm.DB, string, log.Logger, bool, error) { +func SetupSimulation(dirPrefix, dbName string) (simtypes.Config, dbm.DB, string, log.Logger, bool, error) { if !FlagEnabledValue { - return simulation.Config{}, nil, "", nil, true, nil + return simtypes.Config{}, nil, "", nil, true, nil } config := NewConfigFromFlags() @@ -36,12 +36,12 @@ func SetupSimulation(dirPrefix, dbName string) (simulation.Config, dbm.DB, strin dir, err := ioutil.TempDir("", dirPrefix) if err != nil { - return simulation.Config{}, nil, "", nil, false, err + return simtypes.Config{}, nil, "", nil, false, err } db, err := sdk.NewLevelDB(dbName, dir) if err != nil { - return simulation.Config{}, nil, "", nil, false, err + return simtypes.Config{}, nil, "", nil, false, err } return config, db, dir, logger, false, nil @@ -49,9 +49,9 @@ func SetupSimulation(dirPrefix, dbName string) (simulation.Config, dbm.DB, strin // SimulationOperations retrieves the simulation params from the provided file path // and returns all the modules weighted operations -func SimulationOperations(app App, cdc *codec.Codec, config simulation.Config) []simulation.WeightedOperation { +func SimulationOperations(app App, cdc *codec.Codec, config simtypes.Config) []simtypes.WeightedOperation { simState := module.SimulationState{ - AppParams: make(simulation.AppParams), + AppParams: make(simtypes.AppParams), Cdc: cdc, } @@ -72,7 +72,7 @@ func SimulationOperations(app App, cdc *codec.Codec, config simulation.Config) [ // CheckExportSimulation exports the app state and simulation parameters to JSON // if the export paths are defined. func CheckExportSimulation( - app App, config simulation.Config, params simulation.Params, + app App, config simtypes.Config, params simtypes.Params, ) error { if config.ExportStatePath != "" { fmt.Println("exporting app state...") diff --git a/types/module/module.go b/types/module/module.go index 0b1633e3cd24..4a3447230878 100644 --- a/types/module/module.go +++ b/types/module/module.go @@ -33,7 +33,6 @@ import ( "github.com/gorilla/mux" "github.com/spf13/cobra" - abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/client/context" diff --git a/types/module/simulation.go b/types/module/simulation.go index e142b3c882d7..2efcb669a4e2 100644 --- a/types/module/simulation.go +++ b/types/module/simulation.go @@ -8,7 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/simulation" + "github.com/cosmos/cosmos-sdk/types/simulation" ) // AppModuleSimulation defines the standard functions that every module should expose diff --git a/x/simulation/account.go b/types/simulation/account.go similarity index 100% rename from x/simulation/account.go rename to types/simulation/account.go diff --git a/x/simulation/account_test.go b/types/simulation/account_test.go similarity index 97% rename from x/simulation/account_test.go rename to types/simulation/account_test.go index b0f6494fac30..62a4b7ac8f5e 100644 --- a/x/simulation/account_test.go +++ b/types/simulation/account_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/require" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/simulation" + "github.com/cosmos/cosmos-sdk/types/simulation" ) func TestRandomAccounts(t *testing.T) { diff --git a/x/simulation/config.go b/types/simulation/config.go similarity index 100% rename from x/simulation/config.go rename to types/simulation/config.go diff --git a/x/simulation/rand_util.go b/types/simulation/rand_util.go similarity index 100% rename from x/simulation/rand_util.go rename to types/simulation/rand_util.go diff --git a/x/simulation/rand_util_test.go b/types/simulation/rand_util_test.go similarity index 96% rename from x/simulation/rand_util_test.go rename to types/simulation/rand_util_test.go index 9d46164e59f6..09de644d17ee 100644 --- a/x/simulation/rand_util_test.go +++ b/types/simulation/rand_util_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/require" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/simulation" + "github.com/cosmos/cosmos-sdk/types/simulation" ) func TestRandSubsetCoins(t *testing.T) { diff --git a/types/simulation/transition_matrix.go b/types/simulation/transition_matrix.go new file mode 100644 index 000000000000..f2759df3dee9 --- /dev/null +++ b/types/simulation/transition_matrix.go @@ -0,0 +1,12 @@ +package simulation + +import "math/rand" + +// TransitionMatrix is _almost_ a left stochastic matrix. It is technically +// not one due to not normalizing the column values. In the future, if we want +// to find the steady state distribution, it will be quite easy to normalize +// these values to get a stochastic matrix. Floats aren't currently used as +// the default due to non-determinism across architectures +type TransitionMatrix interface { + NextState(r *rand.Rand, i int) int +} diff --git a/types/simulation/types.go b/types/simulation/types.go new file mode 100644 index 000000000000..ada219ccd057 --- /dev/null +++ b/types/simulation/types.go @@ -0,0 +1,160 @@ +package simulation + +import ( + "encoding/json" + "math/rand" + "time" + + "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +type WeightedProposalContent interface { + AppParamsKey() string // key used to retrieve the value of the weight from the simulation application params + DefaultWeight() int // default weight + ContentSimulatorFn() ContentSimulatorFn // content simulator function +} + +type ContentSimulatorFn func(r *rand.Rand, ctx sdk.Context, accs []Account) Content + +type Content interface { + GetTitle() string + GetDescription() string + ProposalRoute() string + ProposalType() string + ValidateBasic() error + String() string +} + +type SimValFn func(r *rand.Rand) string + +type ParamChange interface { + Subspace() string + Key() string + SimValue() SimValFn + ComposedKey() string +} + +type WeightedOperation interface { + Weight() int + Op() Operation +} + +// Operation runs a state machine transition, and ensures the transition +// happened as expected. The operation could be running and testing a fuzzed +// transaction, or doing the same for a message. +// +// For ease of debugging, an operation returns a descriptive message "action", +// which details what this fuzzed state machine transition actually did. +// +// Operations can optionally provide a list of "FutureOperations" to run later +// These will be ran at the beginning of the corresponding block. +type Operation func(r *rand.Rand, app *baseapp.BaseApp, + ctx sdk.Context, accounts []Account, chainID string) ( + OperationMsg OperationMsg, futureOps []FutureOperation, err error) + +// OperationMsg - structure for operation output +type OperationMsg struct { + Route string `json:"route" yaml:"route"` // msg route (i.e module name) + Name string `json:"name" yaml:"name"` // operation name (msg Type or "no-operation") + Comment string `json:"comment" yaml:"comment"` // additional comment + OK bool `json:"ok" yaml:"ok"` // success + Msg json.RawMessage `json:"msg" yaml:"msg"` // JSON encoded msg +} + +// NewOperationMsgBasic creates a new operation message from raw input. +func NewOperationMsgBasic(route, name, comment string, ok bool, msg []byte) OperationMsg { + return OperationMsg{ + Route: route, + Name: name, + Comment: comment, + OK: ok, + Msg: msg, + } +} + +// NewOperationMsg - create a new operation message from sdk.Msg +func NewOperationMsg(msg sdk.Msg, ok bool, comment string) OperationMsg { + return NewOperationMsgBasic(msg.Route(), msg.Type(), comment, ok, msg.GetSignBytes()) +} + +// NoOpMsg - create a no-operation message +func NoOpMsg(route string) OperationMsg { + return NewOperationMsgBasic(route, "no-operation", "", false, nil) +} + +// log entry text for this operation msg +func (om OperationMsg) String() string { + out, err := json.Marshal(om) + if err != nil { + panic(err) + } + return string(out) +} + +// MustMarshal Marshals the operation msg, panic on error +func (om OperationMsg) MustMarshal() json.RawMessage { + out, err := json.Marshal(om) + if err != nil { + panic(err) + } + return out +} + +// LogEvent adds an event for the events stats +func (om OperationMsg) LogEvent(eventLogger func(route, op, evResult string)) { + pass := "ok" + if !om.OK { + pass = "failure" + } + eventLogger(om.Route, om.Name, pass) +} + +//________________________________________________________________________ + +// FutureOperation is an operation which will be ran at the beginning of the +// provided BlockHeight. If both a BlockHeight and BlockTime are specified, it +// will use the BlockHeight. In the (likely) event that multiple operations +// are queued at the same block height, they will execute in a FIFO pattern. +type FutureOperation struct { + BlockHeight int + BlockTime time.Time + Op Operation +} + +// AppParams defines a flat JSON of key/values for all possible configurable +// simulation parameters. It might contain: operation weights, simulation parameters +// and flattened module state parameters (i.e not stored under it's respective module name). +type AppParams map[string]json.RawMessage + +// GetOrGenerate attempts to get a given parameter by key from the AppParams +// object. If it exists, it'll be decoded and returned. Otherwise, the provided +// ParamSimulator is used to generate a random value or default value (eg: in the +// case of operation weights where Rand is not used). +func (sp AppParams) GetOrGenerate(cdc *codec.Codec, key string, ptr interface{}, r *rand.Rand, ps ParamSimulator) { + if v, ok := sp[key]; ok && v != nil { + cdc.MustUnmarshalJSON(v, ptr) + return + } + + ps(r) +} + +type ParamSimulator func(r *rand.Rand) + +type SelectOpFn func(r *rand.Rand) Operation + +// AppStateFn returns the app state json bytes and the genesis accounts +type AppStateFn func(r *rand.Rand, accs []Account, config Config) ( + appState json.RawMessage, accounts []Account, chainId string, genesisTimestamp time.Time, +) + +type Params interface { + PastEvidenceFraction() float64 + NumKeys() int + EvidenceFraction() float64 + InitialLivenessWeightings() []int + LivenessTransitionMatrix() TransitionMatrix + BlockSizeTransitionMatrix() TransitionMatrix +} diff --git a/x/auth/module.go b/x/auth/module.go index 910a54a2b951..79a6e26de540 100644 --- a/x/auth/module.go +++ b/x/auth/module.go @@ -13,11 +13,11 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/cosmos/cosmos-sdk/x/auth/client/cli" "github.com/cosmos/cosmos-sdk/x/auth/client/rest" "github.com/cosmos/cosmos-sdk/x/auth/simulation" "github.com/cosmos/cosmos-sdk/x/auth/types" - sim "github.com/cosmos/cosmos-sdk/x/simulation" ) var ( @@ -148,12 +148,12 @@ func (AppModule) GenerateGenesisState(simState *module.SimulationState) { } // ProposalContents doesn't return any content functions for governance proposals. -func (AppModule) ProposalContents(_ module.SimulationState) []sim.WeightedProposalContent { +func (AppModule) ProposalContents(simState module.SimulationState) []simtypes.WeightedProposalContent { return nil } // RandomizedParams creates randomized auth param changes for the simulator. -func (AppModule) RandomizedParams(r *rand.Rand) []sim.ParamChange { +func (AppModule) RandomizedParams(r *rand.Rand) []simtypes.ParamChange { return simulation.ParamChanges(r) } @@ -163,6 +163,6 @@ func (AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { } // WeightedOperations doesn't return any auth module operation. -func (AppModule) WeightedOperations(_ module.SimulationState) []sim.WeightedOperation { +func (AppModule) WeightedOperations(_ module.SimulationState) []simtypes.WeightedOperation { return nil } diff --git a/x/auth/simulation/genesis.go b/x/auth/simulation/genesis.go index f809042d1426..5309baf34917 100644 --- a/x/auth/simulation/genesis.go +++ b/x/auth/simulation/genesis.go @@ -9,10 +9,10 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" + "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/cosmos/cosmos-sdk/x/auth/exported" "github.com/cosmos/cosmos-sdk/x/auth/types" vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" - "github.com/cosmos/cosmos-sdk/x/simulation" ) // Simulation parameter constants diff --git a/x/auth/simulation/params.go b/x/auth/simulation/params.go index afca0348d3a5..a9240276ac31 100644 --- a/x/auth/simulation/params.go +++ b/x/auth/simulation/params.go @@ -6,8 +6,10 @@ import ( "fmt" "math/rand" - "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/cosmos/cosmos-sdk/x/simulation" + + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/cosmos/cosmos-sdk/x/auth/types" ) const ( @@ -18,8 +20,8 @@ const ( // ParamChanges defines the parameters that can be modified by param change proposals // on the simulation -func ParamChanges(r *rand.Rand) []simulation.ParamChange { - return []simulation.ParamChange{ +func ParamChanges(r *rand.Rand) []simtypes.ParamChange { + return []simtypes.ParamChange{ simulation.NewSimParamChange(types.ModuleName, keyMaxMemoCharacters, func(r *rand.Rand) string { return fmt.Sprintf("\"%d\"", GenMaxMemoChars(r)) diff --git a/x/bank/module.go b/x/bank/module.go index 7cb86714272c..9be8dab93913 100644 --- a/x/bank/module.go +++ b/x/bank/module.go @@ -7,19 +7,18 @@ import ( "github.com/gorilla/mux" "github.com/spf13/cobra" - abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/cosmos/cosmos-sdk/x/bank/client/cli" "github.com/cosmos/cosmos-sdk/x/bank/client/rest" "github.com/cosmos/cosmos-sdk/x/bank/keeper" "github.com/cosmos/cosmos-sdk/x/bank/simulation" "github.com/cosmos/cosmos-sdk/x/bank/types" - sim "github.com/cosmos/cosmos-sdk/x/simulation" ) var ( @@ -144,12 +143,12 @@ func (AppModule) GenerateGenesisState(simState *module.SimulationState) { } // ProposalContents doesn't return any content functions for governance proposals. -func (AppModule) ProposalContents(_ module.SimulationState) []sim.WeightedProposalContent { +func (AppModule) ProposalContents(simState module.SimulationState) []simtypes.WeightedProposalContent { return nil } // RandomizedParams creates randomized bank param changes for the simulator. -func (AppModule) RandomizedParams(r *rand.Rand) []sim.ParamChange { +func (AppModule) RandomizedParams(r *rand.Rand) []simtypes.ParamChange { return simulation.ParamChanges(r) } @@ -157,7 +156,7 @@ func (AppModule) RandomizedParams(r *rand.Rand) []sim.ParamChange { func (AppModule) RegisterStoreDecoder(_ sdk.StoreDecoderRegistry) {} // WeightedOperations returns the all the gov module operations with their respective weights. -func (am AppModule) WeightedOperations(simState module.SimulationState) []sim.WeightedOperation { +func (am AppModule) WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation { return simulation.WeightedOperations( simState.AppParams, simState.Cdc, am.accountKeeper, am.keeper, ) diff --git a/x/bank/simulation/operations.go b/x/bank/simulation/operations.go index c3ff22f9ceed..583929100a4d 100644 --- a/x/bank/simulation/operations.go +++ b/x/bank/simulation/operations.go @@ -10,6 +10,7 @@ import ( "github.com/cosmos/cosmos-sdk/simapp/helpers" simappparams "github.com/cosmos/cosmos-sdk/simapp/params" sdk "github.com/cosmos/cosmos-sdk/types" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/cosmos/cosmos-sdk/x/bank/keeper" "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/cosmos/cosmos-sdk/x/simulation" @@ -23,7 +24,7 @@ const ( // WeightedOperations returns all the operations from the module with their respective weights func WeightedOperations( - appParams simulation.AppParams, cdc *codec.Codec, ak types.AccountKeeper, bk keeper.Keeper, + appParams simtypes.AppParams, cdc *codec.Codec, ak types.AccountKeeper, bk keeper.Keeper, ) simulation.WeightedOperations { var weightMsgSend, weightMsgMultiSend int @@ -53,33 +54,33 @@ func WeightedOperations( // SimulateMsgSend tests and runs a single msg send where both // accounts already exist. -func SimulateMsgSend(ak types.AccountKeeper, bk keeper.Keeper) simulation.Operation { +func SimulateMsgSend(ak types.AccountKeeper, bk keeper.Keeper) simtypes.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, - accs []simulation.Account, chainID string, - ) (simulation.OperationMsg, []simulation.FutureOperation, error) { + accs []simtypes.Account, chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { if !bk.GetSendEnabled(ctx) { - return simulation.NoOpMsg(types.ModuleName), nil, nil + return simtypes.NoOpMsg(types.ModuleName), nil, nil } simAccount, toSimAcc, coins, skip, err := randomSendFields(r, ctx, accs, bk, ak) if err != nil { - return simulation.NoOpMsg(types.ModuleName), nil, err + return simtypes.NoOpMsg(types.ModuleName), nil, err } if skip { - return simulation.NoOpMsg(types.ModuleName), nil, nil + return simtypes.NoOpMsg(types.ModuleName), nil, nil } msg := types.NewMsgSend(simAccount.Address, toSimAcc.Address, coins) err = sendMsgSend(r, app, bk, ak, msg, ctx, chainID, []crypto.PrivKey{simAccount.PrivKey}) if err != nil { - return simulation.NoOpMsg(types.ModuleName), nil, err + return simtypes.NoOpMsg(types.ModuleName), nil, err } - return simulation.NewOperationMsg(msg, true, ""), nil, nil + return simtypes.NewOperationMsg(msg, true, ""), nil, nil } } @@ -100,7 +101,7 @@ func sendMsgSend( coins, hasNeg := spendable.SafeSub(msg.Amount) if !hasNeg { - fees, err = simulation.RandomFees(r, ctx, coins) + fees, err = simtypes.RandomFees(r, ctx, coins) if err != nil { return err } @@ -126,14 +127,14 @@ func sendMsgSend( // SimulateMsgMultiSend tests and runs a single msg multisend, with randomized, capped number of inputs/outputs. // all accounts in msg fields exist in state -func SimulateMsgMultiSend(ak types.AccountKeeper, bk keeper.Keeper) simulation.Operation { +func SimulateMsgMultiSend(ak types.AccountKeeper, bk keeper.Keeper) simtypes.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, - accs []simulation.Account, chainID string, - ) (simulation.OperationMsg, []simulation.FutureOperation, error) { + accs []simtypes.Account, chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { if !bk.GetSendEnabled(ctx) { - return simulation.NoOpMsg(types.ModuleName), nil, nil + return simtypes.NoOpMsg(types.ModuleName), nil, nil } // random number of inputs/outputs between [1, 3] @@ -157,10 +158,10 @@ func SimulateMsgMultiSend(ak types.AccountKeeper, bk keeper.Keeper) simulation.O } if err != nil { - return simulation.NoOpMsg(types.ModuleName), nil, err + return simtypes.NoOpMsg(types.ModuleName), nil, err } if skip { - return simulation.NoOpMsg(types.ModuleName), nil, nil + return simtypes.NoOpMsg(types.ModuleName), nil, nil } // set input address in used address map @@ -175,7 +176,7 @@ func SimulateMsgMultiSend(ak types.AccountKeeper, bk keeper.Keeper) simulation.O } for o := range outputs { - outAddr, _ := simulation.RandomAcc(r, accs) + outAddr, _ := simtypes.RandomAcc(r, accs) var outCoins sdk.Coins // split total sent coins into random subsets for output @@ -184,7 +185,7 @@ func SimulateMsgMultiSend(ak types.AccountKeeper, bk keeper.Keeper) simulation.O } else { // take random subset of remaining coins for output // and update remaining coins - outCoins = simulation.RandSubsetCoins(r, totalSentCoins) + outCoins = simtypes.RandSubsetCoins(r, totalSentCoins) totalSentCoins = totalSentCoins.Sub(outCoins) } @@ -210,10 +211,10 @@ func SimulateMsgMultiSend(ak types.AccountKeeper, bk keeper.Keeper) simulation.O err := sendMsgMultiSend(r, app, bk, ak, msg, ctx, chainID, privs) if err != nil { - return simulation.NoOpMsg(types.ModuleName), nil, err + return simtypes.NoOpMsg(types.ModuleName), nil, err } - return simulation.NewOperationMsg(msg, true, ""), nil, nil + return simtypes.NewOperationMsg(msg, true, ""), nil, nil } } @@ -245,7 +246,7 @@ func sendMsgMultiSend( coins, hasNeg := spendable.SafeSub(msg.Inputs[0].Coins) if !hasNeg { - fees, err = simulation.RandomFees(r, ctx, coins) + fees, err = simtypes.RandomFees(r, ctx, coins) if err != nil { return err } @@ -273,15 +274,15 @@ func sendMsgMultiSend( // as the transferred amount. // nolint: interfacer func randomSendFields( - r *rand.Rand, ctx sdk.Context, accs []simulation.Account, bk keeper.Keeper, ak types.AccountKeeper, -) (simulation.Account, simulation.Account, sdk.Coins, bool, error) { + r *rand.Rand, ctx sdk.Context, accs []simtypes.Account, bk keeper.Keeper, ak types.AccountKeeper, +) (simtypes.Account, simtypes.Account, sdk.Coins, bool, error) { - simAccount, _ := simulation.RandomAcc(r, accs) - toSimAcc, _ := simulation.RandomAcc(r, accs) + simAccount, _ := simtypes.RandomAcc(r, accs) + toSimAcc, _ := simtypes.RandomAcc(r, accs) // disallow sending money to yourself for simAccount.PubKey.Equals(toSimAcc.PubKey) { - toSimAcc, _ = simulation.RandomAcc(r, accs) + toSimAcc, _ = simtypes.RandomAcc(r, accs) } acc := ak.GetAccount(ctx, simAccount.Address) @@ -291,7 +292,7 @@ func randomSendFields( spendable := bk.SpendableCoins(ctx, acc.GetAddress()) - sendCoins := simulation.RandSubsetCoins(r, spendable) + sendCoins := simtypes.RandSubsetCoins(r, spendable) if sendCoins.Empty() { return simAccount, toSimAcc, nil, true, nil // skip error } diff --git a/x/bank/simulation/params.go b/x/bank/simulation/params.go index 458a8a09a16e..1117197279ab 100644 --- a/x/bank/simulation/params.go +++ b/x/bank/simulation/params.go @@ -6,16 +6,18 @@ import ( "fmt" "math/rand" - "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/cosmos/cosmos-sdk/x/simulation" + + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/cosmos/cosmos-sdk/x/bank/types" ) const keySendEnabled = "sendenabled" // ParamChanges defines the parameters that can be modified by param change proposals // on the simulation -func ParamChanges(r *rand.Rand) []simulation.ParamChange { - return []simulation.ParamChange{ +func ParamChanges(r *rand.Rand) []simtypes.ParamChange { + return []simtypes.ParamChange{ simulation.NewSimParamChange(types.ModuleName, keySendEnabled, func(r *rand.Rand) string { return fmt.Sprintf("%v", GenSendEnabled(r)) diff --git a/x/distribution/module.go b/x/distribution/module.go index dfa1b10244e9..474f1ba0f193 100644 --- a/x/distribution/module.go +++ b/x/distribution/module.go @@ -7,18 +7,17 @@ import ( "github.com/gorilla/mux" "github.com/spf13/cobra" - abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/cosmos/cosmos-sdk/x/distribution/client/cli" "github.com/cosmos/cosmos-sdk/x/distribution/client/rest" "github.com/cosmos/cosmos-sdk/x/distribution/simulation" "github.com/cosmos/cosmos-sdk/x/distribution/types" - sim "github.com/cosmos/cosmos-sdk/x/simulation" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" ) @@ -168,12 +167,12 @@ func (AppModule) GenerateGenesisState(simState *module.SimulationState) { // ProposalContents returns all the distribution content functions used to // simulate governance proposals. -func (am AppModule) ProposalContents(_ module.SimulationState) []sim.WeightedProposalContent { +func (am AppModule) ProposalContents(simState module.SimulationState) []simtypes.WeightedProposalContent { return simulation.ProposalContents(am.keeper) } // RandomizedParams creates randomized distribution param changes for the simulator. -func (AppModule) RandomizedParams(r *rand.Rand) []sim.ParamChange { +func (AppModule) RandomizedParams(r *rand.Rand) []simtypes.ParamChange { return simulation.ParamChanges(r) } @@ -183,7 +182,7 @@ func (AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { } // WeightedOperations returns the all the gov module operations with their respective weights. -func (am AppModule) WeightedOperations(simState module.SimulationState) []sim.WeightedOperation { +func (am AppModule) WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation { return simulation.WeightedOperations( simState.AppParams, simState.Cdc, am.accountKeeper, am.bankKeeper, am.keeper, am.stakingKeeper, ) diff --git a/x/distribution/simulation/operations.go b/x/distribution/simulation/operations.go index f134861ab139..cd1fbaa02061 100644 --- a/x/distribution/simulation/operations.go +++ b/x/distribution/simulation/operations.go @@ -9,6 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/simapp/helpers" simappparams "github.com/cosmos/cosmos-sdk/simapp/params" sdk "github.com/cosmos/cosmos-sdk/types" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/cosmos/cosmos-sdk/x/distribution/keeper" "github.com/cosmos/cosmos-sdk/x/distribution/types" "github.com/cosmos/cosmos-sdk/x/simulation" @@ -25,7 +26,7 @@ const ( // WeightedOperations returns all the operations from the module with their respective weights func WeightedOperations( - appParams simulation.AppParams, cdc *codec.Codec, ak types.AccountKeeper, + appParams simtypes.AppParams, cdc *codec.Codec, ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, sk stakingkeeper.Keeper, ) simulation.WeightedOperations { @@ -78,23 +79,23 @@ func WeightedOperations( } // SimulateMsgSetWithdrawAddress generates a MsgSetWithdrawAddress with random values. -func SimulateMsgSetWithdrawAddress(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simulation.Operation { +func SimulateMsgSetWithdrawAddress(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simtypes.Operation { return func( - r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, - ) (simulation.OperationMsg, []simulation.FutureOperation, error) { + r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { if !k.GetWithdrawAddrEnabled(ctx) { - return simulation.NoOpMsg(types.ModuleName), nil, nil + return simtypes.NoOpMsg(types.ModuleName), nil, nil } - simAccount, _ := simulation.RandomAcc(r, accs) - simToAccount, _ := simulation.RandomAcc(r, accs) + simAccount, _ := simtypes.RandomAcc(r, accs) + simToAccount, _ := simtypes.RandomAcc(r, accs) account := ak.GetAccount(ctx, simAccount.Address) spendable := bk.SpendableCoins(ctx, account.GetAddress()) - fees, err := simulation.RandomFees(r, ctx, spendable) + fees, err := simtypes.RandomFees(r, ctx, spendable) if err != nil { - return simulation.NoOpMsg(types.ModuleName), nil, err + return simtypes.NoOpMsg(types.ModuleName), nil, err } msg := types.NewMsgSetWithdrawAddress(simAccount.Address, simToAccount.Address) @@ -111,37 +112,37 @@ func SimulateMsgSetWithdrawAddress(ak types.AccountKeeper, bk types.BankKeeper, _, _, err = app.Deliver(tx) if err != nil { - return simulation.NoOpMsg(types.ModuleName), nil, err + return simtypes.NoOpMsg(types.ModuleName), nil, err } - return simulation.NewOperationMsg(msg, true, ""), nil, nil + return simtypes.NewOperationMsg(msg, true, ""), nil, nil } } // SimulateMsgWithdrawDelegatorReward generates a MsgWithdrawDelegatorReward with random values. -func SimulateMsgWithdrawDelegatorReward(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, sk stakingkeeper.Keeper) simulation.Operation { +func SimulateMsgWithdrawDelegatorReward(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, sk stakingkeeper.Keeper) simtypes.Operation { return func( - r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, - ) (simulation.OperationMsg, []simulation.FutureOperation, error) { - simAccount, _ := simulation.RandomAcc(r, accs) + r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + simAccount, _ := simtypes.RandomAcc(r, accs) delegations := sk.GetAllDelegatorDelegations(ctx, simAccount.Address) if len(delegations) == 0 { - return simulation.NoOpMsg(types.ModuleName), nil, nil + return simtypes.NoOpMsg(types.ModuleName), nil, nil } delegation := delegations[r.Intn(len(delegations))] validator := sk.Validator(ctx, delegation.GetValidatorAddr()) if validator == nil { - return simulation.NoOpMsg(types.ModuleName), nil, fmt.Errorf("validator %s not found", delegation.GetValidatorAddr()) + return simtypes.NoOpMsg(types.ModuleName), nil, fmt.Errorf("validator %s not found", delegation.GetValidatorAddr()) } account := ak.GetAccount(ctx, simAccount.Address) spendable := bk.SpendableCoins(ctx, account.GetAddress()) - fees, err := simulation.RandomFees(r, ctx, spendable) + fees, err := simtypes.RandomFees(r, ctx, spendable) if err != nil { - return simulation.NoOpMsg(types.ModuleName), nil, err + return simtypes.NoOpMsg(types.ModuleName), nil, err } msg := types.NewMsgWithdrawDelegatorReward(simAccount.Address, validator.GetOperator()) @@ -158,40 +159,40 @@ func SimulateMsgWithdrawDelegatorReward(ak types.AccountKeeper, bk types.BankKee _, _, err = app.Deliver(tx) if err != nil { - return simulation.NoOpMsg(types.ModuleName), nil, err + return simtypes.NoOpMsg(types.ModuleName), nil, err } - return simulation.NewOperationMsg(msg, true, ""), nil, nil + return simtypes.NewOperationMsg(msg, true, ""), nil, nil } } // SimulateMsgWithdrawValidatorCommission generates a MsgWithdrawValidatorCommission with random values. -func SimulateMsgWithdrawValidatorCommission(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, sk stakingkeeper.Keeper) simulation.Operation { +func SimulateMsgWithdrawValidatorCommission(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, sk stakingkeeper.Keeper) simtypes.Operation { return func( - r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, - ) (simulation.OperationMsg, []simulation.FutureOperation, error) { + r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { validator, ok := stakingkeeper.RandomValidator(r, sk, ctx) if !ok { - return simulation.NoOpMsg(types.ModuleName), nil, nil + return simtypes.NoOpMsg(types.ModuleName), nil, nil } commission := k.GetValidatorAccumulatedCommission(ctx, validator.GetOperator()) if commission.Commission.IsZero() { - return simulation.NoOpMsg(types.ModuleName), nil, nil + return simtypes.NoOpMsg(types.ModuleName), nil, nil } - simAccount, found := simulation.FindAccount(accs, sdk.AccAddress(validator.GetOperator())) + simAccount, found := simtypes.FindAccount(accs, sdk.AccAddress(validator.GetOperator())) if !found { - return simulation.NoOpMsg(types.ModuleName), nil, fmt.Errorf("validator %s not found", validator.GetOperator()) + return simtypes.NoOpMsg(types.ModuleName), nil, fmt.Errorf("validator %s not found", validator.GetOperator()) } account := ak.GetAccount(ctx, simAccount.Address) spendable := bk.SpendableCoins(ctx, account.GetAddress()) - fees, err := simulation.RandomFees(r, ctx, spendable) + fees, err := simtypes.RandomFees(r, ctx, spendable) if err != nil { - return simulation.NoOpMsg(types.ModuleName), nil, err + return simtypes.NoOpMsg(types.ModuleName), nil, err } msg := types.NewMsgWithdrawValidatorCommission(validator.GetOperator()) @@ -208,28 +209,28 @@ func SimulateMsgWithdrawValidatorCommission(ak types.AccountKeeper, bk types.Ban _, _, err = app.Deliver(tx) if err != nil { - return simulation.NoOpMsg(types.ModuleName), nil, err + return simtypes.NoOpMsg(types.ModuleName), nil, err } - return simulation.NewOperationMsg(msg, true, ""), nil, nil + return simtypes.NewOperationMsg(msg, true, ""), nil, nil } } // SimulateMsgFundCommunityPool simulates MsgFundCommunityPool execution where // a random account sends a random amount of its funds to the community pool. -func SimulateMsgFundCommunityPool(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, sk stakingkeeper.Keeper) simulation.Operation { +func SimulateMsgFundCommunityPool(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, sk stakingkeeper.Keeper) simtypes.Operation { return func( - r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, - ) (simulation.OperationMsg, []simulation.FutureOperation, error) { + r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { - funder, _ := simulation.RandomAcc(r, accs) + funder, _ := simtypes.RandomAcc(r, accs) account := ak.GetAccount(ctx, funder.Address) spendable := bk.SpendableCoins(ctx, account.GetAddress()) - fundAmount := simulation.RandSubsetCoins(r, spendable) + fundAmount := simtypes.RandSubsetCoins(r, spendable) if fundAmount.Empty() { - return simulation.NoOpMsg(types.ModuleName), nil, nil + return simtypes.NoOpMsg(types.ModuleName), nil, nil } var ( @@ -239,9 +240,9 @@ func SimulateMsgFundCommunityPool(ak types.AccountKeeper, bk types.BankKeeper, k coins, hasNeg := spendable.SafeSub(fundAmount) if !hasNeg { - fees, err = simulation.RandomFees(r, ctx, coins) + fees, err = simtypes.RandomFees(r, ctx, coins) if err != nil { - return simulation.NoOpMsg(types.ModuleName), nil, err + return simtypes.NoOpMsg(types.ModuleName), nil, err } } @@ -258,9 +259,9 @@ func SimulateMsgFundCommunityPool(ak types.AccountKeeper, bk types.BankKeeper, k _, _, err = app.Deliver(tx) if err != nil { - return simulation.NoOpMsg(types.ModuleName), nil, err + return simtypes.NoOpMsg(types.ModuleName), nil, err } - return simulation.NewOperationMsg(msg, true, ""), nil, nil + return simtypes.NewOperationMsg(msg, true, ""), nil, nil } } diff --git a/x/distribution/simulation/params.go b/x/distribution/simulation/params.go index 60c591a6dc3b..98fcec342fd9 100644 --- a/x/distribution/simulation/params.go +++ b/x/distribution/simulation/params.go @@ -6,8 +6,10 @@ import ( "fmt" "math/rand" - "github.com/cosmos/cosmos-sdk/x/distribution/types" "github.com/cosmos/cosmos-sdk/x/simulation" + + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/cosmos/cosmos-sdk/x/distribution/types" ) const ( @@ -18,8 +20,8 @@ const ( // ParamChanges defines the parameters that can be modified by param change proposals // on the simulation -func ParamChanges(r *rand.Rand) []simulation.ParamChange { - return []simulation.ParamChange{ +func ParamChanges(r *rand.Rand) []simtypes.ParamChange { + return []simtypes.ParamChange{ simulation.NewSimParamChange(types.ModuleName, keyCommunityTax, func(r *rand.Rand) string { return fmt.Sprintf("\"%s\"", GenCommunityTax(r)) diff --git a/x/distribution/simulation/proposals.go b/x/distribution/simulation/proposals.go index f212397b5342..719229cb96f3 100644 --- a/x/distribution/simulation/proposals.go +++ b/x/distribution/simulation/proposals.go @@ -5,9 +5,9 @@ import ( simappparams "github.com/cosmos/cosmos-sdk/simapp/params" sdk "github.com/cosmos/cosmos-sdk/types" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/cosmos/cosmos-sdk/x/distribution/keeper" "github.com/cosmos/cosmos-sdk/x/distribution/types" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/cosmos/cosmos-sdk/x/simulation" ) @@ -15,20 +15,20 @@ import ( const OpWeightSubmitCommunitySpendProposal = "op_weight_submit_community_spend_proposal" // ProposalContents defines the module weighted proposals' contents -func ProposalContents(k keeper.Keeper) []simulation.WeightedProposalContent { - return []simulation.WeightedProposalContent{ - { - AppParamsKey: OpWeightSubmitCommunitySpendProposal, - DefaultWeight: simappparams.DefaultWeightCommunitySpendProposal, - ContentSimulatorFn: SimulateCommunityPoolSpendProposalContent(k), - }, +func ProposalContents(k keeper.Keeper) []simtypes.WeightedProposalContent { + return []simtypes.WeightedProposalContent{ + simulation.NewWeightedProposalContent( + OpWeightSubmitCommunitySpendProposal, + simappparams.DefaultWeightCommunitySpendProposal, + SimulateCommunityPoolSpendProposalContent(k), + ), } } // SimulateCommunityPoolSpendProposalContent generates random community-pool-spend proposal content -func SimulateCommunityPoolSpendProposalContent(k keeper.Keeper) simulation.ContentSimulatorFn { - return func(r *rand.Rand, ctx sdk.Context, accs []simulation.Account) govtypes.Content { - simAccount, _ := simulation.RandomAcc(r, accs) +func SimulateCommunityPoolSpendProposalContent(k keeper.Keeper) simtypes.ContentSimulatorFn { + return func(r *rand.Rand, ctx sdk.Context, accs []simtypes.Account) simtypes.Content { + simAccount, _ := simtypes.RandomAcc(r, accs) balance := k.GetFeePool(ctx).CommunityPool if balance.Empty() { @@ -36,14 +36,14 @@ func SimulateCommunityPoolSpendProposalContent(k keeper.Keeper) simulation.Conte } denomIndex := r.Intn(len(balance)) - amount, err := simulation.RandPositiveInt(r, balance[denomIndex].Amount.TruncateInt()) + amount, err := simtypes.RandPositiveInt(r, balance[denomIndex].Amount.TruncateInt()) if err != nil { return nil } return types.NewCommunityPoolSpendProposal( - simulation.RandStringOfLength(r, 10), - simulation.RandStringOfLength(r, 100), + simtypes.RandStringOfLength(r, 10), + simtypes.RandStringOfLength(r, 100), simAccount.Address, sdk.NewCoins(sdk.NewCoin(balance[denomIndex].Denom, amount)), ) diff --git a/x/gov/module.go b/x/gov/module.go index 5d07091fd1ab..624ca5928f91 100644 --- a/x/gov/module.go +++ b/x/gov/module.go @@ -16,12 +16,12 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/cosmos/cosmos-sdk/x/gov/client" "github.com/cosmos/cosmos-sdk/x/gov/client/cli" "github.com/cosmos/cosmos-sdk/x/gov/client/rest" "github.com/cosmos/cosmos-sdk/x/gov/simulation" "github.com/cosmos/cosmos-sdk/x/gov/types" - sim "github.com/cosmos/cosmos-sdk/x/simulation" ) var ( @@ -184,12 +184,12 @@ func (AppModule) GenerateGenesisState(simState *module.SimulationState) { // ProposalContents returns all the gov content functions used to // simulate governance proposals. -func (AppModule) ProposalContents(_ module.SimulationState) []sim.WeightedProposalContent { +func (AppModule) ProposalContents(simState module.SimulationState) []simtypes.WeightedProposalContent { return simulation.ProposalContents() } // RandomizedParams creates randomized gov param changes for the simulator. -func (AppModule) RandomizedParams(r *rand.Rand) []sim.ParamChange { +func (AppModule) RandomizedParams(r *rand.Rand) []simtypes.ParamChange { return simulation.ParamChanges(r) } @@ -199,7 +199,7 @@ func (AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { } // WeightedOperations returns the all the gov module operations with their respective weights. -func (am AppModule) WeightedOperations(simState module.SimulationState) []sim.WeightedOperation { +func (am AppModule) WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation { return simulation.WeightedOperations( simState.AppParams, simState.Cdc, am.accountKeeper, am.bankKeeper, am.keeper, simState.Contents, diff --git a/x/gov/simulation/genesis.go b/x/gov/simulation/genesis.go index f2541643bd36..694c54e651bf 100644 --- a/x/gov/simulation/genesis.go +++ b/x/gov/simulation/genesis.go @@ -11,8 +11,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" + "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/cosmos/cosmos-sdk/x/gov/types" - "github.com/cosmos/cosmos-sdk/x/simulation" ) // Simulation parameter constants diff --git a/x/gov/simulation/operations.go b/x/gov/simulation/operations.go index 608585adaf84..883a2a5ed1e5 100644 --- a/x/gov/simulation/operations.go +++ b/x/gov/simulation/operations.go @@ -10,6 +10,7 @@ import ( "github.com/cosmos/cosmos-sdk/simapp/helpers" simappparams "github.com/cosmos/cosmos-sdk/simapp/params" sdk "github.com/cosmos/cosmos-sdk/types" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/cosmos/cosmos-sdk/x/gov/keeper" "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/cosmos/cosmos-sdk/x/simulation" @@ -25,8 +26,8 @@ const ( // WeightedOperations returns all the operations from the module with their respective weights func WeightedOperations( - appParams simulation.AppParams, cdc *codec.Codec, ak types.AccountKeeper, - bk types.BankKeeper, k keeper.Keeper, wContents []simulation.WeightedProposalContent, + appParams simtypes.AppParams, cdc *codec.Codec, ak types.AccountKeeper, + bk types.BankKeeper, k keeper.Keeper, wContents []simtypes.WeightedProposalContent, ) simulation.WeightedOperations { var ( @@ -52,14 +53,14 @@ func WeightedOperations( for _, wContent := range wContents { wContent := wContent // pin variable var weight int - appParams.GetOrGenerate(cdc, wContent.AppParamsKey, &weight, nil, - func(_ *rand.Rand) { weight = wContent.DefaultWeight }) + appParams.GetOrGenerate(cdc, wContent.AppParamsKey(), &weight, nil, + func(_ *rand.Rand) { weight = wContent.DefaultWeight() }) wProposalOps = append( wProposalOps, simulation.NewWeightedOperation( weight, - SimulateSubmitProposal(ak, bk, k, wContent.ContentSimulatorFn), + SimulateSubmitProposal(ak, bk, k, wContent.ContentSimulatorFn()), ), ) } @@ -82,8 +83,8 @@ func WeightedOperations( // voting on the proposal, and subsequently slashing the proposal. It is implemented using // future operations. func SimulateSubmitProposal( - ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, contentSim simulation.ContentSimulatorFn, -) simulation.Operation { + ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, contentSim simtypes.ContentSimulatorFn, +) simtypes.Operation { // The states are: // column 1: All validators vote // column 2: 90% vote @@ -107,21 +108,21 @@ func SimulateSubmitProposal( return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, - accs []simulation.Account, chainID string, - ) (simulation.OperationMsg, []simulation.FutureOperation, error) { + accs []simtypes.Account, chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { // 1) submit proposal now content := contentSim(r, ctx, accs) if content == nil { - return simulation.NoOpMsg(types.ModuleName), nil, nil + return simtypes.NoOpMsg(types.ModuleName), nil, nil } - simAccount, _ := simulation.RandomAcc(r, accs) + simAccount, _ := simtypes.RandomAcc(r, accs) deposit, skip, err := randomDeposit(r, ctx, ak, bk, k, simAccount.Address) switch { case skip: - return simulation.NoOpMsg(types.ModuleName), nil, nil + return simtypes.NoOpMsg(types.ModuleName), nil, nil case err != nil: - return simulation.NoOpMsg(types.ModuleName), nil, err + return simtypes.NoOpMsg(types.ModuleName), nil, err } msg := types.NewMsgSubmitProposal(content, deposit, simAccount.Address) @@ -132,9 +133,9 @@ func SimulateSubmitProposal( var fees sdk.Coins coins, hasNeg := spendable.SafeSub(deposit) if !hasNeg { - fees, err = simulation.RandomFees(r, ctx, coins) + fees, err = simtypes.RandomFees(r, ctx, coins) if err != nil { - return simulation.NoOpMsg(types.ModuleName), nil, err + return simtypes.NoOpMsg(types.ModuleName), nil, err } } @@ -150,15 +151,15 @@ func SimulateSubmitProposal( _, _, err = app.Deliver(tx) if err != nil { - return simulation.NoOpMsg(types.ModuleName), nil, err + return simtypes.NoOpMsg(types.ModuleName), nil, err } - opMsg := simulation.NewOperationMsg(msg, true, "") + opMsg := simtypes.NewOperationMsg(msg, true, "") // get the submitted proposal ID proposalID, err := k.GetProposalID(ctx) if err != nil { - return simulation.NoOpMsg(types.ModuleName), nil, err + return simtypes.NoOpMsg(types.ModuleName), nil, err } // 2) Schedule operations for votes @@ -173,10 +174,10 @@ func SimulateSubmitProposal( whoVotes = whoVotes[:numVotes] votingPeriod := k.GetVotingParams(ctx).VotingPeriod - fops := make([]simulation.FutureOperation, numVotes+1) + fops := make([]simtypes.FutureOperation, numVotes+1) for i := 0; i < numVotes; i++ { whenVote := ctx.BlockHeader().Time.Add(time.Duration(r.Int63n(int64(votingPeriod.Seconds()))) * time.Second) - fops[i] = simulation.FutureOperation{ + fops[i] = simtypes.FutureOperation{ BlockTime: whenVote, Op: operationSimulateMsgVote(ak, bk, k, accs[whoVotes[i]], int64(proposalID)), } @@ -187,23 +188,23 @@ func SimulateSubmitProposal( } // SimulateMsgDeposit generates a MsgDeposit with random values. -func SimulateMsgDeposit(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simulation.Operation { +func SimulateMsgDeposit(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simtypes.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, - accs []simulation.Account, chainID string, - ) (simulation.OperationMsg, []simulation.FutureOperation, error) { - simAccount, _ := simulation.RandomAcc(r, accs) + accs []simtypes.Account, chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + simAccount, _ := simtypes.RandomAcc(r, accs) proposalID, ok := randomProposalID(r, k, ctx, types.StatusDepositPeriod) if !ok { - return simulation.NoOpMsg(types.ModuleName), nil, nil + return simtypes.NoOpMsg(types.ModuleName), nil, nil } deposit, skip, err := randomDeposit(r, ctx, ak, bk, k, simAccount.Address) switch { case skip: - return simulation.NoOpMsg(types.ModuleName), nil, nil + return simtypes.NoOpMsg(types.ModuleName), nil, nil case err != nil: - return simulation.NoOpMsg(types.ModuleName), nil, err + return simtypes.NoOpMsg(types.ModuleName), nil, err } msg := types.NewMsgDeposit(simAccount.Address, proposalID, deposit) @@ -214,9 +215,9 @@ func SimulateMsgDeposit(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Ke var fees sdk.Coins coins, hasNeg := spendable.SafeSub(deposit) if !hasNeg { - fees, err = simulation.RandomFees(r, ctx, coins) + fees, err = simtypes.RandomFees(r, ctx, coins) if err != nil { - return simulation.NoOpMsg(types.ModuleName), nil, err + return simtypes.NoOpMsg(types.ModuleName), nil, err } } @@ -232,26 +233,26 @@ func SimulateMsgDeposit(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Ke _, _, err = app.Deliver(tx) if err != nil { - return simulation.NoOpMsg(types.ModuleName), nil, err + return simtypes.NoOpMsg(types.ModuleName), nil, err } - return simulation.NewOperationMsg(msg, true, ""), nil, nil + return simtypes.NewOperationMsg(msg, true, ""), nil, nil } } // SimulateMsgVote generates a MsgVote with random values. -func SimulateMsgVote(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simulation.Operation { - return operationSimulateMsgVote(ak, bk, k, simulation.Account{}, -1) +func SimulateMsgVote(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simtypes.Operation { + return operationSimulateMsgVote(ak, bk, k, simtypes.Account{}, -1) } func operationSimulateMsgVote(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, - simAccount simulation.Account, proposalIDInt int64) simulation.Operation { + simAccount simtypes.Account, proposalIDInt int64) simtypes.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, - accs []simulation.Account, chainID string, - ) (simulation.OperationMsg, []simulation.FutureOperation, error) { - if simAccount.Equals(simulation.Account{}) { - simAccount, _ = simulation.RandomAcc(r, accs) + accs []simtypes.Account, chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + if simAccount.Equals(simtypes.Account{}) { + simAccount, _ = simtypes.RandomAcc(r, accs) } var proposalID uint64 @@ -261,7 +262,7 @@ func operationSimulateMsgVote(ak types.AccountKeeper, bk types.BankKeeper, k kee var ok bool proposalID, ok = randomProposalID(r, k, ctx, types.StatusVotingPeriod) if !ok { - return simulation.NoOpMsg(types.ModuleName), nil, nil + return simtypes.NoOpMsg(types.ModuleName), nil, nil } default: proposalID = uint64(proposalIDInt) @@ -273,9 +274,9 @@ func operationSimulateMsgVote(ak types.AccountKeeper, bk types.BankKeeper, k kee account := ak.GetAccount(ctx, simAccount.Address) spendable := bk.SpendableCoins(ctx, account.GetAddress()) - fees, err := simulation.RandomFees(r, ctx, spendable) + fees, err := simtypes.RandomFees(r, ctx, spendable) if err != nil { - return simulation.NoOpMsg(types.ModuleName), nil, err + return simtypes.NoOpMsg(types.ModuleName), nil, err } tx := helpers.GenTx( @@ -290,10 +291,10 @@ func operationSimulateMsgVote(ak types.AccountKeeper, bk types.BankKeeper, k kee _, _, err = app.Deliver(tx) if err != nil { - return simulation.NoOpMsg(types.ModuleName), nil, err + return simtypes.NoOpMsg(types.ModuleName), nil, err } - return simulation.NewOperationMsg(msg, true, ""), nil, nil + return simtypes.NewOperationMsg(msg, true, ""), nil, nil } } @@ -325,7 +326,7 @@ func randomDeposit(r *rand.Rand, ctx sdk.Context, maxAmt = minDeposit[denomIndex].Amount } - amount, err := simulation.RandPositiveInt(r, maxAmt) + amount, err := simtypes.RandPositiveInt(r, maxAmt) if err != nil { return nil, false, err } @@ -344,7 +345,7 @@ func randomProposalID(r *rand.Rand, k keeper.Keeper, switch { case proposalID > initialProposalID: // select a random ID between [initialProposalID, proposalID] - proposalID = uint64(simulation.RandIntBetween(r, int(initialProposalID), int(proposalID))) + proposalID = uint64(simtypes.RandIntBetween(r, int(initialProposalID), int(proposalID))) default: // This is called on the first call to this funcion diff --git a/x/gov/simulation/params.go b/x/gov/simulation/params.go index 420b5a8eec78..c0f0ac05aecf 100644 --- a/x/gov/simulation/params.go +++ b/x/gov/simulation/params.go @@ -8,6 +8,7 @@ import ( "math/rand" sdk "github.com/cosmos/cosmos-sdk/types" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/cosmos/cosmos-sdk/x/simulation" ) @@ -23,8 +24,8 @@ const ( // ParamChanges defines the parameters that can be modified by param change proposals // on the simulation -func ParamChanges(r *rand.Rand) []simulation.ParamChange { - return []simulation.ParamChange{ +func ParamChanges(r *rand.Rand) []simtypes.ParamChange { + return []simtypes.ParamChange{ simulation.NewSimParamChange(types.ModuleName, keyVotingParams, func(r *rand.Rand) string { return fmt.Sprintf(`{"voting_period": "%d"}`, GenVotingParamsVotingPeriod(r)) @@ -47,7 +48,7 @@ func ParamChanges(r *rand.Rand) []simulation.ParamChange { } pc := make(map[string]string) - numChanges := simulation.RandIntBetween(r, 1, len(changes)) + numChanges := simtypes.RandIntBetween(r, 1, len(changes)) for i := 0; i < numChanges; i++ { c := changes[r.Intn(len(changes))] diff --git a/x/gov/simulation/proposals.go b/x/gov/simulation/proposals.go index b3d73d15c349..322774c984eb 100644 --- a/x/gov/simulation/proposals.go +++ b/x/gov/simulation/proposals.go @@ -5,6 +5,7 @@ import ( simappparams "github.com/cosmos/cosmos-sdk/simapp/params" sdk "github.com/cosmos/cosmos-sdk/types" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/cosmos/cosmos-sdk/x/simulation" ) @@ -13,20 +14,20 @@ import ( const OpWeightSubmitTextProposal = "op_weight_submit_text_proposal" // ProposalContents defines the module weighted proposals' contents -func ProposalContents() []simulation.WeightedProposalContent { - return []simulation.WeightedProposalContent{ - { - AppParamsKey: OpWeightSubmitTextProposal, - DefaultWeight: simappparams.DefaultWeightTextProposal, - ContentSimulatorFn: SimulateTextProposalContent, - }, +func ProposalContents() []simtypes.WeightedProposalContent { + return []simtypes.WeightedProposalContent{ + simulation.NewWeightedProposalContent( + OpWeightMsgDeposit, + simappparams.DefaultWeightTextProposal, + SimulateTextProposalContent, + ), } } // SimulateTextProposalContent returns a random text proposal content. -func SimulateTextProposalContent(r *rand.Rand, _ sdk.Context, _ []simulation.Account) types.Content { +func SimulateTextProposalContent(r *rand.Rand, _ sdk.Context, _ []simtypes.Account) simtypes.Content { return types.NewTextProposal( - simulation.RandStringOfLength(r, 140), - simulation.RandStringOfLength(r, 5000), + simtypes.RandStringOfLength(r, 140), + simtypes.RandStringOfLength(r, 5000), ) } diff --git a/x/gov/types/content.go b/x/gov/types/content.go index 21d70d5ab1e8..44cbe6af7547 100644 --- a/x/gov/types/content.go +++ b/x/gov/types/content.go @@ -17,6 +17,8 @@ const ( // information such as the title and description along with the type and routing // information for the appropriate handler to process the proposal. Content can // have additional fields, which will handled by a proposal's Handler. +// TODO Try to unify this interface with types/module/simulation +// https://github.com/cosmos/cosmos-sdk/issues/5853 type Content interface { GetTitle() string GetDescription() string diff --git a/x/mint/module.go b/x/mint/module.go index 88c03dfea20d..914cb2545df3 100644 --- a/x/mint/module.go +++ b/x/mint/module.go @@ -16,10 +16,10 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/cosmos/cosmos-sdk/x/mint/client/cli" "github.com/cosmos/cosmos-sdk/x/mint/client/rest" "github.com/cosmos/cosmos-sdk/x/mint/simulation" - sim "github.com/cosmos/cosmos-sdk/x/simulation" ) var ( @@ -152,12 +152,12 @@ func (AppModule) GenerateGenesisState(simState *module.SimulationState) { } // ProposalContents doesn't return any content functions for governance proposals. -func (AppModule) ProposalContents(_ module.SimulationState) []sim.WeightedProposalContent { +func (AppModule) ProposalContents(simState module.SimulationState) []simtypes.WeightedProposalContent { return nil } // RandomizedParams creates randomized mint param changes for the simulator. -func (AppModule) RandomizedParams(r *rand.Rand) []sim.ParamChange { +func (AppModule) RandomizedParams(r *rand.Rand) []simtypes.ParamChange { return simulation.ParamChanges(r) } @@ -167,6 +167,6 @@ func (AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { } // WeightedOperations doesn't return any mint module operation. -func (AppModule) WeightedOperations(_ module.SimulationState) []sim.WeightedOperation { +func (AppModule) WeightedOperations(_ module.SimulationState) []simtypes.WeightedOperation { return nil } diff --git a/x/mint/simulation/params.go b/x/mint/simulation/params.go index a467ac0fbf59..b75b0fc7000c 100644 --- a/x/mint/simulation/params.go +++ b/x/mint/simulation/params.go @@ -6,8 +6,10 @@ import ( "fmt" "math/rand" - "github.com/cosmos/cosmos-sdk/x/mint/types" "github.com/cosmos/cosmos-sdk/x/simulation" + + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/cosmos/cosmos-sdk/x/mint/types" ) const ( @@ -19,8 +21,8 @@ const ( // ParamChanges defines the parameters that can be modified by param change proposals // on the simulation -func ParamChanges(r *rand.Rand) []simulation.ParamChange { - return []simulation.ParamChange{ +func ParamChanges(r *rand.Rand) []simtypes.ParamChange { + return []simtypes.ParamChange{ simulation.NewSimParamChange(types.ModuleName, keyInflationRateChange, func(r *rand.Rand) string { return fmt.Sprintf("\"%s\"", GenInflationRateChange(r)) diff --git a/x/params/module.go b/x/params/module.go index 0510ed5f92c9..0aca58729456 100644 --- a/x/params/module.go +++ b/x/params/module.go @@ -11,9 +11,9 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/cosmos/cosmos-sdk/x/params/simulation" "github.com/cosmos/cosmos-sdk/x/params/types/proposal" - sim "github.com/cosmos/cosmos-sdk/x/simulation" ) var ( @@ -74,12 +74,12 @@ func (AppModule) GenerateGenesisState(simState *module.SimulationState) { // ProposalContents returns all the params content functions used to // simulate governance proposals. -func (am AppModule) ProposalContents(simState module.SimulationState) []sim.WeightedProposalContent { +func (am AppModule) ProposalContents(simState module.SimulationState) []simtypes.WeightedProposalContent { return simulation.ProposalContents(simState.ParamChanges) } // RandomizedParams creates randomized distribution param changes for the simulator. -func (AppModule) RandomizedParams(r *rand.Rand) []sim.ParamChange { +func (AppModule) RandomizedParams(r *rand.Rand) []simtypes.ParamChange { return nil } @@ -87,6 +87,6 @@ func (AppModule) RandomizedParams(r *rand.Rand) []sim.ParamChange { func (AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) {} // WeightedOperations returns the all the gov module operations with their respective weights. -func (am AppModule) WeightedOperations(_ module.SimulationState) []sim.WeightedOperation { +func (am AppModule) WeightedOperations(_ module.SimulationState) []simtypes.WeightedOperation { return nil } diff --git a/x/params/simulation/operations.go b/x/params/simulation/operations.go index 82018b158b83..a5097968ce70 100644 --- a/x/params/simulation/operations.go +++ b/x/params/simulation/operations.go @@ -4,16 +4,15 @@ import ( "math/rand" sdk "github.com/cosmos/cosmos-sdk/types" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/cosmos/cosmos-sdk/x/params/types/proposal" - "github.com/cosmos/cosmos-sdk/x/simulation" ) // SimulateParamChangeProposalContent returns random parameter change content. // It will generate a ParameterChangeProposal object with anywhere between 1 and // the total amount of defined parameters changes, all of which have random valid values. func SimulateParamChangeProposalContent(paramChangePool []simulation.ParamChange) simulation.ContentSimulatorFn { - return func(r *rand.Rand, _ sdk.Context, _ []simulation.Account) govtypes.Content { + return func(r *rand.Rand, _ sdk.Context, _ []simulation.Account) simulation.Content { lenParamChange := len(paramChangePool) if lenParamChange == 0 { @@ -40,7 +39,7 @@ func SimulateParamChangeProposalContent(paramChangePool []simulation.ParamChange // add a new distinct parameter to the set of changes and register the key // to avoid further duplicates paramChangesKeys[spc.ComposedKey()] = struct{}{} - paramChanges[i] = proposal.NewParamChange(spc.Subspace, spc.Key, spc.SimValue(r)) + paramChanges[i] = proposal.NewParamChange(spc.Subspace(), spc.Key(), spc.SimValue()(r)) } return proposal.NewParameterChangeProposal( diff --git a/x/params/simulation/proposals.go b/x/params/simulation/proposals.go index ad1c37dd88b7..165193735fbd 100644 --- a/x/params/simulation/proposals.go +++ b/x/params/simulation/proposals.go @@ -2,6 +2,7 @@ package simulation import ( simappparams "github.com/cosmos/cosmos-sdk/simapp/params" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/cosmos/cosmos-sdk/x/simulation" ) @@ -9,12 +10,12 @@ import ( const OpWeightSubmitParamChangeProposal = "op_weight_submit_param_change_proposal" // ProposalContents defines the module weighted proposals' contents -func ProposalContents(paramChanges []simulation.ParamChange) []simulation.WeightedProposalContent { - return []simulation.WeightedProposalContent{ - { - AppParamsKey: OpWeightSubmitParamChangeProposal, - DefaultWeight: simappparams.DefaultWeightParamChangeProposal, - ContentSimulatorFn: SimulateParamChangeProposalContent(paramChanges), - }, +func ProposalContents(paramChanges []simtypes.ParamChange) []simtypes.WeightedProposalContent { + return []simtypes.WeightedProposalContent{ + simulation.NewWeightedProposalContent( + OpWeightSubmitParamChangeProposal, + simappparams.DefaultWeightParamChangeProposal, + SimulateParamChangeProposalContent(paramChanges), + ), } } diff --git a/x/simulation/mock_tendermint.go b/x/simulation/mock_tendermint.go index 349de27b60c2..127f14f32573 100644 --- a/x/simulation/mock_tendermint.go +++ b/x/simulation/mock_tendermint.go @@ -35,7 +35,7 @@ func newMockValidators(r *rand.Rand, abciVals []abci.ValidatorUpdate, for _, validator := range abciVals { str := fmt.Sprintf("%v", validator.PubKey) liveliness := GetMemberOfInitialState(r, - params.InitialLivenessWeightings) + params.InitialLivenessWeightings()) validators[str] = mockValidator{ val: validator, @@ -100,7 +100,7 @@ func updateValidators(tb testing.TB, r *rand.Rand, params Params, // Set this new validator current[str] = mockValidator{ update, - GetMemberOfInitialState(r, params.InitialLivenessWeightings), + GetMemberOfInitialState(r, params.InitialLivenessWeightings()), } event("end_block", "validator_updates", "added") } @@ -125,7 +125,7 @@ func RandomRequestBeginBlock(r *rand.Rand, params Params, voteInfos := make([]abci.VoteInfo, len(validators)) for i, key := range validators.getKeys() { mVal := validators[key] - mVal.livenessState = params.LivenessTransitionMatrix.NextState(r, mVal.livenessState) + mVal.livenessState = params.LivenessTransitionMatrix().NextState(r, mVal.livenessState) signed := true if mVal.livenessState == 1 { @@ -169,13 +169,13 @@ func RandomRequestBeginBlock(r *rand.Rand, params Params, // TODO: Determine capacity before allocation evidence := make([]abci.Evidence, 0) - for r.Float64() < params.EvidenceFraction { + for r.Float64() < params.EvidenceFraction() { height := header.Height time := header.Time vals := voteInfos - if r.Float64() < params.PastEvidenceFraction && header.Height > 1 { + if r.Float64() < params.PastEvidenceFraction() && header.Height > 1 { height = int64(r.Intn(int(header.Height)-1)) + 1 // Tendermint starts at height 1 // array indices offset by one time = pastTimes[height-1] diff --git a/x/simulation/operation.go b/x/simulation/operation.go index 8565b42961d7..1da136b552b1 100644 --- a/x/simulation/operation.go +++ b/x/simulation/operation.go @@ -4,25 +4,10 @@ import ( "encoding/json" "math/rand" "sort" - "time" - "github.com/cosmos/cosmos-sdk/baseapp" - sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/simulation" ) -// Operation runs a state machine transition, and ensures the transition -// happened as expected. The operation could be running and testing a fuzzed -// transaction, or doing the same for a message. -// -// For ease of debugging, an operation returns a descriptive message "action", -// which details what this fuzzed state machine transition actually did. -// -// Operations can optionally provide a list of "FutureOperations" to run later -// These will be ran at the beginning of the corresponding block. -type Operation func(r *rand.Rand, app *baseapp.BaseApp, - ctx sdk.Context, accounts []Account, chainID string) ( - OperationMsg OperationMsg, futureOps []FutureOperation, err error) - // entry kinds for use within OperationEntry const ( BeginBlockEntryKind = "begin_block" @@ -60,12 +45,12 @@ func EndBlockEntry(height int64) OperationEntry { } // MsgEntry - operation entry for standard msg -func MsgEntry(height, order int64, opMsg OperationMsg) OperationEntry { +func MsgEntry(height, order int64, opMsg simulation.OperationMsg) OperationEntry { return NewOperationEntry(MsgEntryKind, height, order, opMsg.MustMarshal()) } // QueuedMsgEntry creates an operation entry for a given queued message. -func QueuedMsgEntry(height int64, opMsg OperationMsg) OperationEntry { +func QueuedMsgEntry(height int64, opMsg simulation.OperationMsg) OperationEntry { return NewOperationEntry(QueuedMsgEntryKind, height, -1, opMsg.MustMarshal()) } @@ -80,65 +65,8 @@ func (oe OperationEntry) MustMarshal() json.RawMessage { //_____________________________________________________________________ -// OperationMsg - structure for operation output -type OperationMsg struct { - Route string `json:"route" yaml:"route"` // msg route (i.e module name) - Name string `json:"name" yaml:"name"` // operation name (msg Type or "no-operation") - Comment string `json:"comment" yaml:"comment"` // additional comment - OK bool `json:"ok" yaml:"ok"` // success - Msg json.RawMessage `json:"msg" yaml:"msg"` // JSON encoded msg -} - -// NewOperationMsgBasic creates a new operation message from raw input. -func NewOperationMsgBasic(route, name, comment string, ok bool, msg []byte) OperationMsg { - return OperationMsg{ - Route: route, - Name: name, - Comment: comment, - OK: ok, - Msg: msg, - } -} - -// NewOperationMsg - create a new operation message from sdk.Msg -func NewOperationMsg(msg sdk.Msg, ok bool, comment string) OperationMsg { - return NewOperationMsgBasic(msg.Route(), msg.Type(), comment, ok, msg.GetSignBytes()) -} - -// NoOpMsg - create a no-operation message -func NoOpMsg(route string) OperationMsg { - return NewOperationMsgBasic(route, "no-operation", "", false, nil) -} - -// log entry text for this operation msg -func (om OperationMsg) String() string { - out, err := json.Marshal(om) - if err != nil { - panic(err) - } - return string(out) -} - -// MustMarshal Marshals the operation msg, panic on error -func (om OperationMsg) MustMarshal() json.RawMessage { - out, err := json.Marshal(om) - if err != nil { - panic(err) - } - return out -} - -// LogEvent adds an event for the events stats -func (om OperationMsg) LogEvent(eventLogger func(route, op, evResult string)) { - pass := "ok" - if !om.OK { - pass = "failure" - } - eventLogger(om.Route, om.Name, pass) -} - // OperationQueue defines an object for a queue of operations -type OperationQueue map[int][]Operation +type OperationQueue map[int][]simulation.Operation // NewOperationQueue creates a new OperationQueue instance. func NewOperationQueue() OperationQueue { @@ -147,7 +75,7 @@ func NewOperationQueue() OperationQueue { // queueOperations adds all future operations into the operation queue. func queueOperations(queuedOps OperationQueue, - queuedTimeOps []FutureOperation, futureOps []FutureOperation) { + queuedTimeOps []simulation.FutureOperation, futureOps []simulation.FutureOperation) { if futureOps == nil { return @@ -159,7 +87,7 @@ func queueOperations(queuedOps OperationQueue, if val, ok := queuedOps[futureOp.BlockHeight]; ok { queuedOps[futureOp.BlockHeight] = append(val, futureOp.Op) } else { - queuedOps[futureOp.BlockHeight] = []Operation{futureOp.Op} + queuedOps[futureOp.BlockHeight] = []simulation.Operation{futureOp.Op} } continue } @@ -172,7 +100,7 @@ func queueOperations(queuedOps OperationQueue, return queuedTimeOps[i].BlockTime.After(futureOp.BlockTime) }, ) - queuedTimeOps = append(queuedTimeOps, FutureOperation{}) + queuedTimeOps = append(queuedTimeOps, simulation.FutureOperation{}) copy(queuedTimeOps[index+1:], queuedTimeOps[index:]) queuedTimeOps[index] = futureOp } @@ -180,57 +108,51 @@ func queueOperations(queuedOps OperationQueue, //________________________________________________________________________ -// FutureOperation is an operation which will be ran at the beginning of the -// provided BlockHeight. If both a BlockHeight and BlockTime are specified, it -// will use the BlockHeight. In the (likely) event that multiple operations -// are queued at the same block height, they will execute in a FIFO pattern. -type FutureOperation struct { - BlockHeight int - BlockTime time.Time - Op Operation -} - -//________________________________________________________________________ - // WeightedOperation is an operation with associated weight. // This is used to bias the selection operation within the simulator. type WeightedOperation struct { - Weight int - Op Operation + weight int + op simulation.Operation +} + +func (w WeightedOperation) Weight() int { + return w.weight +} + +func (w WeightedOperation) Op() simulation.Operation { + return w.op } // NewWeightedOperation creates a new WeightedOperation instance -func NewWeightedOperation(weight int, op Operation) WeightedOperation { +func NewWeightedOperation(weight int, op simulation.Operation) WeightedOperation { return WeightedOperation{ - Weight: weight, - Op: op, + weight: weight, + op: op, } } // WeightedOperations is the group of all weighted operations to simulate. -type WeightedOperations []WeightedOperation +type WeightedOperations []simulation.WeightedOperation func (ops WeightedOperations) totalWeight() int { totalOpWeight := 0 for _, op := range ops { - totalOpWeight += op.Weight + totalOpWeight += op.Weight() } return totalOpWeight } -type selectOpFn func(r *rand.Rand) Operation - -func (ops WeightedOperations) getSelectOpFn() selectOpFn { +func (ops WeightedOperations) getSelectOpFn() simulation.SelectOpFn { totalOpWeight := ops.totalWeight() - return func(r *rand.Rand) Operation { + return func(r *rand.Rand) simulation.Operation { x := r.Intn(totalOpWeight) for i := 0; i < len(ops); i++ { - if x <= ops[i].Weight { - return ops[i].Op + if x <= ops[i].Weight() { + return ops[i].Op() } - x -= ops[i].Weight + x -= ops[i].Weight() } // shouldn't happen - return ops[0].Op + return ops[0].Op() } } diff --git a/x/simulation/params.go b/x/simulation/params.go index 2673822d8f43..0c8accd1e28a 100644 --- a/x/simulation/params.go +++ b/x/simulation/params.go @@ -1,13 +1,10 @@ package simulation import ( - "encoding/json" "fmt" "math/rand" - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/cosmos/cosmos-sdk/types/simulation" ) const ( @@ -37,78 +34,86 @@ var ( }) ) -// AppParams defines a flat JSON of key/values for all possible configurable -// simulation parameters. It might contain: operation weights, simulation parameters -// and flattened module state parameters (i.e not stored under it's respective module name). -type AppParams map[string]json.RawMessage - -// ParamSimulator creates a parameter value from a source of random number -type ParamSimulator func(r *rand.Rand) - -// GetOrGenerate attempts to get a given parameter by key from the AppParams -// object. If it exists, it'll be decoded and returned. Otherwise, the provided -// ParamSimulator is used to generate a random value or default value (eg: in the -// case of operation weights where Rand is not used). -func (sp AppParams) GetOrGenerate(cdc *codec.Codec, key string, ptr interface{}, r *rand.Rand, ps ParamSimulator) { - if v, ok := sp[key]; ok && v != nil { - cdc.MustUnmarshalJSON(v, ptr) - return - } +// Params define the parameters necessary for running the simulations +type Params struct { + pastEvidenceFraction float64 + numKeys int + evidenceFraction float64 + initialLivenessWeightings []int + livenessTransitionMatrix simulation.TransitionMatrix + blockSizeTransitionMatrix simulation.TransitionMatrix +} - ps(r) +func (p Params) PastEvidenceFraction() float64 { + return p.pastEvidenceFraction } -// ContentSimulatorFn defines a function type alias for generating random proposal -// content. -type ContentSimulatorFn func(r *rand.Rand, ctx sdk.Context, accs []Account) govtypes.Content +func (p Params) NumKeys() int { + return p.numKeys +} -// Params define the parameters necessary for running the simulations -type Params struct { - PastEvidenceFraction float64 - NumKeys int - EvidenceFraction float64 - InitialLivenessWeightings []int - LivenessTransitionMatrix TransitionMatrix - BlockSizeTransitionMatrix TransitionMatrix +func (p Params) EvidenceFraction() float64 { + return p.evidenceFraction +} + +func (p Params) InitialLivenessWeightings() []int { + return p.initialLivenessWeightings +} + +func (p Params) LivenessTransitionMatrix() simulation.TransitionMatrix { + return p.livenessTransitionMatrix +} + +func (p Params) BlockSizeTransitionMatrix() simulation.TransitionMatrix { + return p.blockSizeTransitionMatrix } // RandomParams returns random simulation parameters func RandomParams(r *rand.Rand) Params { return Params{ - PastEvidenceFraction: r.Float64(), - NumKeys: RandIntBetween(r, 2, 2500), // number of accounts created for the simulation - EvidenceFraction: r.Float64(), - InitialLivenessWeightings: []int{RandIntBetween(r, 1, 80), r.Intn(10), r.Intn(10)}, - LivenessTransitionMatrix: defaultLivenessTransitionMatrix, - BlockSizeTransitionMatrix: defaultBlockSizeTransitionMatrix, + pastEvidenceFraction: r.Float64(), + numKeys: simulation.RandIntBetween(r, 2, 2500), // number of accounts created for the simulation + evidenceFraction: r.Float64(), + initialLivenessWeightings: []int{simulation.RandIntBetween(r, 1, 80), r.Intn(10), r.Intn(10)}, + livenessTransitionMatrix: defaultLivenessTransitionMatrix, + blockSizeTransitionMatrix: defaultBlockSizeTransitionMatrix, } } //----------------------------------------------------------------------------- // Param change proposals -// SimValFn function to generate the randomized parameter change value -type SimValFn func(r *rand.Rand) string - // ParamChange defines the object used for simulating parameter change proposals type ParamChange struct { - Subspace string - Key string - SimValue SimValFn + subspace string + key string + simValue simulation.SimValFn +} + +func (spc ParamChange) Subspace() string { + return spc.subspace +} + +func (spc ParamChange) Key() string { + return spc.key +} + +func (spc ParamChange) SimValue() simulation.SimValFn { + return spc.simValue } // NewSimParamChange creates a new ParamChange instance -func NewSimParamChange(subspace, key string, simVal SimValFn) ParamChange { +func NewSimParamChange(subspace, key string, simVal simulation.SimValFn) simulation.ParamChange { return ParamChange{ - Subspace: subspace, - Key: key, - SimValue: simVal, + subspace: subspace, + key: key, + simValue: simVal, } } // ComposedKey creates a new composed key for the param change proposal func (spc ParamChange) ComposedKey() string { - return fmt.Sprintf("%s/%s", spc.Subspace, spc.Key) + return fmt.Sprintf("%s/%s", spc.Subspace(), spc.Key()) } //----------------------------------------------------------------------------- @@ -117,7 +122,23 @@ func (spc ParamChange) ComposedKey() string { // WeightedProposalContent defines a common struct for proposal contents defined by // external modules (i.e outside gov) type WeightedProposalContent struct { - AppParamsKey string // key used to retrieve the value of the weight from the simulation application params - DefaultWeight int // default weight - ContentSimulatorFn ContentSimulatorFn // content simulator function + appParamsKey string // key used to retrieve the value of the weight from the simulation application params + defaultWeight int // default weight + contentSimulatorFn simulation.ContentSimulatorFn // content simulator function +} + +func NewWeightedProposalContent(appParamsKey string, defaultWeight int, contentSimulatorFn simulation.ContentSimulatorFn) simulation.WeightedProposalContent { + return &WeightedProposalContent{appParamsKey: appParamsKey, defaultWeight: defaultWeight, contentSimulatorFn: contentSimulatorFn} +} + +func (w WeightedProposalContent) AppParamsKey() string { + return w.appParamsKey +} + +func (w WeightedProposalContent) DefaultWeight() int { + return w.defaultWeight +} + +func (w WeightedProposalContent) ContentSimulatorFn() simulation.ContentSimulatorFn { + return w.contentSimulatorFn } diff --git a/x/simulation/params_test.go b/x/simulation/params_test.go new file mode 100644 index 000000000000..8ba53efd8675 --- /dev/null +++ b/x/simulation/params_test.go @@ -0,0 +1,55 @@ +package simulation + +import ( + "fmt" + "math/rand" + "testing" + + "github.com/stretchr/testify/require" + + abci "github.com/tendermint/tendermint/abci/types" + + sdk "github.com/cosmos/cosmos-sdk/types" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" +) + +func TestParamChange(t *testing.T) { + subspace, key := "theSubspace", "key" + f := func(r *rand.Rand) string { + return "theResult" + } + + pChange := NewSimParamChange(subspace, key, f) + + require.Equal(t, subspace, pChange.Subspace()) + require.Equal(t, key, pChange.Key()) + require.Equal(t, f(nil), pChange.SimValue()(nil)) + require.Equal(t, fmt.Sprintf("%s/%s", subspace, key), pChange.ComposedKey()) +} + +func TestNewWeightedProposalContent(t *testing.T) { + key := "theKey" + weight := 1 + content := &testContent{} + f := func(r *rand.Rand, ctx sdk.Context, accs []simtypes.Account) simtypes.Content { + return content + } + + pContent := NewWeightedProposalContent(key, weight, f) + + require.Equal(t, key, pContent.AppParamsKey()) + require.Equal(t, weight, pContent.DefaultWeight()) + + ctx := sdk.NewContext(nil, abci.Header{}, true, nil) + require.Equal(t, content, pContent.ContentSimulatorFn()(nil, ctx, nil)) +} + +type testContent struct { +} + +func (t testContent) GetTitle() string { return "" } +func (t testContent) GetDescription() string { return "" } +func (t testContent) ProposalRoute() string { return "" } +func (t testContent) ProposalType() string { return "" } +func (t testContent) ValidateBasic() error { return nil } +func (t testContent) String() string { return "" } diff --git a/x/simulation/simulate.go b/x/simulation/simulate.go index 800432c74d60..3f5100caa690 100644 --- a/x/simulation/simulate.go +++ b/x/simulation/simulate.go @@ -1,7 +1,6 @@ package simulation import ( - "encoding/json" "fmt" "io" "math/rand" @@ -15,18 +14,14 @@ import ( "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" -) - -// AppStateFn returns the app state json bytes and the genesis accounts -type AppStateFn func(r *rand.Rand, accs []Account, config Config) ( - appState json.RawMessage, accounts []Account, chainId string, genesisTimestamp time.Time, + "github.com/cosmos/cosmos-sdk/types/simulation" ) // initialize the chain for the simulation func initChain( - r *rand.Rand, params Params, accounts []Account, app *baseapp.BaseApp, - appStateFn AppStateFn, config Config, -) (mockValidators, time.Time, []Account, string) { + r *rand.Rand, params Params, accounts []simulation.Account, app *baseapp.BaseApp, + appStateFn simulation.AppStateFn, config simulation.Config, +) (mockValidators, time.Time, []simulation.Account, string) { appState, accounts, chainID, genesisTimestamp := appStateFn(r, accounts, config) @@ -45,8 +40,8 @@ func initChain( // TODO: split this monster function up func SimulateFromSeed( tb testing.TB, w io.Writer, app *baseapp.BaseApp, - appStateFn AppStateFn, ops WeightedOperations, - blackListedAccs map[string]bool, config Config, + appStateFn simulation.AppStateFn, ops WeightedOperations, + blackListedAccs map[string]bool, config simulation.Config, ) (stopEarly bool, exportedParams Params, err error) { // in case we have to end early, don't os.Exit so that we can run cleanup code. @@ -58,7 +53,7 @@ func SimulateFromSeed( fmt.Fprintf(w, "Randomized simulation params: \n%s\n", mustMarshalJSONIndent(params)) timeDiff := maxTimePerBlock - minTimePerBlock - accs := RandomAccounts(r, params.NumKeys) + accs := simulation.RandomAccounts(r, params.NumKeys()) eventStats := NewEventStats() // Second variable to keep pending validator set (delayed one block since @@ -76,7 +71,7 @@ func SimulateFromSeed( ) // remove module account address if they exist in accs - var tmpAccs []Account + var tmpAccs []simulation.Account for _, acc := range accs { if !blackListedAccs[acc.Address.String()] { tmpAccs = append(tmpAccs, acc) @@ -113,7 +108,7 @@ func SimulateFromSeed( // These are operations which have been queued by previous operations operationQueue := NewOperationQueue() - timeOperationQueue := []FutureOperation{} + timeOperationQueue := []simulation.FutureOperation{} logWriter := NewLogWriter(testingMode) @@ -234,21 +229,21 @@ func SimulateFromSeed( //______________________________________________________________________________ type blockSimFn func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, - accounts []Account, header abci.Header) (opCount int) + accounts []simulation.Account, header abci.Header) (opCount int) // Returns a function to simulate blocks. Written like this to avoid constant // parameters being passed everytime, to minimize memory overhead. func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, w io.Writer, params Params, event func(route, op, evResult string), ops WeightedOperations, - operationQueue OperationQueue, timeOperationQueue []FutureOperation, - logWriter LogWriter, config Config) blockSimFn { + operationQueue OperationQueue, timeOperationQueue []simulation.FutureOperation, + logWriter LogWriter, config simulation.Config) blockSimFn { lastBlockSizeState := 0 // state for [4 * uniform distribution] blocksize := 0 selectOp := ops.getSelectOpFn() return func( - r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accounts []Account, header abci.Header, + r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accounts []simulation.Account, header abci.Header, ) (opCount int) { _, _ = fmt.Fprintf( @@ -258,7 +253,7 @@ func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, w io.Wr lastBlockSizeState, blocksize = getBlockSize(r, params, lastBlockSizeState, config.BlockSize) type opAndR struct { - op Operation + op simulation.Operation rand *rand.Rand } @@ -269,7 +264,7 @@ func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, w io.Wr for i := 0; i < blocksize; i++ { opAndRz = append(opAndRz, opAndR{ op: selectOp(r), - rand: DeriveRand(r), + rand: simulation.DeriveRand(r), }) } @@ -306,9 +301,9 @@ Comment: %s`, } // nolint: errcheck -func runQueuedOperations(queueOps map[int][]Operation, +func runQueuedOperations(queueOps map[int][]simulation.Operation, height int, tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, - ctx sdk.Context, accounts []Account, logWriter LogWriter, + ctx sdk.Context, accounts []simulation.Account, logWriter LogWriter, event func(route, op, evResult string), lean bool, chainID string) (numOpsRan int) { queuedOp, ok := queueOps[height] @@ -336,9 +331,9 @@ func runQueuedOperations(queueOps map[int][]Operation, return numOpsRan } -func runQueuedTimeOperations(queueOps []FutureOperation, +func runQueuedTimeOperations(queueOps []simulation.FutureOperation, height int, currentTime time.Time, tb testing.TB, r *rand.Rand, - app *baseapp.BaseApp, ctx sdk.Context, accounts []Account, + app *baseapp.BaseApp, ctx sdk.Context, accounts []simulation.Account, logWriter LogWriter, event func(route, op, evResult string), lean bool, chainID string) (numOpsRan int) { diff --git a/x/simulation/transition_matrix.go b/x/simulation/transition_matrix.go index 0a0ee7ebea04..ca374bc56e4a 100644 --- a/x/simulation/transition_matrix.go +++ b/x/simulation/transition_matrix.go @@ -3,6 +3,8 @@ package simulation import ( "fmt" "math/rand" + + "github.com/cosmos/cosmos-sdk/types/simulation" ) // TransitionMatrix is _almost_ a left stochastic matrix. It is technically @@ -19,7 +21,7 @@ type TransitionMatrix struct { // CreateTransitionMatrix creates a transition matrix from the provided weights. // TODO: Provide example usage -func CreateTransitionMatrix(weights [][]int) (TransitionMatrix, error) { +func CreateTransitionMatrix(weights [][]int) (simulation.TransitionMatrix, error) { n := len(weights) for i := 0; i < n; i++ { if len(weights[i]) != n { diff --git a/x/simulation/util.go b/x/simulation/util.go index 58795cd879e9..4671b193a6a6 100644 --- a/x/simulation/util.go +++ b/x/simulation/util.go @@ -27,7 +27,7 @@ func getTestingMode(tb testing.TB) (testingMode bool, t *testing.T, b *testing.B func getBlockSize(r *rand.Rand, params Params, lastBlockSizeState, avgBlockSize int) (state, blockSize int) { // TODO: Make default blocksize transition matrix actually make the average // blocksize equal to avgBlockSize. - state = params.BlockSizeTransitionMatrix.NextState(r, lastBlockSizeState) + state = params.BlockSizeTransitionMatrix().NextState(r, lastBlockSizeState) switch state { case 0: diff --git a/x/slashing/module.go b/x/slashing/module.go index b404b8c4ecde..26876e506c19 100644 --- a/x/slashing/module.go +++ b/x/slashing/module.go @@ -14,7 +14,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" - sim "github.com/cosmos/cosmos-sdk/x/simulation" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/cosmos/cosmos-sdk/x/slashing/client/cli" "github.com/cosmos/cosmos-sdk/x/slashing/client/rest" "github.com/cosmos/cosmos-sdk/x/slashing/simulation" @@ -162,12 +162,12 @@ func (AppModule) GenerateGenesisState(simState *module.SimulationState) { } // ProposalContents doesn't return any content functions for governance proposals. -func (AppModule) ProposalContents(_ module.SimulationState) []sim.WeightedProposalContent { +func (AppModule) ProposalContents(simState module.SimulationState) []simtypes.WeightedProposalContent { return nil } // RandomizedParams creates randomized slashing param changes for the simulator. -func (AppModule) RandomizedParams(r *rand.Rand) []sim.ParamChange { +func (AppModule) RandomizedParams(r *rand.Rand) []simtypes.ParamChange { return simulation.ParamChanges(r) } @@ -177,7 +177,7 @@ func (AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { } // WeightedOperations returns the all the slashing module operations with their respective weights. -func (am AppModule) WeightedOperations(simState module.SimulationState) []sim.WeightedOperation { +func (am AppModule) WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation { return simulation.WeightedOperations( simState.AppParams, simState.Cdc, am.accountKeeper, am.bankKeeper, am.keeper, am.stakingKeeper, diff --git a/x/slashing/simulation/genesis.go b/x/slashing/simulation/genesis.go index d9dae7cd3d7b..eb918573c760 100644 --- a/x/slashing/simulation/genesis.go +++ b/x/slashing/simulation/genesis.go @@ -11,7 +11,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" - "github.com/cosmos/cosmos-sdk/x/simulation" + "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/cosmos/cosmos-sdk/x/slashing/types" ) diff --git a/x/slashing/simulation/operations.go b/x/slashing/simulation/operations.go index c0f0b94554f6..112f598ab652 100644 --- a/x/slashing/simulation/operations.go +++ b/x/slashing/simulation/operations.go @@ -9,6 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/simapp/helpers" simappparams "github.com/cosmos/cosmos-sdk/simapp/params" sdk "github.com/cosmos/cosmos-sdk/types" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/cosmos/cosmos-sdk/x/simulation" "github.com/cosmos/cosmos-sdk/x/slashing/keeper" "github.com/cosmos/cosmos-sdk/x/slashing/types" @@ -22,7 +23,7 @@ const ( // WeightedOperations returns all the operations from the module with their respective weights func WeightedOperations( - appParams simulation.AppParams, cdc *codec.Codec, ak types.AccountKeeper, + appParams simtypes.AppParams, cdc *codec.Codec, ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, sk stakingkeeper.Keeper, ) simulation.WeightedOperations { @@ -43,44 +44,44 @@ func WeightedOperations( // SimulateMsgUnjail generates a MsgUnjail with random values // nolint: interfacer -func SimulateMsgUnjail(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, sk stakingkeeper.Keeper) simulation.Operation { +func SimulateMsgUnjail(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, sk stakingkeeper.Keeper) simtypes.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, - accs []simulation.Account, chainID string, - ) (simulation.OperationMsg, []simulation.FutureOperation, error) { + accs []simtypes.Account, chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { validator, ok := stakingkeeper.RandomValidator(r, sk, ctx) if !ok { - return simulation.NoOpMsg(types.ModuleName), nil, nil // skip + return simtypes.NoOpMsg(types.ModuleName), nil, nil // skip } - simAccount, found := simulation.FindAccount(accs, sdk.AccAddress(validator.GetOperator())) + simAccount, found := simtypes.FindAccount(accs, sdk.AccAddress(validator.GetOperator())) if !found { - return simulation.NoOpMsg(types.ModuleName), nil, nil // skip + return simtypes.NoOpMsg(types.ModuleName), nil, nil // skip } if !validator.IsJailed() { // TODO: due to this condition this message is almost, if not always, skipped ! - return simulation.NoOpMsg(types.ModuleName), nil, nil + return simtypes.NoOpMsg(types.ModuleName), nil, nil } consAddr := sdk.ConsAddress(validator.GetConsPubKey().Address()) info, found := k.GetValidatorSigningInfo(ctx, consAddr) if !found { - return simulation.NoOpMsg(types.ModuleName), nil, nil // skip + return simtypes.NoOpMsg(types.ModuleName), nil, nil // skip } selfDel := sk.Delegation(ctx, simAccount.Address, validator.GetOperator()) if selfDel == nil { - return simulation.NoOpMsg(types.ModuleName), nil, nil // skip + return simtypes.NoOpMsg(types.ModuleName), nil, nil // skip } account := ak.GetAccount(ctx, sdk.AccAddress(validator.GetOperator())) spendable := bk.SpendableCoins(ctx, account.GetAddress()) - fees, err := simulation.RandomFees(r, ctx, spendable) + fees, err := simtypes.RandomFees(r, ctx, spendable) if err != nil { - return simulation.NoOpMsg(types.ModuleName), nil, err + return simtypes.NoOpMsg(types.ModuleName), nil, err } msg := types.NewMsgUnjail(validator.GetOperator()) @@ -106,23 +107,23 @@ func SimulateMsgUnjail(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Kee validator.TokensFromShares(selfDel.GetShares()).TruncateInt().LT(validator.GetMinSelfDelegation()) { if res != nil && err == nil { if info.Tombstoned { - return simulation.NewOperationMsg(msg, true, ""), nil, errors.New("validator should not have been unjailed if validator tombstoned") + return simtypes.NewOperationMsg(msg, true, ""), nil, errors.New("validator should not have been unjailed if validator tombstoned") } if ctx.BlockHeader().Time.Before(info.JailedUntil) { - return simulation.NewOperationMsg(msg, true, ""), nil, errors.New("validator unjailed while validator still in jail period") + return simtypes.NewOperationMsg(msg, true, ""), nil, errors.New("validator unjailed while validator still in jail period") } if validator.TokensFromShares(selfDel.GetShares()).TruncateInt().LT(validator.GetMinSelfDelegation()) { - return simulation.NewOperationMsg(msg, true, ""), nil, errors.New("validator unjailed even though self-delegation too low") + return simtypes.NewOperationMsg(msg, true, ""), nil, errors.New("validator unjailed even though self-delegation too low") } } // msg failed as expected - return simulation.NewOperationMsg(msg, false, ""), nil, nil + return simtypes.NewOperationMsg(msg, false, ""), nil, nil } if err != nil { - return simulation.NoOpMsg(types.ModuleName), nil, errors.New(res.Log) + return simtypes.NoOpMsg(types.ModuleName), nil, errors.New(res.Log) } - return simulation.NewOperationMsg(msg, true, ""), nil, nil + return simtypes.NewOperationMsg(msg, true, ""), nil, nil } } diff --git a/x/slashing/simulation/params.go b/x/slashing/simulation/params.go index 72048f2264bd..e7c8fcf491b0 100644 --- a/x/slashing/simulation/params.go +++ b/x/slashing/simulation/params.go @@ -6,6 +6,7 @@ import ( "fmt" "math/rand" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/cosmos/cosmos-sdk/x/simulation" "github.com/cosmos/cosmos-sdk/x/slashing/types" ) @@ -18,8 +19,8 @@ const ( // ParamChanges defines the parameters that can be modified by param change proposals // on the simulation -func ParamChanges(r *rand.Rand) []simulation.ParamChange { - return []simulation.ParamChange{ +func ParamChanges(r *rand.Rand) []simtypes.ParamChange { + return []simtypes.ParamChange{ simulation.NewSimParamChange(types.ModuleName, keySignedBlocksWindow, func(r *rand.Rand) string { return fmt.Sprintf("\"%d\"", GenSignedBlocksWindow(r)) diff --git a/x/staking/module.go b/x/staking/module.go index 33034842f75d..3054683ffb2f 100644 --- a/x/staking/module.go +++ b/x/staking/module.go @@ -17,8 +17,8 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - sim "github.com/cosmos/cosmos-sdk/x/simulation" "github.com/cosmos/cosmos-sdk/x/staking/client/cli" "github.com/cosmos/cosmos-sdk/x/staking/client/rest" "github.com/cosmos/cosmos-sdk/x/staking/simulation" @@ -188,12 +188,12 @@ func (AppModule) GenerateGenesisState(simState *module.SimulationState) { } // ProposalContents doesn't return any content functions for governance proposals. -func (AppModule) ProposalContents(_ module.SimulationState) []sim.WeightedProposalContent { +func (AppModule) ProposalContents(simState module.SimulationState) []simtypes.WeightedProposalContent { return nil } // RandomizedParams creates randomized staking param changes for the simulator. -func (AppModule) RandomizedParams(r *rand.Rand) []sim.ParamChange { +func (AppModule) RandomizedParams(r *rand.Rand) []simtypes.ParamChange { return simulation.ParamChanges(r) } @@ -203,7 +203,7 @@ func (AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { } // WeightedOperations returns the all the staking module operations with their respective weights. -func (am AppModule) WeightedOperations(simState module.SimulationState) []sim.WeightedOperation { +func (am AppModule) WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation { return simulation.WeightedOperations( simState.AppParams, simState.Cdc, am.accountKeeper, am.bankKeeper, am.keeper, ) diff --git a/x/staking/simulation/genesis.go b/x/staking/simulation/genesis.go index 1ce83be9ef18..dd6ee56187c6 100644 --- a/x/staking/simulation/genesis.go +++ b/x/staking/simulation/genesis.go @@ -11,7 +11,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" - "github.com/cosmos/cosmos-sdk/x/simulation" + "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/cosmos/cosmos-sdk/x/staking/types" ) diff --git a/x/staking/simulation/operations.go b/x/staking/simulation/operations.go index 6d87a8c425c4..c1e9ab8eecc8 100644 --- a/x/staking/simulation/operations.go +++ b/x/staking/simulation/operations.go @@ -9,6 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/simapp/helpers" simappparams "github.com/cosmos/cosmos-sdk/simapp/params" sdk "github.com/cosmos/cosmos-sdk/types" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/cosmos/cosmos-sdk/x/simulation" "github.com/cosmos/cosmos-sdk/x/staking/keeper" "github.com/cosmos/cosmos-sdk/x/staking/types" @@ -25,7 +26,7 @@ const ( // WeightedOperations returns all the operations from the module with their respective weights func WeightedOperations( - appParams simulation.AppParams, cdc *codec.Codec, ak types.AccountKeeper, + appParams simtypes.AppParams, cdc *codec.Codec, ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, ) simulation.WeightedOperations { @@ -93,30 +94,30 @@ func WeightedOperations( // SimulateMsgCreateValidator generates a MsgCreateValidator with random values // nolint: interfacer -func SimulateMsgCreateValidator(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simulation.Operation { +func SimulateMsgCreateValidator(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simtypes.Operation { return func( - r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, - ) (simulation.OperationMsg, []simulation.FutureOperation, error) { + r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { - simAccount, _ := simulation.RandomAcc(r, accs) + simAccount, _ := simtypes.RandomAcc(r, accs) address := sdk.ValAddress(simAccount.Address) // ensure the validator doesn't exist already _, found := k.GetValidator(ctx, address) if found { - return simulation.NoOpMsg(types.ModuleName), nil, nil + return simtypes.NoOpMsg(types.ModuleName), nil, nil } denom := k.GetParams(ctx).BondDenom balance := bk.GetBalance(ctx, simAccount.Address, denom).Amount if !balance.IsPositive() { - return simulation.NoOpMsg(types.ModuleName), nil, nil + return simtypes.NoOpMsg(types.ModuleName), nil, nil } - amount, err := simulation.RandPositiveInt(r, balance) + amount, err := simtypes.RandPositiveInt(r, balance) if err != nil { - return simulation.NoOpMsg(types.ModuleName), nil, err + return simtypes.NoOpMsg(types.ModuleName), nil, err } selfDelegation := sdk.NewCoin(denom, amount) @@ -127,25 +128,25 @@ func SimulateMsgCreateValidator(ak types.AccountKeeper, bk types.BankKeeper, k k var fees sdk.Coins coins, hasNeg := spendable.SafeSub(sdk.Coins{selfDelegation}) if !hasNeg { - fees, err = simulation.RandomFees(r, ctx, coins) + fees, err = simtypes.RandomFees(r, ctx, coins) if err != nil { - return simulation.NoOpMsg(types.ModuleName), nil, err + return simtypes.NoOpMsg(types.ModuleName), nil, err } } description := types.NewDescription( - simulation.RandStringOfLength(r, 10), - simulation.RandStringOfLength(r, 10), - simulation.RandStringOfLength(r, 10), - simulation.RandStringOfLength(r, 10), - simulation.RandStringOfLength(r, 10), + simtypes.RandStringOfLength(r, 10), + simtypes.RandStringOfLength(r, 10), + simtypes.RandStringOfLength(r, 10), + simtypes.RandStringOfLength(r, 10), + simtypes.RandStringOfLength(r, 10), ) - maxCommission := sdk.NewDecWithPrec(int64(simulation.RandIntBetween(r, 0, 100)), 2) + maxCommission := sdk.NewDecWithPrec(int64(simtypes.RandIntBetween(r, 0, 100)), 2) commission := types.NewCommissionRates( - simulation.RandomDecAmount(r, maxCommission), + simtypes.RandomDecAmount(r, maxCommission), maxCommission, - simulation.RandomDecAmount(r, maxCommission), + simtypes.RandomDecAmount(r, maxCommission), ) msg := types.NewMsgCreateValidator(address, simAccount.PubKey, @@ -163,57 +164,57 @@ func SimulateMsgCreateValidator(ak types.AccountKeeper, bk types.BankKeeper, k k _, _, err = app.Deliver(tx) if err != nil { - return simulation.NoOpMsg(types.ModuleName), nil, err + return simtypes.NoOpMsg(types.ModuleName), nil, err } - return simulation.NewOperationMsg(msg, true, ""), nil, nil + return simtypes.NewOperationMsg(msg, true, ""), nil, nil } } // SimulateMsgEditValidator generates a MsgEditValidator with random values // nolint: interfacer -func SimulateMsgEditValidator(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simulation.Operation { +func SimulateMsgEditValidator(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simtypes.Operation { return func( - r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, - ) (simulation.OperationMsg, []simulation.FutureOperation, error) { + r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { if len(k.GetAllValidators(ctx)) == 0 { - return simulation.NoOpMsg(types.ModuleName), nil, nil + return simtypes.NoOpMsg(types.ModuleName), nil, nil } val, ok := keeper.RandomValidator(r, k, ctx) if !ok { - return simulation.NoOpMsg(types.ModuleName), nil, nil + return simtypes.NoOpMsg(types.ModuleName), nil, nil } address := val.GetOperator() - newCommissionRate := simulation.RandomDecAmount(r, val.Commission.MaxRate) + newCommissionRate := simtypes.RandomDecAmount(r, val.Commission.MaxRate) if err := val.Commission.ValidateNewRate(newCommissionRate, ctx.BlockHeader().Time); err != nil { // skip as the commission is invalid - return simulation.NoOpMsg(types.ModuleName), nil, nil + return simtypes.NoOpMsg(types.ModuleName), nil, nil } - simAccount, found := simulation.FindAccount(accs, sdk.AccAddress(val.GetOperator())) + simAccount, found := simtypes.FindAccount(accs, sdk.AccAddress(val.GetOperator())) if !found { - return simulation.NoOpMsg(types.ModuleName), nil, fmt.Errorf("validator %s not found", val.GetOperator()) + return simtypes.NoOpMsg(types.ModuleName), nil, fmt.Errorf("validator %s not found", val.GetOperator()) } account := ak.GetAccount(ctx, simAccount.Address) spendable := bk.SpendableCoins(ctx, account.GetAddress()) - fees, err := simulation.RandomFees(r, ctx, spendable) + fees, err := simtypes.RandomFees(r, ctx, spendable) if err != nil { - return simulation.NoOpMsg(types.ModuleName), nil, err + return simtypes.NoOpMsg(types.ModuleName), nil, err } description := types.NewDescription( - simulation.RandStringOfLength(r, 10), - simulation.RandStringOfLength(r, 10), - simulation.RandStringOfLength(r, 10), - simulation.RandStringOfLength(r, 10), - simulation.RandStringOfLength(r, 10), + simtypes.RandStringOfLength(r, 10), + simtypes.RandStringOfLength(r, 10), + simtypes.RandStringOfLength(r, 10), + simtypes.RandStringOfLength(r, 10), + simtypes.RandStringOfLength(r, 10), ) msg := types.NewMsgEditValidator(address, description, &newCommissionRate, nil) @@ -230,43 +231,43 @@ func SimulateMsgEditValidator(ak types.AccountKeeper, bk types.BankKeeper, k kee _, _, err = app.Deliver(tx) if err != nil { - return simulation.NoOpMsg(types.ModuleName), nil, err + return simtypes.NoOpMsg(types.ModuleName), nil, err } - return simulation.NewOperationMsg(msg, true, ""), nil, nil + return simtypes.NewOperationMsg(msg, true, ""), nil, nil } } // SimulateMsgDelegate generates a MsgDelegate with random values // nolint: interfacer -func SimulateMsgDelegate(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simulation.Operation { +func SimulateMsgDelegate(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simtypes.Operation { return func( - r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, - ) (simulation.OperationMsg, []simulation.FutureOperation, error) { + r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { denom := k.GetParams(ctx).BondDenom if len(k.GetAllValidators(ctx)) == 0 { - return simulation.NoOpMsg(types.ModuleName), nil, nil + return simtypes.NoOpMsg(types.ModuleName), nil, nil } - simAccount, _ := simulation.RandomAcc(r, accs) + simAccount, _ := simtypes.RandomAcc(r, accs) val, ok := keeper.RandomValidator(r, k, ctx) if !ok { - return simulation.NoOpMsg(types.ModuleName), nil, nil + return simtypes.NoOpMsg(types.ModuleName), nil, nil } if val.InvalidExRate() { - return simulation.NoOpMsg(types.ModuleName), nil, nil + return simtypes.NoOpMsg(types.ModuleName), nil, nil } amount := bk.GetBalance(ctx, simAccount.Address, denom).Amount if !amount.IsPositive() { - return simulation.NoOpMsg(types.ModuleName), nil, nil + return simtypes.NoOpMsg(types.ModuleName), nil, nil } - amount, err := simulation.RandPositiveInt(r, amount) + amount, err := simtypes.RandPositiveInt(r, amount) if err != nil { - return simulation.NoOpMsg(types.ModuleName), nil, err + return simtypes.NoOpMsg(types.ModuleName), nil, err } bondAmt := sdk.NewCoin(denom, amount) @@ -277,9 +278,9 @@ func SimulateMsgDelegate(ak types.AccountKeeper, bk types.BankKeeper, k keeper.K var fees sdk.Coins coins, hasNeg := spendable.SafeSub(sdk.Coins{bondAmt}) if !hasNeg { - fees, err = simulation.RandomFees(r, ctx, coins) + fees, err = simtypes.RandomFees(r, ctx, coins) if err != nil { - return simulation.NoOpMsg(types.ModuleName), nil, err + return simtypes.NoOpMsg(types.ModuleName), nil, err } } @@ -297,24 +298,24 @@ func SimulateMsgDelegate(ak types.AccountKeeper, bk types.BankKeeper, k keeper.K _, _, err = app.Deliver(tx) if err != nil { - return simulation.NoOpMsg(types.ModuleName), nil, err + return simtypes.NoOpMsg(types.ModuleName), nil, err } - return simulation.NewOperationMsg(msg, true, ""), nil, nil + return simtypes.NewOperationMsg(msg, true, ""), nil, nil } } // SimulateMsgUndelegate generates a MsgUndelegate with random values // nolint: interfacer -func SimulateMsgUndelegate(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simulation.Operation { +func SimulateMsgUndelegate(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simtypes.Operation { return func( - r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, - ) (simulation.OperationMsg, []simulation.FutureOperation, error) { + r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { // get random validator validator, ok := keeper.RandomValidator(r, k, ctx) if !ok { - return simulation.NoOpMsg(types.ModuleName), nil, nil + return simtypes.NoOpMsg(types.ModuleName), nil, nil } valAddr := validator.GetOperator() @@ -325,21 +326,21 @@ func SimulateMsgUndelegate(ak types.AccountKeeper, bk types.BankKeeper, k keeper delAddr := delegation.GetDelegatorAddr() if k.HasMaxUnbondingDelegationEntries(ctx, delAddr, valAddr) { - return simulation.NoOpMsg(types.ModuleName), nil, nil + return simtypes.NoOpMsg(types.ModuleName), nil, nil } totalBond := validator.TokensFromShares(delegation.GetShares()).TruncateInt() if !totalBond.IsPositive() { - return simulation.NoOpMsg(types.ModuleName), nil, nil + return simtypes.NoOpMsg(types.ModuleName), nil, nil } - unbondAmt, err := simulation.RandPositiveInt(r, totalBond) + unbondAmt, err := simtypes.RandPositiveInt(r, totalBond) if err != nil { - return simulation.NoOpMsg(types.ModuleName), nil, err + return simtypes.NoOpMsg(types.ModuleName), nil, err } if unbondAmt.IsZero() { - return simulation.NoOpMsg(types.ModuleName), nil, nil + return simtypes.NoOpMsg(types.ModuleName), nil, nil } msg := types.NewMsgUndelegate( @@ -347,7 +348,7 @@ func SimulateMsgUndelegate(ak types.AccountKeeper, bk types.BankKeeper, k keeper ) // need to retrieve the simulation account associated with delegation to retrieve PrivKey - var simAccount simulation.Account + var simAccount simtypes.Account for _, simAcc := range accs { if simAcc.Address.Equals(delAddr) { simAccount = simAcc @@ -356,15 +357,15 @@ func SimulateMsgUndelegate(ak types.AccountKeeper, bk types.BankKeeper, k keeper } // if simaccount.PrivKey == nil, delegation address does not exist in accs. Return error if simAccount.PrivKey == nil { - return simulation.NoOpMsg(types.ModuleName), nil, fmt.Errorf("delegation addr: %s does not exist in simulation accounts", delAddr) + return simtypes.NoOpMsg(types.ModuleName), nil, fmt.Errorf("delegation addr: %s does not exist in simulation accounts", delAddr) } account := ak.GetAccount(ctx, delAddr) spendable := bk.SpendableCoins(ctx, account.GetAddress()) - fees, err := simulation.RandomFees(r, ctx, spendable) + fees, err := simtypes.RandomFees(r, ctx, spendable) if err != nil { - return simulation.NoOpMsg(types.ModuleName), nil, err + return simtypes.NoOpMsg(types.ModuleName), nil, err } tx := helpers.GenTx( @@ -379,24 +380,24 @@ func SimulateMsgUndelegate(ak types.AccountKeeper, bk types.BankKeeper, k keeper _, _, err = app.Deliver(tx) if err != nil { - return simulation.NoOpMsg(types.ModuleName), nil, err + return simtypes.NoOpMsg(types.ModuleName), nil, err } - return simulation.NewOperationMsg(msg, true, ""), nil, nil + return simtypes.NewOperationMsg(msg, true, ""), nil, nil } } // SimulateMsgBeginRedelegate generates a MsgBeginRedelegate with random values // nolint: interfacer -func SimulateMsgBeginRedelegate(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simulation.Operation { +func SimulateMsgBeginRedelegate(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simtypes.Operation { return func( - r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, - ) (simulation.OperationMsg, []simulation.FutureOperation, error) { + r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { // get random source validator srcVal, ok := keeper.RandomValidator(r, k, ctx) if !ok { - return simulation.NoOpMsg(types.ModuleName), nil, nil + return simtypes.NoOpMsg(types.ModuleName), nil, nil } srcAddr := srcVal.GetOperator() @@ -407,13 +408,13 @@ func SimulateMsgBeginRedelegate(ak types.AccountKeeper, bk types.BankKeeper, k k delAddr := delegation.GetDelegatorAddr() if k.HasReceivingRedelegation(ctx, delAddr, srcAddr) { - return simulation.NoOpMsg(types.ModuleName), nil, nil // skip + return simtypes.NoOpMsg(types.ModuleName), nil, nil // skip } // get random destination validator destVal, ok := keeper.RandomValidator(r, k, ctx) if !ok { - return simulation.NoOpMsg(types.ModuleName), nil, nil + return simtypes.NoOpMsg(types.ModuleName), nil, nil } destAddr := destVal.GetOperator() @@ -421,35 +422,35 @@ func SimulateMsgBeginRedelegate(ak types.AccountKeeper, bk types.BankKeeper, k k destVal.InvalidExRate() || k.HasMaxRedelegationEntries(ctx, delAddr, srcAddr, destAddr) { - return simulation.NoOpMsg(types.ModuleName), nil, nil + return simtypes.NoOpMsg(types.ModuleName), nil, nil } totalBond := srcVal.TokensFromShares(delegation.GetShares()).TruncateInt() if !totalBond.IsPositive() { - return simulation.NoOpMsg(types.ModuleName), nil, nil + return simtypes.NoOpMsg(types.ModuleName), nil, nil } - redAmt, err := simulation.RandPositiveInt(r, totalBond) + redAmt, err := simtypes.RandPositiveInt(r, totalBond) if err != nil { - return simulation.NoOpMsg(types.ModuleName), nil, err + return simtypes.NoOpMsg(types.ModuleName), nil, err } if redAmt.IsZero() { - return simulation.NoOpMsg(types.ModuleName), nil, nil + return simtypes.NoOpMsg(types.ModuleName), nil, nil } // check if the shares truncate to zero shares, err := srcVal.SharesFromTokens(redAmt) if err != nil { - return simulation.NoOpMsg(types.ModuleName), nil, err + return simtypes.NoOpMsg(types.ModuleName), nil, err } if srcVal.TokensFromShares(shares).TruncateInt().IsZero() { - return simulation.NoOpMsg(types.ModuleName), nil, nil // skip + return simtypes.NoOpMsg(types.ModuleName), nil, nil // skip } // need to retrieve the simulation account associated with delegation to retrieve PrivKey - var simAccount simulation.Account + var simAccount simtypes.Account for _, simAcc := range accs { if simAcc.Address.Equals(delAddr) { simAccount = simAcc @@ -459,15 +460,15 @@ func SimulateMsgBeginRedelegate(ak types.AccountKeeper, bk types.BankKeeper, k k // if simaccount.PrivKey == nil, delegation address does not exist in accs. Return error if simAccount.PrivKey == nil { - return simulation.NoOpMsg(types.ModuleName), nil, fmt.Errorf("delegation addr: %s does not exist in simulation accounts", delAddr) + return simtypes.NoOpMsg(types.ModuleName), nil, fmt.Errorf("delegation addr: %s does not exist in simulation accounts", delAddr) } account := ak.GetAccount(ctx, delAddr) spendable := bk.SpendableCoins(ctx, account.GetAddress()) - fees, err := simulation.RandomFees(r, ctx, spendable) + fees, err := simtypes.RandomFees(r, ctx, spendable) if err != nil { - return simulation.NoOpMsg(types.ModuleName), nil, err + return simtypes.NoOpMsg(types.ModuleName), nil, err } msg := types.NewMsgBeginRedelegate( @@ -487,9 +488,9 @@ func SimulateMsgBeginRedelegate(ak types.AccountKeeper, bk types.BankKeeper, k k _, _, err = app.Deliver(tx) if err != nil { - return simulation.NoOpMsg(types.ModuleName), nil, err + return simtypes.NoOpMsg(types.ModuleName), nil, err } - return simulation.NewOperationMsg(msg, true, ""), nil, nil + return simtypes.NewOperationMsg(msg, true, ""), nil, nil } } diff --git a/x/staking/simulation/params.go b/x/staking/simulation/params.go index 97938fb91e2d..f71b1534114a 100644 --- a/x/staking/simulation/params.go +++ b/x/staking/simulation/params.go @@ -7,6 +7,8 @@ import ( "math/rand" "github.com/cosmos/cosmos-sdk/x/simulation" + + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/cosmos/cosmos-sdk/x/staking/types" ) @@ -17,8 +19,8 @@ const ( // ParamChanges defines the parameters that can be modified by param change proposals // on the simulation -func ParamChanges(r *rand.Rand) []simulation.ParamChange { - return []simulation.ParamChange{ +func ParamChanges(r *rand.Rand) []simtypes.ParamChange { + return []simtypes.ParamChange{ simulation.NewSimParamChange(types.ModuleName, keyMaxValidators, func(r *rand.Rand) string { return fmt.Sprintf("%d", GenMaxValidators(r)) diff --git a/x/supply/module.go b/x/supply/module.go index 1a2531d99259..5b40fc1db6d2 100644 --- a/x/supply/module.go +++ b/x/supply/module.go @@ -7,14 +7,13 @@ import ( "github.com/gorilla/mux" "github.com/spf13/cobra" - abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" - sim "github.com/cosmos/cosmos-sdk/x/simulation" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/cosmos/cosmos-sdk/x/supply/client/cli" "github.com/cosmos/cosmos-sdk/x/supply/client/rest" "github.com/cosmos/cosmos-sdk/x/supply/simulation" @@ -153,12 +152,12 @@ func (AppModule) GenerateGenesisState(simState *module.SimulationState) { } // ProposalContents doesn't return any content functions for governance proposals. -func (AppModule) ProposalContents(_ module.SimulationState) []sim.WeightedProposalContent { +func (AppModule) ProposalContents(simState module.SimulationState) []simtypes.WeightedProposalContent { return nil } // RandomizedParams doesn't create any randomized supply param changes for the simulator. -func (AppModule) RandomizedParams(_ *rand.Rand) []sim.ParamChange { +func (AppModule) RandomizedParams(r *rand.Rand) []simtypes.ParamChange { return nil } @@ -168,6 +167,6 @@ func (AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { } // WeightedOperations doesn't return any operation for the supply module. -func (AppModule) WeightedOperations(_ module.SimulationState) []sim.WeightedOperation { +func (AppModule) WeightedOperations(_ module.SimulationState) []simtypes.WeightedOperation { return nil } From de3f8806f63218c1f1a83c64fc10fe2d79e44224 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Mon, 23 Mar 2020 16:40:47 +0100 Subject: [PATCH 446/529] crypto/keys: simplify pass keyring directory (#5852) Store keys into $HOME/.password-store/keyring-appcli instead of $HOME/.password-store/$HOME/.appcli/. The latter is very user unfriendly. --- crypto/keys/keyring.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crypto/keys/keyring.go b/crypto/keys/keyring.go index e664b1d2d13b..ff2516afeea5 100644 --- a/crypto/keys/keyring.go +++ b/crypto/keys/keyring.go @@ -34,6 +34,7 @@ const ( const ( keyringDirNameFmt = "keyring-%s" testKeyringDirNameFmt = "keyring-test-%s" + passKeyringPrefix = keyringDirNameFmt ) var _ Keybase = keyringKeybase{} @@ -490,7 +491,7 @@ func newKWalletBackendKeyringConfig(appName, _ string, _ io.Reader) keyring.Conf } func newPassBackendKeyringConfig(appName, dir string, _ io.Reader) keyring.Config { - prefix := filepath.Join(dir, fmt.Sprintf(keyringDirNameFmt, appName)) + prefix := fmt.Sprintf(passKeyringPrefix, appName) return keyring.Config{ AllowedBackends: []keyring.BackendType{keyring.PassBackend}, ServiceName: appName, From a1ac04c96b15eba2c02f19b359b65dac9a5e9d0a Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Mon, 23 Mar 2020 19:02:10 +0100 Subject: [PATCH 447/529] add keyring backends docs (#5854) In addition to #5822. --- docs/interfaces/keyring.md | 90 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 docs/interfaces/keyring.md diff --git a/docs/interfaces/keyring.md b/docs/interfaces/keyring.md new file mode 100644 index 000000000000..34230d12a4e3 --- /dev/null +++ b/docs/interfaces/keyring.md @@ -0,0 +1,90 @@ + + +# The keyring + +Starting with the v0.38.0 release, Cosmos SDK comes with a new keyring implementation +that provides a set of commands to manage cryptographic keys in a secure fashion. The +new keyring supports multiple storage backends, some of which may not be available on +all operating systems. + +## The 'os' backend + +The `os` backend relies on operating system-specific defaults to handle key storage +securely. Typically, operating systems credentials sub-systems handle passwords prompt, +private keys storage, and user sessions according to their users password policies. Here +is a list of the most popular operating systems and their respective passwords manager: + +* macOS (since Mac OS 8.6): [Keychain](https://support.apple.com/en-gb/guide/keychain-access/welcome/mac) +* Windows: [Credentials Management API](https://docs.microsoft.com/en-us/windows/win32/secauthn/credentials-management) +* GNU/Linux: + * [libsecret](https://gitlab.gnome.org/GNOME/libsecret) + * [kwallet](https://api.kde.org/frameworks/kwallet/html/index.html) + +GNU/Linux distributions that use GNOME as default desktop environment typically come with +[Seahorse](https://wiki.gnome.org/Apps/Seahorse). Users of KDE based distributions are +commonly provided with [KDE Wallet Manager](https://userbase.kde.org/KDE_Wallet_Manager). +Whilst the former is in fact a `libsecret` convenient frontend, the former is a `kwallet` +client. + +`os` is the default option since operating system's default credentials managers are +designed to meet users' most common needs and provide them with a comfortable +experience without compromising on security. + +## The 'file' backend + +The `file` backend more closely resembles the keybase implementation used prior to +v0.38.1. It stores the keyring encrypted within the apps configuration directory. This +keyring will request a password each time it is accessed, which may occur multiple +times in a single command resulting in repeated password prompts. If using bash scripts +to execute commands using the `file` option you may want to utilize the following format +for multiple prompts: + +```sh +$ gaiacli config keyring-backend file # use file backend +$ (echo '1234567890'; echo '1234567890') | gaiacli keys add me # add the key 'me' +$ (echo '1234567890'; echo '1234567890'; echo '1234567890') | gaiad collect-gentxs # multiple prompts +``` + +::: tip +The first time you add a key to an empty keyring, you will be prompted to type the password twice. +::: + +## The 'pass' backend + +The `pass` backend uses the [pass](https://www.passwordstore.org/) utility to manage on-disk +encryption of keys' sensitive data and metadata. Keys are stored inside `gpg` encrypted files +within app-specific directories. `pass` is available for the most popular UNIX +operating systems as well as GNU/Linux distributions. Please refer to its manual page for +information on how to download and install it. + +::: tip +**pass** uses [GnuPG](https://gnupg.org/) for encryption. `gpg` automatically invokes the `gpg-agent` +daemon upon execution, which handles the caching of GnuPG credentials. Please refer to `gpg-agent` +man page for more information on how to configure cache parameters such as credentials TTL and +passphrase expiration. +::: + +The password store must be set up prior to first use: + +```sh +$ pass init +``` + +Replace `` with your GPG key ID. You can use your personal GPG key or an alternative +one you may want to use specifically to encrypt the password store. + +## The 'test' backend + +The `test` backend is a password-less variation of the `file` backend. Keys are stored +unencrypted on disk. This backend is meant for testing purposes only and **should never be used +in production environments**. + +## The 'kwallet' backend + +The `kwallet` backend uses `KDE Wallet Manager`, which comes installed by default on the +GNU/Linux distributions that ships KDE as default desktop environment. Please refer to +[KWallet Handbook](https://docs.kde.org/stable5/en/kdeutils/kwallet5/index.html) for more +information. From 999a83d698539f9a49a3cfb59953216ff8dd75ed Mon Sep 17 00:00:00 2001 From: Marko Date: Tue, 24 Mar 2020 11:21:30 +0100 Subject: [PATCH 448/529] docs: link checker (#5860) --- .github/workflows/linkchecker.yml | 17 +++++++++-------- docs/architecture/README.md | 2 +- docs/architecture/adr-009-evidence-module.md | 18 +++++++++--------- docs/spec/addresses/bech32.md | 18 +++++++++--------- 4 files changed, 28 insertions(+), 27 deletions(-) diff --git a/.github/workflows/linkchecker.yml b/.github/workflows/linkchecker.yml index c78daa396f45..2fff6999403e 100644 --- a/.github/workflows/linkchecker.yml +++ b/.github/workflows/linkchecker.yml @@ -1,11 +1,12 @@ -name: Check links -on: [pull_request] +name: Check Markdown links +on: + schedule: + - cron: '* */24 * * *' jobs: - link-check: + markdown-link-check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - name: Link Checker - uses: peter-evans/link-checker@v1 - with: - args: -v -r * \ No newline at end of file + - uses: actions/checkout@master + - uses: gaurav-nelson/github-action-markdown-link-check@0.6.0 + with: + folder-path: "docs" diff --git a/docs/architecture/README.md b/docs/architecture/README.md index 737217bb20a3..c7310d73982b 100644 --- a/docs/architecture/README.md +++ b/docs/architecture/README.md @@ -39,7 +39,7 @@ Please add a entry below in your Pull Request for an ADR. - [ADR 010: Modular AnteHandler](./adr-010-modular-antehandler.md) - [ADR 011: Generalize Genesis Accounts](./adr-011-generalize-genesis-accounts.md) - [ADR 012: State Accessors](./adr-012-state-accessors.md) -- [ADR 013: Observability](./adr-013-observability.md) +- [ADR 013: Metrics](./adr-013-metrics.md) - [ADR 015: IBC Packet Receiver](./adr-015-ibc-packet-receiver.md) - [ADR 016: Validator Consensus Key Rotation](./adr-016-validator-consensus-key-rotation.md) - [ADR 017: Historical Header Module](./adr-017-historical-header-module.md) diff --git a/docs/architecture/adr-009-evidence-module.md b/docs/architecture/adr-009-evidence-module.md index 8ef5d6e5cdd6..f6f47170c9f1 100644 --- a/docs/architecture/adr-009-evidence-module.md +++ b/docs/architecture/adr-009-evidence-module.md @@ -17,7 +17,7 @@ evidence can be submitted, evaluated and verified resulting in some agreed upon penalty for any misbehavior committed by a validator, such as equivocation (double-voting), signing when unbonded, signing an incorrect state transition (in the future), etc. Furthermore, such a mechanism is paramount for any -[IBC](https://github.com/cosmos/ics/blob/master/ibc/1_IBC_ARCHITECTURE.md) or +[IBC](https://github.com/cosmos/ics/blob/master/ibc/2_IBC_ARCHITECTURE.md) or cross-chain validation protocol implementation in order to support the ability for any misbehavior to be relayed back from a collateralized chain to a primary chain so that the equivocating validator(s) can be slashed. @@ -28,14 +28,14 @@ We will implement an evidence module in the Cosmos SDK supporting the following functionality: - Provide developers with the abstractions and interfaces necessary to define -custom evidence messages, message handlers, and methods to slash and penalize -accordingly for misbehavior. + custom evidence messages, message handlers, and methods to slash and penalize + accordingly for misbehavior. - Support the ability to route evidence messages to handlers in any module to -determine the validity of submitted misbehavior. + determine the validity of submitted misbehavior. - Support the ability, through governance, to modify slashing penalties of any -evidence type. + evidence type. - Querier implementation to support querying params, evidence types, params, and -all submitted valid misbehavior. + all submitted valid misbehavior. ### Types @@ -161,15 +161,15 @@ type GenesisState struct { ### Positive - Allows the state machine to process misbehavior submitted on-chain and penalize -validators based on agreed upon slashing parameters. + validators based on agreed upon slashing parameters. - Allows evidence types to be defined and handled by any module. This further allows -slashing and jailing to be defined by more complex mechanisms. + slashing and jailing to be defined by more complex mechanisms. - Does not solely rely on Tendermint to submit evidence. ### Negative - No easy way to introduce new evidence types through governance on a live chain -due to the inability to introduce the new evidence type's corresponding handler + due to the inability to introduce the new evidence type's corresponding handler ### Neutral diff --git a/docs/spec/addresses/bech32.md b/docs/spec/addresses/bech32.md index e2f0ef1ba744..7f0babb144b3 100644 --- a/docs/spec/addresses/bech32.md +++ b/docs/spec/addresses/bech32.md @@ -6,14 +6,14 @@ In the Cosmos network, keys and addresses may refer to a number of different rol ## HRP table -| HRP | Definition | -|-------------------|---------------------------------------| -| cosmos | Cosmos Account Address | -| cosmospub | Cosmos Account Public Key | -| cosmosvalcons | Cosmos Validator Consensus Address | -| cosmosvalconspub | Cosmos Validator Consensus Public Key | -| cosmosvaloper | Cosmos Validator Operator Address | -| cosmosvaloperpub | Cosmos Validator Operator Public Key | +| HRP | Definition | +| ---------------- | ------------------------------------- | +| cosmos | Cosmos Account Address | +| cosmospub | Cosmos Account Public Key | +| cosmosvalcons | Cosmos Validator Consensus Address | +| cosmosvalconspub | Cosmos Validator Consensus Public Key | +| cosmosvaloper | Cosmos Validator Operator Address | +| cosmosvaloperpub | Cosmos Validator Operator Public Key | ## Encoding @@ -21,4 +21,4 @@ While all user facing interfaces to Cosmos software should exposed Bech32 interf To covert between other binary representation of addresses and keys, it is important to first apply the Amino encoding process before bech32 encoding. -A complete implementation of the Amino serialization format is unnecessary in most cases. Simply prepending bytes from this [table](https://github.com/tendermint/tendermint/blob/master/docs/spec/blockchain/encoding.md#public-key-cryptography) to the byte string payload before bech32 encoding will sufficient for compatible representation. +A complete implementation of the Amino serialization format is unnecessary in most cases. Simply prepending bytes from this [table](https://github.com/tendermint/spec/blob/master/spec/blockchain/encoding.md#public-key-cryptography) to the byte string payload before bech32 encoding will sufficient for compatible representation. From 43627d0d1c30d008c678c6b6a5569575e1dfc47f Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Tue, 24 Mar 2020 21:20:30 +0500 Subject: [PATCH 449/529] Update docs website (#5827) * query-lifecycle and started modules-interfaces * query-lifecycle first draft done * module interfaces first draft * rest and intro skeletons * rest and intro done * small edits and links * comments * revisions * cli.md comments * comments * minor edits * better flow for query lifecycle * add transactions into core * hans comments * add transactions into core * checkout master-docs files * deleted some * remove modules readme * cli.md comments * comments * module-interfaces comments * Merge PR #4857: Add Context concept doc * working * working * finish messages and queries * handler * querier * last comments! * punctuation * querier2 * consolidate intro * querier * workiiiing * refactor for new module interface * karoly review * working on baseapp doc * baseapp work * reorg * almost there * finish first draft * remove old files * finish intro * workinnn * initial commit after rebase * query-lifecycle and started modules-interfaces * query-lifecycle first draft done * module interfaces first draft * rest and intro skeletons * rest and intro done * small edits and links * comments * revisions * cli.md comments * comments * minor edits * better flow for query lifecycle * checkout master-docs files * deleted some * remove modules readme * cli.md comments * comments * module-interfaces comments * keeper * genesis * finish * Apply suggestions from code review Co-Authored-By: Hans Schoenburg * hans review * Update docs/core/baseapp.md Co-Authored-By: Hans Schoenburg * working * last comment * workin * Apply suggestions from code review * encoding and node * almost finish store * finish docs * fixes * fede comments + permalinks * hans review * add more permalinks * update docs theme version (#5239) * R4R: Docs Cleanup (#5246) * start * work * work * work * remove table of content * links intro * fix links * remove junk * cleanup * cleanup * work * finish cleanup * addback readmes * remove nft * fix links * remove dup * remove dup * remove dup * remove dup * remove dup * fix links * add subscribe events * refine rest * index page * sidebar * theme version * theme version * testing netlify * theme version * tooltip example * version * testing code embedding * reverting back * theme version * version * version * version * readme and version * cleanup * redo app anatomy * modules readme, theme version * theme version * fix modules list * theme version * new snippets * modules readme * update docs readme * modify synopsis * version * fix yaml * version * version * version * version * version * version * version * version * version * version * add hide banner * version * version * version * small fixes * modules readme, version * remove hotkeys dep, version * version * version * version * version * version * version * version * slight notice * fix links and hide * permalinks * small clean * version * resolve conflicts, add google analytics * fix merge remants * version * changelog 1/2 * Changelog: docs UI * version * remove merge conflicts * Code: Update link for Contributing to the docs to docs_readme * HTML/CSS: Update layout of homepage footer to match new layout in Figma * version * final modifs * modules, version * modules readme * link to module list from homepage * version * building modules link * version * version * fonts * version * version * fix link * fix package.json * links in explore sdk section * core concepts * version * change delimeters for frontmatter * frontmatter in comments * version * temp add tiny-cookie * fixed link issues * fixed styling issues, copy * hide frontmatter * hide frontmatter * layout fixes, padded ascii diagram * fira sans font for code * scrollbar color * move synopsis from frontmatter * move synopsis from frontmatter * code styling in synopsis fix * tutorial link * active headers * 404 fix * homepage links fix * fix link in footer * misc fixes * version * prerequisite links on mobile * version * version * Fix footer links * version * Fix permalink popup * Update version * package-lock.json * Update Questions section in the footer * Config for Algolia Docsearch * Update version * Update to the latest version of the theme * Use docs-staging as a branch for staging website * Update version * Add google analytics * Remove {hide} from Pre-Requisite Readings * Replace Riot with Discord Co-Authored-By: billy rennekamp * Fix yaml syntax error in docs * Fix formatting in keyring.md Co-authored-by: Gloria Zhao Co-authored-by: gamarin Co-authored-by: Jack Zampolin Co-authored-by: Hans Schoenburg Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Co-authored-by: Alexander Bezobchuk Co-authored-by: billy rennekamp --- docs/.vuepress/config.js | 16 +- docs/architecture/adr-013-metrics.md | 2 +- docs/basics/accounts.md | 5 +- docs/basics/app-anatomy.md | 3 +- docs/basics/gas-fees.md | 5 +- docs/basics/tx-lifecycle.md | 5 +- docs/building-modules/beginblock-endblock.md | 5 +- docs/building-modules/errors.md | 3 +- docs/building-modules/genesis.md | 5 +- docs/building-modules/handler.md | 5 +- docs/building-modules/intro.md | 7 +- docs/building-modules/invariants.md | 5 +- docs/building-modules/keeper.md | 5 +- docs/building-modules/messages-and-queries.md | 5 +- docs/building-modules/module-interfaces.md | 5 +- docs/building-modules/module-manager.md | 5 +- docs/building-modules/querier.md | 5 +- docs/building-modules/structure.md | 5 +- docs/core/baseapp.md | 5 +- docs/core/context.md | 5 +- docs/core/encoding.md | 5 +- docs/core/events.md | 7 +- docs/core/node.md | 5 +- docs/core/store.md | 5 +- docs/core/transactions.md | 5 +- docs/interfaces/cli.md | 5 +- docs/interfaces/interfaces-intro.md | 5 +- docs/interfaces/keyring.md | 13 +- docs/interfaces/query-lifecycle.md | 5 +- docs/interfaces/rest.md | 5 +- docs/intro/why-app-specific.md | 3 +- docs/package-lock.json | 1788 +++++++++++------ docs/package.json | 6 +- x/staking/spec/05_end_block.md | 2 +- x/staking/spec/06_hooks.md | 2 +- x/staking/spec/07_events.md | 2 +- x/staking/spec/07_params.md | 14 + 37 files changed, 1315 insertions(+), 668 deletions(-) create mode 100644 x/staking/spec/07_params.md diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index e25d835a7a39..48b47b3d4c89 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -1,11 +1,6 @@ module.exports = { theme: "cosmos", title: "Cosmos SDK", - markdown: { - anchor: { - permalinkSymbol: "" - } - }, head: [ [ "link", @@ -23,9 +18,6 @@ module.exports = { kr: { lang: "kr" }, - kr: { - lang: "kr" - }, cn: { lang: "cn" }, @@ -40,6 +32,11 @@ module.exports = { docsDir: "docs", editLinks: true, label: "sdk", + algolia: { + id: "BH4D9OD16A", + key: "ac317234e6a42074175369b2f42e9754", + index: "cosmos-sdk" + }, sidebar: [ { title: "Using the SDK", @@ -91,10 +88,11 @@ module.exports = { } }, footer: { + questionsText: "Chat with Cosmos developers on [Discord](https://discord.gg/W8trcGV) or reach out on the [SDK Developer Forum](https://forum.cosmos.network/) to learn more.", logo: "/logo-bw.svg", textLink: { text: "cosmos.network", - url: "/" + url: "https://cosmos.network" }, services: [ { diff --git a/docs/architecture/adr-013-metrics.md b/docs/architecture/adr-013-metrics.md index bb2b2b8d6230..78c8ada17e52 100644 --- a/docs/architecture/adr-013-metrics.md +++ b/docs/architecture/adr-013-metrics.md @@ -38,7 +38,7 @@ func (bm BasicManager) RegisterMetrics(appName string, labelsAndValues... string } ``` -Each module can define its own `Metrics` type and`CreateMetrics` function in the x//observability/metrics.go file: +Each module can define its own `Metrics` type and`CreateMetrics` function in the x/\/observability/metrics.go file: ```go type Metrics struct { diff --git a/docs/basics/accounts.md b/docs/basics/accounts.md index f5667a26009e..7b32a1f55a12 100644 --- a/docs/basics/accounts.md +++ b/docs/basics/accounts.md @@ -1,11 +1,12 @@ # Accounts -## Pre-requisite Readings {hide} +This document describes the in-built accounts system of the Cosmos SDK. {synopsis} + +### Pre-requisite Readings - [Anatomy of an SDK Application](./app-anatomy.md) {prereq} diff --git a/docs/basics/app-anatomy.md b/docs/basics/app-anatomy.md index 359016b2c8e8..f27bfdce5ee1 100644 --- a/docs/basics/app-anatomy.md +++ b/docs/basics/app-anatomy.md @@ -1,10 +1,11 @@ # Anatomy of an SDK Application +This document describes the core parts of a Cosmos SDK application. Throughout the document, a placeholder application named `app` will be used. {synopsis} + ## Node Client The Daemon, or [Full-Node Client](../core/node.md), is the core process of an SDK-based blockchain. Participants in the network run this process to initialize their state-machine, connect with other full-nodes and update their state-machine as new blocks come in. diff --git a/docs/basics/gas-fees.md b/docs/basics/gas-fees.md index 5bb4d779f5c0..5271b147a6a5 100644 --- a/docs/basics/gas-fees.md +++ b/docs/basics/gas-fees.md @@ -1,11 +1,12 @@ # Gas and Fees -## Pre-requisite Readings {hide} +This document describes the default strategies to handle gas and fees within a Cosmos SDK application. {synopsis} + +### Pre-requisite Readings - [Anatomy of an SDK Application](./app-anatomy.md) {prereq} diff --git a/docs/basics/tx-lifecycle.md b/docs/basics/tx-lifecycle.md index 098b1507b341..c536aa6f8758 100644 --- a/docs/basics/tx-lifecycle.md +++ b/docs/basics/tx-lifecycle.md @@ -1,11 +1,12 @@ # Transaction Lifecycle -## Pre-requisite Readings {hide} +This document describes the lifecycle of a transaction from creation to committed state changes. Transaction definition is described in a [different doc](../core/transactions.md). The transaction will be referred to as `Tx`. {synopsis} + +### Pre-requisite Readings - [Anatomy of an SDK Application](./app-anatomy.md) {prereq} diff --git a/docs/building-modules/beginblock-endblock.md b/docs/building-modules/beginblock-endblock.md index 578a0f733828..fc9c93302660 100644 --- a/docs/building-modules/beginblock-endblock.md +++ b/docs/building-modules/beginblock-endblock.md @@ -1,11 +1,12 @@ # BeginBlocker and EndBlocker -## Pre-requisite Readings {hide} +`BeginBlocker` and `EndBlocker` are optional methods module developers can implement in their module. They will be triggered at the beginning and at the end of each block respectively, when the [`BeginBlock`](../core/baseapp.md#beginblock) and [`EndBlock`](../core/baseapp.md#endblock) ABCI messages are received from the underlying consensus engine. {synopsis} + +## Pre-requisite Readings - [Module Manager](./module-manager.md) {prereq} diff --git a/docs/building-modules/errors.md b/docs/building-modules/errors.md index 426a9d6d9177..5e3c31bca0d8 100644 --- a/docs/building-modules/errors.md +++ b/docs/building-modules/errors.md @@ -1,10 +1,11 @@ # Errors +This document outlines the recommended usage and APIs for error handling in Cosmos SDK modules. {synopsis} + Modules are encouraged to define and register their own errors to provide better context on failed message or handler execution. Typically, these errors should be common or general errors which can be further wrapped to provide additional specific diff --git a/docs/building-modules/genesis.md b/docs/building-modules/genesis.md index 8cb8815b7ce8..a95064dc0369 100644 --- a/docs/building-modules/genesis.md +++ b/docs/building-modules/genesis.md @@ -1,11 +1,12 @@ # Module Genesis -## Pre-requisite Readings {hide} +Modules generally handle a subset of the state and, as such, they need to define the related subset of the genesis file as well as methods to initialize, verify and export it. {synopsis} + +## Pre-requisite Readings - [Module Manager](./module-manager.md) {prereq} - [Keepers](./keeper.md) {prereq} diff --git a/docs/building-modules/handler.md b/docs/building-modules/handler.md index 1bb9c9b48a37..08850b258259 100644 --- a/docs/building-modules/handler.md +++ b/docs/building-modules/handler.md @@ -1,11 +1,12 @@ # Handlers -## Pre-requisite Readings {hide} +A `Handler` designates a function that processes [`message`s](./messages-and-queries.md#messages). `Handler`s are specific to the module in which they are defined, and only process `message`s defined within the said module. They are called from `baseapp` during [`DeliverTx`](../core/baseapp.md#delivertx). {synopsis} + +## Pre-requisite Readings - [Module Manager](./module-manager.md) {prereq} - [Messages and Queries](./messages-and-queries.md) {prereq} diff --git a/docs/building-modules/intro.md b/docs/building-modules/intro.md index 1d125b51b8a7..99a9a57caafd 100644 --- a/docs/building-modules/intro.md +++ b/docs/building-modules/intro.md @@ -1,11 +1,12 @@ # Introduction to SDK Modules -## Pre-requisite Readings {hide} +Modules define most of the logic of SDK applications. Developers compose module together using the Cosmos SDK to build their custom application-specific blockchains. This document outlines the basic concepts behind SDK modules and how to approach module management. {synopsis} + +## Pre-requisite Readings - [Anatomy of an SDK application](../basics/app-anatomy.md) {prereq} - [Lifecycle of an SDK transaction](../basics/tx-lifecycle.md) {prereq} diff --git a/docs/building-modules/invariants.md b/docs/building-modules/invariants.md index 64b8e4696dc9..576baa796b96 100644 --- a/docs/building-modules/invariants.md +++ b/docs/building-modules/invariants.md @@ -1,11 +1,12 @@ # Invariants -## Pre-requisite Readings {hide} +An invariant is a property of the application that should always be true. In the context of the Cosmos SDK, an `Invariant` is a function that checks for a particular invariant. These functions are useful to detect bugs early on and act upon them to limit their potential consequences (e.g. by halting the chain). They are also useful in the development process of the application to detect bugs via simulations. {synopsis} + +## Pre-requisite Readings - [Keepers](./keeper.md) {prereq} diff --git a/docs/building-modules/keeper.md b/docs/building-modules/keeper.md index a9132bae041c..ee373d8b567f 100644 --- a/docs/building-modules/keeper.md +++ b/docs/building-modules/keeper.md @@ -1,11 +1,12 @@ # Keepers -## Pre-requisite Readings {hide} +`Keeper`s refer to a Cosmos SDK abstraction whose role is to manage access to the subset of the state defined by various modules. `Keeper`s are module-specific, i.e. the subset of state defined by a module can only be accessed by a `keeper` defined in said module. If a module needs to access the subset of state defined by another module, a reference to the second module's internal `keeper` needs to be passed to the first one. This is done in `app.go` during the instantiation of module keepers. {synopsis} + +## Pre-requisite Readings - [Introduction to SDK Modules](./intro.md) {prereq} diff --git a/docs/building-modules/messages-and-queries.md b/docs/building-modules/messages-and-queries.md index 3c87cc84eeab..30ea4f344d9f 100644 --- a/docs/building-modules/messages-and-queries.md +++ b/docs/building-modules/messages-and-queries.md @@ -1,11 +1,12 @@ # Messages and Queries -## Pre-requisite Readings {hide} +`Message`s and `Queries` are the two primary objects handled by modules. Most of the core components defined in a module, like `handler`s, `keeper`s and `querier`s, exist to process `message`s and `queries`. {synopsis} + +## Pre-requisite Readings - [Introduction to SDK Modules](./intro.md) {prereq} diff --git a/docs/building-modules/module-interfaces.md b/docs/building-modules/module-interfaces.md index bfb820d75e40..442777b3a9d1 100644 --- a/docs/building-modules/module-interfaces.md +++ b/docs/building-modules/module-interfaces.md @@ -1,11 +1,12 @@ # Module Interfaces -## Pre-requisite Readings {hide} +This document details how to build CLI and REST interfaces for a module. Examples from various SDK modules are included. {synopsis} + +## Pre-requisite Readings * [Building Modules Intro](./intro.md) {prereq} diff --git a/docs/building-modules/module-manager.md b/docs/building-modules/module-manager.md index bbafacca29c7..70291e1ee279 100644 --- a/docs/building-modules/module-manager.md +++ b/docs/building-modules/module-manager.md @@ -1,11 +1,12 @@ # Module Manager -## Pre-requisite Readings {hide} +Cosmos SDK modules need to implement the [`AppModule` interfaces](#application-module-interfaces), in order to be managed by the application's [module manager](#module-manager). The module manager plays an important role in [`message` and `query` routing](../core/baseapp.md#routing), and allows application developers to set the order of execution of a variety of functions like [`BeginBlocker` and `EndBlocker`](../basics/app-anatomy.md#begingblocker-and-endblocker). {synopsis} + +## Pre-requisite Readings - [Introduction to SDK Modules](./intro.md) {prereq} diff --git a/docs/building-modules/querier.md b/docs/building-modules/querier.md index be4750778661..61eb1c5e10df 100644 --- a/docs/building-modules/querier.md +++ b/docs/building-modules/querier.md @@ -1,11 +1,12 @@ # Queriers -## Pre-requisite Readings {hide} +A `Querier` designates a function that processes [`queries`](./messages-and-queries.md#queries). `querier`s are specific to the module in which they are defined, and only process `queries` defined within said module. They are called from `baseapp`'s [`Query` method](../core/baseapp.md#query). {synopsis} + +## Pre-requisite Readings - [Module Manager](./module-manager.md) {prereq} - [Messages and Queries](./messages-and-queries.md) {prereq} diff --git a/docs/building-modules/structure.md b/docs/building-modules/structure.md index 5f7315f91bd8..2745caff0658 100644 --- a/docs/building-modules/structure.md +++ b/docs/building-modules/structure.md @@ -1,12 +1,11 @@ # Recommended Folder Structure +This document outlines the recommended structure of Cosmos SDK modules. These ideas are meant to be applied as suggestions. Application developers are encouraged to improve upon and contribute to module structure and development design. {synopsis} + ## Structure A typical Cosmos SDK module can be structured as follows: diff --git a/docs/core/baseapp.md b/docs/core/baseapp.md index 04dbdfc61b47..bc0af1a78650 100644 --- a/docs/core/baseapp.md +++ b/docs/core/baseapp.md @@ -1,11 +1,12 @@ # Baseapp -## Pre-requisite Readings {hide} +This document describes `BaseApp`, the abstraction that implements the core functionalities of an SDK application. {synopsis} + +## Pre-requisite Readings - [Anatomy of an SDK application](../basics/app-anatomy.md) {prereq} - [Lifecycle of an SDK transaction](../basics/tx-lifecycle.md) {prereq} diff --git a/docs/core/context.md b/docs/core/context.md index f54c9d036d93..29af8ebb2262 100644 --- a/docs/core/context.md +++ b/docs/core/context.md @@ -1,11 +1,12 @@ # Context -## Pre-requisites Readings {hide} +The `context` is a data structure intended to be passed from function to function that carries information about the current state of the application. It holds a cached copy of the entire state as well as useful objects and information like `gasMeter`, `block height`, `consensus parameters` and more. {synopsis} + +## Pre-requisites Readings - [Anatomy of an SDK Application](../basics/app-anatomy.md) {prereq} - [Lifecycle of a Transaction](../basics/tx-lifecycle.md) {prereq} diff --git a/docs/core/encoding.md b/docs/core/encoding.md index ac05f52c676a..44b6d1348335 100644 --- a/docs/core/encoding.md +++ b/docs/core/encoding.md @@ -1,13 +1,12 @@ # Encoding -> NOTE: This document a WIP. +The `codec` is used everywhere in the Cosmos SDK to encode and decode structs and interfaces. The specific codec used in the Cosmos SDK is called `go-amino`. {synopsis} -## Pre-requisite Readings {hide} +## Pre-requisite Readings - [Anatomy of an SDK application](../basics/app-anatomy.md) {prereq} diff --git a/docs/core/events.md b/docs/core/events.md index d5ac5893f062..4df9f810ffeb 100644 --- a/docs/core/events.md +++ b/docs/core/events.md @@ -1,13 +1,12 @@ # Events -## Pre-Requisite Readings {hide} +`Event`s are objects that contain information about the execution of the application. They are mainly used by service providers like block explorers and wallet to track the execution of various messages and index transactions. {synopsis} + +## Pre-requisite Readings - [Anatomy of an SDK application](../basics/app-anatomy.md) {prereq} diff --git a/docs/core/node.md b/docs/core/node.md index 8ca558609504..54ae46e753c8 100644 --- a/docs/core/node.md +++ b/docs/core/node.md @@ -1,11 +1,12 @@ # Node Client (Daemon) -## Pre-requisite Readings {hide} +The main endpoint of an SDK application is the daemon client, otherwise known as the full-node client. The full-node runs the state-machine, starting from a genesis file. It connects to peers running the same client in order to receive and relay transactions, block proposals and signatures. The full-node is constituted of the application, defined with the Cosmos SDK, and of a consensus engine connected to the application via the ABCI. {synopsis} + +## Pre-requisite Readings - [Anatomy of an SDK application](../basics/app-anatomy.md) {prereq} diff --git a/docs/core/store.md b/docs/core/store.md index 31a8db919a0a..cd642d0f8a09 100644 --- a/docs/core/store.md +++ b/docs/core/store.md @@ -1,11 +1,12 @@ # Store -## Pre-requisite Readings {hide} +A store is a data structure that holds the state of the application. {synopsis} + +### Pre-requisite Readings - [Anatomy of an SDK application](../basics/app-anatomy.md) {prereq} diff --git a/docs/core/transactions.md b/docs/core/transactions.md index 3023d6fce8dd..42302d32063a 100644 --- a/docs/core/transactions.md +++ b/docs/core/transactions.md @@ -1,11 +1,12 @@ # Transactions -## Pre-requisite Readings {hide} +`Transactions` are objects created by end-users to trigger state changes in the application. {synopsis} + +## Pre-requisite Readings * [Anatomy of an SDK Application](../basics/app-anatomy.md) {prereq} diff --git a/docs/interfaces/cli.md b/docs/interfaces/cli.md index 0e7c786ed1f9..b06acdba3b00 100644 --- a/docs/interfaces/cli.md +++ b/docs/interfaces/cli.md @@ -1,11 +1,12 @@ # Command-Line Interface -## Pre-requisite Readings {hide} +This document describes how to create a commmand-line interface (CLI) for an [**application**](../basics/app-anatomy.md). A separate document for implementing a CLI for an SDK [**module**](../building-modules/intro.md) can be found [here](#../building-modules/module-interfaces.md#cli). {synopsis} + +## Pre-requisite Readings * [Lifecycle of a Query](./query-lifecycle.md) {prereq} diff --git a/docs/interfaces/interfaces-intro.md b/docs/interfaces/interfaces-intro.md index 029ed39accb5..fa2c8bf8d496 100644 --- a/docs/interfaces/interfaces-intro.md +++ b/docs/interfaces/interfaces-intro.md @@ -1,11 +1,12 @@ # Interfaces -## Pre-requisite Readings {hide} +Typically, SDK applications include interfaces to let end-users interact with the application. This document introduces the different types of interfaces for SDK applications. {synopsis} + +## Pre-requisite Readings * [Anatomy of an SDK Application](../basics/app-anatomy.md) {prereq} * [Lifecycle of a Transaction](../basics/tx-lifecycle.md) {prereq} diff --git a/docs/interfaces/keyring.md b/docs/interfaces/keyring.md index 34230d12a4e3..588a3a0c9ded 100644 --- a/docs/interfaces/keyring.md +++ b/docs/interfaces/keyring.md @@ -1,16 +1,17 @@ # The keyring +This document describes how to configure and use the keyring and its various backends for an [**application**](../basics/app-anatomy.md). A separate document for implementing a CLI for an SDK [**module**](../building-modules/intro.md) can be found [here](#../building-modules/module-interfaces.md#cli). {synopsis} + Starting with the v0.38.0 release, Cosmos SDK comes with a new keyring implementation that provides a set of commands to manage cryptographic keys in a secure fashion. The new keyring supports multiple storage backends, some of which may not be available on all operating systems. -## The 'os' backend +## The `os` backend The `os` backend relies on operating system-specific defaults to handle key storage securely. Typically, operating systems credentials sub-systems handle passwords prompt, @@ -33,7 +34,7 @@ client. designed to meet users' most common needs and provide them with a comfortable experience without compromising on security. -## The 'file' backend +## The `file` backend The `file` backend more closely resembles the keybase implementation used prior to v0.38.1. It stores the keyring encrypted within the apps configuration directory. This @@ -52,7 +53,7 @@ $ (echo '1234567890'; echo '1234567890'; echo '1234567890') | gaiad collect-gent The first time you add a key to an empty keyring, you will be prompted to type the password twice. ::: -## The 'pass' backend +## The `pass` backend The `pass` backend uses the [pass](https://www.passwordstore.org/) utility to manage on-disk encryption of keys' sensitive data and metadata. Keys are stored inside `gpg` encrypted files @@ -76,13 +77,13 @@ $ pass init Replace `` with your GPG key ID. You can use your personal GPG key or an alternative one you may want to use specifically to encrypt the password store. -## The 'test' backend +## The `test` backend The `test` backend is a password-less variation of the `file` backend. Keys are stored unencrypted on disk. This backend is meant for testing purposes only and **should never be used in production environments**. -## The 'kwallet' backend +## The `kwallet` backend The `kwallet` backend uses `KDE Wallet Manager`, which comes installed by default on the GNU/Linux distributions that ships KDE as default desktop environment. Please refer to diff --git a/docs/interfaces/query-lifecycle.md b/docs/interfaces/query-lifecycle.md index 5d1eab955af2..a18bd50bf490 100644 --- a/docs/interfaces/query-lifecycle.md +++ b/docs/interfaces/query-lifecycle.md @@ -1,11 +1,12 @@ # Query Lifecycle -## Pre-requisite Readings {hide} +This document describes the lifecycle of a query in a SDK application, from the user interface to application stores and back. The query will be referred to as `Query`. {synopsis} + +## Pre-requisite Readings * [Introduction to Interfaces](./interfaces-intro.md) {prereq} diff --git a/docs/interfaces/rest.md b/docs/interfaces/rest.md index 9ba57ffb2af9..da9f9e88d3f5 100644 --- a/docs/interfaces/rest.md +++ b/docs/interfaces/rest.md @@ -1,11 +1,12 @@ # REST Interface -## Prerequisites {hide} +This document describes how to create a REST interface for an SDK **application**. A separate document for creating a [**module**](../building-modules/intro.md) REST interface can be found [here](#../module-interfaces.md#rest). {synopsis} + +## Pre-requisite Readings - [Query Lifecycle](./query-lifecycle.md) {prereq} - [Application CLI](./cli.md) {prereq} diff --git a/docs/intro/why-app-specific.md b/docs/intro/why-app-specific.md index a3645f9e3095..5852489127b4 100644 --- a/docs/intro/why-app-specific.md +++ b/docs/intro/why-app-specific.md @@ -1,10 +1,11 @@ # Application-Specific Blockchains +This document explains what application-specific blockchains are, and why developers would want to build one as opposed to writing Smart Contracts. {synopsis} + ## What are application-specific blockchains? Application-specific blockchains are blockchains customized to operate a single application. Instead of building a decentralised application on top of an underlying blockchain like Ethereum, developers build their own blockchain from the ground up. This means building a full-node client, a light-client, and all the necessary interfaces (CLI, REST, ...) to interract with the nodes. diff --git a/docs/package-lock.json b/docs/package-lock.json index b2aa82c75358..fd136c2262c5 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -12,18 +12,35 @@ "@babel/highlight": "^7.8.3" } }, + "@babel/compat-data": { + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.8.6.tgz", + "integrity": "sha512-CurCIKPTkS25Mb8mz267vU95vy+TyUpnctEX2lV33xWNmHAfjruztgiPBbXZRh3xZZy1CYvGx6XfxyTVS+sk7Q==", + "requires": { + "browserslist": "^4.8.5", + "invariant": "^2.2.4", + "semver": "^5.5.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, "@babel/core": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.8.3.tgz", - "integrity": "sha512-4XFkf8AwyrEG7Ziu3L2L0Cv+WyY47Tcsp70JFmpftbAA1K7YL/sgE9jh9HyNj08Y/U50ItUchpN0w6HxAoX1rA==", + "version": "7.8.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.8.7.tgz", + "integrity": "sha512-rBlqF3Yko9cynC5CCFy6+K/w2N+Sq/ff2BPy+Krp7rHlABIr5epbA7OxVeKoMHB39LZOp1UY5SuLjy6uWi35yA==", "requires": { "@babel/code-frame": "^7.8.3", - "@babel/generator": "^7.8.3", - "@babel/helpers": "^7.8.3", - "@babel/parser": "^7.8.3", - "@babel/template": "^7.8.3", - "@babel/traverse": "^7.8.3", - "@babel/types": "^7.8.3", + "@babel/generator": "^7.8.7", + "@babel/helpers": "^7.8.4", + "@babel/parser": "^7.8.7", + "@babel/template": "^7.8.6", + "@babel/traverse": "^7.8.6", + "@babel/types": "^7.8.7", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.1", @@ -68,11 +85,11 @@ } }, "@babel/generator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.3.tgz", - "integrity": "sha512-WjoPk8hRpDRqqzRpvaR8/gDUPkrnOOeuT2m8cNICJtZH6mwaCo3v0OKMI7Y6SM1pBtyijnLtAL0HDi41pf41ug==", + "version": "7.8.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.7.tgz", + "integrity": "sha512-DQwjiKJqH4C3qGiyQCAExJHoZssn49JTMJgZ8SANGgVFdkupcUhLOdkAeoC6kmHZCPfoDG5M0b6cFlSN5wW7Ew==", "requires": { - "@babel/types": "^7.8.3", + "@babel/types": "^7.8.7", "jsesc": "^2.5.1", "lodash": "^4.17.13", "source-map": "^0.5.0" @@ -103,33 +120,53 @@ } }, "@babel/helper-call-delegate": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.8.3.tgz", - "integrity": "sha512-6Q05px0Eb+N4/GTyKPPvnkig7Lylw+QzihMpws9iiZQv7ZImf84ZsZpQH7QoWN4n4tm81SnSzPgHw2qtO0Zf3A==", + "version": "7.8.7", + "resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.8.7.tgz", + "integrity": "sha512-doAA5LAKhsFCR0LAFIf+r2RSMmC+m8f/oQ+URnUET/rWeEzC0yTRmAGyWkD4sSu3xwbS7MYQ2u+xlt1V5R56KQ==", "requires": { "@babel/helper-hoist-variables": "^7.8.3", "@babel/traverse": "^7.8.3", - "@babel/types": "^7.8.3" + "@babel/types": "^7.8.7" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.8.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.8.7.tgz", + "integrity": "sha512-4mWm8DCK2LugIS+p1yArqvG1Pf162upsIsjE7cNBjez+NjliQpVhj20obE520nao0o14DaTnFJv+Fw5a0JpoUw==", + "requires": { + "@babel/compat-data": "^7.8.6", + "browserslist": "^4.9.1", + "invariant": "^2.2.4", + "levenary": "^1.1.1", + "semver": "^5.5.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } } }, "@babel/helper-create-class-features-plugin": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.8.3.tgz", - "integrity": "sha512-qmp4pD7zeTxsv0JNecSBsEmG1ei2MqwJq4YQcK3ZWm/0t07QstWfvuV/vm3Qt5xNMFETn2SZqpMx2MQzbtq+KA==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.8.6.tgz", + "integrity": "sha512-klTBDdsr+VFFqaDHm5rR69OpEQtO2Qv8ECxHS1mNhJJvaHArR6a1xTf5K/eZW7eZpJbhCx3NW1Yt/sKsLXLblg==", "requires": { "@babel/helper-function-name": "^7.8.3", "@babel/helper-member-expression-to-functions": "^7.8.3", "@babel/helper-optimise-call-expression": "^7.8.3", "@babel/helper-plugin-utils": "^7.8.3", - "@babel/helper-replace-supers": "^7.8.3", + "@babel/helper-replace-supers": "^7.8.6", "@babel/helper-split-export-declaration": "^7.8.3" } }, "@babel/helper-create-regexp-features-plugin": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.3.tgz", - "integrity": "sha512-Gcsm1OHCUr9o9TcJln57xhWHtdXbA2pgQ58S0Lxlks0WMGNXuki4+GLfX0p+L2ZkINUGZvfkz8rzoqJQSthI+Q==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.6.tgz", + "integrity": "sha512-bPyujWfsHhV/ztUkwGHz/RPV1T1TDEsSZDsN42JPehndA+p1KKTh3npvTadux0ZhCrytx9tvjpWNowKby3tM6A==", "requires": { + "@babel/helper-annotate-as-pure": "^7.8.3", "@babel/helper-regex": "^7.8.3", "regexpu-core": "^4.6.0" } @@ -196,15 +233,16 @@ } }, "@babel/helper-module-transforms": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.8.3.tgz", - "integrity": "sha512-C7NG6B7vfBa/pwCOshpMbOYUmrYQDfCpVL/JCRu0ek8B5p8kue1+BCXpg2vOYs7w5ACB9GTOBYQ5U6NwrMg+3Q==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.8.6.tgz", + "integrity": "sha512-RDnGJSR5EFBJjG3deY0NiL0K9TO8SXxS9n/MPsbPK/s9LbQymuLNtlzvDiNS7IpecuL45cMeLVkA+HfmlrnkRg==", "requires": { "@babel/helper-module-imports": "^7.8.3", + "@babel/helper-replace-supers": "^7.8.6", "@babel/helper-simple-access": "^7.8.3", "@babel/helper-split-export-declaration": "^7.8.3", - "@babel/template": "^7.8.3", - "@babel/types": "^7.8.3", + "@babel/template": "^7.8.6", + "@babel/types": "^7.8.6", "lodash": "^4.17.13" } }, @@ -242,14 +280,14 @@ } }, "@babel/helper-replace-supers": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.8.3.tgz", - "integrity": "sha512-xOUssL6ho41U81etpLoT2RTdvdus4VfHamCuAm4AHxGr+0it5fnwoVdwUJ7GFEqCsQYzJUhcbsN9wB9apcYKFA==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.8.6.tgz", + "integrity": "sha512-PeMArdA4Sv/Wf4zXwBKPqVj7n9UF/xg6slNRtZW84FM7JpE1CbG8B612FyM4cxrf4fMAMGO0kR7voy1ForHHFA==", "requires": { "@babel/helper-member-expression-to-functions": "^7.8.3", "@babel/helper-optimise-call-expression": "^7.8.3", - "@babel/traverse": "^7.8.3", - "@babel/types": "^7.8.3" + "@babel/traverse": "^7.8.6", + "@babel/types": "^7.8.6" } }, "@babel/helper-simple-access": { @@ -281,12 +319,12 @@ } }, "@babel/helpers": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.8.3.tgz", - "integrity": "sha512-LmU3q9Pah/XyZU89QvBgGt+BCsTPoQa+73RxAQh8fb8qkDyIfeQnmgs+hvzhTCKTzqOyk7JTkS3MS1S8Mq5yrQ==", + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.8.4.tgz", + "integrity": "sha512-VPbe7wcQ4chu4TDQjimHv/5tj73qz88o12EPkO2ValS2QiQS/1F2SsjyIGNnAD0vF/nZS6Cf9i+vW6HIlnaR8w==", "requires": { "@babel/template": "^7.8.3", - "@babel/traverse": "^7.8.3", + "@babel/traverse": "^7.8.4", "@babel/types": "^7.8.3" } }, @@ -301,9 +339,9 @@ } }, "@babel/parser": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.3.tgz", - "integrity": "sha512-/V72F4Yp/qmHaTALizEm9Gf2eQHV3QyTL3K0cNfijwnMnb1L+LDlAubb/ZnSdGAVzVSWakujHYs1I26x66sMeQ==" + "version": "7.8.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.7.tgz", + "integrity": "sha512-9JWls8WilDXFGxs0phaXAZgpxTZhSk/yOYH2hTHC0X1yC7Z78IJfvR1vJ+rmJKq3I35td2XzXzN6ZLYlna+r/A==" }, "@babel/plugin-proposal-async-generator-functions": { "version": "7.8.3", @@ -334,6 +372,15 @@ "@babel/plugin-syntax-decorators": "^7.8.3" } }, + "@babel/plugin-proposal-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.8.3.tgz", + "integrity": "sha512-NyaBbyLFXFLT9FP+zk0kYlUlA8XtCUbehs67F0nnEg7KICgMc2mNkIeu9TYhKzyXMkrapZFwAhXLdnt4IYHy1w==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-dynamic-import": "^7.8.0" + } + }, "@babel/plugin-proposal-json-strings": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.8.3.tgz", @@ -343,6 +390,15 @@ "@babel/plugin-syntax-json-strings": "^7.8.0" } }, + "@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-TS9MlfzXpXKt6YYomudb/KU7nQI6/xnapG6in1uZxoxDghuSMZsPb6D2fyUwNYSAp4l1iR7QtFOjkqcRYcUsfw==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0" + } + }, "@babel/plugin-proposal-object-rest-spread": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.8.3.tgz", @@ -361,6 +417,15 @@ "@babel/plugin-syntax-optional-catch-binding": "^7.8.0" } }, + "@babel/plugin-proposal-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.8.3.tgz", + "integrity": "sha512-QIoIR9abkVn+seDE3OjA08jWcs3eZ9+wJCKSRgo3WdEU2csFYgdScb+8qHB3+WXsGJD55u+5hWCISI7ejXS+kg==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.0" + } + }, "@babel/plugin-proposal-unicode-property-regex": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.8.3.tgz", @@ -410,6 +475,14 @@ "@babel/helper-plugin-utils": "^7.8.3" } }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, "@babel/plugin-syntax-object-rest-spread": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", @@ -426,6 +499,22 @@ "@babel/helper-plugin-utils": "^7.8.0" } }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.8.3.tgz", + "integrity": "sha512-kwj1j9lL/6Wd0hROD3b/OZZ7MSrZLqqn9RAZ5+cYYsflQ9HZBIKCUkr3+uL1MEJ1NePiUbf98jjiMQSv0NMR9g==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, "@babel/plugin-transform-arrow-functions": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.8.3.tgz", @@ -462,16 +551,16 @@ } }, "@babel/plugin-transform-classes": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.8.3.tgz", - "integrity": "sha512-SjT0cwFJ+7Rbr1vQsvphAHwUHvSUPmMjMU/0P59G8U2HLFqSa082JO7zkbDNWs9kH/IUqpHI6xWNesGf8haF1w==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.8.6.tgz", + "integrity": "sha512-k9r8qRay/R6v5aWZkrEclEhKO6mc1CCQr2dLsVHBmOQiMpN6I2bpjX3vgnldUWeEI1GHVNByULVxZ4BdP4Hmdg==", "requires": { "@babel/helper-annotate-as-pure": "^7.8.3", "@babel/helper-define-map": "^7.8.3", "@babel/helper-function-name": "^7.8.3", "@babel/helper-optimise-call-expression": "^7.8.3", "@babel/helper-plugin-utils": "^7.8.3", - "@babel/helper-replace-supers": "^7.8.3", + "@babel/helper-replace-supers": "^7.8.6", "@babel/helper-split-export-declaration": "^7.8.3", "globals": "^11.1.0" } @@ -519,9 +608,9 @@ } }, "@babel/plugin-transform-for-of": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.8.3.tgz", - "integrity": "sha512-ZjXznLNTxhpf4Q5q3x1NsngzGA38t9naWH8Gt+0qYZEJAcvPI9waSStSh56u19Ofjr7QmD0wUsQ8hw8s/p1VnA==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.8.6.tgz", + "integrity": "sha512-M0pw4/1/KI5WAxPsdcUL/w2LJ7o89YHN3yLkzNjg7Yl15GlVGgzHyCU+FMeAxevHGsLVmUqbirlUIKTafPmzdw==", "requires": { "@babel/helper-plugin-utils": "^7.8.3" } @@ -543,6 +632,14 @@ "@babel/helper-plugin-utils": "^7.8.3" } }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.8.3.tgz", + "integrity": "sha512-3Wk2EXhnw+rP+IDkK6BdtPKsUE5IeZ6QOGrPYvw52NwBStw9V1ZVzxgK6fSKSxqUvH9eQPR3tm3cOq79HlsKYA==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, "@babel/plugin-transform-modules-amd": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.8.3.tgz", @@ -610,21 +707,37 @@ } }, "@babel/plugin-transform-parameters": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.8.3.tgz", - "integrity": "sha512-/pqngtGb54JwMBZ6S/D3XYylQDFtGjWrnoCF4gXZOUpFV/ujbxnoNGNvDGu6doFWRPBveE72qTx/RRU44j5I/Q==", + "version": "7.8.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.8.7.tgz", + "integrity": "sha512-brYWaEPTRimOctz2NDA3jnBbDi7SVN2T4wYuu0aqSzxC3nozFZngGaw29CJ9ZPweB7k+iFmZuoG3IVPIcXmD2g==", "requires": { - "@babel/helper-call-delegate": "^7.8.3", + "@babel/helper-call-delegate": "^7.8.7", "@babel/helper-get-function-arity": "^7.8.3", "@babel/helper-plugin-utils": "^7.8.3" } }, + "@babel/plugin-transform-property-literals": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.8.3.tgz", + "integrity": "sha512-uGiiXAZMqEoQhRWMK17VospMZh5sXWg+dlh2soffpkAl96KAm+WZuJfa6lcELotSRmooLqg0MWdH6UUq85nmmg==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, "@babel/plugin-transform-regenerator": { + "version": "7.8.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.7.tgz", + "integrity": "sha512-TIg+gAl4Z0a3WmD3mbYSk+J9ZUH6n/Yc57rtKRnlA/7rcCvpekHXe0CMZHP1gYp7/KLe9GHTuIba0vXmls6drA==", + "requires": { + "regenerator-transform": "^0.14.2" + } + }, + "@babel/plugin-transform-reserved-words": { "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.3.tgz", - "integrity": "sha512-qt/kcur/FxrQrzFR432FGZznkVAjiyFtCOANjkAKwCbt465L6ZCiUQh2oMYGU3Wo8LRFJxNDFwWn106S5wVUNA==", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.8.3.tgz", + "integrity": "sha512-mwMxcycN3omKFDjDQUl+8zyMsBfjRFr0Zn/64I41pmjv4NJuqcYlEtezwYtw9TFd9WR1vN5kiM+O0gMZzO6L0A==", "requires": { - "regenerator-transform": "^0.14.0" + "@babel/helper-plugin-utils": "^7.8.3" } }, "@babel/plugin-transform-runtime": { @@ -680,9 +793,9 @@ } }, "@babel/plugin-transform-typeof-symbol": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.8.3.tgz", - "integrity": "sha512-3TrkKd4LPqm4jHs6nPtSDI/SV9Cm5PRJkHLUgTcqRQQTMAZ44ZaAdDZJtvWFSaRcvT0a1rTmJ5ZA5tDKjleF3g==", + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.8.4.tgz", + "integrity": "sha512-2QKyfjGdvuNfHsb7qnBBlKclbD4CfshH2KvDabiijLMGXPHJXGxtDzwIF7bQP+T0ysw8fYTtxPafgfs/c1Lrqg==", "requires": { "@babel/helper-plugin-utils": "^7.8.3" } @@ -697,53 +810,67 @@ } }, "@babel/preset-env": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.3.4.tgz", - "integrity": "sha512-2mwqfYMK8weA0g0uBKOt4FE3iEodiHy9/CW0b+nWXcbL+pGzLx8ESYc+j9IIxr6LTDHWKgPm71i9smo02bw+gA==", + "version": "7.8.7", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.8.7.tgz", + "integrity": "sha512-BYftCVOdAYJk5ASsznKAUl53EMhfBbr8CJ1X+AJLfGPscQkwJFiaV/Wn9DPH/7fzm2v6iRYJKYHSqyynTGw0nw==", "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-async-generator-functions": "^7.2.0", - "@babel/plugin-proposal-json-strings": "^7.2.0", - "@babel/plugin-proposal-object-rest-spread": "^7.3.4", - "@babel/plugin-proposal-optional-catch-binding": "^7.2.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.2.0", - "@babel/plugin-syntax-async-generators": "^7.2.0", - "@babel/plugin-syntax-json-strings": "^7.2.0", - "@babel/plugin-syntax-object-rest-spread": "^7.2.0", - "@babel/plugin-syntax-optional-catch-binding": "^7.2.0", - "@babel/plugin-transform-arrow-functions": "^7.2.0", - "@babel/plugin-transform-async-to-generator": "^7.3.4", - "@babel/plugin-transform-block-scoped-functions": "^7.2.0", - "@babel/plugin-transform-block-scoping": "^7.3.4", - "@babel/plugin-transform-classes": "^7.3.4", - "@babel/plugin-transform-computed-properties": "^7.2.0", - "@babel/plugin-transform-destructuring": "^7.2.0", - "@babel/plugin-transform-dotall-regex": "^7.2.0", - "@babel/plugin-transform-duplicate-keys": "^7.2.0", - "@babel/plugin-transform-exponentiation-operator": "^7.2.0", - "@babel/plugin-transform-for-of": "^7.2.0", - "@babel/plugin-transform-function-name": "^7.2.0", - "@babel/plugin-transform-literals": "^7.2.0", - "@babel/plugin-transform-modules-amd": "^7.2.0", - "@babel/plugin-transform-modules-commonjs": "^7.2.0", - "@babel/plugin-transform-modules-systemjs": "^7.3.4", - "@babel/plugin-transform-modules-umd": "^7.2.0", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.3.0", - "@babel/plugin-transform-new-target": "^7.0.0", - "@babel/plugin-transform-object-super": "^7.2.0", - "@babel/plugin-transform-parameters": "^7.2.0", - "@babel/plugin-transform-regenerator": "^7.3.4", - "@babel/plugin-transform-shorthand-properties": "^7.2.0", - "@babel/plugin-transform-spread": "^7.2.0", - "@babel/plugin-transform-sticky-regex": "^7.2.0", - "@babel/plugin-transform-template-literals": "^7.2.0", - "@babel/plugin-transform-typeof-symbol": "^7.2.0", - "@babel/plugin-transform-unicode-regex": "^7.2.0", - "browserslist": "^4.3.4", + "@babel/compat-data": "^7.8.6", + "@babel/helper-compilation-targets": "^7.8.7", + "@babel/helper-module-imports": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-proposal-async-generator-functions": "^7.8.3", + "@babel/plugin-proposal-dynamic-import": "^7.8.3", + "@babel/plugin-proposal-json-strings": "^7.8.3", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-proposal-object-rest-spread": "^7.8.3", + "@babel/plugin-proposal-optional-catch-binding": "^7.8.3", + "@babel/plugin-proposal-optional-chaining": "^7.8.3", + "@babel/plugin-proposal-unicode-property-regex": "^7.8.3", + "@babel/plugin-syntax-async-generators": "^7.8.0", + "@babel/plugin-syntax-dynamic-import": "^7.8.0", + "@babel/plugin-syntax-json-strings": "^7.8.0", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0", + "@babel/plugin-syntax-object-rest-spread": "^7.8.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.0", + "@babel/plugin-syntax-top-level-await": "^7.8.3", + "@babel/plugin-transform-arrow-functions": "^7.8.3", + "@babel/plugin-transform-async-to-generator": "^7.8.3", + "@babel/plugin-transform-block-scoped-functions": "^7.8.3", + "@babel/plugin-transform-block-scoping": "^7.8.3", + "@babel/plugin-transform-classes": "^7.8.6", + "@babel/plugin-transform-computed-properties": "^7.8.3", + "@babel/plugin-transform-destructuring": "^7.8.3", + "@babel/plugin-transform-dotall-regex": "^7.8.3", + "@babel/plugin-transform-duplicate-keys": "^7.8.3", + "@babel/plugin-transform-exponentiation-operator": "^7.8.3", + "@babel/plugin-transform-for-of": "^7.8.6", + "@babel/plugin-transform-function-name": "^7.8.3", + "@babel/plugin-transform-literals": "^7.8.3", + "@babel/plugin-transform-member-expression-literals": "^7.8.3", + "@babel/plugin-transform-modules-amd": "^7.8.3", + "@babel/plugin-transform-modules-commonjs": "^7.8.3", + "@babel/plugin-transform-modules-systemjs": "^7.8.3", + "@babel/plugin-transform-modules-umd": "^7.8.3", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.8.3", + "@babel/plugin-transform-new-target": "^7.8.3", + "@babel/plugin-transform-object-super": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.8.7", + "@babel/plugin-transform-property-literals": "^7.8.3", + "@babel/plugin-transform-regenerator": "^7.8.7", + "@babel/plugin-transform-reserved-words": "^7.8.3", + "@babel/plugin-transform-shorthand-properties": "^7.8.3", + "@babel/plugin-transform-spread": "^7.8.3", + "@babel/plugin-transform-sticky-regex": "^7.8.3", + "@babel/plugin-transform-template-literals": "^7.8.3", + "@babel/plugin-transform-typeof-symbol": "^7.8.4", + "@babel/plugin-transform-unicode-regex": "^7.8.3", + "@babel/types": "^7.8.7", + "browserslist": "^4.8.5", + "core-js-compat": "^3.6.2", "invariant": "^2.2.2", - "js-levenshtein": "^1.1.3", - "semver": "^5.3.0" + "levenary": "^1.1.1", + "semver": "^5.5.0" }, "dependencies": { "semver": { @@ -754,57 +881,41 @@ } }, "@babel/runtime": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.8.3.tgz", - "integrity": "sha512-fVHx1rzEmwB130VTkLnxR+HmxcTjGzH12LYQcFFoBwakMd3aOMD4OsRN7tGG/UOYE2ektgFrS8uACAoRk1CY0w==", + "version": "7.8.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.8.7.tgz", + "integrity": "sha512-+AATMUFppJDw6aiR5NVPHqIQBlV/Pj8wY/EZH+lmvRdUo9xBaz/rF3alAwFJQavvKfeOlPE7oaaDHVbcySbCsg==", "requires": { - "regenerator-runtime": "^0.13.2" + "regenerator-runtime": "^0.13.4" }, "dependencies": { "regenerator-runtime": { - "version": "0.13.3", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz", - "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==" - } - } - }, - "@babel/runtime-corejs2": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs2/-/runtime-corejs2-7.8.3.tgz", - "integrity": "sha512-yxJXBKdIogkfF+wgeJrvU7Afp5ugBi92NzSgNPWWKVoQAlixH3gwMP6yYYr7SV1Dbc0HmNw7WUJkV5ksvtQuHg==", - "requires": { - "core-js": "^2.6.5", - "regenerator-runtime": "^0.13.2" - }, - "dependencies": { - "regenerator-runtime": { - "version": "0.13.3", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz", - "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==" + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.4.tgz", + "integrity": "sha512-plpwicqEzfEyTQohIKktWigcLzmNStMGwbOUbykx51/29Z3JOGYldaaNGK7ngNXV+UcoqvIMmloZ48Sr74sd+g==" } } }, "@babel/template": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", - "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", + "integrity": "sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg==", "requires": { "@babel/code-frame": "^7.8.3", - "@babel/parser": "^7.8.3", - "@babel/types": "^7.8.3" + "@babel/parser": "^7.8.6", + "@babel/types": "^7.8.6" } }, "@babel/traverse": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.3.tgz", - "integrity": "sha512-we+a2lti+eEImHmEXp7bM9cTxGzxPmBiVJlLVD+FuuQMeeO7RaDbutbgeheDkw+Xe3mCfJHnGOWLswT74m2IPg==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.6.tgz", + "integrity": "sha512-2B8l0db/DPi8iinITKuo7cbPznLCEk0kCxDoB9/N6gGNg/gxOXiR/IcymAFPiBwk5w6TtQ27w4wpElgp9btR9A==", "requires": { "@babel/code-frame": "^7.8.3", - "@babel/generator": "^7.8.3", + "@babel/generator": "^7.8.6", "@babel/helper-function-name": "^7.8.3", "@babel/helper-split-export-declaration": "^7.8.3", - "@babel/parser": "^7.8.3", - "@babel/types": "^7.8.3", + "@babel/parser": "^7.8.6", + "@babel/types": "^7.8.6", "debug": "^4.1.0", "globals": "^11.1.0", "lodash": "^4.17.13" @@ -826,9 +937,9 @@ } }, "@babel/types": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", - "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "version": "7.8.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.7.tgz", + "integrity": "sha512-k2TreEHxFA4CjGkL+GYjRyx35W0Mr7DP5+9q6WMkyKXB+904bYmG40syjMFV0oLlhhFCwWl0vA0DyzTDkwAiJw==", "requires": { "esutils": "^2.0.2", "lodash": "^4.17.13", @@ -843,10 +954,13 @@ } }, "@cosmos-ui/vue": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/@cosmos-ui/vue/-/vue-0.5.21.tgz", - "integrity": "sha512-Y60AMxFKgHrgE/EHxnGKaTcYUN1nJa5m3SylhsCe/d0AvzF9RSYGSPwVgDxmW4KiufBKXkv4PmiNG9WDNWwdxw==", + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@cosmos-ui/vue/-/vue-0.10.0.tgz", + "integrity": "sha512-dQySi+cjICuEl7OnFHMTY1ZKiVQ/dkZ22oiVFQRzfrhRLYa3HgEgM22EMBSzmhGVg6J52yS18OWpIruftWIW1Q==", "requires": { + "clipboard-copy": "^3.1.0", + "js-base64": "^2.5.2", + "prismjs": "^1.19.0", "tiny-cookie": "^2.3.1", "vue": "^2.6.10" } @@ -865,6 +979,19 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==" }, + "@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==" + }, + "@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "requires": { + "defer-to-connect": "^1.0.1" + } + }, "@types/babel-types": { "version": "7.0.7", "resolved": "https://registry.npmjs.org/@types/babel-types/-/babel-types-7.0.7.tgz", @@ -878,6 +1005,11 @@ "@types/babel-types": "*" } }, + "@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==" + }, "@types/events": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", @@ -899,9 +1031,9 @@ "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==" }, "@types/node": { - "version": "13.5.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-13.5.1.tgz", - "integrity": "sha512-Jj2W7VWQ2uM83f8Ls5ON9adxN98MvyJsMSASYFuSvrov8RMRY64Ayay7KV35ph1TSGIJ2gG9ZVDdEq3c3zaydA==" + "version": "13.9.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.9.0.tgz", + "integrity": "sha512-0ARSQootUG1RljH2HncpsY2TJBfGQIKOOi7kxzUY6z54ePu/ZD+wJA8zI2Q6v8rol2qpG/rvqsReco8zNMPvhQ==" }, "@types/q": { "version": "1.5.2", @@ -927,23 +1059,31 @@ } }, "@vue/babel-preset-app": { - "version": "3.12.1", - "resolved": "https://registry.npmjs.org/@vue/babel-preset-app/-/babel-preset-app-3.12.1.tgz", - "integrity": "sha512-Zjy5jQaikV1Pz+ri0YgXFS7q4/5wCxB5tRkDOEIt5+4105u0Feb/pvH20nVL6nx9GyXrECFfcm7Yxr/z++OaPQ==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@vue/babel-preset-app/-/babel-preset-app-4.2.3.tgz", + "integrity": "sha512-Xlc8d9Ebgu9pNZMUxKZWVP2CctVZzfX3LAxjBDWAAIiVpdXX4IkQQCevDhgiANFzlmE3KXtiSgPGs57Sso2g7Q==", "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/plugin-proposal-class-properties": "^7.0.0", - "@babel/plugin-proposal-decorators": "^7.1.0", - "@babel/plugin-syntax-dynamic-import": "^7.0.0", - "@babel/plugin-syntax-jsx": "^7.0.0", - "@babel/plugin-transform-runtime": "^7.4.0", - "@babel/preset-env": "^7.0.0 < 7.4.0", - "@babel/runtime": "^7.0.0", - "@babel/runtime-corejs2": "^7.2.0", - "@vue/babel-preset-jsx": "^1.0.0", - "babel-plugin-dynamic-import-node": "^2.2.0", - "babel-plugin-module-resolver": "3.2.0", - "core-js": "^2.6.5" + "@babel/core": "^7.8.4", + "@babel/helper-compilation-targets": "^7.8.4", + "@babel/helper-module-imports": "^7.8.3", + "@babel/plugin-proposal-class-properties": "^7.8.3", + "@babel/plugin-proposal-decorators": "^7.8.3", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-jsx": "^7.8.3", + "@babel/plugin-transform-runtime": "^7.8.3", + "@babel/preset-env": "^7.8.4", + "@babel/runtime": "^7.8.4", + "@vue/babel-preset-jsx": "^1.1.2", + "babel-plugin-dynamic-import-node": "^2.3.0", + "core-js": "^3.6.4", + "core-js-compat": "^3.6.4" + }, + "dependencies": { + "core-js": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.4.tgz", + "integrity": "sha512-4paDGScNgZP2IXXilaffL9X7968RuvwlkK3xWtZRVqgd8SYNiVKRJvkFd1aqqEuPfN7E68ZHEp9hDj6lHj4Hyw==" + } } }, "@vue/babel-preset-jsx": { @@ -1045,23 +1185,24 @@ } }, "@vuepress/core": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@vuepress/core/-/core-1.2.0.tgz", - "integrity": "sha512-ZIsUkQIF+h4Yk6q4okoRnRwRhcYePu/kNiL0WWPDGycjai8cFqFjLDP/tJjfTKXmn9A62j2ETjSwaiMxCtDkyw==", - "requires": { - "@babel/core": "^7.0.0", - "@vue/babel-preset-app": "^3.1.1", - "@vuepress/markdown": "^1.2.0", - "@vuepress/markdown-loader": "^1.2.0", - "@vuepress/plugin-last-updated": "^1.2.0", - "@vuepress/plugin-register-components": "^1.2.0", - "@vuepress/shared-utils": "^1.2.0", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@vuepress/core/-/core-1.3.1.tgz", + "integrity": "sha512-BBtM3imJUPwCTz0Fzl++ZLgf1afcsas4jo/wbVvroIdI0R6GEbXdivnisVGD48tZ10WcwvY94tlL1jWO8xV6bg==", + "requires": { + "@babel/core": "^7.8.4", + "@vue/babel-preset-app": "^4.1.2", + "@vuepress/markdown": "^1.3.1", + "@vuepress/markdown-loader": "^1.3.1", + "@vuepress/plugin-last-updated": "^1.3.1", + "@vuepress/plugin-register-components": "^1.3.1", + "@vuepress/shared-utils": "^1.3.1", "autoprefixer": "^9.5.1", "babel-loader": "^8.0.4", "cache-loader": "^3.0.0", "chokidar": "^2.0.3", "connect-history-api-fallback": "^1.5.0", "copy-webpack-plugin": "^5.0.2", + "core-js": "^3.6.4", "cross-spawn": "^6.0.5", "css-loader": "^2.1.1", "file-loader": "^3.0.1", @@ -1082,18 +1223,25 @@ "vuepress-html-webpack-plugin": "^3.2.0", "vuepress-plugin-container": "^2.0.2", "webpack": "^4.8.1", - "webpack-chain": "^4.6.0", + "webpack-chain": "^6.0.0", "webpack-dev-server": "^3.5.1", "webpack-merge": "^4.1.2", "webpackbar": "3.2.0" + }, + "dependencies": { + "core-js": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.4.tgz", + "integrity": "sha512-4paDGScNgZP2IXXilaffL9X7968RuvwlkK3xWtZRVqgd8SYNiVKRJvkFd1aqqEuPfN7E68ZHEp9hDj6lHj4Hyw==" + } } }, "@vuepress/markdown": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@vuepress/markdown/-/markdown-1.2.0.tgz", - "integrity": "sha512-RLRQmTu5wJbCO4Qv+J0K53o5Ew7nAGItLwWyzCbIUB6pRsya3kqSCViWQVlKlS53zFTmRHuAC9tJMRdzly3mCA==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@vuepress/markdown/-/markdown-1.3.1.tgz", + "integrity": "sha512-UJoGHR9GsFnPk+Jot8tieO4M6WJQ5CkdIWlQfbpC1+Z0ETJjlNIel23BKLNzqfo3NhLq+/i33RnzMVzkBKlVvQ==", "requires": { - "@vuepress/shared-utils": "^1.2.0", + "@vuepress/shared-utils": "^1.3.1", "markdown-it": "^8.4.1", "markdown-it-anchor": "^5.0.2", "markdown-it-chain": "^1.3.0", @@ -1122,61 +1270,61 @@ } }, "@vuepress/markdown-loader": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@vuepress/markdown-loader/-/markdown-loader-1.2.0.tgz", - "integrity": "sha512-gOZzoHjfp/W6t+qKBRdbHS/9TwRnNuhY7V+yFzxofNONFHQULofIN/arG+ptYc2SuqJ541jqudNQW+ldHNMC2w==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@vuepress/markdown-loader/-/markdown-loader-1.3.1.tgz", + "integrity": "sha512-JxjQgSClW51hE0bCrcAqnG0yrvVURzcZwP2zbWkcCMD7vomHbvkHyPmuf6oa8Jk4S//RQUYINrzC/KrDjVuzIQ==", "requires": { - "@vuepress/markdown": "^1.2.0", + "@vuepress/markdown": "^1.3.1", "loader-utils": "^1.1.0", "lru-cache": "^5.1.1" } }, "@vuepress/plugin-active-header-links": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@vuepress/plugin-active-header-links/-/plugin-active-header-links-1.2.0.tgz", - "integrity": "sha512-vdi7l96pElJvEmcx6t9DWJNH25TIurS8acjN3+b7o4NzdaszFn5j6klN6WtI4Z+5BVDrxHP5W1F3Ebw8SZyupA==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@vuepress/plugin-active-header-links/-/plugin-active-header-links-1.3.1.tgz", + "integrity": "sha512-mrawXXAv2K1GrD1JNoFHxF8xX3KiphVcwvf+58GXpsyAQ5ag5X1BZG3gCA1JdNFUe3SXRh5jF6HTBuM2dc6Ovg==", "requires": { "lodash.debounce": "^4.0.8" } }, "@vuepress/plugin-google-analytics": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@vuepress/plugin-google-analytics/-/plugin-google-analytics-1.2.0.tgz", - "integrity": "sha512-0zol5D4Efb5GKel7ADO/s65MLtKSLnOEGkeWzuipkWomSQPzP7TJ3+/RcYBnGdyBFHd1BSpTUHGK0b/IGwM3UA==" + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@vuepress/plugin-google-analytics/-/plugin-google-analytics-1.3.1.tgz", + "integrity": "sha512-Xb7g86JT/LD1sLYG2txvpp4ztDTOqN5yNRZK5OtzEekCh0NWxIxz0fEYKqVlaskIFnzoA1dfizudyjGCKY+hMw==" }, "@vuepress/plugin-last-updated": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@vuepress/plugin-last-updated/-/plugin-last-updated-1.2.0.tgz", - "integrity": "sha512-j4uZb/MXDyG+v9QCG3T/rkiaOhC/ib7NKCt1cjn3GOwvWTDmB5UZm9EBhUpbDNrBgxW+SaHOe3kMVNO8bGOTGw==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@vuepress/plugin-last-updated/-/plugin-last-updated-1.3.1.tgz", + "integrity": "sha512-n1EhhFcaWxQtbC9ICyLg8kmSULjV18wYMbHCyaKRYAvyhlPau95zbSpQfG2Nl3ZgFR6kRodK6AmZUOgho0zh/g==", "requires": { "cross-spawn": "^6.0.5" } }, "@vuepress/plugin-nprogress": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@vuepress/plugin-nprogress/-/plugin-nprogress-1.2.0.tgz", - "integrity": "sha512-0apt3Dp6XVCOkLViX6seKSEJgARihi+pX3/r8j8ndFp9Y+vmgLFZnQnGE5iKNi1ty+A6PZOK0RQcBjwTAU4pAw==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@vuepress/plugin-nprogress/-/plugin-nprogress-1.3.1.tgz", + "integrity": "sha512-vDBnIhTgGZbADwhaatSLsFnuj+MDDpCWQ79m9o+8RtMZO2HemedcCRNIj/ZLRJSBFjXrDdnXF5lpW4EEIeRaew==", "requires": { "nprogress": "^0.2.0" } }, "@vuepress/plugin-register-components": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@vuepress/plugin-register-components/-/plugin-register-components-1.2.0.tgz", - "integrity": "sha512-C32b8sbGtDEX8I3SUUKS/w2rThiRFiKxmzNcJD996me7VY/4rgmZ8CxGtb6G9wByVoK0UdG1SOkrgOPdSCm80A==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@vuepress/plugin-register-components/-/plugin-register-components-1.3.1.tgz", + "integrity": "sha512-ae/94omRTPZkJKuVic8Rvzfnu2NtqsyVPYTL6qcnjDgxieR3L7EAYLNEvYpg1jof+QTHoEDCaVU2c63chZcfEQ==", "requires": { - "@vuepress/shared-utils": "^1.2.0" + "@vuepress/shared-utils": "^1.3.1" } }, "@vuepress/plugin-search": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@vuepress/plugin-search/-/plugin-search-1.2.0.tgz", - "integrity": "sha512-QU3JfnMfImDAArbJOVH1q1iCDE5QrT99GLpNGo6KQYZWqY1TWAbgyf8C2hQdaI03co1lkU2Wn/iqzHJ5WHlueg==" + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@vuepress/plugin-search/-/plugin-search-1.3.1.tgz", + "integrity": "sha512-iOIvMWUTPHrGxjDprFoGTcuI8Y8/6e6JjLO4mO6qe6qVqR1yCQ8cJzVYXIizjEHUFYJ04uZ3jF9gBV8npS+3ZQ==" }, "@vuepress/shared-utils": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@vuepress/shared-utils/-/shared-utils-1.2.0.tgz", - "integrity": "sha512-wo5Ng2/xzsmIYCzvWxgLFlDBp7FkmJp2shAkbSurLNAh1vixhs0+LyDxsk01+m34ktJSp9rTUUsm6khw/Fvo0w==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@vuepress/shared-utils/-/shared-utils-1.3.1.tgz", + "integrity": "sha512-MlIAlnptjDC9+l0SJKW6BpkuwtxfKDzq4Rmag75RdyIqkkNv4EsCXZ8Y3HSuzENWFBwoD31jLC+nCZ3hULcvSg==", "requires": { "chalk": "^2.3.2", "diacritics": "^1.3.0", @@ -1190,29 +1338,19 @@ } }, "@vuepress/theme-default": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@vuepress/theme-default/-/theme-default-1.2.0.tgz", - "integrity": "sha512-mJxAMYQQv4OrGFsArMlONu8RpCzPUVx81dumkyTT4ay5PXAWTj+WDeFQLOT3j0g9QrDJGnHhbiw2aS+R/0WUyQ==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@vuepress/theme-default/-/theme-default-1.3.1.tgz", + "integrity": "sha512-CihkB6/+5vfgeTI5HRDs4+QgTkIN4/K54OpQCGLW51OinXuz4rjMVQW2uSlSqSeKEr+MERHa+Jc5deIpA0opoA==", "requires": { - "@vuepress/plugin-active-header-links": "^1.2.0", - "@vuepress/plugin-nprogress": "^1.2.0", - "@vuepress/plugin-search": "^1.2.0", + "@vuepress/plugin-active-header-links": "^1.3.1", + "@vuepress/plugin-nprogress": "^1.3.1", + "@vuepress/plugin-search": "^1.3.1", "docsearch.js": "^2.5.2", "lodash": "^4.17.15", "stylus": "^0.54.5", "stylus-loader": "^3.0.2", "vuepress-plugin-container": "^2.0.2", "vuepress-plugin-smooth-scroll": "^0.0.3" - }, - "dependencies": { - "vuepress-plugin-smooth-scroll": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/vuepress-plugin-smooth-scroll/-/vuepress-plugin-smooth-scroll-0.0.3.tgz", - "integrity": "sha512-qsQkDftLVFLe8BiviIHaLV0Ea38YLZKKonDGsNQy1IE0wllFpFIEldWD8frWZtDFdx6b/O3KDMgVQ0qp5NjJCg==", - "requires": { - "smoothscroll-polyfill": "^0.4.3" - } - } } }, "@webassemblyjs/ast": { @@ -1423,9 +1561,9 @@ "integrity": "sha1-xdG9SxKQCPEWPyNvhuX66iAm4u8=" }, "ajv": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.11.0.tgz", - "integrity": "sha512-nCprB/0syFYy9fVYU1ox1l2KN8S9I+tziH8D4zdZuLT3N6RMlGSGt5FSTpAiHB/Whv8Qs1cWHma1aMKZyaHRKA==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.0.tgz", + "integrity": "sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw==", "requires": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -1515,17 +1653,50 @@ "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=" }, + "ansi-align": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz", + "integrity": "sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==", + "requires": { + "string-width": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, "ansi-colors": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==" }, "ansi-escapes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.0.tgz", - "integrity": "sha512-EiYhwo0v255HUL6eDyuLrXEkTi7WwVCLAw+SeOQ7M7qdun1z1pum4DEm/nuqIVbPvi9RPPc9k9LbyBv6H0DwVg==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", + "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", "requires": { - "type-fest": "^0.8.1" + "type-fest": "^0.11.0" } }, "ansi-html": { @@ -1760,18 +1931,6 @@ "object.assign": "^4.1.0" } }, - "babel-plugin-module-resolver": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-module-resolver/-/babel-plugin-module-resolver-3.2.0.tgz", - "integrity": "sha512-tjR0GvSndzPew/Iayf4uICWZqjBwnlMWjSx6brryfQ81F9rxBVqwDJtFCV8oOs0+vJeefK9TmdZtkIFdFe1UnA==", - "requires": { - "find-babel-config": "^1.1.0", - "glob": "^7.1.2", - "pkg-up": "^2.0.0", - "reselect": "^3.0.1", - "resolve": "^1.4.0" - } - }, "babel-runtime": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", @@ -1949,6 +2108,110 @@ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" }, + "boxen": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", + "integrity": "sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==", + "requires": { + "ansi-align": "^3.0.0", + "camelcase": "^5.3.1", + "chalk": "^3.0.0", + "cli-boxes": "^2.2.0", + "string-width": "^4.1.0", + "term-size": "^2.1.0", + "type-fest": "^0.8.1", + "widest-line": "^3.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + }, + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==" + } + } + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -2046,13 +2309,13 @@ } }, "browserslist": { - "version": "4.8.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.8.5.tgz", - "integrity": "sha512-4LMHuicxkabIB+n9874jZX/az1IaZ5a+EUuvD7KFOu9x/Bd5YHyO0DIz2ls/Kl8g0ItS4X/ilEgf4T1Br0lgSg==", + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.9.1.tgz", + "integrity": "sha512-Q0DnKq20End3raFulq6Vfp1ecB9fh8yUNV55s8sekaDDeqBaCtWlRHCUdaWyUeSSBJM7IbM6HcsyaeYqgeDhnw==", "requires": { - "caniuse-lite": "^1.0.30001022", - "electron-to-chromium": "^1.3.338", - "node-releases": "^1.1.46" + "caniuse-lite": "^1.0.30001030", + "electron-to-chromium": "^1.3.363", + "node-releases": "^1.1.50" } }, "buffer": { @@ -2096,9 +2359,9 @@ "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" }, "cac": { - "version": "6.5.6", - "resolved": "https://registry.npmjs.org/cac/-/cac-6.5.6.tgz", - "integrity": "sha512-8jsGLeBiYEVYTDExaj/rDPG4tyra4yjjacIL10TQ+MobPcg9/IST+dkKLu6sOzq0GcIC6fQqX1nkH9HoskQLAw==" + "version": "6.5.7", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.5.7.tgz", + "integrity": "sha512-DjjOqLvoX/oO/snovTNm553kRYWTmIIQBfHQ2UqktbCudoHJuxzvRhjwdCHkXrQwp/lnu3bYyZ+LfaHtwk0Wjw==" }, "cacache": { "version": "12.0.3", @@ -2151,6 +2414,40 @@ "schema-utils": "^1.0.0" } }, + "cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "dependencies": { + "get-stream": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", + "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", + "requires": { + "pump": "^3.0.0" + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==" + }, + "normalize-url": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz", + "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==" + } + } + }, "call-me-maybe": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", @@ -2203,9 +2500,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001023", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001023.tgz", - "integrity": "sha512-C5TDMiYG11EOhVOA62W1p3UsJ2z4DsHtMBQtjzp3ZsUglcQn62WOUgW0y795c7A5uZ+GCEIvzkMatLIlAsbNTA==" + "version": "1.0.30001033", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001033.tgz", + "integrity": "sha512-8Ibzxee6ibc5q88cM1usPsMpJOG5CTq0s/dKOmlekPbDGKt+UrnOOTPSjQz3kVo6yL7N4SB5xd+FGLHQmbzh6A==" }, "caseless": { "version": "0.12.0", @@ -2279,9 +2576,9 @@ } }, "chownr": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.3.tgz", - "integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==" + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" }, "chrome-trace-event": { "version": "1.0.2", @@ -2334,10 +2631,15 @@ "source-map": "~0.6.0" } }, + "cli-boxes": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.0.tgz", + "integrity": "sha512-gpaBrMAizVEANOpfZp/EEUixTXDyGt7DFzdK5hU+UbWt/J0lB0w20ncZj59Z9a93xHb9u12zF5BS6i9RKbtg4w==" + }, "clipboard": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.4.tgz", - "integrity": "sha512-Vw26VSLRpJfBofiVaFb/I8PVfdI1OxKcYShe6fm0sP/DtmiWQNCjhM/okTvdCo0G+lMMm1rMYbk4IK4x1X+kgQ==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.6.tgz", + "integrity": "sha512-g5zbiixBRk/wyKakSwCKd7vQXDjFnAMGHoEyBogG/bw9kTD9GvdAvaoRR1ALcEzt3pVKxZR0pViekPMIS0QyGg==", "optional": true, "requires": { "good-listener": "^1.2.2", @@ -2360,6 +2662,14 @@ "wordwrap": "0.0.2" } }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "requires": { + "mimic-response": "^1.0.0" + } + }, "coa": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", @@ -2520,6 +2830,29 @@ } } }, + "configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "requires": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + }, + "dependencies": { + "make-dir": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.0.2.tgz", + "integrity": "sha512-rYKABKutXa6vXTXhoV18cBE7PaewPXHe/Bdq4v+ZLMhxbWApkFFplT0LcbMW+6BbjnQXzZ/sAvSE/JdguApG5w==", + "requires": { + "semver": "^6.0.0" + } + } + } + }, "connect-history-api-fallback": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", @@ -2659,19 +2992,6 @@ "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==" }, - "p-limit": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", - "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", - "requires": { - "p-try": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" - }, "pify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", @@ -2689,6 +3009,22 @@ "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz", "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==" }, + "core-js-compat": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.6.4.tgz", + "integrity": "sha512-zAa3IZPvsJ0slViBQ2z+vgyyTuhd3MFn1rBQjZSKVEgB0UMYhUkCj9jJUVPgGTGqWvsBVmfnruXgTcNyTlEiSA==", + "requires": { + "browserslist": "^4.8.3", + "semver": "7.0.0" + }, + "dependencies": { + "semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==" + } + } + }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -2776,6 +3112,11 @@ "randomfill": "^1.0.3" } }, + "crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==" + }, "css": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz", @@ -2864,11 +3205,6 @@ "source-map": "^0.6.1" } }, - "css-unit-converter": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.1.tgz", - "integrity": "sha1-2bkoGtz9jO2TW9urqDeGiX9k6ZY=" - }, "css-what": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", @@ -2994,6 +3330,14 @@ "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "requires": { + "mimic-response": "^1.0.0" + } + }, "deep-equal": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", @@ -3007,6 +3351,11 @@ "regexp.prototype.flags": "^1.2.0" } }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + }, "deepmerge": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-1.5.2.tgz", @@ -3021,6 +3370,11 @@ "ip-regex": "^2.1.0" } }, + "defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==" + }, "define-properties": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", @@ -3257,13 +3611,18 @@ } }, "dot-prop": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", - "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.2.0.tgz", + "integrity": "sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A==", "requires": { - "is-obj": "^1.0.0" + "is-obj": "^2.0.0" } }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" + }, "duplexify": { "version": "3.7.1", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", @@ -3319,9 +3678,9 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, "electron-to-chromium": { - "version": "1.3.341", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.341.tgz", - "integrity": "sha512-iezlV55/tan1rvdvt7yg7VHRSkt+sKfzQ16wTDqTbQqtl4+pSUkKPXpQHDvEt0c7gKcUHHwUbffOgXz6bn096g==" + "version": "1.3.375", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.375.tgz", + "integrity": "sha512-zmaFnYVBtfpF8bGRYxgPeVAlXB7N3On8rjBE2ROc6wOpTPpzRWaiHo6KkbJMvlH07CH33uks/TEb6kuMMn8q6A==" }, "elliptic": { "version": "6.5.2", @@ -3343,9 +3702,9 @@ "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" }, "emojis-list": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", - "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==" }, "encodeurl": { "version": "1.0.2", @@ -3476,6 +3835,11 @@ "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" }, + "escape-goat": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==" + }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -3759,9 +4123,9 @@ "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==" }, "figures": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.1.0.tgz", - "integrity": "sha512-ravh8VRXqHuMvZt/d8GblBeqDMkdJMBdv/2KntFH+ra5MXkO7nxNKpzQ3n6QD/2da1kH0aWmNISdvhM7gl2gVg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", "requires": { "escape-string-regexp": "^1.0.5" } @@ -3816,22 +4180,6 @@ } } }, - "find-babel-config": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/find-babel-config/-/find-babel-config-1.2.0.tgz", - "integrity": "sha512-jB2CHJeqy6a820ssiqwrKMeyC6nNdmrcgkKWJWmpoxpE8RKciYJXCcXRq1h2AzCo5I5BJeN2tkGEO3hLTuePRA==", - "requires": { - "json5": "^0.5.1", - "path-exists": "^3.0.0" - }, - "dependencies": { - "json5": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" - } - } - }, "find-cache-dir": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", @@ -3843,11 +4191,11 @@ } }, "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "requires": { - "locate-path": "^2.0.0" + "locate-path": "^3.0.0" } }, "flush-write-stream": { @@ -4528,9 +4876,9 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "fuse.js": { - "version": "3.4.6", - "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-3.4.6.tgz", - "integrity": "sha512-H6aJY4UpLFwxj1+5nAvufom5b2BT2v45P1MkPvdGIK8fWjQx/7o6tTT1+ALV0yawQvbmvCF0ufl2et8eJ7v7Cg==" + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-3.6.1.tgz", + "integrity": "sha512-hT9yh/tiinkmirKrlv4KWOjztdoZo1mx9Qh4KvWqC7isoXwdUY3PNWUxceF4/qO9R6riA2C29jdTOeQOIROjgw==" }, "gensync": { "version": "1.0.0-beta.1", @@ -4609,6 +4957,14 @@ "process": "^0.11.10" } }, + "global-dirs": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.0.1.tgz", + "integrity": "sha512-5HqUqdhkEovj2Of/ms3IeS/EekcO54ytHRLV4PEY2rhRwrHXLQjeVEES0Lhka0xwNDtGYn58wyC4s5+MHsOO6A==", + "requires": { + "ini": "^1.3.5" + } + }, "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -4638,6 +4994,24 @@ "delegate": "^3.1.2" } }, + "got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "requires": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + } + }, "graceful-fs": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", @@ -4728,6 +5102,11 @@ } } }, + "has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==" + }, "hash-base": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", @@ -4909,6 +5288,11 @@ } } }, + "http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" + }, "http-deceiver": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", @@ -5040,6 +5424,11 @@ "resolve-from": "^3.0.0" } }, + "import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=" + }, "import-local": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", @@ -5078,6 +5467,11 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" + }, "internal-ip": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz", @@ -5111,9 +5505,9 @@ "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=" }, "ipaddr.js": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz", - "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==" + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" }, "is-absolute-url": { "version": "2.1.0", @@ -5166,6 +5560,21 @@ "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==" }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "requires": { + "ci-info": "^2.0.0" + }, + "dependencies": { + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" + } + } + }, "is-color-stop": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz", @@ -5263,6 +5672,27 @@ "is-extglob": "^2.1.1" } }, + "is-installed-globally": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.1.tgz", + "integrity": "sha512-oiEcGoQbGc+3/iijAijrK2qFpkNoNjsHOm/5V5iaeydyrS/hnwaRCEgH5cpW0P3T1lSjV5piB7S5b5lEugNLhg==", + "requires": { + "global-dirs": "^2.0.1", + "is-path-inside": "^3.0.1" + }, + "dependencies": { + "is-path-inside": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.2.tgz", + "integrity": "sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg==" + } + } + }, + "is-npm": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz", + "integrity": "sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig==" + }, "is-number": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", @@ -5282,9 +5712,9 @@ } }, "is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==" }, "is-path-cwd": { "version": "2.2.0", @@ -5374,6 +5804,11 @@ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=" }, + "is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==" + }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -5399,10 +5834,10 @@ "resolved": "https://registry.npmjs.org/javascript-stringify/-/javascript-stringify-1.6.0.tgz", "integrity": "sha1-FC0RHzpuPa6PSpr9d9RYVbWpzOM=" }, - "js-levenshtein": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", - "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==" + "js-base64": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.5.2.tgz", + "integrity": "sha512-Vg8czh0Q7sFBSUMWWArX/miJeBWYBPpdU/3M/DKSaekLMqrqVPaedp+5mZhie/r0lgrcaYBfwXatEew6gwgiQQ==" }, "js-stringify": { "version": "1.0.2", @@ -5433,6 +5868,11 @@ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" }, + "json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=" + }, "json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", @@ -5494,6 +5934,14 @@ "promise": "^7.0.1" } }, + "keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "requires": { + "json-buffer": "3.0.0" + } + }, "killable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", @@ -5513,6 +5961,14 @@ "webpack-sources": "^1.1.0" } }, + "latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "requires": { + "package-json": "^6.3.0" + } + }, "lazy-cache": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", @@ -5526,6 +5982,19 @@ "invert-kv": "^2.0.0" } }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==" + }, + "levenary": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/levenary/-/levenary-1.1.1.tgz", + "integrity": "sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ==", + "requires": { + "leven": "^3.1.0" + } + }, "linkify-it": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", @@ -5545,21 +6014,21 @@ "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==" }, "loader-utils": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", - "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", "requires": { "big.js": "^5.2.2", - "emojis-list": "^2.0.0", + "emojis-list": "^3.0.0", "json5": "^1.0.1" } }, "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "requires": { - "p-locate": "^2.0.0", + "p-locate": "^3.0.0", "path-exists": "^3.0.0" } }, @@ -5631,9 +6100,9 @@ "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=" }, "loglevel": { - "version": "1.6.6", - "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.6.tgz", - "integrity": "sha512-Sgr5lbboAUBo3eXCSPL4/KoVz3ROKquOjcctxmHIt+vol2DrqTQe3SwkKKuYhEiWB5kYa13YyopJ69deJ1irzQ==" + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.7.tgz", + "integrity": "sha512-cY2eLFrQSAfVPhCgH1s7JI73tMbg9YC3v3+ZHVW67sBS7UxWzNEk/ZBbSfLykBWHp33dqqtOv82gjhKEi81T/A==" }, "longest": { "version": "1.0.1", @@ -5653,6 +6122,11 @@ "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=" }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==" + }, "lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -5721,9 +6195,9 @@ "integrity": "sha512-xLIjLQmtym3QpoY9llBgApknl7pxAcN3WDRc2d3rwpl+/YvDZHPmKscGs+L6E05xf2KrCXPBvosWt7MZukwSpQ==" }, "markdown-it-attrs": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/markdown-it-attrs/-/markdown-it-attrs-3.0.1.tgz", - "integrity": "sha512-fcpdmxdEsctDVJEunPyrirVtU/6zcTMxPxAu4Ofz51PKAa8vRMpmGQXsmXx1HTdIdUPoDonm/RhS/+jTNywj/Q==" + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/markdown-it-attrs/-/markdown-it-attrs-3.0.2.tgz", + "integrity": "sha512-q45vdXU9TSWaHgFkWEFM97YHEoCmOyG9csLLdv3oVC6ARjT77u4wfng9rRtSOMb5UpxzT7zTX5GBbwm15H40dw==" }, "markdown-it-chain": { "version": "1.3.0", @@ -5731,6 +6205,17 @@ "integrity": "sha512-XClV8I1TKy8L2qsT9iX3qiV+50ZtcInGXI80CA+DP62sMs7hXlyV/RM3hfwy5O3Ad0sJm9xIwQELgANfESo8mQ==", "requires": { "webpack-chain": "^4.9.0" + }, + "dependencies": { + "webpack-chain": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/webpack-chain/-/webpack-chain-4.12.1.tgz", + "integrity": "sha512-BCfKo2YkDe2ByqkEWe1Rw+zko4LsyS75LVr29C6xIrxAg9JHJ4pl8kaIZ396SUSNp6b4815dRZPSTAS8LlURRQ==", + "requires": { + "deepmerge": "^1.5.2", + "javascript-stringify": "^1.6.0" + } + } } }, "markdown-it-container": { @@ -5915,6 +6400,11 @@ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" + }, "min-document": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", @@ -5953,9 +6443,9 @@ } }, "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.4.tgz", + "integrity": "sha512-wTiNDqe4D2rbTJGZk1qcdZgFtY0/r+iuE6GDT7V0/+Gu5MLpIDm4+CssDECR79OJs/OxLPXMzdxy153b5Qy3hg==" }, "mississippi": { "version": "3.0.0", @@ -6178,9 +6668,9 @@ } }, "node-releases": { - "version": "1.1.47", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.47.tgz", - "integrity": "sha512-k4xjVPx5FpwBUj0Gw7uvFOTF4Ep8Hok1I6qjwL3pLfwe7Y0REQSAqOwwv9TWBCUtMHxcXfY4PgRLRozcChvTcA==", + "version": "1.1.51", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.51.tgz", + "integrity": "sha512-1eQEs6HFYY1kMXQPOLzCf7HdjReErmvn85tZESMczdCNVWP3Y7URYLBAyYynuI7yef1zj4HN5q+oB2x67QU0lw==", "requires": { "semver": "^6.3.0" } @@ -6415,6 +6905,11 @@ "mem": "^4.0.0" } }, + "p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==" + }, "p-defer": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", @@ -6431,19 +6926,19 @@ "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==" }, "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", + "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", "requires": { - "p-try": "^1.0.0" + "p-try": "^2.0.0" } }, "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "requires": { - "p-limit": "^1.1.0" + "p-limit": "^2.0.0" } }, "p-map": { @@ -6460,9 +6955,20 @@ } }, "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + }, + "package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "requires": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + } }, "pako": { "version": "1.0.11", @@ -6652,54 +7158,6 @@ "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", "requires": { "find-up": "^3.0.0" - }, - "dependencies": { - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "requires": { - "locate-path": "^3.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", - "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" - } - } - }, - "pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", - "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", - "requires": { - "find-up": "^2.1.0" } }, "portfinder": { @@ -6733,9 +7191,9 @@ "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" }, "postcss": { - "version": "7.0.26", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.26.tgz", - "integrity": "sha512-IY4oRjpXWYshuTDFxMVkJDtWIk2LhsTlu8bZnbEJA4+bYT16Lvpo8Qv6EvDumhYRgzjZl489pmsY3qVgJQ08nA==", + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", + "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -6753,36 +7211,13 @@ } }, "postcss-calc": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-7.0.1.tgz", - "integrity": "sha512-oXqx0m6tb4N3JGdmeMSc/i91KppbYsFZKdH0xMOqK8V1rJlzrKlTdokz8ozUXLVejydRN6u2IddxpcijRj2FqQ==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-7.0.2.tgz", + "integrity": "sha512-rofZFHUg6ZIrvRwPeFktv06GdbDYLcGqh9EwiMutZg+a0oePCCw1zHOEiji6LCpyRcjTREtPASuUqeAvYlEVvQ==", "requires": { - "css-unit-converter": "^1.1.1", - "postcss": "^7.0.5", - "postcss-selector-parser": "^5.0.0-rc.4", - "postcss-value-parser": "^3.3.1" - }, - "dependencies": { - "cssesc": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", - "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==" - }, - "postcss-selector-parser": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", - "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", - "requires": { - "cssesc": "^2.0.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - }, - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" - } + "postcss": "^7.0.27", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.0.2" } }, "postcss-colormin": { @@ -6904,11 +7339,11 @@ }, "dependencies": { "postcss-selector-parser": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz", - "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", + "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", "requires": { - "dot-prop": "^4.1.1", + "dot-prop": "^5.2.0", "indexes-of": "^1.0.1", "uniq": "^1.0.1" } @@ -6981,11 +7416,11 @@ }, "dependencies": { "postcss-selector-parser": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz", - "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", + "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", "requires": { - "dot-prop": "^4.1.1", + "dot-prop": "^5.2.0", "indexes-of": "^1.0.1", "uniq": "^1.0.1" } @@ -7233,11 +7668,11 @@ } }, "postcss-safe-parser": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-4.0.1.tgz", - "integrity": "sha512-xZsFA3uX8MO3yAda03QrG3/Eg1LN3EPfjjf07vke/46HERLZyHrTsQ9E1r1w1W//fWEhtYNndo2hQplN2cVpCQ==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-4.0.2.tgz", + "integrity": "sha512-Uw6ekxSWNLCPesSv/cmqf2bY/77z11O7jZGPax3ycZMFU/oi2DMH9i89AdHc1tRwFg/arFoEwX0IS3LCUxJh1g==", "requires": { - "postcss": "^7.0.0" + "postcss": "^7.0.26" } }, "postcss-selector-parser": { @@ -7279,9 +7714,9 @@ } }, "postcss-value-parser": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.0.2.tgz", - "integrity": "sha512-LmeoohTpp/K4UiyQCwuGWlONxXamGzCMtFxLq4W1nZVGIQLYvMCJx3yAF9qyyuFpflABI9yVdtJAqbihOsCsJQ==" + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.0.3.tgz", + "integrity": "sha512-N7h4pG+Nnu5BEIzyeaaIYWs0LI5XC40OrRh5L60z0QjFsqGWcHcbkBvpe1WYpcIS9yQ8sOi/vIPt1ejQCrMVrg==" }, "prepend-http": { "version": "2.0.0", @@ -7344,12 +7779,12 @@ "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=" }, "proxy-addr": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz", - "integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", + "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", "requires": { "forwarded": "~0.1.2", - "ipaddr.js": "1.9.0" + "ipaddr.js": "1.9.1" } }, "prr": { @@ -7537,6 +7972,14 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, + "pupa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.0.1.tgz", + "integrity": "sha512-hEJH0s8PXLY/cdXh66tNEQGndDrIKNqNC5xmrysZy3i5C3oEoLna7YAOad+7u125+zH1HNXUmGEkrhb3c2VriA==", + "requires": { + "escape-goat": "^2.0.0" + } + }, "q": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", @@ -7612,10 +8055,21 @@ } } }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + } + }, "readable-stream": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.5.0.tgz", - "integrity": "sha512-gSz026xs2LfxBPudDuI41V1lka8cxg64E66SGe78zJlsUofOg/yqwezdIcdfwik6B4h8LFmWPA9ef9X3FiNFLA==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -7675,9 +8129,9 @@ "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==" }, "regenerate-unicode-properties": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz", - "integrity": "sha512-LGZzkgtLY79GeXLm8Dp0BVLdQlWICzBnJz/ipWUgo59qBaZ+BHtq51P2q1uVZlppMuUAT37SDk39qUbjTWB7bA==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz", + "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==", "requires": { "regenerate": "^1.4.0" } @@ -7688,11 +8142,12 @@ "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" }, "regenerator-transform": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.1.tgz", - "integrity": "sha512-flVuee02C3FKRISbxhXl9mGzdbWUVHubl1SMaknjxkFB1/iqpJhArQUvRxOOPEc/9tAiX0BaQ28FJH10E4isSQ==", + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.2.tgz", + "integrity": "sha512-V4+lGplCM/ikqi5/mkkpJ06e9Bujq1NFmNLvsCs56zg3ZbzrnUzAtizZ24TXxtRX/W2jcdScwQCnbL0CICTFkQ==", "requires": { - "private": "^0.1.6" + "@babel/runtime": "^7.8.4", + "private": "^0.1.8" } }, "regex-not": { @@ -7733,16 +8188,32 @@ } }, "regexpu-core": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.6.0.tgz", - "integrity": "sha512-YlVaefl8P5BnFYOITTNzDvan1ulLOiXJzCNZxduTIosN17b87h3bvG9yHMoHaRuo88H4mQ06Aodj5VtYGGGiTg==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.0.tgz", + "integrity": "sha512-TQ4KXRnIn6tz6tjnrXEkD/sshygKH/j5KzK86X8MkeHyZ8qst/LZ89j3X4/8HEIfHANTFIP/AbXakeRhWIl5YQ==", "requires": { "regenerate": "^1.4.0", - "regenerate-unicode-properties": "^8.1.0", - "regjsgen": "^0.5.0", - "regjsparser": "^0.6.0", + "regenerate-unicode-properties": "^8.2.0", + "regjsgen": "^0.5.1", + "regjsparser": "^0.6.4", "unicode-match-property-ecmascript": "^1.0.4", - "unicode-match-property-value-ecmascript": "^1.1.0" + "unicode-match-property-value-ecmascript": "^1.2.0" + } + }, + "registry-auth-token": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.1.1.tgz", + "integrity": "sha512-9bKS7nTl9+/A1s7tnPeGrUpRcVY+LUh7bfFgzpndALdPfXQBfQV77rQVtqgUV3ti4vc/Ik81Ex8UJDWDQ12zQA==", + "requires": { + "rc": "^1.2.8" + } + }, + "registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "requires": { + "rc": "^1.2.8" } }, "regjsgen": { @@ -7751,9 +8222,9 @@ "integrity": "sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg==" }, "regjsparser": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.2.tgz", - "integrity": "sha512-E9ghzUtoLwDekPT0DYCp+c4h+bvuUpe6rRHCTYn6eGoqj1LgKXxT6I0Il4WbjhQkOghzi/V+y03bPKvbllL93Q==", + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.4.tgz", + "integrity": "sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw==", "requires": { "jsesc": "~0.5.0" }, @@ -7798,9 +8269,9 @@ "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" }, "request": { - "version": "2.88.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", - "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", "requires": { "aws-sign2": "~0.7.0", "aws4": "^1.8.0", @@ -7809,7 +8280,7 @@ "extend": "~3.0.2", "forever-agent": "~0.6.1", "form-data": "~2.3.2", - "har-validator": "~5.1.0", + "har-validator": "~5.1.3", "http-signature": "~1.2.0", "is-typedarray": "~1.0.0", "isstream": "~0.1.2", @@ -7819,7 +8290,7 @@ "performance-now": "^2.1.0", "qs": "~6.5.2", "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", + "tough-cookie": "~2.5.0", "tunnel-agent": "^0.6.0", "uuid": "^3.3.2" }, @@ -7846,15 +8317,10 @@ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" }, - "reselect": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/reselect/-/reselect-3.0.1.tgz", - "integrity": "sha1-79qpjqdFEyTQkrKyFjpqHXqaIUc=" - }, "resolve": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.0.tgz", - "integrity": "sha512-+hTmAldEGE80U2wJJDC1lebb5jWqvTYAfm3YZ1ckk1gBr0MnCqUKlwK1e+anaFljIl+F5tR5IoZcm4ZDA1zMQw==", + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz", + "integrity": "sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==", "requires": { "path-parse": "^1.0.6" } @@ -7877,6 +8343,14 @@ "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "requires": { + "lowercase-keys": "^1.0.0" + } + }, "ret": { "version": "0.1.15", "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", @@ -7996,6 +8470,14 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" }, + "semver-diff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "requires": { + "semver": "^6.3.0" + } + }, "send": { "version": "0.17.1", "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", @@ -8703,6 +9185,11 @@ "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + }, "stylehacks": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz", @@ -8714,11 +9201,11 @@ }, "dependencies": { "postcss-selector-parser": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz", - "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", + "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", "requires": { - "dot-prop": "^4.1.1", + "dot-prop": "^5.2.0", "indexes-of": "^1.0.1", "uniq": "^1.0.1" } @@ -8822,10 +9309,15 @@ "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==" }, + "term-size": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.0.tgz", + "integrity": "sha512-a6sumDlzyHVJWb8+YofY4TW112G6p2FCPEAFk+59gIYHv3XHRhm9ltVQ9kli4hNWeQBwSpe8cRN25x0ROunMOw==" + }, "terser": { - "version": "4.6.3", - "resolved": "https://registry.npmjs.org/terser/-/terser-4.6.3.tgz", - "integrity": "sha512-Lw+ieAXmY69d09IIc/yqeBqXpEQIpDGZqT34ui1QWXIUpR2RjbqEkT8X7Lgex19hslSqcWM5iMN2kM11eMsESQ==", + "version": "4.6.6", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.6.6.tgz", + "integrity": "sha512-4lYPyeNmstjIIESr/ysHg2vUPRGf2tzF9z2yYwnowXVuVzLEamPN1Gfrz7f8I9uEPuHcbFlW4PLIAsJoxXyJ1g==", "requires": { "commander": "^2.20.0", "source-map": "~0.6.1", @@ -8965,6 +9457,11 @@ } } }, + "to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==" + }, "to-regex": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", @@ -9025,19 +9522,12 @@ "integrity": "sha1-LmhELZ9k7HILjMieZEOsbKqVACk=" }, "tough-cookie": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", - "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", "requires": { - "psl": "^1.1.24", - "punycode": "^1.4.1" - }, - "dependencies": { - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" - } + "psl": "^1.1.28", + "punycode": "^2.1.1" } }, "tr46": { @@ -9049,9 +9539,9 @@ } }, "tslib": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", - "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz", + "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==" }, "tty-browserify": { "version": "0.0.0", @@ -9072,9 +9562,9 @@ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" }, "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==" + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", + "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==" }, "type-is": { "version": "1.6.18", @@ -9090,6 +9580,14 @@ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "requires": { + "is-typedarray": "^1.0.0" + } + }, "uc.micro": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", @@ -9133,14 +9631,14 @@ } }, "unicode-match-property-value-ecmascript": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.1.0.tgz", - "integrity": "sha512-hDTHvaBk3RmFzvSl0UVrUmC3PuW9wKVnpoUDYH0JDkSIovzw+J5viQmeYHxVSBptubnr7PbH2e0fnpDRQnQl5g==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz", + "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==" }, "unicode-property-aliases-ecmascript": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz", - "integrity": "sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw==" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz", + "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==" }, "union-value": { "version": "1.0.1", @@ -9179,6 +9677,14 @@ "imurmurhash": "^0.1.4" } }, + "unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "requires": { + "crypto-random-string": "^2.0.0" + } + }, "universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", @@ -9235,6 +9741,72 @@ "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==" }, + "update-notifier": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.0.tgz", + "integrity": "sha512-w3doE1qtI0/ZmgeoDoARmI5fjDoT93IfKgEGqm26dGUOh8oNpaSTsGNdYRN/SjOuo10jcJGwkEL3mroKzktkew==", + "requires": { + "boxen": "^4.2.0", + "chalk": "^3.0.0", + "configstore": "^5.0.1", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.3.1", + "is-npm": "^4.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.0.0", + "pupa": "^2.0.1", + "semver-diff": "^3.1.1", + "xdg-basedir": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "upper-case": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", @@ -9288,6 +9860,14 @@ "requires-port": "^1.0.0" } }, + "url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "requires": { + "prepend-http": "^2.0.0" + } + }, "use": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", @@ -9385,9 +9965,9 @@ "integrity": "sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==" }, "vue-loader": { - "version": "15.8.3", - "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.8.3.tgz", - "integrity": "sha512-yFksTFbhp+lxlm92DrKdpVIWMpranXnTEuGSc0oW+Gk43M9LWaAmBTnfj5+FCdve715mTHvo78IdaXf5TbiTJg==", + "version": "15.9.0", + "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.9.0.tgz", + "integrity": "sha512-FeDHvTSpwyLeF7LIV1PYkvqUQgTJ8UmOxhSlCyRSxaXCKk+M6NF4tDQsLsPPNeDPyR7TfRQ8MLg6v+8PsDV9xQ==", "requires": { "@vue/component-compiler-utils": "^3.1.0", "hash-sum": "^1.0.2", @@ -9397,9 +9977,9 @@ } }, "vue-router": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.1.5.tgz", - "integrity": "sha512-BszkPvhl7I9h334GjckCh7sVFyjTPMMJFJ4Bsrem/Ik+B/9gt5tgrk8k4gGLO4ZpdvciVdg7O41gW4DisQWurg==" + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.1.6.tgz", + "integrity": "sha512-GYhn2ynaZlysZMkFE5oCHRUTqE8BWs/a9YbKpNLi0i7xD6KG1EzDqpHQmv1F5gXjr8kL5iIVS8EOtRaVUEXTqA==" }, "vue-server-renderer": { "version": "2.6.11", @@ -9469,15 +10049,16 @@ "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==" }, "vuepress": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/vuepress/-/vuepress-1.2.0.tgz", - "integrity": "sha512-EfHo8Cc73qo+1Pm18hM0qOGynmDr8q5fu2664obynsdCJ1zpvoShVnA0Msraw4SI2xDc0iAoIb3dTwxUIM8DAw==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/vuepress/-/vuepress-1.3.1.tgz", + "integrity": "sha512-i0f0JB0zdmdVH8P8cO4w7PljPQpf8ObiVk/1pOidvMQCMEhFmIpYz+730Wlf0rtB/GG4QUsqQ27Ckp5Rfob+hQ==", "requires": { - "@vuepress/core": "^1.2.0", - "@vuepress/theme-default": "^1.2.0", - "cac": "^6.3.9", + "@vuepress/core": "^1.3.1", + "@vuepress/theme-default": "^1.3.1", + "cac": "^6.5.6", "envinfo": "^7.2.0", - "opencollective-postinstall": "^2.0.2" + "opencollective-postinstall": "^2.0.2", + "update-notifier": "^4.0.0" } }, "vuepress-html-webpack-plugin": { @@ -9499,6 +10080,11 @@ "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==" }, + "emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=" + }, "json5": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", @@ -9543,19 +10129,19 @@ } }, "vuepress-plugin-smooth-scroll": { - "version": "0.0.9", - "resolved": "https://registry.npmjs.org/vuepress-plugin-smooth-scroll/-/vuepress-plugin-smooth-scroll-0.0.9.tgz", - "integrity": "sha512-UXX+HLZO1NKVwyiOJlj0smh8F9dKnwybjEi7w/Mj9EYLhKrNYr5uXs+N+OTt8VwKCn3f0vZ1XAwFIjsPlD7GJA==", + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/vuepress-plugin-smooth-scroll/-/vuepress-plugin-smooth-scroll-0.0.3.tgz", + "integrity": "sha512-qsQkDftLVFLe8BiviIHaLV0Ea38YLZKKonDGsNQy1IE0wllFpFIEldWD8frWZtDFdx6b/O3KDMgVQ0qp5NjJCg==", "requires": { - "smoothscroll-polyfill": "^0.4.4" + "smoothscroll-polyfill": "^0.4.3" } }, "vuepress-theme-cosmos": { - "version": "1.0.146", - "resolved": "https://registry.npmjs.org/vuepress-theme-cosmos/-/vuepress-theme-cosmos-1.0.146.tgz", - "integrity": "sha512-guJcjAffvQcTBbuJarYIvt/O4IpmGKj/jHVlfooDK/NTZd/9/X1cYRSzYZbu+M+GgzV6QEjlikPAGnZI2o/MnQ==", + "version": "1.0.156", + "resolved": "https://registry.npmjs.org/vuepress-theme-cosmos/-/vuepress-theme-cosmos-1.0.156.tgz", + "integrity": "sha512-g5KqkeRu8Dg+eYUwWYy4TfdMKp9yYy+BQpD+gegwqIPbHSBIvFV+0w3olk5/mFaCzXKfEmTXtLltok9arrayLg==", "requires": { - "@cosmos-ui/vue": "^0.5.20", + "@cosmos-ui/vue": "^0.10.0", "axios": "^0.19.0", "cheerio": "^1.0.0-rc.3", "clipboard-copy": "^3.1.0", @@ -9599,9 +10185,9 @@ "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" }, "webpack": { - "version": "4.41.5", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.41.5.tgz", - "integrity": "sha512-wp0Co4vpyumnp3KlkmpM5LWuzvZYayDwM2n17EHFr4qxBBbRokC7DJawPJC7TfSFZ9HZ6GsdH40EBj4UV0nmpw==", + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.42.0.tgz", + "integrity": "sha512-EzJRHvwQyBiYrYqhyjW9AqM90dE4+s1/XtCfn7uWg6cS72zH+2VPFAlsnW0+W0cDi0XRjNKUMoJtpSi50+Ph6w==", "requires": { "@webassemblyjs/ast": "1.8.5", "@webassemblyjs/helper-module-context": "1.8.5", @@ -9629,19 +10215,26 @@ }, "dependencies": { "acorn": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.0.tgz", - "integrity": "sha512-gac8OEcQ2Li1dxIEWGZzsp2BitJxwkwcOm0zHAJLcPJaVvm58FRnk6RkuLRpU1EujipU2ZFODv2P9DLMfnV8mw==" + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz", + "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==" } } }, "webpack-chain": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/webpack-chain/-/webpack-chain-4.12.1.tgz", - "integrity": "sha512-BCfKo2YkDe2ByqkEWe1Rw+zko4LsyS75LVr29C6xIrxAg9JHJ4pl8kaIZ396SUSNp6b4815dRZPSTAS8LlURRQ==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/webpack-chain/-/webpack-chain-6.4.0.tgz", + "integrity": "sha512-f97PYqxU+9/u0IUqp/ekAHRhBD1IQwhBv3wlJo2nvyELpr2vNnUqO3XQEk+qneg0uWGP54iciotszpjfnEExFA==", "requires": { "deepmerge": "^1.5.2", - "javascript-stringify": "^1.6.0" + "javascript-stringify": "^2.0.1" + }, + "dependencies": { + "javascript-stringify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/javascript-stringify/-/javascript-stringify-2.0.1.tgz", + "integrity": "sha512-yV+gqbd5vaOYjqlbk16EG89xB5udgjqQF3C5FAORDg4f/IS1Yc5ERCv5e/57yBcfJYw05V5JyIXabhwb75Xxow==" + } } }, "webpack-dev-middleware": { @@ -9657,9 +10250,9 @@ } }, "webpack-dev-server": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.10.1.tgz", - "integrity": "sha512-AGG4+XrrXn4rbZUueyNrQgO4KGnol+0wm3MPdqGLmmA+NofZl3blZQKxZ9BND6RDNuvAK9OMYClhjOSnxpWRoA==", + "version": "3.10.3", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.10.3.tgz", + "integrity": "sha512-e4nWev8YzEVNdOMcNzNeCN947sWJNd43E5XvsJzbAL08kGc2frm1tQ32hTJslRS+H65LCb/AaUCYU7fjHCpDeQ==", "requires": { "ansi-html": "0.0.7", "bonjour": "^3.5.0", @@ -9729,54 +10322,16 @@ "ms": "^2.1.1" } }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "requires": { - "locate-path": "^3.0.0" - } - }, "is-absolute-url": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.3.tgz", "integrity": "sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==" }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, - "p-limit": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", - "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" - }, "supports-color": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", @@ -9925,6 +10480,49 @@ "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" }, + "widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "requires": { + "string-width": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, "window-size": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", @@ -9986,6 +10584,17 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, "ws": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", @@ -9994,6 +10603,11 @@ "async-limiter": "~1.0.0" } }, + "xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==" + }, "xmlbuilder": { "version": "13.0.2", "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-13.0.2.tgz", diff --git a/docs/package.json b/docs/package.json index 4189d8bd368c..ceeeba7e86e3 100644 --- a/docs/package.json +++ b/docs/package.json @@ -14,9 +14,7 @@ "author": "", "license": "ISC", "dependencies": { - "@vuepress/plugin-google-analytics": "^1.2.0", - "tiny-cookie": "^2.3.1", - "vuepress-plugin-smooth-scroll": "0.0.9", - "vuepress-theme-cosmos": "^1.0.113" + "@vuepress/plugin-google-analytics": "^1.3.1", + "vuepress-theme-cosmos": "^1.0.156" } } diff --git a/x/staking/spec/05_end_block.md b/x/staking/spec/05_end_block.md index 16444134f424..3207c078cd30 100644 --- a/x/staking/spec/05_end_block.md +++ b/x/staking/spec/05_end_block.md @@ -1,5 +1,5 @@ # End-Block diff --git a/x/staking/spec/06_hooks.md b/x/staking/spec/06_hooks.md index c2c372b624d8..2eac2d4a1708 100644 --- a/x/staking/spec/06_hooks.md +++ b/x/staking/spec/06_hooks.md @@ -1,5 +1,5 @@ # Hooks diff --git a/x/staking/spec/07_events.md b/x/staking/spec/07_events.md index fe716baf9180..d8255ca92b13 100644 --- a/x/staking/spec/07_events.md +++ b/x/staking/spec/07_events.md @@ -1,5 +1,5 @@ # Events diff --git a/x/staking/spec/07_params.md b/x/staking/spec/07_params.md new file mode 100644 index 000000000000..6df38579dc81 --- /dev/null +++ b/x/staking/spec/07_params.md @@ -0,0 +1,14 @@ + + +# Parameters + +The staking module contains the following parameters: + +| Key | Type | Example | +|---------------|------------------|-------------------| +| UnbondingTime | string (time ns) | "259200000000000" | +| MaxValidators | uint16 | 100 | +| KeyMaxEntries | uint16 | 7 | +| BondDenom | string | "uatom" | From 2be38d0304d4c269671d6aefeeffbb7af127b234 Mon Sep 17 00:00:00 2001 From: billy rennekamp Date: Tue, 24 Mar 2020 17:30:35 +0100 Subject: [PATCH 450/529] Improve keyring docs (#5822) * Update cli.md * Update cli.md * Update docs/interfaces/cli.md Co-Authored-By: Alessio Treglia * Update docs/interfaces/cli.md Co-Authored-By: Alessio Treglia * replace cli modifications with keyring md * update pasword to keypasswd Co-authored-by: Alessio Treglia Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> --- docs/interfaces/cli.md | 4 +--- docs/interfaces/keyring.md | 7 ++++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/docs/interfaces/cli.md b/docs/interfaces/cli.md index b06acdba3b00..d447abe82f17 100644 --- a/docs/interfaces/cli.md +++ b/docs/interfaces/cli.md @@ -62,8 +62,7 @@ The root command (called `rootCmd`) is what the user first types into the comman * **Status** command from the SDK rpc client tools, which prints information about the status of the connected [`Node`](../core/node.md). The Status of a node includes `NodeInfo`,`SyncInfo` and `ValidatorInfo`. * **Config** [command](https://github.com/cosmos/cosmos-sdk/blob/master/client/config.go) from the SDK client tools, which allows the user to edit a `config.toml` file that sets values for [flags](#flags) such as `--chain-id` and which `--node` they wish to connect to. The `config` command can be invoked by typing `appcli config` with optional arguments ` [value]` and a `--get` flag to query configurations or `--home` flag to create a new configuration. -* **Keys** [commands](https://github.com/cosmos/cosmos-sdk/blob/master/client/keys) from the SDK client tools, which includes a collection of subcommands for using the key functions in the SDK crypto tools, including adding a new key and saving it to disk, listing all public keys stored in the key manager, and deleting a key. -For example, users can type `appcli keys add ` to add a new key and save an encrypted copy to disk, using the flag `--recover` to recover a private key from a seed phrase or the flag `--multisig` to group multiple keys together to create a multisig key. For full details on the `add` key command, see the code [here](https://github.com/cosmos/cosmos-sdk/blob/master/client/keys/add.go). +* **Keys** [commands](https://github.com/cosmos/cosmos-sdk/blob/master/client/keys) from the SDK client tools, which includes a collection of subcommands for using the key functions in the SDK crypto tools, including adding a new key and saving it to disk, listing all public keys stored in the key manager, and deleting a key. For example, users can type `appcli keys add ` to add a new key and save an encrypted copy to disk, using the flag `--recover` to recover a private key from a seed phrase or the flag `--multisig` to group multiple keys together to create a multisig key. For full details on the `add` key command, see the code [here](https://github.com/cosmos/cosmos-sdk/blob/master/client/keys/add.go). For more details about usage of `--keyring-backend` for storage of key credentials look at the [keyring docs](/keyring.md). * [**Transaction**](#transaction-commands) commands. * [**Query**](#query-commands) commands. @@ -135,4 +134,3 @@ Here is an example of an `initConfig()` function from the [nameservice tutorial And an example of how to add `initConfig` as a `PersistentPreRunE` to the root command: +++ https://github.com/cosmos/sdk-tutorials/blob/86a27321cf89cc637581762e953d0c07f8c78ece/nameservice/cmd/nscli/main.go#L42-L44 - diff --git a/docs/interfaces/keyring.md b/docs/interfaces/keyring.md index 588a3a0c9ded..a4076cd62f07 100644 --- a/docs/interfaces/keyring.md +++ b/docs/interfaces/keyring.md @@ -44,9 +44,10 @@ to execute commands using the `file` option you may want to utilize the followin for multiple prompts: ```sh -$ gaiacli config keyring-backend file # use file backend -$ (echo '1234567890'; echo '1234567890') | gaiacli keys add me # add the key 'me' -$ (echo '1234567890'; echo '1234567890'; echo '1234567890') | gaiad collect-gentxs # multiple prompts +# assuming that KEYPASSWD is set in the environment +$ gaiacli config keyring-backend file # use file backend +$ (echo $KEYPASSWD; echo $KEYPASSWD) | gaiacli keys add me # multiple prompts +$ echo $KEYPASSWD | gaiacli keys show me # single prompt ``` ::: tip From b0f784d8f92bb3e8999f13d0f8ad4b8bfe76e401 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Tue, 24 Mar 2020 15:55:52 -0400 Subject: [PATCH 451/529] Implement factory and remove tx generator from CLIContext --- client/context/context.go | 11 +-- client/tx/factory.go | 166 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 167 insertions(+), 10 deletions(-) create mode 100644 client/tx/factory.go diff --git a/client/context/context.go b/client/context/context.go index 80813b7655cd..b552bb149a42 100644 --- a/client/context/context.go +++ b/client/context/context.go @@ -7,14 +7,12 @@ import ( "github.com/pkg/errors" "github.com/spf13/viper" - yaml "gopkg.in/yaml.v2" - "github.com/tendermint/tendermint/libs/cli" tmlite "github.com/tendermint/tendermint/lite" rpcclient "github.com/tendermint/tendermint/rpc/client" + yaml "gopkg.in/yaml.v2" "github.com/cosmos/cosmos-sdk/client/flags" - clientx "github.com/cosmos/cosmos-sdk/client/tx" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/crypto/keys" sdk "github.com/cosmos/cosmos-sdk/types" @@ -26,7 +24,6 @@ type CLIContext struct { FromAddress sdk.AccAddress Client rpcclient.Client ChainID string - TxGenerator clientx.Generator Marshaler codec.Marshaler Keybase keys.Keybase Input io.Reader @@ -138,12 +135,6 @@ func (ctx CLIContext) WithInput(r io.Reader) CLIContext { return ctx } -// WithTxGenerator returns a copy of the CLIContext with an updated TxGenerator. -func (ctx CLIContext) WithTxGenerator(txg clientx.Generator) CLIContext { - ctx.TxGenerator = txg - return ctx -} - // WithMarshaler returns a copy of the CLIContext with an updated Marshaler. func (ctx CLIContext) WithMarshaler(m codec.Marshaler) CLIContext { ctx.Marshaler = m diff --git a/client/tx/factory.go b/client/tx/factory.go new file mode 100644 index 000000000000..be1b27e85341 --- /dev/null +++ b/client/tx/factory.go @@ -0,0 +1,166 @@ +package tx + +import ( + "io" + "strings" + + "githuf.com/spf13/viper" + "githuf.com/tendermint/tendermint/crypto" + + "githuf.com/cosmos/cosmos-sdk/client/flags" + "githuf.com/cosmos/cosmos-sdk/crypto/keys" + sdk "githuf.com/cosmos/cosmos-sdk/types" +) + +// AccountRetriever defines the interfaces required for use by the Factory to +// ensure an account exists and to be able to query for account fields necessary +// for signing. +type AccountRetriever interface { + EnsureExists(addr sdk.AccAddress) error + GetAccountNumberSequence(addr sdk.AccAddress) (uint64, uint64, error) +} + +// Factory defines a client transaction factory that facilitates generating and +// signing an application-specific transaction. +type Factory struct { + keybase keys.Keybase + txGenerator Generator + accountRetriever AccountRetriever + feeFn func(gas uint64, amount sdk.Coins) sdk.Fee + sigFn func(pk crypto.PubKey, sig []byte) sdk.Signature + accountNumber uint64 + sequence uint64 + gas uint64 + gasAdjustment float64 + simulateAndExecute bool + chainID string + memo string + fees sdk.Coins + gasPrices sdk.DecCoins +} + +func NewFactoryFromCLI(input io.Reader) Factory { + kb, err := keys.NewKeyring( + sdk.KeyringServiceName(), + viper.GetString(flags.FlagKeyringBackend), + viper.GetString(flags.FlagHome), + input, + ) + if err != nil { + panic(err) + } + + f := Factory{ + keybase: kb, + accountNumber: viper.GetUint64(flags.FlagAccountNumber), + sequence: viper.GetUint64(flags.FlagSequence), + gas: flags.GasFlagVar.Gas, + gasAdjustment: viper.GetFloat64(flags.FlagGasAdjustment), + simulateAndExecute: flags.GasFlagVar.Simulate, + chainID: viper.GetString(flags.FlagChainID), + memo: viper.GetString(flags.FlagMemo), + } + + f = f.WithFees(viper.GetString(flags.FlagFees)) + f = f.WithGasPrices(viper.GetString(flags.FlagGasPrices)) + + return f +} + +// nolint +func (f Factory) AccountNumber() uint64 { return f.accountNumber } +func (f Factory) Sequence() uint64 { return f.sequence } +func (f Factory) Gas() uint64 { return f.gas } +func (f Factory) GasAdjustment() float64 { return f.gasAdjustment } +func (f Factory) Keybase() keys.Keybase { return f.keybase } +func (f Factory) ChainID() string { return f.chainID } +func (f Factory) Memo() string { return f.memo } +func (f Factory) Fees() sdk.Coins { return f.fees } +func (f Factory) GasPrices() sdk.DecCoins { return f.gasPrices } +func (f Factory) AccountRetriever() AccountRetriever { return f.accountRetriever } + +// SimulateAndExecute returns the option to simulate and then execute the transaction +// using the gas from the simulation results +func (f Factory) SimulateAndExecute() bool { return f.simulateAndExecute } + +// WithTxGenerator returns a copy of the Builder with an updated Generator. +func (f Factory) WithTxGenerator(g Generator) Factory { + f.txGenerator = g + return f +} + +// WithAccountRetriever returns a copy of the Builder with an updated AccountRetriever. +func (f Factory) WithAccountRetriever(ar AccountRetriever) Factory { + f.accountRetriever = ar + return f +} + +// WithChainID returns a copy of the Builder with an updated chainID. +func (f Factory) WithChainID(chainID string) Factory { + f.chainID = chainID + return f +} + +// WithGas returns a copy of the Builder with an updated gas value. +func (f Factory) WithGas(gas uint64) Factory { + f.gas = gas + return f +} + +// WithSigFn returns a copy of the Builder with an updated tx signature constructor. +func (f Factory) WithSigFn(sigFn func(pk crypto.PubKey, sig []byte) sdk.Signature) Factory { + f.sigFn = sigFn + return f +} + +// WithFeeFn returns a copy of the Builder with an updated fee constructor. +func (f Factory) WithFeeFn(feeFn func(gas uint64, amount sdk.Coins) sdk.Fee) Factory { + f.feeFn = feeFn + return f +} + +// WithFees returns a copy of the Builder with an updated fee. +func (f Factory) WithFees(fees string) Factory { + parsedFees, err := sdk.ParseCoins(fees) + if err != nil { + panic(err) + } + + f.fees = parsedFees + return f +} + +// WithGasPrices returns a copy of the Builder with updated gas prices. +func (f Factory) WithGasPrices(gasPrices string) Factory { + parsedGasPrices, err := sdk.ParseDecCoins(gasPrices) + if err != nil { + panic(err) + } + + f.gasPrices = parsedGasPrices + return f +} + +// WithKeybase returns a copy of the Builder with updated Keybase. +func (f Factory) WithKeybase(keybase keys.Keybase) Factory { + f.keybase = keybase + return f +} + +// WithSequence returns a copy of the Builder with an updated sequence number. +func (f Factory) WithSequence(sequence uint64) Factory { + f.sequence = sequence + return f +} + +// WithMemo returns a copy of the Builder with an updated memo. +func (f Factory) WithMemo(memo string) Factory { + f.memo = strings.TrimSpace(memo) + return f +} + +// WithAccountNumber returns a copy of the Builder with an updated account number. +func (f Factory) WithAccountNumber(accnum uint64) Factory { + f.accountNumber = accnum + return f +} From d4d4da4a6ee762a22c0edef94b4c26d8980c3b88 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Tue, 24 Mar 2020 16:36:12 -0400 Subject: [PATCH 452/529] Implement client and factory --- client/context/context.go | 1 + client/tx/factory.go | 6 +- client/tx/tx.go | 268 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 272 insertions(+), 3 deletions(-) diff --git a/client/context/context.go b/client/context/context.go index b552bb149a42..2970dab6ed3e 100644 --- a/client/context/context.go +++ b/client/context/context.go @@ -254,6 +254,7 @@ func (ctx CLIContext) PrintOutput(toPrint interface{}) error { out, err = yaml.Marshal(&toPrint) case "json": + // TODO: Use ctx.Marshaler. if ctx.Indent { out, err = ctx.Codec.MarshalJSONIndent(toPrint, "", " ") } else { diff --git a/client/tx/factory.go b/client/tx/factory.go index be1b27e85341..a4d3897692ab 100644 --- a/client/tx/factory.go +++ b/client/tx/factory.go @@ -4,12 +4,12 @@ import ( "io" "strings" - "githuf.com/spf13/viper" - "githuf.com/tendermint/tendermint/crypto" - "githuf.com/cosmos/cosmos-sdk/client/flags" "githuf.com/cosmos/cosmos-sdk/crypto/keys" sdk "githuf.com/cosmos/cosmos-sdk/types" + + "githuf.com/spf13/viper" + "githuf.com/tendermint/tendermint/crypto" ) // AccountRetriever defines the interfaces required for use by the Factory to diff --git a/client/tx/tx.go b/client/tx/tx.go index be25ec7541c7..49dfb1cddf90 100644 --- a/client/tx/tx.go +++ b/client/tx/tx.go @@ -1,7 +1,19 @@ package tx import ( + "bufio" + "errors" + "fmt" + "os" + + "githuf.com/cosmos/cosmos-sdk/client/flags" + "githuf.com/spf13/viper" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/input" + clientkeys "github.com/cosmos/cosmos-sdk/client/keys" "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/crypto/keys" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -36,3 +48,259 @@ type ( CanonicalSignBytes(cid string, num, seq uint64) ([]byte, error) } ) + +// GenerateOrBroadcastTx will either generate and print and unsigned transaction +// or sign it and broadcast it returning an error upon failure. +func GenerateOrBroadcastTx(ctx context.CLIContext, txf Factory, msgs ...sdk.Msg) error { + if ctx.GenerateOnly { + return GenerateTx(ctx, txf, msgs...) + } + + return BroadcastTx(ctx, txf, msgs...) +} + +// GenerateTx will generate an unsigned transaction and print it to the writer +// specified by ctx.Output. If simulation was requested, the gas will be +// simulated and also printed to the same writer before the transaction is +// printed. +func GenerateTx(ctx context.CLIContext, txf Factory, msgs ...sdk.Msg) error { + if txf.SimulateAndExecute() { + if ctx.Offline { + return errors.New("cannot estimate gas in offline mode") + } + + txBytes, err := BuildSimTx(txf, msgs...) + if err != nil { + return err + } + + _, adjusted, err := CalculateGas(ctx.QueryWithData, txBytes, txf.GasAdjustment()) + if err != nil { + return err + } + + txf = txf.WithGas(adjusted) + _, _ = fmt.Fprintf(os.Stderr, "%s\n", GasEstimateResponse{GasEstimate: txf.Gas()}) + } + + tx, err := BuildUnsignedTx(txf, msgs...) + if err != nil { + return err + } + + out, err := ctx.Marshaler.MarshalJSON(tx) + if err != nil { + return err + } + + _, _ = fmt.Fprintf(ctx.Output, "%s\n", out) + return nil +} + +// BroadcastTx attempts to generate, sign and broadcast a transaction with the +// given set of messages. It will also simulate gas requirements if necessary. +// It will return an error upon failure. +func BroadcastTx(ctx context.CLIContext, txf Factory, msgs ...sdk.Msg) error { + txf, err := PrepareFactory(ctx, txf) + if err != nil { + return err + } + + if txf.SimulateAndExecute() || ctx.Simulate { + txBytes, err := BuildSimTx(txf, msgs...) + if err != nil { + return err + } + + _, adjusted, err := CalculateGas(ctx.QueryWithData, txBytes, txf.GasAdjustment()) + if err != nil { + return err + } + + txf = txf.WithGas(adjusted) + _, _ = fmt.Fprintf(os.Stderr, "%s\n", GasEstimateResponse{GasEstimate: txf.Gas()}) + } + + if ctx.Simulate { + return nil + } + + tx, err := BuildUnsignedTx(txf, msgs...) + if err != nil { + return err + } + + if !ctx.SkipConfirm { + out, err := ctx.Marshaler.MarshalJSON(tx) + if err != nil { + return err + } + + _, _ = fmt.Fprintf(os.Stderr, "%s\n\n", out) + + buf := bufio.NewReader(os.Stdin) + ok, err := input.GetConfirmation("confirm transaction before signing and broadcasting", buf) + if err != nil || !ok { + _, _ = fmt.Fprintf(os.Stderr, "%s\n", "cancelled transaction") + return err + } + } + + txBytes, err := Sign(txf, ctx.GetFromName(), clientkeys.DefaultKeyPass, tx) + if err != nil { + return err + } + + // broadcast to a Tendermint node + res, err := ctx.BroadcastTx(txBytes) + if err != nil { + return err + } + + return ctx.PrintOutput(res) +} + +// BuildUnsignedTx builds a transaction to be signed given a set of messages. The +// transaction is initially created via the provided factory's generator. Once +// created, the fee, memo, and messages are set. +func BuildUnsignedTx(txf Factory, msgs ...sdk.Msg) (ClientTx, error) { + if txf.chainID == "" { + return nil, fmt.Errorf("chain ID required but not specified") + } + + fees := txf.fees + if !txf.gasPrices.IsZero() { + if !fees.IsZero() { + return nil, errors.New("cannot provide both fees and gas prices") + } + + glDec := sdk.NewDec(int64(txf.gas)) + + // Derive the fees based on the provided gas prices, where + // fee = ceil(gasPrice * gasLimit). + fees = make(sdk.Coins, len(txf.gasPrices)) + for i, gp := range txf.gasPrices { + fee := gp.Amount.Mul(glDec) + fees[i] = sdk.NewCoin(gp.Denom, fee.Ceil().RoundInt()) + } + } + + tx := txf.txGenerator.NewTx() + tx.SetFee(txf.feeFn(txf.gas, fees)) + tx.SetMsgs(msgs...) + tx.SetMemo(txf.memo) + tx.SetSignatures(nil) + + return tx, nil +} + +// BuildSimTx creates an unsigned tx with an empty single signature and returns +// the encoded transaction or an error if the unsigned transaction cannot be +// built. +func BuildSimTx(txf Factory, msgs ...sdk.Msg) ([]byte, error) { + tx, err := BuildUnsignedTx(txf, msgs...) + if err != nil { + return nil, err + } + + // Create an empty signature literal as the ante handler will populate with a + // sentinel pubkey. + tx.SetSignatures(txf.sigFn(nil, nil)) + + return tx.Marshal() +} + +// CalculateGas simulates the execution of a transaction and returns the +// simulation response obtained by the query and the adjusted gas amount. +func CalculateGas( + queryFunc func(string, []byte) ([]byte, int64, error), txBytes []byte, adjustment float64, +) (sdk.SimulationResponse, uint64, error) { + + rawRes, _, err := queryFunc("/app/simulate", txBytes) + if err != nil { + return sdk.SimulationResponse{}, 0, err + } + + // TODO: Use JSON or proto instead of codec.cdc + var simRes sdk.SimulationResponse + if err := codec.Cdc.UnmarshalBinaryBare(rawRes, &simRes); err != nil { + return sdk.SimulationResponse{}, 0, err + } + + return simRes, uint64(adjustment * float64(simRes.GasUsed)), nil +} + +// PrepareFactory ensures the account defined by ctx.GetFromAddress() exists and +// if the account number and/or the account sequence number are zero (not set), +// they will be queried for and set on the provided Factory. A new Factory with +// the updated fields will be returned. +func PrepareFactory(ctx context.CLIContext, txf Factory) (Factory, error) { + from := ctx.GetFromAddress() + + if err := txf.accountRetriever.EnsureExists(from); err != nil { + return txf, err + } + + initNum, initSeq := txf.accountNumber, txf.sequence + if initNum == 0 || initSeq == 0 { + num, seq, err := txf.accountRetriever.GetAccountNumberSequence(from) + if err != nil { + return txf, err + } + + if initNum == 0 { + txf = txf.WithAccountNumber(num) + } + if initSeq == 0 { + txf = txf.WithSequence(seq) + } + } + + return txf, nil +} + +// Sign signs a given tx with the provided name and passphrase. If the Factory's +// Keybase is not set, a new one will be created based on the client's backend. +// The bytes signed over are canconical. The resulting signature will be set on +// the transaction. Finally, the marshaled transaction is returned. An error is +// returned upon failure. +// +// Note, It is assumed the Factory has the necessary fields set that are required +// by the CanonicalSignBytes call. +func Sign(txf Factory, name, passphrase string, tx ClientTx) ([]byte, error) { + if txf.keybase == nil { + keybase, err := keys.NewKeyring( + sdk.KeyringServiceName(), + viper.GetString(flags.FlagKeyringBackend), + viper.GetString(flags.FlagHome), + os.Stdin, + ) + if err != nil { + return nil, err + } + + txf = txf.WithKeybase(keybase) + } + + signBytes, err := tx.CanonicalSignBytes(txf.chainID, txf.accountNumber, txf.sequence) + if err != nil { + return nil, err + } + + sigBytes, pubkey, err := txf.keybase.Sign(name, passphrase, signBytes) + if err != nil { + return nil, err + } + + tx.SetSignatures(txf.sigFn(pubkey, sigBytes)) + return tx.Marshal() +} + +// GasEstimateResponse defines a response definition for tx gas estimation. +type GasEstimateResponse struct { + GasEstimate uint64 `json:"gas_estimate" yaml:"gas_estimate"` +} + +func (gr GasEstimateResponse) String() string { + return fmt.Sprintf("gas estimate: %d", gr.GasEstimate) +} From 8bb0cfdf6f5f6d6147edb8d42f4594b1b618bd84 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Tue, 24 Mar 2020 16:45:34 -0400 Subject: [PATCH 453/529] Use JSON for SimulationResponse --- baseapp/abci.go | 9 +++++++-- client/tx/tx.go | 6 +++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/baseapp/abci.go b/baseapp/abci.go index e984fe0edf24..3342f1aebc61 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -1,6 +1,7 @@ package baseapp import ( + "encoding/json" "fmt" "os" "sort" @@ -9,7 +10,6 @@ import ( abci "github.com/tendermint/tendermint/abci/types" - "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) @@ -336,10 +336,15 @@ func handleQueryApp(app *BaseApp, path []string, req abci.RequestQuery) abci.Res Result: res, } + bz, err := json.Marshal(simRes) + if err != nil { + return sdkerrors.QueryResult(sdkerrors.Wrap(err, "failed to JSON encode simulation response")) + } + return abci.ResponseQuery{ Codespace: sdkerrors.RootCodespace, Height: req.Height, - Value: codec.Cdc.MustMarshalBinaryBare(simRes), + Value: bz, } case "version": diff --git a/client/tx/tx.go b/client/tx/tx.go index 49dfb1cddf90..638c7eeec6e8 100644 --- a/client/tx/tx.go +++ b/client/tx/tx.go @@ -2,6 +2,7 @@ package tx import ( "bufio" + "encoding/json" "errors" "fmt" "os" @@ -216,14 +217,13 @@ func CalculateGas( queryFunc func(string, []byte) ([]byte, int64, error), txBytes []byte, adjustment float64, ) (sdk.SimulationResponse, uint64, error) { - rawRes, _, err := queryFunc("/app/simulate", txBytes) + bz, _, err := queryFunc("/app/simulate", txBytes) if err != nil { return sdk.SimulationResponse{}, 0, err } - // TODO: Use JSON or proto instead of codec.cdc var simRes sdk.SimulationResponse - if err := codec.Cdc.UnmarshalBinaryBare(rawRes, &simRes); err != nil { + if err := json.Unmarshal(bz, &simRes); err != nil { return sdk.SimulationResponse{}, 0, err } From 0f4473936dc0a19d46c8a648918c5286e9ae1950 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Tue, 24 Mar 2020 16:51:59 -0400 Subject: [PATCH 454/529] Fix imports --- client/tx/factory.go | 10 +++++----- client/tx/tx.go | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/client/tx/factory.go b/client/tx/factory.go index a4d3897692ab..1bd4fd975211 100644 --- a/client/tx/factory.go +++ b/client/tx/factory.go @@ -4,12 +4,12 @@ import ( "io" "strings" - "githuf.com/cosmos/cosmos-sdk/client/flags" - "githuf.com/cosmos/cosmos-sdk/crypto/keys" - sdk "githuf.com/cosmos/cosmos-sdk/types" + "github.com/spf13/viper" + "github.com/tendermint/tendermint/crypto" - "githuf.com/spf13/viper" - "githuf.com/tendermint/tendermint/crypto" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/crypto/keys" + sdk "github.com/cosmos/cosmos-sdk/types" ) // AccountRetriever defines the interfaces required for use by the Factory to diff --git a/client/tx/tx.go b/client/tx/tx.go index 638c7eeec6e8..cb90d3aef0e1 100644 --- a/client/tx/tx.go +++ b/client/tx/tx.go @@ -7,10 +7,10 @@ import ( "fmt" "os" - "githuf.com/cosmos/cosmos-sdk/client/flags" - "githuf.com/spf13/viper" + "github.com/spf13/viper" "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/input" clientkeys "github.com/cosmos/cosmos-sdk/client/keys" "github.com/cosmos/cosmos-sdk/codec" From ef29fef5142ba72a27947e84600939a774c8579e Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Tue, 24 Mar 2020 18:00:22 -0400 Subject: [PATCH 455/529] Fix test and update ADR --- baseapp/baseapp_test.go | 6 ++++-- .../adr-020-protobuf-transaction-encoding.md | 9 +++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index 2da5b95f6f00..11d3e346c484 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -3,6 +3,7 @@ package baseapp import ( "bytes" "encoding/binary" + "encoding/json" "fmt" "os" "sync" @@ -936,12 +937,13 @@ func TestSimulateTx(t *testing.T) { require.True(t, queryResult.IsOK(), queryResult.Log) var simRes sdk.SimulationResponse - err = codec.Cdc.UnmarshalBinaryBare(queryResult.Value, &simRes) - require.NoError(t, err) + require.NoError(t, json.Unmarshal(queryResult.Value, &simRes)) + require.Equal(t, gInfo, simRes.GasInfo) require.Equal(t, result.Log, simRes.Result.Log) require.Equal(t, result.Events, simRes.Result.Events) require.True(t, bytes.Equal(result.Data, simRes.Result.Data)) + app.EndBlock(abci.RequestEndBlock{}) app.Commit() } diff --git a/docs/architecture/adr-020-protobuf-transaction-encoding.md b/docs/architecture/adr-020-protobuf-transaction-encoding.md index 6689f29e2356..184ddf6af5f7 100644 --- a/docs/architecture/adr-020-protobuf-transaction-encoding.md +++ b/docs/architecture/adr-020-protobuf-transaction-encoding.md @@ -123,11 +123,12 @@ type ClientTx interface { } ``` -We then update `CLIContext` to have two new fields: `Generator` and `Marshler`. +We then update `CLIContext` to have a new field: `Marshler`. -Then, each module will at the minimum accept a `Marshaler` instead of a concrete -Amino codec. If the module needs to work with any interface types, it will use -the `Codec` interface defined by the module which also extends `Marshaler`. +Then, each module client handler will at the minimum accept a `Marshaler` instead +of a concrete Amino codec and a `Generator`. If the module needs to work with any +interface types, it will use the `Codec` interface defined by the module which also +extends `Marshaler`. ## Future Improvements From 486fa5b4b0163cdb3e6c0f0da4b034810a77d192 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Tue, 24 Mar 2020 18:55:53 -0400 Subject: [PATCH 456/529] Fix constructors --- codec/std/tx.go | 6 ++++-- x/auth/types/stdtx.go | 7 ++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/codec/std/tx.go b/codec/std/tx.go index eca3553f306d..8305c751775f 100644 --- a/codec/std/tx.go +++ b/codec/std/tx.go @@ -122,9 +122,11 @@ func (tx Transaction) GetSignatures() []sdk.Signature { // SetSignatures sets the transaction's signatures. It will overwrite any // existing signatures set. func (tx *Transaction) SetSignatures(sdkSigs ...sdk.Signature) { - sigs := make([]auth.StdSignature, len(tx.Signatures)) + sigs := make([]auth.StdSignature, len(sdkSigs)) for i, sig := range sdkSigs { - sigs[i] = auth.NewStdSignature(sig.GetPubKey(), sig.GetSignature()) + if sig != nil { + sigs[i] = auth.NewStdSignature(sig.GetPubKey(), sig.GetSignature()) + } } tx.Signatures = sigs diff --git a/x/auth/types/stdtx.go b/x/auth/types/stdtx.go index 12e4aecd0bea..04e9ec1fdd79 100644 --- a/x/auth/types/stdtx.go +++ b/x/auth/types/stdtx.go @@ -59,7 +59,12 @@ func (fee StdFee) GasPrices() sdk.DecCoins { } func NewStdSignature(pk crypto.PubKey, sig []byte) StdSignature { - return StdSignature{PubKey: pk.Bytes(), Signature: sig} + var pkBz []byte + if pk != nil { + pkBz = pk.Bytes() + } + + return StdSignature{PubKey: pkBz, Signature: sig} } // GetSignature returns the raw signature bytes. From 33c090ee179a0e3ce6f5c83b33bcd7cc9832f7b3 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Tue, 24 Mar 2020 18:56:20 -0400 Subject: [PATCH 457/529] Use auth instead of func interface --- client/tx/factory.go | 15 --------------- client/tx/tx.go | 7 ++++--- 2 files changed, 4 insertions(+), 18 deletions(-) diff --git a/client/tx/factory.go b/client/tx/factory.go index 1bd4fd975211..55a4982cb8f0 100644 --- a/client/tx/factory.go +++ b/client/tx/factory.go @@ -5,7 +5,6 @@ import ( "strings" "github.com/spf13/viper" - "github.com/tendermint/tendermint/crypto" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/crypto/keys" @@ -26,8 +25,6 @@ type Factory struct { keybase keys.Keybase txGenerator Generator accountRetriever AccountRetriever - feeFn func(gas uint64, amount sdk.Coins) sdk.Fee - sigFn func(pk crypto.PubKey, sig []byte) sdk.Signature accountNumber uint64 sequence uint64 gas uint64 @@ -107,18 +104,6 @@ func (f Factory) WithGas(gas uint64) Factory { return f } -// WithSigFn returns a copy of the Builder with an updated tx signature constructor. -func (f Factory) WithSigFn(sigFn func(pk crypto.PubKey, sig []byte) sdk.Signature) Factory { - f.sigFn = sigFn - return f -} - -// WithFeeFn returns a copy of the Builder with an updated fee constructor. -func (f Factory) WithFeeFn(feeFn func(gas uint64, amount sdk.Coins) sdk.Fee) Factory { - f.feeFn = feeFn - return f -} - // WithFees returns a copy of the Builder with an updated fee. func (f Factory) WithFees(fees string) Factory { parsedFees, err := sdk.ParseCoins(fees) diff --git a/client/tx/tx.go b/client/tx/tx.go index cb90d3aef0e1..dca9787c2a02 100644 --- a/client/tx/tx.go +++ b/client/tx/tx.go @@ -16,6 +16,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/crypto/keys" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" ) type ( @@ -187,7 +188,7 @@ func BuildUnsignedTx(txf Factory, msgs ...sdk.Msg) (ClientTx, error) { } tx := txf.txGenerator.NewTx() - tx.SetFee(txf.feeFn(txf.gas, fees)) + tx.SetFee(auth.NewStdFee(txf.gas, fees)) tx.SetMsgs(msgs...) tx.SetMemo(txf.memo) tx.SetSignatures(nil) @@ -206,7 +207,7 @@ func BuildSimTx(txf Factory, msgs ...sdk.Msg) ([]byte, error) { // Create an empty signature literal as the ante handler will populate with a // sentinel pubkey. - tx.SetSignatures(txf.sigFn(nil, nil)) + tx.SetSignatures(auth.NewStdSignature(nil, nil)) return tx.Marshal() } @@ -292,7 +293,7 @@ func Sign(txf Factory, name, passphrase string, tx ClientTx) ([]byte, error) { return nil, err } - tx.SetSignatures(txf.sigFn(pubkey, sigBytes)) + tx.SetSignatures(auth.NewStdSignature(pubkey, sigBytes)) return tx.Marshal() } From 70d024137309fbfcb87b18087f9dddfbf166ca0a Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Tue, 24 Mar 2020 19:07:27 -0400 Subject: [PATCH 458/529] tx tests --- client/tx/tx.go | 2 +- client/tx/tx_test.go | 106 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 client/tx/tx_test.go diff --git a/client/tx/tx.go b/client/tx/tx.go index dca9787c2a02..a3ead89d6679 100644 --- a/client/tx/tx.go +++ b/client/tx/tx.go @@ -191,7 +191,7 @@ func BuildUnsignedTx(txf Factory, msgs ...sdk.Msg) (ClientTx, error) { tx.SetFee(auth.NewStdFee(txf.gas, fees)) tx.SetMsgs(msgs...) tx.SetMemo(txf.memo) - tx.SetSignatures(nil) + tx.SetSignatures() return tx, nil } diff --git a/client/tx/tx_test.go b/client/tx/tx_test.go new file mode 100644 index 000000000000..55688dba7ef6 --- /dev/null +++ b/client/tx/tx_test.go @@ -0,0 +1,106 @@ +package tx_test + +import ( + "encoding/json" + "errors" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/client/tx" + "github.com/cosmos/cosmos-sdk/codec/std" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/bank" +) + +func TestCalculateGas(t *testing.T) { + makeQueryFunc := func(gasUsed uint64, wantErr bool) func(string, []byte) ([]byte, int64, error) { + return func(string, []byte) ([]byte, int64, error) { + if wantErr { + return nil, 0, errors.New("query failed") + } + simRes := sdk.SimulationResponse{ + GasInfo: sdk.GasInfo{GasUsed: gasUsed, GasWanted: gasUsed}, + Result: &sdk.Result{Data: []byte("tx data"), Log: "log"}, + } + + bz, err := json.Marshal(simRes) + if err != nil { + return nil, 0, err + } + + return bz, 0, nil + } + } + + type args struct { + queryFuncGasUsed uint64 + queryFuncWantErr bool + adjustment float64 + } + + testCases := []struct { + name string + args args + wantEstimate uint64 + wantAdjusted uint64 + expPass bool + }{ + {"error", args{0, true, 1.2}, 0, 0, false}, + {"adjusted gas", args{10, false, 1.2}, 10, 12, true}, + } + + for _, tc := range testCases { + stc := tc + + t.Run(stc.name, func(t *testing.T) { + queryFunc := makeQueryFunc(stc.args.queryFuncGasUsed, stc.args.queryFuncWantErr) + simRes, gotAdjusted, err := tx.CalculateGas(queryFunc, []byte(""), stc.args.adjustment) + if stc.expPass { + require.NoError(t, err) + require.Equal(t, simRes.GasInfo.GasUsed, stc.wantEstimate) + require.Equal(t, gotAdjusted, stc.wantAdjusted) + require.NotNil(t, simRes.Result) + } else { + require.Error(t, err) + require.Nil(t, simRes.Result) + } + }) + } +} + +func TestBuildSimTx(t *testing.T) { + txf := tx.Factory{}. + WithTxGenerator(std.TxGenerator{}). + WithAccountNumber(50). + WithSequence(23). + WithFees("50stake"). + WithMemo("memo"). + WithChainID("test-chain") + + msg := bank.NewMsgSend(sdk.AccAddress("from"), sdk.AccAddress("to"), nil) + bz, err := tx.BuildSimTx(txf, msg) + require.NoError(t, err) + require.NotNil(t, bz) + + tx := &std.Transaction{} + require.NoError(t, tx.Unmarshal(bz)) + require.Equal(t, []sdk.Signature{sdk.Signature(auth.StdSignature{})}, tx.GetSignatures()) +} + +func TestBuildUnsignedTx(t *testing.T) { + txf := tx.Factory{}. + WithTxGenerator(std.TxGenerator{}). + WithAccountNumber(50). + WithSequence(23). + WithFees("50stake"). + WithMemo("memo"). + WithChainID("test-chain") + + msg := bank.NewMsgSend(sdk.AccAddress("from"), sdk.AccAddress("to"), nil) + tx, err := tx.BuildUnsignedTx(txf, msg) + require.NoError(t, err) + require.NotNil(t, tx) + require.Equal(t, []sdk.Signature{}, tx.GetSignatures()) +} From 206a511fa9b636f007c85959505a4de6b2367223 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Wed, 25 Mar 2020 00:46:10 +0100 Subject: [PATCH 459/529] Use cosmos' fork of github.com/bartekn/go-bip39 (#5867) Thanks @fedekunze for pointing this out. --- client/keys/add.go | 2 +- client/keys/mnemonic.go | 2 +- go.mod | 1 - go.sum | 2 -- 4 files changed, 2 insertions(+), 5 deletions(-) diff --git a/client/keys/add.go b/client/keys/add.go index 4f5fda67d731..a2e8fd2164f9 100644 --- a/client/keys/add.go +++ b/client/keys/add.go @@ -8,7 +8,7 @@ import ( "io" "sort" - bip39 "github.com/bartekn/go-bip39" + bip39 "github.com/cosmos/go-bip39" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/input" diff --git a/client/keys/mnemonic.go b/client/keys/mnemonic.go index 01d7416f0536..e665130ee4c3 100644 --- a/client/keys/mnemonic.go +++ b/client/keys/mnemonic.go @@ -5,7 +5,7 @@ import ( "crypto/sha256" "fmt" - bip39 "github.com/bartekn/go-bip39" + bip39 "github.com/cosmos/go-bip39" "github.com/spf13/cobra" "github.com/cosmos/cosmos-sdk/client/input" diff --git a/go.mod b/go.mod index 8780987da431..836c9d81088e 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,6 @@ module github.com/cosmos/cosmos-sdk require ( github.com/99designs/keyring v1.1.4 - github.com/bartekn/go-bip39 v0.0.0-20171116152956-a05967ea095d github.com/bgentry/speakeasy v0.1.0 github.com/btcsuite/btcd v0.0.0-20190115013929-ed77733ec07d github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d diff --git a/go.sum b/go.sum index 620da8f5397f..69f6ec57f93d 100644 --- a/go.sum +++ b/go.sum @@ -29,8 +29,6 @@ github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6l github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= -github.com/bartekn/go-bip39 v0.0.0-20171116152956-a05967ea095d h1:1aAija9gr0Hyv4KfQcRcwlmFIrhkDmIj2dz5bkg/s/8= -github.com/bartekn/go-bip39 v0.0.0-20171116152956-a05967ea095d/go.mod h1:icNx/6QdFblhsEjZehARqbNumymUT/ydwlLojFdv7Sk= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= From c4a4047ed2c924253e7f2f6245b6aa25c80e9a04 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 25 Mar 2020 10:55:28 -0400 Subject: [PATCH 460/529] Implement NewSendTxCmd --- x/bank/client/cli/tx.go | 63 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/x/bank/client/cli/tx.go b/x/bank/client/cli/tx.go index 0764045968a7..906db932b3a8 100644 --- a/x/bank/client/cli/tx.go +++ b/x/bank/client/cli/tx.go @@ -8,6 +8,8 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/tx" + clientx "github.com/cosmos/cosmos-sdk/client/tx" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" @@ -15,7 +17,65 @@ import ( "github.com/cosmos/cosmos-sdk/x/bank/types" ) +// NewTxCmd returns a root CLI command handler for all x/bank transaction commands. +func NewTxCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command { + txCmd := &cobra.Command{ + Use: types.ModuleName, + Short: "Bank transaction subcommands", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + txCmd.AddCommand( + NewSendTxCmd(m, txg, ar), + ) + + return txCmd +} + +// NewSendTxCmd returns a CLI command handler for creating a MsgSend transaction. +func NewSendTxCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command { + cmd := &cobra.Command{ + Use: "send [from_key_or_address] [to_address] [amount]", + Short: "Create and/or sign and broadcast a MsgSend transaction", + Args: cobra.ExactArgs(3), + RunE: func(cmd *cobra.Command, args []string) error { + inBuf := bufio.NewReader(cmd.InOrStdin()) + txf := tx.NewFactoryFromCLI(inBuf). + WithTxGenerator(txg). + WithAccountRetriever(ar) + + cliCtx := context.NewCLIContextWithInputAndFrom(inBuf, args[0]).WithMarshaler(m) + + toAddr, err := sdk.AccAddressFromBech32(args[1]) + if err != nil { + return err + } + + coins, err := sdk.ParseCoins(args[2]) + if err != nil { + return err + } + + msg := types.NewMsgSend(cliCtx.GetFromAddress(), toAddr, coins) + return clientx.GenerateOrBroadcastTx(cliCtx, txf, msg) + }, + } + + return flags.PostCommands(cmd)[0] +} + +// --------------------------------------------------------------------------- +// Deprecated +// +// TODO: Remove once client-side Protobuf migration has been completed. +// --------------------------------------------------------------------------- + // GetTxCmd returns the transaction commands for this module +// +// TODO: Remove once client-side Protobuf migration has been completed. +// ref: https://github.com/cosmos/cosmos-sdk/issues/5864 func GetTxCmd(cdc *codec.Codec) *cobra.Command { txCmd := &cobra.Command{ Use: types.ModuleName, @@ -31,6 +91,9 @@ func GetTxCmd(cdc *codec.Codec) *cobra.Command { } // SendTxCmd will create a send tx and sign it with the given key. +// +// TODO: Remove once client-side Protobuf migration has been completed. +// ref: https://github.com/cosmos/cosmos-sdk/issues/5864 func SendTxCmd(cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "send [from_key_or_address] [to_address] [amount]", From f20db1c835a2142ba79d0d7ebeab0a2be901a685 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 25 Mar 2020 11:03:36 -0400 Subject: [PATCH 461/529] Update ADR --- .../adr-020-protobuf-transaction-encoding.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/architecture/adr-020-protobuf-transaction-encoding.md b/docs/architecture/adr-020-protobuf-transaction-encoding.md index 184ddf6af5f7..d58df6fb5de2 100644 --- a/docs/architecture/adr-020-protobuf-transaction-encoding.md +++ b/docs/architecture/adr-020-protobuf-transaction-encoding.md @@ -125,10 +125,11 @@ type ClientTx interface { We then update `CLIContext` to have a new field: `Marshler`. -Then, each module client handler will at the minimum accept a `Marshaler` instead -of a concrete Amino codec and a `Generator`. If the module needs to work with any -interface types, it will use the `Codec` interface defined by the module which also -extends `Marshaler`. +Then, each module's client handler will at the minimum accept a `Marshaler` instead +of a concrete Amino codec and a `Generator` along with an `AccountRetriever` so +that account fields can be retrieved for signing. If the module needs to work with +any interface types, it will use the `Codec` interface defined by the module which +also extends `Marshaler`. ## Future Improvements From e77d5cb67787d34319b66d38b7cb2882844ff800 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 25 Mar 2020 11:09:26 -0400 Subject: [PATCH 462/529] Update ADR + changelog --- CHANGELOG.md | 1 + docs/architecture/adr-020-protobuf-transaction-encoding.md | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f855ade9fe6..b3aacd0de6e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,6 +54,7 @@ older clients. ### API Breaking Changes +* (baseapp) [\#5865](https://github.com/cosmos/cosmos-sdk/pull/5865) The `SimulationResponse` returned from tx simulation is now JSON encoded instead of Amino binary. * [\#5719](https://github.com/cosmos/cosmos-sdk/pull/5719) Bump Go requirement to 1.14+ * (x/params) [\#5619](https://github.com/cosmos/cosmos-sdk/pull/5619) The `x/params` keeper now accepts a `codec.Marshaller` instead of a reference to an amino codec. Amino is still used for JSON serialization. diff --git a/docs/architecture/adr-020-protobuf-transaction-encoding.md b/docs/architecture/adr-020-protobuf-transaction-encoding.md index d58df6fb5de2..d3afaa7be512 100644 --- a/docs/architecture/adr-020-protobuf-transaction-encoding.md +++ b/docs/architecture/adr-020-protobuf-transaction-encoding.md @@ -103,6 +103,11 @@ to handle all the types, but also knows how to generate transactions, signatures and messages. ```go +type AccountRetriever interface { + EnsureExists(addr sdk.AccAddress) error + GetAccountNumberSequence(addr sdk.AccAddress) (uint64, uint64, error) +} + type Generator interface { NewTx() ClientTx } From 9cce836c08d14dc6836d07164dd964b2b7226f36 Mon Sep 17 00:00:00 2001 From: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Date: Wed, 25 Mar 2020 12:20:36 -0300 Subject: [PATCH 463/529] crypto/keys: move keybase and keyring to crypto/keyring/ dir (#5866) * crypto/keys: move keybase and keyring to crypto/keyring/ dir * Update client/keys/root.go * Update crypto/keyring/errors.go * Update crypto/keyring/keybase.go * Update crypto/keyring/options.go * format * changelog * fix build * format * lint --- CHANGELOG.md | 5 +- client/context/context.go | 8 +- client/flags/flags.go | 4 +- client/keys/add.go | 36 +++--- client/keys/add_ledger_test.go | 10 +- client/keys/add_test.go | 4 +- client/keys/codec_test.go | 12 +- client/keys/delete.go | 6 +- client/keys/delete_test.go | 10 +- client/keys/export.go | 4 +- client/keys/export_test.go | 6 +- client/keys/import.go | 4 +- client/keys/import_test.go | 4 +- client/keys/list.go | 4 +- client/keys/list_test.go | 6 +- client/keys/migrate.go | 10 +- client/keys/root_test.go | 4 +- client/keys/show.go | 16 +-- client/keys/show_test.go | 18 +-- client/keys/types.go | 2 +- client/keys/update_test.go | 27 +++-- client/keys/utils.go | 28 ++--- .../base_keybase.go} | 50 +------- crypto/{keys => keyring}/codec.go | 2 +- .../keybase.go => keyring/db_keybase.go} | 52 +-------- crypto/{keys => keyring}/doc.go | 2 +- crypto/keyring/errors.go | 13 +++ crypto/{keys/types.go => keyring/info.go} | 107 +----------------- crypto/keyring/keybase.go | 79 +++++++++++++ crypto/{keys => keyring}/keybase_test.go | 3 +- crypto/{keys => keyring}/keyring.go | 8 +- crypto/{keys => keyring}/keyring_test.go | 3 +- crypto/{keys => keyring}/keys.toml | 0 crypto/{keys => keyring}/lazy_keybase.go | 2 +- crypto/{keys => keyring}/lazy_keybase_test.go | 2 +- crypto/keyring/options.go | 39 +++++++ crypto/{keys => keyring}/output.go | 2 +- crypto/{keys => keyring}/output_test.go | 2 +- .../keys.go => keyring/signing_algorithms.go} | 12 +- crypto/keyring/types.go | 68 +++++++++++ crypto/{keys => keyring}/types_test.go | 2 +- crypto/keys/keyerror/errors.go | 81 ------------- crypto/keys/keyerror/errors_test.go | 24 ---- crypto/keys/mintkey/mintkey.go | 9 +- crypto/keys/mintkey/mintkey_test.go | 10 +- server/init.go | 8 +- server/init_test.go | 10 +- types/errors/errors.go | 6 + x/auth/client/cli/tx_multisign.go | 8 +- x/auth/types/txbuilder.go | 14 +-- x/genutil/client/cli/gentx.go | 6 +- 51 files changed, 385 insertions(+), 467 deletions(-) rename crypto/{keys/keybase_base.go => keyring/base_keybase.go} (83%) rename crypto/{keys => keyring}/codec.go (98%) rename crypto/{keys/keybase.go => keyring/db_keybase.go} (88%) rename crypto/{keys => keyring}/doc.go (99%) create mode 100644 crypto/keyring/errors.go rename crypto/{keys/types.go => keyring/info.go} (57%) create mode 100644 crypto/keyring/keybase.go rename crypto/{keys => keyring}/keybase_test.go (99%) rename crypto/{keys => keyring}/keyring.go (98%) rename crypto/{keys => keyring}/keyring_test.go (99%) rename crypto/{keys => keyring}/keys.toml (100%) rename crypto/{keys => keyring}/lazy_keybase.go (99%) rename crypto/{keys => keyring}/lazy_keybase_test.go (99%) create mode 100644 crypto/keyring/options.go rename crypto/{keys => keyring}/output.go (99%) rename crypto/{keys => keyring}/output_test.go (98%) rename crypto/{keys/keys.go => keyring/signing_algorithms.go} (64%) create mode 100644 crypto/keyring/types.go rename crypto/{keys => keyring}/types_test.go (98%) delete mode 100644 crypto/keys/keyerror/errors.go delete mode 100644 crypto/keys/keyerror/errors_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f855ade9fe6..c21c3c457bb9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -64,15 +64,16 @@ heights are kept after pruning. The `IsValid` method should be called whenever u `SnapshotVersion` and `FlushVersion` accept a version arugment and determine if the version should be flushed to disk or kept as a snapshot. Note, `KeepRecent` is automatically inferred from the options and provided directly the IAVL store. -* (modules) [\#5555](https://github.com/cosmos/cosmos-sdk/pull/5555) Move x/auth/client/utils/ types and functions to x/auth/client/. +* (modules) [\#5555](https://github.com/cosmos/cosmos-sdk/pull/5555) Move `x/auth/client/utils/` types and functions to `x/auth/client/`. * (modules) [\#5572](https://github.com/cosmos/cosmos-sdk/pull/5572) Move account balance logic and APIs from `x/auth` to `x/bank`. * (types) [\#5533](https://github.com/cosmos/cosmos-sdk/pull/5533) Refactored `AppModuleBasic` and `AppModuleGenesis` to now accept a `codec.JSONMarshaler` for modular serialization of genesis state. -* (crypto/keys) [\#5735](https://github.com/cosmos/cosmos-sdk/pull/5735) Keyring's Update() function is now no-op. +* (crypto/keys) [\#5735](https://github.com/cosmos/cosmos-sdk/pull/5735) Keyring's `Update()` function is now no-op. * (types/rest) [\#5779](https://github.com/cosmos/cosmos-sdk/pull/5779) Drop unused Parse{Int64OrReturnBadRequest,QueryParamBool}() functions. * (keys) [\#5820](https://github.com/cosmos/cosmos-sdk/pull/5820/) Removed method CloseDB from Keybase interface. * (baseapp) [\#5837](https://github.com/cosmos/cosmos-sdk/issues/5837) Transaction simulation now returns a `SimulationResponse` which contains the `GasInfo` and `Result` from the execution. +* (crypto/keys) [\#5866](https://github.com/cosmos/cosmos-sdk/pull/5866) Move `Keyring` and `Keybase` implementations and their associated types from `crypto/keys/` to `crypto/keybase/`. ### Features diff --git a/client/context/context.go b/client/context/context.go index 80813b7655cd..30e2c141aba2 100644 --- a/client/context/context.go +++ b/client/context/context.go @@ -16,7 +16,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" clientx "github.com/cosmos/cosmos-sdk/client/tx" "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/crypto/keys" + "github.com/cosmos/cosmos-sdk/crypto/keyring" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -28,7 +28,7 @@ type CLIContext struct { ChainID string TxGenerator clientx.Generator Marshaler codec.Marshaler - Keybase keys.Keybase + Keybase keyring.Keybase Input io.Reader Output io.Writer OutputFormat string @@ -295,13 +295,13 @@ func GetFromFields(input io.Reader, from string, genOnly bool) (sdk.AccAddress, return addr, "", nil } - keybase, err := keys.NewKeyring(sdk.KeyringServiceName(), + keybase, err := keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), input) if err != nil { return nil, "", err } - var info keys.Info + var info keyring.Info if addr, err := sdk.AccAddressFromBech32(from); err == nil { info, err = keybase.GetByAddress(addr) if err != nil { diff --git a/client/flags/flags.go b/client/flags/flags.go index b4c501d99ccf..7497355ba215 100644 --- a/client/flags/flags.go +++ b/client/flags/flags.go @@ -10,7 +10,7 @@ import ( tmcli "github.com/tendermint/tendermint/libs/cli" - "github.com/cosmos/cosmos-sdk/crypto/keys" + "github.com/cosmos/cosmos-sdk/crypto/keyring" ) // nolint @@ -23,7 +23,7 @@ const ( GasFlagAuto = "auto" // DefaultKeyringBackend - DefaultKeyringBackend = keys.BackendOS + DefaultKeyringBackend = keyring.BackendOS ) const ( diff --git a/client/keys/add.go b/client/keys/add.go index a2e8fd2164f9..d8f768cc4f14 100644 --- a/client/keys/add.go +++ b/client/keys/add.go @@ -12,7 +12,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/input" - "github.com/cosmos/cosmos-sdk/crypto/keys" + "github.com/cosmos/cosmos-sdk/crypto/keyring" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/spf13/cobra" @@ -77,16 +77,16 @@ the flag --nosort is set. cmd.Flags().Uint32(flagAccount, 0, "Account number for HD derivation") cmd.Flags().Uint32(flagIndex, 0, "Address index number for HD derivation") cmd.Flags().Bool(flags.FlagIndentResponse, false, "Add indent to JSON response") - cmd.Flags().String(flagKeyAlgo, string(keys.Secp256k1), "Key signing algorithm to generate keys for") + cmd.Flags().String(flagKeyAlgo, string(keyring.Secp256k1), "Key signing algorithm to generate keys for") return cmd } -func getKeybase(transient bool, buf io.Reader) (keys.Keybase, error) { +func getKeybase(transient bool, buf io.Reader) (keyring.Keybase, error) { if transient { - return keys.NewInMemory(), nil + return keyring.NewInMemory(), nil } - return keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), buf) + return keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), buf) } func runAddCmd(cmd *cobra.Command, args []string) error { @@ -108,7 +108,7 @@ input output - armor encrypted private key (saved to file) */ -func RunAddCmd(cmd *cobra.Command, args []string, kb keys.Keybase, inBuf *bufio.Reader) error { +func RunAddCmd(cmd *cobra.Command, args []string, kb keyring.Keybase, inBuf *bufio.Reader) error { var err error name := args[0] @@ -116,12 +116,12 @@ func RunAddCmd(cmd *cobra.Command, args []string, kb keys.Keybase, inBuf *bufio. interactive := viper.GetBool(flagInteractive) showMnemonic := !viper.GetBool(flagNoBackup) - algo := keys.SigningAlgo(viper.GetString(flagKeyAlgo)) - if algo == keys.SigningAlgo("") { - algo = keys.Secp256k1 + algo := keyring.SigningAlgo(viper.GetString(flagKeyAlgo)) + if algo == keyring.SigningAlgo("") { + algo = keyring.Secp256k1 } - if !keys.IsSupportedAlgorithm(kb.SupportedAlgos(), algo) { - return keys.ErrUnsupportedSigningAlgo + if !keyring.IsSupportedAlgorithm(kb.SupportedAlgos(), algo) { + return keyring.ErrUnsupportedSigningAlgo } if !viper.GetBool(flagDryRun) { @@ -190,7 +190,7 @@ func RunAddCmd(cmd *cobra.Command, args []string, kb keys.Keybase, inBuf *bufio. var hdPath string if useBIP44 { - hdPath = keys.CreateHDPath(account, index).String() + hdPath = keyring.CreateHDPath(account, index).String() } else { hdPath = viper.GetString(flagHDPath) } @@ -202,12 +202,12 @@ func RunAddCmd(cmd *cobra.Command, args []string, kb keys.Keybase, inBuf *bufio. return errors.New("cannot set custom bip32 path with ledger") } - if !keys.IsSupportedAlgorithm(kb.SupportedAlgosLedger(), algo) { - return keys.ErrUnsupportedSigningAlgo + if !keyring.IsSupportedAlgorithm(kb.SupportedAlgosLedger(), algo) { + return keyring.ErrUnsupportedSigningAlgo } bech32PrefixAccAddr := sdk.GetConfig().GetBech32AccountAddrPrefix() - info, err := kb.CreateLedger(name, keys.Secp256k1, bech32PrefixAccAddr, account, index) + info, err := kb.CreateLedger(name, keyring.Secp256k1, bech32PrefixAccAddr, account, index) if err != nil { return err } @@ -285,13 +285,13 @@ func RunAddCmd(cmd *cobra.Command, args []string, kb keys.Keybase, inBuf *bufio. return printCreate(cmd, info, showMnemonic, mnemonic) } -func printCreate(cmd *cobra.Command, info keys.Info, showMnemonic bool, mnemonic string) error { +func printCreate(cmd *cobra.Command, info keyring.Info, showMnemonic bool, mnemonic string) error { output := viper.Get(cli.OutputFlag) switch output { case OutputFormatText: cmd.PrintErrln() - printKeyInfo(info, keys.Bech32KeyOutput) + printKeyInfo(info, keyring.Bech32KeyOutput) // print mnemonic unless requested not to. if showMnemonic { @@ -301,7 +301,7 @@ func printCreate(cmd *cobra.Command, info keys.Info, showMnemonic bool, mnemonic cmd.PrintErrln(mnemonic) } case OutputFormatJSON: - out, err := keys.Bech32KeyOutput(info) + out, err := keyring.Bech32KeyOutput(info) if err != nil { return err } diff --git a/client/keys/add_ledger_test.go b/client/keys/add_ledger_test.go index d69dae252a67..dd53d1b361ce 100644 --- a/client/keys/add_ledger_test.go +++ b/client/keys/add_ledger_test.go @@ -11,7 +11,7 @@ import ( "github.com/tendermint/tendermint/libs/cli" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/crypto/keys" + "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/tests" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -51,7 +51,7 @@ func Test_runAddCmdLedgerWithCustomCoinType(t *testing.T) { require.NoError(t, runAddCmd(cmd, []string{"keyname1"})) // Now check that it has been stored properly - kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) + kb, err := keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) require.NoError(t, err) require.NotNil(t, kb) t.Cleanup(func() { @@ -66,7 +66,7 @@ func Test_runAddCmdLedgerWithCustomCoinType(t *testing.T) { require.NotNil(t, key1) require.Equal(t, "keyname1", key1.GetName()) - require.Equal(t, keys.TypeLedger, key1.GetType()) + require.Equal(t, keyring.TypeLedger, key1.GetType()) require.Equal(t, "terrapub1addwnpepqvpg7r26nl2pvqqern00m6s9uaax3hauu2rzg8qpjzq9hy6xve7sw0d84m6", sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, key1.GetPubKey())) @@ -98,7 +98,7 @@ func Test_runAddCmdLedger(t *testing.T) { require.NoError(t, runAddCmd(cmd, []string{"keyname1"})) // Now check that it has been stored properly - kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), kbHome, mockIn) + kb, err := keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), kbHome, mockIn) require.NoError(t, err) require.NotNil(t, kb) t.Cleanup(func() { @@ -113,7 +113,7 @@ func Test_runAddCmdLedger(t *testing.T) { require.NotNil(t, key1) require.Equal(t, "keyname1", key1.GetName()) - require.Equal(t, keys.TypeLedger, key1.GetType()) + require.Equal(t, keyring.TypeLedger, key1.GetType()) require.Equal(t, "cosmospub1addwnpepqd87l8xhcnrrtzxnkql7k55ph8fr9jarf4hn6udwukfprlalu8lgw0urza0", sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, key1.GetPubKey())) diff --git a/client/keys/add_test.go b/client/keys/add_test.go index fe72f0e0eb01..5276e942d0ce 100644 --- a/client/keys/add_test.go +++ b/client/keys/add_test.go @@ -10,7 +10,7 @@ import ( "github.com/tendermint/tendermint/libs/cli" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/crypto/keys" + "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/tests" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -31,7 +31,7 @@ func Test_runAddCmdBasic(t *testing.T) { mockIn.Reset("testpass1\ntestpass1\n") } else { mockIn.Reset("y\n") - kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), kbHome, mockIn) + kb, err := keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), kbHome, mockIn) require.NoError(t, err) t.Cleanup(func() { kb.Delete("keyname1", "", false) // nolint:errcheck diff --git a/client/keys/codec_test.go b/client/keys/codec_test.go index 6bc6bd49e365..7aca4510f958 100644 --- a/client/keys/codec_test.go +++ b/client/keys/codec_test.go @@ -7,25 +7,25 @@ import ( "github.com/stretchr/testify/require" - "github.com/cosmos/cosmos-sdk/crypto/keys" + "github.com/cosmos/cosmos-sdk/crypto/keyring" ) type testCases struct { - Keys []keys.KeyOutput - Answers []keys.KeyOutput + Keys []keyring.KeyOutput + Answers []keyring.KeyOutput JSON [][]byte } func getTestCases() testCases { return testCases{ // nolint:govet - []keys.KeyOutput{ + []keyring.KeyOutput{ {"A", "B", "C", "D", "E", 0, nil}, {"A", "B", "C", "D", "", 0, nil}, {"", "B", "C", "D", "", 0, nil}, {"", "", "", "", "", 0, nil}, }, - make([]keys.KeyOutput, 4), + make([]keyring.KeyOutput, 4), [][]byte{ []byte(`{"name":"A","type":"B","address":"C","pubkey":"D","mnemonic":"E"}`), []byte(`{"name":"A","type":"B","address":"C","pubkey":"D"}`), @@ -37,7 +37,7 @@ func getTestCases() testCases { func TestMarshalJSON(t *testing.T) { type args struct { - o keys.KeyOutput + o keyring.KeyOutput } data := getTestCases() diff --git a/client/keys/delete.go b/client/keys/delete.go index 3559a228082a..0c379e49bcaf 100644 --- a/client/keys/delete.go +++ b/client/keys/delete.go @@ -6,7 +6,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/input" - "github.com/cosmos/cosmos-sdk/crypto/keys" + "github.com/cosmos/cosmos-sdk/crypto/keyring" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/spf13/cobra" @@ -43,7 +43,7 @@ private keys stored in a ledger device cannot be deleted with the CLI. func runDeleteCmd(cmd *cobra.Command, args []string) error { buf := bufio.NewReader(cmd.InOrStdin()) - kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), buf) + kb, err := keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), buf) if err != nil { return err } @@ -54,7 +54,7 @@ func runDeleteCmd(cmd *cobra.Command, args []string) error { return err } - if info.GetType() == keys.TypeLedger || info.GetType() == keys.TypeOffline { + if info.GetType() == keyring.TypeLedger || info.GetType() == keyring.TypeOffline { // confirm deletion, unless -y is passed if !viper.GetBool(flagYes) { if err := confirmDeletion(buf); err != nil { diff --git a/client/keys/delete_test.go b/client/keys/delete_test.go index e897f5aadbef..80da06ad8d95 100644 --- a/client/keys/delete_test.go +++ b/client/keys/delete_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/crypto/keys" + "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/tests" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -27,7 +27,7 @@ func Test_runDeleteCmd(t *testing.T) { fakeKeyName1 := "runDeleteCmd_Key1" fakeKeyName2 := "runDeleteCmd_Key2" if !runningUnattended { - kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) + kb, err := keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) require.NoError(t, err) t.Cleanup(func() { kb.Delete("runDeleteCmd_Key1", "", false) // nolint:errcheck @@ -41,18 +41,18 @@ func Test_runDeleteCmd(t *testing.T) { viper.Set(flags.FlagHome, kbHome) // Now - kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), kbHome, mockIn) + kb, err := keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), kbHome, mockIn) require.NoError(t, err) if runningUnattended { mockIn.Reset("testpass1\ntestpass1\n") } - _, err = kb.CreateAccount(fakeKeyName1, tests.TestMnemonic, "", "", "0", keys.Secp256k1) + _, err = kb.CreateAccount(fakeKeyName1, tests.TestMnemonic, "", "", "0", keyring.Secp256k1) require.NoError(t, err) if runningUnattended { mockIn.Reset("testpass1\ntestpass1\n") } - _, err = kb.CreateAccount(fakeKeyName2, tests.TestMnemonic, "", "", "1", keys.Secp256k1) + _, err = kb.CreateAccount(fakeKeyName2, tests.TestMnemonic, "", "", "1", keyring.Secp256k1) require.NoError(t, err) if runningUnattended { diff --git a/client/keys/export.go b/client/keys/export.go index fb12eb508d5e..dba66d8352aa 100644 --- a/client/keys/export.go +++ b/client/keys/export.go @@ -8,7 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/input" - "github.com/cosmos/cosmos-sdk/crypto/keys" + "github.com/cosmos/cosmos-sdk/crypto/keyring" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -25,7 +25,7 @@ func ExportKeyCommand() *cobra.Command { func runExportCmd(cmd *cobra.Command, args []string) error { buf := bufio.NewReader(cmd.InOrStdin()) - kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), buf) + kb, err := keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), buf) if err != nil { return err } diff --git a/client/keys/export_test.go b/client/keys/export_test.go index f83c428cfc87..e7e6fb4915b0 100644 --- a/client/keys/export_test.go +++ b/client/keys/export_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/crypto/keys" + "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/tests" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -23,7 +23,7 @@ func Test_runExportCmd(t *testing.T) { viper.Set(flags.FlagHome, kbHome) // create a key - kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) + kb, err := keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) require.NoError(t, err) if !runningUnattended { t.Cleanup(func() { @@ -34,7 +34,7 @@ func Test_runExportCmd(t *testing.T) { if runningUnattended { mockIn.Reset("testpass1\ntestpass1\n") } - _, err = kb.CreateAccount("keyname1", tests.TestMnemonic, "", "123456789", "", keys.Secp256k1) + _, err = kb.CreateAccount("keyname1", tests.TestMnemonic, "", "123456789", "", keyring.Secp256k1) require.NoError(t, err) // Now enter password diff --git a/client/keys/import.go b/client/keys/import.go index 6e58dd872225..89a1f3769f8c 100644 --- a/client/keys/import.go +++ b/client/keys/import.go @@ -9,7 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/input" - "github.com/cosmos/cosmos-sdk/crypto/keys" + "github.com/cosmos/cosmos-sdk/crypto/keyring" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -26,7 +26,7 @@ func ImportKeyCommand() *cobra.Command { func runImportCmd(cmd *cobra.Command, args []string) error { buf := bufio.NewReader(cmd.InOrStdin()) - kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), buf) + kb, err := keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), buf) if err != nil { return err } diff --git a/client/keys/import_test.go b/client/keys/import_test.go index d0325677bc81..1bcae042cc4d 100644 --- a/client/keys/import_test.go +++ b/client/keys/import_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/crypto/keys" + "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/tests" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -25,7 +25,7 @@ func Test_runImportCmd(t *testing.T) { viper.Set(flags.FlagHome, kbHome) if !runningUnattended { - kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) + kb, err := keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) require.NoError(t, err) t.Cleanup(func() { kb.Delete("keyname1", "", false) // nolint:errcheck diff --git a/client/keys/list.go b/client/keys/list.go index dbac54502d98..8af7f97154d1 100644 --- a/client/keys/list.go +++ b/client/keys/list.go @@ -5,7 +5,7 @@ import ( "github.com/spf13/viper" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/crypto/keys" + "github.com/cosmos/cosmos-sdk/crypto/keyring" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -26,7 +26,7 @@ along with their associated name and address.`, } func runListCmd(cmd *cobra.Command, _ []string) error { - kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), cmd.InOrStdin()) + kb, err := keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), cmd.InOrStdin()) if err != nil { return err } diff --git a/client/keys/list_test.go b/client/keys/list_test.go index 9770346dd984..c259793e9b80 100644 --- a/client/keys/list_test.go +++ b/client/keys/list_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/crypto/keys" + "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/tests" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -32,13 +32,13 @@ func Test_runListCmd(t *testing.T) { viper.Set(flags.FlagHome, kbHome2) mockIn, _, _ := tests.ApplyMockIO(cmdBasic) - kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) + kb, err := keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) require.NoError(t, err) if runningUnattended { mockIn.Reset("testpass1\ntestpass1\n") } - _, err = kb.CreateAccount("something", tests.TestMnemonic, "", "", "", keys.Secp256k1) + _, err = kb.CreateAccount("something", tests.TestMnemonic, "", "", "", keyring.Secp256k1) require.NoError(t, err) t.Cleanup(func() { diff --git a/client/keys/migrate.go b/client/keys/migrate.go index ef1d832ac113..2f7f3c95df5b 100644 --- a/client/keys/migrate.go +++ b/client/keys/migrate.go @@ -8,7 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/input" - "github.com/cosmos/cosmos-sdk/crypto/keys" + "github.com/cosmos/cosmos-sdk/crypto/keyring" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/pkg/errors" @@ -59,7 +59,7 @@ func runMigrateCmd(cmd *cobra.Command, args []string) error { var ( tmpDir string - keybase keys.Keybase + keybase keyring.Keybase ) if viper.GetBool(flags.FlagDryRun) { @@ -70,9 +70,9 @@ func runMigrateCmd(cmd *cobra.Command, args []string) error { defer os.RemoveAll(tmpDir) - keybase, err = keys.NewKeyring(keyringServiceName, "test", tmpDir, buf) + keybase, err = keyring.NewKeyring(keyringServiceName, "test", tmpDir, buf) } else { - keybase, err = keys.NewKeyring(keyringServiceName, viper.GetString(flags.FlagKeyringBackend), rootDir, buf) + keybase, err = keyring.NewKeyring(keyringServiceName, viper.GetString(flags.FlagKeyringBackend), rootDir, buf) } if err != nil { return errors.Wrap(err, fmt.Sprintf( @@ -107,7 +107,7 @@ func runMigrateCmd(cmd *cobra.Command, args []string) error { continue } - if keyType != keys.TypeLocal { + if keyType != keyring.TypeLocal { if err := keybase.Import(keyName, legKeyInfo); err != nil { return err } diff --git a/client/keys/root_test.go b/client/keys/root_test.go index 50bb3a5975c1..daafecf7b9fa 100644 --- a/client/keys/root_test.go +++ b/client/keys/root_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/crypto/keys" + "github.com/cosmos/cosmos-sdk/crypto/keyring" ) func TestCommands(t *testing.T) { @@ -20,6 +20,6 @@ func TestCommands(t *testing.T) { } func TestMain(m *testing.M) { - viper.Set(flags.FlagKeyringBackend, keys.BackendTest) + viper.Set(flags.FlagKeyringBackend, keyring.BackendTest) os.Exit(m.Run()) } diff --git a/client/keys/show.go b/client/keys/show.go index c959ff157750..f4e6cc1fbe5d 100644 --- a/client/keys/show.go +++ b/client/keys/show.go @@ -13,7 +13,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/crypto" - "github.com/cosmos/cosmos-sdk/crypto/keys" + "github.com/cosmos/cosmos-sdk/crypto/keyring" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -55,9 +55,9 @@ consisting of all the keys provided by name and multisig threshold.`, } func runShowCmd(cmd *cobra.Command, args []string) (err error) { - var info keys.Info + var info keyring.Info - kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), cmd.InOrStdin()) + kb, err := keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), cmd.InOrStdin()) if err != nil { return err } @@ -84,7 +84,7 @@ func runShowCmd(cmd *cobra.Command, args []string) (err error) { } multikey := multisig.NewPubKeyMultisigThreshold(multisigThreshold, pks) - info = keys.NewMultiInfo(defaultMultiSigKeyName, multikey) + info = keyring.NewMultiInfo(defaultMultiSigKeyName, multikey) } isShowAddr := viper.GetBool(FlagAddress) @@ -127,7 +127,7 @@ func runShowCmd(cmd *cobra.Command, args []string) (err error) { return fmt.Errorf("the device flag (-d) can only be used for accounts") } // Override and show in the device - if info.GetType() != keys.TypeLedger { + if info.GetType() != keyring.TypeLedger { return fmt.Errorf("the device flag (-d) can only be used for accounts stored in devices") } @@ -156,11 +156,11 @@ func validateMultisigThreshold(k, nKeys int) error { func getBechKeyOut(bechPrefix string) (bechKeyOutFn, error) { switch bechPrefix { case sdk.PrefixAccount: - return keys.Bech32KeyOutput, nil + return keyring.Bech32KeyOutput, nil case sdk.PrefixValidator: - return keys.Bech32ValKeyOutput, nil + return keyring.Bech32ValKeyOutput, nil case sdk.PrefixConsensus: - return keys.Bech32ConsKeyOutput, nil + return keyring.Bech32ConsKeyOutput, nil } return nil, fmt.Errorf("invalid Bech32 prefix encoding provided: %s", bechPrefix) diff --git a/client/keys/show_test.go b/client/keys/show_test.go index 80bb86505928..f7b35cb3d3e0 100644 --- a/client/keys/show_test.go +++ b/client/keys/show_test.go @@ -11,7 +11,7 @@ import ( "github.com/tendermint/tendermint/crypto/secp256k1" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/crypto/keys" + "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/tests" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -19,10 +19,10 @@ import ( func Test_multiSigKey_Properties(t *testing.T) { tmpKey1 := secp256k1.GenPrivKeySecp256k1([]byte("mySecret")) pk := multisig.NewPubKeyMultisigThreshold(1, []crypto.PubKey{tmpKey1.PubKey()}) - tmp := keys.NewMultiInfo("myMultisig", pk) + tmp := keyring.NewMultiInfo("myMultisig", pk) require.Equal(t, "myMultisig", tmp.GetName()) - require.Equal(t, keys.TypeMulti, tmp.GetType()) + require.Equal(t, keyring.TypeMulti, tmp.GetType()) require.Equal(t, "D3923267FA8A3DD367BB768FA8BDC8FF7F89DA3F", tmp.GetPubKey().Address().String()) require.Equal(t, "cosmos16wfryel63g7axeamw68630wglalcnk3l0zuadc", tmp.GetAddress().String()) } @@ -49,7 +49,7 @@ func Test_runShowCmd(t *testing.T) { fakeKeyName1 := "runShowCmd_Key1" fakeKeyName2 := "runShowCmd_Key2" - kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) + kb, err := keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) require.NoError(t, err) t.Cleanup(func() { kb.Delete("runShowCmd_Key1", "", false) @@ -58,13 +58,13 @@ func Test_runShowCmd(t *testing.T) { if runningUnattended { mockIn.Reset("testpass1\ntestpass1\n") } - _, err = kb.CreateAccount(fakeKeyName1, tests.TestMnemonic, "", "", "0", keys.Secp256k1) + _, err = kb.CreateAccount(fakeKeyName1, tests.TestMnemonic, "", "", "0", keyring.Secp256k1) require.NoError(t, err) if runningUnattended { mockIn.Reset("testpass1\n") } - _, err = kb.CreateAccount(fakeKeyName2, tests.TestMnemonic, "", "", "1", keys.Secp256k1) + _, err = kb.CreateAccount(fakeKeyName2, tests.TestMnemonic, "", "", "1", keyring.Secp256k1) require.NoError(t, err) // Now try single key @@ -161,9 +161,9 @@ func Test_getBechKeyOut(t *testing.T) { }{ {"empty", args{""}, nil, true}, {"wrong", args{"???"}, nil, true}, - {"acc", args{sdk.PrefixAccount}, keys.Bech32KeyOutput, false}, - {"val", args{sdk.PrefixValidator}, keys.Bech32ValKeyOutput, false}, - {"cons", args{sdk.PrefixConsensus}, keys.Bech32ConsKeyOutput, false}, + {"acc", args{sdk.PrefixAccount}, keyring.Bech32KeyOutput, false}, + {"val", args{sdk.PrefixValidator}, keyring.Bech32ValKeyOutput, false}, + {"cons", args{sdk.PrefixConsensus}, keyring.Bech32ConsKeyOutput, false}, } for _, tt := range tests { tt := tt diff --git a/client/keys/types.go b/client/keys/types.go index 079ef4962d24..129d26e29823 100644 --- a/client/keys/types.go +++ b/client/keys/types.go @@ -1,6 +1,6 @@ package keys -// used for outputting keys.Info over REST +// used for outputting keyring.Info over REST // AddNewKey request a new key type AddNewKey struct { diff --git a/client/keys/update_test.go b/client/keys/update_test.go index d763e9e7646d..2c951b7c31f1 100644 --- a/client/keys/update_test.go +++ b/client/keys/update_test.go @@ -1,18 +1,20 @@ package keys import ( + "errors" "testing" "github.com/spf13/viper" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/crypto/keys" + "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/tests" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) func Test_updateKeyCommand(t *testing.T) { - assert.NotNil(t, UpdateKeyCommand()) + require.NotNil(t, UpdateKeyCommand()) // No flags or defaults to validate } @@ -23,12 +25,15 @@ func Test_runUpdateCmd(t *testing.T) { cmd := UpdateKeyCommand() // fails because it requests a password - assert.EqualError(t, runUpdateCmd(cmd, []string{fakeKeyName1}), "EOF") + err := runUpdateCmd(cmd, []string{fakeKeyName1}) + + require.EqualError(t, err, "EOF") // try again mockIn, _, _ := tests.ApplyMockIO(cmd) mockIn.Reset("pass1234\n") - assert.EqualError(t, runUpdateCmd(cmd, []string{fakeKeyName1}), "Key runUpdateCmd_Key1 not found") + err = runUpdateCmd(cmd, []string{fakeKeyName1}) + require.True(t, errors.Is(err, sdkerrors.ErrKeyNotFound)) // Prepare a key base // Now add a temporary keybase @@ -37,17 +42,17 @@ func Test_runUpdateCmd(t *testing.T) { viper.Set(flags.FlagHome, kbHome) kb, err := NewKeyBaseFromDir(viper.GetString(flags.FlagHome)) - assert.NoError(t, err) - _, err = kb.CreateAccount(fakeKeyName1, tests.TestMnemonic, "", "", "0", keys.Secp256k1) - assert.NoError(t, err) - _, err = kb.CreateAccount(fakeKeyName2, tests.TestMnemonic, "", "", "1", keys.Secp256k1) - assert.NoError(t, err) + require.NoError(t, err) + _, err = kb.CreateAccount(fakeKeyName1, tests.TestMnemonic, "", "", "0", keyring.Secp256k1) + require.NoError(t, err) + _, err = kb.CreateAccount(fakeKeyName2, tests.TestMnemonic, "", "", "1", keyring.Secp256k1) + require.NoError(t, err) // Try again now that we have keys // Incorrect key type mockIn.Reset("pass1234\nNew1234\nNew1234") err = runUpdateCmd(cmd, []string{fakeKeyName1}) - assert.EqualError(t, err, "locally stored key required. Received: keys.offlineInfo") + require.EqualError(t, err, "locally stored key required. Received: keyring.offlineInfo") // TODO: Check for other type types? } diff --git a/client/keys/utils.go b/client/keys/utils.go index 008d3ccf7822..a6dc78ecb183 100644 --- a/client/keys/utils.go +++ b/client/keys/utils.go @@ -7,10 +7,10 @@ import ( "github.com/99designs/keyring" "github.com/spf13/viper" "github.com/tendermint/tendermint/libs/cli" - "gopkg.in/yaml.v2" + yaml "gopkg.in/yaml.v2" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/crypto/keys" + cryptokeyring "github.com/cosmos/cosmos-sdk/crypto/keyring" ) // available output formats. @@ -22,22 +22,22 @@ const ( defaultKeyDBName = "keys" ) -type bechKeyOutFn func(keyInfo keys.Info) (keys.KeyOutput, error) +type bechKeyOutFn func(keyInfo cryptokeyring.Info) (cryptokeyring.KeyOutput, error) // NewKeyBaseFromDir initializes a keybase at the rootDir directory. Keybase // options can be applied when generating this new Keybase. -func NewKeyBaseFromDir(rootDir string, opts ...keys.KeybaseOption) (keys.Keybase, error) { +func NewKeyBaseFromDir(rootDir string, opts ...cryptokeyring.KeybaseOption) (cryptokeyring.Keybase, error) { return getLazyKeyBaseFromDir(rootDir, opts...) } // NewInMemoryKeyBase returns a storage-less keybase. -func NewInMemoryKeyBase() keys.Keybase { return keys.NewInMemory() } +func NewInMemoryKeyBase() cryptokeyring.Keybase { return cryptokeyring.NewInMemory() } -func getLazyKeyBaseFromDir(rootDir string, opts ...keys.KeybaseOption) (keys.Keybase, error) { - return keys.New(defaultKeyDBName, filepath.Join(rootDir, "keys"), opts...), nil +func getLazyKeyBaseFromDir(rootDir string, opts ...cryptokeyring.KeybaseOption) (cryptokeyring.Keybase, error) { + return cryptokeyring.New(defaultKeyDBName, filepath.Join(rootDir, "keys"), opts...), nil } -func printKeyInfo(keyInfo keys.Info, bechKeyOut bechKeyOutFn) { +func printKeyInfo(keyInfo cryptokeyring.Info, bechKeyOut bechKeyOutFn) { ko, err := bechKeyOut(keyInfo) if err != nil { panic(err) @@ -45,7 +45,7 @@ func printKeyInfo(keyInfo keys.Info, bechKeyOut bechKeyOutFn) { switch viper.Get(cli.OutputFlag) { case OutputFormatText: - printTextInfos([]keys.KeyOutput{ko}) + printTextInfos([]cryptokeyring.KeyOutput{ko}) case OutputFormatJSON: var out []byte @@ -63,8 +63,8 @@ func printKeyInfo(keyInfo keys.Info, bechKeyOut bechKeyOutFn) { } } -func printInfos(infos []keys.Info) { - kos, err := keys.Bech32KeysOutput(infos) +func printInfos(infos []cryptokeyring.Info) { + kos, err := cryptokeyring.Bech32KeysOutput(infos) if err != nil { panic(err) } @@ -90,7 +90,7 @@ func printInfos(infos []keys.Info) { } } -func printTextInfos(kos []keys.KeyOutput) { +func printTextInfos(kos []cryptokeyring.KeyOutput) { out, err := yaml.Marshal(&kos) if err != nil { panic(err) @@ -98,7 +98,7 @@ func printTextInfos(kos []keys.KeyOutput) { fmt.Println(string(out)) } -func printKeyAddress(info keys.Info, bechKeyOut bechKeyOutFn) { +func printKeyAddress(info cryptokeyring.Info, bechKeyOut bechKeyOutFn) { ko, err := bechKeyOut(info) if err != nil { panic(err) @@ -107,7 +107,7 @@ func printKeyAddress(info keys.Info, bechKeyOut bechKeyOutFn) { fmt.Println(ko.Address) } -func printPubKey(info keys.Info, bechKeyOut bechKeyOutFn) { +func printPubKey(info cryptokeyring.Info, bechKeyOut bechKeyOutFn) { ko, err := bechKeyOut(info) if err != nil { panic(err) diff --git a/crypto/keys/keybase_base.go b/crypto/keyring/base_keybase.go similarity index 83% rename from crypto/keys/keybase_base.go rename to crypto/keyring/base_keybase.go index 2947949e273b..c2f7952b820a 100644 --- a/crypto/keys/keybase_base.go +++ b/crypto/keyring/base_keybase.go @@ -1,24 +1,18 @@ -package keys +package keyring import ( - "github.com/cosmos/go-bip39" "github.com/pkg/errors" + tmcrypto "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/secp256k1" "github.com/cosmos/cosmos-sdk/crypto" "github.com/cosmos/cosmos-sdk/crypto/keys/hd" "github.com/cosmos/cosmos-sdk/types" + bip39 "github.com/cosmos/go-bip39" ) type ( - kbOptions struct { - keygenFunc PrivKeyGenFunc - deriveFunc DeriveKeyFunc - supportedAlgos []SigningAlgo - supportedAlgosLedger []SigningAlgo - } - // baseKeybase is an auxiliary type that groups Keybase storage agnostic features // together. baseKeybase struct { @@ -39,34 +33,6 @@ type ( } ) -// WithKeygenFunc applies an overridden key generation function to generate the private key. -func WithKeygenFunc(f PrivKeyGenFunc) KeybaseOption { - return func(o *kbOptions) { - o.keygenFunc = f - } -} - -// WithDeriveFunc applies an overridden key derivation function to generate the private key. -func WithDeriveFunc(f DeriveKeyFunc) KeybaseOption { - return func(o *kbOptions) { - o.deriveFunc = f - } -} - -// WithSupportedAlgos defines the list of accepted SigningAlgos. -func WithSupportedAlgos(algos []SigningAlgo) KeybaseOption { - return func(o *kbOptions) { - o.supportedAlgos = algos - } -} - -// WithSupportedAlgosLedger defines the list of accepted SigningAlgos compatible with Ledger. -func WithSupportedAlgosLedger(algos []SigningAlgo) KeybaseOption { - return func(o *kbOptions) { - o.supportedAlgosLedger = algos - } -} - // newBaseKeybase generates the base keybase with defaulting to tendermint SECP256K1 key type func newBaseKeybase(optionsFns ...KeybaseOption) baseKeybase { // Default options for keybase @@ -238,16 +204,6 @@ func (kb baseKeybase) SupportedAlgosLedger() []SigningAlgo { return kb.options.supportedAlgosLedger } -// IsSupportedAlgorithm returns whether the signing algorithm is in the passed-in list of supported algorithms. -func IsSupportedAlgorithm(supported []SigningAlgo, algo SigningAlgo) bool { - for _, supportedAlgo := range supported { - if algo == supportedAlgo { - return true - } - } - return false -} - // SignWithLedger signs a binary message with the ledger device referenced by an Info object // and returns the signed bytes and the public key. It returns an error if the device could // not be queried or it returned an error. diff --git a/crypto/keys/codec.go b/crypto/keyring/codec.go similarity index 98% rename from crypto/keys/codec.go rename to crypto/keyring/codec.go index c3b3e76a3a8b..a8cd37d13fe4 100644 --- a/crypto/keys/codec.go +++ b/crypto/keyring/codec.go @@ -1,4 +1,4 @@ -package keys +package keyring import ( cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino" diff --git a/crypto/keys/keybase.go b/crypto/keyring/db_keybase.go similarity index 88% rename from crypto/keys/keybase.go rename to crypto/keyring/db_keybase.go index 268778b0e947..e1513b38e08a 100644 --- a/crypto/keys/keybase.go +++ b/crypto/keyring/db_keybase.go @@ -1,4 +1,4 @@ -package keys +package keyring import ( "fmt" @@ -10,59 +10,13 @@ import ( cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino" dbm "github.com/tendermint/tm-db" - "github.com/cosmos/cosmos-sdk/crypto/keys/keyerror" "github.com/cosmos/cosmos-sdk/crypto/keys/mintkey" "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) var _ Keybase = dbKeybase{} -// Language is a language to create the BIP 39 mnemonic in. -// Currently, only english is supported though. -// Find a list of all supported languages in the BIP 39 spec (word lists). -type Language int - -//noinspection ALL -const ( - // English is the default language to create a mnemonic. - // It is the only supported language by this package. - English Language = iota + 1 - // Japanese is currently not supported. - Japanese - // Korean is currently not supported. - Korean - // Spanish is currently not supported. - Spanish - // ChineseSimplified is currently not supported. - ChineseSimplified - // ChineseTraditional is currently not supported. - ChineseTraditional - // French is currently not supported. - French - // Italian is currently not supported. - Italian - addressSuffix = "address" - infoSuffix = "info" -) - -const ( - // used for deriving seed from mnemonic - DefaultBIP39Passphrase = "" - - // bits of entropy to draw when creating a mnemonic - defaultEntropySize = 256 -) - -var ( - // ErrUnsupportedSigningAlgo is raised when the caller tries to use a - // different signing scheme than secp256k1. - ErrUnsupportedSigningAlgo = errors.New("unsupported signing algo") - - // ErrUnsupportedLanguage is raised when the caller tries to use a - // different language than english for creating a mnemonic sentence. - ErrUnsupportedLanguage = errors.New("unsupported language: only english is supported") -) - // dbKeybase combines encryption and storage implementation to provide a // full-featured key manager. // @@ -163,7 +117,7 @@ func (kb dbKeybase) Get(name string) (Info, error) { } if len(bs) == 0 { - return nil, keyerror.NewErrKeyNotFound(name) + return nil, sdkerrors.Wrap(sdkerrors.ErrKeyNotFound, name) } return unmarshalInfo(bs) diff --git a/crypto/keys/doc.go b/crypto/keyring/doc.go similarity index 99% rename from crypto/keys/doc.go rename to crypto/keyring/doc.go index 30a086941810..7b09f25ac5e8 100644 --- a/crypto/keys/doc.go +++ b/crypto/keyring/doc.go @@ -42,4 +42,4 @@ // https://www.passwordstore.org/ // test This backend stores keys insecurely to disk. It does not prompt for a password to // be unlocked and it should be use only for testing purposes. -package keys +package keyring diff --git a/crypto/keyring/errors.go b/crypto/keyring/errors.go new file mode 100644 index 000000000000..4ec6d2e465fc --- /dev/null +++ b/crypto/keyring/errors.go @@ -0,0 +1,13 @@ +package keyring + +import "github.com/pkg/errors" + +var ( + // ErrUnsupportedSigningAlgo is raised when the caller tries to use a + // different signing scheme than secp256k1. + ErrUnsupportedSigningAlgo = errors.New("unsupported signing algo") + + // ErrUnsupportedLanguage is raised when the caller tries to use a + // different language than english for creating a mnemonic sentence. + ErrUnsupportedLanguage = errors.New("unsupported language: only english is supported") +) diff --git a/crypto/keys/types.go b/crypto/keyring/info.go similarity index 57% rename from crypto/keys/types.go rename to crypto/keyring/info.go index 5149d1c582a0..b9df095a9733 100644 --- a/crypto/keys/types.go +++ b/crypto/keyring/info.go @@ -1,4 +1,4 @@ -package keys +package keyring import ( "fmt" @@ -10,101 +10,6 @@ import ( "github.com/cosmos/cosmos-sdk/types" ) -// Keybase exposes operations on a generic keystore -type Keybase interface { - // CRUD on the keystore - List() ([]Info, error) - // Get returns the public information about one key. - Get(name string) (Info, error) - // Get performs a by-address lookup and returns the public - // information about one key if there's any. - GetByAddress(address types.AccAddress) (Info, error) - // Delete removes a key. - Delete(name, passphrase string, skipPass bool) error - // Sign bytes, looking up the private key to use. - Sign(name, passphrase string, msg []byte) ([]byte, crypto.PubKey, error) - - // CreateMnemonic generates a new mnemonic, derives a hierarchical deterministic - // key from that. and persists it to storage, encrypted using the provided password. - // It returns the generated mnemonic and the key Info. It returns an error if it fails to - // generate a key for the given algo type, or if another key is already stored under the - // same name. - CreateMnemonic(name string, language Language, passwd string, algo SigningAlgo) (info Info, seed string, err error) - - // CreateAccount converts a mnemonic to a private key and BIP 32 HD Path - // and persists it, encrypted with the given password. - CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd, hdPath string, algo SigningAlgo) (Info, error) - - // CreateLedger creates, stores, and returns a new Ledger key reference - CreateLedger(name string, algo SigningAlgo, hrp string, account, index uint32) (info Info, err error) - - // CreateOffline creates, stores, and returns a new offline key reference - CreateOffline(name string, pubkey crypto.PubKey, algo SigningAlgo) (info Info, err error) - - // CreateMulti creates, stores, and returns a new multsig (offline) key reference - CreateMulti(name string, pubkey crypto.PubKey) (info Info, err error) - - // The following operations will *only* work on locally-stored keys - Update(name, oldpass string, getNewpass func() (string, error)) error - - // Import imports ASCII armored Info objects. - Import(name string, armor string) (err error) - - // ImportPrivKey imports a private key in ASCII armor format. - // It returns an error if a key with the same name exists or a wrong encryption passphrase is - // supplied. - ImportPrivKey(name, armor, passphrase string) error - - // ImportPubKey imports ASCII-armored public keys. - // Store a new Info object holding a public key only, i.e. it will - // not be possible to sign with it as it lacks the secret key. - ImportPubKey(name string, armor string) (err error) - - // Export exports an Info object in ASCII armored format. - Export(name string) (armor string, err error) - - // ExportPubKey returns public keys in ASCII armored format. - // Retrieve a Info object by its name and return the public key in - // a portable format. - ExportPubKey(name string) (armor string, err error) - - // ExportPrivKey returns a private key in ASCII armored format. - // It returns an error if the key does not exist or a wrong encryption passphrase is supplied. - ExportPrivKey(name, decryptPassphrase, encryptPassphrase string) (armor string, err error) - - // ExportPrivateKeyObject *only* works on locally-stored keys. Temporary method until we redo the exporting API - ExportPrivateKeyObject(name string, passphrase string) (crypto.PrivKey, error) - - // SupportedAlgos returns a list of signing algorithms supported by the keybase - SupportedAlgos() []SigningAlgo - - // SupportedAlgosLedger returns a list of signing algorithms supported by the keybase's ledger integration - SupportedAlgosLedger() []SigningAlgo -} - -// KeyType reflects a human-readable type for key listing. -type KeyType uint - -// Info KeyTypes -const ( - TypeLocal KeyType = 0 - TypeLedger KeyType = 1 - TypeOffline KeyType = 2 - TypeMulti KeyType = 3 -) - -var keyTypes = map[KeyType]string{ - TypeLocal: "local", - TypeLedger: "ledger", - TypeOffline: "offline", - TypeMulti: "multi", -} - -// String implements the stringer interface for KeyType. -func (kt KeyType) String() string { - return keyTypes[kt] -} - // Info is the publicly exposed information about a keypair type Info interface { // Human-readable type for key listing @@ -342,13 +247,3 @@ func unmarshalInfo(bz []byte) (info Info, err error) { err = CryptoCdc.UnmarshalBinaryLengthPrefixed(bz, &info) return } - -type ( - // DeriveKeyFunc defines the function to derive a new key from a seed and hd path - DeriveKeyFunc func(mnemonic string, bip39Passphrase, hdPath string, algo SigningAlgo) ([]byte, error) - // PrivKeyGenFunc defines the function to convert derived key bytes to a tendermint private key - PrivKeyGenFunc func(bz []byte, algo SigningAlgo) (crypto.PrivKey, error) - - // KeybaseOption overrides options for the db - KeybaseOption func(*kbOptions) -) diff --git a/crypto/keyring/keybase.go b/crypto/keyring/keybase.go new file mode 100644 index 000000000000..b2f619aff3e6 --- /dev/null +++ b/crypto/keyring/keybase.go @@ -0,0 +1,79 @@ +package keyring + +import ( + "github.com/tendermint/tendermint/crypto" + + "github.com/cosmos/cosmos-sdk/types" +) + +// Keybase exposes operations on a generic keystore +type Keybase interface { + // CRUD on the keystore + List() ([]Info, error) + // Get returns the public information about one key. + Get(name string) (Info, error) + // Get performs a by-address lookup and returns the public + // information about one key if there's any. + GetByAddress(address types.AccAddress) (Info, error) + // Delete removes a key. + Delete(name, passphrase string, skipPass bool) error + // Sign bytes, looking up the private key to use. + Sign(name, passphrase string, msg []byte) ([]byte, crypto.PubKey, error) + + // CreateMnemonic generates a new mnemonic, derives a hierarchical deterministic + // key from that. and persists it to storage, encrypted using the provided password. + // It returns the generated mnemonic and the key Info. It returns an error if it fails to + // generate a key for the given algo type, or if another key is already stored under the + // same name. + CreateMnemonic(name string, language Language, passwd string, algo SigningAlgo) (info Info, seed string, err error) + + // CreateAccount converts a mnemonic to a private key and BIP 32 HD Path + // and persists it, encrypted with the given password. + CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd, hdPath string, algo SigningAlgo) (Info, error) + + // CreateLedger creates, stores, and returns a new Ledger key reference + CreateLedger(name string, algo SigningAlgo, hrp string, account, index uint32) (info Info, err error) + + // CreateOffline creates, stores, and returns a new offline key reference + CreateOffline(name string, pubkey crypto.PubKey, algo SigningAlgo) (info Info, err error) + + // CreateMulti creates, stores, and returns a new multsig (offline) key reference + CreateMulti(name string, pubkey crypto.PubKey) (info Info, err error) + + // The following operations will *only* work on locally-stored keys + Update(name, oldpass string, getNewpass func() (string, error)) error + + // Import imports ASCII armored Info objects. + Import(name string, armor string) (err error) + + // ImportPrivKey imports a private key in ASCII armor format. + // It returns an error if a key with the same name exists or a wrong encryption passphrase is + // supplied. + ImportPrivKey(name, armor, passphrase string) error + + // ImportPubKey imports ASCII-armored public keys. + // Store a new Info object holding a public key only, i.e. it will + // not be possible to sign with it as it lacks the secret key. + ImportPubKey(name string, armor string) (err error) + + // Export exports an Info object in ASCII armored format. + Export(name string) (armor string, err error) + + // ExportPubKey returns public keys in ASCII armored format. + // Retrieve a Info object by its name and return the public key in + // a portable format. + ExportPubKey(name string) (armor string, err error) + + // ExportPrivKey returns a private key in ASCII armored format. + // It returns an error if the key does not exist or a wrong encryption passphrase is supplied. + ExportPrivKey(name, decryptPassphrase, encryptPassphrase string) (armor string, err error) + + // ExportPrivateKeyObject *only* works on locally-stored keys. Temporary method until we redo the exporting API + ExportPrivateKeyObject(name string, passphrase string) (crypto.PrivKey, error) + + // SupportedAlgos returns a list of signing algorithms supported by the keybase + SupportedAlgos() []SigningAlgo + + // SupportedAlgosLedger returns a list of signing algorithms supported by the keybase's ledger integration + SupportedAlgosLedger() []SigningAlgo +} diff --git a/crypto/keys/keybase_test.go b/crypto/keyring/keybase_test.go similarity index 99% rename from crypto/keys/keybase_test.go rename to crypto/keyring/keybase_test.go index eabce8f07df0..cc96a7c37a9d 100644 --- a/crypto/keys/keybase_test.go +++ b/crypto/keyring/keybase_test.go @@ -1,5 +1,4 @@ -//nolint: goconst -package keys +package keyring import ( "fmt" diff --git a/crypto/keys/keyring.go b/crypto/keyring/keyring.go similarity index 98% rename from crypto/keys/keyring.go rename to crypto/keyring/keyring.go index ff2516afeea5..3db8c3d433a9 100644 --- a/crypto/keys/keyring.go +++ b/crypto/keyring/keyring.go @@ -1,4 +1,4 @@ -package keys +package keyring import ( "bufio" @@ -18,9 +18,9 @@ import ( cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino" "github.com/cosmos/cosmos-sdk/client/input" - "github.com/cosmos/cosmos-sdk/crypto/keys/keyerror" "github.com/cosmos/cosmos-sdk/crypto/keys/mintkey" "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) const ( @@ -145,7 +145,7 @@ func (kb keyringKeybase) List() ([]Info, error) { } if len(rawInfo.Data) == 0 { - return nil, keyerror.NewErrKeyNotFound(key) + return nil, sdkerrors.Wrap(sdkerrors.ErrKeyNotFound, key) } info, err := unmarshalInfo(rawInfo.Data) @@ -170,7 +170,7 @@ func (kb keyringKeybase) Get(name string) (Info, error) { } if len(bs.Data) == 0 { - return nil, keyerror.NewErrKeyNotFound(name) + return nil, sdkerrors.Wrap(sdkerrors.ErrKeyNotFound, name) } return unmarshalInfo(bs.Data) diff --git a/crypto/keys/keyring_test.go b/crypto/keyring/keyring_test.go similarity index 99% rename from crypto/keys/keyring_test.go rename to crypto/keyring/keyring_test.go index 072c07acdf9f..c4c3ee301423 100644 --- a/crypto/keys/keyring_test.go +++ b/crypto/keyring/keyring_test.go @@ -1,5 +1,4 @@ -// nolint: goconst -package keys +package keyring import ( "bytes" diff --git a/crypto/keys/keys.toml b/crypto/keyring/keys.toml similarity index 100% rename from crypto/keys/keys.toml rename to crypto/keyring/keys.toml diff --git a/crypto/keys/lazy_keybase.go b/crypto/keyring/lazy_keybase.go similarity index 99% rename from crypto/keys/lazy_keybase.go rename to crypto/keyring/lazy_keybase.go index 3ee7e2c16b2b..c2b5aa972cf3 100644 --- a/crypto/keys/lazy_keybase.go +++ b/crypto/keyring/lazy_keybase.go @@ -1,4 +1,4 @@ -package keys +package keyring import ( "fmt" diff --git a/crypto/keys/lazy_keybase_test.go b/crypto/keyring/lazy_keybase_test.go similarity index 99% rename from crypto/keys/lazy_keybase_test.go rename to crypto/keyring/lazy_keybase_test.go index cf61e67702d6..d639f500c327 100644 --- a/crypto/keys/lazy_keybase_test.go +++ b/crypto/keyring/lazy_keybase_test.go @@ -1,4 +1,4 @@ -package keys +package keyring import ( "testing" diff --git a/crypto/keyring/options.go b/crypto/keyring/options.go new file mode 100644 index 000000000000..21e69398f002 --- /dev/null +++ b/crypto/keyring/options.go @@ -0,0 +1,39 @@ +package keyring + +// KeybaseOption overrides options for the db +type KeybaseOption func(*kbOptions) + +type kbOptions struct { + keygenFunc PrivKeyGenFunc + deriveFunc DeriveKeyFunc + supportedAlgos []SigningAlgo + supportedAlgosLedger []SigningAlgo +} + +// WithKeygenFunc applies an overridden key generation function to generate the private key. +func WithKeygenFunc(f PrivKeyGenFunc) KeybaseOption { + return func(o *kbOptions) { + o.keygenFunc = f + } +} + +// WithDeriveFunc applies an overridden key derivation function to generate the private key. +func WithDeriveFunc(f DeriveKeyFunc) KeybaseOption { + return func(o *kbOptions) { + o.deriveFunc = f + } +} + +// WithSupportedAlgos defines the list of accepted SigningAlgos. +func WithSupportedAlgos(algos []SigningAlgo) KeybaseOption { + return func(o *kbOptions) { + o.supportedAlgos = algos + } +} + +// WithSupportedAlgosLedger defines the list of accepted SigningAlgos compatible with Ledger. +func WithSupportedAlgosLedger(algos []SigningAlgo) KeybaseOption { + return func(o *kbOptions) { + o.supportedAlgosLedger = algos + } +} diff --git a/crypto/keys/output.go b/crypto/keyring/output.go similarity index 99% rename from crypto/keys/output.go rename to crypto/keyring/output.go index 6c911f46cebe..5f76789caadf 100644 --- a/crypto/keys/output.go +++ b/crypto/keyring/output.go @@ -1,4 +1,4 @@ -package keys +package keyring import ( sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/crypto/keys/output_test.go b/crypto/keyring/output_test.go similarity index 98% rename from crypto/keys/output_test.go rename to crypto/keyring/output_test.go index d6091c190e85..89f2b188fa7e 100644 --- a/crypto/keys/output_test.go +++ b/crypto/keyring/output_test.go @@ -1,4 +1,4 @@ -package keys +package keyring import ( "testing" diff --git a/crypto/keys/keys.go b/crypto/keyring/signing_algorithms.go similarity index 64% rename from crypto/keys/keys.go rename to crypto/keyring/signing_algorithms.go index af5590814b49..12e000aeb9dd 100644 --- a/crypto/keys/keys.go +++ b/crypto/keyring/signing_algorithms.go @@ -1,4 +1,4 @@ -package keys +package keyring // SigningAlgo defines an algorithm to derive key-pairs which can be used for cryptographic signing. type SigningAlgo string @@ -14,3 +14,13 @@ const ( // Sr25519 represents the Sr25519 signature system. Sr25519 = SigningAlgo("sr25519") ) + +// IsSupportedAlgorithm returns whether the signing algorithm is in the passed-in list of supported algorithms. +func IsSupportedAlgorithm(supported []SigningAlgo, algo SigningAlgo) bool { + for _, supportedAlgo := range supported { + if algo == supportedAlgo { + return true + } + } + return false +} diff --git a/crypto/keyring/types.go b/crypto/keyring/types.go new file mode 100644 index 000000000000..fadf47ad588a --- /dev/null +++ b/crypto/keyring/types.go @@ -0,0 +1,68 @@ +package keyring + +import "github.com/tendermint/tendermint/crypto" + +// Language is a language to create the BIP 39 mnemonic in. +// Currently, only english is supported though. +// Find a list of all supported languages in the BIP 39 spec (word lists). +type Language int + +const ( + // English is the default language to create a mnemonic. + // It is the only supported language by this package. + English Language = iota + 1 + // Japanese is currently not supported. + Japanese + // Korean is currently not supported. + Korean + // Spanish is currently not supported. + Spanish + // ChineseSimplified is currently not supported. + ChineseSimplified + // ChineseTraditional is currently not supported. + ChineseTraditional + // French is currently not supported. + French + // Italian is currently not supported. + Italian +) + +const ( + // DefaultBIP39Passphrase used for deriving seed from mnemonic + DefaultBIP39Passphrase = "" + + // bits of entropy to draw when creating a mnemonic + defaultEntropySize = 256 + addressSuffix = "address" + infoSuffix = "info" +) + +// KeyType reflects a human-readable type for key listing. +type KeyType uint + +// Info KeyTypes +const ( + TypeLocal KeyType = 0 + TypeLedger KeyType = 1 + TypeOffline KeyType = 2 + TypeMulti KeyType = 3 +) + +var keyTypes = map[KeyType]string{ + TypeLocal: "local", + TypeLedger: "ledger", + TypeOffline: "offline", + TypeMulti: "multi", +} + +// String implements the stringer interface for KeyType. +func (kt KeyType) String() string { + return keyTypes[kt] +} + +type ( + // DeriveKeyFunc defines the function to derive a new key from a seed and hd path + DeriveKeyFunc func(mnemonic string, bip39Passphrase, hdPath string, algo SigningAlgo) ([]byte, error) + // PrivKeyGenFunc defines the function to convert derived key bytes to a tendermint private key + PrivKeyGenFunc func(bz []byte, algo SigningAlgo) (crypto.PrivKey, error) +) diff --git a/crypto/keys/types_test.go b/crypto/keyring/types_test.go similarity index 98% rename from crypto/keys/types_test.go rename to crypto/keyring/types_test.go index 3c18f4cf10ad..c2cb9723c2c7 100644 --- a/crypto/keys/types_test.go +++ b/crypto/keyring/types_test.go @@ -1,4 +1,4 @@ -package keys +package keyring import ( "encoding/hex" diff --git a/crypto/keys/keyerror/errors.go b/crypto/keys/keyerror/errors.go deleted file mode 100644 index 5b3a9a7b1f38..000000000000 --- a/crypto/keys/keyerror/errors.go +++ /dev/null @@ -1,81 +0,0 @@ -package keyerror - -import ( - "fmt" -) - -const ( - codeKeyNotFound = 1 - codeWrongPassword = 2 -) - -type keybaseError interface { - error - Code() int -} - -type errKeyNotFound struct { - code int - name string -} - -func (e errKeyNotFound) Code() int { - return e.code -} - -func (e errKeyNotFound) Error() string { - return fmt.Sprintf("Key %s not found", e.name) -} - -// NewErrKeyNotFound returns a standardized error reflecting that the specified key doesn't exist -func NewErrKeyNotFound(name string) error { - return errKeyNotFound{ - code: codeKeyNotFound, - name: name, - } -} - -// IsErrKeyNotFound returns true if the given error is errKeyNotFound -func IsErrKeyNotFound(err error) bool { - if err == nil { - return false - } - if keyErr, ok := err.(keybaseError); ok { - if keyErr.Code() == codeKeyNotFound { - return true - } - } - return false -} - -type errWrongPassword struct { - code int -} - -func (e errWrongPassword) Code() int { - return e.code -} - -func (e errWrongPassword) Error() string { - return "invalid account password" -} - -// NewErrWrongPassword returns a standardized error reflecting that the specified password is wrong -func NewErrWrongPassword() error { - return errWrongPassword{ - code: codeWrongPassword, - } -} - -// IsErrWrongPassword returns true if the given error is errWrongPassword -func IsErrWrongPassword(err error) bool { - if err == nil { - return false - } - if keyErr, ok := err.(keybaseError); ok { - if keyErr.Code() == codeWrongPassword { - return true - } - } - return false -} diff --git a/crypto/keys/keyerror/errors_test.go b/crypto/keys/keyerror/errors_test.go deleted file mode 100644 index 80aaf9a69b9f..000000000000 --- a/crypto/keys/keyerror/errors_test.go +++ /dev/null @@ -1,24 +0,0 @@ -package keyerror_test - -import ( - "errors" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/cosmos/cosmos-sdk/crypto/keys/keyerror" -) - -func TestErrors(t *testing.T) { - err := keyerror.NewErrKeyNotFound("test") - require.True(t, keyerror.IsErrKeyNotFound(err)) - require.Equal(t, "Key test not found", err.Error()) - require.False(t, keyerror.IsErrKeyNotFound(errors.New("test"))) - require.False(t, keyerror.IsErrKeyNotFound(nil)) - - err = keyerror.NewErrWrongPassword() - require.True(t, keyerror.IsErrWrongPassword(err)) - require.Equal(t, "invalid account password", err.Error()) - require.False(t, keyerror.IsErrWrongPassword(errors.New("test"))) - require.False(t, keyerror.IsErrWrongPassword(nil)) -} diff --git a/crypto/keys/mintkey/mintkey.go b/crypto/keys/mintkey/mintkey.go index 184be9b35e94..988c54d40664 100644 --- a/crypto/keys/mintkey/mintkey.go +++ b/crypto/keys/mintkey/mintkey.go @@ -11,8 +11,7 @@ import ( cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino" "github.com/tendermint/tendermint/crypto/xsalsa20symmetric" - "github.com/cosmos/cosmos-sdk/crypto/keys/keyerror" - "github.com/cosmos/cosmos-sdk/types/errors" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) const ( @@ -139,7 +138,7 @@ func encryptPrivKey(privKey crypto.PrivKey, passphrase string) (saltBytes []byte saltBytes = crypto.CRandBytes(16) key, err := bcrypt.GenerateFromPassword(saltBytes, []byte(passphrase), BcryptSecurityParameter) if err != nil { - panic(errors.Wrap(err, "error generating bcrypt key from passphrase")) + panic(sdkerrors.Wrap(err, "error generating bcrypt key from passphrase")) } key = crypto.Sha256(key) // get 32 bytes privKeyBytes := privKey.Bytes() @@ -176,12 +175,12 @@ func UnarmorDecryptPrivKey(armorStr string, passphrase string) (privKey crypto.P func decryptPrivKey(saltBytes []byte, encBytes []byte, passphrase string) (privKey crypto.PrivKey, err error) { key, err := bcrypt.GenerateFromPassword(saltBytes, []byte(passphrase), BcryptSecurityParameter) if err != nil { - return privKey, errors.Wrap(err, "error generating bcrypt key from passphrase") + return privKey, sdkerrors.Wrap(err, "error generating bcrypt key from passphrase") } key = crypto.Sha256(key) // Get 32 bytes privKeyBytes, err := xsalsa20symmetric.DecryptSymmetric(encBytes, key) if err != nil && err.Error() == "Ciphertext decryption failed" { - return privKey, keyerror.NewErrWrongPassword() + return privKey, sdkerrors.ErrWrongPassword } else if err != nil { return privKey, err } diff --git a/crypto/keys/mintkey/mintkey_test.go b/crypto/keys/mintkey/mintkey_test.go index ffeea07c4f88..5b0db5cba137 100644 --- a/crypto/keys/mintkey/mintkey_test.go +++ b/crypto/keys/mintkey/mintkey_test.go @@ -15,7 +15,7 @@ import ( "github.com/tendermint/tendermint/crypto/secp256k1" "github.com/tendermint/tendermint/crypto/xsalsa20symmetric" - "github.com/cosmos/cosmos-sdk/crypto/keys" + "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/crypto/keys/mintkey" ) @@ -26,7 +26,7 @@ func TestArmorUnarmorPrivKey(t *testing.T) { require.Error(t, err) decrypted, algo, err := mintkey.UnarmorDecryptPrivKey(armored, "passphrase") require.NoError(t, err) - require.Equal(t, string(keys.Secp256k1), algo) + require.Equal(t, string(keyring.Secp256k1), algo) require.True(t, priv.Equals(decrypted)) // empty string @@ -67,17 +67,17 @@ func TestArmorUnarmorPrivKey(t *testing.T) { func TestArmorUnarmorPubKey(t *testing.T) { // Select the encryption and storage for your cryptostore - cstore := keys.NewInMemory() + cstore := keyring.NewInMemory() // Add keys and see they return in alphabetical order - info, _, err := cstore.CreateMnemonic("Bob", keys.English, "passphrase", keys.Secp256k1) + info, _, err := cstore.CreateMnemonic("Bob", keyring.English, "passphrase", keyring.Secp256k1) require.NoError(t, err) armored := mintkey.ArmorPubKeyBytes(info.GetPubKey().Bytes(), "") pubBytes, algo, err := mintkey.UnarmorPubKeyBytes(armored) require.NoError(t, err) pub, err := cryptoAmino.PubKeyFromBytes(pubBytes) require.NoError(t, err) - require.Equal(t, string(keys.Secp256k1), algo) + require.Equal(t, string(keyring.Secp256k1), algo) require.True(t, pub.Equals(info.GetPubKey())) armored = mintkey.ArmorPubKeyBytes(info.GetPubKey().Bytes(), "unknown") diff --git a/server/init.go b/server/init.go index c9a95d7ab7e9..3a410ffed766 100644 --- a/server/init.go +++ b/server/init.go @@ -3,7 +3,7 @@ package server import ( "fmt" - "github.com/cosmos/cosmos-sdk/crypto/keys" + "github.com/cosmos/cosmos-sdk/crypto/keyring" clkeys "github.com/cosmos/cosmos-sdk/client/keys" sdk "github.com/cosmos/cosmos-sdk/types" @@ -15,7 +15,7 @@ func GenerateCoinKey() (sdk.AccAddress, string, error) { // generate a private key, with recovery phrase info, secret, err := clkeys.NewInMemoryKeyBase().CreateMnemonic( - "name", keys.English, "pass", keys.Secp256k1) + "name", keyring.English, "pass", keyring.Secp256k1) if err != nil { return sdk.AccAddress([]byte{}), "", err } @@ -25,7 +25,7 @@ func GenerateCoinKey() (sdk.AccAddress, string, error) { // GenerateSaveCoinKey returns the address of a public key, along with the secret // phrase to recover the private key. -func GenerateSaveCoinKey(keybase keys.Keybase, keyName, keyPass string, overwrite bool) (sdk.AccAddress, string, error) { +func GenerateSaveCoinKey(keybase keyring.Keybase, keyName, keyPass string, overwrite bool) (sdk.AccAddress, string, error) { // ensure no overwrite if !overwrite { _, err := keybase.Get(keyName) @@ -36,7 +36,7 @@ func GenerateSaveCoinKey(keybase keys.Keybase, keyName, keyPass string, overwrit } // generate a private key, with recovery phrase - info, secret, err := keybase.CreateMnemonic(keyName, keys.English, keyPass, keys.Secp256k1) + info, secret, err := keybase.CreateMnemonic(keyName, keyring.English, keyPass, keyring.Secp256k1) if err != nil { return sdk.AccAddress([]byte{}), "", err } diff --git a/server/init_test.go b/server/init_test.go index 349a9c169624..e1c56a26ee49 100644 --- a/server/init_test.go +++ b/server/init_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/client/keys" - crkeys "github.com/cosmos/cosmos-sdk/crypto/keys" + "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/server" "github.com/cosmos/cosmos-sdk/tests" ) @@ -17,7 +17,7 @@ func TestGenerateCoinKey(t *testing.T) { require.NoError(t, err) // Test creation - info, err := keys.NewInMemoryKeyBase().CreateAccount("xxx", mnemonic, "", "012345678", crkeys.CreateHDPath(0, 0).String(), crkeys.Secp256k1) + info, err := keys.NewInMemoryKeyBase().CreateAccount("xxx", mnemonic, "", "012345678", keyring.CreateHDPath(0, 0).String(), keyring.Secp256k1) require.NoError(t, err) require.Equal(t, addr, info.GetAddress()) } @@ -27,7 +27,7 @@ func TestGenerateSaveCoinKey(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) t.Cleanup(cleanup) - kb, err := crkeys.NewKeyring(t.Name(), "test", dir, nil) + kb, err := keyring.NewKeyring(t.Name(), "test", dir, nil) require.NoError(t, err) addr, mnemonic, err := server.GenerateSaveCoinKey(kb, "keyname", "012345678", false) @@ -39,7 +39,7 @@ func TestGenerateSaveCoinKey(t *testing.T) { require.Equal(t, addr, info.GetAddress()) // Test in-memory recovery - info, err = keys.NewInMemoryKeyBase().CreateAccount("xxx", mnemonic, "", "012345678", crkeys.CreateHDPath(0, 0).String(), crkeys.Secp256k1) + info, err = keys.NewInMemoryKeyBase().CreateAccount("xxx", mnemonic, "", "012345678", keyring.CreateHDPath(0, 0).String(), keyring.Secp256k1) require.NoError(t, err) require.Equal(t, addr, info.GetAddress()) } @@ -49,7 +49,7 @@ func TestGenerateSaveCoinKeyOverwriteFlag(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) t.Cleanup(cleanup) - kb, err := crkeys.NewKeyring(t.Name(), "test", dir, nil) + kb, err := keyring.NewKeyring(t.Name(), "test", dir, nil) require.NoError(t, err) keyname := "justakey" diff --git a/types/errors/errors.go b/types/errors/errors.go index 3179aed26369..a781a4cdd3b9 100644 --- a/types/errors/errors.go +++ b/types/errors/errors.go @@ -82,6 +82,12 @@ var ( // ErrTxTooLarge defines an ABCI typed error where tx is too large. ErrTxTooLarge = Register(RootCodespace, 21, "tx too large") + // ErrKeyNotFound defines an error when the key doesn't exist + ErrKeyNotFound = Register(RootCodespace, 22, "key not found") + + // ErrWrongPassword defines an error when the key password is invalid. + ErrWrongPassword = Register(RootCodespace, 23, "invalid account password") + // ErrPanic is only set when we recover from a panic, so we know to // redact potentially sensitive system info ErrPanic = Register(UndefinedCodespace, 111222, "panic") diff --git a/x/auth/client/cli/tx_multisign.go b/x/auth/client/cli/tx_multisign.go index 6018ce2a7a4f..83c068db1821 100644 --- a/x/auth/client/cli/tx_multisign.go +++ b/x/auth/client/cli/tx_multisign.go @@ -15,7 +15,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/crypto/keys" + "github.com/cosmos/cosmos-sdk/crypto/keyring" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/x/auth/client" @@ -65,7 +65,7 @@ func makeMultiSignCmd(cdc *codec.Codec) func(cmd *cobra.Command, args []string) } inBuf := bufio.NewReader(cmd.InOrStdin()) - kb, err := keys.NewKeyring(sdk.KeyringServiceName(), + kb, err := keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), inBuf) if err != nil { return @@ -75,8 +75,8 @@ func makeMultiSignCmd(cdc *codec.Codec) func(cmd *cobra.Command, args []string) if err != nil { return } - if multisigInfo.GetType() != keys.TypeMulti { - return fmt.Errorf("%q must be of type %s: %s", args[1], keys.TypeMulti, multisigInfo.GetType()) + if multisigInfo.GetType() != keyring.TypeMulti { + return fmt.Errorf("%q must be of type %s: %s", args[1], keyring.TypeMulti, multisigInfo.GetType()) } multisigPub := multisigInfo.GetPubKey().(multisig.PubKeyMultisigThreshold) diff --git a/x/auth/types/txbuilder.go b/x/auth/types/txbuilder.go index 47c79d39009b..2c2576841c40 100644 --- a/x/auth/types/txbuilder.go +++ b/x/auth/types/txbuilder.go @@ -10,14 +10,14 @@ import ( "github.com/spf13/viper" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/crypto/keys" + "github.com/cosmos/cosmos-sdk/crypto/keyring" sdk "github.com/cosmos/cosmos-sdk/types" ) // TxBuilder implements a transaction context created in SDK modules. type TxBuilder struct { txEncoder sdk.TxEncoder - keybase keys.Keybase + keybase keyring.Keybase accountNumber uint64 sequence uint64 gas uint64 @@ -53,7 +53,7 @@ func NewTxBuilder( // NewTxBuilderFromCLI returns a new initialized TxBuilder with parameters from // the command line using Viper. func NewTxBuilderFromCLI(input io.Reader) TxBuilder { - kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), input) + kb, err := keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), input) if err != nil { panic(err) } @@ -90,7 +90,7 @@ func (bldr TxBuilder) Gas() uint64 { return bldr.gas } func (bldr TxBuilder) GasAdjustment() float64 { return bldr.gasAdjustment } // Keybase returns the keybase -func (bldr TxBuilder) Keybase() keys.Keybase { return bldr.keybase } +func (bldr TxBuilder) Keybase() keyring.Keybase { return bldr.keybase } // SimulateAndExecute returns the option to simulate and then execute the transaction // using the gas from the simulation results @@ -149,7 +149,7 @@ func (bldr TxBuilder) WithGasPrices(gasPrices string) TxBuilder { } // WithKeybase returns a copy of the context with updated keybase. -func (bldr TxBuilder) WithKeybase(keybase keys.Keybase) TxBuilder { +func (bldr TxBuilder) WithKeybase(keybase keyring.Keybase) TxBuilder { bldr.keybase = keybase return bldr } @@ -272,11 +272,11 @@ func (bldr TxBuilder) SignStdTx(name, passphrase string, stdTx StdTx, appendSig } // MakeSignature builds a StdSignature given keybase, key name, passphrase, and a StdSignMsg. -func MakeSignature(keybase keys.Keybase, name, passphrase string, +func MakeSignature(keybase keyring.Keybase, name, passphrase string, msg StdSignMsg) (sig StdSignature, err error) { if keybase == nil { - keybase, err = keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), os.Stdin) + keybase, err = keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), os.Stdin) if err != nil { return } diff --git a/x/genutil/client/cli/gentx.go b/x/genutil/client/cli/gentx.go index 641a6099907f..6e2d7f73b602 100644 --- a/x/genutil/client/cli/gentx.go +++ b/x/genutil/client/cli/gentx.go @@ -22,7 +22,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/crypto/keys" + "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/server" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" @@ -93,7 +93,7 @@ func GenTxCmd(ctx *server.Context, cdc *codec.Codec, mbm module.BasicManager, sm } inBuf := bufio.NewReader(cmd.InOrStdin()) - kb, err := keys.NewKeyring(sdk.KeyringServiceName(), + kb, err := keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flagClientHome), inBuf) if err != nil { return errors.Wrap(err, "failed to initialize keybase") @@ -137,7 +137,7 @@ func GenTxCmd(ctx *server.Context, cdc *codec.Codec, mbm module.BasicManager, sm return errors.Wrap(err, "failed to build create-validator message") } - if key.GetType() == keys.TypeOffline || key.GetType() == keys.TypeMulti { + if key.GetType() == keyring.TypeOffline || key.GetType() == keyring.TypeMulti { fmt.Println("Offline key passed in. Use `tx sign` command to sign:") return authclient.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}) } From d962526b700de7e771381bc7291292efe19c48fb Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 25 Mar 2020 12:24:13 -0400 Subject: [PATCH 464/529] Implement and use CLIContext.Print --- client/context/context.go | 44 +++++++++++++++++++++++++++++++++++++-- client/tx/tx.go | 10 ++------- 2 files changed, 44 insertions(+), 10 deletions(-) diff --git a/client/context/context.go b/client/context/context.go index 2970dab6ed3e..8b26da6e1439 100644 --- a/client/context/context.go +++ b/client/context/context.go @@ -1,6 +1,7 @@ package context import ( + "encoding/json" "fmt" "io" "os" @@ -240,9 +241,49 @@ func (ctx CLIContext) WithBroadcastMode(mode string) CLIContext { return ctx } +// Print outputs toPrint to the ctx.Output based on ctx.OutputFormat which is +// either text or json. If text, toPrint will be YAML encoded. Otherwise, toPrint +// will be JSON encoded using ctx.Marshaler. An error is returned upon failure. +func (ctx CLIContext) Print(toPrint interface{}) error { + var ( + out []byte + err error + ) + + switch ctx.OutputFormat { + case "text": + out, err = yaml.Marshal(&toPrint) + + case "json": + out, err = ctx.Marshaler.MarshalJSON(toPrint) + + // To JSON indent, we re-encode the already encoded JSON given there is no + // error. The re-encoded JSON uses the standard library as the initial encoded + // JSON should have the correct output produced by ctx.Marshaler. + if ctx.Indent && err == nil { + var generic interface{} + + err = json.Unmarshal(out, &generic) + if err == nil { + out, err = json.MarshalIndent(generic, "", " ") + } + } + } + + if err != nil { + return err + } + + _, err = fmt.Fprintf(ctx.Output, "%s\n", out) + return err +} + // PrintOutput prints output while respecting output and indent flags // NOTE: pass in marshalled structs that have been unmarshaled -// because this function will panic on marshaling errors +// because this function will panic on marshaling errors. +// +// TODO: Remove once client-side Protobuf migration has been completed. +// ref: https://github.com/cosmos/cosmos-sdk/issues/5864 func (ctx CLIContext) PrintOutput(toPrint interface{}) error { var ( out []byte @@ -254,7 +295,6 @@ func (ctx CLIContext) PrintOutput(toPrint interface{}) error { out, err = yaml.Marshal(&toPrint) case "json": - // TODO: Use ctx.Marshaler. if ctx.Indent { out, err = ctx.Codec.MarshalJSONIndent(toPrint, "", " ") } else { diff --git a/client/tx/tx.go b/client/tx/tx.go index a3ead89d6679..906c2647ec97 100644 --- a/client/tx/tx.go +++ b/client/tx/tx.go @@ -90,13 +90,7 @@ func GenerateTx(ctx context.CLIContext, txf Factory, msgs ...sdk.Msg) error { return err } - out, err := ctx.Marshaler.MarshalJSON(tx) - if err != nil { - return err - } - - _, _ = fmt.Fprintf(ctx.Output, "%s\n", out) - return nil + return ctx.Print(tx) } // BroadcastTx attempts to generate, sign and broadcast a transaction with the @@ -159,7 +153,7 @@ func BroadcastTx(ctx context.CLIContext, txf Factory, msgs ...sdk.Msg) error { return err } - return ctx.PrintOutput(res) + return ctx.Print(res) } // BuildUnsignedTx builds a transaction to be signed given a set of messages. The From d21020e0f8a85002bcd827efbfbc01497a69975f Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 25 Mar 2020 12:27:03 -0400 Subject: [PATCH 465/529] Update x/bank CLI query commands --- x/bank/client/cli/query.go | 91 ++++++++++++++++++++++++++++++++++++++ x/bank/client/cli/tx.go | 4 +- 2 files changed, 92 insertions(+), 3 deletions(-) diff --git a/x/bank/client/cli/query.go b/x/bank/client/cli/query.go index e7327a091eb4..b63b9eabae3e 100644 --- a/x/bank/client/cli/query.go +++ b/x/bank/client/cli/query.go @@ -18,7 +18,95 @@ const ( flagDenom = "denom" ) +// NewQueryCmd returns a root CLI command handler for all x/bank query commands. +func NewQueryCmd(m codec.Marshaler) *cobra.Command { + cmd := &cobra.Command{ + Use: types.ModuleName, + Short: "Querying commands for the bank module", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + cmd.AddCommand(NewBalancesCmd(m)) + + return cmd +} + +// NewBalancesCmd returns a CLI command handler for querying account balance(s). +func NewBalancesCmd(m codec.Marshaler) *cobra.Command { + cmd := &cobra.Command{ + Use: "balances [address]", + Short: "Query for account balance(s) by address", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithMarshaler(m) + + addr, err := sdk.AccAddressFromBech32(args[0]) + if err != nil { + return err + } + + var ( + params interface{} + result interface{} + route string + ) + + denom := viper.GetString(flagDenom) + if denom == "" { + params = types.NewQueryAllBalancesParams(addr) + route = fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryAllBalances) + } else { + params = types.NewQueryBalanceParams(addr, denom) + route = fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryBalance) + } + + bz, err := m.MarshalJSON(params) + if err != nil { + return fmt.Errorf("failed to marshal params: %w", err) + } + + res, _, err := cliCtx.QueryWithData(route, bz) + if err != nil { + return err + } + + if denom == "" { + var balances sdk.Coins + if err := m.UnmarshalJSON(res, &balances); err != nil { + return err + } + + result = balances + } else { + var balance sdk.Coin + if err := m.UnmarshalJSON(res, &balance); err != nil { + return err + } + + result = balance + } + + return cliCtx.Print(result) + }, + } + + cmd.Flags().String(flagDenom, "", "The specific balance denomination to query for") + + return flags.GetCommands(cmd)[0] +} + +// --------------------------------------------------------------------------- +// Deprecated +// +// TODO: Remove once client-side Protobuf migration has been completed. +// --------------------------------------------------------------------------- + // GetQueryCmd returns the parent querying command for the bank module. +// +// TODO: Remove once client-side Protobuf migration has been completed. +// ref: https://github.com/cosmos/cosmos-sdk/issues/5864 func GetQueryCmd(cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ Use: types.ModuleName, @@ -35,6 +123,9 @@ func GetQueryCmd(cdc *codec.Codec) *cobra.Command { // GetAccountCmd returns a CLI command handler that facilitates querying for a // single or all account balances by address. +// +// TODO: Remove once client-side Protobuf migration has been completed. +// ref: https://github.com/cosmos/cosmos-sdk/issues/5864 func GetBalancesCmd(cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "balances [address]", diff --git a/x/bank/client/cli/tx.go b/x/bank/client/cli/tx.go index 906db932b3a8..6f59ec426dfe 100644 --- a/x/bank/client/cli/tx.go +++ b/x/bank/client/cli/tx.go @@ -27,9 +27,7 @@ func NewTxCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobr RunE: client.ValidateCmd, } - txCmd.AddCommand( - NewSendTxCmd(m, txg, ar), - ) + txCmd.AddCommand( NewSendTxCmd(m, txg, ar), ) return txCmd } From 7e67d84c0e95aa2189c748adcd492e8761617afa Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 25 Mar 2020 12:30:10 -0400 Subject: [PATCH 466/529] Lint --- x/bank/client/cli/tx.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/bank/client/cli/tx.go b/x/bank/client/cli/tx.go index 6f59ec426dfe..92341a371a5f 100644 --- a/x/bank/client/cli/tx.go +++ b/x/bank/client/cli/tx.go @@ -27,7 +27,7 @@ func NewTxCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobr RunE: client.ValidateCmd, } - txCmd.AddCommand( NewSendTxCmd(m, txg, ar), ) + txCmd.AddCommand(NewSendTxCmd(m, txg, ar)) return txCmd } From 3ecc4613850e4bb620a9b0c55235e4200cbb39d7 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 25 Mar 2020 13:03:14 -0400 Subject: [PATCH 467/529] Implement and use MarshalIndentFromJSON --- client/context/context.go | 8 +------- types/utils.go | 13 +++++++++++++ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/client/context/context.go b/client/context/context.go index 8b26da6e1439..f3746e31c0a8 100644 --- a/client/context/context.go +++ b/client/context/context.go @@ -1,7 +1,6 @@ package context import ( - "encoding/json" "fmt" "io" "os" @@ -261,12 +260,7 @@ func (ctx CLIContext) Print(toPrint interface{}) error { // error. The re-encoded JSON uses the standard library as the initial encoded // JSON should have the correct output produced by ctx.Marshaler. if ctx.Indent && err == nil { - var generic interface{} - - err = json.Unmarshal(out, &generic) - if err == nil { - out, err = json.MarshalIndent(generic, "", " ") - } + out, err = sdk.MarshalIndentFromJSON(out) } } diff --git a/types/utils.go b/types/utils.go index be33160261d5..56639e636f5c 100644 --- a/types/utils.go +++ b/types/utils.go @@ -14,6 +14,19 @@ var ( DBBackend = "" ) +// MarshalIndentFromJSON returns indented JSON-encoded bytes from already encoded +// JSON bytes. The output encoding will adhere to the original input's encoding +// (e.g. Proto3). +func MarshalIndentFromJSON(bz []byte) ([]byte, error) { + var generic interface{} + + if err := json.Unmarshal(bz, &generic); err == nil { + return nil, err + } + + return json.MarshalIndent(generic, "", " ") +} + // SortedJSON takes any JSON and returns it sorted by keys. Also, all white-spaces // are removed. // This method can be used to canonicalize JSON to be returned by GetSignBytes, From 17b68fb365253ebe76ceb3a7d08237b3a946587b Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 25 Mar 2020 13:20:29 -0400 Subject: [PATCH 468/529] Prep PostProcessResponseBare and PostProcessResponse --- types/rest/rest.go | 68 ++++++++++++++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 23 deletions(-) diff --git a/types/rest/rest.go b/types/rest/rest.go index 258917586248..ca79eb7175ce 100644 --- a/types/rest/rest.go +++ b/types/rest/rest.go @@ -229,21 +229,31 @@ func ParseQueryHeightOrReturnBadRequest(w http.ResponseWriter, cliCtx context.CL // PostProcessResponseBare post processes a body similar to PostProcessResponse // except it does not wrap the body and inject the height. -func PostProcessResponseBare(w http.ResponseWriter, cliCtx context.CLIContext, body interface{}) { +func PostProcessResponseBare(w http.ResponseWriter, ctx context.CLIContext, body interface{}) { var ( resp []byte err error ) + // TODO: Remove once client-side Protobuf migration has been completed. + // ref: https://github.com/cosmos/cosmos-sdk/issues/5864 + var marshaler codec.JSONMarshaler + + if ctx.Marshaler != nil { + marshaler = ctx.Marshaler + } else { + marshaler = ctx.Codec + } + switch b := body.(type) { case []byte: resp = b default: - if cliCtx.Indent { - resp, err = cliCtx.Codec.MarshalJSONIndent(body, "", " ") - } else { - resp, err = cliCtx.Codec.MarshalJSON(body) + resp, err = marshaler.MarshalJSON(body) + + if ctx.Indent && err == nil { + resp, err = sdk.MarshalIndentFromJSON(resp) } if err != nil { @@ -259,24 +269,36 @@ func PostProcessResponseBare(w http.ResponseWriter, cliCtx context.CLIContext, b // PostProcessResponse performs post processing for a REST response. The result // returned to clients will contain two fields, the height at which the resource // was queried at and the original result. -func PostProcessResponse(w http.ResponseWriter, cliCtx context.CLIContext, resp interface{}) { - var result []byte +func PostProcessResponse(w http.ResponseWriter, ctx context.CLIContext, resp interface{}) { + var ( + result []byte + err error + ) - if cliCtx.Height < 0 { + if ctx.Height < 0 { WriteErrorResponse(w, http.StatusInternalServerError, fmt.Errorf("negative height in response").Error()) return } + // TODO: Remove once client-side Protobuf migration has been completed. + // ref: https://github.com/cosmos/cosmos-sdk/issues/5864 + var marshaler codec.JSONMarshaler + + if ctx.Marshaler != nil { + marshaler = ctx.Marshaler + } else { + marshaler = ctx.Codec + } + switch res := resp.(type) { case []byte: result = res default: - var err error - if cliCtx.Indent { - result, err = cliCtx.Codec.MarshalJSONIndent(resp, "", " ") - } else { - result, err = cliCtx.Codec.MarshalJSON(resp) + result, err = marshaler.MarshalJSON(resp) + + if ctx.Indent && err == nil { + result, err = sdk.MarshalIndentFromJSON(result) } if err != nil { @@ -285,17 +307,11 @@ func PostProcessResponse(w http.ResponseWriter, cliCtx context.CLIContext, resp } } - wrappedResp := NewResponseWithHeight(cliCtx.Height, result) - - var ( - output []byte - err error - ) + wrappedResp := NewResponseWithHeight(ctx.Height, result) - if cliCtx.Indent { - output, err = cliCtx.Codec.MarshalJSONIndent(wrappedResp, "", " ") - } else { - output, err = cliCtx.Codec.MarshalJSON(wrappedResp) + output, err := marshaler.MarshalJSON(wrappedResp) + if ctx.Indent && err == nil { + output, err = sdk.MarshalIndentFromJSON(output) } if err != nil { @@ -312,10 +328,12 @@ func PostProcessResponse(w http.ResponseWriter, cliCtx context.CLIContext, resp // default limit can be provided. func ParseHTTPArgsWithLimit(r *http.Request, defaultLimit int) (tags []string, page, limit int, err error) { tags = make([]string, 0, len(r.Form)) + for key, values := range r.Form { if key == "page" || key == "limit" { continue } + var value string value, err = url.QueryUnescape(values[0]) if err != nil { @@ -326,13 +344,17 @@ func ParseHTTPArgsWithLimit(r *http.Request, defaultLimit int) (tags []string, p switch key { case types.TxHeightKey: tag = fmt.Sprintf("%s=%s", key, value) + case TxMinHeightKey: tag = fmt.Sprintf("%s>=%s", types.TxHeightKey, value) + case TxMaxHeightKey: tag = fmt.Sprintf("%s<=%s", types.TxHeightKey, value) + default: tag = fmt.Sprintf("%s='%s'", key, value) } + tags = append(tags, tag) } From 0e83e328d029b05ba1a958d26a18cc801ec1ce9f Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 25 Mar 2020 13:22:29 -0400 Subject: [PATCH 469/529] Prep QueryBalancesRequestHandlerFn for proto --- x/bank/client/rest/query.go | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/x/bank/client/rest/query.go b/x/bank/client/rest/query.go index 99b3680bbb16..baf1cbe42922 100644 --- a/x/bank/client/rest/query.go +++ b/x/bank/client/rest/query.go @@ -7,6 +7,7 @@ import ( "github.com/gorilla/mux" "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/rest" "github.com/cosmos/cosmos-sdk/x/bank/types" @@ -14,7 +15,7 @@ import ( // QueryBalancesRequestHandlerFn returns a REST handler that queries for all // account balances or a specific balance by denomination. -func QueryBalancesRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { +func QueryBalancesRequestHandlerFn(ctx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") vars := mux.Vars(r) @@ -26,7 +27,7 @@ func QueryBalancesRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return } - cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) + ctx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, ctx, r) if !ok { return } @@ -36,6 +37,16 @@ func QueryBalancesRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { route string ) + // TODO: Remove once client-side Protobuf migration has been completed. + // ref: https://github.com/cosmos/cosmos-sdk/issues/5864 + var marshaler codec.JSONMarshaler + + if ctx.Marshaler != nil { + marshaler = ctx.Marshaler + } else { + marshaler = ctx.Codec + } + denom := r.FormValue("denom") if denom == "" { params = types.NewQueryAllBalancesParams(addr) @@ -45,19 +56,19 @@ func QueryBalancesRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { route = fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryBalance) } - bz, err := cliCtx.Codec.MarshalJSON(params) + bz, err := marshaler.MarshalJSON(params) if err != nil { rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } - res, height, err := cliCtx.QueryWithData(route, bz) + res, height, err := ctx.QueryWithData(route, bz) if err != nil { rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return } - cliCtx = cliCtx.WithHeight(height) - rest.PostProcessResponse(w, cliCtx, res) + ctx = ctx.WithHeight(height) + rest.PostProcessResponse(w, ctx, res) } } From 3e0cf99e81870dadf1640c2115761051d9a61a6b Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 25 Mar 2020 14:23:34 -0400 Subject: [PATCH 470/529] Finish remaining x/bank REST handlers --- client/tx/factory.go | 33 +++++++++----- client/tx/tx.go | 90 ++++++++++++++++++++++++++++++++------ client/tx/tx_test.go | 3 +- types/rest/rest.go | 11 ++--- x/bank/client/rest/rest.go | 15 +++++++ x/bank/client/rest/tx.go | 47 ++++++++++++++++++++ 6 files changed, 169 insertions(+), 30 deletions(-) diff --git a/client/tx/factory.go b/client/tx/factory.go index 55a4982cb8f0..00f2b135ed8a 100644 --- a/client/tx/factory.go +++ b/client/tx/factory.go @@ -80,31 +80,31 @@ func (f Factory) AccountRetriever() AccountRetriever { return f.accountRetriever // using the gas from the simulation results func (f Factory) SimulateAndExecute() bool { return f.simulateAndExecute } -// WithTxGenerator returns a copy of the Builder with an updated Generator. +// WithTxGenerator returns a copy of the Factory with an updated Generator. func (f Factory) WithTxGenerator(g Generator) Factory { f.txGenerator = g return f } -// WithAccountRetriever returns a copy of the Builder with an updated AccountRetriever. +// WithAccountRetriever returns a copy of the Factory with an updated AccountRetriever. func (f Factory) WithAccountRetriever(ar AccountRetriever) Factory { f.accountRetriever = ar return f } -// WithChainID returns a copy of the Builder with an updated chainID. +// WithChainID returns a copy of the Factory with an updated chainID. func (f Factory) WithChainID(chainID string) Factory { f.chainID = chainID return f } -// WithGas returns a copy of the Builder with an updated gas value. +// WithGas returns a copy of the Factory with an updated gas value. func (f Factory) WithGas(gas uint64) Factory { f.gas = gas return f } -// WithFees returns a copy of the Builder with an updated fee. +// WithFees returns a copy of the Factory with an updated fee. func (f Factory) WithFees(fees string) Factory { parsedFees, err := sdk.ParseCoins(fees) if err != nil { @@ -115,7 +115,7 @@ func (f Factory) WithFees(fees string) Factory { return f } -// WithGasPrices returns a copy of the Builder with updated gas prices. +// WithGasPrices returns a copy of the Factory with updated gas prices. func (f Factory) WithGasPrices(gasPrices string) Factory { parsedGasPrices, err := sdk.ParseDecCoins(gasPrices) if err != nil { @@ -126,26 +126,39 @@ func (f Factory) WithGasPrices(gasPrices string) Factory { return f } -// WithKeybase returns a copy of the Builder with updated Keybase. +// WithKeybase returns a copy of the Factory with updated Keybase. func (f Factory) WithKeybase(keybase keys.Keybase) Factory { f.keybase = keybase return f } -// WithSequence returns a copy of the Builder with an updated sequence number. +// WithSequence returns a copy of the Factory with an updated sequence number. func (f Factory) WithSequence(sequence uint64) Factory { f.sequence = sequence return f } -// WithMemo returns a copy of the Builder with an updated memo. +// WithMemo returns a copy of the Factory with an updated memo. func (f Factory) WithMemo(memo string) Factory { f.memo = strings.TrimSpace(memo) return f } -// WithAccountNumber returns a copy of the Builder with an updated account number. +// WithAccountNumber returns a copy of the Factory with an updated account number. func (f Factory) WithAccountNumber(accnum uint64) Factory { f.accountNumber = accnum return f } + +// WithGasAdjustment returns a copy of the Factory with an updated gas adjustment. +func (f Factory) WithGasAdjustment(gasAdj float64) Factory { + f.gasAdjustment = gasAdj + return f +} + +// WithSimulateAndExecute returns a copy of the Factory with an updated gas +// simulation value. +func (f Factory) WithSimulateAndExecute(sim bool) Factory { + f.simulateAndExecute = sim + return f +} diff --git a/client/tx/tx.go b/client/tx/tx.go index 906c2647ec97..71c57a3180d0 100644 --- a/client/tx/tx.go +++ b/client/tx/tx.go @@ -5,6 +5,7 @@ import ( "encoding/json" "errors" "fmt" + "net/http" "os" "github.com/spf13/viper" @@ -16,7 +17,9 @@ import ( "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/crypto/keys" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/rest" "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/auth/types" ) type ( @@ -71,12 +74,7 @@ func GenerateTx(ctx context.CLIContext, txf Factory, msgs ...sdk.Msg) error { return errors.New("cannot estimate gas in offline mode") } - txBytes, err := BuildSimTx(txf, msgs...) - if err != nil { - return err - } - - _, adjusted, err := CalculateGas(ctx.QueryWithData, txBytes, txf.GasAdjustment()) + _, adjusted, err := CalculateGas(ctx.QueryWithData, txf, msgs...) if err != nil { return err } @@ -103,12 +101,7 @@ func BroadcastTx(ctx context.CLIContext, txf Factory, msgs ...sdk.Msg) error { } if txf.SimulateAndExecute() || ctx.Simulate { - txBytes, err := BuildSimTx(txf, msgs...) - if err != nil { - return err - } - - _, adjusted, err := CalculateGas(ctx.QueryWithData, txBytes, txf.GasAdjustment()) + _, adjusted, err := CalculateGas(ctx.QueryWithData, txf, msgs...) if err != nil { return err } @@ -156,6 +149,70 @@ func BroadcastTx(ctx context.CLIContext, txf Factory, msgs ...sdk.Msg) error { return ctx.Print(res) } +// WriteGeneratedTxResponse writes a generated unsigned transaction to the +// provided http.ResponseWriter. It will simulate gas costs if requested by the +// BaseReq. Upon any error, the error will be written to the http.ResponseWriter. +func WriteGeneratedTxResponse( + ctx context.CLIContext, w http.ResponseWriter, txg Generator, br rest.BaseReq, msgs ...sdk.Msg, +) { + + gasAdj, ok := rest.ParseFloat64OrReturnBadRequest(w, br.GasAdjustment, flags.DefaultGasAdjustment) + if !ok { + return + } + + simAndExec, gas, err := flags.ParseGas(br.Gas) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + txf := Factory{fees: br.Fees, gasPrices: br.GasPrices}. + WithAccountNumber(br.AccountNumber). + WithSequence(br.Sequence). + WithGas(gas). + WithGasAdjustment(gasAdj). + WithMemo(br.Memo). + WithChainID(br.ChainID). + WithSimulateAndExecute(br.Simulate) + + if br.Simulate || simAndExec { + if gasAdj < 0 { + rest.WriteErrorResponse(w, http.StatusBadRequest, types.ErrorInvalidGasAdjustment.Error()) + return + } + + _, adjusted, err := CalculateGas(ctx.QueryWithData, txf, msgs...) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + + txf = txf.WithGas(adjusted) + + if br.Simulate { + rest.WriteSimulationResponse(w, ctx.Marshaler, txf.Gas()) + return + } + } + + tx, err := BuildUnsignedTx(txf, msgs...) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + output, err := ctx.Marshaler.MarshalJSON(tx) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + _, _ = w.Write(output) +} + // BuildUnsignedTx builds a transaction to be signed given a set of messages. The // transaction is initially created via the provided factory's generator. Once // created, the fee, memo, and messages are set. @@ -209,9 +266,14 @@ func BuildSimTx(txf Factory, msgs ...sdk.Msg) ([]byte, error) { // CalculateGas simulates the execution of a transaction and returns the // simulation response obtained by the query and the adjusted gas amount. func CalculateGas( - queryFunc func(string, []byte) ([]byte, int64, error), txBytes []byte, adjustment float64, + queryFunc func(string, []byte) ([]byte, int64, error), txf Factory, msgs ...sdk.Msg, ) (sdk.SimulationResponse, uint64, error) { + txBytes, err := BuildSimTx(txf, msgs...) + if err != nil { + return sdk.SimulationResponse{}, 0, err + } + bz, _, err := queryFunc("/app/simulate", txBytes) if err != nil { return sdk.SimulationResponse{}, 0, err @@ -222,7 +284,7 @@ func CalculateGas( return sdk.SimulationResponse{}, 0, err } - return simRes, uint64(adjustment * float64(simRes.GasUsed)), nil + return simRes, uint64(txf.GasAdjustment() * float64(simRes.GasUsed)), nil } // PrepareFactory ensures the account defined by ctx.GetFromAddress() exists and diff --git a/client/tx/tx_test.go b/client/tx/tx_test.go index 55688dba7ef6..6fb3ceafb477 100644 --- a/client/tx/tx_test.go +++ b/client/tx/tx_test.go @@ -53,10 +53,11 @@ func TestCalculateGas(t *testing.T) { for _, tc := range testCases { stc := tc + txf := tx.Factory{}.WithChainID("test-chain").WithTxGenerator(std.TxGenerator{}) t.Run(stc.name, func(t *testing.T) { queryFunc := makeQueryFunc(stc.args.queryFuncGasUsed, stc.args.queryFuncWantErr) - simRes, gotAdjusted, err := tx.CalculateGas(queryFunc, []byte(""), stc.args.adjustment) + simRes, gotAdjusted, err := tx.CalculateGas(queryFunc, txf.WithGasAdjustment(stc.args.adjustment)) if stc.expPass { require.NoError(t, err) require.Equal(t, simRes.GasInfo.GasUsed, stc.wantEstimate) diff --git a/types/rest/rest.go b/types/rest/rest.go index ca79eb7175ce..8f90855f986a 100644 --- a/types/rest/rest.go +++ b/types/rest/rest.go @@ -119,16 +119,16 @@ func (br BaseReq) ValidateBasic(w http.ResponseWriter) bool { return true } -// ReadRESTReq reads and unmarshals a Request's body to the the BaseReq stuct. +// ReadRESTReq reads and unmarshals a Request's body to the the BaseReq struct. // Writes an error response to ResponseWriter and returns true if errors occurred. -func ReadRESTReq(w http.ResponseWriter, r *http.Request, cdc *codec.Codec, req interface{}) bool { +func ReadRESTReq(w http.ResponseWriter, r *http.Request, m codec.JSONMarshaler, req interface{}) bool { body, err := ioutil.ReadAll(r.Body) if err != nil { WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return false } - err = cdc.UnmarshalJSON(body, req) + err = m.UnmarshalJSON(body, req) if err != nil { WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("failed to decode JSON payload: %s", err)) return false @@ -158,9 +158,10 @@ func WriteErrorResponse(w http.ResponseWriter, status int, err string) { // WriteSimulationResponse prepares and writes an HTTP // response for transactions simulations. -func WriteSimulationResponse(w http.ResponseWriter, cdc *codec.Codec, gas uint64) { +func WriteSimulationResponse(w http.ResponseWriter, m codec.JSONMarshaler, gas uint64) { gasEst := GasEstimateResponse{GasEstimate: gas} - resp, err := cdc.MarshalJSON(gasEst) + + resp, err := m.MarshalJSON(gasEst) if err != nil { WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return diff --git a/x/bank/client/rest/rest.go b/x/bank/client/rest/rest.go index 578e41c06712..48e2776c8765 100644 --- a/x/bank/client/rest/rest.go +++ b/x/bank/client/rest/rest.go @@ -4,8 +4,23 @@ import ( "github.com/gorilla/mux" "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/tx" + "github.com/cosmos/cosmos-sdk/codec" ) +// RegisterHandlers registers all x/bank transaction and query HTTP REST handlers +// on the provided mux router. +func RegisterHandlers(ctx context.CLIContext, m codec.Marshaler, txg tx.Generator, r *mux.Router) { + r.HandleFunc("/bank/accounts/{address}/transfers", NewSendRequestHandlerFn(ctx, m, txg)).Methods("POST") + r.HandleFunc("/bank/balances/{address}", QueryBalancesRequestHandlerFn(ctx)).Methods("GET") +} + +// --------------------------------------------------------------------------- +// Deprecated +// +// TODO: Remove once client-side Protobuf migration has been completed. +// --------------------------------------------------------------------------- + // RegisterRoutes - Central function to define routes that get registered by the main application func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router) { r.HandleFunc("/bank/accounts/{address}/transfers", SendRequestHandlerFn(cliCtx)).Methods("POST") diff --git a/x/bank/client/rest/tx.go b/x/bank/client/rest/tx.go index 30178166bb5f..b9712c160acf 100644 --- a/x/bank/client/rest/tx.go +++ b/x/bank/client/rest/tx.go @@ -6,6 +6,8 @@ import ( "github.com/gorilla/mux" "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/tx" + "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/rest" authclient "github.com/cosmos/cosmos-sdk/x/auth/client" @@ -18,7 +20,52 @@ type SendReq struct { Amount sdk.Coins `json:"amount" yaml:"amount"` } +// NewSendRequestHandlerFn returns an HTTP REST handler for creating a MsgSend +// transaction. +func NewSendRequestHandlerFn(ctx context.CLIContext, m codec.Marshaler, txg tx.Generator) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + ctx = ctx.WithMarshaler(m) + + vars := mux.Vars(r) + bech32Addr := vars["address"] + + toAddr, err := sdk.AccAddressFromBech32(bech32Addr) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + var req SendReq + if !rest.ReadRESTReq(w, r, ctx.Marshaler, &req) { + return + } + + req.BaseReq = req.BaseReq.Sanitize() + if !req.BaseReq.ValidateBasic(w) { + return + } + + fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + msg := types.NewMsgSend(fromAddr, toAddr, req.Amount) + tx.WriteGeneratedTxResponse(ctx, w, txg, req.BaseReq, msg) + } +} + +// --------------------------------------------------------------------------- +// Deprecated +// +// TODO: Remove once client-side Protobuf migration has been completed. +// --------------------------------------------------------------------------- + // SendRequestHandlerFn - http request handler to send coins to a address. +// +// TODO: Remove once client-side Protobuf migration has been completed. +// ref: https://github.com/cosmos/cosmos-sdk/issues/5864 func SendRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) From f4e6bd6ad7c1646f1fbd99c14c164817e9b9aefc Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 25 Mar 2020 14:30:42 -0400 Subject: [PATCH 471/529] Fix build --- client/tx/factory.go | 10 +++++----- client/tx/tx.go | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/client/tx/factory.go b/client/tx/factory.go index 00f2b135ed8a..c4f08805e049 100644 --- a/client/tx/factory.go +++ b/client/tx/factory.go @@ -7,7 +7,7 @@ import ( "github.com/spf13/viper" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/crypto/keys" + "github.com/cosmos/cosmos-sdk/crypto/keyring" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -22,7 +22,7 @@ type AccountRetriever interface { // Factory defines a client transaction factory that facilitates generating and // signing an application-specific transaction. type Factory struct { - keybase keys.Keybase + keybase keyring.Keybase txGenerator Generator accountRetriever AccountRetriever accountNumber uint64 @@ -37,7 +37,7 @@ type Factory struct { } func NewFactoryFromCLI(input io.Reader) Factory { - kb, err := keys.NewKeyring( + kb, err := keyring.NewKeyring( sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), @@ -69,7 +69,7 @@ func (f Factory) AccountNumber() uint64 { return f.accountNumber } func (f Factory) Sequence() uint64 { return f.sequence } func (f Factory) Gas() uint64 { return f.gas } func (f Factory) GasAdjustment() float64 { return f.gasAdjustment } -func (f Factory) Keybase() keys.Keybase { return f.keybase } +func (f Factory) Keybase() keyring.Keybase { return f.keybase } func (f Factory) ChainID() string { return f.chainID } func (f Factory) Memo() string { return f.memo } func (f Factory) Fees() sdk.Coins { return f.fees } @@ -127,7 +127,7 @@ func (f Factory) WithGasPrices(gasPrices string) Factory { } // WithKeybase returns a copy of the Factory with updated Keybase. -func (f Factory) WithKeybase(keybase keys.Keybase) Factory { +func (f Factory) WithKeybase(keybase keyring.Keybase) Factory { f.keybase = keybase return f } diff --git a/client/tx/tx.go b/client/tx/tx.go index 71c57a3180d0..750f40b3f36a 100644 --- a/client/tx/tx.go +++ b/client/tx/tx.go @@ -15,7 +15,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/input" clientkeys "github.com/cosmos/cosmos-sdk/client/keys" "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/crypto/keys" + "github.com/cosmos/cosmos-sdk/crypto/keyring" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/rest" "github.com/cosmos/cosmos-sdk/x/auth" @@ -326,7 +326,7 @@ func PrepareFactory(ctx context.CLIContext, txf Factory) (Factory, error) { // by the CanonicalSignBytes call. func Sign(txf Factory, name, passphrase string, tx ClientTx) ([]byte, error) { if txf.keybase == nil { - keybase, err := keys.NewKeyring( + keybase, err := keyring.NewKeyring( sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), From 3eb01e43be449618d3314dcd62ffcc904c89d070 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 25 Mar 2020 14:44:20 -0400 Subject: [PATCH 472/529] Add changelog entries --- CHANGELOG.md | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c21c3c457bb9..31274448f4f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -81,14 +81,8 @@ to now accept a `codec.JSONMarshaler` for modular serialization of genesis state ### Bug Fixes -* (baseapp) [\#5718](https://github.com/cosmos/cosmos-sdk/pull/5718) Remove call to `ctx.BlockGasMeter` during failed message validation which -resulted in a panic when the tx execution mode was `CheckTx`. -* (client) [\#5618](https://github.com/cosmos/cosmos-sdk/pull/5618) Fix crash on the client when the verifier is not set. -* (x/distribution) [\#5620](https://github.com/cosmos/cosmos-sdk/pull/5620) Fix nil pointer deref in distribution tax/rewward validation helpers. * (types) [\#5741](https://github.com/cosmos/cosmos-sdk/issues/5741) Prevent ChainAnteDecorators() from panicking when empty AnteDecorator slice is supplied. * (modules) [\#5569](https://github.com/cosmos/cosmos-sdk/issues/5569) `InitGenesis`, for the relevant modules, now ensures module accounts exist. -* (crypto/keys/mintkey) [\#5823](https://github.com/cosmos/cosmos-sdk/pull/5823) fix errors handling in UnarmorPubKeyBytes (underlying armoring function's -return error was not being checked). * (crypto/keys) [\#5844](https://github.com/cosmos/cosmos-sdk/pull/5844) Keybase/Keyring `Sign()` methods no longer decode amino signatures when method receivers are offline/multisig keys. @@ -172,15 +166,31 @@ Buffers for state serialization instead of Amino. * (types) [\#5585](https://github.com/cosmos/cosmos-sdk/pull/5585) IBC additions: * `Coin` denomination max lenght has been increased to 32. * Added `CapabilityKey` alias for `StoreKey` to match IBC spec. -* (server) [\#5709](https://github.com/cosmos/cosmos-sdk/pull/5709) There are two new flags for pruning, `--pruning-keep-every` +* (server) [\#5709](https://github.com/cosmos/cosmos-sdk/pull/5709) There are two new flags for pruning, `--pruning-keep-every` and `--pruning-snapshot-every` as an alternative to `--pruning`. They allow to fine tune the strategy for pruning the state. -* (crypto/keys) [\#5739](https://github.com/cosmos/cosmos-sdk/pull/5739) Print an error message if the password input failed. -* (client) [\#5810](https://github.com/cosmos/cosmos-sdk/pull/5810) Added a new `--offline` flag that allows commands to -be executed without an internet connection. Previously, `--generate-only` served this purpose in addition to only allowing -txs to be generated. Now, `--generate-only` solely allows txs to be generated without being broadcasted and disallows -Keybase use and `--offline` allows the use of Keybase but does not allow any functionality that requires an online connection. +* (client) [\#5810](https://github.com/cosmos/cosmos-sdk/pull/5810) Added a new `--offline` flag that allows commands to be executed without an +internet connection. Previously, `--generate-only` served this purpose in addition to only allowing txs to be generated. Now, `--generate-only` solely +allows txs to be generated without being broadcasted and disallows Keybase use and `--offline` allows the use of Keybase but does not allow any +functionality that requires an online connection. * (types/module) [\#5724](https://github.com/cosmos/cosmos-sdk/issues/5724) The `types/module` package does no longer depend on `x/simulation`. +## [v0.38.2] - 2020-03-25 + +### Bug Fixes + +* (baseapp) [\#5718](https://github.com/cosmos/cosmos-sdk/pull/5718) Remove call to `ctx.BlockGasMeter` during failed message validation which resulted in a panic when the tx execution mode was `CheckTx`. +* (x/genutil) [\#5775](https://github.com/cosmos/cosmos-sdk/pull/5775) Fix `ExportGenesis` in `x/genutil` to export default genesis state (`[]`) instead of `null`. +* (client) [\#5618](https://github.com/cosmos/cosmos-sdk/pull/5618) Fix crash on the client when the verifier is not set. +* (crypto/keys/mintkey) [\#5823](https://github.com/cosmos/cosmos-sdk/pull/5823) fix errors handling in UnarmorPubKeyBytes (underlying armoring function's return error was not being checked). +* (x/distribution) [\#5620](https://github.com/cosmos/cosmos-sdk/pull/5620) Fix nil pointer deref in distribution tax/rewward validation helpers. + +### Improvements + +* (rest) [\#5648](https://github.com/cosmos/cosmos-sdk/pull/5648) Enhance /txs usability: + * Add `tx.minheight` key to filter transaction with an inclusive minimum block height + * Add `tx.maxheight` key to filter transaction with an inclusive maximum block height +* (crypto/keys) [\#5739](https://github.com/cosmos/cosmos-sdk/pull/5739) Print an error message if the password input failed. + ## [v0.38.1] - 2020-02-11 ### Improvements @@ -3050,7 +3060,8 @@ BUG FIXES: -[Unreleased]: https://github.com/cosmos/cosmos-sdk/compare/v0.38.1...HEAD +[Unreleased]: https://github.com/cosmos/cosmos-sdk/compare/v0.38.2...HEAD +[v0.38.2]: https://github.com/cosmos/cosmos-sdk/releases/tag/v0.38.2 [v0.38.1]: https://github.com/cosmos/cosmos-sdk/releases/tag/v0.38.1 [v0.38.0]: https://github.com/cosmos/cosmos-sdk/releases/tag/v0.38.0 [v0.37.8]: https://github.com/cosmos/cosmos-sdk/releases/tag/v0.37.8 From e950dd34aa383c8b1aa3a7e1386aa5cd1a678f98 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 25 Mar 2020 15:12:39 -0400 Subject: [PATCH 473/529] Error when keybase is nil during Sign --- client/tx/tx.go | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/client/tx/tx.go b/client/tx/tx.go index 750f40b3f36a..1d1d6a101697 100644 --- a/client/tx/tx.go +++ b/client/tx/tx.go @@ -326,17 +326,7 @@ func PrepareFactory(ctx context.CLIContext, txf Factory) (Factory, error) { // by the CanonicalSignBytes call. func Sign(txf Factory, name, passphrase string, tx ClientTx) ([]byte, error) { if txf.keybase == nil { - keybase, err := keyring.NewKeyring( - sdk.KeyringServiceName(), - viper.GetString(flags.FlagKeyringBackend), - viper.GetString(flags.FlagHome), - os.Stdin, - ) - if err != nil { - return nil, err - } - - txf = txf.WithKeybase(keybase) + return nil, errors.New("keybase must be set prior to signing a transaction") } signBytes, err := tx.CanonicalSignBytes(txf.chainID, txf.accountNumber, txf.sequence) From 6a33b424a6068fe70f434d8653bf263ad9e9f1e3 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 25 Mar 2020 15:15:43 -0400 Subject: [PATCH 474/529] Do not sanitize memo --- client/tx/factory.go | 3 +-- client/tx/tx.go | 3 --- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/client/tx/factory.go b/client/tx/factory.go index c4f08805e049..4b05b2419a42 100644 --- a/client/tx/factory.go +++ b/client/tx/factory.go @@ -2,7 +2,6 @@ package tx import ( "io" - "strings" "github.com/spf13/viper" @@ -140,7 +139,7 @@ func (f Factory) WithSequence(sequence uint64) Factory { // WithMemo returns a copy of the Factory with an updated memo. func (f Factory) WithMemo(memo string) Factory { - f.memo = strings.TrimSpace(memo) + f.memo = memo return f } diff --git a/client/tx/tx.go b/client/tx/tx.go index 1d1d6a101697..593f13a2a0f5 100644 --- a/client/tx/tx.go +++ b/client/tx/tx.go @@ -8,14 +8,11 @@ import ( "net/http" "os" - "github.com/spf13/viper" - "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/input" clientkeys "github.com/cosmos/cosmos-sdk/client/keys" "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/crypto/keyring" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/rest" "github.com/cosmos/cosmos-sdk/x/auth" From 75412d00f87400032384b7c2c90c8c58980034e3 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 25 Mar 2020 15:17:12 -0400 Subject: [PATCH 475/529] Rename to Println --- client/context/context.go | 4 ++-- client/tx/tx.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/client/context/context.go b/client/context/context.go index 4827f68e0f06..fb1708aed168 100644 --- a/client/context/context.go +++ b/client/context/context.go @@ -240,10 +240,10 @@ func (ctx CLIContext) WithBroadcastMode(mode string) CLIContext { return ctx } -// Print outputs toPrint to the ctx.Output based on ctx.OutputFormat which is +// Println outputs toPrint to the ctx.Output based on ctx.OutputFormat which is // either text or json. If text, toPrint will be YAML encoded. Otherwise, toPrint // will be JSON encoded using ctx.Marshaler. An error is returned upon failure. -func (ctx CLIContext) Print(toPrint interface{}) error { +func (ctx CLIContext) Println(toPrint interface{}) error { var ( out []byte err error diff --git a/client/tx/tx.go b/client/tx/tx.go index 593f13a2a0f5..7088a0bfda1a 100644 --- a/client/tx/tx.go +++ b/client/tx/tx.go @@ -85,7 +85,7 @@ func GenerateTx(ctx context.CLIContext, txf Factory, msgs ...sdk.Msg) error { return err } - return ctx.Print(tx) + return ctx.Println(tx) } // BroadcastTx attempts to generate, sign and broadcast a transaction with the @@ -143,7 +143,7 @@ func BroadcastTx(ctx context.CLIContext, txf Factory, msgs ...sdk.Msg) error { return err } - return ctx.Print(res) + return ctx.Println(res) } // WriteGeneratedTxResponse writes a generated unsigned transaction to the From 7310a0cca9cf2f89314af486aed4df218930a1ad Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 25 Mar 2020 15:21:20 -0400 Subject: [PATCH 476/529] Fix build --- x/bank/client/cli/query.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/bank/client/cli/query.go b/x/bank/client/cli/query.go index b63b9eabae3e..ba81f44dfa8d 100644 --- a/x/bank/client/cli/query.go +++ b/x/bank/client/cli/query.go @@ -88,7 +88,7 @@ func NewBalancesCmd(m codec.Marshaler) *cobra.Command { result = balance } - return cliCtx.Print(result) + return cliCtx.Println(result) }, } From 2978de90e1c001434e8cf67cfe5be2b8aef0aaff Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 25 Mar 2020 15:59:29 -0400 Subject: [PATCH 477/529] Fix MarshalIndentFromJSON --- types/rest/rest_test.go | 47 ++++++++++++++++++++++++++++++----------- types/utils.go | 2 +- 2 files changed, 36 insertions(+), 13 deletions(-) diff --git a/types/rest/rest_test.go b/types/rest/rest_test.go index db842696eeaf..ed3ca4173951 100644 --- a/types/rest/rest_test.go +++ b/types/rest/rest_test.go @@ -19,6 +19,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/types" + sdk "github.com/cosmos/cosmos-sdk/types" ) func TestBaseReq_Sanitize(t *testing.T) { @@ -204,13 +205,12 @@ func TestProcessPostResponse(t *testing.T) { // setup expected results jsonNoIndent, err := ctx.Codec.MarshalJSON(acc) require.Nil(t, err) - jsonWithIndent, err := ctx.Codec.MarshalJSONIndent(acc, "", " ") - require.Nil(t, err) + respNoIndent := NewResponseWithHeight(height, jsonNoIndent) - respWithIndent := NewResponseWithHeight(height, jsonWithIndent) expectedNoIndent, err := ctx.Codec.MarshalJSON(respNoIndent) require.Nil(t, err) - expectedWithIndent, err := ctx.Codec.MarshalJSONIndent(respWithIndent, "", " ") + + expectedWithIndent, err := sdk.MarshalIndentFromJSON(expectedNoIndent) require.Nil(t, err) // check that negative height writes an error @@ -222,6 +222,7 @@ func TestProcessPostResponse(t *testing.T) { // check that height returns expected response ctx = ctx.WithHeight(height) runPostProcessResponse(t, ctx, acc, expectedNoIndent, false) + // check height with indent runPostProcessResponse(t, ctx, acc, expectedWithIndent, true) } @@ -313,11 +314,15 @@ func TestPostProcessResponseBare(t *testing.T) { ctx := context.CLIContext{} w := httptest.NewRecorder() bs := []byte("text string") + PostProcessResponseBare(w, ctx, bs) + res := w.Result() require.Equal(t, http.StatusOK, res.StatusCode) + got, err := ioutil.ReadAll(res.Body) require.NoError(t, err) + t.Cleanup(func() { res.Body.Close() }) require.Equal(t, "text string", string(got)) @@ -328,15 +333,19 @@ func TestPostProcessResponseBare(t *testing.T) { X int `json:"x"` S string `json:"s"` }{X: 10, S: "test"} + PostProcessResponseBare(w, ctx, data) + res = w.Result() require.Equal(t, http.StatusOK, res.StatusCode) + got, err = ioutil.ReadAll(res.Body) require.NoError(t, err) + t.Cleanup(func() { res.Body.Close() }) require.Equal(t, `{ - "x": "10", - "s": "test" + "s": "test", + "x": "10" }`, string(got)) // write struct, don't indent response @@ -346,11 +355,15 @@ func TestPostProcessResponseBare(t *testing.T) { X int `json:"x"` S string `json:"s"` }{X: 10, S: "test"} + PostProcessResponseBare(w, ctx, data) + res = w.Result() require.Equal(t, http.StatusOK, res.StatusCode) + got, err = ioutil.ReadAll(res.Body) require.NoError(t, err) + t.Cleanup(func() { res.Body.Close() }) require.Equal(t, `{"x":"10","s":"test"}`, string(got)) @@ -358,11 +371,15 @@ func TestPostProcessResponseBare(t *testing.T) { ctx = context.CLIContext{Indent: false}.WithCodec(codec.New()) w = httptest.NewRecorder() data2 := badJSONMarshaller{} + PostProcessResponseBare(w, ctx, data2) + res = w.Result() require.Equal(t, http.StatusInternalServerError, res.StatusCode) + got, err = ioutil.ReadAll(res.Body) require.NoError(t, err) + t.Cleanup(func() { res.Body.Close() }) require.Equal(t, []string{"application/json"}, res.Header["Content-Type"]) require.Equal(t, `{"error":"couldn't marshal"}`, string(got)) @@ -384,31 +401,37 @@ func runPostProcessResponse(t *testing.T, ctx context.CLIContext, obj interface{ // test using regular struct w := httptest.NewRecorder() + PostProcessResponse(w, ctx, obj) require.Equal(t, http.StatusOK, w.Code, w.Body) + resp := w.Result() t.Cleanup(func() { resp.Body.Close() }) + body, err := ioutil.ReadAll(resp.Body) require.Nil(t, err) require.Equal(t, expectedBody, body) - var marshalled []byte + marshalled, err := ctx.Codec.MarshalJSON(obj) + require.NoError(t, err) + if indent { - marshalled, err = ctx.Codec.MarshalJSONIndent(obj, "", " ") - } else { - marshalled, err = ctx.Codec.MarshalJSON(obj) + marshalled, err = sdk.MarshalIndentFromJSON(marshalled) + require.NoError(t, err) } - require.Nil(t, err) // test using marshalled struct w = httptest.NewRecorder() PostProcessResponse(w, ctx, marshalled) + require.Equal(t, http.StatusOK, w.Code, w.Body) resp = w.Result() + t.Cleanup(func() { resp.Body.Close() }) body, err = ioutil.ReadAll(resp.Body) + require.Nil(t, err) - require.Equal(t, expectedBody, body) + require.Equal(t, string(expectedBody), string(body)) } func mustNewRequest(t *testing.T, method, url string, body io.Reader) *http.Request { diff --git a/types/utils.go b/types/utils.go index 56639e636f5c..d927ff755917 100644 --- a/types/utils.go +++ b/types/utils.go @@ -20,7 +20,7 @@ var ( func MarshalIndentFromJSON(bz []byte) ([]byte, error) { var generic interface{} - if err := json.Unmarshal(bz, &generic); err == nil { + if err := json.Unmarshal(bz, &generic); err != nil { return nil, err } From 7e78ce3198c6a8cda472657f17ac420b7e77950e Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Wed, 25 Mar 2020 16:12:01 -0400 Subject: [PATCH 478/529] Update CHANGELOG.md Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 31274448f4f9..9ada18219b6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -181,7 +181,7 @@ functionality that requires an online connection. * (baseapp) [\#5718](https://github.com/cosmos/cosmos-sdk/pull/5718) Remove call to `ctx.BlockGasMeter` during failed message validation which resulted in a panic when the tx execution mode was `CheckTx`. * (x/genutil) [\#5775](https://github.com/cosmos/cosmos-sdk/pull/5775) Fix `ExportGenesis` in `x/genutil` to export default genesis state (`[]`) instead of `null`. * (client) [\#5618](https://github.com/cosmos/cosmos-sdk/pull/5618) Fix crash on the client when the verifier is not set. -* (crypto/keys/mintkey) [\#5823](https://github.com/cosmos/cosmos-sdk/pull/5823) fix errors handling in UnarmorPubKeyBytes (underlying armoring function's return error was not being checked). +* (crypto/keys/mintkey) [\#5823](https://github.com/cosmos/cosmos-sdk/pull/5823) fix errors handling in `UnarmorPubKeyBytes` (underlying armoring function's return error was not being checked). * (x/distribution) [\#5620](https://github.com/cosmos/cosmos-sdk/pull/5620) Fix nil pointer deref in distribution tax/rewward validation helpers. ### Improvements From e98cb63d39c3b3ceb3fa3857a2b671277fdf598b Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Wed, 25 Mar 2020 16:12:10 -0400 Subject: [PATCH 479/529] Update CHANGELOG.md Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ada18219b6a..f69fe047b67c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -182,7 +182,7 @@ functionality that requires an online connection. * (x/genutil) [\#5775](https://github.com/cosmos/cosmos-sdk/pull/5775) Fix `ExportGenesis` in `x/genutil` to export default genesis state (`[]`) instead of `null`. * (client) [\#5618](https://github.com/cosmos/cosmos-sdk/pull/5618) Fix crash on the client when the verifier is not set. * (crypto/keys/mintkey) [\#5823](https://github.com/cosmos/cosmos-sdk/pull/5823) fix errors handling in `UnarmorPubKeyBytes` (underlying armoring function's return error was not being checked). -* (x/distribution) [\#5620](https://github.com/cosmos/cosmos-sdk/pull/5620) Fix nil pointer deref in distribution tax/rewward validation helpers. +* (x/distribution) [\#5620](https://github.com/cosmos/cosmos-sdk/pull/5620) Fix nil pointer deref in distribution tax/reward validation helpers. ### Improvements From c77b2b90bb77de962165913790559f9a2b1748f5 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Thu, 26 Mar 2020 11:11:03 -0400 Subject: [PATCH 480/529] Update docs/architecture/adr-020-protobuf-transaction-encoding.md Co-Authored-By: Aaron Craelius --- docs/architecture/adr-020-protobuf-transaction-encoding.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture/adr-020-protobuf-transaction-encoding.md b/docs/architecture/adr-020-protobuf-transaction-encoding.md index d3afaa7be512..4d32267a7ad2 100644 --- a/docs/architecture/adr-020-protobuf-transaction-encoding.md +++ b/docs/architecture/adr-020-protobuf-transaction-encoding.md @@ -128,7 +128,7 @@ type ClientTx interface { } ``` -We then update `CLIContext` to have a new field: `Marshler`. +We then update `CLIContext` to have a new field: `Marshaler`. Then, each module's client handler will at the minimum accept a `Marshaler` instead of a concrete Amino codec and a `Generator` along with an `AccountRetriever` so From 07b8210dee1582098eb7310505ae340ac56701dd Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Thu, 26 Mar 2020 16:40:57 +0100 Subject: [PATCH 481/529] Update ADR 3: add ReleaseCapability --- .../adr-003-dynamic-capability-store.md | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/docs/architecture/adr-003-dynamic-capability-store.md b/docs/architecture/adr-003-dynamic-capability-store.md index 7fd438fd931c..20ef7dee8335 100644 --- a/docs/architecture/adr-003-dynamic-capability-store.md +++ b/docs/architecture/adr-003-dynamic-capability-store.md @@ -184,6 +184,33 @@ func (sck ScopedCapabilityKeeper) GetCapability(ctx Context, name string) (Capab } ``` +`ReleaseCapability` allows a module to release a capability which it had previously claimed. If no more owners exist, the capability will be deleted globally. + +```golang +func (sck ScopedCapabilityKeeper) ReleaseCapability(ctx Context, capability Capability) err { + persistentStore := ctx.KVStore(sck.persistentKey) + memoryStore := ctx.KVStore(sck.memoryKey) + name := memoryStore.Get(sck.moduleName + "/fwd/" + capability) + if name == nil { + return error("capability not owned by module") + } + // delete forward mapping in memory store + memoryStore.Delete(sck.moduleName + "/fwd/" + capability, name) + // delete reverse mapping in memory store + memoryStore.Delete(sck.moduleName + "/rev/" + name, capability) + // update owner set in persistent store + owners := persistentStore.Get(capability.Index()) + owners.remove(sck.moduleName + "/" + name) + if owners.size() > 0 { + // there are still other owners, keep the capability around + persistentStore.Set(capability.Index(), owners) + } else { + // no more owners, delete the capability + persistentStore.Delete(capability.Index()) + } +} +``` + ### Memory store A new store key type, `MemoryStoreKey`, will be added to the `store` package. The `MemoryStoreKey`s work just like `StoreKey`s. From 6135912e5324aeddf6f2fe542dc40a9dc06dd444 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Thu, 26 Mar 2020 12:46:10 -0400 Subject: [PATCH 482/529] JSON Proto changes --- baseapp/abci.go | 10 +- baseapp/baseapp.go | 4 +- client/context/context.go | 2 +- codec/json.go | 48 +++ codec/proto_codec.go | 9 +- types/codec.go | 15 +- types/rest/rest.go | 6 +- types/rest/rest_test.go | 5 +- types/result.go | 39 +- types/types.pb.go | 752 ++++++++++++++++++++++++++++++++++- types/types.proto | 33 ++ types/utils.go | 13 - x/bank/handler.go | 4 +- x/bank/keeper/keeper_test.go | 10 +- x/crisis/handler.go | 2 +- x/distribution/handler.go | 8 +- x/evidence/handler.go | 2 +- x/gov/handler.go | 6 +- x/slashing/handler.go | 2 +- x/staking/handler.go | 10 +- 20 files changed, 868 insertions(+), 112 deletions(-) create mode 100644 codec/json.go diff --git a/baseapp/abci.go b/baseapp/abci.go index 3342f1aebc61..30273a12c839 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -1,7 +1,6 @@ package baseapp import ( - "encoding/json" "fmt" "os" "sort" @@ -10,6 +9,7 @@ import ( abci "github.com/tendermint/tendermint/abci/types" + "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) @@ -189,7 +189,7 @@ func (app *BaseApp) CheckTx(req abci.RequestCheckTx) abci.ResponseCheckTx { GasUsed: int64(gInfo.GasUsed), // TODO: Should type accept unsigned ints? Log: result.Log, Data: result.Data, - Events: result.Events.ToABCIEvents(), + Events: result.Events, } } @@ -214,7 +214,7 @@ func (app *BaseApp) DeliverTx(req abci.RequestDeliverTx) abci.ResponseDeliverTx GasUsed: int64(gInfo.GasUsed), // TODO: Should type accept unsigned ints? Log: result.Log, Data: result.Data, - Events: result.Events.ToABCIEvents(), + Events: result.Events, } } @@ -331,12 +331,12 @@ func handleQueryApp(app *BaseApp, path []string, req abci.RequestQuery) abci.Res return sdkerrors.QueryResult(sdkerrors.Wrap(err, "failed to simulate tx")) } - simRes := sdk.SimulationResponse{ + simRes := &sdk.SimulationResponse{ GasInfo: gInfo, Result: res, } - bz, err := json.Marshal(simRes) + bz, err := codec.ProtoMarshalJSON(simRes) if err != nil { return sdkerrors.QueryResult(sdkerrors.Wrap(err, "failed to JSON encode simulation response")) } diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 0373a199cf07..f52aa0dd11e6 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -606,7 +606,7 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode runTxMode) (*s msgEvents := sdk.Events{ sdk.NewEvent(sdk.EventTypeMessage, sdk.NewAttribute(sdk.AttributeKeyAction, msg.Type())), } - msgEvents = msgEvents.AppendEvents(msgResult.Events) + msgEvents = msgEvents.AppendEvents(msgResult.GetEvents()) // append message events, data and logs // @@ -620,6 +620,6 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode runTxMode) (*s return &sdk.Result{ Data: data, Log: strings.TrimSpace(msgLogs.String()), - Events: events, + Events: events.ToABCIEvents(), }, nil } diff --git a/client/context/context.go b/client/context/context.go index fb1708aed168..5e536251b0b6 100644 --- a/client/context/context.go +++ b/client/context/context.go @@ -260,7 +260,7 @@ func (ctx CLIContext) Println(toPrint interface{}) error { // error. The re-encoded JSON uses the standard library as the initial encoded // JSON should have the correct output produced by ctx.Marshaler. if ctx.Indent && err == nil { - out, err = sdk.MarshalIndentFromJSON(out) + out, err = codec.MarshalIndentFromJSON(out) } } diff --git a/codec/json.go b/codec/json.go new file mode 100644 index 000000000000..0bb44df31fd4 --- /dev/null +++ b/codec/json.go @@ -0,0 +1,48 @@ +package codec + +import ( + "bytes" + "encoding/json" + + "github.com/gogo/protobuf/jsonpb" + "github.com/gogo/protobuf/proto" +) + +// MarshalIndentFromJSON returns indented JSON-encoded bytes from already encoded +// JSON bytes. The output encoding will adhere to the original input's encoding +// (e.g. Proto3). +func MarshalIndentFromJSON(bz []byte) ([]byte, error) { + var generic interface{} + + if err := json.Unmarshal(bz, &generic); err != nil { + return nil, err + } + + return json.MarshalIndent(generic, "", " ") +} + +// ProtoMarshalJSON provides an auxiliary function to return Proto3 JSON encoded +// bytes of a message. +func ProtoMarshalJSON(msg proto.Message) ([]byte, error) { + jm := &jsonpb.Marshaler{EmitDefaults: false, OrigName: false} + buf := new(bytes.Buffer) + + if err := jm.Marshal(buf, msg); err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +// ProtoMarshalJSONIndent provides an auxiliary function to return Proto3 indented +// JSON encoded bytes of a message. +func ProtoMarshalJSONIndent(msg proto.Message) ([]byte, error) { + jm := &jsonpb.Marshaler{EmitDefaults: false, OrigName: false, Indent: " "} + buf := new(bytes.Buffer) + + if err := jm.Marshal(buf, msg); err != nil { + return nil, err + } + + return buf.Bytes(), nil +} diff --git a/codec/proto_codec.go b/codec/proto_codec.go index f8a4169d4d8b..ff123cee23a3 100644 --- a/codec/proto_codec.go +++ b/codec/proto_codec.go @@ -95,14 +95,7 @@ func (pc *ProtoCodec) MarshalJSON(o interface{}) ([]byte, error) { // nolint: st return nil, fmt.Errorf("cannot protobuf JSON encode unsupported type: %T", o) } - buf := new(bytes.Buffer) - - marshaler := &jsonpb.Marshaler{} - if err := marshaler.Marshal(buf, m); err != nil { - return nil, err - } - - return buf.Bytes(), nil + return ProtoMarshalJSON(m) } func (pc *ProtoCodec) MustMarshalJSON(o interface{}) []byte { diff --git a/types/codec.go b/types/codec.go index 21cd269043a0..9cd1097c201b 100644 --- a/types/codec.go +++ b/types/codec.go @@ -1,10 +1,7 @@ package types import ( - "bytes" - jsonc "github.com/gibson042/canonicaljson-go" - "github.com/gogo/protobuf/jsonpb" "github.com/cosmos/cosmos-sdk/codec" ) @@ -19,19 +16,17 @@ func RegisterCodec(cdc *codec.Codec) { // can be signed over. The JSON encoding ensures all field names adhere to their // Proto definition, default values are omitted, and follows the JSON Canonical // Form. -func CanonicalSignBytes(m codec.ProtoMarshaler) ([]byte, error) { - jm := &jsonpb.Marshaler{EmitDefaults: false, OrigName: false} - buf := new(bytes.Buffer) - - // first, encode via canonical Protocol Buffer JSON - if err := jm.Marshal(buf, m); err != nil { +func CanonicalSignBytes(msg codec.ProtoMarshaler) ([]byte, error) { + // first, encode via canonical Proto3 JSON + bz, err := codec.ProtoMarshalJSON(msg) + if err != nil { return nil, err } genericJSON := make(map[string]interface{}) // decode canonical proto encoding into a generic map - if err := jsonc.Unmarshal(buf.Bytes(), &genericJSON); err != nil { + if err := jsonc.Unmarshal(bz, &genericJSON); err != nil { return nil, err } diff --git a/types/rest/rest.go b/types/rest/rest.go index 8f90855f986a..74bf5946d4c4 100644 --- a/types/rest/rest.go +++ b/types/rest/rest.go @@ -254,7 +254,7 @@ func PostProcessResponseBare(w http.ResponseWriter, ctx context.CLIContext, body resp, err = marshaler.MarshalJSON(body) if ctx.Indent && err == nil { - resp, err = sdk.MarshalIndentFromJSON(resp) + resp, err = codec.MarshalIndentFromJSON(resp) } if err != nil { @@ -299,7 +299,7 @@ func PostProcessResponse(w http.ResponseWriter, ctx context.CLIContext, resp int result, err = marshaler.MarshalJSON(resp) if ctx.Indent && err == nil { - result, err = sdk.MarshalIndentFromJSON(result) + result, err = codec.MarshalIndentFromJSON(result) } if err != nil { @@ -312,7 +312,7 @@ func PostProcessResponse(w http.ResponseWriter, ctx context.CLIContext, resp int output, err := marshaler.MarshalJSON(wrappedResp) if ctx.Indent && err == nil { - output, err = sdk.MarshalIndentFromJSON(output) + output, err = codec.MarshalIndentFromJSON(output) } if err != nil { diff --git a/types/rest/rest_test.go b/types/rest/rest_test.go index ed3ca4173951..0f259b7fc14c 100644 --- a/types/rest/rest_test.go +++ b/types/rest/rest_test.go @@ -19,7 +19,6 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/types" - sdk "github.com/cosmos/cosmos-sdk/types" ) func TestBaseReq_Sanitize(t *testing.T) { @@ -210,7 +209,7 @@ func TestProcessPostResponse(t *testing.T) { expectedNoIndent, err := ctx.Codec.MarshalJSON(respNoIndent) require.Nil(t, err) - expectedWithIndent, err := sdk.MarshalIndentFromJSON(expectedNoIndent) + expectedWithIndent, err := codec.MarshalIndentFromJSON(expectedNoIndent) require.Nil(t, err) // check that negative height writes an error @@ -416,7 +415,7 @@ func runPostProcessResponse(t *testing.T, ctx context.CLIContext, obj interface{ require.NoError(t, err) if indent { - marshalled, err = sdk.MarshalIndentFromJSON(marshalled) + marshalled, err = codec.MarshalIndentFromJSON(marshalled) require.NoError(t, err) } diff --git a/types/result.go b/types/result.go index 54cc0e05330b..c488a027705b 100644 --- a/types/result.go +++ b/types/result.go @@ -7,39 +7,30 @@ import ( "math" "strings" + yaml "gopkg.in/yaml.v2" + "github.com/cosmos/cosmos-sdk/codec" ctypes "github.com/tendermint/tendermint/rpc/core/types" ) -// GasInfo defines tx execution gas context. -type GasInfo struct { - // GasWanted is the maximum units of work we allow this tx to perform. - GasWanted uint64 - - // GasUsed is the amount of gas actually consumed. - GasUsed uint64 +func (gi GasInfo) String() string { + bz, _ := yaml.Marshal(gi) + return string(bz) } -// Result is the union of ResponseFormat and ResponseCheckTx. -type Result struct { - // Data is any data returned from message or handler execution. It MUST be length - // prefixed in order to separate data from multiple message executions. - Data []byte - - // Log contains the log information from message or handler execution. - Log string - - // Events contains a slice of Event objects that were emitted during message or - // handler execution. - Events Events +func (r Result) String() string { + bz, _ := yaml.Marshal(r) + return string(bz) } -// SimulationResponse defines the response generated when a transaction is successfully -// simulated by the Baseapp. -type SimulationResponse struct { - GasInfo - Result *Result +func (r Result) GetEvents() Events { + events := make(Events, len(r.Events)) + for i, e := range r.Events { + events[i] = Event(e) + } + + return events } // ABCIMessageLogs represents a slice of ABCIMessageLog. diff --git a/types/types.pb.go b/types/types.pb.go index 845bf267ba4f..6b4d9813ab5f 100644 --- a/types/types.pb.go +++ b/types/types.pb.go @@ -7,6 +7,7 @@ import ( fmt "fmt" _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" + types "github.com/tendermint/tendermint/abci/types" io "io" math "math" math_bits "math/bits" @@ -239,38 +240,199 @@ func (m *ValAddresses) GetAddresses() []ValAddress { return nil } +// GasInfo defines tx execution gas context. +type GasInfo struct { + // GasWanted is the maximum units of work we allow this tx to perform. + GasWanted uint64 `protobuf:"varint,1,opt,name=gas_wanted,json=gasWanted,proto3" json:"gas_wanted,omitempty" yaml:"gas_wanted"` + // GasUsed is the amount of gas actually consumed. + GasUsed uint64 `protobuf:"varint,2,opt,name=gas_used,json=gasUsed,proto3" json:"gas_used,omitempty" yaml:"gas_used"` +} + +func (m *GasInfo) Reset() { *m = GasInfo{} } +func (*GasInfo) ProtoMessage() {} +func (*GasInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_2c0f90c600ad7e2e, []int{5} +} +func (m *GasInfo) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GasInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GasInfo.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 *GasInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_GasInfo.Merge(m, src) +} +func (m *GasInfo) XXX_Size() int { + return m.Size() +} +func (m *GasInfo) XXX_DiscardUnknown() { + xxx_messageInfo_GasInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_GasInfo proto.InternalMessageInfo + +func (m *GasInfo) GetGasWanted() uint64 { + if m != nil { + return m.GasWanted + } + return 0 +} + +func (m *GasInfo) GetGasUsed() uint64 { + if m != nil { + return m.GasUsed + } + return 0 +} + +// Result is the union of ResponseFormat and ResponseCheckTx. +type Result struct { + // Data is any data returned from message or handler execution. It MUST be length + // prefixed in order to separate data from multiple message executions. + Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` + // Log contains the log information from message or handler execution. + Log string `protobuf:"bytes,2,opt,name=log,proto3" json:"log,omitempty"` + // Events contains a slice of Event objects that were emitted during message or + // handler execution. + Events []types.Event `protobuf:"bytes,3,rep,name=events,proto3" json:"events"` +} + +func (m *Result) Reset() { *m = Result{} } +func (*Result) ProtoMessage() {} +func (*Result) Descriptor() ([]byte, []int) { + return fileDescriptor_2c0f90c600ad7e2e, []int{6} +} +func (m *Result) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Result) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Result.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 *Result) XXX_Merge(src proto.Message) { + xxx_messageInfo_Result.Merge(m, src) +} +func (m *Result) XXX_Size() int { + return m.Size() +} +func (m *Result) XXX_DiscardUnknown() { + xxx_messageInfo_Result.DiscardUnknown(m) +} + +var xxx_messageInfo_Result proto.InternalMessageInfo + +// SimulationResponse defines the response generated when a transaction is +// successfully simulated. +type SimulationResponse struct { + GasInfo `protobuf:"bytes,1,opt,name=gas_info,json=gasInfo,proto3,embedded=gas_info" json:"gas_info"` + Result *Result `protobuf:"bytes,2,opt,name=result,proto3" json:"result,omitempty"` +} + +func (m *SimulationResponse) Reset() { *m = SimulationResponse{} } +func (*SimulationResponse) ProtoMessage() {} +func (*SimulationResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_2c0f90c600ad7e2e, []int{7} +} +func (m *SimulationResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *SimulationResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_SimulationResponse.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 *SimulationResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_SimulationResponse.Merge(m, src) +} +func (m *SimulationResponse) XXX_Size() int { + return m.Size() +} +func (m *SimulationResponse) XXX_DiscardUnknown() { + xxx_messageInfo_SimulationResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_SimulationResponse proto.InternalMessageInfo + +func (m *SimulationResponse) GetResult() *Result { + if m != nil { + return m.Result + } + return nil +} + func init() { proto.RegisterType((*Coin)(nil), "cosmos_sdk.v1.Coin") proto.RegisterType((*DecCoin)(nil), "cosmos_sdk.v1.DecCoin") proto.RegisterType((*IntProto)(nil), "cosmos_sdk.v1.IntProto") proto.RegisterType((*DecProto)(nil), "cosmos_sdk.v1.DecProto") proto.RegisterType((*ValAddresses)(nil), "cosmos_sdk.v1.ValAddresses") + proto.RegisterType((*GasInfo)(nil), "cosmos_sdk.v1.GasInfo") + proto.RegisterType((*Result)(nil), "cosmos_sdk.v1.Result") + proto.RegisterType((*SimulationResponse)(nil), "cosmos_sdk.v1.SimulationResponse") } func init() { proto.RegisterFile("types/types.proto", fileDescriptor_2c0f90c600ad7e2e) } var fileDescriptor_2c0f90c600ad7e2e = []byte{ - // 305 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x2c, 0xa9, 0x2c, 0x48, - 0x2d, 0xd6, 0x07, 0x93, 0x7a, 0x05, 0x45, 0xf9, 0x25, 0xf9, 0x42, 0xbc, 0xc9, 0xf9, 0xc5, 0xb9, - 0xf9, 0xc5, 0xf1, 0xc5, 0x29, 0xd9, 0x7a, 0x65, 0x86, 0x52, 0x6a, 0x25, 0x19, 0x99, 0x45, 0x29, - 0xf1, 0x05, 0x89, 0x45, 0x25, 0x95, 0xfa, 0x60, 0x15, 0xfa, 0xe9, 0xf9, 0xe9, 0xf9, 0x08, 0x16, - 0x44, 0x9b, 0x92, 0x3b, 0x17, 0x8b, 0x73, 0x7e, 0x66, 0x9e, 0x90, 0x08, 0x17, 0x6b, 0x4a, 0x6a, - 0x5e, 0x7e, 0xae, 0x04, 0xa3, 0x02, 0xa3, 0x06, 0x67, 0x10, 0x84, 0x23, 0xa4, 0xcc, 0xc5, 0x96, - 0x98, 0x9b, 0x5f, 0x9a, 0x57, 0x22, 0xc1, 0x04, 0x12, 0x76, 0xe2, 0x3e, 0x71, 0x4f, 0x9e, 0xe1, - 0xd6, 0x3d, 0x79, 0x66, 0xcf, 0xbc, 0x92, 0x20, 0xa8, 0x94, 0x15, 0xcb, 0x8b, 0x05, 0xf2, 0x8c, - 0x4a, 0x5e, 0x5c, 0xec, 0x2e, 0xa9, 0xc9, 0xe4, 0x98, 0xe5, 0x92, 0x9a, 0x8c, 0x66, 0x96, 0x26, - 0x17, 0x87, 0x67, 0x5e, 0x49, 0x00, 0xd8, 0x5f, 0xb2, 0x5c, 0xcc, 0x99, 0x79, 0x25, 0x10, 0xa3, - 0x50, 0xed, 0x07, 0x89, 0x83, 0x94, 0xba, 0xa4, 0x26, 0xc3, 0x95, 0xa6, 0xa4, 0x26, 0xa3, 0x2b, - 0x05, 0x19, 0x0f, 0x12, 0x57, 0x72, 0xe2, 0xe2, 0x09, 0x4b, 0xcc, 0x71, 0x4c, 0x49, 0x29, 0x4a, - 0x2d, 0x2e, 0x4e, 0x2d, 0x16, 0xd2, 0xe1, 0xe2, 0x4c, 0x84, 0x71, 0x24, 0x18, 0x15, 0x98, 0x35, - 0x78, 0x9c, 0xf8, 0x7e, 0xdd, 0x93, 0xe7, 0x42, 0x28, 0x0a, 0x42, 0x28, 0xb0, 0x62, 0x69, 0xb8, - 0xa3, 0xc0, 0xe8, 0xe4, 0x72, 0xe3, 0xa1, 0x1c, 0x43, 0xc3, 0x23, 0x39, 0x86, 0x13, 0x8f, 0xe4, - 0x18, 0x2f, 0x3c, 0x92, 0x63, 0x7c, 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, 0x39, 0x86, 0x0b, 0x8f, - 0xe5, 0x18, 0x6e, 0x3c, 0x96, 0x63, 0x88, 0x52, 0x4a, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, - 0xce, 0xcf, 0xd5, 0x87, 0x44, 0x09, 0x94, 0xd2, 0x2d, 0x4e, 0xc9, 0x86, 0xc4, 0x58, 0x12, 0x1b, - 0x38, 0xec, 0x8d, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0xa7, 0x40, 0xd2, 0x04, 0xc7, 0x01, 0x00, - 0x00, + // 534 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x52, 0x4f, 0x6f, 0xd3, 0x4e, + 0x10, 0xb5, 0x7f, 0xf6, 0x2f, 0x7f, 0x36, 0xe1, 0x4f, 0x17, 0x8a, 0xa2, 0x0a, 0xec, 0xc8, 0x48, + 0x28, 0x48, 0xd4, 0x16, 0x29, 0xa7, 0x70, 0xc2, 0x04, 0x55, 0xe1, 0x84, 0x16, 0x01, 0x12, 0x97, + 0x68, 0xe3, 0xdd, 0xba, 0x56, 0xe3, 0xdd, 0xc8, 0xbb, 0x29, 0xca, 0x2d, 0x47, 0x8e, 0x7c, 0x84, + 0x7e, 0x9c, 0x1e, 0x73, 0xac, 0x10, 0xb2, 0x20, 0xb9, 0x70, 0xee, 0x91, 0x13, 0xda, 0xb5, 0xc1, + 0x6a, 0x7a, 0xe3, 0x92, 0xcc, 0xce, 0xbc, 0x79, 0x33, 0xf3, 0xfc, 0xc0, 0x8e, 0x5c, 0xcc, 0xa8, + 0x08, 0xf4, 0xaf, 0x3f, 0xcb, 0xb8, 0xe4, 0xf0, 0x46, 0xc4, 0x45, 0xca, 0xc5, 0x58, 0x90, 0x13, + 0xff, 0xf4, 0xe9, 0xde, 0x23, 0x79, 0x9c, 0x64, 0x64, 0x3c, 0xc3, 0x99, 0x5c, 0x04, 0x1a, 0x11, + 0xc4, 0x3c, 0xe6, 0x55, 0x54, 0xb4, 0xed, 0x1d, 0x5c, 0xc7, 0x49, 0xca, 0x08, 0xcd, 0xd2, 0x84, + 0xc9, 0x00, 0x4f, 0xa2, 0x24, 0xb8, 0x36, 0xcb, 0x3b, 0x04, 0xf6, 0x4b, 0x9e, 0x30, 0x78, 0x17, + 0xfc, 0x4f, 0x28, 0xe3, 0x69, 0xc7, 0xec, 0x9a, 0xbd, 0x26, 0x2a, 0x1e, 0xf0, 0x21, 0xa8, 0xe1, + 0x94, 0xcf, 0x99, 0xec, 0xfc, 0xa7, 0xd2, 0x61, 0xeb, 0x3c, 0x77, 0x8d, 0xaf, 0xb9, 0x6b, 0x8d, + 0x98, 0x44, 0x65, 0x69, 0x60, 0xff, 0x3c, 0x73, 0x4d, 0xef, 0x35, 0xa8, 0x0f, 0x69, 0xf4, 0x2f, + 0x5c, 0x43, 0x1a, 0x6d, 0x71, 0x3d, 0x06, 0x8d, 0x11, 0x93, 0x6f, 0xb4, 0x18, 0x0f, 0x80, 0x95, + 0x30, 0x59, 0x50, 0x5d, 0x9d, 0xaf, 0xf2, 0x0a, 0x3a, 0xa4, 0xd1, 0x5f, 0x28, 0xa1, 0xd1, 0x36, + 0x54, 0xd1, 0xab, 0xbc, 0x17, 0x82, 0xf6, 0x7b, 0x3c, 0x7d, 0x41, 0x48, 0x46, 0x85, 0xa0, 0x02, + 0x3e, 0x01, 0x4d, 0xfc, 0xe7, 0xd1, 0x31, 0xbb, 0x56, 0xaf, 0x1d, 0xde, 0xfc, 0x95, 0xbb, 0xa0, + 0x02, 0xa1, 0x0a, 0x30, 0xb0, 0x97, 0xdf, 0xba, 0xa6, 0xc7, 0x41, 0xfd, 0x10, 0x8b, 0x11, 0x3b, + 0xe2, 0xf0, 0x19, 0x00, 0x31, 0x16, 0xe3, 0x4f, 0x98, 0x49, 0x4a, 0xf4, 0x50, 0x3b, 0xdc, 0xbd, + 0xcc, 0xdd, 0x9d, 0x05, 0x4e, 0xa7, 0x03, 0xaf, 0xaa, 0x79, 0xa8, 0x19, 0x63, 0xf1, 0x41, 0xc7, + 0xd0, 0x07, 0x0d, 0x55, 0x99, 0x0b, 0x4a, 0xb4, 0x0e, 0x76, 0x78, 0xe7, 0x32, 0x77, 0x6f, 0x55, + 0x3d, 0xaa, 0xe2, 0xa1, 0x7a, 0x8c, 0xc5, 0x3b, 0x15, 0xcd, 0x40, 0x0d, 0x51, 0x31, 0x9f, 0x4a, + 0x08, 0x81, 0x4d, 0xb0, 0xc4, 0x7a, 0x52, 0x1b, 0xe9, 0x18, 0xde, 0x06, 0xd6, 0x94, 0xc7, 0x85, + 0xa0, 0x48, 0x85, 0x70, 0x00, 0x6a, 0xf4, 0x94, 0x32, 0x29, 0x3a, 0x56, 0xd7, 0xea, 0xb5, 0xfa, + 0xf7, 0xfd, 0xca, 0x03, 0xbe, 0xf2, 0x80, 0x5f, 0x7c, 0xfd, 0x57, 0x0a, 0x14, 0xda, 0x4a, 0x24, + 0x54, 0x76, 0x0c, 0xec, 0xcf, 0x67, 0xae, 0xe1, 0x2d, 0x4d, 0x00, 0xdf, 0x26, 0xe9, 0x7c, 0x8a, + 0x65, 0xc2, 0x19, 0xa2, 0x62, 0xc6, 0x99, 0xa0, 0xf0, 0x79, 0xb1, 0x78, 0xc2, 0x8e, 0xb8, 0x5e, + 0xa1, 0xd5, 0xbf, 0xe7, 0x5f, 0xf1, 0xa9, 0x5f, 0x0a, 0x13, 0x36, 0x14, 0xe9, 0x2a, 0x77, 0x4d, + 0x7d, 0x85, 0xd6, 0x6a, 0x1f, 0xd4, 0x32, 0x7d, 0x85, 0x5e, 0xb5, 0xd5, 0xdf, 0xdd, 0x6a, 0x2d, + 0x4e, 0x44, 0x25, 0x28, 0x1c, 0x5e, 0xfc, 0x70, 0x8c, 0xe5, 0xda, 0x31, 0xce, 0xd7, 0x8e, 0xb9, + 0x5a, 0x3b, 0xe6, 0xf7, 0xb5, 0x63, 0x7e, 0xd9, 0x38, 0xc6, 0x6a, 0xe3, 0x18, 0x17, 0x1b, 0xc7, + 0xf8, 0xe8, 0xc5, 0x89, 0x3c, 0x9e, 0x4f, 0xfc, 0x88, 0xa7, 0x41, 0x41, 0x55, 0xfe, 0xed, 0x0b, + 0x72, 0x52, 0x18, 0x7c, 0x52, 0xd3, 0x0e, 0x3f, 0xf8, 0x1d, 0x00, 0x00, 0xff, 0xff, 0x0e, 0xe8, + 0xc3, 0x0c, 0x62, 0x03, 0x00, 0x00, } func (this *Coin) Equal(that interface{}) bool { @@ -505,6 +667,135 @@ func (m *ValAddresses) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *GasInfo) 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 *GasInfo) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GasInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.GasUsed != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.GasUsed)) + i-- + dAtA[i] = 0x10 + } + if m.GasWanted != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.GasWanted)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *Result) 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 *Result) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Result) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Events) > 0 { + for iNdEx := len(m.Events) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Events[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.Log) > 0 { + i -= len(m.Log) + copy(dAtA[i:], m.Log) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Log))) + i-- + dAtA[i] = 0x12 + } + if len(m.Data) > 0 { + i -= len(m.Data) + copy(dAtA[i:], m.Data) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Data))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *SimulationResponse) 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 *SimulationResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *SimulationResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Result != nil { + { + size, err := m.Result.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + { + size, err := m.GasInfo.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func encodeVarintTypes(dAtA []byte, offset int, v uint64) int { offset -= sovTypes(v) base := offset @@ -583,6 +874,59 @@ func (m *ValAddresses) Size() (n int) { return n } +func (m *GasInfo) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.GasWanted != 0 { + n += 1 + sovTypes(uint64(m.GasWanted)) + } + if m.GasUsed != 0 { + n += 1 + sovTypes(uint64(m.GasUsed)) + } + return n +} + +func (m *Result) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Data) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.Log) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + if len(m.Events) > 0 { + for _, e := range m.Events { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + return n +} + +func (m *SimulationResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.GasInfo.Size() + n += 1 + l + sovTypes(uint64(l)) + if m.Result != nil { + l = m.Result.Size() + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + func sovTypes(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -1104,6 +1448,372 @@ func (m *ValAddresses) Unmarshal(dAtA []byte) error { } return nil } +func (m *GasInfo) 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 ErrIntOverflowTypes + } + 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: GasInfo: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GasInfo: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field GasWanted", wireType) + } + m.GasWanted = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.GasWanted |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field GasUsed", wireType) + } + m.GasUsed = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.GasUsed |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Result) 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 ErrIntOverflowTypes + } + 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: Result: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Result: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...) + if m.Data == nil { + m.Data = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Log", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Log = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Events", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Events = append(m.Events, types.Event{}) + if err := m.Events[len(m.Events)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *SimulationResponse) 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 ErrIntOverflowTypes + } + 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: SimulationResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SimulationResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field GasInfo", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.GasInfo.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Result", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Result == nil { + m.Result = &Result{} + } + if err := m.Result.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipTypes(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/types/types.proto b/types/types.proto index 7fff608b9c9d..c26219caa789 100644 --- a/types/types.proto +++ b/types/types.proto @@ -2,6 +2,7 @@ syntax = "proto3"; package cosmos_sdk.v1; import "third_party/proto/gogoproto/gogo.proto"; +import "third_party/proto/tendermint/abci/types/types.proto"; option go_package = "github.com/cosmos/cosmos-sdk/types"; option (gogoproto.goproto_stringer_all) = false; @@ -45,3 +46,35 @@ message ValAddresses { repeated bytes addresses = 1 [(gogoproto.casttype) = "ValAddress"]; } + +// GasInfo defines tx execution gas context. +message GasInfo { + // GasWanted is the maximum units of work we allow this tx to perform. + uint64 gas_wanted = 1 [(gogoproto.moretags) = "yaml:\"gas_wanted\""]; + + // GasUsed is the amount of gas actually consumed. + uint64 gas_used = 2 [(gogoproto.moretags) = "yaml:\"gas_used\""]; +} + +// Result is the union of ResponseFormat and ResponseCheckTx. +message Result { + option (gogoproto.goproto_getters) = false; + + // Data is any data returned from message or handler execution. It MUST be length + // prefixed in order to separate data from multiple message executions. + bytes data = 1; + + // Log contains the log information from message or handler execution. + string log = 2; + + // Events contains a slice of Event objects that were emitted during message or + // handler execution. + repeated tendermint.abci.types.Event events = 3 [(gogoproto.nullable) = false]; +} + +// SimulationResponse defines the response generated when a transaction is +// successfully simulated. +message SimulationResponse { + GasInfo gas_info = 1 [(gogoproto.embed) = true, (gogoproto.nullable) = false]; + Result result = 2; +} diff --git a/types/utils.go b/types/utils.go index d927ff755917..be33160261d5 100644 --- a/types/utils.go +++ b/types/utils.go @@ -14,19 +14,6 @@ var ( DBBackend = "" ) -// MarshalIndentFromJSON returns indented JSON-encoded bytes from already encoded -// JSON bytes. The output encoding will adhere to the original input's encoding -// (e.g. Proto3). -func MarshalIndentFromJSON(bz []byte) ([]byte, error) { - var generic interface{} - - if err := json.Unmarshal(bz, &generic); err != nil { - return nil, err - } - - return json.MarshalIndent(generic, "", " ") -} - // SortedJSON takes any JSON and returns it sorted by keys. Also, all white-spaces // are removed. // This method can be used to canonicalize JSON to be returned by GetSignBytes, diff --git a/x/bank/handler.go b/x/bank/handler.go index 30341ab47b57..5ec0033bce82 100644 --- a/x/bank/handler.go +++ b/x/bank/handler.go @@ -47,7 +47,7 @@ func handleMsgSend(ctx sdk.Context, k keeper.Keeper, msg types.MsgSend) (*sdk.Re ), ) - return &sdk.Result{Events: ctx.EventManager().Events()}, nil + return &sdk.Result{Events: ctx.EventManager().ABCIEvents()}, nil } // Handle MsgMultiSend. @@ -75,5 +75,5 @@ func handleMsgMultiSend(ctx sdk.Context, k keeper.Keeper, msg types.MsgMultiSend ), ) - return &sdk.Result{Events: ctx.EventManager().Events()}, nil + return &sdk.Result{Events: ctx.EventManager().ABCIEvents()}, nil } diff --git a/x/bank/keeper/keeper_test.go b/x/bank/keeper/keeper_test.go index 472fe39972d5..6135ad5d723c 100644 --- a/x/bank/keeper/keeper_test.go +++ b/x/bank/keeper/keeper_test.go @@ -240,7 +240,7 @@ func (suite *IntegrationTestSuite) TestMsgSendEvents() { suite.Require().Error(app.BankKeeper.SendCoins(ctx, addr, addr2, newCoins)) - events := ctx.EventManager().Events() + events := ctx.EventManager().ABCIEvents() suite.Require().Equal(2, len(events)) event1 := sdk.Event{ @@ -272,7 +272,7 @@ func (suite *IntegrationTestSuite) TestMsgSendEvents() { suite.Require().NoError(app.BankKeeper.SendCoins(ctx, addr, addr2, newCoins)) - events = ctx.EventManager().Events() + events = ctx.EventManager().ABCIEvents() suite.Require().Equal(4, len(events)) suite.Require().Equal(event1, events[2]) suite.Require().Equal(event2, events[3]) @@ -306,7 +306,7 @@ func (suite *IntegrationTestSuite) TestMsgMultiSendEvents() { suite.Require().Error(app.BankKeeper.InputOutputCoins(ctx, inputs, outputs)) - events := ctx.EventManager().Events() + events := ctx.EventManager().ABCIEvents() suite.Require().Equal(0, len(events)) // Set addr's coins but not addr2's coins @@ -314,7 +314,7 @@ func (suite *IntegrationTestSuite) TestMsgMultiSendEvents() { suite.Require().Error(app.BankKeeper.InputOutputCoins(ctx, inputs, outputs)) - events = ctx.EventManager().Events() + events = ctx.EventManager().ABCIEvents() suite.Require().Equal(1, len(events)) event1 := sdk.Event{ @@ -336,7 +336,7 @@ func (suite *IntegrationTestSuite) TestMsgMultiSendEvents() { suite.Require().NoError(app.BankKeeper.InputOutputCoins(ctx, inputs, outputs)) - events = ctx.EventManager().Events() + events = ctx.EventManager().ABCIEvents() suite.Require().Equal(5, len(events)) event2 := sdk.Event{ diff --git a/x/crisis/handler.go b/x/crisis/handler.go index cd94db85a5b1..3abf3fa83158 100644 --- a/x/crisis/handler.go +++ b/x/crisis/handler.go @@ -83,5 +83,5 @@ func handleMsgVerifyInvariant(ctx sdk.Context, msg types.MsgVerifyInvariant, k k ), }) - return &sdk.Result{Events: ctx.EventManager().Events()}, nil + return &sdk.Result{Events: ctx.EventManager().ABCIEvents()}, nil } diff --git a/x/distribution/handler.go b/x/distribution/handler.go index 642b9e0d89a1..5216cdad29f6 100644 --- a/x/distribution/handler.go +++ b/x/distribution/handler.go @@ -47,7 +47,7 @@ func handleMsgModifyWithdrawAddress(ctx sdk.Context, msg types.MsgSetWithdrawAdd ), ) - return &sdk.Result{Events: ctx.EventManager().Events()}, nil + return &sdk.Result{Events: ctx.EventManager().ABCIEvents()}, nil } func handleMsgWithdrawDelegatorReward(ctx sdk.Context, msg types.MsgWithdrawDelegatorReward, k keeper.Keeper) (*sdk.Result, error) { @@ -64,7 +64,7 @@ func handleMsgWithdrawDelegatorReward(ctx sdk.Context, msg types.MsgWithdrawDele ), ) - return &sdk.Result{Events: ctx.EventManager().Events()}, nil + return &sdk.Result{Events: ctx.EventManager().ABCIEvents()}, nil } func handleMsgWithdrawValidatorCommission(ctx sdk.Context, msg types.MsgWithdrawValidatorCommission, k keeper.Keeper) (*sdk.Result, error) { @@ -81,7 +81,7 @@ func handleMsgWithdrawValidatorCommission(ctx sdk.Context, msg types.MsgWithdraw ), ) - return &sdk.Result{Events: ctx.EventManager().Events()}, nil + return &sdk.Result{Events: ctx.EventManager().ABCIEvents()}, nil } func handleMsgFundCommunityPool(ctx sdk.Context, msg types.MsgFundCommunityPool, k keeper.Keeper) (*sdk.Result, error) { @@ -97,7 +97,7 @@ func handleMsgFundCommunityPool(ctx sdk.Context, msg types.MsgFundCommunityPool, ), ) - return &sdk.Result{Events: ctx.EventManager().Events()}, nil + return &sdk.Result{Events: ctx.EventManager().ABCIEvents()}, nil } func NewCommunityPoolSpendProposalHandler(k Keeper) govtypes.Handler { diff --git a/x/evidence/handler.go b/x/evidence/handler.go index e7b83eb1900d..1d3c82f93726 100644 --- a/x/evidence/handler.go +++ b/x/evidence/handler.go @@ -41,6 +41,6 @@ func handleMsgSubmitEvidence(ctx sdk.Context, k Keeper, msg exported.MsgSubmitEv return &sdk.Result{ Data: evidence.Hash(), - Events: ctx.EventManager().Events(), + Events: ctx.EventManager().ABCIEvents(), }, nil } diff --git a/x/gov/handler.go b/x/gov/handler.go index b50644a519ad..02edefcdbd80 100644 --- a/x/gov/handler.go +++ b/x/gov/handler.go @@ -59,7 +59,7 @@ func handleMsgSubmitProposal(ctx sdk.Context, keeper Keeper, msg MsgSubmitPropos return &sdk.Result{ Data: GetProposalIDBytes(proposal.ProposalID), - Events: ctx.EventManager().Events(), + Events: ctx.EventManager().ABCIEvents(), }, nil } @@ -86,7 +86,7 @@ func handleMsgDeposit(ctx sdk.Context, keeper Keeper, msg MsgDeposit) (*sdk.Resu ) } - return &sdk.Result{Events: ctx.EventManager().Events()}, nil + return &sdk.Result{Events: ctx.EventManager().ABCIEvents()}, nil } func handleMsgVote(ctx sdk.Context, keeper Keeper, msg MsgVote) (*sdk.Result, error) { @@ -103,5 +103,5 @@ func handleMsgVote(ctx sdk.Context, keeper Keeper, msg MsgVote) (*sdk.Result, er ), ) - return &sdk.Result{Events: ctx.EventManager().Events()}, nil + return &sdk.Result{Events: ctx.EventManager().ABCIEvents()}, nil } diff --git a/x/slashing/handler.go b/x/slashing/handler.go index 629a92dde29e..91d3c49d1e47 100644 --- a/x/slashing/handler.go +++ b/x/slashing/handler.go @@ -37,5 +37,5 @@ func handleMsgUnjail(ctx sdk.Context, msg MsgUnjail, k Keeper) (*sdk.Result, err ), ) - return &sdk.Result{Events: ctx.EventManager().Events()}, nil + return &sdk.Result{Events: ctx.EventManager().ABCIEvents()}, nil } diff --git a/x/staking/handler.go b/x/staking/handler.go index e6ed8e3b57c3..d140dc92bfb2 100644 --- a/x/staking/handler.go +++ b/x/staking/handler.go @@ -116,7 +116,7 @@ func handleMsgCreateValidator(ctx sdk.Context, msg types.MsgCreateValidator, k k ), }) - return &sdk.Result{Events: ctx.EventManager().Events()}, nil + return &sdk.Result{Events: ctx.EventManager().ABCIEvents()}, nil } func handleMsgEditValidator(ctx sdk.Context, msg types.MsgEditValidator, k keeper.Keeper) (*sdk.Result, error) { @@ -172,7 +172,7 @@ func handleMsgEditValidator(ctx sdk.Context, msg types.MsgEditValidator, k keepe ), }) - return &sdk.Result{Events: ctx.EventManager().Events()}, nil + return &sdk.Result{Events: ctx.EventManager().ABCIEvents()}, nil } func handleMsgDelegate(ctx sdk.Context, msg types.MsgDelegate, k keeper.Keeper) (*sdk.Result, error) { @@ -204,7 +204,7 @@ func handleMsgDelegate(ctx sdk.Context, msg types.MsgDelegate, k keeper.Keeper) ), }) - return &sdk.Result{Events: ctx.EventManager().Events()}, nil + return &sdk.Result{Events: ctx.EventManager().ABCIEvents()}, nil } func handleMsgUndelegate(ctx sdk.Context, msg types.MsgUndelegate, k keeper.Keeper) (*sdk.Result, error) { @@ -244,7 +244,7 @@ func handleMsgUndelegate(ctx sdk.Context, msg types.MsgUndelegate, k keeper.Keep ), }) - return &sdk.Result{Data: completionTimeBz, Events: ctx.EventManager().Events()}, nil + return &sdk.Result{Data: completionTimeBz, Events: ctx.EventManager().ABCIEvents()}, nil } func handleMsgBeginRedelegate(ctx sdk.Context, msg types.MsgBeginRedelegate, k keeper.Keeper) (*sdk.Result, error) { @@ -287,5 +287,5 @@ func handleMsgBeginRedelegate(ctx sdk.Context, msg types.MsgBeginRedelegate, k k ), }) - return &sdk.Result{Data: completionTimeBz, Events: ctx.EventManager().Events()}, nil + return &sdk.Result{Data: completionTimeBz, Events: ctx.EventManager().ABCIEvents()}, nil } From da400156c31f673d7c1bab5d78e8c1d4975bc9bd Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Thu, 26 Mar 2020 12:50:39 -0400 Subject: [PATCH 483/529] Fix tests --- baseapp/baseapp_test.go | 5 +++-- client/tx/tx.go | 6 ++++-- client/tx/tx_test.go | 6 +++--- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index 11d3e346c484..9de25e701049 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -3,12 +3,13 @@ package baseapp import ( "bytes" "encoding/binary" - "encoding/json" "fmt" "os" + "strings" "sync" "testing" + "github.com/gogo/protobuf/jsonpb" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -937,7 +938,7 @@ func TestSimulateTx(t *testing.T) { require.True(t, queryResult.IsOK(), queryResult.Log) var simRes sdk.SimulationResponse - require.NoError(t, json.Unmarshal(queryResult.Value, &simRes)) + require.NoError(t, jsonpb.Unmarshal(strings.NewReader(string(queryResult.Value)), &simRes)) require.Equal(t, gInfo, simRes.GasInfo) require.Equal(t, result.Log, simRes.Result.Log) diff --git a/client/tx/tx.go b/client/tx/tx.go index 7088a0bfda1a..6d1c1cd08157 100644 --- a/client/tx/tx.go +++ b/client/tx/tx.go @@ -2,11 +2,13 @@ package tx import ( "bufio" - "encoding/json" "errors" "fmt" "net/http" "os" + "strings" + + "github.com/gogo/protobuf/jsonpb" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/flags" @@ -277,7 +279,7 @@ func CalculateGas( } var simRes sdk.SimulationResponse - if err := json.Unmarshal(bz, &simRes); err != nil { + if err := jsonpb.Unmarshal(strings.NewReader(string(bz)), &simRes); err != nil { return sdk.SimulationResponse{}, 0, err } diff --git a/client/tx/tx_test.go b/client/tx/tx_test.go index 6fb3ceafb477..13e94f819bfa 100644 --- a/client/tx/tx_test.go +++ b/client/tx/tx_test.go @@ -1,13 +1,13 @@ package tx_test import ( - "encoding/json" "errors" "testing" "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/client/tx" + "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec/std" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" @@ -20,12 +20,12 @@ func TestCalculateGas(t *testing.T) { if wantErr { return nil, 0, errors.New("query failed") } - simRes := sdk.SimulationResponse{ + simRes := &sdk.SimulationResponse{ GasInfo: sdk.GasInfo{GasUsed: gasUsed, GasWanted: gasUsed}, Result: &sdk.Result{Data: []byte("tx data"), Log: "log"}, } - bz, err := json.Marshal(simRes) + bz, err := codec.ProtoMarshalJSON(simRes) if err != nil { return nil, 0, err } From 78fd300127c3f1f382ce91c0563fb70e5a124aed Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Thu, 26 Mar 2020 13:50:34 -0400 Subject: [PATCH 484/529] Fix bank tests --- x/bank/keeper/keeper_test.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/x/bank/keeper/keeper_test.go b/x/bank/keeper/keeper_test.go index 6135ad5d723c..c41e41be09d1 100644 --- a/x/bank/keeper/keeper_test.go +++ b/x/bank/keeper/keeper_test.go @@ -264,8 +264,8 @@ func (suite *IntegrationTestSuite) TestMsgSendEvents() { tmkv.Pair{Key: []byte(types.AttributeKeySender), Value: []byte(addr.String())}, ) - suite.Require().Equal(event1, events[0]) - suite.Require().Equal(event2, events[1]) + suite.Require().Equal(abci.Event(event1), events[0]) + suite.Require().Equal(abci.Event(event2), events[1]) app.BankKeeper.SetBalances(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin(fooDenom, 50))) newCoins = sdk.NewCoins(sdk.NewInt64Coin(fooDenom, 50)) @@ -274,8 +274,8 @@ func (suite *IntegrationTestSuite) TestMsgSendEvents() { events = ctx.EventManager().ABCIEvents() suite.Require().Equal(4, len(events)) - suite.Require().Equal(event1, events[2]) - suite.Require().Equal(event2, events[3]) + suite.Require().Equal(abci.Event(event1), events[2]) + suite.Require().Equal(abci.Event(event2), events[3]) } func (suite *IntegrationTestSuite) TestMsgMultiSendEvents() { @@ -325,7 +325,7 @@ func (suite *IntegrationTestSuite) TestMsgMultiSendEvents() { event1.Attributes, tmkv.Pair{Key: []byte(types.AttributeKeySender), Value: []byte(addr.String())}, ) - suite.Require().Equal(event1, events[0]) + suite.Require().Equal(abci.Event(event1), events[0]) // Set addr's coins and addr2's coins app.BankKeeper.SetBalances(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin(fooDenom, 50))) @@ -371,10 +371,10 @@ func (suite *IntegrationTestSuite) TestMsgMultiSendEvents() { tmkv.Pair{Key: []byte(sdk.AttributeKeyAmount), Value: []byte(newCoins2.String())}, ) - suite.Require().Equal(event1, events[1]) - suite.Require().Equal(event2, events[2]) - suite.Require().Equal(event3, events[3]) - suite.Require().Equal(event4, events[4]) + suite.Require().Equal(abci.Event(event1), events[1]) + suite.Require().Equal(abci.Event(event2), events[2]) + suite.Require().Equal(abci.Event(event3), events[3]) + suite.Require().Equal(abci.Event(event4), events[4]) } func (suite *IntegrationTestSuite) TestSpendableCoins() { From fa7024d3e4039165d667a739b63c5fff2d0e5cad Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Thu, 26 Mar 2020 23:33:48 +0100 Subject: [PATCH 485/529] exclude generated code from code coverage statistics .codecov.yml is not working. We should filter out all generated code that we don't want to be included in the coverage report. --- .circleci/config.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 635bf9b0a94a..18d519cf9af7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -165,6 +165,8 @@ jobs: name: filter out DONTCOVER command: | excludelist="$(find ./ -type f -name '*.go' | xargs grep -l 'DONTCOVER')" + excludelist+=" $(find ./ -type f -name '*.pb.go')" + excludelist+=" $(find ./ -type f -path './tests/mocks/*.go')" for filename in ${excludelist}; do filename=$(echo $filename | sed 's/^./github.com\/cosmos\/cosmos-sdk/g') echo "Excluding ${filename} from coverage report..." From 5db6d54825dd35c7be67be76272e665bea008d39 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Fri, 27 Mar 2020 10:24:19 +0100 Subject: [PATCH 486/529] merge crypto/keys/mintkey into crypto/ (#5880) crypto/keys/mintkey provides only armoring functions. It makes very little sense to keep it standalone and under a name which does not really seem consistent with the features it provides. --- CHANGELOG.md | 1 + crypto/{keys/mintkey/mintkey.go => armor.go} | 2 +- .../mintkey/mintkey_test.go => armor_test.go} | 67 ++++++++++++------- .../mintkey/README.md => bcrypt_readme.md} | 0 crypto/keyring/db_keybase.go | 24 +++---- crypto/keyring/keybase_test.go | 65 +++++++++--------- crypto/keyring/keyring.go | 14 ++-- crypto/keys/mintkey/mintkey_bench_test.go | 26 ------- 8 files changed, 94 insertions(+), 105 deletions(-) rename crypto/{keys/mintkey/mintkey.go => armor.go} (99%) rename crypto/{keys/mintkey/mintkey_test.go => armor_test.go} (66%) rename crypto/{keys/mintkey/README.md => bcrypt_readme.md} (100%) delete mode 100644 crypto/keys/mintkey/mintkey_bench_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e1327fc9588..1505a53da4bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -75,6 +75,7 @@ to now accept a `codec.JSONMarshaler` for modular serialization of genesis state * (baseapp) [\#5837](https://github.com/cosmos/cosmos-sdk/issues/5837) Transaction simulation now returns a `SimulationResponse` which contains the `GasInfo` and `Result` from the execution. * (crypto/keys) [\#5866](https://github.com/cosmos/cosmos-sdk/pull/5866) Move `Keyring` and `Keybase` implementations and their associated types from `crypto/keys/` to `crypto/keybase/`. +* (crypto) [\#5880](https://github.com/cosmos/cosmos-sdk/pull/5880) Merge `crypto/keys/mintkey` into `crypto`. ### Features diff --git a/crypto/keys/mintkey/mintkey.go b/crypto/armor.go similarity index 99% rename from crypto/keys/mintkey/mintkey.go rename to crypto/armor.go index 988c54d40664..934e2cfe7d0b 100644 --- a/crypto/keys/mintkey/mintkey.go +++ b/crypto/armor.go @@ -1,4 +1,4 @@ -package mintkey +package crypto import ( "encoding/hex" diff --git a/crypto/keys/mintkey/mintkey_test.go b/crypto/armor_test.go similarity index 66% rename from crypto/keys/mintkey/mintkey_test.go rename to crypto/armor_test.go index 5b0db5cba137..29aeb6af64a8 100644 --- a/crypto/keys/mintkey/mintkey_test.go +++ b/crypto/armor_test.go @@ -1,4 +1,4 @@ -package mintkey_test +package crypto_test import ( "bytes" @@ -9,45 +9,45 @@ import ( "github.com/stretchr/testify/require" "github.com/tendermint/crypto/bcrypt" - "github.com/tendermint/tendermint/crypto" + tmcrypto "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/armor" cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino" "github.com/tendermint/tendermint/crypto/secp256k1" "github.com/tendermint/tendermint/crypto/xsalsa20symmetric" + "github.com/cosmos/cosmos-sdk/crypto" "github.com/cosmos/cosmos-sdk/crypto/keyring" - "github.com/cosmos/cosmos-sdk/crypto/keys/mintkey" ) func TestArmorUnarmorPrivKey(t *testing.T) { priv := secp256k1.GenPrivKey() - armored := mintkey.EncryptArmorPrivKey(priv, "passphrase", "") - _, _, err := mintkey.UnarmorDecryptPrivKey(armored, "wrongpassphrase") + armored := crypto.EncryptArmorPrivKey(priv, "passphrase", "") + _, _, err := crypto.UnarmorDecryptPrivKey(armored, "wrongpassphrase") require.Error(t, err) - decrypted, algo, err := mintkey.UnarmorDecryptPrivKey(armored, "passphrase") + decrypted, algo, err := crypto.UnarmorDecryptPrivKey(armored, "passphrase") require.NoError(t, err) require.Equal(t, string(keyring.Secp256k1), algo) require.True(t, priv.Equals(decrypted)) // empty string - decrypted, algo, err = mintkey.UnarmorDecryptPrivKey("", "passphrase") + decrypted, algo, err = crypto.UnarmorDecryptPrivKey("", "passphrase") require.Error(t, err) require.True(t, errors.Is(io.EOF, err)) require.Nil(t, decrypted) require.Empty(t, algo) // wrong key type - armored = mintkey.ArmorPubKeyBytes(priv.PubKey().Bytes(), "") - _, _, err = mintkey.UnarmorDecryptPrivKey(armored, "passphrase") + armored = crypto.ArmorPubKeyBytes(priv.PubKey().Bytes(), "") + _, _, err = crypto.UnarmorDecryptPrivKey(armored, "passphrase") require.Error(t, err) require.Contains(t, err.Error(), "unrecognized armor type") // armor key manually - encryptPrivKeyFn := func(privKey crypto.PrivKey, passphrase string) (saltBytes []byte, encBytes []byte) { - saltBytes = crypto.CRandBytes(16) - key, err := bcrypt.GenerateFromPassword(saltBytes, []byte(passphrase), mintkey.BcryptSecurityParameter) + encryptPrivKeyFn := func(privKey tmcrypto.PrivKey, passphrase string) (saltBytes []byte, encBytes []byte) { + saltBytes = tmcrypto.CRandBytes(16) + key, err := bcrypt.GenerateFromPassword(saltBytes, []byte(passphrase), crypto.BcryptSecurityParameter) require.NoError(t, err) - key = crypto.Sha256(key) // get 32 bytes + key = tmcrypto.Sha256(key) // get 32 bytes privKeyBytes := privKey.Bytes() return saltBytes, xsalsa20symmetric.EncryptSymmetric(privKeyBytes, key) } @@ -60,7 +60,7 @@ func TestArmorUnarmorPrivKey(t *testing.T) { "type": "secp256k", } armored = armor.EncodeArmor("TENDERMINT PRIVATE KEY", headerWrongKdf, encBytes) - _, _, err = mintkey.UnarmorDecryptPrivKey(armored, "passphrase") + _, _, err = crypto.UnarmorDecryptPrivKey(armored, "passphrase") require.Error(t, err) require.Equal(t, "unrecognized KDF type: wrong", err.Error()) } @@ -72,16 +72,16 @@ func TestArmorUnarmorPubKey(t *testing.T) { // Add keys and see they return in alphabetical order info, _, err := cstore.CreateMnemonic("Bob", keyring.English, "passphrase", keyring.Secp256k1) require.NoError(t, err) - armored := mintkey.ArmorPubKeyBytes(info.GetPubKey().Bytes(), "") - pubBytes, algo, err := mintkey.UnarmorPubKeyBytes(armored) + armored := crypto.ArmorPubKeyBytes(info.GetPubKey().Bytes(), "") + pubBytes, algo, err := crypto.UnarmorPubKeyBytes(armored) require.NoError(t, err) pub, err := cryptoAmino.PubKeyFromBytes(pubBytes) require.NoError(t, err) require.Equal(t, string(keyring.Secp256k1), algo) require.True(t, pub.Equals(info.GetPubKey())) - armored = mintkey.ArmorPubKeyBytes(info.GetPubKey().Bytes(), "unknown") - pubBytes, algo, err = mintkey.UnarmorPubKeyBytes(armored) + armored = crypto.ArmorPubKeyBytes(info.GetPubKey().Bytes(), "unknown") + pubBytes, algo, err = crypto.UnarmorPubKeyBytes(armored) require.NoError(t, err) pub, err = cryptoAmino.PubKeyFromBytes(pubBytes) require.NoError(t, err) @@ -90,7 +90,7 @@ func TestArmorUnarmorPubKey(t *testing.T) { armored, err = cstore.ExportPrivKey("Bob", "passphrase", "alessio") require.NoError(t, err) - _, _, err = mintkey.UnarmorPubKeyBytes(armored) + _, _, err = crypto.UnarmorPubKeyBytes(armored) require.Error(t, err) require.Equal(t, `couldn't unarmor bytes: unrecognized armor type "TENDERMINT PRIVATE KEY", expected: "TENDERMINT PUBLIC KEY"`, err.Error()) @@ -100,7 +100,7 @@ func TestArmorUnarmorPubKey(t *testing.T) { "type": "unknown", } armored = armor.EncodeArmor("TENDERMINT PUBLIC KEY", header, pubBytes) - _, algo, err = mintkey.UnarmorPubKeyBytes(armored) + _, algo, err = crypto.UnarmorPubKeyBytes(armored) require.NoError(t, err) // return secp256k1 if version is 0.0.0 require.Equal(t, "secp256k1", algo) @@ -110,7 +110,7 @@ func TestArmorUnarmorPubKey(t *testing.T) { "type": "unknown", } armored = armor.EncodeArmor("TENDERMINT PUBLIC KEY", header, pubBytes) - bz, algo, err := mintkey.UnarmorPubKeyBytes(armored) + bz, algo, err := crypto.UnarmorPubKeyBytes(armored) require.Nil(t, bz) require.Empty(t, algo) require.Error(t, err) @@ -122,7 +122,7 @@ func TestArmorUnarmorPubKey(t *testing.T) { "version": "unknown", } armored = armor.EncodeArmor("TENDERMINT PUBLIC KEY", header, pubBytes) - bz, algo, err = mintkey.UnarmorPubKeyBytes(armored) + bz, algo, err = crypto.UnarmorPubKeyBytes(armored) require.Nil(t, bz) require.Empty(t, algo) require.Error(t, err) @@ -131,14 +131,14 @@ func TestArmorUnarmorPubKey(t *testing.T) { func TestArmorInfoBytes(t *testing.T) { bs := []byte("test") - armoredString := mintkey.ArmorInfoBytes(bs) - unarmoredBytes, err := mintkey.UnarmorInfoBytes(armoredString) + armoredString := crypto.ArmorInfoBytes(bs) + unarmoredBytes, err := crypto.UnarmorInfoBytes(armoredString) require.NoError(t, err) require.True(t, bytes.Equal(bs, unarmoredBytes)) } func TestUnarmorInfoBytesErrors(t *testing.T) { - unarmoredBytes, err := mintkey.UnarmorInfoBytes("") + unarmoredBytes, err := crypto.UnarmorInfoBytes("") require.Error(t, err) require.True(t, errors.Is(io.EOF, err)) require.Nil(t, unarmoredBytes) @@ -147,9 +147,24 @@ func TestUnarmorInfoBytesErrors(t *testing.T) { "type": "Info", "version": "0.0.1", } - unarmoredBytes, err = mintkey.UnarmorInfoBytes(armor.EncodeArmor( + unarmoredBytes, err = crypto.UnarmorInfoBytes(armor.EncodeArmor( "TENDERMINT KEY INFO", header, []byte("plain-text"))) require.Error(t, err) require.Equal(t, "unrecognized version: 0.0.1", err.Error()) require.Nil(t, unarmoredBytes) } + +func BenchmarkBcryptGenerateFromPassword(b *testing.B) { + passphrase := []byte("passphrase") + for securityParam := 9; securityParam < 16; securityParam++ { + param := securityParam + b.Run(fmt.Sprintf("benchmark-security-param-%d", param), func(b *testing.B) { + saltBytes := tmcrypto.CRandBytes(16) + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := bcrypt.GenerateFromPassword(saltBytes, passphrase, param) + require.Nil(b, err) + } + }) + } +} diff --git a/crypto/keys/mintkey/README.md b/crypto/bcrypt_readme.md similarity index 100% rename from crypto/keys/mintkey/README.md rename to crypto/bcrypt_readme.md diff --git a/crypto/keyring/db_keybase.go b/crypto/keyring/db_keybase.go index e1513b38e08a..4a09cc4afb24 100644 --- a/crypto/keyring/db_keybase.go +++ b/crypto/keyring/db_keybase.go @@ -10,7 +10,7 @@ import ( cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino" dbm "github.com/tendermint/tm-db" - "github.com/cosmos/cosmos-sdk/crypto/keys/mintkey" + "github.com/cosmos/cosmos-sdk/crypto" "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) @@ -160,7 +160,7 @@ func (kb dbKeybase) Sign(name, passphrase string, msg []byte) (sig []byte, pub t return } - priv, _, err = mintkey.UnarmorDecryptPrivKey(i.PrivKeyArmor, passphrase) + priv, _, err = crypto.UnarmorDecryptPrivKey(i.PrivKeyArmor, passphrase) if err != nil { return nil, nil, err } @@ -199,7 +199,7 @@ func (kb dbKeybase) ExportPrivateKeyObject(name string, passphrase string) (tmcr return nil, err } - priv, _, err = mintkey.UnarmorDecryptPrivKey(linfo.PrivKeyArmor, passphrase) + priv, _, err = crypto.UnarmorDecryptPrivKey(linfo.PrivKeyArmor, passphrase) if err != nil { return nil, err } @@ -221,7 +221,7 @@ func (kb dbKeybase) Export(name string) (armor string, err error) { return "", fmt.Errorf("no key to export with name %s", name) } - return mintkey.ArmorInfoBytes(bz), nil + return crypto.ArmorInfoBytes(bz), nil } // ExportPubKey returns public keys in ASCII armored format. It retrieves a Info @@ -241,7 +241,7 @@ func (kb dbKeybase) ExportPubKey(name string) (armor string, err error) { return } - return mintkey.ArmorPubKeyBytes(info.GetPubKey().Bytes(), string(info.GetAlgo())), nil + return crypto.ArmorPubKeyBytes(info.GetPubKey().Bytes(), string(info.GetAlgo())), nil } // ExportPrivKey returns a private key in ASCII armored format. @@ -259,7 +259,7 @@ func (kb dbKeybase) ExportPrivKey(name string, decryptPassphrase string, return "", err } - return mintkey.EncryptArmorPrivKey(priv, encryptPassphrase, string(info.GetAlgo())), nil + return crypto.EncryptArmorPrivKey(priv, encryptPassphrase, string(info.GetAlgo())), nil } // ImportPrivKey imports a private key in ASCII armor format. It returns an @@ -270,7 +270,7 @@ func (kb dbKeybase) ImportPrivKey(name string, armor string, passphrase string) return errors.New("Cannot overwrite key " + name) } - privKey, algo, err := mintkey.UnarmorDecryptPrivKey(armor, passphrase) + privKey, algo, err := crypto.UnarmorDecryptPrivKey(armor, passphrase) if err != nil { return errors.Wrap(err, "couldn't import private key") } @@ -289,7 +289,7 @@ func (kb dbKeybase) Import(name string, armor string) (err error) { return errors.New("cannot overwrite data for name " + name) } - infoBytes, err := mintkey.UnarmorInfoBytes(armor) + infoBytes, err := crypto.UnarmorInfoBytes(armor) if err != nil { return } @@ -310,7 +310,7 @@ func (kb dbKeybase) ImportPubKey(name string, armor string) (err error) { return errors.New("cannot overwrite data for name " + name) } - pubBytes, algo, err := mintkey.UnarmorPubKeyBytes(armor) + pubBytes, algo, err := crypto.UnarmorPubKeyBytes(armor) if err != nil { return } @@ -336,7 +336,7 @@ func (kb dbKeybase) Delete(name, passphrase string, skipPass bool) error { } if linfo, ok := info.(localInfo); ok && !skipPass { - if _, _, err = mintkey.UnarmorDecryptPrivKey(linfo.PrivKeyArmor, passphrase); err != nil { + if _, _, err = crypto.UnarmorDecryptPrivKey(linfo.PrivKeyArmor, passphrase); err != nil { return err } } @@ -366,7 +366,7 @@ func (kb dbKeybase) Update(name, oldpass string, getNewpass func() (string, erro case localInfo: linfo := i - key, _, err := mintkey.UnarmorDecryptPrivKey(linfo.PrivKeyArmor, oldpass) + key, _, err := crypto.UnarmorDecryptPrivKey(linfo.PrivKeyArmor, oldpass) if err != nil { return err } @@ -396,7 +396,7 @@ func (kb dbKeybase) SupportedAlgosLedger() []SigningAlgo { func (kb dbKeybase) writeLocalKey(name string, priv tmcrypto.PrivKey, passphrase string, algo SigningAlgo) Info { // encrypt private key using passphrase - privArmor := mintkey.EncryptArmorPrivKey(priv, passphrase, string(algo)) + privArmor := crypto.EncryptArmorPrivKey(priv, passphrase, string(algo)) // make Info pub := priv.PubKey() diff --git a/crypto/keyring/keybase_test.go b/crypto/keyring/keybase_test.go index cc96a7c37a9d..e55995db9d31 100644 --- a/crypto/keyring/keybase_test.go +++ b/crypto/keyring/keybase_test.go @@ -4,20 +4,19 @@ import ( "fmt" "testing" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/crypto" + tmcrypto "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/ed25519" "github.com/tendermint/tendermint/crypto/secp256k1" + "github.com/cosmos/cosmos-sdk/crypto" "github.com/cosmos/cosmos-sdk/crypto/keys/hd" - "github.com/cosmos/cosmos-sdk/crypto/keys/mintkey" sdk "github.com/cosmos/cosmos-sdk/types" ) func init() { - mintkey.BcryptSecurityParameter = 1 + crypto.BcryptSecurityParameter = 1 } const ( @@ -28,8 +27,8 @@ const ( func TestLanguage(t *testing.T) { kb := NewInMemory() _, _, err := kb.CreateMnemonic("something", Japanese, "no_pass", Secp256k1) - assert.Error(t, err) - assert.Equal(t, "unsupported language: only english is supported", err.Error()) + require.Error(t, err) + require.Equal(t, "unsupported language: only english is supported", err.Error()) } func TestCreateAccountInvalidMnemonic(t *testing.T) { @@ -38,8 +37,8 @@ func TestCreateAccountInvalidMnemonic(t *testing.T) { "some_account", "malarkey pair crucial catch public canyon evil outer stage ten gym tornado", "", "", CreateHDPath(0, 0).String(), Secp256k1) - assert.Error(t, err) - assert.Equal(t, "Invalid mnemonic", err.Error()) + require.Error(t, err) + require.Equal(t, "Invalid mnemonic", err.Error()) } func TestCreateLedgerUnsupportedAlgo(t *testing.T) { @@ -48,13 +47,13 @@ func TestCreateLedgerUnsupportedAlgo(t *testing.T) { supportedLedgerAlgos := kb.SupportedAlgosLedger() for _, supportedAlgo := range supportedLedgerAlgos { if Ed25519 == supportedAlgo { - assert.FailNow(t, "Was not an unsupported algorithm") + require.FailNow(t, "Was not an unsupported algorithm") } } _, err := kb.CreateLedger("some_account", Ed25519, "cosmos", 0, 1) - assert.Error(t, err) - assert.Equal(t, "unsupported signing algo", err.Error()) + require.Error(t, err) + require.Equal(t, "unsupported signing algo", err.Error()) } func TestCreateLedger(t *testing.T) { @@ -71,15 +70,15 @@ func TestCreateLedger(t *testing.T) { secpSupported = secpSupported || (supportedAlgo == Secp256k1) edSupported = edSupported || (supportedAlgo == Ed25519) } - assert.True(t, secpSupported) - assert.True(t, edSupported) + require.True(t, secpSupported) + require.True(t, edSupported) ledger, err := kb.CreateLedger("some_account", Secp256k1, "cosmos", 3, 1) if err != nil { - assert.Error(t, err) - assert.Equal(t, "ledger nano S: support for ledger devices is not available in this executable", err.Error()) - assert.Nil(t, ledger) + require.Error(t, err) + require.Equal(t, "ledger nano S: support for ledger devices is not available in this executable", err.Error()) + require.Nil(t, ledger) t.Skip("ledger nano S: support for ledger devices is not available in this executable") return } @@ -87,23 +86,23 @@ func TestCreateLedger(t *testing.T) { // The mock is available, check that the address is correct pubKey := ledger.GetPubKey() pk, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pubKey) - assert.NoError(t, err) - assert.Equal(t, "cosmospub1addwnpepqdszcr95mrqqs8lw099aa9h8h906zmet22pmwe9vquzcgvnm93eqygufdlv", pk) + require.NoError(t, err) + require.Equal(t, "cosmospub1addwnpepqdszcr95mrqqs8lw099aa9h8h906zmet22pmwe9vquzcgvnm93eqygufdlv", pk) // Check that restoring the key gets the same results restoredKey, err := kb.Get("some_account") - assert.NoError(t, err) - assert.NotNil(t, restoredKey) - assert.Equal(t, "some_account", restoredKey.GetName()) - assert.Equal(t, TypeLedger, restoredKey.GetType()) + require.NoError(t, err) + require.NotNil(t, restoredKey) + require.Equal(t, "some_account", restoredKey.GetName()) + require.Equal(t, TypeLedger, restoredKey.GetType()) pubKey = restoredKey.GetPubKey() pk, err = sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pubKey) - assert.NoError(t, err) - assert.Equal(t, "cosmospub1addwnpepqdszcr95mrqqs8lw099aa9h8h906zmet22pmwe9vquzcgvnm93eqygufdlv", pk) + require.NoError(t, err) + require.Equal(t, "cosmospub1addwnpepqdszcr95mrqqs8lw099aa9h8h906zmet22pmwe9vquzcgvnm93eqygufdlv", pk) path, err := restoredKey.GetPath() - assert.NoError(t, err) - assert.Equal(t, "44'/118'/3'/0/1", path.String()) + require.NoError(t, err) + require.Equal(t, "44'/118'/3'/0/1", path.String()) } // TestKeyManagement makes sure we can manipulate these keys well @@ -121,9 +120,9 @@ func TestKeyManagement(t *testing.T) { edSupported = edSupported || (supportedAlgo == Ed25519) srSupported = srSupported || (supportedAlgo == Sr25519) } - assert.True(t, secpSupported) - assert.False(t, edSupported) - assert.True(t, srSupported) + require.True(t, secpSupported) + require.False(t, edSupported) + require.True(t, srSupported) algo := Secp256k1 n1, n2, n3 := "personal", "business", "other" @@ -132,7 +131,7 @@ func TestKeyManagement(t *testing.T) { // Check empty state l, err := cstore.List() require.Nil(t, err) - assert.Empty(t, l) + require.Empty(t, l) _, _, err = cstore.CreateMnemonic(n1, English, p1, Ed25519) require.Error(t, err, "ed25519 keys are currently not supported by keybase") @@ -254,7 +253,7 @@ func TestSignVerify(t *testing.T) { // let's try to validate and make sure it only works when everything is proper cases := []struct { - key crypto.PubKey + key tmcrypto.PubKey data []byte sig []byte valid bool @@ -418,7 +417,7 @@ func TestSeedPhrase(t *testing.T) { info, mnemonic, err := cstore.CreateMnemonic(n1, English, p1, algo) require.Nil(t, err, "%+v", err) require.Equal(t, n1, info.GetName()) - assert.NotEmpty(t, mnemonic) + require.NotEmpty(t, mnemonic) // now, let us delete this key err = cstore.Delete(n1, p1, false) @@ -438,7 +437,7 @@ func TestSeedPhrase(t *testing.T) { func ExampleNew() { // Select the encryption and storage for your cryptostore - customKeyGenFunc := func(bz []byte, algo SigningAlgo) (crypto.PrivKey, error) { + customKeyGenFunc := func(bz []byte, algo SigningAlgo) (tmcrypto.PrivKey, error) { var bzArr [32]byte copy(bzArr[:], bz) return secp256k1.PrivKeySecp256k1(bzArr), nil diff --git a/crypto/keyring/keyring.go b/crypto/keyring/keyring.go index 3db8c3d433a9..1752c099ba16 100644 --- a/crypto/keyring/keyring.go +++ b/crypto/keyring/keyring.go @@ -18,7 +18,7 @@ import ( cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino" "github.com/cosmos/cosmos-sdk/client/input" - "github.com/cosmos/cosmos-sdk/crypto/keys/mintkey" + "github.com/cosmos/cosmos-sdk/crypto" "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) @@ -270,7 +270,7 @@ func (kb keyringKeybase) Export(name string) (armor string, err error) { return "", fmt.Errorf("no key to export with name: %s", name) } - return mintkey.ArmorInfoBytes(bz.Data), nil + return crypto.ArmorInfoBytes(bz.Data), nil } // ExportPubKey returns public keys in ASCII armored format. It retrieves an Info @@ -285,7 +285,7 @@ func (kb keyringKeybase) ExportPubKey(name string) (armor string, err error) { return "", fmt.Errorf("no key to export with name: %s", name) } - return mintkey.ArmorPubKeyBytes(bz.GetPubKey().Bytes(), string(bz.GetAlgo())), nil + return crypto.ArmorPubKeyBytes(bz.GetPubKey().Bytes(), string(bz.GetAlgo())), nil } // Import imports armored private key. @@ -300,7 +300,7 @@ func (kb keyringKeybase) Import(name string, armor string) error { } } - infoBytes, err := mintkey.UnarmorInfoBytes(armor) + infoBytes, err := crypto.UnarmorInfoBytes(armor) if err != nil { return err } @@ -336,7 +336,7 @@ func (kb keyringKeybase) ExportPrivKey(name, decryptPassphrase, encryptPassphras return "", err } - return mintkey.EncryptArmorPrivKey(priv, encryptPassphrase, string(info.GetAlgo())), nil + return crypto.EncryptArmorPrivKey(priv, encryptPassphrase, string(info.GetAlgo())), nil } // ImportPrivKey imports a private key in ASCII armor format. An error is returned @@ -347,7 +347,7 @@ func (kb keyringKeybase) ImportPrivKey(name, armor, passphrase string) error { return fmt.Errorf("cannot overwrite key: %s", name) } - privKey, algo, err := mintkey.UnarmorDecryptPrivKey(armor, passphrase) + privKey, algo, err := crypto.UnarmorDecryptPrivKey(armor, passphrase) if err != nil { return errors.Wrap(err, "failed to decrypt private key") } @@ -376,7 +376,7 @@ func (kb keyringKeybase) ImportPubKey(name string, armor string) error { } } - pubBytes, algo, err := mintkey.UnarmorPubKeyBytes(armor) + pubBytes, algo, err := crypto.UnarmorPubKeyBytes(armor) if err != nil { return err } diff --git a/crypto/keys/mintkey/mintkey_bench_test.go b/crypto/keys/mintkey/mintkey_bench_test.go deleted file mode 100644 index 1dd0b36cb373..000000000000 --- a/crypto/keys/mintkey/mintkey_bench_test.go +++ /dev/null @@ -1,26 +0,0 @@ -package mintkey - -import ( - "fmt" - "testing" - - "github.com/stretchr/testify/require" - "github.com/tendermint/crypto/bcrypt" - - "github.com/tendermint/tendermint/crypto" -) - -func BenchmarkBcryptGenerateFromPassword(b *testing.B) { - passphrase := []byte("passphrase") - for securityParam := 9; securityParam < 16; securityParam++ { - param := securityParam - b.Run(fmt.Sprintf("benchmark-security-param-%d", param), func(b *testing.B) { - saltBytes := crypto.CRandBytes(16) - b.ResetTimer() - for i := 0; i < b.N; i++ { - _, err := bcrypt.GenerateFromPassword(saltBytes, passphrase, param) - require.Nil(b, err) - } - }) - } -} From 702c44ff6bbf27288b41fdb8e54dbbf82fa003b8 Mon Sep 17 00:00:00 2001 From: Marko Baricevic Date: Fri, 27 Mar 2020 15:34:16 +0100 Subject: [PATCH 487/529] move some sims to github actions --- .circleci/config.yml | 47 --------------- .github/workflows/sims.yml | 117 +++++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+), 47 deletions(-) create mode 100644 .github/workflows/sims.yml diff --git a/.circleci/config.yml b/.circleci/config.yml index 18d519cf9af7..d684e5bcd4fe 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -86,41 +86,6 @@ jobs: target: proto-gen proto-lint proto-check-breaking description: "Lint and verify Protocol Buffer definitions" - test-sim-nondeterminism: - executor: golang - steps: - - make: - target: test-sim-nondeterminism - description: "Test individual module simulations" - - test-sim-import-export: - executor: golang - steps: - - make: - target: test-sim-import-export - description: "Test application import/export simulation" - - test-sim-after-import: - executor: golang - steps: - - make: - target: test-sim-after-import - description: "Test simulation after import" - - test-sim-multi-seed-long: - executor: golang - steps: - - make: - target: test-sim-multi-seed-long - description: "Test multi-seed simulation (long)" - - test-sim-multi-seed-short: - executor: golang - steps: - - make: - target: test-sim-multi-seed-short - description: "Test multi-seed simulation (short)" - test-cover: executor: golang parallelism: 4 @@ -197,18 +162,6 @@ workflows: only: - /^v.*/ - proto: - requires: - - setup-dependencies - - test-sim-nondeterminism: - requires: - - setup-dependencies - - test-sim-import-export: - requires: - - setup-dependencies - - test-sim-after-import: - requires: - - setup-dependencies - - test-sim-multi-seed-short: requires: - setup-dependencies - test-sim-multi-seed-long: diff --git a/.github/workflows/sims.yml b/.github/workflows/sims.yml new file mode 100644 index 000000000000..73f3de53a7c9 --- /dev/null +++ b/.github/workflows/sims.yml @@ -0,0 +1,117 @@ +name: Sims +on: [pull_request] +jobs: + build: + runs-on: ubuntu-latest + if: "!contains(github.event.head_commit.message, 'skip-sims')" + steps: + - uses: actions/setup-go@v1 + id: go + with: + go-version: 1.14 + - name: Setup env for GO + # this is only used until the setup-go action is updated + run: | + echo "::set-env name=GOPATH::$(go env GOPATH)" + echo "::add-path::$(go env GOPATH)/bin" + echo "::set-env name=GO111MODULE::"on"" + shell: bash + - name: install runsim + run: | + go get github.com/cosmos/tools/cmd/runsim@v1.0.0 + - uses: actions/cache@v1 + with: + path: ~/go/bin + key: ${{ runner.os }}-go-runsim-binary + + test-sim-nondeterminism: + runs-on: ubuntu-latest + needs: Build + steps: + - uses: actions/setup-go@v1 + id: go + with: + go-version: 1.14 + - name: Setup env for GO + # this is only used until the setup-go action is updated + run: | + echo "::set-env name=GOPATH::$(go env GOPATH)" + echo "::add-path::$(go env GOPATH)/bin" + shell: bash + - uses: actions/checkout@v2 + - uses: actions/cache@v1 + with: + path: ~/go/bin + key: ${{ runner.os }}-go-runsim-binary + - name: test nondeterminism + run: | + make test-sim-nondeterminism + + test-sim-import-export: + runs-on: ubuntu-latest + needs: Build + steps: + - uses: actions/setup-go@v1 + id: go + with: + go-version: 1.14 + - name: Setup env for GO + # this is only used until the setup-go action is updated + run: | + echo "::set-env name=GOPATH::$(go env GOPATH)" + echo "::add-path::$(go env GOPATH)/bin" + shell: bash + - uses: actions/checkout@v2 + - uses: actions/cache@v1 + with: + path: ~/go/bin + key: ${{ runner.os }}-go-runsim-binary + - name: test-sim-import-export + run: | + make test-sim-import-export + + test-sim-after-import: + runs-on: ubuntu-latest + needs: Build + steps: + - uses: actions/setup-go@v1 + id: go + with: + go-version: 1.14 + - name: Setup env for GO + # this is only used until the setup-go action is updated + run: | + echo "::set-env name=GOPATH::$(go env GOPATH)" + echo "::add-path::$(go env GOPATH)/bin" + shell: bash + - uses: actions/checkout@v2 + - uses: actions/cache@v1 + with: + path: ~/go/bin + key: ${{ runner.os }}-go-runsim-binary + - name: test after import + run: | + make test-sim-import-export + + test-sim-multi-seed-short: + runs-on: ubuntu-latest + needs: Build + steps: + - uses: actions/setup-go@v1 + id: go + with: + go-version: 1.14 + - name: Setup env for GO + # this is only used until the setup-go action is updated + run: | + echo "::set-env name=GOPATH::$(go env GOPATH)" + echo "::add-path::$(go env GOPATH)/bin" + shell: bash + - uses: actions/checkout@v2 + - uses: actions/cache@v1 + with: + path: ~/go/bin + key: ${{ runner.os }}-go-runsim-binary + - name: test-sim-multi-seed-short + run: | + make test-sim-multi-seed-short From f7f8543dcbbdaf97d2cfc6061da479b182018eae Mon Sep 17 00:00:00 2001 From: Marko Baricevic Date: Fri, 27 Mar 2020 15:37:23 +0100 Subject: [PATCH 488/529] add back multi seed long --- .circleci/config.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index d684e5bcd4fe..7acc25182774 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -86,6 +86,13 @@ jobs: target: proto-gen proto-lint proto-check-breaking description: "Lint and verify Protocol Buffer definitions" + test-sim-multi-seed-long: + executor: golang + steps: + - make: + target: test-sim-multi-seed-long + description: "Test multi-seed simulation (long)" + test-cover: executor: golang parallelism: 4 From 2be5378d2a8260b44b69d2f9ada85bc9434709c8 Mon Sep 17 00:00:00 2001 From: Marko Baricevic Date: Fri, 27 Mar 2020 15:38:55 +0100 Subject: [PATCH 489/529] cleanup redundant ci --- .circleci/config.yml | 5 +---- .github/workflows/sims.yml | 8 ++++++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 7acc25182774..6e65eff6ab79 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -11,7 +11,7 @@ executors: AWS_REGION: us-east-1 protoc: docker: - - image: tendermintdev/docker-protoc + - image: bufbuild/buf commands: make: @@ -79,9 +79,6 @@ jobs: proto: executor: protoc steps: - - make: - target: protoc-gen-gocosmos - description: "Generate go plugin for protoc" - make: target: proto-gen proto-lint proto-check-breaking description: "Lint and verify Protocol Buffer definitions" diff --git a/.github/workflows/sims.yml b/.github/workflows/sims.yml index 73f3de53a7c9..d0b4b0fe7f6c 100644 --- a/.github/workflows/sims.yml +++ b/.github/workflows/sims.yml @@ -1,6 +1,14 @@ name: Sims on: [pull_request] jobs: + cleanup-runs: + runs-on: ubuntu-latest + steps: + - uses: rokroskar/workflow-run-cleanup-action@master + env: + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + if: "!startsWith(github.ref, 'refs/tags/') && github.ref != 'refs/heads/master'" + build: runs-on: ubuntu-latest if: "!contains(github.event.head_commit.message, 'skip-sims')" From 72ceb5cc6c86557f8b103210442e8bc229aaa7ef Mon Sep 17 00:00:00 2001 From: Marko Baricevic Date: Fri, 27 Mar 2020 15:42:27 +0100 Subject: [PATCH 490/529] remove make from proto --- .circleci/config.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 6e65eff6ab79..1d67adbdb18f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -79,8 +79,10 @@ jobs: proto: executor: protoc steps: - - make: - target: proto-gen proto-lint proto-check-breaking + - checkout + - run: + name: proto check + command: make proto-lint && make proto-check-breaking description: "Lint and verify Protocol Buffer definitions" test-sim-multi-seed-long: @@ -165,9 +167,7 @@ workflows: tags: only: - /^v.*/ - - proto: - requires: - - setup-dependencies + - proto - test-sim-multi-seed-long: requires: - setup-dependencies From bb0922d56474ac3dffe26e6b1456dc8f454b8a0d Mon Sep 17 00:00:00 2001 From: Marko Baricevic Date: Fri, 27 Mar 2020 15:43:01 +0100 Subject: [PATCH 491/529] fix circle --- .circleci/config.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1d67adbdb18f..72223908da70 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -83,7 +83,6 @@ jobs: - run: name: proto check command: make proto-lint && make proto-check-breaking - description: "Lint and verify Protocol Buffer definitions" test-sim-multi-seed-long: executor: golang From a4efd33488a4985f1ba3646de5f30c42726cba5e Mon Sep 17 00:00:00 2001 From: Marko Baricevic Date: Fri, 27 Mar 2020 15:46:24 +0100 Subject: [PATCH 492/529] move proto to github actions --- .circleci/config.yml | 8 -------- .github/workflows/proto.yml | 12 ++++++++++++ 2 files changed, 12 insertions(+), 8 deletions(-) create mode 100644 .github/workflows/proto.yml diff --git a/.circleci/config.yml b/.circleci/config.yml index 72223908da70..6a1cce30bc94 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -76,13 +76,6 @@ jobs: key: go-src-v1-{{ .Revision }} paths: - ".git" - proto: - executor: protoc - steps: - - checkout - - run: - name: proto check - command: make proto-lint && make proto-check-breaking test-sim-multi-seed-long: executor: golang @@ -166,7 +159,6 @@ workflows: tags: only: - /^v.*/ - - proto - test-sim-multi-seed-long: requires: - setup-dependencies diff --git a/.github/workflows/proto.yml b/.github/workflows/proto.yml new file mode 100644 index 000000000000..20615373f78e --- /dev/null +++ b/.github/workflows/proto.yml @@ -0,0 +1,12 @@ +name: Proto check +on: [pull_request] +jobs: + proto-checks: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - uses: docker-practice/actions-setup-docker@master + - name: lint + run: docker run -v $(shell pwd):/workspace --workdir /workspace bufbuild/buf check lint --error-format=json + - name: check-breakage + run: docker run -v $(shell pwd):/workspace --workdir /workspace bufbuild/buf --against-input .git#branch=master From 2d459350487563253e695c39f817e5757bf214b7 Mon Sep 17 00:00:00 2001 From: Marko Baricevic Date: Fri, 27 Mar 2020 15:48:30 +0100 Subject: [PATCH 493/529] remove shell --- .github/workflows/proto.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/proto.yml b/.github/workflows/proto.yml index 20615373f78e..9048c1607280 100644 --- a/.github/workflows/proto.yml +++ b/.github/workflows/proto.yml @@ -7,6 +7,6 @@ jobs: - uses: actions/checkout@master - uses: docker-practice/actions-setup-docker@master - name: lint - run: docker run -v $(shell pwd):/workspace --workdir /workspace bufbuild/buf check lint --error-format=json + run: docker run -v pwd:/workspace --workdir /workspace bufbuild/buf check lint --error-format=json - name: check-breakage - run: docker run -v $(shell pwd):/workspace --workdir /workspace bufbuild/buf --against-input .git#branch=master + run: docker run -v pwd:/workspace --workdir /workspace bufbuild/buf --against-input .git#branch=master From db39408c447a2b67f3ffd2aca12da4154fc6df9c Mon Sep 17 00:00:00 2001 From: Marko Baricevic Date: Fri, 27 Mar 2020 15:51:04 +0100 Subject: [PATCH 494/529] test pwd --- .github/workflows/proto.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/proto.yml b/.github/workflows/proto.yml index 9048c1607280..3a8abb632838 100644 --- a/.github/workflows/proto.yml +++ b/.github/workflows/proto.yml @@ -6,7 +6,8 @@ jobs: steps: - uses: actions/checkout@master - uses: docker-practice/actions-setup-docker@master - - name: lint - run: docker run -v pwd:/workspace --workdir /workspace bufbuild/buf check lint --error-format=json - - name: check-breakage - run: docker run -v pwd:/workspace --workdir /workspace bufbuild/buf --against-input .git#branch=master + - run: pwd + # - name: lint + # run: docker run -v pwd:/workspace --workdir /workspace bufbuild/buf check lint --error-format=json + # - name: check-breakage + # run: docker run -v pwd:/workspace --workdir /workspace bufbuild/buf --against-input .git#branch=master From a495e7daee90acb3eb9487fd13ead1e17f13d1de Mon Sep 17 00:00:00 2001 From: Marko Baricevic Date: Fri, 27 Mar 2020 16:04:55 +0100 Subject: [PATCH 495/529] revert proto changes --- .circleci/config.yml | 15 ++++++++++++++- .github/workflows/proto.yml | 13 ------------- 2 files changed, 14 insertions(+), 14 deletions(-) delete mode 100644 .github/workflows/proto.yml diff --git a/.circleci/config.yml b/.circleci/config.yml index 6a1cce30bc94..82ed61fb9558 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -11,7 +11,7 @@ executors: AWS_REGION: us-east-1 protoc: docker: - - image: bufbuild/buf + - image: tendermintdev/docker-protoc commands: make: @@ -77,6 +77,16 @@ jobs: paths: - ".git" + proto: + executor: protoc + steps: + - make: + target: protoc-gen-gocosmos + description: "Generate go plugin for protoc" + - make: + target: proto-gen proto-lint proto-check-breaking + description: "Lint and verify Protocol Buffer definitions" + test-sim-multi-seed-long: executor: golang steps: @@ -172,6 +182,9 @@ workflows: - test-cover: requires: - setup-dependencies + - proto: + requires: + - setup-dependencies - upload-coverage: requires: - test-cover diff --git a/.github/workflows/proto.yml b/.github/workflows/proto.yml deleted file mode 100644 index 3a8abb632838..000000000000 --- a/.github/workflows/proto.yml +++ /dev/null @@ -1,13 +0,0 @@ -name: Proto check -on: [pull_request] -jobs: - proto-checks: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@master - - uses: docker-practice/actions-setup-docker@master - - run: pwd - # - name: lint - # run: docker run -v pwd:/workspace --workdir /workspace bufbuild/buf check lint --error-format=json - # - name: check-breakage - # run: docker run -v pwd:/workspace --workdir /workspace bufbuild/buf --against-input .git#branch=master From 32699c59854c0388bed2b15081c34919e3e68fe7 Mon Sep 17 00:00:00 2001 From: Sahith Reddy Narahari Date: Fri, 27 Mar 2020 21:21:53 +0530 Subject: [PATCH 496/529] Added proto compatible x/slashing clients --- x/slashing/client/cli/tx.go | 53 ++++++++++++++++++++++++++ x/slashing/client/rest/rest.go | 8 ++++ x/slashing/client/rest/tx.go | 68 +++++++++++++++++++++++++++++++--- 3 files changed, 124 insertions(+), 5 deletions(-) diff --git a/x/slashing/client/cli/tx.go b/x/slashing/client/cli/tx.go index 4233d5c7a072..1cf91360b328 100644 --- a/x/slashing/client/cli/tx.go +++ b/x/slashing/client/cli/tx.go @@ -8,6 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/tx" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" @@ -15,7 +16,56 @@ import ( "github.com/cosmos/cosmos-sdk/x/slashing/types" ) +// NewTxCmd returns a root CLI command handler for all x/slashing transaction commands. +func NewTxCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command { + slashingTxCmd := &cobra.Command{ + Use: types.ModuleName, + Short: "Bank transaction subcommands", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + slashingTxCmd.AddCommand(NewUnjailTxCmd(m, txg, ar)) + + return slashingTxCmd +} + +func NewUnjailTxCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command { + cmd := &cobra.Command{ + Use: "unjail", + Args: cobra.NoArgs, + Short: "unjail validator previously jailed for downtime", + Long: `unjail a jailed validator: + +$ tx slashing unjail --from mykey +`, + RunE: func(cmd *cobra.Command, args []string) error { + inBuf := bufio.NewReader(cmd.InOrStdin()) + txf := tx.NewFactoryFromCLI(inBuf). + WithTxGenerator(txg). + WithAccountRetriever(ar) + + cliCtx := context.NewCLIContextWithInputAndFrom(inBuf, args[0]).WithMarshaler(m) + + valAddr := cliCtx.GetFromAddress() + msg := types.NewMsgUnjail(sdk.ValAddress(valAddr)) + return tx.GenerateOrBroadcastTx(cliCtx, txf, msg) + }, + } + return flags.PostCommands(cmd)[0] +} + +// --------------------------------------------------------------------------- +// Deprecated +// +// TODO: Remove once client-side Protobuf migration has been completed. +// --------------------------------------------------------------------------- + // GetTxCmd returns the transaction commands for this module +// +// TODO: Remove once client-side Protobuf migration has been completed. +// ref: https://github.com/cosmos/cosmos-sdk/issues/5864 func GetTxCmd(cdc *codec.Codec) *cobra.Command { slashingTxCmd := &cobra.Command{ Use: types.ModuleName, @@ -33,6 +83,9 @@ func GetTxCmd(cdc *codec.Codec) *cobra.Command { } // GetCmdUnjail implements the create unjail validator command. +// +// TODO: Remove once client-side Protobuf migration has been completed. +// ref: https://github.com/cosmos/cosmos-sdk/issues/5864 func GetCmdUnjail(cdc *codec.Codec) *cobra.Command { return &cobra.Command{ Use: "unjail", diff --git a/x/slashing/client/rest/rest.go b/x/slashing/client/rest/rest.go index 4237d59e258a..78e2a99f747f 100644 --- a/x/slashing/client/rest/rest.go +++ b/x/slashing/client/rest/rest.go @@ -4,8 +4,16 @@ import ( "github.com/gorilla/mux" "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/tx" + "github.com/cosmos/cosmos-sdk/codec" ) +func RegisterHandlers(ctx context.CLIContext, m codec.Marshaler, txg tx.Generator, r *mux.Router) { + registerQueryRoutes(ctx, r) + registerTxHandlers(ctx, m, txg, r) + +} + // RegisterRoutes registers staking-related REST handlers to a router func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router) { registerQueryRoutes(cliCtx, r) diff --git a/x/slashing/client/rest/tx.go b/x/slashing/client/rest/tx.go index 9498ea8ba5ff..21d8435bf651 100644 --- a/x/slashing/client/rest/tx.go +++ b/x/slashing/client/rest/tx.go @@ -7,17 +7,16 @@ import ( "github.com/gorilla/mux" "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/tx" + "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/rest" authclient "github.com/cosmos/cosmos-sdk/x/auth/client" "github.com/cosmos/cosmos-sdk/x/slashing/types" ) -func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router) { - r.HandleFunc( - "/slashing/validators/{validatorAddr}/unjail", - unjailRequestHandlerFn(cliCtx), - ).Methods("POST") +func registerTxHandlers(ctx context.CLIContext, m codec.Marshaler, txg tx.Generator, r *mux.Router) { + r.HandleFunc("/slashing/validators/{validatorAddr}/unjail", NewUnjailRequestHandlerFn(ctx, m, txg)).Methods("POST") } // Unjail TX body @@ -25,6 +24,65 @@ type UnjailReq struct { BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` } +// NewUnjailRequestHandlerFn returns an HTTP REST handler for creating a MsgUnjail +// transaction. +func NewUnjailRequestHandlerFn(ctx context.CLIContext, m codec.Marshaler, txg tx.Generator) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + ctx = ctx.WithMarshaler(m) + + vars := mux.Vars(r) + bech32Validator := vars["validatorAddr"] + + var req UnjailReq + if !rest.ReadRESTReq(w, r, ctx.Marshaler, &req) { + return + } + + req.BaseReq = req.BaseReq.Sanitize() + if !req.BaseReq.ValidateBasic(w) { + return + } + + fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + valAddr, err := sdk.ValAddressFromBech32(bech32Validator) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + + if !bytes.Equal(fromAddr, valAddr) { + rest.WriteErrorResponse(w, http.StatusUnauthorized, "must use own validator address") + return + } + + msg := types.NewMsgUnjail(valAddr) + err = msg.ValidateBasic() + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + tx.WriteGeneratedTxResponse(ctx, w, txg, req.BaseReq, msg) + } +} + +// --------------------------------------------------------------------------- +// Deprecated +// +// TODO: Remove once client-side Protobuf migration has been completed. +// --------------------------------------------------------------------------- +// ref: https://github.com/cosmos/cosmos-sdk/issues/5864 +func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router) { + r.HandleFunc( + "/slashing/validators/{validatorAddr}/unjail", + unjailRequestHandlerFn(cliCtx), + ).Methods("POST") +} + func unjailRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) From f4dd7f5a521eadbf64b5681902c961dd18d8341d Mon Sep 17 00:00:00 2001 From: Sahith Reddy Narahari Date: Fri, 27 Mar 2020 22:55:56 +0530 Subject: [PATCH 497/529] Did minor code cleanup --- x/bank/client/cli/tx.go | 3 +-- x/slashing/client/cli/tx.go | 1 - x/slashing/client/rest/rest.go | 1 - x/slashing/client/rest/tx.go | 1 - 4 files changed, 1 insertion(+), 5 deletions(-) diff --git a/x/bank/client/cli/tx.go b/x/bank/client/cli/tx.go index 92341a371a5f..3925da637954 100644 --- a/x/bank/client/cli/tx.go +++ b/x/bank/client/cli/tx.go @@ -9,7 +9,6 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/tx" - clientx "github.com/cosmos/cosmos-sdk/client/tx" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" @@ -57,7 +56,7 @@ func NewSendTxCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) * } msg := types.NewMsgSend(cliCtx.GetFromAddress(), toAddr, coins) - return clientx.GenerateOrBroadcastTx(cliCtx, txf, msg) + return tx.GenerateOrBroadcastTx(cliCtx, txf, msg) }, } diff --git a/x/slashing/client/cli/tx.go b/x/slashing/client/cli/tx.go index 1cf91360b328..9d8ea841d296 100644 --- a/x/slashing/client/cli/tx.go +++ b/x/slashing/client/cli/tx.go @@ -27,7 +27,6 @@ func NewTxCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobr } slashingTxCmd.AddCommand(NewUnjailTxCmd(m, txg, ar)) - return slashingTxCmd } diff --git a/x/slashing/client/rest/rest.go b/x/slashing/client/rest/rest.go index 78e2a99f747f..d4c500f84c94 100644 --- a/x/slashing/client/rest/rest.go +++ b/x/slashing/client/rest/rest.go @@ -11,7 +11,6 @@ import ( func RegisterHandlers(ctx context.CLIContext, m codec.Marshaler, txg tx.Generator, r *mux.Router) { registerQueryRoutes(ctx, r) registerTxHandlers(ctx, m, txg, r) - } // RegisterRoutes registers staking-related REST handlers to a router diff --git a/x/slashing/client/rest/tx.go b/x/slashing/client/rest/tx.go index 21d8435bf651..f0ce72c6ae6d 100644 --- a/x/slashing/client/rest/tx.go +++ b/x/slashing/client/rest/tx.go @@ -29,7 +29,6 @@ type UnjailReq struct { func NewUnjailRequestHandlerFn(ctx context.CLIContext, m codec.Marshaler, txg tx.Generator) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { ctx = ctx.WithMarshaler(m) - vars := mux.Vars(r) bech32Validator := vars["validatorAddr"] From 0ba4e3a630ac97e9d7a5b3ae210f8e7504392bef Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Sat, 28 Mar 2020 00:19:44 +0100 Subject: [PATCH 498/529] types/errors: make Wrap() work like github.com/pkg/errors.Wrap Wrap(ErrInsufficientFunds, "40 < 500") returns strings like "insufficient funds: 40 < 50". Although he function syntax fits perfectly SDK app developers use case and as such it should not be changed, the interface is still counter-intuitive as most Golang developers may reasonably expect a different result similar to what other popular libraries' (see [1]) would produce (e.g. "40 < 500: insufficient funds"). Follow up PR of #5876. [1] https://godoc.org/github.com/pkg/errors#Wrapf --- types/errors/abci_test.go | 33 +++++++++++---------------------- types/errors/errors.go | 2 +- types/errors/errors_test.go | 25 +++++++++++++++++++++++++ types/errors/stacktrace_test.go | 8 ++++---- 4 files changed, 41 insertions(+), 27 deletions(-) diff --git a/types/errors/abci_test.go b/types/errors/abci_test.go index 9b9e8280aac7..6e89d83cdda0 100644 --- a/types/errors/abci_test.go +++ b/types/errors/abci_test.go @@ -28,7 +28,7 @@ func TestABCInfo(t *testing.T) { "wrapped SDK error": { err: Wrap(Wrap(ErrUnauthorized, "foo"), "bar"), debug: false, - wantLog: "unauthorized: foo: bar", + wantLog: "bar: foo: unauthorized", wantCode: ErrUnauthorized.code, wantSpace: RootCodespace, }, @@ -95,15 +95,9 @@ func TestABCInfo(t *testing.T) { tc := tc t.Run(testName, func(t *testing.T) { space, code, log := ABCIInfo(tc.err, tc.debug) - if space != tc.wantSpace { - t.Errorf("want %s space, got %s", tc.wantSpace, space) - } - if code != tc.wantCode { - t.Errorf("want %d code, got %d", tc.wantCode, code) - } - if log != tc.wantLog { - t.Errorf("want %q log, got %q", tc.wantLog, log) - } + require.Equal(t, tc.wantSpace, space) + require.Equal(t, tc.wantCode, code) + require.Equal(t, tc.wantLog, log) }) } } @@ -119,19 +113,19 @@ func TestABCIInfoStacktrace(t *testing.T) { err: Wrap(ErrUnauthorized, "wrapped"), debug: true, wantStacktrace: true, - wantErrMsg: "unauthorized: wrapped", + wantErrMsg: "wrapped: unauthorized", }, "wrapped SDK error in non-debug mode does not have stacktrace": { err: Wrap(ErrUnauthorized, "wrapped"), debug: false, wantStacktrace: false, - wantErrMsg: "unauthorized: wrapped", + wantErrMsg: "wrapped: unauthorized", }, "wrapped stdlib error in debug mode provides stacktrace": { err: Wrap(fmt.Errorf("stdlib"), "wrapped"), debug: true, wantStacktrace: true, - wantErrMsg: "stdlib: wrapped", + wantErrMsg: "wrapped: stdlib", }, "wrapped stdlib error in non-debug mode does not have stacktrace": { err: Wrap(fmt.Errorf("stdlib"), "wrapped"), @@ -165,10 +159,7 @@ func TestABCIInfoStacktrace(t *testing.T) { func TestABCIInfoHidesStacktrace(t *testing.T) { err := Wrap(ErrUnauthorized, "wrapped") _, _, log := ABCIInfo(err, false) - - if log != "unauthorized: wrapped" { - t.Fatalf("unexpected message in non debug mode: %s", log) - } + require.Equal(t, "wrapped: unauthorized", log) } func TestRedact(t *testing.T) { @@ -208,12 +199,12 @@ func TestABCIInfoSerializeErr(t *testing.T) { "single error": { src: myErrDecode, debug: false, - exp: "tx parse error: test", + exp: "test: tx parse error", }, "second error": { src: myErrAddr, debug: false, - exp: "invalid address: tester", + exp: "tester: invalid address", }, "single error with debug": { src: myErrDecode, @@ -260,9 +251,7 @@ func TestABCIInfoSerializeErr(t *testing.T) { spec := spec t.Run(msg, func(t *testing.T) { _, _, log := ABCIInfo(spec.src, spec.debug) - if exp, got := spec.exp, log; exp != got { - t.Errorf("expected %v but got %v", exp, got) - } + require.Equal(t, spec.exp, log) }) } } diff --git a/types/errors/errors.go b/types/errors/errors.go index a781a4cdd3b9..f881a2827b13 100644 --- a/types/errors/errors.go +++ b/types/errors/errors.go @@ -262,7 +262,7 @@ type wrappedError struct { } func (e *wrappedError) Error() string { - return fmt.Sprintf("%s: %s", e.parent.Error(), e.msg) + return fmt.Sprintf("%s: %s", e.msg, e.parent.Error()) } func (e *wrappedError) Cause() error { diff --git a/types/errors/errors_test.go b/types/errors/errors_test.go index f6e6e8cd7f52..d618902c55b8 100644 --- a/types/errors/errors_test.go +++ b/types/errors/errors_test.go @@ -208,3 +208,28 @@ func TestWrappedUnwrapFail(t *testing.T) { err := Wrap(errTest2, Wrap(errTest, "some random description").Error()) require.NotEqual(t, errTest, stdlib.Unwrap(err)) } + +func TestABCIError(t *testing.T) { + require.Equal(t, "custom: tx parse error", ABCIError(RootCodespace, 2, "custom").Error()) + require.Equal(t, "custom: unknown", ABCIError("unknown", 1, "custom").Error()) +} + +func ExampleWrap() { + err1 := Wrap(ErrInsufficientFunds, "90 is smaller than 100") + err2 := errors.Wrap(ErrInsufficientFunds, "90 is smaller than 100") + fmt.Println(err1.Error()) + fmt.Println(err2.Error()) + // Output: + // 90 is smaller than 100: insufficient funds + // 90 is smaller than 100: insufficient funds +} + +func ExampleWrapf() { + err1 := Wrap(ErrInsufficientFunds, "90 is smaller than 100") + err2 := errors.Wrap(ErrInsufficientFunds, "90 is smaller than 100") + fmt.Println(err1.Error()) + fmt.Println(err2.Error()) + // Output: + // 90 is smaller than 100: insufficient funds + // 90 is smaller than 100: insufficient funds +} diff --git a/types/errors/stacktrace_test.go b/types/errors/stacktrace_test.go index 042edc0b6919..bef4bccb704e 100644 --- a/types/errors/stacktrace_test.go +++ b/types/errors/stacktrace_test.go @@ -15,19 +15,19 @@ func TestStackTrace(t *testing.T) { }{ "New gives us a stacktrace": { err: Wrap(ErrNoSignatures, "name"), - wantError: "no signatures supplied: name", + wantError: "name: no signatures supplied", }, "Wrapping stderr gives us a stacktrace": { err: Wrap(fmt.Errorf("foo"), "standard"), - wantError: "foo: standard", + wantError: "standard: foo", }, "Wrapping pkg/errors gives us clean stacktrace": { err: Wrap(errors.New("bar"), "pkg"), - wantError: "bar: pkg", + wantError: "pkg: bar", }, "Wrapping inside another function is still clean": { err: Wrap(fmt.Errorf("indirect"), "do the do"), - wantError: "indirect: do the do", + wantError: "do the do: indirect", }, } From b6c45b76a77abff4ee729c19a08e492941ba19db Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 30 Mar 2020 10:49:54 -0300 Subject: [PATCH 499/529] Bump github.com/spf13/cobra from 0.0.6 to 0.0.7 (#5891) Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 0.0.6 to 0.0.7. - [Release notes](https://github.com/spf13/cobra/releases) - [Commits](https://github.com/spf13/cobra/compare/v0.0.6...0.0.7) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 836c9d81088e..79db3d450f75 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/rakyll/statik v0.1.7 github.com/regen-network/cosmos-proto v0.1.1-0.20200213154359-02baa11ea7c2 github.com/spf13/afero v1.2.1 // indirect - github.com/spf13/cobra v0.0.6 + github.com/spf13/cobra v0.0.7 github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.6.2 diff --git a/go.sum b/go.sum index 69f6ec57f93d..5a22393f253f 100644 --- a/go.sum +++ b/go.sum @@ -377,6 +377,8 @@ github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.6 h1:breEStsVwemnKh2/s6gMvSdMEkwW0sK8vGStnlVBMCs= github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/cobra v0.0.7 h1:FfTH+vuMXOas8jmfb5/M7dzEYx7LpcLb7a0LPe34uOU= +github.com/spf13/cobra v0.0.7/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= From db76afe840d785b91864a63a1649fd796512d518 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Mon, 30 Mar 2020 16:54:01 +0200 Subject: [PATCH 500/529] crypto/keyring: change addrKey to store chain-agnostic addresses (#5858) Keyrings store keys by name and hexbytes representation of address. This turns keyring internal storage more chain-agnostic and types.Config independent. Obsolete Keybase internal state representation is not affected. --- CHANGELOG.md | 7 ++++--- client/keys/add.go | 2 +- client/keys/list.go | 4 ++-- client/keys/parse.go | 18 ++++++++-------- client/keys/parse_test.go | 2 +- client/keys/show.go | 40 +++++++++++++++++++++++++----------- client/keys/show_test.go | 10 +++++++-- client/keys/utils.go | 27 ++++++++++++------------ crypto/keyring/db_keybase.go | 14 +++++++++---- crypto/keyring/keyring.go | 8 ++++---- 10 files changed, 82 insertions(+), 50 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1505a53da4bb..a0356406f9b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -69,13 +69,14 @@ and provided directly the IAVL store. * (modules) [\#5572](https://github.com/cosmos/cosmos-sdk/pull/5572) Move account balance logic and APIs from `x/auth` to `x/bank`. * (types) [\#5533](https://github.com/cosmos/cosmos-sdk/pull/5533) Refactored `AppModuleBasic` and `AppModuleGenesis` to now accept a `codec.JSONMarshaler` for modular serialization of genesis state. -* (crypto/keys) [\#5735](https://github.com/cosmos/cosmos-sdk/pull/5735) Keyring's `Update()` function is now no-op. +* (crypto/keyring) [\#5735](https://github.com/cosmos/cosmos-sdk/pull/5735) Keyring's `Update()` function is now no-op. * (types/rest) [\#5779](https://github.com/cosmos/cosmos-sdk/pull/5779) Drop unused Parse{Int64OrReturnBadRequest,QueryParamBool}() functions. * (keys) [\#5820](https://github.com/cosmos/cosmos-sdk/pull/5820/) Removed method CloseDB from Keybase interface. * (baseapp) [\#5837](https://github.com/cosmos/cosmos-sdk/issues/5837) Transaction simulation now returns a `SimulationResponse` which contains the `GasInfo` and `Result` from the execution. -* (crypto/keys) [\#5866](https://github.com/cosmos/cosmos-sdk/pull/5866) Move `Keyring` and `Keybase` implementations and their associated types from `crypto/keys/` to `crypto/keybase/`. +* (crypto/keyring) [\#5866](https://github.com/cosmos/cosmos-sdk/pull/5866) Move `Keyring` and `Keybase` implementations and their associated types from `crypto/keys/` to `crypto/keyring/`. * (crypto) [\#5880](https://github.com/cosmos/cosmos-sdk/pull/5880) Merge `crypto/keys/mintkey` into `crypto`. +* (crypto/keyring) [\#5858](https://github.com/cosmos/cosmos-sdk/pull/5858) Make Keyring store keys by name and address's hexbytes representation. ### Features @@ -85,7 +86,7 @@ to now accept a `codec.JSONMarshaler` for modular serialization of genesis state * (types) [\#5741](https://github.com/cosmos/cosmos-sdk/issues/5741) Prevent ChainAnteDecorators() from panicking when empty AnteDecorator slice is supplied. * (modules) [\#5569](https://github.com/cosmos/cosmos-sdk/issues/5569) `InitGenesis`, for the relevant modules, now ensures module accounts exist. -* (crypto/keys) [\#5844](https://github.com/cosmos/cosmos-sdk/pull/5844) Keybase/Keyring `Sign()` methods no longer decode amino signatures +* (crypto/keyring) [\#5844](https://github.com/cosmos/cosmos-sdk/pull/5844) Keybase/Keyring `Sign()` methods no longer decode amino signatures when method receivers are offline/multisig keys. ### State Machine Breaking diff --git a/client/keys/add.go b/client/keys/add.go index d8f768cc4f14..530431eb808d 100644 --- a/client/keys/add.go +++ b/client/keys/add.go @@ -291,7 +291,7 @@ func printCreate(cmd *cobra.Command, info keyring.Info, showMnemonic bool, mnemo switch output { case OutputFormatText: cmd.PrintErrln() - printKeyInfo(info, keyring.Bech32KeyOutput) + printKeyInfo(cmd.OutOrStdout(), info, keyring.Bech32KeyOutput) // print mnemonic unless requested not to. if showMnemonic { diff --git a/client/keys/list.go b/client/keys/list.go index 8af7f97154d1..770bde2f1465 100644 --- a/client/keys/list.go +++ b/client/keys/list.go @@ -36,12 +36,12 @@ func runListCmd(cmd *cobra.Command, _ []string) error { return err } + cmd.SetOut(cmd.OutOrStdout()) if !viper.GetBool(flagListNames) { - printInfos(infos) + printInfos(cmd.OutOrStdout(), infos) return nil } - cmd.SetOut(cmd.OutOrStdout()) for _, info := range infos { cmd.Println(info.GetName()) } diff --git a/client/keys/parse.go b/client/keys/parse.go index 79ccca739f0a..5167cd810084 100644 --- a/client/keys/parse.go +++ b/client/keys/parse.go @@ -4,6 +4,7 @@ import ( "encoding/hex" "errors" "fmt" + "io" "strings" "github.com/spf13/cobra" @@ -83,38 +84,39 @@ hexadecimal into bech32 cosmos prefixed format and vice versa. return cmd } -func parseKey(_ *cobra.Command, args []string) error { +func parseKey(cmd *cobra.Command, args []string) error { addr := strings.TrimSpace(args[0]) + outstream := cmd.OutOrStdout() if len(addr) == 0 { return errors.New("couldn't parse empty input") } - if !(runFromBech32(addr) || runFromHex(addr)) { + if !(runFromBech32(outstream, addr) || runFromHex(outstream, addr)) { return errors.New("couldn't find valid bech32 nor hex data") } return nil } // print info from bech32 -func runFromBech32(bech32str string) bool { +func runFromBech32(w io.Writer, bech32str string) bool { hrp, bz, err := bech32.DecodeAndConvert(bech32str) if err != nil { return false } - displayParseKeyInfo(newHexOutput(hrp, bz)) + displayParseKeyInfo(w, newHexOutput(hrp, bz)) return true } // print info from hex -func runFromHex(hexstr string) bool { +func runFromHex(w io.Writer, hexstr string) bool { bz, err := hex.DecodeString(hexstr) if err != nil { return false } - displayParseKeyInfo(newBech32Output(bz)) + displayParseKeyInfo(w, newBech32Output(bz)) return true } -func displayParseKeyInfo(stringer fmt.Stringer) { +func displayParseKeyInfo(w io.Writer, stringer fmt.Stringer) { var out []byte var err error @@ -136,5 +138,5 @@ func displayParseKeyInfo(stringer fmt.Stringer) { panic(err) } - fmt.Println(string(out)) + fmt.Fprintln(w, string(out)) } diff --git a/client/keys/parse_test.go b/client/keys/parse_test.go index 759deb386c75..2f2941b82f90 100644 --- a/client/keys/parse_test.go +++ b/client/keys/parse_test.go @@ -23,7 +23,7 @@ func TestParseKey(t *testing.T) { for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { - require.Equal(t, tt.wantErr, parseKey(nil, tt.args) != nil) + require.Equal(t, tt.wantErr, parseKey(ParseKeyStringCommand(), tt.args) != nil) }) } } diff --git a/client/keys/show.go b/client/keys/show.go index f4e6cc1fbe5d..c423caa1aaea 100644 --- a/client/keys/show.go +++ b/client/keys/show.go @@ -35,10 +35,10 @@ const ( // ShowKeysCmd shows key information for a given key name. func ShowKeysCmd() *cobra.Command { cmd := &cobra.Command{ - Use: "show [name [name...]]", - Short: "Show key info for the given name", - Long: `Return public details of a single local key. If multiple names are -provided, then an ephemeral multisig key will be created under the name "multi" + Use: "show [name_or_address [name_or_address...]]", + Short: "Retrieve key information by name or address", + Long: `Display keys details. If multiple names or addresses are provided, +then an ephemeral multisig key will be created under the name "multi" consisting of all the keys provided by name and multisig threshold.`, Args: cobra.MinimumNArgs(1), RunE: runShowCmd, @@ -62,16 +62,16 @@ func runShowCmd(cmd *cobra.Command, args []string) (err error) { return err } if len(args) == 1 { - info, err = kb.Get(args[0]) + info, err = fetchKey(kb, args[0]) if err != nil { - return err + return fmt.Errorf("%s is not a valid name or address: %v", args[0], err) } } else { pks := make([]tmcrypto.PubKey, len(args)) - for i, keyName := range args { - info, err := kb.Get(keyName) + for i, keyref := range args { + info, err := fetchKey(kb, keyref) if err != nil { - return err + return fmt.Errorf("%s is not a valid name or address: %v", keyref, err) } pks[i] = info.GetPubKey() @@ -112,11 +112,11 @@ func runShowCmd(cmd *cobra.Command, args []string) (err error) { switch { case isShowAddr: - printKeyAddress(info, bechKeyOut) + printKeyAddress(cmd.OutOrStdout(), info, bechKeyOut) case isShowPubKey: - printPubKey(info, bechKeyOut) + printPubKey(cmd.OutOrStdout(), info, bechKeyOut) default: - printKeyInfo(info, bechKeyOut) + printKeyInfo(cmd.OutOrStdout(), info, bechKeyOut) } if isShowDevice { @@ -142,6 +142,22 @@ func runShowCmd(cmd *cobra.Command, args []string) (err error) { return nil } +func fetchKey(kb keyring.Keybase, keyref string) (keyring.Info, error) { + info, err := kb.Get(keyref) + if err != nil { + accAddr, err := sdk.AccAddressFromBech32(keyref) + if err != nil { + return info, err + } + + info, err = kb.GetByAddress(accAddr) + if err != nil { + return info, errors.New("key not found") + } + } + return info, nil +} + func validateMultisigThreshold(k, nKeys int) error { if k <= 0 { return fmt.Errorf("threshold must be a positive integer") diff --git a/client/keys/show_test.go b/client/keys/show_test.go index f7b35cb3d3e0..fe1070e1ffb7 100644 --- a/client/keys/show_test.go +++ b/client/keys/show_test.go @@ -38,8 +38,8 @@ func Test_runShowCmd(t *testing.T) { runningUnattended := isRunningUnattended() cmd := ShowKeysCmd() mockIn, _, _ := tests.ApplyMockIO(cmd) - require.EqualError(t, runShowCmd(cmd, []string{"invalid"}), "The specified item could not be found in the keyring") - require.EqualError(t, runShowCmd(cmd, []string{"invalid1", "invalid2"}), "The specified item could not be found in the keyring") + require.EqualError(t, runShowCmd(cmd, []string{"invalid"}), "invalid is not a valid name or address: decoding bech32 failed: invalid bech32 string length 7") + require.EqualError(t, runShowCmd(cmd, []string{"invalid1", "invalid2"}), "invalid1 is not a valid name or address: decoding bech32 failed: invalid index of 1") // Prepare a key base // Now add a temporary keybase @@ -78,7 +78,13 @@ func Test_runShowCmd(t *testing.T) { if runningUnattended { mockIn.Reset("testpass1\n") } + + // try fetch by name require.NoError(t, runShowCmd(cmd, []string{fakeKeyName1})) + // try fetch by addr + info, err := kb.Get(fakeKeyName1) + require.NoError(t, err) + require.NoError(t, runShowCmd(cmd, []string{info.GetAddress().String()})) // Now try multisig key - set bech to acc viper.Set(FlagBechPrefix, sdk.PrefixAccount) diff --git a/client/keys/utils.go b/client/keys/utils.go index a6dc78ecb183..4581d6861603 100644 --- a/client/keys/utils.go +++ b/client/keys/utils.go @@ -2,12 +2,13 @@ package keys import ( "fmt" + "io" "path/filepath" "github.com/99designs/keyring" "github.com/spf13/viper" "github.com/tendermint/tendermint/libs/cli" - yaml "gopkg.in/yaml.v2" + "gopkg.in/yaml.v2" "github.com/cosmos/cosmos-sdk/client/flags" cryptokeyring "github.com/cosmos/cosmos-sdk/crypto/keyring" @@ -37,7 +38,7 @@ func getLazyKeyBaseFromDir(rootDir string, opts ...cryptokeyring.KeybaseOption) return cryptokeyring.New(defaultKeyDBName, filepath.Join(rootDir, "keys"), opts...), nil } -func printKeyInfo(keyInfo cryptokeyring.Info, bechKeyOut bechKeyOutFn) { +func printKeyInfo(w io.Writer, keyInfo cryptokeyring.Info, bechKeyOut bechKeyOutFn) { ko, err := bechKeyOut(keyInfo) if err != nil { panic(err) @@ -45,7 +46,7 @@ func printKeyInfo(keyInfo cryptokeyring.Info, bechKeyOut bechKeyOutFn) { switch viper.Get(cli.OutputFlag) { case OutputFormatText: - printTextInfos([]cryptokeyring.KeyOutput{ko}) + printTextInfos(w, []cryptokeyring.KeyOutput{ko}) case OutputFormatJSON: var out []byte @@ -59,11 +60,11 @@ func printKeyInfo(keyInfo cryptokeyring.Info, bechKeyOut bechKeyOutFn) { panic(err) } - fmt.Println(string(out)) + fmt.Fprintln(w, string(out)) } } -func printInfos(infos []cryptokeyring.Info) { +func printInfos(w io.Writer, infos []cryptokeyring.Info) { kos, err := cryptokeyring.Bech32KeysOutput(infos) if err != nil { panic(err) @@ -71,7 +72,7 @@ func printInfos(infos []cryptokeyring.Info) { switch viper.Get(cli.OutputFlag) { case OutputFormatText: - printTextInfos(kos) + printTextInfos(w, kos) case OutputFormatJSON: var out []byte @@ -86,34 +87,34 @@ func printInfos(infos []cryptokeyring.Info) { if err != nil { panic(err) } - fmt.Printf("%s", out) + fmt.Fprintf(w, "%s", out) } } -func printTextInfos(kos []cryptokeyring.KeyOutput) { +func printTextInfos(w io.Writer, kos []cryptokeyring.KeyOutput) { out, err := yaml.Marshal(&kos) if err != nil { panic(err) } - fmt.Println(string(out)) + fmt.Fprintln(w, string(out)) } -func printKeyAddress(info cryptokeyring.Info, bechKeyOut bechKeyOutFn) { +func printKeyAddress(w io.Writer, info cryptokeyring.Info, bechKeyOut bechKeyOutFn) { ko, err := bechKeyOut(info) if err != nil { panic(err) } - fmt.Println(ko.Address) + fmt.Fprintln(w, ko.Address) } -func printPubKey(info cryptokeyring.Info, bechKeyOut bechKeyOutFn) { +func printPubKey(w io.Writer, info cryptokeyring.Info, bechKeyOut bechKeyOutFn) { ko, err := bechKeyOut(info) if err != nil { panic(err) } - fmt.Println(ko.PubKey) + fmt.Fprintln(w, ko.PubKey) } func isRunningUnattended() bool { diff --git a/crypto/keyring/db_keybase.go b/crypto/keyring/db_keybase.go index 4a09cc4afb24..0ed7cbfd927a 100644 --- a/crypto/keyring/db_keybase.go +++ b/crypto/keyring/db_keybase.go @@ -1,6 +1,7 @@ package keyring import ( + "encoding/hex" "fmt" "reflect" "strings" @@ -126,7 +127,7 @@ func (kb dbKeybase) Get(name string) (Info, error) { // GetByAddress returns Info based on a provided AccAddress. An error is returned // if the address does not exist. func (kb dbKeybase) GetByAddress(address types.AccAddress) (Info, error) { - ik, err := kb.db.Get(addrKey(address)) + ik, err := kb.db.Get(addrStringKey(address)) if err != nil { return nil, err } @@ -344,7 +345,7 @@ func (kb dbKeybase) Delete(name, passphrase string, skipPass bool) error { batch := kb.db.NewBatch() defer batch.Close() - batch.Delete(addrKey(info.GetAddress())) + batch.Delete(addrStringKey(info.GetAddress())) batch.Delete(infoKey(name)) return batch.WriteSync() @@ -414,13 +415,18 @@ func (kb dbKeybase) writeInfo(name string, info Info) { kb.db.SetSync(key, serializedInfo) // store a pointer to the infokey by address for fast lookup - kb.db.SetSync(addrKey(info.GetAddress()), key) + kb.db.SetSync(addrStringKey(info.GetAddress()), key) } -func addrKey(address types.AccAddress) []byte { +// this is to be removed together with dbKeybase and the old Keybase interface +func addrStringKey(address types.AccAddress) []byte { return []byte(fmt.Sprintf("%s.%s", address.String(), addressSuffix)) } +func addrHexKey(address types.AccAddress) []byte { + return []byte(fmt.Sprintf("%s.%s", hex.EncodeToString(address.Bytes()), addressSuffix)) +} + func infoKey(name string) []byte { return []byte(fmt.Sprintf("%s.%s", name, infoSuffix)) } diff --git a/crypto/keyring/keyring.go b/crypto/keyring/keyring.go index 1752c099ba16..c48e0ba4a9c7 100644 --- a/crypto/keyring/keyring.go +++ b/crypto/keyring/keyring.go @@ -178,7 +178,7 @@ func (kb keyringKeybase) Get(name string) (Info, error) { // GetByAddress fetches a key by address and returns its public information. func (kb keyringKeybase) GetByAddress(address types.AccAddress) (Info, error) { - ik, err := kb.db.Get(string(addrKey(address))) + ik, err := kb.db.Get(string(addrHexKey(address))) if err != nil { return nil, err } @@ -313,7 +313,7 @@ func (kb keyringKeybase) Import(name string, armor string) error { kb.writeInfo(name, info) err = kb.db.Set(keyring.Item{ - Key: string(addrKey(info.GetAddress())), + Key: string(addrHexKey(info.GetAddress())), Data: infoKey(name), }) if err != nil { @@ -401,7 +401,7 @@ func (kb keyringKeybase) Delete(name, _ string, _ bool) error { return err } - err = kb.db.Remove(string(addrKey(info.GetAddress()))) + err = kb.db.Remove(string(addrHexKey(info.GetAddress()))) if err != nil { return err } @@ -454,7 +454,7 @@ func (kb keyringKeybase) writeInfo(name string, info Info) { } err = kb.db.Set(keyring.Item{ - Key: string(addrKey(info.GetAddress())), + Key: string(addrHexKey(info.GetAddress())), Data: key, }) if err != nil { From 2a7a408d358e1343994e2b016a126b229957ffb4 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Mon, 30 Mar 2020 20:30:50 +0200 Subject: [PATCH 501/529] crypto/keyring: deprecate old keybase (#5889) Remove the Update method from the Keybase interface. Remove redundant lazy keybase implementation altogether. Created LegacyKeybase interface to restrict capabilities to only those required by keys commands that deal with legacy keybase such as update and migrate. Rename keyring.New() -> keyring.NewLegacy(). Rename client/keys.NewKeyBaseFromDir -> NewLegacyKeyBaseFromDir. crypto/keyiring.NewInMemory() now returns a in-memory keyring. BackendMemory is added yet not exposed via command line --keyring-backend flag. keys add uses it when --dry-run flag is on. --- CHANGELOG.md | 6 + client/keys/add.go | 9 +- client/keys/add_ledger_test.go | 8 - client/keys/add_test.go | 43 +- client/keys/delete_test.go | 44 +- client/keys/export_test.go | 20 +- client/keys/import_test.go | 19 +- client/keys/list_test.go | 10 - client/keys/migrate.go | 4 +- client/keys/root.go | 1 - client/keys/root_test.go | 2 +- client/keys/show_test.go | 28 - client/keys/testdata/keys/keys.db/000002.ldb | Bin 0 -> 391 bytes client/keys/testdata/keys/keys.db/CURRENT | 1 + client/keys/testdata/keys/keys.db/CURRENT.bak | 1 + client/keys/testdata/keys/keys.db/LOCK | 0 client/keys/testdata/keys/keys.db/LOG | 18 + .../testdata/keys/keys.db/MANIFEST-000004 | Bin 0 -> 237 bytes client/keys/update.go | 55 -- client/keys/update_test.go | 58 -- client/keys/utils.go | 19 +- crypto/keyring/base_keybase.go | 4 +- crypto/keyring/db_keybase.go | 432 ------------ crypto/keyring/doc.go | 9 +- crypto/keyring/keybase.go | 3 - crypto/keyring/keybase_test.go | 495 -------------- crypto/keyring/keyring.go | 22 +- crypto/keyring/keyring_test.go | 631 +++++++++++++++++- crypto/keyring/lazy_keybase.go | 221 ------ crypto/keyring/lazy_keybase_test.go | 453 ------------- crypto/keyring/legacy.go | 188 ++++++ crypto/keyring/legacy_test.go | 44 ++ .../keyring/testdata/keys/keys.db/000002.ldb | Bin 0 -> 391 bytes crypto/keyring/testdata/keys/keys.db/CURRENT | 1 + .../keyring/testdata/keys/keys.db/CURRENT.bak | 1 + crypto/keyring/testdata/keys/keys.db/LOCK | 0 crypto/keyring/testdata/keys/keys.db/LOG | 18 + .../testdata/keys/keys.db/MANIFEST-000004 | Bin 0 -> 237 bytes go.mod | 1 + go.sum | 8 + server/init.go | 3 +- server/init_test.go | 5 +- 42 files changed, 976 insertions(+), 1909 deletions(-) create mode 100644 client/keys/testdata/keys/keys.db/000002.ldb create mode 100644 client/keys/testdata/keys/keys.db/CURRENT create mode 100644 client/keys/testdata/keys/keys.db/CURRENT.bak create mode 100644 client/keys/testdata/keys/keys.db/LOCK create mode 100644 client/keys/testdata/keys/keys.db/LOG create mode 100644 client/keys/testdata/keys/keys.db/MANIFEST-000004 delete mode 100644 client/keys/update.go delete mode 100644 client/keys/update_test.go delete mode 100644 crypto/keyring/db_keybase.go delete mode 100644 crypto/keyring/keybase_test.go delete mode 100644 crypto/keyring/lazy_keybase.go delete mode 100644 crypto/keyring/lazy_keybase_test.go create mode 100644 crypto/keyring/legacy.go create mode 100644 crypto/keyring/legacy_test.go create mode 100644 crypto/keyring/testdata/keys/keys.db/000002.ldb create mode 100644 crypto/keyring/testdata/keys/keys.db/CURRENT create mode 100644 crypto/keyring/testdata/keys/keys.db/CURRENT.bak create mode 100644 crypto/keyring/testdata/keys/keys.db/LOCK create mode 100644 crypto/keyring/testdata/keys/keys.db/LOG create mode 100644 crypto/keyring/testdata/keys/keys.db/MANIFEST-000004 diff --git a/CHANGELOG.md b/CHANGELOG.md index a0356406f9b6..33da257d94ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,6 +51,7 @@ that parse log messages. * (client) [\#5799](https://github.com/cosmos/cosmos-sdk/pull/5799) The `tx encode/decode` commands, due to change on encoding break compatibility with older clients. * (x/auth) [\#5844](https://github.com/cosmos/cosmos-sdk/pull/5844) `tx sign` command now returns an error when signing is attempted with offline/multisig keys. +* (client/keys) [\#5889](https://github.com/cosmos/cosmos-sdk/pull/5889) Remove `keys update` command. ### API Breaking Changes @@ -77,6 +78,11 @@ to now accept a `codec.JSONMarshaler` for modular serialization of genesis state * (crypto/keyring) [\#5866](https://github.com/cosmos/cosmos-sdk/pull/5866) Move `Keyring` and `Keybase` implementations and their associated types from `crypto/keys/` to `crypto/keyring/`. * (crypto) [\#5880](https://github.com/cosmos/cosmos-sdk/pull/5880) Merge `crypto/keys/mintkey` into `crypto`. * (crypto/keyring) [\#5858](https://github.com/cosmos/cosmos-sdk/pull/5858) Make Keyring store keys by name and address's hexbytes representation. +* (crypto/keyring) [\#5889](https://github.com/cosmos/cosmos-sdk/pull/5889) Deprecate old keybase implementation: + - Remove `Update` from the `Keybase` interface. + - `NewKeyring()` now accepts a new backend: `MemoryBackend`. + - `New()` has been renamed to`NewLegacy()`, which now returns a `LegacyKeybase` type that only allows migration of keys from the legacy keybase to a new keyring. +* (client/keys) [\#5889](https://github.com/cosmos/cosmos-sdk/pull/5889) Rename `NewKeyBaseFromDir()` -> `NewLegacyKeyBaseFromDir()`. ### Features diff --git a/client/keys/add.go b/client/keys/add.go index 530431eb808d..1170c714ee3f 100644 --- a/client/keys/add.go +++ b/client/keys/add.go @@ -27,7 +27,6 @@ const ( flagInteractive = "interactive" flagRecover = "recover" flagNoBackup = "no-backup" - flagDryRun = "dry-run" flagAccount = "account" flagIndex = "index" flagMultisig = "multisig" @@ -72,7 +71,7 @@ the flag --nosort is set. cmd.Flags().Bool(flags.FlagUseLedger, false, "Store a local reference to a private key on a Ledger device") cmd.Flags().Bool(flagRecover, false, "Provide seed phrase to recover existing key instead of creating") cmd.Flags().Bool(flagNoBackup, false, "Don't print out seed phrase (if others are watching the terminal)") - cmd.Flags().Bool(flagDryRun, false, "Perform action, but don't add key to local keystore") + cmd.Flags().Bool(flags.FlagDryRun, false, "Perform action, but don't add key to local keystore") cmd.Flags().String(flagHDPath, "", "Manual HD Path derivation (overrides BIP44 config)") cmd.Flags().Uint32(flagAccount, 0, "Account number for HD derivation") cmd.Flags().Uint32(flagIndex, 0, "Address index number for HD derivation") @@ -83,7 +82,7 @@ the flag --nosort is set. func getKeybase(transient bool, buf io.Reader) (keyring.Keybase, error) { if transient { - return keyring.NewInMemory(), nil + return keyring.NewKeyring(sdk.KeyringServiceName(), keyring.BackendMemory, viper.GetString(flags.FlagHome), buf) } return keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), buf) @@ -91,7 +90,7 @@ func getKeybase(transient bool, buf io.Reader) (keyring.Keybase, error) { func runAddCmd(cmd *cobra.Command, args []string) error { inBuf := bufio.NewReader(cmd.InOrStdin()) - kb, err := getKeybase(viper.GetBool(flagDryRun), inBuf) + kb, err := getKeybase(viper.GetBool(flags.FlagDryRun), inBuf) if err != nil { return err } @@ -124,7 +123,7 @@ func RunAddCmd(cmd *cobra.Command, args []string, kb keyring.Keybase, inBuf *buf return keyring.ErrUnsupportedSigningAlgo } - if !viper.GetBool(flagDryRun) { + if !viper.GetBool(flags.FlagDryRun) { _, err = kb.Get(name) if err == nil { // account exists, ask for user confirmation diff --git a/client/keys/add_ledger_test.go b/client/keys/add_ledger_test.go index dd53d1b361ce..b21a0b1850d6 100644 --- a/client/keys/add_ledger_test.go +++ b/client/keys/add_ledger_test.go @@ -17,7 +17,6 @@ import ( ) func Test_runAddCmdLedgerWithCustomCoinType(t *testing.T) { - runningUnattended := isRunningUnattended() config := sdk.GetConfig() bech32PrefixAccAddr := "terra" @@ -58,9 +57,6 @@ func Test_runAddCmdLedgerWithCustomCoinType(t *testing.T) { kb.Delete("keyname1", "", false) }) mockIn.Reset("test1234\n") - if runningUnattended { - mockIn.Reset("test1234\ntest1234\n") - } key1, err := kb.Get("keyname1") require.NoError(t, err) require.NotNil(t, key1) @@ -79,7 +75,6 @@ func Test_runAddCmdLedgerWithCustomCoinType(t *testing.T) { } func Test_runAddCmdLedger(t *testing.T) { - runningUnattended := isRunningUnattended() cmd := AddKeyCommand() require.NotNil(t, cmd) mockIn, _, _ := tests.ApplyMockIO(cmd) @@ -105,9 +100,6 @@ func Test_runAddCmdLedger(t *testing.T) { kb.Delete("keyname1", "", false) }) mockIn.Reset("test1234\n") - if runningUnattended { - mockIn.Reset("test1234\ntest1234\n") - } key1, err := kb.Get("keyname1") require.NoError(t, err) require.NotNil(t, key1) diff --git a/client/keys/add_test.go b/client/keys/add_test.go index 5276e942d0ce..172d7d9e1ce6 100644 --- a/client/keys/add_test.go +++ b/client/keys/add_test.go @@ -16,7 +16,6 @@ import ( ) func Test_runAddCmdBasic(t *testing.T) { - runningUnattended := isRunningUnattended() cmd := AddKeyCommand() assert.NotNil(t, cmd) mockIn, _, _ := tests.ApplyMockIO(cmd) @@ -27,31 +26,27 @@ func Test_runAddCmdBasic(t *testing.T) { viper.Set(flags.FlagHome, kbHome) viper.Set(cli.OutputFlag, OutputFormatText) - if runningUnattended { - mockIn.Reset("testpass1\ntestpass1\n") - } else { - mockIn.Reset("y\n") - kb, err := keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), kbHome, mockIn) - require.NoError(t, err) - t.Cleanup(func() { - kb.Delete("keyname1", "", false) // nolint:errcheck - kb.Delete("keyname2", "", false) // nolint:errcheck - }) - } + mockIn.Reset("y\n") + kb, err := keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), kbHome, mockIn) + require.NoError(t, err) + t.Cleanup(func() { + kb.Delete("keyname1", "", false) // nolint:errcheck + kb.Delete("keyname2", "", false) // nolint:errcheck + }) assert.NoError(t, runAddCmd(cmd, []string{"keyname1"})) - if runningUnattended { - mockIn.Reset("testpass1\nN\n") - } else { - mockIn.Reset("N\n") - } + mockIn.Reset("N\n") assert.Error(t, runAddCmd(cmd, []string{"keyname1"})) - if runningUnattended { - mockIn.Reset("testpass1\nN\n") - } else { - mockIn.Reset("y\n") - } - err := runAddCmd(cmd, []string{"keyname2"}) - assert.NoError(t, err) + assert.NoError(t, runAddCmd(cmd, []string{"keyname2"})) + assert.Error(t, runAddCmd(cmd, []string{"keyname2"})) + mockIn.Reset("y\n") + assert.NoError(t, runAddCmd(cmd, []string{"keyname2"})) + + // test --dry-run + assert.NoError(t, runAddCmd(cmd, []string{"keyname4"})) + assert.Error(t, runAddCmd(cmd, []string{"keyname4"})) + + viper.Set(flags.FlagDryRun, true) + assert.NoError(t, runAddCmd(cmd, []string{"keyname4"})) } diff --git a/client/keys/delete_test.go b/client/keys/delete_test.go index 80da06ad8d95..73db7faecb6a 100644 --- a/client/keys/delete_test.go +++ b/client/keys/delete_test.go @@ -15,7 +15,6 @@ import ( ) func Test_runDeleteCmd(t *testing.T) { - runningUnattended := isRunningUnattended() deleteKeyCommand := DeleteKeyCommand() mockIn, _, _ := tests.ApplyMockIO(deleteKeyCommand) @@ -26,38 +25,27 @@ func Test_runDeleteCmd(t *testing.T) { fakeKeyName1 := "runDeleteCmd_Key1" fakeKeyName2 := "runDeleteCmd_Key2" - if !runningUnattended { - kb, err := keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) - require.NoError(t, err) - t.Cleanup(func() { - kb.Delete("runDeleteCmd_Key1", "", false) // nolint:errcheck - kb.Delete("runDeleteCmd_Key2", "", false) // nolint:errcheck + kb, err := keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) + require.NoError(t, err) + t.Cleanup(func() { + kb.Delete("runDeleteCmd_Key1", "", false) // nolint:errcheck + kb.Delete("runDeleteCmd_Key2", "", false) // nolint:errcheck - }) - } + }) // Now add a temporary keybase kbHome, cleanUp := tests.NewTestCaseDir(t) t.Cleanup(cleanUp) viper.Set(flags.FlagHome, kbHome) // Now - kb, err := keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), kbHome, mockIn) + kb, err = keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), kbHome, mockIn) require.NoError(t, err) - if runningUnattended { - mockIn.Reset("testpass1\ntestpass1\n") - } _, err = kb.CreateAccount(fakeKeyName1, tests.TestMnemonic, "", "", "0", keyring.Secp256k1) require.NoError(t, err) - if runningUnattended { - mockIn.Reset("testpass1\ntestpass1\n") - } _, err = kb.CreateAccount(fakeKeyName2, tests.TestMnemonic, "", "", "1", keyring.Secp256k1) require.NoError(t, err) - if runningUnattended { - mockIn.Reset("testpass1\ntestpass1\n") - } err = runDeleteCmd(deleteKeyCommand, []string{"blah"}) require.Error(t, err) require.Equal(t, "The specified item could not be found in the keyring", err.Error()) @@ -65,24 +53,14 @@ func Test_runDeleteCmd(t *testing.T) { // User confirmation missing err = runDeleteCmd(deleteKeyCommand, []string{fakeKeyName1}) require.Error(t, err) - if runningUnattended { - require.Equal(t, "aborted", err.Error()) - } else { - require.Equal(t, "EOF", err.Error()) - } + require.Equal(t, "EOF", err.Error()) { - if runningUnattended { - mockIn.Reset("testpass1\n") - } _, err = kb.Get(fakeKeyName1) require.NoError(t, err) // Now there is a confirmation viper.Set(flagYes, true) - if runningUnattended { - mockIn.Reset("testpass1\ntestpass1\n") - } require.NoError(t, runDeleteCmd(deleteKeyCommand, []string{fakeKeyName1})) _, err = kb.Get(fakeKeyName1) @@ -90,14 +68,8 @@ func Test_runDeleteCmd(t *testing.T) { } viper.Set(flagYes, true) - if runningUnattended { - mockIn.Reset("testpass1\n") - } _, err = kb.Get(fakeKeyName2) require.NoError(t, err) - if runningUnattended { - mockIn.Reset("testpass1\ny\ntestpass1\n") - } err = runDeleteCmd(deleteKeyCommand, []string{fakeKeyName2}) require.NoError(t, err) _, err = kb.Get(fakeKeyName2) diff --git a/client/keys/export_test.go b/client/keys/export_test.go index e7e6fb4915b0..175acdfe92fc 100644 --- a/client/keys/export_test.go +++ b/client/keys/export_test.go @@ -13,7 +13,6 @@ import ( ) func Test_runExportCmd(t *testing.T) { - runningUnattended := isRunningUnattended() exportKeyCommand := ExportKeyCommand() mockIn, _, _ := tests.ApplyMockIO(exportKeyCommand) @@ -25,23 +24,14 @@ func Test_runExportCmd(t *testing.T) { // create a key kb, err := keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) require.NoError(t, err) - if !runningUnattended { - t.Cleanup(func() { - kb.Delete("keyname1", "", false) // nolint:errcheck - }) - } - - if runningUnattended { - mockIn.Reset("testpass1\ntestpass1\n") - } + t.Cleanup(func() { + kb.Delete("keyname1", "", false) // nolint:errcheck + }) + _, err = kb.CreateAccount("keyname1", tests.TestMnemonic, "", "123456789", "", keyring.Secp256k1) require.NoError(t, err) // Now enter password - if runningUnattended { - mockIn.Reset("123456789\n123456789\ntestpass1\n") - } else { - mockIn.Reset("123456789\n123456789\n") - } + mockIn.Reset("123456789\n123456789\n") require.NoError(t, runExportCmd(exportKeyCommand, []string{"keyname1"})) } diff --git a/client/keys/import_test.go b/client/keys/import_test.go index 1bcae042cc4d..cad3d6a44d3f 100644 --- a/client/keys/import_test.go +++ b/client/keys/import_test.go @@ -15,7 +15,6 @@ import ( ) func Test_runImportCmd(t *testing.T) { - runningUnattended := isRunningUnattended() importKeyCommand := ImportKeyCommand() mockIn, _, _ := tests.ApplyMockIO(importKeyCommand) @@ -24,13 +23,11 @@ func Test_runImportCmd(t *testing.T) { t.Cleanup(cleanUp) viper.Set(flags.FlagHome, kbHome) - if !runningUnattended { - kb, err := keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) - require.NoError(t, err) - t.Cleanup(func() { - kb.Delete("keyname1", "", false) // nolint:errcheck - }) - } + kb, err := keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) + require.NoError(t, err) + t.Cleanup(func() { + kb.Delete("keyname1", "", false) // nolint:errcheck + }) keyfile := filepath.Join(kbHome, "key.asc") armoredKey := `-----BEGIN TENDERMINT PRIVATE KEY----- @@ -45,10 +42,6 @@ HbP+c6JmeJy9JXe2rbbF1QtCX1gLqGcDQPBXiCtFvP7/8wTZtVOPj8vREzhZ9ElO require.NoError(t, ioutil.WriteFile(keyfile, []byte(armoredKey), 0644)) // Now enter password - if runningUnattended { - mockIn.Reset("123456789\n12345678\n12345678\n") - } else { - mockIn.Reset("123456789\n") - } + mockIn.Reset("123456789\n") require.NoError(t, runImportCmd(importKeyCommand, []string{"keyname1", keyfile})) } diff --git a/client/keys/list_test.go b/client/keys/list_test.go index c259793e9b80..d5d4eebcf706 100644 --- a/client/keys/list_test.go +++ b/client/keys/list_test.go @@ -14,7 +14,6 @@ import ( ) func Test_runListCmd(t *testing.T) { - runningUnattended := isRunningUnattended() type args struct { cmd *cobra.Command args []string @@ -34,9 +33,6 @@ func Test_runListCmd(t *testing.T) { mockIn, _, _ := tests.ApplyMockIO(cmdBasic) kb, err := keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) require.NoError(t, err) - if runningUnattended { - mockIn.Reset("testpass1\ntestpass1\n") - } _, err = kb.CreateAccount("something", tests.TestMnemonic, "", "", "", keyring.Secp256k1) require.NoError(t, err) @@ -57,18 +53,12 @@ func Test_runListCmd(t *testing.T) { for _, tt := range testData { tt := tt t.Run(tt.name, func(t *testing.T) { - if runningUnattended { - mockIn.Reset("testpass1\ntestpass1\n") - } viper.Set(flagListNames, false) viper.Set(flags.FlagHome, tt.kbDir) if err := runListCmd(tt.args.cmd, tt.args.args); (err != nil) != tt.wantErr { t.Errorf("runListCmd() error = %v, wantErr %v", err, tt.wantErr) } - if runningUnattended { - mockIn.Reset("testpass1\ntestpass1\n") - } viper.Set(flagListNames, true) if err := runListCmd(tt.args.cmd, tt.args.args); (err != nil) != tt.wantErr { t.Errorf("runListCmd() error = %v, wantErr %v", err, tt.wantErr) diff --git a/client/keys/migrate.go b/client/keys/migrate.go index 2f7f3c95df5b..840db70f10e1 100644 --- a/client/keys/migrate.go +++ b/client/keys/migrate.go @@ -43,10 +43,12 @@ It is recommended to run in 'dry-run' mode first to verify all key migration mat func runMigrateCmd(cmd *cobra.Command, args []string) error { // instantiate legacy keybase rootDir := viper.GetString(flags.FlagHome) - legacyKb, err := NewKeyBaseFromDir(rootDir) + var legacyKb keyring.LegacyKeybase + legacyKb, err := NewLegacyKeyBaseFromDir(rootDir) if err != nil { return err } + defer legacyKb.Close() // fetch list of keys from legacy keybase oldKeys, err := legacyKb.List() diff --git a/client/keys/root.go b/client/keys/root.go index d3df8e046868..801cc065aedd 100644 --- a/client/keys/root.go +++ b/client/keys/root.go @@ -45,7 +45,6 @@ The pass backend requires GnuPG: https://gnupg.org/ ShowKeysCmd(), flags.LineBreak, DeleteKeyCommand(), - UpdateKeyCommand(), ParseKeyStringCommand(), MigrateCommand(), ) diff --git a/client/keys/root_test.go b/client/keys/root_test.go index daafecf7b9fa..29fbe145504c 100644 --- a/client/keys/root_test.go +++ b/client/keys/root_test.go @@ -16,7 +16,7 @@ func TestCommands(t *testing.T) { assert.NotNil(t, rootCommands) // Commands are registered - assert.Equal(t, 11, len(rootCommands.Commands())) + assert.Equal(t, 10, len(rootCommands.Commands())) } func TestMain(m *testing.M) { diff --git a/client/keys/show_test.go b/client/keys/show_test.go index fe1070e1ffb7..cf157c4c588c 100644 --- a/client/keys/show_test.go +++ b/client/keys/show_test.go @@ -35,7 +35,6 @@ func Test_showKeysCmd(t *testing.T) { } func Test_runShowCmd(t *testing.T) { - runningUnattended := isRunningUnattended() cmd := ShowKeysCmd() mockIn, _, _ := tests.ApplyMockIO(cmd) require.EqualError(t, runShowCmd(cmd, []string{"invalid"}), "invalid is not a valid name or address: decoding bech32 failed: invalid bech32 string length 7") @@ -55,29 +54,17 @@ func Test_runShowCmd(t *testing.T) { kb.Delete("runShowCmd_Key1", "", false) kb.Delete("runShowCmd_Key2", "", false) }) - if runningUnattended { - mockIn.Reset("testpass1\ntestpass1\n") - } _, err = kb.CreateAccount(fakeKeyName1, tests.TestMnemonic, "", "", "0", keyring.Secp256k1) require.NoError(t, err) - if runningUnattended { - mockIn.Reset("testpass1\n") - } _, err = kb.CreateAccount(fakeKeyName2, tests.TestMnemonic, "", "", "1", keyring.Secp256k1) require.NoError(t, err) // Now try single key - if runningUnattended { - mockIn.Reset("testpass1\n") - } require.EqualError(t, runShowCmd(cmd, []string{fakeKeyName1}), "invalid Bech32 prefix encoding provided: ") // Now try single key - set bech to acc viper.Set(FlagBechPrefix, sdk.PrefixAccount) - if runningUnattended { - mockIn.Reset("testpass1\n") - } // try fetch by name require.NoError(t, runShowCmd(cmd, []string{fakeKeyName1})) @@ -88,17 +75,11 @@ func Test_runShowCmd(t *testing.T) { // Now try multisig key - set bech to acc viper.Set(FlagBechPrefix, sdk.PrefixAccount) - if runningUnattended { - mockIn.Reset("testpass1\ntestpass1\n") - } require.EqualError(t, runShowCmd(cmd, []string{fakeKeyName1, fakeKeyName2}), "threshold must be a positive integer") // Now try multisig key - set bech to acc + threshold=2 viper.Set(FlagBechPrefix, sdk.PrefixAccount) viper.Set(flagMultiSigThreshold, 2) - if runningUnattended { - mockIn.Reset("testpass1\ntestpass1\n") - } err = runShowCmd(cmd, []string{fakeKeyName1, fakeKeyName2}) require.NoError(t, err) @@ -106,23 +87,14 @@ func Test_runShowCmd(t *testing.T) { viper.Set(FlagBechPrefix, "acc") viper.Set(FlagDevice, true) viper.Set(flagMultiSigThreshold, 2) - if runningUnattended { - mockIn.Reset("testpass1\ntestpass1\n") - } err = runShowCmd(cmd, []string{fakeKeyName1, fakeKeyName2}) require.EqualError(t, err, "the device flag (-d) can only be used for accounts stored in devices") viper.Set(FlagBechPrefix, "val") - if runningUnattended { - mockIn.Reset("testpass1\ntestpass1\n") - } err = runShowCmd(cmd, []string{fakeKeyName1, fakeKeyName2}) require.EqualError(t, err, "the device flag (-d) can only be used for accounts") viper.Set(FlagPublicKey, true) - if runningUnattended { - mockIn.Reset("testpass1\ntestpass1\n") - } err = runShowCmd(cmd, []string{fakeKeyName1, fakeKeyName2}) require.EqualError(t, err, "the device flag (-d) can only be used for addresses not pubkeys") diff --git a/client/keys/testdata/keys/keys.db/000002.ldb b/client/keys/testdata/keys/keys.db/000002.ldb new file mode 100644 index 0000000000000000000000000000000000000000..b36586df3626e4a01631c987005dd5b167ff1da2 GIT binary patch literal 391 zcmey$^r4Z#RxCNcI5)r8Fr~Dl+#<2KsJx`KtSZ&C+#n^bq%tF`u)-ugH7~cY)V$I% zr?5&dF(suawYZp(g#iqTO7lVsQW8s2opV#-y;CcV^fL3(^4ZPAathMRi}EtE%8be? z%1q6&N-NC^O3Kqxat-nfiYqI#QcBBG%aVb{ar!ebvHCgrGpHDX^)kqL7g=R6a7wZ; zGIE+rc**mTQf0Uyr1m=MWxFC%+6+;l*L&_w+s))UMK~hzht#w>p1XUJc$A%Z zPwESPNR;9%PE9T_GBwLK6yWnVVl8E1WG;$fU@+p1Im5hYq0HxtQ@kC!+?#3MRPJ a`@iD$YnizAFo}VL@PqK*4c#iG?zaJJVsO>~ literal 0 HcmV?d00001 diff --git a/client/keys/testdata/keys/keys.db/CURRENT b/client/keys/testdata/keys/keys.db/CURRENT new file mode 100644 index 000000000000..cacca7574c03 --- /dev/null +++ b/client/keys/testdata/keys/keys.db/CURRENT @@ -0,0 +1 @@ +MANIFEST-000004 diff --git a/client/keys/testdata/keys/keys.db/CURRENT.bak b/client/keys/testdata/keys/keys.db/CURRENT.bak new file mode 100644 index 000000000000..feda7d6b2481 --- /dev/null +++ b/client/keys/testdata/keys/keys.db/CURRENT.bak @@ -0,0 +1 @@ +MANIFEST-000000 diff --git a/client/keys/testdata/keys/keys.db/LOCK b/client/keys/testdata/keys/keys.db/LOCK new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/client/keys/testdata/keys/keys.db/LOG b/client/keys/testdata/keys/keys.db/LOG new file mode 100644 index 000000000000..386101e4fb91 --- /dev/null +++ b/client/keys/testdata/keys/keys.db/LOG @@ -0,0 +1,18 @@ +=============== Mar 30, 2020 (CEST) =============== +02:07:34.137606 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed +02:07:34.144547 db@open opening +02:07:34.144770 version@stat F·[] S·0B[] Sc·[] +02:07:34.145843 db@janitor F·2 G·0 +02:07:34.145875 db@open done T·1.315251ms +02:07:34.335635 db@close closing +02:07:34.335736 db@close done T·98.95µs +=============== Mar 30, 2020 (CEST) =============== +02:08:33.239115 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed +02:08:33.239264 version@stat F·[] S·0B[] Sc·[] +02:08:33.239281 db@open opening +02:08:33.239310 journal@recovery F·1 +02:08:33.239398 journal@recovery recovering @1 +02:08:33.322008 memdb@flush created L0@2 N·4 S·391B "cos..ess,v4":"run..nfo,v3" +02:08:33.323091 version@stat F·[1] S·391B[391B] Sc·[0.25] +02:08:33.421979 db@janitor F·3 G·0 +02:08:33.422153 db@open done T·182.707962ms diff --git a/client/keys/testdata/keys/keys.db/MANIFEST-000004 b/client/keys/testdata/keys/keys.db/MANIFEST-000004 new file mode 100644 index 0000000000000000000000000000000000000000..557b4bdbbc93fd41441cfe30d1ca16f08f47f344 GIT binary patch literal 237 zcmeykNagJ_21Z7yoYb<^oRlOzr^=Gl^338?=ltA)#G=HK{30f1W>ywfb_S+)X4~Za z;@tdV!<5pJa*M>`qVkf`vZ_?ma)Xq#lFE#%!U~i0)V$onQu9j7oWd%-#FUhx)Z$`B l76veoD=N(kEl5c$Np;RmiT6&eG}6n=OUq|uhDg)i1^~DrOBnzF literal 0 HcmV?d00001 diff --git a/client/keys/update.go b/client/keys/update.go deleted file mode 100644 index 2ca46d43289b..000000000000 --- a/client/keys/update.go +++ /dev/null @@ -1,55 +0,0 @@ -package keys - -import ( - "bufio" - - "github.com/spf13/cobra" - "github.com/spf13/viper" - - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/client/input" -) - -// UpdateKeyCommand changes the password of a key in the keybase. -// It takes no effect on keys managed by new the keyring-based keybase implementation. -func UpdateKeyCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "update ", - Short: "Change the password used to protect private key", - Deprecated: `it takes no effect with the new keyring -based backend and is provided only for backward compatibility with the -legacy LevelDB based backend. -Refer to your operating system's manual to learn how to change your -keyring's password. -`, - RunE: runUpdateCmd, - Args: cobra.ExactArgs(1), - } - return cmd -} - -func runUpdateCmd(cmd *cobra.Command, args []string) error { - name := args[0] - - buf := bufio.NewReader(cmd.InOrStdin()) - kb, err := NewKeyBaseFromDir(viper.GetString(flags.FlagHome)) - if err != nil { - return err - } - oldpass, err := input.GetPassword("Enter the current passphrase:", buf) - if err != nil { - return err - } - - getNewpass := func() (string, error) { - return input.GetCheckPassword( - "Enter the new passphrase:", - "Repeat the new passphrase:", buf) - } - if err := kb.Update(name, oldpass, getNewpass); err != nil { - return err - } - - cmd.PrintErrln("Password successfully updated!") - return nil -} diff --git a/client/keys/update_test.go b/client/keys/update_test.go deleted file mode 100644 index 2c951b7c31f1..000000000000 --- a/client/keys/update_test.go +++ /dev/null @@ -1,58 +0,0 @@ -package keys - -import ( - "errors" - "testing" - - "github.com/spf13/viper" - "github.com/stretchr/testify/require" - - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/crypto/keyring" - "github.com/cosmos/cosmos-sdk/tests" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" -) - -func Test_updateKeyCommand(t *testing.T) { - require.NotNil(t, UpdateKeyCommand()) - // No flags or defaults to validate -} - -func Test_runUpdateCmd(t *testing.T) { - fakeKeyName1 := "runUpdateCmd_Key1" - fakeKeyName2 := "runUpdateCmd_Key2" - - cmd := UpdateKeyCommand() - - // fails because it requests a password - err := runUpdateCmd(cmd, []string{fakeKeyName1}) - - require.EqualError(t, err, "EOF") - - // try again - mockIn, _, _ := tests.ApplyMockIO(cmd) - mockIn.Reset("pass1234\n") - err = runUpdateCmd(cmd, []string{fakeKeyName1}) - require.True(t, errors.Is(err, sdkerrors.ErrKeyNotFound)) - - // Prepare a key base - // Now add a temporary keybase - kbHome, cleanUp1 := tests.NewTestCaseDir(t) - t.Cleanup(cleanUp1) - viper.Set(flags.FlagHome, kbHome) - - kb, err := NewKeyBaseFromDir(viper.GetString(flags.FlagHome)) - require.NoError(t, err) - _, err = kb.CreateAccount(fakeKeyName1, tests.TestMnemonic, "", "", "0", keyring.Secp256k1) - require.NoError(t, err) - _, err = kb.CreateAccount(fakeKeyName2, tests.TestMnemonic, "", "", "1", keyring.Secp256k1) - require.NoError(t, err) - - // Try again now that we have keys - // Incorrect key type - mockIn.Reset("pass1234\nNew1234\nNew1234") - err = runUpdateCmd(cmd, []string{fakeKeyName1}) - require.EqualError(t, err, "locally stored key required. Received: keyring.offlineInfo") - - // TODO: Check for other type types? -} diff --git a/client/keys/utils.go b/client/keys/utils.go index 4581d6861603..1a6f1d019207 100644 --- a/client/keys/utils.go +++ b/client/keys/utils.go @@ -5,7 +5,6 @@ import ( "io" "path/filepath" - "github.com/99designs/keyring" "github.com/spf13/viper" "github.com/tendermint/tendermint/libs/cli" "gopkg.in/yaml.v2" @@ -25,17 +24,14 @@ const ( type bechKeyOutFn func(keyInfo cryptokeyring.Info) (cryptokeyring.KeyOutput, error) -// NewKeyBaseFromDir initializes a keybase at the rootDir directory. Keybase +// NewLegacyKeyBaseFromDir initializes a legacy keybase at the rootDir directory. Keybase // options can be applied when generating this new Keybase. -func NewKeyBaseFromDir(rootDir string, opts ...cryptokeyring.KeybaseOption) (cryptokeyring.Keybase, error) { - return getLazyKeyBaseFromDir(rootDir, opts...) +func NewLegacyKeyBaseFromDir(rootDir string, opts ...cryptokeyring.KeybaseOption) (cryptokeyring.LegacyKeybase, error) { + return getLegacyKeyBaseFromDir(rootDir, opts...) } -// NewInMemoryKeyBase returns a storage-less keybase. -func NewInMemoryKeyBase() cryptokeyring.Keybase { return cryptokeyring.NewInMemory() } - -func getLazyKeyBaseFromDir(rootDir string, opts ...cryptokeyring.KeybaseOption) (cryptokeyring.Keybase, error) { - return cryptokeyring.New(defaultKeyDBName, filepath.Join(rootDir, "keys"), opts...), nil +func getLegacyKeyBaseFromDir(rootDir string, opts ...cryptokeyring.KeybaseOption) (cryptokeyring.LegacyKeybase, error) { + return cryptokeyring.NewLegacy(defaultKeyDBName, filepath.Join(rootDir, "keys"), opts...) } func printKeyInfo(w io.Writer, keyInfo cryptokeyring.Info, bechKeyOut bechKeyOutFn) { @@ -116,8 +112,3 @@ func printPubKey(w io.Writer, info cryptokeyring.Info, bechKeyOut bechKeyOutFn) fmt.Fprintln(w, ko.PubKey) } - -func isRunningUnattended() bool { - backends := keyring.AvailableBackends() - return len(backends) == 2 && backends[1] == keyring.BackendType("file") -} diff --git a/crypto/keyring/base_keybase.go b/crypto/keyring/base_keybase.go index c2f7952b820a..abec03359a86 100644 --- a/crypto/keyring/base_keybase.go +++ b/crypto/keyring/base_keybase.go @@ -33,6 +33,8 @@ type ( } ) +var fundraiserPath = types.GetConfig().GetFullFundraiserPath() + // newBaseKeybase generates the base keybase with defaulting to tendermint SECP256K1 key type func newBaseKeybase(optionsFns ...KeybaseOption) baseKeybase { // Default options for keybase @@ -139,7 +141,7 @@ func (kb baseKeybase) CreateMnemonic( return nil, "", err } - info, err = kb.CreateAccount(keyWriter, name, mnemonic, DefaultBIP39Passphrase, passwd, types.GetConfig().GetFullFundraiserPath(), algo) + info, err = kb.CreateAccount(keyWriter, name, mnemonic, DefaultBIP39Passphrase, passwd, fundraiserPath, algo) if err != nil { return nil, "", err } diff --git a/crypto/keyring/db_keybase.go b/crypto/keyring/db_keybase.go deleted file mode 100644 index 0ed7cbfd927a..000000000000 --- a/crypto/keyring/db_keybase.go +++ /dev/null @@ -1,432 +0,0 @@ -package keyring - -import ( - "encoding/hex" - "fmt" - "reflect" - "strings" - - "github.com/pkg/errors" - tmcrypto "github.com/tendermint/tendermint/crypto" - cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino" - dbm "github.com/tendermint/tm-db" - - "github.com/cosmos/cosmos-sdk/crypto" - "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" -) - -var _ Keybase = dbKeybase{} - -// dbKeybase combines encryption and storage implementation to provide a -// full-featured key manager. -// -// NOTE: dbKeybase will be deprecated in favor of keyringKeybase. -type dbKeybase struct { - base baseKeybase - db dbm.DB -} - -// newDBKeybase creates a new dbKeybase instance using the provided DB for -// reading and writing keys. -func newDBKeybase(db dbm.DB, opts ...KeybaseOption) Keybase { - return dbKeybase{ - base: newBaseKeybase(opts...), - db: db, - } -} - -// NewInMemory creates a transient keybase on top of in-memory storage -// instance useful for testing purposes and on-the-fly key generation. -// Keybase options can be applied when generating this new Keybase. -func NewInMemory(opts ...KeybaseOption) Keybase { return newDBKeybase(dbm.NewMemDB(), opts...) } - -// CreateMnemonic generates a new key and persists it to storage, encrypted -// using the provided password. It returns the generated mnemonic and the key Info. -// It returns an error if it fails to generate a key for the given key algorithm -// type, or if another key is already stored under the same name. -func (kb dbKeybase) CreateMnemonic( - name string, language Language, passwd string, algo SigningAlgo, -) (info Info, mnemonic string, err error) { - - return kb.base.CreateMnemonic(kb, name, language, passwd, algo) -} - -// CreateAccount converts a mnemonic to a private key and persists it, encrypted -// with the given password. -func (kb dbKeybase) CreateAccount( - name, mnemonic, bip39Passwd, encryptPasswd, hdPath string, algo SigningAlgo, -) (Info, error) { - - return kb.base.CreateAccount(kb, name, mnemonic, bip39Passwd, encryptPasswd, hdPath, algo) -} - -// CreateLedger creates a new locally-stored reference to a Ledger keypair. -// It returns the created key info and an error if the Ledger could not be queried. -func (kb dbKeybase) CreateLedger( - name string, algo SigningAlgo, hrp string, account, index uint32, -) (Info, error) { - - return kb.base.CreateLedger(kb, name, algo, hrp, account, index) -} - -// CreateOffline creates a new reference to an offline keypair. It returns the -// created key info. -func (kb dbKeybase) CreateOffline(name string, pub tmcrypto.PubKey, algo SigningAlgo) (Info, error) { - return kb.base.writeOfflineKey(kb, name, pub, algo), nil -} - -// CreateMulti creates a new reference to a multisig (offline) keypair. It -// returns the created key info. -func (kb dbKeybase) CreateMulti(name string, pub tmcrypto.PubKey) (Info, error) { - return kb.base.writeMultisigKey(kb, name, pub), nil -} - -// List returns the keys from storage in alphabetical order. -func (kb dbKeybase) List() ([]Info, error) { - var res []Info - - iter, err := kb.db.Iterator(nil, nil) - if err != nil { - return nil, err - } - - defer iter.Close() - - for ; iter.Valid(); iter.Next() { - key := string(iter.Key()) - - // need to include only keys in storage that have an info suffix - if strings.HasSuffix(key, infoSuffix) { - info, err := unmarshalInfo(iter.Value()) - if err != nil { - return nil, err - } - - res = append(res, info) - } - } - - return res, nil -} - -// Get returns the public information about one key. -func (kb dbKeybase) Get(name string) (Info, error) { - bs, err := kb.db.Get(infoKey(name)) - if err != nil { - return nil, err - } - - if len(bs) == 0 { - return nil, sdkerrors.Wrap(sdkerrors.ErrKeyNotFound, name) - } - - return unmarshalInfo(bs) -} - -// GetByAddress returns Info based on a provided AccAddress. An error is returned -// if the address does not exist. -func (kb dbKeybase) GetByAddress(address types.AccAddress) (Info, error) { - ik, err := kb.db.Get(addrStringKey(address)) - if err != nil { - return nil, err - } - - if len(ik) == 0 { - return nil, fmt.Errorf("key with address %s not found", address) - } - - bs, err := kb.db.Get(ik) - if err != nil { - return nil, err - } - - return unmarshalInfo(bs) -} - -// Sign signs the msg with the named key. It returns an error if the key doesn't -// exist or the decryption fails. -func (kb dbKeybase) Sign(name, passphrase string, msg []byte) (sig []byte, pub tmcrypto.PubKey, err error) { - info, err := kb.Get(name) - if err != nil { - return - } - - var priv tmcrypto.PrivKey - - switch i := info.(type) { - case localInfo: - if i.PrivKeyArmor == "" { - err = fmt.Errorf("private key not available") - return - } - - priv, _, err = crypto.UnarmorDecryptPrivKey(i.PrivKeyArmor, passphrase) - if err != nil { - return nil, nil, err - } - - case ledgerInfo: - return SignWithLedger(info, msg) - - case offlineInfo, multiInfo: - return nil, info.GetPubKey(), errors.New("cannot sign with offline keys") - } - - sig, err = priv.Sign(msg) - if err != nil { - return nil, nil, err - } - - return sig, priv.PubKey(), nil -} - -// ExportPrivateKeyObject returns a PrivKey object given the key name and -// passphrase. An error is returned if the key does not exist or if the Info for -// the key is invalid. -func (kb dbKeybase) ExportPrivateKeyObject(name string, passphrase string) (tmcrypto.PrivKey, error) { - info, err := kb.Get(name) - if err != nil { - return nil, err - } - - var priv tmcrypto.PrivKey - - switch i := info.(type) { - case localInfo: - linfo := i - if linfo.PrivKeyArmor == "" { - err = fmt.Errorf("private key not available") - return nil, err - } - - priv, _, err = crypto.UnarmorDecryptPrivKey(linfo.PrivKeyArmor, passphrase) - if err != nil { - return nil, err - } - - case ledgerInfo, offlineInfo, multiInfo: - return nil, errors.New("only works on local private keys") - } - - return priv, nil -} - -func (kb dbKeybase) Export(name string) (armor string, err error) { - bz, err := kb.db.Get(infoKey(name)) - if err != nil { - return "", err - } - - if bz == nil { - return "", fmt.Errorf("no key to export with name %s", name) - } - - return crypto.ArmorInfoBytes(bz), nil -} - -// ExportPubKey returns public keys in ASCII armored format. It retrieves a Info -// object by its name and return the public key in a portable format. -func (kb dbKeybase) ExportPubKey(name string) (armor string, err error) { - bz, err := kb.db.Get(infoKey(name)) - if err != nil { - return "", err - } - - if bz == nil { - return "", fmt.Errorf("no key to export with name %s", name) - } - - info, err := unmarshalInfo(bz) - if err != nil { - return - } - - return crypto.ArmorPubKeyBytes(info.GetPubKey().Bytes(), string(info.GetAlgo())), nil -} - -// ExportPrivKey returns a private key in ASCII armored format. -// It returns an error if the key does not exist or a wrong encryption passphrase -// is supplied. -func (kb dbKeybase) ExportPrivKey(name string, decryptPassphrase string, - encryptPassphrase string) (armor string, err error) { - priv, err := kb.ExportPrivateKeyObject(name, decryptPassphrase) - if err != nil { - return "", err - } - - info, err := kb.Get(name) - if err != nil { - return "", err - } - - return crypto.EncryptArmorPrivKey(priv, encryptPassphrase, string(info.GetAlgo())), nil -} - -// ImportPrivKey imports a private key in ASCII armor format. It returns an -// error if a key with the same name exists or a wrong encryption passphrase is -// supplied. -func (kb dbKeybase) ImportPrivKey(name string, armor string, passphrase string) error { - if _, err := kb.Get(name); err == nil { - return errors.New("Cannot overwrite key " + name) - } - - privKey, algo, err := crypto.UnarmorDecryptPrivKey(armor, passphrase) - if err != nil { - return errors.Wrap(err, "couldn't import private key") - } - - kb.writeLocalKey(name, privKey, passphrase, SigningAlgo(algo)) - return nil -} - -func (kb dbKeybase) Import(name string, armor string) (err error) { - bz, err := kb.db.Get(infoKey(name)) - if err != nil { - return err - } - - if len(bz) > 0 { - return errors.New("cannot overwrite data for name " + name) - } - - infoBytes, err := crypto.UnarmorInfoBytes(armor) - if err != nil { - return - } - - return kb.db.Set(infoKey(name), infoBytes) -} - -// ImportPubKey imports ASCII-armored public keys. Store a new Info object holding -// a public key only, i.e. it will not be possible to sign with it as it lacks the -// secret key. -func (kb dbKeybase) ImportPubKey(name string, armor string) (err error) { - bz, err := kb.db.Get(infoKey(name)) - if err != nil { - return err - } - - if len(bz) > 0 { - return errors.New("cannot overwrite data for name " + name) - } - - pubBytes, algo, err := crypto.UnarmorPubKeyBytes(armor) - if err != nil { - return - } - - pubKey, err := cryptoAmino.PubKeyFromBytes(pubBytes) - if err != nil { - return - } - - kb.base.writeOfflineKey(kb, name, pubKey, SigningAlgo(algo)) - return -} - -// Delete removes key forever, but we must present the proper passphrase before -// deleting it (for security). It returns an error if the key doesn't exist or -// passphrases don't match. Passphrase is ignored when deleting references to -// offline and Ledger / HW wallet keys. -func (kb dbKeybase) Delete(name, passphrase string, skipPass bool) error { - // verify we have the proper password before deleting - info, err := kb.Get(name) - if err != nil { - return err - } - - if linfo, ok := info.(localInfo); ok && !skipPass { - if _, _, err = crypto.UnarmorDecryptPrivKey(linfo.PrivKeyArmor, passphrase); err != nil { - return err - } - } - - batch := kb.db.NewBatch() - defer batch.Close() - - batch.Delete(addrStringKey(info.GetAddress())) - batch.Delete(infoKey(name)) - - return batch.WriteSync() -} - -// Update changes the passphrase with which an already stored key is -// encrypted. -// -// oldpass must be the current passphrase used for encryption, -// getNewpass is a function to get the passphrase to permanently replace -// the current passphrase -func (kb dbKeybase) Update(name, oldpass string, getNewpass func() (string, error)) error { - info, err := kb.Get(name) - if err != nil { - return err - } - - switch i := info.(type) { - case localInfo: - linfo := i - - key, _, err := crypto.UnarmorDecryptPrivKey(linfo.PrivKeyArmor, oldpass) - if err != nil { - return err - } - - newpass, err := getNewpass() - if err != nil { - return err - } - - kb.writeLocalKey(name, key, newpass, i.GetAlgo()) - return nil - - default: - return fmt.Errorf("locally stored key required. Received: %v", reflect.TypeOf(info).String()) - } -} - -// SupportedAlgos returns a list of supported signing algorithms. -func (kb dbKeybase) SupportedAlgos() []SigningAlgo { - return kb.base.SupportedAlgos() -} - -// SupportedAlgosLedger returns a list of supported ledger signing algorithms. -func (kb dbKeybase) SupportedAlgosLedger() []SigningAlgo { - return kb.base.SupportedAlgosLedger() -} - -func (kb dbKeybase) writeLocalKey(name string, priv tmcrypto.PrivKey, passphrase string, algo SigningAlgo) Info { - // encrypt private key using passphrase - privArmor := crypto.EncryptArmorPrivKey(priv, passphrase, string(algo)) - - // make Info - pub := priv.PubKey() - info := newLocalInfo(name, pub, privArmor, algo) - - kb.writeInfo(name, info) - return info -} - -func (kb dbKeybase) writeInfo(name string, info Info) { - // write the info by key - key := infoKey(name) - serializedInfo := marshalInfo(info) - - kb.db.SetSync(key, serializedInfo) - - // store a pointer to the infokey by address for fast lookup - kb.db.SetSync(addrStringKey(info.GetAddress()), key) -} - -// this is to be removed together with dbKeybase and the old Keybase interface -func addrStringKey(address types.AccAddress) []byte { - return []byte(fmt.Sprintf("%s.%s", address.String(), addressSuffix)) -} - -func addrHexKey(address types.AccAddress) []byte { - return []byte(fmt.Sprintf("%s.%s", hex.EncodeToString(address.Bytes()), addressSuffix)) -} - -func infoKey(name string) []byte { - return []byte(fmt.Sprintf("%s.%s", name, infoSuffix)) -} diff --git a/crypto/keyring/doc.go b/crypto/keyring/doc.go index 7b09f25ac5e8..369f053b76a3 100644 --- a/crypto/keyring/doc.go +++ b/crypto/keyring/doc.go @@ -6,12 +6,11 @@ // The Keybase interface defines the methods that a type needs to implement to be used // as key storage backend. This package provides few implementations out-of-the-box. // -// New +// NewLegacy // -// The New constructor returns an on-disk implementation backed by LevelDB storage that has been +// The NewLegacy constructor returns an on-disk implementation backed by LevelDB storage that has been // the default implementation used by the SDK until v0.38.0. Due to security concerns, it is -// recommended to drop it in favor of the NewKeyring or NewKeyringFile constructors as it will be -// removed in future releases. +// recommended to drop it in favor of the NewKeyring constructor as it will be removed in future releases. // // NewInMemory // @@ -42,4 +41,6 @@ // https://www.passwordstore.org/ // test This backend stores keys insecurely to disk. It does not prompt for a password to // be unlocked and it should be use only for testing purposes. +// memory Same instance as returned by NewInMemory. This backend uses a transient storage. Keys +// are discarded when the process terminates or the type instance is garbage collected. package keyring diff --git a/crypto/keyring/keybase.go b/crypto/keyring/keybase.go index b2f619aff3e6..149069ff50be 100644 --- a/crypto/keyring/keybase.go +++ b/crypto/keyring/keybase.go @@ -40,9 +40,6 @@ type Keybase interface { // CreateMulti creates, stores, and returns a new multsig (offline) key reference CreateMulti(name string, pubkey crypto.PubKey) (info Info, err error) - // The following operations will *only* work on locally-stored keys - Update(name, oldpass string, getNewpass func() (string, error)) error - // Import imports ASCII armored Info objects. Import(name string, armor string) (err error) diff --git a/crypto/keyring/keybase_test.go b/crypto/keyring/keybase_test.go deleted file mode 100644 index e55995db9d31..000000000000 --- a/crypto/keyring/keybase_test.go +++ /dev/null @@ -1,495 +0,0 @@ -package keyring - -import ( - "fmt" - "testing" - - "github.com/stretchr/testify/require" - - tmcrypto "github.com/tendermint/tendermint/crypto" - "github.com/tendermint/tendermint/crypto/ed25519" - "github.com/tendermint/tendermint/crypto/secp256k1" - - "github.com/cosmos/cosmos-sdk/crypto" - "github.com/cosmos/cosmos-sdk/crypto/keys/hd" - sdk "github.com/cosmos/cosmos-sdk/types" -) - -func init() { - crypto.BcryptSecurityParameter = 1 -} - -const ( - nums = "1234" - foobar = "foobar" -) - -func TestLanguage(t *testing.T) { - kb := NewInMemory() - _, _, err := kb.CreateMnemonic("something", Japanese, "no_pass", Secp256k1) - require.Error(t, err) - require.Equal(t, "unsupported language: only english is supported", err.Error()) -} - -func TestCreateAccountInvalidMnemonic(t *testing.T) { - kb := NewInMemory() - _, err := kb.CreateAccount( - "some_account", - "malarkey pair crucial catch public canyon evil outer stage ten gym tornado", - "", "", CreateHDPath(0, 0).String(), Secp256k1) - require.Error(t, err) - require.Equal(t, "Invalid mnemonic", err.Error()) -} - -func TestCreateLedgerUnsupportedAlgo(t *testing.T) { - kb := NewInMemory() - - supportedLedgerAlgos := kb.SupportedAlgosLedger() - for _, supportedAlgo := range supportedLedgerAlgos { - if Ed25519 == supportedAlgo { - require.FailNow(t, "Was not an unsupported algorithm") - } - } - - _, err := kb.CreateLedger("some_account", Ed25519, "cosmos", 0, 1) - require.Error(t, err) - require.Equal(t, "unsupported signing algo", err.Error()) -} - -func TestCreateLedger(t *testing.T) { - kb := NewInMemory(WithSupportedAlgosLedger([]SigningAlgo{Secp256k1, Ed25519})) - - // test_cover and test_unit will result in different answers - // test_cover does not compile some dependencies so ledger is disabled - // test_unit may add a ledger mock - // both cases are acceptable - supportedLedgerAlgos := kb.SupportedAlgosLedger() - secpSupported := false - edSupported := false - for _, supportedAlgo := range supportedLedgerAlgos { - secpSupported = secpSupported || (supportedAlgo == Secp256k1) - edSupported = edSupported || (supportedAlgo == Ed25519) - } - require.True(t, secpSupported) - require.True(t, edSupported) - - ledger, err := kb.CreateLedger("some_account", Secp256k1, "cosmos", 3, 1) - - if err != nil { - require.Error(t, err) - require.Equal(t, "ledger nano S: support for ledger devices is not available in this executable", err.Error()) - require.Nil(t, ledger) - t.Skip("ledger nano S: support for ledger devices is not available in this executable") - return - } - - // The mock is available, check that the address is correct - pubKey := ledger.GetPubKey() - pk, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pubKey) - require.NoError(t, err) - require.Equal(t, "cosmospub1addwnpepqdszcr95mrqqs8lw099aa9h8h906zmet22pmwe9vquzcgvnm93eqygufdlv", pk) - - // Check that restoring the key gets the same results - restoredKey, err := kb.Get("some_account") - require.NoError(t, err) - require.NotNil(t, restoredKey) - require.Equal(t, "some_account", restoredKey.GetName()) - require.Equal(t, TypeLedger, restoredKey.GetType()) - pubKey = restoredKey.GetPubKey() - pk, err = sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pubKey) - require.NoError(t, err) - require.Equal(t, "cosmospub1addwnpepqdszcr95mrqqs8lw099aa9h8h906zmet22pmwe9vquzcgvnm93eqygufdlv", pk) - - path, err := restoredKey.GetPath() - require.NoError(t, err) - require.Equal(t, "44'/118'/3'/0/1", path.String()) -} - -// TestKeyManagement makes sure we can manipulate these keys well -func TestKeyManagement(t *testing.T) { - // make the storage with reasonable defaults - cstore := NewInMemory(WithSupportedAlgos([]SigningAlgo{Secp256k1, Sr25519})) - - // Test modified supported algos - supportedAlgos := cstore.SupportedAlgos() - secpSupported := false - edSupported := false - srSupported := false - for _, supportedAlgo := range supportedAlgos { - secpSupported = secpSupported || (supportedAlgo == Secp256k1) - edSupported = edSupported || (supportedAlgo == Ed25519) - srSupported = srSupported || (supportedAlgo == Sr25519) - } - require.True(t, secpSupported) - require.False(t, edSupported) - require.True(t, srSupported) - - algo := Secp256k1 - n1, n2, n3 := "personal", "business", "other" - p1, p2 := nums, "really-secure!@#$" - - // Check empty state - l, err := cstore.List() - require.Nil(t, err) - require.Empty(t, l) - - _, _, err = cstore.CreateMnemonic(n1, English, p1, Ed25519) - require.Error(t, err, "ed25519 keys are currently not supported by keybase") - - // create some keys - _, err = cstore.Get(n1) - require.Error(t, err) - i, _, err := cstore.CreateMnemonic(n1, English, p1, algo) - - require.NoError(t, err) - require.Equal(t, n1, i.GetName()) - _, _, err = cstore.CreateMnemonic(n2, English, p2, algo) - require.NoError(t, err) - - // we can get these keys - i2, err := cstore.Get(n2) - require.NoError(t, err) - _, err = cstore.Get(n3) - require.NotNil(t, err) - _, err = cstore.GetByAddress(accAddr(i2)) - require.NoError(t, err) - addr, err := sdk.AccAddressFromBech32("cosmos1yq8lgssgxlx9smjhes6ryjasmqmd3ts2559g0t") - require.NoError(t, err) - _, err = cstore.GetByAddress(addr) - require.NotNil(t, err) - - // list shows them in order - keyS, err := cstore.List() - require.NoError(t, err) - require.Equal(t, 2, len(keyS)) - // note these are in alphabetical order - require.Equal(t, n2, keyS[0].GetName()) - require.Equal(t, n1, keyS[1].GetName()) - require.Equal(t, i2.GetPubKey(), keyS[0].GetPubKey()) - - // deleting a key removes it - err = cstore.Delete("bad name", "foo", false) - require.NotNil(t, err) - err = cstore.Delete(n1, p1, false) - require.NoError(t, err) - keyS, err = cstore.List() - require.NoError(t, err) - require.Equal(t, 1, len(keyS)) - _, err = cstore.Get(n1) - require.Error(t, err) - - // create an offline key - o1 := "offline" - priv1 := ed25519.GenPrivKey() - pub1 := priv1.PubKey() - i, err = cstore.CreateOffline(o1, pub1, algo) - require.Nil(t, err) - require.Equal(t, pub1, i.GetPubKey()) - require.Equal(t, o1, i.GetName()) - iOffline := i.(*offlineInfo) - require.Equal(t, algo, iOffline.GetAlgo()) - keyS, err = cstore.List() - require.NoError(t, err) - require.Equal(t, 2, len(keyS)) - - // delete the offline key - err = cstore.Delete(o1, "", false) - require.NoError(t, err) - keyS, err = cstore.List() - require.NoError(t, err) - require.Equal(t, 1, len(keyS)) - - // addr cache gets nuked - and test skip flag - err = cstore.Delete(n2, "", true) - require.NoError(t, err) -} - -// TestSignVerify does some detailed checks on how we sign and validate -// signatures -func TestSignVerify(t *testing.T) { - cstore := NewInMemory() - algo := Secp256k1 - - n1, n2, n3 := "some dude", "a dudette", "dude-ish" - p1, p2, p3 := nums, foobar, foobar - - // create two users and get their info - i1, _, err := cstore.CreateMnemonic(n1, English, p1, algo) - require.Nil(t, err) - - i2, _, err := cstore.CreateMnemonic(n2, English, p2, algo) - require.Nil(t, err) - - // Import a public key - armor, err := cstore.ExportPubKey(n2) - require.Nil(t, err) - err = cstore.ImportPubKey(n3, armor) - require.NoError(t, err) - i3, err := cstore.Get(n3) - require.NoError(t, err) - require.Equal(t, i3.GetName(), n3) - - // let's try to sign some messages - d1 := []byte("my first message") - d2 := []byte("some other important info!") - d3 := []byte("feels like I forgot something...") - - // try signing both data with both .. - s11, pub1, err := cstore.Sign(n1, p1, d1) - require.Nil(t, err) - require.Equal(t, i1.GetPubKey(), pub1) - - s12, pub1, err := cstore.Sign(n1, p1, d2) - require.Nil(t, err) - require.Equal(t, i1.GetPubKey(), pub1) - - s21, pub2, err := cstore.Sign(n2, p2, d1) - require.Nil(t, err) - require.Equal(t, i2.GetPubKey(), pub2) - - s22, pub2, err := cstore.Sign(n2, p2, d2) - require.Nil(t, err) - require.Equal(t, i2.GetPubKey(), pub2) - - // let's try to validate and make sure it only works when everything is proper - cases := []struct { - key tmcrypto.PubKey - data []byte - sig []byte - valid bool - }{ - // proper matches - {i1.GetPubKey(), d1, s11, true}, - // change data, pubkey, or signature leads to fail - {i1.GetPubKey(), d2, s11, false}, - {i2.GetPubKey(), d1, s11, false}, - {i1.GetPubKey(), d1, s21, false}, - // make sure other successes - {i1.GetPubKey(), d2, s12, true}, - {i2.GetPubKey(), d1, s21, true}, - {i2.GetPubKey(), d2, s22, true}, - } - - for i, tc := range cases { - valid := tc.key.VerifyBytes(tc.data, tc.sig) - require.Equal(t, tc.valid, valid, "%d", i) - } - - // Now try to sign data with a secret-less key - _, _, err = cstore.Sign(n3, p3, d3) - require.Error(t, err) - require.Equal(t, "cannot sign with offline keys", err.Error()) -} - -func assertPassword(t *testing.T, cstore Keybase, name, pass, badpass string) { - getNewpass := func() (string, error) { return pass, nil } - err := cstore.Update(name, badpass, getNewpass) - require.NotNil(t, err) - err = cstore.Update(name, pass, getNewpass) - require.Nil(t, err, "%+v", err) -} - -// TestExportImport tests exporting and importing -func TestExportImport(t *testing.T) { - // make the storage with reasonable defaults - cstore := NewInMemory() - - info, _, err := cstore.CreateMnemonic("john", English, "secretcpw", Secp256k1) - require.NoError(t, err) - require.Equal(t, info.GetName(), "john") - - john, err := cstore.Get("john") - require.NoError(t, err) - require.Equal(t, info.GetName(), "john") - johnAddr := info.GetPubKey().Address() - - armor, err := cstore.Export("john") - require.NoError(t, err) - - err = cstore.Import("john2", armor) - require.NoError(t, err) - - john2, err := cstore.Get("john2") - require.NoError(t, err) - - require.Equal(t, john.GetPubKey().Address(), johnAddr) - require.Equal(t, john.GetName(), "john") - require.Equal(t, john, john2) -} - -// -func TestExportImportPubKey(t *testing.T) { - // make the storage with reasonable defaults - cstore := NewInMemory() - - // CreateMnemonic a private-public key pair and ensure consistency - notPasswd := "n9y25ah7" - info, _, err := cstore.CreateMnemonic("john", English, notPasswd, Secp256k1) - require.Nil(t, err) - require.NotEqual(t, info, "") - require.Equal(t, info.GetName(), "john") - addr := info.GetPubKey().Address() - john, err := cstore.Get("john") - require.NoError(t, err) - require.Equal(t, john.GetName(), "john") - require.Equal(t, john.GetPubKey().Address(), addr) - - // Export the public key only - armor, err := cstore.ExportPubKey("john") - require.NoError(t, err) - // Import it under a different name - err = cstore.ImportPubKey("john-pubkey-only", armor) - require.NoError(t, err) - // Ensure consistency - john2, err := cstore.Get("john-pubkey-only") - require.NoError(t, err) - // Compare the public keys - require.True(t, john.GetPubKey().Equals(john2.GetPubKey())) - // Ensure the original key hasn't changed - john, err = cstore.Get("john") - require.NoError(t, err) - require.Equal(t, john.GetPubKey().Address(), addr) - require.Equal(t, john.GetName(), "john") - - // Ensure keys cannot be overwritten - err = cstore.ImportPubKey("john-pubkey-only", armor) - require.NotNil(t, err) -} - -// TestAdvancedKeyManagement verifies update, import, export functionality -func TestAdvancedKeyManagement(t *testing.T) { - // make the storage with reasonable defaults - cstore := NewInMemory() - - algo := Secp256k1 - n1, n2 := "old-name", "new name" - p1, p2 := nums, foobar - - // make sure key works with initial password - _, _, err := cstore.CreateMnemonic(n1, English, p1, algo) - require.Nil(t, err, "%+v", err) - assertPassword(t, cstore, n1, p1, p2) - - // update password requires the existing password - getNewpass := func() (string, error) { return p2, nil } - err = cstore.Update(n1, "jkkgkg", getNewpass) - require.NotNil(t, err) - assertPassword(t, cstore, n1, p1, p2) - - // then it changes the password when correct - err = cstore.Update(n1, p1, getNewpass) - require.NoError(t, err) - // p2 is now the proper one! - assertPassword(t, cstore, n1, p2, p1) - - // exporting requires the proper name and passphrase - _, err = cstore.Export(n1 + ".notreal") - require.NotNil(t, err) - _, err = cstore.Export(" " + n1) - require.NotNil(t, err) - _, err = cstore.Export(n1 + " ") - require.NotNil(t, err) - _, err = cstore.Export("") - require.NotNil(t, err) - exported, err := cstore.Export(n1) - require.Nil(t, err, "%+v", err) - - // import succeeds - err = cstore.Import(n2, exported) - require.NoError(t, err) - - // second import fails - err = cstore.Import(n2, exported) - require.NotNil(t, err) -} - -// TestSeedPhrase verifies restoring from a seed phrase -func TestSeedPhrase(t *testing.T) { - - // make the storage with reasonable defaults - cstore := NewInMemory() - - algo := Secp256k1 - n1, n2 := "lost-key", "found-again" - p1, p2 := nums, foobar - - // make sure key works with initial password - info, mnemonic, err := cstore.CreateMnemonic(n1, English, p1, algo) - require.Nil(t, err, "%+v", err) - require.Equal(t, n1, info.GetName()) - require.NotEmpty(t, mnemonic) - - // now, let us delete this key - err = cstore.Delete(n1, p1, false) - require.Nil(t, err, "%+v", err) - _, err = cstore.Get(n1) - require.NotNil(t, err) - - // let us re-create it from the mnemonic-phrase - params := *hd.NewFundraiserParams(0, sdk.CoinType, 0) - hdPath := params.String() - newInfo, err := cstore.CreateAccount(n2, mnemonic, DefaultBIP39Passphrase, p2, hdPath, Secp256k1) - require.NoError(t, err) - require.Equal(t, n2, newInfo.GetName()) - require.Equal(t, info.GetPubKey().Address(), newInfo.GetPubKey().Address()) - require.Equal(t, info.GetPubKey(), newInfo.GetPubKey()) -} - -func ExampleNew() { - // Select the encryption and storage for your cryptostore - customKeyGenFunc := func(bz []byte, algo SigningAlgo) (tmcrypto.PrivKey, error) { - var bzArr [32]byte - copy(bzArr[:], bz) - return secp256k1.PrivKeySecp256k1(bzArr), nil - } - cstore := NewInMemory(WithKeygenFunc(customKeyGenFunc)) - - sec := Secp256k1 - - // Add keys and see they return in alphabetical order - bob, _, err := cstore.CreateMnemonic("Bob", English, "friend", sec) - if err != nil { - // this should never happen - fmt.Println(err) - } else { - // return info here just like in List - fmt.Println(bob.GetName()) - } - _, _, _ = cstore.CreateMnemonic("Alice", English, "secret", sec) - _, _, _ = cstore.CreateMnemonic("Carl", English, "mitm", sec) - info, _ := cstore.List() - for _, i := range info { - fmt.Println(i.GetName()) - } - - // We need to use passphrase to generate a signature - tx := []byte("deadbeef") - sig, pub, err := cstore.Sign("Bob", "friend", tx) - if err != nil { - fmt.Println("don't accept real passphrase") - } - - // and we can validate the signature with publicly available info - binfo, _ := cstore.Get("Bob") - if !binfo.GetPubKey().Equals(bob.GetPubKey()) { - fmt.Println("Get and Create return different keys") - } - - if pub.Equals(binfo.GetPubKey()) { - fmt.Println("signed by Bob") - } - if !pub.VerifyBytes(tx, sig) { - fmt.Println("invalid signature") - } - - // Output: - // Bob - // Alice - // Bob - // Carl - // signed by Bob -} - -func accAddr(info Info) sdk.AccAddress { - return (sdk.AccAddress)(info.GetPubKey().Address()) -} diff --git a/crypto/keyring/keyring.go b/crypto/keyring/keyring.go index c48e0ba4a9c7..a5b62ba3eef2 100644 --- a/crypto/keyring/keyring.go +++ b/crypto/keyring/keyring.go @@ -2,6 +2,7 @@ package keyring import ( "bufio" + "encoding/hex" "fmt" "io" "io/ioutil" @@ -29,6 +30,7 @@ const ( BackendKWallet = "kwallet" BackendPass = "pass" BackendTest = "test" + BackendMemory = "memory" ) const ( @@ -66,6 +68,8 @@ func NewKeyring( var err error switch backend { + case BackendMemory: + return NewInMemory(opts...), nil case BackendTest: db, err = keyring.Open(lkbToKeyringConfig(appName, rootDir, nil, true)) case BackendFile: @@ -86,6 +90,13 @@ func NewKeyring( return newKeyringKeybase(db, opts...), nil } +// NewInMemory creates a transient keyring useful for testing +// purposes and on-the-fly key generation. +// Keybase options can be applied when generating this new Keybase. +func NewInMemory(opts ...KeybaseOption) Keybase { + return newKeyringKeybase(keyring.NewArrayKeyring(nil), opts...) +} + // CreateMnemonic generates a new key and persists it to storage, encrypted // using the provided password. It returns the generated mnemonic and the key Info. // An error is returned if it fails to generate a key for the given algo type, @@ -414,13 +425,6 @@ func (kb keyringKeybase) Delete(name, _ string, _ bool) error { return nil } -// Update changes the passphrase with which an already stored key is encrypted. -// The oldpass must be the current passphrase used for encryption, getNewpass is -// a function to get the passphrase to permanently replace the current passphrase. -func (kb keyringKeybase) Update(name, oldpass string, getNewpass func() (string, error)) error { - return errors.New("unsupported operation") -} - // SupportedAlgos returns a list of supported signing algorithms. func (kb keyringKeybase) SupportedAlgos() []SigningAlgo { return kb.base.SupportedAlgos() @@ -581,3 +585,7 @@ func newRealPrompt(dir string, buf io.Reader) func(string) (string, error) { } } } + +func addrHexKey(address types.AccAddress) []byte { + return []byte(fmt.Sprintf("%s.%s", hex.EncodeToString(address.Bytes()), addressSuffix)) +} diff --git a/crypto/keyring/keyring_test.go b/crypto/keyring/keyring_test.go index c4c3ee301423..e994f91db0b3 100644 --- a/crypto/keyring/keyring_test.go +++ b/crypto/keyring/keyring_test.go @@ -2,19 +2,49 @@ package keyring import ( "bytes" + "fmt" + "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/crypto" + "github.com/tendermint/go-amino" + tmcrypto "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/ed25519" + tmamino "github.com/tendermint/tendermint/crypto/encoding/amino" + "github.com/tendermint/tendermint/crypto/multisig" + "github.com/tendermint/tendermint/crypto/secp256k1" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/crypto" "github.com/cosmos/cosmos-sdk/crypto/keys/hd" "github.com/cosmos/cosmos-sdk/tests" sdk "github.com/cosmos/cosmos-sdk/types" ) -func TestLazyKeyManagementKeyRing(t *testing.T) { +func init() { + crypto.BcryptSecurityParameter = 1 +} + +const ( + nums = "1234" + foobar = "foobar" +) + +func TestNewKeyring(t *testing.T) { + dir, cleanup := tests.NewTestCaseDir(t) + mockIn := strings.NewReader("") + t.Cleanup(cleanup) + kr, err := NewKeyring("cosmos", BackendFile, dir, mockIn) + require.NoError(t, err) + + mockIn.Reset("password\npassword\n") + info, _, err := kr.CreateMnemonic("foo", English, "password", Secp256k1) + require.NoError(t, err) + require.Equal(t, "foo", info.GetName()) +} + +func TestKeyManagementKeyRing(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) t.Cleanup(cleanup) kb, err := NewKeyring("keybasename", "test", dir, nil) @@ -99,7 +129,7 @@ func TestLazyKeyManagementKeyRing(t *testing.T) { // TestSignVerify does some detailed checks on how we sign and validate // signatures -func TestLazySignVerifyKeyRingWithLedger(t *testing.T) { +func TestSignVerifyKeyRingWithLedger(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) t.Cleanup(cleanup) kb, err := NewKeyring("keybasename", "test", dir, nil) @@ -134,7 +164,7 @@ func TestLazySignVerifyKeyRingWithLedger(t *testing.T) { require.Equal(t, "not a ledger object", err.Error()) } -func TestLazySignVerifyKeyRing(t *testing.T) { +func TestSignVerifyKeyRing(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) t.Cleanup(cleanup) kb, err := NewKeyring("keybasename", "test", dir, nil) @@ -184,7 +214,7 @@ func TestLazySignVerifyKeyRing(t *testing.T) { // let's try to validate and make sure it only works when everything is proper cases := []struct { - key crypto.PubKey + key tmcrypto.PubKey data []byte sig []byte valid bool @@ -212,7 +242,7 @@ func TestLazySignVerifyKeyRing(t *testing.T) { require.Equal(t, "cannot sign with offline keys", err.Error()) } -func TestLazyExportImportKeyRing(t *testing.T) { +func TestExportImportKeyRing(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) t.Cleanup(cleanup) kb, err := NewKeyring("keybasename", "test", dir, nil) @@ -241,7 +271,7 @@ func TestLazyExportImportKeyRing(t *testing.T) { require.Equal(t, john, john2) } -func TestLazyExportImportPubKeyKeyRing(t *testing.T) { +func TestExportImportPubKeyKeyRing(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) t.Cleanup(cleanup) kb, err := NewKeyring("keybasename", "test", dir, nil) @@ -282,7 +312,7 @@ func TestLazyExportImportPubKeyKeyRing(t *testing.T) { require.NotNil(t, err) } -func TestLazyExportPrivateKeyObjectKeyRing(t *testing.T) { +func TestExportPrivateKeyObjectKeyRing(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) t.Cleanup(cleanup) kb, err := NewKeyring("keybasename", "test", dir, nil) @@ -298,7 +328,7 @@ func TestLazyExportPrivateKeyObjectKeyRing(t *testing.T) { require.True(t, exported.PubKey().Equals(info.GetPubKey())) } -func TestLazyAdvancedKeyManagementKeyRing(t *testing.T) { +func TestAdvancedKeyManagementKeyRing(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) t.Cleanup(cleanup) kb, err := NewKeyring("keybasename", "test", dir, nil) @@ -332,7 +362,7 @@ func TestLazyAdvancedKeyManagementKeyRing(t *testing.T) { require.NotNil(t, err) } -func TestLazySeedPhraseKeyRing(t *testing.T) { +func TestSeedPhraseKeyRing(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) t.Cleanup(cleanup) kb, err := NewKeyring("keybasename", "test", dir, nil) @@ -393,15 +423,6 @@ func TestKeyringKeybaseExportImportPrivKey(t *testing.T) { require.Equal(t, "The specified item could not be found in the keyring", err.Error()) } -func TestKeyringKeybaseUpdate(t *testing.T) { - dir, cleanup := tests.NewTestCaseDir(t) - t.Cleanup(cleanup) - kb, err := NewKeyring("keybasename", "test", dir, nil) - require.NoError(t, err) - require.Equal(t, "unsupported operation", kb.Update("john", "oldpassword", - func() (string, error) { return "", nil }).Error()) -} - func TestSupportedAlgos(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) t.Cleanup(cleanup) @@ -410,3 +431,575 @@ func TestSupportedAlgos(t *testing.T) { require.Equal(t, []SigningAlgo{"secp256k1"}, kb.SupportedAlgos()) require.Equal(t, []SigningAlgo{"secp256k1"}, kb.SupportedAlgosLedger()) } + +func TestInMemoryLanguage(t *testing.T) { + kb := NewInMemory() + _, _, err := kb.CreateMnemonic("something", Japanese, "no_pass", Secp256k1) + require.Error(t, err) + require.Equal(t, "unsupported language: only english is supported", err.Error()) +} + +func TestInMemoryCreateMultisig(t *testing.T) { + kb, err := NewKeyring("keybasename", "memory", "", nil) + require.NoError(t, err) + multi := multisig.PubKeyMultisigThreshold{ + K: 1, + PubKeys: []tmcrypto.PubKey{secp256k1.GenPrivKey().PubKey()}, + } + _, err = kb.CreateMulti("multi", multi) + require.NoError(t, err) +} + +func TestInMemoryCreateAccountInvalidMnemonic(t *testing.T) { + kb := NewInMemory() + _, err := kb.CreateAccount( + "some_account", + "malarkey pair crucial catch public canyon evil outer stage ten gym tornado", + "", "", CreateHDPath(0, 0).String(), Secp256k1) + require.Error(t, err) + require.Equal(t, "Invalid mnemonic", err.Error()) +} + +func TestInMemoryCreateLedgerUnsupportedAlgo(t *testing.T) { + kb := NewInMemory() + + supportedLedgerAlgos := kb.SupportedAlgosLedger() + for _, supportedAlgo := range supportedLedgerAlgos { + if Ed25519 == supportedAlgo { + require.FailNow(t, "Was not an unsupported algorithm") + } + } + + _, err := kb.CreateLedger("some_account", Ed25519, "cosmos", 0, 1) + require.Error(t, err) + require.Equal(t, "unsupported signing algo", err.Error()) +} + +func TestInMemoryCreateLedger(t *testing.T) { + kb := NewInMemory(WithSupportedAlgosLedger([]SigningAlgo{Secp256k1, Ed25519})) + + // test_cover and test_unit will result in different answers + // test_cover does not compile some dependencies so ledger is disabled + // test_unit may add a ledger mock + // both cases are acceptable + supportedLedgerAlgos := kb.SupportedAlgosLedger() + secpSupported := false + edSupported := false + for _, supportedAlgo := range supportedLedgerAlgos { + secpSupported = secpSupported || (supportedAlgo == Secp256k1) + edSupported = edSupported || (supportedAlgo == Ed25519) + } + require.True(t, secpSupported) + require.True(t, edSupported) + + ledger, err := kb.CreateLedger("some_account", Secp256k1, "cosmos", 3, 1) + + if err != nil { + require.Error(t, err) + require.Equal(t, "ledger nano S: support for ledger devices is not available in this executable", err.Error()) + require.Nil(t, ledger) + t.Skip("ledger nano S: support for ledger devices is not available in this executable") + return + } + + // The mock is available, check that the address is correct + pubKey := ledger.GetPubKey() + pk, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pubKey) + require.NoError(t, err) + require.Equal(t, "cosmospub1addwnpepqdszcr95mrqqs8lw099aa9h8h906zmet22pmwe9vquzcgvnm93eqygufdlv", pk) + + // Check that restoring the key gets the same results + restoredKey, err := kb.Get("some_account") + require.NoError(t, err) + require.NotNil(t, restoredKey) + require.Equal(t, "some_account", restoredKey.GetName()) + require.Equal(t, TypeLedger, restoredKey.GetType()) + pubKey = restoredKey.GetPubKey() + pk, err = sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pubKey) + require.NoError(t, err) + require.Equal(t, "cosmospub1addwnpepqdszcr95mrqqs8lw099aa9h8h906zmet22pmwe9vquzcgvnm93eqygufdlv", pk) + + path, err := restoredKey.GetPath() + require.NoError(t, err) + require.Equal(t, "44'/118'/3'/0/1", path.String()) +} + +// TestInMemoryKeyManagement makes sure we can manipulate these keys well +func TestInMemoryKeyManagement(t *testing.T) { + // make the storage with reasonable defaults + cstore := NewInMemory(WithSupportedAlgos([]SigningAlgo{Secp256k1, Sr25519})) + + // Test modified supported algos + supportedAlgos := cstore.SupportedAlgos() + secpSupported := false + edSupported := false + srSupported := false + for _, supportedAlgo := range supportedAlgos { + secpSupported = secpSupported || (supportedAlgo == Secp256k1) + edSupported = edSupported || (supportedAlgo == Ed25519) + srSupported = srSupported || (supportedAlgo == Sr25519) + } + require.True(t, secpSupported) + require.False(t, edSupported) + require.True(t, srSupported) + + algo := Secp256k1 + n1, n2, n3 := "personal", "business", "other" + p1, p2 := nums, "really-secure!@#$" + + // Check empty state + l, err := cstore.List() + require.Nil(t, err) + require.Empty(t, l) + + _, _, err = cstore.CreateMnemonic(n1, English, p1, Ed25519) + require.Error(t, err, "ed25519 keys are currently not supported by keybase") + + // create some keys + _, err = cstore.Get(n1) + require.Error(t, err) + i, _, err := cstore.CreateMnemonic(n1, English, p1, algo) + + require.NoError(t, err) + require.Equal(t, n1, i.GetName()) + _, _, err = cstore.CreateMnemonic(n2, English, p2, algo) + require.NoError(t, err) + + // we can get these keys + i2, err := cstore.Get(n2) + require.NoError(t, err) + _, err = cstore.Get(n3) + require.NotNil(t, err) + _, err = cstore.GetByAddress(accAddr(i2)) + require.NoError(t, err) + addr, err := sdk.AccAddressFromBech32("cosmos1yq8lgssgxlx9smjhes6ryjasmqmd3ts2559g0t") + require.NoError(t, err) + _, err = cstore.GetByAddress(addr) + require.NotNil(t, err) + + // list shows them in order + keyS, err := cstore.List() + require.NoError(t, err) + require.Equal(t, 2, len(keyS)) + // note these are in alphabetical order + require.Equal(t, n2, keyS[0].GetName()) + require.Equal(t, n1, keyS[1].GetName()) + require.Equal(t, i2.GetPubKey(), keyS[0].GetPubKey()) + + // deleting a key removes it + err = cstore.Delete("bad name", "foo", false) + require.NotNil(t, err) + err = cstore.Delete(n1, p1, false) + require.NoError(t, err) + keyS, err = cstore.List() + require.NoError(t, err) + require.Equal(t, 1, len(keyS)) + _, err = cstore.Get(n1) + require.Error(t, err) + + // create an offline key + o1 := "offline" + priv1 := ed25519.GenPrivKey() + pub1 := priv1.PubKey() + i, err = cstore.CreateOffline(o1, pub1, algo) + require.Nil(t, err) + require.Equal(t, pub1, i.GetPubKey()) + require.Equal(t, o1, i.GetName()) + iOffline := i.(*offlineInfo) + require.Equal(t, algo, iOffline.GetAlgo()) + keyS, err = cstore.List() + require.NoError(t, err) + require.Equal(t, 2, len(keyS)) + + // delete the offline key + err = cstore.Delete(o1, "", false) + require.NoError(t, err) + keyS, err = cstore.List() + require.NoError(t, err) + require.Equal(t, 1, len(keyS)) + + // addr cache gets nuked - and test skip flag + err = cstore.Delete(n2, "", true) + require.NoError(t, err) +} + +// TestInMemorySignVerify does some detailed checks on how we sign and validate +// signatures +func TestInMemorySignVerify(t *testing.T) { + cstore := NewInMemory() + algo := Secp256k1 + + n1, n2, n3 := "some dude", "a dudette", "dude-ish" + p1, p2, p3 := nums, foobar, foobar + + // create two users and get their info + i1, _, err := cstore.CreateMnemonic(n1, English, p1, algo) + require.Nil(t, err) + + i2, _, err := cstore.CreateMnemonic(n2, English, p2, algo) + require.Nil(t, err) + + // Import a public key + armor, err := cstore.ExportPubKey(n2) + require.Nil(t, err) + err = cstore.ImportPubKey(n3, armor) + require.NoError(t, err) + i3, err := cstore.Get(n3) + require.NoError(t, err) + require.Equal(t, i3.GetName(), n3) + + // let's try to sign some messages + d1 := []byte("my first message") + d2 := []byte("some other important info!") + d3 := []byte("feels like I forgot something...") + + // try signing both data with both .. + s11, pub1, err := cstore.Sign(n1, p1, d1) + require.Nil(t, err) + require.Equal(t, i1.GetPubKey(), pub1) + + s12, pub1, err := cstore.Sign(n1, p1, d2) + require.Nil(t, err) + require.Equal(t, i1.GetPubKey(), pub1) + + s21, pub2, err := cstore.Sign(n2, p2, d1) + require.Nil(t, err) + require.Equal(t, i2.GetPubKey(), pub2) + + s22, pub2, err := cstore.Sign(n2, p2, d2) + require.Nil(t, err) + require.Equal(t, i2.GetPubKey(), pub2) + + // let's try to validate and make sure it only works when everything is proper + cases := []struct { + key tmcrypto.PubKey + data []byte + sig []byte + valid bool + }{ + // proper matches + {i1.GetPubKey(), d1, s11, true}, + // change data, pubkey, or signature leads to fail + {i1.GetPubKey(), d2, s11, false}, + {i2.GetPubKey(), d1, s11, false}, + {i1.GetPubKey(), d1, s21, false}, + // make sure other successes + {i1.GetPubKey(), d2, s12, true}, + {i2.GetPubKey(), d1, s21, true}, + {i2.GetPubKey(), d2, s22, true}, + } + + for i, tc := range cases { + valid := tc.key.VerifyBytes(tc.data, tc.sig) + require.Equal(t, tc.valid, valid, "%d", i) + } + + // Now try to sign data with a secret-less key + _, _, err = cstore.Sign(n3, p3, d3) + require.Error(t, err) + require.Equal(t, "cannot sign with offline keys", err.Error()) +} + +// TestInMemoryExportImport tests exporting and importing +func TestInMemoryExportImport(t *testing.T) { + // make the storage with reasonable defaults + cstore := NewInMemory() + + info, _, err := cstore.CreateMnemonic("john", English, "secretcpw", Secp256k1) + require.NoError(t, err) + require.Equal(t, info.GetName(), "john") + + john, err := cstore.Get("john") + require.NoError(t, err) + require.Equal(t, info.GetName(), "john") + johnAddr := info.GetPubKey().Address() + + armor, err := cstore.Export("john") + require.NoError(t, err) + + err = cstore.Import("john2", armor) + require.NoError(t, err) + + john2, err := cstore.Get("john2") + require.NoError(t, err) + + require.Equal(t, john.GetPubKey().Address(), johnAddr) + require.Equal(t, john.GetName(), "john") + require.Equal(t, john, john2) +} + +func TestInMemoryExportImportPrivKey(t *testing.T) { + kb := NewInMemory() + + info, _, err := kb.CreateMnemonic("john", English, "secretcpw", Secp256k1) + require.NoError(t, err) + require.Equal(t, info.GetName(), "john") + priv1, err := kb.Get("john") + require.NoError(t, err) + + // decrypt local private key, and produce encrypted ASCII armored output + armored, err := kb.ExportPrivKey("john", "secretcpw", "new_secretcpw") + require.NoError(t, err) + + // delete exported key + require.NoError(t, kb.Delete("john", "", true)) + _, err = kb.Get("john") + require.Error(t, err) + + // import armored key + require.NoError(t, kb.ImportPrivKey("john", armored, "new_secretcpw")) + + // ensure old and new keys match + priv2, err := kb.Get("john") + require.NoError(t, err) + require.True(t, priv1.GetPubKey().Equals(priv2.GetPubKey())) +} + +func TestInMemoryExportImportPubKey(t *testing.T) { + // make the storage with reasonable defaults + cstore := NewInMemory() + + // CreateMnemonic a private-public key pair and ensure consistency + notPasswd := "n9y25ah7" + info, _, err := cstore.CreateMnemonic("john", English, notPasswd, Secp256k1) + require.Nil(t, err) + require.NotEqual(t, info, "") + require.Equal(t, info.GetName(), "john") + addr := info.GetPubKey().Address() + john, err := cstore.Get("john") + require.NoError(t, err) + require.Equal(t, john.GetName(), "john") + require.Equal(t, john.GetPubKey().Address(), addr) + + // Export the public key only + armor, err := cstore.ExportPubKey("john") + require.NoError(t, err) + // Import it under a different name + err = cstore.ImportPubKey("john-pubkey-only", armor) + require.NoError(t, err) + // Ensure consistency + john2, err := cstore.Get("john-pubkey-only") + require.NoError(t, err) + // Compare the public keys + require.True(t, john.GetPubKey().Equals(john2.GetPubKey())) + // Ensure the original key hasn't changed + john, err = cstore.Get("john") + require.NoError(t, err) + require.Equal(t, john.GetPubKey().Address(), addr) + require.Equal(t, john.GetName(), "john") + + // Ensure keys cannot be overwritten + err = cstore.ImportPubKey("john-pubkey-only", armor) + require.NotNil(t, err) +} + +func TestInMemoryExportPrivateKeyObject(t *testing.T) { + kb := NewInMemory() + + info, _, err := kb.CreateMnemonic("john", English, "secretcpw", Secp256k1) + require.NoError(t, err) + require.Equal(t, info.GetName(), "john") + + // export private key object + _, err = kb.ExportPrivateKeyObject("john", "invalid") + require.NoError(t, err, "%+v", err) + exported, err := kb.ExportPrivateKeyObject("john", "secretcpw") + require.Nil(t, err, "%+v", err) + require.True(t, exported.PubKey().Equals(info.GetPubKey())) +} + +// TestInMemoryAdvancedKeyManagement verifies update, import, export functionality +func TestInMemoryAdvancedKeyManagement(t *testing.T) { + // make the storage with reasonable defaults + cstore := NewInMemory() + + algo := Secp256k1 + n1, n2 := "old-name", "new name" + p1 := nums + + // make sure key works with initial password + _, _, err := cstore.CreateMnemonic(n1, English, p1, algo) + require.Nil(t, err, "%+v", err) + + // exporting requires the proper name and passphrase + _, err = cstore.Export(n1 + ".notreal") + require.NotNil(t, err) + _, err = cstore.Export(" " + n1) + require.NotNil(t, err) + _, err = cstore.Export(n1 + " ") + require.NotNil(t, err) + _, err = cstore.Export("") + require.NotNil(t, err) + exported, err := cstore.Export(n1) + require.Nil(t, err, "%+v", err) + + // import succeeds + err = cstore.Import(n2, exported) + require.NoError(t, err) + + // second import fails + err = cstore.Import(n2, exported) + require.NotNil(t, err) +} + +// TestInMemorySeedPhrase verifies restoring from a seed phrase +func TestInMemorySeedPhrase(t *testing.T) { + + // make the storage with reasonable defaults + cstore := NewInMemory() + + algo := Secp256k1 + n1, n2 := "lost-key", "found-again" + p1, p2 := nums, foobar + + // make sure key works with initial password + info, mnemonic, err := cstore.CreateMnemonic(n1, English, p1, algo) + require.Nil(t, err, "%+v", err) + require.Equal(t, n1, info.GetName()) + require.NotEmpty(t, mnemonic) + + // now, let us delete this key + err = cstore.Delete(n1, p1, false) + require.Nil(t, err, "%+v", err) + _, err = cstore.Get(n1) + require.NotNil(t, err) + + // let us re-create it from the mnemonic-phrase + params := *hd.NewFundraiserParams(0, sdk.CoinType, 0) + hdPath := params.String() + newInfo, err := cstore.CreateAccount(n2, mnemonic, DefaultBIP39Passphrase, p2, hdPath, Secp256k1) + require.NoError(t, err) + require.Equal(t, n2, newInfo.GetName()) + require.Equal(t, info.GetPubKey().Address(), newInfo.GetPubKey().Address()) + require.Equal(t, info.GetPubKey(), newInfo.GetPubKey()) +} + +func ExampleNew() { + // Select the encryption and storage for your cryptostore + customKeyGenFunc := func(bz []byte, algo SigningAlgo) (tmcrypto.PrivKey, error) { + var bzArr [32]byte + copy(bzArr[:], bz) + return secp256k1.PrivKeySecp256k1(bzArr), nil + } + cstore := NewInMemory(WithKeygenFunc(customKeyGenFunc)) + + sec := Secp256k1 + + // Add keys and see they return in alphabetical order + bob, _, err := cstore.CreateMnemonic("Bob", English, "friend", sec) + if err != nil { + // this should never happen + fmt.Println(err) + } else { + // return info here just like in List + fmt.Println(bob.GetName()) + } + _, _, _ = cstore.CreateMnemonic("Alice", English, "secret", sec) + _, _, _ = cstore.CreateMnemonic("Carl", English, "mitm", sec) + info, _ := cstore.List() + for _, i := range info { + fmt.Println(i.GetName()) + } + + // We need to use passphrase to generate a signature + tx := []byte("deadbeef") + sig, pub, err := cstore.Sign("Bob", "friend", tx) + if err != nil { + fmt.Println("don't accept real passphrase") + } + + // and we can validate the signature with publicly available info + binfo, _ := cstore.Get("Bob") + if !binfo.GetPubKey().Equals(bob.GetPubKey()) { + fmt.Println("Get and Create return different keys") + } + + if pub.Equals(binfo.GetPubKey()) { + fmt.Println("signed by Bob") + } + if !pub.VerifyBytes(tx, sig) { + fmt.Println("invalid signature") + } + + // Output: + // Bob + // Alice + // Bob + // Carl + // signed by Bob +} + +func accAddr(info Info) sdk.AccAddress { + return (sdk.AccAddress)(info.GetPubKey().Address()) +} + +var _ tmcrypto.PrivKey = testPriv{} +var _ tmcrypto.PubKey = testPub{} +var testCdc *amino.Codec + +type testPriv []byte + +func (privkey testPriv) PubKey() tmcrypto.PubKey { return testPub{} } +func (privkey testPriv) Bytes() []byte { + return testCdc.MustMarshalBinaryBare(privkey) +} +func (privkey testPriv) Sign(msg []byte) ([]byte, error) { return []byte{}, nil } +func (privkey testPriv) Equals(other tmcrypto.PrivKey) bool { return true } + +type testPub []byte + +func (key testPub) Address() tmcrypto.Address { return tmcrypto.Address{} } +func (key testPub) Bytes() []byte { + return testCdc.MustMarshalBinaryBare(key) +} +func (key testPub) VerifyBytes(msg []byte, sig []byte) bool { return true } +func (key testPub) Equals(other tmcrypto.PubKey) bool { return true } + +func TestInMemoryKeygenOverride(t *testing.T) { + // Save existing codec and reset after test + cryptoCdc := CryptoCdc + t.Cleanup(func() { + CryptoCdc = cryptoCdc + }) + + // Setup testCdc encoding and decoding new key type + testCdc = codec.New() + RegisterCodec(testCdc) + tmamino.RegisterAmino(testCdc) + + // Set up codecs for using new key types + privName, pubName := "test/priv_name", "test/pub_name" + tmamino.RegisterKeyType(testPriv{}, privName) + tmamino.RegisterKeyType(testPub{}, pubName) + testCdc.RegisterConcrete(testPriv{}, privName, nil) + testCdc.RegisterConcrete(testPub{}, pubName, nil) + CryptoCdc = testCdc + + overrideCalled := false + dummyFunc := func(bz []byte, algo SigningAlgo) (tmcrypto.PrivKey, error) { + overrideCalled = true + return testPriv(bz), nil + } + + kb := NewInMemory(WithKeygenFunc(dummyFunc)) + + testName, pw := "name", "testPassword" + + // create new key which will generate with + info, _, err := kb.CreateMnemonic(testName, English, pw, Secp256k1) + require.NoError(t, err) + require.Equal(t, info.GetName(), testName) + + // Assert overridden function was called + require.True(t, overrideCalled) + + // export private key object + exported, err := kb.ExportPrivateKeyObject(testName, pw) + require.Nil(t, err, "%+v", err) + + // require that the key type is the new key + _, ok := exported.(testPriv) + require.True(t, ok) + + require.True(t, exported.PubKey().Equals(info.GetPubKey())) +} diff --git a/crypto/keyring/lazy_keybase.go b/crypto/keyring/lazy_keybase.go deleted file mode 100644 index c2b5aa972cf3..000000000000 --- a/crypto/keyring/lazy_keybase.go +++ /dev/null @@ -1,221 +0,0 @@ -package keyring - -import ( - "fmt" - - "github.com/tendermint/tendermint/crypto" - tmos "github.com/tendermint/tendermint/libs/os" - - sdk "github.com/cosmos/cosmos-sdk/types" -) - -var _ Keybase = lazyKeybase{} - -// NOTE: lazyKeybase will be deprecated in favor of lazyKeybaseKeyring. -type lazyKeybase struct { - name string - dir string - options []KeybaseOption -} - -// New creates a new instance of a lazy keybase. -func New(name, dir string, opts ...KeybaseOption) Keybase { - if err := tmos.EnsureDir(dir, 0700); err != nil { - panic(fmt.Sprintf("failed to create Keybase directory: %s", err)) - } - - return lazyKeybase{name: name, dir: dir, options: opts} -} - -func (lkb lazyKeybase) List() ([]Info, error) { - db, err := sdk.NewLevelDB(lkb.name, lkb.dir) - if err != nil { - return nil, err - } - defer db.Close() - - return newDBKeybase(db, lkb.options...).List() -} - -func (lkb lazyKeybase) Get(name string) (Info, error) { - db, err := sdk.NewLevelDB(lkb.name, lkb.dir) - if err != nil { - return nil, err - } - defer db.Close() - - return newDBKeybase(db, lkb.options...).Get(name) -} - -func (lkb lazyKeybase) GetByAddress(address sdk.AccAddress) (Info, error) { - db, err := sdk.NewLevelDB(lkb.name, lkb.dir) - if err != nil { - return nil, err - } - defer db.Close() - - return newDBKeybase(db, lkb.options...).GetByAddress(address) -} - -func (lkb lazyKeybase) Delete(name, passphrase string, skipPass bool) error { - db, err := sdk.NewLevelDB(lkb.name, lkb.dir) - if err != nil { - return err - } - defer db.Close() - - return newDBKeybase(db, lkb.options...).Delete(name, passphrase, skipPass) -} - -func (lkb lazyKeybase) Sign(name, passphrase string, msg []byte) ([]byte, crypto.PubKey, error) { - db, err := sdk.NewLevelDB(lkb.name, lkb.dir) - if err != nil { - return nil, nil, err - } - defer db.Close() - - return newDBKeybase(db, lkb.options...).Sign(name, passphrase, msg) -} - -func (lkb lazyKeybase) CreateMnemonic(name string, language Language, passwd string, algo SigningAlgo) (info Info, seed string, err error) { - db, err := sdk.NewLevelDB(lkb.name, lkb.dir) - if err != nil { - return nil, "", err - } - defer db.Close() - - return newDBKeybase(db, lkb.options...).CreateMnemonic(name, language, passwd, algo) -} - -func (lkb lazyKeybase) CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd, hdPath string, algo SigningAlgo) (Info, error) { - db, err := sdk.NewLevelDB(lkb.name, lkb.dir) - if err != nil { - return nil, err - } - defer db.Close() - - return newDBKeybase(db, - lkb.options...).CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd, hdPath, algo) -} - -func (lkb lazyKeybase) CreateLedger(name string, algo SigningAlgo, hrp string, account, index uint32) (info Info, err error) { - db, err := sdk.NewLevelDB(lkb.name, lkb.dir) - if err != nil { - return nil, err - } - defer db.Close() - - return newDBKeybase(db, lkb.options...).CreateLedger(name, algo, hrp, account, index) -} - -func (lkb lazyKeybase) CreateOffline(name string, pubkey crypto.PubKey, algo SigningAlgo) (info Info, err error) { - db, err := sdk.NewLevelDB(lkb.name, lkb.dir) - if err != nil { - return nil, err - } - defer db.Close() - - return newDBKeybase(db, lkb.options...).CreateOffline(name, pubkey, algo) -} - -func (lkb lazyKeybase) CreateMulti(name string, pubkey crypto.PubKey) (info Info, err error) { - db, err := sdk.NewLevelDB(lkb.name, lkb.dir) - if err != nil { - return nil, err - } - defer db.Close() - - return newDBKeybase(db, lkb.options...).CreateMulti(name, pubkey) -} - -func (lkb lazyKeybase) Update(name, oldpass string, getNewpass func() (string, error)) error { - db, err := sdk.NewLevelDB(lkb.name, lkb.dir) - if err != nil { - return err - } - defer db.Close() - - return newDBKeybase(db, lkb.options...).Update(name, oldpass, getNewpass) -} - -func (lkb lazyKeybase) Import(name string, armor string) (err error) { - db, err := sdk.NewLevelDB(lkb.name, lkb.dir) - if err != nil { - return err - } - defer db.Close() - - return newDBKeybase(db, lkb.options...).Import(name, armor) -} - -func (lkb lazyKeybase) ImportPrivKey(name string, armor string, passphrase string) error { - db, err := sdk.NewLevelDB(lkb.name, lkb.dir) - if err != nil { - return err - } - defer db.Close() - - return newDBKeybase(db, lkb.options...).ImportPrivKey(name, armor, passphrase) -} - -func (lkb lazyKeybase) ImportPubKey(name string, armor string) (err error) { - db, err := sdk.NewLevelDB(lkb.name, lkb.dir) - if err != nil { - return err - } - defer db.Close() - - return newDBKeybase(db, lkb.options...).ImportPubKey(name, armor) -} - -func (lkb lazyKeybase) Export(name string) (armor string, err error) { - db, err := sdk.NewLevelDB(lkb.name, lkb.dir) - if err != nil { - return "", err - } - defer db.Close() - - return newDBKeybase(db, lkb.options...).Export(name) -} - -func (lkb lazyKeybase) ExportPubKey(name string) (armor string, err error) { - db, err := sdk.NewLevelDB(lkb.name, lkb.dir) - if err != nil { - return "", err - } - defer db.Close() - - return newDBKeybase(db, lkb.options...).ExportPubKey(name) -} - -func (lkb lazyKeybase) ExportPrivateKeyObject(name string, passphrase string) (crypto.PrivKey, error) { - db, err := sdk.NewLevelDB(lkb.name, lkb.dir) - if err != nil { - return nil, err - } - defer db.Close() - - return newDBKeybase(db, lkb.options...).ExportPrivateKeyObject(name, passphrase) -} - -func (lkb lazyKeybase) ExportPrivKey(name string, decryptPassphrase string, - encryptPassphrase string) (armor string, err error) { - - db, err := sdk.NewLevelDB(lkb.name, lkb.dir) - if err != nil { - return "", err - } - defer db.Close() - - return newDBKeybase(db, lkb.options...).ExportPrivKey(name, decryptPassphrase, encryptPassphrase) -} - -// SupportedAlgos returns a list of supported signing algorithms. -func (lkb lazyKeybase) SupportedAlgos() []SigningAlgo { - return newBaseKeybase(lkb.options...).SupportedAlgos() -} - -// SupportedAlgosLedger returns a list of supported ledger signing algorithms. -func (lkb lazyKeybase) SupportedAlgosLedger() []SigningAlgo { - return newBaseKeybase(lkb.options...).SupportedAlgosLedger() -} diff --git a/crypto/keyring/lazy_keybase_test.go b/crypto/keyring/lazy_keybase_test.go deleted file mode 100644 index d639f500c327..000000000000 --- a/crypto/keyring/lazy_keybase_test.go +++ /dev/null @@ -1,453 +0,0 @@ -package keyring - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - amino "github.com/tendermint/go-amino" - "github.com/tendermint/tendermint/crypto" - "github.com/tendermint/tendermint/crypto/ed25519" - tmamino "github.com/tendermint/tendermint/crypto/encoding/amino" - - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/crypto/keys/hd" - "github.com/cosmos/cosmos-sdk/tests" - sdk "github.com/cosmos/cosmos-sdk/types" -) - -func TestNew(t *testing.T) { - dir, cleanup := tests.NewTestCaseDir(t) - t.Cleanup(cleanup) - kb := New("keybasename", dir) - lazykb, ok := kb.(lazyKeybase) - require.True(t, ok) - require.Equal(t, lazykb.name, "keybasename") - require.Equal(t, lazykb.dir, dir) -} - -func TestLazyKeyManagement(t *testing.T) { - dir, cleanup := tests.NewTestCaseDir(t) - t.Cleanup(cleanup) - kb := New("keybasename", dir) - - algo := Secp256k1 - n1, n2, n3 := "personal", "business", "other" - p1, p2 := nums, "really-secure!@#$" - - // Check empty state - l, err := kb.List() - require.Nil(t, err) - assert.Empty(t, l) - - _, _, err = kb.CreateMnemonic(n1, English, p1, Ed25519) - require.Error(t, err, "ed25519 keys are currently not supported by keybase") - - // create some keys - _, err = kb.Get(n1) - require.Error(t, err) - i, _, err := kb.CreateMnemonic(n1, English, p1, algo) - - require.NoError(t, err) - require.Equal(t, n1, i.GetName()) - _, _, err = kb.CreateMnemonic(n2, English, p2, algo) - require.NoError(t, err) - - // we can get these keys - i2, err := kb.Get(n2) - require.NoError(t, err) - _, err = kb.Get(n3) - require.NotNil(t, err) - _, err = kb.GetByAddress(accAddr(i2)) - require.NoError(t, err) - addr, err := sdk.AccAddressFromBech32("cosmos1yq8lgssgxlx9smjhes6ryjasmqmd3ts2559g0t") - require.NoError(t, err) - _, err = kb.GetByAddress(addr) - require.NotNil(t, err) - - // list shows them in order - keyS, err := kb.List() - require.NoError(t, err) - require.Equal(t, 2, len(keyS)) - // note these are in alphabetical order - require.Equal(t, n2, keyS[0].GetName()) - require.Equal(t, n1, keyS[1].GetName()) - require.Equal(t, i2.GetPubKey(), keyS[0].GetPubKey()) - - // deleting a key removes it - err = kb.Delete("bad name", "foo", false) - require.NotNil(t, err) - err = kb.Delete(n1, p1, false) - require.NoError(t, err) - keyS, err = kb.List() - require.NoError(t, err) - require.Equal(t, 1, len(keyS)) - _, err = kb.Get(n1) - require.Error(t, err) - - // create an offline key - o1 := "offline" - priv1 := ed25519.GenPrivKey() - pub1 := priv1.PubKey() - i, err = kb.CreateOffline(o1, pub1, algo) - require.Nil(t, err) - require.Equal(t, pub1, i.GetPubKey()) - require.Equal(t, o1, i.GetName()) - keyS, err = kb.List() - require.NoError(t, err) - require.Equal(t, 2, len(keyS)) - - // delete the offline key - err = kb.Delete(o1, "", false) - require.NoError(t, err) - keyS, err = kb.List() - require.NoError(t, err) - require.Equal(t, 1, len(keyS)) - - // addr cache gets nuked - and test skip flag - err = kb.Delete(n2, "", true) - require.NoError(t, err) -} - -func TestLazySignVerify(t *testing.T) { - dir, cleanup := tests.NewTestCaseDir(t) - t.Cleanup(cleanup) - kb := New("keybasename", dir) - algo := Secp256k1 - - n1, n2, n3 := "some dude", "a dudette", "dude-ish" - p1, p2, p3 := nums, foobar, foobar - - // create two users and get their info - i1, _, err := kb.CreateMnemonic(n1, English, p1, algo) - require.Nil(t, err) - - i2, _, err := kb.CreateMnemonic(n2, English, p2, algo) - require.Nil(t, err) - - // Import a public key - armor, err := kb.ExportPubKey(n2) - require.Nil(t, err) - err = kb.ImportPubKey(n3, armor) - require.NoError(t, err) - i3, err := kb.Get(n3) - require.NoError(t, err) - require.Equal(t, i3.GetName(), n3) - - // let's try to sign some messages - d1 := []byte("my first message") - d2 := []byte("some other important info!") - d3 := []byte("feels like I forgot something...") - - // try signing both data with both .. - s11, pub1, err := kb.Sign(n1, p1, d1) - require.Nil(t, err) - require.Equal(t, i1.GetPubKey(), pub1) - - s12, pub1, err := kb.Sign(n1, p1, d2) - require.Nil(t, err) - require.Equal(t, i1.GetPubKey(), pub1) - - s21, pub2, err := kb.Sign(n2, p2, d1) - require.Nil(t, err) - require.Equal(t, i2.GetPubKey(), pub2) - - s22, pub2, err := kb.Sign(n2, p2, d2) - require.Nil(t, err) - require.Equal(t, i2.GetPubKey(), pub2) - - // let's try to validate and make sure it only works when everything is proper - cases := []struct { - key crypto.PubKey - data []byte - sig []byte - valid bool - }{ - // proper matches - {i1.GetPubKey(), d1, s11, true}, - // change data, pubkey, or signature leads to fail - {i1.GetPubKey(), d2, s11, false}, - {i2.GetPubKey(), d1, s11, false}, - {i1.GetPubKey(), d1, s21, false}, - // make sure other successes - {i1.GetPubKey(), d2, s12, true}, - {i2.GetPubKey(), d1, s21, true}, - {i2.GetPubKey(), d2, s22, true}, - } - - for i, tc := range cases { - valid := tc.key.VerifyBytes(tc.data, tc.sig) - require.Equal(t, tc.valid, valid, "%d", i) - } - - // Now try to sign data with a secret-less key - _, _, err = kb.Sign(n3, p3, d3) - require.NotNil(t, err) -} - -func TestLazyExportImport(t *testing.T) { - dir, cleanup := tests.NewTestCaseDir(t) - t.Cleanup(cleanup) - kb := New("keybasename", dir) - - info, _, err := kb.CreateMnemonic("john", English, "secretcpw", Secp256k1) - require.NoError(t, err) - require.Equal(t, info.GetName(), "john") - - john, err := kb.Get("john") - require.NoError(t, err) - require.Equal(t, info.GetName(), "john") - johnAddr := info.GetPubKey().Address() - - armor, err := kb.Export("john") - require.NoError(t, err) - - err = kb.Import("john2", armor) - require.NoError(t, err) - - john2, err := kb.Get("john2") - require.NoError(t, err) - - require.Equal(t, john.GetPubKey().Address(), johnAddr) - require.Equal(t, john.GetName(), "john") - require.Equal(t, john, john2) -} - -func TestLazyExportImportPrivKey(t *testing.T) { - dir, cleanup := tests.NewTestCaseDir(t) - t.Cleanup(cleanup) - kb := New("keybasename", dir) - - info, _, err := kb.CreateMnemonic("john", English, "secretcpw", Secp256k1) - require.NoError(t, err) - require.Equal(t, info.GetName(), "john") - priv1, err := kb.Get("john") - require.NoError(t, err) - - // decrypt local private key, and produce encrypted ASCII armored output - armored, err := kb.ExportPrivKey("john", "secretcpw", "new_secretcpw") - require.NoError(t, err) - - // delete exported key - require.NoError(t, kb.Delete("john", "", true)) - _, err = kb.Get("john") - require.Error(t, err) - - // import armored key - require.NoError(t, kb.ImportPrivKey("john", armored, "new_secretcpw")) - - // ensure old and new keys match - priv2, err := kb.Get("john") - require.NoError(t, err) - require.True(t, priv1.GetPubKey().Equals(priv2.GetPubKey())) -} - -func TestLazyExportImportPubKey(t *testing.T) { - dir, cleanup := tests.NewTestCaseDir(t) - t.Cleanup(cleanup) - kb := New("keybasename", dir) - algo := Secp256k1 - - // CreateMnemonic a private-public key pair and ensure consistency - notPasswd := "n9y25ah7" - info, _, err := kb.CreateMnemonic("john", English, notPasswd, algo) - require.Nil(t, err) - require.NotEqual(t, info, "") - require.Equal(t, info.GetName(), "john") - addr := info.GetPubKey().Address() - john, err := kb.Get("john") - require.NoError(t, err) - require.Equal(t, john.GetName(), "john") - require.Equal(t, john.GetPubKey().Address(), addr) - - // Export the public key only - armor, err := kb.ExportPubKey("john") - require.NoError(t, err) - // Import it under a different name - err = kb.ImportPubKey("john-pubkey-only", armor) - require.NoError(t, err) - // Ensure consistency - john2, err := kb.Get("john-pubkey-only") - require.NoError(t, err) - // Compare the public keys - require.True(t, john.GetPubKey().Equals(john2.GetPubKey())) - // Ensure the original key hasn't changed - john, err = kb.Get("john") - require.NoError(t, err) - require.Equal(t, john.GetPubKey().Address(), addr) - require.Equal(t, john.GetName(), "john") - - // Ensure keys cannot be overwritten - err = kb.ImportPubKey("john-pubkey-only", armor) - require.NotNil(t, err) -} - -func TestLazyExportPrivateKeyObject(t *testing.T) { - dir, cleanup := tests.NewTestCaseDir(t) - t.Cleanup(cleanup) - kb := New("keybasename", dir) - - info, _, err := kb.CreateMnemonic("john", English, "secretcpw", Secp256k1) - require.NoError(t, err) - require.Equal(t, info.GetName(), "john") - - // export private key object - _, err = kb.ExportPrivateKeyObject("john", "invalid") - require.NotNil(t, err, "%+v", err) - exported, err := kb.ExportPrivateKeyObject("john", "secretcpw") - require.Nil(t, err, "%+v", err) - require.True(t, exported.PubKey().Equals(info.GetPubKey())) -} - -func TestLazyAdvancedKeyManagement(t *testing.T) { - dir, cleanup := tests.NewTestCaseDir(t) - t.Cleanup(cleanup) - kb := New("keybasename", dir) - - algo := Secp256k1 - n1, n2 := "old-name", "new name" - p1, p2 := nums, foobar - - // make sure key works with initial password - _, _, err := kb.CreateMnemonic(n1, English, p1, algo) - require.Nil(t, err, "%+v", err) - assertPassword(t, kb, n1, p1, p2) - - // update password requires the existing password - getNewpass := func() (string, error) { return p2, nil } - err = kb.Update(n1, "jkkgkg", getNewpass) - require.NotNil(t, err) - assertPassword(t, kb, n1, p1, p2) - - // then it changes the password when correct - err = kb.Update(n1, p1, getNewpass) - require.NoError(t, err) - // p2 is now the proper one! - assertPassword(t, kb, n1, p2, p1) - - // exporting requires the proper name and passphrase - _, err = kb.Export(n1 + ".notreal") - require.NotNil(t, err) - _, err = kb.Export(" " + n1) - require.NotNil(t, err) - _, err = kb.Export(n1 + " ") - require.NotNil(t, err) - _, err = kb.Export("") - require.NotNil(t, err) - exported, err := kb.Export(n1) - require.Nil(t, err, "%+v", err) - - // import succeeds - err = kb.Import(n2, exported) - require.NoError(t, err) - - // second import fails - err = kb.Import(n2, exported) - require.NotNil(t, err) -} - -// TestSeedPhrase verifies restoring from a seed phrase -func TestLazySeedPhrase(t *testing.T) { - dir, cleanup := tests.NewTestCaseDir(t) - t.Cleanup(cleanup) - kb := New("keybasename", dir) - - algo := Secp256k1 - n1, n2 := "lost-key", "found-again" - p1, p2 := nums, foobar - - // make sure key works with initial password - info, mnemonic, err := kb.CreateMnemonic(n1, English, p1, algo) - require.Nil(t, err, "%+v", err) - require.Equal(t, n1, info.GetName()) - assert.NotEmpty(t, mnemonic) - - // now, let us delete this key - err = kb.Delete(n1, p1, false) - require.Nil(t, err, "%+v", err) - _, err = kb.Get(n1) - require.NotNil(t, err) - - // let us re-create it from the mnemonic-phrase - params := *hd.NewFundraiserParams(0, sdk.CoinType, 0) - hdPath := params.String() - newInfo, err := kb.CreateAccount(n2, mnemonic, DefaultBIP39Passphrase, p2, hdPath, algo) - require.NoError(t, err) - require.Equal(t, n2, newInfo.GetName()) - require.Equal(t, info.GetPubKey().Address(), newInfo.GetPubKey().Address()) - require.Equal(t, info.GetPubKey(), newInfo.GetPubKey()) -} - -var _ crypto.PrivKey = testPriv{} -var _ crypto.PubKey = testPub{} -var testCdc *amino.Codec - -type testPriv []byte - -func (privkey testPriv) PubKey() crypto.PubKey { return testPub{} } -func (privkey testPriv) Bytes() []byte { - return testCdc.MustMarshalBinaryBare(privkey) -} -func (privkey testPriv) Sign(msg []byte) ([]byte, error) { return []byte{}, nil } -func (privkey testPriv) Equals(other crypto.PrivKey) bool { return true } - -type testPub []byte - -func (key testPub) Address() crypto.Address { return crypto.Address{} } -func (key testPub) Bytes() []byte { - return testCdc.MustMarshalBinaryBare(key) -} -func (key testPub) VerifyBytes(msg []byte, sig []byte) bool { return true } -func (key testPub) Equals(other crypto.PubKey) bool { return true } - -func TestKeygenOverride(t *testing.T) { - dir, cleanup := tests.NewTestCaseDir(t) - t.Cleanup(cleanup) - - // Save existing codec and reset after test - cryptoCdc := CryptoCdc - t.Cleanup(func() { - CryptoCdc = cryptoCdc - }) - - // Setup testCdc encoding and decoding new key type - testCdc = codec.New() - RegisterCodec(testCdc) - tmamino.RegisterAmino(testCdc) - - // Set up codecs for using new key types - privName, pubName := "test/priv_name", "test/pub_name" - tmamino.RegisterKeyType(testPriv{}, privName) - tmamino.RegisterKeyType(testPub{}, pubName) - testCdc.RegisterConcrete(testPriv{}, privName, nil) - testCdc.RegisterConcrete(testPub{}, pubName, nil) - CryptoCdc = testCdc - - overrideCalled := false - dummyFunc := func(bz []byte, algo SigningAlgo) (crypto.PrivKey, error) { - overrideCalled = true - return testPriv(bz), nil - } - - kb := New("keybasename", dir, WithKeygenFunc(dummyFunc)) - - testName, pw := "name", "testPassword" - - // create new key which will generate with - info, _, err := kb.CreateMnemonic(testName, English, pw, Secp256k1) - require.NoError(t, err) - require.Equal(t, info.GetName(), testName) - - // Assert overridden function was called - require.True(t, overrideCalled) - - // export private key object - exported, err := kb.ExportPrivateKeyObject(testName, pw) - require.Nil(t, err, "%+v", err) - - // require that the key type is the new key - _, ok := exported.(testPriv) - require.True(t, ok) - - require.True(t, exported.PubKey().Equals(info.GetPubKey())) -} diff --git a/crypto/keyring/legacy.go b/crypto/keyring/legacy.go new file mode 100644 index 000000000000..2d61f3155418 --- /dev/null +++ b/crypto/keyring/legacy.go @@ -0,0 +1,188 @@ +package keyring + +import ( + "fmt" + "strings" + + "github.com/pkg/errors" + tmcrypto "github.com/tendermint/tendermint/crypto" + tmos "github.com/tendermint/tendermint/libs/os" + dbm "github.com/tendermint/tm-db" + + "github.com/cosmos/cosmos-sdk/crypto" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +// LegacyKeybase is implemented by the legacy keybase implementation. +type LegacyKeybase interface { + List() ([]Info, error) + Export(name string) (armor string, err error) + ExportPrivKey(name, decryptPassphrase, encryptPassphrase string) (armor string, err error) + ExportPubKey(name string) (armor string, err error) + Close() error +} + +// NewLegacy creates a new instance of a legacy keybase. +func NewLegacy(name, dir string, opts ...KeybaseOption) (LegacyKeybase, error) { + if err := tmos.EnsureDir(dir, 0700); err != nil { + return nil, fmt.Errorf("failed to create Keybase directory: %s", err) + } + + db, err := sdk.NewLevelDB(name, dir) + if err != nil { + return nil, err + } + return newDBKeybase(db, opts...), nil +} + +var _ LegacyKeybase = dbKeybase{} + +// dbKeybase combines encryption and storage implementation to provide a +// full-featured key manager. +// +// NOTE: dbKeybase will be deprecated in favor of keyringKeybase. +type dbKeybase struct { + db dbm.DB +} + +// newDBKeybase creates a new dbKeybase instance using the provided DB for +// reading and writing keys. +func newDBKeybase(db dbm.DB, opts ...KeybaseOption) dbKeybase { + return dbKeybase{ + db: db, + } +} + +// List returns the keys from storage in alphabetical order. +func (kb dbKeybase) List() ([]Info, error) { + var res []Info + + iter, err := kb.db.Iterator(nil, nil) + if err != nil { + return nil, err + } + + defer iter.Close() + + for ; iter.Valid(); iter.Next() { + key := string(iter.Key()) + + // need to include only keys in storage that have an info suffix + if strings.HasSuffix(key, infoSuffix) { + info, err := unmarshalInfo(iter.Value()) + if err != nil { + return nil, err + } + + res = append(res, info) + } + } + + return res, nil +} + +// Get returns the public information about one key. +func (kb dbKeybase) Get(name string) (Info, error) { + bs, err := kb.db.Get(infoKey(name)) + if err != nil { + return nil, err + } + + if len(bs) == 0 { + return nil, sdkerrors.Wrap(sdkerrors.ErrKeyNotFound, name) + } + + return unmarshalInfo(bs) +} + +// ExportPrivateKeyObject returns a PrivKey object given the key name and +// passphrase. An error is returned if the key does not exist or if the Info for +// the key is invalid. +func (kb dbKeybase) ExportPrivateKeyObject(name string, passphrase string) (tmcrypto.PrivKey, error) { + info, err := kb.Get(name) + if err != nil { + return nil, err + } + + var priv tmcrypto.PrivKey + + switch i := info.(type) { + case localInfo: + linfo := i + if linfo.PrivKeyArmor == "" { + err = fmt.Errorf("private key not available") + return nil, err + } + + priv, _, err = crypto.UnarmorDecryptPrivKey(linfo.PrivKeyArmor, passphrase) + if err != nil { + return nil, err + } + + case ledgerInfo, offlineInfo, multiInfo: + return nil, errors.New("only works on local private keys") + } + + return priv, nil +} + +func (kb dbKeybase) Export(name string) (armor string, err error) { + bz, err := kb.db.Get(infoKey(name)) + if err != nil { + return "", err + } + + if bz == nil { + return "", fmt.Errorf("no key to export with name %s", name) + } + + return crypto.ArmorInfoBytes(bz), nil +} + +// ExportPubKey returns public keys in ASCII armored format. It retrieves a Info +// object by its name and return the public key in a portable format. +func (kb dbKeybase) ExportPubKey(name string) (armor string, err error) { + bz, err := kb.db.Get(infoKey(name)) + if err != nil { + return "", err + } + + if bz == nil { + return "", fmt.Errorf("no key to export with name %s", name) + } + + info, err := unmarshalInfo(bz) + if err != nil { + return + } + + return crypto.ArmorPubKeyBytes(info.GetPubKey().Bytes(), string(info.GetAlgo())), nil +} + +// ExportPrivKey returns a private key in ASCII armored format. +// It returns an error if the key does not exist or a wrong encryption passphrase +// is supplied. +func (kb dbKeybase) ExportPrivKey(name string, decryptPassphrase string, + encryptPassphrase string) (armor string, err error) { + priv, err := kb.ExportPrivateKeyObject(name, decryptPassphrase) + if err != nil { + return "", err + } + + info, err := kb.Get(name) + if err != nil { + return "", err + } + + return crypto.EncryptArmorPrivKey(priv, encryptPassphrase, string(info.GetAlgo())), nil +} + +// Close the underlying storage. +func (kb dbKeybase) Close() error { + return kb.db.Close() +} + +func infoKey(name string) []byte { + return []byte(fmt.Sprintf("%s.%s", name, infoSuffix)) +} diff --git a/crypto/keyring/legacy_test.go b/crypto/keyring/legacy_test.go new file mode 100644 index 000000000000..1e2b475660b6 --- /dev/null +++ b/crypto/keyring/legacy_test.go @@ -0,0 +1,44 @@ +package keyring_test + +import ( + "path/filepath" + "testing" + + "github.com/otiai10/copy" + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/crypto/keyring" + "github.com/cosmos/cosmos-sdk/tests" +) + +func TestNewLegacyKeyBase(t *testing.T) { + dir, cleanup := tests.NewTestCaseDir(t) + t.Cleanup(cleanup) + kb, err := keyring.NewLegacy("keybasename", dir) + require.NoError(t, err) + require.NoError(t, kb.Close()) +} + +func TestLegacyKeybase(t *testing.T) { + dir, cleanup := tests.NewTestCaseDir(t) + t.Cleanup(cleanup) + + // Backup testdata + require.NoError(t, copy.Copy("testdata", dir)) + + kb, err := keyring.NewLegacy("keys", filepath.Join(dir, "keys")) + require.NoError(t, err) + t.Cleanup(func() { kb.Close() }) + + keys, err := kb.List() + require.NoError(t, err) + require.Equal(t, 2, len(keys)) + + armor, err := kb.ExportPubKey(keys[0].GetName()) + require.NoError(t, err) + require.NotEmpty(t, armor) + + armoredInfo, err := kb.Export(keys[0].GetName()) + require.NoError(t, err) + require.NotEmpty(t, armoredInfo) +} diff --git a/crypto/keyring/testdata/keys/keys.db/000002.ldb b/crypto/keyring/testdata/keys/keys.db/000002.ldb new file mode 100644 index 0000000000000000000000000000000000000000..b36586df3626e4a01631c987005dd5b167ff1da2 GIT binary patch literal 391 zcmey$^r4Z#RxCNcI5)r8Fr~Dl+#<2KsJx`KtSZ&C+#n^bq%tF`u)-ugH7~cY)V$I% zr?5&dF(suawYZp(g#iqTO7lVsQW8s2opV#-y;CcV^fL3(^4ZPAathMRi}EtE%8be? z%1q6&N-NC^O3Kqxat-nfiYqI#QcBBG%aVb{ar!ebvHCgrGpHDX^)kqL7g=R6a7wZ; zGIE+rc**mTQf0Uyr1m=MWxFC%+6+;l*L&_w+s))UMK~hzht#w>p1XUJc$A%Z zPwESPNR;9%PE9T_GBwLK6yWnVVl8E1WG;$fU@+p1Im5hYq0HxtQ@kC!+?#3MRPJ a`@iD$YnizAFo}VL@PqK*4c#iG?zaJJVsO>~ literal 0 HcmV?d00001 diff --git a/crypto/keyring/testdata/keys/keys.db/CURRENT b/crypto/keyring/testdata/keys/keys.db/CURRENT new file mode 100644 index 000000000000..cacca7574c03 --- /dev/null +++ b/crypto/keyring/testdata/keys/keys.db/CURRENT @@ -0,0 +1 @@ +MANIFEST-000004 diff --git a/crypto/keyring/testdata/keys/keys.db/CURRENT.bak b/crypto/keyring/testdata/keys/keys.db/CURRENT.bak new file mode 100644 index 000000000000..feda7d6b2481 --- /dev/null +++ b/crypto/keyring/testdata/keys/keys.db/CURRENT.bak @@ -0,0 +1 @@ +MANIFEST-000000 diff --git a/crypto/keyring/testdata/keys/keys.db/LOCK b/crypto/keyring/testdata/keys/keys.db/LOCK new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/crypto/keyring/testdata/keys/keys.db/LOG b/crypto/keyring/testdata/keys/keys.db/LOG new file mode 100644 index 000000000000..386101e4fb91 --- /dev/null +++ b/crypto/keyring/testdata/keys/keys.db/LOG @@ -0,0 +1,18 @@ +=============== Mar 30, 2020 (CEST) =============== +02:07:34.137606 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed +02:07:34.144547 db@open opening +02:07:34.144770 version@stat F·[] S·0B[] Sc·[] +02:07:34.145843 db@janitor F·2 G·0 +02:07:34.145875 db@open done T·1.315251ms +02:07:34.335635 db@close closing +02:07:34.335736 db@close done T·98.95µs +=============== Mar 30, 2020 (CEST) =============== +02:08:33.239115 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed +02:08:33.239264 version@stat F·[] S·0B[] Sc·[] +02:08:33.239281 db@open opening +02:08:33.239310 journal@recovery F·1 +02:08:33.239398 journal@recovery recovering @1 +02:08:33.322008 memdb@flush created L0@2 N·4 S·391B "cos..ess,v4":"run..nfo,v3" +02:08:33.323091 version@stat F·[1] S·391B[391B] Sc·[0.25] +02:08:33.421979 db@janitor F·3 G·0 +02:08:33.422153 db@open done T·182.707962ms diff --git a/crypto/keyring/testdata/keys/keys.db/MANIFEST-000004 b/crypto/keyring/testdata/keys/keys.db/MANIFEST-000004 new file mode 100644 index 0000000000000000000000000000000000000000..557b4bdbbc93fd41441cfe30d1ca16f08f47f344 GIT binary patch literal 237 zcmeykNagJ_21Z7yoYb<^oRlOzr^=Gl^338?=ltA)#G=HK{30f1W>ywfb_S+)X4~Za z;@tdV!<5pJa*M>`qVkf`vZ_?ma)Xq#lFE#%!U~i0)V$onQu9j7oWd%-#FUhx)Z$`B l76veoD=N(kEl5c$Np;RmiT6&eG}6n=OUq|uhDg)i1^~DrOBnzF literal 0 HcmV?d00001 diff --git a/go.mod b/go.mod index 79db3d450f75..9e6361c8504f 100644 --- a/go.mod +++ b/go.mod @@ -14,6 +14,7 @@ require ( github.com/gorilla/mux v1.7.4 github.com/hashicorp/golang-lru v0.5.4 github.com/mattn/go-isatty v0.0.12 + github.com/otiai10/copy v1.1.1 github.com/pelletier/go-toml v1.6.0 github.com/pkg/errors v0.9.1 github.com/rakyll/statik v0.1.7 diff --git a/go.sum b/go.sum index 5a22393f253f..c3ce5db04216 100644 --- a/go.sum +++ b/go.sum @@ -297,6 +297,14 @@ github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxS github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/otiai10/copy v1.1.1 h1:PH7IFlRQ6Fv9vYmuXbDRLdgTHoP1w483kPNUP2bskpo= +github.com/otiai10/copy v1.1.1/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= +github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= +github.com/otiai10/curr v1.0.0 h1:TJIWdbX0B+kpNagQrjgq8bCMrbhiuX73M2XwgtDMoOI= +github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= +github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= +github.com/otiai10/mint v1.3.1 h1:BCmzIS3n71sGfHB5NMNDB3lHYPz8fWSkCAErHed//qc= +github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= diff --git a/server/init.go b/server/init.go index 3a410ffed766..054cdb460863 100644 --- a/server/init.go +++ b/server/init.go @@ -5,7 +5,6 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/keyring" - clkeys "github.com/cosmos/cosmos-sdk/client/keys" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -14,7 +13,7 @@ import ( func GenerateCoinKey() (sdk.AccAddress, string, error) { // generate a private key, with recovery phrase - info, secret, err := clkeys.NewInMemoryKeyBase().CreateMnemonic( + info, secret, err := keyring.NewInMemory().CreateMnemonic( "name", keyring.English, "pass", keyring.Secp256k1) if err != nil { return sdk.AccAddress([]byte{}), "", err diff --git a/server/init_test.go b/server/init_test.go index e1c56a26ee49..e51b88effdeb 100644 --- a/server/init_test.go +++ b/server/init_test.go @@ -5,7 +5,6 @@ import ( "github.com/stretchr/testify/require" - "github.com/cosmos/cosmos-sdk/client/keys" "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/server" "github.com/cosmos/cosmos-sdk/tests" @@ -17,7 +16,7 @@ func TestGenerateCoinKey(t *testing.T) { require.NoError(t, err) // Test creation - info, err := keys.NewInMemoryKeyBase().CreateAccount("xxx", mnemonic, "", "012345678", keyring.CreateHDPath(0, 0).String(), keyring.Secp256k1) + info, err := keyring.NewInMemory().CreateAccount("xxx", mnemonic, "", "012345678", keyring.CreateHDPath(0, 0).String(), keyring.Secp256k1) require.NoError(t, err) require.Equal(t, addr, info.GetAddress()) } @@ -39,7 +38,7 @@ func TestGenerateSaveCoinKey(t *testing.T) { require.Equal(t, addr, info.GetAddress()) // Test in-memory recovery - info, err = keys.NewInMemoryKeyBase().CreateAccount("xxx", mnemonic, "", "012345678", keyring.CreateHDPath(0, 0).String(), keyring.Secp256k1) + info, err = keyring.NewInMemory().CreateAccount("xxx", mnemonic, "", "012345678", keyring.CreateHDPath(0, 0).String(), keyring.Secp256k1) require.NoError(t, err) require.Equal(t, addr, info.GetAddress()) } From e5bde0199e69769e5ae537ebc72f391a2adc7801 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 30 Mar 2020 23:55:28 +0200 Subject: [PATCH 502/529] client: support offline flag in config command (#5856) Update config hardcoded keys Add test cases. Co-authored-by: Alessio Treglia --- CHANGELOG.md | 1 + client/config.go | 48 ++++++++++++++++++++++--------------------- client/config_test.go | 40 ++++++++++++++++++++++++++++-------- 3 files changed, 57 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 33da257d94ac..14b54ec6d12c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -182,6 +182,7 @@ internet connection. Previously, `--generate-only` served this purpose in additi allows txs to be generated without being broadcasted and disallows Keybase use and `--offline` allows the use of Keybase but does not allow any functionality that requires an online connection. * (types/module) [\#5724](https://github.com/cosmos/cosmos-sdk/issues/5724) The `types/module` package does no longer depend on `x/simulation`. +* (client) [\#5856](https://github.com/cosmos/cosmos-sdk/pull/5856) Added the possibility to set `--offline` flag with config command. ## [v0.38.2] - 2020-03-25 diff --git a/client/config.go b/client/config.go index 226d056fea06..f4bb16b2a6b1 100644 --- a/client/config.go +++ b/client/config.go @@ -27,6 +27,13 @@ var configDefaults = map[string]string{ "broadcast-mode": "sync", } +var configBoolDefaults = map[string]bool{ + "trace": false, + "trust-node": false, + "indent": false, + "offline": false, +} + // ConfigCmd returns a CLI command to interactively create an application CLI // config file. func ConfigCmd(defaultCLIHome string) *cobra.Command { @@ -56,7 +63,7 @@ func runConfigCmd(cmd *cobra.Command, args []string) error { } // load configuration - tree, err := loadConfigFile(cfgFile) + tree, err := loadConfigFile(cmd, cfgFile) if err != nil { return err } @@ -67,7 +74,7 @@ func runConfigCmd(cmd *cobra.Command, args []string) error { if err != nil { return err } - fmt.Print(s) + cmd.Print(s) return nil } @@ -75,20 +82,17 @@ func runConfigCmd(cmd *cobra.Command, args []string) error { // get config value for a given key if getAction { - switch key { - case "trace", "trust-node", "indent": - fmt.Println(tree.GetDefault(key, false).(bool)) - - default: - if defaultValue, ok := configDefaults[key]; ok { - fmt.Println(tree.GetDefault(key, defaultValue).(string)) - return nil - } + if defaultValue, ok := configBoolDefaults[key]; ok { + cmd.Println(tree.GetDefault(key, defaultValue).(bool)) + return nil + } - return errUnknownConfigKey(key) + if defaultValue, ok := configDefaults[key]; ok { + cmd.Println(tree.GetDefault(key, defaultValue).(string)) + return nil } - return nil + return errUnknownConfigKey(key) } if len(args) != 2 { @@ -98,19 +102,16 @@ func runConfigCmd(cmd *cobra.Command, args []string) error { value := args[1] // set config value for a given key - switch key { - case "chain-id", "output", "node", "broadcast-mode", "keyring-backend": - tree.Set(key, value) - - case "trace", "trust-node", "indent": + if _, ok := configBoolDefaults[key]; ok { boolVal, err := strconv.ParseBool(value) if err != nil { return err } tree.Set(key, boolVal) - - default: + } else if _, ok := configDefaults[key]; ok { + tree.Set(key, value) + } else { return errUnknownConfigKey(key) } @@ -119,7 +120,8 @@ func runConfigCmd(cmd *cobra.Command, args []string) error { return err } - fmt.Fprintf(os.Stderr, "configuration saved to %s\n", cfgFile) + cmd.PrintErrf("configuration saved to %s\n", cfgFile) + return nil } @@ -132,9 +134,9 @@ func ensureConfFile(rootDir string) (string, error) { return path.Join(cfgPath, "config.toml"), nil } -func loadConfigFile(cfgFile string) (*toml.Tree, error) { +func loadConfigFile(cmd *cobra.Command, cfgFile string) (*toml.Tree, error) { if _, err := os.Stat(cfgFile); os.IsNotExist(err) { - fmt.Fprintf(os.Stderr, "%s does not exist\n", cfgFile) + cmd.PrintErrf("%s does not exist\n", cfgFile) return toml.Load(``) } diff --git a/client/config_test.go b/client/config_test.go index 242facaeea5f..178baa22f94b 100644 --- a/client/config_test.go +++ b/client/config_test.go @@ -1,24 +1,23 @@ package client import ( - "io/ioutil" "os" "path/filepath" "testing" "github.com/spf13/viper" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/tests" ) // For https://github.com/cosmos/cosmos-sdk/issues/3899 func Test_runConfigCmdTwiceWithShorterNodeValue(t *testing.T) { // Prepare environment - t.Parallel() - configHome, cleanup := tmpDir(t) - defer cleanup() + configHome, cleanup := tests.NewTestCaseDir(t) + t.Cleanup(cleanup) + _ = os.RemoveAll(filepath.Join(configHome, "config")) viper.Set(flags.FlagHome, configHome) @@ -39,8 +38,31 @@ func Test_runConfigCmdTwiceWithShorterNodeValue(t *testing.T) { assert.Nil(t, err) } -func tmpDir(t *testing.T) (string, func()) { - dir, err := ioutil.TempDir("", t.Name()+"_") - require.NoError(t, err) - return dir, func() { _ = os.RemoveAll(dir) } +func TestConfigCmd_OfflineFlag(t *testing.T) { + // Prepare environment + configHome, cleanup := tests.NewTestCaseDir(t) + t.Cleanup(cleanup) + + _ = os.RemoveAll(filepath.Join(configHome, "config")) + viper.Set(flags.FlagHome, configHome) + + // Init command config + cmd := ConfigCmd(configHome) + _, out, _ := tests.ApplyMockIO(cmd) + assert.NotNil(t, cmd) + + viper.Set(flagGet, true) + err := cmd.RunE(cmd, []string{"offline"}) + assert.Nil(t, err) + assert.Contains(t, out.String(), "false") + out.Reset() + + viper.Set(flagGet, false) + err = cmd.RunE(cmd, []string{"offline", "true"}) + assert.Nil(t, err) + + viper.Set(flagGet, true) + err = cmd.RunE(cmd, []string{"offline"}) + assert.Nil(t, err) + assert.Contains(t, out.String(), "true") } From 6a6fd1c7ac9401616a953791ef7fa06b00f31743 Mon Sep 17 00:00:00 2001 From: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Date: Mon, 30 Mar 2020 19:09:28 -0300 Subject: [PATCH 503/529] patch auth register cdc (#5892) * readd RegisterAccountTypeCodec * fix * remove seal * update BaseAccount and StdSig to use amino codec * remove comments * rename * changelog * rename --- CHANGELOG.md | 2 ++ x/auth/types/account.go | 3 +-- x/auth/types/codec.go | 8 +++++++- x/auth/types/stdtx.go | 2 +- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 14b54ec6d12c..cb6bfb4f6822 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -94,6 +94,8 @@ to now accept a `codec.JSONMarshaler` for modular serialization of genesis state * (modules) [\#5569](https://github.com/cosmos/cosmos-sdk/issues/5569) `InitGenesis`, for the relevant modules, now ensures module accounts exist. * (crypto/keyring) [\#5844](https://github.com/cosmos/cosmos-sdk/pull/5844) Keybase/Keyring `Sign()` methods no longer decode amino signatures when method receivers are offline/multisig keys. +* (x/auth) [\#5892](https://github.com/cosmos/cosmos-sdk/pull/5892) Add `RegisterKeyTypeCodec` to register new +types (eg. keys) to the `auth` module internal amino codec. ### State Machine Breaking diff --git a/x/auth/types/account.go b/x/auth/types/account.go index bae7d8f3b4fe..8be072d1d169 100644 --- a/x/auth/types/account.go +++ b/x/auth/types/account.go @@ -8,7 +8,6 @@ import ( "github.com/tendermint/tendermint/crypto" yaml "gopkg.in/yaml.v2" - "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth/exported" ) @@ -61,7 +60,7 @@ func (acc BaseAccount) GetPubKey() (pk crypto.PubKey) { return nil } - codec.Cdc.MustUnmarshalBinaryBare(acc.PubKey, &pk) + amino.MustUnmarshalBinaryBare(acc.PubKey, &pk) return pk } diff --git a/x/auth/types/codec.go b/x/auth/types/codec.go index be7f21b3f1d1..53de61568a1a 100644 --- a/x/auth/types/codec.go +++ b/x/auth/types/codec.go @@ -26,6 +26,13 @@ func RegisterCodec(cdc *codec.Codec) { cdc.RegisterConcrete(StdTx{}, "cosmos-sdk/StdTx", nil) } +// RegisterKeyTypeCodec registers an external concrete type defined in +// another module for the internal ModuleCdc. +func RegisterKeyTypeCodec(o interface{}, name string) { + amino.RegisterConcrete(o, name, nil) + ModuleCdc = codec.NewHybridCodec(amino) +} + var ( amino = codec.New() @@ -41,5 +48,4 @@ var ( func init() { RegisterCodec(amino) codec.RegisterCrypto(amino) - amino.Seal() } diff --git a/x/auth/types/stdtx.go b/x/auth/types/stdtx.go index 04e9ec1fdd79..786d8ffde979 100644 --- a/x/auth/types/stdtx.go +++ b/x/auth/types/stdtx.go @@ -79,7 +79,7 @@ func (ss StdSignature) GetPubKey() (pk crypto.PubKey) { return nil } - codec.Cdc.MustUnmarshalBinaryBare(ss.PubKey, &pk) + amino.MustUnmarshalBinaryBare(ss.PubKey, &pk) return pk } From fd2bb9aab6a2bd2ed36b71798e8ffcc8356755df Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 31 Mar 2020 10:04:42 -0300 Subject: [PATCH 504/529] Bump github.com/tendermint/tm-db from 0.5.0 to 0.5.1 (#5897) Bumps [github.com/tendermint/tm-db](https://github.com/tendermint/tm-db) from 0.5.0 to 0.5.1. - [Release notes](https://github.com/tendermint/tm-db/releases) - [Changelog](https://github.com/tendermint/tm-db/blob/master/CHANGELOG.md) - [Commits](https://github.com/tendermint/tm-db/compare/v0.5.0...v0.5.1) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 9e6361c8504f..94b3d1391dc4 100644 --- a/go.mod +++ b/go.mod @@ -30,7 +30,7 @@ require ( github.com/tendermint/go-amino v0.15.1 github.com/tendermint/iavl v0.13.2 github.com/tendermint/tendermint v0.33.2 - github.com/tendermint/tm-db v0.5.0 + github.com/tendermint/tm-db v0.5.1 google.golang.org/protobuf v1.20.1 // indirect gopkg.in/yaml.v2 v2.2.8 ) diff --git a/go.sum b/go.sum index c3ce5db04216..f5755bcfdd78 100644 --- a/go.sum +++ b/go.sum @@ -429,6 +429,8 @@ github.com/tendermint/tendermint v0.33.2/go.mod h1:25DqB7YvV1tN3tHsjWoc2vFtlwICf github.com/tendermint/tm-db v0.4.1/go.mod h1:JsJ6qzYkCGiGwm5GHl/H5GLI9XLb6qZX7PRe425dHAY= github.com/tendermint/tm-db v0.5.0 h1:qtM5UTr1dlRnHtDY6y7MZO5Di8XAE2j3lc/pCnKJ5hQ= github.com/tendermint/tm-db v0.5.0/go.mod h1:lSq7q5WRR/njf1LnhiZ/lIJHk2S8Y1Zyq5oP/3o9C2U= +github.com/tendermint/tm-db v0.5.1 h1:H9HDq8UEA7Eeg13kdYckkgwwkQLBnJGgX4PgLJRhieY= +github.com/tendermint/tm-db v0.5.1/go.mod h1:g92zWjHpCYlEvQXvy9M168Su8V1IBEeawpXVVBaK4f4= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= From b239cc8bb4e4458961ee8cb4a7d722d373f32d6a Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Tue, 31 Mar 2020 16:05:18 +0200 Subject: [PATCH 505/529] client: show defaults when config help screen is displayed (#5896) Closes: #5895 Thanks: @njmurarka for pointing this out. --- CHANGELOG.md | 1 + client/config.go | 24 +++++++++++++++++++++++- client/config_test.go | 43 +++++++++++++++++++++++-------------------- 3 files changed, 47 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cb6bfb4f6822..939bea0de042 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -185,6 +185,7 @@ allows txs to be generated without being broadcasted and disallows Keybase use a functionality that requires an online connection. * (types/module) [\#5724](https://github.com/cosmos/cosmos-sdk/issues/5724) The `types/module` package does no longer depend on `x/simulation`. * (client) [\#5856](https://github.com/cosmos/cosmos-sdk/pull/5856) Added the possibility to set `--offline` flag with config command. +* (client) [\#5895](https://github.com/cosmos/cosmos-sdk/issues/5895) show config options in the config command's help screen. ## [v0.38.2] - 2020-03-25 diff --git a/client/config.go b/client/config.go index f4bb16b2a6b1..68ff9c653424 100644 --- a/client/config.go +++ b/client/config.go @@ -1,12 +1,14 @@ package client import ( + "bytes" "fmt" "io" "io/ioutil" "os" "path" "strconv" + "text/template" toml "github.com/pelletier/go-toml" "github.com/spf13/cobra" @@ -39,7 +41,8 @@ var configBoolDefaults = map[string]bool{ func ConfigCmd(defaultCLIHome string) *cobra.Command { cmd := &cobra.Command{ Use: "config [value]", - Short: "Create or query an application CLI configuration file", + Short: "Get and set client options", + Long: configCommandLongDescription(), RunE: runConfigCmd, Args: cobra.RangeArgs(0, 2), } @@ -167,3 +170,22 @@ func saveConfigFile(cfgFile string, tree io.WriterTo) error { func errUnknownConfigKey(key string) error { return fmt.Errorf("unknown configuration key: %q", key) } + +func configCommandLongDescription() string { + longDescTemplate := template.Must(template.New("configCommandLongDescription"). + Parse(`{{ range $key, $value := . }} {{ $key }} = {{ $value }} +{{ end }}`)) + defaultsTextBuffer := bytes.NewBufferString("") + must(longDescTemplate.Execute(defaultsTextBuffer, configDefaults)) + must(longDescTemplate.Execute(defaultsTextBuffer, configBoolDefaults)) + return fmt.Sprintf(`Display or change client application configuration values. + +Defaults: +%s`, defaultsTextBuffer) +} + +func must(err error) { + if err != nil { + panic(err) + } +} diff --git a/client/config_test.go b/client/config_test.go index 178baa22f94b..5a114a3e68b5 100644 --- a/client/config_test.go +++ b/client/config_test.go @@ -6,7 +6,7 @@ import ( "testing" "github.com/spf13/viper" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/tests" @@ -23,19 +23,25 @@ func Test_runConfigCmdTwiceWithShorterNodeValue(t *testing.T) { // Init command config cmd := ConfigCmd(configHome) - assert.NotNil(t, cmd) - - err := cmd.RunE(cmd, []string{"node", "tcp://localhost:26657"}) - assert.Nil(t, err) + require.NotNil(t, cmd) + require.NoError(t, cmd.RunE(cmd, []string{"node", "tcp://localhost:26657"})) + require.NoError(t, cmd.RunE(cmd, []string{"node", "--get"})) + require.NoError(t, cmd.RunE(cmd, []string{"node", "tcp://local:26657"})) + require.NoError(t, cmd.RunE(cmd, []string{"node", "--get"})) +} - err = cmd.RunE(cmd, []string{"node", "--get"}) - assert.Nil(t, err) +func TestConfigCmd_UnknownOption(t *testing.T) { + // Prepare environment + configHome, cleanup := tests.NewTestCaseDir(t) + t.Cleanup(cleanup) - err = cmd.RunE(cmd, []string{"node", "tcp://local:26657"}) - assert.Nil(t, err) + _ = os.RemoveAll(filepath.Join(configHome, "config")) + viper.Set(flags.FlagHome, configHome) - err = cmd.RunE(cmd, []string{"node", "--get"}) - assert.Nil(t, err) + // Init command config + cmd := ConfigCmd(configHome) + require.NotNil(t, cmd) + require.Error(t, cmd.RunE(cmd, []string{"invalid", "true"}), "unknown configuration key: \"invalid\"") } func TestConfigCmd_OfflineFlag(t *testing.T) { @@ -49,20 +55,17 @@ func TestConfigCmd_OfflineFlag(t *testing.T) { // Init command config cmd := ConfigCmd(configHome) _, out, _ := tests.ApplyMockIO(cmd) - assert.NotNil(t, cmd) + require.NotNil(t, cmd) viper.Set(flagGet, true) - err := cmd.RunE(cmd, []string{"offline"}) - assert.Nil(t, err) - assert.Contains(t, out.String(), "false") + require.NoError(t, cmd.RunE(cmd, []string{"offline"})) + require.Contains(t, out.String(), "false") out.Reset() viper.Set(flagGet, false) - err = cmd.RunE(cmd, []string{"offline", "true"}) - assert.Nil(t, err) + require.NoError(t, cmd.RunE(cmd, []string{"offline", "true"})) viper.Set(flagGet, true) - err = cmd.RunE(cmd, []string{"offline"}) - assert.Nil(t, err) - assert.Contains(t, out.String(), "true") + require.NoError(t, cmd.RunE(cmd, []string{"offline"})) + require.Contains(t, out.String(), "true") } From 35e15521dc92ee100c7ba80b9a22ec432cbb9741 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Tue, 31 Mar 2020 16:18:02 +0200 Subject: [PATCH 506/529] x/auth: use validateMaxMemoCharacters() for memo fields (#5898) Add test cases. --- x/auth/types/params.go | 2 +- x/auth/types/params_test.go | 39 ++++++++++++++++++++++++++++++++++--- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/x/auth/types/params.go b/x/auth/types/params.go index f2347e299b5a..b6a91d69f0cb 100644 --- a/x/auth/types/params.go +++ b/x/auth/types/params.go @@ -156,7 +156,7 @@ func (p Params) Validate() error { if err := validateSigVerifyCostSecp256k1(p.SigVerifyCostSecp256k1); err != nil { return err } - if err := validateSigVerifyCostSecp256k1(p.MaxMemoCharacters); err != nil { + if err := validateMaxMemoCharacters(p.MaxMemoCharacters); err != nil { return err } if err := validateTxSizeCostPerByte(p.TxSizeCostPerByte); err != nil { diff --git a/x/auth/types/params_test.go b/x/auth/types/params_test.go index 9929b8e06a1c..f25a44914957 100644 --- a/x/auth/types/params_test.go +++ b/x/auth/types/params_test.go @@ -1,16 +1,49 @@ -package types +package types_test import ( + "fmt" "testing" + "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/stretchr/testify/require" ) func TestParamsEqual(t *testing.T) { - p1 := DefaultParams() - p2 := DefaultParams() + p1 := types.DefaultParams() + p2 := types.DefaultParams() require.Equal(t, p1, p2) p1.TxSigLimit += 10 require.NotEqual(t, p1, p2) } + +func TestParams_Validate(t *testing.T) { + tests := []struct { + name string + params types.Params + wantErr error + }{ + {"default params", types.DefaultParams(), nil}, + {"invalid tx signature limit", types.NewParams(types.DefaultMaxMemoCharacters, 0, types.DefaultTxSizeCostPerByte, + types.DefaultSigVerifyCostED25519, types.DefaultSigVerifyCostSecp256k1), fmt.Errorf("invalid tx signature limit: 0")}, + {"invalid ED25519 signature verification cost", types.NewParams(types.DefaultMaxMemoCharacters, types.DefaultTxSigLimit, types.DefaultTxSizeCostPerByte, + 0, types.DefaultSigVerifyCostSecp256k1), fmt.Errorf("invalid ED25519 signature verification cost: 0")}, + {"invalid SECK256k1 signature verification cost", types.NewParams(types.DefaultMaxMemoCharacters, types.DefaultTxSigLimit, types.DefaultTxSizeCostPerByte, + types.DefaultSigVerifyCostED25519, 0), fmt.Errorf("invalid SECK256k1 signature verification cost: 0")}, + {"invalid max memo characters", types.NewParams(0, types.DefaultTxSigLimit, types.DefaultTxSizeCostPerByte, + types.DefaultSigVerifyCostED25519, types.DefaultSigVerifyCostSecp256k1), fmt.Errorf("invalid max memo characters: 0")}, + {"invalid tx size cost per byte", types.NewParams(types.DefaultMaxMemoCharacters, types.DefaultTxSigLimit, 0, + types.DefaultSigVerifyCostED25519, types.DefaultSigVerifyCostSecp256k1), fmt.Errorf("invalid tx size cost per byte: 0")}, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + got := tt.params.Validate() + if tt.wantErr == nil { + require.NoError(t, got) + return + } + require.Equal(t, tt.wantErr, got) + }) + } +} From ca19fbc5f8731817344063b4ac1ba898419f95c1 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Wed, 1 Apr 2020 09:50:22 +0200 Subject: [PATCH 507/529] types/rest: add convenience functions for error checking (#5900) --- CHANGELOG.md | 1 + client/rpc/block.go | 6 +- client/rpc/status.go | 6 +- client/rpc/validators.go | 6 +- client/tx/tx.go | 12 ++-- types/rest/rest.go | 49 ++++++++++----- types/rest/rest_test.go | 32 ++++++++++ x/auth/client/rest.go | 12 ++-- x/auth/client/rest/broadcast.go | 13 ++-- x/auth/client/rest/decode.go | 12 ++-- x/auth/client/rest/encode.go | 9 +-- x/auth/client/rest/query.go | 12 ++-- x/bank/client/rest/query.go | 9 +-- x/bank/client/rest/tx.go | 12 ++-- x/distribution/client/rest/query.go | 33 ++++------ x/distribution/client/rest/rest.go | 3 +- x/distribution/client/rest/tx.go | 24 +++----- x/evidence/client/rest/query.go | 12 ++-- x/gov/client/rest/query.go | 96 ++++++++++------------------- x/gov/client/rest/tx.go | 12 ++-- x/mint/client/rest/query.go | 9 +-- x/params/client/rest/rest.go | 3 +- x/slashing/client/rest/query.go | 21 +++---- x/slashing/client/rest/tx.go | 20 ++---- x/staking/client/rest/query.go | 46 +++++--------- x/staking/client/rest/tx.go | 18 ++---- x/staking/client/rest/utils.go | 30 +++------ x/supply/client/rest/query.go | 15 ++--- x/upgrade/client/rest/query.go | 12 ++-- x/upgrade/client/rest/tx.go | 15 ++--- 30 files changed, 227 insertions(+), 333 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 939bea0de042..19203677ad69 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -186,6 +186,7 @@ functionality that requires an online connection. * (types/module) [\#5724](https://github.com/cosmos/cosmos-sdk/issues/5724) The `types/module` package does no longer depend on `x/simulation`. * (client) [\#5856](https://github.com/cosmos/cosmos-sdk/pull/5856) Added the possibility to set `--offline` flag with config command. * (client) [\#5895](https://github.com/cosmos/cosmos-sdk/issues/5895) show config options in the config command's help screen. +* (types/rest) [\#5900](https://github.com/cosmos/cosmos-sdk/pull/5900) Add Check*Error function family to spare developers from replicating tons of boilerplate code. ## [v0.38.2] - 2020-03-25 diff --git a/client/rpc/block.go b/client/rpc/block.go index bce145370c33..4d52ac781527 100644 --- a/client/rpc/block.go +++ b/client/rpc/block.go @@ -136,8 +136,7 @@ func BlockRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { } output, err := getBlock(cliCtx, &height) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } @@ -149,8 +148,7 @@ func BlockRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { func LatestBlockRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { output, err := getBlock(cliCtx, nil) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } diff --git a/client/rpc/status.go b/client/rpc/status.go index 330d595d5736..da530a0ce2f4 100644 --- a/client/rpc/status.go +++ b/client/rpc/status.go @@ -76,8 +76,7 @@ type NodeInfoResponse struct { func NodeInfoRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { status, err := getNodeStatus(cliCtx) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } @@ -98,8 +97,7 @@ type SyncingResponse struct { func NodeSyncingRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { status, err := getNodeStatus(cliCtx) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } diff --git a/client/rpc/validators.go b/client/rpc/validators.go index 0fa06db3b821..abcef14522a7 100644 --- a/client/rpc/validators.go +++ b/client/rpc/validators.go @@ -184,8 +184,7 @@ func ValidatorSetRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { } output, err := GetValidators(cliCtx, &height, page, limit) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } rest.PostProcessResponse(w, cliCtx, output) @@ -202,8 +201,7 @@ func LatestValidatorSetRequestHandlerFn(cliCtx context.CLIContext) http.HandlerF } output, err := GetValidators(cliCtx, nil, page, limit) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } diff --git a/client/tx/tx.go b/client/tx/tx.go index 6d1c1cd08157..21fa4c16ffee 100644 --- a/client/tx/tx.go +++ b/client/tx/tx.go @@ -161,8 +161,7 @@ func WriteGeneratedTxResponse( } simAndExec, gas, err := flags.ParseGas(br.Gas) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } @@ -182,8 +181,7 @@ func WriteGeneratedTxResponse( } _, adjusted, err := CalculateGas(ctx.QueryWithData, txf, msgs...) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } @@ -196,14 +194,12 @@ func WriteGeneratedTxResponse( } tx, err := BuildUnsignedTx(txf, msgs...) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } output, err := ctx.Marshaler.MarshalJSON(tx) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } diff --git a/types/rest/rest.go b/types/rest/rest.go index 74bf5946d4c4..b0ef4f555da0 100644 --- a/types/rest/rest.go +++ b/types/rest/rest.go @@ -123,8 +123,7 @@ func (br BaseReq) ValidateBasic(w http.ResponseWriter) bool { // Writes an error response to ResponseWriter and returns true if errors occurred. func ReadRESTReq(w http.ResponseWriter, r *http.Request, m codec.JSONMarshaler, req interface{}) bool { body, err := ioutil.ReadAll(r.Body) - if err != nil { - WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if CheckBadRequestError(w, err) { return false } @@ -148,6 +147,34 @@ func NewErrorResponse(code int, err string) ErrorResponse { return ErrorResponse{Code: code, Error: err} } +// CheckError takes care of writing an error response if err is not nil. +// Returns false when err is nil; it returns true otherwise. +func CheckError(w http.ResponseWriter, status int, err error) bool { + if err != nil { + WriteErrorResponse(w, status, err.Error()) + return true + } + return false +} + +// CheckBadRequestError attaches an error message to an HTTP 400 BAD REQUEST response. +// Returns false when err is nil; it returns true otherwise. +func CheckBadRequestError(w http.ResponseWriter, err error) bool { + return CheckError(w, http.StatusBadRequest, err) +} + +// CheckInternalServerError attaches an error message to an HTTP 500 INTERNAL SERVER ERROR response. +// Returns false when err is nil; it returns true otherwise. +func CheckInternalServerError(w http.ResponseWriter, err error) bool { + return CheckError(w, http.StatusInternalServerError, err) +} + +// CheckNotFoundError attaches an error message to an HTTP 404 NOT FOUND response. +// Returns false when err is nil; it returns true otherwise. +func CheckNotFoundError(w http.ResponseWriter, err error) bool { + return CheckError(w, http.StatusNotFound, err) +} + // WriteErrorResponse prepares and writes a HTTP error // given a status code and an error message. func WriteErrorResponse(w http.ResponseWriter, status int, err string) { @@ -162,8 +189,7 @@ func WriteSimulationResponse(w http.ResponseWriter, m codec.JSONMarshaler, gas u gasEst := GasEstimateResponse{GasEstimate: gas} resp, err := m.MarshalJSON(gasEst) - if err != nil { - WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if CheckInternalServerError(w, err) { return } @@ -194,8 +220,7 @@ func ParseFloat64OrReturnBadRequest(w http.ResponseWriter, s string, defaultIfEm } n, err := strconv.ParseFloat(s, 64) - if err != nil { - WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if CheckBadRequestError(w, err) { return n, false } @@ -208,8 +233,7 @@ func ParseQueryHeightOrReturnBadRequest(w http.ResponseWriter, cliCtx context.CL heightStr := r.FormValue("height") if heightStr != "" { height, err := strconv.ParseInt(heightStr, 10, 64) - if err != nil { - WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if CheckBadRequestError(w, err) { return cliCtx, false } @@ -257,8 +281,7 @@ func PostProcessResponseBare(w http.ResponseWriter, ctx context.CLIContext, body resp, err = codec.MarshalIndentFromJSON(resp) } - if err != nil { - WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if CheckInternalServerError(w, err) { return } } @@ -302,8 +325,7 @@ func PostProcessResponse(w http.ResponseWriter, ctx context.CLIContext, resp int result, err = codec.MarshalIndentFromJSON(result) } - if err != nil { - WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if CheckInternalServerError(w, err) { return } } @@ -315,8 +337,7 @@ func PostProcessResponse(w http.ResponseWriter, ctx context.CLIContext, resp int output, err = codec.MarshalIndentFromJSON(output) } - if err != nil { - WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if CheckInternalServerError(w, err) { return } diff --git a/types/rest/rest_test.go b/types/rest/rest_test.go index 0f259b7fc14c..189316a7662c 100644 --- a/types/rest/rest_test.go +++ b/types/rest/rest_test.go @@ -440,3 +440,35 @@ func mustNewRequest(t *testing.T, method, url string, body io.Reader) *http.Requ require.NoError(t, err) return req } + +func TestCheckErrors(t *testing.T) { + t.Parallel() + err := errors.New("ERROR") + tests := []struct { + name string + checkerFn func(w http.ResponseWriter, err error) bool + error error + wantErr bool + wantString string + wantStatus int + }{ + {"500", CheckInternalServerError, err, true, `{"error":"ERROR"}`, http.StatusInternalServerError}, + {"500 (no error)", CheckInternalServerError, nil, false, ``, http.StatusInternalServerError}, + {"400", CheckBadRequestError, err, true, `{"error":"ERROR"}`, http.StatusBadRequest}, + {"400 (no error)", CheckBadRequestError, nil, false, ``, http.StatusBadRequest}, + {"404", CheckNotFoundError, err, true, `{"error":"ERROR"}`, http.StatusNotFound}, + {"404 (no error)", CheckNotFoundError, nil, false, ``, http.StatusNotFound}, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + w := httptest.NewRecorder() + require.Equal(t, tt.wantErr, tt.checkerFn(w, tt.error)) + if tt.wantErr { + require.Equal(t, w.Body.String(), tt.wantString) + require.Equal(t, w.Code, tt.wantStatus) + } + }) + } +} diff --git a/x/auth/client/rest.go b/x/auth/client/rest.go index f79caa1af30e..aba689f75b19 100644 --- a/x/auth/client/rest.go +++ b/x/auth/client/rest.go @@ -19,8 +19,7 @@ func WriteGenerateStdTxResponse(w http.ResponseWriter, cliCtx context.CLIContext } simAndExec, gas, err := flags.ParseGas(br.Gas) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } @@ -36,8 +35,7 @@ func WriteGenerateStdTxResponse(w http.ResponseWriter, cliCtx context.CLIContext } txBldr, err = EnrichWithGas(txBldr, cliCtx, msgs) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } @@ -48,14 +46,12 @@ func WriteGenerateStdTxResponse(w http.ResponseWriter, cliCtx context.CLIContext } stdMsg, err := txBldr.BuildSignMsg(msgs) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } output, err := cliCtx.Codec.MarshalJSON(types.NewStdTx(stdMsg.Msgs, stdMsg.Fee, nil, stdMsg.Memo)) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } diff --git a/x/auth/client/rest/broadcast.go b/x/auth/client/rest/broadcast.go index 92a94eefccd5..5ce235ab1a61 100644 --- a/x/auth/client/rest/broadcast.go +++ b/x/auth/client/rest/broadcast.go @@ -23,28 +23,23 @@ func BroadcastTxRequest(cliCtx context.CLIContext) http.HandlerFunc { var req BroadcastReq body, err := ioutil.ReadAll(r.Body) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } - err = cliCtx.Codec.UnmarshalJSON(body, &req) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if err := cliCtx.Codec.UnmarshalJSON(body, &req); rest.CheckBadRequestError(w, err) { return } txBytes, err := cliCtx.Codec.MarshalBinaryBare(req.Tx) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } cliCtx = cliCtx.WithBroadcastMode(req.Mode) res, err := cliCtx.BroadcastTx(txBytes) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } diff --git a/x/auth/client/rest/decode.go b/x/auth/client/rest/decode.go index dfe7436b8e72..2a71e83ff865 100644 --- a/x/auth/client/rest/decode.go +++ b/x/auth/client/rest/decode.go @@ -28,27 +28,23 @@ func DecodeTxRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { var req DecodeReq body, err := ioutil.ReadAll(r.Body) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } err = cliCtx.Codec.UnmarshalJSON(body, &req) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } txBytes, err := base64.StdEncoding.DecodeString(req.Tx) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } var stdTx authtypes.StdTx err = cliCtx.Codec.UnmarshalBinaryBare(txBytes, &stdTx) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } diff --git a/x/auth/client/rest/encode.go b/x/auth/client/rest/encode.go index b2fe6681e10e..1ffebeab6066 100644 --- a/x/auth/client/rest/encode.go +++ b/x/auth/client/rest/encode.go @@ -23,21 +23,18 @@ func EncodeTxRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { var req types.StdTx body, err := ioutil.ReadAll(r.Body) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } err = cliCtx.Codec.UnmarshalJSON(body, &req) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } // re-encode it via the Amino wire protocol txBytes, err := cliCtx.Codec.MarshalBinaryBare(req) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } diff --git a/x/auth/client/rest/query.go b/x/auth/client/rest/query.go index 8ff7f567d05b..a350bed55543 100644 --- a/x/auth/client/rest/query.go +++ b/x/auth/client/rest/query.go @@ -23,8 +23,7 @@ func QueryAccountRequestHandlerFn(storeName string, cliCtx context.CLIContext) h bech32addr := vars["address"] addr, err := sdk.AccAddressFromBech32(bech32addr) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } @@ -94,14 +93,12 @@ func QueryTxsRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { } events, page, limit, err = rest.ParseHTTPArgs(r) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } searchResult, err := client.QueryTxsByEvents(cliCtx, events, page, limit, "") - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } @@ -148,8 +145,7 @@ func queryParamsHandler(cliCtx context.CLIContext) http.HandlerFunc { route := fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryParams) res, height, err := cliCtx.QueryWithData(route, nil) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } diff --git a/x/bank/client/rest/query.go b/x/bank/client/rest/query.go index baf1cbe42922..1b1a3bab4058 100644 --- a/x/bank/client/rest/query.go +++ b/x/bank/client/rest/query.go @@ -22,8 +22,7 @@ func QueryBalancesRequestHandlerFn(ctx context.CLIContext) http.HandlerFunc { bech32addr := vars["address"] addr, err := sdk.AccAddressFromBech32(bech32addr) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } @@ -57,14 +56,12 @@ func QueryBalancesRequestHandlerFn(ctx context.CLIContext) http.HandlerFunc { } bz, err := marshaler.MarshalJSON(params) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } res, height, err := ctx.QueryWithData(route, bz) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } diff --git a/x/bank/client/rest/tx.go b/x/bank/client/rest/tx.go index b9712c160acf..db671b741b4f 100644 --- a/x/bank/client/rest/tx.go +++ b/x/bank/client/rest/tx.go @@ -30,8 +30,7 @@ func NewSendRequestHandlerFn(ctx context.CLIContext, m codec.Marshaler, txg tx.G bech32Addr := vars["address"] toAddr, err := sdk.AccAddressFromBech32(bech32Addr) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } @@ -46,8 +45,7 @@ func NewSendRequestHandlerFn(ctx context.CLIContext, m codec.Marshaler, txg tx.G } fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } @@ -72,8 +70,7 @@ func SendRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { bech32Addr := vars["address"] toAddr, err := sdk.AccAddressFromBech32(bech32Addr) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } @@ -88,8 +85,7 @@ func SendRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { } fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } diff --git a/x/distribution/client/rest/query.go b/x/distribution/client/rest/query.go index 4c362409dd13..1d614c17fe6a 100644 --- a/x/distribution/client/rest/query.go +++ b/x/distribution/client/rest/query.go @@ -87,8 +87,7 @@ func delegatorRewardsHandlerFn(cliCtx context.CLIContext, queryRoute string) htt route := fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryDelegatorTotalRewards) res, height, err := cliCtx.QueryWithData(route, bz) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } @@ -134,8 +133,7 @@ func delegatorWithdrawalAddrHandlerFn(cliCtx context.CLIContext, queryRoute stri bz := cliCtx.Codec.MustMarshalJSON(types.NewQueryDelegatorWithdrawAddrParams(delegatorAddr)) res, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/withdraw_addr", queryRoute), bz) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } @@ -177,14 +175,12 @@ func validatorInfoHandlerFn(cliCtx context.CLIContext, queryRoute string) http.H // query commission bz, err := common.QueryValidatorCommission(cliCtx, queryRoute, valAddr) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } var commission types.ValidatorAccumulatedCommission - if err := cliCtx.Codec.UnmarshalJSON(bz, &commission); err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, cliCtx.Codec.UnmarshalJSON(bz, &commission)) { return } @@ -196,14 +192,12 @@ func validatorInfoHandlerFn(cliCtx context.CLIContext, queryRoute string) http.H } var rewards sdk.DecCoins - if err := cliCtx.Codec.UnmarshalJSON(bz, &rewards); err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, cliCtx.Codec.UnmarshalJSON(bz, &rewards)) { return } bz, err = cliCtx.Codec.MarshalJSON(NewValidatorDistInfo(delAddr, rewards, commission)) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } @@ -247,8 +241,7 @@ func paramsHandlerFn(cliCtx context.CLIContext, queryRoute string) http.HandlerF route := fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryParams) res, height, err := cliCtx.QueryWithData(route, nil) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } @@ -265,14 +258,12 @@ func communityPoolHandler(cliCtx context.CLIContext, queryRoute string) http.Han } res, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/community_pool", queryRoute), nil) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } var result sdk.DecCoins - if err := cliCtx.Codec.UnmarshalJSON(res, &result); err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, cliCtx.Codec.UnmarshalJSON(res, &result)) { return } @@ -296,8 +287,7 @@ func outstandingRewardsHandlerFn(cliCtx context.CLIContext, queryRoute string) h bin := cliCtx.Codec.MustMarshalJSON(types.NewQueryValidatorOutstandingRewardsParams(validatorAddr)) res, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/validator_outstanding_rewards", queryRoute), bin) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } @@ -311,8 +301,7 @@ func checkResponseQueryDelegationRewards( ) (res []byte, height int64, ok bool) { res, height, err := common.QueryDelegationRewards(cliCtx, queryRoute, delAddr, valAddr) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return nil, 0, false } diff --git a/x/distribution/client/rest/rest.go b/x/distribution/client/rest/rest.go index 1a19f5b633a1..ee26ce9544f5 100644 --- a/x/distribution/client/rest/rest.go +++ b/x/distribution/client/rest/rest.go @@ -43,8 +43,7 @@ func postProposalHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { content := types.NewCommunityPoolSpendProposal(req.Title, req.Description, req.Recipient, req.Amount) msg := gov.NewMsgSubmitProposal(content, req.Deposit, req.Proposer) - if err := msg.ValidateBasic(); err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, msg.ValidateBasic()) { return } diff --git a/x/distribution/client/rest/tx.go b/x/distribution/client/rest/tx.go index 23713add7efd..233c92832c78 100644 --- a/x/distribution/client/rest/tx.go +++ b/x/distribution/client/rest/tx.go @@ -83,8 +83,7 @@ func withdrawDelegatorRewardsHandlerFn(cliCtx context.CLIContext, queryRoute str } msgs, err := common.WithdrawAllDelegatorRewards(cliCtx, queryRoute, delAddr) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } @@ -118,8 +117,7 @@ func withdrawDelegationRewardsHandlerFn(cliCtx context.CLIContext) http.HandlerF } msg := types.NewMsgWithdrawDelegatorReward(delAddr, valAddr) - if err := msg.ValidateBasic(); err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, msg.ValidateBasic()) { return } @@ -148,8 +146,7 @@ func setDelegatorWithdrawalAddrHandlerFn(cliCtx context.CLIContext) http.Handler } msg := types.NewMsgSetWithdrawAddress(delAddr, req.WithdrawAddress) - if err := msg.ValidateBasic(); err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, msg.ValidateBasic()) { return } @@ -179,8 +176,7 @@ func withdrawValidatorRewardsHandlerFn(cliCtx context.CLIContext) http.HandlerFu // prepare multi-message transaction msgs, err := common.WithdrawValidatorRewardsAndCommission(valAddr) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } @@ -201,14 +197,12 @@ func fundCommunityPoolHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { } fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } msg := types.NewMsgFundCommunityPool(req.Amount, fromAddr) - if err := msg.ValidateBasic(); err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, msg.ValidateBasic()) { return } @@ -220,8 +214,7 @@ func fundCommunityPoolHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { func checkDelegatorAddressVar(w http.ResponseWriter, r *http.Request) (sdk.AccAddress, bool) { addr, err := sdk.AccAddressFromBech32(mux.Vars(r)["delegatorAddr"]) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return nil, false } @@ -230,8 +223,7 @@ func checkDelegatorAddressVar(w http.ResponseWriter, r *http.Request) (sdk.AccAd func checkValidatorAddressVar(w http.ResponseWriter, r *http.Request) (sdk.ValAddress, bool) { addr, err := sdk.ValAddressFromBech32(mux.Vars(r)["validatorAddr"]) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return nil, false } diff --git a/x/evidence/client/rest/query.go b/x/evidence/client/rest/query.go index 24fc811eb5e0..071693b09c1a 100644 --- a/x/evidence/client/rest/query.go +++ b/x/evidence/client/rest/query.go @@ -53,8 +53,7 @@ func queryEvidenceHandler(cliCtx context.CLIContext) http.HandlerFunc { route := fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryEvidence) res, height, err := cliCtx.QueryWithData(route, bz) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } @@ -66,8 +65,7 @@ func queryEvidenceHandler(cliCtx context.CLIContext) http.HandlerFunc { func queryAllEvidenceHandler(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { _, page, limit, err := rest.ParseHTTPArgsWithLimit(r, 0) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } @@ -85,8 +83,7 @@ func queryAllEvidenceHandler(cliCtx context.CLIContext) http.HandlerFunc { route := fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryAllEvidence) res, height, err := cliCtx.QueryWithData(route, bz) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } @@ -104,8 +101,7 @@ func queryParamsHandler(cliCtx context.CLIContext) http.HandlerFunc { route := fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryParameters) res, height, err := cliCtx.QueryWithData(route, nil) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } diff --git a/x/gov/client/rest/query.go b/x/gov/client/rest/query.go index 3eb5800d7a99..4b7f42bfa5e0 100644 --- a/x/gov/client/rest/query.go +++ b/x/gov/client/rest/query.go @@ -37,8 +37,7 @@ func queryParamsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { } res, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/gov/%s/%s", types.QueryParams, paramType), nil) - if err != nil { - rest.WriteErrorResponse(w, http.StatusNotFound, err.Error()) + if rest.CheckNotFoundError(w, err) { return } @@ -71,14 +70,12 @@ func queryProposalHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { params := types.NewQueryProposalParams(proposalID) bz, err := cliCtx.Codec.MarshalJSON(params) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } res, height, err := cliCtx.QueryWithData("custom/gov/proposal", bz) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } @@ -105,20 +102,17 @@ func queryDepositsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { params := types.NewQueryProposalParams(proposalID) bz, err := cliCtx.Codec.MarshalJSON(params) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } res, _, err := cliCtx.QueryWithData("custom/gov/proposal", bz) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } var proposal types.Proposal - if err := cliCtx.Codec.UnmarshalJSON(res, &proposal); err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, cliCtx.Codec.UnmarshalJSON(res, &proposal)) { return } @@ -131,8 +125,7 @@ func queryDepositsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { res, _, err = cliCtx.QueryWithData("custom/gov/deposits", bz) } - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } @@ -156,8 +149,7 @@ func queryProposerHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { } res, err := gcutils.QueryProposerByTxQuery(cliCtx, proposalID) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } @@ -189,8 +181,7 @@ func queryDepositHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { } depositorAddr, err := sdk.AccAddressFromBech32(bechDepositorAddr) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } @@ -202,20 +193,17 @@ func queryDepositHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { params := types.NewQueryDepositParams(proposalID, depositorAddr) bz, err := cliCtx.Codec.MarshalJSON(params) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } res, _, err := cliCtx.QueryWithData("custom/gov/deposit", bz) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } var deposit types.Deposit - if err := cliCtx.Codec.UnmarshalJSON(res, &deposit); err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, cliCtx.Codec.UnmarshalJSON(res, &deposit)) { return } @@ -224,8 +212,7 @@ func queryDepositHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { // for directly via a txs query. if deposit.Empty() { bz, err := cliCtx.Codec.MarshalJSON(types.NewQueryProposalParams(proposalID)) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } @@ -237,8 +224,7 @@ func queryDepositHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { } res, err = gcutils.QueryDepositByTxQuery(cliCtx, params) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } } @@ -284,20 +270,17 @@ func queryVoteHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { params := types.NewQueryVoteParams(proposalID, voterAddr) bz, err := cliCtx.Codec.MarshalJSON(params) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } res, _, err := cliCtx.QueryWithData("custom/gov/vote", bz) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } var vote types.Vote - if err := cliCtx.Codec.UnmarshalJSON(res, &vote); err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, cliCtx.Codec.UnmarshalJSON(res, &vote)) { return } @@ -306,8 +289,7 @@ func queryVoteHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { // directly via a txs query. if vote.Empty() { bz, err := cliCtx.Codec.MarshalJSON(types.NewQueryProposalParams(proposalID)) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } @@ -319,8 +301,7 @@ func queryVoteHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { } res, err = gcutils.QueryVoteByTxQuery(cliCtx, params) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } } @@ -333,8 +314,7 @@ func queryVoteHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { func queryVotesOnProposalHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { _, page, limit, err := rest.ParseHTTPArgsWithLimit(r, 0) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } @@ -360,20 +340,17 @@ func queryVotesOnProposalHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { params := types.NewQueryProposalVotesParams(proposalID, page, limit) bz, err := cliCtx.Codec.MarshalJSON(params) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } res, _, err := cliCtx.QueryWithData("custom/gov/proposal", bz) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } var proposal types.Proposal - if err := cliCtx.Codec.UnmarshalJSON(res, &proposal); err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, cliCtx.Codec.UnmarshalJSON(res, &proposal)) { return } @@ -386,8 +363,7 @@ func queryVotesOnProposalHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { res, _, err = cliCtx.QueryWithData("custom/gov/votes", bz) } - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } @@ -399,8 +375,7 @@ func queryVotesOnProposalHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { func queryProposalsWithParameterFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { _, page, limit, err := rest.ParseHTTPArgsWithLimit(r, 0) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } @@ -417,39 +392,34 @@ func queryProposalsWithParameterFn(cliCtx context.CLIContext) http.HandlerFunc { if v := r.URL.Query().Get(RestVoter); len(v) != 0 { voterAddr, err = sdk.AccAddressFromBech32(v) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } } if v := r.URL.Query().Get(RestDepositor); len(v) != 0 { depositorAddr, err = sdk.AccAddressFromBech32(v) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } } if v := r.URL.Query().Get(RestProposalStatus); len(v) != 0 { proposalStatus, err = types.ProposalStatusFromString(gcutils.NormalizeProposalStatus(v)) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } } params := types.NewQueryProposalsParams(page, limit, proposalStatus, voterAddr, depositorAddr) bz, err := cliCtx.Codec.MarshalJSON(params) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } route := fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryProposals) res, height, err := cliCtx.QueryWithData(route, bz) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } @@ -483,14 +453,12 @@ func queryTallyOnProposalHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { params := types.NewQueryProposalParams(proposalID) bz, err := cliCtx.Codec.MarshalJSON(params) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } res, height, err := cliCtx.QueryWithData("custom/gov/tally", bz) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } diff --git a/x/gov/client/rest/tx.go b/x/gov/client/rest/tx.go index fb2bfa5c6420..627525a49a24 100644 --- a/x/gov/client/rest/tx.go +++ b/x/gov/client/rest/tx.go @@ -41,8 +41,7 @@ func postProposalHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { content := types.ContentFromProposalType(req.Title, req.Description, proposalType) msg := types.NewMsgSubmitProposal(content, req.InitialDeposit, req.Proposer) - if err := msg.ValidateBasic(); err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, msg.ValidateBasic()) { return } @@ -77,8 +76,7 @@ func depositHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { // create the message msg := types.NewMsgDeposit(req.Depositor, proposalID, req.Amount) - if err := msg.ValidateBasic(); err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, msg.ValidateBasic()) { return } @@ -112,15 +110,13 @@ func voteHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { } voteOption, err := types.VoteOptionFromString(gcutils.NormalizeVoteOption(req.Option)) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } // create the message msg := types.NewMsgVote(req.Voter, proposalID, voteOption) - if err := msg.ValidateBasic(); err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, msg.ValidateBasic()) { return } diff --git a/x/mint/client/rest/query.go b/x/mint/client/rest/query.go index f9fc7d43b167..7cfb69775fc5 100644 --- a/x/mint/client/rest/query.go +++ b/x/mint/client/rest/query.go @@ -38,8 +38,7 @@ func queryParamsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { } res, height, err := cliCtx.QueryWithData(route, nil) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } @@ -58,8 +57,7 @@ func queryInflationHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { } res, height, err := cliCtx.QueryWithData(route, nil) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } @@ -78,8 +76,7 @@ func queryAnnualProvisionsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc } res, height, err := cliCtx.QueryWithData(route, nil) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } diff --git a/x/params/client/rest/rest.go b/x/params/client/rest/rest.go index 665dea834f05..59c5a4cd3df3 100644 --- a/x/params/client/rest/rest.go +++ b/x/params/client/rest/rest.go @@ -37,8 +37,7 @@ func postProposalHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { content := proposal.NewParameterChangeProposal(req.Title, req.Description, req.Changes.ToParamChanges()) msg := govtypes.NewMsgSubmitProposal(content, req.Deposit, req.Proposer) - if err := msg.ValidateBasic(); err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, msg.ValidateBasic()) { return } diff --git a/x/slashing/client/rest/query.go b/x/slashing/client/rest/query.go index 2d3d9bfab798..f82ec97afedb 100644 --- a/x/slashing/client/rest/query.go +++ b/x/slashing/client/rest/query.go @@ -34,8 +34,7 @@ func signingInfoHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) pk, err := sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeConsPub, vars["validatorPubKey"]) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } @@ -47,15 +46,13 @@ func signingInfoHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { params := types.NewQuerySigningInfoParams(sdk.ConsAddress(pk.Address())) bz, err := cliCtx.Codec.MarshalJSON(params) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } route := fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QuerySigningInfo) res, height, err := cliCtx.QueryWithData(route, bz) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } @@ -68,8 +65,7 @@ func signingInfoHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { func signingInfoHandlerListFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { _, page, limit, err := rest.ParseHTTPArgsWithLimit(r, 0) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } @@ -80,15 +76,13 @@ func signingInfoHandlerListFn(cliCtx context.CLIContext) http.HandlerFunc { params := types.NewQuerySigningInfosParams(page, limit) bz, err := cliCtx.Codec.MarshalJSON(params) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } route := fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QuerySigningInfos) res, height, err := cliCtx.QueryWithData(route, bz) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } @@ -107,8 +101,7 @@ func queryParamsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { route := fmt.Sprintf("custom/%s/parameters", types.QuerierRoute) res, height, err := cliCtx.QueryWithData(route, nil) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } diff --git a/x/slashing/client/rest/tx.go b/x/slashing/client/rest/tx.go index f0ce72c6ae6d..dba316db8462 100644 --- a/x/slashing/client/rest/tx.go +++ b/x/slashing/client/rest/tx.go @@ -43,14 +43,12 @@ func NewUnjailRequestHandlerFn(ctx context.CLIContext, m codec.Marshaler, txg tx } fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } valAddr, err := sdk.ValAddressFromBech32(bech32Validator) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } @@ -60,9 +58,7 @@ func NewUnjailRequestHandlerFn(ctx context.CLIContext, m codec.Marshaler, txg tx } msg := types.NewMsgUnjail(valAddr) - err = msg.ValidateBasic() - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, msg.ValidateBasic()) { return } tx.WriteGeneratedTxResponse(ctx, w, txg, req.BaseReq, msg) @@ -99,14 +95,12 @@ func unjailRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { } valAddr, err := sdk.ValAddressFromBech32(bech32validator) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } @@ -116,9 +110,7 @@ func unjailRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { } msg := types.NewMsgUnjail(valAddr) - err = msg.ValidateBasic() - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, msg.ValidateBasic()) { return } diff --git a/x/staking/client/rest/query.go b/x/staking/client/rest/query.go index ddd6c03c7c6b..5f307e77695c 100644 --- a/x/staking/client/rest/query.go +++ b/x/staking/client/rest/query.go @@ -125,8 +125,7 @@ func delegatorTxsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { delegatorAddr := vars["delegatorAddr"] _, err := sdk.AccAddressFromBech32(delegatorAddr) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } @@ -173,15 +172,14 @@ func delegatorTxsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { for _, action := range actions { foundTxs, errQuery := queryTxs(cliCtx, action, delegatorAddr) - if errQuery != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, errQuery.Error()) + if rest.CheckInternalServerError(w, errQuery) { + return } txs = append(txs, foundTxs) } res, err := cliCtx.Codec.MarshalJSON(txs) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } @@ -210,8 +208,7 @@ func redelegationsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { if len(bechDelegatorAddr) != 0 { delegatorAddr, err := sdk.AccAddressFromBech32(bechDelegatorAddr) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } params.DelegatorAddr = delegatorAddr @@ -219,8 +216,7 @@ func redelegationsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { if len(bechSrcValidatorAddr) != 0 { srcValidatorAddr, err := sdk.ValAddressFromBech32(bechSrcValidatorAddr) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } params.SrcValidatorAddr = srcValidatorAddr @@ -228,22 +224,19 @@ func redelegationsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { if len(bechDstValidatorAddr) != 0 { dstValidatorAddr, err := sdk.ValAddressFromBech32(bechDstValidatorAddr) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } params.DstValidatorAddr = dstValidatorAddr } bz, err := cliCtx.Codec.MarshalJSON(params) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } res, height, err := cliCtx.QueryWithData("custom/staking/redelegations", bz) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } @@ -271,8 +264,7 @@ func delegatorValidatorHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { func validatorsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { _, page, limit, err := rest.ParseHTTPArgsWithLimit(r, 0) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } @@ -288,15 +280,13 @@ func validatorsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { params := types.NewQueryValidatorsParams(page, limit, status) bz, err := cliCtx.Codec.MarshalJSON(params) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } route := fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryValidators) res, height, err := cliCtx.QueryWithData(route, bz) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } @@ -333,15 +323,13 @@ func historicalInfoHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { params := types.NewQueryHistoricalInfoParams(height) bz, err := cliCtx.Codec.MarshalJSON(params) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } route := fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryHistoricalInfo) res, height, err := cliCtx.QueryWithData(route, bz) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } @@ -359,8 +347,7 @@ func poolHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { } res, height, err := cliCtx.QueryWithData("custom/staking/pool", nil) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } @@ -378,8 +365,7 @@ func paramsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { } res, height, err := cliCtx.QueryWithData("custom/staking/parameters", nil) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } diff --git a/x/staking/client/rest/tx.go b/x/staking/client/rest/tx.go index 7838d95515cd..402d52a08255 100644 --- a/x/staking/client/rest/tx.go +++ b/x/staking/client/rest/tx.go @@ -69,14 +69,12 @@ func postDelegationsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { } msg := types.NewMsgDelegate(req.DelegatorAddress, req.ValidatorAddress, req.Amount) - if err := msg.ValidateBasic(); err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, msg.ValidateBasic()) { return } fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } @@ -103,14 +101,12 @@ func postRedelegationsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { } msg := types.NewMsgBeginRedelegate(req.DelegatorAddress, req.ValidatorSrcAddress, req.ValidatorDstAddress, req.Amount) - if err := msg.ValidateBasic(); err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, msg.ValidateBasic()) { return } fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } @@ -137,14 +133,12 @@ func postUnbondingDelegationsHandlerFn(cliCtx context.CLIContext) http.HandlerFu } msg := types.NewMsgUndelegate(req.DelegatorAddress, req.ValidatorAddress, req.Amount) - if err := msg.ValidateBasic(); err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, msg.ValidateBasic()) { return } fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } diff --git a/x/staking/client/rest/utils.go b/x/staking/client/rest/utils.go index 80e0a54be1a4..1cfaa4b4f02f 100644 --- a/x/staking/client/rest/utils.go +++ b/x/staking/client/rest/utils.go @@ -42,14 +42,12 @@ func queryBonds(cliCtx context.CLIContext, endpoint string) http.HandlerFunc { bech32validator := vars["validatorAddr"] delegatorAddr, err := sdk.AccAddressFromBech32(bech32delegator) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } validatorAddr, err := sdk.ValAddressFromBech32(bech32validator) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } @@ -61,14 +59,12 @@ func queryBonds(cliCtx context.CLIContext, endpoint string) http.HandlerFunc { params := types.NewQueryBondsParams(delegatorAddr, validatorAddr) bz, err := cliCtx.Codec.MarshalJSON(params) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } res, height, err := cliCtx.QueryWithData(endpoint, bz) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } @@ -83,8 +79,7 @@ func queryDelegator(cliCtx context.CLIContext, endpoint string) http.HandlerFunc bech32delegator := vars["delegatorAddr"] delegatorAddr, err := sdk.AccAddressFromBech32(bech32delegator) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } @@ -96,14 +91,12 @@ func queryDelegator(cliCtx context.CLIContext, endpoint string) http.HandlerFunc params := types.NewQueryDelegatorParams(delegatorAddr) bz, err := cliCtx.Codec.MarshalJSON(params) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } res, height, err := cliCtx.QueryWithData(endpoint, bz) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } @@ -118,8 +111,7 @@ func queryValidator(cliCtx context.CLIContext, endpoint string) http.HandlerFunc bech32validatorAddr := vars["validatorAddr"] validatorAddr, err := sdk.ValAddressFromBech32(bech32validatorAddr) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } @@ -131,14 +123,12 @@ func queryValidator(cliCtx context.CLIContext, endpoint string) http.HandlerFunc params := types.NewQueryValidatorParams(validatorAddr) bz, err := cliCtx.Codec.MarshalJSON(params) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } res, height, err := cliCtx.QueryWithData(endpoint, bz) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } diff --git a/x/supply/client/rest/query.go b/x/supply/client/rest/query.go index 021159dfaf17..fd5256b6b9e7 100644 --- a/x/supply/client/rest/query.go +++ b/x/supply/client/rest/query.go @@ -34,8 +34,7 @@ func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router) { func totalSupplyHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { _, page, limit, err := rest.ParseHTTPArgsWithLimit(r, 0) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } @@ -46,14 +45,12 @@ func totalSupplyHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { params := types.NewQueryTotalSupplyParams(page, limit) bz, err := cliCtx.Codec.MarshalJSON(params) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } res, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryTotalSupply), bz) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } @@ -73,14 +70,12 @@ func supplyOfHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { params := types.NewQuerySupplyOfParams(denom) bz, err := cliCtx.Codec.MarshalJSON(params) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } res, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QuerySupplyOf), bz) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } diff --git a/x/upgrade/client/rest/query.go b/x/upgrade/client/rest/query.go index 8c3372b2a7aa..101235419b2c 100644 --- a/x/upgrade/client/rest/query.go +++ b/x/upgrade/client/rest/query.go @@ -23,8 +23,7 @@ func getCurrentPlanHandler(cliCtx context.CLIContext) func(http.ResponseWriter, return func(w http.ResponseWriter, request *http.Request) { // ignore height for now res, _, err := cliCtx.Query(fmt.Sprintf("custom/%s/%s", types.QuerierKey, types.QueryCurrent)) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } if len(res) == 0 { @@ -34,8 +33,7 @@ func getCurrentPlanHandler(cliCtx context.CLIContext) func(http.ResponseWriter, var plan types.Plan err = cliCtx.Codec.UnmarshalBinaryBare(res, &plan) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if rest.CheckInternalServerError(w, err) { return } @@ -49,14 +47,12 @@ func getDonePlanHandler(cliCtx context.CLIContext) func(http.ResponseWriter, *ht params := types.NewQueryAppliedParams(name) bz, err := cliCtx.Codec.MarshalJSON(params) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } res, _, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/%s", types.QuerierKey, types.QueryApplied), bz) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } diff --git a/x/upgrade/client/rest/tx.go b/x/upgrade/client/rest/tx.go index e67aa79bfc61..6b40ae202892 100644 --- a/x/upgrade/client/rest/tx.go +++ b/x/upgrade/client/rest/tx.go @@ -62,16 +62,14 @@ func postPlanHandler(cliCtx context.CLIContext) http.HandlerFunc { } fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } var t time.Time if req.UpgradeTime != "" { t, err = time.Parse(time.RFC3339, req.UpgradeTime) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } } @@ -79,8 +77,7 @@ func postPlanHandler(cliCtx context.CLIContext) http.HandlerFunc { plan := types.Plan{Name: req.UpgradeName, Time: t, Height: req.UpgradeHeight, Info: req.UpgradeInfo} content := types.NewSoftwareUpgradeProposal(req.Title, req.Description, plan) msg := gov.NewMsgSubmitProposal(content, req.Deposit, fromAddr) - if err := msg.ValidateBasic(); err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, msg.ValidateBasic()) { return } @@ -102,15 +99,13 @@ func cancelPlanHandler(cliCtx context.CLIContext) http.HandlerFunc { } fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, err) { return } content := types.NewCancelSoftwareUpgradeProposal(req.Title, req.Description) msg := gov.NewMsgSubmitProposal(content, req.Deposit, fromAddr) - if err := msg.ValidateBasic(); err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + if rest.CheckBadRequestError(w, msg.ValidateBasic()) { return } From c87a1e00deae04048559f51859cd84e6c6e3b578 Mon Sep 17 00:00:00 2001 From: eosforce Date: Wed, 1 Apr 2020 20:34:35 +0800 Subject: [PATCH 508/529] docs(cn): match new docs in intro and basics --- docs/cn/README.md | 28 +-- docs/cn/basics/README.md | 10 ++ docs/cn/basics/accounts.md | 130 ++++++++++++++ docs/cn/basics/app-anatomy.md | 241 ++++++++++++++++++++++++++ docs/cn/basics/gas-fees.md | 80 +++++++++ docs/cn/basics/tx-lifecycle.md | 163 +++++++++++++++++ docs/cn/intro/README.md | 32 +--- docs/cn/intro/overview.md | 33 ++++ docs/cn/intro/sdk-app-architecture.md | 80 ++++----- docs/cn/intro/sdk-design.md | 92 ++++++---- docs/cn/intro/why-app-specific.md | 87 ++++++++++ 11 files changed, 864 insertions(+), 112 deletions(-) create mode 100644 docs/cn/basics/README.md create mode 100644 docs/cn/basics/accounts.md create mode 100644 docs/cn/basics/app-anatomy.md create mode 100644 docs/cn/basics/gas-fees.md create mode 100644 docs/cn/basics/tx-lifecycle.md create mode 100644 docs/cn/intro/overview.md create mode 100644 docs/cn/intro/why-app-specific.md diff --git a/docs/cn/README.md b/docs/cn/README.md index bbd14a3109f3..1161f445e152 100644 --- a/docs/cn/README.md +++ b/docs/cn/README.md @@ -7,22 +7,28 @@ parent: ## 开始 -- **[SDK 介绍](./intro/README.md)**:从“高层”了解Cosmos SDK. +- **[SDK 介绍](./intro/README.md)**:Cosmos SDK的总体概览 +- **[快速开始](./using-the-sdk/quick-start.md)**:构建一个标准的基于cosmos sdk的app并启动节点 - **[SDK 开发教程](https://github.com/cosmos/sdk-application-tutorial)**: 一个学习 SDK 的教程。它展示了如何从头开始基于 sdk 构建区块链, 并在此过程中解释了 SDK 的基本原理。 -## 开发资源 -- [规范](./spec/README.md): Cosmos SDK 的模块及其他规范。 -- [SDK API 参考](https://godoc.org/github.com/cosmos/cosmos-sdk): Cosmos SDK Godocs 文档 。 -- [REST API 规范](https://cosmos.network/rpc/): 通过 REST 与 `gaia` 全节点交互的 API 列表。 +## 索引 + +- **[基础文档](./basics/)**:cosmos sdk的基础概念文档,例如应用结构、交易的生命周期、账户管理等 +- **[核心文档](./core/)**: cosmos sdk的核心文档,例如`baseapp`,`store`,`server`等 +- **[构建模块](./building-modules/)**: 对于模块开发者来说的一些重要概念,例如`message`,`keeper`,`handler`,`querier` +- **[接口](./interfaces/)**: 为cosmos应用设计接口的文档 -## 创建新的 SDK 项目 -若要创建新项目, 以下两个方法任选其一: -- 克隆这个 [教程](https://github.com/cosmos/sdk-application-tutorial/),如果不需要, 请不要忘记从各种文件中删除 `nameservice` 模块。 -- 使用社区工具, 如 [chainkit](https://github.com/blocklayerhq/chainkit). +## 开发资源 + +- **[模块目录](../../x/)**: 模块的实现和文档 + +- **[规范](./spec/):** Cosmos SDK 的模块及其他规范。 +- **[SDK API 参考](https://godoc.org/github.com/cosmos/cosmos-sdk):** Cosmos SDK Godocs 文档 。 +- **[REST API 规范](https://cosmos.network/rpc/):** 通过 REST 与 `gaia` 全节点交互的 API 列表。 ## Cosmos Hub @@ -35,7 +41,3 @@ Cosmos-SDK 目前是用 [Golang](https://golang.org/)编写的, 尽管该框架 ## 贡献 参考 [文档说明](https://github.com/cosmos/cosmos-sdk/blob/master/docs/DOCS_README.md) 了解构建细节及更新时注意事项。 - -## 版本 - - 这份文档通过以下提交构建: diff --git a/docs/cn/basics/README.md b/docs/cn/basics/README.md new file mode 100644 index 000000000000..e3e4c6640737 --- /dev/null +++ b/docs/cn/basics/README.md @@ -0,0 +1,10 @@ +# 基础文档 + +此目录包含对cosmos sdk的基础概念介绍 + +1. [SDK应用解析](./app-anatomy.md) +2. [交易的生命周期](./tx-lifecycle.md) +3. [账户系统](./accounts.md) +4. [Gas 和 Fees](./gas-fees.md) + +阅读完基础文档后,可以阅读 [核心文档](../core/README.md) 进一步加深对cosmos的理解。 \ No newline at end of file diff --git a/docs/cn/basics/accounts.md b/docs/cn/basics/accounts.md new file mode 100644 index 000000000000..97a5a8d79157 --- /dev/null +++ b/docs/cn/basics/accounts.md @@ -0,0 +1,130 @@ +**原文路径:https://github.com/cosmos/cosmos-sdk/blob/master/docs/basics/accounts.md** + +# 账户系统 + +# 必备阅读 {hide} + +- [一个SDK程序的剖析](./app-anatomy.md) {prereq} + +## 账户定义 + +在Cosmos SDK中,一个账户是指定的一个公私钥对.公钥可以用于派生出`Addresses`,`Addresses`可以在程序里面的各个模块间区分不同的用户.`Addresses`同样可以和[消息](../building-modules/messages-and-queries.md#messages)进行关联用于确定发消息的账户.私钥一般用于生成签名来证明一个消息是被一个`Addresses`(和私钥关联的`Addresses`)所发送. + +Cosmos SDK使用一套称之为 [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)的标准来生成公私钥.这个标准定义了怎么去创建一个HD钱包(钱包就是一批账户的集合).每一个账户的核心,都有一个种子,每一个种子都有一个12或24个字的助记符.使用这个助记符,使用一种单向的加密方法可以派生出任意数量的私钥.公钥可以通过私钥推导出来.当然,助记符是最敏感的信息,因为可以不停通过助记符来重新生成私钥. + +``` + Account 0 Account 1 Account 2 + ++------------------+ +------------------+ +------------------+ +| | | | | | +| Address 0 | | Address 1 | | Address 2 | +| ^ | | ^ | | ^ | +| | | | | | | | | +| | | | | | | | | +| | | | | | | | | +| + | | + | | + | +| Public key 0 | | Public key 1 | | Public key 2 | +| ^ | | ^ | | ^ | +| | | | | | | | | +| | | | | | | | | +| | | | | | | | | +| + | | + | | + | +| Private key 0 | | Private key 1 | | Private key 2 | +| ^ | | ^ | | ^ | ++------------------+ +------------------+ +------------------+ + | | | + | | | + | | | + +--------------------------------------------------------------------+ + | + | + +---------+---------+ + | | + | Master PrivKey | + | | + +-------------------+ + | + | + +---------+---------+ + | | + | Mnemonic (Seed) | + | | + +-------------------+ +``` + +在Cosmos SDK中,账户可以在[`Keybase`](#keybase)中作为一个对象来储存和管理. + +## Keybase + +`Keybase` 是储存和管理账户的对象,在Cosmos SDK中,`Keybase`要实现以下接口 + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/crypto/keys/types.go#L13-L86 + +在Cosmos SDK中,`Keybase`接口的默认实现对象是`dbKeybase`. + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/crypto/keys/keybase.go + +`dbKeybase`上面对`Keybase`接口中方法实现的笔记: + +- `Sign(name, passphrase string, msg []byte) ([]byte, crypto.PubKey, error)`对`message` 字节进行签名.需要做一些准备工作将`message`编码成 [] byte类型,可以参考`auth`模块`message`准备的例子.注意,SDK上面没有实现签名的验证,签名验证被推迟到[`anteHandler`](#antehandler)中进行 ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/x/auth/types/txbuilder.go#L176-L209 +- `CreateMnemonic(name string, language Language, passwd string, algo SigningAlgo) (info Info, seed string, err error)`创建一个新的助记符并打印在日志里,但是**并不保存在磁盘上** +- `CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd string, account uint32, index uint32) (Info, error)` 基于[`bip44 path`](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki)创建一个新的账户并将其保存在磁盘上.注意私钥在[保存前用密码加密](https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/crypto/keys/mintkey/mintkey.go),**永远不会储存未加密的私钥**.在这个方法的上下文中, `account`和 `address` 参数指的是BIP44派生路径的段(例如`0`, `1`, `2`, ...)用于从助记符派生出私钥和公钥(注意:给相同的助记符和 `account`将派生出相同的私钥,给相同的`account`和`address`也会派生出相同的公钥和`Address`).最后注意`CreateAccount` 方法使用在[Tendermint library](https://github.com/tendermint/tendermint/tree/bc572217c07b90ad9cee851f193aaa8e9557cbc7/crypto/secp256k1)中的`secp256k1` 派生出公私钥和`Address`.总之,这个方法是用来创建用户的钥匙和地址的,并不是共识秘钥,参见[`Addresses`](#addresses) 获取更多信息 + +`dbKeybase`的实现是最基本的,并没有根据需求提供锁定功能.锁定功能指如果一个`dbKeybase`实例被创建,底层的`db`就被锁定意味着除了实例化它的程序其他程序无法访问它.这就是SDK程序使用另外一套`Keybase` 接口的实现`lazyKeybase`的原因 + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/crypto/keys/lazy_keybase.go + +`lazyKeybase`是`dbKeybase`的一个简单包装,它仅在要执行操作时锁定数据库,并在之后立即将其解锁。使用`lazyKeybase`[命令行界面](../interfaces/cli.md)可以在 [rest server](../interfaces/rest.md)运行时创建新的账户,它也可以同时传递多个CLI命令 + +## 地址和公钥 + +`Addresses` 和`PubKey`在程序里面都是标识一个参与者的公共信息.Cosmos SDK默认提供3中类型的`Addresses`和`PubKey` + +- 基于用户的`Addresses` 和`PubKey`,用于指定用户(例如`message`的发送者).它们通过 **`secp256k1`**曲线推导出来 +- 基于验证节点的`Addresses` 和`PubKey`用于指定验证者的操作员,它们通过 **`secp256k1`**曲线推导出来 +- 基于共识节点的`Addresses` 和`PubKey`用于指定参与共识的验证着节点,它们通过 **`ed25519`**曲线推导出来 + +| | Address bech32 Prefix | Pubkey bech32 Prefix | Curve | Address byte length | Pubkey byte length | +|--------------------|-----------------------|----------------------|-------------|---------------------|--------------------| +| Accounts | cosmos | cosmospub | `secp256k1` | `20` | `33` | +| Validator Operator | cosmosvaloper | cosmosvaloperpub | `secp256k1` | `20` | `33` | +| Consensus Nodes | cosmosvalcons | cosmosvalconspub | `ed25519` | `20` | `32` | + +### 公钥 + +在Cosmos SDK里面`PubKey`遵循在 tendermint的`crypto`包中定义的`Pubkey`接口 + ++++ https://github.com/tendermint/tendermint/blob/bc572217c07b90ad9cee851f193aaa8e9557cbc7/crypto/crypto.go#L22-L27 + +对于`secp256k1` 类型的秘钥,具体的实现可以在[这里](https://github.com/tendermint/tendermint/blob/bc572217c07b90ad9cee851f193aaa8e9557cbc7/crypto/secp256k1/secp256k1.go#L140)找到.对于`ed25519`类型的密钥,具体实现可以在[这里](https://github.com/tendermint/tendermint/blob/bc572217c07b90ad9cee851f193aaa8e9557cbc7/crypto/ed25519/ed25519.go#L135)找到. + +请注意,在Cosmos SDK中,`Pubkeys`并非以其原始格式进行操作。它使用[`Amino`](../core/encoding.md#amino)和[`bech32`](https://en.bitcoin.it/wiki/Bech32)进行2次编码.在SDK里面,`Pubkeys`首先调用`Bytes()`方法在原始的 `Pubkey`中(这里面提供amino编码),然后使用`bech32`的`ConvertAndEncode` 方法 + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/address.go#L579-L729 + +### 地址 + +在Cosmos SDK默认提送3种类型的地址 + +- `AccAddress` 用于账户 +- `ValAddress` 用于验证者操作员 +- `ConsAddress` 用于验证着节点 + +这些地址类型都是一种长度为20的十六进制编码的`[]byte`数组的别名,这里有一种标准方法从`Pubkey pub`中获取到地址`aa`. + +```go +aa := sdk.AccAddress(pub.Address().Bytes()) +``` + +这些地址实现了 `Address` 接口 + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/address.go#L71-L80 + +值得注意的是,`Marhsal()`和`Bytes()`方法都返回相同的`[]byte`类型的地址,根据protobuff的兼容性要求我们需要前者.同样,`String()`也被用来返回`bech32`编码类型的地址,这个应该是用户看到的最终编码形式.下面是一个例子: + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/address.go#L229-L243 + +## 接下来 {hide} + +学习[gas and fees](./gas-fees.md) {hide} \ No newline at end of file diff --git a/docs/cn/basics/app-anatomy.md b/docs/cn/basics/app-anatomy.md new file mode 100644 index 000000000000..69ad93aa5a9c --- /dev/null +++ b/docs/cn/basics/app-anatomy.md @@ -0,0 +1,241 @@ + + + + +# SDK应用程序剖析 + +## Node Client + +全节点的核心进程是基于SDK包的。 网络中的参与者运行此过程以初始化其状态机,与其他全节点连接并在新块进入时更新其状态机。 + +``` + ^ +-------------------------------+ ^ + | | | | + | | State-machine = Application | | + | | | | Built with Cosmos SDK + | | ^ + | | + | +----------- | ABCI | ----------+ v + | | + v | ^ + | | | | +Blockchain Node | | Consensus | | + | | | | + | +-------------------------------+ | Tendermint Core + | | | | + | | Networking | | + | | | | + v +-------------------------------+ v +``` + + + +区块链全节点以二进制形式表示,通常以`-d`后缀表示`守护程序`(例如,`appd`表示` app`或` gaiad`表示`gaia`)。 这个二进制文件是通过编译一个简单的代码文件 main.go构建的,`main.go` 通常位于`./cmd/appd/`中。 此操作通常通过用Makefile编译。 + +编译了二进制文件,就可以通过运行[`start`命令](https://docs.cosmos.network/master/core/node.html#start-command) 来启动节点。 此命令功能主要执行三件事: + +1.[`app.go`] 创建了一个状态机实例。 + +2.用最新的已知状态初始化状态机,该状态机是从存储在`~/ .appd / data`文件夹中的db中提取的。 此时,状态机的高度为:`appBlockHeight`。 + +3.创建并启动一个新的Tendermint实例。 该节点将与对等节点进行连接交换信息。 它将从他们那里获取最新的`blockHeight`,如果它大于本地的`appBlockHeight`,则重播块以同步到该高度。 如果`appBlockHeight`为`0`,则该节点从创世开始,并且Tendermint通过ABCI接口向`app`发送`InitChain`初始化链命令,从而触发[`InitChainer`](https://docs.cosmos.network/master/basics/app-anatomy.html#initchainer)。 + +## Core Application File + +通常,状态机的核心是在名为`app.go`的文件中定义的。 它主要包含“应用程序的类型定义”和“创建和初始化它”的功能。 + +### Type Definition of the Application + +在app.go中重要的一个是应用程序的type。 它通常由以下部分组成: + +- 在`app.go`中定义的自定义应用程序是`baseapp`的扩展。 当事务由Tendermint发送到应用程序时,`app`使用`baseapp`的方法将它们转送到对应的模块。 baseapp为应用程序实现了大多数核心逻辑,包括所有的[ABCI方法](https://tendermint.com/docs/spec/abci/abci.html#overview)和转送消息逻辑。 + +- 一条key链包含整个状态,他是基于 Cosmos SDK 的multistore实现的。 每个模块使用multistore的一个或多个存储来存储其状态。 可以使用在“ app”类型中声明的特定键来访问这些存储。 这些密钥以及`keepers'是Cosmos SDK的 对象功能模型 的核心。 +- 模块`keeper`的列表。 每个模块 都会抽象定义一个keeper,该keeper 实现模块存储的读写。 一个模块的“ keeper”方法可以从其他模块(如果已授权)中调用,这就是为什么它们在应用程序的类型中声明并作为接口导出到其他模块的原因,以便后者只能访问授权的功能。 +- 应用程序的`codec`用于序列化和反序列化数据结构以便存储它们,因为存储只能持久化`[]bytes`。 “编解码器”必须是确定性的。 默认编解码器为amino +- 模块管理器是一个对象,其中包含应用程序模块的列表。 它简化了与这些模块相关的操作,例如注册routes操作,query route操作或设置各种功能的模块之间顺序执行情况,例如InitChainer操作,BeginBlocke操作和EndBlocker操作 +- 请参阅[gaia](https://github.com/cosmos/gaia)中的应用程序类型定义示例 + ++++ https://github.com/cosmos/gaia/blob/5bc422e6868d04747e50b467e8eeb31ae2fe98a3/app/app.go#L87-L115 + +### Constructor Function + +此函数构造了以上部分中定义的类型的新应用程序。 在应用程的start命令中使用,它必须具有AppCreator签名。 + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/server/constructors.go#L20 + +以下是此功能执行的主要操作: + +- 创建初始化一个新的codec实例,并使用 基础模块管理器初始化每个应用程序模块的`codec`。 +- 使用baseapp实例,编解码器和所有适当的存储键的引用实例化一个新应用程序。 +- 使用每个应用程序模块的`NewKeeper`功能实例化在应用程序的`类型`中定义的所有keeper。 注意,所有keeper必须以正确的顺序实例化,因为一个模块的NewKeeper可能需要引用另一个模块的`keeper`。 +- 使用每个应用模块的AppModule 来实例化应用程序的模块管理器 +- 使用模块管理器,初始化应用程序的routes和query route。 当事务由Tendermint通过ABCI中继到应用程序时,它使用此处定义的路由被路由到相应模块的 回调handler。 同样,当应用程序收到查询时,使用此处定义的查询路由将其路由到适当的模块的querier。 +- 使用模块管理器,注册应用程序的模块的invariants。 invariants是在每个块末尾评估的变量(例如token的总供应量)。 检查不变式的过程是通过InvariantsRegistry 的特殊模块完成的。 invariants应等于模块中定义的预测值。 如果该值与预测的值不同,则将触发不变注册表中定义的特殊逻辑(通常会中断链)。 这对于确保不会发现任何严重错误并产生难以修复的长期影响非常有用。 +- 使用模块管理器,在每个应用程序的模块 的InitGenesis,BegingBlocker和EndBlocker函数之间设置执行顺序。 请注意,并非所有模块都实现这些功能。 +- 模块实现这些功能。 +- 设置其余的应用程序参数: + + `InitChainer`于在应用程序首次启动时对其进行初始化。 + + `BeginBlocker`,`EndBlocker`:在每个块的开始和结尾处调用。 + + `anteHandler`:用于处理费用和签名验证。 +- 挂载存储. +- 返回应用实例. + +请注意,此函数仅创建该应用的一个实例,而如果重新启动节点,则状态将从`〜/ .appd / data`文件夹中保留下来状态加载,如果节点是第一次启动,则从创世文件生成。See an example of application constructor from [`gaia`](https://github.com/cosmos/gaia): + ++++ https://github.com/cosmos/gaia/blob/f41a660cdd5bea173139965ade55bd25d1ee3429/app/app.go#L110-L222 + +### InitChainer + +InitChainer用于根据创始文件(即创始账户的代币余额)初始化应用程序的状态。 当应用程序从Tendermint引擎收到`InitChain`消息时调用该消息,该消息是在节点以`appBlockHeight == 0`(即创世)启动。 应用程序必须通过[`SetInitChainer`](https://godoc.org/github.com/cosmos/cosmos-sdk/baseapp#BaseApp.SetInitChainer )方法设置其[constructor](https://docs.cosmos.network/master/basics/app-anatomy.html#constructor-function)中的`Initchainer`。 + +通常,`InitChainer`主要由每个应用程序模块的InitGenesis函数组成。 这是通过调用模块管理器的InitGenesis函数来完成的,而模块管理器的InitGenesis函数将依次调用其包含的每个模块的InitGenesis函数。 请注意,必须使用模块管理器的SetOrderInitGenesis方法设置模块的InitGenesis函数的顺序。 这是在 应用程序的构造函数 application-constructor 中完成的,必须在SetInitChainer之前调用SetOrderInitGenesis。 + +查看来自[gaia](https://github.com/cosmos/gaia)的InitChainer的示例: + +See an example of an `InitChainer` from [`gaia`](https://github.com/cosmos/gaia): + +查看来自[`gaia`](https://github.com/cosmos/gaia)的`InitChainer`的示例: ++++ https://github.com/cosmos/gaia/blob/f41a660cdd5bea173139965ade55bd25d1ee3429/app/app.go#L235-L239 + +### BeginBlocker and EndBlocker + +该SDK为开发人员提供了在其应用程序中实现自定义代码可能性。 这是通过两个名为“ BeginBlocker”和“ EndBlocker”的函数实现的。 当应用程序分别从Tendermint引擎接收到`BeginBlock`和`EndBlock`消息时,将调用它们,它们分别在每个块的开始和结尾处发生。 应用程序必须通过 [SetBeginBlocker](https://godoc.org/github.com/cosmos/cosmos-sdk/baseapp)和[SetEndBlocker](https://godoc.org/github.com/cosmos/cosmos-sdk/baseapp#BaseApp.SetEndBlocker)方法在其 constructor中设置`BeginBlocker`和`EndBlocker`。 + +通常,`BeginBlocker`和`EndBlocker`函数主要由每个应用程序模块的`BeginBlock`和`EndBlock`函数组成。 这是通过调用模块管理器的BeginBlock和EndBlock函数来完成的,而后者又会调用其包含的每个模块的BeginBLock和EndBlock函数。 请注意,必须分别在模块管理器中使用SetOrderBeginBlock和SetOrderEndBlock方法来设置模块的BegingBlock和EndBlock函数必须调用的顺序。 这是通过应用程序的构造函数中的模块管理器完成的,必须调用SetOrderBeginBlock和SetOrderEndBlock方法。 在SetBeginBlocker和SetEndBlocker函数之前。 + +附带说明,请记住特定于应用程序的区块链是确定性的,这一点很重要。 开发人员必须注意不要在BeginBlocker或EndBlocker中引入不确定性,还必须注意不要使它们在计算上过于昂贵,因为[gas]不会限制计算代价当调用 BeginBlocker和EndBlocker执行。 + +请参阅[gaia](https://github.com/cosmos/gaia)中的`BeginBlocker`和`EndBlocker`函数的示例。 + ++++ https://github.com/cosmos/gaia/blob/f41a660cdd5bea173139965ade55bd25d1ee3429/app/app.go#L224-L232 + +### Register Codec + +MakeCodec函数是app.go文件的最后一个重要功能。 此函数的目的是使用 RegisterCodec 函数实例化 codec`cdc`,例如amino初始化SDK的编解码器以及每个应用程序的模块。 + +为了注册应用程序的模块,`MakeCodec`函数在`ModuleBasics`上调用`RegisterCodec`。`ModuleBasics`是一个基本管理器,其中列出了应用程序的所有模块。 它在`init()`函数中得到实例化,仅用于注册应用程序模块的非依赖元素(例如编解码器)。 要了解有关基本模块管理器的更多信息,请点击[这里](https://docs.cosmos.network/master/building-modules/module-manager.html#basicmanager)。 + +请参阅[gaia](https://github.com/cosmos/gaia)中的`MakeCodec`示例: + ++++ https://github.com/cosmos/gaia/blob/f41a660cdd5bea173139965ade55bd25d1ee3429/app/app.go#L64-L70 + +## Modules + +Modules 是SDK应用程序的灵魂。 它们可以被视为状态机中的状态机。 当交易通过ABCI从底层的Tendermint引擎中继到应用程序时,它由 baseapp 找到对应的模块以便进行处理。 这种范例使开发人员可以轻松构建复杂的状态机,因为他们所需的大多数模块通常已经存在。 对于开发人员而言,构建SDK应用程序所涉及的大部分工作都围绕构建其应用程序尚不存在的自定义模块,并将它们与已经存在的模块集成到一个统一的应用程序中。 在应用程序目录中,标准做法是将模块存储在`x/`文件夹中(不要与SDK的`x/`文件夹混淆,该文件夹包含已构建的模块)。 + +### Application Module Interface + +模块必须实现Cosmos SDK AppModuleBasic中的[interfaces](https://docs.cosmos.network/master/building-modules/module-manager.html#application-module-interfaces) 和 AppModule。 前者实现了模块的基本非依赖性元素,例如“编解码器”,而后者则处理了大部分模块方法(包括需要引用其他模块的`keeper`的方法)。 `AppModule`和`AppModuleBasic`类型都在名为`module.go`的文件中定义。 + +AppModule在模块上公开了一组有用的方法,这些方法有助于将模块组合成一个一致的应用程序。 这些方法是从模块管理器中调用的,该模块管理应用程序的模块集合。 + +### Message Types + +每个`module`定义[messages](https://docs.cosmos.network/master/building-modules/messages-and-queries.html#messages)接口。 每个`transaction`包含一个或多个`messages`。 + +当全节点接收到有效的交易块时,Tendermint通过[`DeliverTx`](https://tendermint.com/docs/app-dev/abci-spec.html#delivertx)将每个交易发到应用程序 。 然后,应用程序处理事务: + +- 收到交易后,应用程序首先从`[] bytes`反序列化得到。 +- 然后,在提取交易中包含的消息之前,它会验证有关交易的一些信息,例如费用支付和签名 +- 使用message的Type()方法,baseapp可以将其发到对应模块的 回调 handler以便对其进行处理。 +- 如果消息已成功处理,则状态将更新。 + +有关事务生命周期的更多详细信息,请看[这里](./ tx-lifecycle.md)。 + +模块开发人员在构建自己的模块时会创建自定义消息类型。 通常的做法是在消息的类型声明前加上`Msg`。 例如,消息类型`MsgSend`允许用户传输tokens: + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/x/bank/internal/types/msgs.go#L10-L15 + +它由`bank`模块的回调`handler`处理,最终会调用`auth`模块来写`keeper`以更新状态。 + +### Handler + +回调`handler` 是指模块的一部分,负责处理`baseapp`传递的`message`消息。 仅当通过ABCI接口的DeliverTx 消息从Tendermint 收到事务时,才执行模块的“处理程序”功能。 如果通过CheckTx,仅执行无状态检查和与费用相关的有状态检查。 为了更好地理解`DeliverTx`和`CheckTx`之间的区别以及有状态和无状态检查之间的区别,请看[这里](./ tx-lifecycle.md)。 + +模块的“处理程序”通常在名为`handler.go`的文件中定义,并包括: + +- NewHandler 将消息发到对应的回调“ handler”。 该函数返回一个“ handler”函数,此前这个函数在[AppModule`]中注册,以在应用程序的模块管理器中用于初始化应用程序的路由器。 接下来是[nameservice tutorial](https://github.com/cosmos/sdk-tutorials/tree/master/nameservice)的一个例子。 + +++ https://github.com/cosmos/sdk-tutorials/blob/master/nameservice/x/nameservice/handler.go#L12-L26 +- 模块定义的每种消息类型的处理函数。 开发人员在这些函数中编写消息处理逻辑。 这通常包括进行状态检查以确保消息有效,并调用[`keeper`](https://docs.cosmos.network/master/basics/app-anatomy.html#keeper)的方法来更新状态。 + +处理程序函数返回结果类型为sdk.Result,该结果通知应用程序消息是否已成功处理: + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/result.go#L15-L40 + +### Querier + +`Queriers`与`handlers`非常相似,除了它们向状态查询用户而不是处理事务。 最终用户从interface 发起query,最终用户会提供`queryRoute`和一些` data`。 然后使用`queryRoute`通过baseapp`的`handleQueryCustom方法查询到正确的应用程序的`querier` 函数 + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/baseapp/abci.go#L395-L453 + +模块的Querier是在名为querier.go的文件中定义的,包括: + +- NewQuerier将查找到对应query函数。 此函数返回一个“`querier`”函数,此前它在 AppModule中注册,以在应用程序的模块管理器中用于初始化应用程序的查询路由器。 请参阅[nameservice demo](https://github.com/cosmos/sdk-tutorials/tree/master/nameservice)中的此类切换示例: + +++ https://github.com/cosmos/sdk-tutorials/blob/86a27321cf89cc637581762e953d0c07f8c78ece/nameservice/x/nameservice/internal/keeper/querier.go#L19-L32 + +- 对于模块定义的每种需要查询的数据类型,都具有一个查询器功能。 开发人员在这些函数中编写查询处理逻辑。 这通常涉及调用[`keeper`] 的方法来查询状态并将其 序列化为JSON。 + + +### Keeper + +[`Keepers`](https://docs.cosmos.network/master/building-modules/keeper.html)是其模块存储器件。 要在模块的存储区中进行读取或写入,必须使用其`keeper`方法之一。 这是由Cosmos SDK的 object-capabilities 模型确保的。 只有持有商店密钥的对象才能访问它,只有模块的`keeper`才应持有该模块商店的密钥。 + +`Keepers`通常在名为`keeper.go`的文件中定义。 它包含`keeper`的类型定义和方法。 + +`keeper`类型定义通常包括: + +- 多重存储中模块存储的“密钥”。 + - 参考**其他模块的`keepers`**。 仅当`keeper`需要访问其他模块的存储(从它们读取或写入)时才需要。 +- 对应用程序的“编解码器”的引用。 “ keeper”需要它在存储结构之前序列化处理,或在检索它们时将反序列化处理,因为存储仅接受“ [] bytes”作为值。 + +与类型定义一起,keeper.go文件的一个重要组成部分是Keeper的构造函数NewKeeper。 该函数实例化上面定义的类型的新`keeper`,并带有`codec`,存储`keys`以及可能引用其他模块的`keeper`作为参数。 从应用程序的构造函数中调用`NewKeeper`函数。 文件的其余部分定义了`keeper`的方法,主要是getter和setter。 + +### Command-Line and REST Interfaces + +每个模块都定义了application-interfaces 向用户公开的命令行命令和REST routes。 用户可以创建模块中定义的类型的消息,或查询模块管理的状态的子集。 + +#### CLI + +通常,与模块有关的命令在模块文件夹中名为`client / cli`的文件夹中定义。 CLI将命令分为交易和查询两类,分别在`client / cli / tx.go`和`client / cli / query.go`中定义。 这两个命令基于[Cobra Library](https://github.com/spf13/cobra)之上: + +- Transactions命令使用户可以生成新的事务,以便可以将它们包含在块中并更新状态。 应该为模块中定义的每个消息类型message-types创建一个命令。 该命令使用户提供的参数调用消息的构造函数,并将其包装到事务中。 SDK处理签名和其他事务元数据的添加。 +- 用户可以查询模块定义的状态子集。 查询命令将查询转发到应用程序的查询路由器,然后将查询路由到提供的`queryRoute`参数的相应 querier。 + +#### REST + +模块的REST接口允许用户生成事务并通过对应用程序的 light client daemon(LCD) 查询状态。 REST路由在`client / rest / rest.go`文件中定义,该文件包括: + +- `RegisterRoutes`函数,用于注册路由。 从主应用程序的接口 application-interfaces 中为应用程序内使用的每个模块调用此函数。 SDK中使用的路由器是 [Gorilla's mux](https://github.com/gorilla/mux)。 +- 需要公开的每个查询或事务创建功能的自定义请求类型定义。 这些自定义请求类型基于Cosmos SDK的基本“请求”类型构建: + +++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/rest/rest.go#L47-L60 + +- 每个请求的一个处理函数可以找到给定的模块。 这些功能实现了服务请求所需的核心逻辑。 + +## Application Interface + +Interfaces允许用户与全节点客户端进行交互。 这意味着从全节点查询数据,或者接受全节点中包含在块中的新事务。 + + 通过汇总在应用程序使用的每个模块中定义的 CLI命令构建SDK应用程序的CLI。 应用程序的CLI通常具有后缀-cli(例如appcli),并在名为`cmd / appcli / main.go`的文件中定义。 该文件包含: + +- main()函数,用于构建appcli接口客户端。这个函数准备每个命令,并在构建它们之前将它们添加到`rootCmd`中。在appCli的根部,该函数添加了通用命令,例如status,keys和config,查询命令,tx命令和rest-server。 +- 查询命令是通过调用`queryCmd`函数添加的,该函数也在appcli / main.go中定义。此函数返回一个Cobra命令,其中包含在每个应用程序模块中定义的查询命令(从`main()`函数作为`sdk.ModuleClients`数组传递),以及一些其他较低级别的查询命令,例如阻止或验证器查询。查询命令通过使用CLI的命令“ appcli query [query]”来调用。 +- 通过调用`txCmd`函数来添加**交易命令**。与`queryCmd`类似,该函数返回一个Cobra命令,其中包含在每个应用程序模块中定义的tx命令,以及较低级别的tx命令,例如事务签名或广播。使用CLI的命令`appcli tx [tx]`调用Tx命令。 +- registerRoutes函数,在初始化 轻客户端(LCD)时从main()函数调用。 “ registerRoutes”调用应用程序每个模块的“ RegisterRoutes”功能,从而注册该模块routes 到LCD的查询路由。可以通过运行以下命令“ appcli rest-server”来启动LCD。 + +从[nameservice demo](https://github.com/cosmos/sdk-tutorials/tree/master/nameservice)中查看应用程序的主要命令行文件的示例。 + ++++ https://github.com/cosmos/sdk-tutorials/blob/86a27321cf89cc637581762e953d0c07f8c78ece/nameservice/cmd/nscli/main.go + +## Dependencies and Makefile + +因为开发人员可以自由选择其依赖项管理器和项目构建方法。 也就是说,当前最常用的版本控制框架是[`go.mod`](https://github.com/golang/go/wiki/Modules)。 它确保在整个应用程序中使用的每个库都以正确的版本导入。 请参阅[demo](https://github.com/cosmos/sdk-tutorials/tree/master/nameservice)中的示例: + ++++ https://github.com/cosmos/sdk-tutorials/blob/c6754a1e313eb1ed973c5c91dcc606f2fd288811/go.mod#L1-L18 + +为了构建应用程序,通常使用[Makefile](https://en.wikipedia.org/wiki/Makefile)。 Makefile主要确保在构建应用程序的两个入口点[`appd`](https://docs.cosmos.network/master/basics/app-anatomy.html#node-client)和[`appcli`](https://docs.cosmos.network/master/basics/app-anatomy.html#application-interface)之前运行`go.mod`。 请参阅 nameservice demo 中的Makefile示例 + ++++ https://github.com/cosmos/sdk-tutorials/blob/86a27321cf89cc637581762e953d0c07f8c78ece/nameservice/Makefile + +## Next + +了解有关[交易生命周期](./ tx-lifecycle.md)的更多信息 + diff --git a/docs/cn/basics/gas-fees.md b/docs/cn/basics/gas-fees.md new file mode 100644 index 000000000000..00585e67093e --- /dev/null +++ b/docs/cn/basics/gas-fees.md @@ -0,0 +1,80 @@ +**原文路径:https://github.com/cosmos/cosmos-sdk/blob/master/docs/basics/gas-fees.md** + +# Gas and Fees + +## 必备阅读 {hide} + +- [一个SDK程序的剖析](./app-anatomy.md) {prereq} + +## `Gas` and `Fees`的介绍 + +在Cosmos SDK中,`gas`是一种特殊的单位,用于跟踪执行期间的资源消耗.每当对储存进行读写操作的时候会消耗`gas`,如果要进行比较复杂的计算的话也会消耗`gas`.它主要有两个目的: + +- 确保区块不会消耗太多资源而且能顺利完成.这个默认在SDK的 [block gas meter](#block-gas-meter)中保证 +- 防止来自终端用户的垃圾邮件和滥用.为此,通常会为[`message`](../building-modules/messages-and-queries.md#messages)执行期间的消耗进行定价,并产生`fee` (`fees = gas * gas-prices`).`fees` 通常必须由`message`的发送者来支付.请注意,SDK并没有强制执行对`gas`定价,因为可能会有其他的方法来防止垃圾邮件(例如带宽方案).尽管如此,大多数应用程序仍然会使用`fee` 方式来防止垃圾邮件.这个机制通过[`AnteHandler`](#antehandler)来完成. + +## Gas Meter + +在Cosmos SDK中`gas`是一种简单的`uint64`类型,被称之为*gas meter*的对象进行管理,Gas meters 实现了`GasMeter`接口 + ++++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/store/types/gas.go#L31-L39 + +这里: + +- `GasConsumed()`返回`GasMeter`实例中消耗的`gas`的数量 +- `GasConsumedToLimit()` 返回`GasMeter`实例消耗的gas数量,如果达到上限的话就返回上限 +- `Limit()`返回`GasMeter`实例的上限,如果是0则表示对`gas`的数量没有限制 +- `ConsumeGas(amount Gas, descriptor string)` 消耗提供的`gas`,如果`gas`溢出了,使用`descriptor`内容进行报错,如果`gas`并不是无限的,则超过限制就会报错. +- `IsPastLimit()` 如果`gas`消耗超过了`GasMeter`的限制则返回`true`,其它返回`false` +- `IsOutOfGas()` 如果`gas`消耗大于或等于了`GasMeter`的限制则返回`true`,其它返回`false` + + `GasMeter`通常保存在[`ctx`](../core/context.md)中,`gas`消耗的方式如下: + +```go +ctx.GasMeter().ConsumeGas(amount, "description") +``` + +通常,Cosmos SDK使用两种不同的 `GasMeter`, [main gas meter](#main-gas-metter[)和 [block gas meter](#block-gas-meter). + +### 主 Gas Meter + +`ctx.GasMeter()` 是应用程序的主 `GasMeter`,主 `GasMeter`通过`BeginBlock`中的`setDeliverState`进行初始化,然后跟踪导致状态转换的执行序列中的`gas`消耗.也即是说它的更新由[`BeginBlock`](../core/baseapp.md#beginblock), [`DeliverTx`](../core/baseapp.md#delivertx)和[`EndBlock`](../core/baseapp.md#endblock)进行操作.主 `GasMeter`必须在 [`AnteHandler`](#antehandler)中**设置为0**,以便它能获取每个transaction的Gas消耗 + +`gas`消耗可以手工完成,模块开发者通常在 [`BeginBlocker`, `EndBlocker`](../building-modules/beginblock-endblock.md)或者 [`handler`](../building-modules/handler.md)上执行,但大多数情况下,只要对储存区进行了读写,它就会自动完成.这种自动消耗的逻辑在[`GasKv`](../core/store.md#gaskv-store)中完成. + +### 块 Gas Meter + +`ctx.BlockGasMeter()` 是跟踪每个区块`gas`消耗并保证它没有超过限制的`GasMeter`.每当[`BeginBlock`](../core/baseapp.md#beginblock)被调用的时候一个新的 `BlockGasMeter`实例将会被创建. `BlockGasMeter`的`gas`是有限的,每个块的`gas`限制应该在应用程序的共识参数中定义,Cosmos SDK应用程序使用Tendermint提供的默认共识参数: + ++++ https://github.com/tendermint/tendermint/blob/f323c80cb3b78e123ea6238c8e136a30ff749ccc/types/params.go#L65-L72 + +当通过`DeliverTx`处理新的[transaction](../core/transactions.md)的时候,`BlockGasMeter`的当前值会被校验是否超过上限,如果超过上限,`DeliverTx` 直接返回,由于`BeginBlock`会消耗`gas`,这种情况可能会在第一个`transaction`到来时发生,如果没有发生这种情况,`transaction`将会被正常的执行.在`DeliverTx`的最后,`ctx.BlockGasMeter()`会追踪`gas`消耗并将它增加到处理`transaction`的`gas`消耗中. + +```go +ctx.BlockGasMeter().ConsumeGas( + ctx.GasMeter().GasConsumedToLimit(), + "block gas meter", +) +``` + +## AnteHandler + +`AnteHandler`是一个特殊的处理程序,它在`CheckTx` 和 `DeliverTx`期间为每一个`transaction`的每个`message`处理之前执行.`AnteHandler`相比`handler`有不同的签名: + +```go +// AnteHandler authenticates transactions, before their internal messages are handled. +// If newCtx.IsZero(), ctx is used instead. +type AnteHandler func(ctx Context, tx Tx, simulate bool) (newCtx Context, result Result, abort bool) +``` + +`AnteHandler`不是在核心SDK中实现的,而是在每一个模块中实现的,这使开发者可以使用适合其程序需求的`AnteHandler`版本,也就是说当前大多数应用程序都使用 [`auth` module](https://github.com/cosmos/cosmos-sdk/tree/master/x/auth)中定义的默认实现.下面是`AnteHandler`在普通Cosmos SDK程序中的作用: + +- 验证事务的类型正确。 事务类型在实现`anteHandler`的模块中定义,它们遵循事务接口: + +++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/tx_msg.go#L33-L41 + 这使开发人员可以使用各种类型的应用程序进行交易。 在默认的auth模块中,标准事务类型为StdTx: + +++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/x/auth/types/stdtx.go#L22-L29 +- 验证交易中包含的每个[`message`](../building-modules/messages-and-queries.md#messages)的签名,每个`message`应该由一个或多个发送者签名,这些签名必须在`anteHandler`中进行验证. +- 在`CheckTx`期间,验证`transaction`提供的 `gas prices`是否大于本地配置`min-gas-prices`(提醒一下,`gas-prices`可以从以下等式中扣除`fees = gas * gas-prices` )`min-gas-prices`是每个独立节点的本地配置,在`CheckTx`期间用于丢弃未提供最低费用的交易.这确保了内存池不会被垃圾交易填充. +- 设置 `newCtx.GasMeter` 到0,限制为`GasWanted`.**这一步骤非常重要**,因为它不仅确保交易不会消耗无限的天然气,而且还会在每个`DeliverTx`重置`ctx.GasMeter`(每次 `DeliverTx` 被调用的时候都会执行`anteHandler`,`anteHandler`运行之后`ctx`将会被设置为`newCtx`) + +如上所述,`anteHandler`返回`transaction`执行期间所能消耗的最大的`gas`数量,称之为`GasWanted`.最后实际`gas`消耗数量记为`GasUsed`,因此我们必须使`GasUsed =< GasWanted`.当返回时`GasWanted` 和 `GasUsed`都会被中继到共识引擎中. \ No newline at end of file diff --git a/docs/cn/basics/tx-lifecycle.md b/docs/cn/basics/tx-lifecycle.md new file mode 100644 index 000000000000..ac65fe5d8fa0 --- /dev/null +++ b/docs/cn/basics/tx-lifecycle.md @@ -0,0 +1,163 @@ +# Transaction的生命周期 + +本文档描述了Transaction从创建到提交的生命周期,Transaction的定义在[其他文档](https://docs.cosmos.network/master/core/transactions.html)中有详细描述,后文中Transaction将统一被称为`Tx`。 + +## 创建 + +### Transaction的创建 + +命令行界面是主要的应用程序界面之一,`Tx`可以由用户输入[以下命令](https://docs.cosmos.network/master/interfaces/cli.html)来创建,其中`[command]`是`Tx`的类型,`[args]`是相关参数,`[flags]`是相关配置例如gas price: + +```bash +[appname] tx [command] [args] [flags] +``` + +此命令将自动**创建**`Tx`,使用帐户的私钥对其进行**签名**,并将其**广播**到其他节点。 + +创建`Tx`有一些必需的和可选的参数,其中`--from`指定该`Tx`的发起[账户](https://docs.cosmos.network/master/basics/accounts.html),例如一个发送代币的`Tx`,则将从 `from`指定的账户提取资产。 + +#### Gas 和 Fee + +此外,用户可以使用这几个[参数](https://docs.cosmos.network/master/interfaces/cli.html)来表明他们愿意支付多少[fee](https://docs.cosmos.network/master/basics/gas-fees.html): + +* `--gas` 指的是[gas](https://docs.cosmos.network/master/basics/gas-fees.html)的数量,gas代表`Tx`消耗的计算资源,需要消耗多少gas取决于具体的`Tx`,在`Tx`执行之前无法被精确计算出来,但可以通过在`--gas`后带上参数`auto`来进行估算。 +* `--gas-adjustment`(可选)可用于适当的增加 `gas` ,以避免其被低估。例如,用户可以将`gas-adjustment`设为1.5,那么被指定的gas将是被估算gas的1.5倍。 +* `--gas-prices` 指定用户愿意为每单位gas支付多少fee,可以是一种或多种代币。例如,`--gas-prices=0.025uatom, 0.025upho`就表明用户愿意为每单位的gas支付0.025uatom 和 0.025upho。 +* `--fees` 指定用户总共愿意支付的fee。 + +所支付fee的最终价值等于gas的数量乘以gas的价格。换句话说,`fees = ceil(gas * gasPrices)`。由于可以使用gas价格来计算fee,也可以使用fee来计算gas价格,因此用户仅指定两者之一即可。 + +随后,验证者通过将给定的或计算出的`gas-prices`与他们本地的`min-gas-prices`进行比较,来决定是否在其区块中写入该`Tx`。如果`gas-prices`不够高,该`Tx`将被拒绝,因此鼓励用户支付更多fee。 + +#### CLI 示例 + +应用程序的用户可以在其CLI中输入以下命令,用来生成一个将1000uatom从`senderAddress`发送到 `recipientAddress`的`Tx`,该命令指定了用户愿意支付的gas(其中gas数量为自动估算的1.5倍,每单位gas价格为0.025uatom)。 + +```bash +appcli tx send 1000uatom --from --gas auto --gas-adjustment 1.5 --gas-prices 0.025uatom +``` + +#### 其他的Transaction创建方法 + +命令行是与应用程序进行交互的一种简便方法,但是`Tx`也可以使用[REST interface](https://docs.cosmos.network/master/interfaces/rest.html)或应用程序开发人员定义的某些其他入口点来创建命令行。从用户的角度来看,交互方式取决于他们正在使用的是页面还是钱包(例如,`Tx`使用[Lunie.io](https://lunie.io/#/) 创建并使用Ledger Nano S对其进行签名)。 + +## 添加到交易池 + +每个全节点(Tendermint节点)接收到`Tx`后都会发送一个名为`CheckTx`的[ABCI message](https://tendermint.com/docs/spec/abci/abci.html#messages),用来检查`Tx`的有效性,`CheckTx`会返回`abci.ResponseCheckTx`。 +如果`Tx`通过检查,则将其保留在节点的 [**交易池**](https://tendermint.com/docs/tendermint-core/mempool.html#mempool)(每个节点唯一的内存事务池)中等待出块,`Tx`如果被发现无效,诚实的节点将丢弃该`Tx`。在达成共识之前,节点会不断检查传入的`Tx`并将其广播出去。 + +### 检查的类型 + +全节点在`CheckTx`期间对`Tx`先执行无状态检查,然后进行有状态检查,目的是尽早识别并拒绝无效`Tx`,以免浪费计算资源。 + +***无状态检查***不需要知道节点的状态,即轻客户端或脱机节点都可以检查,因此计算开销较小。无状态检查包括确保地址不为空、强制使用非负数、以及定义中指定的其他逻辑。 + +***状态检查***根据提交的状态验证`Tx`和`Message`。例如,检查相关值是否存在并能够进行交易,账户是否有足够的资产,发送方是否被授权或拥有正确的交易所有权。在任何时刻,由于不同的原因,全节点通常具有应用程序内部状态的[多种版本](https://docs.cosmos.network/master/core/baseapp.html#volatile-states)。例如,节点将在验证`Tx`的过程中执行状态更改,但仍需要最后的提交状态才能响应请求,节点不能使用未提交的状态更改来响应请求。 + +为了验证`Tx`,全节点调用的`CheckTx`包括无状态检查和有状态检查,进一步的验证将在[`DeliverTx`](#delivertx)阶段的后期进行。其中`CheckTx`从对`Tx`进行解码开始。 + +### 解码 + +当`Tx`从应用程序底层的共识引擎(如Tendermint)被接收时,其仍处于`[]byte`[编码](https://docs.cosmos.network/master/core/encoding.html)形式,需要将其解码才能进行操作。随后,[`runTx`](https://docs.cosmos.network/master/core/baseapp.html#runtx-and-runmsgs) 函数会被调用,并以`runTxModeCheck`模式运行,这意味着该函数将运行所有检查,但是会在执行`Message`和写入状态更改之前退出。 + +### ValidateBasic + +[Message](https://docs.cosmos.network/master/core/transactions.html#messages)是由module的开发者实现的`Msg`接口中的一个方法。它应包括基本的**无状态**完整性检查。例如,如果`Message`是要将代币从一个账户发送到另一个账户,则`ValidateBasic`会检查账户是否存在,并确认账户中代币金额为正,但不需要了解状态,例如帐户余额。 + +### AnteHandler + +[`AnteHandler`](https://docs.cosmos.network/master/basics/gas-fees.html#antehandler)是可选的,但每个应用程序都需要定义。`AnteHandler`使用副本为特定的`Tx`执行有限的检查,副本可以使对`Tx`进行状态检查时无需修改最后的提交状态,如果执行失败,还可以还原为原始状态。 + +例如, [`auth`](https://github.com/cosmos/cosmos-sdk/tree/master/x/auth/spec)模块的`AnteHandler`检查并增加序列号,检查签名和帐号,并从`Tx`的第一个签名者中扣除费用,这个过程中所有状态更改都使用`checkState` + +### Gas + + [`Context`](https://docs.cosmos.network/master/core/context.html)相当于`GasMeter`,会计算出在`Tx`的执行过程中多少`gas`已被使用。用户提供的`Tx`所需的`gas`数量称为`GasWanted`。`Tx`在实际执行过程中消耗的`gas`被称为`GasConsumed`,如果`GasConsumed`超过`GasWanted`,将停止执行,并且对状态副本的修改不会被提交。否则,`CheckTx`设置`GasUsed`等于`GasConsumed`并返回结果。在计算完gas和fee后,验证器节点检查用户指定的值`gas-prices`是否小于其本地定义的值`min-gas-prices`。 + +### 丢弃或添加到交易池 + +如果在`CheckTx`期间有任何失败,`Tx`将被丢弃,并且`Tx`的生命周期结束。如果`CheckTx`成功,则`Tx`将被广播到其他节点,并会被添加到交易池,以便成为待出区块中的候选`Tx`。 + +**交易池**保存所有全节点可见的`Tx`,全节点会将其最近的`Tx`保留在**交易池缓存**中,作为防止重放攻击的第一道防线。理想情况下,`mempool.cache_size`的大小足以容纳整个交易池中的所有`Tx`。如果交易池缓存太小而无法跟踪所有`Tx`,`CheckTx`会识别出并拒绝重放的`Tx`。 + +现有的预防措施包括fee和`序列号` 计数器,用来区分重放`Tx`和相同的`Tx`。如果攻击者尝试向某个节点发送多个相同的`Tx`,则保留交易池缓存的完整节点将拒绝相同的`Tx`,而不是在所有`Tx`上运行`CheckTx` 。如果`Tx`有不同的`序列号`,攻击者会因为需要支付费用而取消攻击。 + +验证器节点与全节点一样,保留一个交易池以防止重放攻击,但它也用作出块过程中未经验证的交易池。请注意,即使`Tx`在此阶段通过了所有检查,仍然可能会被发现无效,因为`CheckTx`没有完全验证`Tx`(`CheckTx`实际上并未执行`message`)。 + +## 写入区块 + +共识是验证者节点就接受哪些`Tx`达成协议的过程,它是**反复进行**的。每个回合都始于出块节点创建一个包含最近`Tx`的区块,并由验证者节点(具有投票权的特殊全节点)负责达成共识,同意接受该区块或出一个空块。验证者节点执行共识算法,例如[Tendermint BFT](https://tendermint.com/docs/spec/consensus/consensus.html#terms),调用ABCI请求确认`Tx`,从而达成共识。 + +达成共识的第一步是**区块提案**,共识算法从验证者节点中选择一个出块节点来创建和提议一个区块,用来写入`Tx`,`Tx`必须在该提议者的交易池中。 + +## 状态变更 + +共识的下一步是执行`Tx`以完全验证它们,所有的全节点收到出块节点广播的区块并调用ABCI函数[`BeginBlock`](https://docs.cosmos.network/master/basics/app-anatomy.html#beginblocker-and-endblocker),`DeliverTx`,和[`EndBlock`](https://docs.cosmos.network/master/basics/app-anatomy.html#beginblocker-and-endblocker)。全节点在本地运行的每个过程将产生一个明确的结果,因为`message`的状态转换是确定性的,并且`Tx`在提案中有明确的顺序。 + +``` + ----------------------------- + |Receive Block Proposal| + ----------------------------- + | + v + ----------------------------- + | BeginBlock | + ----------------------------- + | + v + ----------------------------- + | DeliverTx(tx0) | + | DeliverTx(tx1) | + | DeliverTx(tx2) | + | DeliverTx(tx3) | + | . | + | . | + | . | + ----------------------------- + | + v + ----------------------------- + | EndBlock | + ----------------------------- + | + v + ----------------------------- + | Consensus | + ----------------------------- + | + v + ----------------------------- + | Commit | + ----------------------------- +``` + +### DeliverTx + + [`baseapp`](https://docs.cosmos.network/master/core/baseapp.html)中定义的ABCI函数`DeliverTx`会执行大部分状态转换,`DeliverTx`会针对共识中确定的顺序,对块中的每个`Tx`按顺序运行。`DeliverTx`几乎和`CheckTx`相同,但是会以deliver模式调用[`runTx`](../core/baseapp.md#runtx)函数而不是check模式。全节点不使用`checkState`,而是使用`deliverState`。 + + +* **解码:**由于`DeliverTx`是通过ABCI调用的,因此`Tx`会以`[]byte`的形式被接收。节点首先会对`Tx`进行解码,然后在`runTxModeDeliver`中调用`runTx`,`runTx`除了会执行`CheckTx`中的检查外,还会执行`Tx`和并写入状态的变化。 + +* **检查:** 全节点会再次调用`validateBasicMsgs`和`AnteHandler`。之所以进行第二次检查,是因为在`Tx`进交易池的过程中,可能没有相同的`Tx`,但恶意出块节点的区块可能包括无效`Tx`。但是这次检查特殊的地方在于, `AnteHandler`不会将`gas-prices`与节点的`min-gas-prices`比较,因为每个节点的`min-gas-prices`可能都不同,这样比较的话可能会产生不确定的结果。 + +* **路由和Handler:** `CheckTx`退出后,`DeliverTx`会继续运行 [`runMsgs`](https://docs.cosmos.network/master/core/baseapp.html#runtx-and-runmsgs) 来执行`Tx`中的每个`Msg`。由于`Tx`可能具有来自不同模块的`message`,因此`baseapp`需要知道哪个模块可以找到适当的`Handler`。因此,`路由`通过[模块管理器](https://docs.cosmos.network/master/building-modules/module-manager.html)来检索路由名称并找到对应的[`Handler`](https://docs.cosmos.network/master/building-modules/handler.html)。 + +* **Handler:**`handler`是用来执行`Tx`中的每个`message`,并且使状态转换到从而保持`deliverTxState`。`handler`在`Msg`的模块中定义,并写入模块中的适当存储区。 + +* **Gas:**在`Tx`被传递的过程中,`GasMeter`是用来记录有多少gas被使用,如果执行完成,`GasUsed`会被赋值并返回`abci.ResponseDeliverTx`。如果由于`BlockGasMeter` 或者 `GasMeter` 耗尽或其他原因导致执行中断,程序则会报出相应的错误。 + +如果由于`Tx`无效或`GasMeter`用尽而导致任何状态更改失败,`Tx`的处理将被终止,并且所有状态更改都将还原。区块提案中无效的`Tx`会导致验证者节点拒绝该区块并投票给空块。 + +### 提交 + +最后一步是让节点提交区块和状态更改,在重跑了区块中所有的`Tx`之后,验证者节点会验证区块的签名以最终确认它。不是验证者节点的全节点不参与共识(即无法投票),而是接受投票信息以了解是否应提交状态更改。 + +当收到足够的验证者票数(2/3+的加权票数)时,完整的节点将提交一个新的区块,以添加到区块链网络中并最终确定应用程序层中的状态转换。此过程会生成一个新的状态根,用作状态转换的默克尔证明。应用程序使用从[Baseapp](https://docs.cosmos.network/master/core/baseapp.html)继承的ABCI方法[`Commit`](https://docs.cosmos.network/master/core/baseapp.html#commit),`Commit`通过将`deliverState`写入应用程序的内部状态来同步所有的状态转换。提交状态更改后,`checkState`从最近提交的状态重新开始,并将`deliverState`重置为空以保持一致并反映更改。 + +请注意,并非所有区块都具有相同数量的`Tx`,并且共识可能会导致一个空块。在公共区块链网络中,验证者可能是**拜占庭恶意**的,这可能会阻止将`Tx`提交到区块链中。可能的恶意行为包括出块节点将某个`Tx`排除在区块链之外,或者投票反对某个出块节点。 + +至此,`Tx`的生命周期结束,节点已验证其有效性,并提交了这些更改。`Tx`本身,以`[]byte`的形式被存储在区块上进入了区块链网络。 + +## 下一节 + +了解 [accounts](./accounts.md) \ No newline at end of file diff --git a/docs/cn/intro/README.md b/docs/cn/intro/README.md index 81609d2a7378..68bd364f8374 100644 --- a/docs/cn/intro/README.md +++ b/docs/cn/intro/README.md @@ -1,31 +1,13 @@ -# SDK介绍 +# 介绍 -## 什么是Cosmos SDK? +此目录包含对cosmos sdk的相关介绍 -[Cosmos-SDK](https://github.com/cosmos/cosmos-sdk) 是一个架构,用于构建多资产股权证明(PoS)的区块链,比如Cosmos Hub,以及权益证明(PoA)的区块链。使用Cosmos SDK构建的区块链通常称为**特定应用区块链**。 +1. [概述](./overview.md) -Cosmos SDK的目标是允许开发者从头开始轻松创建原生就能同其他区块链相互操作的自定义区块链。我们设想SDK类似于Ruby-on-Rails框架之上构建应用一样,可以很方便在[Tendermint](https://github.com/tendermint/tendermint)之上构建安全的区块链应用。 基于SDK的区块链通过可组合的模块构建出来的,大部分模块是开源的,并且可供任何开发人员使用。 任何人都可以为Cosmos-SDK 创建一个模块,集成已经构建的模块就像将它们导入到区块链应用程序一样简单。 更重要的是,Cosmos SDK是一个基于**能力**(capabilities)的系统,开发人员可以更好地了解模块之间交互的安全性。 要深入了解能力,请跳到[OCAP](./ocap.md)。 +2. [基于特定应用的区块链](./why-app-specific.md) -## 什么是特定应用区块链? +3. [应用架构](./sdk-app-architecture.md) +4. [Cosmos SDK设计概述](./sdk-design.md) -今天区块链的一个发展模式是像以太坊这样的虚拟机区块链,开发通常围绕着在现有区块链之上通过智能合约构建一个去中心化的应用程序。 虽然智能合约对于像单用途应用程序(如ICO)这样的一些场景非常有用,但对于构建复杂的去中心化平台往往是不够的。 更一般地说,智能合约在灵活性、主权和性能方面受到限制。 - -特定应用区块链提供了与虚拟机区块链截然不同的开发模式。 特定应用区块链是一个定制的区块链来服务单个应用程序:开发人员可以自由地做出应用程序运行最佳所需的设计决策。 它们还可以提供更好的主权、安全和性能。 - -要了解有关特定应用区块链的更多信息,可参考[这里](./why-app-specific.md)。 - -## 为什么是 Cosmos SDK? - -Cosmos SDK 是目前用于构建自定义的特定应用区块链的最先进的框架。 以下是一些你可能需要考虑使用 Cosmos SDK 构建去中心化应用的原因: - -* SDK中默认共识引擎是 [Tendermint Core](https://github.com/tendermint/tendermint) 。 Tendermint 是已存在的最成熟(也是唯一的)的BFT共识引擎。 它被广泛应用于行业,被认为是建立股权证明系统(POS)的黄金标准共识引擎。 -* SDK是开源的,旨在使其易于从可组合模块中构建区块链。 随着开源SDK模块生态系统的发展,使用它构建复杂的去中心化平台将变得越来越容易。 -* SDK 受基于能力的安全性启发,及多年来解决区块链状态机的经验。 这使得 Cosmos SDK 成为构建区块链的非常安全的环境。 -* 最重要的是,Cosmos SDK已经被许多特定应用区块链产品所使用。 如:[Cosmos Hub](https://hub.cosmos.network), [Iris](https://irisnet.org), [Binance Chain](https://docs.binance.org/), [Terra](https://terra.money/) or [Lino](https://lino.network/) ,除此之外还有很多建立在Cosmos SDK的项目。 你可以在这里查看[生态系统](https://cosmos.network/ecosystem)。 - - -## 开始使用 Cosmos SDK - -* 了解[SDK 应用体系架构](./sdk-app-architecture.md)的详细信息 -* 了解如何从头构建特定应用区块链,参考[SDK教程](https://tutorials.cosmos.network/) 。 +了解完成相关介绍后,可以前往 [基础文档](../basics/README.md) 了解更多。 \ No newline at end of file diff --git a/docs/cn/intro/overview.md b/docs/cn/intro/overview.md new file mode 100644 index 000000000000..0304b0c20498 --- /dev/null +++ b/docs/cn/intro/overview.md @@ -0,0 +1,33 @@ +# Cosmos SDK 介绍 + +## 什么是Cosmos SDK + +[Cosmos SDK](https://github.com/cosmos/cosmos-sdk)是开源框架,用于构建类似Cosmos Hub等基于POS共识算法的多元资产公有区块链,以及基于权威证明共识算法的许可链。使用Cosmos SDK构建的区块链通常被称为特定应用区块链(专用区块链)(application-specific blockchains)。 + +Cosmos SDK的目标是让开发者可以快速地构建一条能与其他区块链以源生的方式进行互操作的可定制区块链。在我们的设想中,这套SDK就像Web应用框架一样,可以让开发者迅速构建出基于[Tendermint](https://github.com/tendermint/tendermint)算法的安全区块链应用程序。 由Cosmos SDK的区块链由组合式[模块](https://docs.cosmos.network/master/building-modules/intro.html)构建,其中大部分模块都是开源的,且任何开发者均可使用。任何人都能为Cosmos SDK创建新的模块,集成已经构建的模块就像将他们导入你的区块链应用程序一样简单。还有一点,Cosmos SDK是基于功能(capabilities)的系统,这允许开发者可以更好地考虑模块之间交互的安全性。更深入地了解功能,请跳至[本节](https://docs.cosmos.network/master/core/ocap.html)。 + +##什么是特定应用区块链 + +目前在区块链领域中,一种开发模式是通过像以太坊这样的虚拟机区块链展开,即开发者在现有的区块链上通过智能合约的方式去构建去中心化应用。虽然智能合约在单用途应用场景(如ICO)下非常有用,但在构建复杂的去中心化平台时无法达到要求。更具体地说,智能合约在灵活性、所有权、性能方面会受到限制。 + +特定应用区块链提供了与虚拟机区块链截然不同的开发模式。特定应用区块链是面向单个具体应用程序的高度定制化区块链:开发者可以完全自由地做出让应用程序可以达到最佳运行状态的设计决策。他们也可以提供更好的主导权、安全性和性能。 + +了解更多可参考[特定应用区块链](https://docs.cosmos.network/master/intro/why-app-specific.html)。 + +## 为什么选择Cosmos SDK? + +Cosmos SDK是目前最先进的构建可定制化特定应用区块链的框架。以下是一些可能让你希望通过Cosmos SDK构建去中心化应用的原因: + +- Cosmos SDK 默认的共识引擎是[Tendermint Core](https://github.com/tendermint/tendermint). Tendermint是目前最成熟的、唯一的BFT共识引擎。它被广泛应用于行业中,被认为是构建POS系统的最佳标准共识引擎。 + +- Cosmos SDK是开源的,你可以通过组合式[modules](https://docs.cosmos.network/master/x/)轻松地构建出区块链。随着SDK生态中各种开源模块的发展,通过Cosmos SDK构建复杂的去中心化平台会变得越来越容易。 + +- Cosmos SDK 受基于功能的安全性所启发,并受益于多年来在区块链状态机领域的经验。这让Cosmos SDK成为一个非常安全的构建区块链的环境。 + +- 最重要的是,Cosmos SDK已经构建出了多个正在运行中的特定应用区块链。例如,Cosmos HUB,IRIS HUB,Binance Chain, Terra 和 Kava。更多机遇Cosmos SDK构建的区块链参考[这里](https://cosmos.network/ecosystem)。 + +## 开始使用Cosmos SDK + +了解更多请参考[SDK应用架构](https://docs.cosmos.network/master/intro/sdk-app-architecture.html)。 + +了解如何从头建立特定应用区块链,请参考[SDK教程](https://cosmos.network/docs/tutorial)。 \ No newline at end of file diff --git a/docs/cn/intro/sdk-app-architecture.md b/docs/cn/intro/sdk-app-architecture.md index c31d888e1416..a431cb42cebd 100644 --- a/docs/cn/intro/sdk-app-architecture.md +++ b/docs/cn/intro/sdk-app-architecture.md @@ -1,12 +1,12 @@ -# SDK 应用程序架构 +# 区块链架构 ## 状态机 -区块链应用的核心是[具有最终确定性的复制状态机](https://en.wikipedia.org/wiki/State_machine_replication)。 +区块链的核心是[复制确定状态机](https://en.wikipedia.org/wiki/State_machine_replication)(replicated deterministic state machine)。 -状态机是计算机科学概念,一台机器可以具有多个状态,但在任何给定时间只有一个`状态`,其描述了系统的当前状态,及触发这些状态转变的交易(译者注:也对应数据库中事务的概念)。 +状态机是计算机科学领域的一个概念,即一台机器可以具有多个状态,但在任意给定时刻只具有一个确定的状态。我们用`state`描述系统当前状态,`transactions`触发状态转换。 -给定一个状态S和交易T,状态机会返回一个新的状态S'。 +给定一个状态S和Transaction T,状态机会返回新的状态S'。 ``` +--------+ +--------+ @@ -16,7 +16,7 @@ +--------+ +--------+ ``` -实际上,交易以区块的形式打包在一起以提高过程的效率。给定状态S和包含交易的区块B,状态机将返回新状态S'。 +在实际中,Transaction集会被打包进区块中,以让处理过程更加高效。给定一个状态S和一个包含Transaction集 B的区块,状态机就会返回新的状态S'。 ``` +--------+ +--------+ @@ -26,70 +26,66 @@ +--------+ +--------+ ``` -在区块链上下文环境中,状态机是确定性的。这意味着如果你从一个给定的状态开始,重放相同顺序的交易,将始终以相同的最终状态结束。 +在区块链的上下文环境中,状态机是确定的。这意味着节点从给定状态开始,重放相同的Transaction序列,总能得到相同的最终状态。 -Cosmos SDK 为你提供了最大的灵活性用以定义自身应用程序的状态、交易类型和状态转换函数。在接下来的章节中会更深入细致的描述如何使用 SDK 来构建状态机。但首先,让我们看看状态机是如何使用 **Tendermint** 进行复制的。 +Cosmos SDK为开发者提供了最大程度的灵活性去定义应用程序的状态,Transaction类型和状态转换功能。接下来的章节中会更详细地介绍使用SDK构建状态机的过程。在此之前,先让我们看看如何使用Tendermint复制状态机。 -### Tendermint +## Tendermint -作为一个开发者,你只需要使用 Cosmos-SDK 定义状态机,而[Tendermint](https://tendermint.com/docs/introduction/introduction.html)将会为你处理网络层的状态复制。 +得益于Cosmos SDK,开发者只需要定义好状态机,[Tendermint](https://tendermint.com/docs/introduction/what-is-tendermint.html)就会处理好状态复制的工作。 ``` ^ +-------------------------------+ ^ - | | | | 通过 Cosmos SDK 构建 - | | 状态机 = 应用(层) | | + | | | | Built with Cosmos SDK + | | State-machine = Application | | | | | v | +-------------------------------+ | | | ^ - 链节点 | | 共识层 | | +Blockchain node | | Consensus | | | | | | | +-------------------------------+ | Tendermint Core | | | | - | | 网络层 | | + | | Networking | | | | | | v +-------------------------------+ v ``` -Tendermint是一个与应用程序无关的引擎,负责处理区块链的*网络层*和*共识层*。实际上,这意味着Tendermint负责传播和排序交易字节。Tendermint Core 依赖于拜占庭容错(BFT)算法来达成交易顺序的共识。要深入了解Tendermint,可点击[这里](https://tendermint.com/docs/introduction/what-is-tendermint.html)。 - -Tendermint一致性算法通过一组称为*验证人*的特殊节点一起运作。验证人负责向区块链添加交易区块。对于任何给定的区块,有一组验证人V。通过算法选择V中的验证人A作为下一个区块的提议人。如果超过三分之二的V签署了[prevote](https://tendermint.com/docs/spec/consensus/consensus.html#state-machine-spec)和[precommit](https://tendermint.com/docs/spec/consensus/consensus.html#state-machine-spec),并且区块包含的所有交易都是有效的,则该区块被认为是有效的。验证人集合可以通过状态机中编写的规则进行更改。要深入了解算法,[点击](https://tendermint.com/docs/introduction/what-is-tendermint.html#consensus-overview)。 - -Cosmos SDK 应用程序的主要部分是一个区块链服务后台(daemon),它在每个网络节点的本地运行。如果验证人集合中三分之一以下的是拜占庭(即恶意的),则每个节点在同时查询状态时应获得相同的结果。 +[Tendermint](https://tendermint.com/docs/introduction/what-is-tendermint.html) 是一个与应用程序无关的引擎,负责处理区块链的网络层和共识层。这意味着Tendermint负责对Transaction字节进行传播和排序。Tendermint Core 通过同名的拜占庭容错算法来达成Transaction顺序的共识。 +Tendermint[共识算法](https://tendermint.com/docs/introduction/what-is-tendermint.html#consensus-overview)与一组被称为Validator的特殊节点共同运作。Validator负责向区块链中添加包含transaction的区块。在任何给定的区块中,都有一组Validator集合V。算法会从集合V中选出一个Validator作为下一个区块的Proposer。如果一个区块被集合V中超过三分之二的Validator签署了[prevote](https://tendermint.com/docs/spec/consensus/consensus.html#prevote-step-height-h-round-r)和[precommit](https://tendermint.com/docs/spec/consensus/consensus.html#precommit-step-height-h-round-r),且区块中所有Transaction都是有效的,则认为该区块有效。Validator集合可以按照状态机中写定的规则更改。 ## ABCI -Tendermint通过名为[ABCI](https://github.com/tendermint/tendermint/tree/master/abci)的接口将交易从网络层传递给应用程序,因此应用程序必须要实现 ABCI 。 +Tendermint通过被称为[ABCI](https://tendermint.com/docs/spec/abci/)的接口向应用程序传递Transactions,该接口必须由应用程序实现。 ``` -+---------------------+ -| | -| 应用 | -| | -+--------+---+--------+ - ^ | - | | ABCI - | v -+--------+---+--------+ -| | -| | -| Tendermint | -| | -| | -+---------------------+ + +---------------------+ + | | + | Application | + | | + +--------+---+--------+ + ^ | + | | ABCI + | v + +--------+---+--------+ + | | + | | + | Tendermint | + | | + | | + +---------------------+ ``` -注意,Tendermint 仅处理交易字节。它不知道这些字节究竟是什么意思。Tendermint 所做的只是对交易确定性地排序。赋予这些字节意义是应用程序的工作。Tendermint通过ABCI将交易字节传递给应用程序,并期望返回代码以知晓消息是否成功。 +需要注意的是,Tendermint仅处理transaction字节,它并不知道这些字节的含义。Tendermint所做的只是对transaction字节进行确定性地排序。Tendermint通过ABCI向应用程序传递字节,并期望返回状态码以获知包含在transactions中的messages是否成功处理。 -以下是ABCI中最重要的消息类型: +以下是ABCI最重要的Messages: -- `CheckTx` : 当 Tendermint Core 收到交易时,如果符合一些的基本的要求会将其传递给应用程序。`Checkx` 用于保护全节点的交易池免受垃圾邮件的侵害。一个名为“Ante Handler”的特殊处理器用于执行一系列验证步骤,例如检查手续费用是否足够和验证签名是否合法。如果交易有效,则将交易添加到[交易池(mempool)](https://tendermint.com/docs/spec/reactors/mempool/functionality.html#mempool-functionality)中并广播到对等节点。注意, `CheckTx` 不会处理交易(即不会对修改状态),因为它们尚未包含在区块中。 -- `DeliverTx` : 当 Tendermint Core 接收到[有效区块](https://tendermint.com/docs/spec/blockchain/blockchain.html#validation)时,块中的每条交易都将通过 `DeliverTx `传递给应用程序进行处理。正是在这一阶段发生了状态转换。“Ante Handler”也将连同实际处理交易中每条消息的handler一起再次执行。 -- `BeginBlock`/`EndBlock` : 无论区块是否包含交易,这两个消息都将在每个区块的开头和结尾执行。触发自动的逻辑执行是很有用的。过程中要足够小心,因为计算成本高昂的循环运算可能会减慢区块链的速度,甚至发生无限循环引起区块链本身停滞。 +`CheckTx`:当Tendermint Core接收到一个Transaction时,它会传递给应用程序以检查是否满足一些基本要求。`CheckTx` 用于保护全节点的内存池免受垃圾transactions攻击。`AnteHandler`这一特殊处理程序用于执行一系列验证步骤,例如检查手续费是否足够以及验证签名。如果检查通过,该transaction会被添加进[mempool](https://tendermint.com/docs/spec/reactors/mempool/functionality.html#mempool-functionality),并广播给其他共识节点。请注意,此时transactions尚未被`CheckTx`处理(即未进行状态修改),因为它们还没有被包含在区块中。 +`DeliverTx`:当Tendermint Core收到一个[有效区块](https://tendermint.com/docs/spec/blockchain/blockchain.html#validation)时,区块中的每一个Transaction都会通过`DeliverTx`传递给应用程序以进行处理。状态转换会在这个阶段中发生。`AnteHandler`会与Transaction中每个Message的实际[`handlers`](https://docs.cosmos.network/master/building-modules/handler.html)一起再次执行。 -有关 ABCI 方法和类型的详细介绍请[点击](https://tendermint.com/docs/spec/abci/abci.html#overview)。 +`BeginBlock/EndBlock`:无论区块中是否包含transaction,messages都会在每个区块的开头和结尾处执行。触发自动执行的逻辑是很有用的。但需要谨慎使用,因为计算量庞大的循环会严重降低区块链的性能,而无限循环甚至会导致区块链宕机。 -在 Tendermint 上构建的任何应用程序都需要实现ABCI接口,来同本地的底层 Tendermint 引擎进行通信。幸运的是,你不用必需实现ABCI接口。Cosmos SDK以[baseapp](./sdk-design.md#baseapp)的形式提供了样板实现。 +获知更多关于ABCI的详细内容可以访问[Tendermint docs](https://tendermint.com/docs/spec/abci/abci.html#overview). -### 接下来,让我们学习[SDK的高级设计原则](./sdk-design.md) \ No newline at end of file +基于Tendermint构建的任何程序都需要实现ABCI接口,以便和底层的本地Tendermint引擎通信。幸运的是,您不需要实现ABCI接口,Cosmos SDK 以 [baseapp](https://docs.cosmos.network/master/intro/sdk-design.html#baseapp) 的形式提供了样板实现。 \ No newline at end of file diff --git a/docs/cn/intro/sdk-design.md b/docs/cn/intro/sdk-design.md index 353382fdc256..37820d6d79ee 100644 --- a/docs/cn/intro/sdk-design.md +++ b/docs/cn/intro/sdk-design.md @@ -1,48 +1,74 @@ -# Cosmos SDK 设计概览 +# Cosmos SDK的主要组件 -Cosmos SDK是一个方便开发者开发基于Tendermint的安全可靠状态机的一套框架。其核心是Golang版的ABCI的实现。它附带一个`multistore`来持久化存储数据还有一个`router`来处理交易。 +Cosmos SDK 是一个框架,可以促进基于Tendermint的安全状态机的开发。SDK的核心是一个基于Golang的[ABCI](https://docs.cosmos.network/master/intro/sdk-app-architecture.html#abci)样板实现。它带有一个用于存储数据的[`multistore`](https://docs.cosmos.network/master/core/store.html#multistore),和一个用于处理Transaction的[`router`](https://docs.cosmos.network/master/core/baseapp.html#routing)。 -下面一个简单的视图展示了当从Tendermint的`DeliverTx`请求(`CheckTx`的处理流程与其相同,除了不会执行状态的改变)中接收到一笔交易时,基于Cosmos SDK构建的应用程序是如何处理交易的: +下面的简化视图展示了当通过`DeliverTx`从Tendermint 转移transactions时,基于Cosmos SDK构建的应用程序如何处理这些transactions。 -1. 解码从Tendermint共识引擎接收到的交易(记住Tendermint只处理`[]bytes`) -2. 从交易中提取消息并进行基本的合理性检查。 -3. 将每条消息路由至对应的模块进行处理。 -4. 提交状态变更。 +- 解码从Tendermint共识引擎中接收到的`transactions`(Tendermint只能处理 `[]bytes` 类型的数据) -应用同样可以生成交易,进行编码并传递给底层的Tendermint来进行广播 +- 从`transactions`中提取`messages`并进行基本的健全性检查。 -## `baseapp` +- 将每个Message路由到对应的模块中,以进行相应处理。 -`baseApp` 是Cosmos SDK的ABCI的实现样板。里面的 `router` 用来把交易路由到对应的模块。我们应用程序的主体文件`app.go` 将自定义`app`类型,它将嵌入`baseapp`。这样,自定义的`app`类型将自动继承`baseapp`的所有方法。阅览[SDK应用教程](https://github.com/cosmos/sdk-application-tutorial/blob/master/app.go#L27)代码示例。 +- 提交状态更改。 -`baseapp`的目的是在存储和可扩展状态机的之间提供安全接口,同时尽可能少地定义该状态机(保持对ABCI的真实性)。 +## BaseApp -有关`baseapp`的更多信息,请点击[这里](../concepts/baseapp.md)。 +`baseapp` 是 Cosmos SDK 应用程序的样本实现,它拥有能够处理和底层共识引擎的连接的ABCI实现。通常,Cosmos SDK 应用程序通过嵌入[`app.go`](https://docs.cosmos.network/master/basics/app-anatomy.html#core-application-file)来实现拓展。查看示例请参考SDK应用教程: + +```go +type nameServiceApp struct { + *bam.BaseApp + cdc *codec.Codec + + // keys to access the substores + keys map[string]*sdk.KVStoreKey + tkeys map[string]*sdk.TransientStoreKey + + // Keepers + accountKeeper auth.AccountKeeper + bankKeeper bank.Keeper + stakingKeeper staking.Keeper + slashingKeeper slashing.Keeper + distrKeeper distr.Keeper + supplyKeeper supply.Keeper + paramsKeeper params.Keeper + nsKeeper nameservice.Keeper + + // Module Manager + mm *module.Manager +} +``` + +`baseapp` 的目标是在存储和可拓展状态机之间提供安全的接口,同时尽可能少地定义状态机(对ABCI保持不变)。 + +更多关于`baseapp`的信息,请点击[这里](https://docs.cosmos.network/master/core/baseapp.html)。 ## Multistore -Cosmos SDK 为状态持久化提供了 multistore 。multistore 允许开发者声明任意数量的[`KVStores`](https://github.com/blocklayerhq/chainkit)。`KVStores`只接受`[]byte`类型作为值,因此任何自定义的类型都需要在存储之前使用[go-amino](https://github.com/tendermint/go-amino)进行编码。 +Cosmos SDK 为状态持久化提供了`multistore`。Multistore允许开发者声明任意数量的`KVStores`。这些`KVStores`只接受`[]byte`类型的值,因此任何自定义的结构都需要在存储之前使用[codec](https://docs.cosmos.network/master/core/encoding.html)进行编码。 -multistore 抽象用于区分不同的模块的状态,每个都由其自身模块管理。要了解更多关于 multistore 的信息,点击[这里](../concepts/store.md) +Multistore抽象用于区分不同模块的状态,每个都由其自己的模块管理。更多关于multistore的信息请点击[这里](https://docs.cosmos.network/master/core/store.html#multistore)。 ## Modules -Cosmos SDK 的强大之处在于其模块化开发的理念。应用程序通过把一组可以互相操作的模块组合起来进行构建。每个模块定义状态子集,并包含其自己的消息/交易处理器,而SDK负责将每条消息路由到其各自归属的模块。 +Cosmos SDK的强大之处在于其模块化开发的理念。SDK应用程序是通过组合一系列可互操作的模块而构建的。每个模块定义了状态子集,并包含其Messages与Transactions的处理器,同时SDK负责将每个Message路由到对应的模块中。 -下面是一个简化视图, 旨在说明每个应用链的全节点是如何处理接收的有效块中交易的: +以下的简化视图展示了应用链中的每个全节点如何处理有效区块中的Transaction。 ``` + | - | 交易通过全节点的 Tendermint 引擎的DeliverTx - | 传递到应用层 + | Transaction relayed from the full-node's Tendermint engine + | to the node's application via DeliverTx + | | | +---------------------v--------------------------+ - | 应用(层) | + | APPLICATION | | | - | 用 baseapp 的方法: 解码 Tx, | - | 提取及路由消息 | + | Using baseapp's methods: Decode the Tx, | + | extract and route the message(s) | | | +---------------------+--------------------------+ | @@ -52,15 +78,16 @@ Cosmos SDK 的强大之处在于其模块化开发的理念。应用程序通过 | | | - | 消息传给相应的模块处理 + | Message routed to the correct + | module to be processed | | +----------------+ +---------------+ +----------------+ +------v----------+ | | | | | | | | | AUTH MODULE | | BANK MODULE | | STAKING MODULE | | GOV MODULE | | | | | | | | | -| | | | | | | 处理消息, 更改状态 | -| | | | | | | | +| | | | | | | Handles message,| +| | | | | | | Updates state | | | | | | | | | +----------------+ +---------------+ +----------------+ +------+----------+ | @@ -69,18 +96,19 @@ Cosmos SDK 的强大之处在于其模块化开发的理念。应用程序通过 | +--------------------------+ | - | 返回结果到 Tendermint + | Return result to Tendermint | (0=Ok, 1=Err) v ``` -每个模块都可以看做一个小型的状态机。开发人员需要定义模块所处理的状态的子集,以及修改状态的message自定义类型(*注意* : message 是由 `baseapp` 的方法从交易中提取的)。通常,每个模块在 multistore 声明它自己的`KVStore` 来持久化保存它所定义的状态子集。大多数开发者在构建自己的模块时也需要访问其他的第三方模块。鉴于Cosmos-SDK是一个开源的框架,一些模块可能是恶意的,这就意味着需要安全原则来合理化模块之间的交互。这些原则基于[object-capabilities](./ocap.md)。实际上,这意味着不是让每个模块保留其他模块的访问控制列表,而是每个模块都实现称作`keeper`的特殊对象,这些对象可以传递给其他模块并授予预先定义的一组能力。 +每个模块都可以看成是一个小的状态机。开发者需要定义由模块处理的状态子集,同时自定义改变状态的Message类型(注意:`messages`是通过`baseapp`从`transactions`中提取的)。通常,每个模块会在`multistore`中声明自己的`KVStore`,以存储自定义的状态子集。大部分开发者在构建自己的模块时,需要访问其它第三方模块。由于Cosmos SDK是一个开放的框架,其中的一些模块可能是恶意的,这意味着需要一套安全原则去考虑模块间的交互。这些原则都基于[object-capabilities](https://docs.cosmos.network/master/core/ocap.html)。事实上,这也意味着,并不是要让每个模块都保留其他模块的访问控制列表,而是每个模块都实现了被称为`keepers`的特殊对象,它们可以被传递给其他模块,以授予一组预定义的功能。 + +SDK模块被定义在SDK的 `x/`文件夹中,一些核心的模块包括: + +- `x/auth`:用于管理账户和签名。 -SDK模块在SDK的`x/`目录下定义。一些核心模块包括: -+ `x/auth`: 用于管理账户和签名. -+ `x/bank`: 用于实现token和token转账. -+ `x/staking` + `x/slashing`: 用于构建POS区块链. +- `x/bank`:用于启动 tokens 和 token 转账。 -除了`x/`中已有的模块,任何人都可以在他们的应用程序中使用它们自己定义的模块。你可以查看[示例教程](https://learnblockchain.cn/docs/cosmos/tutorial/04-keeper.html)。 +- `x/staking` + `s/slashing`:用于构建POS区块链。 -### 接下来 学习 Cosmos SDK 安全模型,[ocap](./ocap.md) +除了`x/`文件夹中已经存在的任何人都可以使用的模块,SDK还允许您构建自己自定义的模块,您可以在[教程中查看示例](https://cosmos.network/docs/tutorial/keeper.html)。 \ No newline at end of file diff --git a/docs/cn/intro/why-app-specific.md b/docs/cn/intro/why-app-specific.md new file mode 100644 index 000000000000..e156c779bb73 --- /dev/null +++ b/docs/cn/intro/why-app-specific.md @@ -0,0 +1,87 @@ +# 特定应用区块链 + +## 概要 + +本文档解释了什么是特定应用区块链,以及为什么开发者更希望构建特定应用区块链,而不是开发智能合约。 + +## 什么是特定应用区块链? + +特定应用区块链是面向单个具体应用程序的高度定制化区块链。与基于像以太坊这样的底层区块链搭建去中心化应用不同,开发者需要从头构建他们自己的区块链。这意味着构建全节点客户端、轻节点客户端和所有必要的接口(CLI, REST, 等等)来和节点交互。 + +``` + ^ +-------------------------------+ ^ + | | | | Built with Cosmos SDK + | | State-machine = Application | | + | | | v + | +-------------------------------+ + | | | ^ +Blockchain node | | Consensus | | + | | | | + | +-------------------------------+ | Tendermint Core + | | | | + | | Networking | | + | | | | + v +-------------------------------+ v +``` + + + +## 智能合约的局限是什么? + +早在2014年,像Ethereum这样的虚拟机区块链就满足了可编程性的需求。当时,开发去中心化应用的选项非常有限。许多开发者只能在复杂且有限制的比特币脚本语言上开发,或者fork难以运行和定制化的比特币代码。 + +虚拟机区块链在当时提出了新的价值主张。他们的状态机集成了虚拟机,从而能够执行被称为智能合约的图灵完备程序。虽然智能合约在一次性事件(如ICO)的应用场景下非常有用,但在构建复杂的去中心化平台时无法达到要求。以下是原因: + +智能合约通常由可以被底层虚拟机解释的特定编程语言开发。这些编程语言常常并不成熟,并受限于虚拟机本身。例如,以太坊虚拟机并不允许开发者实现代码的自动执行。开发或者也被限制于EVM的账户体系,他们只能从一组有限的功能中进行加密操作。虽然这些只是示例,但它们展现了智能合约环境通常缺少灵活性。 + +智能合约都运行在同一台虚拟机上,这意味着它们会相互争夺资源,并严重影响执行效果。即使状态机分分成多个子集(例如通过分片技术),智能合约依然需要由虚拟机解释,比起在状态机上实现的本地应用程序,这依然限制了合约应用的性能。( 我们的基准测试表明,在删除虚拟机后,应用程序的性能提高了10倍。) + +智能合约共享底层环境带来的另一个问题是主导权的最终限制。去中心化应用是一个涉及众多参与者的生态系统,如果去中心化应用建立在通用的虚拟机区块链上,利益相关者(stakeholders)对他们的应用程序就只有非常有限的主导权,并最终会被底层区块链的治理所取代。如果该应用程序还存在着漏洞,那任何人都无能为力。 + +特定应用区块链的出现,就是要解决上述问题。 + +## 特定应用区块链的优势 + +### 灵活性 + +特定应用区块链赋予了开发者最大的灵活性: + +- 在Cosmos区块链中,状态机通常通过被称为[ABCI](https://tendermint.com/docs/spec/abci/)的接口和底层共识引擎连接。该接口可以被包装为任何编程语言,开发者可以自己决定用哪种编程语言来构建状态机。 + +- 开发者在构建状态机时有多种选择,目前最常用的是Cosmos SDK,但也有其他的框架,如Lotion和Weave等。开发者通常都是基于他们使用的编程语言来选择使用哪一种框架(Cosmos SDK和Weave基于Golang,Lotion则基于JavaScript)。 + +- ABCI允许开发者更换特定应用链的共识引擎。目前只有Tendermint共识可以投入使用,但在未来还会有更多共识引擎可被使用。 + +- 即使已经选好了开发框架和共识引擎,但如果他们不能完全符合原始格式的要求,开发者依然可以对其进行调整。 + +- 开发者可以自由探索出最能满足实际需求的方案(如验证人数量 vs Transaction吞吐量;安全性 vs 异步可用性等)和链的设计选项(如DB存储或IAVL树;UTXO或账户模型,等)。 + +- 开发者可以实现代码的自动执行。在Cosmos SDK 中,每个块的开头和结尾都可以自动触发逻辑。与虚拟机区块链环境下的合约开发者不同,特定应用区块链的开发者可以自由地选择应用程序所需要的加密库,而不会受到底层环境的功能限制。 + +上述的列表展示了特定应用区块链给予开发者的充分灵活性。Cosmos 和 Cosmos SDK 的目标是让开发者工具尽可能的通用化、模块化,从而在保持兼容的情况下对堆栈的每个部分进行分叉、调整和优化。随着社区的不断发展,每个核心构建模块都将有更多可替代方案,为开发者提供更多选项。 + +### 性能 + +基于智能合约的去中心化应用在性能方面会天然地受到底层环境的限制。如果一个去中心化应用要进行性能优化,就需要将其构建为特定应用区块链。以下是特定应用区块链在性能方面的优势: + +- 特定应用区块链开发者可以选择像 Tendermint BFT 这样的新型共识引擎。与目前被大多数虚拟机区块链使用的POW共识相比,Tendermint BFT 在吞吐量方面有显著提高。 + +- 一个特定应用区块链只运行单个应用程序,所以该应用程序不需要和其他程序去竞争计算资源和存储资源。这与目前所有非分片虚拟机区块链正好相反,在这些区块链中的智能合约都会争夺计算和存储资源。 + +- 即使某种虚拟机区块链能够提供基于应用程序的分片和高效的共识算法,其性能也依然会被虚拟机本身所限制。真正的吞吐量瓶颈在于状态机,要求Transaction由虚拟机解释会大大增加处理它们的计算复杂度。 + +###安全性 + +安全性很难进行量化,而且不同区块链平台之间存在很大差异。以下是特定应用区块链所能带来的重要优势: + +- 与不成熟的智能合约编程语言相反,开发者可以在构建特定应用区块链时选择像Golang这种可靠性已被验证的编程语言。 + +- 开发者不会局限于底层虚拟机所提供的加密功能,他们可以使用自定义的加密技术,也可以依赖经过可靠审核的加密库。 + +- 开发者无需担心底层虚拟机中潜在的漏洞或可被利用的机制,从而可以更容易地确保应用程序的安全性。 + +### 主导权 + +特定应用区块链的一大好处是主导权。去中心化应用是一个涉及众多参与者的生态系统,如用户、开发者、第三方服务,等等。当开发者在多个去中心化应用共存的虚拟机区块链上开发应用程序时,出现的一个问题是围绕应用程序所组成的社区人群和底层链的社区人群并不是一样的,但后者却会在治理的过程中取代前者。如果应用程序中存在一个漏洞,或者需要上线新的功能,应用的stakeholders几乎没有任何办法升级代码。如果底层区块链社区拒绝执行,那应用程序就无法升级。 + +根本问题是应用程序的治理和网络治理并不是统一的,而这个问题可以通过特定应用区块链解决。因为特定应用区块链只专门运行单个应用程序,所以应用的stakeholders对整条链有完全的主导权。这能确保社区在漏洞被发现时不会卡住,而且有充分的自由去选择链和应用程序的演化方向。 \ No newline at end of file From f7c0578fea8f41019221ea622b5bba1a8cc89825 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Wed, 1 Apr 2020 16:46:47 +0200 Subject: [PATCH 509/529] crypto/keyring: drop password from keyWriter internal interface (#5899) Add an extra test case to increase coverage. --- crypto/keyring/base_keybase.go | 4 ++-- crypto/keyring/keyring.go | 4 ++-- crypto/keyring/keyring_test.go | 9 +++++++++ 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/crypto/keyring/base_keybase.go b/crypto/keyring/base_keybase.go index abec03359a86..039b09e8ff14 100644 --- a/crypto/keyring/base_keybase.go +++ b/crypto/keyring/base_keybase.go @@ -25,7 +25,7 @@ type ( } writeLocalKeyer interface { - writeLocalKey(name string, priv tmcrypto.PrivKey, passphrase string, algo SigningAlgo) Info + writeLocalKey(name string, priv tmcrypto.PrivKey, algo SigningAlgo) Info } infoWriter interface { @@ -87,7 +87,7 @@ func (kb baseKeybase) CreateAccount( var info Info if encryptPasswd != "" { - info = keyWriter.writeLocalKey(name, privKey, encryptPasswd, algo) + info = keyWriter.writeLocalKey(name, privKey, algo) } else { info = kb.writeOfflineKey(keyWriter, name, privKey.PubKey(), algo) } diff --git a/crypto/keyring/keyring.go b/crypto/keyring/keyring.go index a5b62ba3eef2..3f77ce4bb30f 100644 --- a/crypto/keyring/keyring.go +++ b/crypto/keyring/keyring.go @@ -364,7 +364,7 @@ func (kb keyringKeybase) ImportPrivKey(name, armor, passphrase string) error { } // NOTE: The keyring keystore has no need for a passphrase. - kb.writeLocalKey(name, privKey, "", SigningAlgo(algo)) + kb.writeLocalKey(name, privKey, SigningAlgo(algo)) return nil } @@ -435,7 +435,7 @@ func (kb keyringKeybase) SupportedAlgosLedger() []SigningAlgo { return kb.base.SupportedAlgosLedger() } -func (kb keyringKeybase) writeLocalKey(name string, priv tmcrypto.PrivKey, _ string, algo SigningAlgo) Info { +func (kb keyringKeybase) writeLocalKey(name string, priv tmcrypto.PrivKey, algo SigningAlgo) Info { // encrypt private key using keyring pub := priv.PubKey() info := newLocalInfo(name, pub, string(priv.Bytes()), algo) diff --git a/crypto/keyring/keyring_test.go b/crypto/keyring/keyring_test.go index e994f91db0b3..83cd5a409d3e 100644 --- a/crypto/keyring/keyring_test.go +++ b/crypto/keyring/keyring_test.go @@ -2,6 +2,7 @@ package keyring import ( "bytes" + "errors" "fmt" "strings" "testing" @@ -432,6 +433,14 @@ func TestSupportedAlgos(t *testing.T) { require.Equal(t, []SigningAlgo{"secp256k1"}, kb.SupportedAlgosLedger()) } +func TestCustomDerivFuncKey(t *testing.T) { + kb := NewInMemory(WithDeriveFunc(func(mnemonic string, bip39Passphrase, hdPath string, algo SigningAlgo) ([]byte, error) { + return nil, errors.New("cannot derive keys") + })) + _, _, err := kb.CreateMnemonic("test", English, "", "") + require.Error(t, err, "cannot derive keys") +} + func TestInMemoryLanguage(t *testing.T) { kb := NewInMemory() _, _, err := kb.CreateMnemonic("something", Japanese, "no_pass", Secp256k1) From cc2a79ce12dfbb5c4a419051bc31e197a5454958 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Thu, 2 Apr 2020 15:23:45 +0200 Subject: [PATCH 510/529] x/staking: fix REST calls panic on some method call (#5906) Improve message validation to prevent REST handlers from panicking. --- CHANGELOG.md | 2 ++ x/staking/types/msg.go | 8 ++++---- x/staking/types/msg_test.go | 17 +++++++++++------ 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 19203677ad69..2bcbedca0ae0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -96,6 +96,8 @@ to now accept a `codec.JSONMarshaler` for modular serialization of genesis state when method receivers are offline/multisig keys. * (x/auth) [\#5892](https://github.com/cosmos/cosmos-sdk/pull/5892) Add `RegisterKeyTypeCodec` to register new types (eg. keys) to the `auth` module internal amino codec. +* (rest) [\#5906](https://github.com/cosmos/cosmos-sdk/pull/5906) Fix an issue that make some REST calls panic when sending +invalid or incomplete requests. ### State Machine Breaking diff --git a/x/staking/types/msg.go b/x/staking/types/msg.go index 18e0bac2dc13..f7fc713c9e4a 100644 --- a/x/staking/types/msg.go +++ b/x/staking/types/msg.go @@ -81,7 +81,7 @@ func (msg MsgCreateValidator) ValidateBasic() error { if msg.Pubkey == "" { return ErrEmptyValidatorPubKey } - if !msg.Value.Amount.IsPositive() { + if !msg.Value.IsValid() || !msg.Value.Amount.IsPositive() { return ErrBadDelegationAmount } if msg.Description == (Description{}) { @@ -184,7 +184,7 @@ func (msg MsgDelegate) ValidateBasic() error { if msg.ValidatorAddress.Empty() { return ErrEmptyValidatorAddr } - if !msg.Amount.Amount.IsPositive() { + if !msg.Amount.IsValid() || !msg.Amount.Amount.IsPositive() { return ErrBadDelegationAmount } return nil @@ -230,7 +230,7 @@ func (msg MsgBeginRedelegate) ValidateBasic() error { if msg.ValidatorDstAddress.Empty() { return ErrEmptyValidatorAddr } - if !msg.Amount.Amount.IsPositive() { + if !msg.Amount.IsValid() || !msg.Amount.Amount.IsPositive() { return ErrBadSharesAmount } return nil @@ -268,7 +268,7 @@ func (msg MsgUndelegate) ValidateBasic() error { if msg.ValidatorAddress.Empty() { return ErrEmptyValidatorAddr } - if !msg.Amount.Amount.IsPositive() { + if !msg.Amount.IsValid() || !msg.Amount.Amount.IsPositive() { return ErrBadSharesAmount } return nil diff --git a/x/staking/types/msg_test.go b/x/staking/types/msg_test.go index 99866b11ca65..127e80549ba8 100644 --- a/x/staking/types/msg_test.go +++ b/x/staking/types/msg_test.go @@ -34,6 +34,7 @@ func TestMsgCreateValidator(t *testing.T) { {"empty address", "a", "b", "c", "d", "e", commission2, sdk.OneInt(), emptyAddr, pk1, coinPos, false}, {"empty pubkey", "a", "b", "c", "d", "e", commission1, sdk.OneInt(), valAddr1, emptyPubkey, coinPos, false}, {"empty bond", "a", "b", "c", "d", "e", commission2, sdk.OneInt(), valAddr1, pk1, coinZero, false}, + {"nil bond", "a", "b", "c", "d", "e", commission2, sdk.OneInt(), valAddr1, pk1, sdk.Coin{}, false}, {"zero min self delegation", "a", "b", "c", "d", "e", commission1, sdk.ZeroInt(), valAddr1, pk1, coinPos, false}, {"negative min self delegation", "a", "b", "c", "d", "e", commission1, sdk.NewInt(-1), valAddr1, pk1, coinPos, false}, {"delegation less than min self delegation", "a", "b", "c", "d", "e", commission1, coinPos.Amount.Add(sdk.OneInt()), valAddr1, pk1, coinPos, false}, @@ -56,19 +57,20 @@ func TestMsgEditValidator(t *testing.T) { name, moniker, identity, website, securityContact, details string validatorAddr sdk.ValAddress expectPass bool + minSelfDelegation sdk.Int }{ - {"basic good", "a", "b", "c", "d", "e", valAddr1, true}, - {"partial description", "", "", "c", "", "", valAddr1, true}, - {"empty description", "", "", "", "", "", valAddr1, false}, - {"empty address", "a", "b", "c", "d", "e", emptyAddr, false}, + {"basic good", "a", "b", "c", "d", "e", valAddr1, true, sdk.OneInt()}, + {"partial description", "", "", "c", "", "", valAddr1, true, sdk.OneInt()}, + {"empty description", "", "", "", "", "", valAddr1, false, sdk.OneInt()}, + {"empty address", "a", "b", "c", "d", "e", emptyAddr, false, sdk.OneInt()}, + {"nil int", "a", "b", "c", "d", "e", emptyAddr, false, sdk.Int{}}, } for _, tc := range tests { description := NewDescription(tc.moniker, tc.identity, tc.website, tc.securityContact, tc.details) newRate := sdk.ZeroDec() - newMinSelfDelegation := sdk.OneInt() - msg := NewMsgEditValidator(tc.validatorAddr, description, &newRate, &newMinSelfDelegation) + msg := NewMsgEditValidator(tc.validatorAddr, description, &newRate, &tc.minSelfDelegation) if tc.expectPass { require.Nil(t, msg.ValidateBasic(), "test: %v", tc.name) } else { @@ -91,6 +93,7 @@ func TestMsgDelegate(t *testing.T) { {"empty delegator", sdk.AccAddress(emptyAddr), valAddr1, coinPos, false}, {"empty validator", sdk.AccAddress(valAddr1), emptyAddr, coinPos, false}, {"empty bond", sdk.AccAddress(valAddr1), valAddr2, coinZero, false}, + {"nil bold", sdk.AccAddress(valAddr1), valAddr2, sdk.Coin{}, false}, } for _, tc := range tests { @@ -115,6 +118,7 @@ func TestMsgBeginRedelegate(t *testing.T) { }{ {"regular", sdk.AccAddress(valAddr1), valAddr2, valAddr3, sdk.NewInt64Coin(sdk.DefaultBondDenom, 1), true}, {"zero amount", sdk.AccAddress(valAddr1), valAddr2, valAddr3, sdk.NewInt64Coin(sdk.DefaultBondDenom, 0), false}, + {"nil amount", sdk.AccAddress(valAddr1), valAddr2, valAddr3, sdk.Coin{}, false}, {"empty delegator", sdk.AccAddress(emptyAddr), valAddr1, valAddr3, sdk.NewInt64Coin(sdk.DefaultBondDenom, 1), false}, {"empty source validator", sdk.AccAddress(valAddr1), emptyAddr, valAddr3, sdk.NewInt64Coin(sdk.DefaultBondDenom, 1), false}, {"empty destination validator", sdk.AccAddress(valAddr1), valAddr2, emptyAddr, sdk.NewInt64Coin(sdk.DefaultBondDenom, 1), false}, @@ -141,6 +145,7 @@ func TestMsgUndelegate(t *testing.T) { }{ {"regular", sdk.AccAddress(valAddr1), valAddr2, sdk.NewInt64Coin(sdk.DefaultBondDenom, 1), true}, {"zero amount", sdk.AccAddress(valAddr1), valAddr2, sdk.NewInt64Coin(sdk.DefaultBondDenom, 0), false}, + {"nil amount", sdk.AccAddress(valAddr1), valAddr2, sdk.Coin{}, false}, {"empty delegator", sdk.AccAddress(emptyAddr), valAddr1, sdk.NewInt64Coin(sdk.DefaultBondDenom, 1), false}, {"empty validator", sdk.AccAddress(valAddr1), emptyAddr, sdk.NewInt64Coin(sdk.DefaultBondDenom, 1), false}, } From e8a82f78caa140a8baa0d27f22ac3d47fc81ab14 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Thu, 2 Apr 2020 12:07:34 -0400 Subject: [PATCH 511/529] Merge PR #5894: ADR 021 - Protocol Buffer Query Support --- docs/architecture/README.md | 1 + .../adr-021-protobuf-query-encoding.md | 258 ++++++++++++++++++ 2 files changed, 259 insertions(+) create mode 100644 docs/architecture/adr-021-protobuf-query-encoding.md diff --git a/docs/architecture/README.md b/docs/architecture/README.md index c7310d73982b..a6a92e652c06 100644 --- a/docs/architecture/README.md +++ b/docs/architecture/README.md @@ -46,3 +46,4 @@ Please add a entry below in your Pull Request for an ADR. - [ADR 018: Extendable Voting Periods](./adr-018-extendable-voting-period.md) - [ADR 019: Protocol Buffer State Encoding](./adr-019-protobuf-state-encoding.md) - [ADR 020: Protocol Buffer Transaction Encoding](./adr-020-protobuf-transaction-encoding.md) +- [ADR 021: Protocol Buffer Query Encoding](./adr-021-protobuf-query-encoding.md) diff --git a/docs/architecture/adr-021-protobuf-query-encoding.md b/docs/architecture/adr-021-protobuf-query-encoding.md new file mode 100644 index 000000000000..198432e94baf --- /dev/null +++ b/docs/architecture/adr-021-protobuf-query-encoding.md @@ -0,0 +1,258 @@ +# ADR 021: Protocol Buffer Query Encoding + +## Changelog + +- 2020 March 27: Initial Draft + +## Status + +Proposed + +## Context + +This ADR is a continuation of the motivation, design, and context established in +[ADR 019](./adr-019-protobuf-state-encoding.md) and +[ARD 020](./adr-019-protobuf-transaction-encoding.md), namely, we aim to design the +Protocol Buffer migration path for the client-side of the Cosmos SDK. + +This ADR continues from [ARD 020](./adr-020-protobuf-transaction-encoding.md) +to specify the encoding of queries. + +## Decision + +### Custom Query Definition + +Modules define custom queries through a protocol buffers `service` definition. +These `service` definitions are generally associated with and used by the +GRPC protocol. However, the protocol buffers specification indicates that +they can be used more generically by any request/response protocol that uses +protocol buffer encoding. Thus, we can use `service` definitions for specifying +custom ABCI queries and even reuse a substantial amount of the GRPC infrastructure. + +Each module with custom queries should define a service canonically named `Query`: + +```proto +// x/bank/types/types.proto + +service Query { + rpc QueryBalance(QueryBalanceParams) returns (cosmos_sdk.v1.Coin) { } + rpc QueryAllBalances(QueryAllBalancesParams) returns (QueryAllBalancesResponse) { } +} +``` + +#### Handling of Interface Types + +Modules that use interface types and need true polymorphism generally force a +`oneof` up to the app-level that provides the set of concrete implementations of +that interface that the app supports. While app's are welcome to do the same for +queries and implement an app-level query service, it is recommended that modules +provide query methods that expose these interfaces via `google.protobuf.Any`. +There is a concern on the transaction level that the overhead of `Any` is too +high to justify its usage. However for queries this is not a concern, and +providing generic module-level queries that use `Any` does not preclude apps +from also providing app-level queries that return use the app-level `oneof`s. + + +A hypothetical example for the `gov` module would look something like: + +```proto +// x/gov/types/types.proto + +import "google/protobuf/any.proto"; + +service Query { + rpc GetProposal(GetProposalParams) returns (AnyProposal) { } +} + +message AnyProposal { + ProposalBase base = 1; + google.protobuf.Any content = 2; +} +``` + +### Custom Query Implementation + +In order to implement the query service, we can reuse the existing [gogo protobuf](https://github.com/gogo/protobuf) +grpc plugin, which for a service named `Query` generates an interface named +`QueryServer` as below: + +```go +type QueryServer interface { + QueryBalance(context.Context, *QueryBalanceParams) (*types.Coin, error) + QueryAllBalances(context.Context, *QueryAllBalancesParams) (*QueryAllBalancesResponse, error) +} +``` + +The custom queries for our module are implemented by implementing this interface. + +The first parameter in this generated interface is a generic `context.Context`, +whereas querier methods generally need an instance of `sdk.Context` to read +from the store. Since arbitrary values can be attached to `context.Context` +using the `WithValue` and `Value` methods, the SDK should provide a function +`sdk.UnwrapSDKContext` to retrieve the `sdk.Context` from the provided +`context.Context`. + +An example implementation of `QueryBalance` for the bank module as above would +look something like: + +```go +type Querier struct { + Keeper +} + +func (q Querier) QueryBalance(ctx context.Context, params *types.QueryBalanceParams) (*sdk.Coin, error) { + balance := q.GetBalance(sdk.UnwrapSDKContext(ctx), params.Address, params.Denom) + return &balance, nil +} +``` + +### Custom Query Registration and Routing + +Query server implementations as above would be registered with `AppModule`s using +a new method `RegisterQueryServer(grpc.Server)` which could be implemented simply +as below: + +```go +// x/bank/module.go +func (am AppModule) RegisterQueryServer(server grpc.Server) { + types.RegisterQueryServer(server, keeper.Querier{am.keeper}) +} +``` + +Underneath the hood, a new method `RegisterService(sd *grpc.ServiceDesc, handler interface{})` +will be added to the existing `baseapp.QueryRouter` to add the queries to the custom +query routing table (with the routing method being described below). +The signature for this method matches the existing +`RegisterServer` method on the GRPC `Server` type where `handler` is the custom +query server implementation described above. + + +GRPC-like requests are routed by the service name (ex. `cosmos_sdk.x.bank.v1.Query`) +and method name (ex. `QueryBalance`) combined with `/`s to form a full +method name (ex. `/cosmos_sdk.x.bank.v1.Query/QueryBalance`). This gets translated +into an ABCI query as `custom/cosmos_sdk.x.bank.v1.Query/QueryBalance`. Service handlers +registered with `QueryRouter.RegisterService` will be routed this way. + +Beyond the method name, GRPC requests carry a protobuf encoded payload, which maps naturally +to `RequestQuery.Data`, and receive a protobuf encoded response or error. Thus +there is a quite natural mapping of GRPC-like rpc methods to the existing +`sdk.Query` and `QueryRouter` infrastructure. + +This basic specification allows us to reuse protocol buffer `service` definitions +for ABCI custom queries substantially reducing the need for manual decoding and +encoding in query methods. + +### GRPC Protocol Support + +In addition to providing an ABCI query pathway, we can easily provide a GRPC +proxy server that routes requests in the GRPC protocol to ABCI query requests +under the hood. In this way, clients could use their host languages' existing +GRPC implementations to make direct queries against Cosmos SDK app's using +these `service` definitions. In order for this server to work, the `QueryRouter` +on `BaseApp` will need to expose the service handlers registered with +`QueryRouter.RegisterService` to the proxy server implementation. Nodes could +launch the proxy server on a separate port in the same process as the ABCI app +with a command-line flag. + +### REST Queries and Swagger Generation + +[grpc-gateway](https://github.com/grpc-ecosystem/grpc-gateway) is a project that +translates REST calls into GRPC calls using special annotations on service +methods. Modules that want to expose REST queries should add `google.api.http` +annotations to their `rpc` methods as in this example below. + +```proto +// x/bank/types/types.proto + +service Query { + rpc QueryBalance(QueryBalanceParams) returns (cosmos_sdk.v1.Coin) { + option (google.api.http) = { + get: "/x/bank/v1/balance/{address}/{denom}" + }; + } + rpc QueryAllBalances(QueryAllBalancesParams) returns (QueryAllBalancesResponse) { + option (google.api.http) = { + get: "/x/bank/v1/balances/{address}" + }; + } +} +``` + +grpc-gateway will work direcly against the GRPC proxy described above which will +translate requests to ABCI queries under the hood. grpc-gateway can also +generate Swagger definitions automatically. + +In the current implementation of REST queries, each module needs to implement +REST queries manually in addition to ABCI querier methods. Using the grpc-gateway +approach, there will be no need to generate separate REST query handlers, just +query servers as described above as grpc-gateway handles the translation of protobuf +to REST as well as Swagger definitions. + +The SDK should provide CLI commands for apps to start GRPC gateway either in +a separate process or the same process as the ABCI app, as well as provide a +command for generating grpc-gateway proxy `.proto` files and the `swagger.json` +file. + +### Client Usage + +The gogo protobuf grpc plugin generates client interfaces in addition to server +interfaces. For the `Query` service defined above we would get a `QueryClient` +interface like: + +```go +type QueryClient interface { + QueryBalance(ctx context.Context, in *QueryBalanceParams, opts ...grpc.CallOption) (*types.Coin, error) + QueryAllBalances(ctx context.Context, in *QueryAllBalancesParams, opts ...grpc.CallOption) (*QueryAllBalancesResponse, error) +} +``` + +Via a small patch to gogo protobuf ([gogo/protobuf#675](https://github.com/gogo/protobuf/pull/675)) +we have tweaked the grpc codegen to use an interface rather than concrete type +for the generated client struct. This allows us to also reuse the GRPC infrastructure +for ABCI client queries. + +`CLIContext` will receive a new method `QueryConn` that returns a `ClientConn` +that routes calls to ABCI queries + +Clients (such as CLI methods) will then be able to call query methods like this: + +```go +cliCtx := context.NewCLIContext() +queryClient := types.NewQueryClient(cliCtx.QueryConn()) +params := &types.QueryBalanceParams{addr, denom} +result, err := queryClient.QueryBalance(gocontext.Background(), params) +``` + +### Testing + +Tests would be able to create a query client directly from keeper and `sdk.Context` +references using a `QueryServerTestHelper` as below: + +```go +queryHelper := baseapp.NewQueryServerTestHelper(ctx) +types.RegisterQueryServer(queryHelper, keeper.Querier{app.BankKeeper}) +queryClient := types.NewQueryClient(queryHelper) +``` + +## Future Improvements + +## Consequences + +### Positive + +* greatly simplified querier implementation (no manual encoding/decoding) +* easy query client generation (can use existing grpc and swagger tools) +* no need for REST query implementations +* type safe query methods (generated via grpc plugin) +* going forward, there will be less breakage of query methods because of the +backwards compatibility guarantees provided by buf + +### Negative + +* all clients using the existing ABCI/REST queries will need to be refactored +for both the new GRPC/REST query paths as well as protobuf/proto-json encoded +data, but this is more or less unavoidable in the protobuf refactoring + +### Neutral + +## References From e0c1774e202e080e34c161bfe5fe6a8cc5219fef Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Thu, 2 Apr 2020 15:07:47 -0400 Subject: [PATCH 512/529] Merge PR #5916: Migrate x/crisis tx command --- x/bank/client/cli/tx.go | 5 +--- x/crisis/client/cli/tx.go | 62 +++++++++++++++++++++++++++++++++------ 2 files changed, 54 insertions(+), 13 deletions(-) diff --git a/x/bank/client/cli/tx.go b/x/bank/client/cli/tx.go index 3925da637954..8a46c0aee148 100644 --- a/x/bank/client/cli/tx.go +++ b/x/bank/client/cli/tx.go @@ -39,11 +39,8 @@ func NewSendTxCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) * Args: cobra.ExactArgs(3), RunE: func(cmd *cobra.Command, args []string) error { inBuf := bufio.NewReader(cmd.InOrStdin()) - txf := tx.NewFactoryFromCLI(inBuf). - WithTxGenerator(txg). - WithAccountRetriever(ar) - cliCtx := context.NewCLIContextWithInputAndFrom(inBuf, args[0]).WithMarshaler(m) + txf := tx.NewFactoryFromCLI(inBuf).WithTxGenerator(txg).WithAccountRetriever(ar) toAddr, err := sdk.AccAddressFromBech32(args[1]) if err != nil { diff --git a/x/crisis/client/cli/tx.go b/x/crisis/client/cli/tx.go index 47c421a0d15f..3ca350ee67d4 100644 --- a/x/crisis/client/cli/tx.go +++ b/x/crisis/client/cli/tx.go @@ -1,4 +1,3 @@ -// nolint package cli import ( @@ -9,6 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/tx" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" @@ -16,27 +16,50 @@ import ( "github.com/cosmos/cosmos-sdk/x/crisis/types" ) -// command to replace a delegator's withdrawal address -func GetCmdInvariantBroken(cdc *codec.Codec) *cobra.Command { +// NewTxCmd returns a root CLI command handler for all x/crisis transaction commands. +func NewTxCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command { + txCmd := &cobra.Command{ + Use: types.ModuleName, + Short: "Crisis transactions subcommands", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + txCmd.AddCommand(NewMsgVerifyInvariantTxCmd(m, txg, ar)) + + return txCmd +} + +// NewMsgVerifyInvariantTxCmd returns a CLI command handler for creating a +// MsgVerifyInvariant transaction. +func NewMsgVerifyInvariantTxCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command { cmd := &cobra.Command{ Use: "invariant-broken [module-name] [invariant-route]", - Short: "submit proof that an invariant broken to halt the chain", + Short: "Submit proof that an invariant broken to halt the chain", Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { - inBuf := bufio.NewReader(cmd.InOrStdin()) - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) - cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) + cliCtx := context.NewCLIContextWithInputAndFrom(inBuf, args[0]).WithMarshaler(m) + txf := tx.NewFactoryFromCLI(inBuf).WithTxGenerator(txg).WithAccountRetriever(ar) senderAddr := cliCtx.GetFromAddress() moduleName, route := args[0], args[1] + msg := types.NewMsgVerifyInvariant(senderAddr, moduleName, route) - return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + return tx.GenerateOrBroadcastTx(cliCtx, txf, msg) }, } - return cmd + + return flags.PostCommands(cmd)[0] } +// --------------------------------------------------------------------------- +// Deprecated +// +// TODO: Remove once client-side Protobuf migration has been completed. +// --------------------------------------------------------------------------- + // GetTxCmd returns the transaction commands for this module func GetTxCmd(cdc *codec.Codec) *cobra.Command { txCmd := &cobra.Command{ @@ -52,3 +75,24 @@ func GetTxCmd(cdc *codec.Codec) *cobra.Command { )...) return txCmd } + +// command to replace a delegator's withdrawal address +func GetCmdInvariantBroken(cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "invariant-broken [module-name] [invariant-route]", + Short: "submit proof that an invariant broken to halt the chain", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + + inBuf := bufio.NewReader(cmd.InOrStdin()) + txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) + cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) + + senderAddr := cliCtx.GetFromAddress() + moduleName, route := args[0], args[1] + msg := types.NewMsgVerifyInvariant(senderAddr, moduleName, route) + return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } + return cmd +} From 22422c6de1d842b6015c3da62a9ee896557ff9a6 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Fri, 3 Apr 2020 10:59:46 -0400 Subject: [PATCH 513/529] Merge PR #5927: Fix parseQueryResponse --- x/auth/client/tx.go | 8 +++++--- x/auth/client/tx_test.go | 16 +++++++++------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/x/auth/client/tx.go b/x/auth/client/tx.go index 09f3146e7cdf..ba19d1be5983 100644 --- a/x/auth/client/tx.go +++ b/x/auth/client/tx.go @@ -6,7 +6,9 @@ import ( "fmt" "io/ioutil" "os" + "strings" + "github.com/gogo/protobuf/jsonpb" "github.com/pkg/errors" "github.com/spf13/viper" @@ -142,7 +144,7 @@ func CalculateGas( return sdk.SimulationResponse{}, 0, err } - simRes, err := parseQueryResponse(cdc, rawRes) + simRes, err := parseQueryResponse(rawRes) if err != nil { return sdk.SimulationResponse{}, 0, err } @@ -286,9 +288,9 @@ func adjustGasEstimate(estimate uint64, adjustment float64) uint64 { return uint64(adjustment * float64(estimate)) } -func parseQueryResponse(cdc *codec.Codec, rawRes []byte) (sdk.SimulationResponse, error) { +func parseQueryResponse(bz []byte) (sdk.SimulationResponse, error) { var simRes sdk.SimulationResponse - if err := cdc.UnmarshalBinaryBare(rawRes, &simRes); err != nil { + if err := jsonpb.Unmarshal(strings.NewReader(string(bz)), &simRes); err != nil { return sdk.SimulationResponse{}, err } diff --git a/x/auth/client/tx_test.go b/x/auth/client/tx_test.go index 22e9586d76e6..ab2ce267ece3 100644 --- a/x/auth/client/tx_test.go +++ b/x/auth/client/tx_test.go @@ -22,19 +22,20 @@ var ( ) func TestParseQueryResponse(t *testing.T) { - cdc := makeCodec() - simRes := sdk.SimulationResponse{ + simRes := &sdk.SimulationResponse{ GasInfo: sdk.GasInfo{GasUsed: 10, GasWanted: 20}, Result: &sdk.Result{Data: []byte("tx data"), Log: "log"}, } - bz := cdc.MustMarshalBinaryBare(simRes) - res, err := parseQueryResponse(cdc, bz) + bz, err := codec.ProtoMarshalJSON(simRes) + require.NoError(t, err) + + res, err := parseQueryResponse(bz) require.NoError(t, err) require.Equal(t, 10, int(res.GasInfo.GasUsed)) require.NotNil(t, res.Result) - res, err = parseQueryResponse(cdc, []byte("fuzzy")) + res, err = parseQueryResponse([]byte("fuzzy")) require.Error(t, err) } @@ -45,12 +46,13 @@ func TestCalculateGas(t *testing.T) { if wantErr { return nil, 0, errors.New("query failed") } - simRes := sdk.SimulationResponse{ + simRes := &sdk.SimulationResponse{ GasInfo: sdk.GasInfo{GasUsed: gasUsed, GasWanted: gasUsed}, Result: &sdk.Result{Data: []byte("tx data"), Log: "log"}, } - return cdc.MustMarshalBinaryBare(simRes), 0, nil + bz, _ := codec.ProtoMarshalJSON(simRes) + return bz, 0, nil } } From 7f78e61b93a522989b603e30871b4e9e9a779402 Mon Sep 17 00:00:00 2001 From: SaReN Date: Sat, 4 Apr 2020 01:36:37 +0530 Subject: [PATCH 514/529] Merge PR #5915: Tx Client Migration: x/staking --- x/slashing/client/cli/tx.go | 2 +- x/staking/client/cli/tx.go | 416 +++++++++++++++++++++++++++++----- x/staking/client/rest/rest.go | 7 + x/staking/client/rest/tx.go | 128 ++++++++++- 4 files changed, 491 insertions(+), 62 deletions(-) diff --git a/x/slashing/client/cli/tx.go b/x/slashing/client/cli/tx.go index 9d8ea841d296..e04a7e16cf29 100644 --- a/x/slashing/client/cli/tx.go +++ b/x/slashing/client/cli/tx.go @@ -20,7 +20,7 @@ import ( func NewTxCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command { slashingTxCmd := &cobra.Command{ Use: types.ModuleName, - Short: "Bank transaction subcommands", + Short: "Slashing transaction subcommands", DisableFlagParsing: true, SuggestionsMinimumDistance: 2, RunE: client.ValidateCmd, diff --git a/x/staking/client/cli/tx.go b/x/staking/client/cli/tx.go index 3199ece93dc5..c9b9211e1856 100644 --- a/x/staking/client/cli/tx.go +++ b/x/staking/client/cli/tx.go @@ -16,6 +16,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/tx" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" @@ -24,8 +25,19 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking/types" ) -// GetTxCmd returns the transaction commands for this module -func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { +//__________________________________________________________ + +var ( + defaultTokens = sdk.TokensFromConsensusPower(100) + defaultAmount = defaultTokens.String() + sdk.DefaultBondDenom + defaultCommissionRate = "0.1" + defaultCommissionMaxRate = "0.2" + defaultCommissionMaxChangeRate = "0.01" + defaultMinSelfDelegation = "1" +) + +// NewTxCmd returns a root CLI command handler for all x/staking transaction commands. +func NewTxCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command { stakingTxCmd := &cobra.Command{ Use: types.ModuleName, Short: "Staking transaction subcommands", @@ -35,35 +47,34 @@ func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { } stakingTxCmd.AddCommand(flags.PostCommands( - GetCmdCreateValidator(cdc), - GetCmdEditValidator(cdc), - GetCmdDelegate(cdc), - GetCmdRedelegate(storeKey, cdc), - GetCmdUnbond(storeKey, cdc), + NewCreateValidatorCmd(m, txg, ar), + NewEditValidatorCmd(m, txg, ar), + NewDelegateCmd(m, txg, ar), + NewRedelegateCmd(m, txg, ar), + NewUnbondCmd(m, txg, ar), )...) - return stakingTxCmd } -// GetCmdCreateValidator implements the create validator command handler. -func GetCmdCreateValidator(cdc *codec.Codec) *cobra.Command { +func NewCreateValidatorCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command { cmd := &cobra.Command{ Use: "create-validator", Short: "create new validator initialized with a self-delegation to it", RunE: func(cmd *cobra.Command, args []string) error { inBuf := bufio.NewReader(cmd.InOrStdin()) - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) - cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) + txf := tx.NewFactoryFromCLI(inBuf). + WithTxGenerator(txg). + WithAccountRetriever(ar) - txBldr, msg, err := BuildCreateValidatorMsg(cliCtx, txBldr) + cliCtx := context.NewCLIContextWithInputAndFrom(inBuf, args[0]).WithMarshaler(m) + + txf, msg, err := NewBuildCreateValidatorMsg(cliCtx, txf) if err != nil { return err } - - return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + return tx.GenerateOrBroadcastTx(cliCtx, txf, msg) }, } - cmd.Flags().AddFlagSet(FsPk) cmd.Flags().AddFlagSet(FsAmount) cmd.Flags().AddFlagSet(fsDescriptionCreate) @@ -77,20 +88,20 @@ func GetCmdCreateValidator(cdc *codec.Codec) *cobra.Command { cmd.MarkFlagRequired(FlagAmount) cmd.MarkFlagRequired(FlagPubKey) cmd.MarkFlagRequired(FlagMoniker) - - return cmd + return flags.PostCommands(cmd)[0] } -// GetCmdEditValidator implements the create edit validator command. -// TODO: add full description -func GetCmdEditValidator(cdc *codec.Codec) *cobra.Command { +func NewEditValidatorCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command { cmd := &cobra.Command{ Use: "edit-validator", Short: "edit an existing validator account", RunE: func(cmd *cobra.Command, args []string) error { inBuf := bufio.NewReader(cmd.InOrStdin()) - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(auth.DefaultTxEncoder(cdc)) - cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) + txf := tx.NewFactoryFromCLI(inBuf). + WithTxGenerator(txg). + WithAccountRetriever(ar) + + cliCtx := context.NewCLIContextWithInputAndFrom(inBuf, args[0]).WithMarshaler(m) valAddr := cliCtx.GetFromAddress() description := types.NewDescription( @@ -128,20 +139,14 @@ func GetCmdEditValidator(cdc *codec.Codec) *cobra.Command { msg := types.NewMsgEditValidator(sdk.ValAddress(valAddr), description, newRate, newMinSelfDelegation) // build and sign the transaction, then broadcast to Tendermint - return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + return tx.GenerateOrBroadcastTx(cliCtx, txf, msg) }, } - - cmd.Flags().AddFlagSet(fsDescriptionEdit) - cmd.Flags().AddFlagSet(fsCommissionUpdate) - cmd.Flags().AddFlagSet(FsMinSelfDelegation) - - return cmd + return flags.PostCommands(cmd)[0] } -// GetCmdDelegate implements the delegate command. -func GetCmdDelegate(cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ +func NewDelegateCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command { + cmd := &cobra.Command{ Use: "delegate [validator-addr] [amount]", Args: cobra.ExactArgs(2), Short: "Delegate liquid tokens to a validator", @@ -156,8 +161,11 @@ $ %s tx staking delegate cosmosvaloper1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm 10 ), RunE: func(cmd *cobra.Command, args []string) error { inBuf := bufio.NewReader(cmd.InOrStdin()) - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(auth.DefaultTxEncoder(cdc)) - cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) + txf := tx.NewFactoryFromCLI(inBuf). + WithTxGenerator(txg). + WithAccountRetriever(ar) + + cliCtx := context.NewCLIContextWithInputAndFrom(inBuf, args[0]).WithMarshaler(m) amount, err := sdk.ParseCoin(args[1]) if err != nil { @@ -171,14 +179,18 @@ $ %s tx staking delegate cosmosvaloper1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm 10 } msg := types.NewMsgDelegate(delAddr, valAddr, amount) - return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + return tx.GenerateOrBroadcastTx(cliCtx, txf, msg) }, } + cmd.Flags().AddFlagSet(fsDescriptionEdit) + cmd.Flags().AddFlagSet(fsCommissionUpdate) + cmd.Flags().AddFlagSet(FsMinSelfDelegation) + + return flags.PostCommands(cmd)[0] } -// GetCmdRedelegate the begin redelegation command. -func GetCmdRedelegate(storeName string, cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ +func NewRedelegateCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command { + cmd := &cobra.Command{ Use: "redelegate [src-validator-addr] [dst-validator-addr] [amount]", Short: "Redelegate illiquid tokens from one validator to another", Args: cobra.ExactArgs(3), @@ -193,9 +205,11 @@ $ %s tx staking redelegate cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj ), RunE: func(cmd *cobra.Command, args []string) error { inBuf := bufio.NewReader(cmd.InOrStdin()) - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(auth.DefaultTxEncoder(cdc)) - cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) + txf := tx.NewFactoryFromCLI(inBuf). + WithTxGenerator(txg). + WithAccountRetriever(ar) + cliCtx := context.NewCLIContextWithInputAndFrom(inBuf, args[0]).WithMarshaler(m) delAddr := cliCtx.GetFromAddress() valSrcAddr, err := sdk.ValAddressFromBech32(args[0]) if err != nil { @@ -213,14 +227,14 @@ $ %s tx staking redelegate cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj } msg := types.NewMsgBeginRedelegate(delAddr, valSrcAddr, valDstAddr, amount) - return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + return tx.GenerateOrBroadcastTx(cliCtx, txf, msg) }, } + return flags.PostCommands(cmd)[0] } -// GetCmdUnbond implements the unbond validator command. -func GetCmdUnbond(storeName string, cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ +func NewUnbondCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command { + cmd := &cobra.Command{ Use: "unbond [validator-addr] [amount]", Short: "Unbond shares from a validator", Args: cobra.ExactArgs(2), @@ -235,8 +249,11 @@ $ %s tx staking unbond cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj 100s ), RunE: func(cmd *cobra.Command, args []string) error { inBuf := bufio.NewReader(cmd.InOrStdin()) - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(auth.DefaultTxEncoder(cdc)) - cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) + txf := tx.NewFactoryFromCLI(inBuf). + WithTxGenerator(txg). + WithAccountRetriever(ar) + + cliCtx := context.NewCLIContextWithInputAndFrom(inBuf, args[0]).WithMarshaler(m) delAddr := cliCtx.GetFromAddress() valAddr, err := sdk.ValAddressFromBech32(args[0]) @@ -250,21 +267,65 @@ $ %s tx staking unbond cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj 100s } msg := types.NewMsgUndelegate(delAddr, valAddr, amount) - return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + return tx.GenerateOrBroadcastTx(cliCtx, txf, msg) }, } + return flags.PostCommands(cmd)[0] } -//__________________________________________________________ +func NewBuildCreateValidatorMsg(cliCtx context.CLIContext, txf tx.Factory) (tx.Factory, sdk.Msg, error) { + amounstStr := viper.GetString(FlagAmount) + amount, err := sdk.ParseCoin(amounstStr) + if err != nil { + return txf, nil, err + } -var ( - defaultTokens = sdk.TokensFromConsensusPower(100) - defaultAmount = defaultTokens.String() + sdk.DefaultBondDenom - defaultCommissionRate = "0.1" - defaultCommissionMaxRate = "0.2" - defaultCommissionMaxChangeRate = "0.01" - defaultMinSelfDelegation = "1" -) + valAddr := cliCtx.GetFromAddress() + pkStr := viper.GetString(FlagPubKey) + + pk, err := sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeConsPub, pkStr) + if err != nil { + return txf, nil, err + } + + description := types.NewDescription( + viper.GetString(FlagMoniker), + viper.GetString(FlagIdentity), + viper.GetString(FlagWebsite), + viper.GetString(FlagSecurityContact), + viper.GetString(FlagDetails), + ) + + // get the initial validator commission parameters + rateStr := viper.GetString(FlagCommissionRate) + maxRateStr := viper.GetString(FlagCommissionMaxRate) + maxChangeRateStr := viper.GetString(FlagCommissionMaxChangeRate) + commissionRates, err := buildCommissionRates(rateStr, maxRateStr, maxChangeRateStr) + if err != nil { + return txf, nil, err + } + + // get the initial validator min self delegation + msbStr := viper.GetString(FlagMinSelfDelegation) + minSelfDelegation, ok := sdk.NewIntFromString(msbStr) + if !ok { + return txf, nil, types.ErrMinSelfDelegationInvalid + } + + msg := types.NewMsgCreateValidator( + sdk.ValAddress(valAddr), pk, amount, description, commissionRates, minSelfDelegation, + ) + + if viper.GetBool(flags.FlagGenerateOnly) { + ip := viper.GetString(FlagIP) + nodeID := viper.GetString(FlagNodeID) + if nodeID != "" && ip != "" { + txf = txf.WithMemo(fmt.Sprintf("%s@%s:26656", nodeID, ip)) + } + } + + return txf, msg, nil +} // Return the flagset, particular flags, and a description of defaults // this is anticipated to be used with the gen-tx @@ -342,6 +403,247 @@ func PrepareFlagsForTxCreateValidator( } } +// --------------------------------------------------------------------------- +// Deprecated +// +// TODO: Remove once client-side Protobuf migration has been completed. +// --------------------------------------------------------------------------- + +// GetTxCmd returns the transaction commands for this module +// +// TODO: Remove once client-side Protobuf migration has been completed. +// ref: https://github.com/cosmos/cosmos-sdk/issues/5864 +// GetTxCmd returns the transaction commands for this module +func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { + stakingTxCmd := &cobra.Command{ + Use: types.ModuleName, + Short: "Staking transaction subcommands", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + stakingTxCmd.AddCommand(flags.PostCommands( + GetCmdCreateValidator(cdc), + GetCmdEditValidator(cdc), + GetCmdDelegate(cdc), + GetCmdRedelegate(storeKey, cdc), + GetCmdUnbond(storeKey, cdc), + )...) + + return stakingTxCmd +} + +// GetCmdCreateValidator implements the create validator command handler. +func GetCmdCreateValidator(cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "create-validator", + Short: "create new validator initialized with a self-delegation to it", + RunE: func(cmd *cobra.Command, args []string) error { + inBuf := bufio.NewReader(cmd.InOrStdin()) + txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) + cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) + + txBldr, msg, err := BuildCreateValidatorMsg(cliCtx, txBldr) + if err != nil { + return err + } + + return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } + + cmd.Flags().AddFlagSet(FsPk) + cmd.Flags().AddFlagSet(FsAmount) + cmd.Flags().AddFlagSet(fsDescriptionCreate) + cmd.Flags().AddFlagSet(FsCommissionCreate) + cmd.Flags().AddFlagSet(FsMinSelfDelegation) + + cmd.Flags().String(FlagIP, "", fmt.Sprintf("The node's public IP. It takes effect only when used in combination with --%s", flags.FlagGenerateOnly)) + cmd.Flags().String(FlagNodeID, "", "The node's ID") + + cmd.MarkFlagRequired(flags.FlagFrom) + cmd.MarkFlagRequired(FlagAmount) + cmd.MarkFlagRequired(FlagPubKey) + cmd.MarkFlagRequired(FlagMoniker) + + return cmd +} + +// GetCmdEditValidator implements the create edit validator command. +// TODO: add full description +func GetCmdEditValidator(cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "edit-validator", + Short: "edit an existing validator account", + RunE: func(cmd *cobra.Command, args []string) error { + inBuf := bufio.NewReader(cmd.InOrStdin()) + txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(auth.DefaultTxEncoder(cdc)) + cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) + + valAddr := cliCtx.GetFromAddress() + description := types.NewDescription( + viper.GetString(FlagMoniker), + viper.GetString(FlagIdentity), + viper.GetString(FlagWebsite), + viper.GetString(FlagSecurityContact), + viper.GetString(FlagDetails), + ) + + var newRate *sdk.Dec + + commissionRate := viper.GetString(FlagCommissionRate) + if commissionRate != "" { + rate, err := sdk.NewDecFromStr(commissionRate) + if err != nil { + return fmt.Errorf("invalid new commission rate: %v", err) + } + + newRate = &rate + } + + var newMinSelfDelegation *sdk.Int + + minSelfDelegationString := viper.GetString(FlagMinSelfDelegation) + if minSelfDelegationString != "" { + msb, ok := sdk.NewIntFromString(minSelfDelegationString) + if !ok { + return types.ErrMinSelfDelegationInvalid + } + + newMinSelfDelegation = &msb + } + + msg := types.NewMsgEditValidator(sdk.ValAddress(valAddr), description, newRate, newMinSelfDelegation) + + // build and sign the transaction, then broadcast to Tendermint + return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } + + cmd.Flags().AddFlagSet(fsDescriptionEdit) + cmd.Flags().AddFlagSet(fsCommissionUpdate) + cmd.Flags().AddFlagSet(FsMinSelfDelegation) + + return cmd +} + +// GetCmdDelegate implements the delegate command. +func GetCmdDelegate(cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "delegate [validator-addr] [amount]", + Args: cobra.ExactArgs(2), + Short: "Delegate liquid tokens to a validator", + Long: strings.TrimSpace( + fmt.Sprintf(`Delegate an amount of liquid coins to a validator from your wallet. + +Example: +$ %s tx staking delegate cosmosvaloper1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm 1000stake --from mykey +`, + version.ClientName, + ), + ), + RunE: func(cmd *cobra.Command, args []string) error { + inBuf := bufio.NewReader(cmd.InOrStdin()) + txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(auth.DefaultTxEncoder(cdc)) + cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) + + amount, err := sdk.ParseCoin(args[1]) + if err != nil { + return err + } + + delAddr := cliCtx.GetFromAddress() + valAddr, err := sdk.ValAddressFromBech32(args[0]) + if err != nil { + return err + } + + msg := types.NewMsgDelegate(delAddr, valAddr, amount) + return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } +} + +// GetCmdRedelegate the begin redelegation command. +func GetCmdRedelegate(storeName string, cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "redelegate [src-validator-addr] [dst-validator-addr] [amount]", + Short: "Redelegate illiquid tokens from one validator to another", + Args: cobra.ExactArgs(3), + Long: strings.TrimSpace( + fmt.Sprintf(`Redelegate an amount of illiquid staking tokens from one validator to another. + +Example: +$ %s tx staking redelegate cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj cosmosvaloper1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm 100stake --from mykey +`, + version.ClientName, + ), + ), + RunE: func(cmd *cobra.Command, args []string) error { + inBuf := bufio.NewReader(cmd.InOrStdin()) + txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(auth.DefaultTxEncoder(cdc)) + cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) + + delAddr := cliCtx.GetFromAddress() + valSrcAddr, err := sdk.ValAddressFromBech32(args[0]) + if err != nil { + return err + } + + valDstAddr, err := sdk.ValAddressFromBech32(args[1]) + if err != nil { + return err + } + + amount, err := sdk.ParseCoin(args[2]) + if err != nil { + return err + } + + msg := types.NewMsgBeginRedelegate(delAddr, valSrcAddr, valDstAddr, amount) + return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } +} + +// GetCmdUnbond implements the unbond validator command. +func GetCmdUnbond(storeName string, cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "unbond [validator-addr] [amount]", + Short: "Unbond shares from a validator", + Args: cobra.ExactArgs(2), + Long: strings.TrimSpace( + fmt.Sprintf(`Unbond an amount of bonded shares from a validator. + +Example: +$ %s tx staking unbond cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj 100stake --from mykey +`, + version.ClientName, + ), + ), + RunE: func(cmd *cobra.Command, args []string) error { + inBuf := bufio.NewReader(cmd.InOrStdin()) + txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(auth.DefaultTxEncoder(cdc)) + cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) + + delAddr := cliCtx.GetFromAddress() + valAddr, err := sdk.ValAddressFromBech32(args[0]) + if err != nil { + return err + } + + amount, err := sdk.ParseCoin(args[1]) + if err != nil { + return err + } + + msg := types.NewMsgUndelegate(delAddr, valAddr, amount) + return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } +} + // BuildCreateValidatorMsg makes a new MsgCreateValidator. func BuildCreateValidatorMsg(cliCtx context.CLIContext, txBldr auth.TxBuilder) (auth.TxBuilder, sdk.Msg, error) { amounstStr := viper.GetString(FlagAmount) diff --git a/x/staking/client/rest/rest.go b/x/staking/client/rest/rest.go index 4237d59e258a..b43cf152c662 100644 --- a/x/staking/client/rest/rest.go +++ b/x/staking/client/rest/rest.go @@ -4,8 +4,15 @@ import ( "github.com/gorilla/mux" "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/tx" + "github.com/cosmos/cosmos-sdk/codec" ) +func RegisterHandlers(cliCtx context.CLIContext, m codec.Marshaler, txg tx.Generator, r *mux.Router) { + registerQueryRoutes(cliCtx, r) + registerTxHandlers(cliCtx, m, txg, r) +} + // RegisterRoutes registers staking-related REST handlers to a router func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router) { registerQueryRoutes(cliCtx, r) diff --git a/x/staking/client/rest/tx.go b/x/staking/client/rest/tx.go index 402d52a08255..01328279ea1a 100644 --- a/x/staking/client/rest/tx.go +++ b/x/staking/client/rest/tx.go @@ -7,24 +7,26 @@ import ( "github.com/gorilla/mux" "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/tx" + "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/rest" authclient "github.com/cosmos/cosmos-sdk/x/auth/client" "github.com/cosmos/cosmos-sdk/x/staking/types" ) -func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router) { +func registerTxHandlers(cliCtx context.CLIContext, m codec.Marshaler, txg tx.Generator, r *mux.Router) { r.HandleFunc( "/staking/delegators/{delegatorAddr}/delegations", - postDelegationsHandlerFn(cliCtx), + newPostDelegationsHandlerFn(cliCtx, m, txg), ).Methods("POST") r.HandleFunc( "/staking/delegators/{delegatorAddr}/unbonding_delegations", - postUnbondingDelegationsHandlerFn(cliCtx), + newPostUnbondingDelegationsHandlerFn(cliCtx, m, txg), ).Methods("POST") r.HandleFunc( "/staking/delegators/{delegatorAddr}/redelegations", - postRedelegationsHandlerFn(cliCtx), + newPostRedelegationsHandlerFn(cliCtx, m, txg), ).Methods("POST") } @@ -55,6 +57,124 @@ type ( } ) +func newPostDelegationsHandlerFn(cliCtx context.CLIContext, m codec.Marshaler, txg tx.Generator) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + cliCtx = cliCtx.WithMarshaler(m) + var req DelegateRequest + + if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) { + return + } + + req.BaseReq = req.BaseReq.Sanitize() + if !req.BaseReq.ValidateBasic(w) { + return + } + + msg := types.NewMsgDelegate(req.DelegatorAddress, req.ValidatorAddress, req.Amount) + if rest.CheckBadRequestError(w, msg.ValidateBasic()) { + return + } + + fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From) + if rest.CheckBadRequestError(w, err) { + return + } + + if !bytes.Equal(fromAddr, req.DelegatorAddress) { + rest.WriteErrorResponse(w, http.StatusUnauthorized, "must use own delegator address") + return + } + + tx.WriteGeneratedTxResponse(cliCtx, w, txg, req.BaseReq, msg) + } +} + +func newPostRedelegationsHandlerFn(cliCtx context.CLIContext, m codec.Marshaler, txg tx.Generator) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + cliCtx = cliCtx.WithMarshaler(m) + var req RedelegateRequest + + if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) { + return + } + + req.BaseReq = req.BaseReq.Sanitize() + if !req.BaseReq.ValidateBasic(w) { + return + } + + msg := types.NewMsgBeginRedelegate(req.DelegatorAddress, req.ValidatorSrcAddress, req.ValidatorDstAddress, req.Amount) + if rest.CheckBadRequestError(w, msg.ValidateBasic()) { + return + } + + fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From) + if rest.CheckBadRequestError(w, err) { + return + } + + if !bytes.Equal(fromAddr, req.DelegatorAddress) { + rest.WriteErrorResponse(w, http.StatusUnauthorized, "must use own delegator address") + return + } + + tx.WriteGeneratedTxResponse(cliCtx, w, txg, req.BaseReq, msg) + } +} + +func newPostUnbondingDelegationsHandlerFn(cliCtx context.CLIContext, m codec.Marshaler, txg tx.Generator) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + cliCtx = cliCtx.WithMarshaler(m) + var req UndelegateRequest + if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) { + return + } + + req.BaseReq = req.BaseReq.Sanitize() + if !req.BaseReq.ValidateBasic(w) { + return + } + + msg := types.NewMsgUndelegate(req.DelegatorAddress, req.ValidatorAddress, req.Amount) + if rest.CheckBadRequestError(w, msg.ValidateBasic()) { + return + } + + fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From) + if rest.CheckBadRequestError(w, err) { + return + } + + if !bytes.Equal(fromAddr, req.DelegatorAddress) { + rest.WriteErrorResponse(w, http.StatusUnauthorized, "must use own delegator address") + return + } + + tx.WriteGeneratedTxResponse(cliCtx, w, txg, req.BaseReq, msg) + } +} + +// --------------------------------------------------------------------------- +// Deprecated +// +// TODO: Remove once client-side Protobuf migration has been completed. +// --------------------------------------------------------------------------- +func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router) { + r.HandleFunc( + "/staking/delegators/{delegatorAddr}/delegations", + postDelegationsHandlerFn(cliCtx), + ).Methods("POST") + r.HandleFunc( + "/staking/delegators/{delegatorAddr}/unbonding_delegations", + postUnbondingDelegationsHandlerFn(cliCtx), + ).Methods("POST") + r.HandleFunc( + "/staking/delegators/{delegatorAddr}/redelegations", + postRedelegationsHandlerFn(cliCtx), + ).Methods("POST") +} + func postDelegationsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req DelegateRequest From dfbc6cd81b47b5fa7d49d9174d613cc63b0ea36e Mon Sep 17 00:00:00 2001 From: colin axner Date: Sat, 4 Apr 2020 11:24:11 -0700 Subject: [PATCH 515/529] Merge PR #5920: Fix validate cmd bug --- client/cmd.go | 37 ++++++++++++++++++++++++++++--------- client/cmd_test.go | 2 ++ 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/client/cmd.go b/client/cmd.go index afddf20fe2b9..df9c5be62f21 100644 --- a/client/cmd.go +++ b/client/cmd.go @@ -2,6 +2,7 @@ package client import ( "fmt" + "strings" "github.com/pkg/errors" "github.com/spf13/cobra" @@ -9,23 +10,41 @@ import ( // ValidateCmd returns unknown command error or Help display if help flag set func ValidateCmd(cmd *cobra.Command, args []string) error { - var cmds []string - var help bool + var unknownCmd string + var skipNext bool - // construct array of commands and search for help flag for _, arg := range args { + // search for help flag if arg == "--help" || arg == "-h" { - help = true - } else if len(arg) > 0 && !(arg[0] == '-') { - cmds = append(cmds, arg) + return cmd.Help() + } + + // check if the current arg is a flag + switch { + case len(arg) > 0 && (arg[0] == '-'): + // the next arg should be skipped if the current arg is a + // flag and does not use "=" to assign the flag's value + if !strings.Contains(arg, "=") { + skipNext = true + } else { + skipNext = false + } + case skipNext: + // skip current arg + skipNext = false + case unknownCmd == "": + // unknown command found + // continue searching for help flag + unknownCmd = arg } } - if !help && len(cmds) > 0 { - err := fmt.Sprintf("unknown command \"%s\" for \"%s\"", cmds[0], cmd.CalledAs()) + // return the help screen if no unknown command is found + if unknownCmd != "" { + err := fmt.Sprintf("unknown command \"%s\" for \"%s\"", unknownCmd, cmd.CalledAs()) // build suggestions for unknown argument - if suggestions := cmd.SuggestionsFor(cmds[0]); len(suggestions) > 0 { + if suggestions := cmd.SuggestionsFor(unknownCmd); len(suggestions) > 0 { err += "\n\nDid you mean this?\n" for _, s := range suggestions { err += fmt.Sprintf("\t%v\n", s) diff --git a/client/cmd_test.go b/client/cmd_test.go index 554d39953730..94de383114e6 100644 --- a/client/cmd_test.go +++ b/client/cmd_test.go @@ -41,6 +41,8 @@ func TestValidateCmd(t *testing.T) { {"no command provided", []string{}, false}, {"help flag", []string{"commission", "--help"}, false}, // nolint: misspell {"shorthand help flag", []string{"commission", "-h"}, false}, // nolint: misspell + {"flag only, no command provided", []string{"--gas", "1000atom"}, false}, + {"flag and misspelled command", []string{"--gas", "1000atom", "comission"}, true}, // nolint: misspell } for _, tt := range tests { From 597093d8be20e1cd6fb34d96949f1689fe2c2f29 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 6 Apr 2020 10:05:44 -0400 Subject: [PATCH 516/529] Bump github.com/pelletier/go-toml from 1.6.0 to 1.7.0 (#5932) Bumps [github.com/pelletier/go-toml](https://github.com/pelletier/go-toml) from 1.6.0 to 1.7.0. - [Release notes](https://github.com/pelletier/go-toml/releases) - [Commits](https://github.com/pelletier/go-toml/compare/v1.6.0...v1.7.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 94b3d1391dc4..af9ad30d22bf 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/hashicorp/golang-lru v0.5.4 github.com/mattn/go-isatty v0.0.12 github.com/otiai10/copy v1.1.1 - github.com/pelletier/go-toml v1.6.0 + github.com/pelletier/go-toml v1.7.0 github.com/pkg/errors v0.9.1 github.com/rakyll/statik v0.1.7 github.com/regen-network/cosmos-proto v0.1.1-0.20200213154359-02baa11ea7c2 diff --git a/go.sum b/go.sum index f5755bcfdd78..51383251f8a4 100644 --- a/go.sum +++ b/go.sum @@ -311,6 +311,8 @@ github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtP github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.6.0 h1:aetoXYr0Tv7xRU/V4B4IZJ2QcbtMUFoNb3ORp7TzIK4= github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys= +github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI= +github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= From 498bb185d3da098fd0da38e6b21c7ee277d88a42 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 6 Apr 2020 10:15:50 -0400 Subject: [PATCH 517/529] Bump github.com/tendermint/iavl from 0.13.2 to 0.13.3 (#5933) Bumps [github.com/tendermint/iavl](https://github.com/tendermint/iavl) from 0.13.2 to 0.13.3. - [Release notes](https://github.com/tendermint/iavl/releases) - [Changelog](https://github.com/tendermint/iavl/blob/master/CHANGELOG.md) - [Commits](https://github.com/tendermint/iavl/compare/v0.13.2...v0.13.3) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> Co-authored-by: Alexander Bezobchuk --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index af9ad30d22bf..68148f31e5bb 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,7 @@ require ( github.com/tendermint/btcd v0.1.1 github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 github.com/tendermint/go-amino v0.15.1 - github.com/tendermint/iavl v0.13.2 + github.com/tendermint/iavl v0.13.3 github.com/tendermint/tendermint v0.33.2 github.com/tendermint/tm-db v0.5.1 google.golang.org/protobuf v1.20.1 // indirect diff --git a/go.sum b/go.sum index 51383251f8a4..f118cb66ae69 100644 --- a/go.sum +++ b/go.sum @@ -426,6 +426,8 @@ github.com/tendermint/go-amino v0.15.1 h1:D2uk35eT4iTsvJd9jWIetzthE5C0/k2QmMFkCN github.com/tendermint/go-amino v0.15.1/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= github.com/tendermint/iavl v0.13.2 h1:O1m08/Ciy53l9IYmf75uIRVvrNsfjEbre8u/yCu/oqk= github.com/tendermint/iavl v0.13.2/go.mod h1:vE1u0XAGXYjHykd4BLp8p/yivrw2PF1TuoljBcsQoGA= +github.com/tendermint/iavl v0.13.3 h1:expgBDY1MX+6/3sqrIxGChbTNf9N9aTJ67SH4bPchCs= +github.com/tendermint/iavl v0.13.3/go.mod h1:2lE7GiWdSvc7kvT78ncIKmkOjCnp6JEnSb2O7B9htLw= github.com/tendermint/tendermint v0.33.2 h1:NzvRMTuXJxqSsFed2J7uHmMU5N1CVzSpfi3nCc882KY= github.com/tendermint/tendermint v0.33.2/go.mod h1:25DqB7YvV1tN3tHsjWoc2vFtlwICfrub9XO6UBO+4xk= github.com/tendermint/tm-db v0.4.1/go.mod h1:JsJ6qzYkCGiGwm5GHl/H5GLI9XLb6qZX7PRe425dHAY= From bc9949e3834ee0495b0e7d02c09aa4a6876a5045 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Mon, 6 Apr 2020 10:24:40 -0400 Subject: [PATCH 518/529] Merge PR #5936: Handle and return error on tx.SetMsgs --- client/tx/tx.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/client/tx/tx.go b/client/tx/tx.go index 21fa4c16ffee..7958122dad31 100644 --- a/client/tx/tx.go +++ b/client/tx/tx.go @@ -235,10 +235,13 @@ func BuildUnsignedTx(txf Factory, msgs ...sdk.Msg) (ClientTx, error) { tx := txf.txGenerator.NewTx() tx.SetFee(auth.NewStdFee(txf.gas, fees)) - tx.SetMsgs(msgs...) tx.SetMemo(txf.memo) tx.SetSignatures() + if err := tx.SetMsgs(msgs...); err != nil { + return nil, err + } + return tx, nil } From 5098548b8c18017d50bb51bc1fd3ec748640bf0d Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Mon, 6 Apr 2020 17:40:35 +0200 Subject: [PATCH 519/529] run go mod tidy (#5937) --- go.sum | 6 ------ 1 file changed, 6 deletions(-) diff --git a/go.sum b/go.sum index f118cb66ae69..cb61d29e88ee 100644 --- a/go.sum +++ b/go.sum @@ -309,8 +309,6 @@ github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIw github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml v1.6.0 h1:aetoXYr0Tv7xRU/V4B4IZJ2QcbtMUFoNb3ORp7TzIK4= -github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys= github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI= github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= @@ -424,15 +422,11 @@ github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15/go.mod h1:z4YtwM github.com/tendermint/go-amino v0.14.1/go.mod h1:i/UKE5Uocn+argJJBb12qTZsCDBcAYMbR92AaJVmKso= github.com/tendermint/go-amino v0.15.1 h1:D2uk35eT4iTsvJd9jWIetzthE5C0/k2QmMFkCN+4JgQ= github.com/tendermint/go-amino v0.15.1/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= -github.com/tendermint/iavl v0.13.2 h1:O1m08/Ciy53l9IYmf75uIRVvrNsfjEbre8u/yCu/oqk= -github.com/tendermint/iavl v0.13.2/go.mod h1:vE1u0XAGXYjHykd4BLp8p/yivrw2PF1TuoljBcsQoGA= github.com/tendermint/iavl v0.13.3 h1:expgBDY1MX+6/3sqrIxGChbTNf9N9aTJ67SH4bPchCs= github.com/tendermint/iavl v0.13.3/go.mod h1:2lE7GiWdSvc7kvT78ncIKmkOjCnp6JEnSb2O7B9htLw= github.com/tendermint/tendermint v0.33.2 h1:NzvRMTuXJxqSsFed2J7uHmMU5N1CVzSpfi3nCc882KY= github.com/tendermint/tendermint v0.33.2/go.mod h1:25DqB7YvV1tN3tHsjWoc2vFtlwICfrub9XO6UBO+4xk= github.com/tendermint/tm-db v0.4.1/go.mod h1:JsJ6qzYkCGiGwm5GHl/H5GLI9XLb6qZX7PRe425dHAY= -github.com/tendermint/tm-db v0.5.0 h1:qtM5UTr1dlRnHtDY6y7MZO5Di8XAE2j3lc/pCnKJ5hQ= -github.com/tendermint/tm-db v0.5.0/go.mod h1:lSq7q5WRR/njf1LnhiZ/lIJHk2S8Y1Zyq5oP/3o9C2U= github.com/tendermint/tm-db v0.5.1 h1:H9HDq8UEA7Eeg13kdYckkgwwkQLBnJGgX4PgLJRhieY= github.com/tendermint/tm-db v0.5.1/go.mod h1:g92zWjHpCYlEvQXvy9M168Su8V1IBEeawpXVVBaK4f4= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= From 7d6033ea5837edc242160c3c18401d612fdf316a Mon Sep 17 00:00:00 2001 From: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Date: Mon, 6 Apr 2020 12:33:15 -0400 Subject: [PATCH 520/529] Merge PR #5938: x/genutil: fix InitializeNodeValidatorFiles --- CHANGELOG.md | 1 + x/genutil/utils.go | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2bcbedca0ae0..4f1fc9c7bbd7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -98,6 +98,7 @@ when method receivers are offline/multisig keys. types (eg. keys) to the `auth` module internal amino codec. * (rest) [\#5906](https://github.com/cosmos/cosmos-sdk/pull/5906) Fix an issue that make some REST calls panic when sending invalid or incomplete requests. +* (x/genutil) [\#5938](https://github.com/cosmos/cosmos-sdk/pull/5938) Fix `InitializeNodeValidatorFiles` error handling. ### State Machine Breaking diff --git a/x/genutil/utils.go b/x/genutil/utils.go index 7d1a761ef562..3d8aa8f2ed00 100644 --- a/x/genutil/utils.go +++ b/x/genutil/utils.go @@ -52,7 +52,7 @@ func InitializeNodeValidatorFiles(config *cfg.Config, nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile()) if err != nil { - return nodeID, valPubKey, err + return "", nil, err } nodeID = string(nodeKey.ID()) @@ -60,12 +60,12 @@ func InitializeNodeValidatorFiles(config *cfg.Config, pvKeyFile := config.PrivValidatorKeyFile() if err := tmos.EnsureDir(filepath.Dir(pvKeyFile), 0777); err != nil { - return nodeID, valPubKey, nil + return "", nil, err } pvStateFile := config.PrivValidatorStateFile() if err := tmos.EnsureDir(filepath.Dir(pvStateFile), 0777); err != nil { - return nodeID, valPubKey, nil + return "", nil, err } valPubKey = privval.LoadOrGenFilePV(pvKeyFile, pvStateFile).GetPubKey() From 7b21c543592731658c5330e09d79b7014f161ddc Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Tue, 7 Apr 2020 14:32:37 -0400 Subject: [PATCH 521/529] Fix IncrementSequenceDecorator (#5950) * Fix IncrementSequenceDecorator * Update PR # * Update godoc * Add TestIncrementSequenceDecorator test --- CHANGELOG.md | 1 + x/auth/ante/sigverify.go | 17 ++++++++-------- x/auth/ante/sigverify_test.go | 37 +++++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f1fc9c7bbd7..ce320d48f65d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -99,6 +99,7 @@ types (eg. keys) to the `auth` module internal amino codec. * (rest) [\#5906](https://github.com/cosmos/cosmos-sdk/pull/5906) Fix an issue that make some REST calls panic when sending invalid or incomplete requests. * (x/genutil) [\#5938](https://github.com/cosmos/cosmos-sdk/pull/5938) Fix `InitializeNodeValidatorFiles` error handling. +* (x/auth) [\#5950](https://github.com/cosmos/cosmos-sdk/pull/5950) Fix `IncrementSequenceDecorator` to use is `IsReCheckTx` instead of `IsCheckTx` to allow account sequence incrementing. ### State Machine Breaking diff --git a/x/auth/ante/sigverify.go b/x/auth/ante/sigverify.go index 895be5373c61..c40712bb0838 100644 --- a/x/auth/ante/sigverify.go +++ b/x/auth/ante/sigverify.go @@ -218,13 +218,13 @@ func (svd SigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simul // IncrementSequenceDecorator handles incrementing sequences of all signers. // Use the IncrementSequenceDecorator decorator to prevent replay attacks. Note, -// there is no need to execute IncrementSequenceDecorator on CheckTx or RecheckTX -// since it is merely updating the nonce. As a result, this has the side effect -// that subsequent and sequential txs orginating from the same account cannot be -// handled correctly in a reliable way. To send sequential txs orginating from the -// same account, it is recommended to instead use multiple messages in a tx. +// there is no need to execute IncrementSequenceDecorator on RecheckTX since +// CheckTx would already bump the sequence number. // -// CONTRACT: The tx must implement the SigVerifiableTx interface. +// NOTE: Since CheckTx and DeliverTx state are managed separately, subsequent and +// sequential txs orginating from the same account cannot be handled correctly in +// a reliable way unless sequence numbers are managed and tracked manually by a +// client. It is recommended to instead use multiple messages in a tx. type IncrementSequenceDecorator struct { ak keeper.AccountKeeper } @@ -236,8 +236,8 @@ func NewIncrementSequenceDecorator(ak keeper.AccountKeeper) IncrementSequenceDec } func (isd IncrementSequenceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) { - // no need to increment sequence on CheckTx or RecheckTx - if ctx.IsCheckTx() && !simulate { + // no need to increment sequence on RecheckTx + if ctx.IsReCheckTx() && !simulate { return next(ctx, tx, simulate) } @@ -252,6 +252,7 @@ func (isd IncrementSequenceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, sim if err := acc.SetSequence(acc.GetSequence() + 1); err != nil { panic(err) } + isd.ak.SetAccount(ctx, acc) } diff --git a/x/auth/ante/sigverify_test.go b/x/auth/ante/sigverify_test.go index 35aaa8c9f806..54f74b3eac02 100644 --- a/x/auth/ante/sigverify_test.go +++ b/x/auth/ante/sigverify_test.go @@ -212,3 +212,40 @@ func runSigDecorators(t *testing.T, params types.Params, multisig bool, privs .. return after - before, err } + +func TestIncrementSequenceDecorator(t *testing.T) { + app, ctx := createTestApp(true) + + priv, _, addr := types.KeyTestPubAddr() + acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr) + require.NoError(t, acc.SetAccountNumber(uint64(50))) + app.AccountKeeper.SetAccount(ctx, acc) + + msgs := []sdk.Msg{types.NewTestMsg(addr)} + privKeys := []crypto.PrivKey{priv} + accNums := []uint64{app.AccountKeeper.GetAccount(ctx, addr).GetAccountNumber()} + accSeqs := []uint64{app.AccountKeeper.GetAccount(ctx, addr).GetSequence()} + fee := types.NewTestStdFee() + tx := types.NewTestTx(ctx, msgs, privKeys, accNums, accSeqs, fee) + + isd := ante.NewIncrementSequenceDecorator(app.AccountKeeper) + antehandler := sdk.ChainAnteDecorators(isd) + + testCases := []struct { + ctx sdk.Context + simulate bool + expectedSeq uint64 + }{ + {ctx.WithIsReCheckTx(true), false, 0}, + {ctx.WithIsCheckTx(true).WithIsReCheckTx(false), false, 1}, + {ctx.WithIsReCheckTx(true), false, 1}, + {ctx.WithIsReCheckTx(true), false, 1}, + {ctx.WithIsReCheckTx(true), true, 2}, + } + + for i, tc := range testCases { + _, err := antehandler(tc.ctx, tx, tc.simulate) + require.NoError(t, err, "unexpected error; tc #%d, %v", i, tc) + require.Equal(t, tc.expectedSeq, app.AccountKeeper.GetAccount(ctx, addr).GetSequence()) + } +} From 7325692550073bf05c4811f095b7054c44ec8866 Mon Sep 17 00:00:00 2001 From: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Date: Tue, 7 Apr 2020 18:33:30 -0400 Subject: [PATCH 522/529] x/staking: skip HistoricalInfo in simulations (#5949) * x/staking: import and export HistoricalInfo * staking/types: add HistoricalInfo to GenesisState * changelog * add staking module to app BeginBlockers * remove JSON files * address comments from review * add HistoricalInfoKey to skipped prefixes * fix DiffKVStores * rm JSON --- .github/workflows/sims.yml | 6 ++--- CHANGELOG.md | 1 + simapp/app.go | 2 +- simapp/sim_test.go | 1 + store/types/utils.go | 11 ++++----- x/staking/alias.go | 1 - x/staking/genesis.go | 12 ++++------ x/staking/keeper/historical_info.go | 26 +++++++++++++++++++++ x/staking/keeper/historical_info_test.go | 29 ++++++++++++++++++++++++ x/staking/keeper/keeper.go | 1 + x/staking/simulation/decoder.go | 6 +++++ x/staking/simulation/decoder_test.go | 4 ++++ x/staking/types/keys.go | 3 --- 13 files changed, 80 insertions(+), 23 deletions(-) diff --git a/.github/workflows/sims.yml b/.github/workflows/sims.yml index d0b4b0fe7f6c..9e750db4c487 100644 --- a/.github/workflows/sims.yml +++ b/.github/workflows/sims.yml @@ -51,7 +51,7 @@ jobs: with: path: ~/go/bin key: ${{ runner.os }}-go-runsim-binary - - name: test nondeterminism + - name: test-sim-nondeterminism run: | make test-sim-nondeterminism @@ -97,9 +97,9 @@ jobs: with: path: ~/go/bin key: ${{ runner.os }}-go-runsim-binary - - name: test after import + - name: test-sim-after-import run: | - make test-sim-import-export + make test-sim-after-import test-sim-multi-seed-short: runs-on: ubuntu-latest diff --git a/CHANGELOG.md b/CHANGELOG.md index ce320d48f65d..162c3bbea90a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -99,6 +99,7 @@ types (eg. keys) to the `auth` module internal amino codec. * (rest) [\#5906](https://github.com/cosmos/cosmos-sdk/pull/5906) Fix an issue that make some REST calls panic when sending invalid or incomplete requests. * (x/genutil) [\#5938](https://github.com/cosmos/cosmos-sdk/pull/5938) Fix `InitializeNodeValidatorFiles` error handling. +* (x/staking) [\#5949](https://github.com/cosmos/cosmos-sdk/pull/5949) Skip staking `HistoricalInfoKey` in simulations as headers are not exported. * (x/auth) [\#5950](https://github.com/cosmos/cosmos-sdk/pull/5950) Fix `IncrementSequenceDecorator` to use is `IsReCheckTx` instead of `IsCheckTx` to allow account sequence incrementing. ### State Machine Breaking diff --git a/simapp/app.go b/simapp/app.go index e9c32a713918..90e75741399b 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -236,7 +236,7 @@ func NewSimApp( // During begin block slashing happens after distr.BeginBlocker so that // there is nothing left over in the validator fee pool, so as to keep the // CanWithdrawInvariant invariant. - app.mm.SetOrderBeginBlockers(upgrade.ModuleName, mint.ModuleName, distr.ModuleName, slashing.ModuleName, evidence.ModuleName) + app.mm.SetOrderBeginBlockers(upgrade.ModuleName, mint.ModuleName, distr.ModuleName, slashing.ModuleName, evidence.ModuleName, staking.ModuleName) app.mm.SetOrderEndBlockers(crisis.ModuleName, gov.ModuleName, staking.ModuleName) // NOTE: The genutils moodule must occur after staking so that pools are diff --git a/simapp/sim_test.go b/simapp/sim_test.go index 6053ff83cc75..bcfb64398717 100644 --- a/simapp/sim_test.go +++ b/simapp/sim_test.go @@ -148,6 +148,7 @@ func TestAppImportExport(t *testing.T) { {app.keys[staking.StoreKey], newApp.keys[staking.StoreKey], [][]byte{ staking.UnbondingQueueKey, staking.RedelegationQueueKey, staking.ValidatorQueueKey, + staking.HistoricalInfoKey, }}, // ordering may change but it doesn't matter {app.keys[slashing.StoreKey], newApp.keys[slashing.StoreKey], [][]byte{}}, {app.keys[mint.StoreKey], newApp.keys[mint.StoreKey], [][]byte{}}, diff --git a/store/types/utils.go b/store/types/utils.go index 8d4c83735460..8cfc2921eab5 100644 --- a/store/types/utils.go +++ b/store/types/utils.go @@ -38,20 +38,17 @@ func DiffKVStores(a KVStore, b KVStore, prefixesToSkip [][]byte) (kvAs, kvBs []t kvB = tmkv.Pair{Key: iterB.Key(), Value: iterB.Value()} iterB.Next() } - if !bytes.Equal(kvA.Key, kvB.Key) { - kvAs = append(kvAs, kvA) - kvBs = append(kvBs, kvB) - continue // no need to compare the value - } compareValue := true for _, prefix := range prefixesToSkip { // Skip value comparison if we matched a prefix - if bytes.Equal(kvA.Key[:len(prefix)], prefix) { + if bytes.HasPrefix(kvA.Key, prefix) || bytes.HasPrefix(kvB.Key, prefix) { compareValue = false + break } } - if compareValue && !bytes.Equal(kvA.Value, kvB.Value) { + + if compareValue && (!bytes.Equal(kvA.Key, kvB.Key) || !bytes.Equal(kvA.Value, kvB.Value)) { kvAs = append(kvAs, kvA) kvBs = append(kvBs, kvB) } diff --git a/x/staking/alias.go b/x/staking/alias.go index 1b7c78772f73..3568daebe2cc 100644 --- a/x/staking/alias.go +++ b/x/staking/alias.go @@ -12,7 +12,6 @@ const ( DefaultParamspace = keeper.DefaultParamspace ModuleName = types.ModuleName StoreKey = types.StoreKey - TStoreKey = types.TStoreKey QuerierRoute = types.QuerierRoute RouterKey = types.RouterKey DefaultUnbondingTime = types.DefaultUnbondingTime diff --git a/x/staking/genesis.go b/x/staking/genesis.go index 8a2ecce10740..76ecf0c5c827 100644 --- a/x/staking/genesis.go +++ b/x/staking/genesis.go @@ -144,10 +144,6 @@ func InitGenesis( // GenesisState will contain the pool, params, validators, and bonds found in // the keeper. func ExportGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState { - params := keeper.GetParams(ctx) - lastTotalPower := keeper.GetLastTotalPower(ctx) - validators := keeper.GetAllValidators(ctx) - delegations := keeper.GetAllDelegations(ctx) var unbondingDelegations []types.UnbondingDelegation keeper.IterateUnbondingDelegations(ctx, func(_ int64, ubd types.UnbondingDelegation) (stop bool) { unbondingDelegations = append(unbondingDelegations, ubd) @@ -165,11 +161,11 @@ func ExportGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState { }) return types.GenesisState{ - Params: params, - LastTotalPower: lastTotalPower, + Params: keeper.GetParams(ctx), + LastTotalPower: keeper.GetLastTotalPower(ctx), LastValidatorPowers: lastValidatorPowers, - Validators: validators, - Delegations: delegations, + Validators: keeper.GetAllValidators(ctx), + Delegations: keeper.GetAllDelegations(ctx), UnbondingDelegations: unbondingDelegations, Redelegations: redelegations, Exported: true, diff --git a/x/staking/keeper/historical_info.go b/x/staking/keeper/historical_info.go index 2ce0aee7dbcc..01ae38cc4092 100644 --- a/x/staking/keeper/historical_info.go +++ b/x/staking/keeper/historical_info.go @@ -36,6 +36,32 @@ func (k Keeper) DeleteHistoricalInfo(ctx sdk.Context, height int64) { store.Delete(key) } +// IterateHistoricalInfo provides an interator over all stored HistoricalInfo +// objects. For each HistoricalInfo object, cb will be called. If the cb returns +// true, the iterator will close and stop. +func (k Keeper) IterateHistoricalInfo(ctx sdk.Context, cb func(types.HistoricalInfo) bool) { + store := ctx.KVStore(k.storeKey) + iterator := sdk.KVStorePrefixIterator(store, types.HistoricalInfoKey) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + histInfo := types.MustUnmarshalHistoricalInfo(k.cdc, iterator.Value()) + if cb(histInfo) { + break + } + } +} + +// GetAllHistoricalInfo returns all stored HistoricalInfo objects. +func (k Keeper) GetAllHistoricalInfo(ctx sdk.Context) []types.HistoricalInfo { + var infos []types.HistoricalInfo + k.IterateHistoricalInfo(ctx, func(histInfo types.HistoricalInfo) bool { + infos = append(infos, histInfo) + return false + }) + return infos +} + // TrackHistoricalInfo saves the latest historical-info and deletes the oldest // heights that are below pruning height func (k Keeper) TrackHistoricalInfo(ctx sdk.Context) { diff --git a/x/staking/keeper/historical_info_test.go b/x/staking/keeper/historical_info_test.go index 3a3f1100592b..37e3b7237f58 100644 --- a/x/staking/keeper/historical_info_test.go +++ b/x/staking/keeper/historical_info_test.go @@ -114,3 +114,32 @@ func TestTrackHistoricalInfo(t *testing.T) { require.False(t, found, "GetHistoricalInfo did not prune first prune height") require.Equal(t, types.HistoricalInfo{}, recv, "GetHistoricalInfo at height 5 is not empty after prune") } + +func TestGetAllHistoricalInfo(t *testing.T) { + _, app, ctx := createTestInput() + + addrDels := simapp.AddTestAddrsIncremental(app, ctx, 50, sdk.NewInt(0)) + addrVals := simapp.ConvertAddrsToValAddrs(addrDels) + + valSet := []types.Validator{ + types.NewValidator(addrVals[0], PKs[0], types.Description{}), + types.NewValidator(addrVals[1], PKs[1], types.Description{}), + } + + header1 := abci.Header{ChainID: "HelloChain", Height: 10} + header2 := abci.Header{ChainID: "HelloChain", Height: 11} + header3 := abci.Header{ChainID: "HelloChain", Height: 12} + + hist1 := types.HistoricalInfo{Header: header1, Valset: valSet} + hist2 := types.HistoricalInfo{Header: header2, Valset: valSet} + hist3 := types.HistoricalInfo{Header: header3, Valset: valSet} + + expHistInfos := []types.HistoricalInfo{hist1, hist2, hist3} + + for i, hi := range expHistInfos { + app.StakingKeeper.SetHistoricalInfo(ctx, int64(10+i), hi) + } + + infos := app.StakingKeeper.GetAllHistoricalInfo(ctx) + require.Equal(t, expHistInfos, infos) +} diff --git a/x/staking/keeper/keeper.go b/x/staking/keeper/keeper.go index feddaf3b96f8..c4f19286597e 100644 --- a/x/staking/keeper/keeper.go +++ b/x/staking/keeper/keeper.go @@ -37,6 +37,7 @@ func NewKeeper( cdc codec.Marshaler, key sdk.StoreKey, bk types.BankKeeper, sk types.SupplyKeeper, ps paramtypes.Subspace, ) Keeper { + // set KeyTable if it has not already been set if !ps.HasKeyTable() { ps = ps.WithKeyTable(ParamKeyTable()) } diff --git a/x/staking/simulation/decoder.go b/x/staking/simulation/decoder.go index 86f1cecc9e00..efd8cb917e42 100644 --- a/x/staking/simulation/decoder.go +++ b/x/staking/simulation/decoder.go @@ -51,6 +51,12 @@ func DecodeStore(cdc *codec.Codec, kvA, kvB tmkv.Pair) string { cdc.MustUnmarshalBinaryBare(kvB.Value, &redB) return fmt.Sprintf("%v\n%v", redA, redB) + case bytes.Equal(kvA.Key[:1], types.HistoricalInfoKey): + var histInfoA, histInfoB types.HistoricalInfo + cdc.MustUnmarshalBinaryBare(kvA.Value, &histInfoA) + cdc.MustUnmarshalBinaryBare(kvB.Value, &histInfoB) + return fmt.Sprintf("%v\n%v", histInfoA, histInfoB) + default: panic(fmt.Sprintf("invalid staking key prefix %X", kvA.Key[:1])) } diff --git a/x/staking/simulation/decoder_test.go b/x/staking/simulation/decoder_test.go index 40dd39710e84..813f7fc74a6f 100644 --- a/x/staking/simulation/decoder_test.go +++ b/x/staking/simulation/decoder_test.go @@ -7,6 +7,7 @@ import ( "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto/ed25519" tmkv "github.com/tendermint/tendermint/libs/kv" @@ -38,6 +39,7 @@ func TestDecodeStore(t *testing.T) { del := types.NewDelegation(delAddr1, valAddr1, sdk.OneDec()) ubd := types.NewUnbondingDelegation(delAddr1, valAddr1, 15, bondTime, sdk.OneInt()) red := types.NewRedelegation(delAddr1, valAddr1, valAddr1, 12, bondTime, sdk.OneInt(), sdk.OneDec()) + histInfo := types.NewHistoricalInfo(abci.Header{ChainID: "gaia", Height: 10, Time: bondTime}, types.Validators{val}) kvPairs := tmkv.Pairs{ tmkv.Pair{Key: types.LastTotalPowerKey, Value: cdc.MustMarshalBinaryBare(sdk.OneInt())}, @@ -46,6 +48,7 @@ func TestDecodeStore(t *testing.T) { tmkv.Pair{Key: types.GetDelegationKey(delAddr1, valAddr1), Value: cdc.MustMarshalBinaryBare(del)}, tmkv.Pair{Key: types.GetUBDKey(delAddr1, valAddr1), Value: cdc.MustMarshalBinaryBare(ubd)}, tmkv.Pair{Key: types.GetREDKey(delAddr1, valAddr1, valAddr1), Value: cdc.MustMarshalBinaryBare(red)}, + tmkv.Pair{Key: types.GetHistoricalInfoKey(10), Value: cdc.MustMarshalBinaryBare(histInfo)}, tmkv.Pair{Key: []byte{0x99}, Value: []byte{0x99}}, } @@ -59,6 +62,7 @@ func TestDecodeStore(t *testing.T) { {"Delegation", fmt.Sprintf("%v\n%v", del, del)}, {"UnbondingDelegation", fmt.Sprintf("%v\n%v", ubd, ubd)}, {"Redelegation", fmt.Sprintf("%v\n%v", red, red)}, + {"HistoricalInfo", fmt.Sprintf("%v\n%v", histInfo, histInfo)}, {"other", ""}, } for i, tt := range tests { diff --git a/x/staking/types/keys.go b/x/staking/types/keys.go index d278b50db3e7..dc4d027b66f2 100644 --- a/x/staking/types/keys.go +++ b/x/staking/types/keys.go @@ -15,9 +15,6 @@ const ( // StoreKey is the string store representation StoreKey = ModuleName - // TStoreKey is the string transient store representation - TStoreKey = "transient_" + ModuleName - // QuerierRoute is the querier route for the staking module QuerierRoute = ModuleName From a1feca39c205e7564b77112e8b77def215615761 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Wed, 8 Apr 2020 11:38:28 +0200 Subject: [PATCH 523/529] Enter the new keyring interface (#5904) crypto/keyring: `Keybase` interface gives way to its successor: `Keyring`. `LegacyKeybase` interface is added in order to guarantee limited backward compatibility with the old `Keybase` interface for the sole purpose of migrating keys across the new keyring backends. The package no longer depends on the `github.com/types.Config` singleton. `SupportedAlgos` and `SupportedLedgerAlgos` methods have been removed. The keyring just fails when trying to perform an action with an unsupported algorithm. crypto/ subdirs reorganization: `crypto/keys/hd` was moved to `crypto/hd`, which now groups together all HD wallets related types and utilities. client/input: * Removal of unnecessary `GetCheckPassword`, `PrintPrefixed` functions. * `GetConfirmation`'s signature changed to take in a io.Writer for better integration with `cobra.Command` types. client/context: * In-memory keyring is allocated in the context when `--gen-only` flag is passed in. `GetFromFields` does no longer silently allocate a keyring, it takes one as argument. Co-authored with @jgimeno Co-authored-by: Jonathan Gimeno --- CHANGELOG.md | 23 +- client/context/context.go | 43 +- client/context/context_test.go | 27 +- client/input/input.go | 39 +- client/keys/add.go | 48 +- client/keys/add_ledger_test.go | 16 +- client/keys/add_test.go | 28 +- client/keys/codec_test.go | 24 +- client/keys/delete.go | 40 +- client/keys/delete_test.go | 71 +- client/keys/export.go | 8 +- client/keys/export_test.go | 9 +- client/keys/import.go | 2 +- client/keys/import_test.go | 4 +- client/keys/list.go | 2 +- client/keys/list_test.go | 9 +- client/keys/migrate.go | 22 +- client/keys/migrate_test.go | 6 +- client/keys/mnemonic.go | 2 +- client/keys/root_test.go | 2 + client/keys/show.go | 8 +- client/keys/show_test.go | 18 +- client/tx/factory.go | 8 +- client/tx/tx.go | 4 +- crypto/armor_test.go | 11 +- crypto/hd/algo.go | 68 ++ crypto/hd/algo_test.go | 16 + crypto/hd/doc.go | 12 + crypto/{keys => }/hd/fundraiser_test.go | 18 +- crypto/{keys => }/hd/hdpath.go | 17 +- crypto/{keys => }/hd/hdpath_test.go | 85 +- crypto/{keys/hd => hd/testdata}/test.json | 0 crypto/keyring/base_keybase.go | 234 ----- crypto/keyring/codec.go | 2 +- crypto/keyring/doc.go | 4 +- crypto/keyring/info.go | 26 +- crypto/keyring/keybase.go | 76 -- crypto/keyring/keyring.go | 677 +++++++++------ crypto/keyring/keyring_ledger_test.go | 128 +++ crypto/keyring/keyring_test.go | 996 +++++++++++++--------- crypto/keyring/legacy.go | 52 +- crypto/keyring/legacy_test.go | 15 + crypto/keyring/options.go | 39 - crypto/keyring/signing_algorithms.go | 41 +- crypto/keyring/signing_algorithms_test.go | 71 ++ crypto/keyring/types.go | 10 +- crypto/keyring/types_test.go | 4 +- crypto/ledger_mock.go | 2 +- crypto/ledger_secp256k1.go | 2 +- crypto/ledger_test.go | 2 +- server/init.go | 34 +- server/init_test.go | 12 +- x/auth/client/cli/tx_multisign.go | 4 +- x/auth/client/tx.go | 4 +- x/auth/types/params_test.go | 3 +- x/auth/types/txbuilder.go | 14 +- x/genutil/client/cli/gentx.go | 4 +- 57 files changed, 1751 insertions(+), 1395 deletions(-) create mode 100644 crypto/hd/algo.go create mode 100644 crypto/hd/algo_test.go create mode 100644 crypto/hd/doc.go rename crypto/{keys => }/hd/fundraiser_test.go (78%) rename crypto/{keys => }/hd/hdpath.go (91%) rename crypto/{keys => }/hd/hdpath_test.go (64%) rename crypto/{keys/hd => hd/testdata}/test.json (100%) delete mode 100644 crypto/keyring/base_keybase.go delete mode 100644 crypto/keyring/keybase.go create mode 100644 crypto/keyring/keyring_ledger_test.go delete mode 100644 crypto/keyring/options.go create mode 100644 crypto/keyring/signing_algorithms_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 162c3bbea90a..84555f11f9da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -70,19 +70,22 @@ and provided directly the IAVL store. * (modules) [\#5572](https://github.com/cosmos/cosmos-sdk/pull/5572) Move account balance logic and APIs from `x/auth` to `x/bank`. * (types) [\#5533](https://github.com/cosmos/cosmos-sdk/pull/5533) Refactored `AppModuleBasic` and `AppModuleGenesis` to now accept a `codec.JSONMarshaler` for modular serialization of genesis state. -* (crypto/keyring) [\#5735](https://github.com/cosmos/cosmos-sdk/pull/5735) Keyring's `Update()` function is now no-op. * (types/rest) [\#5779](https://github.com/cosmos/cosmos-sdk/pull/5779) Drop unused Parse{Int64OrReturnBadRequest,QueryParamBool}() functions. * (keys) [\#5820](https://github.com/cosmos/cosmos-sdk/pull/5820/) Removed method CloseDB from Keybase interface. * (baseapp) [\#5837](https://github.com/cosmos/cosmos-sdk/issues/5837) Transaction simulation now returns a `SimulationResponse` which contains the `GasInfo` and `Result` from the execution. -* (crypto/keyring) [\#5866](https://github.com/cosmos/cosmos-sdk/pull/5866) Move `Keyring` and `Keybase` implementations and their associated types from `crypto/keys/` to `crypto/keyring/`. -* (crypto) [\#5880](https://github.com/cosmos/cosmos-sdk/pull/5880) Merge `crypto/keys/mintkey` into `crypto`. -* (crypto/keyring) [\#5858](https://github.com/cosmos/cosmos-sdk/pull/5858) Make Keyring store keys by name and address's hexbytes representation. -* (crypto/keyring) [\#5889](https://github.com/cosmos/cosmos-sdk/pull/5889) Deprecate old keybase implementation: - - Remove `Update` from the `Keybase` interface. - - `NewKeyring()` now accepts a new backend: `MemoryBackend`. - - `New()` has been renamed to`NewLegacy()`, which now returns a `LegacyKeybase` type that only allows migration of keys from the legacy keybase to a new keyring. +* (client/input) [\#5904](https://github.com/cosmos/cosmos-sdk/pull/5904) Removal of unnecessary `GetCheckPassword`, `PrintPrefixed` functions. * (client/keys) [\#5889](https://github.com/cosmos/cosmos-sdk/pull/5889) Rename `NewKeyBaseFromDir()` -> `NewLegacyKeyBaseFromDir()`. +* (crypto) [\#5880](https://github.com/cosmos/cosmos-sdk/pull/5880) Merge `crypto/keys/mintkey` into `crypto`. +* (crypto/hd) [\#5904](https://github.com/cosmos/cosmos-sdk/pull/5904) `crypto/keys/hd` moved to `crypto/hd`. +* (crypto/keyring): + - [\#5866](https://github.com/cosmos/cosmos-sdk/pull/5866) Rename `crypto/keys/` to `crypto/keyring/`. + - [\#5904](https://github.com/cosmos/cosmos-sdk/pull/5904) `Keybase` -> `Keyring` interfaces migration. `LegacyKeybase` interface is added in order +to guarantee limited backward compatibility with the old Keybase interface for the sole purpose of migrating keys across the new keyring backends. `NewLegacy` +constructor is provided [\#5889](https://github.com/cosmos/cosmos-sdk/pull/5889) to allow for smooth migration of keys from the legacy LevelDB based implementation +to new keyring backends. Plus, the package and the new keyring no longer depends on the sdk.Config singleton. Please consult the package documentation for more +information on how to implement the new `Keyring` interface. + - [\#5858](https://github.com/cosmos/cosmos-sdk/pull/5858) Make Keyring store keys by name and address's hexbytes representation. ### Features @@ -92,8 +95,8 @@ to now accept a `codec.JSONMarshaler` for modular serialization of genesis state * (types) [\#5741](https://github.com/cosmos/cosmos-sdk/issues/5741) Prevent ChainAnteDecorators() from panicking when empty AnteDecorator slice is supplied. * (modules) [\#5569](https://github.com/cosmos/cosmos-sdk/issues/5569) `InitGenesis`, for the relevant modules, now ensures module accounts exist. -* (crypto/keyring) [\#5844](https://github.com/cosmos/cosmos-sdk/pull/5844) Keybase/Keyring `Sign()` methods no longer decode amino signatures -when method receivers are offline/multisig keys. +* (crypto/keyring) [\#5844](https://github.com/cosmos/cosmos-sdk/pull/5844) `Keyring.Sign()` methods no longer decode amino signatures when method receivers +are offline/multisig keys. * (x/auth) [\#5892](https://github.com/cosmos/cosmos-sdk/pull/5892) Add `RegisterKeyTypeCodec` to register new types (eg. keys) to the `auth` module internal amino codec. * (rest) [\#5906](https://github.com/cosmos/cosmos-sdk/pull/5906) Fix an issue that make some REST calls panic when sending diff --git a/client/context/context.go b/client/context/context.go index 5e536251b0b6..c908a2044a82 100644 --- a/client/context/context.go +++ b/client/context/context.go @@ -25,8 +25,8 @@ type CLIContext struct { Client rpcclient.Client ChainID string Marshaler codec.Marshaler - Keybase keyring.Keybase Input io.Reader + Keyring keyring.Keyring Output io.Writer OutputFormat string Height int64 @@ -58,8 +58,19 @@ func NewCLIContextWithInputAndFrom(input io.Reader, from string) CLIContext { var nodeURI string var rpc rpcclient.Client + homedir := viper.GetString(flags.FlagHome) genOnly := viper.GetBool(flags.FlagGenerateOnly) - fromAddress, fromName, err := GetFromFields(input, from, genOnly) + backend := viper.GetString(flags.FlagKeyringBackend) + if len(backend) == 0 { + backend = keyring.BackendMemory + } + + keyring, err := newKeyringFromFlags(backend, homedir, input, genOnly) + if err != nil { + panic(fmt.Errorf("couldn't acquire keyring: %v", err)) + } + + fromAddress, fromName, err := GetFromFields(keyring, from, genOnly) if err != nil { fmt.Printf("failed to get from fields: %v\n", err) os.Exit(1) @@ -84,9 +95,10 @@ func NewCLIContextWithInputAndFrom(input io.Reader, from string) CLIContext { Output: os.Stdout, NodeURI: nodeURI, From: viper.GetString(flags.FlagFrom), + Keyring: keyring, OutputFormat: viper.GetString(cli.OutputFlag), Height: viper.GetInt64(flags.FlagHeight), - HomeDir: viper.GetString(flags.FlagHome), + HomeDir: homedir, TrustNode: viper.GetBool(flags.FlagTrustNode), UseLedger: viper.GetBool(flags.FlagUseLedger), BroadcastMode: viper.GetString(flags.FlagBroadcastMode), @@ -129,6 +141,12 @@ func NewCLIContextWithInput(input io.Reader) CLIContext { return NewCLIContextWithInputAndFrom(input, viper.GetString(flags.FlagFrom)) } +// WithKeyring returns a copy of the context with an updated keyring. +func (ctx CLIContext) WithKeyring(k keyring.Keyring) CLIContext { + ctx.Keyring = k + return ctx +} + // WithInput returns a copy of the context with an updated input. func (ctx CLIContext) WithInput(r io.Reader) CLIContext { ctx.Input = r @@ -307,7 +325,7 @@ func (ctx CLIContext) PrintOutput(toPrint interface{}) error { // GetFromFields returns a from account address and Keybase name given either // an address or key name. If genOnly is true, only a valid Bech32 cosmos // address is returned. -func GetFromFields(input io.Reader, from string, genOnly bool) (sdk.AccAddress, string, error) { +func GetFromFields(kr keyring.Keyring, from string, genOnly bool) (sdk.AccAddress, string, error) { if from == "" { return nil, "", nil } @@ -321,20 +339,14 @@ func GetFromFields(input io.Reader, from string, genOnly bool) (sdk.AccAddress, return addr, "", nil } - keybase, err := keyring.NewKeyring(sdk.KeyringServiceName(), - viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), input) - if err != nil { - return nil, "", err - } - var info keyring.Info if addr, err := sdk.AccAddressFromBech32(from); err == nil { - info, err = keybase.GetByAddress(addr) + info, err = kr.KeyByAddress(addr) if err != nil { return nil, "", err } } else { - info, err = keybase.Get(from) + info, err = kr.Key(from) if err != nil { return nil, "", err } @@ -342,3 +354,10 @@ func GetFromFields(input io.Reader, from string, genOnly bool) (sdk.AccAddress, return info.GetAddress(), info.GetName(), nil } + +func newKeyringFromFlags(backend, homedir string, input io.Reader, genOnly bool) (keyring.Keyring, error) { + if genOnly { + return keyring.New(sdk.KeyringServiceName(), keyring.BackendMemory, homedir, input) + } + return keyring.New(sdk.KeyringServiceName(), backend, homedir, input) +} diff --git a/client/context/context_test.go b/client/context/context_test.go index 3b6ea0e71af5..7429fc18605d 100644 --- a/client/context/context_test.go +++ b/client/context/context_test.go @@ -1,13 +1,16 @@ -package context +package context_test import ( + "os" "testing" + "github.com/cosmos/cosmos-sdk/crypto/keyring" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/spf13/viper" "github.com/stretchr/testify/require" + "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/flags" ) @@ -15,7 +18,7 @@ func TestCLIContext_WithOffline(t *testing.T) { viper.Set(flags.FlagOffline, true) viper.Set(flags.FlagNode, "tcp://localhost:26657") - ctx := NewCLIContext() + ctx := context.NewCLIContext() require.True(t, ctx.Offline) require.Nil(t, ctx.Client) @@ -24,7 +27,7 @@ func TestCLIContext_WithOffline(t *testing.T) { viper.Set(flags.FlagOffline, false) viper.Set(flags.FlagNode, "tcp://localhost:26657") - ctx = NewCLIContext() + ctx = context.NewCLIContext() require.False(t, ctx.Offline) require.NotNil(t, ctx.Client) } @@ -59,10 +62,26 @@ func TestCLIContext_WithGenOnly(t *testing.T) { for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { - ctx := NewCLIContextWithFrom(tt.from) + ctx := context.NewCLIContextWithFrom(tt.from) require.Equal(t, tt.expectedFromAddr, ctx.FromAddress) require.Equal(t, tt.expectedFromName, ctx.FromName) }) } } + +func TestCLIContext_WithKeyring(t *testing.T) { + viper.Set(flags.FlagGenerateOnly, true) + ctx := context.NewCLIContextWithFrom("cosmos1q7380u26f7ntke3facjmynajs4umlr329vr4ja") + require.NotNil(t, ctx.Keyring) + kr := ctx.Keyring + ctx = ctx.WithKeyring(nil) + require.Nil(t, ctx.Keyring) + ctx = ctx.WithKeyring(kr) + require.Equal(t, kr, ctx.Keyring) +} + +func TestMain(m *testing.M) { + viper.Set(flags.FlagKeyringBackend, keyring.BackendMemory) + os.Exit(m.Run()) +} diff --git a/client/input/input.go b/client/input/input.go index 73dd822fd369..4e36bbe5192a 100644 --- a/client/input/input.go +++ b/client/input/input.go @@ -2,8 +2,8 @@ package input import ( "bufio" - "errors" "fmt" + "io" "os" "strings" @@ -36,40 +36,15 @@ func GetPassword(prompt string, buf *bufio.Reader) (pass string, err error) { return pass, nil } -// GetCheckPassword will prompt for a password twice to verify they -// match (for creating a new password). -// It enforces the password length. Only parses password once if -// input is piped in. -func GetCheckPassword(prompt, prompt2 string, buf *bufio.Reader) (string, error) { - // simple read on no-tty - if !inputIsTty() { - return GetPassword(prompt, buf) - } - - // TODO: own function??? - pass, err := GetPassword(prompt, buf) - if err != nil { - return "", err - } - pass2, err := GetPassword(prompt2, buf) - if err != nil { - return "", err - } - if pass != pass2 { - return "", errors.New("passphrases don't match") - } - return pass, nil -} - // GetConfirmation will request user give the confirmation from stdin. // "y", "Y", "yes", "YES", and "Yes" all count as confirmations. // If the input is not recognized, it returns false and a nil error. -func GetConfirmation(prompt string, buf *bufio.Reader) (bool, error) { +func GetConfirmation(prompt string, r *bufio.Reader, w io.Writer) (bool, error) { if inputIsTty() { fmt.Printf("%s [y/N]: ", prompt) } - response, err := readLineFromBuf(buf) + response, err := readLineFromBuf(r) if err != nil { return false, err } @@ -90,7 +65,7 @@ func GetConfirmation(prompt string, buf *bufio.Reader) (bool, error) { // GetString simply returns the trimmed string output of a given reader. func GetString(prompt string, buf *bufio.Reader) (string, error) { if inputIsTty() && prompt != "" { - PrintPrefixed(prompt) + fmt.Fprintf(os.Stderr, "> %s\n", prompt) } out, err := readLineFromBuf(buf) @@ -117,9 +92,3 @@ func readLineFromBuf(buf *bufio.Reader) (string, error) { } return strings.TrimSpace(pass), nil } - -// PrintPrefixed prints a string with > prefixed for use in prompts. -func PrintPrefixed(msg string) { - msg = fmt.Sprintf("> %s\n", msg) - fmt.Fprint(os.Stderr, msg) -} diff --git a/client/keys/add.go b/client/keys/add.go index 1170c714ee3f..c6a396e5d3a6 100644 --- a/client/keys/add.go +++ b/client/keys/add.go @@ -12,6 +12,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/input" + "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/crypto/keyring" sdk "github.com/cosmos/cosmos-sdk/types" @@ -27,6 +28,7 @@ const ( flagInteractive = "interactive" flagRecover = "recover" flagNoBackup = "no-backup" + flagCoinType = "coin-type" flagAccount = "account" flagIndex = "index" flagMultisig = "multisig" @@ -73,19 +75,20 @@ the flag --nosort is set. cmd.Flags().Bool(flagNoBackup, false, "Don't print out seed phrase (if others are watching the terminal)") cmd.Flags().Bool(flags.FlagDryRun, false, "Perform action, but don't add key to local keystore") cmd.Flags().String(flagHDPath, "", "Manual HD Path derivation (overrides BIP44 config)") + cmd.Flags().Uint32(flagCoinType, sdk.CoinType, "coin type number for HD derivation") cmd.Flags().Uint32(flagAccount, 0, "Account number for HD derivation") cmd.Flags().Uint32(flagIndex, 0, "Address index number for HD derivation") cmd.Flags().Bool(flags.FlagIndentResponse, false, "Add indent to JSON response") - cmd.Flags().String(flagKeyAlgo, string(keyring.Secp256k1), "Key signing algorithm to generate keys for") + cmd.Flags().String(flagKeyAlgo, string(hd.Secp256k1Type), "Key signing algorithm to generate keys for") return cmd } -func getKeybase(transient bool, buf io.Reader) (keyring.Keybase, error) { +func getKeybase(transient bool, buf io.Reader) (keyring.Keyring, error) { if transient { - return keyring.NewKeyring(sdk.KeyringServiceName(), keyring.BackendMemory, viper.GetString(flags.FlagHome), buf) + return keyring.New(sdk.KeyringServiceName(), keyring.BackendMemory, viper.GetString(flags.FlagHome), buf) } - return keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), buf) + return keyring.New(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), buf) } func runAddCmd(cmd *cobra.Command, args []string) error { @@ -107,7 +110,7 @@ input output - armor encrypted private key (saved to file) */ -func RunAddCmd(cmd *cobra.Command, args []string, kb keyring.Keybase, inBuf *bufio.Reader) error { +func RunAddCmd(cmd *cobra.Command, args []string, kb keyring.Keyring, inBuf *bufio.Reader) error { var err error name := args[0] @@ -115,25 +118,27 @@ func RunAddCmd(cmd *cobra.Command, args []string, kb keyring.Keybase, inBuf *buf interactive := viper.GetBool(flagInteractive) showMnemonic := !viper.GetBool(flagNoBackup) - algo := keyring.SigningAlgo(viper.GetString(flagKeyAlgo)) - if algo == keyring.SigningAlgo("") { - algo = keyring.Secp256k1 - } - if !keyring.IsSupportedAlgorithm(kb.SupportedAlgos(), algo) { - return keyring.ErrUnsupportedSigningAlgo + algo, err := keyring.NewSigningAlgoFromString(viper.GetString(flagKeyAlgo)) + if err != nil { + algo = hd.Secp256k1 } if !viper.GetBool(flags.FlagDryRun) { - _, err = kb.Get(name) + _, err = kb.Key(name) if err == nil { // account exists, ask for user confirmation - response, err2 := input.GetConfirmation(fmt.Sprintf("override the existing name %s", name), inBuf) + response, err2 := input.GetConfirmation(fmt.Sprintf("override the existing name %s", name), inBuf, cmd.ErrOrStderr()) if err2 != nil { return err2 } if !response { return errors.New("aborted") } + + err2 = kb.Delete(name) + if err2 != nil { + return err2 + } } multisigKeys := viper.GetStringSlice(flagMultisig) @@ -146,7 +151,7 @@ func RunAddCmd(cmd *cobra.Command, args []string, kb keyring.Keybase, inBuf *buf } for _, keyname := range multisigKeys { - k, err := kb.Get(keyname) + k, err := kb.Key(keyname) if err != nil { return err } @@ -161,7 +166,7 @@ func RunAddCmd(cmd *cobra.Command, args []string, kb keyring.Keybase, inBuf *buf } pk := multisig.NewPubKeyMultisigThreshold(multisigThreshold, pks) - if _, err := kb.CreateMulti(name, pk); err != nil { + if _, err := kb.SaveMultisig(name, pk); err != nil { return err } @@ -175,13 +180,14 @@ func RunAddCmd(cmd *cobra.Command, args []string, kb keyring.Keybase, inBuf *buf if err != nil { return err } - _, err = kb.CreateOffline(name, pk, algo) + _, err = kb.SavePubKey(name, pk, algo.Name()) if err != nil { return err } return nil } + coinType := uint32(viper.GetInt(flagCoinType)) account := uint32(viper.GetInt(flagAccount)) index := uint32(viper.GetInt(flagIndex)) @@ -189,7 +195,7 @@ func RunAddCmd(cmd *cobra.Command, args []string, kb keyring.Keybase, inBuf *buf var hdPath string if useBIP44 { - hdPath = keyring.CreateHDPath(account, index).String() + hdPath = hd.CreateHDPath(coinType, account, index).String() } else { hdPath = viper.GetString(flagHDPath) } @@ -201,12 +207,8 @@ func RunAddCmd(cmd *cobra.Command, args []string, kb keyring.Keybase, inBuf *buf return errors.New("cannot set custom bip32 path with ledger") } - if !keyring.IsSupportedAlgorithm(kb.SupportedAlgosLedger(), algo) { - return keyring.ErrUnsupportedSigningAlgo - } - bech32PrefixAccAddr := sdk.GetConfig().GetBech32AccountAddrPrefix() - info, err := kb.CreateLedger(name, keyring.Secp256k1, bech32PrefixAccAddr, account, index) + info, err := kb.SaveLedgerKey(name, hd.Secp256k1, bech32PrefixAccAddr, coinType, account, index) if err != nil { return err } @@ -269,7 +271,7 @@ func RunAddCmd(cmd *cobra.Command, args []string, kb keyring.Keybase, inBuf *buf } } - info, err := kb.CreateAccount(name, mnemonic, bip39Passphrase, DefaultKeyPass, hdPath, algo) + info, err := kb.NewAccount(name, mnemonic, bip39Passphrase, hdPath, algo) if err != nil { return err } diff --git a/client/keys/add_ledger_test.go b/client/keys/add_ledger_test.go index b21a0b1850d6..dc78c778a48f 100644 --- a/client/keys/add_ledger_test.go +++ b/client/keys/add_ledger_test.go @@ -41,6 +41,9 @@ func Test_runAddCmdLedgerWithCustomCoinType(t *testing.T) { t.Cleanup(kbCleanUp) viper.Set(flags.FlagHome, kbHome) viper.Set(flags.FlagUseLedger, true) + viper.Set(flagAccount, "0") + viper.Set(flagIndex, "0") + viper.Set(flagCoinType, "330") /// Test Text viper.Set(cli.OutputFlag, OutputFormatText) @@ -50,14 +53,14 @@ func Test_runAddCmdLedgerWithCustomCoinType(t *testing.T) { require.NoError(t, runAddCmd(cmd, []string{"keyname1"})) // Now check that it has been stored properly - kb, err := keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) + kb, err := keyring.New(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), kbHome, mockIn) require.NoError(t, err) require.NotNil(t, kb) t.Cleanup(func() { - kb.Delete("keyname1", "", false) + kb.Delete("keyname1") }) mockIn.Reset("test1234\n") - key1, err := kb.Get("keyname1") + key1, err := kb.Key("keyname1") require.NoError(t, err) require.NotNil(t, key1) @@ -90,17 +93,18 @@ func Test_runAddCmdLedger(t *testing.T) { viper.Set(cli.OutputFlag, OutputFormatText) // Now enter password mockIn.Reset("test1234\ntest1234\n") + viper.Set(flagCoinType, sdk.CoinType) require.NoError(t, runAddCmd(cmd, []string{"keyname1"})) // Now check that it has been stored properly - kb, err := keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), kbHome, mockIn) + kb, err := keyring.New(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), kbHome, mockIn) require.NoError(t, err) require.NotNil(t, kb) t.Cleanup(func() { - kb.Delete("keyname1", "", false) + kb.Delete("keyname1") }) mockIn.Reset("test1234\n") - key1, err := kb.Get("keyname1") + key1, err := kb.Key("keyname1") require.NoError(t, err) require.NotNil(t, key1) diff --git a/client/keys/add_test.go b/client/keys/add_test.go index 172d7d9e1ce6..5776aa8b0743 100644 --- a/client/keys/add_test.go +++ b/client/keys/add_test.go @@ -4,7 +4,6 @@ import ( "testing" "github.com/spf13/viper" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/libs/cli" @@ -17,36 +16,37 @@ import ( func Test_runAddCmdBasic(t *testing.T) { cmd := AddKeyCommand() - assert.NotNil(t, cmd) + require.NotNil(t, cmd) mockIn, _, _ := tests.ApplyMockIO(cmd) kbHome, kbCleanUp := tests.NewTestCaseDir(t) - assert.NotNil(t, kbHome) + require.NotNil(t, kbHome) t.Cleanup(kbCleanUp) viper.Set(flags.FlagHome, kbHome) viper.Set(cli.OutputFlag, OutputFormatText) + viper.Set(flags.FlagUseLedger, false) mockIn.Reset("y\n") - kb, err := keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), kbHome, mockIn) + kb, err := keyring.New(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), kbHome, mockIn) require.NoError(t, err) t.Cleanup(func() { - kb.Delete("keyname1", "", false) // nolint:errcheck - kb.Delete("keyname2", "", false) // nolint:errcheck + kb.Delete("keyname1") // nolint:errcheck + kb.Delete("keyname2") // nolint:errcheck }) - assert.NoError(t, runAddCmd(cmd, []string{"keyname1"})) + require.NoError(t, runAddCmd(cmd, []string{"keyname1"})) mockIn.Reset("N\n") - assert.Error(t, runAddCmd(cmd, []string{"keyname1"})) + require.Error(t, runAddCmd(cmd, []string{"keyname1"})) - assert.NoError(t, runAddCmd(cmd, []string{"keyname2"})) - assert.Error(t, runAddCmd(cmd, []string{"keyname2"})) + require.NoError(t, runAddCmd(cmd, []string{"keyname2"})) + require.Error(t, runAddCmd(cmd, []string{"keyname2"})) mockIn.Reset("y\n") - assert.NoError(t, runAddCmd(cmd, []string{"keyname2"})) + require.NoError(t, runAddCmd(cmd, []string{"keyname2"})) // test --dry-run - assert.NoError(t, runAddCmd(cmd, []string{"keyname4"})) - assert.Error(t, runAddCmd(cmd, []string{"keyname4"})) + require.NoError(t, runAddCmd(cmd, []string{"keyname4"})) + require.Error(t, runAddCmd(cmd, []string{"keyname4"})) viper.Set(flags.FlagDryRun, true) - assert.NoError(t, runAddCmd(cmd, []string{"keyname4"})) + require.NoError(t, runAddCmd(cmd, []string{"keyname4"})) } diff --git a/client/keys/codec_test.go b/client/keys/codec_test.go index 7aca4510f958..33f6103d1888 100644 --- a/client/keys/codec_test.go +++ b/client/keys/codec_test.go @@ -1,12 +1,12 @@ -package keys +package keys_test import ( - "fmt" - "reflect" + "bytes" "testing" "github.com/stretchr/testify/require" + "github.com/cosmos/cosmos-sdk/client/keys" "github.com/cosmos/cosmos-sdk/crypto/keyring" ) @@ -58,15 +58,9 @@ func TestMarshalJSON(t *testing.T) { for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { - got, err := MarshalJSON(tt.args.o) - if (err != nil) != tt.wantErr { - t.Errorf("MarshalJSON() error = %v, wantErr %v", err, tt.wantErr) - return - } - fmt.Printf("%s\n", got) - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("MarshalJSON() = %v, want %v", got, tt.want) - } + got, err := keys.MarshalJSON(tt.args.o) + require.Equal(t, tt.wantErr, err != nil) + require.True(t, bytes.Equal(got, tt.want)) }) } } @@ -94,10 +88,8 @@ func TestUnmarshalJSON(t *testing.T) { for idx, tt := range tests { idx, tt := idx, tt t.Run(tt.name, func(t *testing.T) { - if err := UnmarshalJSON(tt.args.bz, tt.args.ptr); (err != nil) != tt.wantErr { - t.Errorf("unmarshalJSON() error = %v, wantErr %v", err, tt.wantErr) - } - + err := keys.UnmarshalJSON(tt.args.bz, tt.args.ptr) + require.Equal(t, tt.wantErr, err != nil) // Confirm deserialized objects are the same require.Equal(t, data.Keys[idx], data.Answers[idx]) }) diff --git a/client/keys/delete.go b/client/keys/delete.go index 0c379e49bcaf..e05019699988 100644 --- a/client/keys/delete.go +++ b/client/keys/delete.go @@ -2,7 +2,6 @@ package keys import ( "bufio" - "errors" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/input" @@ -43,49 +42,36 @@ private keys stored in a ledger device cannot be deleted with the CLI. func runDeleteCmd(cmd *cobra.Command, args []string) error { buf := bufio.NewReader(cmd.InOrStdin()) - kb, err := keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), buf) + kb, err := keyring.New(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), buf) if err != nil { return err } for _, name := range args { - info, err := kb.Get(name) + info, err := kb.Key(name) if err != nil { return err } - if info.GetType() == keyring.TypeLedger || info.GetType() == keyring.TypeOffline { - // confirm deletion, unless -y is passed - if !viper.GetBool(flagYes) { - if err := confirmDeletion(buf); err != nil { - return err - } - } - - if err := kb.Delete(name, "", true); err != nil { + // confirm deletion, unless -y is passed + if !viper.GetBool(flagYes) { + if yes, err := input.GetConfirmation("Key reference will be deleted. Continue?", buf, cmd.ErrOrStderr()); err != nil { return err + } else if !yes { + continue } - cmd.PrintErrln("Public key reference deleted") - return nil } - // old password and skip flag arguments are ignored - if err := kb.Delete(name, "", true); err != nil { + if err := kb.Delete(name); err != nil { return err } + + if info.GetType() == keyring.TypeLedger || info.GetType() == keyring.TypeOffline { + cmd.PrintErrln("Public key reference deleted") + continue + } cmd.PrintErrln("Key deleted forever (uh oh!)") } return nil } - -func confirmDeletion(buf *bufio.Reader) error { - answer, err := input.GetConfirmation("Key reference will be deleted. Continue?", buf) - if err != nil { - return err - } - if !answer { - return errors.New("aborted") - } - return nil -} diff --git a/client/keys/delete_test.go b/client/keys/delete_test.go index 73db7faecb6a..3d2136a7252a 100644 --- a/client/keys/delete_test.go +++ b/client/keys/delete_test.go @@ -1,13 +1,13 @@ package keys import ( - "bufio" - "strings" "testing" "github.com/spf13/viper" "github.com/stretchr/testify/require" + "github.com/cosmos/cosmos-sdk/crypto/hd" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/tests" @@ -20,30 +20,25 @@ func Test_runDeleteCmd(t *testing.T) { yesF, _ := deleteKeyCommand.Flags().GetBool(flagYes) forceF, _ := deleteKeyCommand.Flags().GetBool(flagForce) + require.False(t, yesF) require.False(t, forceF) fakeKeyName1 := "runDeleteCmd_Key1" fakeKeyName2 := "runDeleteCmd_Key2" - kb, err := keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) - require.NoError(t, err) - t.Cleanup(func() { - kb.Delete("runDeleteCmd_Key1", "", false) // nolint:errcheck - kb.Delete("runDeleteCmd_Key2", "", false) // nolint:errcheck - - }) // Now add a temporary keybase kbHome, cleanUp := tests.NewTestCaseDir(t) t.Cleanup(cleanUp) viper.Set(flags.FlagHome, kbHome) // Now - kb, err = keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), kbHome, mockIn) + path := sdk.GetConfig().GetFullFundraiserPath() + backend := viper.GetString(flags.FlagKeyringBackend) + kb, err := keyring.New(sdk.KeyringServiceName(), backend, kbHome, mockIn) require.NoError(t, err) - _, err = kb.CreateAccount(fakeKeyName1, tests.TestMnemonic, "", "", "0", keyring.Secp256k1) + _, err = kb.NewAccount(fakeKeyName1, tests.TestMnemonic, "", path, hd.Secp256k1) require.NoError(t, err) - - _, err = kb.CreateAccount(fakeKeyName2, tests.TestMnemonic, "", "", "1", keyring.Secp256k1) + _, _, err = kb.NewMnemonic(fakeKeyName2, keyring.English, sdk.FullFundraiserPath, hd.Secp256k1) require.NoError(t, err) err = runDeleteCmd(deleteKeyCommand, []string{"blah"}) @@ -55,53 +50,21 @@ func Test_runDeleteCmd(t *testing.T) { require.Error(t, err) require.Equal(t, "EOF", err.Error()) - { - _, err = kb.Get(fakeKeyName1) - require.NoError(t, err) + _, err = kb.Key(fakeKeyName1) + require.NoError(t, err) - // Now there is a confirmation - viper.Set(flagYes, true) - require.NoError(t, runDeleteCmd(deleteKeyCommand, []string{fakeKeyName1})) + // Now there is a confirmation + viper.Set(flagYes, true) + require.NoError(t, runDeleteCmd(deleteKeyCommand, []string{fakeKeyName1})) - _, err = kb.Get(fakeKeyName1) - require.Error(t, err) // Key1 is gone - } + _, err = kb.Key(fakeKeyName1) + require.Error(t, err) // Key1 is gone viper.Set(flagYes, true) - _, err = kb.Get(fakeKeyName2) + _, err = kb.Key(fakeKeyName2) require.NoError(t, err) err = runDeleteCmd(deleteKeyCommand, []string{fakeKeyName2}) require.NoError(t, err) - _, err = kb.Get(fakeKeyName2) + _, err = kb.Key(fakeKeyName2) require.Error(t, err) // Key2 is gone } - -func Test_confirmDeletion(t *testing.T) { - type args struct { - buf *bufio.Reader - } - - answerYes := bufio.NewReader(strings.NewReader("y\n")) - answerYes2 := bufio.NewReader(strings.NewReader("Y\n")) - answerNo := bufio.NewReader(strings.NewReader("n\n")) - answerInvalid := bufio.NewReader(strings.NewReader("245\n")) - - tests := []struct { - name string - args args - wantErr bool - }{ - {"Y", args{answerYes}, false}, - {"y", args{answerYes2}, false}, - {"N", args{answerNo}, true}, - {"BAD", args{answerInvalid}, true}, - } - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - if err := confirmDeletion(tt.args.buf); (err != nil) != tt.wantErr { - t.Errorf("confirmDeletion() error = %v, wantErr %v", err, tt.wantErr) - } - }) - } -} diff --git a/client/keys/export.go b/client/keys/export.go index dba66d8352aa..2c17bfe84f76 100644 --- a/client/keys/export.go +++ b/client/keys/export.go @@ -25,21 +25,17 @@ func ExportKeyCommand() *cobra.Command { func runExportCmd(cmd *cobra.Command, args []string) error { buf := bufio.NewReader(cmd.InOrStdin()) - kb, err := keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), buf) + kb, err := keyring.New(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), buf) if err != nil { return err } - decryptPassword, err := input.GetPassword("Enter passphrase to decrypt your key:", buf) - if err != nil { - return err - } encryptPassword, err := input.GetPassword("Enter passphrase to encrypt the exported key:", buf) if err != nil { return err } - armored, err := kb.ExportPrivKey(args[0], decryptPassword, encryptPassword) + armored, err := kb.ExportPrivKeyArmor(args[0], encryptPassword) if err != nil { return err } diff --git a/client/keys/export_test.go b/client/keys/export_test.go index 175acdfe92fc..99262ceaa94b 100644 --- a/client/keys/export_test.go +++ b/client/keys/export_test.go @@ -6,6 +6,8 @@ import ( "github.com/spf13/viper" "github.com/stretchr/testify/require" + "github.com/cosmos/cosmos-sdk/crypto/hd" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/tests" @@ -22,13 +24,14 @@ func Test_runExportCmd(t *testing.T) { viper.Set(flags.FlagHome, kbHome) // create a key - kb, err := keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) + kb, err := keyring.New(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), kbHome, mockIn) require.NoError(t, err) t.Cleanup(func() { - kb.Delete("keyname1", "", false) // nolint:errcheck + kb.Delete("keyname1") // nolint:errcheck }) - _, err = kb.CreateAccount("keyname1", tests.TestMnemonic, "", "123456789", "", keyring.Secp256k1) + path := sdk.GetConfig().GetFullFundraiserPath() + _, err = kb.NewAccount("keyname1", tests.TestMnemonic, "", path, hd.Secp256k1) require.NoError(t, err) // Now enter password diff --git a/client/keys/import.go b/client/keys/import.go index 89a1f3769f8c..cbba4598dcb2 100644 --- a/client/keys/import.go +++ b/client/keys/import.go @@ -26,7 +26,7 @@ func ImportKeyCommand() *cobra.Command { func runImportCmd(cmd *cobra.Command, args []string) error { buf := bufio.NewReader(cmd.InOrStdin()) - kb, err := keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), buf) + kb, err := keyring.New(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), buf) if err != nil { return err } diff --git a/client/keys/import_test.go b/client/keys/import_test.go index cad3d6a44d3f..6451277d3e7f 100644 --- a/client/keys/import_test.go +++ b/client/keys/import_test.go @@ -23,10 +23,10 @@ func Test_runImportCmd(t *testing.T) { t.Cleanup(cleanUp) viper.Set(flags.FlagHome, kbHome) - kb, err := keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) + kb, err := keyring.New(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), kbHome, mockIn) require.NoError(t, err) t.Cleanup(func() { - kb.Delete("keyname1", "", false) // nolint:errcheck + kb.Delete("keyname1") // nolint:errcheck }) keyfile := filepath.Join(kbHome, "key.asc") diff --git a/client/keys/list.go b/client/keys/list.go index 770bde2f1465..9ec4df43bf4a 100644 --- a/client/keys/list.go +++ b/client/keys/list.go @@ -26,7 +26,7 @@ along with their associated name and address.`, } func runListCmd(cmd *cobra.Command, _ []string) error { - kb, err := keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), cmd.InOrStdin()) + kb, err := keyring.New(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), cmd.InOrStdin()) if err != nil { return err } diff --git a/client/keys/list_test.go b/client/keys/list_test.go index d5d4eebcf706..849ac9b8d8df 100644 --- a/client/keys/list_test.go +++ b/client/keys/list_test.go @@ -7,6 +7,8 @@ import ( "github.com/spf13/viper" "github.com/stretchr/testify/require" + "github.com/cosmos/cosmos-sdk/crypto/hd" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/tests" @@ -31,14 +33,15 @@ func Test_runListCmd(t *testing.T) { viper.Set(flags.FlagHome, kbHome2) mockIn, _, _ := tests.ApplyMockIO(cmdBasic) - kb, err := keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) + kb, err := keyring.New(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) require.NoError(t, err) - _, err = kb.CreateAccount("something", tests.TestMnemonic, "", "", "", keyring.Secp256k1) + path := "" //sdk.GetConfig().GetFullFundraiserPath() + _, err = kb.NewAccount("something", tests.TestMnemonic, "", path, hd.Secp256k1) require.NoError(t, err) t.Cleanup(func() { - kb.Delete("something", "", false) // nolint:errcheck + kb.Delete("something") // nolint:errcheck }) testData := []struct { diff --git a/client/keys/migrate.go b/client/keys/migrate.go index 840db70f10e1..8d52bd83faf8 100644 --- a/client/keys/migrate.go +++ b/client/keys/migrate.go @@ -60,21 +60,21 @@ func runMigrateCmd(cmd *cobra.Command, args []string) error { keyringServiceName := sdk.KeyringServiceName() var ( - tmpDir string - keybase keyring.Keybase + tmpDir string + migrator keyring.InfoImporter ) if viper.GetBool(flags.FlagDryRun) { - tmpDir, err = ioutil.TempDir("", "keybase-migrate-dryrun") + tmpDir, err = ioutil.TempDir("", "migrator-migrate-dryrun") if err != nil { return errors.Wrap(err, "failed to create temporary directory for dryrun migration") } defer os.RemoveAll(tmpDir) - keybase, err = keyring.NewKeyring(keyringServiceName, "test", tmpDir, buf) + migrator, err = keyring.NewInfoImporter(keyringServiceName, "test", tmpDir, buf) } else { - keybase, err = keyring.NewKeyring(keyringServiceName, viper.GetString(flags.FlagKeyringBackend), rootDir, buf) + migrator, err = keyring.NewInfoImporter(keyringServiceName, viper.GetString(flags.FlagKeyringBackend), rootDir, buf) } if err != nil { return errors.Wrap(err, fmt.Sprintf( @@ -92,16 +92,10 @@ func runMigrateCmd(cmd *cobra.Command, args []string) error { keyName := key.GetName() keyType := key.GetType() - // skip key if already migrated - if _, err := keybase.Get(keyName); err == nil { - cmd.PrintErrf("Key '%s (%s)' already exists; skipping ...\n", key.GetName(), keyType) - continue - } - cmd.PrintErrf("Migrating key: '%s (%s)' ...\n", key.GetName(), keyType) // allow user to skip migrating specific keys - ok, err := input.GetConfirmation("Skip key migration?", buf) + ok, err := input.GetConfirmation("Skip key migration?", buf, cmd.ErrOrStderr()) if err != nil { return err } @@ -110,7 +104,7 @@ func runMigrateCmd(cmd *cobra.Command, args []string) error { } if keyType != keyring.TypeLocal { - if err := keybase.Import(keyName, legKeyInfo); err != nil { + if err := migrator.Import(keyName, legKeyInfo); err != nil { return err } @@ -130,7 +124,7 @@ func runMigrateCmd(cmd *cobra.Command, args []string) error { return err } - if err := keybase.ImportPrivKey(keyName, armoredPriv, migratePassphrase); err != nil { + if err := migrator.Import(keyName, armoredPriv); err != nil { return err } } diff --git a/client/keys/migrate_test.go b/client/keys/migrate_test.go index aec085ecc1d2..9b82b18ba169 100644 --- a/client/keys/migrate_test.go +++ b/client/keys/migrate_test.go @@ -3,6 +3,8 @@ package keys import ( "testing" + "github.com/otiai10/copy" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/tests" @@ -18,18 +20,18 @@ func Test_runMigrateCmd(t *testing.T) { mockIn, _, _ := tests.ApplyMockIO(cmd) kbHome, kbCleanUp := tests.NewTestCaseDir(t) + copy.Copy("testdata", kbHome) assert.NotNil(t, kbHome) t.Cleanup(kbCleanUp) viper.Set(flags.FlagHome, kbHome) viper.Set(cli.OutputFlag, OutputFormatText) - mockIn.Reset("test1234\ntest1234\n") assert.NoError(t, runAddCmd(cmd, []string{"keyname1"})) viper.Set(flags.FlagDryRun, true) cmd = MigrateCommand() mockIn, _, _ = tests.ApplyMockIO(cmd) - mockIn.Reset("test1234\n") + mockIn.Reset("test1234\ntest1234\n") assert.NoError(t, runMigrateCmd(cmd, []string{})) } diff --git a/client/keys/mnemonic.go b/client/keys/mnemonic.go index e665130ee4c3..66b3b17d027a 100644 --- a/client/keys/mnemonic.go +++ b/client/keys/mnemonic.go @@ -46,7 +46,7 @@ func runMnemonicCmd(cmd *cobra.Command, args []string) error { if len(inputEntropy) < 43 { return fmt.Errorf("256-bits is 43 characters in Base-64, and 100 in Base-6. You entered %v, and probably want more", len(inputEntropy)) } - conf, err := input.GetConfirmation(fmt.Sprintf("> Input length: %d", len(inputEntropy)), buf) + conf, err := input.GetConfirmation(fmt.Sprintf("> Input length: %d", len(inputEntropy)), buf, cmd.ErrOrStderr()) if err != nil { return err } diff --git a/client/keys/root_test.go b/client/keys/root_test.go index 29fbe145504c..e995da9796d2 100644 --- a/client/keys/root_test.go +++ b/client/keys/root_test.go @@ -9,6 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/crypto/keyring" + sdk "github.com/cosmos/cosmos-sdk/types" ) func TestCommands(t *testing.T) { @@ -21,5 +22,6 @@ func TestCommands(t *testing.T) { func TestMain(m *testing.M) { viper.Set(flags.FlagKeyringBackend, keyring.BackendTest) + viper.Set(flagCoinType, sdk.CoinType) os.Exit(m.Run()) } diff --git a/client/keys/show.go b/client/keys/show.go index c423caa1aaea..11473aba4072 100644 --- a/client/keys/show.go +++ b/client/keys/show.go @@ -57,7 +57,7 @@ consisting of all the keys provided by name and multisig threshold.`, func runShowCmd(cmd *cobra.Command, args []string) (err error) { var info keyring.Info - kb, err := keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), cmd.InOrStdin()) + kb, err := keyring.New(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), cmd.InOrStdin()) if err != nil { return err } @@ -142,15 +142,15 @@ func runShowCmd(cmd *cobra.Command, args []string) (err error) { return nil } -func fetchKey(kb keyring.Keybase, keyref string) (keyring.Info, error) { - info, err := kb.Get(keyref) +func fetchKey(kb keyring.Keyring, keyref string) (keyring.Info, error) { + info, err := kb.Key(keyref) if err != nil { accAddr, err := sdk.AccAddressFromBech32(keyref) if err != nil { return info, err } - info, err = kb.GetByAddress(accAddr) + info, err = kb.KeyByAddress(accAddr) if err != nil { return info, errors.New("key not found") } diff --git a/client/keys/show_test.go b/client/keys/show_test.go index cf157c4c588c..54746e0207b4 100644 --- a/client/keys/show_test.go +++ b/client/keys/show_test.go @@ -11,6 +11,7 @@ import ( "github.com/tendermint/tendermint/crypto/secp256k1" "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/tests" sdk "github.com/cosmos/cosmos-sdk/types" @@ -24,7 +25,7 @@ func Test_multiSigKey_Properties(t *testing.T) { require.Equal(t, "myMultisig", tmp.GetName()) require.Equal(t, keyring.TypeMulti, tmp.GetType()) require.Equal(t, "D3923267FA8A3DD367BB768FA8BDC8FF7F89DA3F", tmp.GetPubKey().Address().String()) - require.Equal(t, "cosmos16wfryel63g7axeamw68630wglalcnk3l0zuadc", tmp.GetAddress().String()) + require.Equal(t, "cosmos16wfryel63g7axeamw68630wglalcnk3l0zuadc", sdk.MustBech32ifyAddressBytes("cosmos", tmp.GetAddress())) } func Test_showKeysCmd(t *testing.T) { @@ -48,16 +49,19 @@ func Test_runShowCmd(t *testing.T) { fakeKeyName1 := "runShowCmd_Key1" fakeKeyName2 := "runShowCmd_Key2" - kb, err := keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) + kb, err := keyring.New(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) require.NoError(t, err) t.Cleanup(func() { - kb.Delete("runShowCmd_Key1", "", false) - kb.Delete("runShowCmd_Key2", "", false) + kb.Delete("runShowCmd_Key1") + kb.Delete("runShowCmd_Key2") }) - _, err = kb.CreateAccount(fakeKeyName1, tests.TestMnemonic, "", "", "0", keyring.Secp256k1) + + path := hd.NewFundraiserParams(1, sdk.CoinType, 0).String() + _, err = kb.NewAccount(fakeKeyName1, tests.TestMnemonic, "", path, hd.Secp256k1) require.NoError(t, err) - _, err = kb.CreateAccount(fakeKeyName2, tests.TestMnemonic, "", "", "1", keyring.Secp256k1) + path2 := hd.NewFundraiserParams(1, sdk.CoinType, 1).String() + _, err = kb.NewAccount(fakeKeyName2, tests.TestMnemonic, "", path2, hd.Secp256k1) require.NoError(t, err) // Now try single key @@ -69,7 +73,7 @@ func Test_runShowCmd(t *testing.T) { // try fetch by name require.NoError(t, runShowCmd(cmd, []string{fakeKeyName1})) // try fetch by addr - info, err := kb.Get(fakeKeyName1) + info, err := kb.Key(fakeKeyName1) require.NoError(t, err) require.NoError(t, runShowCmd(cmd, []string{info.GetAddress().String()})) diff --git a/client/tx/factory.go b/client/tx/factory.go index 4b05b2419a42..25cff13d6720 100644 --- a/client/tx/factory.go +++ b/client/tx/factory.go @@ -21,7 +21,7 @@ type AccountRetriever interface { // Factory defines a client transaction factory that facilitates generating and // signing an application-specific transaction. type Factory struct { - keybase keyring.Keybase + keybase keyring.Keyring txGenerator Generator accountRetriever AccountRetriever accountNumber uint64 @@ -36,7 +36,7 @@ type Factory struct { } func NewFactoryFromCLI(input io.Reader) Factory { - kb, err := keyring.NewKeyring( + kb, err := keyring.New( sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), @@ -68,7 +68,7 @@ func (f Factory) AccountNumber() uint64 { return f.accountNumber } func (f Factory) Sequence() uint64 { return f.sequence } func (f Factory) Gas() uint64 { return f.gas } func (f Factory) GasAdjustment() float64 { return f.gasAdjustment } -func (f Factory) Keybase() keyring.Keybase { return f.keybase } +func (f Factory) Keybase() keyring.Keyring { return f.keybase } func (f Factory) ChainID() string { return f.chainID } func (f Factory) Memo() string { return f.memo } func (f Factory) Fees() sdk.Coins { return f.fees } @@ -126,7 +126,7 @@ func (f Factory) WithGasPrices(gasPrices string) Factory { } // WithKeybase returns a copy of the Factory with updated Keybase. -func (f Factory) WithKeybase(keybase keyring.Keybase) Factory { +func (f Factory) WithKeybase(keybase keyring.Keyring) Factory { f.keybase = keybase return f } diff --git a/client/tx/tx.go b/client/tx/tx.go index 7958122dad31..0cd4e71f3dd9 100644 --- a/client/tx/tx.go +++ b/client/tx/tx.go @@ -127,7 +127,7 @@ func BroadcastTx(ctx context.CLIContext, txf Factory, msgs ...sdk.Msg) error { _, _ = fmt.Fprintf(os.Stderr, "%s\n\n", out) buf := bufio.NewReader(os.Stdin) - ok, err := input.GetConfirmation("confirm transaction before signing and broadcasting", buf) + ok, err := input.GetConfirmation("confirm transaction before signing and broadcasting", buf, os.Stderr) if err != nil || !ok { _, _ = fmt.Fprintf(os.Stderr, "%s\n", "cancelled transaction") return err @@ -332,7 +332,7 @@ func Sign(txf Factory, name, passphrase string, tx ClientTx) ([]byte, error) { return nil, err } - sigBytes, pubkey, err := txf.keybase.Sign(name, passphrase, signBytes) + sigBytes, pubkey, err := txf.keybase.Sign(name, signBytes) if err != nil { return nil, err } diff --git a/crypto/armor_test.go b/crypto/armor_test.go index 29aeb6af64a8..9ebb7cc8c818 100644 --- a/crypto/armor_test.go +++ b/crypto/armor_test.go @@ -15,8 +15,11 @@ import ( "github.com/tendermint/tendermint/crypto/secp256k1" "github.com/tendermint/tendermint/crypto/xsalsa20symmetric" + "github.com/cosmos/cosmos-sdk/crypto/hd" + "github.com/cosmos/cosmos-sdk/crypto" "github.com/cosmos/cosmos-sdk/crypto/keyring" + "github.com/cosmos/cosmos-sdk/types" ) func TestArmorUnarmorPrivKey(t *testing.T) { @@ -26,7 +29,7 @@ func TestArmorUnarmorPrivKey(t *testing.T) { require.Error(t, err) decrypted, algo, err := crypto.UnarmorDecryptPrivKey(armored, "passphrase") require.NoError(t, err) - require.Equal(t, string(keyring.Secp256k1), algo) + require.Equal(t, string(hd.Secp256k1Type), algo) require.True(t, priv.Equals(decrypted)) // empty string @@ -70,14 +73,14 @@ func TestArmorUnarmorPubKey(t *testing.T) { cstore := keyring.NewInMemory() // Add keys and see they return in alphabetical order - info, _, err := cstore.CreateMnemonic("Bob", keyring.English, "passphrase", keyring.Secp256k1) + info, _, err := cstore.NewMnemonic("Bob", keyring.English, types.FullFundraiserPath, hd.Secp256k1) require.NoError(t, err) armored := crypto.ArmorPubKeyBytes(info.GetPubKey().Bytes(), "") pubBytes, algo, err := crypto.UnarmorPubKeyBytes(armored) require.NoError(t, err) pub, err := cryptoAmino.PubKeyFromBytes(pubBytes) require.NoError(t, err) - require.Equal(t, string(keyring.Secp256k1), algo) + require.Equal(t, string(hd.Secp256k1Type), algo) require.True(t, pub.Equals(info.GetPubKey())) armored = crypto.ArmorPubKeyBytes(info.GetPubKey().Bytes(), "unknown") @@ -88,7 +91,7 @@ func TestArmorUnarmorPubKey(t *testing.T) { require.Equal(t, "unknown", algo) require.True(t, pub.Equals(info.GetPubKey())) - armored, err = cstore.ExportPrivKey("Bob", "passphrase", "alessio") + armored, err = cstore.ExportPrivKeyArmor("Bob", "passphrase") require.NoError(t, err) _, _, err = crypto.UnarmorPubKeyBytes(armored) require.Error(t, err) diff --git a/crypto/hd/algo.go b/crypto/hd/algo.go new file mode 100644 index 000000000000..264f0ae8dfe6 --- /dev/null +++ b/crypto/hd/algo.go @@ -0,0 +1,68 @@ +package hd + +import ( + "github.com/cosmos/go-bip39" + "github.com/tendermint/tendermint/crypto" + "github.com/tendermint/tendermint/crypto/secp256k1" +) + +// PubKeyType defines an algorithm to derive key-pairs which can be used for cryptographic signing. +type PubKeyType string + +const ( + // MultiType implies that a pubkey is a multisignature + MultiType = PubKeyType("multi") + // Secp256k1Type uses the Bitcoin secp256k1 ECDSA parameters. + Secp256k1Type = PubKeyType("secp256k1") + // Ed25519Type represents the Ed25519Type signature system. + // It is currently not supported for end-user keys (wallets/ledgers). + Ed25519Type = PubKeyType("ed25519") + // Sr25519Type represents the Sr25519Type signature system. + Sr25519Type = PubKeyType("sr25519") +) + +var ( + // Secp256k1 uses the Bitcoin secp256k1 ECDSA parameters. + Secp256k1 = secp256k1Algo{} +) + +type DeriveFn func(mnemonic string, bip39Passphrase, hdPath string) ([]byte, error) +type GenerateFn func(bz []byte) crypto.PrivKey + +type WalletGenerator interface { + Derive(mnemonic string, bip39Passphrase, hdPath string) ([]byte, error) + Generate(bz []byte) crypto.PrivKey +} + +type secp256k1Algo struct { +} + +func (s secp256k1Algo) Name() PubKeyType { + return Secp256k1Type +} + +// Derive derives and returns the secp256k1 private key for the given seed and HD path. +func (s secp256k1Algo) Derive() DeriveFn { + return func(mnemonic string, bip39Passphrase, hdPath string) ([]byte, error) { + seed, err := bip39.NewSeedWithErrorChecking(mnemonic, bip39Passphrase) + if err != nil { + return nil, err + } + + masterPriv, ch := ComputeMastersFromSeed(seed) + if len(hdPath) == 0 { + return masterPriv[:], nil + } + derivedKey, err := DerivePrivateKeyForPath(masterPriv, ch, hdPath) + return derivedKey[:], err + } +} + +// Generate generates a secp256k1 private key from the given bytes. +func (s secp256k1Algo) Generate() GenerateFn { + return func(bz []byte) crypto.PrivKey { + var bzArr [32]byte + copy(bzArr[:], bz) + return secp256k1.PrivKeySecp256k1(bzArr) + } +} diff --git a/crypto/hd/algo_test.go b/crypto/hd/algo_test.go new file mode 100644 index 000000000000..767b42154034 --- /dev/null +++ b/crypto/hd/algo_test.go @@ -0,0 +1,16 @@ +package hd_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/crypto/hd" +) + +func TestDefaults(t *testing.T) { + require.Equal(t, hd.PubKeyType("multi"), hd.MultiType) + require.Equal(t, hd.PubKeyType("secp256k1"), hd.Secp256k1Type) + require.Equal(t, hd.PubKeyType("ed25519"), hd.Ed25519Type) + require.Equal(t, hd.PubKeyType("sr25519"), hd.Sr25519Type) +} diff --git a/crypto/hd/doc.go b/crypto/hd/doc.go new file mode 100644 index 000000000000..38d65213c177 --- /dev/null +++ b/crypto/hd/doc.go @@ -0,0 +1,12 @@ +// Package hd provides support for hierarchical deterministic wallets generation and derivation. +// +// The user must understand the overall concept of the BIP 32 and the BIP 44 specs: +// https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki +// https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki +// +// In combination with the bip39 package in go-crypto this package provides the functionality for +// deriving keys using a BIP 44 HD path, or, more general, by passing a BIP 32 path. +// +// In particular, this package (together with bip39) provides all necessary functionality to derive +// keys from mnemonics generated during the cosmos fundraiser. +package hd diff --git a/crypto/keys/hd/fundraiser_test.go b/crypto/hd/fundraiser_test.go similarity index 78% rename from crypto/keys/hd/fundraiser_test.go rename to crypto/hd/fundraiser_test.go index 6fa4ca725f0d..0f6a539d4fd5 100644 --- a/crypto/keys/hd/fundraiser_test.go +++ b/crypto/hd/fundraiser_test.go @@ -1,4 +1,4 @@ -package hd +package hd_test import ( "encoding/hex" @@ -13,6 +13,8 @@ import ( "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/secp256k1" + + "github.com/cosmos/cosmos-sdk/crypto/hd" ) type addrData struct { @@ -24,19 +26,23 @@ type addrData struct { Addr string } +func TestFullFundraiserPath(t *testing.T) { + require.Equal(t, "44'/118'/0'/0/0", hd.NewFundraiserParams(0, 118, 0).String()) +} + func initFundraiserTestVectors(t *testing.T) []addrData { // NOTE: atom fundraiser address // var hdPath string = "m/44'/118'/0'/0/0" var hdToAddrTable []addrData - b, err := ioutil.ReadFile("test.json") + b, err := ioutil.ReadFile("testdata/test.json") if err != nil { - t.Fatalf("could not read fundraiser test vector file (test.json): %s", err) + t.Fatalf("could not read fundraiser test vector file (testdata/test.json): %s", err) } err = json.Unmarshal(b, &hdToAddrTable) if err != nil { - t.Fatalf("could not decode test vectors (test.json): %s", err) + t.Fatalf("could not decode test vectors (testdata/test.json): %s", err) } return hdToAddrTable } @@ -56,8 +62,8 @@ func TestFundraiserCompatibility(t *testing.T) { t.Log("================================") t.Logf("ROUND: %d MNEMONIC: %s", i, d.Mnemonic) - master, ch := ComputeMastersFromSeed(seed) - priv, err := DerivePrivateKeyForPath(master, ch, "44'/118'/0'/0/0") + master, ch := hd.ComputeMastersFromSeed(seed) + priv, err := hd.DerivePrivateKeyForPath(master, ch, "44'/118'/0'/0/0") require.NoError(t, err) pub := secp256k1.PrivKeySecp256k1(priv).PubKey() diff --git a/crypto/keys/hd/hdpath.go b/crypto/hd/hdpath.go similarity index 91% rename from crypto/keys/hd/hdpath.go rename to crypto/hd/hdpath.go index a92d79be1f21..763267087484 100644 --- a/crypto/keys/hd/hdpath.go +++ b/crypto/hd/hdpath.go @@ -1,20 +1,8 @@ -// Package hd provides basic functionality Hierarchical Deterministic Wallets. -// -// The user must understand the overall concept of the BIP 32 and the BIP 44 specs: -// https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki -// https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki -// -// In combination with the bip39 package in go-crypto this package provides the functionality for deriving keys using a -// BIP 44 HD path, or, more general, by passing a BIP 32 path. -// -// In particular, this package (together with bip39) provides all necessary functionality to derive keys from -// mnemonics generated during the cosmos fundraiser. package hd import ( "crypto/hmac" "crypto/sha512" - "encoding/binary" "errors" "fmt" @@ -255,3 +243,8 @@ func i64(key []byte, data []byte) (il [32]byte, ir [32]byte) { return } + +// CreateHDPath returns BIP 44 object from account and index parameters. +func CreateHDPath(coinType, account, index uint32) *BIP44Params { + return NewFundraiserParams(account, coinType, index) +} diff --git a/crypto/keys/hd/hdpath_test.go b/crypto/hd/hdpath_test.go similarity index 64% rename from crypto/keys/hd/hdpath_test.go rename to crypto/hd/hdpath_test.go index a5110e2cbde2..9f95f7edec36 100644 --- a/crypto/keys/hd/hdpath_test.go +++ b/crypto/hd/hdpath_test.go @@ -1,10 +1,11 @@ -package hd +package hd_test import ( "encoding/hex" "fmt" "testing" + "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/types" bip39 "github.com/cosmos/go-bip39" @@ -21,9 +22,9 @@ func mnemonicToSeed(mnemonic string) []byte { // nolint:govet func ExampleStringifyPathParams() { - path := NewParams(44, 0, 0, false, 0) + path := hd.NewParams(44, 0, 0, false, 0) fmt.Println(path.String()) - path = NewParams(44, 33, 7, true, 9) + path = hd.NewParams(44, 33, 7, true, 9) fmt.Println(path.String()) // Output: // 44'/0'/0'/0/0 @@ -31,40 +32,40 @@ func ExampleStringifyPathParams() { } func TestStringifyFundraiserPathParams(t *testing.T) { - path := NewFundraiserParams(4, types.CoinType, 22) + path := hd.NewFundraiserParams(4, types.CoinType, 22) require.Equal(t, "44'/118'/4'/0/22", path.String()) - path = NewFundraiserParams(4, types.CoinType, 57) + path = hd.NewFundraiserParams(4, types.CoinType, 57) require.Equal(t, "44'/118'/4'/0/57", path.String()) - path = NewFundraiserParams(4, 12345, 57) + path = hd.NewFundraiserParams(4, 12345, 57) require.Equal(t, "44'/12345'/4'/0/57", path.String()) } func TestPathToArray(t *testing.T) { - path := NewParams(44, 118, 1, false, 4) + path := hd.NewParams(44, 118, 1, false, 4) require.Equal(t, "[44 118 1 0 4]", fmt.Sprintf("%v", path.DerivationPath())) - path = NewParams(44, 118, 2, true, 15) + path = hd.NewParams(44, 118, 2, true, 15) require.Equal(t, "[44 118 2 1 15]", fmt.Sprintf("%v", path.DerivationPath())) } func TestParamsFromPath(t *testing.T) { goodCases := []struct { - params *BIP44Params + params *hd.BIP44Params path string }{ - {&BIP44Params{44, 0, 0, false, 0}, "44'/0'/0'/0/0"}, - {&BIP44Params{44, 1, 0, false, 0}, "44'/1'/0'/0/0"}, - {&BIP44Params{44, 0, 1, false, 0}, "44'/0'/1'/0/0"}, - {&BIP44Params{44, 0, 0, true, 0}, "44'/0'/0'/1/0"}, - {&BIP44Params{44, 0, 0, false, 1}, "44'/0'/0'/0/1"}, - {&BIP44Params{44, 1, 1, true, 1}, "44'/1'/1'/1/1"}, - {&BIP44Params{44, 118, 52, true, 41}, "44'/118'/52'/1/41"}, + {&hd.BIP44Params{44, 0, 0, false, 0}, "44'/0'/0'/0/0"}, + {&hd.BIP44Params{44, 1, 0, false, 0}, "44'/1'/0'/0/0"}, + {&hd.BIP44Params{44, 0, 1, false, 0}, "44'/0'/1'/0/0"}, + {&hd.BIP44Params{44, 0, 0, true, 0}, "44'/0'/0'/1/0"}, + {&hd.BIP44Params{44, 0, 0, false, 1}, "44'/0'/0'/0/1"}, + {&hd.BIP44Params{44, 1, 1, true, 1}, "44'/1'/1'/1/1"}, + {&hd.BIP44Params{44, 118, 52, true, 41}, "44'/118'/52'/1/41"}, } for i, c := range goodCases { - params, err := NewParamsFromPath(c.path) + params, err := hd.NewParamsFromPath(c.path) errStr := fmt.Sprintf("%d %v", i, c) assert.NoError(t, err, errStr) assert.EqualValues(t, c.params, params, errStr) @@ -93,7 +94,7 @@ func TestParamsFromPath(t *testing.T) { } for i, c := range badCases { - params, err := NewParamsFromPath(c.path) + params, err := hd.NewParamsFromPath(c.path) errStr := fmt.Sprintf("%d %v", i, c) assert.Nil(t, params, errStr) assert.Error(t, err, errStr) @@ -106,38 +107,38 @@ func ExampleSomeBIP32TestVecs() { seed := mnemonicToSeed("barrel original fuel morning among eternal " + "filter ball stove pluck matrix mechanic") - master, ch := ComputeMastersFromSeed(seed) + master, ch := hd.ComputeMastersFromSeed(seed) fmt.Println("keys from fundraiser test-vector (cosmos, bitcoin, ether)") fmt.Println() // cosmos - priv, err := DerivePrivateKeyForPath(master, ch, types.FullFundraiserPath) + priv, err := hd.DerivePrivateKeyForPath(master, ch, types.FullFundraiserPath) if err != nil { fmt.Println("INVALID") } else { fmt.Println(hex.EncodeToString(priv[:])) } // bitcoin - priv, err = DerivePrivateKeyForPath(master, ch, "44'/0'/0'/0/0") + priv, err = hd.DerivePrivateKeyForPath(master, ch, "44'/0'/0'/0/0") if err != nil { fmt.Println("INVALID") } else { fmt.Println(hex.EncodeToString(priv[:])) } // ether - priv, err = DerivePrivateKeyForPath(master, ch, "44'/60'/0'/0/0") + priv, err = hd.DerivePrivateKeyForPath(master, ch, "44'/60'/0'/0/0") if err != nil { fmt.Println("INVALID") } else { fmt.Println(hex.EncodeToString(priv[:])) } // INVALID - priv, err = DerivePrivateKeyForPath(master, ch, "X/0'/0'/0/0") + priv, err = hd.DerivePrivateKeyForPath(master, ch, "X/0'/0'/0/0") if err != nil { fmt.Println("INVALID") } else { fmt.Println(hex.EncodeToString(priv[:])) } - priv, err = DerivePrivateKeyForPath(master, ch, "-44/0'/0'/0/0") + priv, err = hd.DerivePrivateKeyForPath(master, ch, "-44/0'/0'/0/0") if err != nil { fmt.Println("INVALID") } else { @@ -151,14 +152,14 @@ func ExampleSomeBIP32TestVecs() { seed = mnemonicToSeed( "advice process birth april short trust crater change bacon monkey medal garment " + "gorilla ranch hour rival razor call lunar mention taste vacant woman sister") - master, ch = ComputeMastersFromSeed(seed) - priv, _ = DerivePrivateKeyForPath(master, ch, "44'/1'/1'/0/4") + master, ch = hd.ComputeMastersFromSeed(seed) + priv, _ = hd.DerivePrivateKeyForPath(master, ch, "44'/1'/1'/0/4") fmt.Println(hex.EncodeToString(priv[:])) seed = mnemonicToSeed("idea naive region square margin day captain habit " + "gun second farm pact pulse someone armed") - master, ch = ComputeMastersFromSeed(seed) - priv, _ = DerivePrivateKeyForPath(master, ch, "44'/0'/0'/0/420") + master, ch = hd.ComputeMastersFromSeed(seed) + priv, _ = hd.DerivePrivateKeyForPath(master, ch, "44'/0'/0'/0/420") fmt.Println(hex.EncodeToString(priv[:])) fmt.Println() @@ -167,8 +168,8 @@ func ExampleSomeBIP32TestVecs() { // bip32 path: m/0/7 seed = mnemonicToSeed("monitor flock loyal sick object grunt duty ride develop assault harsh history") - master, ch = ComputeMastersFromSeed(seed) - priv, _ = DerivePrivateKeyForPath(master, ch, "0/7") + master, ch = hd.ComputeMastersFromSeed(seed) + priv, _ = hd.DerivePrivateKeyForPath(master, ch, "0/7") fmt.Println(hex.EncodeToString(priv[:])) // Output: keys from fundraiser test-vector (cosmos, bitcoin, ether) @@ -188,3 +189,27 @@ func ExampleSomeBIP32TestVecs() { // // c4c11d8c03625515905d7e89d25dfc66126fbc629ecca6db489a1a72fc4bda78 } + +func TestCreateHDPath(t *testing.T) { + type args struct { + coinType uint32 + account uint32 + index uint32 + } + tests := []struct { + name string + args args + want hd.BIP44Params + }{ + {"44'/0'/0'/0/0", args{0, 0, 0}, hd.BIP44Params{Purpose: 44}}, + {"44'/114'/0'/0/0", args{114, 0, 0}, hd.BIP44Params{Purpose: 44, CoinType: 114, Account: 0, AddressIndex: 0}}, + {"44'/114'/1'/1/0", args{114, 1, 1}, hd.BIP44Params{Purpose: 44, CoinType: 114, Account: 1, AddressIndex: 1}}, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + tt := tt + require.Equal(t, tt.want, *hd.CreateHDPath(tt.args.coinType, tt.args.account, tt.args.index)) + }) + } +} diff --git a/crypto/keys/hd/test.json b/crypto/hd/testdata/test.json similarity index 100% rename from crypto/keys/hd/test.json rename to crypto/hd/testdata/test.json diff --git a/crypto/keyring/base_keybase.go b/crypto/keyring/base_keybase.go deleted file mode 100644 index 039b09e8ff14..000000000000 --- a/crypto/keyring/base_keybase.go +++ /dev/null @@ -1,234 +0,0 @@ -package keyring - -import ( - "github.com/pkg/errors" - - tmcrypto "github.com/tendermint/tendermint/crypto" - "github.com/tendermint/tendermint/crypto/secp256k1" - - "github.com/cosmos/cosmos-sdk/crypto" - "github.com/cosmos/cosmos-sdk/crypto/keys/hd" - "github.com/cosmos/cosmos-sdk/types" - bip39 "github.com/cosmos/go-bip39" -) - -type ( - // baseKeybase is an auxiliary type that groups Keybase storage agnostic features - // together. - baseKeybase struct { - options kbOptions - } - - keyWriter interface { - writeLocalKeyer - infoWriter - } - - writeLocalKeyer interface { - writeLocalKey(name string, priv tmcrypto.PrivKey, algo SigningAlgo) Info - } - - infoWriter interface { - writeInfo(name string, info Info) - } -) - -var fundraiserPath = types.GetConfig().GetFullFundraiserPath() - -// newBaseKeybase generates the base keybase with defaulting to tendermint SECP256K1 key type -func newBaseKeybase(optionsFns ...KeybaseOption) baseKeybase { - // Default options for keybase - options := kbOptions{ - keygenFunc: StdPrivKeyGen, - deriveFunc: StdDeriveKey, - supportedAlgos: []SigningAlgo{Secp256k1}, - supportedAlgosLedger: []SigningAlgo{Secp256k1}, - } - - for _, optionFn := range optionsFns { - optionFn(&options) - } - - return baseKeybase{options: options} -} - -// StdPrivKeyGen is the default PrivKeyGen function in the keybase. -// For now, it only supports Secp256k1 -func StdPrivKeyGen(bz []byte, algo SigningAlgo) (tmcrypto.PrivKey, error) { - if algo == Secp256k1 { - return SecpPrivKeyGen(bz), nil - } - return nil, ErrUnsupportedSigningAlgo -} - -// SecpPrivKeyGen generates a secp256k1 private key from the given bytes -func SecpPrivKeyGen(bz []byte) tmcrypto.PrivKey { - var bzArr [32]byte - copy(bzArr[:], bz) - return secp256k1.PrivKeySecp256k1(bzArr) -} - -// CreateAccount creates an account Info object. -func (kb baseKeybase) CreateAccount( - keyWriter keyWriter, name, mnemonic, bip39Passphrase, encryptPasswd, hdPath string, algo SigningAlgo, -) (Info, error) { - - // create master key and derive first key for keyring - derivedPriv, err := kb.options.deriveFunc(mnemonic, bip39Passphrase, hdPath, algo) - if err != nil { - return nil, err - } - - privKey, err := kb.options.keygenFunc(derivedPriv, algo) - if err != nil { - return nil, err - } - - var info Info - - if encryptPasswd != "" { - info = keyWriter.writeLocalKey(name, privKey, algo) - } else { - info = kb.writeOfflineKey(keyWriter, name, privKey.PubKey(), algo) - } - - return info, nil -} - -// CreateLedger creates a new reference to a Ledger key pair. It returns a public -// key and a derivation path. It returns an error if the device could not be queried. -func (kb baseKeybase) CreateLedger( - w infoWriter, name string, algo SigningAlgo, hrp string, account, index uint32, -) (Info, error) { - - if !IsSupportedAlgorithm(kb.SupportedAlgosLedger(), algo) { - return nil, ErrUnsupportedSigningAlgo - } - - coinType := types.GetConfig().GetCoinType() - hdPath := hd.NewFundraiserParams(account, coinType, index) - - priv, _, err := crypto.NewPrivKeyLedgerSecp256k1(*hdPath, hrp) - if err != nil { - return nil, err - } - - return kb.writeLedgerKey(w, name, priv.PubKey(), *hdPath, algo), nil -} - -// CreateMnemonic generates a new key with the given algorithm and language pair. -func (kb baseKeybase) CreateMnemonic( - keyWriter keyWriter, name string, language Language, passwd string, algo SigningAlgo, -) (info Info, mnemonic string, err error) { - - if language != English { - return nil, "", ErrUnsupportedLanguage - } - - if !IsSupportedAlgorithm(kb.SupportedAlgos(), algo) { - return nil, "", ErrUnsupportedSigningAlgo - } - - // Default number of words (24): This generates a mnemonic directly from the - // number of words by reading system entropy. - entropy, err := bip39.NewEntropy(defaultEntropySize) - if err != nil { - return nil, "", err - } - - mnemonic, err = bip39.NewMnemonic(entropy) - if err != nil { - return nil, "", err - } - - info, err = kb.CreateAccount(keyWriter, name, mnemonic, DefaultBIP39Passphrase, passwd, fundraiserPath, algo) - if err != nil { - return nil, "", err - } - - return info, mnemonic, err -} - -func (kb baseKeybase) writeLedgerKey(w infoWriter, name string, pub tmcrypto.PubKey, path hd.BIP44Params, algo SigningAlgo) Info { - info := newLedgerInfo(name, pub, path, algo) - w.writeInfo(name, info) - return info -} - -func (kb baseKeybase) writeOfflineKey(w infoWriter, name string, pub tmcrypto.PubKey, algo SigningAlgo) Info { - info := newOfflineInfo(name, pub, algo) - w.writeInfo(name, info) - return info -} - -func (kb baseKeybase) writeMultisigKey(w infoWriter, name string, pub tmcrypto.PubKey) Info { - info := NewMultiInfo(name, pub) - w.writeInfo(name, info) - return info -} - -// StdDeriveKey is the default DeriveKey function in the keybase. -// For now, it only supports Secp256k1 -func StdDeriveKey(mnemonic string, bip39Passphrase, hdPath string, algo SigningAlgo) ([]byte, error) { - if algo == Secp256k1 { - return SecpDeriveKey(mnemonic, bip39Passphrase, hdPath) - } - return nil, ErrUnsupportedSigningAlgo -} - -// SecpDeriveKey derives and returns the secp256k1 private key for the given seed and HD path. -func SecpDeriveKey(mnemonic string, bip39Passphrase, hdPath string) ([]byte, error) { - seed, err := bip39.NewSeedWithErrorChecking(mnemonic, bip39Passphrase) - if err != nil { - return nil, err - } - - masterPriv, ch := hd.ComputeMastersFromSeed(seed) - if len(hdPath) == 0 { - return masterPriv[:], nil - } - derivedKey, err := hd.DerivePrivateKeyForPath(masterPriv, ch, hdPath) - return derivedKey[:], err -} - -// CreateHDPath returns BIP 44 object from account and index parameters. -func CreateHDPath(account uint32, index uint32) *hd.BIP44Params { - return hd.NewFundraiserParams(account, types.GetConfig().GetCoinType(), index) -} - -// SupportedAlgos returns a list of supported signing algorithms. -func (kb baseKeybase) SupportedAlgos() []SigningAlgo { - return kb.options.supportedAlgos -} - -// SupportedAlgosLedger returns a list of supported ledger signing algorithms. -func (kb baseKeybase) SupportedAlgosLedger() []SigningAlgo { - return kb.options.supportedAlgosLedger -} - -// SignWithLedger signs a binary message with the ledger device referenced by an Info object -// and returns the signed bytes and the public key. It returns an error if the device could -// not be queried or it returned an error. -func SignWithLedger(info Info, msg []byte) (sig []byte, pub tmcrypto.PubKey, err error) { - switch info.(type) { - case *ledgerInfo, ledgerInfo: - default: - return nil, nil, errors.New("not a ledger object") - } - path, err := info.GetPath() - if err != nil { - return - } - - priv, err := crypto.NewPrivKeyLedgerSecp256k1Unsafe(*path) - if err != nil { - return - } - - sig, err = priv.Sign(msg) - if err != nil { - return nil, nil, err - } - - return sig, priv.PubKey(), nil -} diff --git a/crypto/keyring/codec.go b/crypto/keyring/codec.go index a8cd37d13fe4..35860e71ce42 100644 --- a/crypto/keyring/codec.go +++ b/crypto/keyring/codec.go @@ -4,7 +4,7 @@ import ( cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino" "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/crypto/keys/hd" + "github.com/cosmos/cosmos-sdk/crypto/hd" ) // CryptoCdc defines the codec required for keys and info diff --git a/crypto/keyring/doc.go b/crypto/keyring/doc.go index 369f053b76a3..0a76866e4b41 100644 --- a/crypto/keyring/doc.go +++ b/crypto/keyring/doc.go @@ -19,9 +19,9 @@ // generated keys are discarded when the process terminates or the type instance is garbage // collected. // -// NewKeyring +// New // -// The NewKeyring constructor returns an implementation backed by a keyring library +// The New constructor returns an implementation backed by a keyring library // (https://github.com/99designs/keyring), whose aim is to provide a common abstraction and uniform // interface between secret stores available for Windows, macOS, and most GNU/Linux distributions // as well as operating system-agnostic encrypted file-based backends. diff --git a/crypto/keyring/info.go b/crypto/keyring/info.go index b9df095a9733..a391d86a943e 100644 --- a/crypto/keyring/info.go +++ b/crypto/keyring/info.go @@ -6,7 +6,7 @@ import ( "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/multisig" - "github.com/cosmos/cosmos-sdk/crypto/keys/hd" + "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/types" ) @@ -23,7 +23,7 @@ type Info interface { // Bip44 Path GetPath() (*hd.BIP44Params, error) // Algo - GetAlgo() SigningAlgo + GetAlgo() hd.PubKeyType } var ( @@ -39,10 +39,10 @@ type localInfo struct { Name string `json:"name"` PubKey crypto.PubKey `json:"pubkey"` PrivKeyArmor string `json:"privkey.armor"` - Algo SigningAlgo `json:"algo"` + Algo hd.PubKeyType `json:"algo"` } -func newLocalInfo(name string, pub crypto.PubKey, privArmor string, algo SigningAlgo) Info { +func newLocalInfo(name string, pub crypto.PubKey, privArmor string, algo hd.PubKeyType) Info { return &localInfo{ Name: name, PubKey: pub, @@ -72,7 +72,7 @@ func (i localInfo) GetAddress() types.AccAddress { } // GetType implements Info interface -func (i localInfo) GetAlgo() SigningAlgo { +func (i localInfo) GetAlgo() hd.PubKeyType { return i.Algo } @@ -87,10 +87,10 @@ type ledgerInfo struct { Name string `json:"name"` PubKey crypto.PubKey `json:"pubkey"` Path hd.BIP44Params `json:"path"` - Algo SigningAlgo `json:"algo"` + Algo hd.PubKeyType `json:"algo"` } -func newLedgerInfo(name string, pub crypto.PubKey, path hd.BIP44Params, algo SigningAlgo) Info { +func newLedgerInfo(name string, pub crypto.PubKey, path hd.BIP44Params, algo hd.PubKeyType) Info { return &ledgerInfo{ Name: name, PubKey: pub, @@ -120,7 +120,7 @@ func (i ledgerInfo) GetAddress() types.AccAddress { } // GetPath implements Info interface -func (i ledgerInfo) GetAlgo() SigningAlgo { +func (i ledgerInfo) GetAlgo() hd.PubKeyType { return i.Algo } @@ -135,10 +135,10 @@ func (i ledgerInfo) GetPath() (*hd.BIP44Params, error) { type offlineInfo struct { Name string `json:"name"` PubKey crypto.PubKey `json:"pubkey"` - Algo SigningAlgo `json:"algo"` + Algo hd.PubKeyType `json:"algo"` } -func newOfflineInfo(name string, pub crypto.PubKey, algo SigningAlgo) Info { +func newOfflineInfo(name string, pub crypto.PubKey, algo hd.PubKeyType) Info { return &offlineInfo{ Name: name, PubKey: pub, @@ -162,7 +162,7 @@ func (i offlineInfo) GetPubKey() crypto.PubKey { } // GetAlgo returns the signing algorithm for the key -func (i offlineInfo) GetAlgo() SigningAlgo { +func (i offlineInfo) GetAlgo() hd.PubKeyType { return i.Algo } @@ -228,8 +228,8 @@ func (i multiInfo) GetAddress() types.AccAddress { } // GetPath implements Info interface -func (i multiInfo) GetAlgo() SigningAlgo { - return MultiAlgo +func (i multiInfo) GetAlgo() hd.PubKeyType { + return hd.MultiType } // GetPath implements Info interface diff --git a/crypto/keyring/keybase.go b/crypto/keyring/keybase.go deleted file mode 100644 index 149069ff50be..000000000000 --- a/crypto/keyring/keybase.go +++ /dev/null @@ -1,76 +0,0 @@ -package keyring - -import ( - "github.com/tendermint/tendermint/crypto" - - "github.com/cosmos/cosmos-sdk/types" -) - -// Keybase exposes operations on a generic keystore -type Keybase interface { - // CRUD on the keystore - List() ([]Info, error) - // Get returns the public information about one key. - Get(name string) (Info, error) - // Get performs a by-address lookup and returns the public - // information about one key if there's any. - GetByAddress(address types.AccAddress) (Info, error) - // Delete removes a key. - Delete(name, passphrase string, skipPass bool) error - // Sign bytes, looking up the private key to use. - Sign(name, passphrase string, msg []byte) ([]byte, crypto.PubKey, error) - - // CreateMnemonic generates a new mnemonic, derives a hierarchical deterministic - // key from that. and persists it to storage, encrypted using the provided password. - // It returns the generated mnemonic and the key Info. It returns an error if it fails to - // generate a key for the given algo type, or if another key is already stored under the - // same name. - CreateMnemonic(name string, language Language, passwd string, algo SigningAlgo) (info Info, seed string, err error) - - // CreateAccount converts a mnemonic to a private key and BIP 32 HD Path - // and persists it, encrypted with the given password. - CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd, hdPath string, algo SigningAlgo) (Info, error) - - // CreateLedger creates, stores, and returns a new Ledger key reference - CreateLedger(name string, algo SigningAlgo, hrp string, account, index uint32) (info Info, err error) - - // CreateOffline creates, stores, and returns a new offline key reference - CreateOffline(name string, pubkey crypto.PubKey, algo SigningAlgo) (info Info, err error) - - // CreateMulti creates, stores, and returns a new multsig (offline) key reference - CreateMulti(name string, pubkey crypto.PubKey) (info Info, err error) - - // Import imports ASCII armored Info objects. - Import(name string, armor string) (err error) - - // ImportPrivKey imports a private key in ASCII armor format. - // It returns an error if a key with the same name exists or a wrong encryption passphrase is - // supplied. - ImportPrivKey(name, armor, passphrase string) error - - // ImportPubKey imports ASCII-armored public keys. - // Store a new Info object holding a public key only, i.e. it will - // not be possible to sign with it as it lacks the secret key. - ImportPubKey(name string, armor string) (err error) - - // Export exports an Info object in ASCII armored format. - Export(name string) (armor string, err error) - - // ExportPubKey returns public keys in ASCII armored format. - // Retrieve a Info object by its name and return the public key in - // a portable format. - ExportPubKey(name string) (armor string, err error) - - // ExportPrivKey returns a private key in ASCII armored format. - // It returns an error if the key does not exist or a wrong encryption passphrase is supplied. - ExportPrivKey(name, decryptPassphrase, encryptPassphrase string) (armor string, err error) - - // ExportPrivateKeyObject *only* works on locally-stored keys. Temporary method until we redo the exporting API - ExportPrivateKeyObject(name string, passphrase string) (crypto.PrivKey, error) - - // SupportedAlgos returns a list of signing algorithms supported by the keybase - SupportedAlgos() []SigningAlgo - - // SupportedAlgosLedger returns a list of signing algorithms supported by the keybase's ledger integration - SupportedAlgosLedger() []SigningAlgo -} diff --git a/crypto/keyring/keyring.go b/crypto/keyring/keyring.go index 3f77ce4bb30f..de834428792a 100644 --- a/crypto/keyring/keyring.go +++ b/crypto/keyring/keyring.go @@ -12,15 +12,16 @@ import ( "strings" "github.com/99designs/keyring" + "github.com/cosmos/go-bip39" "github.com/pkg/errors" - "github.com/tendermint/crypto/bcrypt" tmcrypto "github.com/tendermint/tendermint/crypto" cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino" "github.com/cosmos/cosmos-sdk/client/input" "github.com/cosmos/cosmos-sdk/crypto" - "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/crypto/hd" + sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) @@ -34,48 +35,116 @@ const ( ) const ( - keyringDirNameFmt = "keyring-%s" - testKeyringDirNameFmt = "keyring-test-%s" - passKeyringPrefix = keyringDirNameFmt + keyringFileDirName = "keyring-file" + keyringTestDirName = "keyring-test" + passKeyringPrefix = "keyring-%s" +) + +var ( + _ Keyring = &keystore{} + maxPassphraseEntryAttempts = 3 ) -var _ Keybase = keyringKeybase{} +// Keyring exposes operations over a backend supported by github.com/99designs/keyring. +type Keyring interface { + // List all keys. + List() ([]Info, error) + + // Key and KeyByAddress return keys by uid and address respectively. + Key(uid string) (Info, error) + KeyByAddress(address sdk.Address) (Info, error) + + // Delete and DeleteByAddress remove keys from the keyring. + Delete(uid string) error + DeleteByAddress(address sdk.Address) error + + // NewMnemonic generates a new mnemonic, derives a hierarchical deterministic + // key from that, and persists it to the storage. Returns the generated mnemonic and the key + // Info. It returns an error if it fails to generate a key for the given algo type, or if + // another key is already stored under the same name. + NewMnemonic(uid string, language Language, hdPath string, algo SignatureAlgo) (Info, string, error) + + // NewAccount converts a mnemonic to a private key and BIP-39 HD Path and persists it. + NewAccount(uid, mnemonic, bip39Passwd, hdPath string, algo SignatureAlgo) (Info, error) + + // SaveLedgerKey retrieves a public key reference from a Ledger device and persists it. + SaveLedgerKey(uid string, algo SignatureAlgo, hrp string, coinType, account, index uint32) (Info, error) + + // SavePubKey stores a public key and returns the persisted Info structure. + SavePubKey(uid string, pubkey tmcrypto.PubKey, algo hd.PubKeyType) (Info, error) + + // SaveMultisig stores and returns a new multsig (offline) key reference. + SaveMultisig(uid string, pubkey tmcrypto.PubKey) (Info, error) -// keyringKeybase implements the Keybase interface by using the Keyring library -// for account key persistence. -type keyringKeybase struct { - base baseKeybase - db keyring.Keyring + Signer + + Importer + Exporter } -var maxPassphraseEntryAttempts = 3 +// Signer is implemented by key stores that want to provide signing capabilities. +type Signer interface { + // Sign sign byte messages with a user key. + Sign(uid string, msg []byte) ([]byte, tmcrypto.PubKey, error) -func newKeyringKeybase(db keyring.Keyring, opts ...KeybaseOption) Keybase { - return keyringKeybase{ - db: db, - base: newBaseKeybase(opts...), - } + // SignByAddress sign byte messages with a user key providing the address. + SignByAddress(address sdk.Address, msg []byte) ([]byte, tmcrypto.PubKey, error) +} + +// Importer is implemented by key stores that support import of public and private keys. +type Importer interface { + // ImportPrivKey imports ASCII armored passphrase-encrypted private keys. + ImportPrivKey(uid, armor, passphrase string) error + // ImportPubKey imports ASCII armored public keys. + ImportPubKey(uid string, armor string) error +} + +// Exporter is implemented by key stores that support export of public and private keys. +type Exporter interface { + // Export public key + ExportPubKeyArmor(uid string) (string, error) + ExportPubKeyArmorByAddress(address sdk.Address) (string, error) + // ExportPrivKey returns a private key in ASCII armored format. + // It returns an error if the key does not exist or a wrong encryption passphrase is supplied. + ExportPrivKeyArmor(uid, encryptPassphrase string) (armor string, err error) + ExportPrivKeyArmorByAddress(address sdk.Address, encryptPassphrase string) (armor string, err error) +} + +// Option overrides keyring configuration options. +type Option func(options *Options) + +//Options define the options of the Keyring +type Options struct { + SupportedAlgos SigningAlgoList + SupportedAlgosLedger SigningAlgoList } -// NewKeyring creates a new instance of a keyring. Keybase -// options can be applied when generating this new Keybase. -// Available backends are "os", "file", "kwallet", "pass", "test". -func NewKeyring( - appName, backend, rootDir string, userInput io.Reader, opts ...KeybaseOption, -) (Keybase, error) { +// NewInMemory creates a transient keyring useful for testing +// purposes and on-the-fly key generation. +// Keybase options can be applied when generating this new Keybase. +func NewInMemory(opts ...Option) Keyring { + return newKeystore(keyring.NewArrayKeyring(nil), opts...) +} + +// NewKeyring creates a new instance of a keyring. +// Keyring ptions can be applied when generating the new instance. +// Available backends are "os", "file", "kwallet", "memory", "pass", "test". +func New( + appName, backend, rootDir string, userInput io.Reader, opts ...Option, +) (Keyring, error) { var db keyring.Keyring var err error switch backend { case BackendMemory: - return NewInMemory(opts...), nil + return NewInMemory(opts...), err case BackendTest: - db, err = keyring.Open(lkbToKeyringConfig(appName, rootDir, nil, true)) + db, err = keyring.Open(newTestBackendKeyringConfig(appName, rootDir)) case BackendFile: db, err = keyring.Open(newFileBackendKeyringConfig(appName, rootDir, userInput)) case BackendOS: - db, err = keyring.Open(lkbToKeyringConfig(appName, rootDir, userInput, false)) + db, err = keyring.Open(newOSBackendKeyringConfig(appName, rootDir, userInput)) case BackendKWallet: db, err = keyring.Open(newKWalletBackendKeyringConfig(appName, rootDir, userInput)) case BackendPass: @@ -83,135 +152,151 @@ func NewKeyring( default: return nil, fmt.Errorf("unknown keyring backend %v", backend) } + if err != nil { return nil, err } - return newKeyringKeybase(db, opts...), nil + return newKeystore(db, opts...), nil } -// NewInMemory creates a transient keyring useful for testing -// purposes and on-the-fly key generation. -// Keybase options can be applied when generating this new Keybase. -func NewInMemory(opts ...KeybaseOption) Keybase { - return newKeyringKeybase(keyring.NewArrayKeyring(nil), opts...) +type keystore struct { + db keyring.Keyring + options Options } -// CreateMnemonic generates a new key and persists it to storage, encrypted -// using the provided password. It returns the generated mnemonic and the key Info. -// An error is returned if it fails to generate a key for the given algo type, -// or if another key is already stored under the same name. -func (kb keyringKeybase) CreateMnemonic( - name string, language Language, passwd string, algo SigningAlgo, -) (info Info, mnemonic string, err error) { +func newKeystore(kr keyring.Keyring, opts ...Option) keystore { + // Default options for keybase + options := Options{ + SupportedAlgos: SigningAlgoList{hd.Secp256k1}, + SupportedAlgosLedger: SigningAlgoList{hd.Secp256k1}, + } - return kb.base.CreateMnemonic(kb, name, language, passwd, algo) + for _, optionFn := range opts { + optionFn(&options) + } + + return keystore{kr, options} } -// CreateAccount converts a mnemonic to a private key and persists it, encrypted -// with the given password. -func (kb keyringKeybase) CreateAccount( - name, mnemonic, bip39Passwd, encryptPasswd, hdPath string, algo SigningAlgo, -) (Info, error) { +func (ks keystore) ExportPubKeyArmor(uid string) (string, error) { + bz, err := ks.Key(uid) + if err != nil { + return "", err + } - return kb.base.CreateAccount(kb, name, mnemonic, bip39Passwd, encryptPasswd, hdPath, algo) + if bz == nil { + return "", fmt.Errorf("no key to export with name: %s", uid) + } + + return crypto.ArmorPubKeyBytes(bz.GetPubKey().Bytes(), string(bz.GetAlgo())), nil } -// CreateLedger creates a new locally-stored reference to a Ledger keypair. -// It returns the created key info and an error if the Ledger could not be queried. -func (kb keyringKeybase) CreateLedger( - name string, algo SigningAlgo, hrp string, account, index uint32, -) (Info, error) { +func (ks keystore) ExportPubKeyArmorByAddress(address sdk.Address) (string, error) { + info, err := ks.KeyByAddress(address) + if err != nil { + return "", err + } - return kb.base.CreateLedger(kb, name, algo, hrp, account, index) + return ks.ExportPubKeyArmor(info.GetName()) } -// CreateOffline creates a new reference to an offline keypair. It returns the -// created key info. -func (kb keyringKeybase) CreateOffline(name string, pub tmcrypto.PubKey, algo SigningAlgo) (Info, error) { - return kb.base.writeOfflineKey(kb, name, pub, algo), nil -} +func (ks keystore) ExportPrivKeyArmor(uid, encryptPassphrase string) (armor string, err error) { + priv, err := ks.ExportPrivateKeyObject(uid) + if err != nil { + return "", err + } -// CreateMulti creates a new reference to a multisig (offline) keypair. It -// returns the created key Info object. -func (kb keyringKeybase) CreateMulti(name string, pub tmcrypto.PubKey) (Info, error) { - return kb.base.writeMultisigKey(kb, name, pub), nil + info, err := ks.Key(uid) + if err != nil { + return "", err + } + + return crypto.EncryptArmorPrivKey(priv, encryptPassphrase, string(info.GetAlgo())), nil } -// List returns the keys from storage in alphabetical order. -func (kb keyringKeybase) List() ([]Info, error) { - var res []Info - keys, err := kb.db.Keys() +// ExportPrivateKeyObject exports an armored private key object. +func (ks keystore) ExportPrivateKeyObject(uid string) (tmcrypto.PrivKey, error) { + info, err := ks.Key(uid) if err != nil { return nil, err } - sort.Strings(keys) + var priv tmcrypto.PrivKey - for _, key := range keys { - if strings.HasSuffix(key, infoSuffix) { - rawInfo, err := kb.db.Get(key) - if err != nil { - return nil, err - } + switch linfo := info.(type) { + case localInfo: + if linfo.PrivKeyArmor == "" { + err = fmt.Errorf("private key not available") + return nil, err + } - if len(rawInfo.Data) == 0 { - return nil, sdkerrors.Wrap(sdkerrors.ErrKeyNotFound, key) - } + priv, err = cryptoAmino.PrivKeyFromBytes([]byte(linfo.PrivKeyArmor)) + if err != nil { + return nil, err + } - info, err := unmarshalInfo(rawInfo.Data) - if err != nil { - return nil, err - } + case ledgerInfo, offlineInfo, multiInfo: + return nil, errors.New("only works on local private keys") + } - res = append(res, info) - } + return priv, nil +} + +func (ks keystore) ExportPrivKeyArmorByAddress(address sdk.Address, encryptPassphrase string) (armor string, err error) { + byAddress, err := ks.KeyByAddress(address) + if err != nil { + return "", err } - return res, nil + return ks.ExportPrivKeyArmor(byAddress.GetName(), encryptPassphrase) } -// Get returns the public information about one key. -func (kb keyringKeybase) Get(name string) (Info, error) { - key := infoKey(name) +func (ks keystore) ImportPrivKey(uid, armor, passphrase string) error { + if _, err := ks.Key(uid); err == nil { + return fmt.Errorf("cannot overwrite key: %s", uid) + } - bs, err := kb.db.Get(string(key)) + privKey, algo, err := crypto.UnarmorDecryptPrivKey(armor, passphrase) if err != nil { - return nil, err + return errors.Wrap(err, "failed to decrypt private key") } - if len(bs.Data) == 0 { - return nil, sdkerrors.Wrap(sdkerrors.ErrKeyNotFound, name) + _, err = ks.writeLocalKey(uid, privKey, hd.PubKeyType(algo)) + if err != nil { + return err } - return unmarshalInfo(bs.Data) + return nil } -// GetByAddress fetches a key by address and returns its public information. -func (kb keyringKeybase) GetByAddress(address types.AccAddress) (Info, error) { - ik, err := kb.db.Get(string(addrHexKey(address))) +func (ks keystore) ImportPubKey(uid string, armor string) error { + if _, err := ks.Key(uid); err == nil { + return fmt.Errorf("cannot overwrite key: %s", uid) + } + + pubBytes, algo, err := crypto.UnarmorPubKeyBytes(armor) if err != nil { - return nil, err + return err } - if len(ik.Data) == 0 { - return nil, fmt.Errorf("key with address %s not found", address) + pubKey, err := cryptoAmino.PubKeyFromBytes(pubBytes) + if err != nil { + return err } - bs, err := kb.db.Get(string(ik.Data)) + _, err = ks.writeOfflineKey(uid, pubKey, hd.PubKeyType(algo)) if err != nil { - return nil, err + return err } - return unmarshalInfo(bs.Data) + return nil } -// Sign signs an arbitrary set of bytes with the named key. It returns an error -// if the key doesn't exist or the decryption fails. -func (kb keyringKeybase) Sign(name, passphrase string, msg []byte) (sig []byte, pub tmcrypto.PubKey, err error) { - info, err := kb.Get(name) +func (ks keystore) Sign(uid string, msg []byte) ([]byte, tmcrypto.PubKey, error) { + info, err := ks.Key(uid) if err != nil { - return + return nil, nil, err } var priv tmcrypto.PrivKey @@ -234,7 +319,7 @@ func (kb keyringKeybase) Sign(name, passphrase string, msg []byte) (sig []byte, return nil, info.GetPubKey(), errors.New("cannot sign with offline keys") } - sig, err = priv.Sign(msg) + sig, err := priv.Sign(msg) if err != nil { return nil, nil, err } @@ -242,91 +327,74 @@ func (kb keyringKeybase) Sign(name, passphrase string, msg []byte) (sig []byte, return sig, priv.PubKey(), nil } -// ExportPrivateKeyObject exports an armored private key object. -func (kb keyringKeybase) ExportPrivateKeyObject(name string, passphrase string) (tmcrypto.PrivKey, error) { - info, err := kb.Get(name) +func (ks keystore) SignByAddress(address sdk.Address, msg []byte) ([]byte, tmcrypto.PubKey, error) { + key, err := ks.KeyByAddress(address) if err != nil { - return nil, err + return nil, nil, err } - var priv tmcrypto.PrivKey + return ks.Sign(key.GetName(), msg) +} - switch linfo := info.(type) { - case localInfo: - if linfo.PrivKeyArmor == "" { - err = fmt.Errorf("private key not available") - return nil, err - } +func (ks keystore) SaveLedgerKey(uid string, algo SignatureAlgo, hrp string, coinType, account, index uint32) (Info, error) { + if !ks.options.SupportedAlgosLedger.Contains(algo) { + return nil, ErrUnsupportedSigningAlgo + } - priv, err = cryptoAmino.PrivKeyFromBytes([]byte(linfo.PrivKeyArmor)) - if err != nil { - return nil, err - } + hdPath := hd.NewFundraiserParams(account, coinType, index) - case ledgerInfo, offlineInfo, multiInfo: - return nil, errors.New("only works on local private keys") + priv, _, err := crypto.NewPrivKeyLedgerSecp256k1(*hdPath, hrp) + if err != nil { + return nil, err } - return priv, nil + return ks.writeLedgerKey(uid, priv.PubKey(), *hdPath, algo.Name()) } -// Export exports armored private key to the caller. -func (kb keyringKeybase) Export(name string) (armor string, err error) { - bz, err := kb.db.Get(string(infoKey(name))) +func (ks keystore) writeLedgerKey(name string, pub tmcrypto.PubKey, path hd.BIP44Params, algo hd.PubKeyType) (Info, error) { + info := newLedgerInfo(name, pub, path, algo) + err := ks.writeInfo(info) if err != nil { - return "", err + return nil, err } - if bz.Data == nil { - return "", fmt.Errorf("no key to export with name: %s", name) - } + return info, nil +} + +func (ks keystore) SaveMultisig(uid string, pubkey tmcrypto.PubKey) (Info, error) { + return ks.writeMultisigKey(uid, pubkey) +} - return crypto.ArmorInfoBytes(bz.Data), nil +func (ks keystore) SavePubKey(uid string, pubkey tmcrypto.PubKey, algo hd.PubKeyType) (Info, error) { + return ks.writeOfflineKey(uid, pubkey, algo) } -// ExportPubKey returns public keys in ASCII armored format. It retrieves an Info -// object by its name and return the public key in a portable format. -func (kb keyringKeybase) ExportPubKey(name string) (armor string, err error) { - bz, err := kb.Get(name) +func (ks keystore) DeleteByAddress(address sdk.Address) error { + info, err := ks.KeyByAddress(address) if err != nil { - return "", err + return err } - if bz == nil { - return "", fmt.Errorf("no key to export with name: %s", name) + err = ks.Delete(info.GetName()) + if err != nil { + return err } - return crypto.ArmorPubKeyBytes(bz.GetPubKey().Bytes(), string(bz.GetAlgo())), nil + return nil } -// Import imports armored private key. -func (kb keyringKeybase) Import(name string, armor string) error { - bz, _ := kb.Get(name) - - if bz != nil { - pubkey := bz.GetPubKey() - - if len(pubkey.Bytes()) > 0 { - return fmt.Errorf("cannot overwrite data for name: %s", name) - } - } - - infoBytes, err := crypto.UnarmorInfoBytes(armor) +func (ks keystore) Delete(uid string) error { + info, err := ks.Key(uid) if err != nil { return err } - info, err := unmarshalInfo(infoBytes) + err = ks.db.Remove(addrHexKeyAsString(info.GetAddress())) if err != nil { return err } - kb.writeInfo(name, info) - - err = kb.db.Set(keyring.Item{ - Key: string(addrHexKey(info.GetAddress())), - Data: infoKey(name), - }) + err = ks.db.Remove(string(infoKey(uid))) if err != nil { return err } @@ -334,150 +402,148 @@ func (kb keyringKeybase) Import(name string, armor string) error { return nil } -// ExportPrivKey returns a private key in ASCII armored format. An error is returned -// if the key does not exist or a wrong encryption passphrase is supplied. -func (kb keyringKeybase) ExportPrivKey(name, decryptPassphrase, encryptPassphrase string) (armor string, err error) { - priv, err := kb.ExportPrivateKeyObject(name, decryptPassphrase) +func (ks keystore) KeyByAddress(address sdk.Address) (Info, error) { + ik, err := ks.db.Get(addrHexKeyAsString(address)) if err != nil { - return "", err + return nil, err } - info, err := kb.Get(name) + if len(ik.Data) == 0 { + return nil, fmt.Errorf("key with address %s not found", address) + } + + bs, err := ks.db.Get(string(ik.Data)) if err != nil { - return "", err + return nil, err } - return crypto.EncryptArmorPrivKey(priv, encryptPassphrase, string(info.GetAlgo())), nil + return unmarshalInfo(bs.Data) } -// ImportPrivKey imports a private key in ASCII armor format. An error is returned -// if a key with the same name exists or a wrong encryption passphrase is -// supplied. -func (kb keyringKeybase) ImportPrivKey(name, armor, passphrase string) error { - if kb.HasKey(name) { - return fmt.Errorf("cannot overwrite key: %s", name) +func (ks keystore) List() ([]Info, error) { + var res []Info + keys, err := ks.db.Keys() + if err != nil { + return nil, err } - privKey, algo, err := crypto.UnarmorDecryptPrivKey(armor, passphrase) - if err != nil { - return errors.Wrap(err, "failed to decrypt private key") + sort.Strings(keys) + + for _, key := range keys { + if strings.HasSuffix(key, infoSuffix) { + rawInfo, err := ks.db.Get(key) + if err != nil { + return nil, err + } + + if len(rawInfo.Data) == 0 { + return nil, sdkerrors.Wrap(sdkerrors.ErrKeyNotFound, key) + } + + info, err := unmarshalInfo(rawInfo.Data) + if err != nil { + return nil, err + } + + res = append(res, info) + } } - // NOTE: The keyring keystore has no need for a passphrase. - kb.writeLocalKey(name, privKey, SigningAlgo(algo)) - return nil + return res, nil } -// HasKey returns whether the key exists in the keyring. -func (kb keyringKeybase) HasKey(name string) bool { - bz, _ := kb.Get(name) - return bz != nil -} +func (ks keystore) NewMnemonic(uid string, language Language, hdPath string, algo SignatureAlgo) (Info, string, error) { + if language != English { + return nil, "", ErrUnsupportedLanguage + } -// ImportPubKey imports an ASCII-armored public key. It will store a new Info -// object holding a public key only, i.e. it will not be possible to sign with -// it as it lacks the secret key. -func (kb keyringKeybase) ImportPubKey(name string, armor string) error { - bz, _ := kb.Get(name) - if bz != nil { - pubkey := bz.GetPubKey() + if !ks.isSupportedSigningAlgo(algo) { + return nil, "", ErrUnsupportedSigningAlgo + } - if len(pubkey.Bytes()) > 0 { - return fmt.Errorf("cannot overwrite data for name: %s", name) - } + // Default number of words (24): This generates a mnemonic directly from the + // number of words by reading system entropy. + entropy, err := bip39.NewEntropy(defaultEntropySize) + if err != nil { + return nil, "", err } - pubBytes, algo, err := crypto.UnarmorPubKeyBytes(armor) + mnemonic, err := bip39.NewMnemonic(entropy) if err != nil { - return err + return nil, "", err } - pubKey, err := cryptoAmino.PubKeyFromBytes(pubBytes) + info, err := ks.NewAccount(uid, mnemonic, DefaultBIP39Passphrase, hdPath, algo) if err != nil { - return err + return nil, "", err } - kb.base.writeOfflineKey(kb, name, pubKey, SigningAlgo(algo)) - return nil + return info, mnemonic, err } -// Delete removes key forever, but we must present the proper passphrase before -// deleting it (for security). It returns an error if the key doesn't exist or -// passphrases don't match. The passphrase is ignored when deleting references to -// offline and Ledger / HW wallet keys. -func (kb keyringKeybase) Delete(name, _ string, _ bool) error { - // verify we have the proper password before deleting - info, err := kb.Get(name) - if err != nil { - return err +func (ks keystore) NewAccount(uid string, mnemonic string, bip39Passphrase string, hdPath string, algo SignatureAlgo) (Info, error) { + if !ks.isSupportedSigningAlgo(algo) { + return nil, ErrUnsupportedSigningAlgo } - err = kb.db.Remove(string(addrHexKey(info.GetAddress()))) + // create master key and derive first key for keyring + derivedPriv, err := algo.Derive()(mnemonic, bip39Passphrase, hdPath) if err != nil { - return err + return nil, err } - err = kb.db.Remove(string(infoKey(name))) - if err != nil { - return err - } + privKey := algo.Generate()(derivedPriv) - return nil + return ks.writeLocalKey(uid, privKey, algo.Name()) } -// SupportedAlgos returns a list of supported signing algorithms. -func (kb keyringKeybase) SupportedAlgos() []SigningAlgo { - return kb.base.SupportedAlgos() +func (ks keystore) isSupportedSigningAlgo(algo SignatureAlgo) bool { + return ks.options.SupportedAlgos.Contains(algo) } -// SupportedAlgosLedger returns a list of supported ledger signing algorithms. -func (kb keyringKeybase) SupportedAlgosLedger() []SigningAlgo { - return kb.base.SupportedAlgosLedger() -} +func (ks keystore) Key(uid string) (Info, error) { + key := infoKey(uid) -func (kb keyringKeybase) writeLocalKey(name string, priv tmcrypto.PrivKey, algo SigningAlgo) Info { - // encrypt private key using keyring - pub := priv.PubKey() - info := newLocalInfo(name, pub, string(priv.Bytes()), algo) + bs, err := ks.db.Get(string(key)) + if err != nil { + return nil, err + } - kb.writeInfo(name, info) - return info -} + if len(bs.Data) == 0 { + return nil, sdkerrors.Wrap(sdkerrors.ErrKeyNotFound, uid) + } -func (kb keyringKeybase) writeInfo(name string, info Info) { - // write the info by key - key := infoKey(name) - serializedInfo := marshalInfo(info) + return unmarshalInfo(bs.Data) +} - err := kb.db.Set(keyring.Item{ - Key: string(key), - Data: serializedInfo, - }) +// SignWithLedger signs a binary message with the ledger device referenced by an Info object +// and returns the signed bytes and the public key. It returns an error if the device could +// not be queried or it returned an error. +func SignWithLedger(info Info, msg []byte) (sig []byte, pub tmcrypto.PubKey, err error) { + switch info.(type) { + case *ledgerInfo, ledgerInfo: + default: + return nil, nil, errors.New("not a ledger object") + } + path, err := info.GetPath() if err != nil { - panic(err) + return } - err = kb.db.Set(keyring.Item{ - Key: string(addrHexKey(info.GetAddress())), - Data: key, - }) + priv, err := crypto.NewPrivKeyLedgerSecp256k1Unsafe(*path) if err != nil { - panic(err) + return } -} -func lkbToKeyringConfig(appName, dir string, buf io.Reader, test bool) keyring.Config { - if test { - return keyring.Config{ - AllowedBackends: []keyring.BackendType{keyring.FileBackend}, - ServiceName: appName, - FileDir: filepath.Join(dir, fmt.Sprintf(testKeyringDirNameFmt, appName)), - FilePasswordFunc: func(_ string) (string, error) { - return "test", nil - }, - } + sig, err = priv.Sign(msg) + if err != nil { + return nil, nil, err } + return sig, priv.PubKey(), nil +} + +func newOSBackendKeyringConfig(appName, dir string, buf io.Reader) keyring.Config { return keyring.Config{ ServiceName: appName, FileDir: dir, @@ -485,6 +551,17 @@ func lkbToKeyringConfig(appName, dir string, buf io.Reader, test bool) keyring.C } } +func newTestBackendKeyringConfig(appName, dir string) keyring.Config { + return keyring.Config{ + AllowedBackends: []keyring.BackendType{keyring.FileBackend}, + ServiceName: appName, + FileDir: filepath.Join(dir, keyringTestDirName), + FilePasswordFunc: func(_ string) (string, error) { + return "test", nil + }, + } +} + func newKWalletBackendKeyringConfig(appName, _ string, _ io.Reader) keyring.Config { return keyring.Config{ AllowedBackends: []keyring.BackendType{keyring.KWalletBackend}, @@ -494,7 +571,7 @@ func newKWalletBackendKeyringConfig(appName, _ string, _ io.Reader) keyring.Conf } } -func newPassBackendKeyringConfig(appName, dir string, _ io.Reader) keyring.Config { +func newPassBackendKeyringConfig(appName, _ string, _ io.Reader) keyring.Config { prefix := fmt.Sprintf(passKeyringPrefix, appName) return keyring.Config{ AllowedBackends: []keyring.BackendType{keyring.PassBackend}, @@ -504,7 +581,7 @@ func newPassBackendKeyringConfig(appName, dir string, _ io.Reader) keyring.Confi } func newFileBackendKeyringConfig(name, dir string, buf io.Reader) keyring.Config { - fileDir := filepath.Join(dir, fmt.Sprintf(keyringDirNameFmt, name)) + fileDir := filepath.Join(dir, keyringFileDirName) return keyring.Config{ AllowedBackends: []keyring.BackendType{keyring.FileBackend}, ServiceName: name, @@ -586,6 +663,88 @@ func newRealPrompt(dir string, buf io.Reader) func(string) (string, error) { } } -func addrHexKey(address types.AccAddress) []byte { - return []byte(fmt.Sprintf("%s.%s", hex.EncodeToString(address.Bytes()), addressSuffix)) +func (ks keystore) writeLocalKey(name string, priv tmcrypto.PrivKey, algo hd.PubKeyType) (Info, error) { + // encrypt private key using keyring + pub := priv.PubKey() + + info := newLocalInfo(name, pub, string(priv.Bytes()), algo) + err := ks.writeInfo(info) + if err != nil { + return nil, err + } + + return info, nil +} + +func (ks keystore) writeInfo(info Info) error { + // write the info by key + key := infoKey(info.GetName()) + serializedInfo := marshalInfo(info) + + exists, err := ks.existsInDb(info) + if exists { + return fmt.Errorf("public key already exist in keybase") + } + if err != nil { + return err + } + + err = ks.db.Set(keyring.Item{ + Key: string(key), + Data: serializedInfo, + }) + if err != nil { + return err + } + + err = ks.db.Set(keyring.Item{ + Key: addrHexKeyAsString(info.GetAddress()), + Data: key, + }) + if err != nil { + return err + } + + return nil +} + +func (ks keystore) existsInDb(info Info) (bool, error) { + if _, err := ks.db.Get(addrHexKeyAsString(info.GetAddress())); err == nil { + return true, nil // address lookup succeeds - info exists + } else if err != keyring.ErrKeyNotFound { + return false, err // received unexpected error - returns error + } + + if _, err := ks.db.Get(string(infoKey(info.GetName()))); err == nil { + return true, nil // uid lookup succeeds - info exists + } else if err != keyring.ErrKeyNotFound { + return false, err // received unexpected error - returns + } + + // both lookups failed, info does not exist + return false, nil +} + +func (ks keystore) writeOfflineKey(name string, pub tmcrypto.PubKey, algo hd.PubKeyType) (Info, error) { + info := newOfflineInfo(name, pub, algo) + err := ks.writeInfo(info) + if err != nil { + return nil, err + } + + return info, nil +} + +func (ks keystore) writeMultisigKey(name string, pub tmcrypto.PubKey) (Info, error) { + info := NewMultiInfo(name, pub) + err := ks.writeInfo(info) + if err != nil { + return nil, err + } + + return info, nil +} + +func addrHexKeyAsString(address sdk.Address) string { + return fmt.Sprintf("%s.%s", hex.EncodeToString(address.Bytes()), addressSuffix) } diff --git a/crypto/keyring/keyring_ledger_test.go b/crypto/keyring/keyring_ledger_test.go new file mode 100644 index 000000000000..7c4bc37b7f1b --- /dev/null +++ b/crypto/keyring/keyring_ledger_test.go @@ -0,0 +1,128 @@ +//+build ledger test_ledger_mock + +package keyring + +import ( + "bytes" + "testing" + + "github.com/cosmos/cosmos-sdk/crypto/hd" + "github.com/cosmos/cosmos-sdk/tests" + "github.com/cosmos/cosmos-sdk/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" +) + +func TestInMemoryCreateLedger(t *testing.T) { + kb := NewInMemory() + + ledger, err := kb.SaveLedgerKey("some_account", hd.Secp256k1, "cosmos", 118, 3, 1) + + if err != nil { + require.Error(t, err) + require.Equal(t, "ledger nano S: support for ledger devices is not available in this executable", err.Error()) + require.Nil(t, ledger) + t.Skip("ledger nano S: support for ledger devices is not available in this executable") + return + } + + // The mock is available, check that the address is correct + pubKey := ledger.GetPubKey() + pk, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pubKey) + require.NoError(t, err) + require.Equal(t, "cosmospub1addwnpepqdszcr95mrqqs8lw099aa9h8h906zmet22pmwe9vquzcgvnm93eqygufdlv", pk) + + // Check that restoring the key gets the same results + restoredKey, err := kb.Key("some_account") + require.NoError(t, err) + require.NotNil(t, restoredKey) + require.Equal(t, "some_account", restoredKey.GetName()) + require.Equal(t, TypeLedger, restoredKey.GetType()) + pubKey = restoredKey.GetPubKey() + pk, err = sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pubKey) + require.NoError(t, err) + require.Equal(t, "cosmospub1addwnpepqdszcr95mrqqs8lw099aa9h8h906zmet22pmwe9vquzcgvnm93eqygufdlv", pk) + + path, err := restoredKey.GetPath() + require.NoError(t, err) + require.Equal(t, "44'/118'/3'/0/1", path.String()) +} + +// TestSignVerify does some detailed checks on how we sign and validate +// signatures +func TestSignVerifyKeyRingWithLedger(t *testing.T) { + dir, cleanup := tests.NewTestCaseDir(t) + t.Cleanup(cleanup) + kb, err := New("keybasename", "test", dir, nil) + require.NoError(t, err) + + i1, err := kb.SaveLedgerKey("key", hd.Secp256k1, "cosmos", 118, 0, 0) + if err != nil { + require.Equal(t, "ledger nano S: support for ledger devices is not available in this executable", err.Error()) + t.Skip("ledger nano S: support for ledger devices is not available in this executable") + return + } + require.Equal(t, "key", i1.GetName()) + + d1 := []byte("my first message") + s1, pub1, err := kb.Sign("key", d1) + require.NoError(t, err) + + s2, pub2, err := SignWithLedger(i1, d1) + require.NoError(t, err) + + require.True(t, pub1.Equals(pub2)) + require.True(t, bytes.Equal(s1, s2)) + + require.Equal(t, i1.GetPubKey(), pub1) + require.Equal(t, i1.GetPubKey(), pub2) + require.True(t, pub1.VerifyBytes(d1, s1)) + require.True(t, i1.GetPubKey().VerifyBytes(d1, s1)) + require.True(t, bytes.Equal(s1, s2)) + + localInfo, _, err := kb.NewMnemonic("test", English, types.FullFundraiserPath, hd.Secp256k1) + require.NoError(t, err) + _, _, err = SignWithLedger(localInfo, d1) + require.Error(t, err) + require.Equal(t, "not a ledger object", err.Error()) +} + +func TestAltKeyring_SaveLedgerKey(t *testing.T) { + dir, clean := tests.NewTestCaseDir(t) + t.Cleanup(clean) + + keyring, err := New(t.Name(), BackendTest, dir, nil) + require.NoError(t, err) + + // Test unsupported Algo + _, err = keyring.SaveLedgerKey("key", notSupportedAlgo{}, "cosmos", 118, 0, 0) + require.EqualError(t, err, ErrUnsupportedSigningAlgo.Error()) + + ledger, err := keyring.SaveLedgerKey("some_account", hd.Secp256k1, "cosmos", 118, 3, 1) + if err != nil { + require.Equal(t, "ledger nano S: support for ledger devices is not available in this executable", err.Error()) + t.Skip("ledger nano S: support for ledger devices is not available in this executable") + return + } + // The mock is available, check that the address is correct + require.Equal(t, "some_account", ledger.GetName()) + pubKey := ledger.GetPubKey() + pk, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pubKey) + require.NoError(t, err) + require.Equal(t, "cosmospub1addwnpepqdszcr95mrqqs8lw099aa9h8h906zmet22pmwe9vquzcgvnm93eqygufdlv", pk) + + // Check that restoring the key gets the same results + restoredKey, err := keyring.Key("some_account") + require.NoError(t, err) + require.NotNil(t, restoredKey) + require.Equal(t, "some_account", restoredKey.GetName()) + require.Equal(t, TypeLedger, restoredKey.GetType()) + pubKey = restoredKey.GetPubKey() + pk, err = sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pubKey) + require.NoError(t, err) + require.Equal(t, "cosmospub1addwnpepqdszcr95mrqqs8lw099aa9h8h906zmet22pmwe9vquzcgvnm93eqygufdlv", pk) + + path, err := restoredKey.GetPath() + require.NoError(t, err) + require.Equal(t, "44'/118'/3'/0/1", path.String()) +} diff --git a/crypto/keyring/keyring_test.go b/crypto/keyring/keyring_test.go index 83cd5a409d3e..566fd2c87ba4 100644 --- a/crypto/keyring/keyring_test.go +++ b/crypto/keyring/keyring_test.go @@ -1,46 +1,49 @@ package keyring import ( - "bytes" - "errors" "fmt" "strings" "testing" - "github.com/stretchr/testify/assert" + "github.com/99designs/keyring" + "github.com/cosmos/go-bip39" "github.com/stretchr/testify/require" - "github.com/tendermint/go-amino" tmcrypto "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/ed25519" - tmamino "github.com/tendermint/tendermint/crypto/encoding/amino" "github.com/tendermint/tendermint/crypto/multisig" "github.com/tendermint/tendermint/crypto/secp256k1" - "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/crypto" - "github.com/cosmos/cosmos-sdk/crypto/keys/hd" + "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/tests" + "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types" ) +const ( + someKey = "theKey" + theID = "theID" + otherID = "otherID" +) + func init() { crypto.BcryptSecurityParameter = 1 } -const ( - nums = "1234" - foobar = "foobar" -) - func TestNewKeyring(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) mockIn := strings.NewReader("") t.Cleanup(cleanup) - kr, err := NewKeyring("cosmos", BackendFile, dir, mockIn) + kr, err := New("cosmos", BackendFile, dir, mockIn) require.NoError(t, err) + nilKr, err := New("cosmos", "fuzzy", dir, mockIn) + require.Error(t, err) + require.Nil(t, nilKr) + require.Equal(t, "unknown keyring backend fuzzy", err.Error()) + mockIn.Reset("password\npassword\n") - info, _, err := kr.CreateMnemonic("foo", English, "password", Secp256k1) + info, _, err := kr.NewMnemonic("foo", English, types.FullFundraiserPath, hd.Secp256k1) require.NoError(t, err) require.Equal(t, "foo", info.GetName()) } @@ -48,41 +51,40 @@ func TestNewKeyring(t *testing.T) { func TestKeyManagementKeyRing(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) t.Cleanup(cleanup) - kb, err := NewKeyring("keybasename", "test", dir, nil) + kb, err := New("keybasename", "test", dir, nil) require.NoError(t, err) - algo := Secp256k1 + algo := hd.Secp256k1 n1, n2, n3 := "personal", "business", "other" - p1, p2 := "1234", "really-secure!@#$" // Check empty state l, err := kb.List() require.Nil(t, err) - assert.Empty(t, l) + require.Empty(t, l) - _, _, err = kb.CreateMnemonic(n1, English, p1, Ed25519) + _, _, err = kb.NewMnemonic(n1, English, types.FullFundraiserPath, notSupportedAlgo{}) require.Error(t, err, "ed25519 keys are currently not supported by keybase") // create some keys - _, err = kb.Get(n1) + _, err = kb.Key(n1) require.Error(t, err) - i, _, err := kb.CreateMnemonic(n1, English, p1, algo) + i, _, err := kb.NewMnemonic(n1, English, types.FullFundraiserPath, algo) require.NoError(t, err) require.Equal(t, n1, i.GetName()) - _, _, err = kb.CreateMnemonic(n2, English, p2, algo) + _, _, err = kb.NewMnemonic(n2, English, types.FullFundraiserPath, algo) require.NoError(t, err) // we can get these keys - i2, err := kb.Get(n2) + i2, err := kb.Key(n2) require.NoError(t, err) - _, err = kb.Get(n3) + _, err = kb.Key(n3) require.NotNil(t, err) - _, err = kb.GetByAddress(accAddr(i2)) + _, err = kb.KeyByAddress(accAddr(i2)) require.NoError(t, err) addr, err := sdk.AccAddressFromBech32("cosmos1yq8lgssgxlx9smjhes6ryjasmqmd3ts2559g0t") require.NoError(t, err) - _, err = kb.GetByAddress(addr) + _, err = kb.KeyByAddress(addr) require.NotNil(t, err) // list shows them in order @@ -95,21 +97,21 @@ func TestKeyManagementKeyRing(t *testing.T) { require.Equal(t, i2.GetPubKey(), keyS[0].GetPubKey()) // deleting a key removes it - err = kb.Delete("bad name", "foo", false) + err = kb.Delete("bad name") require.NotNil(t, err) - err = kb.Delete(n1, p1, false) + err = kb.Delete(n1) require.NoError(t, err) keyS, err = kb.List() require.NoError(t, err) require.Equal(t, 1, len(keyS)) - _, err = kb.Get(n1) + _, err = kb.Key(n1) require.Error(t, err) // create an offline key o1 := "offline" priv1 := ed25519.GenPrivKey() pub1 := priv1.PubKey() - i, err = kb.CreateOffline(o1, pub1, Ed25519) + i, err = kb.SavePubKey(o1, pub1, hd.Ed25519Type) require.Nil(t, err) require.Equal(t, pub1, i.GetPubKey()) require.Equal(t, o1, i.GetName()) @@ -118,98 +120,52 @@ func TestKeyManagementKeyRing(t *testing.T) { require.Equal(t, 2, len(keyS)) // delete the offline key - err = kb.Delete(o1, "", false) + err = kb.Delete(o1) require.NoError(t, err) keyS, err = kb.List() require.NoError(t, err) require.Equal(t, 1, len(keyS)) // addr cache gets nuked - and test skip flag - require.NoError(t, kb.Delete(n2, "", true)) -} - -// TestSignVerify does some detailed checks on how we sign and validate -// signatures -func TestSignVerifyKeyRingWithLedger(t *testing.T) { - dir, cleanup := tests.NewTestCaseDir(t) - t.Cleanup(cleanup) - kb, err := NewKeyring("keybasename", "test", dir, nil) - require.NoError(t, err) - - i1, err := kb.CreateLedger("key", Secp256k1, "cosmos", 0, 0) - if err != nil { - require.Equal(t, "ledger nano S: support for ledger devices is not available in this executable", err.Error()) - t.Skip("ledger nano S: support for ledger devices is not available in this executable") - return - } - require.Equal(t, "key", i1.GetName()) - - p1 := "1234" - d1 := []byte("my first message") - s1, pub1, err := kb.Sign("key", p1, d1) - require.NoError(t, err) - - s2, pub2, err := SignWithLedger(i1, d1) - require.NoError(t, err) - - require.Equal(t, i1.GetPubKey(), pub1) - require.Equal(t, i1.GetPubKey(), pub2) - require.True(t, pub1.VerifyBytes(d1, s1)) - require.True(t, i1.GetPubKey().VerifyBytes(d1, s1)) - require.True(t, bytes.Equal(s1, s2)) - - localInfo, _, err := kb.CreateMnemonic("test", English, p1, Secp256k1) - require.NoError(t, err) - _, _, err = SignWithLedger(localInfo, d1) - require.Error(t, err) - require.Equal(t, "not a ledger object", err.Error()) + require.NoError(t, kb.Delete(n2)) } func TestSignVerifyKeyRing(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) t.Cleanup(cleanup) - kb, err := NewKeyring("keybasename", "test", dir, nil) + + kb, err := New("keybasename", "test", dir, nil) require.NoError(t, err) - algo := Secp256k1 + algo := hd.Secp256k1 n1, n2, n3 := "some dude", "a dudette", "dude-ish" - p1, p2, p3 := "1234", "foobar", "foobar" // create two users and get their info - i1, _, err := kb.CreateMnemonic(n1, English, p1, algo) + i1, _, err := kb.NewMnemonic(n1, English, types.FullFundraiserPath, algo) require.Nil(t, err) - i2, _, err := kb.CreateMnemonic(n2, English, p2, algo) + i2, _, err := kb.NewMnemonic(n2, English, types.FullFundraiserPath, algo) require.Nil(t, err) - // Import a public key - armor, err := kb.ExportPubKey(n2) - require.Nil(t, err) - err = kb.ImportPubKey(n3, armor) - require.NoError(t, err) - i3, err := kb.Get(n3) - require.NoError(t, err) - require.Equal(t, i3.GetName(), n3) - // let's try to sign some messages d1 := []byte("my first message") d2 := []byte("some other important info!") d3 := []byte("feels like I forgot something...") // try signing both data with both .. - s11, pub1, err := kb.Sign(n1, p1, d1) + s11, pub1, err := kb.Sign(n1, d1) require.Nil(t, err) require.Equal(t, i1.GetPubKey(), pub1) - s12, pub1, err := kb.Sign(n1, p1, d2) + s12, pub1, err := kb.Sign(n1, d2) require.Nil(t, err) require.Equal(t, i1.GetPubKey(), pub1) - s21, pub2, err := kb.Sign(n2, p2, d1) + s21, pub2, err := kb.Sign(n2, d1) require.Nil(t, err) require.Equal(t, i2.GetPubKey(), pub2) - s22, pub2, err := kb.Sign(n2, p2, d2) + s22, pub2, err := kb.Sign(n2, d2) require.Nil(t, err) require.Equal(t, i2.GetPubKey(), pub2) @@ -238,7 +194,17 @@ func TestSignVerifyKeyRing(t *testing.T) { } // Now try to sign data with a secret-less key - _, _, err = kb.Sign(n3, p3, d3) + // Import a public key + armor, err := kb.ExportPubKeyArmor(n2) + require.NoError(t, err) + require.NoError(t, kb.Delete(n2)) + + require.NoError(t, kb.ImportPubKey(n3, armor)) + i3, err := kb.Key(n3) + require.NoError(t, err) + require.Equal(t, i3.GetName(), n3) + + _, _, err = kb.Sign(n3, d3) require.Error(t, err) require.Equal(t, "cannot sign with offline keys", err.Error()) } @@ -246,149 +212,138 @@ func TestSignVerifyKeyRing(t *testing.T) { func TestExportImportKeyRing(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) t.Cleanup(cleanup) - kb, err := NewKeyring("keybasename", "test", dir, nil) + kb, err := New("keybasename", "test", dir, nil) require.NoError(t, err) - info, _, err := kb.CreateMnemonic("john", English, "secretcpw", Secp256k1) + info, _, err := kb.NewMnemonic("john", English, types.FullFundraiserPath, hd.Secp256k1) require.NoError(t, err) require.Equal(t, info.GetName(), "john") - john, err := kb.Get("john") + john, err := kb.Key("john") require.NoError(t, err) require.Equal(t, info.GetName(), "john") johnAddr := info.GetPubKey().Address() - armor, err := kb.Export("john") + armor, err := kb.ExportPrivKeyArmor("john", "apassphrase") + require.NoError(t, err) + err = kb.Delete("john") require.NoError(t, err) - err = kb.Import("john2", armor) + err = kb.ImportPrivKey("john2", armor, "apassphrase") require.NoError(t, err) - john2, err := kb.Get("john2") + john2, err := kb.Key("john2") require.NoError(t, err) require.Equal(t, john.GetPubKey().Address(), johnAddr) require.Equal(t, john.GetName(), "john") - require.Equal(t, john, john2) + require.Equal(t, john.GetAddress(), john2.GetAddress()) + require.Equal(t, john.GetAlgo(), john2.GetAlgo()) + require.Equal(t, john.GetPubKey(), john2.GetPubKey()) + require.Equal(t, john.GetType(), john2.GetType()) } func TestExportImportPubKeyKeyRing(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) t.Cleanup(cleanup) - kb, err := NewKeyring("keybasename", "test", dir, nil) + kb, err := New("keybasename", "test", dir, nil) require.NoError(t, err) - algo := Secp256k1 + algo := hd.Secp256k1 // CreateMnemonic a private-public key pair and ensure consistency - notPasswd := "n9y25ah7" - info, _, err := kb.CreateMnemonic("john", English, notPasswd, algo) + info, _, err := kb.NewMnemonic("john", English, types.FullFundraiserPath, algo) require.Nil(t, err) require.NotEqual(t, info, "") require.Equal(t, info.GetName(), "john") addr := info.GetPubKey().Address() - john, err := kb.Get("john") + john, err := kb.Key("john") require.NoError(t, err) require.Equal(t, john.GetName(), "john") require.Equal(t, john.GetPubKey().Address(), addr) // Export the public key only - armor, err := kb.ExportPubKey("john") + armor, err := kb.ExportPubKeyArmor("john") + require.NoError(t, err) + err = kb.Delete("john") require.NoError(t, err) + // Import it under a different name err = kb.ImportPubKey("john-pubkey-only", armor) require.NoError(t, err) + // Ensure consistency - john2, err := kb.Get("john-pubkey-only") + john2, err := kb.Key("john-pubkey-only") require.NoError(t, err) + // Compare the public keys require.True(t, john.GetPubKey().Equals(john2.GetPubKey())) - // Ensure the original key hasn't changed - john, err = kb.Get("john") - require.NoError(t, err) - require.Equal(t, john.GetPubKey().Address(), addr) - require.Equal(t, john.GetName(), "john") // Ensure keys cannot be overwritten err = kb.ImportPubKey("john-pubkey-only", armor) require.NotNil(t, err) } -func TestExportPrivateKeyObjectKeyRing(t *testing.T) { - dir, cleanup := tests.NewTestCaseDir(t) - t.Cleanup(cleanup) - kb, err := NewKeyring("keybasename", "test", dir, nil) - require.NoError(t, err) - - info, _, err := kb.CreateMnemonic("john", English, "secretcpw", Secp256k1) - require.NoError(t, err) - require.Equal(t, info.GetName(), "john") - - // export private key object - exported, err := kb.ExportPrivateKeyObject("john", "secretcpw") - require.Nil(t, err, "%+v", err) - require.True(t, exported.PubKey().Equals(info.GetPubKey())) -} - func TestAdvancedKeyManagementKeyRing(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) t.Cleanup(cleanup) - kb, err := NewKeyring("keybasename", "test", dir, nil) + + kb, err := New("keybasename", "test", dir, nil) require.NoError(t, err) - algo := Secp256k1 + algo := hd.Secp256k1 n1, n2 := "old-name", "new name" - p1 := "1234" // make sure key works with initial password - _, _, err = kb.CreateMnemonic(n1, English, p1, algo) + _, _, err = kb.NewMnemonic(n1, English, types.FullFundraiserPath, algo) require.Nil(t, err, "%+v", err) - _, err = kb.Export(n1 + ".notreal") + _, err = kb.ExportPubKeyArmor(n1 + ".notreal") require.NotNil(t, err) - _, err = kb.Export(" " + n1) + _, err = kb.ExportPubKeyArmor(" " + n1) require.NotNil(t, err) - _, err = kb.Export(n1 + " ") + _, err = kb.ExportPubKeyArmor(n1 + " ") require.NotNil(t, err) - _, err = kb.Export("") + _, err = kb.ExportPubKeyArmor("") require.NotNil(t, err) - exported, err := kb.Export(n1) + exported, err := kb.ExportPubKeyArmor(n1) require.Nil(t, err, "%+v", err) + err = kb.Delete(n1) + require.NoError(t, err) // import succeeds - err = kb.Import(n2, exported) + err = kb.ImportPubKey(n2, exported) require.NoError(t, err) // second import fails - err = kb.Import(n2, exported) + err = kb.ImportPubKey(n2, exported) require.NotNil(t, err) } func TestSeedPhraseKeyRing(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) t.Cleanup(cleanup) - kb, err := NewKeyring("keybasename", "test", dir, nil) + kb, err := New("keybasename", "test", dir, nil) require.NoError(t, err) - algo := Secp256k1 + algo := hd.Secp256k1 n1, n2 := "lost-key", "found-again" - p1, p2 := "1234", "foobar" // make sure key works with initial password - info, mnemonic, err := kb.CreateMnemonic(n1, English, p1, algo) + info, mnemonic, err := kb.NewMnemonic(n1, English, types.FullFundraiserPath, algo) require.Nil(t, err, "%+v", err) require.Equal(t, n1, info.GetName()) - assert.NotEmpty(t, mnemonic) + require.NotEmpty(t, mnemonic) // now, let us delete this key - err = kb.Delete(n1, p1, false) + err = kb.Delete(n1) require.Nil(t, err, "%+v", err) - _, err = kb.Get(n1) + _, err = kb.Key(n1) require.NotNil(t, err) // let us re-create it from the mnemonic-phrase params := *hd.NewFundraiserParams(0, sdk.CoinType, 0) hdPath := params.String() - newInfo, err := kb.CreateAccount(n2, mnemonic, DefaultBIP39Passphrase, p2, hdPath, Secp256k1) + newInfo, err := kb.NewAccount(n2, mnemonic, DefaultBIP39Passphrase, hdPath, hd.Secp256k1) require.NoError(t, err) require.Equal(t, n2, newInfo.GetName()) require.Equal(t, info.GetPubKey().Address(), newInfo.GetPubKey().Address()) @@ -398,192 +353,98 @@ func TestSeedPhraseKeyRing(t *testing.T) { func TestKeyringKeybaseExportImportPrivKey(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) t.Cleanup(cleanup) - kb, err := NewKeyring("keybasename", "test", dir, nil) + kb, err := New("keybasename", "test", dir, nil) require.NoError(t, err) - _, _, err = kb.CreateMnemonic("john", English, "password", Secp256k1) + + _, _, err = kb.NewMnemonic("john", English, types.FullFundraiserPath, hd.Secp256k1) require.NoError(t, err) - // no error, password is irrelevant, keystr cointains ASCII armored private key - keystr, err := kb.ExportPrivKey("john", "wrongpassword", "password") + keystr, err := kb.ExportPrivKeyArmor("john", "somepassword") require.NoError(t, err) require.NotEmpty(t, keystr) + err = kb.Delete("john") + require.NoError(t, err) // try import the key - wrong password - err = kb.ImportPrivKey("john2", keystr, "somepassword") + err = kb.ImportPrivKey("john2", keystr, "bad pass") require.Equal(t, "failed to decrypt private key: ciphertext decryption failed", err.Error()) // try import the key with the correct password - require.NoError(t, kb.ImportPrivKey("john2", keystr, "password")) + require.NoError(t, kb.ImportPrivKey("john2", keystr, "somepassword")) // overwrite is not allowed err = kb.ImportPrivKey("john2", keystr, "password") require.Equal(t, "cannot overwrite key: john2", err.Error()) // try export non existing key - _, err = kb.ExportPrivKey("john3", "wrongpassword", "password") + _, err = kb.ExportPrivKeyArmor("john3", "wrongpassword") require.Equal(t, "The specified item could not be found in the keyring", err.Error()) } -func TestSupportedAlgos(t *testing.T) { - dir, cleanup := tests.NewTestCaseDir(t) - t.Cleanup(cleanup) - kb, err := NewKeyring("keybasename", "test", dir, nil) - require.NoError(t, err) - require.Equal(t, []SigningAlgo{"secp256k1"}, kb.SupportedAlgos()) - require.Equal(t, []SigningAlgo{"secp256k1"}, kb.SupportedAlgosLedger()) -} - -func TestCustomDerivFuncKey(t *testing.T) { - kb := NewInMemory(WithDeriveFunc(func(mnemonic string, bip39Passphrase, hdPath string, algo SigningAlgo) ([]byte, error) { - return nil, errors.New("cannot derive keys") - })) - _, _, err := kb.CreateMnemonic("test", English, "", "") - require.Error(t, err, "cannot derive keys") -} - func TestInMemoryLanguage(t *testing.T) { kb := NewInMemory() - _, _, err := kb.CreateMnemonic("something", Japanese, "no_pass", Secp256k1) + _, _, err := kb.NewMnemonic("something", Japanese, types.FullFundraiserPath, hd.Secp256k1) require.Error(t, err) require.Equal(t, "unsupported language: only english is supported", err.Error()) } func TestInMemoryCreateMultisig(t *testing.T) { - kb, err := NewKeyring("keybasename", "memory", "", nil) + kb, err := New("keybasename", "memory", "", nil) require.NoError(t, err) multi := multisig.PubKeyMultisigThreshold{ K: 1, PubKeys: []tmcrypto.PubKey{secp256k1.GenPrivKey().PubKey()}, } - _, err = kb.CreateMulti("multi", multi) + _, err = kb.SaveMultisig("multi", multi) require.NoError(t, err) } func TestInMemoryCreateAccountInvalidMnemonic(t *testing.T) { kb := NewInMemory() - _, err := kb.CreateAccount( + _, err := kb.NewAccount( "some_account", "malarkey pair crucial catch public canyon evil outer stage ten gym tornado", - "", "", CreateHDPath(0, 0).String(), Secp256k1) + "", hd.CreateHDPath(118, 0, 0).String(), hd.Secp256k1) require.Error(t, err) require.Equal(t, "Invalid mnemonic", err.Error()) } -func TestInMemoryCreateLedgerUnsupportedAlgo(t *testing.T) { - kb := NewInMemory() - - supportedLedgerAlgos := kb.SupportedAlgosLedger() - for _, supportedAlgo := range supportedLedgerAlgos { - if Ed25519 == supportedAlgo { - require.FailNow(t, "Was not an unsupported algorithm") - } - } - - _, err := kb.CreateLedger("some_account", Ed25519, "cosmos", 0, 1) - require.Error(t, err) - require.Equal(t, "unsupported signing algo", err.Error()) -} - -func TestInMemoryCreateLedger(t *testing.T) { - kb := NewInMemory(WithSupportedAlgosLedger([]SigningAlgo{Secp256k1, Ed25519})) - - // test_cover and test_unit will result in different answers - // test_cover does not compile some dependencies so ledger is disabled - // test_unit may add a ledger mock - // both cases are acceptable - supportedLedgerAlgos := kb.SupportedAlgosLedger() - secpSupported := false - edSupported := false - for _, supportedAlgo := range supportedLedgerAlgos { - secpSupported = secpSupported || (supportedAlgo == Secp256k1) - edSupported = edSupported || (supportedAlgo == Ed25519) - } - require.True(t, secpSupported) - require.True(t, edSupported) - - ledger, err := kb.CreateLedger("some_account", Secp256k1, "cosmos", 3, 1) - - if err != nil { - require.Error(t, err) - require.Equal(t, "ledger nano S: support for ledger devices is not available in this executable", err.Error()) - require.Nil(t, ledger) - t.Skip("ledger nano S: support for ledger devices is not available in this executable") - return - } - - // The mock is available, check that the address is correct - pubKey := ledger.GetPubKey() - pk, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pubKey) - require.NoError(t, err) - require.Equal(t, "cosmospub1addwnpepqdszcr95mrqqs8lw099aa9h8h906zmet22pmwe9vquzcgvnm93eqygufdlv", pk) - - // Check that restoring the key gets the same results - restoredKey, err := kb.Get("some_account") - require.NoError(t, err) - require.NotNil(t, restoredKey) - require.Equal(t, "some_account", restoredKey.GetName()) - require.Equal(t, TypeLedger, restoredKey.GetType()) - pubKey = restoredKey.GetPubKey() - pk, err = sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pubKey) - require.NoError(t, err) - require.Equal(t, "cosmospub1addwnpepqdszcr95mrqqs8lw099aa9h8h906zmet22pmwe9vquzcgvnm93eqygufdlv", pk) - - path, err := restoredKey.GetPath() - require.NoError(t, err) - require.Equal(t, "44'/118'/3'/0/1", path.String()) -} - // TestInMemoryKeyManagement makes sure we can manipulate these keys well func TestInMemoryKeyManagement(t *testing.T) { // make the storage with reasonable defaults - cstore := NewInMemory(WithSupportedAlgos([]SigningAlgo{Secp256k1, Sr25519})) - - // Test modified supported algos - supportedAlgos := cstore.SupportedAlgos() - secpSupported := false - edSupported := false - srSupported := false - for _, supportedAlgo := range supportedAlgos { - secpSupported = secpSupported || (supportedAlgo == Secp256k1) - edSupported = edSupported || (supportedAlgo == Ed25519) - srSupported = srSupported || (supportedAlgo == Sr25519) - } - require.True(t, secpSupported) - require.False(t, edSupported) - require.True(t, srSupported) + cstore := NewInMemory() - algo := Secp256k1 + algo := hd.Secp256k1 n1, n2, n3 := "personal", "business", "other" - p1, p2 := nums, "really-secure!@#$" // Check empty state l, err := cstore.List() require.Nil(t, err) require.Empty(t, l) - _, _, err = cstore.CreateMnemonic(n1, English, p1, Ed25519) + _, _, err = cstore.NewMnemonic(n1, English, types.FullFundraiserPath, notSupportedAlgo{}) require.Error(t, err, "ed25519 keys are currently not supported by keybase") // create some keys - _, err = cstore.Get(n1) + _, err = cstore.Key(n1) require.Error(t, err) - i, _, err := cstore.CreateMnemonic(n1, English, p1, algo) + i, _, err := cstore.NewMnemonic(n1, English, types.FullFundraiserPath, algo) require.NoError(t, err) require.Equal(t, n1, i.GetName()) - _, _, err = cstore.CreateMnemonic(n2, English, p2, algo) + _, _, err = cstore.NewMnemonic(n2, English, types.FullFundraiserPath, algo) require.NoError(t, err) // we can get these keys - i2, err := cstore.Get(n2) + i2, err := cstore.Key(n2) require.NoError(t, err) - _, err = cstore.Get(n3) + _, err = cstore.Key(n3) require.NotNil(t, err) - _, err = cstore.GetByAddress(accAddr(i2)) + _, err = cstore.KeyByAddress(accAddr(i2)) require.NoError(t, err) addr, err := sdk.AccAddressFromBech32("cosmos1yq8lgssgxlx9smjhes6ryjasmqmd3ts2559g0t") require.NoError(t, err) - _, err = cstore.GetByAddress(addr) + _, err = cstore.KeyByAddress(addr) require.NotNil(t, err) // list shows them in order @@ -596,39 +457,39 @@ func TestInMemoryKeyManagement(t *testing.T) { require.Equal(t, i2.GetPubKey(), keyS[0].GetPubKey()) // deleting a key removes it - err = cstore.Delete("bad name", "foo", false) + err = cstore.Delete("bad name") require.NotNil(t, err) - err = cstore.Delete(n1, p1, false) + err = cstore.Delete(n1) require.NoError(t, err) keyS, err = cstore.List() require.NoError(t, err) require.Equal(t, 1, len(keyS)) - _, err = cstore.Get(n1) + _, err = cstore.Key(n1) require.Error(t, err) // create an offline key o1 := "offline" priv1 := ed25519.GenPrivKey() pub1 := priv1.PubKey() - i, err = cstore.CreateOffline(o1, pub1, algo) + i, err = cstore.SavePubKey(o1, pub1, hd.Ed25519Type) require.Nil(t, err) require.Equal(t, pub1, i.GetPubKey()) require.Equal(t, o1, i.GetName()) iOffline := i.(*offlineInfo) - require.Equal(t, algo, iOffline.GetAlgo()) + require.Equal(t, hd.Ed25519Type, iOffline.GetAlgo()) keyS, err = cstore.List() require.NoError(t, err) require.Equal(t, 2, len(keyS)) // delete the offline key - err = cstore.Delete(o1, "", false) + err = cstore.Delete(o1) require.NoError(t, err) keyS, err = cstore.List() require.NoError(t, err) require.Equal(t, 1, len(keyS)) // addr cache gets nuked - and test skip flag - err = cstore.Delete(n2, "", true) + err = cstore.Delete(n2) require.NoError(t, err) } @@ -636,26 +497,16 @@ func TestInMemoryKeyManagement(t *testing.T) { // signatures func TestInMemorySignVerify(t *testing.T) { cstore := NewInMemory() - algo := Secp256k1 + algo := hd.Secp256k1 n1, n2, n3 := "some dude", "a dudette", "dude-ish" - p1, p2, p3 := nums, foobar, foobar // create two users and get their info - i1, _, err := cstore.CreateMnemonic(n1, English, p1, algo) - require.Nil(t, err) - - i2, _, err := cstore.CreateMnemonic(n2, English, p2, algo) + i1, _, err := cstore.NewMnemonic(n1, English, types.FullFundraiserPath, algo) require.Nil(t, err) - // Import a public key - armor, err := cstore.ExportPubKey(n2) + i2, _, err := cstore.NewMnemonic(n2, English, types.FullFundraiserPath, algo) require.Nil(t, err) - err = cstore.ImportPubKey(n3, armor) - require.NoError(t, err) - i3, err := cstore.Get(n3) - require.NoError(t, err) - require.Equal(t, i3.GetName(), n3) // let's try to sign some messages d1 := []byte("my first message") @@ -663,19 +514,19 @@ func TestInMemorySignVerify(t *testing.T) { d3 := []byte("feels like I forgot something...") // try signing both data with both .. - s11, pub1, err := cstore.Sign(n1, p1, d1) + s11, pub1, err := cstore.Sign(n1, d1) require.Nil(t, err) require.Equal(t, i1.GetPubKey(), pub1) - s12, pub1, err := cstore.Sign(n1, p1, d2) + s12, pub1, err := cstore.Sign(n1, d2) require.Nil(t, err) require.Equal(t, i1.GetPubKey(), pub1) - s21, pub2, err := cstore.Sign(n2, p2, d1) + s21, pub2, err := cstore.Sign(n2, d1) require.Nil(t, err) require.Equal(t, i2.GetPubKey(), pub2) - s22, pub2, err := cstore.Sign(n2, p2, d2) + s22, pub2, err := cstore.Sign(n2, d2) require.Nil(t, err) require.Equal(t, i2.GetPubKey(), pub2) @@ -703,8 +554,19 @@ func TestInMemorySignVerify(t *testing.T) { require.Equal(t, tc.valid, valid, "%d", i) } + // Import a public key + armor, err := cstore.ExportPubKeyArmor(n2) + require.Nil(t, err) + err = cstore.Delete(n2) + require.NoError(t, err) + err = cstore.ImportPubKey(n3, armor) + require.NoError(t, err) + i3, err := cstore.Key(n3) + require.NoError(t, err) + require.Equal(t, i3.GetName(), n3) + // Now try to sign data with a secret-less key - _, _, err = cstore.Sign(n3, p3, d3) + _, _, err = cstore.Sign(n3, d3) require.Error(t, err) require.Equal(t, "cannot sign with offline keys", err.Error()) } @@ -714,52 +576,55 @@ func TestInMemoryExportImport(t *testing.T) { // make the storage with reasonable defaults cstore := NewInMemory() - info, _, err := cstore.CreateMnemonic("john", English, "secretcpw", Secp256k1) + info, _, err := cstore.NewMnemonic("john", English, types.FullFundraiserPath, hd.Secp256k1) require.NoError(t, err) require.Equal(t, info.GetName(), "john") - john, err := cstore.Get("john") + john, err := cstore.Key("john") require.NoError(t, err) require.Equal(t, info.GetName(), "john") johnAddr := info.GetPubKey().Address() - armor, err := cstore.Export("john") + armor, err := cstore.ExportPubKeyArmor("john") + require.NoError(t, err) + err = cstore.Delete("john") require.NoError(t, err) - err = cstore.Import("john2", armor) + err = cstore.ImportPubKey("john2", armor) require.NoError(t, err) - john2, err := cstore.Get("john2") + john2, err := cstore.Key("john2") require.NoError(t, err) require.Equal(t, john.GetPubKey().Address(), johnAddr) require.Equal(t, john.GetName(), "john") - require.Equal(t, john, john2) + require.Equal(t, john.GetAddress(), john2.GetAddress()) + require.Equal(t, john.GetAlgo(), john2.GetAlgo()) + require.Equal(t, john.GetPubKey(), john2.GetPubKey()) } func TestInMemoryExportImportPrivKey(t *testing.T) { kb := NewInMemory() - info, _, err := kb.CreateMnemonic("john", English, "secretcpw", Secp256k1) + info, _, err := kb.NewMnemonic("john", English, types.FullFundraiserPath, hd.Secp256k1) require.NoError(t, err) require.Equal(t, info.GetName(), "john") - priv1, err := kb.Get("john") + priv1, err := kb.Key("john") require.NoError(t, err) - // decrypt local private key, and produce encrypted ASCII armored output - armored, err := kb.ExportPrivKey("john", "secretcpw", "new_secretcpw") + armored, err := kb.ExportPrivKeyArmor("john", "secretcpw") require.NoError(t, err) // delete exported key - require.NoError(t, kb.Delete("john", "", true)) - _, err = kb.Get("john") + require.NoError(t, kb.Delete("john")) + _, err = kb.Key("john") require.Error(t, err) // import armored key - require.NoError(t, kb.ImportPrivKey("john", armored, "new_secretcpw")) + require.NoError(t, kb.ImportPrivKey("john", armored, "secretcpw")) // ensure old and new keys match - priv2, err := kb.Get("john") + priv2, err := kb.Key("john") require.NoError(t, err) require.True(t, priv1.GetPubKey().Equals(priv2.GetPubKey())) } @@ -769,133 +634,131 @@ func TestInMemoryExportImportPubKey(t *testing.T) { cstore := NewInMemory() // CreateMnemonic a private-public key pair and ensure consistency - notPasswd := "n9y25ah7" - info, _, err := cstore.CreateMnemonic("john", English, notPasswd, Secp256k1) + info, _, err := cstore.NewMnemonic("john", English, types.FullFundraiserPath, hd.Secp256k1) require.Nil(t, err) require.NotEqual(t, info, "") require.Equal(t, info.GetName(), "john") addr := info.GetPubKey().Address() - john, err := cstore.Get("john") + john, err := cstore.Key("john") require.NoError(t, err) require.Equal(t, john.GetName(), "john") require.Equal(t, john.GetPubKey().Address(), addr) // Export the public key only - armor, err := cstore.ExportPubKey("john") + armor, err := cstore.ExportPubKeyArmor("john") + require.NoError(t, err) + err = cstore.Delete("john") require.NoError(t, err) + // Import it under a different name err = cstore.ImportPubKey("john-pubkey-only", armor) require.NoError(t, err) // Ensure consistency - john2, err := cstore.Get("john-pubkey-only") + john2, err := cstore.Key("john-pubkey-only") require.NoError(t, err) // Compare the public keys require.True(t, john.GetPubKey().Equals(john2.GetPubKey())) - // Ensure the original key hasn't changed - john, err = cstore.Get("john") - require.NoError(t, err) - require.Equal(t, john.GetPubKey().Address(), addr) - require.Equal(t, john.GetName(), "john") // Ensure keys cannot be overwritten err = cstore.ImportPubKey("john-pubkey-only", armor) require.NotNil(t, err) } -func TestInMemoryExportPrivateKeyObject(t *testing.T) { - kb := NewInMemory() - - info, _, err := kb.CreateMnemonic("john", English, "secretcpw", Secp256k1) - require.NoError(t, err) - require.Equal(t, info.GetName(), "john") - - // export private key object - _, err = kb.ExportPrivateKeyObject("john", "invalid") - require.NoError(t, err, "%+v", err) - exported, err := kb.ExportPrivateKeyObject("john", "secretcpw") - require.Nil(t, err, "%+v", err) - require.True(t, exported.PubKey().Equals(info.GetPubKey())) -} - // TestInMemoryAdvancedKeyManagement verifies update, import, export functionality func TestInMemoryAdvancedKeyManagement(t *testing.T) { // make the storage with reasonable defaults cstore := NewInMemory() - algo := Secp256k1 + algo := hd.Secp256k1 n1, n2 := "old-name", "new name" - p1 := nums // make sure key works with initial password - _, _, err := cstore.CreateMnemonic(n1, English, p1, algo) + _, _, err := cstore.NewMnemonic(n1, English, types.FullFundraiserPath, algo) require.Nil(t, err, "%+v", err) // exporting requires the proper name and passphrase - _, err = cstore.Export(n1 + ".notreal") + _, err = cstore.ExportPubKeyArmor(n1 + ".notreal") require.NotNil(t, err) - _, err = cstore.Export(" " + n1) + _, err = cstore.ExportPubKeyArmor(" " + n1) require.NotNil(t, err) - _, err = cstore.Export(n1 + " ") + _, err = cstore.ExportPubKeyArmor(n1 + " ") require.NotNil(t, err) - _, err = cstore.Export("") + _, err = cstore.ExportPubKeyArmor("") require.NotNil(t, err) - exported, err := cstore.Export(n1) + exported, err := cstore.ExportPubKeyArmor(n1) require.Nil(t, err, "%+v", err) + err = cstore.Delete(n1) + require.NoError(t, err) // import succeeds - err = cstore.Import(n2, exported) + err = cstore.ImportPubKey(n2, exported) require.NoError(t, err) // second import fails - err = cstore.Import(n2, exported) + err = cstore.ImportPubKey(n2, exported) require.NotNil(t, err) } // TestInMemorySeedPhrase verifies restoring from a seed phrase func TestInMemorySeedPhrase(t *testing.T) { - // make the storage with reasonable defaults cstore := NewInMemory() - algo := Secp256k1 + algo := hd.Secp256k1 n1, n2 := "lost-key", "found-again" - p1, p2 := nums, foobar // make sure key works with initial password - info, mnemonic, err := cstore.CreateMnemonic(n1, English, p1, algo) + info, mnemonic, err := cstore.NewMnemonic(n1, English, types.FullFundraiserPath, algo) require.Nil(t, err, "%+v", err) require.Equal(t, n1, info.GetName()) require.NotEmpty(t, mnemonic) // now, let us delete this key - err = cstore.Delete(n1, p1, false) + err = cstore.Delete(n1) require.Nil(t, err, "%+v", err) - _, err = cstore.Get(n1) + _, err = cstore.Key(n1) require.NotNil(t, err) // let us re-create it from the mnemonic-phrase params := *hd.NewFundraiserParams(0, sdk.CoinType, 0) hdPath := params.String() - newInfo, err := cstore.CreateAccount(n2, mnemonic, DefaultBIP39Passphrase, p2, hdPath, Secp256k1) + newInfo, err := cstore.NewAccount(n2, mnemonic, DefaultBIP39Passphrase, hdPath, algo) require.NoError(t, err) require.Equal(t, n2, newInfo.GetName()) require.Equal(t, info.GetPubKey().Address(), newInfo.GetPubKey().Address()) require.Equal(t, info.GetPubKey(), newInfo.GetPubKey()) } +func TestKeyChain_ShouldFailWhenAddingSameGeneratedAccount(t *testing.T) { + dir, clean := tests.NewTestCaseDir(t) + t.Cleanup(clean) + + kr, err := New(t.Name(), BackendTest, dir, nil) + require.NoError(t, err) + + // Given we create a mnemonic + _, seed, err := kr.NewMnemonic("test", English, "", hd.Secp256k1) + require.NoError(t, err) + + require.NoError(t, kr.Delete("test")) + + path := hd.CreateHDPath(118, 0, 0).String() + _, err = kr.NewAccount("test1", seed, "", path, hd.Secp256k1) + require.NoError(t, err) + + // Creating another account with different uid but same seed should fail due to have same pub address + _, err = kr.NewAccount("test2", seed, "", path, hd.Secp256k1) + require.Error(t, err) +} + func ExampleNew() { // Select the encryption and storage for your cryptostore - customKeyGenFunc := func(bz []byte, algo SigningAlgo) (tmcrypto.PrivKey, error) { - var bzArr [32]byte - copy(bzArr[:], bz) - return secp256k1.PrivKeySecp256k1(bzArr), nil - } - cstore := NewInMemory(WithKeygenFunc(customKeyGenFunc)) + cstore := NewInMemory() - sec := Secp256k1 + sec := hd.Secp256k1 // Add keys and see they return in alphabetical order - bob, _, err := cstore.CreateMnemonic("Bob", English, "friend", sec) + bob, _, err := cstore.NewMnemonic("Bob", English, types.FullFundraiserPath, sec) if err != nil { // this should never happen fmt.Println(err) @@ -903,8 +766,8 @@ func ExampleNew() { // return info here just like in List fmt.Println(bob.GetName()) } - _, _, _ = cstore.CreateMnemonic("Alice", English, "secret", sec) - _, _, _ = cstore.CreateMnemonic("Carl", English, "mitm", sec) + _, _, _ = cstore.NewMnemonic("Alice", English, types.FullFundraiserPath, sec) + _, _, _ = cstore.NewMnemonic("Carl", English, types.FullFundraiserPath, sec) info, _ := cstore.List() for _, i := range info { fmt.Println(i.GetName()) @@ -912,13 +775,13 @@ func ExampleNew() { // We need to use passphrase to generate a signature tx := []byte("deadbeef") - sig, pub, err := cstore.Sign("Bob", "friend", tx) + sig, pub, err := cstore.Sign("Bob", tx) if err != nil { fmt.Println("don't accept real passphrase") } // and we can validate the signature with publicly available info - binfo, _ := cstore.Get("Bob") + binfo, _ := cstore.Key("Bob") if !binfo.GetPubKey().Equals(bob.GetPubKey()) { fmt.Println("Get and Create return different keys") } @@ -938,77 +801,394 @@ func ExampleNew() { // signed by Bob } -func accAddr(info Info) sdk.AccAddress { - return (sdk.AccAddress)(info.GetPubKey().Address()) +func TestAltKeyring_List(t *testing.T) { + dir, clean := tests.NewTestCaseDir(t) + t.Cleanup(clean) + + keyring, err := New(t.Name(), BackendTest, dir, nil) + require.NoError(t, err) + + list, err := keyring.List() + require.NoError(t, err) + require.Empty(t, list) + + // Fails on creating unsupported pubKeyType + _, _, err = keyring.NewMnemonic("failing", English, types.FullFundraiserPath, notSupportedAlgo{}) + require.EqualError(t, err, ErrUnsupportedSigningAlgo.Error()) + + // Create 3 keys + uid1, uid2, uid3 := "Zkey", "Bkey", "Rkey" + _, _, err = keyring.NewMnemonic(uid1, English, types.FullFundraiserPath, hd.Secp256k1) + require.NoError(t, err) + _, _, err = keyring.NewMnemonic(uid2, English, types.FullFundraiserPath, hd.Secp256k1) + require.NoError(t, err) + _, _, err = keyring.NewMnemonic(uid3, English, types.FullFundraiserPath, hd.Secp256k1) + require.NoError(t, err) + + list, err = keyring.List() + require.NoError(t, err) + require.Len(t, list, 3) + + // Check they are in alphabetical order + require.Equal(t, uid2, list[0].GetName()) + require.Equal(t, uid3, list[1].GetName()) + require.Equal(t, uid1, list[2].GetName()) } -var _ tmcrypto.PrivKey = testPriv{} -var _ tmcrypto.PubKey = testPub{} -var testCdc *amino.Codec +func TestAltKeyring_NewAccount(t *testing.T) { + dir, clean := tests.NewTestCaseDir(t) + t.Cleanup(clean) -type testPriv []byte + keyring, err := New(t.Name(), BackendTest, dir, nil) + require.NoError(t, err) -func (privkey testPriv) PubKey() tmcrypto.PubKey { return testPub{} } -func (privkey testPriv) Bytes() []byte { - return testCdc.MustMarshalBinaryBare(privkey) + entropy, err := bip39.NewEntropy(defaultEntropySize) + require.NoError(t, err) + + mnemonic, err := bip39.NewMnemonic(entropy) + require.NoError(t, err) + + uid := "newUid" + + // Fails on creating unsupported pubKeyType + _, err = keyring.NewAccount(uid, mnemonic, DefaultBIP39Passphrase, sdk.FullFundraiserPath, notSupportedAlgo{}) + require.EqualError(t, err, ErrUnsupportedSigningAlgo.Error()) + + info, err := keyring.NewAccount(uid, mnemonic, DefaultBIP39Passphrase, sdk.FullFundraiserPath, hd.Secp256k1) + require.NoError(t, err) + + require.Equal(t, uid, info.GetName()) + + list, err := keyring.List() + require.NoError(t, err) + require.Len(t, list, 1) } -func (privkey testPriv) Sign(msg []byte) ([]byte, error) { return []byte{}, nil } -func (privkey testPriv) Equals(other tmcrypto.PrivKey) bool { return true } -type testPub []byte +func TestAltKeyring_Get(t *testing.T) { + dir, clean := tests.NewTestCaseDir(t) + t.Cleanup(clean) -func (key testPub) Address() tmcrypto.Address { return tmcrypto.Address{} } -func (key testPub) Bytes() []byte { - return testCdc.MustMarshalBinaryBare(key) + keyring, err := New(t.Name(), BackendTest, dir, nil) + require.NoError(t, err) + + uid := someKey + mnemonic, _, err := keyring.NewMnemonic(uid, English, types.FullFundraiserPath, hd.Secp256k1) + require.NoError(t, err) + + key, err := keyring.Key(uid) + require.NoError(t, err) + requireEqualInfo(t, mnemonic, key) } -func (key testPub) VerifyBytes(msg []byte, sig []byte) bool { return true } -func (key testPub) Equals(other tmcrypto.PubKey) bool { return true } -func TestInMemoryKeygenOverride(t *testing.T) { - // Save existing codec and reset after test - cryptoCdc := CryptoCdc - t.Cleanup(func() { - CryptoCdc = cryptoCdc - }) +func TestAltKeyring_KeyByAddress(t *testing.T) { + dir, clean := tests.NewTestCaseDir(t) + t.Cleanup(clean) - // Setup testCdc encoding and decoding new key type - testCdc = codec.New() - RegisterCodec(testCdc) - tmamino.RegisterAmino(testCdc) - - // Set up codecs for using new key types - privName, pubName := "test/priv_name", "test/pub_name" - tmamino.RegisterKeyType(testPriv{}, privName) - tmamino.RegisterKeyType(testPub{}, pubName) - testCdc.RegisterConcrete(testPriv{}, privName, nil) - testCdc.RegisterConcrete(testPub{}, pubName, nil) - CryptoCdc = testCdc - - overrideCalled := false - dummyFunc := func(bz []byte, algo SigningAlgo) (tmcrypto.PrivKey, error) { - overrideCalled = true - return testPriv(bz), nil - } + keyring, err := New(t.Name(), BackendTest, dir, nil) + require.NoError(t, err) + + uid := someKey + mnemonic, _, err := keyring.NewMnemonic(uid, English, types.FullFundraiserPath, hd.Secp256k1) + require.NoError(t, err) - kb := NewInMemory(WithKeygenFunc(dummyFunc)) + key, err := keyring.KeyByAddress(mnemonic.GetAddress()) + require.NoError(t, err) + requireEqualInfo(t, key, mnemonic) +} - testName, pw := "name", "testPassword" +func TestAltKeyring_Delete(t *testing.T) { + dir, clean := tests.NewTestCaseDir(t) + t.Cleanup(clean) - // create new key which will generate with - info, _, err := kb.CreateMnemonic(testName, English, pw, Secp256k1) + keyring, err := New(t.Name(), BackendTest, dir, nil) require.NoError(t, err) - require.Equal(t, info.GetName(), testName) - // Assert overridden function was called - require.True(t, overrideCalled) + uid := someKey + _, _, err = keyring.NewMnemonic(uid, English, types.FullFundraiserPath, hd.Secp256k1) + require.NoError(t, err) - // export private key object - exported, err := kb.ExportPrivateKeyObject(testName, pw) - require.Nil(t, err, "%+v", err) + list, err := keyring.List() + require.NoError(t, err) + require.Len(t, list, 1) + + err = keyring.Delete(uid) + require.NoError(t, err) + + list, err = keyring.List() + require.NoError(t, err) + require.Empty(t, list) +} + +func TestAltKeyring_DeleteByAddress(t *testing.T) { + dir, clean := tests.NewTestCaseDir(t) + t.Cleanup(clean) + + keyring, err := New(t.Name(), BackendTest, dir, nil) + require.NoError(t, err) + + uid := someKey + mnemonic, _, err := keyring.NewMnemonic(uid, English, types.FullFundraiserPath, hd.Secp256k1) + require.NoError(t, err) + + list, err := keyring.List() + require.NoError(t, err) + require.Len(t, list, 1) + + err = keyring.DeleteByAddress(mnemonic.GetAddress()) + require.NoError(t, err) + + list, err = keyring.List() + require.NoError(t, err) + require.Empty(t, list) +} + +func TestAltKeyring_SavePubKey(t *testing.T) { + dir, clean := tests.NewTestCaseDir(t) + t.Cleanup(clean) + + keyring, err := New(t.Name(), BackendTest, dir, nil) + require.NoError(t, err) + + list, err := keyring.List() + require.NoError(t, err) + require.Empty(t, list) + + key := someKey + priv := ed25519.GenPrivKey() + pub := priv.PubKey() + + info, err := keyring.SavePubKey(key, pub, hd.Secp256k1.Name()) + require.Nil(t, err) + require.Equal(t, pub, info.GetPubKey()) + require.Equal(t, key, info.GetName()) + require.Equal(t, hd.Secp256k1.Name(), info.GetAlgo()) + + list, err = keyring.List() + require.NoError(t, err) + require.Equal(t, 1, len(list)) +} + +func TestAltKeyring_SaveMultisig(t *testing.T) { + dir, clean := tests.NewTestCaseDir(t) + t.Cleanup(clean) + + keyring, err := New(t.Name(), BackendTest, dir, nil) + require.NoError(t, err) + + mnemonic1, _, err := keyring.NewMnemonic("key1", English, types.FullFundraiserPath, hd.Secp256k1) + require.NoError(t, err) + mnemonic2, _, err := keyring.NewMnemonic("key2", English, types.FullFundraiserPath, hd.Secp256k1) + require.NoError(t, err) + + key := "multi" + pub := multisig.NewPubKeyMultisigThreshold(2, []tmcrypto.PubKey{mnemonic1.GetPubKey(), mnemonic2.GetPubKey()}) + + info, err := keyring.SaveMultisig(key, pub) + require.Nil(t, err) + require.Equal(t, pub, info.GetPubKey()) + require.Equal(t, key, info.GetName()) + + list, err := keyring.List() + require.NoError(t, err) + require.Len(t, list, 3) +} + +func TestAltKeyring_Sign(t *testing.T) { + dir, clean := tests.NewTestCaseDir(t) + t.Cleanup(clean) + + keyring, err := New(t.Name(), BackendTest, dir, nil) + require.NoError(t, err) + + uid := "jack" + _, _, err = keyring.NewMnemonic(uid, English, types.FullFundraiserPath, hd.Secp256k1) + require.NoError(t, err) + + msg := []byte("some message") + + sign, key, err := keyring.Sign(uid, msg) + require.NoError(t, err) + + require.True(t, key.VerifyBytes(msg, sign)) +} + +func TestAltKeyring_SignByAddress(t *testing.T) { + dir, clean := tests.NewTestCaseDir(t) + t.Cleanup(clean) - // require that the key type is the new key - _, ok := exported.(testPriv) - require.True(t, ok) + keyring, err := New(t.Name(), BackendTest, dir, nil) + require.NoError(t, err) + + uid := "jack" + mnemonic, _, err := keyring.NewMnemonic(uid, English, types.FullFundraiserPath, hd.Secp256k1) + require.NoError(t, err) + + msg := []byte("some message") + + sign, key, err := keyring.SignByAddress(mnemonic.GetAddress(), msg) + require.NoError(t, err) + + require.True(t, key.VerifyBytes(msg, sign)) +} + +func TestAltKeyring_ImportExportPrivKey(t *testing.T) { + dir, clean := tests.NewTestCaseDir(t) + t.Cleanup(clean) + + keyring, err := New(t.Name(), BackendTest, dir, nil) + require.NoError(t, err) + + uid := theID + _, _, err = keyring.NewMnemonic(uid, English, types.FullFundraiserPath, hd.Secp256k1) + require.NoError(t, err) + + passphrase := "somePass" + armor, err := keyring.ExportPrivKeyArmor(uid, passphrase) + require.NoError(t, err) + err = keyring.Delete(uid) + require.NoError(t, err) + newUID := otherID + // Should fail importing with wrong password + err = keyring.ImportPrivKey(newUID, armor, "wrongPass") + require.EqualError(t, err, "failed to decrypt private key: ciphertext decryption failed") + + err = keyring.ImportPrivKey(newUID, armor, passphrase) + require.NoError(t, err) + + // Should fail importing private key on existing key. + err = keyring.ImportPrivKey(newUID, armor, passphrase) + require.EqualError(t, err, fmt.Sprintf("cannot overwrite key: %s", newUID)) +} + +func TestAltKeyring_ImportExportPrivKey_ByAddress(t *testing.T) { + dir, clean := tests.NewTestCaseDir(t) + t.Cleanup(clean) + + keyring, err := New(t.Name(), BackendTest, dir, nil) + require.NoError(t, err) + + uid := theID + mnemonic, _, err := keyring.NewMnemonic(uid, English, types.FullFundraiserPath, hd.Secp256k1) + require.NoError(t, err) + + passphrase := "somePass" + armor, err := keyring.ExportPrivKeyArmorByAddress(mnemonic.GetAddress(), passphrase) + require.NoError(t, err) + err = keyring.Delete(uid) + require.NoError(t, err) + + newUID := otherID + // Should fail importing with wrong password + err = keyring.ImportPrivKey(newUID, armor, "wrongPass") + require.EqualError(t, err, "failed to decrypt private key: ciphertext decryption failed") - require.True(t, exported.PubKey().Equals(info.GetPubKey())) + err = keyring.ImportPrivKey(newUID, armor, passphrase) + require.NoError(t, err) + + // Should fail importing private key on existing key. + err = keyring.ImportPrivKey(newUID, armor, passphrase) + require.EqualError(t, err, fmt.Sprintf("cannot overwrite key: %s", newUID)) } + +func TestAltKeyring_ImportExportPubKey(t *testing.T) { + dir, clean := tests.NewTestCaseDir(t) + t.Cleanup(clean) + + keyring, err := New(t.Name(), BackendTest, dir, nil) + require.NoError(t, err) + + uid := theID + _, _, err = keyring.NewMnemonic(uid, English, types.FullFundraiserPath, hd.Secp256k1) + require.NoError(t, err) + + armor, err := keyring.ExportPubKeyArmor(uid) + require.NoError(t, err) + err = keyring.Delete(uid) + require.NoError(t, err) + + newUID := otherID + err = keyring.ImportPubKey(newUID, armor) + require.NoError(t, err) + + // Should fail importing private key on existing key. + err = keyring.ImportPubKey(newUID, armor) + require.EqualError(t, err, fmt.Sprintf("cannot overwrite key: %s", newUID)) +} + +func TestAltKeyring_ImportExportPubKey_ByAddress(t *testing.T) { + dir, clean := tests.NewTestCaseDir(t) + t.Cleanup(clean) + + keyring, err := New(t.Name(), BackendTest, dir, nil) + require.NoError(t, err) + + uid := theID + mnemonic, _, err := keyring.NewMnemonic(uid, English, types.FullFundraiserPath, hd.Secp256k1) + require.NoError(t, err) + + armor, err := keyring.ExportPubKeyArmorByAddress(mnemonic.GetAddress()) + require.NoError(t, err) + err = keyring.Delete(uid) + require.NoError(t, err) + + newUID := otherID + err = keyring.ImportPubKey(newUID, armor) + require.NoError(t, err) + + // Should fail importing private key on existing key. + err = keyring.ImportPubKey(newUID, armor) + require.EqualError(t, err, fmt.Sprintf("cannot overwrite key: %s", newUID)) +} + +func TestAltKeyring_ConstructorSupportedAlgos(t *testing.T) { + dir, clean := tests.NewTestCaseDir(t) + t.Cleanup(clean) + + keyring, err := New(t.Name(), BackendTest, dir, nil) + require.NoError(t, err) + + // should fail when using unsupported signing algorythm. + _, _, err = keyring.NewMnemonic("test", English, types.FullFundraiserPath, notSupportedAlgo{}) + require.EqualError(t, err, "unsupported signing algo") + + // but works with default signing algo. + _, _, err = keyring.NewMnemonic("test", English, types.FullFundraiserPath, hd.Secp256k1) + require.NoError(t, err) + + // but we can create a new keybase with our provided algos. + dir2, clean2 := tests.NewTestCaseDir(t) + t.Cleanup(clean2) + + keyring2, err := New(t.Name(), BackendTest, dir2, nil, func(options *Options) { + options.SupportedAlgos = SigningAlgoList{ + notSupportedAlgo{}, + } + }) + require.NoError(t, err) + + // now this new keyring does not fail when signing with provided algo + _, _, err = keyring2.NewMnemonic("test", English, types.FullFundraiserPath, notSupportedAlgo{}) + require.NoError(t, err) +} + +func TestBackendConfigConstructors(t *testing.T) { + backend := newKWalletBackendKeyringConfig("test", "", nil) + require.Equal(t, []keyring.BackendType{keyring.KWalletBackend}, backend.AllowedBackends) + require.Equal(t, "kdewallet", backend.ServiceName) + require.Equal(t, "test", backend.KWalletAppID) + + backend = newPassBackendKeyringConfig("test", "directory", nil) + require.Equal(t, []keyring.BackendType{keyring.PassBackend}, backend.AllowedBackends) + require.Equal(t, "test", backend.ServiceName) + require.Equal(t, "keyring-test", backend.PassPrefix) +} + +func requireEqualInfo(t *testing.T, key Info, mnemonic Info) { + require.Equal(t, key.GetName(), mnemonic.GetName()) + require.Equal(t, key.GetAddress(), mnemonic.GetAddress()) + require.Equal(t, key.GetPubKey(), mnemonic.GetPubKey()) + require.Equal(t, key.GetAlgo(), mnemonic.GetAlgo()) + require.Equal(t, key.GetType(), mnemonic.GetType()) +} + +func accAddr(info Info) sdk.AccAddress { return info.GetAddress() } diff --git a/crypto/keyring/legacy.go b/crypto/keyring/legacy.go index 2d61f3155418..2aa76fdcb5f9 100644 --- a/crypto/keyring/legacy.go +++ b/crypto/keyring/legacy.go @@ -2,6 +2,7 @@ package keyring import ( "fmt" + "io" "strings" "github.com/pkg/errors" @@ -179,10 +180,53 @@ func (kb dbKeybase) ExportPrivKey(name string, decryptPassphrase string, } // Close the underlying storage. -func (kb dbKeybase) Close() error { - return kb.db.Close() +func (kb dbKeybase) Close() error { return kb.db.Close() } + +func infoKey(name string) []byte { return []byte(fmt.Sprintf("%s.%s", name, infoSuffix)) } + +// InfoImporter is implemented by those types that want to provide functions necessary +// to migrate keys from LegacyKeybase types to Keyring types. +type InfoImporter interface { + // Import imports ASCII-armored private keys. + Import(uid string, armor string) error +} + +type keyringMigrator struct { + kr keystore +} + +func NewInfoImporter( + appName, backend, rootDir string, userInput io.Reader, opts ...Option, +) (InfoImporter, error) { + keyring, err := New(appName, backend, rootDir, userInput, opts...) + if err != nil { + return keyringMigrator{}, err + } + kr := keyring.(keystore) + return keyringMigrator{kr}, nil } -func infoKey(name string) []byte { - return []byte(fmt.Sprintf("%s.%s", name, infoSuffix)) +func (m keyringMigrator) Import(uid string, armor string) error { + _, err := m.kr.Key(uid) + if err == nil { + return fmt.Errorf("cannot overwrite key %q", uid) + } + + infoBytes, err := crypto.UnarmorInfoBytes(armor) + if err != nil { + return err + } + + info, err := unmarshalInfo(infoBytes) + if err != nil { + return err + } + + return m.kr.writeInfo(info) +} + +// KeybaseOption overrides options for the db. +type KeybaseOption func(*kbOptions) + +type kbOptions struct { } diff --git a/crypto/keyring/legacy_test.go b/crypto/keyring/legacy_test.go index 1e2b475660b6..11ea30bf05e1 100644 --- a/crypto/keyring/legacy_test.go +++ b/crypto/keyring/legacy_test.go @@ -1,6 +1,7 @@ package keyring_test import ( + "io" "path/filepath" "testing" @@ -38,7 +39,21 @@ func TestLegacyKeybase(t *testing.T) { require.NoError(t, err) require.NotEmpty(t, armor) + _, err = kb.ExportPrivKey(keys[0].GetName(), "12345678", "12345678") + require.Error(t, err) + armoredInfo, err := kb.Export(keys[0].GetName()) require.NoError(t, err) require.NotEmpty(t, armoredInfo) + + importer, err := keyring.NewInfoImporter("cosmos", "memory", "", nil) + require.NoError(t, err) + err = importer.Import("test", "") + require.Error(t, err) + require.Equal(t, io.EOF, err) + require.NoError(t, importer.Import("test", armoredInfo)) + + err = importer.Import("test", armoredInfo) + require.Error(t, err) + require.Equal(t, `public key already exist in keybase`, err.Error()) } diff --git a/crypto/keyring/options.go b/crypto/keyring/options.go deleted file mode 100644 index 21e69398f002..000000000000 --- a/crypto/keyring/options.go +++ /dev/null @@ -1,39 +0,0 @@ -package keyring - -// KeybaseOption overrides options for the db -type KeybaseOption func(*kbOptions) - -type kbOptions struct { - keygenFunc PrivKeyGenFunc - deriveFunc DeriveKeyFunc - supportedAlgos []SigningAlgo - supportedAlgosLedger []SigningAlgo -} - -// WithKeygenFunc applies an overridden key generation function to generate the private key. -func WithKeygenFunc(f PrivKeyGenFunc) KeybaseOption { - return func(o *kbOptions) { - o.keygenFunc = f - } -} - -// WithDeriveFunc applies an overridden key derivation function to generate the private key. -func WithDeriveFunc(f DeriveKeyFunc) KeybaseOption { - return func(o *kbOptions) { - o.deriveFunc = f - } -} - -// WithSupportedAlgos defines the list of accepted SigningAlgos. -func WithSupportedAlgos(algos []SigningAlgo) KeybaseOption { - return func(o *kbOptions) { - o.supportedAlgos = algos - } -} - -// WithSupportedAlgosLedger defines the list of accepted SigningAlgos compatible with Ledger. -func WithSupportedAlgosLedger(algos []SigningAlgo) KeybaseOption { - return func(o *kbOptions) { - o.supportedAlgosLedger = algos - } -} diff --git a/crypto/keyring/signing_algorithms.go b/crypto/keyring/signing_algorithms.go index 12e000aeb9dd..425f49eb859a 100644 --- a/crypto/keyring/signing_algorithms.go +++ b/crypto/keyring/signing_algorithms.go @@ -1,26 +1,33 @@ package keyring -// SigningAlgo defines an algorithm to derive key-pairs which can be used for cryptographic signing. -type SigningAlgo string - -const ( - // MultiAlgo implies that a pubkey is a multisignature - MultiAlgo = SigningAlgo("multi") - // Secp256k1 uses the Bitcoin secp256k1 ECDSA parameters. - Secp256k1 = SigningAlgo("secp256k1") - // Ed25519 represents the Ed25519 signature system. - // It is currently not supported for end-user keys (wallets/ledgers). - Ed25519 = SigningAlgo("ed25519") - // Sr25519 represents the Sr25519 signature system. - Sr25519 = SigningAlgo("sr25519") +import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/crypto/hd" ) -// IsSupportedAlgorithm returns whether the signing algorithm is in the passed-in list of supported algorithms. -func IsSupportedAlgorithm(supported []SigningAlgo, algo SigningAlgo) bool { - for _, supportedAlgo := range supported { - if algo == supportedAlgo { +type SignatureAlgo interface { + Name() hd.PubKeyType + Derive() hd.DeriveFn + Generate() hd.GenerateFn +} + +func NewSigningAlgoFromString(str string) (SignatureAlgo, error) { + if str != string(hd.Secp256k1.Name()) { + return nil, fmt.Errorf("provided algorithm `%s` is not supported", str) + } + + return hd.Secp256k1, nil +} + +type SigningAlgoList []SignatureAlgo + +func (l SigningAlgoList) Contains(algo SignatureAlgo) bool { + for _, cAlgo := range l { + if cAlgo.Name() == algo.Name() { return true } } + return false } diff --git a/crypto/keyring/signing_algorithms_test.go b/crypto/keyring/signing_algorithms_test.go new file mode 100644 index 000000000000..1293249b09d9 --- /dev/null +++ b/crypto/keyring/signing_algorithms_test.go @@ -0,0 +1,71 @@ +package keyring + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/crypto/hd" +) + +func TestNewSigningAlgoByString(t *testing.T) { + tests := []struct { + name string + algoStr string + isSupported bool + expectedAlgo SignatureAlgo + expectedErr error + }{ + { + "supported algorithm", + "secp256k1", + true, + hd.Secp256k1, + nil, + }, + { + "not supported", + "notsupportedalgo", + false, + nil, + fmt.Errorf("provided algorithm `notsupportedalgo` is not supported"), + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + algorithm, err := NewSigningAlgoFromString(tt.algoStr) + if tt.isSupported { + require.Equal(t, hd.Secp256k1, algorithm) + } else { + require.EqualError(t, err, tt.expectedErr.Error()) + } + }) + } +} + +func TestAltSigningAlgoList_Contains(t *testing.T) { + list := SigningAlgoList{ + hd.Secp256k1, + } + + assert.True(t, list.Contains(hd.Secp256k1)) + assert.False(t, list.Contains(notSupportedAlgo{})) +} + +type notSupportedAlgo struct { +} + +func (n notSupportedAlgo) Name() hd.PubKeyType { + return "notSupported" +} + +func (n notSupportedAlgo) Derive() hd.DeriveFn { + return hd.Secp256k1.Derive() +} + +func (n notSupportedAlgo) Generate() hd.GenerateFn { + return hd.Secp256k1.Generate() +} diff --git a/crypto/keyring/types.go b/crypto/keyring/types.go index fadf47ad588a..443896d785b2 100644 --- a/crypto/keyring/types.go +++ b/crypto/keyring/types.go @@ -1,6 +1,10 @@ package keyring -import "github.com/tendermint/tendermint/crypto" +import ( + "github.com/tendermint/tendermint/crypto" + + "github.com/cosmos/cosmos-sdk/crypto/hd" +) // Language is a language to create the BIP 39 mnemonic in. // Currently, only english is supported though. @@ -62,7 +66,7 @@ func (kt KeyType) String() string { type ( // DeriveKeyFunc defines the function to derive a new key from a seed and hd path - DeriveKeyFunc func(mnemonic string, bip39Passphrase, hdPath string, algo SigningAlgo) ([]byte, error) + DeriveKeyFunc func(mnemonic string, bip39Passphrase, hdPath string, algo hd.PubKeyType) ([]byte, error) // PrivKeyGenFunc defines the function to convert derived key bytes to a tendermint private key - PrivKeyGenFunc func(bz []byte, algo SigningAlgo) (crypto.PrivKey, error) + PrivKeyGenFunc func(bz []byte, algo hd.PubKeyType) (crypto.PrivKey, error) ) diff --git a/crypto/keyring/types_test.go b/crypto/keyring/types_test.go index c2cb9723c2c7..cf935d906c85 100644 --- a/crypto/keyring/types_test.go +++ b/crypto/keyring/types_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/tendermint/tendermint/crypto/secp256k1" - "github.com/cosmos/cosmos-sdk/crypto/keys/hd" + "github.com/cosmos/cosmos-sdk/crypto/hd" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -16,7 +16,7 @@ func Test_writeReadLedgerInfo(t *testing.T) { bz, _ := hex.DecodeString("035AD6810A47F073553FF30D2FCC7E0D3B1C0B74B61A1AAA2582344037151E143A") copy(tmpKey[:], bz) - lInfo := newLedgerInfo("some_name", tmpKey, *hd.NewFundraiserParams(5, sdk.CoinType, 1), Secp256k1) + lInfo := newLedgerInfo("some_name", tmpKey, *hd.NewFundraiserParams(5, sdk.CoinType, 1), hd.Secp256k1Type) assert.Equal(t, TypeLedger, lInfo.GetType()) path, err := lInfo.GetPath() diff --git a/crypto/ledger_mock.go b/crypto/ledger_mock.go index 21fc8a2b0f43..20a45c158bb3 100644 --- a/crypto/ledger_mock.go +++ b/crypto/ledger_mock.go @@ -14,7 +14,7 @@ import ( bip39 "github.com/cosmos/go-bip39" - "github.com/cosmos/cosmos-sdk/crypto/keys/hd" + "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/tests" sdk "github.com/cosmos/cosmos-sdk/types" ) diff --git a/crypto/ledger_secp256k1.go b/crypto/ledger_secp256k1.go index 2c346d4355a4..809512e47d35 100644 --- a/crypto/ledger_secp256k1.go +++ b/crypto/ledger_secp256k1.go @@ -11,7 +11,7 @@ import ( tmcrypto "github.com/tendermint/tendermint/crypto" tmsecp256k1 "github.com/tendermint/tendermint/crypto/secp256k1" - "github.com/cosmos/cosmos-sdk/crypto/keys/hd" + "github.com/cosmos/cosmos-sdk/crypto/hd" ) var ( diff --git a/crypto/ledger_test.go b/crypto/ledger_test.go index fbcf9239b49d..7d73a36c9803 100644 --- a/crypto/ledger_test.go +++ b/crypto/ledger_test.go @@ -9,7 +9,7 @@ import ( tmcrypto "github.com/tendermint/tendermint/crypto" cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino" - "github.com/cosmos/cosmos-sdk/crypto/keys/hd" + "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/tests" sdk "github.com/cosmos/cosmos-sdk/types" ) diff --git a/server/init.go b/server/init.go index 054cdb460863..cf433aa1184d 100644 --- a/server/init.go +++ b/server/init.go @@ -3,7 +3,9 @@ package server import ( "fmt" + "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/crypto/keyring" + "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -11,31 +13,39 @@ import ( // GenerateCoinKey returns the address of a public key, along with the secret // phrase to recover the private key. func GenerateCoinKey() (sdk.AccAddress, string, error) { - // generate a private key, with recovery phrase - info, secret, err := keyring.NewInMemory().CreateMnemonic( - "name", keyring.English, "pass", keyring.Secp256k1) + info, secret, err := keyring.NewInMemory().NewMnemonic("name", keyring.English, types.FullFundraiserPath, hd.Secp256k1) if err != nil { return sdk.AccAddress([]byte{}), "", err } - addr := info.GetPubKey().Address() - return sdk.AccAddress(addr), secret, nil + return sdk.AccAddress(info.GetPubKey().Address()), secret, nil } // GenerateSaveCoinKey returns the address of a public key, along with the secret // phrase to recover the private key. -func GenerateSaveCoinKey(keybase keyring.Keybase, keyName, keyPass string, overwrite bool) (sdk.AccAddress, string, error) { +func GenerateSaveCoinKey(keybase keyring.Keyring, keyName, keyPass string, overwrite bool) (sdk.AccAddress, string, error) { + exists := false + _, err := keybase.Key(keyName) + if err == nil { + exists = true + } + // ensure no overwrite - if !overwrite { - _, err := keybase.Get(keyName) - if err == nil { + if !overwrite && exists { + return sdk.AccAddress([]byte{}), "", fmt.Errorf( + "key already exists, overwrite is disabled") + } + + // generate a private key, with recovery phrase + if exists { + err = keybase.Delete(keyName) + if err != nil { return sdk.AccAddress([]byte{}), "", fmt.Errorf( - "key already exists, overwrite is disabled") + "failed to overwrite key") } } - // generate a private key, with recovery phrase - info, secret, err := keybase.CreateMnemonic(keyName, keyring.English, keyPass, keyring.Secp256k1) + info, secret, err := keybase.NewMnemonic(keyName, keyring.English, types.FullFundraiserPath, hd.Secp256k1) if err != nil { return sdk.AccAddress([]byte{}), "", err } diff --git a/server/init_test.go b/server/init_test.go index e51b88effdeb..c2b9b469d170 100644 --- a/server/init_test.go +++ b/server/init_test.go @@ -5,9 +5,11 @@ import ( "github.com/stretchr/testify/require" + "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/server" "github.com/cosmos/cosmos-sdk/tests" + "github.com/cosmos/cosmos-sdk/types" ) func TestGenerateCoinKey(t *testing.T) { @@ -16,7 +18,7 @@ func TestGenerateCoinKey(t *testing.T) { require.NoError(t, err) // Test creation - info, err := keyring.NewInMemory().CreateAccount("xxx", mnemonic, "", "012345678", keyring.CreateHDPath(0, 0).String(), keyring.Secp256k1) + info, err := keyring.NewInMemory().NewAccount("xxx", mnemonic, "", hd.NewFundraiserParams(0, types.GetConfig().GetCoinType(), 0).String(), hd.Secp256k1) require.NoError(t, err) require.Equal(t, addr, info.GetAddress()) } @@ -26,19 +28,19 @@ func TestGenerateSaveCoinKey(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) t.Cleanup(cleanup) - kb, err := keyring.NewKeyring(t.Name(), "test", dir, nil) + kb, err := keyring.New(t.Name(), "test", dir, nil) require.NoError(t, err) addr, mnemonic, err := server.GenerateSaveCoinKey(kb, "keyname", "012345678", false) require.NoError(t, err) // Test key was actually saved - info, err := kb.Get("keyname") + info, err := kb.Key("keyname") require.NoError(t, err) require.Equal(t, addr, info.GetAddress()) // Test in-memory recovery - info, err = keyring.NewInMemory().CreateAccount("xxx", mnemonic, "", "012345678", keyring.CreateHDPath(0, 0).String(), keyring.Secp256k1) + info, err = keyring.NewInMemory().NewAccount("xxx", mnemonic, "", hd.NewFundraiserParams(0, types.GetConfig().GetCoinType(), 0).String(), hd.Secp256k1) require.NoError(t, err) require.Equal(t, addr, info.GetAddress()) } @@ -48,7 +50,7 @@ func TestGenerateSaveCoinKeyOverwriteFlag(t *testing.T) { dir, cleanup := tests.NewTestCaseDir(t) t.Cleanup(cleanup) - kb, err := keyring.NewKeyring(t.Name(), "test", dir, nil) + kb, err := keyring.New(t.Name(), "test", dir, nil) require.NoError(t, err) keyname := "justakey" diff --git a/x/auth/client/cli/tx_multisign.go b/x/auth/client/cli/tx_multisign.go index 83c068db1821..e0d502a47f14 100644 --- a/x/auth/client/cli/tx_multisign.go +++ b/x/auth/client/cli/tx_multisign.go @@ -65,13 +65,13 @@ func makeMultiSignCmd(cdc *codec.Codec) func(cmd *cobra.Command, args []string) } inBuf := bufio.NewReader(cmd.InOrStdin()) - kb, err := keyring.NewKeyring(sdk.KeyringServiceName(), + kb, err := keyring.New(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), inBuf) if err != nil { return } - multisigInfo, err := kb.Get(args[1]) + multisigInfo, err := kb.Key(args[1]) if err != nil { return } diff --git a/x/auth/client/tx.go b/x/auth/client/tx.go index ba19d1be5983..cc04cd730842 100644 --- a/x/auth/client/tx.go +++ b/x/auth/client/tx.go @@ -97,7 +97,7 @@ func CompleteAndBroadcastTxCLI(txBldr authtypes.TxBuilder, cliCtx context.CLICon _, _ = fmt.Fprintf(os.Stderr, "%s\n\n", json) buf := bufio.NewReader(os.Stdin) - ok, err := input.GetConfirmation("confirm transaction before signing and broadcasting", buf) + ok, err := input.GetConfirmation("confirm transaction before signing and broadcasting", buf, os.Stderr) if err != nil || !ok { _, _ = fmt.Fprintf(os.Stderr, "%s\n", "cancelled transaction") return err @@ -184,7 +184,7 @@ func SignStdTx( var signedStdTx authtypes.StdTx - info, err := txBldr.Keybase().Get(name) + info, err := txBldr.Keybase().Key(name) if err != nil { return signedStdTx, err } diff --git a/x/auth/types/params_test.go b/x/auth/types/params_test.go index f25a44914957..fcec36cb833c 100644 --- a/x/auth/types/params_test.go +++ b/x/auth/types/params_test.go @@ -4,8 +4,9 @@ import ( "fmt" "testing" - "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/x/auth/types" ) func TestParamsEqual(t *testing.T) { diff --git a/x/auth/types/txbuilder.go b/x/auth/types/txbuilder.go index 2c2576841c40..41f33684be6f 100644 --- a/x/auth/types/txbuilder.go +++ b/x/auth/types/txbuilder.go @@ -17,7 +17,7 @@ import ( // TxBuilder implements a transaction context created in SDK modules. type TxBuilder struct { txEncoder sdk.TxEncoder - keybase keyring.Keybase + keybase keyring.Keyring accountNumber uint64 sequence uint64 gas uint64 @@ -53,7 +53,7 @@ func NewTxBuilder( // NewTxBuilderFromCLI returns a new initialized TxBuilder with parameters from // the command line using Viper. func NewTxBuilderFromCLI(input io.Reader) TxBuilder { - kb, err := keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), input) + kb, err := keyring.New(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), input) if err != nil { panic(err) } @@ -90,7 +90,7 @@ func (bldr TxBuilder) Gas() uint64 { return bldr.gas } func (bldr TxBuilder) GasAdjustment() float64 { return bldr.gasAdjustment } // Keybase returns the keybase -func (bldr TxBuilder) Keybase() keyring.Keybase { return bldr.keybase } +func (bldr TxBuilder) Keybase() keyring.Keyring { return bldr.keybase } // SimulateAndExecute returns the option to simulate and then execute the transaction // using the gas from the simulation results @@ -149,7 +149,7 @@ func (bldr TxBuilder) WithGasPrices(gasPrices string) TxBuilder { } // WithKeybase returns a copy of the context with updated keybase. -func (bldr TxBuilder) WithKeybase(keybase keyring.Keybase) TxBuilder { +func (bldr TxBuilder) WithKeybase(keybase keyring.Keyring) TxBuilder { bldr.keybase = keybase return bldr } @@ -272,17 +272,17 @@ func (bldr TxBuilder) SignStdTx(name, passphrase string, stdTx StdTx, appendSig } // MakeSignature builds a StdSignature given keybase, key name, passphrase, and a StdSignMsg. -func MakeSignature(keybase keyring.Keybase, name, passphrase string, +func MakeSignature(keybase keyring.Keyring, name, passphrase string, msg StdSignMsg) (sig StdSignature, err error) { if keybase == nil { - keybase, err = keyring.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), os.Stdin) + keybase, err = keyring.New(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), os.Stdin) if err != nil { return } } - sigBytes, pubkey, err := keybase.Sign(name, passphrase, msg.Bytes()) + sigBytes, pubkey, err := keybase.Sign(name, msg.Bytes()) if err != nil { return } diff --git a/x/genutil/client/cli/gentx.go b/x/genutil/client/cli/gentx.go index 6e2d7f73b602..1e138820de88 100644 --- a/x/genutil/client/cli/gentx.go +++ b/x/genutil/client/cli/gentx.go @@ -93,14 +93,14 @@ func GenTxCmd(ctx *server.Context, cdc *codec.Codec, mbm module.BasicManager, sm } inBuf := bufio.NewReader(cmd.InOrStdin()) - kb, err := keyring.NewKeyring(sdk.KeyringServiceName(), + kb, err := keyring.New(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flagClientHome), inBuf) if err != nil { return errors.Wrap(err, "failed to initialize keybase") } name := viper.GetString(flags.FlagName) - key, err := kb.Get(name) + key, err := kb.Key(name) if err != nil { return errors.Wrap(err, "failed to read from keybase") } From d351a574a8a6beece84e89bbd127167f6788b6f8 Mon Sep 17 00:00:00 2001 From: Marko Date: Wed, 8 Apr 2020 14:47:24 +0200 Subject: [PATCH 524/529] lint: migrate to review-dog (#5955) golangci is being deprecated in April 15th. Remove riot and add sims badge. --- .github/workflows/lint.yml | 12 ++++++++++++ README.md | 2 +- types/context_test.go | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/lint.yml diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 000000000000..ad499d9afd74 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,12 @@ +name: Lint +on: [pull_request] +jobs: + golangci-lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: golangci-lint + uses: reviewdog/action-golangci-lint@v1 + with: + github_token: ${{ secrets.github_token }} + reporter: github-pr-check diff --git a/README.md b/README.md index c783fc279efe..7b9eaacf183d 100644 --- a/README.md +++ b/README.md @@ -9,12 +9,12 @@ parent: [![version](https://img.shields.io/github/tag/cosmos/cosmos-sdk.svg)](https://github.com/cosmos/cosmos-sdk/releases/latest) [![CircleCI](https://circleci.com/gh/cosmos/cosmos-sdk/tree/master.svg?style=shield)](https://circleci.com/gh/cosmos/cosmos-sdk/tree/master) +![Sims](https://github.com/cosmos/cosmos-sdk/workflows/Sims/badge.svg) [![codecov](https://codecov.io/gh/cosmos/cosmos-sdk/branch/master/graph/badge.svg)](https://codecov.io/gh/cosmos/cosmos-sdk) [![Go Report Card](https://goreportcard.com/badge/github.com/cosmos/cosmos-sdk)](https://goreportcard.com/report/github.com/cosmos/cosmos-sdk) [![license](https://img.shields.io/github/license/cosmos/cosmos-sdk.svg)](https://github.com/cosmos/cosmos-sdk/blob/master/LICENSE) [![LoC](https://tokei.rs/b1/github/cosmos/cosmos-sdk)](https://github.com/cosmos/cosmos-sdk) [![API Reference](https://godoc.org/github.com/cosmos/cosmos-sdk?status.svg)](https://godoc.org/github.com/cosmos/cosmos-sdk) -[![riot.im](https://img.shields.io/badge/riot.im-JOIN%20CHAT-green.svg)](https://riot.im/app/#/room/#cosmos-sdk:matrix.org) The Cosmos-SDK is a framework for building blockchain applications in Golang. It is being used to build [`Gaia`](https://github.com/cosmos/gaia), the first implementation of the Cosmos Hub. diff --git a/types/context_test.go b/types/context_test.go index 225d5e1adec9..73e5bab9e39e 100644 --- a/types/context_test.go +++ b/types/context_test.go @@ -151,7 +151,7 @@ func TestContextWithCustom(t *testing.T) { require.Equal(t, cp, ctx.WithConsensusParams(cp).ConsensusParams()) // test inner context - newContext := context.WithValue(ctx.Context(), "key", "value") + newContext := context.WithValue(ctx.Context(), "key", "value") //nolint:golint require.NotEqual(t, ctx.Context(), ctx.WithContext(newContext).Context()) } From add93849bd6b5777037a5c77abc728ba74bc38a8 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Wed, 8 Apr 2020 15:00:59 +0200 Subject: [PATCH 525/529] client/flags: bind keyring flag for query commands (#5956) --- client/flags/flags.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/flags/flags.go b/client/flags/flags.go index 7497355ba215..cf67c64ee56d 100644 --- a/client/flags/flags.go +++ b/client/flags/flags.go @@ -87,10 +87,12 @@ func GetCommands(cmds ...*cobra.Command) []*cobra.Command { c.Flags().Bool(FlagUseLedger, false, "Use a connected Ledger device") c.Flags().String(FlagNode, "tcp://localhost:26657", ": to Tendermint RPC interface for this chain") c.Flags().Int64(FlagHeight, 0, "Use a specific height to query state at (this can error if the node is pruning state)") + c.Flags().String(FlagKeyringBackend, DefaultKeyringBackend, "Select keyring's backend (os|file|kwallet|pass|test)") viper.BindPFlag(FlagTrustNode, c.Flags().Lookup(FlagTrustNode)) viper.BindPFlag(FlagUseLedger, c.Flags().Lookup(FlagUseLedger)) viper.BindPFlag(FlagNode, c.Flags().Lookup(FlagNode)) + viper.BindPFlag(FlagKeyringBackend, c.Flags().Lookup(FlagKeyringBackend)) c.MarkFlagRequired(FlagChainID) From ed9f488fd9abbdf61d8c78e2a78aa70d5d816cc5 Mon Sep 17 00:00:00 2001 From: SaReN Date: Wed, 8 Apr 2020 20:35:14 +0530 Subject: [PATCH 526/529] Merge PR #5941: Add proto compatible x/distribution tx cli --- x/distribution/client/cli/tx.go | 233 +++++++++++++++++++++++++++- x/distribution/client/rest/query.go | 50 +++--- x/distribution/client/rest/rest.go | 10 +- x/distribution/client/rest/tx.go | 216 ++++++++++++++++++++++++-- 4 files changed, 466 insertions(+), 43 deletions(-) diff --git a/x/distribution/client/cli/tx.go b/x/distribution/client/cli/tx.go index 892058f6b38b..4c2a055ac9e2 100644 --- a/x/distribution/client/cli/tx.go +++ b/x/distribution/client/cli/tx.go @@ -4,6 +4,7 @@ package cli import ( "bufio" "fmt" + "github.com/cosmos/cosmos-sdk/client/tx" "strings" "github.com/spf13/cobra" @@ -34,6 +35,237 @@ const ( MaxMessagesPerTxDefault = 5 ) +// NewTxCmd returns a root CLI command handler for all x/distribution transaction commands. +func NewTxCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command { + distTxCmd := &cobra.Command{ + Use: types.ModuleName, + Short: "Distribution transactions subcommands", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + distTxCmd.AddCommand(flags.PostCommands( + NewWithdrawRewardsCmd(m, txg, ar), + NewWithdrawAllRewardsCmd(m, txg, ar), + NewSetWithdrawAddrCmd(m, txg, ar), + NewFundCommunityPoolCmd(m, txg, ar), + )...) + + return distTxCmd +} + +type newGenerateOrBroadcastFunc func(ctx context.CLIContext, txf tx.Factory, msgs ...sdk.Msg) error + +func newSplitAndApply( + newGenerateOrBroadcast newGenerateOrBroadcastFunc, + cliCtx context.CLIContext, + txBldr tx.Factory, + msgs []sdk.Msg, + chunkSize int, +) error { + if chunkSize == 0 { + return newGenerateOrBroadcast(cliCtx, txBldr, msgs...) + } + + // split messages into slices of length chunkSize + totalMessages := len(msgs) + for i := 0; i < len(msgs); i += chunkSize { + + sliceEnd := i + chunkSize + if sliceEnd > totalMessages { + sliceEnd = totalMessages + } + + msgChunk := msgs[i:sliceEnd] + if err := newGenerateOrBroadcast(cliCtx, txBldr, msgChunk...); err != nil { + return err + } + } + + return nil +} + +func NewWithdrawRewardsCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command { + cmd := &cobra.Command{ + Use: "withdraw-rewards [validator-addr]", + Short: "Withdraw rewards from a given delegation address, and optionally withdraw validator commission if the delegation address given is a validator operator", + Long: strings.TrimSpace( + fmt.Sprintf(`Withdraw rewards from a given delegation address, +and optionally withdraw validator commission if the delegation address given is a validator operator. + +Example: +$ %s tx distribution withdraw-rewards cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj --from mykey +$ %s tx distribution withdraw-rewards cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj --from mykey --commission +`, + version.ClientName, version.ClientName, + ), + ), + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + inBuf := bufio.NewReader(cmd.InOrStdin()) + txf := tx.NewFactoryFromCLI(inBuf). + WithTxGenerator(txg). + WithAccountRetriever(ar) + cliCtx := context.NewCLIContextWithInputAndFrom(inBuf, args[0]).WithMarshaler(m) + + delAddr := cliCtx.GetFromAddress() + valAddr, err := sdk.ValAddressFromBech32(args[0]) + if err != nil { + return err + } + + msgs := []sdk.Msg{types.NewMsgWithdrawDelegatorReward(delAddr, valAddr)} + if viper.GetBool(flagCommission) { + msgs = append(msgs, types.NewMsgWithdrawValidatorCommission(valAddr)) + } + + for _, msg := range msgs { + if err := msg.ValidateBasic(); err != nil { + return err + } + } + + return tx.GenerateOrBroadcastTx(cliCtx, txf, msgs...) + }, + } + cmd.Flags().Bool(flagCommission, false, "also withdraw validator's commission") + return flags.PostCommands(cmd)[0] +} + +func NewWithdrawAllRewardsCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command { + cmd := &cobra.Command{ + Use: "withdraw-all-rewards", + Short: "withdraw all delegations rewards for a delegator", + Long: strings.TrimSpace( + fmt.Sprintf(`Withdraw all rewards for a single delegator. + +Example: +$ %s tx distribution withdraw-all-rewards --from mykey +`, + version.ClientName, + ), + ), + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + inBuf := bufio.NewReader(cmd.InOrStdin()) + txf := tx.NewFactoryFromCLI(inBuf). + WithTxGenerator(txg). + WithAccountRetriever(ar) + cliCtx := context.NewCLIContextWithInputAndFrom(inBuf, args[0]).WithMarshaler(m) + + delAddr := cliCtx.GetFromAddress() + + // The transaction cannot be generated offline since it requires a query + // to get all the validators. + if cliCtx.Offline { + return fmt.Errorf("cannot generate tx in offline mode") + } + + msgs, err := common.WithdrawAllDelegatorRewards(cliCtx, types.QuerierRoute, delAddr) + if err != nil { + return err + } + + chunkSize := viper.GetInt(flagMaxMessagesPerTx) + return newSplitAndApply(tx.GenerateOrBroadcastTx, cliCtx, txf, msgs, chunkSize) + }, + } + return flags.PostCommands(cmd)[0] +} + +func NewSetWithdrawAddrCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command { + cmd := &cobra.Command{ + Use: "set-withdraw-addr [withdraw-addr]", + Short: "change the default withdraw address for rewards associated with an address", + Long: strings.TrimSpace( + fmt.Sprintf(`Set the withdraw address for rewards associated with a delegator address. + +Example: +$ %s tx distribution set-withdraw-addr cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p --from mykey +`, + version.ClientName, + ), + ), + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + inBuf := bufio.NewReader(cmd.InOrStdin()) + txf := tx.NewFactoryFromCLI(inBuf). + WithTxGenerator(txg). + WithAccountRetriever(ar) + cliCtx := context.NewCLIContextWithInputAndFrom(inBuf, args[0]).WithMarshaler(m) + + delAddr := cliCtx.GetFromAddress() + withdrawAddr, err := sdk.AccAddressFromBech32(args[0]) + if err != nil { + return err + } + + msg := types.NewMsgSetWithdrawAddress(delAddr, withdrawAddr) + if err := msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTx(cliCtx, txf, msg) + }, + } + return flags.PostCommands(cmd)[0] +} + +func NewFundCommunityPoolCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command { + cmd := &cobra.Command{ + Use: "community-pool-spend [proposal-file]", + Args: cobra.ExactArgs(1), + Short: "Submit a community pool spend proposal", + Long: strings.TrimSpace( + fmt.Sprintf(`Submit a community pool spend proposal along with an initial deposit. +The proposal details must be supplied via a JSON file. + +Example: +$ %s tx gov submit-proposal community-pool-spend --from= + +Where proposal.json contains: + +{ + "title": "Community Pool Spend", + "description": "Pay me some Atoms!", + "recipient": "cosmos1s5afhd6gxevu37mkqcvvsj8qeylhn0rz46zdlq", + "amount": "1000stake", + "deposit": "1000stake" +} +`, + version.ClientName, + ), + ), + RunE: func(cmd *cobra.Command, args []string) error { + inBuf := bufio.NewReader(cmd.InOrStdin()) + txf := tx.NewFactoryFromCLI(inBuf). + WithTxGenerator(txg). + WithAccountRetriever(ar) + cliCtx := context.NewCLIContextWithInputAndFrom(inBuf, args[0]).WithMarshaler(m) + + depositorAddr := cliCtx.GetFromAddress() + amount, err := sdk.ParseCoins(args[0]) + if err != nil { + return err + } + + msg := types.NewMsgFundCommunityPool(amount, depositorAddr) + if err := msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTx(cliCtx, txf, msg) + }, + } + return flags.PostCommands(cmd)[0] +} + +// --------------------------------------------------------------------------- +// Deprecated +// +// TODO: Remove once client-side Protobuf migration has been completed. +// --------------------------------------------------------------------------- // GetTxCmd returns the transaction commands for this module func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { distTxCmd := &cobra.Command{ @@ -184,7 +416,6 @@ $ %s tx distribution set-withdraw-addr cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75 ), Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - inBuf := bufio.NewReader(cmd.InOrStdin()) txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) diff --git a/x/distribution/client/rest/query.go b/x/distribution/client/rest/query.go index 1d614c17fe6a..4f0c203ee721 100644 --- a/x/distribution/client/rest/query.go +++ b/x/distribution/client/rest/query.go @@ -14,59 +14,59 @@ import ( "github.com/cosmos/cosmos-sdk/types/rest" ) -func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router, queryRoute string) { +func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router) { // Get the total rewards balance from all delegations r.HandleFunc( "/distribution/delegators/{delegatorAddr}/rewards", - delegatorRewardsHandlerFn(cliCtx, queryRoute), + delegatorRewardsHandlerFn(cliCtx), ).Methods("GET") // Query a delegation reward r.HandleFunc( "/distribution/delegators/{delegatorAddr}/rewards/{validatorAddr}", - delegationRewardsHandlerFn(cliCtx, queryRoute), + delegationRewardsHandlerFn(cliCtx), ).Methods("GET") // Get the rewards withdrawal address r.HandleFunc( "/distribution/delegators/{delegatorAddr}/withdraw_address", - delegatorWithdrawalAddrHandlerFn(cliCtx, queryRoute), + delegatorWithdrawalAddrHandlerFn(cliCtx), ).Methods("GET") // Validator distribution information r.HandleFunc( "/distribution/validators/{validatorAddr}", - validatorInfoHandlerFn(cliCtx, queryRoute), + validatorInfoHandlerFn(cliCtx), ).Methods("GET") // Commission and self-delegation rewards of a single a validator r.HandleFunc( "/distribution/validators/{validatorAddr}/rewards", - validatorRewardsHandlerFn(cliCtx, queryRoute), + validatorRewardsHandlerFn(cliCtx), ).Methods("GET") // Outstanding rewards of a single validator r.HandleFunc( "/distribution/validators/{validatorAddr}/outstanding_rewards", - outstandingRewardsHandlerFn(cliCtx, queryRoute), + outstandingRewardsHandlerFn(cliCtx), ).Methods("GET") // Get the current distribution parameter values r.HandleFunc( "/distribution/parameters", - paramsHandlerFn(cliCtx, queryRoute), + paramsHandlerFn(cliCtx), ).Methods("GET") // Get the amount held in the community pool r.HandleFunc( "/distribution/community_pool", - communityPoolHandler(cliCtx, queryRoute), + communityPoolHandler(cliCtx), ).Methods("GET") } // HTTP request handler to query the total rewards balance from all delegations -func delegatorRewardsHandlerFn(cliCtx context.CLIContext, queryRoute string) http.HandlerFunc { +func delegatorRewardsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) if !ok { @@ -85,7 +85,7 @@ func delegatorRewardsHandlerFn(cliCtx context.CLIContext, queryRoute string) htt return } - route := fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryDelegatorTotalRewards) + route := fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryDelegatorTotalRewards) res, height, err := cliCtx.QueryWithData(route, bz) if rest.CheckInternalServerError(w, err) { return @@ -97,7 +97,7 @@ func delegatorRewardsHandlerFn(cliCtx context.CLIContext, queryRoute string) htt } // HTTP request handler to query a delegation rewards -func delegationRewardsHandlerFn(cliCtx context.CLIContext, queryRoute string) http.HandlerFunc { +func delegationRewardsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) if !ok { @@ -108,7 +108,7 @@ func delegationRewardsHandlerFn(cliCtx context.CLIContext, queryRoute string) ht valAddr := mux.Vars(r)["validatorAddr"] // query for rewards from a particular delegation - res, height, ok := checkResponseQueryDelegationRewards(w, cliCtx, queryRoute, delAddr, valAddr) + res, height, ok := checkResponseQueryDelegationRewards(w, cliCtx, types.QuerierRoute, delAddr, valAddr) if !ok { return } @@ -119,7 +119,7 @@ func delegationRewardsHandlerFn(cliCtx context.CLIContext, queryRoute string) ht } // HTTP request handler to query a delegation rewards -func delegatorWithdrawalAddrHandlerFn(cliCtx context.CLIContext, queryRoute string) http.HandlerFunc { +func delegatorWithdrawalAddrHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { delegatorAddr, ok := checkDelegatorAddressVar(w, r) if !ok { @@ -132,7 +132,7 @@ func delegatorWithdrawalAddrHandlerFn(cliCtx context.CLIContext, queryRoute stri } bz := cliCtx.Codec.MustMarshalJSON(types.NewQueryDelegatorWithdrawAddrParams(delegatorAddr)) - res, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/withdraw_addr", queryRoute), bz) + res, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/withdraw_addr", types.QuerierRoute), bz) if rest.CheckInternalServerError(w, err) { return } @@ -161,7 +161,7 @@ func NewValidatorDistInfo(operatorAddr sdk.AccAddress, rewards sdk.DecCoins, } // HTTP request handler to query validator's distribution information -func validatorInfoHandlerFn(cliCtx context.CLIContext, queryRoute string) http.HandlerFunc { +func validatorInfoHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { valAddr, ok := checkValidatorAddressVar(w, r) if !ok { @@ -174,7 +174,7 @@ func validatorInfoHandlerFn(cliCtx context.CLIContext, queryRoute string) http.H } // query commission - bz, err := common.QueryValidatorCommission(cliCtx, queryRoute, valAddr) + bz, err := common.QueryValidatorCommission(cliCtx, types.QuerierRoute, valAddr) if rest.CheckInternalServerError(w, err) { return } @@ -186,7 +186,7 @@ func validatorInfoHandlerFn(cliCtx context.CLIContext, queryRoute string) http.H // self bond rewards delAddr := sdk.AccAddress(valAddr) - bz, height, ok := checkResponseQueryDelegationRewards(w, cliCtx, queryRoute, delAddr.String(), valAddr.String()) + bz, height, ok := checkResponseQueryDelegationRewards(w, cliCtx, types.QuerierRoute, delAddr.String(), valAddr.String()) if !ok { return } @@ -207,7 +207,7 @@ func validatorInfoHandlerFn(cliCtx context.CLIContext, queryRoute string) http.H } // HTTP request handler to query validator's commission and self-delegation rewards -func validatorRewardsHandlerFn(cliCtx context.CLIContext, queryRoute string) http.HandlerFunc { +func validatorRewardsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { valAddr := mux.Vars(r)["validatorAddr"] validatorAddr, ok := checkValidatorAddressVar(w, r) @@ -221,7 +221,7 @@ func validatorRewardsHandlerFn(cliCtx context.CLIContext, queryRoute string) htt } delAddr := sdk.AccAddress(validatorAddr).String() - bz, height, ok := checkResponseQueryDelegationRewards(w, cliCtx, queryRoute, delAddr, valAddr) + bz, height, ok := checkResponseQueryDelegationRewards(w, cliCtx, types.QuerierRoute, delAddr, valAddr) if !ok { return } @@ -232,7 +232,7 @@ func validatorRewardsHandlerFn(cliCtx context.CLIContext, queryRoute string) htt } // HTTP request handler to query the distribution params values -func paramsHandlerFn(cliCtx context.CLIContext, queryRoute string) http.HandlerFunc { +func paramsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) if !ok { @@ -250,14 +250,14 @@ func paramsHandlerFn(cliCtx context.CLIContext, queryRoute string) http.HandlerF } } -func communityPoolHandler(cliCtx context.CLIContext, queryRoute string) http.HandlerFunc { +func communityPoolHandler(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) if !ok { return } - res, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/community_pool", queryRoute), nil) + res, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/community_pool", types.QuerierRoute), nil) if rest.CheckInternalServerError(w, err) { return } @@ -273,7 +273,7 @@ func communityPoolHandler(cliCtx context.CLIContext, queryRoute string) http.Han } // HTTP request handler to query the outstanding rewards -func outstandingRewardsHandlerFn(cliCtx context.CLIContext, queryRoute string) http.HandlerFunc { +func outstandingRewardsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { validatorAddr, ok := checkValidatorAddressVar(w, r) if !ok { @@ -286,7 +286,7 @@ func outstandingRewardsHandlerFn(cliCtx context.CLIContext, queryRoute string) h } bin := cliCtx.Codec.MustMarshalJSON(types.NewQueryValidatorOutstandingRewardsParams(validatorAddr)) - res, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/validator_outstanding_rewards", queryRoute), bin) + res, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/validator_outstanding_rewards", types.QuerierRoute), bin) if rest.CheckInternalServerError(w, err) { return } diff --git a/x/distribution/client/rest/rest.go b/x/distribution/client/rest/rest.go index ee26ce9544f5..02fe286f9f65 100644 --- a/x/distribution/client/rest/rest.go +++ b/x/distribution/client/rest/rest.go @@ -1,6 +1,8 @@ package rest import ( + "github.com/cosmos/cosmos-sdk/client/tx" + "github.com/cosmos/cosmos-sdk/codec" "net/http" "github.com/gorilla/mux" @@ -14,12 +16,18 @@ import ( govrest "github.com/cosmos/cosmos-sdk/x/gov/client/rest" ) +func RegisterHandlers(cliCtx context.CLIContext, m codec.Marshaler, txg tx.Generator, r *mux.Router) { + registerQueryRoutes(cliCtx, r) + registerTxHandlers(cliCtx, m, txg, r) +} + // RegisterRoutes register distribution REST routes. func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, queryRoute string) { - registerQueryRoutes(cliCtx, r, queryRoute) + registerQueryRoutes(cliCtx, r) registerTxRoutes(cliCtx, r, queryRoute) } +// TODO add proto compatible Handler after x/gov migration // ProposalRESTHandler returns a ProposalRESTHandler that exposes the community pool spend REST handler with a given sub-route. func ProposalRESTHandler(cliCtx context.CLIContext) govrest.ProposalRESTHandler { return govrest.ProposalRESTHandler{ diff --git a/x/distribution/client/rest/tx.go b/x/distribution/client/rest/tx.go index 233c92832c78..28be05d77f52 100644 --- a/x/distribution/client/rest/tx.go +++ b/x/distribution/client/rest/tx.go @@ -1,6 +1,8 @@ package rest import ( + "github.com/cosmos/cosmos-sdk/client/tx" + "github.com/cosmos/cosmos-sdk/codec" "net/http" "github.com/gorilla/mux" @@ -14,54 +16,236 @@ import ( "github.com/cosmos/cosmos-sdk/types/rest" ) -func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router, queryRoute string) { +type ( + withdrawRewardsReq struct { + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + } + + setWithdrawalAddrReq struct { + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + WithdrawAddress sdk.AccAddress `json:"withdraw_address" yaml:"withdraw_address"` + } + + fundCommunityPoolReq struct { + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + Amount sdk.Coins `json:"amount" yaml:"amount"` + } +) + +func registerTxHandlers(cliCtx context.CLIContext, m codec.Marshaler, txg tx.Generator, r *mux.Router) { // Withdraw all delegator rewards r.HandleFunc( "/distribution/delegators/{delegatorAddr}/rewards", - withdrawDelegatorRewardsHandlerFn(cliCtx, queryRoute), + newWithdrawDelegatorRewardsHandlerFn(cliCtx, m, txg), ).Methods("POST") // Withdraw delegation rewards r.HandleFunc( "/distribution/delegators/{delegatorAddr}/rewards/{validatorAddr}", - withdrawDelegationRewardsHandlerFn(cliCtx), + newWithdrawDelegationRewardsHandlerFn(cliCtx, m, txg), ).Methods("POST") // Replace the rewards withdrawal address r.HandleFunc( "/distribution/delegators/{delegatorAddr}/withdraw_address", - setDelegatorWithdrawalAddrHandlerFn(cliCtx), + newSetDelegatorWithdrawalAddrHandlerFn(cliCtx, m, txg), ).Methods("POST") // Withdraw validator rewards and commission r.HandleFunc( "/distribution/validators/{validatorAddr}/rewards", - withdrawValidatorRewardsHandlerFn(cliCtx), + newWithdrawValidatorRewardsHandlerFn(cliCtx, m, txg), ).Methods("POST") // Fund the community pool r.HandleFunc( "/distribution/community_pool", - fundCommunityPoolHandlerFn(cliCtx), + newFundCommunityPoolHandlerFn(cliCtx, m, txg), ).Methods("POST") +} +func newWithdrawDelegatorRewardsHandlerFn(cliCtx context.CLIContext, m codec.Marshaler, txg tx.Generator) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + cliCtx = cliCtx.WithMarshaler(m) + var req withdrawRewardsReq + if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) { + return + } + + req.BaseReq = req.BaseReq.Sanitize() + if !req.BaseReq.ValidateBasic(w) { + return + } + + // read and validate URL's variables + delAddr, ok := checkDelegatorAddressVar(w, r) + if !ok { + return + } + + msgs, err := common.WithdrawAllDelegatorRewards(cliCtx, types.QuerierRoute, delAddr) + if rest.CheckInternalServerError(w, err) { + return + } + + tx.WriteGeneratedTxResponse(cliCtx, w, txg, req.BaseReq, msgs...) + } } -type ( - withdrawRewardsReq struct { - BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` +func newWithdrawDelegationRewardsHandlerFn(cliCtx context.CLIContext, m codec.Marshaler, txg tx.Generator) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + cliCtx = cliCtx.WithMarshaler(m) + var req withdrawRewardsReq + if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) { + return + } + + req.BaseReq = req.BaseReq.Sanitize() + if !req.BaseReq.ValidateBasic(w) { + return + } + + // read and validate URL's variables + delAddr, ok := checkDelegatorAddressVar(w, r) + if !ok { + return + } + + valAddr, ok := checkValidatorAddressVar(w, r) + if !ok { + return + } + + msg := types.NewMsgWithdrawDelegatorReward(delAddr, valAddr) + if rest.CheckBadRequestError(w, msg.ValidateBasic()) { + return + } + + tx.WriteGeneratedTxResponse(cliCtx, w, txg, req.BaseReq, msg) } +} - setWithdrawalAddrReq struct { - BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` - WithdrawAddress sdk.AccAddress `json:"withdraw_address" yaml:"withdraw_address"` +func newSetDelegatorWithdrawalAddrHandlerFn(cliCtx context.CLIContext, m codec.Marshaler, txg tx.Generator) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + cliCtx = cliCtx.WithMarshaler(m) + var req setWithdrawalAddrReq + if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) { + return + } + + req.BaseReq = req.BaseReq.Sanitize() + if !req.BaseReq.ValidateBasic(w) { + return + } + + // read and validate URL's variables + delAddr, ok := checkDelegatorAddressVar(w, r) + if !ok { + return + } + + msg := types.NewMsgSetWithdrawAddress(delAddr, req.WithdrawAddress) + if rest.CheckBadRequestError(w, msg.ValidateBasic()) { + return + } + + tx.WriteGeneratedTxResponse(cliCtx, w, txg, req.BaseReq, msg) } +} - fundCommunityPoolReq struct { - BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` - Amount sdk.Coins `json:"amount" yaml:"amount"` +func newWithdrawValidatorRewardsHandlerFn(cliCtx context.CLIContext, m codec.Marshaler, txg tx.Generator) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + cliCtx = cliCtx.WithMarshaler(m) + var req withdrawRewardsReq + if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) { + return + } + + req.BaseReq = req.BaseReq.Sanitize() + if !req.BaseReq.ValidateBasic(w) { + return + } + + // read and validate URL's variable + valAddr, ok := checkValidatorAddressVar(w, r) + if !ok { + return + } + + // prepare multi-message transaction + msgs, err := common.WithdrawValidatorRewardsAndCommission(valAddr) + if rest.CheckBadRequestError(w, err) { + return + } + + tx.WriteGeneratedTxResponse(cliCtx, w, txg, req.BaseReq, msgs...) } -) +} + +func newFundCommunityPoolHandlerFn(cliCtx context.CLIContext, m codec.Marshaler, txg tx.Generator) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + cliCtx = cliCtx.WithMarshaler(m) + var req fundCommunityPoolReq + if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) { + return + } + + req.BaseReq = req.BaseReq.Sanitize() + if !req.BaseReq.ValidateBasic(w) { + return + } + + fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From) + if rest.CheckBadRequestError(w, err) { + return + } + + msg := types.NewMsgFundCommunityPool(req.Amount, fromAddr) + if rest.CheckBadRequestError(w, msg.ValidateBasic()) { + return + } + + tx.WriteGeneratedTxResponse(cliCtx, w, txg, req.BaseReq, msg) + } +} + +// --------------------------------------------------------------------------- +// Deprecated +// +// TODO: Remove once client-side Protobuf migration has been completed. +// --------------------------------------------------------------------------- +func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router, queryRoute string) { + // Withdraw all delegator rewards + r.HandleFunc( + "/distribution/delegators/{delegatorAddr}/rewards", + withdrawDelegatorRewardsHandlerFn(cliCtx, queryRoute), + ).Methods("POST") + + // Withdraw delegation rewards + r.HandleFunc( + "/distribution/delegators/{delegatorAddr}/rewards/{validatorAddr}", + withdrawDelegationRewardsHandlerFn(cliCtx), + ).Methods("POST") + + // Replace the rewards withdrawal address + r.HandleFunc( + "/distribution/delegators/{delegatorAddr}/withdraw_address", + setDelegatorWithdrawalAddrHandlerFn(cliCtx), + ).Methods("POST") + + // Withdraw validator rewards and commission + r.HandleFunc( + "/distribution/validators/{validatorAddr}/rewards", + withdrawValidatorRewardsHandlerFn(cliCtx), + ).Methods("POST") + + // Fund the community pool + r.HandleFunc( + "/distribution/community_pool", + fundCommunityPoolHandlerFn(cliCtx), + ).Methods("POST") + +} // Withdraw delegator rewards func withdrawDelegatorRewardsHandlerFn(cliCtx context.CLIContext, queryRoute string) http.HandlerFunc { From 8eb4808b0e59ff136273ea41acff1a3537c585da Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Wed, 8 Apr 2020 17:17:55 +0200 Subject: [PATCH 527/529] Add flag to FlagKeyringBackend to QueryTxsByEventsCmd (#5957) --- x/auth/client/cli/query.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/x/auth/client/cli/query.go b/x/auth/client/cli/query.go index 1d7e60639aa9..968771953b70 100644 --- a/x/auth/client/cli/query.go +++ b/x/auth/client/cli/query.go @@ -178,6 +178,9 @@ $ %s query txs --%s 'message.sender=cosmos1...&message.action=withdraw_delegator cmd.Flags().Bool(flags.FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)") viper.BindPFlag(flags.FlagTrustNode, cmd.Flags().Lookup(flags.FlagTrustNode)) + cmd.Flags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|kwallet|pass|test)") + viper.BindPFlag(flags.FlagKeyringBackend, cmd.Flags().Lookup(flags.FlagKeyringBackend)) + cmd.Flags().String(flagEvents, "", fmt.Sprintf("list of transaction events in the form of %s", eventFormat)) cmd.Flags().Uint32(flags.FlagPage, rest.DefaultPage, "Query a specific page of paginated results") cmd.Flags().Uint32(flags.FlagLimit, rest.DefaultLimit, "Query number of transactions results per page returned") From b5a658729170e577b0e6e809e73d5e0756b90e07 Mon Sep 17 00:00:00 2001 From: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Date: Wed, 8 Apr 2020 20:57:52 -0400 Subject: [PATCH 528/529] x/ibc: IBC alpha (#5277) * IBC alpha * ICS 23 Implementation (#4515) * add mapping * rm unused mapping/*, rm interfaces * rm unused code * mv mapping -> state, rm x/ibc * rm GetIfExists * add key * rm custom encoding/decoding in enum/bool * fix lint * rm tests * add commitment * newtyped remote values * newtyped context * revert context newtype * add README, keypath * reflect downstream ics * add merkle * add test for proving * soft coded root keypath * add update * remove RootUpdate * separate keypath and keuprefix * add codec * separate root/path * add path to codec * add docs in progre * add comments * add comments * Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * add comments in progress * add comments * fix comment * add comments in progress * recover IntEncoding scheme for integer * add uint tests, don't use codec in custom types * finalize merge * add godoc * reformat test * rm XXX * add godoc * add query * update query.go * update query.go * add Query to boolean.go * fix key * godoc cleanup * godoc cleanup * godoc cleanup * godoc cleanup * godoc cleanup * merge from ics04 branch * merge from ics04 branch * fix lint * Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * applying review in progress * apply review - make querier interface * fix dependency * revise querier interface to work both on cli & store * rm commented lines * rename Path -> Prefix * Store accessor upstream changes (#5119) * Store accessor upstream changes (#5119) * add comments, reformat merkle querier * rm merkle/utils * ICS 23 upstream changes (#5120) * ICS 23 upstream changes (#5120) * update Value * remove Mapping * remove store accessors * refactor ICS23 * cleanup types * implement batch verification * gosimple suggestion * alias * add tests * ICS 24 Implementation (#5229) * add validation functions * validate path in ics-23 * address @fede comments * move errors into host package * flatten ICS23 structure * fix ApplyPrefix * complete types testing * delete empty test file * remove ibc errors from core error package * start batch-verify tests * minor changes on commitment types * use testsuite * upstream changes * context changes * ICS 02 Implementation (#4516) * add mapping * rm unused mapping/*, rm interfaces * rm unused code * mv mapping -> state, rm x/ibc * rm GetIfExists * add key * rm custom encoding/decoding in enum/bool * fix lint * rm tests * add commitment * newtyped remote values * newtyped context * revert context newtype * add README, keypath * reflect downstream ics * add merkle * add test for proving * soft coded root keypath * add update * remove RootUpdate * separate keypath and keuprefix * add codec * separate root/path * add path to codec * add client * add counterpartymanager * fix manager * add Is() to counterobject * add readme, reflect ICS02 revision * reflect downstream ics * test in progress * add test * in progres * fin rebase * in progress * fin rebase * add CLIObject in progress * cli in progress * add CLIObject * separate testing from tendermint * add key to node * add root and storekey to tests/node, add codec * rm cli/query.go * fix test * fix lint * fix lint * add handler/msgs/client * rm relay * finalize rebase on 23 root/path sep * fix lint, fix syntax * rm freebase, reformat query * add docs in progre * add comments * add comments * Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * add comments in progress * add comments * fix comment * add comments in progress * recover IntEncoding scheme for integer * add uint tests, don't use codec in custom types * finalize merge * add godoc * add godoc in progress * reformat test * rm XXX * add godoc * modify store * add query * update query.go * update query.go * cli refactor in progress * cli refactor in progress * add Query to boolean.go * fix key * fix cli / merkle test * godoc cleanup * godoc cleanup * godoc cleanup * godoc cleanup * godoc cleanup * merge from ics04 branch * merge from ics04 branch * merge from ics04 branch * fix lint * Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * applying review in progress * apply review - make querier interface * fix dependency * fix dependency * revise querier interface to work both on cli & store * revise querier interface to work both on cli & store * reflect downstream change * fix cli * rm commented lines * address review in progress * rename Path -> Prefix * Store accessor upstream changes (#5119) * Store accessor upstream changes (#5119) * add comments, reformat merkle querier * rm merkle/utils * ICS 23 upstream changes (#5120) * ICS 23 upstream changes (#5120) * update Value * update test * fix * ICS 02 upstream changes (#5122) * ICS 02 upstream changes (#5122) * cleanup types and submodule * more cleanup and godocs * remove counterPartyManager/State and cleanup * implement SubmitMisbehaviour and refactor * errors * events * fix test * refactors * remove Mapping * remove store accessors * proposed refactor * remove store accessors from ICS02 * refactor queriers, handler and clean keeper * logger and tx long description * ineffassign * Apply suggestions from code review Co-Authored-By: Jack Zampolin * Apply suggestions from code review Co-Authored-By: Jack Zampolin * add verification functions * ICS02 module.go * top level x/ibc structure * Update x/ibc/02-client/client/cli/query.go Co-Authored-By: Jack Zampolin * Update x/ibc/02-client/types/tendermint/consensus_state.go Co-Authored-By: Jack Zampolin * address some of the review comments * minor UX improvements * rename pkg * fixes * refactor ICS23 * cleanup types * implement batch verification * gosimple suggestion * various fixes; remove legacy tests; remove commitment path query * alias * minor updates from ICS23 * renaming * update verification and rename root funcs * move querier to x/ibc * update query.go to use 'custom/...' query path * add tests * ICS 24 Implementation (#5229) * add validation functions * validate path in ics-23 * address @fede comments * move errors into host package * flatten ICS23 structure * fix ApplyPrefix * updates from ICS23 and ICS24 * msg.ValidateBasic and ADR09 evidence interface * complete types testing * delete empty test file * remove ibc errors from core error package * custom JSON marshaling * start batch-verify tests * minor changes on commitment types * R4R - Store consensus state correctly (#5242) * store consensus state correctly * fix client example * update alias * use testsuite * Integrate Evidence Implementation into ICS-02 (#5258) * implement evidence in ics-02 * fix build errors and import cycles * address fede comments * remove unnecessary pubkey and fix init * add tests * finish tendermint tests * complete merge * Add tests for msgs * upstream changes * fix * upstream changes * fix cons state * context changes * ICS 03 Implementation (#4517) * add test * in progres * fin rebase * in progress * fin rebase * add CLIObject in progress * cli in progress * add CLIObject * separate testing from tendermint * add key to node * add root and storekey to tests/node, add codec * rm cli/query.go * fix test * fix lint * fix lint * add handler/msgs/client * rm relay * finalize rebase on 23 root/path sep * fix lint, fix syntax * fix querying * extract out context withstore * fix 02-client test * fix 23-commitment test * add query in progress * rm freebase, reformat query * add cli/handler/msg in progress * add cli/msg/handler * add CLIQuery, fix tests * fix golangci * add docs in progre * add comments * add comments * Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * add comments in progress * add comments * fix comment * add comments in progress * recover IntEncoding scheme for integer * add uint tests, don't use codec in custom types * finalize merge * add godoc * add godoc in progress * reformat test * rm XXX * add godoc * modify store * add query * update query.go * update query.go * cli refactor in progress * cli refactor in progress * add Query to boolean.go * fix key * fix cli / merkle test * godoc cleanup * godoc cleanup * godoc cleanup * godoc cleanup * godoc cleanup * fix test * fix client * merge from ics04 branch * merge from ics04 branch * merge from ics04 branch * merge from ics04 branch * fix lint * Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * applying review in progress * apply review - make querier interface * fix dependency * fix dependency * revise querier interface to work both on cli & store * revise querier interface to work both on cli & store * reflect downstream change * fix cli * reflect downstream changes * rm commented lines * address review in progress * address review, rm cleanup/closing * rename Path -> Prefix * Store accessor upstream changes (#5119) * Store accessor upstream changes (#5119) * add comments, reformat merkle querier * rm merkle/utils * ICS 23 upstream changes (#5120) * ICS 23 upstream changes (#5120) * update Value * update test * fix * ICS 02 upstream changes (#5122) * ICS 02 upstream changes (#5122) * ICS 03 upstream changes (#5123) * ICS 03 upstream changes (#5123) * cleanup types and submodule * more cleanup and godocs * remove counterPartyManager/State and cleanup * implement SubmitMisbehaviour and refactor * errors * events * fix test * refactors * WIP refactor ICS03 * remove Mapping * remove store accessors * proposed refactor * remove store accessors from ICS02 * refactor queriers, handler and clean keeper * logger and tx long description * ineffassign * Apply suggestions from code review Co-Authored-By: Jack Zampolin * Apply suggestions from code review Co-Authored-By: Jack Zampolin * remove store accessors * refactor handshake to update it to the latest ICS03 spec * update handler and msgs * add verification functions * update verification * ICS02 module.go * top level x/ibc structure * update connection queries * update connection tx * remove extra files * update expected client keeper and export verification funcs * Update x/ibc/02-client/client/cli/query.go Co-Authored-By: Jack Zampolin * Update x/ibc/02-client/types/tendermint/consensus_state.go Co-Authored-By: Jack Zampolin * address some of the review comments * resolve some TODOs and address comments from review * update connection versioning * minor error updates * minor UX improvements * rename pkg * fixes * refactor ICS23 * cleanup types * rename pkg and fix import * implement batch verification * gosimple suggestion * various fixes; remove legacy tests; remove commitment path query * alias * minor updates from ICS23 * renaming * update verification and rename root funcs * move querier to x/ibc * update query.go to use 'custom/...' query path * add tests * ICS 24 Implementation (#5229) * add validation functions * validate path in ics-23 * address @fede comments * move errors into host package * flatten ICS23 structure * fix ApplyPrefix * updates from ICS23 and ICS24 * msg.ValidateBasic and ADR09 evidence interface * complete types testing * delete empty test file * remove ibc errors from core error package * custom JSON marshaling; msg.ValidateBasic; renaming of variables * minor update * custom JSON marshaling * start batch-verify tests * minor changes on commitment types * R4R - Store consensus state correctly (#5242) * store consensus state correctly * fix client example * update alias * update alias * use testsuite * Integrate Evidence Implementation into ICS-02 (#5258) * implement evidence in ics-02 * fix build errors and import cycles * address fede comments * remove unnecessary pubkey and fix init * add tests * finish tendermint tests * complete merge * Add tests for msgs * upstream changes * fix * upstream changes * fix cons state * context changes * fix cli tx * upstream changes * fix * ICS 05 implementation (#5193) * fix lint * fix lint * add handler/msgs/client * rm relay * finalize rebase on 23 root/path sep * fix lint, fix syntax * fix querying * extract out context withstore * fix 02-client test * fix 23-commitment test * add query in progress * rm freebase, reformat query * add cli/handler/msg in progress * add cli/msg/handler * add CLIQuery, fix tests * fix golangci * add docs in progre * add comments * add comments * Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * add comments in progress * add comments * fix comment * add comments in progress * recover IntEncoding scheme for integer * add uint tests, don't use codec in custom types * finalize merge * add godoc * add godoc in progress * reformat test * rm XXX * add godoc * modify store * add query * update query.go * update query.go * cli refactor in progress * cli refactor in progress * add Query to boolean.go * fix key * fix cli / merkle test * godoc cleanup * godoc cleanup * godoc cleanup * godoc cleanup * godoc cleanup * fix test * fix client * merge from ics04 branch * merge from ics04 branch * merge from ics04 branch * merge from ics04 branch * fix lint * Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * applying review in progress * apply review - make querier interface * fix dependency * fix dependency * revise querier interface to work both on cli & store * revise querier interface to work both on cli & store * reflect downstream change * fix cli * reflect downstream changes * rm commented lines * address review in progress * address review, rm cleanup/closing * rename Path -> Prefix * Store accessor upstream changes (#5119) * Store accessor upstream changes (#5119) * add comments, reformat merkle querier * rm merkle/utils * ICS 23 upstream changes (#5120) * ICS 23 upstream changes (#5120) * update Value * update test * fix * ICS 02 upstream changes (#5122) * ICS 02 upstream changes (#5122) * ICS 03 upstream changes (#5123) * ICS 03 upstream changes (#5123) * cleanup types and submodule * more cleanup and godocs * remove counterPartyManager/State and cleanup * implement SubmitMisbehaviour and refactor * errors * events * fix test * refactors * WIP refactor ICS03 * remove Mapping * remove store accessors * proposed refactor * remove store accessors from ICS02 * refactor queriers, handler and clean keeper * logger and tx long description * ineffassign * Apply suggestions from code review Co-Authored-By: Jack Zampolin * Apply suggestions from code review Co-Authored-By: Jack Zampolin * remove store accessors * refactor handshake to update it to the latest ICS03 spec * update handler and msgs * add verification functions * update verification * ICS02 module.go * top level x/ibc structure * update connection queries * update connection tx * remove extra files * update expected client keeper and export verification funcs * ICS 05 Implementation * release port and godocs * Update x/ibc/02-client/client/cli/query.go Co-Authored-By: Jack Zampolin * Update x/ibc/02-client/types/tendermint/consensus_state.go Co-Authored-By: Jack Zampolin * address some of the review comments * resolve some TODOs and address comments from review * update connection versioning * minor error updates * update errors and add port Keeper to ibc Keeper * minor UX improvements * rename pkg * fixes * refactor ICS23 * cleanup types * ICS 5 updates (#5222) * Validate port identifiers * Refactor to static bind * Add comments * Add 'GetPorts' query function * rename pkg and fix import * implement batch verification * gosimple suggestion * various fixes; remove legacy tests; remove commitment path query * alias * minor updates from ICS23 * renaming * update verification and rename root funcs * move querier to x/ibc * update query.go to use 'custom/...' query path * add tests * ICS 24 Implementation (#5229) * add validation functions * validate path in ics-23 * address @fede comments * move errors into host package * flatten ICS23 structure * fix ApplyPrefix * updates from ICS23 and ICS24 * msg.ValidateBasic and ADR09 evidence interface * complete types testing * delete empty test file * remove ibc errors from core error package * custom JSON marshaling; msg.ValidateBasic; renaming of variables * minor update * custom JSON marshaling * use host validation for port ids * start batch-verify tests * minor changes on commitment types * R4R - Store consensus state correctly (#5242) * store consensus state correctly * fix client example * update alias * update alias * update alias and keeper.GetPort() * use testsuite * Integrate Evidence Implementation into ICS-02 (#5258) * implement evidence in ics-02 * fix build errors and import cycles * address fede comments * remove unnecessary pubkey and fix init * add tests * finish tendermint tests * complete merge * Add tests for msgs * upstream changes * fix * upstream changes * fix cons state * context changes * fix cli tx * upstream changes * upstream changes * ICS 04 Implementation (#4548) * merge from ics04 branch * merge from ics04 branch * fix lint * add port * fix test * add mocks * fix connid -> portid in handshake.go * add mock * add ibc module.go, finalize mock * add keeper * add StoreKey const * fix test * Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * applying review in progress * apply review - make querier interface * fix cli errors * fix dependency * fix dependency * reflect method name change * revise querier interface to work both on cli & store * revise querier interface to work both on cli & store * revise querier interface to work both on cli & store * reflect downstream change * fix cli * reflect downstream changes * reflect downstream changes * fix from address in tx cli * fix cli in progress(squash later) * fix cli * remove timeout, add channel cli * fix golangci * fix cli * Clean up * fix mock cli in progress * finalize cleanup, mock cli wip * add cli for mocksend * fix handler * rm commented lines * address review in progress * address review, rm cleanup/closing * rename mock packages * fix interface for gaia * rename Path -> Prefix * Store accessor upstream changes (#5119) * Store accessor upstream changes (#5119) * add comments, reformat merkle querier * rm merkle/utils * ICS 23 upstream changes (#5120) * ICS 23 upstream changes (#5120) * update Value * update test * fix * ICS 02 upstream changes (#5122) * ICS 02 upstream changes (#5122) * ICS 03 upstream changes (#5123) * ICS 03 upstream changes (#5123) * update test * cleanup types and submodule * more cleanup and godocs * remove counterPartyManager/State and cleanup * implement SubmitMisbehaviour and refactor * errors * events * fix test * refactors * WIP refactor ICS03 * remove Mapping * remove store accessors * proposed refactor * remove store accessors from ICS02 * refactor queriers, handler and clean keeper * logger and tx long description * ineffassign * Apply suggestions from code review Co-Authored-By: Jack Zampolin * Apply suggestions from code review Co-Authored-By: Jack Zampolin * remove store accessors * refactor handshake to update it to the latest ICS03 spec * update handler and msgs * add verification functions * update verification * ICS02 module.go * top level x/ibc structure * update connection queries * update connection tx * remove extra files * refactor: remove store accessors, update keeper and types to match spec (WIP) * update handshake and packet * implement packet timeouts * implement send and receive packet * implement packet ACK * update handler * add channel errors * channel querier * update expected client keeper and export verification funcs * ICS 05 Implementation * release port and godocs * Update x/ibc/02-client/client/cli/query.go Co-Authored-By: Jack Zampolin * Update x/ibc/02-client/types/tendermint/consensus_state.go Co-Authored-By: Jack Zampolin * address some of the review comments * resolve some TODOs and address comments from review * update connection versioning * minor error updates * update ICS04 with downstream changes * Implement tx cli actions * add MsgSendPacket handler; msg validation, errors and events * update errors and add port Keeper to ibc Keeper * minor UX improvements * rename pkg * fixes * refactor ICS23 * cleanup types * ICS 5 updates (#5222) * Validate port identifiers * Refactor to static bind * Add comments * Add 'GetPorts' query function * rename pkg and fix import * implement batch verification * gosimple suggestion * various fixes; remove legacy tests; remove commitment path query * alias * minor updates from ICS23 * renaming * update verification and rename root funcs * rm legacy tests; add query proofs support * remove capability key generation and authentication logic * move querier to x/ibc * update query.go to use 'custom/...' query path * add tests * ICS 24 Implementation (#5229) * add validation functions * validate path in ics-23 * address @fede comments * move errors into host package * flatten ICS23 structure * fix ApplyPrefix * updates from ICS23 and ICS24 * msg.ValidateBasic and ADR09 evidence interface * complete types testing * delete empty test file * remove ibc errors from core error package * custom JSON marshaling; msg.ValidateBasic; renaming of variables * minor update * custom JSON marshaling * use host validation for port ids * downstream changes; custom marshal JSON; msg validation, and update errors * update errors and aliases * start batch-verify tests * update msg validation and CLI UX * minor changes on commitment types * fix channel and packet check (#5243) * R4R - Store consensus state correctly (#5242) * store consensus state correctly * fix client example * update alias * update alias * update alias and keeper.GetPort() * authenticate port ID; remove send packet msg from CLI * comment out handlers * use testsuite * Integrate Evidence Implementation into ICS-02 (#5258) * implement evidence in ics-02 * fix build errors and import cycles * address fede comments * remove unnecessary pubkey and fix init * add tests * finish tendermint tests * complete merge * Add tests for msgs * upstream changes * fix * upstream changes * fix cons state * context changes * fix cli tx * upstream changes * upstream changes * upstream changes * IBC v1.0.0 (#5245) * applying review in progress * apply review - make querier interface * fix cli errors * fix dependency * fix dependency * reflect method name change * revise querier interface to work both on cli & store * revise querier interface to work both on cli & store * revise querier interface to work both on cli & store * reflect downstream change * fix cli * reflect downstream changes * reflect downstream changes * fix from address in tx cli * fix cli in progress(squash later) * fix cli * remove timeout, add channel cli * fix golangci * fix cli * Clean up * fix mock cli in progress * finalize cleanup, mock cli wip * add cli for mocksend * fix handler * rm commented lines * address review in progress * address review, rm cleanup/closing * rename mock packages * fix interface for gaia * rename Path -> Prefix * Store accessor upstream changes (#5119) * Store accessor upstream changes (#5119) * add comments, reformat merkle querier * rm merkle/utils * ICS 23 upstream changes (#5120) * ICS 23 upstream changes (#5120) * update Value * update test * fix * ICS 02 upstream changes (#5122) * ICS 02 upstream changes (#5122) * ICS 03 upstream changes (#5123) * ICS 03 upstream changes (#5123) * update test * cleanup types and submodule * more cleanup and godocs * remove counterPartyManager/State and cleanup * implement SubmitMisbehaviour and refactor * errors * events * fix test * refactors * WIP refactor ICS03 * remove Mapping * remove store accessors * proposed refactor * remove store accessors from ICS02 * refactor queriers, handler and clean keeper * logger and tx long description * ineffassign * Apply suggestions from code review Co-Authored-By: Jack Zampolin * Apply suggestions from code review Co-Authored-By: Jack Zampolin * remove store accessors * refactor handshake to update it to the latest ICS03 spec * update handler and msgs * add verification functions * update verification * ICS02 module.go * top level x/ibc structure * update connection queries * update connection tx * remove extra files * refactor: remove store accessors, update keeper and types to match spec (WIP) * update handshake and packet * implement packet timeouts * implement send and receive packet * implement packet ACK * update handler * add channel errors * channel querier * update expected client keeper and export verification funcs * ICS 05 Implementation * release port and godocs * Update x/ibc/02-client/client/cli/query.go Co-Authored-By: Jack Zampolin * Update x/ibc/02-client/types/tendermint/consensus_state.go Co-Authored-By: Jack Zampolin * address some of the review comments * resolve some TODOs and address comments from review * update connection versioning * minor error updates * update ICS04 with downstream changes * Implement tx cli actions * add MsgSendPacket handler; msg validation, errors and events * update errors and add port Keeper to ibc Keeper * minor UX improvements * rename pkg * fixes * refactor ICS23 * cleanup types * ICS 5 updates (#5222) * Validate port identifiers * Refactor to static bind * Add comments * Add 'GetPorts' query function * rename pkg and fix import * implement batch verification * gosimple suggestion * various fixes; remove legacy tests; remove commitment path query * alias * minor updates from ICS23 * renaming * update verification and rename root funcs * rm legacy tests; add query proofs support * remove capability key generation and authentication logic * move querier to x/ibc * update query.go to use 'custom/...' query path * add tests * ICS 24 Implementation (#5229) * add validation functions * validate path in ics-23 * address @fede comments * move errors into host package * flatten ICS23 structure * fix ApplyPrefix * updates from ICS23 and ICS24 * msg.ValidateBasic and ADR09 evidence interface * complete types testing * delete empty test file * remove ibc errors from core error package * custom JSON marshaling; msg.ValidateBasic; renaming of variables * minor update * custom JSON marshaling * use host validation for port ids * downstream changes; custom marshal JSON; msg validation, and update errors * update errors and aliases * start batch-verify tests * update msg validation and CLI UX * minor changes on commitment types * fix channel and packet check (#5243) * R4R - Store consensus state correctly (#5242) * store consensus state correctly * fix client example * update alias * update alias * update alias and keeper.GetPort() * authenticate port ID; remove send packet msg from CLI * comment out handlers * add ibc module to simapp * ICS20 implementation (#5204) * add ibc bank mock * modify handler * import channel * add receiving logic * add cli proof handling * modify cli * modify receiver type * modify errcode * optimize codes * add denom prefix when source is true * refactor code * error return * switch ibc antehandler to decorator pattern * fix name/comment * ICS 20 implementation (#5250) * move ics20 code to 20-transfer * clean code * fix compiling error * add transfer module * address ICS20 comments from review * add routing callbacks * clean code * add missing err return * modify err type * modify err type * add supply handling * modify proof type * add comments for msg and packet data * add timeout supply handling * modify module account name * use supply keeper for burn and mint coins * restructure keeper * update alias and module.go * golangci linter * add ics20 handler to IBC handler * update callbacks * update ICS20 escrow address * fix querier routes * fix create client cli * minor updates * ibc querier test * Refactor ibc/mock/bank into ICS 20 (#5264) * Most of code port from mock module to ICS 20 * A few minor fixes * Apply suggestions from code review Co-Authored-By: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com> * Fix suggestions from autolinter * Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * Fix order of messages * Add invalid height error code, check non-nil proof * Fix linter error * Return the underlying error * Tendermint starts at height 1 * Apply suggestions from code review * setup ics20 test suite * add event to MsgRecvPacket * update ibc keeper test to use test suite * Add handshake commands * WIP connection handshake * WIP Connection Handshake * use testsuite * Add cliCtx.WaitForNBlocks * fix connection handshake in progress * fix connection handshake in progress * Integrate Evidence Implementation into ICS-02 (#5258) * implement evidence in ics-02 * fix build errors and import cycles * address fede comments * remove unnecessary pubkey and fix init * add tests * finish tendermint tests * complete merge * Add tests for msgs * upstream changes * fix * upstream changes * fix cons state * context changes * fix cli tx * upstream changes * upstream changes * upstream changes * upstream changes * IBC demo fixes (#5267) * WIP refactor ICS03 * remove Mapping * remove store accessors * proposed refactor * remove store accessors from ICS02 * refactor queriers, handler and clean keeper * logger and tx long description * ineffassign * Apply suggestions from code review Co-Authored-By: Jack Zampolin * Apply suggestions from code review Co-Authored-By: Jack Zampolin * remove store accessors * refactor handshake to update it to the latest ICS03 spec * update handler and msgs * add verification functions * update verification * ICS02 module.go * top level x/ibc structure * update connection queries * update connection tx * remove extra files * refactor: remove store accessors, update keeper and types to match spec (WIP) * update handshake and packet * implement packet timeouts * implement send and receive packet * implement packet ACK * update handler * add channel errors * channel querier * update expected client keeper and export verification funcs * ICS 05 Implementation * release port and godocs * Update x/ibc/02-client/client/cli/query.go Co-Authored-By: Jack Zampolin * Update x/ibc/02-client/types/tendermint/consensus_state.go Co-Authored-By: Jack Zampolin * address some of the review comments * resolve some TODOs and address comments from review * update connection versioning * minor error updates * update ICS04 with downstream changes * Implement tx cli actions * add MsgSendPacket handler; msg validation, errors and events * update errors and add port Keeper to ibc Keeper * minor UX improvements * rename pkg * fixes * refactor ICS23 * cleanup types * ICS 5 updates (#5222) * Validate port identifiers * Refactor to static bind * Add comments * Add 'GetPorts' query function * rename pkg and fix import * implement batch verification * gosimple suggestion * various fixes; remove legacy tests; remove commitment path query * alias * minor updates from ICS23 * renaming * update verification and rename root funcs * rm legacy tests; add query proofs support * remove capability key generation and authentication logic * move querier to x/ibc * update query.go to use 'custom/...' query path * add tests * ICS 24 Implementation (#5229) * add validation functions * validate path in ics-23 * address @fede comments * move errors into host package * flatten ICS23 structure * fix ApplyPrefix * updates from ICS23 and ICS24 * msg.ValidateBasic and ADR09 evidence interface * complete types testing * delete empty test file * remove ibc errors from core error package * custom JSON marshaling; msg.ValidateBasic; renaming of variables * minor update * custom JSON marshaling * use host validation for port ids * downstream changes; custom marshal JSON; msg validation, and update errors * update errors and aliases * start batch-verify tests * update msg validation and CLI UX * minor changes on commitment types * fix channel and packet check (#5243) * R4R - Store consensus state correctly (#5242) * store consensus state correctly * fix client example * update alias * update alias * update alias and keeper.GetPort() * authenticate port ID; remove send packet msg from CLI * comment out handlers * add ibc module to simapp * ICS20 implementation (#5204) * add ibc bank mock * modify handler * import channel * add receiving logic * add cli proof handling * modify cli * modify receiver type * modify errcode * optimize codes * add denom prefix when source is true * refactor code * error return * switch ibc antehandler to decorator pattern * fix name/comment * ICS 20 implementation (#5250) * move ics20 code to 20-transfer * clean code * fix compiling error * add transfer module * address ICS20 comments from review * add routing callbacks * clean code * add missing err return * modify err type * modify err type * add supply handling * modify proof type * add comments for msg and packet data * add timeout supply handling * modify module account name * use supply keeper for burn and mint coins * restructure keeper * update alias and module.go * golangci linter * add ics20 handler to IBC handler * update callbacks * update ICS20 escrow address * fix querier routes * fix create client cli * minor updates * ibc querier test * Refactor ibc/mock/bank into ICS 20 (#5264) * Most of code port from mock module to ICS 20 * A few minor fixes * Apply suggestions from code review Co-Authored-By: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com> * Fix suggestions from autolinter * Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * Fix order of messages * Add invalid height error code, check non-nil proof * Fix linter error * Return the underlying error * Tendermint starts at height 1 * Apply suggestions from code review * setup ics20 test suite * add event to MsgRecvPacket * update ibc keeper test to use test suite * Add handshake commands * WIP connection handshake * WIP Connection Handshake * use testsuite * Add cliCtx.WaitForNBlocks * fix connection handshake in progress * fix connection handshake in progress * Add print debugging (old-school) * Add log line * More debugging * Set prove flag to true * More debugging * Use store query * Fix query, hopefully * Fix query path * Hmm * Fix context bug * Generate & return & use consensus state proof * Print debugging * Add debugging * Begin working on the channel creation command * remove submodule prefix from keypath, fix addConnectionToClients to treat nil as empty array * fix OpenConfirm, rm debugging code * WIP channel shake :man_dancing: * WIP channel shake :man_dancing: * WIP channel shake :man_dancing: * WIP channel shake :man_dancing: * WIP channel shake :man_dancing: * WIP channel shake :man_dancing: * WIP channel shake :man_dancing: * Update bound port * Add from flag to ICS 20 commands * Undefine flag * add debug * Uncomment channel message handlers * fix validatebasic identifier failure * Fix printing * add debug code * CLI debugging * fix counterpartyHops, channel handshake working w/o port * Fix compilation error * Push channel query command update * Remove unused code * Add gaiacli keys test * Update error * Add printf * fix token restriciton * comment out port * fix querier to retrieve the next sequence * Alter command to take arguments * Name it packet-sequence * add packet query utils * Use the querier * Packet is JSON * printf the value * fix query packet * fix packet receive in progress * lol * export Packet fields, rename Packet.XXX() -> Packet.GetXXX() * fix route * add debug * comment out port logic from packet.go * token transfer now working * fix client tx * Integrate Evidence Implementation into ICS-02 (#5258) * implement evidence in ics-02 * fix build errors and import cycles * address fede comments * remove unnecessary pubkey and fix init * add tests * Apply suggestions from code review * clean up * finish tendermint tests * complete merge * Add tests for msgs * ICS02 changes * upstream changes * fix * upstream changes * fix cons state * context changes * fix cli tx * upstream changes * upstream changes * upstream changes * upstream changes * more cleanup * Add unit tests for ICS03 (#5275) * add Is() to counterobject * add readme, reflect ICS02 revision * reflect downstream ics * test in progress * add test * in progres * fin rebase * in progress * fin rebase * add CLIObject in progress * cli in progress * add CLIObject * separate testing from tendermint * add key to node * add root and storekey to tests/node, add codec * rm cli/query.go * fix test * fix lint * fix lint * add handler/msgs/client * rm relay * finalize rebase on 23 root/path sep * fix lint, fix syntax * fix querying * extract out context withstore * fix 02-client test * fix 23-commitment test * add query in progress * rm freebase, reformat query * add cli/handler/msg in progress * add cli/msg/handler * add CLIQuery, fix tests * fix golangci * add docs in progre * add comments * add comments * Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * add comments in progress * add comments * fix comment * add comments in progress * recover IntEncoding scheme for integer * add uint tests, don't use codec in custom types * finalize merge * add godoc * add godoc in progress * reformat test * rm XXX * add godoc * modify store * add query * update query.go * update query.go * cli refactor in progress * cli refactor in progress * add Query to boolean.go * fix key * fix cli / merkle test * godoc cleanup * godoc cleanup * godoc cleanup * godoc cleanup * godoc cleanup * fix test * fix client * merge from ics04 branch * merge from ics04 branch * merge from ics04 branch * merge from ics04 branch * fix lint * Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * applying review in progress * apply review - make querier interface * fix dependency * fix dependency * revise querier interface to work both on cli & store * revise querier interface to work both on cli & store * reflect downstream change * fix cli * reflect downstream changes * rm commented lines * address review in progress * address review, rm cleanup/closing * rename Path -> Prefix * Store accessor upstream changes (#5119) * Store accessor upstream changes (#5119) * add comments, reformat merkle querier * rm merkle/utils * ICS 23 upstream changes (#5120) * ICS 23 upstream changes (#5120) * update Value * update test * fix * ICS 02 upstream changes (#5122) * ICS 02 upstream changes (#5122) * ICS 03 upstream changes (#5123) * ICS 03 upstream changes (#5123) * cleanup types and submodule * more cleanup and godocs * remove counterPartyManager/State and cleanup * implement SubmitMisbehaviour and refactor * errors * events * fix test * refactors * WIP refactor ICS03 * remove Mapping * remove store accessors * proposed refactor * remove store accessors from ICS02 * refactor queriers, handler and clean keeper * logger and tx long description * ineffassign * Apply suggestions from code review Co-Authored-By: Jack Zampolin * Apply suggestions from code review Co-Authored-By: Jack Zampolin * remove store accessors * refactor handshake to update it to the latest ICS03 spec * update handler and msgs * add verification functions * update verification * ICS02 module.go * top level x/ibc structure * update connection queries * update connection tx * remove extra files * update expected client keeper and export verification funcs * Update x/ibc/02-client/client/cli/query.go Co-Authored-By: Jack Zampolin * Update x/ibc/02-client/types/tendermint/consensus_state.go Co-Authored-By: Jack Zampolin * address some of the review comments * resolve some TODOs and address comments from review * update connection versioning * minor error updates * minor UX improvements * rename pkg * fixes * refactor ICS23 * cleanup types * rename pkg and fix import * implement batch verification * gosimple suggestion * various fixes; remove legacy tests; remove commitment path query * alias * minor updates from ICS23 * renaming * update verification and rename root funcs * move querier to x/ibc * update query.go to use 'custom/...' query path * add tests * ICS 24 Implementation (#5229) * add validation functions * validate path in ics-23 * address @fede comments * move errors into host package * flatten ICS23 structure * fix ApplyPrefix * updates from ICS23 and ICS24 * msg.ValidateBasic and ADR09 evidence interface * complete types testing * delete empty test file * remove ibc errors from core error package * custom JSON marshaling; msg.ValidateBasic; renaming of variables * minor update * custom JSON marshaling * minor changes on commitment types * R4R - Store consensus state correctly (#5242) * store consensus state correctly * fix client example * update alias * update alias * implement ics25 * update comment * refactor method name * fix file name * add test case * refactor code * refactor code * blocked the consensusState check * refactor code * fix golangci comments * refactor testcase * replace rootMultiStore with simApp * remove unless code * remove unless code & refactor test case * refactor testcase * goimports code * clean up * Add unit tests for ICS04 (#5286) * fix test * Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * applying review in progress * apply review - make querier interface * fix cli errors * fix dependency * fix dependency * reflect method name change * revise querier interface to work both on cli & store * revise querier interface to work both on cli & store * revise querier interface to work both on cli & store * reflect downstream change * fix cli * reflect downstream changes * reflect downstream changes * fix from address in tx cli * fix cli in progress(squash later) * fix cli * remove timeout, add channel cli * fix golangci * fix cli * Clean up * fix mock cli in progress * finalize cleanup, mock cli wip * add cli for mocksend * fix handler * rm commented lines * address review in progress * address review, rm cleanup/closing * rename mock packages * fix interface for gaia * rename Path -> Prefix * Store accessor upstream changes (#5119) * Store accessor upstream changes (#5119) * add comments, reformat merkle querier * rm merkle/utils * ICS 23 upstream changes (#5120) * ICS 23 upstream changes (#5120) * update Value * update test * fix * ICS 02 upstream changes (#5122) * ICS 02 upstream changes (#5122) * ICS 03 upstream changes (#5123) * ICS 03 upstream changes (#5123) * update test * cleanup types and submodule * more cleanup and godocs * remove counterPartyManager/State and cleanup * implement SubmitMisbehaviour and refactor * errors * events * fix test * refactors * WIP refactor ICS03 * remove Mapping * remove store accessors * proposed refactor * remove store accessors from ICS02 * refactor queriers, handler and clean keeper * logger and tx long description * ineffassign * Apply suggestions from code review Co-Authored-By: Jack Zampolin * Apply suggestions from code review Co-Authored-By: Jack Zampolin * remove store accessors * refactor handshake to update it to the latest ICS03 spec * update handler and msgs * add verification functions * update verification * ICS02 module.go * top level x/ibc structure * update connection queries * update connection tx * remove extra files * refactor: remove store accessors, update keeper and types to match spec (WIP) * update handshake and packet * implement packet timeouts * implement send and receive packet * implement packet ACK * update handler * add channel errors * channel querier * update expected client keeper and export verification funcs * ICS 05 Implementation * release port and godocs * Update x/ibc/02-client/client/cli/query.go Co-Authored-By: Jack Zampolin * Update x/ibc/02-client/types/tendermint/consensus_state.go Co-Authored-By: Jack Zampolin * address some of the review comments * resolve some TODOs and address comments from review * update connection versioning * minor error updates * update ICS04 with downstream changes * Implement tx cli actions * add MsgSendPacket handler; msg validation, errors and events * update errors and add port Keeper to ibc Keeper * minor UX improvements * rename pkg * fixes * refactor ICS23 * cleanup types * ICS 5 updates (#5222) * Validate port identifiers * Refactor to static bind * Add comments * Add 'GetPorts' query function * rename pkg and fix import * implement batch verification * gosimple suggestion * various fixes; remove legacy tests; remove commitment path query * alias * minor updates from ICS23 * renaming * update verification and rename root funcs * rm legacy tests; add query proofs support * remove capability key generation and authentication logic * move querier to x/ibc * update query.go to use 'custom/...' query path * add tests * ICS 24 Implementation (#5229) * add validation functions * validate path in ics-23 * address @fede comments * move errors into host package * flatten ICS23 structure * fix ApplyPrefix * updates from ICS23 and ICS24 * msg.ValidateBasic and ADR09 evidence interface * complete types testing * delete empty test file * remove ibc errors from core error package * custom JSON marshaling; msg.ValidateBasic; renaming of variables * minor update * custom JSON marshaling * use host validation for port ids * downstream changes; custom marshal JSON; msg validation, and update errors * update errors and aliases * update msg validation and CLI UX * minor changes on commitment types * fix channel and packet check (#5243) * R4R - Store consensus state correctly (#5242) * store consensus state correctly * fix client example * update alias * update alias * update alias and keeper.GetPort() * authenticate port ID; remove send packet msg from CLI * comment out handlers * add ibc module to simapp * ICS20 implementation (#5204) * add ibc bank mock * modify handler * import channel * add receiving logic * add cli proof handling * modify cli * modify receiver type * modify errcode * optimize codes * add denom prefix when source is true * refactor code * error return * switch ibc antehandler to decorator pattern * fix name/comment * ICS 20 implementation (#5250) * move ics20 code to 20-transfer * clean code * fix compiling error * add transfer module * address ICS20 comments from review * add routing callbacks * clean code * add missing err return * modify err type * modify err type * add supply handling * modify proof type * add comments for msg and packet data * add timeout supply handling * modify module account name * use supply keeper for burn and mint coins * restructure keeper * update alias and module.go * golangci linter * add ics20 handler to IBC handler * update callbacks * update ICS20 escrow address * fix querier routes * fix create client cli * minor updates * ibc querier test * Refactor ibc/mock/bank into ICS 20 (#5264) * Most of code port from mock module to ICS 20 * A few minor fixes * Apply suggestions from code review Co-Authored-By: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com> * Fix suggestions from autolinter * Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * Fix order of messages * Add invalid height error code, check non-nil proof * Fix linter error * Return the underlying error * Tendermint starts at height 1 * Apply suggestions from code review * setup ics20 test suite * add event to MsgRecvPacket * update ibc keeper test to use test suite * Add handshake commands * WIP connection handshake * WIP Connection Handshake * Add cliCtx.WaitForNBlocks * fix connection handshake in progress * fix connection handshake in progress * add channel unit test * add more channel tests * fix channel test * refactor channel test * add capability test for channel * make channel testing work * optimize channel test * delete types/errors.go * modify capability test * uncomment * add msg tests for channel * fix port capability store * fix channel test * use simapp * modify channel test * refactor channel msg test * go fmt * IBC alpha general cleanup (#5291) * remove prefix from keeper; update client queries; address ICS02 comments from @cwgoes * add proof for root query * golangci * remove hardcoded bind port logic * space * WIP: register errors * register errors; make format * use new instead of register; unescape path * golangci * Fix codec issue in ics23 * Modify codec registration style to match previous working state * write port tests * ICS-02: Keeper Tests (#5329) * add keeper tests * fix tendermint tests * Fix proof verification; remove store key prefixes; add additional path validations (#5313) * fix poof verify * minor cleanup * fix tests * remove key prefixes * fix tests * Add ICS20 tests (#5308) * add ics20 test * delete debug * fix ics20 test * revert and modify * optimize test * add ics20 msg test * fix test * add packet tests and more msgs tests * add ReceivePacket and callbacks tests * fix callbacks test * add handler tests for ics20 * fix handler tests * minor cleanup * test all positive amounts * update test suite NotNil to Error * fix ics20 tests * expected error * Add IBC REST endpoints (#5310) * add rest framework * add rest endpoints for ibc connection * add rest endpoints for ibc client * add rest endpoints for ibc channel * modify ibc rest api * add rest endpoints for ibc transfer * fix query route * fix receive packet * fix query client state api * use sub module name instead of icsxx * use const for prove judgement * modify ibc rest api * add api docs to swagger * add ibc config * fix proof path in swagger * return query result proof * update swagger docs * parse prove * clean up * fix ibc rest api and swagger docs * fix host validate * fix typo * add submitMisbehaviour error response in swagger * fix rest queryRoot and swagger doc * add response comments for each REST functions * fix rest function comments * fix IBC proofs (#5351) * fix ICS02 proofs * fix ICS03 proofs * fix ICS04 proofs * fix ICS20 proofs * make format * fix build; comment handshakes * ICS-2 Implement Misbehavior (#5321) * ibc client evidence route * split evidence from misbehaviour * clean up client events * test misbehaviour and evidence * remove comments * remove frozen comments from demo * Update x/ibc/02-client/types/tendermint/evidence_test.go Co-Authored-By: Aditya * change evidence to detect malicious chain * remove unnecessary sort * fix evidence and persist committers to check misbehaviour * minor fixes and remove incorrect tests * add evidence tests * remove debug statements * cleanup evidence test * start misbehaviour tests * fix nondeterministic bug * add same height and next height checks in misbehaviour * fix bugs * apply fede review suggestions * finish code review changes * fix GetCommitter and write keeper-level misbehaviour tests * remove incorrect special case checking * save * final fixes * save * fix conflict * fix conflicts and add back submit misbehaviour msg * Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * save * add godocs and fix test * fix test panics in other modules * Update x/ibc/02-client/keeper/client.go Co-Authored-By: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com> * add back aliases * Misc ibc fixes (#5357) * fix cli ExactArgs * remove full handshakes * rm dup flag * fix error handling * Implement Query Committer methods in ICS-02 (#5402) * add query methods for committers in ICS-02 * Update x/ibc/02-client/keeper/keeper.go * add REST docs * fix test * IBC UX improvements (#5364) * ICS02 iterators * ICS03 iterators * ICS04 iterators * ICS02 client updates * CLI connections * setup queriers * clean up queriers * add tests * IBC top-level querier tests * update ICS02 keys * update ICS03 keys * make format * update ICS04 keys * fix a few tests * fix ICS20 tests * update keys * fix ICS02 queries (#5425) * fix CLI JSON param unmarshaling (#5431) * Fix inconsistent string lookup functions (#5437) * fix inconsistent string lookup functions * test client type and ordering * channel and connection state tests * address golangcibot comments * fix test * Update x/ibc error handling (#5462) * Merge PR #5428: Add mod, exponentiation for uint * Modified examples in distribution module (#5441) * Merge PR #5442: Remove of the client/alias.go * Merge PR #5445: Mock rpcclient in tests for votes pagination * Merge PR #5435: Added iterator that allows to read only requested values * Merge PR #5427: Remove code duplication in x/auth/client/cli * Merge PR #5421: Refactor Error Handling * update x/ibc error handling * update ICS24 and ICS02 errors * ICS03, ICS23 and common errors * updates from master and errors from ICS04 * build * fix ics20 tests * fix tests * golangcibot fixes Co-authored-by: Kevin Davis Co-authored-by: kaustubhkapatral <54210167+kaustubhkapatral@users.noreply.github.com> Co-authored-by: Ferenc Fabian Co-authored-by: Dmitry Shulyak Co-authored-by: Alessio Treglia Co-authored-by: Alexander Bezobchuk * ADR 015 Implementation (#5401) * implement in progress * rm unneccessary change under simapp, modify baseapp for codetxbreak * fix test in progress * fix test error * fix golangci * address minor comments * mv antehandler to ante/, address comments * fix GetCommitment => GetData, fix syntax * checkout types/ to ibc-alpha * checkout to origin/ibc-alpha * fix branch problem * fix syntax error * recover PacketI interface * mv recvpacket rest from 20 -> 04 * address minor comments * Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * rm wrong files * Apply suggestions from code review * PacketDataI field is now named, not embed * add acknowledgement hashing * rename finalization functiosn * Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * Rename GetCommitment() to GetBytes() * Add recv sequence incr to RecvPacket() * Revert but where is PacketExecuted() called * Call PacketExecuted(), check seq in RecvPacket() * The port is called "bank" * Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * Update simapp/app.go Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * Remove omitempty * Add godoc * Move events * set ProofVerificationDecorator on AnteHandler * Apply suggestions from code review Co-Authored-By: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com> * format Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Co-authored-by: Christopher Goes Co-authored-by: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com> * IBC alpha * ICS 23 Implementation (#4515) * add mapping * rm unused mapping/*, rm interfaces * rm unused code * mv mapping -> state, rm x/ibc * rm GetIfExists * add key * rm custom encoding/decoding in enum/bool * fix lint * rm tests * add commitment * newtyped remote values * newtyped context * revert context newtype * add README, keypath * reflect downstream ics * add merkle * add test for proving * soft coded root keypath * add update * remove RootUpdate * separate keypath and keuprefix * add codec * separate root/path * add path to codec * add docs in progre * add comments * add comments * Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * add comments in progress * add comments * fix comment * add comments in progress * recover IntEncoding scheme for integer * add uint tests, don't use codec in custom types * finalize merge * add godoc * reformat test * rm XXX * add godoc * add query * update query.go * update query.go * add Query to boolean.go * fix key * godoc cleanup * godoc cleanup * godoc cleanup * godoc cleanup * godoc cleanup * merge from ics04 branch * merge from ics04 branch * fix lint * Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * applying review in progress * apply review - make querier interface * fix dependency * revise querier interface to work both on cli & store * rm commented lines * rename Path -> Prefix * Store accessor upstream changes (#5119) * Store accessor upstream changes (#5119) * add comments, reformat merkle querier * rm merkle/utils * ICS 23 upstream changes (#5120) * ICS 23 upstream changes (#5120) * update Value * remove Mapping * remove store accessors * refactor ICS23 * cleanup types * implement batch verification * gosimple suggestion * alias * add tests * ICS 24 Implementation (#5229) * add validation functions * validate path in ics-23 * address @fede comments * move errors into host package * flatten ICS23 structure * fix ApplyPrefix * complete types testing * delete empty test file * remove ibc errors from core error package * start batch-verify tests * minor changes on commitment types * use testsuite * upstream changes * context changes * ICS 02 Implementation (#4516) * add mapping * rm unused mapping/*, rm interfaces * rm unused code * mv mapping -> state, rm x/ibc * rm GetIfExists * add key * rm custom encoding/decoding in enum/bool * fix lint * rm tests * add commitment * newtyped remote values * newtyped context * revert context newtype * add README, keypath * reflect downstream ics * add merkle * add test for proving * soft coded root keypath * add update * remove RootUpdate * separate keypath and keuprefix * add codec * separate root/path * add path to codec * add client * add counterpartymanager * fix manager * add Is() to counterobject * add readme, reflect ICS02 revision * reflect downstream ics * test in progress * add test * in progres * fin rebase * in progress * fin rebase * add CLIObject in progress * cli in progress * add CLIObject * separate testing from tendermint * add key to node * add root and storekey to tests/node, add codec * rm cli/query.go * fix test * fix lint * fix lint * add handler/msgs/client * rm relay * finalize rebase on 23 root/path sep * fix lint, fix syntax * rm freebase, reformat query * add docs in progre * add comments * add comments * Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * add comments in progress * add comments * fix comment * add comments in progress * recover IntEncoding scheme for integer * add uint tests, don't use codec in custom types * finalize merge * add godoc * add godoc in progress * reformat test * rm XXX * add godoc * modify store * add query * update query.go * update query.go * cli refactor in progress * cli refactor in progress * add Query to boolean.go * fix key * fix cli / merkle test * godoc cleanup * godoc cleanup * godoc cleanup * godoc cleanup * godoc cleanup * merge from ics04 branch * merge from ics04 branch * merge from ics04 branch * fix lint * Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * applying review in progress * apply review - make querier interface * fix dependency * fix dependency * revise querier interface to work both on cli & store * revise querier interface to work both on cli & store * reflect downstream change * fix cli * rm commented lines * address review in progress * rename Path -> Prefix * Store accessor upstream changes (#5119) * Store accessor upstream changes (#5119) * add comments, reformat merkle querier * rm merkle/utils * ICS 23 upstream changes (#5120) * ICS 23 upstream changes (#5120) * update Value * update test * fix * ICS 02 upstream changes (#5122) * ICS 02 upstream changes (#5122) * cleanup types and submodule * more cleanup and godocs * remove counterPartyManager/State and cleanup * implement SubmitMisbehaviour and refactor * errors * events * fix test * refactors * remove Mapping * remove store accessors * proposed refactor * remove store accessors from ICS02 * refactor queriers, handler and clean keeper * logger and tx long description * ineffassign * Apply suggestions from code review Co-Authored-By: Jack Zampolin * Apply suggestions from code review Co-Authored-By: Jack Zampolin * add verification functions * ICS02 module.go * top level x/ibc structure * Update x/ibc/02-client/client/cli/query.go Co-Authored-By: Jack Zampolin * Update x/ibc/02-client/types/tendermint/consensus_state.go Co-Authored-By: Jack Zampolin * address some of the review comments * minor UX improvements * rename pkg * fixes * refactor ICS23 * cleanup types * implement batch verification * gosimple suggestion * various fixes; remove legacy tests; remove commitment path query * alias * minor updates from ICS23 * renaming * update verification and rename root funcs * move querier to x/ibc * update query.go to use 'custom/...' query path * add tests * ICS 24 Implementation (#5229) * add validation functions * validate path in ics-23 * address @fede comments * move errors into host package * flatten ICS23 structure * fix ApplyPrefix * updates from ICS23 and ICS24 * msg.ValidateBasic and ADR09 evidence interface * complete types testing * delete empty test file * remove ibc errors from core error package * custom JSON marshaling * start batch-verify tests * minor changes on commitment types * R4R - Store consensus state correctly (#5242) * store consensus state correctly * fix client example * update alias * use testsuite * Integrate Evidence Implementation into ICS-02 (#5258) * implement evidence in ics-02 * fix build errors and import cycles * address fede comments * remove unnecessary pubkey and fix init * add tests * finish tendermint tests * complete merge * Add tests for msgs * upstream changes * fix * upstream changes * fix cons state * context changes * ICS 03 Implementation (#4517) * add test * in progres * fin rebase * in progress * fin rebase * add CLIObject in progress * cli in progress * add CLIObject * separate testing from tendermint * add key to node * add root and storekey to tests/node, add codec * rm cli/query.go * fix test * fix lint * fix lint * add handler/msgs/client * rm relay * finalize rebase on 23 root/path sep * fix lint, fix syntax * fix querying * extract out context withstore * fix 02-client test * fix 23-commitment test * add query in progress * rm freebase, reformat query * add cli/handler/msg in progress * add cli/msg/handler * add CLIQuery, fix tests * fix golangci * add docs in progre * add comments * add comments * Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * add comments in progress * add comments * fix comment * add comments in progress * recover IntEncoding scheme for integer * add uint tests, don't use codec in custom types * finalize merge * add godoc * add godoc in progress * reformat test * rm XXX * add godoc * modify store * add query * update query.go * update query.go * cli refactor in progress * cli refactor in progress * add Query to boolean.go * fix key * fix cli / merkle test * godoc cleanup * godoc cleanup * godoc cleanup * godoc cleanup * godoc cleanup * fix test * fix client * merge from ics04 branch * merge from ics04 branch * merge from ics04 branch * merge from ics04 branch * fix lint * Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * applying review in progress * apply review - make querier interface * fix dependency * fix dependency * revise querier interface to work both on cli & store * revise querier interface to work both on cli & store * reflect downstream change * fix cli * reflect downstream changes * rm commented lines * address review in progress * address review, rm cleanup/closing * rename Path -> Prefix * Store accessor upstream changes (#5119) * Store accessor upstream changes (#5119) * add comments, reformat merkle querier * rm merkle/utils * ICS 23 upstream changes (#5120) * ICS 23 upstream changes (#5120) * update Value * update test * fix * ICS 02 upstream changes (#5122) * ICS 02 upstream changes (#5122) * ICS 03 upstream changes (#5123) * ICS 03 upstream changes (#5123) * cleanup types and submodule * more cleanup and godocs * remove counterPartyManager/State and cleanup * implement SubmitMisbehaviour and refactor * errors * events * fix test * refactors * WIP refactor ICS03 * remove Mapping * remove store accessors * proposed refactor * remove store accessors from ICS02 * refactor queriers, handler and clean keeper * logger and tx long description * ineffassign * Apply suggestions from code review Co-Authored-By: Jack Zampolin * Apply suggestions from code review Co-Authored-By: Jack Zampolin * remove store accessors * refactor handshake to update it to the latest ICS03 spec * update handler and msgs * add verification functions * update verification * ICS02 module.go * top level x/ibc structure * update connection queries * update connection tx * remove extra files * update expected client keeper and export verification funcs * Update x/ibc/02-client/client/cli/query.go Co-Authored-By: Jack Zampolin * Update x/ibc/02-client/types/tendermint/consensus_state.go Co-Authored-By: Jack Zampolin * address some of the review comments * resolve some TODOs and address comments from review * update connection versioning * minor error updates * minor UX improvements * rename pkg * fixes * refactor ICS23 * cleanup types * rename pkg and fix import * implement batch verification * gosimple suggestion * various fixes; remove legacy tests; remove commitment path query * alias * minor updates from ICS23 * renaming * update verification and rename root funcs * move querier to x/ibc * update query.go to use 'custom/...' query path * add tests * ICS 24 Implementation (#5229) * add validation functions * validate path in ics-23 * address @fede comments * move errors into host package * flatten ICS23 structure * fix ApplyPrefix * updates from ICS23 and ICS24 * msg.ValidateBasic and ADR09 evidence interface * complete types testing * delete empty test file * remove ibc errors from core error package * custom JSON marshaling; msg.ValidateBasic; renaming of variables * minor update * custom JSON marshaling * start batch-verify tests * minor changes on commitment types * R4R - Store consensus state correctly (#5242) * store consensus state correctly * fix client example * update alias * update alias * use testsuite * Integrate Evidence Implementation into ICS-02 (#5258) * implement evidence in ics-02 * fix build errors and import cycles * address fede comments * remove unnecessary pubkey and fix init * add tests * finish tendermint tests * complete merge * Add tests for msgs * upstream changes * fix * upstream changes * fix cons state * context changes * fix cli tx * upstream changes * fix * ICS 05 implementation (#5193) * fix lint * fix lint * add handler/msgs/client * rm relay * finalize rebase on 23 root/path sep * fix lint, fix syntax * fix querying * extract out context withstore * fix 02-client test * fix 23-commitment test * add query in progress * rm freebase, reformat query * add cli/handler/msg in progress * add cli/msg/handler * add CLIQuery, fix tests * fix golangci * add docs in progre * add comments * add comments * Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * add comments in progress * add comments * fix comment * add comments in progress * recover IntEncoding scheme for integer * add uint tests, don't use codec in custom types * finalize merge * add godoc * add godoc in progress * reformat test * rm XXX * add godoc * modify store * add query * update query.go * update query.go * cli refactor in progress * cli refactor in progress * add Query to boolean.go * fix key * fix cli / merkle test * godoc cleanup * godoc cleanup * godoc cleanup * godoc cleanup * godoc cleanup * fix test * fix client * merge from ics04 branch * merge from ics04 branch * merge from ics04 branch * merge from ics04 branch * fix lint * Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * applying review in progress * apply review - make querier interface * fix dependency * fix dependency * revise querier interface to work both on cli & store * revise querier interface to work both on cli & store * reflect downstream change * fix cli * reflect downstream changes * rm commented lines * address review in progress * address review, rm cleanup/closing * rename Path -> Prefix * Store accessor upstream changes (#5119) * Store accessor upstream changes (#5119) * add comments, reformat merkle querier * rm merkle/utils * ICS 23 upstream changes (#5120) * ICS 23 upstream changes (#5120) * update Value * update test * fix * ICS 02 upstream changes (#5122) * ICS 02 upstream changes (#5122) * ICS 03 upstream changes (#5123) * ICS 03 upstream changes (#5123) * cleanup types and submodule * more cleanup and godocs * remove counterPartyManager/State and cleanup * implement SubmitMisbehaviour and refactor * errors * events * fix test * refactors * WIP refactor ICS03 * remove Mapping * remove store accessors * proposed refactor * remove store accessors from ICS02 * refactor queriers, handler and clean keeper * logger and tx long description * ineffassign * Apply suggestions from code review Co-Authored-By: Jack Zampolin * Apply suggestions from code review Co-Authored-By: Jack Zampolin * remove store accessors * refactor handshake to update it to the latest ICS03 spec * update handler and msgs * add verification functions * update verification * ICS02 module.go * top level x/ibc structure * update connection queries * update connection tx * remove extra files * update expected client keeper and export verification funcs * ICS 05 Implementation * release port and godocs * Update x/ibc/02-client/client/cli/query.go Co-Authored-By: Jack Zampolin * Update x/ibc/02-client/types/tendermint/consensus_state.go Co-Authored-By: Jack Zampolin * address some of the review comments * resolve some TODOs and address comments from review * update connection versioning * minor error updates * update errors and add port Keeper to ibc Keeper * minor UX improvements * rename pkg * fixes * refactor ICS23 * cleanup types * ICS 5 updates (#5222) * Validate port identifiers * Refactor to static bind * Add comments * Add 'GetPorts' query function * rename pkg and fix import * implement batch verification * gosimple suggestion * various fixes; remove legacy tests; remove commitment path query * alias * minor updates from ICS23 * renaming * update verification and rename root funcs * move querier to x/ibc * update query.go to use 'custom/...' query path * add tests * ICS 24 Implementation (#5229) * add validation functions * validate path in ics-23 * address @fede comments * move errors into host package * flatten ICS23 structure * fix ApplyPrefix * updates from ICS23 and ICS24 * msg.ValidateBasic and ADR09 evidence interface * complete types testing * delete empty test file * remove ibc errors from core error package * custom JSON marshaling; msg.ValidateBasic; renaming of variables * minor update * custom JSON marshaling * use host validation for port ids * start batch-verify tests * minor changes on commitment types * R4R - Store consensus state correctly (#5242) * store consensus state correctly * fix client example * update alias * update alias * update alias and keeper.GetPort() * use testsuite * Integrate Evidence Implementation into ICS-02 (#5258) * implement evidence in ics-02 * fix build errors and import cycles * address fede comments * remove unnecessary pubkey and fix init * add tests * finish tendermint tests * complete merge * Add tests for msgs * upstream changes * fix * upstream changes * fix cons state * context changes * fix cli tx * upstream changes * upstream changes * ICS 04 Implementation (#4548) * merge from ics04 branch * merge from ics04 branch * fix lint * add port * fix test * add mocks * fix connid -> portid in handshake.go * add mock * add ibc module.go, finalize mock * add keeper * add StoreKey const * fix test * Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * applying review in progress * apply review - make querier interface * fix cli errors * fix dependency * fix dependency * reflect method name change * revise querier interface to work both on cli & store * revise querier interface to work both on cli & store * revise querier interface to work both on cli & store * reflect downstream change * fix cli * reflect downstream changes * reflect downstream changes * fix from address in tx cli * fix cli in progress(squash later) * fix cli * remove timeout, add channel cli * fix golangci * fix cli * Clean up * fix mock cli in progress * finalize cleanup, mock cli wip * add cli for mocksend * fix handler * rm commented lines * address review in progress * address review, rm cleanup/closing * rename mock packages * fix interface for gaia * rename Path -> Prefix * Store accessor upstream changes (#5119) * Store accessor upstream changes (#5119) * add comments, reformat merkle querier * rm merkle/utils * ICS 23 upstream changes (#5120) * ICS 23 upstream changes (#5120) * update Value * update test * fix * ICS 02 upstream changes (#5122) * ICS 02 upstream changes (#5122) * ICS 03 upstream changes (#5123) * ICS 03 upstream changes (#5123) * update test * cleanup types and submodule * more cleanup and godocs * remove counterPartyManager/State and cleanup * implement SubmitMisbehaviour and refactor * errors * events * fix test * refactors * WIP refactor ICS03 * remove Mapping * remove store accessors * proposed refactor * remove store accessors from ICS02 * refactor queriers, handler and clean keeper * logger and tx long description * ineffassign * Apply suggestions from code review Co-Authored-By: Jack Zampolin * Apply suggestions from code review Co-Authored-By: Jack Zampolin * remove store accessors * refactor handshake to update it to the latest ICS03 spec * update handler and msgs * add verification functions * update verification * ICS02 module.go * top level x/ibc structure * update connection queries * update connection tx * remove extra files * refactor: remove store accessors, update keeper and types to match spec (WIP) * update handshake and packet * implement packet timeouts * implement send and receive packet * implement packet ACK * update handler * add channel errors * channel querier * update expected client keeper and export verification funcs * ICS 05 Implementation * release port and godocs * Update x/ibc/02-client/client/cli/query.go Co-Authored-By: Jack Zampolin * Update x/ibc/02-client/types/tendermint/consensus_state.go Co-Authored-By: Jack Zampolin * address some of the review comments * resolve some TODOs and address comments from review * update connection versioning * minor error updates * update ICS04 with downstream changes * Implement tx cli actions * add MsgSendPacket handler; msg validation, errors and events * update errors and add port Keeper to ibc Keeper * minor UX improvements * rename pkg * fixes * refactor ICS23 * cleanup types * ICS 5 updates (#5222) * Validate port identifiers * Refactor to static bind * Add comments * Add 'GetPorts' query function * rename pkg and fix import * implement batch verification * gosimple suggestion * various fixes; remove legacy tests; remove commitment path query * alias * minor updates from ICS23 * renaming * update verification and rename root funcs * rm legacy tests; add query proofs support * remove capability key generation and authentication logic * move querier to x/ibc * update query.go to use 'custom/...' query path * add tests * ICS 24 Implementation (#5229) * add validation functions * validate path in ics-23 * address @fede comments * move errors into host package * flatten ICS23 structure * fix ApplyPrefix * updates from ICS23 and ICS24 * msg.ValidateBasic and ADR09 evidence interface * complete types testing * delete empty test file * remove ibc errors from core error package * custom JSON marshaling; msg.ValidateBasic; renaming of variables * minor update * custom JSON marshaling * use host validation for port ids * downstream changes; custom marshal JSON; msg validation, and update errors * update errors and aliases * start batch-verify tests * update msg validation and CLI UX * minor changes on commitment types * fix channel and packet check (#5243) * R4R - Store consensus state correctly (#5242) * store consensus state correctly * fix client example * update alias * update alias * update alias and keeper.GetPort() * authenticate port ID; remove send packet msg from CLI * comment out handlers * use testsuite * Integrate Evidence Implementation into ICS-02 (#5258) * implement evidence in ics-02 * fix build errors and import cycles * address fede comments * remove unnecessary pubkey and fix init * add tests * finish tendermint tests * complete merge * Add tests for msgs * upstream changes * fix * upstream changes * fix cons state * context changes * fix cli tx * upstream changes * upstream changes * upstream changes * IBC v1.0.0 (#5245) * applying review in progress * apply review - make querier interface * fix cli errors * fix dependency * fix dependency * reflect method name change * revise querier interface to work both on cli & store * revise querier interface to work both on cli & store * revise querier interface to work both on cli & store * reflect downstream change * fix cli * reflect downstream changes * reflect downstream changes * fix from address in tx cli * fix cli in progress(squash later) * fix cli * remove timeout, add channel cli * fix golangci * fix cli * Clean up * fix mock cli in progress * finalize cleanup, mock cli wip * add cli for mocksend * fix handler * rm commented lines * address review in progress * address review, rm cleanup/closing * rename mock packages * fix interface for gaia * rename Path -> Prefix * Store accessor upstream changes (#5119) * Store accessor upstream changes (#5119) * add comments, reformat merkle querier * rm merkle/utils * ICS 23 upstream changes (#5120) * ICS 23 upstream changes (#5120) * update Value * update test * fix * ICS 02 upstream changes (#5122) * ICS 02 upstream changes (#5122) * ICS 03 upstream changes (#5123) * ICS 03 upstream changes (#5123) * update test * cleanup types and submodule * more cleanup and godocs * remove counterPartyManager/State and cleanup * implement SubmitMisbehaviour and refactor * errors * events * fix test * refactors * WIP refactor ICS03 * remove Mapping * remove store accessors * proposed refactor * remove store accessors from ICS02 * refactor queriers, handler and clean keeper * logger and tx long description * ineffassign * Apply suggestions from code review Co-Authored-By: Jack Zampolin * Apply suggestions from code review Co-Authored-By: Jack Zampolin * remove store accessors * refactor handshake to update it to the latest ICS03 spec * update handler and msgs * add verification functions * update verification * ICS02 module.go * top level x/ibc structure * update connection queries * update connection tx * remove extra files * refactor: remove store accessors, update keeper and types to match spec (WIP) * update handshake and packet * implement packet timeouts * implement send and receive packet * implement packet ACK * update handler * add channel errors * channel querier * update expected client keeper and export verification funcs * ICS 05 Implementation * release port and godocs * Update x/ibc/02-client/client/cli/query.go Co-Authored-By: Jack Zampolin * Update x/ibc/02-client/types/tendermint/consensus_state.go Co-Authored-By: Jack Zampolin * address some of the review comments * resolve some TODOs and address comments from review * update connection versioning * minor error updates * update ICS04 with downstream changes * Implement tx cli actions * add MsgSendPacket handler; msg validation, errors and events * update errors and add port Keeper to ibc Keeper * minor UX improvements * rename pkg * fixes * refactor ICS23 * cleanup types * ICS 5 updates (#5222) * Validate port identifiers * Refactor to static bind * Add comments * Add 'GetPorts' query function * rename pkg and fix import * implement batch verification * gosimple suggestion * various fixes; remove legacy tests; remove commitment path query * alias * minor updates from ICS23 * renaming * update verification and rename root funcs * rm legacy tests; add query proofs support * remove capability key generation and authentication logic * move querier to x/ibc * update query.go to use 'custom/...' query path * add tests * ICS 24 Implementation (#5229) * add validation functions * validate path in ics-23 * address @fede comments * move errors into host package * flatten ICS23 structure * fix ApplyPrefix * updates from ICS23 and ICS24 * msg.ValidateBasic and ADR09 evidence interface * complete types testing * delete empty test file * remove ibc errors from core error package * custom JSON marshaling; msg.ValidateBasic; renaming of variables * minor update * custom JSON marshaling * use host validation for port ids * downstream changes; custom marshal JSON; msg validation, and update errors * update errors and aliases * start batch-verify tests * update msg validation and CLI UX * minor changes on commitment types * fix channel and packet check (#5243) * R4R - Store consensus state correctly (#5242) * store consensus state correctly * fix client example * update alias * update alias * update alias and keeper.GetPort() * authenticate port ID; remove send packet msg from CLI * comment out handlers * add ibc module to simapp * ICS20 implementation (#5204) * add ibc bank mock * modify handler * import channel * add receiving logic * add cli proof handling * modify cli * modify receiver type * modify errcode * optimize codes * add denom prefix when source is true * refactor code * error return * switch ibc antehandler to decorator pattern * fix name/comment * ICS 20 implementation (#5250) * move ics20 code to 20-transfer * clean code * fix compiling error * add transfer module * address ICS20 comments from review * add routing callbacks * clean code * add missing err return * modify err type * modify err type * add supply handling * modify proof type * add comments for msg and packet data * add timeout supply handling * modify module account name * use supply keeper for burn and mint coins * restructure keeper * update alias and module.go * golangci linter * add ics20 handler to IBC handler * update callbacks * update ICS20 escrow address * fix querier routes * fix create client cli * minor updates * ibc querier test * Refactor ibc/mock/bank into ICS 20 (#5264) * Most of code port from mock module to ICS 20 * A few minor fixes * Apply suggestions from code review Co-Authored-By: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com> * Fix suggestions from autolinter * Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * Fix order of messages * Add invalid height error code, check non-nil proof * Fix linter error * Return the underlying error * Tendermint starts at height 1 * Apply suggestions from code review * setup ics20 test suite * add event to MsgRecvPacket * update ibc keeper test to use test suite * Add handshake commands * WIP connection handshake * WIP Connection Handshake * use testsuite * Add cliCtx.WaitForNBlocks * fix connection handshake in progress * fix connection handshake in progress * Integrate Evidence Implementation into ICS-02 (#5258) * implement evidence in ics-02 * fix build errors and import cycles * address fede comments * remove unnecessary pubkey and fix init * add tests * finish tendermint tests * complete merge * Add tests for msgs * upstream changes * fix * upstream changes * fix cons state * context changes * fix cli tx * upstream changes * upstream changes * upstream changes * upstream changes * IBC demo fixes (#5267) * WIP refactor ICS03 * remove Mapping * remove store accessors * proposed refactor * remove store accessors from ICS02 * refactor queriers, handler and clean keeper * logger and tx long description * ineffassign * Apply suggestions from code review Co-Authored-By: Jack Zampolin * Apply suggestions from code review Co-Authored-By: Jack Zampolin * remove store accessors * refactor handshake to update it to the latest ICS03 spec * update handler and msgs * add verification functions * update verification * ICS02 module.go * top level x/ibc structure * update connection queries * update connection tx * remove extra files * refactor: remove store accessors, update keeper and types to match spec (WIP) * update handshake and packet * implement packet timeouts * implement send and receive packet * implement packet ACK * update handler * add channel errors * channel querier * update expected client keeper and export verification funcs * ICS 05 Implementation * release port and godocs * Update x/ibc/02-client/client/cli/query.go Co-Authored-By: Jack Zampolin * Update x/ibc/02-client/types/tendermint/consensus_state.go Co-Authored-By: Jack Zampolin * address some of the review comments * resolve some TODOs and address comments from review * update connection versioning * minor error updates * update ICS04 with downstream changes * Implement tx cli actions * add MsgSendPacket handler; msg validation, errors and events * update errors and add port Keeper to ibc Keeper * minor UX improvements * rename pkg * fixes * refactor ICS23 * cleanup types * ICS 5 updates (#5222) * Validate port identifiers * Refactor to static bind * Add comments * Add 'GetPorts' query function * rename pkg and fix import * implement batch verification * gosimple suggestion * various fixes; remove legacy tests; remove commitment path query * alias * minor updates from ICS23 * renaming * update verification and rename root funcs * rm legacy tests; add query proofs support * remove capability key generation and authentication logic * move querier to x/ibc * update query.go to use 'custom/...' query path * add tests * ICS 24 Implementation (#5229) * add validation functions * validate path in ics-23 * address @fede comments * move errors into host package * flatten ICS23 structure * fix ApplyPrefix * updates from ICS23 and ICS24 * msg.ValidateBasic and ADR09 evidence interface * complete types testing * delete empty test file * remove ibc errors from core error package * custom JSON marshaling; msg.ValidateBasic; renaming of variables * minor update * custom JSON marshaling * use host validation for port ids * downstream changes; custom marshal JSON; msg validation, and update errors * update errors and aliases * start batch-verify tests * update msg validation and CLI UX * minor changes on commitment types * fix channel and packet check (#5243) * R4R - Store consensus state correctly (#5242) * store consensus state correctly * fix client example * update alias * update alias * update alias and keeper.GetPort() * authenticate port ID; remove send packet msg from CLI * comment out handlers * add ibc module to simapp * ICS20 implementation (#5204) * add ibc bank mock * modify handler * import channel * add receiving logic * add cli proof handling * modify cli * modify receiver type * modify errcode * optimize codes * add denom prefix when source is true * refactor code * error return * switch ibc antehandler to decorator pattern * fix name/comment * ICS 20 implementation (#5250) * move ics20 code to 20-transfer * clean code * fix compiling error * add transfer module * address ICS20 comments from review * add routing callbacks * clean code * add missing err return * modify err type * modify err type * add supply handling * modify proof type * add comments for msg and packet data * add timeout supply handling * modify module account name * use supply keeper for burn and mint coins * restructure keeper * update alias and module.go * golangci linter * add ics20 handler to IBC handler * update callbacks * update ICS20 escrow address * fix querier routes * fix create client cli * minor updates * ibc querier test * Refactor ibc/mock/bank into ICS 20 (#5264) * Most of code port from mock module to ICS 20 * A few minor fixes * Apply suggestions from code review Co-Authored-By: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com> * Fix suggestions from autolinter * Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * Fix order of messages * Add invalid height error code, check non-nil proof * Fix linter error * Return the underlying error * Tendermint starts at height 1 * Apply suggestions from code review * setup ics20 test suite * add event to MsgRecvPacket * update ibc keeper test to use test suite * Add handshake commands * WIP connection handshake * WIP Connection Handshake * use testsuite * Add cliCtx.WaitForNBlocks * fix connection handshake in progress * fix connection handshake in progress * Add print debugging (old-school) * Add log line * More debugging * Set prove flag to true * More debugging * Use store query * Fix query, hopefully * Fix query path * Hmm * Fix context bug * Generate & return & use consensus state proof * Print debugging * Add debugging * Begin working on the channel creation command * remove submodule prefix from keypath, fix addConnectionToClients to treat nil as empty array * fix OpenConfirm, rm debugging code * WIP channel shake :man_dancing: * WIP channel shake :man_dancing: * WIP channel shake :man_dancing: * WIP channel shake :man_dancing: * WIP channel shake :man_dancing: * WIP channel shake :man_dancing: * WIP channel shake :man_dancing: * Update bound port * Add from flag to ICS 20 commands * Undefine flag * add debug * Uncomment channel message handlers * fix validatebasic identifier failure * Fix printing * add debug code * CLI debugging * fix counterpartyHops, channel handshake working w/o port * Fix compilation error * Push channel query command update * Remove unused code * Add gaiacli keys test * Update error * Add printf * fix token restriciton * comment out port * fix querier to retrieve the next sequence * Alter command to take arguments * Name it packet-sequence * add packet query utils * Use the querier * Packet is JSON * printf the value * fix query packet * fix packet receive in progress * lol * export Packet fields, rename Packet.XXX() -> Packet.GetXXX() * fix route * add debug * comment out port logic from packet.go * token transfer now working * fix client tx * Integrate Evidence Implementation into ICS-02 (#5258) * implement evidence in ics-02 * fix build errors and import cycles * address fede comments * remove unnecessary pubkey and fix init * add tests * Apply suggestions from code review * clean up * finish tendermint tests * complete merge * Add tests for msgs * ICS02 changes * upstream changes * fix * upstream changes * fix cons state * context changes * fix cli tx * upstream changes * upstream changes * upstream changes * upstream changes * more cleanup * Add unit tests for ICS03 (#5275) * add Is() to counterobject * add readme, reflect ICS02 revision * reflect downstream ics * test in progress * add test * in progres * fin rebase * in progress * fin rebase * add CLIObject in progress * cli in progress * add CLIObject * separate testing from tendermint * add key to node * add root and storekey to tests/node, add codec * rm cli/query.go * fix test * fix lint * fix lint * add handler/msgs/client * rm relay * finalize rebase on 23 root/path sep * fix lint, fix syntax * fix querying * extract out context withstore * fix 02-client test * fix 23-commitment test * add query in progress * rm freebase, reformat query * add cli/handler/msg in progress * add cli/msg/handler * add CLIQuery, fix tests * fix golangci * add docs in progre * add comments * add comments * Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * add comments in progress * add comments * fix comment * add comments in progress * recover IntEncoding scheme for integer * add uint tests, don't use codec in custom types * finalize merge * add godoc * add godoc in progress * reformat test * rm XXX * add godoc * modify store * add query * update query.go * update query.go * cli refactor in progress * cli refactor in progress * add Query to boolean.go * fix key * fix cli / merkle test * godoc cleanup * godoc cleanup * godoc cleanup * godoc cleanup * godoc cleanup * fix test * fix client * merge from ics04 branch * merge from ics04 branch * merge from ics04 branch * merge from ics04 branch * fix lint * Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * applying review in progress * apply review - make querier interface * fix dependency * fix dependency * revise querier interface to work both on cli & store * revise querier interface to work both on cli & store * reflect downstream change * fix cli * reflect downstream changes * rm commented lines * address review in progress * address review, rm cleanup/closing * rename Path -> Prefix * Store accessor upstream changes (#5119) * Store accessor upstream changes (#5119) * add comments, reformat merkle querier * rm merkle/utils * ICS 23 upstream changes (#5120) * ICS 23 upstream changes (#5120) * update Value * update test * fix * ICS 02 upstream changes (#5122) * ICS 02 upstream changes (#5122) * ICS 03 upstream changes (#5123) * ICS 03 upstream changes (#5123) * cleanup types and submodule * more cleanup and godocs * remove counterPartyManager/State and cleanup * implement SubmitMisbehaviour and refactor * errors * events * fix test * refactors * WIP refactor ICS03 * remove Mapping * remove store accessors * proposed refactor * remove store accessors from ICS02 * refactor queriers, handler and clean keeper * logger and tx long description * ineffassign * Apply suggestions from code review Co-Authored-By: Jack Zampolin * Apply suggestions from code review Co-Authored-By: Jack Zampolin * remove store accessors * refactor handshake to update it to the latest ICS03 spec * update handler and msgs * add verification functions * update verification * ICS02 module.go * top level x/ibc structure * update connection queries * update connection tx * remove extra files * update expected client keeper and export verification funcs * Update x/ibc/02-client/client/cli/query.go Co-Authored-By: Jack Zampolin * Update x/ibc/02-client/types/tendermint/consensus_state.go Co-Authored-By: Jack Zampolin * address some of the review comments * resolve some TODOs and address comments from review * update connection versioning * minor error updates * minor UX improvements * rename pkg * fixes * refactor ICS23 * cleanup types * rename pkg and fix import * implement batch verification * gosimple suggestion * various fixes; remove legacy tests; remove commitment path query * alias * minor updates from ICS23 * renaming * update verification and rename root funcs * move querier to x/ibc * update query.go to use 'custom/...' query path * add tests * ICS 24 Implementation (#5229) * add validation functions * validate path in ics-23 * address @fede comments * move errors into host package * flatten ICS23 structure * fix ApplyPrefix * updates from ICS23 and ICS24 * msg.ValidateBasic and ADR09 evidence interface * complete types testing * delete empty test file * remove ibc errors from core error package * custom JSON marshaling; msg.ValidateBasic; renaming of variables * minor update * custom JSON marshaling * minor changes on commitment types * R4R - Store consensus state correctly (#5242) * store consensus state correctly * fix client example * update alias * update alias * implement ics25 * update comment * refactor method name * fix file name * add test case * refactor code * refactor code * blocked the consensusState check * refactor code * fix golangci comments * refactor testcase * replace rootMultiStore with simApp * remove unless code * remove unless code & refactor test case * refactor testcase * goimports code * clean up * Add unit tests for ICS04 (#5286) * fix test * Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * applying review in progress * apply review - make querier interface * fix cli errors * fix dependency * fix dependency * reflect method name change * revise querier interface to work both on cli & store * revise querier interface to work both on cli & store * revise querier interface to work both on cli & store * reflect downstream change * fix cli * reflect downstream changes * reflect downstream changes * fix from address in tx cli * fix cli in progress(squash later) * fix cli * remove timeout, add channel cli * fix golangci * fix cli * Clean up * fix mock cli in progress * finalize cleanup, mock cli wip * add cli for mocksend * fix handler * rm commented lines * address review in progress * address review, rm cleanup/closing * rename mock packages * fix interface for gaia * rename Path -> Prefix * Store accessor upstream changes (#5119) * Store accessor upstream changes (#5119) * add comments, reformat merkle querier * rm merkle/utils * ICS 23 upstream changes (#5120) * ICS 23 upstream changes (#5120) * update Value * update test * fix * ICS 02 upstream changes (#5122) * ICS 02 upstream changes (#5122) * ICS 03 upstream changes (#5123) * ICS 03 upstream changes (#5123) * update test * cleanup types and submodule * more cleanup and godocs * remove counterPartyManager/State and cleanup * implement SubmitMisbehaviour and refactor * errors * events * fix test * refactors * WIP refactor ICS03 * remove Mapping * remove store accessors * proposed refactor * remove store accessors from ICS02 * refactor queriers, handler and clean keeper * logger and tx long description * ineffassign * Apply suggestions from code review Co-Authored-By: Jack Zampolin * Apply suggestions from code review Co-Authored-By: Jack Zampolin * remove store accessors * refactor handshake to update it to the latest ICS03 spec * update handler and msgs * add verification functions * update verification * ICS02 module.go * top level x/ibc structure * update connection queries * update connection tx * remove extra files * refactor: remove store accessors, update keeper and types to match spec (WIP) * update handshake and packet * implement packet timeouts * implement send and receive packet * implement packet ACK * update handler * add channel errors * channel querier * update expected client keeper and export verification funcs * ICS 05 Implementation * release port and godocs * Update x/ibc/02-client/client/cli/query.go Co-Authored-By: Jack Zampolin * Update x/ibc/02-client/types/tendermint/consensus_state.go Co-Authored-By: Jack Zampolin * address some of the review comments * resolve some TODOs and address comments from review * update connection versioning * minor error updates * update ICS04 with downstream changes * Implement tx cli actions * add MsgSendPacket handler; msg validation, errors and events * update errors and add port Keeper to ibc Keeper * minor UX improvements * rename pkg * fixes * refactor ICS23 * cleanup types * ICS 5 updates (#5222) * Validate port identifiers * Refactor to static bind * Add comments * Add 'GetPorts' query function * rename pkg and fix import * implement batch verification * gosimple suggestion * various fixes; remove legacy tests; remove commitment path query * alias * minor updates from ICS23 * renaming * update verification and rename root funcs * rm legacy tests; add query proofs support * remove capability key generation and authentication logic * move querier to x/ibc * update query.go to use 'custom/...' query path * add tests * ICS 24 Implementation (#5229) * add validation functions * validate path in ics-23 * address @fede comments * move errors into host package * flatten ICS23 structure * fix ApplyPrefix * updates from ICS23 and ICS24 * msg.ValidateBasic and ADR09 evidence interface * complete types testing * delete empty test file * remove ibc errors from core error package * custom JSON marshaling; msg.ValidateBasic; renaming of variables * minor update * custom JSON marshaling * use host validation for port ids * downstream changes; custom marshal JSON; msg validation, and update errors * update errors and aliases * update msg validation and CLI UX * minor changes on commitment types * fix channel and packet check (#5243) * R4R - Store consensus state correctly (#5242) * store consensus state correctly * fix client example * update alias * update alias * update alias and keeper.GetPort() * authenticate port ID; remove send packet msg from CLI * comment out handlers * add ibc module to simapp * ICS20 implementation (#5204) * add ibc bank mock * modify handler * import channel * add receiving logic * add cli proof handling * modify cli * modify receiver type * modify errcode * optimize codes * add denom prefix when source is true * refactor code * error return * switch ibc antehandler to decorator pattern * fix name/comment * ICS 20 implementation (#5250) * move ics20 code to 20-transfer * clean code * fix compiling error * add transfer module * address ICS20 comments from review * add routing callbacks * clean code * add missing err return * modify err type * modify err type * add supply handling * modify proof type * add comments for msg and packet data * add timeout supply handling * modify module account name * use supply keeper for burn and mint coins * restructure keeper * update alias and module.go * golangci linter * add ics20 handler to IBC handler * update callbacks * update ICS20 escrow address * fix querier routes * fix create client cli * minor updates * ibc querier test * Refactor ibc/mock/bank into ICS 20 (#5264) * Most of code port from mock module to ICS 20 * A few minor fixes * Apply suggestions from code review Co-Authored-By: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com> * Fix suggestions from autolinter * Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * Fix order of messages * Add invalid height error code, check non-nil proof * Fix linter error * Return the underlying error * Tendermint starts at height 1 * Apply suggestions from code review * setup ics20 test suite * add event to MsgRecvPacket * update ibc keeper test to use test suite * Add handshake commands * WIP connection handshake * WIP Connection Handshake * Add cliCtx.WaitForNBlocks * fix connection handshake in progress * fix connection handshake in progress * add channel unit test * add more channel tests * fix channel test * refactor channel test * add capability test for channel * make channel testing work * optimize channel test * delete types/errors.go * modify capability test * uncomment * add msg tests for channel * fix port capability store * fix channel test * use simapp * modify channel test * refactor channel msg test * go fmt * IBC alpha general cleanup (#5291) * remove prefix from keeper; update client queries; address ICS02 comments from @cwgoes * add proof for root query * golangci * remove hardcoded bind port logic * space * WIP: register errors * register errors; make format * use new instead of register; unescape path * golangci * Fix codec issue in ics23 * Modify codec registration style to match previous working state * write port tests * ICS-02: Keeper Tests (#5329) * add keeper tests * fix tendermint tests * Fix proof verification; remove store key prefixes; add additional path validations (#5313) * fix poof verify * minor cleanup * fix tests * remove key prefixes * fix tests * Add ICS20 tests (#5308) * add ics20 test * delete debug * fix ics20 test * revert and modify * optimize test * add ics20 msg test * fix test * add packet tests and more msgs tests * add ReceivePacket and callbacks tests * fix callbacks test * add handler tests for ics20 * fix handler tests * minor cleanup * test all positive amounts * update test suite NotNil to Error * fix ics20 tests * expected error * Add IBC REST endpoints (#5310) * add rest framework * add rest endpoints for ibc connection * add rest endpoints for ibc client * add rest endpoints for ibc channel * modify ibc rest api * add rest endpoints for ibc transfer * fix query route * fix receive packet * fix query client state api * use sub module name instead of icsxx * use const for prove judgement * modify ibc rest api * add api docs to swagger * add ibc config * fix proof path in swagger * return query result proof * update swagger docs * parse prove * clean up * fix ibc rest api and swagger docs * fix host validate * fix typo * add submitMisbehaviour error response in swagger * fix rest queryRoot and swagger doc * add response comments for each REST functions * fix rest function comments * fix IBC proofs (#5351) * fix ICS02 proofs * fix ICS03 proofs * fix ICS04 proofs * fix ICS20 proofs * make format * fix build; comment handshakes * ICS-2 Implement Misbehavior (#5321) * ibc client evidence route * split evidence from misbehaviour * clean up client events * test misbehaviour and evidence * remove comments * remove frozen comments from demo * Update x/ibc/02-client/types/tendermint/evidence_test.go Co-Authored-By: Aditya * change evidence to detect malicious chain * remove unnecessary sort * fix evidence and persist committers to check misbehaviour * minor fixes and remove incorrect tests * add evidence tests * remove debug statements * cleanup evidence test * start misbehaviour tests * fix nondeterministic bug * add same height and next height checks in misbehaviour * fix bugs * apply fede review suggestions * finish code review changes * fix GetCommitter and write keeper-level misbehaviour tests * remove incorrect special case checking * save * final fixes * save * fix conflict * fix conflicts and add back submit misbehaviour msg * Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * save * add godocs and fix test * fix test panics in other modules * Update x/ibc/02-client/keeper/client.go Co-Authored-By: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com> * add back aliases * Misc ibc fixes (#5357) * fix cli ExactArgs * remove full handshakes * rm dup flag * fix error handling * Implement Query Committer methods in ICS-02 (#5402) * add query methods for committers in ICS-02 * Update x/ibc/02-client/keeper/keeper.go * add REST docs * fix test * IBC UX improvements (#5364) * ICS02 iterators * ICS03 iterators * ICS04 iterators * ICS02 client updates * CLI connections * setup queriers * clean up queriers * add tests * IBC top-level querier tests * update ICS02 keys * update ICS03 keys * make format * update ICS04 keys * fix a few tests * fix ICS20 tests * update keys * fix ICS02 queries (#5425) * fix CLI JSON param unmarshaling (#5431) * Fix inconsistent string lookup functions (#5437) * fix inconsistent string lookup functions * test client type and ordering * channel and connection state tests * address golangcibot comments * fix test * Update x/ibc error handling (#5462) * Merge PR #5428: Add mod, exponentiation for uint * Modified examples in distribution module (#5441) * Merge PR #5442: Remove of the client/alias.go * Merge PR #5445: Mock rpcclient in tests for votes pagination * Merge PR #5435: Added iterator that allows to read only requested values * Merge PR #5427: Remove code duplication in x/auth/client/cli * Merge PR #5421: Refactor Error Handling * update x/ibc error handling * update ICS24 and ICS02 errors * ICS03, ICS23 and common errors * updates from master and errors from ICS04 * build * fix ics20 tests * fix tests * golangcibot fixes Co-authored-by: Kevin Davis Co-authored-by: kaustubhkapatral <54210167+kaustubhkapatral@users.noreply.github.com> Co-authored-by: Ferenc Fabian Co-authored-by: Dmitry Shulyak Co-authored-by: Alessio Treglia Co-authored-by: Alexander Bezobchuk * ADR 015 Implementation (#5401) * implement in progress * rm unneccessary change under simapp, modify baseapp for codetxbreak * fix test in progress * fix test error * fix golangci * address minor comments * mv antehandler to ante/, address comments * fix GetCommitment => GetData, fix syntax * checkout types/ to ibc-alpha * checkout to origin/ibc-alpha * fix branch problem * fix syntax error * recover PacketI interface * mv recvpacket rest from 20 -> 04 * address minor comments * Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * rm wrong files * Apply suggestions from code review * PacketDataI field is now named, not embed * add acknowledgement hashing * rename finalization functiosn * Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * Rename GetCommitment() to GetBytes() * Add recv sequence incr to RecvPacket() * Revert but where is PacketExecuted() called * Call PacketExecuted(), check seq in RecvPacket() * The port is called "bank" * Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * Update simapp/app.go Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * Remove omitempty * Add godoc * Move events * set ProofVerificationDecorator on AnteHandler * Apply suggestions from code review Co-Authored-By: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com> * format Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Co-authored-by: Christopher Goes Co-authored-by: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com> * Fix build errors * remove tmcmn instance * remove tmcmn instance * Fix compliation errors * Fix build errors * Fix build errors * ICS07 Tendermint Client implementation (#5485) * implement ICS07 * build * update tests and cleanup * x/ibc/02-client/types: remove misbehaviour in favor of evidence * remove root query, update queriers, implement verification funcs * remove committer; cleanup * move keys to ibc/types * fix paths * update ICS03 connection verification * move order and states to exported pkg * update ICS04 to latest spec * fix build * move ics02 types/errors package to /types * update a few tests * update tests; fix codec registration * minor changes from code review * ibc/client/types: fix tests * ibc/02-client/keeper: fix tests * ibc/03-connection/keeper: begin tests for verify.go * ibc/23-commitment: add IsEmpty() to Prefix, Path and Proof * address comments from review * add tests for evidence * x/ibc/07-tendermint: add tests for consensus state, header and update * ibc/07-tendermint: fix verification panic and add tests * ibc/07-tendermint: add failure test cases * x/ibc/03-connection/keeper: add verification tests for failing cases * remove unused queriers * Update ICS 7 tests (#5556) * Update ICS 7 tests * Fix one problem * Also set consensus state for height 1 * Apply same fixes to ICS 4 tests * Remove unnecessary change * Fix ante tests; remove printfs * Remove printf * Update x/ibc/ante/ante_test.go Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * add TODOs for ADR 03 dynamic store * add tests for msgs and packet (#5559) * Add skeleton for ValidateBasic tests * Move tests; basic one passes * Add more ValidateBasic tests * Add more ValidateBasic testcases * Fix minor typo * Add `ValidateBasic` tests for Packet * Move to packet_test.go * use app.Commit for tests * update verify.go * Fix all ICS 07 Tests (#5565) * ICS 07 Debugging * WIP Debugging * Foo bar baz, baz bar foo, :man_shrugging: * cleanup print statements * cleanup verification test * add return err for proof verification * cleanup; start handshake testing * connection handshake tests * scopelint * WIP Test refactor * fix ICS03 tests * fix ICS04 tests * nolint Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * cleanup comments and add a few tests * typo Co-authored-by: Christopher Goes Co-authored-by: Jack Zampolin * fix build * IBC historical info support (#5475) * implement GetConsensusState * introspect past consensus states on ICS03 handshake * implement ToTmValidator staking util function * add test cases * update tests * Fix various compile erros * fix historical info * fix dep cycle * Fix golint issues * Fix proto docs lint fail * move consensus state query downstream to ICS03 * remove unused funcs on expected keeper * update tests and move get consensus state to ICS03 * increase cov for verification funcs * fix tests * interfacer fix * fix expected keeper * remove TODOs Co-authored-by: Jack Zampolin * cleanup ibc-alpha diff with master * Add bank alias for gaia * Moar bank alias gaia * Moar bank alias gaia * Fix query all clients * update to current Tendermint master * TxSearchMock: add orderBy field to TxSearch method * fix build errors * Small changes for compilation of gaia * Small changes for compilation of gaia * Add 07-tm.Header.ConsensusState() to make conversions easy * Add additional IBC Channel Tests (#5578) * Add stubbed out tests * one working testcase and mocked packet types * Finish TestSendPacket * Move mocked proofs to ibc/types and finish TestRecvPacket * Implement TestPacketExecuted * WIP TestAckPacket * Start on timeout tests, 1 passing * WIP Tests * first cleanup * test send transfer * add packet tests * fixes and more tests * finish tests * Update x/ibc/04-channel/keeper/packet.go * golangcibot fixes Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Co-authored-by: Christopher Goes * merge master * ICS07 follow up changes (#5606) * ADR07 follow up changes * add assertion checks * update ICS02 tests * update ICS07 tests * add trusting and ubd period to msg * tests * more test updates * ICS07 follow ups (#5631) * refactor tendermint package to move msgs here * fix rest of package to accomadate 07 refactor * added GetHeight to ConsensusState and moved clientstate struct creation to 07-tendermint * start work on making misbehavior retrieve consensusState LTE misbehavior * allow misbehavior submission at height not equal to persisted consensusState * optimize submitMisbehavior by erroring earlier * cleanup misbehavior and propose lazy fix * fix bug * Update x/ibc/02-client/keeper/client.go Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * address fede review * add chain-id into clientstate * address necessary fede review Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Co-authored-by: Aditya * IBC SDK specification (#5426) * IBC SDK specification * update events * add implementation mapping * minor additions to readme * fix conflicts * add missing ADRs, modules and ICS * fix build * Merge PR #5670: Fix Packet Timeout Bug * add destination height to MsgSendTransger * quick fix * Add defensive checks before setting param keytables in keeprs * ICS 20 Cleanup and Tests (#5577) * Add comments, remove unused code and attempt to point to places where the spec is being implemented * close channel when transfer fails * rename packer data transfer to align to spec; refactor table tests * ICS 20 implementation cleanup work (#5602) * Simulation docs (#5033) * simulation docs * update docs with the latest simulation changes * minor imporvments * clean up of simulation.md * expand section on weights * minor reword * minor wording fix Co-authored-by: Marko * Merge PR #5597: Include Amount in Complete Unbonding/Redelegation Events * Add bank alias for gaia * Moar bank alias gaia * Moar bank alias gaia * Call `TimeoutExecuted`, add wrappers * Remove unused `MsgRecvPacket` Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Co-authored-by: Marko Co-authored-by: Alexander Bezobchuk Co-authored-by: Jack Zampolin * Merge PR #5603: Remove acknowledgement interface in favour of []byte * fixes and cleanup * spec compliance * refactor relay prefixes and tests * Fix test compilation * cleanup; add notes and additional test case * Receive transfer test * Apply suggestions from code review Co-Authored-By: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com> * Fix autolinter application * Add testcase with incorrect prefix * golangcibot fixes * delete extra comment Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Co-authored-by: Christopher Goes Co-authored-by: Marko Co-authored-by: Alexander Bezobchuk Co-authored-by: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com> * Merge PR #5666: Use Tendermint lite client verification * Disambiguate error codes * Fix binary marshalling for state storage * readd MsgSubmitClientMisbehaviour * Fix double flag registration * ICS23 refactor (#5710) * ICS23 restructure directories * more fixes * format * Merge PR #5711: Switch mock proofs to real proofs * Add key, path, value to mock proofs * Also alter mock types (why are there duplicates) * Remove mock proofs from handshake_test.go * Use actual proofs * Try to fix historical info, no luck * Have test-cases produce consensus heights * Fix consensus height / proof height difference in verifyClientConsensusState * Bug fixes contd. * Fix some identifier issues * `TestConnOpenConfirm` now works * further on proof * fix debugger print statement * IT PASSES * revert identifier changes * refactor query proof to generate proofs from either chain * fix ack and confirm * Remove temporary break * fix connection and channel verify tests * fix everything but verify client consensusstate * fix all verify tests * fix ics07 tests * fix handshake tests * fix packet tests * fix timeout tests Co-authored-by: Aditya Sripal Co-authored-by: Federico Kunze * Try to fix store decoding issue * Sim issue update * add error in msg * remove next validator set from ibctmtypes.Header * remove warning msg * Make IBC updating more robust * blh * bump tm dependency * remove redundant clockdrift correction * remove blh commit * fix test build failures * Change time from PST to UTC * Merge PR #5770: Update error message in connection keeper * Merge PR #5774: Debug timestamp issues * Merge PR #5786: Fix MsgTransfer routing * Fix test-case * register MsgPacket * Flip boolean * emit packet event on SendPacket * Fix attribute setting * Implement in-memory KVStore * Start keeper and types * Add codec * Add keys logic * Update types * Update keeper * Implement NewCapability * Implement InitializeAndSeal * Update simapp * Implement GetCapability * Add logging for new and claimed caps * Call InitializeAndSeal in SimApp * Update keeper semantics + unit tests * Use big endian * More unit tests * Increase keeper test coverage * Remove TODO * Add module doc * Update doc * Apply suggestions from code review Co-Authored-By: Aditya * Update NewCapability godoc * Clarify owner * Add forgery test case to TestAuthenticateCapability * Format doc * Update to tm@v0.33.2 * Update ADR * Explicitly take pointer in FwdCapabilityKey * Update set to be logn * Update app module * Lint * Fix broken test after packet format changed * Add stub and unit tests for ReleaseCapability * Finish implementation * Add test case to TestAuthenticateCapability for releasing a cap * remove swagger files from ibc module (#5893) * Move IBC packet data interpretation to the application module (#5890) * fix: move IBC packet data interpretation to the application module This also adds a channelexported.NewOpaquePacketData(rawBytes) implementation to assist apps in being able to manipulate the raw packet data using the codec layer. * feat: use an internal-to-module PacketDataI type This one only has a GetBytes() method, which is implemented by OpaquePacketData. * fix: remove OpaquePacketData No need to wrap the []byte packet.GetData(). If the caller wants it, they can use it directly. * docs: update adr-015 * fix: put the TimeoutHeight back into the packet commitment * refactor: simplify unmarshalling of transfer packet * docs: update for new unmarshal steps * fix: clean up usage of sdkerrors.Wrapf * Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * chore: remove unnecessary "encoding/binary" import Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * fix ibc-alpha sims (#5909) * fix some simulations * fix HistoricalInfo sim decoders * add staking sim decoder test case for HistInfo * Merge PR #5901: Add & update IBC queriers for relayer use * Add identifier to connection responses (ref #5829) * Update querier as well * Fix test-case * Update for consistency * Add querier for connection channels; fix linter * Fix build (?) * Add JSON & Yaml tags * Add tags * Add identifiers to channels as well * fix test * Merge PR #5914: x/capability: Fix Object Capability Model * Merge PR #5918: Remove source field from ICS 20 packet & message types per latest spec * fix ics20 client args (#5924) * Merge PR #5930: Add GetChainID to ClientState interface * Merge PR #5925: Add additional events to x/ibc * Migrate x/capability to Protobuf (#5926) * migrate x/capability to protobuf * fixes * format * remove capability from codec std * return pointer for getOwners * remove & * Update x/capability/keeper/keeper.go Co-Authored-By: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com> * rename remove Capability interface; rename CapabilityKey -> Capaility; cc @cwgoes * x/capability: remove RegisterCapabilityTypeCodec and seal amino cdc Co-authored-by: Alexander Bezobchuk Co-authored-by: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com> * Merge PR #5939: Unmarshal packets as JSON * Merge PR #5888: Dynamic Capabilities with Routing * cleanup ibc-alpha (#5945) * cleanup ibc-alpha * remove HasKeyTable() * add preexisting checks * undo remove checks * x/staking: import and export HistoricalInfo * staking/types: add HistoricalInfo to GenesisState * changelog * add staking module to app BeginBlockers * remove JSON files * address comments from review * cleanup ibc-alpha * fix ibc-alpha lint (#5959) * x/ibc: changelog (#5960) * x/ibc: changelog * add reference to the spec * Merge PR #5954: Bind Transfer Port on InitChain * Bind transfer port in InitChain * push fixes * address @fedekunze review * Apply suggestions from code review * lint Co-authored-by: Jack Zampolin Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Co-authored-by: Federico Kunze Co-authored-by: Joon Co-authored-by: Christopher Goes Co-authored-by: vincent Co-authored-by: Jack Zampolin Co-authored-by: Aditya Sripal Co-authored-by: Kevin Davis Co-authored-by: kaustubhkapatral <54210167+kaustubhkapatral@users.noreply.github.com> Co-authored-by: Ferenc Fabian Co-authored-by: Dmitry Shulyak Co-authored-by: Alessio Treglia Co-authored-by: Alexander Bezobchuk Co-authored-by: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com> Co-authored-by: Anton Kaliaev Co-authored-by: Marko Co-authored-by: Aleksandr Bezobchuk Co-authored-by: Michael FIG Co-authored-by: Segue --- CHANGELOG.md | 16 +- client/context/query.go | 3 +- client/lcd/statik/statik.go | 2 +- client/lcd/swagger-ui/swagger.yaml | 1199 ++++++++++++++++- .../adr-003-dynamic-capability-store.md | 131 +- .../adr-015-ibc-packet-receiver.md | 33 +- docs/package-lock.json | 2 +- docs/spec/ibc/README.md | 3 - simapp/app.go | 120 +- store/rootmulti/store.go | 3 +- store/types/store.go | 18 + types/coin.go | 4 +- types/store.go | 2 + types/utils.go | 10 + types/utils_test.go | 2 +- x/auth/ante/ante.go | 10 +- x/auth/ante/ante_test.go | 26 +- x/auth/keeper/keeper.go | 7 +- x/auth/types/querier.go | 2 +- x/bank/keeper/keeper.go | 10 +- x/capability/alias.go | 42 + x/capability/docs/README.md | 89 ++ x/capability/keeper/keeper.go | 325 +++++ x/capability/keeper/keeper_test.go | 245 ++++ x/capability/module.go | 117 ++ x/capability/types/codec.go | 30 + x/capability/types/errors.go | 14 + x/capability/types/keys.go | 51 + x/capability/types/keys_test.go | 29 + x/capability/types/store.go | 56 + x/capability/types/types.go | 87 ++ x/capability/types/types.pb.go | 710 ++++++++++ x/capability/types/types.proto | 33 + x/capability/types/types_test.go | 69 + x/crisis/keeper/keeper.go | 7 +- x/evidence/exported/evidence.go | 12 +- x/ibc/02-client/alias.go | 51 + x/ibc/02-client/client/cli/cli.go | 28 + x/ibc/02-client/client/cli/query.go | 180 +++ x/ibc/02-client/client/rest/query.go | 172 +++ x/ibc/02-client/client/rest/rest.go | 18 + x/ibc/02-client/client/utils/utils.go | 157 +++ x/ibc/02-client/doc.go | 10 + x/ibc/02-client/exported/exported.go | 193 +++ x/ibc/02-client/exported/exported_test.go | 49 + x/ibc/02-client/handler.go | 104 ++ x/ibc/02-client/keeper/client.go | 153 +++ x/ibc/02-client/keeper/client_test.go | 316 +++++ x/ibc/02-client/keeper/keeper.go | 171 +++ x/ibc/02-client/keeper/keeper_test.go | 188 +++ x/ibc/02-client/keeper/querier.go | 37 + x/ibc/02-client/module.go | 28 + x/ibc/02-client/types/codec.go | 25 + x/ibc/02-client/types/errors.go | 27 + x/ibc/02-client/types/events.go | 22 + x/ibc/02-client/types/expected_keepers.go | 14 + x/ibc/02-client/types/keys.go | 12 + x/ibc/02-client/types/querier.go | 75 ++ x/ibc/03-connection/alias.go | 72 + x/ibc/03-connection/client/cli/cli.go | 41 + x/ibc/03-connection/client/cli/query.go | 107 ++ x/ibc/03-connection/client/cli/tx.go | 251 ++++ x/ibc/03-connection/client/rest/query.go | 84 ++ x/ibc/03-connection/client/rest/rest.go | 62 + x/ibc/03-connection/client/rest/tx.go | 204 +++ x/ibc/03-connection/client/utils/utils.go | 124 ++ x/ibc/03-connection/exported/exported.go | 89 ++ x/ibc/03-connection/exported/exported_test.go | 46 + x/ibc/03-connection/handler.go | 113 ++ x/ibc/03-connection/keeper/handshake.go | 234 ++++ x/ibc/03-connection/keeper/handshake_test.go | 286 ++++ x/ibc/03-connection/keeper/keeper.go | 156 +++ x/ibc/03-connection/keeper/keeper_test.go | 318 +++++ x/ibc/03-connection/keeper/querier.go | 57 + x/ibc/03-connection/keeper/verify.go | 236 ++++ x/ibc/03-connection/keeper/verify_test.go | 427 ++++++ x/ibc/03-connection/module.go | 33 + x/ibc/03-connection/types/codec.go | 28 + x/ibc/03-connection/types/connection.go | 133 ++ x/ibc/03-connection/types/connection_test.go | 79 ++ x/ibc/03-connection/types/errors.go | 16 + x/ibc/03-connection/types/events.go | 24 + x/ibc/03-connection/types/expected_keepers.go | 13 + x/ibc/03-connection/types/keys.go | 15 + x/ibc/03-connection/types/msgs.go | 310 +++++ x/ibc/03-connection/types/msgs_test.go | 215 +++ x/ibc/03-connection/types/querier.go | 93 ++ x/ibc/03-connection/types/version.go | 96 ++ x/ibc/04-channel/alias.go | 85 ++ x/ibc/04-channel/client/cli/cli.go | 42 + x/ibc/04-channel/client/cli/query.go | 47 + x/ibc/04-channel/client/cli/tx.go | 251 ++++ x/ibc/04-channel/client/rest/query.go | 52 + x/ibc/04-channel/client/rest/rest.go | 84 ++ x/ibc/04-channel/client/rest/tx.go | 382 ++++++ x/ibc/04-channel/client/utils/utils.go | 69 + x/ibc/04-channel/exported/exported.go | 170 +++ x/ibc/04-channel/exported/exported_test.go | 91 ++ x/ibc/04-channel/handler.go | 171 +++ x/ibc/04-channel/keeper/handshake.go | 393 ++++++ x/ibc/04-channel/keeper/handshake_test.go | 629 +++++++++ x/ibc/04-channel/keeper/keeper.go | 173 +++ x/ibc/04-channel/keeper/keeper_test.go | 452 +++++++ x/ibc/04-channel/keeper/packet.go | 451 +++++++ x/ibc/04-channel/keeper/packet_test.go | 423 ++++++ x/ibc/04-channel/keeper/querier.go | 68 + x/ibc/04-channel/keeper/timeout.go | 260 ++++ x/ibc/04-channel/keeper/timeout_test.go | 233 ++++ x/ibc/04-channel/module.go | 33 + x/ibc/04-channel/types/channel.go | 128 ++ x/ibc/04-channel/types/channel_test.go | 30 + x/ibc/04-channel/types/codec.go | 42 + x/ibc/04-channel/types/errors.go | 23 + x/ibc/04-channel/types/events.go | 42 + x/ibc/04-channel/types/expected_keepers.go | 73 + x/ibc/04-channel/types/keys.go | 15 + x/ibc/04-channel/types/msgs.go | 582 ++++++++ x/ibc/04-channel/types/msgs_test.go | 511 +++++++ x/ibc/04-channel/types/packet.go | 115 ++ x/ibc/04-channel/types/packet_test.go | 32 + x/ibc/04-channel/types/querier.go | 119 ++ x/ibc/05-port/alias.go | 37 + x/ibc/05-port/keeper/keeper.go | 73 + x/ibc/05-port/keeper/keeper_test.go | 74 + x/ibc/05-port/types/errors.go | 13 + x/ibc/05-port/types/keys.go | 31 + x/ibc/05-port/types/module.go | 77 ++ x/ibc/05-port/types/router.go | 65 + x/ibc/07-tendermint/client/cli/cli.go | 26 + x/ibc/07-tendermint/client/cli/tx.go | 162 +++ x/ibc/07-tendermint/client/rest/rest.go | 45 + x/ibc/07-tendermint/client/rest/tx.go | 155 +++ x/ibc/07-tendermint/doc.go | 5 + x/ibc/07-tendermint/misbehaviour.go | 103 ++ x/ibc/07-tendermint/misbehaviour_test.go | 136 ++ x/ibc/07-tendermint/module.go | 29 + x/ibc/07-tendermint/tendermint_test.go | 57 + x/ibc/07-tendermint/types/client_state.go | 344 +++++ .../07-tendermint/types/client_state_test.go | 567 ++++++++ x/ibc/07-tendermint/types/codec.go | 26 + x/ibc/07-tendermint/types/consensus_state.go | 57 + .../types/consensus_state_test.go | 79 ++ x/ibc/07-tendermint/types/errors.go | 15 + x/ibc/07-tendermint/types/evidence.go | 135 ++ x/ibc/07-tendermint/types/evidence_test.go | 187 +++ x/ibc/07-tendermint/types/header.go | 64 + x/ibc/07-tendermint/types/header_test.go | 30 + x/ibc/07-tendermint/types/msgs.go | 217 +++ x/ibc/07-tendermint/types/msgs_test.go | 62 + x/ibc/07-tendermint/types/tendermint_test.go | 48 + x/ibc/07-tendermint/types/test_utils.go | 59 + x/ibc/07-tendermint/update.go | 107 ++ x/ibc/07-tendermint/update_test.go | 158 +++ x/ibc/20-transfer/alias.go | 47 + x/ibc/20-transfer/client/cli/cli.go | 36 + x/ibc/20-transfer/client/cli/query.go | 47 + x/ibc/20-transfer/client/cli/tx.go | 67 + x/ibc/20-transfer/client/rest/query.go | 51 + x/ibc/20-transfer/client/rest/rest.go | 28 + x/ibc/20-transfer/client/rest/tx.go | 72 + x/ibc/20-transfer/client/utils/utils.go | 33 + x/ibc/20-transfer/genesis.go | 35 + x/ibc/20-transfer/handler.go | 97 ++ x/ibc/20-transfer/handler_test.go | 304 +++++ x/ibc/20-transfer/keeper/keeper.go | 105 ++ x/ibc/20-transfer/keeper/keeper_test.go | 276 ++++ x/ibc/20-transfer/keeper/relay.go | 228 ++++ x/ibc/20-transfer/keeper/relay_test.go | 215 +++ x/ibc/20-transfer/module.go | 261 ++++ x/ibc/20-transfer/types/codec.go | 22 + x/ibc/20-transfer/types/errors.go | 12 + x/ibc/20-transfer/types/events.go | 17 + x/ibc/20-transfer/types/expected_keepers.go | 51 + x/ibc/20-transfer/types/keys.go | 50 + x/ibc/20-transfer/types/msgs.go | 75 ++ x/ibc/20-transfer/types/msgs_test.go | 110 ++ x/ibc/20-transfer/types/packet.go | 69 + x/ibc/20-transfer/types/packet_test.go | 39 + x/ibc/23-commitment/exported/exported.go | 71 + x/ibc/23-commitment/types/codec.go | 27 + x/ibc/23-commitment/types/commitment_test.go | 37 + x/ibc/23-commitment/types/errors.go | 14 + x/ibc/23-commitment/types/merkle.go | 187 +++ x/ibc/23-commitment/types/merkle_test.go | 141 ++ x/ibc/23-commitment/verify.go | 64 + x/ibc/alias.go | 29 + x/ibc/ante/ante.go | 48 + x/ibc/ante/ante_test.go | 371 +++++ x/ibc/client/cli/cli.go | 51 + x/ibc/client/rest/rest.go | 17 + x/ibc/handler.go | 202 +++ x/ibc/keeper/keeper.go | 46 + x/ibc/keeper/keeper_test.go | 37 + x/ibc/keeper/querier.go | 53 + x/ibc/keeper/querier_test.go | 113 ++ x/ibc/module.go | 140 ++ x/ibc/spec/01_concepts.md | 8 + x/ibc/spec/02_state.md | 21 + x/ibc/spec/04_messages.md | 80 ++ x/ibc/spec/05_callbacks.md | 5 + x/ibc/spec/06_events.md | 147 ++ x/ibc/spec/README.md | 109 ++ x/ibc/types/errors.go | 11 + x/ibc/types/keys.go | 207 +++ x/ibc/types/mock.go | 73 + x/ibc/types/utils.go | 15 + x/mint/keeper/keeper.go | 7 +- x/slashing/keeper/keeper.go | 7 +- x/slashing/types/expected_keepers.go | 1 + x/staking/simulation/decoder.go | 6 - x/staking/simulation/decoder_test.go | 4 - 211 files changed, 23566 insertions(+), 155 deletions(-) delete mode 100644 docs/spec/ibc/README.md create mode 100644 x/capability/alias.go create mode 100644 x/capability/docs/README.md create mode 100644 x/capability/keeper/keeper.go create mode 100644 x/capability/keeper/keeper_test.go create mode 100644 x/capability/module.go create mode 100644 x/capability/types/codec.go create mode 100644 x/capability/types/errors.go create mode 100644 x/capability/types/keys.go create mode 100644 x/capability/types/keys_test.go create mode 100644 x/capability/types/store.go create mode 100644 x/capability/types/types.go create mode 100644 x/capability/types/types.pb.go create mode 100644 x/capability/types/types.proto create mode 100644 x/capability/types/types_test.go create mode 100644 x/ibc/02-client/alias.go create mode 100644 x/ibc/02-client/client/cli/cli.go create mode 100644 x/ibc/02-client/client/cli/query.go create mode 100644 x/ibc/02-client/client/rest/query.go create mode 100644 x/ibc/02-client/client/rest/rest.go create mode 100644 x/ibc/02-client/client/utils/utils.go create mode 100644 x/ibc/02-client/doc.go create mode 100644 x/ibc/02-client/exported/exported.go create mode 100644 x/ibc/02-client/exported/exported_test.go create mode 100644 x/ibc/02-client/handler.go create mode 100644 x/ibc/02-client/keeper/client.go create mode 100644 x/ibc/02-client/keeper/client_test.go create mode 100644 x/ibc/02-client/keeper/keeper.go create mode 100644 x/ibc/02-client/keeper/keeper_test.go create mode 100644 x/ibc/02-client/keeper/querier.go create mode 100644 x/ibc/02-client/module.go create mode 100644 x/ibc/02-client/types/codec.go create mode 100644 x/ibc/02-client/types/errors.go create mode 100644 x/ibc/02-client/types/events.go create mode 100644 x/ibc/02-client/types/expected_keepers.go create mode 100644 x/ibc/02-client/types/keys.go create mode 100644 x/ibc/02-client/types/querier.go create mode 100644 x/ibc/03-connection/alias.go create mode 100644 x/ibc/03-connection/client/cli/cli.go create mode 100644 x/ibc/03-connection/client/cli/query.go create mode 100644 x/ibc/03-connection/client/cli/tx.go create mode 100644 x/ibc/03-connection/client/rest/query.go create mode 100644 x/ibc/03-connection/client/rest/rest.go create mode 100644 x/ibc/03-connection/client/rest/tx.go create mode 100644 x/ibc/03-connection/client/utils/utils.go create mode 100644 x/ibc/03-connection/exported/exported.go create mode 100644 x/ibc/03-connection/exported/exported_test.go create mode 100644 x/ibc/03-connection/handler.go create mode 100644 x/ibc/03-connection/keeper/handshake.go create mode 100644 x/ibc/03-connection/keeper/handshake_test.go create mode 100644 x/ibc/03-connection/keeper/keeper.go create mode 100644 x/ibc/03-connection/keeper/keeper_test.go create mode 100644 x/ibc/03-connection/keeper/querier.go create mode 100644 x/ibc/03-connection/keeper/verify.go create mode 100644 x/ibc/03-connection/keeper/verify_test.go create mode 100644 x/ibc/03-connection/module.go create mode 100644 x/ibc/03-connection/types/codec.go create mode 100644 x/ibc/03-connection/types/connection.go create mode 100644 x/ibc/03-connection/types/connection_test.go create mode 100644 x/ibc/03-connection/types/errors.go create mode 100644 x/ibc/03-connection/types/events.go create mode 100644 x/ibc/03-connection/types/expected_keepers.go create mode 100644 x/ibc/03-connection/types/keys.go create mode 100644 x/ibc/03-connection/types/msgs.go create mode 100644 x/ibc/03-connection/types/msgs_test.go create mode 100644 x/ibc/03-connection/types/querier.go create mode 100644 x/ibc/03-connection/types/version.go create mode 100644 x/ibc/04-channel/alias.go create mode 100644 x/ibc/04-channel/client/cli/cli.go create mode 100644 x/ibc/04-channel/client/cli/query.go create mode 100644 x/ibc/04-channel/client/cli/tx.go create mode 100644 x/ibc/04-channel/client/rest/query.go create mode 100644 x/ibc/04-channel/client/rest/rest.go create mode 100644 x/ibc/04-channel/client/rest/tx.go create mode 100644 x/ibc/04-channel/client/utils/utils.go create mode 100644 x/ibc/04-channel/exported/exported.go create mode 100644 x/ibc/04-channel/exported/exported_test.go create mode 100644 x/ibc/04-channel/handler.go create mode 100644 x/ibc/04-channel/keeper/handshake.go create mode 100644 x/ibc/04-channel/keeper/handshake_test.go create mode 100644 x/ibc/04-channel/keeper/keeper.go create mode 100644 x/ibc/04-channel/keeper/keeper_test.go create mode 100644 x/ibc/04-channel/keeper/packet.go create mode 100644 x/ibc/04-channel/keeper/packet_test.go create mode 100644 x/ibc/04-channel/keeper/querier.go create mode 100644 x/ibc/04-channel/keeper/timeout.go create mode 100644 x/ibc/04-channel/keeper/timeout_test.go create mode 100644 x/ibc/04-channel/module.go create mode 100644 x/ibc/04-channel/types/channel.go create mode 100644 x/ibc/04-channel/types/channel_test.go create mode 100644 x/ibc/04-channel/types/codec.go create mode 100644 x/ibc/04-channel/types/errors.go create mode 100644 x/ibc/04-channel/types/events.go create mode 100644 x/ibc/04-channel/types/expected_keepers.go create mode 100644 x/ibc/04-channel/types/keys.go create mode 100644 x/ibc/04-channel/types/msgs.go create mode 100644 x/ibc/04-channel/types/msgs_test.go create mode 100644 x/ibc/04-channel/types/packet.go create mode 100644 x/ibc/04-channel/types/packet_test.go create mode 100644 x/ibc/04-channel/types/querier.go create mode 100644 x/ibc/05-port/alias.go create mode 100644 x/ibc/05-port/keeper/keeper.go create mode 100644 x/ibc/05-port/keeper/keeper_test.go create mode 100644 x/ibc/05-port/types/errors.go create mode 100644 x/ibc/05-port/types/keys.go create mode 100644 x/ibc/05-port/types/module.go create mode 100644 x/ibc/05-port/types/router.go create mode 100644 x/ibc/07-tendermint/client/cli/cli.go create mode 100644 x/ibc/07-tendermint/client/cli/tx.go create mode 100644 x/ibc/07-tendermint/client/rest/rest.go create mode 100644 x/ibc/07-tendermint/client/rest/tx.go create mode 100644 x/ibc/07-tendermint/doc.go create mode 100644 x/ibc/07-tendermint/misbehaviour.go create mode 100644 x/ibc/07-tendermint/misbehaviour_test.go create mode 100644 x/ibc/07-tendermint/module.go create mode 100644 x/ibc/07-tendermint/tendermint_test.go create mode 100644 x/ibc/07-tendermint/types/client_state.go create mode 100644 x/ibc/07-tendermint/types/client_state_test.go create mode 100644 x/ibc/07-tendermint/types/codec.go create mode 100644 x/ibc/07-tendermint/types/consensus_state.go create mode 100644 x/ibc/07-tendermint/types/consensus_state_test.go create mode 100644 x/ibc/07-tendermint/types/errors.go create mode 100644 x/ibc/07-tendermint/types/evidence.go create mode 100644 x/ibc/07-tendermint/types/evidence_test.go create mode 100644 x/ibc/07-tendermint/types/header.go create mode 100644 x/ibc/07-tendermint/types/header_test.go create mode 100644 x/ibc/07-tendermint/types/msgs.go create mode 100644 x/ibc/07-tendermint/types/msgs_test.go create mode 100644 x/ibc/07-tendermint/types/tendermint_test.go create mode 100644 x/ibc/07-tendermint/types/test_utils.go create mode 100644 x/ibc/07-tendermint/update.go create mode 100644 x/ibc/07-tendermint/update_test.go create mode 100644 x/ibc/20-transfer/alias.go create mode 100644 x/ibc/20-transfer/client/cli/cli.go create mode 100644 x/ibc/20-transfer/client/cli/query.go create mode 100644 x/ibc/20-transfer/client/cli/tx.go create mode 100644 x/ibc/20-transfer/client/rest/query.go create mode 100644 x/ibc/20-transfer/client/rest/rest.go create mode 100644 x/ibc/20-transfer/client/rest/tx.go create mode 100644 x/ibc/20-transfer/client/utils/utils.go create mode 100644 x/ibc/20-transfer/genesis.go create mode 100644 x/ibc/20-transfer/handler.go create mode 100644 x/ibc/20-transfer/handler_test.go create mode 100644 x/ibc/20-transfer/keeper/keeper.go create mode 100644 x/ibc/20-transfer/keeper/keeper_test.go create mode 100644 x/ibc/20-transfer/keeper/relay.go create mode 100644 x/ibc/20-transfer/keeper/relay_test.go create mode 100644 x/ibc/20-transfer/module.go create mode 100644 x/ibc/20-transfer/types/codec.go create mode 100644 x/ibc/20-transfer/types/errors.go create mode 100644 x/ibc/20-transfer/types/events.go create mode 100644 x/ibc/20-transfer/types/expected_keepers.go create mode 100644 x/ibc/20-transfer/types/keys.go create mode 100644 x/ibc/20-transfer/types/msgs.go create mode 100644 x/ibc/20-transfer/types/msgs_test.go create mode 100644 x/ibc/20-transfer/types/packet.go create mode 100644 x/ibc/20-transfer/types/packet_test.go create mode 100644 x/ibc/23-commitment/exported/exported.go create mode 100644 x/ibc/23-commitment/types/codec.go create mode 100644 x/ibc/23-commitment/types/commitment_test.go create mode 100644 x/ibc/23-commitment/types/errors.go create mode 100644 x/ibc/23-commitment/types/merkle.go create mode 100644 x/ibc/23-commitment/types/merkle_test.go create mode 100644 x/ibc/23-commitment/verify.go create mode 100644 x/ibc/alias.go create mode 100644 x/ibc/ante/ante.go create mode 100644 x/ibc/ante/ante_test.go create mode 100644 x/ibc/client/cli/cli.go create mode 100644 x/ibc/client/rest/rest.go create mode 100644 x/ibc/handler.go create mode 100644 x/ibc/keeper/keeper.go create mode 100644 x/ibc/keeper/keeper_test.go create mode 100644 x/ibc/keeper/querier.go create mode 100644 x/ibc/keeper/querier_test.go create mode 100644 x/ibc/module.go create mode 100644 x/ibc/spec/01_concepts.md create mode 100644 x/ibc/spec/02_state.md create mode 100644 x/ibc/spec/04_messages.md create mode 100644 x/ibc/spec/05_callbacks.md create mode 100644 x/ibc/spec/06_events.md create mode 100644 x/ibc/spec/README.md create mode 100644 x/ibc/types/errors.go create mode 100644 x/ibc/types/keys.go create mode 100644 x/ibc/types/mock.go create mode 100644 x/ibc/types/utils.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 84555f11f9da..59e22714749f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -79,17 +79,27 @@ to now accept a `codec.JSONMarshaler` for modular serialization of genesis state * (crypto) [\#5880](https://github.com/cosmos/cosmos-sdk/pull/5880) Merge `crypto/keys/mintkey` into `crypto`. * (crypto/hd) [\#5904](https://github.com/cosmos/cosmos-sdk/pull/5904) `crypto/keys/hd` moved to `crypto/hd`. * (crypto/keyring): - - [\#5866](https://github.com/cosmos/cosmos-sdk/pull/5866) Rename `crypto/keys/` to `crypto/keyring/`. - - [\#5904](https://github.com/cosmos/cosmos-sdk/pull/5904) `Keybase` -> `Keyring` interfaces migration. `LegacyKeybase` interface is added in order + * [\#5866](https://github.com/cosmos/cosmos-sdk/pull/5866) Rename `crypto/keys/` to `crypto/keyring/`. + * [\#5904](https://github.com/cosmos/cosmos-sdk/pull/5904) `Keybase` -> `Keyring` interfaces migration. `LegacyKeybase` interface is added in order to guarantee limited backward compatibility with the old Keybase interface for the sole purpose of migrating keys across the new keyring backends. `NewLegacy` constructor is provided [\#5889](https://github.com/cosmos/cosmos-sdk/pull/5889) to allow for smooth migration of keys from the legacy LevelDB based implementation to new keyring backends. Plus, the package and the new keyring no longer depends on the sdk.Config singleton. Please consult the package documentation for more information on how to implement the new `Keyring` interface. - - [\#5858](https://github.com/cosmos/cosmos-sdk/pull/5858) Make Keyring store keys by name and address's hexbytes representation. + * [\#5858](https://github.com/cosmos/cosmos-sdk/pull/5858) Make Keyring store keys by name and address's hexbytes representation. ### Features * (x/ibc) [\#5588](https://github.com/cosmos/cosmos-sdk/pull/5588) Add [ICS 024 - Host State Machine Requirements](https://github.com/cosmos/ics/tree/master/spec/ics-024-host-requirements) subpackage to `x/ibc` module. +* (x/ibc) [\#5277](https://github.com/cosmos/cosmos-sdk/pull/5277) `x/ibc` changes from IBC alpha. For more details check the the [`x/ibc/spec`](https://github.com/cosmos/tree/master/x/ibc/spec) directory: + * [ICS 002 - Client Semantics](https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics) subpackage + * [ICS 003 - Connection Semantics](https://github.com/cosmos/ics/blob/master/spec/ics-003-connection-semantics) subpackage + * [ICS 004 - Channel and Packet Semantics](https://github.com/cosmos/ics/blob/master/spec/ics-004-channel-and-packet-semantics) subpackage + * [ICS 005 - Port Allocation](https://github.com/cosmos/ics/blob/master/spec/ics-005-port-allocation) subpackage + * [ICS 007 - Tendermint Client](https://github.com/cosmos/ics/blob/master/spec/ics-007-tendermint-client) subpackage + * [ICS 020 - Fungible Token Transfer](https://github.com/cosmos/ics/tree/master/spec/ics-020-fungible-token-transfer) module + * [ICS 023 - Vector Commitments](https://github.com/cosmos/ics/tree/master/spec/ics-023-vector-commitments) subpackage + * (ibc/ante) Implement IBC `AnteHandler` as per [ADR 15 - IBC Packet Receiver](https://github.com/cosmos/tree/master/docs/architecture/adr-015-ibc-packet-receiver.md). +* (x/capability) [\#5828](https://github.com/cosmos/cosmos-sdk/pull/5828) Capability module integration as outlined in [ADR 3 - Dynamic Capability Store](https://github.com/cosmos/tree/master/docs/architecture/adr-003-dynamic-capability-store.md). ### Bug Fixes diff --git a/client/context/query.go b/client/context/query.go index 4d335c85d512..0dbb0fd6899d 100644 --- a/client/context/query.go +++ b/client/context/query.go @@ -103,8 +103,7 @@ func (ctx CLIContext) queryABCI(req abci.RequestQuery) (abci.ResponseQuery, erro return result.Response, nil } - err = ctx.verifyProof(req.Path, result.Response) - if err != nil { + if err = ctx.verifyProof(req.Path, result.Response); err != nil { return abci.ResponseQuery{}, err } diff --git a/client/lcd/statik/statik.go b/client/lcd/statik/statik.go index 48a9278324ee..0639033f1870 100644 --- a/client/lcd/statik/statik.go +++ b/client/lcd/statik/statik.go @@ -8,6 +8,6 @@ import ( ) func init() { - data := "PK\x03\x04\x14\x00\x08\x00\x08\x00\x00\x00!(\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x00 \x00favicon-16x16.pngUT\x05\x00\x01\x80Cm8\x00\xbd\x01B\xfe\x89PNG\x0d\n\x1a\n\x00\x00\x00\x0dIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1f\xf3\xffa\x00\x00\x01\x84IDATx\x01\x95S\x03Luq\x1c\xfd\x8c\xf1\xc3\xec0\xa7)\xcda\xb6k6\xb2\x9b\xf9\xb2k\xc85/\xdb\x8dqx\xc6\x94m\xcc{\xef\x7fO\xff\xf3l\xdc\xed\xf2\xe0\xfe\xf8\xc9\xffP\x14\x11/\x14[\xa3P\xc4\xa1\xbc?\xf1t>7\x12s\x13\x03\x85\xca7IR a\xb5j\x8f\xa71\xbe]\x88\xf6\xb9L\xf0\x1c\x93\xcf\xda\xe3)\x10\x93f\x8d\xe4\x06\x13\xcf\xde<\x9b\xd14\x95\x8a\x92\x81OA\xcfF\x89\xdd<\x9b M\xe6}L\xe4\x07\x15\xc5\xf5\xe3\xffI\x0c{\xd6\x8d\xffs\x994\xbasfh\xae?\xafk\x1aprw\x10 <\xb9\xdb\xc7\x86\xa6\xd1\x19I\n\xa8\xb1\xd7\x84y3g\x171T$\xb5c\x7fq\xfbbq\xbfk\x8e'\x1dQ\xb0\xc2,\x92\x0bx|;F\xe5\xf0\xef\x00\x83\xf2\xa1\x1fx|?q\xbd\xcb\xc2\x16\x80ZF\xf0\xc4J\xf3\xe3\xe4n1\xcc\x17k`:}\xcby\xe8\x98\xcbB\xc7|6z\x97r\xd14\x9d\x06\xd3\xf9\x8a\xe4\x94\x90\x8b\xb6\xd9\x0cP\xebc@\xd0|\xbe*\xc94\xc8\xa7\x98'\xcdh\x00\xe3\xd92\xa6vK}\x0cB\xa4\xf0+D\n\xc7\x81)\xb0\x10\x9a\xe3\xa9\xd8\x8bx\xe4(\xa2\xbb\x8dl\x0d\x01\xb6\x8a-\xf378\xbe\xdd\xc7\xa6\xb6\xc9\xd9\xc6d\xd8\\m\xf4\x0c\x92 uQ\x0e\xd2\xf5\xb3\xd1\xf1w\xdfQ\x16\xb34a$\xa1\xc4\xc4(V\xbcF\xd9\xdf\xa4\x91\xe9\xb0&,\x12+\xcd\x93\xcf\x1c\x1cb\xdc\xca\x00qt\xeb\xcc-\x14\x89\xfe\xfc\x0fm2j\x88\xec\xccs\x18\x00\x00\x00\x00IEND\xaeB`\x82\x01\x00\x00\xff\xffPK\x07\x08\xd4`4t\xc7\x01\x00\x00\xbd\x01\x00\x00PK\x03\x04\x14\x00\x08\x00\x08\x00\x00\x00!(\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x00 \x00favicon-32x32.pngUT\x05\x00\x01\x80Cm8\x00u\x04\x8a\xfb\x89PNG\x0d\n\x1a\n\x00\x00\x00\x0dIHDR\x00\x00\x00 \x00\x00\x00 \x08\x06\x00\x00\x00szz\xf4\x00\x00\x04|ID\xc4\xcf\xd0@\x04&%\xad\x1e\x16\x0f\xf7\x8d\x97AR\xfa\xca\xe7l\x87\x05\xf8\xd2\xfb\x0c\x84\x1d\x0dLVY\xdc/ju\x13\x1a\x88\xd2\xa0\xaaa\x82|nzp_\xf4\x03\xc8 \xd4;^\x8a9}\xeeu\x9a\x91 `\x04\x14s\xec\xe1\x0c\xc6]\xa3\x05``\xd1w\x12*~ \x00\xf3\xae\xd3\xa0\x9cb\x82\xa2bx(\xb3n\x1fqx\xd2\xf2\xda4\x1d\x8a}\x1ck\xd4>\x9cI+\xeb\xb3\xf4k\xc8u`L\x93\xf3]4\xb5\xd0\xc3\xe33\xd9\xee\xd7\xf2\xd9\x19\xea\x18\xc9\xc1Y:\x18\xfb(-\xadN\x82\x06e\xd5\x1f0\xa2\x1dV\xf8\xbe0\xc1\x985\x01\xf8\xd2~\\\xa6\xa5\xb5)&\xf6\x98V\x80l\xe4\x03\xf8\x03\x04\x00s\x9a^\xec\x85\x00\xf4+\x0b\x00\xe1:G\xf2p\x96\x0e\xc4,\xe46\x1e5\xbbP\xdd\x15J\x80}\xce\xa4\xe2\xc8{m\xa4\xe2\xc3\xc2\x01\x07\xc0\xdb\xa4\x18-\xa1\x931\xba\x10S\xfa%\xb6P`\x10\x19v\x99#|Gg\x9b \x10W\xf6\x8dI1\xba\x92\xd66\x17E\x12\xfa\xd9\xa8\xf3UTe\n\x1b\x95\x9d\x81f\xe5\x18\xa5umc\x81\x86\xa6\xeb\xec \x804\xcbg\x17\xa19\xfa\xc6\xf7<\xa3\xbd\xf2\x0e\x7f\x02\x80\x97Y\xc7\xac\x184$h\xa3v\xba! \xcc{\xcd\xb4!\xb1\xd8\x92%h\xe3\x93\xdc\xd3_\xda1\xe6\xaei\xcf\x83\xa6p\xbc$\xf0\xb2\xda\x94\xa2q\x14B@\x13\xdb\xff\xf3\xd7\x0d\xfaA\xb9\xc5n{\x8e\xd6Y\x08\x01u\xc1'~\x16\x8e\xe9\x04\xa2\xfbA+\xc74\x0c\x98\xab\xd7:\xfc0\xd1v\xaf$\xa2#\xb7\xf1\x08\xfdm!OXh8\x10j|g\xd1\xe0a\xb2\x99\x04\x9a[y\x9a\xbdk\xf24C$\xa0\x9e#\x9f\xa3\xa8\x001\xc6\x1a\"\xc0\xe4i\xa6\xcc0\xf3\xf7\xb7\xf5XE\xb8\xe0\xa1\xc9\xc2\x0c\x90\x83\x80$\x838\xdf\xd6\xe3\xd4\x82FNG\x0f\x876\x8a\xbf1\xa8d(\xa7@\x8cQX\x90\xdb\x19\x9f\xc5YG\xe9\x9e\x00\xa5y3]\x9aJ\xe1\"\x00\x00\x00\x00IEND\xaeB`\x82\x01\x00\x00\xff\xffPK\x07\x086B\xc8\xd7\x7f\x04\x00\x00u\x04\x00\x00PK\x03\x04\x14\x00\x08\x00\x08\x00\x00\x00!(\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\n\x00 \x00index.htmlUT\x05\x00\x01\x80Cm8\x9cT]k\xdc:\x10}\xdf_1Q\x1e\x92\\\"\xfb&\x81p\xf1\xb5\xfd\x90\xa6\xa5\x81\x94\x06\x92}(\xa5\x14\xd9\x1a{\xa7\x91\xa5E\x92\xf7#!\xff\xbdX\xf6\xae\xb7\xdd\x90BYX\x8f\xe7\x9c9\x1a\x1d\x8d\x9c\x1ep\x0e\x1f\x1f>\xddBe,8/<\x95 \xc9yKE\xeb\xc9h(Z-\x15B\xd1\x92\x92\xc0y>I\x0f\xae?\xbf{\xf8r\xf7\x1ef\xbeQ\xf9$\xed\x1e\xa0\x84\xae3\x86\x9a\xe5\x13\x80t\x86Bv\x01@\xda\xa0\x17P\xce\x84u\xe836}\xf8\xc0\xffc\x03\xe4\xc9+\xcc\xef\x97\xa2\xae\xd1\xc2\xf4&\x8d\xfbL\x8f*\xd2\x8f`Qe\xcc\xf9\xb5B7C\xf4\x0c\xfcz\x8e\x19\xf3\xb8\xf2q\xe9\x1c\x83\x99\xc5*c\xae\xd7\xe0-E!\xbb'A\xa5\xd1\x9bbjD\x8d\xf1\\\xd7\x9b\xeaJ,:\x9c_\x9c\xaf.\xce\xa3\x008zB\x97\xb1\x90a\x10\xff\x9d\xde\xd9\xe5\xea\xec\xf2\x17\xbd\x90\x19\xf5\xc2\xc6\xfa\x18\x82\x9bC\xf8<<\x01\n\xb3\xe2\x8e\x9eH\xd7 \x14\xc6J\xb4\xbc0\xab\xff\xb7\xb8Y\xa0\xad\x94Y&\xc0\x1b\xf3\xc4]i\x8dR\x85\xb0\x8e/\xd0z*\x85\xda\xe7\xf2u\x02=q\x83\xbdL\x86\xe0\x9f\xd3M\x90\x14X\x19\x8b\xe3\xbb\xa8<\xda7\xfb#=CK~O\xb40r\xbdW\xd8\x08[\x93N\xfe\x1d\xdb+D\xf9X[\xd3j\x99\xc0a%\xba\xdf(\xd5\xfd\xa7\xf1\xd6\xaf4\xee'\xac\x0b;\xf9\xc1OI\x0b \xb9;\x0e,OcI\x8b|2\x18^Z\x9a{p\xb6\xdc%\xf1~\xc6\xa3\x1f\x8e\xe5\xdd*\x81\x94\xbfY\xe1\xbc\xd0R(\xa3\x91\xcf-:\xf4o\x14\xf7/K\xd2\xd2,#\xa3\x95\x11\x122\xa8Z]v\x17\xec\xf8\x04\x9e7N\xc51\\\x85{&\xc0\xad\x9d\xc7f\xc8\x97F;\x0f-A\x06\xc3m\x99\xde\\\x85\x9e\x8fGG[\xab\x12`Q\xeb\x8c\xd8v\xfb_}K7\xd3F\xfe]\xb1\xa1\x82h%q{\x8b\x9b6\x88/\xc4i }\xc07u~}\xe5\xad\xfd\xc9\x98\xe7q\xd8_}o\xf1\x92%\x9dx\x15\x9f\xd3yO\xbdX]\x1aA\xc9>t\xd6o\x93\xd3\x92\xf2\x04l\xc5\x8d\x92jz\xc1jN\xd6\xf2\xa9\x87\xfa\xb5]\x05\xcc\xf9\x1acB\xa9,\x9f\xd0\x08\x05\xb7\x962\xec\xdb\xb6\xe2\x16b\xc6\xd5\x942H\x05KfI\x06\x7f\x9c\x98\xa8\xc0\xd5\x9c\xa2\x0c\x13\xa3\xe7U\x8e\xb55;'Nk\xe6\xd0\x9d;\xd4%^\x14\xbd\xd5\xf7\x92QN\x8e.\x1c`\x079m\xe3\x9e\x8a\xfe\xed\xa2\xad\xe0y>\xe6\xe23\xdc\xf8u\xa7=\xa3\xf6\xa1\x98\xb4\x17g\xa9\xf4\x1dA\xa8Z\xe4\xf6\x88_\xfc)\xf8\xd5N\xcf,\xea\xb4\xabS\xf2\xd2\xe0v\x10\x90\x82\xbd\xb3\xe1\xc1g\xc8>\x120\x0c{\x1d\xbd\x1c\xd1\x7fd\xb4\xbf\x82|\xf7\x9f\xd0\xa7\x1e\x82\xc5`H\xc0\x94F3p0$H.\x0f]v3\xaa\x9b\x1c\x83EW}\xba4\x12O`_\xb5!H5\xd1 \x9a\x0c\xaa\xcd\x04\x8cE\xe7M:\xe1\x08\xfe\xefQ\xab\x02\xfe\xb7A\xeb\xb6k\xbb\x05{\xef\x8e\xde\x84\xcb\x9c\xb2\x8f\x04\xd7U\xf9\x9aQ:\xbe\xf51\xf1\x1a\xaaW\x97uR\xdd\xe7\xf59\x974\xb7\xfc5s\xd0\xc4P\xdf\xdd\"\xd7\x96\xc2\xdab7x\xb8;\xfc\x01\xfa'\x00\x00\xff\xffPK\x07\x08]\x12r 9\x03\x00\x00T \x00\x00PK\x03\x04\x14\x00\x08\x00\x08\x00\x00\x00!(\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14\x00 \x00swagger-ui-bundle.jsUT\x05\x00\x01\x80Cm8\xec\xfdyw\xdb6\xf68\x8c\xff\xffy\x15\xd7\xfa\xf6\x9b!kZ\xb1\x9d\xa5\xad\x13\xc5\x93\xc5m\xb3g\xe2\xa4\xcb\xa8\x1a\x1fZ\x82,6\x14\xa8\x90\x90m\xb5\xf2\xef\xb5\xff\x0e.\x00\x12$\x01\x10r\xdc\x99\xf9<\xcf\xc3s\xdaX\\\xb0\\\\\\\xdc\xfdn\xc1tI\xc7,\xc9h@\"`!\xfc\xf9?\x00\x00\xbd\xec\xf4w2f=\x18\x0c\x80\xad\x16$\x9b\x02\xb9\\d9+\xe0\xd6-\xd3\xd3y6Y\xa6\x04\x0e\xe5\x1f}\xf5\xf6\x00X\x10\xc2\x01\xf4T7\xfaG\x132M(\xe1-\x8a\xbf\xfa\xf1|\x02\x87\xf2G0\x1c\xe1\x80\x0e\\\x839T\x7f\xf5\x8f/\xe2\xb33\x92\x7f|\xfedI'));&\xe6'\xffs\x15\xb0YRD\xd5\xf4\xd5\xd4s\xc2\x969\xd5\xc0\xa2\x1e\xf0\xeb<\xce\x81\xc1\x00\xfe\xbcz\xf0?\xe5M\xf5*\xd0 \xd7_\xe6W2\x85\x80\x0d\xf3Q\xa8\xda\xe5?\x14t\x1e\xd4^\xe5mg|t\xc3|\xc4\xbb\xa8=\xc4\xb6\x0e \x8fZw\xd3\x03\xd8\xdak\xdf\x96]\x1c\xc0\x9fW\xb5gW\xf5N\xe5\xa8\x08\x1f\xd58N\xd3 S\x83\x8b \x8b@\xfbEC\xfe3\x85\x01l\xedj\x0f\xca\xd6\xaand\x9b\xb4?\x87\x01\x90\x08h\x7f\xcc\xa7\xc5\xff\x98\xc0\xa0\x8ep\x11\xb4@F\xfb\x99\xc4\xc5\xf5\x1a\xde\xe2\xd2\xf7\x05J\xbc\xcb\xb3\x05\xc9\xd9J~\xd9\x86\xd08\xa3\xd3\xe4l\x99\xc7\xa7)\xb1\x80\x85.\xe7D=\xdfm??#\xec\x00\xf2:\xc4\xc2j\x8e|\x0e\xb46\x87\xe6\xe8\x15\x86 Z\x93\xfe\xc9 )^\xab\xbd\xd1\xc25\xfdR+\xc1\xe7\x1a/SV\x1f\x03\x1c\xf8}\xed\xb1\xd6\xb4? X\x04\xbd\xb8\xc7\x81\x1c\x01\xabO/k.Q\xb3;\xd9\x8c\\\x99E\x9e\xb1\x8c\xef\xca\xfe,.\xde^P\xb5F\x02\x9b\xf0\xfbz\xfb\x0b\x18@\xef\xf6$)X/\x02\x1a\xd0>'\x12w\xef\xde\x13\xaf]\x05\xc3\x06~P\xbd\xff\xde\xb2 P\xb0<\x19\xb3^59\x9d\xdc\xd0\xe0\x1b\xd5T\xd4D\xb5ZS\xf5\x8f\xbe\xbdw'\x0c\xbc\xbe3\x0f\x81\xe9+-\xb6\x08S+\xd9\x05PN#\xb6\x02\x02 -XL\xc7\x9c\xbe\xb10\x046\xcb\xb3\x0b\xa0\xe4\x02>\xac\x16\xe4(\xcf\xb3<\xe8=\x8d)\xcd\x18p\xe0B\x0c\xe34.\n\x88\x0b\x88\xcb\x1ezacG\xde\xcct\xaaG\x1c\xc1\xf3\x08)\x15\x0d\xf6\xef\xef\x87\xf5M\x94\xc0\x00\x82\x1c\x06\x90\x85|\x07\xe4\xf5\x1d\x90\xc3\x81\x01y%\x9cZ\x1bO\x1f\x8f\x01\x96M8\x96t\x98\x18\xc1\x8c\xafd9\x04|\x06|\x13\xef>\x00\n\x0f\x81\xf5SB\xcf\xd8\xec\x01\xd0\xedm\xd3G\xa0f\x8d\xc4\x99\x8e\x1e\x18\xdf\xc8\xfb\x15m\x81A\xfd\xe7z\xcd\x89\x11\xe4}\x9d@I4\xe9\x9d\xc7\xe9\x92\xf4 \xa1\x90s\x88\x05y\xff\"OX\xf9F\x18A\xb0\x1bA\xa2 \x10\xf2\xc9\xe5\xfdOd\xc5igk(\x0djo\xda\xb9%\x009.\x18\x08\xb0\xf6*E*\x16h\xdb\\\x1c\x04\xb9\xbc\xcf\xbf\xd6)H\xbd\xcf+\xbf\x1d\xa5\xef\xc4\xfaHJ\xc4\xa0\xc17\xf7\xef70\xadB,N\xca\xff\x9dX\x7f\xf7\xde\x7f\x0e\xe9\xad\x04\x84\xe8\x14\xe3=\x99\x92\x9c\xd0\xb1\"\x1b\x9c\xd7\x81Y\\\xd0\xbf18%\x84BB\x13\x96\xc4iR\x90 \xec@\xb1\\\x90<\x08kop\x12C&\xbd\xd0x\x86l1\x8e\xd3%c\xb65\x18@p\x9e%\x13\xd8\x85\x01\xe7\xd2\xe0\x10zK*N\xedI\x0f\x0e\x9a(\xcc\xe9\x1bg$+\xaep\xab\xe4\xed\xf8\xc7\x04\x0e\xf4s\xe9\xaf[R\x18@\x1cp\xec\xfa6l\xaci&\x1f\xdd\xb9\xfb]\xf3Q\"\x1f\xdd\xbd\x17\x86&>0n\xb3\x05\xea|6p\x05\xc4\x8d\x1e\xc4\xb6\xb9\xae\x87'\x16\x90\xdf\xba\x05t\x99\xa6\xb8\x92\xccr\xf6\x1cs,\xe1\x8ceN\x8a\x82\xcfs\xbe,\x18\x90\x84\xcdH\x0e\xa7D4\x90\xe5\xdaa\x14\x01?\xacz\xb0\xbd1v4\xd0\x8eT\x04\x88o5d@\xab\xd7\xf9\xe8k$\xca\xc8\x19\x16,_\x8eY\x96\x9b\xa0\x0d\x88\x0f\xe9\x92\x1c\x00i3\x85\xd0d\x1c\x0d\x8c%\xbf\x14\xdd6\xb3\x96\xd0fPw[/5\xc87'\xae\xf2PPk|\x88\xd3\xcfk\xc7\x01\x13\x92\xce\xc9 \xc2\xe0\xe4\x84\x1fT\x1b\xf2\x01\xb8\x1b*\xa0\xe7\xae\x83\xd6\xbc\xd5T+|\x85\x1e\xe7y\xbc\xd2x\xc3\"M\xc6D\xdb*\xa0o\x17f=\xae\xc5\xdc\xeb\x8b/\xf9\xceqNbV;\x99\xc20\xd2\xf1\xa4\xaf-9\xe7\xc7\x1b\xdb\xc8<\x14\x03C\x0f\xd5\xee\xc5}-6\xec\x8b\x80\x84^-\xe6\xce\x16\x97U\x8b\xbf\xfa\xb6\x989[,\xaa\x16_\xfa\xb6\x98t\xcf\xfa\xd6-\xd8J\xab\xa6\x7f\xf0m\xda@\n\xb5\xa6\xb7\x82-\xc1\x1c\x91\xe1t\xe4\xd7\xe0\xd2\xb7\xc1\x85g\x83\x85o\x83\x13\xcf\x06\xd3\xee\x15_\xaf\xb1[\xaf\xe6\xc6\xbe\xe3\x9b\xb5\xc6\xa7\xffbA.X7\x16d\xea\x8fD\xfcA\xfbI\xf1\x9c\x95\x9ck,\xee\xbc$+\xc2\xc5\xf5\xa5|\x81N\xc8%\xde(\xc4\x8d\xc7E\x91\x8d\x93\x98%\xe7\xfc\xa3T\xdc|\x9bOH\x8eo\x8d\xf9\x0d\xd5\x06\xef\xba_\xb5\xc0\x07\xd0?&\xfc\xbcJ\xda\xf4c\xca\x05\xc4\xbf\xff\xfd\xe4\xe4\xf9\xeb\xd7\x1f?<~\xf2\xea\xe8\xe4\xf9\x87\xa3\xf7\xf8\xc7\xc9\xdf\xff\xdekS\xd6E\xfb\x8b\x97G\xbf\x1e=\xb3\xbc>1t\xf0\xe6\xd9\xd1/\xd6\x0ff\xed\x0f\xde\xbe\x7fv\xf4\xde\xfa\xc19\x0c\xe0^\xfb\xf6\x1c\x06\xb0\x07\x0f\x1f\xc2\xb9A\xf1\x00\x03\x98\xc3\x0e\x18\x8e\x96\x15*\x9c\xda\xf7O\x8dZ\"\xa8\x8e\xb2\xad\xbd\xd6SC3'\xd7i\xc6F\xcb/\x9c\xd8J\xfa\xd8$g\xc4\xf6\"O\x92|dn\x91\xc8\xa3\xa1lp\xd7o;]\xf2\xd3\xcc\xf6\xf0\xd8q\x12q\xbee\xbd\x86\xdd\xb6\xf4W\x13*_\xc7l\xd6\x9f\xc7\x97\xfc\x90&R\xb2\x84\x1dT\xb4\xf0c\x88\xb3Tx8\x06\xa8O\x13Rh\x06\x0f\x81>\x80\x8c\x8b\x9f\xf90\x1b\xf1\xe3j\x98\xc160\x83\xac)A\x99{\xcd\xf6\xa9s94\x9e\x8c\xf4\x8b\xe4\x0f\x05S\xfcs\x80\x0cE\xc2\xe9\x02#\xc1cq\xba\xf2'^\x1d\x7f\xb2B\x12\x99P\xba\x9c\x9f\x92\xbc\xc6\x82\xba$o\x8a\xd0\x7f\xf4\xe8\x91 \xfc\xa0\x1a\xe5|&\x15\x1c,_\xa9\xbb\xfb\xdf\xdd\xfd\xee\xfe7\xfb\xdf\xdd\xc3\x19\xd2R\x05\xfb&~cn\x85/2m\xe3\xba\x0d|\x0c\x1e\xc2.\x1c\n o\x03\xab\xc9,\xe0\x00\xcec\x97\n\xaf\xc1\x14\xda\xdaxkb\xe2\x1aM\x05rm94\xe4Zs\xe8\x08\xa1\x1e\x1e\x0e`\x87\xe2\xc9^g\xce\x0d/3x\xc4\x01\xe85\xb0w\xd6\x95\x97\xa3z-G\xee\xb9a?\xf8\xb6\xc7\xfc\xda{\xed\x018}c\xc0!P\xce]\xcb\xc5\xd6\xf77\x83m \x9c\xf5n\x087\x9cC\x12\xef%\xa8di\x9d\xf4\xfa/\x8e\xdf\xcf9\x1dhS\xe6\xdf\xf9y\xd1\xbe\xfd\x06\x06\xb0\xdf\xbe\xfd\x9e\x9fR\x95tW\x19K\x8eW\xf3\xd3,\xe5\xeb(\xfe\xea\x8bM\x9d\x19\x8c \xcf\xc4I\xa7^0\x1cm\xaf`\x00\xef9\x8e<\xb3\x1d\x01\x1f\xcd4\x87\xcd\x92\xa2O\xc9%\xf3f\xc6?\xab\x95\xb2\xe8\xa8\x94\xc1\xa4Z(\xbe\x05\xf7j\xcb6\xe4\xdf;\xa8(\x1cB^\x9e!\x19\x1c \x91v\x9e\x86\x99Y\xb2\x9bd\xd4v\xe2z\xd2\xea\xef]T\xc19$\x81~\xcequJ\x9a\x96A\xfd\xe1\xe6>\xb7~\xf4ec\x9f\xb8\x19\x83\x866H\xb3\xf4!\xcexu\xf1\x93\xb9\x0be\x91\xe1C\xb5\"\x82\xd4!\x08\xa3\x85\xdf\x8c~tw'\x0e\xd3\xf7Hk\x87\xefG|\xcb\x90\xe1\xb3\x91a\x08\x0d\xb5\xcc@?\x13\xd5\xf0\xbcF\xf4\xb3\x07\x8c\xd5\xc9\xabCXp)^]\xbcpv\x81\x1a\xa0\xe6\x91\xa3\xb6cB\xd0 \xab\x84\xe8>\xcb\x8e\xc9g\xbc\xa5Z7\xb7\x0d\x1aP\x0b\"\xc5'\x93M\x18\x95X\xe4\x02\x181\xae4(M\xa9M\xbfut\xb9 cF&\x82A\x83,\x87DIE\xa27\xc8\xa6b\xcb\x15\x11\x7f\xfa \xa5\x1b\xf1\xe8\x00\xb5\\\xb6n\x8d\xab\xc8\xaf+_d\xfb\xf5\xcb\xe0\xdeg\x19\xcab\n\xe2r\x11\x96\xed\xb5 \xfdi\x9e\xcd\x8f(\xcbW\xe5\xcb\xc4w\x94/\xbfl\x94\x86\x81\x11} |\x9cR\x8aT\xb7\x96\xdec\xfb\xc19\xb6\xe0\xcb\x07\xa7F\x13\"4\x19\xdeo\x8cL\xff\xf5QSU\xb1\xec\x98\xe5 =s)\xdd\xb4\xc1\xf6\x86\xcf\xe5\x01=\xea\xd5{\x88\xe0c\xff\xe5\xd1\xaf\xc70\x80\xe7\xfc\xef\x9f\x1e\xbf\xfax\xc4\x7f\xfd\xce\x7f\x1d\xbd\xf9\xf0\xfe9\xfe|\x13\xd5\xfaOh\xc1Q\x1f\x06\xcdQe\xcb|Le\xf2\xd9\xb3M\xd3\xd8^\\\x7fQ\x11|''%\x00{|$\x7f\xf6\"\xe8]\xf5\x9cc\x1e\xc7\xe3\x19yO\x8a\x0e\xeb\xa8\xd6\xd5\x96\xe8\x0b?\xc4sOt-e\xbd\x8f\x14\x1fL\xf0\xfc\xd2\xdf\x1c\x88\x17+\xac\xef\xb3L\xc8\xb2a$\x1eI\xc1Q\xfbH\x9e-\xf2\x05\xd74\xca\xfe\xbb\xac\x18\xdaDR\"\xbdx\x04\xa3\xd8\xd2\x01\x98{\xc8\xf2\x0d\xba\x18wv\xc1\x82_#x\x11F\xf0km\xf1\x15\xbd\xf5\\\x133\xa6\xbf\x14-\xbf\xf4\xc7\xf4\x97\x0eL\x7fY\x1b`EI=\x9b6\x0d\xf1\xe5\x0d#\xfc\x90#\xfc\xa8\x8d\xf0/o\x18S\xf6\xbcz\xf8\"Liw\xc1\x82\x1f\xc4z\xfe\xe0\xbf\x9e?8\xd6\xf3\x87\x06\xe5b_\xb6\x96/\xfaI!Z\xc8\x08\xff\xa5\xb4\xb7\x1c\xbd\xa5\xba\x96\x8f_S\xe4\xbelko\xbf\x8a\xe0\x9f\x11\xfc\x12\xc1?\xdaJ\xd3\xe3\xa3\x7f\xa0\xc2\xd4&9\x12\xe2\x10\x1dOb\xe4\xca\xd0\xa3L'6\x1b\xb1\xaf\xcc\xd2\x83\xe2/\xa5q\xe9\x13Y\x15F\x1eR\x8cDr\x83\xd5PN\xf8\x07\xc2\xc7\xadF\x077\x19\x1auN>\xa9\xf4\xf3\x96\xf9\xa3\x80\xe1\xaf\xa0\xcb\xbb\xbb\x93\x86\xb3\xa8q\xef\xa9<\x0c\x86#\xaf\x8e2KG\xea,\xaa\x0c\x18\xff\xf04\xb0 7fm\xf0+\xdeZ\xf0\x95\xd4\xb5\x12\x12\x0cG\xa1_\xbbq\x07r\x08\xa3fR\x883\x0fy@\xd9\x05 \xdb\\\xf3\x93\xea\x8d\xdc\xfc\xc6\x1f\xd5\x1b\xd4\xfc\x86Q\xca9\xac\x84\x9cR\xf5d\x16*\xbfL\xd2\x19~\x8a\xe0|\x04\xfc\xb8O6\x92x6\x92Y\x97\x1d@/\xcc\xc2\xdc\x97OO\x08r74\x8b\xc2\x8d\xe4?7\xb0\xc5\x80\x1e\x06|(W\xd7k\x08)\xf1T\x97\x11\xc9\x9a\x99\x81\x9a\xd9D\xf0\xd2\xca\x91\xf0\x03\xa2\xb2l\xecE\x10\x0b3F\x0c\x0f\x07\x90<\x80\xd8\xeeF\x07r\x1cK\xde\xc6\x90r\xd1\nv \xe6\xb2\x95\xc5\xad\x0e\xd4b\x0b\xbd\x1e\x0b\x96\xc3\xbdQ\x84\x8a\xbb\xe5pw\xc4\xbf\x8c\x80\x84\xa5\xa6$\x86mh+\xe1\xa0%~\xa9K}\xd6zhU\xfb\x936\xab\x8c\x9et~Df\xfc\x17/\x93q\x85\xac\x90\x15+\xe7\x02\x0c\xc7\xc6\x8f\x81\x93\xa5P\x97r\xfe\xf0_X\x05\xfc\xedmx\x04 \x1c:\x1a\x07?u\xa7\xba\xacjOu]\xc1\x01|F\x07F.\xcaKL\x12\xe8L\x86{\x8d\x93\xa8\xfc\xa8}\xdb\x03M\xb2\xfc\x1ax2\xb5;\xb1*\xca\xa4y\x94\x0b_L\x8eR\x11XQ\x83\xe3M\xfd\x0c\xa3\xd5\xbe\x91\xba\xcf\x0c\x9bx\x19\xd0\xb0?\x8f\x17\xd5\xba\xbb\xda\x05m\xd2\x08Q\x0c\x1d\xa06\x10:Ts\x13b\x1d\xd2\xaf\xff\x81!\xa9-\xd0^t\xb4\xeaD\xd0\xeb\x99|\xcd\xf8\xd5\xeb5=\xf7\xf0;N\xd3\x17\xde*\xab\x85\xfbT1\xf0#/9\x1b\xc1\xa1\xb4 \\:\x7f\x95\x14\"\nfB\xc4\xf3_\xeb\xcf_\xc7\x0b\xa1\xbb\xf2\x1a\xce\xc4=\x1ce=\xae\xf9]\x0d\x14O\xdd\xd4\xaa\xe9\xaf\xf9Acf\xdf\x11\x1cwHe\xbe$\xb0%\xf5\xef\x0c-\xcc%Fm\xd9\x18%\xc1\x82j/\xeem\xa0\xa6\x97N\x08o\xa7V#\x06So\xb8\xb6f \xb8y\xf9f\x10\x868\xa1\x00=\x0f\xf4\xbb\x9bN\x10\xec\x93\xf4\xa7f[f\xc7Q\xd2'\x9f\x97qZ\xa0J\xde\xf4\x02\xd3^\xd8Ro\x07\xcc\x93#?\xf7Z\xf2\xee\xe5\x8d\x03\x11M\xa4\xd9\xb5+\x87\x07\xed&+o\xca\xc7\xda\xcd\xe6\xe7''\xb3\xb8\x98\xb5\x1a\xa8n\x97\xaf\xd4\x1e\xac\xd7B\x7f\xcco.\xe5\xb0\nu\xa3\x907\xc6\xea\xc6\x18=\xa5;\x90\xb2\xe9\xc1!\x0d\xd1\xf8\xdb \x1b\xe5Z\x81\x9e}\xe6\xb6\xf9H\\\xac\x06J\x88})#\x04\x1d\xe6\x8f>9'\xf9*\xe8T\xa8\xa8K\xb1B9\xda\x00\x83P\xec\x82Nv\"\xe3@\x98\x91 CNQ8/\x06\x94\xc3\x15o\xeeb\\\xa1\xed(\x00\xf4\xdf\x97\xfdq.\xc2c\x8f\xa8q\xda\x16\xa8\xe5gc\xee\xbc\xf1\xaaZ@\x0b\xcd\xd1\xd5\xbe\x88m\xda\x0d\xdbB\x90\xb4 \x0exg\x0d\x0f\xf9\xe6\xa5xK\xc7\x12\x10\xa9\x05\x81\x01$f\x08\x1b\xa17\x15\xc10\xc6/\x16 \xb6\x8frE*\xd1\xc7\x14<\xa8_\x1c\x9e\x9c\x13\xdd\xc2\xd8\xb4\x00\x9d\xa43\xfe{\x86<\x01\xe9\x9f\x11\xf4\x8a\\\x85\xfc \xbf\xab\xddB\x1cQ\x185\x95\x1ek\x06\x8a \x885V\xf1q\xaa\x11\x13\xbe\xa8\x0b/\xba7w\xd3\xbd-T4\xea\xf1bsM\x02\xe2\x1c\xbbj\xc0\x8c\x8fB\x9f\xa3\xbc\x1e\x1a\xfa\xa4\x86/\xcb\x1e\xdc\x86\xdd\xd2\x9fE\xfa\xbd\x84\x91zC}\xe8:\xd8\xfeY\x0e\xed\x9ff\xc4\xf9\xa7\xb4\x19tl5\x1b\xb4\xce:\xa0U\x8b\x8c\x11*\x02O_\xa1\x15q9\x0b\x99\x97b\xd5X\n\xad\x0d\xf3j\x9c\x91@\xbaZE\xa0\xe2\xfb\nF\x16\x10\xc3\xfb\x98\x9e\x118]\xc1n/\x8cpo\xe19\xb4\x1b\xd5W \x0d5\xe8[z\x1bv\xc3\x08i\xba\xf6\x02\xc5e\x94K\x18\x9f\x16\xe8z\xc8\xe0\xa1\xe4\xd8\xf8\xdb;T\x99pN\n\x16\xe75\xdd&\xa1\x13M\xb5y\x82C\xc3\xc1\xeaX\xa3\xa3\x07\xfe=&I\x1a\x04\x0cv8\x01\xbe\x0d\x94\x8bV!\x97\xcd7\xc3\x9d_JX\xfeb\xc6\x9d_\xbe\x0cwN\xcd\xbaD\x81/\x9aJ\xe9\xf1i\xc1\xf2x\xcc\x9a\x96 K\xb3'\xc4\xe5fz\xe1|z$\x9f\xea\x0f53\xd6\xf0\x1f#\x15`\x1a\x10\x12\xc1K\x8e\x19z\xdc\xc3\x19\xe9\x0c\x04\x82\x86\x15\x86\x93G\x94\x0f4M\xfb\xf0\x932g\x84\xa3\xb6gc\xa3\xcf\x8dL25\x7fY\xadG\xe9![S-U\x1e\xb2\x03\xc8\x85\x8b\xac\x15W\xa4\x8a\x88\x04t\xc80\xecn\x07=\xba\xb2\x11\n\x7f\xbc\xa3jgf\x1c\x15\xadT;\xf3\x9a\xac\x9fu\xc84Q\xe3\x14Z\x937\xbe\x95\x9956\x9bikJ \xaa7\xbd\\M\xa8/\xf4\xc3CbD\xf9Z\xdf\xb3\xb8p&\x02\x80\xa6\xa5S4\xdd\x08\x93o\xa9\x02\x1a\xbd|\xe9\xc6\x12\x9d\x8a\x9dU\x99\xaa\"\xc9V\xeb;-\x11;-\xe1;-{\x00\x89;\x16:\xe6\xdf\xe3bf\xb0\x03 \x1c@b\xd1\xf35vf<\x8a n\xee\xc6\xc4\xa8\xb4\xb5\n\xa3\x89\x17\xc8\xae\xb3=%\xb8\xac\xfbS\x03\xa1uw\xe6\x9d{8\xb9\x89=\xbc\xd9*(\xc8\xa1\xa65\xfb\xf7\xed\xf9\x98\xef\xf9\xd8o\x8fk\x8b8\x9cU\x87\x1c\x95\x87\x1c5\xee\x8b\xd2[\xc5c\xad\x91\xf7\x0dk\xbb\xb2&4iB\x86\x85{V\xd8\xf2SP7\xcb\x86v\x94\xb1\xe8$\x9e\x04\xd4\"\x83\x96\xbb8{\x00[\x01F\x9cKyT\x08\xa4\x18\x8b\xb7'\xb4\x10A&d\xe2\x08\xf2\xedm\xb9\xab\x1e\xd8\xa5\x91\xbc s#L+}\xf5\x8d\x025\xcb7\x86\xaaE\x9d\xf3D\xd7\x12\x8b\xed\xf2\xbd\xa5Y\xcb\nl\xbe\xd5\x98\xb6\x0e\x1dZ\x0e\\$\xe1\x8c\x8e{@,\x8dX(\xaf\x8d\x10\xe4\x12\xe5\xf3\xff\x02\x94\xaf\x0e\x15\xfd\x14)C\x08D\xca\xa2\xb6\x83\x80~\xa0\x94\xc6\xa8\x07\x1e\xcc[6LF\x11'T\xadC\xc226\xbeK\xa8\xa6%\x12\xbb\xe4A\x17\xdd\xa4.m\x12\x9a\xd8\x86\xc9H\x84C\x96c\x8b\xeb\x03;\xcdI\xfc\xa9\xbd\xa06lk\x1d[\xc6\xe5\xfd\x8f\xed\xbe\xc6\xc2Z \x9ai\xb1\x8d/\xdf\x08\xab\x8a+\x01\x8f\xaac\xb5Ka\xd8\xbdQA\xc1\x0d\x11\xa5\x02\x9eC\xb1(\x82\xf2\xe4\x1e6\xbe\xe6\xb4.+\xf67\x1f\xfa3\xbcsI\x03\xe6\xe4\xfa.v\x0dA\x1b\x0e\xa1\xf7\x9e,H\xcc`8\xea\xc1A\xf5\x0b\xbd \x98\xa6\x16\xda\x86^u\x0f\xbf\xe5wX2'\x05\xb4\x9d\x8e\xe7\xd7g\xcaML\xb8\x18\x82\x81\x01\xaf\xf5\x93\xd0q\xba\x9c\x10o.|Ft\xc5W;*\xab\xd1<\xa6,\xf0\x99Hm\xffpPYQ^\x8b\xd9\x13S\x85\x03\xa5\xad\xab\x8d\xec\x83\xb0\x13\xc3\x8e\x08\xa6k2\n\xcd\x91\xe6\xe4\x9c\xe4\xc5&n\xda\x1dp\x9d\x90\xcb\xb7\xd3\xeb\x83\x15\x0eQc\xb8\xb3\xe7\xec&\x8d\x0b\xf6\xfc\x06\xba\xaa0\xb4\xb3\xcb\xeb\x0bS*UT\xb9\xc4\x98+\xcaJ\xb0\xca\x03\xa36\\\xda<\xd1\xa8S A\xbd\xe6\xb2\xb9\x94\xb3\x11\xab\xba\x19\xb1Vl&<\x04\xaa(N\xc5\x02Q \x89\xd0\x98\xf0F]7\"~xP\xd8\x1a4\xa5\x91\xd2\x13\x0fI]\xf5\x0e\x87m\xcc\xd4\xa6z\xde\xb6\xf7s\xfa\xbe\x92\xf4}u\xc3\xf4\x1dU\xc6\x8a\xbc\x8b\x1f\x1au\x17\xda\xddm\xe8\xf5\xfb\xfd\xea.\xa1\x13\xd8\x86@\x08\x15\xeaE\xb2\xe0\xed\xc1\xe9\xaa\xf69Y\xf0\x86{!\x9e\x07\xed\x93`u\xb3'\x81\x1an\xa5\x8b\x84\xaf\xebCi\x9d\x11\xabk\x9d\x11\x8as\x08\x08\xec\xe8}\x87p[\xeb\xcf\xba?0@zW\x18\xe452!n\xf05B\x9d\xf84\xcd\x0c\xb6\x87\xc6\x90\xbd\xcf\x9d\xc6\xa1Rv\xaa\x1d.\xe8R \x02\xb2\xcb\xa7\x91\xb0\x15\xe0\x19S\xdd\x0d\xe1\xe1\xa0\xf4-]\x91`7\x82\xddP\x1eO+\x89\xdcg\x84\x05\xbaU@\x99\x0c\xf8}f\xb8\x8f k\x9f]\xab\xeb\x1c6\xe7eTemy,\xf6-\xf8\xbf:\x92\x0c\x06|.vi@d\x17p\xaf3\x94\xf6D\xb5\xd0\xb5\xf3 4\x13mp\x89\x03\xed\xc3j\xf5\x85\xe7#\x0eGB\xd4@sV7s\x16V\xd8\x8dz\xc3J$\xe0\x90\x93\xf2`k\x03S\xf8\x1a\xf3\xe0iw\xeb*G\xeaT9\xd6%\xc4\x08\x12\xa3\x06\xd1\xbcl\x19l\x8b\x11\xed\xf0\x01\xe4\xfe\x0b\xd4\x92\xd7\x8c\x00\xdc\xfc\x00\xae\x80g\x1co\x03\xa0\x969\xf9\x02\xd9\x0c\xce\x9b8\xec\x95 \x9d9\xd5!\x0d\xe8\xf3E\x7f\x84\x16\xc9\xbf\x98\x03P\xca\x17\x94\xd7c\x1f\x91kuC\x0c\xc1\x8a4\x16F\xf8}\xc8\x1fe\xb8\x1d\x9aU\xc5\x13\xfegy_\x92,\xf9 \x9eq\xe7ed\x91\x81\x8f8%*\x9d\xd3 \x89\xe0\x94\xe0\x9f\x17\xd5\x9fG\xea\xcfSRF\xf4\x887\xb5@\x1e\xf1\xbe\x0c\xf29jH0|\xa1/\x89-\xbb\x04\x9el\xc9|\x89 &v\xf6\xab\xd3\x8e\xdf\x0b\xaa$,\x11\xec\x87*\x7f\x06\xbe~\xe0\xbfk\xee\xdf\xbbw\xe7\x1e\xdc\xe2\xe7\xd9\x9a\x13s\xfb\xc6)\xdfd\xe2M;\x92\xe3^\xd9F\xb7\xbbG\x8f\x1e\xc1\xde\xfdP\xde\xe1O\x02V\xde|\xf8\x10\xf6\xee\x8b\xdc3!\xac\x9b\xce\xf8\xb6P\xa6\xe3._Il\x1en\xc1\xde\xee7w\xbe\xb9\xbb\xf7\xed\xfe]X\xc3\x9d\xfd\xfd\xbd\xfd\xfd{w\xbf\xe1O\xfc\x9c2\x9fZ:\xd2)&\xac\xd7\x8e\xe0\xeb\x92\x86Z4\xd5\xdd>\x8f\xaa\xa3\xb6\x07\xa3\xbb\xe3\xae\x9e\xb7\x9a#4Px\xc5\x18\xa8qY\xe6P\xa5=\x18\xd8}\xce\x12\xf4)\xdc\x92C\x15\x0e;\xc2\xa7\xc21P\xd0\xf0t\x17\xd66\xe7(q\xec\x8d\xe0\xbd\x80\xf5\x1b\x993\x83`:\x1cxF0\xf1\x19>\xe7T\x1c\x1b\xe7K}\x9d,\x0bp :\xdb\x08\xc7gq1{\x9aM\x88\x06\x19u\xcb\xa4\\\xc4\x96\xaa\x90-\x1d\xa4\x9e \xb43\x9e\x1f\x9a\xbe\xaa\x08\xbfw\xc2c\x8d\x84a\x97\x1a3\xa9\x9c\x0b\xcb\xaf\xc9\xf09\x19y}\xb9\xf5\xd6:n\xb05\xceOS\xb4q?/\x8e\xaaT\xd8\xe8\x0egz\xe25\x16[g\xdd\xe0\xd5\xbf\x96\xa3\xa0\xd9\x84|X-\xf8\x96\xdb\x0d\xa1\xb8H\xd8x\x06Au\xbf\xab)~\x8d\xe3\x82\xc0\xdeA\xe7{\xa0\xd1\xfe\xfe\x92&\x9f\x97\xe4\xf93\xfb\x1c\xd5\x85\xcd\x7f\xb7a\xf3\x93l\x8c\x01\xc3G)\xe1\xff\x88\xc96n\x96cp6mVj\x83\xdcR\xdaj\x19\xdf3\x7f\xcd\x97k{\xfb5\x89\xf4\xa3\xef\x16\xbc\x16{\xff5\xee}G\x88\xc8\x07\x12r\xac/\xa4,z=G\xd7\x06\n=V6\xd5\x01\xfe@\x97\xe7\xa6\xc7`\xefMFw\xc8%#\xb4H\xaa@\xc2\x02\xe2\x9c`\x92\xe38M\xb3\x0b2\x81\xb8\x80OdU\xf4\x9b\x89\xb3\x9b\xdd\xf3\x0de-n\xf1\xdc\x98\xc3X\xbf|\xd2\x11\xab\xab\xbb*\x86~iI\x8c;\xde\x94|\xbay\xf1\x01\xcc~\xb1\xea\xc2\x15j\xac\xc3\xa6$C\xb2\xc9Z$\x89\xc6\xc1\x9b>\x08\xad\x0d\xb9\xd5m\xfa\xa5\xcb\xda\xfe=\xf7\xe3\xc5\"]I6\xde\x12\xd1\xaf_W\x91\x83L\xf23\xb0\x03\xb2\xddD\xb0\xe6\x94^\x91\xbc\x16\xde\x7f\xa4\x08!\x96AA\x18\xc4@\xf9>\xa8 \xa7\xc6\x08\x19\x95{\xc2\x89\xfa\xfc*\xe7`\x9f\xfd\x06\xf4\xc4y\xeaot\xda+\xe5kI\xd68\xc3\xa0e\xb41\xe6\x03h@\xeb'4]\xf1&\x85\xd6\x14\xd5\xa4c\xe1\xd4{J\x80s\x0fd\xd2\xf7\xf4\"\xfdd\xe1\xedKu\x0c\x13\x8c\x92f\xa1 \xf5b\x16\xfc\x85;{\xf0\xb5HU\xd8\x1f\xcf\xe2\x9c3/\x8fY@Q\x98\xb1\x8aG\xc7\xa4\xed#\xad\xff\xe2\xbd?&U\xc6\x84\xa48*ic\x9bj\xbc\xf5\xdaa,_9\xf0V\xa9;\x8d4\xf3\xcf\xab\x08z\x7f\xefE\x82]\xb4\xea\x04\xc6\xb18\xe2]{\\\xf6cs\xf57\xa0Y\xd8\x16\x97\xdf\x91\x08>XE\xe6\x9fI\xfc\xe9u\xdc\xd02\n\x06/xGd\xe6\x02\xf9\x92\xa1qqF\xb6\xa1\xfc\x1c;<9I\xe6\xf3%\x92p\x8em''\x8d\x14\xed\x1d)\"\x03lE\xfc\x0e\x9e\x93&\xd2\xf3\xfe\x7f\xe7o\xec\xdd7$\xa6\xe4\x0f\xf6\xef\x192\x1f\xbf\xb7\x0cY\xb2\xf86)\xfa\x95e\x03\x9c\x91@\xc4f\xa1tV\xb9\xcd/H>\xcd\xf2\xb9P\x7f\xc7\xa2\x8d\x8b\x84\xcd \xa6\x90\xd0iB\x13F\xa0H\xfe \xbe;\xf0\xa3[\x8cw&\x0d\xfbE$\x0d\xfb\x8cMp\xfeb\x1c\x94\xf9\xd3\xf9\xb3>\x1f\xd9\xeb%\x8byO\x85\x16\xd6\xd2\xa5\xab\xce\xad\xe9\xed^\x91\x80*-?\xedO\xb3\xfc(\x1e\xcfj\xf1V\xc6@\x06u)R\x8a\xdc\x15m\xa9\x9b\xd4e\x8a\x82\xf6\x03\xe7g\xef\\ \x7f\x90\x8el\xe6\x1fI\x04'|\x9e\x1f\x89G2\x9d\xd2| B\x8a\xcb\x038r\xa9\x88\\\x8bd%!\x1d\x15\x86`{\x00\xfb]\xa2\x14\xda\x85\xe1Q\x95@\xc6p,\xbfN\x8a\"\xa1g\x82 \xc3^?\x91\x95\xc8f\xc1\x86\xd4\x94fR]\x82y\xe6/E\xfcU\xde\x97-\xdc\xbds\x9d\x11\xfc\xd76_\n\x85\xa7\x96\x01\xeau\xbc\xb0\xa6<\xfb\xf8\x85\x96\xc5\x93<\xcb*\x959\xff\x81\xa2s\x19K#\xf26\x85&\x93b\xad\xebb\xa3\xae\xff\xa1'\x85r\xcf\xa9 \xec9\xdd\xa0i\x9c\xc8r1\x89\x19y\x8e/\xaf\x0c\xd5\x0cm\xdfn\xba\xb29\x99g\xe7\xa4S\xd26\xccz\xe5nxBR\xc2'\xe0\xdbtk\xd6\xbeS^m:e\xd1IsA\xdc\x89\xa3\x85\x08Y\x92\x17\xa5G;\x94\xae \xa12\xce\x94\x13\x18\x92\x91l\xd4c,m\xf4\xb0\x8c\x06\x83]\xd1)R\xc6b\n\x14w\xf8\xc8\x96$\xda'\x91\xc4\xb9\x8c\x03\x15\xa6\x8d\x95]'\x1aw\xfa\xe2qr\x17K?<;Q<\x97)c\x12YM\xcbb\xd6RW\x01\x03\xc8\x82\xa5\x83\x06\xca\xe5*p\x02K\xe9\xac\xdb\x8e!\x03\xab\xd4qF\x82\x04cH\xd0p\xc3\xf7n\x04\xbd\x84\x9e\xc7i2\xe1\x94\xf8]\xccf69\x88\xcf&\x85\x01\xc4.\x0fT\xfe\xd2XNy\xc5\xa7\x8c\xd4*\xe5\xfb\xc9\xfe\x01?\x07I0\xae\x16\xd0\xa9(\x9d\xe2\xec\xc7r\xf6\xe2\xd7\x8a\xff\x92\xbb=H9\xbe\x06I\xc5\xcb\xb0\x10\xcf\x8e4\x82\xa9\x81\x07\x90{\x9eR\xd4\xe9Z\"\x1ee\xdfy\xd9\x9b\xe4\x9aZu\xd0\x1a;`\x9c\x92\xd8Y\x94Hk\xbc\xed\x16\xc3\x84?\x84Ym\xc0:\xea\x8d\xb3\xee\xf6k2P\xe7\x04J\x8b,_\xa9\xb8x-t\x11&\x06@\x8e\x86 b\xb1\xfeE\\<\x16\xf44@\x1f\xb6\xfe\xc9 \xa1\xc52'o9\xbd\x0e\xea\xc4[\xb1R\xce\x81\x97\xbd{\xee\xc1\xd6\xf9P?7\xf4\xd1pQ\xec\xd2\x0d\xb6\xb8x\xae41\x9b\xf5\xaf\xf7\xd3\xb12%\xc86\xebA\x9e[\xce\xb67spR\x1a\x11r\x01/\xfde\x9e\x8d\xbc\xd0\xbe\xd4\x89Y;\xdcKo\x1b\x94\x03\xdb\x99E:\x88\x08\xba3\x93\x80a\x82\x19\x86\x19eL6\xf7H\x94}\xea\x80\x80\xb6\xda\x9d{K\xed\x98\x8a\xc11`+?\xd2\xfeI*\xd6Fgk\xa2*\xaf\x03\xb24\xc8\xe15\x1a\xd2r?\xe8\x0c\xce\x9edp\x0c\xd3I\n.\xb9\x0f\xe0\xb3\xc1s\xe8{\x12\x01\xb2W\x8dd\xc0\xaf\x1f\xbf\xb3TO{\xc2\xdf\xd6\x81dS\x0f\xfedO\xfc\x81\xc3oOH&*j\x19\x1f\xac5>\x9c @,\x9d\x9c&l\x8e\xe0PN\xb14\x13.\xc8\xd4\xab\xcf\x9f\xaf\xd3\xe78[Rv\xed._\\\xa7\xcbOd\xf5\xa3`\x8aY\x0b\xba~\xdd\xfezs\xdd\xae\xbc;}\xd9\xdd\xe9 \x13\xa5FK\xa7\xe6*\xc2\x86V\xbe\xcd\xf1\xf8\x93H\xd3\xa9(\xcaW$\x90\xbf\xfc\xb4\xa1?t\xa6x\x14\x15\x90D\xc6\xaaVRJ[\xb3_u6k\xa6m\x1ce\xac\xe5o\xd1\xab\xf8\xc0\xe6\x8eyr\xb2\xc8\xc9\xb9\xc9\x14\xec\x97\x85\xe5\x9f\xbeIQ\xeb\xc5_\x9f8\xf2\xf6fJ\xaa#\x11d\xa5H\xc7\xf0\x87F\xe9\xa8\xb8!\xa5\xbb\\\xfc\xaa\x13\xbd\xcck\n\xbf8\x93R\x7f\x8fz\xed\xe0{>\xa0\x7f\x92`\xd73\xff\xdd?\x9c\xb8z.k\x92\x9b\x8d\x9c\n\x15-\xab\xadt8\x17\xc1\xa9\xc5\x9d\x12d~\xd8\x8b\xe0\xc4\xa1\xbc\xc1\x04pL\xf5\x86\x91/\n\xbc\x11h\xcaU\xb1\xb8I\x04q\x18\xc1\x96T}T~U\xe6\x0eD\x1e\\\x19~\x18$\xb2P\xd7!\xe7\x02\xa4\xf6`g\x0fK~\x1d4\xab\xc9\xf1\xeb\xcae\n\x17zvl\xc6g\x14{U\xf9\xc6\x9fp\x9bW\x93\x1cZ\xa1'\x8a\x8f\x19\x1f\x9b\x82@m\xc8C\xea*\x8b\xb2>c\x16\x95\xd4\x07Q\x97\xb4\xd5\x14\xa4\xa5\xa3@O\xb8\\p\x08\x19\xee6\x93\xbe\xc2\x82\x8f\xd2\xe9\xa6\xd4/\x89\x05\x8d`\xe9\xe4U\xb8D%$\xb6\xc0\xf8\xe9\x01GD\xb9\x9e\x84\xf3#G\xc12\x8c\xe0(\x881\xeb\xc3\x05?'D\x0e\xd7!\xff\xcc7\x9d;cn\x1e\xaa\x95\xa8\xf4W\xe1\xf6\xd9\xba\xff\xc2\xcf\x13\x976\x80c\xea[l\xcc\xf2\x08\x1b\x0c\xf8\x02h\xac\xf3\x8br\xa6\xb2\xbaP\x04\x99\xc9\x96\x83\xbbW$\xde\x0e\xaa$_U\xcb\x07\xda\xdf\x8f\x1e=\xe2\xf4\xe3\x16\x9c\x99\xf7\xf9\xb2\xde\x08\xba\xe9k\x1fY),\x1f\xef\x8f8^\xaci\x1b\xc3Z\xfc\xb1\xc4qI\xbd\xea\xb0\x82\nl\xc3\xb9\x84\xccH\xe8\x15\x07\xf5\xd5\xcdB\xfe\xe5C\xf1\x1d\xe1+\x0d\x070L\" \xbeK\x9e3\x17\xbd\xac\x12k`\xf5\x82Z\x86\x02Z\x9a\xe8:\x12\xdfph\xd1a2\xb2\xd3\xcc\x02M\xb46\xeds\x1c,\xd1-:\xe0\xaf\x15\xf5\x8c\xc6>~ \xd3V4\xa1\xba\xae\xc2\x90\x1f_\x8be1\x0b\x0c\x9eEV\xf2\x12+\xa0e~@\xce\x9c@.w=zmUj\x95[\xb7\x00\xb3\xb0\xd6\xd4+\"'c\x99\xd8Wl\x7f?\xce\x12\xc1S\x82\xc9h\x87\xbc\xa3QX\xe3\xc8\x98\x0fG\xa6.\xe5l\xc0\x86\xb6\x04x\xea\xca\x10\xab%\xf9'5\x115FEKl\xad\xfe\x01F.J]\n\xd9\xcd\xb4\x99wU8\x8d\xf2|\n\x0b\x90\xd1a\x9a\x82W\xc9\x99\xd6\x8e\xb9d\xb7\xe0\xb8\x85\x14\xa9\xe8\xb2\xf9\x1f\"\x7f\x9dJ\xdb\xff\x0e\xec\xc1!L\xfa\x8bLT\x82\x98\x0cSN\x8dZ7\x86|\xe4\x9c\x1f\x9f\x08\x06S\xfc\x0e#\xec9hh\xff&\x95)\\ \xcc\x11L\xbaX\xd2\xab\x08~\xbc693F\x97!vY6+\n\xf5\\\\ \x82z\xfdp\x11\xf9IP\xf6\xb1hF\x12EC\x84\xa6\xd7J\xd8x\xc3\\\xce\xb9%\xb8\xbb24\x1b\x95\xb3\xc3%\x13\x8f03\xf2H\xc4q \x19\x89\x99\xd8\x89&x\xaeM\x17k\x99\xa1U\x02\xe8\xa7$\xc8m\xa0\xd2\x04D&Y\x1e\x8a@b\x0e\xa9\xb2P\xf0]\x9a\x9f\xa7u\x18\x9a_\x1acL\xe5\xd6\x00\x82\x14n\x81 \xb5\x91\xae!\xa1\xce\x1a\xca\x1c3AUtz\xc9D\x93\x08|s\xe7\x0b5B\\.\xf3;|\xef\x8d\xe1\x10\x16\xc3\xe9\x08\xdc!\xeb3\xa1(\x9b\x08\x0b\x8cX\xe8\xfaZ\x99g'\xd4\x04\x13\x8f\x83B\xc0\x01E\x97\x85F\xde\xc7N\xf2\xeep\xf3\xaaU\xfc\x92\x0c\x01\xdf\xcf\xa2\xde\xcc<\x8c\x103v\x1fHV\x9f>\x80%\xa6\xf9\xe1\xb81\x80\xbd\x10\xe2\xe1r\x84hp\x0b5\x0bl\x98lo\x8f\x1c5\xeb@\x13J\x87\xf9H\xa8\xb8\x84/|\x80 \x05\xb7\xb1\xda\x98\x81\x90\xf0\xc7\x8b\x08\xd2\x08\x96\x11\xcc,\x90\x94\xe79\xff\xbf\x08S/\xa1\xc4\xe5?\x16,\x86{\xf0/\x98j\x9c\x8b\xba\xe3h\x0f?\xde357\xab\xda\x99\x99\x11\xf1tSr\x7f\"\xd1m\x86\x14\xfc\x00R\xf8\x17\x92\xfd\x14\xd6`\xc1\xd0\x0b\xed\x93\x82\x05\x8b\x08\xa6\x11\xcc\"8\x0d\x9b\x01\xf8\x1d\xe2\xc7yY\xed\xa3\xf2\x80\xb0\x1f\xb5B\xbdZ\xa6\xbf\xc9\xb5\x08Z!\xc5P\x80O\xb9\xa7\x1eb\x99=Q\xf3\xacslz\x97\x88\xf6\xf5\x0e\xdd*\x8d\xa4\xfa\xcc1\x06\xb7\xa2#\xe9\x92\x16\xf0%\xb5L5\x00\xa8\xbbn\x19\xa2\x81_0\x80\xafH\x90X\xed\xe7\xe0\x14\x17\xc6\x19e \xdd\xa8\xf8C\xbb\x7f\xedW_\xf8\xccv\xecj\xa8\xb6\xa7mct\xe6J\xb5\xe6Im\x10\x90:0\xf9*\xa7|\x06s\xb8\x0dw\xdb-\x8f\xd5\xb3\xfd\xf6\xb3i\xf9\x9d\xcds\x7fa\xf1\x188\x97\xb1CG\xc6\x80a\xe4\x9b\xbb\xf3XZ\xe4\xea \xe6\xc9+\xa9\x9d\x99/\xa4\x18:\xec\xaa\xe7D\xdd5\x1e\xc4`r\xa9\x03\n^\x89\xe3:\x87G\"kt\x0e\x0fa\x0e\x87p\x81\x99\x07\xf2\x08U\x0c\x18g\x8a\x85 X@\xfb,\x13\xf2w\x88ei\xd9\xc6n1\xe8'r\x9c\xfc!z6\xa4\x01\xe9\xd2\xf4\x96\x9a\xda\x0e\x7f\x13\x93\x17\x89\x9f\xa7\xc5\xc4\xed0\xa2\xe5\x01\x99\xb1\x8e< \x0b\x16\xc1\x05\xe1l2\xf3\xc8\x03\xa2 \x1f\x81=\xc6r\xc1\xb4#\xeeKsZ\xbcJ\n\x06\xc3^\x04\xbdQ;\xa9E\xad'\xcf\xa4\x16\x89\xaa\x15_%\xc5\x0f\xcb\xac\xe4\xa4\x9e\x95\xdcq\x9ar\x01\xb6d-1I3\x8e<\xcb\x93\xb3\xc4\xe6\xd9\xa6d.\xde\x13\xed\x8b2\xa1\x04n\xc1\x99!\x14\xd2\n '\x0c6\xcb\xae\xe1k\xbf@\x901\x04\x99d\xabjU\xf3\x1dE\xa00\xb1\x7f\xe5\xc4\xc6\xe0\xa1\x96\x0dvs\x975\xc0c\xe1!\xec\xc2!|\x92\x19\x0cq\x9b\xed\xca\x08SqsW\xa8\x1f\xf7\xc43f\x8c.\x03\xb0'\xd8c\xe8\xfb\xa4\x16\xd3\xfcNe\xcf9aq\x92\xba\x19*\xe5\xdeo})q\x06\n \x14\xdfb\x94\xc08^\xc4\xe3\x84\xad\x84A|\x00\x97Xo\xbb\x195 \xe4A\x14\xb12\xf1R\xd6x\x89\xf4ORrN\xd2\xea]\xfb\"n%~\xe1\x06\x89\x08\x9b\xa8BL\xcbuV^\xf6b\x14\x1c^\x9b\xb8\xdc;7\xd3\x05\x82E\xac\x14~\xad \xa4\xcf13z\x17^\xb9\xe2,k\xdbj\xb3\xf4-H \xcaJ\x1c\x9aU\x03 \xcb,\x992T\\h2\xaf\xcah\xaf^R\xba\x0d\xf1p\x91&c\xe4\xdb\xf6lQ\xbb\xb5\xc1&\xb4 \xf9&d\xa0\xd1\xcbn'8\xfe\x0d\xc9$tjZ\xfeTK\xab'\x9b\xc0\x15\xe6\xf8\xd3\xc8>!%%\x81j\xd7NE\xc1\x19)'(\x16\xcbb\xd6\x05 %\xbcU\x11\xfa\x96]\xae\xc1\xc9\xca \xe1\x1b\x16\xbai%\xe0\x9f\x90\x11\x91dQ\xd9R-;\xbe\xe6\x16\xbc\x8b2\xbb\x96\x16\x11%w*\xe8*l\xe3\x1e\x1e\xe6^%\xd9\xea`\xcb|\xf3:|R\x87\xecn\x04;{\xeeV\x97\x14wWW\xcb\xad\xf5\xb8\x16\xb0\xad\xa1a\x9f\xf0\xc8\xd9\xf1\x05\xb3#\xfbd\x99HnH7\x07\xb1\x17(\x9a@\xee\x00\xf0&\x89W\x1e\xfb'^i\xf7\xe1\x95\x90\xa3\xd9\x91o\xe2\x95vw\x1b\xe4\x19y\xec\x97g\xc4\xdc\x87\xd7\xb4\xce\xaf\x93\xd7\xe3qg\x9e\x91&\x9fx,\x08\xad\xd7\x89\xa6o\xc2v\x11\x8dz\xcb\xbe\xf5\x97\xce\xbf\xa8\xee_9\"Y\xe2\xaf\xac\xfa\xe7\x1e\xddfI\x19\xca\xedi\x17gOJ\xe4\xb3\xaf\xcd\x06\x05a0\x14\xb1\xabB.\x9e\xa8\xa7\xec\xdfW\x04\x86b\xd1\xd6\x8d)\xd0F\xd9)\x9aur\xa5\xfe\xd8 _\xbc\x02\xa1s@\xa1\x04\xc1\xa2\xd7w\xa6\xd7\xad\xec\xdc\x98\xc8_\x92d\xe2\x82\x05:\x9b\x135\xb8\x9c\x1a\x87\xa3s7\x91\xc6\xdcl\x94\x90\xc2\xb4\\I\x81\x12\xf6\x00&\xac\xad\xc1\x9a\xb1v\xe2\x89W\xcf\x8f?X2O\x9c\xa3\x05]\x83\x9cM\x7f5gV<\xc0\xb1\xa3h\xac%-\xa8f\xd2\x8cn\xd3\x7f\x9d\xb3\xe1\x8c\xa9`\x90sV\x05\x83\x9c\xb32\x18\xe4\x9c\x95\x89\"\x9f\xc8\x9c\x91\xda\xbbx\xbf|[\xbd\xa5~\xe1\x8b\xa5\xfd\xed\x89\xb2\xc5i\xb7\xd5\x17\xea\x17>\xaaR{=)\xf3|U\x0f\xcadOOj\xd9\x9f\xf0\x85f\xe2\xa0'\x0d\x89\x19_\xd2\x93\xf4<\xd1r\xf6\xc8\x87z\x0e\x9d'\xb5\xa4:\xa2\x0b=\x03\xce\x13=#N\x04\xf3\xb6\x08\xf4\x84L\xb3\xdcd}\xb4iZh\xe9\xd0\x84\xde\xcc\x0c#\xdb\xca\x8d\x81\xeb\\\x86^hL\x97Y\xbb\x88\xfaC\xe1\x13e\x0e\xad\x15\x0e\x80\x8f\\\xadK=\xe1p\xc4O2s7\x99\xf4\xbb\x10\xaaHs/LT\xbd\xb0S\xf2\x18\xf4Q\x0c]\x06,,R\x1fs\xba\x15\xd7\xc0\x8c\xb0\x85\x1d\xd4q\x86!\x8e\x06\xdfJj\xa0jSe\xe3\x80\x85\x95,\xf3\x80\xf2\x12\x06p\\\xe5\xce2\xcf\x7f+1\xabTj\x8e\x13\xbb\x0f\xa0\x10.\xa6\x05\xfaIJX\x14\xa3R\xfc\xb2\x12\xe4\x0c\xddD\x96%\xf48\x8d\x0f#X6)\x98\x01G\x1fO\x19i\x1d\xef\x9d(\x1a\xd4q\x14\x83\x8c\xbf\x00S\xa5\xf5\x13\x85\xfa\x0e\x84\xcd\xdc\x08k\xee\xc4\x0b\x07\x93:\x0e\xda,J\x88\x839&\xcb\xe4\xd8\xa5\x83\xd1\x80\x82\xf8Rf\x86\x0c\x1a\xbf6DN\xb5Y\x9c('\x9b\x8ceoRY\x91\xa1\x92/\x92~mq9M\xceD\x85\x11\xc4udi\x1fog,\x82\x15\x8b8\xd3\xe0J\xa3~b?\xad*^]\x1d\xe2F\x08KEay\xb2\x1b_\xc2\x04-,\xc8\x1dQ3Ryf\x87O-\x91\x88d\x1cv\xc3\xc6\xc4\xa0\x16\xf7\xcc\xe7\xb6\x8c\xc0jc\xad\xe9q\x96\xb5rV\x16O\x13u)b\x12K\xff\xa5C\x85`\xe2x?PQ\xee\xf8\xd3\xce\xa3\x82\xf4K\x89e\xe5\xc3]\xf4\x8c\xdd\x81\xd8\xfd \xaa\x18\xf9k\x16\xbe\x11_y\x04s\xc4\x1d\xfe\xf2\xdca\x0f\x95@\xe8\xe4\xe1\xd5\x95\xa0\xe3,\x9fvZ\xee\x87SG\xd1\x11\xd0\xd4\x12X\xedq'\x85\x03N5\xdd\x9f\xc8\x96\xd1\xb3k9$\xe6\\)`\xdcvx\x97/a\xd1t\xcb\xcfPs\xdc\xb1\xac\xc2\xa9\xd5\x7f\x01S$/\xf5\x05L\xe0\xd1#\xc8\xdc\xdf\x8d1\x00f\x9b\x1f\xeb\xea\x03\xc72\x8d\xcb\x05\x1d\xdf\xf0\x82\xe2\xb9\xf6\xc0\xea`\xa1_|\xed\x8d\x19]L\x97Z\xf4\xa5M\xe8k^\x89,\xb2\xc7E\x9d.\x85|\xf3ZJUh\xe7\xcbv;\xbe\xba\xf80\xd2\x86/a\x17\x82\x83.\xf5#\x92\x8f\xe1\x00\xd2.$\x079\xf2X\xb8\xa2\x17\x98y?\x13\x87R\xc2Q\x83\xf2S;\x0b\xedn \xe0\x9c\x92co ]l=\xf6K(qaL\xf6c;D\x96\xad\xec\\\xe7\x0e\x8d\xc2\xb2T\x93\xc3\x0e\x17\x92\x96\x9a\xaa\\\xfc\xd4T\xe5\x0co(=9\xc5_U\xd6\xa3e\xa9$\xcf\xf0\x87&5&\xe2\x86\xd4\x97\xc7\xe2W=\xb9\xd7\xd2\x0b\x14G\xcc\xa5Q;c\x18\x06}\xc6\x07$\xec\xfa\\|\xf34\x85_\xb6\xa1l\x03q,\xfc\xf1er\x1ewL\x05\x11N\xf3\x0f\x15qS\x8a\xd9\xd6\x07\xc8\x0b#^j\xbe\x14\x99kc\n\x96\xb3\x83sK\x1b\xc4u\xb8td\xcc\x19\x0b\x13\x9f\xb4\xe5\x89\x8d\xa1`\xe1\xd4$\x8d\xc5 \xa5\xf2F\x05\x92\x0d\x136\xde\xb2c\x18\xc0\xd8\x1c6h[\xd1\xa2>\xf2\xf2\xf8'\x95[\xa6\xdeUT\x83\x9d\x80<\n;-\xde\x12\x0e\xcb\x9b\xcaD\x16\xeb\xe3l\xc7 \xd8\xf0\xe6\xd8\xce\xd3\x95j6\xf4\x07(c\xf0\x88\xe6\x99J\xa4\x07\xea\x9c\x05\"?\x97dK\x91+\xe5\xa3\xe2\xe2\xa5g\x1a\xc3\xa7\xf6\x91\x94\x16\xf4\x86\xedW\xb7\xac\x9a\xf9A\xf1\xe5C!\xd0(V\x10\xb6\xe1\xdc\x86t5sD\xc9DJ\xbe\x15\xbf~ \xfc\x16\xd0\x15\x07\x0b\xab\x0eJ\x1f\x06\x11\xaa\x95\xa3'\x03\xffhg\x00\xe7N\xc4\xeb*\xf3n\xad\xe8\xe5L\xd2\xa3\x05\xbd\xa8\xa83Q\xeeX\x7f\xa2\xe2\x0f,\xe5\x8d5\xb3\xbe\x9en\x07\xf33\xd8\xd9\xf6\x0e\xf6?\xf1a\xff1\xc6\x03\xb6m\xc5\x19\x96\xa5\xcc\x8c\xd8H\x91\x9b>@\xb3\xd1.\xfe\xbd\x8d!c\xbc\x05\x83\xc7\x02\xc7\x87\xb8\xb9\xbf\x92.2\x15s\xdc[j\xd8\x86\x86_\x13\xa7R\x13\xfb+\xd1#\xd5\x91i\xac\x82N\xb7a\xccG\xfd \xc4\xe7r\x1fa\xf5\xac\xb4\xbe\xe3\x0fa\xa8\x8cG\xe9H\xee*.\xd8\x8da[e\x1f(\xf8\x9f\xe7\x86\x11\x8d\x85L\xc8\x1f\x8f#QF}\xcc\x0f\x00\xf1o\x82\xff\xba&2\x15\xd2X\x82\x11\x04\xf8\xe72|\x00\x0b\x0e\x11\xec\xb9\xe0\xbb\xc9k\n\xb5\xa1\x8b\xf1\x9a\xf1n\xd2\xe5N2\xc3 \x8a\x87\x18#!\xc8\xc6RH\xdc\x07|`x[Soat\xe3\xc4\xbc\xb2X0]|s\xeb\x16\xc6\x01\xa3h6i\xa8 :h\xc5\x1c#X\x90\x90\xa7bz\x9c\xdf(\x1e\xc0\n\x1e\xc19\xff\x87S\x82.Y\xe2\x14\x060E\n\xb22+I\xd4\xc5\xbb\x9bK\x92s:\x12\xfdV\xbf\xad \xa4\xcc\xfc\x9d\xfaP\xf4|\x8e\xb4\x0b\x060\xe9\xa0L\xa0\x18|\x05\xb2\x80/\n\xc6\xac\xcfj\x8a\x93\x1c\xd9\x98e\x88g\xdd\xa3\x01,B\x8898\x16\xb8h\xf8o!\xdc\x16*\x07\x85VSR\x0f(\xda2\x85O\x96\xee\xc8\\8\xce8\xa5B\xfcp\xae\x9c\xdc\x87\xa9S\x98\xe1\x0bs\"\x84\xeeG\x8f\xf8\x81\xeeZ\x18>\x80\x13\xa4\xae\x8b\xea\xf5\x10Ns\x12\x7f\xb2\x7fu\"\x05\xb5\xed\x01\x04bK\x85\xf05\x9c\xe0&\xd9)!#\xf7\xd3\xf0\xc4,\xdc\x9a\x177\x15X\xfdH\xaa\x11E;M\x90\x16|ev`\xcc\x97(\x15\xfb\xe1\xa1\xd8\x0f\xb5\x0f\xca\xe5,8%\x90\xef+\xea\xb2#\xa9\xca\x8e1\x8ar\xe3\x94\xa4KTkT\xc7\x89`\xbbI\x8d\x9d_V\xba\x1d\xc08\xce\xca\xbd*\xd5\xdd\xabf\xbe\xeeU\x9cL\\\xb0 \x16\xe2\x0eFj6\xa3\x1b-\xc7\xf1c\xbf|\x91\xb9\x9e/\xb2\x16A_eY[\xba#B0)\xb6\x93 F \xc6\x9a\xbe'\x15\x10~$\xf7l\x82\xeb++\xfd\xc5A!RJ\x8aU\xbf\xe9\x94\x92\xb9\x88GK7@\x8f\x04\x1e)\xa7\xc9[\xb7D\x82\xa8\xca+9A\x92\xa2 \xdf\xccrcY\xa9\xb7])\xe6\x84[\xf5.*\xe5\x94\xce\xfa\x9co\xcas\xaf\xf6\xdf\xb9\xdbw\x16z|.\xdc\xe1>\xb0\xaa\xbe#\xbf\xb5\xb1\xdf\xcd\xf9\xff\xfa\xfa\x8e\x1f\xdcP,Ka\x8e\x9b\x08gk\xf0\xb5oJ\xbe\xba\xea\xe1\x9dfT\xb1+!\xaa\x14\xe1(\x02\xe1\x8f\x03\xb4\xdb\xf7OD\xea \x91;<\x15\xf6e\x8f\xdc\xe1^sz\xeeT&\xac\x842a\xc5{|\xcd\x02Q\xdd\xe6\x88\x05\xadP?K\xeb\xbf\xbb%\x0ci\xda\x89\x14KoM\xbd\x14K>8)\x1c\xfc\xbcHI\xc1,\n\xff\xa2\xe2\xf8\xf9\xd1\xba\xb4\xa9\x12\x06\"o\x93\x19o\x85~\xa2KQ\x18K\xf28\x10\xda\xd3\xea\xe7>|\x0d\x89r\xdcD\x1b\x910V\xb6\x93\x9fZDXu\xc9\xfe\xb5\xf9H\x15\x0bJk\x96}\x14\xf6Y\xf6\x92\xac\xc8\xe4\x98|\x0e\xc2\xcd)3\x19\xeeZ\xb8\x86\xb0?M\x93E\xc0;x\x1d\x8b|:\x1anr\xa2\x9b\xd7p\xb5\x8e\xb9\xba\x933:\\\xa0\xf1L\x95}c\xa10\xfe)%\x86\xe6\xdc\x1bkj\x0bND\x96J45(/\xb5X3\xabm\xa6B\x80\x18Qi\x19\x0e\xf7F]\x8b\x9d\x0b\xd5\x9eXG9\n\x91j\xdd:\x081?\xe9L\x1f+\x12Z\xb5\x10\xcbB)\xb2\x19+\xc9\xb0\xf1=\xb9\xfc\x9e(\xca!|\xc3%\xe5\xc8\xcc\x9c\x0c\x07\xe3kt\x7f\xf7\xcc\xbc\xfc\xa6\xc3\xeb\x04\xdd\x954\xaf\x93\x93eA^\x92U\x01U)\x0bE\xf1\xdaI|m\x9d\xbe\xb7\xd0tc\x8f\x9b7\xff\xec\xafm\xfe\xd5_\xdb\xfc\xc7\x8e8\xb6\x7f0W\x8aXV\x1bA\xbd{~\x83o\xf1.\xafN\xad9CR\xe6\x08\x8b9\xaa\xe2%\x9d\x0d\x9d\x97e\x92\xe5G\xb2\xfe\x19\xfa^9\x15b\xfe\x83\x05}7\xc9n\x02\x0b#\x12\x99*\x8a\xf09\xcd\xe2\xa2\xd3\x0d\x15\xf4\x8e\x12:N\x97\x13R4\xab\xda\x97-\xaa\x176kv\x16\xdb[\x1c\xc7\xe3\x19yO\x8a%\x86Q\x12\x1aaE3\xe9Q\xf8\x91\xe2\xe3Z\xd9.W\x04\x93\x12C\xcc\xce\x14P\xa7P\xadzV\x9e\x8c\xa1\xf4:\x14\xbc\xa1]\x1da-v\xa5y\xa7n:?\xa1\xef\xe5\x07\xc1\x9b.\xa9^i7UW\xa2]\xbb\x98\xaeXx?'Vu)\xbbf\xee,_\xab.\xe4RHg\x1d[uU\xfb\x0c\xdd\\\x87\xbb\x1d\xd9\x90\x00\xc3:\xd5\xbb\xda\x87{\xa3H\xfb\xbb\xe5^\xd8\xbc\xdcfQ+\x19Q\x97-\x8b\xb9\x1f>\xf2\x95\xc2\x15\xfe\x9d\xcbLp\x00\xbf[\x11\xa9v\xd3F{?ws\xba\x9d\x148o\x12\xdd|s\xd2b\xa7\x01y3\xa4\xd3\xa7\xa82\xc6\x81bbz7\xc5\xadj\xa6d\x18&\x8c\xbe\xf6\xa2\xc4Nn\x14\xedp@N\x02\xe43\xbck\x13\xa0\xac\xc3\xd9\xa6N\x83\xf2\xa0\x9a\x91\xfaXZ\x04mD)\xeb\x98\xb2\x99(\xf9\xcc\xb9\x86\xc3o:\xeb*o@i\x94\xf8\x9atR\x19t\xb4\x93\x04F\xc9\xaf\xf6\xb7\xcf\xa5OZ&h\x83\xdbE\x05}\x13\x9c4H\xc9\xef\x1cZ\xcbHC\xb6\x18)\xd0\x92\xe3\x9bq\x01\xc0\xa2NhUE\xb4\xec\xf1\xef\xbb=\xd7\xdc\x1b\x9c\xea,\x16m\xeev\xba s\xe4\xe2\xb2\x88`\x7f\xd02\xe7\xcd \xa9S\xe0\xa3y\x06\xa0sW\x1b\x8c\x13\xf4\xbd(\xa4D\xdb\x961pW\xa8Yj\x90-W:\xc1\xb2'\xd4\x04\xc8\xbc\x8f;{\xb0cHa\x0d\x92{h\xd2X+WP\xa7\xb1\xb5\xc6--_\x8f\x8d\xeb\xe0\x0e\xa9\x81\x97\xa3\xe6\xe8\x90\xff8\x0f\xd7Q\x8c\xe4*\x82-\x1b\xec\xcc\xb1E\xae\x19\x19\xcfx{\x0f^[\xfe\x0f_\x95_\xc7\xc9\x8e\x9b1k\xa2\x9a\x15\x8f\xcf\xcbD\xbd~\xc7o\x86\xc7\xd4\x8a\xf7\xb2\xb5U\x11\xc4\xccq\xfaf\x7f-;P\x8e\xa7\xcd\x0bH[\xbb\xa1\xb4P(t\x98\x0e\xa6\xc0\xe5My\xae\xc5 \xd8\xcf\x98\xa5\xb9*/t#|\xe2p\xeb\x05%5\xe8|\x02~P%R\xdc\xde\x8e \xe3\x0d\xe5\x12\x02hn\xb6\xe7\xf9\xe4Sm\xfa\x84\x81Z<7\x1f\xe1\x03\xa6&\x1f\x918*/v\x03m\x036\xc3\xd3\xf9S\xe1\\\xdc\xc9\x8d\x80\n\xca\xa8s$\x89\xfb\x0be\x08K|\xb8\x12\x906\xb1b\xb8\xeb\xb0\x9a\xa9\x0b\xb3Y\x1a\x13\x83\xeaW\x1d_\xc6h*\xd4r\x02}\xc6\x8a\x882\xb7:\"\xcf\xd8\xcap\x82U\xf01\xf3;~\xb6\x81'\xbe\xc4\x8fX\"N\xf9\x0c7r#\xe2B\xc4\x1e\xdcF\x1f\x1c\x0cDD\x9f\x1c\xf9\xfe[Y\xc1,\xeb\xcc\x9b\xc4\xd1\xe6\x9d\xa8cf\xb7'|@\ni \xc8\xe1\x04\x0c\x12X\xaf!\xe6\x7f\xc5e\x8f\x1c&}\x96 \x15\xbav\x10\x07a\x05)\xf3\xa0\xa4\x93w\x0c;&\xcc,`0\x10\x9e~\x01\xdfl\x85tD\xda\x85\x03c\xa5\x89s\xe9\xd5\xe8>vR\xc5bV\xe1\x06K\xac\xac\xa5\x8c\xa1\xcb\xca\x80\x18\xc1\x16\x9eR\x992\x8b-\xcb4>A\xda<+<\x8ea\x99\xe1\x86\xc9p\xd3*)\x10\x93E\x15\x15\x93\xb6\xcd\xe9$\xa6\x9b1\xf8\xb1\x85\x11\xa4_\xa6\xa7\xca\x9c\xe09\x96!\xda\xa4\xc2\xbcf!F\x11\xb4\xdd\xe5\xaf\xf45\xbe\x9e\xb2N\xda\xf4x\xff^K\xe4\xd6\xd3)\xb4\xd1Zm\xab\xf8\xec\xeb\xe3\xb1\xbc7|\x96\xaa\xb5z\x10B\xd6yZrxmo\x17\xf0HC\xf9\xae\x93\xd8+\xfa\x1d\xba\"\xe0\xf9u\xe5V\x13\x10T\x13tM\xa1\xe4\xaa1 \x96\xd2\xe2\x11\x0c\xb0g\x91\xa8\xa3\x13\xc9'\xcfU\x92\\\xf4\xc6\xd05\x95\x9b(\x08\xeaXk;0\x7f\xf2=0\xddd\xfb\x86x`;\x19K|\xf6\x08 \x1c.\xef\xe72\xc8\xc2E\xa7\xba\x11\xdd\xc1i\xa7\x9d\xa4J\xa4\xe4\xc6\xd3\xb2\xc9u\xa7aE\xb5\x8a\x16\xdb]\xb8\xd9\xee0\x02C\xa0\xe5\xcd\xf0\xdc7\xb0,Y\xee\xb3.\x9b0\xf7_~\xdel@\xb0p\x93\xe3\"\x19\x12\xb5\xabk\x92uP\xa4De\x1d\\JZ\x11\xd6Y\x7f\xa4\x0cY\x832d\x918\xc2\xb2.\xba\xd0-7L+\xabG\x07\x8f\xcf1\x04+\xf9\x8d\xf1/\xde\x81\xe0\xf2\x8a\x1a\xde\x8ee<\x93\x83\xbd\x87\x8bY\x92\x12\xb0:\xe5\x81\xae\x0e@\xdb\x95>\xf3\x04\xfb\xd8\x88\xe6\xf9 ?\xde\x88\xe1\xe3\x8b-\x01\x0e\xfcE:e\xa9s$\x07P\xce\x86\x04E\x07\xed9WUC\xac[\x99_\x85\x89\xb2e\x1d\n\x04\xd0\xb8\xe7-\xf4\xbcJ\xe1!\x16\xac\xb9\x05q\x80U\xfb\x90(\xa7\x18\xa8\x0d\x07*M7R\x04*\xcb\x01$()\x86\xa5$\xb1\xb5\x8b\xc59\xedxeW\x95\xf3\x85\xe5_\xb7K(\xfd\x15\xa6\x8c\xdc.\xae\x81\\\xc5aG\xa1\xf3\x1b\xa3R\x92\xadJ\xbc\x94\x14\xc4\xcbd\x02\xea\xdc\x92\xa9\xe672\xcf\xa6\xbe\xf4\x06d/\xb9\xa4\x00\xa5\xfb\xf5po\xc4%T\xd4\x10\x06K\x15O\x81\xd8\xc5\x8f\xd18H\xab#\x93\x96\x84#\x8f\xc4\xf9\x99v\x93E~-\x85sn\"K\xa3\xa5\xad\xe5u\xb6\xa0\\\xb4\x90\xac\xa3g\x97\x1di\xbb(`\xd7\xaa\xdd C\xbb\x01E\xf533\xfd\xec\xa4\xa8\xc2#\x13]@M\xf2\x8b\"\xb8Kk\xda\xe8\xccN-\xc5\x9eT\xda\x8d\x9a\x83 \xeb(\xe2$\xe1>\xccq\xe4\x99(\xbdx\x08\xe2C\xe9^\xc6\xac\xee\x83e\x96i\xeb\x11\x91\xf4\x8b,g~\xd2\xacb\xa2\x022\xbc3\x8a\x80\x0e\xef\x8c\x10\xcb\xc9p\x7f\x04;@\x87\xfb\x86\x0c\xc1aU\x90\xbc\x91\x95\xc1j\xb1I\x86l\xa4v\xd2\x00\xf6\xdbm6+\xf4\xb9\x1a\xe2\xa0\x1f\xee\x99\x06&8\xd7_e\x8d\x0f\xe1\xd6\xfdR\xfc\xfa!h(\x04m8\xf5\xc2\x89S\xc2\xdfE\xc3+\x0f\xbb\xd1\x17\xe2 \x1fJ\x89\x1bV\xbc\xc8\xc9d9\xde@\x87![\xff\x15=+\x05;G\xd1\x87S(*,\xf9\xf2\xdd\xb6\x0c\xd4\x8a\xe5&\xdfWG@\xca&\x03\xaf\x0f:\x12\x89\xf9\xcc\xc3\xf5\xf4|\xff\xd5\x8b'\x13\xf5s\xec[N%\x8f\xbfu\x0b\xa8\xa6\xbf\xad\x85M\xae\xd7U4\x82\xf8\x05[\x03\xde\xedz-b[\xbd\xc6\xfb\xb2\x8a\xbf\xf8\x02\xa1Y\xea:\xf91OH\x90\xfbz8\x97k\xd6\xf2\xb3\x04\x81\x84\xf3\x84\x06u\xcb\x14\x0c\xfc\xf6u3\x0b\x9f\xf0\xf3\xac\xce\xc4\xdfE\xbcv&Bx\xb6T\xfd\x0bM\xa2\x81Z\xfa=i\xa9\x10\xe4\x95\xd9\x92\xf0\x81\x06\x94\xf6|\xba\x05Y\xe2\xc1\xb9\xe5\x9e\xc0U\x97\x022_\x1f~2\xc1O\x01\x86\xb0W>\x97\x1c\xdf\x1d\x07\xfe\xf5\xf5m\x1e\xec\xff\x06\x9c!\xaef\xa7\x00\x86\xba \\\xce\xe4\x9a\x80\x92X\xe0\x02\x88H@\xd2/\xb29\xb9N\x07\x1c\xbd\x1c\xcd\xcb\xfaR\xffFFJ\xe5\xc7\x8c\x11\xbb\xa5\xb3\xaf,Gq](\xe2\x00]\xb3\xbcy\x81\xf8\x87\xce\\\x08\xc2\xc4\"jr\x90\xfe8\xa3\x05\xcb\x97c\xd4,\xfb\xd1\xf7\xaf,\x8e\xdeI\x99\xcdFD a\x89\x116\xcb\xb3\x0bD\xf1\x0f\xab\x059\xca\xf3,\x0fzG\x97\x0b2fd\x02\xc3\x97\x11\xfc4\x02\xb6\\\xa4\xe4\x00z\xb0\xdd\xcaHk\x19\xc3?\xdd\xd1U\xaf\x88\x8cG\x08#x\xea\x1b`\xf5\x8b\xbb\xcd\xa5\x00[^\xb1A\x19\x17x\xbd\x9a\xfe\x87\xbb\xe9z\xc4V {\xfaUc\xb88\xb7\x15j\x81\\^\xbd\x12\x8f\xea\x1c\x9c\x14\xd7\\zT\xee\xf6\xd6\x13\xb41\xce\x9aY\xdd\xf1-\xe9\xa4/\xf3\xac\xbf\xd0\xb3\xcbW\xdf\x0bm\x13k\xa7.\xb5\x8c\x9eu\xe6\xba'\xf0Hf\xa3<\x10\xc5>\xe0\x10v\xf8\x0f\xbfs\x9fZ\xb6\xf2\xb9\xf4E\xfb\xc9x\xe0\xa3\x14m\xe7\xa5\xf9\xd3\x9f=0\x1f\x8f\xc0\xd3\x94@\x96\x03\x06E\xef\xa4\xc9\xa7r\x0f\x98I\xbc\x18\x14\x1f\xb5\x81@X\x97\xd9\x0b\x16yG\xe2d\xc1A\x94$\xd0\x99SLX\xb0\x13Z\xb0\x98\x8eI6\xd5*\x9e;\x9c\"\x10r\x88\x1e\xf5Ok\xc9>\xf3\xc0\xa6z.\x9bpr\xe8\xfc\xa2\xa8\x96\xea\xd6\xb2\xc6U(\xe5'\xb2*\xac~\x89\xea\xda\xf2\xe3\xca\xf4\x8b\xe5+\x8f\xb7\xf8\xc5\x8c\x11\xae^\x9d\xa8K\xceeB\xa6 %\xef\xf2lAr\xb6\x92\x9c\xaf\x7f+\xfc:#L\x13-7\x19\x83\xbat\x12$\xc2&7j\xe2\xaa\xdb F\xbf\x8a\xdax;\x8fo\xd3uF\x1a\x89\x98#\xe8=\x8d)\xcd\x18o\x1d2\n1\x85\xa4L\xcf\x9b\x93q\x96O\xfa\xbd\x92d\x8ah;\x07\x8bi\xba\xba3\xb7\xa9\xcb\x12\x8d\xd0\xbc\xae\xfa\xa7 \x9d\x04U\xd4]\xf7gW0\x8e\xd9x\x06\x086\xf7\x80\xae\x02\xe5\x9a\xae\x8e\x88X\xea'\x90\xeb\xa7\xf1\x9c\x94\xa1\xc3\x9fD(^\x8c?&d\x1a/S\xf6\x13\xe7\x960\xe7\x8c\xb5\x1b\xfb\x00\xc4\xea\x88\x80\xc3\x8f\xa4\xa9\x98P\x97\x05q2\x94)\xcaS\xab\x15C\x9d\x99t]\xa5\xe4\xa7\xb1P\"\xda\xb1\xa9h\xd3\x7f\xb1\xe0\x1d\x8b\xe0#gL\xde\xdd\\\x95\xaew7Y\xa5\xebm>!9\x99\xbc\x8e\x17\xf0g/\x82\xdeU\xbbV\xd7\xbbk\xd4\xea:\xd7k\x04\xf0\x95\x125\xfc\xed\x90\xadyh\xc9b:\x18F\x8a\x1f\xd2PT\xa6m\xd5\xd0z\xf7o\xaenS\x96\x9d\xe1S\x92I\x95\"}\xb4\xb5{\xa1\xcc\x88\xe0\x1c\xf5f\x95\xbf~g\xae\xdaG\xef\xae_\xfbHo\xb8]\x06\xb5\xd6p-\xf5\xb8\x0f\xb0+\x90U\x9f\x06\xa8\xb8\xd1 \xa7?rv\xbf\x91nDGD+\xf2i\xa30\xd8\xd2\xba\xdc\xe8E\xbe\xb9\x80\xa1\x0e\x90\xa1\x05\xd6\x12\xde\xe57/\xbf\x12\x17\xed\xa1O\xf3l~DY\xbe\x12\xbaRM\xf9\xd3\x8d+\x9b\x15J\x10\xc2\xdf\xa0U%\xc1#\xbf6\xab\x11\x85Z\xb7V3BEH\xe4\x12\xd5?\xb2.+\xdf\xd5\xaf\x99t\xe5$\xfe\xd5\x16\xd4\xd1\xc2\xf4\x9d-\xf2^\x18$\x1a\x84dRh\x84t\x00\x1fX\x1d\xbe\xc3\x99\xaanP\x83zY\xe7\xc0\xb0o#`\xc1\x1b\x16\xc1\xafa\x04o\xaeA\x81\xdb\x82\x1fR`\x13&\xd4\x9ao\xc4\x0dt\x96K\x13m\x8b\xa2i\xce\x86Q?rL>oD3\xb0q\xf5e\x9b.\xbc\xa9\xc3\xcd+T\xe8\\\xab\xc8l\xc67\x0e\xdf\xef\x159\xdc2%\x1b\xac\x8dQ%\x1b@\xa3\x86\xf74A\xd7\x1d\x89y*+\x87=8\xfc*l\x05\x896\x80 0\xb7\x13;t\xb2h\x06\x02\xa7\x02\x9fk\x87\xcd\x06`\xc8\xaf\x03\x06\xda\x00\xc3<^\x18\xf0\x15$\x18Z\x85_\xde|\xd9\x19\x119B\x94\xda(\xa99\xe0\xd6&\xaf\x99\xf3<\x1c\x97I\xc0l1KW\x9c@\xa9|\xcb\xff\x14\xeb\x10\x8a,=e\x0fV\xd5y\xd9|\x16\xc9|\xcd\x14\x0eD1 SWa'Q\xd8\xechB\x1b\x9f\x0e\x96\xd0\x01Au<\x99\x8f\x0bZ\xd7=\xb5\x0c\x1aV\xd4m\x82\xcd\xba\xa8\x9e\nye\x19\xa2N\xef\x8bRL@\x83\x8aP\x1a\xa2\xa2Y\xac\x02\x16\xc4G\xbf\xb0\xd2\xbcbZ\x0e\xd7RT' \x0b\xde\xb3\x08^\x86\x11\xbc\xd7\x97\xca\x14\x08\xe8I\xc4\xcbh\xc06%\x7f\xffe\x9b\xab\x93\xd2\xd8\xd7\xc7\xb8\xe9\xbcy3\xdca\x08r_\x96\xcc8S?\xbc\xff\"\x84\xbd\x11\x0ce\xbe\x18\xca\x14\x862\x85\xa1\xa2\xda\x96\xc2K\xaf\x9aa,x\xc6\"\xf8!\x8c\xe0\xd9\x97s\x10\x0e\xe4{v#\xc8\xf7Wb\x18\xf3\xc7/\xe3dn\x0c\xbf\xfe\xc3HT\xe1\xcf\x86\x88\xf4Jr\xba\xaft\xe8\x10)\xcct\xf1\x10\xedu\x94,D\xb3\x9fW\xff\x95\x88\x84\xc7\xa5\xed!\xbf\xbeb\x81\xb5\x88\x9e\xe6d\x11;\xdf*\xd1\x15K\xf4\xa30 \xaa\x12\xa3\xd8Z\xdd\xdc\x157-R,\xbf\xdaz9#\xa2\x1b\x81\xfd_\x83\xe8\x1e\x91\xa1~{\x01\xca\xf0\xca\x9a[\xb8\xa3\xa2\x86Z/\xd6\xe5e\x89\xde\x95\xae\x11\x82@\x0eS\x18\xa0~)\xde%\xee|S\x0e\x1e\xf7r\x06\x87\"\x91\x8b@\x89\x1cQ\xa2\xba\xb9'n\xee\xb5\xf3\xe5\xeb\x97\xc5e\xd1\x83&\xd4\xce\xe1z\x1a\x827\xf6G\xcf\xec\x8f^\xd9\x1fa\x8e\xaa \xa7\x11\x9c\x10.ZP\xed\xcd/T\xb0.\xa9\xe4A\xb7\xa1g\xd5\xb0\xd6:\xdc\xf8\xf8\xaci\xd4\xf9\xe7o/he\xf2qw\xe6\xa9L\x10v\xd0YY\x1d\xdd\x85\xe6\xf5\xcd[\x1b\xdc\x90\x18\xe2\x94ks\xe1\xe2\xeba\xf5\xb7\xd2Y\x18b6\x9b3\xf1R\xfeV\x92\x89Qe%\xfa\xbfuK\x1b@M\x9fk\x9eli\x1f\xd7l\x03v\x9dT\xff\x84\xcc\x17l\x85br\xf9c\x001\x95\xa2\xf6/\xa4\x9d\xf2\xb41UO\x8dq{\xd1*+\xb5\xb0P\xffM\xb3j-\xe9'\x9a]P\xf8DV\xd0\xfb\x1bl\x03\x81m\xf8[\x0f2\n\xfc\x97\xc2c\x8b\x91\xbc\x06\xbd\xad\n|\xb2\x98~Y\x8b\xc3\x8c\x14\x1ez\xc3\x9a1\xa1\xbeD\x85\xd2ku\xe0V\xad,\x846\x9a\n\xe7\xe0\xa0Z\x87v\x1d\xe6\xda\x1ax*\xd7\xed\x1b\xc7OCZ\x9f\xa9\xccS\xea\xca\xac\xd8\x9a)\xeb\x9ci\xfb\xe8\xae\xcd\xf4\x86\xb4\xfd\xce>\xae\xcf\x1eX!\x91\x07\x06\\k:jZ:\x00])e1Y_uk\xd8\x8dS\xbc9v\xf3\xdf8C\xe25\xc1\xff\x84 \xa1\xbeA62\x0dT\x1b@\x06\x0d\xf8\x1a\x04\x1ap\xa8w\x82\xcc\x16z\xd7j\xc0\xb1\x15\xa8\x8c\xc5\nuxO\xd7\xed\xd3\xf2\xd7\x19a\xefT\xf3o\xa7\x9c\xb4\xd8\x11E\x1b\x7f\xde\xcc\xe4\xed\x17(\xb2\xec(\x99--\xfe\xebu\xdd\xcb\xb0\xaf\xee\xf6\xde\xa3\x93D\xcf\xab\xb3\xc2\xdd\x993'\xfd9E\xff\xde\x94\xcacgk\x1c\x94\xc9\xe9\xf9\xb3k'\xa7O\xae\x9d\x9c\xde\xc5\xc1\x97\x92t<\x99\xd8\x8b\x11\x18\xb6\xa6\x17 S7 \xb7\x82-\x04\xe1\x16\x19N\x9b9\xa4\xeb,zF+[UFK\x0bUy\x1b\xeb`\x97\x0f\xda\xe5\xb73*Jdk\xd5\xb2\xab\x9b?'\x18\xd4\xa2\x1e\xf0\x9f\xd5\xc3V\xf9m\xf5\xe0\x19!\x8bF\xf1\xed\xfa\xc3F\xb3\xeaV\xfd%c\x01\xef\x8c\x1aJ\x8dg\xd4XA\xbc\xbc\xdd\xae \x9eQ\x8f:\xe0\x19\xed\xdb\xeb\x80\xe3CW\x1dp\x16\x144\x82#\x8ey\x05\xbd1\x07\x93\x82\xa2-Yf\xd0\xf6\x96D\x02Nq\xfb\x9f\x88\xb0?\x9bZ\xbd1\xa9\xaawL\x98U\x9a*\xbeH\x9a\xaa\xb8Vg\xbb\xf1d\xe2\xdb\xee\xa4\xc0\x9aq\xac\xac\xbcC\xb7\xb7CH\x026\xa4\xa3\xb0}\xec85\x8a\xe5\xb1\xcd\x8f\x1d\x8b\xfa\xc6x\xec(\x07\xa9Z$\xc1p\xb7yx4\x96>\xa1\x8c\xe4\x05\x19\xb3\x9b]\xfe*\xa3\x12\xf3\xab\xbd.0\xc4/\xbeC6\x94\x98NeS\x18\x9f\x17\xcb~-,0\xf0\x14N\xbfg\xd6'\xe7$_y\xb4\xac\xae\x12\x1dJ#\x8cE\xf5\x0b\x02 \x90\xcd\x93\xa4\xc5\xa6$\xeefZ\x1aHR,OY\x1e\xff\x7f8\xf2o\xc2\x91\xeb\xc6ry\xa2\x08&\xb2\xbai\x14Q<\xa4\xcf1\x85`\xc43G\xab\xe5\x10\x81\x93\xebi\xf4$9H7I=/K\xaf6\xd1q\xafCM\xd3\x1e\\[\xe7T\xdf!Y\xce|y\x819\x0d~.\xbdw:Nf\xde\xee\x93\x95\x8f^\xc2\xd08\xebn\xff/\xd2 \x15\x7f\xadz\x85iZ\x85\xb61\xcf#3t\x90c\xcc\xb9\xafa\xd88\x1d?\x85Xk\xc4\x9b\xea\x80L\xf9\xb0;\xd5[\xc5\x7f^\xfb\xb3\x99\xc2G\xf65\x8f?\x91\xe0\x0bu>8\xfb\xa48FM|J\xdb*\xa01\x8d`\xcaq\xac\xf7\xf7\xbf\x9f\x9c<\x7f\xfd\xfa\xe3\x87\xc7O^\x1d\x9d\x1c\x1f}89\xf9\xfb\xdf{mG\x90\x05\x7f\xbb\xf0P\x1aM:\x11\x81X\xaa5\xb1f\xb5&\x05\x05U([j\x88\xb1\x1c\x9c<4\xa5w<\xae\xf0|\xc1V\"|\xba\x04\xa3\x9f\"b\xd6\xbd\x17\xebJ\xae\x85#\x08\xa3\xcaf\xdf(_G\xd5\xb4\x88\xc8\xea]\xad)\xf3M\xc2}\xee\xa4Kc\xcc;\x10\x8c\xf9xg40\x99j,\xed\xce\xbf@\xa5u!TZg\xb4\xd2d]\xfc\xbfM\x93u\xe6\x86_\xa9\xee3\x14X\xd4\x7f-\xe8pJ\x95\x03\xddBSj-*\xa5\xd6\xa2\xae`R?\xeb\x0f$k\xb0\xa0\xba\xcej\xe1\xa3\xf0Y\xb8\x14>\x8b.\x85\xcf\x82\xaa}\x08\x038\xa7\xf2\x06\xdf\x8a\x88\x92\x11\xb0`N9q\n#\x98\xdf\x9cFh\xfe\x97h\x84\xe67\xa9\x11\x92\xfe\xf7.\xc5\xd0\x9cV~\xfa\x82r\x9f\x19(\xf7\x8aFp\xca\xf7\xc9\xdc\x83\x16\x9flJ\xd8N\xffC\x84\xed\xc2 \xcd\x95 l+>\xde\x13\x1a<\xf7/\xbby\xf4\x05\x84\xed\xad l\x97\x1aa\xe3\xb7\xfaKZ\xcc\x92){\x9c\xa6\xbe\xd1\xfc\x97\xde\x8a\xee\xa7nE\xf7)\xad\x1clO\xf5\xbdvA\xe5\x0d\xb9\xd7Np\xaf\x1d\xd1\x08.8\xb5<\xba\xb9\xbdvt\x93\xbb\xe2\x98\xc5\xe3O0\xe4\x1bb\xd4\xde\x10G\xd7p\x05\xa9\x1b\xe3g$6\x14\xaaG\xbd\x15\xd1\x92r\x93\xf0\x81H\xbcNvv\x1e\x84\xf8\xbd\xf0\xaa\xb2\xef\x058\x04\x99\x84\xc6\x14\xf7W\x1b\xf9\x82\x90O\x1b\x01\x88\x8f\xba2\x1c\xf2_\x86\xec\x1d\xad^\x96\xc5\xac\xab\x97J\xdbP\xae\xaf\x9f\xd6\xa1\xd4\xf4\x95\xce$\xb8\xfb\xb7[\xedD\x1a\x03\xcc\x07\x1e!0\x9bo\xc1\x0e\xecq\x88?\x12j\xc3\x9d\x9d\x10?\xb3\xf1\x05\x98Y\xa5lcH-\xb9\x0f\xf9\x825\xd7\x82_\x86D\xcbu|\xb4\x04S\x96\x9c6\xae\x87\x16o\xd5\xac\x18*\xef\xd6\xcb\x9f3\xe9\xda\xff\x98\x9a\xc5\x93\xd6\xe2=\xe6\xa4\xc8C0\x91\xead\xb4u\x05$\x0c\x05G\xe4^\xbf*\x07I\x87\xd4\x82\x0c\xb8\x19\xba\x1d\x9b\xaa\xe4\xed\xcb\xf0\xa0\x0d84&\xb2\xe4\xd9P\x00*4pT\xa7\x10\xeb\xdfN\x9d\x0f-2\x8aw\xca\xc0X\xdb\xfa\xb3\xc6\xfa\xd3\xeb\xae\x7f\xdb\xfd\xba\xb5\xfeYge*\x1de\x8b4\x19\x93`\xcf\xdd\xa6<\xa66i\x97\xa3\xa1\xa7:\xca\xd4\x95\x0f\x067\xbb3\x9d\xa2\x8d\xd67\x9fF\xb6\xb8\xce,6\xb12}i|\xb6D\xa9\x06\x06m\x82W\x9c\x15q\x83\x8d#\x89\xcf\x91\xc9\x89\xca[\xe9\xe8Q\x0e\xd6\xc7\x15\x8cbq\x11\xa2\x7fe\xd6p\x7f\x08jM\xd7-TeG\x17\xa49\xfa*M\x8f5\xc6\xaf<\x99\xf2\xda\xc9\x84e\xce\xb2:\xc9\xe2\x07\xcd\x83\x10\xeff\xee\xd3\xdd\xbd\x88yc\x11\xb3k\xad\xdfcj\xaa0\xddX\xc3\xcd\xd4V\xa5.\xa9\xad\xb9\xaa\x10\x94\xe3\xeacZMH\x9f\xcc\x86a\xc8\xfa\xcc\xf6,z\xa8\xa3kkAe\xdc\x81\xbe$\xd5\xd1\xa2y~\xb9\x90\x82\x8a=\x977\x10!\xaf%\x13\xccU0\x08\xd5\x92 \xe27y\x07\x13\xe85Y?\x1d\xa9\xd7l3\xb3\x0e\xb1\x9a\xa9\xf1\xec\xcb\xfdNn\xcf\xc8\x84N\xaf\x7f\xc5O\xe4]\xf1\x03\xb2\xdf\n\xd0\x91\xf0\xec\x17\xcb`Q\xd1\x98g(Z\xead\x1e\xba\xb2\xf393\xf3\xf9D\x05\x1c\xa1\xd6\x15\x85\x9a\x01\\\x1a\xa4\xf7c\x1a\xc1S\x93\xde\xf5\xc3\xe3\xa7/-\x9a\xd7O\xfc\xfd#\x0fi\xffq\xe9\xae\xd7\x91?\xb4.\xf3\x7frf\x94\xa9\x98\xe1L\xe7\x84\xb3\xa6\xa3^V\xd1\xbf\\\xfc\xaaS\x07\xbf\x94\x81o\x9d\xa7\xee\xb1\xd0\x03\x1cs\x80<\xa6A\xcb=\xc5\xd2\xe8\xbbnq\xb1D{\xabYR;\x9c\x86\xa8\xa3cCjH\x84k\x85\xa4\x9e\xbe\x8bU\xbc1\x0d#\xa8\\&\xb5\xd0\x88\xe3\xd5\xfc4K\xb1B\x82\xeby\xb3\xadf}|\xfd\xd7':|Z\xaa\x17?\xf9h\x03?\xb9\xb4\x81\x9f\xba\xb4\x81\xbc\x0b\xdd\xb6\xf6D\xb7\xb5E@\xfb\xcf+\x02\xf91\xe2\xcbDM\xe9\xbfdJl\x8f4_\xafH\xe0bE@.8\x91\xb9qE\xa6\xed\xeah_\xaf\x8d6zh0\x06U\xbe\x07\x8b\xe9\xcdi\xdaV\xd8c\xa61\xad\x15\xc4\xbbm\x9a\xc0\xb2\xe7tB.\xc9\xe4\x98|\xf6\x00\x8cF\xe2\xdf\xcb\xa8s\xbf^^\x1c\xfb\xb7\x8e\xc01\xa6\xc2\xf6\xd1\xccc\x82\xdf\x9e\xfa\xa4\x07\x9c\x85Y-H6\xc5\xfc\xda/\x8eQ\xe7\xc8\xff\x10\x16\x1e\x0b\xf8P\xbb\xc4\xdf\xf1\x9d\xde\xdb7\xff-\x13|\xfb\xa6\x9c\xe2\xdb779\xc9\x97du\x0dAC\xf8\x13\xd8\xfa\xa4\x93F\x8f\x1eU\xa3\x10\x98\xfcS\xcc\x89\x1aX\xcc\x1b\xa0\xebI\x0f1\xa1\x89\xb9<\xb8aXB+\xb4\x19,j\xc8\x125W\x9c\xa1\x84\x8ay\xbbYh.Sc\x18\x08\xe7@|6o\xa3oRZR\x04=\x84C\xe8aE\x028\x80^\xd4\xb3c2\x83\x01\xf4\x0czTu} \xa6\xbbp\x9c\xcaR\xfd[{\xe8\xb2\xba-,%\xfc_t3\xdaR%\xa4\xb4I\xe1\x9a\x96^4x\xe6\xf4\xda\x9c%\xc8\x1d\xe0\xc5\xb7}\"\xab/ ?\xcf\xbdVt^\x93C=\xd0\xaa\xdcb\xf5\x94\x9d^\x9d\x89\xb3t\xc3\x0d\x16A\xe6\\\xe0\x06\xae\xb5\x1cT\x1e\xc2>\xe6G\xe4\x98\x02\x07b\xc3\xb6\xb6\x83\xae\x06\xc0\x9a\xb5\x0e\xe4\xc8\xe0\x10\x82LR9l.\x94\xed\x92\xb2\xf4\xad\xa8\x18\x988\x0b2\xe7\xfe {\x9f\x9c\xcd\xd8\x86pS\x84Ig\x84*C\x94\x9b>I\xaeG\x9a\xdes\xab\xdd\x1dl\x83\xc6^\xfcq\xb7D*=\x19\xaeWWh\\\xbe&\x06?\xb9\xde!\xc1\xb9\x91\xcdz\x14yYD\xac\xdc\x1b\x8a\xa5\xc2LY0L]\xe5^5&\x9a3\xb3\x06\xe4\x80\xb9\x1f\x94\xba\xbf\x80\xd6\xfc\xee\xd5\xcb\xe9\x92\xbd\x8a7Q\x0f\x88}\x8d\x1e2\xbb\x11\xec\xecy\xf5\x92\x14G\xf3\x05\xf3\xb11\xc8^4\"\xae\xcb\xe9M\xc9\xfd@.c\x9d\x19\xf5\xe0EmFH\xaf\xd9\x8c\xb3%m\xee\xfc\x8e\xf9<\x0dH\xa5J\x12\xdb^\n\xb0\xe2\xe3\x0d\xf4*\xd8\xfb\x13_\xf6T\xf6\xefK\xa5@\xa3T\x1fI\x10V\x06)W\x06<%\xe5\x98\x88w\x17\xeb\x8a\xdf\xcb\xbc AU\xa7\\T\x12\xe7\xbbR\xcfy\xec%\xb5i2\x97\x99\xddU\x97\xa3\x94\n\x9e\x05\xba\xb9\xcdR!\xefJ?o}V\x8f|^\xc6\xe9&\xc2\xd69)\xc9\x86W\xfb2k\xa6\xc7V\xd3\x1dN\xcdk\x8b\x81Z\xfd\x13L\x97W+\xceDHu\xdf\xcd)\xd6\xab\xb7\xfeN\xc3\x86\xaa\xd5\xcd'\xd6\xaa\x1at\xf9\x8e5>&\xc6<\xa0\xea\xba\xf2\xe4\xf7\xc4.}\x93m\xb8\xdf\xa5\xf8\x81;|\xa3\xd3\xa5\x14Y6\xe7,,\xd5\";xn\xea']V\xc2%m\n\x97\xbc\xefa\x16\x01\x1d9\x05L/\xd6\x8aO\xff%\xf1%n5o\xf4M\x84=T\x8dQc\xa9]\xf3\x98\x1agd\xc7\x8a\xe8 7\xb3z8\xda\xb2\x99MF\xb1!rx\x0e\xa5\x02\xdc\xa6\xe3\xf1_-\xcf\xa1\xbc$r\x05\xfdF\x91o\xcc\xbc \xe8\x1f\xfb5\x9f\xc6\xec\xf5\xb5\xa51\xdf5\x02m\x13\xffb\xae\x93\xa4\xae&m\xabk\xea\xbb6\xb2\xd6Bn8k]\xc7\xa1\xae\x895o\xf1\x8d%O\xd9\xe2\x06ga \xd9\x1f5)\xc1WD\xd0\x8f\x12\x7f\x8c\xe1\xa7\xdd\xab\x0d\xcc\x90\xf5\x82y\x1e\xd8R\xa1\xa4.\xef\xfa\x14\x1f\x9fa]m\x9b>5\xaa\xfcd}\x07\xfe\x9cz\x0e\xddTnZ\xf8\x03c\xa1MUa:\xabU\x98\xee\xcc\xb6\x9c`\\\x90GV\xe4\x00}\x1a\xb1Z:\xc6-\xa9\xa4\xc4I\x04+\xceJ\xafB\x14\x13V\x95\xbf\xa7\x19D\xaee\xf1:\xad\xce\xf2l\xb9\xf8w\xb0\xe2~6\xbc@f\xbb{\xc7P\xd5\xc5\xf9wO\x06\xde\xc8\xb9w\xe9\\\xf8\x95\xb59w\xfe\x99\xe0\xdc\xbb\xf7\xb5~I\xf0\x04\"\x04r\xbd\x86\xe1(\xc4\x18\x06\xccY>\x8c#HFp\x00\x89\x87q\xd0A\xc7\xec0P(\xe8G\x81\xb3:\xe5\xed4?U\x14\x8cD\x90\x04&\x12\xa9.\xcb\xf87\x165f\xf1&r\x06\xd2!\x99py%b\x08V\x9e\xbd<\xdf\x84\x86\xab~\x9e\xd3M{J\x8a\xe3\xe5\xa9g\x81\xcfR\x06\x1c\xd8|\xc2\xcaJ)\xc2\xea,y\xf4J'\xe4\xb7\xb4\xe5y\\&\xc6\xd9 \x9f\x96y\x8a\x0b\xce\x0bm2\xc9\xc05K 3m\x96ay\xd3\xffT\xfbDVo\xa7\x1b\x0c\xa9<\xd483\xb7\x11$o\xc0H(\"\xce\xfd\x8f\xf8\x9aV\x86\xef\xea\xe7-)\xd5\xa7\xdbts5Z\xab\xe4W\x1f\xf9Y\xff\xfe^^g],\xbc7\xae\xb11\x97U\xbb\xefy|\xb9A\xaf/\xd8F*\x8cy|\xb9\xe9\x99\xfa\xa2\x96\x8f\xc8\xab\x13?\xa3Yk\x06p\x08\xef\xa9pa\xf9\xe8'(\xcd\x13z\xfd\xe9\x88\xee\x98\xe8\xcewn9\xd9\x18\x13\x8d!\x8f`n\xbe\xf8\x94,6\x80\x9d\xd6\xfe\xeb\x98\xcd\xfa\xf3\xf82\xb0T$\xb6t\xd6\x14\xbe}\xa5\x04\xcb\x1e\xe3M\x06D\xbb\xe3=\x90\x9fgI\xba\xa1\x99\xa1\x1c\xccO\xd74l|J\x16\x1f)K\xd2\xcd\xba\x15@WC\xdeL\x05%\x12\x82m\xd6_\xdb\xcaa\xc8\x0c\x06\xe6\xfeX\xfc\x89l\xb0\xbc\xacf\x80\xb8\x06J\xf1\xfen\x18\xa5x\x93\x9b\xa3\x14\xff\xeaKP\xea:\x92\xc4?\xbc\xb8[\xad\x84\xd1G\x8aj\xdeZ\xf26\x8c\xac\xec`x\x15;\xcd\xac\xdaeuq\x91.\xab\xc7\xe6i\x05Zja \xd8\xb1\xbb\xb5sY\xcf\xbf\xa3\xec\x7f\xc9\xb8\x19\x04\x1f\x82*\x91e\xd7\x0c\xb5f*\xe9\xa7\xfc\xf6\xd6-\xd8\xde\x8eQH\x95\x0dZ\n\x95\xab\xeb*\x8c \xb6\xbeq\x15\x81^\x06\xe9\xbfhU\xb2|\x93e!5o,\xfe\x9d[\xae\xe5\xd7\xd2\xe1Q\xa2.9N\xcf(K\xfdB\xdf\xa9e9\xd3\xee\x0f\xc0?\xe2Q\xbf\x9c\xd1\x8f\xfae\x89\x95\xd0/e\xba\x89;\x8bS\xa9K\xe8\xf0kE\xaa<\x1c\x1aUD\xa3\xac\xdf\xeb7\xd1B:\xab\xfa\xbd\x9d\xe2\xdb{\x1d\xae\xad`\xdaki\x04\x05j<\x0f9i\x1b\x0c\xe0\x8d\x14s>s\x8c,\xf0\x05\x91\xe6o)=C\xfe\x0b\x16\xb7\x8b\x088)\x80\xf1\xe1\xe6\x9aW~\xf0\\\x97\xa9(\x0f\xad\xcd\x98\n\x15C\xb0!_\xba\xb9\x186\x8b\x8b\xd9\xd3l\xb2\x81\xa3\x0b\x9bU\xd9\x05\xb0\x8a\xf3L\xcf6\xd0\xcd#@\xb9\xbd\x84\x83\xf2`\x00{p\x1bv\xcb\x8d\xe6 ]\xcaL:\xeeT\xf0\xf9\xb9\xf2\xa36\x16\x0ea\xcf\\\xf5\xb6|M\x0c\xcck\xf1\x1b\xdf\xf0\xd1^\xa2\x90~\xe7\xee\x9d\xfd\xef\xf6\xbe\xbds\xefN\x18\x95\xb7\xe1\xe1C\xd8\xbb\x07k`\xf0\xe8\xd1#\xd8\xd9\xbb\x17\xc1\xdd\xfb{\xdf\xde\xbd\xf7\xdd\xee7\xcd\xf7\xeeh\xef\xdd\x89\xe0^\xf5\x1c\xd3\xb9\x07\x0c\xb6\xe1\xce\xb7\xf7\xef\xee\x7f\xb7\xbf\xf7\xdd}Xs\x98\xfe\x8bo\xe9\x7f\xc9\xcf\xf6\xeeG\xb0\xbf\x7f\xf7\xfe\xb7\xfb\xfb\xf7\xca\xe6\x8f\xe5\xe7\xd8M\xf9\xe6\x9d\x08\xee\xec\xdf\xbf\x7f\xf7\xdb\xef\xbe\xdb\xfd.\xd4\x9bpl\xb9@\xe7\x0f(\xd6\xba<\xdc\x10j0\x80;{\xf05\xe4\xb0\x0d\x9fi\xf0\x94\xe0\xa6yJ\x02\x16\x86|F\xf6\xce\xc1sw\xaaKh\xc5\xaf\xd1K}R>\xdd\x943\xc2\x8e:;\xd8\xacq\xcfvCc9k( \xa2\x89\x14\xd6\xee4\x95\xc1|/~\x10\xc9\xc9\xb4\\\x00\xfa\x1b\x1f\xe8p\xaa\x02\xbc?\xd0\xe1+\xfe\xf7\x07i\xb2(\xf8-\x19:*n\xcb\xc0\xea\xf2\xbe\x1e8\x04\x03xF\xf1IB\x8b\x85\xc8\x8d\x8f\x9f\x1cg\xcb\xbc\x9eW\xc6\x04\xb2\x86\x12I\xba\xb7\xd6g\x87\xad\x8fgqBE\xdb\xd2\x96)ng\x94\xc5 F\xa5\xe3\x10\x84\xee\x12c\xc4s\xd3)9M\x93\x0dB#K\x01\xe5#\xb3\xae\x84I\xed\xb38j\xb9\xf7\xfbZ\xff\xedT1\xb7\xcb\x02N\xe1n#\xc3j)M('\x89a\x12A6\xb2\x17\x9f\x06\x10FU\xcd&\xe9)4\xce\xe3\xc5\xcb\xba\x0f\xb2/\x8c\xae\x01\x04\xbe\xeeMXt\x89\x19-X\x88h\x04\x07\x10\xb0\x93\xeb\xec\xd6\xd7\x14\x93\x9btf\xeexn\x07\x92\xdaI\xf5\xbe,\xed\xfc\xde\xd9\xce\x90E@F^\x8d\xbd\xb1\x90\xc3\xe6\xd9\xdc\xb1\xd9\xb6\x88O2.h\xc3\xd32\xac\xf773\xac\x9d\x1b\x1e\xd63\xf7\xb0z\x05\xd2\xc0\x9a\xf1\x03\x0e\xe1\xc5\xf1\xdb7}\xf1(\x99\xae\x84\xdaVRK\xcf\xdc\xa2\xaf\x9c\x04\xf8\xd8\x9a\xc9\xd3\xd2\xdc\xc7N\x0c\"\xf0\xb0\xe4\xe0\x08<\xc2\xbfw\x90\x9d\xf3\xea\xe0\xb3G\x07\x9c\xf5\xd9\x86\xfd\xfb\xf7\xee\xde\xbds\xef\x9b\xfb\xdf\xc16\x04\x843d\xf7C\xf1\xe7\xa3G\xb0\xdf>}\xeb\x0b%[{M\x87\x0bu$\xbe\xae\x8eD\x19\xa8\xc5\xef5\xceD\x91^\xa0|\xd08\x14;\x89\x9a\xec\xb6\xb1\xb0\x0c\xa3o\x0f0\xfc\x161\xa5>p<\xd82s\xf2\x93/M\xdf\xe0\xa73\xbf\xd1\xc0\xa9=\xbf\x93b\x9a\xd0 JO\x9e\xdd~\x817\xdd!:\xd3\xc1\x01\xec\xb4\xfd\xffLfN>*?\xc3\xd5\xb9\x9e>S\x99\xa8\x9c\xa3\xd1\xd2\x0c\x97{\xc7\xcb\xd53\x8d\x0b\xf6\xfc\x9a#+\x8dq\x7f\xd9\xe8n\"~\xc3\x13qn2~\xc3\xb7\xcb\xc5\x06}*Dm\x86\x15\xd9\x9d\x98\xf9:U\x96\x02.u\x8a\xa0Z\xb1\x10\x98\xf6j_\xfe\x89\x15\x8c;\xb23\xf2\x8b\xa8\xec\x8c\x9c`\xef*\xe7~t\xce\xafRDt\x04\x85VI\x15\x959\xa3\x03{J0\xef\xc9\xd1\x1eB\x0e\x07\x90\xab\xd0\xfdc=\x02x_94\x88\xd61\xc7\x81gP\xb0r\xee\xfc\"\xf2Qz\xab\xfe\x15$\xe4:\x8e\x9f\xa2\x9a\xbdW\xeb7\xe4\x9a\xe8\x89\xfd\x1b;\x0d6\xd2k\x87\x88\x82\xaa\x14]]\x0b\xa5e^\xafG\xd3\xdc\xba%\xf8\x8b\x99\x96dU\xe1\xed\xb5\xfc\x11EUmKV\xa5M\xdd\x117s^j\xc1\xe3\xd1\x00v1\x07\x85%\x90\xc8\x02(d\xbefUt\xd1\xce^\xf5\xa5<\xb4Z\xd5\x14\xc1v\xc61\x92/\xb2b\x13\xd3\xe6\xf5\x93|\xf8\x99\xf5\xaa\x12\x03%\n\xec\xc3\xd7\xea\xd7\x0e\xec\x89\x02\x03\x0e\xcb\x9f-\xf5\xa1~)\xa3\x01s\xca\xe5\xeaJ\xbe\xd8V\xd79 \xad\x8d`+\xc1R\x00b]Eh)\x17\xd1\xb30\xd4\x92\x96b\xb3\xf2\xbe\xb3\xe5+\xde{\xe4\xca\xa3\xa1C\xd4l\xb6\xf3\x06i\x84\xb0\xaa\x19\xd0~\xc7\xfe;'\xefo\x0f\xbd\x86\xfd\xac\x84l\xc6!\x1b\xc3\xff\xe5\xb2\x03\xdfz\x1c\x07\x92\x9a\x0b0\xc6\xfc\x1e\x88w\xe0\x10>\xf3\xb9\xc7\"\x1d)Zm\xd4\xcfL\xa5\x8c\xed\x02\xbf\xd3ZbIU^Q \xefm\x9c\x92\xf8\xdc\x87\xf3Rf\xb9!\xefbd8\x94C\xc7bq\x1e\xe5\xa5 \x00J\xff\x12\xc1\xcb~6EgZ\xebg\"?\x89\xe6\x9d\xef}\\\xc3\xbf\x8e\x1f\xf8\x9e\x11\xaa7\xed\xde\xe3y\xf2\xffq-\xbd\xeaK\xf5\xc7+\x1a\xb9\x90\xcd{\x0c?'l\xe6sN)\x99G\xef\xc5\x8do\x9c\xa7S\x01\x02\xed\xf1\xdbL\x96\xb5;W!\xa7\x08Uz\xd8\x89\xd27\xe87\xcb\xba-\xef\xd0q\xbd=\xfc\x8dy,\xc4 Q\x0bZ\x9a\x95\xbd\xe4\xb4\xeb\xe6\xd31T\x9d\x86\x9b\xd9l\xd8|\x95\xc3\xcd\x03\xda\x89\x96g[\x94\xd0\xaeY \xf4\xc7\x9a%A\xbf]3)\xfc\x1a\xe9J\xda\x10\xef\xbd\xac-\x9f\xb8\xf7C\xadiq\xef\x84\x18>\xbe \x86\xaf\x8fH\xf3\xf36TT~\xb9\x03\xa0m\xb8\"P_\xb4\xef?\xcd\xd2\x94 \xa4\x0f\xe0\xd4\xe0\x03\x81\x01b\x1f\x0d\x0f\xf4\xb4\x92\xefX\xfb\xb9\xc8\xcb\xb70<\x91\xa9\x02\x8f\x8c\xa3d\x07P\x18\x1e\xe8Y%\xe7\x86\xe7\xef\xc98\xcb'\x07\x90\x9b\x9e\xc5\xf4\x8c\x1c\xc0\xca0\x89\xf7dAb\xde\xa4\xe1YR\x1c\xc0\xccp\x7f\x9agsLmkK\x97|\x15\x01\xe9\x93\xcbE\x96\xb3\x02\x93\xc4 \xac\xbcr\xfb\xb4\xf5\x96\x05\x81\x82\xe5\xc9\x98i\xf9i\x94 ]\xdbn\x9a\x0f\x8d\xdeQ\xb3u\x15\xfb\x16G\xb0\x8c\xa0hn$L\xc6\x1e\xb00\x82-\xe3\x1e\xe6]\xa7m\xfa\xa7\xa5\x01C=OX&L;\xca\xf3,\x0fz\xaf\x13\x9aL\x132\x01r9&\x0b> \xc8\xc6\xe3e\x9e\x93\xc9\x03\xe0\x93d3\x024\xa3;s\xf5\xe2\x84\x9c\x03\xa1\xe7I\x9eQNu1\x02\x8b\xbf4]\xa6)\x10\xde*\xccIQ\xc4g\x04b:\x81x2Ix\xb3q\n3\x92.\xa6\xcb\x14.\xe2\x9c&\xf4\xac\xe8\xf7\x0c\x14\x9b\xa4\x05q\x90\xfc1\xe7i\x9a\xc0r\xf8\xf7L\xed\xfcfP\x07\x05\xeb\xe7d\x91\xc6c\x12\xdc\xfe\xbf\xc5\xed\xb3\xa8\x9b\xa8AE\xd8\xc6\xc3\xe9\xf6v;\x84\x17\x90\x8a\x85a\x9f\xc6s\x0c\x8dxN\xcf\xe3<\x89)\x83\x9f\x92,\xc5\xe4\xdb\x86\xfc\x92\xad;l\x96g\x17\x90\xf6\xa7y<'\xc5\x87\xec\x1dV\x91\xd9k\xa6b\xd3\xb0\xfa\xcb\x91\x98\x06w\xee\x86f\xdc\xcd\xaf\xdf\xba#K\xa2L~>!\xd3\x84\x12\x95\xfc\x9c\x8bE\xbd\x93\x13R\xbc\xce&\xcb\x94\xf4L\xa4T:I5\\\x9e0\x8f\x12\xe7\xbb\x9ef\xf3yF\x8f.\x19\xa1\x85\xcc\x7f\x8e\xf7\x1bwH1\x8e\x17XS\xf1UB?\xbd\x8b\xb1\xae\xa2J\x9d\xdf\xba]\xcc\xe24\xcd.\x8e>/\xe3TV#d\xfd\xd3e\x92N\xbe\xcf\xf2\xf9\xb3\x98\xc5\xe2\xb5,g$\x97OY&o\x92<\x89\xd3\xe4\x0frL\xe2|,\xda[\xc4y\xa1\xff>#\xec8\x9e/Rr<\x9e\x91\xb9\xf8\xee\xaf\x17\xc7o\xdf\x88\x9d\xd1\xe9\x01\xc6\xf2U\x07\xb3\x8c\xb6*D5\xab\x8eF\xe8\xa8o\xdd\x82^\x86\xbd\xf6D\x11\xb2\x86\xb1\xa0\xb7\xa4b\x9fNzp\x00\\\x82*\xf8\xc6\x8d\x97)\x0b\x03\x16\x86\x8ex\xd7+\x18\xc7l<\x03q8\xb6\x1e\xcb\xef\x1a\xd9\x1b\xae\xf8^\x16\x03J\xa6\xabNH\xc8F\x8e\x05\xc3|$\xf9f-\xa9<\x1c4\xfb\xc6\x1e\xe2<\x8fW\x1bt@d\xb3\xe8]\xa3\xff-\xeaI\n+\xefp\xd4\xeeH\xb0%\x92O\xd2z\x03b\x0eM\xe3\xabr\x84\x1eT\n\xae\xe6\xb3\x9eAB\x0b\x16\xd31\xc9\xa6\xb0RK\xd2\xe7[\xd2\xf5i /\xc6\x01U\xcf\x86\x8b\xb7\xd2\xb2)\xce\xb8\xcb\xb4\xbc$\xec\x8b\x8c\xce8\xdb\xea\x95\x8a\xd9\xac\xde4\xd5Nd\x98`\xf0Cv\xcc<\x0b\x05)\x15\xa3)\x87\xbb\xd2\xfd\xecF\xb0\xacP\x91\xb4\xb3\xf3v [\xe6\xf0\xc5!3$\xe80\x14\xbe\xeb*\xc6N\x879\x17\x0f\xc90\x1f\x89\xf4\x8at\x99\xa6fMt+\x13&\x82\x8cf\xf9\x1c\x0f\x0f\x81s\x03\xb8\x8c\x90N|O}\x91\xd6<\xc1vOIQ\xd2\x9dc\xd9\xc7\x92\x8eo\xbe\x175\x11\xaff\x9b\x99\x9a\x8dT\xe2u\xbc\xf0A'+\xca4\x93\xfa\xba\xf4\xa2\xf5ue\x01_Y\xa1\x8a5\xe5\xee\x84?\xdb\xa5\x84p\xc8\xef\xb1\xcb\x7f\xdb\xa8K\xc5x9^\xa7\xee$s\x1e\x08Y\xd7\x81 U\xda\xfcn\\\xdd\xa5\x18r\xb1\x01\x98\x8aU\xc1\xc8\xfc\xc3lI?\xbdN&\x93\x94\\\xc49\xf1E\x9c\xee\xfd\xcf\xfa\x93\xa4X\xf0\xb3I2\x8eH\x97\x9cp\xe9n\xd4\xf4\xb2\xd3\x82\x05\x1d[\x08\xcd\x93\x01 0\x959\x0b,\xbel`\x14#\xccw\x0d\xe7\xa0\\#\x0e\x80e\xf14\x9btC\xf9\xbcL\xb2\xa5\xaal[I4+55\xc1\x05?[.\xf8D\xfc\x93\xa8+\xe0\xec\xf7Ty\xd4m\xe8\xf5Bc\x06\xa5\x10\x19pK0\xf3\x95\\f~\x82\xf9l<\x8c\xce\xa9N9\xa5\xc0\xe1\xbc\xa7\xfc3\xd0\x8a)V/\x8a\x13\xb2\x0d\x0eu\x9a\x11\x99\x83\xc0p\xec2\xce>\xb0\x91\x1d\x96\xf5^\xfaI\x81\x9dQ\x91\xf8\xfe\xa05\x88\xf6\xfcg\xc9\xd9,M\xcef\xdd\xdc\xa5Z\xe1I6Fu\xab\x99\x01\xd9\xaa\xf8\x8c\x9e!s\xaf\x08N`\xe4\x92=\xcd(#\x94\xa94\xac\x8f\xe0\x1e\xb9S\xc5\x03\xe9\xafX'\xdf\x8d+\xb5\xec0\xba\xd2@\xa4\x83\xab\xfa\x88\x90\x0b\xdf\x8dP=\xb2\x1c\xee\x8e\"\xd44\xecE\xa8@ \xfd\x84R\x92\xff\xf8\xe1\xf5+\x91q\x18\x16\xa8V\x10r\xb2\xa8g\xbb\x80\x87\xf0\x0d\x92\xc9\xdf~\xc3\xfdJ\xa5\xe7\xdc\xd8\x99m\x86\x03\x84\xf7\x94\xaa\xae\xb7\xb7\x8b\x910\xafM+\xd8\xecE\xb05\x86\xf5\x1a\x16\xf0\x08\xbe\x15\xbd\x08\xaa\x80w\x87\xb7\x7f;\xbe\xddg\xa4`\xc18\x8c\xf8\xdb\xfc\x83\xdb\xc3\xaf~\xbb\x18i\xf7\x83\xdem9\xb2\xf5\xbal\x80\"iN\"\xf8[\xefo\xa0\xdcN\x92\x08z\x7f\xeb\xe9?\x97\xc3\x02v\xe0\xee\x08\xb6\xd1)\x9e\xf2g\xbd\x9d\x9d\xdf.\xefp\x99\xbc\xba\xf5\xf5\xed\xdeh\xb8\x18\xb9\x8de\xb8,SQ\x98\xa1\x1f/\x16\x84N\x9e\xce\x92t\x12\xc4\x9a\xc8}\x94\x12\x8efA\xafX\xc4\xb4\x17\x86\xfd\x82\xb0\xc7\x8c\xe5\xc9\xe9\x92\x91\xa0W\xb0\x15\xaa\x03\x86\xbdq\x96f\xf9\x01\xfc\x9f{\xf7\xee=\x80iF\xd9\xce\x05\x11 qO\xb3t\xf2\xa0\x17\xe1\x8a\xe1\x7f\xfa\xabxo4\\\xc0!\xae\xdd\x1d8\x84}8@\x08\xdf\x87C\xb8+\xff\xe6\xf7\xef\xc0\x01l\xdf\xfeW\x10\x07\xa7\x05\xcb\xe31[\xa7I\\\xac\xe9d\xadL\x0fk\xbeg\xd7E0_\x17$g\xe1\xe1z\xc9\xb2p}\x1a\xc4\x05Y\x93\xb3\x84\xae\xb3,\x0dHL\xc3\xc3uN\xe2O\xeb\x15#\xe1z\x8c\x8f\xf9\x81\xb3\x9e\xc5\xf9\x1aE\xdb\xc9:\x8d\x8bb\x9df\x94\xac\xb3\xf9\"]g\xb4`\xeb\x8c\xb2\x84.I\xb8\x9e\x90\xe0tyvF\xf2\xf58\x99\xc7\xe9z\x9c\xc69YO\x03\xbe\xc7\xd7$\x0f\x0f\xd7 M\xd8:\x0d\xc8Y\xcc\xc8\x9a0\x12\x1e\x86\xebI\xb6\x9ed\xcb\xd3\x94\xacI0\x9ee\xeb\xb48L\xa6\xeb\xb4 A2\x0d\x0f\xf9<\xb0\xf6\xe8\x9a.\xe7\xebsB\xd9\xfa2\x18\x93\x05[\x93\xf1z\x11\xa4\xc98a\xeb,g\xe1\x9a\x91\x80N\x8a5*M\xd69\x0d\xc3\x90w\x9d\xa6l\x96g\xcb\xb3\xd9:N\x0b\xb2Nh\x9c\x06\xe9\x8a\x0f\xe5\x92O'\x8b\xf9\xd7\x01\x89\xc73>\xfb\x84p\xb0e\xf3\xf5\x92\x8e\x03\xbe{\xf9\x00\xcf\xd2\xec4N\xd7g\x19\xcb\xd6g\xcb8\x9f\xac\x93`\xba\x9e/\x02\x81\x03\xc5Z\x1b\x04\x0d\x12\xb6F\x95~p\x92\xd11 \x0f\xd7i\xc2\xa1\xb5dk%\xfa\xacY@\xf2i<&k\x92\xd38\x0d\x0f\xc3\xc3u\x11\xae\xd3 \x9e\x9fN\xe25a\xebl\xfci\x9d\xd1\xb3p=\x0f\x92q\x9e! \\\xa3\x8ai-\xd4\x08\xe1\xfaM\xfcfM\x83xN\x8a\x05o)f\xc99Y\x93K\xb6&\x17\xeb$]gl\xbdL\xd3p\x9d\x05\xc8\x16\xad\x17\xc2\x10\xbe\xce\xd7K\xb6>'y\x9eLH\xb8^\x04\xf1\xf8S|F\xd6q\x1e\xcf\x8bu\x9e\x9c\xf3u\xc93F\xc6\x8cp@\xb0l\x9c\xa5\xeb\xe5i\x9a\x8c\xc3u\x1e\xc4 \xc7\x98 \x9ed4]\xf1\x85\x9b\xae\xcf\x92\x82\x91|\xbd 1[\x7f^&y5\xefb\xbc$k\xa1b[\xb3|\xb5\xe6T1\x0c\xd7Ep\xba\xe2\x8b\x1f\xa7d\xb2&\xe9t=\xcbr\xb6N\xce(\x99\xac\x93?\x10<1K\xc6kT\xe7\xacY\xbe\x1c\xb3\xf5\xf2\xb4\x18\xe7\xc9\x82\xad\x97\x0b\x92\xafWt<\xcb3\x9a\xfcA&\xeb\x8b\x84\x8dg!\x87\xe8|\x91\xf2\xc1\xcf\x08]\xcf\x92b=\xcb\xb3\x8b\xe2p\x9d\xc7\xb4H8\xd2\xe4K\xb2\xceW\xeb\xd5\x82\x041\xee\x8f \x99\xae\x93\xc9\x9a\xc6s\xb2\xce\xa6a\xb8^\x064\x18K4\x9f\x90i\xc0\xd9E\x8e'\x19]\xa7\xa4(\xd6\x85\x18#K\xd2p]\x90u\x91\xf0\x05:\x0f\xe2|\x9d\xe4l\x19\xa7\xeb,\x99\xacQm\xca\xd7\xe7\"\x18\xcf\xe2\xfc\x84\x89\x01\x91\x9c\xacgIJ\xd6 \x9b\x85\xeb\xcb,_\xaf\x12\x92N\xc2\xaf$\x01\x9cr~iw\x14r\x16T'9\x8a\xdc| \x97\xecM6!\xc14\x0cC\x91Al\xc1)\x94\xa0\xeb\x9cF\x1c\xf0\xf3c\xaa\x1d\x00{{\x0f`k\xb8\x17\xc1\xed\xe1o\xb7\xff\xbc\x1a\x06\xbf\xedl\x7f=x\xf8\xe8\xe0\xc1\xfa\xb7\xdf\xfa\xd1\xe1\xd6\xad\xbf\xff\xfft\xfa{{\xf8\xdb(\xac\xdfhPhI\xa0\xc7\xbc\xe3\x0cS\x93sR\xff\xb0\x07[x\xceH\x12=.\xa9\xf3\x98\x1fS\xdb\x90\xc26\x12\xe8m\xd8\x1b\x95\x7f\xee\x8f\x90 \xffvyg\xbc\xb5\xb3\xd3So\xf2{\xb7\xbf\xae\xff\xbc\xcdi\xe1\xff\x11-\x8e\x86;;\x8b\xd1\x03\x87\x07\xcf\x14\xb6\x070\xf6e.\x8d2\xda<^|\xc8\x1a|\x97M\xf5as\xb1\xe4\xc7b#\xc9~\xf9\xcapo\x04\x87\xf5\x9f\x07\xd0\xfbDV\x06\x96D)\x06\x0d\xed\xef[\xdb\xdf\xaf\xb7\xbf?\xaa1[\xaf\xe3\x85\x89\xe1k0\x90\xaf\xe3E?)\x84\x96\x04=\x81\x84\xf7\xc3\x06\x1cd\x9dc\xa4\xa2\x82\x0dE\x0b\x89\x89g\xe4\xfd\xd3*\xef\xfd^\xa5\x11\xea\xcfI~F\x02\x93\x14x.\xa3\xe5\xbbG\xc3\xdf\xe4\x8c\x155V\x07\xe2O\x0bK\xf4\xbc2\xecl\xed\x99\x9fM-:]p*=K\xe6o\x11\xc1\x04\x06(~&\x9a\x96RE\x06\x04!\xa6 \xe4\x83\x0b\xf8\xb6\x9e\xd4\x1c\x85\xc2\x07r\xd8..\x8e\xf72\xe3\x14\xc3'8\xfd\\\x8e%\xab\xc62C\x17Y\xe7Ws\x0e\x83\xceP\xf63|k\xaf\xe3\xad\x15\xe7i\x83\xb3\x08h\x99m'\x82\x9c3X\xc12\x82yS\x0d\xad_mTPB\xc7\x8a\x0b\x1d\xb1r\xfe\xc0\xec\x87\xb1H\x9a\xb72s\x83\x06b\xa1\xab\x86\x8d\xdf\x8c\xa5k\x05r\xe5\x86\xef\xa7\x9c\xfbHm\x18a\xc7\x15~ma \xdeI_n\n\xedo[\xe2\xe6\x8e\xee@\xf1\xf7\xa14\xe0M}\xe1\xd0\xba#\xc7\x14\xb7I)\xb9D\x8e\xf4\xfb$%o\xe29\xf9>\xcf\xe6R\xa6y\x96\x14\x8b\xac@\xe3\xeb\x8f$\x9ex\x94\x95W\"\xde\xedi\x92\x12~l\x0fz\xc1\xf0_\x0fF_\x87\x0f\x0e{\xb7\x93>\xb9$c\xa3\xe1\x00\xcb\x9e\x08\xdb\x00g\xea\xebm\x94MT-\xd8\x88\x93\xaa\x9e\x82\xcdh\xb2\xa1F\xaa\x8c\xf9\x19\x94\x12n\x99\xa6m\x08-\xe2b\x1c\xa7O\xe3\x82\xc0\x00\x9e\xd6\xef|/\x07\xd9 \x1a\xd9\xc3\xd3\x80Tf\xe2\xdf\xfa\xc3\x7f\xf5o\x8f\xbe\xfe\xea6\x17%B\x93\xc6*\xa6 K\xfe \x1f\xf3\xb4\xb3\x07\x0e\x802vlK\x8b\x1d\xe3\xc2\x9a\xd0u\xb8ekM18\xd6{\x0e\x8dG\xf0\x19a\x8f\xc7\x9c\xcb\xe7\xd8\x92gi\x9a\xd0\xb3\xf7\xa4Xd\xb4\xe8\x86F\xe3$\xab\x14\xfe\xfd\xa4\xd0\xb4\xff\x9a:\x84/\x8dMcP?\xf6\xccoV\xfa\xa5\xbaCx\x97Wry\xc2\x15,\xceY\xf1s\xc2fAo\xbfW\xea#u\x15*:\xe9\xf5\xc6b\xf7\xf4\xf04\xfd\xf3*\xac\xb0\xd0V\xa8\xc1LlK\xd5N\xd0\x93]\x88&\x8dv\x12K\x1b|\xcb\x06\xd40.s#a\xa9|\x93\xa6.5v\xa1\x0d2CVA\x887\x9b\xb7\xf1dB\xc8\"]\x1d\xb3\x8e\xbaLmJ\xf3\xdeP\x86\xffye\x0eLi\xe0hf09\xd9\x15\xdaU\x1cQ\x1edC6\xc2\xbdr\x08\x13\x92\x12F\x80\xdf\xe1B\x0d\xff\x87\xf3\x03\xe2\x0dj\xcce`\xcaV\xabl\x03\x06\xb2\xa7\xa2!\xbd\x08\x89)`\xd6\x95\x19HV We=\x95Y\xd7r\xa6X\xad\x16\xa4k\xc1\x89\xb0Z\x94\x87\x12 \x1d\x0c\x84F|s\xad\x89\x08\x84}o\xdf\x00R\xc5\xect\x19$\xcdQ\xc2\xe0\xe2\x13\x88#\x15\x03\xebS\xf4\xbd\xf8\x90\x95\xfe\x1c\x1ek$\xbe\xb1\xac\x91\xd6\x9b\x15M\x1a\xa6\xbf\xfa{\xe7\xb2\x92\xe7I@\x83oL>\x12ctH\xba\xf7\xcd\x9e\xe1\xd9T~x\xef\x1b\xa3{\xc5B\xb9f|\xbbkz<)\x1f\xdf5=\x9e\x95\x8f\x8d\xe3:\x97\x8f\xef\xdf36>W.%\xbb\xf7L\x8f\xcfpV{\xdf\x99x\xff\x95\xfc\xf4\x8eqR\xa7\nX\xfbw8\xe2\xd7\x9e\x97\x04\xfa\xa4\xc3w\xe1\xd6-\x0c\xe1P\xbeU\xd2\xb5\xd8\x8c\x8b\x12\xa5M\xa5\xea\x9bQ\xf3\xfa/\xbe\xb0\x170\x80\xf2\x08lO\xe5\xc8\xe0\xc0\xd3\xad\xd9o\xc9\xc8fsL{\xb06`]ndv\xae\n\x047&on\xfc\xd8\xd9\xf8\xd6\x16q\xdaW}(\x95c\x0dtO\xa9\x89\xfa\xc8\x06\x86\xa7\xce\x91\xf2~\x17U\xbf\xfc\xe7\xd4\x7f\x18u\x07\xaeN\x16\xce\xa1\xf8\xd9\x8c\x8b\x18Z\xc4a\x0b\x8br\xc7\xda\xf8\x9dz\xe3wD\xe3NN\xbcn\xa2\x97} \xefQ\x7f\xc8\xca\x87\xeb5 `\xcfk\xc7\x88\x0e-\xab\xfd\x18\x9d\x84\xab\xfc\xdf\xb4b\xbfM\x9a\x15\xd0\xfd\x00\x86\xd4\x92\xf6\xces\xa3\xc1!h\x02AR\x04\x182\xc5Q\xd5\xcaq\xf9\xa05\n?\xb6\x06|\xfc\x0e\xf0\x08'\xf8i\xd6&\x06\x82{k\xd4l\xeb*`\xb3\xc5{\x99k\xc3\x1cR\xceY\x0d\xa9\xc1\xeau\xd5\xdc\x12\xeds\xef\x93\xc5\xe1\xb1s\x7f\x80\xb2\xa7\xc2#\xa8\xc2\xc4{?\xc5\xe9\x92\xc0|Y08%\x90\x92\xa2\x006\x8b)\xc8\x96\xbd\xca\xd9?\xb68fn0\xa6\x87\xf61\x9d\xa1\xc2=\x97\xc3\x12\x8d{\x0d\xeb\xad\xd9\x85\xb4\xfb\xb4@9\xf3\xf6\xbfv\x0e\x7f\x9bl\x07\xbf\xf5\xf9?\xe1\xa1\xb2\x0chRjc\xa01H\xb6\xc7gp\xef,>\xaf\x9b\x8d\xcecP\x14#\x01\xcf<\x87\xf5\xc1\xe4\x9b\xeb7&<\x95\xb6\x02\xe2\xf0)\xb4Cn\x9a\xa4\xc4k\x80\xaf-\x0e\xc5~c\xec\xb1|Iz\xb2n0?D\xa7qZ\xe87\xb6v\xb5\xbf\xf7\x14#o\x1b\xf5\xa9\xe8\xdek\xe0\xcf\xcd\xce\xd1~\xe3\x16\x835\xa8{\xecc\x93/\xfb\x0c\xedw\x9b3\xb7\xdf\xe0\x92\xe2M\xfc&\xe0\x9f\x95\xce\xc2\x8e\x95V\xcd{\x8d\xec\x8d\xc9\xef\xdcoTJ\xd8S\xa2F\x9fe\xaf\xb2\x0b\x92?\x8d\x0b\x12\x84\x11l\xdd\xfe\xd7\xf0\xcf`t8\xdc\xdd\xf9.\xde\x99\x8e\xfe\xfc\xf6j\xa7\xfc\xfb\xae\xc7\xdf{\xfbW\xc3\xf0j\xe4E\x18\xf8\xc8\xbd&\xfc\xde\xea~\xefOL+\xde\xc4\x8f\xce\x8b.\xbc\x86\xf7\xcc\x1a3\xb0\xf9\xf06 \xf9\x1b\x8c\xf0\x95%\xd2\xc1{|[\x94\\\xc0{rvt\x89\xfe\xc8\xae\xa5\x9dfi\x9a]\xc0Bv\xd2\x83m\x93\x03{\xfd\x0co\xc7et\x8e\xec\xba\x9c\xed\xad[\xb5\xdfv\xae\xd6\xc6\xf1\"\xab\x87\x94\xe74\x9b\xac\xa4RY\xa8\x17\x13\xda\x13N\xf2\xf8\x0b\xcdX'\x97\xf3\xb4\x87\xee\xf2\xda\xcd\x9eEU\x99T\xea\xce\x9c\xa0\x9b\xc2\xc4\xf6j\x0c\xc2;J\xbe^`\x84\x8b\xe8\xc8\xa2\"\x8e\xcb\xd5\xca\xedv\xc7X47\x97|\x8e\xa5\xf3\xb1\xf6\xa6d=,oN\xab79q\xb6\xbd\xb6\xa8^\x9bf\xf9\x8f\xe0,\x82\xd3\x08N\"\xb8\x88\xe0(\x82\xcb\x08\x8eG\x0d\xe1\xd59\xf6J\xdfd|\xc5V\x92\x0eYB\xe4\x9f\x9f\x86\xcd\xb9\xbf\x97\xb4\x1e\xa6 I'\x90\x14@3\x06\x8b<;O&x\x02\x98(\xb6j\xf4\xdc5X>\xf1\x8f0\x80WA\x16\xc1\xb9\xc3%\xe1#\x1a8\xc4x>\xfa\xba\x1a\x80\x1c\xc2\xa4\xda:\x93\xae\xd1|\x86\x01\xbc\xe7\xa3\x998F\xf3Y\x1b\xcd\xe7MG3\xeb\x1a\xc2\xf70\x80g|\x083\xc7\x10\xbe\xd7\x86\xf0\xfd\xa6CXV\x00q\x96\x1d\xe1\xa3\xf9\x03S]a\x91\x11\xfbh\xfe\xd0F\xf3\xc7\xa6\xa3\x19W\xa3\x19w\x8d\xe6 \x0c\xe01\x1f\xcd\xd81\x9a'\xdah\x9el:\x9a\xfa\x91\xd85\x9e\x9f\x1c^K\xeaB\xee&\xf8 5\xe41#;\x8c\xcbQ\xd8\xfc\x02\x0e\xe1\xf7\x00Uh\xbd%\x176\xca\xbbo\xc4\xdd\xe7\x82\x88\xda\xf9\"u\xc9\xd9\xfedsb\xa9\xc8l\xfd`\xeb\x9a\xdf\x8f0\x80\xd7\x81\xab\xda\n\xce\xee\xc7\x0d\xc6\xf8c\xf7\x18k\x87g\xd7\x10\x7f\x86\x01\xbc\xed\x1e\xe2\xcf\x1b\x0c\xf1\xe7\xee!\xd6O\xe8\xae1\xbe\xc0\xec\x8d\x9dc|\xb1\xc1\x18_t\x8fQg\xb0\xbaF\xf8k\xc7\xd0N\x91\xf9)\xd90\x9f\x81\xfe\xaax\xd6\xe74\x18\xf6\x12F\xe6E/\x02\xc1g\x8f0\xc9N\xcb\xcc\xdd\xe5\xe9\x01\x9a`\xd5\xb5\xed\xf8U\xc3\xa4_\xd1E\x82#\x0b\x86\xaa\xd6\x97P=|'\x1f\xeaT\xe0Wd\xc0\xf8\xd3\xe7\\\xa8\x8c\xa4\xb9]\xac\x83{\xb0\xfcJDVKC\xde\x95\xe6\x85\x995\x0e,\x99\xc4\xd4\xe5\xac7\xdb\x89\x13\x1a\x83\xdc\x85\x12/a\x00\x1f\xba\x91\xf6\xa5\x0f.H`\xbd\xf4\xa5\xc6V\xab\xb7\xc1{\xa5\x9dF\xc1\xcd))7\xa3/w66X:Az\x05m*\xf6\xb7\x0cZ\xa6\xf8g\x0e\xef\xdb\x97\xf3T\xea\xae\x98U\xbeK\x84\xcf\xd5\xe5<\xc5m\x8b\x7fa~\x12\xd7\x9a\x0b=\x0f\xff\x86K\xf9\xf2\xdb?\xaf\"\xfe\xfdW_\xe5d\xaa;\x03\xac\x16\xe8\xb4F\xfa\xb8\xaf\xc5\x9f\x0b\x91\xcf#!\xf2w\x95\x16\xe6]\xf5\xe4\x10\xfe\xf6\xf0\x907~N\xf2\"\xc9\xe8\xa0\xb7\xd7\xdf\xed\x01\xa1\xe3l\x92\xd0\xb3A\xef\xe3\x87\xefw\xbe\xed\x1d>\xfa\x8dJ\xb7v\xf8\xe5\xf5+ \x97\xb8\xc40\x8e)g>O \x9c\x11\x8a\xc9\x19' B\x94\xfef\xf5~R\xd7yY^\n\xa7\xd3\x9fsQ \xb8\xfd\xdb\xf1\xd7\xbf\xdd\x0e~;\xde\x0e\xbf\xba\xed@\xf6\n\x88\xb2\x84\x94'*C\xddXx\xa6,\xb5\x93\xa7\xa8/\xfb\xe5\xf5\xab#17\xe1J\xe2\xe3\x01r.\xcb\xaa\xd5\xdb\x13\x9b\xe0\xfb<\x9b\x8b\x8d \xdbk\xcfH)\xc5l\x92]\xd2%\xd9%a\x08\x87M?\x98\xa4\xf2\x83\x81\x83F\x8eJ\xe9\xa3\xa9\xa7?q\xba}\x9d\xcb\xcc\x86\x7f\x1at\x85 \x93\x17V\xe2|\x9a\x8d1\xcbN\xbf\xc0\xc6-\xfa\xa5Joi\xdbZ=\xa1\xa4w)MD\x16\x94byZ\xb0<\xd8\x0b\xfb\xc5\"MX\xd0\xbbe\xd2\xc6\x80\xee\x9f\x9eCB\x81\x86@\xfb\xb3\xb8x{A\xcb\xdc7\xb9pS\xc4(\xc3a>R-\x0e\xb8XE\x86\x132\xce&\xe4\xe3\xfb\xe7O\xb3\xf9\"\xa3\x84\xb2 \x1f\xee\x8e\xc2\x11\x0c \xe7T\xe8\xd6-0\xbe\xb37\x12v\xd5\x9e\x0f>\xa9m\xdd^\xb3v\x1a\x1b7m\xb5Z\xc5\xfd\xca\x97\xab\x81\xd0\xd6\x8cD\xca\xfdA\x0f\xb6MO\xc9\x90\x19\x0d\xb3\xfd\xdf\xb3\x84\xe2\xf2\xb4\xa7&S\xf5\xb8\x07\xa5\xe6S\xcb\xb9\xa1r\x17Sr\x01$`\x9a\xb9\"\x82\xde\x92Mw\xbe\xed\x85au\xb7w\x1a\x17\xe4\xfe]\xd3\x18\xaa\xd4A\xed\xae3\x0c6K2Z\x1c\xe3[6\xaf\x9d8]\xccb\xcf\\\x83\xa0\xbb\x8f)m\xe2\xac\x17\xe2\x16J \x07h\x9c\xf3)i\xcf,G\xb6yc\xce \x9be\x93k\x8fF|n\x1b\x8fz\xea\xcdD\xb4\xc7\xc8\xe2\xb3\xbf\n\x9c\x8d!{\x0f\xd2\x80\x99\x8d\x14S~\xec\x8c\xc9I\xa5\x8a\x8d\xe6\xe4\xc7z\xfa+_^b\xf5\x10\xd1\xd8\x96\x1c5\x88\xbd\xeao&x\xbb!\x8d\xf8\x06\x8dL\xfb3\x0f\xb5\xc4k\xfb\xbb\xb7\xcf\"\xe8m\xf7\xc2\x91\xdc\x9f\xa6%\xb5R)\xe6\xda\xd4\x86\x94]\xb5\x95\xb48\xd6\x94J3N\xb8f\x15\xe1\xa2\x9aSN\x97\xcb\xc8F\x1e#\xf5\x91\xd7a\xae\x94b\x96\xbcd^\x04\xd8X\xa0\x063\x8ektL\x9a\xb31\xa5Q\x9e\xcc\x03m\x91~\xc3\xecx\xbd\x13\xb4\xd8\xf4z\xae\xe1Z\xb2\xaay\x0d\x93\xc3\xec\xb4\x82\xd9\xc7\xb6{Yd\xc8\xe3\xe6\xd54ig\x9b\xe8N\xc2z\xfb_\x97;%s\xdd\xb9l\x915\xf7\xdc_9Bi\xffY\x97\xf6\xa5ui=ZK\xbb\xd8ZZ\xbd\xfc\xa7\xf2?\xd5\x83\xb2\x90\x16\x0d\xee\xdd\x0d\xfbO\x96\xd3)\x91\xde\xe2\xd7\xca\x06hN\x88\xd9\x9cfI\xa9\x8c\x92\x99\xc8\x15\x0f\xff\x7f\xf2\xde\xbc\xbbm\x1cK\x14\xff\xbf?\xc55\xa7_\x8a,\xd3\xb4$\xaf\x91\xedx\xb28\xdd\x99\xc9\xf6b\xa7\xea\xd7\xa3\xf2xh\n\x92\xd8\xa1H\x15\x17;\xae\xb2\xe7\xb3\xff\x0e.\x00\x12\x04\x01\x92rR\xd3\xfd\xde\xe3\xc9\x89E\x12\xc4r\x01\\\xdc\xfd\x9e@\x15\xcb\xf2\x13\xf1\x83\x9c\xc7\xa2\xfc\x17$\x0b(\x81p\x047a\x16\xe6\xb0\xc8\xf3\xd5x{{\xe6\x07\xe4:I\xbex\xf30_\x14\xd7^\x98l\xa7\xf4\xbb\xedi\x12d\xdb\xf8\xf1\x16#\x9fRo\x91/\xa3\xd3P\xc4nd\x94\x86\xcb\xf3\xb9A\n\xc7\x90\x1fA\xba\xb9\xe9@\x0c\x9b'`=\xf1\xd3y6\xb94Q$\x157\x97\xa2\xcb\xaeB\x1f\xb2:\xeaq5ED\xcd$\xed\x1f\x94\xb3\n\xc8\x99uG\xe2l\xa2\x99\xa4\x16\x1dS\xe5\x15\x98C[\xd2\x1a\xd8\x12\xc58j\xc4\xca\xca\n\xef\xbb\xc4\xa8'\x14\xd8\xe7\xa4\x1f\xac\x932\x1a\xf1#\x9a\xacB\x19\xcbcf\x1d\xa8nz\xf5#\xcb\xfd\xe0\xcb#\xba\x80\x11\x98\xd9\xb8\xe9/:r\xfa\xb7W\x9b!\xb7\xd0}D\xb3\xc2\xb8\x17[\xd6\x18\xfd\xf6j?\xc5H\xcfk\xb5^\xd4\xb3\xbd\x88\xa8=\xad\xca\xa8\xf2\x84\xc84'\x04\x8b\xac\xc3\x8c\x102x\x06{p\n\x19l\xc1\x1e\x8c1\xf3R\x00'\xb0w\x04\x01\x1cCv\x04\x01E\xe3\xd1$\xa0\x05.\xe5\xda&AKb\xf0\x1b\xee\xa5n\xb6\xa3\x86R\xdb3\x93\xe9\xac\xd4c\xc1\xb0\x8d\xe2:q\xd1\x16\xd0\xd4\xc4\x9eux\x8a\x03\xb75 \xdb\xe5\xdf\x1c\xdcR,h\x8a\xc3\xa3p\x8afOSzb\xc2\x7f\xd1\x9f\x05\xfd\xf9_\x90\xcc\x90Zd\xcfV\xecYV\xacV\x11=\x7f\xf2\x84=O\xf0\xb9\x0b\xe4\xeb\n\x03\x9c\x80\x1fC\xe9\xd8\xe1\xfd=\xe3\xa1\xbf=\x8d\xe8A\\z)\x19\xc8\xb3\xbch\xe5X\xc4EK\xde \xe7\xb2\xe8H\xe9\xde\xa9\x8b\x16\x97\xb0\x8d\x99\x95\xd9\x03\xdb\xacN\xe4\x0b\x1d\xf3y\x1eJ\x91~h\xb2taQ\xaeo\n9\x8f\xc2pQfP\x88\xda<\xf1\xc5E;?/\xe5W\xf3\xd6\xf2f\xd8\x1a\x82\xc5\xf5\xda\xe4\xd9\xc2_\x911\xac\x9aoD\xa07\xed\xcb\xa5\xbfzY\xbe\xef\x8d\x1ef\x88\x9c\x1ew\x06F\x18\xe5>\xb3\xf5\xe7\xb6\xb6\x87X\xbc\xd9Z\xdb\xf9\x8a\x9f\xf4<+\xb5'#V\xd0<\xeb\xdaN6\xb9\xcd\xae\xb3\xcap2\xb1V\x0dg\x8d\xae\x9f\xbf\xf2~\xfe\xca\xfb\xf9+\xf6\xf3WM\xd9\x94\xc7\xfb\xcfl\x8b\xed\x7f\xcb\xed?\xe1D\x87.\x9b\xb3\xadi6,S,d\xf6\x9a\xc7\x99\xec&&z\n~\xb3\xaf\x82+\x11|t}\xbb\xf2\x11h\x9c\xc7\x84\xfeu\\\x1f\x1e\xb3R\xa5\xef\x85\xfc}\xac\x8e_\xf4\x97\x16\xaa0+r\x1ae\xcen\xbb\x14>\x03\x06F\xac\x05\xdf}\xd0\x8c\xac\xd00]\xe2]\xce\x8f\xe1\xb4\x0c\x9e\xa7\x9b\xb0\xb5N\xe0}~\x02\xefK'\xf0\xbe\xee\x04\xde\xef>\x81\x05\xd5\x00'\x80\xa6+)\x0b\x9e\xc7\x8c\x1c]\xe1\xbd\xcb\xe2\xb3\x9e\x02QQpm`2\xe2\xe5\xc9\xe8\xa5\xe3\xb14u\xa2\xc0\xf6\x1b\xe7\xe3\xad\xcfl\x9f\xb2\x15 \x18S\x16\xc6\xac@\x88\x05<\x94\x97\xb0\x86\xebk\xad\xb1\xa2\x98&A\n\x0f\xbc1t\xb4++\xf6\xc2\xac\xec\x96\xfa\xcd\xa0\x16\\U7\xed\x99\x96\xfco\xd2ar\xf4D\xed\xec\x8b\x89\xa7P6\xa9X\xec\xac\xd5\xe44B\xda\xa6#\x87\x8f\x81X \xdb\x89\x95\xa8/\xb1\xf2_\xa5\xac\xe0\xbft\x14\x8aQ\xec\xd8\x8c;\xe2\xb4\xc2=2\xc9\x1b\x9b\xa0\xaf\xe0\xaeI\n\x02\xf2\xc6\x8b\xb4\x1b/(7^\xc4I\xdfH\"}g\x8c\xf4\x9d\xc11DG0\xa3\x1b/\x98\xcc\x9a\xa4\xef\xcc\x10\xd0i\x85\xaa\xa6\xc44\xe7\xb1\xbdj\x9ds\xbaf\x0b3\xfd\x84F\xd0\xf6\xeaQKB\xa2_3\xcd\x92X\x18\x96D\xd8E\xbf\xa2K\x00#\xd5\xfa,\x10fW\xc1'S\xef\xe7\xa3\x19\x00-#\x1ce\x0d]\xc4y_\xa5\xc9\xea\xa2\x1cS\xd6\xe8{\xb9\xe2\xb4\x99V\xca\x95s\x83\x91\xab\xca\xc8\xf5.\x92\xb8\x03\x97\xd3\xac<\xa1-,\xe1\x18\xe6G\xb0\xa4\x8b\xc4<\xa5\x18ZJE\xb27.,\xcbEL{9\xa1\xfd]\xd2_\x97V\x89t\x03\x13\xb5K\x81x'\x9f\x82\x08\xae\x12\x80w\x1d\xf3\xd0\xb1\x19\x85xC\x17.\xbb\xb9\x1f[\xb7`\xa2\xdd\x82a\xb9\x05\x13\xc7\xe5 \x10\xc1\x87cH\x8e\xc0\xa7\xd0\x0c'~}\xbb\xf9\xe6s\x0eQ\x07vU\x01r\x88:]\x16\x7f \xf3\x8d\xb8r\xb7\xab!\xa2[\xae~\xfe\xcaq\x84\xdaq\xf8\xe58B\x8eJB \x95\x14\x0c\x95\x14p\x0c\xe1\x11\x14t\\\xfe\xa4h\xa2\x92\xc2\xa4E\xe2(\x8cLrC \xe3^\xca\xda\xf6\xd2\x17r\x97]H\xfb\xc9NV\\\x08\x9a\x91 \x89\xa7e\xd7\x9c\xe6V\x8bM[\xad\xc9\xe6\xb6o5\x90\xa1\x8b\xe1~\xe5H=\xe5\xbe\x9b\xb1}G\xb1jP\xee;\x8a\x9cW\x1c9\x9b9T\x81N3u\xef\x05.\xcc\xca\x99G\xa4\xb8\xf5\x8c\x02\xc5\xa6\xe3\x08&\xb3K\xfa\xcc\xa9v\xa1\xdf\xc6s2\x8bi\xe3Nl\x92\xe5\xa0\xc5\x8a\x0fNs\xf5\xea\x0f\x98l\x9d\x9d<3\xd3\xe7\x92\x05\x8bb\xb7U1\x060\xae\xbdk\x9eK\xb1\xa9\"\xb4\xd1\xd2r\x15\xb5:G\x97Z\"\xee\xff\xa5\xd3\xfe\xb1\xc7y\xd1~\x9cO\xff\x87\x8e\xf3\x9b2\xcec%\xffi=X\xbb4\xebK\xc4x7-\x18o\xd9\xb5\xeb\xe9)\xbdTw\xfd\xc2\x85\x9b\xda\x89\x8b\x1c\xe2M\xf7Y\x0b=%J\x9d\xc6\n\xed[u\xd5\xdc\xaa\x95|G\xfeT\xfc\x925\x85\xcc~\xecQ\x8a\xa3\xed\x1f\xcb\x9f\x8c\xc3\xde\xf2\xb3,\x9cWl\x92\x1d8p\x1e\xc6\xd3\x94\xc0y\x92.\x8a\n\x01\xfdk\x14\x06$\xce\x08\xbc{sQ>\xfcq\xbb\xfc)tR<\x8d\xd9\x9c\xe4\x92)\xd7\xf9\xdd\xf2:\x89\xb2\xa6\xae\x8a\x97\xae%\xb9\x94\xbek\xea\xae\x1a\x1fp\xcb\xca\xbb7\xd9Y\\,\x19\xda9\xd2\xc2\xcdH\xc4\xe8=\xa9pS\xf3\xe6\x18\x94Z\xc3\x89\xdcp\xbb<\xba\x83\x85u\x93\x7f\x1d\x98|\x11\xc9\x04\xb1\x8e5%\x96\x0b\xd6\x1e\xb34\xd4\xc2\xee\xbd\xbf$\x99M\x9c\xc9\xe0\xb2\xb5\x0355\xf1\xef\x0fL)<8\x82\x18\x8eaH\xffR\x84\x97O\xac+\xba\x15X\x0f1\x0f\xd3\xcb\x85\x9f\xbeL\xa6\xc4\x8e\xd1t.\xd6\xf7\xd7\x1a\x0cG;\xbb{\xfb\x07\x87O\x99}KK_s\xc5\xa6\xadK\xc4\x95\xabq\x84\x00$\x0b5\xab=\x8c\x8bXw-I\x91\xe8\xc9p3\xb4\xb6\xb2\xd2\xb6\xc2\x94\xd7\xc4\xbb\x9aE\xfe<\x83'PPZ\xe5\xa5\x1f,\x08K\xa5@[\xd1\xcbxo\xcaLG\x154\xe8\x17)\xd1$\x80\x06\x11\xa7\x82%m\xc2\x82M\x9c@\xc6\xb2\xb8\x02\xed\xe7\xb55!zV\xed\xea\xc3Vm\xfb\x0d\x8fx\x1fO\xc2\x8e8\xea\x19\x02\xddw\xbc\xabi\xb2|\xf3\xaa\x9d\xa2f\x16\xb2Z\xaeN\xbepTGU\xd4\xd1\xe4\x08\xa1\x91`P\xfa\xf3\xf0:\n\xe3\xb9Yy..\xda`d'\x94\x8b\xecjP\\3\xdbw\xa1\xcd\xa3K\xbe\x02\x9e\x91FC\x08\xa8\x97Y\xe7L\xaf\xd4\xb6vF\x16\xed\xa7\xb1\x98A5\xdd\\\x12bi\xde\x9f\xe8\xd7\xe6\x9f\xf4\xdf\xeb\xb6\xc0\xb4\xb9\xb5\x19\xd1\x9aU4(\xbd92\xec~&qa\x96\xd7\xb0\x81%M\xc4\x03w\x7f#\x98\xda\xdb[\xf9)\x89q\xc3:\xb2vA\xb3\x01p?U\xc5\x0d\x83\x83jI\x91\xd2U\x11\x87q\x84U\xa4\xde*Y\xd9\x8e\x83\xd8\x8a\xf6Y\x98U>y\x02+z\x96\xaa(E\x90\xac\x7fj\xb6%\xb8\xe3\xfa8\xe7$\x7f\x19%\x19\xc9rq\xc6\xbcN\x93%\xed\xf2\x18\xa6\xaeZ\xb4Y\xa6\x9d\xfc\x12\xf4\xfeT\x1b\x97^\x82 \xca\x0b\x99I\xba\x84\x13y\x18\xc2\x9c\xfb\x87\xd5\x81\xd8\xe8\x1c\xfd\x86vLt\xb2\xabsa=\xfb:\x91Z\xc6\x98\xcc\xd6\xce\x0e\xba\xf2T\xcf%7\xba\xf2Y\x07\xa7\xc3V\x98T\xdc\x11V\xf7\xa4\xaa\xfb#\xae\x13\xd4\x8f\xda\xd6\xce.\xb6\n'\xf5\xb7\x86v\x8e\xca@\xfcl\xc5\xe4b\xc5\xe01!\xf7\xdd\x08\x7f\xa9P\x1b\x84W) \xe8\x96\xadvl\xc3nD\x14\xe1KC!ub\xf9]\xafe\xd3\nf&L\xe7\xd1\xb2\xe9\xc9Y\x1b.\xdd/E\x14\x19\x8d\xa5\xf5<\xf8\x02\x9f\xaa\x04\xa4\xdc\xc5\xea\xb0\xac\xbeR\xce{\xe6\x1d9\x06k\xe4\xedy{\x96\xaeMM\xc0\xe6\xab+\x86\x01\xe8\xdf\x13q^~+);\xd0\x19\xe0N\xac/a<\xa5|}J\xb2$\xba!,\xf7Z\x9ca\xae)z#D\xc8\x1ff\xf4n\x95\x92i\x18\xf89a\x9f\xacR\x92\x91\x18\xcbq\xf3\xffs\x9e\xec\x8de}{\x1e\x85~F2\xeb\xb2I.O\xac,\xf0#?\xc5\xb2\xe4\xd7\x82\xc4\x01~\xb7\xf4W\xab0\x9e[\x97\x1d\x92\x11#y\xe5\x82__ \xe1\x8c\xe5\xb9\xc8\x85'\xac\xcc\xe1\xe6}\xc3\xb4\xd3Z\xb6x\xd8 \x0f\x9d\xc1?\xcc\xd0w\xb7b\x1bS\xfb\x87\xcf\xf1\x978\xb9\x8d\x81\xa9.\xc0\xfa\x81\x13\xa8?X\x10f\xb0$9%\x80\x90KD\x03oHf\xac\x0cae\xfe\xf6\xfc\xdd[\\\x04\xde\x0f\xcaju\\\xc8\x17a\xe6\xe5\xfe\x9c\xae8~G'\x0f7:\xfe\xe0\xf1\xed\xf9;>\xa1\xf8Z\xfc\xbe\xbf7\x8b\x96@b\xd3\x15\xb3\x07^c\xb9.\x98[Ky'\xd7\xda\xea*\xa1\xad\xb5Z`,\xbctu[\x1fO\xb9\xf4\x18f+\xef\xd4Q\xf35\xc9\xc7-\xee\xea\xa5\xe4\xc5\x8a\x05k\x0f\xeae\xe5\x85\x8c\xec\x1cs\x1e\x95\x9f\x96\x1f\xf8B\x9e%hB\x8c1 \xaf\xb7\xb8\xaf\x08'\x9e\x90\xcb\x9eK\x93^\xfe\xa4d\xc6LR\x9f\xc6\x82\xf2\x1d\x17\xf8\x92\x0e\xab%-\xd6\x95ii\xe3Rc\x0b\xbb\\\x82b\x81W\x165\xf4@\xea\\\xd9\xbdx\xf4\n\x85\x8dvG\x8em\xdd~\xc9\xd4\xf8j\x8c+\x1f\xee\x1b\xd8\xf2\x1d\xc7cR\xdd&s\xaeM\xdc+\x99\xe3\xda\xfd\xfc^\xf8\x02G\x91\xdb\xfd=\xd8\\\xf6\xe6\xd3\xd9\x0f\xc5C\x1f\xf5\xb0cH\x1c\xdbb\xfda\xc6`\x92\xb3\xd4\x83\xe3ey\x82\xa9\x92\xd3>\xb0\xd1#\xfd\\\x0e\x15_\x0f\xdc%\x80\x19\xda\xb1\xbd\xb7\x7f\xa8\x06\xacO\xf8\xab\xa7CG+7\x08\x8dC\xef\x1f\xa3\xde\x10\x9f\xfe\xe1O\xcd_\xe5\xbel\x13\x89\x0bmD\xdb\xc1\x00\x1c\x81\xab\xf6}\x15\x11\xa7\x17\x81)\xce\xf1\xa5\xf0\xae\xfa\xb0\xb3Y\x90\x08\x05S\xb0Gz\xa5,_\x96\xf1}\x88!\xe1\xcc\xef\xfd\x8e`*\xed1\xd8J:\xb5`bH%\xeb\x19\xc1\xbck\x98\xe3\xa6@\xd5u-\xef\x1a\xe3V\x18%[\xb0\xbcj\x94EbHW\x8e\xa4\x9e;G|\x9c\x06\xe6\xb5_`\xb7\x90\xa7\x16\xf3\xb5\x88\x0e\xa0_\xbe\xaf\xee\xa0t\x1b\xe8\x18\x9bIi\xc6\xb2\xf64c\xd0\xb3i\xe0\xcb+\x14(\xd67W\xa7\x1f\x9f\xf6\xa9\xe0\xa1\x1a/\x1f\xd8\xea\xd4\xd0\xcd:\x91\xb7\xd0\xe6\xfayN\x96\xab\x1c\xf2\x04\xa6\x84\x1d\xf5E\xca\xbc\xd9\x84\xbdni`\xa0*\x03\xaa\xcdl\xf7\xa2^%:u\xbf\x1d\xc9\x0f\xf7\xb5H~4\xfc\xbf\x16\xc9K\x07\xa0^\x1c=\xdc\xd3\x82d\xf7\xa9F\x1a\x1d\xdb\x0d!u\xc1\x1e\xab\xa9M\xfaz]\xa3\xf2\xc1\x05f\xbd\xb2\x02\x0c\xe0\x0d\x99\xf7Z\x8f\xaa\xa6e\x81\xbf\xe8\x0b,\xca\x02\xe7\xfa\x027e\x81\x8f\xfa\x02\xcb\xb2\xc0\x0b}\x81yY\xe0g}\x81;8\x81)\x9cB\"\x92.\xd1\x99\xe5\xd9\x97~7e\x11\xbb\xc6h&\xa5\xb6W_\xe8\x8a\xd7\x9c\xc2\x18\x16\xf4/\xcb\xecd\xa7\xbc\x95\xdf\x1f\x9c\xaa\n\x03\x9b\x8f\x9a\x9ei)\"\xca\x1d:1\x98\x9a|\x03\xf3\xe0^)\x11\x8a\xae&\x11\xd3\xb1\x14\xf6\x1d\xaa\x7f\xe8h(\xb1\x1d\xc0)\xbe\x841\xaa\x81\\\xb8c:!\xac[k\xbf\x85\xa5O\xb14\x8caI\xcb\xd1JB{\x86&yc\x98c\x07\xb0\x9a\x13\x98\xc1i\x07c\x00\x12\x83_\xd1\xb8z\x0b?\xf9B\x96n\x11f\xb5x\x1e]\xe2\xd3\x0c\xf3#\x83\xad\xea\xd6\xba\xbe\xa3W\xe0g\x04\x06\xe3\xcerP\xb7\x8f\xd1L\xa1za\xcd\xc3\xf5k\xb6u\xf8\\\xbd\xb0\xf2\xd1c*\xd7\xc60\x92\xaf\x0ea\xb1Z\x996W\x99\xb8\xccu\x95b)f5C\xe7\xdc\xad\x94\xa3\xfa\x1a5\xdau\x90\xc4\xa1\xd5\xfebr\xd9r\xc3\xea\x02\x88\xb3d\xd47\xca\x86\xa8N\x91\x19\xae\xfe\xd7\xfc\x0d\xaa5]\xc0of.\xfb\xcc\xb6\xef\xbc\x1b\x96\x14\x1b7^u\x87\xb8\xc4a[n\xe6r\x8c\xf4\x89~sM\xff\xdb\xb8\xa6\xaf\x9e<\x01\xdf\xbev\x01\xab5\xa7(\xc9\xbc\xd7\xcci;\xf3\xfe\x02'0\xa2?\xce\xe1\x04v\xe9\x8f\x8fp\x02\x87\xf4\xc7\x0bZf\x9f\xfe\xfa\x19N`\x07K}\x86\x13\xd8\xc7b\x9f\xe8\xdb\xd1\xa1[\x93\xb70Q\xfc\xbaR09\xeeT\x85=n\xc3x\x9a\xdc\xd2!\xb1_\xde;\x0c2q\x82ZL8\x15\xef\xc7\x86\xcf3\x12a\x10e\xfaW\xfd\x14\xdf\x8dAL\x84m\x89\xd9^\x84\x99\xe5\xc8\xa6_Zq\xdb\x9c\x8b\xdb\xe6\xdf(n\xeb\xe2\xbc\\~b\x8f\xf6\xd5\xd3\x16\x03\x81\xd1S\x9eE\xcaN\xeb\x9cT\xda\xceI\xa5\xa6e\xa1e\xa0\xda=\x1aPBEx`\xb0\xb0\x96\xd9(w\xb5\xc7\x7fT\x901h\xd4\x83\xa44r\x1ak9\x9b \x89g\xe1\xbch)q\x9b\x86\xb9x[\x1f\"\x86\xa0g\x07r\xec\xd6T\xb1\xd0=wfym \xd1\xd8\xde\xdb\xd9Q\xa6\xa8\x9a\x91Z\x7f\xf4M\xeavH\x8d\xfb\xd4\x8b7\xe3>\xfd\xff\xc6\xb5\xa7\x8e\xeb\x8f_z\xe52j\x17\x15\xd6\x94%\xc3#\xc8\xb5\x860\xb9\xde\x10\xe6F\xcd\xd4\xa0\xb5NoDr\xeb\xb0\xea+\x0dUx\x8072I/\xb9\xf7\x94\x89\xe3\x01\xbd\x89\x00=\xa8\xde\xef\xef\x0d\x06\x07\xec\xfd\xfe\xde\xde\xce\x1e]I\xfc\xd7\x13`\xf2&z\xb7\xaby.*\x1c\x94\x95\x1d\xb2\xe7\xc3a\x95]J\x14\x1a\xee\x96\xa5v\x86\xb5\xcf\x87\xa3\x83\xf2\xd5p\xef\xa9\x03<\xbf\xd63\x18\x0e\x87\xbb\xc3\xe1\xd0a\x97\x04\xd3&T4\xbe\xba!\xcf\x02\x87\x9d6\xa11\x8a\xfe\x18\xc06\xc1\xb6 l\x9d`\xf9}\x07\x9e=\x83\xa1\xca\xbe\x8b\x8b\"\xbf\xbd\xfd\x9d\xd1\x80~5\x1c\x8cv\x10&FM\xaf\xce\xac\xb6I\xf5k\xd1\x9a\xeeS\xad)\xf8\x0dw6\xdd~bO\xfc\xad\xdf\xfe\xe5\x92\xfe?\xd8zz\xf9\xfb\xd0\xdd\x19>8G\xdbs\xc5\xe0\x8dR\xc5\xdb\xff\xf9/\xb6}:\xfe:\xf1\xb7f\xbc\xf0\xe1\xc3\xfd\xa4\xfc\xe98\xdb\xcaW,\xe7\xec\xeep_+\xb4n7\xc5R\xc4\xa5|\x88\x89\x1d\xf0\x14\xcc\x01\xe3\xd0w\xf6PO\x92{\x01\x1f\xf1\xf3\xdc\x1e\xe0\xb2\x88Dx.F\xabc|\xab\xaf\xcc\x946\x9f\x0c/\xeb\xb9\xaf\xe0\x140\x80\xea\x9b8\xb7\xf3\xd2D\xcf\x85\xe1>\xa5h\x1a\xaf\x86\xf4\xd5\x00\xe3\xb4\x16v\x8cD\x8f\x01\xcc+\n\xb8\xc9\x93\xe3g\xd6\xe5v\x1d8S\xe9\xcd\xbc\xfe\xaai\x02B/\xeb\x895\x06\xeb\x89\xbf\\\x1diB#[\xc7\xf86\xca\xb5/\x9f\xe1\xcb\xb9\xf6\xe5\x0f\xd6\x0f\xf4\xe5\xafE\x92\x1f5b\xd15\xa7\xed\xc6\x88S\x16\xb2\x11\xb6\xac-\xe0V\xba=\x84x\x93K\x06a\x86\x1eK\x9a\xc1\x85\xe1:\xfa\xe0\xd6dVR2Lq\x0c\xe6z#c\xb4`\x149H\xf8W\x06\xe6\xbeKum\x0coH/2\x89/y\xe4\x1bm\x19]\x0c\x91\xfa<95Z\xdb\xc5l\xc0=\xd2\xe9q\xa0[\x1368\x8e@.y\x04\xf3V \x11\xff\xb4q<\nSW~\xbe5\xcd\xa9\xeb\xdd\\\xf8xN\xd3\x9fE\xcc\"\x1d\xbek\xcfgWJ\x1e\x84b\xd4\xfa\xe5\x17\xcb\x81c\x18p\xcd\x16)\xe3,\x86.X\x7f\x1eZ\x8e\n\x99\x9f\xfc(\x9c\x9e\xc5y\x98\xdf\xbddf(>}\x81x3\x99\x92\x8fI\x88j\xea\xc2e\x9ajZ\x17\x96\x0eI/A\xb4\xd4\xb5'\x86\x9ee\xae\x9c\x18\x08\xbb\xc5\x06\xff\xd7\x1c\x03\x84w\xb6\xb1\x12I\xd80\"\x83\xa8v\xea\xc2\x8d\x0e\x19\xb51Ak\xc9\xd8\xa5\xa0\xd6U\xe0\xcbS)\xc1;\x8c\xf5\xf2\x98\xae\x1e\x19E\xeb\x0dn\x8f1K\xfb\xeai\xcbD\xeb{\x87Z\xd1\xfa\x81Z \x13\xad\x0fGj-\x8f\x93\xad\xbb\x92\xf4\xdc ^_t\x89\xd7o\xba\xc4\xeb\xcb.\xf1\xfa\xbcK\xbc~\x07'L\xb6\x8d\x923.\xe3f\n\x13!A7\x8a\xbc\xcd\xa2\xf5\xc5\xba\xf2\xf8+8\x81kI\xd8G\xbf\xb9\xae \xff~\xd7\xa5Q\xaaD\xechY)\x89\xd8\xd1+\xd3f\x82v\x14\x91\xdfA]\xd0~\x87\x82\xf6S\xb8\x831\xc4\x0eJ\xd4\xe9\xb1\x8c\xc2\xa5\x00\x8fp!&G\xc9\xb9Q\xa0X\x98\x04\x8aw\x8c\xc4\xb8c\xe2@!2\xfc\xec\xb8\x80\xb2\xc2\x0d\x9ee,\xe4\x02\xc3\x15\x06\x08\x10\x02y\xf1\xd6\xbe\xe2\"G\xa301\xf5\x02\xa6\x9eJ\xdc\xffi\xc1\xa2Y\xf5\xa5*\xb3\xb8\xeak\xa0\xaa\xc4\xf8\x06Uw\"\xdd\xa0\xdb\x96J\x00\x15\x9a}hP=\xdc\xf0\xa8\x01\xdc\xcc&\xc4\x1c\"\xda\x85W``KtM0R\xdf<\xf22*\x95\xed\x82\x85\x11\x15~\xec?\x9c\xa0\xe1\x0coH\n\xba\xec\xbb%\xf9\xe4\xa0U\xcd\x0f\x0e\x8fF\xf6\xactu?\xde.}\"\x9e\x19\x03\xfe\xaegP\xa7\xf1X\x8b\x99\xea3\xb7\x0b\xc7\x85\xd4N\xbd\x8f\xb0 \xa9\xf7\x1a~\x84\xa4=\x02\x83\xe0o,\x0b&\xe4\xd2\xa6c0\x02)gF\x03\n\x05}\x7f\x0f9w\x88\xa3_K\xd9\xe0\xeb\xc3u0 #\xc6O\xae\xb15\xddG\x15\x8e\xba\xeaU\xdc\xc3\xfa$_\x84\x95\xd1\xfa\x83,on\x9a\x19\xd0\xfab:\x0c\xa3\xb4\x1aq\xd5\xc0\x05r\xe3G\x8em\xb1\xc7U\xf5F# \xcd\xb1Y\xc9\xdc\x11\x93\xb1[\x1d\xaf\xf6\x9d\xa4\x905Q\xe3S\xdd\xe6\xfc\xfe\xa2\xc6^\x9e\xb37\"\x19E\xa3\x01\x91xb\xacMT\xb1\x08\xb3SV\x160\xf1\xf0j\xb9\xd0\x84\xe7C\x91\xd89\xf6\xb2\x15 \xceIDh/2\xcd#\xbc\xfb\xb7,i\x15\xf7\x89\xa3\xcc\xf4\xad. \x8e\xb8x\xa7}\xbb\xa0\x0cmi \\\xd7\x1e\xd25\xa8XH\xff\xfe\x80\xb1lb\x9d\xa5\x80|}H\xc3\xb1\xc6\xdeF\\\x0f\x18\xd5\xd3\xd4l\xeeB\xd8\xf7x\x85j0\xe2\xd4\xb8\xf5\xd3\xd8\xb6p\x95\xde\xa6\xfejE\xd21\x04I\x11M\xe3\x1fr\x98\x13\x16\x17\xd4r\xdc\xa6\x9fa\xb3 \xad\x17\x99@dt{\x0c\xfe\xa1\x86\xf4\xcd\x86[\"\xe3\xf2\xcdGiZ\x7f\x15\xaa\x9bO0\xae\xcd\x944\xcc\xf9\xae\xbe\xc9v\xbc\x81g!\x8d\x9fW\x0c\xdan\x17\x13f\xe6\xfe\x0f\x9d.\xeeU\x1d\x15:\xc1\xa7h\xe3\xcf\x08\x91J\xde\x8eqCE\x02l?\xe6\"\xf7\x0d\xc3\x88\x1f-R\x1c\x1d\xa8RBLy\xd1\xe4\xd1d*\xa0\xa4\x06\x18\xda\x96\"\xb2\x887M\x8e*\xa5\xfcb\xd2\xcaQ\xea\xa1\xa7\x0f\xcf$\x8f\xa6\x1f\xaco\xfa\xc4V\x16\xae\xbdL\x03[\x03\x03\xed\xba\"\x0d[s\xa9tx?\xd6\xfc\xb2\xdb\xcc\x7f\xae\x8b\xf9E\x92D2\xb3\xd9\xab}I\x90\xac\xda\xa7\x0b\xab\x1bu1\x84\xdcv[uZ\xf2+k\x80\xfa\x99-\x9f\xb23\xa6\xf1\xdc\x95\xa2\xe6\xd4\x0b\xab\xd1s4\x87\x13\xba\xb4\xa3\xeb1\xda\xe8P\xb4\x8a\xe4Qj\xc7\x8ekN\xdb_\x1e\x0d\xa2\xdaZ\x89\x1a\xe1\xfe\xd0h\xcf\x9a\x93\xdcb\x91j\xe8\x9cg\xe2\xae\xb9I\xad\xe7A@\xb2\x8c\x9e\x7f\x18\xab\xb9X\xd19#S\xd36\xb5\x90d\xe1u3\x86\x8c\x99\x87\x95\x0e)kn\xe4~Vb\x0dw\x84\xb5\xac\xc4\x1e\xd7\xa4\xbab\xbe\xa5\xc9N\xb7a\x83\xcb\x81\xce\x88,\xb6w\xf6v\xb5\x8a\x91}Uz[\xf0\xe2\xaa\xe7\x02J\x9f\xecCu\xafD\xac\xd1]u\xe4L\xf1\xaf\x96\x9ei\\\xadV\x18\xb0\xb3\x0eS\xb4L\x9b\x93\xfcc\x92Dd\xaa\xe6\x87Xh\xe4\x1a7%2)\x1f\x97'\xeb\xb2\xc1\x1d\x9cy\x98\xde\xea\x13 \x928\x08#r\x91\xfaq\xe6\xb3\xd2O\x9e\xc0\x0d0'\xff\xe1h\xc72YOP\xeem\xa2l\xdb8\xccY6\xcfq;\xe3\xc5<]\xc34\xbf+i\xdb\x8ce\x18\xc3\xbc\x18\xecX\xae}\xa5\x88\xa54\x82\xabu\x1a\xd98\xa9\x9a\x81S\xb0g(\xb5\x0d\x08%\x19\xcd\x9f9.\xdc\xdaH\xfe\x95\xdf\x9e\x18\xc3\xb0?\xa8t\xe6z\xc0 \xfc(\xba\xf6\x83/\xff\xbb \x05\xf1R\x92\x91\\\x11{<\x16\"\xf5\x9a\xe3$\x0fgw\xcf\xa3H\xad\xbd\x1a\xc8\xa5nI\xdd5\xe3\xff1\x1f\xe7j\x98\xd2\x9a\xb2\x9d6\xb8\xf2\x95\xebj\xfa\xd7\xd8\x07\xa2\x19\xcd\xba=i[\xd5R%\x1b\x83v\xdb\xa8\xeb6\xe35\xe2]-\x93\"\xce1\x15\x06lA.\xdf\xb7V{\xd5F\xdej\xe1\xa2\x88G\xeb\xab\x96\xc5\xfe\x18\x8ev-\xc4\x9c\xe2\xb9C\x7ffI\x9a\xdb\xd7\x8e\x0b\xab\xcd\xcdz%Ud\xba*\xaca\xce\xa3\x1a6\xd7\x0b\x17tR\x04:\x9b\xc4\x06\x0fQ\x1f\xe7\xe8jE\xe2i\x18\xcf_\xf2\xd9\xcb\x9a\x0c\x1c\xba\x156\x0b\x96\xb3_xQ2\xbfHVo\xc9\x0d\x89>a\x88'c\xa0\xa3\x1b\x1e\xbd\xd6\x90\x9e(\xf4\xae\x82\"MI\x9cs\xc6\x0c\xf3\x89c\x9e\x03?\xc8E\x1b?3\x16\x0b\x8f\xe4\x88\x8d\xa2\x11g\xcba\n\x03\x8be\x03,VS?',\xb8WD\x97\xd4{\x7fI\xe8\xaa\x14\x0c\\\x1e.\x89\x9dt\x19\xab\x00\x87F\xe6\xadH:K\xd2\xe5g\xac\xf7\xcd\xec=\xa1\x84\x85\x9f\xde\xd9\xa1\x8bF\x0d\xcd\x85\xcct\xa7 *n\xa5F\xcf\xe2)\x8b\x0c\xae\xe7>{D\xbe#\nf \xf1\xaf\xf4\xaf\xedO\x82K\x97\xef\xc2\xe2:\n\x03\x11\xb8\xc6V}>\xfe\xd4\xfc\x95\xd8\xb2\xdf\x19D*R\x9c\x93\\\x1a\x1b\x9f\x90\xac\x03\x8d\xf1\xad8oC\x87\xc2-4I\xfb\xe0\xc4v\xb4\x14z)\x89\x88\x9f\x11\xbb\x89\xa0\x1c\x03\xd6b_\xb6!\xa4Z\x9d\xba\x99\xee@v]\xa1\x86\xf8\xd2\xea&\xb6\xa1\x02i$\x16$\xcf\xd1\x89>M\xc6N\x88\xc2-E\\\xd0\x93\xe2\xd5R\xa1k\xd6\xf3\xa7S\x8a\x9c\xc3x~\x91\xd8w\x8a8\xef\xb6M\xcc\xc9\xa3\x0b\x95h\xf1\xfe\x1e\x16\xc6(Y\xb3\x0e\xb7:\xa1\x88\xbb\x93\x8f\x1c=\x86!b\xf0\xf6\x95HKO\xd7\xc2]9\xad\xba\xd4v\xdaN\x19{\xc3\xa8<}\xf3\xe2\xe4\xd0\x04\xb5\x03-\xfd\x08\xb9|\xd4\xd7\xd6tWG\x8d\x82\xa4\xb3\x06/`\\\xed,2V}\x81^Sn\x8cL\x19\xee\xcb\x9a\xeb\xb4\xcc\x17\xd3\xb2`\x97t,7^\xbd\xaaf\x05m\xfb\x84\xe3\xb9\xcf\x1c\xb5\x97\xe75\xd1\xdbP\xf2\x16\xc3\xec\x05m3\x8c\xe7\xbcQFFb\xa0\x81\x9c\x0b\xe8PZ\xe0]\xb1C\x03\x8b\xbfGm\x08\x17Ji^\x9c`N\xbc!\xd2\x98\xdaQ\xb5\x8ed\x16\x15\xd9\xe2\x85\x02\xd5[\x85\x19\x8a)G\xceT\xca\xcd\xe5\x88/\xf5\xf3g\x16\xb1\x88\x8b\x94L\xc3\xbe\xe5\xb4\xe2>\xbd\xb6\xb0I^\xb0\xfe\x08@\x9f\xe7\xa9\x9f\x93\xf9\xddz}9\xa0}\xd1gOQ\x00\\\x92T\x87\xf8\xc95\xdd:\xbe\xf2Es\xda\xc5GO\xe9G7\xfa\x91\xb5M\x9a\x9f\xf9\xab\x1e\xa9T\x03[\xb3\xe6\\N\x97\xf0[\x8f\xd5\xf5\xd2\x8f\x7f\xc8\xc5\xb2\x06?\xc6&@\x1cP\x10\xc6\xe0c\xe8E\xf25\x87\xdb\x05II\xc1\x87\xe2c\x08\x85\x1c\xaeI\x18\xcf\xc5\xf6\xf4\xe8\xb8\xa6%5\x80\xfds\x19n2\xb2>z\x81\xd6\x19>]C\xce\xb0\x11\xdb{C\xc7l\xb4\xc3q\xc0\x01\x9d!\xbd*\xe9\xf7\x07\x17,\xbf\xa1B\x02FytP\x06r\x13]s\xeaxU\x9c\x8c\x87G\xa84\xc5\xd3.O9\xcc~@\xc1\xf2T\x17\x1f\x07_\x8d\x86\xea\xab\xd0\x14h\xa2\xd4b\xa0\xcd_\x861!\xe4\xf7\xa5\xf6\xa4\xd3[^\xc8tUSWz=@\xd7\x8e\x95\xf5\x0b\xdd\x1d%U|\xaf$\xe5Q\xcf\xe4\xd7,\xe2i\xa9\xa0\xa9\xcc*O\xab1\x8e\x0d]]\xcf\x83\xe8\xbb*D\xc4/\xd9;\xb1\x1b\x18\xd2\xac\x9d@hW\xfa\xae\xd6)\xe3\xfd\x97\xc3JR\xe8H\x86\x00c\xd4\x03U\xddk\x9d\xc3\x7f\xc4\xfc\xad\xd1\xf7\xc7oG\xb3\xd4\x93\xb3\x97J\xc4O}S&\xfc\xd6 \xd0\x9a^Bgx\xfe=\xc6( T\x0d\x86\xe6\xaa\x84\x94\x0bTu\xf2T;\xb6\x9f:.L\xaci\x98\xad\xe8\x01\xf2\x12=\xa9-\x17\xac\xab\xdcOylVz\x1b\xfbyx\xc3\xfc+1\x96c\xf6\x8a\xcd\xf7\xc7\x94\xd0gd\xca\x9eRT\xee\xcf\xd1\x08\xee\xa5\xa94B\x1f\xca\xdd%j\xd8p\xdf\x18K\xdb\x10\x1d\xad4\xfb\xd3ft\x03\\\xd4\xa7\xd8i\x96\x01\x8e{\xe3Y\x0c\x00\xec`\xf0y \x8f=D\xc5\xecX\xfa&\x9e\xf8\x9a\xdc!\x0d\xe8\x08Y\x1d\xe6B\xf5\xd4Y\x87S\xdd\xc31l\xb08\x8e1\xb7\xde\xfb\xa9i\xbc(i\x84\xbd&\"\x80\x13\xa0\xdcU\xd8\xb0\x9aR\xf6\x1bZY\x89\xc8\x9d\x1a\xc4\x81<\xb1\xbe\xfc\x9f\x9acN\xedL\x96\\\xd5\xa7l\xc5\xfa\xf6J\x9c\xea=$L\xcdAmh&\\H \xd4\xd5\xda,\xc9t\xd5\xc4\xabw\x05}\xa1\xea\x8fl\x87\xd9\xf8a\x88\xcc:7#M\x08\xafM~r\x02h\xadf\x9e\x95\xc6\x8c\xb4r\xa7Y\x9e\xac\xa4I\xe9\x00\xda\xfa\x80P\xeaGH(\xcfZ@\xc1\xb0\xea\x0bD\xbd\xbc\xc2\xda\xa3\x13\xa6\x80\xee\xbd\xb8:\xc1\xb1\"i\x86\x99\xc4\xbb\xd7N\x98}d\x85\x19\xdaj\xb4\xd3\xd6\x8c\xfc\xadv\xbf\xd4J\xf7\x96\x9a\xd6\xa6\xa7\x07\xae\x84z\x0c\x0d\x96\xd1\x0c\xf1\x0f\xd3\x84k\xa3\xd3\xeb\x94\x15\x95\xd0\x9aebB\x146\x89//\xb5\x12\xd1j_;.dU\xe7\x98kc\xe6\xf9\xc5|I\xe2\xfce\xe4g\xbd\x1dNd\xb8\xa8\xbe'5\x1f.\x84\x8d!b\xda\x0d\x8fn\x10\x93[\xf5\x18J\x99\xec\xbf\xfc\xd0\xa9\xdda\"\x16\xf9A\x9d\x98\x06\x8c\xa6.\x8f3E&\x18\xfbR>f<\x9e\x8b\x98\xa4\x19\x908H\xa6a<\xafgD\xc8\x17$\xc6\x8d\x87\xc9\xd2\xca\xc3\x0fD\xe0\x17\x1fx\x03\x06e\xb88c\xb9\xc1@/\xd57\xffF\x18\x19\x18\xcc\x04\xf4S\x13\xb5\x88\x85\xc0\x0cCC\x8c\x9b\x1f\x84}n}\xdc<\x9b\xa6\x0f\xac\xa2\x16gp\xbd\x03\x1d\xae\xdb\x17\x0c\xdb=y\x82LO\xb9\x1e\xe4w\xcdC\xbe\x85P\xc3\xd0>\xde\xf5]N\xde\xf2l\xdd1FWA\xcf\xf3\xea1\x1cWv\xcb\xeaV\xfd!\x99\xcd2\x92\xff@\x97@R\xe4\x90\xcc\xe0:)\xe2if\x9a]\xb5MZ9l\x82\x8d\xb6\xfd\x03\xc7\xd8\x0e\xdbs\xfd\xdb\xc9\xeb\x99\xd1\x99!juO!\xd5@\nuE\x80\xae\x08n\xe0\xb1\xee1\x05\xb3\xbe'\xad\x88)oCD\xb4\x00\xcf|\xd8\xbaU4J\xe2\xda\xec\x8f\xf5\xde,\xdd\x04\xa1\xb84\x9f#@\xcb\xe8\x0e\xf7\xf7\xcc\xed\xde*\xf2\xd9a\xdb\xd4od^\x98\x9dq\xbca\xc7\x8ei\x13 \xd4bIh\x83\x1d\n\xac+%\xee\xd1\xed$\x90\xce\xd3\x01\xdc\xc3\x82M\x9c\xde\xe2\x10\xf8\xe1\x8a\xd3\x81\xc7V\xea8\xdem\x1a\xe63/HX\xa7\xdcL\x8d\xe1\x98\x11\x91\x84rZ$\xb9)\x1bUJi\x08\xfag\xf3\x04\x86t`\x18\xbax\xb4\xb7\x07O \x9f\xa4\x1a=\xd7Z#\xd4$^\x85r\xdd<;\xa1\xbc\x95\x89jy^e\x96\xf1#\x0c\xbfB\xf8\xce\x82\xc8O\xe7\x842\xa8~\x0cK\xffk\xb8,\x96\x90\xa1;\xc7\xe0+\xe5\xb3}9\xcd\xf5p\xdfAWNJ6i)\x9e\x12a\xdf\xf7\x1c\xd4\xa2u%J'\x8b\x9c;JH\xcb\xf5\xdb\xb4\x0f\x92\xd6\xdasHe\xbc0\xfb)$,\xd0H\xf31\x9d\x88\xfb{ \x06\x14/\xf7\xb4\"0\x9b\xbd\xd5\xb8\xd6W\x8c\x9e\xa5\x13r\x80\xb4\x9c\xdb\xa1\xc0\xa9\xcd\xb2'\x9a\xedU[\xbe\x1b\xc3\xa3#\xa7\x14\x0d\x1bOB\x14\x88Z~\x16\x84\xa1\xa5\x17\x8b\xb2\x12\x91\x9f\x87\xf1\xb0\xb5\xc8u\x18\xfb\xe9\x9d\xa1\x08H\x12(\xfdq\xc2*A2\xaf\xad\x95\"\x9fm\xb5\x96`\x84vg/^\xdb\xc41\x02\x1c\xaa\xe6\x82l\xd4\xde\x9f \xdb\xea(\x91\xcf\x86\xfb\x11\xe9*\xb3\xd5R\x08\xaa~\x8f\xe0\xc7v\x08.\xc8\xd7\xeeZbx\xf6\xec\x19\x18\xac\xb6\xf9t\xfa\x19\xd9\xdf\xed\xae\xea\xb7.@\n\xa32cE\xa8\xedpzO\x0cp&\xcc\xc6\x1d\x95;\xf5\xe8f.\xcf\x8f\xd6\xf8T\x95\xbe\xeb\xd1\xd7M\x1b\xc7\"\xf6\x16\xd1F\xc6\xe7riz\xfc\xb9\xe2\x10L{5\xba\x94\x98*\x83\xc6\xa1B\x01\xa4\xa4\x189\xc0\xb64\xd3h\x10\xb7\xc4\x94;L\x99\xf0\x1cOn\xe49\xe1\x99,\x91;\xc575\x11\x1d=\xdd\xb7\xca'\x87 b\xa1I\xcf\x1cV\xe1f\xecB\x98\xbd\xf7\xdf\xdb\xb1S\x16K\xf8\xe1\\\xca\xb7\xb6`\xe8\x08\x91\x80(T\xbe\xdcDZ?\xa6\x07 \xe9p\x84@\xcb\x95V8\x00\x8f\xfe$7\xdd\\\x19@\xa2\x8c`m1\xa3\xd7\xcc\xcdm\xf4k\xafk\xf9A\x8bH\x8c\xd9\xdd#\xcf>K\x93%\xe5\x15S\x07\x15\xc35\xae\xac\xc6J\xe5\x15\xfb\xb45\x841\xcc\x95\x15eX!Z\xe1\x13\xaf8\x87'H\xeb\xb8\x069\x83\xe9\xd0\xad\xc4\x17\x92\xf6\x97\xc7\xd9\xc5\x08\xa4\xa7\xadE*\xf5\x04\xe7Z\xb5\x85#?\xcb\xdf\x18>\xc0\xb1O\xf2\xcb\xb6\xd1ky\x97\x1b?* {\xc1\xae0\x08Q\xce\x843Z\xfd\xe8q\x15\xfe\x06d\x12\xb2\xf0l\x86\xd8o\x85\xb4p\xf5%2\x89\n\xd6O\xb1\x14\\\x95\x89\x14\xd8\x89\xc6\xf8\xef\xb4\x8a\xc6\x99*h\x14\xe9!~\xb8q\xa1\x15>\xe0gY\xfd\xd1\x96\xf4\xcc(/@\xb2\xb6\xa2\xd8GL\x18X\xddw\xee+\x9fEO-`\x9bEQ\xe5\x7fc\xfc\xab\xd9o\x8dG\x8a`\xd6\xd4Q\xde\x8dai\x92FX\x00{\xe2\xa5\xc4\x9f~~\x13\xe7\xc3\xfd\x17gv\x0e?\xea\xdc\x18\xf5\xfb\xdc\xa8E\x16\xce\x8e\xa6A#M\x87j\x98#\x08\xe1\x18\x8a#\x0877\xf5L\x19\xf0\xc6px\xa1\x83\xfdG\xad4OQ\x1cp<\x1c\xc2\x16\x04\xadr\x1dQS\xf9!]9\xb4\x9b\xa1\xe3\xb2\xcfa\x93\x03(+\xe7-\xa0\x001V\xc9\x91\xec\x16K\"\xc1j\x0ca\xeb\x84\xf7\xc6\xe5P0 g3lb\xd8\x84\x0c\x9eAQ\x9e$\x05lA\xe60\x7f`\x84\xda3d\xe6\xc2\xad\xad\xb6!\x97\xc4\xf3\x8c\x07\x0b\\1\x1ep\x05\xc7\x90\x1d\xc1\xaa\x0d\xe8P\x03[{>\x1cCz\x04\x9b\x9b~\x1b\xfa\xa0\xc7\x84\x9c\xf7\xa2\xb8\xce\xf2\xd4\xa6|\x82\xef\x02O\x8d\xa1_X8H\xa4\xd6\x8a\x8a\xa0\xf0\xf5e\xc9\x84\xee4f\xba\xdb\x03\xe9\x89\xcaz-\x9a\xeb\x8eE\xc3+{a\xbf\xa6\x1bJ^\x16\x0e\xaa\xe4\x9a&@\xa6\x96\xae\xfa\xb6d6\x18(\xeb\x94smM.]Y\x14V\xb2\xf2L\"\x963\x87K&8\"r\x02\x94\xb8C\xa2\xafK\xa8\x98\xaf;\xe8\xdb~\x83\xae\xc1\xa6W\xc5g\xfd*~a\xff\xb6~\xa7\xbf\xf6\xad\xbb\x97V\xa3\x92W\x96\xde\xb6|\xd6\xa4\xadF\xa4\xa0\x15\x1b\xb6\x9d\xd3\xd3i\x84i!\x1c\xbe \x19+!\xcd\x9f\xcf\xf9M\xcaO\xc3!\x8f\xdaL\xd1\xc6\xde\xbe\x0b!\x9b\xf6\xc4)\x7f\x9a4yF\x94\xfc\xf0\xad\x0b\xfe\xbc\x8d\x9f\xad\xb3\x10t\xd8q\x8d\xc5\x84SH\x91\x07yq\x97\x13\x91\xf1\x9dbU\xf5!WQ\xe5u\x9b\xae\xb6~\xbdl\xeb\x17\x05\xf3;?_x\xcb0.i\xc6\x1e\"[:\x9f\xe8\x1aq\x04 \x8an\xdb\xd0&\xa5\xbd]\xb4\xafu1F\x07\x99$-\xc9\xe5\x03\x11,\xc1X\x82\x9e\xe0\x11e\xa5w\x9e\xc2)\xec\xc2\x98\xdd\x8dv\xe0\x14v\xf8\xdd\xf0\xe9\x10Na\x04c\x93\xe8\x05iE\xd8\x84\x19\x1c\xa3\xb0O\xc8\xeffm4D\x9f\x04\xb8\x11\x1c\xc3ptX\x12rQ\x8b^ \x04\x9da.\xd2'-.m\x8er\x19\xc3\xa7#x\xc2\x88X2\xa1\x83\x1b^:L8@\xd9\x17{g\x08O r\xe0\xf8\x18\xf6\xe1\x1e\xf6w\xe0 %^\x9f\x89\x0cb\xd8\xdd\xec;t\xd7`\xf6).\xb9\x7f<3>\xde\x8d.]e(!\xf6\xbe\xfe\xcc\x97F4\xdc+G4\x1c\xc1=\xd8bL\xf2\x10}:\xc4\xd1`\xf7\x80\x7fw\xcc\x13\x96\xdd\xdf#9+%x\xfb^\xe3\xdf}\xfc\xf8\x8b\xf2ng\x0dh\xd4\x9f\x15\x06\x08\x1d*\x10\x92@\xe6\xd7AV8\"\xef\x1b\xad\x89\x82\x8c\xa5\x92\x1bI`\xd2\x0eQO\x12\x97\xc6X\x94/\xc2\xcfi\xdd;.\xee\xe4!\xc5s\x81\xdc\x9e\x1d\x94i\xe4\\H\x19>\x0f\x98\x18u\x00O\x00\xf3\xc5\xdd\xb3I\xe4\xdc\x0c\xcb%w\x0f<\x95\x1cer\xc4w\x18\x1bg\xf3\x04fM\x8co\xc2\xd2\xdd\x14\xc9M\x19\xa7\xa9M|\x8a\x8aq\x8a^\xbe\x94$\x9f&\x1d\x1d\xb71>\xe7b\x10\x9d\xde\x02$\xdd\x85\xa5\xc9V&\xaeT\xaf\x0c\x04(\xc3\xa2\xa4\xa8=\xa4\xc7\xeb\xe6I\x9f\xce\xf0\xe3&u\x99j\xeeK\x07\x11\x157\x81l7\x8eO\xf9.\xf7\xb8b\xe9\x84\x1e\x0e\xb9w\x1e%\xb7\xe5\x93\xf6y\xd8$U\x84N\x82\x12V\x0dC\xc0\xba\x95y\xa8\xba\xb37\x1b\x1e8\x90{o\xde\x9f\x7f<{yq\xf5\xee\xf9\xffw\xf5\xe2o\x17g\xe7t=\x0dL\xb2\xb8\x139\x89\x0e1\x98\x05\xe9\x9fwy\xf6\x18\x83\xdf\x0b\xdf\x1a\xc5di\xd8a\xa2R\xb3J2\x9fie)\xbd\x00\xb0\xe5\x18N\x92\x1e\x01\x13\xc4\xc5{\xb5\xdb\x94\x1f\x89K\x8f;\x1e\\\xd8\x1dqZi\x96$\xb6c\x14\x87\x12\xca\x901K\xd3'O\x84'x\xf9\xcc\x1eb\xc2\xbcJ\xa9\xd8\\\xaa\x9d\xd9\x0d\xf8\x1864\xb2\x93\xfa\xbab\xf1u\xbe\xbc\xf3\xbf\x96\x91\xa3|\x1b\x05\xcb\xab$\x89\xce\xc3\xdf\xe8t\x1e\x0e\x9fb\xf2\xa1+\xeea\xd3\xb9\xe2\xb5\x13[sJT=\xbf\xb8`\xbb\x87\x1f\x8cT\x7fd\xf3\xf0EZ\x0b\xcc\x16!\xb5\xec Y\xeb\xa3v]\xd1\x91k\xcb\xb8\x06\xfb\xc9st\xf5\xa7\x0d\xb1_\x18\x1cJ+!\x13\xdetY\xa9Xa_hmM\x98\xe1K\xdd\xd5\xad\xcd\xccAV\xec16\x08\x02ZGc\xdf\xd43\xd0\xc9\xb5\xd5\\j\xb5\xd0B\x0c\x933\x0c\xd2\"\xd5\xa5\xbc\x07\x99\xc4\x97FvK\xc8\xa5j\xc7\x83\xad\xcb\xb3\x0f\xdcV\xdc\x84\xee\xcc\xbd0\x13\xe7>7F1\xb3\x812\n\xf7\xff\xa0\xf9\xa3\x97\xcf\x8c\xb9Q\x13\xce\x19_\xe1 \xdf\xb1\x16\xa1Z\xb7is\x91J\xce\x1e'\xb0p\xa1F\xe9I\xc7\xe7\xc6\xa0\xfe.\xbb\xf5W\xc3\xfd\xb6x\x9d\xa0\x06\x0fh\xd3\x13\x11\xad\x9eH6\xd7\xe4=\xc9(\x89]\x99\x0e/\x8b(\x0fW\x11\xa1\x10\x1c\xeeo]\x87\xb9\xf6X\xac)\x1a\x06Gh\xbeK\x8e\xd8\xf2\x1b9p#\xe2\x9f\xba\x98\xb4R\xc7\x7f e\x82\x1cB\x04\x04\x10\xeb`\xd9\x19}W\xb0\xec~#XvF\x8f\x02\xcbn\x03,;\x8e[=\xa2`b\x7ftZ\xb85\xa0\xb5\xbf\xfb]\xa1u\xf8\x8d\xd0\xda\xdf}\x14\xb4\x0e\x1b\xd0:\xd0Ck_y\x9d\xe8\xda\xf9\x83F0\xcc\xe6LX}a\xfc\x16x&\x8f\xa7\xf2(\xb1\xfa\xd5\x8b~S\xb1Z\x890\x90\x90\x1f\xa2\x19\x1e.\xba>M\xa0\xd9(\x96>>\xa1\xbd\xe5w\x9d\x1f\xe3\xeac \xa4\x89\xe4\xcc%\x19(\x1b\xa5\x1b\xd0\x83\xee\x14\x17\xef\xc5\xc7j1\x9b\x9c\xac\xa0\x0f\xb5\n\xbd(Vq\xf1\xc6_\xae\xd3x\x1b\x9d+.^\xef\xf3u\xeam\xa5\x8e\xa1\x1f\x85,.\xde\xfe\x87u\xda\xef\xb4\x1d\x86\xaa\xe2\xf3u*n\xa1\xc6\xa1\x17E\x0e=\xa9rX\x872\x87j4\x17\xfdF\xd3I\xac\x03\x94v\xd1Z\xc6\xfa3\x8b\x0eUz+\x8e\xb51\x14\xd4\x8b0w\xc4M\xb0\xac\xbef\xd3\xa0\xa5\xc9\x1eD\x0c\x12\x1c\xac)\x0cI\x1d\xa9\x93_\x0b?j\x8f\x1f\x01ZiC\x87lA:\x0c\x85\x8df\xeb\xc1\xc3\xcf\x80\xfb{\x8e,KY\x88\xde/\\\x19E\x18g+L+\xd6\xefd2)F\x98\xffRC\xca\xdf\xdaqq>=\xe3f\xd3%]Q\xba\xf3 \x8e\xe4\xfe\x92\xde\xd2\xcf\x83\x85\xbd\xed\xfd>z\xd8\x9e;\xde\xdf\x930\xb6-\xb0Dx\xb0\xb22\x9e\xec\x89\xa5P\xf7<\x0f,\xc7q\xc1:\xe6\xf4\x06\xae+]6\xf4:\\\x0c\xf2\xa4N\xa3\xf6\xef?\xd5*\x8fW;YU\xcfmf{\x8e\xda\x11\x0e\x90\xb1Z.-\xed\xb6\x94\x17\xcc\xd6,i\x9c\xa8\xb9\xf0u\xa7'pY\xef\xfd=\np\x06,\xd5\x9cr4\xeb)>\xee\x8f\x9e\xd2G\x80\xf6\xd1\xa6\xf1\xa6\xf0\x8c\xf7'\xa7\xbfZ\xdd\x84\xaa\xf2\x9d.\x04Je\xe6RH\x07\xb8\x10\x97\xbf\xd2\xf2WR\xfe\xaa6_/\xf1^\x88\xae\x03[t\xf5`\x0e,\xd8\xa2\xcb\xa9\x90%z\xa1\x0b\xbe\xc3\xcc7\x10\x9c\xa5^0\xe1*\xd8\x9ae\n\xd3\xec\x0e\x8e`\xc6\x0ci77gf `4\x991 `0\x99\xb5J\x00i7ia\xd6KZ\xda\x8c\x83\x1f!\x01\x0c\xe1\x18\x8d\x90Q\x02\xe8\xc31\x84f \xa0\x8c\xa5\x82\xa8\x98\x92>\xb1\xc6\xa4\xb6\xb8q.\x82\x92\x9b\xe3\xdbf z\xd3\xba\x7f\xad\xc6\x96\xf5\x90\x1a\x98:\xaf\xad\x11\xc9\xe4\xff[\x1b\x1a\xb66\x84\x1e\xfaz\x0cf=\xbdp\xdf\xd4E\x10\x86\x1cm}\xa5\x10?X\xac\x0f\xda0@\\X\"\xe2\x87\x984\xd99\xba\xa8\xf1\xe5\x1f\x1a\x03\x03\xa9\x91\xfe\xd4\xd8t\xa6\xeacz&IB\x07s\x1c\xcc)\xf9\n\xb2x\xa1'D\xff\xde\xc1\x0c\xe5\xa5O\x7f\xce\xed\xa9\xf7p\xc2\xf5z\xc9\xda\xeeU\xadud\xaf\x17\x17Fu\xc3\x1d\xee\x8e\x96\\\x02\xea!\x9e`P\x9e\xe3c8\x84\x1f)\xfd{\n \x8ca\x08[\x908\x0e\xdahk^\xf4\x1a\xf0\xfb\xb5\x06\xbc;z\xba\xfbt\xff`\xf4\xf4;\x8dz\xd7<\xea\xbc9\xac\x1d\x1c\x16\x03F\xaf\xc1}\xea\xbd?\xbeea\x99\x96j\x0b>y\xf4\xfa|U\x1bQ[J\xc6\x90\xeeB\x04\xc0\xc0e\xa0v!\xe1<\xae\\\xc7h\x87\xbd\xa3\x10\xd8\xed\xd5\x87\xb7\x8f\xee\xc3\xa1\xa1\x0f{#\xf6\x8e\xf6\xe1P\xe9\x83|\x97\xa9t]\x1f\xfb\x1d\xe1\x15\xd7OI}\x02\xff\xfd\xdf\xc4U\x83`\xe6p\x8a\xa9Z\xfe\xfb\xbfs\x97\x9d\x14,\x0c\xe5&=\xb5\xcb\x1dBD\xc4\x11B\x0f\xf6\xf2Q\xeaT!\xc9\xec\\\xf9&\x17\xdf\xe4\xe57\xb9\xf4\x0d)\x9f\x10\xc7`\x03\xecT:\xcf\xd2\xea\x1aaa\x0c\x90\xb9\x96\xfc\xa4\xa4\xc0`K\x8d\xcb/\xae\xb8\x0c\xf3\x9b\x08q\x86\x81\xbb\xa81\xe7\x9cNH8\x19\x13S\"\x80\x0d\x04)\x00\xd2\x95\n\x07\xaa\x85V\xf7\x80P\xd8\x0f\x11\xd5\xe0\xedYO\xb9\x1a\xe1\x92\x19!\xb8A\xaaM\x90\x13\xb2|\xa3\x05\xf7\x89\xe56!\xdcgoX\x12G\x9b\x9bt\xd89\x17\xae\xffxB\xe9\x1e\xe7\x88\x13\xb5\xec\x1b\xd8\x84\xf0\x12~\xd4\xb9v\xebIY\xfd\x88_\xfccF\x0c\x9b\xb0\xb5\x95\x8bq\x1f\xe1\xd2\x1et\x0c\x97~\xf0\xed\x03>\xec\x83\x10\x84\xc6\xa9\x1c\xe3\xd0U\x15\x1cl\xe2\xfa\xb48\xdco.\xab^\x8d\x8e\x0c\x8drK\x0f\x04\xca\xf0\x12\xcf\xfc~\xfdhN\xf6\xb7\xf5\x03\xa9\x8dZg\xfa\xf4cg\xf4Hx\xec\xaa\xfd\xb0\xcd\x00\x91\x1f\x8d\xf0\x11\x8b\xf37\xdc?88\x18\x0d)\x17Q\xbe\xdf\xe9\xd9\xedG\x82\xaf\xd1\xedF\x1f(gc+#\x18\xee7\x87P\x1b\xd5\xcee\xab\x08\x9fv\xfb\xff:\x8c\x06\xcfN\xf8\xe7\xc3\xd1\xa1\xc3E\xe1[\x9cv\\%\xb76\xa5\x12(X\x1d\xc7\xedF\x07\xff\x10\xf4W\x03\x8c\x84\xdb\xd2\xcb#$/\x9bX0T\xb0`\xda\x0e\xa4P\x03\xa4\xd0\x08\xa4\xb0\x07\x90\xbe\x13\xcaD\xdf\xebr\xc5\xa3:\xefG\xc0\x88\x10[\xd2>@\xaf\xd3\x9e\xd8u\x0d\xe4j\xc4fM8\xde\x88\xd8\xaaF\xe4b\x84\xfd\xce\xe8`\x9f\x0e2\x86S\xc6\x08\x0d\x86\x07\xfb\x03\xb8\x87\x18\xc6\xdd\x14\xc8\x1a8\xfa\xd1\xc3a\x83\xb8\xaf\xa1\xf0?n8\xdf\x0f\xd5\xaf\x87\xe9\xebx\x92>\x1b\xed\xf6\xean?\xe8\xf7\xef.\xb6\xdc\xect\x0f\xe4\xde\xd5\xdd\xd7Q\xe2k\xb0\xfb\xe3\xba\x9b`\x95\x95\xa2ac \xb8\xbe^\xdd\xf8^Pktc\xd8\xb7\x1b\xaf\x92\xe2:\"\x8f\x04\xc7ag?\x06\x82\x01\xed\xd7\x8fG\xc2\xa3\xbb\x1f\xc3>\xfd@\xe6\xd9\xc8\xcd\x18\x848\xc8\x86n\x92\xda\x01\xc7\xacXPm\xfbF5 P\x0f\x93\xd8\x81-\x8a\xf2M\x8e(\x899\xc6_\xd8\xe2\xf4\x81\x1b\"\xafBN\x13AI\xc4\x8dc\x92\x15eD\xc4 \x10\xd8\x86\x84\xc9\x81\x8c\xe8\x8d\x16n\xc5b%$\xb5d\xc2?\x10\x921\x161BSc\xa4$AS\x88\xcfJ\x88nm%\x18 \x8e\x93\n\x1a\x90&\x02\xa4\xe1w\x03i\x83\xa8h\xb7`\xd1\x00U\x85%E\x16{{.\xeaQ\x8c\xf9~pv\x10\xe4\xb3(IP\xd2\xcd\xb1\xb5\xbc\xca\xb8\xc9\x7f\xaf\x81\xe8(\x90o\x1e\xcb\xc8e\x92\xe3\xb6\xd1\x9cj\xb6\x87[\xcd\xd9\x90\xcd\x19\x8aH)M\xf5\xf7Z\x03,G*=|z\x0e\xb27\xa5\xfc\x07\x0e\x92\x8fF\x1d$\x1f\xbbf\x90\xc3\xb5\x06\xa9\xa3V\xbey\x90\xbb\xae$\x12\xef5RF\xb3\x88\xd1\x8ev\xa5\xe1\x8e\xaa\xe7\xc3}\xc3\\k\x963\x85\xcc{\xfd\xf4\xb7\x92E\x12d\xfe\x80\xe9_\x1f2\x06\xa8\x0c\x0dP\x19\xe9\xd7\xccN;d\x86\xbd!\xb3\xe6\x11+\xa4\xc72X6\x8c\x06G\x02\xd57\x8e\x07\x0c\x1d\xad\x97\x9d6\xce\x96\x84\x1d%[\x1a7o\xbd=\x18\x9e\xc5\xfa\x83\xa5#J\xef#Op_:n\x88\x10y3\x89z\xc1~\nsLv\xb6\xd3\x01]\xe2\x97\x05\x86(r\x95s\xdf\xa6\xa7\x94\x0f\xcf\x9e\xc1\x80\x9e\xa3\xc5w9\xaf\xd6\xa4\x00\xfeO\x99\xe8\x16*\xe2\x9b&[\xcc\x85D`\x84\x15\x81\xb1\xf6\x8co\xfecf\xfc\x0f!P\x86\xa3\x03\x17\xb6\x86\xa3\xc3\xb5i\x14R\xd3!Q\xd02\x9f\x84\xe1\xb7\xd0/\x7f \xf9\xb23:\xd8\xa7cE\x19B?\xd4\xfe\x07\xd20\x7f \xf3\x88\x81\xfe\x81t\xcc\x1fH\xc6T\xf9\x10\\%\xedA\x8f!\xb7\xcfm\x0f\x12\xa7F\x12}\x13A\xf3\x07\xd23f\x10\xd5\xb7o\xcdHB\xec\xe2\x1eP\xfc'\"~\x0c\xf2\xa7v(\xbeR\xe6\xac\xcb\xab\xa2ji\xdd\xf9RZ\x1a\xf6j\xc9$Ejo\xea\xedc\x06e\x12\x14\xad\xd5T\xe7\xa8\x82du\xb7\x1e\xddR\xa5\x9b\x1c\xa0Cd\xe9\"X\xd9\xd5\xe7\x8a\xa7\x97\x94\xa5\xa42E\x90\x0b\xd0\x0f\xf3\xb2F\xae\xe2HK\x12\x10\x9d\x17\x98\xf7eWz\xa7\xb0\x11 \xa5\xea\xa0\xdc\xad\x8e*\xf26\xc3\x9b\xdcO\xe7$?\xcf\xfd4\xef\xce\x86Z\x9a\xf1\x003\xd6T\xba\xa1o!K\x8a4 k\xb4\x90\xb6\xf5\x97\xd5v\x16O\xbb\xebJ\xeb\xce\x17%\xf4\xeb3*\xd9_\xe5\x18{iK\x9a\xa8\xda\xcbM\xadU.\x12\xb4L\xbf\x95\xea\xe3\xd6\xe3\x1cTn\xa8\x18t\x99+\x07\xb1\xc5\x96\x904 \xb0t \xc3#HxV\x83\xad-4\x0bK`\x13\x10I\"\xae\xa3w\xba\xb8/\xa5\x93\x11eA\x86d\x07X\x18\xaf\xf5\xb2\xfe\xb105\x8aY\xda\x1a\xedk\xf3\xb9d$\xaf\xf2\xb8\xd4Lubf\xf6\x14:\xfa\\\x98B\xef\xd7\x86\x08fa\x14\xad\x87\x084NWkg\xb6\x16\xe9 0\xa4\x06?6\x95\x1d\xa2M\x9f+\xe1\x85\xe6'.\xcf\xba\xd1\x95\x19 $\xde\xaa\x16\xb0\xdcdy\x04\x18\x80\xe8\x18m\x8c\xc5Am\x88\x8ff\xce\xb7\xaa&\x9b\xd1\xe4\xc33\xf9\xb3\x97\x19\xbf\xfb&\xf36\x80\x1d\xdb\xad\xe7\x02NM^\xc5&\xcf\x8fF{\x95\x12`:-\xc9\x9b)\xcb-\xe2T\xe9\x17a9\x00n\xab\x87>\xca\xb5A\x08\xbc\xe8OB\xf8_P\xaca\xb3\x977b\xe4\xd4\xfb@\x07\xfb\x19N`{\xf2\x9f\x9b\xbfl\x0f\xb6\x9e>\xdf\xfa\x0f\x7f\xeb\xb7\xad\xab\xcb\xed\xb9\xc9\xf5\xe6\xd7\xf6\x10\xae\x80\xca\xd9S\xb0\x06\xe8\xf4_O\x13:V\x1e\xd4\xfbfh\xf0\xb5Q\x01x\xa3\x0f\xd0\x96\x03\x8f\x8a3\x84\xed\xce\x1c\x97\x95\x83L\"\xc2\xf3\xeb\xf2:\xb4\xa7P Y`\x9bFb\x07\x07\x9ea4\xef=qD\xef\x1d\xec\xec\xee\xb6!\xdc\x90\xe7\x873\x97\x80r\x93>\x83\xbd\xfd\x9d\xe1\xd3\xae\xc2\xf4b\x89(vh\x7f\xb6\x86\xb43<\x99\xc4h\xe7\xa9\x0b\xc3\xa7C\x17\x86\x87O[\xd0\xba\xb8\x82$\xce\xc3\xb8\xd0\xe7R\x12\x979{\x10\xf0\xbe\xfb R?\x19\xa5z\xf2\xf5O\xd4{\\$\xed-u\xb6\xd2\x9e] \x97\xc9\xfe\xce\xc8\x98BP\\\xfd\xa0\xe2\xfe\xc1]\x8e\xb9\x8f\xc6>lR\xban\x8b\xa7 8>\x86!3t\xd9\xe2\xa3\xd1\xd6\xc0O\xc5\x84\xf3==\xc6c>\xc9\xab\xfd\x1b\xb3D\x15]\xfb\x8c58d\xd9Y\xba\xd2\x1f\xf0\xce\xc4\xad\xe3\x10\xf37\x1a\xec\xf6l}\xb4^\xeb\xf0\xec\x19\xe62\xc0\x00\xdb\x98\xd0 \xa6w\xa3\xc3^\xdd\xc2y\xea\xd7\xaf\x9d\xf5\xfb\x85I\x17F\xa3]\x16\xc2\x03\xf6\xe1 \xed!\xf6n\x8d\xbev\xa0F\x1c\x07O\xd9\xa0\x8b3 \xd2i\x05\xc9\x94\xc0*1x\x91\xc9U\xb2\xf1\xee>b\xbc\x87t\xbc\xbb\xe4\xeb*I\xf3\x0cN\xe0\xf7\x07\x89v,\xc1\x106<\xd2\x1b\x9b7#\xf9E\xb8$I\x91\xc3\xc2g~\xa0\xd7\x84\xc4 B\xe6W\xf0~\xd04\xe0w7\x10D\xc4O\xbf\xa1\x89\xa2\xb9\xe0\x19n\xc5\x18`e\xef\xab\xe8\xc2\xe5#\n>\x95o\x16T\xe3\xc9 \xf3\xe2\xda`\xf9\x8e5\xf5\xd0C\xb6z\xecv\xd4\xab\xcf\xb7!\xaab_\xd4\x97\x81\xc8\x0f\xa17\x955\xa6\xef\x10U\xb2\xa5SF\xcb\xd79\xfc\xb7\xb6\xd0\xac\xab\x94\xd2v\x07\x0f\xa8&l\xa3Z\xac\x8d\x95\xa0\x1d\x03f\x9d\x11\xdf\xc8\xbc\xa6\xb4\x10O\xe5\x9b\xb1\x8av[\x13k\xd0\xeaU4-\xdf\x19\xe6\xc9\xd4\xa9\xda\xe2=\xad\xdf\x8e\xd5,\x89\xad\x1d\xa3M\xa8Y\x15\xcb_\xb6\xb4\x9a\xe8\x1e\xe7\xa9\xcd&Jb\xb3\x00C\xbf\xd4\x9f\xcdx\x12\xda\xe6\xc6Y5f\x04\xb3\xb7b\x1a\x0b\x9bW\x05\xa5X\xe0\x14[\x14\x01\xc4\xed\x08\xc3\xa7b\xdd.D\x92\xecuj;\xed\xfbu\xdah\x16\x89\x88\xc0\xc4L\xd2\xb3\xad\xb0W\x1a\x8a\x01\xfb\xd8\xc6KR\xa6S\xf4\xed\x083\x11\xe9\xd79~@\xb1d$\xe0\x8aA\xc4x\xf6\"\x9e\xf2cv\xe9\xa5El\x9b<\xfc8(\xe4&;v \xf0D\xcfl\x8f\xea\xe6N\\\xfd\x8ev&T\xa7\x98K^\x86U\x1a_\xe9\xa1\xdd\x16P\x12Q \xab\xc8G\x14\xc8b5h+\xa5\xabV~\xe1\xf6o\xc6\x8c\xc2\xc4\x95\xda\x06\xf9\x12\xf4\xc2^\xe2\xean\x08d\xf2K\xc6\x9b\xe6\xe6a\xad.@\xa3\x01\x8eL;\x1a0\x8f^\xfb\xe6A\x05\xd8C\xebN\\h\x858(\x0b\x9c\x15(9\xe1B{\x96\xe6\xe8D\xcaZ\xaa\xab\xee\x86n\xec\xaa\xc5\xc4\x8b\xc9\xd7\xfc\"\x0c\xbe\xb4\x12\xa7b\x9fR\x8a\x80\xd1\xbc\x8d\xb8\xcdM\x93!\x94W\xa8\xc5\x9e\xc1\xb0 \xce\x12\x17\xc4\xcc'\x93\xb2*\xea\x97G\x10onRr-f\x86XR\xe8\xe8F\x98\xfd\x883\x1b\xe4V\x80\x0fe\xf7\x98\x15Z\xa2\x07\x03\xfa_aO%T\xe8\xc2B\xb6\xabG\x00\x9b\xcfF> <\x1c+[\x8e\xd5\\\xd4\xaaM\xbc<\xcc#\x0cJz\x9d&\xb7\x19I-\xfa\x90\xff\xe6a\xf2\x13\x8f\xc47H\x07\xd2\xdf~:\xbf\x11y5\xbd\x1b\x92ft\xfeX$\x93\xf2>+K\xe3\xbb\x1b\xfcn:}\x1bf9\x89\xb1\xde\x1b\xf6\x12\xdd\xd1\xd9\xef\xd9L\xfcL\xc92\xb9!ja\xf6\xf4y\x14\x89\x17\x99xC\x96a.~\xafR\xb2\"q\xa3%\xfe\xf8C\x1c4\xea\x8d\xa4\xea\xccK\x8d\xef\xc0\xc9e\x1dz\xd7a\xdc\x99\\\xa5A\xb5\xae\xd2$ YV~\xccC\xa4HA\xf1\xea\x8d\x04\xb7\xd3\xb6\xf9\x16\xac\xd2\xb6\xa5|\xb6\x98\x86\xe9\xe3z\xc6>\xed\xeaW\xb1\xf4\xb3/=z6\x90\xb6>h\xb8\x10E\xc5o\x15\x19AEO\x90KL\x9c\xcc\x90\x98G\x84\x1a\xa0\x8a\xd8\xda\x90Uu:}\x0f\x06\xb1\x15\x03\xf5\xcb\x8aU\x19C\x83k|\xc4@\x9aH/\xd5\xe2\xd0\xca\xbe\xe6\xa4\x0bk&f\x94\xd8\xc0p\xc7'0\xa4\x88E\xd2\xdeT\x98jx\xc9\x835\xc8\x8f\x9a\xf4DlLx+duZ\xb0\x19\xd7\x07\xa8\xc2{\xb5\xd7Lt\xcfP{\xea\xa8\x02|\x9fb\xdep\xe2\xd7\xb1\xaeof\x961\x17\xd6\x86\x88\xa2\x19\x0b\xd0 \xc3&\x91\xa1\xa1GnHzW\xcb\"\xdd\x95\xda\x0c\x19\xb7x\x92^j\xf8\x1bts\xb1\x19W\xcdp2\x9b\x04\x17B\xc7a:\xb5\xd05s\xf2Z\xde\xbb1\xf15\xc2\xb5 \xc7\xb8\x84cN\x0f;8\xc5\xe0\x14C\x1e\xd98e\x07\x1c\xcb\xb9 )\x85k3\xa9\x9d\xe4-\xa0\x16\x97\x00]\xfb\xa6\xef\x03}6\xc4Y\x9a,[Yv;4\xcc\xc3\x83\xf1\xb8\x8f\xbc\x94dE\x94\xbf.\xe2\x80\xae%\x17\x9f\x04\xc9rU\xe4~\xce\xd9\x94\xce\xcd&6Z\xe3\xe5\x03\xab/#\xf9\xa7GWJgH[q\xed\xa1L\x0c\x88_\xb9wuE\xb2w\xc9\xb4@\xf6\x8d\xf2i\x98:\xd6/\xa2\xfc\x1dY&,soB\x9f\"\xda$\x02\x8b\xbedH\x94\x11\x1d\xe5\xcb<-\x82\xbcH\xc9\xb4D\xb6}\x18\xefGP\x99\xbeBe6\x99s+\xc1<\xb8F\xea]\xc8\xfeM\x1dg\x87C\x06\xb30\xcd\xf2*^\";\x18\xfc\x18X\xf5p\xbb )\x01\xe2\x07\x0bX\xf1\\\xbb\x94\x11\xf0A\x9c%\x9a\xa3\xc3Gk\xb0\xb2SG\x0d\xa0\xd0\xbd\xc6\xd3\xf8~!wYC\x88UR\x8bq\x1dU\xb5\xf9\xc3\xd3\x0dY_\x0e\x8e\xdb\x93\xe4\"Z\x84\x9cW\x08\x81\xd3~\x03F\xfb\x11N\xfb\xe5\x93\xb4\x9d\xee\x03i(^J\xa6E@l\x85\x13\xea\"\x98\xc9\x84R\xcb\x97\xcc\x18R\xa3\x8es\xe1\xf7\x07E %\xb1\x9fu\x91\xb6\x8f\x04L}\x99\xd3\xf5m'z\xb5\x97\xc2\xa7 \xee#\xb6\x87\xc3\x03\xe5@D\xc6\xc6\x1e\xed\xee8zV4\xb6\x87\x83\x01\xa5\xfc\xda\x1a\x00Y\x84'\xd2'$6Z\xabK\x83\xea\x91TLZ\x12\xcc\x18tM\x96\xb4\x1a\xea\xc1\xaeaD\xed\xcc\xf5\x86\x1c\x0b\xd5\xc4G\x8b=\xb6\xf1H>Z\xedq\xac*$\xeb\xfb\x8e\xc9\x9c\xc6`\x8d\xbc=o\xcf\xd2\xad\x12\x8d\xfd\xe1\xd5\x153\xd4\xa4\x7fO\x84\xdb@o\xf0\x8d\x0e\x0e\xd6\x86\x9f\xcc\x85\xca)\xe7j\xb2\xeau\xa7Q\xbf`\xf7\x0ev\x95\xe7!\x7f\xbe\xa7<\xa7{\xc7\x9ap\x9c\xf8\xbe\x88\xa2K%Tx!\x17\xf8,\xd2\x9d\xab\xa524n?E\x13\x04f\x0fx\xe1\xcf\xcb\xcc\xde\xdf\x01R\xd2\x89Bo\x0b\xcc|2\xe6\n\x16\x08c\x8ev\x99q'\nF\xc6\xc8&?\x16\xb0{OGz\xc8>\xdd\xeb\x9cx\x0d\xbd,\x96q\xc2\xdej\xb7E\xca\xb2\\\xc4%\xd8\x1e\xdb\xf7\xd1Su\x96Y\xdf\xf7w\xd41\xb1Uqp\xd89$\xc3\x0c\x85\x0c\xde)\x83w\xb26\xbc\xf5\xb2> !\xef\x0e4#\x91NXJl\xb4\x93\xd4\x82V\x99h\xce0\x89s c\xa42\x84U\x98\xf9\xbc\xab\xbdx0\xc0\xad>\x96\x90\x1f\x14\xfbR\xb5\xa1\x17\xc6\x0b\x92\x86\xfc\x149\x1c:\xcd3-\xb6w\x06\xeaL\x16\xac\xae\xda*\xac\xea\xb2g.\xf8\xd2\x9br\x80\x19\xae\xbd\xa2\xd2\"\xf0\x14I\x83#\x88\xe0\x18*uFD \x80\xe6\xda\xa5\x04t6\x89\x14\x18\xce\xaa\xfa&\xc1%\x8a\xb9\x94G\x94)\x93\x1f\xb4\xebwg\x86C\x879\xc7\x88@\xda\xc9\x0cfU~IJ\x12\xce\x1a\x84\x96_W\x95\xb9P\xa8\x0f\x10\xfbo\x08\xd7\x89\x94\xf8S\xff:\xe2\xb1c\x17aV=9a^\x80\xf5\xf2\xb7i\x98\xd7\xcb\x97Oxy\xa6q\x89\xa2\xe4\xf6\xaf~4\xfb\xb0\"1'\xd3\xeb\x15\xd5K\x94\xb55>,\xabL\xe2\x80\xd8\x16\x89\xa7\x96\x0b\xabvp6\xb5\xf4\x9a\xba\x85\xc3\xc1\x95\x18\xc0y\xee\xe7\xc4#\xf1\x94L\xe9\xcb\xb4\xd4\xc5\xd9S\xd6\x85.\x1d}c\x0e\xb16[E\x0d\xf4\xe2;\x99\x1d*\x1f9\x19.\xaf!\x17,\xd1\xaf\xbf\x86\xf3\xc5\xcf~N\xd2w~\xfa\xc5r\xd56\xe2bIRZn\xdc\xd0\x85\xcfI>n\xa7\x98\xc5\xe6\xd6\x00b!7[\xdf\xfc\xd5\x80\x1c\xb7\xd7P\xa6$\xcb\xd3\xe4\x8eL\x1b\xdd\xef\xddE\xc9\x9f\x86\xf5V\xacS\xec-]@\x8d\x12\xb5\xf1TK\xac\xfe\xa5W\xf6\x0d\xbd\xce4\x80(\x0b(d\xb9B\x08\xd4\x06\xa2\xc7\xc8\x7f\xfc\x10*\xfd\xb3i\x10\xb4\x88Q\xe1M\x19,I\xe1z\xc5\xbf\xea:\xe4\xb1Av\x80\x14Q$6,\xae}W\xdeGyM{\xff]\x0e\xca\x9d\xe1\xc8\xb1\x1f{\x8a\x93\xca=\xabT\x91t\xd1\xe8k\xf6o\xff@w\x90\xb3\x10\xf7\xfe\xd7G\xf6;\xb1\x07.\xd2\x1e\xdf\x00\xccu\xcbk\xa9\x94\xa1flvl\x1f:]\xf2\xbe\x90;~z\xe2l\xfb\x98$\xc2\x16\xc0\xc4@\x0b\x82\xa6\xf9\x1d*8\xf4\xb2;\x19\xc1 \xc3Pz\n6\x05\xd6F\x0bez\xd0\xd2\xef\x1b\x86\"\x1a\x9a\xb2}\xd4D>\xca\xf1h\xa7\xe7\x8cm\x8d\xf6,t\xb7\xc5\xedVP.\xde\x16\x9bH\x03\x1f8\xe6\x1b.I\xa2\xf3\xf07R\xe2\xad:L\xe8vl\xa4o\xad\xdd\xfa((\xab=*\x1a\\&\x16\x9cNi\x9d\x94\xb9I\xc6\xed\xa8@\\%\xfb\xda:-q\xad\xcf\xdc\xba\"\xf6\xe6$\xa7\xf7\x88\xac\xd0\x01\xca\xa7O\xcb\xf1\xa2czu{\x02\xc3\x81C\x0b\xa4$\"~F\x98\x84\xaf)\xa1}\xd0\xa8oc\"\xd2\xa9b\x83\xe9X\x05\x08\xbd\xf2\xdbD-\xd5\x0b\x06\x8fY\xe4 \xeb\xa6\xd6Y\xe8\xa0[\xec1\x8b\x10\xe0\xe8\xc0\x01\xda5\x0f\xbauO\xab\xe8\x03\xce|\x91\x92\x06@\xbbD;\xe2\xfa\x16h\xa5\xdf\x05Zi\x19G\xa9\x114Z\\\xfd\x01\xd6\x88\xc8\x00z\x98\xcd\x92\"\xed\x02Y\x8bT\xf1[\xa0\x96|\x17\xa8%R\xf4\xa9\xd4Q\xf5\xf9\xe2Z\x0bp\xae\xd6\xf1\xb8\x8e\xca\xf4Gg\x81O\xdb\xe4ju\x03\x7fmq\xb3\x98tO\x95.%\xfcy\xb7l\xc4p\x94\xa7v\xb2\xfe9.\xf7\xe8\xd1-s\xb9\xd1#\xc8\x08\x89\xfa\xda\xd1\xcb\x8a\x0e\xb5\xe2\x96\xe1P}\xce\x98\xfd\xe1\xfe\x81c[Y\x1aX\x1a\x9e\xff5\xefH)_k\xca\xdfX\xfe\xc1\xc2\xf1\xb2U\x14\xe6\xb6%J\xcaR\xd8\xd8\xde\x1f8\"a\xf99F\xca\xe8\x03$\xce=\x93\x9a\x05\x98m\x94~\xe1\xda-tr\x84\xc8d\x0d\xafx4FH\xe4\x87\x14s[\xb1\xbf$\x16\x1a\xd1$\xd5=7\x9fDIxi\xd2cK\x9f\xf9\xd5\x17>/\x87\xf2\xd6M\xf6{\x0c\x19\xb3H\xe0\xde\xcb\xb9\xe3\xb0\xa8b,\xb6\xcbi)c\x871\x14\xe2\xb6\xf64\xa9\xd6\xc4\x18\xec)\x89HN\xf0\xbd+\xbd\x92\xd7\x94c\x97\x93(3\x85\xe54\xb5hu\xf84h!\x87\x04\x14\xa7}&>Ja$a\x87\xdc\xfeZH\xa1sM\x94z:9\xf4\xc1\xa9\xc4A\xc0\xb8\xcb^\xa5\xd76\xeb\xa4\xbe\xf5\x9bo\xb4o\x10\x81\xef\xeckw\xdf\xde\xaeJ\xc53Q\xdb\x81Z<\xe3\xc5UYj\xc4\x9f\xab\x12\xbb\x80?W\xeb\x99\xf1\xe7*2X\xa1\xd0\x8ci\xb3\xce\"B\x0f\xc4z\x81\xa9T\xe0\xb5O\xc9\xe4\xbbz\x81\x05+\x10%\xb1\xbe\x82\x1b8\x81\xb4\xfeh\xd9I\xb47t7\xd0<\xc8\xe7Z\xb2\xf9\xe5\"\x8c\xa6)\x89\xc7\x86sx\xe9\xaf\xc6\x10zK\x7f\xd5$\x0b\x80 1\xcf\xfc`A\xcb\xf0\x9f\xfarAR\xc49-\x85?\xf4e\xf2\x045\x9f\xb4\x14\xff\xa9/\x97\xc4\xd1\xdd\x18f\x8dw\x1a\xca\xe5e\xb2\\%1\xa1M'^y\xd3,\xf7\xb1HI\xadl\xedA\xb3|m\x05\x8cA\x03\x1cy\x86\xc7\xa0\x81J\x98\xfd\xe4G\xe1\xb4,Rx\xf5'\x9aN\xa6\xc9\xea\x82\x99De\xa6.\xbd\x8c\xfc,\x1bC`z\xcf\xd7\xe4\x18\xa6\xa6\x12\xef\xc2\xafa<\x86e\xf3\xfd\xab\x0f\xef\xc6\xe07\x9f\x97J>\x8d\xf1\xe9\xd5U\xb6J\x89?\x1d\xc3M}q\xea)\x829>\xfdc\x90Nc\x93\x87L\x12\xf0\x94\xb2\x1e\xf6h\x7f\xbf\x12\x14V\xe2\xa5\x85\x9f}\xb8\x8d\x85\xc8P\x8b\x9cF\xfb\xaa\x9eO\xcf\xa1~!wc\xd8\xd0XA\xa6d\xa6\x7fqu\x95\x91\xc8\xfc\x0e)\x84\xb1\x9a\xbeX\xeb\x10\x9a\x19O\nI\x9cG\xbc\x94T\xbbJ'?\x8e\xfaU\xf3\x85\xdcI\xd5\x88_BU\xa1\xe1\x1cX2C\x03Y\xd2\xd4*\xd3\xeb\xcf\x7ff'\x96vE\xe6\x98^\x994_\xe0\x1ch\xb6\x16NA\xdc|\xbeJ\x93U6\x86B\x03\xff\xe46\xa6|PhZ\xd6P\x01\xa7\x8a\x0b#\xbd\x0f\xea\xc7\x88\x060:`\xa4\xcc\xd0\xfaw\x1d\x97\x06&\x0b\xf0\x15\xe8,\xc0\xd1\x9b\x96\x11\x04:\xde\x19\xd5S)\x84t\xf1\xe4,3\xcf\nm9R2s\\\x88\xc4\xc3\x19:\x98\xc0&\xa0\xd2\xcfqky\x06=\xb6\x84\x05\xe91.\x9f4\x8b1z\xb7^\x10\x9f!\x1d\x14\x96\x921\xe6\xb5\xb6Q([\xd3\xe6\x99\x87}f\x1f\x93OR5\xe3.\x05\xdfTg\x18\xb5\x05\xa3&d\x98\x0eh\xea\x80\xef\x05\xfc\x8c\x84Fl\x8f2\xe2\xc3\x14\xbd\x944\xcb\xb4T\xf2-J\xc3\x9e)\x85\x11S\xef\xdd\xc01L\x8f\xe0fs\xd3\x81\xc5\xe4\xa6n\xd8s\x83\x811\x9b\\\xee\xc0\xad\xf7\xa9\xee\x8f\xf8\xd0\x18 \n\xdf\x88\xb0?\xa3\xf0\xcat=\xa5\x9d\\\xa21\x87\\\xb2\xd9|\xb5.\x96N\xcd\x96\x8c\x02^\x9a\x81e\xc3\xe0\xfeA\xb77\x02\xba\xdag.\xac0\xa9&z4\x05E\x9a\xd2\x03\x10\xfc\x1aK\x13\xd4\xc9\xaa^Fp\xca&C\xb7\x9e\xd2 P\xbbWs\x8f\"\x0f\xae\xa4P\x9a\xa7G\xfa\xf3x\xfa\x89\xc5F\xf8w\xd2\xa9t\xa8\xc6\xe81\x86\"w\x19\x96\xa5\x7f\xf8>\xa0?\xf8:'\x1e\xc3*\xf4\x17b\x1eu\xfc\x12M\xd1\x13_\xf8\x0c\xb8\x94\xa8\xb4\x7f\x7f\xa8*n\" \xd4\xba\xd0-\xdc|\xb5\x00~8h\xce~\x0cj\xdd2\x16\x8d\x87_\x17\xd2\xf1kHg!\x90\x0e\xdb5\xe5\xf2\x90q\xd0T\xc5A\x0c\xdel\xe1\xe39.\xaf\xe9\x12mi\xde9\n\xb6\xf1\x0d\xd8\x86=\xb7e$F\xf9\xbb\xba~\x8c\xe2\xbd\x15\xf3\x81\x99\xd1?cqG\xcbj\xb0\xd3rM\xec\xb4t`\xd5\x07;-;\xb1\xd3\xbc\xc4NK\xc7\x85;\x86\x9d\xee\xe0\x18\x96GpG\xb1\xd3|rW\xc7Nw\x06\xecT\xeb\xd0\xbc\xd7\xfe\xe7{c\xea\xc2B \x81\x9b\xba\xfe\x9c.\xfe:u\xfch&\xb8\xa6Gc\x0bD\x90\x12\x0c\x8d\xc9\xad\xca\xa4i\xf0'\xe8&M%\xb1\xd3\x81\xe3\x9d\xdf-\xaf\x93HO\xe9\xa6\xebU7:\xd4\x9b\x0d\x0d\x0f\xbf\xcd\xd6m\x83C!\xa9\x0c\xd0q\xc1\x7f\x8b\xdd\xdb\xc8 \x81|\xaa\xaa\x19\x19\xd3\xbf\xdf\xb0#bt\xf5\xfe\xb0sdf\x94+E\x12\xe4f]p\n\x13r\x89\x96g\xfe\xb7\xc8\x131\x1e~cxJ\xf8\xbb~\x13\x11\x1aB\x972\x95\x1b\xa9\xechH\x13W`\xe0b\xd8lD\xe1\x11k\x7f\xc0j\xa4\x93I\xfbF\xe8\xddV\x02\xa7`m\x0d,J_u\x8c\xbf\xc6p\xe9$E\x9cUb\xe7+F\x1c\xea9C\xc4\xcb\x8a\x15I\xaf\xb8yq\xc5lU\xd6c\xacR;\x97eqM\xec\x15$\xb1\xd0E\x9a\xc4\x17\x98\x98_\xcb @\x87]\x8a\xb8\x84\x89\x82\x9e\x0b\x03\xd6\x8dY8/D=\x1a\x9f\x81\xda\x93\x87\xbaU\xf1\xa3\xc0\xd6\\\x0e\xaa\xd7\xb9\xc2\x88\xc45(\xd7\xe0Z\x9f\x80\x98\xdc\xa2\xe9r-.w f\xf8\xfe\xb6\x07\xfb\x9d\x9b\\\xb7kj\xa6\xceJ\x98\xd8\x97~\x1c'9\xd0\x86\x11\xc5%)\x14q\x19sH\xbb[\xbe\xcb\xa0\x1a^\x1f\xcaxyt@\xfb\xa0\x81@P\x10\x91b\x04_\xba_S\xb9\"\xe6\xfb\xdb\\\xdd\x9ch\x19\xab\x99c\xe5\xfe\xf02\x9d\xd0\xec\xe3\xc9\xf4\x87x.\x89\x93\xa8>\x04\xdd\x0c\xd9\x03\x17B1 g\xed\xc3\xa9\xe7\x8c\xb9\x06\xa0\xb5\x18\x0d\xab;M\xf2\x99\x16f\xab\x18\xff\xf7\xc3\x8cr\xa8\x98X\xe6\xfe\xbeK\xceT\xc6\xd6\xe6Lm\xccX*\xd2dj\x1b\x10|\x048\xca\xc7\xa5\x9c'\xed\x92\xf30S\xef\xfb{a\x06\xde\xc4\x0b \xefg/\xcc\xde'\xf9\x82EcH\xdd\xda\x0b\x06\x8a>\x04K7=W\xf5An\x83\x0b\x93\xfb4\xa1\xee\x04NBpjbB\xc9\x079\xd5o\xad\x99\x94\xac\x88\xdfo\xdd0\xcf\x1e\xf5\xe8\xc6\xa5\x133\xda;f^\xd61lb\xd4L\xccP\x85\xc5\\\xefL\xcf\xc1\xe6F\xf4[e\x81\x1a\xcby1\x18/\x8c\x83\xa8\x98\x12\xa1\x95\xe9p\x1fG\xef\xe0\xb2\xad\xda\xeb\x07\xae\xc9\xed[S\xb3\\\x9bEM\xee\xe5\xfe\x9c\x9b[\xd3_O\x9eP\x1e>\xa4\x8b\x88\x89\x92\xe9O<\x13M!a\x1f\xd0\xaeJkJ\x86ofa\x94\x93\xd4n]\x91PAn\x8b\xc7J.\xb1v\xaeV*\xad\x93\xe6\x84i\xa2\x16r\xf3\x15\x9c\x0e\x14:\x88\xdf\xf7\xf7hK\xc6\xde/WQ\x18\x84,\x1dIy#\x97 _\xa5\x12\xe5\x8d\xae\x8e\x9e3\x85\xb2A/J\xfc\xe9\xbfs [Y\xe0G~jq1\xbex%\xd3Y\x89m]\xa0s&\xbac\xc6I\xbc\xc5\xbeA\x84LO\xbc|A\xa0\xec\x7f\x14f\x18\x07\xdf\x87,X\x90\xa5\xef\xc1\x1b\xf1*%Y\x12\xdd\xd0\x13!\x99AV\x04\x0b\xe6\xed\xdf\x08l\xe3Y\xcdIe\x86=\xc9r\x15Fd\xfa\xa6\x82\x9c\xcf]\x08,\xd1\x01\xcb\x85\xc9\xa5\xfa\xc1\xd9\xd7\xe6\x07\x02\x9e\xda\x0f(m\xf9\xce_)\x14v\x03\x9etK\xf2\x1d\xa4\xd5X\xd0\x8b\x01k\xac\x95\xdf\xe3{\xf2kA\xe2\x80\x98K,\xfd\xd5\ns\x1f\x98\n\xcc\xfc(\xba\xf6\x83/c9h\x97\xb8\x1e\x94H\xf3\xd0q\xea\x8b+\x9e\xb0\xadx9\xc1m\x8af\x16\x9eh\xa9z\xa6\xf1\x15m6GQ9a\xa8\\\xe7\xa7|\x84q\xed\xf3#\x16,v\xe8H2'R!!U\xae\x08Fj\xd2\xd6\xae\x16\xc3\x9aP\xc9Jz\x15\xde\xab\xb3\xd7\xcf?\xbf\xbd\x10\xfa\x95R\xc1\xdf\xb6\"\xc4j\xa8w3\xbb\x0d1\xb2\x9c:h\x1d\xdc\x03?#0\x1ck\xe7\x03\x83'\x8a~)p\x9c\x0c\x0c1\x02\x0c\xf1\x96\xb1\x9d\x91\xb9\x1d\xb9b\xb5)\xd5G\\\\\x86\xa6\x04\xd3\xa2\xfd\xa6\x86d~N\x93x\x0e\xcc3\x141\x88h\x12\xd7\xcf9\xc3&|\x16J\xe9D\x9b\xba!\xe4y.SA\x0e\xa2\x83u^{\x92;.l\x90^\xf1_\xc49+[K\x17\n\xa2R\xf0\xe6\xf9\x8a\x04\xe1,$\xd3\x12-\"C\xcfQc\x06v\x92RD\x19\xc6\xf3\x88\xf0\x11r_]\x07\x83\xc6\xfba,pn\xed\xad\xa72\xb5k\x84\xb1\xd1\x0d#\\w\x18\x7f{\xfe\xee-\xc7\xde\xb51P\xbci\x1a\x81\xf4\xae\xd1\x7f\xb1\x8f\xc9-\x14\xb6\xe6\xdcb\xc7\xa7V\xaa#\xf0\xf8X\xf5\x05\xac \x93\xbb\xad1\xd7$\xf6\x86\xc3\x9a\x19\xdf\xa1\x96\x96K\xda\xe4\x956\x81'\xf4\xa5\x1aXLn+\xd4\x1e+\xef>\x9f_\\}>?\xbb\xfa\xf8\xe9\xc3\xc7\xb3O\x17\x7f\x1b\xeb\x92\xa1\xfe\xf5\xf9\xf9\xd5\x8b\x0f\x1f\xde\x9e=\x7f\x7f\xf5\xd3\xf3\xb7\x9f\xcf\xc6\xb0\xab/\xf5\xfe\xf3\xbb\xb3Oo^\x8aR\x87\xfaR\x1f?\x9c\xbfA\xd6@)>2\xd4\xfa\xe1\xa7\xb3Oo?<\x7fu\xf6J\xed\xc6\xce\xa8\xf9E\x18\xd3\x85\xf1\xea\xc3;\xc1\x10\xbfD\x19[\x97\xf3\x12H\xb2\xd1P\x7f:\x02'v\x89\xc7\xab\x0e z8\x98NS\xe0\xe2h\xe2\xbd\xfa\xf0\xeey\x9e\xa7\xe1u\x91\x93\xf7\xfe\x92d+?\xe8\xfe6\xd3\x7f\xdb\xf5Y$>\x13\x00\xe8\xf5U \xbez\xc7\xe3\x9d\xbc#\xf9\"\x99\xf2\xef\xf4\x98\xba\x94W\xccP^\xe1\x85\xd9\xcb\"\xcb\x93e\xd9_J\x18\x16\xdeU\xe3\xb9\xb0\x97\xe4^U\x9a/\x9d\x16\xba\x1f\xf0`]\x95s\xa0\xea\xd7fL\x12f[\xbb\x87\x96\x0b\xb3\x16co\xdaw\xa4\xcd\xbc&Y\x98\x877\xc4X\xa7\x1e\xcb\xf5\xab\xfc\xc3\x0dI)\x07E\xa6\xc6\xe1\x9b\x90b\x93\xc9\x95/\xc3F\x06~\xf2/<\x05\xe2\xb0 \xf8L\x1e\xa5x\xa6\xefd\x19*(\xb5\xad\xbd\x01\xee?\x174[\xb4ms\x03\xdf\x9a7\xe8\x9c>\xeb\x08[\xb5\xf0j{\x02N\x14sA\xf9\xd2\xbbi\x00:\x96k\xb1\x88\xad\xd4\x8e;\x0es|\xcd(\xaf\x17\x19\xbf\x92w\x1b\x9c@\xc4\xca\x07\xc6\xf2\xf5\xcd\x06'\x10\xb0/dD7\x99]6lv\xc4\xa5\xe1\xd7jO4\xbeq\xd6\xf8\xf9\xd6\x7f\\\xf9[\xbf\xfd\xf2K1\x18\xbc\x1cl\xe1\xdfW\xfb\xec\xcf!\xbb}\xcdn_\xb3\xdb\xd1\xeb\xd7\xf4\xcf\xce\x01+\xbcs\xf0\x8a\xfdyMo\x87\xaf\xf1\xedh0x\xb9\xc5\xfe\xbe\xc2?\xac\xf0hx\x88o_\x0e\xd8\xed\xeb3z\xbb3\x18\x0c\xe9\xed\xab\x03\xfc\xf6\xf5S\xf6\xf6\xf5\xab\x97x\xfb\xea5\xbb}\xfd\xfa\x95&|Is\x05\xbdyu\xf5\xfc\xe2\xe2\xd3\x9b\x17\x9f/\xce\xae\xde?\x7fw6\x06k\xea\xe7\xfeVJ\xfc \x0f\xa7Vs\xfb}\xfa\xf0\xe1\xa2\xed\xa34Ir\xcdg\xf5/\xae\xce/\x9e\x7f\xba\xb8z\xf9\xd7\xe7\x9f\xb4F\x85Ji^\x0e6\xc1\xfa\xe5\x97-o\xb0\xf5\x14\x81\xfc\xe2\x00\xa19\xe0\xc0\xddg\xd0\xdcy\xcd\xa0\xb9;\xd0t\xa3Z\x1cz\xae\x1e]\x0d\xb3,d\x8e\xd2\xf1\xd4O\xa7\x0c\xff\xeb\x91y\xcbQ=n\xa4\x16\x00\xb4DV\xca\xf7\xa1\xb3\xea\xfa \xa6\xfai'\x13jj!3\xe2\xc00\xf5\x03\xb7\xbd\xb2I~\xe9\xc8\nr\x8d\xd6\x15\x8c\xa8B|3ln7\x13)\x8a\xe6\xcdFS\xcf\xef\xceO\x1c\x1c\xee\xd4\x18\x8a\x1df\xa3\xfc\xd4\xc0W4x\n\x8a\xef\xfc`\xf1\x89\xcc2.\xe1Bi\xc7\x157\x9d\xe264:a\x87\x9e\xcfX&E\x9cK\xf6\xf1\xea\xd8P\x98\x1f\xa2\xb5\x94^.V eZ\xaf\xc6\xae\x7fi\x94\xe7\x10\xb5\xdf\x92\xce\xa7\xf9\xd2K\xc9\x8cI\x91\xe7$\xffD7\xff;\xda\xea'\xe2O\xefl\xc7#\xf1\xaf\x05)\x08z\x04R\xcc\xdc\x86_\xe7$\xffk\x92\xe5\xef\x93i\xe7\x8e(\xbb*}c\xb7:6\x17q+P\xb5\x8dxSRN+3\xb1S&\x94>S+n\x08\xb0\xeb\xfd\xe0\xf1\xf3Z'74M+\xe3\x8c\x94^4'\x12\x95:(T\xc6\xc4\x13!\x97/_\x05I\x9c\x93\xafF\xdfdM\n\x10\x90\xd6S\xeae\x8b\xa4\x88\xa6\x9fWS?'\x08\x14_\x9ft\x18\xf0\xacA-B\x1d\x82\xbe\xc3\xec1\xeb \xb0\xc5\xa8]\xf6\xd5\xe3\x16`\xdcc\x016\x11P\xdbT\xadH:K\xd2%\x1b\xef\x9b\xd9{\x12\x90,\xf3\xd3\xbb~\xfe\xcb\xc4\xbb*\xf0\xcb\x17~\x1e,\x98\x86\x8f'\x8a\xc51\x9ajo\xac\x9f\nk\xe81`\xf8=0\xe0\xc8\x10\xedo\xb8\xfbT\xab?\x1b\x19\xfc6w\xf6\xd4\xf2\x183\xad2\x08\x91\"YN\x93\xa0\x10\xd3\xab J'^{\xe2\xc7\xbb\x84)q\xf4\xb5\xc5\xfeM8\xc7h\x9erf\xe5\x93\xe6{\xaf\xc8H\xfa|\xce\x1b\xde\xfe\xe5\xfal:'\xbfl\xff2\xdd\xf6r\x92\xe5\xb6\xa6\xa0\xf6\x1c\xd0\xf8x\xd0\x8d\xd7\xf0\xa9\x00\xd9\x82\xcc\x8b\x93\xa9\xc1:*\xe69V\x995\xa7~W\x8b8\xedz\x8e\xa5\x16?\x9e\xc7\xb1\x8cK:\x00\xc3Y\xb2,h\x93\xf4\xd2\xc5\x1d\xa5\xd9\xbch\xc5Z\xed\xb6E\xbe\x8c0\x8a\x1c\xda\x8e\xd1;\x07\xc6\xd2{\x8aP(\x1c}V\x00\xf1\x8bi\xfd\xd6\xd6]\x84Q)\xbbv\xd2p\xc8=\x16(\xdc\xf0?\x94db\x02\\\xdd\x0b:\xf7\x95\xd9B\xed=\xa5\xe1\xea2\x0bf\xeb\xc1\x03\xeb\x89\x92\x82a\xf9\xfc\xe9\x0d\xc6\x83\xd2C\xe1\x1c+\x10\x85\x84\xd2\x94A\x8e\xb7\xaf>\xbc\x93\x7f\xb3\xca\xc5\xddE\xf2\x85\xc4\xec\xc6\xcf\xfd\x8b\xd4\x8f\xb3\x19I\xdf\xe4d\x89\x0f_\x87\xbcQ\xba\x9d\x9fG\xd1\xcb$\x8a\x18\xc7\x8bO\x94\xdb\xd7I\xba\x14\x0e\xca\xf4\x9e\x85t\x16O\xde\x91i\xe8ce\xef\xc2%\x1e\x80\xcc\x8d\x9b\x9e\x03S\x8a\xce\xde\xf9+\x97\xfe\xc52\x1f\xfd\x90\x8e\xe1\xd7\x82d\xac\xeb\x1f\xa3b\x1e\xc6\xfc\x0f\xfb\xf2\xfc\xa7\xbf\xbc\xc5\xb5\x8e\x05\xce\x7f\xfa\x0b#\\\xc5\xddG?_\x9c\x93yy\x9b\x84q.n$(\x9c\xff\xf4\x176\xee$e\x83f\xd15^\x14\xb3\x99\xa8\x8b\x82\xfb|A\x08\xfb\x9c\xa2\xa1\x8b\xd4\x0f\xbe\xbc\xe4\x00/\x1f\xb0\xbb\xa4\x08\xb0G\x96\x88\xe7\xe1\xd2y\xcc\x18\x99\x93\xa1(Dl\xd1L\x1f\xb4\x93\xee\xccb\x92iv&\xddK)\xdd\x89\x8d73\xe0\xfb-\xa8,G\x15t\x81\xce\x1b3\xee\x8a\x94`\xc8Q\x17\"\xba\x10'\xd1%\xdd\xee\x1e\xc2\xb5c\xcd\xab8\x91\xa1\xa62\xbcI\x17\x024\x1c\xe9\xb1\x08T\xe2eQ\x18\x10\xfb\xd0\x85\xada\x97!\xafi\xbb\x9b[\xeb\xce3\xd5\x99c\xea{\x04\xc7\xeem\xd8o$xj\xee \xf6\x10\x9e\xd0s\xbf\xb9\\\xea\xee\x07\xf6\xc8PNrd\xb0w\x0de\xb8\xbb\x84\xa2;_\x0fAJ\xb8pG\xe5\xbd8\x0f\xb7o\x8a\xd8\xde;xp\xe5\xe5\xe3B\xd2\xb5\x84\x8c\x1d\xdc\x1d8\xdeL\xd7\xc3=},\xe6&\xee\xee\xda z&\x82E\x99M\xd0\x1e%\xe6&\xc6D\xf6\xc9\x08\xb9\xf6\x93\xa0l\xac\xb92T\x97\x93\xbe3\xb9&\xa4\xba\x98\xf4\xdd\xbd=\xc7\xde\x18\xd4D\x95\xa3\x9d\x03\x87\xc7\xedq\xc1jF\xcf\xd1\x9bG^QR\x8eG\xfb!\xc2\xfe\xee\xaa\x9e\x82\xe3\xa1%\x06\x8f\xb0\xb6\x12\xd1\xc2\xae4>\xfee\xb8\xba\xabPooRK\xfe}\xaa\xa5\xa8\x10\xa8<]L\xe3\xf54\x895\xe1\x18\x90\xdbB\xff\xdb\x9c\xf1Wbl\x9b'\xa5\xaf\x84n\x8e\xcd\xaeK\xbc\x9d\xa1qn\x1d\xed\xe4\xfe\x13!\xf5\x162n#\xb6\x87\x83\xa1c\x1b\xa7\x9a\xb7{@\x11\xbb>\xae\xef\xef\x0f.X~#\x8c/\xf4\n\xe5+7\xd1x\xa9\x88\xe7\x1c\xcf_\x07\xe8\xfd\xe0\xda\x9aQ|c\xa3!Vn\xcf>\xadU\x8ftat#\x89\xddk6e\xb3(\xdd\x01\xc0\x02\xcb\x86\xf1#\x17\x1c\x81g0@\x1e#ET\xf1t08\x18>}:\xda\xdb=\xd8\x1d<}:\xa4,\xc7\x9a4\xfd\xb7d\xb5lM\xa1\x07[0d\xe6\xc0\xd6\xbb0fVs(\x12\x06B\xc9\x0f\xf8\x17\x0cyFi\x90#\xb8 \xb30\x87E\x9e\xaf\xc6\xdb\xdb3? \xd7I\xf2\xc5\x9b\x87\xf9\xa2\xb8\xf6\xc2d\x1b\x15\x99\xdb\xd3$\xc8\xb6\xf1\xe3\xad) \x92)ar\x9f\xd30\xbe\xf1\xd3\xd0\x8f\xf3\x13\xac\xb2\x96:\xa6L\x1bHQ\x8e\xf5\xc4O\xe7\xd9\xe4\x92\x95\x8bi\x15\x9f?\xbd\xa9d\xdfRb\x19\xd8\x84\xa1\xeao\xc4\xea\xc0Qc\xae\xb6\"\x8a`I\xb2\xcc\x9f\x13t\xb4\xcb\x08>\x8f\x93xk)F<%7@\xe2\x9b0Mb\x14\xaf\xd2\x8f\xf1C\x1cG\x06~<\x05\x7f:\x0d)\x80\xfd\x08\x16$Z\xcd\x8a\x08n\xfd4\x0e\xe3y\xe6)n27<,d\x95oHM \xc0\xa8\xbc\x04\x85d\x14\xf6o\x04p\xe0\xa70\x89\x90\x9d\xc2\x8c\xb8\xb3\xd4_\x92\xec\"\xf9\x98\xac\xe0\x84\xceT\xf2\xc8\x8d\xd1\x87\xbe\xe3IC)]CJ\xb7\xeb\x1c\xc9\xd3\xf5Vk\x8bI\xa7x\x03\xedj\xaa\x86\xf7\x998\x03\x1a\x91\x04\xa1\x81\xf4r\xe1\x1d\xd5\xba+\xa4\xc6j.Up\xdat\xb1\x1aW)L\xf0\xd9%\x93\x94\xc6\xcd\xc8\xc0\xd887T\xe9\xdb\xbcu\xcd\xca\x9b\x932\xf2z\xdf\xa3\xdc\xb5_\xa5\x1a\xaf7\xa5\xa6\x0fi\x99\x8ee\xcdJMu2}M\xbf\xaa4\xda\x0bm\xadl\xd6{\xd7\xaaqU\xd7\xd6\x8aa\x0f\xfa\xd7\x8a\xc5;k]\x1b\x9e\xb2\xab\xa2\xae\xc2Od~\xf6u\xd5\xb7\xb6r\x8d\xb2\xcf:\x16i\x0f\xa7F\xb9\xee\xfe\x8e\x8dR\x1b\xaf\x14\x0f\x84^\xbd\xa7\x1fu\xf4\x1dq\xea\xda\x15\xe3WR\xcd\x0c\xcfIf\xe5X@\xd7\x9e0\xea\xe8\xdd\xa4(\xd5\xb9d>\xa6\xe1\x12\x0d\xfc\xfaV]\xedk\xd4\xeb\xe9P\x07\xbe\xd0l/|n\x88\xe5\xa0[\xe2P\xcf\xc4\xa7\xed?\x93O1\x970~S\x16{p\xca\x185\xb1\xbd\xb7\xebx\xec\xbd\x9e\n]\xdf\xfdWs\x8e\xe1\x04J\xc1K9'#\x0e\xd9\xbf=\x7f\xf7\xf6\xeck@V\xfcx\xc5\x97)\xf13\x9cY\xc2\x1f,\xfd\xf4\x0b\x0b\xfc\xc0n9\xe9pR%v\xa1\xe5)\xcc\xec\"\xfe\x12'\xb71\xb0g\x8e\xe5\xc0&/\x85\x95\x9c\x82\xc52\xfe\x89'\xe5)f\xe3\x99b9n\xd9\xe5U^\xa4\xe4<\xf7\x83/\x17\xa9\x8fQ\xc6\x0codk\x19)\xee\x01\xad\x10\x9fe\xb4$\x86\x0d\x14\xc4\x87\xc3\x9f\xd1.K\xe9\xcd\xca_iK|\x0b\xd6 9\xedOj\x8c\xbb\x90\xd6_\x8a\xb1\xb6\xae\xec\x1b9\x1b\x01\xce\xd3&Xc\xd0G\x0c\xc9)e\xd79 .lT\xc1\xfcq\x1e0\xe1\x07\xa3\nM\xd3\xe1(\xa1\xb4\xd6\x8e\x83\xd3%\x8884E\x91\xa0\xd3\x94*>$\xa5\xff\xc8$\xb6wv\x07\x8e\"h\x15\xbe\x83\xf8\xfe`o\x88\x96W\x07{#\xb5\\\xe5j\x82\xe5vx\xb9]\xfew\x8f\xff\xddw$w\xf1G\xecN\xf1T\xe6\xaat\xe9:b{\xd4Hu\x11r\x13\x08\xf5\xb90\x8dP\xa5\\E\x15\x103\xf5\xe6L\x14NX\x0c\xaf&\x92\xc8L\xd2-\xd1\xd3\xb61\xaaeso\x1af+\xca\xc82O\x0fo\xb5\xf032\xfdD\xe6a\x963\x05\x08Z\xeeNbs\x14\x89\xc2&\x8d\xa0\xec\x0f\xf4Y\xdc\xb4\nJ\x99\xaa\xdd\xbb\x12\xcd\x8a\xa1\xa2\x01\x8b\xf6\x05\x8b\x1c/\xbdy\xc3\xcf\xb6\xc6'\xe5\x0b\x17\xeaq\x86\x9a@\xd4\x04\xd4\x14\xe1\xfaz\xc1\x03\xa5\xfc^\x9e\xfa7$\xcd\xc8\xc5m\xf2\x91\x96\xb3\x89w\x95\xfb\xe9\x9c\xe4\xb4+.dJN\x9bf?\x02\xbd\x18}\xad\xbe\x98\xe6\x97\xd9\x99\xc8\x1dj\x14\x03!\x9e\xa3|=\xa6\xd6@\x05\xb8\x00$\xd3M7#X\xd2K3\xfaX\x1d1@]\xe6\xd1\x1c\xff\xcc\xb4H\xd1\xc8\x85\x99s)PH\x95\xf1\xb7-\xef\xce\x8f\xf5 \xa1\xfb\x9a\xafj\xcd\xc0\x1f\xb3\x84\x93o[\xc2\xd0 \xc8U\xdf\x05\xadB\x80\x16\x9a\xa9\x0bw\xa0I\xc6\x04\x1c\xae\xd3\x86\xce\xd7\x0f\x82bYD~^.\x85W\xbcM\x92u\x19pb\xf0\x83\xa8\xd5R\xb2\xad\xfa\xf3/\xe1\xea\x02;\xde\xab!U\x15nj\xe8U\x98\x92 _s\x14\xab\x9e\x95\x9f\xc59I\xdf\x12\xff\xc6\x00\xa6\xd2\xb4W\xd7R\xb5\xed\xaajlf\xcd;\xe3 ]L\xabF\x7fRO\xf1\xe97\x1f\x8d\x86\x93Q\x1fy\xaeyb\xf2\x88\xceC\xdd\xc9\xa8;I3\xc3I\x1aUI\xa6~Ws0a\xcc\xf9\x86\xc9\xd1\xacK\x8c\x04b+\xd9\xa1G\xbe\x92\xa0\xc8\xa5y{\x13\x7fH\xa7\x84\xd3\xedh\xfb\x95}$i\x86\x1b?\xb7\x193&\x13\x94\"\x0f\x91\xdd\xd8\xdd\xf5^\xf5f\x8f\x11\x81n\x0cZ+\xeb\xcd\xb9\xb3\xca\x86\xad\x95-\xfaVfy(\xe9\xf4\xae\xd2$A\x93\xaa7\xaf\xea\xf5\xd6\x17\xd2M\x03\xadH\x1e\x00\xcdF\xd8\xcb\xb3\x1b\x12\xe7\xccl\x01\xe7a\x0c\x89\xa7\x7f\xd3D\xf4\x8dr\xd9\x0b\xee\xde\xa7\xa9\x83\xbfk\x9d\xb2\xa2\xa4\xdb\xfa\x19\x06ku\xe51S@ZOw-\xfcR<\xd6\x1cD7\xdce`\xd1H\xf4I/;\x9a\xe4,\xfbh\xc4\"\x81\xfd\xfe\xe08\x93\x10#H\xe8\xeb\xc2\x94_\x8d\xf3\x81\xd9\xebd\xda0b>\x1a|z\xd3p\xfa\xb1\x1a\xbc\xeeY \x866\x00J\x84o\x0f\xa3|\xa1I\x8b\xb4=\xa3\xe4C\x9f9\x00)6\x84v1\x8b\x0b\x835XI\xfc2\n\x83/\x96>\x90B\xa3\xdcK\xc6\xe6\xf6(\xfe*)\xae#\xd2\xb7r\xa9t\xff&\xde%EF^%\xb7\xf1:e\xd7\xac\xfe]r\xb3V\xd95\xab\xff\xbc\xea_\xb2\xbbj\x90\xf4t\xf6\x06\x92\x8a\xfeu\xc4\x12\xbcbT\xc0\xdc\x05\xeb\xba\xc8s\xb6Cy2H+\x8cWE.?\xc8\xd0\x14K~\x92\x93\xaf\xb9\x9f\x12\x9f?sZ\xbc\xa8[#s\x88K\xf4\xb2\xe98\x05\xa0\xea \xc4\x85\x87s\xe3\xcd\x03\xb3\xceV]'DDJ\xf59\x8bY\xed\xc8b:=\xeeH\x8dx\xa8T\xf2SZ~\x92^\xb6a\x00\x96/\xe8\x11H`=\xb4\xc5\xf9\x8a\xdb0\x8a^\xd5Z4=g\xed\x9bG\xae\xc7AX\x1dO\x81\x94N(tz\x0c\xfey\x14\x95lC\x17\xd5)\x98<=\xe0\xeby\xbc\x15\x12[\\\x14O6\xfcpc\xb4\x82\x89&\xf1\xe5$\xbflC\x8ab\xfcf\xf0\xeb\xc4\x06\xe2B\xf8\xa4\x86i\xd0=\xb7\xb9\xa1<\x87)\xef`\x8f=\xf1\xa0J\x90\xf2\xd4\xe7\xc7{\x7f\xca\xbb\x84g\xe8\xf2\xa3r\xc5H\x83\x9a\xfd\xa1\xdff\x7f(.a\x87\xe8O2\x03|p^\xba@O \xda\xc8\xab\x8dF\x1e\x83\x19\xf2\xccv8D.7\xa4\\\x91~q4\x11K\xf3 \xdf\xdea+\xbc\x99\xebU\x13\xdefR;\xc0\xbe\x05\x1a.X!\xba\xd2$ Y\x86U\xffo\xdaHW\xf5b\xcf\x04M\xe8\x94\xfc\x01d\x88%\xe1\x14V0\x86\xa9\xe32\x80Q\xaa\x0c\x93\xb1\xfa^JP\xd5\xfd\xd2/\xe6\x8b\x9c\xe9\xc2[\xbbyu\xb5*\xd29\xe90\x81\x89*S\x0fc=\x12\x91\xf4\xc2\x8f\xbf\xf4\xcb\x8f\x1d\xd5\xeb,\xef\x0c,!\x0b\x01\xf0\x8d,a#\x85\x97` \xd5$A\xfa\xe8:7!\xb9\xed\x9aK(\x83\xe9\xd1\xd2U\xd0n\xbc\xd5\xaf~1\xfd\x89\x16e\x82\xf0\x99\xf4n\xc3x\x9a\xdc2\xcb\x81\xb2b\x8d\x87%H\x87P\xeea\xe2\x85W\xdcKM_\xb8<\x0eO!\x16!o\x7f\n\xc9-\xc6t\xe5\xfe'?\xb3\xc6\xc7\xc0z\xd1\xdc\x85MffJr?\x8c\xfa\x00\xac\x04\x12\xfb\x84\xb6\xdb\x199\xbb5B\xa6\x0b\x89\xda\x16oCRZIy@\x1bf\xa3\xf8\x85\xe7\x17s\n5\xcc\xa3e\xfb\xcc\x0bT^\x94\xfe\xb7/J\xb5\x93\xcb\xe4\xa6\x13_\x10\xcc\xa7\x1e\xe4o\xe2\x9c\xa4\xb1\x1f \x01\x1d\xdd&\xa8El\xdb\xae=\xc4R\xe5t\xe8\x9bi\xab}\xe1w\"\xd3\xbaF\x9e{\xff\xae\xdd\x90\x92\xbe\xde$#1C\xcah\xd7\xac\xc7?\xbdTS8\xa9\xd5\xf7\xdb?nH\x8d\xbcLVwi8_\xe4`\x07\x0e\x8c\x06\xc3}\xf872\x85\x9f\xfd\xdcT\xec\xefdz\xcb\xea\xabl\xc5\x02\xbaz\xd1E\xb0,\xff\xe3\xf6\xffQ}\xdc0\x1f(\xfa\xcd\x05u\xab\xd6:)\xa9D\xbd,\x91G3t\x02\xc8\x14\x16\xe1\xd9\xbe\xa5\x10\x17\xcdh\x95-\xe1,\xc4\x86\xafl\xeat\xf49plo\xcc\x9f\x0c\x92\x90\x85\xcbaR3Q\xa5$\x958\x81P1Y8\x81\xd0\x01\xc2\x9c\xfe\xda\xa8\xb32}L\xddb+u\xca\xaf\x13\xcf_\xad\xa2;\x9eP\xa9\x95\xbf,+\xaby\xc3\x86z\x82O\\\xe5D`F\xa0\xd4\x11\xc6\xc6\xa9\xc8\xcb\x93rG\x17\xde\x1f\xff\x9b\xe9G\xc2\xf2\xceZ\xd0\x1aKR\xc6c\xacy\x814\xeai0\x92\xd2\x85\x0eGk\xd7\xb4\xa2-x\xb2\x9e\x9e\xfa\x81C9\xc7\xd8\xb4(\xcb\xade\xf7\x95T\x9e\x0f\xf6zV\xc8\xdc.\xb8\x0f\x8a\xe3\x9e\x1b:\xd5\xf3?\x81A\xaf\xda]\x16*\xbc\xde\x9a\xe8i\xea\xc7\xd3diw\xfan\x18\xbak1\xf36\xdb\xf2\x82$\x0e\xfc\xdc\xae\x85\xc4\xc74\xc6cJeX\xce\x95\xe5\x82\xbd\xb9\x19\xc3&\xa4Ne\x0e\xb1\xb3\xff\xf8\xe43\x8dh\x06<\xb5e\xe39Sp\xec6\xe6\xcb\x07\x83\xd5|\x05\x8d\xdcc\xd9o\x87\x83\x81\x03\xa7\xfa\xd2\xd0-ZF\x94V\x06Y\x0d\xe9\xf2\xdd\x188.\xa46\xe5\x9d\x13\xa7\xdd\xd0\xdd\x14\x8c\\\xb6v\x7fh\xb4g\xcdInQ\\\xc1\xacW2q\xd7t\xfc\xb2\x9e\x07\x94aKR%\xdc\xb4\xc9\xf3\xcbBw\x0c^7\xe5\x0cE\xb2i\x0f_P\"\xf1\x11KTsP\x89\"\xeb\x9a\x17\xc7e\xce\x88F\\\x9f>=\xc1\x9d\x11\x9002l\x9aY\x94$iW\xef\x0c]\x0b\xb3\xf7\xfe{\xf4\x81\xd9\xc44\n\x03\xe6\x12\xc3v}\nc\x88\xd7O\xe8!\xe1\xa4Q\xaf\x87J\xe3>\xc3\x99\xa6\x91\x1b\xb4\xc4qn\xf4\xc1 \\R\xcaK\xddh\x98\xd6\x88\xcb\xd4\x93\x9d\xfe=\xd1\xb0n\x9aO\xea\x9d\xa91p\xf2\xa5\xf0\x8c\xba\x05\xd9\xe7\x0c&\xd5\xa9[\x92ofC\x08X\xe3\xd05\xef\x97\x7f\xa0\xe7\xaa\xd9Gr_\x9f\xc8b\xcf\xe4\xc3\xd9\x89\x0eR;Y?\xffZ\x97\x98gO/\xe69\xd0Iy\x98\x87Y\xf3\\\xc4A\xd5\x1f3\xbd\xff\xb0;\xc7\x9e\xd9\x14.cF<\x1ao[\x96\x94\xdeGk%\xcb\x82 \xb9\xd4\xb9\xf7\xa2\\\x7f`\xf0\x06\x8f\x1a\x11\xd8C\xb3\xe7\x1cH\x82']8`!^\x9ad\x97]\x84\xaaT\\\xe3%\xe72\xef<6\xa6f\x02\x0ds\xc21X\x1f,\xd8\x84\xcdMM\xf2oq\xddj\x93l@\xe3\xdc\xc1'\xad\x92\xf9\x99H\xeb\xa2\x8dfB\xaf\x7f?\xfb\xdb\x184\xf6#\xef\xcf\xce^\xe9\xd3\x17\xce\xfc,\xffw\xa2\x86\x873mg\xcc\x1a\x90\xc8A5\xb5n\x0b\xcc[]\x9f\xb6\xf2\x14\xacs\xca\xfdX\x1f\xd1X\x9f\x98e\x1d\x1b!NOk\x04a,\x97\xd5:\xf4\xdaj\x97{lT\xd4\x9bu\xd6R6P]_\xc4\xa5\x9fLq\x86N\xd2K/lNl\x13\xf2s\x92\xffL\xfc/\xeb@\xfeQ\x00\xd90\x84H\x84&<6\x86\x7f\x088zi\x05\x92\xf8uJ\xc8o\x9dBn\xa8*\x8f\xd0\x1e\xd4\xa3\x8b\x9b\xfe\xc2\xd8vO\x9e\x80\x00\x13\xfd\x1d\xd8u\xb6K\\:\x02\xb0\x8d6c\xfc\xee\xef\x0fe\xb8\xe77\xd9Y\x19yC\xfb\xf5Z\xb4\xc9\xef\xdf\"]\xd6W\xadw{\xcf]\xb0\xaa\xc8F\x0d\xf7w\x8e\xf2\xe4xG\x947\xf7^\xbe={\xfe\xe9\xea\xc5\xdfPs\x847\xf8\xeb\xfd\xd9\xcfW\xcf?_\xfc\xf5\xea\xecS\xf5\xe0\xfc\xe3\xd9K\xfa\xe0\xea\xc5\xf3\x8b\x97\x7fm<.\x1f\\\xfc\xf5\xd3\x87\x9f\xdfkJV/J\xc5\x05\xedCLn/(}\x1b\x9f\xa5\xed\x9eg|u4\x97\x0e\xc5A\xda\xa8\xcd+\xff.J\xfc\xe9\xb8%\x83$\xd4\x89y\xb5C\x18/\xf3[z\xa59@\xca^\x91\x8e^\x9c\xafH\xf0\x8d@\xc9\xbe\xbd\xf9o\x06\x81&\xbe^\xef>\xbf\xba\xa6;\xd7j2\x01\x0d\xc4]~\x9c\xadH\xa0i92\x1f\x02\x8dO\xb5\xad\x06\xbac\xa5\xfc\xd4/\xf2\x85\xa6\xd5Y\xedT\xc2\xd2\xb8\x80\x95b\xab\xaa\x18;\xc9\xaa\x92W\xd7w\xcc-\xb37_\xb6\xaf2X\\\xc6\xaeK\xdcY\xba?3\xa5\xc0\xe5\xda\xe1C\xdaH\xed\xfb{\xb4\x0fa6?\xc4\xa1\xef*\xeasMfs\x7f\xc7\xe1\xec\x96\x0b\x16s?5E\xaf\xeaE\x98H5\x0f\xf4\xee\x88\xfb\x0d\x19\x0bO\xf7?\xd03\xb0\xfb\x03\xbd\xf0e\x7f\xb0\xdb7\xdc\xb1\x10nli\x98\xa1\x98[U\x01W\xd3\x0c0\xe6\x16W\xe2\xd6\xd7\\\x92r?c\\@\xb6s\x04\x9b\x9b9\x1cCl\x0c\xb3\x99\x1a3\\3\xafa\x92\xdb)f\xcfK'\xc3\xcbv)\"\xbd2\xd9\x0b\x98\x9f@\xa9[{\xccm\x0fO \xa9?\x9f\x13\x96\xfc\xaa\xf6p\xe1\xa3\xe5J\xfda\x86%\x8b\xbauK\xb6\xde\xdc\x0f\x07{}$c*\xd8$\x93\xd0\x13)_x\xbc\xb5u\xd4\xe4C\xb8\x94~\x12_\xb2\xfc\x83\x92\x19\xb0\xf6\xac\xd8\x1a>z\x8f\x0c\xba\x93\xd1kFS\x0d\xe4\xeaj\xea\xe7\xfe\xd5\x95\xb6_\xa9\x9d;p\n\xf1D\xc3:\xe7\x94u\x16\x8f\xc7`-\xfcla\xd1\x134\xf6\x96\xfe\xea\xd1\xe31\xb8C\xed7\xe2\xf2\x89\xf0v\x06w\xa8]\xfd\xc6\xec\x11\n\xd7\x84\xeeD \x9dlA\xde\xa5!\x85\x86.:\xc6)\xf86*\x93\x12\x9b\xe0\xba tg\x89T\xddc\x94\xb8v\xc0M\xee\xdbZ\xbd'\xde-\xb9^\xf9\xc1\x97\x8fIt7\x0b\xa3\x88\xab\xe4\xa7d\x95\x92\xa0\x99\x17\x14=\xdeW~\xbe\xc8\xb8=I\x15z\x99\x7fY\xde\x9e\xb0\xf4\xb3z\x06\x8f\xb8`\xb1dM\xda\xd8f\xb5p\x91\x9a\xf0tk\xc5>#^\xd4x\xad0\xd6\xad\xfd\x0c\xffG\xfa\xa8\x11\xc64\xfa\xd8\x9c\xad\x13\x18>R_\xab\x9a&\xd4\x07@w\xdd\xf6\x7f\xda\xa7\xe3\xc1\xfdd\xb8\xf5\xf4\xf2\x97\xe9\x8f\xce\x9f\xb7\xbb\xb6\x88\x01\xa3$\x95\xb1\x8f>\xef\xfb\xc6\x86\xfd\xff\xb3\xf7\xef}q\xe3\xc8\xe20\xfe\xff\xbe\x8a\xc2\xe7\x9c\xac=\x18\x03I&\x97\xce\xb0,\x03\x9d\x1d\xce\x06\xc8\x0f\xc8\xcc\xce\xaf\xc3\x971\xb6\xba\xdb\x1b\xb7\xddk\xab\x9b\xb0\x9b<\xaf\xfd\xf9\xa8$\xd9\xb2,\xd9\x86\xb0{.\xcf\xd7\x7f@[\xd6]\xa5RU\xa9.T9\xd3\x18\n\xc9`\xc4*{\xf2\x04\\\xd5EI\xde\xf0A\xb2\xb1\xc7M\x87\x0b\x1e]\x80xX\x80\xc0\x1f`k\x97\xff\xfa\x0f\xf4e\xcfi}\x8c\xc5\xfb\x80\x99\xd2]L\xf5\xcd\x82\xed(\x17\xfa5\x8a\xe9\xa2\xf9z\x8b+\xd8\x18\xf1\n\x86\x03P\xba\x82*\xae}\xc8\xa1\x83\x90\xd2\xb1\xa1`\x1f^Y\xc8\x9dg\xfa\xfd\x99 w\x9e\xe9\x0e\xc6\x05V}\xa6\xd3\x99\xa5\x99*M\xc5%\x81^\x0d^\x18\xb9\x85\xd7&\xa4S7\xf7\xdats\xea&Zj\x8c\xa9\xa1\x96:\xc7\xd4\x95\x96\x8a\xe1\xdd\xea%q\xb9\xe1\x91\xe2m(\xfc9!\xb7W\x08vk\x97\xbb\xe3`\x7fQ\x97\x8c\xbb\xacqw=\xae\xd5\x947\xca\x9e\x84K\xb5X\xee\xf1\xd01j\x96\xf7E\xbeHJ\"\xb3%\x01\x0f*N\\^_\xd8\xc8|A\xa8Z_\x88YV\x8d,\xbf\x90\xf0\x93\xd6\xec\x8ao\x0fw=\x08ZK\xe3=_\xa62\n|c\\9r\xcf6\xfd\xbc\xd8\x9d\x8b\"\xf4\xc1>\xa4n\xc6\xdd\xdbh\xd7~\\\x81P*)\x18/\xf7\xf1Z>\xea\xbc\x967\xac\\\x9b\xa6\xc5z\xa6\xc3\xea\xc1\xe9\xb4T\xb1\x1cVE\xb5\xca\x96j\xe2a\xd5\xe0\xfa[\xaa\x98\x0f\xab\xa2\x82\x8fFn\xa3\x8a\x81\x8235\x05\xf2AV\x0d\n\x89\xfd\xecu/\x95e\xbf|\xce5\xaeG\x88nF`\xb4%\x13}W\xb4arq\xaa\xf49F\xb4v\xbf%T\xe1\xd8\xf2\xd5\xce\x90Au\xf2\x0d;\xdc\xb9>\x1e\x82\xe8[\x97x^\xcdJ\xc8x0l\xf3f\xf0\x03$o<\x94i\x91I\xee\xd2I\xb6\xb9y\xe5]\x19\x07\xcf\x8d\xf2\x90\xd7\x16\xf4\xa8\xa6_?h\x02\xccr\xfb\xfaZ\xb45\xb4\x0d\x1a\xacIQ&\xdc\xef\x92PE\x92IA\x92\xc5\xe4\xf3\xd9\xd4u\xd6;\x81\xe3u\xe7\xd8e9\x9e<\x11\x02:s\x8eW,\xcf~\xcf\x85cF>\xd3\xcb$\xd2n\xb1z\xf4u\xfaUX\x18V\xad\xd5X~\xefDa\x9a\xde\x84\xd1'\xa7\x92\x1eb\xf8Y\xb8!\x8aZ\xcb\xef-\xaa\xc5ka\x07\xc7c(\xb4\x94\xb3\x8de$\x8e4\x06F\x92\x0f\xa2\x85\x9d\x1e+_\x8b\xc2\x97|$*\x08\xe4LZ\x8d}\xa0G}K>\xed\x1a{ie\xf5\x11\x1aT\\]\xdb\xa2X&\x1f=\x10\x89\xfat\xe9w\xc9\xe7Q\xbbjU>\x93Ooo\x9f\xffk{k\xd5N\x93OW\x87\x07\xd9b#.D\x12SRS\xee\n\xb6\x90\xb3 \xb9\xb9B\xc8\xd0\x9e\xdc \x1e$\x93ps\xf3\xaaa\x8d\x10\xf6D\xe5\xfd\xe6YQ\xcd\x03zt\xfd\xbf\x0e\xbd\x81\xd68<\x14\xe3\xd5hL=wU\x07\x89\xdf{f\xcdx\xbb\xa6\xb5\x89\xcc/\x84\x97E\x93<2\xe9;\xb2\x92\x0c\x91\xe0$\xbb\xc2s(S\xfc\xc2u\xd9\xb5Y\x84\x10y\xf5]\xa9F\xfe\xca\x83i\x91/\x00\x9d\x83\x85i\x9aG\xca\xcf\x0fY\x19NI+\xe1\"\xcdo\xb5#\x81\x91\xa3n\xe2\x16\xdc\xa7\x0c\x0d*w\x94\xa1\xe7C\xe2\xe6<~b\xc8\xdb\xea\xa7G\xf0h0x\xce4\x1f\x0c\xceA\xe34\xc8rq\"\x88\n\xcc\x94\x8biRX\x0f\xf9\x1c\xdc\xb3\x8b\xbdg\x97\xd6\xc5\x8e\xeeI\xb0j\x9b{6I\xae\x0d\xc1\x14\x98\xc2\x05\xc2>\x14\xc14\x91Z\xc1\x8c\x86\x13\xaf\xcaoT\xb07\x8c],z\xaf\xf2\xe9?a\xec\xf5\xd2\x98\x16E\x01\xbe\xff\xc2\xce\x15\x01\xeb\x81`G{\x05\x87\x83h=u#e\xee\x8b\x97\xdf{\xae3\xcd\x8bq\x18\xcd\x9dA\xa8\xa8O\xe3\xf5\xd9\xaeY\x10\xf1\xcc\xe2\x06r\xf7\xb5.)\x10\x82\x88W\xaa\x18\xd7\x1dL\x8c#R\xc3\xf8$+T\xcfL\x8d3\xdb\xbaC\xfe\x01\x9e6\\\xe5n4\x84\xban)\x9c\xc3r\x97\xb1D\xb0/\x0c\xc2\xcb\xc6\xd1\xf5T\x04\x8c\x94\x8c\x0dFO[\xa1I\x13\xe7\x0b6\xd0n\x08\x93\xc3J\x7f\xd3\x89\x1c\x11\x93KI#2\x04\x97\x92v\xebx\x9e\xcf\x0d\xe1\x1b\xa3\x82Z\x91\xc6\xe0\xc6\xb0\x19\x96%kgP\xc5\x9fI\xfbs\x1d\xa2G\x8fK\x0c%\xdb\xfen\xee\x96\xac[ld\xb5x\xf6\xab\x17\xcc\x86\xf2\x83b\xa9|\xdd\xef@u\x0di^\x15\x945\xf1@\x06\xe6\xc5I\x1b\x8b\xf3LY\x1c\x86\xceh\xa5\xec\x03#H\xc4=\x88\xf8\x8e\x16\xe8\xcd\xef\x19\xb7qS\x1a\xe5\x1fqA\xd3\xba\x0f\xca\x17\x0d\x18$ \x945 \xac\x0c\x80P\xb6\x00\x01},\x98\x16\x1d\x05\xd3\x86%G\x9bd\xc3J7A\xc1\xa0\x01\xa4\x82B\xa9\xafv*V;\xf5D\x0c\xbd\xe8~(\xa9\xc6\x12\xadp\xb9\x02I<5_\x01={f2\x18\xcb\\\x8b\xb0rwW\x17nrt\xb7\xfbB\xc7M\xdc\xa7D[R\xa9\xaa\xbd\xb8TS\x82\xd5\x87\x88\xbe\x05\x97&\xb8\x8e}\x98\xfb\xb0\xf6a\xe1\xc3\x0c\xf6`\xa9\xaa\x89\xdbhU);n}dD\xa5Y\x94w\x87\xc2\x06\xde\x11\x06\xd9Oa\x04:\xbae\xcf\x0d\x92\xe0\xcd \xb6q\xc6\xb3\x1e\xe3\x8e\x84r8i\x99v\xb0\x1a\x13wf\xd4\x19E\xba3\xe6\xa6\x072F\xef\x1b\x88\xe1\x0fp\xf3\x06n67\xcd\xd46\xab\xd1]\x08G\xacwn\xe8\xce\x91T\xbd\xb9\xf2\xf0\x8em.\xee\xd8\xee\\L\xf3P\x06\x81\xb7_\x0b\x1e\x0b\xb2\xba\x9a]4!\x1a\xcd\x7f\xcd}\\\xc3\x1eTq'\xde\xc0\x066\xb9F\x8e\xc3\xf5\xbc \xce3b\xb8\x14\x06\xb5\xb3\xb9\xbb\xf6\xe1\xce\x879\xb7\xc5\xe3w\xc4\x03\xba\xf6\xd5\x0b~<\x1f\x1f\xfc\x99\xc7j\xa5\xc1\xf9\xf8\xf2\xc3\xf9)\xec\x89\xdd\xf6\x8d\xe7\xb3\xd5'u\x11\x1c\x8d\xdf\x1e|xw \xfd\xfe\xa9ww^\xf5\xf8\x9d~)\xfcL\xbf\x12\xff_\xdf\xdb\xdf\xb4BR<\xb7\xdcm\xec\xe8\xdb<1\\\xf1\xdc\xdf\x94\xd1rH\x85Fm\x8aD1pD\xee\xc5\x0d\xb1\x18\xddd\x83\x00\xad6a&\x1f\xec\x96\xd6+W\xa8\x869O_\xeaGCU\xcchc]}\xb5-\xdc\x0e\xa7}\xd9\x7f\xdep\x05\xa7\x07\x82\xc9\x8cxp\xf8\xda \xb39FQ\xde\xe2(\x10\xa6I\x16\xa6ig\xd7:;\x0eP\xb9&\xeb\xcf\x08r\xa4Q\x9a\x97b\x00\x9d\x05\x9aF\xe6\xdcu\xc5\xe0\n\x86\x0c\x0e\xba\xe6\xde\x93\xa8\x15{\x1a@\xba\xd2\xb0\xd9)\x81d-\xb0\x11s\x03a\xdbu\x8b|V\xed\xab\x05\x90\xd8\x81\xfb\x83GM?\xae\xff\x93U\xbcNh\xe7u*\xcffA$\xa0\xf8\x80\xbaa\xa7+\n\xae\x01\xd6\xa3T\xc5\x88,\xe7\xc9\xdfV9}\xd3\xe1\x8b\x83=7\x05 ?\xd9\xb3\xf0\xd6^\x0di-\\,\x1f\xa5\xb1\xd7C\x1a\xfb\xb7\xcfO_>Fk/:\x14\x0d\xa1j-}\x94i|\xd1\xa3b\xc8\xdb\x9a}k[\x83t\xd8\xa2<\xa3I\xb6j\xdf\x0c\x81\x95\xc5\xe3|0j\xf6\xbb l2\xfcX\xaen\xf8\xb5\xb5\xbb\xf2!\xf4\xe4e>\xe3@\x19+\xbc\xa9#:s\xe5b\xaf\xca\xfa\xf7Y\xc9v\xe50\xd2C\x0c<\x92\xbaH\x83\xea2\xfa\xa67\x851\x0b\x852\xb5\xd9@\xaf\xcd\\\x96\"\xbf\xce@ [\x92\x96FId\xb8\xb5\x9d\xa2p\xa1\x99\xb6l\xa3\xabvx>\xf6\xd0|yp\x93\x17t\x04N\xc8\xfe\x1b\xd0\x1f\xcb\x92%\x0b\x0c\xe11\xce\xe2\x11\x94\xae\x13\xca\x04\x92\xc5\\\xff\xb9\x99\xd4]\xcb1%<\"H\xb3\xaeD&\xeb5\xd6\x1f\xba\xeb\xbd\xa0!\x1b\x89Zg\xc9\x92\xf4\xfax\xa2\xb1\xae\x1f\xd3U1\x02\xe7&]\xe9&\xed\"\xc3a\x98\xbdO\xc3\xbb\x118Q\x98-\xd3\xf0\xae3\xdb\xe5\xbc\xc8W\xb3y\x9d\x9b\xf2\x04K\xa1y\x98\xcd\x08\xcb\x8c?,\x99RT\x01w\"\x8c e\xce\x92/\x96y\x99T\x0b\xe6Du\x82uu\x94Bb\x1e\xd5b\x1dS\xa6\x14\xfc\xb0\x8cQ&\xa0\x96\\a\x9a\xadhF\xc9gzB\xb2\x15\x16\xc2\xb7\x05\xc9V\xb6\xecK\x9c\xf8|i\x9b\xf5\x15v{e\xe9\xa9\x12\x1ek\x04N|\x93v\xcc\xe1Q\x11\xceX\xa6\"\x9c\xd93\xf0\xd9ey\xac\xd3\xca\xb3QRT\x19)\xb1\x80\x16f\xfd\x9cP\x99\xf3sb\x1bG\x11\xce0\xc0\xa3\xc8\x99\xb2\xdf\xf6\xacg\xeb\xaa\xf5|\xdd\xd5\xb8\\w\x96\xb3c\xc1\x8f\x8a|\x89\xb9\xf2\xa5%\xc3\x8ao\xd7\n\x9ec\x91\xd0\x05\xd7\xe3\xc5\x92&\x84\xcd'\xe1\xbf,\xd9\xb2\xa8\xb8[R\x9eQ\xfe\xb6e\x8dE\xb6\xd8\x9a\xa5(r67\x84\xfd7gy\x9bG\xabr\x04\xce\x94\xfd7g9\xce\x96\x08x<\x02\x981\xcb\x9f\xc9\xddQ~\x9b\x8d\xc0\xf9D\xee\xe2\xfc\xd6\x82\xca\xfeL\xee\xde\x17\xa4,y\xbe%\xfbi\xcd\xf8a\xc9s\xad,\xab\xf0\x0e-\x93\x19\x0f2\x92f\xca\x8cs\xe9\xca|Bh\x18\xab\x05\x16\"\xc1^H\xc2\x0c\xcb\xdf\x013U\xe0\xb8\x118\x0b\xf6\xdb>\x07U\x108\x99\x95qW\x1dY\xcfp\xee1gn\x9b~\x9e\x91\xef\x03\x9e\xd3\xba\x11D\x988\x99\xd16\xbb\xef\xc3\x121\xdd\x92\xfd\xb7eY\x95<\xcb\xaa\xb4e\xe1G\x89\xfd\x1ca\x19\x92l&\xf2$\x99\x05\x19\xbd/\xf2\x99\x80\x9b\xa5\xf8i\xcex\x1eRRm\xcb\"\xa4\xa4kKr \xdb\x08\x9c\x12\x7fX2\x11\xf2 \xb7Y\x89?\xec\x99\xf80J\xfe\xcb\x96-\xe5\x91=\xab.\x962\xa5\xb3\x9f4LS\xde\x07\xfe\xcb\x92mU. b\xec\x92\xff2g\xbb$\x9f\xa9\xdc\xd1T\xfe\xb6dM\x16\xa4:\xf3h\xb2 ]\x87\xdde\xbe\x8a\xe6\x87a\x16\x116\xa5\x94\xbdE\xf8\xd6\x91\x9d\x1f0\x98\xd7\xde_\xf6U\xec\x17\xcci\xdf/\x98U\xeeX\xcc\xdb\xb1e\xf1\xda/Q\xa9>Z\xa5\xd4d_3\xcdX\xd1\xcfy\xbaZ\xd4P\xb7\xc6\xd7\xae\xf5\xfc%L(\x87\x96[\xfe\xcb\x92mNp*o\xd9\x7f\xcd\x04\xb4Y`\xcex(\x1e\x85\xa6\n\xa2w|\xe4\xc0\xa6\x90\x18\xb9\x8d8\x04^P\xa6ID\xdc\xa7^\x93\x1dX\xa3j\xdb?\xbe\xa2VE\x93\x94>'2\xd2Z\x1d\xa4\xb0}\x990 p\xad\xa9\xa2~\xf99:\x8f\xf9)\xcc\xe2\x94\\\xe6\xcbwdMRw\x1d\xcc\x1b \x9e\x0f\xeb\xa0]=\xec\xf5{ll\x8e\xa2$t\x9ca@\xcc\xbe\xae\x19\xdb{\xf2\xc4\x98\x1e\xd4\xd5\xb6\\\x01j\xb3X\xb6\x9b7\xb5.5\x88\xdc\x0dc?\xbe|\x01\xe3\x87\xa0\xaa\xdf\xed\x0e1\x97b\x81\xcb|\x80S\xd1\x86\xa4\x98\xfa\xd0\xed;O>b\x00=j}\x95\x16\xde\\D\"\x99\xcc\xaf`\x0f\x96\x9b\x9b>D\x13\xf6&\x82\xfcV\xaf\xed\xe5\xe6\x11 `\x0f\x92V\xc0\xc6#\xc20%\xc9\xa2\x84\x94\x13r\xd50f\xcb\x87\x08\xb3P\xcb\x9d\xed\x1c\xabu[\xa1\xc7\x99\\\x89X2+\x1e\xa7\xd8\x91{\x9d\xcb\x86Wht/v\xbd\x07\xfbfp\xa2E\xb8\xfcqu\xc3\xd6\x11?(\xb5\xf8\x12e\x08\xb3\x9d\xd4\xe5G\xfd7\xd5\xa8\xd4 \xaa}@%Gg'H~\\\x88\xf3\x96W\xe4TGqc\x02\xe4\xa1\x0c\x1b;\x9d}\x16\x01o\x95\xf6\xaa\xea\xeb:\xee\xd9cC\x0d\xc6\xc2\xbf\x1c\x9f\x1e\x9d\xfdr\xfd\xd3\xc1\xe9\xd1\xbb\xb1\x1c\x0bR\xd4r(x\x86p\xbe\xbb\x1e\x9d\x9b\xba\x92\xde\x16\xa3s\xef1\xbc\xb7\xa2dUEf\xc1}\x96\xf2\xd8\x17_\n\x01 \xf3\x04\x90`uI\xe6\x08\x15\xd7\xc1\x93\xd5\xecO\x92\xf5\xf5\xa8U\x81\xec\x10\x96G\x1a\x97u\xca\x87\"\x10\x1f\x85N\n\xbeck\x98\xc0\xba\x1d\x9b\xf7\xd6\xb0\xb6W>\xc4\x93\xd5\x15\xef.n\xc7\xbdVHy\xe8;.\xf4Z\xfb\x03\xd5\x80b\x867\xa8\x9f-\x85bK7\x1aK\xfd8\xfdhB\xcf\x90\x8e\x88\xc86<4\xe9\xfbpF\xfe\xf2k\xcfA\x86\xb7\x17\xfa\xad\x1e+\xdd\xe9Kz-\x9c\x86\x9a\n\xba\x0e\xa2\x19\xfcm\xd2\xe3\x92\xf7$\xaa\xd3\x06UQ\xa0k|$+W\x85\xc0`?\x87\xe9\x8a\x9c\xe4YB\xf3\x02 \xba\xdeq*\xae.\x90T\xc0K\xdcu`\x984\x97\xed\x80\x0d\xcc\xb41\xed:|\xd8$\xac\x82\x82L\x0bR\xce\x95~\x95\x96\xfb@\xd3R/\xf8\x18\x94\xd2\xe8\xebzZ\x87\xecR\x1fm?To_-\x06\x08\x83<\x904\xc5\xd4Ur\xa5\xd1P\xb4\xe6\x94k\xb4^\x17\xab\x94\x94\xd7\xd7\x0d\xdd\xf0\xeb(\x8c\xe6\x04\x13-\xd7\x8b\x85Bp\\_O\x93,\xc6\xdcv\xaa\xa5\xad\xf7W5-\xc8\x04~\x8d\xb7\xb5\xfb\x06\xa8\xd5\xb1`\xb3\xe0ds3\xbbB\x85\x01\xae*s\x0fO\x83\xbe6\x82(_,\x93\x944\x07a\xbaB'\xa2\xfb\x06\x96\x83M\xa1\xe3hT\x0cQ\xc6)\xecI\xddn\xda\x8e\x04\x84\x13\x98\xfc~\xe3\xf5\x18\x07\xa8\x95\xa2\xae\xfe?\xd0\x07q\xaby[ OY\x92\xc7\xda\xe2\xae\xf3:\x86oD\xa9\xec\xc9\xd4)p\xd1!X\x86\x13!\x07G\xf9\xe0\xbe|\xd1Z\xe5#\xcd\x82if\x88M\xdd\x1a\xad\x0d\x1cB:\xd0\xf2\xa5\xa8a\x99o\x01\xa3\x11\x1a^\x12\xb1\xbe\xea>\xa3\x19Doq\xb5\x81B\xb5\x8c\x16V\xd1\xef\xc3\xa2$\x05\xb0\xe9C\xc3\xb2i\xbeB~\x1f6A7K\xd7\xf6Eq\x15L\xa5\xf1g\xebK\x98b$c\xfc\xff\xe5\xcb\x90]\xdf\x9c\x9d\x1b2\xcd\x0bb4\xf7k\xb9\xb1ZK\xcfx\xbd\x93\x94Hm\x9c\x8eI\xca\x1fs\x92\x82r\x89l|\xee\xc3\x8e\xc9\xf5!C+F\x13R\"\xd9K\x93C\xc4if4/\x0dS:\x82\xa4\x9e\xf2\xd6\xb6\xbb\xd7\n\x84SJ\x8a\xff=\x0b\xc0o~\xff\xa7-\x02\xc34\xf7@\x13F\x04\xa0M\x08\"/\xdb$\x18T[z'\xc10q8 \xc5cM\x02\xefA\x9f\xf2\x17\xcb\xd0\x0cJ\x8b\xae` \x8c\x00e\x06\xdc\xe3cs.\x86\x1dy\xf5Y\xd9\xd2\xa0\xe7\x87\xd9\xb0j4\xba\xa4\xda%fU!\xca\xce\x1e\xc3N8g]\x87E\x98\x853R\x8c \xc9\xd6a\x9a\xc4bg0\"\xc5\xb4'\xa0\x8d\xbd\xe9\x95:*=\x84\x13\xe6\xbe\xef:\xc5I\xd9Z(}\"\xdc\xeee\xf2\xfe\x17\xcc\xe5\xeec\xcc\xe5\x8cP\xde\xbb\x01jo\xc2\xcb\xc1\x9e\xdeB\x0d\xef\x15\xe1\xe9\xb6\xfa1!W\xda\x1e\xfd\xea\xdf\xdf\xf3{\xbf\xbb\x93\xce\xbd\xbb\xe6nC\nn1hq\xd6\x8e\x16\xc0\xc12/O\xc2\xcf\xed\xaf+\xf9\xb5\xfd\xa9\xc4OIy\x9c\xbd\x0boH\xda>x\x94\x8f^M\xc7\x9b\xf2\xa5,\xcf\x87l\x11\xd2hN\xe2\x8b(_\x92\xb2\x8e\x0dj\xfc\xbc\xb5\xe5\xb7*C>\x05{\x8bf\xf5x4)\x9d\x10\xa2\x14F\\\xed\xbe\xe1\xa3\x82\x1f 4z\x9ag\xfdz\xcd\x0fN7\x07\xa1\xca\xaf\xea\xecaq\xcf\xf3 \xdb\xdclCr\x15\x82\xfb\xf53\xe1\xdb\x11\xbd\x04\xb2\x9f[[V\xd2\x99\x0b{\xcc\xbc+\xea\x80\xb5\xbe\xb4u\xabP)\xb7$EP~J\x96\x97\xf9'\x92\xd9\xc3\xef\x80\xa2\x11\x0f\xfb\xdc\xc5\x19_l\xcb\xa4\xc3\x1e\xf7\x0cb\xfd\x9a\xc1\x16\x9ft\xbe\x06+}\xfeK\xff\xe1a\x15^\xdb\xa2`r)\xba\xeb\xfc\xdd\xf1\x8cq\xa5\\%\xb6r\xa7V\xaa\xd4w\xbd\xa8=B\x15\x02\x8f\"\xc1C]\xc7a\xc3\x17\x0d\xf6j\xa3\xa9\xf5\x0f\xd3\xb8m\xc8IL\xa1H\x9d\xc30\xfb=\x85(LSX\x10:\xcfc\xc830b\xd4\x96\xcb\x8d{\xcew+&\xa20S\xd8\xf5\x02)x\xd2no\xd0a\x87\x08\xe0\xe2\xe6M%\xf5^\x1f\xa4\x96\xc5H`\x1f\xb4\xaa\\\xf4:\xaf\xd8\xb1\xdd\x7f`}\x9d1 S\x14\xd5\x15jD8\xcdW\xb8\xc0\xb6y\x1b\xc1!\x8dd\xf2\x97\xedr\xedt\x19\xae\x9c\x87]+\x10\xe1\xc8\x18\xd3^\xdd\x9e\xa1\xe6\x8eJ\xd1?\xc7\xd9\xf4\xfeun\xfcs\xbak\x83\xe4<[\x93\x82\x82p\xfbKsX\x16\xc9\"\xa1\xc9\x9ap\xefON\xdf.\xd3\xd6\xb9\xe9\x0c\xec\xfb\x9d\xfb\xfa\xe5\xd0\xadpd\xd4w\xdd'\xb8\xf0\xf4\xf5B\xd7\x1f\x0dE\xfa\xae\xe7:\xc7\xe3\xeb\xf7\xe7g\x97gz\xd0\xd1U+jA\xe3s\xd9%\xc8\x02)\xcc\x12\x8e\x99\xdc\xdd\xef_x\xae\x93L\x8bpA\xf4\x86\xe4S\xe0\x05\xa0\xcdS+\x8f\xc2\x12\xa0I\x10#7\x97ix\x07{\xe0dyF\x1c\x1f\xa3R\xecx\x0d;\x17\xee\xa4\xb0,\"\x96\xed\xaf\xe1:\xe4VE#\xc7\xe7\xa4(\x0dP\xe3/\xa3\xbf$Y\x9c\xdfV\x08\xc3\x0b\xf2%\xc9\\\x1e*\xa0H(q\x9d\x1fx\xd1?T\xc2\xec\xb7{\x1c\xbf\xfe\xf0q[|r0?\x1a\xbc\xba\xc2\x95\x14 \xde\xbe\x81bk\xeb\x8d\x07\"<\x8b\x12oe\x92L\x8a+\xc3\x8d\xa4\x00\xcc\xd2\xd5\x0e\xc4\xaecE\xa0\x1eP\xa3\xb6Zi-#\x02\x16\xa2v\xe9.Kq\x8e\xcf\x8f\x17N\x91\xa0\x03t\x1f\x9a\x9f\x85\x93\xd3I\x88n,\xd1\xfe\x04=\x9fka\xd4\xa5\xe3h7\xfb\xff^D\xfa\x17O=\xd7\xf9D\xeeJs`\xdf\xdd\xdd\xfe83\x96\x8e\x17\x82\x86w\xf1\x07w(\xf9\xe0~>5\xd9$\x17\x13\x871\x11\x05\xd9\xfaky]\xce\xc3\x82\xc4\xd7\xd7\x8el\xd4\xfc\x0d\xef\xfb\x1f8\xa2\\\x8e(\xe7#\xfa\xc7\xd7\xbe\xf1\xd8\x10\xab\xa38\xd2\xf7\x9b\xd7\x90~R\xbe\x97 |6\xf5M\x04\x99O\xf3wy\x14\xa6\x84\x9f#\xbe\xe4\x9e'\xb0u\x82~\x07\xd1\xa1\xacsVG]B\xbb\xb2\x02\xcd\"-T\x18;\\\xc34%8be\xe9F\xc2\x12\x19\x1e\x008\xde5#8773\xd8\x84\xc2\xab\x18\x13F\xc4\xf7\x9dl\xd6\xbd\xf0\xd2\xe2\xea\xf7\xd9\xffx\xb6\xf7y\x0f\xa9\xf4\xe2\xe5C{\xfb\xa8\xa4\xd2\xee\xeeK/\x98\x9a\x899\x93\x07\x17\x13\x9e\xea\x1b\x87\xf9\xbe\x07\x95a6r$V3!='5A\xeeC\"\x03\x84\xa2\x03\xb6\xf6foz\xa25\xdd\xecH\x87\xc6\xcd\x8d~\xcf\xb9\xea\xf5\x80\xf3t\xd74\x03\x18{\xbdw-\x19#b\xcf\x04\n\xcem3X(\x03_\xf2\x18B\x82\xa7!\x0d\xdf\x11\xc6XI\xa0\x13L\x8c\xa5\xf9\xf2Eu\xd4\x9e\x19$a?\x86\xb1\x8cW\x04\n9ju\xcf\xc7=)g\x95\xec]}\xaa\xcb3\x11\xd5J\xa0\xd1*\x11e\x13\xe8\x8eVc\x1d\xbf\x81uy\xfa\xbdY\xd4\xf0\xbdM\xce\xd9\x07\xbe F\xefd\xc8\xbf5W|k\xfc\x9b\x03\x9b\x90\xa1\xbf\xdb8'e\xf6{\na\x14\x91%\x85\x82\xcc\xc8\xe7\x96\xd3[\x01\x11\x02\xa9~\xdb\xa6f[\x14\xa5\xc5\xfd\x9b\xd3x\xc6\xc3\x1el\x07\xdb\x9aH\xc9x\xe2:\xdb\xc1\xb6\x03\x13r\xe5jnu\xaa\xa3\xd6(\x80\xef=\xbe\xe9\xa4\xb8\xe2\xf6\xb8\xb0am\x03z\x8et\xd3\xfcn\xdc3\xe0\x11\xc5\x8d\x8c\xb4\xfd\x90\xec=L(\xb27F\xac\xda2Q\x16\xa2\xad\xd6 \xc9M\xa0\x9f\xefx\xc1\xf4\xa1k\x9b\x07\xfc\xcc\xe7\xec\xa9|\xe1\x81\xa1\xfe\xf1\x15\x83.\xd4\x19\xfe\xa1Gtq\xae\x91\xc4!xAs@\xdd\x1d\xd4\x97'\x90d\x1c\x93\xac0f\x95 c\x0b|\x1c\x06\xd3\xd65I\x1f\xac\xb7\x97DH\x8cf\x84*\xfc0\xef\xb6\xd9\x8d\x07\x0fXz\x7fT\xdf\xa1\xcd\xb5\xfd\xddFs\x90\xdf\xc1\x1fc\xc2\x05iI\x9e\xc19\x89VE\x99\xac\x89\x94\xb8\x92\xcf\x94dq\x92\xcdZ\xc5\xc2\x15\x9d\xe7\x05\xfc\x9c\x84\xd1\x9c\x94i\xb8\x86w9-\x17a\x96\xaf\xe1\x87T\xfe|\xf5\xfa\x8f\xb3E\x98\xa4A\x94/\xfe\xd0\xaa#M\"\x92\x95\x04N\x8e/\xb5oz\xd6\xcb9\xe6\x82w\xa2\x84{r|\xe9\xf5\x949\xcc\x97wE2\x9bSp#\x0f\x9e\xee\xec>\xdbz\xba\xb3\xfb\xca\xd8\xe5\x9e\xaa\xde\x93b\x91\x94\x18\x14,)aN\nrs\x07\xb3\"\xcc(\x89}\x98\x16\x84@>\x05\x06_3\xb6L9\x84\xd9\x1d,IQ\xe6\x19\xe474L\xb2$\x9bA\x08Q\xbe\xbc\x83|\xaaW\xcf\xce\x11(\xf3)\xbd\x0d\x0b\x02a\x16CX\x96y\x94\x84\x94\xc4\x95\x1e/Zf\xc04II .\x9d\x13p.D \xc7\xc36c\x12\xa6\x90d\xed\xca \xc8\x9cp\x9b\xd0y\xbeb(\x9d\x83M\x92g\xbe\xf0s\xcdz(?\xa7\xc9\"\x11\x0d\xb2\xe28\x8b%\xd0\\\xaf{U\x12\x1f\x07\xe5\xc3\"\x8f\x93)\xfbOp\x0e\x96\xab\x9b4)\xe7>\xc4 k\xe9fE\x89\x0f%K\xc4\x05\xf4\xd9(\xb7\xf3\x02J\x92\xa6\xac\x86\x84\x94\xc6\x89\xa9\xfb\x8eE\xf0\n\x80-\x06\x15\xd3\xcbz\x05\xb7\xf3|\xd1\x1cgR\xc2tUdI9'X&\xce\xa1\xcc}\xbd\xfarU\xdd+\xb0\xd2\xd3>\x1a\x1f\x81sp\x01\xc7\x17\x8e\x0f\xbf\x1c_\xfet\xf6\xe1\x12~98??8\xbd\xfc\x15\xce\xde\xc2\xc1\xe9\xaf\xf0\xe7\xe3\xd3#\x1f\xc6\x7fy\x7f>\xbe\xb8\x80\xb3s\xbd\xe6\xe3\x93\xf7\xef\x8e\xc7G>\x1c\x9f\x1e\xbe\xfbpt|\xfa'\xf8\xf1\xc3%\x9c\x9e]\xc2\xbb\xe3\x93\xe3\xcb\xf1\x11\\\x9ea\xfb\xa2\xe6\xe3\xf1\x05\xab\xfbd|~\xf8\xd3\xc1\xe9\xe5\xc1\x8f\xc7\xef\x8e/\x7f\xf5\xe1\xed\xf1\xe5\xe9\xf8\xe2B\xaf\xff\xed\xd99\x1c\xc0\xfb\x83\xf3\xcb\xe3\xc3\x0f\xef\x0e\xce\xe1\xfd\x87\xf3\xf7g\x17c88=\x82\xd3\xb3\xd3\xe3\xd3\xb7\xe7\xc7\xa7\x7f\x1a\x9f\x8cO/\x038>\x85\xd33\x18\xff<>\xbd\x84\x8b\x9f\x0e\xde\xbd\xc3\x96\x0f>\\\xfetvn\xea\xfd\xe1\xd9\xfb_\xcf\x8f\xff\xf4\xd3%\xfct\xf6\xeeh|~\x01?\x8e\xe1\xdd\xf1\xc1\x8f\xef\xc6\xbc\xe5\xd3_\xe1\xf0\xdd\xc1\xf1\x89\x0fG\x07'\x07\x7fb}?\x87\xb3\xcb\x9f\xc6\xe7\x98M\xf4\xfd\x97\x9f\xc6,\xa957\xa7pp\n\x07\x87\x97\xc7g\xa7l\xcc\x87g\xa7\x97\xe7\x07\x87\x97>\\\x9e\x9d_V5\xfdr|1\xf6\xe1\xe0\xfc\xf8\x82\xcd\xde\xdb\xf3\xb3\x13\x1f\xd8R\x9c\xbdeY\x8eO\xdb\x9d>=\x1d\xf3J\xd9\xaa5\x17\xf7\xec\x1c\xdf?\\\x8c\xeb\x9e\x1e\x8d\x0f\xde\x1d\x9f\xfe\xe9\x82uH\xcd\xacC\xcdv\xe3]\x9e%`!\xf7\xa5\xf4\x02\x92\x8c\xc1g\xc4\xe3\xfc\x8a\xf3\xb5J9\x12\x97$\x8d\xc4s2\x1b\x7fn:\xf1S\xe2oAS\xc7\xdd\xd88\xea\x874Z\xb6q\x10R&AE\x04\xaa}\xf9\xab\x0e\xca\x00#dI\xa8\x12\xa6\xc1XU\xa5x\xc26<\x1a\xd0\x19\xbc\x92\xf7w\x95M\x89\xa7\xb2U,\xc1E%\xa4\xcbdA\x1a\xd2.k%|\n\x1b\xd5\xf0$\xa3ZVK\x17\xebCF>/I\xc4N\x992\xa1+\xe1\x83e\xd0\x8a\xe4VI\x97\x14\xd3\\_#o|}\xedT\xf7PUh\x99\x96\xb0\xab9ak\xe1\x94\xcbH%\xda\x00\xc1\x10\xe0h\x17\xad\xccd\xd4\xfa:\xd0G\x1d g\xe7\xaa\xd3\x96\xc6R\xefS\xaf%\xab\x9c\xec\x18\xae\x14\xe5M,7\x9e\xec\xce+*\xe4jz\xb5N\x1aZ$\xf3\xeb\xf3\xaa\xbc\x0f\xbb\x06\x9d=k\x14M\xc3\x04\xa0\xf9]%\xe0\xc4\xb7\xa6~\xe0\nidA\xb2~\"w\xa5\xbb24iu\xa1\x0f\nc\x84\x12\x9f\x90\xfb\xa2G\xe1I\xee\xa2gz\x1e\x19$T\xc1\xc2\xd0S\xd2\xe8\xa9\x8c\x9c\xeb\x86\x93\xb2\xba\xf54h6\xaay*\x90%f\xeb\x06\xf5Y\x0b\xa5\xea\xc9\xd0x\x8cm\x03\ntN\xd5\xdd\n\xa8\x8b\xa2\x85G\xaf\xee\x83\xd9~i\x8e\x0c\xa35\xe5\xe2\xba\x97\x8bw\xb3F\xa2\x90\xf9\x8a\xb7\x04-\xd6\xd5\x94\xb6\xf7-\xf5\xf9\xea\xf9\x90[s|E\xdd\x96\x11?\x06\x9a\x13\\\x88O\x86\xd5\xa3\x8d\xd5\xa3m8\xa3ze\xbc\xd7\xbc\xc2f:\x0f,l\xec\xa0!d%\x1bMhA1\xcd\x80\x94\xcf=\x11Oq\x10\xbf|\x1f\xa5K\x9b\x00\xbb\xbd\xf4D\x89\x92\xc4\xd6\xd6b\x94\x88\xcc\xba\x01u\xb4\xd4{qZ'W(\x11n\xe7\xcf\xb8>\xba\x1et\x9a=\xea\x8e\xa7\x86\x1do\x0d7,Q6\x9d\xe4\x96\xbdc\x0c\xb9\x94\x08\xffqO\x9e\x98\xa6\x85\xf1\xf7[\xbb\\\xc6W[\x08M\xf2+6\xbcb\x92_a<\xf7\xc3\xa4\x88ViX\\90\x92\xa9\x04\xb3\xf9\x90 \x97\x0e;\x08P\xe2\xa3!\x00\xaa)\n\xac!\xf6#\xe56ih\x9f(\xcc\xd3D\xda\xd0\xf2\x0bR\x96\xe1LV!\xdf\xf6\xea/C+*i\x18}\x12\xd5\xf0\xdf{2\xd5P\x85\x14\xc57w\x04\x03\xf0 \x06\x922\xde\x06\xe1m\xca\xe4\xad\xf8\xc2-?\x84\x1f_\xe0~\xd5\xf2\xecn\x91\xafJ\xc7\x83Mpp\xfe\x1f\xacP\xf8\xfd+\xf35\xe3\x0bc\xc8#\x96n\xf2|\xcc\xd2\xf5k\x80\x95H\x7f\xed\x99\xcc'K\xbb\xd8\xc9\xa4\x10\x8d\xda8J\x84\xbb\x1d\xae\xf0j\xd0\x9d\xe2zS\xdc\x19? \x0b\xd7{\x03\x9b\x9b\x14~\x80\xcc\xa8S,g\xa2\x1do \xa4\xec\xbc$\xd4-0\xfeW1\xd9\xbd\xb2\xe9\xed\xd6\xbf\x14\xa5'\xde\x07\x86\xac\xfdF\xb2P\x8f\xc2`\x1ceS\x15\x9em\x94f\xe2{\xe9\xf9\xe0\x9c\x84K\x9b\x10x\x90V\xbc\"Un\x85\xd0\x13\x10e\xf1\xea\xf8\xc2\"\xd2|\xd1\x12\x81\n\x88\xda\xd5E\xf4\xa5H\x7fi\x84\xb4\xd4\x0ei\xc2< \x0ei\xc8\xad\x140\x1a\x99\xd1\xca\xaaL\xfe\xce\xf1\x05\xfbaX\xf4\xd4\xb0\xe8\xb9\xdfH\xae\x16=i\xa6\xf3E\x0f\x9b\x89|\xd1W\xcdD\xbe\xe8es\xd1S\xe3\xf2\xa8C\x1e\xacN\xdb\xf0\x9b\xb2\xb5\xcb\x1d\xa7\xd0\xca\x9c\x98\xeb\xdcK\x1f$\x9b\x9b\x19\xfc\x00\xc5\x1b\x0f\xc8$\x87M\xc0\xf81\xed\xb05\x92o\xd3\xe6l08\xbdx\xaa#\x1c\xa1\xf2\xfcZ\x07\x1bcL6\xa3\xaaS\x0b\xda\xba\x84\xc4m\x18\x0c\xd5\xe0\x8a]\xec\xb9\x8a\xb1\x90,@B\\Q\x1e(\xdc\x90\x1b\xb6[E\xc7Z\x8dj\x10\xb8V\xbe\xaf\xba\x03\x1dF\x83\x9a\xf7\xf4\xea\xbe\x8b`>%\x9e\xebkcZ\x83\xf6t'\x9a\x97\x8c\xf6\x14'\x03\x16\x0eq\xd37\xaa\xb6\x08u\xc7A\xab\x99\xb3\xaf<\xe8L\x15E\x15\xd56\xb8\x87\x92\x8dU;\xbd\xd9\x9ey)\x06!\xed\x0e\x1b\xb1z\x95\x9e\xe9\xab\x015\xf2m!e\x90\xbaB\x16\x8e\x08\xffl\xd0 \xcbcry\xb7D\xd2\xc9d\xfe\x88\xf7Af:\x92;\xa4\xc7zH\xa3\x1e\x83\xe9%\xdfW8\xbb\xd5\xd4\xec\xf1\xab&\x19t^\xb0&&\xbf\xe0l\x1e\xdd\x15\xec\xc3*HJ-7\xb2\xd4\x9a\xde{{\xfeAgPv\x9f=\xf7\xaa\xcb\xd5!z7\xafwv^\xee\xbe~\xfd\xf4\xfb\xe7/\x9f\xef\xbc~\xbd\xfbP6\xc5\xe4\xbf\x1d\xe7\xf1\x0f\x8c(\xc7_\xff\x81\xbe\xf1\xb93\x02\x02?\xec)\xa2\xb0\xfek\xb1{\xf5\xa6\x1b1I\xdc\xde\xba\xd4\xed\xe9\xceC\x80\xfb\xe9K\x9d\xc0\x04\x01\xdd\xdf\x08\xc1l\x13\xe4\x8f\x00\xc1\xd5NH\x1a\x10\x8cU\xa3\xb9cDJ\x83\xc5\x9env\xd0\xca\x00\x9d\xf7\xe0 \xe5]u\xeb\x05\xf9\xdb*)H\xe3\xc5uV4I\x1d/`\x03\xb3xb\x01U\xae\xfc\xe5\x8b\xdc\x8e7 \xdeD6^du\xc6zz\x02[}u=\xfbf\\=`3v(W\x99\xaf\xd6[FT\x0c\x04\xb6?\x06_>N\xdc\xfd\xd1\xe4\xffL>^]}\xf7\xc5\x9d8\xbf\xbf\xf2\xdc\xfd\x91\xbb\xbf\xf1q\xd7\x9b\xfc\x9f\x8f\x1f\xaf\xbe|\xfc\x18x\xdf\xed\x7f\xdc\xf5>\xea\x81Yx\x00\x98\x8f\xb7\xdf\xfd{oH\x07\x8b!S\xc3\x8eI\x17\x8bV\x92t\x01\x98F\"k\xc3\xad\xb0\xc7\xc6\x1ed\x08\xd4%R1JB\x158B\xa64\xdc\x0em\xa0F .?\x8f\x05\xc2\xa3\xc8n$\xea\x9b,A\xf9\xf6H\xa4\xd3<\xf7^\x86\x0e\xf7BD\xf7\xa4\x1f\xcd\xf2\"A\x99pm\xd3\xcaE\x17\xf5\xc1\xb9\xbe&\xe5I\x1e\xafR\xe2\xe8\x1a B\x1bAU\x08AC\x9b\x05Y\xe4\xc9\xdfI|\x11.\x96)y[\xe4\x8b\x8bhN\x16\xa1\x90*\xf0\x8f\x87\xa8,\xf8\x97\x93w\xe3\xcf\x98\x8d\xb3\x10\xf8\xf3/\x8bT+\x94dSR(\xefe\xbbfq\x00\x824\x81i\xd4\xac(z(\xec\x98\x89\x1b\x0b\xdd\xcc}\xf1\xfd\x0b\xcf\xb0\x0f\xf0\xd3\x8b\xd7\x9e\x91\x97\n\xed\xeb\x83\xa0\x10\xd4\xf3(T\xf5\xdaXKFF\xd0\xddZ\xfd\xae\xfdk-|\x19\xb6+\xe1\xa2\x99\xe1qm\xa5,\xa7\x95\xc7\x10F\x8bg\xbd&\x8b0I\xef\xd1\xc2\xaa$\xc5\x1f _\x8c \xca\x17\x83\xda\x12\xfdb,(\xd9\xa2\xc9\x828\xc3[t\xe5\xf5\x95\x17\xd0\xfc\xf8\xe2L\xa8\x84\x19\xf8\x02\x83<\x05\xd1\xc4\xf0\xb6\x06\xc5u\xe3\x95^O\xd3<\xa4\x8f\\u\x92Q2{\xf4\x0e\x0bT\xd8G\xff\x83\xb2\xca*\xf6\x94\xb88\x10 \x8dW\xad\xf2\xa5\xdd~\x13\xdc\xdb\xbcLw'\xa4\xcc\x82mt\x17\x9d\x0frr%\x99\xdeyF\xff3 \xc4f4h3a\xf2AO6\xc14/\x16\xa1\x812\x02\x81\x12V\x13\xd4O\xbcv`\x13\xb8\xa9\xcc\xca\x18\xd5S\xc2%\xf6.)\xdf\xae\xb2\xc8s\x13\xc6c%\\O\xda\xf9\x90}\xca\xf2\xdb\x0c\xb5 \x85K\x1b\xec]\xd7\xd4\xa46\\Xa%\xcb\x0d\x93<2[7\x89\x7f\x00\xa4\xa3\x15U\xd6\xfa\x8ep\xf7\n\xf6\x9b\xaf\xa3\x96)\xa8|r\xd3RP\xcbR \x99\xd9\xb1\x14\xca\x97\"P\xe1\x8035V\xb3Vg\xaa9\xef\x1c[\x16\x00m\xce\xb26\x844\x93\xcf\xa2\xe3\xdb\x0c\xc9\xb0\xcf\x0bC\xc0f\xf60\x1c6\xc3;j\xf3\xf7\x1b\xfc\xbe,\xc841x\xb4b\xcfuU\x03F\xab5g\xba\xe5S\x9b\xad\x16\xe6\xef\xe3\x8aG\xb6\x1c\xe0a\xc7\x01\xceN\x90\xd4C\xa8\xfa\x97\x9c\xe2a\xdf)\xee\xb2Y\xbd\xc3K\xff,\xa7\xe1\x8cM\x8e\xc3\xcd\xa5\xdc\x1b\xd8\x87\x1bF\x96\x8f\xd0>\x16u\x01\xee|\xb8\xe6\xde\xd2\x17\x13\xf6\xdd\xf9\xbcH\xb3r\xc4\xce\x8e\x1b\x96 _\xd1_\xc1\xb5\x85\xc0Q\x0f\x05\xc48\x91\x0d\xf9\xb2\xdc\x11\x83\x07\xd8\x03\xfe\xff\xcb\x17\x98qK\x10\x9f\xa7HU\x0d\xe5\x85\xe5\xe1P\x023\x11\xa9>\xae\x88\xbf\xf5$\x93nn\x9b'\x04\x9e\x0d\xd3\x81ns\xe5\x13\xc9\x1d\xc8\xfd\xb6\xb2\xca\x85\xdf^v\"\xe4V\x9d\xa6\xd6\xf94g\xad\xcf\xef\xdd\xba|\xb6\xac\x8b\xfb\x8d\x0bs\xaf\xf6E\xaeV\xa6\x01\xe4\xb6U;\x91M\xfd\x85\x99\xdc\xee!\xa7\x0f\x199\xad\xec\x19\xb4$\x95\x1b\xf0\xc2N\x9d\xb2\xbe]\xe8q\n\x0e9\xde\xd8\xb8\x98\x1c*\x84\xf7\x97/\xb0T?\xd4$7#\xc6-\xd3\xd5h\x87\x95\xe2H\xa2\xfa){(\xde\x03\x06\xb3h\xa9\xd2\xb5l\xf2a\x03\xff\xd4R\xbc\xc3\xba\x90Jc\x9d\xad\xde&;Wv\x96E}\x0ed\xff:\x0fm\xfd9\x93\xa5\x04D\xd91\xbd|\x16\x93j\xd4\x12\x1d\x1e^UG\x16\x92M\x07l\x04\x07\xd04\xb5\x9dN\x0e\x91\xef\xc1\xff\xcdOg,\xfd\x8c%~b\x7fJ\x9c\x8b\xee\x85\xf9\xdaw\x80\xc9\xa7\xd9\xd9=hw\xbe\xe1\xf3H\x9dA\x8d\x18\x94\x03p\x1byx\xba\x05\xce\xd5\x87\xad\xfa{d\x99.\x86\x15h\x82\xc7{Tw\xe5;\x05\xd1\xa8pa\xf0^\xa2[\x8e\x04\xde\xf7L[\x17j\x94\xcc\xa4h\xa8\x0fQ7\xa9\xcd\x118\x07\xd9\x1d\x9d\xa3\x0dT\x98\xc1\x0dAc7\x0bU\x80\xe1Q\x86\x9e\x08zC\xa5\x8doeH\xee\x11\xcf\x99\x018R\xcc\xdc\xb8 \xffSv\xd4W,\x15&\xcd\xd9\xf9\xdbB\xff\xb7lQo9WV\xa2]\xb8Xa\xc6\xe1M\xcc}\xb7\xf6\xfb\xab\x0fcV\xd1X\xef\xfaW\xe3=\xc8\xd4x\x89'\x05\x8e\x11\xff\xda\x84R\x86\x0d\xb3\x86\x9c+\x97x\xc3s3\x93\x19lL\xa24\x94\x81{M~\x0b\x92,\xc6\xc0*\xceG\xaa\x85c\xd3\xaf\xe1\x00\xcda;.\xa5X\x7f\x92\xba?\xd3\xbe\x1b.-\x7f\xda\xaf&Q\xcd][t\xcf\xd5\xf0\xc8\x9aq\x87\x95V\x9ex\x15\x87\x05O[\x84\x9f\xabxrU\xc6Fb\x85\x1b\x95 hw\xc1`\xd7$\x85\"2OCl\xd8YY~?\x8ds\xd5\xd8\xa0\xbb\xe2\xc4Z\xb1\xeaz\xc5\xb0\xd2\x0dGY>d\x01\x06W\x19/\x12\xca\xdd\xdcc\x9a\x12\xac\xa3\x9ayy\xbb\xd8\xf8\xaaMz\x9dG\xac\xfeI\xf3\xfb\xaeV\xbe$z\x0e\xbb\xd4\x03\xa9&\xe5\x06\x9b*\xc6(D\x06\xa8\x10\xbe\xebL\x1e\x152X\xacJ\xca\xd0g\x08<\x1e\xf2\x9a\x88[)\x8b\x1b\x05#\\\x11\x0eo\xf5\xcc6GD\x16 \xed\xb7\x9f\xe7\xfe\x8f|X\xf9P\xfa`\xf0\xc4\xac\x83\xb9\xabm\x03\x0c!'\"\xe5\n+\x1c$\xc4\xd4l\x01~F\x05'\xb7\x9d\xce\xd5\xd2\xda\xe9\xd2\xd0\xceDo\xb1\x9e\xa1\x8b#U^\xe3\xa9\xc6oc^5\x9f|\x03\xcd\xc3F\x1f eZ\xbe.\xbf\xff\x90E\xe1j6\xa7>\xac\xb2rI\xa2d\x9a\x90\xb8\x1a\x1bv-\x00\xf7\xf7\xb0\x89\x0e\xa2\x1d\xcf\xe4.\x84\xb7\x17\x05\"j5\xa7\xde\xa3&\xdak\xcdq\x82^\xa2\xd4\x19\x98\x90+\xbb\x92\x05\xd7\xc2\xc8<\x0f\xca\xdb\x04UXt9\x97i\xca\xa2\xb0$\xb0k\x8e\xf4/\\\xb0\xa2[t3\xd5\x82>\xa4\xdb\x9f\xb0\xd2\xa7\xbd\x95\xfa\xcdu\xba\x7f\x13\xcf\xee\xd9\x84\xfa\xf6\xf4\x9e\x0d\xca\x9b\x7fc\x99UE\xd4\xf7[\xe1\xb1\xfd\x18.\x97\xe9\x9d\xe8\xe0J\xd7{\xad\x84\xf4\xb9k\n\\\x83,\xd4\xfd\x1a\xc4C/\xc5\xeb-n\xda\xe2y\x95^t\xc9C4r\xc7\xe5Pnnz\x90N\xca+\xad\x8bF\xfc\xa3j\x954\xb1L\x18\xc7J\xcc\xd0N\xe5!\xb6\xe3\xc26$oX\xfc\xce\xa4\xb2\xda\x1aYV\xa7^\x17\x96\xecAU\x0d<\x93\x91[5\x02)~cx\xd3u\x94/\x0e\xfa\xff(\\\x1a\xc8.y(\x90\xaf:8\x02\xaaU\x94\x04\x08/\xa5\x9f\xf6\xae\x074\x87$\x8b\n\xc2\x90\x0d\xfa\xb7\x08\x9c\xd6\x92J\xe4\xea\x9b\xe9/\xd9\x7fZ\x84\x11\x1e\x82\x8d\x04\x0cL\xd7u^\xe7h\xe6\x00\x1b`\x15\xb9&<\xfa\x8du5\xd9\xc3\x03\x88d\x12\x83\xee\x83[\xfd\xdec\x8c\x8dyU\xd0\x08[F\xd8J8M\xf0\xad\xeb\xd4\xbf\x13\xfb\xb7\xdaA\x9a\x0e\xe3\xad\xd6F\x07\x81\xad\xed\xd1\xb3\x156:\xc6\\\x15\xe5\x9ci\xeb\x8ax_g\xf4\xd1\x87\x98~\xe6>y\xd2\xb9/\xda]2\xb7f\x05t\x8a\x0e\xc8\x1a#\xd6\x97G8\x02\x90K\xd8\x9eh\xa3\x0d\xb7J+\x19\x8a\xe8\x8dh\xf0#cC\xaa\x0b\x0eF\x9e\xa6\xb0\xf04\x96\x93!\xb3\xa1\x03\x83\xc6\x04N\xd0\x9bjo\xbc\xb1W:\xa9\xf6\xcc\x16\xb4\xf8\x0e1\x13]\xcbh\x03\xeat\x10,\x9b\xc8\xd26\x8d\xc4\xdd\xf1\xea\xdbx\xbfE\xfc\x19(?I\xe3\xc3H\x8b\x16e\xea\xeba\xbe\xca\xba\x05\x02:\xbboS\xae\xa0\xed\x85m\xc3YRy\x94\x14\xd3`q\xa0R\x87+\x96\x16\x9c\xfd\xf8F\xe3F\xec#4\x1c\xe6\x95\xbaJ\xa3T\xbfI\x80n\x0cD5\x0f4\x99\xfbl\xe7{\xcf\x0b.hA\xc2\x85\xa0H\x82s\x12\xc6\"\x02\x1b\xbe\xffR$T\xbcg\xee\xee\xeb\xefQ\x80y\xb4Z\xa6\xe437\x80\xe3)\x97E\x98\x95\xd3\xbcX\xf0\x8aww0\xf5}X\x96\x97\xf3\"_\xcd\xe6<\xf3\x8b\xe7\x83LMz\x1d\x01\xf28_&T,\xdc9>\xdf\xf1l\xf4\x9fA\xd7\x1e481II\x12\xc6|\xa1|\x84\x07\xaa\xe0\xa7PF\x8b\xbbf\xd24\xc9\x92f\xc0E\xdb9\xbd\xd19\x07\xfa#-\x0f\x08o\xd4~\xb6\x93F\xaf\xec\xf9\x04R*\x8c\xe6\xfb\xea\xb3\x16^d\nd\xe0o\xc2\xc8 \x82P\x1f\x1a,\xb9\x93\xc5\xe8fk\x8b\xf1y\x18v\x1d+`3h-k\xbe\x07\x02\xac1\xca\x8bO$>'\x7f[\x91\x92\x96o\x0b\xf4\xe9mJ\x96\x8bDP/\xcdPlO\xd3\xdb\x92\xcfW\xee\x91\xa5\xf5\xedk\xc7\xeeV\xb7\xd3]\x9b\x0fYq\x11\xc6\x06\x0dn\x8a\xfc\xb6\xe4\xd4\xcb\xc4Y\xef\x04\xbb;\x8e\x0f\xec\xc7\xeb\xc0\xb9\xaa]\x81\x04kR\x94I^y\xf9\xf0\xe1{\x8fk\xd2\n{\xda\x04\x87w\x99\xe8KpW\xed\xd3\x0b\x1a\xa2-\xfc\xac\xdd\x9dT\xd8\xad\xbc\xd0\x8e\x954H\xb29)\x12\x81\x15^\xed\x1aX\xaa\xc8h-\x02(|\x12z\xa6#\xdc\xe0\xcf\x06\x99IL\x05\xfe\xd1=\x0e\x80\xd4uvw\x9f\xefJG6\xed,\\u\xebC\x92\xd1W(i\x025`\x8d\xd7R1e\x03\x98\xfb\xa8\xa1\xc5\x1a}iE\x0d\x0b,l\xf983bg\x10\"6\xee\x82\x8a\xa3C\x0420\x84Q\x05e\x1fSU\xf6k \xd5\x11\x99\xf0\x8b\x8e\x93\xd9\x15\xfc\xeaz\x7f\xea/\x10\x19z\xb7\x0f\xbb/`\x04\xbb/\x9e\xbdzn\x99\x85FW\xd0\xaa\xf4\xcb\x17A\x0c\xe7\xb0\x0f9\x8c\xc4\\\xa4\xf5\x87\x94Q$)\x8c \xf2\xcd\x95\xd4\xb1~\xdc\xf6w\xafF\xe6az\x18\xa62,\xa7/\x0f\x02\x12\x1f\x15a\x92\xa9\x89\x1c\xe7i)\xcdr\xfclh\xa6\xc5\xa4\xa4E~'\x12\xcd+\x82\xf1\xf99\x7fE\x82\x98Dy,\xa2\xc9\xd8N\xaaF\x1eVxZ\xb5\x86B\xb2q\x16\xe5\xa2\xb7\xa4\x95\xf6\xe5\x0b8+:}%\xe5I*\x13\x87 l\xc5\xb5\xa1rD\xab\xe4)\xef\xb2HJL\xd8\xfb\x0dn\xe5\xf7\xdcZW+\x9cg\xa8\xff\xd2\xab\xb8\x0b\xedC\xb3\xef\xc4\xe4A\xdc\xaeoU\xec\xd8\xad\x84RpY\xf4]\x16u\xe7\xe3\x81\xe0\xb0\xe3\xd1\x8d\xfd@d\x14c\xff\xa8\xe4C\xb4\xb9%\xb2\x81\x8a\xc6 \x15\x7f \xf7\x1eII\xe6+\xbf\xd9\"X\x1b\xf9\x8a\x871\xf5\x0c\xc4\x87\x99\xa6\xd2\x9f\xad-\xe5x\xf71r\x80[\x9fJn\xeeC\xe1\xf9\xca9\xe5^\x08\xa6\xdco\xad\x03\x97\x9br\xb9\xa8\x14\xa9\x12\xc1\xd8\xf3+,V\x19\xe3\x15\xdc\xdc-\x1e\\\x81\x0f\x17\x1cT\xecZ(\xe89\x8aO\x00es\xd0A\\\xf5+\xf8\xe0\xad\x01\xec\xc1\xd8\xd5YD\xfd \xf1\xcc\x90{\x07\x7f\xb7\xb6 C\xde2\xb9\xa2dX\xea-gB}\x8cfZ\xba\xd78\xcd\xfcj4gsv\xed*\xef\xf6\x91\x1b\xbfXi!\x05\x01\xa8@Y'\n\xf8kl\xfa\xba\xdb\x8d\xfciX\xd2\x1f\xbb2T`\xa6\xd4\x88\x8a\xcem$\xaa\x03\xc2\xae\xb9\x03\x92\xdf\xdai`-\x8d<\xcc\xc8-\x84\xfcf\xb11\x016\xba\xe0\xce\xbc\xad\xb9\xe6s\x930\xd8p\xe7\xfc\x12\xec\x8ew\x00\x8d\xbe\xd9\x8f\x06-\xe05\x1c\xa0\xdeY|\x9f2n\xf6V#\xfaX~N\xa6(\xe1\xa2ok\x0e\x0e7\x08\x9e\x94f}\x0c\xbe\x86\xca\xc5\x87\xc4\xcb\xe2\x8b\xed\"A|^\xeb%\xd7u\xd1\xb5\xbd\xac8\x01\x95\xc22e\xaf\xfej/\x8eg\xb4R\x98\xbf\xef\xc9/\x9e\xe7\xc3T\xb9-\x1e\xb4\xa67M\xa4\xc8E\xe9\xc6k\x03\x15\xec\x19\xfaP\xf6F(_\x05>\xc7\xcb\x03\xe5\\\xc4\xa8+r\xa6\x18\xe6\xa4\xf2$\xe4a\x87\xf9\x17\x97\xb7^\x7fSk\xd9\x1d4\x9ake4\xa6Ad\xd0\x17\xf0Q>\"\x06\xa3<\x83\x9e<\x01\xaa\x10C\xb8\x06-\xe2Hb\xe4\x98\xa59\x06,\xfc\xd5\x15\x07\x84\xc68\x16n\x8d\xbb\x07\x8d\xf3\xd6\xdawj\xa4?\x0c\xb6\x0c\xeb\xca\xb1\xb2\x86:\xcc\xb2\xa0j\xf9PD\xcfo#\xd8\xc9g\x9b\xbf\x8a\xf87b&;\xc1\x91\x8b\xcd\xcd5\xf4\x8a\x0e\x83AtZi@l\xe6\x93(\xa9e\x05\xe6\x0c\x95R\xf4\x8a\xa3\xcd\x92\xcf\x1b:\xfd\xcb\xf1\xc6\x82k=\xa1w \xbc'\xc3\x1c\xbb2\xd0'\xce\x86\x0f+\xd8\xdc3\xc9\xd3\xd8\x93\x07a\x9a\xf2\x83\xa0\xe4^\xd8\xe4\xee\xe3;\xa6\xf2\x92\xe6\x83\xe30\xd2\x82\x1f\x00Mx\xd9\xdc\xc4\xac\x1dG\n'I\x18\xb9b\x11\x0b$\xa2\xaf\x89*\xe7\xf1\xecb\x04qN`?l\xe7L\x1b\xd6\xbb(\x08)&\xee\x94\xc8T\x9c|\x10\xcdW\x99\x85\xd1\x92\x0f\xea\x0b\x05DP\xf6\xddy\xb99r\xbf\x88\x87\xc1}\xb5B\xbb\x88\x99\x1a\xdc\x1c\x8c \xad\x16-\xf5\x19\x036\xd5\xc0\xc1\x0b\xae\n\xb9\xa3\x81S\xdau\xf4\xca\x83\xbd\xa6\xb9\xf9\x1e\xb2\xd4ZW\xa9\x87\x0bhn\xa4Z\xb4\xc8H^\x86\x06fM\x07\x9d\xc2\xa7\\\x8f\xb4\xbc:\x85*\xf1\x96\xb6\x07xx\xf0\xc9\xd5\x1b o<6\x0c\xb4=\x92\xa28\x9c6\xebJk\xe1\xe9\x0c\xc2\xca>A~\xb7\x171\xb3s$e\x1e|p\xf8pZ.\x92\xf4gF\xe8\x08\x0d\xad\x84\xc8\xb5\xdbI\xa3\xfe\xa8\xb7{\xd5\xd4\x1b\xdc\xda\xa8\xcfW\x1f\x1c\x8d\xe9\xe6}\x85\xa4\xacE\xbfBYI\xcbX//\xe3nH\x18\x07\x8e\x0f\xce\xd1\xf8\xfd\xce\xce\xce3\x8b\x8f3ho\xf0*\xb9\xd7\xfd\x99\x85E\x10\xb1\xb4\x9e<\x11\xbf\x82yX\x1e\x0b~\x0bl\xa1C\xa5\x9b\xe8z\x99&\xed\xd2Wh(\x07{\x03s\xfb\x16X\xb8\xf3\x0d=\xeb\x08\xe0\xd5/O\x92Z\x90\x1bsU\xdf\x94\xd4\xfc&\xdb\xed\x9c\xe3\x92\x0e\xa6\x9a\xbc\xa4\xc2\x8f\xce\xfaN\xcb\xaf\x88\x85\xe6\xbd\xe2;y\xce5\"\x9c\xb4\xee\xe5}P\x15G\x97\xc9\x92\xf4a\x07.\x01h\x1e4uP\x90\xc30\xcbr\n\xac\"\x1f\xd8\xafB\xdcp\xea\xac\x88\xd6r[$i\xbf\xa3C\xb2\x9e\x1b\xf0\x1b\x18s\xbb\x8d\xfd\x86\xc1#7\x88\x0b\x85\x8d\\\xa5\xab\xd01:W\xa1_V\xae8\xdd\x02\x17\xb4P'4\xb6\x1fi+$\x0d\x94\xe2\xdc\xed\xaa;L\xf0**Y\x06\xd3\"_\xe8\xf1\xe3\x00DH\x05\xcb\x16D\"\x85\xebWpT\x8dT\x18\xe3\x0b\xf6\xf1U\"@FmsEX\xbc\xe1\xd1$\xd3\xcd\xdak;\x86\xac\xaa}\xe1\xf9\x90\x0b\xb9\xfb\xfe\xb0\xb3[R\x03\n\xc8\xf0\xa5\x0f\xa7\x94\x14@\xb2\xd8\x16d\xd3D\xdd(G\xb4\xc5y\x86\xd8\x8b\x19\x9e\xdc\xab\x16\xe7m\xe7\xd2A\xb9\x9e1Y-\xc9'\xb4\\$\x80B\xdc\xd4\xa4\xf2>\xf7\nN\x1az\x80'\xe1\x1dn\x15>\x11\x98\x1bQ\x0fF'+Q_\xc0\xf1\x8c\xd1\xa3\xb9,A\xb1\xa3\xc989\xd4\xbc\x8er\x0dm\x1eg\xeb0Mb\xc8\xf2l\x8bW\xbb-N\x1a\xe4s\x1c\x0f\x95\xc5\xb9/\x8e\xe6\xbc\x87\xcdy/xJ.\xf9\xd0v\x10\x10\xb9\x069\x97\x99\xf2\x00\xd2n\xde$\xc0B\xc3\xde\xaf\xa4A\xb6\xf5AU\xae\xdek|S\xd5}\x078\xd1o\xf4\x8c\xd7Axw#\x17E\x8b[\x82{Jl_\xda\xe1\xc2G>F\xf2H}\xbeVz\x18\xf6\x8a\n\xee\xb2\xa4\xda\xa0\x8c\x88\xcc\x95\x0d\xcf\x15\x03,\xce#\xcc|\x9e\x94F\x18\xf8\xce\xc2\x18\xb9@>\x95\xd8j\xd3\xaa\x1b\xc9\xeaF\x0b\xb8:8\x12m\xde\x0c\x9a\xcb \xed\xfd\xa6\xeck\xa7\xc3GR-\x18\xc4\xed\xc1\x05\x0c}p\xc3=\xb6\x19\xd8Z\xfb\xfc\xdb\xb8\xe0n`\xc3\x1d7\x02\xc3\xcd\xbb\xfaH\xb1\xc2\x08\xf4P\x84\xda\x83\x07\xce\x08\xb2\x1eY\x85\x90<\x8c \xe9\xce\xc8v:\x8fgo\x07M\x1f-\x86S)\xca1O\xc3\xc8\xc8\xe4\x1b\xf3Z\x85<\x9b{\xd0vs\x06\xb5\xa4G\x95\x94\xacj\xfc\xd1\x89\x9e\xcb.\x8c\xb5\xf2A\xa2\x8cvL\xa0& \xc3\xa0j\x10\xf1\xa4\x11\xee\x1c\x1a77\xbb\xea^eCjo\xf0l\xcdV\xda3 \x1b\x16H\x9e\xbflm\xf9\xca\xad(:\x82\xac\xef\xcb\x14\xa9\x07\xbe\x19o\xcf\xda\x02\x13\xbc=\x93$q'\x11X\x12z\xd4\xba1\xef\xa6\x95\xd0\xd6\xd2\xe2\"O\xb8\x99\xa2\xf9\xbb\xfc\x96\x14\x87a\xc9\x8d,6\xdc\x893'\x9f\x19w$\xee\xdd\xd9\xff-\xfc\x11\x96Q\x92\xb0\x1f7I\x16\x16w\xf8+,\xc9\x8b\xe7\x98+*\x9f\x8a\xff[OE\xb1\xdd\x17\xe8k\x17k\x90\xbf\x8b\xf0VQ3r l\x82\xe3xZ?P\xcf\xa8\xb2\n\xd0Ng\xe9`\xb2\xde\xf3\xe8d\xb2G]W\x83+\x83\xf2\x81I3\xd7\xca&5X\xe6[\x93\xda\x89\x91\x83&U\x9c\x83\x91\x91\xe2F\xae\xba\x97\x93\xee\x18W\xe3\x80h\xef\xdd\xe6\xe8\xbc&\x84]\xdf\x87\xcf\xc8\\\x85J\x15\xd7C\x1e\xe3\xc4\x19\xb1\x96,\x96)Y\x90\x8c\x92\xb8\x87\xb5\xa9/\xe7\xb8h\\\xfdF\xb2x`g\xaa\xbb\x8c!{\xdb\x1a\x90 \xa9\x02\xc2\x055\xe2\xeeW\x11\xbd\xdf\x8b\x99\xa8\xcd\xbf\xa1\xe9$\x83{\xa8\xaf\xee\xa8\xa5\xcc\xabP\xf1MQ\xab\xb0\xc8\xcbc\x8e\xe2p\x87\x16R6\xcb\xd8\xad\x06\xd2\x192S\x80\x07q\xad\x1f\xb4S 7\xfdJX]\xd5\xb9\xaf\xd2\xb2\x19\xbf \xcc\xb3\x88TB\xb7\x0e\xd2\x8d\xd6*G;\xbe\xa2\x9a\xd5\x16Q\x83r\xa8\x14-Fe\xe0\x16\xacT\x97\x8c\xdb\xee^\xdbJY-\xd3\xd5v\xa5\x84\xae#\x14\xd1\x81\xf6\xd8\xda\xdb\xbcl\xf4\xc7\xca\xe7Z\x9aw;\xdb\xc7\xd8\x8d\xf7\xdc\xf9\xf5%\xf7Z\xfe\xd6\xb6\xe9*S\xf3ToZ\xae:O/\xbf\xcb%%Y\xecz>\xd0V\x0c\xf8\xdf\xd5=U\x03\n~\xcf\xa0\xd4}\xb6\xf3\xcac\xc7\xe1\xf1bA\xe2$\xa4\x04\x13w\x87\x85\x0ex\x8c(\x83F\x04\xf2\xbbf\xe7\xbf\xb9\x1b\x99\xfb\xe2\xf5\x8e\xe7z\x95\xdbN\xc6-a\x98\xc8\x17\xafw\xbfa\xa8\xeb\xcam\xfc\xcb\x1ds\xf0\x84\x17\xa6\x88?\x99\xfb\xea\xa9!\x86\x97n]-\x0e\xf6f\xc6\x95)jSWx\xa0R*E\x867\x9a\xff\xc5\xb4\xa1.y\xdf\x05\\W^\x1b\"_u\xa5\x0f\xb51\xa2\x12\x9f!\xb4\x98W6\xcb\xe1\x85@\x86\xc1W\xb9A\xb0W\x9b\xbaF\x9a\x93\x05~F\xa0sI\xf4p\x11y\"\xce]\x04\x7f\xd8\x83\x1d\xc6&\xb0\xb4\x914H\x96vN[\x90\xba\xa5\x1by\xde\x1b\xe0a\xee`s\xd3p\x1d\x85z>\xaa\x94\x95rq\xc2T\x1c\x8d\x13z\xe5C\xe1N\xbdz\x8c\x1a\xbf&R\x15w\xc9\xdf\x00\xcd\x0d#\x89\xd6i$\x05\x95Z\x07\x86\x11\xb5&\xd1\x1b1\xd3\x8bHaJ\xc2\xc4nD\n\x8aT\xb8\xf1\xe1+\x97\x12tw\xaa\x06,\x967\xce#\\r\x11\xc0\xe1\x92|\xa6\xa7yL\\\xc7\xe9p\x1cn\xd0\x00QT\xaf\x06\xdc\xaf \x83\xd3\xc1\xe6{\xf2\x80\xe7\x97\xeb\xdc=\x16\xb5\x9d\xdfC\xfc_f\xfd\xfe/\xb11\xe3W\xb3D\x05\xad\xd6\x9a\xe4\x94E\x8e[;Z\"B\xf3\xa3\xca\x8f'8\xd1c\xd0\xc8\x077l\x1e\xc4!\xe5\xe1|\xf6`s3\x81\xff\x80\xa7\\\xdd\x01k\x0b\xcay2\xa5.z\xa1\x10\xe2\x17ix-(\\6\x82 \xad\x96qH\xc9\xbb\xf0\x8e\xcd\xf3\x00*\xd7@\xb2cD\x0f\x83\x80u\x19\xde\xa5y\x18w\x84\xfb\xa9;\xf06I)\xe9>\xe5{:`\x10\xc9\x0e\xeb@9\xcfo\xfb\xc9C\xc6\xa0\xb6|B\xf5\xf8>\xe7\xc1\xb4\x94\x04#UE*\x17\xb0\xba\xfby\x06\xc5\xb6\xe1\xae:\x86ke\x1b\xb3\xd9\xc8\x14\xbf\x8e=l\x16\xb2\x91\xe1.\xc5f]\x88s\x17\xcd\xc3lF\x84UW\xff\x0c\xdes\xfe\xda\xbe\xe3\x1d\xe7\x11\xa70|\xe4)\\\xe41\xb9\xd7\x0c\x9a\xb8/c\xd0\xae\xf6\x06vR\xdc\xb1\xd7|\xf7\\\xf37\xa7\xcd\x9f\xb5\x91\x81Vr\x8a\x1b\xcfi\xb3p:Z\xd1\xca\xb1\xc1:m~\xae\xc2J2;\x83+\xee\xa2\xf2\xbf\x1ea\xe2\xf5mH\xc9\x8fd\x9a\x17d\xfc\x99D+\x14l\xd2 \n3\xf1\x8a~.y\"k\x0cOR%m\x1e\x96?\xe5\xe2\x12\xa6\xfa\xfeKB\xe7'\x84\xf2Y[\x86E\xb8 \x94\x14\xe6\xd4\xe3,JW%\xab\x94P\x9ad\xb3\xb7ya.\xf6\xe3\xddqL2\x9a\xd0;\xfc\x1e\xa6i~{Y\xdc\x1d\xd3\xb3\x15\x95\x85\x16\xec\xa8\xafn\x0ddj\xa1\xbf\x96\xcb<+\x89\xb9P\xa9\x16)\x1b\x05\xf8\x1b\x0dg3\x12\x9f\xc9\xb1\x96\xcd\xa1\x97\xac\xbb\x97\xe1\xac\xca{Dh\x98\xa4\xd5\xab)\xfby\x9e\xd3c\xaet\x87r)\xca\xa3Z\x88\xf6\xe6rzo\xc2\x92\xbc\x0f\xd1\xacO\x00@Rw`\x9ad\xf1Q\x95\xc6+!\xd1\xaaH\xe8\xdd\x91\x96U\xa6\xf3i.\xf2x\x15\x89\xa6\xa2<+W\xb2\xdd\xbc9\xc2eH\xe7\xb2\xfcb\xcd\xfd!I\xe3g\xfcM>SRdaz\x94G<_\x92M\xf9^M\xca\xb3\x83\x8bg\xbc\xec\x92D\xd5\x8f\xff,9\xa8\x9c\x932O\xd7$\xbeX\xdd\xd0\x82\x88\xe6Y\x06\xedC+\xbdQS\xf5r\x91\xaf\x8a\xa8\xce|Ay_WE}\x19\x8b,\xaf!>\x82\xa2\x15\x94\xb9\xafLA\xdaQ\xa5'GyA\xd1\x0c\xf1Wt\x87\xf8+\x9aH\xafn\x13cm\xbf\x97\xd0nVa\xb0\x1c\xfd\x08\x17\xecL\x9d\\1\x96bF\xe8q\xe6N\x9c\x05\xa1\xa1\xe3\x83\x83K\xe6T.\x9e5G\xb5\xd4\xf3a\xe2T\xdb\xact\xae<\x1f\x0f\x8d\x12Eh\xffy\xe1\xb9\x93+\xcfC\xc8\xea\xb1\x87\x94\x97\xa0\xc1I\xb8\x0c\x92\xf2$\\\nE%\xec\x93\xeb`\xb0\x06\xaf\xd6\xf4\x16\xc9I&\x12\xb5\xb9A2\x81\xf7\xe4$\\z*9\xea\xab\x98\xe1g\xae\xe0\xd2\x7f\xf7a\x9a\xae\xf7Bj%)\xbf \xb1O\x94\xe7\xf1\x0e+\x93%\xa7\xea]RR\xcf\xf5\xbc\xa0 l\x1f\xb9\x8d\xaet\xdd\xc1\xc8\x08\xa4\xb1\x081A\x959\xd9\x97o\x88\xb8\xaf?/R\x87[5\xd4\x89]r\x19F\x9c\xbbj}\x9b\xe0\x04\x0el\xca\n\xf8r0\xb0j\xce\xbb\xbe\xfc\xffP\xa3\xa87\xa7\xbe<\xe6AX\x8e\xb3\xff\x1a:\x87\xf1\x84|\xf2\x83\xa4d\xffT\x81$ \xca|A\xbe\x11f+\xe0\xd4\x94\x8d\xfbf\xe4\x92\x07\x1d\xba\xf49>\xa5$\xa3,\xc9\x0c\xabz\xc7\x14\x08}\xd3\x9aH6\xd5\xb1K\xbcj\x9f\xf7\xed\xef\xd6~f\x0b\xda&\xd5\xb8\x8b\x92\xfb\"\x8f\x81\x953Tz\"n\xceZ\x1fQ\xa7\xac\xb5\xb5x\\]r+vW\xbb\xd8\n\x1d\x93`1yb]\x8bM\x811\xd2\xcd_Fp\x89\xd1\xf30j\x15\xcb\xe8,V)M\x96aA\xb7\xa7y\xb1\xd8\x8aC\x1a:u\xb6\xbcX\x1c\xb1\x14\xcc\xcapE\x12\xe1q\xb8\xfdy\xeb\xf6\xf6v\x0b\x8b\xac\x8a\x14\xaf\xd7I\xecT~\xda\x8d\x04\xb96U\x06h\x14\n*\x15\xc0\x189\x1aI\x894\xf2\xe5\x9d\x00Z\x1d\xe3\x87\xf5\xe1\xde \x83&dy/\xb0c\xc7\x8a\x9c}\xc3\xa1\xd2\xc6*\xd1\xaa(HF\xdf\x0bR\x84\xd3e'\xcdS\x19A\xc5\xfd^\xbfrY\x99y\x04~1\xf4\xd2k\xd6\xc1\xce\xff\x893#\x14\xe1{\xc5\xff\xe5%\xfe\xe7\x1e\xba\xd8\xaf|\x89D\x0f\xfb9'a,\xf6B4g?\xd0\xcb\xa6\xa3E\xd2\x88z\xc5\xde\x15Wf;\xd7\x00Z\xf7\x9fS\x1e%M\xa5VX\xd1P\x08\xcb/HJ\"\x9a\x17\x9e\x1b\xf5\x05\x82\xac\xb0\"\xee\x8b\xaaBM\x9d\x9fs\x04\x9cHz\x94\x86V\x85\x1e\x15\x9d7Q\xd3d\x8f\xd2\x0c\xab\x8e\xa3\x0cG\xf7\xfc\xef\xeb\x04\xe1\xa35\xc8k\x14\xcdf9\xdd\"qB\xf3\xc2\xd6\x01A\x9e>J\xf3\x7f-\xf3\xac\xa2>8\x18\xe9\xb3\xacm\x86%\x87$\x8dp~\x94\xce\x14\xa2\xbe\x9e\x0e\xf9Vz\xbe\x97\\R\xdbC\xecSh\xccB\xf7\x11\xc5Qr\x8b\xce\x91\xcd\xca\x80\x89\xc3\xe8\x03~M\xa8\xa6d\xdc\x8f1\xce\x05\x8f\xca\x8a \"~b\x19\x9c\x151)H\xccg%X\x90bF\x18\xc3S\xd3\xa9#\xdd\x16K[\xbbx\x08\xb3\xf4mK\xd9\xdd\xd3\xa5\xdf\x00<\xcf\xd7\x97\xbeZ\x87\xf6\xaa7\xde\xe7*\xff7\xa8c\xd3\x96\xbaC\xb3\xc6\xb5\x88#)\xb9K\xf34\xcc\xfd\xee\x0b\x16\xd1\x98n\x0f\x8a0+8\xd8\xfe\x8a\xbb\x86\xf1Wi\xaf#\xc8\xcai\xde\x9e*m\xae\x16|d\x1aG\xfd\x98\xddP\xab6\xac\\\x83\xb57\xb7\xbb\x1e\xd8\xae\xda\xaa\xa8\xb3u,h\xc3\x9f \x84%\xe5\x0c\xe6\x0e,\x06v`{\xbd\xefNv\xb6^_}\xe7}\x0c\xda\xbf\xb6\x93\x80|&\x11#p\xb8\x0b\xb7]\xd3lH\xe9\x87\xb9+\xf1\xc0\xae\x10I\xeb2\x02\xaag\x12\xee\xdaB\x18s\xe3\xb3\xbe\xc6\xf1\x0e\x9a\x07\x0e \xca\xe4\xef\x04~\x80]\xaf\xb9\xfb\x05\x17\xdbf)%\x03\xd7\x93\xad\xb9\xd6\"\n\x1d\xec\x83K\xda!\xe9H\x87\xca]\xdd\xd5\x8d\xaad\xd5Uk\x18bc\x1bV\x83\x1c\x10F\xae\\\xb3\xb6\xf0d0\x15\x97K\xd9\xf0\x9a\xb7\x8f\\W\x1f\xb6\x9a\xbd\x9a\xf2\x0bB\xe7y\xdc\xab\x9f_-\xb7U\xa6.\x9f\x84U\xc6\x18\xfb-\xc6\xd8\x9bU\x07\x80\xc3\x95\xe5J\xdat/\x8f\x87\xf0\xa8\xb9\xda\xfanh\xbc\xdf\xe8r\xc3oCR\xbc\xe1\x0bB=\x974\xd9\xb8\xbe\xe3\xe5Z\x97f>vGd\xd5}\x1d\xb9\x95\xc8\xab\x12\xb2~[O$\xd5)\xeak \x9e\x0c\xc8\xca,\xf8}\xd4n(U\x1b\x89\xfc\x968\xba\x97\xd0\xab]\xbfY)=d\xd3\xeav}\xa0W\xbe\xd031\x82xS\xb0!\x08g[\x15v\xb5\"\xd4 F\x99D\xeb\xa6\xdcoI\xe2\x1fe\x96\xd5.\xda\x85\xa1P\xcd\xb6r3\xf0(\xed\xcb\xfa\x8cK+\xee#\x1e\xa5!V\x97\x99I\xac.@\x1e\xa5\x1dQ\xdd\x006\xa5\xfbf\xc6\xdc\x99;\x1fn|\xb8\xee\xbe\xceku\xac\x11\xd8\xdd\xaa\xc5Qe\xe7\xd7\x8c\xaeSu\xd0\xe9\x9b\x02\xf9\xa0\xd7\xa3\xae\x0c2\xd3FS\x18\xda\xaf\xb5\x06j\x07o\x13:\x97\xaa6\xe5\x80\x91\x19+\xd1p>'Z\xe4\xd0\xab\xf4\xa1#W\x1f\x03b\x17|\x8ekP\x11\xd5\x9f\xaf5\xe3S\x1f\x04\xcd\xdeU\xe9\x8f\xdc;\x83E\xb2\xfe|m\x85\xb6o\xe7\xb0~\xb6\xfbpnt\xca\x80|\xe4c$%\xb4\xbd\xa5\xa1h\xae\x97#\xeeC\x1fe\x8b\xb3\xbaz\x0f\xc7\xc6\xfbg\xd9\x87\xfa\x8a\xb6\xf7\x94\x92S\x82~\x81*\xc4\\]\x02q\xe5\x01W\xd9G\x83\xee\xcf\xa05\x1a\xe5\xc6\xcc\xa0?\xd1\x89\xc6\x9a\x83\xbc\xd0\xd8\x08\xe5z\xda<\xed\xb7>\x8c\xfd\xc1\x13A\x06\xdf{\x81r\xc6+`N\xab\xf3YEl|5\xaflJ\xb7\xf2d\x0e\"\xf4\xab\xcfH\xf8]\xf4\xcc'\xf7\xa2\x10\x02\xe9\xf0\xd0\x07QZ\xfdD\x06\xce\xb2@=\xc6A1\x8c\xbf\xd32\\G\xe8\xd9\x03\xfb\x08C\xfb \xf6\xed\xff\xd5\xea2\xf4^\xcbZuC\xb9w\x94w\x8c\x1d\xfb\x11TPn\xc8\x9fz6\xee!'\xb1\x0d\x8a\x18\x83\x10F\x95i\x10\x9c\xe2x\x0e\xf3l\x9a\xccJ\xb6<\xf6\x85\xc5\xcb,\x06\xb8\x17yAM>\xd0\xe5\xc3\xfd\x10\xd7{\x92\xe7\xef\x04\xf5\x0b\x94O\xe4\x05\xfd\xf1n\xd8\x9a(e\xcd\xee\x00\xba\x02\xd4\xea\x8f\x9c\x0f\xa3\xdej!t\x1fV\xd8?R\x94\xca\x1cL\nK\x14}P\xe9\xeb}\x90]\xe8\xb0\x11\xff\xea5)\xa6>\x0f\x0c\xf2\x9e\xdd\xd8g\xe9\x83\xbc\xee\xb3\xbe\x1a\x93\xbc'^z\x02{8t\x8aU\xb8\x05^\xd0\xf7\x0eV\xc1\xdb\xdd[\xbb>\x96F\xdc\xd9[\xd6\x01z\xa0\x8a\x0e\xca\x11$\xf7F\x04\x86\x9d\xd9\xdc\x82\xbe\xa6\x07e><\x86\xca\x9ck\x192\xaf\xf0~\x17\x1a\x9f\xf0LST\xb4\x1e\xa93\xbc\xbe>&\xa1\xf1~\x80]ik\x90=J\x8f\xb4j\xef\xd5\xb13\x8e#\x9b\xban\xf7\xe0O\x0e\x95\x1b_\x96U\xb2\xc9&\xa8P\xb4\xeb\xee\xd1\xc2\xa7\xc1-\x98\xb4\xfa\xee\xd1\xd0\xc1\xe0\x86\x0c:\x85U;\x1d\x0dh\xc6)M\xbd\x10\xa3\xfa\xe2\x90\xdeK\x04v\xef\xbbw\xa3JW\xf3|5\xa3\x92\xfcA\x8a \x03\x9b\xb4\xcaW\x8a\x81\x9c\xb0\x14E\xe7\xb89\xb2\x06\x9d,\x15\x9c2y\xc9\xe2\xd8\xc6\x08\xe2\xa4\x1eX\x0b\xa6\xcd\xc3r\xce\xc5\xac\xf8\xf30\x8f\x89q@\xa0\xe3y\xc3\xa5\x9aXq\x93\x11\xca\x03Y\x85JQI\xed\xb6Y\xf7NMi\xb7o^\xb7N,\xf3\x9ec\x99\x1ee^\x1d\xda-\xc2y\xe9)+\xab\x16\xc2@\x13\xa9c\x7f8\x98^'\xb2\xa3\x0c\xab\xe6\x0cf7\xf4{\x1f\xe3.\xbe\xffh\xfe\x19\xdb\xf7\x1b\x01\xa5\xb0\x80\xc7P\x90\xb0\xae\xca\x99\x98\x93\xdc0\x95&\xe5\xf0oD\x83\xbc\xd0\xd5c\xa1\xb8\x07T\x97\xd4\x9ah]\xba\xa1\x0d\x04\xd7y1\xa5N\xa4<\xac\x0c\xb8\x02p/Z\xd7\xc1\x8e}\xd0\xf7\x17\xf2i\xcd\x0e'\xfa>W\xf5\x93k\x1d\xff\x07Hj$\xdanH|\x8d:r\x06\x17<\xdc\xcc\xb1V\x1a\xc5\xf8\xcf\xce\xb6\x08K9\xd9Q\x02\x12\xaa\x11\xa2do\xe0\xd2\xde\x9f\xff\x81*\xa9lRz\x95R\x0d\xb3p\xf2\xaf\xd155\\\xa3\xa0\x99\xb2\xf4\xf1\xd2\xb9\xbd\x1f\x88\xd0\x85\xccU(y^y\x9d\xf7A\xb9T7\xe5#\xaa\xe5\xb5;\xbd\x97@x\xff\x83A\xac\x1a\xaa\xa0x\xa7\xd4\\\x8a\xdf\xb5\x7f\xb11\x1e7\xe5p\x95\x05M\x1f\nl\xcc\x8fP\xaa\x0b\x16!\x8d\xe6\xee\xf6\xffq'\xe1\xd6\xdf\xaf\xd8\x9f\x9d\xad\xd7\x9b\x1f\xb7\x82\xab\xef\xbc\xd1\xb6E\x0b\x97\xbb\xa0HJ\x19\x90\x80\xb1\xed\x1c\x92\xb3V\xd0\xc1\xd6)\xcb/P$\x8a\x14\x92\xef\xd6G\xe7Z\xac\x0f\x1f\x9e\xc33\xe6\x9ar^\xc3\xf6\xc1`h\xd47%\xa2s\x13gN\xe9\x12\xd54)]\x96\x8a\xb7\xac\xe3\xaa$\xf7\x90U\xb7\xdce\xf4\xd4)\x0d\xe9\xdd,zd\x8a\xc7\xa1S\xecF\x19-\x8d\x07\xdb\xe6Rp/z\xdf,M\x96\x03\x02\xcfJqj\xe5\xfa\xd1\xa0\x0b\x93\xa9\xeb\xd8\xc65\x7fm\xf7\xc4\x8c\xd6\xf61\xde#W\xf3> \x97\xda\xb6\xf9\xaf\xb7\x8d#\x8a5\x9c\xf8\xddp8\x98\xcf\xd4\xd7\x92p3\xf3\xa6W\xc2\x92\xd0\xd6+\xe7\xc7\xb9E\x12J\x80\xc7\x8b%\xbdC\xfb\x9f\x8az\xc6\xaf\x12N\xf1\x93\xb4\xa8\x92\x89\x9a\x16\xe0a\x18\xcd\xd5:M\x86S\x82O7\x7f\xc2\xb4\x0bi\x9c\xb5\x0c\x8b\x92\\\xe6\x95U\xd5\xc5\xf8\xf2\xfa\xe2\xf0\xa7\xf1I\xc3\x9c\xfa||q\xf6\xee\xe7\xf1\xd1\xf5\xc5\x87\x1f/\xcf\xc7\xc6oj\xda\xd9\xfb\xf1\xf9\xc1\xe5\xf1\xd9\xe9\xf5\xc9\xf8\xf2\xe0\xfa\xe7\x83w\x1fx\x99\xc3w\xe3\x83s\xf6~\x8c\xf9\xde\x1f\x9c\x1f\x9c\\(_\xce\xc7\xff\xbf\x0f\xe3\x8b\xcbF\xca\xc5\xfb\xb3\xd3\x0b^\xfc\xdd\xd9\x9f\x1aYXoO>\\\x1e\\\x8e\x8fZ\xe9\xedw\xa5\"S\x0fD\xdf\xc7'\xef/\x7f\xe5\xe9\xd7\xc7\xa7\x87\xef>\\\x1c\x9f\x9d\xaa\x19\xf0\x93\x9a\xf0\x9f\x17\xcd\x0c\x1f\xce\xdf\xa9\xaf\x17\xef\xc7\x876\x034\xd8\x83\x1b7s\x9f~\xaf\x93\x9d\xb9\xf8\xf2\xea\xb9\xfe%\x91e\x9e\xe9_B\xf1\xe5\xf9S\xfd\xcbJ\x96\xd9i\x15*\xc5\xa7g\xcf^\xe9\x9f\xd2\xea\xd3k\xfdS$\x9b\xfa\xdek\xd0\x8f\x1c&/\xfaT?%\xb6z\xc7\xe8\x8e\x82,\xd30\"\xee\xf6G\xba=\xf3\xc1\x01\xd0\xf1\x96\xcdkc\xad/\xd6Fsh/q\xdd>\x1f+3g\x8d\xaej\x9e\x1c\xcd\xbd\xf5-\xb6\xf9\xa7\x1d]\x18\xe0\x1c\xe0\x03j\xe9?\xb8\xf5\xdbok\x9d\xa1\x85\xde\xc5\xec\xe9\xc2\xf8\xa1]\xe0\x06\xf6\x88\x13\xcd\xbc\xb8! bO_>w\xf4\xc5\xcc\xa9q\x95?\x8b\x86\x9e8P,\xf7?x\xb4\x9f\x86\x0b2\x02K\xf0\xa8%?\n\xac*\x85I\xf9\x97E\xaa[\xfd\x00\x0crL\x80\xf3\xd6)\x89\xb4\x1b\x9b\xfe\x8b\xa6\x0f\x87o\x9d\x1c1\xb9\xddSS\xdcsjR\x12\x16?\xeb\xa7\xed\x83A\xfb\xf8A\xf3q\"\x14D\xdbj\x1c\x03\x96U\x9av\xa1\x91a\x1f)\xdb\xd3\xfd\xbf>\xa8\xfb}\xbb\xc1\xb2\x9c\x9f\xc8\xdd\x08tS\xbd\x87\xcc\x80\xb4\x1d\xfb\x1f:\x03\x1a\x1f{\xcf\x19`\xf0\xab\x10\x96\xdf2\xf6\xcb\xc7\x1d\xbbT{\xbe\x87\x0f\x10eD\x92r\xfe\x96\x01\x9d\xfc\xb7\x18PI\xe8}\xd9[\xdb\x80\x8e\xee= \xce\x9ew \\6^\x0bx\xca\xf1\x1ad\xc3\xb6\xf16\x89\xd9iEd\xbe4\xd9\xa5e\xaen\xd1\x19W\x05Z\xf4\xe5\\|\xda}\xd9\xfa\xb4\x96Ti\x9b\xcc]\x88O/_\xb4\xc8\xdcY\xf5\xa9Ej\xdfI\xc3R\x13\x93{c=\x14dh\x1e\xd51\x04\xe9v\x0ca%w\x1a\xf3xm`\x1e\xd0\x14Q\xfa\x9fA;\xc8\xe6\x18n\xdb\xfcG\xa3\xc8\xaaH\xb5\x12c\x03\x07\xd3(\xc2\x95\xa8\x1be>\x9b\xd8\xa0F!<\xd2\xb5R\x83\xb8\xabF-\x84\xf1\xc9\xbc\xae\xfa\xfaF\xab\xf5\xd0\xc2\xc7\xf1\x8a$\xf3l\xec\xd0'\x13O\xc8\xcb\x95\x84^\xcb\x8bt\xad\xd4\x81\x81\xb3T\x0b!\n\xd3\xca\x9cup\xa9uYq\xe9m\xa9\xe3\xbd\x81\xf3\xe5e\xd3|f)ca\xa0y1D\xb9\xb6Q\x9e\x18\x99\xf1fAS\x8b\xc7\x9d\xec\xbdZ\xbesi\xfe:@\x8a\xd0\x00\x95J\xccz\xbd 4\x14\x87j\xb3\xceS\x8b\xb4\xa2QOm\xde\xda({\xde#\x051\xd6q]r\x81\x8bV\xd7Q\x05\x0c\x95\x80\xc5a\xcb/e\xaa\x8d\xcc\xef\x86\xaa\xb8\xb9;>\xba\xa8\x16R\xc5J\xdc\xa6\x9bH\xab\\zS\xe8\xd3K\xfeV\x19:\xad9\xb8\xc5\xe7\x01\xe6,\xcdGLQe\x937J\x96\x8c\xdc\x99\x10)\x8a\xce\xea\xf8\x95\x9c027g \x85{R\x83\x1c\xd4\x1a\x16\x10\xc3@\xc0\x97/\x90\xb8\x18\xb0\n\xc1\xb6C\x87\xabD\x0bqF\xda\xb1i-\xda$\x1d{\xbez\"h\x91\\\xaa\xa0\x0c\xa7\xe4]\x1e\xc6\xc6h]j4=\xf3T\xf2\xa5a\xf4t\x9e\x8aX\xfb\xe8\xf1-\x0f2r\xcbx\xf6qq\x9fN\x9b\xa7\x8f=)Y\x93t\x042\xa0\x935\xdf\x82\x94e8c\xc4GP\x90\xb0\xcc;\xcc\xe4\xd2$\xc3|\x8b\xb0\xf8\xc4OQ\xf6+`\xc9\xa8\xdb[\xbfmb\xe4 .:\xb3\xcck{\xf2l[\x05\x03\x1d)\xde6\xf7\xc0Uba\x85\xb0\x0f\xce*\xe3\"et\xf2\xc1\xb6VTo\xad\xd0\xe3&\xe0M\xd1\x88\x1bz\xec\xd0\x1fH#}0\xc4\x95\xfb[\xa5\xbf\xa5Hf; a0\xecM\xab\x86d\xe5\x85\xa8\x7f\x7fBus6`\x8f\x82t\x83\xde\xbbO\xa1\xf2\xff2\xed\x00\x8a\x15\xecA\x18L \x8d\xe6\xf6L%f\x12S\xd5\x01`\x98\xed\xe0\xc2\xc0\xe3\xc8'\xaaD\xb2\xb8\xfa)\xec\xc3?\xbe\xc2\x08R{\x91\xa9\xbcT\x14:\xc2f\xb5\xa0\x0fh, 7\xe6mXd\xdc\x91\x84\x98\xa2\xc6:7\xc2tB\x99d\x11\x81\xf5\xb3`w'\xd8\x810\x8b\xe16IS\xb8!P\x90E\xbe&1$\x19\xac\x9f\x07;\xc1\xce\x1bX\x95\x04,r~\x11\xd0s\xc3\xf1|\x0ep\xb6XW\x0c4\x18i>\xedRv\x8e10\xd9\"\x8fI*/ZN\xc2\xa8\xe8\x88*5\xc7\x12\xd5\xcdVO\xee5\xe6\x16C9\xce()\"\xb2\xa4y\x87R\xf5B\x94\xe0\x04\x8cR\xc42\xcaz\x95\xeb8?y\xe5i\xc1\xad\x9dG\xf0\xfb\xf6\xca%x\x1e\xac\x8a\xd4\xaa\xfe\xc5&\x8fq\x15\x11\x83\x88wIFNW\x8b\x1bR\xbc\xcd\x0b\xb4\xcf\xdb\xb7}h\x86\xdd0\x84\xc2\x90\xcf]\xd5\xcd\x0bZ\xd8\\w\xcb\x1b\xb7\x0eT\x8f[\xca\xe8cH>\xac\x8dN3\xe4\x9b\xb0$Gyd\xe5\x1dA\xb8\x00mB\xc8\x08b{\xf6&x\x8c\xa0c\xd3\xb7ac\x04\xeb\xae\xec-\xc0\x18\xc1\xc2\x98\xfd\xab\x17\xd09\xc9\x06\xe8WA\xe3\x8e\x95M\x98\xbd\x03\xec\xe1\xf6\xad\xfc\x1a\xd6\xae*\x9eL\xc1Mz \x0c\xa8$\x02\x0e\xba\xf3\xcf\xcc$\x06\x082\xa3y\xfb\x9f\xe1\x1do\xa6(\xd6t\x0d\x11T\xe5\xbc\x81\xda\x9a\xeac%K\x08?\xcf\xd9\xa4LWi*\xb6\xc8\xcc\xbd\xf3\x95\x14i\x15\xc0\xd2\x96\xdc\xc8\xb5\x91\xbd~ \xfe\x9a'\x99\xeb\x04\x8eZ\x04)\x15FU\xcb\xd8\x93$\xa0\xdcE\x9b\x9c7\x1f\xb5s\x84\x8b iu\xccr\x9a\xef\x93\x89\x0f\x8e kz\xa3?\xcb\xa7\x11\xcf\xaa#\x10\xa8\xfa\x08\xb9! Dc\xbd\x85\x86X\x01\xda\xa1\x8e= #\x13/qV\xc6E\xf1#j\x99\xe4\xdf`9XhWfvS\xaaVr\xcb\xfc`r\xa5\x1dGo\x85>\xda\xa2&\xc6\xd8kZ\xbf\x96\x15Y\xcdh\xc7\nh\x81X\x03\xdfQ5b\xa8\x0f!\x0f\x80\xe2C\xec\xc3\xdc\x87\xb5\x0f\x0b\x1f*k\xdf[\x1f\xc6V\x85\xa1\xba\xed\xdbb\xd0\x86\xc1p\x0bo\xdexP\xde&\x9c\xca\x0f\x96\x05F\xfc\xe2\xc1\xd0\xbb6Z\x14\x96\x04vF\xddk;\xe5\xe7\xd7\xdf\x82\xf2\xae\xa4d1d\xe3\x12\x19\x8c\xf1y7\xdc\xb0\xe7\xa6 a;\x92\x9a\xfa\xd8\xc1\x05lH\xc2\x89\xc9\x8d\x00\x1e\xe9\x05`\x04q\x9e\xfd\x9e\xc2<\\\x13\x08\x81\x0f\x06h.\x0c`\x08\xe4\x99\x0f\xe1M^\xd0$\x9b\x05\xdcaQxS\xac\x96h\xe2\xc1\xda\xb0\x05\x07\x069\x93\xcf\xfbg2\xd3yQ\xc1\xc6\x92\xa2\xa8)d\xc1\xb1N3\x1fi\xe2\xbc\xa2\xf2\xf8P8\xef\x97#E\xaaS\x9e\xa1\xa4\xfc\xade\xee9\x04\x94\xd6\"R\xe8`\xacK\x0dw\xf3\xb6\x87U\x1eb\xe8\xd4\x14\x91\xf0\x12\x91\xf0\xa2\x1fh\xe1\x1bp\xb0\xe9\xf9\x16\xbclz\x86\xe0j\xd3S)\x14\x8au{\xeaw\x99\x1b\x9a\x1el\xf9\xe9\x83[\x0e9\x91K2\xea\x0b\xb6\xbc \xe5*\xa5'\xe1\xd2\x17\xbc5\x83\xf2_\x12:?\xe4\x0e=%\xcaV\xa0\xed\xa5\x0f\x89\x9b\xe2\xf9z\xbfi\x93O\xc5tL9\x1f6\x8c\x96\xd2\x1f\x13[r\xf7\xb0\xaat\x96\xe5\xe6a\xd5\x98\xd8\x19\x83\xa2\xd2\x90\xc7\xc8\xea\xdc\xde\xbb\xaa>bQ\x7f\x10\xbc^>\x18\xbc\"\x05\xbc\x96\x88x9\x9f\xc4\x8f\xba\x88sWP\x04a\x9a\xe2 R\xba\x1e\xf7f\x86\x8c\xcc\x10n\xc9\xf6\x0c\xe4\xa2lO\x9b\xbbZ\"w\xb5\xd4\xcc\x16\\.\xa1\xb8?\xfbdz*l`b\xa0\xe6\xee\xfa\x7f\x1b\x03ez\x1e\xc2T\x99\x9e{3Z\xa6\xa7\x9f\xf92=\xa8Pm`\xba\x16\xd2\xbd\xf6\xac>WW\x885\xe3\xf6\x87\xb4\xfa\xd0\xa2\x83\x1e:\xbd\x15f\xef\x94\x10u=\x96\xa3`\x04\xf6\x08\xf0\xb6\xe7A\x88h\xf7\xfb\xfba\",\xe4\x90,v\xeeW\x0e\xd4\xcdX\xd2|i\xf1\x91cz\xba\xa9g\xf9|\xc5\xe8\xf1&G\xb6\xc6\xdc6\xc9\xa4\xfa\xb4\xae\xf0z|)\xa8O5Xs\xd0\xcf\xde:\xba\x07\xfd\x95Q\xc3\xab\x8an\x13\xb8d\x00bW \xd6\x9d\x9a\x9c\x0d\xbb\x93\xab\xcac\xcfR\x9a\xd0\x074\xff\xcf\x8b!D\x84\x15\x9c\xa7\x8a\xc8X\xd4\xd6=\xc0\xae\xf5\xe1\x90\xdb\xc3~\x8e\x95\x83\x92{-\xafxz\x1f\xaf\x8dx0\x10I&>\xed\x06\x07\xe4\xf1\xfaz\xf4\xba\xbbG5c\xf1\x1aO\x87\x1d\xec!^V\xba\xbb\xbb\x9e\xafK\xfe\x02j\xbb{\x80\x8aL\xed\xa1Sc\xb3\xa1\x83\xcb\xc6>\xae \xd3\xdef\x9e\xd9\x9b\x19\x8a\x11\x86\xec\xfe6\xd0\xab\xbb\xda\x87\x89\xb1\xd4\x841j\xbb\xaf\xafZ\x1f\xaf\xda\x0e2\xe0\xd9\xf7\x0d\x9d{\xab\xb5\xc77^\xec\xffM\xc6\xc1\xf4+\xa8\x03\x0cC\xfaV\xf7LX\xbd}m\xdb\x02\xdc\xd3\x11x\x8fJ\xdcy{\xff~\x8b\x8e\x9fT\xd8l\xaf\x99m\x80\xfe\x10\xdb\x1c+o\xfdO\x1a\xdd\xc4\xe2\xc0F\x0cO\xc5\x83\xf7\x1bi\xcb0\xe9[\xd6\xee\xf0A\xa3\xab\xb4\xa5\xcdC\xe4.\xc1\xef\xbd\x84]\xf6X\xdf\xae'\x7f\xf1\xcf\x18\xe9#\x98\x13\xf0\xb058\xea\x9f\x85\xe9\xc2\xf0iS\xb7v\xd3\xbc\xed\xc1j\xae\x03&\xa5_=\xd7\xfc\xb9`'\xb6\xc9\xcd\x81e\xc9>uAK\xc3\xb8\xef\xbf\xe7h\xffv\xaf\xd1\x1e\xf4\x8c\xb6e\xe0\xf8\xbfa\xd0g]\x83n\x18y\xf6\x1e\x9c\x1d\xe34\x8c\x857\xff\xbe\xab\xf9\x96\xd9io\x17\x86*\xe5\xd9Tn\x8aa*{\xf9P\x95\xbd\x95&\xeb6\xe7\x12\xf1\x06\xc3\xf2YOu)\x12\x96\x0c<\x18\xca3\xe7\xe1r$qW`\xcc1\xc5\x1c\x95\x8e\xa8\x05m\xc2\x1e\xacl\x9c\xc1\xfd\xb4S\xac\x9a)\xe6\xec3\xbc0\xe0\xacD\x9b|M\xa6\xe0\xce\xe0\xc9\x13\x98)\xa1\xc7\xf4w)y\xd2\x93\x85{\xd2~\xf1\x93\xa4iY\x0d\x1bBK\x86{\xc7\xaa\xcf\x89\xf6\x1e3\x98\xa5w\xc6\x0b\xcf;\x1d\x07\xb9\x93\xd4\x87\xe8\x8am\x84\x8c\xad6\xd2X^\x17\x9bJ\xd4)\xd9k\xbe~\xf9b\x8d\x1f\x00\xca\xd6P\xcbLx\xc3\x1d\x1e\x0c\xdd\x0dt\x0e\x8e\xa1\xfcv\x84\x8b\xa52\xf9;w\xda\xe1\x9a\xea\x82=p\x0c\xbe\x97\xc0\xcc#\xa0H\x07\x83\xc8}\xa6\x1f\xaa\xc8Lq-\xfa\x91\xcaH\x01\xcd/\xd0\x12\x96\xb1\xcf\x02<*\x00?\x8eQ\xc8\xa7\xbe\xefi\xdfG\xbcP\xca\xfeD\xa2\xf3\xcd\xfcY\x90/\x8fcw\xc6\xefc<\xd4)\xe5d\x96k]\x136\xa97\xb0\x07)l\x823r`\x13\"\xf3\\2v\xb6\xe0\xb1>\xca\xa0D\x1c@\xe2\x0bLro\x90ko%w\xe8_]\x8bjX\xbe\x9f\xc3\" oR\xd2\xa5\n\x05\x18,\x9d\xe5\x1eU=\xe9\x96\x08\xb0\xa5,\x97aDFpc\xcd\xf8\xb5_\xbap\xfb\x08=\xedo\xbf{\xce\xabv+\xf7>\x15t]{\x12\x91\xec\xc35\x8c\xe0\xd6G5^=R\x1d\x0e\xa2\x9d\xec\"\xa0\xf0\"\xad\xa8u\xa2L+\x9d\x17B\x87!\xdfm\x7f\xe7\xd8\x17y\xac\xb6\xfac\x1es\x9c\xc4\x8b\x9bK\xb1\xc1\xdd\x05I\xf9\x9f\x17g\xa7\\0\xed\xb9cT\x8cW\xab\x81=`\x19\xb86\xbc;\xf6F0f\xfba\x8csi\xc8<\x16\x93\x0c\xa3\xf6\xa7\xf6\x86n\xa5\xb0\xa1|\x163\xaf\xb8\x01\xf9\x07z\xe6m\x8f\xe33\xee\xc4\x9bU\x92J2\xcc\xfd\xec\xf9P(\xc4\xa8\xab\x1c\x90\xf5A\x08\x9f\x0d\xb5\x11\xc3\x11\xa6R\x19\xbd\xfeq\xd7\x0d!\xe0\x84\xea*:\xea\x93\x9bG\x99u\xab0\x16m\xc2\xd32\xc0\xbc\xe1\x9bD>_U\xf8k\x0e\xd3p\x97\xcc\xc6u\x01{p\x14R\x12d\xf9mG\xa8\x9bLRg.\xd1\xd5\x05\xad\xd3F\x83x\xc5Qj\xa3\x0d\xd8\x82\x8bj\x0dyO-c4\xa8O}\xf5\x84\xa0\xad\xbfyuJ{\x1a\xea8c\xb9\xf6F\xd7}\x0b)\n.^\x98\xab~m\xccg\x9ei@\x8d$\x0b\xafI\xdan{\xf4aK\xf5\x04\x83\xa3\xaf\x1d\xab\xa3\xaf\x9d\xa6\xa3\xaf\x9d+T\xe37P\xef\x15%\xda\xfe\x96uR\xa0\x89\xd8\x07\xb9b\x9e\xc3}\xfeP\x0c1\xc9\xcb9Wf\x1fi\xdd\xa4\x9bT\xd2$\xc14\xebR\x9a\x0f+}\xd5\x01\xf4;\xe9\xe7\x07\xca\xea\xf6\xdf\x16\xa5\xce\xed>\x0c\xb9\xfa\x80\xe6\x1d\x8b_K\xd8\xa9\xfc\xb0\x1d_W8x\xednl\x8a\xf7\xc9\xed\x03\xcb\xce\x08D\xa6\xa3\xca\x9c\x9d\xd1J\xdb\x9f\x17\xe9v\x12P\x86\xac\xa6\x96N\xccq\x00\x15\x81\xd8\xe8\xbe\x0f\xb1\xfd\xec\x16\x80\xb0\xd2\xb8C\xd4},\x9a\xb85\xb1md\xa1\xfcm\xd1\xbf\xe7\x8a\xdf\x96\xa5\x96\xd8\xa2\xdfb\xd8V^\x92\xc4V\xednS,\xdc\xa9\xa5\xab\xc2\xb4\xd9b\x9fa\x0c\x97\xbb4\xa0\x1c+\xce\xc1_=\xce\xa8H@>/\xf3\x02\xfd>7\xe7\xbb\xb2\xf1\xcd\xdc\x97\xcf\x9ej\x90P\xdb\x087\xbdO\x19\x9b\xb4\xb57@,\x89\x91]\\n\x00\x12f\x11\xbaUD\nKA\x80\xe8\x11\xb4\x80$\x03\xe2\x01\xde\xea\x03\x9b,T\xb4p\xd1\x1f\xeb\x08\x92,\xca\x8b\x82D\x14\x92l\x9ds\x07x\x1b\x16W\x8e\xe4~3hv\xe7U\xd9(\xb9\xaf\x9f+\xcdT\xc3\x0f\xa6CD\"\x19\xb9\x1d\x805Y\x8f\xda{\x8d\xd15\xc1\xb2\xc8\x17 \x8a4YUdX\x9096\xe9\xca\xfcRm\xbe\xb3\xf6,;?\x861\xbc\x17mEyV\xd2b\xc50\xb3M\x97\x11O \x1f\x0f\x1b\x83\xbc\xd6\xf3y\xe7\xc5\x05*\xcb\x84\xbe\xe5D\"\xa3~1M\x0b.\xf3U\xb5;\x1c\xb4t\xf5\"}\xbfcZ\xa4\x01bB\xd4\xb0\xe3GW\x921\xd8D~\x9aLrv\x16\xe3\xbf=\xa0\xec\xdf\x08\nVG\xee\xe3\xeb\xbf\x04\xf2^>\xdf\xb5\x8c\xaax\x8c\xea_\xbd\xb0\xd4\xce@M\xd7g\"\x9f\x97i\x12%t\x04\x13\xd6\xb1\xe7\x8c\xe0u_>\xff^\xfc\x7f\xe1\xa9\xdeP\x1f\xde\xbb\x0eJR\x99\x97\x17\xbb\x167\x93\xec\x9b\x8e\xea@\xd0=\x9a\xc7\xca`s\xeb\xea\xbb\x91\xb7\xef~\xdc\xfe\xb8\xed\xed\xbb\x93\x8f\x17\x1fK\x0c\xc9\xd9.\x1eb\xf1\xc9\xc1\xd6\xff\x1f+\xe0\xffw\xb6^on\x05W\xdf\x8dX\x05\xdb\xedB\x8c|\xb1\\\xad:\xff\x86\x9e#\xc3r\xae\x87\xf3\xae\xb3\xec\xb3,\x7f[\x91\xe2\xce\x9eg[\xfatDG\xca\xd6l\x7fd\xd9\xc2\x15\x92x\xbb\xb6\\\xa7\xe1)\xeb\x13\x8fH.\xaf\x86w;\nl\x8f\xdc\x8f\xf1\xa6\xf7\xef\xdb\x18\xc8\xbch\x14\xebo\x04{\xac5\xd4*c\xa8\xa6}\xce\xc9\x87M\xe7\x08v\xcd-\xe3D\x8e`\xb7\xf5Q\xf5# \xaa\x9b\x8d\xd4\x8e\xaf3\xaepo\xb3\x94C\x015\xfa\x83s+\xc3m\x1a\xa4\xe2\xd4\xe2\xc2@\x8bp\xd5\xb9I\xf3\x9b\x91#d\x9e\xcb\"\xa7y\x94\xa7\x1e\x87{v\x96\xb8\xab\x8c\x94Q\xb8\x94\xbc\x13\x9bF\xcf7WH\xd2\x92\xe8\x8e\xea\xf6t\xf7\xd8\xf2A<\x981\x1cX\xb7E\xb0b\x1fJO\xeaz\x14\x93\xcc \x91\xac\x1bR-\x99\xad\xda\xd6uS\x84\xa1\xdb$\x03\x94\x90\xba\xacr6_\x93LG\xaf\xf2Ql\x14\x8a\xa0L\xc3rNP\xfc\xec\xd6o\x8c\xb0\xa5\x9cQ\x9f\x17dj\x8a\xfa\xd3J\x91\xbc\xe9\xef\x9a\xd9\xccp\x11u{;\xad\x02\xfaZ\x89g\xf3\xa4\xc8\xb5\x1e\x01\xe5\x0e\x9f\xd9\xbf\x80\xe6\xef\xf2[R\x1c\x86%A)\x8fc\xb1v\x17\xa3\x1f\xc1\xc6\x06\x9d<\xb5\xec\xbe\x82\x94\x94U\xff\xac\xbd\xd1\xf4+V\xf3\xd0\xa7\xb6C\x14*J\x8f\x1d\xf1*\xb17\xad\xbdPW0E\xcd\x82\x176\x83\xdc\xec\xa9\x94\x1a\xf7sn\xc1\xb0\x12\xc1\x91-\xdc\xcc\x02j\x97\xdd\xe6\x1c3\x96c\x9eX\xb8\x8a;\xd8\x83\x9dv\x7f\x10L+\x88f\x84\xd3\x02\xad\xf5\xe5f\xaaR\xb8=\x8e\x8f\xcb\xcf\x1d@s\"B \xfe\xb3Q\xf50\xabJ\xe4\\\xcc\xe7\xf1\x82)RH\xec\x9c\xdap\xd9q\x13\xb9\x84{.\xf6\xbc\n\x0f\xe0\x85H(A\xdd\x87Y\x03\xea\xe5\xef/_ \xe1\x1eu\x95\x8cU\x15\xc8\xf8\xc9\x17DL\xea\x9b\xe3\xf8\\l\xc1h7\xea7ku\xd7\x93\xa7l\x83N\xb6\xdd\xe0;o\xbbq\xf4xo\xe0\x0e~\x80\xb5\x10s\xbc\x81\xbb\xcdM\x0f\x91\xb5\xcbx\xd8\xf5\xe4\xee\xca\x9b\xec\\\xf9\xdc\x12{\xb2{\xe5C\xc9f\xa5\x84}\x98M\xe6\xb8\xef\x19|\xb7]j\xb2\x1c\xff\x8f\x1b\xa3,@\xfaX.=~\xc9\xe1dh\xfe\xa2f_\xb2>\xee\x83++\x15\xa0\xb3#tT\x95\xa4\x1861\xb7\x87A\x87\xb5\xfczf,\xcfs\xc6(\xfc\x15\xbb\x9c\xf7C\x14\x8eq\\z1\xdek\xcf\xf3\xe5@\xf1\x9f\\\xa5\xe5\xe4\xd9\x15\xae\x96Hd+\xb0\x9c<\xbfR\xebe\xff\x9a\xa8\xc0\xb0}8`\xcd\x02<\xe9\x90\x14\x12\xbf=\x84+\x15 @\xf1c?\xab\x8e\x91 \x9a\x87\xc5\x01uw\xc4\xdc\xea\xdfy\xef8GQ\x9f=\xa2\xd5*\xd3\x00?\x11\xa0\x92\xdd\x18\xe9\x0c9\x14g\xdb\xf1\x82r\x99&\xd4\xe5?\xe5\x0cn\xedz\xd2a5Q2x\xbep\"\xc1A\x8e\x1b\xbce\x93\x02\xb6\x18\xfd\xc1\xb7\xd2.7s\xdby\x03\xc5\xd6\xd6\x1b\x0f#{\xe0M\xd9\xa4\xb8B\xcf\x19\xac\xba\x08#\x13\xec\"~\x0d\x9a\x19\xdcf\x0e\x1fB\x06\xd6#\xee\xb7\xc3\xdd\xa9\x03Z\xb8 \xf7j\xe0C\xab\xc4\xd6V\xb7\x94\x19\xd7&\x0bVY9O\xa6\xd4u\x1c\xcf\xc7~\xb2\x89\xceq\xa9\x82\xea\xed\xcb\x17\xc8\xb8\x0e\x1cf\xcb\x84\xce\xfc\xb6)\xa2\x8a\xb2*\xbe\xbabl\xde\xd8\xb7\xbc\xa0*f\xe0\xfa\xa93\x19a\x97\xff\xe0\x85yf~{\xc8\xdeV%)\xc4b\xb36\xca\xf26/b\xfc\xcc\xbe2B\x13\xa7d\x89\xdf\xd9\xab\\\xb5Q\xab\xfcr\xb2S\x81}\xa3.\x86#\x04\x02d_\xf2\"\x99%\x19oP\xc1\x86\xa2\xbb\x88l\x93\x94\x8c*\x98\x95y\xf6\xd5\x97Mp\xb6\xb7\x1d\xd8\x94\xc5F\xe00|\x8dM3b\x01\xab\xaf/3\xb53Q}\x9b\xf2J\x85)B\x1b\xc4KBG\xbd\xac\xa7|\xf0\xe0\x13'\x94\x19R*\xeb\xaf\xae\x0bh\xae2\xca9\x86n\xa5\xd1\xdeX\x17\xd2\xdd\x84\x8b\xd4\xaa<\xa8x\xa0\x85d\x82\x17\xc9=\xe6_C4{9\xd7\xd0c\xee*Zc0K}H\x14p\xdd\x17~1\x12 \xb2I\x05\xb2\xd5\x95/\x0f(o\xc8Q\x8d\xc3\xe92\xd7\x84\xa1#\xa98\x9a\xa1\xa3I\xf8\x96\xe2\x13\xbd\xb9'\xba\xcbS\xd9$\xcb\x1e?\xc64#O7\xb4c\xdb\xa3\x8f\xf1\xe6\xbfos\x1a\x9a\xb2Yv\x85\xffxe\x0b'\x12!\xd0`\x99/\xdd\xaa\xc3bSS\x81\x96F\x8e\xa7\xcc\xbf\xfc\xa8\x14\x7f\x9c\xc9\x97 \xd17F\x95\x08\xa2\xcd\xf3\x94\xf5\xa9\xa6\xa56z\xa2N\x0f\xeb\x95\xa4\x8d\xfa\x94\xbcQ\x0c\xd0o\xf4=\xc8\xd6\x13\x0dW\xd9\xc4V\xad\x0b'3\xfbx\xe0\x8f\xc0\xf97\xcb\xb5\xb6\xfaHhP(\x82\x0da\x16\x1e\xb2M\x05&\xe5V\xf5\xf9*X\xc2\xc7@\x15R\x8c=\x08~\x8d\x99\xccF\x1f\x15\x05Rr\x02\xa1\x84\x1f`U\x91\xaf%;\xe7\xed\xf3\xcd\xca10ZM\xca\x0e\x0d\x9dT\xd2q\xc9$\x9d\xec^\xb1\x1e\x8a_\x1a5w\x8fnK\xa2\xa1>\x11\x93\xc6\x89\x98\x18O\xc4D=\x11\x13\xc3\x89\x98\xe8'b\"O\xc4\xa4\xa1\xde\xd3\x0e\xeei\xba\x9f\x14\x05F=\xb2o@\xd7vMNI\xf1\xa5\x8f\x04\x89\xf0\x8c\x84\xf5%\xd3\xbb\x0e\xcd\x1b\xca\xe5\xd1v>\x0f@\xc6\xc9\x95\xe3\xb7\xd0e\xd8%1s\x85\xdc\x04\x85<\x1c\xb7\x18\xa9\x88B\x07\x81\xb8;\xfa\xc4\xe3\xb4n\"\x1d)\xd0\xcb>\x9f\xf2\x91\x1d\xf9U\x97\xfc\x15\x9d\xc4 \xcc\xcd=%\x8d\x11\x7f\x15\xb9T}\xe7\xc7H\xfd\x05I\x7f\x96\xfeGG\xfe\xcc\xf8J\xf3\\\x92\x10\xcf\x87\x8d4X\xa6\xabY\x92\x95\x93\xec\xaa\x0biR\xb9\x86\xe35\xc9h)\xeby)\xeaQ\xab\xe9>5\xe4)G\x03\xb2\x167\xab\x1d\x1e\xad\x14D\x9fd\x10z\xb0r\xc3Iy\x85\xeb\\z\xb2\x17\xaf\x1c\x94;\x19<_\x82\x11\x17\xab\xd7\xb4\xed\x95\\\xd9h\xfe\x94w\xf94\\\x90\xa3\xa4\\\x864\x9a\x0b\xedd\xb6\x19\xcen\xb3\xcaP\x99{\xc9b]{\xed\xa0*BGY!8m\xceA\xad\x8f\xb1\x9c\x87%\x89\xcf\xc9,))\xd7q`uhS\xc6A\xcd\xb0|\xd5\xfc%l\xfe\xacR]\xaeS\xab\x0d\"\xf1<(\xdd|\x92\\\x89\xe9\xe8\xd9\xe9P\xa3?=\xae\xed\xefLy6HPh\xc3B\xfcR\xba\xed\x0f\xa2\x07>c\xd3;\x17\xaf\xb4/\x9e^'\xbfB/\x19\xf5\xc1\x17kwg\xa7\x02\xe7\x8e\xccH\x06\xb7s\x1c\x91%\xc9b\x92EI\x95M\x01\xf1Iv\x15\xc4J\x0ee\x10\xf2\x97\xa4K\x9a\xfd\x16\xfb\xaam\x95e\x83\xa7\xb6\xda\x91e,\xfd\x19\xd5!\xb5s/\xf3\xb2LnR\xd2\x82M\xe1\x01\xa0 \xa1\x19;\x9e\x10y\xbc\xc7\x11a\x8c\xc9>\"#\xafVf\x97\x9d\x81u0\xba\x8a\x83\xe7\x92&~0\xb0\x95\x0bu\xd6\xbf\xa7\x1b\xe5\x8fw\\)e\xc0M?\n\xa5,\xb2f.\x0e\xc3k\x11\xeb\x0e#m4\xd1G\xa7\xe6\xe2N\xc5\x8e!\x133\xeeI\x10\xadH\xb9\x93\x8b\xafr.\x9f\n\x9c\xc4\xf3\xe0\xad8\x17\x80\x0dD\x9fH\xa1\xf6L\xf4\x8c\x88 \xe6\xc0\xf66/p\xd2\x87\xce3 \xe2\x06T\xb7\xc7\x8flUk\x13V\x17\x16\xf6\x1d\xdc.\x84\xb2*\xb3[g]\x1b\xc3\x86\x8e\xbbNqn83\x08\x8f\xcb\xa7\x02)\xd4\xac1`^\xf9\xe0\xc9\xaeC@\xd1 V\xa0\x80\x96}\x96\xb2Iq\xd5\x01uP\x1f:b\xc2\xdbQ\x85\xe4\xd3u\xfe\xcaG\x92\xcd\xab4\xed\x82\xaa\xeb\x82\x94\xa4\xb1}Gv5Nh\x11[\xb9\xb8\xe4A\x8fg\xad\x8d\xc3\xe5\xe1\xe2\xb2\x94\x91]\xed\xe1Wd\x8e\xe4'\x8c\x97O\x12\x88\xedg~\x1f\x12\xa1\x1e\x0f\x9e\xdb\xde\xd7\xa2{\xd4\x88\x13$Yk]\xd6\x8evC\xbc>\xf6\xa0\xd0\xdb\x0d\xd5v\x8bI\xd8\xbc\x804j\xd9\xaa\xf4;_\xcf\x87S\xe9\xdc\xa3\xa2\x99VG/\xd0\xee\xd3\xdd\xa7\n\xdd+Hw\xf7\xb51\xfe\xc6\xaaC\xdd\xad\xa6\xb9P4\xfc\xe5\x0b8\xab\xecS\x96\xdff[\xb8\x8e\x9a\xf0\x85\x04\x11w\xe9p\x19\x163B\xf1biF\xe8i\x1e\x93\xb7E\xbe8\x16\xf7\xa8n\x81\x97\x84\xfb\x10\x06I\xb6\xce?\x91?\xad\xc2\"&\xf1a\x98\xa67a\xf4 }Cp\x7f\x99\xd8-\x82W\x14\xe6\xbcU\x16\xdf\xd0zc\xef4\xa9\x8a\xb6\xdeER\x8e\xb38)\xe7}\xf8X\xecK\x87\xe6\xcb\x93|U\x92\x0fK)\x94b\xd3C\xf3\xe5e\xbe\x8a\xe6\xe3,6%\x1f\xb2\xf1\xa7\xe2K\xd7\xb6N\xca\x93|M\x1e\xd0\x1dV\xcc\xd4\xb2\x92\xde\xdd\xee\x05\x0d\x0b\xfa\x80\x86\x8f\xf2\xdb\xcc\xd40\xd67\xa0e\xa1\x82{\x94\x14$\xa2\x129\xf4u\xa2>\x1c\xaf\xe5\xe9\xf8.))\xc9\x88M\x0b;k\xe6\x960i\xc0\x03M?T\x94\xd3\x10\x8cXx\xe6\x18\xa1\x8dA\xb4\x19\xde3\xcf\x18\x18\x18\x14\xfc\xc4\nS\x97\xd83J\x95<#\x90\xfb\xc6 0}\xac\xc6[},\x06-\n/M\xca\xe36\x95j\xb9\x16]WV\x80C\x97\xa6\x18\xbc4\xec\x9c\xd5\x9d0w\xe8\x01I4\xb6\xf3\x06r\xf8\xa1v\xd5\xfc\xe4 l\x90 )\x19b\x0fg\\[\x9e\xe6\xcb%\x89]\xef\x0d\xe4\x9b\x9b^\x8d\x1d'\xf9\x95\x0fE[U\x12\xa4\xc2\x10^X7\x90\xa9!\xe3\x03W\xe9!K\xc4Fr@/\x8b\xd5`J\xbe_\xbay\xff\xed\x06\xf7\xdar`\\[\xdaI\xbc)\x84!\xbf\x19\x87\x1f\x1a7\x7f\x1d+\\lnv;\x18B\x8azR\\\xb1Ue\xe4\x9f\xa2\xfd3)\xdajG\xa0\xdc\x15\xa0\x87\xe0'O\xd8\xa6\xe6\xc1\xb3e\xc1n!\xa9\xbe\xd8Xe\x97\xfaU\xe7\xde\xee\x847\xda\x05U\xf3\xb0\xac!\xaa\x0f\x80\x14\xf1E\xbb\xbd\xaeV0\x9e7\xef4C\x98\x0cq\x0el\xab\x08\x0ce\xf5@/\xed\xd6t\xd4|\x9f\xd6Zh\xbd\xbb\xb5\xa4<`k\x81\x0e#{\x91\xa5\xe4\x18\x82\xba\x14\xcf\xdb3\x9ew\xf9-Zw,\x16y\xf6\x90\xe6,U\x0cj\xfb}\xc8\xce\xa1{\xce$6\xd9,\xd93\x8f\xb4\x08\xd7\xa4(\xc9\xe5m\xfe\x9e1\x8c\xc3\x14\x11\xaa\xe6\xf4\xe2U\xa1!m\x8e3J\x8aw$\\\x1bZE\xd7\xe6FYu\xab\xed\xba\x1a\xadp'\xfc\xa0\\&\xc93\x93g\x0f\xfe\xf10_,\xf3\x8c\x11\x03\x05\xe9]\x00\x90'l\x1b\xbf\xb4Q7\xaf\x9fU{\xc9\xc7\x10\xa6C\xea\xcf\xcd\xf5\xff\xce\xfcfa\x8f8\xc6x8{\x042 U\x95\\\xf1:\xb9\x0dd\xcc\xb1\xaah\xcb\xa4\xa33j\x14kUQ\xa1\xc2\xc9\xee6\x86\x02\xe5^M\xe3FL\xccN\xcb\xca\xac\x9b}je/\x08\x1a\xca\x1c\x86\xab\xd9\x9c\n\xd7\xe1\x9d\xb2\x02v\x8aY\xcdr\xd6\xc2&\xd4\x12\x14\x86\xdb\xe4\x14\xf5Y\xf4\xadp\x91<\x1c.\xcc\x164&n\x97S7\x94\x13\xd7_\xbe\x00 \xca\"\x1a\xa7dA2|\xbfM\xb28\xbf}\xa3O+\xdb\xef4@\x9b\xaer\x99gq\x92\xcd>\x94D\x96\x93\xfaG\xd6\x1c\x9e\x0f\xcfxh\x9c \xcbc\x82F\xfd\xfb<\x8c\x1c\xc9\xf0\xe0i\xe8(|\xab5\x8e\xd0-t\x9f\xaa\x163y\x10\x85\xd9\x87\x92\x1c\x9d\x9dT\xe0\x1b\xe7\x11\x1a\xef\x06\xc9b\xc9{\xca/'\x9f<\xb1}\n\xe6a\xf9\x96\x84tUH\x7f'\x1b{\xd6z\x94\xcc\xae\xe3\xf8\xa8\x1d\xdc\x98\xd9\xed\xef\xbekB\xcdwp8'\xd1\xa7\x92Af\x98q\x81?$%\x94\xab%[_\x1e\xc0\x89\xce \x08.IP\xc7\xe82=['E\x9ea7\xb4J\xf56N\xcf.\xc7#\xb8\x9c'%\x8f\x0f\x95\xe5\x14n\xf3\xe2\x13\x08\xa3\xbd\xf4\x0e\xa9\xce,\xcf\xb6f\x8c\xc6I\"\xde\x13\xd6\x8fh\x0ea \xbf\xf1H\xca\xbf\xf9z\xd5\xbf\xa1\xb8\xee7\x1f~K\xf30f\xff\xd1\x08\xfc7\x1f\xa3Q\xfd\xc6\x1ds\xfc\xd6\xd7\xc1\x1f\xf3\xa2\xc8oK\x98\x16\xf9\x02N\xf2\x98\x14Y\xf2\xf7\xa2\xaf\xd4\x1f\xd1^\x14\xfe\xc1\xb5\x0f\xbe\xd6\xd7%\x17\xab\xe94\xf9\x0c(D\x84L\x98\xaf\xcf\x02p\xa24\x89>9z\xbdUE\xfb7y\x9e\x920chq\x89K\x8e\xab\xc3\x16\x07\xd7@$\xa2\x9c\xb7\xb1J\xed\x1a\xa51AU#c\\dE\xedenW\x90\xb036\x0b\xd3\xd6\x874\x89HV\x92z\x9a\xe0Y\xb0\x13\xec,\x0b\x02\xee\xe1\xaa\xa4\xf9\x02~\\%i\xec\xc1\x1789\xbe\xd4\xcao7\xde}\xbb-\x9e\x8eL\xd0~@\xddS_\xbe\xf0[\x82\x0d\xd7 \xe3\x18\xe7Z\xd2\xc8\x0e\x83Z\xb9GjVA\xbfY\x91\x1c\xb5\x93g\x0el\x9a\xfc`\xa1PP\xad\xecM\xbbOF\x92e-\xae\xa0\xab\x8d\x1a\x15$\xa4\x12=\xb9N\x9c\xacM\xea\x1daP\x12z@i\x91\xdc\xac(q3\x1f\x84\xb3\xe47\x8e\xd0\xfe7\xaa\xc2\x84\x93\xcc&2\x05\x85\x9d@Mb\xae\xbdr;'\x95\xd8\x0c\xa4~\xf2\x10\xac\xc2\xef\xe6\x03^\xde\x07\xe7Y\xb0\x83\xaa\xd6\xc9\xa3!\xd3\xd6\xd1}\x90\xd2\x118aJ\xffL\xee\xf4\x90\xbayF\x8b<\x1d\x81\x13\xd1\"m\x7f?!4\x1c\xa1\xdb\x82\xb0\xfd\xf1b\x9eLY\xcd\xa8W\xcd>\xd7C\xb0\xd0:\xb6\x03\x0e\x0dW\xb3\x90&k\x82\xf3\xd3\x86\x12\xf43v\x92\xc7\xc94!\xc5\x05\x0di}\x8d\xd4\xfe\xd4bO%\xa0\x16\xad\x1b\x83\x8aS\xc43dc\x83\xaa\x90PC\xc1\xb0\xf3\xbau\xcd\xf2\x08K\x99\xb9\xaf^\x1b\xd4_2\xf7e+=\xe1j1\xbb\xdcv\xf4\xd9k\xfc\xf7t\xf7\x95\x1e\xfd\x9a\x8b\xe4w\x9f\xeb\xe5W\x98\xfe\xec{\xb3X\xbe4b\x151d\x93h\x92S\x18\x93\xdd+!\\\xa7\xe8\xb5\xf8\"\xb9I\x93l\x86\x1eu\xa6IQ\xd2\xc3y\x92\xc6\x86)_\x8b\xab\xf6\xc4\xedc\xafH\x90d%)\xe8\x8fd\x9a\x17\xc2\xb1D]\xa1q0\x91\xad\xaeB\xd4\xc58\x0dQ_\x8b?3\xe94XM\xb7Z3\xb3ob\xdcl(07+\xeaTaK\xec\x840\x8fI\xa4\xcc\xb8]\xb8\x95\xba\xdc\xee\xba\xe0\xd7\xf7\xdc\x82\xbdCk4\xafh_\xf5\xd1\x88g\x1c\x1cZ$Q\xb4\xdaA\x91s:l2\x97\xd6\x03l\x88\x1c\xae\xba\xcf\x9d\xec\x1a\xee\xdfb\xac\x1b?\xef\\\xf1;v\x12\xf0`\x9b\x08\x89-\x0eK\x0355+\xed\x1eFl\x83\x89\x8e\xe5\xab\xc4\xef\xddK\x87|P\xcfR5\xfbZ\x0cc\xfc\xe6\x0861\xa3\x15\x8b|U\xa6w\xe7d\x99\x86\x11a$?\xe3\xe3N\xc2\xe2\xd3j\xd9DS\xeb\xb6k\x8c\x9e\xf2-\xef \x05\xcfuD\xd2d\x91P\x12_\x92\xcf\x03\x0d<\xe4\x84\x11\x8571K~\xf9\xbda\xe7\xb4\xe6\"\x1c\xe8>\x17\x9e\xa7n\xe1\xeb\x14\x08\xeb\x19\x8a\xf6\x18\xe4\xe4x=\x02\xfb\xe0\xae\xf0\xde\xcf\xf3!v\xf9u(E\xd5||\xeb\x95]-\x8b<\"e\xf9\x01=\x14\x97\x03\xc4e\x0d\xeb\xae\x9d7\x90)\"\xe67\x90\xd9u\xab+\xf0\xb2\xea\xabHS\x98\x02oXm\xf5@\xa5]\x7f|z1>\xbf\xbc>98\xff\xf3\x87\xf7=j\xf6\x88u\x0b\xe9\xd8\xc7\xe7GJ\x11\x84SJ\n6\xa7}\xd1\x0d\x06\xd9\x05\x9c\x9c\xfd<\xbe\x1e\xff\xe5\xf8\xe2\xf2\xf8\xf4O=\x1d\x9a\xf2\x0eL\x85\xb8\xf6\x9f\xd4\xa3\x8b\xf1\xc0\xf9 \x1b\xf3\xf3\x18M_\x8e\xffry}xvz9>\xbd\xeci|\xf5\xe8\x8d\x9f\x8fq-N\xcf\x8e\xc6=m/\x9b\xeb0T\xc9\xe9\x9e\xf2\x9a5\xa6>\x88\x1a\xb3{\x01\x9a\xd3\x05#\x9f\xe7\x94.G\xdb\xdb\xb7\xb7\xb7\xc1\xed\xb3 /f\xdb\xbb\xaf_\xbf\xde\xfe\xcc>kd\xf3\"\xa4s{\x99W\xdb'!\x9d\xe3\x9f\x93wZ\xc9r=3\x16{\xba\xb3\xb3\xb3]\xaeg\n\x01\xfe8C\xed%u\xd5\xe8\xe9\xb5\x0d\xf6\xc9\xc5\xc1r\xc9\x10(\xfe@S\xde\x0f\x19\x0f~\x1f\x85\xe9[y>*\x94P%\x826\xaa\xbfvV\xd3\x1f\xd6N^L\xa9\xad\xb4aI\x17\xac\x8e\x1e\xdb\xdb\x8cQ\x8d=s_\xed\xbc4\xd0\xf1\x99\xfb\xf4\xc5+\xcf\xcd\xdc\x97\xdf{AR\xfe\x1c\xa6I\\\xc9\xe6\x1a\xb9CE\x19\xdee4\x7f{\x12nV\x94\xe6\x99\xd9\xaf_4'\xd1\xa7\x9b\xfc\xb3\xf9k\xb2\xc0\xf8\xfe\xa6O\xf3$\x8e\x89\xa5\xd2\"\x8c\x93\xdc\xf2\x89\xa0\xed\xa6\xe9S\xb9\xbaY$t\xd4\xd2L\xb6i \xe9\xeb\x8d\xe2\xee\x0dv\xc8\xe3\xa0H\xfc.\xc9>10\xac?`x\x04\x99\\\xb8\xce\xab\x97N\xaf\xae\xb2\xde\xcc\n\x95X]\xadR\xa9\x9f\xc8\x93\xf2\xec\x10\xe5mR\xc7\xfc\xd5\xab\x9ev\x0c\xdePZ\xed\x88Q\xf5\xb4\xf4\xba\xd1\x92\xfc\xc5\xc002\x9a\xd2\x8a\x88\x11Ch-P\x18f2\xa1\xa8\x93\x19N\xb8.\xd6\x15\x17N\xcb\xee\xf0\xb7\x82\x84\xf1Y\x96\xde\xf1\xb78)\xc3\x9b\x94\xc4\x8c\xbcb\xfd\x1f\xa1\xcb\n\xe1 \xeb\xd7|%\xc3\x83\xc6\x10\xc2o\xd8\xad\xdfX\xd2\x12h\x0e!\xa3y\x160MH\x1a\xc3mB\xe7\xf9\x8aB\x98\xc1o\xb2\xc1\xdf`\x1efqJ\x8a@\x91\x93\x16$\x8bI\x01!\xb0\x8el\xe5\xac'XC\x00\xc7\\\x90\xc7\xeb+\xe7\xf9*\x8d\xe1\x86\xc0bEY\x171\xd4\xfeo\xc22\x0e\xbd\xf7\xfd\x16\xc0\x19\x9d\x93\xe26)\x19\x99@(\x90\x84\xbd\xab\x1d\xc8\x0b\xf8M\x8e\xf8\xb7\xc0d2n\xd9~$~\xf8\xfc?\xe2\x94\x8b\xbe\xfc\xb7\x98\xf4C\xd1\x97\x7f\xd2\xb4\xcb\xd2#H\x026\xf3\xbf\xeb\xc8?\xb5\xda\x13-\xdb\x9b\x16u\xc8m|\n\xbf\xcb\x99\x11\x94q\xdb\xfc\xbf\xd3J\xb0\xe5\x08\xe95\x9b31\xa9\xdc\xff\"\xe4S\xf8\x8d[~m\x82\xf3[\xd0\x0ckh\x94]::m\x00\xa2Oq\x0b) \x18\xbc/\xf2%\x1aE\x0c\x83\xcc\xa62td\x03^6\xbe\xc8\xa4\n-%\x16\xd1\xa4\xb8b\xc74\xe7\x9a\x1c\x06\x88\x8e/\xee\xeb\xf2\x0e\xcb\xa9D\xf5\x89\x83\xe0\xcd%\xdb\x89\x0c\xfb\xc7\xba5\xedV\xdb\x99T\x99\xafP\xd5\xdeN\xde.u!\x81|zI\xd4&d\xcd\x08\xfdY\xc7\xbe\xa6.V\x9a5\xf5\xf1\xb5\x8f68(\xbc\xa8\x12\xff_\xf6\xfew\xbdm\x1cY\x18\xc4\xbf\xf7U\x94\xf9;\xa7\x0f9\xa6\x15\xc9v\x9cD\x89\xe3\xe3v\xdc\xd3\x997\x89sbg\xfa\x9d\x9f\xc6G\x0f-A\x16'\x12\xa9CRv<\x93\x9c\xeb\xd8o{\x0d{\x01\xfb\xec%\xed^\xc2>(\x00$\x08\x14H\xcaq\xf7\xf4\xec;\xfc\x90X\x04\x88?\x85B\xa1\xaaP\x7f\xc4_\"X\xf5\x8d\x15\xc4\xdf\xee\xfb\xc4\xa6=\x8d\xbd\xeb\xa7\xea\x11\xaa\x8d\x84\xd9a\xf5Z\x1f\x81|\xdd4\x06i)vVn\xc6V\xc1\xb7+$T\x94Ql\xd7/\xe4\xfd\xa9\x1c^m|M\xb3q\xb4\"\xab\xc8vJ\xf2{\xa4\xfd\x10\xce.*\xf8\x1aFI\x10?\x1c;\xd5!\xb1\x08\xe8\xfd\x12|\xa7\xe4\x18\xb7\xcc2\xfb\xe2\x1f*\xf5\x8c\xa9\xc4\xb1]\x88\xa0\xd2f\xa0\xda)cI\xa9\xd5\xa0k7Z\x95T\x15N\xab\xcb\xd26|UO\xe5\x98\xb4/b*\x90\xb3@\x92L\x96\xc8h\x18\xc4\\@\x06\x8f#\x8a\xc4M\xb6\xc1\xc1\xaa\xa7\x95<\xd0X\xf0\x0dv\x06\n\x0bd\xae\xd6\xca%\xabN\x83\xdd\xa6)\x0e\xb9\x8f\x95\x8a2q\x9f\x8e\xcc\x87\x16\x0du\x00\x8f\xb0\x0e\xfeQ\xf0}\x82\xdc*\xda\x1f\xa2\xa0Xa>9\xe5FB\x80N-\xa2\xa4\xba\x9a\xec\xdbwFZl\xb1\x9a\xcf{i\x16#\xec\xc2\xedZE\xadV\xd1z\xff)\xa1\xfb\x89\xdd!%\xb2q\xdc\xa8cjW\x84\x87\x90\xb4\x10\x15\xe1\x04\xc4\x0fg\xcf\x9aK\x08*\x00#\xcd\x8a\xf89\x06Q\xb2\x071\x03\x7f+\xab\xdc\xb3G\x91H\x99\xb9\x95\xfal\xc4\x7f\xa1\xaa\x1e\xffp\xdf\xf8\x96\xd06\xd6\xef^\xc8\xd9y\xc1\x15\x9c\xeb\x0b\xb75\x10\x7f\x132\xa6^\xb7\xd0\xea\x12\x17\x8b\x18\x81'\xab\xaca\x85\xbd\x94\xbd\xceU\xd0I\xd7=\xb7B\x1e\x12b\xf5\x10\x91\x88wUl5\xfe\xe6\xa8^%\xb6\xaa\xc40\x84Z\xfcG\xbc\x8dV\xe9\x9a\xd1T\x07\xff\xc4\x97\x9f\xd8\x9d|\xf7\x89\xdd=\xc4Z\xd17\xcb\"Tf\x1bAV\xac/M\xaa\xbdCo\x08\xdea\xdf\x11y\xd1\x1bb\xf1\xae\x9d\xba\x9bH\xf8\xa3\x80\xfd/\x9c9\xf6=4J\x08\x14u\xf7\x1f\x8d\x0e\x87\x97\x8f\xae\xc3\x0e\xe7\x87\xbaZ\x1e1\"\x96c\xa3._\xc5\x0f\xfdV\xa0\xf4q\xda.\xa0\x1c\xee\xf2\xe2\xe1&@\x11\xe0\xf0U\x8466\xea\xa3\xb7)\x87\x95\xf8\x8dQ1Y/__ D\xf4w\x05\x83S\xbd\x18\x04\x81\x06M\xff\xb0\xff\xe5p7xx\x80V\xf8J\xd3\x8a\x07 \xce\xec\xe2\x8a\xf6\x0fP\x916\x18\xec\x9a\xd7\xe6\xf2z]\xde\xab\xef\xef\x05\x9d=\xda\"BN\xec\xb1\xe4\xbf\xd6l\xcd\x04\xdfP\x8f\xccm\xb7@h\xbbJ\xdb I\x94\x1a\xcf?\xfd\x14+\xe8C\x0csQ\xa9\xb8\xe4\x82\x8ah/z*B!\x11\x014\xb3\x8e@\x92\x04fF\x8a\x8e\xf2\xf7\x0b\xd8\xed\xe3\x95\xdb6x\xe0\xf3&\x86\xc0q5\x93a\xaeB\xf0\x02^\x16x\xa0g\xffs\x87\x16p\x9d\x1fh\xeb\xed\x1a^\xa2\x0e}\xad\x03\xbd\x01\xdb\xed?\xce\xdf\xa6\xeb\xa4h\x97\xa0\xd4R\xd1\xfd\x83n\x86RH3\x94\xdeXH\xfclZ\xdaT\xd77\x89!I d\xaa\xecr\xbb\x08\xed\x8b2\xd9k\xe9\xbc\x88U\xed\xe1\xa9mc\xaf-\x94\x9cEu\x84\xd2\xeeb\xbd\xf1\x8a\xa1\x95\xa9\xea,\x87#\xea\xad\x08\xbf\x88\"\x13\xf5\xcd!\x8c\x8a\xcb\x10\"\xebB\xbb\x11 \xaf\xa51^\x07\x11\x93\x91\x03%\xdej\x03\xa5\xbe)\x07\xda\xecM \x07\xfac\x9aM$-\xe8\x8aM\xf4bH\xe3\xder@Z\xc3(\x98\xf0\x11\x15fJ\x0crH\xf2\xe6\x1e-\xaa\xba!T3\x9aH#\xf4rd\xd8\xf0\x7f\xf0\x9e\x14\xac\xaa2\xbdo9l=\xc1\x82\xa6\xd4\x97\xbf|\x02\x99\x85\xf5_\xd5\x90\x17\x84\x9b\xa2a\xd2\x80\x86\xc9e \xf0\xb0\x0b0\xcfYA\x01\xd2\x05\xc5\xc4 E1[?\xa1\xc0\xf8\xe5\x0b\xd0\x05\x870\xba\x0c\x02\x85\xb0|\xd4\xa6{\"=jy\xe3\xe4\xd8=\x0e,\xa86\x8327\xc7h,\xac7\x96\xc9\x0e\xf9\xf9\xdb\xbe1\xcc\xe5\xec\x0093\xd6\x99.\xf7I]\xc0\xee\xae\x87#\xe7\x07\xea\x86l\xc77x\xc9'\xfe`/\xa0\xb8\x90\xbd}\x9a\x0b\xe1<\x86\xee\xaf\xa9\x8f#\xbd\xff8\xba\xdd\xed\xdeT\xc1\xdeP\x928I\xa7\x8c\x16j&\xf3(\xe3\xa5h/\xccP\x1b\xc0yI_(\xbaU)^M\x0d\x84?ARZ\x06\x0e\xf6\xf8\xde\x92\xc8P\xc0\xcbC\xd8\xdbE\xd5\xc1^\xa9[(`\x08\x1bJ\x9a\x15h\xad<\x15\xd2\xc5`\xf7)y\xdd\xbao\xde\xc2b\x98\xc7\x91`\xa1${si\xb0\xe3k8\x04u\x0d]\xe9V\xeaurB\xfbR\xaf\x81q\x0e\xcb \x80\xf5\xb2 \x86,\xa8+k\xec\xdb\x89\x85\x90\xeae\xde\xc3M\x97[\x18a\xf3\xf7\x18\xaa\x8b\x05|\xdfD\x8dJ\x0fdf,\xf2\x84\xe24\xa15\xe9\xd3\x0c\xe7\xa4\xd4Ex\xb5\x8c8\xa8$\xd2yO\x1a\xf7\xaam~X\x0f\xfe\x9e\xe8w\x01\xc2\x8eK\xf4\x94\x04\xbc\xea\xec\xbe\x08\xb5\xfb\xecI a\x8c>\x83j5\xcff!4\x82\xbe\x93\xbc\xa2\xf7\xe3\xcaJ\xd3\xb2eA&1\xd2a\xe7\xb3\xde\xd5]\xc1\xde\x08u\x12\xcd\xf8b6\x9a\"\xe8\xe5\xac\xf0\xc5\x0f\x0cb\xdd\xe6\xdec\x8e^\x05\x87\xc4\xf5\x9b\xc7yo*\xe6\xa5R \x0e!\xe2EJmm\x16\xba\xc1\xa0\x00\xaam\xfc\x01n\xf2G\xfa\xc6\xff\xef\xbe\xd8\xf8\xfa\xbeG\x94\xc4\xa8\x0b\xc5\xfc\x03\x9b\xac\xb3<\xc6$\x86\xebP\xf8r\xf1\xf7mWB\xb8w\x8d\x8dk\xedX\xc5\x95H\xaabs\xab\x9e\xa7|(\x84s\xb8f\x1c%\xe84z\xda\xce\xd2u\x82~\xbcY\x9a\x16\x8e\x9c\x98\xe6~\xc6I\xce\xa3\xfc\xa3BhmB\xc0\xec`\xf3q\x15\xc4\xb0\x99{\x16&B$fuq\x8e\x01\xcb{ \x94\xfe&u\xec\xc5c\x90\xfc\x1a\x14\xf4}\xe4\xc0\x02\x02\xd9\xd4\xf3\x95\xcc\\V^\x94\xb9\xc6\xa7\xae\xdbb\xdf\xb4u\xd5\x9f\x08\x15\xaar\xd4\xeeyjg|\xd4qV\xe9(\xb9l\x99\x18\xb9\xdb\xaa\xe4w_\xeb\xb2~3\xef^\xa2E\xa1\x19(;\"yH\xc3\x12\x91\x92\xbdL\xf9\xa9l\x9cD\x96,\xe1K\x89\xb9 \x12\xf9\x13\x0fl.\x89\xc8\xdfe.fyh\xf0wE\xc6\x98\xe5\xd8EN\x14\xcd\xb5Y]B\xf0q\xdbh{\xa3\xe8!w)l\xb1:\xc6\xd0\xa8d \xcb7Q\x08\xef\x83\xc7\xa6\xbeD\x08\xefOLY_\xba8\x0e\x1e\x93.\x8e\xcf\x06OZ%\xac\x86k\x04\xce\x06Q\x97\xc0\xbc\x81]G\x19\x17\xf2\xf7\x1ce\\\xc8\xdfw\x94q\xf1\xfe\xc0Q\xb6\x82Cx\x0c\xea:\x9cH\xa2<\x05y\xfd\xbd&iV9\xd9\"\xe4\xb4w\xde\xc8D\xdf\x84\xb0\x0c1\xd1\x1bnKL\xea\x96\xfa\xd7A\x08W\x98kv\x8d\xd9\xe4\xf6\x82\x10\xc6\xfcL\xf1\xef*6\xfbV\x90\x99S\xf4\x05?\x82)\xefo\xccE\xa4\\\xfd\xeaW\x06R\xcfa\x0c/\xe1\xf69\xdc\xba\xb6*\xdf\xa6\xfe\nc_p\xa2,\xa3\xe4/\xe1\x10\xae\xfc\x1b8\x84\xbb\xd1\xede\x08\xb7!\xf0\xc1\x99Z>\xb3\xa1$\x80\xd3\xd1-\xe7\xf5\x974\x11\xe1OI\xc5\x96A\xb7TA\xa0\x18\x9a\xbdf\xbf\x17\xd0\xcfjw\xff\xa0\x9a{\xdc\xb9\xb9\x9b\x0e\xad\x1dtn\xed\xb6Ck\xbb\xed\xad\x9d\ny\xe5\xc6\xbd$\xda\x891i\xe4\x7f\x14\n\xc3\x11\x17K\x86\x80\xd9\xf5&p\x04\x13\x18\xc2i\xad\xba\xe9\xeax/\xcd\xa9\x14\xdb\xc4a^j$\x8a\x10\xbc*\xd3\xb7g\xfa^H\xd3z\x9d\x0d\xe3T\x13Sv\xa5Y\xfcW\x95\xde\x1d\xcf\xdf\xf2\xe5\xf1\x04\xed\xca\xa4-\xda\x0fQ\x1eO\x8e\xd7\xc5\x9c%E\\\xa6bpV\xff1\xcd\x96\xef\xa3,Z\xe6F\xad\xd5jA~\xfe\xbeJ V\xf4V\x19;V\x05\xaf\x97\"!1\x16\x9c\x9c\xbd\xfb\xf1\xf5\xef?~8\x1d\x1f\x7f\xbc\xf8 _\xfd\xf1\xf8\xcd\xebW\xc7\x17\xa7\xf8\x83\xbf=\xfb\xf0\xfa\xff\x7f:>\xe3\x7f\xee\xe2\xcb\xf7\xb2\xbaU\xf0\xe6\xec\xf7g\x1f/\xea\x1f\xe2\xaf\xf3\x9f\xce~\xc6O\xc6\xef\xcf\xde\x7f|\x0f\x87\x8a(|W\x81T\x86\xcf\xf5\x13\x7f\xff\xb1yE\x9f\xca\x92\xdd=\xea\xf2\x1e\xbf\x19\x04\xb5C*\x9f\xa7\xb7\xaf\xf8\xa2\xc6\x1c4\x9d|\x9e\xecm_`\xea\xf9 A\xa1\xa3\xbbE\x1aM\x87\xcdbG\xb9\x16\xdf\xd2;A\xfe\xbb\xf5\xbeH\xaf\xd3u'V\xdf\xd5\xf5\xea\xbe]\x97\x13?\xe3\x7f\xed~\xcb\x18\xa6\xf7\x1d\xc3\x04\xa3=\xaf\x05\xe2\x7f\xcb\x08\xe6\xf7\x19A\x1d\xb1#\x85\xbe\xfdg&\xfe\xaee\xd1\x9ee\x96\x92\x0bV\xa7OZ\x9e\x10nEJn\x13&\x1e\x15\xf5\x92\x8a\x1c{zJ\xacv\xcf\xa26\x89\x89c'{|\xab\x8dW\xe9j\xbd\xf2\xec+\x8c:%\xf0J\xcc0\xaa\xae\xea\xf4\xc3\x13\xc8kT\x9ab\xcaK\x17\xf9\xf1V\x19\x1b\x97\xed\x8fSD=/\xa4\x89\x98gU4\xa0?\x17}i\xc4\xd0S\x17\x97\xd8\xa6E8\xbd\x12\xe1p\x10^\x8d\x1a9\xe8o+NV\x9c\x1c\xc5\x95\x94\xcay\xdcp\xc7X\xb3!\xe2m\xd1cY\xd6XKx\xd2\xf3\xc6\xe8\xf2H\xc4,K?\xb1\x84\xae ,\xa8\xa5[#]e!\xf2RM\xe6l\x19\xd15&\"\xc2E\xb4t\xf8\xfb\x8b\x9b\xb1kV\xf8\xdel\x91\xdeR\xe1\x82d\xc4\xf4uO\xe2x/\xbf\x8d\xae\xafY\xf6\xf1\xf5\x076\xc5\xb8\xcf\x822\x85\xe0E\xe51+t\x063\xcep\x88\x1c;\xbd\x84\xdd\xf2e;\xcd\xcc\xa4\xfe\xea\xe1\x8d\xbc\x9e\x92G\x04\x7f\xf2t\x9dM\xd8P\xe5\x90\xa7\xe1\xc1n\xd8b\x08\xdem\x94%qr\xed\xa8%%\xc1!x\n\x8f\xc4\x91\xbf\x8c\xee\xe0\x8a\xc1\x1a\xddgCXEy\xce\xa6\x90\xa3y\xc5m\x94\x83\x88\x0e\x86J\x8e\x9ce7,\x83\xf7F\x95\xe4\xdf\n\x89ml*\xc2|a\x1eRQ\x9b\xb0C\x0cB\x88z\x18J\x0c\xed+~M\x10a\xafm\x00\xf2\xfb!\xc4j\xdd\x03?\xa2<\x821\x13\x97qH5\x0c\xdf\no\xa8\x1e\xdc C\x88\x88.\\$U\xa7\n\x14\xaf\xf6\xeb\x92\x04\xd6\xb8\x11c\x11X\xc3\xb9\x11\x059(\x13\xab\x91u\xd62\x84\x87\x98\xa0\x9b$Tu.\xac\x8bt\xf5L\x84zu\x11\xb3\xa4x\xedhk\xa6\xd59g\x93\x8c92\x9b\xaf\x9c&\xba\xfc\xb9\xce\xa2\xa4\x18\x8b\xf3\xdfS\x03s`\x1e\x7f\xf2I\xca\xabrp\xa6+\x96K\xfbF |\x16\x01\xac+A\xf5\xa0\xc7\x9e\xa3l.}\x15\xcd\xf7JKy\xc5\xa5 A\xc0\x16p\x04\xf3^\x9dL\x1c\x82\x87\xf2\x06\x9a_\xf2\x1d\x92\xf7\xae\x8a4\n\xfc\xa8\xcc\xf8\xba\xc6\xbbM^\x96V\xbbgEy\x9d\xf3G-:\x89\xfc\xae\x8f\x14 \x87\xb0&\xe9\x8a\xcc\xc1[\xce\xc2\x9f\xa0\x06`*\x97s\x1cs\x08M\x82\x10f\xf5\xf79\xae3\xdf<\xe8\xba\xd5y\xf2\x93r\xf2\xb3\x00\xd3\xec\x99\xf2\x9b\x83&\\\xa5\xd3\xbb\xa1ji\x1d/\xa6\\8{\x15\x15Q\xe0\xaf\x1c\x8a\xcdu\xb6\x18\x8a\xe0\xce\xbe\x87T\xe3c\xb60Y\x0e\xf5\x08\xb8\xc6\x0eD`\xd1\x94e9\xc9\x96\xf2\x07AH\xb2\xcdPR3\xe2N\xdcI\xafB\xb7\xb0\xf9[\"U\xa9\xac\xc1w\xdf\xb7\x10\xb3f\xe2\xb2\xeeH\\l\x93b\xfd\xa9a\xe7\xb0\xcb\xce\xdc\x84\x8a\xd0\xc1\x00\xd4S#lr\xfbL26eI\x11G\x8b\xbc\x9d\xc4\xa5m\xb4\xcdI\xa3\x1eb{M\xee\xb3e6\xd9{r\x83\xb4\xec=\"r~\xc7\x0d\xe4\xd6\xe9\xb4\xdb\x00\xb98\xf3D\xba:\n\xc6\xf6c\xb6hV\n;m\x8f\xb3\xb2\x8fV!\xa1h\xe5\x1b\x8a\x96\xadVt\xd8j\xc57o\xb5\x1a\xbaG\xfa\xbe\x1bO8\xc7\xefF\xf7 f\x08(z\x13g\xd81\xac\xa5\x0e\xa6!8`\xa1\xd5\x12\xc7\xd4\x10\xd6\xee\x9aj\x11\xc7\xeb,\x1e\x12V\x04\xd0\xb8\xc3\xb2\x07\xd8af\xd2U\xf5\xb4\xef\xb0t\x93\x1df'\x9c\xbe\xd7\x0e\xa2\x95\xa8\xff\xdcJ\xb5\xe7a\xb6\xd2o\xe6\xd4\xfa\xbbm\xe3\xbf\xff\xe6\xbc\xff\xf1\xb7\xd9\xe6\xfc\xa5\x8e\xbf\xeaZ\xe4\xc1x\xc7\x99C\x13%\x90\xfe\x9a\x152\xeb\x1f]+\xef\xc6\x7f.:i\xcf\x84\x824\x8d\xf2\xbds\x0c\xae\x9e\xbaR\x15 \xbdh\xbeb\x93\x96\x8a\xabrx-\x15\xa7Ho8\xe68\x96\x0e\xcbQ6\xa0+\xdc\x94W2(}\xcd\xe1\x08\xfe\xf6\x15\x9cR\xc6\x12\xdb\x93\x08AW\xb9\xae\xb7\xb8T-.\xe9\xeaw-\xec\xf9\x95\xd05dD\xa4 \xfe\x8c[4\x97\xb7p\x08\xfeJ\xc3\x07\x1f\xad\xe2\xff\xf65\xe8E\xd3)\xde\x11E\x8b\xff\xe0\xf0\x11\xd6\xfa\x82-\xa3\xdb:%\xae\xaf\xf4\xb2Y/\xce\xcf\x8e\xcf\xf7\xfc\x80\xcb\xb0\xfd\x10\xa2J\xa0\xbe\na\xd2\x13\xb1\xf7\xd9\xf4\x1cul\xbe\xc8\xac\x0cC\xa2\xee\x8c\xcfXV\x08\xeb^\xe2\xbaU\xd1-\x1c\xd5\"\xf6\x89\xa6\xb2\xaa\xa9\xdb@\\\xa6\x9f\xca\xb4\xf4\x87`\x08\xfa\x7f\xfb\x1a\x82,\x0c\xe1\x96\xb2\xe3\xe3[\xee3\x1c\xc2i\xe9\xd1\xe0;\x88\xc89\xd1\xbc\x93\xa8\xf2\xf3|\x85a\xcc+\xd9\xf2\xd1_\xf24 \xa1`\x9f\x8bG\xabE\x14'!\xfc\xee\xd1\xef\x1a\xa8\xbcw\"\x82[\xee\\\xdc\xad\x98g4\xf6y\xe7\xf6\xf6vg\x96f\xcb\x9du\xb6` ?\n\xa6\xb6b\x13\x04\xb5\xba\xa6\\\xb3z3VL\xe6\x8eY }\xfd\xec\xd8'\x18\xd6i\x08\xde*\xcd\xcd\xdb\x0c\xf5\x94d\xf5\x9c.\x97\x12\xfd\x8dc_\xe0i\xe18\xf9e\x9c\x1bt\xf3\xe2`N\xb3!\xac\xfd\xa0g\xbfw}\x9f\xaf\xd2$gD\x03V\x81\xd5\xc0\xd7\xa0\xc7\xf92\xbf\x99[\x02\x8d+\xd3,KYo\xcaO<\xf7\x92#\xf5\x97.\x91B\x1b\xfd\xe5\x0bx\xaes\x0d\xd4\x15\x88\xfc\x02;9\xd5>\xa3\xed X/\xfd\x84\x0e\xcc_\xbe@\x06G\xb0hWw\x83\xa6\xf2v\xd0Z\xe8\xa8\xd2\x86\x8e\xeaqhP\x7f\x13\x16\x85\xa0T\xe0yG\x158\x94\x8c\xc1\xd8=\x00\xa9\n\xb7\xf9zP\xdd\xfd\x03\x00\x8f\xf5\xf2\"*\xd6\xf9\x05\xfb\xec\x9a\x08\x85\xe6\x98\xaai\x03<\xaf\xacQY\xa0l\xfch\x04D\xcb\xc5r\xb7\x89\x9b]\xf5K\xec\x90\x06\xae\xf9\xa6\x0c\x00P\xfb\xc4m\xf2C\xe7\xa6\xd2\x1f%\xdbh!M*\x17\xad#}\x03\x8bL\xa4\xcd\xe6E\x99\xdc\xb9\xc2sp\xfb\x10\xbc\x10\x98H\x16%\xc2\x04\xe0\x0ft\xee\xc5\xbf\xc6S\x96O\xb2x\x85b\x9e\xfe\x91\xf6\xbe\xf6\xa9\xfeA\x93m\x92\x96k\xcb\xf6\x0e\x02\xa0|\x86\x00\xfd\xec\x7f\xf3\x18\xbd\x01\x1a\xd7^\xfd\xf6l\xab\x10\xad\xfe\x14-\x17\x82\x81s\x99\x10\x95\x19\xa7\xc8\xe8\xbb\x98k*\x15!U\xeb&\x12Y\xb3\x89\x84\x91\xbb\xb6v\xb7o\x0d\xac\xd1\xd8\x94\xdedR\xea\x89\xab\x0bk\x0c\x87\x1cM-g\xea\xc6\xc4p\xb2\x19\x91\x0fT\x13X8\xa2^\xcc\xb3\xf46\xe1\xa8\xaa\xd3\x9f 4q\xfe\xb7\xb7\xf4\x8b4\x9a2a\xc8vq\xf6\xfb\xdf\xbf9\x1d\x0b\xeb\x8bs|\xf5\xf1\xfd\xab\xe3\x0b\xfdU3^\x98\x16\xc5\xbf\x14Z\xacUh\x86Flh\xb1=\"\xb4\x11\xa5\xed\x91q\xd2s\x0e\x9e\xd9 *PrH\x16\xe9\xf5\xf5\xe2\x9b\xcc\xd1\x08\xe5\xe5}\xac\xa1\x88e\x93\x064\xf9X@\x8ep\xc9&\x96\xbf\xfcH\xcc\xcc\xd3W\xa0D\x9br\xb2m\xba\x86\x1a\xfd\xbf\x07\xf6\x97\xafK;\xadL}D\x07AG\x03\xfd<\xc3\x8bmi\xae\xcf\x92\x9b\x9aA\x7f!\xcd\x17\x95\xc9?\x92\x1b\xe4e\x95}?\xe7\xbcr\xcd\xe0\x7f\x95\xe6\xc20[\xfdz\x1bq\xc1M\xf5%\xed\xb7e1\x9e\x9e\xd6Z\x90j\xe3\xf1U:\xbd\x1b#\xf6y\xb6,e5&\xb3T\x8d/\xfe\xf4\x9enN2Vx\xbfk4\x18\xd5\x1b<\x7f\x7f\xf6\xee\xfc\xb4\xa9E\xb1\xd3\x9b\x9a\\\xd7\xe1\xc5\xc14\xfe\xe3\xf1\x87\xd7\xc7?\xbc9%\xe6,\xa06\xbe\x91\x08/\xa7\x8d-\xde\xeb\xd8\xbf\xd1\x02\x95R1\xc2\x12\x7f\xb7O\xba\xc2\x0e\x1e\x9b\xf1\xad\x84/\xecc\xb3\xbap\x85}b\xbe\x16\xee$\xfb\x8f\xcd\xf0\xa8\x0b\xe19kjK&b,\xfbf\xf5\x99\x18\xcc\xb3\xc0\xf7\xe2\x82e\x11Fv\xaaWYq\xfe\xdf\x1f]b,\x14\x8c\x9c\x91p\x8e\x1a\xe2\x04\xe4K\xdf\xf4ui\x94\xd2@Sl\xcc\xe3\xbc\xbe-*\xc8:\xdd}Q\xfa\x9a\x87\xca\xd3\xd5l>\xf7\x13\xacdFQ\xe2+u\x17\xc2U\x08c\xe1\xea\xda\xae\xe0\xc50\x10\x98 \x0b\xf3R\x9c\x94\x9e\x8e'V~Z\xf5tr;\x15148\xe4\x1a\xf2\xad\x89J\x88\x9fM\xd5\x80\x96{\x1b\xebk\xdf$\xec\x16\x12\xe9\xa7\xee\xc8\xe7\xa6\x9eMT\xa9\x9b\x8c\xa8\xfbH\xec\xbe\x08\xf3\x13\xf4P\xc4\x10\xb5\xaf\x15B\xdb\x95>K\x07 \x0e[8<\xa4n\xe3\xce\x85\xd8k\xbd?\x11\xdc\x02\x1d#\x8e?\x9f\xe0\x10NF3\xcc\xfas2\xf2\xfe\xfd\xdf\xcb\x8d\x85\xafn8>\x9d\x8cn.\xed/\x8f\xe1\x10>\xa1\xc3\xb4\x7fC\xdc|\x9d\xc1!\xdc\xc0\x11|\x86#\xb8\xf5=\x96\x14Y\xccr/\x80!\x1c\x97~\xd9\xf6g\xe8\xd4\x85\xb1&\x84~\x1f\xfb\xef\xc9\xafyoF\x82@\x8e\xf5\xefQ\x1f?\x86C\x98\xf8\xefeT6v\x0b,\x08\x02\x8c\xe5i\x86\xbc\xe2\xd5\xc7\x98\xb3\x13?\\\xf8\xe3\x10N\xe55\xb7\xb8\x93S\xa8\xa0\xdf1\x8c%\x94\"^}\x16\xc24\x08B\xf8\xcc[\xc0\xbc_\xe5\x02\xf1\x1e?\x89X \xbc\xf5s\x19i\xf4\xb8#\x95\xf9T\x05c0\xb4i8\xba\xef\xbf\x87\xadk\x0c>\x8f[}\xeb\\,\x90\x1a\xda \x0e\xed8\x08a=*\xb8\xa8z\xcc\xff:\xe5\x7fMC |\xa49\xfc\xee\x9c\xf6ObNC\\D\xbej\xb7\xbe\x9a\xa6\xe3\xaeS\xc4Y^V\xd5\x91n8*\xcbU\x1d\xc2\x19\xb1U\xe0\x9a\xdeV(\xd8_I\x1f}\xfc\xff\x84O=\xe6S\xbf\n\xe1ntuI\\\xa8\xa2\x03x\xea\xa7\xbd\xf7\xb0\x0di\xefG\xf8\x1d\x08o\xff\xf3\x00\xe9\xef\x1d\x1d\x80e\xc3(\xf7\xfa)\xb0\x95\xf8\xfb\xfb\xa8\xd5\xddJ\xfc\xc7\x83\xc0\x9dQP\xf6\xf5\x04\xb6\x0e\x1d\x829?\x80\x0f\x02\x99\x9f>\x04/\xb2ds\x10\xc9w\x86\xedDL\xf5f\x83\xdc\xc0\xb6^\xe5\\!\xefg:\x07\xdaxLG\xc9|B\xe5\x85\xe1l\xc1^\xe0[9cd\xb0\x8d\x83A\xe0{\xafO\xc7\xef?\x9c]\x9cy\xf7\x0e\xb0\x11\"g\x92\x92\x894\x84\xc2\xd2z\xbdp\xc5M\xc3P\x82\xeb\x00\x12\x0ci\x89z{\x7f\x8d\xb0\xc0\xa8\x902\xc4/\xf1\xe1\xf32 \x0e\xbc\x84\xfcy \xbf\xe3G\xc0(\xdf\xde\xbe\x14f2\xff\x1d\xfb\x0bl\xed\xcb\x97\xaa5\x1a=\xcd\xa8\xe2\x9d\x17hw\x10\xf4T\nb\x1a\xa4\x99\xb8\x8fP\x95d\xd0\xdd\xcdzq\xa1\x01u\x0bb/\xb5\x8d\x0e&\x1d\xa7GN\x06\xd3\xac\x07\x8btj\xe4$\x8a\x08\xcdy\x8ca\xe8F\xf1%\x0c\xe9\x13\xc1\x0en\xaf\x07 \xad\x97\x1e\x19\x91\xef\xab\xc3hX\xffL\x86\x88:\x82\x08\x86T\xe4\xf8\xce\xd0\xdf\xdb#\xa0\x9f\x8d\xbc\xf1x\x92fl\xe7/\xf98\x9fG\x19\x9b\x8e\xc7\xe2\xa8\xf7]e\x87\xf0\xb7\xaf\xad\x1b\xcf\x01\xd2t$r8\xfa\xa9\xd0\x9c\xfe\xedk\xd02\x1f\x17=\xbd\x9fF\x91%\xeb%\xcb\xb8\xf04\x84-\x7f\x00\xdf\x03E\x01\x94\xf7\xb4\xaa\xb7\xeb\xa8w\x9b\xc5\x85\xaa\xb3\xef\xa8\xa3\x14#\xb5\x82o\xba\xd8\xa9Z.\xb7\xef\xfe\xe3\xc0\xdf\xd2\xb5\xd4\xfc\xddA\xe0\xcbh\xbf\xe0\x89?\xbc\xa6$\x1a\xa8g\x1e\x17p\x08\xd2\xa2\xaeT\xca\x8f\xe3\xfa\xcdG\xe8>U\xf8\x98\x98L}/\xda\xb3!Rj\xe0\xc71I\xc5\x12xyXQ\xc6#b\x15%L]<\xe34M\x98\x9d\xe0\x15\x86\x18\xcc\x0d2\x91\x7f\xa0\x9a\xdb\xf6a\x19V\x8f:Feg\x04\xaf,\xfb\x19\xd4\xfb\xd1\x10z\xc3cr0\xa0\x03R=\xde\xbb\xefv++4\x05\xd3\x8fC\x88\xc4y(\x17>\xf5\x0bS&V\x0f\x1e\x05~\xe2(\x15A\xa6]\xd1\xd2\xe4\x98rx\x01}\xe1\xd7\xfeR\xb8V28\x02\xcf+\x85\x00\xbeP1\xb6\xa4\x05/\xcc\x83\x00^\xc0\xe3\xc7\xbb\xcf\x0e\x90\xbd\x83\x97\xf0\xf8`o\xf0L4\xb4\x0d\x03\xe9\xa8\xc9iKd}\xcc+\x88\x06\x0e\xf6v\xb1\xf3\x887\xf0do\x7fO\xf6/\xeacG0\xc44H\xe2m\xbe\x88'\xcc\xcfC\xec\x04s\xd5D\xb0#\x9b\xd9\xe6\xe3\xdc\x91\x83z\xf1\x02\x06\xfd\x00\xb6\xe1\xe0\xf1\xe3\xbd\x83_v\xb7\x9b\xfa\x11\xa9\xab1\xb1G\x86-3\xe9\xbeT\xd5\x98\x1a\x9c\xb5\x0c\xf1a\x9e\xc6RWs@\xebj\x06\x96ng\"\xeb\x9b\x83\x94\xca\x9a'\xffT\xd6\x10\xcf?\x955\xfa\xf3Oe\x0d>\xffT\xd6\xfcSY\xf3Oe\xcd/\xa6\xacqjj\x06duw\x18\xd1\x03\xc7\xdd\xc9\xe3\xbe\x83o\xd3\xc2\xb3w\x12DQ\xfcL\xdb$\xa5\x0d\xf9\xca\xb7Q1\xef-\xa3\xcf6\xcf J\xe2\xa4\xc3 \xe9\x18\xb0d\xb4\x19\xf2\\}8\xe2b4l\x83\n\xc2\x19\xfb\xcc\x88\xc9\x0f\x1b\xac\x8f\x9e\xc8#4\xb2\x96\xc4\xb9\x9e1c%_\xbf\xceOK\xb9/,\xd27\xe9$Z0)\x1b\x95)Qpo\x9c\xcd\xbc^\xbeZ\xc4\x85\xef\x85\xde\x86\xec\xfb\xde\xde\xaf\xa2Dq\x04\xad\xdd\xa5\x95i\xc8o\xe5+6A\xfa}\x8f\x15\x95\xea\xb2H.hk\xca\x14\xcd\x13,\xc2CH\xfd\x16Q\x923?\nF\xf1e \x13\xef\xa4z\x92\xf3\xeeh-b\x17\x87J)h\xddR\n^v\xff\x89 \xab\\nL\x07/{`\xf2\xc4\x13Zs\xc2Y\xd9\x89\xca\xcdl\xb3\xb0\x93^\xce\x8a\xd7\xcb%\x9b\xc6Q\xc1l~u\xd2\x9b,X\x949j\xcc\xb1\xc6[a4\x7f2\x8f\x92\x84\x19~\x867X\xe3U\x9c\xaf\xa2bb\x98},m\xe5\xe55\x11\xca\xe7\xae\xed@CA\x1e\x0ea\x9b\x9fe6I\xe6'\xcf\xb5\x99:\x85\xce\x90\x01\x9a\xe1\xc5\xb5\x93\x9b\x95A\xd2x\x85\x10\n\x9f\xf0 \xa8\xbd1\xa6s\xd5\xcad\xdf\xc9\\ \xc2Q\xa5\xdeV5\"<\x96\xa7(D\xae\x1a\x9b\xac\xa5\xfd\x18]\n\xad\xed\xe09D\xd95n\xed\xbcR\xec&\xcf\x03\x95C\xa3,\x1d%\xdb\xdb\xe6I'\xf7\xcf\xf5h{{y\xd9\xb6\xd0\x02(\x7f\xe5\x0c&_\x87\x9b^\x92\xde\xb6\xb6\x86\xb5\x9c\x0d\xcd\xe1H(\x13|$\x93\xec\x16\xe6A\x8f\xd3\xbd\xdd\x10R\xfcc\xd0K\x93*\xb4\xf9\x95\x08T\x1f\xf9qo\x95\xe6\x85\xdc\x85Hk\x06\x18\xcfi\xd2\x8b\xa6\xd3\xd3\x1b\x96\x14o\xe2\xbc` C\x9aN.\x86\xd6\x00r{\x93^\xbc\xe4=\x9e\xa3\x17P\xceG\xd6<\xb5\x89>\x06<@=/\x04\xefw\xf54\x07\xf6\x88|ON\xc8C\xaejK\x8c\x1c]\xa5\xd2$c\xd1\xf4\x0e\x03\xee\x89p|(]/|O\xf8&a\xaa\x15\xf7\x88\xf2^\xb4Z\xb1d\x8a\xf9\xe8}\xed\xab\xa0g\xb7\xdc\x86\xc3y/c\xcb\xf4\x86\x89\xc6\x90g\x0e\xcb}\xea\xf4\x1c\x80\xa6\xcc\x959+.\xe2%K\xd7\x85\x86\x11\x9c\xe9\xa8\xbe\x0f\xeaF\xb3\xd6\xf7V\xa4Y\xa4\xd5C\x98VM\xe0_]\xb9\x15\xf7`\x1b\x9doh:\x8a\xeaF\x9a\x1f\xbf\x19\x02k'\x9b]\x1cv\xdc]\x13\"\x1f\xc8\xae\xdb:n\x81\xde\xa6\xec\xce\x13:D\xff\xe0I{V3G\x9e\x8f\x0cie\xea\x17vj8\x91\x90\xa8-\xb5q\xdc\x9b\xb9\xb2\xfe\xfa\xfd\x10\x92^\xc6\xf2tq\xc3\x02\x8cl\x8f\xa9\xfc\x96\xb1\x96\xdfjC\xc0X\x10\x10\x80yF+\x01\x91\x0dDg\x86v&\x90\xe2\x00\xe9|\xf3\x98\xc7\x8f\xcb\xc9Z\xdaT\x91wF\xb2x[[\x9c\xc9\xf3>\xb0\xeb\xd3\xcf+\xa4\x8di-%\xe6\x86s\xb6\xf8<\x95\xb0\x81\x9c\xf3\xe3{\xe1\x82ZN?\xed\xc9\xab7\x11\x9aA^\\\x89w\x9cK\xb10>\"\xc2\"F\xd2A\xc0O\xf0\x161\xeb\x9d\xa3C(\x17ac\xb7\x05\x00\x88l\x9e\xb6\nA&\x8c\xf1B\x88\xee\x0d\xc4g\xae\xdb\x84Zf\x97Nr\xa9\xa6\xeb\xc9\xea\xc9\xc57\x1a\xd1\xee\x9eC\xa69\xd8Cyc\x12\x15\xbe'\xf8)O0\x1dB\xc2\xab\x875\x9e\xd5\xeez5\xbe\xf4]\xb4d\xbf\x8e\x9c\xbdk\"\xa2\xdc\x934~Z\xe6\x0fR\x9aylj\xce\x854c\xdd\x9eKaf\xcf\x14Z\x16.@\xbc\x92\x0e\xc8\xba\xe4&\xe0&lS\x8e`\x01- peF$\xcc\x98'\xae\xf9\"\xbf\x90\xda\xb7\xd2\xccL|`\x1eH_\xad\xaedN\xa5\x92\xf4\xa6\xfeV\xd6\x9bii\xfdB`\xa3\xe2\xb2m\xc5\xcc\xe5Jp\xa7\x96\xb1C\x1el;\xa8D\xae\xf8\xc9\xa5\xe0\x8a-~\xa6\x13R\xb9Y\x94\xd2\xdd3\xf1\x1f\xef\x99\x18Ty\xeb\xd4\xfdr\xbat\xd9v\xed\xf4\xec\x80\xde\xa4O\xcc\xf7\xb1c3\x08\xf4\xb6\xac=\xe4\xbd\x93\x95tGS\x94Ey\x1e_;\xd4Q[\xb8\xb5[L\xaa\x944KE\xb4-\x1c\xef9\x92\x9c\xdf-\xaf\xd2\x05\x15[\x06\xb9\xe9\xe8j2e\xb3\xeby\xfc\x97O\x8be\x92\xae\xfe+\xcb\x0b\x8f<)e:\xd1'!dJ\xbf\xe4\x05\xbdY\x9a\x9dF\xad\xd1\x1a\nq\x86\x18\x0e\xadA(,\xc4r\xe1l\x1b\xf0\x0e\xca\xf3I\xdc\x95\x89\xa2\"\x08d\x98L\x0f\x93\xeeVn\x16_\xeb\xcc~\x9b\xd7\\\x84{\x9e\xc3\xdc\x94rC\xa49\x83PFK\x9f\x85\xa8!\x89{\xb3\xe7\x90\xc3KX<\xb7\xf9\xd2\xb2\xe5\x95\x90=\xd7\x9ap\xbc\xe0\xc2q(\x14!\\\xfe\xf3\xa7\xe510\xf1\xa7B\x98\xf1\xa7A\x88\x8a\x90y9\x86\xa5H\xc2u\x03/a\xf9<\x00I&\xa6!\xead\xe6\xa3eiQ\x95\x8cV\xa8S\x1f\xad\x1c2\xb8\x96a\x0d\x86\xdd\xb2J\xb5\xed\x9eA\x9f\xe6\xd7\x06\xa6nI\xec\x9e\xdd\x03j\xf7\xf8\xbc\xe0\x80s\x8f\xfe`\xf7 \xa8\xd9{<\xc5\xd7\x8f\xf7\x1e\x93)\x1a\xd6\xd4\x98\xa1t\xd7\xcc\xd2U\xae\xb9\xfdV)\xd4\x95_o\xc6f\xb9\xcc\xe2\xc7\x7f\n\xafh\x9c\x19\xea\xef5Jc\xf7\x9d\xff\x1d\xfb^\xd4\xdd\xa8\xd7\x9aof\x9c\x7f`\xd1\xa4\xd0\xf3\x10\xf2\xed\xa2W\xc9e>\xfd6\x9e\xb1\x8c\x85e\xe4\x82wg\x89\xc7\xbc\xbe[\x87e\xca\xf8\xa7\x8f\xbd\xa0>\xbf\x9e\x91\xd3\xbf\xbc\xaf\x0ceD\x05\xa2\xae\xcab\xafR\xb7\x85\xe0\xa9)\xd4u\x06\xfa$gi6a\x1f\xed\x00\x01\xe4j\x19\x1d\xfeX}\xab\x04x\xd6qp,\x04O\xeb\xba>\xbeE-\xab\xf1Z\xcfj\x9c\xd7\xf3#\xb3[X\xd4^\x1a)\x97s.\xd3\xe5z\x03ZkA\xfd\xcb8\x7f\xbf\xce\x98\x85\x15[\xfd&\x95AY\xd3r\xe5\xe2\x8di\xa5\xb9\x86\xa8p_\x82\x92\xf8\xcf\x02\x9b\xbc\x18\x0bc\xf5l\xfe\x90\xae\xafa\x861\x0c\xba\xfe\x07\x91\xcb\x13q\xb5k\x1fjk\x10\xf5+X;nb\xee\xbf\x04\n\xe8z\xc2\xb0\x07n\x9aT'\n^\x84\xef.\xf1\x17\xdf\xb8\xf5_\xbe\x97q\xdc\xed1q\xaf\xe4\xa1\xc9\xf0A\x7f\xd0\xdf\xfb\xc5F\x9a\xf8\x8f\xf7\xefm\x9d\x86\xe2\xd6\xd6`C\xd6\x98\x1eP\xed\x82\xf0\xfc\xf4\xe4\xc3\xe9\xc5\xf8\xd5\xd9\xf8\xdd\xd9\xc5\xf8\xfd\xf1\xf9\xf9\xf8\xe2\xa7\xd7\xe7\xe3\xb3\x0f\xe3?\x9d}\x1c\xff\xfc\xfa\xcd\x9b\xf1\x0f\xa7\xe3\x1f_\x7f8}\xf5\x0d\xees\x0f\xe65O\xc1u\xd7\x12\x0f\xa51\xe0\x01\xed\x92\xf7\xd82\xd0\x92v^\x074\xc3\xbd\xfb\xe4q\xdd^\xf4\xc9\xbe\xfe\xbb\x87)\x13=\x91k\xfe\xbcH3\xe65\x98}\xaa\x05\xed]i\xb3\n\xabV\xd2\xe5U\x9c\xb0\x0fl\xba\x9e\xa0\xd7gkKi\xcd\xdb\xa0j\xe9*N\xa6\"\x8c\xd0 \x1fY\xda\xa9\xb1\xd8\xd1X\xb4Z-\xee\xde\xc6\xd3\xe9\x82\xddF\x9d&\x189Z\x9ap2\x9fwia\xbd\xb1\x1b\x85\xe3 Ps\xe8\xd0g\\\x1bs\xd1\xd3o\xcb\x80\xc9|\xb0V\xf46\x8e\x8aFJO\x92.a\xf4\xb3\xda\xad/\xe7\xb1\x11\xf9\xc4\xb5\x98(38m-\x15\xf1\x16\xff\x88:\x9f0\xa5/\xc5BED*\xe5\xd3\xcf+\x8c\xf9\x00\xc5\x9c\x01K\xe6Q2a\x19\x14)\\1\x88\xca\xe9\xf6\xa8\xe8\x8ajq}\x16\x08C\xd9Z\x0d[+A\x8e\xa9h\x1bS&\xb0\xbf}H72\x99/\xa1g\xc6{j\xfb\xf5\x84pM\xe1\xef\xf1\x9e\xda~\xbd\x92\xa7W\xad\xa0D\x88)\xa9\x8e\x9c\xe1\xda\x8a\x1c(\xe2\xfa[X\xc6\x06&\xb0\xe8F\xe7MVS\x8bNM\xdc\xd0L\x8csAX\xd3\x82,\xd4\xe5]\xebj\x80v}M\xa5O\x95s\x98\xfaA\x08\xb32\x9a\x8dU\x0d\xb4\xa94\xda(\x8a\xd4\xdb\x0d\x15@\xea,\xb6\x06!\xef\xd5\x1e\x91\xfe(\xd9}&\xb23\x9f\xd9W\x14\xe63C\xfd\xc4\x84\xf9I\x08\x03\xda\x8a\x0b\xac]A\xbfu\xad\xe4\xd2\xbd\x92[Y/B;\x02k\xe9d\xf08X\xae\xf3\x82/\x19\xc6\xe2\x05!x\xe5=\xf8\x983\x98\xac\xf3\"]\xc2\xb2\xa4\xe8\xa8e\x88\xf2\xbbd\x02\x91\xf8\x9c\\^#-:\xeb\xa1l`\x0d\xe1\xdf\xca!Dw\x98\xb2}\x1e\xdd0\x88\x12(\x83\x1d\x83\x87jiPvG=\xf8\x89W\xb9K\xd7\xb0\x8c\xf3|\xc5\x16\x0b6\x85\x08PD\x89\x92\xe2\xe8\xdf\x1c\xa3Y\x11\x00P\xa7g\xd9\xfdT\x1a\x804\xce\xcd\x1dFs%E\x1bNSr\x7fA\x9a\xc2~\x85Y\x9cD\x8bEc\x1b\x03\xfb3\x9b|\xe8\xf6\x12\x9c\\\xcd\xc4\xd9 \x93\xa6k\x89\xe1\xb7\xb7]\xc8\x7f#3\xb6\x17\xa3\xc4aD\x92\xb6^\x80\x82\xa6\x92\xfb\xce]m\xe9\x0c\xc8\x15\xf7^\xbf{}Q\xff\x94V\"\xadI\xc3L\xb5hd\xec\xf1|}\x95O\xb2\xf8\x8a\x91\x11\x96\xafKq\x87\n\xf5\"\xe4'\x89$m\x92\x1f\xdc\x9bp\xf2\x93,a\x9f\x8b\x0f]O3\xf5H\x1d\x0f\x05Y\xf58!\xac\x1e*Th})BX\x8f\xd2^\xd4j?sS\xf9)\x11I\xacu+Fz\xb8\xdaJ\xb5C\x1a\x14\xb4 5\x91\x0e\xeb\x8b\xbb\x15\xa3\xe0\x9d^\xc9t\x89\x12\xd8\x8a\xec!\xac\x9d=\x96\xe4\xb6\xddJ\x9f\x95\xf6\xd4\xe2/\x7fn\x9e\xeb\xfaC\x93~@)\xa2\xe1pQ\xa2Ma9\xc3\xeaO\xa3\x0d\x82z\xd6\x89\x06\x7f;l\x90z\xba\x9cQ\xf8&\xe8\x843P\x0d\xcf\xf2&\x01\x81|\xcc\xc2\xc6\xf2\x05\x11)\x87\x0b]\xb4K\xecc\xeb\x0e0&Q\x91\xef\x94!x\xff\xfe\xef\x9c\xb9\xfc\xfc\x88\xff\xac\x07\x93\xff\x06\x89Z\x17\xf1\x1d~i\xd6\x9d\x8d\x14E\x1f\x9bWB\\\x1a(o\xc7\x84\xd8|I\x84\xc2Qfk.\x9f\x87\x9cp\xfa\xad\xd7\x10\x1eh\xa5Mo\xad\x8c\x1f;\xb9a\xb3X\xaf!\x92\xb9\xe2\xb5\x81\xe8\xa6v\xc1\x1c5\xea4\x90{\x89\x91{\x01\xcc\xd7\x8a\x7fm\xa1hS*\xdal^\xbc\xc0\x1b\x93\xc8b\xcbxs\xa8$\xe6\x1cIQ5\xd1\xb7\x9bH\x90\x1d\x17\x8e\x07a\xcd:\xda\xb3mY\xc8\xa3\xca-\xd7%\xba+2\xbe\x91\xf0I\x02^uV\xa1\xf7\x83 \xda\xe3~\xd0\x8bzB\xa3e\x82~cm\xd5\xa6\xf5\x9dkm.u\xc9\xcc0\xf2.\xacP\x97\xc7x_\xa6q9exIq\x19\xa8Y\x83^\xda\x8b/xQ\xc5\x18\x95\x08\xd0|\xda\xd0\xac\x8d\xdd\xf8\x80n\xbc\x18\xf5/I\x04)zBz\xf5k\xb0l\x18AWB\xca\xfc\xa2\x87j\x18\xc9\x80\x87\x15T\x88\x13\xc88\xec\x1fDq\xf8`J\xbc\x10\n\x15\x00\xb9\x8b\xf2S\\\x10\xd5(\xb7&}\xc0\x11xq\x12\x17q\xb4\x107P\n,*\xabr\x91\x82\xae\x9b\x83!\xa6\x1c\xbf\x89\xd3u.\xd3)gl\xc2\xe2\x1b6\x85\xab;]\xffP\x8b\xec\xaakM\xcb\xd1w\x81e\xb5g\x9f8\x9cQ-\xdb{y\xb1i\x1e\x19\xca\x84\x9frG\x1d\xc0#\xd3\x98]\xb8Q\x1cA=b\x02\xe5\x90\x86r\x0d\x1cA^\x1e\x07e\xc5j\xf5)}5GJ\x8a\xba\x13y\x06\n\x97Q \xaf\x1f\xfb5\xcb\x95\x82KXh\xc3kW\x8d\xf4\xaa\x0bL\xee!\xe8y\xc0\x17\xd6\xa3i~A4\xa6\x08z_\x18\x9fp\x1c\xe3@,\xf8\xaf\x9d5\xc7\xaa\x9d>G\x96d\xb3\xadS\xed{\xa7\xbd\x9c\x96\x0f\xa8\x84\x0e\x9e>\xe2\x08\x92\xb6t\x87\xa5G\x1f\xbe\xae\x0f^_\x0cm\x80Ay\xb6%\xfe\x9e2\xf0\xde\xdc\xfc\xb6\xcd\xbcag l\xbf\xe5\xa9\x8b\xb6\xf4}\x18j\xb1\x01\xd2\x92\xb0g\xc1s\xd8\xde\xe64={\x1e@*\xe8y\xe1\xb3Qr\x89\xcaT\x87\x1dh\xba\x19\xd4\xb5\x83\xf1\xc9A\xe0{E\xfaq\xb5b\xd9I\x943\x97\x15'}Hv\x02\x0eqA\xaf\x06\xb0C\xd8\x1c\x8bh\x97\x94\xaf\x7f\x81>_\"%\xc6!\xec\x14\xf0\x12R \xcb\x14\xb6\xd1h\x0b]\x81\x12Y\x90r|\x0c\xca\x8f\x12\xd8>\x844\x10\xe0\xe6\x1f'\xf2\xe3\x04v\xf8\xef\x97/1v7\xff\xe3\xd0\xcczU.h\\.U\x8aK\x95\xc1\x0bH\x9f\x07\x10\x8f2\xb4\xa5\x19e|$\xf4a\x17\xb7\xac\x92\xb9D|.\xc2\xc2\xd5\xf7F\x7f\xfe\xf3z\xb7\xdf\x9f\xfe\xf9\xcf\xeb\xe9\xd3~\x7f\x87\xff?\x9b\xcd\xfe\xfc\xe7u\x7fO\xfc\xec\xef\x1d\xf0\x9f3\xb6\x8b?glw\x86\xdfL\xf1\xe7n\x7f&J\xfbL\xfc7\xbb\xdc\xdc`W\xce#\xe9\x15,/\xdaM\xcf\xbabG\x08\x19\x85 \xa9\x03A\xe2\x86\xbdD\xac\x1a\xdee\xc6\x12\x03\xf8\nmo\xa7\x97\xb8v)\xbc\x80\xf8y h\x9e\xcfw\xd7(\xbdD\x0f0\xc76\xdb\x90\xb8U\xdbl\xf0\x9420\xae\x84\xf1J\xcdA\xc6\xd7\x8fI\"\xe3\xd6\xb3\xa0\xe1\x9a4\x04)\x9c\xf6\"\x05\xad\"H\x89[\x83\xa4M\x84US-\x99,ZQ-v\xde\x11(\xdeLXldhx5\xea\x13\xa6\xcf\xa0\xd6[\x04*\xb7\xc5{<\x0f\xb9\xec\xe5\xa7\xd5A\x17c\x1eHs\" \xc7)r`\xd7\x07`\xd7,q]e\x00\x88{9o\x14/\xb4\xbe|A'\xc1\xdaG_i\x94)\xbfO\xd8\xad\x1f\xf7N\xf0\x17\x97\xe38\x0bo\xe0\x13\x7fT\x15\xcc\x8e\xa0\xef\x9ax3\x94\xb3ng\x05\xfbd\x19\xf5\xc6\xba\x04}\x9c\xdf%\x13%,\x9b\x82tM\xd6vUZ\xeb\x95~\xcf\x12\x116\xc0U;\xd7k\xbf\xcf\xd2\xcfw\x97\x8e\xab\xf7\x16\xf9\x18\xad\xff\xdb\xc4\xe1\xcc\xe5F\x81\\\x0c:\x95\xe2_\xeb\xf2\xaf\xb8\xfc\xab\xcd\xc8\x86\xa2\xdd\xb6\xd6\xa1\xc52\xb8y\x92\xa5i\x17\xb5\x01\xdd\xeax\x0d\x11m\xff'\xfe\xb4d\x86jmY\xf8\x8fm\xd2\xecWj\x11\xf4\xd4\x10\x1b\xa2\xfa\xa0\x1f\xf8\x89\x7f\xb0\xff$\xd8\x88{ih\xd0\xdc%b\xf3\xec?i92\xcbKo\x19\xfa\xc8q\x80\nv\x15\xad\x0c\x95.\x06\x8a\x92h\xab\xa2-\xe53\xb4\x95\xfa\x89\xf0kV\xf4\x1c#\x02&h\xae\xaa\xf7\xc7x\x97m\xa7r\xc3\xacim\xdc\xee3\xda0\xe4\xc0\xca2\x14\xa1\xb1n\xed\x15\xa7\x07\xbbm\xd8\xae\xd8\x80<\x84E\x08\x13\x8a\x19@g\x02\xf8\x9e\x0c \xaf1\x8cv\xa9\xc8\xa8Dq\x07x\x1f\xc6\x019E \xfb3@\x1f\xdd\x97\xb0j&%\xc2\x8f\x9a\x9f0\x94nm\xce[\x11\xc5\x9a\xe85\xc7%\xb6\xdb\xbaq\xf08Kq\x87f\xbd\xbf\x96`\xe0\x12\x17?\xb63B\xf4\x04\xc5\xf9\xa0\xbb\xb8\xa0N\"!k!dE\xce\xfb\xdc\xc0\x0bX=w\x1d\xe5\x98\xa7\x96\x8c\xef\x02\xd2)\xba\x18\xdd\x10we\x1c\x00y\x80M\x8c\xf9\ns)\xd9\xbf\n\xe1\x0eC\x1d\x15\x88\xa1\x13\xcc\xca\xe8\x8b8F7\"\x9d\x13\x7fK\xb7\xa6\x99r\x8c]*\x1f^o\x1c`\xea\x9a8Y;\x92\x0c.\x0d\xcb:\xfd\xb9\xcaX\xf4\xc9*\xb1I!:\xa77\x8db\x0b\xa5\xf1V]V\xed\x93\xd8\xbf\xc6j\x9cA\xbd\x13\x9a\x1a\xbe\xfb\x17\xd2\xcdTl\x8bIP\xe1\xd2\xb50\x06p&\xbdl\xea\xb1 \n\xe0\x84\x04\x90\xd0\xf8*\xe2\xa7\xc4\x18+\x86/\xd0\x15\xee\xa3\x85\\\xdar\xe0\x8e\xe1|\xeb\x82\x90\x87\xc8\xa4'<\xcaQCZ\xfe(\xeaN\xe9\xf8\xd7\xbd\x84\x95o\x92\xf35\xc9\x9e\xc4\xac\x9a\x98\xefT\xcc\x97\x84\xa9e>N2\xbf\xf7$\xe8}\x8c\x93\xe2)\x8a\xb1\x0fr^\xee>\xa3B\x80r\xb1\x87\xbe\xc79\xd8\xbf\xaf\xe8)\xe2\xa5~\x93/\xddSz\xac\xbb\xedcr\xeb2b\xa1\xa5q(g\xf8l\x8e0\xf4_\xe6\xc7!$\x1dp\xa4D8x\xfc8\xf03\xc7\xd6M7\xebc\xd0\xa7\xa3RqN\xcd\xbf\n!'&v\x0d\x870\xf2X\x96\xa5\x99\x17\x827Y\x08\x7f5o\xca\xf2\"K\xef0\xb0N\xb4\x16\xef2\x96\xaf\x97\xcc\xbbt\xb9\x08\xdd9\x11&\x06y\x1b\xc3a\x88\xde\xe0ROf\xce\x154\x1aU\xe8F\x86\xb1]\x0f\xbd\xc9\xc5\xed\xd3\xdbt\xca\x9b\xdc\xdab\xda\x0b\x19Z\xd9\xb7\xeb\x99o\xbe|\xc1O3\xb9\x7f\xce\xca\x12\xc7\x1d\xa40r\x98\xc7\xd7\xf3\x9f\xa3\x82eo\xa3\xec\x93\xbd& id\xd5\xeeO\xed\x1f\xac\x89\xd1\x1d\xc1\xe0\x00\x8608\xd8{\xba\xef\x80Bm(\xfc,\xe0S\x12'\xa42\xa5\x10\xb0\x88\xaa\x82(\x90\xd9c\xd6!\xdd\x08\xc6\xfb\x9d-\xd24\xf3\xedr\x15\x96@\x08\x8a \\\xeeo\xca\x84\xed\x18\xe4R\xcb\xd8\x1e\x8b<\xe9\x9c\x8f\xd5_\x9d\xa4k\xf4\xa5W\xf5f\x8b\xf4V\xa4\x1a\xd7j\xb2D\xa4\xc8/\xf3\xb5\xb3d*\xe8W\xed-\x87\xb2\xf8\xb6|\x85.>\xc2\x9d\x05\x7f'\x8cM\x15\x91\xac5(Z\xa3\x8a\xd4\xda\x89 \x8aF\xfbbC\x9cO\xe6l\xba^\xd4G#\xf7\x8f\xf9\x12-\xe9N\x93I*\x87\xca\xacw\\\xae^\x17\xb3\xa7*\xe3|t\x1b\xc5\xc5\xab,\x8a\x13\x0dNr\xaeo\xd3\x8c\xd5\xdb\x9f\xa4S\x96\x99\xe0+{\x13oY\xf5\x8a\xa3\xc4\x1c/\xb2\xe6\x92\x82<\x0bzBE\xf1J\xb4\x15\xd8M\xb3[\x98\xfbU#\x81\xdd\x8fVX\xc3W\x97\xe7\xd7\x95\xdb\xf3\xcb\xa4\x1c[\x88\x8b:e\xb8\xaa8\x08>\xb4+\xd2\x95\x0dG8\xce\x8c\x03\x92\xd7\x17DK\x04\xa9\xa8\xad\xb8\n\xf1 \x14\"4\x03\xcc\xebV4\x06\xdb/w|\x10\xba\xd8f\x89\x1b\xda\x87\xea\xcdaU\x1a`\x14\nW\xdcx\x07 \xc7\xd5m\\\x16B\xeab\xe9%\x17\xc1\x0c\x88\xd8`\xabL\xcd\xe1\x08\xfc\xc8\xd8c\x9d\xf8\x04\xd4\x8d\x8b=\xac\xd6\xc9\xee\xa7\xaa(\xf1\xcc\xd5\x1ah\x9c{Y\x99\xb7\xde\xe4b\"\x94\x01\x8a*!\xd4%\xddRy\xd3\xc2*\xb1\xd06o\xb8N}aX\xb1\x91d'\xf6\xed\n\xa0\xb9xI\xb9\xfa!\x9c\x93\x97\xf7\x1ct\x11\x86.\xf2\x91f#\xbew\x82+B\x81\x9es&\xa2\xe4,zq.\xd8'?\x13\xce\x07\xfa\xb6A\xcd%e\xbb\nztn\xa5*1NKa\xa8W\xf7Mz\x9d\xdcD\x8bx\nI\x9a\xec\x88f\x1f\xc9\xc3a2_'\x9f<39\x9dz\xf0\xb8wLDnk\x02n\x11F\xb0\n!F\xe1\x93\x13p\xbf\xe4bb\xcc\xc7c\x0cY\x1a\x9c\x96\xf1\x97\xfb\x1c\xa3]\xf37?&\x93\xc5qi\x16\xb3\x0bi6\xc7\x1c6\xcdv\xde\xc6\xdc\x16\xbdY\x96.i\xdc\xc0 f\xfc\x94\xd6\x8f<{\xbe\x9aC\x9e\xe0({\xeb$\x9f\xc7\xb3\xc2\x0f \x9a\x15,\x03\x96L\x81\xdd`\xf0\x8f\x00s80\xb48\x10!\xfa\x10X\x02U\xbb\xb4\x8d[F5|z\xf6\xa3h\xd2\"\x0eQyd`nK\x0em\x8c\x0bXn\xda\xdb,\x96\x97{&\xb4\xa5\x8e\xaeJ\xf5\xa5\x8fw\xc0{\xfbT\xed\x9bz\x99\x0ci\x8c\xe9\x9ej\x03\xa2\xb0\xcfT,\xb6\xad\xd5\x16\x93`\xe2$\x84\xd5\xb9 \xdc$r\xc0/L\xe6\xb0b\xba\x98\x93\x8e|\xf5\xcd\xf8\xe3\x0e\x1a\x7f\xab\xd1xj\xc0E\xc9E}\xff=\xd4\xddEp)\n\xc1\x16\x1d\xf1)\x88\xb5\x9eFE\xc4\x97\x1ac s\xa0\xf9}\xb1\xa6\x1d\x89\xa2@\xd2\x92\xa6*\xe4Kx\x1b\x14\xa5\xad\x01\xee\xfb\xef\x914\x06\xa1XT3\x10d\xed\x17\xed\x94q\xa5\x87q\xf2J\xc6\xeb\xdb\x93\x9f\xea\nc\x82\x7fP\x01\xad\xea\xaf+\xce\xcf^bB\n\xae\x8d\xc7\x89\x80\x8e\xee\xfd\xc6\xfe\xf9 \xdf\xee,\x13\x82\x06\xbf^\xc5\x88,\xd5\xdf\xf5\n\xe3u\xa2\xd7)\x7f\x19\xb5\xaa:\xad\x87\x99\x90\x06\x10;\xd6\x8b\x05G\x10+\xccw\xbdq^\xb7K\xc37\"EE\x06\xe4\xf29\xc9AVG\xf4\x04\xcfoC{Th1\xdb|\xa4kxld&7/r\x15eu\x86\x9b\xa1;\xa1 \xfb\xc2\xba\x07U\xac\x9e\xf4\n\xc3\xa0\xa9\xe3*\x1c\x1a\x126;\xfcH\x1d&r\xcf\xb5\x9e\xe4\x97/_\xc2\xa0\xf6k\xb7\xf6k\xbf\xf6\xebi\xfd\xbb\x83\x10\xd8\xf6v`:]\x83\xe0\xb6\x03T>\xbd\xa8q\x17\x0c\xe7\xab\xa0\xa9\xcf\xbc\xb04\x06\xfd\x10\xfa\x1dc\xdb\x9c\xd3PPW*\xed\xc2\x97\xdd;\x97\xf3-e\x05\xc7\xfa\xa9\xef\xf1\xd7\xea\x9d\x17V\x8b\x1eP\xdfH\x9d\x88\xe2\x04\xd2*\xf5\xc6 \xba\xa3\x0d\xe1\xa4f\xe6\x02\x0d\xf3<\xa1\xe7)\x87\x04j\x92\x9e\xc8\xb0\x80\x0c\x87\xfe\xee\xc2N\xea@\xf7\xf3\xc9}\x82\xd4\xf4!\xc8\x82\x9b\x1a\x92~\xa8O\xf2X\x10\xd6\x8e\x13\xbb\xca!\x864\"\x01\x0bXV\x9c\x16\x17\x10\xce\x9c\xab\\\xeaK8x\x8bx\xf2\x89\x1ag\xa7>\xde\xb7\xaf\xb0\xc2v\xa1y\xa3zB|w(\xe6,eZ\x85\x90\xa8\xd9\x96\xe8\x18\x82\xb9d\xdarn6\xa5\x8bo%\x02\x88bS\xdf\xe3\xe3\xa9m\xeb\xe7\xf5AJ\x0b\x01\xa5|\xf2\x83\xe7\x86\xc0\xe3\x1a\xe1\xdb\xb6C\xc88z\x8eDWH\x1d-F\xa9{\xaf\xe3\x98\xdeu\x13I\xfaB\xfbU\xb9\xb0\x08\x07\x16\x0c7D\xe2\x15_$\x91\x93\xa4\x16^\x8a\xb8g\x92%;\xa6\xf4\xa0\xff\xd2\x15:\x99\xd8\x93\xcd\x1a\x02)Mx\xe2\xecd\x9a\x91$\x9f\xef\xc0\xb4\x95\x02\x0d\x01 \xa5\x0dM 1\x8a\x00\x8d\x9er\xfd\xa4r\x832\n(\xa9\x9b\xd0\xfeZ\x9al\x0d\xc3\x0f-\x99\xee\xcb\x17\xa5f\xa8n\xac\xe5\x8c\x87`\x89\xef\xa2\x9d\xb0\xfc$l\xd4\x01\xbd\x16\x97\xc40\x84s\x95q\x81\x13D\xd7<%\x81>T*\xa8@k-p0\xfe\xdf\x7f\xafzq\xb5\x8d|\xb2\x0c\xd0Q\x03\x8d\x13}\xa6\xbe\xc7\xebUJ\x82\x10C|\x18Q\xae\x04\xe4\xaa\x93\xc6\x96\x97q\xfcS\xe5\xf6\x00\x0b\x96\xe7P\xcc\xa3\x04ny\x8de\x94}\xf2\xc4\xb8P\xb9\xaa\xc0\x86\xcd*\xd1\xeeH\xad\x05\xff\x91\xe2\x95\x19\xde!\xa4b\xe1\x91\xbf\x93R\xf94\xc5\x01{A\xa8}_S\xa9HM\x91\x05@J\xa3T\xd38\x9aJ\xb5@or\x10\x1a\x82\xb0X\xc1\x04WP\xae\x8aX\xdaL\x1e\xf1}8*\x05\xbc\xa1<\"\x8f\x1cz-\xfe\x7f?\xd0u\x7f;\xa8\xec$gQ\x02\xd01\xa3\xa4\xdaJ\x9a\xc2C\xe2\x8f\x1a*\xea\xc6\xcbk\x94\xda]\x14?\xb0\xea\xa7\x9b\xa1 \x1ew\"(Z\xc3\xc4\x85\xa6\x80x\x00q\x8e\x81s\xe3\xe5JdH`6\x1d6n b\xcc2\xd2\xca\x8c\x96\x82\xd6\xf7B\xb8#\x8b\xa7Y\x14'^\x083\xb2T\xed\xcf%Y*g\x17\xc2\"\x109S\x8d\x8f\x13N\xaa'\x0deWd\x99\xa467AX\xc6\xbd\xde\x8au-!^\xeb\x8fo\xb3\xb8\xa8]\xbcn\x99/\x91\x08\x96\x9f\xcc\xa88\xb9_\x1b\xd6w\xe2\xbc\x8a\xc6\xb5E\xceP\x18\xeeM;\xc5\xb2\x8e\xeb\x06#\x1a\xef\x8b\x04\xf2\x8c\xab\x8cQ9^\\X\x17\"\xea!|\xeb\xc9X\xc6\x02\xc6\xd5.\xa0A\xac\xb20Pes 24\x00\xd4\xb2!8O\x05\xc4$1\xc1P\xb6\x14*j\xc5Jk\x1c\x8e\xbeBt\x91\xd1@k\xe4\x12\x1d&%qW\xa1\x0ej\x15^\xc2\x80W\xda\x11\xcd\xbe\xf3+\xfa/x\xcc\xad\x95b\xa2f\xd1\"g\x80\xddB\xc6\xf2U\x9a\xe4,\x04ek\x9e\x98\x17\xb0\xb5%n(\xdd\xde\x96\x93\xeb\x8bl\xca\xbc\xbdMw\xe3\xb2\x05\x88\x8aT\x15A\x08W~+5\x13\x08'\x10L\xbc\x17\xe7\x82\xc1\x98\x10\x11!\x9a\x06y\xed\xdcV-\x84\xf9\x8a\xa4 \xee\x8e\xee\x9ai\x93l\xbb\xf5\xb8\xd8\xb4\xdb\xab\xa6n\xab\xc3.\xe9\x89\xbf\xbb\x9d\xfdJ\x9e\x15;\xb1$\xfed7]o\x07\x00\xac`n\xba\xb1\xef*c+\x96L\x15P*/=\xb3D\xe4\x98iP\xa1\xf7\xc6h\xc2\x97\x0b\xe4\x91?F\xc5%\x1cA\xe4\xeb/\x02\xb4\xe3\xab~\xd7-\xb2j\x9f\x1e\xc2( k\xaf.\xb1\x8a\xf0\\J\x1c\x04OCeu`\x8b\x03\xa5\xce\x1f\x88w\x06W \x90^\x9e3|3\xc7%\xa1\x95w{\xc8\x8aU7r\x89\xbc\xcd\xf3\x03\xebR\xdf2\x82\xb1\x18\xf3&\x9d\xd5F*\x03\xf7\xdaWL\xd4\x90Jz\xc1\x1f\xc2\xc9%\xd6b9\xeb\x1c\xbdR\x11\xce\xe3\x9c\xfeh\xe0\xfe\x88U\xcc\xa5,\x87#lIXq(\x89Q\x96\xe1Qi8f\xd8^\x19\xfa)8\x90\xd6\xf0j\x11KvA\x18\x13%R\x92%p\x18\x9d\xfd\x9c\xfcB\xe9\xf0#\x0f\x0b'\xa8S\xa8\xcf\x9c\xde,\x9b\xce\x8an\xa5\x163\xb4\xff\x1cb\x0c\x15\n\xf1\xf6v\x00\xd9(\xbet\xc1\xa0Qak\x19\x0e\x01I\xa6nd\x9c\xc3w~Q\x9d\x9f\x0d:8D\x89H[l\xf9\x99\xca\xd9\x13\x850\x08\x0c@\xec\xa0\xe4cc\x93d~\x14\x08\xe5_\xa3\xfe\xa5\xb6{]\x0b\xdf\xb49S\xeb\xc6\xb5Ib\xcek_Vn\x10\xd2p\x83\xc60A\xd1\x05g\x12\x94\x82\x98\xdb\x00\xadT=(\x02C\xf0l*FRe\xb3\xa2\xdao\xc1\xe5.B=\xe0]Q]\x89\x9c\x11.G|\xe7R\xef\xc5\x85\x88\xa5\xc9\xc9\x1c\x0eM\x99\xa6\xec\xca4}\xcey\xa9<\xd4\x04\x853\xb9\xa6\x9b\x1c\xabM\xeb\x1fM\xcb\x93\x0e\x0e\x0d\xcc\x08\x0dU1\xdav\xb4\x98\x19\xde\xc8@\xfb\x9d\x00]\x9e\xb9\xc6QS\x9d2\xcc`\xf7[1\x15\xa4YJ\xdd\xd0D\x19\x1fY\xe6'\xf5\x1b\x88\xf7\xa4\x01\x12\xe0\xd9*\xd1<\x08(;CC\x0f\xc5\xb9\xdb6@U\xaaV\xbe\x8b\x04\x87\x0dr\xb2B\xc7\xd1\xb0E\x82\xb0\xe3>\xc2\x83\x1b\x99w\x87\x05e\xfd\x1c\xd1\x14s\xf2\xab\x0e\xd3\xbd\xcd\xa2\xd5F\xa7\xbb\xfb8\xef|\xf6g\x8e#\xa2<\x1eR\x8c\xc7\x83\x0c\xa5\x10\xa7[\xc5^NN\xa6\xbe\xc7g\xb3bS\x90\xc2}R\xf7\x97P\xba\xf8f\xc9\x99 \xcb\x87nnP\xf2\xec\xd6\xaf\x0f\\Z3p^c\x16\x9a\xa9\xb6\x8d\xbc\xa5&A\xf2\xd6%,HW4\xfe\xe8\x90P\xc2i\x0d\x14~Z\x9b\xa3\x90SS\x8e.[\x89\xe17R*\x95QS\xafY\xef\xa7B\xa4\xf7\xcd\x0f\xb0\x9e\xb2JQb?\xce/\x0d\x04\xd1U\xba\xf1R\x90\xa4\xb6l\x806\x93\xba\xcf\xd4<\xceG\xe9%\xd4c7kR\x81,\xf4UE\x0d\xa9\xdb\x1c\xee[\xd1K\xab\xcb8\xf3/B%3=\x85F\xc7\xf5\xfe\xca\xe1\xdc\x80\xfa\x1agt]^1\"\x83\x84Hp=\x8a/\xb5\x9d\xde\xbb\x8a\x93\xa9\xa4n\xbc\xa8\xc1#\xa7\xd0\xbd)\xdb!\xa3\xa1\xd0X\xde\x1f\x16\x81\xf2\xfe\xce\x14\xe7Z\x89\x11\xf6Di\xda\xd3\xc5\xddD\x91\x90\x9ao7\xe9z\xc2\x92\xf5\x92e\xbc.\x97\x13lj\xb3\x91k\nEak\x17G\xf6\x1c\xeb\xb3C\xbf\x8f\xf1,K\x97\xfcT\x86Cx\xfb]UV\xcf\xac\x10b\n\x1eG\x82\x05C0\xae\xe5j\xb0\xe3Mti\xa2-\x1b\x90\x88\x99Q\x16\x94\n\x83\x94<\xaa\x1b\xb4,_\xc9Q\xd7?\x97~,\x1d\x0c\x8f\xee}\xd7\x03m~D\xee\xd0\x02\xe23K;M\xbc\xaeZsn:\xf4\xb2\x8e\x84\x9f\xde\x11:\xe1\x94\xd6\x9b\x1b\xf4\x83p\xae\xb1\xb3%\xd3\x93*yA9Y\x08s\x9d{\xba6i\x17\xa7\xd6\xc0\xfcF\x08\xd4?\x96\xaf\xfd\xf2\x04 ;h\xb8\xb7\xe4=\xce\x11\xe7\xcb\xf5 &bv 5(\xf3e\x1dV8(\xbc~E\xd0\x92\xfa,\x87\x9cU\xfbYzd\xb5\x10\x93{\xc3}@\xf3w\x99\x1d~\xc1\xf2\xa1\x996\xb6`\x84u\xf8\x96\xe5\x1d\x90\xdf\x12#\xb0\xca\xcd)\xd4+\x08]Vs\x1b\xc6\xa2\x9aNU\x06\xf9\xe9\x9ca\x87\x0c\xc8\x96\x95\xa1g\xaa\xfbvDd\xafL>\xabG\xcf\xca\xd9B\x04\xb5\xe4\xff\x7f\xf9\x02\xb7q2Mom\xfa\x92\xd2\xe1\xef\x91\x93p93\xd1Y.\xa0\xc4\xb4xZ\xf9N\xf5\xc6h\x89\xfd#\xd2K\x07x\xf0\xcb^\xce\x8a\x8bx\xc9\xd2u\xd1Q\xccI\xd8-\xc4~*N\xb0\xeak\x8c\x87P1@!\xe0\x00d\xa1\xa5\xb7\xc0~_'\x05\xcbn\xa2\xc5=;V\x9f\xd3=\xabR\xa2k}d\xa8\x80\xa9}\xd0*\xffH.\x1f5\xb1\xbe\xd5|\\S\x97fl\x86\xb6\x91\xba\xec=3\xe6k|\x84\xed\xb6\x81\xa4\xb6\xc6\x02\"YX\xe2\x011g\x96d\xe9b\xd1EA\xa4C\xc7g\xbc\xb9\x05\x93?_OQ\xfc\xd0_\xd9\xf8\xc5{['D\x7f\x0f\xd2\x99i\x0e\xc7{\x1b#\x9c\x8f'E|#\xb4\xaf\x91\xfa\xf3[:\xa7/\x08\xe5M\xaaV\xd5\xaeW\xc0\xcbC\x99S\xc9l\x15\x0e\xa1\xda2~+/\xcaz\xe34Q\x93\x17\x97\x12\xe5o\xea\xb6\x87p\xb9\n1\xa4\xd5n\xa0\xf6\xdcr\xc9\xa6\xb1\x08\xce\xd2N\xc2\xea_Ta+*Rh\xd5\xe08X\xb2.za\xb9\xf36\x1c\x82\xf1\x0d9\x08\xbbNm\x18\xf5\xe2\xea|\xe8\x94\xe0lc\xe6\xd9\x11S-Eeb\x9c\xebq\x88\x9a\xf1SY$\xe1\x9d\x82\xe7\xc16\x17\x82q\xbeE\xfa&\xbd\x15 \xc9|\xa7\xfd7\x1a\x11ys\xf6\xd9\xa3\x8d{D9FBj\xa9\xb0\xd3\\#\xca'q\xdcX\xe3*N\xa2\xec\xae\xb9J\x94\xb3\x83\xfd\xe6\x91L\xf2\xdd\xb6\n;-5\x8a\xd9\xe0`\xc1\xda\xea\xec\xb4V\xca\xa2[G9h\x1e\xda\xfd{\xda\\\x95\x1e\xde\xf6\x16\xaf\xefnG6,\x8a\x931\x08\x95B.\xdc \xac\xab'\xb8\"\x81\xed\x0c\xbc\xba\x90\x92S\x11x\xd6r\x11T<\x7f\x1e\x94\x03s\xb6\x0c]p\x17:\xe1\xafz:\x0c\x12\xba\xa0!tBE\xe8\x88\x8e\xd0\x15%\xd5\xa3M\x03k\xb7\xcdd\x11\x15q2h\xed\xbdq\xf7\xaaG\xf5-\xdbl\xeb\xbaq\xbbC'\xd2\x02\x1dh\x9cz\x94\xba\xae\xc1\xe8\xa9mO\x82r\xb1h\x0e\xb2\xa5\x1eN\xb3}I\xb4\xeb\xf4ZD\xa3\xd0R\xd8\xea\x0f\xa5#\xa4n&\x1d\xd1{\xc5\xe5b\xed\x989<\x94\xd1\nE\x120\xdb+\xc4\xfb\x98|J\xd2\xdb\x04\x14\x15\x18\x82\x18\xb6[{\x88V{uJT\x05v(#\xd3Q,W\x07\xb4\xc7F\n\xf6\x99C)/\xdb\xe4\xac\xd3B\x80\x8e\x88\xd1\x08n#\xd7VR\x81\x1d\xcc\xe2\xc5\xe2M\x84z\xba\xf5\xfd{i\xc4j}^\x93\xda\xbcf\xa2\xc7\xbd\x8dzlDX]\x89),\xc0\x0ea\x15\"\xe7\xe4k\x1d\x9b\x92B\xed\x17\xd6[Dy\xf1\x8e\xa1\xa0\xadB#\xf2W\x17i\x81\x92\x92\xfe\xeed\x1e \x9f:\xdd\x1f\xb0\xa6\x0d,\xff,\xcf\xaa\xc8&\xf3\xa5\xa9\xc5\x8bC\x18\xec>QIb\xe0\xe5Kx\x0c\x87\x87p #B\xe3\x9b}\xfef\xb0\x0fG\xb0\xa7^\xed\xf1W{}8\x82}\xf5\xea\x80\xbf\xda\x85#\xd8\x19\xc0\x10vv\x1b\x87\xb4v\x1c\x9fJ\x1bXM\x7f\xa7\x0e\"[\xca\xdf\xc4\x05\x1a-Ov\x9f\xf2\xbd\xec\x0f\x9e\xed\xc2\xf7\x98\x14<\xd0\xac\x99\xeaK\xe1\xfd\xdf\xff\xd7\xff\xe9\xa0\xb2\xe8cTU\x97\x16\x83\x9ak\xd8\xa0\xe9h\xa5\x062p\x0dd\xd08\x10\xa0\x06\xb3k\x0c\x06\x7f\x9b\x1d\xee\xba:\xdc\x95\x1dv&\x9e\x85T\x88>\xa7\x90L\x93$\x12t\xb0\x1f\x1aX\xffB\xf36\xc3x^\xe8\x97YCy\\V}\x1f\xf0\x0f\x03c_\x94\x89\x0d\xeb\xfcVho*\x11\x17\xac\xa9\xa32\xc2\x99\xbe\x9f\xcb\x11\xefh!\xd0\x9a\xf7^N\xaa\x00\xf8z\x95\xd9T8\x8a\x07\xf0\xaf\xb0\xcb7P\xbfI)_\xa5n\xf4K\xf2\xee\xb6#i\x0e\x04\x80\xd7\x91\x93y\x94\x9d\xa4Sv\\\xf8\x9a\x0f\xac\x199Z=\x18b\x9f\x8b\xdd\x8f\x1f\xef>;\x004\xcc\x7fq\x08\x8f\x0f\xf6\x06\xcfj&_\x06.Y\x04m\xdfX\xb8Q_\xa4-\xd6 \xb2{i\xd6\x19Xu\x06\x97!$\x95\xa3\xfa\xce\xe0\xfeF\x1e\x14\xde\x9a3\x19\x103\xd9m\x9f \x1f\xa5c\xe1*4C\xa87\"\xd2\xc2M1\xeb7\xe2G\xda\x81$n?\xa8\x9c\xec\xf5\x8d\xd4r\x11\xe4&\xc7\x0d\xdc\xcb\xb6ksj\x10\xe8\xdb\x01\xc1\xc8\x95h\x84\xcc\x84\xdcbj\xfc\xd66\xdb#\x89T_z\x9b\x1c\xd5\xd6J\xb2\x1a\xd2\xf1\xcc71b\x0fv !\xb0bOY\xa4%j5\x1a\xf1\xa3\xd6\xf47\xed\x87 t\x0c\xbf\x86iI\x0b\xcd\x9a=\x1c\xaa\x91[\xe9\xa8\x11;\xcaA\xf7C\x04\xb0\x81\xa9\xc3\x16lX\xb9\x99\x1d\xc7\xf9\xd0\x0c\x8ci\x03\xf3\xd4\x06\x0b\xada\xf5WQ\x8f\xe7\x06\x87\x10\xd75\xd3\x8a\x91t\x0b\xff\x95\xcdmy\x06\x95\x82\xa1\x01~\\\xb6\xd0t|\xee\xb4\xff\xe3*\xef%\xfab\x96\xac\x99b\xe2\x85\x9c\xe3\xe8\x18t\x03%\xd5Mhs\xbb\xf5\xbd/\xec\x14\xd1\xe5\x9bD\xa3\x04c\x92V\x00\xd71\x89\xf3\xfc\x9c\x10$\x81\xe2/\xeao\xf0:I[\x91:\xd4\xa5\x88\xd0xK\xf5\xc0\xf8\x8f\x1cV\x1d\x9d\xebc\x92RL\xe3]\xc2\x8d\x99\x17\xbd\x81\x01\xae\xec\x93+\x8aAs\x0e\x19\xbc\xe0M(\xd2hW\xba\x91\xd9\x03\"\xbf\x18e\x97\x0e\xfe#E\x0d}\xd9L\x8a\x8e\xbcB_\xaf\xa1@\x8aG_\x08)\xdd\xc8\xce\x0e\x0e\x86\xaf\xde\xce\xae\x10\xb3\x9b\x06\x86\x8c\x956\xb2\xa0\xf3\x18v\x7f\xfd1\xc8\xb60\xf8\xce\xa1\xca\xd2Y\x1f\xd5\x1e=*\xd5y}\xfb\xb8M\x8bQOhly\x9b*\x96\x01\xfb\x8d\xaf\xad\xf3-\xb1\xa9\x8c\x1e\xa0\x01v\xc0O,\xcaMn\x0c\x9a\x05\xef\x0b\xcfijh\xf5|a\xf5\x0d\xa3\xa9\x17\x9a\xa9g};\xbe \x08\xa9C4h\xe4\x85\x1eT@\xa9C\xeb\xde\xc3\xd1\xc4\x98\xfa\xa45 \xc68\xa5\xeeu5\xa3\x9b\x1ei9Nn\xb4\\Pt\xa63LcS\x164\xa9\xd7\x11\x87\x11\x04\xb5\x84*\xf5\xb4 \xb1\x9d\x01\xabfu_Zc\x14Y\x94\xe4\xb34[\ns\x0c\xca3\x06C\x83_\xa8z\x1dl\xa7\xc0d\x9b\x8d^h\xa9*\xe9\x95\xb5\x9a]9*\xb1\x0d\x0f\x9c\xc9\x95[J\xdb\xca\xea\xf2\x983v\x80\xe068\x84\xae\xa2\xc9'\x15\xaaf\xb9^\x14\xf1j\xc1\xa0\x88\x97,w\x86\xbcW\x03\x99\xaf\x93O\xa5\x9bJ9\xba\xea\x8d\xcc\xfaW\x94W\x852ut\x88Y\xf8\xdc\x93M\xbb\xda\xc5\xf3'5Lw\xfc\xd4\x8al\xaeLd\xe1\x05\xa4D\xe0\x8d\xaa+\xdf,\xb6z\xfcZ\x99\x81Ri\x04\x19\x9bj\x88C\x99I\xeakN\xd7\x90`\x14\xf1.\\\xc5\x1c\xf4\x8d5*u3\xafT?/h\xfb%\xc2\x13\x83\xaa\xa6E\xf3h\xcc-RNT3y\xaa\xde\x1d\xea5\xdc\xa9Ff\x8bu>\xd7\x1a\x10\xbf\x0fU\x89\xb2\xbaG\x9b\xedU\xc6J_\xbd\xa8M1J\xf1S\xca\x1d\xa3\x8eg\xe4\xc8\xf4\xd1\x1c\xe9\xbfj\x99\xd3Hnl]\x12\xd7\xfa\xa2p.r-\xc9U\xb5\x7f\x9a\xe7\xb1v\xb1}\xb5\xab\x14\xc2\x88\xd4\xe6\x12j\x99GY\x15\xee\xde\x8a\x14\xa0\x0eL\xeb\xa2\xe3$Z,\xf86\xac\x16y\x9a&\x0cn\xe7,\x81\xdb2\xa9\xd2\xd6!\xf4\xcd\\\x86B\x8bi\x10\xcd\x1au\xdc\xb0\xbb\xbc\x88\x17\x8b\xdaV3\xbb,!C\xb8\x03TB[j\xa5V\x0b\xb5w~,\xd8\x95x\xc3\xe0\xee:\x816']\xa3 \xa5\xdfS\xbd}\xcb\x9d\xac\x1ay}0\xb5\xfd\xd6&)X\x00\xae\xbev\xc4\x98qvk\x8b\xb2t\x97ug\xb3\xa63\x13\x85\x13\xfd\x80\xe1P\xa9\x1dB\xac|\xa3]\xb7\x17!le\x06\"\xd1\xf2Q\xe7#\xc7\xcf\x8c5\xc2\xf3\xe5\x17:q\xbe:Al:\x174\xdf\xaa4\xc2\xb6t;)t\x88\xe25\x82\x02\xb8\x88\"\\cW0\x0c\x93\xc9\xc0\xf4-.\xcb\xd7\x1b\x0dU\x93\x15\x03\\\xf4\xea\xdc\x960!\xb6\xb7A\xdf \x89\x8e\xa9\x1at\xfe\xccd\x14\xed\xd6\x8c-\xd6l\x90Q\xf8\xc2fZ\x10Y\xe1Cn\x12w\x83\xb8\xdc\x8b\xd7\xd6\x98j3\xeb$G_\xcc#\xa9KEiv\x1aM\xe6\xf5\x8aq\x95\xdf~\x92\xb1\x1a.tK\xdf\xab\xf0*\x16D\x93\xa4\xaa\xd2\x8a\xb4\xb4\x1am\x03 \xe7\x069\x8eug\xb4iV\x10M]\x12\x99`\xbe\xc08\x80\xc0F\xc9\xa5U\xf9\xab/\xf3f\xa3\\`\xaeUX\xd34\xc2}\x97\x8b\x84g\x00\x7f\xfb\x86&5\x0c\xd0Sen\x92\xb7\x16\x89\x1d\xb9jq\xfe.z\xe7c\xfa_\xd4b\x14B\x7f\x817w\xdf\x7f/\xd5\x15;\x98\x9b!\xc5\xe8\xd6\xc32\xfc\n^ \xb5\xa7O\xef4\xc7\xba\x0b\xce\xc1\x93\xa7\x81\xcf\x87$\x916\xca\xf3\xf8:\x81!\x16=\xfbV\x9b\xc2\x10\xd2\x10\xb3\xc9\x85\xb0\x0eA\xf5h\xec\xadNv\xbd\xd6\x85\x05\x7f\xb4\xb8 Evg|E{g-B\x90Q\x00I'\xacI\x9a\xcc\xe2\xeb\xb5r\xc3\xea\xd3\xcc\x7f\xe4t\xd2js\xe2\xc2,\xd8C0\xcc\x80\xb5u\x85IT\xda\x8fU\xa7\x93\xb8\xf4Xhw\xb9\x99%Y7\x0f\xdd=\xec\xfa\x90\xab\x91\x88\xd0\x86$\x14\xc3\x8d\x13\xd4\xa35\x0cJ\xa6\xa5.\x0b\x1d!ez\x0d?\x13\xf9\xc1\x05K\x81\x9eZ\xd5*e\xfa\xad\n^\x17\xc9\xd4\xd2\x83\x83 \xc4\x8c\xa8\xa3\xcb\x10\xe2v\xaa\x1aR\x1ap\xce\xf9\xacG\xec\xb2d\xe6\xf9\x8fz\x15${\x05\xf6\xf3\x1c\xd8\xce\xce\xf3@\xb9\xb9z\x91\x07\xdb\xe0oo'A\xa5\x82\xda;0\xe5zM\x8f\xa2\xdc&|o\x96\x88\x9c\xb9XTJ\x1c>o\xb0\x90Q\xeeC\xf0\x02\xd8\xe6\xff\xfcM\xb51K\xa4\xc3\xa68;+\xc7\x81\xe7\xf0\xf5y\x9de\xec\xbcF\x04\xc5G\xf9\xc6\xb1f\xaeD\xf2 \x9eZE`\xa9\x1e\xec\xbd\xc9\x9f\xc8OB3\x01\x95\x03\xfd\x81\xba^\xfe\xfa\xad\xc4I\x88\x1cT&u\x1a\xe9\xeb\x00\xaa\xaa]\xb3\xe2\xec6Q\xd5^\xb1|\x92\xc5\xab\"5\x0c\xa8#\xd7\x07\xef\xa2\xa5\x19\xd3d\xed\xaa{~\xb7\xbcJ\x17y\x87\x93\x89\\cA\x82\xe5\xd1\x9c\xf9\x85\x89\xa7('\xea50\xca@\xe4\xe7\x81bv*\xf1\x9b\xce-G\xae4\x7fpOg\xa1H\xba\x9eQ>\xb6\xfa\xd2\x93M\xa0\xa1\x86\xfd]\x1d\x81\\\xaa\x0e\xcc\xe7\xbe\xfe\x07\x9b\x89n\xe0SJ\xe8\xb4\x9c\xfd]\xbd\x95o\xdc\x15\x8f)\xfe7\xf1\x07\xfb\xe6n\x89iO0\xce\x9e\xde\x17I\xf9\xc1Fd\xc2\xe3\xfb\xa7\xa4v\xa3\xddK\x12\x0c\x19\x92+\\!\xbd#\xc1\x87\xac\xa9\xe5HF\xd9%\xfa8)_\x8a\x08\x05\x12\xf5\x85\xb5$I\x0b\xa0\xf5>\xba1\xfcr\xe8[[R\xdb'B\x10\xd4\xd3\xc8}\xf9\xe2P\xe0![\xefR\x10\xceY\xdbh;\xa1\x05\xcdH\x15!x\xe31\xcb\xdf\xa6\xd35\x9a\x9c\x98K\x89\x8c\x8e.W\x06\"\xde<\xda}v\x81\x88\xbdX9\x17\xae\xdf/\xd6\xd7q\x92\x0f\x1d{\x8be\x99\xab\x08\xb0\xed\xe9z\xc2\xb2|\x08~\x9f\x0b\xbar\xe9\xcd\xe2E\xc1\xb2\xee\xc4\x80\xf5>\xb1\xbbs\xf6_~\xd0c7,\xd3\xc8\xb4\x13\xb4`u_\xb4d\x0bD\xa9mT4d6Q\xb2?z\xb8f\"\x16aw\xb2\xefDg\xd6[\xb2\xec\x9a\xf9N \x19\xc5T\";\xdc\x06X0\xfe\xe1O\x0f\x8d\x08\x9a\x1e\xa3\xf2 N~\x0dtH\xe8pZ\xbf\x06\x805)\xb2.\xc2\xc5B\xe5\xb6k^\x97\x89\xcb\x0f\xf3m%\x94\x0f:\x0b\xe5j2\xa6\\./e\xec\xc9\x95\xaa\x03\xc3{\xfa;\xfb/>\x83\x85uG\xc5\x19\x9b!\x18WS\x0bv\xc3\x16\xc32`|\xadl\xc9\xf2<\xba\xe6Go\xe9\xe6\x8d\xb5\x8c\x1e\xff\xbe\xa2\xb7K\xaf\xd5\xa4\xe1\xb4`\xfb\x97\xfc|\xc5&C(z\x9c\xc98W\xda$\xfc\xf5\x87\x04\xd6\x91\xb28f\xf35\xe8\xc0\xb1\xaaok\xa2\x80\xd8\xa1\xf8b\x15 \xbe\xc4l\xba\xc2G\x87\xf6\xf0\xc9\xae\xa9\xd4\x7fH\xed!Er\x08\xf7\xf8\xff\x15\xf4\x80 \x87\x8e7\xd3\x11\xd2\xe4]q\x8f\xc6\xff\xdc\xab\xfe\xdc\x0f\x02a:\xf3\xf7'_\xb4!\xa3\xeb\xc0\xe8\x80\xc67e\xb41\xc4ZI\xc7\xbd\xa0\x17'S\xf6\xf9l\xe6{\xd2\xe21\x9dA\x84g\xbd\x9f\x07\xa6\x11)\x947\xd1/a\xc7\xe9\xf6\x7fS:q\x1b] \x07ft \xa3:S\x96\xb6\x98\x05\xa1\xf0\xbd\x90\xea\x1e\xf4i\xe7z\xfb\xa1\xab\xc3>\x92\xd8\xed\x0ebB\xadqq3\xe1\x9b\x88\xd0\x90\xd7\xcdh\"\x91i\xdc*'4\xb1\xab\xe5\xef\x970\xc0\x83}\x1b\xbc4\xc3\x18)\x05\x0c!\x1b%\xb0\x0d\x83K\xa3\xea\xae\xac\x8a\xc0\x0b\xc1\xd3kj%X\x80\xbf\x9c\x03\xfc\x1a\x82\x97\xcf\xd3\xf5b\nW\x0c\"\x97Z\xc3O6\xc9$\xe0&~\xbf\xe9\xfdD\x9c\xbdEO\x1c\xfc$\xa1\xd1nu\x1dD}\xb0\xf7TCZ\x071\x0f\x91_\xfcMC\xe6\x1b(\x8dkw\xfa\x14\xf9\x11&@\x9e\xf2s\xeay\"e\xeaj\x11M\x98\x9f\xb0[\xf8\xc0\xaeO?\xaf\xfc$\x04\xef\x9aW\xf7\xbc\x80\xd2\x1b({\xa2\xdf:\x1e.\xa2\xbc@ss\x11Yr\xb1\xc0\x1fy\x19\x16\xd6@+R\xb4\x10\x98\xf6\xd8|\x1d[M\n\xa5\x8b0{U\x0cl\xd0q\xf5\xea\x80l\xd3\xb1\x94k\xae\x8b}JXU\x9a\x16cm\xaa\xa9\xd6\xc1B\x8f:n\x1aB\xd9=oG\xe3\xc8\xbf\xc5$\xe9A\x97\x9d\x90F\x1cs\xb0a\xdb\xe5\x92}\x11\xdd\xa5\xeb\xa2\xdb={)\x88\xfc\x03\xdc\xafS8\xfeP\x1c2}\xbf\xbe\xdb\xef\xbb\xef\xd7\x9fv\x16\xe5\xffW\xe0\xab\xff\xbe\xdb\xca\xc6\x99P\xaahvM\xa3\xa8HaM\xfc\xd0X\xb3& \xb4\xb0\xab\xe6\x98\xa4\xd3\xb8\n\x96hm\xaen\xe7\xa3J/\x90\x86\x90\xf7>\xbe\x7fu|q:~s\xfc\xa7\xb3\x8f\x17-\x8a\x82\xfaQ+\x88\x00\x9e\xa0R\xb9\xa7S\xc2\xc6\xde~|\xfd\xe6\xe2\xb4M\x91\\\xefM\x08\xde\x9b\xf5v\xfe\xd3\xd9\xcf-\x9dX\n\xca^>Oo\x13\x9b\x0e\xa9\xa3b]j\xed\xabO\x8ay\x9c\\\xbb\x1c\xe0\x94\x16\x1f\xdb\x95\x87T\xd5\xc8\xdf\xf8\xd8;\x1ev\x1c\x0e\x19\xe1\xd8\xd8\n\x07 \xf5\xb7g\xafN7\x06\x07\xce\x8d\x06GUi\x99N\x99c\xfa\x18\xea\xdc\x1fy\xbcJ\xee]\xaa\xfb\xab\x84\x0f5\x13\xb1C\xd0\xc6\xd9\xabO#\xfd\xad\x1c\xa5|\xd9\xce\xd7\xcbe\x94\xdd\xe1\x94o\xe7\x91\xc8\x0f\xc4\x7f\xc4\xf99_U\x11\x86}\x9de,)~D<\xd5\xdf\xb8\x98-u\xec<\xdd\xfbUO\x1d\x82\x95\x13de`Z\x97\xe5\x92\xda\xe8T\xa5\x9aS\x07\xf6\xe8Z#\x13\xda\xf2\x86\x04\xb4\xba\xb6&\xc9\x80S\xdd\xb50\xd6\xa5 {\xb4\xd6\x8brw'i\xb6\x8c\x16\xf1_\x19\xba{\x05\xd2\xfe\x1d\xfb\xd6wp\xae\xef\xe0\x00\xcb\xeb\xaf\xf9w 9\xcc\x1a\x0eu\xda\x8d\xa5\xdd\xab.\xa0\xd7SX\xe9\xa6\xb1pT\xff\xe9\x8e\x9e\xd3>kj\xef\x1a\xea\xe5\"0\xa6jo\x1bA\x94\xbaK\x06\xb6\xfc\xdb\x81\x1d\xdfBf\xc3c\xd3\xb8Hk\x18\xd2\x89\x94T\xf2\xcf\xdeAG\xd7/N\xa5\x8c\xa1\xd0jt9\xc0\x14\xf3\xe6d~\x12\x8c\xfa\x97!$\xa3\xc1%zc\xfa&EoTm\xab\xbb!\xd6\x13\xcd\xda\xc2\xa90\x14\xd7\x90#\x16\xfec\xd2\xc8Y\xa4\x0e\xac\xf7\xf8]\xfd\xaf\xce\xb0zb\xd2\x0c\xa9\x96x\x16\xf8^\\\xb0,\xc2\xa5\xb0\xc9\x9b\xe1K\xd9\x06o\xc7\x8a\x9b\xa1\xf4\xfd\xac\x87\x0dk\xc9\xc71{\xdaa\x8d\x9f\xddp\x8a\x8dsI\x8d\xb0\"\xf6\xfa\xab\xe5\x1a=\xb9\x1ce\x97f\xfe\xbdX.b\x93\xa4\x06\xaa\x1f#*Q(\xa1\xc8)NM^\xa5\x1a\x108\xb1[oA\x83 \xedx\xd3\xd9r_\xc4AB?\xe6*\x84\x93\x19oE\x913\xf3=\xbdi4\xc0\xd1R!?\xccb\x02\xa6X\x86Y\x97\xda\xa0\nMr\xb0z\xa6i\xc2\x86b\xdc\x9d\x83^\x878\xb0\x0d\xba\x8f\xa86\x98\x1f;\x08\x03\xeb\xe0\x1e\xd5\x05\xcb\x7f\x05\xfe\xe9\x97VE\xe4xk\xea^\xbe\xdb,Z\x1d+\xfdBC\xee\xe8\x7fH\x85\xc5\xde\xaf\xcb:.Paa\x99\x94\xaf\xcb\xa2\x81Y\x94\xcb\xa2\xbd\xfd\x03Z\x97AD_\xfd\xa7.\xe3\x97\xde\x97$:\xadHw\x81X\x95\xec\x99%\x91,yj\x954i),!c!\x9b\xd9\xb3\xba\x9eH\xb5\xc6\xc0x?\x93\xefwI\x84j\x08S\xfaK\xd8\xb9\xd4\xf4,\x99\xa6g\xd1\xac\x0f\xb3\x10fJ\x06?\x7f\x7fz\xd2M\xefQ\xe6G\xd0\xa2\")\x81\x1b\xa3\xe9\xa2Z\x04-Ru\xa5\x08\xe8\xa3V\n\x01\xc7`>~x\xd3m,\xb2\xb3u\xb6\xd0\xfb\"\xc4\xf6\x86\xce\xfep~\xf6n\xa3\xde\xfe\x92\xa7\xa6\xb4u\x96MY\xc6\xa6\x9a\xee%\xe8\xdc\xff\x87\xd3\xf3\xb37\x7f<}\xb5\xc1\x18P\xf8\xc9X\x9e.n\xd8\xd4\xbb|\xf8\xb1\x8c\xcf?\xfep\xf1\xe1tc\xad\x0c\xad\x8fI\x84\x13\xbd]\x98J\x13\xdab\xde\xa2\xa4Qs=__\x15\x193e>]\xad\x14\x04\x0ehd\xdd\xa1\xf0\xfe\xf8\xc3\xf1\xdb\x87\x9a:\x9f\x9d{\xe6Y\xb4|\x17- \xd0\xc4U\x85\xd7\x84\xd6o]\x15\xdb\x85y\x13\xcc1\x9cg/\xce\xff\xe7\x92\x88 7!tB\xea\xbd\xf0T\xe6\xe7\xcf\xfc$\x9d\"\xd1\xda\x8a\x05g\x0dG\xb0\x16\xaa\x88$Z2\xa17\xeby\xb0\xad\xde\xc6\x89|\xc7?\xde\x11\x05\xaa\x1d\x1f\xf3\xf7\x97_\xc4\xf61\xca\xe9\xea\x02\x8e\xc0\xc3\x19\x8d?/\x17\x1e\x0c\xe5/Z\x7f\xa0i\xf7\x18\xe6\xf3F\xeb$7\xd6dA\x08#\x0f\xa1\xc9\n\x86Wv\x93\x10f\x97A\x08yg\xac9}\xfb\xfe\xe2O\x02w\xc6\xaf\xdf\x9d\xbc\xf9x\xfe\xba\x95\xb0l\x84EoY1O\x89\x1a\x0f\x83Kq2Y\xac\xa7\xect\xb9*\xee\xfe\xc8Ak\xf3-\xc2\x1cx+.y\x1ee\xc2v\x1be\x89\xef\xfd\x1ce \x06\x1el\x02\x08L\xd0\xe4\"I\x0b\xb8f \x17^\x19D\x80c\xfb\x1f\xec\xae\x87\x16d6\n\xe4\x18\x1d\xd7\x81#\x0f\xb3\xe8c\x04@\xce\xd9g/\x84\x9c\xaf\xfd\xba}\xed\xffx\xfc\xe6uE3\xce\x7f\xbd\xe5\x8e\xf3\xb3\xe3\xf3=z\xad5\x05YGH\x04\x84\xfa\x9f0\"\xe7\xb4\xe3\xd1\xe7\xe5\xe2Q\xdc+X^\xf8\xb1\xd8\xde\x1c\x0d\xd6K\x96\x8f\xc5\x96\xa4\xbe\xe4{x\xd2\xe3\x9ca\xc4\xa1\xf3s\x8c\xf3\x8bd\xcc\x10ArB\x18\xb1\x86!6\xdfcl4]c\xb7_R\xd3\xefx\xfb1S\xd6\x8f\x1a\xed\x10m\x95\x8e\x15\x94\x01\x95K\xecV\x18\"\x8e\xb0\x9bh\x11\xf3\xc9\xbd\xe7\xad\xa3\x91\xfb\"\x84\xb4\x835\x18\x87FAR\xe4\xa2\xa2\xc8!(\x0b\x85Ks\xfe\xa4\xd1\x93\x1d\x15\xa5}\x7f\x08\x93\xfco\xdc%\xdavx(\x1cH\xdaq`t\xd9\x15\x07\xbaX\x03\x81\xc5F\xd6\xacCj\xdd\x12\xb0\xdf\x18\xf0\xe7\xa7\x17\x9c\x9b{\x7f\xf6\xee\xfc\xc1\xb8\xb8\xcc\x8c\x07\x035\x1e\xce.\xc3k\x9d\xde\xd2A\xc8\xd6\x0ef\xc3_\xa3\x13\x1d\xc2\x07\x8e\xc0\xd0\xea\xdb\xa0\x15\xd6\xd2dP,\x8e\xfcC\xd1V/!\xcf\xc6\xd2\x90_T\x92? \x9e\xaa\x88\x8au\xce\x19\x16U\xb5zS_\x9bP\x96g,_\xa5I\x8eY\x02\xb2\xa07g\xd1\x94\xa19\xd2\xba\xfc\xfb\xcb\x17K?\xc0\x17c\x824\\\xe3}\xb1\x1d\x8e*i\x08\x91\x8b\xdd_;(\xe4B\xc1\xae\xf7\xc3\"\xbd\x12\xda\x97iTDzPm\xbb\x8e?A\x8a\xed\x1aD\x08^\xc1>\x17\x9cr\x88\xd6\xf8\x112\xe9\x88\x95\xff\xf1\xf1\xf4\xbc\xedJ\x7f\x03\xa4\xfc\xaf\xcd\x902\xd6\x90\xb2U\xec\xf8\xaf5\xcb\x0b9\xe9\xd8\x05\xf9.\xa2\x05\x9f\xf9\xdb\x8f\x17\xc7\x17\xa7\xaf\xfe\x91 \xb0\\\x17Q\xc1\xa6\x1f\x1e\x0e\x10\x929<{\x7f\xfa\xe1\xf8\xe2\xf5\xd9\xbb\xf1\xdb\xd3\x8bc~B||0:\xd5$r9\xa4\"\x01\x92O\xec\x8e\x96\xa6F\xad,\x85\x83[\xeaz\x1eYN\xa0\xe5J(V\x0e\xb5\x0e\xae\xcf\xf3 \x080{dY\xbd\xd2\x0el\xfcI\xab\x90\x8d\x9f\x1eUX\xe2\xaa\xb7\xe0\x87ll\x9f\xaci\xd0M\x1b$\x98\x87\x87>\xc5\x9a\xb0\xa3qOL\xd9\x82I&C'\x87Y\x08\xe9e;\xde\xab\xc9<\xe8\xd6\x7f\x98\xb9\x94{\xbb\xe3T8-;?\xf9\xe9\xf4\xed\x83\xadI>\x993\xeat\xfe&*\x96\xf2s,\xd6\x11\xd5\x13\xfdTT,\x13\xca\x87/_\xb0\x9e\xbc\xb6\x1dR\x1fxc \x83s\xf1\xe6\xb2\x9e\x97$(\x7fv\xbe\xbf\xdd\xa3c\x99=\xdb'4\xdd\xf2\xb67_\xb1I\xccr\xaf\x8b\x1d\x00\xb9\x16!\xb2d\x99\xcf\xd0_?/\xb2\xf5\xa4H3\x12zZ*\xa8HK\x0f\x7fx\x08~\x82mD\x01\xdf\xdb\x98\xdbh\x08\xa9n+\xd0\xe9*\xe1\xa6\x16\x87\x15\xe7\xb8\xff\x8cV\xd8\xef\x99 \x91\x86\x85\xfb\x94\xce>\xf1\x07V\x948\xa9\xb1\xa7\x14\xf6\x93\xde*K',78\xdbU\xc9\xfd\x94\x89\xf6k\xe5S,\xafg\xc0\xaf\xd7\x98c\x8d\xb7\x82\x9f<\x99GI\xc2\x0c\x85\xdb\x0d\xd6x\x15\xe7\xab\xa80\xc35/1\x1di\xed\xd55\x11\x80\xee\xae\xed*\xf7F\xa67\xd8\xb6\xc3_\x83\xd4\xea\\\x1bWJ>s\xe6\xbeW\x97Z\xd7V(R\xf5\x08\xba\x82\x15B(|B\x92\xa9\xbd1\xa6s\xd5h\\\xc1\x1fu\xe1%x\xcez[\xd5\x88V|\xe7O1\xc6\xc1\xaa\xb1\xc9*G\xba\x8c\xd6\xcaQ{\xf0\x9c2lJ\xaa\xe8\xaa\x95\x11S\xb2\xbd\xed\xb8g\xbb\x1emo/[o\xda\xd7\x8e$\x1a\xf2\x06\xe8\xc7j\xe0\xa1\x15\xae:\x84\xcc_\x06!,\xbf\xd3^5\xc7\x86\xd7VG\xff\xc8\x93[\x00\x87\x90\xf8\xcf\xf6\x02\x7f\x16\xe0\xb5l#\xec\xd0\x94\xe1\"\x9e|\xf2#\xff\x0e\xe3\x94\x0ct\xfe\x0f\x86p\x83\xc6`\xbd$\xbdmm\x0dk9\x1b\xc2\xd0\xc2\xb12\x19N\xd8-\xcc\x83\x1e'{\xbb\xfct\xe2\x7f\x0czi\"\x8578\x84\xab\x10\xbb\x8b\xfc\xb8\xb7J\xf3B\xeeB$5\x03d>&\xbdh:=\xbdaI\xf1&\xce\x0b\x96\xb0\x0c\\\x01\x0b\xb5\x06P\xdb=\xe9\xc5K\xde\xe39\x86S\xcdU\xd0c\xf7\xd4&\xfa\x18|tt\xe3\x07\xca\xef\xea\xa6\x87\xf6\x88t\xa7\xa1\xab\x10\xb6\xc4\xc8y_^\x9ad,\x9a\xde\xa1\x1d\xc2d\x1e%\xd7\xcc\x838\x81\x85\xef\x89 \xaf\x1e_>\xf7\x88\xf2^\xb4Z\xb1dz2\x8f\x17S_\xfb*\xe8\xd9-\xb7\xe1p\xde\xcb\xd82\xbda\xa21\x91 \xa7\xdc\xa7\x06\xce\xd6\x16\xb5a|\xac\xb8\x88\x97,]\x17\x1aF\x84\xd0\xaf\x1f\xb8\xfa\xd1g}?\x84\x95q\x06pZ=\x84i\xd5\x04\xfe\xf5\xedq2\x1bM\xebh:\xea\x08\xc2\xcd\x9f\x9b!\xb0v\xb2\xd9\x18\xc9\xb5\xb5kBQ\x02\xb2\xeb\xb6\x8e[\xa0\xb7)\xb3\xb3\xfb\x94dvv\xfb\x8f\xef\xc3\xe2`\xb2\x10\xa4\x95\xa9_\x88|\x1b:\x9b#\xed\xedJK\x08[\xf1\x82\x91\xa2{3;\xa5\x98\xf8\x82\xf3\xc2\xa8\x05\xe3b\x92\xb4\xa4\xe5\xec\xc32\xce7\x8cs[\x8fu\xffd\xef[\x02\xda\x17\xba\xe5\xc0!l\xb9\xcc\xb9w\xfb\xbf\xa4Q\x8e>\x1eY\xa7\x8b\xa5d+\xf3\"\x9c%\x1d\xa1\xc5]\xa8\x8f\x89\xe1\xd40j\x8aw2\x9a\x13\xd8\xe3\x81\xccOC\x88\\\xb5\xa112\x85zn\xa4\xb3}1J/\xfd\x88\xd0\x10\x98\x8f\xd0\x0e\xa2\x8a\xc2Y\xb7=\x8a\xb3ztF\x9e\x0c$\xa3\x1e\xdb\xe0K=x\xeb\xb7\xeeM\xd3\xa4\xda7%`\xd5N\xf0\xf3\x00c\xfav\xd0\x80\xab'\xf3=\xce\x15\xcb\xc8\x1b\x89\x88\xd7 \xd2'\\\xb6exq\x918\xc2^\nM\xc0\xb7R_\x84\xc9\x8e\xe5\xff\x98\x0d\x87\x8b\xdb\x9b\xa1Q5\xe9\xc1>}\xca>1\xe5j\xa9R\xd83St\xca\xfc\x15\xe6\xa1,\xc4\xf0\xa7\xfd.g2\xba\x1f\xe4\xd4\xc9\xbc\x15\xa1d\xa9TP\xf5\x8dX\nb\\\x84\xdf\x19\x84(\xb2\xa3\xa7|\x8aQ\xe2\x82@Jb\xa1\x90\xdaa\x07\x06!J\xe9\xecy\x99o\x12\xc5\xbe\xed\xed\x05\xbc\x80\xc9s\xd7\x81\xc2%\xa4\xb5_\x8c\x16\x97\x0e\x82\xcc\x05w\xc2y\x81O\x01{\x995I\xc7\\\xa6_\x8d\xa6\x0e\xe9XO\xaf\xcd\xbb\xe1\xc2C\xee\xdf\x840\x0da\xc5\x99{QA\x98r\xceQ\x80\xb9\xe1\x9c\xfc\x0d\x0c!\xe6c\xc6@\x17\xfc\xcd\xe8\x92\x9f\xceT\xf8!\xebM\xe6\xaf\xb0\x83y \x00\xc6\x87\xf7\x9d\xfb\x13\xb5>\xf7E\xc2\xbd\xfdN\xbc\x1bq\x14{\xe31\x9a\xb9\x8e\xc7b\xaf\xe0\x9e\xe0\x8c\x88\xfc\xc0\x86z{V\x9cZ\x12\x19\xa2\\Z\xa1\x12V1Zb\x1a\xc3\xbf\x01\x95\xd7\xa3\x82\x0b\xf7\x1b\x9a\xb5k\xf4\xc9\xe4\xc5\xd261\xab9\x10\x16C\x95\x9c0\xc4\x0d\xc1\xab\x9b\xe2\xb6\xc5\x8f\xc10\x94\\&E\xb3\x07B\x06p\x9b\xf7\x7f\xf5\x1d\x8b\x9dv\x81\xc7/lN\x1cBQ7\xa1\xc8Q\x17\xcd>\xb3\xc9\xba`\xf2N\x0b_ \xfb\x81?\xe4ir\xbeb\x13\xed\x95\xfc\xe9\nJ\x11\xfb\x89\xbfO\x862\xe7%\x83=\x87\xa3<\x91\xecX\xad\xc5/c\x0b\\\x9bL\xa3\x0cU\xa9\xec\xf3\x15\x9bH\x07\x05R\x1aj\xc4VfX\xf6TL{(L\xd1rv\x91rx\xcbz\x89^\xc55\xa1\x90Z\xa9_c655\xa1\xa9\x1b\x0c+\xc71\x14 #\xcc\xe5\x04\x11\xbc\x80\xe29D\xdb\xdb\x01\xc4\xa3\xe8\xb2\x96&$\"\x0e\x08\x13d1\x82*N\x14\x06\x7f\xa8_\xcf\x9dD\x939\xa3\\\x8c\x94\xd4\x11\x8f\xfa\x0e\x07\xa5\xdc\x0eP\xbf\x0e\xab;\xce\x80\xb2K\xe0\x8f_\x8f\xb9I\xe5\xacq\xf2\xe9F\x7f9\x1a{\x05\xbd\x7f\xc9\xd8\x8c\xa3<\xdeb\xf3\xedh\xcc\xd2W\xa3\n\x81]n\xc2\x80\x87\xd4F\x7fh\\!\xcd\xb8\x94\x0c\xda[\xa4\xd7\xb2k\xe1\xb6\xea\x9b\x1a\xdc\xfah-J\xb5\xc1h\xcb\xb0\x8c\xf7\x1f/\xc3`\xc7\xd2\xae\xd0\x8aRcP\x95\xbf?]\xef\xa2c\xb8\xd1c\xbd\x9d\xa4\xcbU\x9a`VJ\x0b\x04e\x94\xb6\xf3\"\xcd\x1c\xd6\x01Z\xa0b\xbb\x02\xde\xaa\xd5z\xb1\xeb\x08\xab\xa6\x8c%S\x96\xd9\xa5\xb9\x0c\x1c\xfe\x89\xbd\x8dV+6=I\x93\"\x8a\x13\xaa\xea\xa2\xdc\xbeK\xb6L\xe3\xbf\xb2\xc0\x8fDvr\x91>:F\x1e\xdcJ\xa2\xe5T\x0bfiZ\xbcN\xf8\xda8\x9d\xd9\xf4\x99\x0d\x810\x1c\xe7\x0f1\xf8\xa19\xd0\xdc\x1e\xe8\x02\xc7J7)\xa05\x84\xb5\xfdYd\xdd\x88\x80\xc5\xcb\xba=\xd5Z/\x9a6r\xf6\x02\x0d\xd9(\xc2\xd9\xe2\xf4\x05\xbf\xa8\xe3\x17Tk\xeft\xfe\x02d\xe58\xf3\xfe\x94bf\xd0=\xea7\xb2\xf1uTD\xfa'p\x04\xff$0\xb0\x81y\xbb\xe6\xcc\xdbcj\xbe\xd7$[\x17\xcb\x12\xda\xe5\x0cK\xac\xd6\xd6\xaa5\xca\x01\x11?1\x0b\x16\xb2\xc0\xead\"\x0b\xac>f\xb2\xe0\xc0,X\xe1\xd2\x99\x97\xe4S\xac\xbe2\xde\xcee#O\x9eXC\xbd\x11\xe2\xffc\xf3\xfa|)?y\xfa\xf8\x19\xcd\xe6^\xff\xbal._W+\x1d\xb4C\xe5k\x13\x81\x06\xa3l \x8eR\xa7\"Y=\x9a&\xb9\xad*\xd4\xaf\x18\xf2\x8aM\x12\x1a\xefL\xda\xe1L\xcc\x02?\xeb\x952\xb3\x8a\xe8\xbf\xae\x19\x9594\xe7n\x0d)\x90:\x04\xfd\xd1F:\xab\x19\x06%r\x98\x8b\xda\xdbQ\xfb\xdc?\xb1\xbb!xb\x1f{\xf4A\xa0?\x9224r\xec\xd4#\x07>-\xf5\xd7\"\xee\xc7\xa9Hl\xcf\xe9\x91a\xbf\xf67\xf4u\x0fdn\xf3U\x96\xaer\xf9\xf7$M\n\xf6\xb9h\x81#\xb4\xc2\xf2\xebe\x10\x12\xe1\xd8\xcbb\x7f\xd5+\x89\x9dK9\x8d\x98KC-\x95\x9c\xc2\x0d\x1fp\xc2&\x85\x16\xdb\xa4-\x80\xeb\x8dL\x8eo\x9a_\x7fE31\xe6S\xd1'\xd5\xa3PD?\xbe\x96\xd1\ns\xd0_\xa4\xfc\x04@\xdb\xe7v\xa9\xc1h\xb0}\x9d\xf1\xde\x9a\xba\xc7\xd4\x1f\xf7\x9a|\x0d\xfc\xa4\x8c\xf1D\x146d\xf6Ij7\xee\x0d\xd4d#J\xb2\x01\x15\xf9\xadP\x107t\x1f\x96rl@5\xeeC1Z\xa8\xc5M\xef}\x96\xde\xc4\x9c\x97\xef\xd0\x18 j\xa6Y+j\x82\xe0\xb16\xa3Qn\xf2t_:\xdf@\x97Zh\xd2W\xb1\x81`h$\x0ci\xb4\xf4j\x8c(]r\xc6)\xe7\x8c\x1b=\xa7by\xd9JS&\xd2\xba'\x1670\xc9(\xbd\x0c!\xc3\x7f\x19\x99\x88\xa6i6c\xbc\xacp\xb0\x9f\xc44\x85\xcdc\x830\xde,\xb1C\x9d0\xb8x\x1c\xf58(\x82\x9b|\xeb\xa4\xff>\x14C\xa4\xac\xc5\xda8\xb6\xf6\x93\xe2\x8a\x03'\x12Z~\x8c\xb2G\xa3^\x13=\xb5\xa9J\xb1)U\x11\x14e\xa2\x90\xfb\xe7x\xb1\xf8\xc0&,\xbeA\xa1%o 2&\x81id%\xf9\xa3M\xb8\xda\xbd\x9b\xd2\xd4\xafM\xa4\xa7#y\xdc\x944\xaa\xcb\x06\x0e\xd8e\x1d7\x14 \x8a\xa4\xd3\x96\xa6\xee\x8b8A\x18\xb9n\xdc\xf4\xa7@a#\x0e\xc1\xcb\xd2\xb4p\xdd\\\xa8\xa7\x9d\xa5\xdb\xd8\xec\xc1A\xfa\x1a\xc8\xde\xd7P\x97B\xc9\xedn\xc5c\x03\x8db\xa9\xaaY\x08\xde\xf1j\xe55\xcc}\xde\xabl/x\x7f\xbek\xe6q\x88\xb7\xa2\x81\xc5\xcc\xb4\x1aUTJ\xb3$Z\x12z\x8e\x16\x90{\xd3\xf8\xc6\x92\xe5\xd5\x93\x17w\x0b\xd6\x14\x14i\x15M\xa7\xe8B\xee\x0d\xd8\xb2\x01k'\xe9\"\xcd\x86\xe0\xfd\xff\xa2(r\xe4\xbd\xb3W0\x04\xef\xff\xf9\xdf\xff\xb7\xff\x03<\xf7\xf9\xea\xc5\x9e\x00\\\x08\xdeI\xe9\xa8.\xd7\x96/\x0c\xe6\xbf>\x84\x02\x8e\xc0\xe38\x0f%\xb5\xf0`\xc8\x17\xd1\x0b!g\x0c\x8a9+\xbd\xe3=+\xe4w}b\xb7\xad\xca(\xb5&\xdd\x18f\xb9B[>\xab\xd8o!oW\xdcx\x9c\x7f`\xd1\xa4h\x17.\x9a\x0dI\xf5\xa7\xf3\xd1\xa5\x9e\xf2\x08k\xa7:\xd0\xc2\xdf&N\xfe6i<\xad\x92{\xf0\xb7\xd0*\xd5\xd1'RB\x9eHI+\x9f\x0b\xdd\x89\xb9z6%\xea\xea\xa9\xae\x02:\x9cI\xea\xe9 \xe1&n\x1a\xdcI\xc2\xc5\x1bwz\xda\xd2\xbd\xa8Dl\x01\xa3\x06\x0d\xa8Y\xb5\xed\xde\x1dZM\xfdJ\x06\x95\x91\xb7\x83Yy;\x88\x96\xa9\xe2v0\x85\x17\xc0\x9eC\xba\xbd\x1d \xd7Y\xbb\x1dt1\xb0\xa0\xdf.\xe9h\x9b9 \xd7\xc9TP\xb6XOG\xc5\x87\xea\"\x92\xe36\x89G:d;VL=\xc27\xbb\xc0c\xc6\x8d\x1f\x8e\x99Q\xd4\xddPgW0\xb4\x94\xc6\xf6\x19\x9d\x86\x10\x9b@\x8ag\xe0\x97\xc6[U\xe2\xbf4\x90A+\x13v\x0b\x17w+v*\x12x\xbdcl\n\x11\x88\x0fB(R\x981\x0e\xfd\xa8:#z\xf0s\x94\xc3u|\xc3\x12\x880\xd5\x8d\xaf\x99\x04\xa5\xfcPY'BM>\xe5\xe7\x89q\xe1\x9aZA08\xd6 \xa3-3*\x84\\U\xce\x8b\xc5\xbc]\xe4(\xb0\x1b\xfe\xf3N\xb1\x9f>\xfa\x14\xe0\xcf[?\xc2\x1f\xb7\x82[\xf3\x99\x1f\xf4\x16\xe9\xb5\x0c\xeeR\x9d\x86\xb38\x99j\xc7\x1e\xe70$\xb3Q\x0e\xa0\xd3%\xa1\xdb|_Nx\x08\x89\xff\xe4\x89i\xc8W\xe9\x8c\xeb\x97\x03]\xba\xa4\xaf'\xdc\x03\x99G9^\xb3\x0bG\x89w\xe9\x94\xe5C\x18\xddX\x12\xc2:\x04\xe1V\xa4\x90\xd5w\x10T4\xdb\x16\xb1\x93\x1c'\x838\x94\xd7x\n$x\np\xc4Jz\xf2,\x80\xa1\x8a_\x87\xb1\x89\x9d:\xee\x05\xca\x11\x92\xfd\xec)\xa4\xc6hl[\xfd\xc6\x03\xd0\x81\x8e\x8dwR4,\x0b\xa1U\xd1\x1b4\xb8@\xd26[g\xd0\x84\x1b\xec7\xf1\\\xf5Q\xcbKC\x93\xceO\xd1b\x8cz[\xc4K\xa2\xc4SE;\x8bt\x12-<\xbb\x06[F\xf1\xc2~\xbdL\x93bn\xbfN\xd6\xcb+F\x8ck\x15\xe5\xf9m\x9aM\xed\x92\x8c\xef\x07\xfbu\xce\xa2lBtP0b0\x9c\xef'\xde\x923^gD\x03\xb7\x8c}\xaak`\xdb\x94tN.W\\N*v\xb6\xfe\xab\xce\xb5\x92\xac\xae\xce\xe5\x16p\x04[[\xd9Hp\xce\x98b\x8e\xcf4\xcaX$+T\xe3}p\xfc\x12\xa9\x03\xcf'\\\x8c|\xc3f\xc5\xd0\x0c\xe1U\xabq\x91\xae\xac\n\x19\x9be,\x9f\x8b\n\xb8m\xf3\xb6}\x98\xf5\xac~Q:\xf8\x1c\x9aE\x17)\xfaK\xf7\xeejm\xb4\xee\xc3\xec\xdb\xe1\xe4R\x83\xfa\x83\xc7\xa6u\xbatM\xb7B\xc1E]\xd4W\x9c\x82\xb7\x86\xd6f\xbdY\x9c\xe5\x05\xaa\xf4\xddZ\x1b\x94\x9f\x12\x112\x06\xd3ic}\xferO\x8aS\x1cC/\xeeV\xd5\x89s\x93\xc6S_\xbc\xc7\xa5\x83\xc3v\x0f\x15@`k\xeaX\x8bU\xd2V\xc5T\xfbvW\xf9r\xae\xba\x15\x82{\"a]918\xe2\xc4]\x04\xd3AMy}j\x15\xde\x04F0\xa6o\xa0\xdc\xdd(\x07}\x1f\xcbz\xb3t\xb2\xce\xcds\x86v^~\xf0\xdd\x1f%\xf1\x12c\xdb\xbf.d\x90\xfb\x93t\x9d\x104\xf6*\xcd\xa6,{\xbd\x8c\xae\xd9\xd9\xba@\x06\xbf\xa1\xca\xf9\"\x9e\x10$Y\xab\xf1s<\xa5\x8e\x95\xab\xf4\xf3\x8f\x0b\xf6\xd9Y\xf0\xfb,]\xaf\xc8\xd2\xb3l\x1a'\xd1\xc2Qa\x92.\xd6K\xd7\xdcDan\x17\xcc\xc8\xa1\xcc\xc48n\xe9\x92\xf7i\x1e\x17\xf1\x0d1{^z>\xcf\xe2\xe4\x13]\xf6\x8e]G\xee/1\\\xb1]t\x9d\xc5\xd3\x0f\xd4Xd\xc1iB\x1c\xc5\xb2\xec|\x15%\xee\xc2\"\xca\x08X\xf1\xd2\x13\x84WS\x99\xb3WQ\xec\xeeX\x96\xd3}\xcf\xd2\xa4\xf8\x99\xc5\xd7s\xa2l\x11'\xecd\x11-\x89\xb5\xe7E?9>KW\xd1$.\xee\x88\x02\x1a\xdci\xb6\x9aG\x14\xaa\x14\xd1\xd5y\xfcWb\xedn\xe3izK|\xf0\xd7\xd7\xc9\x94\xc2\xae\xbf\xa6\xe9\x92\x98z\xbcX\x9c\xb9\xc6:[\xa4\xe9\xd4Y\xca\xb9\xd9\x86\xc2,\xfd\xc4^E\xf9<\xca\xb2\xa8\xb1B:\x9b\x91\xdb^\xd4x\x1b\x17,[\xc4\xcb\xd8Y\xa3e\x0c%A(\xcb\xbe\xda\x17p#\xefgv\xf5).\xbc\x10\xbce\xce\xff}\x9b\xfe\x95\xffw\xe6i\x9a\x1e\xa9\x89\xf9\xc4\xeer?\xeb\xe2\xee\x9d\xdauh\xa7\xe3Q\xeba\x0e\x9a:\x11\x13WL\xe6Qv\\\xf8\xfd\xa0W\xa4\x1f\xb90+5\x99\xbc,__ \xc3\x0b\x7f@\xd9\xa4\xa3!\xe8%gf\xf4\xd0\x97X\xa6\xa98\x8d{\xca\xd8\xa2\xf1q\xfe1\x89\x8b\x05\xcb\xf3w\x92i7\xdcs\xf3y\x9a\x15\xf3(\x99*\xad\xd5\xe9\xe7U\x94\xe4\"'\xa3=\xc5\xabh\xf2\xe9:K\xd7|\x8f\xd3\x00\xa8j\x1c\x17E4\x99/\x19Ev\xed\xda'\xb4\xaccW\xc4#\xa4KEA\x8d\xd3\xe4\x7fnR\xf9O]*\x7f`+\x16\x15C*\x8d)\xa1:\xb1;i\x87\xdd\xfd\xc7\xdeiD\x92\xc29F\x81\xa5\x8eC\xba^\xe9\\\x98\xc76W*W\xb6\xfb\xd0~H\x8b\x82\x93\xc2\xa6\x01\x8a:\x9d\x86)\xaav\x1a\xac\xa8z\x8f!\x0b\xf1\xa9i\xc0\xbcF\xa7\xe1\xf2\x8a\x9d\x06\xcb+\xdec\xa8\x1f\xc4y\xd84V\xac\xd2i\xb0X\xb3\xd3h\xb1\xe6=\x86\x8bbg\xd3`/\xd2U\xa7\xa1^\xa4\xabN\x03\xbdHW\x1b\x0d\x93\xf3&\xae\x11\xf2\xb2\x96Ny\x95?FY\x1c5\x11\xca&\xfeG\xafC3\"\xeaib\x87\xd4\xc3[\xf91Z\xc6\x8b\xbb\xae\xf3O\xd7\x05o\xd8\x05\x02Y\xdc\xb2D\xb2V\x0b\xacd\xad\x86\xe5\xf9\x8e\xfe\xe5P\x15\xc4\xf8\xf6\x9b\x84\xaa\xc4\x7fj\x06\xe3K\x85a\xd0`\x1f\xe3\x02\xee\x89\xf0\x80O\xfb\x96\x83\xbc4 \xc2rv\x0b\x1f\xd8\xf5\xe9\xe7\x95\xef\xfd\xe7\xc8\x83m\xc8z\xc7\x17\x17\x1f^\xff\xf0\xf1\xe2t\xfc\xee\xf8\xed\xe9\xf8\xfc\xe2\xf8\xc3\xc5\xf8\xe4\xa7\xe3\x0f\xb0\x0d\xde%]\xa9,\xfe\xdd\xbfXi\xcd\"\"\x1e\xfbZ\x06\x80(_\x96w\xa5\xb9\xf3\xaetkkmG`\xc7\x00\x81\x11\xf1\x9e\xcb\xfd2\xfb\x1a\x1a\xb4\xf9\xeb\x11\xbb\xc4\xb0\xaf\xa8\xdd\x85!\xf8\x91\xf6\xa6\x16H\x9bNs\xdc\xc5\x9e\x10\xf3\x84\xcc\xa3\xfc\x874]\xb0(\x11:\x80\xef\xbf\x87\xad\xaa\xe8\xddz\xc9\xb2xR\x16\xc5\xf9\xbb\xe8\x1dg\xfeT\x05%\xce\x99\x15\x0bx\x01\x83\xb2\xd6\xd9\x0d\xcb\x16i4eS\xab\xaf\x01\xa9\xc0\x03\x89<\x13[\x1f\x87V\xcbo\xa3\xec\xd3z\xf5c\x9a\xbd~\xd5\xaaJ\x13\xd3\xcez\xaf_\x8d\xeb\x88\xc0q\xe0\x90cHj\x85\xb4\xae#@\xce\x8a\xe3\xa2\xc8\xe2\xabu\xc1\xac>\x1d\x8c.f\x9b(\xbf\xf2\x89\xee\x89\xe0\xefM3\xfd\x90\xa6m\xd7\x95\xe5T?\x9c\x9d]\xd8\x93\xfd\xb7C\xcf\xfb\xb7\x0d\xe6i\xf4HB\xd7\x9a&\xd1uXK\xdcK\xf4k\xccT\xed\x8c\x0ePV\xea?\xbc\xfc\xe6\x1f\xc5,'\xf6\xd7Q\xad\xc2\x08U\xc8\xb4Q\x15j ]\x82\x0bF\x8b\x14.\x1f\xa5~\xd0\xf3huc\xe9\x07\xd6\x8b\x14tl\xb3\x0e\xf5\x94\xf6\xff\xe6n\xfc\xf2E\xbcl\xd8@\xfdRE\x1e\xab5\x86!\xfe\xad\x90\xbb\x93\xbe\xb2\xc4\x9d8?Y\xe7E\xba\xac\x16\x15\x01X\x91\x0d\xbc\xc1\x1a\xa2\xf8V\xf5 \x01\xba\xc1*\x1b\xbdtXl9\xc4\\RL\x15{\xa7\xc00#\xc6`<\xaf\x05\xd1\x11\x80ndk\x880\x92\xb6\xe0[a\xe1[\xd1\x8co\xa4\x1f!h8\x94\xf60cW\x9c&T\xbeD\xf5\xf0\xa6\xe2@hw]\x06~l\x913GgP\"x\x8a\xee\xbd\xba\x02\\\x98}\x89\xabb\x13pb\xb9\xe8\xeeT\x9b|\x02y\xf11/\xed>\xd0$Q\x81\xe8\x8eo\x8cK:@\xabzZ\x06\x0e\x9a\xbdQZ\xdfq4\x93\xa4?k\xfb\xa3|\x15M\x1c{\xb5\xfa\xea\xc8\xa0~\xef\xce\xfd\xb5\xc8\xa2\x877\xbc\xe8.O\xed\xe8\xb4\xd3\x8eN\xac\xf6}l:P\xa9\x8c\x8c\xf7\xd8\xa5s\xc4\x8e+|\x9b0\x08Hc\xd0}\x82\x14\x14\x06^Lz\xdaV\xd2(\x86\xdcA\x1d\xf7\xa0\x8b\x0886a.\xf3\x00\xf8\x8a& P\x89\x84\x15\xfaXmH\x15%\xa4\x1a\xc7V\xc7\xf4Mh\x145\x8c\xee==\xf0\xc9\xb71%r\x9e|\xa5\x85\x7fgJ\x94\x06\x9c\xad\nU\xf0\xe3\x06r\x84\x1d\xdb\x04\xc2\xbd\xd9\xab\xa3U' \xee\xddj\x1f\xabG\xc0F1\xb2\xd3\x03\x0c\xfb\x8b\x7f{\x0e\x9fc1J{a\x8d\x93\x9d8d\xc5\x97\xf4>\x12\x17\xe2m\xc8R\xfer\xc8f\"9\xe77\xcaf\x03*lq\xe2\xef\x0e\x1c\x11\xc6\xcdp\xeb2\xcf\x97\xd9\xca\xba\x92\xdc\xb6\x06\xa4\x91lnq\xb1x\xd7\x8bV\xccY\x9a\xa25\xcd\xebW\x95\x0dv\xcd\xdci\xc5\x92i\x9c\\\x7fD\xa3\"\n]\xda\xbe\xc1\xe5\xb7\xb1\xc6\xf0.\x10w\xed\xf2\xcaU\x06C \xf1\x04\xc3\x9aW\xf6B\x94\xfdL\xc5\xb1|\xff=(\x03>\x89\x98>\xeb-\xd7\x8b\"^-\xa8\xb4P\x15\x1e8\xc5=\x82X\xde\x94\xd9\xd8\"\xcc\x81B\x1b(\xf5\xd2UaGEu\xde\xba\xa3\xbbA&\xc4d\xdd\xe5 \xa9\xbb\x1cd#AhG\xe9\xe5\xff\xcb\xde\xbbv\xc7\x8d\x1b\x0d\xc2\xdf\xf3+J\xcc\xacCF4\xad\x8b\xc7c\xb7G\xd1\xeb\xb1\xe5\x8d\xb3\xe3\xcbZ\x9e\xe4\xeci+Z\xaa\x1b\xdd\xcd\x11\x9bdH\xb6de\xac\xe7\xb7\xbf\x07\x85\x0bA\x12 \xc0\xb6<\x93d\x1f|\xb0\xd5$\x88K\xa1P\xa8*\xd4\xe5\xac\x93\xc0\xa4\xd5\x92\xd2B\xdcn\xc1L\x89X\xd0\xcd\x0e\xb1\x8b\xa7\xf9\x197\xa4\xd2\x93\x02\xacPaLU2\xc7[\xf1\x0d\x9e\"\xed\xe7Gj\x82xQ:\x1a\x13\x137\"A\xc3\xa6\xde\x02O{r\xda\x01R\x907\xb3@&\xa0l\xdb!t\x87\xba\xa3#\xac\xb1\xe2k\xe2\xc7\xd3\xbd\xee\x17F\xcc\x12\x7f\xe9\x05\xef%\xa9\xff\x9cW5\x06Mq8\x9f\x84<\xc1b\x19\x99\xecA\xf3\x8c\xd9\x01Nz\xd6\x8c\xe2\x8d~\xb3q_xv\xb8\xf4\x97k\xf0\xc8]\xe7\x9b\xac\xfe\x1b\xeb\xcba\"\xe2\xa0U\xf6\xb6\x8e\xdd\xed\x8c\xbf\x07>QZ$\xc8\x9c1*\xc9\x92:\x89Sn\xb9*\x08\x07et2\x984!?\xf1\xbdI\x8f\xc9\x12\x8eU\xecs\x83\xaeP\xc2\x7fX\xcc\x17EXw\x8d%\x8e\xa20@\xf2\x10\xceoy\xe7\xec\"\xcf|~\xeb\x0e\x04\xdf\x85\xba\x9b\xd8\x0eP\xcd\xb9\xe3*.|\x1ec\xcb\x18\xd5\xe0\x96\x85\xaa5\xd9\xf9_\xc7\xd5kN\xbc'\x92\xa0\xd7\x0dA\xefch\xa8\xa6\x8d\xa8\xf9\x8eW\x13r\x1eu\x16\x99\xbe\xdc\xa0\xc9\xcfF\xb7\x8d\xc3\xee^e\xc1\xa3\xf1\xd3\xe7\xcc!\xc8\xb6\xc6\x06/\x0f\x15\x13\x87\xfa,\xf2\xaaf\xa0\xd7\xec-\xd3\xc6bVmZD\xb2n\xb1\xd6\xc8\x0cY\xe7\xa1e\"\xd6\xfe\\Y4{_Je8\xd2-\xb1\xbe\xdf\xd2N8\xc4\xde.\x99\x7f\xb6\x8da \xd9q\xaf\x19A\x08%Ztex\xb6i*42\xd3N\x0f\xbb\x8e\x07\x9amW\xa5]\x0c\xd5\x15?D>\x13\xaf\x17)G\xfe\xfa\xaaLm7\xb0m\xae\xe7u\x19O\xfbx\xbf\x1b\x91\x80g\xcdy\xd45q\xdc\xf0\xe7\xdd\xfb\x8c\x8a;:\xd3\x0e\x809<3\xdewx\x13 \x19\x93N<==\xb4\x96m\xd6\xab\xf7\x11\xcd\xfb<\x1c\x97\x91\x8fxz\xa2}\x91/\x8f\xee\x88\x98\xc7\x00\xf1\xd3\x0e^J\xb9\xccc\xd9\x92Zi\x8e\x86\xf4b\x86\xb3\x88)\xb1h\x03z\xb9S\xeb:\x84A\xfc4\xa1:z!=D\x11|\x8bI%\xbb\x17\xc2\x0cv]\xbc@Ax\xf9\x0eU\x80\x16\x0d\xa3\xbcu\xbc\xd6\xe6nP\x0bg\xab\x85\xf2\x18\x9e\xaf\xc8\xec\x12\x03K\xf1\xc05,\xf55\xe4\x0b\xf8\xbf\xe8\xa3\x05\xbb\xe0\xfd\xdfH/\x9a\x82Q\xb1\x03\x8a!\xb5A\xac\xf5\xf3\xe8<\xbf\xceHI \x87\xef\xed\x1f\xeeyMX\x89\x04\xd5\xc9\x13 \xf2\x10f6\xae\x98\x16MV,\xb6\xec\xc8\xb7\x1c\xc1\x86#\xdc\xab\xac&e\x16\xa72|\x8b\x8f\xc1%]<`\xc4\xac\x1a\x8cQ3p\xdd\xbb'NPf\xf5\xda\n\x95\xa5\xffF\x8dfK9\xc3&\xa4\x8c\xcb'%\x0b%(?\xea\x03\xc9g\x10\x088\x082r\x0d\x15\x9b\xae/~\xb3\x1a~\x1e\x04\x11\xe7\xb2)\xa3\x83\x87}\xd6zr\x04\x19C4\xbcr\xcb\xe7]r\xc16\xae)7\x99\xc7\x9c\x12\xba9\x89\xdb\x0b\xc3\x9d+s\x0c\x1c\xe1#\xb5G\xec\xd8\xf7\xc2\x86\x02\xb4q\\\xde^\x9c#\x00\xd1p\x8fy\x8f\xcbGk\x96\xc1\x97\xb9)w\xf3+\xd1\x92\xfb\x95\xea\xbf\x98t\x05\x86s\x16\xc9\xa1N0g\x8a\x1a\xe4l\x02\xcd\xadC7\x81,{\xf3uN\x92\xef\xbay\xd6\x94P\x17}\xd4\xfd\xf3\xdb\xd3\x0f=\xc7\x00Z\x9e\xbf}\xfd\xee\xed\xe9\xab\x0f'\x13\xd0\x88\x02'\xaf\xdf}\xf8?\x138\xe8\xbfY\x92\xfa\xc3M\xe1\xc4\xb8\xb7/~;'\x01\xdd\xe8\x11v\x83\xea\xea\xa4\xfak\x9c&s\x11\x15\n\xd1\xd6\xb0 \xf8\xbeN\"9\x05\x98@\x12\xd1\x99\x8a\xa4g\xa5\xef\x1d<\xd2'o\xec\x88\xd4\x067\xf1/\xb5=`\"x\x1f, f\xc68Y\x17\xf5\x8dD\xa4\x97\xf1\xac\xce\xcb\x1b'\x88R\x92o\x9bR\x1f;\xfa\x8d\xb1]\xe7\xd4\xa5\x90\xa7\xed\xb0l`\x90Dl\xa2\x94k8\x82<\xbcS\xd8\x9a7\x07\xdf\x05,Ve\x0f\nm\xf5\xf3\x95\xd6K\xdcpL\xd8\x00\xc5\x81\x94S\x04\xa7Tk\x9fR-\x86\xa9\xdc~\xc4v\xd5\xaf%\x83\x8e\xddb\x82ZK\xfbI\xf5\x01\xdd;\xc6M\xa8\x15\xc8&\x19l_\xac\xb7\xce\xd2\x88\xbd\xfc\x9f$#e2\x93cx\x9e\xc6\x95\xd5! \xf8\xd2j\xb0\xbeO\x9bX?\xad\x89:w\x92\xb8l-\xf9\xeb\xeby\x19\x9aQ\xfb\xe1#\xc6\xe1\xef\xf7rj\x08YB\x97\x81S\xec \xff\xa0\x9fiD\xd1\x94{\x91\xa7\x11,\xbc\x89\xe7.\x08H\x9c\xa1\xfc\x8b\x86\x7fW\xef\xceItIn\xe0\x18\xe2\x88T\xb3\xb8 >>\x08P\xc5T\xe7,G\xaa\x7f\xf8H57\x12\x7f\x8d\x89\xd9\xd51=\xa2\xc7\xc6\x9e\x92+\x9e\xa7\xa9\na\x16\xea\x13q\xd2E)BLr\xc2gQ\x1b\x04 %\xd2\x1e\xe5\x00\xd1\xb7\xcb\xbb`\x92\xaaxD\xf9\xaa\x9a\x13\xa2&\x94\x9a\x88\x94\xd10O\xbc\xae\xc26\x89'\x0dTy\x17u\xf4\xcd7|d\x18\xf4Or\xf83\x7f\x81 \xf1\x85p\xa2\x07\x8b\xc6\x0e\xa3\xf7\x84\x13\x94U\xeb\x05\x86\xda\xf0\xbc\xae\xb9\xc5\x97\xfaA\xb2\xd0\xa9h\xcb\xb2 \xa1\xc2tn3v(\xeeuo\x7f\x17\xec\xf6\xf7Q'\xe0%S\x7f\xe9N\xad\xc2\xec4\xfe\x92\xd7Q\x04lq\n\xf5\x177k\x02\xe4\x98\xf2\xa9\xf5?\xa2G\xbb\xb4!\xf6\x98\x07\x12\x06\x89\x0c\xa2\x92\x14i<#\xfe\x83\xe9\xc7\x8f\x7f\xff&\xfa\xe3\xee\xb1\x1fL?\x9e\xfdr\xfb\xf9\xec\xc12\x04\xef\xe3\xc7o\xeeyJ\xb5vW\x9f\xa5oT\x10\xfd\xf1\xd8?>\xfa\xf8\xf1\xa3\x1f|\xc6m\x1b\xed\xf2\x07g\x01\xb6\xf4\xcd~\xf4\xc7c\x86\x18\xdft\x03\xc2\xeb\xbd`\x85~\x8d\x8fV\xa7n\x96\x06|hF\xdc\x0d\x10?\x184X\xd8,\xef\xb7\xbf\xf9]\xff\xaf\x8e\xb2\xae\xe1*\xd8\x11\xb3(\xf3\xb5Qm\xf2:\xc6T\xde\x85\xff:.Z\x06|\xaf\xe3\xc2AQ\xd3\xaa\x85\xdbL\xb6\xd6y\x1e\x18\xdb8%5\xfb\xe8\x94\xd4\xad!\x9c\x92\xdaa\x08\xadZ\xca\x10\xfa\xcf{q\xa4\xaex\x92r*#\xbc\x8e\x8b>b\xae\xf8\xcbS\xd2am\x9c\x12\x9a\xcd\xa3\x8a\xd4\xecm{\x0d\xc3v\x0e\xea\xa1\xe5\x9fGK\xd2\xd7@\xb3D\xb8\xc3\x0d\xcc\xb9i\xa0\xe6\xe3\xd8\x16T\x8ew\xde\xe0\x8f?g4\xb4g\xa1\x85l\xf2\xf0@VQ<\x9fkF1\xecx\x0e<\x07\x83a\n\xd6\x98\x94\xfd)\xac\xf4Sh6\x94\x8e)\xba\xe2\x99\xe6\xbb\xee\x07\xc0\xb3\xf2\xe9\x9e/\xad\x13\x03Eg\x1a\xe9C\x1ai\xda\xbd\x19\xd3.&~~\x95\xd5>\xe1\x1e\x9b\xfe>ej\xf74\x8a\x8a-P[\\\xdf-\xb5T\xef\x8ae\xc8\xac\xc7c\xbd8s\xf4\xed\n\xab\x8bi}6~?\x0c7\xcd#.\xe9\x9av\xdd-*\xafq\x15D\xeb\xb8\xf0o\xb6\xd8.\xc3\xe3\\\xb3l\xf8\xddD\xf9.\xbb\xc9 \x00k\x0d\x00\\\xf7\x9a\n\x80\xb5\x1e\x00\xbf\xeb\xffE\x87E\x05\x85\xe9\x99\x8e/97\xf3%yo\x1eF\xf3\xa8+\x99\xc2y\xb6J\xd2\xf9\xab\x17:\x99\x0c\xc3Oe\xd2\xab\xfa|\x8c\xb5\xd7\xb5E\xc8\xf6>f\xd8G\xc6B\xd13\xcd\xffO\xd9e\x96_g\xc8s\xf8h\xc2\x0f~\\\x03c\x80\x16I\xca\xa2\xf2H\xd6\xe6\xef\xd1\x1f\xa7\x1f?~|p\xf6\x80Y\x1c\xef\x827au\xd3$#\xccM\x9a>\x0c<\x14<\xb19\xa69\x9b\xc3\xc5\x0d6\x9b\xc9\xf7\xaa\xf3\x87nB'}\xb8k\xf4\x05\xde\xef\xc9\xba\xa8o\xb0\xc1q\xf7\x1b\xde\xefk\xf2\xa96}(\xd4\xd8\xfc\x8f \xff#\x9a'U\x91\xc6hY\xca\xdc\x98\xf0i\xc6\x7fJ\x80\x0e\xce\xec\x93\x01\xa3B\xc4\x90Sz\xde\xbeh\xba\xd1Z\x97\x94\xa2b\xa3\x91\xefW\xcaE\xa5\xb7\xd7\x19)_\xbd\xe8a\xab\xd4\x8b\xa2\xe5\x8c\xae\xef<\x08B\xb8\xc6\xfc\x91\x80\xb1\xc8\xcf\xab|S\xce\xda\x1cE{'\x9d\xf6\xb4\xb6yvJXH\x9d\x92dcL\xab\xf4\xd6\x92\x14\xd03\xdf\xdb\x7f\x88\xd1\x923\xb9\xa1\xe8\xee\xeaW\x97\x92z\xc9$\xf5\xb2\xa5\xbe(\x87-\nY\x8e\xb9\xd2\x90Z\x1f\xb8\x0e/\xf7\x13\x93m\xa1\x1ck+:\x7f\xdc\x8cY\xaf\x8c\x8b#\xc2\x83\xf9(\xcch\xeb!6\xbaO\x1b\x8d\xa3\xa4z\x9do2\xba\xc9Xo\xdf\xed\xb7;+\xe2\x92d57\x90R~\x1ea\x8cr\xe5\x01^\x8e\xca\xd6\x0f<&\xec\xc9\xf7.\x176\x1d\xd5h\xf6\x03Y\xe4%y\xdd\xbaAu3\xe7/}c\xb8H\x0e\x87 h2\xaf\x03FSc\x03\x9e@\xa6\xaf\xc0\xec\x9e\xcc\xf6oby&05\xac\xbd\x84\xb9\xd9V\x8f\xc55\xe4\xc1s\xc6Z#\n\xc8\xfd\xc4\x1b\xd1\x83n\x9b\xddC1JA\x194\xfe\x91\x98\xd5\x8bb\xd5\x1b\x96y)\x87N|\xfd`\xea\xf6V\xae\x95a1\x97Va\xf1\xa6b\xf0\xc6r\x95\x92g\x030\xdbf\x8c\xa8\xc7m\x01\xac\x8e\x94\xb5\xdd\xdd\xb5\x8c&[\xdf)\xc8X\xa4\xc7\x16\xa4\xf6\xf5\x90\xaa|\xa2K\xc7x!\x82\xf7\x0f\x8d\xbb\xd8\x94K\xc2\x87N\xe6r\xf0\x95\xc5\xd5\x14\xc3j\x9eF\xe7EI\xaeHV\xbf\xdb\x94\xcb$3*j[\xc9\x94\xf6\x9e\x02\x81\xef\xe1B\xd2fb\xa6\xcd\xb4\x9c\xfb\x17Sr\xe6\xaa8\x03\x9c\xf8@\xd0\xfa\xe1[\xdaf\xb7\x7f\xc9\xe2 \x85\xcaN\x17\xa9\x86\xfa^\x92\xfa9\x8f\xecW\xc7\xb3\xcbg\xf39\xc9\xe6\x9b\xb5\xebHtVO\x836L\x82~\x9c\x0c\x86\xaf.\x99\xe5$Z\n\xe9\xcf\xbe\x1av\x8f\x18\xeb@\x1a\xae\x81s\x11\xd2*\xcav\x9e\x80\xa2\xe4Z\x88\x08\x87\x06\x8aL\xc1N\x9b\xcf\xa3\xf39\xb9\xd8,_\xbd0\xae\x00\x8e\x0d\x99\x9d\x16L\x7f\xb8y\xf5B\xc4\x9c\x17EcB\xdb\xfd\xc4\xb6\x14\x12\xcd\xf9z\x00y\x1a\xb0!|B\x8e\x9f\x08\xce\xeb\x1d\xdf\xbcC\xc8\xd3\x15i{\xb8\"\x8f.7\xfc\x18\xc4T*\x124\x12\x0b\xa6\xf5\xb4t\xaf0\x8f\xae#\xe8\xf0\xb1\x83\x839q\xf3)n\x1at\x1d\x84\x03\x18\xc4\x19\xe9\xd4=g\xb9]\xbbw\x87\x01\x12\x0e\xb6\xefpT\xecO\x89\xf2n\xa3{'\x19$\xb7\xe19@G\x1e\xcfk$Gi\xff\x15Y&UMJ\xc2\xe8U\xdc\xe5@\xaa\xd5\x9b<;\xad\xe3l\x1e\x97\xf3\xbf\xc5e\x96dK$\xbe\x0e\\\xb0\xf1FB\xa4>,I(\xf2\xc2N\xaat\xd8\xecH\xa2N2\x94;\xb5/\xc6\x86\xda?\xc5\xa7\xdb\x1b\x010G\x97\xeeu\xbf\xde\x9e\x969\x1b\xba\xe9{\xa09gH\x14\xcf\xe7'T\x80\xfc\x91{+2'\xa8\xeeSn\x1e\xb6\xb3\xaf\xb5\xadn\x1a]\xe7Wc\xd2\x8a\x08\xff{C_c1\x90\xc5\x9b\x881\xa4'6\xc9'\xd3<\xf0=\x8a\x00\xbb\x0c4w<\x959\xd1w\xb3\xcd,L~\xb5\xfd\xed?\x8b\x8bzS:\x06\xee\x80\xedW~\xef\xae\xc15\xb0\xf2\x9a\x8bKQ\x06`f\x1f]\xa9\xff\xd8\x05\xcc%\xe7\xa0^\x88$\xba\xeaL\x8d\xe6\xdf\xad\x84kwA\x0d\x1e\x1f\xe8\xc2\xf8\xd1\xe7\xfaP\x11\x87\x8f\xba\x99\x00\xb8[\xddw\x07A\xbb\xfd\x8d.M/\xf3aM\xf2\xecy\\\xc4\x17I\x9a\xd4\x89=u\xc2\xd5\x97&\xa0\x80\x8e\x14\xe6\xb7SQ\xdc\xbb\xc7\xb2Ox<\x8d\x00^\x1b}\xfe\xdcKI\xc1\x9e\x95\x1b\"*\xceXL\xff\x93yR\xc7\x17]\xa7`\x93\x03o\x92g\xaf\xb2E^\xb2(\xf4\x16\x0c\x17\x1a\xb6x`Jz4\xc5\x18\xfb\x04\xdd>\x8c)\xbe+1\xa0\xf7\xccc\x1c\x03\x1cj\x97\xc8G\xb7\x91M\xa4\xce\xc2'Zy\x1el'nI\xaa:/\x89l\xc7i\xf9\xd9\x05[lJ\xda\xc3tZ\xca\x9c\x0d\x13\xc6j\xedi\xeb\x14\xed;G\x9c\xe9\xc7\xab\xb52\x84\xdc7\xe5l`\xa1\xe30!\x90\x19z%\xd6\xd8D\x95\n\xbe2\x84*\x08!\xf1\xcb\xe1\xd0E*\xcc\x9d`\xa5\xd7\x1azr\xda\x18l\x1e\x13Q\x90\x007\x96\x1e\x83*\x16\x93^\x81\x17~\xa8\x87,\xc9\xe6\xad\xaa'\xd9\xbc\x8f\x15\xfd\x81I\xebP ^\xd9B\x7f\xb3\xab\xbb\xd6\xb4\xf1m\x12a\xbf\x1f\xee'\x87\xb8`\xf2\xf5\xcc\xb8\x8eD\x08*\x01\xf7\xb4\x12\x18b>)8\x10\xefg\x11=1\x10\x80\xbe7[\xc5e<\xabI\xe9\x85p\x9f\xa7\xf9\xe2\n\xee\x01\xb1\x04A\xcc\x1b\xa2\xcc\xe3`3\xdaV4Y\xfa\xb9\xddR-\xd2]\xbd\xc5\x98\xf7\xd5\xb0*\xe1\xf3\xe7a\x941\x98\xb8\xe3\x04F\xaa\xef+\x03\xf2[n\xd0\xea\xa82\xe3*3\xbb$\x99&\xd6\x15E\xc5V\xaa\x7f\x91\xb6\x9b2w\x86\x1d\xd4\xdd \xb4v\xd8\xd9\x0bp\x04\xaf\xe3z\x15\xad\x93\xccG\xa7\xad\xd6b\xfd\xc6\xfb\x02\x1dt\xf86\xf8@>\xd5\x83[!\x89fy\x9a\xc6EE|d\xe1\x12\x13bg\xf2e\x0fYs\xb8\xcf_\xb3Y\xe9\x12\xcf\x8aH[\x95\x82\x93CQ\x94\xf4<\x12\xcb/\xb8\x15\x8f\xe4\x96\xe2\xa6\x830>\x01\xee\x8d\xd9q\\\x11\x02\xa2XO8n\xfe\x14\xdcy\xd0\x84\xe2\xeb+B\xf5\xea\xa5\x86\xf7\x9e\xd5\xc9\x15Q\xf2\x08\x91\xe8\"\x9fwRH \x81z(\xbc\x8f\xee\xbb\xdf\xb5\xff\xda\n\x9cW6\xef\xdb\xc7z\x86\xb3\x17f:\xd6\xfb\xea\xb2(\x0e\xfb\xdfv\x1b\xafZ.^}\x0f\xaf\x94\xf5\xf2\xb0+\x15\xcf\xf8\xf3n?\xcc8\xfe\xf0\xdb\xee\xf3\x82\xcf\xad\x1bub\xce\xfa\x17\xe1\xb0\x1f>\xea\x0e`\xc5:z\xdcy|\x85\x8f\x0f\x0e\xba\xe3Z\x8364\xdb\x92u\xdf\xcb\xdfu\xc3\xb9\xf6n3\x17\xaa\x03\xdb\xfe\xc3'\xddQ\x9d\xf3\xee\xbb\xd3\xb9n\x1c\xdb\x92~\x00\xe4N\xe5\x13\x8cQ\xa6\x8b\x1f\xdc\xaa\xf6 \x8e\xba\x9e\xd2\xa7p\x04O\xda\x8f\x9e\xd3Z\x9dj\x97\xc68\xde\xcf\x8c&h\xcc4L&\xcf\xa2\xbb\xf6\x14\x1fu\x93qMZ)\xc8\xba\xac\xae\xce:\xec\xad\xb9Sz\xb6\xca\xa0\x80\x8c\x84\xabO\xfck\x96\x8ew\xd8\xfa\xec\x9d\xd8n!\xf2\xa4\xdd\xbe\x90\x96\xb7\xa9\x06%O\x8b\xa8\x9f5\xdbtv\xc6\xe6\xe8=\xec.\xd1\x14\xf2\x03\x8e\xc0C/~\x16\x8ck\xc2L\x155w$1\x1cC\x0c\x13\x88\xbb\xf6x1\x9a\xe2\x05\xa1T\x95\xd5\xc9\x9a\xf4\xaet{\x13\xa6\xfb~\xd5\x89\xf3@\xc1\x94\x85<6\x01w\xa9D\x07\x98n\xf8\xa8DU\xcd\xd1\xfe\xe8Q\x95`\xc8\x81s\x16\xbdC1\xa0\x88\xcek\x0eD\x1e\x0e\x89e\x87\xffQ\x8d\x88\xf0*\xabsLa\xbd\xc1\x85\"\xb8P\xd9\xb0\xb5\xe4\x07eUuKJ\xc9\xe3:B\xe0\xbe'\xb3<\x9b%)\xf9P\xc6Y\x153\xfeuI\xeawy\x9e\x92\xb9\xbf\x83\xcc\xc1,\xdaT\xe49\x9e\xe6|\x01;\xb3\xce\xa3\x82\x94T\x02\xf5\xdf \xb1\x11\xe4|\x10\xe1`\x7f%I \xe5)\xf2\xe1i\xbd6\xe9\x8d\xf0*d/\x84U\xb4\xc94\xeb\x86\xd6D\x9d\xed)\xf8\xec\x9e\xf4\x15<\x85\xbaI\xfb\xf74\x80\x9a\xab\x81\xf0\xb7\xaf\xbc\x1b\x1e\xec+\xb3\xa5\xf0\xb3\xf1\x96\xc2U\xa4\xcbj\xae\xf3Q\x13f%t\xe9>\x7f\x86\x9d,:_\xe5\x15\xbf\xdb\x18cC\xfc\xb3\x91\xf4\xec\xf8;\xdc\xdeU\x02u\x07\xfd\xde$\x1f)\x9f\x9dj\x9e=\x1f\x06\xdc\x1b3\xe0\x1c$U\x0e^=\x9b\xce.\x88\xef\xdd\x1b\x0fN\xdc\x06mX\xf20{\xfd\x9bW\x93e-\xbb\xf6\xc2\x16\x9e\xe7Y\x1d'\x19)_e\x8b\xbcO\x05z\x07\x83\xf8\x8bN\xf1}\xffl{a\xb3\x88\xc7\x08R%^\xbe\xc2\x11\xbc\xefZ\xa95\xc3}\xa1\xf8(%U;\x88\n\x0f\xe7\xf9\xa2\x15\xd9\x06\xe3\x11\x0d\xf4.\xe6N\x07\xa0\x10\xfdfn\xb4A\xde\xd3\x87\x1e1T#\x82\xd2\xb9\xff\xd8\x93\x8c;\xdfL\xe0E\x87\xeb\x10A\x11\xaa\x1fn\x18\x01B(L\xe0\xb2\xc3\xd4a\xa2\xd4\xd7y\x96\xd4\xb9K\xc4\xc7\xae\x84\xd1\x112\xcf\xd9\xbd8\xedl\xc0\xd2U\x7f\xe8B\x03\xb6\x1f\xa3\xd6\xb8\xfc2\xb4\xab\xaf\xaf\"\x92\xfdcC6\x82T\x8b\x00\x19\x92x\x86L\x08\x95\xf5\x9e\xc7iz\x11\xcf.\xd5\x8a\xb9F~\xa2\x87\xd8\xe0\x9c\x196\xbc!\xd7\xd6ik\xe7\xfc3\xcf\x19R\xfa\xde\xe1w^\x10\xc2&\"Y\xb5)\x89\x92\x14\x97\x03\x02\x93J\xf77\xab\x10=1\xde<\xc6\x13\xee\xd6XG\x17T`!sf\x0dQ\xf9\x1f\xd0\xacY\x8cJ\xdf$\x0b\x8c+1\x89o$#\xad\xb8\x9c\xc6g\xf4\x8bp8\n\x07\x83\xd6\xe9\xe6\xa2. \x9e\xf2\x92(8C\xacc\xc6\x82\\`\x11\xadbT\xaerH>\xa6\x90\xfcQ0\x1f\xba\xee\xd4N\x1c\xd6\xf7\x8bF|\x15]\xc5i\x82&#\x1c\xeb\xfc<\xe4|\xde\x8b\xb7\xaf9A\x11\x96\xec\xad0C\x0dr<\xf1B\x93\xad\x8c\x07\x94\xaa\x93\x18\x83\xa3\x15qU%\xd9\x12b`\x95!M. \xfca\x9e\\\xfd!\xc4\x97\x80\xfdr=\x85\xe8\x07\xdf\x07\x90\x97\xf0\xfd<\xb9\x82\x07\x7f\x8a\xd0-DL\xd0\xb1\xc7YJ\xdb\xc7\x0e_\xe6\xf9@w/\xf3\x9cu\xf62\xcfEg\x99\x1a\x03Z\x89U\xc6\xf9f\xec\xf5\xc3*\xa9`\x1d\xdf\xc0\x05\x81Y\xbc\xa9\x98W\xcd&K\xf0\x02!\xc9\xb38Mo \xcd\xe39\x1dP}\x9dC\x92\xcdIA\xe1\x9b\xd50\xcb\x8b\x84Tt\xc8lL\xdc\x07\xc7\xb0\xa5\x98\x9fX\xdc\x19\xf9\x0b\xd3m\x1bR\xf8 h\xe2\x9ci:\xb0\x9a\x9fRq\xbb\xe0n\xa7\x06\x05\x122H\xe7E\x99\xcfHU!o\xc6\xc3\x99\xfaUt>c\x7f\x1a\x15B\xf4\xeb\xa5~\xe2T\x92\x7f\xe3\xeb\xf2d`\x12\x8c\xa1QSa?\x1d\x12{\x0cSY\x80\x7f\xee\xcf\xd8\x15\x80Y\x07L{X\xb0\x1e\xfaB\x05\xe5\xde7\x17i2\x93\xf1\xbb-\x96)sa,k=[\xd4\x9237\xf3\x85\xf9\"\x14@\xab\xa1\x17E\x9eq\xba\xc3\xd2O1\xac@\x82\xa4d\x1e\x84\xb0\xd0\xb6\xa3\xbfk\xfd\xb1'\x07<\xc3\xd8xvS\x0e\xe0\xc0]!\x1f\x99\x19\x00\xb7\xa6\x12\"r\x84;o}\x93\x82\xfd\x06\x8e\xe0\x95\xb1\x89\x0b*\x82a\x13)\xfe\xab C\x00\\9\"\x89w\xf7d\xa5\"a\x16\xc2E\x08I\xe0\x88\x08\xc6C\x8b\x1bK\xe3\x92^\x07!\\\xdb\x8f.\xb7\xfb\xfcf\x95\x07N Ud\x1c\xce\x08\xa2_X\xdb%\xd6\xcf\xcd\x81\xf8p\xcfD\xe6j\xdc\xed:\"\x83\x8e\x0c\xc6T\xb5\xaf\xd0n{_Q\x96\x7f\xe0\x01\x020\xd4D\xa3\x9191\xd0/!V\xed; '\xaf\xcb\xddc/\xa7u\x8f/9\x0b\xfb\\\xcek\xa1;@\xeb\x98\x9e\xb7n\xeb\xa7F\xf7\xa0;\xde\x93\x10b\x1dD(\xac\x14N\x8e\xb9\xa5\x0d\x86c\xdd\xe0^\x1b\n\xee3\x8ffq\xf6\x9el*\x9e\x19\x8a\x8eb\xd3\xc92C\xc5\x0b2\x8bg+\xc2v:\xad\xa1oQP\xf6M[_6\x8f\x9e\xff\xf9\xe4\xf9\xff:\xfd\xe95\xaa\x16\x99\xf6Q\xdf\xc2\xa6\x97\x93c\xc4\xc7\xe2t\xd8D\xf9\xa6&\xe5\x9f?\xbc\xfe\xd1\xd4Ke\x1b_\x08\xdd\xa8\xbc\xa2\x88\x13b \xb5Q\xe1\xe2Y\xaf\x16\xe9\xba\x90\xa9\x97O\xe2\xce)\x94\x9e\x94A\xa8\xfaWf\xcc\xb1r\xb0e\x10\x8c\x80H\xf5\\\x06\x9c\xe1\x91\xbf\xe5j\x1b\x1c\xec\x85P\xc0.\x1c\xec\xa1S\xf4\xc7\x0c\xfc\x8a\x94W\xa4d\xd5g\xe6\xea\xfa\x99\xe9tWtg\x1dx!h\xaee\xfb4\x03\xb5K\x86F\x0e\x19\xaf\xdd\xd3\xef\x19P\x81\x07\x98r\xd5\x90\xe9'\x94GIV\x91\xb2\xfeP\x12\xc2\x1c\x1b}F\x9d\xe81`\xe4\xd3.X\n\x80P\xb3\xd3kE\xab>\xf2:\xefG|\xfa\x85\xf7O\x87\x8f\xbe\x0d\xf4\xcd\x9b\x8f\xa5\xc6\x0fH\x03$TM*\x1a\xe37|\xed\x98\x95@\xd9DS}\x1a\xa01\x8fN\xb9l\xd0A\xb1\x060\x00\xeb\xb1\xf6;\x98\xc8Z,\xe4+\xcf\xeb\xd7\xb3\xf8\xfb\x82\xab\xbb::?'\xd5\xeb|\xbeI\x89F\xcd\xc3C\xb2f~\xf7\xea\x0d\xc3\xe7b\xbc|4\x7f)\xd5f\x8e\xa1\xd4Z\xd8\xcd\x859\\\xdb\xb4\xeeV\x1d\x0d\xaf\x83r>\xff;\xaaVqA:f\xd3t\xe7\xce\xca\xe4\x82L\x94\x8at\xfa\xa8\xc2\xfa\xc7&)\xc9\xbc=\xe2yR\x15\xf4,v\xfe\x80\xf9\x94\xd5C=4+\x10\xdc\xe1\x12\x84-8\x98\x11W\x7f\x0b\xcd\xaf<\xc0\x14\x16I\\\x89\x90\xb2\xccK\xf5\x8e\x04\x1f\xf4\xb8.\xfd\xddt\xbd*\xf3k\x8c\x80t\xc2\xbfj/\xa9\xde\xbc\xdb O\x95\xcb\xe4\xc7\xdd\x1bJ~\x9b\xdc\xb3S\x14\xa9\xae\xba7\xa41\xaf\xdf\xc5\xde\x0d\x7f\xdem\xbf\xe2\xcf\xbb\x17\xc0\xfc\"\xb9\x97^\x80_$\xf7\xd2\x0b,\xf8\xf3\xee\xc5/\xbbH>x\xa2\xbbH\xce\xfc\xc3\xc7\xddy\xb1\xfb\xe3\xfd\xc3n\xfbW\xbc\xfd\xee\xb5\xfa\x9a_\xabw\xdbY\xf2\xe7\xddy\xb1\x1b\xe4\xde=\xf4\x05\x07\x7fw\xba\xe7\xbc\x99\xeep\xae\xf9\xf05W\xc4\xb4zw\x94\x9f\xf0y\xef\xda\xfa\xb4\xafN\x7f\x0eG\xddh\xda\x97p\x04\x0f\xdb\x8f\x9eQN@\x04\x00|V.\xf1\x12\xa9:\xebD\x18|\xab\xd6\x12\xa1\xeb\xba\x95\xde\xa9\x950\xf4n\\\xe7\xa5\xa9\xf6\x07\xb5\xb6\x88<\xd8\xae\xf2\x9a\xdfb\xcb\xdf\xd3gg\x94g\x9b*\x03.\xe3\x9b3O\xf7\xf4\x87\xcdbA\xca\xde\xbb\x17q\x1d\xff5!\xd7\xbd\x17<\xc7\x87\xee\x03\xd2{\xf82\xcd\xe3\xfa\xf0@\xdf=\xbe|\xf4P\xff\xf2UV?6\xbe\xd9\x7fd|e\xea\xecu\\\xf4\x9e1\x17\x14\xf1\xf8C\xe7-\x8b \xd8\xfb\xe8\x94\xd4\xfdg\xc8\xdf\xf5\x1f\xdf\xac/\xf2\xb4\xf7\xf8\xa7\xc487|\xf5<\x8d\xd7\x05\x99\x9bk\x98\xa6O\xdf\xb5\xe6O\xc9\xbc\xf2\x1e\xc9\xa8\xf8\xeam\xe7\xe3\xbf\x91\xf8R\x02ig?\xd4262,\xef\xab\x10~\x0e\xe1M\x08\xefu\xb7w/B\xbc\xbb\xc9\xe0\x1e\x9c\xf6\x99\xeb\x9f\xf8\xab\xe7\xfdW\xff\xe0\xaf.\xdb\xe7\x03ei_\xe1%\xee\x0b*\xb5\xc31\xbc\xa2\xe3\x90#\x98\xd0\xdfA\x10\xaa\xda\xd3\x17R\x84x\xd1ol\xe7Z\xcd[\xdaa\x9e\xe8\x0c^\xe2\xbdBWJ\xa5\x9f\xbe4\x89\xc1thW~M%\xee\x1fe\xd3\x18\xd5\xf7E\xf7\xe02\xc4\xbf\xa5\x1d\xff\x13\x8e`E[\xe9\xbd\xa5\xe5\x078\xa25\x8e\xe0-\x15\xb8\xf1\xafwz\x05\xc6\x85:\xc1\x8a\x8e\xe2G\x83\xaa\x03[\xf9 \xdb{F\xff\xfa\x01\xb5ToLr\x81\x98\xeeO\xac\xee1\xfcr\x0b\x13Xv'\xff\x13\x1c\xc3\x82v\xbd\xf1_0\x1d\xe7\x04f\xf4w\xcc\x7f\xf7\x1a7\x82F\xf4\xba\xf3z\xfa\xcf3\xd9\xc1\x1b\xee/\xfb\x8bA\xefH\xc7\xb8\xa6\x1d\xfe\x93N\xbf\xdf\xdb\xef\xcc\xbf\xde\xa3\x0d\xde{`!\x18\xcb\xa0\x8f\"\x7f\x85#x\x8f\x9aj\x1d\x9a\xfcU\x0e\xf2\xaf\xfd\x97\xef16#bF\x88~\xed\x0d*\xca\x08`\x92}\xe9\xd9t\x00\xde\xdcbXC\xbf\x14\xbb\xb1D&\xe7}\xd7\x12<\x08u\xe8\x7fn\xeb\xd2p\x9f\xf3\x02\xc7\x9d\x87\xa0t\x9c\xbbvLa\xf6g8\x82\x7f\xc01b\xc6\x1c&P\xc0\x04\xff\xbe$7\xd5\xab\x0c\x03\xe2\xf6:\xfd\x1b\x1c\xc1K8\x16{{\x02\x7f\xee\x01\\h5\xfd\xbf\xd1U\xab\x15\xde\xcf4\x93\xbf!5)1\xc6\x13z\xe8\x9e\xa1%\xfd\x0b\x9c\x8f\xdb\xec\xe4\x93\x91\x1c\xe7\xc1\x93.\x87$8N}\"\xaa\xef\x1e\x8f\x9669<\x12\xe6u\x81W~;\x18Z\xbc\x95\xeb`\xe4\xb8\xf7\x1f\x1b\x92\xc2\x1ety2\xce)?\xd6g\x85=x\xd2}\xbei\xc2\xf62\x0f[\x11A\x97\x1d\xa0\x15%#\x83\n\xdfV\x94\x8d\xe9\x19\x8b\xb2\x81\xce[\x14\x04<\xcc\xc6\xb0{{{}a\x02\xb1\x1e\xe8N\x06\xc1\xeab\xeb\x81v\xd8cX\xb9{\xd4\xf6\xab\x8d\xcb\x9c\xb4\xaeuG\xae\xf0\xe3\xc7z\xcc<\xec\xc9H|\xb0\x8f\x0f\xb7\x1dl\xe2+\xa9\xa0\x99\xc9\x18&\xec\xf7\xbe`\xf0]4\xcc\xa5\xde2\xfed\x1b\xa6\xfeF\xa3Q\xa3@\xaeZi\xd7\xa8L\xe1Z\xc6\xfb\xb0\x0f\x13\xc0\xe0\xfd}\xe2e\xbdc\x93\xa8KA\x1a\x0b\xb9\x82\xc5\xfd\xbc\xbf\xcf\xaebs?i:c\x1d\xa1\x14\xc9\x82\xf7o\x82\xa7\xb0\xbb\x1b\xc3\xf7\xb0y\x1a@\xc5\xcd\x11\xa65\xecB|\xa6?\x17Y\xe3\xfawr@\xa9\xec\x816\xb5/{\xa9\x9f\x06\x90\x8a^L=\x08\xf6\x87\x05\x0c\xcd\xfc\nS\x8a\x11\x96S3\x04\x9d\xdeo\xfb\x85\xefn%a\x0f\xbe\x1f\xf8\xa5\x01A\xbf\xc0\xf7\x91S*\xa6\x15i\x12\xab\x87\xe05*\x16\xaf{Y\xce\xb3\xd3*w1\xb7\x81A\x05c@B\x0d\xd5\xcbzZ\xae\xa6\xf5\xa7=H\x99\xf7$\xea\xe2\xd9\x0dV3\x05\xc9\x1f\x90\xfe1^w\x04N\xd1\x884M\xe9/\xafr\x9b\xc0\xbc^,q\xdayTs\\\x11\xb4\xdedQ}\xc94;3\xd8\xdb)\xb0\xa4k\xd9\x80\xc2\xcf\xfc\xfd'\x07\xc1\x17h\xcf\xbe\xf6\x92\x1bM \xf54\x03\xc3\x88\x18\xbd\xa4\x92l\x91k3\x87\xd1\x92\xe6Km\xee0\xc0\x94\xb5e6\x81C\xfdKT\xdcM\xe0a\xef\xa5\xc659\xb3\x1ao\x82\xb2nSrF\xb9\xb6\xfb\x9a\xfb\xd0~\xd3\xccOs\x96g\x8bdYEi\xbeDs\xc0~=F\x02J5\xdb\x00\xa8f\xa7\x89\x8d\x91`\x97Z\x92 \xcb[\xafDR\xc5\x12\xfe\x04\xfb\xa8\x87f'\x00\xa5\xca\x94\xb0\xee?\x05J&\xcb\xa7\x10\xef\xee\x06\x94F\xd2\ngjkZ\xb2\x89\xa0\xfa\xd3\x91\x12\x92\x95+M\x83)9\x8b\xe2\xa2H\x11\xe5\x06\x0d\xda\xc5\xe9\x1a\xd1\xb5D\xfd6&)f\x17\xee\x1e}\x88\xf7\xb3\\/\xdb}\x8fOY\x05\x8aD\xbd\xf7\xf4!{\x8d\x18\xd8{\x8fO=\xad[>^Vc\x0e\xa8\xca\xe4\x17\x8f\xa8\x99\xf4\x91\xc00]\xa7S\xc2\x9a\x07\x8e21]M\xe3\xd7\xb9vpc\x8f\xc4\xc6\x978\xae\xa5u\xfa\xb3\xc0\xc0`\x90\xce}\xc4:\xbe$\x7f\xae\xeb\xc2\xa7\xc4\x97\xbc\xa4\xaf)Y*\xf2\xaa\xc6\x1f\x06\xd5\xc3\xc5&I\xe7\xef\xc9?6\xa4\xaa\xd5\xe6\xd4\xe7\x06\xd2\xc1r{\xab\x1f\xf1G\xfa\xfa%\xa9\xf2\xf4\xaaU\x9f?\x1a\xac\xcfMM4\x9f\xf17\xfa\xaf+R&q\x9a\xfc\x93\xbc'\x95\xfa\xad\xfa\\\xffe^\xbc\x9a\xab_\xacHZ\x90\xb2\x8a\xe8\xf3\xbbEc7\xdc\x91\xc4\xad\xd6\xeb\x0c\xf0\x84\x9e\x96\x8d\xfa\x84\xfe\x10-\xf7\xe9\xd1\x15w\x1d\xa1\xb5\x8cGQ2\x81\xd2p\xd2\x98\xa3\xe3\xf2.'\xba\xa8<\x1aM\x8e\xe0C\xe8h\x91+\xc8\xc5\xa0Q>W~\xa1\x97N\x94r\xcd\xa7|a\x00=\xf0If\x1anF2\x15k\xceNDx\x0d\x83\xe7wGp\xd0\xb9\xdd\x00^\xb9\xe5\x9c\x7f\xf9\xfc\xd9\xc0A\xb0\xaf\xf5\x90e\xfb\x7fS\xc6\x17)\x19\x00e\xb6Y\x13Q\xc7\xc0\x10,I\x8f.\x01h\x82\x10C\x1d\xd9On\x01\xb0\x1e\xbf\xa8\n\xe9\x96#\x9f\x88-\xd3\x1f\x138Dl\x11\xad\x8c\xc0\x9d:\x9a\xfbY\x08^\xcc\xfd\x8a\xb3\xfe\xd4s\x17\xfb\x18\xde\x9c+\xef\xdaO\xbdRG\x05KL\x05\xb5_Gt?\x1f\x1c*\"\xaf?\x1d\x1c\x82J\x072\xff\xe1\x81\xf2e8<\xf8\xce\x97\xdfn\xfbek\xb4\xe3\xbe\xdc\xba\xcf\xc3\xc3\xc7\xe6O5R{\xfb\xd0o\xbd\x92$\xb2\xd4c\xb7@-\x0dr\x13c@\x1fy\xf6\xdb\x93T\xea\x07\x93\x1b\xf1M\xec\xb6.\x1f\n\x7f\x82\x83\x8e\xb5x\xc3\\\x1e\x9c\xc1q\xfb\xe7\xc4\x98\n\x8d\xb29\xbe\xa6\xf5Cc\xeb\x87\xed\xd6\x0f\xcfP\xff\x1eDW\x07o\x0bRbL\x9aWh^\x12\xd7 \xc6/\xb9y\x9d\xcf5\x1e\x9f*\xa8[\xa9\xddTE\x0b&kP,\x10&\xe8\xf87\x13\xf4#\xf0I\x10\xb0(Qy\xd39s\x84U\xd2r}\xac0\xc7\x96\x174\x86a\xab\xf6'\x01L \xe1W[\xfaE\x1e\x9e\x9e\x9e\xbej\xfd\xc5\xcc\x02\xc9@8K\xdd\x12\x8dC\x00\xfb\x12\x99\xc8\xad\xc0A\xbfnG\x84\x80]\xf0\xce1}P+QZ\xb5\xf3\xff\xfd\xfe\x9b\xff\xf1\xf7{\x7f\xf4\x83\xf3\xdd\xa3\xe9/\x1f\xcfn\x9fN\xbe\xff\xd3\xe7\xe8\xe3\x83\xe3\xf0\xe3\xc7?x\xde}\x96<\xed\\g\x99\x0b\x0df\xb0\\\xe8\xcc\xf3\xb0\xb1\xa1\xdbo\xfa\xad\x95~}\xff<\xf8\xe5 \xbc\x0dD\xd3J\xe6\x12\xff<\xf8\xa3@\x80\xe6\x83\xe9\xf9Y\xf0\xc7o\xf8s\xcb\xc6UF\x851X\xe7~M\x87\xd1\x0f\xa4nX\xdc\xd8v\xa0\xf0\x06\xbd\xfb\xfdtL\xa667\xb66+N\x1fw\xf6\x90\x03q\xc6\xc4\xcaDWA\xdc\xc1\xb1\xe0Vb\xcf\xeel\xb3g?\x7f\x86\x1d\x12\x15q\xbd\xaa\xfa\x8du\xaa\xb3jC\xb1-@Qs\xf1\xea\xfd\nR\xb6\xcf!\xc9\xa0\xd4\x9b\xa8*\xeaXZi\x9a\x1b\xa2\xcc\x03\x87\x85\xf7\xee\xd9\xfbg\xafO>\x9c\xbc?e\x83O\xa2:\xff\xa9(laSD\xb9\xe2\x0eg\xb4\xa7ibP\xa6\x8aB;\x8c\x07\xe9el\x83}\x1cX\x87\x04\xd0\x18j\xdbk\x8aR\x15df\x8c\x13\xa6+t\x95XX\xd1\xdc\xfd\xa35\xa9W9\n]-(\xbb7 i\xfed \x9c\xa8Z4:(]\xc1\x0c4\xbe\xc9\x06]-(\x85\xa1W\xb2D\xe8\xcd\xe0Gz\xa7\x97\xfe\x9b\xf6\xaf\xadT\x96\xa0U[b\xe3\x9a\x0bp*g\x95~\xe6\xef?\xee\x06\xff\x00n\xb6\x86o\xbby(\xea(\xa9\xde>;=t\x125\x98.$/H\x16\x17\x89\x91\x89\xe0Y\x15(\xae\x17\x0d\xae\xd3\xc9\x1ez\x1a\x16<\xa9N\xaf\xe3\xe5\x92\x94\x07#\xc6P\xb1O\xb6\x18\xc3\x81n\x0cy\xf1j\xce\x12\xf0\xd7Q2\x7fY\xe6\xebwq\xbdz\x8d\xf8\xcd\xdcI\xeb(%\xcbxv\xf3\xaa\xff6\xa6o\x97\xa4\x96\xc7\xf9\xfb\xf8z\x84\xf8\xc2\xd9[F}\x8f\xd9Ib\xd7\xd7J\xc9/\x12[\xd7\xbc5\x18!f\xbb\xd5\\+\x11\x8b\xcb&\xa1\xdf;x\xe2$\x83'Nb\xa3z\x89\x12\x19i\xc7p\xef%H^\xa2\xf2\x85\x83\x0c\xca4\xf7\x13\x19\xf0\"\xf6\xf9\x1f\x9b\xb3\xa8\xca\xd7\xc4\xb7\x03\x14\xba+\xc2\xee\x16\xb5uu\x91\xd7\x0c\xd9\x10\xd0>>\x9bK\xdc\x80#\xd8\xd0\x87$\x9e\xad\xd4\x87\x15\x8b\x93Q\xaeQ\xcb\xc5w\xc4\x98\x0dQ\x90\x99~mY\x005D/\xb3\xd4\xa1\xb3\xd9\xc1\xb5F\x96\xaf\x8e\xbe\xf9F\x8emn\xba\x8b\x82\xde\x89m\x0c2+\x0e\xda\xccx\xca\"\x9f\xbd\x17\xc2\xa2uZ\x0e\xac\x9d\xc0\x18\xcc\x92\x15\xafIMJ\x0d\xdb!\x8a\x1cgE\xc7\x19\x07\xb0\xe3\xb0\xe7D\x91r\xe0\x948\xf0\x08;\x9did\x0d\xf6{\xb3<\xab\x93lC4\xa9a\xd4r\xc5]qs\x9f9\x7f\x99\x9cqE\xa1\xddj\x83\x02uK9\xad\xa8tB\xffc\x91\xca3\x8a\xc6\xf8\xf4\x08\xa6\x99ev\xc0\x87\x86\x87\xcb\xb4r\xa8M\x076k\x84\xa6\xfd\x00f}{'\x13\xbd\xd4\x15\x12\x9d\x9f\xe7e\xb2L\xb28U\xc4)\xe6\x96\xa1}\x83\x12\x8cBT\xc2\xf6O\x96\xb7\x9f%L\xe7W\xed\xd6\x81\xe8\\\xab\xbbE\x86\x00Td\xc4\xac-\xf4\xba\xcd\x98\x02\xbc\x80#\x98M\xf7\x1c\x00NKa\x84\x91\xe9\x0d\x15P\xda0*:0\xaa\xac=\x9b\x19%\xfb[\xe4\xe5\x9bm\xcc\xce\x18\xeb\xb6\x04\x0e\x9d\xb9%U\x84ZV\x06\xda\xd7-\x92^\\QzQ\x07\xe0\x15e>\xdf\xcc\x08\x1f\xdc\x15\n\x02\xb3<\xab6\xeb\xf6\xb3\x8a\xcc6eR\xdf\x88g\x9f?\x83\xbf\x9a^\x9d\xa1\xb1\xdb\xd5Y\x08s\xb6\xf3V\xba\x0ca\xddB\x01\xb3A\xc6f\xa5\x909v\xa64\xed\xd0\xbf\xb97\xa0\x03\xc8\x80\x83m\xcd\x14\xf5N\xf5\x81{\x18\x98\x14\xe1\xbar\x03G\\Ab\x9f'X3pt\x8b\\\xa0\x8b\x10\x9d\x16(\xd1M\x1b\xa2;\x0f\x9e\xc2\x8eO\xa7\xe8_\xc0\x11\x9cG\x19\xf9T\xfbA\x10\xcd\xf3\x8c\x04O\xf9\xe4]\xc1%\n\xed\x8f\xb2z\x17,\x00\xa8\xdb\xbcD\x91#>\xa1(um'3\xdd\xc2n\x90N\xce\xc6\x8eZ\x94\xde.\xa3\x0c\xcf\xc9\xb6\xad\x01\x87\xc7\xa7\x91h\xa4+\xa7#QKW\x9e\x8fD7]\x19\x87\x82\xba\"\x17\xf92D\xa7\x95\x0eZ^\xd3\xe5\xa3\x98I\xa1\xe6_\xc2\x11<\xebb\xe6'\x8e\x99;\xf6\xab\x981\xe5\x8a\x87\"\xbf\xdc\x06uu\x85bb\x87\xd7v>\xc5mE\xde\x1be\x1e\x81\xb7\x19*p\xc4\\\n\xc4\xbcq\xfe\xd4q\x9d\xac\xb5\xb6\x150n\xfdJ\x0f\x1b\x8d\xf9K\xef\x89<\x89T\x85\x08G\x8e\xceMQ_E\xbb\xe0J\xd8\x87\xdf\xe9T\xb4\x85P\xd1\xf6\x82Z\x03\xf7\x17\xb6k(\xf8\xf0\x98\x07\xa4b\x11\xa1\\\x15rs\x08\x8d\x06\xab\xdf\xe9jL\xa7D\xb9w\xfc\xfb\xc7\xeb\xb3\x07\xcb\x84]\xfe\x0d\x80u\x9c\xe9\xc1\xe3'\x036\x16\xffo\x98\x1e\xdc\xcd\xd5s\x9a\xc7\xf3S\xa3\xc2\xb0\x94\x9c3\xd3R\xd0\xe6\x0d\xe9\xdb\xf5\xc9\xc6\xe4\xdb\xcb \x90(\xbf43\xf2\x9b2\xa5U6e\xca\\\xc5\x8c\x15\xab:\xae7\x15\xe6$\xc1\xbfl5Y\x8aPQ\x9b\xfe2\x7f\xb1\"\xf1\x9c\x94\xd5\x04\x12\x9fD\xfc\x87\x81B\xe8\x1b\x89\xe1\x08r\xf1\xe5\xd4\xe3y\x84\xee\xd3\x9d\xe7\x19\xf4\x10\x1b\xccC\xf9\xf93\x9c\xfb\xb1\xd9\x0f\xca\xdf\xa0kKM>\xb1\xf8\xe5\x17i~\xc1\x14X\x17\xe8'\x1e\x88\xcd\x1c\xd5+\x929(\xb9)\xc9\xceY{hH\x97G\xf3\xb8\x8e\xd9\xdf\x9b\xc0r\x00]\xf5\"\x01;(\xea\x84\xa63.\x8a4\x99\xa1\x02\xe9\xc1\xcf\x15\x8bO\xc1\\w\xfer\xfa\xf6MT\xc4eE|LA\xb4l\x8c>\xe3\x05\xf91\x8f\xe7C\x0c\xf4-\x1d\x85\x0e\x84\xa2\xe4\x98\x01\x01\x8e(\x85\xc8\xa3\xfc\xe2g0j\xf5\x9dX\x83\x9c\x8d\xf5\x84\xdbl\xeb\xb9\x01\xfd\xe9\xc3a\x91\xf7\xa9\x83\x9b\xe1B2\x9cT\xaaO\x19\xf6\x8c\x94a\xafM\x19\xf6\x18e\xd0\xe3\xaa\xce\xbf\x04\x94\xa5\x15\xe3SC\x8e\x10\xa1\xd6e\xf6@:\x1d\xaf\xf9r@ \xba9\xcd\xe8@\x85\xbf \x9a\xfaGI\xc5\x1d\xa1\xa6\xd9Y\x00\xc7\xac\xd2\x04\xa6\xf4\xff\xb3\x10\x7f\n\xb9\x8b\xe2\x93\xf0U\xd1@\x1d\xf1\xb7\x1b,s\xc0ld\xe0\xa4\xd0Gfy\x99\xf0#C\xc4\x89\x13\xcfd\x9c\xd1\xa3\xadl\xaeVm\xfb\x0dS\xe0\x17\x12\x15I\xf1\xa5\x06,\xcdM\xe3,Oy\xd6\x9a\x97\x98\xf0\xcc||\x90(N\xd3\xfc\xfad]\xd47\x18;\xd8|||\xd9\xcc\x8fE\xf2\x1dJ\x1f\xf5WX\xdd\x04@es\xfdb\xc8\xc8\x1f\xfb9\xcb\xdfp\xc1\xa2k\xa8 \xcd\xe5\xd7y\xff\xe3+\x91~'\x9b\xe5s\xf2\xd3\xfbW\x86\x80P\xa0p\x92\xa8\xcdM\xb8j\xe8\xa6\x99]\x1eX\x1dma\xd0\xfc\x16l\x81\x19\x95\xcf;\xf7\xe4:\xee0\x08\xcdW\xbe\xb9m\xa9rfd\xd4\xde\xbf8C\x97G\x18\xfe\x1d\x8e!\x8f\xd6q\xe1'A\xf4s\x9ed\xbe\x17zt\xf3z\xebMZ'\x0c}\xd4J0\xe9\xd4\xd7\x03`V]M\xc0\x0b\x0d\x06\x99\x15\xbe\xfd\x1f\x07{\x86\xf75{\xbf\xf7\xc4\xf0\x9en\xbfj\x02\xdeg\xaf\x0fP\xa4^\x94\xe9\xc0\x14\xd0\x9e\xe7\xb4M\xab\xe1{\xe0\xceU#\xda\x02\xce73U'7Dx\x85\xd1\xd64\x1b\xb8>\xa1\x9bvg\xa7\x8c\xaa\xcb\xa48\xa1\x88\x9ed\xcba\xab\x82\x9c\x87\xeb\xefo\x0bc\x88V\xe0l\x95\x1d\x83EQ9\xf6/\xa2)\xc6^ny\xe2\xbf\x9d6\x82v\xa3Q\x88\"6\xf84\xa1\xc7\xcf\xc6\x8f\x8d\xeeJ\xa2pc\x1fC\x1a\xd2\x10\xf2 \xd4\x05v\x0e)Oo$0\xeb\x86\x9dB\xa90Y\xa0\xe1\x91~\x14l\x85\xcc\x0e\x0eI6Of\x14\xa3u\xf1R\xbb9o`\x00\x8f\xd3\xdf\x8e\x95Aq\xc3*\xf9\x08\xee\xd4\xf3\xd0\x9d\\[=\xc7\xd6\xfe\xb1!\xa5!\x8203\xa9Y\xe4\xe5Z\x7f\xd0\x0c\x86fM\xfb\xfb9 \xc6X\xb3@\x83\x04\xb1\x9fL\xc9\x19;)\x07\x10|`3\x168\x15\x83\x8c\xc3d\x12\xf9\xf29\x7f\xf9\x01_\x9a\xed;P\xe8{\x80\xf4\xbb\x88\xcb\xfa\xe3\x03\n\xa9\xfbT\"y\x90D5\xa9j\xbf\xb0\x9a|\xf08j\xa6\xf8\x9d\x80J\x04.\x01d\xe4\x1a\xe6\xa1\x06\xa8=\xf6\xd4*\xd6\xb06\xa3\xb8(H6gAu\x92i}\x86\xf6\xbdC\x00\xd6om\xa6\xf4\x94\xe3\xac\xfc\xc40\x1d\x1ez\x98\xe1T\x7f\x07j\x91L\x1bq\x058\xf8V\x98)\xb2*\xd2\xa4\xf6\xbdco\x00\x01\xae\xa0g\x0b\xbc\n\xa1\x1b\x8aB-K\xba\x9b\xa6{\x03G ^ O\xf7\x07j\\\xa0=\x86\x19\x85nl\xf8q\x8e\xe9\x96\x04 db\xe6\xcd\x00\xb2t\x90#\xd7 \x87\xeb\xa6\xe3\x8bu>%f%6e\xab.ZCl\xa8\xf4\xf9PFmP\xa9u?\x0b\xa7(&\x8c3\"\xc4\xb5-\x9d\x8d(\xf2fSG\xb0C\x96\x0c\x08\xcfG\x12\xb0l\xbf{O!\x83\xef\x81<\x85lw7\x10bYC\xb8\x87\xac\x8d\x04gRG\x8b$\xadI9~1\xccZ\xfb[\xc1O\xde3\xb9@@\xd3LI\x8f\x84c\x0fv\xf1(\xf7\xfal\x1d \xa3p\x11BE\x99^}{L\xe1u\x04K\xd8\x85\xeb\xb0\xd9\xd4x\x928\xecj\xed\x94\xbe\xb2\xc1q\x08uT\xad\xf2M:\x7f\x91_gi\x1e\xcf\x9f\xa1Z\x8deg%\xe9\xc2p\xdd.\xed\xc3\xfc\xcc?\xe8eK\xa4Eh\xc5\xf7\x86\x94\xe2Z\xa3\xe6\xb9\xd0\xa7\xeb^\xae\x1a\x8b\xe7\xfe\xcb+\xf1Rc\x0f\xad\xba\x1a\x0b\x9b`\xf9\xec\xcf\xec\x8c\x136\xc1l\x07Ri\xf8m\xf9\xbf\xe9\xea K\xce5)\x97\xe4U\x86\xcf\xde\x96\xb4\x02\x1cA\x8ao\xb8\xc3\xb7C\xc0\x1bh\xd6Zz\xdf\xd8\x11\xdf,\x11\xb2]Y\x7fq3\xda\xfa\xb2E\xad\xfb\xad(B\xf2\xeeg\x90a \xbaK\xab\x9b\x03\xaa\x8c\xf5,2\x08\x82\xaa\x01\xbf_\xf2\xc8\xe85\xfe\x95\xf9\xa4\x97\xa8[6\xd1F}Z\xf9\xe0;\x8d\xc5\xfdZ\xa0\xb5\x169\x97\x02\xc5\xbe\xd5\xbd\xbd\x11\xdf\xf6Ru\x02?\xf5\xe4\xae\xd2\x83\xa3\xed(op\xda\xe8\x83a\x02\x9a\xf4\xee\xdd\x1d\xc0\x8f\"\xdbI \x88?=2\xaf\x14S+y\x94\xad\xe3\xf2RRj f\xae\nUL,!\x17Kn\xa0\x97\x01\xf6\x8d2\xc0~[\x06\xd8?\x1b\x08C(Ng9\xcc\xeb2.\x1c\x0f\x14\x16\x82\xfdi\x00\xd5u\xc2T\xc5QQ\x92+\xe4\x8d3\xf2\xc9\xca6\xce\xe2\x8a\xc0\xded\xb0\x0e\x08\xd3,\x93\x10[\xdb\x84X\x91\xc2\x1e5\x02\x14\x96u@O\x1c\x0c6\xbf\x92\x04\xac\xf9\xfb\xf3gL.\xa7\xdd6q\x10\xc2N\x1c\x95,\xa4\x04\xa6)\x9b\x91\xa2\xce\x07w\xb9Z\x18`\xe0\x08\xf6\x1d\x0d\xb1.J\x12_Zk\xda\xef\x87\xe5\xb5$\xef\xff\x11\x9d~\x7f\x1e\xda\xfb\x17\xb5\xe0\x9a=r[3\x12\xd5{\xcc\x1c\x9fdu\x08\xf4\xe7h8=\xf9u\xc1\xc4\x87\x1c;\x00\xe1\x89\x1d\x08,\xe3lmYjlm\xdfa\x1f(\xa7_<$|\xc6&\xe13\x1c\x96/y8+\xce\x81\x19\xbb\x90<\x9a\xb1\x1f~\xb8\x88\x08z\x92,\xec\x1f\x86\xca\x0ex\x14\x82\x8f\xf9\x1eJ\x8c\xed\x82\x071\x06y\xa1O\xcbt\xf8\"\x0b$\xe0\x1c\x90Q\xb2\xab*2\x8aa<\xa1{]=@|\x16\xaf\xd4\xadw\x07,\xa0[A\xed\x1a HU\xe4YE\xbe\x84\x82\x1c|\xf7\xebn\x8d.\x0598d$\xa47\x13\xa3\x0eP\x14\x84\xdc\xc1\xa1\x1b\xe4HT\xef\xb7\x89\xc8\xfexP=\xfauA\xc5\xc7l\xc9\x0f\xc3\xc0\xe0\x82\xbe\x8c\x8c\x18\x9c\xc3Da\xcd}goN\x82\xe5\xd0\x01\x83\x10$.\x1d;n\x04I\x0b\x0e\x9e\xe0b\x1e\xb0\xbb\xb4\xb8\x9e\xad\xfc\xfd\xc3\xc0\x10\xafFW\x9ai\x1c\xda\xa7\x01w\xb8\xba\xcc\xc4\x8b\x8e\xdd\x01.\x87\x0eh\xce\x1a\xf4s\xae\x94c\x19%J\xc5Z#\x08\xf8\x8f\xe7\xf9\x1c\xc3\xc5\xf2\x9fL]\xc5L@ \x97{Q\xde\xc6G\xf5A\xa8\xbb\x99S\x0b\x1b\xa5\x03\xda \x19\x8b\xf2\xcb\xd1\xeb\xf3\xd0\x02'Q\xeev}\xf0\x16\xd1\x0d\x9c\x89\x0e\x9c\x89\x04'}\x1cv\x93\xcfw\x0b\x82\xf1\xe1\x81\x1d\x8c\x92\x8c\xc6\x17\xe5\xa6\xa8}\x8f=\xf0\xc2^ \xefna]X\xf0 +y$\x9b{#\x86R\xd5y1`\"\xa9\x07\xf9-K\x93\x871S\xa7\xc6o\xa7\xf4\xcc?x\xa2\xd7\xf9i\x02\x18\xdc\xea\xd4D|\xa0v\x85t\x03\\\x16\x92\x10\x07'%![(\x8d\xdbnVB\xa125*{\x06%B>\x98\x07\xfe\xcfU\x9e}\xfe\xb4N?\xdf\xc4\xeb\xf43\xa6\x00\xfdx\xf1\x80\xf1\\_|\xb9\xd3\x8d\x10\xb2\xad9\xe1\xc3\xfd\xffxk\xc2\x81\xc1\xb4/1I\xa0\x06Q\xfe\x1eCi\xe2\xd5\x97\xf7\x00\x83\xa0\xe0M\xba]F\x16\xe6\x04\x99`\x02\xddkTS\xe3\xb3\x01\x13)#\xa3\x85\xbaR\xba9\xd8\xbc\x9b\x00\xcfti\xce\x95\xa5\x19GZ5S\x991+g\x9d9\xaa#i]\x0c3\x19\xeeW\xa4\xfc\x0b\x85\xf1\xd2\x8d\xcaiL\x85\x9d\xf1\x19i\x94ua6\xca2\x0db\xee0\x08Q\xb9e&\xeb\xd4\xfaJ\xdf:zAY\xf6\xb8\x88\x9b4x!\xe1\xc5\xf3\xb9\xb0\x8a\xff\xfc\x99\xb2#\xeb\xfc\x8a\xb4\x9f0\x06\xc5\x10\x99\xc6\xb8/;\xc6Z\xa6 ^\x0d\x82\x0f\xa7\xff\xf93\xd0\xb9\"$\xd7\x9b:\x16\x90D\xc9\xfb\xc6\xd1\xd4x=\xd8\xcf\x15o\xdfo\xe0AA\xd7\x07\x80|\x8a\xb7\x16\xbag/\x08)\x9a\xe7n8\xb4t\xc0\xa1\xaf\x8e\xc87Fcl\xb3\x87\x06\x1f\xe1\xa9\xbc\xd6Z\x92\x1aM\xaf\x7f\xb8y\x97'\x19\xa5\x08\xfd\x18\xb8\x00.n\x0f\x82\xbcw\xb2\x86\x86\xda\x88\xd1\xbf3\xff\xbas\xa3\x84\xbe\xecz1t\xeb\x7f\xce_\x1ej\x0d\x06\xae\x87\xec\x10N\xc4\xa7\xda\xdb\xdcO\xe26W\xf7\xf2T|\xaa\xb5~x>d\xc3p)>\xd5:\x0c>\x13o\x1f\xf7\x8d\x18\x9a+\xdc>4\xe3\xf9|2,'\x8b2(3\x81\x90\x9b\xe8>\x1d0\x1c\x1c\x92\x9b@\x91\x9d\xb4\x154\x08\xd6o\x89\x93\x85 $\xbaw\x94\x8a\xde\xe9|9a\xb6Ny\xfb !\xf5\xba\xab1S\xba\xe8\x1a'\x8a8\x899\x19\xca\x86\xa3\xe5\xdc\x06\xdd %\xad\xb7!L\x87\xb6\xa3\x89\x9a\x9b\x0e\x1ae=\xdb\x8a\x0b\xdd\x9a\xdaV\xf1\xaa!\xb6\xe6\x11f\xcc\xeb\xf85\xa9c\x1c\x1d\xa9\x00\x83}\xadI\x8d\xaa\xcd\xb5_3\xd5B\xc7\x8f\\\xd0\xfc\xcf\x9f[xEk^\xe9)\xd7U\xc8\x9b\x15\xe9l\xafl00\x9e\x85\xf5Y\x10\xde\xf1\xc8m\xc0\\v\x0e\xc7a<\xbb\xd0\x83`)A0\x1ee\x14\x06\xe0\xc2\xc8\x00h\x9f\x8a\xdd\xd7{\xa9a\xcf\x8a\xb8$Y\x8d\xa1\xba5<\xda\x10\x83\xd6\xf1\xf0\xac\xed\xf1\xaa\x95\x84\x9aG\x98B\x17\xf1\x95]\x9b0\xbf\x97\x92\xf9\xbd\x18aE\xfbE\x9f\x18\xd4\xc3\xa2s\xb0\xa5O\xf1\xba\xef\xfd\xa3\x01\xc6\"\x8d\xeb\x9ad\x13\xd0\x04}Yl\xd2\xf4\xe6\x8d\x08g\x84s\x1e\xe1;\xbe\xf0g~\xea\x93\xae\xf6\x1a\xf4\xe3\xc8:\xddh<1\x93\xea]\x99\xaf\x93\x8a\x8c\x18D\xc1\xb5\x86s\x9f`,\x14\xa7\xb1p\xcf\xae7\xe4\xda\x117\x86\xe3\xa3\xf0\xa1\xe0}m\xa5U\xb5\x01\xb8\xa8\xdb`\x08\xcf\xc1U\xc4j&\xf7\xaeL\xd6I\x9d8kA\xdcg\xb9\xf9\xcdg\x99T\x7f\xa9\xf2\x8c\xcb`+\xdd\xfb\xe7L\xde\xed\x89i\x16\x84\x92jn!/\x9b\xb4\xdc`\x1a\x18\xefQ\xe3\x1b\x9fT\xaf\xb9&b\x02W\xba\xd7\xcf\xe6s\\\xb0\xa6\xdaZW\xed\x7f\x92\x8c\x94q\x9d\x97#\xe6\xf5\\\x92d\xe5\xfb\x97\xcd\xd7ns\x13\x1fL@\x93P \xa9\x18\xdb=\x81B\xf7\xf2\x84\xe5\xaeu\x1eq+x\n~\xdc\x1fc\xeb \x95\xdf\x15C\x1f\xa9\x0c\xfd\x9dRap#t\xa3\x8e}A\xae\xb4'\xdb~\xba?\x94fm\xf8\xd3'{\x03\x86M\xb6O\xb7\xcebw\xb0\xf7\x9d\xf9\xd3\xff`s*q\xbfw\x07\xfeJz>\x8c\xe5o\xe8;\xae\xe8k\x97\xbcv\xcfF]_\x9d\x850\xb8N\xea\xd5\xf3\x92\xccIV'qZ\xc11xI6K7s\x82&`U\xbc&\xf7Y\x9cx\x8d+\xb6`\x03\xc4z\xdb\x14yd@hB\xe7\xbe\x81Pm\"p\x9d9\xbd&`G]XML\x01\xecX\xf5\x1e\xb0\x8cyTA\x8d\x177,\xfc=\x9b\xd1\xb6&\x9a\xd0g\xc6\xcf\x06\xd2\x1b\xcd\x9a\xe5\x99h\"\x88\x01\x8aw\xaea\xe0@\x95c/\xf2\xb9>x\xa7.\xcb\xc9\xef\xcc\xbf~\x85\xdb\xbdd\xe8\xb2,\x1e\xf0\xe9]\xc7\x97,\xb7\xf2_N\xdf\xbe\x11N\xbd\xb3\x94\xc4\xe5\xf3x\xb6\"6\xbb\xd6**\xd2\xcd2\xc9\xaa\xa8$\x8bJ\xf9\xb0cB|\xeb\x9aQ\x1eT\xc2R\x9b\x17J\x10\x97z\x95\x18\x92\x99\x9c\xa0X\xd8\x19\xe0<\x9f\xe1\xf0X\x14]\x12\x84\xdd\x19,TX\xf8\xd7C\xeae\xddf2\x84;\x01\xd3f\xba0\xe0\x97~JB\x8c\x9a\xb6\x07m\xd0i\n\xeb \x01N\xd5\xb0cI\x81\x931MM\xd3X\x13\xf2>\x08\xf5\xdf\xad\xf5\xdf1\x9cN\x08~\xc7\x8f.$\xec\x85\xb6~\x9c\xa6o\x17A\xd8\x8d\xf9n\x06\xb55k\x9b\xbc\x11\x1a\xa6<\x17qE^\xe4\xb3 \x9clCi\xf8\xf0\x07IfW[\xa1\xe5\xbdE\xa1\x82\xfe\x8b\xa4\x9aQ1$c\xec\xaa\x86\xebmj\xf3\xd5y\x1d\xcf\xca\\\xcb?\x8b\xb2\xce\xe7$\x15\x94\x86W\xefGE\x01\x854\x9e\xbb\xe4E\x86\x8eos\xdc\xac]b\xf4mv\xd5\x1b&\xdb\xb8\x1d\x8b\xf2\xa5\xee\xc7\xa2\xb8\xba!\x8b\"\xcf\x8a\x9e\x07\x87\xc9\x16\xb4[\x98\xeb\xa0[\x8fc\x1c:D\x91#\xb48v\x882\xac\xf2\xe6\x8e\x1e\xe6f\xb4>\x1b\xa283D\x9d\x0f\x9c}8D1(\xd2\xfd\x00&0\xeb%\x13\xb3\x9d\xe6\xa0\x90^\xc2N\x083\x8b9\x94pl1\x1cd\x8bE\x92\xa2{W\xff~\xde\xc4\x8fT(\x8c\xbe\xee\xaa\x1d\xb0\x0b3\x17\x19R\xdc\xb1]\xd2\xa3E\xfa\xcak9\xc66}\xd1\xd7^\xf2\xa6U\xc2\xa5\xaf\x89\xf1\xe3\x9dy\xf9\x0b^\xdb\x91\x97?g\xebr\x99\x14B\x97\x87<\xa7\xbe\xf25\x8b\xe7U\xd7\x1a\x19\x1d\xb8\xc1\x13\x89\xf8Ibd\xfai\xad\x13tc\x0e\xb1E\xbc\xd5\xbe\xa6\xffl\x04\x9d\x0b1fN\xed\x97\x18\x91\xd1\xcck\x8c\xe03\x1cy\x8c\xdb\xc0?\xe1t\xbf\x9b\xfa\xbd\xcfZn8\xf7\xa8\xb5\xb4\xe2\xd2\xfc\xbe\xe6\x15K\xbbY\x19Rnf\xfe\xd6\xba\x83\x83\xbd\xad\x93\xbb?\xd9Z\xfe\xdfZ\xfa\x1f\x18\xabU\xf6W\xdf\xdc\xb9\x10a\xe2\xc8\x0d\xfaOy\xa2\x9b\xd9\x03TAE\xb3\xb8\xa87%9\xad\xe3\xd9\xe5\x872\x9e\x1186\xbd\xe1\x04\x9d\xfe\x1b\xcd\xf2\xac\xaa\xcb\xcd\x0c\xdd\xdf'\xecYEkR^C\xfan\x06\xec\x99\xe5\xaaA\x1fx+k\x05\xde*Y\xe0\xad\x92\x05\xde*ww\x03\xc8\xa6e;\xf0Vi\xe0\xacqpkRU\xf1\x92`\xae\xc6\xbd\xb3\x90\x99\xd0\xd4\xad\x93J\xa7l7\x11\x8c\xac\xb9\x8bW\x9dUC\xf5\x05\xcf\xedC\x8f`\xf5\xa9\x02:\xfai\xd8q\xa8\x1a\xad\xf5\xfb\xed\xf12\xa9^\x96\x84\xa47o\xe25\xb1\xe7w\x90\x86\xe4S\xd2\xf2\xc7\xd1\xae\x1d;\xc4\xa5\x0b\x9d\x91\x80\x97Q\x92\xcd\xc9\xa7\xb7\x0b\xca\xa5\xfc \xee\xefS\xda\x9d\xcb\x87Y\xf30q\x0d=)WZ4BX#}$\xb1\x12e\xf4i\xf2\x1a\xb9K\x17M?\xc7:\xb80 \x1dX\xe5\x85\xa0f5\x0b\xc1\x13\xe7\x05\xfe\x10\xf9\xf8^\xb4\xbf\x98\x89\x90\xb4\xd5\x83j\xb6\"\xeb\xb8\xfb\xb4\xd5\x88\xf2\xbc\xdd\x95\xda\x0c\xef\xe8\x946\xa7\x1f{\x82cg\xfd= \x9f\xe2u\x91\x12\xefl\x0c\xc6v\xc8\xf7\xc3/ \xc3\xadW\xff\x96*X$G\xc6\xedp\x07\n\xda\xfe6B\xf3\x86~03\n\x87\x8cG\xf9\xc3`\xef\x8c\x9c\xed \xc5T\xef3r%\x91>\xb9F\xab\x8f~'\x1d!TP\xdd~E\xb1g\x90r\x97\xa4\xca\xd3+\xe2w\xb5\x82\x96}[G\xf3\xa4\x8a/R\xc6]-\xe2\x19\xc1\x00Q\xdd1\x84\x18]\xfb\x92<+\x92\xeaC\xbc\x94\xd9C\xfd:\xd0G)\x1e\xa2A\xb34!\x99\\\xc1Nt\xb7\xdfL\xcbxh\xd62\xfah\xed\xffm\x80\x91\xe4\x1e\x05\xba\x8a\x82\xa1\xd4\xa7\xf3\xa9\xc4[\xad\xb7A\x8a\xbb\xf9;\x03SY\xfa\xa9!\x8cb\xe6\xef?2\x06Q\\\x0cEP\xd4\x86\xb0[17\xf9'\x86\x00\x8a\x99\xff\xad\x8e#^s\xbe\xb7\x0d\xd8\x1ce\x0d48\x94\x82A\xae\x06CL\xe5\x8f\xe8\"\xc9\xe6~\xb6I\xd3\x90\x7f\x16\xf0X\x1f\x14\x9f1m\xad\xd2\x04\x7f|\xba\xb9\xa8KB\xdf\xce\xd5\xb7\xe4\x13\x99mj\xb4\xd0\x11\x7f\xd3\xc7\x9d\x18\x8fi\xebA\xabB\x13\xf01\xed=\xa4\x15\xdbJd\xe5g\xc82\x85\xb0\xb3\xe1\x87M\x92\xf2f\xae\xa2w\xcf\xde?{}\xf2\xe1\xe4\xfd\xf9\x0f?\xbd\xfa\xf1\xc5\xc9\xfbS\xd3f\x82#Xi_\xd0\x0f.h\x9b\xef\x99\xd4\x84\xed\xaa\x0f\x10r$-X\x9f\xfd\xdd\x90\x17\xaf\xe6\x13Xc\xe2\xfb\xf6\x86\xc0q+-\xc8\xac\xd1\xe2\xf1\xffY\xd8\x17\xfe\x00\x9d\xfc\x98 \xc5\xfe4\x99\x8e\xdao [\x14\xa5\xbd\xcbm\x17o*n\x0d \x84`\x1d(.\xe8y4\x96fe/l\xf4R\xc8\xc3xt\xef{\x83\xbe\xbb\x94\x08WRi\xcf\x02\x88\xd7\x06\xed/\x89Vy\x85\xbe\xba>\xff\xf3\x082\xfc#@ 3I\x80\xbf\x17\xbf\x8e`\xca\xc5\xdcY\x9e\xca\xe8(\xde\x84\x8a\x13^p\x86_^\xc4\x15y\x17\xd7+\xfe\xa9\xfcy\x04T\xba\xb3/\x80\xaa\x03\xc9\xc7\n\xca\x16e\xd3\xde\x80\xd01\xfc\xe9\xfe\x17\x98\xb8l\xadW{\xb2\xf7h\xdbO\x0f\x1fn\xad\x1f{\xb27` \xf4\xef%\x9a\xa9\xbf\xee\x9c\x1bG\x9bdv\x01\x89\xb8I \xd5\xeb\xb8\x18\x08.\x9e\xc3@\x84\xf0d\xc8\x1dX\x1a\x0chu\xbe\x9b![\x83j\xc8W8\x15\xedj\x87$\x82\xa1\x1fj\x9d\x85\x17C\x9e\xc42C\xa86h\xb4\xe0\xe5\x0f\xf6\x86\xdc\x81\x87Y2E\x14\xbd\xf6I@E\xc1\x02\x8d\xb6\xad\xaa\x1a\x11n\xfdP+5\x89x\xeb\xda\x81\x8b8\xda\x87\xda\xb7\"\x8e\xf6Cm\xc3\"\x8e\xf6C\xed2 o\xf0\x87Z\xafm\xe1\x0e\xfeP\xeb\x98\xed\x94\x08A\xb9\x00\x1e<\x80;\xf9\xb5\x98\x98K\x82^.\x12\xf6b\x98\xcdd,\x92g\xf1'\x99\x93\x8b\xcd\xf2GrE(\xe7\x98d\x8b\xdcR_\xde\xfaO-\xael\xac\xe2\x9f\x93\xaa\xce\xcb\x1b\xb3\xd5\x9a(\x8cy\xb07+|s\x1d\xaa\x16\xcc:|.Y:\xdb\x07U\x1dSi\xc46\xd4\xc2\xb5\xbd\xc6\x0c\xc3\xd2\"\xaf\xf8\xa1$d\x82\x9b\xea\xdc,4\xa9\xa5Z\xe5\xd7/\xe8\x02\x9a31\x89\x12\xa7\xa93\x1c\xd8\xd2Q2M\xa5 FY-h\x91&\x17\xafI\xbd\xca\xe7\xd5\xa4\x8b\xab\x9dd0\x14u\x035\x10\xbcu\xdc\x1d\xc6\\\x93RJ\x14\xca\xc1\x04\xfc\x06eI$\xb7w\xbe$5S\x16\xf0\xceE\x05n\xf3\xad\xd6\xe3\x8f\xfa\xd5Wq\xf5~\x93\xc9\xaa\xecg\xbf\xdau\x19\x17\x05\x99\xbfk\xce&\xfaT\x98\xfa\xac\xe3\xc2\x97\xd5X\x1d\xa5\x89@\x84\xe4\x91\xc0\x89\x1a\x13j\xd1\x01\xc7>fD\xd4T\x8c\xe7s\x7fz\x166\x1cp`\xf9\x80\xe3\\\xf3\x11\x7f \xbf\xdb\x14\xf3\xb8&\x1c\xec\xbe\xda\x94\xde\xd2`\xd0\x11\x87\"\xc1\xbcA\x02\x12\xc2\xd4L\xbd.\xc9\xcd\x04<\xa4L\x03h\xc7Y\x03\xbb\xee@\x14\xe4\xef\xe94\x1a\x9a\xc7\x8c\xf5m\x1f\x82z\x9bV\x87Z-1\xbbBc\x17j\x19\xaa\x8c\x8f!\x83\xfb\xb0\x0f\x13\xd8\x0bBd?\xf6\x9fB\x0e\xdfC\xf6\x14\xf2\xdd\xdd\x00\xcai\x8e73\xadK\xb6\xdc\xc1%\x17\xdd\xbfy\x94\x95 J\xf3e\x13\x86Jc\xbd\xa1\x16\xb39\x8b\xc1Fd\xe8\x90a\xcbtE\xca\x8b\xbc\x1a\x8a\x04\xb1\xd5B\xc9v\x99\xf3_{\xd9l\x0d\xc0\xbf\xcf\x82M\xbd)\x06\xce\x84]\xf0\xce(C\x7ff\x8b\xca&\xcaWX\xcb\x86*\x8dYNKx\x05P\x04dAE\\lk\xd4\x827\xb9\x83*\x13Qr\x83\x08\xd0-B\xfa\x99*\xf4\x99\x9ex\x98F\xb8d\xd70h\xf4\xde\xab\x10\xc0\x04t\x04\xda\xc7\xb0m9\xbf\xc9Qk0\xe9G\xc4\xab\xca\xad\xdcu\xb7\\m\x93P[\x14>\xd1\x9d^\x889\xcc\xc5G\xaeHy3\xce\xb1Y-R\x86<\xe2I\x98\x9d\xbe4$\x1bkU\xb1o*\xde\xb7T\xd4tL-K?\x0f\xc1\x988\xb1[0\x16D\x08\xb3\x10\x16!\x14\xe8\x14\xbf\na\x8d\xee\xab7\xf6\xb1\x80n\x85p\x1a\xc2\xf3\x10.Cx\x16\xc2\xdb\x10\xde\xb9A\xbe[,+\x11o;~\xd0\xadL,V&\xdeje\xbae\xdb\x95\xea\x16\xcch\xdd\xa7A\xf9\xa8\x00\x16C%\x96\xf9r\xb6[\xa4nq\x0fk1T\xec!*l\x85\xa5b\xb8$7x\xd3\xbf\x98.T#\x9a;\x07\xde\xc3\xff,\xe0\xf1\x9d\xd7L\x0f\xe3D\xe3\xd9\xe9\xa3>\xf9\x92\xdc \x0d1%.u-,\xe2\xff\x97o\x93f\xa4\x8f\xbfl@\xe0\x96\x11\xc4V\\\x93H\xd9\n\x9a\x89)\x98\x1b\xa2\xe2m1\x9d\x9f\x85\xa8G[H\xab+\xd5l*\x08Q\x8d\xa6>\xc2\x93\x1dC\xa9\xcc\xf1\xcfu\x88\x87B\xa2\x0dD1\x9b\xe6\xd17\xdf\x94dq\xc6\xb2\x95\xee\xec\x85\xa8=\xdb\xd9gf\xbf\"\xed\x91\xa4\x99\xfb\x0fC\xb4\x0d\xee\xb8\xbe\xd0\x9fU\xf3\xd3\x98 \xd3\xb58\xa7C\xb2\x15J\x1c0\xce\xc5'8\x82\x13\xc4\x1d?\x08\xa2y\x9e91r.Eb\xe4\xe1\x7f\x18m\xc0\xe8&p\x04\x9fD\x10\xf9\xe7p\x04\xf9\xf4\xf4,\xc4\xf8\x95\x0b!\xf7\x9c\x06!\x86\xac\xd4\x9c^\xcf\x83\x10\xdeb\x96\x17\xc4\xb2\x10\x06\xd3\xfa\x8e)\xf1\xd8\x84H\xb6\xf2\xaf\x04\xf5\x9dg\xff\x0d&K\x91^W:\xb2\xf6\x16\xe5\xb6\xd9\xf4\xed\x19\xd2\xb4\x80Y\xb8\xa5d\x19\xd7\xe4\xff$$\x9d\xfb\xa5\xcf\xd8\xd6\"\x08\xc1\xab\xf7\xbc\x10\x0e\x1e\xdd\x05\xcdr\xc9\x81e+\x18x\x9aJ{\xa7,d\x0c=\x83\xef\x1c\x1f\x0e-)\xb8\\\xcb\xbf\n>P\xa0\xbd\xc3\xcc\x06\x19\x8b\xd0\x96a$\xbbw\xff\x0d8K\xe9r\x80\x87\xfb\n\x0b\xf8\x1c%\xbcK\xcc\xddZ\xdc\xc5\xfe8tt\x15\x1c*\x82Q\x89\x9b\xf4\x8b_62\xb8CV\xf0\xf0Ny\\\xc7\xcc\xaaC\xe5\xce&v\x07\x94M\xb2\x91\x87\x98\xb3\x153\x0b\xc6\"c\xde\xc3\x80\xf3\x9e{\x8c\xf7\x8c\xadi\x02m\x85\xc9\x1cw \x9b\xcbq?Ty\xe1\x87\xfb!\xec\\P2s\x12\xf1]\xa4\xfc\xddM\xc05\xb68\xa5Hs)\x9426c>\x0ca\xe7\xfc\xce\x89\xe2\xc3;\xd8\x81\xf0/D\x14Y\xde\xbd\xeb/\x9b\x14[\xc1;\xd86\x92D/\x92,\xa9V\xfe\xc3\xc3;\xc1-\x87D\x89\xb6\xd2\x1b\xd9\xde\x9d\x8c\xec\xf1\x97\x8dl\x1b?sS\x913t\xf4?7\x95\xedp\xf26\x84\xd8\x9e\x98\xd0V\xa6Tj\xa7$\x97\x92\xaf\x87\x8f\x1dB\x1a\x9b\xca\x94\xd2\xbc\x10\xa9\xc8\xc3\xef\xdc\xee\x0e\xba\xc5\x10\x15r\xa8\xdc\xb2\xc4\xf1\x9d\x8b\x83\x9b D\x9b+\x0c\xc9\xcb\xcf\x8d\x82\xeb.\xe6\x8a\xeeBj\xe2\x1f\x852f\xac\xa2\xba\xc8uw\xf8\xdd8mc\xf5\x19\x88\x81[`1\xa5\xd5\x18\x84x\x8d\x1e\x02w\xa1\xae(%\x97\xb4\xa5zb;\x9a<\x1e\xdf\xf9N[\xc2\x11\xac\x85\xc6\xa1\xec\x88m7\xfeR\xbcZ\xf28\xa3K)\xc1\xed\xefo\xb3J\xfb[p\xa4\x02\xdd$l\xb7\xd0En\xc1\x97\xb1\xf1n\xc1`\xcaq\x1el\xc1Pn=\xd0-N>\xb9W\xf7\x1fQ\xe8\xb2\xd4\xd3\x9cA|\x14\xf0\xfd\xbd\xc7\xf6w9\x9a?d\x12\xfa\x16\xfc\xa0\x1c\xd6\x81JO\x0e(\xff\xb7\xa0<\xdfJ\xe1\xffV[\xf2\x7f\xce\x99\xc4\xbb\x85%3\x16c\xa2\xfc\xdd\xd6\xf7}\xe5\x97j\x8b~-Z\xc1\xf8\xb3\xf9\xb8An\xad\xa0\x91\xee\x8c\x9c\xcb9\x18\xcb\x7f9\xe73\xef\x96^\xcfc\xf9+\xd6\xf3\xc8\x93\xe8K\xf8'9\xe2\x91\xfc\x92\x1b\x0e\xdc\x86P\x8e\xe7\x87\xa6\x8fB$(t\xf7\x1e\x8ca\x7f\xa6\x07\xc8\xee\xd0Mu\xe0\xc8\xee8\xb07\x16k\x8a[\x9f\x04}\x03\xe2\x9c\x99\x1d\x96\x81\xcd\x8a\x18\xa4=\xe8\x9bxM&\xc0\xa3.|\xfe<\x14~Q\x94V\xe8Y\x95!\x92\x8f\xfd\xdc2\xfa\xd1Q\x8d\xecVN\x94(\x8d\xb6r\xb2\xd1@\xbbw\x9b(\x8aE\xe4\xaam\x16\xdb1\x1eU\xbc?\x9c\xcc\n\xa4\xf7\xd6\x92\xd4\x82\xd3\xac^\xe6%k\xce\xaf\xd5\x8c\xae\xbf\x0d\xd0U\x83\xec;\x84\xbd4\xec\xecX|\xb72\xd8J\xc9K`\xa1\x0c\xb9\xd2\xfb\xcc-u\xa7Z$\xe8q\xe8\x16\xe0~\x05\xe8. \xc7hno?\x02\xb8\xd6\xf9\xa9Q\x13\"\xd9\x11\xa5\x06>\xb1\x1c\x1f\xaa\xd7n\xcb\x1f`Z\xf3\xfc3_\x11\x14\xef7\xd9\xf3|\x93\x0de\xb0\x1a\x0d\x0buB]\x98\xfbDl\xb0\xaf8)\xde\xd7\x87d\xc8 \x7f\xf4\xb4\xf4K\xdc\xcc\xcbm\x951\xe2\xcf\xb4V\xedeX\xf2\xaa\xaf\x08\x0fA\xe7^es\xf2\xe9W\x03\xc9\x87\xa4\xc0\xe4\xcbj\xe7N0\xf2\xb2\xcd\xfa\x82\x94\x1e\xec4\xbe\xd9p\x0c\xf7\xf7\xc1\x94&\x0d\xee\x04Lt\xb7\xde%t$\xbdkX\x83\xbb\x1f=w@\xd8\x96\xae9\xd8\xc8\xb6\xcc\x92\xc7\x916_C\xd4\xb2\xb3\xb6\xbf\x87\xf2\x9c\xa7TG\x1f\x8c\xa1x\x91_\x08+v\x80}E(\x0d\x03\xa5a\xf1\xda\xe9;\xe8f\xe1y&F\x1e\xach\x8d\xd7\x0b\xec\x1f@\xc6\xbd\xcd\x19Dm\x8bE\x0bf\xd8\x19NY\xa1\x16\xb4\x9b\xd0\x1aqKV\x025\x82\x19sK\xf0\xbb+\x00\xde\xff\xcck\x88!\xcb\xb3\xfb,\x0f0\xf3\x1b\xf3Bp\x19-\xf0!d\x91\xf4\xf1b\xb1\x83\x1b?.1\xf5\xb0\xc5Ys\x1e\xcb'2=\x91\xf0\xd5\xec\xb19\xcd\xf7l\"\xad\xf7\x1fV$s\x82+h\x8cM\xd5\\\x1a\x1a\x88U\xd2\xcd\xca'\\\xed&\x86\xbb]\x7f\xe2\x14\xd0\xf4\xc5\x96E\xb2\xc3\xba\xcc\x15\xdd\xe2\x96\x93D-\xfd\x8c\xc7]\xfc\xb463,\xb0~\x0d\x8e\xbc\x03\x991D\xc3\x06\x97v\xe6\xebvL\x16\xb1\xd2hO\xd1qJP^!\x19\xd5\x19\xe3\x88Z\\\xf5\xae\xc8\xb4\xbf\xdc6xdA$q\xba+\xfesM\xe2)\xe6BW\xc75\xc1\xf0\xbev\x14p\x0c\x1ebY\xe1\xe1\x11\xb3\xc0\x14\xd8\xaet\x81mvp3dJ\xa7\xbf\x02\xb2\xb0\\\xc6\xdb\npV\x84iq[]:\xd5\xc4\x07\xb4\x81\xe8{\xd8\x13!n8U\xfeP&d\x0eu\xce\xf3;C\xdc\xf6\n\x86z\x15\xd7\x90T\xd9\x1fj\xa8W\xa4$;\x9e\x0c\xb7\xd9\x1dFU\xa4 \x95\x18C\xd8\xff\n\x00\xee\x11\xdf\xaf\x05^'>\xb5\xd9c\xfc\xafN\x14\x19''!\x11eN\xb7M]\xb6\x154S\xcd\xac\x95m\xfb\x070\xbe\x81\x06\x8d\xd9\xfe\xe9x\xbb\xda\xdc(\x03~\x890\x0e \xee\xfdkB\xa5\xaa\xe5k\x1c\x07\xaa\xd2h\x0c\xee90\x90\x8d\x97\x18\xa0\xe6p/\xd4\x0bBH\xe1\x04\x15h\xa8\x1c\x93'\x05\x95k\x9eW\xb8\x1f-\x01\xd8\xbf\x00\x1c\xcf7eI\xb2\xad\xa0\xe2\x08\x11!w\xe8\xb4u\xfc\x15\x1f\x04\x7f\xfa\x95tG\xfd\xfeG\xccu\x14\xf5\x89\xf4\x92\xbb\x95\xb6\x9b\x00\xe6\xd7\xb0\xfbU\xe8q\x17\xf4#\x00b\x83\x87:\x97\x99\xda\xc7W\x99\x05')o\x17\x1fn\x8aQ:\x80\x11\x1b[\xd8<|\xa5\x8d\xf8cr1b\xe0\x8e\x83F\xf07a+\xee~\xe0\xe7K\xf25t\x8f\x0d\xcb\x8a\xc9\xf1\xdb\xdc\xeaW\x80\xbf\x12\x14\xe3+\xcc\x86m\x82&\xfc \x9d\xd4\x90\xb8\xb4\xf54\xaa\xadf\xe1\xbe\x07z\x13\xa9\xe8D\xbe\xce\xd9\xc4\x83\x8f\x8c\x99\xc8\x98Y\xf44\xe8\xc6\xc3\x08\xfe\x04>;\xd1\xbf\xc6,gi\x9e\x8d\xa2X\x8e\x93\xfc\xcb\xe9\xdb7<@\x1feMsE6\xfd\x1a\xe7\xab\x88\x8d5b&\xb6\x89H\x97lb\x9f4-\x84 \xce-\x81W\x93\xcc\x97k.\xda\xac( a\xfbH\x14\xd09\xfe\xedW\xc6\x99sM\x19\xc0\xba\xb9\xcf\xb5\x19\xc9\xa0R\xcf\xc9\x11_D\x8ck:h\xf1\xec\x0e\xc2\x06\xed+\x97\xda\xa8\xdc1\xb8v\xb7\x88}i\x8a\xb0\xa6+}\xe9\xe4\xeb\xf6f\x87\x85\x88\x96\xed6\n5\xb6+\x9ekN_\x89\x00b\xf8\x1d\xfba\xfd\xce=\xca\x04\x1b\x8d\xaa\x8a\xf5\x13\x11\x0eI\xa0I\xa3\x9a\x0dB\xf5\x9e\x99\x07\xb3M\xbed\x131]0\xbbV@\x9a\x8c\x11C\xd5\xdfx\xd3\x16\xb6\x1f\xb2\x0c\x1e~\xef\x19Rl\xca8k\xea\xff \xf6\xf7\xb4\xd7\xe5\xd6\x98\xbc\xa2\xb0\xf5\xcb\\\x17O,\x9cT\x99r?P\x99\xf4\xc3\xf7\xfeF\xfepE\xa0$\xf1lE\xe6\x10\xc3*.\xe7\x90&\xeb\xa4\x86|A\xc7\xcbMT\xa0\xdcd\x95g\xa3V\x0eD\xa2DW\xb9>\x87.5\x93zK\x03\x97}&\x92\x08i\x9b\x19oy\x00\xe3\xac\x0f\xc0\x01\x00\x00\xd0_\xfe8M\xfd\xcd\x97\x8e\x0fi\xa0\x88\x97\x13\x82\x0cmfm\xe56p\xcdN\xd0-\xdb\x91\xb4/\xd8\xa9\xbc\xc3Q\x03\xcd:Xv\x04\xa5}\x89\xc4\xb9\x9aE\x1a]\x85o \xab'J\x8e\x0dtu-p\x1f\x1cla\xc7]\xa6\x95\xaa\xd9\x97\x0bPD\x11\x87\xc7P&_]\x89\x99\xf1\xfe\xa8o6\x8e\xd1\xa3\xd4\xe2\x0e\x06Qdh\xb2\x8a\x99 w\\\x08J\xbf\x0e\xd9\xaa\xfe\x98\\\xf8A\x10<\x85\x1d\x9fB\xc0\xaf0\xa9A\xcb\x8c\xff)\x87M\x00\xc4\xaf\xf8\xe5\x87\xf3`\xc6\xdft\x89\x12s\xcbi\n0;\xc5\x11\xe5\x16\x16I\x16\xa7\xe9X\x80\x8d\x071-; %\xd7\x85bL]Hc\xeaQ\x8dm;l\x10\xeer\x01\xb70\xde\x8c\xfa\xdc\xcd\x86\x15\x9ck\xde\xb2;p\xd2G0\xeb\xe7\x12Q\xac\xe2\xb0(\xed+Q\x8ck\xeeO-\x91A\x9d\x8cQEa'\xfe\x04\xfaY\xfeu\xe56p\xb1\xa4\x1d\xb9\xceRTj\x99K\x95cf\xd12!2%\xec\xee\x16\x97\xf8i\xd6\x1a\xd2,\xc0\xf1`\xbc\x1dxo\x90\x8d1&}\xef\xd5\xad\xeel:1J\x07%YT\x13X\x0b4\xd1\xd3sL\xa1<\x81\xe5p\xad&\x05\xd7\x04n,Ue\x04\x9c \\\x88\xaa\xfd\xa9\xb4O 5\x0c\xf9u;By\x93ay\\<\xf8\xc3\x87\x03\xf1\xe0\x87?=x\xfc\xdd\xb6\x9f>\xde:\xa5\xe4\xc1\xf6\x91\xef\xf7\xf7\xb6\xfdt\xff\xbb\xed\x13\x04\xec\x7fIF\xca\xd6+\xa9\x94\xf9\x8d\xe2\xed\xeb\x07\x93\x1b\x95\x98,2LT\x93\x8aY5\xe9\x07\x80\xb5jq\x80Q\x99\xecm\xebV\x9d\xe5Z\x8a\xa1$i\\'W\x04~z\xffc\x08\xd7I\xbd\xca75\xac\xe2\xab$[B\x0c\"\x13E\x84Y\xbe'\xf0\x07\x19\xf4\xf4\x0f\xf2\x1d\x7fZ\xe3S].Bh\xa0\xf8\xa9'\x97\xd6Z\xf5w\x9f2\x89ep\x82^b\x84\x9e \x9f\x0c \xcf\xf3M:\x87,\xaf%DJ\xb2 %\xc9f\x04.\xc8,\xa6X\x93/&\x80\xb3\x16\xb92\x11\xc3:c6\x0d$\x1e\xc4)\x1f!\xe9\x05h\xa3P\xfb\xde\xef=\xb7V7\xc6\xe9 \x9b\xbfwS\xa2\x89o\x8b\xda\x084\xe09\xd5\x98\x9eeA0\xc0\xb1 \xab\x80\x14\x99\x90\xe1U\xa6\x0c\xc2E\xc3 ,{\x8b>\xec\xbfr~\xce\x15\xabz\x1eA\x97\x91\xc6\xca\x10\xf3\x91\xa9C\xe1v\x81\xee\xb8W\xf9\xa4+\xce\xda\xfaKM\xf8\xed\xb6\xd0\x95\xbe\x03!B\xeaWY\x88\xcep\x0c\xbae\xae\x038\x86\x1a&\xd0_\x96:\x80 \xf8\xb4U8\x82W,G\xf8_N\xdf\xbe\xe9\xcf\xdb\xc8O\xf2\xcey\x1b\xb5>U`\x88\xef\xdd@\x90Zq}\xa6\xbd\x85f\x9a7.\x17\x7f\x0f\xfbR5V\xf7\xeb\n\xdc>\xed\xde\xd1\xe91\x1d\xcd\x18\x9b\xac\xe4e\x87\xca\xf6\x89J\x91'YMJNG\xe8\x9e\x87yN*\xacC>%U\x0dI\x06\xf3|\x86\xa1\xa9\xb5\xf9Th\x91\xadh\xce\x14\xcd(\xf9t\xbb\xc9\x16\xf5P\x9e\xe9\x11\xad\x95\xfe\xb21\xf9 \xea\x8c?\xdc\x14\x84\xeb\xfbN>\x15dV\xa3\xaa\x8f}\x14\xc2\x12\xadi\xe9\xbcU\x90\xd1\xc3\xd3\xdbd,\xaf\xcc\xdc\x03\x96|\xe0\xaau\xa3c\x9e\x92\xf7\x80Y(\x92\xe9\xde\x99\xbc!!Q\xb5\xb9\xa8\xea\x12s\xc1\x80\xe7\xc9~\xa6g0\xc1\x0cXHb\x1fx\x01\xd3\x86\xb9a\xdfb\x90~\xeb@\xc3\xd9\x82\x13\x89J\x9b\x8cT\xb3\xb8 >\x91\xc9\x9f\x1e\xfc\xd7\xfe\x83e\x88\xb9\x9d\x94g{\xf8\xec\xbf\xbazP\xd3\xd0\x8a\xc1\xa15\xfdkzg\x1d\xed\xa9\xbd\x7f|\xc0\x1e\xee\xbbv?\x1fdP~\xf6\xeb\xc6\xa4wG\xa3\x95\x11\x9b\x97D\xb3U\\>\xab\xfdZ\xda\x0b\xe9\xe9\n\xcb^\x86\xa6C\xf7u\x1e\xfe\xbc/\x8e_j\xdac\x8a!;\x98\xb9^ \x0e\xfb\xf1{\xfe\x03k\xd0_;t3;M~%\xf8\xcc\x10\xb4:1q\x0d\xf5\x01\xef\xc5K\xcdpsL\xf5\x95\xf3\xc0\x15\x1f\xf0\xda\xb9\x0cA\x1b2Sh\xd2\xec\xa7\x0e\xf4\x01\xc1)\xe01\xdd\x12\x13\x84\x00\xb22q\xe1\x17A\x93@Z\xdb\xda\xad\x9f\x19V#\x86#\xf0\xf1\xee\xc2\xfb\xbe*\xc8l\x1d\x17\xf7);\xf8'/\xa0\xd4\xed\xf7\xd8\x89\x9ep\xd6p\x84\xce\xfc\x1d\xdb\x81\xe9Y\x80i\xcf^\xe43\x0cZ\xea'\x98\xca\xd0\x86B\x1b8\x02\xcf3Q\xffq\x19\xadi[\x1b:|\x84Q\x81\xb7\xaa\xf9t\x83$\x86\xfe\xef\xda\x9c\xd2$n\x92\x18c\xb6\xcf\xfd\xd8h\xe8\xa1\xe3h\x86\xe7\x9eO\x13\xbc\"\xc2\xff\xb9\x93\n\xbf\x7f\x89\xbb\xfbW\xfdu\xe7 \xbd\xdaC\xa3Kr5\x94\x93k=\x94Xk9\x98\xb0K\xa6\x82\xd2~{1\x94X\xeb\x9c%\xba\xd5e\xb3\xbd\x16}jSH\x9d\x88>\xb5\xcd~\x1aL\xf2{:\x94\x13\xeb\xb9\x18\xae\x16J\x97B&\xef\xbfz\xc6\xd3\xea\xbf'\xcb\x93O\x85\xef\xfd\xdd\x9f\xc6\xf7\xffy\xb6;y\xf0\xe0\xf3\x83\x07\x81\x17\x82\x97x\x9a\xef\xder}\xf5\xf3\xe6\x8c\xf5(k\xf7\x9e,\xf0\xf0\xf6\xec2\xb4(x\x03&2M\xe2\xc7,_\x7f\x87\xebGk\x00\xe0\x17\x9c:\x04\xef\x0f\xf2\x1d#\x87\xbd\xe7\x1f\xf8\xa4\x07\x94?\xaf\x8d\x8a(f\xcd\xf1MI\x16\x06K\x0e\xa1\x91\xec\xce\xdf@\xdbE\xc1\x8b\x00\xbc\x86a\xa7\xd2^\x08\xda\x83I\x14\x94\xc8i\xad\xcb(\xa9^\x96\x84\xa47o\xe25\x99\x07~e\x0d\xeeN\xfb\xc2\xb4sJ\xf6#?\x93\x14\xd3~1\xaag\xe2\xda\xc20\x05\xd1\x04\xd6\x9b\xaa\x86\x0b\"Y8\xf0)\x9a\xdc\x7fO\x16\x81\x913U\x0bk\xc5\xe1\xfe\x98\x8f}\x02\x0e\xd9A\x16\x1b\xbc\xa3_\xd9,\xcamW\xa4\x14\x8e\x0b8B\xb1\xdc\xdek\x81\xa1\xb7\xf7\x1c\"E`\xd8\xee)\xf3\x9b\xb5en\xa3\xe5\xca\xf1\xbe\xca\xed\x02\x85\xb6\x96\xd2\xae\x0b8\x86\xdc/BH\xa9 gL.+\xca\xb8\xdb\x01\x8e, =-\xec\xb5A\x15X\xe6v\x88\xc0\x18\xd4\x01\x8e>\x0c%\xae\xdc>p\xc5!\xd0\x1f\xc8\xad\xd7V$[6\x91\xc7\xac\x9d\xdd8\"\x03\x12\x90\x95?\x0f\xe1*\x84\n\xcd\xbb\x1c\x16\x029\xa1M\x9aR\xb6\xeb\n\x8e\xc1\xbfA\x91y.\xfc\x07\x19\x9f\xe8/\x05u\xf1o\x02\xc62/9\xd1\x1dV\x93q\x99\xf6_\x06%\\)\n\x8c\xc6\x88\x80\xee\xa9%OhD\xe9(Bh\xe3_\x850\x0f\x82\x88+\xad\xe0\x18\x96\xf2\xef ,\xbb&]N[\x0ddl\xa3\x11\xbb\x0d\xb6\x00/\x8c\x051l\x01f\x18 j\xb0o@\xe0j\xa4\xa5\xc6\xc5\x98\xd3\xa9\xe9\xa9\xa2\xdeZ\xe7W\x84\n3\xb0t\xc8\xfaE\xf7\xefEK\x1b$\xa4\xe4\n\xd3\xdf\xb8-\xc77\x1c\xae\xd6\xca\xb63\x0b\x84\xc6\x89\xee\xca+\x14R\xd3f\x96\x17\xa12N\x91\x1b\xd0\x9acT\x14\xb9\x94W\xd6\xea\xb7\x81\x03\xe8\xdc\xce+\x10\xc4l\x9c\xc5\xb6Z\x84\xfa@\xab\x005\x15iST\xc4\xf5**\xc9|3#\xfe\xd6C\x00\xf52\x96ytNk\xbc:\x9d\xd6nA\xa2h\xc1\x8c\xfd\xee\xfb\x08F$\xa55\x15>hU7\xcc\x9d\xe4\xb9\xb2$S\xb5'\x7f:\x82=\xd4U\xec\x85\xcdmn\xe0\xd7AG\x1cv\xf2\xa4\xd3\x15q\xb1\xe3\xd7\xd3\xcc\xe1\xb2\xbf[\x86\xe2\xf2\xe8\xca\xad_\x8f1\xb7\xb9\xf5K\xe1\xa5q\xd1\x88\xe4\x17\xd6o\xed7\x12\xdd\"p\xc9\xc6\xb5\x81\x95\x011\xbf5\\\xf8\xf7\x9ejd\xb0W\\\x80T$\xbc\xd7&23\xcfg\xcf\xe3\xd9\x8aL\xe0\x9d\x1e\xb5\xe3\x8b*O75I\x167\x13\xc8\xf5uf)\x89K\xde\x8c\x9b\xd2\x85\xf33;\\\xf1;')\xa9 \xbb\x8a\x98t\xf1\xf7\xdd6\x91-\x94\x16\xcd 6\xa8x\xf4\x93TE\xf0 \xbc\xd5W\xba.\xe3\x82\xd7H\xf45\x96\xa4F2n0\xbfG\xdd\xf7\x04b\xfd[\xf2\xa9.\xe3Y\xfd\xb2\xcc\xd7\xd8\xc8F_M\xde\x06\xb9.\x87r\x19x\xce\xee\x920\x81\xec0\x88W$\x9e\xa3\xa1\x87}\xd3<\x9b\xcdHQO\xc0\x8b\x8b\"Mfh\x8f\xf3\xe0\xe7*\xcfBP\x9f\xdc\xc4\xeb\xd4\x1b\xde/\xc3\xf47\xcd\xe3\xf9)\xdaF\xef\x98\xe3\xaf\xdd:\xdf\x0c\x8a\"\xe8^\x84G\xf6\x80\x91\xce\xb6-_K\x02_\xc5\x0b\xf2c\x1e\xcf\x07=\xb4F\xe1-\xc7\x19#\x0fH\x97\xe1\x1dcF?\xe4\xe8\xa42\x81\x99\xbe\xaa\xb8\x1f\xf9\x8b\xfa\xc9%\xc9&\xb0\xe8\xd3\xa5\xa0k\xb9\xc3\xa7\x08G\xf0\xaa\xaf\x8a\xfc\xd9\xaa4\x17*V\xa2^\x0f\x10\xf5z\xa0cp\xd0\xeeD5J\xa9{\xe6FcMZ\x1enm\x0ds\xf0\xed\xf6\x9f>\xfa\x02C\x1a\xf5\xcd\xaf\xa0Z.\xad\xeb \xdb\x1a\xec\xc0\xb0\xd1\x0e\xe8\x8fI\x93\xc29\x17\n\\3\xba\xf6\x87\xc1\x14\x95h\x12\xa7Q!\x99\xb5\x94 ^1\xe8\xa7\x85lv\x1c\xadI\x1dS\xa4\xe6\x7f\xb24\\6\xe5\xe6f\x1b\xe5f\xdeUnn\xacZ\nf\xd0\xd4Isk\xfb\x08T\x0dl\xfb\x16\x1a!\xd8\xe813\x88i\x9b&\xc3$\xb5\x08;\x8fH\x88\xabL\xb1m\x89\x003\xf8Vhn],\xdag\x98\xee\x04\xb7\xc3\xf0X7[\xf0.\x80\x1d`B,8\x82Y\xcf\xfe\xa2[\xa8x\xcd\xf8\x1d\xfc\xc0\xdfca\xd89\xfb\xf4\xcbm\x08\xb3 \x88\x10\xd6n:\xd7i\"\xe5\xe8M\x08\xbf\xdc\x062c6\xe9\xf8\xa78\nb\x887I;\xc4\x97\xfd+\xe0_624\xe5\xb8\xed\xb8A\x0b.\xa4\xa3\x8b\x81\xa0W]\x13\x89\x94`\xfeqH2h#*\x8b\xbdT\xb9\xe0)(\xe6\x1d\x1d\\\xb5\x9bU;\x9b\x18'\xd1\x9a\x94K\xf2\x82\x90\x82\xae\x98E`\xba\xb5\xc5n\xe2\xad.\x98\xac\xdci|\x16\x04!\xcc\x18]\xa2\x84J\xd6\xe2\xba\x9b\xa9D\x96M\x08\x1eV\xf3\x02\xfaM\x9fG\x10\xc5Y\xd6i=\xc1XTc\x0eu\xeb\x19\xd9z%e\xf7\xdf\xc8\xd8T\xfd\xf5+\x1c\xd8\xf9\xd0\xadl\xd2\\\x90\x8e?&\x1b\x9b\xf0Qgei9+{\xd9\xd6q\x1d\xec^\x82\xe2\xbc\xec8\xa6O\xcf\xec\xea\x9d\xfe\x1d\xa2E\x1c\xe9wC\xa9q\xd2\xb1]+\xa3\xaa \xb3\x10\xaa\xa1})e\x90\xfey\xe2@\x84\xdd\xb4}\x9bi}\xa6,h\x19\xc9\xa5{\x1d\xcf\xca\xdcO\xed\xa4e\x94.E\xe0]\xe3\x87j\x0bR\x03\x0d$\xf2\x0e9\x1dv\xec\x18P\xb4\x04\xea\x8a\x88s/\x0bac\x10\xb3\xb4O%!\xd64d5\\\xfdoJ\xf6oB\xc9\x9a\xa4\xcd\xa3(\x99i/\xd0\xd1\xc6z\x1aa\xda\x08\xd2\xb1qC\xd9\x122d\x06NK<\xdd\xb4w\xf4:\x9f\x93T\xc0\x9d\xedjZ\xc7\x80\xeaN\xbbY\xe5\xed\xed\xbbx\x14\xe3>~\xaf\xc5\xff\x8f\xef5\xfd`\xcc.*\xd2T@\xdf\xf3l\x95\xa4\xf3\x92d\x13]\x8cq\x16e\xb0v3BM\x86l\x95\xe4\xe1&b\"\xca`\x0b$*\xca\xbc\xce\xff\xca\x9fgp\x8c\xbbe\xd3\xde-\x99R\xab\x89P\x8a\xc6\xc4W\xec\x99\xbf\xa7\x04\x8c\x08|\x12\x89\x99i\x94\xcb\xc6\xd3T\xb5\x84e_Ok\xc3\xa5V\xab\n\x1cAB\x913\x13\xa3\xd1\xba\x19t=\xf9~u\xc2\x19\x0fY\xfcm\xf8\xcbC\xdd\xcbJ\x98\xd7i-\xe8RA\x90\xb5\x0d\xcfTM\x91 \xf2\xae\x17i\x9d\xb4\xf6\xcc\xb0M\x86o-\xf3\x9cR\xc1\xdc7\x9a\xba\x81\x8d\xe8t\x1c\xc9I\x08S\xf3hd\\\xac\x11\x81\x89\\\xb8\xb9\xabnP\xf5\xb8$\x19\xc6\xc2\xda\xb1\xa5\x1bB\x1b\x13[\xfb\xa0\x08\xc5dJ\xd4t\x03v\xd5\x08p\xa3\xe3L\xee\x00;K\x17O\xcb38\x86\xc4\xa7\x7f\x0821a\x8fq\xbd\xe8\x83\xc1V\xb8\xe7u\xe2\xcb\x85f\xcdl\xd2t@\x91\xae_\x7f{\xc0\xa9;\x8e;G\x17\xc5\x97\xb1;\xa7g\x81\xd6\x19FL\xccE\xed$\xd9\x04\x19\x15\x92\x81$S\xd3,*\x7fS\x9ei\xef)\xe4\xf0}c\x87~\xef\x1e\xf8\x0c\x03\xf2\xb3\x10|D\xb8\x86lN\xcb\xb3\xe0)\xe4\xbb\xbb\x01\x0b\x911--\xd7\xfbb\x1a\x18\xe0E\xa1\xd7_eu\xd8\x8e\x18\xb3F\x0e\xdb\xaeu\x03A\x945\x82cfi4Q\x9f\x1e\x888\xc9Hu\xd0\xafE\x11\x1cu6\x0dN\xfb\x12Ui\x8dA\xa8\x05\x0f@\xdd\xc9#6\xa4\x98j9\xcd\xd0\xa8\x9eE\x8e-Y\xfe\x85\x1c\xad\xd4\xd0\xe8?\x04\xfalxg*\xc4w\xf4V4\xfa\xb7\x9b\x99\xf7\xd9X\x06o\xf8\xd6\xe5p\xc0\xf1\xf9\xdf\x8b5T\x7f\xfd\n\xdc\x84\x10\xc3\x1e\x0e\x89aZnB\xf0!\xfbZ\x8b{\xc1\x88\xeck\xe5;\xc9\x89<2q\"\x99\xff\xed\x00\xf6\x0cr\"W<\x03Y\x87\x99\x94\xa2\x1bKs\xab\xf2*\x03\x9b\x1a\xb7%f\x0b\x9e\x85\xb0\x08\xa1\x08a\x1e\xc2\nMF\xd7h\xbdv\x03G\x10\x97Kt5T2m\x1d\xa0uYc@!\xabL\x0f\xe8!\xda\xfaI\xf9v\xfdn\x97Z\x141\xf6\xeb\xd29\xf2\x14\x9e.O\x9f\x06P]'L>\x14\xd9, \x86\xce\xb1\xd11LW\xe8\x90\xd5S(\xce\xe1\x08nx\\\x99\x93\xacNJ\xf2\xa1$\x84\xa5\x18\xbe\x11\x86\xf5,\xb50\xad\xf6\x8f\x0d\xa9\xeaWYM\xca\x19)\xea\xbcd\xc9\x86\xe9\x9b\xaa\xc8\xb3\x8a\xb4^\x15\xf8\xaa\xad\xe7b\xd9Jo4\xb22\xcbGl'\xd2\x80\xa10\xea\xd5\x8b\xa4\x9a\x95\xc9:\xc9X~\xbe\xcc\x8d{\x92\xa6~\x06+\x90n\xe9O\xd9x\x83\xdf-\x1a\x98L`\xe1\xf6m\x1bh\x13(\xdc>\xebCu\x02s\xeb\x97\xb7!\xda\xce3\xf6[\xa6\xbe9\xbd\x8e\x97KR\x06\x0e!\xf3\xa0 {h\xadKe\xb15\x86\xf2d\x8aY\"\xb2\xac~\x1bv%\x8cN\xea\x0d*\x8c\xael\x863\xa2\xb0\xe1\xac\xdd\xc0\xd6\xcf\x80\xe1\x1a\xad\xab\xbaL\n\x11\x85\x14\xedl\x06\xadcD\xb1^\x12\xe1&\xfe\xd6y\x13/\x99\xe3/\xc9\xea\x10vJJ\xc2\xda\n|\xe6\xdb\x99\xa9\xcc\xe7\x12\xc1\xcfW]\x91\xf8\x97|Y2\xf4\xd6C\x16\x9f\xaeQ|Qn\x8a\xda\xf7X\x87^\x08K\x97\x19X2\xad\x8e\xc9\xac*\xb5\x18\x96L\xaaF\xc6\x960VI\xebb\xd8\x9f\x8a\xb8\xa5\x93j\x8b\x81\xc3F\x0e\x0d\x93\xb0p\xb9X\x9e\x14V\x9d\x99\x1f\x8ce\xaa\xfe\xbdX#\xfd`\xf2A&@s2\xef\x19O\xe6\xbd\xf6\xc9\xbcg:\x99{kjSE1\x0b\xe97\xf1z\xc0+\x809d\xaf1\n\xbb\xb9\x16\xc6\xe2\x8d(Yf\xe1\xb2\x0c\xb9\x9a\x9dG\x08|\x94\x89\x1eV\xfbFX\xed\xb7a\xb5?\xc4\xc5\x80\x8a\xdb\xe4\x13\x99mj\x16rZa\xcf\x86\x891#\xc2\x04I\x8ay\xc7\x86]\x1aDB\xf0\xfa\xe7\xae\x87O{G*}\xbc\xa9H\xf9\x92\xd4\xb3\x95g\x8d\xc1&V\xd4\xca0\xb0%\x9d@9\\M\x0d\xcaeI)\xac,\xffP\xa8\xb4\xdb\x10\x12\x831\xb7\xf5\xd6\xde\xac\x1f6\xed\xb6\x9a\x1d\x1d\x94\xe6k\xbb\xe4*\xd9\x0b\xfd\xdbF\xcd\xc1\x03\n\x1c\x03\x95\xd4\x0d\xa0\xcd\xb1-\xbe\xcc\x1f\xe2\xa5\xbeV\xd2n3\x87c\xf0\xf87\x1e\x18\xcd\xa4c\x96\xec\xe7\xe0m\x03\xe4\xe7\xf9\xba\x88\xeb\xe4\"I\x93\xfa\xe6u>7\xec\xe2\x8d\xc1\xdb\x96\x96\x05\xbe3\x92\x12\xc6\xaf\x90x\xb6\x92\xdd\x06\xf4\xa8\xb0s\xfa\x8d\xb6\xdbNb\x18\xd8l$&\xc5Z\x12\xc7\xf4[\xdaO\xa3:^Vp\x0c3\xfeg\x00\x13\x98&gc\xcd\xc0[\xce\xb4G\xaa3\xad]\xbb\x8a1\x1cX`\x1c\xfc\x8f\xddF\x0c~\x06\\\x97\xcd\x00\x9e\x17\xaf\xe6\x81\x9f\xe2\xfd_n\xdb\xf0\xa2\x0c\xa3\xc6\x04bk+:W\xedn)PDv\x1b\x11\xe7\x98\xed\x8d\xc2\x18\xba%\x8a\xa0_\x86\xfd\xd2-\x12q\x9c\xfd\xd9Z\xe4\xccL\xdeE\xb1\xf9wQ\x8c\xdaLgg\x01\xd0\x7fwwCH\xa6\x9e\x07\xbb0\x83]|D\xf1\xa5\x18n\x83\xa9\xa9\x9b\xb0D\xf4\xecK\xb0M\xfb\x8aP\xcc\xa4\xa2)\xed\x8a\xa2\xa4C\x04a\xacz\x04s\x16\x8a|\xfcp\x81wK\xe5^:L{m\xeeyA+\xb7:\x9c\xd3\xde\xcc\x89\x9bAQ\xe2\xb31\x17\xc6\xba\x06\x06Z\x7f\xa9\xd66;\xfb\xcaj\xb0\x10\xea\xa8\"\xe9\xc2\xe0'\xac\xde\xb2\x1d\xf6-\x10\xd6\xf1%9aL\x0c\x1cQ\xb2\xc1\x1e=+\x92\xeaC\xbc\x94\xb4\xa1\x92\x7f5\x95\x9d\xf4Vw\xc0\xb2\xea\xf7\x1dj\xce\xd4\xe1\x1b\x9d\xf63^\xb3hMh\x80\x1a\xd9h\xe2v\x07*t8?s\xad\xd9\x85Ic`\xa2\xb5\xa5\xe1@\x96w29$\x99\xe9>KVJh\xa5r\x9a\x9f\x0d*\x9c$\x81\xab\xb47\xf4\xc0x\xb5l\x9a\x9f\x05\xd8Xs\xf8V,,\x8d\xb9i\xceMO\xf0\xebi\xa2W\xf2\x9b\xf9\x0e}\xc3q\x91T\xba`\x81=\x1b\x0d=\xe6\xffK\"\xfaV \xf8\x8f\xd9\x03nK\xd9\x9e*=K\xfa\x84Q(\xf6\xbf\xd5\x9a T\\u\xdf\x7f\x93\xda\xb0\x02\x9a%\xd1\xbalj\xd6z6\xc6}\xa5g\x89\xca\xb4\x12:\xd7CMW\x0b\x16.\x8d\x1d\x1a\xfa~\xba\xf03:\x17*\x88\xa9\x13\xdf\x9a\xa5\x19w\x07\xf6\xe4` \xce\xf1\x7f\x86\xa6\xe7\x0b\x85O\x85\xd14\x1f\n>\x89*2\xdb\x94I\x9d\x90*\x04\"\xee*0JPV\x7f\xb8)\x08{\xca\x14\x08\xcac\xc3I\xc3\xa4\xaej\xb6\"&\xd9\x8c\x89\x9c\x9a;\x11m\xed\x8a\xd7\xee\xdf\x93h\xab\xcf\x98\xdc\xcd\"\x19\xfcT\x1ax\xf2\x05\xd6\x92\xea\x0f}\xa5\x82\x81\x87\x0f\xf4\x87|~\x13\xa2\xb6\xb8\xbc\"\xa5a\xf2s\xaeP\xa6U\xfe\x1a\x97I|\x91\x12\x83S\xed\n\xab\xae\xea\xdapE\xb1\xe4R\xaeP\x93\xe8k\xdd\xb4k\xfd\xb0I\xd2\xb9\xb1\xb2\x08\xe2\xf5)J\xaa\xb7\xcfN\x0f\x03\xbf\xd6\x1c\x147\xe8\xaeO\x1b~\x0b\xc7p.\xef!\x95\x88\xe8\x86 \x83\xef\x8c\xc4bS\xa6\x13cd\xa3YI\xe6$\xab\x938\xad&\x80Z\xf6Ut\x9d\xd4\xab\xe7\xcds8\x06/\xc9f\xe9fN0\x0ca\x15\xaf\xc9}\x16C\xcc\xd0h\xe3\x08l85gy~\x89q\xdeuF\x84\xfd\xf9\xc5\xa8\xfd\x7f\xa7A[z\xb4\x07!T\xb2B\x0fS\xe1\x08*\xca\xf4\xf3\x1a\x12\xed(=7\x80\xf2\x83\\\xaa%\xa9%\x91}\x1f_\x07CQew>\xa8\x91U\x9f\xfb^\xc3\xa4P\x89'\xc3\xd0\xb1Y^\xc3\"\xdfds\x9d\xab\x10\xed\xfb5F\x9e\x94\xd4C\x0f\xbeWmm\xd3k8\x86_na\x02\xaf\xf5\xd5\x7f\xc66\x87t1o\xb0\x86\x10\xd7\xf5\xf3{\x17m\xca\x14v\x8f\x8c\xa6\xa1\x83\xaa\x01F\x93\xcc\x01\x03$\xcd0\xdeT\xb2\x8dm\xbcU\xec\xec{c\x18\x9dF'\xf1\xc6pdr\x1d\xc4\xcf}\xcc\x0cB\xd8\xc9\xa4\xa5\x8d\x88(\x10ql\x0e\xe1]\x1fr\x12joBx\xc7\xd7\x80\xa2\x17J\xc1?\x07Q\x9d\xffT\x14\xa4|\x1eW\xc4\xc7\xa08G\xb0d\xca%=~\xbc\x97*\xfej\xfa\xe6\xccT\xb3\xe4\xd8\xce7b\x14\xa3\xbb=e\xa7\x0ch\xf7\x02\x8e\xe0\x99\xe2\xa9u\xea\xbfR\xc8_\x104\xcf\xdf\xb7\x9ek\x9a{1B+'4\x8a7S\x12%\xd9\x80-ai\x89\xb3\x85\xaa\xbd\x8b|~\xe3\xc9\x18\xb2\x8ca@\xbc\x8b\xd5\xbf\xa3\xc6h_Z\xb4-;\x11\xb5\xd0:\x8a}\x94\xc5k\xfck9e\x7f\x9fQn\xce\xf0>\xc1M\x1e\xb10\xadX\x19&p\xe9\xb3\xbfCx\x11tn;D\xc2\x96\xeb\xb8\xcc|\xef\x9d\x80+\x8f\xd4\xcf\x9a\xc6p\xfdI\x05\xf1\xfa\"Yn\xf2M%\x83\xdb\xd7+\x02<\n3\xee=X\xc5\x15\xac\xf3\x92\xbe\x893\xc83\xd2(\xfa1;\x00~\x91!\xee\xf7z\x88\xb39\xbe.\xe2\xaa\"\xf3\xfbI\xa6|\x8b\xba\x8d\n\xe6 \x8b#\xc6\xfa\x848\x83?$\xd9\x1f\xd8\xdb\xc8\x0bB\x11\\\xebh8\xf6bG\xd5%u\xeb\x8a8\x86\x91\xb9\x1bsCy\xf2\x85\xbd\n\x8cCHJ2\xa7\xbfvH\x84\xb7\xe2'\xeb\xa2\xbe\xf9+3\xf9nH2\xf7\xe2|/>h&\xd8\x06\x06\x856\x9dgQ\xe6W\xc9\x9chI\xb5:\x99\xb7]L\xf3\x98;\xa8@E\x8ev\xf5M\x81\x88\xa2\xd1@\x976\xaf\x0d\xe0[@I\xa3:\x90.\xdf\xcdK\x03d\xa02\x058M\xb48\xec\x85;\xb6vqA\x84\x97\x8c+\x1c\x91!\x041\x18\x15s\x80l\xf2\xbd{\x90Y\xb4\xce%\xf9\x871\x0e\x8d(rl\xd6@h\"3\xc1p-E\xa9\xfcj\xb8\xa6\xcdz\xc4\xd9\x9c\\\xa7f\xa6\xa4\xf1\xc7\xbe\xa9\xc3/\xcc*@\x0f6u\xe8N\x9d\xa0\x9d\xf1;\xcem\xd2\x9e\xae\x9b\x9e~\x0c\xe1]\xc0\x83\xef\x9ct\x1e\x07\xe2\xcc\xc3M\xda\xb6\x80\x97\xe7a`\xf1\xbd\xa43\xfc\xa9\x9f\x8aM\xf9~l\x98/q\x9c\xc8&\x8c\xde\x18\xa0J\x96\xbb\xe0cP\xfb{\xc8\xdeb\x18\xec&goE\xca\x04M\x8b\x06l\xceoC\xfa\x99\xbe\xa7\xe6\x10~\x8ec\x82#\xf8\xa9\xbf6\xfd\x13\x9c\x0d\xee\x9d\n\xe8>\xc3\xc1\x02#\xa17\xf6\xab\xec\x7foHy\xf3\xb6|\x99\x97\xeb\xc0\x7f\x17\x84\xf0\xeew\xed>Z?m\xf7\xac\xcama#\xb20\xb9\x97\x9e\x80ng\xbbMV\x06)/\xdbo\x14K\xa7\x1b\xc5\\\x11\x02\xcd\xb5\x12'A\x15\xa4\xbc\xec$TB+\x99!\x12\xffXp\xe6\x03\x86{\x15\xdf\x02J\x92\xb6:\x84\xa9\x87<\x9e\x87\xf7\x85~\xc9\x82\xd3Rv\xf1\xc7\xfc\xbaa\x17=6\xb0\xca;\x0bD\x9c\xb7\x81f\x1cj75\xcc\x03N1n\xbb\xf9\xfd\x8c\xc7\xd94sj9\xc5fDi\x97,\xae\x14\x91\n*\xc6\x8dL\x85*\xcd@6\xa59*\xdb\xd0\x0d_!c\xe9\xe5\x01\xfc \xee#\xcf\xe6\xa7\xec&\x86\xce\xb2\x9a\xaaUL>\x93;io\xba\xb2\xa1j\xbawF\xc7'\xda\xdb;\x0b(1\x14\x8dz\xbfxM\xcfn3o9zL\xcf\x98\x87\xc7\x83_\xfc\xe9\xdfo\xcfv\x83\xdb\x07K\xd5\xcf\xe3)\x0bs\x81\x862> \x9e\x06T\xb6\xd8T+\xbf\x9c\xee\x9f\xd9}6\x0d*`?\xdd\xe6f~\x16]\x89\xfd\x85\xbcq\xf3sJ\xac\x97\xa1b\xc2\xed\xaf\x86\x8fo\xe0\xc4g\xc3\xef\xf3\xa5\x0d\x9b\xfd\xb3\xb2\x13\xc9\xfd\x17\x99\x1c\xe6\xd6\x0b\xc1[\xda\x02\x81\xd0\xa5O\xa5\x97j9\xe8\xccd\xba\xdb\xd4\xf7\xd0\xb5\xc6\xb2m\xac;\xb9\x1c\xb1\x85\xcd\xae\xef\xc2\xe2\xcb\xd6 ]\xca\x95<\xb6\x19\x93l\x8b\xdfPj\xbe\xa9-\xdf\xd0\x13\xe6\x9d\xcf\x1dLgy\x8a\xb4\xf4\x9d_\xb6\x1f\xd8F\x9b\xe0\xbe[\xe5\x15z\x1e\x96\xf8\xd7\xf0\x17\xcc\x85\x8e\x92s\x14T\x1c\xfap\xc9\xac\xcb\xf1E\x84O\xf3\xe97H\x9e\x138\x86\x9cb\xf4\xe4\x01\xe6\xd4\xf0\x13\xd8\x85\x18\x9d\xf0\x82\xe9F\xf5\x00\x84c\xd8\xb4\\\x99`b\xc8\xbaz\xeb\xa7!hr\xb2\xdf\xfa\xe8\x9bk\xa7\x15\xe3x\x8a!=8H\x8e\xc2\x85\x0b\xc8\xdb\xc7z)R\xb2XX\x8c.j\xe5\x03\xa8E\x97\xb7}oT\xf3 T\x98\xf4K\xfc`;\x0e\xfd\xad\x8cma\xf4/\x8a!1\xc3\xcd\xa4\x83\x9b\xab\xba.\x06p\x87\x19\xf4\n\xdcL\xe4_C\xf8\x96\xe27\"\xb0\xbb\xad\xf6\xcc\x82\x99]\xac\x9caz\x17>\xc9\xae\x99+\x96\xf6\x89\xf0\x1b\x17&\xc6\xf2\xbfy\xf80E\xdd\xc4n\x98e\x8di&i\xa2\xe6nU\x03\x82\x7flH\xf9\x95V\xc86{ &\xb3\x8e\xbd\x8ep|\x08\x03\xf6\x17\x87\xc0\xce>w{\xbbw\x0f\xbc\x8b'?\xbd\x7f\xf5<_\x17yF\xb2\xda\xcf4\xbe\xa7:\xcb\xea\xbc\\\xbf\x88\xeb\xf8_\x12\x00~\xc64\xc1=\x0b\x16F\xa5\xe8\xd8\x11<\xf8\x87D\x13\xfa\xcbiC\x89-a\x1ee\xa7\xe3I\x7f,\xe6o]\xb6\xab\x1ei\x1d\xfc\x05\xfe\x93\x03\x0d\xa8\xbf\xee\x9c\xc5\xe8\xcb\xf9\xf9\x90\x12P\xc4`\xd2\x8a\xc8B-\xf9\xed\xe3q\x81r\xff\x05\x08\x8e\xb9bC\xa9\xcdu\x10*QU\xdf\xa4\x03\x95P/K\xd14\x1d\xf6\xae\xe9\xabr\x86%\x18\x8c_g\x1b!8moZp\x16\x13HP?_%\xeb\x82\"\xd4\xe0\x17|J\x13\xd8\xd0ol\x990X6\xa0 \xec\xec\x1b\xab\x99$\xcb!\xfa\x9f\x0b\xd2\xaf\x0bL\xf2\x1f\xc9\x98\x99\x19\xb06K5\xcc\x88l\xfa\x91\x0e\xbcM\xc6mF=n\xdb\xa5\x04+\xd2\x99\xb6\x8b\xe2\xcd )\xde*\x86\x8d|Op\xc3\xb1\\me\xa4\xb4\x0f\nq\xca\xacY!\xdb\\$\xc5\x8c\xa9\xbc}?\xf3\x86\x0fAQ\xf8n\x19\xb5\x15E\xc1-\xe9\x98r\x95\xf7\xe3\xe8\xce\xcew\xa7\ni\xb7\x0f\xc5\xb6\xe3\x07\xf6{\x82f\xb4\xf0\xd0IP\xcd\xc6\x1dJ\xee;e\xf4\xa1\xd0\xdf\x1e\xad'\xb7}U\x0b]\xdf\xa9\xc7S(K\xe6\x8c\x12\x9e\x9a\xbf\xec\x9ad\x11\x14\xbb\xa6g\xae\xdd\x81\xeat!\xc1\xb0\xff\xa8\xe3\xe5\xac\xdf`[t\xe2\xfd\x0f\x14\xfcM\xed\xfd\x9c'\x99\xefi\x9c\x13\x95w\xd0E\xd8_]#\x9b\x0cid\xe3F#\xdb\xd5\xb9\xb2[\x90\x17I\x85\\!\x99S\xfc\x88g5;\x01\xf3P\x1f\xc3\xdeb\xb8i8_\xb5VF\xf5X/\xb0Krcc\x04\x9cTl\x16M,3\xfd\xb42D\xcc\xafk\x88\x1e\x00W\xeb\xda\xe7(\n\x87\x13\xe6\xd6\xb2Ku\xe2(\x1c\x8e\xe1h8\x8f\xa0\x7f\xe6\x88\xc2\xa2\\2\xa6\x92\xb15M\xb6\xdc\xf1{lc\xca;/7Qhrv\xc1\x81\xa4\xf1\x05I\xbb\xe3`.\xf2_e4\xd1\xe0h\xd6q]&\x9f\xbe2X\xc6&r\xe1M\xb2,2 \x1c\xd3\x83\x84\xb9\xfbQ\x06\xef)\x05U\xcdX=\x0c#2a\xaa\xce\x10\x7f\xe9\xc70\xe0\x8e\x8a``\x8a\xb4#\x9b\xa7\xbe\x90`\x13\xee\x1c\xdb\x8ccB\xfb73\x9e[\xc0\x15\x1c`\x0b\xcaBkn\x02\xc0(\xed\xb3-Q\xc43\xf2\x82\xa4\xc9:\xa9)\x93\xee4\xfd\x94O_\x99\xf8o;o\x0f\x83\x15\x18RX\x0d\xcc\xbeH\x8a\xd1\x93\x9f\xfd\xcbM\xfe3\xc6\x0eu\x9dh\xde\x0d H\xeb\xa1AE\xc7\x1d\x92\xbe}\xc2\x1c\x92\x1e\xe9\x1d\x92\x985\xf9#]~\xff\xd4i%\x05\xec&\x0f\x8e\x7f?=\xfb\xffv\xbe\xb9\xf7\x07?\xf8\xe3n\xf8\xf4\xc8\x93\xf7\x19\xdcp\xb6?\x15\x8d&~L\xa7\x0f\xfe>\x8d\xef\xffs\xef\xfe\x93\x8f\xf7\xa3\xf3\xff:\xdb\xfd\xe6A\x12\xd5\xa4\xaau,\xd7\xb6~\x01O\x0e\xf7\xb7\xb7\xd1?\xd8\xfe\xd3\xc3/0\xefo\xbd\xfa\xb7\xd4\x8a\xca\x00\xa9f\x95\xa6\xdd5\xb5\xec[ a\xcc\x9a\xc1\x84(\x96\x08\x95\x9a|(\xd8\xe6`\"\x14\xb3\xdb\xef\xa2\xef=\x8bw\xa3\x86\xcbbtR\x8c\x84\xc2\x9d\x18\xdc{\xe7\xed1\x16b\x8c\x06\xdfeLx \x80\x89F[q\xeb\xd7\xd4\x10n\xe4\n\xb3-\xdc\xbb\x07;;\x1d\xfd\xea\\D\xc8\xd2\x7f\xb8\xee\xc7\xc6\x8aC\x98z3a\xf6\xac:\xfd\xde\x9c\xb2\xf0\x00<\xb6\xcfP*)\xe5\xa6l\xd1\xbd\\]H\xe3\xb4E\xdb8\xad3\xf42P\x14\xd8W\xf4\x1f\x16\xd3\xa6s}\xd5\xc0\x0bG\xd5\xfc\x94a\x7f\x8e\xc1_il4\x06X\x13\x19\xe0&\x83$\x1bN\xde\"8\x98\xf9t(\xb6$p\xa4^O\xb3\x01{\x0f\xb4\x07\xb0\x9d\xd3R\xa1\xcb\xf3\xd6\x7f\xfel\xbb\x10\x03\x8e\xfd9zN\x0c\x9b\x9b\xb0!X\x9bCy?.\x92\xffEx4\xcc8\x00\x0f\x17\x93\xdf3\xf2\xe0\x98\xfeB8\x19\xc8\xeb\xf0$\x08\xc1c(\xd1\xab+.\xcf;\xb5\xd9\x9dp\xaf\xb6\x08\xc0\xa6\xd6\x1e\x9e\x1d\xa8>\x18\xcc/^\x8c\xde\xce\xf2\x80\x8c\x01\x1aW\xc9L\x8c\x86\x85\xccp\xfd\x1e\x14\xae \xc1@\xc1\xf6[\xcfnAuYT\xc4Uu\x9d\x97\x03a\xcatE\xc8\xb3\x8a\x7f,\x0buA\xd9\xa3\xca\x01z\xa2\xc8\xb5\x8a\x9e\xa9w\x8ep\x04\xde\x0f\x14\xfcN\xf1\xbf\xbc\xe5\x81*-R\xae>R\xa1\xe0r\xf9\xb9\x87a\xdf\xe9\x06\x8eVq\xf5\xf6:\x13'`{x\xb9-_\xb2d\xb3 \xcf)Bi\xfa\xdeS\xa8\xe1{8\xf8\xf6\xd1S\xd8\xdd\xad\x03 ,\xda&\xf3\xca\xa1t\xff{\xd8\x7fD\xb9\xb1=\xc5\xf2\xb1\xe5\x17\xd4q\x0c2\xab\xef:>:\xbeR\xb3\x8ebJ:?\xe4l\xca\xb6\xb3V\x91\x18\x8e\x00s\xce\xd5Q\x91\xc6I\xc6>\xa7\x9c\x1a\x87\xdd\xac$qM\xfcl\x93b|y\xca\x0b\x96l\xda%|/\x1d\xb8\xe8\xdc\xcb@UV\x91iy\x86\xf8\x98\xd1?\xd8\xef\xee\x92sS\xe9f\xcd1)6)\x97\xa43\xfe,\xec;\x92\xa2\xba\xb6IC\xd9\xe1\xc3\xd9\x0d\x99T\x7f \x9d\x9b\xd6\x03\x81\xd6\xed\xc6\x0e\x96\xeb\xa8\xb3\xa5E*gVDk\xfa%r\x9cS:\x1d\x83\xe8\xe5\xe7\xedE\xf8\xfc\x99\x8a(i\x9a_\xbf\x13\x18\x8c\x0fw\xcah\x16\xa7\xa9\xdfEo\xba7\x18\x11 S\x0cv\xbb\xb37b\xc3\x0fy\x809LK&\xcd\xecBLp\x87D\xbb\xfa\xbd\xa0\xcd}\xef\xdf\x8c\xcd)A'\xd0\x16\x9aS\xdc@m\xa7\xae\x95^#\xc7\xe0g}\xc1:\x0b!\xd1*\xc0\x18\x8c \xbe>\x062M\x10\x9f\x15\xad\xb6\x84\x02}\xc5k\xfc\xff\xec\xbdk\x97\x1c\xc7\x95 \xf6]\xbf\"P3KU\x0d\n\x8d\xee\x06@\x11MAt\xa3\xbb\x014\xd4\xe8n\xf6\x03 \x00a\xa0\xac\xcc\xa8\xaaDge&\xf2Q\xdd\x8d\x11\xe6\x90#\x8a\xc2\x83;\xb3\xde\x91\xa8\x91=cy\xd6$H\x00\xb3^\xdb\xeb\xb5\xd7\xf6\x8e\xf7\x1c>\xd6>Gs\xa8\x99\xbf\x80?\xb0\xfe >\x117\"2\xf3\xde\xc8\xac\x02 R\x9c\x1d\xd59\x12\x1by\xe3\x1d7\xee+\xee\xbdqFcp[\xfcSc\xeeB\x81M\xe2o(X%\xf9B\x8e\x97\xbe\x9cjS\xf7\xf8a\xda\x0e\xada4\xd6\xe1j\xd2\x1b^\xf7\xebc6ms\xc2#v\xf4\x88\x01\xe8t1bT\xde.\x01\xbe\x90\xa6\xfe \x9cDs\xd4\x18\xca\xf3\xcb\xa6\x0f\x13\xd2H\n\x88\x9d]\x0foX\x06\xc6\xd1\xc0<.$\x95F'A\xfb\x8b\x93\xaa7\xa8_\xc9\xb1X\xce.|Tf\x17f-\x946\xc0<e\xbe\x9e\x9e5_O\x7f\xc7|\x9d\x9b\x9f\x97q\xc5G\xf5\xc0\xe4\xa0\xd8\x82\x80\xb2\xb9\xf9W40\x12\xd8\x0e_\xe7gO\x96>\xcf\x9d\x9eg\xb2\xd9\xef\xb1\x97o\xb0\xa3\xe2\xcb\xfc+\xecG\xec\xe5\x13\xec%f\xea\x9c:5\x7f\xfae\xd3\xff\xa9\xef\x9c8y\xb2hb~\xfe\xa4nbn\xbe\xdc\x06\xb4\xca^b/\x9f\xb07\xddND\x0bs]\xb9\xb0/\x9f:u\xe2e)S\xcc\xcd\xce\xcb\"\x1d\xf6\xdd\xef\xb2\xb9Y\xf6#\xa6\xbe\xa0\xb5\x97; C89k\x86\xf0\n\x19\xc2\xdc<\x19C\xf3\xd0:\x0d\xac\xc2\xce\xd5\xddh\x14;ns\x14n\xf5\xcd6\x8aaQ\xefV\xdd\xc5Cd\xbdr\xa0\xe2g\x9cD\xf1\x02kE\xd5\x0c{\x96fI\xeef\x91zH\xbb\xf4\xa1\xe8\xab\x16\"4\x85b|\xdfb_VaU3/\x16C \x1bTS=\xfe\xcf\xe6g\x8f\x0f\x8a\x16\xca\xf7\xc4\xd5\xc50\x97\xb2\xad\xadsK'N\xbf\xf22J\x1f\xd3\x97i\x89\xe1m \x8a\xbd[\xe7\x96\xe6\xbes\xe2\x95ib\x8c\x88\x90\x19uY\xeb\xa8-\xf3\x04\xa5\x13jh\xcf\xd1\xcd\xc4+\xe6j'f\x1e-\xf5W\x8b\xc0a\x00f\x95\x9eo_\xf5\x0e\x02E(6P\xbe\xbdF\xb7/l\x9f\x9e\xc3a4\xbe\xfa>\x8f\xbe\x9b0W\xb5\xbd\x93n\xfdY\xe9\x04H\xef\xc8P\xbf{\x02O\xb9H\xc7\xac6/;\x9b,;\x99<\x13\x19\xf9\xf8\x1a\xe33\x03\x9e\xed\xf8#\xde\xee@\xf5\xd2\xbf\x17T\xbc\xfe\x11x\x19\xcf\xa2!Vt\xa6\xe2\xbb\xcc\xf62\x03\xe7@\xca\x9f0\xb0\x05\xf9\x97\xfcc\x9aY2\xb5\xf0A\x97\xb9\xf5t;oC\n\x97\\\x12h\xb52G,~f\xba\x02/\xf6\x0fhp\xf1\xef\xa9\xea\xfb\xd2\x80\xa0\x0b\x1e\xf1\x85\"\xa03\xe3\xe8\xd3\xd1\x01\xf3\x91\xfag\xd6\xe92\xc7\xcc\xb4\x81\x07\xa5\xb2\xe9z&#\xad\"\xe94\x13ef\xb2\xca\xbc\x083E\xbaDSm\xc9\xd0\x02`bA\xc5\x18\x14\x1c=\xda|\xe7);\xbe\x1e\xdcP,.\xb81U\x87\xba\xc8\xb4\xe9\xfeX\xad~\xa7\x7fc\xf5\xe8W4\xf1\x8d\xd4X\x96\xcaj\\\xf6\xb4\xc67M\xd2\x8c\xba\xe4s\xb5{\xde/v\x88\xc5\xd3n\x90\xdc\x9c\xfeL\x1a%Y\xbb\xd3e\xb1\xf9K\x06\xea\x95\x9e\x88\x14{\xf7=\xd8\xc3c\xc7\xeawM\x0e\x04v\x8c\xc5\xd3l\x98\xc1\x8e/\xd8\x99\x8c\xed\xbb\x1e\xdc\xe8\xb2#N\x9b_wotY&\xff?\x9c\x8c\xdbZx\xd14\xa8\x90yi\xfa\xfd\xbb\xc5\xb1\xab\xc0\xee\x96\x1c\xa6\x8c\x7fR\xde,kHu\x9c\x15Y\x17\xcfT\x1e\xce\xbaki0\xadm\xf0H\x1bH\xab\x95\xa8\x8a\xef:\xffV\xe9\xbbA\x0e\xe9\xcc\xa9;\xa9(\xfb3n\x14\xcb\xb7\xf8j\xc0\x92_I\xf1\xa8\xa0\x0c\xea!d[\x8f\xd7go<\xaf\x04\xa49%=(\xc0\x0e\xe8u\xb3\x8d}\x9e8=ka\x9f\x13/\x98\xd5\xe2Fj`H\xad\xbbK\x19o\xd8\x9e?1[1\xb4_L\xa3pS\x1cw\xfd\xa0\x9b3S\xfc\x13\xacN<^\n\xa2P>*=s\xd3\xfc\xb3*\xee\xe5\xd6%p#\xfe[G\xc8s\xa9+\xd4\x11\xa2\\&O\xa9;\xdc\xf9\x8c\xf8o\xf5@\xd9\x14\xaa\xc0*\xa9Kw\x03\xd0K\xean5\xb5\xd5\x9e.\xa7d\x02\xa2w\x0b\x17P\xd4\x1f\x8f\xab\xfcO\xc3i\xe4Mt\x97\x85\xb0q\xa6\x8cM\x8bs\x95\x93JR\xe3\xa7R ~\xd3\xd2\xcf\x91\xb9\"\xbc\xeb\x8cN|.\x1f\x98?2\xdb\xe9\xaa\x82V--a\xaf\xb1Dp\xc2\xd9.\xe3\xf2\xeeDH[l\x81\xc5\xf2\xa3\xcc\xb8\xdcR\x179\x00\xa2\xab4V\x99\x0d\xed\xe8XAE\x8b\xa5\x95\"=x\xb0{\x9e\xee7\x8a\xcd\xce\xb93\xa5\xe6\xe4\x1d\x8a:\n\x16\x9b\x9dlF\x9d\xc7\xe7jJ\x8bl\xe2T\xd6\xb7,\xa5C\xd3\xacT\xa3\x05\x8eO\xd1\x93D\xd4\x10D\x94.\xc3\x0d\x89\xad\xaa\x0c\xa1S?\x06ql\xca\x1d\xdaw@\x9a@\xe4\x11cg\x04\xf75\x88\xd81Od\x01\xb8\xc3\xb2a\x12\xed\x8b-#\xcai\xbb\xb5#\x1a0\xce\xc1\xac\xef\xf8\x01\xf7Z]\xd6\xdaY\xd9\xde\xb9\xb9\xb1\xb9\xb2\xb5\xb8\xb3\xba\xb1~\xf3\xdc\xe2\xea\xda\xcarK\xa2T\xd8e|\x82\x18\x86\x16G\xac8E\x92\xba\xcd\xad\xae]i\xc5\xab[\x88\xb7:\x0f\xecf^\xd9\xaa<\xef\xb4\xcd\xb0\x90\x18j\xeb&\xcd+h\x1e\x81g?\x8c\xe2\x1f\xca\x8bL\x9ed\x87\xccOY\x18eL\xa8\xf9Q\xbfX\xe2\x94\xa9\xa8J\xe6\x87l\xeb\xdc\xd2\xb1\x97O\xcf\xce\x8b\x05/\xd6zc\xf3\xe6\xea\xfa\xe5\xc5\xb5\xd5\xe6\xf5\xd6\xcbR%V\x95\x7fE\xca\x92\x8fT)\x8eU)m\xe6l\x03=`\x90WW2\xd0\xac\xdd:\xde\xb2\xd8>a\x17\xc8\xe7!;\xc3,\x8f\x16\x8cKv>\x0b\xb31!b\x146h\x80\x1d\xd6\x84\xe3J\xd3\xe2\xa1|\x1a\xae\x8e:\nb\xf8\xaa\xf5\xcaWl\xf9@\xda\x16\x877\x14\x95-\x11a\x08\xde.\xc7\xb3]\x1f\xdc`\xaf\xc9)\xf4\xc18\xd6\x9e\xed\xb2\xa1N\xc5z\\f\xe7\x1b\x8a\xee\xc7\xec\x18\xe4\xe2o\x8f\x98\xa1\xbc\x95\x00^\xd9\xf8aA\xb8G\x82R\x0f\x8f\x1e\xc5\xf7\xc8^\xad\x89_\xe2\xfa1@\xf4AG.\x9e\xa7\xad\xee\xd6\n\x0d\xae\x8aL\xe3\xbf\xb4\xf6\x95\xa5\xd2A\xa7\xf9H\xac\x1c\xc4\xdc\xcd\xb8\xc7\x9c\x90\xe5a\xea\x0f\x04\xba\xf7\x9c\x94\x1f\x9b\x9be\xea9d\xa6\x08\xf3\xc8\xd9\xf3\xc3\x01\xcb\x86\\6\x96\xf0>Ox\xe8r\x0f\nH\x80\xf4\xe9c<\xe0\xf2\xa8\xef\xfb\xd9P~\xbe\xc3\x93\xe8\x98h\xd6\x03\x81\xb5z\x8a6\x17w.\xdc\\][[9\xbf\xb8vsqkk\xf1\xea\xcd\xd5\xf5\xe5\x957\xd4\x99\x02\xed\x8e5\xbd\xe5W\x9d\xb2\xdc9\xb1\xa0\x7f\xfc\xc7\x83iu\x1b\xa6\x96p\xc8\xbew\x86\x8d'\xdd\xcb\xc8\x85\xae\xf2H\xf1e\xc0\xbeg6q\x021\x1fr\x19\xc6\xe1\xf7}\xbd&\xec\xd2\xee\xf6\x0e[\xdf\xd8a=\xce\x06\xd2W7a\xd9\xd0 a\xc5\xa5\xc1V\xd0'\xb5\xb8\xa9\xa0Jf\xc9\xab\x0bzyqmw\xe5\xe6\xc6\xee\xce\xcd\x8ds7\xcfn\xec\xae/oO\xbf\x96\xf2\xde \xd8\x92\xb4\xdc\xa7\xd7\xc5\xf4n\xc0\xedV\xd8e^\x97\x0d\x04\x99\xeb|\xfd<\x8b\xd5\xd1R\xfd\xb3\x08\xccE \xc3@\xb9\xc5\x1c9\xc3\x06E\xaa\x83?n\x15\xf8\xe2\xcc\xe4!\xe4\x9a\xdct\xb2a\xe1)8\x90\xa7\xbb\x113\xf0\xaa\xe5\xdf\x9cU\xab]1\xbaZ\x1e\x032Y\xc3\xa8l\x02s\x7fz\x81\xd9&\x16\x13\x07\xe1\xe6\xa5\x91\x7f\xb3\x94\xdf\xce\x05\xe5a\xa3<\xcd\xc4qq\xc2\xe2\x18l\xaf\xbc\xbe\xbb\xb2\xbe\xb4rs}c\xe7\xe6\xe2:\x10\x14\x1c\xe12-\xbb5\x9e>\xf2F\x9f\xef3\x1d\xd6\xa4\x0e\xb9\xf2\x00\xebB>Msk\x9a\xb3\xef\xb2\xf4U\x96\x1f=\xdaa\xfe\xf5\\\x86`\xcau\xba\x9e\x0bN\x05\xf7\xf7\x12R\x16\x8d\xac\xda\x8bO\x054\xbfqC\xe2 \x1bRw\x0bU\xbd\xf6\xa2^\xf4\xd3IVJ\x96rB\xa6\xba\xa9\x10&\xb5%\x1bg/\xae,\xed\xb4\x00k\xc5z\xbcJFy$\xbf\xce\xc5\x01\x9a\xb6\xdf\xafD\xa2\xab\x1f\x9eq\xbe-_\xd9\x81\x826\xe5xEa:b\x87\xa9\x86-\x0cr\x8aa)\x9f(9\x92\x82\xc4\x1d\x07\x12\xa7>\x177\x81\x8dc\xfdv\xfdX\xe5\xa9K3'Q\x1c\xbeu\xbc\xf5\xed/6\xde\xb2\x1a\xc7\xa9\x1a\xc7\xa5\x02 X\xadm\xb9\xa5\x027\xedr\x8b\xc2t\xb9\xe3\x84\xa7\xe2X\xb5U\x88\\/\xe0\x025~(F\xf5C\xe6\x84\x1e\xfb\xa1\x18\xcd\x0fK(\xd4\xa9n\xcd\xb9\xad\x8dK7\xb7V^\xdf]\xddZ\x994W#/\x98\xa9V\xd4c\xf3\xb5P+\xcd\x02\x94o\xa1\xb5Eq\xca\x99\xcb\xd2\xd3O\xdd\xf1\xbc\x1fv\xd9\x0f\xd5\xc8\xd4\"\x88\x115,\x02\xc8\x1b_\xfd*83C'\xdd\xd5\xc9n\xdaz%\xbeyK\xb1\xb4\xb8.H\xdd\xd2\xc6\xfa\xce\xe2\xea\xfa\xcd\xdd\xf5\xe5\x95s\xab\xeb\x13\x96\xc6r%Q6\xc5\xa8e\xa87cB\xa0\xb4<\xe3\x85:\xd8\x98_\x83)kxD+\xd8E 1\x1e_\xd2\x98\x94\x1d\x05\x15I\xfd\xb3y\x0f\x96\x9cP.4OdT\xb2\xa3\x16\xb7$\xe48\x99\x14f=\x9e\xfa \xf7\xa4u\xcfB\x03\xd5\xba..\x97W\xb2I\xe6\xab\xc1\xad\xb2\xe5\xc2|,\x0c\x0fM+\xed\x83W\x99\xa3\xdc\xac\xa2\xe7\x9a\xb8\x98be\xce\x8e\x9c\xa9\x10\xf33\xe6E\x1c\xf0\x91\x1f\xf8if\x99\xfd\xee\xfa\xd6\xca\xf6\xc6\xda\xe5\xc5\xb3k+\xd3\xce\x7f\n\xfaZ\x8fQ\x81\x10\x07\xdb\x16\xff}\xfdk2\xd0\xea\x1f\x18j\x81\\O\xbc\xa3\xab\xc9}.~wo\xd0c\xa3\x7fb\xaa\xd2\xeb\xbdq\xc9\xe4\x9c\x03\x99\xf9\xe2K\xec\x9a\x98\xc7\xd4\xfb&\xd9\xc3\xd4\xfb\xd6(\xd7yZ\xae\xc3;f\xf7\x8b\x93B\xd4\xf3Iq/J\xb8\xd6\xdd\x87\x1d\xd6oW\xe4\xeb\xb0\xd3\xc5\x02\xb7\xd0\x03~\xf4#\xa1\x11\xd0F\x1aL\x1e\x89L\x19\xf6\xa3\x1f\xd5\xe5\x01\xac\x84t(\xd7\xfc\xc2\xab1\x12\x82y\xd2\xe6\xd7\xa3\x1b\xd2\xb79\xd4\xc6\x9dI1\x0b\xcd\xee\x81\x926\x94\xfdn\xf1\x1a\xd7]\x81\x88\x1f\xecLm0\x99\xf9K:\xed\xca\xf7\x92\xcf\x1enF~\x98I\x0f\xfa\xc0Du\x17\xfc\xee\x0cs\xcdW\xd8\xdb3\xaco\xbel\xc9p\xbd\x04\xc7\xe7\xe2y\xe9\x0b2u\x8bb\x91\xd4A\xebM\xbe>\xc5V\xadaR\xd6\x8c\x8a\x85\x12\x13\x1c;\x81\xef9\x99\xf4\xe9\x8aK\x1f\x84\xd6\xe5}K\x15\x9b\xc6\xb3-l\xcf\xbfR\xea\xbd\xd6w\xdb\xa6h\x1dI\x94\xb72\x9f\xb9\x99\x81{\xac^\x9e\x9d\xc3\x98\xab5Y\x0de@U\xe6\x0b\xa9#\xe1.\xf7\xc7<\xe92\xf3\x96\x84L)\"x\xe2\x11|\xcc4*!\x1c\xf9BQ\x0b_(\xad\x0cM)SN'Sr\ni\xcf\xcfw*\x8ew\x96<25\xbe\x93\xf4\x909\xfd\x8c'k\x91\xe3M\x13a \xafk\x93(\xcaVC\x08\xc4>C?\xe9w\xc9\xd1\xf7\x19?\xf4\xb3\x8d\xc5<\x1bB\xb2\x98<\x1b.\xca\xde\xd2\x197\n\xfb\xfe O\xb8\x80Zj\xc6 7)\xdc\x16e*(is\xee\xf9\xa1\xd7\x86\xcb\x0f\xe94\xdeT\x0d\xf2\x1a\x9dan\xb5\x16%O\x94\xa5\xa6\x99\x93\xf1\xcd \x1f\xf8\xa15\x0eD\xfcD?u0&W_\x12\x87t\x81Ez\xb3\xeay\xb7\x03\xcb\xd2\x185\x96\xf2\x80\xbbY$Z\xb4\xbf\x0fY\x93\x95\x16r\xdd\xd4\x0ft?q\xe2E\xdd\xbf\xfdQ\xae\x89\xee!U\xdaa\xdd\x05\x0c(v\xb5\x8a\xf0\x91B\xf8\x13\xa7O\xe2\x9c\x19>\xbc<\xd4\x9e?A\xb2M:\nt\xe2\xf4)\x0c\xca\x0dH\xe6\xd90\xb0&\xb7c`C(\xdbc\xd3\xed{&\xa3J(iWQW6\xbc#\x89\xea&$\xe80\x91D*\x05@\x06\xd1\xdf\xfczX\x93K\xa2L$x9\xff\xa7M6\nj}\xaf\xa7\xcfzY\x93\xf1\xb2Y(s5\x89\xb5\x18\xdb\n\x9d\xacL;\x0c\nQ|/\x1e\x0d\xd9\xd6\xa7\x85\x16\xca\xa5\xcdR\x14\x12\xdc\xd5r\xfaMz5?\xddX\xdc>\xd1\x91 \xcd&>\xb2\xc1\x16\xd8\xf5\x96%\xd3b\xcb\x12\xa6*\xd4\x82\xbc\xdd\x11r\xc8j\xd8\xben\xd2E\xa4]v=\xbbA\xd2\xc1\xc0F\x04\xec5\xe6\xcb\x07\x99\x13\x94\n\xb3![\x99\xfd\xdc\xebdq\xb5\xae5:u\x9c\xcd\xcf\xd2F0\xc5\"8\x0b,\x98\xc9\xa2\x8b\xdb\xe8=gHS+NB#\"\xf4\xeb\x1c\x8d4U\x98\x1a\x0b\xfci\xb0\xc0\x81\xb7[j\xb1 7O ~eX \xc3\x98-X\x907aA\xca^c\xd1\xf3b\x81\x0d\xcb\xd5\x96\xa5So\x19\xfb\xa6\x89F]\xed\n-\xa5#\xca+$\x84d^r\x14d\x8e<\x00\x90Kq\xf5;\xe8+$\x1b\x9e\xc3\x11\x16\x81\x8a\x87\x98\xb7\xf2\x14\xf7\xeb!\xa7\xfa\xaf2\xa9\x97\xfeT:'kT\xca\xc9\xdae\xc1\xcc\xf6\x85\x8d+7\x17ww.\xdc\xdc\xdc\xd8\xdc\xdd\x9c\x90oY\xfb\x95e3\xb1-\x9f\x9f\x9e\xd1L\xca\xb3v+\x1dF\xfbe\x84\x17\xa8Q\xda;\xfbx\xc4P6\xb6V\xaf\xad<\xefH(B'&Op?\x89F\x17\xb7;BW&\xa5\x80\x90\x0c\xc4\x80\x8b\x1c\xc1-x8CV\xbe\xe4\xc4\x1d\x1c\xf8n\xd4%\x1ef\xc9\xe16\xbf\xdd\x9e6\xe3\xba\x96\x0dP\xbaN\xdee8\xb0U\xff\xe4,\xaf\xcf\xd6\xe46H$t\xae\x06\nIe\x159i\xc1 \x17T*\x939\xcfjl\x0c\x95T\xab2\xc7H\xe9\xa5\x1d\xbf#W,\x92[\x1c\xda\xcdG\x85\xa9\xac\x94\xdf\xd4\x9a\x97\x87\x95\xc2}\x8aq\xca\x93.\x86\xa9\xb9R\xebFC\xfca`\xaf\xab\x19\x96u\x9aLm|\xdb\xccET\x0e\xbbL\xd5ot\x9f.xe^?*H3\xb7P\xce\xa6\n\x8f\x93\xf5\xb2\xc8)?\xdaS\xf7Ls\xa7S\x1e\x96\xda\xba\x1b]\x98j[\x7f\x98\x98\x11B\x066\xc3y,\xa1\xb7\x10\xad\xa6?\x8a77\xc4\x9f\xf3/\xe6D\x86\x92Q\xdb\xcfaX\x97,\xd9\xa9\xf1u2\xe7\x10\xde\xeb!o\xfd\n\xaa\x17u \xcfH\x95\x14$z]$\xd6T\x96\xc6\x81\x15\x96\x88\xd7\xb9\xd1-\xe7\x05\xac[\xaa\xb5\x8d\xf3\x1b\xbb;/f\x81,\xc4hf\xdf\xcf\x86\x97\xf2\x0c\xaeG\xa6\xc8\xa8h\xc9\xe4\xd5\xf8\x8c+\x9f\x81\xc0\xb2\xda\x10^\x0b\x9a\xd5\x98N,\xb8\x96L^\xc0\xa5\x8d\xf5s\xab\xe7w\xb7V$/z\xde\x85l\x1a \x18\x16,\xdcG\x8d\xea\xb7+\xc0t\xc1\xf6\xb8\x04\x83\x94s\xf2\xd3E\xb3x\x90\xd4\xad\xfaO\xaf`\xa9\xe7\xa2d\x0bLY\xe0\xbe\xa4\xd2\x0f\x94\x98\xee\xd9\xc3ug\xc4S\\q'2}H\x90`\xd5a\xa9\x9a\xe5\xb8i\xdbS\xde\x0e\xdb'\x89t\x15)\x08\x95\xa1 o\xc3),D9J\xb4z\xbe8\xe2\xafDV\x1a\xab\x04B\xf5\xc7\x8a\x9a\x05\xcb\x967\xcb\xe2\x01\x19\x82\xec\x90Z\xe5\xe8\x08enr\x1f\x8a\xbc#\xd9\xa9\x83p\xa6v/'\xf7\\\xd3\xf1tb\x0b\xd2\xa2l\x0f \xb4\x8d\xec\xe4\x80\xecT\xfb\xcaQh\xe4\xa05?\xcd\x88\x90\xc5\xca\x96\x8b\xe7\x16\xb4\x18\x12\xb6\xa2\xa9\x84-fD\xaa:\x81\x8b)\x9c\xae\x17\xbaXIYt\xac\xe2c\xb9T.\xc9T\xd2\x95/%\x86\xe0\x1b\x9b\xa7\xc3vn#\xb9]\x9c\x17\x91\x92\x12\xeb\xe1o$\xa7S#@H\x11\x80\xce\xcb\x8d\xc24\n\xf8\xcc\xbe\x93\x84\xed\xd6\x95\xc5\xad\xf5\xd5\xf5\xf3\x0b\xcc>2?e\x1e\x8f\x13\xee:\xe00\xeb\xb1}?\x08X\x8f\xeb0\x1e\xed\x91\x19\xf2\x83\x8c\x8d\x9c[Q\xc2\xc6\\g\x9aB7\xe2;\xd3\x04\xbb\x11\xe7\x99\xce`,I\x98?\xa1W\x1b\x8f\xc1\xbf\xca\x9b\x039PF\xa9\xba(\xd7\x95T\xd0\xbc\x97^b\xed6\xbcp\xa1$\xe3(\xe6i\xab\xd3\x99\xd9\xe3_h%\x99\xf4~v\xa30s\xfc0U\x17N\xb2\x87T\x8bI\xdc\"w\xeb\xdf]\xe5\xc1\x98+I(\x08\xa2}\xeem\xc3\xa8\xba,\xed\xa8\xe46\x99\x84\xfb]f9\xe9\xba\x1d\x1f\x9e\n\x95\xb9\xcd\xec\xf4\xc0\xaf\xa3\x07\xddI\xa2B\xfdbh|u\x92\x81\xbc\x08L\x0b\x07\xb79V\xcd\x15f\x8a\\\x9f\xbb\xc1^\xab\xfes\xa1\xe9TMEtT\xa16\x18\xfa\n\xaec\xe7~e\xc6\xa3\xfa\xecL\x9f\x84\xdc\x1c\xf14\x1a\xf1)\xc5fSG \x1e/\xe1\x9b\x9f\xa4Y\xbb\x06G\xac\xb2t\xd3.V\xe4\xbf\xc9\xfc}\x82da3rh\xa2\x84\xb8 \x92D_$\x13\xa9\xeeg1\xa6\x06\xe2\x0b\x9b:\xe3\xa7\xe2?\x10\x1b|\xe4H\xa6\x8c\x95\xcf\xbd\xcf*\x97#2\x9b\xf2\xce\xcc\xc8\x89\xa7h\xa5\xd4\xd2\x91#!\xec\x7f\xddv\x1b\xaf\xd1#s\xb6\xad\xd7\x87\x0b\x99W\x19E\x84\x8a\xa2\xf0\xa5\x11A+F\xe5]\xff\x16\xfbFhD\xfc\x80\xbb\xb9\xf4,\xb0j!]\x95\xe5f\xfe\x94E\xd7\x90\xd6\xceH2\x88\xa4\xaa($\xcd\x8aB5^\xb8\"\xe1\x17\xe3\x99R/\xad\xa0\xb7]\xcd\xcf\x9a\x04)|\x9aj\x9f\x83\x89\x94\x1a\\\xe7\x8e\xe8\xa8\x0c\xd6\xd90\xaayr,\x97%\xa6x\xc1M,C\x968\x0d\xcf\xc9\xd6\x1f\x95\xe2\x80/(\x03\x90>\xeeb\x9f\xaa_\xd4\x89\xae\x97\x1eJ\xd4\x7f\x81%5*\x88\xdc~+hb\xfb\xe5W\xdd\xca\x1d\xe0VMS\xf6s_K\xc8x\x1b[\xa9\xac\x0d\x80\x93_\xcd\x1by\xb0\xa3\x0b\xcc\xb1\x83K\x0f\xde\xd4\xd8(\xcb\xaf\xe6X^\xbf\x95rJ\x1d-\xfa\x86P\x89/\xe3\xf1\xd2\x0f\xebnB\xd3\xa1\x94\xd8Vn\xe7N\xf0}~\x08(\x86\xbe\xd1\xf5\xaa[*j?\x917G\xdf\x80\x15\xa4#K\xdba\xfb$y\xe7:2>\x16\x13\xfd\x8dj\x05I>\xd3\xb7\x10\x16{\x82\x02\xf1\xf3\xa2\xfd0\x98\xd2\x1d\x89Y\xc8emj\n\xfd+\xf4D\x9e$\xea\x02\xb9Y]aZQ\x9at\x8d\x8c\x7f\x8e\xa94u?\x10\xf8Tp\xfb\xc95\x02I\x9f\xfb\xa0\xc4v\xcc\xddv6\x93 ~'\xf4\x8a< \xda\x9d\"\x93\xbf.\xb6\x9b\x04u6\n\xfdk\x1e\xbbL\x14#8\xac\xea\xa2[7\xc6\x00\xfe ,\xdc\x0d\xb8\x934\xbc\x8d\xa1\x7f\xcf\x83dB\xfe\x0f\xa6h3O\x82\x05[\x9e\x16\xfc\x13\x03\xde\x96^\xd1G\x1a\x1e<\xd4?\xf5 \xe9j\x98\xf1\xc4\xe5q\x16%\x0b2=\x0f\xfe*\x96j:\xf9\xb5\xfc#w\x8du\xbf\x1a\xef\xee\xf2/\xe1i\x1c\x85)'C%\x9f\x7f\xfbcu\x13\xee\xf10\xf3\x9d ]`\xad\xd4\x19qEg\x1b\xe2\xe0\xf4O\x91\xb7&\xa7\xf6\xf2OP\xc98[\xa8\xbe\xe2y+\x8d\xc2\xee\x1f\x1c\xff\x83\xc9\xe4\xad\xf9\x94\xdc\xed\xccdC\x1e\xb6\xfb]\xd6o\xb8$\xb0Bj\x96\xc9r\xc8\xa6\xd5\x8c\xb4@x\x1d\xa2\x1d\xcc\xd1\xec\xb2V\x11*\xa4i\x8a\xf9\x08zG\xab\xe1\x0d\xf4\xaa\x1553&Nx\\N\xdf\x01r\x95\x11G\xfcg\x01\xc4p)\x90Ws h\xdf\xa8\x92\x1d6\xebLdT\xd9a,\xa8\x85\x90\xb5n\xc2\x02\xddT\x93\xbb B\xf8\x04\xbcQ\xae#\xb6\x04n\xfaW\xb3I\xe4\xab\xcd\xff\xb9V\xb7\x0d\xaa\xdbh7\xe3N\xb7\xb9\xc6)\xa2\xce\x8c_\xfe\xddm\xb2\x0c\x97\x7fU+qe\xb8pc@\xcc\xd4\xfag\xbb\xd9\xb0\xda5i\xe7\xd3\x04\xd8L\x8a[113\x8d\xd9!u\x10N3v\xd5\xa3\xd5B\xb3\x0d\xd8\xf6S\xb3\xb6\xbc.g<\x98 \xd1)]\xf0nQD\xe6;m&=\xf5\x98\xdc`\xed,\xa2\x88j\x1e\xa0\xa2\x9b\xfa-\xfb\xbf\x90\xb5k\x82\xe7O\xf5\xab \xca\x99\x9f:&\xe7\xab\xf2 \xfa\xed\xda\xe5\xbe\xace\xf3\x85\x9e\xa4\x1a\xf32\xab\xe2M\xdf\x8e7\xf6\xba\xea\xdai\xbaH\xb9t\xe6EG\xca}\xe9x6j7u\xdba\xfb\xf4 \x12\x9c\xa6\xee\xa8N\x9c\xb0\\R\xc9\x00NZ\xc5Q\xa0\x93\xb3\xb3\xb6P\x04\x00\x11\x0bm\xaa\xc6pr\xb6\xe6\xecXB\xb9\xfe\xe9\xc5\xb3}\xcd\x01\x18c\x95T\xb2\xda\xc8\x80gk\x91\xeb\x04 `-4\x9b\x03\xb5\xf7\x834K\xc4N\x92\xf2\xab\xceHU\xed\xb4\x0bi\xa9q,\xbf}bf\xec\xd8g\x0fw\x130Tk\xfb>|op6\x85\xf3S\xb9v\xc0U'^w7_\xa2\x96\x169\x9b\xe9\x87`C\xef`E\xb9\xee\"^O\xe9\xb9\\#\xac\x06*}\x99[\xb9*\xa0\xf2\xb7<\xb7\xe6\x9cFh9\xda\\)\x1f~\x97\xf96\x03\xbf9\x0d~\xfd\x1dIh5\xe2\x87U#>{\x8d\xb5\xa3&\xfb\xbdR!:\x02w\x9f\xab\xd8n\x12\xb4[\xe2CU\x89\x08KV\xfd\xc2\xa8?\x93'\x81@2x\x81]HH\x99\x8a\x84#\xe7%\x04\x03\x89ED\xfd\x06\x9f\x9f2\xe6\x0fx6%\xa6q\x15\x0d\x83\xdf\xdf\x94\xf6\xfc\x05\x19J\xf8\x0d\x9d\xa5v\xef\xe8*\xe1q\xde\xf6\xda\x9f\xf4\xf0\xf0\xbf\xbc\x87\x07e\xb0u\xb1~\x82U\xdb\xef>e\x00\x91\x8e\xad+\xc5sE]\x96\xce\xecn./\xee\xac\xdc\x84\xd8\x86\xed A\x0df\xef\xe0\xb9\xf1j\xb4J\xa1\x04\xd0P\n\xdc\xeb\xce\xc6\xf9\xf3k\xd3\xf6\xfa\\1)8U\x89\x19\xb2\x8a\x05;\x82\x02=\xa2o\xc2=\xf7\xf3\xc9\xd3\xd7\x0d[\xb5\xd9\x1f\xa6\x91\xad\xa7\x90o+ \x16\xea\x8b1e-\xe0\xf8\x15\x8d\xe7\xd09\x9f\xfb\xbe\x91C&\x1b\x95c\xb4[xtNa\xb2f%\x84\xda\xf7C/\xda/.3\x86NZ\x93\x00\x0d\xff\xb2\x99\xc09\x8c\xf2L\xc7uKJ\xbe\xccy\xbc\xe6\x87{\x17\x9ct8\xcd\xfd\xd2\x04\x1b]-\xf4K\x98|\xc4\xae\x9a\xfc\xb6\xb5\x1b[\xf2\xcc\x99\x90\x06\xc4$\x1d\xdaq\x06\x0b\x85\xbb\x10\x1dJ\xe5\xcb\xdd\"\xd1\xacEUq\xa4\x9a`UU\x00\xf4\xb2-|\x07@\xdf\xb1+\x17\xce\xd7'W\xff\xf6 \x89\xbc\xcc\xd8v\x93(\x08v\xc0\xf5.U\xffPw\xe0\xf2[\xc2\x1d\xefp'\x82r\x8a\xb8\"\x1c\xae\xd45!X\xcd\x0e\x8f\xfd\xda\xb8\xf6\xbe5\xf2\n\x0c-'g\xb1\x97d\xaej\x9c>AR\xa34\x86\xb6c\xde(\xdf\xa0l\x07V\xac\xe8\x7f}X\xc1\xd4*\xc5\xe5e\x9cH/\x0b\xc67\xc9\xcf\x06\x9c5\x81&5\xc4\xbdLKp+\xef\xf8c\x0f{\xd8h-\xafU\xde\xc2\xcfT\xee\xe3\x08r\x1f\x17\x9e\xf6y\x8d\x99\x1e\xb2*V\xa9y\xd4\xe9\xb2\xb0\xdd\x91\x8f0\nT\xf4\xc3Ag\x8aG`\xc5\xfeG\x13#D\\Yj\xae\xe1\xd6 0O@k\xa14\x10Bi \x84\xd2\xa0\xa1\x9eV\xa6\x13!\xef\x8b\xe3#+\x9fK\xa2\xd1j\xba=\x8c\xf6\xc3\xef\xf3C\x89\x88u\x0d\xc8\xdca}\xf4:ls\x7f1\x8d&\xeeO\x8e\xa5\xf1\xd8\x19\x16O\\\xa9\xa1,\xd5\xb4Rr\xc0n\xa7\xac\x9e:B\xcc\x12\x93\xef\xc8\xa4\xa2\xf5u\xe7\xe5\x9d\x8cyX\xf65\\\xbb-\xe3\xd0\xe1\xcaA\xd3\xa4M'\x83v\xd9Q\xe6Iw\x16\xf1\xd7P\xaaTs\xd5\xf6^z\xe9\xb9\x1b\xac\x8b\x84\x98\xea.\xbe\xaa\x07N\xff\xb2Z\x95hT7\xc4\xc3\xf4\xb7\xf9j\xa4\xd6\xd8\xca\x8a\x8b( \x107\xa1\xcd\x9bYTs\xfdd\xae\x9dp\x1eIE\x06\xafs\xfaTW\xe3T\x86\xb5\x0cf\xaa95[GX\x85RV\xe4\xb2z\x0c\x9f\x92`2\x85\xe6`z)\xa8p\xa7J\x9f$\xbbh\xc2\x8f\xb1\xc9\x06\x04\x0f\x90\xcc5\x1c\x8d\xd6\x11\xf08\x13\xc4\x8c\xe9\xcc\xf9\x91\xa9\xd8\xe9J\xc4o*\xd1L4|\x9c\xf9w\xfah\x12\xfd\xd3'\x9e\xebwhT\xba\xdd\xf6\xf1\x9b\xc7\x07]\xd6b\xad >\x1c\x13(\x94#\xe9\xa8o\xe8\xa6\xa0\xa2\xbb%\xaa\xda\xf6\x1b\xe6\x18J\xfe\xdav\xba\xf0\xdc@h\x8eP\xdby!\xe7rl\x95\x9f&2\xf3\xa9,l\xac\xe2\xf7\x8b\xd0S\xe0\x9f\x96\xeb\x043\xa9Y\x03\xd7xi\xf9i;\x01\xfd;0Z:\xef\x80\xe1:D\x1a\x0c\x92\x11%g\xc7e*\x92\xa5-t\xacq\xddF5\xb2\xe8\x8b[\xb9f!A\xca\xbd`&\xec\x87\xc5Zn:\x89\x98/\x17\x92\x8cY9u\xd7-\x0b\xc8G\x1eg\xb2\xa8\x96\xac\xff\xd68\xc4@\xae(\x96\xf7\xa7\xb1\xd7O\xc3%d\xbb\x8aWP\x87\x1340\xbb\xe5\xa9\xda\x8d=\x9e\x01m\xc4\x94f\x04M\xf0\x8d\x97\xaf\xfeC\xe1U3\xe5\x97\x84|\x14\xe7\x19\xf7\xb6\xb3\xc3@\xe6#\xae\xad \xd6\xb4\xe5\xf4\xd2(\xc83\x95S;\x99\x89\xa3T\xc6\xea\xd4W\x93\xf1\xf7\xec5v\xbc\xed\xe4Y\xf4#X\xc7\x1f\x0d}\xcf\xe3a\xe78[\xa8\x02:\xc7\xeb\x99O\xab\xef\x1fp\x0f\xf7\\\xbc\x90f\xafidx\x99^\xf0U\xf9\x1fG\xf0\xe0b\x91^\xad\xa7\xd221\xbdm\xa5\x9cN\x97\xb5\x8f\xc8wTZi\xe6d\xbe\x0b\xae\xd3\xe5\x81\xbd\xf4\x12\xf3eZ\xe0v2\x13\x8dy\xd2\x0f\xa2}v\x94\x15\xff\xb8Z\xf9\xd7\x1b\x9d\xc2\xdd\xde>\x17=\xd3IX\x88\x14\xc5 \x960\xc0\xf3\xdaT\xa9\x93\x8d_\x88\x96-\xb0\x86D\xe7\xba\xec\x02\xab\x89q\x13\xbf\xcaQ^`\x83\x06,.\xb3\x9f\x056\xae/I\xa4\xae\x056\xb4\x13\x1f{\x1b\xa5{\xe9\xfa\x95\xa8r\xa6i\x1d\xbf\x18\xc3\x9e\xccM\xef$\xf5UZ\xac\xed\x01\xb4_\xd4{\xa44\x8b&\xa9\x1e^;\xf1\xbb,\xb7SgDX\xb2\xa1\x9fvY\x9d]\xd5\x08\xc1\xa9\xd5\x90\xed\x1aCv\xda\xe9J\xeb\xed\xec\xab\xac\x0f\x8f\xf8\xf5\x8f\x1e\xed0\xf7z\xbfj\xc8\xee7\xbf\x16/\xd8\x9cO3\xa7\xc2 \xe5\xbb\x83\xc1\xcc\xcd\x9b\xd2\xb9\xec\xe6M\xed\x12]\xf2)\x0f:\x1d\xe9a\xa6L\xe2\xbc\xcb\xae\x8b\xba&\xc9\xb2\xdb\xe9\xc8\xf0\x99(\\\x8b\x1co\xa2\xfdL\xff4\x07\xf6g\xe2$\x8a\xd3\"\x93\xc2L\x16\xc1\xc1j\xca5\xc0\x14\x17F\x92G8\x939\x83\xae|\x04U}]\xf5\x1a8*\xbe2\xadH\xb0\x82?\xd4\xe9\xc4p\xc3\x10\x12G\x02{V\"J\x96K\xe6\xe9\xbc\xb4\xd2\xf06<\x92I\x82.\xaby\xf6hO\x88=\xad\x84\x87\x1eOj\xcc\xa6\x8a\xdaL\xbc]a\xc5\xa0Rdq0Q\xaai\xec\x84\x84\x9c\xd1F\xfa\x0b\xf0\x9c\x04\xe0Cm\xe1\xbb\xdd\xda\x9e\xb8z\x90B\"F\x1d?\xa7\xab|\xa3\xd3E)\x19\xee\xb6\x8b.\xcc\x15\xf37\xda\x87\xe7\x1bG\xfaCi\x176\xff\xfc\x1d\xd9/\xfd~G\xf6\xbf8\xd9\xb7\xe8\x85\x9a\x13d\xce\xe0\x0b\xd3\xec\xf0w4\xfbw4\xfb\xab\xa6\xd9\xcf\xe7\x1ag!?\xb5It\xa28='\x13\xb2=\x87\xe3R10\xc4Kt\xba\xaf\x93\xb3\xa7-L\xe3E\xe5\xfb\xfa\xe6\xeeG\xa3\xb7(\xc9{gy/\xa5TA\xbe\xd5~\x86\x85&`\x13\x87\x0f\xfc\x97\x85\xa1\x93\xcc\xd4l\x8a`\xa8)\xed\x19\xcc\x04\xeaB$\xf9tlD\xff\xa6\xf5\x1e\xc2?U/\x91\x0f\xc0w\x1b\xbc7'\xb6f7\x9a\x19h\xb3\n\x03\x13\xbf\x98F!\x9e\xfc\x146L\xf6%\xe6os\xe3jwf\xa2P\x90\xdc\x80g\x96G!m?\xb3\x8c/\xbd\xc4Zz\x10\xe5@\xcdP^\xec\xa6<\xdb\xf1G<\xca\xa5\xbb3<\xb8\x7f\x86\x1d\x99\xeb|\x95+_\x0b\xad1s\x92\xaf\xd3\xd2Y9\x15\xeb\xa1/\xefF\xf9\xbd\xc6\x96\xe7d\xce\x82?r\x06\xfcx:\x1e\x1c=\x18\x05\xaf\xf6\x9c\x94\xbf|\xb2\xbbya}\xfe\xda\xe1\xd9\x13\xce\x95\xadYgy\xd6\xbftkq\xdf\xbd0\xf0W\x97\xceF\xd7\xae\x04\xa1s\xe1\xf5\xd3\xab\xb7V\xf7/]8{r\xd5_\x1c\xf0\xf3si/\xbctzu4\x9c\xf5.,\xbe\xbcvx\xfa\x84w\xc2\xcd\xbd;\x97\xf2\xde\x89\x8b\xe1\xda\x9d\xd5\xfdK\xcb\x8bc\xf7\xc4\xb5p\xd5?;\xef\\\xb9|\xe2\xf5\xd1\xe9\x93\x9b\xdb\xab\xfb\xab\xcb\x8b\x83K;\x8b\xfb\xab\xcb+\xfb\x97\x96V\x07\xee\x85\x8b\x81;\x7f\xf9\xd0\x1b]>\xeb\x9e8\x1b\\=\xb1\xb5}\xf5\x8d\xad\xb8wg\xd6\xe7+s\xf1\xb5s\xc1\xbas\xe5u\x7f\xf5\xfczz\xf5\x8d\xf5;\x9b\xdb\x17\xd3k\x17.e\xee\xe8t\xda;\x1f\xe4\xd7\x0eW\x07\xee\x89\xadS\xbd\xf3\xbb\xa7WG\x17\x87W\xe7\xb3\xd0\x1d\x9d\x9e\xeb\x8d^\xcf\x9c+s\xc3k\xf3\xbb/\xaf\x9e?5\xee\x8dv\xbf\xb3z\xbe\nw\xcf\x9f\xbe\xe3\x88\xbe\xe6O\xbe\xbcz>\xc8\xc5\xdfW\xaf\xec\x0f\x9c+\xa7b\xef|0\xec-\xa7\x83\xab\xa3s\xb7\x9cy\xef\xb0w\xe2r~mi\xee\xf0\xda\x1bg\x83\xabo\xbc^W\xde\xdf\xbcup\xcby\xe3\xe2\xad\xde\xf9\xdd\xc1\xd5\x13\x83\xd3\xab\xb7v\xf7W\xfd\xb3\xb7\xf8\xce\xac\xbf\xbe\xb3\xe8\xaf\x9e\xbf\x16\xf7\xce\xef\x9f^\x1d\xc91\xf9\xab\xe7O\x85kW\xce\xcdz\x17V3\xf7\xc4\xd6ao>\x0b6\xb7/~\x87\xcf\xaf\x8f{\xa3k\xf1\xb5\xc3S\xb7z\xf3\x07c7\x9c;\xbd\xea\x9f\xcd\xaf\x1d\xce\x0d\xbd\x0b[\x87ko\xac\xcf\xba\xa3\xd3\xc9\xb5\xed9\xb3o\xfcDv\xab7\x7fj\xe4\\qso>\xd8\xf3\xce\x0fO\xf7\xb7W\x07\xbd\x91\x9b]}ck\xd6\xf5\xe7\x0eQ\xdb\x87W\xafl\xc5\xde\x1b\xeb\xb8\xdc\x1d\xef\xc2\xc5\xb13\xbf\x9b];\x7f\xee\x8es\xfe\xdc\xa1;:w\n\xd5\xdd\xbb\xfa\xc6zt\xf5\x8d\x8b\x87W\xdf\x08d\xfdb\xfc\xab\xb7\xd6wv\xe7\xc4\xffV\xfd\xb3\xa6-\x18\x93X\x93\x15\xb1&\x87\x9b\xdb\xabw\xd6K\xf5\xd6\xael\x0d\xdd\xf9\xe1\xd0\x0d/\x0e\xc5z]\xda\xb9:\xbbvk\xef\xce\xa5;W\x0f\xd6\x97/\x1d\\\xba\xf3\xfa\xfc\xfa\xf2\xca\xdc\xea\xf2\xee\xfc\xda\xad\xbd\x13\xebw\x06'.\xed\xbc~g\xfd\xce\xe0\xf0\xd2\xce\xa5\x93\xab\xb7N\xber\xf5\xca\xa9\xb8w\xe5\xdc\xec\xb5\xcb[\x87W\xaf\x9c\xbasmt\xfa\xb0\xb7}V\xae\x99s\xe5\xe2\x9cw\xfe\xf2\xc6\xd5+sb\x8dg\xdd\xd1\xb9\xdc\x9d\xbf6vG\xb3\xfe\xea\x85\xadS\xae\xc0\xa1\xf0\xe2\xd8;\x7fn\xf6\xda\xf6\xea\xe0\xea\xfc\xb9\xf4\xea\xec\xdc\xf8\x9a\xc4\xad\x83\xb87\xbau\xf9|\x90]{\xe3\xd2\xe9\xd5[\x8b\xdf\xb9\xb4\xbd:\xb8v\xe1\xb2\x98\xf3\x81{\xb8:\xb8:\xba\x1c:WN\x9e^\xbdu\xf6\x8eX\x0b\xc0\xab\xade\x81g\xde\xf2\xac\xef\\9\xb5w\xed\xca\xb5\xb87\n\xc4X\x8en.\x9d\x1e\xf6F\x81\xd8\x9f\xe0\xf2\x85\x8b\xc3^\xb8>\xea\x9d\xb8\x98m\xde\xda\x1f_\x9d\x0f\x0e\xaf\xce\x1f\x04\xe2oq\xe66\x07\xd1\x99\xd67D\"X\x8a\x82\xc0\x89Sx\xbab\xcd\x0f\xf7\xe4\x1f\xe0\xcb#\xff\\\x0d\xe3\x1c\xfe\xda\xe1\x07\xd9b\xc2!\x0d\xea\xd9<\xcb\"\xe0\x16[\xd2KX6\xa5\xfe+\xb3}\xcb\xb7{\xeb\x82\x11\xa5\xff51Ch\xcf\xecW\xac\xafS\xf6mF\x10G7f3i\xf4mF\x90T\x01H\xef\x81\x02\x10#\x88\xab\x00\x15#\x88\xf4\x13\xb7\x9b\xbf\xbf&\x87m\xdaqLx\xbd\xb10p\xab\x85!3\x16\x06\xae^L\x98}\x95\x85\xec\xbb\x8c\xbf\xca\xc2\xa3G;L\xc5\x0d\x17\x16\x86\x10\xa9\xe1jb\xd9tI\xa3U\xe9#G\xd0\xac:3\xb7\"?l\xb7X\xab3\x93%\xfe\xa8\x8dEg&\xb5\xfc2f\xd5wd\x96#\x9b\x14\nLl \x99R\xdbSb\x1c\xc9\xa8a\xa4|G\xdc\xe9(\x99\x05\x8a\x17\x12K]\xec+\x1aIPj\x0b\x9e\xdfE6\x85\xccj=\x98`9\x98\xd6j\xa0\x11\xa4\xd0\xd6\xebET\x95\x834\x0f\x82\xd4M\xb8\xed\x81)\xfd\x0bM\xc9\xfa2\x96\\q\xbc\xcb\xae\xb7\x8a\xf6e&\x9d<\x08j\xdf\x1e\x93\xc9\xec\x8cg\x8e[k\xf5\xe0 \x88B4\xaf\xad!\xed\x84\xd4J\xf7\x9d\xc1\x80'\xc7\\\x8dn2\xabN\xc8^c\xadcr(l\x81\xb5\xea\xbc\xc6\xa7\x1fG\x9b>3\xe97\x99e\xdc\xc0I\xd3u\xf9XZ\xdc\xf6g\xcc?+\xafj\x95\x7fw'\xbb>\xde\xe8Tb\xfd\xdb\xae\xc5\xceR\xa5\xde\x1e\xf1\x97\x1bE=?\xe0bI\xaa\xfb\x9c9\xbd\x80g\x0b\xacu\x0c\xfeB`\x8f\xa7{Y\x14\x0b\xb8\xfa\x13\x15\x08\x9cd \x9a=6\xf4JW\xb3\xafV\xe8A\xf0;J\x00\xbf\xdf\x1a%\x18\xfa^CV8\xa0\x01{\x9c\xc7K\x90\x8d\xb3\xa1=I\x0b\xf8\x0c\xa0\x93\xd0\x02\x01m\xba\xd2\x9bB\"\x88\xf8Sb\x05\xf1\xdb\x90DC\x0cE\x90\x8brw\xe2\xdf\xd0\xa2|\xabQ!\"k\x19\x94c-\xd9b\x8b< k\x86%\x93\xf1\xbe\xf4\x12;\x12NAe\xc0\xb6*C\xe8\x9b\xa9\xcc\xf5\x1a{\xb6\xe1\xd89\xf3C\xe65\xbb>z(\xedG;\xefL\xd2\xf6\xf5u\x83W\x1b\xec\xa4\x7f\xa2\x83\x1c\x1e\x0d2F\xdc)L :\xc8\xa9\xa85\xb1'\xa6z\x0b\xd8w\xd9\xdc4}0\x99\xd4Q\xbe\xe5\xd2\n\xa3\x90\x0b\x02=mT\xad\xa0\xea~\x98O\x91hob =\x84^\x10\xb9{0\x86\xae\xf9\xe8F\xc11\xf9(\xa5\xfc\xde\xd8\xd6\xf3\xda%t\x0cW\x8c\x0c%\xd7K\\\xc1\\\xca8u\x88=\x11\x97\xbf0\xa7J\xb3\xc3\xa0\xf6yl\xfd\xf3\xfc4\x0e\x9c\xc3\x05\xe9}\xacv\xd1\xf2nG\xf9\xd7`9+1\xc7\x9a\x14J/\x86\x19v\x8d\xc2\xf3;\xb6\xf3\xe2\xd8\xce$T\xf4\xfc\xb1\x1d\x0dK|jZ\xc9\xa9\xa8R\x16\xa1Z\xfb\x89\x13\xc7<\xa9u\xd2{!\xd8S\x1c\xc4vI\x85\xfe\x1d&}}\x98\xd4\x93\x8b\xfeU#\x93\xea\xe5+\xc5\xa5\x8e\xfe&\x98?\xcd\x91Y\x1af\xabF|.\x19t\xeaQp\xd2\x82f\xfc s\x12\xee\xb4*\xb7\xec2\xb5\x936\x1d}\xf1\xc6}\xd1\x02j\xb9r\x86\x8c\xa1j\xaa3Tw\xa1Ws\x80(\xdb\xd4\xe6\xab/z\xb0dV6(-\xc7b\xe9b\x08\x85lo\x81\xeb\xe8\xcc\xba\x17 \xd4jB\x00\xa7<02\x15&\xfc\xb5\xc0\xf8\xcc(\x0f2?\x96V\xa7\xeb\xad\x96\xf4\x0bo\x89S \xaf\xf6j\xb3\xac\xaa\xa3\x17Q\xa4\xedZ/~\xf5\xef\x1bC\x13\x9e_\xa9Q\x0f\x0d^\x16\x1d4\x14\x06\xedF\xafj}\xb9\xa4hte\x14g\x87\xb2\xdd\xfa\xe2\x91\x1e\xab\xdc\x17\xd8?\xf9<\x12{\xcd\xfe\xbd-\xb3u!\xc8\x17\x15\xfa\xc4\x81jt\x0f)Q\x16+\xf9\xab\xad\xa8\x17\xaa1\xab\xac\xc6\xb6\x86\xe5 \x97\x86N8\xe0\xc6?\x05\xfei-/P\x94\xbdV?\xdd(V\"n\xfdt\xd5\x80Z\xf6d\xd6w\xbb\xacu\xecX\xab\xa3DWA\xf6\xaaq\xca\xd3\x054|\x99\x012}R\x1a\xa2 Y1\x91m\x999\xb7)}\xfd\xddnQ\xe8\xb7\xc9\xc2\n|92\x87\xac\xfe\xd5\xa3T\xbd\xd7\xa8\xda\xab\x86\x93BM\xcb\xd4\x81\x9e\x99\n\x8a\x95\x9b\x9a\x18\xf2\xc9'\x91\x1a\x08\x9e\xd6m7\x93\x83p\n*\xe3K\xab\x02\x84\xd7+N3\x939\xc9\x80g3\x80Ei\x83\xf3\xb43\xe1\xa5\x1b\x01\x8f\xd8k\xcc\x9f\xce\xd0\xaf\x7f\xc6\xb7\x06\xe8\n\xb7\xfb\x91\xdd}\x9e\xe0~\xd3\xa4\xc4\xe7\x9a\xf6\x04=\xd4\x93\x97\xe5\xba\x103\x04\x81!\x13\x0f\xbbS\xd3l\x17\xdc\x1a\x12[\x88>\xc2\xff\xeaR\x8f\x85\xd0`.\xd8\x9a':A\xe8g\xbfe\xc1\x9f\x91\xb9\xb2\x17\xc2\xec\xd9d\x86\xcf\x9e\x83\xe9\xb3)\x88\xab\xf3e\xf4\x00\xe8 X`\xad0\x8ab\x1e\xf2\x84\x85Q\xc2\xfb\x9fCe\xd5e\xb0\xce\xb6\xd1\x8c\x98c\xf3\x04\x9d;\xf4\x03/\xe1\x96\x90\xeeIK\x0e\x9a\xbc}U'\x9a\x8d\x86\xdc\x1f\x0c\xe5c\x13ymR\x18\xf1\xebE\x89\xc7\x93\x05eUj\x10H\x9cd\xe0\x87\x0b\xac\xe1\xa1\x92\xd8\xf1\x95\xfa\xf2O\xc9\x04\xb0\x1ee\x8b\xa1?r2\xee} \xc9_\xdfN\x17'\xccO7\xc4Y\xf5\x1a\x84\xc2\xb1\x8e\x19,\x1fL\x85\xf0\x82\xb1\xd4\xe2v\x18\xa5n\xe2\xc7\x99\xbe\x00\x98@6\xef\xda\xce\xc1oO\xe5Q\xab=I\xdb\xd1\x0b8I\xdb\xa9'\x11\xac\xb41\xec5p:\x0e\x95\x8f1,\xfc\xc4\x9dI:F\xe3!\xe8by\xb3\xe3\xc5\x8b\xa6z\x15,\xa2\xa9\x1a\xc6\x82v\x00d\xec\x9b\xe1\xffK\x9dp\xbcZ'\x1c\xcf\xe6j\xe3\xeb*6\x1f\x1c\xcf\xe6j\x93+\x8057\xa2gs\xb5 \x14\x80\xe4\xecw\x15\xe0\xf4+\xa71\xa8\xaf@sd`\xb1\x86\xd8\xfdt\xbc\xaf\xc7OG\xffE\xb4\x91\xe7\xa5\xf5E\xfcQ\xd2\xb5\xa5 \xc1d\xbc\xd6\x8c5!\xee(\xa8\xc4\x1d\xb9\xe0\x15\xe4B\xdc\x91{\xf4h\x87\x05\xd7\xdd\xaaW\x90k\xb9\xe0SK)\xa8\x866\x99\xe5\x84\x11\x81\xdf\x19aF\x115\x9b\xd5\xc5\x1c\x052\xe6(\x99\x19\xf0\xecR\xe4\xf1@HO\x13E\xec\xd2\xf8\x94\x17?7^\xfc\xad\xdf;^z\x15\xfbxKf\x93+2\x87\xfd\xe1\xcc\x1f\xfc\xde\x0f\xca%~p\xfcx\x97\xb5\xa4\x05\xc0\xd6\x96k\xd2\xd8\x1eO\xdd!\x1f9\xa4\xc9\x9aB\xbaQ\xd0\xca\xc8\x14\xee\xaaIo\xf1\xfe\xb6\xac\xf2<\x93N\x14[\xab\xbc\xbf;\xd3\xf7C\xafx\xde\xdbf!\xb8\xdb\x85\x9c\x14\x84\xa1'\xc4 \xa5V8H\xad\xc2\x81\xf3<\xc2\xc1\xd7\xca\x18Uj!\xb9=\xcdJ:\x9f\x98\xff\x94)2\xca\xa7}\xf9\xd8\x81\xc2r\x83\xebK\xe5\xb2T\xc2o\xe7~\xd2\xc4\x99SY.l4\xd2\xb9\x8a\xcbo\xf1~}\xa1\xbe\x99\xc3f\xeds\xf9L\x11`>\xa3nz\x9b\x8d\x832\x8dd\xbb\x05\xecN\x9e\xe4V\x83\xb9b\x08\xa5%\x95\x9aXx\x0c\x857\x13\x7f\xe4g\xfe\x98O\xac0bgX+\x92#i\xd0\x1e\x06\x82\x04\xc2\xab\x902)\xd0\xef\xff~\xc2\xfbuna2 \xa9|\xccx\x00\xe1\x0f\x1a\x07\xcbt\xab=\x10\xb4\xec\x88S\x14sJ\xc5\xccIo\xa7P\xcc\xb8\xa3\x04\xb5\xd6\xdcI\xa1~\xe5[\xa2\x91\x18\x06\x93\xff\x7f,\xf3\xb3\x80\xd7Z<_`\x7f\xd0\xd3\xcd\x9b\x19?\xc8j\xfb\x8b\x05_\x10\xbc\xa8\xb6c\x7f4h\xec7M\xdc\x05\x16\xb6O\xce\xcd5!\x95V/\xe7g\xe3\x83\x86\x8d\xdf\xf7\xbdl8\xb9\xd8Du\x96\x19\x15t\x8d\xf7E\xbfs|4\xe9\xa5=\x95\xbcL\x92\xc2\xc0\x11\xd8<\xa1F/\xca\xb2h\xb4\xc0Zb\xb0\xb5%k\xe2_\xea\\G\x04\x15=\x94\x89\x1a\xfctcq\xfbD\xbbS:\x07\x1e\x8f\x13\xeeJ\xcd\xad\xa6z\xba\xef\xcbL\x84\xae1:J\xbe\xe9\n\xa5\x8c-\xb0#G\x06]y\x06\xcb\xa7+;\x8c9\xbc\x997j2\xf9\xb8N\xca\xcd\xd9]h\\\x99 \x87\xc7\xa3\xb6\xa1\xc6\xe6\x18Bo5\x86\xc6:\xcfelb*\xc0N\x90\xdc\x05\xd6@\x9d\xf5\xaf\xe0F\x8d\xf7)\xfa\x07\\\xa6\xf1\xa12\xfd\x0b\xe5\x14\xa7xL\xbf\xc0\x85\x05v8\xb9\xb8d;\x0b\xccm^\xb4\xa6\xcc\xb1\xb0\xff\x8e\xe0\x0b_n\xfb\x87_r\xfba\x08/v\xf7\xff\xf1m\xa8\x96I\xea\x1e\x8b\xd3\xbf)\xf6T\xbd\xf8X\xbf\xa9P,\xccG=\x9eL,\xe6\x87\x19\x1fLQ\xae\x17E\x01w\xc2\x86rZ\x03\xfc2\xc86\xfe\x92vh\xa6\x91C\xc9\xa9\x13\xef\x02\xd9\x7f\xe9\xd8d\x85O\x8c\xe7\xac\xb5\x0c\x95\xb0s(\xb7d\xe70\xe6\xd4,\xa4\xd7\xa8o\xf6YZ\xa2\xb9w\xc9\x89\xa5Lm\x93\xd0\xab\x1b\x17\x9b\xaaB\x97i\xae\xa46o\xca*\x15\x95\xa3\\\x0b8Um=\xd8\xcd\xa28\x1c\xc4j\x99\x92\x88?\xa9\xa8\xa2\xf1E!q\xc4\xaaE\x8a}n*\xc5\x0fbG(\xac\xb1`\x87EA \x00hx\xd3\x14*\xf1VS.\xf0\xd3\xf2\xc2\x14\xa8Q\x8d\xa6\x87L\xa5\xbf]\xfb\x9e\x18Q\xea\x08\xdd\xfd\x8e\x0c\x90\n\xa8\xc1/\xb7Y\xd6\x84\xe6\xda\xce\xc1J\xd6\x95EN\xce\x9d\xea\xd8\x8c\x7f\xb2\xd0\xec)\xab\xfdO\xc2\xe6N\xd8\x0dm\xf9\xd7kh36\xb0\x19\xc7\xf3.D\xd1^\xbb\xd5\xe3\xfd(\xe1\xdbjy\x14\xd9M\x1b\xd3:\x9a{\xe6a\xc2\xfb0\xcc\x94g\x8bY\x96\xf8\xbd<\xe3m!\x80\xb7\xba\xf6\xdb\xbfN\xb74LlzM\xa7q\x89;\xfe\x87\xd7\x17\x8f]\xfbA:{\xec\xf4\x91\xd7~0s\xe3\xe8\xef\x1f\x1f\xa8d\xc5Ug8\xba\xda\xf5i\x98\x8a\x85\xd1\x88\"\xf0\x94\xae\xf5\xe2\xf2\xf2\xcd\xc5\x9d\x9d\xad\x05v\xbd\x05\x97\xe8\xadj\x86P\x92\xda\x82\xd5\xe6c\xc2C).\x11\xd3(O\\\x8bE\x00\xee\x19\x1a\xfc\x89\xfcBm8s\x06\xee\x0eZ\xd2w\xbc*B\x08\x95;mgE\xd6\xe6\xa4N{\xac\xbb\x94\xach\xabN\xb2\xe7E\xfbaU\xa4\xbbK\x0d\xac\x10\xbbq\x86\x85|\xbf\xb0c\xd6\x08\x8f\xc3l\x14\x88clg}\xd9a\x1c\x0d\x12'\x1e\xf2\xa4\xbeP/\xe1\xce^Z\x0f\x0f\xfcp\xcf\xef\x1f6\x17\xd8\x91\x9b\xbc\xc0Z7{\x81\x13\xeeY\xd2\xa8w\xd4EK;\xb3(\xd0\xae\xcc\x12\x96\xa3\x850w\xff\xafI\x15\x05\xf8\x9fq\x8d\x91\xe3\x8aa\x7fJ\x86\xa6\x01\x04\xb1FN \xd6\xeb\xd9Gx\xd7\x17/m.\xb0\xd6K\xa4|l\xf9\xba\x18J\xccy\xfc\xe7\xb84|\xbf\xf7!\xfd\xae@\x8f\x7fNA\x00\xf8K\nH\x83H>)\xf1\xec\xf1_P\xe0X\x02\xfe\x1b\x02\x90\xb3\xbbGvDz\xa6\xb6\x9e=z\x9f\x02d\x94\xac\xb5\xca(\x85\xf9`,\x02\x90\xe3\xc8\x16?\xb2\x03{\x12\xf8\xd8\x0e\x94\x07\xf2\xd1\x13;P\xf6\xf9\xe8\xa9\x1d\x08\xb3\xf8\x1b;P\xe2\xfc\xa3\x7fm\x07\xca\x85y\xf4?\xda\x81\x12#\x1f\xfd\x1b\nL2\xb9\x02\xbf\xb2A\xc6r\x8e\x0f\x08]\x01\x18L\xe3\xaf(0\x05\xfc\xbfGhE8HEo\x9f\xfc\x84\x02\xee8\x89\xc0\xe7g\xff\xfc?`T\x8c\x06\xd2\xee\xfa)9\xd0\x1a\x80[[\x8c\xe2>\x1c\xf5\x7fO\xaa(\xc8\xcf\xff%\x86\x88S\xf0\xec\xfe=\xf2Y\x10>\x89\x88d\xe9bID\x1fcJ\xe6\x00F\xdf\x7f@\xbe\xfbr\xc1\xee?$\x80(]`\xado\xe3Y\xc4qpxN1#+\xa9s\xe28\x89\x0ej\xc6-@\xfc\xb6u$\x8b\x89\xf4\xac\xb2l\x83\x06|\x80k\xa4.\x10\xcf\x7fI\x0e\xb1\x81\xfco\xa4N\xea\x0f\xe4\xc0\xef\xff\x8cT\x12X\xf0\x07\xe4\xeb\xe1\xa8f\x17\x04DM\xe6\x9f\xe3n2?\xf0$\x8d&L\xd1@\xfe\x07\\'\x17\x02G\xeb\x13\x82Q\xea;!!\xfbn\x14\xfa!\x1c\x14\xcc2\x9d}\x05\xf9\x08S\xf5\x9e\xe3\xee\xb9\x11\xd0\xab\xfb\xefZ\x80Z\xcf\xee\xbdG\xa0\x89\xa4\xbaO1}\xef9\xc9\x98\xcb\xb1<\xc0\xfd\x9du\x92}.1\xfb]\xcc\xbb{\x05\x08\xa3\x1a\x80\x80dS`/\xd9\x13\x80?%\xf3\xee%{\x99\x06\x92%\xab]\xeb\xb3 s\x90\xfd\x81\xcf\x98\xe7\xf6\xbc\xdby$\x97\x1dK\n=\xee:y*W\x0e\x8f\xec\xac\x04q+\xac\xd7\x08\x1b\xc5\xd9\xa1\\\xf4G\x98\x92\xf4\x04~X\x91\x83'a\x94\x8b:oc>qV\x82\x82\xc0Ok\xc0\x99\x9430\xf9\xeb\xa9\xef\xff\x0b\xfd\x0e\xa2\x0c\x1dB\xb6\xcf9\x1co\xd2\x89\x96\xb4\xc8\xbej\x00f6=\x7f\xe0\x02\x05~\x88\x05O\x01\x02\xd1\xf3\xd9/0 \x16\xb0\x1c\xaa\xe1\xc3\xdf\xf3\x07\x91\x17\xc1\xb9\xc4\xb2\x93\x80\xc5\x01l\xe4GX~\x12\xc0\xcc\x1fq\x80ZF\x93\xdeV}~D\xd0\xdd\x1f\xa4\x99#\xb9\xc5_\x90\xa9\xfb\x83,\xf1\xa5,\"\xf4&Q\xe6=rr\x8b2\xd0\xc3{\x98\xd6\xf4\xfcAnF\x8e\xa9W\xcf\x1f\xa83\xfa\xd02)s\xda\x1e\x92\xe5\xd8s\x92h_\x80\xde\xc7\xd4\xa2\x178\xee^\x10\xdd\xe1J\xb8\xfa\x10\xcb,\xb2@z;w\x12 \x7f\x0f\x0b<\x12\xae'%K`5\xa1R\xc2,\x0d\x968*\xa5\x02\xb8\xb5}\xf6\x0b\xb2;\xe5R\x89\xbaT~\xf6\x1e\x96\x02\xa4\xae- \xff\x023\x86^\xb077/\xeb\x90\x03\x12\xec\xcd\x9d\x94\x10BE\x82\xbd\x13\x00\xc1\xc2\xb2LO !\x98\xa1\xf5B\xb1\x18g\x9e\xfd\x183\xda^\xc8o\xe7\xbe$\x07\xf7\xff\xda\x02^\x07\x94~\x8a%\xc0^\x08\x80w\xb1\xbau\xd6\xc8B\xff\x07\xaebd!2nh\xeb\x01\xe9]_i\xdb@\xfb\x99\x0f\xe8E\xe6\x1a\x1d\xf4@J\xf9\xf0>\x05-\xaf \xc8\xcf\x7fa\x81\x04\x12\x82YT/:\xf0\xa0\x0eV4\x04D\xd6\xf9\x19^\x04\xd1\xda\x96\xac\x83%\x11\x01\x91\x07\xd6\xb2\x08\x07\x1e\xd4!\xa8\x10\x1dx\xb2\xce\xcf\x08O\x8f\x0e.\xc8*\x96\x01H2\xfa3r\xf6\xa2\x83\x0b\xcb\xb2\nVo\x05D\xb2\xce\x9fciD4\x06u\xe8.\x1c\x0ce\x9d\x9fa\x92,Z\xdb\x95u\xb0\xbe\" \x92\x95\xfc\x9c\xf0\xfc\xe8`\x08u\xb0\x02$ \xb2\xce\xcf\xc8i\x8e\x0eF~\x08\x04\xea\x01\xa1\xf2\xd1\x81&^\x0f\x08k\x8d\x0e\x0c\xd5}\x80\x15\xb5^t\xb0\x0b{\x8e\x95\x0d\x01\x01<\xc1\x82i/:\xc8\xa1\xce\x7fk\x81\x00\x9e`\xa5S\xb4\x06{\x8e\xb5N\x01\x01<\xf9\xa5\xa55\xa8ci-\x07<\xb1`\xddeY\x85\xd0\x92\xe8@\x9e\xfd\x9f\x11\xca\x16\x1d\\\x06\xd4\xb2\xec\xece\x89[?'\xb49:\x18C\x1dB\x95\xa3\x831\xe0#V\xb6Dk\xb0j\x844F\x07\x97a\xa5\xb1V'Z\x83:XA\x11\x10Xi\x0b\x0e_\x86U\xb3\xec\xf5eXi\x0b\xfa\x8c\xa1\x8e\x05y\xc6\xb0\xd2\x04\x0b\xeae\xe8\xb3\xca\x98\xf6k\xb2o\xf5\x80qO\xb2\xf7\x8f\xf1a=\x0bZ\x10\x95\xb7zF=\xfa\xdf \x84\x8f\x84p\xf7\xec\xad?#\x90:\xc9>Us!R}/\x8d\xc4:\xff\xe0\x07\x96\xefR\x85\xff\x90\xc8#i\x14\x0c\xd3\\\x02\x7fEHv\x1e\xc8m{\x93lu\x1e@j1\x1bH)o\x7fj\x01HM\xf9 \xb6L\x08\x08\xe8\xcax \xce\xe6F\xdf\xb35\xa7@\xb8\xd6\x92\xb6E~\x8a%3\xd7@~J\xea\x80\xfc\x88\x89\xbc\x12G\xefar\xe9:\xb16ta\xf9\xcbu\xe2^\xa2d\xc3\xc7\x98\xd5\xb9N\xac\x9a|\x8c\xf5\x7f\x01R\xb5\xf0\xe8\\'VB\xecc\xcc9\x96\x9c\xd8\xcf\x9c`\xd9\xef\xf7y\xc2\xc3\xccw\x02\xc9\x14~\x82w\xdaubPY\x1e\xff\xe7\x7f\x8f\x1bq\x9d\x04\xb6\xf3-,1\xbaN\"\x15\xd3_\xd3\x05;\x0c\xf8!h\x17X\nqu_\x8f1\x82.\xe9\xf6>\xc5<\xd35\x10Z\x87{\xbe\xd4\xc7\xc9\xb2\x18\x08\xe6YKJW\xf8\x14\xa3\xb4\xab\x01xc\x96J\xaa=V\xc0\\7W\xf3\xa1\xa3\xce\xe34\x95\xc7\xf41f\xf6K\xb0e\x9fb\xb3\x8b\xab\xbe\x93\xfdW\x93\xf9\x18\xcb\xa9K\x02\x1086\x90[R\x1b\xb1\xce\xe6J\x7f\x86\xd6\xc7\xf8\x84.\xf10\xe3\xc9\xb2\x1c\xc4\xc7\x98\x1c\xb9\x12\xe8\xd9\x81K\xfd\xc4\xbe\xdfZ\x9f\xc3D|\xe9\x02\xa8\xd6x{\xdc\xa1\xfc\xfe\x0fdC\x87\x1c$\xe5\xbf\xc4b\x98\x84\x8c\x9c\xc4\x0e]\x1a\n\x12\xfa9\xedF\xaa\xcd\xa4\x17\xb0\xe4\xfd\x82l\x00\xa0\xc6\xaf \xd5\xf0\x13W\x91\x1a,\x9f\nP\xc0\x9d$\x89\xf6\xb56\xf2\xce\xffY_\xc6\xe8\"\xef\xfc_\xd6B\x1eX\xc4\x9e=\xc0\xb2\x8a\x02k\x0d\xf8\x01\x96K\x14\xdcS\x06\x9d\x07X>Z\x92\xf0e%\xd0c\xd9E\xd5\x16L\xf5cL\x9c\x15l[T\xfcs|\x9a\xa0\xd9KF\xd2\xc3B:\xc07\xb5\xb0\x87%u\x00\xef\x18y\xcf\xb2\xba\x92c|\x88\xb5z\xd7\x07=\xd3\xb6\x1f}}\x8c?\xc2\x07\xd2\xf5\x93\x11\xd8^\x9fb\x0b\x82\xeb'\xa9B\x8b\x0f\xb1\xcc\xb5$\xd4\xb7}?\xe5KQ\x98Ey\xb2\x1af|\x908\x923\xde\xc3\x87n)\x88R\xbe\x94'\xc1\xe1r\x94\xf7\x02\xfez\x1ee w\x90-1%\x8b2dc\x82\xbc'\x97\xe6\x97X\x0c\x93\x90\xdc\xcf\xac\xc0\xa5\x08\xac\x89\xcf\xee\x91\xe3\xad \x0b\xb6\x1ap\x03\x83Ey\xd7\x80\x88\xfd\x16@\xb7k`\xa3\x91 Y]\xdbw1\xec\xff\x8a\x02\x80\xd5\x12\x16\x14\x8d\xe2>L\x07Kb\xae|\x19a\xc4\x15\xdd\xb6\xd5\x0c\xf8\x01`\xd7\xdbx_\x8d\x99\x90p\xca(\x1chv\x8bI\xddR\x14\x0e\x92\\ux\x1f\x0b\xbaK\x05\x0f!\x18V\x80\xf0\x11\xb3\xe1\x15-#\xb5t\xdb,\xb4\xfaNw N\"\xb8\xd6\"\xacI\x82r7\xb3C76\xaf\nR@d\x9e(>\xac\xfb\x9e\x02g\xc0\xe7q)\xca\x05?i%\xa2e\xa6\x90\xec!\x99M\xee9I\"W\xe7}26 \x93\xeb\xf3>^\x1f7\xe7\xb1\x84<$s\xcdy*9\xc7C\xacM\xb9y\xa0\x97\x1b\xdbv\x01$\xa7\xf5>\xd6A\x96\x94\xbd\x95\xf0i\xf8~\x0f\xab\x9an.\x84b%\xf9\x126\x92\xc7J\xfe&\xd7:nn\xe4e\xc2\x96s#/\x13\x11+\xd7\xf2\xf2\x03K\x83\x11\\\xe4\x91c\xaf\x84\xbc{O,\x02rn\x90\x92\x90T \x92\"\xe0\xfbX\x8dv\x05y\xe7\xb7\xe3\x84\xbb5\xdb\"\xe1i\xee\xd6mN\x12\x1cjc.\xd6\x80$\xb00\xe7\x12\\\xcd\x93D\x1a\xe6?\xc6J\xb7\x9b'c$\xb3\xd0\xad\xd7E\n\x91\x85N\xbc~d\xea\xba\x87\x0e\xaa|\x83F\x04V}\x83v\x0f_\xc5\xb8\x87\x81\x9b \xda\xf3\xec]L\x90\x97e\xaep\x01z\x13Sc\xaf\x00a\xc1\xd4s\x02}\xa3\x81\x0f\xd8\xb2\xdeh\xd2\xdc\"\x00~\x8aq\xde\xd35(\x00\xc4\xb171QXv\xd2!\\\xb0\xe1\xbd\xf14\xe4\x01f\xea^\xc9>\x8f\x97\xd5\xeb\x05\xd2\xd3\xe0\xd7X\xc8X6Z\x15\xde#\xcf@pc\xcb \xb3cv\xe2\xc1g,\x1e,\xdb\xb5M\xf0\xf5\xf8 >\xb3\x9e\xd7\xb0]z\x1d\x7f\x8a\x8f\xf3\xf2r\x94%\x0e\x984\xdf\xc7\x94\xd7\xf3\xa2,\x05!\xe41FQ\x8f\x0b\x0e\xff1\xd6\xe7\x969p\x1e\xac\x18,\xf3\x00\xae\xbf\xc8\xdc5\x00\xcf\xde+\xe9_\x18i\xbd\xbe\x9f\xc2\xd1\xf9\x00\xbb\xe0,k\x85 \x8f\xc0\xd3\x00\xb28\x17\xe0B\xe9\x03l\xeb\xf5\x86\x0ep\x8a\x9fb!Y@`=\xb1\xcc\xb0\xec;n\xe2g\xbe\xeb\x04\x8bun[\xa52\xa06\xfc\x1a\x0b\xa7\x95\x12B\xd6\xd5mQ,,J\x9eW\x9eT?\xac/\xb2\xa3\xae\xeb\x7f\x8d\x8dx\x9e\xefH2\xfb\x10[\\\x96}g\x14\x815\x86\xc0\xbc\xc90#Gcs\x9e\x80\xa75\x10\xb9h\xd8 N\xad0\xe4\x00\xf8\x03\x07\x04\xe3\xdf\xe0U\xf2\xfc\xd4\x97b\xeeCL\x18=y\x13\xf4 \xc1n\x7f\xec\x83c\x83\x1d\x12\x85\xc6\x94\xfe\x90 \x9a?\x8e\xc2\x03+h\xf9\"\x9ct\x8c5\xde-P\xda\xb1\x1c\xe3\x05n\x94\xc8\x81\xbf\x8b\xf9\x9b\x17\xb8\x89|b\xe0\xd9\xbb\x98\x0f{Q\x10H\x94\xfe}\xdc\xbd\xb9\xa9\xc2:\xb2gD]\xacH*c\x06\xde\x0e\xaf\x06q\xa3Li\xc2?&(\x16eJ\x9f\xc1$[B\x94Pq\x1f\xd3\xa0\xe5([\xb9\x9d\x83>8+:f\x01S\x0c\xae\x01\xd8Z\xc1\xb5\x9d\xf4\xd9}\x8c\x1f+\xb0hX\x0d\xe5\xb0fX\xca\xe1\xcbJ\xd2 \xaa\xc9\x8a\xba\x05\xc2\x83\xd5Fz\"cpU\x01\x1fR8\x9f?\xc1R\x1c\xef\xeb\x860cZ\xd1:\x066\xc3p\x0d\xc07FR\x8bz\xf6\x04o\xc5\x8a \x8b -\x19\x08fy| \x89\xf7\x132\xedA\xaa\x8e\xca\x13l\xe4\x05e\xed \x96\xe2VJ\x86_\xd2\x7f\xe0\x87\x19OdW\x7f\x86 \x13\x87K\xed\xb71\x93\xe2\x01\x0c\x0d\xef8\x0f\xcc\xd0\xf0\xda\xaf\xe8\xe8\x0b\xbc\xc6\\\x03H'B_\x94c\xc6\x04IBR\xb8\x86%@\x99ky{\xe4\x04\xc1\xb6\x91\x08\x7f\x81\xe5\xe3B\x17\xb5\xd7\xbf\xcc\x13\xdc\xc6{\xd8Y\x84\x8fRI{\xdf\xc4\x9cS\x00\xe6NH\x10V\xa3$H\xba\xbe\xbdI\xfa]?\xbf\xc0Z\x9f\x91\x83'-\xef\x9f\xe1\x0b8\x1e\xaa\xce1G^\xd1.\xfe\x0474\x80`\x87\xd1\"\xb0M\x8e\x1b-\x82\xe0`\x0cT\xf4!\xc1\x80\xd8IR\xe0\n\xd8*\xc3\xb5\xf4\xfe\x18Sx\xe5\xb4\xfb9&\xd6+\xc6\xd9\xfbs\xda\x8f\x01\xe1Z\x02$\xb6\xf67\x04p[_\n\x12\xba\xc7o\xd7\x931~[y\x97\xdc\xc7k\xcdo\xa7\x81\x13f\x83,\xb1\x1fT\x00\x07<\xb5\x9f\x16\xa3\x07=\xa6#\xcd\x1dy\xc4\xce\xd8\xaah\xad\xdf6\xa0\x9c\xc3\xb5\xe8}\xcc\x92Vn\xe7~\xe0\xf7\x12?\x97s\xf9)\x16\x18JN\x946\x08\xd8\xae\x1ec\xa5\x81\xdf\x1e\x17\x1b\x8e\xa5h\xaeY\xe0\x07d\xc3\x13Mq\xf1\xa1_\xd1nA\xd8\x10\xc55\x00\xf3m\xaeI\x0e\xd1&W\xd4\xbe=\xc6\xd7&\xbcnCW\xc0tE\xf8\x06|&|i\xe7\x82\xa0\xdb\xb8[\xb0\x96~\x82'\xb0\xa2\"%\xc8IV\xdf y\xc9\x13\xe9R\xff'\xd8A\x8a\x1f\xb8\xa2\xc2\x11\xf2\xd9\x87\xad\xbf\x87\xe9\xd1\x8a\x80\xa4V\x10?\x88\xb9\x9b9:^\x86\xac\xfa\xca\x01${\xf0\x9d@^/S\xdeY\x14\xb03\xd7\xbe\x13\x04\xbe\xbc$T\x96G\xc2d\xcf\x81\x98\x80\xa5\xe6>\x88 \x98\x82\xf6\xf9Hu\xf5K|\xf3\xd0\xef\xfb\x10\xf8\xf8\x9f\xff\x06\xcf\xb3\xdf\xd7\x10Z)\xd0 \xdc\xd59\xcd\xe4\xb1\x9c\xd6\xd7\x00L\xe2\x8a\x01`5\xe2\x9c\x1f\x04\xdc\xc3l \x13\\(ec>X\xec\xea\xdf\x82\x9e\xfa\xb70 p\xc0B\x87\xc5\xaeb\x9e\x18\xeb\xfbA\x16J\xf4x\x0f\x9f\xd3~\x18 \x06\xf0\x9f\xc8\x96\x19\x96\x81\xf5\xb3\xbea\x19\xf8\x10\x9d\x8b\x92E\x10'\xee\x91=\x88\x12\xa7\x1e$\xfdX\x1eb\xc3\x87\x00\xc0\xbd\x00\xe6g\xe7\xa2<\xf1y\x92%p\x0bL\xe6\x14;I\xa6\xfd\x1e\xb0\x10\xdaO\x1cW\xba\xb3\x7fL&& \x92\xa9\xff\x04\xd3, \x12L\xfdc\xbc\x9f\x12rJV\xc2\xc4_\x82^\x96 <\x01 zE\x82\xb0\xe0.@\xf30\n\xb2 \x02\x04}aF$@\xd2\xe1\xfec\xac(I\x08T\xc2\xfb%A0\nl\xfa\x13\xa0\x93P\x0bK\x19\x02t\n\xa6\x85e` \x82\x06\xb1=W\x80\xbe\x03 l\x13\xe8'\x0e\xb0\x97\xb7\x08%HT\xe8\xc3\xbbX\x08?\xa7y\x05\xd9{\xa3\xfbb\x81p\xa0U\xaf\xff\x07\xf3\xe2\xf3\xca\x08\xfd9\xdevm\x9d\xfe\x1c\xb3\x17Y\xc3\x13\x12\x08^\xb8\x81\x81\xe0\x15\x18\xc0\xcd\xed\x13l\x970\xa2\xc9\x13L\xd6\x00$\xf9\xfb\x13L\x8e\x15\x0c\xe6\x8a\x91~\xc0S5Yz\xf3.`0\xc8'\x988\x9c\xd7\x1c\x0b\xab\x17\x03\x0d\xc0\xec\xf7\xbcTd\x1fb\xda4\x00? ,\xac\x0c\x065\xc5\xfd\x11l\xce\xdbXx:\xaf\xaeN0\xa7\x1e\xa8\xab\x13\x82qpc\x80\x9b\x19Hg\xcfgO\xc8\x1e\x83\xbc\xf2\x04s\xaeApK~\xc7\xd3\x1d\x84\xea\x00\x92\x05\n\x8b\x98a\x0b\x10\x10\x98\xec\xc5\x9ckud]\x96U}\xaf\x82\xcf\xb4\xaf\x01X\xc6\xf0G\x0eh^\xb6\xb6\x06~\xe8$\x87\xab\xf6\xd5\x199\x83@\x9d\xe8\xb71j\x0b`\xec@\xca$\xbaw#\x99\xc5\xb4\xf5)\xd6\xd4\xfd\x91\xb4<={\x80Y\xb8?\x8a\xa5\xc3\xec\x7f\xc2\xf8\xb4:\x8a\x03\x1f\xd4\x1f\xe2`\xe2\x87l\xc1v\xf9\xe5\x87\xae2\xb0\xbd\x8d\xafc\xcc\xde\xdd\xc3\x8a\xb7\x84\xa8\xd0\xfd\x0f\xb1\xbe\xec\x87*\x87\x06\x99\xd1\xaa\xc2\x12\x82q\xea;\xd9\x8d0s\x81\xc6<\xc0B\x9c\xca\x08\x0d\xb1\x1a\x98\x81V\x9c\x97,\x8d\xf2\xa4\xae\xd9Uy\x11\xc8M\xf6$\x92X\xc4\x0f\xb3\xc0I\x86\xd2 \xf7\x11\x16\xda\xfc0\xd3A\x14\x1fa!q5\x1c\xfb\xa9/\x1d\xac\xc0fb![\xba\x88\x89qz\x0bK\xe5\xab\x1b@I\xb0m\xd5\x8f@\xf4!X\xabo\xbc0\xc1\xf35\x00\xdf%\xac\x1a\xae\x86\xf9\x92o \xd8\xac\xb5\n'\xf9s\xcc\x07\xd5 \xff\x1c\x0b\x16~\xed*\xf9Z\xca\xfe\x18\xb3\xf9U\xcd\x15\xc9\xe12\\\x11k?\xdaC\x92\xe2|\xea\x87Z\xf0&49\xf5A\xc8}HF\x9d\xfa`#~\x88\xbd_%DZb\x1fb\xca$@c\xfb 2\xfb\x0e\xeb\xfcS\x9f\xe2\xcbp\xdf@\x08\xc1\xcc\xf7\x00-\xb0\xee\xe1+\xc0?`s\xe8\xaa\xbaq\xc1\xac\xdbW\xdf1V\\\xd4\")\x9e\xfa-\x0d\xc0\xeb\xa8l\x1b\x18%\xc0\xb4\xf1\xf7xm/j\x06\x86y\xff-\x0d\xc02\xca-E6\xff_L\x1d/\x1a4\xc5\x87\xe4\x96\x81`}\xea\xa2\xc1!,\x94\xde2\x10\x8c\x90\x17S\x9e\xc0d\xf0\xce\xde\xd2\x90\x7f\xc0\xf2\xc4E\xbdQ\xd8\xa6uKo\x14\xe6\xf8\xdfw\xe2X\x9e!|\xe6\xf64\x00\x930 \x90\x97\xbfX<\xf9\xbe1\x8abo\xa5=\x03\xc1\xab\xf9}\x18/\xe9\x1d>\xe3\xbe\xbf\xafw\x0b\x0b^{\x1a\x80\x91zo\x90@B\xa8O\xb1\x90\xf5}\x15\x0d\x8cwdOE\x03cn\xf5}\x85qX8\xd9S\xd64,\x7f|\xdf`\x03\xa6\xf1{\x06B\xea\x18l\xc0\x82\xd6\x9e\x86\xfc9&\x9b\xc1\xa2\xd6\\\xf0\"\xae\x99\xfc\x02\xf88\x04\x06\x82W8pJ1\x04\xf80\x06\xce q\xe0\x16\x13\xb3\xff5g\xd4\xf3$\xbe`\xdc\x0f\x0c\x04\xabOk*k\xe6\xaf\xb0\xf8\x14h\x00\xdeM\x01\x80\xfc\x8e\x98\x11\x05\xc6\xb3\xccR \xcc\x8exC\xd7\x1c\xf9\xe2\x9a\xbe\xc4\xc23\n\x1cH\xb8\xf61f\xf0kZ\xab\xc7RK\xa0\xed\x00\x98\x85\x98\x986\x1b@\xc6\xf6\xfd\x14\x8b\x18\x12\xd2\x97\xec\xe0}|\xf9 `\n\x84e#\x01\x02\xe1\x81\xa8\xa2\x02\x14\xc8\x95x\x07\xcfH\x06\xd6I\x81\xe5}\x8a)\x89\xb6\xe7|\x80y\x8f\x80e\xb2\xda;\x98\xcb\xa8\x1b\xd2'\xa4\xa7\xc5\xcc\xf1\xa1'\x8a'\x06\x84\x89z\xe0@D\xf2\x13,\xfe\x0b\x00\x98\xa8\xfe5\xb5\x18\x05g\xd5\xb2\xbf\x8f\xa9E\xd0\xd3\x10|\x98\x03\x9d\xe4\xef\xaf\xb0n\x10\xf4\x12\xb0:\xfc\x91\x0d \xea\\\xa7\x80=9\xecGX\xd1\x16\x904\x00D\xc6\x1c\x12`2\x8f\xd1#\xcc\xac\xd6\x8c\xb7!V\xd0\x03\x03\xc1B\xca\x9a!\xbd\xf8\xf8\x05\x06\x82\xa5\xa4\xc0\xe5\xb0\x13\xefb\xd6\x13\xb82\x16\x15\xaf\xc1\x1a\x90F\xb2\xa5\xf0\x99t\xec\xb9R@}\x1f\xb3\x89\xc0\xe48\xc4\x84QB\xc0\xe2AN\x9d\x97x\xda\xe1\x143\xf1\xc0K\xf2T\x03\xc9.x`\xd2x\x87l5\x18!1 \x06\xf2r\x1f\x9fT\xe9\xf2/\x88\xcfY\x81\x07\xe01GhP%.\x80\x90\x81\xb5\xb2\x0d\x89R\x8f\x8a\x85\xc9V\xb7\xec\xedN(\x89)\x80\"\x04\xb0,g\xba\xd1\xc7\x90\x1cj\xd1\xd2\x12\xf7\x03H\xc7J\x91C\xc0\xc1\xf9\xbf\xbc\x14x\x19\xa1\x94t\xd7.\xf9\x8dc\x0b\x85.Ur\x1b\xc7\xb6\x9ej\x11\xed5\x8ei\x87(u.\x88\xa0\x8dw\xb1\xe9VLZy\xe0\xeb,\x7f\xc4\x1f\xbeT\x06\x02|\xdf!\xe7\x85\xf73\xb3|\xa0\x1ec+5\x0d\xf8 FaQ\xa4j+$\xf6\x99\x80\x14!\xadT\x8b\xa4\xb5[-\xcb\xa8iA)r>t\xa9\xf4v\xee\x0f\x8a\x1e1\x11\xb6\x05'`\x8a[\x8a\x9e!\xa1\xa4\nV,\x8c\x0d\x83\xab\xd8\x82%\x1d1\xd4l\x98p^\x84\x98\xe1\xd9\xc8FJ)\x1f\x1f\xe0S_.\xa0\x90\xe9CL\x9c\xcbe\x8c}\xf2\x01\x16\x93D)\x08\x92)\x0d\x19\x0b,P\xa8:-|\xa7\x0feJ\xa1\x1aXG(\x17\xd0\x07\x00\xeb\x04(\xda\x03\xe3.\x8d\xf4 \x82\xd0\n8\\S\xfc\x80\x0bi\xba\x19p\xc1CD\x1a}\xf3C k\xc9'\x80\x9e\xbe\xb4\xee\xbb\xba\x99#\xf2\x9e\xf1 x\x8c\xd7+(\xf9\x04`\xedM\xc1\xe4\x1a<\xc1\xb4&\xe0\xa9\x9a\xacE\xce\xe0\xa9r\\x\x82o\xd4\x03\x9e\xa6\xa5\xab;,\x81\n\xb0\xb6\x13`\x0dZ\xc0\xf8m\xe5\xf7jYc\x01\xd5`\xb25kO\xaa*\x14\xa1U\xa2\x08\x12\xb0 \xe1\x8a\xeeHrA\x94\x80\"\x95\xb8\x0d&\xcdC$\xc7x\x00k\xd9\xb6|\x06\xd7\x92GD\x18\xd0~:T\x1eOJ\x04\x92X{\x12\xa5\xc0R\x01=1\xb4\x91\xec\x00\xa4\x00z\x93X>\x12E3\x1f\x10\xca\x98:Z\xf9\xc6\xf8\xb9\xa6\xafF\x88dh\x8c\x92X\x98ZS\xaa5\xa1\x95\xb5\xdfk\xa4\x81\xc08}ac\x88\x80\x80`J8vz\xbbg\xb3\xc7\xa4z\x82\x041Rc] B\x92vb\xf8\x8c\xc8\x8b\x06\x82\xed\xbbk;\x0b\xac\xf5]\xfcQ\"\x05\xe5\x9a\x99\xa5l\xa0\x9d\xce\x08\xdd6Ng\x84\x86d\xb5\x82\xa4T\x8c\x16l:QP\xa8K\x84=e\x9a\x9d\x7f@hQ\xc9U\x8d\x98v4K&t$K\xe0:\x97hK\x81\x0e1&\x89\xf3\x83,\xd1\xeerdRy\xe2\x19\xc3\x0e9\xb3ybB\x90\xc9\nV|\xd0>\xb2H\xf3\xda\x07\xcd\x02S\xb7\xfa\x1f\xe3\xdb+\x13.\x83g0r\x80\x16\xfc%\xd6\xec\x04\x80\xc3\xe3\x1b\x04v \xc4\x89\xf71\x91\x1e\xc1\xf7w\xf0\x94\n\xfeT\x032\x96\x0dl\x1e\x03\xb0a)Xa\x03\xb0\xb2y\xe0k\x92\x91\x93\xec\x01\xc5z\x0f\xdf\xfd\x8et\xb6\xc5g\x1fa\x99\xf9\x12H\xa0\xd8\xbc7\x82\xcf\x98\xbd\x8eL\xca*l\xe5\x18\xe9H\xe6{\x98\xb1\x8f\xb8\x93\xe6 \xf7\x8a\x07\xb6\xb0\xf2q\x89{~>2Ndoa\x82{\x89\x07\x81\x1f\xeak\x01l\xf4\xbe\xa4\xd5\x01l\x88\x1bi\x00>\xe2\xa3\xa1\xdc\x9c\xb7\xc9\xea\xfb\xae\x0c?\xfb\x18K:*-\xe8=l(\x19\xf9\x9e\xfd\x8d\xa2\x91\xef)\xba\xf0\x14\x13\xd6\x91\xef\xd5\xa4\xcf-\xb2\xc0`\xb2.!\xf0\xc6\x16^\x1b \x82\xd1a \x0e@R]\xf9\x08/\x81\xcc\xc9\xaa\x13\xaf\xde\xc3\x8cq\x14\xb8\x90\xad\x10\xdb\x8fG\x01\xb3\xb4g\x1e\x1a\xa3\xb0\x0c\x1e9\xf8%\xa6M\x12\x02f\x85:\x18\xf8\xfc`\x1f\xbb\xb0'\x9d\x8c?\xc6\xd4:,R\xcc\xd3\xb1\x97r\xc9S\xa0\xce$\x89\x97}]\xdf\xe5|\x86\xb7*4\x10lz_\xd7w9\x9fa\xae\x11\x1a\x08\x96:C\x93r\x96\xf6S\xce9k\x19\xb9Jt\x89Q|\x1d\xc88\xd6\x14B\xf8\x8c\x15\xca\xd0Pw|\xbaT\x82_\xb2\xd4\\{F\xbd\x8fYU\xc8\xf5\xdd+V*D% y\xc7\nQ\xaa\x02\x85\x99\x88g2\xfdu>p2\x7f\xcc\x11\x1fy\x13KW\xba\xdc\xce\xd0w\xf7\xa6*\x16N.u\x99'\x87\xcd%Ko\xf5`KS\xc8S\xaer\"a[AX\x04l[&\x9cf\xdc\xa3A%$\x82\x02\n\x96-\x7fD\xde]\xe7\xfb\xca1\xf9\x07!\x19\x82 \xaf&\xf4\x86\x17\xf1\xd5\x18\xb6\xae\xf9.6\xb8\x85\x1a\x80\x87\x19\xea\x988\x8a\xd9*,\x0e;\x16\x86:\xce\xcd\x06\xb8]\xdfX9\xd6\xcd\x06O\xeb@:4\xccRI\xef\x13\x96\x1aB\x1d\xd6b!\xc9\x03\x00a\xb95\xd4\xc6[\x028\x9f\x01\x06=\xa5\x030\xd1\x0eX\xb7\x0cM\xb8\x03!\xacCexx\x8a\xd5\xbbPj\x0b\xf7\x08\x0e\xc3Cq\x0f1\xf3\x0b}\x10>\x1eb\xa9/\x04\x8c'\x0d\xad+\x93'V\x11Be\xf2\xc4\xea^h|8\xb0\xba\x19\x1a'\x0eZGI)XD\x0e\xf5E2]Du\x97\x8c\xa5\xb5\xb0z\x13L\xc7P\xb9\n&\x03\xb1\xdc \x92M\xb2\\!\x92\xed\xd278dx\xc5\x15\x8emJ\xe5[\x1c\x1b\x19jM\xdbr\x0e@\x1b\xa3\xddh\xb5\xf5!&W\xa1\xd1[\x1fbkZ\xb8\xa6\xce\xc8\x13:8-\xc1c6\xb5\x1e\x9dM\xb8#Y\xd8[\x98\xbb\xadG\xa1\x04\xfa\xe1@\x13w\"l\xac\xebX\x11\"\x9d\x18\x01\x16K\xec\xfam62|\xd0\n\xf0\xe7\xf5(\xab&\x95\xc7\x86\xc9_\x01.\x06\x81)\x7fQ\x06\xc5b\xda\x86b\xe3\x9d\x0d\xe5\x0c\xf7\xc4V\x9e\xa2\x08\x0e\xcclh\xadX&\xcc2\xd6\xa3\x8c\x86\xe2\xd8ZB\xf18\x14\xe1\xa3L\xb9B\x13I\\@\x8c/\xb4\xbd\xa2r\x87\xb6\x03\xc7N}\xbb\xf0\x10\xf4C\xac\xd9\x02\x0cr\x98c\xe3\xd5z\x94aO\x00r\xe8Q\x19\xe3\x0c`[\x19\xabG\x00\xa1\x15\xb2`\x0d\x8dS\xb0by1\xd5U\x05\xca\xc8c\x1dHY\xea\xb2\x0f\x95^\xac\xd6\x95+p\x06\x93\xd7\xf5(\xab\x93\x07\x9f\xfc+[sT(|\xf2\xd7\xb6\xadV\xa2\x00\xf6\xc8\x93\x10\x85\x04v\x18 \x01\xd6\xa9\x01\x06H\x805\x8f\xf5(\xdbL\xb8\xcb=\xf5\xd2\x0b\xb6\xf3\x95\xe0f\xad\x9e\xfc\x1b\xdb\xe4t\xb1\xea\xba>\xb4P\xac->\xe6I\xca\xcbD\x0fOG\x94\x92\x195\xcb\xc8IdlTHc\xa7EOA%\x8b\xe1Y\xa86\xe4\xc1\xd9\xce{*\xe7\xdb\x03+\xb6\x97K\x15\xcdYX\x84.\x18\x8b9C\x83\xd6\x01V\xcb\x15Mb\xd3\x97(Z\x8c\xedO(k7\x05\n\xb7\x1c\xa2#\x8b\"\xae\xcb\xb9\x07\xbb\x8e\x0d\xfa%x\xb1\xeb\xd4XQ*\x86v\x1d\x1b\x1aK%\x8b\xf3\xf4\x1f\xed\x0d\x96\x16\xea\xc75\xb3Ck\xf4\xc0\xc23\x8bn,\x93\x93\xc0\x82\xccXx\xa2,Qeg\xc4Z\xa4J\x15=Y\x86\x81\x99?\xd1\xd6\xe3\x1a\xa9@\x00\x9c P \xf1mPH\xcd\xf1\xf4o\xe9+\xb4\xa1\x8e\x80\xbbG\xa5\x810\x8e\x02\x1d\\\x88M\xc9!?}\xc7Z &Id\xcc4\x8f\x1b\x88\xb2\x02\xabI\xd6T\xd6\x93\xb4\xf4\x9b\xa9|;D\xc8\xd7qx\x9f\x10\x8b\x96\x81\x10;T\xa6\xbc\xd1h/\xe8yr\xaa\xe2\x96K\xc0d\xa8\xaeK\x9e/\xa7\x07\xbfRD\xb5C\x04\x0dy\xa5A\xec\xc3\xf2+1\x0f\xcb,\x9a\xbfG\xbfrH\xda\xf86\xbe\x13\x0es\x9d-\x96\xd8\xb3\xc7\xfa='\xcb.^^\xd6\xcf\x14\x12+\xd8e\xf3\x82!\xb1\x18\x8cM-B\xe6\xc6\xa6\x16Y\xc6\xb1N\xbbe\x19\xc7\x18\xf2\xcf\xd8 \x17t\xb8\n9\xbc\xe3\"\xfe\x1d\xdf\\\x85cm\xcbz\x1f\xdb\xe9\xc3\xb1\x8ee\xb0\xf5\x06. v\x88\xb9\xc4\xb7\x815\x0b{\x9f\xd0\xdd\xb1\xe1\n\x0f\xfe\x9d\xad\xa6~[\xf8?X\x80\xfb\xc6\xe8Oh\xda\xbe\xe6\x99\x04\x15\xf65\xcf\xb4B\x14W\xa3\xb0P\x9b\xc7\xf1\xd5\xe1\x86I\x11\x81\xef*\"\x03\xc1W\x81Q\xdd\xf3\x99\x91\xba\xac%\xeffn\xe8\xf4\x11XF\x894\x00kc*\\\x1b\xef=Dk\xff=\xd6\x89\xa2\xda\x1797\xf4\x9bM\x9f\xe1k\xed\xc8@05\x8a\xe0!\x98g\x1fa\x9a\x13\xe9\xd7\xce\xb0\x93V\xe4\xa5\x91\n{\xc2\x96\xdd\x8d\x15H\xbd\xf0\x19\xde\xff\x88+\x00Y\xf8\xbeZ\xc6G\xd8\x95iC\x1b\xfeI[\x1a\x80\x0f\xa6\nV\xff5\xde\xa9\x0d\x93\xc4\x824e \xd8\xa4\x1d\x81\xb1\xfdC\xcc\xba\"\x9d\xa8\xe7\x116\xc3DC\x81\xfd\x9fc9&\xaa{\xa112\xa6hl\x06\x8f\x02\xbd&d\xeb\x03\xf3(\xe1#\xec\xb4\x13\xe9\xc4\x12o\xd2Z0\x17,\xcbn(O\x98\xcf\xb0\n\x1bi\x006]o\x8c\xf8\xc0\xb1\xceR\x01~\x83\x19\xe8\x86\xf4\x8f\x90\xe9\xa7\xb1M3*@x\xef#%R=\xc2\x86\x9fhT\xfb.\xec\x861\x9e\xe2+\xd2\xc8@\xb0\n`\\)\xb1\xf1i#\xe6\xa1\xf5\xc5U|\xbdo\n\x16E\xb0_Z\x14sx\xf0\xf0\x11\x96\x11\x8c\xef%y\xc5vC\x0e\xeb1\xa1 N\xe2k\xbf\xc8(\x17\x04)\xc0\xb3\xf01\xa6\x14Q\xe2\x81\xb5\xe7mL\x8b$\x04R\x8a\xd8`2\x13\x17\x16>\xa2\xc4\x13\xb8\xff1A\xe4\xc4\x1f\xa8\xec$d#\x13\xf5b\"\xde\xc6(I\x83\x08D\xb9\xc7\xf8>7J$\xa9zLH\xb1\xfd%\xe1\x0d\xa3\\\x90\x01k\xc7\x0fB\x89u\x8a\xa4O\xc8.\x1a\x08!\x94\xeau\x8f\x07\xb8\xca\x86\x11\xf4\xf0\xf6F\x06\x82\xa9\xc8F\xe1s\x8bq\xb2p\xc7%\x8f\x1a\x03\xc8\x81zx\xa97T\xb6\x06\xb2\xd2\xea;\xd9\x9a\xb1\"q\xefbanc\xccu|\x11!2\x12\xa6\x82k\x9f\xfd\x19fe\x1a\xaa\xc2 \xff\x94\xac\xfb\x98'\x9bN\xc2\xc3l\xc8S\xb86\xfc3|\xd4\xb42\x85M\x06B\xd7\x13\xd8\x87\xe7Q\xd1\x01-\x95\x94\xb8\xf2\x14s\xfc\x92}\x82B\x94m\x02\x016\x9d\xc4<\xcfF\x81\xc0\xc61\xf9\x8b\xe13&}1O\\\xc91\xfe\x19\x05\xf82\x1f\xca\x0c\x05\x8c \xd6\xf3Mlt\xd6\x94\xe7\x01\x99>O2\x1eJ\x81\xecM\xac\x85lj\xfe\x8ayu\xac\x01XX\xde\x84\xa7\xd2\xb1\x96\x1b\xc3S\xe9\x98\x1c\xc7Cxu\x00\x1f\x8ax\xa8^q\xa6\xfeX\xf1P=\x17\xfd\x17\xf8&tS\xf6\x8c\xe9z,;\xc6\xfc.\xf63wX\x9b';\x86Q\xe1S\x12\x07N\x08\xef\xc7\x93\xa4i\x00\x82\x84jx\\\x02\x06i\xb7-\xd5$\xd1?j\xf9\xec(\xc6\xff\x11\x16\x92\x05\x104\x7f|\xb2\x04D\xd7\xc2\xa6\x04\x01\xf3\xa4\x9aE\xde\x81\x93 p\xf3#\xb8\x11\xe4\xe0\xd3\xfa\x18\x0bE\x9bA\x9e\xea\x87\xd9?\xc6h#\xaa\x8d\xc2:\x88:l\x1f\x11\x1c \xf24\xdb\x97c\xfc\x08\x8b\xeb\xf1\xc8\xd6\xdaf\x04\xc9\xa8\xc4\n\xcba\x92\xcc\x83\xb1\x90\xb9\xb4\xa1\x10c\xd9\xa6\xbe|\xc5bml\xa4\x04l\xbf\x8a\xa3\\>\xf6\xf81\xde\x95M\xb9\xecO0\xd3\x05S\xe4}\xcc\x0d\xe3DE\x18a\xc2nL\x94\xf7\xb1<\x1d\xc3[\xf5O\xc8y\xd0\x96K\xfa\xdd\xad\xe9\x9b\xbb\xa50&:\x02\xee\xaaw\x83\xad\xe3(\xdf\xb3\x90\xb6-\x97,5%\xaa\x96\xf6\xda^\n\xab4f2e\xe3\xab\x05T\x8e\xd4\xc2\xb2\x96\x84+;\xce\x13\xccu%P\x87Ya\xe9J\x00\xb5\xc5\x10\x0fh3Q\x16\xc37\xe9\x16i\x08>E\x12\x92\xdaq0\xd1Qht\xf8p\xc1j\x19z\xc3\xc0\xd5S\xed\x98\x02m\x96\x1ej'\xd4)\x89\xfaN\xa0\x04\x00\xac\xb3\x08\xa0V3\xde\xc5\xca\x94\x00\xa698\\\xbfKx\x87z\x7f\xed\x1e\x96D7\x93(\x8e\x12\x9dI\xed\x1e\xc6\xcc\x02\xac\x12\xb5\xe1\xfa\xa2a\xf0\x9b\xb7\x80\xea\xb6-N\xf2\x04\x04\x83\x07\x98en\x1a\xa1\x11\xdb\xc6bc\x91\xc6\x86\xc9Mx\x95\x87\xac\xbf\xfc\xfc\x1b,\x96\xc6y\xe8*\x13\x17\x06\xbd\xae9,&\xd7\xb75\x00\xef\xc8\xed\xbal\x8b\xafk:\x87\xcd\x13\xb7\x0d\x9d\xc3\xec\xe2\xb6\xc1\xd9\xb7\xb0\x80\xf9\xbaY\x15\xact\xdf6\xab\x82\xf9\xfc\xed\xdc\xc9x\x12\xfa*3\x01\xc9\x8c*\xe0z\xf4\x98\xeb\xea\xd8\x94\xd7l\xdf\x15\x91\xc2\x02\xd5\xeb\xbb\x1b;\x0b\xec\xdb\xado\xe3*Qf\xf9\x9c\x98\x84KX\x9b\xd0B\xec\xbd\xbf\xfd;\xcc{\xb6\x8c/5\xde\xa0\xc4@0\xc3I\x1c\x0f\x12\x90\xde\xc3;\x91\x94\xb34a\xfa\xb1\xa5c;1\x1a&\x1a\x80u\xf0\xc4\xa4U\xc2'S@\xe4\x94\x1ea^\x9f\x14 \x97hs*s\x12fo[Z\xd9\xc4R\x97\xb9\xfc\xa2\xfd\xab\x1a6\x00\x10\xbc\x0f0]KLR%:\xe6\"\xa9\x12\x19Bq\x97f\x81\xa8JX\x84J\x8atKXQL\x8atK\x18\xf1\x13\x93n\xe9\x03L\x0f\x92R\xba%\xac\xe9l\x99tK\xefc\xa4O\x8aLLX\xd2(]\x03\x92E7 \x97\xb0\xc2\x94\x14\xb9\x98(\xeae>\x10M\xac5IH\xa8\xfd\xe7q\xbd-\x93\x8d [\x18\x13\x03\xc1\x1c%1y\x9a0\x05HL\x9e&\xb2[:O\xd3]\x1b@\xd4\xb9A\x01*O\x13\xa6\x84I)O\x13\x16\xd3\x93R\x9e&<\xa3-\xe3\xa7\x8f\x15\xfb\xc4@0\x03\xdf2~\xfads\x0d\x04\xd3\xd6\xc4\xe4i\xc2\xc6\xb3\x04\xf24\xe15\xd8\x02\xcd\x91\xe0>8\xc3b\xad'\xd1y\x9a0kM\xbc\xc0\xa4\\\"\x87\xdf\xe4p\"\xf8V\xe4p\xa2 \x15\x17Jh\x19\xc8\xe9\x04?9\xf0t+@g\xc9%\xd4\x99;\x81\xc9\x92k\xab\x08\x88K\xc6\xc6A\xdey\x0f\xeb\xae[+\xe7\x05\x91\xc3|5\x81W\xfe\xf1g\x8b\xff\x0fvV\xd6E\xd03r5\xc5vcT\x90<\xb7\x9a\x14\x890\xb0=\")\x12a\x90\xe6U\x0eh\xb2BZ\x90 \xdd\xe8\xc4\x16\xf8\x16\xdb\x84'\x93\x17\x7f\x13\x9d\xd8\xe2\xa7\x04\xe7\x8a\xc4\x16\x98ln\xc98\xba\xcf\xb1\x8e\x95\xc8\xcf\xbf\xa1]DR+'\x8cX\xc6\x88\xe3|]\x18\x8bQ$9\xe6>\xc8}\x820\xa7\xaa\xf7\x84\xb5v%g\x17fTE\x89J\xd4\xfbO\xf1\xfd_\xd1\x91I\xda\x85\xe9\xbfl\xaa\x9c\xb5\x0b\x93\nY\x80\xa6\xed\xc2*\xb5*\x86\xf3v\xe1\xd3b\x8a\x95\x12wa\xb3\x16*\xa3\xf3\x0ea\xf1G\x16;W\x8b\xa7\xe5\x04V:\xc2\x95\"Z\xa9\x10\xf8\x06P\x8c\x13EP\xf6.\xeb:\x97\xf2\x80A)\xc2.D)\x9c{\x8bPf\x9ff\xd4\xb2.\xa2N\x97\x85em\x0d,\xb0\x13[F,\xcfr\x13Z(\x8a\xa0\x8cYx:\xc4\x17\xf1\x01\xa1\xceVG\xc4\xa6B\x85\xf7\x1a\x96\xdad1\x925\x0bK\x04\xaaTur\x98R\xa9B\xa5\xa4WX\x8b\xab\x94\xd0\xf8\x87\x05s\x94\xd3\x8c N \xae\x9b\xc0\xbak\x02\x87\xee\xd7D\x88\xf2\xd3\xea\x83\x8d\xa4\xa2I\xa6CP1\xd0\xe9 \x08\xfa\x05\x90\xf3\x81HQEf\x1bL\x0c\x93jf\x1b\x02\xd6\x81\x0cO \x933 d0WLL\x02\x19\xbc\xe8\x89I \x83iKbn\xd3\xb0&\xb8\xa5uQ\xc2\x95\x8d.J\x04\xde\"/ \x1duqGB\xf0/\xcaC\xaf\x94\xe0\xfe\x03\xac\xde'0\xc6\x8e\xe53\xdc\xf8>\"\x9a]\\r;$<\xc2d\x03!\x04\x19\x85\xf0\x90\xb3[d\xea\xc0\x06\xb5-};E\xebh]\x1b\xfb\xc6l)\xc9\x8b\xec}\xedw\x99\\\x83\x08\xd1&\xb9\x06\x16l\x93\"\xb9\x06\x01\x15\xa9)\x082\x17t \xc7ni\xdf\xc3\xf7\xb0\xa5\xab\xe4db\x81H\xc2zE:\xe2\xc5\x93\xf7d\xbc\xb5\xe8:\xf2a0\xefR\x88\xdc\xc9'd'G*\xaf<65\x08\x00\x84\xaa\xfd\x0d\xcd\x02\xb5\xbdqn\x07\xce*\xa9\x16\xf538\xadX\x9c\x01G\x9f\xe3\xf4\xab$\xe3\x1fb!_\x00\xd4E\x1aa!F\xf0\xc5rQj d\xc9bG]\xc1\xfe\x92\xa0\x99\x04\xe9w\xfd,\xd0\xc4z\xf0\xd3\xdbJ\x96x@\x98\x9f\x80\x80\xaf\xd1\x9f\xd3\xb5Ko\xab\xdc!\x0f\xb0\xb0,!P\xefg\x965\xbf\xad\xfcg\x88\xd4t[\x076`\xb5\xa7\x08\x94x@(\xce\xedR\xf8\x82\xb5^\xe1\xd7o\xab\x0b3 \xb4\xd4D_<\xc04P\x82L \\\x0dPuH\xebJK\xd9{\x98\xd5\x97^\xae'R@=\x08j\xe1g\xa8\xc8.\xd2p\xc0\x86\x02\x85R\x8f\x17\xcb\x16\x06\xd8X\xa4h\x8a\xb0\x11Yn7\xd4#\xa6\xf8\x93;p\x83L\x1e\xf2Oo\xe75\x80\xda\xeb\xa5msk\x89u\xc8\xd4hR\x98#\xa7\x0d\x02I\x03mJ35\xee\x87\x98jogp\xfa\x08 U\x80\xbf\xb0\x01d[\x7fAD\xc6,q\x04\x9f\xe6q\xea\x07r \x7f\x83\x95$]D9_as\\\x9a%\xd2\xeeE\xb2\xdfm\xc3\x01|H\xf0Z\x1dL\xc2r\xf3\x9e~\xb3\x9b\xa8\x0e&\x16\x89\x02\xe0d\x91\x19\xe7=\x9d\xaa\xe7)\xe1\xbayo\x94\x83\x07\xf3S\"[\xe7=\x90\xfa\x9fb\xbb\xa2\x80@_\x84\xc0\xe6=\xcdE\x9f`\xb2\x9c\xe6=\xc3E\xb1^Z\x1c#\xdb\x1a\x990*+H\x11\x05\xcb\xb4\xcb\x11T\xd6\x0e\x8b\xb3d\xaf\xad\x12\n\xdb\xa6 \xd0\xdbu\xeb\xa3\xfd\x1f\xb1-A\x80`\xd3\x9f\x12\xec\x11 \xc8\xf2F8\x86\n\xf6\xa2\xfaj\xee\x96]\x8f\xb0\xd6*\xc0e\xd7#\x8cL\xe5`_\xd2\xb6%\xd2\xb7\xa6\x04r=\xaa\xeb\xa5\x14\xe1k\x19\xa7\x0eY\xb3\x80\xca\xaeGD5\x15p\xedzD\xd4S\x01\xacUPs\xb7^\x0b\xcd\xdd\xe1\xce\xd0\xb1_Bm\xc3e\xd2=\xc2\xf7j\xbf\x83!\xf0\x97\x98\xb8n\xc3v?\xa4\x15\x80}\xd2\xd3\x1a\xcf \xf2\x82OO\x9a\xc7\xf3\xe2;\x91M\xf3\xf8\x84\xf8N\x84\xc7<\xd6\xe4\x05[ \x05H#(\x11XM\x84 \x05\x009\xa0\xd8\x1e\x1b\xd2\x83\x05\xb8j@w\x0d\xb08\xa0\x96\xa6\x87\xca7\xfcWXQ\x9405 |!\x9c\xe6\xb1I\xdbJOSl\xa8!\xa55\xb1\xa2\x86Dp\xcdcE\x0d)\x1d\x8855|J\xc45#\xed\xd8\xb6\xbfn]*b\x90eI\xca\xe1\x94V\xa8\xa6h\x96\xa1\x96)\x9ae\x8e\x9a\xa2\x11\x9e\x9e\xc7z\xad\x89\xc0!@@\xd1\x08\xbb/b\xd6\x88\x19\xc6\xc4\xacachjb\xd6\xac\x90\x9a\xbc\xd7\xe9~\xa8\x8d'D\xba\xb9\x03\x91S\x9f`=q\xc7\x113\xfaA\x86>gN2\x80\x9dy\x17Oh\xc7\x91!\x9aX\xaf\xc8\xe4\xe7\xdf`\xe4\xcf\x94\x9d\x9f\xf8\xea\xef\x18k\"i\xc9@\xb0\xa6\xb1cl\x80\xd8\xfe\x92\x19\x08\x96\xa9\x94zF+H\xdd\x0c#\xbf\xce\x9c\xfcclw\xcdx\xa0\xbcb\xdf\xc5\xeclG\xdb\x8b\xf0 \xcc4\x00\xdb\xcd\xb3!O\xf8I\xd1\xd8=\xb2,\x02\xd4\x8f@b'\xd0\xac\x11\xba3\xe4\xf0\x06*\xa6g\x99\x06`\xb6)\x01\xe9\xa1\xc0\xf7\xdf\xe0\xc3)ac;\xc4w\xf7J\x197\xf1A\x91\xf0:cJ5\x03\xe2[\xbf\xa2/\xf5gC?T\x9e\x8d\x98\xdeU\xb3\x1dbh6\xdcS\xb1\xbdtD\xf5\xe3\xb9\xb0\xb1\xb5.N\x066\xc7d\xc3(\x11X\xf8 \xe6\x1c\x86\xbb\x93\xb6t<\xce\xaf\xb1%\x1a\xa5\xdb\xc0\xc4\xce\x92k\x03\x8bq(\xd1\x06\x99\xa0\xba!\xf9\x84\xe0\xa0\x00\x80\xec\x8d\x15z\x00\x01\xc1\xf8\x88\xa0\xa8\x00\xc2\xbb\xb9XP\xc9\xea\x1e\xe0\xce\"\x0e>B\xd8n\x99\x81\xd7\xee\x03r\xd2\xa3\xb8\x07\xe7\xed],\xd0dQ\xac\xd3\x18\xe3\xa1\xed\x18\xdb\x06\xa6\xed\x99\x81`\xca! *d\xe3)6\x1bdQ\n\xc3\xc6rSVx_\x93\xa3\xb6\xb5\xb8,\x99\xe4\xdb\x84\xb0$\x0e\xec\x91\x05R\\\x9f\xbf\x87\x15.\x0d\xd4\xde\x0b\xefaA\x0d\xc7\xee\x93\xac\xea4t\x9f\xa4W\xd7E@F\xc6HJ\xe2\xfa\xc9\xa5\x9a%\xac\x9f\\\xafe\x89zU\xe5\xd9/\xb0IL_\xc9\xd9z6\xb6\xc1\x8f\xb0\xdc\xbb\x93\xf8q\xc0\x97\xeb\xe8\xb2\x80\xaa\x9a\x96\xe1\x02\xea\x7f\x88]\x06\xb3\xc4\xcf\xd4\xd6~\x84e\xa3,\x89\xf9\x1d\xe5F\xf5gx\x0fw\x8c-\x00k\xbe\x99\xb1\x05\x10\xa2\xa5nz0\xfb\xcf\xd4U\x0f\x96_v\xb4\xf9\x9f\xa0\xb7\xb6\xff\xe3E\xd81\xcf\x0f\xd0>4\x04_\xc0d\xfb>\\\x8c\xdc'\xdb\xb4\x1f\x0d\xb9\xe3U\xf3K\x12\xea\x08\x85\x90w\x13&1\xbb& \x1e\x1f\xba\xdc@\xf0~\xefj\xd1\x07\x8b*\xb9\x96\x960?\xcau\x0d\x0c\x10M\xe9\x00\xfb\x0f\xf0\xb6\xec\xf6\xd4\x93\xca\xf8\xa67W\x80\x7f\xc0s\xde\xed%\\\xc6y\x7f\x86\x97,7\x10L\x13wu\xb4>\xde\xb3\\\x030\xfe\xed\xc2\xa8\xb0\x1c\x93\xc3\x98\xf0\xa9\xcf=\xed:\x809\xc6\xae \xd6\xc7\x04<7\x10LZs\xe3\xca\x89M]y\xe1?\x88\xf9\xe1\xae\x16s\xb0\xd8\x91k\x00V\xd7vM\xc0<\x16as\x03\xc1\x879\xd7\x9e\x85da\x86N\x02\xeen\x98d\xe6& -\x1ern\xde\xc5\xc2\xdaJ.\xdf\xa7\x12\xa0w1\x95\xca\xcbOWY\x80*6\xe5]l\x1e\xcd\xcdC\x18X\xfc\xda\xd5\x11\xf2X\\\xcf5\x00\xbb\xedC\xb0\xed\xc7\x98\xc1\xee\x86\x9e\x8e\xa9\xc5\xef\xe5\x00\xc8\x84\xd4\xe2Ce\xc0:\xa6\x16\xd3sY\x00\x07\xd5\xe2{(c\x8a}\x88\xf1SBt\xb6\xff\x07\xf8\xa8\xed\xaad\x0b\x9fa\x0c\xc95\x00k\xf4\xbb\x86\xc5c\xcd-7\x10L\x04\x9b.\x1cw\xe3\xc2\xb9\x86\xd0\x95\x02f\xa9Wv\xda|\x1f\xdb\x8c\x15\xb8r'KOh\\\xbd\xb3\xc5\x8a\xc5n,\xa4\x81b|\x18\x9eW\xe1\x96\xfa\xd8+\x98\x9c\xeaX91\x9aw?\xc8\x19\xd2%\x8a\xa7\xa4\xc8a\x8ak\xb77\x8e\xf1[MX\x9b\x94E\xd0\xad1\x96awU\x08\x14^\xe4\\}\xc7\xeb*\xbe\x0fm\x15v\x8d\xc1\xfbs, \xe6\x85-\x9cn\x93v\xbf\xc4\x95$\xa4\x187mSa\x10x\x7fb\x99=O\x0c\xa9\xc1\xe7)/?\x02e\x01jRC\x16\\9\x19~F6Z\x03\xb0\xd8\x92k\x0f\xaa_`\x82\xbbkD\x1d\xc2?\x8c\xa8\x83U\xb7\xdc\xbc<\x84\xeb\xecj\xdd\xe83L\xbbr\x03\xc1\xf2w\xae\x9d\xbb0M\xca\x8d\x0b\x17\x96ps-\x0b\x90\xd5\xdeUy\n\x08\xe1V\xdf\xb1.\x97\xef\x1ba\xfd\x11\x96\x9d\xc6N8\x80;\xc8G\xb8\xb9\xb1\x934\\\xab\x8c\x9dD(\xce\xd2c\x01\xaf\xd0\xd8I\xc2H\xe8\xbe\xf0\x9a\x06\xc6\xc2\xb1\x93\xd4\\\xc6\x08\x88o\x0b:\x17\x80\xfa\xb8\xc6\xb1\x16\xa7,\xed%Vz\"\x00\xe0`\x8f\xe5\x86\xb1\x93\x18O\x0clR\x11\xb0\xea\x1d\x03\xbd\xd2-\x97Q7\x0d5\x85*\xa6\xbd\xe62\xca\xc0g-\xa4-\"\xc4\xb6!`H\xd3\"\xaf\x03\x97\xca\x18\xaaH\xfc\xa1/+\xcd\xfa)f\xe1c\xc53\x9e\xe2\x83 \x002\x8a\xef)>\x08\x97A$\xc4\xe4l\x0c\x9f\xf1\xf0\x8a$f\xb8\xeb\"\x87\x19\xee\xa1HaFFe\xea`]H\xb6&%\xaf\xa7\x98\xe3^V\x9e\x9c\xf8\xa6m\x0c\xdfI\xea\x991\xe7j\xb9\x1e`qx\xcc\xb9\xd2W\xb1\n1\xe6A\xe0\xc3\xbd\x02&w\x97y\xa2\xda{\x93\x1c\n\x0d\xfa\x11\xad\x93\xd5\xd5\xc8j\xca\x97\x13\x9bb\xb9T\xc3\xd5\x13\x17u\xd5\xb7y\xec$\x8e\xf2+\xff+,B\xebR\x85\xe5\x07#3}\x04\x04\x13\xe5\xcbZ\x0c\xc7\xc2\xf6X\x030\xee\x8e\xb5\xc4JQ\xdf\xe4\x8e\xb4dz\x1c\x9b\x9c\x8b\x96\x0c\x89\x97\x8dx\x86\x95\xf1\xb1\x81\x10:[\x1b\xef=6o\x17\x92sg\xd8\x16!R\x86ma\xc5z\\\xba\x01\xb6\x90\x8b\xd2-\xb0\x15j\xeeKj\xa0\xbc\x8eZ].\x0e\x17\xd6\x00\xc6w\xfc\xc1\x1dG\xb2\x82G\x18\xf1\xafh\xbfV\xcc\xfd\xf65\x00\xf3\x9d}\xee\xa9\xf3\xf0\x18+\x00W\xb8\x07Q\xbd\x0f\xf1\xe8\xf65\xe4\x1e\xde\x17 \x81C\x89qj\x9f\xfb*[\xcc\xdb\x18\x97\xafht\xc3\xf3\xd9\xd7\x00<\x9f+\x063\xb0\xa0\xb3o \x98\x94\xec\xdb;\xdfO\xac\xa7g?\xe1N6\xb4\x82\xae\x18D\xc2\x87`\xdf \x12\xd6A\x0e\x94'\xd4C\xcc\x04\x0f\xd4\xce<\xfb\x05\x16\xc0\x0e\x94\x13\x14\xd1\x9c\x0e<-\xfe\xe0k\xe67\xf4za\x9b\xc2\x81\x06\xe0\xfd?\xd0\x0f\xb5\x90\xb7o\x0f\xb4\x8eL\x9e\xbb}Cf#\xc06\x90\x03\xf9\x15\xab\x00\x07:\xbd$y\xcb\xf7@\xdfA\x927|\x0f\xd4\xf3d\xe4!\xdd\x03\xfd\xe2\x0bf\x05\x07:\x99\xe0Gx\xaf\xde0\xe8\x80\x95\xef\x03\x03\xc1,\xef\xa0\x88\x0d\xc1l\xea 2\xd6A\xb2\x91:<\x9d\xbc\xdc{\xa0}>\xc8\x83\xbdo\x18L\xc2\xc4\xea\xc0`\x12&\x8a\x07\xc6;\xee#l\x1f<0\n\xd7G\xf8\xb6\xed\xc0\x88\xcc\xa4\xa7q\x0dK>\xd8\xaf%\x00W\x8d\x8d\x0e\x93\xdfC\x03\xc1\xb8yu\x11\x84\x12\x8c\xe6\x87\x0e\xd8\xaf\xf0\xfe\\\xd5$\x0b/\xda\xa1\x06`\xbc\xbc\n\x1d`\xd9\xe6\x10\xda\xc7\xa4\xfd\x90\xcbdBX5\xbb\xaaO\n\x96\xdf\x0f5\x00\x8f\xe7\xea*\xf4\x8b\xef\xa2\x0f}\xe8\x18+\xadW\x0d\xe2a?\x9fC\x03\xc1D\xff\xaaA\x14L \x0f\x0d\xa2`JxU\xd9\x0b\xb1\x08t\xa8\x0c\x86\xa4<\xe8;\x9f\xe1\x83z\xa8\xf4 l\x00\xb8fBQ0\xc2\xdf1\x10LT\xae\x99\x1b\\\x8c\x1ew\x0c\x04\x93\x90k0\x0d\xbc\x8cw\xe03F\x82k\xea\xe5vL\"\xee\xa8\xef\x98\xa6\xdc\xe1\\?\xe2\x89\x19\xc65\x9eDW|/\x1b\xd6?\xa3vM]\x9fb\xc9\xf0\x8e\xfa\x8eq\xe5\x9a\n\x9b\xc6]\xdd\xd1\xc8E\xa6\xa3,\xfe\xa4\x030\xf8\xff=\xee\xe0\x8e?0!c\xf8l^\xd3ar\xf8\xb6\xed\x8e\xc1;|v\xae\x19\xbc\xc3D\xfa\x8e\xc1;|p\xef\xec\xdf\x92k\x85 \xd7\x9d\xfd\x10\x00\xef\xb6\xcc\xf7\xbb\xf2\xaf\xbb]\xd6\xcfC\xe9g\xda\xe6]\x96uY\xd8a\x7fd\n\xb5\xf2\x94\xb34K|7k\xbdj\xbe\x8e\x9d\x84%\xec\x0c\x0b\xdb'\xe7^\xe9T\xbb\x8a\xe4\xf7\xf9\xeftf\xf2\x90\xa7\xae\x13\xf3K^Q\x93\xcf\xf0\x838J\xb2\x94\x9d\xa9\xf6[\xeeTw\x11v\x99\xdfeN\x97\xe5\xec\x0c\xcb\xaa\xdd\x88\x9fh\x84\xcf\xc4Qz\xc99x\xb5\x02\xf5\xfb\xac\xfd\xf2,;sF\x14H\x13w\xc6\x1d:\xc9R\xe4\xf1\xc5\xac\x9dup_\xe2\xd7\x8f\x12\xd6\xce\x8e\x1e}\x95e\xec\xbb,}\xd5VF\xb7<\x07-\xb7Cfo\xbe\xc3\x12\x9e\xe5I\xc8\x8e\xcc\xbdZ\xdb\xc8\xcb\xf3\xb2\x91\xd0\x14v\xd8\x19\x96\xb4\xa36\xb4\x98\x06\xbe\xcb\xdb9;\xca\xe6\xc4\xeat:]v\xe4\x08\x9f\x89\x9d$\xe5\xc9\xcc\xd8 |\xcf\xc9\xf8\x9a\x1f\xee\xb5\x9d\x0e{\xe9%\xd6\x96+!\x16\n\xea\xf0\x99\xc0\x0f\xf7\x96\xa20\xe3a\xc6\xce\x88e<2\xdb\xb1\x8f\xe7\xb4\x1a\x8bhGV\x17K\xc0^\x13\x7f\x9fa\xf3l\x81eG\x8f\x92\x8aw\xc9\x173\xebo\xd5\x97\x93\xeb\xec\xb33lV\xad\xb4\xe8\xf3\xc4<;\xd2\xb4\xa0\xa2\xcc\x91v\xc8\xbe\xc7^\x11\x7f\x86\xec\xbbl\xeed\xe7\xd5\x0e\x19\x81XX\xebd:j.t\xfe\xfe\x83\xf4\xe8\xf1A\x97\xb5X\xab3\x93E\xf2\x0eg\xc9Iy\xfb\x85\xe0\xf0F\xef\x16w\xb3\x19\x8f\xf7\xfd\x90o&Q\xcc\x93\xec\xb0\x9duY\xeb\xe6M\x9e^\x8a\xbc<\xe0\xad.\xc1\xd6 \xe7\x0b\xec\xc8l1\x82N\x97\xc9V\x9c<\xc8\xca\xd3\xac\x99%\xc5\x147\x1a\xc5Q\xc8\xc3,]`\x8en\x89\"\xfb~\xe2\xc4K\xa5\xa2y}\xd14s2\xbe\x19\xe4\x03?L\x17jXA\x1as\xb7\x0e\xc6Tw\xdb<\x90\xb9&\xd2\x05\x96\xd0^\xf4/-J\xf9\xd6Bw\xedu\x9d<\x1b>\xc7\x08\xa2\xe7i;r\xd2\x13Mm;r\x8f\xd2\x05\x96\xd6\xcf+\xe1^\xeer\xd1\xb5[\xbf\xd4\xfaWZ\x84\xc0>P\xf2\xf5n\xcd)\xbcK\xe9l\xdc\x0e\xdb'\xe7\xe7;\x16\xc9\x14@'0\xc87\xa0\x93\x18$\x88W_\x82NaP\xaeA'H\xadT58\x7f\xe2e\x0c\nt_'\xc9\x08]\xdd\xe0\xc9\x13\x9d\xce\xab\xdf20}JX\xbf\x9e\x1c\x08\x02\xc6g\x8a\xc3\xc8^c\x9c\xd96Um\xce\x02\xe3u+j\xe98\xa6\x1d\x0b\x92Mz-\x88t\x95\xd4j\x0e\xfeGw)\xbb \xf3 `G\xce0N\xe59\xc9P$\xcfc~\xc8xG\x93\xa18\x89\xb2(;\x8c\xf9\xcc\xd0I7\xf6CM\x90f\\'\x08\x04Q\x0bA\xd6\xc9\xae\x877\x04S\xb9\x1e\xde@|N\x0d\xb3L\x8b\x04-,-\x02\xfbF\x90J?\xdd\xdew\x06\x03\x9e\xcc\x0b\x8e7\xe3\xa7\x1b\x8b\xdb'\xe4\x9f)O\xc6\xb7\x1b(\x82\x103y\x91\x942\xc5#KtY.\xddJ\xa4\xec\xaa\x93\xe6\xc7\x03&\"\x99\xb0\x90\x00\n\x17^l\xb1\x97{fz\xaek\xcd\x03\xcc\x9f9o0\xefp\xde\xa4=/2+vD\x00\x01 \"\x80$)Y\xd5}\xb0\x96\xad$\"\x10\xd7\x1d;\xf6}'a\x00\x9b*\xfaf\xe7\xbe\x92\x1bl\xbf\x0d\xf1\xed\xd6\x8e\x12\xc6}-\x8cW[\xd1\xde\x07]=\x1d\x13W\x0d\xd8;#\xc5\xe1U^\x10z\x91R\x1c_aP\xfc\xeb\xbb\x9c6\xa2&\xday_\xf6\xa6\x0b!\xdf\x16\xc7\xce\x1cz\xec\xcb\x85\xcdc\xa7\x851\xd5\xf8\xec\xa3\xcc\x94\xf7t\xc8\xb0/\x9fq\x03\xf4\xc5L\xd94s\xb7\x89\x85\xf1o E\xe3\xdf\x12\xfe\xc6\xbfk\xdc\xce\xfe\xac\xd0\xfe\xddLI,e\xffvUw\x8f\x91C\x1d\x82\x83)\x84\x13\xbcXn\x86\x7f\x95\xb8\x17\x87\xed\x85\xf9K\x1f\x89\x15F\xfe\x18\xcee=\xbd\xce=\xfb\xb9MP\x0c\xed6\x93\xc4_\xbf?=#\xe1\x9f\xa3\xe4IY,\x92,\xfc\x99\x18\x88\x8a\x9cR\xd1JZ\x9e\x96\x8c\x1e\xa8Hy\x05!\xe2+ \x91\xd2D\x88\xe4\x9f\x86\xd8\x16\xbf\xe8\x84#\x0d\xaan.\x95-\xee\xceP\x7f7k\x87.\x83}\x7f\xed6\xccvq\xab\x8c'\xdc\x01\xc2+>t\xdf{\x11\xe6\x85\xd3\x06\xfe\xeav#q\x91]\x1d\x92\xbf\xdb\x8e7O\xb2\x03\x7f\xb60\xcc\x0d\xa4[\x93\x1d\x06\xbe\xee\x0e\x1d\xc7\xd8Q3\xa2\x14R\x8a\xe9\xe6\xb1\xba\x14u\x0e\xd3\x91\xa6\x94\xe2\xdf\x92Q\x01\x94\x0d\xb1\x14g\xd8J(\xcb>\xb6P\xbe\x84bn\xfe\xc1c\x7f\xf6}D\xf7|\xd2\x04\x00m\xfdk\x0d\x03\x11#\x03\x92\x96\xf9\xc2\x8e\xc9\x05\xf8\x14\x81\xf3\x1b\xbd\xda\xd6_\xaeQ\x056\xf3\xe6aT\x90l\x00|@}\x88\x18FE\x91-Q\xd6\xbdv\x1cG\xc1v8.X\x8b\xa2H-\xfc\x14!\xd7\xf2\xd3\xf0\xcf\xe4J\xbc\xa1\x84\xc2\n\xc3/;\xfd\xd0>\xe2?\xc8\x7f\xadt\xe5*\x99\xbfJV@o\x8d\x8a\xad\xf2\"\x12\x9f\x15\x0b&2\x7f\x92e\xfe\x95\x9d\xc1c\x18\xc1>d\xb0\x01#\x98\xc0\xa6\xe3\".\x18=\x82\x10\xbe\x82\xec\x11\x84\xeb\xeb\x0e$\xd3\x90V8\x96[\x9b\x86\xc7\xdd\xcd\xa4}\xfaws\xd9\x97\x155\xe3\xd3\xcb=j1\x8b\xd3\xe2\x98\x92\x8b3\xbf\xb0\x13\x87r\x93mV3\xd1^\xff\xac\xe0\xf7\xbf\xff[\xf2\x8c\x9a\x9a\xbdK\xa1\x82\xdc\x06W\x1f\x0f\xe3\xebVe\x91\xef\x84\x8d\\\x99\x81\xbd3\xd6y \x03+\x13%\xf5\x86\xa1Z\xa7GB\xa0\xd5\xe4E\x1d\xde\xd6\xc8\xd7\xe6m\xbev\x18\xf1\xb2\x12\x8f\xe3\xf6*#\xccK[\xe1\x9fB\x89\x7f\xe2\n\xff\x14\x1c\xff\x14\x12\xfe\xc9\x18\xfe\xc9\xe0+(\x1eAF\xf1O<\xcd\xba\xf8'\xd3\xe0\x9f\x04Ug\xb7\xc6?\x127E\xf1\x8f\xdfB/1\xc59]\xd1\x8e\xe9\x88\xaf\x84\xd7?)+E>gV\xa9\x8b\x07\x99\x0e\xa2\xa3MH\xaa\xa2\xfb*N\x88\x15u\x98\xa4Z\xa9\xf1P\xaf\xd4\xd8T)5X\xd1H%\xcdcEz\xa5\xc6\xd6\xef\xab\xd4\x10\xbfd\x91\x7f\xb3\xa1\xa7~\x14\x9d\xfa\xb3\xf7\xf9\xa4&b\x9as\xf9\xb6(\xd2'\xa8\x88\x8b\xd4\x15\xde\x12Lc\xf5u\x12\\Mj\xfa\xbcY\xe7\x90a#\xad\xfa\x92\x97?M\xe2\xc2\x0f\xd1\xdfL\xa3\xbc\x94:;\x08B\xf4V\xc8\xd55_\xa7\x84%\xff\xa9\xfa\xd6(\xe9\x12Q\xf1E\x18\xbf\x9f@(j}\xe6\x87\xc3\xb7c\xbb\xab\x9fKxI\x07\x90C\xbc\xbe\xec\xd8\xa6p\x8cUF\x14l\x91\xa8XQ'\xf1\xd1A\xb4\xff.%\xa8\xf5B\xc0\xedr-\xb1\xb8\x18*ex\xb7\x0e7\x0cI\xc9\xec\x8d_,\xba\xe5LJbU@TA\xa6\xa5\xb0)\x0b\xe7`\xaf\x15\x95\x1e\xb0:\x03\x9cH\xe0\xe9ul+O}J\xf5\xd0\xdb\xc4\x05\xebU\x02\xd5$\xda\xcc4\x9d'SI-\xfd\xb4\xa6-z\x94@\xda\x8e\x83\xf0\xbc\x03e\xe2yO\xae&\x12c\"\x9ekW\xdf\xdcb\\\xcd\"\xc6\xeb\xaf=\xc8\\\xc7\xaa\xf1\x81Z_|\x91\x91\xb9\x10\x13\xecc[0\xb9\xd9\xf8A\xcc!W\x16_\xab\xc6\x17\x99XI\xba\x9b\xf2\x00\xa3jc\xe90\xd5\x8c-\xf0=\x9bUR\xaaa\x02\x83\n\xf7LZ\n\x0c\xf9\xd1q\xd3\xd0\xbf\xf3\xa5\x0b\n\xfe\x94\x98\xd6\x12pX\x13\x98\x99\xc5\x01\xb8\xe4Q\x8f\xc8\x00\xfd\x86,s\xa5%)\x16I\xd0\xdbV\x8a\xee1=\xa2\x15q\x9e\xe9=\xc3\xd8t\x17r\xba\xdd=\x12\x99(J.\x8e\xb2\xab\xe7\xc5\xeb\xb2\x98\xb4\x8d9\xe5\xe7Z!<\xd0\xbdo\xbfko\xe3\xb0C\xcb\x8eY\xfey\x194uo\xa3Pu\xe7\xd0\xcb\xc8\x0e\xc5\x9d\x13\xf6\xdf9\xe1\xe7}\xe7d5\xf1\xa1\xbbu\xa4*\xdf\xd3\x85\xeb\xd6\x0b\x07\xdfNX'\x9e\x87g\n\xa8/\xab\xfb\xabb \xba\x95\x98\xb1\xf8<\xee\x96D\xec\x0ee\x06\x84GW\xa9b\x9c3\xac\x12\xe6\x07\x97dV\x16\x8a\n\xf3\x9e+4\xc5\xf2$~\xba\xf0\xe33\xc5\xf7\x01\x82\x8d\xf5\xd2\xcf\xde\x07\xc9E\xac\x92?.X\x95e\x12\x90\xe8\xe0\xd2_\xa6\x11QU;g\xd5:\xb4\xa1\xaa\xee\x12\xb85q\xc1\xe4\x01\x01\xc9gY\x98\xd2\xad\xb7*]f\xf7\xb3\xb3\xd6g|\xe9\xf8'\xe4\x02\x12\xefu\x16\x90\x8c\x04/\xfd\xb4y\xce\xe9ZG\xb4\xda\x99\xf7\x9e\x08\xe1w\x98\xe5E\x9bu\xa3\x80v\x05{p\x86]\xa8\x90\xd6)\xec\x81\x95\xe0)fw\xd3U\xcd\xef\xa3\n\xdar\x81\xc9f\xdb\xb6?H\xa2\\\x19n2\xbc\xf5(\xeb\x1b\xce\xf0B\xba\x97\xcc\nRl\xe4EF\xfc%\xbf\x08\xe9$\x98\x91k\xe4\x85q@._\xcfm+\\\xfag\xe4\x1e[\x88N\xa1_\x06a\xa2+<\x0f\x03B\x0bu,\xf0 \xdb\xd6\xe7qZ\x16*m\x03\x9f\xcb\x0c\xf6\xeb\x0b\xae\x85DOt7\x1d\x93f[\xf3\x90b\xecK\xf3;\xc1\x0e\xa1\x82V\x98t\n\xb5\xa3)\\lL;(.'\xd0\x8f*/\xae\"b\xb2^\x07\xf4\x1a\x880\x98\x07\x1d\x9d\xb6b\xf72\x026F\xeb\xdf\xfe\xf5\x8f\x96\x90}\xdf\x14\x07\x81\x0e:NN\xf0p\xea:/]\x88(\xc0\xdf|\x85\x1a\xbdfI\xba\xc1O\xb8v\xba\xf6\x17\xfc^p,\xe7#L7 iFf~\xa1\xdb\x0b\xca\x95\x0b\xbcQ\xd5\xa4\x97\x82\xfc\xb7\xd8\x0d\xd3\xf8nw\x88dj\xb8w\x9c\x12\xe1\xec\x1a\xa9\xb0\x06+\xab\xabta\x1a\xf6<6\xf2\xfeA\x98\xa7~1[<\x8f\xc3\"\xf4\xa3\xef9\xcb\xaa`J\xc4\xc3n\xff (\xf8\x12\xf1H\x13\x9c\xa0\x9f\x94\x05\x1b`\xc1\xbaz\x01\xb4\xcd\xc8\x9c\xde\x04B}E\xcehs\x13\x06\x8a\xcf\xe7\xb0\x0f\x01L`\xae\xffhU*\x15\x18\xa5\x8azu\x83\xfd\x86z\xef\x9d\n\x1f(\xa5\x1dZC<\x18p\x07\xc9 \xb24\x9d\xfd@\x05'yRf32\x81es\x04\x86\x83\xb2P5\xd3\xbbW5K>\x01_\xc1p\xcb\xfc\xf8\x04\xcan\x0dr\x99\xfaq\xf0\x8c\xa4\xc5b\x02#\x85t@\xf0\xdbJ\x01\x9c\x80\xda+a\xb8\x83$\xac\x02\xf8jA\xd8\x9c \xc2d\xe2WQ\x9f\x13&z.\xe4\\w:3Y\xfb\xa3!\x12j M\xd5\x15\x90\xd58B\x96L#\x06\xec\xdd\x19\xe8]\xe9 \xefz\x8c\xa7\x15\xe9\xa2\xad\xd2\x90\xbc\xc5\x14\xeb\x95\xb0\xaf\xad\x9e\x18g\xcc\x89\x9d\xee\xed\x05B\x98\xc8\x996\xedh\xd2L\x12\x03VJn\xf8\x17\x0b\x8dW-\xfa\xaf~\xb2\x19\xff\xd4\xd4\x81\\\xc9zS\x818X=f\xaf\xf2\x83\"i!\x04Y\xdbCQd2\x87Z\xd1nY\xbd\x8a\xd1\xc2\xcb\xd3(,l\xeb\xc7\xd8r\x86)\xd3\x15\xad\xc4\xf0\x186a\x9f\x1b\xb3\x11X\x87\x91\xe3\xfd\x94\x84\xb1m\x81\xe5\xc0:\x14`V\xe0\xf2\xcat\x10\xeaM\xa3\xb8\xaa\xa5\xa9\xf5\xc5\x06\x8d\x1d&/\xfa\xe5z\xd8\xb6\xa8\xa8\xf3\xe6=q\xdc4,\xb4#\xafF\x91\xb2\xe5#\xef\n\xf6 \xc5\xb7\x9f\x1b\xf13S\x918 /\xe8\x908!/\xe8\x908>/Pz\xbb\xcfT$N\xce\x0b:*\xcf\x88\xdb\xe9\xd6c\x9d *gf\xa0rf\x9f\x9e\xca1;e\xf6P9x\xa5\xbb=\xc2\x90U\xa1'L\xce\x18\xd3\xd3k\x88M\x9f\xd0\xcbI\xc1\xbe\xaa\xd5Hx\x06\x14gY\xee\xe3{?\x0b\xfd\xd3\x88\xa0\xc8c\x85\x0e\x85R;\xec#\xc8bn\xb3^(\xfa\xd3\x7f\x951O\xfc2\xcbH\xcc\xbf4\xd3j\xd5\xa4\xcfH\xf1\xa4(\xb2\xf0\xb4,\x88m\x05~\xe1o\x9c\xf3>\xfb\xe8\xac\xe6\xc2\xa9\xaf\x06K,\x8d\x05{\xd5\x8d\x82\x91pb\x83\xa9\x0e3\xa66\xc68AZ9\xd1\x97\x9f\xfb\xd1\x04|e\xf1\xb5f\x8f\xabE\x1f\xb4\xa3\x8c\xe3\xc0\xddd_R.\x97\x04\xac\x85\x8e\xe9/\xef\x04\xcd\xdc:\xdc\x00\xfa\xafh\x90\x08\xb4\xbd7T\x9cE8\x8c\xb3\xa8\\\x8b\x9f\x85\xc1\xcb\xa4\x8c\xdb\xc9\xff\xe0\xa32\x19\xdcB^\x0d'\xa4 \xbcH\xf9\xd3\x96\xebcZ\x08%>#\xc7\xcb,\xb2\xfa/^\x15Y\xd7Z\x8b\x1f\xc2(zKf$<\xc7\xcb2\x1f\xb0&\xbd\xa7|\xc8\xa2\xc4\xb2sJ\xdf\xc9^\x15\x1f$\x955{\xe3+\xf5\xdaS\xba\xaf\x1eqk#\xd0\xb5\xab\xf9\xceD\xc4\xd1\x15@/\x19o\x1e\xc6\x81D\xfc\x0d\xa4\xfc\niwyl\xc5F\xdf\xda6LF{h\x8c\x11Vdl\x0b\xb0b\x15`\xe9\x1b\xb3CVO`\xc9\xdc\xaa<>\xa2\x96:zu\xfa7\xb1[\xf3\xc5o>|\x80\xac\xc7\xb0\x11$\xac\xd9n\xa2\xf7Cf\x92\xda_\x0fqj\xa1P\xb7Zz\xe6\x0e\xd4\x08\xb7\xa7Ha\xb31\xf4`\xdf\xa9\xf8\xc4\x8c\xd3\xee\xfc\x98\x0f\xdc7\xcd\xe9\x1e `9\x98\xcf\xc9\xac\x08\xcf\x89\xf8\xd2\x88E\xd0\xfb\xaa}\x92{\xd5\x1d\xb2k\x94|\x92MgW{\x82\x06\x1e5\xb3\x04\x87\xc7\x14\xf4\xf2\xf0g\x0d\n\xe4c\xceo*\x14\x91\xd5|\xc2\x13L\x0d\xd8\xae\xbe\x93\xc8?%\x91\xb1\x9bE\xb1\x8c\xbeA%\xf3\x8d;aa\xd1\x8c\xbd\xd4\xea\x03\x04\xf0&y\xad\xeb0fT 3\xb7k\xda\xa2\x98\x00\xa6o\xe1\x13&p\xeb3\xa0\xe6g[\x8693:C\\!W\xd7\x03\xa7\xdb\xa8\xa7\xb3G\xf6\x8a\x841N\x8e\x905\xf5\x00\x1374\xbe\x0b\x88\xa3\xb4LY\x90`\x83\x8eP\xb7A\xd6S^\x0b\xde\xbd}1\xb1\x0c]7Dg\xa1\x9d\xe1\x8c\xb4\xb5\x17\xdb\xb5d\x8b\xd3\x0c\xd2y5|\xd8\xb4s\xd2Wk\xd89\xf9\xab\xdd\xa9}\xe0\xd5c\x89\x03z\x7f\x0d\xf1\x98\xce\x1a\xda\x06\xd4~\x1bC\xea\xf1\xdb\x95\xc4\xe5\x12\xcd\x11ns\x8e\xe9\xd3\xe2\xe8z\xaf\xf9\xfa\xec\x13\x13\xcfkZ\x8e\xc6\x14V@\x050`\xbf\x06\xa2\x03\xa8\xe2?\x92`B/\xf3\xbd=Hl$\xa6\xfa\xa9\x1c\x86\x1a\xfa\xeb \x9cc\xacH\xb1\x87\x89\xfaq`\xa2\x9fm\x88\x96\xb8}\x93\xe5\xa6\xb5\x05\xb9T\xf1s\xf2\xc3G\xccW\xa2\xcf&\x0e\x86\x83\x83\xb9\x91.\x0c\x9a\x16D\xeb\xf0Q[Ctj\xf4\x88[\xeb\x05\xee\x13\xbb\xce\xf1\xed\xe7&v\x8dtb\xd7H'v\x8dtb\xd7H'v\x8dtb\xd7\x88\x89]\xebQEL\xc0\xaa\x12\xabF\x9f^\xac:\xbb\x8dXU\x12\xac(\xa4\xa7]\xad\xadVy\xdc\x92Z\xdeJy|+\x11\xcf\x9dr?}\xbcM1\xc4)F\x19\xe9\xa3\xa6Q4\xb7\xa5\xeb\xb5\x10\xb2\xa5\x98\x81I\xdbMk\x1f\xa1w\xee1+\xa4p~\xe5\xd8\xed:\x15\xd2\x17\xb0>GI8\x962\x0fE4\xe5a\xf3\xe8\xe3\x9d\xb9\x8b\xdb\x0fYX\x90\xd7qt\xd5\xc0\xbc\xedG\xa7\xabp%\xb0\x1f\x0c\x08\x83\xa1\xb7W\xcc\xc0\x80\x96\xe9\xee\xaa\xd3g\x02\xd9\x85\x1f\x07\x11y\xbd\xea\x88[\xa0;\x14\xd0(\x10\xdf\xfb)O\xe2{\xa1W\x90\xbc\xb0\x0b\x16\xc0^\xb6\x1d\xe0yf`2\xc8\xa6\x00VY\xbe\xf6\xe17m\xaf\xbc\x91vlX\xc1\"9;\x8b\xc8\xf3\xfc \x08\x8b\xaf\x93K0$\x99\x91\x1f\x19\xbf\xb2\xb1\x0f[y\xe9\xdb~\xb9W(F5\x815\x8c'\xc0\xfe2~\xa7\xb6\xc0\x84\x1e\x98\xc7\xa46\x9d\x08W\xf2#\x8fE\xe1|!\x9e\x0e\x82\xd6W\xe5\xa7A\xa3p\xa4\xc3\xea\x14t'w{f\x1bV\xb2\xa9\x80\x15\xf8o\xfa\x08\x05u\xe3\x16\xaa/\xf1\xc1*S\x1d\xf6[\xdd\x02\x02V\xb1\x82\x001\x85\x16\x9e\xe0\xb6\x04\xf5\xdf_~\xa9\x9e\xaa-Ur\\X\x93\x1a\xab\\N\x18\x11\xd8\xf8\xb3\xd2\xeb\x0f@\x0b2d\xae\x8e\xf1o\xbc\xd4\xcf\xc2\xe0]\x1a\xf8\x85.\x08\xc2M\xd7X\xa2\x11\xf8*\xcbo\xb4\xeb\xac\xda\xa5;\x9a\xb2V\x10\x05+\x1e\x86a\xeaxXA%\x0f\x15ie\x88\xb6\"?\x99P\x9f\x0f\x101A\xa5\x9f\x1fx?\x86\x98O\xce\xfa\xba,\n\xb3c#p\xba+\xb3\xad#rY<\xc9\x88\xd2\x15M~JV}\x11\x9e-\xa2\xf0lQ0\xb0\x9a\xf4T\xe1\xee\xab\x97\x9ef\\zz\x13W\xe0\x81\xd2\xd3\x94U\xcc\x0c\xa3@\xf2\xad\x8f\"\x1f\xaa\xf0\xd5SK\x91M\xcer!9\xee\xd9'\xc7\x85s\x13\xa3a-vk\xab\xe7*o^`\x19XS\xbfo\x99fC\xe6%b\x11\xa8\x82R\xf4\xcf\xe9\xc6c\xab|\x13\xf8\x94\xdfqH\x9bX\xb8Rz\xfe\xb4\x15\x01\x15,\x17\xce\xf1_\n\xa2\x06 \x83y8\xbd|\x1e\xacd\x17\x0b\x9ck 3\x12\xe0\xed&\"b\xf6~\xc5\x08\xa2\xfa\xe0\xf5\x7f\xd1q\xae\xe8\x91\xc7\x00\xdb\xbb\xbb\xdc\xbc7~\x9e_$Y\xb0\xf2\xe6\xfd\x11\x9fO\xb1w7\xdb\x0d\xbf,\x12z\xddG\xa4\xa0\xbb\x12\x93\x8b\x8d\x94\xcfu\xc0\xd7\xb1\x08\"8\xf8\x0b\x0ea+|q\xf3\xdd_\xe8\xfdkz\xc2z\x88\xa7\x07\xdd\xe7C\xf6\x85>\x84^\x9e\x83,\xe4\xa1\nf\xda[\xd5\xe0\"\xc8\x8a\x0dF\xf4\xda\x12\x11\xb6\xe4\x94\xf8\x19\xc9\xf8\xbdj\x82\xf7\xdf\xe9\xc6\xc3\xe1\xdd\xea\xca\xbb\xf1u\x87\xd7B\xf0\xd9]u7\xba\xe6\xee\xf6\x8ac\x16\x89\x16.\xcf\xe7\x86\"\x87_m\xab\"\x9c\xbb@6w\x81h\x86#\x99\x01\x08\xc6\xe8\x7fl\xda\xa9a\x08\x81,\xfb\xeb\xd4\x11\xab\x12\x0c\xf6\xfe\xed\xd1\xd1\x1b\xccLK\xe2\x82\xcbR'P\xc6y\x99\xa6IV\x90\x80IR\x08\xa5\x97\xac\xffh\xc1:\xa4\xb0N\x7f\xddN\xfc[\x0f\xaf\x16\x017W8\xed\xb3e\x919\xf6.{\xd1\x002\xb9)c4r\xc6\xab7-\x98\xf4\x1b\xcf\xb4\xab\xccLH_+D\x0b\xb5\x1e\xd5$3c33\xf1e\x95\x82\x92\xaf\x1d\xcf\xe9\xc3\xc4e\xfd\x02$w\xb3\x00\x9d\x99\xa8\xb2\x92\x1b\xb3\xbe\xd1;'O}J\xe3\xd6\xab\xa7\x96\x1e*s\x9d\xd1\x01\x9d\x99\x00\xca\xb4\x9cd\xc8r2Q\xbby9\xd9\xc5=h9\xd9\xeau\x86l\x17\xd5\xec\x15\x06\xb7\xf54\xe5\x15\x87\x9e\x94\xbf\xe2\x11\xa4E\xefT3\x96g\xbe\x17r\xe2\x95\xa7*\x0f\xdbp\xdbK\xd0\x90\xd5\xd0\xa0\x1fL\x15\xe9G\x0d0tM\xb4k\xa9r\xbc\xfa\xf4\x07q\x05LT-\xa7j\xe4\x03\x82\xc8\x19h;\xe5)T\xc7\xa9Q\x07\x8d\xcb\xebxn\xd2\xd5\xe17\x12\x08B\x87\xa0\xba\xbd\xfa\xf2ws\xf6MZY~\xfbp\x03\x85\x82\xde\xaaYGW\xa7\x06 \x96\xf7\x95R>k\xf1\x80$\xa1\xe7\xbc\x8d+u\xe5;pKo\xea\xa2\x11[p\xb8;t\xdb\xa1\xba\x9eT6(\xc2\x9b\xd6\xa3Z4\xa4*U\xef\xfe\x8d\xe2Yw\xe5J\xffhB\x83\xed-\xbd\xd4`\xab\xc3\xd3\x87UQ\xc7\xad\xd9\xaf\x8a\x1e\xe8d\x07\xdb[\x0fu\xd2\x83\xedme\x8ckV\xf4yX\xf2\xc9\xfb\xd9lHX\x8dHym\x9aSyR\x16\x8b\xe7\x05YJ\xb9\xc7\x9b\x15\xea\xec\x0c\x93ZR\xd0\xacR\xa7\xa26\xa6<%3\x1e\xb6\xd0\x9ba?\x98\x90\xeb\xeb\xab\xe7\x01\x89\x8b\xb0\xc0\xa06b\x08\x7f&W\xa8*\xc2\xbe;\x8db`mQ\xf5i\x12\xe7\xe5\x92\xe4?0\x01\xd1JB\xfb\xdea\x17\x8aa\x8b\x0eQX\xe0\xd8Ek\xd0\x9a\xe12_\xcf#\xfft\xd0\x00\x05\n\x97\xd2\xf2\xb1\xbc\x0f\xb0\x8f\xd1\xe0z-%\xea\x0f\xbf\x0f\xf3\x10\x85'k\x9bj*\x8d>\x14FN\xfd\xd9\xfb\xba\xb2:\x1c\x14\xa2QK\xd4^uP\xdd^\x0cCR\xcd\xc00(FO\xab\xd7\xde\xec\xc2\xa5\x98\xbbzT\xca5U\xf6\xa8A\x1f\xf0\xb9j9\xf4\xbb04z\x04\xd3n%\xf1Qv\x95\x94\x05:\x07\xeb+'\xbc2\xf3g\xee\xa9\x1cr\xbd\x99X{}M\x96\xe5\xd2\x8f\xa2\xe4\xe2(\xbbz^\xbc.\x0d\x96P,\x87e\xc1\xeb\x1d\xc4\xfei\xa4\"\xd5\xc4\x83\xf1\x1f\xbc\xb9A\x0b\x12\xad\x10\x0e#\xa8\xebb\x1ag}\xcd\x05\xd6\x1c\x18L\xf6\xbc\xaa\xdc\x1b\x1fv\xc9\xb6`H(\xd9\xb3\xaa\xea\x80!\\UZ\xce\x97\xa8\xc5\xd4\xd7<\xad\x06\xfb\xc6\xa8\x13=a\xdd\x0b\xad\x8e\xbe\xe2\x05\x86e\xaeQf\x8f\xc3\xd8\x01\xab. \xa5?\xd2\xc8%\xfb\x80\x07\x85;BZZ_\xfb\x90\xd5~Z\xa1\xca\x1e\x0f\xb0\xa7\xac\xfe\xdb\xdaM\xbc\xef\x8b\xf7\xb0\x07%\xa5m\x0c>\x7fO(Q\xe5\x859e\xbe\xf4\xb5^\xc3\x1e\x9c0\x16ArS7\xcd\xee\x0d\xec\xc1\xa9\x97G\xe1\x8cP\x9c\xb51rx\x82\xef\xc6\xf7F\xe5\xdf\x8dS\xad\x1a\xb4oZ\xcd\xcd\xc7\xe8\xacO\x05w'}\x0eP\xf5\xdd\xb8\x9f\xd5\x838T>~\x155\xd3\xcc\x1c\xac\xfdX# \x02\xc5l\xc3\x82,\xc1\x82u\x9e}\x8b\xd9\x93v\xae^\n\xf7\x96\x8f\xaa\x1b]2S\xc3\xca\xac\xa0\x13\x1c\xa6\x04\xd5\xf6\xc4#2W>F\xf5ZQv\x86\x1f\xba\x9a\x9er\x0c\xd9x?\xd1~J\x83\xf9h\xdb\xd9\"\xb9\xfe17\xb3F\xedR\xcce\x17\xcd\x9bu-\x1c\x98\x06J\x18\x0d\xa2\x14\x8b\x88\xa7A3\x193=6H1]r 9K\xb3\xf1\xb4\xdd\x02*\xe5\xf5\xaf\x1b\x1e\x10r=\xf4fI\x19\x17\xf6\xad\xceD\x0b\x1c#2\xa0cmg\"7\xcf\xb0\xee$\xc4\xb8zO\x14\xe7W\xa0\xa6\xaf\x96\x0d\xa8\xb3\x18<\xe2Y\x12\xc1,\x89N\xd8\x85\x03\x8d\xdd\x8aN\xd0IK7\x13\xeb\x15\xbap}\x8aq\xc8nO\xda\xe1<\x93}\xa3\x1c\xe3\xb8\x1a\x99\x94\x06\x99P\x82\x8c:%\x9f \xee7\x9fV]\xbd\xf4S/\xcc_\xfa)\xf3\x17R\xd8\x1f\xd2\xe7\xda\x0e\xa5\x8e\x07&o\xd2\xcd\xe7\xa2\xcf\x8fh\x1e\x1bc\x95@G\xcaj\x88ZB\x1fA\xc1O\xe0\x94\xd1\x80}\xd9\x84j\xb6g\x02\x06\xfe\x80>\x99\x7f\x81W\xe6\x04z\xe2T\xa4\xac\xd6\xa2F]?\x84\xc8\x82\xf8\xb5|\xc9\xbe\xc2\xf4%\xc6v\x98\xdb\x94\xec\x94h\xae\xdf\xcc\x04\xd4\xe7\xa3#\x7f!\xa4H\xf2\x97-QV\xff\xbaK\xb2t\x03\x07%jsNo\x02\xe7}\x8b)\xb8\xb7 \xf4\x04\xd7\xaeBEN\xe0\xbd\xb6\xa2.^h#;\x1c\x06\xd8\xbb\x0b,\x7f\x13\xe31m\xc7i}\xdd\xbfJ m\x90o0\x01\xcbj\xdc\x9bm\xb2\xe6\x8e\xee\xad\x8a\"\xab\xef.\xb8\xcbY\x1e\x1a\x07\":\x9f\xf0\xb0\xe2\x98Z\xb2K\xb8\x1a\x0e\x8a\x8c!\x14,c\x1f\xc1y]-\xf5\x13\xdb\xa1\xa4\xe2\xeb:t\xab\x9e9\xb8\x93\x95\xff\x87d/oJ\x0f\xd7\xe0}\x82w=\xa3\xda_\xd7r\x01\x8c7\x80; \xfd\xa9\xbd\x81\xb9$\x03#%\x1a \x83\xa6\x87\xb1\xae\xda\xa5iN\\\xe6y&\xe2\xfb>\xade4\xdc\xff\xe8\xccmk\x8a\xafL + y\xf2 \xf05\x10\xe9\x00\x1c\xef=\xb9\xc2\x1b\xdfH\xa8\xf3\x8b\xa1_\xd8/\x9e\xa5\x97\x93\xe2mg\x06\x03r\x1c\x8bh\xf8fd\x0dm\xdcn\xacmr\x0f\x1e\xc6\xfeI\xd1<\xf9\xd2m\xa0\x06Zw\xcaM@r\x93\x83t\x17\xb8\xf1\xa9\xd1,\xb7Blo\xf4+\xd2\x08\xfc\xf8zP\xbd\xef[\xe0\\\xbd3\x01s\x9d\xf8\xa1/\xf9\xaf|i\xaf\x06\xc1\x03\xdc\xdc\xb5\xa6T\xedG\xa85W\x9be?\x84\x03W0\xcck\xea\xdb\x8e)\x0f\x19C\xe3\n3D\x9d\x12\x0f'\xb5\xe5sY\x0dr\xc0\xa9\x84\xd5h)\xf1\xf0\xc3\x9c\xd0^\x9f\xc7L5\xd4\xfba_\xa4\x90\xc1\x88g\x95 ~Fh\xa7F\x97\xab_\x03Z|t\x03\x8bo\x95\xa5\xf7\xb9\xe8M\x1dD\xb6%\xa9\xe9\xcb\xb5\xd4\x12\x01\xf5Uoi\xb8\xba\xda\xcd\x86\xbe\xac\xab\x92\x95\x94\xdb\x13\x98\xd6!SZ\xf1h\xe9\xaa\x06\x06\x1b\xaf\xf3\xcf\xd0\xa8\xc6e\xa6\x0b\x1d\x03\x16\xcc)\x95\xc1\x1e$H\xecdM\xd3\x91\xccl:\xd2\xf4\x93k\x81\xac_[\xe8\x89W\xab\x98)\x0e4\x94SZ\x83\x85\x83\x84\x9a\xbaZ\\?\xadod\xe9G\xea$\xedyq\x15\x11\x9de)%\xfb\xcf\xb2\xa4\x8c\x83\xa7I\x84\x19\xdc\xff\x7f\x0f\x1e\x9e\xce7\xb7\xbb\xf7t\xeb\xe4\x19\xc6\x92fj\x19\x9dL\"\x9c3\x1bx\xab\xdd\xa8E\x17\xdf\x92O\xfegj\x0d\xd6\x03E\xd9\x10(\xd2\xd8K5\x0dj?\xcf\xe9\x07\xdax\x16\x81\xce\x18.\xd0\x19\xc3\x05:c\xb8@g\x0c\x17\xacf\x0c\x17\xa8\x8d\xe1\x82\xda\x18\xae\xebd\x93r\x0f\x81-\xa5\xb1[\xf0\xe9\x8d\xdd\xcc)\xfe$c7\x15\xed'\x19\xbd(L\xde:\x9e\xc2\x83M\xdbn\x95Q\xf8\xf31\xbf\xe93\xae)jO\xe0\x1es\x11JPO-t\xde\xd98M.\xadc\x03}O!L\xeb%\xcc\xd7i\x8d\xf9M\x88\xe0\xc2\"\xeeX\x9a\x91\x99_\x08i\x80\x1dsI\x8e\\\xc0.\xd7>U\xda0\x86\x8e\xcd\xa7n}\xe3\xc2\xcf\xe20>3\x89\xffE\xdd\x89uW|e\xec\xfd\x94\x84\xb1m\x81^\xe8\x91\xe8{J\xbd\x97t\x16\x1d\xfa\xf3\x97kW\x86\x01\xc3Pd\xb9\xb9\xc9\xb6\x88\xa4\x94#5d\x0b#\x97\xa9\x1f\x07\xcfX\xbd\xbaoOzO\xcf\x9b:\x01\xd4\xcd\x1c!\xfb\x1c \x19_\xa6\xbf\xb3\x16\x9f\xe75\xf4\xef\x0e\x1a\x9f\xad\x83\x86\xc15C\xaf\xa8\x890\x91c\x97\x89\x02~\x93\x87\xde<\xc9\x96\xbe\xa2_\xee\x92\xc1\x03\x9a\xab\xfd1\x84K\xd7\xda\xde\x1eD\x18\xd9\xfb4\x8c\xfd\xec\x8a\xbd\xc1\xecB\xd6\xa9\x9f\x93\xddm\xf1F\xef\xa9\xc1@_\xef\xd2\xa0\xf4\xe4\xe0\x01\x12\xe7\xa12\xdd\x90\x84\xeaJ\x1eS\n\xf6\xc1\n\xe3s?\n\x03\x8b\xc9\xe0\xbbm\x86E\xd4\xfc\xa2\xd4\xd4\\E$\x9a\xdbU\xcaK:\xda|\xba\xa9\x08\xd2\xaf\x90\x07\x04a\xce\xd9\xdc\xc2\x0b\xf3g\xfc\xaf\xe6a\xf8\xcch{\xb7\xca\xbd\xdfL\xef\x0duR~\xe1\xe8\x9e+\xde\xd5u3\x92\xa7I\x9c\x13I\xea\x01R\xa6\\\xcd\xebJ\xde\xc3\xdbnEN\xd2\xb9\xcb\xc6\xf6}\x05\xd6\xd3\"\xb7P\x8b\xdc\x8c\x84R\x15\xf0\xacP\x06<\x8b\xab\x80g\x94\x88\xccX\xc0\xb3\x0c\xbe\x82\xe2\x11d\xeb\xeb\x0e\xc4\xd3\xac\x19\xf0,\xd3\x07<\xab\x15\xf0&\x92\xadJzwx\x95\x17di;M\xdb\\\xfc\xeb\xbb\x9cN\xc7HW1Z\x96\xd9e:v\xc6r\xbf2j\x96\xad8?\xde\x0d^L<\xad\xdb\xf6\x0f\xdd_\x8a\x8d\x0c\xcd\xd1J\x854\xb6\x80}\xc0\xd4\x18\xcd\x06\xacc`\x81t\x9b/\x95x\x0e)\xd5\xe7\xb1\x1d\xf3\xec\x05-XW\xc0]kl\n\x03\x88V\xd3Sag\xfa\xcc/|\x8b}\xe22\x85\x03\xcbZr\x8c}\xb78YWw\x18\xee\xaa\xffn\xe3\xa6\x81\xa8N\xeb\xdd\x8d\xa4\xd3\xba~(j\x84\xd2?\x14q\x1eT\xae\xcc\x98\xb8\xa1\xbe\xf0\x84\x0f\xb3\xd6\xc9:\x91P\x9b\x9are~\x00Ul*\xc59\xc6\x80\xa2\xfb0\x0d\x11|;s\xc2\x98\xcf.\xc4\x02\x94\xf5\x15\x9a\xe7\x0bH\x94\x13\x15S\x8b\xbc\x96\xa6\x9d\xa2\xdb\x8ei\x1b\xb3a{\x93\x0f?\xc8\x9f\xc9\xa6\xc4C6\xc5\xbc#\x03\xb7#6n\xc7\n{\x11W\xaa\xb4\xcc{\x9dq\x17\xf5\xd4\xb1\x1d\xe5\xd6t.\xed!\xfb\xe3Br\xbb\x9d {w\xc6\xef\xdb\x99\x84\xc5\xddeq>\xf7k\x84\xe2\x9b6\x8a%#\x17\xa8G_M\xb5e\x08Mn\x9d\x82\xa8\xa7\x89G\x9de\xa3\xb4}\xa2\xbcrl\xdah\xac\xd9\xb6\x81\xb1\xbai\xeb\xa5\x97\x914\xf2g\xc4\x8e\xc9\x05\xbc%g\x07\x97\xa9m\xfdb\xc1:`D\xc6k\xcb\x05\xeb\xccr:*9\n\x11\xa5\x04\x1f\xf8\xf3\xf7\xa5+\x95\xca\x8e\xd2\x8e\xedqG\n\x1a\xf2\x92Q'4\x0fSX\x8c\xb7v\x95T]\xf9;\xb2\xac\x14\xfb\xfer\xed\xb6\xa5\x82\x99\x0b\xbe\xf7\xee\xcd\xb3'G\x07'\x87\x07/\x0e\x9e\x1e\x1d<;9}\xfd\xea\xe8\xe0\xd5\xd1\xc9\xd1\xdf\xde\xfc\xfbZ\xaa\x88\xe0\xd5\x16\xf5\xf0\xcd\xebW\x87\x07\xbf\xcf\xaa\xeadR\xaa\x98\xac=\xeb\x91\xb8\x10\xeaH\xf1U\x16\x84a\xaf\x93\xef\x9f\xbc}\xfe\xe4\xeb\x17\x07w{du$\xc4 \x0c\x16{\xef\x89\xc2\xa8\xc5\x17K\xad\x069 \xef)\xef\xfe\xcc\x85\xd0H\x11b\x05\xe3V\x94.\xf8\xcd\xf5\xcdnq%\xd72\x8fQ[\xbd\x97\xf0\xd7;\x0f\xa4\xfb6\xa1\xcb\x82y\xf4\x92\xec\xc0\x9f-l\xbdh\x01\xe9>\xef^\x18\x07\xe4\xd2\xfb)gr?-\xd5Gw4\xb1U1\"\x88G.\xd3$+\xf2)#\x80R?\x9f\xf9\xd1S?'\xdf\x84\x11\xa1\xdb\xe8\xd8\x85s\x8c\x1b#.\xd1}\xe9w\xdbAH\xba~\x07-\\loo\xefR\xb2H\x8c\x03\xd7eg\xb43\xe8k\xc3\xb2\x0b\x1b\x8d\xad\xb1L\xd0\xd4\x11\xbd\xecU\x0c5*Z#\x93\xa6W P\xdfd\xc92\xcc\x91r\x89\xed\xed\x9d\xfb\x8e\x0b\x87H\x91\xd7\xa65^^\xf8Y\x91\xff\x102\x0dIlo?\xd8\x1d4\xc3\xd8~8FM\xef\xc3\x07\x9dU\xda\xde\x19\xd6F\x1fpno?TB\xe7\xf6\x8e\xca\xc0%\xb6\xef\xb7_3b\xef\xfeHZ\xe9\xe6H\xc7[\xf7\x1d\x1b\x05n.X\xf8\xaf\xd5\x83\x87P\xbbt\x82\xd2;\x9b\x08'\xb3\x13\xda\xff\xa6\xf8\xe3=ES\xf5~\x18\x92x4T\xa6'\n!|\x15\xac\xe0Da\xd7\x18W\x85\xe1\xfa\xba\x12{\xac\x11\xdcTxL\x19\x94J\x9cm\xd7s\x10\xa2\xb9\xc4\x1e\xa1MzB\x0f\x9bE\x0f;\x8b\xd3\xc6\x8d\x0cYZ\xd9\xfa\x1d\x992\x99C\xec\xe2O\x89;\xbav\xab\xcah]\xf3D\x08*Q\xd7\xc0W:\xb3Y\x17\x0e\xfe\xac\xabg\xb6E\xe2\"\x0b\x890\x9co\xc3\x8f\xbc~\xf2F\xca\x0b\xac\x8e\xd0\xd8\xfb\xa5j\xaf\xf9*\xaaP\x17\x8b\xb9\xda\xdd\x93 \x89)\xdb\xb2f\xa6\xfdoy.F;\xeas\xf1\xb0\x1d\x95\x91\x1d\x8b\x87m\xc1\xb6\x8f\x9c\xc6#\xe9,\xeflb4\xf3\xd8\x1e=tl+,H\xe6\x17\x98CV\x0f\xbb|q(,\xd5\xb3k\xa1\x82>y\x1b\xa9\x11\x11\xc6\xef\xf6U:\x9e\x98\\\x16\x142Gn;u\x00\xed.\xc4\xb6)+\x0b\xcf\xaba\xaf\xb6\xdc\x12\xc2Q\xdf\x86[\xbb\xeau\xdd\xd5\xe2\x95\xedm\x07\xf6\x95\x9coHr\xe81@N\xecv\xa2\xa1Jk\x10\xbb\xb8y!\xaa\x07\x90\xda\xadT\x079S\x16\x94\xf0\x18\xf2G\x0ed\xde\xdc&\\\x182\xcd\xd7\xd7\x8f](\xa6q[\x08!\xa8\x8c\x9b.\xd8\xfd\x91\x9a|\x18\xa9!q{g[\xb3duw\x1a8\xab)\x0e\x96wFGQ\x94l%\xf4q-#$9\x84\xcaES U\xa3\x14\x1c#\x05iBI\x1cv\xa9\xc2\xda\x9e\xde\xb5\x117\xed\x11D\xf0\x18f\x8f\xf46\xc0\xb45\x9bne>\x9d\xad\xaf\x1f;\xb4\xcd\xd2\xa9\xcdU:\x1f2\xe1S\x7f\x970[_\xef\xe9\x16\xaf\x87\x19\x841\xe4Ho\xe4\xd3\xd91\x0b+\xea\xd4r\x0f\xac\xf2\xe1\x03j\xa2\xaak\xe5\xcb/a\xa3\x19\xbbhE\x1c'a\xb3]\xd5\xa9{\xe9\x17\x0bo\xe9_v\xc1\x88\x95\x84q\x1f \xe9\x11\xba\xcd\xb0\x0dq\x1c\xf8\n6a\x9f\x9e8X\xa7C\xdc\xa4\x97 C)7F\"\xea\xf9P\xac\xbds'\xc0\xaf\x83\xfc\x10\x83\xb8SHbD\x9eM k\x0d|\xb3#\xa2\xf3k\x8dPp\xc8\x0e\x88B+\xc1\xc6\x94\xe3\xda}\xf8\x009%/\"\x14\x87\xf1X\xb4\x9c\x9a\x9d\x80\x8dr8o\xb6\xf0\xb3\xa7I@\x9e\x14v\x8ek\xbe\xb33~\xb8K\xbf\x0d\xe11\xec\xecn\x8d\x1e\xb2\x86\xd6a\x84\xe0\x87\xb6\x04\xb6\xdf\xf9\x98V`\x0d\xecn\x8d\xb1s\x9f6p\x7fk{\x8b\xf7\xcf\xeacGt'a\xc2\xdf2/\xbd\xdc\xc5N\xc6\xb4\xcc\x87\x0d\xde\xcc:\x1d\xe7\x06\x1f\xd4W_\xc1h\xd3\x81u\xd8\xdd\xd9\xd9\xda\xbd\x1b\x08\xef\xdc\x1f\x1c vu\xd8\x90\x02\x8b\x83\x12e~\xa5\x0d\x8a*\xdc\xbd7\x90\x19\x13\x1f\xb6\xc4\xf0\xc5\"K.\x802\xef\x98%\x1dO\x80\x05a\x0eqR\x00R\x00\xa7\x11Y\xd3X~dv\xc1\xa2\xf0\x11g\xc5sB/\x81\x07\xc88\x8c\xb7\xb7\xf1\xdf\xed\xdd\x87\xec\xdf\xfb[\xec\xdf\x07\xfc\xfd\x83\x9d\x0eg\xb1\xbb\xe9\x08\xaefHg\xbd\x84\xd4\xaejgd\xd2(\x99\xc6\xf6\xe8\xbec[E\xc2N\xd5\x91\x7ff!\xdbi\xfdlQVn\x9d\x82\xfc\xda\x1eX\xd3\x04o{\xf8\xf9\xd8b\x0c\xd7\xfd-\xc7\xe6\x14@\xed\xc9\x00UCV?mU\xb5\x89\xe9j\x90l\xa7\x90i\x1dK\x1ah\x0c\xa94d-\xe4\x85\\\xa3\x1c\xfe\xa6\xc32\xac\xd8\xa3\xcdQ\xbf\x0d\xf5}:I\xb5(\x9f\xae\xe3\x03\x87Y\x1e:.X\xbe\xd2\xfe\x10\x83ik{i\xf7\xd6)l\x99\x088\x9e_\xaf\xc1\xa0\xf9KDK?\x11\xa2\xb8;0)\x0d\xbb4\xc4\xd5\xf8\xa8s\x0c\xd5z0Le#\x9d\xc3*\x02\xb6\xcdTG\x02$\xd8\x86d6\x13U\x89\xf3U\xf5\xa7\xd2\xb0\xe9\x1bE\x1e\xe5\xf5|\xf56\xd7>\xcep\xdb\xf8\xc6z\xea\xc7\xff\xb1\x80Y\x12\x9f\x93\xac\x00\x0e\xe9E\x02i\x16.\xc3\"<'\x8c\xcdZ\x95\x9a\xef;\xf3\xdb\xbbm\xc91\xc3\xc6\xe3\xed-%\xcd:RJ\x15Z\xec\xd3\x03\xc1>\xdd\xff\xef\x99}\xd2\xb0\xa5\xdb\xbb\xea\x95\x1dw\xc48>\xc7\xca\x94 }~p\xf2\xe6\xed\xeb\xa3\xd7\xed\x80\x15e\x9b\xdfo\x16\xb7\xc5\x01\x9d\xf58g\xb9+\x0b\xde\x15E\\\xe1<3D\xc6@+\x0c-5\x84$w\xe1\xa1S\x90\x17\x84y\x1a\xf9W\xf4v\x88\x93\x18\xf3E\xdb\xe3\x9d\x11\x9a\xf5\x938x\xba\x08\xa3\x00Y\xb7\xc2\xcb3\xcacX?\xf9\xe7>\xf3\xe9\x9dXU\x16J\xee\xfb\xf7C\x18\x07\xc9\x85\x17$3\x14\xa18^\x92\x92\xd8F\x18\xb9\xc8\xc2\x82\xd8\xd6W\xec\xd3\xc7\xa2\x8a\xf7\xcd\x1eC\xd1_\xfdx\x8f\x17\xa1j\xd7\x9bEI\x8e\xe9\x0ds<\xc1\xdf<\x82lc\xe3\x91\x03\x01\x89HA \xaf\x01i\x1aN\xb3c\xbdMYn\xb7`H\x8dI\xf9E\xc1,8)\x9dfD\xad\x889\x95tF\\F\x11J\x90)\x15g\x97-x'\x0ecpcrA\xf9\xbef1s\xff\x8aYZ^\x82\xa6g\x98\xd5\xc2qei\xab\x90p%v|+\x9a\x7f\xa46\x1e\xec\x9c\x08\x0e\xf9\xdb\x0f\xf4\x94\x1f\xbd\x98\xff{\x90\x1d\x8cF\x0f\xd4d\xf1\xb8\x8d\xa0\xb9\xf0`w\xd7\xb1\xd7\xda\x02\x075\xca\xb8\xc1\xfd\xce\x97\xa8\xe4\x84t\x17\x17\xe0\"u_Sfiz\xacX\xf3\x98\xf2\xd5\xa5\xc3\xa4\x04>\x8a\xf31%<^\x9b\x91\x88,\xa4\xf8\xf0\x11\x14BX\xcb\xf7\x03\xbf\xa3\xa8\x01w\x83\xb9\xa8\xfc\xa7\xd0\x8e\xb0\xb5\x0f\x1f\xea\xd6\xd4[\x14\xddt\x8b\x1e>\xd4\xac$\x83N\xdb\xfa\xd9r\xd0\xd5\x82\xd2\x81\xcf\xf3\x83\xb8\\2\xbe\xc1\x96`\x18L\xe6\xd1\x82\xd2=\xac\x93\x83\xd0s\x8d\xe6;y\x1a\x85\x85ma\x8e}\xde!\xb9\xf9 \xed@\x95\xd0ti.\xa7m\xdd\xdc{'\xd3\xe0\xd6\xff]T\xf5\xdf\x92\xa8J\x83\xb2\xb6w\xdb\xef\xc3\x01\x94\x8c__\x94\xd5\xc5e\xbcN\xcfH\xf1FT|=o^\xab\x1aX$\x02\x9d\x01fp\x0e\xf1dMQ\x1b\xad\xa2\xf0)\xa9\x90\xc4y\x91\x95\xb3\"\xc9\xd0\xe4 \xc28/\xfcx\xd6-\xddo\xfe-\xdd\xbe\x93\xe6g\x1c\x0f\xec\x83\xdf6\x00_q\xfdw\xb6nz&9\xfe\xc8V\x17XT\xf7'g\x1f(;P\xb1\x0c\x0f( \xcd\x98\xca-\xc7\x15\xde\xf0[\xfc\x82E\xc6\x80'\x8f\xb5G\x9bc\xc7\xe5>\xb5\x94Z\xc0\x83\x1b\xb5\xb8\x05\xf6\xaa!kp\xd1s6\x17\xba\xb3\xa0\x13m\xe1\xe9\xe1\xe1\xdb2\"/\xc2\\\x11\xec\xe0\xe9\xe1\xe1!%M\x9f\x91Y\xe4\xb3x\xd3\xdd\x80 O\x0f\x0f\xd1\x14\x817\xd1.\x8dB\x12\x17o\xc9\xacP\x97?{\xfd\xd2X\xc8\xe6\xa2->J\xde\x93X=\xf8g~\xe1\x1fe~\x9c\xcfI\xf6\xbc Ku\x1b\xdf\x84\x91f\xe4\xdf\x1e\xbd|\xf1$\x8a\x9e&Q\xc4\"P\xa9\xab\xf4\x95\x7f\x93dK\xee\x85\xa4\xae\xc0\x9c%\xb4U^\x92 \xf4\xd53|\x19. e\x89qs\xbb_\xbe\xf2\x97$x\x95\x04\xe4\xa5\x9f*J\x93@\xb3\xebo\xfc0\x16\xe1O\xd4K\xf3&*\xcfB\xc5|\xd9{\xcdp\x0e\xbf\xff\xd3\x0b\xbc\x8a\xd4m\x1e~\xff\xa7W\xe5\xf2\x94d\xda\xe27\x98%X\x03\x0b\xb4< c\xcd\x80\x0f\xbf\xff\x93 \x90\x0e\xbf\xff\x13\x83\x94$\xd3\x80\xc9!f\\\xfb\xba\x9c\xcf\xb5\x03\xa4\x07\xe5pAH\xa1^\xd5#rY\x1ce\xfe\xec\xfdS\xddQ\xa9jh\x8a\x93rV\xad]Ur\xed\xa2+zb\x07\x945a\x94\xf89|\x05\x0b\xc1s\xc2\xf9\xfa\xba\x8aZ]\xba\x18\xc9~1=W\x18\xbcQ&4\x98\x9e)JN\x91\xacW\x95\x9c\xc0\x1e\x9cR\xa4\x7f\xaa\xba\x90\x80_\xc5'H~\x9e\xd0\xfb\xf7\xc3\x07(\xed\x13\x17f.\xa4\x8e\x0b'\xd3y\xfdn\xee\xc2\x19E~\xd33\xca\x80\xa5.\xa8\xe2\xd2 r]\xd2[=s\xe0d\xba\xc4\xcfC\xfa\xf9\xd2\x85l\xba<\xae\xc5\x9b0\x14a\xf7\n\x804J\xcb\xed\xfbj\xbe\x03\x11w\xe3\xbd_Q\x94:&n\xbc\xbd\xfb\xefv%\xff8v%z\x82\xef\xbec[e\x9c\xcf\x92\x14\xbdU\xda$\\\"\xfc\xf5T\x07\xa6\x123@2\xcd\x8e\x99R`\xe7\x01\x1a\xaff.\xfc\xa2\x97\xf6u\x98\xfaiv<%\xf4\x18\xc9\xf6\xf0\xca\x99\xe8$\xfeF\xd8\xfb\x0c\xed\\\x84\xb1\xa9/(\xa9\xf1v[\xc2\x92W\xc4V\xe35\xa7\xb0\xc6\xaa\xb8%*\x8d\xcf\x9c5\xdf\x16\xd4\xb0p%\xf7\xb7[\xaf\x03\xdez\x1b\x85,8\ni\xd7?\xe7\xef\xdb\xf6\x10K\xd6\xebN\x1b\xb5\x9c\xf1\xf7[\x8e\x97\x93\xd6\xba_\xb1\xb6\x1elvb\xe1\x9dr`m\x8f\xea\x84\xb7\xd6\x1e\xd5\x05\x7f\xdf\x1e\xd5\x01R\x9a\x95\x8c\xbeYx\x89\x85i\x96\xccH\xde\xf2D?\xc4\"\xae\x98k\x16=\x85=\xb0\xf8Gx\xceg\xf6e\xab\xd7\xf7f\x89\xee\x13\xb4\xb0\xdd\x83So\xde,xM\x0f\xc4\x9aY\xda[dW\x1a\x9eW\xe0\xc8C/#y\x12\x9d\x13\xbb\xbdz\xf2\x83\x1e\x1aM\xf6g\x8f\x1ea\xa1\x1e\xccS2C\xfcr<(\x1b\x96x\x88\xfd\xde\x85\xf7z\xd6\xf7\xba\xcb\xd2\x83d\xc7\xf0\x14\xfdQU|\x1c\xdf\x8b\xb7\xe4'F\xd9\x1e\x9c\x93\xb8p\x98\x0fK\xb1 \xb1\xfd\xde\x919\xb4\xa2\xd3\xcd5\xcc\xfcb\xb6\x00\x9cCK\xf9\xd6\x06\xbf7\xbdsF\x15\xb5V\xa8\xbcf\xaf\xa5\xf4\xbb\xe6d*m\xb5\xcd\xe21\xd0a;8\x85\xe6h[\xe0r\xd4\x87\xed@\xe8\xb9\x88w\xa2\x95\x88\xd02\xc4\xb7\xea\x0d8\xe7\xb6\xcb\xc4;\x99\xa9k\\\xe95\xaa\xf2\xd3\xe0.\x89wr\xcex\xcb\x11`\x8c\x9a\x93\x9c\xb1\x97\x9b\x8c\xb5\xac\x05K}p\xc5\x85\x995\x02M`\x1f\n/y\x0f\x13(\xbc\xb9\x1f\xf6\x84@\x87*A\x14?\x1c\xfd\xd5#^\x9d\x02\\\x7fm\x9649H\x96~\x18\xab\x17P<\xfa\x13,?%\xa5?\x124\x1b\x19\xf3\xb5[PP\xf9 \x89)\xfck\x0fF\x8e+\xe2\xff\x94H\x81\xec\xa1I\xb5\x8d\x81*f\x1e\x89\x0b\x92\xd9\\\xa7P\xda\x19\xf2\xe8\x98\xa1\xd8#\x97aas\x06\x7fm\xd3au\xf6\xd0\x1b\x81\xdbX\xefCd\x1f\xd8\x16?w\x1b\xb3\x85\x1f\xc60\xbb\x9aE\xc4B\n\x08Ma\xde\xd8\x14\x82\xf7!d\xda\xd2\x18\xfdK\"Z\x9cc\xc9\x04\"[\x91\x1dP~\x1a\xe7\xb2wYp\xfck>\x9f\x1f\x9fDd\xf7\x84\xdf\xbc6\xe0#\x88k\xd9t\xf8\xc8\x01\xdf\x8e\xa7\xe1\xfaz[9 ?\xf4\x90\xa0\x90\xdc\xad\x8e\xd5\xc8\x05\xd42\xaf\x89}z\xa9\x1b\x93\"z\xe6\xb5\xe9\xf8\xbf\xec\xc5Egl\xf1s\x03\xfd,\x1eD[(\xc4\xe5f\xfbxB\xb5\x13\xa5[\xfc\xbc\xa3\x80\xa9J\xe7\x14\x08(|\xc0C\xe0\xf0\xa3c\xea\xed\xa7\xde\xdeV\x85_54\xca\x80U-\xfa\xb7l7,\x01S\x05\x87\xa9\xaa\x02\xdf.v\x0b\x9b\x92u\x0e\x00'\x01J\xf4L\x0d>\xfa\xc6\x9dz\xd5\xbbv\xc2T\x8er\xaa\xddu)\xbc\x93\x00\xaf\x10\xfcA1\xbd\xcb\xd6\xa0\xf0N.hA\xe1x'\x94\xa2\xa7d\x85wB/\xc81\xfe\xf2\xc5W\xccG\xfdd\xc6\xed\x0d\xe9Eqd\x17(\xc40\x8e\xfc\xed\xb0\x91\xbb\x15o\xaeV\xf5\xac\xc5\xdeI\xa0\x03\x86\xb8\x9e\x14*\xcd\xf9\x9c4\xd7\xaf\xf9\xda\xa5\x9d\xb1\x1b\xb0:X\xf5\xe5\x073\xb4\xec9\xa5\xa7\x19\x89\x87\x00\xc2\"'\xd1\\\x97?\x8f>\xb8\xceo\xd0\xbcj\x7f(\xf1\x04\x12\xaf\xde\x7f\x17\x9e\\L\xc0\x90l\xb1\xaa\x16h\xd3\xb2\x8aGC\x95\x8bg\x18\xc5\"\x0c(\xe9}\xfc\x16/\x98\x11\xde\xcd\xaf\xf8\xef\xbb$\x03^\xb1\xbe\xb2\xde\xc0\xdb\x86\x9b\xdf\xa1wL\x05\xfe1\x03\xff\x11\x85\xef\xd8\x855\xddx\x87\x8d\x93\x8f\xcf<\x91\x01\xfb\xd7\xb3w\xd7\xda\xf9w\xe7\xdd\"2\xea\x1d\x7f\x8dg\xfd\xd0x`\x17<\x82\xe7\xa1\x0b\xe2PX.X'\x0b\xcbq1\xd4\xa9\x0bY\x9d\xc5\xbau*\xd4\xe0Cl\x04\x13\xd6n\x05)\xe2\xcf\x16r1.\xfa\xabf\xfe\xec\xe6\x97\xd5_\xd7.\xbb\xc4\xf5\x93d\xd2>A\xd9\xb1\xbf\xe4\x9b\x97\xbd\xc9e f h?\xfc\xeb\xbcSy!Wf\x84b= \xa7i\xdeco?\x189\xf6\xa1l[\xdb\x1e\x1f\x89\x07\x84\xfa\x17\xac\xdc\x13{)v\xcd\x9cS\xfc=\xec)\xd9T\xa6\x7f\xc6\xb3A\x19\xacf\xad\x9a3G\xba\x97br\xce\xfd \x19C\xefb\xfe\xe7\xa4\xb5&\xb3*\x07U\xb5\xc6\"Y\xcc\x89\xdf.\xcbi\xd9\x11\x9f\xc7\x1a\x05\x93Xp(\xcd}n\x9e#\x04\x97\xbe(v\x92\xc5\"\x13!\x88q\xeaa\x88kG{\xe5\xd41\xb9\x80\xecQ\x17\xba\x04U\xc8n\\\xfa\x86\xdf(\xa8'}\x8b \xd5GNU\x84Z\xe6=v2\xb0D\x86\xe6SoNwy\x88\xb2\x98\xe0\xcdv\x88\xdb\x89?}JA\x93\x0b\x16\xf4m\x82\n\xf5\xc6$\xe7\xf6\xdc\xfb\x13\xac\xc3\xdc\xfb\x01\xff\xff\x0d\xfc\x11\xd6^\xb7\x01\xf2\x8d \x8a\x0e\x1b\x1f3\x13S[\xc6\x15\xdc\xfe}\xec\xd8\xf2+\xa6v\x90L\xe0Y\xc7\x87\x8d.%|\xd3\x9e\x1b]\x9e\xbeM\x16\x04\xd2\x13\x15f\x02I\xf4\xb4\xe9V\xdc\xbe\xc3\x14\x16j@\xeb\xacS=\\\xbb\xa4+\xbc\xf6\xda1\x8e\x1a\xf7\xbbo\xd8|T\x17v)\x0eG\xb5o\x870\x81>\\\xd7\x19\xda\x9a\xfd\x9a\xc9\xeb\xb7\x1fl\x99\xa2\x85\x1ez\xcc\xea\xd9\xc3\x13d\xbf\x97\xc1\xc24-?\x8a\xfa\xa6$\x93\xaa\xea[\x8fa-\x9d\xf1\x10\x8b\x86`\x14\xdf$\xbc\x8a^d\x13\x0e\xe7T\x05\x1e\x9d\x1a\"4\x03o\xd2\x90$\x1f\xb8~m\xa4\xa7\xb1\xce).\xa7\xd7\xc8p9\xeb9\x0f\xb6\x14\xae\xaf\xf7S\x80\xe8!a\xe8\x1f\x90\x98F\xcc\xcbP =\x9b\xeb\xebn--\xa3\x10\x81(r\xf8\x08\x01;\xa6\xa4E.\x88\xf4iy\xcc0\xdf\xc6\x062\x18\x99\x1d\xf7Q\x85Z\xa6\x198\x98KM)\xeb]\xeb\x8f|\xe8\xa1-Ub\x87\xde\xf9\xd0\x8b%\xf3g\xbdg\xf7\xae\x00]\x0f\xc5\xc9\nP\xbc:luw\xbd>v`\x90\xe6i\x93\x08jw a;\x90\xd9\x89i\x07$\x14\x84?o\xa4\"dB\xaf\xf6\xd4\x91\xc7\xb4\x1b\xb6]\x05\x8a\xed\xb9\xaasmo\x0f\x98\x84\x07\xc2\xb8f\x0dk\xa7\x8f\x18\xd6\xc1\x9a@\x18\xcf\x92,\xa3\xb7u\x18\x9f'34K\xd2\xb9\x9a\xdd\xdc\xbe\xb8\xa3\x02\x14z~\xb5;\xf7\xf6}\x95\x9f\xbc\xc2\x86\xbb\xe4f\x01m\xcdc\xce\x9bi\xdb\x02F,\xb0W\xe3\xdd\xac\xe5C\xc2u\x1c\xa6\xdd\x98\xbb\x90\xaa\x08\xa8\xc0\x85\x85\x0b\xe7\xae\xb0\x07Ia\xbf_2\xd4Y\\\xf1\\\xa30Ze\xff|\xc5|Fq E-p\xeb\xd4;E\x13\x96\x0e\xdc(I\xe6\xb3\x9b\xfa!\xa20\xd5>sT\xf3C\x9dJ\x802|a\x9d\xe0<\x82\x00\x1e\xc3\xe9#8\xd5Y\x9a\xa2\x95\xe9\x92\x07\x8c\xbd\xb2}\x9b2#dzz\xecL7\x8f]XLG\x18+\xf0\xca\xc6wN\xed\xa7\xba\xc4\x9f\xb3\xca\x0cu\xd9<\x8ej\x13X\xa6\xf7\xc1da\xdcq\xea\x11\xaca\x97\xe7^L.\x0b\xdbq\xbc \x89\x89\xc6\x1a\xb7\x1alb\x9f\xbbp\xe5\xc2\x82\x07\x82\x82b\xd8\xd0\xae\x1d\xef\xeb\xb7\x07O\xfeL\xc9ezq\xbd=8z\xf7\xf6\x15\xec\xc1l\xb5C\xb6\xd3o%-\xe07\xe90\x90JFW\xe0:\xd8\x87\xc2\xa6\xf7\x14.\x7f\xcc\x97\xbfh_\\\x15\xafk\x8c,I<\xd6\xacB\xe6\x87\xe0'\xe1\xaf\x90\xa1\xd8\xb0rhs\xdb\xfa\xc6?4\x7f\x0d^\xab\xae!QR\x1b\x99Hf\xa0M@7Y\x98\x0c3\x1f\xe1+*\xcd\x11\xaf\x11;cv3L\x8c\x87\x86W\xd3\xe4\x98\x0b\xf5n&:\x8d\x1c/a\x98\xc3NuY\xa1f\x0b?\xf3g\x05\xc9\x9e\xf9\x85?Q\xba\x94q\xfb\x9c\xde\x85H\xbd\xc0/\xd0j\x8aNe\xde\x03\xdfJ$\\\xf5\xa1\x9a\x85'\xde\xdc.\xd0TOA\xf0a\x82\xb4\x12\xb9\xe0\xaeK\n\xac\x1aX\xa5\x90\xe3M\x88\xa7u\x14nLo\x18\x89\xfc\xa4%U\xed\xde\x7f\x82Y\x9b\xde?\x9ef\xc7m,\x1br\x16\xae\xef\xec'M3y`\x13`,\xd4\xac\xd3q H\x04\xe3\xaaB:\x1d\x1c\xc5\xd3\x12t\xfc\x01\xb8\xf3C#t\\fg\xde\x1bX\x87\xcc{kP1\xcd\xc3\xd8\x8f\xa2\xab\xa1\xd2w\x9f+\x8d\x93*j0\xe5\x88\xc5\x1f\x1a\xd1{\xacSr\xab\x92\xd9\xb4\xd5\xc7\xb1,\xa7\xd4\x1ab\xf3\xcfJ\xcchj;m\xbd\x8a\x89\xcc\xeal\xb4\xfc\xa8\x8c\xcb(\xebF\xa9\x8b\x8f<.\x86`V\x1b\x96^u\xf9\x11\x81\xb7\xebP\"\x02\xf7l\xb7\xc0\xf1\xd0\x00\x88E6\x18\x08\xf1\"\\\x84\xb9\x01\xdcB\xa5}\xad\xd0J\xc7\x1eACwn\x0b0\xa9\x953\x8e\x1d\xa3\xd2\xa4_M=dAc{\xfb\xc1}\xae\xa5\x7f\xc0\xff}\xd8\x8cj\xc7\xc3co?\xe4Q\xed\x1e\x8a\xf7;\xfc_\xfe\xfdC\xfe\xfdC\xf6\xfd\x0e%G\xf0\xdf\x11\xffw\xcc\xff\xdd\xe2\xffn\xf3\x7fw\xf8\xbf\xbb\xfc\xdf\xfb\xfc\xdf\x07\xfc_\xde\xde\x88\xb77\xe2\xed\x8dx{#\xde\xdeh[\x19e\x8f9\xdb\x0eY\x8b^0\x1aw\xc2x\x87U\x90J\xbc\x92\x9f\xf2\x10\x8f]\x94(WJ\x02\x82\xfe\xc1-\xc8CD\x88\xe6\x04k\xcc\xd0}\x84\xf1V\xaa\xa0\x19Ul\x91\x0e\x82\x94\x1b\xed\x83\xd0:o\x9f+\xb4\xdc8\xe9n\n?_$\xed{\x0c\xbeVL\xc0\xa2\xc2\xed\xc1z\x9d\xc8\xcf\xc78; \xc5'\xa3\xd1h{4\x1a9\"v>C\x18o\xfd\xf8\x8c\xebH\nYG\xe2\x03\xa6\xb3\x84Y\x12\x10H\xe9dtv\x96\\i]\xc0W,\xba%\xecc4 \x0cy\xca\xa2_\xae\x83m\x17\xb0\xb1\xc7\xca\x1dx\xfc\x18\x10~\n\xf8\x0f0\xda\x1co\xc3:\x8b\x99\xd9\x9b1\x17$\xfc\xcb\xb3\x0c[\xb7\xc3a\xbd`\xa6\x8b\x1b4\xda\xdcR`+\x0dPd\xfe\xc5pP`\xb15\xbc\xcc\xbf\xe0LiX\xcbnM\xe0A\x81\xa7d`\x12\xc3c(\x1f9\xc0-\xb9x\xe4\xd6bZ\xae\xaf\x1f;\x18F\xe2+&kiV\xa8\xc1\xa6<6X\xab\xf9w\xb3\xf4\xea\xeb\x83\xe2\xacM\xc7\xb6\x8a,\\Z&\x85y\x9b\x9bV-\xaa`\x059\x15\xb2u\xbb\x01\xf7\xc2\xca\x8e&\xd6\xdf\xa6:\xbc\xd4\xf6\xc3\xf6{\xba}\xd6\xd4\x82u\xf0YD\xce\xaeXS$\xdb\xfa\xff\xd3Z%\xff\xcf\xfac\x9b/\x8a\xea\xaau\xa5/\xda\xb5f\x03\xb8o\x90\x85\x12\x8aT\xb2\xc0\xc7\x1d\x0e#S\x04k\xb2\xe6O\xc9\xb1\xcd\xbc\xf3~\xfb\xf5\xff\xf8\xb7\xff\xc2\xe2\x9d\xf2\x9fX\xa6l\xe3Zs\x8b\xd3\xb5I\x98;s\x89J\xbe9\x86\xe3\xed0\xca\x807\xfe\x97_\x82\x9dLcZ;GWnA\xfbR\x94_\xca\x07\xb9e\xf9\xd2Z\x809\xec\xc1\xcc\xa3\xb0\xda\xc7\xa0\x81\x04\x8er0eT\x05\x8e\x803\xef6\xe1jE\x96]-w\xc1\xc2\xbc\xeccM\x85HTh\x11\x1ej\xc1\x82Z\x0b+\x8fT\xaem\xfdX\xfc\x18\xffx\xfe\xe3\xfc\xc7\x0c\xfe\xed_\xff\xeb\xff\xf5\xeb\x7f\xfd\xd7\xff\xf3\xb7_\x7f\xfd\xed\xd7\xff\xfc\xdb\xaf\xff\xc3o\xbf\xfe\x8f\xbf\xfd\xfa?\xfd\xf6\xeb\x7f\xf9\xed\xd7\xff\xf9\xb7_\xff\x97\xdf~\xfd_\x7f\xfb\xf5\x7f\xfb\xed\xd7\xff\xfd\xb7_\xff\x9f\xdf\xfe\xf3\xff\xfd\xff\xfe\xfa\xeb\x8f\xe5xs\xfc\x00\xff\xff\xf0\xc7rN\xe6sk\xc8\x19\xbb!M9\xde\xde\xc1(n-vF\x8f\x91g\xe2\x8a~\xd2{I\x0b\xd5q\xafm\xf3 $r\xc3 \xea\x02\x8a\x8d:\xe1%(n\xb1,\x8f\xc4\x01\xe6_Q1x\x14\xc8\xe9\xa7[\x8em\x89z\x96\x81\xa6\x11u\xfaVJ\\_\xa1X*\x17\xe4\xf6\x95\xe76V\xdcg\xf0\x18F\xb0/\xa5#\x1e\x1d\xd7\x06\xcc\xcaV2\x96\xf1\xc7\x1c\xd3\xacl\xe9Iy\xee\x1b\x11\xf9\xddN\xd0\xe493 \x18~j\x0d\xbc\x82O\xc7\xcdM\xe1\xd1\x0f\xb3DM \xf7\xdc)a\x03\xeaK\xbbd6\x15\xf9\xef\x02O\xf7\xc7J\xde_\x06\x8d0\x9eEe\xc0\x82]\xe8@C\xd4\xe9\x03\x8d\n\xed\xff\xa7D\x02\x8e\xba\x07\x0fS;\xbd\xc6\x08\x91\xab\x80\xc3\xed\x0ecc\x99\x06\xe3\x8e\x8c\xa4\xc4/&x\x83\xef:+v\xd9\xb7_\xa3\x91\x96\xb6\xb8\xa9\xb4\xb8\x0e\xdcO\x99`\x05x\xa3\xc0E\x91\x89>\xe4\xf1P[\"S\xf48\xe5a\xfaC\xd8\xdb\x83\x11\xdc\x83M\x05Ca=M\xca\xb8\xa8\x1d\xb7br\xe6\x17\xe19is\x12\x0f/\xc9\xdd\x0f\xbd(>\xc9\xd8\x93\xb8\x98%\xd1\xc78\xb2\xb4i:|\xd1\xfc\xc7<\xb6\xb4\xaf<\xfc\x99|\xbcY\xf0\xd6?\xe6$\xc2\xc2\x8f\xc2Y\xbe\xd2\x1c\x86L!\xfc\x14\x80\xb42\xf2\x19\xb4\xfa\x88\xf6\x17\x19\x99\x7f\xe4\xa5\xcf\x97~\x14\xad4\xfc!\xa3\x17\xad~\xf4\xc5\xa7\xef\xdf\xaf\x06\xfc\x83\xc6/\x9a\xfd\xf8\x13(O\xef~\xf4\xe5'\xc1\xfey\x99~\x84\xa1\xa7w4\xf4\xd8\x1e\x8d)\xb9\xbc\xf4\x8b\xd9\xc2rad\xae.\x0dfZ\xd5S\x8a?\xd5k\"\x1e\xc1\x19\x10\x93\x921\x91e\x0f(z\xa8\xd2\x99\xc5\xd3B\x9f\x19C2\xafO`_\xd8\xe11/\xaa \x9a\xc0q)o\xecL\x8bc!\xc8\xcf:qA >\xbe\xe1jrQ\xa3\xe5\xc2\xf8\x06\xeb\x99)<4`\xd0\x92\x86}K\xea7\x964\x93\x974\x1b\xb8\xa4\x12?\x91a\\\xb3\x04W\x95\xbd\xe1k\x19:,N\xd3\xdd\xadhN\xfc\xec\xdf\x01\xf4\xee\x963\x8d\xc2B \x9e\x1d\x03K\xfd: \x0dGl\x8fw\xda\xbe& D!\xdd\xd7L\xef\x86J\xb4\xae\x90\xc4\x9a\xa1\xf1\x8a\xe5\x9f\x9e\xce,\x9ew\xe2\x9e}\xea\xfc\xf1\x9eC\x99\xe3\x0f\x1f`\x1bu\x1e\x05\xc9\x8b\xba|\x7f\xe2\xdcsac$\xc2:\xd1zc\xac\xe7\x9f\xca\xb5|lH\xaa\xc4\x1a\xf3\xea:\xde\xbeC\xffkT\x92\xcb\x1d[*\xa3\xdc;-\xaf\x8a\xbd\xfd\xaaP\x05r\xe7\xdc\xf7Y\x12\xa8\xde\xb3\x9d\xfd\xfd{\x1e\xb9$3\xdb\xb2\xe8\x1c\x15P3DO\x02\x92\xad\x9a\xd0]\xaa\xe3\x06@\xd3'gOx!\xf14<\x95%\\;\x95\x8a\xfc\xedZ\"\xa7_\xab\x83\xe8\xe1\xe8\xd4\x9f\x9d3K\xff\xdc\x85\x08\xc3T\xcfY8}\x93\x93z\xc0B}\x86gq\x92\x91\xa7>\xc6\xf6\xb3B\x0b&\xf4\xda\x83uZ\xb6,\xa3\"\x8c\xc2\x18\x8b\x96\x8d\xa22\x0eQ\x11\xbf\x0fV\xd9(\xc8\x8bp\xf6\xfe\x8a\xbe\xbf\xe2\xef\xf5CX\x98}\xe4\xcf\x9b\xbbY\xc0>l\x8f\x1fn?\xdc\xbd?~\xb8\x83\xe6\xfe\x8f\x1f?65\x80\xd1g\xeb\x03O\xbc\x1c\x83\xa3\xbb\x10\xc0:Xg:\xfb\x01\x94\xfea\xd0\x06t\x8e\x90Z`J\xce%o\x876\xf2\x85\xbd\xbf\xf6\xe3\x8f\xb9c\xb9\x10\xa84\xd4\xd5\x83\xfe\xeeK\x06\x8b<\xbe\xe7\x9amG\x18y\x0cE\xcd\xb0\x0e\xf9t\xf3\xb8\x82\xf0\xc7\x80\xf1\xd5\xec\x94\x07?\xe12\xa5\x85+>p\x1c\x17\xd6\xd0\xb6\xbf!\xf1\xc2\xa4!\x9b\xc7\x95F.s\xcd\xe4O\xe3\xc1\xa9\xcf1.\x01\xcc\xe1\xab\xae\xe4{\x03\xc6\x8f`\xbe\xbe\xee\xc8;S\x8b\xd8\xe6h\xe8k\xe3\x8f=\xa5D\xbc\xf1\\;nw\xf0|9\xbe\xaaC0\xa2]\x00s\x14J\xe9\x07l%F\x0e\xcf.!-\x1b\x8b1\x1f\xb9\x90V\xad\xee\xc1\xb9\xe3|\x00\xbec,\xa3O{\xfb\xe8\xa0\xeb\xc1\xc19\xecC\xca\xcb6]8\xc7O:#hY.3\x8f\x06kS\xa0F!\xd3\xdct\xa4\x15\xb3\x07a\xb6\xe6\xa5\xd9FW\xb0\x0f\xd3c\x98\x08\x1cT g\xdb\xdc\xa0Z\xcc-\xd1\x08\x1a\xa2\xeb\x06d\xd5\x8d\x08\x01\x89\xac\x8ak\xb2*\xeb\x90U\xb1\x8a\xac\xcaV\xa5\x03\xcc\xf2\xfa\xd4\x8e\xed\xedQ[\xec\x9c\x88\x92q\xbb$\x14%;\xed\x12\x9f\x97\x8c\xee?h\x17\x95\xbchgk\xb3]\x94\xf3\xa2\xadNO\x11/\xb9?\xden\x17\xcdz\x03\xf7U)\x98\x88wrB\xf2\x97IPFD\x97C\x14$\x99\xff/\nW\x10\x8c\xbb\xc7r\xe2\xe9B\x99\xd5\xf9\xdex\x0c\x86v\x8a!o\xe1\xe7\xaf/b\x91\xbe\xb5\nC\x17s\x95\x0d3\xb6 \xdd\x84oP\x83\x10&\xa6\xf3\xcb\xa8\xe0\xa1\x99\x9a\xa0A7e\xbb\xb3Ts\xae|q\x1e\xfd\xa1z/\x96\x0eR-\x8b\xdaY;\xcc\xf4<\x18Y\xa3.E\x92\xd6Y0\xde\xdd\xd9\xdd\x1c\x05-E\x1b\xbdv\xad-o\xf4\xc0\x1b\xb7J\xe8}j\x9d\xfa\xf1OI\xab\xe0\x8c\x16\x1c\xfa\x85\x0b\xe3\x1dxR\x9e\xc1xs\xf4\x006\xefOv\xc6\x93\xf1.\xfc\xe9\xe5\x91t\x10\x86\xe9\ns\xb1\xf4\xde9\xc9\xf20\x89s\xbc*;/?|\x80_\xae]E\x89\x97_\xf8gg${\x17*\x9d\x97x\xb5 (\x02\xdd\x9e\x85\xc5[r\x1e\xb2\xf2\x85\xb2\xfcY\x98\x15W\x13\x08\xba\x85\xa7e\x18\x05G\xe1\x92\xe4\x85\xbfL'p\xd6\xad\xb2\xf4g\x8b0&\x93v\x0c\x85.\x07Ph\x1d\xaf\x82dy\x12\x06,\xcf\x94\x1ao\x06\xc9\xf2U\x12\x10S\x95<%\xb3\x89\xde\x88*\x8b&J5,/\xccMMG\xfeUR\x16\x13\xb0\xbe\xf6s\xf2\x02\xff\xd0\xb4\x14$\xb3\x83\xcb\xd4\x8f\xd9r[Q\x98\xebj.\xfd\xcbg,\xf5( \x8e\xfc3c\xff\xf30*Hf\xaa\x81\xe6\xa4~\x91d\xefp\x9e\x8b\xa2H\xf3\xc9\xbd{IL)^\x01=^\x98\xdc\xab*j\x86\xc5|\x97r\xfdB\xce\xca\xbcH\x96\xfar\x9eO\xf5uJX\xea\xaa\xe7A7\xa9N\xab.\xcfz\xf4\xac\xd4%\xbb\xaa\xea\x13\x92\xbe\x08\xe3\xf7a|\xa6\xaf\x94\xb1\xd6\x9e\xc7\x05\xc9f$-\x92\xacOc[\x7f\xc9\xb0\x97\xb2\x82f\xba\x19\xc9\xd3$\xce\xc9'\xea._$\x17\xe8\xd3M\x02\xbejj\x073\xa8q\xeb\xcb$ \xd1[\x12\x07$\xc3u\xb3\xc8\xa5\xbfL#\xa2\x83`\xe9+\x04\xe5\xe0\x19I\x8b\xc5\x04\xb4{R\xd7\xcf\x87|@\xa7ppY\x10<#\xb9~\x1fi\xbd\xa7\xc9r\x99\xc4\x83j\x97)\xc5\xc3$8,O\x97a\xc1\xa2M\xe4\x13\x98Zg\x04\xd5.i\xc9\xfeIr\xfc\x97e\xd1\xa5\xbf\x92\x94nU\x8e\xfa\x01\xe2\x07X\x89\xcb8\xad\"\xf3g\xc4\xd20\x9eiFrR\xd0>\"\x81\xb0u51C\x17\xad\xa9\xa9\x10\xc6a\x11\xfa\xd1!\xddX\xfd\xd1\x9a\xc7\x86c\x99,\xd3$\xa6|\xcb\xa4\xed<\x05jp\xa2\xfc?%\xd3\xe7^\xeag99D\xb9Y'M p\x82\x89x\x1c\x057\xf1:OF\xac)\xa5X?\xe5\xdd\xf8b\x8d\x1c\x9b\xdeq\x05\xd2\xde\xb1\xa2\xb7+\xed5\x91_\xe5\x05Y\xaa\xc8\x08\xf1T\xd8+\xf5\xf8\xcfU\x0eW\xb5M\xa9\xc7\xf7V\x03kl\x9b\xda\xb3\xd2\x8eJ\\\x1ff~U\xd4J=\xf6K\xdd\xb7x\xc4\x95\x90z\xec\x97\xb6\xb2f\xaeP\xdf\x98\xc6~X\x1d\xdd\xc5)\x1e\xbc]S\xaf\xcc\"\xfd84;\x01\xa9'C\x7f\x97@V\xc4&\xe8\xfb\xa4\xa2\xa7O)=\xdd\xaa\xdd\xfa\xbbEZ\xdb\xa7HRK\xfdS\x15\x9a\x078`\xb2\xdc#\xa5\xc0\x86\xb0\x073\xc7\x85\x13/'\x05\x1bCn\x97\x8e\x0b\x17\x02;=\xc1\x99\xe7^\x94\xf8\x01 0\x8fI\x9d=\x9d6\xb5\x16\xd3CE\x7fZ \xf2\x84\x16KQ\xb0\xe9BX\x8f\xb2\xc4y3^p\xd3\x85\xa4S\"%|ck$:.\xd3\xc0/\xc8\xbb,\xb2-\x0b\x07\xd6-|\x91\xf8A\x18\x9fQ\xe8/s\xdb\xca\xcb\x19\x06~\xd1\xd4>L\xc9\xcc\xa6\x83\xc8:\x83\xc0d)\xcdo\x82\xe4\"\xa6s\x07\x0c\xea\xc1g\xaa\x1d\"\xd6\xe8\xf4+\xda\xe0\xc5\xe8\x81#6\xc0\x81\x0b/C\xd2\xa7\xde\x14\x17\xac'i\xaa\x93\x97V\x91J\xb0\xfeI\xa8\x0d\xcd\x0f\x1c0s9\xb2\xc6\xdfK\x92] \xf8\xab\x9b\xd0\x8bR\xab\xe1\xe5bXj4\xc9\xa3\x89P\xe0\xc0T8\xbceL\x06\xd0x\x89`\xf7\xe1\x03\xf04\x1e\"k\xc7\xe1\xfb0MI\x00YM\x07\xc6 \xfc\x0bk\xe5_ \xc9\xf07\xfd\xf8_\xe0\xc2\xcf\x11\xed\x87\xf3\x90\x04\xbau\xe2x\xe8\xa2\x8b\x18\xba\xe7\xeb\x92bB\x0e\xf2L\xa6\xc8~\xbf\xcb\"\xa5\xac\x0d\xe5\x98\x8dM\xee\xbc\xa0G\x9b\x9d\xa8\xaf\xaf\xdeq\xb0Y3\xd6\xf8\xf0\xc1\xd8\x82\xe2\xfa\xc6K\xed\xb2;\x1d\nlo\xc92)\x08\xfb^M\x81\xab\xd8\x90\xd4\xeb\xbeU}\xa9`)\xe8\xa7\x9d\xd7M\x1c\xec\xc2\x01fb\xb0\x8d\xf3\xbc\xa4\xd5\\\xb8\xa0\x87\xf1@r\x03\xba\x96\x91,\xe9\xa5E\x1c2\xe1\xd8\xde\x19=\xe88\xf0\x8ev\x1c\x8f\x8b\xfd\xde\x93\xab|HC\xf5\xcau\xac\xa0\x99\xb6\xf5\xe1\xae4\xe1\xd8\x1e\xef\xdcwx\xbaM\x03\x95\xd1631\xbb\xed4\xb3s\x03\xacnX\"/C\xb3\xa3J8\x18\xdb;\x9d\xc0\xb0\xb5pq\xd2\x9fb\xb3\xb3\x03\xdc\x83\x1b\x1d\xbe[\xfbp\x7f\xdb\xf1\xe6rL\x94!-\x0e\x9cD{\x9bn7\x89\x9d1\xf3\x07\x1f\xdd\xe7~\xe4c\xeeW>\xbe\xaf\x04\xaf\xc3\xab\xe5i\x12\x0di\xbb\xd7J_\x9d\x8e\xb7\x13\n\x83G\xe9m\xe7\xb2\xe4\x913\xda[\xca\x83\xf4\xee\xb4\x83\xf1\xf2\x19\x8c\xb7\x1d\xef\xcf\x07\x7fk\x96\xb1\xd4\xa1;\xed\xf1\x88\xcc\xa1\xed\x011\x81\xf6\xc3vX\xa1\x94{\x87\xb4\x8d\x13x\xea\xd0\xb6O\xc2\xa2\x82\x94\xe6\xfbs\xfe^\x9d9tg\xdc\xae/2\x87\xb6'\xcc\xb2\x86n\xb5G\xc3R\x86\x8e\xdb\xb5Y\xc6\xd0N\xdc\x87\x0b\xbe\x9a\xed\xb9\x1e\xb0%h\x8f\xf1\x92Wo\xcf\xf5\x90\x8f\xbd]\xff)\x1bL'X\xca{\xb6\xe5\xed\xd7O\x04Bj\xbe~\x0d{\xf0\xb4\x9d$\xf4\x0d\xec\xc1\xfb\xf6\xcb#\xcc\xfb\xd9z\xf9\x12/\x08\x06\xd7\xcd\x92\xe7\xd5\xd5\xd1|\xff\x13\xec\xc1sJ.<\xafQz\xb3\x06\xbd`\x02\xdb:Y\x84A@\xe2\xb6\xca\xff-+-\x927Y\xb8\x0c\x99\xbfM\xb3\xc63\xd4\x03y)g(\x9f\xe7\x07q\xb9d!\x91\x9b\x15_\xd0\x1b\xd2\xb6r\x1c\xfd\x06c\x05\xb3\xabvs\xef\xe4Z\x9dd\xc6\x7fg\xa5I\xba\xa1\xa9\xf0\x0d\xecu\xb4I\xcd\x1a?\xeb\x02\xc2\xbcl\xd6\xfb\x1aW\xf4/\xac\xb1f\xd1\xf7\xb0\x07k_cf\x88\xaf\xa5\x8c/\xad\xbf\xbdy\x18\x07O\x17a\xd4R4|\x0b<\x82odvr\xe6w\xce}X\xdb\x83K\xfb\x0d\xf2fh\xd7\xab&\xd0\x87\xc5\xd8\x82\xba\xe17\xb2\xad\xb0Y*\xc2\x93,\xdf\xd7V\xbav\xbcn\xd0#P\x8aA\xae\x9dv\xddkG\x0eg\xa3\xb1]\x03 !\xbf\xb6\xbfQ\x9b\xd3d\x92\xac\xe2\x9biq\xec\xc2\x9b\xaa=\x1e\x10\x92 \xb7\xf9\x0d\xfd\xf9\x06\x9b\xe9\x04\xc0\xbf\x86 \xbcin\xd9\x0f\xbd|\xbb\xe0\xd9\xdf1\xaf\xf1K\xfbe\x0d\x08&\x1d%fL\xef\xaa'\x9b\xdd\x7f\x07{\xf032\xc5\x0c\xea\x1bP\xeb\x89\x9b\xbb\xb1\x88\x06\x80R4B:\x0b0\xa8\xa5F\x94\xfd\x97\xa6\x19\xfcm`l\x80\xaa\xe1=\xb1I\x7f\xb3\xff^m\xe0\x15\xcb\xe2\x02{p\xc13\xd6\xd1w\xb4$\xb1\xdf\xa1\x91\xc4>\xc6\xd7\xa9\x10\x10f\\\xa5\xfd\xbdby\x85\xa7\xaf\x8e\xa7\x053s\x11\xbf\xf7x\x0e\"\xdc\xb4Xw\x10\xea&)\x17\xb1\x89\x89\x8bT\x90\x0d\x93\xba\xc3\x0f\x1f\x18\xf4\xbdr\xe1\xc0\x1ea6uJ\xa6\xd4\xfd\xd2\xe1\x7f[\xad\x06\xfd\xb6\x86V\xd3b\xfey\x88q\xc8\x95\xd2\xf5\xad\xd6\xbc\xb3\xe0\x1fK\x9e\xe8\xb3\xa0CKXj+\x16e\x97IP\x98\x1fe\xf2\xc8\x81\xbf\xa1\xfe\x1d\xc3\x05&\x18\x06\xa60j\xdf\x8d)7\xfe4\xf88=k\x18\xaf\xe0\xc6\x13\x96\xaaP\xdb\xf3\x1a\xd6\xae\x01\x08A\x83\xe5\xf7\\K(0\x11f\xc1e\xaf\xd9\x05\xa2\xec\xda\x17\x9f\xff\xf9N\xfc\x16%\x0cz\xe8o\xbay\xe4\x18\x0b\xdbv4\xcd)~1d\x8f\x98\xdd\x05]\xff.\\\x0b)\x11\x89\xa9\x9e\x94\xff\xc8\x11{\x82\x87\xcd\x17\xb3\x8a9\x04\x7f#v+dSz7-\x0c\xe70l\xce\xaa\xae\xf73nmi\xdb/M\x81\x0d1\x08\x14=N2\xa2\xef&\xc4\xb0\x18IZ\x87{\x92\x92\xd0w\xf2b\x9c\xf3\x8cj\xa9\xca\xebw\xb3\xe1\xf5\xbb)\xf9\xe6\xbb\x9d)6\"B*\xaf\x13\xe0Y\xdajl\xc0SZ\xfe\x9d](\xcd\x03\xce\xfe\x9a\xbe:\x16\xf8\xc2\xae\x8f\xbc\xb8'\xbe\xad\x0d\xe9\x10\xa9\xab\xd2\x1d]+\xa5|H\xf2}O\xff\xf7-\xdd\xc3N.@\x18\x14I5\xa7T^\x8bXp\\\xf8\xa1\x99\xeeM\xce8h\x15I\xe5\xe3\xdd'\x04)0C\xdf\xfb?\xc8M?\xc5\xa4t_\xb8\x94E\x81=\xf8\x1bF\x90\xdby\xe8\xe0_\x87\xf8\xff\x7fF\xae|\xbc\xc3\xde\xfd\x89\xf1\xe8\xbb\xec\xaf\xbf\xf2\xfc\xc6k\x94\xdf\xdc\xc6e-\xe9\xfc-\x15\xc3`\xb9\xf4kD0\x0b\xfc\xbaWR\xf5\x83\x1d4$2t\xc4\xbe\xedc\xaa;\x1fS\xdd\xf9,[\xda\xcf\xed\xf5f ;\x91\xe8\x16Y\\V\x1d\xe7\xbfPva\xe1\xe7\xcf\xf9\x01p\xc3\xfci\x12\xcf\xfc\xe20\xcd\x88\x1f \x9b#(0\x17\x9d\x85\\n\xbd\xeb2\xd7\x0c\x97\x07\xe8u\xd1\xde\xd3\x958)W\xec\xcc\x91\x7f\xe6\x96q>KR\xda\\.LC-\xd7\xa2\x17\x01a8\xe2/\xf5!!\xe4\x91\x03\x81\xfd\x97)!\xcd\xb4\xe65\x12\"\x98\x8f*\xf0\xf2\"\xc9\xe8\xe5\x12\xf3V\nR7\x13\xd3f\xce\xed\x82L\xe3V;t\x05\x0f\x1bk\xc7Ox7B]\xbf\xfdG%;{Ao\xb5\xf5=\xb47\xdf\x87\x17\xf4TM\xd8?{\xdd\xe4\xea-\x04\xfc\x9e\\}\xd3\xdf\x15Z\xe0\x7f\x87\x16\xf8\xc6\x9c=>0\x1a\xb8\x83\x9b\xa0\x19<-\x8c\xe1\x85ZCA{z\x81t\xdc\x9e\x9c\xba\xc3H\xc6\x9799$\x05\xaa\xb1\x8d|\xda\xf7\xaa\xf0\xc0\x9d\x96\xc2e\x1a\x91!-5\x93\xcd^w\x8eJk\xa3\x19\xc3\xdb\x8dq\x84A\xd4\x07$+\xedZ%\x17\xb0\x0f\x976\xa6\xa5\xfc\xb3}\xc9h\x1d\xe3f\x07d\x1e\xc6D\xa8\xa8'\xf07CqH\xf2 \xfc\xb9Y\xe1\x8c\x14\x92\x8a\xfb\x19\xc9gY\xc8\xd4\n_\x98*\xbe\xf2\x97\xb4\xb1\x7f6\xd5a\xc7 \x9f\xc0_\x1b\xeb\x88\"\x96\xe6b\xdakx\xc5\x1a\x98|q\x11\xbel\xc7<\x16\x8c\xda4.\xa3\xe8\x18c\x99\xfdd\x0b\xba\xd3\xfa\xe5\x9a\xbf\xe9\xae\xbd\xdf1,m}\xc26\xb7\x851\x1d\x17\xac\xef\x0e_\xbfR\x04\x01\xa9\xb4\x0c+\x10?\x9cd#\xc7\x8c\xa3\x18=R\xc5\xe0\xa1,\x05\xa7\xc9\xea\xeb>ib!\xf1\xf0L\xde\x9c \x1a\x1d\xbb`\x9f\xda\x9d\xa4n\x9c\xc4\xffN\xf6\xbf9\xe3\xd5\xecb\x089.\xfaRJ\x87X\x987\xa44;\x06\xf5\x8eK\xfb-\x1c\x0d\x1a\x00\x0e$t\xect\x1a.\xfc\xc4\xb5*\xcf\xbb\xc2\x87\x06XIB\x84\xe9[$\xc6c{g\xd3\x91\x85\x0b.\xbcm\xd4cI\xb6^\xcf1_\xe8\xcb\x1aq\xb3\xbf\xfdb\xe1\x82E\xff\xb1\xf8=;\xe7j\xa6\x1a\x06\xd66\x07\xa9\x00j\xe9xG\xca)\xa2B\xa9\x93\xd8QBaU\xbd\x94\xe0\x073e\xda\xb7\x98\xc5\xe5\xed\x1a\xce(2HV\xa0\xea\xbb\\\x00O\xf1\x11\xed=\xf4\xe6,/\xcb\xe6#(kH\x8d\x1e9\x90W\x16\xe8\x94`/\xa7\x11\x12\xe5HN2\x10V\x1f`Ia\xb8\xda\x8av\x84\xdb\xc2\x9b\x90\x92]\xdd5\xfd\xe5\xda\x13\xa4D\xb3\x10\x83\x03\xd5\x86\x14\x02\x96/\xc28H.P\xc9\\\xfd\xe2BS\x05F\x84}C\xa1\xcdZ\xa0\xb8]v\x8b\xab\xb5\xa3\x83\xa88\x0c\x8akM\xd9H\xe1\x07l\xf2\x18G\\\xe58\xeb\x95n\xe9\x93\xd5T\x04\x88\xca\xda\xaa7\xf9\xbb\x18\"w\xf4Q4\xd1<\xc06\xcf\xbf\xdc\xd4\x14\x0e\x02\x00\xa6K\xb1-?\xbf\x8ag\xcfWR\xc8\x89OY\xfa\x12\xa4\xa5\x07}\xa7\xd6|\x15\xde\xe9UA^\xb0#0\xe4\\F\xdas\x89\xe9\xa5:%\x19\x96\xb4}:\xf9Ro\xd1\xdb\x13\x83/9p\x0f\xb6aC\xe2\xcd\xaf](\xbc\"\xf9\xfa\xaa <3\x9catm\x9e\xfd\xa4\xb0\xe7\xce1|\xf5\x15\x8c\x1e\xc0\x87N\x11\xac\xc3\x88\x17\x8f\xd5\xc5cV\xbc\xab.\xddr\xe8JL\xf3\xf5u\xbc\xa60\xb2\xf2.| \xe3\x9d\x9d\xf6\xfb\x07\x9d\xd7\xe3\x9d\x1d\xf8\x12Z\x89\xa4\xc6<\xc5\xb5\xb8:\xd5\x93\xd1\x0c\x96\xce\xe5\xf1c\xd8\xeev\xd2\xc2\xb6\xa3A\xbd\x8c6\x8dK\xb6\xad_\xb1\xc7\x8fa\xa6\x87wZ\xb0u\xfd\x12v\xb7\xe8\x0bko\xcfB)\xf7\x98\xb7\"\xf6\xcbf\xed\x8cq\x1f\x1e8\xb0\xaemx\xb4)Z\xa6\x80Q\xb5\xcc\xbb\x1aK]Y\xed\xa1\x0b)L7\xdc\xf4\xb5\x82\x7f\x16B\xc7D\x12>Ze\xcc8\x8f@N\x0f\xfb.\x8c\x8b\x07l\x1f\xf7\xe5?&,\x9f\x0b\xdb\x14\xeb\xc9\xd7O\x9f\x1d|\xf3\xa7o\x9f\x7f\xf7\xe7\x17/_\xbd~\xf3\x97\xb7\x87G\xef\xbe\xff\xe1\xaf\x7f\xfbg\xfft\x16\x90\xf9\xd9\"\xfc\xe9}\xb4\x8c\x93\xf4\xefY^\x94\xe7\x17\x97W?o\x8e\xc6[\xdb;\xbb\xf7\x1f<\\\xbfg\xf1h\xdc\x0c\x8f\xf8\x95t\xbe\x84\xaf \x7f\x04\xeb\xeb\xa5\x03\x19K\xc6\xedOK:\xf0\xa9/\x83r\xe9`,c\x95[[\xa4\xc7\xea\x02\xd8\xba\x84U\x01\xff\x01\xb6)\x1a\x13\x8c6E\x9e\\\x16\xf8\xc1vn\xc2\x84!f:^9mfw\x1df:\x8c_g\x8cB\xf7S9:z\xc1v \xa6\xff\xac\xef\xc1\x96\x83\x00c\x13\xba\x13\x14\xe5P\xec9\xda\xbd?\x1a\xed>\xd8d>\xf6\xd3\x92\x9e-\x06\xe9\x14\\w\xc6\xbc\x84\xa1\x0fV>>\xa6\xac\xb9\x80|;\xc4\x8cZ\x08\xff\x0f$\x98\x0f\xf1\xcd\xb8\xfdfWz\xb1\xbb\x05_B\xd8\xe6\xa9*\x8a\xa6{\x14\xaa_\xc9\xd4\xda\xb0d\x08\xdaD\x08\xda\x1dS\xd0\xb2NTE[JzC^\xcd\xc2\xcb\x88\x1f(T\x81<(\x8a\x02\x0cCW\x10\xea\x0f\xe0\x8f\x90PZ\x80b\x06\x85`\x94.\xfc\x88\xaek\xe9\xa8k\xa0\xbf>\xaeY\xb7\x8c^\xcb\x1b\xf7\xbb\xef\xd1~\x06\xf6\xb1\xe3\x11LT\x01\x0bR^e\x83\x96+\x9a\x0e\x10QR2a\xde\"w\xb8\xc3\xfe\xfa\x1e\xa4\x0c\xc3\x04\xf0%\x9f\xc3\xc6\x8cM\x02\x02x\xfcx\x0f6f\x94rX\xa7'\x18f\x18\xd8\x14\xeb\x8fwv\xe1\x8f\x10\"\xc2d\x1d\xb8 \xda\x9b\xc1\xc6\x1e\xcc_\xf9\xaf\xb8\x8c\xa7\xc0\xb6\x18x\xec\x83\x8dY\x04D1o\x92!\xef\x19j\xe9}\xd1\xd6R5\xcf?\x85\x0dX\x1c\xc3\x87=\x18\x8d\xe9\xc1:o\xddp7b\x8a\xb9\x10\xa4)\x9c\xb6\x0b\x17\xac\xda\xac\xb5#B\xe5\x96S\xb2\xb1\xab4bAj^)\xa3G$\xbcd\xac\x8c+\x81%[\xaa\xb8\x12X\xa2\x8a*A\x0b:_\xe4\xbc\xa0\x13l\x82\x99\x9a\x8e\xef\xb7U\xaf\xcc\xd6\xb4mf9\xc7ff\xad\xb7)o\\\x11\xe6\x82\xd9\x9a\xee\xec\xb6\x03]/\xaaO\x1e\xb6?\xe1\xf6\xa6\xe3v\xdfK1\xb7\xce\xac\x99\xc5\xa9&\xa0\xc3\xd5\xa7\x0f\xe8p:D\x1a&%\x1bm\x82\xca\x89IU_M\x8b(UA\x92t\x9e\xb15J\xe5{\xed\n\xb8\xd6\x88\x0d\xb4y\xdc\xd5\xcb\xab\x82\x7f\xb4\xdc\xc9\x84a\x8d\x8b\x05i\xbb@-p\xcb\xcd^\xc1\xbd\xce\xc5+\xb8\xcd\x9a\xbc\xe3L\xde\xc7\xd0\xf1@\xd6\xd7\xcb\x92\xa4x\x1eS\xd4\xd1S\x11\xe7\xfdF\xccN\xe1\xd4\x0c]M\x99xN\x932\x0e\x0e\xc5\xc45\x95\x8a$\x89N\x93K\x8d\xc34bz4\x00\xa8\\\x18\xe9\x1d\x81\x16\x01\xd5\x1b\xef4\x8c\x03\x1e\xf0\x87\x95\xa1\x82\x99\xdd<{p\xeaVn\xd63\x14r|w\xc8\xf6\x9ayUr\xe1[\xb3\x93\xfe\xb0\x85\xe2\xa9\x18s\xda\xfe\x99\xc7\xf6\xf9hQ\xc6\xef_\x86A\x10\x91\x0b?#\x8e\x1d;\x86\xc0i \x06\xf2\x12\xe1FNN\xde\x1e<{\xf7\xd7\x93g\x07\xdf\x1f\xbd~\xfd\xe2\xf0\xe4\xe0\xafG\x07\xaf\x0e\x9f\xbf~u\xf2\xf4\xf5\xcb7\xaf\x0f\x0fNNP\x87\xc7\xbcGsE$\x1c\x90\xc8\xc6M\x97\xd6D=\xe9!\xaa\xdd\xf9\x84\x12;b\xfa\x9ez\x98\\\xffS\xa5*wTf$6?\xaf\x8eXk\x0cO\xc2\xbdK\xd1\x1a\x05\xdfVN\xb5\xf8\x17?\x1e:\xadRk\xbce}$\x89\x0b\xd3\xee\xba\xbf'W\x13\xb0\xe8f\xd1\x19)\xdc\xa2\xf9\x05gTCC\xcb\xc2\x04a\xa6;\xdf\xe6\x90U\xe8\x81\x8dFLx\xc0hz}l\xd7\xd4\xa9\x07txp\xc4t\xb0\xf2\x0b=\xb0\xc9y\x80\x81\xd8&\xd0\x16\x0f\xe5}\x18t\x879\xa37\x1cJ\x91b\xc09\xfe\x1a\xc5JNC\xdb\xa8\x06KU\x9b\xdf\x94\xf1\xac\xf1-\xb1\x0b4\xa0\xd5y\xf9\xaa\x1aQ\x8c\xc0[\xfai-:\xd7jW\xe5\xa7\x1e@\xc7\xde\xb5\xfd\\;^F\x82rF\xec\x0b4\xa35\x0f\x957\xacA\xa0\xc0t4mTg\xeb\x02\x00^p\xfc\xc5qU\x8c,\x01\xb7\x06m\x1cH\x85\xfe\x03\x9a\xd7r\x1f\x00\x08\xfcF\x9b\xd6O\xf1\x9c\x07\x17U\xc0\xedX\x0b\xb7\xe3\xe6\xfd=>\xeeq\x0d\x07Nd&\xde\xc2\xcf_\xa0\xb7\xb6yD(T\xd0W\x19\n\xd3\xa8\x07T\xa9\xdf\x0b\xcf\x9f\x17${\xc1\x9d\xa7\x91\x83X\xdbt\xe1\xc0\x96J\x1cY3\x1f\x9bB:\x9a\xcf\x84\xdc\x0c?\x1e}\x1e\x12\xd52M\x14\xd9\x9f\xc5c\x82\xdc\xbb=`\xcd\x99dB\x18\xd1\x7f*\x07\xcd\x03\x00TY\x80\xeb\"\xfd4\x85\x95\x18\xb0z\xd3\xc5\xbb\xa1\xad\xf0\x18T\xba\xe3\xd13\x02\xceG\x16\x82K\xe2o\x06u\xfe|9\x81\xb9XZ}\xb5\xb7\xc4\x9f\x15\x93:H\xa2\x1as\nn\x8cqi\x12\xcf \x18\xc6\xe5\x96p\xce\xa7u{p\x92\x07\xa9\x8bX5xdw9\xb0\x01\xc2\x82!c\x87\xce\xf8\xbbo\x0c3\xcaW\x99\x91\x96\xb7Q\x0c\x14\xf6\x14q\xf7\x06\x0f\xab\x894\x07\x0c\xcdxE2b\xc4p\xef {(b`\x0bLmW\x97\x18\x9f\x99,.a\xbea\x8c|JN\x7fz\xe9\xa7\x0e\xbdA\xfa\x97\ndZ\x89\xf1\x18\x99fW\xb9\x87V+\xd6\x0f\xa9X\x93\x9a8\x1bB\xe6\xf7RH<\xc6-F\x82&\xd3\xf8x\x85H\xe0\x82\x10Y\x91\x0c\xe9J\xf8br\x013\xef\xa5\x9f\x9a\x19\x05\xe0\x84\x89\xcc\x15\xf7s\x93k\x99)\xc2\xb0\xfc\x08\x93\x80lZx\x94\x1d\x18\xd0x/\xa3\x0d\x12'u`\xc7\x8e\xc9_N~\xf8\x88\xab D \x97\x0c'\xc6/\xf5\xac(\xa8\xc4\xbe\xed\x07aO\x0d\x95\xc8\x0f\xbbm\xa8,\xe4\x08X\x9b.\x04\xde,Y\x9e\x86\xb18M\xb9\xc3r\xea\x9f\xf6&\xc97\xa3\xdf\xa3\xabt\x88L\xa8W\nC\xa6\x9b\xc7^\x91\xbcKS\x92=\xf5sb\xa3\x11P\x15+\xbeW\xec\x86\xa7\x9e\xcd\xcd\xb1\xf5H\xa2\x1aP\xacH\xe7!?\xe7<\xb6y\xac\xcc\xf8-\x1eTT;\xf28\x92&}\x9c\xc1:\xc5u\xa1\x9aU\xba\xcd\xa5L\xc9\x13A+\x0f\xd8\x80!\xb72\xdfN\xdb\xca\xab\x86o7@N\xef\xdfbx\x02\x915\xc7\xe7\xf3v\x07\x82\x05^\x06d\xc5\xcb\xa0\x03T\xc4`\xd6\xa2z\x1a\x02\x06\x8a^\x1c\x13\xa0\x14\x9dL\xe0\xf2\xa3a\xb5o ?j\xeel\xc0n\xf5\x9ef\xba]\xc3\x98\xd1\x06_\xa8\xf2W\x07\xdd\x86\xc6\xcd\xfd\xe8\xbfpi\xaf*\xac0\x8d\xeb\x0c\x0e\x1b\xf7\x9dc\xef\"\xf3S>\xa4\xdeK:\xe3\xf8U\x03h\x03\x04\xbe\xe2\x0e\xca\xa6q\xcf\xb5\xc6\xbbD\xe3K\x14\x10 A\x91\x9d0\x1f\x17\xb4UL\x8e\x1d\n]m\x9ad\xc8P@Z\xaa\xde\xa3\xd9~\xc4\xbd\x88\x87\xa3!\xaci\xa9:\x14Q\xc4t\x8fB\xbf\xd8~\x90\x90\x90\xcfY\xe6\xc8\x16\x89\x92\x87\xb2\xb4\xad\x10\x13\x12\xe4P$\x954\xaa\x96\xd2\x16\x0b\xbf\xe0\xafs\xf0\xb1\x91\xaa\xcc\x0e \x14\x0b\x02\x17\xec\xe4\x00CD\x8e\x0e\x11\xc9\x0f\xef\xe8\xc0\xcez$\xdd<\xf0\xe67\xbcO)\x88\x08\xbd\xafM$\x82\xb6\xf8n\xf1\xc4*\xd7\x8e Q\n\xa2\xce\x8c,\xb26\xb2\xa8%D\xfd\x01\x0e\x9a'S\xce\xa5\xa3J\xe7%?\xe2TN3 9<4)\x16A\xb87)qL\xc2\xd0J5\xf8^\xc4\x12v\x10K\xb1\xc2\xf0A\x16\xcaO\xb3a\x88\xc5\xef\"\x16\x9f!\x16\xb4x\xf5\x99M\xaa\x82\xd9\xe9\x1d\nH\x14\xd5\xca\x88\xa5\xb2\xbe\x0d\x15\x1c\x0d3Mb\x83\x0d\x1dn#\xcdlr\xc3GP\xae\xaf;h\x0e\xdd\xe0M\xca\x9e\xe5\x10\x8f@\xf1\xc8\xcf\x990\xda\x94\xcb\x8b\x9e\xc7v\xe2\x1cS\x8e{\xe6\x17\xb6\xaf \xad\xdb\xcfM\x10\\hBp\x02\xc0~?\x0c\x17\xf6\xa1\xb7\xc2\x80\xde\xd4<\x0e\x08\xf4\xa6a\x81n\x87\xdeP\xca7\x08\x99\x0d\x90\x94fM\x0b\x17\x15.X]^\xd0\x14\x08\x10\njL\xec\xad^\x0e\xf7v\xe2\xbe\xa6|\xfd\x1fg]\x06#\x16\xc1m\xb3C\xabr\x11\x15\xcf\xf5G\\\xe3o\xe2\x01K{c\x99\xe5\xc4+\x93\xc7z\xeaV\x83\x92\xaa\xb05<\xb6\xf9\xbe~\xf4\xd0\x96,\x8b\xb2[m\xce\x9d\xd2jJz\xaa\xd2\x98T\x14\x99\xb3\xa2\x84EEa\xf5RFz6\xb0\x97\xc1\xe1-\xf4\x1e/\xf9ix\x84u\xc9\x8f\xb0\"?2\xa7\x8a\xe6\xe4\xc3W\x90=\x02\x9f\x92\x1f\xe1\xd4o\x92\x1f\xfe\x00\xf2\xe3\x9c\xa7C=\xb0cAl`*$\x0d\xa9\x11\x1a\x93W\xf2\x87O^i\\\x81\x89(m\xd6c\xe9\xd8\x85\xcd\xa2\xca\x1b\xdb4X\xd7|\x14q\xc5] )\x08\xc6\xe6\xfa\xf0\xa1\xa3\xf1\x13jt\xf5R\xcah\xca\xab\x85[\xed\xc8\x1d\xe2Q\x9f\x18\x99\x84\x1f\x80nl4(<\x0d\xc5\xbc\x9ff\xc4\xa7\x07\xcd\xa9\x10\x17\x90\xc1\xa6 \xd2\xc6\xd7\xce\x8b\x85\x99\xcd\xe8k\x1a\xe4\xeb\xb4\xe8\xb3\xe1\x82\x017\x9b\xfc\x08\xe9\x1f\x05\xfd~\xf8\xd6\xbb\xff\xb7\x1f\x94(\xdeB*!\"\x06\x0cZ\x1e\xe0\x1d\x0e\xabI\x1f\xba5\x138\xf7^\x1d\xfcpr\xf4\xed\xdb\xd7?\xbc:9x\xfb\xb6_\x03#\x1e\xcc\x80\xa0\xcf\x92\xa5zR\xff*J\xfc\x80\xa5\xf8Y\xc8j\x84AM\x98\xb5\x1bX\x03\xe6a\xecG\xd1\xd0-\x12@\xd5[\xd9\xdc\xb5\xc9\x02\xb0p\xb42\xd7[b\xaa\x97~\xca(\xe8\xe4M\x96\xa4C\x90\xd5\x10\xf9\xb7\x11\xcf\xf4\xb6\x04M\xac\xd2\xb2\xe3!\x03H\x9a\xdb.\xc93\x8e^\x87\xaf\xca \x92q\xd8\xb2\x0c!\xee\xec\xa6\x87\x02\x8a\xe5\x0dVL\xc8\x81\xd5VG:P\xea[\xb6c\xfam\xf5\xea\xdaV:\xaa\\hCG\xddZ\xc5\xab2\x02-\xd4\x0d\x9b\xac\xa2\x1b\x0d\x8fT\xde!\x0dA\x860\x03\x95\xb4\"\x83\xea\xcbF\x9a\xcd\xea\x05\n\xd8j\x96\x04)\x9a\xd6\xd5\xd6\xaa2\x80Z\x15T*\x91\xc8r\xe6\x1a$\x91\xf0*\xf9\x1a\x067\xe8H\xe9\xf7\xc1n}\x89&\xb6\x9c\x8c\x9b\xc6\x14\x18x\xf4\xea\xf6`\xa7\xd91\x86\x95\xc1yu\x1b\x99&.\xc4\xc7\xc6\xaf\x9bp\xa7\xd0\x19\xb7\xbe\x91\x13\xfdk\x9a\xd5\xba\xee\xcb\x8c}w[\xdb\xbb\xaa\x8a\xa1Y;\xddC\x18\x9b]B\x98\xa261$\xe5ow\x18V\xa9\xa3\x1aoe\xd5\x8f6\xc2.\xc8\xb2\xd5a\xca\xa2j.%\x9d\x8b\xdfG6\x9c\xf3,K~\xaf\xa8\xb2 `9\x93\xd6\xd2O\xa7\xf9\xb1+$\x9fye\xb1\xde\xd8\x96\xee\x9bir\xac|)O\xb2\xb7\x02\xed\x13\xe3z\xf4Ub\xf3\x13\xb0\xdfW\xdd LU_\xf2}\x88W\x8d\xf4I#2\xa1*J\xc4\x81>Z\xc6\xaa\x9e$*\x9c\xe9xQr\x86\x02]\x850$\x96\x93\xa9\xef1Ij\xcb\xf7\xc3D\xec\x0b'F#\xb1\xa0'\xa3\xa5\xb0\x98*N8\xab8\xe1B\x84\x12\x7f\x04 |\x05\xc5#H('\x9cQ\xf8\x92W@wb\x05\x82GcpN\xa7\x13\x17\xa6\xf4\xba\xaf\x00&SY\xae\x0c\x8d\xe5\x85\x11C\x9a\x19\xc3\x08\xcfE\xd7\x036\xd7\x7f\xe8\xfe\x92\x13\x8d\x9f\xe0\xdb\xdeX];[c\x85\x17\xb0\x9c\x14\xa9.U\x07\xc8S{\xca \x9dE\xdbI\x99\xb4\xa3\xca_\x0f\x19g=\xae\xf1\xa64\xdc\xcc\xce0\xcce\xc6b\x86\xb2|7\xda\xb8\xa1\xedX\x9e\x98+\xc5\x9b\xd7#q\x86\x0c\x85.\xd9\xb6)\x87\x94\x9f\xe7\xe1Y<\xa4\xa9\xfeY\xe9'\xc3z\x99`\"\x98-g\xc59\x98\x93\x0c\xc9\xa7\xf2Z\xbd\xfb\xd9\xed{\xa1\xeb\xd8\xf6\x9ef\xb1\x055\xc1\x1a\xb7\xd4\xb9\x8cv\xb6\xdaYyJ\xcc\x1aP\\$O\xf8\x01\x7f\x93$\x11i\xa5{\xc3Yx\xf3\xa4\xccL\xb5\"\xd8\x83{?\xde[\xbfw\xa6\"\x86gZ\xbfi\xdb\xb2`\x1d\xd0\"\x13MG\xed\xc8\x05\xeb\x8b/\xefYf\x94>W\xca>Q\xd0C\xeb\xf0\xfc\x1c\xf4\xcfY\x12\x17\xe4\xb2`1<\xf9\x9b2\xa6\x7fo\x1a{Hu\xe7Ul\x0b\xc1\x9e\xba\x18_\xd0\x9e\xd8m\x0b\xd33_\x99\x84\x19\x0f\xb1\x81\xac\xaf\x9bg\x1aHaI\x94\xf3\xcdH\xce\xf0\x98\x98\xf1{r\xf5&#\xf3\xf0R\x9a3_\x94\xb8\xb3(\xd9J\x8b\xb2\xe8_\x146\x9c\xee\xb2\xf8XZ\x8d\xad[\xa14\xaci.\xafi\xb7\x98\x02_\xc9\xd66o\xadms\x03\x9a\xc4WD\xa9\xfbs\nq\x19\xaeo\xe8\x15\x0b\xbfx\xcb\xd4\xac\x02\xd8)\x05\xcf\x13\x9e\x02\xcb\xe1\x98xa\xfe\xbd\x1f\x85\xc1ADh\x0d\xda\x0e}\x1f1\xc6 Jb\xf2$\x0e\xde2x\xfe3\xb9\xa2\x1d\xf8\xb0\x0e\xf6ZD\xe7\xcf\xe2\x9e MF\xff\xa2T\x01{\xbf\x0f\x96\x05\x13\x98\xd9\xf8\xa7\x03\xeb`\xdd\xb3\x1c\x0cU\xe8\xb8\"\xf0n\xe4\x98\xc1\xe5\xdc\xee\x0f\xcf\x04{`Y\xcd\x85\x113dq\xb9h\x8d\x19e\xc0\xd9\x10\xba\x1c\x03\xdd\xab\x802\xd2\x88\n\x02\xbb\xc0([\xd8a\xb3\xb2O\x87\xb3p\xa1\xa4\\\x92\x97\x91\x88\xf89\xb1K\xf3\x1c\x96=We\xe3\xce\xaf\xef\xf4\xb9\x14P7 \"\x95\x81I\xcd\xd88\x1a(\xaco\x9d\x8e\xc6\xcb\xce\x01\xa1\x9b\xe2\x07\x01]\x830>;J\xec\xb9\x98\xe8\x8d\x06R\x1dd\xa9W\xf9,K\xaf\xefp\xcc\x81\x0by\x8b\xae9\xeb\xc8>\xe7Iv\xe0\xcf\x16\x93^b\x06\x84-7\xb3\xb5\x96\xa2\xac+\xec\xc5\xabk\xb4 I*\xb7f\x84\xa3\x94\x85\x84\x9aWp\xd4\x8e\xc3\xdc\xc4\x0cK?\xfdH\x03\x9e*\xa8`\xfe\x15\x9e\xbf\xcc\x15\xbb\xc0\x9c\x8f\x8diJ\x96~\xfa<.\x92\x1f\xc2b\xf1g\xb1\xdb\x98?5\xf6\xa3 \x9c7+\xe3\x8e\x0e\xd0\x00\xf2\xd1\xe0\xb2-\xd9h\x8ckU$\x88\x12\xfb$y\x82\x95\xe8[\x80B,\x80\x1a\xa5vRg\xd5\xf0\xa9\xa6\xa2\xce\xf0\xed-\xa9\xa8\xd1f\x9b.\xc2\xc0\x7f\xb1\xfd\xc0\xe9\xb34\x16)U<\x91R\x85B+g\xa3\x86H<\x9b\xdf\xa5I\xda\xa3\x83b\xa7\x17\xfdjY(\x16Epr\xdd\x06\xc4\xe4\x02\xbf\xef$gP\xd0\x8a\xe6Y7R\x85\xd1&1)\x8fm\x8dw0\xc7\x85\x84\xdb*\x1fN\xc5\xfaPv\x92\x16\xa5I\x12\x1d\x86?\xd7n\x9d\xcd5\xa1\x97\x9b9\x9d\x04\xa5 \x92.\x01\xdb\x1d\xb7\x8c\xdf\x06\x9c\x15\x90\xc5`\xc6m\x89\x1bc\xe61%\xe3\x1a{\x01g\xf0}\xfa\xb6\x9a/K\xc7T\xfd\xb9\x07#L\xc6$\xb0\x18\xec\xd1\xbbS\x91\x9bIAZ\xc6\xa4I\x83O\xda\x0bB\x9f\x0e=?p\x0dn\x02\xe4 \xad\xddJ\x80\x0e*`\x8fyl~\xd5r\x80\x12\xe6A\x05\xf7\x9dT\x15\xa0^\xceb\x91\x91\xce\x82\x0e\xb90\xe0\x96\xab\x95\xdd\xc9je\xae\xf0\xcb\xeb\\1\xe2\x19\xbe`\xcax\x1e\x8a5\xeb\xf2\x81\xdd%3\x98\x91\xdcf\xd5\x92;Y\xb5\xa4Z5FM\xa8\x9d\xc0VZ\xb8NB\x88n\x0b\x9a{\x8d\x99k|\xac{m\x9b\xa5Z\x1e\xef\xdeW\xc5\xa2\x8b\xed\x9d\xadv\"]\xbf\xbe\x10c{g\xbb\x13^\xaed\xe5\x0f\x1d\x17,\xaf\x9d\xc6\x95N\xc8\x9aX\x9ax\xc5\n\xc4#\x08-\x0c \xd2\xcdx\x80\xef\x05cB8\x8b\xe4{$\x9f\xf9)\xb1 c\x92&\x18Z\x9e\xe5Q\xb0\xb7v\xdb\xd22\xb8\x990\xae\xa2\x06y\xdc\xccj\"\x84\xc7w\x9a\xb90\xd7\x11H\xa9\x8bq\xf2\x84\xb9F\x1761_I#05\x86\x91\xfd\x12\xacSz\xa2\xfcX\xbc\x12YP\x90|sk\x07F\xbcd,\x16\xab\xd9\xc27X\xd7\x8a\xcb\xe5)\xc9\xe47\xf5\xaa\xf2.\n\xef\x8b/\xf8\xc8\xd0\x15\xb2\"wg\x94{)\\\xca\x83\xb2\x00\xcd\xfbP\xc2: \x05\xb2\x89L\xb0\xe3\xc2HM\x13/0\xc6\xa5\xf2\xc8\x9c#\xb3)59\x81\x18\xd6A\xa1y\xa1\xab\xd2\xe4\xcf\x0b\x8d\x06\xa1\x92j/\x99\xc4zII\x8c*\xbc\xf6r}\xdd\x81\x05\xac\xef\x01\xb1S\xba\x0f\xd3\xe5\xb1\x0b\xe78\x97\xd4\x85\xa5\xc3w\xaf;\x02Ml[\x90\xd8\xa2P\x99\x8d\x10\xf8\xf0\xcf\xfaP\xd8\x95\x8b\xd1\x04\xcf8m\xd7\x13Z\xe6\x0c\xc1\xa0\xf0H\\d!\xe91s\xa9\x16\xe5\x84-\xca\x9a}\x05{p\xea\xc5\xe4\xb2\xb0\x1d\xc7\x0b\x12L\x1d&-\xcc\x15K;#\xad\xcd\xc9\xfa\xba~u\xc4CW\xa9\x7f$\xda\x01\xe8\x17H\x91i\xd2\x8e\xe1\xae\xcdSU(\x92P\xdd\xc1\xca4\xc7\xca\x0e\xc2P\x0e_\x0d\xc6\xd6\x9e5\x01koS\x03\xc1\xd6\x04\x8b\xc7V\x17J\xb4\xf2\x02\xeb\x0b\n\x93\x1d5\xc0\xbd\xe9\xde\xe4\xf8\xdeY\x1fc.5TL\xc9q\xb7_#GY\xc6w\xb3(\x9b8m\xdd\xa2\xec\x8di\xf1d\x95Ea\xcba[\x1e;\xccd\xba\x89\x1az\xbaV\xeco\xd4D\x13//O\x19\x15`\x8f\xd1\x97Pz1r\x1ci5\xed\xbd\xcd\x0f{c\xe7\xee\x17\xb4\x86W\xf5\xd9\xb9\x13\xfd\xd7\xfd]\x87\xc7\xe8\xfc\xc6\x9f\x15Iv\xd5=\xc5\n)\xc0\x84\xa2H\xbfM\xa5b\xd1\xe9i\xc6JOO3e\x85 \xc8H\x9e\xb3:\xec\xb7\xb2ZFx/\x19Qw\x94\x15\xe1,\"\xbc\x0e\xfeVV\xcb\xc3\x80W\xa2\xbf\x94U\xca LX\x15\xfaKU\xe5\x14\x8bO\x95E~\xce\xda\xa7?\x94\x15\x82\x90\x95\x07\xa1\xba8\xe1\xc5\xea\x9e\xc33V\x1c\x9e)\x8b\xa3d\xf6\xfe\xefeR\xf01T\x7f*+'\xc1\x15\xab\x96\x04W\xca\nl\xeb\xd4\x1bwZ\x16E\x12\xb3\n\xf8SUi\xe6\xc7\xe7>\xdb\\\xf6S])\xa5\xe0\xcak\xe1oe\xb5\x90\xcf\x8a\xfePVH\xf8\xd6\xd2\x1f\xea\n\x11/\x8f4\xc5gYR\xa6\xa2\x0e\xfe\xa1\xaa\x18\xf8\x05\x03F\xfaCW!\n\xf3\xa2\xaaD\xffPV\x0cX\x95@YH\xd8p\x03\xa2\x1cn@\n?\x8cr^\x05\x7f+\xab\xcd\xd9\xca\x06s\xe5\xaa\x06\xa1\x1f%\x0c\xa6\xd8Ou\xa5s^\xe3\\Y\xcc\xc7\xa9\x1e&_\x05\xe5\xfc\xc9\x12\x0b\xc9R]xJ\x02^~J\x94K4\x0fI\x14`\xd2\xe7\xcc\xb6\xc4\x1f\xea\x8ag2\x98\xd5\x7fj*\x97\x19\x11\x15\xcbL L\xf3$\xc1\\\xb5\xff\x1f{o\xda\x1d7\x92$\x08\xbe\xdd\x8f\xf5+\x9c\xf1\xaa% \x03\x0c1H\x89\x94B\xa2\xd8J%\xb3[\xdd\x99\x92FRVMw0\x8a Fx0PB\x00Q8xdQ\xef\xf5\xcc\xec\xdc\xf7\xee\\=\xf7\xd9\xb3;\xf7\xb1\xc7\xec\xce\xf4\xf4\x87\xce\xfc#\xf3\x07\xf6/\xecs3w\xc0\x017\x07\x10$\x95U\xbbo\xf1\x81D\xf8\x05wssss3s3Q\x08^\xe9B\xc9R\x16I\xc81.\x86\x90\xbd\x18\x92\x99\xdb\x98\xb9Mf\xee`\xe6\x0e\x99y\x1f3\xef\x93\x99\x0f0\xf3\x01\x99\xb9\x8b\x99\xbbd&\xf7qB\xc4\x8b\xad\x80\x04\n\xbe\x92\x85\xcaU\xb6\xb0\xae\xb1\x85l\x85n![\"\xca\x89\x17\xaa\x00\x92X\x92\xc0\x06\xf3\xc4_\xe2\xe4\xe2+Yh\x89K\"X\x92\xeb!\x88V9\xe2\x1c\xbc\xd1ERY\x80\\\x95\xefO\x10\x90\xefOH8\xbe\xe7\x97\xa7\x1cQ\x15_\xa9B\xa1\x7f\")\x04\xbc\x91E\xf8)\x8f\xf0K\xf8J\x16Bh\x85$\xb8\xc2 z/\xb3\xa3\xf7T\x81\xa5\x1f`G\xc5\x0b]`%\xf3\xc9\x89^\xfa\xc9{\x99\x9f\xd0\x1f\xe0Q\x8e\x05x\x94\xdb\n\x04\x99$%\xea\x07]P\xd2m\xf1b) \xb1\x17\xde\xa8\"\x91\x8f\xa40\xf2IR\x18\xc5\x18M\x19\xcb\xc8\x1fTA<0B1y\xac\xa5\n\xe1\xf4\xd2\xdbU\xbc\xca\xca\x85\xa4~X\n*\xba\x17[i^\x9cg\n\xa7\xf1\x95*\x84\xdf\"?\xb2\xf2\x13\x1fg\x00\xde\xc8\"\xc14StU\xbe\x93\xc5T\x11[v|Zp\x8c\xea\x07U\xf0gP\xe2gTV\x82\x03I\xc8\x91$\x08\x85\x84\x84@\x92\x9f \xcf$^\xa8\x02\xd8/\xb2C\xa9\xbf\xc4\xef\x8a\x17\xb2@\x89:v\xc4I\xf9\xb4\x98N\xf9N\x17\x0b\x15~\xe1+Yh\xe9\x87\x88b\xf0F\x16\x89\xf3d\x8a\x13\x82\xafd\xa1\x95/;\xb4\xf2\xe9\xdedI\x1c!I\xc5W\xba\xd0\xa5d\xe0\xe1\x8d,\x92#\xeb\x9d\xe6$\xf3\x9d\xe6\xcb\xa5\x9f\\\xca\"\xf0N\x17\x93\xf3@\xaf\x97\xcc?\x91\xfd\xc80R,Q\xa4\xe0\x9d3\x1b\xf3\x9c!\xd9\xcdH\x92\x9b\xf1\x8b\xac8\xd2\xa8\x1fdA\xc1[`)\xf1F\x16Y`\xfe\x82\xceT[vf\xdb\xb3\xb3@n\x87\xe2\x85.\x90)x\x887\xb2\x08R\xcd\x8c$\x99Y\xe2O\xdf\xcb|\x7fJ\xd2x$\xf0$u\xcf\x11As\x12;\xcf|\xfc\xf0\x99O~\xf9,\x98qW\xfc\xfa\x9c$\x11<\x0c\x83\x95<@\xcaw\xaa\x18\xae$\x9a5Y\xfa\xa7\x92\xbb\x11oT\x910\x88\xb0\x84x\xb1\x15\xf0\x93_K\xfcY\xc0\xa3\xac(Z&Q\x95\x96~\xaa\xf6\xf1\x94\x9c\xe3\x95\x82\xd0\xca\x02\x9d\x95\x9fe<\x89T\x19\xf1N\x16\x8b\xc3\xcbSI\x00\xe5\xbb\xadX1R\xf5\x83*(\xc6\xe4\x87\x95\xd1V\x93\xc8J\x8a\xb8&6\xd2\x9a\xc5\x92\xc8d1M\xec\xcf$=<#\xe7Q\x10\x85\x82:\x90\x05\n\xa2\x9b!\xd5\xad\x94\xb0\xc8\x88P\x05{\x0b2\xa2\xaa]f\xb5w2\x1a\xfb\xae\x1e|\xac\xd2 eMv\xc3~\x18\xc6\xd7\xf8\xe1\xba\xe95j`)\xfdk\xe4\x0c\xeb\xe1\xb5r\xd9\xf7zq\xb4\xa8\x7fp\xff\xbeeL\x8df\x1f\xcal\xe3&\xf2s&\x8doi\x19\xba\xfa\xcaT\x94x\xf2\xc4\x8f\xe2\xe8r\x19\xe7\xe9\xd3\xa7\x84\xa8tn\x95\xaf\xfah\x99v\xe6\xf4\xe0\x8dB;\x06\x82#\xc1\x98\x9e9\x85\x12\xd5RN\x0c\x17\xca\x15\xe3\xb6\x14Dm*\x14\x95\x8aUKA\xc55\x9f5q\xcd\x0c\x19\x8e@0\x1cg\x8eR\xde\xda\n\x02\xd0\xb1 \xbc\xda\n\xfa\xd1\xe5\x88-\x9cD7\xb3{ \xdab;(_\xcd\xdb\xe4\xdd\xeaQ\x9a\x9c\xaa\x7f\x1fk|\xcc\xfaS\xd3wh\xb7\x9a\\\xdd\x94b\xe6\xf4\xd4U\x13\xf6u\x8f\xf5!8j\xefk\x16\xcf\xcbx]\x98\x91`\xc6\xc2OY \x03\x16\x8b\x9a\xef.W\x9cEq\xe6\x83\x8a>\x88\xd2`\xc6\xd5P\x07m~\xb0\xce\xe4\xbd\xc0\xac\xd5\x99#\xdcn\xad;[k\x83\x01\x93\x9f\x00+F\xc7\xef\xee\xf4CBF\x05f\x16\xc3\x8f\xc5\xf0\xeb \x12 \xc5\xb4\x14\xd3\xd2|\xb5\n\x03>cY\xacC\xcdc\xfcb\xc5\xa7\x19\x9f1?B\xe8\x0c\x08g\xb1\xfa\xd3|Q\xbfP8\x87\xa8p\x0e\xd9\x13-\xc8u\xd8\xefw\x05\x0d\xdc\xd6p|\x8f\x85\x05f\x89\x1e\x8fE\xdfC\xf16\xe9y,\xef\x0091AS\xddf\x11.\xe5\x95\x16\x0e7\x18,ey^\x7fl>T\xe8\xa5\xc8q\x93\xea\xe0Q\x80\xdd|%\xae\x89\xe4|\x0d\xc4\xce?>b\xe7\x9d\x11\x9b\xa5At\x1ar\x8c\xbf \xd9\x80\x9ba\xf9M&\xde\x16^Ja\xe8\xf7J\x887\x1cp\xba\xa6\xad\x0e\xdey\x8e\xf1\xeeN\xe4/\xc1\x98\x95\xb8\x9fC=y\xab}\xb1\xedA\x1c\x1cL\xe3\xa8\xb8;qu\xc5\xaa)\xd0\x9bri\xb7c\x9fz\x94\xd1\x99\xd1X\xa7\x16>\x00\x14\x7f)\x90]\xcd\xa4\xa8\x0e%|(\xf1\x8bCw\x0b\x17\x05\xfa\xafk\x12\xb9\xc6\xbbL\xf5\x07\xd0f\xe9\xf0q6q\xeb\x0c\x86>\x01I9\x01\xb1\x05\xd8\x91IY\x80\xa4\xbc\x8cg\xbc\x95\xa3\xb8 \x0cm$\x03\xf9\xca\xef\x95`\xfc\xc2875\xd6V@\xeb\xbbZ;M\xea\xc6\x81UL\xba6*\xf1\xec\xd7_\xcb\xebpd\xf8\xcd\xd61k\\\x17\xf8\xa5h\x1d\xb6\x18\x90?X\xf8\xe9\xab\xf3\xa8\xb8[\x1ev\"\xfd\xac\x99A\x1b\x00\x83\xd6\x8d5c7e\xcf\xd8/\x80t\xc5\xd1\x1a[4q:\xd0<\xe5\x18\x07\xb4\x06\xbb\xbe\x9b-\xdd\x02A\x8a\x95\xa1{X\xe6\x05\x83\x9e\xeb\x17\x8fm\x8f\x18\xd4J\xcc<\x07\x7f\x1e:\x8c\xdb\x97\xa6Xp\xbf\xf1\xf6\xd5\xcb\x01\x9eu\x83\xf9\xa55\\\x80z\xd6\\i`\x1f\xaao~\x1d\x96Z\x1c\xc1\x8eY,\xcf\xa6\xfd\xf2\x1a\xe8\xf2\xee\xb2\xdd\x9cL=\xb7\x862\x157\x1f[\x8fYV\x99\xe9\xac\xfd(\xa6dAb\xef\xec@\x1f\xa9\x9d!*:\x1e8\x1bC\x8f\x15\xb3\xa7\x9c\x87T\xe6\xa6\x80\xd5\x80\x1d\xd6\x8f\xa5\xb0},\xf8\xf4}\x01\xc6\xd4c'y\xc6\x12>\xe5\xc1\x19\x9f\xb1_I\x99\x9f\xb1 \x9a\xf1\x0b\xf6+\xe9\xa0\xe7\xb1\x13\xf4\xed\x05\xf7\xa4k`\xb3\xcf\xee\xf7\xb2\x04\xa5o\xd1r:\xfc\xf6\xe9`\xda\n\xe2\x9d\xbc\x8f\xeaWX\xd3jo\x05\x81v;QG\xd6\x99\xc6vY\x9f\x96\xa5x{\xeb-]t0\xddT\xcf\x0d\xa7\xf4\xff;\xac\xc6\xd7\xf8\xc5\xaf\xd7\xe44:\x1d\xe0\nfa\x1cv\xc4\xd9i\x97f\x99lz\x0en n\x85\x0f\x99\x17\xa0\x9e\xb7\xd6i^\x12\xdd\x16\xcc\xed1%\xfc\x02BK~oX\x9fv\xc6\xfa\x10\xb0\xbe\xee`\xae\xfe\x18X\x1f\xde\x00\xeb\xc3[\xc7z\x85\xc2>:\x93\x04\xfe\xa9\x8dk)V\xca\\\xac\x94N(-J\xaf`\xa5\xcc;\xae\x94\x8d\xd5zpz\xcf\xe5\x99l\xdeL\x8e\x8f\xa2O\xfdY\xa1\xc2\x10\x195\x9e\x0da\x80\xd7\xf9{L^\x139\x8a@\xd3\x06\xb7J\xc8Z\xfa%\x13\xe5\xa7K\xd6\xef\xb0L\xcf\xe4\xa5\xb2\x95\x93zln\xae\xf6y\xb7\xd5.\xe0\xb6(\xc0\xb6\xf8\x05\xadc#\xf5\x83vE\x92\x99>\x87(\xfcQR+y\xfd\xef\xa0pR\x7fu\xc5\x86\xec\x1ed\xc0K\xc6F\x8c\xc3\x85I\xb8\xed\x07\x0cZ\xa5\xb5\x0f\x96o\xcfhJ\x02\x17g\x97J\"\x81\xe8\x84\xe2=\xf0\xd8\x1c`\x92\xa37\x1ep\xb1\x13#+\xfa\xdc\x0f\xc3 :-D\x0e)\x83\x95\x03\x8e\xb9\xd9,H\xf84\x0b/Y\x90\xb2(F65N\x04\xd18\xb9\x84\xc0*_\xaf\x92x\xb5)\x88N\xfa5[\xf9\xd3\xf7\xfe)\x1f\xb0\xafR\xce\xbe.\x1a\x1c\x00\xc3Z\xfct\xdc\xaf\xc5:\x9b\xfaa(\x9aX\x0e\xd8\x1b\xee\xcf\xd82N\xb8\xe0\\\x17Y\xb6\x1a\xdd\xbb7?\x19,\xf9\xbd<\xe5\x9bP{\xb3\xfc\x8eu\x91hx(f<\x19\x07\x13v\x007+\x8b\xcb\xa1*\x0d\x89\xc4\xbb\x05/\xcf:\x15\xa2\x19\xa4`\xe5(\x18\xef\x94%\xfcgy\x90\x80TQ?O!\xdf\x1dd\xa9$\x067b\xdc\xa9\xe0H\xdb\xa5k\xa6+\xe61\xbc3\x92\xa1\x0d*\xb4^\xba\xd6B\x1co\x10\xd7\xdd\xd5#\xc6\x10c,\x91\xa4\xdbm\xee\xa4v\x9b\xbb\x8b\x10\xe11\xdb\x80\x10\x91A\xed\x16ucMV\xeaBb\xbcB\xadM\xe4\xd0\x0e\x9a5nvS}\xea\xc8\xf5\x82\x17\x9f\xae7\xbbAx-\xf0cc\xe9\xf8\xe3\xe1\xa4\xd3@X\x17\xd9\x8e\x0d\xa3\xa5[\xd8\xf6\x05k~\xbf\xeeu\x96&s\xa7\xcdWL\x95\x9e\xc5\xba?\xd5\xe5\x85\xec\x80I\xbb(\xe0\xfc4\xf1\xfa\x1b~zx\xb1*\xef\x81\xf7XGG@\xf2K\xca\xf4\x08\xaf\x9c\x82;\x89\xb7ZJ6\xee\xfd\xea\xaf*\xd7\x1b\xef\xfc\xd3\x1e,\xe0\x16k\xb2L\xef &\x9bpD\xa7W\xa2\xe3\xaa\x07\xf58r6\xe0^\xda\xddwiN\x98a,\x05\xb5+UZx\x07\xd9\x84\xbc\x9a\x9bSR~m8\x01ht\xb0T\x99\xa1\xcf\xfcL\xfb\xfa\xcc\xcfx\x8f\xc6J\xa3&\xcemY7\xe1\xa7\xfcbE\\1\xb6\xa1Q7x\x9e4#+-\xd0/v\xec\xe6\xad\x1a\x91\xb6i\x1bn\xdd\xf6\xd4\xe8\xfd\x088\x9b\xc6=\xb4y+\xc620\x03M\x05$\x98;\xf4\xa8\xa9C]iL\x9b\xd3\xb7\xea/YIs>\xc9\xf6Q\xc5V\xa6xl^;\xa9\xb0}\xc1J\xcf\x07z\xc2\xdc\xd3\xa4b7\xf0C\xd0\xe4x\xa7P\xe9\xdfR\xfb\xbd\xe1\x83\xc1\xee@z\x1e\xb8Vkg\xa5\x8f\xe9\xdd\xfb\xee\xa0\x88\x98@Y\xf3\xb6\x19\x1b\x07\xb2\x9d\x07\xa4}\xef\x83\xfb{\x16\x83]\xdfQ\x92\xb9\xdb\x18\x87aG\x8c\x9d\x1fn\xd3n\xa3\xeb&\xca\xa2\xb3\xbdep\x11Di\xc7I\xad/xuf\x19\x13\xd2\xc3\xd4j\xef\x8b\x9f\x1c\xb1\xdeg\x87\x9f\xbfxyx\xfc\xe5\xb3\x97\xbfe\xf1\xad\x90f~\x16L\xbb\x95])\x0c\xefTZ\xfaS]\xa3\xc2\"\x08g\xcf\xd7\xadu\xca\xb3\xcf\x90\x1a@\x84\x9dj\x9d\xe3/\x0f\xdf\xfc\xda\xe1g\xf6\xaa/\xa2 \x0b\xfc\x10\"\x17\xadY\xf5\xb9\xd6\xddu\xaa&<\x82\xbb\xb4\xaa\xc6\xab\x97\xcf\x0f\xad \x94+\xe8\xc7A\x18~\x89\x8eK;\x80\xa4\xa8\xf6Y0\xbbF-\xf1\xb17\xa8($@j\xc3\xa3E\x9c\x0bp\xc86\xbeZ\xcd*\x10\xed:\xc8z\xbd.\xfd\xfd,\x98]\xa7\x1a|.Zv\x86\xcfW/\xdf>\xfb\xfc\xf0\xf8\x9asB\xd5^\x1b\xc8T#k\x0c=\x87\xa2\xc5\x1c\x8dX\xef\xd5\x8f\x0e\xdf\xbcy\xf1\xd9\xe1\xf1\xa7\xcf\xde\x1e\x12\xbc\x8f\xd9Nh%:\xb0\x10\x93\xe0\x8c\xcf`5}\x9e\xc4\xcb\x86\x15\xd9\xe5[S\xeb\xb7fA\xba\n\xfd\xcb\x97p\xe3\xbb\x13G\xce\x80\xf0j\xf5X]\xac\xab\x1e\x8b\xd6H\xd1\xd4\xce_\x13\x1cgK(\xb9B\xed\x11\xa1\x9a;\xaa\xb8a\x8b\xfa}W\n\xb4\xc7\xd1d-\x15\x17AJ;\xf7\x9b\x0f\x8c\xda\xe2\x88.C\xa6\x19y\xa4\xabP\xd6\xd0\xb5k\xf7\xca\xd2\xa1\x1b\xf4\xc5\xd8;\xd6\xe8N\xad.8\x13\xaa\xa7\xed\xb3\x85c\xa4B\xcb#\xb2\xf4Z\x08\xa9\xed\xc6kt{\xa5q\xa9\n\x84E\xda\xba\xf0+\x98\x87\xce\x1d\xd8\xe8^\x94u[C\xac\xba\x8e\x82\xa8\xbdU\xf5(>\xaf\xdd\xa6_=\xd0\x9f\xba)`\xd4\xd9\x14\x90)\xb1\x97\xe0\x16A\xd3\xd9\xed\xb3\xe2 \x9c\x8d\xd8cw\xc1\x88\xf6y\xe8\xa7\xe9\x88\xfdV\x9c3\x1f\xf4!\x19_\xae\xb2 :eY,C\xcf0\x9f%<\xe5\xc9\x19\x9f\x01\xa6\x88\x9ez\xec\xeb_I\xbf\xf60\x16>n\xd8\xd1\xd1\xdd\x8c\x9dp\x06\x11\xf2A\xb4\x0b3\xdac\xef\xf9\xe5\x80}\x86M\x05\x19\xf3S\xe6G\xa5\xc1\xb4j\x11R\xb8?{,\xca\x9c\x07a\xc8\xd2L\xfc=\xe1\xcc\x9fNy\x9a\x06'a\xd1\xb8n.~\x97vRo{\x94\xd8\x0b\x80\xd6A\xea\xa5\x1e\x90~\xad3;L\xe3\xb9Cs\xa2\xd9\x01\x0b\xc7\xd1D\xca\xe9\xbb\xf7\x83\x95\xa7\xcb\xc0\xa1\xb6C\x10{\xe4\x1e\xebu\x9e_1\x95\x02\xb2\x97q\x9eh\xb6\xc2\xa0 \xcb\x16~\xc4\xe2h\xca\x07\xec\xdd\"H\x05\xe4\xe7a0\xcd\xd8\xd2\xbf\x14s3\xcb\xb9h\xc9\xc7Mm\xd0C\x07\xc8gq0s8\xc6\x95_\xc0\x8b\xc7\xa8\x80S\xb6\xa7Y\xff\xab?\xf2#\xb4\xc7\xe5\xfa\xd3\xde\xac\xbd\xc4\x07\xa42\xeb\xd04?\xcf\xe2\x93 \x9aU-\xee\xd7PA\xd3\x81u\x98f#\x98\xd6\x11+\x13\x88\x95\x8e3;b\x9d\x10U\xee\xdc\x11\xc8Te\xe1\xd0Ml\x05\x8f \x12\xc2\xdc\x9fr\x1bB\xc5g`\x87Q\x9a#\x86eXj\xc9\xb3ENDg\x9f\xe5Y\xfci\x10\xcd^\xfbAb\x89TY\x8dR\x19\xd5\x97\x99\x0f\xcbl:@\xee\x1f\xa6T\xbe\xbb\xa4\xbfw\xf5\xc0\x1c\xd7\x1bC\xbb\x8a\x1cC\"\xb6\xedJg\xf2^h4\xce;X\x8e\xad`\xd8\xc6\xf7\xda\xf5\x80sg\x85!w\xa6fm\x97M\xc7\xf9D\x0c:li\xa9\xc1\xef\xb3\xfe\x881\xcd(\x02\xd8\xd6S\xd6d7\x0d\xc6+\xe0\xac{\x05\xb7\xdc\x86H*\x06\x8a\x92w\xdb\xc1\xc0P\xbfmR\xf4\xe7L\xba\xcfN[\x03\x96\xeaO\xe0\x80\x13q;\x13\xb0\xac\x13@\x99\\_\x81_E\x85\x11\x81 \xd1l\x15\x87\xc1\xf4\x92\xfdJ\n(\xfd\x9e\xc3\xeb\xf9\x82G\xb8\x02O\x81\xdd,\x96\xa6\xa8\x02\xc4x\x89\xb3\xdf\xd0\x9d\x03\x96`\xe4\xd2\x85#^\x042\xb0\x11\xd5C\xf4\xe0\x8be\xcf\x8a\xb2\xdd\xa0/\xddA\xcb\xda\x1d8+(\x1ec\xd0\x93\\|\xc7+*7\xd6m\xe0\x15\xcc-\xbe\x13\xa1\x9fY\xf7\xfb\xea\xb1$p\xa4AY\x83\xaf~\"=\xf3Xo\xc9\x93S\xaeB\x1c\xbd\x8c?\xcbW\xa1\xd8\x90\xf9o\xf2\xcb\xd4qG\xec\xb9\x1f\x89m\x17\x8a\xb1(\x8e6\xb1\x99\x14\x08x\xe62\xe2\xc8\x82Q\xca*:=`\xf8Z\xbf\xf5.\x91\x06-\xf8\xb5\xec<\x96\xf4;\xc5\xed^p\xfa\xa9\xbf\xe4\x18\x06]l\xbd\x9dv\xd6\xc7\x02D+\xf0\xf0*\xf6\x044\x92SE\xa7~\x9eJk\xb2\xf3\xb8.\xb6u\\\xb1\xc5\xd5\x0e\xd3\x8e\xab8\x0e\xc9w\x8b\x15P\xe9\xa7\xd8\x1c\x17\"\xf5=\xbfL\x15\x0b,\x19S\xcb\x0dUeB\xd8 -\x16m\x96\x88:{i\xdd\xf70\xb04F\x83\x15\x10\xf1\xcaH\xb2\x96{\x8e\xe2\x81C\xad\xa5\x96]=\xaaL\xe2\xca{(I{\xe1\xd2\xd6#\xb2\xef\xde\xe0^\x98\xf0\xd5\xcc4\xa5\x9b\x13\xe3\x14\xc0\x0b\x1dV\xa4\xdbz<\xbb1\xe0\xad\x00\xb7\x02\xf5\x9a]]\xb6\x1e\x1524\x9e\xa3\x94\xc4\n\xec\xb5/\xd5[1C\xd1\xa9\x87P\x13\xb4\x82\x86)\x83\xd6\xe3\xe3 \x85J`\xe3\xb7\xb1E\x96&H\xaa\x89\xb4\x97\xed\x1d\xac\x88\xea\xaf\xddG\xda\xde\xa5S\x1fO\xac}\x94\xfe\xc1\xa5\x02\xa9\xb3p\x0b\xfa\x87\xf2\xf8d\xc0\xa3\x9f\xe5<\xe7o\xb4\xa6$\x86\xad}z-\x06\xdc\x11N\xca\x16g\xa3\x0e\xb0\xeb\xc3\xea\xd8\x1e\xd6\x97iF\xa2\xce\xb1\xaeT\xd7y{vB\x90\xb6\x12\xb2M\xe42\xab\xa9T\x93\x06sPV\xa2\x89yXP\x91\xd7\xee\xdc\xe9\xf0e\xf5T.\x11r\xb2]\xcf\"\xeag\xfd}\xb6\xdd\xd6>\xab\xc9,\xdb\x8f\x05L\x9e\x88\xb2q\xc4\xfal\xd8\x81O\x85\xe0\x0b\xfbH\x99\xe2\xeb\xfaA\xf8\x00\xe8\xab\"\xda\xad\xa4t\x9b[C\xe7&|\x0e\x0e\xc4\xbc\xca\xbaP6\xeaQi1\x9fq\x19\xcb\xc7>\x90\xc2\xcaWT\xa9\xb1\n\xec\x80Lv\xdcV\x81^\xe0\x10\xacY\x0evuUs2`\xa6\x7f\x85\xf8\xc4\x88-\xc5\xc9W\xa2\x7fq]]\xf0.\xe2\xd3=\xb1\xb9\xe8\xea)q\n@~_P\xc14\xd0\x14w=\xb7\x06\x91\x9c^\xad-'\xde\x04\x84\xe5\x15c\x97\x88\x9f\xb3cOO\xac\xf8\x10\xc1h\xc8Z&\x85\xe22\xa8_>\x90!O\x9d\x95n\x00\x9e\xb9\xae\xc7VN\xe6\xb1S\xf5\xc2\xd5\xcb%\xec\xb0u\xb5\x08\\EP\xc1\xe6\x0bMI\xbd\x98\xe3\x82\xacB\xef\x1c*\xda=\xd6\xc3\xc0\x07pnr\x06\x83\x81`\x98M\xd1\x16NO\xb0\\\xa15\n\xf3\xd9\xd7\xd8\xc0\xd7\x92\x93\x04f:u\xf5\xf1\xcb@%N-I\x86\x9bj\xe4w\x9a,\x93n`\xd0s\xd6\x12\xd3\x0c\x0co\xca\xe2\x91cs\xe6g\xa7zr\x00F\x0cg\xee\xca\xe0\x96\xc3\xfb;\x10\xdd\xf2v\xc7\xb3\xbdG\xdb\xe2)\x1b\x00\xb1\xd5\xc5.Ek\xfd\x12*5Z\x0b\xc1X\x1f\xeby\x96#$\x8f\xf2%O\xd0\x01\xfe\x86%\xd0\xe8)\xef*]Q[\xf3\x80\x96\xb5\x13b\x82\xc6\xbe\x07\xdf{\xbf\x83[\xe9\xb7D\x93\x8e\x9d'\x1b\xcf\xea\x08\xc4\xf6\xd9\xd0Bv\x18uz\xb8\xc1\xfao\xa3E\x80\xb7\x9e\x14A\xe3M\xa3*\xca\x927\x95\xe0&\xf5 >Iyr&\x86.\xce\xdcp\x0bXK\x1a\xc9\xa0\xbc\xe2P\xad\x12{\x10\xd1]+\xb4\x8fvr\x19:\xc7\xd6\n\x92;\xf0\xf7\x02\x91\x8a\x80\xc7\xf0\xcf\x00Bn\xa4\x98[\x8fYP\x11\xf0\x04\xb4\xcb\xa2\xb3\xc2)N@\xc8f\xb6<\x1a\xc4|\xecO\xf0\xe2\xa7xA\x07G\xb6\xbd\x8ai\"\x11\xbd\xc7u\xeb\xab-\x93\xd8\xa6\x16F\x8a\xe6\xbc6:\x08\xca\xaa +\x04\x04E\xc5F\x91\xe9\x99\xe6a\xabY\xf2\x85\x07C\xec\xbamm\xeaO\x06\x1e\xc7\x04;\xfb\xe2\xe5\x8bw\x8d\xc5?\xb4\\Q\xd5No\xb1\xcb\xb2E\x12\x9f\x83P\x05n\x119w\xdf\xf0Y>\xe5 \xeb\xdde}\x96\x81\x1b\x90\x9e\xc4`>c\xc5V\xc9fy\x82*[\x90 \x05\xdfH\xe3\x9b\x17sT\xaf\x81\xd8g\xe5\xa7)j\xe2DZ\"[\x0e\xd2\xb2\x19\x8f]\xc69\xca5\xf8\xc5*\x0c\xa6A\x16^\x16\x0bf\xc1U\xfb\xd8\xe0\x80\xbd\xab'\x81\xfe-\x8a\xc1B\xb0h\x15\xba!\x1a\x9e\xc5\xd1\xdd\x8c\x9d\xfbQ&:\x91\xf2\x8c\xf9\xd2\x01\x81X'\xa0\xbf\x93\xbd\xc2\x8eL\xfd\x08\x0c?\x80\xb9\x91\x86\x83,\x9ek-7\xb9\x96\x11\xd3\x1f -\x10\xad^\xdc{\xfd\xe6\xd5\xa7\x87\xc7_\xbd\xfc\xcd\x97\xaf~\xfc\xf2\xf8\xd9\xf3w/^\xbd<\xee\xb1>\xfb\xd2\xcf\x16\x83\xc4\x8ff\xf1\xd2q+\xa1\xcd\xb5\xe0\x9e{\xee ]\x85A\xe6\xf4z*\x80o\xe3\xe7k\x93\xdb\x15\xbd\x10\xb5\xe8\xed\x86\x01>\xdd\x00K@\xbb\xbfJ\xe2\x13\xf1\x1ed\x0b\xe63\x1c6|v\xc0>\x83 \x12\xcb5\x8b\xd9\xc2\x8ff!z\x99P\x98\xce\xfa\xec.\x8b\x13\x16g\x0b\x9e0\x1f\xd6 \x88\x18z\x08\xe1Ozh\xd6\xb5\xf2\xd1<\x8a_\x82\x8d\xd54\x06/\xa3 X\x96\x06g\x80:\x85yO\x81q\x1a\x9aM\xf3$\x01\xa3\x03\xc0)\x81\x1c~t\xc9\xf2\xe8}\x14\x9fG\xea\xbb\x1e\xcb\xa3\x90\xa7)\x0b\xb2\x1a\x12\x07\x11;_\x04\xd3\x05\xde \xa4>PAZ\x8f%\xfc\xd4Of\xd0X\x8c+\x06\xbf!\xc1\xd2\x0d\xcd\xd1\xa9\x86\xc0\xd9\x13D\xd9\xc1]\x8b&\x86\xd0\xfe95\xd3\xa0\xca\x01\xd3(\x0e\xc2\xf1\x06\xfa\xddEo)\x96\x87\xd83\x0b\x9d\xa4\xd2`\xc6\xb2\x12\x14\xc9\x80\x8f\xb2\xf8*/\xbd\xbc\x88\xceb4\xdcz\xed'>\x84u\xff\xb2\xf0\xb1\x9b\x15\xac\x84\xf4\xf4@\x124\xf0\x16$\xb6\xae]\x97\xd8\xbbD\xd6\x83]#+(\xb2\xf6\\\xf2X\xeb[\x95\xba\xd2v\xa4\xb2\xfey\xf3\xfa\xb7\x1e\xc0\xb5\x05_\x1bj\xa2\xe6\xd8[\x0bd\xb1^\x8d\x82\xff/1\xe9\x15\xbds\x04\xe5%\xa61P3L\xcdU\xf0}\xcf\x15E\x9c\xed\x8e\x9f\x82\x1a\x89\xa6\x0e\xb5\x1b\x81\xa4\xb9\xa5'\xbb\xb7Y\x9cp6\x8b9zc^\xf8g\x1c%\xf3\xc1L\xc9\x1c\x06\xecK\xff=g\xf2*//#\x8c\x94J\x85\xfa\xe6\x1b\xa4\xday\xf7|\x11\xa7\x1c\xa7&\x05\x99\xb0l7\x1d\x10\xc1k}I'\x0b\x14s\x0d\xed\x13\xba\x0d-\xb6\x84\x17\x19\xaaM\x07A\xaa^\xf5\xb8.\x85\xbbd\x1f$\xd8A\x8aB\x91\xe2\\\x9e\xd5\xa2\xa2\xa8\xc1e18&\x88*\x81\xdf^,\x979\xc4\x83/\xbeZ\xdec\x9a\xc7a\x18\x9f\x07\xd1\xa9rx\x10\x80S\xaa\xbb\xac\xcf\x02T\x1a\xdc\xedy\xacw\x17eL\x83\xbb\xe6\xd8\xe1\xc0%f\xef-\xff\x19(#\xf0\\\xe8\x0e\xe6A\x98\xf1\xa4\xe5\xa8 \xc7\xbba\xdc\xdf\xaa\x1da\xeaZ)Y/\xd7e\xc0\x07\xac\xa7]\x19\x04\x81\x04^\x94,J\x1d\xb0\x9e\xf2\xeb\xd0c\xa3\xe2G\xc0S\x14\x97\xe1\xc0ss\xe0l\x1e\xe7\x118\xa5\xbe\xab&E\x03\x7f\x16\xb3y\x10\x15a\x83\x04\\Q\xf0\xaf\xe4_\x853 \xbcC.\xc5\x1a\x0dp\xd6\xef>\x96\x9dD\xff\x13'\\J\xeaf\x83\xbbuw\xca\xb7\xbf\x1b\xde\x1aE\xf3\xd6\"\x0euo\x9c]tH\xa4d\x13UH\xa0\x1a\x12X\xaed\xa7\x97+)\x0bEQ\xe7\xad\xc8?\xeb\x02(M\xb6y+\x13\xa4W\xacB\xab\xa0\xd0b\xd7\xae\x07\x00/\xe7\xa9:#]>\x199\x8fP\xc4\xfd\xe8\xa1[\xedy\xe4<\xd8\xdb\xead\xe0Y\x1e\xa1\x87\x86\xafC\xe9l\xf0\x91\xeb\xf4\x8a\xd8\xe0\xa4\xad\xf3\xde\x96\xc5\x8a;r\x86\x0f\\\x8d\x8a\xaeq*\xb0\x1d\x084ER6\x8e\xd1c\xad\x16\xbb\x1c\xee\x14@4\x81:\xcdJ\x1c]~\xd7 \xc0\xcdV\x86\xf7~\xe2\xfc\xca\xf6\xd6\xd5Q\xea~\xe2\xfc\xd4?\xf3\xd3i\x12\xac\xb2\xab\x99\x9f\xf9\xee\xbd`i\xc2\xf2\xde\xf8'G\x17\xdb[\x9bG\x17{\x87\x93{\xa7\xf5\"\x01\xb69\xfe\xc9h\xd2wG\xf7N\x97\xe6qk\xdc\x1b\x08Bt\xaf7\xa1\xe1]\x05h\xeaGA\x16|\xc3\xbfJ\xc26a\xd5\x99\xb4\xb5\xf1\xe4\x8e!\xaf\x95\x89cA\x8fRKw\x12\x10j\x05\xfd\x010\xec\xaf\xe6\x0e\x1foM\\\xf6\x94m\x12\xee\x97\x9d\xdc\x95&\xe7N\x04\x12\xc0\xa5\x9fM\x17N\xe0\x8ad4\xd9\x11\x873\x96\x0c2\x9ef\xe8\xb6\xa4\xe7\x9f\xc4y6: \xfd\xe8\xbd\xd86r\xb8\x1d\xae'V\xbe\xb3\xa6\x15e\xb9<\x1e\xd8\xec\xff\x1f\x0e]#\xdci\xc3f\n.\xa2\x07Y\xfcE|\xce\x93\xe7~\xca\x1dpG\x02\xfa\xa3\x03&\x90\x94\x8d\x0c\x1f\x1f\x96\xe5\x15\xaf7\x84]\xca\x9e>r\xb6\x1f\xda\x96\xaf}z\x95\xb0\xdbI\x1c\xeeVG\xb3\xe6\x1a+\xbb\xb7W\x17]|/\xa6\xe4`H\xdelF\xde\x0d$g\xff\xbf1y1\xc7\xf5 \x8e\xba\xd9\x8cw\x03t!d\xb9\x96\xe5\xb8\xbe\xa2)\x84\x13\xeb\xc1r\xa3g\x8f\xf2\xaf\x0b\xcb\xea\x9aCh\x96\xf5\x80\xc5\x03\x19\x94@\x814F\x12\x18 \xd1\x90\xe2y\xa34\x93\xa8\x0e\x96\x91hd\x91\x0d\xa6\x0b?y\x969[\x16%L*\xcb'N\xe4\xb1\xa1\xb2P\x82\x08!\xd9 \x0d\x83)w\x1a\"\xb0\xe4c>\x01\xc5wU\xd8\x7fm\xda\xbb\xfd\xb0\x1d\xc4\xf6cl\x0c;\x9a\x14\xdf\x93\x98T,2\xe9\x02\xea\x80\xc5\x82w\xf7\xd8\x06\x98\x01D\xec\xe9>\x8b\x95Ux\xf1\xa9\xeb\x8e\xe6\xc1^\x9d l\xc1\xbb\x9b\xd0g\x8e\x08\x02\x97\xb4\x92\xf6\xc5b\xe3h[\xbf\xc4Ks\xb65>\xa1\x10\xb97>:\xcag\x0f\xb7\xb66\xc5\xff\xf9|^\xbf\xf4\x96\xa8B[;Xhkgw~t\x94\xcf\xf96\xfc\x9c\xf3m\xf1s{k\x06?\xb7\xb7\xcc&\xe0\xc6\x00|fg:\xc6\xcf\x9c\xd8>\x07\x86~\xe3\x9f\xb4t\n.\xf49\x07#\xbd\xd1\x19\xdf\x85\xe2\xb3\xf9|\xe2\xfe|\xfb\x03y\xc5Oo\xf7d>\x9f@\xc2\xd4\xfe\xa1T~\xa8\x08\xe1sU\x84\x01r\xc5[\xef\xa0V!T\x9f\x99\xf3-\x8e\xff\xe6\x93\x03\x15\xe1\xc9\x91\x9d\xde\xde\xda\x9a\xc9V\xc7\x18\x93)\x9f\xc8\x95~\x85A\xe2\\k\x1b=\xf7\x93\xfaY`\xaa\xf5r\x1c\xa8\xae\x1e\xf4\xf0\x1a<(\x08\xa3z\xfb\xb5~\xcf\xd9\xbe\x0c\x8c\xe0\xc0\xe8\x9c\x83\xfdr\xa40\xe8)F\x8a\xec\x9d\xf6\xae\xbb&\xb8\xe4*\xe7p_t<\xb9\xee2\xde~hc\x08m\xcb\x98\xf2%/G\xdb\x1b\xdf\xfdo\xbf\xf3\xbb\x93\xde\x8dF\xd6\xbc\x9d\xa8\xdd\xdd \x1c\xb1o\x14,\xbe\x0f,\xbe\x0b\xce\x1ez\xbd\x1b\xdd9\xd2h\x9c\x058\x06\x0b\n\x87\x9e\xf1\xd1\xc5T\x1c\x8bf\xbbG\x17\xb3\x87\x9bG\x17\xf3\xdd\xa3\x8b9\xbc\xcc\x8f\xf2\xad\xa1X\x19\xf9\xd6po>\xb9w\xda\x00\xc2u\xc9\xc3M`\xed\x80\xd0\x1a\xa4\x82 \xa9U\xd0\x0c<\x96\xd4a{} \xdew\x9d\xea\xd7{\x7f\xf8;\xbd\x11\xeb=\xab\xad\x9b\xde\x1f\xfe1:\xf9\x8f\xd3\xc9\x7f\x82N\xfe\x1f\xe8\xe4?I'\xffC\x91\xec\x1b\xc9\xff\x88N\xfe\xc7t\xf2?\xa1\x93\xff)\x9d\xfc\xcf\xe8\xe4?-\x92\x9f\x1b\xc9\xff\\$O\x8d\xe4\xbf\"\x92\xeb\xde\xf1{\x7f\xf8\xefD\xf2\xccH\xfe3\"\xb9\xee;\xbe\xf7\x87\x7f\x96N\xfest\xf2\x9f\xa7\x93\xffg\x91\xcc\x8d\xe4\xff\x85N\xfe\x17t\xf2\xbf\xa4\x93\xff\x82H~a$\xffE:\xf9/\xd1\xc9\x7f\x99N\xfeW\"90\x92\xff5\x9d\xfco\xe8\xe4\x7fK'\xffU\x91\xfc\xd2H\xfe\xf7\"92\x92\xffG\x91\xfc\xcaH\xfe\x9f\xe8\xe4\xbfF'\xffu:\xf9o\xd0\xc9\x7f\x8bN\xfe\x0f\"96\x92\xff#\x9d\xfc\xbf\xd2\xc9\xff\x1b\x9d\xfc\xbf\xd3\xc9\xff\x89N\xfe]\x91\xfc\x95\x91\xfc\xb7\xe9\xe4\xbfC'\xff]:\xf9\xff\x14\xc9\xb9\x91\xfc\x7f\xd1\xc9\xff\x99N\xfe/t\xf2\xdf\x13\xc9\xf5\xd8\x01\xbd?\xfc}\x91|i$\xff\x01\x9d\xfc\xa7D\xf23s9\xfc\x9eH\xf7\xcd\xf4\xbf/\xd2\xdf-\x8c\xf4\xff*\xd233\xfd\x1f\x88\xf44\xad\xa7\x7fK\x93\xe5oi\xfa\xfb-Mh\xbf\x05\"n\x90\xb7o\xff\x04\x9d\xfc'\xe9d\x80\x80A\x0c\xbf\xfd3t\xf2\x9f\xa3\x93\xff\x02\x9d\x0c\x84\xd6\xa0\xa8\xdf\xfeY:\xf9\xcf\xd3\xc9\x7f\x91N\x06\x12d\x90\xe5oij\xfd-P&\x83Z\x7f\xfbW\xe9d \x13\x06\xfd\xfd\xf6\xaf\xd1\xc9\x7f\x83N\xfe[t\xf2\xdf\xa6\x93\x81\x04\x19\xf8\xf6\xed_\xa7\x93\xff&\x9d\xfc\xbbt\xf2\xdf\xa1\x93a\xcd\xfe\x9a\x91\xfc\xf7\xe9\xe4\x7fH'\xffc:\x19\x16\xe7\xa9\x91\xfc\x0f\xe8\xe4\x7fD'\xff\x13:\x196\xfb_7\x92\x7f\x8fN\x06\x1e\xc0X\x98\xdf\xfes:\x19\xb6Xc\x07\xfb\xf6_\xd0\xc9\xff\x8aN\xfe7t\xf2\xbf\xa3\x93a\xfb66\xb6o\xff%\x9dLo\x9a\xdf\xd2\xbb\xe3\xb7\xff\x9eN\x86\xed\xe47\x8cd\xd8N~j$\xc3v\xf2\x9bF\xf2\xff!\x92\xdf\x1b\xc9\xff\x89N\x86\x9d\xe0\x0b#\xf9?\xd3\xc9\xbfO'\xff\x01\x99\xfc\xdd\x1f\xa3K\xc3.\x13\x1a\xc9\xff\x85N\xfe\xafd\xf2w\xbfC'\xffq:\x19H\xaf\xc1\x8d|\xf7'\xe9\xe4?M'\xff9:\x196\x01\x83\xa5\xf9\xeeO\xd1\xc9\x7f\x86N\xfe\xf3t2\xd0o\x83I\xf9\xee/\xd1\xc9\x7f\x85N\x06Bm\xf0\x17\xdf\xfde:\xf9\xaf\xd2\xc9@c\xdf\x18\xc9\x7f\x83N\xfe[t2P\xcd\xc4H\xfe\x9bt\xf2\xef\xd2\xc9@\xa8\xdf\x1a\xc9\x7f\x97N\xfe\xfbt\xf2?\xa4\x93\x81\"\x1b\\\xc1w\x7f\x8fN\xfe\x07t\xf2?\xa2\x93\x81\"\xbf3\x92\xff)\x9d\xfc{t2\x90\xde\xccH\xfegt\xf2?\xa7\x93\x81\x98\x1aL\xe1w\xff\x82N\xfeWt\xf2\xbf\xa1\x93\xff\x1d\x9d\xfc\x1f\xe8d\xa0\xb1\x06\x0b\xf9\xdd\xbf\xa4\x93\xff5\x9d\xfco\xe9\xe4\x7fO'\xffG:\x19H\xef\x8f\x8dd \xbd\xe7F2\x90^\x83\xc7\xfd\x0eH\xaf\xc1\xcc~\xf7\x9f\xe8\xd2@z\x7f\xdbH\xfe\xcft\xf2\xef\xd3\xc9@L\xbf1\x92\xff\x0b\x9d\xfc_\xc9\xe4oav^\x98\x1b\x0f\xc0*0v\x9e\xef\xf0\xb8fp.\xdf\x01\xb3\x14\x9b\xe9\xc0X\xde5\xc9\x1b\xec\x1bi\xa9\xd9\xb5)Hi\x8f>\xd7\x16rw\x12\xb0\x11\xce\xd4F`\xa3[\xa9p\x03\xc9Z=\xf6\xa3\x12;R\x96\xdf\x84\xc4M\x9am?l\xf7\xbcG\xabT\n\x0b\xc5}\xd0+x\xba\xea\x04u\xf4\xfa\xc0AA%\xd5\x10~\xa9\x86\x80\x00T(\x87\xcd\xba\xc9a)\xb5\x01\x18Tlmm\x1e]l\xcf\x8f.v\xfc\xcd\xa3\x8b\xfb[G\x17\x0fN6\x8f.v\xb7\x8e.\xf6\xc4\xcb\xde|\xd2\xbfw]%\xa3\xeadt\x93N\xfa\x9b\xdfL\xc6\xcf6\x7f{r\x05\x7f\x7f\xbe\xed}\x80\xb4\xab\xf1\xd6\xe6\xa3\x89x\xc5L\xf9\x02\xa9W\xe3\x9f\xe0\xcf\xad\xcdGlr\xef\x9a\xdd\x8f\xd0Pb-\xb5O\xa1\x939:\xba\xf0\xa7GG\x17'\xc3\xa3\xa3\x8b\xd9\xde\xd1\xd1\xc5\\\xfc\x01\x01\xab\x008B\x1c@\x8e0\x07\xa0#\xd4\x8f.NP\xe0\xba%\x05\xae\xbbsvt\x94\x89\xea'GG\xa2\xae\xbf\x05r\xd9\xf9\xfc\xe8(::J\xa0\xd0\xf6C\xfc\xf7\xe8\xe8(\x1f\xee>\x14%\x86\x0fA\xf9 \x1a\xc2\x7fC\xfc\xb7\x8d\xffv\xf0\xdf}\xfc\xf7\x00\xff\xed\xe2\xbf=\xfc\x87mn=\xc2\x7f>~\x01;\xf7@\xfc\xdb\xd9\xda\xda\xaa\x11\x18\xd46\xf5X\x9fE\xac\xcfz\x16M\xd2\xac\xdf3\x17\x1cH\xa1\xb7\xf7\xe4\xb0\xf7Nh\xa5\x91\x98j\x01\xd4\xb9\x80\xd4|\xf7\x08\xa5\xddG\x17\xa6\xea''5Q\xaak\xa0\x18\xa9}\xd0\xda\xf4\xb3\xcd\xdf>BA;H\xdaQ\xd4~t1\xe36u\xd3\x1az\xad\xf0Zz-\xd0\x18\x8d;\xf7k\xae)\x98\xfcB\x0d\x96S\x8a\xa4\x95Vt\xda\\t&\x8b\xae\xa9>\xb8\xb2\xa9\x12\xdd\xba2naU\xc6\xcd,\xca8R\xf5\xc8R\x8f\x85\x9d\xf4s3Z?wV\xd1\xcf\xd1\xed\x89\xbc\xda}\xcbe\xa9b\x19OQ\xa3\xa7\xe0\xdf\x17`\x03\xc5\x95s0\x9a]\x85\xe1\xd5\xf2*\xe1W\xe9Uvu\xc6]\xf7@\xaa\xef\xc6\x89\xc7\xa6\x1e\xeb\xfd\xb0g\xaa\xff\xd8\xcah\xe8\xb3\xab/\xbe\xb8\xfa\xf2\xea\xcd\xe1\xd5\xdb\xabwW?:\xac5\xc4\xfalnk\xac\xec\xdf\xbcK\xffT\x8d\xb6\xcf\xf79\xc0\x1d\xeb\x87\xd7\xa6\xec\x1b\xce\x06\xd8t \xea\xa6l\x10\xc0\x14\x97\x1d\xb0\x15\x18A#\xe3\xef\x17\x0eG\xd9Z\xa8S\xdc\xb5~d\xbdk}o\xfc\x93\xc1\xa4\xff\xc3{\x03~\xc1\xa7N,z\x10\xc35\xb1\xf2m\xf0\xe2\xf0\xf8\xf5\x9bW\xef^\x81\x91~\x0f\xac\xb8{\xe8\xc8\xd1I\x93\xa9{<\x1c\xa0E\xd3\x88\xf5z\xd7\x85\xc4F >\x18@`\xd6k\x8c\x14\x91~\xcf\x1d\xf7\x8e\x8f\xa7q\xc27\x7f\x9a\x1e\xa7\x0b?\xe1\xb3\xe3c\x9b\x95\xfdu\xa5\nv\xdf6\xed2\x83\xf6s[7\xb0\xa9\xad\x01\x88\xcb\xc2\x87\xcd\xe3\xce\x1de\xde[!JcN{\x05)\xe9\xd2\xe6>\xcb\xd8\x01\x1b\xb2\x11l\xda\xd7\x05\xbf\xa0\x9e\xc4 \xeb\xf88\x8cg~\xba8\x16{\xfdqqg\xe8\xf8\x988v\xb5\xb8OX\x17\xb9*PR\xf0\xa8\x02#\x983\xc7pZ\xcc\xb4\xf3sf\xc0\x8fULN\xf7\xd1\xa6\xb4\x98\xee\xa6@J\xb2VPx\x15\x86\x95.\xbeP\xd8\xfd\xde.\xf0\xbf\x7fx\x16\xc6\xe7\x07\xd5+>0\xc4X\x1b\xf8\xed\x0e\xb4\x01\xcb\xda\x06\xd9\xe4=\xacu\x9c\xe5\"\xeaW\x17#rdC\x8fEb\xe8\xfbh\x8d\xaf\x89\xd82i\x9d\x9c!\x83pS\x02\xd1\xc6\x96\x8c'\xb7\xc4\x88\x0cw(\xf6\x18\x83\xd7h\xcc\xd8*\x0c\xa6\xbc\x0d\xf2\x9d\xd0\x8bf}\x13D\"rN6\x9c\x88=A\xc7\x11N\x04\x9e\xa0\xd4\xd5\xd4M6\x14\xebm\xb0\x8a\xd1WD\x89\x8f`\x1e\xef\xb1\xcd\xcd\x02H\x1e\xdb\xba\xd6\x9e[@\xe9\x174z\x1c\xbb.\xba\x1dG\x93\xf1\xb0m\x0b\xba\xd5\xa1\x146\xaa\xd5\xb1\x08rW\xb91\xf6\x11\xba\xd2u5\x9b\x80\x8d\x01\xb0\x91\x15\xb0\xb1\x04\xac\xd3\xefkH\x12a\xec\xd0\xb1\xf8\xf0\xc4\x85\x08P\xe3X\xc0[F9j_\xdb\x0d\xc3\xddn\x1d\xae\x0d\x89\x12\x15\xf9\xcd\x95G+\xdb-\xa1\xebr\x01\xad\x14\xc9\x8e\xdf\xd2S\x1d\xd9\x9d\x1e\x9e\xe8\xd1\x81\x1b\xf0\x9bQ\xbe<\xe1\x89\x96\x90\x02\xe7\xa9%\x9c\xc4q\xc8}\xe9\xf4M\xf0\xa6\xc7\xc7@\x89\x8e\x8f{2\x10\xc0Hs\xce\xf7}\xceFe\x1d\xc0d\x9c\xf2\x0eb\xfc\x8f\xdc\x07\xdc\xa1>f\x1f\x1a\x16a\xd9\x0fz\x05F\x80\x8c4e\x03\xc1\x034\xeeU7\xdeHnk\xc8\x8a\xc9\x8d\xf7fK\x8f\xb6{7\xae\x8eI\xe5\xdc\xfdV\x90X\xa6\xa5(\x80{\x10\xe9u\xef\xac\xe2w\x9d\xbcI\x06\x8e/b's\xa9\xfa\xaa\x8dT\x11\xb8\x1d\xa2\x05&o\xaa\x05\xe0{(j\xec\xbb\xfe\xc8q\xa4N>\xe6\x13\xb8|\x90wu3k\xa6\x9cI\x8f\xbc\xbc\x00\x87\x95\xf3\x0ea'a\x07,\x1f\xa7\xc0C\x87\x82\xc1\x0c F\x9a\xb1\x1bH\x03w\x87\xf5[ \xf2\x02\x84!`AL\xd8~\xd4*A\xb2\x12\xc6\xd8F\xa3\x87\x15&\xe6\xce\x1d\x96\x8d\xb7&\xe3\xed \xde\x19\x14\xef[\x82\xbd\x13/\xc3\x89\xd8\x82\x8ao5\xdd`\x8e\xa4\x13Q\x88\xb6\x16QAB\xaf\x0d\xb5\xa1qwF]\x8d\xa3\xa064%U\xdbm0\xc4\xaf\x0bd#\x80\x99\x02\x1d\x91n4\x8d\xe1\x0b\x04K\xcd\xe4)\xdbg\x1b\xb9y8,\xce\xf4\x85\xdf\x98\x8dZ\xfc\n\x10\xb0\xf2\x8a\xc7\x03\x96nnZ\xa5\xabs\xd1\xbdqjq}=\x85`\xa18\xbbs\xc1G\xc0\x166\x9e\x8f\xb7&\x02\xb97\x1c\xf1\x06b\x92\xd2\x93\xcdFS\xac\x0f\xe8\xdec\xd6\xef\xa7\xec \x0b\xad\xbdZ\xb1}\xe6\xa8\xae\xb9V\xe7i3\x10\x0d\xaf,\xb9\x0b1IV\xaf\xde\xc5\xd0l\x04\xa5\xe6\x90\x04B\xdco8\xab\xe6\xd1\x8aG\xc6}\xb7\xd3\xbe3\x86Q)\x1bBQ\xe7.\x94\\\xb2}\x96;3\x8f-<\xb6\xc2U\xe1\xb13\x0b\xc5\x04\xba\xabwy f\x12\x0b\x8f\xcd<\x16\xb0+y_\xeeL,\xcae\xf3\x08\x1afP\xd5\xba\xc1\xa1\xad\xf5\xeai}J\xea\x07HT\xd1\xacu\x86\xbc\x01\x8b\xd8~\x04\xca:\xf3\xb5\xa2\xac\xe4\xd5o\xbd\xc3\xfa\xc7T\x7f\xbb\xf1x\xb7\xf4\xad\x9b\xf2r\x16\x8d\xe0C\xea~\x9fH\xaf\x97\x07b\xbd\xd5\xead\xa1\xeb\xa9\x8c \xbfLy\xd9\x8a\xe7ft1\xa6\xb1G\x91\xa5\x15V\xf0Gb\xab+\xdcT=a>\xdbd\xc3bM\xe6\x95\x83\\\x15\xd3\xfb\xfdH\xa2\x90H5\x9b7\xc6!\x17L\xe0\xe4\x1d\\M[\xf8Z\xc5\xd6\xde\x90\x93\xb5n\xc5u1\x9ade\xb7\xa9x\xa7\"\x9d\xd2\x1c \x14\xaa\xab?Sl\xbf\xaeq\x08ew\xea\xcdL%\xdfTO\x9f\x9b\x9c\xc1J\x0f\xac\xfaLy\xf0\xac\x9b\x97\xcc\xaa\xa5\x12\xff\xb2^b\xa1\x97\xc0M\xbb^\xe4\xec\xe6\xc2S\xc5\xa2,=v\xea\xb1K\n\xffO\x04+\xe2PG\xa1c\xc8\xc9\x88\x9cs\xb6\xcfN\xd8\x01\x9b\xb1\x11\xcb\xc9\xba\x87l\x9f\x1d\x17%\xa86.\xc4^/\x1a:\x17\x9c\xcd\x8a\x1d\xb0\x05\x1b\xb1sW\xfc\"8\xa6\xb7\xa2\xb8h\xf5P/~h+\xfe\\5|h.\xe7\xe7bK\x0fA\xd7e\xaedX\xa5!\x9cb\x8a\x8d\xd2\\l'\xe0+\xc5\x83A42>\xc5\xf76.\x8a\x06/A*x\xa964\xd7c'\"e\x8a\"\xdb\x98\x98\xb5\x11\x0bd\xeay%\xc3\x1c\xdb\x86\x13\xb1;lN\x0eM\xcc\xf6{\xb6\xcf.@\x0c\\\xb8\x96\xe9\x1d\x1f\x9f'\xfej\x05\x82jb\xa2\xc4\xf3\x8c\xed\xb3\xb7Z\xb5\xac^\x8d&w\xef\xc5\xb8\x9e5\x9d\x07_\xb1}\xf6\x9e\x1d0>\x00Wr \x11mp\x9a\xfe\x9a\xed\xb3g >-\x8bg4[d\x05\xf6\xa9\xf3\xcac\xaf\x15\x1c/\xdb|^\xd3l\xd0\x06L\xaac\xb6\xee\x9b\xd3w\xfd\xad\xd1\xd8\xea\xe4\xc1o\x9b6\x96\xd9\xdd\x1ev\xf5\xe3zv\xcbf\x1du.M\xb7\xef\x80\x02\xfel\xe6\x80w\xe1\x1a0\xc4\xe3k\xf4\xcd\x9f\xcd\xc0\xabP\x99\"\xb6D4\xca\xf0\x0d\xfb\x8b\xa0jj\xe1\x93\xf0\xad\x037\xba\x99\xae\xa6\x13O$w\xd3\xc8\xed\xb4s~\x9f\x8cX\xfb\xb7\xec\xbae\x00\xbb\x93\xb5}\xc2\x8a\xd06/I\x86\xb9\x93d\xf5\xb6(7\x17\x14\xdf\x90K\xfc\xafo\xf8\xa9L\xaf\xb7\x13\x9a\x1b\xbb\xe0\x01\xb6\xcd\xed\xbf\xd8\xa3?E o}\x93\xae\xf0\x03\x9f\xf9\x99aiZa\x05\xc0\xa3e#+\xf0\xa5\xbf\xa2\xf8\x00-\xd8\xfb\xf2\x84\x1bM,\xf5\"h\x97R/r\xaa\x17y\xcb\x0dn\xe3\xb2\x92\x0f\x12\xf0z\x91\x93J\x11\x10\x81\xd7\x8b\x1c\x1b\x8c\xcf\xa7\xf9|nv\xf8\xbc\x066\xffG\x01?\xaf\x17:,\x9c\xaa\x15\xeb\xde\xe2\x9b\xea\x02\x18\x83\x03v\x88\xfb\xc2\xabyg\xd7k\x8aX'\x1e;\xf4\xd8[\x8f=\xaf\xe3~z\x1e\x80\x0f4R\x8e\x05q\xdc\xceGF:\x93; \x1f\x9c\\f\xfc\x0bd\xf77\xc41P\xfb}u\xc50\xff\xd5|\x9e\xf2\xac\xcc\xc7\xdf\x8d\x1c\x88x8x\xa3:\x01\x00{\xd2\x1b \xfe2\xcbCG\x8f\xe9\x8e\x16:\xcb\xb6\xden\xbcu\x04u\x8f1\x18\x0c\xbce\xaeKl\xfe\xf0\xb5\xb9\xf95H_Y\xd2\xcf\x1a{\x178}\xee\xb1>%y\x86\xda\xb3\xc6\xda|\x10\x81Oq1&x\x03O+K\xe53\x1c\xc2\x9d\xe0\x0fK\xf3KK\xa7/\x9b?\x8b\xfa\xa0~\xc5(\xa9R\x7fA\xd7W\xbcZn\xa9vj\xaf\xf6\x0c5\xfd,\xb4\x8b\x8b\x80/sD\xfb)x{\x85\xb3\xde\x86\x12R\x00\xbb\xfa\xac\x15\xfb\x14\xfb\xf6\\\n\x1b\xec\x9f{U\xb4\xf5\n\xe0aa\xd8\xd8\xd5>\x9bz\xecyy\x14\xb5\x7f\xf858\xb4{\x0f\x88\xf8\x1eC\x15\x94\x0b\xb8\x91!|^\nm<\xf6\xda\x02\xde\x13\xfb\x8a.\xf9\xf8\x0b\xe55P\x0cJ\xfe\xb0J\xaf\x99\xb6\xce\xda\x94\xcf\xed[\xf4\xba\xec\x9c\x0c\xe1\x04\xd3K\xcb\xaa\xb8\x195\x82\n\xa5\x0e\x0d\x8e\xfb\xfdl\xc2\xf6\xc1\x86\x9e\xd7\xee\xa2\xb9\x1fC\xc4\xf5q\x86\xd786\xbe\xf6\xb0\xecv\xb3\x8f(\xf1\xc7\xd0\xe4xn\xe9\xb0\x8f\xf2\xde\x94\x02\"\x08@\xd8\x1d\x16\x9bp\x9c\x82f\x8e:\xcb\x0b6hJ\xf2\xffb=\xcc\x05\xe1H\x9c\xcc\xd5tC\x1b\xa1\x95z\x14\xd1\x8a\x04\xe34\x7f\xccV\x0dJ\n\xc1:M\xc7+\x8b$\x7f\xc3 A\xc0\x00^\x9aG\x9aA\xdb\xcc\xed\xa8\x95\x10\xdfX\x80\x190E\xc1\xc47`4\xa9\x0c\x87R4\xba \xa8\x98\x12\xf0o\xd4\xbc\xab\xa6\xba`-U\xf1P\xea\xdf*\xa0\"\x18\xb9P\x1c\x9eV\xec \x9b[!s\n\x1a\x10\x05\x1f\x8b\"\xe4\x12,\x07g\x16\xf0\xf9n!\xfe \xe1B\xe5%\x1cWg\x80E\x1c\xf0g\xc4|G\x9c`!\x15\xd1+\xb5)~u\x05\xc4 ;\x10=\xdc\xdf\xc7\xd3w.\x1bA\xd4\x84vO\xecJb\x90\xa8\xd0\x14\xfc$\xe1\xfe{#\xc7T\xe1.a{\x03\x9exZ\x1a\x92\x83m\xc6\xac\x89>\x83\xea\x07\xf0wi\x03\xfc1\xb0\\Z\xab4\xe8\xcf\x81\x17\xd3\x8a\x99\x03:\x16\xeb\xe6\\|\xad\xda\xc9@F\xec0R3\xd4D\x91\x01\x06\x8fE\xde\xb1.\xa6\x86\x14\xb2,|\xf3\\/{\x8eF\xdf\x08\xfa\x0e\x1bX\xaao\xa1\xc5\x0f\x81\xe0g?\xa8V\\\x9f\xf4\x13\x87\xcfJ|\xc7\xcd!F\x83\xb5 (\xd0\xdc|\x0b\x03>\x8e'b)E\xec K\xacK\xc9\x87\xa5T\x8fZ(\x9e\xcc\xf1\x01i\xd1\xac\xd9 \xc6q\xbf\x0f\xb1\x0e;\x80(\xf8\xde\x00\xa1\xa23\xaa\x91\xf2\xc7.K0(cf\x04'\x91\xbdKZzg7E\xa0\x05\xf9\xf7\xa9\xfb\xe2\x94\x94\xbcm\x0b\xb3\xc8\x1dbiZ\x9eHf\xeb\xc6\xd0\xb5|\xa7\x953[\x170C\xcbMz\x03`>\x84)-\xc1\xe3\x8f\x0b\xf0}\x1e\xc6~\xb6\xb3-\xb5\x08\x80\x80\xb5\xcc\xdd\xfbt\xe6\x8b({h\xcd\x19\xeeZ\xb3l\x1f\xfb*\xb06\x08Y\xcfC\x7f\xb9\xe23{ \xdb7E^\xe5\xa3\x1b[\x9e\x9e\xafaP\xad&\xdd^E\xf0P\xcb+\xe48\xb5\xf4R\x08afp#Q\nr\xea\xb3!q\xc5\xc8\x00\xa9N-MIrj\xc9J\x17TKVB\x9dZ2\x08r\xeaiRxSK\xfe1\xf7\xdf\x17\xfd\xd8\x18z\xeb-\xc1@.\xc1\xd8\xe1E\x94&\xb1\x1fm\xf8c\xb1*o`\xdaK\xfb\xa0\xd85\xac\xdfn\x81C\xae\x8f\x0dc5\xe9\xf1\x98L\xfb'u\xf6\x18O,,[$6\xe7\xc2\xec\xc6\xd5\x9c\xf6G\xae\xb9\x91o\x00\x03~\x87e\xa8\xea\xb5\x10\xe86\xcb\xd7\x86\xb3\xc6\x9e\xebh\x81\xb6<\xd93\x8b\xe9\x05}\xfd\xc8N\xe5v\\\x07\xae8y\xac\xa7\xd6\x8b\xed\xe2\xd9\x0d\x9a~\x9d\xc4\xcb \xe5\x1f\xa1\xe5\xb7<\xfb\x08\xad\xca\x95uK-o\x1b\x97v\xe5\x8aX\xdf\xc0\xb3\x12\x856.B8gE\x00\xda\xa8\xe1\xf4\x15\xc0\xf1!\xb2\x1c.\x90m\n(\xb6 \x99\x0f\xe9\x06\x96\x95\xd2E0\xcf\x9c\x06D\xd5.\xfe\x03k\xd1\xb64E\xf9\xc0\x89\x8b\xbd\xcb\xde\xb2x\x00\xf8q\xc3\xa2\xa2)-\x99\x8aS\xe1$\xec\xa9\xf4%\xa6\xf6\xbc\x91\xd8\xc0Y\x9f9\xd2\xc8\xfd\x80\xf5\x9e\xdc\x13TM\xfe\xee\xb3\xde\xd3\x9e^Jn\xa0\x82\xa1\x8aD\xe9\xa3Hf\x83\xa6\x10\xe4\xa0\xd4\xc2\xb3\xcfb`\xdf\xc2\xd4)kC\xc7\x138J\x96\xbf\x07\xfej\xc5#\xf0\xef\xe0\xe9\xf84\xc0\xc4\xb8\x92\xa8\xcc\x18\x9c\x0dq\x06\xdd\xd8\xeaB\"\xe0N\x06br\x01\xb5*\xbc4pi\x80*W\xbf2s=`=\x86e\xb5\x072\x0e\xd6\xabN/\x8a3\xe6\xa7ip\x1a\xf1\x19\xcbb\xe6\xb3\x95\x9f\xf0(\xdb\xa0\xf8\x07\xf5\x9ci\xfe\x91\xe8^\xaa\xa7\xf4H\xa3 f\xec\x0d\xe7\x8e\xd6[IT#\xaf\xd2\x02\x8a\x80\xfa\x82\xc1P\x94\xd6\xf5\x9agE\x7f\x14{\xe9P\xbc\xa2zlT\xca\xc2f\x08\x9a\xd7uJ\xb4\x0d\x17\x0d<\xc4\xd0\xe0\x84\xcb\x95\xd7\x1d\xc1\xe7\xaa\x1c\xd1\xd3\xce$\xd3*\xfa\xac]d+~}pK\xc7\xc3\xce\x83\x07\xf2\x80\xdd$\xe8W\xdbyu\x80\xbd;\xbd\x11\xeb\xdd\xf1\x97\xab\xc75\xa2x\xb7wW\xe4\xfc,\x8f\xb3zV\xef.VZ\xc5\xa9\x91\xf5\x04\xb2B\xb3\xceS\xc88\xcd\x1ek\xc1\xfa\xda\x04\xe3\x16\xa9\xb8$^\x92\xb2\x01\xf1*\xc4=\xce\xf8N\xef\xc9\xd3\xbb\x18c\xa1U\xd8\xa6\x04\xccFP>\xe0\xd9\xca\x8e\x92\xd0\xad\x91G}\x08\xf1\xe3\n\xdc\xa5\x19\xc1\xa3\x1dwpx\xc6\xa3\xecp\x19d\x19O(o\x1f\xe6A:\x913\xbd\x08\x0cu\xb5x\"\xe7\xe1\xd0ub\x0f\xfc\x97\xc4\x837%\xc5\x14_\xbc\x0f\x89?N\x82\xacH\xdc\xdd}\x00\x89\x9f\xe5\xab\x90_\xc8\xa4]Hz\x97\xf8Q:\x8f\x93\xa5L\xdd\x83\xd4\xd7~\x9a\xbe[$q~\xba\x90\xe9\x0f!\x1de\xe2x\xb0\x8bu\x97\x1f\xc1\x8a\xb7\xe97\xce4\xdf]6\xc9yL\x9fF\xf9\xe0\\\x0d\x07U \xb8\xd5\x88D.j\x80\xd5\xd8\xca\xcfS\xae\xbd\x1a\xc7&\xfa\x93\x01I\x85\xa2r\x1f\x82\x16\x13\x9e\xe6\xcb\xca{\xe3\xa9,\x1a\xc4Q\xc1\x92\xc5`,\x08 \x89\x1fD=\x8f\x05\x90r\x1c\xa4o\xb3Y\x00r\xfcL\x1b\x18\x1e\x9e\xc1\x119\xd4\x12l\x9c\xc7r`\x88\xc4od\xdb<\x96\xd6\xa5xg\xd2Ztch\x83oN\x0e\xd6\x87\x8f\xf9r\xc7\xe5H\xc7\xbaA/\xed\xd0 y\xa9\x8d\x0ff<\xcd\x92\xf8\x12\x17\xb6\xfc\xd1\xf5\xb3!M\xb7\xc5\x16:u\\OZ\x02$\x830H3\x1e\xf1\xe4\xb9\xd8\x87\xa4\x13\xe1\x1e\x17\x9bi\xcfU\xfbk\x9d\xde\xd2_\x9cZ\xd1d\x19\x9f\xf1/\xe4wjsndj\xf3oV\xd5\xe7\xb9\x9eW\xce9Y\x13F$\x98%\xea\xabz\xae\xed\xab\xd3\xc6\xafN\xc9v\xcb\xdc\x86\x95\xa0\xc8-br\xa5\x9f\xf5\x14\x1d\xdb\xa7\x06\xb6O\x8b:\xd5\x14<\xca\x08\x02\x04gL\xaf\x95\x86\xbb\x10`\xa9\x89\xac\xf7\x04!I\xb3$\x98f=\x92\xaa\xdf\x1f\xba\x03\xbc\xadDZ\x08\xec\xb6z\x9c\xaf\xe3R\x81f\x9cD\xb3\x8d\xf6m\x8d\x15\xa6\x91\x9ci7E3Wg#\xdf]\xae\xb8d%\x9f\xfb\x91\xe0&\xc5>\xc3|6\x0d\xfd4e~\xca\xfc\xe2K\xc4\xb9\xf0C\xe9\x86\x1b\x19\x9e\x05\xf7g\xd2LK\xa6d~\x10VS\xe4y`\xdf\xea\\\x99i\xbb\xbc\xe9E\xaa\x99QS\xbc\xad\xe5h\xe9g\xbe\xd5;Y\xc4/2\x94G\x99\xe34y3}(O\xc1\x16\xa9\x18.\x88}@Q>\xaa@%\xab\x82$\xf3\x98\x8c\x01\x80\xcdT\xa1\xe1U\xc6\x9eG \xfc\xfe\xf8\xc3/\xfa\xdb\x05\x062\x06\x89\x06 \x10\x06\xebc\xac!\xc6:c6Fl#\xf0R\x00V\xb6\xdat`\xe5\xeaH#z4\x10\x10\xa1\xcf3\x12\x01\x87\xc6\x10\x0f\xaa\x03\xaa\xe1x}\xca\x8b/ \xf0\x16\x91A\x949\x05a\xce\xde\x04\x11\x15\xf5\xae\x11\"M\xbdkY\x81\xd5\xaf\xfd4\x0e\xda\x1d\xb8#\xfc\xf7\xeb\xf0\x97\xd0\xa3|\xe6Tn4\x15\x9d\xc5kM=\x14\xc7\xc3\xacHoH\x02n\x8f]\x16\xb1\xfe>\xe8\xc03\xcb\x9c\xd1f\"5\xf8\xc5\xd1\xd4o_D\xcdcJ\x06~\x18\xc6Sg\xcbb\x8an`LQ\xb3\x0d\xedJ\xc8\xc0\xb19F\xb3)\xf9\xbd\xaf\xa2\xd4\x9fs\x87\xb3\xa7O\x9f\x82x\xd2\xaf\x82/\x17\xd3\xf9\x98\xf9\x8f]\x00\x9c\x0f\xdf@\xa8\x06x\xa3>\xf7@\x97\xb6\xbaD\x9b\x1fQ\xa5\xaf\nV\x0c||\x04\xba\x0d\xc4\x81\x01\xe2\"\xe1\x83`\xb5d\xf4\xb7 JW|\x9aU~\x0c\xa6y\x9a\xc5K \x13\xa5t\xa6\x98\xa0q\xbd\xe0\xa4 \xd9\xd5j.*\x11r5\x1c\xd6\x88YI\x8e\xe5\xf2\xa6(\xae]\xfa,to\xa0/\xd2\xc6k=rw6H\xa2\xb6\xef\xea\xeeN+nH\x8eD=\xb0\xefC0\xcb\x17\xcb%\x9f\x05~f\x95jH\x05\x0d\x1a\x19I\xbf3\xe6}7\xfd \xe1\xa2\xbb=\x7f\xda\xa0\x9baRw\xc3\x07\xb3x\n\x922{\xb9Uitt\xca\xb3\xd7\nI^\x81R\x83\xcc\xb0\xba\xb0\x12M\xad\xc0\x92D\xc0\xe4]\xb0\xe4q\x9e\xc9\xe8\x88\xdc+\xfd\x1c\xac\x92x\xca\xd3t\xd2\x835\xfc\xf3\x0fEpIy!x \x0b\xa0\xb1m\x1b\x1dQ\x8f\xa6\x07j\xa4\xdc\xfa\xb3p\x88\x0b_\xea\xb1 \xb8\xd8HG\x9d\xa6O\x80\x12u\xb0\x8a\xd3\xecK\xe9@M\x9c6\xf9 X\x8a%\xf9v\x9a\x04\xab\xccj\xef\xa3\x1eE\xc47\xb6\x9a\xa5\x88LJ\x12\x05\xb3nu\xd1\xa6?\x05\xf3W\x94o\xdb\xf4\xeaOF\xeb\x10\xf4\x07\xf7\x86\x12\x02N\xaf\xe7\xb1\xde'=y\xaa(?\x1c\xd5o\xd9UZ\xa1g\xc2qA\"%\x9b~\xbe\xf0\xa3\x88\x838\xdb\x01{J~\xce\xaaY\xee@\xc0}H\x0f\xb8\x11\xb9\x16\x0e\x07\nn\x93y\xae\x81\xa7\x01tb\xbb\x02\x14\x0b\x16\x82l\x0c\x16b/\x8e\x12\xee\xcf.\xd3\xcc\xcf\xf8t\xe1G\xa7\x1c|\xdd\xcc\x07\xd3\x84\xfb\x19\x97\xa2w\xa7\x97\x02R\xf5\x04`\xc0\x8eq^\x90\x00Yd\x9d\xae*\xd4\xb3~\xc5\x8e`\xd9\xc0\xec\xf1:\xe8%E\xbdt+\xc8d\xc5\xf2d\xfc|\x11\x8430s\xced\x9e\x1d\x8fD-\x94m\xabZv\xc0w\x87SI\xed\x9c\x85\xc7\xb6\x8c\x1bF\xea\x11\xa4\x03\xc43=}\xcf\xf8\xa1\xd8\xed\xe0\x16P\xe2G\xb3x\xe9\xc8@\xb5\xc8m\x14=h4a\xcc\x06i\x9c'S.ob\x08\x8c\xd1\x83sI\x1b\xa5\x812\xe9\x93|\x172%A4\xe3\x17\xaf\xe6\x8e\x0f\x02\xbd\x85\xd3\x97\xe9\xa0pq\x14\xd3b3q\x14\xeb\xd8\x9f\xcd@\xd8\xaad\x14\xb0*\xeb\x89NO.\xba\x1el\x7f\x1bC\x10\xfc\x0e\xfc,\xf3\xa7\x0b(\xe9\xf4\x8a\x85)\x052Ig\x00T\x89\x8c/XX\xa43\x96\xf9\xf5p\x93*&\xa1\xf3\\kR\xb5\x8d\x9a\x19/\x97DGy7q\x80\xd1\xe6MF\x7f\x156\xbd48.\x14\\\xea\x10\xb1 \x11\x0f#\xe4>#\xf6DwM\xd0\xef\xbb\xca\x97@Qo\x0c\xaaA\x8b\xdd>\xd3\xec\xbe\x9aW\xa1\xd8\x8fO\xfc\xe9\xfbF_\xe3\xe2\xf1\x93\xd3\x942\xb8S\x0fq\xacU\x8f\xdc\x86\xc2q:A\x01w\xe2\xa4\xae\xc7\xd2~\xdf\x86p+<\xa2\xe9sG\x1c\xa4\x1b\x8c\x08f\x0d\x16%\x18\x947\xac\xdfhd-M6\x18\xa9\x80t\xd4\xa5\x88\x04\x0d\x94\x86\xe88L#\xca!\x19\xebV=p\x85\xad\x8d\xc8N ?|\xf5'K.;p\x02\x1b\x1dW\x8f\xfe\xa8\x81\xa0RW\xa0Y;\x83\xa3\x9e\x04\xea \xack\xee\xbdz\x94\x91u\xd2\"\xbb\xa0\x1e0\xbc\xde\xb2\x1b\xdfRO\xa3\x01%\xf5\xb4\x98i\xd7\x1f\xe8\xd3p\xdd>%\xe3-\xeajw\xd3s\x9d~m_\xa7_\x1eK\xc6\xc3\xef\xa3w;\xd7\xef\x9d\xf8\xbb\xfd\x91\xfb\xd8j\xebM=\xa0\xb0\x0fA\xe4@\xd8{P\x0f\xcdQWJ\xd8\x98\xa3\xa2\x00\x9b\x07\x91\x1f\x86]\xe8\xc3\x0c\xd8\xb9i\x87\xf3\x825\xb7\xab\xe1oM\xb6\xe7\xf4\x8a\x98\x05:/\x94\xf2p^^aW\xf7W\xb3E\x90\xc2\x0d\xd7\x11\x14\xd0\x94\xc0\xba\x11\xc0\x0e\xec\xc5v[\x80\xee\xd7\xa2\x8a\xed\xc3B6\xed\xc4\x17\xadV\x06a<\xf5\xc3\xb7Y\x9c\xf8\xa7\xbc9\xe6\xda\xd4\x07\x02\xd8\xe6\x15\xa45\xda\x19\xd3U\xca\x95\xef7\xc6^\x97>#\xc0\x9c\xac\x97%9\xc7\xc3?\x9e\xfb\x9d\xc8\x1dd\xf1\x17\xf19O\x9e\xfb\x84\x06Y\xff\xd5\xf9^\x1fS\x97a\x9c^\x14\x7f\xc6W \x9f\x82\xe9ZO\xbb\x97g\xf6Wi\x9b(\xd7\xaa\xf5\x9b\x82M\x1b\xfe\x06ycS/\x119=\xd0\x10\xd5\xbaV7>\xb29\xf7f`\x90\xd0\xcb\x12\x7f\xca+M\xb0\x036\x8d\xa34\x0e\xf9\x002\x1d\xf0w\xa4\x92\xce\xfd$B7\xe0\xb0\xf7w\\SL\x17\x17 \xa9\xc9@%UZb\xb5\xadC\xebR\xea\xb4\x86hA\\\xc5\xf9N\x99\\j\x0cw\x86\x96+\xe5[\xbbd\x00\x98\xc0\\\x1f\xa8\xdc\x03\xc2\xa0\xe9\xf7\x82\x12\x890v\x98\xe1N\xbb4%!\x02\xe8\x8b'\x1e\x04\xd1\x82'A&\x1d\xc1\x0c\xc1\xd2C\xa59\x01\x9a\x99\x04\x9a`\xfd8\xd3\x8cF\x9a\xa0\xc5\x007\xf0\x94\xdc\xea/\xa4\xc1\xb6&r\x86\x8f\x1et\x9a\x9fj\xad\xdd\xebT\x1a>\xba\xef\x96f1\xd7\xac\xaf\x19\xd0ti\xa1M\xe3\xbc3\xa4\x02\xe8\x8bt\x8bK\x82\xbd\xf6[\xea\xf5\x89\x92\xaa\x08\xbc\xac]\x1e\xe0\x0c^H\xa2\x9b?\x88\xe2d\xe9\x87\xc17<\x81k\xa9\xa0\x96s2\xed\x8678.+\x95\x0d\xa5G\x0c\x7f\xe0\xa7\x97\xd1\xd4E\xcf\x04\xfe`\x95\x04\xcb \x0b\xce\xc4\xd6\xa7\x8c`\xd8A\xf5\x13p\xb1z\x0b\x0e\xeb\x19\\\xb3\xc0\xaaF\x89m\x17<\x7f\x8f\xea\xb5\xb5vE\xb1\x1d\x17bQU\x13\xf70Q\xbc>\x84f\x8a\xae\x82\xe5\x8f\xb3\xb7\xf5\xc8\x95Q\x8d\x96\x8146r\xf6\x86\xa0\x9f\x19\xcc\x82t\x15\x97\x89\xbb\x90\xb8\xf4/\x9e\x9d\x16i{*M&lc\xcd\x84\xcf\xc1@\x85'*}[\xac8\x81(\xfe\x9a\xab\xa6\x0d\x91v\xf7(D\x02\xa1\x8f\x7f\x92\x9a\xa8\x049\xf30\xd6\x1dbwC'\xa5>J_\xfa/\xd1_\x05\xba\xe8\x00,\x11Get\xa7\nN?\xee\xdcaA\xfay\x10\x05\xe0\xa2\x1a\x1c\x0dq\xf0\xf2\xe1\xc4\xd2\xdfP\x9bQG'0\xd4\x88\xc3\xde\xb6\x0b\x82[\x18c\x1a\x9cF0\xf5\xbb{;\x9d\x88F\xfb'\xac\xfb\xb3Re\x15\x1f&\x17\x18m6\x05h/\x0d\xe0\x9c!z\xa5\xdbT\xbf7\xb7\xb7\xd6u\xe7\xb1\xc60\xec\xb6\x99\xdadz\xe5\x8c\x03Q\xd0=\xb2pi:\x81>pn\xa3\x9f%b?\xa0\xbd\xd2\x0e\xef\xd7\xfd\xdaH\x02Y\xf7\x98$\x03V\xee\xd1\x01+\x05\x9dm\x86\x0e\xe3\xb4\xb3\x81\x08oCUgX\xec\xe5\xe8\x10\x03n^I\x97\n\x15\x9a\xebjtG\xd1\x1b\xc2\"\xfc\xd5J|\x1d\xf3 l\xe8\xca\x9f\xf4\xb4\xe6\xce\xa8\xe5\xcc\x9bbEt\xd8z\xa0\xda =6\xf7X4\xe6\x13\x88\xe9\x81Nx\xc8K\xe5\xb6\xe3\xea\xad\xe0\xf2\xae%\x16\xe0\xce\x90\xf6K9\xbco\x89 \xfcp\xcf\x1d,y\xb6\x88g)Ejw\x0d\xff\xc0\xa9\xe4\xec\xeaG\xa8\x90^\x0cp,\xac\x96\x9cv]6\xf3re\xa0\xa6\xb1\x9a\xad\xd9(\xa0(G\x12\xcb\x80\xd7\x86\x82!1\xe3\x9a\xdf\x80\x05\xa4\xf2e\x90uXX\xc4Q\n\xec\xbb=vVD*\xf5\xd8\x89\xc7\x8e!\xc8\xec\xa1\xc7.0\x9a\x96\xc7\xde{\xec\x99\xc7^y\x10tk\x0e\xe7/\x9a\xe2c\x00\x11y\xa1\x14i\xb9\xdc\xbd\x0b\xf14\xee\xd6\\#\xe8\x1aW-\x10\xff\x02\x9cu\xea\xc9\xae\x07Qq.\x06\xa7<\xf3 \xf2\xcd\xc5 \x15\xaf\x97\xf0\x8a\x9a\x0d\x0f\x02\xd9\\\xa0\x06\xc5\xf5J\xc1\xcc \xe1i\x1c\x9e\xf1$\x85\xe6_\xc9\xad\xa5H\x15\x8b\xfa\x19SA\xf3\xed\"-Vn\xc0\xd2\xb4\xaa\xa0 &\xf9\x10\x1b\xf2+\xf8\x1e\xf8\xbeq\x02\xb7\xec\xd2>n\xd2K\x91\x08\x8aIb\x9b|-f\xab8\x89C\xe0]_Z&\x9f\xf2\xac\x07\xab6@s<\xd7c\xaf\xc9\xe8%\xa2\x0f\xe8tO\xf0LAi\x808-\xe8 \x9e\xe2\x83\xf1\xd6DP\x80\xb0\x9e\xae\xfa\xbc\x8f\x9e\xa1\xecB!bd\x8a\xb7H\x9c\xde\xf3 \x99\xe6\xa1\x9f\xb0 :\x8b\xa54\xc7c\xbd\xe7/\xde<\xff\xea\x8bgo\x8e_\xbc\xfc\xd1\xab\xe7\xcf\xde\xbdx\xf5\xd2\xa6x\x17\xad\x9e:\x01!\x8bA\xa5\x92\xe8C\x03\x18o\xa9'r6^\xa3J2\xf6\xd8s}^R5/R\x89/\xf8\x90*\xfd\xf4\xd8\x99[x\x15\x14\xeb\xa3Q\xe0\x06\xc7gzV-C\xc5\xbb\x02\x8dh\xa3\xae\x13\x14\xa8[\xe2\x90\xc5\xaa\x10\xf4m:\xb2\x97xT\xc7\x97Rf\xc6F5$s=\x1b\x9a\x17\x9d\xbe\xe5IB\x93\x000\x19&\xa6\xa9\xb8C\x8eV\xad\xa6'l\xdd\x93\xfa\xed\x92\x02\xfd\x8e'lyRT\x0c\xab\xd0\n\xa6\xb8qZ\xe3*5\xa0\xfc\xda\xc12\xbd)5h\xe8\xdc-O\xdf8\x16k,\"'/V\xf3\x16U\x82\xf21\\c>\xa9\xfc\x8f\x93\xe04\x88\xfc\x90T\xf8+n}\xc4\x9e\x99\x99\x92\xd5\x7f \xde\x83`\xb7W?\xcd\xb2\xa7<\xebr\x15T\x0e\xf2U\xc1\xe8\xbdr\xb8\x0b\xbb\xdc\x01[\xa2\xb3\x07\x89\x14\\L\x86I\xf5\xcc//\xfct\x8d/[\xe6\x91r\x12o~\n\xf7\xdb._\xb3\x900\x86\xfd\xa5{\xc00\xaa\xfa\x9d;\xec\x12-\xa5\xd8>{\x0d\xbc\xaa\xb4`\xc0\x1f\xefu\xb4\xc0\x9c\x1e\x86\xa8\xa3\x1cE\x99\x83\x006a\xd4\xae\xf2P\xa2\x15\"N(\x83\x80\xc8w\xee\xb0\x13q\xe6\xd3X#\xaf\xe8\x18|\xa5\xd7\x15\xb0q4j?\xb52M\xa0#\x16\x7f!\x10y\x0bz\x0f6\x02\x1b\xac2\xf9y\x91,\xa1TZRA\xfcW\xf0\xe41\xab\x08\xf5i\xdf\x15f\x7f\xc5\x18Glaf\x14\x87\xe1\x0e\x00\xe6\xc8\xd9\xca\xe5i~\xb6\xbe\xbc\x8fMV\xcd~\x95\x05-\x8b\x1a\x883.A8\xe5\xe1\xf1\xae\xe4d2\xe0d\"\xe4\xd1\xfc2\xc6]\xbdC\xeb\xec\xe9\x85\xa8[\xb6&7\xbfj\x93\xacmi\x11\xe4\xa3\xdcTp\x17\xf1\xcb\x00}\xf5\xfe\x9e\x83\x14\xbd\x95\xf5\xe0\xad\xb0\x93\xdd(\x87.\xf7\xdc\x91\xda\xef4\xb0r9k\x02\xa0%u\x8b\xb0\xb3bE\x9b\x82\x97\xc3\x8f\xd6O\x1f\x82\xd8K\xd8\x93\xdd-\xb1\xa0\xa1\xe3\x1210\xe6\xbe\xd9\xff\x95\xf3\xcc#\xfa\xac\x0b\xbfF,\x00\xd7UV\x12\x1b8\xc7D\xae\xa4]\x81\xe3\xab\xd3\x8e\xf9\x15\xd8\x89\x02\xe7\x9c\xca\x83\xbd\"p\x0e\xcd>\xfbE\xca\xad\x1c\xf1w\x86T \x10q$\xb7h\x99\xea\xe2-\xb1\x97\x83`r0\xf5WY\x9e\xf0\xb7\x99?}\xff.\xf1\xa7\x9a(\xa9\xe2\xab\xa3U#\x15I{D\x94wR\xd1n\xf3\x8aphH\x88\x90\xd2\x9a\x90\x89<\x0b\x07N*\xddm\xe5\xb8\xa9I\x8f\xa4\xca\xa9=hdR\x19\xd50\xc2\x9b\xb8\x81*\x1b\x0d\xa6\xf1L\xe0^\x0eWu \x08D\x84\x8c\xea\x9a\x0e\xa8\xd7\x90\xc7\x93j\x05\xdc\x81\xa5\x90\x02}\x85t\xd7.H\xf7n\x0e\xed\x15e\x1e\xc7#\xd6K\xfcozu\x1ae\x96=\x11\x18\xdf\x9b\x9d\xfb\x1d\xcaf\xc97\x97#\xd6\x13\xffz\x06\x8a\xf3\xc1<\x8eY\x9f\xf1\xc1\x89\x9f\xc0\x7fQ\x0eh\x83\xe8\xca\xec\xdc\x87z\xb7,\xb8\xdd5\xa2B5Hn\xd7\x08\x9c`\xd1\x10\x94\x17q\x02\xc3\xe4\xd6c\xdb5\xbe\x1blu\xb9.\xe9\x04n\xb4b\xa4M\x8a\x1a\xedV<|\x9c@\xfc\xd1qBX\x9b\xb6\x9a\xecD\xe8\xac@\xac\xebV\xf3\x0bd\xf8\x87\x8f\x99\xcf\x9e\xb0\xf41\xeb\xf7}y\x85\xadX\xa0\xfe\xc4\xc3\xf8\xd4\xca=Q\xee\x9a\xea\x13\xcd5KT\xe8EHL\xff\x18\xaa\xc3\x87CT\x1dj\"vT\x1e>\xdc\xfe\xd8\xcaCz\x12\x15\x8f\xa1\xf9\x96\xed\x15Z\xf5\x1ex[\xac\xceC\xe3\xa4\xd26X\xb7-P\xa6\x94#\xda\x00\xda\x96S\xbd\xe3\xb2\xd31x\xc3-\xe6\x06\x8fg\xeb\x1a\x9f\\\xab\xef\x04\xc5\x94\x9f\x18\x91\x97\xa6\xf0\x16\xda\xc8\x98\x9ak\x0e\x1c\x86}\xe7\x0e\x8b\xc7J11\x11\xebr\xdd\x10\xb9\xed\xa8)\xd0\xfc\x01\xe2\xbf\xbc.W\xb9s\x9b\xf9A\xa4V\xc3\xee\x0dV\x83\x82\xb6N\xe6\xd7\\+M{]R\xf6Ulz\x1b\xcae\x88Ju`\xf7R\xbe\xeb\xeby\xf38\xee\xdd\x8e\xaa]\x0d\xd3\x00\xa5\xbc\x0es]l\xa8\x1d\x11+\xcae\xf6\xf46\xf5\xef\xb5\xeb\xa4\x9er\xc8N\xe9\x80\xe6\xb4^t\xd5Y\x953\xeb\xaa\xcaY4\xabr\xce,\xaa\x9c\xda\xe7\x96]5>\xa7\xed\xc1n\xab\x15.I\x8a1\x8d\xa3yp\x9a\x83\xf6\x95\xa6\x1a\xbc\xd0\xce\xd2\xae\xaf\x95\xa7\xa4&\xba\x92\x1b\xdf\x164*i\xe3V\x98\xe2X\xac\x87\xb69\x185\x9c\xea\xb8\xd7;>\xe6\x1c\x0c\x07\x0e4\x07s\x90&\xcer\"\xe9rp\xe6\x87\xb9\xe0h\x16J\"sV\xab\xed\xb1K\xd7\xd3\n\xcab\xd1\x98O\xd8\x01\xe5t]\xe6\x88\x7f\xe8\xb1\x0d\xacO!u\x9f\x8dQ\x9b\x9aM\xca$\xe9\xad\xa3\n\xb1\x1a\x8d\x8f\xa6|\x04\x94\xbe\x1b\x94<\xdd'\x98z*\x80\x8a\x95[>c\xb9F]\xee(J5u\x8c5\xe0*\x992\xdah\xb7\x8a\x05\x07;\x02\xba\xaf\xa2i\xe1\xd4\xe7\xf8\xb8#(\xe6\xf3\x11\xf0\xbe]!!\x89\x04-\xe7F`l\xd0hS\xf1\xa7@\xd7\x97q\x80J\xc4r\xc7|\xd2\xa1\x9e\x896\xe8`T\xd46!\xc6\x14\xeb\x1d\xe0\xed71y\xc98\x98\x08\x1e6pY\\\xfa\xe5\x8d)\xb8b\xae`\x94\xb7\x95s*%\xd2\x97(\x98\x8c\x03i%7\x14\x88\x99\x0c\xd2\x15\xdc|\x0c<6\xa4\xee\xee\x81*-)?\x9b4~V\x8ac\xa3&\xeb\xf8\xb6iG \xa2\xdfzG\xf1\xac\xf0j\xd18\xef\x16:!\xb6\xe3\xb8:\xa1\xf6\x19\xa1\xe7\xb1\xd9\x19<\xccbD(\xc9d\xac6-\xde\n\xdew\xcc\xf0\xc8\x92\xb1',\x12\xd3\x9d\xb9,\x18g\"\xb3z\xd91k\xb8\x08\x07\x1f\x8d\xc1\x81\x05^h\x95\xedn=\x06\xc2\x1b\x8b\xca\xd8\xb4\\\xc5I\xa9\xc9!\x1b\x95\xbaTu\xa3\xac>\x96&\x00t\xb9\xb55+\x88\x0b\xe8\xa9\xec\x03c\xedw\x8b\xba\xdc\xc6\xaa~\xaf\xc6\xb0\xdc\xfc\xeb-\xb7\xad\x9a\xbe\xeeU\x84G7\xebK\xa7[U\xbf\x10\xfc\x14\xcf\xaa\x06\x05\x1b\xe6\xfd\x80\xfe\xf5\x81\xf2\xc6,8\x8b\xa9S\x17z\xe2^:u\xe2z\xba\xd8X\xa6N\xe0R\x84g\xea\xe8\xe6\xd0hG\xb8t~\xfe\x01\x85q:{\xdc\xec\xf5G\x19\x8bi\xa1*\x17N\x88\xce\x88\x8bSc5T\xa4\xc72e\xb4\xc4\xf6Y\xfe\x03vS\x8eY\x9e\xa3\xea\xb1~\x1b\x04\xab\x04\xdb,\xf88\xd2=q\xf9\xbdf\xe7\x01\x1a\xdd\x1f,\xfdU\xbb#hU\x81\x1d\xb0\xcc\xe1\xe3\x08T\xcf\xe2\x7f\x15%\\\xe9|\xc9\xc9+Zi\xf3\n\xff\x07o\xbdc\x0d\xc8\xbd@\xe0\xd516O O\xc5\xbe\xa1Zq\x05\xd7u\x12D\xb3\xf6P\xb6\xddg\x16\x8f=\x8f(S9\x9c\xa8 \x85\xff\xd7<\xd5\xc5(\xda\xe0\x10\xce\xfdv\xba\xdd\xe9 \xadD\xcb\xc8\x98\xe2H\xe6I\\\x0b\xc8\xd5t\xdcF\xff\xed\xe0]\x00\xe6p\x0c\x82d\x0fe\xc4\x13\xd7c\x9f\xc6q\xc8\xfd\xc8\x01V&+}.C\x01\xd4\x05\x81]\xf4m\x8cY\x13\xe4<\xdav\x07A\xc6\x13?\x8big\x8e\xc6\\\xca%\xfa\xc8fAN\x1a\x90\x1bK7\xa5\xe5\xc9!\xbd\xfe\xa7\xf2\x9bur1\xaf\xe3U\xa7c\xb5yX\x9e\xdd\xc6a\x94\xc8\xd7\x0f\xa3f.\x1c\xe6\x08\x1f\x8c\x1f\xac'\xf9\xeaQ}\xddET\xb2\xa5V\x13\xcaV]\xd2\xdbF]\x128Z*%\xf3)J\xe6C\xe7B\x06\x08\xbf\x90\x0e\x12\x99t\x19\x0eh\x0e\x13'R\x02\xf4\xf8\xec\x16\xbe\xf2\xaa\x8d[\xfc1\xc0 \xe8\xc2zF\x9c3y\x89F\xaeN4\xf7tN\xb5\x10\xc5\x82\xa4 \x16\xc9\xdb\xdb\xf2\xc2\x9e8\x9f;\xcb\n\xc71t!b\xd9>\xe3p\x19}i\xe1\x86\xf0T'\xbe\xda\xc2\x85W[\xaft\xaa\xe2f\xe4T\xb05\x91\xcb\x96h\xcc\xc7I\x0bJ\xf5\xc8\x91.\xc9\x02\xe6\xa5R3e !\x03\x7f`/\x040\x9f\x1bzdf*'\x9cs\xe8n2\xb1\xc2\x02\xe0p\x02f\xae\xe7\xf2J*\x1a\xd2\x08\x82\xa9\xe0#\x0e\xc8\xe2l~\x02\xce\xc5\x9c\x128\x1b\xc7\x83Y\x1c\xf1\xc7.(\xe0/\xd8\x81b\xe2\xd0\x1a\xf8\x18%&\xd2\x90\xbd\xf8%\xf6ogVHS\x0e=\xb6p\x96\xb02fp\xddJ\x82\xf9\xb0\xfe\xd1~\xdf\x125K\xcc\x1c\x11\"\xa84\xf7\x9c6`\x03@\xe0\xb4\x123\xdb\x1c=\x8c\xd7\x03\xb9]\x0d'\x0e%B\xc8Py\"GZ%\xed\xb3\xc3\xc1t\xe1'\xcf\xe3\x19\x7f\x969[\xae\xcb\x9e\xee\xb3\x07\x0f\xb6\x1f\xed\x82\xc5\x12{\xb2\xcf\x1e\xec\xee\x0c\x1fA\xf9Cp:9\xee\xf7\xa3\x89\xb4g0\xc0y(\xedG\x0e\xad <+Ax&A\xd8\xef\x9f\xd9\x81v\xd6\x82\x8e\x1a:\x89=\xf0\xd4D\xb8\x02z\xbe\xa3\xad\x9d\x1a\x00\x9dS\x97^P\xe40%4\x15o\xd7\x1d_H~\x00\xbb2\xab\xc8\xee<\xb6,/\x89B\x8c\x90\xa2\xe6\x0d\xf6\xf5\x9a\x96\xe2\xd1\x8e\xd4R\\.O\xe2\x10U\x12\x8f\xee\xdf\x82J\xa2v\xc2)\xf48\xb5-\x1e>[\x91\xc3\xb6\xe9vH\xbe\xcb\xdcb\xc8{(8J\xcd\xf9Bm\xf7`\xfb\xb2\x88\xd3\xcbx\x9a\xc9\xee\xd5\x8d:i\xf5\xa22o\xac\x9b>\xddD\x89\xa8\x97\xd9H\xc6\x95Q\x14,\xd9\x04\x953F~\x16\xbfV\xdaM(B\x95\xc0N\xbf\xf3O'\xb7\xc74\xea\xba\x0e\x8b\x8aC!_\xfdZL\xd8\xac\x90\x98v\xd54\xcc\xbbi.V\x84B\xc2d\xfa\xc2\xfa\xed\x90\x1az\xed\x1b\xe8U;\x97\x14X\xb5\x06\x1a%\x8e+=\xda6i\xa5\xeb\xeaf&\xe7`\x81\x9b\x80\xb3(\xbb\xef50}57\xbb \x92\xc0\xc5\x98c\xac?\x8c\xa1q-wF\xe3\xca)\xb4z\x98\x8f\xbb\\\x8f5\x89[\xbd\xb3\xfc\xd6:\xeb\xc3\xcdrP\x04\x01\xf4CG\xf3j!\xc5h\xda^\x0b\x01\x1a{\xa5\x15\xa1\xe0B\xa6ND[ \xce8\xfa\xa2\x0c\xe2\xe8\xf8x\xc4r\xf0/\x9aQ\xe6|\xc7\x91\xbf\xe4e\x993\xa7n\x02\xfd\xa1*\x1f\x99:q\xfd\x93\xf38\x11\xd5\x9b\xb1L\x0ez\x86\x8a0\xf87\xc2\x7f\xfb,v\n\x8anHE*\xbf\xdf\xf3\xcb\xcf\xbb|\xccb:\x0e\x8b/cA\xc4R`jgv!\xfel\x9cM\xd0\xd6\xb9\xd4\xdc4vm\xe1\xa7/$\x96(X&\xa8\x06\xd1r\xd0\xa2\xaf\xa7\xa5\x18\x01\xd3\x83\xf49\xc8\xaa\xde\xaeT\xc8\x97Zsf\x01\xd9\xaa\x99a6.\xf7\xb1z\x932Y5$\x7f\x1a\xd5\x97\x82\x1c\xd6\xeaB\x9a\xac\x08\xefF-\x19\x19\xa9VO\xc5N\xc2\x9a\xf2\x97Q7\xe5~b|\x12\x13eM\xfcaV\\\xf1i\xc0\xd3zMLUU\xf1\x17Q7\x0c2\xa3f\x18dE\xbd0\xc8\x8cZ\x1a\x0fP\xab\xab\xe5\xc8\x16\xb4\x14\xa2\x9d\x82S0\xda)r\x8av\x8a\x14\xa3\x9dW\xddS\xdfoT!\xeb\xc2_E\x95j+\xae\xd6\xb1\xd8\xde1\xfd\xcb]\xbe\xaa\xc8\xb7\x031\xdcQ\xf01\xa8\x91Q\xd6g=\xd70 \xad\xfc\x863\xc5\xaby\xd7\xaf\xa6\xb5\x98Z\xcc\x1c\xe5\xbc:\xcaXG&\xaf\x0d\xac\xea\xfa\x89\xfc\x0e-\x1e\x95\x8cw-B<8\xc8(0\xce\xd1;E\xf7\xaa@D\xe8\xd5\xb4\xe7)\x98\xf6\xb0B\xd0^!\xae8\xe3\xafp\xcct\x13UHPM\x94l\xf9M\x1cj\xe9\x02\xda\xdd\xb5=\x19\xa1\xdf3\x108P\x9c\x03\xba\xf6/\xf8\x06\xfa\x1c$'\xeb\xd6\x8dG[E\xfc\x1b\x1bx\xd9\x87D\x93\xab+\x91\xaf\xc7*\xc0\xb2o\x8b\xb2\xe0\xc6\xb4\x1e\xca\xe0\xce\x1dV-2\xae\x16\xaa\xce\xfcm\x0cYM\xa0a\x12\xa5>U]\xc6`K\x81\x12\x88.\xcb\xb8\x10\xc0V\x17\xb2\xe3\xae\x8d*Uk9\xee\x02x\xe2_,\x04\"gg\xb8}\xed\xa1\xd8\xdd\x06\xfdR\x0d\xb2\x12\xf2|\xbd\x01\xa6\x86CqX\x18\x88\xe6\xa6)\x88\xf2\xcf\xa1\x1d)\xb0o\xa2R\x0d&\xee\xedY\xcc\x9e\xe9^`\xd6\x1d*\xc1N7O\xef\x01\xb1XR\x9e\x91\xd7g\xe1\xaeQ-\xea\x9d8\x12\xd1\x91\xa4\xa0t\xe2\xf0\xc1)'.\xd3i\x01R\x07)\x071a\x06/\xfbP'\xe5\x10\x9d\\\xdenC\x15\xa0\xfa\x81%\xf0\x07\xdc9\x93\x01\x8f\xb0\x90\n~$\xca\xe0\xad)\x88\xd1\x0d\xfd\x94\x1f\xc8\xd0\xc1Dv;\x14k\x8d\x89)\x04 J\xdej\x1eb\xb5\xa0\xff\xbd\xff\xbeW\xcd\x97\x87\xa2\xfd\xf2\xd20\xc8e'\xeec\xb6\xb9\x99@D\x9f\xfe>\xeb\xfdw V\x00q4\x89 \xd9\xf77j\xb5\x19\xea\xf7%Ik\xbfB\xd8\x12\x95\xc3\xcb\xf0\xd6`\x82\xf2{A\x02\xb8\x18h\xac\xc2<\xe1@\xb3q\xbf\x9f48\xf61\xd0\xb5\xcb>Q\x8b'\x7f\xcb\x17\x18\x86\x86\n8\xae\x8b\xf8Z\x00mc\x1f ]i\x06*)3=\x82\xd3\xbc\xdd\xc5\x8beA7\x9f\xe6\x99f\xc2JwG=\x01\xd8\x8bZ\xb3}\xeb\"QOPD\xdf\xf2\x8b\x15\x13\x8c}\xb8\xba Fe\xaf%>-J\xda\x06\xc0\x14>>f1{\xc2|\xb6\xc9\x86\x8f\x9b\n3\xd9\xb0t\xa7\x07\"\"\xb9?\x04\xa0\xed\xe4\xe3x\xe2j\x0eW\xad\xdd+Z\x83.\x0e'\xa0C\xe9\xf7ckaS\x05\xa9\x1e\xf9\xad\x96>\xb1\x03\x15\x8eN~N\x81\x8fl\x97\xfe\x9a6*#\x9f\xb8M\x9eV\xd0\xc8jo)\xd0(@ao\x03\x1a\xe5\xcdh\x04\xd2\xc4\x8eh\x94\xba,\xc7\x10\x0e\xfd\xbe%\xf0PK`\x03@\x1ah\xe3\xeaJ\xbe\xec\xb3q\xe3DS+\xb3\x9ao\xcd\x9e\xc8\xab{\xe2;\xf2V\x9c\xc4\xd4M\xe9\xfc\xc3 \xcaI\xcfa\xd2c\x81\xf6h(\x1b@\xd5-i\xe4\x0e\x19\xa2\xa2\xc7\xf2\xf1P&~\xc4\xae\x17}\x1fN\xc6\x01\xe0\xb8\xff\xf8F\xfdv=\xd5\x18N\xe05\xf0WJ8\xc9p\x8b\xe6P\xd7\xf3\x8e!\xdd\xc74`\xb2\xdf\x8c\xc9\xb9\xb4/o\xc6\xf5\\\xe9\xc1\xad\xa5B\xd8\x0e:\xac\x05\xc9l\xf9\x02\xbb\xec\x8bAT\x81X\x80\xe3\xb4\x0b=\x0d4,\xedNO5\xee\xdf\x07t\xc8\xc7\x81FO\x9bIi\x88\x88\xe2\xa3\xa7&\xec\xebp2\x8e\x01\xe9\x82k\x10\xd6[\xe9Yq\x15\xb7\xe8\x8c\xa8\xaf\x0c\xf7c\x0f\x10Z\xe4U\x92\x1e\xb3\x0d(&\x15\xe0w\xee\xb0P\x117\x176\xdcp\xb0\x8aW\x8e\xeb\xe1\xa4\xc8_n\x87\x96\xd7X.\xda}\x80.\xeb\xa4\xab\x03\x16\xc9\xa7\xe8|\x89\xd9\xfc\x0f\xe8_7\xe0\xca\xaa\x9a\xff\xbd-y?\x11\xdd\xd2\x0e\xc0\xa9\x9dt\xec|\x93+\x89k1q\xfa\xb7\xd79\xca\x81\xc2\x9b;?\xff\x00\x84\x92;/\xfd\x97x\x0b\x91;;\xf7\xbf\xcf\xb3N\xc1\xf5o\xec\xdf\x8e\x1c\xac\xca:_\x13\xack\xf2\xc6u\"y\x1bl\xb1F.2\x0f,\xe1,fpU\xe6-.\xb9\xb4h\x1cwZuU&\xab\xcd\x7fh\x8642\xc1\x03W\x84\xbf\xfa}\xee~\x9c\xbdP\x93XA\x10)\xd8\xf87`\xa0x\x86\xaf\x12\xab\xa8\xf2\x9b\xa0\n\xb7Ct\x08~\xe5#\xd0\x9b\xdb<\x05\xd2B\x06\x1a\xd5#++j\xe3\xe3\x08x\x10%\x83\x1b\x1e#\xad\xbe\xaf\n\x89@\xc1:\xa1\xa142\x11\xbc\x95\x89h\xdc\xa6\xb3\xca6\xddr \xeb\xc434\xb2\x96-\xfd(\x97\xb7\xfc\x8c\xf5\x10\xd6\xba\xd2\xad\xc7\xa9\x02\x9c\xd2\x00i\x0b\xaf\xdcD\x8fY\xae\x81\xb3\xe0\xc0\xfd\xb2\xa7\xa9\xe4\xc0s\xc5\x81\x8b\xbcT\xe3\xc0surH;\x9c\x1c\x9aN\x0d\x96\x13\x03\x9c\x16R\xf8\xe8p\x02N>\xfa\xfd\xbc\x0b\xdd\xbc\xce(\\O}\x06\xce\x11\x99\xc7\x02\xb0/\x10hHxN\xee@\x0b;a8\x1es\x91\xcb\xc7\xc1\n\xb2\x14\x82\x18 \x93\xc7\xbbk\xe3<\x9e\xa1B8C\xb5\xb3\xa6)B$W\xc1\xbf\xe5)\x0d\x91\xdf_\x03\xf9eo6\x1a{\xd3rd\xc8\xf4\xcf\xe7&#\x9b\x13,r^e\x91\xd3*\x8b\x9c\x16,r^\xfe\"Xd\xb3ekO%G,f\xaa#xn\xb0e\xd9 9\xbb\xe6\xf2\xf2t\"nv\xf5\x07\xf4\xaf[\xda\x03m\xbe\xc1\xe9\xcb3;C\xfa\x82\x9b\xe9K\\\x1aY\x1a\x17_R\xdb\xcd\xb7j\xb1\xf5\\\x84[6m\x88\x16!\xe3\x18\xb4\xdcx\x97B\xd3\xb9\xc7V\x1e\xd8WN\xa5\x81\xa21\x1f\x8b\xa6\xcc3\xd0n(\xc7sf\xfe\x12\xf2\x95\x13\xc6*F\x97\xf5\xc0$\xbc\x99\x97S\x9cF\xe9_\x98\xc4\xad\x04|C\xa9\xa8\x0ep\xaf\xd4*\xa9\xa7\x9d\xad0\xe5\xb1/A3\xbb\xb4`\x9f\xb7<\xb69\x14[\xc3\x99\xbc}2/\x9c\"\xac\xc4\x9b\xa9s\xead\xb1\x1c8\x1a\x00\xd9Y\x83\xe1\xf2\x87\x1a\xf8\xe2H\xb9\xe9m\x87]\xe3\xf5v\xf2\x02%+\xcc\xdd4\x17\x05$\xcct\xc3\xbd}6\x9e\x81\xcb\x8aH\x19\xf1!u\x8f\\\xd4\xc1\x01h \xeeM= nH`\x91\x89tb%}L@\xa8|e\x93\xdfbD\xa3\x1e\xe0?\xect\x94\xf2\x15\xbb\x901\x0d`\xbf^\xa0\xf7\x8d\xd2%2\xac-\xf4\x07\x1b\xe0~%\xbd\x19'\x10M!\x8e2~\x91A,\xa6\xe44u\x0b\xfb\xcd\x04\xe3G\xc4\x88)A\x89BbNlq\xa2[I#\x86\xfb\x96k\xab\xcd\x0d\xc7\x19^\x8c\x94F\xe1\xd6E\x11\x89\xa1\xf3jd-\xe9\xffC5\xcf\xb8\x1da\x14\xff\x8c,\x05\x1f\x043\xbb\xe4O\xfa\xc2d\x8d\xf1\xfc\x01\x03q\xbb\x13\xadaOf\xe3\xb4t\xdb\x8b?\xe2R'ct>\x03W\x9a\xa9t\x80\xc8\x0e\x98\xd2\xec:\xe0P\xdcY\xa0\xe0\xdc\xde \x86\xf6lbnG\xb8\xe2\x1b\x8bbh\xe7\x06Q_\x89Ri\x89R\xa9G\xaf\xaeXF6\x88\x8b;\xc9nCI\x14\xc3\xd5/\xc7C\xf5n\xd7\x90\xf5Gk\x8c\xb7\xdc\xb4gr\\\xe8)\xdc\xc2\xb5\xa1\x087wBy\x9b\xd9\xf4\xfeB\x1d\xb6q+\xa6\xa8\x00\x97\xbc\xb4\x94\xb3\xca\xae.U\xb3\x1c\xe2\x03NOp\xc9E\xb8\x00}\xcd\x05\xf9\xb2\xc5\xfd\xcc\x07OR\xd9\xb4\x03\x95\x85\x95#I\xe1\x1adr0=\xa9Q\xca\xc1\xf4\xc4-\x0d\xa0\xc5\xcf\x02\xd7\xf1G4\x08\xc4\x96)\x9d\xef\x001e\xa3\x12\xa9\x89\xeb\xe38\x8a\xc2\x9bu\xfbvA\xb0\xeb\x14\xb1\x9c\x01\xb1\xbc\xba\x02BY\xec\x9c\x0b\xdd\xabv\x95\x84b\xa2FEU$\x19 \x98 n\xb1\xf5^\xb9\xbcn\xa7r\xa2\x0bD\xff5>\xa6\xe8\x0f4\xaa\xba\x13\x0b\x8cl_\x1d\x92\xce\xc8\x9e\xf3\xa2\xe7&\xea\x1ac)~\xde\n3k2\xad\xc8\xcc\xee\x191\x18\x03\x99^\xbf\xc4\xed\xcb\xf4\xba7]\x15K\x8c\x0epc2\xb9\x1dn\x0c\xc5N/[p\xf0\xd8/\xfe\x8fd$d\xb8X\x1fG\\\xfd/\xd2\xdd:[\xabB\x19val\xb5\x0b7\xc6\xac\xc4M\x99s\xea\xa6\x11S\xa62[\xca\xec_]\x0e\xac\x96)\x14T\x1c\xfc\xa3\n\xf2\xb3\x01\x91\x96\xe8k!w{\xac\x0f\xde\x1eX\x9f\xf5\xee*3\xcf3?\x0cfL\x0dv\x19\xcf\xb8q\xf1\x8d\"I \xee\xeb\xb65\x11Z\x02\xf4\xc2\xb0r\xc7/ES1:X\xf5\xa5\xc9\x14\xb1Q%\xf4\xe14\xc2\x8aC\x8f\xcde\x13f\x19\xd1\x95i\xabS&\xbd4`\xee\x98\xb2\xb7Q\x8f\x18BH\x04\x9c\xfb\x12yj\xce\xb8\xf8=b\x9f\xf1\x8cO3>cy\x14'3\x9e\xf0\x19\x13\x88x%\xb0\x8e\xdd)\"sC\xf8\x9e\\t\xcec\xe7\x8b`\xba`A\xc4\x002K\xff=O\x19F\x1fc3hMpC\xf1\x9c\xa5\xf9t\xca\xd3\xf4\xde\xdc\x0f\xc2<\xe1,X\xae\xe24\x0dNB\xce\x9c\xf3\x05\x8fD\x13wu\xec\xbe\x0b\x13\xeb\x1eE\xcf\xe3(\x0df\x80N\x04m3*?\x1c7\x1f\x1b\xc6 \x15\xbd\xc8\x02\x89\xb5N\x0e\x84'T\x9dc\xac\xf0\x96:\xbbh9S$k\x9d)H\x13\x97\x8fz\x8a\xa8\x8b\xa6\xa5\x90\xe0#\xe9\x89\x9b\x14\xb7JOY\x06\x90k\x06[\x86\xe7\xe3\xfa\xc5\xfc\xea\xe5\xf3\x9b\x03\x88p}\xa5NYm\x91\x96\xad\x86*\xe8\xf9\xfdV\xe7Q\x9c\xca\xd6\xbf\xbd\xd1\xe8\xa2\x1f\xaf\xe28\xe5\x15\x19p\xe8\xa6]\xfc\xd3\xa2\x895H\xad\xcd\x89\xa3\x0eC\xaf\xfd4\xe5\xb3B\x10\xa3\x05\x84\xc6K4\xc1\x9c\xcf\xea\xf1\x8cn\x17~{\x86JG\xcc\xf3\xbd\xf1Qt\x94\x1c\xe5\xdb[\xdb\x0f\xe1\xef\xa3\xc9\xbd\xd3u\xc1\xac\xd0_\xcc:\x89\xfb\x85\xc2\xe2)\x1bnm1\xe5\x80.\x93\x0eX\xb7<\xf6\xe8\x11\x1c\x13\xff\xdb\xef\xfc^O\xde\xff\xcf\xd4=iAq\x9b\x97\x8a\xfc\xcao\xbc}\xf5r\xa0\xc0y\xe9pW6?\x04\xc5Fm\x19\xdd.p\xff_\x83\x9cJ\xcf1~\x19G\x9b\xd3\x98'S<\xc6e\xb1DD\x17o\xf2N>\xea\x85\x8d\xdb\x88\x11o\xd3&\x96\xdf\x0b\x06\xb3 ]\xc5\xa6L\x85p\xa9)\xfaV\xb3\x81\x08 6\xa5\xa2\x9dg\xa7]W\xe0\xcc\x03\xa7B\x1e\xab\xf93\x05\x89#\xf8\xe4AY\x0b\xdbg+\xc5\x96.@\x89P,\xd0\xd4\xb2@\xd3\xe2\xc7\x01\xeb\xe1za#\x06\xbea\ny#\xeb\x8b\xcf\x17\x1d%\xf1u\x86\x0e\xd6R\x9e\xbd\x0b\x96<\xce\xb3\xf6sO!\x00\x8aH\xe1\n\xb7\xe9\xbb\xc4\xa7\x06y\x94\xf0\xb9\x18@\xf9\xcb\x81\x88\xa7\xe0UNt\xe6\xce\x1d\xd6\x8b\xf8E\xf6.\x98\xbe\xef\x81u\x90J\x86\x05\xa4\xba)\x12E\xc5\xf5\xfb/\x8f,\xcb\xbasa\xd9\xff3[\xff\x97\x95\xfe/\xb5\xfe\xb7hpj\xf3@.\xfb\xca\xd8f\x18\xef\xbf\xd0\x98\x8a\xb3\x15B\xc8\x80\x0c\xa7 \xa3\xd7^\x92A\x15\x05.\xf1\xcf\xb9\xd8XE\xb3g\x18\x1ct\x7f\x7f_\xcf\xb9\xba\x92Q\xdb\xcb4\xb1m\x0fvvv\xd8\x88M\x9d\xb9\x83\xa6\xe8z>\x1aGmI\xcc^\xb2}\xf6\xf3\x0f\xd2\xaf\xd6\x90m\xb23\x97}\x82\xd2M%\xaa\xa8\x03\x07t\xde9\x05\"\x18\xec\xd5\x15\x83\x01\xb2}\x0dK<\x16\xb4O\xbbE\xda!\x1e\x0d\xaa\xfb\x1aT\x1d\x0d\x84\x9e\xae\xb0\xabl\xa1h\xbb\xe6\xc4\xae\x8b\nA\x08\xe8W\xb1\xb3\x91\xc6\x03\xd2b\xae\xb2\x8c}'@Hu\x12O\x84\x1e\x0b5 \x05\xfc\xa4$\x9c\xa6\xdf\xa7\xea\x1eT\x839\xbd\x0d\xcd\xdaP\x96\xd5\xd1\x96\xdc\x8b\xd0\\I \x01bp\xec,\xbb4\\Ctn`\xb9\xe5c\x88q\xc6\xf8\x8b\xdf\xb7\xb2\x05\x1a\xbe\x98\xd5\x11\xf3\xd1\xda\\\xb3\xe0\xca\xa4\x01\x87\xd8\x0e\x9e\xb2\xb8\xc9\xb7\x08\xbf\x98r>K\xd9\xd2\xbf\x08\x96\xf9\x92\x15z\x8b\x0c\xa1\xf2}9\x1b\xd9\x1e\xde\xdf\xbb\xffpg\xf7\xfe\xde\xf5\xdbk\x07\xe76\xad\x17\xdd\xd5\xafx\x04bG\xee\xb8\x1d\xcb8R\xc4^\x9c\x14{q.\xdd\xc0Kk\xf258\xe5\xe6\x8d\xd8G\x13\x9bf\xc4\xd7\xdd\xfb\x02\x8b0X\x04\x99\xeaZ\xbb\xc1\xc0i\xf9)b\x0b\x12\xa3W^\x11\x0cr\x00\x99\xd2\x1d\xc2m K\xcb\xe46(\x9f\x83\xf6xW\xeb\xae\xb1\xb32\x044q\xf3\x01\xc2F\x9a\xc9y)\xff23\xd3\xa6\xcc\x10\xda*R\x1f\xed\x15\xa9\xc3\xedm\xb8\x0f\np\x02\x18 \n\x8e]\xae&\x02\xdcz\xff\xf7\x1f\xfc~\xafq\x1d\x9av\xef\x84\x1d\x85\x8e\xb1 \x82\xc178j{\x15D\x96a>\xabK\xb5\xea\xbe;\xd1\x05\x87\x1f\xdc\xe2\xc2N\xe4\xec\x0co\xe2\xdb\x93\xf4]/\x1a\xee\x1d\x1f\xf3\xf4\xcbx\x96\x87\xbcW\xa7\xda2T\x90\x1eJ\xc1EY\x0f\xc4\xd3k\xb2UQF\x00\x89*\xec\xb1X\xbd\x96\x1b\xd0\x07\x93\xdd\x08\x1cq\xb8}Pw\xf3\x1b\xcb\xac\xfb\xdb\x10\x95\xb3\xc8S\x1d\xc0\x90cd\x1f8\x12\x99r\x9c\xd2\xef+\xb5Ca\x9c\xc0\xba\x9f\xbe\xf5\x88\xe9/\xc7\x04\xa8}\x87&\x8b\xd3x\xb9\x8a#A\x0e)8\xa8\xe7\xd9j5b\x97\xc5\x0cZ\xcb\xf9y\xb6\x88\x93\xe0\x1b_\xf4\xe4u\xbc\xcaW#v\xd2\xbd\x1a\xff4\x8bF\xecx\x8d\n\xafV<\x81\x8fA\xcd\xf3n5\xd3\x11;l/\xf9,\xcf\x16/2\xbe\x1c\xb1\x8b\xf6\xc2\xa2\xd9C4{{\xdb^:\x16\xc5\xb7G\xecY{Q\x7f\x15\xfc&\xbf\x14}\x19\xb1\xe7\xed\xc5O\xfc4\x98b\xe9\xf7\xed\xa5\xe5\x91\xe4U{\xc908\xe3ox\xba\x8a\xa3\x94\x8f\xd8\xeb\xf6\nA4\x8fG\xec\x8f\xb4\x17|\x11\xcd\xe3\xe7\x18\xd8\x9d'#\xc6y{\x95\xdf\xc8\x97\xabw\xf1k_\x8c2\xebP>\x8e\xc2 \xe2?\xf2\xc3`\xe6gq\xf2\xa9?;\xe5#\xf6\xaeCE\x85]\xe9\x88}\xb9F\xf1\x11\xfbi{\xe9\x02u\xdf\xe6\xcb\xa5\x9f\\\x8e\xd8\xcb\xf5+} A1G\xec\xcd\xfaU\x11~\x9f\xb5W\\\x04\xa7\x8b08]d\x82\xe1\x18\xb1\x9f\xb5\xd7H$\xa6\xa4#\xf6y\xf7\xd2#\xf6M\xf7\xc2\x9f\xc6\xb3\xcb\x11\xfb\xb4\xbd\xc2\xcaO\xfc%\xcfx\x92\x8e\xd8\x8f\xd6(\xfe&>\x1f\xb1\xdfh\xaf\xc0/\xf84\xcf\xf8\x88\xfdV{\xd9\x05\xf7g\xd0\x91\xdfl/\x0bF\xb4\xe9\x88\xfdZ{Q\xb8\xc5\x17e\x82y\x1d\xb1\x1f\xb6\x97\x8f\xcfxr\x16\xf0\xf3\x11\xfb\xed\xf6\xc2\xf38\xce\xc4\xc2\x8c:,\xb4\xcf\x830\xe3\x89\xb6\x9a\x93\x0e\x95^\x0b\x88\xe3t\xc6\x1d\x8aO\xf3$\x1c\xb1\xa0C\xc9t\xba\xe0K\x81\x83~\x87\xc2o\xb1\xb0\xd6\xf7\xbcC\xade<\xe3\xe1\xe1\x85\xbf\\\x85|\xc4\xc2\x0e5\xbe\x145~\x9c\xf8\xab\x95\xf8\xc6\xb4k\x8d\xe7q\x18\xfa+\xb1F\xd2\xaeUFl\xde\xb5h:b\xab\x0ee\x0f\xa3|)\x9b\x9eu(\x8e\x8c\x8e\xac\xb0\xe8P\x01\xcc6e\xf9\xb3\x0e\xe5\x0bg\xf7\xb2\xce\xb2S\x1dd\xb8F\xec\xb4C\xe9w\xc9\xe5\x8b\xecU\x9e}\x9ag\x99 \xeb\x97\x1d\xea|\xe9'\xefg\xf1y4b\x17\x1dJ\x7f\xea\xa7\xfc\x0b\xff2\xce\xb3\x11{\xdb\xa1\xfc\x8fx\x92\n\xde*\xf1O\x97>\xae\xb7\x11;\xe9^\xf1m\xe6/W#v\xdc\xa1F\xb1a\x1c^d#\xf6\xc5z\x15\x80|~\xd5^\xe7\xb5\xa2\xb7\xf0\x91__\xa3\xc2\x8bh\x1a\xe63~\xb8\\\x89\xd9\xfcq{\xcd\xa2{\x10i\xe4\xc5\x1a\x154\xaap\xda^\xed3\xceW_\x04\xd1\xfb\x11;\xef\x00e\xc1\xff|%H\xda\x1f\x1d\xc8\xd7\xe6\xb2\x02ap\xeb\xc6\n\xeaw\x03i;;}\x96\xa6\\p\xf8\x87E\x87\xc8\xd2\x9d\xe4\xd8\xb4\x9frV;K<\xef\xa4F\x88:\xb5\xf5\x9eh\x8b\xd4\x1c\x8dg\x05\xbc\xd9\xbc|M\xcbW\xbf|\x0d\xcaW\xeal\x8az@\xf9\x8a\x87\xbb\xb0L\x88<6-\x7f\xad\xca\xd7E\xf9zV\xbe.\xd5k\xe3\x89\xf7\x15\x87\xe0\x03\x8f\xa8#/\xe6m\xef\x1a\x11\x8e\x8a\xbc\x9d\xedz\x9e_\xe4\xdd\xdf3\xa2\xe5\x14y\x0f\xef\x1b\xf1\x80\xca<\xe3\xf8\x1d\x96yF_\xa6E\xde\xa3\x9dz\xde\xbc\xcc3\xfa\xb2*\xf3\x1e\xd6\xf3fe\x9e\x01\x97\x85\xca\xbb\xbfe|\xef\xac\xcc3\xda\\\x16y\xc3\xadz\xde\xa9\xca{\xb4c\x8c\xef\xb2\xcc3\xc6pR\xe6\x19\xdf;.\xf3\x8c1\x9c\x17y\xf7\x8d\xbe\x1c\x96y\xc3z\xdeE\x99g\xcc\xfb\xdb2\xcf\x80\xcb\xf32\xcf\x98\xf7\xf7e\x9e1\xef\xcf\xca<\x03.\xaf\xca\xdaq\x07\xdc\xebv\x11G\xab6\xcd5\xd9\x1amW\xc7\xceQzs\xa8\xc5\xe8=}\x10\xa0\xad\x1a\x04D\x10\xa0\xadj3b\x1a5w\xc9\x807\xbfU5\xb2\xf5x\xfd]ugDN48\x81\x1eD\x837\xf0\x03tX7#\xd7\x12\x8e\xa3\x00X)\x8d\xb3\xdb\x87.>\xaa\xdd\x02\xb2\xaaM\xf1\xc1\xaf\xf3\x14Y\x11\x8f\x84)\xc3\xf6\xd4j\x82\x10\xaf\xb4F\xf5\x98\x06z\xc2\xff\x8c\xf9H\xf5-\\j6\xaf\xbe&\x13\xc9\xd0\x19\x14&\xc5\x1b\xd3\xd1\x0c\xc6\xc2\x82D\xff\xda\xaalar\xad\xaf\xb54\xe7\x05ab\x9b\xe7\xac5\xd6\x1a\xec\xe4Y\xe5\xae\x1d\xb1s\xdd\xc7\x01n\x96\x06\xb8\xa9\x0c\x106]\xb7_$\xa9\x86;\xb8\xbfg0\x14.\xe7\xac\xa9\xcc\xb93D|\xc1\x83\x0c\x83\x9b\xd1\x1b\x98\xa3!G\xe2\xac\xf3\x00x\xcf!\x85\x97\xb0|\x0e\xcb^\xcf\x05\x8c\xea\xbe\xec\xc3\n&p\xed\xac\xa7\xcbY\x1f\x96\x8c\x8c\xb0\xaf\x86\x10+\xe6^\x99\xf4-\x0e\xc6\xb5p\xf7\xc7A<\x87\x0e:f,\x06!\xbdM\x1d\xd7E\x0f\n\xcd\x10\x88\xb3@\x17\xadi4\xc0\xab\xe8>\xb0\x01q\x8b)Q\xa4\x19\x944b\x924}\x9f5W\xc9%\xa6\xe0\xfd7!\x1b\xd5\x8d\xcd\xc9\xc6\xb3\x9d/<\xc10{6;\xc9\xe3\xc1B\xd4\x89\x9c!\xab\xc8\xa6NyT\xeb\x07\x12\xef\xd0\x19\xed\xed!)\x15\x14\xf5\xd9\xa6 \xac[\xe2\xef\x9e\xf8\xfbTKh?p\xf3\xc46]Y\xc0\x95\x87\xcd\xec\xcb0\xbf\xb5\x88i\xbc\xcb\x9a\x83A\xa0'\xd0\x92$VI\xe8BO\xb8\xd7\x82u\xa9\x14\xcf\xf9zU\x87r)\x1a\xa9\x96_\xf3N\xb7\xab\xe5+A\xe7\xab\xe5KQ\xbe\xe3\x0e\x12ZQ\xcb\xde Z\xbf\xe3:U^_\xf4^\x9d\xda\xb9h\xad*Y\xde\x88\xf2*;u\x88\xb1ws+\xb3\xf2\xc3[\x1eI;\x8e<\x9aT\x82q\x9e\xe0#\xb1\xee\xe5G\xaf\x18\x05\x17/!\x01\xf7\x9c\xdb*w_1\x0f\xa9(b\x0f`\x1fw\xc9\xc5`Q~p\xcc\xd8\x97\x8e\xdd\x04T\xef\xcf\x0e\x8a\xdd\xc9\xc9\x00\xa3\x8f]S\xa7\x8aG\xea\x87QC\xa7\x9cZ\x17\xed\xa6\xa6\xa13z\xe6*\xb9\xcbg\xad\xac\xfd\xe4\x87:W}\xb82\x1b\xc3\x1b\xa2\xe1\x08\xc2\xe5\xbcb\xf4]{>\x8a\xb5\xf8H\xff\xe0\x11\xd3\x0e\xafi\xc8M\xdb(w;\xbbr\xd5\x94\xa7\x9a\xa0\xf7\xe6 \xc8\x9f\xab\xe8\xf7\xa1q\xce\xd7\xf5\x8c\xa5P\xcc\xa3\xe3t\xd6\x0e\x8fi\xa9\x8b\xea\x84G\x11\x1f\xb6p\xa2)\x0f\xa7<\x98\xd3\xa6`\x85 M\xf0\xe9\xe0\\\xebM\x0bH\x83\xcfCt\xa7\xd4/\xc0\xb5\x08xH\x07\xe7\x9e\xbe\xc6]\xb3\xc5-\xa8\xd2#O\x18z~\xcd\xcd.\xd1\xd0\x91\x0e\xce\x93RZ\x8c\xbcE\xa37\xb9\xfc\x08c\xd8\x82|F\x18\x817\xba\xc2\x98\xa5\x0b\xe2[nq\xe4'\x11\xf1.ps4W\x0fDu\x86p\xcd\xb5=\xac=\x8fV\xc4oH\xede\xde\xc1\xea'c\xf2\x0c\x1at:\x9b\x02v\xe8\x14\xfb\x07\xda\xb5\xe2\xaf}tj\x15\x0e\xb2\xac>\x97\x83\xc6\xe0\xa0\xb9\xbd7\xa0aJcG\xf0\x1f\x19\xba\xbap\xdfPo@o\xfd\xd4\x11\xeed\x9d\xa1\xcb\xeb\xb0\xdd\xa6\xd8\xe2\x07\xce\xa1\xd3\x15\xfbn\xc3\xbb$~\x08\xde\x9d\x17\xd0.\x0fI\xcd\xd6\xf1\x83\x13rk\xd8<1N\"\x9cA\x13\x87\x9f\xd8\x81\x13\x9b\xa9\x01T\xf7e#Xp\xfc\x1d\"\xe6'&\x11\xe8\xdc.\xd5\x8f\xde\x95\x07\x9f\xd4\xf8\x8d\xc8\xb7\x08\xaf\xec\x89 O\xec\xa08uR\x94D\xad#\xff\xd8n\xe4\xfch\xd2\x0f\x9e{\x15\x0e\xce\x8d\x01=\xc3bR(`\x8b9\x19\x8e_\xfb\xb1\x8b:q\x19\x98\x99o\xac\xe2\xf0\x03\x8f\x84\x8f1\x8c\x98`\x1e\xe6\xe0\xa7 \x0d\x16\xb60\xba\x08\xe7\x0f\xe8&=i\xcb<\x81\"Z7\x9f\x85\xe77c\x08\x9b9\x93\xf3\xf9X\xcd\xf1\xaf\xfb\x18\xb8r\xf9i\xc7\xb1\xa4\xf9E@\xe0|\x14\x01\x9e\xd9\xf7#\xf1\xfd[\xb2\x01Gy\xbe\x8c/?\xf9]v\xc6\xe4\xe8\x1fr\xf4\x1f1\xfc\x0e\xfb\xd01\x8d\xb7\xdd8\xc5\xf8\xec\x13i\xb1~\x0dk\xf7\xd98\x7f\x8deQy\xbb*\xfe\x11\xb8\xd7O\xac\x1b\xf6RD.>\xe9\x83\xdc\x14\xdd>t\xcf/\xbbn\x1f\xe6\xdc\xd5Jx\xcc\\\xfaU\x17;=\xfaP\x07\xd1\x84\xb7\x9bc\x8a\xfcY!.V\xa0\x1f\x15=\xd7\xe0\xa1\xa8\xbb\xfa\xfc\x107O\x925Ppv\xfc\x97z\xf2\xf2\x92\x84\x8b/\xfc\xc7\\\xf2~\xf8\xeb\xbaV\xf9R\xad\xcc\x19\xc5b@nq\xa5&\xd4\x1d\xbb\xaes\xa2\xc4\x8c\xaa\x8d\x8f\x86\xe3fQP\x8ar\x07\xceJ\xae\x9ak\xd3\x15FWe\x9dtGI\xce\xca\xcey\xb67\x98\x80e\xd4\\\xe3\xd9\xc9jq\xe9\x07\xd9\x18v\x16\x8b\x9f\xe3\nL\xbc\"\x97\x8f\x841k\x80\x7f\xad>K\xd8\xb3S1\x8f\xceH\x0dTS^\xe7\xf2>Bti\xd2\xdc\xcb\xebH\xd6\x11\xaa\x10\xe48\xcd8$\x82\xe8\x18\x89\xb9\xd4\xc1\x84\xf4\xa6\xea\xb8\x89\xdd\x14\xe9\x07\xa8\x98\xa18Q0\x04\xecG\xbc\xaf\x1a\xb9\xf9#\xc6\xa4\xe0\x93#\xf1D\xc5\xe6\x8b\xc1\x82\xad\xb2\x15\xa5\x8b\x08\x0f\xfb\xfb\x80>r\xfc+a\x1c4\xbd\xe1\xbe[c\x0c-R\x9a\xe4\xc2Y\x0c~\x82\x1e,\x06\xbf\xe1\xffx\xbfr\\E\xc8\x0f\x92):)\xbd\x1c:\xcf\xf6\\G%\x15B\xbb\xba\xeb:j\x11\xa9*Xy\xbf'\xa5\x1e\x15rS\x9d\x1a\x83N\xd3\x1aK\xfe\xe8@G\x98@\xd1<1\xf4\x14\x10w\x1d\x1e\x8aD\x8bg50\x15\xc3u2\x06\xe0\xce\xb1k\x1d5.w\xd3\xb0\xc5\xa8n\x9cL\xee\x8d|\xd9Nro_+\x9aV \xe9\x1c\xb3\x86\x1ao\xc8N\x06x\x84\xbb\x03\xdc@\xce\x95\x8a\x15\xb6i\x91 h\x9a\x92\xca\xa9\xea\x0f=N\xb4R\x83\xd2\x92\xbb\xf2Z\xb57\x91\xa8b\xd6\xd8\xf8\xed\x05UIFm\xb9 A4iI\x90\x0f2\x96\x8b\x99\xc5\xbaf\xa4\x9c\x9d\"\xed\xd5\xac\x18|\x01\xf6\xc1\xef\xf5\x9a\x19\xc0\xc4\x90\xb6C\xfd\x88\xec\xc9\x9c\x02\xb2\xbd\xd9\xeb\xf5\x0be\x19\xc3\x88\x96\xa9\x0e\xd4O\x82\x9cE\x92'q\xc8D\x12\x89\x8d\x0d\x94/b'lb\n\x8d23\x084W\x9a\xd2\xd6\xd3eG\x90.\xc6\x03\x1e}\xc2\xf1\x07\xd7m\xcf\x95\x98x\x8d{\xf7[!\xba\x19\x8b\xa3\x07`\xf1\xc3q\xab\xbe\xea\xc5\xb6\x03\x8b2O#\xdd\x82}\x05\xa2\x81\x08\xc0\x1b\xd9V@!A\xf8\xf5KmMtgu\\\xdcuc\x94\xc1\xf2P\x93\x1b\x1f\xb9\xce4\x8f\\P\x87\x9cG\x12\n\xc3\xb1~%e\xb8\xa1 P\x8c%L\x85\x9aT\x03\x12lg\xd4\xa2\x9dt:\x9c\xa9m\xf5!\xd5gd\xc7\x167[\xb6\xc8Z\x19i\xda\x15\xe5\x86\xd6\xb7\x1e\xd4:\xfb\x7f\xd3\xd8\x87xj\xe8i\xfb\x0bzb\xffo5\xf4'\xea\x180N\xe9B\xc4=\xc66\x94SQ\x8b\x91f\xbb\xb1\xea\x8d\\d\xb9\x1d\xc5\x14\x84\x83\xf7Y\x8a.1\xc7\x17 \x8d\xaf)\x06v\x88\x07\xbf\xd1\x8b_\xfc\xb4\xfa\xac\xfc>O#\xad\xbd\xde\xcc\xf0\x91\xf6z3\xa9^o\x86\xce\xb3-\xd7!M\xd7\xf9ZNX\x1ay\xb5\xca+\x19\xf7ui\x13\xf0> \xa5\x00\x94\xde\x88\x90*\xa4\x06\x16o\x00\x9e\x035&\x98\xe6J\xeeE\xd8G\xbe\x9c\xa2\xdd\xc5\x97(\x88\"M\xd2\x0cPEScl4\xc8\xa3\xd5cl\x1c$\x04\xa9\")\xb6\x8d>V/)\xb5\"\x00\xc2\xaf|\xca\xf8\\\x9e\xaf\xbf\x00'qy\"D\xdb\x9a\x90\x81\x0cv\xe9\x04\xd6\x06\xf3D\x1e\x1d\x9fcgH\xae\xfd%I\xa5n<\xff9HR\x12\xceI\x10\x85\x1a\xad\x05\xc6\x7fC\x83\x1ey\xda\x98\x00z-\xf2\x7f\xe5\x15\x1d\x83\x1a\xaeq\x8a\xf2\xe3\x89\xc8\xa5\xadu)|\xce\xad\xda\x8frU\x95.M\xb5\x06\x92\xfa\xdd\xb1\xe0\\\x94\xb6\x8b5\xec\xc3<\xf2x\x94\x1c\x1e\xff\xeb\x94\xde\xa6G\xd1\x9c:]\x9d\x8e\x92\x8b~\x81;\x888\xe5p\xd6\xba\xb0Q\xec\xe3]\x92\x98x)\x8d_\x93\x94\x8c\xaby2@J|m\x00\xb1\x1e\xccI\x8a\xb7\xbel*\x8b\x06\xfc\xd6\x12\xe1\xbc\x0f\xedf\xbb\x16A\x08\xf5\xdd/\xc21\xc4\x06~\x0cS\xb2\xf2\x9d\xd4\xb4D\x80\xfb\x8e\xc7\xb2b\xef\xc1>\x86\xcf\xa5<\xfe\x0c\xcf\x0e\x1a\xa2\x9e\x1c\x1f\x19\xe6\xd4\xea\xdch2\xbd2\x9c&5\x93J_o\xa8\xc5\xc5\xef\x9a!\x8fLA\xae\xda\x804\xd0\xfe\xdaN\x95,\xb0>\xc1,\x8f\xa8\x15\xf1\x88Zq-D!W\x07\xe1ej\xcaD\x06\x8cf\xbapR\x0c\x93\xaaa\xc0\xa2p\xe1/\xb3\x98\\p#\xdb\xfa\x12/i\xda\"\x0c\xa0\xa2\x0djB\xcd\x07\x9e\xff\x8d\xeb\xa87\xa13\xaccm\xd5\x89\xc1\xf2*\xcbm\xa2\x8aNc'\x1e|\x80\x1e\xc4\x83\x8f\x16i^\xa4\xf7j+\xe8\x10\xa1\x9e\x8b$G\xc1\xf6\x82/\x7f\x18\xa4\x9c\xd0\x84\x1e\x9a\xa0c5E]\x08\x93blF\x93\x17\xf1\x1aOH\xe0\xb8U\x11\xd6v H\xe5\xa8\xb6\x82\xee\x1a\x8f1\x99}\xf8\xee\xe3\x12\x91\xd3\x1e4,\xb3\x96\xe8;\"o\xddt\xcf\xcfM\xf7\xca\xe8xbA\xc44n\x8d\x84\x11#\x11\x987\xda\x88n\xbe\xd6\x92A*\x00\xc3\x01E\x93\"\xa1u\x1d\x17r\xb0\xeb\x84(\x9f6k\x04\xdb\x00T\x82\xce\xba\xde&b\xf4\xd9A\xa32\x99_\xc2\xe9*\x15\xbb5+J\x0c\x01?\x88\xe9\x92\x864f\x0c\xd8\xc7,L\xfd\x15\n\xdd\xc2\xa9gIS\xc5\x95\xe7\x88\xach\xe2\xc4\xee\xc0\x0f\xe7\xf4\xf6x\xc1\xda\xaf\xbe\xdcu\xe1eM\xe3\xe5\x83\x08c\xa7\xeb\xae\x809&{\xd1\x0d\xa8\xe0c\xcb\xd6\xb7{\xec\xd4\xc2\xb4\xec\xfa\xb7\x94\xc8\xf9\xc8;\xd5yx\x11}S\xf7~\xb1p\xc6\xeb%\xeb`\x8b\xf7\xb5\xeb\xae\xb6\xa5\x18u\xd6\xeel\xf4;\x0c\n\xa37tU\xaf\xf8`\xd5\xb1\x9c/v\xd95\xab^\xcb7\x91\xdd\x93\xbb\xd5E\x14\xc0D~\x19\xd7\xccVA\x9c5\xfe\xc0O9@\xd0\xbe\xf1?\xffS\xfe\xec\xd6\xeb\xa3\x8e\x92\x87}}[~\xa9T\xa6y3\xc17e\xb0\xc3S\xb2\x14\xef)%\x9a\xb7\xf0\x92*BX\x95\xce\x94zMOX\xf7\x99\x91\x15\x04\xc2z.\x04\xc8\xf0\xa9\xa8\xe9\xb9\xad8w\xc7\xd4\x0d\xecC\x80\xb9\xa6d\x93\x0c\xde\xee\xe0&&\x8c\x99?\xaf\x93))\x03t\x93,Y\xd3pN\xe7')\x89S\x0d\x0c@H\x04E\xcd\xbf\xfa4\x98\x1bj\xa2C\n\x8f\xa9\xe4\x87:\x90\x820\x06\xefz\xd1j\xcd\xf6\x92\xa9\xa5k\x9ePA\xfbl\xa5qC\xc4\xf2)\x995\xd1Bhb\xce\xf4\xc0Z\x16\xbbfI\xd3\x0fr\xe3\x1c/\xf4#\xbc\x83}X\xb2e^:K\xe7\xbd3\x9d\xb9\xbaKS\xf48\xb9C\xb3(\x14n\x85pw\x87I\xb3ej\x91;\xcd\x8blD\x17h\x9c\xad\xde\xf9\x1e\x96~\x95\x028;+M+\xb7\xa5\xfa\x17\x15\xeb\xed\x93>\x9cT\x8an\xfbp2M\x18\x88o1MW@\x90\xc6\xb3\xe5\xfcIb\xa4(\xbf\xf8\xa5\xcf\xd7mp6\xc3\x83\xd2\x19\xb2\x0fW8m\x8c'\xaeu+\xb5!j$n\xe8\xaf\x9cs\xf5\x0d{dh\xed\xde`\xa7\xf9\x04\"t\xca\xe2\x1e]\x0f\xb9'\xcbU\xcb\"\x9f\x0e\xe5\x8e]Jk\xfa%\xd0\"\xf7+\xc4\x8f\x8b*vuY\xd97 \xb2}\xb8\xc8O\xe3\x074\xd6\x9d\xf2\xd3\x18\xf2\x01Ur\x1e\x82\\\xe0+z\xd7\x9c\x8a\x04\x14R35\xa46\xa8\xf9\xaf\xa7\xd2\xa8\xc4\xba\xbe\xec\x94\xbe\xa6qB\xab\\\xb4\xfa\x91\xa3\x83f;>\x91\xd9@\xde\x1d\x19\x15\xd4\xeaG\xca\x06\xe9`\x1d\xadMZM\xf5\x83\x0c\xb5\x98fn\xd0\xc3\x91\x08\xd3h\x84\x1c\xb5\xb8\x91\x92^l\x94\x1f\xb3\xa5\x1c(\x02q\xde\xde\xd0\xd6\x9e\x96Hx|`l\x91\xdf\xf7\xe1\xb4D\xe8\xf4\xa0Q\x0e\x8c1\x9c\xeaW%\xa6 m\xb4\x02\x91\x1f\xccz\xc1\xedp\xe8\xb5b\x9a%\x14y\xf2gBCy\x81;8\x17?B\xf1L\x81'\xffM\x03\xba$\x18\xa5\x84'\x92\xc4\xd2\x15\x86 \x95\xd9\xc0\xba\xa2\x94\xc4K\xa5\xa54\xbe;\x0c\xd3\xd8\xa7\x89\xcc\x97\xec|p\xfb\xd0i\xb0h,\xa2\x9d\xb3uG\x91\x17\xbaiWxo\x88P\xdbCW\xe1N\xb8v\x86;Kux\xea\xb4\x9eL\n;\x12 \x86X\x1d\xe1[i :z\xf0'i\xb4n\xa1\\\x03i\x00\x95\xa3\x8f\x19\xb7\xa5\x0dU\x05H\xd3\xe1l XP?\xb2\xb8\xd8`*}\xd4\x93p\x98\xd0\x01\x1eJ\xf2\n\x86-\x82\xf9eU\xd3\x14_\x93zb\x020\x83\x821\"L\x8c<\xbc\xf5\xe8:\xc5\xa8\xb4\x0f\xc4J\x06\x9c|\xa0v\x00\x156\xdf\xcd\xb4*vL\xa9\xf6\xd5\x8f\xd4J\x0d\xc4\x96\x140\xecC&\xf0\x16m\xc4\xc5NA\xef\x11\xae\x04\xaf\xa3\xba\xc4s\x86\xcc\x1d\x8b_\x85y\xe4\x12\xc5\xfd:\x1aHg\x9d\x0d\x18=\x07\x1fU\x11\xcfacC\x1b\x17B\xfd\\\x8b\x1c\xffU\xac\xf2\x1b\xcc{@H\xb1\xa4\x15\xf2\x81D\xc08\x8a\xc4\x9e$\xac\xb7w\x91\x97\x13\xe8\xd8\xe9\xd2pn3\x1d\x97\xad\xc8W\xe1\xc5>\xe4d\xabi\xa2 &\x8b\xb9kD6\xf4>tQ\xc3\xf1.\xf2\xba\x96\xd3M\xfd\x04\xe5\xd7\x85J\x18\x1bhw,\xe1\x9dm\xd0f\xb4P\xa3\xcc/0=/\x1f\xb0\x02\xb7\xa2\x10\x1d\x10\x9a\xc7\x01\xda\x96\x8b\xb9\x94\xdaV\x8a\x1b\x1b\xfe\\\\z&\xdfs\x8a\x8d\x0d\x7f6i\x1et\x1f\xbc\xa3\x0d\xd4\xfc\x1b\"\xf7F\x1a\xdfA\x92\x92\x94b\xd6\xf4\x1b?\xbd\x8c\xb2T(\xc5\xa2X\xde\x07\xb4Yy\xf8n\x10\xb7\xd6\xb0\x98\xf9?\x84\x84\x93\x8b8[\xa7-l\xac\xe5G\xe15\xed\x94*\xcc)\x95\xf1Z@~r&\xb0B\xa9B\x03\xbf+?\\\xb9\xaa\xa1\x18\n+\x10W\xb6rny-\x96*.-U3VI\"m\x10\xe8\xd5\xcfEL\xc9\xd57]D@}&\xa6)\xc5\xc6\xc5y\x8f\xfa\x02\x99>\xac+}z\xf0\x16Q\x01\x0e\xc8\xd4%\xbe2el\xcc\x17\xac\x9c\x05\xdb\xe5a\xe2s\xd7\xd7\xfc`@-^#wA\xe4\x11K\xfb@\xc4a\x99\xf6\xb11\xc7\xc2=\x8a\xa3W\x1do\x1f\xae]a\x0e,GA\x1d\xf2 \x06N\xbe\xf6\x00\xa4\xff\x16\x1cVi\xc58<4\xcb\xc6\x1fLJ\xf3\xc7\xf6a\x0c\xe2\xea\xa3R\xd3\xc9Y7\xb9\x83\x04\xf3\xc2\xfe\xd6\x98s\xd1D\x19\xc0\xfctf=\x84Q\xbc\"A\xa9\x07y5\xed\xa8o\xa4n\x1f\x0c\x1e\x7fz\xa0/\xfc\xd0O\x1a\xfd\x13\xf2\xda\x05\xc7o'2iNd\xda\xf9\xd3k\x88L\xda\x82\xc8\x84\xea\x8e\x11\xdbKe\x9csL\x0c\x95\xad\x81\xc9\x89\x17)\x8d\x19e\xe9\xa3\xe3\xb8 h\xf0P\xb2\xdd\xca\xdbC~\xfe\xfd\xa0)\xa8\x92\x80d;\xa2\xcb\x8d\x84\xdb\xb2\xa4\xa0\xd9\xb5\xb1\xd8\xb5\xcd\xfd\x81\xa26\x8b\xed\xbb[\xfd|0\xd9d\xab\x1f\xfb\xb1\x0e\x05\xc10\xcb\x11\xf0\x85GG\x8d\x0b\xf2\x03&\xca\x07\x82\xef!iJW\xeb\xb4\xfb j*\xb5\x01x\xe32\xae\xea%\xad&\x82\xea\x0eR\x94\n\xf6\xe5\x91Woc\x8c7`\xe7\xecc\x9adAzDVt\x0c\x0d\x01-\x18]{\x17yc\x83m\"p\x85\x0e?\x9d\xb8\xe2A\xa1\xab9u,\xc4@\x03q\xac\x95VM\xc0J?sy\xf6\xbcA\xcd+q\x95\x9f\xf1\x8a\x9eI\x89\x0fs(\xf2\xe6\x1d\xea\x01Q\xcb\xa7\xe9D\xaa\x82[\xfb\x0e\x11Z\xe5S\x07\xef8\xa7:[f\xb1\xc8\xfe\xe0\xdc\x0f\xaf#\x8c\x02j\xb3\x15P?\xb9\xdd\x80U\x8b\x99\xb7f\x8a\x95(?\\s\xc8\xd6n\xae\x11\x08rm-\xf8 \x90 \xa6d~\x07q\x16\x86~\xb8\xb4\x89\x01E\xabZc\xf9jU\x95\x1e\xe5\x19\xc6\x0d\xd9\xf0\xe5GL\xf4\xadA9\x0e\xcd\x9a\x85\xb0\xe0\x00\"<\x96\x10O\xfd\xe7\x8d*Z\xc9\xf6\x85\xf9\x06m&\xef\xa4\xa9Q\x10\x0dg\xe8\x14B\x18\x064\xd3W4\x96m\xd32\xc8\xca\x08\xe3\xeb\"\xafns\x1f\xa0(\x85\x1a+\x7f\xa9x\x06\x12\x13\nZ\"\x97\xc7\x85Pjb\xc3B\x0d\xdb|\xfe\xe4\x92\xb9\x8a]E\xa3\xcd0+\x90x!q\x92m\xbc\xcb~\x9b\xde\x01\x9d\xa9j\xba@\x07_m\xf0v\xe2C/1\xb6\xa1BU\xc3\x01\x97O\x9d\x82o\xe5\xad6l\x18\xd8\x87\xb9\xbd\x8a\xd4\x17\xdd\xe4D\xa8\x19\xb1K\xdcq\xd2\x9a\x99\x10\xc0\x957 \x13\xb8\x841\xac\xfb \x8e\x8b\x87\"i\xe3u\xa6\xfa\x11I\xfd\xb0\xabvZ06\xc6\xb1\x18k\xe3\x0b_\xb3\x07T\\MrQ\xc3\xc9\xf1\xae\x90Y\xa4ZV\xd2\xad\xc4\x8eX\x06F\xbaV\xfa\x99-}\xd8\x07\xe2\xf6+\xc97M\xc7\xf0\x8d\xed\xc42;S4\xaeX\x8ai\xb5$z\x99\xd7\x89\xc4\xcb\xdc\xb3\x07\x87\xd1v\xa6\x8d\x11\x1c\xda\x0eQ,E\xc3\x08\xdb\x0e\xab\x15\xd0\x0f1\x9e\xa0\xe1\xe1\xad\xed\xe1\x89\xed\xe1+=0\xa6R\x01\x91c\x9d$=\xb3\xfc\xce\xcal\xd8&?\"hg;\xf1Le\x83\x05\x93\x84v\xb2\xadW\xb7j\xee\xaa\x9f\xf0\x95\xc5\x9a\xb4Nu\xd4\xd1\xa83\xb1\x19\x1a\xe4]\xf9\xad,\x8d\xe9\x8dt\xa7W \xda\xc0\xc3A\xc9\xb2\x90\x07\xbc\x8ey\x90\xbc\xa6\xd7@\xe1:n\x1c:\x0dg\x18a n\xc9{Hr\xd5\xd9\xdf\x177Fm:\x04\xe5\xa8\xc9\xda\x13a\x10\xd7\x11 \xbf@n\x1e!\x14pE\xcb=\x8dE`\xa0(E\x03L\x05\x8bV/]\x17&r\x1dr\xef\xa2` \x9e>\xc8\xb8\xa3\xfaI\x1d\xb9\x99\xa8X\xa2V\xaf~~\x88\xeb\xae\xfaI\x9d|\xd3>\xacC\x17\xc6u\x10|\xd5\xd4\x93\xdc$\x01C\xc9'-\x07\xd2j\xc8\xcd\n\x04\xe2d-x/\xb1w\xd2Z\xb0\xf8R\xad\xb6T\x08\x14J\x06\"K;\x87\xa0\x8f{z\xcc\xa8B\x9dv\xb5\"]\x07\xd6\xc8/<\xec\xa6\xd4\x0bL\xe5\xfd\xacF\x11U\xb0\xb9F\x99\x13or\xea&\x0e*\xb3\x92\xb6`\xac}L:/\xc74\x10\x80\xa9^\x1f\x17\xca\xd8\xc2PB\xcc\xd5\xd0e\xaev\xbc6\xd3\x84T\xc3:\xe5\x1d\x943\xd0\x9f^\xd2\\\xa1\x02\xf3\x88&\x10F)\xac\xe3\xe8\xda\x9fS \xf0\x18\xdf\x7f\x0c\xbcA\x93b\xc8\x86\x0b\x9aH}\xdaE\x8c\x90*\xc7}e%\xc5\xa85\xf4\xb9&H\x0bz,\xf1\xcf\x02\x80Hh\xc5\xebK\xac\x81\xa8\xbc\xeb\x89\xf4B\x90Tm\xe0\x95\x88\xe0\xed\x9dt\x8a4D\xe8\x9dfx}!\xe2\x99\xa7\x85B_\xa8\x9b\n\xee\x02\xcf\x95\xb4\xa4P\xb2\xdb\x19\xe8f\xc0\xb3\xcd\x8f\xcb\xef6\xa0@\xbe\xfc|\xd0\xe0s\x1c !\x88#\xc4\xd4W\xab\x9d{lwa\xd1o \xae\x1d\x1e\x03\x9d\x0egu\xf4\xa9\xaf\xc3\x88\x9b\x9ar\xa0\xc9\xcbd\xcc\xc72\x9a\xb9}\xd8T\x1f\xabz|\xa0\xdc\x1d>\xd7\xd2c\xd1\xd6\xcc\xad\x9b+\xa19]\xdan\xce\x1f\xecs\xa6\xea\xed\xd9\xfd\xbd\xf6\xfa,\xcdMR\xa4L \xbd:R\x8e\xbf\xa5F\xf6\xab\xd1\x94\x0d\x03;\xd5\x0f\xac2W\xd8\x87\xa9}]\xb8\xa9G}e08\xacd\x92\x8f9\x10\x8b\xc8N M\x9d\xea\xfd\xbei\xa4\xef\xf5#E\xaaj\xd3\x16\"|\xa7\xc4p\x07\x81\xb4]\xa1\x12|\x7f R\x9fom\x8fJ\xcf_\x1d\x7f<,?/eU\x1a\xbc>|s\xf0\xe9\xdd\xe9y\xb5\x9fQ\xa5\x1fY\xef\xcd\xa7w\xefJ\xf5\xb6wJ\xf5\x82\x88\xcc\xf1\xc2\x94}\xa9>8\x08\x82\xfc\xd9\x01\xe3 \x8a\xc7 Y\xd0w\xf2]\xf9CWA\xb6\xa1\xfcV\xab\xcd\xb3\xd5\x1a\xb95\xf6\xa5\xfa\xfek\xf9P\xfeP+\xfc\xf5\xe0\xfd\xbb\\q-`\xb0W\x9a\xdb\xfb\xb7Go\xdf\x1f\xbc\xb3-G[0Z \x98x\x84\xbb\xedv\xd9\xb7n\xe9\xd9\x9a\xc4\x18F\xd1w\xba\xf8\xb5\xfc\x14\x93\x19\xcb\xe7\xe2G\xb9\x06\x99\xcf_\x95<\xa5|\xa7[.\xeb~\x93M\xfc\xb4\xea\x06\x1d\x15\x00-\x95\x8b\xb4Z\xdb\xfaDq\x08\xbdRyV\x80\xacT\x9eh\x9cE\xad^\xa1\x01F\xbd-\x15y\x18\x07\xbaL\xaba\x1f\xb6\xcaE\x0c\x81\xb6\xcbE\xf3z[\x97\xf5\xb6\xae\xebm\xad`\x1f\x9eL\xcfn\x87\xc3\x8d\xb3\xdb\xe1\xd3\xb3\xdb\xe1\x8fg\xb7\xc3Wg\xb7\xc3\xc3\x8d\xb3\xdb\xd1\x9b\xb3\xdb\xbd7\x1bg\xb7O\xb7\xcfn\x9f\xeen\x9c\xdd>{s\x96\xbdy\xf3\xe6\x10\xff\x7f3\xbb\x9f\x9ee\xaf\x9f\xb2\x97\xb3\xd7?\xbey3s&\x1dV\xf2\x8a\x97\xb0\x1a\xee\xbd3\x19O\x7f/W\xbb\xff\xdd\xadT{R\x1e\xd6R\x0c\xeb\xe9\xceY\xb69\xdc|\x8a\xff?\xab\xd6\xba\xc3Z\xfd\xb3\xe9\xd9\xec\xec\x1fg\x9f\xab\x8f/\xd8\xe3\xdf\x9d\xc9\xb8s\xdf\xe9\xdcw\xa6d\xe3\xefg\x1b\xb3^\xc7\xfd\xf3\x13\xbf\\\xf3\xbc\xa89\xfd\xbdh\xcfu&\xe3\xff\x98\x0e7\x9e\x91\x8d\xc5\xec\x1f\x9b\x9f\xef\xf9\xf7\xbf\x9fm\xfc_\xcf\xcf\x9e\x9cM\xc6\xff\xf9h\xff\xacw\xf6\xe7\xfe\xf9\xd9\xa0\xf3?g?<>s\xce\\\xf6\xf6\xcc\xfd\xe1\xcfO|\xddYqc<+F\xc3\xc2\x8an\xb4\xc5\xbf+\xd4\xbc\xde\xd4\xa1\xb1\xa9gEK[\x9b-Z\xba}HK8\xbe\x87\x8e\xf5\xc4\xd8\xc3\xf6v\xd1\xd4\xb3\x91\xf2}K\xe9b\xb3\xf4c\xa7E\x87\x1a\xbd\xbaF\xc5,\xc7\xf0\x14^\xec\x0bgI\xf6mg\x0f\x13Zn\xb0\x07cx\xb6\xc7\xca0\xaa\xf8\xd6&\xdc\x0b\x9bF4a\x1c\x0d7\xd1\x9ca\x83U\xea1\xb0\x8cacd\x1d\x98F\xff]\x8c\x82Or\x02\xdd\xb3a\x97\xf7\x9c\x97\xfc\xff\xb0@\xadr\xc1JF\xa3]\xa5(\xc5J\xd5\x82Q\xbe\\\xac(\xe4EjK\xd7X4\xdcT\x8a\x16\xbc\xd6\xb6R\x14\xf3Z\xa3\xa2\xe8\xff\xcfJ\xb6\x94\xd7\x00\x0b\x8a\x97\x1ew\x1f\xc3\x18\xb6\x95i<\xc1\x11\xaa=\x9d\xb1\x92=e8\xff\xe7\x7fc\x9d\x1d\xa5\xe4\xff\xc6:\xeaL\x91*\xb0\xd2\xa7\xc3J\xe93V\xda\xedZ\x17\xe1\xc0\xb8\x08\xb8\xfe\xbb;;[;0\x01\xeet\x87y\x0b_]\x92\xf8U4\xc7\x9c\xa8c\xed\x83\x9d\x9d\xcdg\xbb\xd0\x03\x87!\x0eka\x17^\xbe\x84\x11\xe3uvv\xb76\x87\xe5G\x8f\x18\xbc\xb7\x14o\xd9\x82_\xcb\xed\xe4\x8e\x85\x9a\x043\xee9\x9b;\x8c5\xfb\xa0);\x054\x97;\x85\x17\xb0\xb9\xb3\xfb\x1cN{=\x17\x8e\xa7\xa73\xd8\x87+\xe7\xd4\x85 \x8c`\x0c\xc3>|(\nu\xc4\xe9\xbdV\xc1\xa9\\\x94Dx\xdf\xc7\xc3\x17\x0f\x16~@C\xb2\xa2\xa8,\x0b\xd7Y\x8aN\xb4Q\xe2\xa7huH\x07\x81\x1fR\xb5\x0c6D!:\xd0\x97\xe6^\x1f\xcb[\xedX8\xcf,\xc6i}\xff\x0f\xed\xfbt\x10\x85\xbf\x918\xf4\xc3%w\x8d\xce\x7f\x8a@\x85\xa8U\x12\xed\xeb\x16\x87\xad\xcbQMe\xc4\x18\xb7\x9a\xd1\x99V\xb9{]$\xa4\xab\xcb\x8e\"7\xf0>\xd0\xc15\x8d\x136\x8dG\x8f8$\xba\xf3l\x1d\xf8\x1eF\x1d\x84h\x01\xff\xc1\xba\x84\xb9\x1fS/\xf5\xaf\x91\xc7\xe2IC\xf2\xa4:\xf9\x9b\xe5\x9a@<\xc6`&@o\x89\x97\x06w\xc0d]\x99\x03\x12\xe3E\xb3A\xb0-\x85w\xe0O~w\xd8\xa17\xeb\xb9g\x03\xf9\xed\xcfO\x06\xf4\x96zN8\x1d\xce\xb8\x17\x1b\xef\xc8\x0f\x82\x8dE\x14\xaf\x98\xa4\"\x1a\x04L\xb0I\xa1>Z\xc6\x8e!\x03\xf96L\x9d\x18\xc3B\xe2^\xf1\xcb\xe5\x9b\xb2\x9c\xcf.*z\xcbB>\x13r\x11\x88\xf6%\xccD\x9f20\x1b\xe7?\xe5\xc3}\x081\x12%\x1dx\x97\xd4\xbbz\xe7\x87\xf4\xc7\x98\x92+\x0c{\xc1v\x90\xec\n\x0d\xdc7\x8b\xaf\x7f\x88^\x93l\xcd8Y:o\xe8\xb4\xb4\xba\xd5\xccb\x07?=\x0c]\xea\xb8\xb2iX\xed\xd3\x83\x9f,\x8b\x9d\xdeDE\xc2O\x06\x988\x07\x08\xf2\xc7\xb8\x0e\x17\x83\x94&\xa9\x13\xa3\xa8][\xda\x94,\x81'o\x01g\xe1\xc7I\x9a7\xe8J \x94\xc6\xc0zI\x84\xeef\x90\x92\xe5{\xb2\xc6\xcb[9\xe2\xc7\xe9%\x8d)\x9a\xbb\xc1:\xa6\xd7~\x94%\xc1\x1d\xcc\xa9\x17\x90\x98\xce!\xc9\x16\x0b\xff\x16\xa9b\xf71\xf4 \x86\x1e<\xee*\xc3x\xec\xf6\xe1\x9c\x0f92\x0fy\x1dS\xd6\x8c\x93P/\n\xe7-\xc6,\x07;\x8dg\xb6xr::\xfa\xd1b'\x89\xb7\x0cy>\xb5\xf2\xba\xa2f\x10^\xe8QA\x18\x93Ib+\xdcH\x11q\x8c\xd1\x81\xf1(\x89\xb8\x83\xad\x8fw\xbfB\xed\x06\x11\xbc\x00\x9f\xfd\xe9\xed\xc3\xc8\x15<\x83C\xb0\x8e'\x8e\xb4\x03\x06PW\xf0~/\xf6y|8\x82|\xcfh\xb4=\x1a\x8d\n`\xd3\xdb5\xf5\xd8\x9e\xb8&\x81?\x87\xbf\x9c\x1c\x1f\x15\x11\x0cuv\x8bhp\xb5\xe2\xab\x96)4\x84-E\x92\xc6\x94\xac\xd0\x16\x89\xf8a\x02a\x14n\xacc?\xe4[=o6\xd1\xb6+n=\xd8\xbc2\xd3\x9ai\x96\xecu\xb1d5\x87M\xbc\x7f\xe1\xeb\xd5\x87\xa0\xdc'B8\x1e\xf8 \x17\xfd\x9cP\xc1@\xa1\xaaY\xd1xIaE\xd6k?\\&\xcf\x11\xdb\xc4\xdd\xd6\x1c\x92(\x8b=*.9\xd8&P\xc9\x1aC\xc3\x8c\xaf\x1e\x13\x16\x1d\xc58\xf6\x8a\xdea\xa2\xb7|A3x\x01\x01\xfb\xc3\x17\x14\x9dd\xa6\xd9,\xdf{)\xda&`r!\x1e\x95 \x9c\x12\xb6\xeb\xf9\x0fU#\xae\x03\xcf;\x05\xa3\xd5t\xaa:P\x05}\xf0\xeax\xcd\xb0\x90\xb3MN\xa4\x9e2y\xc4\x11\xf8\x07\xe6\x83N\xc9r|GV\xc1 \x8a\x97\xfd\xcd\xe1ps\x8c\xf0\x13\xa6\xf3u4gm\xf3\xf4\xd2~\xc2\x99\"\xdf\x96\x958\xe0\xe0\xf4\xf0BL\xc2.\x80\x17\xe0\xb1?\x1cv\x12\x17\xfci0\xd3\x9b\xe4!\xf6\xe6\xd5\xeau\xf09\x1d\xfc\x91\xf0\xbb\x95$\x8f\x82\xcc T\xa7X\x13^\xe0p\xbe\x08\xd8\x1e\xc3\x0c_5\xd6i\x1f2\xfe\xa4`\xb0\xca|\x01\x9dK\x14\x83+z\x87!M\xd2i\x84\x17\x7f\xf9\xadM8\x8dfZ\x01(\xb5.\xfe\xa7V\xb2\x94\x102D\x8aMN\xa3\x14JR\x8c\x1c\xf32\x15?{=&Vl d\x98\x80\xa3>\xea\xe7\xa2\xa6\xb5E\xce\xcb\x15\xaf1\x1e\x9d\x83\x87\x00\x02\x16\x9d\x9e\xd8\xf6\x92\x84\x8aSx|\xd6\xc3\xe4C\ng\x8a\x13\x90\x8dY!\xf37\xd3\xd9]J\xc69\x94\x19\xfflSx.\xb2~GZchqyr\xe8D\xees\xd7\xd4Z\xaf\xa7\xb6\xa7\xdd)\xb8\xdb\xb6\xb8he\x08\xf0?\x8f,\x979mz\xd6\xbe\xfc\x19n.}\xc62\x8c\x86\x05#7\xda*\xbe\x8bb\xc3\xb8;7x\x14\xe12\xd6k t>a\xf2\x90f@\xf7!fx\xc5\xd7\xfbm8\xe7\xe6\xcd\xc3\xe7R\x90e\x0b\xa0>d\x95\x1f<\xed\xcf\xba]\xb6!8\xf4b\xba1G\\e$/\xf8c\xcel\xce\xe9\xc2\xf7|V\xec\xe3S\xe4\xfe\x91k\xb3b\xe5\x1b\xc3~\xed\x8bD\xb3r\xc8ZR\xd0q\xb6wpl\xa6\x8d,2\xe7n\xefr[\x01\x0c\xfd$\x84\x96z]\xe81\x82\xdaTe\x93\x13\xc1\x90m\xc5\xad\xbe\x80MC\xff\x9d['u\x1bd\xc8\xbfke\xc0QNjTf\x81\xeb.R\xcc\xda\xcfc\xce\x15\xcf\xe2AL\xd7\x94\xa4N\xf7\x0c\xcdd`\xa3\x94(K\xd7\xf5\x8f\xda\xae\xafE\\A\x89Q)\xd1X\xe2\xf9\xdck2\xf4.\xaby\xb3A\xa8\xa5u\x99Q2M\xae\x11\xeetQ\x08\x95\xbcM1=\xfe\x831\xb8\xf2;;,\x88\x90 \xda\x11+lk\x9b\x93\x13\xfc~\xebX_Dtp5\x97\xbe\x92\xb9\xed\x0c\xfbP\xa6\xffHbY\xf1\xc6\xc8\xad\xef\x96}\x06c\x99\xbb*\x0b\x82v\xa3\xafu\x9f{.\xf0\x0d\xc2O\xdf\xdf\x04q_\xf0<\x1e\x1d\xcc\xce\xc2\xbb\x92\xc8\xe1\x96\xc7\xd7\xa6\xf3~q\xd8#-\xc8\x8f{1\xa5\x97\"^\x8c\x00\xb0+\xce\xb1\x0b2W\x89\x00\x93Z\x08$\xf4o\x19\x0d=\n4Lcm\x94\x80|b\x15\"\x93ji\xa9$\x01\x9dL\xe0\x08\x13\x9c\xd0W'\xc7\x1dd'\xe8\xe0\xca\x0f\xd1\xaaG\x8e\xa0\xdb/6\xd3>\xe3\x0c\x9b\x18\xca_\xcd4*g1\xf95\xbev\x07T1\x9dMq\x8b\x9f&N\xf3\x11P\xd8\x0f\xe8\xdaQ6\x0c\x9b\xbfI\x03C\x84X\xc9\xafv\x18U\xde\x15\x1cP\x9b\xd3\x82\xf1@\xc8\xcfw\xcc\xdcA\xe5\x851lq.)b\xef\x12%\x01g\xb7\xd3\xe9\xb6o\x85\xbf\xd1\xedC\x99\xd11\x98<\x1b\xd9\x816\xdd\xd5^\xcc\xd9\x00\x85\x0b\xd8\xdd4\x1e\xfd\n\xe5(lF\xd8\xecc\x9d \\\xdaem\x86W\xb0\x89Y\x98K\xb04\x9cK\x9d\x80\x10Do\xfc\xf4\xd2\x0f\x81\xc05\x8d/H\xea\xaf\xd8\xcaW\x15<\xa6p \x82sS\xe6\xdb\xb9\xe5\\\\\xbe\x9al\xaf\x11\x98H \x98,\xa5\xceC\x08\x90B\x10\x06z\xeb\x05d\xc5\x11pE\xe2\xab\xa4\x9b\xa7k\xae\xc0\x82\x1dP%\xf1\xa1\x87\xc9\xed\x84bG\x95QCR\xd1\xe9T\xfaL2\xef\xb2$r\xcb\xcc\xe5U\xf4\xe1\xa4\xbd\x1d\xdc\xeb\x0b\xdd\xbc\x9ew\xb9R\xaa\xd0\x15\x18!\xb5\x08\xa2\x1bF.\xd9v\x8d\xe2\xd2\xf8\xcb\xab\xa6#\x7fx\x90u\xce\xf5\xfd1x5\xc0h\x8c\xf6\x1b\xb1\xcb\x03KH\"\x1a\xc3\xb8\xae\x06\x0b]\xa5F\xaep\ng\xa8\xe6\x1a\xb3]*N\x89\xa2\x16+\x93Ou\x8f\xeb\xf2\xb3\xac\xcf\xb5mY\x98k\xd6\x94UG\xcdZ\x88\x9a\xb5\xc7\x98\xda\xdeJ\xbc\x7f6\x13o\x0dY~\xca\xc9r\xf8\x15d\xd9\xcc\xc8\xe8Is\x08\xa2\x86J\x9e\x0d\x03(af\x15\xab\xe5\xc6\x0d\xc5\xc6\xe5\xa2f\xe7\xc4 \xd9\x0en\xd3\xa2\xf6\x84U\xb6M\xae\x03)\xf6cy\na4\xa7\xb0\xca\x92\x02\xdfH\n\x01%I\x8a\xaa{E\xcbV:\xa6\xed\xbb\xa9a\x81\x7fS\xb4a\x9as\x01\xddqQ\x1b\xb6\xea\xc3\xb2\x0fw}\xb8\xe8\xc3y\x1f\xae\xf8e\x94\xe6\xd0~o8\xcc\xff0\x1c\xe6\xcab\x07~\x92\xd2\x90\xe6\xb2\x12\xff\xe5t\xa35\x0d1\xbfx?\xc7~~}\xa3@A\x16\x08~E\xfe\xcc9\x15^\x80jO\xd8Gc\x88u\xc1\x97-\xf8W\x11q\xad\xca\x88:\xefs~\xb5\xcc\xbe\xc1\x84\x03\x01\xd3_\xa9B\xa6\x90:\xf0\xba\xae\xfa\xf0\x85P\x84\x9d\xa2\xf1\xa5\x8b\x17\x1e\xec\x85\xd3\xfa\x19*N\x14\xe4\xa0\xee\xefq3>w\xcb\xc3\x9b\x14\xa3[q~\xec\xbb\x0c\x12\xc6\xd8\xbcn\xfdV \x832\xbfg\x83\xf4\xf3\x1b\x9cS\xf6`-6\x15\x93\xfa\xce1\"w\x0et/'i\x98\n\x80\x1d+}\xb8*\x1f5\xa5{\xc4\x1cR0\x01\xde+\xca^W\x08\x9c\x87\xdc\xb1\xf4\x0b%ob\x96\xce@X\xee\x98%4\xf6YXBr\xcf-\xcf.%Nj\x9f^[\x9f\xae\xacO\x97\x86\x0d\x08\xc2\x8eF\x97\xa7\xf2\x0b\xe4\xc7\x85PY\xb7\x93\x1f3\xa3\xe7\xbf\xf4Vn\x16'\xfbB`\xe6B\x1b\xa9\xf0\xb4\xbb\\(@\x81f\xe7\xa9\xf8~\x7f\xcfhyl\xb5\x84F\xad\x13\xd2\xc1\xb0\x0f^.\x02\x1auP\xea{\x8a\x80\xd7\xe8F\x880n\x03\xb1C'c\xfb\xdcP\xb5\x81\xbfR?l\x84;\xdc\xde\"s\xe1\xd6\xd4y\x85S\xce9F\xc2X\xf8\x94&k\xe2)\xa7\x8f\xaa[\x05td@\x0e\xfa\x8a\xdemp\xd3\xea\x84\xae \xf7\xf0\xc8\xd9\xe9\x8b \xf2\xae\xa4\xd6\x9a\x1d_(l9x\xd7\xb0\xe8\xc3\xbc\x0f\x97}\xb8\xe6w\x05n\x1f\xf7\xc6\xb5\xa0\xd2\xa2\xe8N\x109\x81\xdc\xc8|\xb2\xbf\x97\xf9\xfe\xc57$\xc1\xb7\xc3\xa5e\xf2+\xa6\x04\x88\x97vF\xe9\xba\x91Q2\xe5'a\x80\x17\xe6\xa0\xce\xba\x19\x17\xf8\x9d\xd8\xb3\xad\xbe\xd0\x83sM\xac.P\xbd\x85\xf2\xb1>G\x9b\x9caX\x1beQ\xf9a\x1d\x8e6wD\x8fC\xde\xe3?\xda8\xf4|\x01[\x15\xbb}0\x80\xa1|\xf2\x0b\xfc_[\x19\xab|\xab\xb1\xbd\xda\x06\xbc\xe2\xbe\xb0.\xbe\xf2\x9b4\x8e\xbb\x97%\xdc\xbdVp\x97\xd1\xdb\x1c\x7falR\x1b\xc7\xe6\xc3d^\xf0\x1f\x9c>\x82\x17\xadV\x04.hzC\xa9P\xf8xQ\x10P.\xc0R\xeeD\xc8H\xa3\xc7\xb6\x95H~\xc9\xc5=\x1f\xef\xd99\x9a\x88\x13a\x0dm//@F*%\xf6\xeb\x8a\xd4\xcdU\x0e\xe5\xeb\x84@\xb9N\xf0\n>%Q(h\xa9\x19\xe3\xc2\x97\x05z\x02\xf9\xe5H!\\ \x8ew\x8d\xe4Xj\x9b\xdb\xe0Qe\x04\xba\xb1/\xca$\x9f\xad1\xd2\xb8\x18\xe9\xbc\x874d\xc1]\x81'\x10\xf3{\x13\xac\xc0\x17A\xa9\xc3*\x89\nI\xb5ga\x1e\xde\nI'\xe0\xcc\x1f0G\xd6-\xd6\x1f\xb5\xd8\xb3\x0fQ\x13W\x90\xb1\xaasd-\x9d\xb3\xd1\xa2\xee\x83 \xd9<\xfdn[R]\x15T\xe7f!\xd5$\xf0y\x96g\x0b\x0c\x8a\xab}\xb4\x86Z\xfe9\xf9\xd1\xe9\x01 \xa7\xa9b\x11I\xf3\"\xba\x82\x87\x7f0\xe1\x16\xb7\x08\xa4\x15\xddntP\x04I\xa6\x95\xab.\x8f\x04$.S\xacnW\x12\\b\xf0deC\xdb\xde\xb2N\xbf.h\x89\x1bU\xe22\xfc\xdcg\xe4k\x82+-\x1a\"\xc8\x7f\x8d1\x80\x17\xc7K~=\xcd\x99\x1b\xef2Z!w\xb3B\x86\x92q-\xfe\xc2\xd7[\xe1A\xb3\xd8\x83b\x80\x83\xc4\x83\xbbI\xa0\xbc\xc8\x93ne\xb9\xb3D&\x9d%6F\xbfF\xf1`\xdf\x18\x11\xbe\x8e5\x0c^\x87\x0e1\xea\x16\xac\xe65m0D?\x0ey\xaf\x86]\x9b\xf9\xfe-\x89Y\xc6!X\xc7\x07_3FP\xc7\xd9\xb9q\x88r\xcf\xad\x19\x90aC*\x1b\xce0P\xc5\x1a\xa8j\xe4\xd37\x8d\xbe\x9d\xf2\xc4\xe9x5Y\xe9\x05;\xe4\x1e=\x92\xd6CDc=\xd4\x06b\xe6%\xebxP5{x \x0bdC\x169{\xc1\x1f\xb8}\xb8A\xd4[\xf7z_\xbc\xd9\xeb\xb3\xb3\xe3C\x82\xf3\xbe\xae\x98\xd3TLf\x02\xf4A\xe9\xc1\x1a\xc6\x8c\xb5\x1e\x8b\xb70\xc4\x88\xcc\xf1\xa8\xd8\xe2\x9c\x85M)\x0f\xecA\xed\xcd\xaa\x0fa\x11=\x01\xb6Q\x18\xc7\xb0\xca\xd9\xb8\x96\x83\xe7Zo\xf9\xe6\xc8\xfa\xe6Z\xf0\x8ccA\xed\xd60\xd1M\x17\x90\xee\xd8\xdaix^\x1e!\xb7\x16\xee\x0c%\xe9\xea\x8b\x83\xbbj\xfe\x05\xd5M\xf8\xdc\xfd\n\\e\x9f\x8fB_\xaaj`;\xa3\xb6\xa4\xd3(@W\x8ek\xc9A=P\xbc\xd53'[\xcf\xbe\xfez\x12\xdar\x0bUi!\xc6\xec\xbd\xfb\x9a\x0b\xc76\xe3\xb1\xb0\x1c[\xdc\xa0\xdf\x9a\xf2\x82\xd5\xfb(8\xf6\xd2\x821\xee\xbe\x01,e\x9e\xa5\x00\x8cE\x17\x18\x97\xe6Y\x85D\x19\n\x863\x0e\xa9\xd7\x8d\x83\xb7\xe6\xf9\xd0#1b4\xf6\xe3\xb2\xc3H\x88_u\xf0\xf2}\x94Kt\xfb\xfb\xfb%\xc3\xdfG\x8f\xb8\xf1\xe4\xc4\xca\xefK\x1f\x9f\x82\xe3O\xfcp\x19P\xf8[\x16\xb1\xaab\xedEBJ\xf3,5\x1b\xe9!b\x86\xbe\xd3o\xb1ST\x01\xc3\xb0k\xb69z\xb4P\xd3}\xfb]\x13\xa29\x85v\xd7\xb4\x18\x8fU3\"|W\xb3|\xd0Z\x8a6t\xabC2!>\xaa\xb16e\x9b-\xf6\xa2\xae\xab\x9bvW4\xae\x8a\xfd\xe6}\x98\xeb53\xee/\xca\x90\xfex\x9a\xcd\xdc\xd2\x01\xf3\x01}G\xd4I\xb6h\x11%\x9c\xd1\xa60\x83\xc3`\x93l/m\xa2+\xf1^.\xcal\xc3\x18\x9e\xee\xe4?\x99\xd80t\xe1%\xfb\xaf\xc5]Y\xc4/\xb4}n\xb4\x1d\xb1\xf7\x9eC\xb4\xb1\xe1b\xef\xaf\xda\xc2\x8a )0\xc1f\x1c\x1f^\xbc\x80m\x17z@r\x91*\xdf\x81\x97\xf4\x96\xcc\xa9\xe7\xafH`wiR?*(\x0f\x1c\xbf\x82/f\xbe\x85\xc3RR\x81\xab0\xba \x81&\x1eY\xd3\xdc\xd8\xd3\xd6u}g\xd8)iVPR\xbe\xf5M\x94\xb4\xde\xf0w\xa2\xa4\xf3(\xbbhCI+\x83i\xc1K<\x84\xb4\xeaG\xa1%\xad\x8a\x1aG\xc95o\x0e\xbd\xc6!\xad\xa7\xaa\xdb\\\x87\xd1|\xf1\xdd\x86\xaa\x1a\x1aie\xee\xc4M\xe0n\x85\xf5[\xe7\xc4\x89\x19\xd9l\xd3b}0\x0f2y\n|\x92<\xc8\xe2Ic\xfc\xd8/\x9b:)*\xf5J8\x16\xd5\x10\xf2q\x16\xe6j\x80\xb9\x18G\xc5(N9\x93T5}8\xab\xde]\xd5\xd9U\x86&_j\x8a\x82ZWO\xea[\xd9IiV\xce\x99/\xba\x19z\xdd:^3b1\x88\x9c8\x1ew\xfb\xe4D\x1a\x85\xde\xad\xa7\xc5\xf7\xedM\xa5|\xab\xf8.\x15}\xf8cW\xad\xf4L\xf9\xae\xd4\xd9\xdaS\xea+\xe5\xcfx\xa8\x07\xcf\x8a\xe5x\xe2\xec*\xdd\x0b\xb5\x99\xc7u\xf4\xb7\xcd\xdbHHg\xf7\xf7\xdc\xbe\x8f\xa1y\x8b\x8d\xd5\xcc\xaeD\xe8K^fw\x85\xd5\xba\xd8`\x9e\x95\x0b\x11\xd6\x19\xd6Dp|A\xbfh\x8a\x16\xe1YI\xaf\xb8\xb5\xd3v\x10\xf6\x01\xa0\xafL\x8b>\x9b\xb4\x12\x8dGM1G\xafY\xfb\xc8\xda\xbc\xc1\x8a\xcdV\x10Y\xaef\x91\xd74\x8a\xf1Y\x90\x17p\x95\x89rrn\x8cjw\xd4\xfb\xf6\x04o\xf2C\x14\xf9\xfd\x8b\xb5U\xe2#S:X+\xda\x839\xab\xc0\xe7\xfe\x1f\xdcx\x80\xd1'u%\xc4\xfduI\xe7\x16|{=\x8e\xbe\x14/\xc08/\xc3\xe9gg$y\x191\xde\x0d\xc8\\\xdb\xe6t\xfbp((\x9fS\xae!\x0c\xcd\x0c\xcb\xd1\xe0\xf2`:\x11\xabC\xedtr2\xc2]\x82\x05\x99Y\x94\xe8\xcb\xba\xaeQ\xe1\xacH_ZQr\xf2\xf7\x87@\xa1\xdc\xd1:\xf7f\xc9\x8d\x0d\xba\x93.\xea\xa6,u\x95\x12q\xb3[\xd8\x81\x15gur\x19e\xc1\x1cmu.\xc95\x05\x12\xdeI\xcbk\xbc\x84\x95\xfe\xde\xad\xaf\xbb\xf3{\xc5Buv\x9a\xcf\n\x8d<\x85\x8dg\xa5i1\xean\xa7[\x14\xe8\x9d\xcd\xba\x93n1S\xab&y\xc9ugw|\xed\x85\x11\xd2\xe9\xdd:OZ\xf7\x1c\x96\xf0\x02\xee\xd8\x1f\xf4\x1f\xb7\xd2\x1c\xe7\xa2\xde\xcet9s\x072\xe0\xbb2u;\x9dPp\xe2b\x90'lW]\xd3\xe4:_\xf0\x1b\xe6/\\\x82o\xbb\x7f\x05\xb1/\xb1t\xe7\xb6`T\x0b\x86N\x19\x13\xbfw\x16\xc7\xdb\x91\xf0\xf0;\x9a\x863\xa9cc\xf4\xf4\x0f\xa1q\xe0\xf44W\x82\x15hZ\xd2<\xfc\xc9\xdcy\x99\x1e\x0c\x15\xd1H\xec\xf7\xc2=\xdfN(\xdaV\xe4\xf1\x1c\xdaW\xdet\xcb\x11]D\x84\x07u\xdc\x0c D\xb3W\x13T\xd0\xadH\\\x8b\xdb\xf2[\xc1\xd3\x8bi\xa2\x9d\xc6Z1N+\x03\xa6N\xa4\x1f=\x82%w\xf0,\xaf\xbd_^{\xc8Cq\x84Q\xb8qp\xf2\xea\xed[%\x9eL\x02$\xa6\xe0\x87)\x8d\xd71E\xc7\x87\x04\xc5\xad<\xe8\x9c\\\xda\xa4\x166\xa0\x85<;\x81\xed\xddf \xbb\x82\x15h\x80\xb0RA\xf1\xa4\xdeP\xa9d]\x1f\x1a\xc5\xa8\x0b\x15\xe8Yxp\x94\xd6\xc3z\x18\xff\xd5\xd1Fa,bAQqv\xa0\xcc\xc3\xce\xc8\xa1\xe4\x17\xf2\xb8v2d\x0c-\x03\xa0\x98\x02\x82@\xc4\x92\xb1Wrhn^\xd0\x87\xdd\x9d\xcd=\x11+U}i(k\xb2r\x8e\x15#\xb7J\xfb\xaeE\xde\xe9\x90\xde4\xdf\xaca\xe6 \\B\xc0DL\xf8[F\xcfds/~\x08\x96G\xd4Id\\\xf6T~\xbd\xbfg27>,\x02Y\xb2\xe7\xc5\xafr\x13\x9c\x13\xc1*\xe2\xeb\xfd=W\xeb\xb3\xa7\x18\xa0\x8a=\x93\x91\xaa\xf2'9\xbb\x86o\xca\x1f\xe5\xb6KB\x8cL\xc2\xcd\x07\x8a\x81\xc0\xfd\x80\xce\xdf\x8a:2\x97 \xe7\xdf\x0d\x95O\xf9\xd3|\xe8\xb8v\x052\x88rE\x171\xccG\x8b\xea\x08\xf5\xa7\xd4H\xa8e\xaa!\x10O\xf7,\xf7'\xf2\x17eB\xcb\x97S\xc3\x04\x86b-\x11\x93\x86\xdd\xaev\xe5\x97s\x93t\xf2\xdc$EZ\x12_3#%$V\x11\x82-\x86\x17\x10\xb1?<\x04[\xea\xf8\xd3xf\xa7-?i7\x9c\xdc\x99\x7f\xd5\xad\x1f\x1b\xb1p\xe8\x96\xd9P4\xfb\x95\xd5\x1a\x89%\x95\xb5$X\xa7C\x8dOA\x91\xc9!r\x8a\x8b\xc3\xfc\x86>\xa7\xa0~\xa8P\xd7>\\d),\xa2\x8c\x9drQL\x1f\x94\xc9\xa1He\xf0K\xbf\x9e\xfa\xe0\xa7\xbe1kA\xd3-D\x8b5E\x94\x89\x07\xf46\xa5\xe1\xdc\xa9\x83\x8fo\xea1\x90\xf2|Xg\x95\xe5\x90\xc8\xf7\x85\x8d\xfdI\xf9\xa9M\xe3`\xa5\xccb6?}\xe9l\xea\xf1\x81\xbf>c\x81.\x98h\xe4\x94B/V\xa7\x81tL\x1c$\xf2l\xb9\xc8\x16\x0bN\xba\xeb$3,\x93\xccX\xfc\xf4\xa2 [\x85\xa5@\xa7\x05\xde))\xd8\x07K\x9a\x9e\x84\xfezM\xd3&\x00\xd7\xcc\xd5\xeb{\xb1\xa3\x0c\xd7U\x95\x06:\xd9\x1bD\x00\xf8m\x85c\xd8\xdb\x11\x11p\xc4\xadKi\xb6\xc2:\x80\x1d\xe7\x1b|?w\xcf\x86g\xf1Y\xf8\x7f\xfe\xb7\x9aU\xa0;\xf0\xc39\xbd=^8\xcah\x90\x8a\x1f\xa4N\xc4\xef/\x0c!\xab\"\xd8@2^\x06\xf2\x06\xf6\x9b\xc2\x13\xd8\xe4\x9c\x87^X\xc3q\xc3`0\x00\x1c|o\x1fv\xf4RJ\x1bw3\x04\x91/ A\xea\x90 \xf0B\xc5\x0d\x85\xbd\xfab\xd0\x10#X\x1c\"\xc8\xf8F\x052-\xa0\xe2\xabP!\x0c\xbe_\x01\x15\x81Q\x99\x84\x87\x98\x00\xe7\xea\"\xee\x8aX\x98R\x02\xaa\xa1\x84\xe4\x95\xa1\x01x\x8f\x07\xcc\xefUkAO\xb3\xe6=\xe5\xbc\xe8A\xf7\xf7\xaeJ\xa0\xd4=\x94F\x9c\xfb\xb5\xe6\xe6UB\xf6u\xbb\xda3\xbe\xd8\xfa\x8caE\x0e\xe2\xb1\x1fr\xe1\xb1x\x86\xd1\x92\x1f\xe3U9\xe3XH\xca%\x186)\xa7\xa0\x04(\xd7\xf5\xd8\xdc\x04%(\x9e\x8b\x02~\x05\x82;\x10\x85r|VP\x03G\xa8\xa8x/c\x0e5\xd4]j\xc9tNi\xbe\x92h\x8ev\x953Em\x9d\x9d\xc6\xb1\xa3 \x87\x93\xa4q\xb7_\x81\xf5\x95\x1f\xce\xc7\xc5}n\xe9Y\xae\x90\x1d7\x98w\xd4t\x9e\x98D\xa2\x94\x8b\x00\xca\x07\xbb\xfb/\x82\x00\xfd\x9b\x11\x02\xb9c\xde\xb7\x85A\x95\xb9\xfe\x97\xc3`E\xd6&\x18\xe4\x8e\xb6\xdf\x16\x04\x15\xd7\xd0\x7f=\x08\xd8\x08\x1f\xb4\x13\xc4\xedA\x13\x00|\x19\xbe\x07Ek\xabm\xf0u\x9e\x8cR\xc8\x01&h\xca\x98\x9d\x8f\x1eA\xf7\x7f\xc4\xcd\x1d\xf2\x02E\xb9\xd3\xc5 \x15\xcf\xbaG\xd5\xdf\x9f\xde\xbd\x13\xbf+\xbcv\xf3R7\xac\xb4\xad\xb9uL1\x10Y#\xe0T\xcc\xc1Q\xdaZ\x8d\xe9:\xa6 \x0d\xd3\xb1\xa6%\x8f\x84Q\xe8{$h\x98\x01\x14\xbdv\xffG\x93J\xb3~5\x12D74\xf6HB\x1f\xd02\xaeK\x9b\xc6\xb3\xf5\xfa\xc1\x8d\xe3\xa2\xb6i\xdc#+\x1a<\xb4q\xfd\xc8m\xeb2\xa7\x0b\x92\x05\xe9Iz\x17\xd01tsxu\xff\xe5\xfb\xfd\"\x8a\xfe\xa9\xfb]c?\xd5z\xbf\x97\xf6u\x1agT\xdd\xc7\xa7\xd5\xdf\x1f?\x1d\xca}\xcd\nv\xd4\x97\x17$HJ\xb5\xdf\xd4\n\x0e\xde\x9d\x1c~)]\xb0m\xe4\x87\x0c\xfc[\x12\x90\xeeT\xa4\x13\xf81\x8a\x02J\xc2\x19\xef\xa3\x96\x9cN\xb2\xa12\x03\xed\x17\x93\x1b\x1dQ0&\xc8\x95\xf6\xa00\x91\x00\x1a\x83X\xa56\xdbXG#Z\xf5\xc5\x81=\x96\xeb\xdd\xa6/\x1d\xc9h\xd7\x97\x9c\xd7\x1b\xc3\xbc\xfe\x1d(\x88)C\xe2\xee\x03\x93\x9c\xd6\xb2\xa7\xed\x14\x03\xd54D\xda7\xb4\xa74$\xbfUI]\xa4#u~\x98\xfe;P:\xae\xb4Q5\xd8Z\xcc\x89\xccn\xf5\xba\xa8\xde \x95'q\xa3ylw\x83\x1bB\xf1[\xd4i4C\x19\xad\xdb\x13y\xdesY\x8eN{\xbdh\xe6\xf6\xa1;\x14\x99\xfe\x8d\xe29j=z\x82!\x8b\x1b=\xbfp\x14\x17\xbcQ\xb5+S\xfb\x90\xbby\xf4z\xa4\x9fb\xe6\xb7\x959\x8ev\xddA\x1a}b\x02\xe9+\x92PG@\xa2\xb1\x9a\x0526\x1c\xab\xc8\x85b*\x15I&aO\x0f\x02\x9f$4\xb1\xe1\xe2t\xb3\x0f\xdd\x0b?\xecjR \xe4\x98>\xedC7\xf2R]\x95\x1c\x8e\xd3\xd1\x10\x13Uy\xbaZ%\x88OG\xbb}\xe8^\xd2\xdb\xee\xf7\xbd\x0b0\x8b\xb5\xe5b_\x08\x90\x1f\xe9\xf2\xf0v\xedt\x7fw&\xe3\xe9Fo6q&\xe3\xe1\xfdt\xb4\xf1l\xc6\x8e\xd8\xf3\xd9\x0f\xae3\x19\x9f\x9d\x0d\xe4/VaJ\x0fgXY\xa4\xc4\x9d\xdc\xe7\x15z\xda\xc7\xc5/\xd1\x8c3\x19\x97\x0f\xf2\xa2\x07^\xf9\xecl\xe0L\xc6~\xb8\xb8\x7f\xcb\xfe\x1d\xbdq\xefyQH\xc2\xfb#rt\x7ftp\xe4\xba\x7fV-\xef1.?&\xedU:\xa7O\xcczB\xad\xf0\xbc\x08\"\xf2]\xc4gU\xbf\xcdoF\x18\xa5u:\xbe\xe0`\\\x95\xf9\xa1S\xd5zo\xf6\xcdy\x1am@\x189B\xd8\x07\xc9G\x08\x03\xe4\x1a;2H\xa3w\xd1\x8d\xdc\xd2\x8c\x97\x80 ;\xc8\xc7 b\x00Og}\xe8\xf66\x94+tdX^\x8a\x13\x86\xdf\xa1\x16\xccH\x1fX\xcdE\xc1{\x08\x0b$\x98\x88\xc3l\xf0\xe1\xf8\xe4\xed\xe9\xdb_\x0f\xcf\xdf\x1e\xbdy{\xf4\xf6\xf4\xaf0\x96\x8f\x8e\x0e\x7f:\xa8>\xea\x0eB\x12\x16\xcd\x1d\x91#\x18CZf1\x04is\xd2/\xe33\xa22\x9f\xf1\x86!\x8e\x95\xd3\x10\xb6w1\xe74\xa2\x07t\x95JN#f\xaf\x9b9\x8d\x10~`|\xf3\x18\xbf(\xa3J\xff\x9dx\x0d\x873\x1b\x9d}\xee\x8d\xa1\xe15\xda2\x1b%Bi\xc2\xf8P\xaf\x1c\xf2\x93#r\xc4\xfa\x82\xe4\xc6O\xbdKp\x8c\xca\x03\x8f$T\xd5D\x8e\xb5\xb5@\x01\x0e\"\x9f^<\xe2\x8d\xe5z\xdc6\x8d\x1d\x1d\x1cY\x1b\xcb\x15\xb5\xad\x1a#G\x1a\x8dl\xe1\xf8l\xdcnB\xeb\xf7=\xa0\xc5v\xfe7\x83\xd6\xdb\xa37\xdf\x0eZo\xc3E\x1bh\xd5)\xd0\xf7\x83\xd6\xc67\x05\xd7\xc67\x85\xd7F#\xc0t\xbb\xbdx}8\x18j\xc6\xa2\x9cKe\xbe\xb7\x0f$\xcf\xe95\x810?\xa6\xba\xb4\xcb\x0e\x14\x1e\x083\xb4\x11\x93\x7f\xd6mC\x8d\xff\x8aj\xfcW\xce\x1e)\xff\xb9\x1b\x8e\xe9\xc7\x9f\xbb\x8d\x1c]c\x8b\x93\xca/\xc6\xbb\x9d\xa6\xb3\xfb)\x9c\x9d\xa5\xb3\x9e[z8V{/\xfd\xe0\x0c\"/\xf9\xc1\xe5\x1c\"\xb6\xf0\x83\xf3\xdf\xf7\x0ec\xc6\xdcj7\xa5\xf7\xdd\x89\xebNJ\xac\\\xab\x1b\xdd\xd4_\xd1$%+\xa3)\xcb7\xe7\xd6\x8a\xb0\xe5\xd1\x80\xdeRO0my\xa9/K\xbf\x03\xbf\xa6\x89\x87b\xb85Y\x0b\xf7L\xfd\xb9\x97\xdf\xe0 \x0b\x96\xcf\xc3\xcd\xb9\xb2b\x12j\x9erW1\xf3>\x8c\xe3(v\xba\xafIJs\x9fZ\xca\xcat\xc1\x99|\x91W\xb4\x97NG3\xce\xfc\xf4\xd2\xe9\xe6\x8c{-\x11\xfesk\xd6\x87N:\xdd\x9e\x15f\xb0\xf4\x06X\x07\x0e\xfbo\xf0\xe9\xf4\x95#\xc0\xa0\xf3\xc3\xf3E\x98\x8a\x1ek\x82G\xa9\xe8\xa5\xd3\x9d\x19\x8fO\xd1K\xa7\xbb\xb3>\xa4\xd3\xbd\x99\x89\n\xa3\xca\x15\x03\xdfN\xf7f\x82+\x1d\xf6a\xcb}\x0e\x8b\xc2\xa7r\xeb\xb9\x0b\x0b4\xf0\xd3Q)l\x87u\xb7\xa8\xd3?\x13z\xa5\xd3g3\x04<[\xb3]\xba\x0d?\x80\xb3;\x84\x1f\x10Z\xc3\x19\xf4\xa0\xe7\xa4\xd3\xd1h\xc6\xd0l(\x95\x80\xb8 \xea\x9b\x1bkW\xc4g0\x82M\xc1\x9e\x85\x8bQ\xd5\x1f=\x02o\x90\xd0\xf4\xd4_Q\xc7\x1b,\xc57\x1760\x88\xa6gCa?LR\x12z\xf4x1\xc6\xeeZph\x96M\xc6\x88\xfa\xdb\x93cA\xd7\x8d\x8e\x00\xdf\x8a\x10?\x90\xcc\xf0\x04\xfc\xdf\x8f\xc4t_\xbcP\xac\"L\xe6O\xdf\x0e\x0c\xc5\xcf4\xbe\xab\x0c\x8b\xc3hg\xdb\x1d\xfc\x88\xb6\xc2E\xaf\xe0\x11dd\xd8L>\x97\x1a\xb4(\x18\xba\x07?\xbez}\xf8\xe6\xa7\x9f\xdf\xfe\xe5\x97w\xef\x8f\x8e?\xfc\xd7\xc7\x93\xd3O\xbf\xfe\xf6\xbf\xfe\xfa\xdf\xe4\xc2\x9b\xd3\xc5\xf2\xd2\xff\xe3*X\x85\xd1\xfaoq\x92f\xd77\xb7w\x7f\x1f\x8e6\xb7\xb6wv\xf7\x9e>\xeb=\xd9?\x0b\xcf\xe2\xee\x03%x\xae\xe4\xf9\x1e+\xf6\xc57\xe0\x06J\x1d5^\x8e3\xfa\xe8\x1b\xae\x88B\x1e\x030\xe4\xbeC\xa1\xed\x9e\xa8\xe3 i'\xb9\xfcK\xa5\x19;\x8f\x06\x08\xbb\xdb\x8d7G)\xbc\x80a\xab\xdb\x1f\xd4\x8b\xefj\x1f\x1b)a\x0c\xff\x01OQ\x01]\xc6\xfb\xaf>:\xa3\xb2\x02cz\x16\x9f\x85\xfb3\xa1\xc60\x03=\xb2.K\x86\x91\x80\xb4\x8f\x12\xf3r\x07\x86;\xa1\xdc\xd3{\xf8\x1c\x18\x94\xc9sH{=\x17R\xf8\x0f4\x05\xe3*\x13~\xa5\x13\x88L\x11\xf0\xf2%\x8cv\xe1\x11l\xee\xec\xb8}P\x8b\x9fVK7wv\xe0\x11$\x8c\xec'\x98\x0e\xe4\xc5\x0b\xd8\x85{\xc8rt\x88$:\xa4\xba\xe3U,\xd1\x10dH\\\x82\x03\xfb\x01v\xf1\x9a\xe6\xab\x86\x04c\x18=\xcdu=\xe5\xb6\x86\xda\xb66E)\xbe*|\x0f\x19h\xd4:\xdb\xf9\x9b1\xa6\xdfX\xc4\xd1*\xff\xe2\x04(\x16 \xbd\xc7\xaf\xdf\xd4~\x15C|0)\x87S\xd0\xf67'm\x11:\xe6n.F\x82b@>\xd2Hk2\x0b\xad1`\xe7V\x05;q\xe7g\xd3\x08\x97\x8f-\xfa\xee\x16\xf2|J\xe9\xa6\xaet\xb7R\xb8\xbb\x05\x8f\x00Mr\xd8\x8c\x9c\x88a\xecS\x17z@\xa7\xa9\xf9R\xb5\x8c\xa0[\xfc\x0e\xf1\x1b\x8f\x08\xc6\xb0Y\xa0k\xa9\x9d\xa1\xae\x9d\xedZ\xe1\x8b\x17P\xedqw\x1b\x1b\x1e\x15\xc8\\j\xb9>\xc0\x17/j\x0d\xefn\x97\xdb\xebC\\F\xbc\xfc\xd7Ws\x10f\x89\xb6\xa6\xff+\x87\x9c\xacs\x08F\x85\xe1\x03\x99\xb4\xc8\xe2\xd1`\xf0\xea\xf8\xca3\xdfd\xcf_\x91\xd7\xb8*\xdcx\x1cP\xdb~\xe3\x97\xd2A\xee%\xccv_\xf8\x9c+\x83\xcd\x1ed\"uh0MgE>\xb0\\]\xcb\x01>\xeb\ny\x15\xd5\xb2q\xb3Q\x87\x88\x89\xe3\x87\x10\xdb\xadx\"\xd1$Jj\x16\x8eB\xd6\xcf\x1a\xbb\x96\x9f/\xb2\xd6A\xe6\xa7\xb9\x0fVM\x98!$\xf9\xa1H\x9a\xc1\"\"[\xb4\xca\xdf\x91#Ny[~!\x83S\xd7O\xfc\xb3\\\x8dZ\xec\xfa/\xdc\xc4k\xe2\xc7\xc9\xbf\xd7.\x16\xbe\xbb\x96\x9dJ\xc4\x8c\x0e\xe2\x98\xdc9\x99t\x81\xcco{\xd8\x16\xce\xbel\x0bg\xb8\x85\xf5[7j\xbdu}\xf4\xe7G\xc3!\x85\xe2^\xd1\xbb\x84\xbd]u\xf17\xb5B\xa6\xe9\x8c\xd12\x7f:d\xe7\x0c\xfe\x9d\xcd\xfe\xe9hoXG\x1dW}]\x0d{&R\xd1\x18\xd6\xd1/\xad#\xd1\xae#1\xad#[-\x82\xab\x15\xd5@\xdc\x07_\xc0.\x12\xb0\x8b\x10vF6\xc6\xff7\xd8\xc1\xe5s\xfb\x81\xfb8\xa1\xc6\x0bt\xbdw\xe1\xf7\xdb\xc4\xd6#\xd6\x0f\xc1\x10\x08L9\xc9\xc2\xbe\xb0D\xccIm8Mg\xd6\xfd\xf2mQ\xdeD\xe9\xff\xed<*\xffH\x9ed\xe1\x9c.\xfc\x90\xce\xbfR\xfbb\x81\xc3\xc3\xa1\xea\xd6\xf2\xcd?T\xa6\xbb\x8e\xfc\xb9\x8c/f\xeb]'\xcd\xd94\x7f\xffn\xae\xd1\x7f$Ob\xba\xa4\xb7\xdf\xe5F\xe5\x01\xca3\x1f\x03\xd5`\xbd6\xe7S\xeeW\xa7\xe7\xb3\x19\x11xr\xf6\xc4\x99.\xfd\xd5\xec\x07\xf7\xcfO\xe4\x05\x87\xbez\xac 9\x00\xd2z\xfa\x89\xd4\xbe\x0f\x8dw \xfc\xc2C\x9a\xf2\x86\xd3\x11\xcab\xf2\x16\xe1%\x93K[\x9c\xd8\xac'4\xeb\x9d\xa6\x85!P\\\xb2 *\x9a\xa9\xb5\xf2\xbd\x8f\xe1\x7f\x0e\xc4\xe56Q\x80\xceo\xe1\xaa\xd0-\x19\x13\xf5\xc1\x001\xbc\xd0*.H\xd3~U\x96\xf9J*\x913j\xbc\x83\xb6&1\x0f%(\xd6\x05a\xb0\xea\x01\x1d$Q\x16{\x14z\xac\xc0\x08X:X\x06\xd1\x05 \xc4\xd5_o\x1f\xbaK\x1e\xb9\xaf\xc8D_\x11\xf5\x9fV\xca3\x9b\xd2\xaf\\5i\xd6.\x94_\x08`\x1f\x9eU\xc8 \xec\xc3\xa8r\xad\xb5\x80}\xd8\xda\xac`\x03+\xdb*\x97\xcdY\xd9v\xb9\xec\x92\x95\xed\x94\xcb\xaeY\xd9^\xb9l\xc5\xca\x9e\x96\xcb\x96\xac\xac2\xbe;\xd8\x87\xed\xcaX.XY\xa5\xdfsVV\xe9\xf7\x06\xf6a\xa7\xd2\xc7!\xec\xc3n\xa5\xbd[VV\x99\xdb +\xab\xf4\xf1\x8a\x81\xaf\xe2\x93x\xc5\xca*\xef\x1e\xb0\xb2\xddr\xd91\xe6/\xacT\xfc\x80\x85\x95^N\xb1\xb02\x95\xf7\xb0\xafA\xfa\xe1\x18\xbaggC\xcdQ\xb4\x87O\x88\xe6\xc9S|r\xa1y\xf2\x0c\x9f\xa4\x9a'#\xdeQ\xa8{4\xc2G\xd7\xbaG\x9b\xf8h\xa1{\xb4\x85\x8f\xaa\x0c\x1d\xfbl\xf2\xa1Wu\xd1\xec\xb3\xb5=\x86\xc7gg\xdd\xc7\x9a\xb1\xf3\xbe\xce\xce\xb4\x9d\xf1\xde\x8et\xcfv\xf9\xd4\xceu\x90\xda\xdc\xe2\xad\xbe\xd3?\xe4\xad~\xa8(\x1a\xcaU\xdf\xb2\xf3\xba{\xd7\xedC\xf7\xaf\xec\xbf;\x9a\xe0w\xf1\xe7\xf0\x84\xfdA\xb6\xb7{\xcc\xff?b\xff\xe3W\xfe-\xc2\xaf\xfc\xffc\xac\xbdX`E\xf1\xe7\xcd\x9b\xeeL\x17U\xe3\x8f:\x9d,\xb4\xb6\x95\xabhn\x82\xb2ou-\xeb\xf3\xc8\x19\x9b;;.\xe7\x85n\xbb<\x80\xeff\xb9\xad\xdc\x1a\x19\xab\xef\xee\xecl\xc9\x172\xf1\xc2\xb6\xe6\x05=\xd7\xde\xe1\x8dlo>\xdb~\xb6\xbb\xb7\xf9l\xc7u\xcb\x11q\xbdhNa\x1d\xf9\xa5\x8c\xb9<\x00\xe2\x8a\xdc\xc9L\x0c\xcb\x98\x92\x94\xc6<\x19\xc3\xf0\xf6\x8d\xf8\xe8X\x07\x1c\xe8'1\xd0\xa7\xe5\x95-\xfd\x92\x87\xde\xd9YW\x84u,\xe28\x0e\xf1\xfd\x8d\\Vv\xa1\xa7\x08p\xba\xc8%G\xf5\xc5R\xa2X\xf3x\xe1y\x98n_\x06\xc9\x961\xa7\xdf\x93\xf4r\xb0\"\xb7\x0e\xa6\x0c\x17\xc5\xf7\xf7\xb0\xe9\xcah\xdfW\xfe\xfamxM\x02\x7f\xce\xdbR~\xab\xa1\xb9\x17At\xf3\x8e^\xd3\x00\x99X?9\x8a\x18L\x97\x0e-\x9e\xb8\xd2\x17I)\x93\xbd\xa4w\x81\x08\xc1]:YMLu=%p\x93Ym\xe1\xdb\xff\x8f\xcf\x06\xcds(\x12\xa2pk\x0d\x9e\x845\xae\xdc\x1b\xa4\xf9\xd5\x0c\x8f\x04\xe0?\xe7ARG\x90\x89\x86X?\xac=\x91\xe4!\x18\xa8>\x97}\xc8xg\x19^\\\xab\x8f\xa6\x19\x1b_8%3\xd8\xaf\x06\xc3\x05E\xcd]\xc6gGA1\x868\xd8b\"\x0d%s\xdc\x89\xe2\xf4\x17z\xc7\xb3\xcf\xe4?\xca\x01\xddC\xfa\x9b?\x97\x01\xd5\xf3_\xf7\xf7\xf0T\x86C\x0f\xa3\x8ft\xc1\xdb\x10_\xd5\x16\xc2\xe8U\xb4Z\x93\xf4=\xdb\xce\xbc\x8eR\xa0\xd6\xf4\"\x86\xdd\xe8zu#@\xa9\x14\xa85\xbf \x84\xbcLOd{\xe5\xf0\xb6\x1cu\x1e\xd3`\x85E\xe4\xfaR\xb6F,\x99g\xec\x0d\x92Ra\xaf\xc0K\xb3\x84\xce_\xabOJ\xb1\xfet4\xe2\xa3v3!\xd2\x8b\xdd\x14\xc1~%\x9al\xea\x8at\xc6\xfc~nc\xc4\xf1\x9a\x8d-Q\x83\xa5\x81\x0f/ y\xeeb\xda\x064`\x97\xd9\xfa\x85K\x1f;\xfb\xc1w\xd1\xec\x87\xfb\x8a\x88\xac\x16\xa2\x83\x04\xb3\xbd\x95\x9e\xb0.ydW\x1f\xad\x86\xf8\xf7P\xd5C\x9c Q0\x14x\xdd\xdb\x87\xc8eC\xec\xedW]\xcb\x04\ngV\x10\xbd\xb6\x85\xe3\xd6\x87\xdb\x95\xe4\xf2\x07H]k\xdb\xef\xea$Z\xca\x1c\x08\xb1\x05\xc3>\xfe\xd5\xbe\x8e\x9f\x8c\x0dmm\x96\xa3T\x8d6wQ~\xdf\x1dU\xc3`m>\xdba\xbf\x18\x87RxP0\x96D\xfc\xba\xbf\x87\x9d\xbd\xad\xed\xed\xf2{\xec0\xdeb\xbfx~\x8a\xbc*+\xdf\xadt=\x1am\x8fF#\xebD\xfef\x9c\x08N\xb1\xd2\x0f\xb6\xcc\xbe^\x14__\x15_\xaf\x8a\xaf\xc7\xc5\xd7\xd3\xe2\xebM\xf1\xf5\xd2:\xac7\xc6a=\xf9\xfd,\xfc\x01dT\x13u\xb9\xe57\xb6\x91\xfe^\x0f<\xf2#cs\xcaE\xbf2Y\xa5\\\xf43\xe3m\xcaE\xbf\x01\x06\x99\xae\x0f\xf2/\xf6\xd0\xebl\x1c\xbej\xe7\xd4\xd1\x84B \x0c\xe5\x0b\xdc\xe9<\xeeG\xfd\xe9{N\x07j\xe5\x8cS\xfd$\x12\x92\x96r\x96TV\x12\x83\xf3t\xde9\xfc0\xca\xb0\xec\xbc\xf8z[|\xbd)\xbe^\x14__\x15_\xaf\x8a\xaf\xc7\xc5\xd7\xd3\xe2\xebe\xf1uU|\xbd+\xbe\xae\x8b\xaf\x1f\x8a\xaf\x87\xc5\xd7e\xf1u^|\xbd.\xbe\x9e\x14_\x0f\xc4\xcc\xcc\x89^49\x1f\xd2\xbaJ(7y\x18r\xba\xaaP\xd9^\xcfv\xb3\xd5\xf9$\xc8\xae\xd2\xbf\xafD\x05\xfaM\xaf\x04f+\xf7\x96\x8d\xfdoZc)\x13\x83\xfd\xc5\xc3\xd4\x0e\x12 \x9f\xe7rd\x1d\xf6a\x01hQ\xcdX\x15\xe4Ya\x03\xde\xe3\xe9\xf2\x92[\xf1vA$\xd2\x9c\xbeg'\xc3\xac\x8f\x88\xe9\x1b\xf4\xdc\xb9P\xc1@\xf4\xb5\x00\xd1n$\x1c%\x0e\xbaq\xa8\x7f2\xb7&\xc6\x85\xdcM\x00\x13\x08\xe1%<\x83\"\xed\xd2o0\xc6\xf2\x9fa\x0c\xbf\xc2\x98\x8f\xb2\x13\xf1\x87\x7f\x871\xfch%m\x7fU\xa8Fu\x85\xe8`\x9e\xadJ\xbc\xb7\xe9.\x84\xdf\xfe\xa6\xd5\xdb\xdf\xee\xe3\xc7\x86\x9b\xd9N\x85!\xe3\xa1\xfd\x19H\xde\x16!\x08\x14W\xd3\xc7\x18\xa0\x1dz\xec\x9b\xfeF\xd9\xcf\xb9\x0b;\xe9\x94\xfc\x17'\xed\xf3$\xc6\xbeH\xdeL\x14\x85\xa3\xd1eY\x80\xb0Q~\x92\x1f)G\xe97\x02\x94\xdcYd\xc0H}\xa6\xd9\x90\x87D\xe3\xd9\x82\xccv\xa8 p\xa2\x9ah6\x9c\xe5\x19H\x15T0\xc5n\x04\xeb\xbd\x0d@\x9e$\xa9\xbe{\x8d\x96\xaf\xe8Q\xfd\xf7F?jM\x06{\x90o\xff\xd8\xf8\xb6\xc0\xed\xc2\xe7\xe51z\xbb<~\xdcuM\xf8\x0e\xb2\xf5_\x9b[\xbfg\xad\xff\xc2\xf3\x04r\xbca\xcd\xfe\xe4|dE\xbe)M\"\xb6\xfess\xeb/\x8d\xad\xb7\xc67(\xcb\xee\xb0\x0fO\x9c\xb3\xb0\xe7:\xd3\xdf\xcf\xc2\xd9\x0f\xee\x93\xa5~W\xa9\x1f\x94\xc9\xb3\x9a|\xe1r\xd9DP\x96\x0c&\x90\xa1\x9aA\xb8U@4\x08H\x92\xbeeo\xf0\xfc\xe0\x7f\xce#\xd3\x0d\xfb\x98\x7f;u\x0d{Z\xfd\xa0\xa8~\x16\xcaP0Ct\xffd$^\xfe6c,\x88\xc9k$l\xf5#b\x0c\xc6\xaa\x0b\xb01\xc1\xa7\xfaam'\xc0\xc3\xbc5O\x04\xc4\xc9\x15O7\x1b\xc6\x0cyJ\x18>\xcb\x00o\x80|\xb6\xd3\x13\xe81Y\x0f\x13\xdc38\x88\n0a_\xc7<\x9f\x1d\xf4\xe0\xcfN\xc0\x85I\xbc\xb5\xb0vf\x8ey \x05*\xfa\xc6J\x9f\x19z\x12\xb7 \xdb\x7fk\xc4\xf6\xc7\x98\xac\xa4\xf9~O~rA\xba\xe0\xca\x85\xa4l\xe4\x91\x84\xce\xb4\xc2\x08\xbd\xe4\x02\xda.\xa0\xe7\x0e\x13\xd7v\xb7F\xc8\x04\xd4\x83\x95\xfa(\x15\xf3wv\xb76\x87PD.\xdd\xda\xdeb\xc26*\xa6\xfepF\xc3Mt`Na\x83\xb7\xce\x93\xc9l\x88\xd7z\\\x86c`c\xbc\xdb\x98\xeb\xbc\xde\x0b\xab\xd9\xde>t\x90\x93\xf9\xe4`Zh:\xf5g0\xe6\xa7\xdc\x1fz\xb74\xf5#\xafSmk\xe6\xf2\x8c\xa2\xfa\x86D \x08\xf3\x92\x95t\xba\xfej\x1d%\x89\x7f\x11\x08\xc7\xf71\xf8BU\xc9\x8d@x \xb2n\x13c\xf7\xd9\xb1\xcb\xf3\xbf\x983K\xc1\xbe\xe4\xd7\xa4\x02\x10\xe3\xafin\x01\xe221)\xc5\x95\xd2\xea/B\xb6\xdfx\x8em\xfd{\x9b\x9c\x1e\xe5\xcf\xd8(\xba\xbd..\x97\xdc\x94\x1b\xfc\xb09\x0b\xbb\xd6\x19\xfed\x14\x84MCf\xb8Q\x90\xd4\x8d\x11\xa6\xf7\xb4\xf6\xf1g-\x14\xd1\x1aAq\xbcV\xc9k\xce\x1bTl\x87UE\x96\xe2CY+:\xae2\x90\x85*\x9d\xc0\x0b\x08\xd8\x1f=\x07\x89\xa2\xa3\xe31)oJf\xee\xa0\x88s\xc0P\xc4\x1b\xe4\xf6\x06\\\xcb\xdd\xf1*5\xba\xdc\xbc\x80aR\x9e9\x90\xd3XY/Z\x80\xfaR\xdeN\xder\xa5#F\xfal\x82.\x95\xea]\x98\x80\x87\xdf\xc7\xd0\x9dt\xfb\xe0\x0dr\xbb\x04\xdb\xb1\xc2\xdaXp\x95\xa8\xb8\x1a\x99b33>\x0e5>N\xdfh>\x91\xf1\xbb\x00\xb5K\xee\x13\xa1\x94\xb03sa\xa1\xe2\x06\x0d\x80\xfaA9/\xa9\xf5\x85\x11-\xca\xf4\x99'\xe8\xf7D\x82\xfe\xc7/1k\xbf\xe0\xfdc \x9eG\xd7i\x82Wo\xfc\x04\xe6i\xc2\x10\x02\x8f\x9bN\x9a\xf2\xb4\xa6\x8b\x19\x9f\x99\xf9\xe41OY\x8a\xc3\xb1\xb6\x8a5\xfe\xb4\xc6&K+\xe6w\xec\xfa\xd1\xffU\xd2\xf1\xf1M_\x95\xd9\xd5\xfb\x83|\xc8a\x9fo\xe5\xb0\x0f\x9d\x11F\xc1\xc9\x7f\x0e5\xd9\x82\x13\xc8\xb1\x847Q\xcd\xdb\x9a\x13?U\xa4}\xc1#\xc4\x95\xa5\xdcjVS\xd6|\xd0\x87E\x1f\xed?\xea\xdeR\x0cAQ\xd9\x91?B\x17\x1f\xf9\xa4\xae.C\x85\x9d\xa3h(\xc5\x8dXqI\x92\xcb\x04\xa1\x8b7f\x85o\x06\x02\xeb\xd1#\xb6\x05\x95\x02T\xdb\xdc\xdf\x83P\x84K\xa5\x02\x12\x86\x97 R.\xfb\xa8*u\x85Z\x8aVn_\xa6\xc1\xcc-\xa0\xdf\xfd!\xa6\x8bs\x86\xe3\x15\xf1\xderQ\x8d\xd3\xc2\xb6;\x9a\xc6q\x08\xba\xf2}\x9eR\xdc\x00W\x97\xaf\x1c\xcf*\xab\xde_\x8aU\x96\xc7\xcd\x04\x9cN\xcd\x96I\xa3!\x92\x9f\xb2r\xb9\xaf.\xb0\xc5\xa2\x95\xdf\x1c\xa7\xc4\"\xe0]V\xeeYM\xb9\xf1\x91\xd6H\x1f\x04y\xa5\xe8\xc2%~w\x9aT\x80J\x0e\xd9\xe2$\xd0\xb4\xa3\x145\xb4\xa8\xbe\\\"u\xf9u\xe7*K\xd0\x92\x80\xc0\x05O|\xc3\x13\x98\xdb\x8c\x10\xa1\xa4b\xe5,\xc4e\xe9\xbe\x8d<\xe72\xd8\xc8E\x95=\x135\xc4\x823\xc8\xf8\x0c\xa9\x1d\x0c\x89$\xae\xb5D\x88\x89p\xca\x18\x9c\xcb\xa9?\x9b\xf5\x05\x8d\xe1\x96\x80\x19O\xcb\xce\xffq\xbc\xc7\xdd\xd5b\x07 \xe4\xc7\xbd\xc1\xbe\x15\x1e\x15L\xf0\x90\x89\xe0e\x1dO,\x1d\xd6,\xe77\x9f\x88 N\x13\xc6\xa8\x8a\xaf\xd0\xc5\x8d\xd7\x93\xaf0\x0e\x83S\x81\xd2\xdc\xd4\xa9$|\x1a\xc1\x17\xf4<.z\x1eC\x97\xe1uo_\xed\xdd$\xedHZk\xa2\xee\x89}&g\xe4K\xda\xe2\x14t\xe4QNG\x90\xc9\xe3\x9d3\xd9\xac\xbe[m[\xb5b#\x914\xec\xd3\xa0y\x9fz-\xf7i5\xa7\xb6\x97\xa3o%\xa7vV\xbf\x8a\x9f\xa0\x00\x8eR\x93\xa0`\xfc\x18\xc2\xbb\xddn\x1fq\x02\x95 S\xb6?\xbci\\`3N\xb63\xe2\x87_\x01\xd22N*\x8dq\x04\xcb\x8a%f2\x96q8\xc8x\xa3eF\xbd\x0e\x17\xaf\xb099\x14R\x1e\n\xb2\xe6Y{lR\x8f\xf5\xee?X\xaf \xeb\xbf\x11\xa3\x9a\xd0\xa9\x0b]\x05\xa9\xeac(\xa8\xa5\xf6`.\x1d-e\xf0~\xc9iRx\x00\xdb03\x93\x98i\xc16\xc5l'4\xd9\xe8\xa8\x84\"D[\x1d\x95\xe4)$4B\x12J\xcad\xa6%1\xc1\xb7\xba\x1b\x0c!\xc4W\x9e5\xb8Xy\xfb\xc2g\xca\xc2\x13\xce!\xcd\x9a\x16\xfd\x9fAF\x1a\xd6\x88\xb4X#\x85\"\x84&\x8a\x90\xf3\xbe\xd3xV\xdeA*1\xf091h\xd8\x8c\xae\xd0U\xb6\x82;Q7\xdc\xb4+S-7\xc2\xbe \xf0\xad6\x9cY\x94\xcc\xb7!\xd7(\x89@\x03I\x93\xf4X2\xd5k\xf4m\x84\xaa*-\x0b\xb98F.\x02\x8a\x9eT\x10-\x801/|,i\x048W$Kz!K/'\x95\xf9\x87G\x8f\xf8\xc5\xa4DbT\xe0\xd6\xc1]+i\xe2K\xca\xab\xc1\xc5N*\xc4\xce\xeeKu=\xfed\xee\xa8.\xd2\xe9D\xb5\xff2+\x03sm\x94.\xd4\x8c\xce\x1d\x87\xc7\xbb\x94-\xa3\xfb\x97\x89~*\xb4\xb3\xbe\xa2\xb9\xe5c'O \xa6\xd1\x80\x98}\xec7\x94\xc0\x14\xa1zO[Xy\x15ia|\xdc\x9c1\xf7ui\xbc\x85\x0fy\xbd\xd4\xed\xf3ce\xe0'<\xb4C\xaa\x89\xce.?Uf851\xc3\xd4I\xa7\xfeL@\xcd<\x12{G\xd5X\x11\x15K\xb8\xc8\xd6y\xc4y\xeb\xb0\xee\xc4\xca\xd0$\xe2dZ\xb9R\xf5\x0d\x97\xa8\x90\xaar-\x82,\x9a\xfa\xd3p6\xabL+\xd5\x98\x03\xe6\xe12b\xbb\xd2\x8fR\xab\"\x9b\xb5s\xc43\x02\xb0S\xe8\x1fUOB\xa9\x97V\xcc2q3\x84\xc8\x03\x85}6GZ\x9c\xb0\x13\x08%\x8b\x85\xda\xcbR\x0e\xf2b\xe7\xe5n\x9fr\xfbR\xaadh\x1f$dA_W\xac\x15,\x96{|\x8a\xf1\x80\xde\xa64\x9c;\xf5}\xc4m4\xc7@\xca\xab\x85'~et_\xe4\xf6\xa3z\xb1Z\x07,\x0d\xe9\xd5\xac\x07x\xd9\xd6q(\xecC\x8f\x9aC\xcaX\xa3\x99\xf3h\xe1\x97i\xba\xd6\x04\n\xe7\x0fo\x12C\x0cq\xd1\xdfS\xc1\xec\xd57T\xd1\xb8\xae \xd9zC\xf3\xdb\xdb[\xf6\xf6\x17\xda\xb1+-l\x8e\xec\x0d,\xa3\xf5%\x8d\xedm\xec5Lr\xe1\x07\xa6P\xebzs\x04\xeda\":\xf9\x16\x98%\x1d\xca\x1a\x83\xc4\xd47~d\xbc\xde\x99S/\x9a\xd3O\x1f\xdf\xbe\x8aV\xeb(\xa4a\xea(Q:\xcfzh\xb2\xc0\x18+\xcd\xceM\x07\xdc\x7f\xc2_\xdc5!{NT\xaa\xf1\x05$\xed\xd1\x9e\x8c\xdcQ\xdc\x0f\xa1\xcb;R\x9d\xcd\xf95\x0dZOO\xd0#\xde\x85X(6\xd1H\xf2\xd1#\x10G\x0f\x0dkS\x8cP\xb2\xdbG\xb6\xa0\xfe\x94'\xf03\xd0\xbe\\\xf4I\xd1O\xf2\x8f\xc8\x0f\x9d\xee\xa3\xae[!o}H\xb9go 2U\xb0\x94.\x92\xd1@b\xfa\xfb\xfe\xe4\xd1\xac\xe7\xeeO\x9c\xe9\xef\x8f\xb8\x95\x04\xae\xfa?>?G(\x86V3\x01i0\x159\xe8\xb4i6\x8fb\x156\xabg\x0b \x9b\xe2\x87\xfc\xba\xd7\x89\xa7\xfe\x8c\xb1\xc9-x\xa6\xf8a\x08^\xf8FnU}\x1a\xb9o\xe4\xde\xee\xb6\xd67rk\xb8\xa9\xf1\x8d\xec\x1e\xde\xae\xa9\x97\xd2\xb9\xaag+W\xcb\x14\xdf\x97\xf2\x93$\x7f\xe2\x87-\xc8\xb8\xe1\xcaL\xdc\x94\xf5a\xdd\x87y\x1f.\xfb\xe8\xc9\xa8\x89\x01\xba2X\xe2.\x0d\xe5w\xa8\xf9-\xafSE\xb5Yl\x8a\x92?\xf4\xe9\xdd\x9ar\x9fh\xa2\xe6R\x06\x950\\\xe8\xcf\x10\xb9+\x03=\x02\xe1\xddK\x1du\x04.\x04\xec)\xec\x8bh=\x1c\x10)W\x1a\xd3\x01Y\xaf\x83;'\xeeW#>}6\x0c\xf0\xdc\xech\x8f\x16\x12\xb0\x01\xe6\xfc\xedJ\xbc\xa0Kn\xb7\xf2R\x90\xa1P\xdei\xa0\xe8\xc0Z\xb9f\xcf\x16\xad\xc6t\xa35\x97dC\xa2\xb8\xb3t\xbbj\x01\xce\xb9\x9ac\xe3\x90\xed\xe0Z\xb59\xec\x83\x08\x05\x1fe\xa9s\xd3oa\x94\"A\x91\xc2\x068\x08\x0f{\x00\x88%L a\xdc\xdaB\xbep\xed\xd6\xf3s\x00ga\xabn\xdf\x06\x88\x1cZ\x1d\xad\xe7\n2\xa0Av\x00\x13\xb8`\xaf\x8c\xf9\x9d\x8e\x8a-5 M\xdf\xe3m\xd3\x1a\xe81\x97\x01\xea\\\x0bz\xb6Bl,$^f+\x1a\xa6 \x0f\xe4\x9f^\xfaI\x1fo+\xa8Ei\xc2^V\x90\xad\x10\xbf\x9b\x97\x0f\x14t\xe5\xbd\xd4\x91\x80 $\xab\x02fkmC\x9f\x1d\xd3\xc2\xb3\xd1-]u5\xea\xcd_8\x97m\xe4\xf0\xfa\xc6BSyG\xd7\xa8\xdb\xaf\x8cT{r`\xaa\x0bF\x85\xee\xefQFrB\xae\xfbA:\xd9a\xe7-\x99\xfb\xe1\x92g\xdap\x18\x95\xec\xae\xc8\xedo\xc4O\xbbty\xbb\xb5PS\xe5~p\xa2{#\x97u\xff@ *\xdd\xeb9\xe1-]B\x0f\xab\xac\x05\x82\xe43\xa1\xaf\x0f\x9d\xd8\xa9\xc4\xcd\xccs\x08\x15\x0c\":`\x8c\xc1#\xe1\xe3\x94\xcd\x0dH\x02\xb9|\xd9\xa9\xd8O~\xd6\xef\xd0\x1a\x80\xc6\xa0]\x14\x14-\xba\xe7\xe7\xd8\xfe\xf99R\xe4\x7f|\x86I\x15LZ-\xa89\xe8\x16\x8fC\xe7l?s\x1di\x15\x85\xe2`\x9f\x81vw\xe8\x0e\x16NUp\xee\x832\x0c\\\xbc>l\xba.\xeb\x7f*\xc3\xd9u\x1c\xaa\xda\x8c\xa1\x9aM\xe78\xd5\x14y*\xd5G\xcd6\x9e\xb0*0\x8cl\x87\xa8\xebK%\\\x8aFx\xf9\x9c\xd0\x1cM\xd0@\xf6\xb8\xae\x06\xad\x9a\xc1\xfe\xe33\xbf|\x19\x8b\x83\xa6\x82z\xde%\xf5\xae\xc6\x8aEv\xebM\xab\x92\xf5\x02\xe5\x8b\x8d\xdb\x82\xe8\x1b\x8f\x1d\x0fC6\xf0:\x0f\x1b\xd9\x97\xed}\xde\xdf\x18\xc7\xff\xcc}\xe0~oV\x1a2p\xed|E[\nx\xab2\xb4\x90\xad\xf7\xb4I\x88\x9d\xad\xbd-m\xdc\xa1\xa7\xba\xb0C\xa1\xb3]\xad\xcd\x07\xfft\xbbZ=\x10\xe5\xd5\x83\xc0\x13\xbdVG\xb9\xe0\xf5w\x86\xa5\xd3\xf0\x99\xf2+\x1a\xf8![\x1a\xa7\x82U\xeb\x1a\x19Z\xf8\xe1\xfc\xf5\xf1\xfb\xa3hN\xc7Ui6\xa6\xe1\x9c\xc6c\xf0\x07\xfc[e\x92\xe1*\xca\xc24\xd7\n\x1d\xa4\xbc\x11\x7f\xa0\x7fR~\xfb\x9a\xc6\x89\x1f\x85cH\xaa\xad&x\xc3v~\xc1\xe8\x05\x9d\x7fZ\xcfIJ\x931d\x83r\x89\xe15>\xd2\x93\xec\"\x8d)}\x1b\xa6\xd1\xab(L\x89\x1f\xb2y\x14\xc2\xabB\xa1\xf5\x91\x1a\xcf\xcf?\x1e\x1e\xbc:=\x7f}\xf8\xeb\xe9\xf1\xf1\xbb\x93\xf3\x9f\xde\x1d\xffx\xf0\xee\xfc\xe7\xe3\xe3_\xce\xd1CWk9e\x7fM,\n{\xbbU\xc5\x8ar>\x87\xe7iL\xa9.i\xf8\x92\xa6\xaf\x82(\xa1I\xfaV\x10\xe47q\xb4\xe2\xab\x12\x0f\xccO5\xba\x16\x8aK\xc6*\xc8\xcaM1\xc3@\xb9b\x18\x88e\xa0\xf3|\xcc\xfc\x02\x921\xfbR/\n=?`\xcb_\\h|\xaepH\xeboAL\xf6\xf6\xaa\xd1\xca$5\xa9\xeewNM\xf6\x9e\xea4u\xac\xbc\x1a\xdd,\x13\xe5U\xaa$\x88\xe1\xd3j\xbf\x81(\xaf\xf6\xcb\xe9\xc9\xde3==\xa9\x11\xc35'3\xa3*Y\x9a\xf3\xf2\xcd\xea\xe1w)\xcaG\x95\xf2kQ^\x9d\xeeJ\x94W\xc9\xe4R\x94W\xc1p'\xca\xab`\xb8\xe0\xe5[\xd5\xf6\xcfEy\xb5\xfd\x1bQ^\x9d\xef!*\x18\xdb\xf0n|{6\xc4\xce>D>\xeeP\xb8p/\x07\x87\xd74L\x0fW~\x9a\xd2Xl\xf0\x8f\x94x)\x96\xbf\xf3\x93\x94\x864vVn^\xf7C\x90-\xfd\xf0\xe7\xecB\xd4V\n\x8f\xe39\x8d\x1dR\xad\xfb)\xf5\x83D\xd4.Q\x0bga\xab\xcaj\x9c\xc6\x84\x91d\x12\xa0\x80\xde<\x82\xe4\xc7\xbb#\xb2\xa2\x9a\xfbC\xf69\xf1W\xeb\x80*\xd5\xc7pS\xa72\xecs\x18\xa64~G\xc9u\xb9v\xa6\xaf\xfd\xea\x92\x84\xcbrMCv\xb3\x13\x1a\x94\x07<\x86s}\xcd\x1f\xe9\"\x8a\xe9\xdbp\x9d\x95\xab\xd7]\xb4>#d~\x8e\x92\x02\xb8\x020?\xb1\xb5\xf3\xbd\xbc\xf8U@\x92\xc4\xf1\x8c\xf5O\xe9mZ\xa9|\x89\x95_\x1f\xbf\x97\xd7T\xa2\xaaR\xf2*\n\x17\xfe\x1235\xb4\xab\x99\xb4\xaey\xc1\x17}\xb5f%\xe5\xb1\x96\x0b\xdf\x10/\x8d\xe2\xbb\x16\xb1>\xa5\xc2\x81\xde\xc0\xba\x1a\x98\xb2\x80\xa68\xcd\xf3\x0d!\xc8\xf5iL\xc2\x84\xf0\x1e\xee4\x15\x7fd\xbc\x80\x1f.O\xd2\x98\xa4ty\xe7\\c\xa5\xda\xd8\xc3k?\x8e\xc2\x15\x0dS'0K\xf3\xf8\xed\x8b\xc8\xbf\x99F\x08\x00\xfb\x8cw\xa9\x03\xa8Kb\x9flxY\x1c\xd30\xed\x8eu\xf7 \xbc\xca\x9c\xa6\xc4\x0f\x12k\x15?a\xac\xcf\xdcV\xe7\xd2\x9f\xcfih\xab!\xfc\x02mU\xae\xe8]r\x19\xc5\xa9\x97\xa5\xd6\x01\x05\xe4\x82\x06\xb6\nq\x14\xd09M\xbc\xd8_#\x07e\xa9J\xb24\xf2\"FMRj\xab\x87\x92\x97\x1d\x06\xf4vM\xc2y\x03\x9cH\xb2\x8e\xd6\xd9\xda:=zm\x9f\xde*\x9a\x13{\x05\x19\xb5\xbc\xb1R\x82d\x8c-\xaf\xadj\x14\xfb4LI\x13,\xf1\xce\xfa2\n\xe64\xb6V\x8bi\x92\xd8\xc1\x14S2\x8f\xc2\xe0\xce^\xe7o\x99\x1f\xdb\xdb\xe1\xd3k\xa8\x13\xc5\xd6\x1drM\x82\x8c\xae\xc8ms\x1d\xdf\n\x1d\xac\x13F7\x8duRzk\x1d\x10I\xa3\x95\xef\xd9j\\d\x89\x15t\x81\x7fm]\xef\x98\x06\xf4\x9a4\x10\x0eF\x7f\x16\x0b&\x9f[j-crqa\x87?\xa3\xc2\xd7\xb8]i8o\xe8\xd4\x8b\x02\x8f\xf1\xe1\x0du\xd0P\xae\xa1N\xb2&\xd6\xe5\xf2\xa20\x8d\xa3\x06\xca\x884\xe6\x82\xce/\xac\xe0F\xcf\xe8\x15M\x12\xb2\xb4\x82}\x11D7id]8F\xf9\x82\xa6\xfe\xa2\x9b\xd0:\xecu\x94\xf8aB\xadP\x8c\xa3\x9bFH\xc7\xd1M#\xa4\xe3\xe8\xa6 \xd2 M\x13\xff\xef\x08\x99R\x8d\x8a\x00\xf6\xfa\xf8\xfdA\x9a\xc6\xfeE\x96R\xc6\x1a\xb2s\xaf^E\xf2\x1dy\x8d\xbc\xc2W\x9c\xc2\x8aFgX\x95V\xc4\xd5\x81^\xa3\xb3\xb7W\xad.e\xb0\xaap#e\xb0\xaap\x83q\x08\x9f\xf5a\xb4\xd5\x87\xcd\xbd>lmV,[\x990\xb6\xb9\xa9 \x14\x1d\x0d<\x12~J\xe8\xeb\xe3\xf7\xa8O@\xde%\xf1\xd9\xcc\x91\x0fE\xbd/O\x11Q~\x19\xc5\xb5R\xda\xfcjS\xf3\xc8\xc3+\xda\xf7\xd1\x9cb3\xb2\x00\xa4\xc3\xa0,\x18\xa8U\xab\xca\"~\xd3Zm\x9c\xf1\xae\xd5\x01\xb2\x07\x1d\xee\xb2\xe7\xd4\x0dk1\xf5\xbbHv\xc1V\x9f\xb8F\x05\xcaz \x14C\xac\x06\x9a\x07\xbd\x0dS'/u\xdc>\x8c\x86.\x8f\xe7\xa7\x11?+cu:\x1e\xc8HT\x0b\xc0\xec\xbe\xec\x0b\x86\xe4\xabL\xf6Z\x13\xa6{\x95G-\xc5t\xbc\xaf\x84W\x03\xe35K\xf5\x96\xdax\xd2\x17\x85\\\xa1\xe3\x00\xd9g}I\x12:\xffH\x97~\xc2\xf8X?\n\xe5\xb6\xd0Vg\x9f\x8b\xec\x82\xf1zc\xe8F\xa1\"\xb9X\xbc\x10<\xb2N\xb3\xb8\xfe\xca+^^\xb7\xe5\x87\xfa\xde\x96\x9f9]\xd3pNC\x0f\xd9\xdai7\x8d\xd6*\xda\x86\xf3n\x1fX\xe1/\xf4\xee\x03\xe3\"\xc4O\x862b\x98\xf8\xfb\x03IR\xda\xd5$\xe5\xab\xf7\xea\x95\x9a\xffN\x80\xac\xce\xa1\x1d,\xcbo}#p\xfe\x18d\xb1\x80\x92 \xb2\xaf\xa3\x9bP\x0f\xe7_\xe8\xdd\xa7\xb5\xf8\xfe>\xca\x12\x8aU\x1f\n\xe7\x93\x94\xc4\xdf\x0be_U\xba\xf9\x02X\xe3{\xdf\x15\xdabd\xff,xs\xc9\xf6\xfb\x03\x9c\xf7\xf3\x05\x10\xe7/~W\x90\xcb\xb1}C\x98\x97J*\xe3\xbb\x13\xaa\xbe\xbc07\x9b\xba\xd0^\xa5I{r\xad\xb2\x83[C\xe7C\xb3ZD\xd7r\xf7\xa2G\xc5\xab\xf2\xe1\xabk\x18gim:o {\xd0D\xd3S\x9b\xe3\x105\x19\xa8\x97@k\xa9\x84ki\xb7\x00\xd7\xc4\xac\xb3F0j\xb2\x1c\xd7ymhL \xafe\xde\xb7\x01W\xa0\x94G!:1\x05A\xe9\xceIJ\x90\xbbIa\x02\xe9\x80\xfd\xac\xdeI\x14#b]\xdd\xe4,Y}t\x87\x92\x8f5\x84\xa6\xcd\xfa\xba\xd8\x0e\x1e\x86l\xb3\x99FC\x13^\x82\xbaT5\xf2\xd6\x18\xf3k9\xa8\x9e z\xe39]\x17\xec\xbczX\x07\x87\xe1\xbc}\xf3\x82Z<\xac\x07\xfeR\x13\x9d\xe0\xd7O7\xdc\x96\x10\x85\x8fG\"J|u\xb8h=\xd7df\"1M\xd9\xc4\"\x92\xd3\xa3G\xca\x8e-\x07\xba\x16\x031\xf7\x8e\xab\xe1\xf6AI\x18^\x16\x08\x00\xf9a\xf6.\xc6q\x17\xe1{kMp\x1c\xab>:\x0c\xd1j\x8f\xe7\xa9c\xf2\xcd\xcd`I\xd3\xd7$%\x8e\xcb\x81\xb3\x0f>\xdawEQ@\xe7NTu\x05`X\xbd\xc0,\xc4E\xa5\xac\xd8\x03udO\\X\xf0]V\x8bsbp\x05\x95\x97\xd9\xe7Z\x7f\xfb\xdc\x92GDH\x91m\xb7qn\x8c\x07\xc4\xf3\xb2U\x16\x90\x94\x9e\xdeD\x1f\xd8\xf1\xfb\xdaO\xd6x\xf9\x9c\xe0E\xca\xc2J\x8dn\x1b\xf6;\xa9\xcf\xbf\x83\xd1\xa2\xe6U\x13\x9fo\xb6\xe3[m\xc7s\xa7\x1a\xb0F~\xda\x1c\x1c\xf2\x93\x1fF7\x97\xbew\x89\x8bp\x0d\x13\xbe\"cp\xee\xc4u\xd8\xaa\xa9\xabBd0\xf7\x95\x1bv\xe3\xfa\xea\x1b\x04\xe5&\x02Q\x1dc_\xdf\x15C\n\xf5\xef5\x86\xd9S\xf6]3M\xc1\xad\xdc\x82\\0d\xb81\xad,:5\xd4\x17\xb6\x88\x0c\xd7\xf1\xd8\xdc\x04\x07cj\x05\x14\xc0)\x1b\xbb\x11z\xfe \xa6\x01% un\xdc~~\xe0\xf5\x0d\x01,\xf5\xae\xce\xeda\x06\x0fBu.O\xb6Z\xabo\x8e\xe1\x8f\x1eA\xa7\x85iD\xe5m\x87\x0e\xbc4\x0e~\xa1w\xb8\x1ayJ~\xd8\xd0\xd1\xa2\xcf\xd1s\x80\xf2\x83\xf7\xba\xf9\xbe\xb9t<]XD\xa8\xb1\xa8\xf8*\x1b \xba1\x8b\xdcQ\x1a\xda\xd6HX\x01J\x810\xc1\xaa\xac\x96\xbc\x0d\x1d\x9c\xdf\xc4d\xbd\xa6\xf1I*\xb2~\xa4\xe5\"\xf3\xd5\x01gT0\xd0\x980\xd7\x0d8\xaf\xd3\x0d\xb3\xd5\x05\x8d\xf3\x95c\x0b`\x19\x0b(\xacw\x97\xe7\x8c\xc3\x03\xcc\xdc3`\xf4\xb5%Ms\x93TG\x9cyn\x112\x17\x1d\xefk\x15\xb4+\"?\xfa{\x8dz)\x9eB\x81\xd1\xe1D\xafp}\x8f\xa5_)*\xef=\xd595\xab)\xde#q\xa4\x8a$\xe2V\xb4i\x197\xd5@\xe0\xf8\xe5\\L\x17\xf5\x85\x928\x18\xd60\xd7\xe2\xce\xaf\xcfV\x00\x13\xa0\x0e\x0f8\x92]\x04\xbe\x97SMd\x02\xe2\x01\x99\x17n\xa8\x07\xc9G\xba8\x8d0m_\xbf\x1ab\x0bp\xe1B.\xc8\x0d\xce\xa3\x9b\x90Vc\x96\x16K\xc8\xc4\xb7\xe42\xca\x02!\x06\xb5\x81\xa6\x84I]r\x03\xa9\xae\xac]a\xe4\xd0\xa7\x06\xe8c\xb9\xc8\x86\x16\xd3\x85LL)\x86_\xbf\x0f\x89\x8c\x03\xf0\xb5\x03P.W\xecX\x90\x13\xcb\x94\x8f\xc3\xc7\xafb\x1c}\x08\xf1m\x0c#\x9eG+,\xde\x8e\x90\xc0\xf1\xbdY\x062g\x89\xdb\x80\xf7\xff5\xc8\x8a<;\xe2fLW\xd15-\xa3';\xf9\xbf \x82~\x075\\)\xe2\x80Q\x03iP\x8a\xfc\xe6\xc1^\x0b\x13G\xedR\xa7\x91Xh\xf3\xfb\x1e\xe6\\\x9a@d\x89\xfc\xe2\xac\x8d\xc1V\xd8\xe73_\x81 W8z\xe6!\x8b\xf0\xa0\xfb\xfb\xe0\xb5\xc4\x94\xb9h\x16D\x92\xe4\x04\xc6|\xb05\xf5G`\xb8\x96\x07\x19uD\xb4\xe2Y[\xf1,\xad\\WlZ\xc9\xa0 P\x88\xd0\xb8S\x0ds\xc9ov\xf0\x9d\x80S'V\xcc\x17\x0c\xd3`]WVq_\x17\x95\x17\x04dV\xfa\xd1 \x81\xc60\xca\x96\xd1\x08\xd0\xaf\xca\x83\xa2\x9c\xb6\xb3\xe2\xbc\x7f\xf6\xab:\xa8y\xd9\xce\xa98D\x95{\xa9\xeb>\xac\xf8&w\xfb0e\xbf\x1a \xa9\xfe\x8c\xcf\xb0\xf4+\x0f\xd2Z\xf4\x1bv\x8e\xca\x00+~\x14\x0e\xde\x7f:9=\xfftrx\xfe\xe1\xe3\xf1\x87\xc3\x8f\xa7\x7f\xad\x9f\xafj\xf5\x9f\x0fN\xce\x7f<>~wxpt\xfe\xeb\xc1\xbbO\x87\xf5c\xb7Z\xfd\xe8\xd3\xfb\xc3\x8fo_\xe9\xaag\x9a\xea\x1f\x8eO\xde\x9e\xbe\xfd\xf5\xd0\xf6^\xa2y\xef\xf8\xd7\xc3\x8f\xef\x8e\x0f^\x1f\xbe\xb6\x0d0\xd0\x9eR~\xf2*K\xd2h\x95k;\xc6\xf0\x91.\x0fo\xd7J\x94\xfc\x94&\xe9\xe0\xc2\x0f\xe7NHo\xc4c\xa7\xfb\xbb3')\xb9'\xb1O\xdc\x0d\xcc\x01\x14\x0f\x0eNO?\xbe\xfd\xf1\xd3\xe9\xe1\xf9\xd1\xc1\xfb\xc3\xf3W?\x1f|\xc4\xbc@?\xfc\xb9\xab\xcb\x1ao\x0f\x85\xc1><\xb3\x8e\xd6\x07\xb9x\xfc\xea\x92\xc4\x185\xd1R+I~\xa1w\x96\x1a)\xc6\x1c3=\x0e\x82\xe8\xe6M\x16\x04'^L\xa99\xb6\x0c\xd6\xc3\x08%xjx\x96\x0e\x03\xcbp\x13\xcb\xa3\xbb\xd03w\x9f\xa5\xd1+\x11\x12\xc3\xdcD\x96F\x1f\x02rglE\\\xec\x9b\x9f\xd3 \xf8@\xe6s?\\\x1a;auN\xd6\xc4\xb3\xd6\xb9$\xf1\x89e\xd5\xbcK\x12\x04\x14-\x1c\x8c50\xb4\xc7\x18\"\xb87\x8e\xd6\xb7\xc0\xc2\x0bH\x92\xbc}m\x7f\xceYLS\x8d(H\x8cA\x89\xbc\x88\x01\xc1\x8cV^\x14\xa64\xb4@\x80??\x9c\xfb\x18\xe8\xc3^\xef6}O\xc3\xccZ'\xc6\xc1\x9a\x00%*\xbc\xf3\x13\xdb\x88\xa2xnFO/\x8e\x92\xe48\xf61L\x92\xa1\x0e\xb7\x0c2?\xa4\xa7\xbe\x05\xdey|\\\xc3,\xe6t\x81\x81 \x0dO\xfd\xd8\xdc\xb2\x08\x96c~9\xba \x83\x88\xcck\x91 \xf3\n1Y.\xad\x0bEC\x8f \x04\xc6\xe7\x8b(^Y\x1f\x1e\xd8\xe9\x14\xabr\xd8\xa2\x8f\xf74\xbd\x8c\xe6\xd6*G\xd1\xaf$\xf0\xb9\xff\xa9\x01 \xac\x1a\xe7\x0f\xcc-\xc5dE\x7f\x8cb\x8c\x16i\xa8sI\xc9\x9c\xc6f\xa4\xba\xa4\xfe\xf2\xd2\xdc\x05\x0f`d\x1c\xe4\xa5\xbf\xbc4\xbf\x1b\xd3\x85\xf5\xe1;b!`\x97\xe9*x\x13Y&\x96\xa6\xeb\xc3\xbfe\xfe\xb5\xb1\x86\xefY\x16\xd37/\x10\xden\xbd\xc7\xf0\x8d\xc6\x1a)]\xc6~j>\x81|3\xc4\xaf\xe8\xdd\x07\x12\x93\x95\xb5\x86\x15\xc9\xae\xfc\xd0d\xeet83ov*nd\xd9$e\xba]D(4\x7f2\xec\"~]\x19\x95\xea3\x08a\x08|\xda\xd7\xed\xbe\xca>3$WK\xbe\x052\xd5\xd0C\xe4\x87xVE2\x11\x9b\xf4\x99>?\x84.\xd9L\xac\xac\xe8\xa40\x9d\xe7\x89x\x04\x85r\xbas\xff\xfa\xffa\xefM\xdb\xdb\xc6\x91E\xe1\xef\xf3+`\xde9ij,)\x96\x9d\xc5Q\xe2\xf6u;\xce\xe9\xdc\xc9\xf6\xc6N/\xa3\xf6\xf8\xc0$$\xf1\x84\"8\\d\xbb;\xf9\xef\xef\x83\x02@\x82d\x81\xa4lgf\xeey.?\xd8\"P\x00\xb1\x16\xaa\n\xb58\xfa\xbe\xb7\xb9\xf2\x1e\xfe\xfd\xb7\xf4//\xdc\xdf\xae\xb6\x07\x0f\xf1Q\xe8\xa5\xdbX\xbb\xca\xcf\xc5\x9a\xa2\xee\xd6\x04\xd1DL:\xfd[\x91\x8ab\xf8\x8af\xde\xd2M\xdb/>\x01Ug\xb3\xc9yU\x1f\xbc9\xf1\xa8yVH\x94np\xe0\xd6u'\xe1\x82\x1bkd4\x0e\xa2\x88%b\xbb\x08\x9c<\x9b\x9c\x93m\xc2\xc86 g\xbb\xc8\n/B\x1a{\x00\xbds\xfe\x9cx\xa3\xd1\xf3\x81\xd4\x0c\x1d\x874\xcd`\xe1V\x17\xa6\\\xda\xd5O\xb1\xe6\x90\xce\xb5B\x98\x9a\xf4\xf4\x87\x9b3\xba\x80H\x0d\x8e\xf4\xb7^?a\xe7:`\xb3\x8c\x16\xadgkH\xb8;\x1f\x8c\xe7<9\xa1\xde\xd2\xcd\xeaF\x80E/br \x83~\x81\xfa\x89\x1b\x8d=\xd1x\xb1m\xd3\xc1s\xb3?\xa2\x87Z\xdfQn\xe42\x0f7\x99,\xf1\xfc\xd7\xfb\xd8\x7f\xfb\x96\xcdm_\x82\xaa\x1d\xedkT+7nI\xcd\x1cTC\xb7\xaa\xd0x`\x86#~\xf0\x808r\x06\xc05\x03T\xb2\xe5:)\xcb^G\x19K\xd64\x94\xe9\x83\x8a\xde\xbc\xa9\x13)p\xb3 \xcd\xe1\xf3r*\x82\x14\xfe\x8b\x06\x8bO{4\x0c\x19S\xf5\x83\xa9G\xc6V\xaa\xda\xea2\x13%\x0eI\xa3\x12 \xa2\xc0\xf6\xbf\xdb\x98\xa3\xdc\xaf6\x7f b'\xe1\x0d\xd5c\xb7U\xd5n\xb6\x85r\x86\xc3\x08\x16+20\x99\x91\xad\x0c.\xc1x\x81\x8c\xc8\xa4\x18 ]\x1c\x9d\x9c\xb1\x1c7\xa3\x9ez(\xf9AK\xbc=\xb5.d?\xcb[v\x18F\x15\x87\x1d\xc1Jf\x9c\xbc&UX\xec\xbaH\xef:7\x13[U\xfa\x9e\xe0\xe4\x05\xc9\x9e\x13\xbe\xbd= \xd1\x8c\x9f\x8bI\x98q\x04\x05i\xf5\x9c\xe6\xdcO\xc9\x8c\x9d\xdf\xef\xb6\xb3\x1c{XP\xa4\xbb\x1ec\xa0\x13\x89h\xed\xcd&C\xf2\xdd\x0b\xc9\x1f\x16\x02\xec\x03'Kr\xe6|\xff\xdd\x908/\x1e\xca\xcc\xef\x9d\xf3\xe6\xc1(J;/\x80\xb1\xfc\xde\x01`\xf5\x1b\xf1\xf4=\xdb+a_d\x97\xdc\xbf\xf9\xfeE\x96\xe8b\xc9\xf7/\x1e\xaaDK\x1d^\xd9\xda\xf5\x82\\\xaf\xc2(=\x00\x8eo\xfa\xf0\xe1\xd5\xd5\xd5\xf8jo\xcc\x93\xc5\xc3\xdd\x9d\x9d\x9d\x87\xe9zQ\xb4~\xbdhT5G\xa9x\xe7/\xceT\xf6\xe8\xf0\x85\x1f\xacU\xcb\xe0\xd7y\xf38\xa4 \xa3\n\xfc\xc5\x8a\xc6\n\x1a~!\xd0\x1e\x0f\xa7d\xb6\xdb\x1c\x01\xddi\x8f\x87\x8b\x84\xe7\xba\x9e\xe2\xd56\x1a\xe2 \xd9\x82E\xben\xc4<`\xa1\x9f\xb2L\xd5P\xbe\"%c\x9a\xd0\x95.(1\x8b*\xa6_\x90BY\x82vAM`\xeb\xdc\x11y\xb7\xb0\x90\"wDn\xcacy\xad\x8bdyT\xe5!l\x92\x1e&4\x13\x9a\x84\xe7\xcc9\xcf\xf0\x9c%\xb3\xdcog~#\x08\xa0,0\xad\xbb\xa7,w\xfa\xcc\xf1\x82\xc4\x0b\x81\xc5\xf5\xc2 \xfe@\xb3\xa5\xf8\xed\xb39\xb8n`a\x18\xc4)d/\xc4\x9f`E\xa5\xaf\x07\x08\x80\xa2\xfe\xd3\xe4?\x13\xea\x07,\x02-\xdd\x15M\xc1\x03D\xac\xaaR72\xf0\x93\x877\x0b^\xfc\xd4u\x88\xc244\xebHddJ'\xcd\xb8\xf4\x0d\xc1\xae\xa5\x060\x84;8/(\x1b\xfba6\x07\x0f>\xc4\x1b\x12*\x7f\x99\xc1xk^N:i\x88@\x9c6\\\x9e\"\xf3\xda)\xa2N?p!\xe4\xfcEpV\xd4\x02\x11T\xe8?\xe7/\xa5m\xb5\xf3\"\x0c\xa2\xcf\xe4\xe1\xf7\x0e\x99\x12\xe7\x85\xa3HP\xe7\xfb\x17\x0f\xcb\xdfN\xd9\x95`<\x0f\x12M}\xa9\xe4C\xd9e\xd4\xd3\xed]\x0f\x01T\xc8`Qwoe~q\xe1BO\xeeW\x1f\x9d\xb8\x82(\xe6\x83\x99\x80\xab\n%\xfb\xd0\x0e/\xa2>\xac$Nl\xde\xc1<\xa2S,\xd1p@\xa3\x19\xc9z$=-\x97\xa8\xcfI\x8eK7R5\x85x\x9c\xc1\x86\x02\xa6\n[\xfa\xa4\xce\xbe\xaa0\x83\x0dW>\xb1\xaa\xbe\x9e.\xe3\x0cN\x1e\xd7;+\xe3\x0c\xee=\xae\xc3\xaf\xf1\x15\xa5\xc2\x0c\xee\xd4;\xab\xc2\x0c\xee\xd4 \x91\x1b\xd5\xfc\xfa`\xaa0\x83\x0d\xbb\x8d\x0b)\xb5\xd9{6\x18B\xb8\xc4\x9d\xba\n\xa4\x8a7\xd8\x18\xbe\x13U\xf0\x11\x14\x9c\xf8\xeb\xebB\xa2`r\x0b\xa2\x85\x16{\xf7\xa8\x10\xf9;\xe4l\x19\xa4D\xd0\xf6\x82c%W4%:L,\xb9\xbc!\xff%\xce\xa9H\x9cS\xff5Fn6\xfed\x7f\xd3\x1f(Ka./\xde\xa1'\x83\xb4Z\xfd?36\xbe\xc8\xe8\xe2\\\x1a\xd7(s\xcfl\xac\x97\x85\x1e)\x99jY\x0c\x8a\x1fu&{O\x1dA\x1d\x88\n\x87\xf6\xc1?$\x0e\x81\x0btA\x8f\xa9\x91P\xaa;\x84\xcf \x9c\xda\x96\xb2\xe5\xc0\x8b\xe1\x1a\xc3\x91\x0f\xf6\x89]M\xb4uO6\xfc\xc9\x0eHu\x11\x9b\xd9\xb6\xfa\xce\xc0\xa3\xa4\x15B\x8a\x94\x9fL\x9cA\xa5\x81p\xcf^1\xd158\xf72W\x14\xddu\x86\xb0\xec\x07\xed.M>\xb6x\xdc\x90N\xb6\x133P\xfd\x15\xea!\x19\xf1\x88\xa8m\xa6\xd9\xf8b \xa1!\xda[\xe4\x05\xac\xf2\x07\x0f\xf4\xcfRN#h\xb6\xd7`\x99#a\xa6\xe2W\x87 \xd3\x91\x9b\x0dI\x00>\xb2\x16L\x06\x8e\x85\x88\xc7\x1f\x19\xf5o\xdc\x81v\xa6\xe5\xbe\xc4\xee\x0e\xa0QQ\x9aM \x12\xeb\x99\xa0\xb6v\x16\x97\x9a\xa1:3\xa6\x88\xdf\xe7\xafVKQd\xb6^6\\ \xcd\xc7q^\xc6\xc1\x05\xe7\x92\xa2\xcd\xca\xcfd\xbd\x85*Y\xb7\xa7}i\xbci|l5\x8ey*G\xf0g\xe9\xca\x02\xbe\xd8^\xcd\xa7F5\x97\xb7\xa9\xe6\x1f\x8dj\x16\xdd\xd5\xe8_b5\xbej\x1ca\x19\x8f\x8f.y\x02w\xd3\xe2\x7f\xed\xcc\xcbx|L#i\x0e\xe0x4\x8aCzc\x05)\xfc\xe1h\xc8L&4\x0b\xbc\xcc\xe5|\x1c+\x0f\x85\x8e\xaf\x12<\xcc\xab`\xc6\xe3\x93U\x9c\x05\xe0K\x90\xc9_\x08H\xe4%7q&\x81\xf4o\x0c\xccW >\x9a\x9d$p\xa3\x0e\x91\xfd\x9a\xd9o8\xf5\x99/\xfd\xd6:!\xbc@\xc8\x0f\x0b\xe0[\x96Q\xdf\x04^\xa9\x04\xbc\x80\x8a\x9f\x04\xb0)\x12\xe4\x08\x1c\x96\xe7\xa9\x18\xb0X\xfcG\xb2\xe5L\xe1\xd3$2\x81\x88\x80\xfc Z _$\xa0X\xe6\xc4\xeag\x13\xe8#\xcdX1s \xcd\x98m\xd6N\x19\x03\xf3\x0b'\x85\x1f8\x80lQ*\x7f! \x19\x0d\xa5\xcf\xc9T\xfeB@\xf24\x06I\x8f\x93\xca_M\x90\xb3`\xc5t\xb4$'\x0bV,\xc7B\x1ae<\xfe\x89\x87\xf9\xaa\xec\xdd\x1a^m\xfd\xfb\x99\x06\x99l\xfe\x95\xfce\xd0\x11\x18 \xf6{c\xff^\x8f\xb3\x84z\x9f{\xec\xfd\x1f\x1aeK_\xcb\x82\xe0~\xfdR\x1f\x98{\xf5\x8b\x1a\xb1\xf3\x199 \xea3\xd5\xcc\xc2W\xbe.\xfe\xc8)<\xf4ft\x81\x1du\xd2\xd3{\x00\xba\xfb\xd6 ?\xeap\xc6\xdd\xb5\xcb\xeaMW@\x05>\x06\xb9\xa9/\x86%\xfeA\xba\x1bU\x0e\xdc\xd4\x1e\x01\xb9\x8f\xfc\xcf\x06\x96k\xe0\xcb\x84\xd1\xcf\xcd,\xd9\xb0u\xe03nm6\xcd\xfd\x00\xcb%\xa6\x0c=+]a\xdb\xfbp>$\xaf\x06\xe4U]\x1e\x93\x01\xb1\xd7Vx\x1c\xe7\xe9\xd2E\x86 \x1b\x92W\xb3\xec\\t\xdcB7\xb7v\\j\xac\xdd\xef\x8c\x9cH4Y\xe0\xcb[\xceI\xb0Z|\xf3v\x0d\xc9\xb7\\Us\x9e\xac\xee\xb7\x0b\x1f\x19h\x88\x11'Q?Z\xbap\x9a_\xae\x02)\xb4\xd4\xbfn\xd7\x8d\xc0\x128E\xad \xe9*\xce\x1a\xd7\x8b]g4a\xf4~\xc7\xe1\xb5\n/>\x14\xad\xd3?\x99=$\x01\x82;\x7fj\xe0\xce\x1b\xa0\x9b\xe4\x89\xd0\x87p\xfa\x11\xe5\xfd\xe5%\x07&k\xb8\xa4\xe2\x94Fs\x12<\x1d\xae@\xb0\x0c\xb6\xba\x14\xc7\x1f\x96\xb5\xb4\xd4\x15\xac,\"\x90@\xc6\x14\xc5\xb2>\xb3\x9b\x05\x8b\xf0\xbc0\x88>\xe39\x82\x9e\xc1s\xd4\x1d\n\x96\xa5Ug\xb1<8\x0e\xf1\xac\xab\xcbN\xe1\xcd\xcf\xe84\x89Uf\x95\n\xc5\x89\xad%j5w}\xf3\xff\x80\xff\xbe\xe6WW,\xca\x83\x8c\xad\x90\xf2\xe4\xc7\x9ap\xedW\xd0\xa2\x99\xd1\xd1\xefG\xa3\xbf\x9d\xab\xff\xd3\x8b\xdf\xc6\xbf\x8d~\xf3\xcf\xff\xf2\xe7\x87U\xf0\xbf\"\xb7\x95\xff i\xb5\xd3\x06#B\xfe\x8cJ3\n\xedJ\x1d^\xd0\x199\x03\xf2\xfd\x01\xd9\xa9J0\x02[\xa4\x92\xbfA\xb0\x01\xe4{\xbf\xb4\xc5\xd8\x13|{\x15\x17u\x85\xc4\xf9Oy\x03\xfeW\xf03\xfb\xe5\x0bq\x7f\x05\xf3su\xcf!\x08\x98\xc7\nW\xfeU\xdf\xbd4\xdc\xbc\x16\x04NUFb\x86\x03\xc9\xe8\x824\\C\xea\xcc\x88\xaeX\x1aS\x8f}\xfa\xf8\x9aT\xe3ph\xb9\x94\xbee\xa8e\xc7 [\x07r\x9e\xb9e\x9dRZ[\x1a\xa4\x05,u%\xa99\x17\xb4\xbe\xa5\x9d*\xbcv\xee\xc6\x16\x08\xd5s\x18\x92\xd7Q\x90\x054\xd4t\xbb\xa0%\xe7C\x92\x0c\xc9\xd5@\xfa\xd8o\xfa\xf4\xfb\xda\xe6fP|\xfd\xa4\\\x98\xf0\x8d\xf71\x8b\xce\xe8B\x9a\xdd\x1cE\xfe\x87\xf2\xda*\x85\x0f\xb6,\xf6\xebZ]JA@\xd6\xa5[k\xe9\xa7h\xfe\xd6\xb5@)?\xce\x8a]yN\x0e\xc9\x89X\xdeR\xf3\xebD\xaet\xb2M\xae\xc5/\xb9\xfc\xadKC\x02\xf7@\xe0\x1b\x92\xaf]\x14O\xc7\xc9\xf2\xa68\x82\xe6c\x9ag\x1c\xc2\x88H\xd3\xba\xd6r\xc1x. M\xfe\xe3\x9fr\x14w4\xeb\xd3\xbfSwZ\xa9\" r\x99gY+-\xf7o\xd0\x8dNz\xb3\xa3Q\xff\xe8O\xbc(\x99J\xab\xbeN\x0f\xcc\xd0CCQ+\xd6\xc8\x03l\x83\xb3\xb0\xb8\xd2H\xe0J\x03?\xc7@\xa7\xa7~\x8f\x91t\xc6\x89\x06/\xee\xb3\xa4\xc5T\xcf\x0c)\x11\xd8\xcfP\x0d\xfa\x1ek\x03x\xa7\xfe\xa8N\xa1\x04\xe2\xa2\xd8\x0e\x04\xfdt8\x87\xd5\x8f\x03\xba$\x92\x96\x01\xcb.7P\x7f5&\xc6$6\xdc\xfd\xe3\xebP+\xa2\x08\xa2-\x80x\xf6r\x9a\xe5\xfc\xbe\xe2 \x94H\xdd@-\xa6\x8e\x06\x135\xa29\xc1\xdc\xeccOA'\x9b\xf4\xe4\x9fK,\x0c\xeb\xe8\x90\xbcm\x8e(\xc8\xd4\xc4\x87\xbcz\x9bk~ ]1\xd8\x10(\x01\x85.\xab\x94\xda'\xb9\xd4 \"\xdb\x07\xc4\x01\x15\xa5\xbc}\xc2\xfb\xc6\xcb0\xcc\xc2#\x9f%g\\\xf0\xf9\x81'\xdbA\x0eID\xa6\xfa\xf4\xa9\xd2\x1cf[\x1a\xad\x07\xfa\x03\xf4\x8eZ\x80^\xbfT\x15\x83\xech\xd0\xea\xd3\x1d;\xb5\xfb\xf9s_\x17\xe1Kp\xe2\x80\x93\x16\xb5\xad\xe6J1\xf7\x1c\x1f\x14\x0b\x85\x8f\xa5\xce#\xccRB\xca\x04divP=b\xc1\x7f\x98\x15\x1aYZUL\xd0\x1b\x86\xe2\x98M\x01R?T\xadu\xc0\x0df\x84p]\x83\x9d_)Q\n\x0c\xdc\x89\x1b\xb4\xd1\xc5f \xda\x86\xd3\x12\xbd\xef\xa5\xfcQ\x13\x8aT\xc5[\x18\xff7\x0f\"\xd7qng\xa7O\xca\xa5\xfc\xb3I\xa3 \xce\xf37\x15\x02,\x19{K\x9a\x1ce\xee\x8e\xd8\xbb\x90\xbcM\x1225\xe2^\x10\xeb\xca\xab\xd1\xb7\xbd\xa5\xa6Z\x89\xed~\x97X>\x86\xd3T\x94\x17\x08\xe2\x7f\xc6bs\xa4\x83\x89\xc0\xe8 \x84\x86\x06\x0c\xd8{\x05Z\x1bY\x9c\xd5i\xfbB\x94\xec\xca\xces\x12\x92\x17$\xd5\xb6\x94$\xdc\xde\x1e\xe8fI\x0e6\x19\x92t\x16\x9ew\x912\x8d\xe8\x14\x1e\x0b\x8c\xf0\x14\x9ba1\x8c6i\x0e\x0d\x06e\xdc\xceHv\xb0h\x81\x9b\xc1\xc9\xdf\x8czR7\xe8\xab\x16\xbb\xc5\x16\x00\x19=\xbe\x8c\x82o+\xd7\xefb\x8c\xb8M\xdc\xcb\x15 \x82f\xda\x96%\xb9\x17J\x9a\xdb\xa4\xb3\xbaMh\xe6\x9d\xda\xd4)\xba\xe56\xf1\xacn\x13\x9ay\xa76\xf5\xe0\x03\xb9M\xec\xaa[\x85f\"$\xb3\x9d\x01\x7fW\x14j\x13\xaapE@7`\n,\xa3 \xc4V\x19v\x8b\xf8\xfa-\xde\x95\xda\xd1\x15M\x8c!\xb9\xc6\x83\xe3\xde\x95\x03\xec1\x1f\x97X\x83\xee\xf0\xc9\xcee\xd9\xc1t\xfe\xd4\x8f\xe9\xac\x9f\xfc\xc8\x0co\x80\xade\x8cI\x0b\xcf\x98 >\x00\xf4\x03:\xf3\x08\xc3(Y~4Y\x1f\x7fl\x96 \xe7\x91Yq\x85+\xeb#YN\xed\xecZ;\x1f\x05\xfd\x0cD?\xd3\x01I\xeb\xed\x0e\xa4\xec\x1fX%pU\xf2\xc7\xd7\xc1,8\x07B\xbd\x83\x9d\xb33\x8f\xedW\x8e\x92Z@\xb8`r\x08\x03G L\xad\xdc\xe6\x89`\xcc*\x0c\x1fka\xf8f\xd8A\xecB\x11\xd1\xed9\x90\x81q\xc5dfn\xaa\xd1\xc4\x83M\xd6x\xebZ\x12\xe0\x10\x98\xa6\x87Pb.\xa6\xb0}\xf1\x0dI\xdc\xb5\xa7Hek\xc4\x03\xb2\x15#{\xe3\xcb\x172\x87\xb1\xc0\xf3n\xb5o\xaa_\x9e\x0f\xd0\xca\x1f< \xb1\xa8OL\xc1\\\xfc\xb0\xecR\x91\xd7!\x81\x90\xfbM\x14E\"\xfb\xe9\xa7\xa0\xe0Q\xe9\x94\x98\x1aC85\x07|;\x95k\xa3\xdc\xaa=j\xaf\xc9n\x06\xf6\x9d\x9c\xb2\xacm\x1b\xb7\xdf\x8d\x17\xdf\xdb`\xa3w\xa3`\xdf\xa6|^\x7f\xca\xddrX\xedI\xd1K_u\x81L\xed\xd8\xc5\xdf0\x10k3\x05\x84U\xd4l\x80\x12\xd8\x15\xe3\x98c'\xb2\xf5\xfc\xbd5\xd7]\xb0\xb6\xac\xc2\xda\xb2~\xac\xed\xdd\x99c\nZz-6|\xd6L\xc5\xd1\xe3\xd5\xe6m\x02\x05\xd0\x8f\xbfU\xb5\xa9\xc1\xc6\xf3\x92\x8d/G\x0b/\x16vq\xffx1\xaf\xf25\x03\xbd[\xbc\x07\xcf+\x9f1\xe0\x11\x1aKg\xa5\x05q\xa4B]e\x06\xff\xabIr\x89\xb8#uF{\xa2\xc8\x16 _\x03\xf8\x8c]gJ\xf8\xe8V,>\x03PF(\xe4\x16\xd6\"d\x9b\x04\x03\xe3\x98\xcc\xc9!\xa1P.\xaf\x95SW\x92\x8e\x14\xf2\x1aE\xc2\x1a`\xd1\x81\x10\x0bg]\xdbL\x8a\xffy\x07\x0e\x85\x8b]\x84\xed\x1d%F\xab\x1b\xd5 u\xe6\x91]\x95\x10\xabyC\x9e\xfd\xff\xe9\xe2\x19\x8f\xd6\xf9\x95c\x87[\x01\xd8\x0f\x07iV\xdezvT<\\\xed<'\x11yA\xb2B\xfa\x15mo\x0fH6\x8b\xce\x95\x0e\x87\xcd\xf2\x9c\xf4a\xe7\xda\xf8\xd9\xde<\xe6\xf58\xcdx|\x96P\xefs\x10-\xbaN\xc7\xce6\x81\xc3\x82\xb6&-\x19\xf5\xdboo\xb9\x7f\xd3\xd2\xde\xc4u\x9e6\x1f\xe93\\\xf6\xd9i*C\xea\xa7\x8f&\x8bA6\xe0\x07\xa2\xf4h|\xc7\x03\xf1\xe9\xb3\xba\xcb2\x0e\x86\x87\xa3U:\xea\xf4\xdc]_\xeaj\xeb&n\xe1e\xdd\xe5C\xe2\xac\xd2\x913\xa8\xe3\xda;\xb5\xfb\xe1\xc8\x1d\x0f\x1e.n\xd9\xbe\xb2u\xc9\xb0\x1b\x85kW\xe0\xe3\x8c\x7f\x12\x14$\xe2\x02\xfc\xeb\xbdv\xceF\xa5(\xaa!\x19\x07\xe9\xa7(\xc8B\x96\xa6\xef\xc0\x7f\xd9\xa0k\x1cZ]\x19iQ\x02h@9\x97\x9c\x87\x8cV\\\x17\xcb\x0c\xa5\xc0_z\xe0\xaa\xed\x04\xady\x11\xa4\xef\xe8;7\xab\xa1\x07\xbd2DU \xe80\x9c(s\xc4?\xe5\x83\x07\x84K/\x922\xd2\x05\x99\x82\x08\xbc\x11!\x80HG\xe3`\x96\x99\x04+\xd0\xcf\xca\xc4y\x13_7N\xf7;N\xca\xfe\x0e6)\x0f\xff~\xb7\x8d2\xa8\xec\x94\x11l\x95\xfbl\xf7Cwv4\xfa\xdb\xf9=m\x16g\xf4\xe7\x893\xb08\xc3\xbfCk\xfb\xb5H\xcb\x0b\xfe\xf8\x8a.\xae\xa2 z\xe6\x17\xdb\xb8\xb6\xd8\"y\xf9\x90\xcd\"pq-M\x89\xa5\x14>\x82\xd54\x8b\xec~\x05\xc8m;lpg\x8fw:\xf7\xafej\xbes\xbe#\xdb\xb0\x88\xc8\xb6x\xb9\xe7\x86M\xcc\x86i\x92\xa9\xda\x10q\x08\x87\xecL\xd9\xfcb\xa2l\x8e\xcdE\x97A7\x01?\xa9\xea\xa6\x1b\xdc>\xa4 !(|\xa7B\xda\xff\x07\xf7\xe0[\x13\x84\x9ft\x931\xbb\xce\x12\xeae\xbat\xd9\x1e+s\x8e\xcf\xc2\xbd\x84~\xd9}2\xc0\xec\xe09z\xe8h\x9e\xc1\xb2\xcc\xa3\x19\xabn\xc0s\xcc*=\x9a9?\xb3\xcb\xcfA\x06\xae\xff\x80\x1c\xb9*\xde3\xc8\x7f\xcb\x7f/3W\xf2E\xe6\xac\xd22\xe3\xedi\x99\xfe\xbeL\xe6\x90\xda\xf8jm \x12\xe3`hN3\x8d\x82\x15\xb8\xf8\x02OM\xdcu\x8et\x823$\xe5\xcbI\xe4c|KQ:\xc8\x98\xf4\x14\xd6R\xc7k\x0d\xd3Z\x93\n\xf5g\xad\x05\x9cqa5d\x89\xa0?\xcd\xae\x9c\x15)\xa2\x86\xf2\x0d:S]\x81My\x02\xe6v\xde\\\x0d\xa6k{q\x00\xe6\xfd\x18\xf6\xca\xa0\x8a}\x01Q\x1b\xae\x82\xc8\xe7W\x80\x04\xa5\xa8\x8d\x04csf\xca\x97!i\x02\x14\x83\xdf\x0e\x06#[\xbe\x0e\xaac\x82\xb4\xa5\xa8\xa22\xb4\xc6[o\x9f\xd9\x82\xc6\xa13v^P.\xe2\xe5y\x03d+0a\x90h(\xe2\xe4 \x1aE\x0d\x113\xce)\xa2\\b$5\\D\x91\xbc\xd2.P`\x88\xce\xd1\x8d_qIJ\xee\x8e\x946s\xfc\xdct\xc1,%_\xbb\x93\xba\x0f\xe3\x1c\x97:J\xc7\xcf\x8f\xf6\x8cCE\xbb#~\x86b\xc7\xb0\xdb\xbd\x19h\x13 zY\xc6@5\xeb\xf5\xac\x07\xaa\xe3-\x99\xf7\xf9\x92_\xebHU:,\x1c\xb8\x84\xe7\x95\xd4\xc3R;d\x0c\xc5\x98oj\x8c\x8c!R\x9b\x05\x1d6\xa3)\x98\xaa|\x1b\x88\x95\xe8x\xa1$ nf\x11\xed$\x1a\xecX6\xb2A\x9a\x93\xb2\xff\x98\xcf\x1a\xf1\xc8\xb0\x9aR\xe8f\xb9f\x850\xa8m\x10\x10(\xba\x15\x80^k\x80F\xfeWX\xddx\xe3Tx\x7f\xd5\xbd\xf6o(\xd8\x9fd\xd8\xc16H\x15\x99P\xcfg\xa4\xccFX\xed\x9e*\x90*\xf4P!^\x91\xa7\xdb\xa5\xabJ\xc8!h\xe8[\xaaR\xfd\xc0++\xddc\xd6K\xeb\x9c\xe6\xd0\xb5\x9e6\xa6\xd9\xff\x06\xeb.\x1b\x9b#\xd9\\O\xac\xa7\x8b\x8dj\x9f\xcb1\xca\x8a-uh\xfc\x9e\x96\xdfm\x1d%sR\xcc:aN\xa1F\xf9kJl\xb7\xffU\x8f\x1f]s\xd1M\xcc\x92\xc6m'\xa6\x11\xde.\x9b\x95\xfb\x9d]3/\xcf\xd8{\xf5q7k\xb7mK\xc74\xa5\xb1\x1bv\x1aI\xae\x0b\x85\xf6\x88\xaeZ,\xe4Azh`Ce\xfbk\xe8k\xa2\x14\xbf\xf9\x14G\xa68Xr\xfb=\xd1\x10\xee0\x82\xe7\xc43\xc2\xf7=\x1f@j%\xa9\xdf\xd7\xe6P\xec\x1f9KnNA\xf7\x96'Ga\xe8\xca\x9b\xdb\x99\xe8\xf5\x81\xa0i\xff\xcf\xe9\xfbwc)i\x08\xe67Re\x01D\xd8\xdf\x9d\x83\xda\xcc\x81\xea\xfd\xf9w\x03\xe9\x02`\xe79\x89\xc9\x8b\"\xf4\xd9s\x12oow\x0d\x01Q#\xee\x83\xd6Y\xdc!\xb3$j\xdc\xfdR'\xc3\x1f\xcfy\xb2\x82\x19\x08\xe0g\x9f/\x12\xf5\xd5\xa5\x1ew=\xdeb\xec\xe1\xd2\xb5\x1e;\xcd\xf6,\x95c\xadg\xe0\xe4\xbb\\d\xcbn\xc9*.\xfa\xec\xce\xb5\xe7\xa0\x01\xa8\xf4\xf3u|\x19D>\x1a\x9eO<\x1e\x8f\xb2\x84Ko\xb2\x1e\xa6N\xd0\xaaM]\xa1<\xba\xf0\xc0\xda\xea@\xbfe\xf3Kd\xab\x10`sn\xca\xe3\xe9\xc1\x03\x12\xa0\xdaq\xf8\x06\x13\xdc\xb4\xa3\xaa\x85;\x1b\x88}\x8b\xcc\xbe&\x17\xad\xd5\xe0\xb8\xb1N\x9b4+\xaeZ\x84\xe1x|N\\)'\xe4pG\xa1M\xde\x00{\x0f\xf4\x0f\xc1\x8d\xeeX\xc4\xf2\xc5MD\x11\xd2\xad\xc4Y]\xb8\x1aD\xec4I\xe5]\xa1\xab\xbe6$\x93\x1d\x90\x18\xb5\xdc\xc9\xb8\\\xeai)\x8f1RcK\xb7VbH0\xa9,\xdb/\x91\x0c\xbe\x80e'\xca\xe2\x1a\x1c\xaf\x039\x8b!\xd6\xa3\x16\xf2*x\x03_W\xcfr\xd9\xd4JJ\xf1\xc9&\xa4[\x03E\x01\xb5f\xd9\x81y\xaec\x0d8.\xf3\xca\x8au\xe2\x01\xd9\xda\xaaC\xb6\x926u/\xe8\xdfl\x7f\xda\xb6Fs*\ne\xb1\xd6\x05\xa8\xf4\xab\xa4\xd7\xd66\xed\x1c\xe9\x05\xb6\xc5d\xa5KA\x08\x02\xbd\xb7~\x02\x9a\x06\x1a\x85\xdc\xa3\xed*I+\x1ee\xcbv=\xaa\xae\xaf]1f\xd3n#\x10a\xb5\xdc2C\xe3-\xea\xa0i\xf5\xd32\xaa\xaa\x82>\xdf\x8ej\x0c\xa2~\x9a\xc7\\\xc1\xb0[(3eb*\xdd\x11H \xa99?,\xbbdl\xa2zZ_(\xfc3u\x05\xcd\xe2\xcd\"M\x9dC\xea\xad\x04\x17f5\xce\xe9\xc9\xf1\xc7\x93\xb3\x8b\x97\xef/\xde\xbd?\xbb\xf8ptzzq\xf6\xe3\xeb\xd3\x8b\xf7\x1f/~}\xff\xe9\xe2\xe7\xd7o\xde\\\xfcpr\xf1\xea\xf5\xc7\x93\x97\xce\xed\xbfi\x08K\xeaR\x11\x15o\xb9\x1e\x0d+\xc0\x85\x1f\x94\xe0q\xa0\xf2\xf2^\x0f\x8e\xdf\"\xb3\x90V\xa4\xf6{\x90\xfa\x15\x9c\xe6\xe2\xc7Z\xad\xae\x88K\xc7\x86\x1d\xc8\xaf\x90[\x10\xe9\x9f\xacq\xd3&\xc5 \xe5)Z\xa6\x1f\x92\x8cl\x8b\x92SiN\x01\xd2\xc8\xad\x9d\xba\x9c}0$Y\xb9:*#\x1c\xe2\xee\xd9\xb8\xe9K\xc2\xd0\xa5\x96\x94\x8b2\xf6\xab\x17,d3\x92!\x01\xc4\x03\xea\xd5\xd7\x99[\xbf\xa8 V\xe4\x10\x0c[\xbc\x80\x98=\xb7X@\x08\x90\xc0PDo2\xca\xdbb\xf7OI\xea\x96\xfa\xef\x03\xf9\xd1\xad\xc9\xb0\x16\xe0\xb7]7\xa9\xe0\xc6\x0c{\xf4\xa4b\x8fn-J4\xf7 .\x0ef\xe1\xb9\xe4~\xfa0>rEv\xb36\x80\xda[\xa1,\x8a\x1b\xa5Y\x90l\x9dl\xda\xed\xe5\"r\xbd\x08\xa6$\xefX\x04\xdf\x96\xe8\xb1s\x1c\x06!\x19X\xe8\x9f\x8a\x037\xd7\x01xg\xa8K\xb6\xd2n\xb7\x14\x87&\x16\xf9e9\x9cm\"\xbf2l[\x8b\x14\x12\xa1\xeaJ\x99oU$\xa7\xbf\xaaN\xcc\xe2\xd5\x0ei\xe1\xbf\xc0\xe7\xa3\xb9\xf7\xec\x02\\\xf5-\xaft5\xcd+\xd7r\xa4\xcf!-U\xee\xeez`nt\xbb\xd0\xbcE\xa0\xf8A\x9aoz\x8b\x90\xf6\xbaE\x08;n\x11\xf4/\xfc\xb8\xdap\xb9j\x81E\xc9\xff\xd8\xad\x9e\x12\xd7y6q \x82\xfe\x1fmRp%\xaf\xbe\x1f\xe1w\xb9\x13\x1c\x159nC\xa1\xf7\xbf\x8b\x9c:\xe8\xbe\x1f\xb1\x9c\xf8\xa6fT+\xc5@\x1b\xe2p\xbb\x187$\x07\x9d\x0ed*\x96QnE\xd7V\xac\x85]\xb1\x16\xaa'n(\xc5 \xa1:F\xc9\x8b\x032\xd1\xf2\xb9=G\xf9~ g;\xe7\x03\xe9\xdc\x16\xe644\xb8r\xa9\xc8K5\xd7\x00\xc2\x9b\xe6\xfc4R\xfa\x1efUq\xbc\x94S\xfc_&w\x0f6\x95\xbb\xab-\x9eK\xc9hZ8m\xec\x10Rv\x8c\xfa\xbfD\xfcH7\x92\xfc%\xf5]\xd7E\x92v\x10\xe3\x92\x9e\xc2\x07Z\xda(F%%\xe2\x96\xfc5\xafH\x9d\x1ar\xab\xa8.\xb7B\xa4o\xcd\x15o\x17\x995+\xac\xc9\xc0\xda\xe6\xf1\xb6D\xdbf3#E\xc9Yi\xc1\x89P2\xea\x82\xdb\x8e\xee\xa1\xafY)\xc5\xd8\x90\xfd\xff\x96\x94\xc5\xee.f\xcf\xe4\n\xf8]\x19\xe4X\xda\xf2l\xaeg\xa3A\x9f*v\xc3\xa85\xfd\x90\xf0\xa1\x9dQ\x04Y\xbfv\x90\xd6\xd6\xec\x14\x1cGgC8;i\xdd`\x99\x0dE-\xc5\xe7\xa4\x06\xa9\xbd\x86\xf28B\x17V\xc7\xaa\xe0bU\xd0\x86\x05q\x04\x12T\xd8\x0fQ}M\xf0\"\x9a\xf6d\xdffg\xa5\x95\xbeg\xaer+h_DR\x1d\xca9;\xf9\xe5\xec\xe2\xf8\xfd\xbb\xb3\x93wg\x16G\xacD]1\xc3\xd0X\xa2 \x8bg\x0e\x07\xb8\xcf\xae\xbb\xbcR\xce\xd5M}\x17\\\xc6{UG\xe7\x19K\xca\xfaP\xb8\xaf\x03\xcc\x1d\xa4m14\xdd\xd8\xfe\x8f_\x07\xa7'g\x17o\x8f>\xfe\xf5\xd3\x87\xff\xb7\nH\xdeq\x1c\xdbVCf\xf8\x16\xbc\x1dIp\xdb/\xd7\xcf\xc9\xea\"\xb4\x8f\x1aG\x14\xb5\xcd\x87v\x9c\x809r6W\x89\x19Wz0\xa5\x92\xa0\xb0\x9f\xcf\xe2\x1c\x84\xab\x97V\xe7wp\x0c\x0d\x0b\x973\xed'\x1f(6\xb5\x83\xf8\xdd \xcbn\x90\xb5\xf5\xe6B?\xb0\xe1=\xa9*\xddZ\x15\x0cC}\xcb{\x9d\xe4\x00Qc\xb3\"\xeav3\x99y=\xe8\x02\xf1,\x04E8\xf3z\xa8oIU\xad\x059$\xee\x1c\xa4\xb9su\xe4\x97\xc1cVC\xb2\x1eB$\x9e\xc1@\x86\xe3yK\xb3\xe5xE\xaf\xdd\x95y\xc0\x0b\x80!Y\xd5\xce\xfc\x18|\xf1\xad\x80\xb1h/\xabB:\x95M\xb8(\x11\xe8\x91\x04s\x17CBg\xcbs\xdd\xa2L\xd9B-\xb7\xb7\x07C\x12\x0b\xf2b\xad\xf9|\xed\x81\xc7E\x9c\x7f\x98\x8f]\x7f\xab\x9c`>h\x1a\x03zR\xbaUk\xb2\x89\xf5]\x980\xc2g\xde\xf9\xa0\xcdm>\xf8?\xd2\xe8}^\xfa\x0fi\xd2\xb5\xcdK\x17\x82\xf6\x00\xc3\x7f\x91\x95\\o=\x087<\x05\x9b\xe7^f\xfah\xb5\x84\x9c\xec\xd3\x81bA\xf6vLF\n7\x05\xe6\x92|!\x80\xeb\x96y\x1d\xa8\x98\x94\xf4g\xfb\x9eU'\xef\xdb\xf7?\x9d\\\x9c\xfc\xf2\xfa\xf4\xec\xf5\xbb\xffl9|\x89y\x00w#?\xe3\x1c\xae\xf4\xa9\xbb\x94{\xcd\xae\x11\xaf\xac\xc7E\n\xb1L\xed}\xcd\xeb\xc7\x13\xd8\xc3\xef\xde\xbf<\xe9;\xab\xdd\xe3\x7f\xd7\xfd\xdbB\xa2\x93\xfeT5\xe9IY\x93\x8em\xdbkV\x9bg\xf8-$a\x85\xc5w\x95\xb4H\xd4\xa9b\xe0\x05Qe\xd4\xbbm\xe6Q\xd5s\xcd\xe9\x0b<\xf8\xb0\x19b\x8f\xe1w\xf0\xc4\xde\xfcH\xbaBl\xb6\xf4O\xf8\x9bEt\xedA\xea\xadD\xd7\xa5\x9b'\xd4\xd6W\xb9\x17\xa8\xfb\xe1 \x86\xa7\xae\xfa-8)\xa5\xdb\xbb\xbb{ \x97\xde\xdd\xdd\xad\x0b\xb4\x89\xa1x\xb6_\x1b\xb4\xdau91\x85\xccy\xc7\x81\xbfV\xb6\x1b\x86\x17&\xd60Z$\xe6} \xa8\x89H\xa1\xb7\xb4\xb3\xe7\x82^i*\x89U\xc7FV\xbfu\xa0*x\x0fN \x11\x15\x0f\x81=.N\xde\xfd4%N\x9cp?\x87^ \xe8\xe4\xe7\x93\x1f>\x1c\x1d\xff\xf5\xe2\xf5\xbb7\xaf\xdf\x9d\\\x9c\x9e\xfd\xfa\xe6\xe4tJ\xb6&\xd5F\xd4FJ\x8b\x0b\x9b\xdfE\xa4\xd8\x1b\x13M\xfa\x8e\x8a\x0dL\xb5\x80v\xb9j\xdd0\\?Z\xbc.>\x9d\xcb@\x01\x1b\x88\xf1\xda\xba@\xa1\xc2\x14\xa2U{\xe0k\xd7\xde#\xf0\xe9\xd1y#+\xf8\x9c\x0e\x9e/n\xf1\xbd\xa4\x1f\xd4\xba6\xee\xcd\xf3 \x06\x15\xd8%\xb8\xd8b\xb3\xf8\x1c\xb8\x0d\xbf~G\xda\x8f\x1d\\\x83\xf5n_k\x1e\xbd9@?(p\x97C\xb2\x1e\x0cH2\xae\x07Sq}`\xc3\xf2!\xf8b\xca\xa4\x1f\xa2\x96\xb1\xd3O\x0f\xbfJ\xfa\x91*JTV\x9dT\xa8W\x1f\xdc.\xd4\xbd\xa2\x8a6mM\xfa\xc4(#\x06w\xcd\xdd5l\xfa~\xa5TOW\xfd\xa0\xc57\x16\xd0\xfaZKW\xf5\xa5\xdb\xaf\xbeH\x8a\xcf;\x98Z\xd2\xca\xd8\xb6\xe7\x96k\x9c\x0d\xc8V\xc3\xc7[\x0cV&\x80\xf8\x90\x05.\xcd\xf5\xc1[[|.\x98\xf5\x8d\xa7\x0em\xd7]Y\xdc\x96\x13\xbdj(o\xf1vG\x88\xc5\xe3]\xd4\xb9\xa55r\xc4O\"\xf3A\xc6\x84\xa3\xb4\x8c~\x90Q\xa9\xa4\xd4\xd0\xb1I5\x94\x17|_\x07\xca\xb5\x8c8\xac\x1f?V\x13p+z\xa2\xf3*\xdc\xa2d\xd7PV\xa7\x96\x8bs\xa5dW\xf7\x89\x99*U\xbd\xba#\x80P\xb5\xa5\x9e\xeeU|h\xee=y\\'P\xe68\xe5\x13\xcb\xfa\x1a>9}Y\xdf\xbe\xa2w&\xf5\xea\x96\xaa;\xf5v\xacK%\xfbzO\x05Z\xaa9\xce\x14Xd\x17\xbb\xd2\x07\xc7T\x7f`\xb7\xf2\x97\xe8\xca/\x15H\xcb\xe5rS:\x7fU\xd1 M\xdf\x15\x18u\xc8\xc8\x01 \xc5\xbe\x96:\x89xX\xe8\xc6\x02\x85\xbb\x0b\xe9\x94Z\xaa\xf7(\x12^*\x97Wbf\xd5c\x0d(*B\xf5\xa9\xa2\xb5_]\x82\x17\xcd\xb1\xbbB\xe9$\x8fGi\x96\xe4^\xaf\xebALM\xcb\x88\xf3eq\xf7\xeb\x89\xad\x9c\x06\x19;\xbb\x89YA\xf4\xcb\xbc@i\xc6\xd4\x92\x8d\xd0\x8f\xcd\x8c\xca%l-_\x0e\xdb\x0f4\xf3\x96\xd2\xffZ-?f\x91\x1fD\x8b\xb2\xedH&h\xd6\x80\x03#<\xff\xa3\xf4\xb9\xa5\x15\xeb\xb6&\xb5\xfcW<\xf1\x98\xbc-\xa8dk\xc1\x9f\x18!d(\n\xb9\xa0\xc6|\xb5|\xb5>j\xa9\x80,\xdf'r\xb1\x16C\x9e)\xafOJi \xef\xc71\x0d\xc3K\xea}N\xeb\x1f\xa2ah4\xe3\xe7 \x0c?I\xa4\x0c\xddi\xac\x0c\xabZD[\xe46\xab%z\xbd\xb3\x1c\xed\xe9\xc5\xf66\xbaV\xb2\xd6\x85b'\xdd\xe9\xd0\xb8\xf3\xe9\xaf\x83G\x14\xe6U\xe3\xaa\x14}\n+\x11{!\xcf\xf61\x1ce\xe8g\x0eJ\x82\x0b\x96\xc9\xe5%\xbdl\xb5|\xc6o\xf5\xbeS\x7f\x14v\xd9r\xb7X\x89\n\xc1\xfa\xd8x\x1f\x07)\x04\xbe*f\xb7\xe5lv\xbd\x96\xb6-\xcb!\xd08\xa8B\x08I\xca\xd0F\x13\xfafD\x86%1LV\x97\x1ay\x1f\xf6\xf2eF6\xe8\xf8\x87\x9d\xe9\xb3tl\xb2\xeb\xb6N\x05\xd2\xb8!\x91\x1e\x06b\x1eD\x99-\xa0\x07\xee\xaa^?E\xd4Vl\xa5V\x9b\x83#f\xed\xda>o=\x0e\xc6 \x97\xa4\x91K\x07u\x1c\x86\xee=7o\xd9\xf9\xa0\x96]\xadC#\xa7\n\xdd\xf0\xc1(Y/`2\ne\xaa\xc2\xc2\x83\x016\xbeV\xba\xb2\xc9bo\xed\x808\xa2\xd2\xeb;\x0fu\xdbZ\x0dn\xb9\x1ao\xb5\xf8\x8aq\xd6\xe3f\xa7IZ4_\x83\x12\x83 \x8a\xb8@|.\x96\xe1v,\x87\xa0\xc7\n\x08\xf4\xa4\x07\xe5<\x0f\x86\x15\xc1~\xa1\xaan\xce4\x90\x0543&\xdc\xb5 \x03\xd7\xca\xe5\xbd'\x90\xb78\xecQ\xcf\x18\xa4\xa1flp0H0,b\x08\xe6\xcd\x81\x07a|\x95|\x02i8\xdc\"x\xe3\x93\xb7\x1f\xce~m\xbf>\xb2,hI\x85\xcc\x11\x15\xdeD/\x92*\x81\xbe\x0cB\xdf\xa0\xd2\xb1(\xde\xc8z\xec\x1f\xd2\x8a\x187\xb3\x15\xb1\x9f\xa5\x03\xbd>\xbfi\xf4+\xa2E\xf0\x96ov\\\x02d\x8dmc\x97\xdcII\xbf\x87q\x8c\x0f\x1e\x90\xad\xac\x8d\xa7\xecs\x87\xd0\xc1\x92\xee\x0c\xdb\xef4\xf4S\xb9\xb8, \xbam\xe2\xa0mw\x07\x1d\x01\x05\x08\xe8w\x07\xd1\x9a\x7ff\xff\x99\xd3\xc4g\xbe\xe6\xa9A\x05\x00\xadU\x9a\x93e-!E )\xac\xd6\xf1*\xda\x82a\xd9\xb6\x08\xe8i51\xbf\x05\x1c\xd3W\xba\xa5\xd8\xa2&\xe1\xf9\xf6\x14r%\xdb&\xe3h\x95\x03\xe1\x92\x16\\\xb8e\x93\xb4\x84:p\x99\x8dE\xec\xb3\xe5/V4\xfd\xac\x10U\x9f\xed\xben3\xa7\x04\x1eVuM\xcc\xa3%\xec\x07\xf8\xdb-C \xc4v\xfc\x8e\xf9\xc1\xd6O5~N6 \xd1,9o\x0d`c\xf5\x14\x87\x8dKU\xd2\xb2\xf9\xd0\x18\xe3j=\xf2\xf4\x99\xb3Q\x83\x8c\x93\xa5w\xabL=\xfb\x8d\xa4AM\xca\xc6>\xa5\x81t3[6\x8f\xe8\xe8\x0c\x8d\x1c\x19\xa8\xa1\x0d\xa1VC\xf0 \\\xb5\xf2rpl\xac\xb6\x82\xa5~\xba9K=\x90\x1f\xc2j\xd5B\x8f\xfd\xcdj\x15g\xbe\x1d\x89\x96.w\xbf\x02\xdf\xdb{\x0f\x13\x83\x1d\xeb\xb5n\x80`7;\xd4_\xab\x0f\xf3\x81\xd1H\xaa_X\xf7\xaf~]Q\xbd\xef{\xe5\xceM\xa1\x9e\xe8T\x1b9\xd9\x86\x84\x95\xdeCyP\x011\xc7@I\xaa\x9f\xaa\xa4b\x1f\xe4\xd9\xf0z\xfe\x8e\x89\x0dJ\x93\x9b>\xfb\xb2P\x8e\xc1\xdayH\xe6ME\x80\xcc\xb0\x14\xab\xc2\x0f\xcb\xfb\x11M\xc7\x97\xce\xa8\x0f\xac\xa7\xe1\x97/\xf6\x83\xee\x10\x1f\xa3\xf2;\xd5\xd9jO\xad\\;\x99M\x94 \xb6\x1b\x95>SPk z\x0f\xd0a\xfdI{\xe2\xb8\xc8\xf4\x97 0\xc2\xde\xa6\xa2\xbb\x16\x16i\x08\xbc\xcc\xd6\xa4m1\x17D\xc3\x81\x0c\xd2\x9b\x83\x11\xb8N\x9dJ\xd7[jF\xab\xf7\x04\xc1@\xd5o\xd3\xbeX+\xc7&\x9dW\x11\x10\xe2\xd8\xe6\x1d\x88\xc0\xd5#X\xe5\x03\xeeW\x9f\x1cJ\x17\x98\xb4Ji~\x94\xeb\x1b\xbc\xa6td\xbb\x9e=\xa6\xd9Z\x07\xfe7\xfb]\xe1r\xa1\xb0\xbdGq\x8bw(\xeb\xf6\x80\xf8h\xe3t\xc9\xf3\xb0$K\x8b\xad\x13\xc3\xc4\xa0\xb9\xa25\xf3\xa1\x8c\x82\xacg\xb5\"\n?8 \xd2\x8c\x03\xda\xe5\xbb\xe1\x90x\xb0\xac\xb6|\xf1E\xd1\xa3!\x99\x03\x9f\xde\xbe{\x86$&\x87\x9a7\xeb$e\x01\x91\xd5\xdb\x1aI\x9d\x19\xb8(ab\x17\x81\x95 \xb6\xd5\xc57\x9b\xb4m0$\xb4\x10\xea{\xe2E\xcb$\xe6Cc\xe5\x1e`\xa6=-$\x909\xbb=\xd5O*|Y\x0f)My,5\xd0f\x1fb \xe1,\xect\x93\xb5\x08\xc6m \xcc\xccVii\x11\xb5]dHGo\x0f\x1e\x90\x89r\xa4+\x1d\xc6\x14\x85\x93\xd9\x8e\x85p6\x88\xb1\x03E\xb2\x08\xfc#\n\x88sF~T\xb9\x84\x13\x19\x132%;\xcfI^\xf1\xee\x96\xb7\xfb\xc5^\x1bf\xd9v\xb2\x89\xbbtH\x1c=\xe5\xa6'\xc2\x94\x1c\x92T\xea\xd8H\x8dE\xb9\x1c\xa6$\xbd\x05e\x85\xf8\xbf\xc1\x96#\xbakn\xa1y\xad\xaf\x87\x87\xda\x13A\xdfe*\xb0\xf1\x0f2d\x9b\x1bV\xee?d[,8\xd3#\xda\xe3O\xa8%\x809\xbc(\xf4\x02\xbe:\n\x91\xe0\x90\x845\x19\x81D \xe07\x0b\xc9(\xee\x03p\xaa\xc0\xd4\xe6\xa8\xa0\x8a\xb0@\x15\xd9P\xb7E\xe2\x95\xd0@\x15I\x15\xef}\xac\xcb\x06\\\x18\xe8\xa1\xec#o\xbf2\xc2\x86L\nO\xc2B\xe9Ut\xbf\x1fv\xb24\xe8V\x18\xaa).iEU\xd1m\xc8g\xbb,\xb7\x1d\xc5\xd9\xa4\xd7s\xe2.]\x10\x95\x0f0\xf2URb\xacMP\x9a\xd9\xa4\xc8\x1d\xca\xac\x1a5U%\xa16{Y\xf1 r\xaah\x88\xbb@\xd7OS\x92\x8d\xb9\xdb\xd6Ou\x1a\xbb\xa5\xd9d\x03\x896\xef'\xd1&-\xb2\xba\xd6\x90\xac\x9a\x18\xc4\xc4\xdd\xc5\xfc\x95:1fJ\xcd{E\xdbT\x8bm\xda\xddp8\x0d\xc5\xf0\xfd\x1cdK\xe9]@\x1c\x01!\xca\xa2\x91\xdeR/\xb4\xe2\xfe\x9c+\x1d\xe3-c\x1b\xd8\xd9Y\xf7\x9fy\xb9\xfb>i\x8az\xda0\x08\xeb\xc9\xcb\x14\xc62\xb2\x11\xee\xddZ\xdc\xb7q]4P\x95\x14\x16+|\xd1F2\xe4c\x85\xf4T\xa7[VS\xeb\x95\xafx\xba\xaf\xb8\xd0iA\x06N?_\xc9<\x88h\x18v}\xd9\xec\x05\xca\xf5\xea\xa7\xd5\xf9\xec\xad\xdb\xdf.*\xd5\xdaA\xcc\xd0\x0eb\xa8v\x10+\xb5\x83\x9em\xc8\x16\x0f\xfbI\xb2h\x96Qo\xf9\x91\xcdos\xa2.X\xf6!\xbf\x0c\x03\xafp\x94f\xe9\xb9\xe6\xf2#\xcd\xe5Ov\xda\x18w\x194\xa7w\xedn\xa4\x14\x99\x0e\x0e\x80=\xd3\xaf\xe4\x8f\xaf@I\x8b\xb7\x81\x0c\x04\xd7\xcbv\xc7g\xc8\x98\xd8\x06D\x05\xd5\xb3\x8d\x07||\xc6\xce\xfb|W\xcdl\xdf\x8d\x7f;\xe1s\xf3~\x10\xcc!*)\xe3B9\x86[\xdcQ\x15\xa8\xae\xa6\xae\xa6l+j\xa9\xacPbS\xf9\xfa\xb5\xaf@\xaa1\xb0\x1b\x8fQ/\xcc\x8d!L\xedc\x02\x96\xf0\xb4\xdf\xa6\xb2\x93\x19\x88\xcd\xaa\xc56R*X\xdd\xc9\x96a\x82\xd7l\x1d9\xcd\xb2no\x17\xc9_\xef\xde\n\x94\xb1<\xbdY]rp\xc7*\x7f\x8d\x057\\ys\x9dD\x8c\xdc\x98\xc9U\xed\x00\xba{\xb23\xd9\xd9\xc3{\x95\xfc\xb3Z*\xa3s\xf2\xa4:\xed\xe0W\xf3\x7f\xffo\x9dy\xeb8\xcc*\x04\x0c\xa8\xe6\xcd\x92s\xd8=3~^\xc3|\xe0\xb3\x1dkmy\x01X\x0f\x0cp\xab\x91i\xb1\xb2\x95V\xb2\xcf\x1b\x9d\x90F4\x9b\x19\xc7\xf2\x0e%;0_\x12CR\\Y\x19\xc1\x12\xda\xf6?\x18/\xb53^\x86^\x0e\xb7\x9a9\xed\x0c\xa5\xa9md\x1a\xdf\xba\\\xda\xddvG\xb8\xaa\x0e\xd2\xbf\xca\x04\xd7\x16\xdc\xd5r\xda\xe3\x96\xb4\x08\x02m\xbbS\xd6(\xc5\xd57@-\x8e\xd3\xbf\x891\x17\x1eb\xe4I\xdd3\xba\x0e1\xf2\x14\xb1\xe6*\xcd\xad\xf6'\x0d\x07\xa79x\xa4\xaa~\xbai\xd9\xacd#\xd5S\xabb\x1e_\xfc.6E\xd8D\x12p>%L9\x8f\x0d~g\x10\xef\x97\xaa\x1a\x87:_\x90\xaag\xfc4\xa3Y\xe0I\x1e\xca\x10\x0f\xe5);6\xa3\x19\x9b\xf2\xd0\xbc\xb4NP\xea\xe5\xb4\xd5k{\xd3\xdd\xa9\xe0\xe2\xcb6)\xe5\x8a\xb4\xe3\xb4V\x8b\xa4\xea!\xa8v\xac6EN\xfd*M;*5\x0c2\xfaUX\x1f\xa8\xb6\xfa}\xa6\xa9\xa8\xda\xccW\xc1J\xed\xcfV0\xad\xe6\xd9\xb2\x8a\nP7,\x0d \xc03\xaa7\x18\x12>\xa6\xbe\xff\x81\xf30\x88\x16g\xdc\x0dk\x18\xe1^\x1c \xef\xee>2\x10\xbfD\xfa&\x14o#@\x8a\xb5\xcf\x9a\xe7\x0d\xa9\xc5\xb8o\xe1Q@\x15\xc6eD\xd3|p.\x0eH\xb6L\xf8\x15\xacjA\xd8I\xfd_\xe7\x98F\x11\xcf\x88\xc0<\x84\x12/\xa4iJhJh\xf1%\x07\xc1\xee\xea\xd6\xb8\xd0\xb5\xca\xca%/\xce\x83\xea\x92\xa8\xce\xa1\xa6\x9bM\xf3\x14X\xd3\xac\xdb\xe6G\x9b\xbb\xd4\x10\xfb\xb0R\x9dB5Z\x81\xaa\x8e\xe9-\xf2\x97z7\xc6A\xfa:\xaa`\x17\xe0\xdc\xea\xb5\xe3\xb2\x19\xbcE\xd5k\xb2\xf6\x9en\xd8\x1c\xa3\xea\xba\xc3w\xbc-\xb5\x0b\xa1\xceU\xb5a{\xcc\xea\xdd\xa6\x1e\n\xde\xa6S\x96}\xab\xf6\xe8\xaa-m)1\x88\xc9a\x9b\xa8\x81\xdf\x07j\xb0\x9c\xc5\xfb\xb6\xb3\x189\x8a{\xac\x1a\xe4\x0e\xb5f\x87\xfa\x8e\xfbu\xa5\xc5[\xdb\xad\xfa|%\xf5\n\xab\x83jbbjb\xe2j\xa3\xbb\xcd-\xad\xbeb\xa8\xbc\xa0\x08\xfcc@\x1e\xc9\xf6v\x93\xf8\xaa6\x91\xa2\x9d\xdd\xd4\xf0R\x0b\xec\x1d\x02\xec\xd9\x88\xad\xe2\xecfJ B\xa5\xf1\xb9m\xe2\x10D\x0bW\xfa!\xa8\x93 m\x14|*\xfb\xc9\xaf\"\x96\xbc\xe4^\x0e\x12\x0e\xe55\x89\xaf@HfSb\xd06\x0b\xe38a\x1e\xf5\x96\xacP\xe5\x967P\xdcEn1\x9b\xf2\xc0\x9aT\xb7FX\x1d\xca0^\xceo\xd7{\xde\xd6h$\xc6!\x17\xbd\x1f\x8d~\xbb\xdecNm\xaf\xd5\xce\x02\xab\x8eW\xf3\xf0\xef\xaf\xc4^t\xdb\x1a\x04\xba\xadQ-\xda\xea(\x930\xce\xa3\xea\xd8\xd6j/qK\x8d\xda\xa0\xf7\x82R&\x15b\x03\x0f\x1b\xc0Q4\xea\x14\xb8\xc0\x01\xe7\x19J\xd0\xba\x07\xd1]j\x99\x99\x91Y]k\x86\x07\x0eP.\x06\x86\xf39\xe1\xcfI3\x80\x1d\x89\xea\x9b\xb4\x12\xb5{G\x1a\x03e\xcf }\x0e\xbfh\xb5t\x80\x96~N\"2\"\x01\xf9\x9e\xec<\x1f\x80\xbc\x8bU\xaf\x91\xa2\xd1\x08-\x16\x90\x11\x89T1@\x04\xd5b\x01ZL\xef\xfe\xe89\xc9G\xa3\xe7v^\x1dB\x02\xb71\x8dHK\x1b\xad\xb0\xac$R\x15\xa5\xff\xa9 a\xae\xb3j\x0b\x83\xf4(\xf2XZ\xa5\xc8m\xa7\xacm\x89$\xc9lr\xbe\x89\x96W\xdb\xdc\xf5gIk\xea\n\x06\xea\xb5\x88\x08\xda8\x07i\xe8\x88\xec\x0e\xbcS\x05\xd1\x01*\xf1v\xa6x\x1c\xb1\xeb\xec4\xb8\x0c\x83h\xf1\xdcJ\xa7\x93\xda\xc5X\xa6\x14Z\x9e\x14\xd6q\x12\xe9\x0e\x86d_2A\xe3H\xab)>x@j\xf8\xcc\x80\x90\x11\x0d[\xbeJ\xcaE\\\xc7 \x16c-\xfd\xb4G\xe0\xb6;\xd3\x94\x04\x981,=\x17\x8d\x9e:A\xe1U\x0fx\x1c\xab\x9d[\xcedVWa\xba\x9b\xa8\xe2vD\x81\xc0\xd0\xb7\x15q\xdc\xcb\x85\x8aEj\xfa\x08'\x07\xf1\x1bL\x19h\xb1:x\x16\xef\xcb\xfafqJh\xf3\xb0\x15\x83\xd7\xb5\xd7 (\x02\x07)\xd8\xce\x04\xd1B\x85M\xb4\xb8\xa0k\x9b_Qfv\xdb6\xf2\xf1<\xcc\xd3%\xb4\x82)-\xf4T\xaa\xa1\xf3\x86\x04Gv%+\xbb!e0\xc9`\x08\x85A\x17m\xee\xd6<\x91}%W\xcb d\xc4\xadKT\x8cX\x82 \x97\xe1\xe4E\xa5n-b\xe1 \xa1\x81\xc5Qd\xce\xf8\xf9\x90,\xc7\xcaC\xd7\x99\x9a\x03\x97U\xa6C:\xb53\x87j\xd8\x18;\x1c\x17\xc7v.\xde\xa6\xa9\xd1\x18&lu\x18$Du\x81\x18\x19\xf5\x01h\xde\x19\x96M\x06n\xb1\xa2\xaa!\xf8\xc5qv\xc5\x8f\x92\x05\xf0\xb5\"\xa7\xe2dx\xad\x1c\xefW\x1b|\xc1\"z\x192\x7f*0d5\xa7:\xc4X\xdc\x95\x9f_\xbf{\xf9\xfe\xe7\x8b\x1f\x8f\xde\xbd|s2%\xc1\xd8\xa3\xd1\xa7\x94\xbd|\xff\x96\x1c\x92\xab \xf2\xf9\x15\xc1\xca\xa5,\xfb\xb1Vy\xbb\xe4\xa81\xe1bQT\xc7\xa6\xf1\x85\x13\xdd\xb1\xce\xaa\xd5\x10\x88Sb\xab\xb5\xd6 mV\xdar\xfc\x96U\xb7U\x9a%4\xfeAJ\x1faQ\xf4\x13V\xeb\xdb\x0drH\xf8X\x06\xf0W\xb1\x89\x96\xa0Z-\x0e@\xa8N\x124r\x99\xb1\x81\x16\xd7v5\xe8X\x892o\xdb\"%\n\xbd\xaf&\xadx\x14d<9\xf5\x12\x1e\xca\x88\xe8]\xd3\xaaQf;\x94x\x98\xeb\xb9r\xad\"\x8e\x9b\xbeV\xdb\xda$<\x8a\xc1\x97U\x0c\x89\x93B#\x1dD\x8d\xa2\x8aN\xcc\x11\xe9)\xd3(\x17T\x1b\xd1$0f\x0c\x86\x06\x02\x05\xb4\xc6\xeei\xb7\xcfI\xc7U\"\xce\xf5\xedr\x81\x1eF7\xf18a!\xa3)so+\\(\xde,$\xd7\x12RoEr\xf5S\xc1.\xc4`?K\xe4\x067\x1d\x86\x0eY\x91q\x88\x8c\x03\xc4\xc5\x8a\xe9\x82\xfd\xf2~>O\x99\x0c\xd82\xf6\xb5\xc6\x82\xfe\xa1m4\xe4:z\xc3\xe6\x88\x00\xf5FW\xf5\xeb\x06U\x9d\xf1\xaaX\xf0+\xc1\x82\xceC+;\xbfm\xa9\xf1O\xd5_\xb7\x9a\x89\x92\xf8\xdd\xaf3\xaa\xea\x9acb!~\x1b\xd7\"\xed\x81\x16\xf6\x9e\xe0\x91\x16&\x8f\xeb\xf5\x84\n\xbe\xde\x1e\x0f\xa7\x97q\xbe\xc9\x10B\xd0q\x10\xfd7\x83qi\x8e\xef\xcb\xf7ou\xfc\x8d)I\xda OVqvcT\x9b\xb7\x02\x0b<\xf3!\xcc\x17A\xf4c~)\xb8\xdf~\xc0\x9f\xb2 L\xc5\xd9\xde\x05~\xb2\n\xb2\x8c%S\xf0\x9bg\x05\xfd\x11t\x88\x8a&\x87m\xb0\x05\xef\xe8\x95P\xd5\xf5\xf6/\xe0\xbc\x1e\xd7\x99\xa6\x00g\xb1\xa8e-\xa9\xb5\xf7\xb4\x9e\x9eV\xd4\xc8'\x8f\x9e\xd6\xd5\xc8\x15\x17\xb6[\xff\xbe\xd7-\x03\x01\x8e\xe0\x94\x85r\x08_G\x82\xd9\xa5\xf8\x98+\xd9H>N\x80\x16eE\xa9\xea\xc0c\xf1\xb9\xcd/v\xca\x7f\xb4\xbc\x97\x8e\x0b\xa2\xaa\xc3&\x92\x8eK\xa2\xce\x85X\xe3\xbd\x0c\xad\xea\x02)+\x1dP\xa9\x1f \x94S\x17D\xddu\x04\x94\xa4\xa8\xa2\xb0.F\x9da\xc6\xad=:\xb6\xd1w\"\x9e\x05\xf3\x9b\xa30\xc4\xbeU\xed(*\xf8B\x98\xfbv\xc9W\xbb\xe5Aa^Pk'\xa8Q\x94\x94Ldx\x99D\x8c\x14\x0c-\xd5\xca\x86\x8e\xef\xd5\x06\xc1\xab\xad\x83z\xc5\xb7\xb2A\xc0:\xdf\xf1\x9d\x8d\xcd\x12Z)l\x9b\x81\xc1&\x0d\xae\xf8\xa8n\xfb\x18b\xa6`W\x18hl\x11\xed\xca\xba\xa1\xc6]y\xed\xcd\xae\xf3\x82,\xc5>7\xb0.\xcc&\xcfR.\xbf\x12\x91%\xee\xdc\x14)\xa4C\x12\x0f\x86$\xa8\xf2\xee\xf3\xba\xe1\x15\x14\xbf\xe3\x01\xd6\x90\x05*]\xea\xddz\xdc\xa7@\x1dl{\xa8\x18\x8f\xb6h)\x94\xd78\xdap[*\xa8%\x96\x8d\x98KO\xe6\x85\x90\xe0\xc1\x03\xe2\xa4\xfa\x80\x01\x85/M\xb9\x8a\xac-\xd71\x8f-\xc8W\x8cZ\xf3\xe8l\xce\xeb\x82e\x928N\xa7$'\x87=N\x00\xcd3\x16tt\xd16u}\xff\x91F\x8b\xd6\xa0,`\xdb1\xce\xd8u\xa6d8vP\xb8\xb3\x1d\xfby\x1c\x06\x1e\xcd\xac\xd7\xb5 \x84\xaa?\xe3\n\xcb\x9dI\xb7\xa6C\x92\xc8\xd3\xca\xff\x00\xbb\xcd9\x89|@\xaaI\xe6\xd8\xb9=-rK\xcc\x16\xb6\x9e\xb9-\xbc\xa1\xf8VC\xed\xcf|X\xe4OA\x03\xa5\xe9\xf7\x95\xe0\xcc\x1e\xe9\xc2\x07\xc4\x98$\xb9\x12*\x84\x8dX4H\xb2mh\xe5-\xb1`\x9dv\xd4-k\"\xe6\x174mz\x86\x05\x95\xf3M#o\xc9!\xdep\xd7tKH\xb9,\xed\xb0\xd2\xb7\xc1\x9c{y\xda^iP\x02v\xd5\x99k\x7f \xb0\x86\x8f2\xd7\xe6\x91\xb0]$\x90\x8fa\xe2\x0b+\x80\xe2\xeazH\xf21\x8b\xfcf\x06>\xf9:XC\x9f\xd8=\xa8\x07\x00\x82.!b\x98\x04P\xb723\xf5\xd1\xaf\x8cpu\x14\x07\xe4\x90\xec\x10A\x04g\xfc\x14\xd40\xdcA\xe7~\x0eA\xf2\xee\x85<\xd2h\x02\x1f\xdfPa\x15\xf1]p\x06\x12e)\xec\xe8P\xedh\xb7>\xc6C=\xea\xaau\xf6\xe5\xe8)\x0d\xa7z\xf9\xd0,/^\xcd\x99R\xef\xd5\xae\x87\x9bt]\xf0\xbb\x1e\xd9&-\xee+c\x13\xadV\x90)\xde\x9bX\x0c\x06\xe03W\xb94\x8b\xf5\xf0p\xbb\x03#\xad\xd2\x14\x8f=\x1e\x864N\x99%`k_\xf4\xe6\x8bs\x83L\x89\xd7\x81\xe6\x04\x9c'\xd0W\xcfu\x8a\x90\xf3\xa9\xf5\xb8\xear\xb52\xd4\n\xcb]\xe7V\xf7icX\xbagbQ\x90CIL\x00\xf2\x801!\xd3\xe2\xd7\xf7\x05\x8c+\x01X\xe4\x0f\x15\xa2\x03\x08\xf0Zi\x94\xd5\x99,\xf2\xc1\xd4\x14?\xd9d\xba\x9c{\xc7[\xd2\x84z\x19K\x1ci\x19\xce[\x8e=^\x14\x16\xcb\xa4R4!\xa3\xa2\xb8\x18\x1a\x8c\xeb!=\x84\xb0D\x1d\x1b\xc8)\xd3\x86\xc8\xf4Q\x81\x1eN\xf6\xa5E\xd4\xb9\xc1f\x81;8\xef\xdc\x86DI\x1d\xde\xd2l9^\x05\x91[\x0e{\xc7G\xf2\xaa\x93\x03=\xad\x94L\xcd\xca\xe4\xf4\xb6\xa9\x95\x89\x035\x1a\xb3\xebL\x94\x7f\xf0\x80P\xf2=i\x0d\xc7C\x0c|\xdd\xe2\xa0\x8d\xa86Ri\xff\x92Z\x01\xed\x9aJZ9\x15\xb4\xd6i\xc7xx\x1a\xd0f7FTo\xc1\xe9\x87\xd7\xa7\x87\xf3\x0d\x11\xa0~\xe6%\"\x0c\xe1L\x15\xe8\x9aK\\=\x04\xc7Eb\xc1\x1f\x85!\xd4\x96\xba\x10/\xe8{\xc0 n$\xb8\x0c\xf9\x959\x00\xcb\x99q=U\x91\xa7+\x82\x8d:\xd7\x08\xb6\x91-\x8a\x1a5\xe1\xc2{b\x1d\xfeN\xb1>.\xc5\x93\xb3\xbc\x11\x13T$\x17\xdcKbWB\x00\xe1\xfdx\x1e$\xa9t\x91_(\"\x18I\x95\x82\x9a\xdb)\x12\xb1\xdb{n\xff\xa0\xdd\x16\xca\xd4\xa0+\xf5\x1a+\xea\x86\x8d\x82\xb2\xad\xa5\xeaCuH\xff\xd4\xfc\xd5\xdb\xb3G\xc5`-\x01\x9cl\x18\x9f\xed<'\x91\xb5'{\x92\x13,\x88\xbf6\x1cJ\xc1i\xed6\x89\x80\x1bQ\xa4\x90Fr$ /\x94\xea$%\xdf\x9b\x86b\xf6\xad\x16\x81\x96)\"\xd3\xd4\x8f\\\xceS\x92\x91\x11\x12\xa6\x8a\x90FHi\xfd\x04\x851b\x05\xb8\x91\"\x07\x8c\xbb\xd1\xe0\x9b\x9a\x7f\xec\xef\xedX\x8c\xb0\x8be(\xd5\x9c,\xfc\xfa\x96b{\xb6\"\xb0\x01WVe\x11$%n&\x13\x137\x1a\x14\xfaR\xc6:\x13\xb8\xc2\xf1$\xf1\x98*\xbb\xb6C\x88f#\x93D\xb1)\xd9\xda\x92\xf1mhR(\xda\x7f\xe0i\xa0\xb9\xb4\xad-w\xf2\x84< V 1\x84\x0d\x15\x8d;\x0f\xdb\xa4c\xd8\xac\x17~\x80F\x1e< {\xe0\xe9\xa6\xc9\xdb\xdc\xa1}\xfd\xda\xa1\xb9^\x97\x899\x19W\xec+\xe0\xf2\x8fL\x8b\xe3e0\xf6\xd9\x9c\xe6a\xf6S\xc0\xaeD\xa6$;Pd\xb6\xe5nI\x17\x83\x16_Qc0\xba9\xac\xder\xaa\xd4)\xeak \x84:\x118D\xaf\xa4W\x95\x9c\xa5v{\x13\xe0\x1d]\xb1\xfb\x9dwg\x99e\xf1\xf4\xe1\xc3\xab\xab\xab\xf1\xd5\xde\x98'\x8b\x87\x93g\xcf\x9e=\xbc\x0e\x83\xe8\xb3\xd3\x94\x90!\xf0\xbf\xbc}#\xca\xec?\x8c\xe8\x8a\xa51\xf5\x98\xd3\x94\xa05\xf1\x12\xf5<\x16e?\xb2`\xb1\xcc\xa6\xc4\x91\xaf\xa3%\xbc#>\x9a\xa8\xe7\xe5\xab<\x04O\xd6;H\xb6\xef\x07Y\xb0\xb6d\x86\xc1\"\x12s\xff\x03MY\x18DL|O\xa7\x8d.U\"\xf6\xd10\xe4W\x1f\x19O|\x96@\x99\xf2\x15\x85\x8e\x97\xf4\x92e\x81\x87\xb7b\x15\x87A\x96\xfb\x966&\xf42\xf0^\xf1d%>\x04/\xa39OV\xd8wR\x0fn\x07\xb1Z\xb2, .\xf3\x8cI7\x88N\xe5\x1d\xabJ\xe7\x8b\xa5g\xc2\x8bw\x0c>\xcf\xf8G\x06\xc6\x92\x02\xba|\xc3`\x7f\x0fVy\xb6D\xdb)\xc6\xfcU\xc2\xfe\x91\xb3\xc8\xbb\x99\x12\xa7\xf2\x8e\xd4%\xf2?$|\x1e\x84LA\xab7\x0b\xac\x98\xcf\xd3e0\xcf\x14\xb4x\x1f\xa5\"\x01+p\xc9\xaf\xf1V\xb2E\x10\xe19\x01M\xf1\x8c\x1b4\xd9\xa3\xa1\xf7\x16\x0e`G\xffD\x1a\xe2\xd1\xb8\xd8\x0f\x1e\x8d\xed\x9b\xc1\x0b\x83\x18\xffN\x18\xc4\x1f\xa8\x18tG\xfc\x1c\xc54[Z\xca\x7f\xcca,\x01,\xc9\xd1\x91\xd4\xb5}\x8a\x02\xc1w;\x95w\x0c\x9e\x87\xb3#\x1b?\x98\xcf\xf3\x94\x1ds\xe9\xabsJ\x9cZ\n\xd2\x1b?H$go\xa9\x11\xbc\x9eZ\xf2\xd6\x81m |\xbe\n\"Z\xc1\xef:\xa9\x0d\xbd\xfb\xb9\xa5:|\\}\xbca\xcc_0\xb5\xb7\xf5O\xe4[,dkj\xed\xb8\xd4[\xfb\x81z\x9f\x17 \xcf#_\xd4\x05I\xa3\xcb\"\x0d\xab4\xc2'U\xd0L\x91m\xda\x04\x9b\x9bD4\xfc\xc8R\x9e'\x1eK?\xb2\x7f\xe4A\xc2\xe0\xa3\xb6<\xe4\xe3\xf3 \x0c\xd1\x0f\x88\x8c\xf71\xf5\x02\xf0k#\xdeF\\\xbeZjQ\xa8\x08 -\xa8H\xeew\xdb\xe72\x96|d\xa9\xacB\xfe\xb6V\xa1q\x99\xf1\x86\xc1\x86\x9c\xfb\xc7\x02\x13\x08P\xf12\x02\xbc`\x035\xba\x0b\xc0-\xfd\xe5^\x9e\x8a\x99\xc5\xfb\xc2\xa3\xec\x15]\x05!T\xc5\xa3l4\x877\xb4\xa2(;\x05]\n \x98\x06\xbf\xa3\x03\xa7\xc0\x8e\xfc\xff\xce\xd3\xcc\x04\x1eQH\xb2\x95\xc9\x12\x96y\xcb\xa2\x80|\xb5\x02\xdf\x84eC\xc4\x8b\x05\xf0'\x9a\x04\x12U\x00\xe8Z\xbeZ\x80\x7f\xd6g!\xc0^\xd9\x0eC\xa9\xae\x83\x0fg\xc2Wx\x06\xbe\xc3\xe7\xf8\x0e_L\xf0\xe4]<9\xbc\x89\x97\x8a\xfe\x82\xdf\xa3\x08'\xbe \xf3}\x12\xb0(\x03\xcc\xf0#O\x82\xdf\x05\x9f\x18\x16%y\x99;Z\x16\xd9=\xea\xfa\x89%Y\xe0YjZ\xabL[=\xe0\xb8\xdb\xd1?1\xa8\x84\xfa\xa2:\xd0\x12\x99K\x9a\xb5\x91\xd6RNo\xc2\xca;\x02\xbf\xa4\xd1\x02Ned\x98a8\x8e\xfc\xf5/S\xe2\xc0\xef\x11\xf5\xd7\xa3k\xac\x16\x91\xfb> \x16AT\x02sxG\xe1\x03\x9f\xf1EB\xe3\xa5\x85\x90\x0fVt\xc1L\x92\x01\x12ZI\x86 \"xU\x11\xbe\x86\x80\xd8\xf1X\x8c/\xeb\xcfx*\xbeJ?\xe3_\xf8\xbc\x87'?\xc2\x93Y\x12\xb1\xf0-\xcd\x92\xe0zJ\x1c\xf3\x15\xe9\xad\xcc\x16\x93\xfa\x06\xe4UE\x892\xc9R\xca6\xd9\x9f\xd9\x0d\xdci\xa4P\x95\xfa\x8d\xd6qs\x1a\x8b\xd3^\x01\xaa\x17\x1c\xf2,Xi8\xf8\x89@Iy[\x81;\xcdW\x14:\xcbXr*p?\xac\x0b\xf9>Je\x02V@\xa040\xa6\x95'\x8d~\xb7\x1e6`\x8f\x0e\x05\"v\x14-\x00\xe96\xd2\xb0r\x1cp\x012\xb2+\x9a|f\xc9 \x90\x1c\xf2\xf7\x88\xa1\xb4\x86\xcc|\x1b\x18\x80\xab\xc0\x0ex*\xaf\x085h*o\xa1,\xc0\x05\xd7c\xbeZ\xa15\xf60\xde\xac\xb0?\x07>\xac?\xe3\x0d\x85M\xf1=U\x84\xcb-qV=\xc9R\x9d n\x87\xcb\x96lE\x15\xa2\xc6>\xcf-\xd2\x82(_\xbd\xf72\xba\x86\xf5[\xbe \xdf\xd0R]\xa4\x12\xae\x89\x164O\xbaa\xc73\xa5<\x04\xcd ld\xa7q\x00\xd9\xf2m\xdc6_\xb3d\x1e\xf2+k\xa6\xd8\xe4Z6:%\x8eN\x1a\xc5*\x0d\x1b\x17\x05s\xb6\x0c\xbc\xcf\x11KS\xb3\\\xa6\x13\x91\x821\x0d\xa2\xec\xbd\x92\x08\xc1\xcb\xc8&\x10\x8ai\xc4S6\x018\xf1k4A\x81\xb2e\x81&\xcb\x17\x1cRP\xe7\xb5\xf5\x88\xa4\xda\xcb\x9a\x07v=\xc9^\xaa\xf6)\xeb78\x1c[\xa0\xee\x0e\xe0\xf2}\xc4 \xc1V\x00\x97\xa3\xc8\xac\xa3\xec\x17]\x8f\xf8m\xad\xe2(\xfb\xd5\x80\xfb\xb5\x05\xeeo\x06\xdc\xdf0\xb8\x84\xa5,Y\xb3\xa30^R\xf0\x1bo\xbc\xb7\xc1\xa71\xf3\xb2\x8fby\x9b\xa5\xcaT\xb4,`\xee5+\xc6\xb7\x92\x80\x94\xc07\x9d \xa2r|\x18\x136\x17#(\xfea\xd5\xb1\xf9\xaf2\x17\x1b\xb2\x82\x9ey\x0d+\x0b\x00U\n\x08cP\xba=a1\xa3\x19(\x89A\x81\xe2\xcd\n\xfbR0\xe1N\xf1\x1b\x85\x93<\xe8\xc9u\xc6\xa24\xe0Q\n\x05\xea\x89-%_1\x9a\xe5 3\xcb\xe9$\xb4\x94\xd2oA\x074\xcdCK\x16\xcflR\x94\x04g7\x12\x1c\xf7\xa6\x1e\xb5\xb0\x87)c8\xc3\x9f.i\\!I!\xa1\x95$MC\x1e[\xbe\xa2 \x184\x8fyyH\x13C\xe8SO\xc2\xbe\xa5@N\n\xb9\x84SO\xc2K\xd9\xba\x1b'\x8c\xfaoY\xb6\xe4>\xd4U\xbeb\xf5\x94\xda]\x02\xb8|Ca\xfd\x97l\x1dh\xe1\xa5\xf9\x8aB\xb3\x15.\xe0\x169kKN\x90y\xcb\xb3 \x84\xe5h\xbc\xa1\xf5\xf3X\xd3\x86\xe2\xb7\x95.\x14\x99\xa5\x0c\x02@\xed\"\x884K\x82\xcf,[&<_,\x8dc\xb3\x92\xdevvV\x00\xcd\x03\xb4ZC\xdb)*o\xb8,\x03\x94\xf0\xcf\x96\x95 Y/i\xba\xa4IBeWE\xca\xc8\xd7I\xf8\xa7T!^\xae\x81\xa2\x14\xb7\xaf\x04\x01\xf3&\x88\x98G\xe3\xb2L(\x13Z\x0b\xfc7\x0f\xa2j \x91b-\xf26\xc8\x04\xdd\xb1\n\x8c\xa6\xad\x8a4k1s\xbe\xa1L\xeb\x8c\xf3\xcfL\xd3\xc2\n\xfc\xcaB\x0c\xa7y2\xa7\x1e;\x95X\xc81_1\xe8\x1b\xb1\xd4\xdf\xd0h\x91\xd3\x05\xc0W\x12\x90\x12\x19\xbd\x0c\xa5\xb7&\xb1d\x8c7\x146Y0 \x02\xd4/+\xcc\xaf\x05\x0cv\x96e\xec:;\x02\xfdV\x01\xc6\xae\xb3\x91\xd4v\xb5\x80\xbed\x1eO4\x0e\x00p\xbfH\xb1\x141\x91/\x94h\xc3\xbd\x02\xa0\xa0\xf9\xca\x17\x0c\x92\xa3\x1b!+\xe98$7\xc7%\x019. \xc8E;k\x14t\x91\xd6\x86\x06\n \x13\x05\x94%\xdb\xb6\x7f\x1e\x05\x9e\x8d\xb7Qy?\x04~\x00\xf5\xc1\xdb\xe82\xf0\x03{E\xa0|e@\x83\xaa:\x0e\x9e\xa5\x1fXr\xb2\x92\xc0Y:\x8a\x05\x85\x8a\x11\xbf\xeb#\xe3>\xd7Y\x8f\xca\xeb]\x0c\xf8G-\xaar\xd6#%\xb6\xc2\xc0^\x9b\xb2%g=2dM\x18\xf8\xdb\n\x87\xe8\xacG&\xcb\x88\x15P\xdb\n\x19\xd65\xf32\x9e\x9c\xcc\xe7\xcc\x13xF\xbe\x8e\x18\xbcc5\xb1$\xb5\xb1jk\x96dG\xfe\xfaW\xa8&\xc9@\xf0\x86\xa1\x1d\x91Y\xca\xdd\x00\xb4E\xecVB\xffZ\x83F\xeb\x0e\xd8\xd5\x0f\xfcZ@\xca_\x16\x983\xc0 \nL\xbe\xa0\x90ip\x19\x846n\x18P%>\xacW<\xf1K\x89\x8fxk\x91\xf7\\% \xa9Q\xb7E\xeam\xb4\xc2o\x8cp\x9a\xf1\xba\x90\x95\\\xdb\xef\x87\xafq\x04p\x8d#\x80\xeb\xe3%\x8d\"\x16J\xad[@\x91\xf5$\xec\x1ba\x10}>\xf2\xb2\x1c\x88^\x07^\xa7T\xbe[\xc1\x13/\xe1\xa1\x01.\xdfm\xe0?& \x88\x96\xb0\xcb\x04\x15EC\xe6G\xb3\xd2\xb6\x1aO\x97\xfc\xaa\x00L\x97\xfc\xca\x06x\x16dF\x95\x99x\xb3\x82\xca\xab\\\x05\x89_\xe2^\xaf\xc2\x1f\xc0\xd3\xb6s\xbd\n\xa7\x97\x14U\x98\xb8^\x85\x11\xbe\xc8 \xe7\x17\xf8\x00\xd4\x10\xa5SLAG\x81\x8a\xb3W})\xa4\xe8:\xbc^\x85b\xcd\xea\xf6`J;D\xfa2@\x1as\x83/\xae\x1b|q\xdd4\x17W= \xf9\xf2\xefh]\xbfs\xbe:\x8a\xfc\x0fT\x1cQ\xe5K\xab\x7fT\x8a*\x1f)\x17\x02\x81\xc0\x95\xf5@\x11Dz\x1982Ug`\x84R\xcc!\x04il\x85\xa4Y\x1dil\x806 \xb9\xec\xdb >v\xd6!\x17z\x1b\x84Z\xe1\xad \xb0\xb2m\x10zI[\x8c\xdc\x8a\x85h\xcfWk\xb0WH\xd9\xc6\x8cL\xcd\xc8]\xa4\xaa\x9d*#\x02\x8e?\xb3\x9b\xd4\x0d\x06\xe39ON\xa8\xb7t\xed\n\x84t\\\xae\x08\x19\xe7vgH\x02\xf1\xeb\xc1\x03\xe2\xd2q\xe3\xeb\x12H@\x18\xeax\xdf$@\xc7N\xddu\x02\xc7\xedW[\x82\xfe`\x0e\x15\xa4\xa3\x85Guk\xd7T\x81\xef\xe2>>\x1e\xe3>>vw\xeb\xd5\xcf\xc16\xbdj\xcb\xaa50\xdf\xea\xf8\x05\xa69k\xc3;\x8b\x80\"/\x0e\xc8\xa4\xe6=\xb1i\xaeN@2\x12\x02]\x83o\xd0xIS\xe6\x7fd\x8b \xcd$\x15\xaf\x97\x10\n.\x1e\xe5\xf1~J\x1c\x1eID\x85\xa0)\xfdh\xd7\xf6\x06\xb4r\x11\xe5\xa0e\x90\xf5M@\xd9&\x16LC\xe4\x01^\x9a9\x19\x8f\x7f\x08\xf3\xc4\x19\x12\x07\x04\x01\x10\x1b\xfb-\x8br\x95\xf2\x8a{y\xaa~\xff\x95\xdd\xbc\xe4WQ\xf9\xf6)V\xbf\xdf\xf2\x06\xe8I\xe47'\xab\xa9\xa2\xbf\xa1EV\x8b\x05q\x87\x0b\x12\xfbf*\x0dM\xa7=\x0d\x82Mc\xd4io\xd3\xe0\xc2du\xda\xcfB\xd8\xb0j\x9dV\x8d\\\xf1m\xdb\xb17\x88\x1a\xed\xa6\xa5a\xab\x85b\x0f\xdb\xc4[\x8e\xbb\xb4KP&\x84\xd3\xc2PA\x07\xc7o\xb1\xf3\x92Q\x12\xa4\xf1I\x0b\x14\x8f\x05\xd0%\xcf#\x1f|5\xc4v\xd8\x90\xcd3\x13\xf8\x0d\x9b\xdfn\x94\xbf\xba~m<\xc0\xb2n\x0d\x8a\xfa\x9e\xbb\x16\x07,6\xde\x80~\x9a\x03\xa9\xcd\xfes\xc3\x93J\xac\xe6aH\x96Cbq\x10\xa7\x06\x9fC\xb4xr\xa0]58C\x91\x04|\xa6\x98\xd7!I\xc6\xa5\xea\xba\x8e\xb8\xf3Ry\xb7c\xa9\x0bf\x99\xd5\xfe\xfd \xf9\x8c%N\x93h\xfce3X\xee\x9aE\xa0\x84\x9aNImF\xd8u\x96P/\xd3wtu\xca\xa4%|\xf4\xd6\xa2\xc3\xea_\x0fdF\x0em\xb1\xd3\x06d\x8a\x9a[\x88'\xbd\n\xdam\xde=\x9a2\xe3\xd8\x9bZW\x9a\x1b\xba\x1c\x82\x9d;Y\x923\xe9#\x9e\x8f\x95\xaa\xed\x89\x1f\x80\xc8Q\x9a\xf1\xf82\xb6\xc7R\xfa\xa2\xd5\x07T\x8b\xd1!\xb8\x82\xc7\xb3\x8b\xf6\xc1\x99mo^qd\x96\xc7d\xf1\xe5\xbb}\xb8<\xe9\xed_\x87\xe3\xd6\x12\x17\x8b\xf4\xfc\x8eI\x89\xe0_\xaa6\xe9S\xdc\xd2 \xb5\xa6\x14\x19@n\xa4E{G\x0b\xeaT\x8b\xbdz\xb1t\xe7\x83^\xdd\xd2$TG\x97$m\xd5\xd9!\xd5\x91\x0edFZ\x1c94\\b\xfa\x1f\xf2\xec\x0d\xf8\xd3d\xf5\xe8k\x16\xaf\xa3%\xf1*M\x97a\xd1\x03u\xb5c\xb5\xc1\xc3\x8d\xaf.!\xf5\xae\xcc\x0c\x1e\x99\xc9\xe6\xaf\xbb\xc9\xfbP\x9c\xc9\xc9\x95\x05\xdbc\x94\x9b\xd9\xdf\xab\xf3J!\xce\xfc(\x8f\xdd{u&g\xae\xd2\xeb\xf0\xb1jM=\xdd\x97\xf0\x8f\xea\xbdZ\xaa\xf4\xfa(\xacUz\x9d\xe9Z\xa9A\xab\xc3/\x14|\xdd\x07\xdf\x8d\x1c\xcd\xfa\xe8\\*\x1e\xad>\n\x17e\x84\xaa?\xbe\xd6\xf2\xaej\xe1\xe8g\x0e\xbd\xe4\xe0G\xc0\xa1Q \xdd\xe3\x9dD~\xe5\xfdu\xc6\xf4\x15\x89\x91\xaa\xfd\x0f8\x97\x8a\x95\xf1h\xf4!\xa47\xc6\xcf3ya\x08)a\xe0}\x86\x1fUn\xc7\xe3\xb1,\x91C]>\xcf/Cv\xac\x81\xfd\x84.\xf4\x7f\xd5*\xf9S\xfa7\x90/\xd7A\xa6\x7fC\x8c7\xfd\xf2~]\x02\x15\x8d\xf5\x13\x0e\x1c\x92\x9f\xcb.)<3$\x0e[\xc5Y\x00Q\xcc\x1c\x16y\xc9M\x9c\xe9\x17_\xfdH\x12\x0e\x15\xce5{\x16D\xb1lv\x10\xadi\x18\x00\xd4\xe7\x92_\xfb\xccn>$pO\x02\xbf%k\x16r\xea\xeb\xff\xcc\x7fI3Z\xbe\xbde\x19\xf5\x8d\x94\xa2\xd5+\x93\xd5\x83\x97\xb7\\v\x14^\xde\xe7%\x94\xee\xf5\xaa\xe4\x06c\x9afL\xfe\xc8S\xf9C\xcd\x93\xf8\x0f\x12m\xe2\xc4 _\xe8\xc6&4c\xe5\xc0\x80s>\xc7t\xf1\xeb\xa4\x8c}\x96\x83\"~\xa9\x1a\xd2\x8c\x86\xa1J\xcd/WrV\xd2<\x8d\x99\x9c\xb9,X\xa9P\xd4\xf0\xc6soy,\xc8\x87\xb0xUS\x0c\xbfu\x07\xe1\xa5\x18\x08\xb8\x1f\x0b\x8cE\xba\xe6a\xbe2\x1a{EA\xf6\x0e?\x97\x8c\x85\xcey\x0f)\x91f\x8d\xd8l\xe7|\x9c\xf1Oq\xcc\x92c\x9a2w@\xb6\x05c\x16\x06\x1es\xeb\x9b\x95(\xcbg\x87G\x10\xe3\xb7\x99\x0bv\x98\x19\x8f-\xd9\x1c\x15x\x90;\x8a5Z\x0c\xc1KiFD\xb6\x89s\x0f\x92\x8c\x04\x91*T\x0f\xe3\x0b)P\xe3Cr5K\xce\x8b\x80\xd9\x00Y\xf3\xd2~\xa2PS\x91X\x08\x07\xae\xad\x16\xca\xce\x18\xe2P\x8d/\x12\xce\x81.}\xfd\xb2\xac\x1f\xa9\xe9\xd4^\xd3e\x9ee\xd2\x0c\xf8@\x06\xe0T\xdb\xdbHH\x8d#W\xa6\x08TF\x13FU\x9a\xf1m\xfdK\xf4\xec\xb8\x95\x92\xbf\xd8\x90\x92\xe7(\x13D\x13B\x87pR\\\xcd\xd89.-\xd8\xba\xe9 \xf5\xfb\xd3\xeaGpjtPT\xc7\xeaD\xe8\x07\xa6O\x8b\x0e\xe8\x97U\xcc\xdd\x01}\xa2\xb0z\x17X\x81\xf1;\x01\xfd\x1e@pRt\x00\xbd\x86\xd5\xd5 $\x0f\x96\x0e\xb07\xe2P\xe9\x01\xa3\x0e\x9c^\x90\xc5a\xd4\x03Z\xe2\xe7\x0e\xc0\x0fp\xfat\x01\xf5X/\x1f\xd4\xa9\xd5\x05\xa6O\xb4\x0e\xb8\x8f\xe5i\xd7\x05 'a\x07\xd0\xa9<\x1b{@\xf5\xe8\xc3\xa9:S\xbb\xc0\xe4y\xdb %\xcf\xe2\x0e\xb0\xb3\xf2\x9c\xee\x80\xfc\xc9<|;`\x7fV\x07\xb3\x9d\xbf\x12<\xc0\x1d\x19\xe5\xbfj\x8a\xab\x9do\x94\xfe\x9e.\xdd\xa8M\x82\xac\x9f\xfbf#!\xb8\xd3\xdd\xba\xd9\"\x88(`\xba\x84)\xa2\x19\xde\xdd\x9a!\xc9\xf4\xf6\xa1\xdeU\xaeq\xe4\xe9\xba\xc9p\xbf4X\x81\x8e\xbev\xc9G\xaa\x80@Y\xf6\x01\xb4Nc\x15\xec}7\x1a\x7f[P\xe6\x1d\x80\xdd\x12\x18\xa2\xe6.\xbe\xdb\xdc\xbd\x14\x9cUGc^*\xae\xab\x17X\xd6\xdd\xb9\x97\x9a[\xeb\x01'9\xb9\x1e\x80}F\xf5e\xc1\x01v\x02\xf2\xae\xadkq\xadHz\x8e\xfb\x99\xc1\xf6t\xe1a\xcd\x12\xf5\x81\xeb\xb3\xa8\xcfJV\xaa\xbd\x8f\x16\xef\xb8\xa4g\x1f\x8fLABG\x9b\x8e\x9aB\x86\xbe%\xfa\xf4\xa4\xc5\xbb^\x9f\x9e\x9cU\xd8\xcd\xf6O\xad\xef\xf6)\x19\xe4\xa7\xe3\x1b\xab\xbb}\xe3g\xe0\x88\xdb?\x81\xf8\\\xd3O\x9fO\x1c\xf3\xb8\x93~;\xeeF\x98\x1f@d\xd1\xde\xd2\xa6?\xc4\xa6\x08\x96\n.-q\x9d\xfd'\x0e\x1e\xc8H\xf0M\x17\x10\x90\xa1\xbc%\xba)9\xadf\x01u\x80\x05\xed\xb7?\x17\x83!\xb9\xa8\x94\xbd\x07\xa1/\xdcV\xf3H\x1e\x89\xa5\xdcw\xeb\xd4e\xe3\x8b\x8c.\xd0\xdb1b\x08j\x05\x1fm\x17\x0f\x04z\x18\x90`\x83\xf8\xac\x9f\x08\x96\xfe\xcb\x17\xe2\x9e(\xde^G\x85\n\x0c\x89\xdf\x0d\x16_\xaamh\xae\x820|\xc9B\x961\xcb\xf0\xdc\xfb\xd8Djll\xbd\x8c\xce\x95\xc3Iw0$>4\x0dR\xbb\xfaU\xbcYd\xef\xc7\x90zG\xd9\xfb\xa3}\xd4\x81=o\x11\x18h\xf7nc\x8f\x86\xa1\x8a\xacn@\x97\xcd.~%c\x9aC\xbc\xf8\xe3\x90\xa6\xa9\xcb\xeba@\n\xa9\xb0\xf4\x8f\xd0\xd4\x06a\xd2/\xb1\xe0-\xb0\xec8e\xb9\xcf\xcb\x0b\xed\xca\xadhM\xfd\x8a\xdf\xd3\xa85o,\x9a+\xc4\x0b\x83\xf8\x92\xd3\x04\xf8\xe6>~\xda\xb54\xa9RP\xe9\x94\x1c\x126\xae\xa4\x17\xb7\xa6\xd5\xe4\xaee\x85Mw\xf0-\xa7;\x90^\x86\xcdI\x08\xeec\x12&\x93\xc9\xbf\xc1\xdaM\x98@\xe2\xbeV(\xff\xf6k\xafy\xf1\xc3-79\xb8\x87\xbd\xcf\xecf\n\xf7V\xf5[4\xa2<\x02d\xa0\xe0\xdf\xdce\xe2\xf1\xb2$\xfc+T\x80f\x83/\xb5\x96|\x1a\xb6\xe5\xaeXF[\xb2\xa51\xa8-\x17|\x19\xa0\xd8\x81\xc8\xb8\x16o\xb9\x1f\xcc\x03pA\x90 8wwR\xbf\x18\x14\x8f\xb7\xa4\xc9q5\xf4~\xe7v\xfd\xccnb\x10\x1cH9\xae\xd4\xfd8\x94nm\xa7\xb5x\xa4\x04\x17\x8f\x7ff7\xb7\xf8\xaa/\xb8V\xf3\xa3_\xbe@z\x1e\xd7\x9a\xc2\xc6\xea\x03}\xdbs\xb5\x0c\xbc\xe5\x86\xadi\x19\x83\xfbll%\x05Eg\xf4[b\x00:$\xc1\xb7P\xe9m\xee_\xfcP9I\xbd)qNR\x8f\xa26\x05\xa0=}I\x93)q\x08\x92\xfd\x06\xf4\xad\x9c\xa3$\xe1W\xe27\x02\xf2)\xd6\x00\x9f0\x83\xc6\x8f\xca\xd0\x04 >ZLM^\xf2\xabH\xc3\xc8\x9b\xc7&\x08\x0b\xa7\xc4\x91\xa4\x1a\x92\xfd3\x18K\xbe?E\xb2\xde\xb2(\x9f\x12\xa7\xa2\xf9\xda\x00:\x8a\xe3\xb4\x13H\xb2MS\xe2\xc8\x1fo\xb8\x87\x19O\xbc\xe5\xbf\x7fH\x82\x08\x14\x84\x00?9\x9f\xa2\xc0gQ&\xf0\x89\xdfjg\x80\xa3\xe0\xfd)q~\xa0\xdeg\x9b\x85\xc5\xb3)q\xce\xe8%\x923\xd9\x15}\n\x19\xc5\xcc#&{ba\xc8\xdb\xedf\xe6\x13\xd1M\x8b\xaf\xcb\xc9S5T \xc7\xec\xc7&\xa2\xc1G!ZR\xb4U\xca\xe6\x9b\x99\xbb;S\xb8(L-\x03\xbb\xfb\xb4m%\xef\xedZ\xd6\xf0\xde\x1e|s\xc1\xd0\xf5\xb9\xf7H\xe5Z\xd6\xdd\xdec\x18%\xcc$|O\x8c\xd1\x8f\x1cu\xcb\xb5\xf7\xb4c\xdb\xec\xed\xb7n\x9b\xbdg]{\xe6\xd1N\xc7\x8ey$Z\xfe:J\x19\xea3\xe7\xd1\x93\xb6\xed4\x81\x95\xf3\ns52\x81u\xf3j\x17\xcd\x12\x83\xf9j\x0f\xcd\x12\xady\xf5\x08\xcd\x12My\xf5\x18\xcd\x12\xc3\xf8\xea \x9a%\x06\xf0\xd5S4K\x0c\xde\xab}tC\x88Q{\xf5\x0c\xcd\x9a@\x97w\xd0<9\x1c\xe8x\xec\xc2xL\xd0\x01y$\x06\xe4]\xbe\xb2\xac\xe8 \xccQ+6\xd9\xdd\x15U\xbce\x19\xada\x0e\x9c\xcb\xb3\x9f\xc0\xd2\x0b\xfegvc\xbb\xd1\xcd\x04\xc99\x03\x90s\x19\xec\xf63\xbbir\xa9\xc0\xfcV0\x1ah\xc8\x97\xde\xe3\xab\n\xb9_\x1b\x8d@\xcf~[\xa3\xb4\x7f|\xabld\xa2\xfc\xe1\x93C\x8d\xcc\xc8\x94\xc8\xb0:\xe3y\xc2W\xc7\x8a@\xab\x07DF\x15d7\xa2;\x82YAy\xc0x\xd5\x06eJ\x9cr\xc6\xee\xc1\xc9\xb6\xd4\x11\xfb\xd7s0>\xcd\xa8t\xf7\xc3\x92\x7f\x1d\x03\xd3\\-\xa0\xbb\xc3R\x1bI/\xb5\xa9\xcf\xda\x81<\xb8]\xf4;\xa0\xee\xc4\x96\xdc\x91%\xb2q&\xd5\xb5\xfd?\x86i\xff\xb7X\xf1\xb1\n\x15\xfd\x7f\x8b\xb8\xe9\xdf\x04O\xb00\xa3\xbft\xf1\x84\x1a\xf1JhCv%\x13\x04\x16\x05\xd5\xba\x97\xd5\xfc\x11\x1b\x1b\xc9\x0d\xc6\xaf\x11\xa74\xcc\xe8\xaf\x1b5\xe5\xd7zS~\xad6\xe5W\xbc)5(\x1c\xa8Ws\xff\x86-%\xc8\x91\x86\xff\xdfj\x19 \xce\xf2\xf1\xa0\xb9\xac\x9eu\xd1\x1b\x88\xac\\\x1f\xe0\xcd\xb1\xbe\xc8x\xfc\x86\xadY\xa8\xe2\x02O b`u\x11\xf8\xe0\xf5KdO\x90\xecJ\x84\x8e\xa9\x8a\x91R\x84\xc0\x80 \xa9\" \xc2\xa9U\xa3y\xd8\xb0\xeb\x85\x8co\x83\xe8O^dta~B\xe0\x82q\xc6\xdf\xf0\xabB{\xd3^\xa9\xb6\xfd\xfe\xf4\xf1uQ\x87\x91F\xa6\x88\xda\xfesl{F\xb5}x\xab\x196\xa7\xaf:3\xf5x\xcfS\xb2U3\xa0\xcfS\xf6*\xb8\x14\x13\xb25\xb9\x8f\xb6\x18\x91c\x1e\xd5\x15\xe6\xc51\xff\xf0\xb7\x87\x87\xdf?\xac\xa6\x0b&\xf9\xe1\xdf_\xfc\xb6\xf5\xdb\xe8\xb7Q-\x0f7\xd4?\xfe\xf1\xe4\xf8\xaf\xa7\x9f\xde^\x1c\x9d\x9d}\xbcxw\xf4\xf6dJ\x1cA\xc7\x8c \xe4\xf0\x08b*\xa79\x1a&\xc3\xf7\x8fU\xee\x19\x97\xb1\xb4\xbb\xf0\x081\xe8i\x9ct%\xe6\xd5^\xc6\xd2LTt\x08\x01f\xd88aqH=&\x10\xaaC\x1c\xb2M\xe8\xb8\xd9~\xb2M\xbe;p\xbe#\xdb$\x13?\x9d??\xf8\xae_@s\x1a}dy\xca\x9a=\xe9\x8a\x80\xa8c\x9b\x16\x16\xec.\xd6\xae\xf6\xce\x8aJ 6QL\x93\x94\xbd\x8e \xf0\xe4dg0\x94\xc1\x7f\x80\x8eo\xf6\xc2\xb6/\xeeY\xa4\xf6\xe4\xf1\xe3\xddI\x17\x92\xab\x0fQ\x11\xc7KL\xf6d\x08=\xdc\x91\x91\"wdH/V\x84\xdb\x12ks\xf4\x88< \xc1s\xc2\xc9\x0bB\xd1\x10_E\x8d\xb9\x19f\x90\x93m\xf2h\xe7\xd9\x93!\xa1\x03Y:\x17\xff\xb6\x0f\xc8\xa3\x01\x89\xc4\x7f7\x13\x7f\xd9X\x0b\xa4\x8f2\x97\x0f\x06d\x1b\xcd \xdbd\xd2\x96\xb9\xdb\x96\xb97@f9#\xffq@\x121\x00\xffa\xc6\xa6&\x8d T\x91\xdaD\x17\xc48lo\xab\xf6c\xcdGq\xa0+?5 _\x88\x1b\xa9\x9f/^\x90\xc9\x93\xfb\xc0G\xe6\xac;\x93\xc7\xe3'\xe3]\xe7\xf6\xb5u\xd8,\xb9\x91\xfb\xe8\xc9`(m\x91p\xdb\xa5I\xdd\x9aG{bx40\x8f\xec}\xa8\xe5\xd9\xc6\xa1\xb7\x04;\x1e)kw\xd6\xa2/'\xe0&\x8a\xfb-\xe3\xce)pV\x85\xd5\xbb\x01\xac7\x1b\xe8O\xd4T\x8a\n\xdcL\x06\x11\x1e\x08\xf4\xc7\xed\xe6\x9e\xcd\x16\xa1\xa1\xb4\x04\xf2\x8c|&N\xfd\xc4u\x1e=rDY\xf1\xeb\xb13\xac\xb8\xf3\xb8\xe7\xf8WbB\xf6,\x83\x9f\xa86\x9d\xe6\x97Y\xc2\x04\xd2\xe3EX\xe0\xdb\x7f9\x1b_\\\xb0\xf4-\xf7\xf3\x90\x81!\xdeP\x86\x87\x8b\x98\x97\x01\xa6\xfe\x90\xf0u \x86BG\x1dm\xb6:p#w\xff\xf1n}\xe5\xf1\"\xeb\xd1\x00e#\x02\xabY\x83\x8a\xf7h4M\x1ejM,\xa7\xa2\xa7MIwL\xc5J_\x12\x1dw\xad\xda_\xae\x93\xefyDU\xad-\x83\x18\xb9u\xfb<\x0eK:r'\xd8\x96\x16\x19{O\x1f\x9b\x18T&=\xc1\xc7\x9a\xfes\xc7Z\x9f;-\x07\x9en\x99\n\x1a\x8d|o\xab\x1fU\x016\"n5\xe8\xdd`@\xb2e\xc2\xafH\xc4\xae\x88@2`\xdc\xe0:\xc74\x8axF\x04oJ(\xf1\x04\xc3IhJh\xf1%\x07\xa1~\x14\x17\x8b\x99\xdd\xaf\x95\x95y\xff\x862\xb3e\x1f\xd9\x9c%,\xf2t\xf3\xc4\x87\xc8\x92\xa6\xd1w\x19\xb9d,\"A\x14d\x01\x0d\x83\x94\xf9dD\xd2\xd3\x05\x1b\x93O)+\xeb\x1b\x83\xb4\xa2xu\x07$\xe3\xf2d\xcc\x96l5&\x1f\x19\xf5\xc9J`m\x9a\x11\x15hu~9^\xb1\x87y\xca\xa4\xa8cT~\xc5\xa9\xdf\x8a\xe1\xa3\x91\xb5-~\x1b]A`\xd0\xcb\x95 \xb8\xe1&\xaf\x80\x0b\x08\x95kn\x04C^r\x1e\xa2\x19\xa2\xb1h\x86\x8c\x94\x8bf\xc9\xa3\x15\xcd\xd2\xce\xc5\xb1\xac\x9b\xd5\xa5\xa5\x114\xc2[\x0d\xfdy?Ge\x8bLK\xdb\x90r\x9a:\xb2\x14\x95\xf2Jk\xc7,\xa5xd\xab\x0fr\xa4\xc7F$\x17\xe2\x01\xe0]\xb8\xa6b\x18kW\xbf(\xff\x1e\xd5\x160\x91r\x83\xb1\x99 \x0e\xec\xa2\xec\x1d\xf0F\x83\xa8o\xa2\x14u\x82\xd14\x0d\x16\x10\x9e\xbb\xaf\xb0\xe79\xc9\xc8\x0bB\x93\x05\x88\x94S%\xe6yN\xb2\xedml\xaf\xe8\xa5^\x14\x98e\x88\xe1t\xf1\x89\x84\x04\x91\xe8\xa1j^y,-i\xfa\xfe*R\x8e&o$-')qqN3\xa9\x1b\x1f\xcd\x92\xf3\x1e\xd7\xdd\x86 9~\xe8\xb4\x8d8Q\x9d\xf2\xccN\xa9Q \xdf\x93=\xd1\x1e\xc95\x01\x8e,\xfb\xbdwN\x0e\xab\xaf\xb8\xfb\xd4\x159 ?p\x1e2\x1a\xa1\xa6\x04\x0b\xa2\x0c\xe3\xe7\xcd\xbc\x1b\x84e\xd3\xe9x\x14n}S@\x0e\x89\xbb#\x0e=5\n\x03)\x81\x88\x9b\x88\x0b<\xa2\x80\x8b\xc0\xe6\xf7\x05\xbd\xe3\x8d\xe3H\xf2z\x1dNb\xdc\x99^u\xcd]Y\x8a\xe6\xd58\x00\xe5\xdb\xbdp\xd4\xeeJ\xcb\xd3\xe8\xcb\x17\xb2%\xe8oZ\xd2\xdf\xba\xce\x12j e$\xf5\xb2\x07\x82\x0d\xa8\xbb\xb2\xd5\x0f: \x95\x11\xbd\x8f1\xa9N\xd1\x1d\x87\xc5\xaf\xe0\xad\x96\x91\xa9\x00\x9a\x83\xe3\xd70\xdf\xa6\xe3\xf3\x96%\x0b\xe6\xdfit\xba$OX9\xb1_/\x8b\x02\xed\xacf\x8b\xf3j\xd2\x85\xa1H\xc1N\x1a\xcb\x08\x1b\xd3\xcd\xa6oKV\xb9*\x07O\xcc\xc8)L\x0b>\x81\x06\xa89}f\x0d\x9bL^\x90\x9e\xe6\x97\xa9\x97\x04\x97\xfd\xe7K\xb5\x1d\x97\xa9\x89\xc6\xe4Q\xaa+\xed\xd3\x86,\xb9)\x1a\xd1\xb7\x0d+p\xbeQ\xffZ9\x1ef\xe2\x81q\x1f8.\x92%\xdc\x92F~\xa8\xa8\xe2\xf1e\x10\xf9\x90<\x18\x0cI#\xdbE\xfc\x8c\x10\xb47\x9f*\x1f\xef\xd5\x9f^=qu\xb3\xaa\xbd\x13\xecd\xaf\xa6\x15\x92\x83\x97\x81\xff\x96\xe7Q\xe7]\xab~\xe0\xa3\xe64\xb9\x9b}\xef\xe7 \x0c?2\x8f\x05k\x84\x93h\xfb\xf0U\xcbN\x90[\x0c\xdc\xc3\xa8\xb9j\xf2@M\x7f\xe5\xfaik\xea\xa7hu\x9b\xd1\xf9\x84\xcc\x94)\xb3\xe8\xd5\x8e\x02~\xa3\xaf\xd7\xb17h\xa5\xd7\xcf\xc2jz\x15c\x18\x19\xb6q,\xb2\x9b\xecd5\x7fm\x9c\xf7?0\x16}H\x98GC\x0f\\\x19\xf9\xca[\x7f\xadi\x06H\xc0#\x10\xa3T\x1b%o\xe6\x99\xaf\xb4\xd4\xab\x99v\xa2\x0b\x01\xaa\xf1%\x0d-|\xfd\xd4&\xc6\xc4\x04}\xa7\x06\x14\x1fk\xfb\xb5\xcf\xa1VCY}\xf9[\x02:\xb9\x07\xc6\xd8\x8eK\xe9Z\xfb\xd9\x07\xec\x8b\x14'\x00\xd1\xd9\xd9L]\xe8\xaa\xc4\xc3m\x1c]\x9f\xea\x08&\xcd\xef\xa2\xf2\xebO\x96\xdcl\x00M\xcc\xab \x1a\xc7\xe1\x8dk\x11\xe2`\xcfW\xe2\xd1vo\xc6\xb6G}s9\x06y\x9a<\xb0\x97\xbdk\xb0\xcb\xb3\xccGQ+6r^\xee\x8a\x0e\x8aI?\xb0<\n\xe7\x9a\xfd\xcaDp\xd3\xb5\xc4\xc8o|\xb7\xab\xd1\x18\xf4\xc7#\xedb?\xd2k\xa8z\xe1\xb4T\xef\xc0~\xd3l\xca\xb4q\n\xc8|\xbe\xb6\xaf\xb8\x16\xe9e\x1f\xbc\xb5`\x99\xb4\xb7\xf2\xb5zu_\xec\xa59\x8c\xea\x15\xc7\xf5\x908g\x9cP\xcfci\n\x97\x12W\xb2\xfa\xe2\xf6kHnxN\"\xc6|\x92q\x88\xe0\x1f\xcco\xc8\x1fD]kNI\x96\xe4\x8c|%T\x16\x9f\xf3<\xc9\x96\xc5\xe50\x01\"\x12\xeeF\xe0~q\x00\xf7HcgP\x1c\x04\xf3t|U\xedQ\x9fq\xe8\xa7\xda\xa5\x1f}\xcdi;\x10\xdb\x11qT\x96l\xae\xab\xf6\xa2\x81\xf9\xd1\x96\xe5\xdf^\x0b\xad\x9c\x02\xb6=\xd7^G\xae\xeb\xa8\x1d\xbd\xf6\xdd_\x1cw\x16\nb\xd2AAL\xfa\xef\xfc\xcd(\x08\xaa\xefih\xbb`-\x95{\xbeuX\xc2\x8e0Hp \xe6\x80\xf5R\xad, /e\xba\xce\xc8!\xd4m\xc2\xb6\n\x88:\x84\x84\x1e\x12\x1d\xb1\xfe\xccU\xb4D[~@\x0ee=;dJ\x803u=\xbd*l\xe7\x8a+x\xa7\x10`\xe7UXT\x82\xe2\xb6]\xc5\x16L\xf2\xd6\x96\xeb\x81\xd6\x07\x8c\xe6\xa0\x18\"\xab\xe8\xc1\x95\xbcqN\x0eIN\xa6jY6i\xc8k\xa5\xf9\xc1\xd5\xf5\x99\xca\x01\x1e#q\xff\xf8\xda$\x95\xbb\xee\xd3d\xe0\xe9\x1a~\xc2#`\x10\xc0\xfd\x03\xd1\x88TX\xc7j\xc5\xd5U\xb4l\xac^um^\xb5\xdf\xaf\x16Z\x93\x03\xe5!\xe0~\xb4\x1e\x87v\xa5\xbez'\xc1K\x90ti[\xdcR\xd5\x8f8\xcd\x98U-\xea\x9a\xc7KR\x83\xa9#\x19\xb0>\xd4\x1a\x83\x82\xd3L\xd4K\xf9\xe5\xda\x81T\xa8G\xf2\xb2j\x9bj\xa44\xbf\xddyN\x02\xf2\x82D\x85zf\xb0\xbd\xdd\xc4\x91\xc0\xd3p\xa5\x194$\xd1,8\x07a\x12\x9b\x89\x9f\xe7\xf2\xeeE\xfe\xb6\xb6\xad\x18\xac\xda\x0e\xf9\xb6Sh\xd9\xe7\x05\x00\xca0\x1b\xd4|\x02\x82\xce#\x00\x06\xdb\x7f\x9e\xa4\xf2\xbc\xe9\x89&\x957\xc2\xa7J\xb4\xd6\xd1[(QV\xd0J\x83\xe3#C\x0c\xb9\x08\x8e\x04\x1a\xd6\nv5\x12\xaf\x17\x94\x1aw8v[\xa0\xcaS\xd2\x0e\xb4`\xd9\xcb^\xb5\x01`\x12\xac\x99\x0fd\xd5\xab\x84\xaf:J\xac\x82\xeb j\xc9/\xceS;H\x06\x8a\xdf\x08+\x8dh\xe7f\xd6\xf1\x8fZG@\xee\xc3\xd6f\xca\xed\xdc2k4\x0c\xc1\x05E[~K\xf9B\xf7\xb8\x0d$\xc8n\xfa\x0e\x85\x81\x0b}6\x0f\"V\xa0\xa0\xe6\xce+A\x17,3\xb0\x15\xc4\\k\xc2s\x1b\xfc)\x98 %\x02[\x89\x97,\xf5\x92 \xce0^\x8fV\n\x19\xdaMMPA\xcaPAEP\xa5'\x85[\xe9\x17\xb4H\xea\x86C\xe2\x0d\xc9\x1cCD\xa0['\x0d-L\xcd:\xcf\xc6\x8e\x0bx\xd4\x0eG?\x023\xc4`g\xeb\xb5\xf0\x12\xb1h\x7f\x0cX\x1d\xb83hc,\xda\x88\x16\xc1e+\xe2S>\xb8\xf8\xb0}\x8a\x13\x1d\x1d\xd8\x17\x84\xb1G3\x97\xbb\xde\xc0\xc6\xe5\x14\x87\xdbR\x9e[K\xf2\x82\xf8\xc5\xb9\xb5\xbd\xbd\xec\xea\xb8 \x1b\xfc\xd9\x121+\xd0\x8fRN\x9e\xad\xc1a]\xa6\xfe\xcfE;\xe7\xb3\xf5\xb9\xd5o\xbd~\xc4WV`\x1f\xee\x0d\xc9\xbaC`\xd8O\xfc\x1a\x89\xb1_\x0f\xc9\xaaC\xf2e\xcaW7\x16\x83\xa1\xa9j\xa56%\xfeMp\x14\xd48\x12\xab\xde\x97\x12\xb7\xd7Y\xd8\xed\x81\xa2^\x1aL\xd1\xf8\x90\x04\xb8A\x9a\xd6\xdcn\x0e:\x084\x9a\xb3%\n\x18\x96\x08\xd9@\xc6\xbaeWD)\xaf\xbe\x0d\"\xf0fH\xd8\xb5\xc7b\xd8\xcf\xdc\xf3\xf2$a\xfes\"\x9a\x9f-\x19\x89x4Zi@\x9f\xad \x8b\xd6A\xc2#\xe0\xab\xc5\xa2\x06\xc9^\x1e\x86\x04\x82\x9a\x92\x15KS\xba`\x84F>\xa1\xbe\x0f\x11OhH\x96,\x8c\xe7yH\xaeh\x12\x05\xd1\"\x1dc\xda\xe2,L\x99eQ\x89>\n\xcehV\x1f\xa6s\xbb\xe0\xc3\x83\x9d\x86f\xbb\xd5\xa1\xc8\n\xbf<\x0f\xff#}\xb8\x18\xf6\x13\x1d\xeau3\xf3\xb6\xb7\x9b\x01\x1c\x88d\xfa\x07\xd2\xee\xe1\x808\xaf\xa35M\x02\x1ae\xe4\xa7\x80K\xe1\x15b\x00\xd1H\x91\xf2\xact\xd2\xec\xcc\x1f_\xf1\x1d\x828Hi\x02\xea\xd5\x87\x89\xd0\xa4#\xa8l\xd8A\x95\x13C}L\xbaE\x91\xf6\xd1!\\k\x83<\xb04\xaf\x9a\x0c\x86\x98\x8d\xff`Hr\xd1QO0d\xa0h,\xc5o\xa2\x7f\xdc\x8d\x86\xe4\xe9\x90\xa4\xd8\x01T\x1c>s\xe3;\xcf\xc9|4z> \x01\xa8\xfc\xcd\xe6\xe7-R\xa2\xeaR\xb3\x99\xdd\xa2\x0b\xcf\x1c\x8c\xde\xbe\xe5\x8a\x06\x8b\xae\x8d&C\xa2E\xbc0U\xe4\x90\xec\x80Nvy|F\xe4\x05I\xe0\x86R\xe9\xd2\xb9l\x16\x9dK.~\xf0\x1c\xa7b\xea1V{o\x99\xc6\x9a\x96;\xe6\xc9\xa3.{d\xac\xab\xa6\xec\x06\xd6\x11w\xb3AE\x90u?\xad\xdb{\xba\xffo\xd1\xbcF\x88t\xd9\xbcI#\x02\xbbB7O\xea\x88\x82vK\x07\xba\xfa\x89\x9e\xad\x89\xcb\xca \x8eA\xc3\xb7\x91\xbe(\xe2\xa84D\xac\xd3\xd9\xb9E\x9e\x91\x835\xd0\xc0u\x0c\x1b\x0c\xa0\x88sP\xe0\x83\x8b\x00*\xe5\x13L\x9c\xfc \xd1\x8e\xc6q\x9e.\xdd\x1c_\xbb]\x06\xb4\xdd\xbb\xae>\x06\xba\x7f\xf5^\x14Hr\xeb\xa0.]%\xd5\x9d\x1aDj^` 3\xd9\xfe\xba\xaa\x9e\xc6\x81\x9b-\x9f\x8e\x88\xdb\xdaM\x1321\x1c\xe2j+c\xb3\x83\xaay\x8f\x8c\xebdx\x95\x14i8\xd3\x05\xd4>R\x8f\x14\xb9B=\xacR\x0ff%N\x943\x81\xa0\x9c\x90\x03Q\xf5!I\xc6?\xe4\xf39K\xc8T\x99}\xdaX\xb3CB\xc74\x0c\xb9\xf7)J\xe9\x9c\x15\xf0\xd5A\xee\xbd\xbb \xa9;\xed\xd21\xca\x91\xc3`]h\xa4+e\xe4\x06\x04QL0\xdc\xc6\xb8\x11h\"\xb3+\x02z\xdez\xe1\xa3\xba\xe3\xc5\xc7=\x1e\xdf\xb8\xc9`h\xf52\xf7uP\n\xf2\xdc\xc9\xde\xa3A\xe1\xeek\xf3-\x80\x0c\x88q\xe64\x1bi\xf4\x1d\xd9\xe9\x99TP#\x07\xe4(I\xa8\xe8\xc5\xa08\x99\x9e\x0fH6\x8b\xce!0|t~\x1f;\xa2\x13\xdfO\xf6\xefr\x1c%\"\x13P\x9d)+\xbc\x9f\x96\xed=\xedt\xdcqO-\xab7+\xba\xff\xa3C\xa3M\xfb\xa6H\x14\xabQ\xdd\x05\x16\xc9\x8a4\x82\xd5B\x13\x03\xcf\xccv\xce\xe5\xa9\xa0\x8f '\x88|v\xedH\xcd\xe0d\x0co\xd0\x0e\xf85$\")\xce3\x95\x14\xe7YeSm8\x93\xbb\xbb8\x93\xb0\xff\xb4N\xae\xabS\xfb)\xee\xdap\xff\xe9\x1e\xca%\xec?\xad\x9f\xf2b\xd4\x9d\x99D\xb8\xdaQ\xc0\xb9\xd3d\x19\n\x98\x974cu\x00\xcf\x04xK\xe3z\xfe\xdc\xcc\x7f\x07\x8eD\xea \xb1 \xf2\x91-N\xae\x1b\xb5\xf8&\xc8)\xcb\xea\xf9\xcbJ>Lm\x1dd]\x01\x01\xe9_\x1dde\x82\x00\x86\x91GF\x1dnQ\x1b\x14\xfaS\xc0\xae\xea@7&\xd0\xab\x90\xd3lo\x17\xea\xac\x03^6\x00\x9f\x01\xd4\xb1\xbbA\x1d\xe2\xef\xc4Z\xd3\xde\xc65\x89\xbf\xbb\xbd\xbc\xe7j+a1\xd6\xb7]\xa9\xfb\xb6\x1b\x90G\xf8R\x9d<\xc3tk\x04\x1b\xdbzH\x90\x9aL\xcd\xc9\xb8\x143;-\x91\x0c*^\xf5\x9aHH<}<\xfb)\x83\x07\xc1~\xe0\x00\xa6\xbb\xbf\x06@\xcd\"V\xb0i\x01\xbe\xf3\xf0\x18`\xdd\xbb\xc5\xb2O[93\xbd\x04,\xab\xa4{\xe3j\xd6h\x7f\xa76\xb2bYL\x9e4\x97\xc4K\x9a\xb1q\xc4\xaf6\xc5:\x9a\xdeA&0hj\xbf\xf5\xe9\xfbZ;\x02\xb5\xf9 \xc8\x01{\x8e\x88K\xc9\x08\xf5O+\x98L\x88\x86#\x0e\xa7\xef\xc9\x0e\xf6\x15\x0d\xb7\xbd\x9d\x91\xef\x0fHapnx\x8e\xdei\xaa\xd4}\x95\x1a\x82\x19\xae\xd7W\xdb\xb8\x9a\xcd,j\xbc'\x89\xe1\xe4\x11.\xe3hluEn?\xc3\xc9\xed\x06S\x9a\x93\x03T\x0d&\x85\xf4\x86\x16L\xd8}\x95Y-\xe0\x011\xde\x89G@ \xdb\xcd\xe0\xf0\x92\xb1\xbb\x80\xc6L\x95\xd6Os\xd8\xc5\x94\xa0\xf3[\xd5\x0c\xc9\x06$,\xf1\xb1\xe6|\x80D\xcafQ\x1d#[\xa8+o\xb3\xa9\xda\x7f\x86\xc7\x93\xd8\xdb\xe9\xbe\x1a\xb7R\xbc\x05\x08v\n\x13\xe3\xfb\x18iG\xf4\xbahU\xa1\x90\xfc\xaf$\xbf\xa2YPeL\xec\xbbR\x14\xd9\x85\"\xbb\xe7\x16\xc5\x10\xa2\xe7\x85\x1aW\xd6\xda\x9f;\xea\xe6Ip\xdan0\x1a\x81mu\xd1\x06\xa9Y\xcf]\xf3`\xcd\xe5U\xb4l\xfc\x0b\xb2g2\x06T\xdak\x81^c\xb1p\x05\x95A\xb6\xb7\x13\x08\x16h\xc3\x12\x9aP\x8ef\x89E\xf5\x1d\xcc\x95\x81\xdcNe4\x8f\xa6\x92\x92U\xb8V\x0bip\xeb\x83\xbeyp\xab\x95fa\xc2\xf7\xf6m\x11\xe5\xfap\x83\x81\xab\x83='bS\x92m\xe28\x1b6\xbd+\x12\xcb\xfe3\x1c\xcb\xed?{j \x1bWo+\xd8/\x03j\xf2xH\xaa\x8e\x8aB\x9a.e(\x882\x91\xe6\xd9\xb2\x9a\xb2\xe4i\xcd\xfd\x8f\x18\xa4&\x8cR\xb0\xae86Jku\xa5\x8c&^-\xed\x1f9Knj\x1f\xa0\xd9\xb2Y\x9dH\xad} asRs)T.\xb2l\x0c!P\xc9\x01\xb9\x1c\x92l\x9c\xb0\x94\x87\xebN\x97\xaejr\xc1\xc7\xdd\xd6\x04\xfc\xba\xe9\xa2\xa6\xaf\x9a\xafF\x95r\x1f\xf5\xac\x98\x91C\xb4\xf2b3V<\xac\xc3g\xe6\x0eRIl*y\x16H}.\xad\xd7D\x15\xdf\xf9\x01D\xe0\x96_\x81\x18\xcb\xa6\x1f\x0f\x99\xac\xafZ\xaa\x0d\xfb\x94\x88%\x15TW.\x85\xd0\xc1\xee\x8c\x8e~\xdf\x19=\x1bo\x8f\xce\xb7\xa7\x83\x87A\xf3\x98}8\x9d\xed\x8c\x9e\x9d\xff\xe5\xcf\x0f\x9bG\xed\xc3\xbf\xbb\xbf=\xfc\xed\xe1\xa1{\xb8\xf5\xdb\xc3\xc1\xec\xef\xbf\x1d\xfe\x96\x9e\xffe\xe0\xfev8\xfb;\xfc:\xac\x97\x02\xb3\x04\xe7\x0fgH\x9c\xaf\xe2\xcf\x17\xf1\xe7\xb7\xdf\xc4\xdf\xbf\x8b?\xff\xe5\x9ck\x03\xa1\x99\xf3B\xa4|\xef\x0c\xc9w\xcew\x90\x07q\x80E\x81\x04\xfeF\xf07s\xce\x07\xcd\xd3{\xe6|WV\x15\xd6\x00\xe6\x00\xf0\x1f\xa2\xf8C\xf1\xe7P\xfcy.\xfe\xfc\xaf\xb2\x90W+\x14C\xa1\x12\xfe\x7f95s\n\x1fFd\xb6-\x87\xf4h\xf4\xb7\x8b\xd1\xf9\x1f;\xc3'{_\xeb\xa3\xb0T\x83\x8f\x80\x0e\xdc\xf1_\x06u\xf85ja\xf8\xdftM\xa5!\x1b\xce\x958\x06\x80\xd3\xe0(j\xd6{\xabo\xff\x89\x05\xfa \x88\xcb\x84V.r,\x86\x89s[\x99\x05\x8f\x976\x83\xc8y`\xe3\xdf\x1ch\x84\xd3\x92\x99Zs\xe7-%Uk\xacEE\x83:\x87\xedF\x9d%\xfb\xe8Yri\x93q\xfc\xff\xec\xbd\xeb~\xdbF\x928\xfa}\x9e\xa2\x84\xec8@\x08R\xa4\xe4+mZ\xeb\xc8\xcaF3\x89\xedc\xd93\xbb\x87V\xf4\x87\xc8&\x89\x18\x048\x00\xa8K\xc6\xdeg9\xcfr\x9e\xec\xff\xeb\xaa\xeeF\x03\xe8\x06@\xdb\xc9dv\x07\x1fl\x11\xe8{\xd7\xbd\xab\xab\xe8\xfa:\x17<\x06a\xa6\\\x8d\xc9\xbc\xa2S\x95\xa6\xe4\xb5\xd2\x1b/4R\xa7\x94(\xb7\x1a@\xdde\x0e\xc7\xa1Q)I\xe9\xdb\xec3\xe2\x12\xbaF,-)\x05^\x05i\xb0f9K\xe1\xebm\x1a}M\x19\x05.\x19\x04\"gU-\x81\x80\xc9Q=,<\x01_.\\\xe7\xc81(s[\x94Q\x8b\x14g\\h\xd3\xea|\xe5xp\xc4\xe9\x02\x8c9a\xa8\xd7\x8f(S\xc6&\n\xf3\x9a\x97z4\x1d\x9e\xc3\x04\xff+\xaeV\xbd{\xb7\xbfD\xf2d\x18\xf0%\xa6\xfb\x99@4\xf89 \xe3Z{|\xf5x\x91\xcbA\x9e\x86k\xd7\xf3a\x0fS\x8d\xcb\xb4\xc54\n>\xe6\x06\xf3\x17\xef\xe7\x02&\x90\x91#\xc3\xa5Ew\xbd(\x07\xf0\x16\xcc\xff\xb2\xcc\xf9/\xeb\x02\xc3\x05J\xc1\x17\\\xf8>\x92\x81\xd0\xa4\xd4\xc1\xdfV\xa4\x8e\x1c\x8e\xe0V\x80\x9bV\x18\xc3\x96\xe6\xa9;\xf2T\x10n\xe3\x07(\xa2\xad\xc9N\x1c\xa7\xd2\xc5\xdf?\x8a82e\\\xac-\xfe5\xd7\xd6\xcd\x8b\x82\x91\xffl\x8by\x02\x13py\xe5\xeb\xe9\xf0\xdc\x1b\xe4\xc9\x0f\xc95K\x8f\x83\xcc\xe8>^\x15\x08O|\xa0-\x15\x13\xbb\xaey\x1f@m\xb4x\x19\x81\xab\xa6\x18\xc1\xf0r\xb0\xc6H\xea\xfb?q\x96=\xfd\xe9\xdf\xdf\xed\x9f\xf7\xfe]\xfc\xbfo\xbc\xef\xca\x87\x8dn\x83\xfb\xfb\x0e\xc2\x8e\xea~\xe8\xc3\x81a\xd4{7\xd4\xdd\x9d;\xb0\x9e^\xe3\x8dZ\xb74\xec\x03\xaf&\xd5V#\x91\xd6\xe7\xb0\x87m\xf1-,\x9a\xdf[N\xaf\xcd\x97t\x95&}\xe6\xc3\xb1\x8f\x9e\x87\xfd\x91\x8f\xde\x82\xc3\xc7\xf0\x0c\x9e\xc0F]\x85zfNP\xc6\x1f\x81\xec\xeeK\x1c\xbeD\xf4\xcd\xf4\xd9\xb9\x88/\xdc'tz\xcf\x87\xf4\x12\x9e\xc0{z\xcd\xfb{iP\xaa\xb8^J-\x1e\x13)\xa1\xcaGpY8\xffpJ\xf2\xef\x98\xa9\xbb\xf6\xd2\x87\xf7\xa2\xdf3ZO\xbcw0\xf4\xe1\xd8S\x90\x81\xaf\x8e1\xa1}YM\x98\xb3Y2go_\x9f\xaa E\xee\x99\xe7\xc9\xb5\xb1(\xbd\xda\x82-\xba,\x18_\xf2\x97\x8f\x8bi\x96\x17n\xf1y\x0bG\x15d\xb1K \xfce\xddG[\x95\xf7\x95Uy\xef)\x12\x94f\xec\xfb$\xcb]\xaf\xae\x14\x95\x7f\x7f\xf8\x00\x8e%\xb3\xd6+<\xd7&\x9c(U\x12\x8e\xe7\xce\xb9\xe9[\xe9\x974'\xf4adP\xd5\x11\xec_\x99\xef\x81+\x00\x7fS\x1d\xb2\xa0\xec\xfb\xef\x06\xfb\x9e\x0f?r\x82\x83\xbb\xe8\xc3\x1b\xb9b\xb4\xa1?6\xee$\x88Y\x9e\xc2\x04\xdeL\x9f\xb5\\\xa2?Et<\x15\xd4e\xdezq^\x0d\xffgA\x85_\xd0\x10_\xc3\x04N\x15\xa0\xbd\x80'\xf0\xfa1\xbc\xe0\xa3<\x1d\xccVAz\x9c\xcc\xd9\xb3\xdc}\xe1\xc1S\x18\x1d<\x80#\xf8\x19z\x13pn8\xcf\xc5?O\xa7/\x1a\xc6\nrY\x7f\xee\x97\x8b~ \x19\xc2\x198\x1e\xf4\xe0\xd2\x80\x15\xcf\x8b\x12\xedc\xb9LY\xf0\xbe\xb1T\xdd\xbc\xd4\xfc\xa5\xfe\xd6\x88GO\xe1\xe0\xde=\x99\xeeA\x1b\xbd\xe3H\xc9\xc0\x86\xe8eV\xec\xc3+-vvQ%\x1d\xe4\xc9\xb3\xb3\xe3\xd3\xd3\xf2\x17\xd3\x05b\x0e2\x7f\x93\xbd\xa0\x15\xe6\x08\x9c1\n\xa1\xea\xcd\x98\x83\xbeq\xbe\xdfu%D:\xe9\xfb\x0ez\xf07]\xe8\xeai\x8d\xf0))\x01\xc8\xba\nRb\xf2\xcd\xeb\xdb\x07\xce\xbb9\xccp\xea~)\x08\x9d\x06H\x97^+\x1f\xbf\x9a\x9e\x9c[.E\n:\xc5i\xd6\xac\xe06\xad\xa4\x8a/\xf5/\xbc\x8e\x95L\xf1\x8e\x05//\xb8\xd1/\x8d\xa8\xcf\x1b\xfd\x96\x8b\xd8q\x8dm\xfe\xd2\x80\x02\xdf\"\xc9\xff\x05\x97\x05\xabg\xb3`\xc3x_\x8a\x17!y\xfe\xc5#\x84\xfa\xd6L\xde\xeb\xf0^\x97A\xffR\xe2\xad\\\x92/\x18\xef_\xb4\xbd&\xcb\x9e\x92\xbe\xfeR\xe1\x8aC\x1f\xfeR\x05`\xde\xfc\xf7\xe5\xe6\x8f\xaa\x88\xaf\xad\xe9\xf7u\xf1]u\xf7\xbdW\x11\xb1\x8b/RH)\xc6*\xcb\x94\xa4||\xe9\xd5G\xfd\xfd\x8eb\xfdeQR\xd3A8\xb1[NO\x10\x90\xcb\xb8\xa1\x82w\xab\xd2\xa6\xfa\\9\xabj62\xbb\x18\x0d\xc8\x04e\x05e\xd0\xea\xd8\x04\x8d\xbf\xaa\x88\xb54\xc1&R t\xaf\xbfA\x0f\xfe\xda\x80\x89\xba\xba&\xf43\xfc[\x1a\x16+JP%^p\xdd\xc8i:eU\xd4\x05\x05P\xc3\xa0\x992~\xe2?\x06Lc\x9e\xa7\xc5\x199|\xb6\x1f\xfa\x9c\x88\x92 \x7f\x02\\N\xae\x03\xae\x8aM\xac4'\xec\xbbNhc\xf3&\xd4\x0b\xa6Z\xcc\xe2\x95\xadPh *\x1b @\x96\x87YP\xed#2\xcb\xdd!\xf5\x14+\xe6\x18#\xc1*\x9c\xd1\xb0.\x86\xe0p\xberD\xc0\xc7r]\x0ex\xfc[\x0f\x8f\xad\xb6r\xe2\x18\xa8\xabR\x94/\x14-\xca\x16ij\x0fB>Ht7/phz\xf4\xd5y)ZOSLQ#B\x96\x89\x8a\xc7\xe5E\xec{\xab:q\xber|p\xfexp\xe8\xe0\xd7\xd4FEL\x87<\x96\x83\x18\xdc\xa2\xf2\xe1\x8b~.\xe3)\xba\xd5\xd2\x97\xe1\xf4\xc7du\xac\x18\x1d\xcd6\x91\xdcl\x16\x85\xe24K\x1b\xa1O\xd4\xb0\x81\"\x97\xe2\xb7`\xbb\x14\xc2\xa5\x8aQ\x9e\x8f\x14e\xf8\x18\x02x\xa2\"\x84>\x86\xc0\x9ef\x1d\xfdO\xa6\x81\xc9\x83q\xba=\x17\x086\xdd\x9e7\x8c\x8eB\x93\nQ\x02\xbd&V>\x97\xaa\xc9\x96\xc89H\x11\x0cH\x1d\xf5i\xdc$\xae\xcb\x0eL\xe1\x1c\x85\x82\x90\xd4\xba\xd1\x9c\x93\xd5\xc3\xac\xa2Uu\xf8\x18\"x\x02E\xd6\xf9\xa8Y\\\x9c\xc1\x04\xb2id\x11\x17\x1d9\x16B\xb5\x19\xe1\xf1tF\xd1\x08f\x06\xf1\xd5z\\\xbe\x9c\xc6jf\xe2:zI\xc0\x88\xcb\xd2E\xacNN\xeb2\x86ya[6\xadXW@g_\xf5\x8bHU\xd3\xa2\xa3\xb4\xbe\x9c\x16u\xcem+Z\n\x96T\xdd\x9e\x0dm\xcf\xa6dB\xda\xb4\x1b\x1e0\x04\xf1t\xd3\xa0\xcc\xc7\xd39\xed\xc8\xdc\x12K\xcc\xf8\xb6\x11L;l,\xa1\x82f\x95-\x16\xc8\xe7\xb8\xc09\xf8\x87\x0f\xb0./\\i?\x99\xfaQ\x9f\\CD\xb7R@D\x97U\xc4\x16O\x9a\xf4\xf7\xb9\"\xb0\xd2X\xee\x9e\xcb\xa4\x8a\xb8\x1a\x90=\xc0\xabEx\x92O1\x83\xa2\x162*V\xd2E]V\xd6\xaf=$\x07\x1c\xa8VB+\\)\xe3\x03~]\xe9\xfe\xf8\xf5\xcf\xa5\xf5Y c\xc3\xbe!\xdf\xbbmC\x94\xf0\xcf\xc4\x9f\xbcM)\xff3\xfa\xcb\x17\xd8G4LL\x93+\x0b\xb14\x922\xfc\xc3\xd7\xb1tR\x999\x13\xeat,}+\x18\xfeQ\x9a\xc2\x87\x0f\x107H\xff @\xfc\xaa\x8c\xe8\x16\xc1R>x\x04\xd8\xa2\x03\xf0G\xd1\x90+\xe8\xc1m\x87\x05T\x18\xa1y\x99\xe8\x02\x91\xa2\xd4\x9f@\x83\xe4IU\x99\xce9\xe2(\xa1x[H3\xf5\x05\xb8(\xed\x173\xb6\xc4:\xb5t\x0d\x13\xb8\xe0\x8d\\\xd2\x16a\x9bD\x17E\xedz\x9d\x13\x98\xc0u\xfd\xf5MmR\xdad\nL\xe4\xfdL\x0d\x11\x17\xcf8\n\xafJ\xb4\xa0<\x90z\x1b\x1a\xb9\x06:\xfc\xd0X\x8bA9?\x13\x1c\xa5\x84\xa7\x1a\xdc\x92sN\xb1\x08\xae\xe0\xe77\x1c\x81\x8f\xe8\xbf\x89\xfc>\x86\x1b\x85\xb0\xf4\xca\xf34t\xe2\x0d\x97YM\x99@P_\xac\xdc5\xabu\xbd\xa2\xaeW\xd45\x93]\x17\xb4\x82\xa9\xae\x15q\xc2\x0c\x7f>n\xedu\xad-D\x135+^\xef\xc23\x13\x01)\xca\x90R\xa6\xba\x8e\x15\xb6[ B\xa9.\xbe<\xd2\x7f\x8c\xb5\xba>t%T\x1c\xbc*WY\x903\xf0\x8d]\xa9\x13[<\nso\xe8*\x8b\x0f7\x83M\xb2\xe1\x18\xc9\xdf\xdcH\x17\x96\x95\xd7\xb5[K\x7fx\x08\xffb\x1bE/\xd3\xb71Et\x9e\xbb\xb2\x19\xa3|\x8c\xe0\xe7\x95\x17M\xad\xfa\x8d\xe4A>\xb8\xaf\xb8\xd2\xbc\xe7\x16@H\x7f\x15\n\xed\xbf;\x1eyD\x17\xdf\x04b\xfc\xbb#\x8e\x92\x14\xf1~U4\xac:+\x0d\xe1U\xc1\xfd\x1a\x88`\x87\x85\xf2A.\x89[`=\x8eF{/\xe9?\xdf\"E\x93\xb5\xf2p\xa4\x13\x901g\xa2\xa8\xb1\xc9\x11\x1c\x15\x83\xc1\x8f\x9f*\x02\xee\xdd(xQ\x93\xdcT\xbd\xf6J\xbd\x8a\xb1\n\xad\xb5\x18D!\x9dJ\xd2\xd1*\xe9+\x99\xe5\x98v\x1e\x8dw\xfd\x91\x87^\xb0\xefiA\n\xca.\xff\xba)\x0c\xfaB_w\x06\x84e\xc7\x88q\x03\xf9\xcb\xd3\x10\xf0X\x9c\xef\xfa\xf0\x12\xfb\x92\xb2\xe6Kx\x8a\x12\xe8\xcb~\xdf\x03\xd9\x0e\x1e\xc0\xdeL_\x9e{\x9c\xd4!L\xcd\x98\xfbR\xdc\x7f+:\xe0J\x7f\xf9\xb3O\xa6\xe81<\xc3\x81\xd5>\xf6\xfb\x06Z\xbcG\xe7\xd5'\x16\xc3\xf7c^\xed1<\xf34*\xcb\xc7Pi\x89\xb2\x10\xead\x9a\xaf\x95\xb8\xfb\xf0\xf0\xfe\xdd\x07fM\x8ck\xfc\x87\xf7\xcd\xdff\x18f\xdc\xf8\x89\x83\xf9\x81\xa5\xda\x867\xf9\xd0\xfcm\x0e\x13xP\xbd\x13'\x1f\x8ez\x0f\x0e\xcc\xdf\xb8n9:\xb0\xb4\x8a\x91\xf1\xfa\x16]s\x89~\xc97q\xbf\xbfo.\xc0\x05\xa1\xfd\xe9O\xefn\x0e\x86\xfdw7\x0fN\xce-\xe5.\xb1\xdc\xbb\x9b\x83\x93w\xdb\xc3\xe1\xf0\xe0\xdd\xf6\xbb\xef\x86'\xfc\xdf\xfb\xa3\xf3\xfd\xa5\xb9\xd2\x855\x8f\n\x7f\x92+\x96.\xa2\xe4z\x0c\xceK\xf5'Em\x8c\x19\x9bgp\x1d\xceY\na\x9c\xb3%K3\xc8\x13\xd8\xa4\xc9\x8ceY\x83b\xed\xc4I\xde\xbf\x0c\xb2p\xe6\x8c\xc19\x8d\"\xb6\x0c\"\xd1*\x17\x1dn\x1e\x0e\xc1\x8d\x93\x1c\x02\xc0R\x80h\xb4I\xc28\xf7\x9a\x9a\x0d\xe3\xab \n\xe7}l \x9b\xa6\x17\xd4\xb49\xf1\x9d!\x9d\n\x08\xc55\x82>\xcc\xcc\x9f\xb9\x8e\xfac\x90\xaf\x06\x8b(\xb1\xe5\xae\xe4:\x01\x19\xb5\x07\x8b4Y\x1f\x0bo\x1a\xcd\x9dX>\xca\xad\xf8\xcc|<\x00*\xc6\xfe\xeb ^\n/\xdc\x8b)3\xdaE\xed\xad\x1f[o\xd4A\xd5\x1e\xaeB\x85\xa2I|z\xfe\x18b\x0c\xc4\x9eR\x84X\n]n1hI?\xe5\x9d\xc6\xf6\xbeql\xc5\xb0\n\x89\xc2\x0e\x07\xa9\xe1\x00P}\x93\x02y!\xef\x82<\xf8\x89\xb98\xd5\x03\xf4\xfbC\xceON=)\xf4\xe0\xd8\xa5\x13Su\xe6r\xe9s\xc9\xd6S6@\xca \xeb\x15N;;\xcd\xfe\x99}\xdf\xd5\xb6P\xac\x06\xda\x0e\x1f\xaf:\x0d}\xe1D-\x05\xef\x84\xae\xa9\xb9\xa4jk\xee[I\xaf\xe7y\x1c\xb5\xee\xdd;xt\x9f8\xc7\x93 \xdc\xbb\x7f8z\x84R\x0b\xaf\x08G\xfc\xc5\xc1\x10\xe3\xa2\xdc\xbf{ot\x00\xe24\xad\xde\x96G\x01\xce\xb8\xbc\xea\xba\xa3\xe1\xc1!\xdc\xe1\xbb\xf7\xe4 \x8c\x86(\xc5\x88w1\xffq\xff\xde\xbd\xc3\xfb(X\x89*9\x17\xa0\xb8r0\x06\xf5\xe6\x0b\xc2\xd2K\xfbj\x8a\xf6\x10\x13\x9a\x8f\xe4\xe4#O\x9el\x00\x05\xfa\xbd\xa1\xa78\xd7{\xa0\x0e}\n\xa3!\xdc\x01\\\x9e\x0f\xb4\x1dB\xa0\xa1\xb5\xff\x00b\xe5\x18\x1d*\xf2&\x0c!\xcd\x01\xcf\x02\x05\xb4\xed\x08l\xaf\x1aQM\xcd\xa5\x07\x07\x07\xd0\x83\x07\xf7\xe0\x1bp\x19<\x81\x83\xfb\x1e\xf4\xc1u\x87\x18\xcd\x0c7\xfb\xden=\xbf\xb1\xdd<\x90\xcf\x95\xb8\xfd`I\x89\x82\xb8\x80\x98 Gp\xe22\xd8\x879\x06\x95\x03\xbe\xae\xc2G\x81\xde\xe7\xdec\xdc\x8fk\xf8\x06\x16\xf8\xf91G\xe4 D\x1e\xae6\x95\xban\x06\xbb\x13\x97\xe3\xbe{\x8d~3\xf0\x0d\xf0*._\x99\x8d\xb7\xdb\xc4\x7f\xb4\xc3\x98\x86\xdaz\xce\x18L\x075\xf7a\xe9\xc3-9\xe2\x98\x8c\x9a\xf2\xb9\xd0I\xb6\xb5\xd4\xb5\xf9\x16\xbe|8\xbf\xba\xb2\x7f>\xae\x1b\xc8\xe4\x83\xfb\"(\x85\xeeA\xbd\xf6f\x82\x82\xd0\xf3\xe1\xc4\xbdF<\x86\xa7\xc0'xc\xe8\xea\x86\xf0\x9d\xca\xf1\x89\xfe\x11\xb3\x03_J\x0b\xd1u\xaf\x87\xa1\xa7n\xba\xfa\xfcA\x81\xfb/\xdd\xcb\xddp\xfc\xf4sq\xdc\x87\x0b\x9fC\x9b\xb8>QMr!\x1f\x04\xccK\xe9\xc3\xf5\x0c]\xb6\xa4\xb0\x96#\n\xa3\xa8$\x84\x83U\xc9{\xe1\x92c\\\xe0\x11tN\x83s\x8e\x9e\x02\xd5\xde\x13j\xdd\xb85\xaf\xa0R\xc7)\x06{\x99\xc0{\xd5g\xa2\xd5^{\x84\xd9\x97\xed\xa8\xc5\x91)k\x19\xdcS\x91\x81\xfc\x16\x9e\x88,\xe6\xbc\xd6m\x837\xa8h\xba\x0fy\x81\x1a1G\x0d\xf7\x02c\x82pBn\x02\xda\x98C\x12U\xe4\x84\xfe\x82\x96rk\x1a\x9f\xb5o\x10\xa6\xc7\xd2\xea\xe2\xf8{\xbd\x18\xa1\xb8\xde\xef-P\xda3\xfbb\xc9\x07g\xc6IK\xec\xa3\x8e\x1a=\x96\xc8\xcc\xd1q\xce\x919\x14\xc8<\xe7\x0b\x17j\xc8<\xc70(\xdec\x98\x0bd\xe68\xb8\x81>\x87<\xa9\xe8,\xfd\x02\x04^\xb9K.\xf3\xc2\x1f98\x0e=O8\x15\x9c\xb8\xc7\x0dF(O\xf9\xb4\x13OAj\xafW\x97\xf0\xf4\xe7c\xaf\x17\xf3R\xf5\x84S\xd0\x86\xc7\xef\x9b\x84\xa4\xea\x9b\xadU\x17\xbebi\x16&\xf1\x18\x1c4\xe6X\xb4\xd0\xed,;0\xe5\xb2\x96\x0f] \x1a\xc33;\x9b%\x1f\xb01\xbc4O\xd5b\xb4\x10\xed\xfeh\xfe,\xdb<5\x7f\x16.\xf6\xe3\x8e\x12\xb1\\\xd8\xee2\xb4V\xebv\x90\xb3,\xa7\x98|\xceM\xdc\xef;\xd0#\xd2iJ\x99-\x9f\x8f\x16\x02n\x9b\xcf\xdb8\xa4\x19w\x1b\xdfg\xcdh\xa9\xcd\xe8GW\xe6\xa6\xb9[\xb9k\xf8i\xf3\xab\x83\xac\x0fZ\xbeD\x94n\xac\xa6Y\xf9\x88qn\xeb\x8d\x15\xc1nP,g\x14\x02\xd3\xd5c}$\x15\xffC\xdd\xe3\xcf\x90\xe6\x86\xffy8\xb2d\xbb\xe9\x14\xdfC\xef\xbc<\x1f\xe9\"\xd8\xb6\xabb\xbe\xa6\x0c%\xe5\xb9\xf8\x95\xe6\xc9\x91\xaak\xf3\x16K\xab\x88\xf58i\xeb\xec\xc56\x8a:v%\"\x85vjR;1\xde\xad\xf5\x1dC\x89u\xda\xcb|@\x84 \x0d\xf8\xf2\x16z\xec>|\xf4\x88+\xb7\x03\"Kd\xdd\x97\xde\xc9@q\xaa\xba%\xf3.\xf7\xaa^+\x91,m\x8a5\xd2\x12\x99J%\xb1\xa9e\xf0\x81\x96\xb0\x87>\xd4l\xf8x\x84\x81G\x89w\x1cbzxC\xd8\x99\x18\xf2\x8a\x07\x86L\x90\xa19M1zC\x0c\x853D\xe5\xc89\xa8\xb7\x8cqE\xde\xf5\xf6+\xc29\xd3\x0ckU;\x8ct\x01\x1d\xb1\xc3\xca\x888\xac;1\xe6\xa3\xd1q \x1c\xac\x83\x9b?\xb3[\x14v0\x85\xa9zch:\xd2\xcdW\xa5\xaf\x99\x0c\xf5\x19I\xc9 \x13PV\x1bQ\xd61J\xa4\n3\x8c,\n\xbd\x9e1\x833zLJ\xa9{\xe5\xa3\xc9\x9eMg\xc5\xfd\xff-\xfaQ\x0fm\xc6\xc55\x17\xaf\xd5\x81\xa7)5\xc6\x1a\xed\xd7p\x04\xee\x02\xcb\x16gTk!D\xa9wk!\x8c\x8eEY\xfa\x8c\xc7\x94s\xf3\xed\xe1\x85\xe7\x83\xe5b\xf1\x86k\xd6n\xe0\xc3\xdc\xa3\xb0\xd3\xd39\x1e\xb4\xf3\xffI\x16[a\x1cTr\xe0\x9c\xf2\xff}X\x9d\x17\xafV\x16\xec\x87\x02a\x82\x02\x0f\x8a\x89\xe3\xf9\x97\xcc'6\x083\xfc\x9f\x83e\xab\x8by9Q\x90\xb8\xba[CJ\x19&\xb2\x1ecgw\x02\xa1\x8f9m\xf4IWYld\xf8\n\x030atO\x89\x94\xcdA>\xebpB\x95/)gTKm.)\xe5\xe9\x96a\x94\x8bE\x10e\xcc`\x8a\xa4\x06\x05>6\xe7B\xc9\xbe\x0b\xe30g$\xb1\xd0\xc1s\xbd\xbd9[\x04\xdb(ol\xc9q,@\xf3\xd1\xcc\xce\xeb\x84\xb2\x16sX\xb4l\xa7\x97\xbe\xc6\x0dA\xdef\"\x91\xc8\xb3\x1c\x7f\x1eA\xe8\x06(\x9b\xa8\x01\x046\xea\xc0I\xa4\xe1\x16F\xea\x06x\xb5\xc2\x90wW\x8c8qI\xe3\xe3\x9d\xf1\xbf\xba\x08\x92R0\x83\x9e\xb9Of\xb22\n\xa3/\x86\xc2\xb2\xd7\xe4c\xa9\xde\x1c)U<2W\xdc\xd24\x1bF\x84\xf0\xf2\xfb\xa2\x04\xe6`o&\xd6O\x0e\xfa\xeb`\xa3\xe5\x92\\\x07\x9b\x1a\xdb+\x9d\x85M\xcfKV\xcb\xe2\xb8%\xed\xf5<\x99\x035w\xd94\xe5\x05-\xfe*\xd5d\xa8\xa0q{\xcd\x81\xbfy\xbd\xae,\xf9O\xcba,\x99\xd7Y\xb6\xa1 \x97\xbfR\x1a\xd4\xda\xea\xef5\xeb*fb-\x9fn!0\xe5#\xc6\xee\x96\x82.\xe5\x82\xde\xc5\xec\x1ar\xb7\x80(\x97S\x8e\xcb0\x0e\xd2[\xc7\xf3\x8a\xd7\xcee\x90\xb1\xfbw[-\x07V\xa5\xe8\xde]O$M\xed$\xce^iY)\xcdA\xdd\x0f, \xcf\x0f\x87\xe6\x84\xe7\xf7;\x05\xf47\x1c\xc8(\xde3\x01\"\x9d1\x14\x19\x0bb\x91\xb1 uC7\xf6\xd0\xc2\xaa\xc4O_$ \xc6P\xacB\x17\x8e\xd1\xbeV\xb8\xe6 un\x81*}@\x9f6p\xc9 \x84\xbe\x8c\xd7o\x14\xc7`\xf0\x84\xe6\x81\xf0\xe0)\xad\x1a\xaf.j\xa5\x9eN\x14\xd4\x90\x13\xf4n\xc8p\xa5%\xfe5E\x84\x1f\xd57\xf3n\xdb\x86YfL\xb9\x16\xe0\x03\x84m2\x92\xde\xc0^C\xc3\x16\xed\nt2\x9b\x9bQ\xd0\xaa\xaf\xc8\x95-.\xfb\xf9\xb0?\xfd\x89\x02\xf2\xbd\xeb\x7f\xf5o\x7f\xbc\xf3\xf57\xbd\xc1\xbb\x9f.\xfe\xcf\x87\xff>\xdf\x0f\xa5m\xc5\x12\x88L\xfaw\xccVA\x1a\xccrtD\x81\x15\x0b\xe6,\x85E\xc8\xa29\xc4\xc1\x9a\x99\"h(\xf2_\xb2\xd2\x94\xd1\xda2\xe7\x8ef\x87\xb6iW\xf5msg\xa9\xb93\xc9 \xcc\xd4/f7\xba\x19\xc3F$Ak\x88I\x7fK\xbbqWL\xd0\xde\x16\x7f\xe6I\xcc\xc6\xba\x8d\xca\xe0\x10\xa8?\"6\xbb\xd9\xb0\x0b5Rk\x7fkH'%\x06\xbc\x1a\x849\x85\x88\xa7s\xf9)%/\xa5\xb7y\x92\x9e\xef`D\xab\x8f\x13\xe3\x97u\xda\xca\xc4\xbc\x95\xe8\x9f\xb8\x0e6\xa8\xf6\xfb\xe50\x81\x89\x0c>z\x12\xccV\xed\x81\xb1Us\xc1f\xc3\xe29%\xbb\xa9\x8f\x98n`\xa3G\xb5.\xab \x85\xc0\xd0]\x97\xbe\x18:\x98\xb3\xe9\xc8\xe4\x94T\xf4\x88{ \xc4\x93%\xcb5\xa1\xe4E\xb0f\x99\xcb\xbcz\xff\x9d\xe7:\xcd\x1b:\xef\xb4G\xa1\x9d\x9e\xb1\xc1e2\xbf}\x9b\xb1\xb9\x12\x1e_\xa5\xc9:\xcc\xd8 exC\xbaB\x9c\x9eE)\x0b\xe6\xb7\xc0\xffuL\x87jE\x8b\x18\x90\xad\xd3\x00\x83f[\x1e\xbb\x96\x83j\x0f\x02\x0e8\x84$\x8e\x92`\xde\x05\x05\xf8\xc3\xc5\xa6\x94e\xdb(\xb7Y\xe4\xb1I\xc6W\xa0k\x9b\xb1\xcb\x06X\xa1\xb3\x11\xbc\xdb^n\x9bI'_\xab\xef\xc2\x88\xbdFva\xa6R1\xca?&\xe7$I\x0f\x06|w\x9feZ\xb2c\x12\x97:\x8d0k\x826\x94\x9dj9\xef\xabn\xfdP\x99Q\x91b\xd8-\xa5\xe9l\x98A\xc6\x08t\xf5\xaa\x18\x82B\xa4j\xec4\x95\xa8)K\x05\xe2\xa9\x0e\xeb2\xdc\xd1E\x18\x87\xf9\xb7\xc9\xfc\xb6\x93P\xcf\xd7\x85\xaa\xf1\xb6N\xe3\x10\x19\x97\x91\xc6\xe9UL\x07\x01\x1e\x14\x0d\xbda7\xd8\x90\x9d\xf3i\x17\xc1.\xa3\x04\xc3\xda|\x1b%\x97\x9a~\x15f\xaf\xe4\xdf/\x17B^\x91\xed\xf3\xa2\x9d\xdb_$\xe9\xfay\x90\xa3\xf3\xf4w\xe2\xef\x8e\xfd\xc8\xe2\x9d\xfb\xa2\xcb\x05\x18\xcc\x15-\xaco_\xffp\xa6\xbd\xea\xd8\xad\\>M\x9d\xea\xd4{P\xa0\x0c\xe0\xf5d\xb9\xb4\xebJ\x07\x1an\xc1\x84\xe3\x8cL'\xeaC\x0d\x1a8\x1c\xf3\xf5v\xa7\xc6\xfa6\x97Uh\xbe\x07.\x1f\xbcXT\x1e\xf9\x87\x0f\xb0\xa7u\xd0\xb0f\x80WH+\xb2\xac`\x15\xdb8\xdbn\xb8\xa8\xcf\xe6\xf0\xad\x9c\x0d\xaf\xd9\x16\xfc\xada\x95\xecH!s\x94T\xb7\xd0\xe6\xe2H7(\x90Lf\x9ci\xbb\xce,\x89s\x16\xe7}\x1a\"\x1e\x1a\x9a\xb0LE\xc6\x11u\xb3Z]\x1f\x9c\x9c\xdd\xe4\xfb\x9b(\x08\xe3\xc7\\\x8c\xcfX>y\xfb\xe6\xbb\xfeCG\x05\x97-\xb0H\x86\x8cRo\x06\xbc\x95.\xdd\x18\xaayx\xd1\xf5\xd3\x91@\x8d\xa6qz\xc1f\x13\x85\xb3\x80S\xb6\xfd\x9b\xfe\xf5\xf5u\x9f\xa3x\x7f\x9bFda\x9bWgm\x94`\n\xec \nxI4\xa5\x95\xbf\xca\xeb9!\x8521\xef/\xf2\x1b[@j\xbdPy\x11\x0db\x90\xc8\x04P.\xd6\xa5=\x0dz\xad\xcd\xb6\xe2v\xa7\x9e$\x954`\xe1,\xd9r\x8d1\xc9QdS\xe4\x17x5\x082\xe0\x8bnC\xc8\x1d\xc6\xcc\xb1\xadj\x9d\x85BP-\x91\x97\x0e[\xac\xf3\xd8\x1a%8\x92;\xcfq\xd4\xbeO\xa5\xe5\x17X\xc7g\xebz\x83|\xc5bwk2D\x8b\xe1\xe6D\xfeZh\xd2m \x8ak\x05\x06\xc1Q\xda\xfb\xd85i\x88n^\x98\xf74Kx^\xb1\x84OQ\x956\\yq\xf3i#\xeb\x95\xda\x8b\xddU\x0b*+\xa6/D\xa7\x95\xfb\x0c\xb4\xe7\x00\xbe#\xda\x97\x91\xddB\xd1uQ\x8fj,\n \xae\x15\x9dt\xb4\xe7#\x94\xa8\xbah@\xd5\x9f\xb3$\xfe\x9c\xb6\xfft\xf6\xf2\x05\xf9qX\xa9W\xe9\xbdMY\x98Y-\x18\xf2\xcc\xc5U'\x80\x7f\xff\xe8\xa1\xeaP_\x7f\xa4\x15\xba\xb5\xc4x\xe6\x0f\x06\xf5\xddhK,\xab\xeb\x0d\x92\xd06%\xb7\x85m*S\xed\xccR6gq\x1e\x06QFn\xdf\xc5o\xaeF \xf9\x00\x8a\x00\xb7\xe2\x05\xa1X\xe22\xf9FE\xfe[\xb3|\x95\xcc\xb11\xfaS\xbe'\x87\x19\x86\x7f\xf8t*\xaa\x1cx4I\x18\xef\x1cC\xe9\x9d_\xb57\x18\xf6P\x13\x0ci\x96\xca`i^~\xc3\xec\xf3\xd2o\x19\x98\xb3\xf2\xceI\xd6a\xee\xf8\xb0W,NE\x98\xb2/Vn_\xacv\xd2W\x98;\xf3\xe4\xedfc\xcf\x04\x00\x05\x1a\xdc*\x8f\x0ftF\xef\x8f\xb8\xbcit\xe7\xfb\xe8\xe6r0r\xe2\xc5O\xe7?N\xde\xa8\xe8\x87k\xe9\xf8\x84\x7f\xa8\xc2\xe2\x87\x96\xc5)e\x0b\x96\xa6( \xd0[\x17\xdb)BRj\x1d|\x7f\xf2\xecy\xed\x0b]\xc7\xb7\xc0<\xaa\xdex\xd12\x8a\x92k6G\xb6\xf0\x1f'o I\x81\xb7\x06)\xfb\xdb\x96eyfB\x08\"rR\x83w\xe3nV\x99E\x07\xab\x8c \x83MV{L\xb1!/\xdf\xddq\x0cV\xc3F3B\xabxP\xbam8i\xbam\xc8\x9f\x94.\xdd\x93\x05]\xcb&\xd2\xc3l\"\xd0V\x1d\x0f\xf7\x04\xf3\x9b8\xc6\x06\xec\xcc3\x97\x16P\x83[\x10\xd7\x91\x0d\xaf\x13\x83\xf4 \x16S[W\xeb\xf6\xa6}_\x93\x86\x0d\x951\xf4\xd3\xa3w\xf1\xfe.\xbbY\xdb\xacq\xdb\xd5\xd0b\xa3\x08\x8a\xec\xe2C\xed\xb6\xbf\xfeH\x7f\x07\xb9qc\xa7\xb9A\xd0\xf7*\xf5\xab\x9e\xb5\xf2\xf9\x9c=\x98[\xf9*q\x84\\O\xb8B\xaa\xf3\x04\x1c\xe1\xea#\x95\xe4,\x0f\xf2-'\xb7\x0e\xfd\xe5`jLN\xf3\xe4\xa71\x1c\x0c\x87\xa2t\xf2^\xc5\x8b\xa5\x8fO'\xfc\xab\"\xe7\xe2\xed\x138TU\xe8\x95\xb49\x14\xbfj\x1da\x9118/\xff,\xc7f\xe7\x05\xbe\xce\xb5r\xfc_\x84\x9a\xab\x90\xa9j@\xd5\xd2/4\xf0\xb0\xc1\x82\xe5\xe68rW\"\x16\xa0\x19*tS\xc2\x18\x9c\x8a%\x01\xa7g\x08w\xc6\x1fy@5\x06\x87\x0e\xa7\xa80\xfaX\xcac*|E_\xcd\x8dp\x85m\x0cN\xa1\xd0h\x8dp\x0d\xa3\xf8\xd9*\x00\xf2'Oo[\xcca\xda\xa1\x03o\xdf7eO\x96\xcfG\x98\x05\xe8R\xd7\xd5\xad~odo\xcb\x8c8\xb6l\xc0R\xaa\xe6k#\xfel\xda\x0bM\xfd\x1e\x83\xa3)\x1aT\xa9\x8e\x9ef\xd1\xa8d&\xf4\x10r\xae0\x95\x9dtv:\x95\xfa\xd6\xb9\xe3\x17.P\x85\x1aV\x7f}\x1c\x05\xeb\x0d\x9b\xd7\xbf\x9e\xc6\xf9\xe8\xbe\xb9\x92\xe9\xfdi\x9c\x1f\x1e\x98\x8b\x9b\xde\x7f\x17%\x81\xfd\xc3\xfd\xbb\xe2\x83\xe5z\xea\xba\x93\\\x06\xba\xeb\xc6\x9d;\xc07\xe9/!\xbbn0\xbf\x99\x81\xc0<\x88\xa5\xf4K\x13V\xda0\xe3\x8d7;[\xe9\x8f>\xb4\xc2\x01\xb8\xd5E\x8d\xc4E\xf3@\xebP\x93h-\x11\x9b\xa8\xf8\xbbX\xd9\x11\xa3\x90\x0cB;\x8f\xdd\xd4\xc2\x82$\xcb\"\xf10\xd8L\x99\xe5\x8e\xa1V@$wO\xa0\x07\x8e\x8f\x81\xb1al\xba\x8f\xef\x97\xc6?g\x11\xcbY\xa7\xad\x17EU\x97|\"\x86\xbc\xda\xe5\xf6\x97,\xef\xd4\xb8\xda8\xb9@\xc4F\x82\x8c\x0e\xbb\xf5y\x8e\xcb\xa9R-\x1d\xaf\x82\x9d\x1c\xd0d\x07\x15\x07<77;w\x96\xfb\xca*\x93l\x80\x80\xf2\xea hk_\x08Ym\xb9Y\xe5SI\x96-z\xf4\xacs$\xe7B\xa6\xfc\xe1\xd4\x18\xe3s\xbaqT;\x957\x8c\x11\x9d\";\x98,\xa4u\xd1vkV\xdf\x8f\xba\x83A\xc3 9\xe0)\xb9p\x904\xa32\xfa\xde\x9bM\"\xfaT\xd0\xd5\xe57\x98L\x87\x99\xd8N\xef;\xce\x84\xc5y\x1a\xfe\x16S\xe9\xb6/S\x0eL\x06\xcf\x0fh\x99R\xc51H\x9b\xa1\xc9E\xc8\xb0\x00\x96\xb3\xf8[\xe4\xf3\xcfO~8ys\xc2\xf9%W\xd8}\xa1\x9e\xfb\xe0\xbc|\xf5\xe6\xf4\xe5\x8b3\xfe\xe7\xab\x97g\xf8\xe9\xd5\xdb7\x8ea\x81fZ\x97\xb3(\x89Y\x97\x15\xd7\xa4\xb2\x19ZP\xfc\x86\x15\xbcL\xe6\xb7\xfa)\xdbi\x1cZ\xee\xd8\x1aWP\xa4\xcb\xd7\xc6\xe9\xa9\x97\xf3\xd2\xcb\xf9gNe^9\xf9o\x9a\x14i\x0fc]\xdb\xb0k\x84\x85\xaa1\xae\xaa'\xf6JB\xeb\x18K5D\xd3M\x1a\x94\xcfm\x1a\x8d\x95\x9a\xb2\xc3*\xcf\x07\x9d\xfdi$\xba\xd1\x92\x91\xc5\xa8}\xa1\x1a\x82\x82\xe8\xcb\xe3X\"h5\x9b\xcf\x98R4q\x16N\xd5\xf3\x11\xcc\xd2\xd0\x95\x88c==\x1c\x8e|8\x1c\x1e\xf0\x7f\x0e\xf9?\x0f\xf8?\x0f\x0d\xe82\x1f\xa4l\x1e\xa6\x1d\xd2\x8d\xcb'\\\xa8\xfc.\x97\x9a\x95O\xb7\x96i\x11\xb7\x94\xbb\xa9Pjg\xc9\xdcz@_\x02\xdd\xae\xfb\xd0\x05\xe2\x9a\x95\xa7(\xa1\xa3\xe6\xc6\xcb\xc6;\x80\x1e\x1b|\xafT\xee\x84\xff|M\x06A\x98\xc0\x8c~f\x9b$\xc6{\x9ds\xfe\x1b5\xe7\xae\xab\xaf\xadQ\xcdi-n\x10v@\xb7\xbe \x99\xc3^\x9aml\xa1(\xfc\x9f?\xfe\xf0}\x9eo\xc4<\xec\xa6\x9apG\xcf8\xd0\xb0\xaf\xb9\x14h;\x1e\xb6\xd2\xa7r\x0dB\xc4\xb0\x13\x91\x92\x8f\x02\x9d\x8d\x1br\xc1\xf9Y\x14\xc9m\x13\x9b\xeb\x8a\xa8\xbev\x97\x110#\xa9\xfe0a|qR\xd1\xf8\xdb\xd7?\xa0\xca\x1c\xc2\x11\x84\x03\xed-\x8c\x81\x95\xfdI\xfe\xb3/\xf6\xa3\xcf+\xb5\xf8\xbcH\x93\xa2\xea\xc8\xd0\x0b\xe6\xe9\x97?\xf8257\x19\xbb\x82\xc7\xe0%x;\xe6\xf8\x08\x16\x9d\xa9\xb1|\xd2\xaak\xe8\x0b\x96_'\xe9{i^\x87E\x10Fln\xf2\xfd\x90\x8f\xe8:\x0f\xd7,\xd9v:o\x97\xcf\x17\xeb|\xc3b7Q\xc7Q \x9d\x7fa\xaa\x1d'\x8cg\xd1v\xce\xe8\xf0!)\x9d\xf6p\xc9*\x1c\\\x87\xf9\xea\xb8tND\x15\xd5\x16\xddn\xe46\x96|\xc1\\m\x17\x05\x17!/\x0c>\x00 B;\xf9G\xcb'\xe4\xea\x95\x80:B\x03\x8b\xbb\xb4|\xb8$\xc9+\xc5sWsoO\xb4C\xb7#:\x8a\x1b\xeb/mR\xa9\x99\xd8\"\xf9\x1cl\x92\xe8v\x11F\x91\xc9+X\xfd\xe5:[y\xd1_\xbfk\x90\xb1h\x01G\xf4\xdfXS\xb1>\xeb\xa2l\xec>\x1a\x9a\xae\xaf\xf0\xf7\x0f\xcd\x17\x92\x1e>\xb2\xdc<*\xef\n\x85!\xe6\x84\xb0\xdc\n\x1e2\x8f!)\xbfUQ\x02\xc6\xb5\x9c\xf7\x9f9\xbf\xc3\x87\xd5y$j\x1e\xf5\xf9\xd5!\xeb2\x0df\xef\x19\x9fHg\xd3\x00f\x84\x9b\x9e\xd7e*\x83\x0d+\x8c\xe7\xe1\x8c\x95Zo\xe7\xab\xd4\x01f\x96\xa3\xe4s]zJ\xd9\x86\x05\xad10@\xeb\xa5\xdej\x19d\xeb\xf7\xd2\x9e\x079+Y\xcdN\xcf^\x92\xe1\xac\\\xd6\x1c\x8dg\xce\xa2p\xcd\x15\xb31\xde\x0e\xae}\x97\xc1n\xf6\x0cR-}K\xc7\x90\x8a\xe0\x13\xb6\"\x7fA]\xfde\x1c\xdd\x8e\x8d9\x063\x96\x86A\x14\xfe\xc2\xf8\\vX\xad\xa0v{U>\x86\xbd\xc8\xde\x87\x9b\x17\xdb(\xca,c@p\xe6\x05\xbe\x0f\xe2y\x84\x91Q*V\xf3J\xa3\xba\xc6\x0eL\x04~Q\xf1\xc82\x1f\"\x9f\x8buE\x88\x04\xd3l\xa4%\xdb\xc0R\xd1\xdbZv\xa0{\x82F\x1eV\x89\xb8Xwe\xba !\xdd\x82\xaft\x7f\x0e\xbe\xb6Tq\xe36\xd6RW\xc2\xaf\x9a\x04\xfdP\xb9LQ\x06\xb4\x15\xa7\x93|D[\x01\x0c\xe8\xfbf\xb8\xe2\xcd\x9f+\xf4\x8fm\x81u\xb0{\x9c_\xa1\x84U\x8f\x97A\xefe \x80\xea\x87t\x10f\xe2V\xc1\x95\xa7\x0d\xff\x08\xa6s\x17#\xc4\xc3\xb8:\x07\x8f#\xfb\x84\xa3\xfd\xdc\xcd\xdc\xab\xd2\xa7s\x18\xf3\x9a\xb1^F\xb8x\\y\x9eA\xa5\xe2\x9b\xbd\xf6\xd1~n\xb2\xe0\xe0\x96\x15\xcc\xf0J\x0d\xd1\x10\xff\x8f\x97-\xdf7\x8a<\x0f\x8f\x07\"\xcb\xd6\xdaU\xdc\xdbJ\xda3\x13t\x808|\x98\xc1\x11\xdc\x0e\xb2$\xcd\xdd\x19\xdf\xe0. \x9a\x94\xa9\xf3\x92\xbc\xdd.\xe1 \xac\x95\xb7[\xafw\xd9\xa4\x7f_\xc0\x04\xd6\xd3K\x8b\xc1\x0b\xdd\xbd\n\x80\x9d^`&\x07wY\xbd9\xef^yp\x04K\x99S\x86\xb9\xbc\xa8\x0f FP\xf3Z\xd0\x96\xcf\xb3V5\x86\x1e\xb8\\8p\x06|\xe7/T\x9e\xd2\x0b\x95\x9b\xb4\xb9Q\x03\xd1\xaa\xbd\x91\xfb_&CfQ\xa0\x91\x99\xa9s\xfd:\xe1\x0b\x80n\xe5\xa6\x83 \xcb\xc2e\xec\xfe\xfd#606\xc6\xcdQ\x01\x99\x02\x89\x07x\x8aS\xdc\xf7-\xbd\xd7\xc8W!T\x05\x05\x810\xba\xd1\x9c\x88\xfa\xab\x00\x03\xa0_2\x08\xd4\xe4j9E\xaeD\xdc\x1b\x0do\x82\x81bjp\x04[\xed\xd7X\xffV_\x89\x19\n\xc4u\xe2\x11\x0c\xea\xcc\x01\x8e\xcc\xaf\xc7\xb05\xbc\xae\xf7\xb5\xb0\xf7%\xf9\x14u\xa1~a\xcb\xf2W\xbd\xc1\x8d\xb5A\x11\x18\xea\xa8\xf8s\xac\xa8X\xbd\x1d\xae\xa2\x1b\xb9N\xb1\xb1G\xda\xdfES\x86\x05]\xd9\xdb\xca(\xa5\xbc\xf8\x83N\x8b\xea\x0d\\\x15;K\xb0\x85\x9eU\xcf\x93\x1cy\x8e\xf6\xb3^u\xdd\xd0\xb7.n\xd0 Jop\xa5\xf57\xf5\xd6\x97-\xab]H<\xdaji/\x8be+^\xd6\x91\xad\x04\xd4$\xdc{\xea/4\xa2\x0bo\x93r\xd5\"\xf3U\xa7\xc8\x15\x89h0gi\xe6\x17\x1dY\xb0\xf3m\xfc>N\xaec\xa1k@\xb2A\xf1g\x93&W\xe1\x9c\xcd\x8d\xf8)\xc2\xb1\xe2\x80\x8b\xae\xa6\xb2\xa7\ni\xb7l\xda\"\x8c\x08\xa1\xd1\xa1\x95s\x12\xf9\xces1/\\\xfd\x06\xae*\x80\xba/&o\xd7\xab\xd5\x07z\xedc*\x82*oF!D\xc6\xc2)\xe8\x98\xee.:\xe1\xfd\x0bj]\xbd\xf8s\x8d\x9d\xa2\xff\xc2w\xb4h\xc2\xc0R~9\xe6\x8a?*&\xa8\xba\x07X@\xbc\xe1lF}\x1csE\x9f\xeb\x15\x8e^\xa7>\x9b\x1b\x98@8\xbd\xaeL\x06\x83\xc8\xb8U\x96\x1f{\x18\x0d\xeb\xce\x1d\xc9\xdc\xabw\x1c\x15\x0f?#\x1e~\x06O\xe0V\xe3\xe1g6\xe1\xf6\x18&p;=3\xf0\xefE\x89w\xc7\xd3c\xe2\xdd|\x07N$\xb7\xcd\\\xfe\x1e\xa3\xf8\xde(\x0e\nG0\x97$\x83C\xd6\xca\x87+\x9f\x0bV\x17>,\xab\x8c\xf5cm]\xdec\x07\xe8f\x16\x19\xcc\x9c\xcf\xd0P \x90.\x98\xcf\xff\x9f-Ko_\xa5l\x11\xde\xf0m8r\x0c1\x9e\xc4\xce\xbf/\xf2 \x0c\xe1\x08\x9eA\x0f\xdeW\"\xfc\xe0_\xbf\x8az\xdd\x82\xeb]\xf4nEN\xcd*\x12~Vn#\xb6B\x1c\xa4\x7f\xe0,v\x0c\x07\x06\xa5\x91\x1c(Qi\xa4?ME\x9au\xd29\xdb\xe4\xab1\xdc30\xc1 \x0d\xd6,g\xa9\x18\xc0\x88\x1d\x1a\nEA\x18\xd3j}1]0\xe8\x10L\x05\xda\xbce\xd5\x0ekl\xeeH\xcb\x92\xb1\xffn\xe0N\x7f\x1aL\xcf{\x1e:\xb2N\xffmt\x8e\xf7\xfa,\xbeW 6z\xdf}7\x9d\xfe4}w~\xfe\xcd\xb9gK\\\x03b\x16\xe5\xc2\x94h*m:\x86\xe3\xd4\x0d\xc5Gq\xa5\xda'\xb2\xc5n0!\x85\xbdb\xd6p\x8e\xcd\x97\xa9\x16\xcd\xacZ`/\x1e\xe8[ \x98/\x0c9Z\x15\x1504\x1a\xa5\xab\xae\xc0\xb0$\xdav\x83vF\xa7\xe2\x86;[`=\xfdQ\xc4R\xe4\xf6VB\xb3\x1b`\x08G\xb1\xa88\xa6\x08\x9e@<@\x90n\x0c\xf3\xcdg\x1cA\x0fC\xe7\xef2\xf3`::\x17[3\xf2\xa1/\x02v\x7f\xc6J\x04\xc6\xa0\x14`]\x0ci\xab\xe1\xdd\x8a&HQ\x92\x10\xa3\xc0E\xe8M\xd6\x01tA\xb0Ry\xb9\x0d\x1c\xa9r\xca\xf2\xa2%7\x1b\x89\xe4\x03\xc3\xc7\xd0\xef'm\x8d\x81@\xd0\x90\xa2\x98\xb3i\xd2\x90\xda[>(9LE\x0c\xb6\xc0Cl\xc44\x08\xd3sO\xb28\x9b{\x99\xfet\xb8M-\x1f\xb4\x18\x97\xc1\xe3H\xf2\x86Y\xca\x82\x9c\xa1\x0eg\xd2\xefl\xcf\x95\x08\xe5\xc7\xb7\x8d\xd8b\x91\x9f\x91+y\xe7\x95\xd7\x81\xb6\xc6\x1e\xc9\xd7\x1a\xfcq-\xcc\xbe\xc7\xd5\x87S 4_\x9f\xc6\xb9\xbb\xf5ad\n\xd9`z\xf6\xc2\xecE\xf0\xc2\xcdp\x88\x01b\x1f\x06\xbd\x17\x06\x9a\xcc\xc31\xe3\xab\x8c\xc2\x8c\x8a\x1c\xc8i\xc6P|\xcc\xe8\xd3\x13\xa4\xc7\x8a\xa9\xc1\x91\xda\xc0iv\x8eQ\xf0\xc7\x10N\xb7\xf8g\xeb\xc0\xcc\x18\xa2?\x1cT\xc3\xc6R\xcdm\x08l\xb3\x0f\xe5\xa3\x9b \xec\xa9\x15\xa9\x98\x9a?\xc3\xcc\xf0 \xf6\x84X\x88\x03U{B\xe9\xbd\xd1\x9e\xa0JX4\x96\xe7l\x07{\x02\x8ei\x10.\xe3$e\xba\xe4\xa7dB\xc3G\x1f\x87 \x8d\x0c\x13S\xacl\xbd\x80\xb0D\xbef\xcb\x93\x9b\x8d\xab}\xf10I\xa5n\xae\x085s\x85\xe4\x12\xbc\x83\xba\xe5S~\xc3?eI\x8c\x83=\x11\x9eZ\xc1\xa0\xf8\xe9#f\xb1\xcd\xb1\xf0B\x0e\x06\x17\xea'f\xa5\xc8f\xc1\x86\xbd\n\xf2\x95\xba0\x8b\xa5\x0c\xefy\xf1ml\xab`\xfcR\x1e\xfe\xd6\x90\xd7\xaf\xd5\xad^\xc0c\xbb\xcf\x01]\xd0\xbc\xccXzE\x1e\x9c\xd3syk\xf3\xf2g\xa8f\xfc\x80\xba<]\xbdQ\x17\xed<\xb4\xb6@\x95\x9cv]\x06\xb3\xf7\x14\xc8\xad4`\x98\x98\xa2mV\x07h\x8a\xfd=\xab/I)\x8b*\xe5\x9cJ1-\xb9\xa471<\x81\xf41\xc4\xbd^]\xcb@\xdb\xce4>\xa7e\xc3H\x0bd[\xb7N\x0d\x19VlQ\xb7/S\x16\xbco\x99\xd9\xc2\xcd\xe9\xbe\x88\xaf:\xe3\x7fm8\x14s\x11\x0b\xd3D\xa8\xdfR{E\xabJ\x81\xaaz\x1b\xa2\xa4\xe1\x08\x81R\xc8\x8a\xefF#q\xa8\x1b\x891\x94\xad,.`\x8a\x15\xfb\xa8n\xfc\xf0_n\x88\x89\xbf4jY\xdf\xac\x85\xab\xb2\x01\xd4,\x1a\x18b\x82\x92\xe9\x98\x96\xda(\xa4\xe7\x83<\xf9\xd3\xd9\xcb\x17@9X'\xea\x85k\n\x14\xa3\xe0\"D\x9epAK\xfdg\xce\x9ar\x8f\x84\xa1\xf2[\xe6\x91\x98\xb37\"\xde\x17\x94\xac3\x99\xb0\xced\xfd~\xa3X\x83\xe6\x18\xe4T\xd3\xec\xbc\xc1\xa2\xb8\x97\xd6.\x8e\xf9\xb0\xf1*\xd2g>\xdd\x9cWt\xd0\x08Mf$\xc0\x94\x8f\x98rO\xc5\xac\xb7\x9bg\x92\x0d\x1e\xd9\xac\x93+\xd6\x90o{\x13\xe4\xab1\xdd\x0c\xdc'\xf3\x98\x81\xe0\xb9\x1b\xfb\xc5\x1c\\HK\xae\xd7\x16\x03\xd2\x95\xc8\xf9\xc2\xe7n7\xaf\x18\xf2ADP$i\xa2\x1f\x86B3\xbd\xd0\x8c\x0b\x89.\x89\xa2\x1cJ[\xe7\xcb\x85\x1d2\x11`;\xee\xde\xd0o_r(\x96\x1d\x05\xf3\x86u\x87\x1d\xd6\xbe\xb9\x15\x11}9\xd5X\xa0;kr\x81\xedjF5\xfbEm9\xe0*j\xb2W`\x8f\xb9YDNMm\x08\x15\xb5\xcez\xbd&\xeb'\x07\x8e\x0d\x9e%f\x0d\xc0Q\xc3-f\xc3-\xae\xfau\xde\xbf`>\xff\x87\xed\x1d\x1fm\xd3\xf6u\xd8=\xcd\xc5X\xfd\xc5\xa5\x1c\xc1\x96\xdb\xeciZQ=+\x02\x97\x94:\xb6\x80\n,\x99\xbe\x9bE\x9cR\x08\xb3!\xf1\xf5\x82\xa1\xe7\x94`871tPL=\xd7\x98\xba\xd2\xe1\xf9\xeb\xf2\x9a\xd4\x02 \xf1\xda\x898\xdao\x95vJz\xb9\x90?\xb9bq\xfeC\x98\xe5,F\xfb\xa3\xed\x93\xeb\xac\x93m\xc6\xb6\x1b\x87\xac.\xd6b\xef\xd9m{!lk\x9e\\\xc7m\x05\xdf\xb3\xdb.\xc5f\xab ^2,\x85\x807Of\xdb5\x8b\xf3\x81\xfc\xe3$b\xf8;\xc8\xf3`\xb6\xc2\xda\xae\x93\xc4\xe59u\xad\xa5O\xb1k\x9d\xea\x8c\xbb\xd6+/@\xd7Z\xfazt0A\xc4\x15\xb9;\x16\xaa\x01iO\xb1\x99J\x9b\x80z\x86y[\x8c m\x84\xddV\x12\xa7\n~!R'\x1f\x03\xc9+\xf4\xc3\x12\xc9C\x9e\xadw%r\x80\xc7>\x8c,\x08\xc9 _\x87\xaehH\x02\xb1\x0d\x13\x0d_-\xc8h,i\xc0G{\x8bu\\\xb3\xb5\xa9J6\xe3\xdb\x9c}\n\xbeUju\xc27SO]0\xa7\xdeW1\xb5\n\xeap\x8eT\xc0\x01\x85n`\xd7@I\x99\xbcRD\xd6\x8fd\xad\x8aYJ&\xa8\x19\xff\x8dv\xbe\xb4\x9b\xa0bp \x91F\x90B\xb1Em\xbd\x9a\x01\xac\xc9h\xa8\xb4\xe3\xcfI\x02\xd69\xadW)\xe1\xafQ\xa9\xd63\x94\x1d\x95~\x8d!\xf6\x06\xd9*\\s\xf6\xdd:/\xb9dZ\xc6\xb7%\xeer\x86'\xf2v\xa2%\x06\xdd\x12q'\x90\xadi\x92\xa7\xd9DdH\xab#}!-Ck\x0d\xf6\xa3mo\xbd?C\xee\x17uK\xcb\xac\x82\xd2\xfb\xfa\xb1\x19\xd3\x8c=\x9d\x9ce\x99\x0f\x0e\xff\x831\x87\x1cij\xb56\xa2\xfciv\x12o\xd7\x14\x11\xc3P\xf7\xc3\x07\xdd\xa5\xec\xa3Kq4\x0b\xc8\x89\xe1\x08}\x0b\x12oPD\xb3\x9f@JVR\xfdUb\x04\x94\x9d|\n\x8d`JQ;p\xe12\x11F\xad\xfaQ\x85\xf4(\x1d\xa8Y\xf6F.y1ih\xba\xebU\xda\xd1\xe6\xf1\xb1\xc1,\x89\xb3<\xdd\xce\xd0\xc0=\x99\xe8\xdf\xd0t \x86\xabv \x8e\x8aI\x8d\x0d#3A\xb9\x1d\xea\xb4\x93\xcc#\x0ee\x11\xb6\xaa\x9fh\xf2\xf7\x1a_\x1c\xeb0:)9z\xd7\x8bR\xa2\xc8#Sz!\x07\xcf\xe5K\xed\xb5\xf4\x9b\xb6\xe1\x96!g\x8f\xc4e}\xc8 \x0d\x00\xb3\xc2\x8c\xd58\xb4/\x81[\xc9Bo\xea\xcc\x90\x7fG\xe9\\\xeb`\xe3\x86\xcdc5\xe4\xa4\x91\xf4\xdcz$,\xe9y\x15\xbdE\x80%7\x9f\xc6\xe7\x18W\x9dM\xe3Z\x10\xfc:\xb57\x8c\xca\x90\x87\xa6\xa4\\+\xbaZ\x18\x82G\x15\x83\xa3*2\x1d\x9d\xf3\xb5\xd4\x7f\x8eIX5;\xf0bT6\xb6\n\xae\xc2d\x9b\x8e\xc15\xf4u`\xed\xeb\xa0\xdc\xd7\xc19\x1e3z\x83r\xabx\xc5N\x9a\xd5J#Pg\xe4|\xeb\x9a\xad\x0d\n\xb91&u\xb9\x15\xcf'+:}\xf3\xa5\x13e\xc4\x85\\%\xf2F&Y\xb7\x94\xbf:\x9dF\xe7t\xda\xad\x1f\x91\xceD\xe2\xe8\xe1c\xd8\xc0\x13X\xa8\x067v#\x18o\x11#WL7\x0d\xa7\xe6+.\xf0L\xe7\x0d%\xae0\x97\xe3\xaa\xc1\x12\xb5\xc6\x12\xe1tn\x8b\xef^\xba\x8a\x80W\xde\xec\x12?\x96- \xe3\x13X7\xa9\x1b \xe6\x8a\x0e z'k8\x02>\xa8\x0e>\x83!%\xc0\xce\xd0\xebk\xba\xf4a\xeb\xae\xbcs\xa3\xbb\x99|D\x9clQs[\xbbz \x1fu\xadE\xa76m\xf3\xd7\x8av\x9a\xfb-\x1ex\xdb\x86 \x1f1V\x07O\xbd\x1d\xe1\x17VA\x13Z2\xe9+pk\xbe,)\x9f\xf2\x1a\xd8\x07\xa0\x97Z\xd5J\x18\xd5\\\xfd\xc0H5\xd3)\x17f#\xd5\"\x12$NA\x90\x84\x1dA\x8en\x1ecL\x1e\xcd)\xc1Hd6(R\x1a\xf0\x02\xe7zk\xd3\xd4,\xefg\xe4\x16Q\x8c\xdd/\x06=\x88\x93\x1f\xb7y\x907*\xe6j\xf0\xcc8\xf8\\\x0d^\xe6g\x18\x92\x1e\xcdH\x8f\x06\xc1\x07\x8a\x81V\x0f \xd5@\xc9\xbf\xd1<\xd2\xeb0_\xbd\xc4+R5\xdfI{\xba\xd5L}\xafl]\x8b\x8cg\x0f\x0c!\xf3\x8fC\xec>\x1a\xdd\xab\x10\xa0\x8b\x0b\x96\xfd\x98\xcc\xb7\x11^\xf3\xdf\xad\xcb\xd8\x1d=x\xc0\x17\xd0}t@\xff\x8d\xee\x8b\x9f#\xf1\xff\xa1\xe7\x97\x05[wt\xcf\x1b\xfc\x95\x05\xef\x7f\x0c6]\xfah\x10]}\x99\xc9\xf7p\xe4\xb9U?\x8ePtV\xbd,C^\x0e\xa3\x83\xbb\x95\xf7[j\xea~5Y0\x0d\xfa\xd1\xa8\x1a\xbb\"\xa2\xf2\xd5\xe6g\xf8\xfa^\xd5{d!\xbcG\x0e*\xef\xf1\xdcr\xb0d9_\x91\xf2\xa7y\xc1\xbb\xc2\xec\xe4&gq\x16^F\x95\xcb\x1e\x9c\xedd\x83\xed\"\xcb\x93\xb4\xf2\xe9\x8a,\xca\xa5w\xed\x01d\xab^\x076\xaa)Y\xb8\x88\x8ag\x904\x86%qbx\xaed\xd3V\xd7\xe3\xf2\x98\x97FYg\xc9:\x05\xd6\xc0{\x13(A\xdb\x89\xbf\xa4q\x1bcj\x06\xf9\x88 \x0b?\xe0\x1c\x8e`\xe5.\xc4\xec\x1d\x01\xcf\x8e\xe7a\x0c&\x94}1\xfa\xb6HU\x14\x16\xb37v`8\xf4\xab\x8b Yy\xca\xedAK\xb2\xc1\x9c-\x0c\x83\xf4\xd1?d\xc7m\xb8\xadj\xa8\xee\xa3\x83\xa1\xe7\xaaV\xf1\n\xde\x12o\xbb\xef\x0d1\x96Q\xb1\x963\xb7\xcd\x18\xf1\x00\xf6&\x80\x96\xa5[\x0fs\x7f\xc9\xbb,\x8b\x94\xb1_P\x18\xa4\x17\x9e{\xe5\xf9\xf0\x80\xd6Yc\xff\x1fI~\xdf\xba.\xa6l\xe3\x9f\x8f\x0b\xad\xd0]\x977I\xbb!\xb3\xf4|\x08\x06/NN\x9e\xe3\x01\xba\x0f\x89;u(\x8e\xae\xe3\x83\xb3\n2\xfe\xdf\x92\xe5\xfc\xbf\x8c\xe5\xce\xb9\xdf\x00w\x12\x96n\xb5.j\xeb\x8c>\xf2\xb5x\xc1!\xc6L\xd2\x1a\xcf\x0d^\x1c\xa0`:'\x03\xc4\x1c\x9d\x10\xcc`@\xb0\xb7(\xd2\x7f\\,\xc4\xe1TSP\xe3P\x065\xbeXL\xd99\x8d\xc2\\Zj\x86|U@\xe8\x9b\xbc&\x8c\x0d\x97\x18\xec\x0e\x91\"\xa8-\x02i^\x8b\xe5\xffQ\xdfc\xfa\xbbs\xa2\xf0G\xa3\x87\x96\xc8I\x8dh$\x07\xc6\xae]\xd4\xbe\xf5\x10\xaf\x9d\xf8b1\x82\x1a\x7f\x10\x1c\xab\xc6\x96\x04\xbbz\xe4\xb9N\xb6a\xb3\x90\x95\xd2\x84t\x93\xd8\x10\xf8\x8cb\nj\xe5\x1c?LW(\x84\xf1I3\xa2\xa0}\x8a\x9c\x85PJBHK\\\xcd\xce\xe5\xa9\x1c\x08\x82\xa6\xfb\x90\n\x90T\xe6\x10\xf2\x18\x9a\x86\xe7\x9e\xf2\x1f\x12\x85\x8b\x1c\xf1\x92\x96R7\xe3\xd6T\xf6\xdd\x85\x03Z\xe7\xe1}\xe3\xfas\xf6o\xe6\xba\xc2\xcd\xb3Z-0\xef\xa6\x10\x1a\x86UaBH:w\xab\xef#%\xaf\x18\xa5\x86\xaat\xd0$5DnU\x92\x9b\xe3\xdb\xea\xc8WxxT\x86\x93\xaeR\x00\x1b\\`\xea\x07\x17\xff \xd2\xb1\xae\x1e\x10\x94~\xae\xdbN\xcb\x90\xb2\x04hrojg\xd9\x86\xa3P\x8cr\xe3\xb2A\xd0D\x94+\xe5\x19\x17F\x10\xf0j\xa5\xaa\xd9\x90\x0b\x98Zk\xd6\xc3\xaa<\xd2A\x16\x91|a)\xe8\x9c5 \x94:\x83\xcb\xa7\xa3\xc6\x15Z\x05\xad\x01\xd2\xa4\xc8\xb2W\xf4\xda\xd4b7\xf9B\x1e;4\xcd$F\xe7yT\xf5r\x99\x021\x10\xf1\xa5Y=\xbete\x1c\xc4|\xdb&'WT\x043\xd6\x01\xa0M.\xca%\x00\x18\x9cv\x0d\xb3\x11\xb5\xfe;\x07\x99\x88%\x90\x07\xa2\xb9\x8f\x97\x08\xf6\xf6\xfe\xbb\x9aTF\xfd\xe57(fe!e\\#u>\x84\xb6\xa9\xa3\xdbc)J\xa35\xc4\xeb\x96\x7f\x8d\xb0E\xe7\"$g\xd7\x8b\x9c\xdcE\xd8\xe0\x82S\xbcU\xaf\xe7\x83@r\xa2\xcc~a$\x04\xbc|\x97\xb9)\x8e\x88M\xc3ss*|\xfb\xd2\xa5n\xa4\x8b\\\xe6av\xdbv\xf9\xa0Gg\x80\x92\xbd\x04\xf3\x91]x\x97@\x9b\xec \xe2s \xbeR\xd2s\xeey\"\x11\x03I\xf71_\x93\x99\x1b\xab\x9c8\xc8\xe4D\xfe\x85X\x89\xfd\xc6\xbe,\xee3\x1d0Z>\xff\x88\xd9\x8bD\x0f\xa6\xa9\x9bgi\x80\x10\x1f\xa2f\xcc_\xd4\x91\xc0\x86\x01)YK\xd1\xb7x\xcft/\xb8<\xa1\x14'\xc4H\xbb\xc8\xc5\xa5\x9bt\xcaP9\x9b d7\x0dM\xa8\xd8c\xb8*P\xfb\x0f\xf0\x05$\x94\xaa( \x04D\x8b9\xa3f\xb6\x08\xcc\xf6\x06\x12L\xeeU[\xc9,RQd\x91Wf\x16\xf9fa\x16\x876$uW\xc3\x9b\xce\xf1\xf5\xdd\xa17X\xd4e\x13\x8b\xf9\xe6\x8a\xea\xdcm\x15\x82%\xa5$\xed\xf3\xd6$\x13_\xe2y\x003\xd8\xe6/`\x02\x97\xf5\xd7\xd7\x9c\xbf\xe1!!\xa30;f?\xd4\x13\x98\xc0\x05G\x86\x8b&m\xef\xc6p\x1e%@\xf3\xcaz\xba\x89\xcd\xba\x18\xad\xe7D\xe5\x16\xe1Rx`W\xa5\xf9\x83*\xf4\x85'\x93*\xb8\x1ez\"\xb9U\x95\xca\x83#p/0\x91\x8b\xaen\x1aqm\xc6\xbf\\\xa0j\xea\\\xcc0\xeb\xe2\xe0b&\xa4\xc1K\x9dO a\xc0\xebsK\x1f\xf2\xe9\xf5y\xcd\xca\xc0)\xc0\xca\xe5\xcb\xe9\xa3\xc3\x94O\x04\xd3\x173\xf4\x97,\xf7WA\xe6g,\xf7\xdf\xb3\xdb\xcc\xa7<\x1f\xbe\x98\x8eO\xb7\x0f\x1c\x99\x9e\xce\xe7\xa3\xe9&&\xe0\x16\x82\xbcnZ\xa8\xacu\xb2\xc1 \x8c\xe1\x84\x9c\xcdq\x03\x1c\x1c**L\xa4Em]}\xc3K:{S\xa8uN\xb4e\x16 \xbe\x9e\x9cn\xa1LA\xfa\xd5\xc2\x8d\x0br\x8e\x06\x07\x1a\xae:\xaf\xb3\xab\xec*\x0f\xd1\xc5\x8c\xab\xec\x05\x05\x1frr\xed[\xd5})\x0f\x15z{R+W\x15\x89=\x9f\x82H\xcd\xcb\x8b\xe0d\xe1/\xcc1\xf1\xf6\xb2t\xdc&\x9a\xd1,\x06\xbc\xb5\xfaPjP<&(^W\xcd=dIY\xfap\xed\xf9\x90\x95G\x1a\xe3\xadOe\xf0\xf1|\xd8\xb8b;n(G\xd3\x85\x0f\x89\x9b\x0c\xfe\x03z\x90\x0c\xfe\x8a\xff~\xe7\xc3\x8d\x9c\xf9\x9a\xb3\x90\xb3\xc9J\x98\xa4\xcd\xb0\x16\xa1\x1eTy\xaf\xec#\xe72=O\xb5\xe7\xc3\xfe\xf4\xa7\xa0\xff\xcb\xb0\xff\xe8]\xff\xab\x7f\xfb\xe3\x9d\xaf\xbf\xe9\x0d\xde\xfdt\xf1\x7f>\xfc\xf7\xf9~8\xc8Y\x86\xb9\xd7\xcc\x81Wd\x82\x97\xd9*H\x83Y\xceR\xceW)\xcd\x00,B\x16\xcd!\x0e\xd6\xc6\x9c/\xca\xfa\x94'?$\xd72\xaftyq-sn\xb6\x84t\x9e6\xeb\xd4\x99\xc1\xf1\x11t'$#p\xc5\x98u\xa4\x95\xac\x82\xd6\x10\x93Iv[\x957{[\xfc\x99'1+9\x88\xb5$<\x11\xb7\xa2\xccI\xac\xc0\xa8\xe2\x99\xdf\x1a\xbcF\xc4\x80+i\xc3rS\xb2\xb0\xd6\xb5\x92\xb2C\xbd\xdf\xce\xd9~\x0d\xde}\xa0\xa5\x02\x14\x97sJ\x19\xf2\x13\x0c\xfd\xb1S\xbe\x0c2\x1eQ\xd6bs\x82\x0c\x91\xf9\xbf\x1e\xcd\x14\xbd\xeaL\xddu\xe9\x8bM\x87\xe7>0c\xe86\xadG\xdc\x03q\xee\xb6d\xb9\xe6\x1e\xf7\"X3\xae\xfd\xef\x90!\xaf:\xd7\xa9)\xab\xdcGS\xe6B\xdb\x1e\x19|\x13A]k\x90\xd9\xf8\x95\x04-\xb2 \x0dR\xc6\xe7S\xcd\xdb\xf2,JY0\xbf\x05\xfe\xafc\xba\xcc\\\xc9\xef\xdfi\x80\x06\x7fF(K0\xb5\xd4LM\x81\xec\xd8\x8eY\x93r\x97\xcf6\xdbF\xb6D)x\xff}\xb7\x8c;\xb1\xcb(aZw\x1bO\xa7\xa52\xf8n\x82F\xf1\xf8Z\x15\xb9\x97\xcdT*FW\xa9\xdc\xce?\xf2\x01\xdf\xddg\x99\x96\xac\x96\xdc}:\x8d\xd0\xe0\xc7 \n\xda0\x86\x8cvCP\x04\x9f1\x8cE\x9fQ\x91\x8f\x98\x03\xecm\xce~\xa0\x0b\xbb\x0d3\xc8\x18\x81\xae^\xd5C\x15\xfc\x12'\xd4i*QS| \xc4S\x1d\xd6G\xd54\xdf\xad\xa7E \x0f/JY\x05\xe9\"UC\x12\xa0\xd0\x9c\xdd\x81yZ\x0eE\x91\xd9\xdc\xa0\xa6\xcbG\xf9\x05\x16\x89\x8e\xbe\x8d\x92K\xcd%\xbf\x9a\xecXo\x9f\x17\xed\xdc\xbeL~\xcd\xfb\x90\xe1g:\xf6#\x8bw\xeeK\xcf\x7f\xce\xfb\xab$@\xef\xd8\xad\\>u\xc1\xa2I\x86\xd0z\xd7\xd2mC)\x87\xd4\xba\xd2\x81\x86[\xe8\xf7\xc9\x04\\\xca\xec\xc0:4\xc4\"\xb7\xb9;5\xd6\xb79\xbdB{\x00\x03\x90&\xf1\xf2\xc8?|\x80==S\xb5}\xcd\xd0\x00\xb3\xac\xc8\xb2\x82U\xe8\xd7-\xbe\x95\xb3\xe15\xdbr\xab5\xac\x92\x1d)\x84+hm\x0b\xab1\xa7\xe5\x83\x05K\xf9\xdffI\x9c\xb38\xef\xd3\x10\xf1\xf8\xd6\x12\x04\xadT7\xab\xd5\xf5\xc1\xc9\xd9M\xbe\x8f\x01\xa9\x1es1>c\xf9\xe4\xed\x9b\xef\xfa\x0f1\x04W\x05\x8b\xe4\xe1\x98z3\x10W-Z\xbb1T\xe3\xed\x7f\x0e\x12\xa8\xd14N/\xd8l\xa2\x90\x92<\xee\xdf\xf4\xaf\xaf\xaf\xfb\x1c\xc5\xfb\xdb4\xa2\xe8\xfc\xf3\xea\xac\x8d\x12\x8c\x96a\x8d\x88)\xd1\x94V\xfe*\x8d&!i\xcc\xe6\xfd\x0d)d\xb4\xe44\xf6B\xe5E4\x88AY\x12]\xb1j\xb1.\xedi\xd0km\xb6\x15\xb7;\xf5$\xa9\xa4\x01\x0bg\xc9\x96k\x8cI\x8e\"\x9b\"\xbf\x98t\x17\x82\x0c(\x93]\xa3e\xa2\xcb\x989\xb6\x9d\x9b\xb7\x99\x04\xda\x12&\xb7nq\xc9\xaaY\xa5\x04Gr\xe79\x8e\xda\xf7\xa9\xb4\xfc\x02\xeb\xf8l]o\x90\xafXl\x8aM\xfdQ\x92\xdf\x9c\x88G\xeb8\x7f\x13Pl\x17\"`G\x11P>vQP>\x15\x91\x90o\xb3A\x16\x94\xcf\xc7_\x0bM\xba-A\xc9\xf3\xbe&\xfd\x91\xbfzaS\xcde\xdc\x17\xf2\xba\x1f\n\xaf{u\xb5E:\xdf\x9f+\x1b\xc7`\x91&\xeb\xe3U\x90\x1e's\xe6\xe6\xd3F\xd6+\xb5\x17J\x99`\xcbk\xfa\xd1\xb2\x10\x9dV\xee3\xd0\x9e\x03\xf8\x8eh_Fv\x0bE\xd7E=\xaa\xb1($\xb8Vt\xd2\xd1>\xc7\xf37B\xd5E\x03\xaa\xfe\x9c%\xf1\xe7\xb4\xfd\xa7\xb3\x97/(\x06\xaf\x95z\x95\xde\xdb\x94\x85Y\xab\xe7\x0f\xf9\xf5\xd1\xfd,\x0fU\x87\xfa\xfa#\xad\xd0\xad%\xc6\x08\x94`P\xdf\x8d\xb6\xc4\xb2\xba\xde Q\xda\\F\xf9T\xf1\xcd\xac\x94)\x95\xe9\xbf\xb9\x1a%\xe4\x83\xc2Gv\xa5r4\xc7\x98\x8f\\e\xd7\xf5\xe4NQ\xd6VlL&p\xa5\xf7\xc9\x9c\xd1\xdbd\xce\xfcR\x82\x18`\x9a$\xcc\xbb\xc2l\\z\x06\xf6\x8a\xbd\xc1\xb0\x87\x9a`H\xb3T\x06K\xf3\xf2\x1bf\x9f\x97~\x7f\xf8P_\xa1\x0f\x1f\xc0I\xd6a\xee\xf8\xb0W,NE\x98\xb2/Vn_\xacv\xd2W\x98;\xf3\xe4\xedf#\xed\xbe\x8d\xc8}\xabe\x1a\x87\xa7\xd0\xa7{H\xa6\x8c\xdd\x1f\xdd\\\x0eFN\xbc\xf8\xe9\xfc\xc7\xc9\x1b\xc7+\xefcN\x7f\xa8\xc2\xe2\x07\xe5\x9d\xc1W)[\xb04EI\x80\xde\xba\xd8\x0e\x99V+\x1d|\x7f\xf2\xecy\xed\x0b\xf9\xcbZ`\x1eUoN\xf90&4\x9b#[\xf8\x8f\x937\x90\xa4\xc0[\x939\x873\x13B\x10\x91\x93\x1a|5\x8e\x8f\x0d\xf7\x17\x1d\xac2\x82\x0c6Y\xed\xd3p\xedz\xf2\x8c\xfe\x8ec\xb0\x1a6\x9a\x11Z\xc5\x03B\x1e\xd1~cxb\xfe\xe0\xf6H\x0b\xba\x96M\xa5\x87YT\xa0\xad:\x1e\xdc \xe67q\x8c\x0d\xd8\x99g.-\xa0\x14d\xf8\xed\xeb\xd3\"&\x19\xd7\x91\x0d\xaf\x93\xeeq\xe1:[\xb77\xed\xfb\x9a4l(\xad\xf4\xfe\xbb\xf4\xe8]\xbc\xbf\xcbn\xd66k\xdc\xb4\xda\xe5\x8d\"(\xb2\x8b\x0f\xdd2\xda\x8b\x8d\x1b;\xcd\x0d\x82\xbeWi\xed\x0e\x82|>g\x0f\xe6V\xbe\x9a+_\xfa\xbf\x17\x82\xbbH\xd0-\xae\xeeI%\x99R\xd5SXs\xfe\x17\xe6\nC\xf7\x0d\xf9i\x0c\x07\xc3\xa1\x8c\xfe\xfa^\xfa\x85\x88\x8fO'\xfc\xab\"\xe7\xe2\xed\x138TU\x8a\\\xf8E'\xfcW\xad#,2\x06\xe7\xe5\x9f\xe5\xd8\xec\xbc\xc0\xd7\xb9V\x8e\xffc\x8a\xfc\xaa\xa1\xb1j\x17)/7\x1axDZo\x1b4\xaf\xac\xc7n\xba)a\x0cN\xc5\x92\x80\xd3\xb3\xe4Q\x92\x07Tcp\xceD\xcc\x88P\x06\xa6\x90\xc7T\xf8\x8a\xbe\x9a\x1b\xe1\n\xdb\x18\x9cB\xa1\xd1\x1a\xe1\x1aF\xf1\xb3U\x00\xe4O\x9e\xde\xb6\x98\xc3\xb4C\x07\xde\xbe_=\xc3\xd0\x9f\x8f0\xc3\xe0\xd4\xcd\x94\x174\x97\xca\x91\xbd-3\xe2T\xa3\x1f\xcbGJ\xd5|m\xc4\x9fM{\xa1\xa9\xdfcp4E\x83*\xd5\xd1\xd3,\x1a\x95\xcc\x84\x1eB\xce\x15L`\xaa\xe2\xd5\x9cJ}\xeb\xdc\xf1\x8b(6\x85\x1aV\x7f}\x1c\x05\xeb\x0d\x9b\xd7\xbf\x9e\xc6\xf9\xe8\xbe\xb9\x92\xe9\xfdi\x9c\x1f\x1e\x98\x8b\x9b\xde\x7f\x17%\x81\xfd\xc3\xfd\xbb\xe2\x83%,A\xfbuP\xf9H^\xc0!\x94o\xd2_Bv\xdd`~3\x03\x81y\x10*[\xaf\xb0\xd2\x86\x19o\x9cS\x88\xdd\x87v\xa5\xc4\xc1\xd6\x10C$.\x9a\x07Z\x87\x9aDk\x89\xd8D\xc5 \xd5\xca\x8eP\x94D\xb5\x9d<\x83\x9a\xae\xde)?\xbeu\xb0\xb1:Di\x05`\x82\xa7\xd0\x18\xfd\xd4\xc7\xe8\xa706$\xff\xc1 ^\xc5\xf8\x85\x93z\x97\xad\x17EU\x97|\"u\x9f\xf6J\xfbK\x96wj\\m\x9c\\ b#\xe4f~T\x9a'\xa5{l\xebx\x154\xfbFU:\x96\x1d\xd4\xc2Bs\xe8h\xeb+\xabL\xb2\x01\x02\xca\xab'\x80\xa0\xad}\xe9\xf3\xdb\xe1\x1a\x14\xd4\x02\xdc\xc8\x1e=\xeb\x1c)\xdc\x8d\x88L\x95\xfb\xc5\x18\xe3st\xfc\xcak\xa7\xf2\x861b\xd0\xb2\x0e&\x0bi]\xb4\xe5\xfb\xd3\xf7\xa3\xee`\xd0\x92\xea\x8d\xc9\xc8lfT\xc6\x8b\x89f\x93\x88>\x15\xf23\xfe\xf5'\xd3a&\xb6\xd3\xfb\x8e3\x11\xae\xd2\xbf\xfeT\xba\xed\xcb4\xae\xdf\xf7\x92O\xd3\x94*\x8eA\xda\x0cM.B\x86\x05\xb0\x9c\xc5\xdf\"\x9f\x7f~\xf2\xc3\xc9\x9b\x13\xce/\xb9\xc2\xee\x0b\xf5\xdc\x07\xe7\xe5\xab7\xa7/_\x9c\xf1?_\xbd<\xc3O\xaf\xde\xbeq\x0c\x0b4\xd3\xba\x9c\x89\xf4\x17\xad+\xaeIe\xd2\x13\xdc\xbe\x82\x97\xc9\xfcV?e;\x8dC\xb3+\x96!\x16\xf5G\x1f\"Bnm\x9c\x9ez9/\xbd\x9c\x7f\xe6T\xe6\x95\x93\xff\xa6I\x91\xf60\xd6\xb5\x0d\xbbFX\xa8\x1a\xe3\xaazb\xaf$\xb4\x8e\xb1TC4\xdd\xa4A\xf9\xdc\xa6\xd1X\xa9);\xac\xf2|\xd0\xd9\x9fF\xa2\x1b-\x19Y\x8c\xda\x17\xca\x90D\xb7\\\x84\x96\xc7q,\x83nDm\xa6\x14M\x9c\x85S\xf5|\x04\xb34$/\xd5L\x0f\x87#\x1f\x0e\x87\x07\xfc\x9fC\xfe\xcf\x03\xfe\xcfC\x03\xba\xcc\x07)\x9b\x87)\x05\xd8\xed\xc4\xd2\xb8\xa0.RK]jV>\xddZ\xf6:\x88\x97UwS\xa1\xd4\xce\x92\xb9\xf5\x80\xbe\x04\xba]\xf7\xa1\x0b\xc45+OQBG\xcd&\xeb\xa4|,\xea\x93\x11\xf4\xd8\xe0{\xa5r'\xfc\xe7k2\x08\x02\x86^\xe5?\xb3M\x12g|{\xe7\xfc7j\xce]W_[\xa3\x9a\xd3Z\xd3%\x17\xd0\xad/H\xe6\xb0\x97f\x1b[(\n\xff\xe7\x8f?|\x9f\xe7\x1b1\x0f\xbb\xa9&\xdc\xd13\x0e4\xeck.\x05\xda\x8e\x87\xad\xf4\xa9\\\x83\x101\xecD\xa4\xe4\xa3@g\xe3bN\xa7gQ$\xb7Ml\xae\xeb\x91\xb1\xc4\xee2\x02f$\xd5\x1f&\x8c/N*\x1a\x7f\xfb\xfa\x07G&\xa2\x0f\x07\xda[\x18\x03+\xfb\x93\xfcg_\xecG\x9fWj\xf1y\x91&E\xd5\x91\xa1\x17L\x0f(\x7f\xf0ejn2v\x05\x8f\xf1\xc1$\x97\xcb\xe7\xa3\x8f`\xd1\x99\x1a\xcb'\xad\xba\x86\xbe`\xf9u\x92\xbe\x97\xe6uX\x04a\xc4\xe6&\xdf\x0f\xf9\x88\xaes\x8a\xfe\xfd\x0f\xe9|\xc3b7Q\xc7Q \x9d\x7f\xe1\xe5&'\x8cg\xd1v.\xe2\xd4%\xa5\xd3\x1e.Y\x85\x18\xa5\xec\xb8tND\x15\xd5\x16\xddn\xe46\x96|\xc1\\m\x17\x05\x17!/\x0c>\x00 B;\xf9G\xcb'\xe4\xea\x95\x80:B\x03\x8b\xbb\xb4|0j\xe4 c\xf1\\\x0f\xa6\x9ah\x87n*}\xa0\xf6\xd2&\x95\x9a\x89-\x92\xcf\xc1&\x89n\x17a\x14\x99\xbc\x82\xd5_\xae\x9e\xc1\x163[\x90lQ\x8d\x85\xf6\x07\xd1xiqv\xbai\x94\x9bn\x19\xdd\xbb\xeb\x0d\xc8\x98b\nd\x1b\x1a\xb7\xc0lQ\x14\\\xc0pLQ5\xd5J\x13\xa2Q'\x10\xcd\xa4*\x8d\x9b\xf4\xc6\xe5\x03\xd1|\x13m\xeb\xa9\xfe\xaa\xb6\xd0\xc6\xcd\n\xb5\x18\xef2\x89\xec\xdd\xf2`W\xf9Ml\xe9\x9eQF\xffE*KN\x910\xdc\x9a&\xe7J\xc4\x1b\xcd\xe0I\x11N\xfa\x88k\xd6\xc2\xbf\xe2Y\xee\xa2s\xfd\x8b\xe0E\x9d\xcee\xd7!\xae\x9a5\xdb\xfd,\xc8\x18\x0c\xc7V\xc0\x97\x0dX\x8f\xd7\xe5\x83\x0d\x1d>\xb0\xb7$\x1f-\xd9\x80\xb8z\xd5\x10Y@>\x98\x86\xad\xb9\x18\x0e\xe0\xeea\xfb\x00\xf0J\xac\xcb\xd7\xf4\xf0\xa0\x85\xdb\xc8\xc0\x86\xadm\x06\xd3\xa8\xd73'\xea\x94\x8fY\xf2\x82\xe6\xc9\xe1\xa4F\xf6\xfe\xb9\x0c\x1b\x92<6\x83\xa7\x13\xb8\xfb\x90On\xc6!\xeb\xde\x03\x0f\xd7z\x06}\xb8\xfb\xd0>O\xe5\x95\x8b\x0d\xdc\xbf\xa7\x1ax0,\x1a\xb8\x7f\x0fz0\xb2\xdc\x10\x86\x1d\x1ch\xa9\x97G\x0fT/\xa3\xe1Ac\xf0<\xf9\xa8\x15>|\xe0k\xcb-p\xab#\x045\x96\xb2o\x10\x08\xb0\xe5+\xf1\xe8\x01\xae\xc4'l3\x1f\xe8\x81}\xa0mPp\xd0\x0c\x05\x82\xc4\x98\xa0 \xfd\\(H\x7f\xe7P\x10\xea\x10\xf1\xeb\x83B\xfa\xd9\xa0\xa0F;\xba\x0f\xdf@\x0c=\x93Q\xfd\x0f\xf6_\x82\xdf\x05ER\xe2\x08\xfaz\xea\x94\x8f\xbe\xc6\xca\xf8\n\x15\xab\xa2XVP\xf2\xf2;\xb8w_2\xaa\xc7\xb0\x85'pp\xef\xfec\xe8\xf5\xb6\x1e\x04\xd3-\x86#\xfe\xa3\x03=p]\xfeqt\x1f\x8e\xc0\x19:\"]r\x0f\xb6\x05\x97\x1d\xdd\xf7<\x9b\x87\x8d\xcc\x9e\xd6hFo\xb8E\xd9\x9b\xf0\xfe\xca[\\\xf2ft\x9cR\xceP\xe1\xac\xc8\xb4T\xc5F\xcdRj\x94%\xb6j:I!\xf0=<$\xf9\x8fkNw\xefi\x7f\xdf/\xfe~\xa4\xbd\x1f\x1dh\x1f\x12\x0e\xfb\x87\x8f\xf8\x8c\x12\x0e\xfbw\x0f\xd4[B\xdc\x84\x10W\xbd%l\xc4\xb7\x8f\x86\xea-a\x0f\xbe\x1d\x1d\x1cX\x04xtd\x80>\xc4*\x1dh\xce\xd7P^(BE\x9b\x8b\xd3|K\x0f\x1e\x12\xbdO9T\xfb\x80\x05\x83ib\xb1\xdd*\x82\xc1\xeb\x1e\x0c\xef\x1a+\x8f\x1e\x1d\x00\x0e\xf7)\xdc?\x87\x1e\x7fs\xf0\x10>\xc0\xfdC\xb8\x03\x9dZ\xbew\xef\xe0\xd1}5\xe7{\x0f\x0e\xef\xde5utppWv4:\xd0{\xa2\xbe\xe1\x0e\xdc?\xdcm\x00\xcd\xd6\x87\xb0\xc1v\x80\x10\xd2\xeb\xe9pW2*\xbd}}*\x94\xb1\xb7\xafOa\x1dD\x8b$]3\xab\xdb!\x08\xfb\xc5hx\xc0\x07]\x81P\xdf\xb4\x18w\x87\xf0\x81\x12\xc5\xdd\xbfw\xef\xf0>b\xad\xa8\x9ex\xf0\xe4 \x8cx\x81\xd0\xf3p\xbd\x1e\xd6\xd6ktP[\xb0\xe6u4\x0e\xbc\x03\x01+\x02\x890\x8c\xfbT\x12qs\xe8\x15\x80\xea\x95c7\x96\x15\x95\x96\x88\x05\xd4\x97\xe5\x8e\n\xef\xd8\x94\xb9\x85#K\x98}\x17\xc6!E\xe4:\x02\x87\x93?,~\x99$\x11\x0b\xe2zSG\xe0\xe4\xe9\x96!Y\\\x04QF\x7f9\xfa\xb8\x0b:,\xf5\xa5hw}\xc9\xae\x1e5\xc51,8\x02F\x1e\x18vQ\x87h\xd1\xc2\xc5-&\x0c\xa4[+U\xa5\xc8\x9c\x0fX9\xf1:w\x04MF\x87UgR\xb9ht\xa5\x12\xfa\xd2\xd8\xca_\x89\x0e\xd8\xa2\x18%bD\xba\xe6H\x96\x03<\xb3\xa9\x7f\xe4\xf8B\x99b'\xf6d>\xa6%,qM=\xe3\x83\xcc1\x1c\xa8\x88$\\\xbd\xdbrvL\xd9\xf29GZ\x10+Z\xc0\x13\xd8r\x1e\xb4h2\xe1S\xaa\xe1EC\xa6\x879\xa5$n\xc9\x16\x11\xba\x19\xe6\xb7\xedU\xd3A\xca\x87\xafm\xf9\x12\xf8\xbcQ\x08Skp\x05\x13\x98\xab\xf9\xaea\x02W4\xdf%\xcds O\xe0\x8a\xcfs\xe9\xc1\x8c\xd3\xa4\x15\xf4p8\xf3\xe9\xf2\x9c\xf3\x1b^`-\xd4\xb0\xde\x04\x9a.V`\x08+\xbep\x91^\xdeLp\x88r\x97{\xe4\xdd\xb5W\xaf\x8bj\x02gf\xedDL\xc7o.v\xa1\x8f<\x024\x995\xbe<\xba\x04\x86\x88_\xa1-\xea\xc6\x87\x0f2[\x8fdFJ|,\xb7`\xa8\x9d\x17\"CM\xec\xba\x12)\xf1c \x08\xb5%$\x8fp\xdbW\x8e\x1b#vXn\x94P\xbdN\x8e\x93\xc1:\xb8\xf93\xbb\xcd\x94\xee\xae\xde\x18\x86\xc5\xd1m\x04\xfbU\xb5p\xa6\x84 ^`f\xa8\xb8\xc1m\x93T\xd2443\x15\xaa\xdb\xaf\xb0\x9b\x0d\x8e\xb3\xfe\xd1&\xc0r\xbc\xde m\n}D\xe1\xe9\xb9\x8f\xc86$,\x1b\n\x0c\xf3\xf1\x94\x99\x13\x96K\xf1\xff\x05\x9d\xc1\\\xd3\x7f'T\xe8\x86\xb0\xf1\xa6\"\x00\xdf\xd8\x04\xe0\xb3\xaa\x00|c\x11\x80\xcfp\x8c\xb9^tm\xa5\x1c\xbc\x82\x18<:]\xb9\x87\x0f\x10\x1c\xcf\xe0\x08\x07:\x821\x9c\xa8\x9d9+\xc4\xe0\xb3B\x0c>+\xc4\xe03RJ\xd5[\x12\x83\xcf\xa4\x12 G\xc0es\xe8\xf5(\xc2\xda5Y\x9b\xb1\x8f \x86\x91\xe6\xb4\xc7j\x0e\x035CJ\xba\xa2\xcdp\xd9\xaa\xa0\xf2\x8a\xbd\xde\x12\xabn=\xb8\x82'\xe0\xbe\x87 \xdc@\x1f\x96\\B\xa38\xd5\xb7\xba\x04~\xe5\xc3{N\xa2\xc4\x96]a\xf1^\x9bIl\x96\xc4y\x18ow=\xe6\x03\xe1\x0d7\xe4\x00\xf3\x9bo\xc5Ee+\xcc4\xdc\xf8\xf6\xee\xa1\x18'o\x077\x10\x8e\xc0\xe5\xebz\xa5\x86[]\xd6\x1b\x0f\xe3\xa9q\xd2\xf5\xc7\x83\xa1\xc0\x11\xea\xbfR\xf3\xd2T\xf3R\xaby-\x8f,\xd4\xf6\x188H\xa1\xb7\xf4zk\x1cn\xd6\xc4\xe5\x8f}\x90\xb0\xb1\xb6o8oN\xce\x97\xc3\xd3{\x1b\x04\xc1X\xfb^\x9d\x10B\x98\x8c\xf88\x81\xc8\xbd\xf5a\xc3\xdf]\x8b\xe2\xfc\xdd\xa5x'\x8e\xc4W\xeaH\xfc\xd6\xf3 \x98\xde\x9ec(KXMW\x82\x96\xf0\x17\x86\x9bY 4(\xf7\x18\xe5\x98\xdbsO\xbf\xa6\x85r\x06\x1c\xc1\xf1\xf4Xk\xe6\x12\xc6\xb2\x8b\xe9\xb1\x0f\x97\x16\xc5\x8c\xaf\x06\x06\xf5\xea\xf7\x17^\x93\xc1\x8cou\x99\x16\xdeb/D,\xd5.\x12UE\x8c\xa8\xef\xe7\x1f\xec\xbf\x16\nt\xaet\x95\xe5\xc3\x07X\xf2/^\xfd\x93\x0e\xb7\xe5\xdd\xe3;\xb7\x86'\x90\x19v\xce\xfb\xcc}\xe3Hb\xdd9D\x84\xcf\xd9\xa3\ns\x90B\xc5\x1f\xcak\xd69\x93\xc1#K*\x83\xc3\x87#\xaf\xfdtO\xba\x13\xc8\xebpp\x04\x7f\xffH \x0dAB\x8b\x91\xeb\xc7e\x9d2]\xea\x03\xaeF\xd5\x13\x03\x1e\xb6GI\xb4'\x85HE\xa7\xad~p\xa2|\xe2\xb2Z\xfa\xb3\xd6\xc8p\xd69\x8d\x0e-s\xba[M[D\x81\x05\x1f<\xea2U\xc3\x0cJ\xfaT\x7fD:\x94\x12\x16Qt\xfc\xfbG.\xad\x04\xa83\xd9D\x16\xbc\xf01\x0d,\x9a\x10\xe6\xe9\xe3#\x88\x0c\x82L\xec\xce\xf8\x07\xa0\x98\x81>\x84nDA:g6\xbd\x18\x8aU\xcfv[`\xf3\x19\xeb\xfe7{E\xdb\xdf\xc0,I\xde\x87L\x7fs\x9cln\xd3p\xb9\xca\xdd\x99\x07\x07\xc3\xd1A\xff`8\xba\x0b\xaf\x93u\x10\xc3\xd9*\xbf\x8d\xd6A\xdcT\xe1\x1e\x1d\x9e#\x0f\x99\xa3*O\xfcf\xc4\x99H)w\n\xc4\xd3\x0d\x95\xc3?&\xb0u\xe7>d\xed\xa1)M8SI\xe4\x9d\xb14\x0c\xa2\xf0\x17\x93~\\],E\xa0\xc4v\xd7WZ7O}\xf8P\xbdm\x88pY\xa8n\x05d\x86\x16\xc8L0\xa9\x1e\x88\x06\xc3\x0cB\xf2\xfe\xab\xee2\xeep\xd0\x12\xa8R\x81y\x1c\xac\x9b\x1a\x93\x1auX\x8b4A\x07|\x18\x9e\x9b\xfa\xda\xb6\xf6u\x15D-]\xe1uu\xe8\x813q\xa0\x07\xdbz\x8f\xc2R\x06)W\xb5\x9f-\xadW<#(\xca@\xdft\x18\x8b\xc7\xd4\xd9\x8b\xe0\x85\x1b\x99\" \x89\xaa\xd9\n\x831 \x0dxA&\x00\x03\x14g(\x98?\x86\x1f\x83\x9b\xfe\xb3%\xc3\xc1\xff\x18\xe4\xab\xc1\"J\x92\xd4\x8d\x9a\xa87\x1e\x87\x0c\xe6\xc9:\x08\x8d=\xe8o\xb0\xd7\xe4\x15$'(\xfa\x98\x9cUe\x9b\xea\xd3\xe6\xdd\xe0D\xc1\x8d\xb3C\x87?\x047\x9f\xd3\x9b\x90\xc5v\xe8\xf0sf\xd8\xeaF\xd4\x04\xf4j\xbfu\xa8\xaf\xb5\xd4\x81\xffj2k1L\xc9Y\xebF\xca\xba\x1aP?N\xa9\xab\x04\xfb\x8f\xe1\x9b\xfd\xf2k.\x9a\xed\xff4}\xb7\x1d\x0e\x87\x8f\xf8\xbf\x07\xc3>\xff\xef\x01\xe3\xff>\xa4\x1f\x8b\xc5y\xef\xdf\xf6M\xc7c\xdb\xdf\xeax\xac\x1a\x93\xb9\xfc\xd7'I\xf8\x1dC\xaa\x8b\xfek\xcb\xeb2-\x1c\xc4t\xefk\xd7\xfb\xe6|\x7f\xd9\x16\x8b\\\x1eK\xa0\xbbF\xc9\x9e;\xf4J^\x1ae'\x8d\xf2\xec\xdb4H\xbd\xe3n\xb3,\xb9i\xc8\x1c\xf32+\xb2\x92\xc7c\xbb<\x9eV\xcd\xd3\xb1E\xe4N\xd1U\x00\x1d\x07\xee\xdc\x81\x14m\x97\xf7\x0fG\xe8q\x11C\x0fF\xfa\xc9|\x83X^s\x08\xc1\xca\x16\xc1\x9a\x0e*\x9fbW\x07h\x1c\x12n\x1c\\un0\x1c\xcb\xe3\xcf\xd1\xf0\xe0.|C\xde\x1a8v\x0fz\x90\xf0\x1f\xd8^\x8f\x8e\xf2\xed\xe4'\xa7\xebp\x07w\x87ey(\x84}\xb8\x7f\xb7\xf8\xc7\xf3at\xf0\xd0Z\xc6\x83?\xc2\xfd\xbb\xd62\xe5\xcf!\xfeB\x1f\x84^\xa3\x1bg\xa3\xbd\xban\xf25\x9c\xc6Qh\x89\xbb\x0f1B\x04\xcd\xf4\xe0ny\x84i\xf3$S\xc3\x04R\x9a\x00\xe7\x97\xbc\x03\xfeR\xb5?zt`l\xa0^WTH;\xd8\x0d\xda\xd2O\xea\x90\xb2gw\xf3\xe7@\xc3la\xf9\xedF\xb2J\x91\x86\x0b\x96(\\\xa6z\xfe/\xcb\x19\xb2\xc4\x93\x86[d\xa1\xddAs\x9e\xb4`F\x80V!v\xc3f\x8d\xa9\xc5\x94\xb62\x99L h4\x0d\x83\xd2\xcbCx\x02\\\xbao)\x9c\x90S\xcd\xf0\\\x19\xa7\xc2^\xcf\x0c\xc8p\xbd\n#\xa6\x14'>\x14s\xbb\xd2v\xc7\x81N\xf3x\xe9\x8f\xcc\x19r\xfe`\xdfIK\x8a\x00\xd0\x9d\x04\x85v\xbaS\xbb\xc2\xach\xa3\x8eZz\x8d;\"\xbd\xc1\xd4\x99\xfet\xee\x9c\x97\xcd\x07d;\xe0\xa2l\xcd\x9e\xa3\xda\x12\xa4\xbd\xed\x92\xf0\x0ea\x81\xb0\x1a!%\x1bd\xc96\x9d\xd9\"Fx\xbe,\x18\xca\x82\xe48\x98\x0efI<\x0bD\x10Gv\x0d\xaf\xd9\xf2\xe4f\xe3\xa6\"\xe0\xcf\x07\xc7\xab\x99]\xc1H\xba\xd8`\x11\xc6\xf3\xe3U\x90\x9e\xc6sv\xd3fB\x93\x0f\x87\xd1\\\x87\x0f\x85\x89\xfd\x86\xb3\xa22\xceZ.>\x95,i\x89\xeb\xf9\x02E\x0b\xd7\x98X\xa2\x1c\xda\x1c\xdcx\x10\x05YN\xc3\x7f\n\xb9\xf7\xd8\xe38\xd0\xb8]\x86\xfc\xcc\xbeX\x8aoos\xb6\xd3R\xc8\xd9\xf0\xd5\xc0\x1b\xb4\xb4 \xe4\x95\x858\x83\xf5q&\xe6x\x8b\xc4\xc5\x9fu\xbe\x1a*\x17\x87n\xa6\xebc\xa6j\xf6\x0d\xe0\xd2\x0c\x9e\x88\xc6\xc6\xbd\xb3EY.\xe4\x1b\xe5\x98\xc9\x85\x8d\xea\x89\x88\xfe$\xe8t\x84\xfb\xd4\x92~KQ\xc6\x84\xeb\x8c\x94)?\x99\x0e\x8dq6tyg\x97\xd5j\xbd)\xa3?r\\Hc\n\xdc\x92(\xe8#\xb50\xee%\x7f>\xb6\xedA\x8a\x06W\xd9\x8b\xf1^\x0c\xd8D\xbc\x96\xa5$\xa9\xf2\xc9\x84\xbcA\x92B\xb4+\xcd\x89\x8f\x15}?\x87\x9e\xafdN\xe95\xca<\xa7\xd0=\xa8\x07\xee\xa2Q\xe0\x10\xde$\x9c\xf4\xbdJ\xc2\xb8\xc5\xe6!\x9f.\xb6\x0f\\\xdb\x99lW\xae\xb1\xc6=DjIU\xc4\x13\xd6\x12\xa1~j\xef\x1b\xa7o\xe1\xfajBo\x84\x85\xe8\x8bM\xac?\xb9\xcf\xd7\xf2\xf9w\xdf\x9d\x1b_\xeek\xbb\xfeQ\x1c\x16t=\x13\xf8\xba\xdf\xef\xbf\x8b1\x00\x96\xb3\xca\xf3M6\xde\xdf\xdf\xb0\x1c\xf3\xdd\x0f\xb2\xeb`\xb9d\xe9 L\xf6\xaf\x0e\xf6\xe5\xaf\x9f\xb3$v\xde\xc5\xf3d}\x11\xce\xc7\xe0|%>\xf4\xb7\xa1\xf3\x8e\x0e\xc1\x82\xd2>\xab\xa60\xf2\xc15-\x07\xf4a\xe6\xc1>$\x1dg\xa5?ie{\xb4\xa3\xc0\x0cz\x10\xc17d\xee\x1d\xdc\x83#8\xc08\x0e\xdf`$&\xfe\xbf{\x17\xfa\xf4\xd2C\x95\xd2\xa6\xe0\xd8\x9e\x02Py\x17#\x0e\xac\x08\\\xdf3t\xef\xf5\xf0\x00\xf2 \x10`\x0f\x88L\xd37.\xb1\xa0\x0b\x90\xbe\xd2\x81\x0f\x8f\x1eiPo\xc7\xce\xea\xf3\xd1\x87G\x1d\x8b\x7ft\x9b\xcb\xd9/%5\x90\x84h\x07S\x85|2wK\xf1\x9e\x8dG4\xf2\xb1\x84\xb4\x93\x8c\xc8N\xa4X\xbe\xdd\x8c\xbb[\xbb\xa1h\xd4\x1571\x91*y\xeap\x8c\x8fU|B\x87\xe6\xdcS\xc6\x9d\xdck\x8a\x1d)\x1f\xe1`\xf4|\x9b\x8a\x00\x90q;\xb8\xb3\xf9\x92\xbd\\,2\x96\x9bBz\xeb\xcf'\xed[\x9e\x8c\xc1\x92\xab\x80>\xff\xd7\xb8\x89\xd6\x85q\x9e\xfc%d\xd7\xe5u6]\x9c\xad>\x92Wc\x9c\xf0o\x93m<\x0f\xe3\xe5q\x14\xb28\x7f\xcdf\xb9\xeb\x0dV\x88'\xed+\x14H\x8a\xae\xf8Z\x0f\xc2\xf6j3YM\xe2j{\x95\xc5N\xbcc\xc3Q\x02zm\xa1n0\x05\xf2\x13Xp\x88\n\x91^<\x85\x19\x1cQ\xbc\x01Z\xc91\x04\xe2\xc3\x06\x8e s\x03N/\xf9\x9b\xa2\x00\xb1\xd2\x06\xccn\x80\x81\x19\x8bs\x96\xd6\xb60\xed\xb0\x8b\x99\xdb$]\x94I\xe1>\x1c@\x8f\xa3\x0b\xc7\xaa\x96]\xe7\x85=OL\xefS\xe6\x94\xe5\xc9f\x0c\x81\xbd\xc0:\xb9\n\xe3e\xc7\x0c\xfcP\xd0\x86\xbd\xbd\xfa!\x90|\x1a\xc6\xc3\x81f,\x80\xa7\xb1\x14.\xdfX[Jca\x833N\xbdUN\xb3\xa4\x14?\x90\x7f\x9cDl]s \x04\xc1G[\x17C,\x82\xd0E\x88\x9f\xfd\x17\x1a\x91\xc5\x8f7\xc9\xa6\xcb\xd0\xd0j\xef\x9a\xfb\xa0x\xd7j\xe0\xd4n\x18/\xc5\xc8yo\xea#/k^N\xa4\\\xddd\xe5\xd2l\xde$\x1c\x92wL]\x81\x9bkIN\xa9P\xa0#\xac\x95\x978\x8cc\x96\n\x89\x01\x97y\x86\xc8Bov\x1c\xa3\x00\xadn\x8b\"\xf5T+\xa2\xe6\xc9\x86\x93 \x14\xde\xe2A\x82,\xca\xb4\xfb`\x06W\x83\xb75\x06%\x0drv\x86\x1bQ\x8b\xeah\xa3G\xd2N\xd5\x08N\x96D2e(i \xcb\xaf \x9c\x03\xef\x8ek\xff_\xbb\xed>k@'h\xec\xe8S`M\xc9\xe7\xac\x04^~' \xdc\x15S>\x0d\nw\x86/\x01/\x7f\xa8\xbct\x82\xf9\xfc\xe4\x8a\xc5\xf9\x0fa\x96\xb3Xd\x0c*L.{b\xcaq\xf2\xff\xb2\x98\xcc/\xf8\x9a\xb9%\x9ac\xbc'&E\x1ag\x15fy\x92\xdeV\xad9\x9bm\xb6:\xcb\x83\x9c\xcc<\xa2\x90y\x9d\xb8L\x13\x92 \x08\xe1\xe05\xe3\x85Qj\xd4+\xd7%\x0b\xcaT*>\x0fj\x95\xf9\xe8\x82m\x9e8\x9e\xda\xdc\xea\x82\xb8N\x94\x04s\xc7o\x87 \xeakWE\xb1ql\xeb \xde\x06\x91%\x86=Wq\x1a\x86\xbdI6\x19\xaen\x9b\xe7\xb5|\x18\x86\xe8&K\xdc/,\x16\xdc\x8cRH\x15\x9f\x12T\xf1\xc4\x8bAQ\xce\x06\xf7\xb0\x87\x97\xf3\xc40e\xb0\xf7\xc1*\xc8\x10\x92v].iUL\x06\xa8\xd0\xb8\xde\xa0\xd0\x08\x9aO\x0dZ\xedC\xd2h\xa7 {\xc9\xa4x\xf0\xed\xed\xe9\xdc\xadM!e\x0b\x99\xc1\xef+\xc7\x9b\x8e\x9a\xf2\x05\x83t\x8ek\x1b\x05\xd4\x0c\x05$L&\x850\x99s\x1e\xc3:\x88\xdc \xe4\x98D\x08\xe9\x9c5\xb5+\xf4Cx2\x81\x14\xc8 \x1d\xd0\xff\xdc \x124\xa8\xa8\xd0\xac}\xd9\xa1\xd9D\xb6\xf6L\xae\xebW2\x8aO\xe1\x86\xe5\xb8?}x\xf7.\xf34J\xe5\xbe{\x97}\xf87\xcf\xe4\xc2i\xc5\x9aY\x14\xce\xdewB\x99\xd2\xb1!\x1b\xe4A\xbad\xf9c:\x89q\x9e9\"\xd8L\x1e,_\x04k\xf6\xd8\x13G\x9f\x9b eq\xfe\"\x997$\n\xdfs\xf7\x90\xb1\x8c(\xe0\xd7\xe0z\x15\xceV\xa4&`\x1a\xc8?\xb3[\xfa\xb5fy\xa0~\xcc\xf24R?\x82\x88\x97j\x8c\xfd\x82\x16\xc86h\x94\x90\xa8\xa8\x94\xa2\x10\xf5\x08d\xe52G\x95\xdf\xe3\x9a\x91\xbc\xfa\xc4\x1a5\xd1\x80\xb6\xb9R{\xca?\xd0\x88\xac\xb8\x96\x82\\\xc7\x8d\xeb\xe7k\xd5\xa7\x94\x02pW\x90\x06\xdd\xc5\x0b\xb3\x18\xe4y\x1a^ns\xe6:\x9cv8\"\x85A3\xd9\x12\xc6\xfe\xe2\xce\xf6W\x0e\xf9\xb7n\xc9C:\x1f\xcc\xa2 \xcb8\x90\xb5\x86\xfa\x91\x06\xdf\x06\xb7w\xf9D\x0d\x840-\xdcZ\xdcQ\x9b\x89\x10\x8fW\xber\xc4\xd1j\x87\xbdB\x0c\x88\xe4\xd1J;\xb9\xca$\xac\x10q\x8c>\x95.\x01egJ\x19'\x08\xcf\xc94\xd5\x06}W\xe2\xcac'\xd6\xa5?\x15^\x02\x93\x16c\x164\xab\xd3\xf2Y\xec\xcc\x19\xa9\x16]\xff,3\x9c\x0c\xfa\xb0@/\xeb;\"x\xd9N\xb3\x94(\xa7\xa4<\xf7\xef\\\xdet\x8c>^\xfa\xf3\x11C\xbb\xa2\x94\x91\xf9\"\x83\xf4\xac\xc1\xe8af'\x16V\xf2\x07{!\xe9\x07\xa7^~t\xcb\xdea\x18\x9e\xd1\x18J-\xc5[\xad\xc1f\x13\xdd\x92\xa7 \x8c9\xac\x7f\xf8\x00\xae~\xa2\x1c\x9a\x0f\xa0;\xdd\xc9\x13\xc1\x1b\xe9\x94\xb2\xc8\xc9\xe7\x83sq\xc1\xb2\x1f\x93\xf96\xe2\x92^y_0}\xdbX\xcf\xc8\xa0\xeb\x99\x926m\xdc\xd8\xbd\xeb\x19\x02\xa8\xf0\x0f\x07\xd5\x0f\xa1\xf8pX\xfd\x10\x88\x0f\xf7\xaa\x1f\xb6\xe2\xc3\xfd\xea\x07L\xf6\xe0\x0e+o#,^MJ\x85'G\xbc\x15\x94&\xf1\x0f\xb2\x88\xb9\x87\x0f\x1fT\x1b^P\x94\x17\xcft1\xd3\x90\xf4Y?\x83f\x83b=E\x9c\xd5:\xac\xcb\x9b\xb1-\x97/A,2E\xbdX\xb1h\xc3\xd2l\x90lN\xe7\xe5\xe1\xb6;\x02\xaa\xd1\x0b\x7f:\x0b\xfe\x91\x9c(F\xe7\x89Lj6\xcf:\xa9\x9e\xf1JA\xb5\x92\x9b\x0f..0\xfd\xd9\x05\xc5\\\x1b\xfa\x18\x19R\x16\xf2<\x91#\x11K\x93{g\xe3\xc1D8\xc8\x93\xe52bg\xab\xe4:\xeeJK\xa4\xb0\x1f\x0e6i\xb2i9c\xcc\x85\xd3\xeem\xb2\xcd\x9fa\xdb-\x15b!\xb7-\x9b\x8b\x91\x97\x1cG8$\xd5\xd5\xcd\xab>\xc25;\xc3\x896\x17E\xad\x96s\xae\xd7,K\xa2+6?\xdb^\xe6)k<\x0f\xc53P\xcd?'@;\xf9@$\xc6\xa95\x84!KV\xc9\xb5;u\xd4\x0c2\x87\xec\xd9\xe7>\xec\xd9\x9c\x9a)u\xcfq\x10\xcfXt\xccE\xe2\xae[\x869j\x04\xbdo\xde\xae\xf4\xf64\x7f\xb9\xcdO\xe2\xe02b\xf31\xec\x85B\xa7\xac|\xb1\xb6b\xc8H\x03\xc5\xd8\xdf\xa4\x1c\x10v\x1a\xfb'\x80[\xb6a\xb3\x1d\x80m\x13\x98b\x8a\xea\x0fA\x1be,j\x10\x0c\x7f\xcbU\xe60\x84.\x1b\x7f!\xbf$F\xc9\xc11\x87ejs\xab\xa3M8\xb9a\xb3m\xde)q\"\xec2-F\xed\x9e\xc6\xaf\xd2d\x99\xb2,\x1b7&\xf2n\x18c\x1d\xfb\xba\x0e\xf6\x13\xa1\xe5\x8cEl\x96'\xe9\xaf\x00/]\x08\x13\x1f\xc2\xab _\xd9aK\xdd\x07\xc0\xac\xf6\x1b6\xab\x12\x15.\x9b\xfd\xe9\xcc\xf5\xe8\x12\xb1\xa9\xc4\xd4\xe1\x03Wt\xa6a\xf9\xcdt\xebW\xde\x82_\x0da\x7f\x85\x0d\xb0\x10\xf6\xf2\x1eX\nu\xdf\x06R\xd1\x9b\xb2\x00\xd6 \xc9\xc8>[\x13zZr\x8a\xfb\xa6;\x97\xb57\xca\x11\xc1\x87\xad&\x85\xf8\xc2\x07\x81OA\x7f;5\xcf\xe3=\xbb\x1d\x83\xb3\x0e6Hb\xde$\\\x8c\xce\x1c\xf34\x84\xe8\xdc\xd9]B\x1aJ\xf2A\xb2i\x07\x98\\\xc8)\x1d\x89A\"\xc4\xb4\x9c\xdc\x1d\xe3E\xb8\xcc\xbc\xb63w\n&?Of'7\x9b \xce\xc2\xa4\x834\xc2\x85G\xb6\xf9!\x8c\xdf\x87q\x8bX\xb4\xa5\xe2a\xb6\x89\x82\xdb\x97]\xa5\xa3L\xaf%R\xd9I\xff\x8f\xe6\x9a\x11\xa9\xb6\xdb\x0d\xd7\xa6\x10\xc6\xd7a\xfe#\xa2]\xcb\xeaa'OO\x16\x83\x1f\x83M\xab\xd2\xfe\xb3\xd0\xf4\x17x\x13\xfcOg^\x0b\x8b\x03T4\xc6p\xda\xdc,\x7f\xf2`\xd9\xe9\x86\x05\xa7\xdfV\xef]\xfd\xc9\xa4\xee\x91[\x14-\xfa.\xf4,\xc7\xc2\xdd\xf4g\xce6)\x9b\x059\x17\xf1OI\xf3-^9B]3\xf6\xa5\x15\xa3\xee\x9a\xccS\xf2!\x0e4\x86\xa4\xbdh\xa1\xa7t\xb8JQ\xd6UZTi\xa8\xaa\x8a-j\x19\x96\xaf\xdb \xc4\x82u\xb7X\xb4\xf7R\xd2/;\\\xf0SzU\x8b.\ne\x15\xaaE\xf6\x80\xbaN\xd9B\xf2AW\x81Z\xf4O\xb0\xe8\xc6-\xda(4\xe8\xc7-B\x12X\xd5\xfd\x16\xce\x0ff\x89\x96\x04b<\xd2\xa9}mo\xb0f\xd6\xd5\x9a\xebzB\x04P\xf7_\xd7\x1fa-\x89\xa4\x89V\xb8\xb5\x0b\x8f\"\xf7\xc7\xb6\xabb\n\x9c\xc7\xf0s\xf3\x8c\nm\xba\xcdh\xdf\x11<\xba\x82\xb4v\xb6-\x96P{\xd3\\\xb5tR)*\x97\xde\xb5U\xd7\x0eiUu\xed][uqD\xa7\xaa\x8a\xdf\xcd\xd5\xa4<5\x86\xcb\xf6\x82\x82\x95\x8f\xe1\xba\xbd\xac\xe2\xe3c\xb8h\x19y!$\x8c\xe1e{Y\xad\xe5W\xcd\xa5K\xf2\xd0\x18\x8e\xbb\x94\xd6Z?k.\xaf Och\xd9\x9d\x92\xe44\x86g\xcd\xa5u\xc1r\x0c'\x1d\n\xa3T9\x86\x9b\xe6\xa2\x8bx\x0co\xac%l\x87\xab\xb5\xb7\x1f\xcf=\xbfrO\xe4\xa3\x9b\x0d^mSfJ1\xb9\x92\xe4\x02-\x1d\xb5\xb3\xa9\x12s\xda\xab84\x16t\x00\xdd\xc7J\xdf*\xbc\xa4Z\xd5\xc4\x0c\xaa\xb2\x84\x8d\xf2k\xc6\x05\xcc\x15#&\x00\x13\xa0\\\x14\xbf7\xc7\xaf\xc8\xe6\xf8\x15\xd9\x1c\xbf\"\x9b\xe3Wds\xfc\x8al\x8e_\xfc\xc3Pw\x1a\x8a\xc8\xb9\xcb\x92k\xfa\xb7\xf6\xd9\x9a5\xfadi\xfeX&k\x8cv\\ip\xc7\xf2?\xd9\xe5Jx\x18bq\x992\xa7\x9a\xd6\xc8\xe8\xd4\xf8\x19\x07\xa7d\xa0Z\xb2\xfc\x07$t\x06)\xbe\xab}j\x17\xdbT\xbe\x83\xaa\x1c\x9b\x14\xdf\xc1l\x9b\xa6\\\xbch\x10t\xd1>\xe9\xc6\x98T\xbc\xd1y\x0d\xef\xe8\xb6\xceO\xab\x90Yd\x1dg5r\xa4O\xeb\xd7\xf0\"\x11\xdc\x03D\xf0\x19\xbcS\xe0|\x8d\xe7\xf5_;\xf0ug\xd2Z\x86\x00\x93@\xd5bg\xfc\xa4=T@a\xb3\xe6\xb6\xac\x06\xa3\xa50\\\xfb(\xcf\xa7\xcc88\xd3\x90\xed\x99\x18\x87Nwg>\xccj|\x84Z\xff\x171\x16\xcf\xfftb\x8c \x8b(\x15\xfa\xd5|a\xb0\x8b\xd3\xac\xba\xf0\xc3WL\x91_\x15_?\x82 \xe5 u3\x8fr\xe8\x0f\x1f\xc3\x0c\x9e@\xf6\x18f\xbd\x9e\x07\xd1tv\xae\xd7\x9c\xce\x0ca\x01\xc5R\xc6x\xe1\xd1\xe6\x9c\x8b\x18\xd8\xca-fA\x14 \x96\xc1|\x98\xf2\xba\xe72\xf4b\x84IZ\xc3\xc1,J\xb2N\xeeV\xc2\xc5J\xb7\xfd\xa11\xfc9G\x85\x10\x7f\xbbU\xffz 4\xc3\x8bZ5\xa6\xc77\xe3\xb7\xe0\\_\x96\xe4ub[\x1d\x0d\x9eqwcj\xba\x03;\xa4\xd3\x15\x96\xa6\x1d\x86\x10\xeeb\xf1\x0e\x84\xf1t\xf0\xec\xec\x8d\xbd\x14\xdfm\xed\x04-\x90)m\x1b\xcc`\x98\x0e\x15\xa1)\xd6\xc1\xa9\x81sS\x8aT\x87\xaf]f\xcb\xd0\xd0\xc6\x8a\xe7\xe1U\x8dT\xeb\x8f\xbaV5\x06g\x1e\x06Q\xb2\xecoo\xacWq\xbfH7\x97\xc1\xec\xfd\x1f\xea\xe57Z<9\xa5>^\xcf\xff\x8d\xfaZ\xb1`\xfe)\x9d\xad\x0e\x95\x1c\xe8<\xbb\n\xc2(\xb8\x8c\x18\xea\xfbI\x1a\xfe\"\\\xb8\x9a6\xfbr\x9b\xe7h\xe0\xb5\x0f8\xbf\xdd P\x89\x92\x9d&\x86\xfc\xa0\x8f\xd3k\xa8\x91\xc4\xba\xb9 \xeb\xec\xbc\x02\xd9\xd5\xb2q\xf4\xd7\xe1<_\x8d\xc19\x186\x0cd%\xa2;\xf0R;\x8f`\x9b\xd5e5\xfdY\xa5l1\x06\xe7+\x9c_\xc3 n\xa20~\xff}\xa9\xb0\x05y\x91\xe9~Y\x00\x9c%q\xce\xe2\xdc:\xfbh\x80|\xee\x8c\xfd\xcd\xf5\x06\xeb`S\xcaI\xdex\xfd\xb7\x85~\xce\xda\xcc\xb6\xc8~[\x0e?\x9e\x9d\xbdi=\xf0\x98\x17,\xc1\x1a\xb7D>e\x13X\xcb\x19\x96\xce\"[\x0f\x81*\xa6\xb8\x96\x93\xdb\x92\x91\xaf\xc5\x00\\1{\xd6\xdd\xa1\xe5c\xb3\xb4y\xf8\xd4\xbe}9%\n\xdf\xfeK_\x12\xcf\xbf\xf4\xa5\xff\xc5\xfa\x92\xe0|]4\xa6\xce\x97S\xf2\xeez@\\\xd7/\x06\x1a}|\x93\xa8\x83g\x9bI&\xafim\xe6\xd4\x15\xffR\xda\xccO,\x80\xac\xac\x8dy\xa4\x8b(\xd9\xedU\xb2\xd9n\x1c4,6+u{{\xbb)>\x89\xa8\x13\x14\xee\xce\xde \x0b\x7f\xb1D\x13\xf9\x92:\x10\xef\xb2\x7f\x9d\x06\x9b\xcd\xa7\x08\xbc\x1d\xe4U\xad\xb3\x04\x8e\xc0\xb9\xccc%\x113\x88\x92\xd9{6w`\\\xfd\xb0\x8d\xc5\xa7\xae\xf2\xaa\xf8\xb5\xf3\x14\xb2M\x10kR\xbb\x1c@\xa3\x98\xfe\xcf\"\xe5\xe2\x82\x7f\xa5\xad\xf1W\x1d\x96U\x13|\x1b\xea\x9bG\x8c\xf4\x14\xddkm#\x8f\x85u\xf8_\x92\x0d\xfcK\xb2\x81\x7fI6\xbf\xbddc\xbd7\xc0\x06Y\x9el8\xd4\x07\xcb\x80\xf8\xb0\x99\xff\xc8\xcb\x05\xd2z,:\xb1\x88&\xe8lop\xa9\xff\x9f(\x8e\x94\x1c\xd5?\x8dy\xef\xc6R9\n\x96\x85\x94\x8b\x0b\xceH5\x9am\xf8\xda\x81\x0b8A\x1a\x06\xfd(\xb8d\x91c\xea\x06h\x9c\xd6\x8e\xe4\xf7\x0e]}!>\xfeO\xc2\x93\xd9g\xf2\xe4\x86\xfa\xe6\x11\xff/\xb4\"\xcc8K\xad\xf1\xd4D|\xa9q\xe1PV11\xdb\x99\x89\x0bo\xc5\x87\x1a\x17\xce\xc4\x87\x1a\x17\x8e\xc4\x87\x12\x17\x9e\xc9\xc8G3\x11\xf9\xc8\xc4\x8fg\xbf=?^t\xe5\xc7\xb6\xb0EU*l\xe5\xb9W\"\xafz\x95\x98[}g\x92:\x0fl W$\x16+\x18$1\xa7\xcd\xc7\xab ^\xb6g0\x02\x8d\xcf\xb1A\x1c\xac-\xbaXP\\[\xab\xb0\xe8\xbf\x7fDL`&\xf4\xe3\xfc.\xc3\xbb\xee|H\x9d\x06S\x0fb\xc7\x1b\xa9\x1f\xdf*\x15\xca\x0d\xc8\xe3\xd7\xd2}\x94,M\x91tv\xe8\xbfY8\x08\xda\x14t\x8a\xab\xd0\xc9@B\xc1\x154\x93H\xcd\xe6\xdd\x1a\x80U@\x819\xa25 \x1d\x19\xe4 \xc9w\x96\x99\xc5b\xcd\\s:\xd3\xa0~\xec\xbe\xc3b\x9a7\xb3\xe3Y|P\x84\xfa\xe0\xbf,8\x0ee\xd9)3\xcaN\xc1?@vj6\xe2t1\xf6\xc4U\x00i\x83\xa5\xee\x87\xeeyW\x1bR\x88\x85\xbb\x9d\xd0\x07t\xd2\xcd\x91\xff4g\xeb\xa6\xabH[*Jy\xe0\xda\x8cO\x19\x15\xfe\x96d\xc8\x96\xa3\xf6\xa4do\xb2\x97\xa5\xc0\x19\x8b0\xcaY\xfaIH\xb7\xb77\xc3k?\x96(\xea\x80\xd8g\xef\x7fc\xee\xbfc\xe7r\xe5D\xd4]\xbc~\x94\xdfnXC\x8c\xd8\xa6\xc1\xcc\xbf\xcc`&;\x0c\xa6Q\x8f\xb0\xdd\xbf\xd8\xdd\x088K\xe2<\x08\x9b\x0e\xd9\xf7\xf66h\x95\xe4b\x87\xb5\xdfE\x92\xae\x1b;Nb\x8a\xf2\"o\xa5(6h\xebvS\xa6\xf6mI\x97Z\x16&\xe8t\xc2\xd9v\xba7[\xb1u\xd0z`\x18\xe3\xf2\xb6\xb4\xb5\xd3\xe9\xa6.\xc3\x8c\x81\x95d\x9a\xe6\x9a\x81vy\xad\xe5\xdeK\xf9\x08\xf5\x13\x8e.\x0bN\xea\x7fA\x00\xbd\xcc\xe3VK\xb5\x00P\x8e^\x0b\xfa\xf3\xc8:\x82\xack\xef\\e\xa6\xa3yi\xa3\xee\xac\xcdjR\x96m\xc8\xce\x0fX\xc6\xf1`\xfciC\x15\x1e!\x84H\x1d=B\xeaS*\x00\xc4\xba\xb8e\xeb\xf8'\x8d\xb5e\x0c|\x8b\xe7I\xdc\xe4\x97\xb1\x83\x97\x8as\x8cn\x1bh\n\x9bs\xa25o\x03 \x01\x94t\x18\xf0E 7\x9b%\x1b\xd6\x9f\xb3E\x83/\x87\xa5\x9bMq,q\xc6[\xc9 H\x19l36\x87<\x81e\x1a\xc49\x041\x04\x9bM\x14\x8a\x80\xd3\xf3p\xb1`)\x8bs\x88\xd8\x15\x8b2H\x16\x10\xccf,\xcbx\x95y\x90\x07\x90\xc4p\xc9VA\xb4\xe0\xdf\xf2\x15\x03\x16\xcfy\xa3\xe9\x00N\x82\xd9\n\x9e\xbd:\x85up\x0bs6\x8bx\x7fI\xcc Ia\x9d\xa4\x0cp2\xd9\xa0i\xf7\xf5Q\xf3\xa6R\xf6\xb7m\x98\xb2\x0c\xbbZ$Q\x94\\\x87\xf1R\xb6\x04Dg\x80b\xe1'1\xcb\xe06\xd9\xc25\x9f\x9a\x9ac\x9e\xc0\x19\xa5\xd1\x85\xb7\xa7\x03\x07\xe3\x03\xef\xc6\x81?\x8d\xfb~\xac\xbb\xd64J<\x9f\xcb\x91A2\x9f\x06%\xc5\xbe\xf0\xdb\xb6\xa6w`\x00\x92\xbd\xb5\x05\x8dA\x10oR\xa9\xda\x19\x04\xa7z\x9ft] \xeal\xa3\xa2\xe4b\xbf7\x1b\xd5\xef\xf2<\xc8\xa7?,\x96\xa8\x7f\xb6\x93\xa1\xffy\x17\xb6\xbe\xa8\xda\xdd\xa6T\x8b\xd0\xaaH\x0b\x9aUo2\x905\xeb\xdc\xbb9\xbaw\x93kC\xe5\xe3\xd1\x16\x1a(\xd8\xc1}^h\xdc\xc1&\xfc3\xbb\xe5\xc3hR\xa4#*|\x19d\xe1\xac\xad\xecL9\xd17+\xdb\xb9\xce\x9a\xcc\xda_v\x1db\x06\x93E\x13C\x9a\x05\x19\x031\x0fgl-\x06bh\xb6\x83\x8dV\xce\x02\x1d\xb5&\xe8\xae9AW\xed j\xfaJ\x87\xc8\x1c:+\xec\x10\xf9c'\x0d\x0dHF\x15\x1a\x9a=\x8d&4\xe8\xf6\xf2\xb9LY`9V\x05\xb5\xbf\x08z\x9f\xb1\xbd\xd1\xbf\xb6\xf7\xf7\xb9\xbd\x92U~\xf2\xcev\x928A\xedn\xf3\\|p\xde\xc6\xef\xe3\xe4:Vas4'nTB\xc1\xf1a\xd1\xf5v+t8\x0bo\x1b?\x8d\x1bz\xe0\xf4\x7f\xde\xae7V\x15\xcb\x90h\xe6\x7f\xf8 \xe8\xefR\xba\xfc\x97L\xf9\xbfD\xa6\xe4\x82V\xd2@HU\x1c\x00\xd7A;E\x93\xd0\x14\x17e\xd7,\xcb\x82%k*\x9d\x16\xa5\xb3d\x9b\xce\xac\x02\xd4\xe7\x92\x1e\xdd\xc6\x83\xb3\xb5\x85m\x05\xcc\xd3}\x1b1\x13\xe4\xea\xcfe0{\xbfL\x93m\xd4)\xd5\xe7\xfbm\x80\x1e\xf5\x07\x97\xe7\x1f\x16\x98\xbay\xa7\xa1t#\xaa\xc9\x95\x16t\x7f\xea;w\x8a\xd4\x10\x9c\xe0\xe14\x1c[z\x9c\xfa\x92\xdbX\xd8\xef\"\x94w\x1b\xdc\x83.(u0\xb2\x81\x12\x95\xba\x99\xc4@\x19\xe6\xda\xf7.\xc44\x8d\xcei\xbc\xd9\xe6m1v\x03*\xfb:\xb9n+\xb9\xa5\x92\xc7I\xa3\xb0\x08*\xff$\x1e\x19\x9fp\xc1\xac\xad\xfc\x8c\xca\xff\x18\xa4\xef\xe7\xc9ukX`\xcaB\xe9\xfc C\x9d\xbe\n\xf2U\x9bO\x0e\x08\x17\x96\\\x04W\x12\xa4\xa9\xb9\xc2\x1c Y\x10E8\x85\xcc\xf5v;\xf0\x92\x8fdo$\x11\xf3%9\x9d;\x1e\x9e\x7f}\xba\xe9\xa2\xdb9W\xcb\x19\xea\xean{\x99Y2g\xaaT\xa2\xe2\x04\xbb\x0e\x07B<\x07t\xfe\xff\xff\x0f\\2pz\x8e\xbd\xa5E\x9b\x11\x84\xa2#OU\x16\x19\xcd\xe7\xce\xf1!9\xb7V\xc6\xb4\xb6\x9bF\x87\x98\xd5}\xc3\xf5\xb2y\xd3\x19j\xd0\xb62\xad\xb7\xf4I\xf7\x19\xcb\xf5\x9a\xb3l\x96\x86\x9b\x1c\xa3^7\xcf\xe5\x93\xc7\xa4\x1f\xfc\n\xbd\xa8\xeb\xd6\x96w\xf5\x8b\x8d\xe24\xde}\x0ca\xfc\xd9#\xa0;\x13j\x14\x88\xeec\x07\xc1\xa4\xc1\xf1\xa04\x18\x07\xbe\xc1\x07\x1a\x9dB\xb6mC \xdb\xc0Dx\x8ep\xe5\xabE\xcd*L\x9e\xf2\x92\x06\xfel\x82%\xcf\x87yS\x98\x8a\xae\xde\x83\x9f\xe4g\"\x1fT\xcd[\x0f\xb2\xa1\xfd\xe4\x1d\xc0\xea\xefD\x9f:\x0b\x1a\xa6\x80\xa9\xa6\xc3\xec\xf2\x907m\x97\xd3u\xc1\xa2N\xbbK\xbb\xa67e\xdd\x85+\x91\xfa\x8e\x15\x97\xbcZN\xe3\xc8[6\x0f\xd2%\xcbi\xe3\xede\xe5\xdd\xb7\x8a\xbf<#\x91\xbcmg\x85\xc0ega6\xf6\xc5\no\xfd\x10\xd3L\x87\xadz\xfc\xbf|\n\x8a\xe7\x93\xac\xbe\xffd>\x05\xb0\x9bN\xde\xe9f)\x88\x9e\x7f\x83\xc4\xdc\x0b*\x186\x8cb\xdb%|\x05\xdf\xd1m\xab\xde\x11a\xa9f\x9d`&\xf3a\x0b\xc1w\xb0\xcdXj\xbfP#v\xbfK\xf6RR\xce\x1b4o\xa9\x9c7\xccS*\xe7p\xd4Bs\xe4\xa8m\x8a<\x7f>r\xf0\xb4\x9a\x19\x7f\xeb\x94\xa8\xffp=\xbf\x8bc\x06\x94\\HZ\x95\x0e\xbaM,\xf5\xfcX\xd3\xf39\xda\xd8\xd6\xbe\xbe\xf0\xffK\xb5\xfdv\xed}\x978\x93\xf0;\xd0\xf6\xa3O\xd3\xf6wS\xdf\x17\xbb\x99\x08\x0c\xda\xbe\"z\xedj\x7f\xf2\xab\xaa\xfduc\xa3\xfetP\xfb[N\xccH#\xb1GH,\xd4~\xe7\xdb \x0bg\xe5\xe8\x88\x8e\xbdj\xab\xce\xdb\xac\xc3\xa7]tx\xfb\xb0\xad:\xbc\xadJ\xd0\xb6\x14\xad6\x89O\xd7\xe1?yLU\xdd\xf5\xad\xe4yR}\xb5V\xac\xa8\xaf\x8e\x0f\x1b\xfc\x9f\xeb\xaf\x0d~e\xcd\xc3\xf9\x82\xfa\xabpC\x9f#q\xa7?[j\x10\xafw$\xde\xfe*\xfa\xf1\x17\xdb\xa8WA\x96]'\xe9|\xe7\x8d\xd2\xed\x0c\xbf\xde>\xed\xbe\xfa\xc16O8g\x8bX\xcew!f\xd7\xfd\x8d\x98c\xb7}\xebXZ@P\xc7\xd2\x9f\xb6\xcb_\xc4\n\xf2Y\xde{\xff$V\x10\xd3\x11yy\xc8\x8b\xdf\xbf\x15$\xd5\xac \xf6R \xda\xf7;\x18I\xd2\x16\x99\x8d\x1c\x9b)\xb5\x176gf\xe0\xc14<\xe7\xb2\x85\xaf\x9b@\x9a\xe4V\x94q\x03\xf3n\xa2\xe5\x84Y\xa3\x0b\x94w\xf5\x9f\xc9\xc7aa\x8d\x1b\xb2\xb0\xf98,l>\x0e\x0b\x9b\x8f\xc3\xc2\xe6\xe3\xb0\xb0\xf98,\xc8\xb2R\xfe\xc0\x05Yw!M,\xfc\x8fGw\x1fxf#\xcb\xe2\xb77\xb2l\xbe\xa4\x91\xe5\xf7\xe6\xf80\xff]:>\x04\x9d\x14\xee\x85*\xd9A\xc3\xe3\xbb8\xe3 B\x17\xf8\xb3\x06\xc5\x07\xa3\x98\x0c\x8a\x04d\xae\xd0\xc8\xed5\xae`Bb\xf7\x86$\\%j\xb5f\x16]Wj\xce\xa2\x90\xc5\xf9\xa9H&\xba\x1a\xc8\xdfm\xed,\x8d\xed\x9c\xb1Y\xca\xf2r[\xf4\xae\xad\xbd\xdbJ{R\xacx\x8379\xb0\xb6\xc8Q\xd8\xbfL\xe6\xb7\xceg\xbb\xa7\x04\x9b\x0d\x9d\xb5\xad\x06\xe2O\xfb\xe0\xbe\x84+\x0b]\xdb\x1c\xc3\xf4\xbc\x01\x14\xc5\xe27\xa6\xdb\xd4W\xb51\xb9favkH\xea(\xd7y\xdc\xb8;\xfan\x8c\xe1\xd6X\xee\x1f\xe0\x8e\xf3\xab\x18\x9b\x9a%\xbd\xaeaU@\x85Vi\xa3?\x00\xbbEV\x81]\xa3\xab\xc0\x8e\x11V@\xb0\xe1\xbc\x83\xcdkKS\xec\x96/\x05\x8a0+\x9d\x8c^\"\xa9I\x07\xa3\xd7\x82Jv0zm\xba\x86y\x01\xe9J\xb2\x83\x85lE\xe5w\xb3\x90]Q\xa5\xae\x16\xb25\x9e\x1b\x84\xd9\xcbgg\x87\xcd%9\x89^\xbb^-\xfe\xe01\xd7c1\xea ^o\xc7\x9f\xcd-\xdd\x16-\x11\xf59N\xd9\x9c\xc5y\x18D\x19\xb5T\\\xa4oi\xea\xff\xb2\xf7\xef\xebm\x1b\xc9\xa28\xfa\xffz\x8a\x12fN\x06\x1c\x93\xb0(\xdf\x99(>\x89-\xef8c\xc7\xde\x96\x9d\xcc\xda\x1ao} \xd0$\x11\x83\x00\x02\x80\x944\x89\xdfe?\xcbz\xb2\xdf\xd7\xd5\xdd\xb8\xf6\x0d\x94l\xcb\x19c\xd6r(\xa0\x80\xbeUW\xd7\xbd\xe6\x98\x04\x06I\xfc\"6/\xeci\x0d\x8eu*I\xc8\xe2\xf9\xd9\x91\xc0\x9f\x14\xfc\x96\xfeSg\x98)\xba\x9d\xb9\x07\xdf\xf7\x0d/\x1e\xa1\x15\xe6Cj\x16\xe5\xc2\x82\xb8t9u\x80W\xc5\xdf;\xbaT\xa7\x9c\xad\x1fG![\xbff\x88\xbf\x08\x040\xf4\x0fsC\xe8;y\\/dK\x1dgT\x9a^\x99\xaf\x94?\x06\x07\xdc\x17\xdfm\xca\xd5\xc1\x18\xe8\xed\x16\x1a\x823\xd2\xb9\xbc\xacL\xca\x02\xbd\x0e\xd57\xe8P\xcb\xba\xca4\xe7Ft\x1e/\xab;\x0d\x9dj\xbd\xf5\xd0g\xa7\xff\xa5J\x9b\xc8\xde8\xd6\xb9\\mM\xc3\x14\xaaU\xd9Zj\x868\x86\xb3\x1d=\xbd\\'Z\xd3\x11F%\xc3\xcc9\xdd\xf8s\xfc\xb9\x1ci\xbf\x99\xf5?\xc9R}\xbcy\xf5l\x80{SRo\xd8\xea\x13o\xf2\x98\xe5F\xa9\x19\xd5~\xef\xea\x9f\x17\xd6\x1d}\x9d\xbe#\xac\x83\xd6\xfds\x1a\xb8\\\xd2\xd7\xab\xcei\x1b\xd4/s3F\x077\x88zm\xc7\xe0<\x89\xd3\xb3\xe13\xca6\x1e\xfa\"\xd6\x93\xb8\x87\x93\xf8\x10!5\x0e\\\x81i\xe7\x1b\x01*=\xb0~\"V\xe5:~\x82AB\x98\x01\xe5\xb4\x92\xb4\xb4\x13\xb2ij\xff\xcf\x068\xaf\xb57pe\xf9\x12;X\xf5\x19\xa3E\xa4\xf4\xe71\x15\x17\xa6\x9a\xf8y@UE\xf1\xaeL3\n\xa8\x1b\xa0r8\x11\xf2u\xa6\xdeDa\x7f>\x0dl\xb7\xb5\xb9\xc2 \xfd\xd2\x9f\xe0'/a\x83@\xfe\xd4JE\xfd\xb1\x11\xb0\xda*Z\x04\xcc\x9aV\x8d!\x08h\xe3=\xf9\xf9b\x9b\xa5\xb1b\x98i\xa3\x8dq\x96/}\x16\x18'\xc6r\x8a\xf94\xb4\x08\x87S6\x14\xd9\xda\xd4\xae\xa9d\xf8|(^\x81r\xafqR\x11 \xdb\xf3\xb9\x0bV\xbd6\xbf\xb8\x1bfiF\x98f\xdc\xbf@?B\xaeoi\xab\xe9\xb48\xf3\x8aA\x02B\xea\xf8\x95\x81=`i=\xb4M\xd7\x0e\x14W\xd9\xf0o\x1b\x92\x1b\xc6\xfc\xbf)\x08d~\xee\xafII\xf2\x02}\xe6)#\xc99E\xd4t\xaa9^|\xdce9\xbf\xfaJ\x8c\x19\xd9'\xc5\x96B\x1e\xd4\xdd;\xa3\x9f@f\xbc\x01'\x14\x8fZ>\xf5\xea\xe9\x0bk\xf642\x1cf\x15\xd8`\x02\xf3g=\xcd\xea\x89\xb3:\xc8,\xd8\xa6\x86\x9fA\x07\xbd\x0c\xda+\x86\xfa\x12\\\x1aB\xde*+\xc4\x87 m\xbd\xfduE{\xe9\xa3\xef\x93\x82YWl\xf6\n\x03\xfd\xb2_\xda\xfb\x85O\xe0n\x18\xcd,.W\xb5\xdfd\xf8\x7fl\xd3\xbdK\xec\x81=$\xfb\xa7\xf8\x8fe:W{-\x01W\xc2\xee\xb4\x92\x98\x9d\x9d\xe3 \xd3\xef\"\xe6\x9e\x0e\xcb^\x0df\xa5\xa1\xd1\x13\x12\xacS:]j\xe2\xa03y\xc1\x8a\x04\xef\xe6\xa9\xa2 \xb8\xb84\xadZEt1\x9cc^\xdfV\xe9\xc3\xe8\xdea9\xa2\x1c\xb8\x01s\xfc%\xba\x8a\xb7\x84\xfb\x8c\xd9PD\xaf0*(i\x08gpf\x06\xe6[\xa9\x9a\x19\xf3\x1b\xf5\xce ^\x9a \x1e\x19\xb6\x05p\xdd\xe4% 54\x89\xb5\xf5|\xed\xba\xd4\"\x9d\x8a\xb9OM\x0c\x8bJ]~\x170M\xc4.H\x8dTp\xe7Q\x9au\x94\xd0iO\xaf\x96\x03\xd6^r9\xbd(t\xdal\xea\xbfMM\x97\xf2\xb2\xd4\x15\x84$\xb5\xef\x18\x8e\xae\xc2\x03R5\xe0\xd0f\xb8\x1f\xcf\x03\xf2\x92\xf87<\xeb=\xb0\x859G\xc9H\xc7'eC\xda\xd6&\x887\x1e\xee\xbd\x0c\xf8\xba\x9e\xdb$\xc0\xff4}\xaf\xde\xd2v\xbf\x91\x15_\xb3\xfa\x97\x1d\x81Ej|\x18\x90\x1e\x1fx\xe7\xab\x14\xf9R(K\xc7\xddz\xcc*\xc7\xdd\xf0\n\x1cw{\xe5\x95\x94\x94\xa3\x94\x94W\"\xbb\x97Wj\xe3\x82i$\xc0GS\xd6n\xc3\xea%\x1b\\\x04\x8b\xe4\xb9\x112\xad\x1dq\xd0\x15O\x0d\x19\x0dq\xc1\xf1\xe1\x10R]\xe2\x92\x8d\x88\xf4\xac\\\x00\x15\x0en^\x10\x13?\xd7\xf8\x1f3\xc7\x82\x19\xe8Y2\xce]\xf9\xfa\x82\x1c\xc2\xd8\xcb\xe0\xe4h\xce\xbd\xb6\x02\x81\xc7#C\xdffU\xa4\xba\x16\x8c\xaf\x94\x96M\xad\x17T\x9b{6`S\xaa\xcd\x7fK\x9b|$\xe06\x8a\x91*\x11\xbc\xc5mZm3\xe1\x1covw\xcf\xd1q\x02\xb9H\x9doj\x8a`\x94\xc1/D\n\x019\x06E\x0bp\xb1\xcc\xf4d\xca==\x18K\xca\xcbJDIH\xce_,\xdctd\xf2\x97\x8b\xa0\xf72\xaf\xa0{\x92\xbe\xd5\xf8uXy\xd1C\xc3crx\x15\x1d qA`/g\x1e\xda\x8a\xf1\xc1\xb7t\n\x18\x84\xb9C\xa23\x9d\xcf\x0dv\xba\xa9\x9c\xc7\xf7\xb4\x89\x84\x94\xf5\x8148\xd8P\x04\\1\x0e\xb6\x91KOY0\xaa\xd5\x14\x9e\xe1\xcbsX\xa4cPE\xdf7\x16\xc9WO\x02\xe3\x98\xacF\xdf?\xe8\xd4\x1e\xe9\x89\xcdy\xc46\xaa\xd5y\xc4\xe6\xd3\xe6_\xfb\xe7\xca\xbf\xbe\xf2\xb2M\xb1r\x9d\x9c\x14Y\x9a\x14\x04\xed\xca\x87\xa8\xd3WP3E\xde|\xd6^ev\x1c\xd2\x1a\xba\x9c\xed\xd4\\\xdf\x95\xf8C\xcca\xcf\xf3y\xc8\xe0\xd8T\xb6^hS0\x87R\xa0d\xe9\xc0\xe1!\x92\xd1t\xc1\xa2X\xc4\xe7*C\xdd!\xaa\xff\x12\xfa\xc17\xaf\x9eV\xb2\x9e\x9bu\x03\xa5(A\xd9b.\x03Vr\xeb\x15 \xa3\x9c\x04\xe5\x9bZ\x9f\xd1\x13\xe8t\x0c+\xfe\xd1\xaf\x9c\xd1[\xf6\x93\x8bS\xa7\x95\x84\xe1\x8b\"9\xa6@\xb09\x8b\xe5\xd4\x19\x89\xba\x06\xa2y\x99Lp\xee \xcd\xe6q\x1a\xbc\xc3\x12\xeey\x1a\x9f\x9e\xceK]\x08c\xdbF\xc4\xff\x92B3\x0b\x11\xf1sI\\\x94\xb1\xde\x89\xa9\xce\xc9\xf5\xcc\xa1\x8aD_\x9a\x03\xe4Z\xd69\x19\xb3\x1f\x07X\x15\xd9\xbd\xf7y\x9c\x05\xd0\xd29\xad\x88\x1f\x92\\b\xf53\xed\x19\xbb\xe0\xc9F\x98\xa1\xa0=\xc0\x9b\xd4\x17\xb2\xce\x1b\xd9\xc1\xbb\x12L{\x81\xcc\xc9N\xea\xd1\x86\\d\xfc(\xc3e\xae\xe9\xa2I\xfb\xe1\x8e\xc1\x81u\xe1\xe8G\x1d\x1aGm8\xf3\xa1M\xa0%Y^\xc6;gr\xb1\xa9\xa7\x06=*\x06W\x9c\xdb\xa1X\xa5\x9b8\xac\x08\xe1\x9b,\xf4K\xdb|\xac6\x15\xcd\xeb$\x0e\x9e\xd0\xf9\xa0tI\xea?\xff\xf8\xa3 E\x0fq\x0e\x81?\xdbO\xd9\xf1\xcd\x9f\xf3?\xda\x10aTd\xb1\x7f\xc11\xeb\xb1P\x7f\xb07\xe4\x0f\xa5c\xf8\xdcR\xb2\x8a\xe9\xd4\xc3\x0eM\xca\x9a\xd6\xf0\x06C=T\xd5\x8e\xe5\x93\xac\x7f\xd3\xafx=\x0b3?T\xcax=\xc7\x07\xfc\xc8\x12\x98\xa2\x87\x0c\x98\xf3\x00\xba\\<\xdfPi8\x14\xe4\xe9!\xf8\xde\xbau\xebI\x9a\xbb\x9b1\x14#\x98\x81\xef\xe5\x9d\x9b\xfa\x86B\xa8\n(S\xa1{cL\xa9\xb0\xa2\xa7+\xcf@$\xd7\x974\xafm\xfd\xf9\xea\x10\xf1\xca\xf4\xc7cSE\x97u\xfdb\x92\x96\x8f\xd3\x00I\x12\x86\x87k\xdf[\xd6\xef\x11\x9b\xf4\x1d\x175<\xfa.\x1a\xc0\xe75x\xe3\x98\xd0\xber\xda\xb7{n-\xd2VlO\x1c\xca\x9f\x92\xa4\x9c`\xe4\xd8[JZ\xb6'\xce#~\x13\xa3\xc24y\x85\x80\xeb\x94\x12\xd7 ,\x16\xea\x9c\x81\x8a\x8d\xfb=\x0b\xcf\xd2\xber\x0c\x87]wm\xa3)\x1c,\x0enk_W\xe8p\xf9\x0c\xc3\xe2\xc8\xe8\xf5%.\xa4\x95z\xa7\\\xe0l=8\x98\xe3\xcc\xc1\x90\xf7\xed y\xcb\xa2\x15\xb5\xef\x9a\x92x<\xa2\xe24\x1e\x06\xc7\\\xe0\x96\x8b\x82`1iMn'\xd0E\xaa\x1c\x99f\x96\xd3\x0fm\xe2\xf6\xd1\x18V\xda\xf4\x06v\xcc\xd7\xed>\xf3\xf5\xe6\xd53-\xdf5\xd4)TD&\xd2-\xa0\x1e\x8f%\xa3\xb7\xd2\xa7Xh\x8e\xe7\x98\xe4[\x92\x83\xd8O\xda1a\xf0\xcc\xc0Q\xb1\xcf\x16\x13\xf6\xeeN#+\xe9~1\xafR\x99\xef\xd85\xb6\x1dw\xec[8\xa8\xd1 \x8d!H\xe3S\xd6d5\xeb\x13z\x8f\x1fk\xban8h$\xd4.\xd1\xd5\xf5\xc7\xca}\x9cv\xea1)\xfd(.\x0cy=J\x8c\xa4\xfdP\xab\xf8\xd1Vo\xe8\x92\x85cX_e(S\xd5\xfe& kfc\xa7\xd1G\x8d\xe0\xba7\x8d\xaf\x81S\xf9\xf8_1\xaa\xed\x84_K\xdd\xf4\xb5\xca\xf7\xb6\n\x8e\xc1\x0d<\x04\xe1\x86\xb8]\x95\x99\xae\x03\x18.4\x9f>7\x0e\x8e183\xb80\xb0\xc8\x0c\x8e\xa5'4\x04\x17m\xf2x\x06\x06\xe6\x9c\xf3\xa7\xda\xcc\x89\xf4j\xca+\xba\x98\xb1\xf7\xf5|<\xd2\xcc\x871\xb4\xb2\xea\xd7\xb1MS\x11=\x96\xe7\x97 k\x10|\xed\x0c\xe6\xe6\x06\xd5\xe1-\x97\xf0\x85\x97\xeb?C\xbc{\xdd\xf4\x9f+\xa5\xfe\x13\x9f\xf4\xb4\x96\x91x\"S\x80\xaed\x9a\xd1\x0d\x7f\xd0\xd3\x8c\x16\xfcA\xaf\x8d\x98?\xe8iF\x03\xfe\xa0\x97\x1dy!\x1a\xdf\x7f\xd0}\x94Q\xf1e%\xb4\xa7h}\xec@\x84\xa2\x83\x8a\x9aU\xab\x8f\xafO\xdd\xda\xda\xd6T\xa9\x94\xa5&*\x99\xfd\xac\x99B\xb9\xb0Q\xbcEm\xc5\x9bE\ne\xac\xd0\\\xc7]\xbc\xc9\xe3!\x96-\x9eU\xb9\xad\xce\x90\xcb\x19\xc2LG\xce`!z\xe9\x12o\x93\xc7.\xe6\xe5\x17;5N\x99\xa3\x00\x95\xe4\x99;\x87+\xd1\x14\xca\xe7*\xe5s\xd5\xd4\xe3\x8c\xdc\x91\xc7\x1d\x8f\xd2\xbc\xe7\xf3\x04`\x9d\xe3\x17\xc9|\x7f\xbaT\xba\x86f\x9b\xb3\xa6\xabd\n\x0f\xc1Y\x95eV\xccn\xdeL\x13*Q\n\xbf\x06/JoV\xef9 \xab\xaa\xd7K\x8a\xab\xb4\xb1\xc5\x0d\\\xa8\x15\xa6m\xcb\x9b\xd2\xc6\x16\x08z\xf9K\x14\xc7\xafH@\xa2-\xd2\xb6\xc2\xc2\xec\xa6\x94\xd3\x85\xe2}\xf8\x12\x81\x88;\xb2p\xac\xc7uB`\xdb\xa5\x02\xddr\x95\x03\x96K\x1eZ'\xf3\xb1o/\xa1\xec\xd4\xbc\"[\xa7\xd8\xa9t\xce\x1b\xba\xe3\xf6\xe4\xd3\xed\xab\x9e\x1a\xb1d\x99W\xf8t.\xffM\xde\xe41\xa3Bu\xb1\x83j\xf2TqF^\xb0\xc9s\x92\x94OXj\x08s\x85\x93-%I{\xcc\xf9\x03\x7f\xbb\x1b,4\x97f\x05\xff\xc6f\x0c\x18\x9f\x88~\x16{Q\xf1\x93\xff\x93\xbbB\xfd\xca\x8a)0\xc4K\x1b\xaf\x88\xa3\x80\xd0M\xb2\xd2U\xc9m\xf9dlzy\xc5|\x13\x9fDw\xc3F \x87\xeb\xa4\xd5:\xea\n\xba@=dU\xbf\xac\x12\x92\xb1\x9d]\xb5\x89\x89\xf5\x0c\xf5\xb5\x00\xb5 \xcb\x17\xf3_\xad\x12\x99\x95\xfeR\x9b-F\\\x9d\xdd\xa7\xcdB\xd3~\xa7\xca[\x93\x9a\xdf\xa8\xf7\x9f6\x8bC\x0b\xdc\xc2& \x8c\xe7\xe8\xae\xbei\xe9\xa1!,\xf0\xe5\xcf|L\xa3m|\x0d*\xb2\xc5\x8d\xc5\xe5*5:\xf1\x89+\xc5@M\x816\xcf\xa2\x82\x9e\x8b\xb4ez\x98&c\xc8u9g\xc4\xc5\xd1\x8f\xc7j\xba%\xaf\xa3\x85\xa5\xad2\x98\xc1bTi \xf3Q\xad\x16\xdc\xb9\xb0\xba\xb8XJ\xd1*3\xa4\x05\x9a\xd0\x8b\x9e\x1e/\xb1\xac\x90\x05\x96\xd0+\xcd\xac\xd0\x1b\xaarE\x169@\x01\x83\xb9\xe9JY\xa17T\xdb\xc7\x08\xaa\x91\x8c\xd8\xe3F>D%d\x13\x8a\"3\xa6\xb5\xfd\x06\xa6\xbaB\xde\xab[\x0d\xaf\x8c\x9fR\xa8\xc9\x17p\x856D \xce\xfe^]8\xe9R\x96mYy\xe6\xcf\xc9\xb2-\xad\xe1\x9b\xaaj\xf8F\xaa\x1a\xbe\xbe\xaa\x86\xefFU\xc3\xb7P\xd5\xf0\x8d{5|Y \xcf\x82K\x05m\xe8@\x04\xcb~\x16%~\x0d\\\xfb\xa7\xe4\xd8\xafi\x88\xe0\x10\xee\x9cq\xe6\x8c\x1bPC%\x02J\x0d\xc2\x8e\xb2`\x15\xc5aN4\x944\x1d\xc6\xa9GC\xb8t\xdf\x9aC\xdf\x0c\x90/\xb0p\xb2\x8e%_\xb0\xc38\x0d\x8e\xce3?)\xb4Q\x14\x19?\xb8I\xf6,J\xdeE\x89fFCQ\x04\xd8Y\xf8qAX\n\xfeL\x0dO\xb9\xf4\x0d\x96\xfd\x8c\xfd\x0c\x1dk\x95\xa0[\x06jSes\xcd@\x1f\xf3\x1e\xeb@\x97\x0c\xd4\x04V\x05\x164\xa1\x1aJ1\x9cb\xab\xb7\x15\xb5r\xc8\xe7yz\xa6\x19\xdcY\x14R\xd2\xe0\x1c\xec\xeb\xbccH\xb4\\\x95\x0cjpo7\x85>\x14\x88\xed\x08\\\xab\xbf\xc4\x14\xcf&\xd8\xe7 r8t\xa9\x9aw5\x9d<\x8f\xa3\xe4\xdd\x0f\x83>\xa6\"6:\xad\xa3\xb6\x86rT\xbc\xc8HB \xf6\x91j\x9er\xa3\xf9@\x92JC'xg\xe2)\x1a\xe6{\xce'BcX\xab\x9d\x16y\xba\xfe\xf1\xd8\xfd\xbd\x1b\xcd\x87\x1a\x0f\xa7\x9e\x94\xf7\xe3k\x97\xd0\xb4/\xd4g*\xa1>S \xf5\x99J\xa8\xcfTB}6,GS\xe6vc\x94\xa9\xe4\xeef:\x97\xf3\x05~\xed^sY\xb96@&\xecg\x1f_\xd8\xd7\x9b\xe9\xbe\x08\xfb\xe2\xfap\xc2\xbeP\xa4\xaa\xe1r\xcbT\x05)\x87\xc3@R\x0dc\xc9\xb4\x07\xe9r\x19\x13d1\xd5\xa0L\x82O\x93\xd79\x15\xf8\xf1\xb8T\x03o8\xf0#? Hl\x00.8\xf0\xd19 6\xba|\xfb\x0b\xa3\xe1.\x1b\xa0<\x08\xadU\x12\xabjq\x8cz\x8e\xed\x10s\xea\x1a\x81\xad2q/+P\x8b\xef^\xb0 \xf5\x8b[\xc6\xef\xce+P\x8b\xef\x9e\xb6\xdd\xce*\xc6J\xc3z`\xb8\xbd)w\x02\x15\x9f\xcf\xbc\x90d9 \xfcRW=\xe0\x1c!\xb98\xa4\x06;F0}n\x8bG\x08c\xcak\xf1\x0e\xa1R\x8dn\xe7;\x84\xd0*\xe0^\xf0\x8f\xf0\xe9\xd2\x95\x9c|\x89\xa0~\x1c\xa7g\xaf\xf3\x8b\xa7\xe5\x8b\x8d\x06\x83_\xb3y\x1b\x98-\xe49\xeb0\xff\xfa\x11\x13?\xd5\xe0O\x11\x9c\xb0\xbd\xf94y\x99\xa7\xcb\x9c\x14\x1a,\xf9\x15\x0e\xe1\x9d\xd7P\xea\xa8A\x7fB\xd0\xa6\xeeF\x0d\xfb\na1\xdd\xb7,\xa3\xb7\xb8\x1e#\xc6 %Q\x9ai\xb5@\xcf\xe0\x10\x1e3#_\x15\x02\xae\xd3\x8f\xbd\xa9\xe1\xb3<\x0d7\x81\x1e\xfc7\xee\x8f\x8c\xa9G\x9eEE9r\x1f\x8f\xe1\xc4iT\xd5\xd5\xf5\xee \x1c\xc2\xb6F\x9bc\x1c\xba{<\x86G\x9a\x97\xfe\xddQl9c\xf8n\x0c/4\xca\xab\xef\x9b\xbd<:/ \xeaI\x8b\x91\xfbX\xd3\xcc\xcf\xc8\x04\xd9\xcd\xda\x0f\x0c\xb6YKX\x0d\xfc\x0b\x03\xe6\xf8\xa6\x83\xfc\x91A\x06,w\x9d\x1a\xee\xbf\x19\x9c\x8d\xf2\xf5\x1f\x0c\xd4F\xf9\xfa\xbf\x18(\xc7G\x1d\xe4_\x19d\xe5\xd5\xc1\xb2,h_\xf9?\x9dW\x8e\xf4I^\xfe\xd9ma\xb3^\xfb\xb96\x17\xca\xfff\xaf\x98\x14\xc2\x84\xf2/!\xcf\xe9S\xe3\x86\xda\xa5\xf7\x19f\x8fe)d\xd1\xc4\xf9-\xec\x9b\xdc\x95\xd0\x9d~\xef\x19\xee+\x1e\x9a\x97{\xad\xec>,F\x87\x838\x9c{\xd3\xb9p\xe4\xe8\xe0R\xf43\xf1\x8c\xa1$\xb6\x16R\x10\x1e\x04\xb4\x7f't\xdfI\xd2\x84\x02\xd8\xe69\xb1\x12\xe6\x9b\xaa\xdb*\xe7c}2R\xf9\xf6\\\x06\xe2\xc0\x0dx\x047\xc0\x91\xe9x\xdbP\xea\xd5\x8e\xc2\x99F\x03\xfe\xefZ\x01\xaa\xd4\x80\xaa\xa6\xe0\x9fZ-\xb1\xc0[\x94ngp\xaa\xeea\x83S\xd5\xfa\x98\xb4}K4\xa7w\xab\x84\xd3Z\x0f\xd7\xf0\x9f\xd1\x1c\xf6\xb53\x84\xca!W=M\xffm\xa7x8\x1f:\xfdC0\xb0R\x8d\xab\xeb\xe2\xbf\x1f\xc3c\xba!\x1f\xb3-\xfe\xc7\x1f\xcc\xff\xe4\xf0\xf0\x10\x1e\xd7\xce(\xea\\\x13\x06?\xe8J\x15u\xeb \xd3\xd5S\x15z-\x03\x18\xbaU'\xee\xed\xe9TC\xe8d\x13\x10\xa7~\x18%\xcb\x89\x9fDk_c\x1f\x19\x8d\xe1H\x9bX\xc8`%\x91\xb5\x8d\xea\xcd\xd3$\xcd\xd7\xbe\"\x07\x10&x\xfa\xc5\xcf\x93(Y\xce\xe0qM\"Fc\xf8\xd5\"\xcf\xd1\xb0\xfe4\xd89}\xa9\xca\xab\xc6Bcf\x10M\x83\xff\xb01G\xfc\xaaX\xd4\xd1h\x0c?\xd1y\xfc \xc3=/\x91\xb6E6,\xc1\xf3N\xc24(v\x9f\xd1\x0f\x86YO\xa2$\x84u\x9a\x13\x08EF\x9f+^\xd8\xd6\x0c\x0c\x1f\xb91\xd0\xd5\xd8\xe6\xa99\xeb\xcceq\xeb\xa7\xa6\x18\xa4\xc23u\x1b\xff[\xd7\x86}\xb0\xac\xc5L\xc4\x91\xf6\x0bJ\x8b\xd6O\xda\xe8X\xf6\xb4\x91c\xa7yj\xa87\xd4\x0f\xbaa\xd7R\xc4\x0c~\xb3:\x85yA\x10;\xf1\xa3\xe2Ef\xf0X\x03\xc5+x\xff\x03\xdd%uj\xb8\xa6\xbaL\xeb\xaa\xdb\xd2\x95I\xeb]\x89\xab#\xb9\xcf\xe0\xb9\x86mi*\x12f\xf0R\x0d\xb9H\xa4Ev\xc4e\xcdP5\xb4d\xda\xecE-\x15\x996\x7fQ\xe6\x97\xab\xe7\xdc\xb1\x93q\xe1\x86nr\x17\xe4P\xb1\xe1*l|\xae\xc1\xc1\xbf\xeap\xd0z2\x98M\xfeX\x0d \x1cV5Ly\xda\x91\x1bgB\x03Q\x98\xe5H\xda~\xf5\xda\x16\x15b\x85;\x12\xda\x91\xe31T\x1f\xd1\xe9!\x96\x84\xbb\x83\x91\x90}l\x06s\xafh\xdd\xd1\xacs\xff\xe5\x0b\xafw\xd3\xf0>\x05\xf9\xd9\xcf#\x8a\xf0?3\xed;\xffH\xef\x89a\x18Mx6\x8ca_8Z,HPF[\">\x85\x9d\x11\xdf\xa9\x9e\xe2}3\xfe}\xf5\x15\xbc\xa4\xff\xbc\xc2\x7fLtq\xa7cV((T4Z\xd5\xd8\xff\xd2\x9eo\xec\xa33x\xf5aq\xdf\x96\x98\xf0H\x16\xa6!\x9b\xc1\x13\xc5\xcc\xd7S\x7f\x15S\xfc\xbcRu\xbc\xa4\x12\xf9\xbcL&\xcb<\xddd(ys\xfd\x95\x91\xb3{.\xdeW\xf5\xe8\x17+\xc9Y{Z\xd9\xce\xe20\x92|\xd9\xb5\xad\xec=3(\xacvJn\x9a\xaa\x1f\xb5(k9 \xf6C\xd3wz4\x86\xa7W\xb5\x97\x85 \x1aT\xc1dCw\xf3.\xcd)]'\xaaey\xa6\x19\xe0\xcf\xba\xd6*\xb5\xf1\x0c\x9e\xa9g\xbaJ\xea\xab\x89*\x11\xcc\x90(\xfb\xa0\x8d\xfd\xb0>\xb7[l\xc4Ul\x98\x86-N\x9b#\xd2\x1aK\xb9\xf5a\x06o\xcc@\xfc\x90\xda\x8a\x80\xbf\x97\xfc\xfe\x934w\x19C\xa59\xfc\xfb\x8c\xb4\x95\xce\xdf~\x1b\xa9A\xe4\x86\xad\x19\xbcV\xbf\x82\\\xac\x89\x9a\x10\xf4\xa0\xf8\xdet\xdc\xfe\x1f\x1d\x06\x93J\x17>\x83\xef\xad1\xce@2vq\x1bz\xb9\xc9\x89\xcce\xa8\xca|'w\x19j\x9c\x1c8)\xad\x87y\xb5\x99d\xcf\xf8\xa6\xec?\xaaQ\x85J\x8a\x0b\x8fY\xbc\xba>5\xcc6\xa1\xf3B\xfa\x12Z\xd4\x9e1\xa5\x17\xd2B\xee\x85\xb4\xa8\xbd\x90\xee5S\x19-4\xeeF_b\x8b\xfe\x03\xdd\x8d\xac\xfc~\x86\xc4\xfb\xe7\xf6\x0e-\xe9\x10\x87\x16\xe6\xa6\xd4\xb6\x13\xa9\xa1}K_\xaa\x0d\xd6\xd039\xa7\x14,\\\x9d\x91-5X\x80`QQ\x95=\xd5\xf0\x0d\x0b\x845\xb9\x9ed\x08\xa5s= Y\xd7V\xe9\xd9\xb1\xa9{+\xfe1\x0b\x17\x94-\x03\xcd\xa3e\x94\xf8\xf1\x0b\x9bW0\x12I8\xa2X\xbd\xb1\x84C\xc8\xcc\xb3z\x81K\xc4\xd5\x1d\xc1&\x8fJ\xadU{\xce\x12(Tu`\xab\xae|_j\x8d\xf9\xa7\x9d\xc4\x0b|:\x9f\x1b\x03\xbf\xcf\xe4/\xbe4\x04\x9a\xf3\x1a'?n\xd6\xd9\xeb\x14\x811;\xc4\x07\xb7.\xd7Z\x01\xd6O\xe8\xfc\x8d\x06b\x8d\x16\xb0\xae*(\x05\xd1\x08 \xa7\xba\x1e\n^P\xc5\xb9\xa9?{f\xaf\xa6\xd3\x05>v\x0c\xd0\x1a\xc3r\xcd\xe3\xc8\xe3\xc6ig\xc3\xab\x92\xfb\xba\xabcc\xafX\xd2\x83\xad\xa8\x99],\x8a\xedn\xe9\xdd\xd5\xc8\"{\xfen=\xab\x93\\D\x8a\x02\x04\xef\xc7 :Qg\xdc\xff\xea+\xb8\xf0\x82t\x93\x94\xae\xaeos\xbdY\xbc&\xb93\xd0d\xcc\x1a\x1e\xe3!N\xd4\x941\x94\x98\xef\x97JMT\"\x89r\xec[\xe1^\x982\x89 \x81\xae\x13\x06\x17\xae\xc2\x01\x05z\xacEu\xd7\xac\xb8\xd2V\xc8\xc9\xb4\x08{\x85B\x87!N\xa1\xbb\xcfL\"D\xb0\xb3\x08q=\x03\x19>i\xa6\xb2\x01\xc5\xa6?\xa32\xa3_\xc4\x04q\xed.&hK:\x9b\xb8\x8fK\x1d\x1b<\xb3\x8e\xf4\xdd\xf7c\x94P\xded\x19\xc9\x1f\xf9\x05\x91%W\xd9\x99P-\x86\x13\xaa\xfa\xbb\xe3\xcf\xa0\xc4\xf1g\xaa\xad\x10\x91S_\x94\x16\xff\xb1\xd4H\xcd\xc0\x95\x034\x11\x89Dc`\x14\xf5\xe9\xc6I\xac\xe2PR\x844\xc6\xa1D\x08\xa6\x8fC\xf1\x11F\x1b?\x82u\xf1\xed\x84\xf7\x82w\xecq\x9d\xc6\xc4\x18\xe1AO\xd8\xb2\x99G\xe4\xc3\x9f\x04y3'\x838\x0d\xe8<\x9d\x9e\xb6\x9d\x9d\xa5@\x83\xcd_\xdazUU\x02\x06\x9d\x02J$`\xd0\x98\xa2\xb2\x06\xdf\xca\x9ao\xfbO\xfbXy\x80J\xd8\x1b\x0d\x0e\xb2,\x0d\x91|\x84Wy\x04^7v\x99\x9e\xaa\xcd\x80\x078\xe4\xe5R\xfa\x87[D\xcf\x84\xfb\xb2\xd3-\xea\x96\xd0\x8f\xd8\xe9\";=\xa2\x8f\x7fz\xf8\x98\xc1\xa63J\xf5q\xb2\xad*\xca\xd7\xe6\xa6>\xe6$\xed\xd27b\xa5\xdb\xe1#\xaf\xd2\xb3\xee\xbe\xe6\x83M\x87j*\xa4\x0c\x9d,\x81\xcc\xfb\xf1\x95~\\Z\x9bS\xd7F\xb3\xb4i\x1d\xbb\xe2P^\xe3R\xfd\xc2\xf2\xa5*c\xbc\xaeC\xa2f*\xeb\x93\x1a\xacU\xe3T\x0d\x96[\xc0\xc8\xeb2\xaa\xcb~\xf6\x06\xe3<\x89H\x8cN\xe5\x1f\xb2\x114Q\xb3\xa2\xa1\xeafZECK\x8f$e~qL~\xc3\xec\xb7\xa6\xcc\xa0\xdbF\x8d\xa8f\x9d\x9f1\x1c(\x881=\xbb\xcb\x93}\x85\xb3!\xee\xe4\x93\xa9$ \xc8\xb0\xad\x12\xd5Q\x84\x0cUT\xa5\xdeT\xb8\x8a\x9e\xa3\xcb\xa9BAy\xfe\xb3\x1f\xcb\xf4<\x9d\x04\x96\xef\xdb\x05\x10\xdf\xcb\xcf\x04\xf6\x99\xebu&\xbcJ\xcf\x0c\xc7\xc2\xed\xe9\x9f\xe2X`\x03\xb59\x19(B\xc8\xcf\x04\xe2Q|\xe8?C\xa6\x14\x1eR\xa63\xfd\xf1\xb8\xfa\xe1\xa2\x92\x91+\x1a\x87\x9d\x14\xd6\x94\x88o]#1ap\x9d\xbd\x1a}&H\xdbG\xcc?Q\x02\x13\n\xf0\xe0\xee\xfe\x9f#g \n\x9f\x98\x949\x1a\xc3\xa6O\xca\x15\x82z\x1fp\x91\xe6\xe0\xd2\xaf\xd1 \xaf$p^Bn\x8c\x13\xceR\xff\x16\xa31N\xf4\xfe\xd7\x10\xc07P|\x0d\xc1\x8d\x1b#\x88O\x82\xb7\xcd7O\x02\xf5\xc1B\xb7v\xc4O\xb2\xbe\xb2\x00ei\xa3\xc2 \xf0\xe3\x98k\x0d\xc8\x18N\xe8\xbboE\x11\x87\x18O\xe1\xc8Cs\x85\x1fG\xff\xae\xa5\x07c\x19\x07zE\x1e\xa1\xe3\xed{?\xbfG\xadBz\x865y^\x936\xef\xab\xfa\x1a\xf3$\xaai\x00\xd7X\xe2\xbe\xa3\xdfc\x7f.\xa2\x98PN\x03S-\n\xef%\xaf|\x0b)Z\x0dY E\xac\xce\x9c\xc07\xacVa\n7 \x82o\x0f\x99;n\xc2\xe2\xbbqs\xf39}\xcc\xd6JV]u\xcc4\x19=E\x17\xdd}\x1fC[u\x95\xb5\xcf\x98\x9c\xbf\x8a\x96\xab\x98\xce9\xaf[I$\xc1P\x1d ]\xc6\xff\xf5\xbb\xf7&\x0b\xfd\x92\\\xaf\xfe}\x02e\xdfV\x1f\x90\xc1vV%h\xe87\x14\xa9\x88\x0f\x15\xc3\xb4:.,0\x86\xc4\xc4\xb9\"\x9f\xeaj!&A\x1a\xaa\xca2\x8eQ/v%\xed\x89\xa1Nx\xc5yY57q\xd5^\x1dt]\x9a\x14Z\xd5M\xe71\x07r\xcc\x96i'\xcb\xf5\xc9\x01YYN\xda\xb4\xe4\xc8\xd1\xf5\xfa\x97\x15!qU\x04KG\xd0\xd5_i\xcc\x19\x96=\x80uD\xbf\xa0\xae{\xfa\x9er\x00\xc6M\xd4W\xc3\x99Tpr\xa7\xd7\xe6N\"\x1e9\xcf\xd2\xbc,Z\xc7S\x9f\xbd\x85\x06\xe7\x99\x903\xf8>N\xe7\xee y+[\x83\xf2\"\xc3\x91ST\xa7\xfc@\xc4\x8ad\xdfL\x83\x92\x94\x93\xa2\xcc\x89\xbf\xeeH\xeb\x1d\xf6'ZT\xf5v\xf7\x0e\x0f\xe1,J\xc2\xf4\xccK\xfcm\xb4\xf4\xcb4\xf7\xd6\xc5\xb1\xbf%\xb4\x0f#\xddC7\xefsV$.\x88\x82k\xa3\x87\x1e\xff\xda\x9bW\xcf8\xc61\x0e\xfe\xcd\xabgn\xae\x91\xe9C\x9e\x0c\xa4\x8b\xa6\xbeL\xef\x1dyX/W\xb8\xb6\xc1!8I\x9aP|\x8e\xbcUN(G\x9c\xd2\xdf\x05)\xbf+\xcb<\x9aoJ\xe2V\x9b\xcfa\xb2N\xa3\x1cq\xcd\x00\xd13\xb3\xfb\x1ec$\x9cq\x15\xd3;\x1a\xd7\xdd\x9d\xa7\xe1\x05\xe5\xd9H\x12>ZEq\xe8F\xc8\xa6\x05t\xeb\xba=\xc0\x9c\xac\xd3-\xa9\x01\x1b\x93\x95\x93m\xfa\xae1Y\xa9\xea\xe8}/E\xc9\xeb L\xc9\x95\xbfR1+R\x89Y\xbeJ\xcc\xda\xa8\xc4\xacB%f\xc5\xfcAOb\nx\xca\xc7\xbe\x1cUKZYU\x12B\x98>+\xe0?\x81`\x95\x8f\xc1\x97\x0bV\xd1u\x14\xacr.Xml\x05\xabt\xa8`\x95{\"x\\\x84\xe1\xfc\xc2B\x04\xad\x84\x0e\xde\xd5\\T\x88\xac\xc3\x85\xbc\xa0\xf5QT\xa8\xba'\x02\x10M\x90\xd5k\xcc\xed\xe2-\xe5\x9f{\xad\xbcg]\x14\xf1T\x8f\x18\xfb\xf0\xfa\"#\xac\xd7V\xdd\xace#\xca~\xe4i\\|\x17\x04$+\x7f@\xf5\xaf\x89\x9f30})\xe6v2\xb0\x8f\x11\xba\xedY\xa5@\xf4\x11To\xa4\xdd \x8c\xceO\xa6\xac\x08\xbad\xea4EZ9\xd1\xd3\xe5\xb4d\xde{j\x00\xe1>\xbb\x91BH\xaa\x17\xbd\x1f3\xabs\xafp4\xdd\xad\x96\x82X!\x15\xc4|;A\xacX\xa5\x9b8\xacX\"ka\xc7\xb4/\x1a>M\xdd\xc0@\xe4NH\xff\xb6(\xbf\xcf\xde\xaab\xdb8x\xfdw\x1bN\x84\xd6q\xb0\xeaO9\x14n\xc6\x0e(\xbb\xd7\x86\x97\x07\xbc\xf1\x17\x15\x0f;-\xfa\xe5J4D\x7f\xb6\x9f2D\xe1\xcf\xd9\x1f}\xdch/\xffG\x92\x06\xf5$\xc1F^d\x1e\x19\xd5z\xe9)C\xd2\xc3\x03=yH,\xbdN65\xac!\xa5,\xf3\xd3\xb0\xcc\x13\x8bl\x841\xefm\xd2\xc6-5p\xc8\xdc\\\x06\xa6\x0d]U=\xd6G\xd5l\xf9\x11Zi\xed\x8e1\x89\xdf\xa34$#7\xd5x>\xac\xb1\x98\x8f\x13\xd4d\xd3T\xd1\xc6w\x9d8\xda\x12\xb1\x86\xa6\xca6~\x1d\xbbj\n\"\x91m\xf5\xaf\xbe\x92\xdd\x16Q\xa4\xb27f\xb5\x84\xf7\xb2\xf5D\xdd\xf8)\x1cB\xd1\xac\xf6\xc7\xa6rIJv\x82>b\xe7)\x95p\xc5\xb0\xe9\xacJ\xcd6\xe229\xee\x0c\xd1+T\x1b\xcc\x98\xd9\xe0J\x9a\xb3q\x01\x10\x971O\x16w\x05x\xd5\x88_n\xcf\xb5)q]\xec\xcfI]3\xc4\xe4\x08\xd5i\x0e8b\xa3\xcc\xad\xcb\xa6\xa5\xad\x16\xc3\x89\xab&(L\xb0\x97\\1\xa2\xe065\xc4\xa6\xde\x7f\xc5\x0c\xe6\x1a\xc0\xc6:\x89t\x17\xfc\xe5 \x8eQ\xbeJ#]\xc6\xabA\xc8Q\xe3b\x94\xe8\x92\"Df\xa5\x9a~E\xb5\xd5^\xea`i\xeb|\x94\x1a^\xae\x99y@\x93\x03\xaa\x93y@CP\x18\xf7\xd8a\x11\xcc\xbcd\x8fk\xd0\x1c'\x8a0}U\xfe\xa5\xe1\xdb\xd4B\xc9(\\k\x86b\x0e{o0=i\xbb\xe8\xa8\xc1\xf2\x1d\xba\xb4+\x8dS\xb8\xe1\x88K\xed\x8eS\xa1\xf0\x84\xde\xe39wU\xcd;\xf4 \xd7&\x03\xbc\xa2~\xd8\x04\xbb9\x8f\x1b@]j\xfe\xa1;\x18G\xc9;\xcd<=\xc3\xc7un\x07\xdd\x8c\xb5<\x9bR\xa5gS\xa9b\xa5\x81\xb3\xd3I\xdf\xc3\xa9T{8\x89\x0bYg\xa5\xa7\x93\xb8\xb0|\xc9\xc9\xd4\x00\x15\x027\x18F\xed\x0c\xcepx\x08)<\xac\xf1\xfc\x94'#A'_G\xce\xb8\x80\x99y\xb9\xd0\xad$\x08a\xc5P\x96\xb8\x8e:[\xb1\x1c':6\x15\xd0\x1d\xf8\xb1\xd0\xa6mQ\xafkh`\x91h#\x13\xa1\x8du\x1aZ\x8b\x90iH\x8cC\xaaO%M8/\x0c:I\x803\x07]u\xce\x8c\xa2\xc6\xe1\xa1.m30\xbe\xa4\xabK\x9aa\xd9\x0f\xa5\xaa\xc9\xdc\x15\x0e\xae\xe5\x87\xc0\xfeT\x85\xfeI\xad\x84U\x14\x85n\x15\x83\xde!\xa1K\x8d\xe7;$u\xe9'C\xeaGX\xd6\x99\x83\x98\x85\x98U\x8a\x1a\xb9'-\xfb\xcf\xaf\x85\xa4\x16\xa7\xea\xa0\xdf\x9b\xd6\x03\xf8\x1c2\xb9\x84*w\xacP\xe5\x8e\x15\xaa\xdc\xb1B\x95;V\xa8r\xc7\n\xa5\xe6\x8b\x98?\x91Z\x10\xdcP\xd8\n\xc2\xcaV\x80\xbf\xa6\xb7z\x05\xa4\x17R\x8b\x03\xaa\x07Te\xa5\xc3\x8fo\\X\xd9\x1a\x17\x88\xc4\xb6 C<\xb3hkjo);O)\x0e\x8d}\x914\xc1'+\xf2N%$n\x90\xba<2)\xb9\x12\xe6\xeb\xd3oF\xfd\ns%\x92\xd1m\xf9\x99\x8b*\xec\xe3\xd2/uJ\xeb\xbcO\xb2\xbbK/\xae\xf7h\xd82\n\xb4\x9a\x11\xc8\xcf\x9c\\\xd1Z\xef6\xfa{Q6\x84\xf4\xe8\xa5\xb8\xa4\xc3q\xfa\xac\x1d\xfd\x94\x02\xbf\xe1\n\xdd\x94\xaeF\xb3\xca\x08-Z\xe0RK\x1d*3\x9aP\xfeB\x0d\xc3\xac%\xe6\x02d\xccbb\xe1\x9a\x13\"\xa0Y\xaf\xb8B8\x9d\x12t\x8b\x10v\x9a\xdau\x0dk\xd0\xd4.\xab\xfeYhj/\xf8\x0cVx\xa4\x06\x9dW\xa0\xf6\xf6\xb1S8\x84\x95\x17%\x0b\x92c\xaeS\x8d\"\xe1\x0c\x0ea\xc9\xc5!5\xd4\x11\x1c\x82\xcf8u&\xe2h\x93\xfa\x9d\xd7\xd0\xe4\xdc_g\xb1>\x07\xe0q\x0d\xced%\x0d\xec#8\x84\xadU'\xdeqH\xe1P\xc5\xe5Q%\xfcw\x0c~\x9d\x86$>b\xbd\xd6\x81\xbf`\xe06%\x80^2\xd0*.\xd3TL\xe75\x83\xb7Tp?\x17\x9b\x16i\x97'\xa1Q\xf4\xc8\xbaPP\xf1\x05\xb8g\xee\xc8$/>\x15+\x84\xc5\xb2x\xc7\x9c1<\x7f;\xe6\x8a\xe7\xe7~6r\x7f\x7f\xdfe3\xba\xd7\xafp\x08O\xb9\xc4\x87\x88\xe9\xf4>\xa0\x16\xf1\xeaP?4M=ma\x98#\x94\xe0\x99W`m\xa0hq1r\xbb0T\xccf@KR\x1e\xe3M\xb6AF\xee\xaf\"\xec\xd70\x9b&A2J\x82x\x13\x92W\xc4\x0f_$\xf1E\x8b\xcb\xec^\xf4\xd0\xa3\xc7\xcd\xaf\xf0\x10\xcaJy\x95\xf0;\xa7U\x9fj\xc5V\xce\x9f\xb9\x8d\xcc\x89\xcd\x151\xf5]L\xfb[\xfaI\x85\xe6\x8d9T\xd1^\x9c\xba\xbe\xe8\x01k\xda\xf7V~Q\xad\x1d\x9d\xf2\x90g\xfb\xacnQ\xb9\x14\x07\x95T\x0b\xd2\x9b\xebd\x0c\xcfu\xf3(\x99C\xcdi\xc4\x80\x7f\xc9\xa3\x92hg\xfc\xbd\xde\xfcq\x8e\xbe\xcc\x94v\x9d[\x04\x8a\x89K\xb0\xc0\x94\x1d\xa2l/+&\xf5\xd7\xbf\xe6d\xe1\x08\x97.\xda\xae\x8a\xebQ\xe0;\xddu?Y8\xf05/a\xdcF\x0bTeo\x1a\x16\xff\xd6\xbc\x9a\xb1p\x0d3\xbe&\x16\xaey\xe5\xda\xb8\xb8\xe6\x95\xf2\x1893\xa4\xe0\xd0[{<5%V\xba\xa4YK\\\xc8t\xc9\xd9IqiMKw*\xcd]\xaeQ\xf2)\xe3\xfe\x9aW\xdb\xa4\xc2h\x9by\xf68[(\x8f\x19\x17\x97,v\xbc~V+-(J_\xd6^b\x1c\xeb\xf0q\n1A3\x06A\x05\xe4\x1b\x92\xa2\xf7\xf9\x18\xde\xed\x98\xdc`\x07M>8p\x03\xdc\x0ds#\xd7l,'\xf4K\x9f\xb9\x85+\x03\xff\xafN\xdd>D\xd7\x1f]\xa1\x9a\x7f\xb0n\x7f\xe7}-[\x8bn\xab\xa7\xa7z\x93\xa1\xaa\xf1\x17\xba\x86E\xd5\x1f_\x94)l\xd8&T\xa7\xc4\x18\xce\xcc\xbb\xcdj\xacL\x9dWQ\xf3\xe6\xd0\x1b6Y\xd3\xcet\x84@2\xf1Q\"\x11\xd6\xa8\x19\xcc5[o\xe84\xbe\xb60q\x1b8\x1e\xf5\x94\xb4\xec\xd7|-\x04#E9\x9b\xee-\xef\x1da\xc7(\x88\xc4\xd5\xc7\xe4\xb7^\xd2\xb9\xe6\xd51\xb1\xcb\xf4>\x8a\xf5\x1e\xc3\\\x9b\x83q\xed\xc7\xb5\x83\x81\xc3\x9d=\n\xd0E\xa1 \xe1\xa8^ar\xa43\x1a\x83\x03l\xe9\xbc\xda\x06Uq\x9b?i:\xf1\x9d\x16\xc5+K\x89u\x9a}MV\xfc\xa6Z^S{\xb1c\xa2\xd0\xd5^D>T\x88\x02L\xb5\xfd\"\x0fIN\xc2\x91\x9bhV\x94\x1fB3\xf8I\xb1p\xd5\xd4\x1di\xa6\xee\x91n\xea\xb8h;\x83#\xeb\x99\xd3\xf7e4\xae\x04\xfc+\xb5w\x0e0r\x1e\xc3C8\xf6\xcaT\xc6\x85v\xa2W\xba\x97\xe1\xc0}i\"T\xc8\xb5i\x14<\xf4JpP\x06 :B\xad\xfe\x11,\x17\x064\xa4p\xa4\xad\x87Yo\xdf\x9fR\xe0\xaa\x92j\x95{\x1f\xbc\x94\x05i\xa5\xb7 \xd5fCF \x85u\xe8\xf7\xf7]s\x89\xcc\x9a\xd7TL6T\xffm\x9b\xd0\xea\xbf\xf8\xcdke\x13Z)sG\xacTQ%+UT\xc9J\x15U\xb2RE\x95\xacTQ%+\xa5Mh%lB+\x8c\xc8\xbf-\xb5\x04\xb1g\xbd/W\xe6\xa0\xf6\xedP\xf4]\x91no\xf5\xf1\x0dE[[C\xd1\x97(\x94\x8e\xd1\xca\x14\x85\xa2\xb7\x88d~^\x90\x90oq\x85X\x85\x91\"\x1bt\xdd\x7f\xd9\x04\x1fd\xf2\x12!)\x9c\x1bSk3\x99\xff|\xa9\x16b)\x10S\x91@\x94\x14\xa5\x9f\x04$]\x00\x0b<4\xebC\x12\x1e,\xf9$\x8aQ=\xa52\x8f\x89+\xf1R\x16\xc6g\x91\xc3\xa0y\xe56\xe6\xb5\xe6\xd5] \xca\x0cobydn\xf3R\x9cD\xd5\xe31~\xca\x0f\xbf+^\x93\xf3\xd2\xd5L,\xd7\x1bZ\xf7\xbc\xd3\xe3\x92\xf2\x07\xac\xaa\xbbN\x03!C\xafO\x1b\xa4r\x95\xd9\x02PN\x90\xec\x15\xd7\xea\x88W\x07a\xec\x942@\xb9)\x95\xbd$b\x7f^\xa2\xabWc\xd5\xb4\xb4d\xd6\xc1g\x16YB\xad\xccu\xac^\xc9&\x97$T\x12\x17\xabR\xc2\xf9|5\x98_\x9b;Xz\x8d\x87\xf0\xfb{\xd0\xba\x0fo\x06d>-\xdav\xa3\xd6nT\xbf\x85\xf5A\x06X\xd5\xe8\xc1\\\xfb\xf2\xa1\xa6\x8b\x92\xcf\xc7~I\xb0\xbe\xe8\xebhMt\"\xf4\xba\x9a\x04\x8d4$\xc9\xf5\xd5\xbc(\xc5\xa7\xcb\x92\x8aL\x0d7\xffo\xc3\x87\xe9_\xad \xf6\x9b\x91W\x92\xa2t\x93\x11\x05\xf6O\x1c>#\x93\xc7Q\x91\xa5\x05f\xe6w\xde\xd2\xe3\xe3\xa6_\x96~\xb0\xa2\x07\xb5xI\x05.\xbe%4,\xa1\xdd\xb7\xa4\xe0\xbd~5\xb4G\xec[\xf4h\x82\xd7\xb9\x9f\x14\x0b\x92\xcb\xba\xd6|\xa3\xd75\xeb\xcfI\xdf\xd0(\x8f\xe9*8\xf4\x98u Jx\x9c\xb9\xe9$\xa4[\xf9\xa2\xca\xb1Q\x92\xf3\xf2\xe6\xaa\\\xc7\x16\xban\x0c\xce\xe9\x1e\xf0\xc2\xcaV%;(\xa5\xc9\x0ed\x17K\x80pa\x84\xed\xca?\xb2\xebT\x9f\x94`n\xf1\x8938\x84\x93\x0b\xca\xd0\x15\x9byQ\xe6n\xea\xc5~Q>MBr\xfeb\xe1:7\x9d\x11\xdc\x80\xe9h\x0c\xa7o\xbd_\xd3(q\x9d\x99n\x9b\x8a\x0b\xed\xfc*D\xd5l\x08=\x13\xd4\xc9\xfdpdZv\xe0K\x7f^\x99{\xc8y\x99\xfbA\xf9\x84\xe7oz\x92\xa7k\xde\x8fF7\x98W\xc4\xc8=2\x18\x84\xe8\x85!<\xb43\xcc\xeaG\xe7\xf3\xdc\xc0 i\x9fR\x1aTy]\xd6\x99+\xe8\xc7%\xb7yB\x8b\x17\xf9\x8b\x8c$\x1c3/eIq|\xa3\xc6\x16\xaa\xfa\xec\x06\x07\\\xd8\xa9\x06\x8a\xb88We3hw>\x863\xfd\xa4\x83q\xe2\x9bYf`\x11 #\xff\xb5\x9aM\x91\xcbc\x06g\x83\xc7\xa2|\x81\xb3\xdb\x14\xf1\x94\xe3`)u\xb8\xce\xa8\xfa2\xe7< $%\x96\xd6\x86\xf9\xa6\x84\x8bt\x93\xc3\xd7r/\xda\x99f\x96k\xda\xe7\x06'\x84\xa2\x81\xdbN~\xc8x\xd7\x9b\x14\xe8_7\xb3\xd8\x8f\x92\x9b\x8d\xd9\xff\xc8\x036\xf0k\xc2\x88\xa7\x181\xcc\xe0\xe6\xff\x8d\xd6\xfe\x92\xfc\xebf\x0b\x87\x12\x8f\xbb\xfd\x14\xaeSl\x97\x8e\xd6\xb0\xd1\xa4\xf9\x0e8\xa8Fv\xc0\xd1+\xdb\xd7K\xed!\x80\xf9\x9ed\x9a\xcb\xe6\xb5\xf6\xcf\x7f\x89\xc2r5\x03g\xba\xbf\xff\xff\x93c\" \xe5W7\x94\x073\x1d\xbb\xa8\xd0\xc8\xf0\xb9\xf37a\x94v\xe6\xce\xea\xb8P\x9f\x8d\xf4\x8bzC\x117G\xaa\x1d\xb1tA\xd1h\x1c\xd7O=\x9d\x11]\xado\x96\xacL\xb5\x89\xe8\xc48\xcc\x7f\x88n\x1f\x04O\x17P~\xfc\xbdQ\x9e\xcbtE\xe22o\x0d\xee\xe4\xf5-\xec\xc3C(lw\x80z\xf9\xad\xcd\x7f\x91:\x9c\xf1M\x92\x93 ]&\xd1\xbfIX\x99\x89p\x8e\xbf\x16\x81A\x94\x89\x10A\xee~\x81\xd4\xdd\xd3E\x8a~\xca\xd9/4\xa4\xf8\xd3M\xe4\x06K\x91@\x99\x8a)\xad\x8d\xf7Z\xb7\xa5\xe5\xa5q\xa4\xe1\xc5Vg,\xc0\xb0Tz\x9e*]\xab\xacm\x916UH\x98Yu'\xcb`\x95\xef\xd0}p\xf7\x8e\xc4\x88\xa7\xd7}\xd6\xbe\x9eY\x1c\x95\xeeM\xf7\x9b\x7f\xdd|x\xf2\x7f\xbf}{\xe3\xdb\xd1\xcd\xe5\xc8[DqIr\x0b\x0fK\xfe!\xc7\xa9\xb2\x0dEkY\"\xdc\x8e\xfa\xba\xdd\xdf\xc8\xb6\xbf7\xbf\xf9\xd7\xcd\x1b\xac\x9b\x9c\x11 \xda\x0f\xfb\xf6\x1f\xc6\xaf\xfe\xeb\xa6\xddw7\xb6\xdf\xb5\x9e@\xec\xc0\x9er\\\x80\xc8E0\xef\xf0^$~\xf8\xbdn\xd6\xf8!\xcf\x9d\xd9\xed\x850JuM|\xf0-Li\x13\x0d]Gm\xcb\x9b\xbe\x85\x87\xed?g\xf0\xbb\xe4\xdcg\xb1[\x82\x83\xed?G\xbd\xad'a\x89\xfb\xa01\x1c\xca\xf4\xa6\x01\x1c\xc2IGeSg\xb2\xa5\x7fu\xe2\xac\xe9x\x17c4\x07\xbb\x0b8\x042\x86\xd4]\xd8\xb8\x13\xf3uR)\xeau!]\xec\x14wK\xd6^\xe4\x96\x94uq\x1e\xc5i\x11%\xcb\xd7\xfe\xd2\x81\x19l\xf8\xdd\x17\x19I\xea\xbb>\xbf{L\xe2E\x1b\xdeyM\xe4\xb9\xbe\xe5\x01\x81\xed\xa3\xf7\xfdH\xe2\xba2\x86TeR\x8eLI\xeaX\xfdq\xa4\xe8\xbd\xe7\xad\x81R\x1e\xdf\xa7\x88\x15O&\xf2\x9e\xd2\xad\x95\xbb\xc9\x18b\x85\x92\x0fK\x89\xc3\x0d\x88\xfa\xef\xa3b\xb69\x83us7n\x8c\xa1\xd0\xd9Y(J\xa4'%L@\xe7\xbe\x1dVP\x07\nM\xa1|\xb8l\xb9\xf0\xef\x0c\xe7 ov\xbb\x1aV\x8f\x109\x1d\xac\x9c\x057 ds\x0f7 \xab~ET\xe8\xc4\x80\x05\xec\xcd\x18\xb0\xeb\xc6\xf0kh\xd0\xa6\x0eN\xb4\xc7\xc3\x81\x02o\x91\xe6G~\xb0\xb2\xdb\x1e\xd9 yK\xf7_\xf7\xe4\xa42jfw\xaa\xf0/\xed\xedu\xfc%F\\\xfb\xfb\xaf\xa6o\xe9%\x12\xb6\xde\xfc\xfb^\xdd\xc0\xdf!'\x19\xf1\xd1vB\x99\xbaoVe\x99\x15\xb3\x9b7\x97Q\xb9\xda\xcc\xbd ]\xdf\xfc5M\x8a`\x15G\xc9;\x92\x977[\xf0\xdf6\xbe\xd4\xfc\xe8\xa34\xbb\xc8\xa3\xe5\xaa\x047\x18\xc1\xc1\xfe\xf4\xf6\xe4`\x7fzg\x0c?\xa6 \x1cW\x1f\xf3\x9a\xef<\x8b\x02\x92\x14$\x84M\x12\x92\x1c\xca\x15\x81\xe7O_\x8b\xdbM\xd0\x9b\xd5od\x06X\xd4c3\xb3\x842\x7frw\xdeq\xe3\x08Ab\xaf\x12$\xc8\x08\xcaU\x9e\x9e\xa1\x9d\xe1\xf5EF\x8e\xf2<\xcd]\x87\x9cgL\xdd\xe6\x03\x7fI\x92\"y\x8a(]\x8e*^\xa3\x0fr\xd0\x05\x81\x1b]0\xe1\xa9@\xc4\xc1\xf4w(\xfb\x1f\xca\x19\xf7A\xa9~\xc3\xce\x98\x8fX\x16\xf4\xfe\xc4@S\x9d\x97Vg\xde!\xc5\x1b\xde\x97\xca\x1e\xb1O\xb1\xa9\xfd*z\xc7|\x8d\xa5\x00\xaa\x97\xd1\x0d\xe3[\x98~=\xa2''\x0b]qS\xb8q\x88F\xf8\x12\xbe\xfd\xf6\x10\xa6c:\xc4\xc3\xee\x18E\x8b\xf4P\xe2o\xb4\x1a\x1f\x86\xed5cxw:2\xe1\x82\xc2\xbb)w\xc9\xc8+\xd3g\xe9\x99\xa8D;\xac\x0f\x1f\xdd\x99\xed3,\xfe\xba\xa82\x1b\xd0_\xf7F\x7f\x8e\x82\xaf\xdb/\x05f\xd4\x05f\x84\x17\xfd\x80h8\x81\xe0\xb9\xaa\x8a\xf6\xa8\xe2\xa8\x8e\xceKM1\xef\xb4[\xb2;U\x97\xecN?\xbeZ\x88 t\x9d\xb1\x98-\x8b\xe6z\xddReh>t\xb7Jy\xa7\xd3Sr^\x92\xa4\xe8\x1d\xf6\xef\x99\xe7\xd4\x0c\x9c1\xf0\xa3)1\xd7\xda\x8e\xae\x1bB=e\x9ecG\xeb\xac\xbc0\x94\x89\xef\xc5\xd4\x8a*\xf1\x98S\xb5~'\x12\xfa\xc9\x88\xeb'\xafU\xc5x\xd5\xc8m\xf0\x10\xb1B\x85\x88Q\xc1\xbf(9\xea\x98\xf9S}\x02\xfb\xfc\x0b\x8f\xa3\x02)\x9d\x14\xa1\xf9\xb9\x8f4\x0f{\x8d\xda-\xf4\xf6\xbb\x0c\xaew\xf4\xa9-\xd4\xa7\xad\x9c\"\x0e\x9d\x96\xe9r\xa9\x11>B\xdesY\xfa\xe7\x9e\xeb\x86\xba\xbfQ\x92mJi#\xcc\x04\xee\x04+\x12\xbc\x9b\xa7\xe7\x12MY\xa3\x0b\xfd\x87\xf8\x1e\x1e!\xa8t\x90(tj^\xc9\xac\x9c\x8c\\Q\xc1\xda\xe3\x1f6\x1e\xb7\xa318\xc7$ \x01'\x95mL\xa7\xe7#\xf4Y\x95\xe8\xff\xa49\xa1\xe5&\x93Pj2Q\x94\x93T\xa4\x88\xbeu\xd0\xcb\x0b\xf0%\x17\xb4\xdc\xb0ag\xd4\xb0\xcd\x05-v\xe0.f\x82\xa1\xeeG_}\xd5\xfa[-F$&\x1bD\xc3\x02\x90TC\x18\xb9\x89'$\xc618\xcc9\x03\xad\xcb\x88\x13\xcc\xbaLD^\xc2\x84\xd5PB\x91\xbfOG\x9a\x96\x14\xebCK\\\xdbai\xb2\xad\x94\xc8y\xad\xc2W\x03\xa5\xd6\x9af\x1fS\x1aX\xc9\xb4\x9b\x1a\x94\x8a\xc4\xda\x05IxT6\xce\x15.\x04N\x1e\xe5\xe4\xdct\x0c\xfe\x186*S\x10\xe6\xf3\xe6\xd5*X\xcdA\x8b\x8c\x05\xc2\x00c\x9ci\xc6KX\xea\xf6\x13\x10u M\xd3\xc8\xca\xb5WHg\\\x18\xb5r\"\x19C\xae\x98\xdbF\xf4\"\x96\xf0`k!\x0e\xb3\xaf\xbe\x02\x07\xb5Y\xb8\xdf\xd2z\xa1t\xfa$\xc1\x9a\xe9\xa2\x96\x01\xcf\xc3\xa88>\xf3\x97K\x92\x1f\xa0N\xd6\x87\xaa\x8d\xf3I\x9d\xf9\xf6\x8f?\xd8]L\xcf\xcbi\x11\x8f\xed\xad\xefW w\xabT\x8aj\x88\xc67f\xd8\x0b\x9e=\xea\xab\xaf\xc0m\xf4A\xd1\x83\xddZ\xaa+`\xef \x07\xb0\x1e}tY8h\xb2Y\xcfI\xfe\x9a\xeb\xc7F\xae\xaf\x88\x93\xeb{q\xc90\xdd\x1d}\x9c|\xedU\x12\x86_\xa28~E\x02\x12m\x91;\x91\xd5\xdc\xb7\xce\xc5Ps\xea\x9fxw\x99R\x88G\x97\xda\x83Hd\xa2\x02 \x1b\xee\x84\x1cf*3\x9a\xcd\xeeJ\xab\xed\xe4F\xad|\xd4#q\xa8\x07,%\xf5h\xc4Q=\xd9\xac\x91w\xf5\x81\xe5b\x88:\xf7u\xad \x17\xcd\xc6{53lJoP\x18\x86\xd2\xd84\x1b\x8c\x03\xa1\xff\x9d\x893#'\xbfm\xa2\x9c\x84\x8cT\xe1\xae\xf2\xd9\x19L\xf72\xba\x89x\x8b(/J\xb7\xb3\x01\xb1\x90e\xc1?+jZ\xdam\xc7bTe\xd1\xee\xee\xb4\xfe\x86lo<\x99\x18\xf4\x01\xbc\x05\xec\xce+\xc3q\x9fX\xee\x8f|@V\x8e\xb4\x865\x98\xcb#.?sm\xaf\x9e\xd7 Z{\xfe\xa6%\xaa\x0b\x95\xb7\x1e#\xad\xe9M`Mo\xc2\xea\xb3\xe6\n\x0f\x85\x91\xde`\x95\x07cj\x11\xafX\xa5gGB\xdde(\xef\xc0\xa0\x1f\xa5\xebu\x9a\xd8\xbcs\x81^\xd9\xce\x8fE\x9a\xb0\xcc\xe7O\xd2|m*)\x9b\xbb\xcc\x98\xfc=\x0b\xaaQ\xc2\x9e\n\xc7\n\xc6n\xa8\x01\xcf\xe0\xb0\xc9\xa2\x9c\x9a\x0b\x98\xceM\xf6\xac\xb6\xc1\xc9`\x15Y$Zk6\xd4\xf6#\x83\x95)\xa8\xec3\x85W\x15S\x10\xd8\xea\x06\x06\xbbP\xd0\xf4\x8f\xa2\x9fh\xa4\xf3\xc1{\xf4\x135\xcd$E\xd9\xc8\\hot\x92\x91I\xbbwk\xf3\x93\xa1\xf4X\xc3\xc2\xa3\xc9\x05\x04\x83\x8b\xb65\x8dL\x81\x12R\x97\xe1\xe4\x88\xe1\xafm\x0d\x8ds\x06nSC\xe3\xb8\xb13\xb8\"\xddT&\xa4 \xde\x94!MEC\n-\x93\x12P\x89^\xfd\x81\xef\xea]\xb9H\xf3\xb5\xaf\xed\xe5\x0b8\x04\xf4\x81^!7Rv\x18\x11\xed\x86x \x87\xf0\x82\xbdP\x1a\x10\xf45%\x00\xb47\x8f\xfd\xd2wL5\xf8\x9eS\xe8'\x15t\x94\xd4\xa1\xe5\xea\x97\x9e\xd6\xc3\xae\x19\x0e5\xf8\xaf\xa2\xf3(\x0cD%Y\x17T\x16\xc0\x81t\xab\xc95\xaf\x9f\xe0\x10\xde\xc1Cx\xd7\xe5\xa1\x1cM$\xe7+8\xc4\xc0GW\xd4\xa2\xe8\x12\xf0\x91[Vy{\x95_y\x0c\x87\xb0n~e\xe0\xfb\xcf,\x12Y\xbd\xb1\x80\xf9\xcd\x02\xe6 \x1c\xc2\xdeT\xab)h0z\xcc\xe9\xfeY\x8dOl=:\xec\xe03:v\xda\xc1gM\xbew\x8c\xfd\xe1\xb7\x84(\x87\x86\xe37\xf5\xf7\x04h\xe3koh\x9bo\xea\xf0e\xda\x03\xec\xf5~\x1b\x8e\xf5\xed\xb7\xfa[U\x1b\xe3f\xccB\xd9\x15G\xb1\x02FWL\xd6z\xa4\xe8\xf3\xf6\xb3\xdc\xfbH\x17&\xa8\xb0\x99\xd9\xba$4\xdf\x8c\x12\xa7\xe5\xde }\xe9\ns\xf8\x0fq&\xba\nC\xffSx\xd82#\xd2\x06\xa1\xa2\x070\xeb=T\xf6\xa6=\xb9\xf8au\xc6\x00VF]\xddC\xabT\x0dA\x1ac\xbe\x10\xdaS\xf5\xd9\xa7\xea\xaf\xf3?\xff\xef\xefN\xc3\x8f\xee*f\xb39Y\x9a:\xe9cx9\x86_Q\x0fu\xe2\xc0\x0d\xf8\x15n\x80\xf3\xd6\x19\xc3w\x18\xc2\xb7\xf3\xac\xb5z\x92\xa7\xd9\x84\x9fg\xca)p\xffJ\x1b\x1d\x833\xd2o\xb5\x1d\xa7 $YN\x02\xbfT\xad\xcf\xfbq}\x96\xd6\xdb\xbf\xf1\x16\xc6\x846\xfe\xfep\xab\x15i\x9c\xe4\\g\xdcb\xdbq\xba\xc6\xb0\xa4}~%\x94\xe3\xaf\xae4G\xfa\xb1\x89\x9dgnW\x14o&\x14\x83\x0c\xeeR\xe7\xff\xb0H\xa9~\xfe\xb3\x1f\xeb\xcb\xb0\xc8g\xa8N\xa0\xbf\xa63\xf2X\xcc\xc8\xe3\xff\xf8\x19\xb9\xc2\x1a+;8wV\xdb\xa9\xe1\xe2\xa9!\xca\xe7Zz\xcc\xeb\x9f\xc8\xbei\xc2\x8a\xbd3\xd4\x0b\xc3\x1f\x7f\xc0\xde\x13\xb3$\xab\xed\x87\xca\xf9\x85\xb2+\xea\xb5\x14\xbdw\xbe\x89\xbe\xfdn\xebG1\xa6\xe2@V\xb4\xf8\xe6f\xf4-=\xe6\xe0\x06\xbc\xb1\x88\x8eo^\xc2|\xaa\xc1\x8f\xda7\x8f\x07\xf5\x8eU\xc9\xcd\xde\x8fZ3\xd5\xe0\x94~\xfb0s&\xd82\xbbi\xe3*A6i\x8d9\xfbM9\x98\xd7t,{\xcf\xb5'Z+\xcb\x13\xc6\xdc\xce\x0cY\xed*)\x07\xcb\xebP\x94\x8a\xcc\xd3\xa3\xad$o\xd0uX\xebM\xb8N\xf3'5\x84`\xabf\xf0T\x0d\xd4\xd8Z\xf2\xedVK\x9d\x8c\xd5\xa2\x14\x0f&\xd0p\xb9m\x83\xcfXx\xbd%\xef\xbb\xabV\x84\xd0\xc5+fB\xccc\x7f\xea\x1a\x12\xf5\\^(\x11\x087\xc3\x0b\x0d\xc5:\xd2-\xab\xf5\xba\xd5\x0e\x96\xdd\xba\x88\x06\xa4\xe0\x0e\xd9\x9a\xacVvZ\x1f{\x8d\x8f\x98\xb3\x8e\xd6A\xb3*\xa2\xf6\x8d<\x89\xa5\x84H\xefX\x01G\x816M\x1d\x8en\x9a\x84K\xda\xac\xa9\xc9\xa9\xec\xe0\xc7\xa4,\xa3d\xf9$\xcd\xdd\xa0'g4\x183\xcdD\xd4>k3\xf8\x89\xb96PY\xf5'\xe4U\xd4\xaf %\xa7~\xf6\xae\xca\x89\xf9\xfa\x97R T\xaeT\x81\xca\x95*P\xb9R\x05*W\xaa`\x98+U\xe0\x16\x8d\x8e\x06jO\xe2\xe0\xe3\xfb?-l\xfd\x9f\xbe\x04\x98\x0b@\xfb\x00\xf38\n\xde}j\x87\x17k?$R[?4goevS\xc30\xcb\xe0\x1aU\xferma\xe2m\xfd8\xe2\x85\x1e\xfcu\xe1\x9e\xa4c\xf0\x91\x02UO\xbe'\x8b4'\xfcp\x12\x00\xa8\xb7\xe3\xb3\xe4\xa5 \x7f\xca|::7\xdd\xd1\x18\x12\x8f\xf0?4\xc7\x82\x18\xb4\xf6\x04\xce\xf0\xf4\xd5\x9c\xa3kn\xe1\xe8\xfb\xec\x02\x12*\x837\xda\xcb<\x0d7\xc1\xb0\xb8\xfe\xca\xdb\x8f\x8d\\\x92r\x80\x7f\x94\x19\xc9O\x04 \xae^\xf5\x1a\xeb\xf8\xdb?i,\xbf)\xf6y\xce\xa2\xabme\x93y\x99\x00G)\x10\xe1G\xfc\xd8f\xa9\xa6\xae\xdb\xb1\x8d\x19X\xee\xab\xb2\xc6H+\xa0I\xd3\xc9\xf8\xaat2\x1bU:\x99B\x95N&\xe6\x0f\xe4\x15\xd0Z\xb9c\xaeY\xc6\x98\xfeG\x84\x1e\xfa/\x0f\x1e<\x90 \xe9\"M\xcac\xa6\xcfv\xa2\xd2\x8f\xa3\xa0\x1b\xa2\xd3\xfa34\xd2'\x03\xe3\x00m\x1a!)\x83\xd6\xab\xbb\xa4\xf6\x93\xee\x94\x1fc\xc72\x03\xaf\x18\x02#\xff\xdb\xe9\xd1\x8e\xa5\x9b\xc0L\xb9`\x00\xf5\x82\x81\xfeEP\xb1\x08\xc62@\xc0\x19\x04:\xac\xb6\x17\xd1\xc8u\xc4\xd6V\xf9\x05C#\x94\x06\x9ae\xe1wVyC\x87\xd0\xf2\xfe\xeb\xe39\x01\xf46&C>\x06\x90\xb7yz\xaaI\xca\x00\x9c>\xff\xc0\xcb\xa9\xea\xe3\xe4\x8dI\x06@\xde\x85\xdd\x86;$\xd3\xc0\xd0.M\xf2\xf4l\xd7^\xed\xd2\\\x90\xc6\xfa\x05\xb8l\x92\x02\xd8\xb1\xddV6\x82\x8f\xdf<\xf3\x1a\x1a\x90\x05\xa1\xf4HR\xe6\x17\xb2\x12\xb9&\xdd\xb1\xf0\x01\xee\xc8?d\x0c\x07\x06\xbf%\x10\xee\xbb'\xfb\x9ax\x10q\xa1\x0b\xef\xc9\xd4\xa2\xda\xcf\x9e$\x1f\x83\x1b\x8d\xaa<\x81\xeaL\xd5\xe2\x12N\xbc\x91\xd7\xf1\x19\x7f;\x12N\xb4\x1dOr\xee=\x02\xb3\xc6S\xa3G\x89\xb86\xb2\xa6Z\x0e\xec\xfa\xee\x9a\xd8W\x8b\xbd\x0c\xe2HJ\xb5`\x97\xf0\x0f\x10\xd7P|\x06\xd6lz \x13\x94\xb8vl:\x92(\xa3?]o|^Fb\xa39H\x13\x9b\xf6)\x97\x80\xb6CGx\xcb\x991\x95\xbe\x83\xa6D\x83\x97\xa0\x80\xe5\xdcb\xa6\x1f\x94F\xfdX\xc3t\x93CHS\xbd\x83\x94c\xeb\x88?x\xcbP\x82\xba)\n\x85x\xf7\xba\x89B\x9fT\x83\x19\xc8\x04\x1e* \xb9\x81\x10xP\xdc\xf93\xa8/\x1b\xfc\xbeDK\xd9g\xf9m#5m$\x90k\xaa/\x19\"m0I\x83\x84Q\x99\xe6F\x0d#SF\x92<\xb7P\\2md\xec_\xa4\x9b\xd2\x02\xbf\xb3p\xb9#\xcc \x884\xdcH\x18\xe55\xf8\xf3\xd5\x07\x84\xcaL\x04\x82gv\x8a\x8c\x04\xe6\xe1\x84W9\x9c+\xeb<\xf3\x0b\x93#\xc8h\xa7tj\xb6\xfc\xfc\xa2\xcdL\xeb\x93\xa7C+\xcc\x19gA>\x05\x0c?u\xc7;\x9e\x95\xa5\xe1h\x14\xec}\xd9<\xa2\x94V\xea\x9d\xf6jo\x9f\xaa\x8f\x9f\xf7c,Mgh\x86\xe9\x90\xf4\xa7\x87\xd031\x7f\x1fVg\xaf\xe9+\xcd\x99\x0fx\x08+\xb7\x03\xc5\x1c\xc3\x1a\xae_\x02\x16Co\xc4\xcd\xcc/W\xf8\xbe\xb2\x1f\xc5\xda\x8f\xe3F-F\xbf\x84\xee\xeb\x0d\x7fW\xf5gt\xce\xebFw\xff\xb3UT\x92\xe3\xcc\x0f\x98k;\x99\xe0\n\xabw\x95U\x15Gi\xaa\x01>\xb05)\n\x7fI\xb4\x07\x8b\x16]\x8cC\xc2\x8a\xa0\x93\x90\x04)3\x91;3p\xb0\x12\x8aah\xc1&/\xd0\xdc\x94\xa5QR*\xb9\x1f\xd9\xd8\xb0\xb6\xb5\x8e\xe6i\xaa(W\x07\x7f\xe2\xcd\xa3$t\x19:\xe4R\xbb\xb6\xf3\xe3f\x9dA\x99\x02\x1d\n\xc5\x96\xbc\xd6U\x88\x1fm\xb24\xd4\x04\xb6\x13m\x91C\xe5\xbc\x8c\x8f\x92ZtwJ\x8e%h\x9fEE\xe9E\x05\xfd\x8f\xdb\xd9\x0c\xf6\x9bI\xb2\x97\xb8\x9f\xb0\xc7v\xd5%>\xc4\xd2\x804\xc8!\xfa\xe3&\xe8\xe5\x91c\xcc\xa4\xdd\xa7\xd3\xa4Z\xc6\xd6\xe7v\xde\x19\x9f\x90\x90Z\x13I\x0c\x0fB\xc4\xfd\xc8$\xcd~3\xff\x99 \xd5\x95\xd2\xa86\xd6Z\xd1\xab\xf6+\x06\xda%\xd3\xd6\xad\x94\xda:\x17\xd3k9\xce\x88W\xa4t\xc0\xb1\xb1\x1d \x11\xfcd\xff\xadW\xa6o\xe8va\xf5\x8a\xe0\x06\x10\xaf\x88\xa3\x80\xb8\xd3N\xc7\x04-\x81^\x1d10\xa7\xccm\xf2\xa4-\xa51\xfb\xc2\x17\xbd.\xbf,\xf5\xbaA\x95\xbb\xefO\xa3\xe1\xfd\xe2\xa0jQ\x01\xe9\x12>\x87\xe2\x13u\x12O\xdc\n\xd7\xd0\x93\xb0\xca\x92\xf58\n\x9f\xa7\x9bD\x16Td\xab$\xaf\x95\xe3\xcdl\x1fE\x95\xce\xa837\n\xf0*?R\x7f\xb2\xda\xf3!;J>`\xea/\xd2\x1bT\xfbN\x9d\xe6\xa9s\xbf*\x9d\xcf+)0\x9dH\x13G\xa4\xc3\xbf\xc4\xf8?\x81\xb9\xa39\x04\x93\xb5\xa3\xe2\"M\xa6\x0e\xec\xaeV%\xddv\xb3\xda\x89\x89\x82^\xc8&\x8edR^dD\xb0\xb7\xc8f\xba ?\xfe\xa5\x9f\xd1\xe9\x11\x0b4\xd6\xec\xd4\x03s\xcd\xf4\x9c\xf5J\xab\xf7\xd5\xc4\x85\xa9\x06SZp6\xe22\xe9fR\xe6C`\xa5\x953\xe8\xdb\xf8\xa05\x81\x9bR\x8fm\x80\xaeE}\xc7\xda\xe9z\xa5\xdbB\xcf\x98I\x12@\x8fzU\xa9\xf9\x08\x93^~\x93\xe6\x16cI\xb5co\x91\xa7\xeb\x1f\x8fG\xee\x89C\x0f\xb5(@.\xff\xe6\xafE\x9a8o\x1b\x9c\xe3\xf8\xday:\xd3\x1e\xbd\x10!\x06\xcf\xa2\xe4\x9d&5\xfcug\x10\x13\xf7\xb6* \xfdg\xc9\x18^\x05?\x98H\xf9\xc1\xa8\xe2\x07\x93\x11\xe3|\xf6\xbf\x86\x0d|\x03\xc9\xd7\xb0\xa1\xfc`t\xb2i\xf3\x83\x1b ?(\xf8\xcd\x0f\xc5\x08F#M\x12i\xcc\xb2\xf8\xda_\xa2\x05\x17u1\xa7\x8d\x1bLx\xa5\xccn\xa1X,\xb8B\xe6\xad\xd9\xb2\xc5i\xaf3:5\x98\xb1\x96\xc7\x003\xfd)\xf2F\xb7\x87\xa8\xe6G\xe87^d\xd7\xb9\x87\x9f\x80c\x1a\x14\xadf\xed\xf4\x91\x0fq\xfaH\x07\xa4\xcad eK\x7f\xb9$aE\xb8\x0b]\xc6G\xcc\\lv 11\x0f\xf6\x8aB;\xee*\xdd\x92|\x1b\x913S\x8d\xc1\x17\x1c\xceA\xa1p\xb0\xf56\xad\xad\xb7U(\x9d6\xaa\x1e\xf8$\x9f4z\xe8/\x0bg\x0c\xa5\xc1Y\x98y\xcf\x08\xa7\x92\x08\x1dI\x8c\xb6\xe2\x9dye\xa86M\xd5OT\xc2*_\xb8\x84\x9f\x05\xec\xe4\xb6\x00\xf5(sF\x1d\xe8\x9cl\xd4\xee\n\x00=;F\xf7jbPL\xd9\x95\xe6\"\xe9}\xd3\x85\xef\xaa3A\xa7\x87\x1b\x0e\xf3\xa2S\xcd\x89o\x9a\x90\xda\xef\xc1\xe0\x93j\xf4}\x00\xd6\xc3t\x00\xab\x0f-\x0bN\x992\x86PG\x06\xc4U\xa7\xeb7\xc32b\xb36d\xb0\x15\x17\xf33\x8b, \xe9N1$G\x05\xce\xde%\x0d/\xad\xc6\x06\x1e\xc3\xc6\xd29}g_\x0b\x10\x1b\xcc\xa2\xa7\xc6\xf8[q\x898\\C\nSzE\xe1\x0c\xd2*\x19\x93\xc5\x0bt\x8b%Z/\x9c&\xe4\x8b\xec\xa9\x19u\x9b\xc0/s\xb2\x88\xce\xb1\xb0]\xbd\x0c\xc6\xb7W9Y\xcc\xc0\xf9K\xf5\x12\x8e\xc6\xa2\xd9\x8a\xde0\xda\xa1'\x1a\xb6\xfe\xdbR\xb0&\x08&\xca\x8f\xfeM\xe0\x1bVUDM1o5\x0c\xfa?\xa5u\x9cv\x01L*\x0b!J01\xc9\x1eHm&\xad;\x03\xe5[\x83SI_\xa4\xb3\x12D\xa4\x04\xc7Z\xe4\x10\xd2\xc6\xae^\xc9\xcd\xfa1\x1a\xbe?i$.H\xbcS\xfe\x077VQ!\xb0=\xaf\xff%\xf9\xc4\xe5\xf9}\xde\xea\xc7\xe5S\xf964\xb1\xa8\xed\xed*'\x91\xcc\xc3\x98\x8fb\xe4\x9e$\xc8\xdc\xc0\x1e{[V\xe4\xbf=\xab\xd7\x8a\x81\xd7\x1d8I#\xd7\x83\x89Y\xc7\xa1\x9b\x98tJ\xcev\xe2\x9fc\x8fnE\xdd\x99\xc3(\xa5\xe6\x0c1\x9a\x99\x81\x87J\xffB\xa2\xe5\xaa\x9cAN\xb9\x9dy\x1a\xb3,\xa4I\x9a\xaf}m\xfc\x9ez\xec\xb2\xe4\x00j\xf0\x96wl\x9c\x06\xef\xaad\x04\x94e\x1b\xee\x05l%z\x08\x9f\x0b;\xe9\x83\xce\xca$\xf6\xe7$\xc6\xf3HQ#|\x0cI\xdbT\xbc\xb3/\x03(\xdbW'\x1f\xb4\xb0=\xd8\x1c\x1b\xff\x05\xd7B\xcb\xf84Y\xa4o\xf2\x18\x8f'\xfa\xfb{\xbf /\xfdr\xa5Q8JS+\xa4\xaa\xd4\n\x91*\xb5\x82\xafJ\xad\xb0Q\xa5V(T\xa9\x15\xe2Vj\x05\xb4C\xb7\x01\xea\xdc\x0b\xdcR=\xdd\xbf\x16\xa9\x17zsn\xc5\x11h\xdc(\xbeD%5\xe1\x86\x9eY\xab\xb4\xd0\xe8x\xd8\xa95\xe7\x8b\xb5\xd3q3(\x16\x84\xb64\xd9\xe4jR\xe4\x9c\x00E\x1dx\xf3\xea\x19\x96\xc1-\xd1g\xc1\x81\xb7\xbb$\x80\xd11\xb6vn\xd1\x06\x0c\x85O\x8c\xa5\xd0\x9b\x05\xb8\x12l\x053\xc6\xc2\x00\xac\x85\x81\x98\x0b\x15\xf6\x86~i\x90\x89\x93\x01\x1aM\x00h:\x9e\xf3\x94\x9c\x7f\xfc\x01N\xb9\"\x10\x92-\x89\xe9\xc9c\x905\xd3\xfa\x0b\x14\x93-\x14|\x1c\x9a\xac\xfd\xc8\x08\xefc\xf2<\x87\xb2p\x16\xf1\x1fV\x8cL\xaa\x15/mX\x1e\xa3\x86\x8aq\x94.\x96\xf5*\xfc$*\xa3\x7f\x937y\x99%r\x90\xfb\xbb\x9d8\xc5\x14\x9e\x945\xd4\xb1\xf3L\xb5\xb9\xc9c\x1d\x10\xb3\xd3\x08\xee\xc4\xe4\xe5^\xa2\x0c\xa9\x83bR[S\xca\xd3A\xc7\xcc\xea\x83L\xee\x15x\xcdc\xee\x98\xbc\xcaV\xa8\xa6\xe1\xb1\x8e\x86\xd3\xdeh\xf99\xe4\x984\x829c\x085\x06\xbc\x9a\x19\xd4\x9cZ\xcd9\xd4\xba\x91\xb6\xcfA\x85\xa3\x8d\xfa\xa4\xb8\x949\xb9y8\xb0\xda\xfe\xd7\xedp(T\x87C\xa1:\x1c\n\xd5\xe1P\xa8\x0e\x87\x82\x1d\x0e2\x92_||\x92\xaf\xd7\xa0\x7f!\xf9\xe2\xb2%\xf9\xc2/v\x97 Z\xc6\x1cXo\xa1\xf8Zn\xa1\xeb\xc1_\xf5\xf7\xd6\x17v\xea\xcf\xb2\xb7v\xd6/4u\x0b\x8b4Ugp\xfa\x8f;\xf7\xae\xc7\xa6\x157\xffDB\xd1\x97\x94B\xda\x94BO0\x9f9K\xff`4\xe5\x03\x9fO\x1ed\xd7\xc8 $\x17\x06\"i\\\xf4&\x0b\xfd\x92\xb0\x86e\xc6\xdbO\x9e{\xe8\xd2d\xf2\x03K\x9d\x83\x82\xae\xa5\x96\xfdG\xa9\xd6\x90B\xe9\x8e\x13\xa7~\x18%K\x96\xd5\xb8\xf4\xf8\x9f\xc7\xa5_n\xb4B\"\xc5[g\xe1G1 \x07\xbf\x8bn\x85^\xb0\xc9s\x92\x94\x1cC\x0c\xd2\xeb\xef\xef\xb5\x82(\xba\xde\xb9\x1b\x0f\x0b\xea\xd1\x9e\xe5$tF\xdc\xdb\xb0y\xff/\xbe\xefk\xb3\xa07%W\xfa/\x8e\x0dmw{S\xfe\xbb\xaa\x1a\x7f5\x07$\x8e\x1f\xebU\xfaQ\xb2CN\xfa|XK rf\xaa'|\x9d\xce\xa3\x98\xcc`z0\xb4/N\x94d\x1b\xfbTCut$\x9f\x05\xfe\xba\xf2\xe5,\xf6\x03\xb2J\xe3\x90\xe43p\x18\xea\xc0\xfc\x02J\x7f\xa9y\xab\xbc\xc8\xd0\xbeE\xceu\xdf\xee%*j\x12M\xf5k\xd5\xc1_c\x8aS\xe6\x1b\xe2T\xd8\xe28\xa0U<\x84U\x81qs\x14\x94\xdcn\xf6\x81\x13x_O^*S\xf1R\x99\x8a\x97\xcaT\xbcT\xa6\xe2\xa5\xb2a%\xc53\xca\x15\xb4\xeeb`L\xa6\x89\x9cY\xe0\xc7\xa6\xfbR.,\xfb\xf8\\X\x08\x87\xf0\x84\xb7\xef!\xebAwO\xbb\xcf\xfa@\x1a\xe8\x84\xd7v\xf0\xa4yYse\xc0{\xa7\xe6\x96\xec8%\x11iK\xfb\xa4Wmn\x19|\xc4B\xa3K\xbf$\xd2\n\xae\xe2\x8a\x8a\xa30*\xbfO\xcfg\xb075\x12\x0bGI\xe4#\xc3.\x86+a\x80`P\x02F\x18\xc0\x13\x81H\x95\xc3\xd8?\xacq]4\xa7\xbef\x96\xac\xcdc\xaa\xd3dx\xb6E\x90\x8cD\x9boB;\x14U\xa2\xb7\xa1#\xf8d\xfel\x8c\xcf\x14\xe7\xde\xa34)6k]\xfeD\xa8\x9c\xd62?\xf7\xd7z@\xe6\xb5\x16\x15\xbcf\xb6\x1e8\x1a\xc2\x1eC\xe5\xb7\x96\xf9\xe5\xea\xb9E\x9a\x8e\xcd\x003\x0ep\n\xbfq\x9d\xefYE\x1c\x0dk\n\x9c\x82o\\\xe759/\xbf\xcb\x89o\x02\xcf\x18\xf8*Z\xae\xe2h\xb9*\x1f\xa5\xa1\xd1\x81,d\xef4R\xf0\x99\xde@\xef\xed\x08\x8bg\xe2Z\x91\x92\xe4\xbfD8[\xfe\xf7\x17OC\x92\x94Qy\xe1\xfa\xdc\xe7<\x1fyu\xd9\x94\xc2\x19s\xd3\xf7\xb3\xa8(Gn\xf7\xc8\xea^[,\xa7\xd9\xe8\x1c\xdb*\xae\xcf?\x9a\x93\xdf6\xa4(\x1f\xd9\xf7~\xddBb\xfai\xc4\xccN*Wq[\xf8,\xc8\xde\x98\xd5\x8c\x0c%\n\xd5\x03}\xfbK\xd1>\x12~=\xec\x05\x1c\xc2\x92\x89\xc7z\xc09\x02V\x07\x85\xd1[\xed\xca\xaa6\xcf\xd3\xf0b\x82X`\xf0zpB\xbf\xf4\x19\xe4\x04c6f\x907#8\xec\xdf\x8e\x92\xfa\xdd(\xd1\xd5\xfc\x1a\xc3\x9c.k\xaa\xa9\xae\xb9\xd8m\xb0\xa7\xa7\xc8\xf0\xc3\x0dpW\x0d\xeb\xa3\x03Q\xb2\xf5\xe3\x88e\x070\x0d\x8a\x93\xdf\x0b\x03\xadk\x8b\x0e+? c\xf2\x82\xdfT\x8f\x9d\xee\xbc\x0b:z\xd5\xc8\x8d\xce@\xaa\x91\x13\xab\n\xa3bp\x9a\x1ej\xca\xae\xee\x8e\x86\x13\x96\x91U_P[\x87\x11\x97i\x9b\x84Q\xa9mX\xd5h1\xa0\xc19\xa6\xa0(\x13\x08\xfc$ 1H\xd6\x86u\x04D%\xb50*\xd5PF\xeck\xa4\xa9(\xd3\xe52&O\x05\x99\xd1\xef\xbc\x87\xe0<\xc2\x1ebG\xe8+u\xd5\x02\xcd\xd2\xb3\x0c\x0e\xa6\xf9X\x95\xeb\xf8 \xd6q\xd8i\xbe\xdb\xf1N\xceKq\x8c\x89L\xb4\xc0\xca\x92\xa9?`\xf4U\xe3\xf8\xbf\xd5Oo;\xf1\xad\x89\xeb\xa9(\x81\xc1\xf9Z\x81\x9d\xad\xe4\xcb\x9a}\xa9L\xea\xd4\xbb\xab\xf0.k\xc7\x9c\xd4\x87\xd1\xaay\\\xf6D\x1eq|\n\xdf8m\x02\xe0\xf6\x04\xe0\xf8\xba\xef\xfd\xfe\xbe+\xbfW\xf3\x17\xca\x1f<\xaaz\x10V\xcf\xdf\xb7\x95\x03\xdb\xa6x\xda\xe5\x97\x9b\x98y\x05\x89\xd9\xfdY\xcdLDU\xde\x10T/\xa5B\xbd\xa4\xd0\x1cQ6\xf9\xe6\xf9:\xbe\x19y%)J*\xceJ\xe1(\x83\x8c\xcbf\x02D\xab\x08<\x84\x84\xc7\x80\xd0\x9e\x9e\x9e\xafYu\xb0\xe6M\x99\xe7P\xb4\x00\x97w~\xef\xf0\x10\n\x9db=\x86C\xd8C\x8e\x0f\x93\x17\xfe\xfe\x9e\x8e\xb2\x903M\xc4+HyLY5W'\x1c\xe1fW\xd4\xb0\x1e\x8d\x9b9\xf1\xf5\x9eH\xc5?\xd7\xb1V\xa1\xd7P\x06(\x12\x9cK\x94u@\xe2\x82\xe0\xdc\xb6\x92\xf3\x17x\x0c\xb8\x0e\xce\xb1\xaa[\xfa.i\xbb\x83L\x88\xacEMc\xda\xcf\xb5)\x0d\x17\xf8\xd97\xad7\x14\xd1I\xafXvK\xb7\xe3R\xae$J\xbcE\xe2E\xc9\x82\xe4\xc7X\xe2\x7f\xe4\xe6<\xdaF\x9dg\x8d\xbe\xb7\xa0h|\x8c=\x16/\xa6\xa8\xefT\xcc\x07+\xb0\xf0K\x1e\x95\xe4E\x12_H\xf3]*\xe6EL{kf\x14\n3\xa1\xf7Lj\x19B=~\n\xf4\xcf\xb5\xa44\x99q\xaf\xf0}\xa2\x90\x90\x0d\x8bOw\xd1i]bc\x0c\xa9|\xdc\xa7C\x06\xee\x92N\xed\x0e\xf8\xe3\x0f\x08G\x0c^\xfa\xf96\x03>\x14\xedl\xe8p\xde%\x98\x89\x82`\xa6\x1d\n\xac\x82\xa3\x84=\xa7Bl\xcb\xe0\xea\x95y\xb4vYA6\xbd!\xb6\xb1\x85\x95ek9\x99\xe8\xc7\xba(\xb0\xb3\xc3J\xea\x8eUh\xa8\xa6k\x0c3+\xd9\xf8;v\x8aURc\xbe\x14^\xc2\xfc\xa8\x0c\xc9\xef\xe5\x96\x8e\xeb\xe9J\x7f\xdd+\x10\xd0\x1f\x0f\xee\xdf\x1a\xfd9\x8a\x10\xfc\xf9\x1c\xc2\x189|\x92\x06\x9bK\x96 \xe2$\x88\x15\x94\xa1\x1cB\x98\x068\x0e\x8f\x9c\x93\xe0Q\xba^\xfbI\xe8:A\x9a]\x98Sd\xc9\xa8\xd4\x07\xf3\xcc\xf0\xb8\x12R\xcd\xb4\x95\x9ck\x88\xeb9%W\xe0\xfd\xae\x0e\xce\xac\x8bK:\x8fX\xee&\xd3\x17\xd5T\xb2]\xbf'\xa3\xd2dQ\xaa\xb3\xcb+\xdb)\xc9y\xe9\xe7D](\x11P\x14CTj)\xbb\xf0\x8ezrs\xe2\x87\x8c7b\xb6q5dk$tZ\xd4\xa0V\x89A[\xc52/\x91\x0bT\xb0E\xf2)\xfd\xa0\xe6\xf7\xebP0\xa7\x7f(m\xe8\xa14\x95\x9dJ\xf4\xc9\xf4\xbe\xecX\xa2O\x1eLUqlj\n$\xbc\xd1N$\xa5\x08(\xe3&\xab?U\xd9|\\gE\xfc\x90\xe4EW$\xa5\xe2h\xe9e\x9bb\xe52T\xc3\x84\x9d\xec\xef\xc9?\x9d\xb1x\x9d\xe5\xd1\xc5\x18N\xfe\xf8o\xce\xdf\xb0zf\x9d\xa1\x08n\xc0\xdf\x9c\xbf\x8dx|\xf4\x06M\x12*V\x93\x9e\xaa{\xfbrTC\xb1Wa@\x0e$9C\xc5U\xe6\x17\x8a\x8dP94.\xc6h{\xea\x9c\x1b\xdd)\xf2HR\xe6\x11)\xa8\x90\x04{.\x16\xba\xa1\xc7i\xe6%\xe4\xbctG#/L\x132\xfa\x9a\x8f\xc2d\x8e\xc4L`6\xd6\x91\x15\xefZ\xe3\xc8\x0d\xc7p`R\xcfS\x9e\xedd\xdfP\xa1b\x8dPS\x89#\xa6\xb8(\x12\xad\x1b\xab\xff\x038\xdd\xd5\xde\xc2\x0dpf\x98?m\xcdW[N\x0b\xfa\x84\x00\x02\xbf\x0cV\xa0>Yc\x86\x11\xb8\xc2}{\xc1{XD\x89\x1f\xc7\xaa\x15V\xaf=\xbd\x98\x12%\xf3\xf8\xa1\xd5\xf8\xed*\x06`h\x0e\xf8\xd6\x89GP\xae\xf2\xf4\x8c\xbb\x07u/\xc9<\xfc\x97\xfa/\xfaA\x8e\x8a\xf34\xbc\x90\xa5\xd6\xa1 \xcez\x13\x97Q\xe6\xe7\xe5\xcdE\x9a\xaf'\xa1_\xfa\xcc\xd1\nG\xe6\xbc|q\xfc\x9a\xfd\xdd\xdd\xbb\x1aNa\xa9\xd9\x8f\xc0-|:\xa7\x8e\xb9f_\x82q}\xaa\xfdy:\xc6\x8c\x1c\xf2\xfd\xc9&\x057\xe7\xc51\xf9\x8d\xefN\xdas\xf7\x14\x0e\xe1\xac\xbb;\x97\xc6\xdd |\xf4G\xfd\x8dw\xca7\xacq\xfb\x01\xcf\xf5qd\xdc\x82\xc0\xb7\xe1\x91v\x1b\x02\x9e\x08|\x0f>q0h>J\x8a\xd2O\x02\x92.j\xae\xdb{\x12\xa1\xb0\xd0\xda\xa0\xe7t\x83\x1e\xfe\xffq\x83z\x89\xbf&\xf4\xef\xaf\xcb\x8b\x8c\x1c\xb2{\xf4'\xdf\xb9(P\xf7\xde5\xeem\x90\xe25X\xedq\x10\x98\xb4?F\x8c\x91\xdb\x05m6\x9f\x1e\x9f\xe8\xb5\x87\xc1\xfcg\x8d=\x7f\xa6\xdf\xf3`\xd94\xf0}x!\xf6\xfe|\xe8\xabe\x0f\x1b\x94\xb7#E\xb5 \x84\x97\x13t\x07uo\xfe\xeb_\xc9\xcd\xe5\x18\x1c\xa7\xab\xd8\xe3\xe3/e\xe5\xac\xdb\x1c\x8d\xcf\xb9\x93[\x8aJz\x9b\x8f'\xc4^7F\xefK\xcc\xca\x97\x98\x95O\x11\xb32 Z%B\x95c\xb0\"k\xab\x9a\xd7\x0dp\xab\xcf\x0b\xf1#29\xd5 c\xa0.K\x1b\xb3\x072\xbeD\xc1/\xa0#\\U_\xb0\x1e\x19\xe2J~\x0dCiZ>\x98\x97\xad\xe3-Q\xde\x148\x01\n\xeb\x1f305\xd6\xff\x9aV\xf0n\xba\xa7\xb1\xd0\x17\x8e\x82H\x9b\xf8\x10\xebr\xdd*p\xcc\xa3\xdb\x1b\xb3x\xfd\xf2c\xff\x00\xca7\xbd\xd2\xad\xea\xbc~_\x91\xf64\xec\xa6\x993;\xae\xd4N+\xbcW\xc3\x95h\xc6\x94\xa3M\x1d\x17o\xc5T\x0e\xf2\x98wF[\x89\xc5\\\xe7[Q\x8c\xdb\xa8\xf6R\x16\x8a\xe1d\x16E\x92\x01u\xfcL\xebdY\xb2\x9b\xf7\xce\xa0Z`\x85\xbd\x95 \xb6%\xbbM[jw\x05\xdf\xf5\x8c\xaf\xf9\xc2\xf7} \xbe\xef\xcfg`\xfa\x14gF\xcd\"\x99\xce\x0d\xcb\xb0\x82|@\x90\x00s\xb1\xa8\xc2\x17\xf91\xac\xd1\x96D\xf8\x02'\xf6\xe6\xd8\xd8\x82\x04\x9b<*/\x1e\xd3}\x1d\x95\xa6Z\xc7t+\xe5\xc6x\xdf\x98A\xf9\x9br\x95\xe6\xd1\xbf\xc9\xf7%\xa5\xb0{\xdd@\xb6\xe6\x15\xb0W\xc4Qx\x05\xf60\x8c\xd4\xe5\xc5&\xff\xf8\x03\xfd\x9d\xae\xc4\xea\xc5\xbax\x890\xda\xcd\xb0\x96\x8a+\x89\xa3m\xce\x86z\"\x02m\xd7\x9a\\\x91>\x84\x94u\\\x9b\xdf\xaa\xb1\xad\xd4\xc6\xae\xcaAX\xb7z<~\xbaJq\xf5\x1f\x9b\xeb\xea\x93zo\xc8\xe3T\x03\xb7ht4P\x1f\xad\xd7\xd9wC\x15Xj\xad6\xd9~\xf8\x80\xd2\x88\xfbP\x89*\xf4\xa1\xc9\x87\n\x1a\xf94\xd2\xe45\xbe\xcchD\xfb\x9e+n\xac\xd3\x90\xc4\x942\x8da\x8f\x07\xaaz\xe4<\xf3\x93\x90\x84#\xa1\xea0\xb8\xc6\n\xf8Y\xff\x13\n\n\xd0\xdf\xc3\xf2\xe9\xdd\x98\xb4&\x18iW\xb5&\x87\x89\x11&\x10S\xc8\xe3\xc8\x94\x1a*S\xb8n=ZE\x9f\xba-\xcd F\x99[\xac\xfeK\xee$\xd8\x86\xeaOI7\x9a\xf7\xc3\xf0^6\x11\xbc\x1f\x8e\x0d[E!9&\xf1\xe2Er\x84\xd3j\xe2\xc5\xf4+\x0d\x15\x1bV\xa1\xb5B\xe7C\xf7D\xd2\x89\x07\xac\xf6F\xdes\x0c\x85!\x1a\x90\x0f\xad\xfd\x11s\x80N\xf0\xf5\x94T\xa3\x19\xb4cw\xd8\xaa\xb6\xf3\xf0 \xb8z\xd4\x82\x98p\x08\x991\x956P\x98|\xaa\xe8\xcd\xfe\xfc\xb2U\xe8b\xae.\xdcl\x88F'\xc1\x0c \xea\xf2\xb6\x0d\xb5\xde*\x8a\xc3\x9c$\x943\xfa(M\xebB\x0d\xcd\x0d\xc9\xc2\xcc\xaasM\xc3Q\xdaxi\x05\x9b\xbc@\xa5[\x96F\x892_\x1c\xf4\xb0\xb7\xba\xcb$\xe7?\xed\xe0v\x1fX\xab\x92\x04%\xaa\x1368\x8c\x8b\x95\xed\x12\x1eP\xe4\xd4\xc7\xa0\"|\x17S\xf6\xcb\xbf Ar\x985a\xbb\x87\xa7\x91J\xf5\x85\x02\x990\xb0h\x1d\xd1\x92\xe8\xb5\xee\xc1\xee\xfc\xeey\xde\xfb\x0e\x89k\xb0C\x1d\xaf\x0f$O\\\xf8i=\x10GO\x9b(v\xdc \xbb\x14\x87~\xbf\x1e\xd2\xf83\xf0\xf9\xbb\x96*\xc11\xfb\xa10\xdc_g\xe5\xe0\xe7!\xc1\xf8A\x19m\xc9k\x7f>\xc8VZ\x99aC\xbf\xf4\x0bR\xa2G\x8e\xfc\xc8\xb6\x92Q\xaa^\xa8\xd5\x12\xbd\xdb\x97\x13JP\x13\x98,\xa2\xa5\x02\x8a\x89%\x86\xc0\xce\x00\x13QW\xb9\x86\x9fS\n\xfc\n\xf9\xaa(Y*E\x18G\xc4\xef#\x8b\x18\xa0k\x1b\x12\xef\xc6\x0d\x97~\xba\x02\xb4HS\xd4\x98\xc1\x98R\xf9\xaa\x8d\x99\xc4\x83\xefc\x0b/W\xc9j7\xb2\xce\xb0-^\xffIg\xafq8\xb5\xe0ly\xef\xc6XG\xee\xc4\xd1\x90\xefG%Y#\x9fY\xd3\x9a\xc3\xc3ff\x9d\xc6\xd9\xf2\x10\x1c\xbe\xb3x^\x96\xc1}\xd3\x07\xadt\xba\x16G\xc9;U\x860\xa8\x92\xd9\xf0$8\x8e9\x9dJ[~\xa8\x86\xa5\x1aDD\xc7{\x14F%`\x8c)\xcb\xbe\xc1\x1a\xe1wX\x154\x8dqd\xd7\xa5\xe0\xe7\xc8\xf5Z\x08\xda\xb3\x88'\xe7i5n\xbbBlTW\xb6>l\xc7\xd6\xb9P\xcc\xb1Y<\x92\xcb\x8c\xe8_}\x05\xe9\x18\x8c\xcb\xa0\xa9\x84\xa65\x071b\xab\xad\x94\xd2.M\xa2\xa1\xf55 \xd5\xa6;h\x1d\x06\xda\xc4'\xa4\xa6\x993\xd0\x14\xb3\x14\x14Y\x97\xef\xb4\xf7\xc0(1~\xdef\xa4\x05\x15\xb1z\x12S\xca\x9f\xf4\xa4\xb2H\xbc\"\x13\xbe\x162\xa9l\xc3\x1f\xf4\xda(\xf8\x83\x9eT\x16K\x0dL(\xfe\xb8qS,W\x1b\x98\x16\x1f_<\xcbl\xc53\xbd\xcfn>\x06\xbf\x7f\x92wy\xdfk\xe3\xb3+\x92\x84ozb\xa2\xc2g7\xed\x8b\x8az\x9f\xdd\xbc6X\x1d\xb6\xb7\x8e\x8aG\xcde\x89\xe3\x01\xabE\xc92\xca\x17\xab\xf4\xcc=a\x94\xb3p\xc6@\xde\xd2o\xf7\xe9\xc0\x989Q\x8c\xbb\xe3\xa5+f\xe9\x0dSH\x85\x1a\xdfN\xa8\xb9\xe6\xbc\xbb\x0dc\x9c6\xf8V\xdd!\x1c\x19B\x9f\x9a\xda\xf8\xe6\x92V\xc7\x05J\xb2Q\xdb\xdb\xb7\x03\xe2E\xc5\xf1*=K\x9aK\xdf\x80\xa6\x1c\xc0[\xccB\xa0?\xa0\xed8\x12\xa6\"\x9d\xa7\xe7J\xdeX\xd5L:\xeejX~o\xa9\xfbu=h\x1e\xb4\xc6\xe3\x93\x84Z\x0f\x8e\x90\x9d\xae\x9ax\xb5ZYY2'P\xf6\xa7\xa9]~l\x97]C\x16\xde\xa7T\xa3\x9f\xf5\x06v<\xabc\xe3\x19\x9d\xe1]\xc3\x19\xed\xea\x1e\x82\xf2\x10\x07\xbe\xad\xd0^\xe2\xf06)g\n%\xc6\x9c\x89^\xcc\xa0c\x84\x16G5\xe7\x02\xfc\xa2\x88\x96h\x931\xeb,\xaa\xe3\x806<\xfd\x1aJ\xf8\xa6w*|\x0d%\xa5\xfcj4\xda\xf2<6\xf5\xa1Pj\x82\xed\xaa&s:\xb4d$\xba]%\xfd\xf6V~\xf1\xe2,\x11l\x0c\xd3\x16b\x04\x02\xeeZr\x92\xd3\x13(9\xc9\xdf\xdaF\xc2B\xe3x\xef\xe3D\x1f\x01S\x1bw\x89\xea\xc4&\xda\xc3\x06\x9aCN\xd8\x81\x9a\xc07PV\xb3\x9b\xe8g\x17\x1a+\\\x9e$\x860\xc6\xdc#\xc9fMr\x7f\x8e\xe7a\xebO,&1\xc6\x9a\x88t\xd3o\x04\xd0\xde\xfe\x18x\xf64\xba$X8\xd1\xcd\xbd\xb3<*+\x88\xd1X\xc1d\x12\xfa\xc1w\xe4B\x1a!\".\xdb\xa0<\xa8\x17\xaa\x9a\xff\x92\x87\x9fh\xa6\xa8\xe27(\xeb\xe66P\x89\xee=^ \x12\xd3B\xe5\xbd\x9c\x84\xe2\xea\xf7\xe5\xbd;\xeao\xb3\xc8\xa8\x8c\xae\xd0\"2\xd5\xb9\xb2\xe2U\x80G>\xee\xb9\xa4\x19\x92Z\x8eD$dB\xce\xe0\xf5EF\x8e\xf2<\xcd]\xe7\x91\x9f$i t\xcf\x80\xcf\x8e\x18\xf0\x0b\xf0\xab\xd6T\x825g\xcbT \xf8\xa014c\x87At\x9a4{\xf9\x8a,HN\x92@t\x956\x08+\xbfH\xfeV\xc2\x9c\x90\x04\xd0\xe5\xd4\x8f\xa3\x82\x840\x81b\x93\x91\xdc\x1d\xb5 \xe8\xb0H\xa8+\xb9\x0f\xf5\xfc\xee\x95h\x97N\x11m\x1d\xd8;\xc4\xcc\x9dt\xf2\x90\xc0V\x13\xd2z\xc2\x98}9\x8e@c\x9e\xdc\xa8\xcd\xba\xf2\xcd\xb1$\xe5K\x81|/\x16nd\xe9\x1e\x0dR\x0c\x1c\x82'\x18\xa5.\x1f\xd2W_\xb1\xc21\xa8\x84V\xa0\xcd1\x9dlz\xe0\xe6\xa4((\xf6\xae7E $*W$\x879a\x1fH\xf3\x06\x1e\x8d\x81\xe2\x99\x037\xaa\x86\x14\xabB\xea\xedX\x9fQ\x8c\x87q\xb1s\xad\xfd\xaaa\x97\xd2\xa4(\xf3\x0d\xe5\xcdL\x96o\xbb\xf8\x8c\x9a2\xea\x8b'\xd0K\xd0\xc2\x996b\x1fX7+\xda*M\xc9'.\x05M\x1cq\x87 \x97\xcfT\xd1\xc2(x\x08\xd2\xfb\x1c7f(\xb9\n\xb4<\x94\x8a)n4\x86\xa62b\x0c)\xbd\xa5-\xd7P\xac\xd2M\x1cV\xef\xbc\xc1l\xa5\x96\x95\x03\xb4\x019\x82\xf5\xc0\xed\xa1\x9d\xd7T\"\xaf\xc2\xb70\xa5s\xd5H\xeeY\xf3 \xd3\xb7\xf0\xb0\xfd\xe7\xacg\x1a\xef^Q+\x01;\xdd\xd7\xaa\x02P\xd0\xa03\xcc\x9f\x81\xa5p}\x910\x1f\x80\x9a$\xbc#\x17\x85\x9b#WNZu(F#\x8flI~Q\xb3\x8b\xdaC\xae\xd1b\xe2E\x05\xf2Ac\xb6y\xb2B\xc9\x0c\x01\xe2\x14\x1e\xfd\xedn\xa2\xb9I\xd1\xcf\x94\x9e\x03\xfd\xeeiW\x12:\xddKO\xa8\x9c\x1c\x9d\x10m\xc7\xe4{\xa0\x8f\xb4\x94S\xef\x18\x06\xbb\xc73\xf1\x9e\xae\xd7\x1b\xdc\xa5\xad$\xc3p\x08\xd1\x18H\x83\x89\x8f4\xbc\x8cNa\x06R\xa5\x19\xb4\x07\xf2\x9e%\x88t\xf7E\xdd\x1d|r\xdd\xb4z\xa14WR\xca\x9f\xdc\xef)\xe9\"\xfe\xa4\xa7\xef\xf3\xf9\x83\x9e\xbeo\xc3\x1f\xf4>U\xf0\x07=}_\xcc\x1f\xf4\xf4}\x81T\xdf\xb7@\xf0\xa0s7\xe3\x1f\xb9\xd7t*\x08\xd5\x8a\xc0\xf0\xe3+\x02\xf5e\x8c\x86(\x02\x15\xc1\xfb=\x97\x0c\xad\"0\x96*\x02\x83J\x11\x18\x8f\xc68\xd7\xfb_\xc3\x02\xbe\x81\xf8kXP\x81%8Y\xb4\x15\x81\x0b;E`a\xab\x08\x8c\xec\x15\x81\x01W\x04.yd\xb2\xff=\xaf\xa9n#\xc7\xf1>\n\xdd_\xcb\xaa\xe0E\xc5\x8b\xef\x8eoa\x01\x87\x93\xdak\xa0p\xc6<\x1e\xc7/\x1cz\xae\x9c8a\x1d1\xe5\xbc\xed\xb5\xf3\x9e\xf7\xeeQ\xc7\x13l@\xff\x1c\xe8\xab\x86\xf0\xb3,\x11\xde\x15h@\x15\x8aN\xce\x8f4\xe7G\xbc\xc0\x93\x1b\xbe\"E\x1aoIx\xbc\x99\x979!\xeeI\xb50\x1d\x85\xaed\x85\\\xbar\xf4\x900\xa5\x17(Z\nU\xdb\xf4\x02\xb1T\xa1\xba\xf9\x04\nU\xbd*\xd5F\xe5\xca\xb2\x1d:\xfaa3<\xcf\xfd\x80\xa0\x8d\x18\xb8#\xb9\xaa=F\xb8,\xa9\x90\x1dE\xb4\xebb\x94$$\x9f\x18z\xa7l\n\x1d&\xad\xdb\xda\x0d\xe1\x9c\x12k' z}\xa4\x99#\xa7\xcc\xb5\x9d\xb1\xcb|\x96\xc6\x98\xf8\xec/w\xef\xde5h\\\x17iR\x1e\xb3o:Q\xe9\xc7Q\xb0C\x9a4\xf5`\xc2\xfa\x90jp\x893GG\x99\x1a/\xa9`^h\xa7(\xdd\xe4\x01\x99\xc1\x91\xbc\xbb\xa3Q\x8d\x80\xe7\x94H\x9f\x8b<\xd0\xe7J\xc3\xb4\x95\x0fw\xc7i\xcf\xa2\x8e\x1b\x0bi2\xd9\xae\xd1=\xe9dj\x80\xa2\xf2\xe4\xa9\x8b\xa7\x8e/\xd8\xf2,'\x81_\xea\x99X\xe0\x02\xe6\nm\xa9^T\xa0I\xf5\x1d~\xe8\x9d\xc7\xad&\x85\x9b\x1b>\x91)\xf3\x1f5\xaf-\xe5\xdc\x03?\xfe.\x8e\x96\xc9\x0c\x9c2\xcd\x0c\xf8I\xaf\x8cr\xff\xc9\xf2\x15\xf7\x9c\xd8\xf7\x0e\xc8\xda\xc03\x1amQ,\x026\xf3(\xfe\xff\x82>\x19p\x08\xce<\x8dC=n\xeaw'\x08\xad\x84&\x0d\x04\xb4I\xca\x86G;Vk\xa5\xde~\xa6=\xa3\xef\x17\xa7\x1c\x99\xee\xfb9\xe7dv'\xcc`K\xa3\xa0A\xa7r\xdd\xb0AIy\x80\x1f<\x7f\xd7s:\xf6sc\xee\xb1\x0c\x81w\xef\xb9\xaa\xcb/\xc7\xddT\x00\x16(\xc7\x03\xbd\xd0V\x99\xc0\x0dp\xf0WN\x7f\x9d\xd2_\xbe\xae'F7\x07!\x0f\x1b-\xf1m\xbf\x00\x83\xd5\xab!\x9b\xf1:\x84\x0d\xcd\x00\x86+\x9a\xdb\xe2\x0e\x02\x81\xa1%\xeeIa\xf0 \xe0Q\xdc\x0b\xb8\xa1\xb3\xa8\x8dd\xd62\xf6\xa46\xa8U\x87\xcc\x99\xf1\xb8\xe7'\xe4\xff\xfc?\xa7\xfdV\xf9\xb1\x0f\xa4\xc4\xea@J\xf9\x81\xa4&\xb2\x18\x8dw>\xe1%b\xbd\"\x8e\x02B{s\xa0,\x08+\xae-/\n\x99\xc2CH\xbd2\xfd\xf1\xb8\xfa\x81S\x9a\xf2 \xb2\x8a\x80\xbc\x0c\x19\x07\xb1\xaf,\x1cU\xac\xc9\x074\x99\xb3{\xf7\xee\xe9i\x07h\xe9\x07\xd8\x1c \x0c\x97\x92K\x92G\x18:\xc6\xc1d\x12l\x86\xda\xf1\xfc\xf3U\xbb\x10\xd4\xbc\xaal\x7f\x1e\xd3\x13\xefX0\x816;\xd5f\xce\x9do\xe0\xef\xf0\xed\xa59]\xc9Q`\"\xd75\xa9\xd6EuZ\xd3\xe9>\x8d\x1e\xaa\x8c\xb5$\xd3\x82D\x1f\xabA\x8c\xe4\x19Is\xb5\xb2\xbf^\xe5z\xa2\x0e\x0c&\xdf\xda\xae\xe8\xaf\x1d\x8am\x88\x197\x91,\x1b\x1f)\xa4W\x9a\xd8\xed+E3\xb0F5\x18\x82n G9T@\xa2\x89\xd2\xdc\x8c\x19\xd5\xa0\x81n\x06\xa7 #\xca\x01(\x92\xad@W\xda\xfc\xe9*\xd1\x11U\xaa\x03\xd0\xf1\xa7/\xe8\xd8\xb8.\x89\x8eL\x9f\xfd\x99\xa3\xe3\xab\xabD\xc7$-\x07 \xa3\x01\xad>\xbf#\x11\x0d\x14Wv\x02\xbe\xba\xec XW\xff\xba\x94 \xa0\xaf\x08\x0e\xe2\xb4\xd0\x94K}\xef\xec\xe0G\x98\x19\xfd\x08\x99\xe1\xee\xba9Pe\xca\xcc\x90\x99\xd4M*\xe2O\xa41\xe4\x99*\x86^z\x971\xa8\xdc\xbc\xac\xdc\xc6\xa0\xf2\xf42\xbbR\x01W\xe1G\x83E\xffd&\xf4\xb7^\x94\x84\xe4\xfc\xc5\xc2\x95\xa4\x12j^\xa6\xd8\xa0%\xcf\xeci\xe1\xfa\x03\xdci\xac\x1c\xe0\xd6\x03\xdcw\xcc&y(p\xe7\xb1\xd2u\xc4\x81h\x02?\x83C\xd8R\xd2~\xb98\x17\xd8\xc5\xbb\x02\xe0\n\"l`wg\x06`\xedo/\x13\xe0d\xd5GK;3\xe8\xe7C\x1b\x9d\x0b\xb5\xeb\x82!\xc4\xaf\xf6L\xf0\xe1\x9bC\xd8\x18\xc8L\xbf\xc2\xd3\x89\xe7yo\xb5#pN\x9c1\xac\x85\xdem\xbd\x9b\xae\x1b:\xfa\xeef\x90\xa9Y\xdf\x0d\xd6:o\xa8\xcc\xb5:\xbd7\x98q\xc1\x18\x97\x05\x95\xe2\xb96\xe2\x98\xfbF\x8f\xd0\x7fX\xaa\xab)\xec\xcf~l\xb4R\nX\xceB\xc9+\x1d\x8aK\x91\xcb\x8a=\xaad\xce\x0c\x1e\xee\x1ej+\x0c\xfb\x1a\x13&m\xa9B\xa9K\xc5\x1b\xb6v\xa3\xa0\xda6C4\x11\x01=\xd4\xfc\x12\xe9\x8c\xc1>\xa51\xb4\xa4\xd8\x80K\xb1V\x078\x0bvN\xb4\x9ex\xd0\x10f\x0d\\\x87\x9dh\x0e\xb5\xe8\xeb\x1bU\x1fcpZ\xf17\xad\xe7\xbd\xbb\x1dy\x14o}\xb6\xb1mr\xc93UI\x9e\x91J\xf2\xf4U\x92\xe7F%y\x16*\xc9S]\xad \xeb\xc5qRy\xd4\xcd\xea0\x9c\xe9\xfe\xe7\"\x80\xde\x9d\xd3\xff]?\x19TR\x14\xa1/\xf4)e\xd0\xf4\x03\xc8\xa0;\xe6\xf8\x87\xeb\"\x83\xdaH\x89\xc9@i5\xddAZ5\xcb\x8a\xfe0Yqc+\xda\x16\x18D\xdb\x0d\x15\xd1{\x03\xb0d\xc4{\xe8\x9f\\E\xa4\x18J\x07\xa0\x06S\x9f\x0d$n\xc4yP\x81\xce\xc2K\x8d\x83/\xd2|\xedk\x95\xb6\xc0\xb7#\x7f\xe1|m\x94\xaa\xb654F\xaa\x1a\xc0\xd7\xd2 \x15\x9f\xfec\xc8\xa7\xb1\x1c\x1c|\x03\\\xa8d\xe1vKR\xd6\x0bG\xf7\xb6\xfeE\x94,\xafL\xf2\xc6\xa9\x19C%\x81\xf3\x95\xb8\x02\x11\x9cw\xf1\xa7\xb4\xdc\xb9\x97\x17\xde\xca/\xcc-\xe9\xe7\xeb\x14\x8fe\x18\x83i.)Y<_\xc7\xe8\xfa\xb7\xfa\x0f\xd9\x13vS\x07;m\x0c\xe3\x84\x83\x81\xf1h\xae\xbd\xf3?\xff\x8f\xfe\xcf\xc1\x14\xe2\xce\x0c\x9c1\x1c\x97y\x94,\xddT\xe7M\xdaL\x94T!\xe8Vw\xe6\x9e\x99&\x83K\xaa[\x03\xa7\xdf\xf2II4=\xbc\x9c\xc2\xcb\\\xfa\xeb:(\xbc\xc6Pz\xe2}I <}\x86\xa7k\x91\xe0I\x14Qj\x8d\xc3&\xd3\x13?\x1e\xfa\xd8\x92T\x8f\x7f\xf6%*\xd9\xb4z\x8c\x87\xc0\x15ef\xe2{\xb2\x97\x0d\xc9*\x05S\xd9\xd9yI3W\x92\x1c\xf9\xa2k\x80|}<\x8be:\xd5\x94?\xe8\xe9T#\xfe\xa0\xa7S\xf5\xf9\x83\x9eNu\xc3\x1f\xf4t\xaa\x05\x7f\xd0B\xf2X\x8d\xe4\xf1\xc7G\xf2\xe0\x8a\xb2\x14\xa5*\x05f\xcf\xbbF\xa6\xc0\xcc\x87+0\x95Y\x8a6R\xc5edR\\~\xb2,Ei\xf2:\xbfH7%\xa6\xdfV\x03'\x1c\xf8\x91\x9f\x04$6\x00\xe7\xcc\xab%\xf1\xe71 \xb5\x01\xfe\x86\xba\xdd\xea\xb3\xb1U\xa8<\xbf\x98\xa4\x1buT\xb7\xb6R\xfb|S\x96\xf6Y\xd1\x9dy\x99\x00o\xef\xf4\x94\xfe\x11\xe0\x84\xd8\x147\x97\x1f\xcb\x94\x0fd\x93\x8aa]\x1f\xaa\x9f6\x1dT\xd4\xfc\x1b\x83\xf3:\xbf\x80\xa8\x84tS\x82\xccdfp\xdd\xd4\x17\xf7\xaeX#V\x12\xaak?i\xe1\xe7\x0c\x9e\xf0\x1d\xd0\xa8\x86\xd6\x01o`\xa8\x19\x9c\xe3\xe8\x0c\xf6jc!&\xc8\xa8\x0f\x95\xebYp\xfc\xcb\xa1\xf2\xe5P\xb9\xbe\x87\xca\xfc\"\xf3\x0bC\x91\x16\xe2E\xc5\xf1\x99\xbf\\\x92\xfc\xc0t\x94\xb0\\?\x1a\x12\x86P~\\\xa4\xc7\xab\xf4L{\xe2\x94\xba\xc3\xa0\x19XP\x8f\xd6\x0bVQ\x1c\xe6$A\xa1\x0e\xcb\xfc\x98?bG\xa6\xb7$/\xa24\x99d\xb9\xbf\\\xfb\xca\x13,\x1d\x7f\x88\xe6NO\xd7\xa4(\xfc%\x01\xc5\xfd\xc9\xc4_\xcf\xa3\xe5&\xdd\xa8\x0b~X\xcd\xa5\x12hu\xab\x0e\x0ey\x83\xb4\x18\xca\x14\x18\xc6\xe2\n@]\xea\x06\x13\xc7\xa8>\x94\x99\xdb\n\xd2\x90\xd4\xad\x15\x0c\xf5X\"V? \xa9\xa4a\xf9j\x9a\x91\xc4\xcf\"\xf6\xea\"\"qXP6 IK\x98\x13\xc8rR\x90\xa4\xc4\x8a\xd4+\x02\x85\xbf&\xc0\xf1\x1c\xd2\x1c^d$\xf9\xee\xe5\xd3\xc6\xb8\xeeY\x8e\xdc9\xdedY\x9a\x97$\x14\x0b*z\xe7\xe7d\xc0\xf8\xf8\xd4\xa0\xf0\xf57\xe7\xc0\xdbw\xfeV\xcdR\xb9J\x0b\x02\xe5\xca/a\xed\x97\xc1j\xc0g\xf9\xb4\xcd\xe0\x96\xb7\xef%l\xf6\xdcE\x9a\x039\xf7\xd7YL\xc6\xbb~k\x1f\xbf5\xf2\x1c\x11\xd3BI\xb0\xc5\x16\xd5\xee\xf3\x0f\xb0\xdf\xae\xdf\xf6^GE\x11%\xcb\xcfgs;\xafWt\x87\xa5\xdb($a\xe3u\x08SR`\xad\xdd\"#A\xb4\xb8\x00\x9f\x1eoQg'X\xef$\xbe#\xa3$\x8c\x02\xbf$\xd5\xd7$\x1b\xb9\xdd\x00|\xd9\x83\x97\x11\x10Z5I\xed\x85\x04q\xf2\xcb<\x0e\xc5\xa6\x96=c|\xca\xe7\xc7\xfd_c\xd5\xe5\xe0\xdc\xf4l\x97\x0c\xd48\xae\xfd8\xae0Q \x96\xe5\xf2\x9cm\x12\x9a\xd9u\xb7\x03\x07\x13\xb6\xe3\x7f\xafY\x92v\x8a\xa0\x8f \xc9\x9eE\xc9\xbb\xcf]\xbd\xdd\x18\x87\x0d\xb2pq]\xa9\xde\x96F/1\xe1\xa0$\xe7\xe50$\xf3\x8d\xb8\x93\xa4\xa8\xe1\x96\x88V\xb5N\x05\x1e\x1a<5\xa11\xd9^\x96\x93-I\xca\xc7\xacG\xae\x84\x92*\xf3\x9b\xae\xb0\xa2[\x89\x15\xddn\xb2\xf4N\x0c\xb4\x8b\xd9&=>\xdbT\xe9g\xa9n\x1f\xe3j\xf7\x1d\x89)\xb6\xb9\xb8+F\xacLk\x0b\xa1s=B\xe7\xed\x19\x94O\x86R\x8a\xe6k\x1b\xd9\xb0RJ UU\xc1\xf3u\x9c\x143pVe\x99\xcdn\xde<;;\xf3\xcenyi\xbe\xbcy\xb0\xbf\xbf\x7f\x13_\x93\xbf\xf4\xcf8J\xdeI\xdf\x9c>x\xf0\xe0&\x16 \x94\xbc\xabM\xf0\x93\xa5\x05rc3p\xfcy\x91\xc6\x1be\xf9{^\x05QQ\xbcF\x94?\xdc\xef\xa3\x7f\x17\x99\xd5\xd3J\x16\x85\xc5\xbc^\xac\xe7i,\x9d\xdamD\xce\xbeO\xcfg\xe0\xec\xc3>\x1c\xd0\xff\x93\x0c\x06\x0bNm\x928\x0d\xdeu\xd3\xd3\xe9z\x97\xb1<\xe0\x12\xa4\x9b\x81\xf3|z\xc7\xbb\x0f\xf7\x7f\x98\xde\xfe\xf9\x8ew\xf7\xd1\xf46\x1cx\xf7\xf6o\xc1\xf4\xc0\xbb{\xf7\x0eLa\xba\x0fS\xb8\xe7\xdd\xbau\x1b\xa6p\x97?\xbd\x0bw\xbc\xbb?\xdf]\x1dl'\xde\xfd\xfd\xe9\xa3\xfbp\xcb\xbbw\xe76\xdc\xf7\xee=\xb8\x07\xb7\xe8K\xb7\x82\xa9w\xb0\x7f\x8b\x0e\x07\xf0\xd9\x01\x1cx\xd3\x07\x0f~\xbe\xff\xc3\xed`\xe2\xdd\xb9s\x0b\xf6'S\xf0\xee\xde\xbe;\x99\xc2\x14\x1fM\xef\x05\xfb\xe0\xdd\xb9\xfd\xc0\xbb}p\x9f\xde\xbb\xf5\xc0{p\x87>\xbd\xb5\x7f/\xa60\xf7\xbc[\xf7\xef=\xba\xe3\xdd\xbdw\x00\xd3\xfb\xde\xfd\xbbS\xb8\xeb\xdd\xb9\x03\xd3\x07p\xcf\x9b\xc2\xf4\xc1\xea\x8ew?\xa0\x9f\x80}\x98\xd2\xcfL\xe8W`J\xbf3\xa9>swB\xbf\x13xw\x0enO\xbc\xe9\xdd{\xde\x83;\xb7&\xde\xbd;\xec\x07m\xee\xee\xcf\x0fh\x97\x1eM\xef\xc1}\xdaG\x98\xde\xf5n\xdd9\x80\xfb\xc0&\xec\xdf\x9d\xf9\x1f\x8d>\xf8\xca_\x9bu\xff\x93\xac\xe0\xf3\xe9\x01\xdc\xff\xe1\xfe\xcfw\x10l\x10\n\x7f\x82\xd5\x97\xe4\xb9\xb8\xc4\xe2\xdf\xf6n\xdd\xbe\x0f\xd3\xdb\xde\xfd\xdb\x0f\x82\x89w\xfb\xee\x03\xfa\xff\x93\xa9wp ~\xdd}p\x0f\xf6\x9fQ4\x98z\xf7\xa7\x0f\xe2\xc9\x81w\xf7\xce\x94\n`\x07\xdaW\xf0Q\xe3\x1f\x04\xa0\x98B\x1f\xc7\x07\xde\xbd;\xf7'\xb7\xbc\xe9\x9d \xfd\xf9\x00\x7f\x1e\x04\xb2\x97\xee\x8b\x97\xaa\xdb\x80\xb7\xc5\xcf\xaa\x83\xf7\xbd\xe9\xfd[1vor\xcb\xdb\xbf5\x0dto\x80\xe8z\xf5\x9ca\x1a\xed\x1d\xf6\x89b\xc2\xf4\x0e]k\xf1;P\xbe\xf2)0AY,\xf7\x12\xf8p\xcb;\xb8\x03\xd3\xfdgw\xbd\xe9\xfe\x038\xf0\xee\xdc\x0f&\xde\xc1\xdd\xfb\x13\xef\xe0\x1e\xffqo\x1f\x17\xf7\xc1\xbd\x07\xe2\x81wo\x7f\x8a\xff}p\xf7\x01\xec\xc7\xf7\xbc\xfb\xb7\xe0\x9e\xf7`\xff~@!\xbc\x83{S\xfc\xef\xbd}:[\xf4\xc5x\xd2\x80\x99\x08 \xfa\xe9)\xb6\x83\xdf\x11\xed\xd2\x15\xec4\xfcL\xf4\xf3\xd3\xce\xfa\xa4\x1fyy\x89\xa9\xbf\xe7\xdd\x9e\xde\x07\x9c\xf8\xc0;\xb8w0\x11\x93\xc6~<\xb8\xf7\x00\xf6\x0b\x9c\xcc{\xfbS\x9c\xc8\xbb8\x91\x0f\xf6\xef\x03\x9d\xce\x00\x97@\xcc\x14\xfb\x81/q\xa0I\x05\xd4XQ\xfc\x14N8[\x81~\x93\xb8\xf3\xe9t\xc7\xd8\xc1\xc9=oz{\xfa\x81\xe6\xfd6\x1c\xdcV\xcd;/\xcbqe\xd3\xfd\x00\xeemo\xffp\xc7\xbb\x7f+\xbe\xe5!)\xba\xf3\xe0\xd9}\xb8\x1bO\xee\x02\xfb\xdf\xd4\xbb=\x9d\xd0\x7f\x9eQ(\x98\xde\xfa\xe1`\xfa\xf3\xbdO0t\x16\xf1~e#\xdf\x87\xe9\xfd\xd5\xed\xed\xe4`5\xb9\xbd=\xf8\xf7\xf3[pw{\xb0\x9a\xde\xff\xf9\xee\x0f\xb7\xfe\xbd\xbe\x05\xf7V\xd3\x83\xed\xe4\xe0\x87\xbb\xdb\xff\x8f\xbdw[r\xe4F\x16\x04\xdf\xfb+\x90l\x9d*\xb2x\xc9d\xd6E\x123\xb3\xb2\xd5j\xe9\xb4\xd6T\xdd2\xa9\xfa\xcc\xce\x90\xacj0\x08\x92\xa1\x8c\x9b\x10\x08ff 5\xd6\x0fk\xfb\x03\xbb\x0f;f\xbb/\xfb0k\xf3\xb2f\xfb\x0b\xf3)\xfd%kp\x07\x107D0\x98U\xea\xd3\xe7LS\xb2\xca\x08\x04.\x0e\xc0\xe1\xeep8\xdc\xcf\xeb\x9d\x1d|\x1c\xc5\x84Q\x18D\xfd\xf3O\x07\x13\x9a\xa6\xfe6\xaa\x9f+G\xfd\xe9\xd9Y\xd5\xa6\xd47\x1f\x9e9\xce\x95\xd5\x87\xe9s\xc7\xb9\xb2\xfa\xf0\xb4\xbaCK\xf1\xc3\xf3j\x13\x81\xf3F\xa5\xdd\x9b\xa9\xba\x9e}\xee0u\xdddA\x80\x9f\x9f\xbb\x82\xedxq\x18\xc6QH\xf9\x8d\xce4\xad\x1c\xc5\xba\xd4$\x9ekP\xd5\x0f\xce\x10R\xee\x91+\xf5\x19\xdeX\x04\xd1\xbb\xf5[\x0c\xd7\x95\xd0}\x8b~\xd6_D|\xc3\xe0\xc3|\xa9S\xfc(\xf0#\xf6*^3rEN\xa6\xa5T<\x0d\x85G\x9d\xbeR\"(\x1e\xba\xaa'\x9d\x8aJv\x86\xa7\xa7\xe6\xc5\xb4x\x9f\xc4[N\x93\x9d\xfe\\x/\xa0S\xbd\xf7\x1b\xe7-\xa9^\n\xe6y=rrE\xc4}\xc2\xe2\x0d\xea\x8c\xfa\xa0\xb1\x19\xc1\xc1qOOWoP\xedL\xc4nIV\xe9\x89J\xa3:\xcd\x8b\xb9\xc9\xe6\xd7\xbb\xa6\x92c\x93\x9c\x056-\xad\x8d\xba\xbd\x1e\xef\xc1\xd5\xc9\x8c\xb3~0gK\x03O\xcaD\x1f\xae\x1e\xfe\xfc\xbe\xba\xa4`\x08r\xf3\x11\x95\xb5UY\xc5\xfb\xc5\xa6G\x84\x15*\x1c\x95j\xb2\xa0tR~\xa9Z\xcb\xfa+\xb80\xc9\x06D\xecx|\x0b\xfd\xfe\x8a\xf3\x98\xf7{\xff\x81\xc7\xd1\x96\xfc\x993\x85\xdet\x15\xb0?\xe3\xa1\xa4\x18\x11o\xc7\xbc\x1b\xb8\x9c\x7f\xea\xa1\x13\x8e\xea\xbd0\x8b\x9f\x18\xabF\x8d\x8cM\x1a\x8c\x88\x02[\xab\xe7!\x87V\xe4\xdc\xb0\xfb\xb4_\xfc6\x98lb\xfe\x15\xf5v\xb9-{m\xd5`sy\x99y\xb4\x84i\xc4\xa6\xcd\x1b\xd7Z\xbf\xbe3+\xc4\xd2\xaa\x10\xc6\xa6\x01W\xd4\xef\x8a\xb4\xde\xf93\x8a\xb8\x82\xc1\x87zj\xaa1\xa1\xfcp\x9dj\x06#\x8d\x99\x9e\xae\x18\xf29\xd5\x91\x16\xedU3\x1eK\xd3~4\x18\x91H\xd3\x89&@\xf4\xa1Z\xb7\xde\x01:!\xb6W\xd6\x94~@\x14\x86\xcea=\xe5\xf5\xa4RZG\xe4\x1b\xb3\xbc?\xe2\xb8D\x15\xbax6\xfa\xa0\xa1\xea\x06\xe2\x03\x06\x0c+\xee2l\xe0\xf7+\xe6B\xd1\xa7M\xe1u\x92 ?H\x0dC\xfe\x15\xf9(|\xbd\x81\xa1?u\x1e\x07\xf85%\xa6%\xb1)D\xfeE!\x01\x9c\x8e\xc4\xa6\x97[&~\xcb\x19U\x14<\xb6/\x0ebZ\xec\xb6\xaf$\xa7nS\xe3\xe0\xba\x9b\x98\x93\xbe\xe9e\x0e\xe1Hk\xfc\x03\x16m\xc5n\x04B\xca\xd9\x08D\x92^\xef\x82\xc4\xe3\xf1\xc5\x80P2\xbc\"|\xce\xe6\xfeR1@\xb6T\x8d\xf8\xc3!\xb6\x84]r#\"-\xcea\x1d\xfa\x8f\x0b\xf7x\x9a\x03>\x1c\xfa\xe4\x92\xc4\x17\x03\xd2\xc3\xa5\x80\x8e\xf3m\x17\xc85\xf6\xaa\x80\xa0\x06\x19U\x16s\x0ej`\x9a5\x8c\xc1Q#\xf0\x91\xb0s\xb2\xa3\xa9\x0bC\xd5\xa7,b\xa9G\x13\xf6j\xed\x92=U\x0e\xce\x92\x80z\xec\xabH\xf8\xc2g\xa9K\x12U\xd9\xb0\x9a\xdf\x8b0\xa8\x8b\xa4?\x17\xb4\xfa\x19J\"?e\xb1`o!\xa6\xd5a\xed~\xef2/\xf3rQ\xd8\x88\xbe\x1f\x95\xeb\x03\x95QG\xb2\xd3\xbb<-\xd4\xda#C\x92b\xf6r\xed\x1eR\xc4.5\xb2\xb9Xj9\xeb\x9a\xf4.\x13\xce^^\xaa\xe2P9\xed\xc3g-\x17\xc0u\xe6\xcbS\xf8zy\xaar\x16\x00 3\xd2\xebR\xb02\x0e\x1b\x16y\xae\x85=R2`\xe0\xe2\x0f\xdeH\x91F\x08\x1d;\x17\x8ekjkX\x1b\x8e\xc305\xeb\x93\x80F\xdb\xef8\xdb\xf8wu\xc9)Q\xe4\x9a\x86\xa9K(Q\xdf\xc1\xc9\x0c\xf8\x9f\xd1\x19'i\x12\xf8\xa2\x7f\xbaH\x87\xa7\xdb\xc1@\x87\xf2\x86H\xde\xbc\x1f\xe0\x12\xc6\x1e\xbe\xf5\xb2T\xc4\xe1\x88x\xf3\xb3\xe5\xc0\xfa\xb1p\xe5\x99\xab,\xcb\xca8\xd4\xed\x17U7\x1f\xe3\xd1\xe3U\xef1\x19\x92\x1d\x0c\xbb\xdf\x8f\xfb\x9b\xc1@\x8d\xf8\xe3\xde\xe3R)\xa7)ia\xc6\xd5\xbc\xad\xd5L\xc1\x0c\xf6\xa3\xc9\xce\xdf\xee\x02\x88p\xf4\xe8\x11)\xbcj\xc3\xd5B\xca\x88\xcc\x133\xd90\xeb\x1e\x15}o\x80n)\xfa\xf6\xd3\xa0\x15\x83\x1c\x88\xa1\x87DK\xeb\xd9d\xc7\xe8\xda\x8f\xb6\xb5%\xd8\xbabv\xaa\x0d@\xc7\xdd\xb7l\xcf\x02\xecb\xb95S\xf1\x91k\xd1Yum\xad\xef\xbap\x00c\xda\x1bM\xeev\"\x0c\xfe\x98\xc1\xb1\xed\xe5\x8e\x93\xd3\x97=X\\;\xfe\x12<\n8\x87k\x95\x05\x01\x13o\x03?\x15\xdd T\x168\x08S\xa1\xa2#G#\x0b\x9a\xa7\x13\xea\xf3\x05\x0b\xbbC\x17\xf8\xd5Y\xca+\xa9A\xd6\x0cU\xe0\xd7;\x19s%\xaa\xad\xdd\xc3\xd5&\x98\xaa\xb9v2\xc0\xdee\x1c\xe8e\x03\x95\x93\x97dJ\xae\xc9c\x92\n\xca\x05\xaeP\xf3 \x96&FTu#L \xbc#'!n\x99\x04E\xb5`[\xdf\xa9\xcfE\x06!\x80\x0c\\\x93\x1e\xa2bR\x9d\x99\xbc\xe6N\xe0\x9a\xe1<\xe9\x17jW;\xe659\x07\xe1\xf1%\x05\x1b\x10\x03\x07R*\xce6\x06\x06\x0c\xf3\x15\xbb(\"\x8c\xc1\x11\xcb\x8cV+\xf0C\xba\xed\"\xb2\x9b\x01|LR\xee\x95 M\xb9\xa7\x01\xad\x8fS\xf6\xd0!oX\xbd~\xb85Q\xcf\xfa\x8f \x0d\xf4hc-4P\xf3\x80\xcc\xd5$\xa0]1.\xe1\xc7\xbd\xc7\xeaO\x86\xeb\xbfH\xbf\xc9i\xaf\xb0\xd0+#\x04\x11D\xbb\xd3C\xc8^'\x16X\xcb\x113\xd5T\x8f\xe2\x81G@\xa3\xb27\xd5r\x0c4\x0d\xf5\xac\xe2\xf5\xfd\x11\xd0\xa8\xecM\xb5\x1c\x03MC=\xfc\x08Pxm\x9e\xf9Q p\xd7\xa8v\xa2\xd8\x1d\xb8\x94\xd8i.E\x03\x7f\x1bi\x0eu\xaf\xd6\x8d`wb\x0c\xa93\xa43\x98\xa3\xca\xac\xea\x90\x1d\xd3\xb7]\xad|\x1d\xe5\x1e\xda\xb3\xf5G\xee\xd9qh\xbc\xae\x96O\x05\x8f\x1d\xa2jc\x15\x98\xbf\xa1\x96# q\xd7s\x8c\xe0\xc5BG\xe9# \xa8\x97_\xb3\xa0{\xf3k\x16\xb8\xca\x1f\x01\x80\xa3\x06?J\xbbC\xe0G\xa9\xab\xfc\x11\x108j\x08)\xaf\x0b\x15\x8d5\xa8\xdc\xce\x1a\x8e\x00\xc2UG\x9a\xad\x0e\xad\xb5\x1c#\xb3U\xf3f\x1e>V\xebN\x8e\xa8;i\xab\xbb&`\xee(_\xaf\xb4.\xf1\x90D\xa1\x1b\xa9\xec\xa4Vj'\xb5\x88P\x12\\9\x88l\x1ao\xc4\xd1M@\x81\x94\\whM=\xd6);\xbb\x13\x1d\x07\xad2T\x95\xf1\x11a`N\xcb\xbaTV\xac\xaa^\x93\xa0\xdb\x0f\xae\x87\xaeVu\xae\xd9R\xd3\xe3KU\xe2\xa0\x14\xf7\xf2\xb1\xa3\x99#\x16\x85\xca_SB\xc5\xb1\x88b\xc1\xder\xb69\x04\xad\xe1D\x7f\xc8\xc2\x15\xe3\x08\x9f\xbf&C2\x1dLD\xac\x1d\x938N\x97\x95\x88\xdb\xdbD\x9cm\xc0\x10\xdb\xc9\xc4P\xea\xcdV\xdf\xac\xc9Kr\x06G\xa6\x9c\x0c\xafHof\xf5\x0c\xf0u0\"\x8f\xd5\n2\xea\x1f\x03\xffX\xd5\xfe\xd2\n\xfd\xbf\xdeD\x8fuL\xdf\xc7=\xe2\xaf\xaf\xac\xc4\xff\xb8\xf7rn>\xf5\x96Jxw.:;.\x80Y]wD\xba3eI\xf8\xf1\xe5\x8eW\xc1M\xc7)Kz\xb0N\x14\x1fn\xce\xa22\xc0\xec_\xa6\x0c\x9a\xaeeSY.\xe3\xa0^\\m\xa1\xa1|k\xcf\x8e\xc0\x9f8PM\x9dj@\xeaT\xc4\xd6|\x14\xea\x07>\xcc\x0fNX;j\xe1l\xd6\xa6\xde\x17,\xac-\x0e\x0b\xcc\x11\x1dt\xe9Kl=4\xf2v\xf1\xc1CE\xb3Fr|o\xefR\xd7\xc5\x105-\x06\x92\xe3|\x01\xe3\xabC\xb4\xa2\xde\x0d\xac\x90\xbf\xfe\xaf\xffM\xe1|e\xb0\xd6\xc7\xc8(\x0e\xcd\xd9\xfa\x08\xcd\xdbZ\xd4D\x9c#\xf6^\xeb\x9a\xb0\xb9>N>rC\x7fL\x0d\xc2Q\xc3Q\x02\xf3\xba\xb2\xe9+\x1f\x03\xa5\xe4\x8ad\xc5\xf3\xc3.\xcb\xa8_\xe4\xa4\x84\xf5]\xc4\xa9\x90}8\x8c\xc8\xcb+\"\xf4\xe9\x1a\x19\x93s\xc5\xc7\x15\x9b.+\xcaP\x13\x05\xd6\x07F\x0b\x85/FmU\xd2X\x89\xb9B\xbf\x82\xc6\xea\xac\x9c\xac\x99\xa5iU\x15\xafh\xcf\x8a\xf5\x9c\x97\xda\xd4 Z\xab\x85=Tip\xc5\xb9\xd4\xcf\xf78P\x03ri\x8f\x0f\xa1\xa9\x8a\n\xd5*\xd9\xecya\xaf.\xa7\xe4SS<\xa8\xcd \xf5\x03\x0f\xfa\xea\xc6]1\xb9\"\xf3\xda\x94\xcd{@\xa8{\xe8\xdb\xff\xec\xf9\xc0q\xf03\xef)\xden\xb2\xbcpg\xe1l\xc38\x8b<\x08\x13\x0f\x19?ug\xd4S\xaa3}\xe6\xced\xe9\xa2\xa0~`\xf2~\xde\x0c\xdc\xb9\xce3=k\x82\x0e\x8e-C\x16 \x03\xdft\xea\xce\x9a\x86\x94\x0b8\x06\xb49\xcf\xdd9\x03?\xba\xf17\xf7&\xd7\xd3\xc1\xb2\x94iy\xc4q\xbf\xc3z\xaahd\xc5\xcb\x84\xdc\x1ej+\x92pvA\x18\xb9$\xb1F\xc6\x0b\xc2\x86\xc3A\xa1\n\x8c$\x12\xcf\xd9r~\xb6\x1c\x11x\x98.]\xa6W\xc5\x03vm\xe5Q\"\x10.n\x84Gi.\xf8\x04\x9a\x02D\xe66X\x01\xa2-\x13\xdfg\x01K\xfb\xbd\xde``\xe1\x16\xe4\x92D\x17D(\xf0\xf9\\,\xfb\xac\xd1\x84\xe3\x03n\xc3\x95,A\x1a\xbb\xc6\x8a\x160\xd7\x84i;\x17\x1c\xcb:\xe1SC6\xb3\xd4\xcae\x01\xa9\x830\xb1I\xca=s\x88\xde?]D\xa7[\xbc\xf6:\x11\xdc\x0f]\xe2m\xc0\xf6,p\xde\xdeRm\xa532?\x1b\x91\xa9\x03?\xf3\xbb\xd8\xf32^\x82CWm\xc2h\x0c\x8f\x14X\xa3\xa2\xbd$\x9b\xb0h?\xb2\x1d\xff\xd8\xc6\xafO\xab\xb6\xaa\xdaJ\xe6y\x93\x91\x0c3\xa7\xb6\xbe\x0b\x0b)\x9c\xe6\xa6#\x12\x8c\xe0\x18\xbb~\x04\xfd\xec\x9c\x9c(\x82<\xf1v\x94\x7f\x19\xaf\xd9\x17\xa2\x7f\x96\x9f\x17\x8f\xa7\xf5\"\x9fO\xebE\xa6\xedE\xb4G}f\x1d\xe4\xf7\x96\xb3^{\x11j\x96x\xa1\x8b#2_\x0eF\xa4\x9f\xc1\xd5b:\"S\xe07gDJ\xf2\xfc\xb3:T\x19\xc8}\x8d\xcd\xc0r\x0c\xc8\x15\xa1\x93$N_\xd1\xbb\x11\x8a\x01\x8a\xc1]\x90\x94\\\x92@\xb1\xb0\xe9\x19\xd4L\x01E\x0b\xb5\xa7\x83\x0b\x92\x0e\x87naR\x873\x0c|\x8f\xf5\xcfG$\x1b\x8c4[\x86C}\xf3\x05\x9a\x1a\x91\xd4\xa0\xb9Y\xf4\xe4\x9a\x8c\xa7dF\xfa>l7\xd9\xde\xa7H\x07\xa5\xac\xa7)\xda8\x18\xe9;\xd8\xd0F%\xc7\x1c%Xo 2m\xe3\xc7+\xb2\x19(X\x1c\x14\xb0\x1bq(\xd0=\xf0'\x82Q=p\xa1\xb8\xccF\x0b\xb4\xa4~\xc9\xd8\xd2\xca)\xd2J\x9aKM\xd3\x12M\xac\x954\x0d8\x85*Z=\xde+\x89R\xd4\xca%\x8dR\x92\xaa\xc0J[.a\xcf\xfc\xa0\x03jY\xd3\x82\xc6\xe2\x82\xf0\x82pt\xd2\xef\xab\xf5\xed\xf7\xf9\xa8`R]\xa56\x88\xe3\x83\x8b\x01\x10 \xaeQ'68S\xb7\xd40\xbfb\xc3\xaa\xe4(o\\\xe1Q>\x14 \xde\xa1=c\xde=\x9bx\xc8[\xef/N\xf9\\6W\xcf\xa6U{B\xaa\xd3\xab\x86\xf8h\xed\xff\xec\xfc\xccIA\xd3\x9c\xbc\xd4\xccp\x14t\x9apB\xe4\x80\xf5\x88\xecFd?\"\xe1\x88l\xbb\xd1\xc5\x03\xa4\xf4\x01t1\xa8\xd3\xc5\xd4\xd0E\x0f\xe8b0\"g\xedt\xd1\xeb@\x17\x13rE\x02K\x17\x15\xd1\xf2\x90.n\xc8%\xc6p\xe8?=G\x8a\xb6\x86\xac\x15\xea\xb8Ac\x9c)R\xa4\xf5\xe0\x82lj\xb4\x12\xc8\x80\xaf\x00\xde\x1c\x80f\x0fM(\xc1R\xc7m\x1ca\xfc)\x03\xa4\x82px\xa5(\xc3G\x04\x0fZ\xb6\xf5\xed`\x1c7\xea\x91\"\xc8\xe4\x9a\xf4\xc3:`\x16(%O@\x86^\x0fSw\x83\x02|\x1a<\x07d\x17\x03\x05\x8c\x93\xad\xd8\xd2\x9a)9J[\xde\xb1U\xbc\xacoX\xcdtD\xbcA\x99M\xa4\x93|s2\xdf\"w\xa8\xa6\xb9.\xbe\xe8\xb8\x9c\xa1\xc3\xe4\x0d\xfc?\xecK\xe9\x8a7m>\x1eS\xf1[\x99\n\x10\xccB\x17\xb4\xc7\x8eR\x92\xb6\xa1>\x92\xff\xf8\xc7\xf3\x9f\"g\xf1\x1b8K\xce\x99\xfc\x1agr\xf2\x1f\xffh\xfe\xe3\x1f\xe2?\xe9/\xc4\x7f\xfcv\xfe\xe3\xbb\xf8\x8f\xff7\xe5?\x0fA\xc1F\xfc\x83\x01\x8fpw\x07n>\xec\x0e.\"\x97\x84_\x90H\xed\xe0JX\x01\x08\x16\xcf\xa3\xe5\xc0\xce\xba\x99\x07\xbd\x03\x11f\x00]\xbb\x10\x91{\x8b\xfb\xd7\x1a\x0d\x90\xcaK\xdb\x0c\x18\x80\xfar\xc2{d\xb5\xf4\xa4b\xf8LJ\x0b\xd9\xaa\xd5\x816\xb1\xfc\xa2\x9a\xddx\xd6B}\xb5\xe8\xdfz\xc5c\x17\xa4\x06\x85\xf5\xc7\x8cB\n$t\x85\x8b\xe6F\x1cF2\x0f\xe8\x8a\x05#r2\x053\x1cGUE\xfdV\xb9\xae\xe9\x88$Z\xce\x0e\x14IMM5}`'z\xfb\xcc\x06#r\xb2\xa9^$\xd2\x93\x9d\x0f\x05\x18%\x0e\\\xdd\x04\x04\xa4\x96\xe4\x95K\x8c\x0en\xd6I\xbeaw\x9c\xc348Q\xd1\xdbpo8\xac}\x06/Q\xb9\xb2\x83:\x15\x1an0\xa0']\xe0%\x0e\x98[\xa0%\xfa\nmK\x90\xc3\x96\x0e\x11\xdd)\xdc% *^\x93>lG\xe7\xcbAG8+\xb4\xbf\x19\x12\x81\x0eh\xda\x82\xcdv\x006\xeb\x08V\xa3\x8e\xc6\xfc\xac\xae\xc6eEh~\x06\xa0\x96j\xac\xfa\xa50\x8c\x1f\x0c}\x95U~\x8cQ\x1d\x8f\xbd\x06\xb8\xe0\xe2\x8a\x82\x1eh\x02\xd0&\x886\xab\xd7x\xfei9\xc8\x97]\x91ji\x83\xf5l\x80\xf2\x8c\x9b\xd3\x9b\xdcs[,\x97@\xac\xf6<_$q\xd2\xcf\x03\xbe\xc4\xf9\xbe3\x8b\x04\x9cg]\x17\x13fJ\xac\xe1\xa8%\xe5p\xa3\x87p\xb5\x1c\x1f\xba\xe6\xf0\x98\xee\xe1\xab\x0e\x0e\xd6Z\xc3|\x1b\xccj\x98\x12\xb7\x14\xe2#G-\xf6\xc9\x1ft\xa3\x84\xc4\xd1\xcbC\xb8u\x10q\xea4\xb2\x96\xd2\x0567\x95n\x83\xae\x05\xb2\nT\x1f$W\xd9d\xbb\xbf\xe6\xcd^\xfdruo\x7f>\xee\x0f\x16\xf3\xc5\xf2\xe7\xf7\xc3\xeb'\x93O\x16o\xe4h\xf6\xeb\xcb\x93\xc5b9\x00E\xf0b\xf1\xc9\xb4\xf71\xf6\x10\x0ey\xa5\xb8\xbb\xef\xb0\xb7()\xcf\x1a\xb6\x0dy\xce\xef\xd9\xf6\xab\xbb\x04\xc4]\xb8&\xd4\x7f#\xe7=\x08\xd2\xb8\x88\xfa\x83\xf9\xf2\xf1\xa27\x19\x9d\\\x8f{\xfafO\xaf\x87\xc1\xb7\xb8\xb9\xdb\x83\xa6\x82\xcbA_\x95*_t\xaeC\xd31n\x97\x9d\x804[\xa5\x82\xf7\xa7\x0e\xbc\x1cL\xd2\x98w\x0cN\xaa\xeb+\x9ck\x9a\x13@W\xbd\xa5\xeeI\xec\xdf\xa0\xff\xc9\x03\xc7\xa5g\xe4\xa3\xc2h\xa3\x82\x04_\xfa\xeb\x11\xe9m{j\xe7\xbb\xb1\x92Q\x9e\x17E\x933$\x98\xbb\x92\xc0\x1e\xa3\xc0\xee\xa6+\xd5\xed\xdd\xce\x9c\xd5\xba\xf3\x93\xe2\x86\xb2\xafH>\x14\xb0\xd2{eo\xf9\x12\xe8\xb2\x18\x8f\x9bk#\x06\n\xc1\xee\x84\xdeLP\xbd\xd9\x1b\x1c\xdc\x1b\x9a\x9f\xd5\x80\x9f\x8d@OF\xf3\xdd\xc6f\x12\xd0T|\x13\xad\xd9\x1d~\xf7\xb4\x0c\xb7g\x81\x11\x8d/@|\xdfL\xd8\x1d\xf3\xfa\x19\xe8-\n\xa5^\xa2\xfa\xfc \x95-\xfe4e\x83N5\xd3\xd9\xe2\xcf\x8a%\x99\xde\x98\x06#\x92\xa0>\x8d\x0cI2\x9f.\xf5\xe0v\x08EG\x0e\xf1\x99\xe2\xef=\xb8q>\xbeo\xd6L\xadc\x07\xb5\xb6\xc5\xb1\xde\xb5\xb8\x91\xcc\xcf\x97\x1d\xa2\xe7\x91\xc3\xf2b\xf1\xf7\xd0\xee=d\xeaT\x0f\xba\x15\xf9\xdb\xcc\xce!>_\xfc\x1d\xe0\xf9\xc5\x9f\x82)\x80\x05\x93/\x921I\xe6O\x0d\x8a6\xabR\xcc/-ho\xfa\x01\xb9$Y!\xe1!\xfd}\xc8t\xd9\x95\xf6K,\xa9\x12aT\x04\x0d(\x8d\x91\x98}\xdd\xf4\xd9\x08\\\x1b\xa4#bR\x04\xea\xb4\xdb)\xe6\x07 7&\xd5\x1cZ\x9c.\x86c\xb9\x98,&rq\x8d\xff\xc9\x93\x93\x93\x139\x1a\xc9\xf1\xf8\xb4~\x98q\xba\xe8\xf7=)B\xc9e2X\x0cN\xb7~\xfd`\xa3>w\xde\x8c\xf4\xfe\xfb\x7fsL\x11W\x1f\xfe_\xc7\x87D}\xf8\x7f\x1c\x1fD8#\xbd\xbf\xfe/\xffw\xaf\xf4\xa5\xc1\xda\xa6\x8b4\x95\xcbQ.iIk\xab\x8a\xbe}\x1a\xe4\xa5\xd2\xde\xa8\xc8\nS\xcd\n\xd3&VXc\xc4v\xd3\x94v\xe7\xc7\x19)\x97;\xcc\x96I\x91\xed*,\xcd,\xdb\x85\x95 gQ9/U\xafx\xd0<\xc8Oz\xfa=<\xa3\xb9&\x01\x99\x91\xc0J\xc3\xf1\xa8\xdd\xf6\xac\xfa\xd3\xd2\x97?\x17\x13\x11\x7f\x1b\xdf2\xfe%MY\xbfbtS\xfc\xa9e\xc6'\x82\xa5\xa2O\x07\x16^Z0\xbf\x18\x8eA\xec\xfe\xef\xff_oPH\x9d\xfc|>z\x0f\x1f\xfe\xfa\x97\xffZ\xfc\xd2\x9f_\x9f,\x07\x7f\xfd\xcb\x7f\x85\x8f\x9fL'\x93\xfa\xd7\x9f\x9f\xe9\xb2\x9fL\xd5\x7f\xc5\x0c#[\xef\xa8T\xee\x8d\x9c\xbf\x19/\x07\xe3\xf1\xb8\xaf\x1e\xe4'\x83\xd3m\x085\xfc\xf5/\xff\xfb'\xe7\x95\xbc\x8bt0\x1e\xf7\x17i)\xdb\xffV\xcb6\x7f3^\xa4\xaa\xd2>>\xd5\xb3\x83\xff\x96\\mM?\x8an\xd5\x12\x8d\xf9\xe3\xde\xd2E\x1c }[\xa7\x08\xa7\xf3\xf1\"\xc5\xdd\xd1\xf2\xd4\xb5\xc3\xa2m\x16\x8a'}a\x0e\x02\x01\x7f\x8d`\x0e\xd3~\xe2#\x120\x85\xbc\x85N\xd6\xdb\xc8\x0e\x98^\xdb\xad\x04\xd0em\x10k\x13\x914WF\x91<\x80\xde\xf8\xceM\x9b=\x92\x1d\x91\xfb\x11Y\x8d\xc8\xdb\x11\xb9\xfd0\x82t\xab5\xbf\xab&\xc2\xb4\xd2\xc4`u.\xc5\x9a\xccFaK\xaer\x88a\xe8\xb60tx\xfct;\xdf\xea\x9c\xe4\xf2\x8al\x06\x17d;\x1e\xb7\x9c(\x99_a\x0c\xb6\n\xb9P\xae\xd2\x9b\x14\xd8_\xd9\x15<\xe8,[\xb1\x19v\xe1\x82(\xc1\xca\x03\xc2\x18\x97vAz\xe3\x13\xe3\x86\xc7\x1f\x0c.\xda\x87\xd9\xfc\xc0\xd7\x07\xb9\"'\xb4\xafPX\xefN\xc6d\xaa\x05\xc2\xd4\xeeW\xa6#rO\xaeH\xef1NL\n\xa6\x89\xa0:\xc0\xb2\x01\x1e[']\xe6\xc3\xfcT\xeb{U\xc3zDB\xf57\xe9\x06\xb5\xf9\xc1\xa0\xb4\xcdc_\xcd\x83\x9a\xcaQeJ\xc9f\xa0\xa7\xf4\xa8\x06\x89\x06z7I\xfdh\x1b0\x18\x8a{\xd5R\xa1r\x95\xb69f\x18\x8a\xbf\x1c\xe0{rM\xfao\xe7;\\j\xc5\xe3\xca\xcc\x91<\";\xb46\xc8\x89 Z\xc4\xce\xcf\x97\x15\xb6\x91\xf5\x0b\x02\x80\x9e`G\xb9\xa7K\xd0&\x7f\x0c\x10\xce\x1e\x08\xc2t\xa9X^qI\x1d^+\xae\x9fj\xca\x8f2V \xbe\xd1\xe5WW\x836\xfd\xf6\xe4\x9a\xdc\x1e\xb3\xcf1?\x18\xc5V\x1d\xb4\xeb\x97\xc4\xe9\xcc\x0e\xddQ%\x11ug\xc4\x11\x07\xbb\xed\xa7\xf7J\x9b\xce\x85\xc0j5T\x8b\x03VH\xff0\x02\xf4\xfe\xfa\x97\xff\xe2\x8a\xa0\xea\xfa\xbd',H\xd9G\xad\xfa\xa3\xee\xc1\xc0\xc0\xbc\xea\xf8\x15\xe4\xa9\xdb\xdb[\xf9\x1b\xb9\x98-N\x17\xa7N\xb9\xc9o\xd4L\x9f\xbe\xb9\\\x9c\xd2E\xfa\xe4\xe5\xa9\x91\x90\xda\xc5#Z3^7F\xe8s\x87^CX\x0b.7\x06\xab\xce&\xe82\xaa\xf9\x9c*\xe3\xc1\x8c\x9c4\xc4\xae`!\xf5[>\x8b[_\x08\xc6\x9b+\xd7\xf2\xf2\xd7Q!0g\xd3\xdd\x16\xf3Ko}\xe1\xed\x14\x92l\x99x}\x9f\xb0\xfeA\xa1\xc1\xa3)#\xbd\x8c\x07\xbd\xd9Add\xc7\xacy%\xb2\xccH4\x81\xc8dl\xfd\x9a\xddu\\\xf60\xaa\xd0\x83?\xf1\xc0\x11\xf9\xa6\xfak:w*\xfe\xe0\xc2n{6\x1c\x08\x98\xb5\xbf\xaf\xa1\xe8)\x90D\x0cjF\x18\x96\xafTB\xbf\xb0\xa3z\xa3s\x9c\xfa\xa3\x92[\x9b\xa6\x9f\xe3\x0c\xcc~j\xfcb63Sg\x8ez\xb9\xea\xb4\xe8\xf2\xf5\x11\x0b\xfc\xe8&\x9d\x11V\x1f\x12\x9a\x89X}U\xcb\xa4\x1c\x93\xda\x15L\xea\xd8\x8d\x0co:\x80*\xeee\n;\x80:|jg\x12eA\xab\xe2E\xdf\xc3i\xd8\xe3\x14,\x95\xee]\x96J\xce\xb1\xaemk\xee;\x1e|\x14\xb6+\xa0o\xb9\xffX\xe7\x1f\xb9\xdb\xa0\x1eXD\x822);\xea\x14\x04\xea\xd1\xb7\xd0\xb5\xdc\x9d\xabr\xb6 \x9f[Vw\xfa\xe6\x92\xce_.\xd2\xa5a\x0d\xdb\x01\x1a\x87\xea+\xa3\xbb\xf1xD\xfc~\x9a;\x18P\x89\xc3\xe1@\xc9\xc6\x90\x0bR\n\x9b\xaf\xbc\xad\x18k\xcc\xcbv\x01\x9e\xe8\x0e\xac\xe0\x90Q\xc9\xf9}\x85\x1b\x14.\x13(\xf4F\xa1\x7f5\xc91\xda\xee:l\xaf\xf6\xa5=e\x08\x05\xfb\x81\x82yo\x15\x06F\xbc;L\xf1\x88\x99tOo\xa3\xd7\xd0\x9a\xde\x11np\xc7\xba!\x97\xb6Y4\xbe\xcdM\xdf \xce%\x15\xec[\x05\xc6~\xbeYN2\x1e\xa0\xa6J\xdb%\x1b-\x1a|\xd4;T\xf5Y\xb5\xb4\x1e\x11\xef\x18\x12I\x1e\xa4\x0d'E\x8dx\x90\xab\xa5\x93\x8eJq\x92\x0b{\xebN\x05 \xb2\xc0C;f\x1d\x8c\x1d\xd1;m\xcc\xab\x87\xbf{9}`\xd5f&T\xfd\x99\x81\xe8p.E\xb4\x02\xf3\xa1#\xf1\xd0)\xb6\x98\xd6\xbd\xec\x91\xd3\xfb\xf0>\x15h\xe0\xd1\xd0\x8d\xc7\xdd\xe1\x0b\xd0\x92\x1eP=!\xc3|L\x0c\x91\xe8 \x0e\xa9_P8\xb4zh\x9f\x1f:\x8fG \xf2\xd1\xf3w_9\xbb\xcaJgWY\xf9\xec\xca\x1b\xd9\x834}vu\xb0\x9d\xf6m2\xee\xd5\x0eV\x82\xe7\x1e\xe3\xf1\x05pI\xadM9\xb9\xb2\x14\x9a\xe0\xadmC/\xe0Sf\xac\xd7/\x06\x8a-\xdb6:\xed\xe0\xf6:(\xe2\x88\xf89z\xc4\xfa\xe6+\x1a\xc0\xd9\xe2U\x8ew\xfa\xe4\xa4\xdc\xa1'\xe4\x0b\xcb\xc7&?\xa6\xd5\x8fg\x93\xe9\xf3\xc9\xd3Jj5\xd3\x97qr\xcf\xfd\xedN\xf4\xbd\x019?\x9b>'\xff\xcc\xd96\xe6\xf7\xe4\x7f\xa2^\xbcJ\xc9\xe5\x96\xb3\xedo\xd4?\xe3\x1f!e\xe2\xc5\xe1\xcbj5\xaf\xbeyM\xbe\xf5=\x16\xa5l=!\x85\x18\x86j\xdc\xd28\xe3\x1e\x83X\x86\x01\xe6IOC_\x8c\xf5\xcb$\xd9%\x07\xa0T\x15\xa6\xb3\xd3\xd3\xad/v\xd9JAp\xaa B\x80N\xdbF\xe1\xb4\xf4\x0e[\xd1Q\xd9\x80\xbd\xddF(\x9e\xfcI\xf8\x81q\xb0\xae\x9d\xe2W\xac\xc4\x9c\x02v\x9c_\x94v\x9fe\xc6Q*x\xe6\x89\x98\xcfH\\_\x88\x19\x0fR\xf7\xb6\xb5eG\x9b\xeff\x1d\x1f#v\xfb\x1f\xfch\x1d\xdf\xba?\x97\xb7\xda\xae\xcay\xa6\xd6.\x9b\xe9{3\xf5\x1c\xc5X\xac.'\xd0\"\x0c\xbe\xa3\x14\x9d\xf8\xe9\x97A\x9c\xa2\x13\x9ck\x18\x89WT\xec&!\xbd\xebGj\xaf2R\xd2\xfc\x0cvK#\xa2\x1d\nT\xfd\xd5\x17\x7f\xa0KC0\"\xe1\x8b{\x0b\xc51e\xf1\xeeV\xab.\x86\x98\xcb\x8bfz\xf5N\xf0\x07\xc1[\xdbP?\x0dJ\xd0\xb2OGX,\xcc\xce\x8cnV\xa5\xe9\x04\xb7F|\xb5\\\xef\xddX\x8d\xc0w\xc1mc\x8c\xa8\xb1\xfaU\xbe\xb6\nj\x0bf\x02w@\xa0,\xc8\xf3=\x94\xfb\x17\x1a\xe8\xa8\x03] s\x15\xef\x02#,=\xf74\x14\xc1\xb7j8bb\x19\x95\x93'\x1e\x0d\x02\x13%FS\xe9\xc1(\x8f\x86te\xa3! rM\x04\x99\x91\x13\xbco\n\xbe\\\xec\xe8\xa0V\x08\x8c\xc7\x05\xf1\xa3T\xd0\xc8S\x85\xe2\x89\" \xaf\xe9V\x15.\xfa\x83\x9a\xd9\xd1}m\x89R\x7f0Y\xa9\xa7>+\xfaY\xea2\x88%\xd23k\x16\x05\xcc\xcf\xa8V\x01\x86\x9c\xbc\xb6\x0e'\x83\xcd\xb1\xa3\x94 \xe0TH\x9a\xe4\xd0\x0cF\x8e\xb3\x0cw\x17^\x15i\xf8q}(\x90\xffc:Q(f{QH\x9b\x141\xbf\x99T \xcb\x85\n\xd5c3\xa9\xd5\x1c\x18r\xc2ssV\xcb\x91!\xb3~k\xce^b\xc2P\xa4\x90\xe2&.\x83#f\xe6u\x81q\x1e719\xcb=f^\xf2RvZ\xbe\x80\xdb\x11\x85\xc5\xd2<\x1f\x05\x81\x05j\xb3\xef-\xc3me\x14l_\xbf6\x17(\x88,H\x05\xcd\xfbQ\x83]Jy?\"1p\x99C\x9e\xb3H>n06}\x81j\xaa~U\xc0\x1c\x19t\xd6\xbe\x7f\xe2\xf2\xaa\xfd9\xcfPIS\xb2\xabS\xfa\xa4\xabTp\xea\x89WL\xec\xe2u\x07d\xc0\xa0f=S\xae\xd7\x05\xe1Ph\x9e\x1d\x1e\x04R\x94\xc3\"\xe2G*\x9b\x98\xech\xfa\xc7\xdb\xc8F\xa3\x8fP\x14a\xf3hI\xd0#X\x03\xfb6\xb8\xd8\x05Fv'X\xb4\xee\x08#\x80\x87\xf2\x1f\xcb\xc5\xfbf\xe4\xaan\xe7\xde7\xdc\xcc)m\x15\x1a\x16\x98\x91\x18AW]\x1b\x9b^a;\xd1\x1b\x00\x93*\xa4\x90\x0e\x13L@\xde)\x14\xd2\x81F\x90\x99R\xbe\xcd\xc01V\x83\x843(u\x01\xc2\x03\xb6\xce\x0d-\x81\x07q\x19\xe9$\xcd\x12\xc6a\x01\xe2\x0d\xe95\x0b\x98`\xe5\xae\x8c*;2\x8a\n\x84\xa8\xd3\\\x07\x81\x9f\xa4~:k\xdd\xa2\x17\x7f\xd6\xa4K\xebh^b\x90\x04\x98\x83(\x0b\x02%VD\xe4\x9a\xf4&\x93\x9e\x12~1\xbc\xa21\xf6Rl\x1f\xf4\xfcc\x12Y\xd5\xf1\x90D] \xb6V\xecvDN%\x0f\x7f\xc19\xbd/x\xe8\xd25\x0c\xf2\x8e\x18eq5r\x83\xf9\x15\x96\xa1\xdd\xeb\xb0\xceG\"\xc4\x9c\xbb\xc0\x1aU\xd2\x95m:j\xc5\x87q\xfd8\xcb1 p\xff\xe5\x8bh\xfd%MD\xc6\xd9\x11\x03s\"&\xdb ^\xd1\xc0\x11\x9e\xf1\xcfP\xed\xf7l\xcb\xee\xfeL\xc2,\x15dG\xf7\x8c\x88\x1d#\x8f\xb7\x8f\xc9&\xa0[\x92\xb2Z`F\xf3\xcbG\xac\xb23\xbc \xb8T\xc1@\x8a\x81\xcf\x00}\xb9\xb9\x80\x1f\xf1\x08\"\xe9\xad\xd9\xdd \xdf7Eh\xbf\x82\xe1(\x8c9\x94Jl\xb5\xdf\xb2\x1b\x8az#Pw}\x84\xeb\\\xc6H\xb9Wf\x99!}\xec\xe3m+W\xdc\xdc\xdb\x9d/X\x9aP\x8f\xc1\x08\xce\x08\x04dr\xec\x0f\x8a\xfa\x8e\xc3\xdb\x02\xb7\xde\xc5\x86+\x8d\x18W\xa0\x1a9#O\x90\xb2\x98\xf2\xfa\xd5\xb7\x9d\xf0\xcanw\xbb\x80V\xdc\x96\x08,\x86\xa1UE12\xa5\xf95\nb\x95\xe6\x8eiMJ\xd2\xeb\xc4\x81S&\xbe\x10\xe5\xbdb\x87\xbbkzC\xa3J\xa6\xfd\xc1\x9c-\xf30\xba]\x1a\xdd\xd6\x1b=\xba\xc5.\xed\xe8\xce\xa5]\x1a\xaa*xtK\xad\x0b\xa9\x82\x829\xfeu\x01n[\x07\xae\xcb PU\x06d\xe8\xc2\xebU)\x0c\xae\xf9\xb9G\xe4K\xc5>\xbb\x8cH\xb1U=\x92\xfd\x1e0\xdf^M\xc3I\x1a\xe4\xbb\xf5\xbass\xb9\x9a\x0d\xd5hf\"\xa0\x82\xfe`\x94\xc7^\xac\x10\x14\xd4\xaf\xe9\xb9\xd0\xdc\x0bo\x11D\xe0\xf8\x1d\xefDr\xb5\x13W\x94\x17\xef/\x98\xc4\x0b\x98\xf4l\x92\xee\xfc\x8d\xe8+\x12<&\xb8\xed\xf7QrP\xdc\x9c\"\xc1l\xe2\x88n\x1c\x9d\x189\x85\x16\x03\xcfu\xc5\x0e\xce\xc2x\xcf\xfe\xee\x07\x8f\x16oX\x95FR\x0de\xbbv\x13\\p\xe2 _\xc0\xa8\xc3\xb1\n\x8e\xb7j\xc1c\xfdtD\x1c\xd7m\xc9!\x8d\xd9G\x9d\x89m}\xc9tY1\xb5\xe6;\x93\xe4\x1dM;\xcf\xbb\x15\x8e\xd0\x9a\xa3GzdX\x9d|\xb8(\xdc+\xdc\xa5\x81LL'w\x81(e\xe2\x1b\xc3?\x8f\x80\xaa\xc6\x89\x8f\xe3\x80\xae&\x8fk\xb1\xf3\x90\x1b\x1d\\\x87\x96J:\x8f\xa2\x16\xbcE\xe5`\xb2\x83\xce\x0f\xb0\xe2\x07\xc1\x0f\xf0\x96y\xef\xb2\x87\xd1\x95 \xaa \xf5\xdcb`2\xd2{\xd9\xcb\xa3\xf8\xda\x91R+\xbdwy\x8a\x05{/{\xcb\xa3T\xc7%\xf0:\x0c\x05\x8a\xcd\x96\x0bYA\xbe\x1a\xc5\xcb\xfc\xaaC\xa7\xd7G\xfb\xc0\xcd\x97\x87\x84j\xe2G\x84\x0d\x08sk\x03\x84\x16\x98\xc9\x90<\xc6\x08\x0b\xb0\xf5\xc0\xa8`\xed\xf4<\xa7\x16\xf5\xd1+\xa5\xbcW\xa2xMou\x84\x88\xfcQD\xdf\xceS\xdc\xa5\x89\xa2\xd6\xc9\xc8\xfcm\xbe?\x8c\xb4\xda\xa3-f\x06\x14\xe5\x1d\x98\x7f<\x0d@\x14`\x85\xd3+T\xb5\xe3X\xfe\x9e\xb3M\x7f\xd0\x82 ~N\"\xa0R\xedoZ\xcf\x04\xbb\x13\xfdBm\xa8\xb7oROt\x19\xbd\x02\xcc\x1d\x05f\xb3On\x1e9bm\x87Dc\x1e\x07(\xe6g\xf9:\xc2\xf6e\x8a\xbcC\xed&\xdb\xe6\x95\x1b\x13u\xa3K1\x1b'\xabA\xd5\x190\xb6!\xb9\"\xbd\xb7\xab\x80F7\xbd\xae\xaa\x942<]P\xae$\x81[-k\xfb\x12\x85\x93\x9a\xa1\xa5\x8dC\xd2\x1b#s\x9bu\xa4\xfc5\x8c\xe9\x02\xa9Uek`\xd7\xf1k\xadF\xae*f\x89\xbb\xd5\xbc\xc0\x11\xcd\x19b\xa2uT\xf6X\xce\xa8\xb0\x15\xbb\xc3@\x1e\x93\xef\xfe\xf8\xc37\xaf\xbf\xf9\x97\xaf\xde~\xf3\x87\xaf\xbf\xf9\xc37\xaf\xffc7\n\xe6<\xd69\x82\x8c\xa9\xf2z\x8f\x0f\x1a\xfe\xd3\xfe\xf5\xac7\x7f\xd3[>\xb9\xee\xc9\xc7\xf37\x8f\x97O\xae\x1f\xcb\xf9\x9b\xc7\xbd\xab\xcb\x97\x7f^\xa4\xcb\xe1\xe0\x14\x19\xdc\xe9\xfc\xcd\"]\x9c\xf5\x1e\xbf\\\x9c^-\xee\xce\xa6\xe3\xc5\xdd\xf4\xeb\xc5\xdd\xa7_/\x87\xa7\x134\x0fQ\xb3\xdb\xbf\x9e-\x16\xe9\x93+\xf5O\x0foM\xdao\x83\xeb\xde\xa8\xe8\xcbd\xaer+Vy\xd9?\xf9\xdd\x1f\xbf|\xfd\x1f\xbf\xfbj\xa0^u\xeab\x91\x0e\xf3W1\"= \xeeQ\n\x15\xaa\xcf\x83'\x86\xdb\xe2\xbb,Tq\xd9?\x85F{\xe0o\xe6t~6\xfe\x9c\x8e\xdf}1\xfeO\xcb\xfcq\xb6|rZ\xad\xb3\x0c\x81\xb0\xad\xa8^\x9d^\x17\xda\xcb\xf9\xf7\x88\xf4\xb6~\xcfE\x0b\xd5\xa0\x7f\xb9\xa3\x9cz\x82q\x13Q\xddhZ\xfa\x8f\xa2U\x9a\\\xc8G\xbf\x9e\xbe8\xbb\x90\x8f\x02\xa1\x9e\xe1q\x8b\x8f\xe7\x17\xf2\xd1OY\x0c/O\x9f\xc1\xbf\x9f_\xd4\xaf\xdb\xab\x1f\x989tA\xd8\xd2n\xa4\xb0\xf7\xb0\xf8Q\xb2\x8c\x98//PUzb|]\x82\xf2g\xfe\xf4@nE\x10ON\xc4A7\x1bAE\x93\x1b\x8f\x88\xd0\x9a\xbaf\xab\x81\xc0\xaa\x87\x91c\xa91Ut\xe7\x8bh\x0d\x93w\xff\x87x\xcdR0'\xf6At\xd1Zv\x7fD\xa2\x81M\xec\x17h\xfeWh\xa4\xa1\xca\xf5\xb5\x8f\x81\x81\xd6\x0d\n\xab\x1b\xa4M>\x86H\xe3fJ\x89wq!@\xc9\xa1\xa9\xf0\xaa\xc3\xd12\n^\xb7Q\xf0\xdc\xa3pD'4\xed\xf4\xbbP\xe5\x06(\x8e\xc3x\xad\xdf\x8dr\xb2Y\xd1I[\xba\xdd\xbcp\xf5~]\xaf\x8f\xc8*\xd79Z\x0eA\xd0\xb1\xf3C\xd3\x01{\xf89\xef\xb02\xa29\x07/\xb2\xcd\xd3E\x0b\x92t\x01\xf3\xd4X!\xda)\x84\xcb\xdc\x99\xf2\x91\xecg\x0f\x99\xba\xbaX\xd4(m\x14V\xc2\xd1'85\xc3\x86\xe2\xb2j\x11|Adh9\xe1\xb3\x92q\xc5\xe1Ds \x0f\xad\xa8\xaa!\x83\xcc\xef\x18Q5\x1f\xfb.H\xdc8\x12\xf9\x0c\x1e\x1c\x88\x0f\x06\xd9\xe0\xd4\x87\x00l\xf1\xf2\xe3\x81\xfb\xabr\x06\x87\xb4\xa4\x1a^\x9e\x8e\xb4S\xb0I\xffz\xe6G\x82\xf1\x08\xbc\xf4\xd1@Z\xf2\xe7\xc7\x91z\x01\x92\x14\xf3T2\x95-\xe1~\xcaR\x99\xecb\x81^i\xeee\xc2\xe35fO\xe5&\xce\xa25\xd4$\xfd0\x8cW~\xe0\xb3H\xfa\xd1:S}`\xa9\x0ciD\xb7\xb0VU\xb9\x84q%tI\xc1\xbc]\x14\x07\xf1\xf6^z;\xee\xa7\"\xa4\xa9\xf4\xe20\xcc\"_\xdc\xcb\xb5\xcf\x99\x82\xe1^\xb2u\xe6a\xf5\xec\xa7\xccO\xa0\x1e?J\x85/2\xc1dH\xf9\x0d\x13~\xb4\x95i\x1cd\x08\xd1\x9eb\x81T\xae(\xdfR_=\xc4\x99\xf0\x7f\xca\x98\\\xa1\xa20\x95j\xfb\xaedf\xe9\x05\x8cF\xf8\x10\x8b\x1d<\xc4a\x92 \xc6\xe5\x9a\x85\xb1\xc7\xa9\x90k\x9f\x86q\xb4N%\xf4\xdf\xf7R\xb9\x8b\x83\xb5\x1fmS\x19\xf8\xdb\x1d\xb4\x9fP.\"Us\x12d\xe1\n \xca\x92$\x80\xber\xeaC\x13{\x16)y4\x95\xd4\xa3k\x16\xdeK\x8fr\x06\xd0\xc4aB\xa3{\xe9\xf1\x0c\x06{\x1d\x87\x007\xbbK\xe2\x94\xad\xe5\x06\x9aI\xe5&\x88\xd5X\xc9-\x0d\x02\xc6\xef\xe56\xf3\x05\xe5\x00\x8e\xbf\xa6\xf7\xf2\xc6WX\x11\xc9\x88e\xa9\xa0\\\xc67~Do\xa9\xe4\xcc\xf3\x13\x96J\xce\"A\x03\xf5w\xef\xb3\xdbT\xa6;\xff&\xddQ\x89\xce R\x009\xe6B\xa6\xf7\xa9`a*\xe9\x96E\xde\xbd\\1\x1e\xf8\x91\xf4h\xc88\x95\x1e\xa0\x85\xf4\xe2\xcd\x861\x85/\xeb8\x95\n\x05\xa2\xadd\xa9\xa0\x82I\xa6z\n\xe03.\xe4&\x13\xab8\x9074\xdb\xb0H\x06\xd9]\xc6\xefeH\xfd4\x8ed\x18G4\xdd\xc90KY\x16\xca\x88n\xe3{\x8a\xb8\xa6\xa0L\xa8\xcf\xd5\x1f\x80)\xf6|\x1a\xe0\xa8\xdeKA\x85\x88c)|\x16\xad\xa9\x1a\xe1=\x0b\xe4\xde\xa7?\xb2T\xee\xfd \xa0\xeaO\xaa\xd0f\x1f\x03d\xfb\xf8\x9en\x99\x04\xccF4P\xa3\xbfN\xa5\xb7c4\x91\x9e\xdaw\xc85\x8d<&a\xd1\xcam@S5\xb2Y\xaa\xd0,\xda\xc62\xf2\xa3\x1f)L\xb4^\x0e2\xdd\xc5j\xd4\xe2\x80r)b5\x03\"\xbe\xb9\x8f\xa5\x88\xe3 \x95\xb7j\x8d\xca\xdb\x98\xdf\xa4\x922\x1eK\xca\x13*i\xeaS\xb9b\xa9\x90+\xff\x86\xc9U\x00h\xf9\xee\x9d\x1a\xdeDzA\xb6\x92^\x1c\xabU\x19'rCy(7~\xba\x93[\x7f#\xe46\xe3\x99\xf4\xa3M,\x7f\x8cW\xa9\xbc\xf1o}y\xc3\xd9Z\x064Z\xcb\xc0\x0fc\x19\xf8\xd1\x8d\x0cY\x94I\xb5\x18e\x18\xaf\xa9\x8ch\xc8d\xa2\xf06Q_\x938\x15\xf2\xa7$\x8e$\xf7\xbd\x9d\xe4\xd9\x8e\xcb\x94\xdd\xddK\xe1'\xa9\x1a/\xa6\xfe\x89\xe5-\x8d\xb6\xf2V-\xe7[\xff\xc6\x97\xef\xe2\x88\xa9%%W\xfeZ\xae|\x05\xf0J\xad#\xe9\xb1Xa\xb0Z\xaar\x1b\xef\xa5\x1f y\xe3\x872\xf4\x03\x191!\xe3(\x901\xdf\xaa\xe5/\x93l%\x15\xc0\x82\x052\x8bby\xcb\xd6\xf2\xee\xeeN\xde\xdd\xbf\x93\xd4\x93t-)\x93t#\xe9VR_\xd2@\xd2P\xd2H\xd2X\xd2\x9f$\xe5\x92\xa6\x92\nI3Io%\xbd\x93\xf4\x9d\\Q\xb9Z\xc9\xd5Z\xae\x98\\m\xe4j+W;\xb9\xf2\xe5\xeaG\xb9\n\xe5*\x92\xabX\xae\xb8\\\xa5r%\xe4j/W\xb7ru/W\n|\xe9y\xd2[Ko#\xbd\xad\xf4v\xd2\xf3\xa5w#\xbd@z\xa1\xf4\x14)\x94\x1e\x97^&\xbd\xbd\xf4n\xa5w'\xbd{\xe9\xbd\x93k&\xd7?\xca\xf5\x8d\\\x87r\x1d\xcb\xf5;\xc9<\xc9\x98d[\xc9\xb8d\xa9dB\xb2Ln|\xb9\xf9Qnn\xe4&\x94\x9bXn\xb8\xdcR\xb9]\xc9\xedZn\x99\xdcn\xe4v+\xb7jb\xe56\x90\xdbPn#\xb9M\xe4\xf6'\xb9\xe5r\x9b\xca\xad\x9an\xb9\xbd\x95\xdb{\xb9\xbb\x91\xbbP\xee\"\xb9\xe3r'\xe4.\x93\xfeZ\xfaL\xfa\x81\xf4C\xe9G\xd2\x8f\xa5\xff\x93\xf4\xb9\xf4S\xe9\x0b\xf9#\x93?\x86\xf2\xc7X\xfe\x98\xc8\x1b&o\xb6\xf2f'o|y\x13\xca\x9bH\xde$\xf2\x86\xcb\x9b[ys/o\xde\xc9\x80\xca`%\x03O\x06\xbe\x0cnd\xc0e\x90\xca@\xc8 \x93\xc1^\x06j\xa9\xca\xd0\x93\xe1Z\x86L\x86[\x19\xeedx#\xc3@\x86\xa1\x0c\xd5\n\x96a\"\xc3\x9fd\xc8e\x98\xcaP\xc80\x93\xe1^\x86\xb72\xbc\x93\xe1\xbd\x0c\xdf\xc9\x88\xca\xc8\x93\x11\x93\xd1FF[\x19\xf92\nd\x14\xcb(\x91\x11\x97Q&\xa3w2\x0eeBe\xc2d\xb2\x91\xc9V&;\x99\xdc\xc8$\x90I(\x93H&\\&\xa9L\x84Lner/\x7fR4M\xf2X\xf2T\xf2L\xf2[\x99R\x99\xaed\xea\xc9t-S&\xd3\xadLw2\xf5e\xfa\xa3Lod\x1a\xc84\x94i$\xd3X\xa6\\\xa6B\xa6\x99L\xf72\xbd\x93\xe9\xbdL\xdfI\xe1I\xb1\x96b#\xc5V\x8a\x9d\x14?Jq#E E(E$E,E\"\x05\x97BH\xb1\x97\xe2V\x8aw2\xa32\xdb\xca\xecFf\xa9\xcc\xeee\xf6N\xee\xa9\xdc{r\xcf\xe4~+\xf7\xbe\xdcGr\x9f\xc9\xdb\x8d\xbcM\xe5=\x93\xf7B\xbe\xa3\xf2](\xdf\xdd\x0e\x16\xab\xd3\xaa\xe6\xb47\"\xe8\xffoq\xbb\x1c\xfc\xa6\xbf\xb8\xfdy:\x9a>\x7f?0\xba\xcc\xb2:\x14r_\xcf\xe6\x8b\xf1\xc5\xec\xd1\xd5b\xb8\xf8d\xb4\xb8]L\x96\xc3\xdf\x14\nD\xf6\x897Ub4\xa3\xb6B\x94\x19\x96\xf3\xf1dh\xc5\x87\xe5p\xd6\xbf>i\xfa\xb48]\x9c\x0e\xfa\xd7'\x8b\xf5pqz=\xe8_c\xca\xb5\x13\x90\xbaJ\xb7?\xb9>E\xa5\xaej\xff\xf6\xf6v19\xbadsG\xad\xf6\x17\xd4\xc5\x8b\xb1\x05|\xf8\xe87\xbf^\x9c\xfe\xd3\xd5\x7f~\xdb\x1f\xc8\xc7\x9f\x80@Tg\xe1O\xbc\x0du\xc8\x11\xb3@\x8c\x0f\xaf\x03y\x12=\x1a\x7f\xe2\x81&-''Y\xb7\"\xdf\xb3\x80\n\x7f\xcfl\xb9\xcd\x81S\xc8\xa3/\xfa\x117\x99$\x87NX\x9a\x87\xd0\xd2\xf7\x19I\x9a\xa1\xb54\x7fF\x1cZc\xf3\x0b\xb1\xdf\x0d\xc1~\xba\x10\xf7vj\xd4E\x08\x81\xdb\xe4\x03\xe3bX!\xf9\x17\xa2_\"W\x87\xf8\xb4\x00$\xc6\x95r\xba\xe8\x9fn\x0f\xdc\xb7\x8fJ\xf9\x07\xa7\xdb\x03<\x1b\xb9\x80\x0d\x0e#%9\x1b\x90K\xd2\x07\xf2\x14\x95\x92-!?9\xeb8\xa6$\x9fs\x87w8\x976\xf2UU0\xeb\xaa\x84\xf4#pK\xd5(X\xce\x17\xb7\xcb\x06\xc1rG\xd3\xaf\xb3 \xc8\x8b\x9a\"-\x12\xbf\xa3\x9a\x8c\xfb?x;\x16\xb2\x83\x15\xb8a\xf8\x0f1_\x7f\xa90d#\x18\xaf\x023\x9b\xbfY\xa4\xcb'\xd7\xa6JG\x15E\xe6\xdb]\x1e5\xd3S\x94\x06tM\x7f2\x1dR\xec\xca\xdcb\xc94!\xfa]\xcc\xd2?\xc4\xe2\xf7to)\xf6\x1f\xf9\xefb\xa1\xad\xd3Z\xb2\x7f!\xbee4\x15\x7f\x8c\x98\xe9q\xa5\x8c\x9f~S\x9b\xcc\x9c\x92\xf5]\xe7\xf1\xce\x13\x89r'\xba,\xd7\xea\x82\xd3](\xce\xeb`~\xb6,\x1f\xac\xb6J\xf1\xbd\x1f\xe9\x9e\xa6\x1e\xf7\x131Cg=0\xce\xbd\xfd\xaa\x9c\xd8\xa5G\x87\x86\xbe\xa3\x89\xa0\x9d\xf1\x13\x86\x8e\xe7\xd5\xfa\x07\xfb\x00\xc7:@\x9fw89c\x13A\xdb\x1avO\\\xded\xbbA^\xc7\x82\x87\x81\x7f\x827&NL\x0f\x9aWQ\xcdW\xac\xf99\x91\xa7\x0d\x05\xbb\xa0\x92\x01\xf3\x84\xd9\xf1m#Q\xcd\xc09\x88$\n#P\xf8\x08\n\xf9Q\xf6\xcf]\x06\xef\x01\xc7\xbc\xaf\x8abS\xd7C\xae\xc2\xbe\x18Jv\x84-7\xf5=\x06\xc2\xa2\xc1\xa6\xb3T\xe3<\xc1\x8e\xc3q\xf6W\x98\xc5\x8fs\xe6\x87\x1ej;\x8e\xc2W\xb8\x7f\xe9Zy\xbe\x1f\xecX\x7fq\x94\xbb6R\xf4g\xfb\xc0\x06\x1f\x80A\x0d\x8d4\xce\xa7\xde\x8a\xfd-fT\xef\xd5\xba\xce\xe9\xeb\xf2\xd6\xaek3E\x0d\x00\x96\xed\xd8\xde\x83\xe6\xd88N\xd3\x0d\x82\xe74;\xe1\x0f\x87\xe2\xb8\x89\xef\xfd\xa6k\x93\x8dh\xf0'\xfe\x80E\x9d\xf1\x00\xf7S\xb9\xc2\x13\xc6\xc3(\x8d\xfb\xa8\x00\xbe>uY\xc3VX\x91\xad\xa2A\x1e5\xf9\xbf\xe3,a\xd1\x9a\xad?\x96\xedI\xc6;S\x99?\xf1.4\xa6tO'\xe3\x0dJ\xa2\"\xb6:\xf7\xb8V\x80\xacn\x9ak\x1f\xec\x90\x94}\xc3d0\xa5=\xed+\x10\xcc\xbdGM\x05!\xf4}G\xaf \x0f\\*\xd0\xb2qv\x9e\xfb\xf4~D\xc3\xe4\x02\xe21=\xeav\xcd\xea\xd85R\xbd6\x05\xed?tN\x8c\xbe\xae\xa8P(\xe7\xc3\x05\xd1\x07\xe7XU\xb5\x83\xa3\xf8\x9f\xcc\x12\xc2\x12\xf6#^`}\xcd\xa9\x1f\xf8\xd1\xf6\x87\x80B\xcc\xf6.\xe3S\xae\xb6\x8bl\xe4V\xd1\x97\x17\xb7\xdb\xe1zS\xf3\xeeAy8,Nb\xd1\x19$\xc7X\x1e\x01J\xef\xb4M\xe1Q\xd4\xe0\x1a\x87\xab\xe3i'/F\x8a\xfa\xda\x94\xf7#\xedh\x11c$\xf16?\xa5\x1a\xb0x\x92\xfb\xe5\x84\xbb\xc0\xf9`\xbc7\xbeeFd\xbe\xc4(>\xfd\xa2\xdbx\x1d\x8a\xeaC\xa3a\x1b\x8c\xc8<\x0fa\xde\x1b\x91\x1e\x04\xa4\x86\xf02\xea-\xf0S\xd1s\x85(\x9d\x973Bm\x9f\x7f@m;\xaek9?\xfb\x80Z\xe0\x93\xaeg\xdaZ\x8f\xbb\xbc \xcbm\xea8\xaf\xd4\xd1\x00;\xa3k?\xda\x9aBO\x1f\xd0pP\xa9\xe3\x99{\xf6v\"\x0c\xa0.\x93\xef\xf9\x03\xda\x12t\x15\xd8\x1e~\xda\xa9\x87k\xb6)\x0em\x15m\xdc\x85\x8aPA\xb1\xcf+\x81\x0d\x97\xee\x98x\xd5\x05\x8a\x14<\x0b\xacW\xb6\x8a\xcb){\xdd\x81\xa1\x1b\x1bF.\x89o\xaf)\xb0\xe1pP\xa8BG\x92\x9f\xb3%\xc4\xe7\x82\x87\xe9\xd2%\x8e\xd1@\xcc\x08\xe6<\x87\xf3\x85\xf9r\xa0\xa9\xd2\xa0BzrJa\x9fh\xc1\xad\x11\x04\x82\xf0\xdf\xb1\xaa\x835\x87\xe6\xcd\xf6E{\xfb-\x00\xbee\xe2\xfb,`)\x1e\xa3\xa3\xa3\x04\xec$\xbaH\x10\xe8\x10\xe1dzA(\xb9\xd4GHl\x12\xf8\x91j\x98\"Q\xbd\xf1\x93\xaf\xc2D\xdc\x7f\xebG,\xedS\x08m@\xc9\xcb+\x12\xa1\x17\xfe\x93>\x9b\x88\x1fv\xfeF\xcc\xe9\x12\xae\xdb\xac\x82\x9bo\xa25\x8b\x84\xfb\xfa\x13\x00\xccq\xe0\xe1F\x08\xd4\x12\xcf\xf9Ru\x91\xc2\xf1\xe6\xc9tpA\xf8p\xe8\x90\x130\xea\x85\xf0\xb7;\xa1`\xcfF\x84M\xfc\x14@4\xb0[\xbe\x90\x19\xb9\xaa\x8f\x9dQ_\x07\xa6\xa7y1\xda\xa86W\x8da%#2\x1c\xdaAB\xaa\xa1\xb9RB9\x8b@\xe8\xad\xd7\xda\x12\x0e&\x1f\xe7\xda\xe7\n\x9f\xcaq\xa5\xcc\x0420S]D\x0bQ\x8b%\x99\x82q*W\x1f\xb3\xb3\xb3\xcf\x9e/\xe5|\x91\x9d?;\x7f\xb6\xc8\xce\xcf\xce?\xd3\x89\xd5R\x01\x94\xca\xce\xce\xe8\xd9i!,X\x111\xe1\x8e\x91\x03+G\x84W\xc7P\x81\xe8#\xa2\xb9<)\x03\x02\x94\x92\xe1>>\xb3\xc7\x02\xd5\x9b\xf3\xc0\xe55\xab7\xc2I0\x02'\x10\xb98\x9b\x8eHo\x11\xa9\x14\xabU\\\x88\xde \x8f^W.\x9f\x15\x18p\x93Z\x1b\xd6V}\x0e5\x94\xd3\xb3\x82p\xf2e\xbcf_\x88~4 \xd7:,,F\xf9\xf3t<\x14\x08\xfe\xa6P\xbf\xa7j\xe8i\xda\x00\xee\x85)\x19\x13o@\xfe\x89<3\xc7\xb5\x90\x08\xc5y\x95z\xe8\xd5\x8c>\x15\x99\xf1\x07k\xe6\xc1\xdc\xab\xd54\xa4\xef\x8f\x14q\xf3#f\xfe\xbe\xa2w\x05\x024*\x05\xb4Al\x1fz\x1epZ\x86U?@e\x18kM\x9a\xeb\xae\xae\x96\xab\xdf\x8a\x00\x9c\x0dj\xa8X\xac;\xdf7\xfd\xaa\x0e\x08/\xbaUD\x1e\xd6\x1a<\xa0\xb8Y\xc7\xfa\xe7li\xd5`(\x11\xb0\xa5\xa2\xbc\x85.\x14=\x9f\xbd\x1f\x95\xda,K\x1a\xadM\xd7]\xda\xeb\xfe\xa2(\x87g\x8f\xfdC\x90]V\x00\x1b\xa0\xe8w\xe1\xea%k\x83\xfa\x87\x84zGC\x9cr/\x978\x0d\xd0z\x15\xd9\x0c\x85%\xc8\x1e\x0c\xde\x97;\xca\xd3C\xaezKn1\x9d\x00F\xf6\xe4\xa9\x06\x19\x02\xfdA\xf0\xfd\x96z5w\xc2\x0e\x86\x0c\xd2\x1f\xb9\x04\x97\xf8\xa6n\x07\xdfP\x10\xbf$\x91#b/Z\xaa\x9d4\x0c\xf2x\xccr\xbb\x04\xa6\x96\xedq\xdd\xd92Q\xc7\xdeV \xa9j\x19\xa98]],b\xb0\x8c\x1a=\x14\xa9,\x81\x82\xb6\xe2\x92\xd4/\xaf\xffy\xa0V\x01F5\xf0\xf1\x10\xce,\x87`9\x02\xb7\xad\x8acpr]Z\x19Pjj\x1c\xc1\xdb\xc4Q>\x82(\xc7\xa8~\x0c\x1c\x93\x91iQ\x05|\xb7\xf6\x05\x19\x83\xe1\xac\xf6 \x1a(\xd4\xbf \x81\xa2\xbc\xf1p8\x80\x88ne\xc8\x06j*Ax\x03&?\x18\x01\x07;\xb3)gZ\x1c\xaa\xf54\xc5\xfe\xe0\xc8\xa8\x15&e\xf7\xcee\xf3xY\\\n\x8d}\xd4c\x9d\xd5}UUD+\xb4\x8d;J\xb42\xa9\xee\x90\x83\xee%b\xf6\x82\x0e,2c*\x96j\x12\n\"\xcd%y\x96\x9b\xe3L\x1ds\x18\x03^\\\x81\x8f\x9a)\xee\xdb\x9aVW\xbe\x03\xe2j-\xb9x~\x8b\xdd\x1fl\x02rHy\x15\xd2\x97W\xe4Y\xfb\xc6J\x81:\x1c\x1er\x06k\xf5\x9cZ\x86\xe3\xa3<\xf6{C\x8c*\x1d\x8b\nUf\xb5\xaf6\xe6TN\x05\xd4\x96\"\x1e\x91g\xe0\xe8\xc5va\x04[\xd2ZyP\xc2\xb8\xaf'*\x10\xd3\x19\x99\x8b\x91\x86\xd7\xa1<\xd1\xe1\xab\x18\xca\x8c\xa5\xcf\xef\x95\xf0\x96\x8bI\xef\x7f\x194\xecN\xdf\\\xc7F\xe8|C/^\xb1\x84\x11\xb3\xc8Z\xcf\xbe\x81\xec\xccd\xaf\xa3\xbaG\x86\xe4)yI6\x8dh\xadrM\xcf_\xa0\xd7\x96\x18u\x1def\xe0\xa1\x82\xe3s\xcc\x13\xb7\xd6\x04\x92\xf7\x08%\xe7\xbeg5'\xc0\xda\xfa\x9e\xda\x03\x0d\xc8\x98\xa4\x03rI\x9e\xb6V\xa45\x159\xc5\x01C\xf9\x89\xe0~\xd8/\xeej\xff\xac7\xb5\xad\x95\xf1\x82\x8d]\x03a\x16\x17\xe4\xa4?\x1cf\xa8\xd1A\xc1 :\x90\x16g$+\xcdH\xb6\x04\x9b\xbe\xd2$\xa84P\x7f\xd8<5]P\x03\xb5\xa8\x8d:0\xb1\xb8\xa2[\xca\\\x84\x00\x04\xf8\xe6\xd1\x06\xe5R9\x0b\x8aj0\xb5\x10\xb0\xbe\x81\n\x01\x9a\x9e\xb9\xe9\x0b\x90\x9en\xd4\xc5\x87vs<\xce\xc9MF\x86\x8ae_\x03\xeb\x81\x93\xbfn\xc4\x07\x94\xf1\x0e\xea\x93PN\xc3tFhG\xc2\x84\x8a\x85\x0c\x16\xa7\x93\x1c\xfd{\xa29\xf5\xb0\xbb\xc7Q\x9b\xf0\x10\xb5\xd9\x93\x97$l]\x89/\xce\xb5\xb1[\x05\xdb\xf7\xc3\xe1\xa0\xb5\xa0\x1e\\\x85\xeey\xac\xdf\x90\xde\xfd\x81\xa5\xc2\x8f\xb6\x1f\xb2\xfc\xf5f\xa3\x0e\x13\xac\xe4\xbd\x92\xc84\x11\xc8Y\x17\xab\xeaA \xeaaa,\x01\xc9\xf3\x91\xbd\"{\x14\xce X\xed\x9e\\\x92\x10\xc2\x11\x15\xd6\xe2~@fd\x0f\xd4,D\x81m^\x98\x0d\xa8/\x17[T\x1d\xe3b\x0b#\xcd\x0bP-TS|\x17\x8e6\x8cO)\x94`b\xb3\xa39\xe9\xf7K\xe8\x10\x97\xd0!^\x02`\xfd\x12\n\xc4\xcb\xc1\x00\x03\xa09IZ\xfb\\7\x8b=~\xabXc\x03+\x9fLGpW\xe7\x0c\xaf\xa6l\xec&-!\x97d}A\x92C\xb1\x0b6\xf3d\xa9/eE\xb0\xfa\xdbt6\x04\xaeA4SC\xf3sSE\xf3k\xf6\xd0\xb5k\xedtf\\\xfd\xdb\xc9Q{\x14\x93\x98\xcf\xd1\xa88c\xa0A{\xfa\xf4\xd3:\x8dF\xc1\xb3\x03\xde;\xdb-\xa2\xc8\xf1x}\x18\xe8\x12f\xc7K\xc7\x8a\x0dH\xf9\xc0aT>~\xb8\xaa\x9c{v\xe4)y\x99\xa6\xa0\xc1\x9a\x19@\x84g1\".wue^P \xed\xfb~0\xca\x97\xa8\xd5K#\x11\x8f\xbb3\xbf\x02\xa0M\xf1om\x9c\xdb&\xa6T\x190\xc5\x1b\xe6\xd3\xa5=\x1d\xd2K\x0b\x17\x13\xcd\x97\x16F\xac\xd6s\x93\x90!\x01Z\x94\xcd\x93\"}\xb2\xe9t\x9e,\xdd\x8a\x83\x12\xf9L\xff.xd\x99\x17:\x0cJ\x0eq\xbf~F\x86%9Gm\xd8\xd3V\xce\xf4\xec\xbcE\xee\xce\x80N>zD\x9e=G\xc9\x1b\xa4\xf0\xe7\x07\xa4pX jEN/HF.I\xea<|\xac\x88\xd8\xb5Vm{O\x11B\xda\xd8\x1e\x01\xbfrVT\xf5\xab(\xef\x9a\xfe\x93\xbe\x8f\x1b\x80G\x8fH\xff\xe4\x84k\xbb\x10-\x13j\xa1\xac\xe3b\xd8\xf1\xe6\x85\xfaaR\xdb\xa0z:}\x14N\xda\xe4\xcai\x90\x0b \xf5\xf9\x90s\xa9\xf4y\x9b\x90\x86\\9.\xa3\xe6\x80\\\x93\xb1\x12\xa8\x0dzE\xae\x89\xe6\x15\xf4\x02)\xe0\xd9S\xfd\xack\xe0\xe4\xb2\x84\x07\xf5Zlc\xbc0Z\xf5\xce\xc7\xad\x9d?N\x0e\x8d\x0f\xadD\xf0\x83\xa8F&_&c\xd7\x1e\xb3e\\.\xc9\xb3\xcf\x14ZF\xe4%y\xfeic5\xa8em\\b\xbc\x1d\x08b\x15=m\xa0\xa8\x1d\xdegj\x0e\"ry\xa5\x80i\x13\x9e\x9e\xa1\xee3R\xb0?{a\xa2\xa6\xb6\x88\x16\x16\xb4\xda\xd7\xa6\xe3\xf7B\xa9\x07\xa2\x87yj\xa7\xd7\xb534p\x87\xd9\xb2\x9b\x19)\x01c;\"\xf7#\xb2\x1a\x91\xb7#r;\"_\x8d\xc8\xdd\x88\xfc0\"_\x8e\xc8\xcd\x88|\xe1\x10\xe1\x00\x15\x94\x08\xa9q\xd4(\x14\xb6\x8e\xbc\x0d\x1a;=\x89\xaa\x12^\xaa\xa4\x95lB\x03\xd3\x96Q\xfe\xd0\x8dO\xe8B\xaa\xb5\xbe\xcf\xed\xb7\xef\x8aV\xb8gG\x12l\xace\xb6\xe4\x1a\xef\x017\xafV\xd8T\xa2\xffj\xad\xd4\xd07\xca\xd5<\x911I\xf0~fg\xfa\x1e\xf35\xe3l\xfd6\xf0S\xd1$\x97A\x9e\x19\xd972\x82\xdb\x87KlJz\xed\x08\xea*\x0b\x02&Z!\xfdpx\xac\xc9\xd2[\xbd\x07\xbak\xdb\xf7\x81\x81\xce\xe0\x82\x9c\xf4O\xfa`\xb6\x836\x98\xb0\x81\xea\xdfW\xd5AkD[K[\xe9Rkf\xee\xc9\x98\xac\x958\xf3\x0cX\xb6*\xadPhG.\xc9\xb4\x94\xa2\xa4\xa8uQ~\xa7\n?v\x9dg\x1b\xc6\xce\x17,<0\x80_}\xc8\x00\x06\xd5\xdd<\xea\xc5\xc0H\xc1\xec\xf5\x0b\x08\xbdq\xec6\x8a;\xf1\xfb\xeaN\xbc,\xdd\x82e\x965\x808\xab\xefU\xb4}`\xd3\xc6\x00\xf7\xa6y%j\xaf\xfe\x16f\x11\x88\x99\x1a\xf5\xb7Vn'c\"\xc8K\x9c\x14\xa7=X\x15\xba\xa0\xda\x9b\xb4\x08\xaeW\x83v\xf3\x80\xa9|\xf0&\x050\xbd\xb0'\xf9\n\xb7(tD\xee+\xd2:\xd1\xa6xj\\\x8a\xa6g\xf8~\xbc]\xde\x8d^\\?\xa0\x82\xe1KrE\xee\xec.\xe8\x07rI\xbe\xbc ?4)\x18\x14\xe9\xbd\x9b\xffP\xb4\xe3kW.\xdc\x1cP,4+\x15\xea\n\x05\xd5\xf8M#\xc7W_\xb7m\xf2C\xce\x08)HAg\x83&Eo\xeev#\xe7{\xe52\xee\xe6C\xb7\xa4\xb0\xd6\xf7\xf6\xeb\xad5\x1cXuAB\xc5\xaf\xca\x1c\x04q\x91T\xa8\xf5\x831\xf4\xd6bdn\xc7\xa8\xa4\x8cG\x8f\xda\xcd\x0cHY\xf2G\x1c\x07>?$\xe7\xf5q\x03\x9c\x8c\xf4\xde\xe8\xdc\x08\xcc%\xe6L\xc6\xe4\xbc\x14\xb7\xd3f\x98GKcAevi\xb9\x851\xd2Y\xad\x08\xca\xf3\x0bm\xc6\xd9\xcf\x13U\xcb\xcb\n!+\x14(\xa4G\xe8\xd8\xbc1k\x97\x82\xa1\x7fO\x9b\x8bv$\x08\x99\xb6g\x1b\x92sT+\xf43\xb3\x0b\xf4\x14\x17x\xfe\x99{\x08\x87\xc3lPVDd\xc3\xa1\xc2m\x16\xed'\xe6VCjn\xae\x94\xd2 \\c-\xeb\x84\xb3\x8d3?~\xd0\x85R+\x9a\xe3\xf1f\x80\x0b;S\xcb\xb8\xa1\xcey\x0f\xae\xf0\xa6Km\x1a\xd9\x8d\x04\xda\x9b\x19o9\xdb0\xce\"\xafY\xbdIW\x8a\xda9\xe2\xe1\x1f\x14\xa9\xe2*?\xae\x1d\xf9\xd1\x03RTI\x10\xcd\x06d\x8c\x82S\xf1\x08%+\x0b/\xc3+\xf2\xac.M\x15.\xa2\x14\x1b(1~C\xd9\xec\xd7\xe1U\xedx\xc7\xb6;.}k\xd1\xe0\xe6\x82Z \"Z\x86z\xac\xa1.\xf6\xdd\xaf\xf64\xfe\x90\xd9}03SR\xca\x07\xe9\xbcL\xea\x07Q\xe7\xe3\xe8\xf2A\xad,\x9c\xe8\xb7ka\x9f>o\xd3\xc2\xe2\xb5\xb5\x03\xd5\xe4ZW\xb3\x16\x1cd\xe6\x82<}\x9e\xf3`P\xce\x82\xca\x94\\^\x91\x17\x17\x03\xe2\x83\xf1Wci\x17\xd5;\xe9\xfb\xe4%y\x81\x10\xea\xfa\xb4.&.S\xb5\xd4\xae1kg\xd8OG\xe4\xa9\":\xf9\xcd\x90\xfa\xf7\xe7\xea\xbb\xda\xfae$7\xcc\xac\x01H\xf3\xcb&`=?(\x08DG\xeas\xf1:W\x13\x8d\xda}\x8bX\xec\xb8\xc9\xfd\x11\x94\xbev\x0c;\x02\xebG\xaa\x9dv+\xa8\x9c\xc6CH\x1fm\xc2r\x084\x18\xb3\x07u\xd1\xdb\xf9\xc1\x1a\x1ci\xcd\x97\xb5\x0ev\xec\x97\x99\x84&R\xd26\x0b\xbf\xacZ\xdd\xa4>\xc4\x12pd\xee\xe1\x88F\x8bV{\xa7K\xcb\x10\xcd{GG\x86\x8aa\x8e=\xe0\xe8\xf7K\xec\x91\x96\x88\x1a\xd5:|\xbfH\xc8\xe8R\xcb$\xfdg\xcf\xf3\x8b\xb8\xb5U\x17#mz\x81:_\x8eE\xe2\xf2B\xee\xc7x\x17\xc6BQ`\xb31l\xd7\xfcb\xb9F\xb5^\xe1>\xdc/\xb0\x9cM\x17\xb4\xbe\xe9\xfca\xa8\x7f\x00\xf7:\x82|\xdc\xa2\x06V\x9d\x1f\xbd|\xdc\xe5\xad\xa8\xea\xbf\xf2\x12\xef03\x87W\xfc\xe0# \x16\x85;\xdfg\xe7\xd5\xbb\xdd\n\x81O\xdf\\\xf6\xe7:x\x9fvu=_\xa4\x8b\xd3\x97U\xd7n>f^\x9c:\xb2\xbf\\\x9ev#4#B]\xb4&?\xa0\xa8H\xc5\xb5\xa1\xab\xd8o\xd63$e1\xba.\xbbxJvMF\xe4$\xdf\xdc\xedD\x18\xb4\xca;\x89\xa2M\x8apx\xb0[zyu\xc0<\xf4\xc5\x99{\xeb\xe4\xb5\xef<\x9f\xe2\xa6\xae\x9f\xb9H\x97\xa7w\xae\x8a|a\xbe\xaci_Y8{._rz\xdfv\x1c\xf3\xecS\x00\x1a\xa4\x96\x93\x96\x1b)\xe6g.\xa5<='\xb2z\xf5\xc0\xfc4\x18`t\xf9\xf9\xa7\xaaf\xa1d\xb7\xe9\xf9y-\xfb\xfb.\xdb\xdeg\x9f6\xf7\x9c\xd8c\xa5\xeaV\x11-a\xd1\x95\x9e?(\xb6R\x87\"W\xd2\xb5\xd7\x13\x0f\x0eC{\x82h\xc0\xe7\xe9|Zq\xd6\xb7o\x0b\xd5m\xfcm\xc6\xa1U\xb5\xb3e\x1c\x9fx\xa8\xfe\xee\xa6\xf0\xef9\xfc\xfb\x14\xfe}\x06\xff>\x87\x7f_\xc0\xbf\x8c\xae\xb1\xd4\xce\xc2\x03\x1e2z\xfe\x86\xd3P\xbb\xc1P\xff\x86\x14>\xc6\xe0\xd9\x0f\x9e\x00\xd28\x13I\x06\xef\xf09A`\x12\x1eo9K\xa1\xf3\xe8b\x12\x9e\x98g\xe0N\xc5=\x8e\xa6\xf1\x11\xd1\x13f\xd8\x04tY\xb0;A9\xa3\xf0\xbc\xc1\x0b\xaf=\x01~'\x04\xc7gF!g\x06p\xec\xfd5\x8b{\xcb\xc9&\xe6_Qo\xd7o\xb9\x808g\xcb\xf2\x0dP\xad\x95\xfa\x90\x1b76\xb9\x8b\xf9\x8aCr\xcc\x95)\xb5u\xc0\xdb\xb6\xecv\xf9\x16N\x8e\xc1BdL\"\x97\xb7\x88v\xf6\xdc\xf5\xcau\xd1\x8a\xa0\xce\xc8\x04\xb2\xc9\xc2];\x17\xbb\x0bJ[]\xe4\xd8Am\xd7\xd0RA\xbf\xa4\xfa\x08J\x12x\xb0,\x9f\xcc\x06\xcd\x14\xd7\x87\x0b\x1d\xa80\xd6\xbb\n\x87J#\xb7\xfb\x81\x1b\xbfZ;\xea\xb7\xd6J\xady\x030\xef\x1199}3\x1f\xcf$Y\x0e?9EW\x9b\xb4]$\x80\x1b\x08\x14C\xa9\xf6{\xb2\xa7\xf6\x1f\x10\x03\xb5M\xad\x92\xe8\xeb\xe7)Z$\xa6\xe4\x92\xe472[no\x9f\xc0\xb9\x947O\x97\xe6\xdaH\x1b\x9fE\xff\x05\xa0\xb8M\xe1\xd1+\xb9W2\xd7\xb2[\x05\x83\x83\xde\x98\x89\x01\xed\xf4\xcd\xecz<\x9c]\x9bq[\xb7\xb3\xdf\xe7\x9f\x01H\xeb\xd2\x81Y \xbek\x92 {se=S\xdf{\x18b\x0b\xce\xbe\xb8\xbf\xdd\x89\xde\x80\xcc\x9c5\x9f\x15\xaa\xeb\x05l\x839MB\xaf\xed\x06\xb7\xea\xdc\x18w\x0c\x05tq\xdc\xdb\x81\xb9o\xc1\x14D\x14\xeb\x9d\xed\xcdB\xca\x85\xfc\x04\xfc\xb3\xf5\x06\x05\x04\x1a\x91\xc4\x8c\xc3Ia\xd2Z\xeb\x8e\xdb-_:\x8a\x0b@\xe8\x0f\x98)\xec>\xc4L\xa1+\x1c\x8ao\x1c\x80C\xc1\x00\x8b\xf6\x97\x84\x83\xff\x92@4/\xfe\xae\xe0\xed\x9a\xc0\xa3\x81\xbf\x8df$\x99\xa7.\xc0>\x02\xec\x1d!<\xacw(\xd0\xb2\x8f\x00\xe9/\xa3W\x10\xbb\x87\x1e@|\xc0R\xe4\x0fm\xf3\x88n\xa9U\xf6\x8b\xb7\xa2d\xc6\x03\xcbh\x0f4\x05\x8f\x0b\x1fDW\x8c\xa0r\x8e\xdb+}\xfb\xa7Efy\xf4\xc88)\xcfiz\xe0\xa6\xe9p\x83\xbd\xd1\xaa\xa6;Q?4^\xa4\x0b\xdd!\x87F\x83|0q!\x058\x1a\x8909DdHW@7F\xa0\xc9\xc3\xf3+Q\x0f\xc4\x15\x95\\e\xe2p\xabrD\x9a\xf2\xc0{Y\x8a\xa8$\x91Y1\xc5j7\x8f\x19\x97F\xb2F\x8a\xa4\xad!\x8a\xca!\x8aE\xda\xa8\x16\xe9\xb8\xf8Hi\x12\x9b\xd689\xb4\xce\x89\x83\x8a\x11\xd8\xa2to\xbe\x99\x90\x91n\xcd\x97W{\xe9\xcdn\xad\x8e E\xbf8\xc1\x03!\xea\xc1\xad\xec\xd0\xfcj\x8f\x7f\x82QI\xed\xf3a\xea\x13\x9b\xdce\x03\\\xb0\xe2\xea|r\xedw\xd8\x06\xc7j\xd3\xe7\x1b\x13z{M\xdf}\x18d\xees\xe8\xbd\x1c7\xc5b\x14\xc7#\xd7\xe9\x8f\xce\x12\x95\xda\x89*\xe3F~\x91}\xb6\xb5\xd6o\x15\xd0\xfb,\xf7\x08\x06\x96\x85\x8f\x1e\xd9\x89x\xe9t\x9d\xb7)\xee\xc3\x8d\xaep\x03\x05\x87\xc3\xcd\xc1m\xbc\x9d\xb3\xcdQ{w\xdf0\xc6\x8d1\x81lm\x03\xd0\xf9h\x9b,m\xa7\\4\xfb\xeb\xbc\xd2\xd6\xc1\x01\xb9\"\xf8\x90\xbdJ\x866\xe9J<\xa8\xf8\xafc\xb3\xb6K2\xf0\xe9^\xdb\x0dn\xb5\xd1\xed\xa1\x1e\x91B\xaf\x1a-\xedIA$\xceF$\xfb\x10\xb6{\x04@\xdd\xb8]A\x03\xac`3\xd8Z\xf4\x8d2m>J$\x1d\x8f\x13I\xb7!\xf8\x98\xfcs\xddlKK\x0e\x11t\x82\xfc\xd3\x89'$_\x9d\x07A!\x05pZe2\x92\x8f\x8f\"k\xf3\x8d\x1b\xf9m\xd6C\xa8B\xf4x\xe1\xb5\x1b}\x9d`\x0d/\x86\x86\x8d\xf4\x89^a\xa6\xf7\xc5#>\xba\x1c\x81\xd2\xa0j)W4\xd9gE\x1f\x89E\xfb\x03\xd8\x12\x14\x13\x14M/\xdd\xc5\x18\x91\xf6\xab\x08\xb9\xb7b\xa7\x91\x1bu\xdfF\xd8\x82\x81\xd1\xbd\xb9\x8d\xb0\x05\xb0\xf4\xf15=x\x1b\xa1\x08\xee\xbe\x08`X\x83oW\x1d\x8adT\x1e\x8du7d%%\x0ciCX\xd2\x05i\x89\xd9F\xa0\x18\xb2\xb1\xfdW\x02\xfb\xcb\xfc\x02^\xd3\xb1\xe2\x01\xb6s\xb0\xac\x83\xf9\xb4\\\xf8\x03\x1a]_x\xb5\x14\xe4\xa5/\xdb\xee\x0f\xfa\xda-\xf0\xa6\xc8j\xb3f\xb7T\xa5\x8e\xd6<\xe3\xb4\x95\x82\x8d'\xd0\xc9\xc1a\x90J\x17@\x1e=\"t8\xcc/\x88t\x01\xadn\xec\xd3\x06\x9a\xef\xbe\xfdP\xca\xfc!\x92\xf8:x\xb8\x80\x1ch\x94,H\xc6\x9b\x11\xb9\xff\xc7\xfd\x04\xe7\xfd\x04\xef\xa3\x1d\xba6\x8a\xcb-\xdb\x87\xe2\xfd\x04\xb7\x91\x9a\x0f\x1e\xb6.\x8d,\xaf\x8f\xc5\x07\x95s\xf1\xd4\x11=\xceZ\xf37\xde\x14\xcc}\xce\x0fP\x13\x12\xd5\xaaE\x9dH#\x19*\xe8\x90R\x971\\\xdb\x0d(\xeb\\O\xc9\x7f>^\xba\x82%o\xd51>\xb9$\xf4\x82\xf8m^]\x88\xa1Is\x1f._\xa5]._\x99_\xdc\xc1\xbb\x0b9\xe8\xe1\x858i\xa9\xf9\xe9\xcdM\xd7\xfb\\\x9aN\xe0j*\xda\x0c\xa4\xcd\xd2b\xbe\xd0\xd3\x11\xe1f\xf1\x15\x97\xca\x01rSYzu\xa2\x03K\xc9\x1d\xf5\xa8\x8b\x19DY\x8c\xaaQ\xac\x8eP\x1eV\x96\xf3CMw\xb4\xc1\xfb\x85\xec\xef\xf2an\"\xeem\xe3\xdc6\x86\x1f\x8d\x88\x1d\x8e\xb0r\xfe\xf4\xb9#\xc0J\xd4?\xff\xb4\x92L\x1b\xe2\xae\x08vgbc<\x9d\xba#wD\xec\x16\xa7\x1as\x9d\xbbs\xb1\xd4\xa3\x89\xcd\xf4\xd4\x9diE\xbd\x1b\xe1{7&\x8a\xcb\xd3\x86`!k\x16\x98\x1c\xcf\xdd9\xfc\xc8\xd6\xf1\xc2\x9d#\xa4\xdc\xc4\x1ay\xda\x10Q\x86\x85\xc9\x8e\xa6\xbe\xad\xe93w\xb64[\x99\x1c\x9f7\xe5Ht\x8egg\xee\x1c\x81\x1f\xd9^?k\x18h{\x95\xc4\xac-\xcc\xdd0\xe0\xc5\x8b'&k\xc3\xb0S\x1d\x1e\xc8dk \xd1\"\xa8 \xe4\xf2\xaca\\Y$|qo2}\xd6%0J\xf6Q\x02\xa3\xe4^\x90\x9c\x81Q\xa8 \x8cB10JE\x11\x0c\xd9\xf7\x18\x81\x99}\xebG7\x8a@\x17\x16i\x1d\xea\xb4n\xe9\xb3\xb7\x81t\x91\xd8\xb7E\xcc\xd5\xbc\xc3\x1c\xc6\xabb\xbe9z\xf9J\x8d\xa1\xafXI\xf1\xf8f\xd63\xf1hU\x89\xb9\x0d\xa6\xdb\x1b\x15\xe3\xed\xf6\xc0H\x0bM\x9c\xd6T\xd0\xde\xd2\xd6 \xcc\x11\xce\xac7\x98\x9f-]\xe6:Y\xc5\xe7\xf5kE*[=\x86C\x9fG\xc6KLa\xd4KQ]j\x88\x02\x8ez\x8d\x8e\xac\xf6\x15u\xafI\x9c:4y([y\xd4\xdb\xb1\x7ff\xa2\xef\xc3\xe5\x97\xb3\x01\xe6W\xe8R\xd1o\xb9MP1l\x03b\x8f \x97$\xbe \xa2Mx\xe2s\x01\"\xcbI\xc1g\x08\x04\xe2\xd2\xa0\xfc\xa0@\x19!\x10\xce3\x86$N\xf1\xdeb={)w>\x17\xefG\xa5\xe90\x1b\xfd\x8e\xfe\xdb\x0fNIy\n\xf2!G\xf7\xf40\x98\x97\xc4o\xd6\nF8x\x91q1s\x02\xc3\xc9\xe7\x11\x8e\xd3t0\xc0}\x84{W\xd6\x18\xe8\x187z\xaa\xf5\x97`\xef\xd4z\xbb\x9dM\x12\x16\xad\xfdh\x8b7\x04S\xee\xcd\xf5H/\x1b\x06\x95\xe0d\xe8R\xa0\xf7P\xe4\xe1;L\xe8\x0f\x9aF\xff\xd8\x802\xcdaO\x1ct\xc7\xeap\xfcF\xa7\xdc\xd9\xaf\xc8\xb1bB\x9dd\xf1:\xc2\xa4\xb7\xbe\xf0v\xc4mw\xed\xd1\x94\x91\xe9\xd9\xcc\xfd\xe1\xf3\xf3\xa6\x0f/\x1a>m\x1a\xad\xa7\x9f65\xdf4(\xd3\xf3\xc6\x91o\x82\xebE\xd38>w\x8c\n)\x98\xd29vbk\xb6\xa1Y \xda\xcb5\xf9S\xeap\x94\xd5H\xec\"\xcb.\x80\x1c\x192\x06T\x89\xd7]7G\x83\xc1\xc5@\xd1&'G\x8e\xf4e\nE\x82\xd4\xb6L\xe8\xbb\xe2UJ\xa3\xad\xf4!\xa3Z\x87\x83Q\xce\x82\xca\xf6\xe2\x1f \xe2w\x1e\x8b\xaa2\xc8\xc9;\xa7\x0d\x17E\xe2v[?=\xbc\xd8\xff\x82\xf1\x81\xd1#\xe1h\x8f\xc8\x89p;\x9a\x85\xd3\xcb\xb3\xd2\xf5TSYyV\x9c\x88ck\x98\x1e\xacA\xbb(9\xa0\xc6\xb0\xf4\x19U^>\x9eS\x12\x7f<>\xac\xb9\xb0~\xd4\x1c\xcd\xfb\x9d\xd4\x189\"\x15\xab\xc9\xedE\xce\x14+\x1e\x92iC\xe8\xd9\xe2\xefC4\x1d\xec\x90\xfe\x9d\xe4[\xe1\x1d\xe5kh\xabE O\xdaw\xbd\xc5\xdf{\xf70\xd7Xzi|\n1SG\x87\x81\xd7\x80\xa7\xf1F\x1c\x02\xbc\x03\xd0N\xa3\x11\x0d\xeb\xc1\x13\xb7C0\x1ch\xdfiv\x17\x0f\x87\xe8\x19\x9a\x93\x96;\xdf\xb1\xa2rq\xe3\xfd\x1b$U\xf1\xc7RF\xd8\xa5\xc5\xb59\xb8\x0e\x9c\xa2\xc0<\x7f\xfe\x02\xfdP\x13\xbd\x19;+\xf4\xaa\xb7X\x9c,z\xbf\xfe\xe4\x9f\x1e=\xee\x0f\x9e\x0cG\x93\xd3\xd9\xc5\xe5\xd5\xcb\xeb\xdf\xcc\x97o\xde\xfe\xf9g\xf9\xfe?\x8f{f\xe3\xd2\x1bt\xbboQ6\xb4Z\x92\xabb$\xa9\xca\xe5\x8b.d\xd5\xd2\xd4\x96\xad\x8a\x92\x9bk\xa4\xf3\xf3\x06\xbf\x8b\x07(\xeep\x18\xe3\xc5\xdf:j\xf9\x8d\x8e1\xf1\xb6\xf0\xf9\xf3\x17\n)\xcc]\xb0(\xbf\x88\xd0\xc4\xc8\x8c\x8fg\x85\x10\xc3+r>r2w\xcd?\xb4\xc3J7\xca\xebM\x15\xf8\xf4\xea\xb6B\xbb\x90\x96N+\x14\xa2\xf2 \xb6\xf9\xc7/\n\xf3k]\x1c\xb6\xb1_5\xbf5\x0fuo\xb1\xe8\x99aV\x1b\xc1\x8f\xb3\xea\x8eE\xe4\xd29F\xb3\xa0\xa0c\x89\x1c\xe3*\xc8\xee \xb3\x11\x01\x0f=\xbc\xb4\xa1\xcc\x0c\xb5\xfa\xfcE\x93+\xa1\x8b\x81*\xe8\"w\xa4,rE\xe8\x12\xc3\xd7\xc1_\xb3\x0b\xb0\x84\xac\xdc\xa7)D \x81\x93\xbf\xe6\x8d,\x85sx\xb8\xceH\x0fAIU=\xd4\x85>>\\\xc0\x19+\xa8\xae\xf2\x00\xb6\xe5\xc5\xd7\x85_4\x84\xed!\xa4\xd9i\x85_\x08\x93?'\x8bh9\x04\x93]\xd2k7Q1\x91|\x9a,S\x0e1\xa6\\\xde\xa5\xb5u\xd2uU\xc4E\xca\x93G\xfd\xfd;Z\x1cJ\xb2\xadu>m\x91\xb1\xcf\x1b\xd6N\xdaN\xf2\xdb\xed\xd7R\xf4^\x06w\x91[\xb257\xfe\xcb9\"\xf3u \xce\x94\xbc$g\x18\\\xa0\xda6\xd8.\xcf\xc0)\x96\xd3\xa7\xb9\x82\xee|0\x02\x03\xca\xab\x83\xd7\xdcL\xaef\x9f\xe7~\xee\xed\x8c*\x9c\xd3|\xab\xb9\x00\xd0\x01\xaeC`\x9ec\xdc0\xb8\x99n\xda\xaa\x81\xcc\x15!\xa8\x05\x0d\xf3\xd1\xa74T\x93\xc7O\xb2\x08\xce\xc9\x98\xa4\xa3FF\xacWt:\"\x1c\x0f\x89\x1c@\x9a%\x97\xe2A~\x8c\x8e\xe4u\x0b\x10>.k\xf4v\xdd\xd8\x19TC\xb6\xf6\xd7\xb6\x80\xceH\x9c\xf7\x161\x0f\xda\x0dY[Xj\x96\n\\\xd2T\xc3\xea@\x11\x9b\x01\xd1\xc4\x82b\xef?\x9a\x8d\x17\xbc\xd8P\xa8\xd7$\x1e\x8f\xc9\xcc:\xc1/|\x84\xe7\x18\x1d6]\x82\xa7\xe7&\xa1%\xfa\xc0\x18J\x04wSxjou\xe6}\xd6\xc1\xd4;\"\xd7zF1\x06\xaa\xd6%T\xe6\xd8\xa2K\xbb\x15\nk6 m3\x8c{\xef\xf6\x98\xd6\xb6\xcb*\xb4\xf8@\xc3\x97\x02\xef\xb0\xdd\xd7\xd6qv02P\xa2\x90Y\x01\xe7A\xad\xfco\x963h\xdf\xfd\xff*\x8c\xa1\xb1\xed\x7f\x13|\xe1\xd9\xd3\x0elAg\xfa[p\x85g\x0d\xee0\xdb\x98\xc2\xc9\x95\xae\xe7\xef\x8e-4\xf5&\xe7\n\xad9\x8e`\n\x1a\x0b\x1f\xce\x13t\x05\xff` \x9dX\x82\x1f\xa5\x7fc\x96\xa0Z\xfc\x07K\xa8\xfcZX\xc2\x8b\x06w\xc3\x7f\x0b\x96\xd0\xd8\xf6\xbf \x96\xa0\xdd\x9e\xb5\xb3\x04\x9d\xe9o\xc1\x12tS\xffNXBSor\x96\xd0\x9a\xe3\x08\x96\xf0b\xfa\x81,AW\xf0\x0f\x96\xd0\x89%\x84\x94\xdf\xfc\x8dy\x024\xf9o\x8c)\xd8\xe46\xd3 \xb3f\x89\x0d\x00\xc50\x00\x14\xa8\xfaT\xea\x8b\xe76\xf5\xf33\x9b\x8a\x9e\xe9X\xd53\xdd\xd1Q\xb9\n\xfeR\xeb\x03\x9b\xa1-}-=mH\x0fZY\x98\xe7Z\xc6\xc2u4\x85\x97\x0c\x1a\xc8\xbb\xc8\xc9;\xeaZ\x03\x18\x89j6\x8a\xa1\x95=\x97\xaaU\x0f:\xdc\x16\x81\xd2`5\x0f\xf7\x9a\xfa\xa8\x10\x1e\xeb\xab\xa7\xcf\xc85\x8c\x02\xf4x\xaa\xf0\xe3i!\x9a\x1f\xb6\xee\x80\x91\x16U\x10H%bt;o\xda\xd1\xd5D\x85\x1c\x91u\xe1\x0c9>G\xa7\xb0\x1e\xc0\xc7\xfb\xda[\xad\xad\x80\xf7\xe3\xdc\x15\xf3\xc9t\xa0\xd0\xbc\xbe|<\x1a\xc1J\x9d\x91\xcc1!4\xc25\xe5t\x07\xbff\x81\x1f\xa63\xe27\x10\x97\x07\xd8Z\xe4RO\xf5\xdap+\xe2l\x9a\x0f\xce\x12\x17Nm\x06uF\xa9C*&\xb0\x01\xc0\xb1O>@\\\xfb\xbb\xdcW>z\x84\xfd\xd3s\xa4\xbax]7\xb7\xb0\x01\x05\x90\xad\xa3C\xea\xd3\xfe\x1b9\x7f\xb3X,\x07\xfd\xc5b\xb1\x18\x00\x83>9\xcc\xf9U\xb6(?K\xd5\xb1\xf8\x80\xcc\x18s\x08\xe3\xdc\xd4\xde\x07}p\xfc\xe1\xc0O\x9du\xe0\x87+2_\x0e\xcc\xee\xac\xfe\xbd\xe0V\xd4E\x0e\xe2\xc3\xe8Xv\x0cR\xa7\xcb\xeb\x87\x84\x8d\xac\xac\x1b\xdc=\xd6\x1c\xa1\xba\x17S\xbd\x93s\x7f\xa9\x06\xaf\xde\x03\xa8p\x96W\x9d&\xb8\x9d\xa9H\xfe\x95%ZXCqm\x07\x90\xd9\x08x\x1fc1\x1d\xbbhJa/\x9b\x17M\xcbU\x1d\xc5\xba\x9e\x92\x97\x07\x8c\\N\x1c\xf8ZM\x83 \xd6\xad\xb54EGo\xb9\x16\xd4\xa60\xc8~9K#k\xa7\x93\xe5v:\xf4\x82\xf0\xe3\xa3\xa3\xf3\xc3\x81\xd7\xa6\x0d\x02}\x87\xa2M\x81\xd5y\xf7\xc0\xeahG\x04\xfd\xd4\xe4\x8e\xab\xe1B\xd7\x8a}\xae\x96cT\x11k2\xe3\x05\x10\x05#-\x12\xe1\x1c5\xc65\x8f\x96\xcd\xe4\xaf\x1bMk\xaf\xfc\x12D9\xad\xaah%|\x0e\x82\x11\xbb \x86\x8e\x98\x1e\xb9\xb4\x08Y$f\xe4\xacN8\xda`\x84\xa8\xcd3\xe2\x82\xb1\x94\xb1\x99~\xcf\xe3\xe5\x04\xdan\xec\x08~\xd6\xd2\xc7\x87R\xf2\xd8\xc1\x80\xb3\xd57\x0f\xa0\xf1\x05\"\xcaK\x04\x94~\xc4\xc0\xe4\x05Y\xe4\xecY\xd5u\x99\xd1\x99|\xe6\xd0\x99\x14\xe2\x8a\x9e\x8d?\x9f\x9c\x80\xf2\xf4\xc9pqzum\x15\xa6\xc3\xdf\xe49\x96\xfd\xebY\xfe6^\xfe|6z1}_\xf8>\xb8\xee_\xcf\x16\x93\xa3J\x0c\x9e\x0c^\x9e\xd6\xf56\x05\xd8&\x8b\xf1\xf2\xe7\xe9\xe8\xfc\xf9\xfb\xc1\xac?\x7fs\xf9rqwv6^\xdc\x9d\x9f-U\xd9\x87\xf3\x91\x92n\xa7U\xc2z\xd1\xa8}\xd0\xd4\xa3_\xa5\x16\x9b\xa2\x13\xaa\x97\xbd\x82(\x04\xaa\x90H\xab\x0f)\xb8\xab?\xe9s\x9b9\xab\xc5\xa1,\x94U\xbb\xa1l~\xb6\xd4\x8dL\xf5\xd5~\x0f\xac\x08\x02\xb5\xe7:\xb1\x02C\xd1/W?(\x8ba\x1dd\xef\xd6\xfd\xc3\xc1]Be\x1d\x1c^\x96\x02|\xe69(\x8e\xd6[\xba\xc2S\xb2\xaa\xe3\xc3\xa3[\xed\xb2\xcb8\xb0\xb2\x87zF\xf2[\x98\x03E\xedN04i\x94\x874\xb5\x13\x986M`/\xa4~ b \x87m\x93\xe9\xfdc2K\xbf\x8f:\x99iu2?\x0e\x91.\xd2\xa6y\xcf\x8b1N\xe7:\xf6\xeb\x8e\xe8(\xa5\xfa\x0fD\xe6\xa4\xab\x18CwR\x0f\x0b\x99?>\x04\xd6\xf48\xfe\x05\xb7u\xf0\x17#\x94\xfa\x18\xffs\x0d>\x1d\xads\xbb\x8d\x80\xb2[\x16\xc3\x1f\xfdo\xb2\xd3\xd1E\x9f\x9ec\x04R\x81\xd9\xd4_(\xee\xd3;\xf8\xa3\x9b\xf6C\xfcW\xbfE\x1b\xa8\xc7O\xf0\x95\xfb\xa9\xf9;Y1f\x13'w\x89W|\xces\x05\xb7\xef\xd4s\xb0\xc6\nq\x19\xc0\x13\xf6-Lyb\xfeB\xa9P\xfc\x84 Y\xa2V\x85z\x8c\xd8-|\x8a6\xf8\xc7\xc7\x7f!\x16i\x14a\x7f\xe2\x84\xfe\x94\xb1 \xf6n`+\xa4\x92\x92\xd8DD\x85b\\\xa4\xf0\x9e2\xbe\xf7=\x86\x8fij\xe2\xa1\x9a\x81I}\xb6\xc7\x8f\xbe~G\xb8\xd2\x10\xffD!&\xc74\xb1C`_ \x0b\xfa\x84\xec p\xca\xa9\xfeD\x188V\xe8\x19\x12;?\x0dY\x9a\x82\x06\x8a\xf4D\xf4\xf4\xfc\xd33x\xc2\x16\x05\xccr\xc6\x01\xae=\x0bC\xe8/\x0e\xc1-\x86t\xbd\xf3\x10j\xf5w\x9c\xa5L#\xca]\x18\xf0\xc4\xb3`\x15^\xb1T\x88\xd3\xf8\xee\xe9\xe7\x93\xe7g<\x7fDd\\\xfbYx'8b\xe8&\xc1?\xf8 \xb1\x82j$\x16\x82z\xbb\x90E\xf8v\xab\xfe]\xb1tG1\xf4\xec\xca\x17^\xeccX\xde8\x80\xb9\xf6h\xa0g\xdd\xdb\xf1\x18\x83\xda\xe2\xd3\x98\xdd \x16\xa566o8f{\x16\x89\x15\xf7\x05\x1bS!X\xb4f\x98\x1d \x0c<\xee\x01\xa8u\x10\xd1q\x12\xd0\xfb\xd4\x8f\xb6\xda\xbf\xa3IR\xb9\xa9\x1f!\xea\xaf\x05T\xbe\xde\xaf\xd4\x1f\xb6>\xbfQ\x7f7\xd4c\xc2GX6\xcc\x84\xf9\x8d\xb6:\x84\xaf\x9f\x02zma*\xb7\xbe\xc0?\xef\xc28\xe1\xb1 \xc0\xbb\x154\x80\xbav\x1e\xae\x04=+~\x82\x7f\xb8^\x13\xde\x0b\xfd\x17\x97\x85@L\xfa\x91BK?\xe2\xdb\x0d\xbbO(\x16\x08h*60\xe0j\xd5\xe0\xa2\xa0[\x8dD\xa1M\xe17:%G\xa5\x10\xeb\n\xd3\xf1\x8e\x05zYE8wa\x16\xea8\xbf\xe1\x1e\xa0\x03\x19[=\xc4\x88; \x0dB\xfc\x9bPN\xdf\xbd\x03\xa4K\x02*L4\xe3\x84\xc7w\x10\x1f8I\xef\x01\xce\x9f2\xc6!\xc1,0\x96\xc6\x19\xc7\x95\xc5\x11iyz\x1fA^.\xf4\xb2a^\x1c\xad\x03\x7f\x83KL\xaf\x88t\x8bk\xf0\xe6>\xc1\xf4\x10\xa6*\x8d\x835\xc5\xc0\xc5I,\xfc\x0d4\x96\xe2\xc4\xa4\x82Q\x00+\xc5\xee\xa8\xd74\x01\xc7)\xb0\xc2\xa2-\xc0\x94\xad\xa1\x81,\xe2\x8c\xc2r\xcc\xc4\xf9\xd9\x19DaVx\xc6}D\xd0\xbd\xcfn\xc79\xf4\xb7l\xe5a\xf6[Aq\xf5\xdd{\xfe\xed= \xc3\xdd\xc6GD\xbf\xe3\xf0\xe9>L\xb7\xbc\xb7|8\xff( \xf9\x9f\x0e&\xbf\x7f\xfd\xea\xdb\xb7\xaf\xbf\xf8\xe7\xb7\xdf\x7f\xf5p\x01\xb8\xa2Eq+\x17+A\xf8I~CE+^\xc8Ic0}\n\xc7\x1aE3\x05\x14\x97\x9f\xea;\x8dN\x97\x0e\x06\x17\xa7\x15\x8d\\\x8a\xe5@u\x04\x98\xac3?\x9d\xbeW\x99\x1f\xce*\x8b\x97v\x1c\x04\xab\xc0\x0f\xeb\xfa\xf8\xa7\x9f\xb9\xb9\xa3w(Z8\xde8\xdd\xb8/\xa9<}\xee\xd6Iy\x9a}\xbai\xa6\xbf1f(9\x93\xf1\x0c'+\x1cI\xa0rA\xf1\xe7\xde\x1dF\xaa \xe6\xd3\xa5b %\xdd\x14\xb9&\xa0\xa1\xf8&\x12}\x95\xc1\xe85\x06#2}\x01\x01\xd6\x8b_Gd\x8aa\xb6\n\x97\x81\xfc~\xa4j\xa1}\xa0\xcc\xb4\xff\xe2\xf9\xf3\xa7OK;\xf2\xa0\xcc\xb6\xea\xc4\x1am6\xc0p\xa8\xb1k)2\xe9X\xf1\x01\x05J\xb5\xa7%\x98\xf8\\eY\xb6\x00\xe1\x14\x95\\\x0e\xec\x1e\xfd\xc2\xfe\xeb\xca\xb3\xac\x05\xb5\x99c\xf2\x95\xe0\xe1\xf6[v\xa7>\xfd1k\x88\xca\x01\x07*iC\xc4\x0e\x1am\xbf\xe3l\xe3\xdf\xcd\xd4\x8e$\xdaft\xcb\xc6.\xed\x8b\x1f\xdd\xf8\x9b\xfb\xc6\xf8*7\xaf)\xdf21sJ\x03\xe2>\x89!\xa8\x08\xe3\xee\n\x809\xa63\xd2\xfb\xeb_\xfe\xcf\xbf\xfe\xe5\xff\xfa\xeb_\xfe\x8f\xbf\xfe\xe5\xbf\xb8\xd4]\xfev\x17`\xfc\x91(\x0b\x1cJ\xa8\xfc\x8clF\xce\xab\xa7\x1c\xa5W/\x0e\x938b\x91p\x8e\xb5\x17s\xe6JW?\x9e\x05\x10\x8a\xa5\x07\x9e\xe4z\xa3<\xea\x8b\xda\x1c\x19+\x19|\x03\xc9E1\"x\xd7\x83\x88{\x1f\xca\x05v\xbb^\x8e\xaeV\xfc\\=\xd8\xa3\x0eA\xfd\xa0\xe7\x08\x83\xe8\x98mto\xd7\x05th\xbe72\xce\xf7\xd4\x06\xd9@`\x1aV\xcf;F\xd7\xc8 {;T2\x890\xb0}\x0f\n\x9fu\x90\xbeB\xd0\xa6\x91\x8e\xa5\xdb\x0dv\x1c\xc7\x83\xc0\x17\x02w\x94b\xa7\xe8\x00)\xc5\x00&y\\\x8e<\x14K5FH!\xc2\x87\x0dHR\x08\xef\x82\xbaP\x07\xfc\xbfr\xbf\xfd\x83,\x14?\xfe\xbb$\x0b-\xcb\xae\x0d\xab\xff\xce0\xc6q\x1d\xbe\x801\x8e\xaf\xff\xc0\x18\xf8=\x04cj\xe9\xe4(F\x82\x0c\xa1\x13\x0d\xfd8\xf4\xffCh~'0?\x94\xd4\x1f\xa2\xf1\xff\n4\x1d\xb6]\xf9\xd2\xe4\xc5}IU\x98w\xaffS\x0b\x83#&jf\x1e\xfez<\x8e\xeeQ?\xbf^s\x86\x07\x04\x943\xcc\xc5\x85\xef\xa1\xde\x97\xa6>N&\xcd\xd6>h=A\xc9\xbaZ\xfb\xf8\x07\x93|\x18\x99\x95\x1d\xda\x12:\xac\xe25\x8c&\xb6\xbc\xca\x84\xd0z{\x1a\xed\xf1D\xcb\xa3\x890\xca|\x16 T\xa6{~\x19\x9b\xbc8\xd0\x7f\xb6<\xce\xf0\xc4+W\xef\xe7\xa7]\x82\x1a\x1cZ\xe39\x18\xf3bNE\x8cZ}d\xe9k\xa6$ d\xf2\x1b\xd4\xf3\xfb\xf8\xdd\xc7\xc32\xcc\x05\xb5\xb0\x80\x99S\x0b\x06\x03\xb6\xf1Y\xb0N\x99\x8e\x11\xb5-\x00\xbf\xf1\xb7\x19\xd72\x01\x96P\xb2\x81>\x1b\xd0\n\xf1\xdd\x14\xfe\x05yl\x87\x87k\xa0X\xde=\x87\x7fA\xe9\xaf\xd6\x83\xf9\xab\x0f\xe2l\x9f\xf3\xf5\xa3\xfe\xc2,\xf8!\x0c\xbf\x1f%x.\x88a\xdbz7+\xa8\x04\xacw\xe0\x81mY\x84IP,\xa4x\xde\x12\x9aC6\x08\xe5\xa6\xfe\xfe\x94\xe1\xf1I\xc8\xa2\xcc\xfc\xf5\x05\xf6>d\xbaC\x11\x9e+F1\xce+\xceN\x9c\x08\x0bil\xc7%\xce\x84\x06\xcd\x9c\xad\xe1\x9fxk0\xef'\xf5\x0f\x9e\xe9q\xc8\xc8\xb3\x15\n\xb6\xf0\x0f\xb5\xe7\x00\xa6\xca\x94\x05\xfa<%\xdd\xd1u\x0c\xc7IiH\x03\x80\"\xd7\xc9\xa7 \xf5\x10\xdc4\xa1XPp\xff\x86\xe9\xa7\x18\x89N*\xee\x11\xdb1\x08]/\xcd\xc2\x90\xe2)\x05\x06\x9d\xd3R\xa7z0\xd8,`$\x05\x0b\x93@\x1f8*\"`V\x90P\x13\x0f\x0f(\xb4\x9a\x195gG\x82\xe3\xbf\x14)\xa0\x80\xbc0\xd6\x19\xf4`\x8f\xc7<{\x7f\x8d\x07\xb3\xb7+\xdes\x04\x8a\x03\xa3\xb0^\xba\x87^\xe0\xd2\x0d\xc46\xb8GQ\xd9<\xafQ.5\xaff&i\xe4\x87T0/\x0epm\xe8\xf706c\xac\x13\x04\xa7Qj\xd0\xd7\x92\x81\xc2\xea\xf5\xb9&\x16^\xe0' \xc5.\xaf\xd9F\x0b\xd1)\x9c\xe5\xb0 \xf0\x93\x14\x17\x87\x1f\xd8E\x81\xcb\x04\xcf\xcb\x0c\xdc\xf0`\x84\xe9\x1b\x86G\x9a\xda\xf6\x1e\xe8\xaf\xfdK\xf9\x96\xd3\xb5\xaf\x97'\x9cnq|J\x11\x97\x99\xa0\x862\x84\x06\xb2\xc2_\xa1+O\xe2\xe0~\x1b\xdbG\xcb5\xe9\xda\xa7A\xb1 n\x90N\xe01q\x8e9\x10\x01\n\x9e\xee\xc3U\xac\x0fq\xef\x84\xf9k\x1a\x05\xabzx\xd0\x1d\x14\x061\xed\\\xef}\x06\xe8\xbc\x87\xae;f=\x82Y\xdf\xb0\xdf\x06z=o\xd8\x97j\x12_Q\xc1\xfd;\x93\xa0\xc5\x88\xd70{z\xb819\xd5\x94U\xbdF\xfb8\xd8\xb3b\xc9\xdf\xf9\x9bM\x96\xb2o\x958\xa3\x99\xb2JL\xed\xde\xf3\x15\xd2\x0bH\x144\x12\x90\x13S\xbe\x0e\xe2XC\xf4u\x16y_\xe4\x8f\xbf\xcd\x1f\xff9\x7f\xfc\x1e\x1f\xff\x99fi\xea\xd3\xe8\xb7A\xa6\xe1|\xc5\xf8\x96\x15\x1e\xff`E\x8aW1Ovq\x10o\xef\xf1\xfd\x8f\x9b\x8d\xa1\xc5\xa87,\x80\xf3C\xc2\xbc,\xa0\xbc\xdc\x97\x1f\x92\xb8\x98\xe9\xb5\xb1\x84`\xaf3\xbe\xca\x02%\xb4\xb8F\x1d\"r\xf4B=\x8f!\x8b\xb4e\x89z\xe6\x1c\x97P\x08\"\x0f\x9a(l8\x05\xc4\x0f-^\xe3\xe9f\x08\x04\x99\xad\x91\x04\x84a\x16\xf8h\xea\x81\xa7\xb0H\x92\xd1\xd8!\xdektN\xe8z\xad\xabMv4\x121\x92b\xae\x89L\xc8\x91\x00\xea\x83\xdc\x04\xa8\x1e&\xfc\x84\xe44\xbc\xb7\x98\x1aj\"\x17j\xd2\xa6\xde\xcd\xa3%s!\x92\xb7\xd0\xa0p\xa8\xa1\xcd\"\xcd\x90\xf0 \x00t\x8cU\x0cc\xf5k\x14\x8b\x1c\xd2\x1a\n$\x9e\xc7\xb4m\x80%\xeb4\xf0\xb7\xfa\x01\xbfd\"V\x12q\xc0\xb4,A\xbd\x1b\xc5`\x10\xefW[K\xbcV1\xd7\x90y,\x08\xd4x\xe9\xf9V\xafj<\xcc\xeb\x8ey78\x94V\xc0\x08(2!/`Hvm\xad^\x8cB\x82\xfa\xab\x97\xa9\x17\xc7|\x8d\x89\x9a:A3\x8a!\x8cW4e\x86g\xd2\xd436>\xe6L\xcf \x84M00\xd3w~\x98!`\xaa\x8a\x8d\x9a \x16y\xf7&A\xd59Nw\xfe\x06\xea[1\xbd\xd2V>\n\x1e(!\x16\x96/ZB\xa9\xbfc\xc3o\xe1E\xed\xffz\x95u\x1d\xf3\xb1Z <\x89\x03j7\x1f\xf5\xe41\n+i\xfe9\xe1\xb11\x9e\xc3\x04\xce\x14)4\xf4\x05f\x07\xbb\x80\x8b\x1d\x12Pf\\#k\xf5\xe2\x08\x18'&\xf1\\\xa8]\x03\x97\xd5Y\xf7~\xaa\xf7,\xc8\x14\xd9z\xcbB\xcd\x06Y\xc0\xf6\x16j#\x04\xf8(\xfc\xaa\xbf\xe3XQ<\\\xf9\xf0nF\xa0 z)V=\xb6#\x82\xaf\xc5bq$\xc6\x1b\x1a\xfaA\xfejP\xdb\xbe\x8c\xe9\xfa\xc7,\x15y\x9a\xe0L\x8bA\xfa]c1\xbc\xed)\xf7i\x94\xe7\xbe\xb5h\xb6A\xd9\x03Z\xda\xc2\x06i\x0b\x1b$`\x9dc\x83?E\xb9\xd0\x08eY\xe4#\xe34 %i\xb5@8u9M\x1a\x950Y\x9e8D-?\x82va\x99\xdf\x00 7\x98\x00;\xb5\x1b\xd8\xa9)\xb1L\x17\xbaa\xf7\x89\x929R\xfd\x92&\x10X]\xbf)n\x00\xcf\x96\xd4\x02%\xcd\xc7,`\x8a\xd6\x8d\x0b\xecI\xd5\xcd\x82\xd0\x8ac\xf8\xae:\x99S\xe1@K3\xf9\xe4\x05\xb16P\x1c\xb3\x84\xef\xbc\x1d\x8d\"\x16\xa0\x00\x84=\xbdw\xa4Asw\xd0\x8f;\xe8\x07\xca\x1f*7\xfc\x03_\xee\xe1\x0b\x18|\xbf\x8b\xe3\x90Fk%09d\x94\xac \xa3\xf4P8\x81U\xaa\x97\xb4\x15{Vl\xcf\x02-k\xdbM\x9a\x17\x07Y\x18\xa56\x13\xbe[r\xad?kQm\xcd\xa28\xb4Y\xd7,\xd1:\x0d+\xcb\xe7l\x1a\x1es>\x07\xbbG\xf5\xc05ykbA\x81\xc2\x1f-q\x17H{\xc4\xc4\xce\xf7n\"\xad\x17\x0b\xecV.\xb0\xfaT\xb5\x05-\xef\x83T\x8a]g\xea\xc50j\xf5\\\xe0\xba!\xbd\xb3_\xfc\xc8>\xc6{\xb55\x81U\x03\x8dFqNL\xa3,\x1f\x07#\xad\xf3\xf8\xd6\xa6\xf1\xf8\xd6\x8e!\n\xcc\x06w\n\xe23\xb7\xbd\xe0\xb6\x17\xb8\xe7\x05\x03\xc5\xfc\xb5\x00\x95\xde\x13\xfb\xef\x98\xde[\xf8Z\x8f\x07\xe8e\xb5\x80 \xb5L\xc2\xbeh\xe2\x03\xa2\x88V\xe2\xe9 \xffV\x96L\xb3\xa4\x9ar\x1f\x86Lp\x1f\xe4\xf1}N}\x0e\x8b\xcex\x83\xe3.\xf0\xa3\x9b\x99\x99\xe3\xbb0\x98i\xebzH\xb7\xe2\xba\xfa`G\x03\xaa\x9cA\x8e\xde\xb2`?I\x8a&\x8f\x81\xd3\n\x89T#7\x9b\xab\x9d\x17$\x1a\x8f/\x06\xa8\xe8\x8c\xb6=ru\x05\xa6\xa6\xf1\x86\x88\xb9\xb9}:\x87[\x98\xeaO\xe5f\xd9\x88\xb0\xb9J^6x\xdf2\xa6\x9b\x95\x83\x0d7\xe4^\xbb-\xae\xebp\x93h\xf5\x16^\xa6\xad\xb7\xaf\xbdc\xfb\x11a\x03\xf2\xc7\xd5\x8f\xcc\x13\x85\xf0\xf2;\x9a\xfe\xf16\xfa\x8e+\xd1A\xdcO<\x1a\xc0\xe0i\xcf\xd1\xba\xd7l\x1e-\x1d\x9eT\x8c\xc9N\xc3\x91\x0d\xd1\x80o\xc0\xbb\xdc\xcf\x8b\x9f\xe7\x8bt\xf1\xc3\xf2\x89\xd4\x7f\x17\xef\x17\xefO\xb7a\xbdG\x89*p\xf9O\x95\xec\xff\xf4\xd2\x99y\x0d\xd6jk*\xe8x\xbe\x18/n'\x8b\xec\xec\xec\xb7\x9f\x8e\x17\xd9\xd7_\x7f\xfd\xf5\xf2\xd4q\xf2\x08%\xd4\x12\xc7\x12\xcb\xe1'\x8e\\{\xc8\xd5\xbf\x9e\xe1\xff\x1b\xb9\x13\x03\x91\xa4\xd7\x12o\xd6H\xc1\x02\x89\xd7-\xa4\xe7\xaf\xe5]\x98$\x83\x99\x9c\xbf\xa1\xe3wK9\xa7\xe3w\xc3\xc9b\xbc\x1c\xf6\xafg\x90\xa6\xdefK\xf9\xc9`P5\xb7#\xda\xb3\x154\xb6\xb8\x1d\xe2\"\x93`\x829se\xde\xaa\xccs\xd5\xcd\xb3\xb3\xb1\xfas~\xa6\xfe\xfd\xe2l\x91M_|\xa6\xfe\xfd\xec\xec\xabEv\x8e\x9f\xcf\xcf\xce?W\xff>\xdf,\xb2\xa7ggg\xcb\xd3m\xbd\xca{rEz\x06 \x8b\xf8\xff\x03hf\x15.\x18%m\xed\xe3D\xc9\x0f\x8a\x86\x90\xeb\x03\x16\xe5\xa4\x803XC\xdd\xa9\xee{2\xeb^\x0b\x03\xc0\xda\xe1f\x13\x10\xd1x\xa6\x18,\x18\xe1\x15\xbe\x81M\xa1\xee\x86]\x13\xe4:\xef\xec\xac\x05\xd2&\xea\xb3r\xc3\xedoH\xff\x0b%\xb5M\xfc\x14\xfe\xf6Y\xa3\x85\xa1%Sj\xd1\x9f\xe1=z]\xc6\x98\xb0_\x10\x01\x11\xe7\x0d \x13\xc3\xe1\x80Ds\x81\xebU,\xeb\xcb\x95\x14\xdc\xf5\xd5{\xd3\xb4\xba\x11\xe4\x0d\x8f\xc3vG\x80\n\xda\xb7m\x07\xae\x85:{J\x00\xd9\xf8\x11[\x17\xe7\xec\xd6\x8f\xd6\xf1-\xb9\x06{\x002\xd3\xef\xe5&\x9d6\x83v\xe4o\x9d\x8d*\xc8\xbe\"W\x84\xf2m\x06\x86`&\x92\xfcK\x8c\x0d_\xf0B`\xb3\xcc\xcf\x96\xe4\xba\xfc:#o\x9b\x02\x9a\xde\x95\x0c`\x9b&\x95\xe4\x10\xdfV\xc7\xd2\xfc\xde\xbb\xbd5\xdcM\xf6\x8c\xa7\xaa\x8bW\xa47\x9d\x9cM\xd4\xae\xfan\xc2Y\x18\xef\xd9Z\xc7\xbd>\xf9\n\x9ck|5Y\xc7\x1e\x80\xad^?\x87~\xe5i\x93(^\xb3\xd7\xf7 \xb3\xb6\x9bw\x13?\xfd!K\x92\x98\x0b\xa8\xead:\"wu0\xd4(\xfe@\x8aU\xb9\xc7\xe2\xcb\x06\xbf~\xeaw\xd3\xf2\xed\x8b\x0eu\xff\x11\xf2\xfcN\xe7\xf9\x9a\xd3ms\xde\xef \xef\xef_\xbf\xfa\xf6\xb5>p\xfc\nO\xa5\xdd\xd9_C\xf6?\xd4,\xad\xcd\xef\x95\xfd\xfe5\xe8\x83\xdc\xb9\xbe\xc1\\4dk\x95\xf5\x15M\xdc\xf9~\xb4\xfc\x1a(\xd27\xe4\xbaRLM\xddW\x93W\xf1;H\xfcB\x08\xae\x12g\xe4\x1bw}\x7f\x80v_\xb3\xbb\x86\xde}\x0f\xdf\xbfD\x8b|w\x96\xdf\xe1\xd8\xfe\xf1\xd5wp[\xda\x9d\xe9[\xc8\xf4?\xbf\xfa\xf6\xf7B$\xdf\xb3\x9f2\x966T\xf7\xa7r\x0f\xbf\x85\x1e\x96\x0b\x92\x19\xf9\xd6]\xf8'h\x86Ej\xff\xf6\xa7\xef\x1b\xfa\xfcu\xb9\x85\x9f\xa0\x05[\x86\xcc\xc8O\xee\xb5\xe4\xe4\x17\xdf5-Z\x85\xf6\xef\x14\xf5\xfd\xff\xd9\xfb\xda\xae\xb8m%\xe0\xef\xf7W\x0c~zR\xfb\xe05\x90\xa4\xb7\xed\x06\xc2!\xb0ii\x03\xe4\x02i\xdaK\xf3p\xcc\xaev\xd7\xc1k\xed\xe3\x17^z\xcb\x7f\x7f\x8eF\x92-\xdb\x92\xec%iz?\\\x7fHXk$K\xa3\x91\xe6E\xa3\x99`\x9c\x92\x8a\x88\xdc\xea\x18\xdb\x10\xc4\xff\x8f@\x98D\xd8\x16S\xfe\x08\xe8mBRI\xc1(c1\xc27\x94\xdb.\xd5\xc8\x87u\xf0\x15\xeb\xa0\x1eK\xbf\xc0\x0e\xbc\n\xa2\xc5\x92\xf7\x1b\x95\x14=\xe4\x8f\x08\xc9G\xc9\xa8\xf0P\xb0u=\xf4{\x84\x9e\x91\\ ${u\x7f\x1e\xce\x18\xb5\xea\xe1\x7fRZ\xef\xb7\x80\x7f\x83\x1d8c=\xa7in^\x97?\xa3T\xdc\x9e\x82\xe6\xae\xf6Kc\xa7\xffE\xf4\x85m\x10\xeat\xf0\xfdr\xaf\xdc\x88\x8e\xe8Ds\xf7\x8d!\xfd\x07\x8c\x8c\xa6\xed\xd4W\xb0\x03\x86\x95\xffo\xd8\x81\x89\xbe\xe8W\xd8\x81\xb9\xbe\xe8_\x18wM[D\x08\xec\x80F\xa4cON0(\xa0\xb6,aez\xcf;@F\x05;\x10\xbb\xffy\xf0\xe1\xe2\x03\xa3\xceq\x98\xbbW\x188\xeb\xca\xcd\xf1\xdf\x04\xffM\xf1_\xeay\x06\xdeH\xed\xdf\x89\xf4\xdf\x89\xb0\xd5\x10\xff-\xf0\xdf\xcc\xf8\x85\xd0\xfe\x85\xc2^\x9c\x11Cb\"\xc0[\x81\x96\xc21\xb1\xb0\xb3\xa9\xadpi+\x9c\xd8\n\xe7\xb6\xc2\x1b[\xe1\xc2V8\xb3\x15\xde\xdb\n\xafl\x18\xba\xb4\x15\xde\x12\x8bB;R\xc8\xa2r\xa0\x91.A\xd2\xa3\xa0\x8a\xf7PZ\x93T\xef\"\xe1\xe4\xc3\xbdD>\x98d7\xed\x97J\xcf\x12\xe1(V\xb9Gq\xa7\x1aSkg\xb5\xd6\xb8a\xb99}uh\xf8\x98R\xc6*\xb1\x97\x85ZI\xfb)\xa5LVB\xfaw\xde\x9d\x8d.\xdf\x9e\x9e\xbc>|3\x92\x9fz\xf2\x04\xa6\x81\xfa\xde\x17\x9b\x14\x0f\x82'\xfa}\xb9wz\xb8\x87\x0d\xfab\x9b\xaa\x17\x1f\xec\x9d\xcbb\xdc\xa8\xe4\xfbw\xc7?\x1f\x9f\xbc?f\x8d\x9f\x9f\xec\x9f\xbc9C\xa5a\xcb\xe7;\xd648\xdb{=\xba|}rz\xf9\xd3\xbf\xde\x8dN\x7f\x93\xa5\xcbF\xe9\xf9\xe8\xe8\xed\x9b\xbd\xf3QY}\xc2\x01\xde\xffx\xf2ftyp\xb2\xff\xeeht|.\x0b\x17\xbc\xf0tt\xfe\xee\xf4\xf8\xf2\xe0\xe4H\x16\xcc\x9a\x05\x97\xafO\xf7~P\xab\xde\xb7 \x0e\x8f\xde\x9e\x9c\x96\xe57\xbc\xfc\xf5\xc9\xe9\xfe\xe8\xf2\xd5\xc9A\xd9\xe3\xab\x1aR\xce\xf6\x8e\x0f\xcf\x0f\xff\xcd\xbav\xe4\x8b\x8dI\x96\xfd<\x1a\xbd\xbd\xdc?9>\x1f\x1d\x9f\xfb\x9ciV\xc4\xf1\xee\xf4\xf0\xf2t\xf4\xc3\xe8\xd7\xb7\xac\xe1\x9c *0\x0c\x11\x91i\xd5f\xfc\x05\xdfa7=\x9cZ\x0c\xecI\xb4\xbc\x0dy%\xa7OT\xdb\xf8Z\xb8%Uh\x80\xd8M\x88\x0f\x8c\xd7\xc6.%>D<\xb3\x97\x84\xcbnf\nX^\x82\x85\xe5_Y\xab\x02\xd7Z2\xa5^\xd2]\x8f\xed\xb3Gj\x97\xd2\x12\xb2P\xebx\xb8\x9a\x0e\xf8\xa2(\x87\xbe\xb3\xc3\xa4\x88\x12\x11c7!\x1e\xd6b-U\xf0UmF\xad\x08Oy\xed\x88\x94\xbf`\xecRQ\x9b\x12\x15\xbe\xaa\xcd&\n\xc9S6\x13\xbbgD[\xe8!\x01\xf0\x8e\x95.Wr\xee\xb8\x85\x94\x1b\x96RB\xfe \xb8*\xab\xb7\xc2\x82\xca\xcb\xdc\xa9\xe7\xf3\xadu\xaa\xdd\xfd\x0c\xdc\xed\x84\xf46\x18\x94J\xbe)&\x82\xfa\x08\xbf\xeb\xa1\xc6Z%\x9f\x07K\xce\xb1<\xbd\xb7\xf4\x04dv\x08\x92\xa0<.:\xb6?\x8f\xe2\x89\xc9\x9c\x01h\xd1\x1b\x87\xf9x\x8ey8\xbaZ\xa7ENR&\x92c\xe8rs\x93\xab \xfb-\xe9\xba\x9e\xac>\xdd8XiF\xd8S\xfa\xf0\x0c!g\x1a\xd3\x9e\xfc\xcd\xb0\xc8$\xea\xce\x16\xa6)]\x0c\x1bv\xf6\xe6\xf3\xd0c\x06\xac\x94\x06\x9f86\xb3p\xa1>\x9f:\x14\xf3\xc4\x89\xae\x97\xd85\x9a\xd8\xf4\x9d<\xef\xbf&\xa5a\x96K2\xf61\xdbNf\xe4\x13M\xc1\xbd\xe1\x1b\x12\xca\x04\xdb|$/\xb77\xc4\x1f\x0e\xac#7\xb8\xee\x9a\xbfn\xeae\x0f\xfb\xc8k\xdb\x92\x85&\xd1\x98\xd1\x0ej\xb4\x03r\x0b\xef\xcc\xc3dO\x1a\xa4$[\xd2$C\x1b$\x1b\xacT\xb4\x1d\x1f\xd2\x80.I\xe2:?\x8c\xce\x1dq/e\xc86\xe7\x0d\xc6\x18_\x8c\xe7a\x9a\x91|\xa7\xc8\xa7\x83\xef|D\x89/\xd2\x9a\x06\x19I&.#@\x8fGE\xa9>\xf3\x08Jb\xd3\xb1\xef\xf5\xc0%\xfb\x92\xcb\x06}\xe0\xf1\x18\x83\xafS\xba8\xc33D\xb6\xcf8e\xdf\x9d\x9ek\xd3\xdc\xa7\xf2v\xfc\x93'\x90\x97\xc6 !\xa8\xe3\x95y\x9e^\x94uIg\xdap\x1d\xc7\xf3\x82+:\xb9\xf7L[x\xa2\x16L\xa34\x93\xcdc1\x13\xc4k\xdb3\xa3\xc7\xf7\xfc\xbc0G\xe9oW\\\xb1\x81\xa1\xb8\xbf\xe4]l\xb6\xefw\x81\xde\xc8]7\xd70 \xd8v\x8c\x00\xca-\xads\xe2~\xbd\x9d\xdd\xcc^n\xcf\x80\xa2\x8f\xf0\x0e\x06~k\x0f\xd3\xf5\x9c\x97\xdb\x1b\xb3\x97\xdb\x1b\x0c\xfck\x03#$\x01\x86\xdb:\x13.\x19.j\x91\x18\x82\xc9\xbd\xe62\x82\xbe\x9e\x9d\\\xdczW\x97/\xb7Qo{\xb9\x1d-f\x90\xa5\xe3\x1dg{\xa3\xf1\xe6\x0eh\x82^\xf2;aL\xd2\xdc\xdd\xf266\x9c\x97_{\x9e\xa6\x83\xc0\xd4T\xae7\xed\xf3N\xea\x11o'\xb6\x07W36\x86\xe7\xa3\xfe{\xa3 \xd4\x1f\xc5Ir\xc3\xde\xf9\xe7\x9fl\xd1\x12\x1f\x8e\x82\xb3\x1fO\xde_\x8e\xde\x8c\xb8\xac/_\xec\x9f\x1c\xd5_\x9c\x8f~=\xf7\xbb\xa9\xa1\xf1\xf9\xa3\xe0\xf5\xe1\x9b\xf3\xd1\xe9\xe5\xde\xfe\xfe\xe8\xed\xb9y\xf5\xd5s.\xd5\x8b\xb4\xaf\x0fWFE\xa9\xfd\xee4\xb4\xdfs\x8d\xf6{\x8e\xb1l D\xe8U6&t\n\xe70\x14\x07\x9d\xa6\x86\x88\xa6!\xc2\xd5h')\x16W$UM\xdd\xa4<\x02\xe2\xc7\xba-\x9f\x07\x0ep\x1c.\x0c)O\xf5\x88\xf9\xd8\x12\xb3\x1a\x973\x9b\xcf\xcf\x17\x04]+\xd8\xff\xc1\x94\xa6\xa3pN<\x95\x0c\x8eQ\xfdT\xdf\x9cb\xe8/\x8d\xcfJ9\x7f\x86 \xce\x03\xc6\x99\xf6\xab\xe3 \xed\x91H\xaer\x07\xcewJi/S\xfb\xf1\xb1\xb3\x89R&\xb3@f\x8a`\\\x05\x969\xe1\xb9\x1al\xf9\x7f\xa5\xf4Q\x91m\xddA\xa7{J\x8a%M\x1a\x13\xc2\xe7\xa3\x83\xfd\xf3\xf3\x8e!\x18\x8eH\xe4\x13\xc61\xbd%\x93\xf3p\x96\x0d!\xb1\xa9f>\xac%\xe4\"\xfd\x80\x01\xff\xd8\x1f]\x8b\x80\x8d\x80\xab\xb2k#\xach\xc2/ \xa2$#i\xbe7\xf9\x18\x8eI\x923&\xdeG\xc4\x01\\i\xed\xba\xae\xb37\xcdI:Bg:\x06\x90p\xc1\xe0\xb3\xc9\x94\xcd\xf97c\xadk\xff]\x9b\x12\x1eT\xb0%\xd3\xf0\xd7\xca1]\xf9C\x0f\xbb\xb6\xb1\xbd1\x0br\x92\xe5.Q\x97\x10\x97\x0eV\xd2\x9d*M=\x18\xc74\xe1\xaa\xa0m\x03\xaba\x99'9\xa9:P\x06\xe8c\x1d\xf4\xc1y\x12\xe7/\x1c\xcf\x93\xa6*\x99\xeaA\xdd\xf7\xb9\xb8X\xfeS\x1fO\xd9\xde\x0f>8\xc0$G\xf9\xe2+\xfe\xc2\xafW\xa8\x82J~\x01,\xa8\xdf\xdd\x81\x84\x0d\x93-\xe2\x90\xd1\xa3}[\xddZ\x85\x0b\x9c\xae\xc8\x05V\xd6\x07\xedpiO8\xda\x13.\xea \x17\xf6\x84+\x1e\xcd\xf2\xca]\xbe>;<\x82j\xc5a\xba\xb6>\x86\xf4v\xcc\x15\xdd\xc3\xda\xe4\x1b\xb5.\xa0\x89\x0e\xfa\x970.z\x82_\x13\xb2d#\xd2\xc7ki>\x82\x15T(\x18\x0253\x04\xd0\xebJ\xea\x83\x8ebl.\xc2\xd2\x11\xac@_\xd6n\xb4\xc8\xec\x92(k\x84\x17\xc5\x07/H\xc2\x05\xf1\x91\xf4\xf2\x00\x0f\x98\x82<\x8d\x16\xae\xe7\xf3\xa0\x85u\xbe\xeaC\x16H\xd4\xf2\x04P\xfc7\"\x8f'\xeb\xc8\x02\x89\x1e\x91J\xb3\xc9m\xf7\x94\x18\x96hJ\xe6_W\x1a\x92\x07d\xb8\x85Q\xe4o\x87G?8\xca\x8e&\x05\x9d0\x88&\x1e\xd29\xfb\x8b\x13\x14w^\xab\xbc]1\xa0]\x10.\x97\xf1=\x1e.\xbf%.?\x8e#\xfcG\xc2\xff\n\xcbL\x12\x91\x07/\xa1\xe0\xbcA\x95PD\xb5\x88\xa3\xc9\"c\xc8\xc7\x90\x12Q\xf7\xa0\x93\xca\xe1\xf1\xdbw\xe7\xbaa\xf2\xbb\x0e\n:\xf0f\x1d\xb7\xb6\x0bs\xf9\x05E b\xad`\x7fy\x1eF\xc5\x8d\x92B\xe3\xc7\xa0{\xd8\xc8\xb0\xb9D3\xec\xc4\x07\xc7Qp\xd5\xd9\xa2\x9d\xcb\x83\x18\xaeB(\x18)\xf8\nY6\xf6d\xad\x1c(\xa7\x03\xfe\x9b\x0d\xcfM!J`\x8f\xfd\x8d\x7f]\x13\xcf\xe8P\xd9|\xd8G\x05#d\x04\x87\xff\xa4\x9dl\xcf\xc3\xa3\xb6'O\xe0\xdf\\\n\xa0^\x8f\x99\x079\xfb8P\xac\xfe\xebc\xaa\xf7\x1b\x18\x88\xc1\xad\x95d\xc0\xa9`E\"\x00\xd1\xcc\x19V\xee_\xa7\x1chN\xf8\x18+\xa4\x12\x82\xb4\xd3w\xcc\xa0\xb6\x86\x97~\x15RPn\x0eT\x04\xc1\x1d{\xaa,0\xdc\x80\xc8m7kw\xe4\xc2\xa4 |\xe8\xa6b\xf5\xc1\xb0\xa2\\\xe6\xfe\xd7g\x18#\xa8\xe3L\xaby\xea\xd5@\xf7\xea\x82N\xd3T\xf3i\xaf\xf8\xd4\xf3\xd5\x93\x01\xba\xb4\xc8h\xea\xb3\x82\xb8\x0f\x9d\x83\xb1\x97\xb6$@\xad\x94alb\xa5\x03\xa5\x03U2\x04b?\xd7\x92wM\xfa\xc8Tl\x13:b\xed\x99\xa9\x07\xf9}[\xa6:\xc3\x80>\x07'G\x0e7\x87\xb0\xc1\xbe\xc0\xef\xa6AB\xeer.X\xbf\xf0Z\x0c\x98W\x14\xa1B\x92R\x18;&n\xc2\xb5\x9a\xa4\xd4\x8f\x14\x8d\xff\x049CU\xe6\xf9p\xcajX:\xde\x9a ]\x97\xf5\xb3`\xbcxr\x17d\xa2\xb1\xbe'|}g\xa3\x8f\xf4\xddG\xf2\xee#u\x87\x1d\x924f#\xe4Qqa\x07\x9c\xdf\xef\x9e\x8d\xd7\x06\x83\xdf\xef\x9e\x11\xc6\x88K\xf3\xceZ\xa5\xeb\xe3\xdetH,\xf7\x0b\xa0\xed\x0b\xab\xd4\x0fr\xcaO1<\xc8\xe7)\xbd\xc5\x83\x1d\xa68\x8e\xd2\x94\xa6\xae#\x8b!\xca \xa19\x84%\xf2M\xce\xb0\xe5\xf7Z\xbd\xc5AU_t\x19\x0b\xd7~t\x12\xa5\xf9}\xf5E\xde\x90\x0f\xe1\x15M1N\x8d\x81x\x8c(]\xab\x1d9t\"J\xb5\xbd\xde\xbb#\xecp\x98GcnHa\xc2\x8a\xce\xec\xd2\x84\xeb\xb6\xe6\xe8\xec\xb1\xa55\xac\xde\x9c\xdb%w\xb2\xf6\x04\x19\x18\x1a\xa8NtV\xdd\x1b\xc1t\xb3M>f\xcc\xcf\x91\x9a\xf7\x08\xba\x916/1\xd4M\xdf\x1e\xf0,\xbb\\HK\xf8\x19J} x\xf5#\x06\xc5a\x98\xed\x04k\x9b\x9eW\xb7w\xbf:9\xf8M\x88\xcb\x95\\\xbd\xcb\xf7J\x18B\xc2\xb4\x03\x92L\xf8\x99Xj:$\xb2\x0bdH_\\\\_\x9b\xe0\x7f\x03\x99-\xb8\x14N\xb6\x1d%\x7f\xb7}\xd5\xac\xc9\x91\xa3\x80+\xea\xf0^\xf3\x9b2\x06W \xfd\x14\xf0\x93\xe6\x13\xb6}\xa3\x95\x8b\x1f\xef\xe9{P\xdeC*8kJ\xbc\x17\xb8\xef\x15u\xae\xc2\x0dL\xb4\x86h\xca]x\xd8T\x1f\x13\x97rnB\x8d\xdc\xe4\x80T\x85\x9c\x9dP\x91\x8c\x98\x1a\xfa\xc60\xb3\xb0\xdae\x18\xc4\xacCG\xc1\x11\xb2-\xf8'~\x9e\x904<\xf0_\x80\x8a\xa6\x17\x1e\x845\x02\xe9\x81C\x90\xf4\x82A\xfb\xcd0b^\xef\xb9V\xc2\x80\x7f\xe3]:\xf3e\xaaK\x1f\xc2\x15&Z4\x88G\xb3\xea\xd9-#\xf2\xd2\x94\xd8\xaa\xf9\xc0\xd6dF\xf2}\x9aL\xa3Y/\x1b\xd8\x1e7\xd2r\xdfdMly\xd6\"\x06\x8aj\xb7ij\xb2rW\x95.\xcf\xfaf\xc3\xc9\xe4GJ\xaf\xfb\xf2\x7f\xfd\xd9\x03\"\x1c\x8f\xa3v\xf8\xa9\xd4\x9f\x7f\xe2^\x84'Sh\xc6\xcc=\xcdU\x8cj\xf3ju\xc1\xf4\xfd\xda\x99\x97^\x90n4\x9b\xad\xd4\xae\x1c\xc5\x85F\xa7Q\x1a\xde\x8b\xe3V\xdb\xc6\xa6\xd1\x0fW\xdbZ\xed\xe5\x832\x16\x9e\xce\xb6\x0c\x8b\x9c\x8a\xa2G\xc5W\x16\xfev\xfcpS\xdeSvs\x1f\x9c\xcbK\x92\x1d\xd1 \x0f\xd3S\xef\xfc\x0d7\xe0\xa9\xa9\x02\x94\xd5)O\x8cb7q\x9f7o\x15PQ\xf0\xb4Y\x10\x89\x82g\xcd\x82P\x14|\xd3,(D\xc1?\x9b\x05\x99(\xd8T%f\xf6b\x8b\xbd(\xdf\x94:F\xdc\x9ey\xf5\x06, *T\xe0\xe9\xb1.\xa8\xaf\x88\xaf\xd6\xf4\x0dlF\xd8\x05\x81\x9f\xb1\x95\xee\xca\x9e\xe5\xb6k\x9e\xee\xa6\x0f4\x10\x1f\xf6\xdc|\x1ee\xdc]\x95\x15\x84\xcd\x027\x0f./\xd1Twy\x89\xccb\xd3\x87T\x01\xf2;\xd3\x88P\xd0%\xbb>\xba\xaf\xab\xe0\xc5\x82\x93\xb4\xb4\x88\x99 \"[/\xaa\x8554]\xc3\xe4`lM\x0dM7<\x01\x0f\x0e3z6\xa7\xb7f\x92[Zmh\xe6\x01,;\x87\x18\xf7Et\x94Li\xba\xe01 ;\x88\xc2\xd2\xa1\xb1\xeds\x0bz\x15\xc5d\x08[OWm\x96\x8aqz\x96\x91N:q1\xed\x84\x98wB\xc4rg\xf8D\x0cXx\x08\xc9\xaes\xba|\x0c\x9a\xc2\x1eh\xfa\xaf\x1e@Q\x0e@\xa7\xb3\xd5\xde<|\xf0|\xe5*\xc2\x83[\xb5Y\nS\n\xa3\xcbe)\xec\xc0\x18\xdf\xfe\xbd\n\x8d\x0fy\xf0SF\x13\x14\x15\xc2Kn\xa1D&\xad\xbc\xbd\xa24&a\xd2|\x8d\xe1\x03\x9b/\xb9\xe9\xb1\xf1\xf65M\x17\x1a.-u\xa8{\xa6*\xb5T\"*KZ:Q$JZzW(\xab\xe8\xb4\xa8{\x9d\xde\x95\x89\x82\xd67bQ\xd0\xd2\xbb\xb8\x94\xd7\x14\x88\xa6\x08>n\xbc]\x8aF\xb6\x9a\x8dp\x01\xed\xdb\xc6\xdb\xb9\x04\xdfj\xf5\xf3F\x16\xb5\x86\xb6\x90%\x9b\xdf\xb4\x061\x13\x89\x8a\xb5\n\xe1\xfd\x97U\x08\x97\xe5\xba`=\x08\xa2\xecT\x84\x85\xf6\x95\xa20\xb9\xf7\x1b\x90\x96bN\xad\x86\xa6x\xa1\x0f7\xe5\x9b8\xcar\x15\x82\x91\xb5\xedw\x98\xdc\xd7i\xf5\xaa\xe5*t\xa3w\xf2\xa1\xc9\xfe\xf9\x86\xb6]\xcd:\xff\x1c:\x7fK\xb5\x97:\x7f\xd6,\xd0\xe9\xfc\xaaF\xfe\xa9:\x7f\xac\xb4U\xe9\xfcuK\x80Q\xe7/\xd3J\x1dD\x93#\x1eG\xb6\x05\xf9\xd7\xa9\xff\x93([\x86\xf9x~\xc8t\x860\xe6\xceP\xc6:\xdc\npc\x07\xe2^\xd2\x92\xc0\xf5\x1a\x17\x1aCS7\xe9\xe4\x9d:\x16\xff\xf7\xd9J\x90\x84\xbb\xd0\xc3\x97Z\x17~:\x90\x18\xd5\x90h\x91\xd8W\xb0\xcb\x14\x08;5\x1c\x0e\xe4AN\x7f\xe2\xd7\xaa9{g?]\xd3a\xbb\xf4\x8b\xb4|.F\x17\xbb\xfc~i\xe9\xfe\x18a\xb8\x9a\xbf\xe0\xa6\x80>*\xa9\x0f\xb4=\xe3\x06\xc6\xd3\x06\xac\x9di6c\x02\xfa\xb88x\xa8\xc5\xc2\xe3\xf9\xaa7_\xc0\x18\xb6\xa1x\x01\xe3\xf5u\x0f\xe2\x8b\xf1\x07\xb5\xe6\xc5X\x13kQ\xc6Y\xc4S\xe5\x1d\x03\xf3\xc3=\xae\x93\x01\x8e\xc38\x16\\\x90\xf8p\xc1\xea\x96\xc1$\xb8\x9e\x96\x96\xdbQ\xaf\xc3\"\xe9\xae\xaez\x8er\x92\x17\xfbh \xa2`\x92\x80G\xec\x0e\x18\xa0\x88\x81X\xbeC\xba4,<\xd1\x9a\xec\x15\xe3\xb2\xf2\x9d\x90\x90\xb4\xc7Sl\x1c\xa3\xa4X\xac0\x16\x81\xe7\xd6\x17\xf5\x1f@\x9bvK\x14a\xf4\xf4%\xe4\x89\xbf\x81/\xf6c?+\x08\x0f]\x8c\x96\xf6b\xb4\x9c\x87J\x99\xb8\x8b\x87N\x08\x8f\xf3d\x8c\\\x07\x82\x85\xa6\x01I\x8a\x85\xd92\xcd:G93\xdd\x15\x7f\xb8\x1e\x0c\xf1\xac\xb7\xe82U#Ou\x1d~\"c\xf3s\xea`;V\xbe\x02u\x8b\x1a\x95\x91Jw\xc1\x89\x12\xcc\x07\x84\xd7\xab;\xee%`\x90\xa8Zm\xda\xa3\x96\xb8\x9b\x80\x82ff\xe5]P\xd1\xaceF@\xb69Z,\xf3{q\xa5b\xcd\xc2\xa2\xa0\xc6\xcb\x90\xc8\xd5\xfd\xc0X\xcft\xbb\xd3\xb8\x86b\xdc\xfch\xba8\x08\xf3Pn\x80\x11\xba\xbb\xaf\xb9\xce\xeb\xb2 JD\x0c\xda\x8e\x83\xa3\xdcu\x0e1\x91\xa4]\x10\xa9\xed\xb7b\x8b5Q\x89\xd5\x82\xc6\xea\x0eEs\x96\x9e}\x12\x1d\xadNC\xad\xa9\xeb\x92\x90e~\xaf!\xc4\xfa dk\xd3\x84\xa0\x85|\xdf\x03Q\xcb0\xcbni:\x91\xb8\xe7R-CFU2\x94\xb9\x07\xffk\xf0\xd9\xbd\xc2\x16Q\xf2\x06[\x1b\xda\xfcK'\xe4\x8a\x16\xc9\x98\x9cG\x0bB\x8b|\x08\xcf\xbe\xb1@+\xa1\xe7\xacb\xe9_0\xdb\xad\xd7\x9fU\x02\x95\x16\xcf^\x02(1\xdc]\xef-dJ\xf3\xe8c\xad\x1e<\xae\x06Bc_\xcc\xd1\xf7\xf5\xc2\xdf\xaa\xf2R\x1ady\x98\x0b!\xc0(\x9c\x1d\xe6D'\x9cY\x1c\xae\xd2 #\xf9\x19k\xba\xba\xdao\x8d\n :hg\x91ri\x88Kj\x19\xc9\xb98f\xacd\xf2\xefW\xb0g\x184w\x98b\x03\xef'\x8fj\xc6k\xbd\x1f\xb0\xcax\xe5\xa5<\x11\xce\xe4/\x19o8\x994\x07\xbb\xcaX\xfb\x04\xc4\x10T\x06;p\xe9J\x8a\xeb\x12\x8a\x04\x06\x048w\xcaslau\x1e\x8d\x80\xd5U\x10\x0d\x1az`\xa1\xdfx\xff\x82\x01\xe2B7^\x9c\x15\x1f\xaefF\xdbH\xed\xe5_\xa3-\x95\xd6\xd7\xf7Q\x1c\x9f\x921\x89n\xf0\xb4,\xeb\xa1@\x19\xe7J\x92\xde\xda\x8e\xd0\xa2\x94]\x8f\x89\x7f\xfc\x9d\x9cN\x9bB\xa0\x92\xa3~*:\xf9\xd9\x17\xb2\xa0\xdau\xc4>\xba$?=\xec\xa7KR\x84\xedV\xed\"\x84\xebR'C\x84\xeaR'\x0b\x842\x99OC\xbc\x11,\xb4\xbeP\xd5\xfa\xec\x06\xd4\"\x88\x92)I\xb9\xf8\xe0FA\x94\x93E\xd6\xedhV?Q\xe9\xe1s\xf6\x8ag\xf7\xef\xf0\x1f\xcbP\xb7\xb5\x88W\xd0\xa6h\xb3&\xbc\xec\xd2v\xe7\xd2\xd3\xed\x13\xb5\xddy\xd7\xc6\xaeH\xd5\xe1\xeaR5T\x92\xb5R;\xecQKf\xdf\xed\xbe\xb7/\xd6\x9c\x85\x96\xa1\xad=\x1b\xa2\xbf\xd7\xa0kz1\xfd\x9b\xf5\xe2\x8ey\x14\x0eW\xdc\xedc\x8dGC\x99\x04\x98]\x91\xfd-\xfet=\xd8\x86\xad\xea^\xca$X\x84KE\x10\xf2\x81v\x11^$\x84\xe6\xb4n\x96\xcf:.\x96\xc9\xd9\xb75\x0f\xe2\x13K\xdc\x10xZ\xd7\x9e\x92\x8b|J \x06\xaf\xf1\xf0[/\xd6J\xb6p\xab\x80'\xeb\x82j\xe5\x9d\x8f\x8b\xe5\xc5\xe6\x07\xbe\xe3\xc1:P\xcb\xdd\xe4\xce{Y\x1dsi\x1f-2\xa2\x0e\xa2T}\xbf>f4\x19\xf0\xed|\xc0\xf4\xeb\x01\xdb.\xad\x0e\x81\xa6\xeeY\xdd\xcd\xa0\xfbd\x05Z\xa7+\x1dF*)]\xf7]\x81\xfd\x04{\xf9\x94$\xa3\xaaO|)\xd8)\xc7\xde\x1dy\x9e\x13Y\x96\xbf\x19\xc7V\xf3\x124\xa6\xf6*O\xe0*O\x06\xd9\x02\xb4\xb3<\xe0\xfaH\xc7\x86K\x93\xfd8\x1a_\xf7\x10^\xd4\xa7\xc4^\xa5\x87\xb9]\x88\xb3\x11\x9d\x03\x03pL\x9e\xa8^\x90S~\xf4\xf3X\xd4\xad\x84\xb6p2\x01\x07\xd6\xab\xcd\xab\xc1\xf8\xb8\x1b\xa1\xf1[%B\x91#\x08\xbdM?06\xee\xbd\xc9\x04\xd8g\xb5\xc3\xef\xb4\xb4\xbc-R\xb2\x8a\xb5\xa5r;\xebeo\xf9\xdf\x81\xdf\xca\x07~\xabj\xa9\xff;(\xd3?\x7f\xd1AY\x97\xceB{\x1d\xa7\xd5\x0f\xca\x0c\xa7\x0bx\xf2%\xf4\x9b\xb4\x9f~\x13\xf69\xcc\xea\x10#\xc2\x9e\x1ba\xba\xbaX/Dz\xa5f\xda\xcfX.\x82\x08$\xb6\xdbFuA\x9d\xbb\xc6MS\xba\xf8\xe9\xccs)jYx\xff\xd3\xc9S\x9e`e\x1a\xc6\x999\xe1\x0b\xe8\xa5\xf9\xb2\x1d\xdb\x81\xd7\xaaB}\xb7I\xe1\xd3L\xe4\xa5\x07\xf1\xa3\xf7\xec\xde{\xb2\\\xa1\x9fl\x1f\xb7X\xc6\xd9\xc2\xc9H\x8esrN\xcf\xc2\xc52\xeee#\xaf\xbc\xbb\\\xf6\xe5\x19\xdb\x1cxm\x8e'\xcf%5w \xfd\xdd`\xa2\xb5\xcb\x1bEF\xd2\xf2\x990\xb4:\x0f\x93ILNVi\xfb\xa6\xccw\xdc\xed\xbb\xa1\x0c^\xe7\x03\xe8\x1b\xbd\x85\xe132\x80\xcf\xe9y\xb9V1\x81\x86\x9dO\x9d\xc3\xf2e\x9bdtw\xb4\xeb8\xf8B\x86\xbc\xffbN\x96\xbb\xce9\xb9\xcb\xf7R\x12>\x92\x9b\xd4\x0c\x0c& \xda\x93\xe50R\x9b+\x06\x04c\x1d\xf6\x08\x9e\xc4\xd8M\x16\xfda\x0d\xcfkF\xbddX\xac\x05d\xc3\x1fi\x94\xb8\x8c}x\xfd8\x97EGm\xb0\x89\xfa\x06\xa0\xad\xf5(w\xbe.\x11\x1f\x81\x1fu\xe3E\x1e\x86\xe2E\x87\x7fz\xc1\x818\x91F\xa7\x89\n,\xad\x17\xf0\x10\x92\xb58\x02\x8f\xef\xc2g\xbdt\xd3\xec\xa6\xe9n\x8c\xf8h\x98e\xd1,a\x8c\xcc.\xa6\xd7\x92>o\xf1\xfc\xceMuE\xe4y\xb6\xef\xf3\x95\xa6bJ\x03]~\n\x03'&=\xf3\xc2c(8\xb4Ta\xac\xe9\x1dH.R]\xa0\x89\xd6\x1b\xc9\x90\xeb$X\xa7x\xda\xc5\x9aK\xd1\x83XO\x9ck\x19\xfe7_@\x02\xdbj\xa2\x7f3\xf6@\x99\xb9\xfc\"1`\x0e\x90P\x99tG\xd2\xf0\n\x05\x8a\xdaO\x91|,e\n\xdb4\x9a\x15\x12hm\xb3L\xda\xc7P\xce\xe3\\\xa6\xc1m\x1a\xe5%D\x99}\xaaI\xa7\x845xM\xee\x19\xfe\xf5\x0b\xbe\xff$\xa8\xd6X>\xa1V\x85\x91\x07\x01u\x15\xd2\xe0\x99\xc3R\xf1\x9eG\x07l{\x157\xb6\x9b\xe6\xc5r\xa6\xd8\x14<\x02F\xbd \x14\x05[\x9b\xdf|\xab\x0f\x86Q|\x91\xbbOn{\x99\xf7\x92\x8a\xb5+{\xad\x9f\xb3\x04\x8f\xf5T\x8b\x80\x95\x9b\xc2\xa1\xed\x87IBs`\xeb\x12B\xce\xfb \xccj\xa1\xd8\xdas\xd2!\x90'}\xbd:\xb0\xa3D\xed\xd9)\x99\x92\x94$\xe32D\xdc<\xca`\x1ef\xc9\xd79\\\x11\x92@\xc4\xaf\xb1D\x19\x99\xc0\x00\xb2bIR\xd7\xabA\xb0\xa1\x90I\x87\xf8\xb0\x86\xc7\x0dJB\xc9Z\x10\x1fm8\xbb\\P\x81\x86F\x0d\xfa\x86X\x843\xc2\x98\x1f'\xfa\x93i\xcb-\xc7\xa2y$\xab9d\x93`I\xd2,\xcarSX\x05\xc9\x14\x92\xee\xd3\xbdd\xa5\xe3kU\x1f\xd0o,=s\xaf\xb0\x1e\xd2~=dO\xe9\x06\xf7\x92U\xe1\x82x\xe9\xcd\x86\xe1\xaa\x12\x9aGS\xbc\xe68,\xb7oxYU|\xf2\xa4\x02J\xf1\x88\xa8G\xbe\x066\xd8!\x08p1\xf8\xaeZP\xe1\xcb\x92\x91\x0e\xf4\xeayUd29\xb7\x89\x12\x13-%?\x93\xfb\x03zk7\xa0\xca\xa7\"\x0f\xa9C\x8a\xda\xfa pFI\xceS\xc20\xf1\xfe\x9a\xdcsdNi:&\xc7\x12\xed\xbe\xc85e0\x10\xb2.\xbe\x8a\x8b\xf4\x91\xfdcUM\xf4\xbbb?\xb8\x86\x80\xf0\x11\xe9\xd7\x1f\x1eQs\x1b6\xbd\x92\x86\xba\x84\x0f\xf9\xc8\x05^\xc4\x06/F\x83V-\x03\xfc\x8a\x84=\xb5\x0f'\xc1\x84\xf2\xf1Z*\xdb\x97^.L)\x8a\xed\xa5\x1b\x0d\xf2I\x82(\x13\xbc\x8e\xdf\xd1a\x02L\xd5)\xab\x9f\x19\xdb\x07\xcd\xcb\\\x87\xddGtg\xd3\xd7\xcf\xbf|\x90\x0e\xa6q\x91\xcd\xfbN#TS\x99\xf3\x9a\xb6\xb4\x13Hf\x8c!\xc7\xab\xb4\xafEk.\x1a\xb2}NOXz\xea\x97\x93\xd4\xa7cI\xc3\xc4$\xce\x18D|Z\xe5r\xad\xfeS\xca\xba\xec5\x9f\x98_\xa0\x86\x03\x1b\xc6J\x0c\xe3^$\x91d&--K\xec8\x81\x04\x0d\xb31\x7f!Wx\x14E\x9e\xa4\xac\x08\x0c\xa2X\xfe\xfeR\x0c\xe8\xf1i3{\x07\xdf\xc1\xa9\xee\xe5\"(\xdd\xe6\x98<\xd6f\x8c\xd8\x8en_\xa9Aj\xcd\x87\x9d\"\xa81r1\xb2\n\xf4=A\x07?\x83\xe8|\xc6\x84O w\xcb\x94d\x19\x93\xda\x17E\x96\x03\x89\xf29I\xe1\x8a\xf0\x06h\xaa\xc8\xd2>\x06\x1dv`\xbd\xfc\x90\x862I\xa5\"U\xba?\xe7N\xae\xc8\xdb\xa8\xe8Pz\xd4\x8ei\x92\xe5i1\xcei\xaaS[\xe4#g\xc0L\xef\x95F\xda\x8e8\xa0>R\xff\xb4\xbbA\xa9\xba\xec\xd0\x94\x8cICK\x92{\xbb\x02\x1bYM\xa2\x86]\xd0\xbe\x17\xf3>DUN\x8a\xe5l:\xeb\xa4\xc3t\xcf\xf2T\xa0a\xbd\xf2\x81\xf630\xbf\x8f\xe2\xf8S-\xcch\x95\xab\x8b!\xaeb`n\xdc\xbf\xe8\xb2\x97X\xac\xc9\x7f\x89K\xac\xdcH;\xb7\xd0D\\\xc6\xab\x8dF\xbf}\xe2\xe8k\x8b\xff\xcf?\xcb\x8c\x85\xb84+g[\xc5\x01\xb7Q\xd2[\x8f1\xddi\xf6!\xa9<}\xb5\x93Q~\xac1}I\xb7\x01\xb5\xe74\xbdK\x16\x9f\x83\xbc\xb8t#{k\x92Xzw\xf1o8\x97\x10\xb9\xbe\xec\xf4\xe5*\x91\x15J\x8a\x04R\xb1k\xbfM\x82\xec\x95\"\x9b\xbc\xbaG\xf5\xc6\xe68\xc3\xa3-TUNP\x1f\xb1\x9c\xef\x8a\x90\x0fB\xab2\x03\x16\x02\xd0\xde\\\x86PQ\xb2,\xf2S25\xc3\xc5}\xcd1\xf2\x916\x9c\xff\xf4I\x1aUZ\x7f\x89\x07y\x19\x96<\xf5\x98\xb8\xb3\xa9XA\xec&aR\x9a\x84\x13n\x12\xc6\xac\x85\xf6\xcfK\x1d\xca\x08\xf4\x80~/\x8e\xa0\x18\xc7\x07G\x12\x85S\x1aQ}pJ\xa2\xc0d\xd1u\xa2\xc0\x83\xfb\x16Q4\xde\xf2y\xe7\xed\x8b\xb9\xe5?\xe4k9G\xd6\xd3\xffqG\x0cKt\xf3\x86]\xcb\xdc\x95_/\x1d\x01\xc4o\xfd\xbe\x06C\x08\xfb\xb6g\x88\x17\x0eC#\x910\xba\x98v\x0c\x89\x95\xd3\x8e.0\x1c\x96\xe3a?\x8c=)z\xb5T\xadB\x99\xba\xb4(r\xaeueb\xe8\xba\"\xf3=\xd8\xd6\xdd\xd7\xad\xcd\x06D{\x93h\x8b\xc2\xad-\xa3\x0d\"w\n\xd9\xc1\n\x97\xf8W\xc7\x99\xa5\xe5\xae\xa0\xdc\xd3\x9d\xd1\xdd\x92\x8cs2QM\xfcmBIa\x07\x8e\xc3\xe3v\x01cz\xce\x85\xf0\xf09\xbb_\\\xd1\xf8\x83\xa6~\x04;\xb0\xf1\x7f\x7f\xcf\xd6\xff\xfc=[\xffjc\xd6\x86\x08\x11\xe2b\xb0\xfea\xf3\xeebs\xf0}8\x98~X\xffjC\xe3\xe6T \xe4\xe6\xd5\xc5\xe6\x96\x01\"\xe3\x10\xf4bs\xf0\xad\x01\x841A\xcc\xad\x7f\xa8\x93\x1d\xd8\xde\xaa\xa4f\xa9\xe9\x81B\xe7:\x11NM;R'\xc3\xd7\xed\xa6\xa6\xfa\xa62\x12OY\x0d\xf5\x7f}\x9b\xac\xa4\xdd,\xdb\x80\xc6x\xf6\xcb\xfey-\xe7\xd9\x91\xd6\xa7y\x949\x9e.\xec\xf2\xa4R\"+\x16,\xd3\xe4\xb4\xc1\xe7\xb0\x03Ga>\x0f\x16\xe1\x9dF\xac+K#\x8d\xf8\xd2\xef\xb6'\xef\xf028`\xdbNBou\xf2\xa7r^\x07\xea\xb9\xd8L\xaf\x7fH\xddC&\xba1\x1e\xa8\xac\xad\xf1\xac\x18\xb5 \xd2d\xddiz\xa7\xea{\xa3\x89\x9e\x08\xd2\xac\xa0\xc9\x97nK\xd3\xc2\xeat\xebX\xa2\xbe\x93\xe1\xba\xab5\xde\xed\x16\xd0hD\xa0BC\xaa\x066\xc0Z}\xf2\x04&B`\xf3@{i\xe5AM\x13\xa4\xb1\xcdc.\x15KF\xa9\x9b2\xa8PmBdF)\xdc\xbdQ\xe5/\xffF'U\x93\x17\x1a\xec\xc0\x8cm\x86\xbb\x90\xc3:\x8f)\xd6u\xc6\x0c\xcd\x0cJk\x9a)\xac\x12\xe6\x13\x18\xc2\xba\xe6\xf3D\xb8\xdc\xf2\x84~\x11\xe6\xf33\x1f\x97\x16\"\x1d\xb4\xe5,\x90\xcdp&\xc1`\x17bW\xe4!u\x9f\xa2\x86\xba\x0bOa\x08\xdf1l\x84\nX\x8a\xfdk\xd0\xb3\xfaK\xf5\x8ci0\x17\xed\xa1>\x1e\xd1\xf9\x10a6\x99\xc2\x87\x0c\x85\x13\xf4w\xd7\x0b\x1cSn\xb2\xd3\x96--e\x13\xb4\xd9\xebIH\x9fpLo\xa8K\xbc\xc6v\x02\xea\"\xbe\xea\xf6w\xb4\\_b|2\xb2Jv\x8ca*\xe9\xdbx\xa0\x17_\xa8x\xdcr\x9e26\xae\xa1Js\xa75\x91;\xe5#;M`\x00\xb1\xb5gJ\xc0\xbd\x98\x11W\xc2T\xb6\x9c\xff\xb5\xcdu\xb7%zB\xc0\x00\xc6\xac\xac\xad\x04\xd8\xfax\xdb\xa9\xf4/l\xe1\xff/k\xf9\xc6\x8c9\xca\x18\xd5f$\x17\x82\x99{\xeb\xf7\xdc\x05K_V\x18\x80\x8b\xb8\xea\xbe\x9c\xba\x84]\xb8q\x13\x1fBYi\xec\xa1\x05\xdf\xb8a\xae6\xab\xa3\xce\x9d?S\x08i\x02\x98\x1dk\x17\xae\xf89\x82\xdb\xa4\xb4b\xb5\xaf\xdf\xf5\x99/\xf3JHx\x1c\x06\xcb\x8cR\xd5\xa5\x8c\xe7\xe4\xe2.\x10L63EJQ\x1bP\x086\xf3\xdaV\xfe.\xb3\x86\xa80\xe6_k\x13N\xee\xf90\xad\xf0\xa9W\x14\x01g\xd6F,\xe2^\xb42c\xed\xcf\\\xb9\xa6\x00\xfb=\x17l\x86b\x8c\xaeq\xcf\xd7\xf4\xdc\xe8\xc5\x95c\xe4\xe8\x1ccbn\xfa0s\x85\x15\x06\xf7\xec\xb54\x88 \xe6f\xe0Y\xb0]\xb6[;\x8b\xf0\xee}\x18\xe5\xdc\xfd\x8cq\x98\xb9{\xef\xa6\x81x-[B\xc3{\xe8\xe3&\xee\xe4i\x18\xc5\xc8K\xd1em\x17\x9b\x96/a\x08\x13L\xe0\xd7\xffhT\xb1\x00#\"0)\x98\xc4B&o_\xf1\xebG\xb1X\x15\xd5\xd2ic\x87}\xbd\xf7\xb9\xafn2v\xa1\x80!\x8c\xdc\x85kH\xf0U{\xa9\xb8\x87IW \x1f\x12\xf7\xd9\x96\xa8\xdc\xa1\xe5I\xe7\xc2z\xf7\x9c`#\x8c\xe3\xe0c\xe6\x0c\xe1\xf9\xf3\xe7~\xab\xb0\xc8\xe7\x1b!6\x9aq\xa8\xa7\xcf\x9e\xea\xa1\xd0\x88\xc7a\x9e}\xffL\x0f\x93\x92I1&i&\xc1\x0c\x1f\xccd\xe2! \xf7\x8d\x01nI\xc6\x83\xdb4\\\x0ej]|\xf6\xfd?[\xf0\xfc\x10)k\x8e\xa5\xdd\x01 8'\xf1\xb2\xec\xe9\xd3g\xed\x01I\xc0\xda\xb8\xbf7\x82\xd5\x87\xfe|\xb3\x8dE \xd9\x18\xfd\xf3\xcd-3(C@mH\xcf\x9b&\x06'\xd8\x98\x10\xb2\x1c\xc4Qr\x1d%\xb3\xfa\xb8\x9eo\xb61[\x83V\x06\xf7|\xb3\x8d\x83\x1al\x1c\xde\xd3\"\x97\xc0m\xcc\xd6\x80\xcb|K\x83<\x9c\xe1\x1c.I\x1a|\xcc\xee\xb0\xf2\xb7}+7+\xb6'~Bo\x93\x98\x86\x93A\x91\xc6r\x96\xbekA\x914\xad\x93\xc6\xd6\xd3v\x1f\x18\x10\xdeG\x18\xe4i\x98dS\x9a.H\x9am\xcc)\xbd\x16-?mO\x95\xa1R\xedGB\xf3\x01\x9d\x0eP\xc9\x16\x0d\xb5\xc9\xa3OC\xcb0\x0d\x17$'\xe9\x80&\x84Nec\xed\x89\xeb\xd3\x18\xd3d\x96\x03\xe9\x0e*\xdbj\xcf+kK]\x04[\xedE\xc0@\x1ak\xffi\x9bN\x19Ts\xe9?m\x13(\x8f\x9dP'\xcd\xf6\x8c\n(\xba\xccxV* \xd9\xee\x1c\xa7\xdb\xc6\xce\xa0YF\x02N\x1d\xea\xd36\xbd \xa8\xe6h\xdb\xd4$\x00[\x03n\x0f%\xa6\x8dm\xe6\xbb6Rh\x98=knn\xed\xceq\xa8\"\x9f\x0f\xc8]N\x92\x8cAo\xe0\x06\xda\xdct44\x83\x95\xcb\xe3\xc5l\x83\xf1\xa0\xabp|\x9d\xc9\xd5\xa7\xc1F\xb3\xce<\xcf\x97\x03\xd6\x01YG\xc3M\x9au\xd4\x89\xd6\x90C\x13\xbc\xda\x1c\xd8vQ\xf6\xad\x8dVs\xc5\x8c\xa7X+\xfb\xd8\x8d\x8b\x94\xfc\xbf\x82d\xf9\xe0\x8aN\xee\x07d\x12\xe5\xb4\xdc\x93\x9e\xb5\xf7\x04[\xed\xb2\xc3m\x8aiV\x13\xdd\xac\xb2\x1d\x95\x9fl\x13\xaf\xa1n\xf9\xb5\xf6\xb2\xc0\x1a5n\xf1\xcc\x80\xfc\xda\x04\x19F\xdb`\x7f\xcf\x0d(m\x92\xe1s\x03y \xe3Sh\xb8E\xbe\xedmJ[OO\xfb\x86\x8f\"\xb0\x82C\\HQN\x16%\xde\x0d\x0b\xa0YQE\x98F\x04\xd1\xd6Q\xa38p\x1b\x93D\x91\x01\xe3\xcd\x06\x16az\xcd\x98\xa1\xfc\xaea2[\xd5\xe8\x84\xc4r\x80\xcf\x0d\x84\xd5\xacD\x938J\xc8\x00\xaf\xb6\x859M\x07W\xe1dF\xe4\x97\x0d\xb4\xd6l\xa4df\xd5B4\xac\x89f\xcd\x1b\x9e\x02r\x90\xe5\xe1bYV\xd6\xec\x00 \xd6\x8aINjs\xb2\xd5\x1ef\x86\xb71\xb3\x8d\xa9\xc0\xdf\xd6\xf7m\"\x910\xb5\xad\xba=\xbd\x8c\x06\x9b\xdcF\xd3\x18\x83R[\xd2\xec\x94\x08\xd3\xe04\x9a\xcd\n\xc1\x1aD\xfeT#U\"\x9cF\x9c~\xde&k\x99\xd5\xeecc\xb4m\xc8\"\x8f\xe2\xba\x8c\xdc\x9e\xc4\x9b\x88\xdc\xd6`\x9e\x1b`RJ\xf3A\x94|$\xe3\xbc\xec\xdcw%\xa46]\x0d5^\xd8I\xdc\xa8fly\xd0\xd4\x8e\xda\xb5\xa5\xad9\xbd \x8d[Z\xfc\x06M\x0e\xeb\xb0U\xbb8S\xbf43\x8d\x92 ,\xf8\x0d\xa1\xaf\x1dX\x07\x02\xeb\xe0|\x1d4\x0d\xbdR\xd7V\xfa'\xff\xa2\xc15\xb9\xb7\xe6O\x16\x95\xc5\x11\x0e\x83v\x95\xcb[\x0f>\xd0 %\x19\x8do\x08St\xeb\x17\x1d)+\x8d\x98\n\xbe\xb5\xf9\x0d\xc7\xee\xc3\x07\xef\x1f\x0f\xde\x8b\x7fll\xfc\x1f\xc8h\x91\x8e\xc9Q\xb8\\F\xc9\xec\xdd\xe9\x9b\x9d*\xc3\xe1\xe0\xaaH&1[\xe7\xc1\"\\\xfe\xff\x00\x00\x00\xff\xffPK\x07\x08-\xe3\xb5\x97=9\x05\x00\xf7\x0c\x1b\x00PK\x03\x04\x14\x00\x08\x00\x08\x00\x00\x00!(\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1f\x00 \x00swagger-ui-standalone-preset.jsUT\x05\x00\x01\x80Cm8\xec\xbdys\xdc6\x9a0\xfe\xff|\x8aG|w\x152M\xd1\xdd\xad\xc3:,k\x1d\xc7\x9e\xf5\xbb\xf1Q\x963\xf3\x9b\xb7\xa3UQl\xb4\x9a1\x9b\xec\xe1!Y\x13i?\xfb\xaf\xf0\x00 \x01\x10 \xd9\xb2\xb33\xbb5\xacT\xac\x06A\xdcx\xeec\x0b\x16U\x1a\x95q\x96\xba\xa5\x0f\xc4\x83\xdf\xfe\x00\x00\xe0dW\xbf\x92\xa8t\xe0\xf4\x14\xca\xbb5\xc9\x16@\xbe\xac\xb3\xbc,`{\xdb\xf4v\x95\xcd\xab\x84\xc0\x19\xff#\x10\xb5O\x81\xb8\x1e\x1c\x83#\xba\x91?\x9a\x93E\x9c\x12\xda\"\xfb+\x08Ws8\xe3?\xdc\xd9\x05\x0e\xe8\xb8k0g\xe2\xaf\xe0\xfc6\xbc\xbe&\xf9\xcfo\xce\xcb0\x9d\x87I\x96\x92\x0f9)HY\x0f\xa1\xec\xab\xf3\x87\x07\xb7\\\xc6\x85\xdf,\x89X\x8e\x9c\x94U\x9eJK%^\xd0\xe7&\xcc\x81\xc0)\xfc\xf6p\xf2\x87\xbaPT\x85\xd4\xcd\xe5\xca\xf4\x89\x17\xe0\x92Y~\xe1\x89v\xe9\x0f\xb1b'JU\xdavLG7\xcb/h\x17\xcaKl\xeb\x18r\xbfU\x9a\x1c\xc3\xd6\xa4]\xcc\xbb8\x86\xdf\x1e\x94w\x0fj\xa7|T%\x1dU\x14&\x89\x1b\x8b\xc1\xf9\x10\xfb \xfdJ=\xfa3\x81S\xd8\x1aK/\xea\xd6\x9anx\x9bi\xb0\x82S(}H\x83\x88N\x8b\xfe1\x87S\xf5\x10\xfa\xd0Z\xb24\xc8\xf8\xf9\xbc\xbf\x87\xf7x\x1c\x02vL>\xe4\xd9\x9a\xe4\xe5\x1d\xff\xb2\xbdBQ\x96.\xe2\xeb*\x0f\xaf\x12bY\x96\xb4Z\x11\xf1~\xdc~\x7fM\xcac\xc8\xd5\x15\xf3\x9a9\xd29\xa4\xca\x1c\xf4\xd1\x8b\x13R\xd2\xa3^\x06\x97\x97\xa4x+\xeeK\xeb\xac\xc9\x8f\xd8 :\xd7\xb0JJu\x0cp<\xec\xeb\x01{\x9d\x06s\x97\xf8\xe0\x84\x0e]d\x1f\x88:\xbdL\xdf\"\xbd;\xde\x0c\xdf\x99u\x9e\x95\x19\xbd\xa9\xc12,\xde\xdf\xa6b\x8f\xd8i\xc2\xef\xd5\xf6\xd7p\n\xce\x93y\\\x94\x8e\x0f\xa9\x9b\x06\x14pL\xc7\x07\xac\xda\x83;\xd3\xceG*\xf7\xefT\x05\x81\xa2\xcc\xe3\xa8tN\x94[\x99\xc3)\xa4\xee\xfe\xd4S\xf7\x94^\xa8\x99\xf39N\xe7\x8e\x0fNN\x8a,\xb9!\xf4\xcf(K\x8b2\xaf\":\n'N\x8b2L#\xf2~A\x7f\xads2\x8f\xa3\xb0$\xec\x935\x05\x1b)\xd6\xe3[s^\xde%\xf8\xb2\xa0\x7f\xbcH\xe2\xb0 \x85s\xa1\xf6\x9ca\xcfE\x14&a\x8eu\xc9_+\x92F\xf8\xdd*\\\xaf\xe3\xf4\xda\xb9h\xe6PJ`\xb4s\xf9\xe9dS\x1f\xaa\x936\x9c\xa1\xb7\x8c^\x9a\xdf\x1e|\xb1=\x9f\xc9]\xe1\x12/Xd\xf9\xab0Z\xbau\xd3\xadvE+;\x138==\x858\x88\xd39\xf9\xf2~\xe1\x12\xcf\x83r\x99g\xb7\x90\x92[\xc8\xdd\xef~N?\xa7\xd9m\n\xd9\x1a\xa1\x9e\xf3\x1d\x8c\x80\xc0\x08\xbes .`EJ\x88S\x06\xd8c\xac\x90-X\x9d\x92\xd5\xf9\xcb\x8b\xb7?!l\x0f\xbe\xf3\xb4\x8b\xe6\x03\x05\xcaA\x19^3\xc8\x81\xbf\xe8\xe6\xd1\x99\xb1?\xee\xef!\xad\x92\x84\xbf\xe3\x1b\x8a\xaf\xc5\xdf\xf7\xf7\x83\xae\xca\xd6X\xed\x9c\xb7X\x9f\x0bl\xb3\xf9%\xb7\xda\xba\xf4`\xbd\x81\xbc\xd5\xe6\x80a\xb3\xd2Ou>\xf5\xd1\xc3j\xcd/}\xd6\xfcL\xf2y\x8b_j-\xf9\xb0bE\xa5@\xad+\x1fd8\x057\xc5\x0f\x94\xd2\xfa\x83\n\xf1\x9f\x8f\xbf`\xeb\xf4\x14R\n\xea\xe4\xf3\x96\x1a\xce\x9bq\xcd\xd2Yy1\xf0h\xd2\xa7\x9a\x9d\x97y\x9c^\xbb\xc4\xa3\x18\xb2lUzh\x1f\xa8\xca\xf3\x81\x1f\xe9\xac>\xd2\xf5\xb9\xb2\x1dm\xd0F%\x1e:\xba\xc8\x87\x85\x0f\x89\x0fk\x1f\x96\x8c\x06\x81\"x\xdd\xa6r\xe83\xaf+\xfc\xd1\\\xe1\xa6\xaepn\xaepWW\xf8`\xaep]W\xf8\xc1\\\x81\x12\x88\x94\x0b\xc8\xe1\x18n\xe8\xbf3\"N\x17A\x1a\xf8\x81\x12\xf3\xae(\xfe\xed\xc1k\xe8\x0ds\x8b\x97\xbc\xc5\x98\x9eB\xd1Z\\\xb7f\xfe\xe8\nN\xe1\xb2i\x19\xbf\x91\x7f\xe3\xa7'\xadO\xe9\xf5w#Dvx\x98\x10hz\xb8?\x94Lv]\n\xec\xb7\x96\xf4\xdd\x8a\xfe\xef&\x8b\xe70F\x90\xb9\x9aE\x17\x1e\xe5\xa0\xe0\x18Ro\x16]\xf8@\xe9\xa2kZm\x01g\x10\xba R\xc6\xc7p\x87L\x98\xe9\x0e'X\xef5\x7f\x83\xf4\x96\x0f \xfd&\xf1Y\x87\x95\xbb\xf2\xe9\xa1\xa0P\x1e\xb7\xe1g\xcf\x87\xcbYt\x01[\xa7\x90\xe0\xcdu/\xb1\xc6\xda\xf3YOW\xf2[\x17\x7f\x9dB\xa2\x81\xd5f)\xf2 bw9\xf6\xe9I\x83S\x98\xd0?\xfeHI:\xfa\xc79\x9c\xc2\x1e\xfd\xe3\x03\x9c\xc2!\xfd\xe3\x07Z\xe7\x80\xfe\xf5g8\x85]\xac\xf53\x9c\xc2\x01V\xfbH\xdfN\x0f}\xe5\xc6\x17\x9b\xdd\xce]\xe3\xed\xdc\xd3\x8b\xf9\xed\xd4\xef\x1b\xbd\x9dO\x9c'\xd7\xed\xcb\xa9\xf7n`]@b\xe38\xaa\xca\xdc\xd2\xb3\x1c;\xda\xa8\xf3\x8c\x02H\xd2>\\\x1c\xde:N\x83b\xdd\x10F\xa7\xe0\x00\xfd\"\xa5\x18\xe7\x14\x91\x0f\xef(\xf7(%\x90\x84\x11q+\x1f\x9c\xed\xbfVYy\xe2x\x88\x99\xbe\xf3|\x08a\x04\xces\xfamL\xffz\xf6\xc4\xe1d\x9b\xf3\xdc\xb1m\xeffD)\xe7\x8b\xe5\xf2\x94a \xe2\x86\x9e\x0f\xb9\x9b\x07\x1f`\x04y\xf0\x1a\xbe\x87\xd8\xed\xa4\xd2\x04\x1f\xe580+/\\:\x07\xeb\"\x11\\#\x12\x94\xd9O\xd9-\xc9_\x86\x05q\x91{$A\xb1N\xe2\x12\xbf\x0e\x12\x92^\x97Kx\x0e\xbb\xeat=\x1f\x1c\xb6\x86\x94!\xe9C\xdc}\xe8\xc9\xa9R\xc6\xac\xce\xe9\xce\x89\xbbz\x1b\xa7\xf3\xec\x96n\"\xfb+x\x1b\x96Kz\x97\xf1\xdf3\xf1\xfe\xd8\xf2yA\x92\x05\xfd\x98\xfe\xab\x7f\x8a\xef\x8eA\xc0\x01\xd7\x11\x84\xe82.\x1c\xcf\xf5z\xf0\xe05\xc7\x83\xd7\x8f\xc0\x83G\x9d\xa4\xca\xbe\x8e&\xd9\x8d;\xfa\xdfC\xaa\xd8\x89\xb8\x03\x9d\x16\xa0Kb\x90m\xc9\x1b[o0#\xa5\x91d\xe5\x7f\xf27\xed\xe5\xcc\xe9\\b\xfa\xbf\x01\xfb/\xaf^6\xf8p\xbf\xc8\xf3\xf0.\x88\x0b\xfc\xd7\xdcX:\xb8\xb1\xff\xe57E\x9e\xf2\xb0\xb3J9nN\x17\xd0\xbe\x04;\xf2\xe9nM^\xe5y\x96\xbb\xce\xcb0\xfd\xae\x04\x8a\xdd)k\xbd\xcc\xe6\x90\xa5\x00\xec\xac\x9aey\x9bB\xb0\xa6\x15E\xb4e\xb9Vt\xb5\x9a\x1e\x94\xf3\x95\xdfi\x9f\xd0\xf6\xd2\xce\xd3\x89wq\xec\x03\xb9 \x13\xcfuXq\xd3\xfee\xd9\xc7\xbf\xcc\xfb\xf8\x97\x9b>\xfe\xe5\xae\x8f\x7fi\x18\x9c?\xdb\x19\x9c\xe5\xa6\xec\x08\xe5aV}\x8c\xce\x15o\x99\xb2Ns\xc1:\xd9x\xa5.\xdee\xa9\xf1.\x8ckY#3\xa0q-W\xc8\xb5loC\x88\x8c\x05\xbb\xbc\x94\xd5\xa1,\x0b\xf2\n\xc7\x90\"3\xb3b\x8c\xc3Rc^\x9a\xd3\x8f\xb5\xcf\xb0\xb6`rh#Y\xcd\xf7\\\xd7\xdc\xc8\xe9)\xb2:\xdd\x92$\x90H\xc6F\x90d\xa7\xd2\xc5C\xaf'\x05: Dr\xecf\xda?\xa0Oq\x1b#T\n\xf3\xebjE\xd2\xb2\xe0\xb4e\xdfw\xf4\x89\xc2\x82\xc0\xf8\xb8\xb7\x1eH\x02{r\x0be{\x0b\xf5\x07[\x9el\xde\xb2K\x0c\x94\xb5\xfe`\xe3\xd3\xc74\xae\xd0\xd4\xa6\xe7\xa1\xf3m\xab1\xba\xa1\xd6/\xecm\xd5\xea\x95p\xbdN\xee\xb8\xf2\xaf\xde@s\x8b\x0f\xe6u\x11\\\x87\"!\x904!\xb2J\xa5n\xcaE\xce\xfc\xa6\x93\x9b\xcfl\xdc<~\xe6\xba\xab\xe0&\xce\xcb*L\xf0\xe25\xbf\x10\x96x\x9cW\x17\xbc\xfeG\xfa\xcd%\xfd\xdf\x16\xb2\xfc(\x0f`\xdc~\xe2yV\x8e\xfe\x1f\x85\x8b\x9f\xeab3.dk\x953\x1cu\xa8#4\x8a\xa2\x8c\xca\xc3f\xaa$X\xb06\xf7=83W\x96\xd5n\x16\xccE!H\xee\x96\x9e\x8f\xb0'\xa3gtk\x8c\xdc.jL=\x03Y\x04\xcd!\xaa\xeaf\xd5\x0d\x91 \x9f\x87V\x7f\xce5)\x1d\n\xbc\x91\xb8r\n\xf1\xcb@>\xbe\x88\"R\x14Y\xce\x08\x8a\xa2Z\xd3\xfd \xf3-\x0bA\xe1\xdc\x84IEx\xdb\xf4\xd0\x95\x0cY\xa5\x01\xbe\xf0\xfcMI\x0e\xf9\x08l\xa5\xee\xf4\xc8\xb3\xf3\xfd|\x0cO)\x9e0+~\x7f{\xe0\x8a\xcb\xf6\x82\xa2\xe6\xb6S\xa4 w\xd1\xbe\xa0\xea\xfa{A\xd8\xcc\xb3\x9f\xd8o\xe4\x1f\x9a\x1a\xb4\x8f\\\xb4\xebWS\xa3\x06u\xc8\x92K\x82j\xcb%\xda\xdd\xb3\xb0\x85\xa9\xbb7\xf5\x14dk>\xf4\x82\xc5\x0e\x16\xbcF\xecNh5\x99t\xef\xbf:\xb5\xf1\x01;b\x1b\x9f-I\xe67\xb1L\xa8\x9b0\xdf\xa2\x17\xb7}iT\x1a<\x05\xc6k\xd8\xaeL\xdf\xa0\xfb\xf8`uX\xff\x8d\n\x8dne\xba\xb2rCd\x82\x88\x9bc\x1f2\x1f*\x1fB\x1f\n3\xa8\xa4@d\xcbHc!\x03\xd0\xc6\xb9\n\x8fL\xc9T\x88\xe8\x1c\xc9-p\x18\xf76N\x99B\x8e|\x89\x08SJgQT\xe59\x99\x9f\x00\x9dd\xb9$\x90f\xe9\xceJT\x9c\x93\x1b \xe9M\x9cg)\xc5\xffH\x0e\xd3J\x8b*I\x80\xd0VaE\x8a\"\xbc&\x10\xa6s\x08\xe7sTe\x87 ,I\xb2^T \xdc\x86y\x1a\xa7\xd7E\xa0\x9f\n\xfa\x90\xa4 \x1dD*E;3}\xb1.\xcct>}(\x86\x1f\x9bi\x11W]\nR\xcb\x80\x9f\xfck\xf1\xe4\xda`\xdedz\xf8A^\xcc\x92\xd1\xe8\xc2X\xeb\xc1\xf3\xbc \x0dW(\x91}\x93\xde\x84y\x1c\xa6%\xfc)\xce\x92\x10)\x99\xd6WmJ\x8c\xdd\xb2(X\xe4\xe1\x8a\x14\x9f\xb2\x0f\xd9\x9aQ\x1a\xd1\x1f\xcc\x1f\x0e\x82\x01}\x16!OM\x9c\xae\xa4\xac\xeeW\xec\x0b\xb6bvaa\xa3\xd8\xa5\x8eS\xca8\x90`]\x15K7\xed\x10V\xab\xb35_\xacD\x9d\nW\xf2\xca@.\x0b\xe2tI\xf2\x98\x83\xed\xdd}O\xfd\x84\xb1\xe8\x93C\x1d\x03p\x1e}\xf2\xd4\xd8\x16e\xbf*\xe9M=?\xdaK\xec\x86\x0d\x91\xeb\xf9x\x0b\xc7'\x10\xc13\x10\x1c\xd0 D\xa3\x91\xbe\x88\xe2\xc8\x17\xb3H[\xc2\xa4io\xb6`\xcc\xb1Vt\n\xa1R \xa3\xc2f\x94|\xff \xb1\x80\xf9\x16\x8b\x97x\x9e\xccY\xd0\xef\xd4\x91U\x1c\xfb\"\x9b@\x89\xbbP/@\xa9\xec\x16\xb3,(\x83\x9c\x84\xf3\xf0*a@\x98\x1bi\xf0\x92S\xd8\x9a\xb4\xea\xdf\xe6q\xa9\xd6\xafKD}Z\x18&Iv\xfb\xefa\xb2x\xbf&)7\xbdS\x1bRk\xd4\xad\xb5>\xac\x9b\xcc\xd2\x88\xb8\x0eA\x83\xa8u\xf7r\xae[P\xc3\xd0\xf6\xfd=+\xbd\x14\x138/\xc3\x92\x04$\x9d\x13\xb4\xd6\xc9\x83\x94|)?\xc5\xd1gw\xc9\x86\xd0\xdd\xe9\xb2\xbd\x87%m\xcd5\x89\xf2\xccTb\"\xf3b\x8e\x18\xd7\xbf\xc7\xd7\xcb?\x87%\xc9\xdf\x86\xf9\xe7\x16 \xa9\x18\x06j\x86\x83\xfd\xa4\xa5$\xd5\xd4\x17b)w\xab\xde\xfdfB\x9e?h*sR\x94yvG\xe6\xad\xe1\x0f\x1e\xa2$\xcea\xa3\x15\xe7\x14G\xab |\x0c\xf3i\x8e\x98\xfaeP\x8f\x8d\xd60-D]Acu4a\xa12\x113@\xfe\xfd\xa7\xd0X\x9f\xd9&A\xabx\x1d\xdb)m\\p\xc9\xbf\xea\xa3\xfc\xb1C\x86?\xaa$\x11\x17\x16\xcf\xbe/\xdf#\xe2\xcb}\x7f\x13499\xda\xb3\xea\x8a\xec\xbb!\x8e=\xaetN\xd7\xb56\n\xeb\xa3\x8a7\x1c\xdf\xde\xc1\x9e\x01\x8f\xbf\x0d\xcbe\xb0\n\xbfv\xeds7\xde|\x02\xd2\x80\xcc\xe3\xd9\xb73\x88LZ2\x90\xb5\xfb\x87a\x10\xa7\x87\x1b/\xf0\xdf\x85A\x1c64!\xaci+\xc1J8\x93\xee\xa0\xcd\x19\xe3\xdb\x8f\xa8S\xc8\xb5\xb5U\xba\x1d\xf2-\xebg\x9a\x85\xeec\xf7\xdeb\xaeg\x16$\xee\xeb\x06\x96\x8c\x90>:\xf4\\\xa7\xc8#\xdd\xd4\x81\x92\xd3\xb5\xd0\xb6\xcc\x98\x1dI[\xfd\xe5:\x0e\x8c \xf4\xb8=\x8a#j\xca'\x06-\x08\x838-\xd6$*\xcf\xb3*\x8f\xc8\x90C \x08S\xe9f\xf96K \xc1\xa5\x87&\x12=\xb2Y`\xa4\xea\xa9\x8e\x10\x7ffn\xea\x83CYB\x07\xf5@q\xf3\x9b\x1e \x8a\xbc\xe8\xadm\x8c\x97\xa4\xcf\xaa\xe6\x8b\x8a\xd7;\x03\\\xa1\x92i\xb1\x8a\xe0\xd7,N\xdd\xda\xda\xd7\xc3\xf6\x90\xe2\xcd\xe1\xac\x86\x07p\x0c\xa1\xf8\xa9\x94\xc6\xcd\x818\x06wN\x12R\x12|\xefK\xaf\x14K\x8fF\xf2.\xd3[\xf56u0\xd2\xe2.\x1a\xef\x19e;894\xab\x90\xc1\x91\xf8\x08\xb9\xffot\x0d\x7fo\xc0\xb01\xd66_\xbd\x03\x93\xa2\xd9M\xdd\x83\x03\xcf\xc7\xf7\xe3\x86 \xb69\x98\x18\xaf\xe9\xe4@7\xf3\x0b\x8d\xaeT\x9f\xc9\x9d\xd9\xff''\x0b\xf3\x8b\xcb\xcb\x82$\xf6wx]\x8f[ \xcb\xe4%VX\xb7M&[\x83\x9c,\xa4\xcdh7\x13\x0dk\xe63\xb9\xd3\xf6\x14$\x96\xbc\x0d\x1ar!\x962\xc2\x88\xb6\xbc\x92>\xff\xf2/\xec\xf8\x1cC\xd5^\x1c\xfa\xea\x18\xca\xf6\x0b\xdc\x03\x83v\x1b\xb7 m\x97\xaf\xf3l]\x1cChX\xff\xec6%\xf917j\x12\x8f\xd9\xfbI\xb2]\x91\xc4\x1cA\x94\x93\xb0$\xaf\x12\xb2bn\x15}\x94 \x9e\xf1\xda\x17\xa25\xa2\x84\x9e\xc6*I\x0c\xb3\xe0o\xd4\xc1QZ\x83\xdfNY\xdc/\x1e\x14\xc3\xe4\x10\xd3\xc3CP\x03\xef\xae\xb9\xef\xc7\xc2\xf3!\x12\x85 3\x98\x1c\x01\xa1\xfb\xee\xf9 \x8bM\x03v\x84\x05\x1c8\xaeK\xda\xd5\x18\xf2Q+b\x19\x02\xa5\x8c\x810\xe6\xbb\xb7\xbd\x0d[\xa1v5]V\xeeV\xcc\x93\x11\xfd\x1fOZ\xcb\xb7\x84S\xd05\xe8\xb0\x03\xd3\xf6\xca0Y\xc7\xd2\x83*\x88\x96q2\xcfQ\xa4\xa1\xa1%\x94\xb9\xd2\xdaKx\x0e\x13\x13YQ\x0b\xb3\xe6\xc2\xac\xcd]\xd25bb\xac\x1bx\x06\xcb\x13\xb8\x19\x8d<\x98\xcfn.\xe4\xd1\xcdn`\x04S\x83\xfco\xec\xabc\x9a\xab'\xb05\x13\xee\x15\xc8=q\xe8z\xb5\x84\xe4\xc0\x97\x07\x8dO\x94\x9a\x16\xf1#\x9e\x8b;O\xdeD\\xi\x07\xee\xe8\x0et\x0cM\x08\x80\xe9ig\xee\x03c\xfc/\x0eP\x8a\x9e\x96\x14g7\x17\xc7\xaf/\xcc\xeb0*\xb3\xfcn\x90G\xa4v\xc9\x82\xab8\x9d\xbb\xdc\x07\xc9L8\x93@(\xd75/\xc5E\x10%YJ^\xa4\xf3\x8fL\xdc\xfd\x1f\xa4\x97\xb9n\xe6\x18p%\xbd\xcf\xa0,\xfd\x87\xdf\x03\xfa\x07?\xe7e\xc0\xa0\x8a\xcf4\xfb\xebB\x9f?\x1d\xc0f\xf0\xa2\xaa\x0d\x9brTd\x8a\x86\xdb@\x02m\x9b\xe8\x15n\xbfB\xc1\x03\x0e\xbb}j(\x12\xed\x9a\x8b\xb79\xd0\xa9\x14\xa03\x17@\x87\xdd\x9a\xfax\xc80h\xa9\xc3 \xb6\xde\xec\xe0#\x1e\x97\xcft\x0d\xb6\x0c\xef<\x0d\xdaT\x16h\xc3\xca\x15\x15\x11%\xb6T9P\x02g\xb0\xa6\xc5\xa7\x90\xd0\x7f\x8e\xc5/Z\xd7\x00\x9d\xee6\x84Nw\x1e\xac\x87@\xa7\xbb^\xe8t]C'\xbaz+\x06\x9dV\xf0\x0c\xeeN`E\xa1\xd3\xf5l\xa5B\xa7\x95\x05:)\x03\xba\x1et\xff\xf9\xddX\xfa0\x17@\xe0F\x95\x13\xd3\xc3\x1f\x17\x7f\n\x93xn:\xfe\x9bP\xa4\x8a\xbc\x88\x1d\x10AJ00&\xf7\xaa\x10\xc0\x7f\x80~\xe2T\xd2\x0e\x1f\x98Y\xc0\xdd\x83~\xa9@\x87\xb3\x03c%\xcc\xa0+wS\x8f\"P8\xe6\x87\xb0\x99\x8aq\xec\xfa\xc09%\xa6\xab\x8a\x8d\x04ef\x10\xd3\x0b\xc3R\xae!-H\xf9)^\x91\xac*a\x192\xb1\xc5\x15!\xdcK\x97\xcc\x9dn\x91|\xd5\xdfA\x94\x900\xff\x8a.B\xb3\xfc%\xc5s\xd0\x8c\xbe\xd6\xda4Et\xf9\xc6\x06\xc8\xc6\xbf\xcd(\xd3\xb5\x95\"\x880\xb4C\xf7\xb1)\xf6{\xda\xed\x94r\xa4\xec\x0b\xf5\x9a 9\x87\xd1\xa7\xd5\xdc\x1c\xb4l@8\x92l\xb5\x0e\xbd=\xb4\xdb\xe2\n,s[\x16\x10\xf1\xb0eg\x7f\xcdsHm\xb2\x04\xe9 \x9e\xc9?Z\xc4{\xa7\x80(\xad=\x18\xea\xfa\x03\x06\x95\xdb\x06\xa5\x1c\xde3\xf5\xe7\xb1\x04\x85\xa0w`\xb4\x8b\xca\xb6\x8a\xae\xa6\xa2-\x98\nu\xa6i\xfe\xd1\xfeV\xd3@Q\x0c\xb931]\xfe\xb6\x8e\x8e\xf9? J\xe4M\xd5\xeaY:9z\xe0\x83(K\xa3\xb0t#\xb4/\xc4\xb6}\x88D\xa5\xedmX\xba^\x9f\x96\xcet]\xb7\x166j\x96\"\x89\xd0]\x1b\xd4\xe28F\x83uC\x8d\x0f)\x01\x18\xd5\xfaerb;\xe7\xf8\x01\x85\x92\x91X\xd7\x13\x18\x8d\x12x\x86\xdf\xe0\x82\x14\xb3\xe4\"\xc8\xab\xd4\xb5X\xbc\x8a\xa5\x90\xbb\xec\xb9%\xc0%|\xec\x8e\x9a\xf6N\x865\xbc\x92\x0b[Jk\xbd\x1d\xdeP\x85 \x90\xf1d\xc6F\xe9\xa9\x95_\xf8\xc3\xbb\xb1\x830\xf1\xe4n\xd9\x864\xe2\xe9\x87^\xe2\xe9\xef\x08d\xb5\x83\x0c7\xed\xdd\xc3FC\x80V\x07\xc2\x1a\xa0\xbb\x03\xfb\xec\x8do\x1e\xf4\x05{\xe8\xbc\x89s\xbb*qQ\xa5\x92&3\xa44%%x;\x9b\xbbq\x15\x8b\xd3\xb8\xd6:\x0e\xe2\xf1(E\xc0hW\x03\xed<1`\xe9V5J\x1d\xdba\x01\x9d\xcf\xe4\x04Rx\xd6\"\xceO \xa5\xc41\x99\xa5\xb4+\x95@N5\xe28\xe2ZVr+\x96\xcf\xf3a\x82th\x0d\x05\xef\xef\x01\xa3s\x84\xeeR\xa1~\xe7\x92D2\xaf:=\xa6\xc4&p\x9bs)\xde\x06\xee\x85\xd2l\x1c\x94q\x89\xd6\x1f\xceU\x9e\xdd\x16$wh!\xff\xbb\x89\xba\x94\xde\xf0\xf0\x1bq\x10\xe6\xd77\x0c\x7f@\x1cp\xbbAd\xbe\xa4\xdfE]\x1b\xdf\xdd\xe0w\xf3\xf9OqQ\x92\x14\xdb\xbda/Q\xd9\xc0\xfe^,\xc4\x9f9Ye7D\xaf\xccJ_$\x89xQ\x887d\x15\x97\xe2\xefuN\xd6$m\xf5\xc4\x8b\xdf\xa7Q\xab\xddDj\xae\x97\xa1\x98]\xa8\xabw\x15\xa7\xf38\xbd\xeeVR\xe9T\xeb:\xcf\"R\x14\xf5\xc7\xb1f%\xedh[\x14\xdd\xce\x07x\xc89O\x1c\xed\xb3\xe5\x0f\x18\xd9&\\\x88\x91R\xe22y&\xc8\x81\xb3\xe1\xbd\xf9\xd3\xab\xcb7\xef^\xbfy\xf7\xe6\xd3_\xb0\xc6\x04\x9e\xd8V\x9a|)I\xda\x8a\x8bh[\x02\xa6\x9dk\xd3Q6\xf9-.\x0d[:7S-\x9f]\xe2y\x0d\xed\x04\xcf o\xd6\xae\x9c\xc5\x94\xc5\x9e\xa5\x17LD\x1a_|\xfb+$J%9\x9d\xd9]\xa5\x15\xd4\x8fYj\x8c=\xd35\xac:5v\x063n1\x95 N\xa3\xa4\x9a\x93\xa1\xa1\xcb(\xa7_\xf7\xa5\xbc~\xe0\xc6\x0fC[2D@3\x8c_<\x84\x85\xc7C\xe5.\xfdk{[\x84\xc6ce\xf8\xe7\xf66\xe4\xc2\x12\xbd\xd5\n\x1d_\xca\xde\xea\x9c\x06\xbeY\xc4IIr\xb7\xf3-IN(\x11\x17\xa2\x17\n\xfb\x06\xc11z\x0d, \xd4\xe3\xa740d\x0b\x08\xa1\x88\x96d\x15\x06\xf0F\xbcb\xf1\x0d)>\xc8\x16PT\xd1\x12[(Z\xc4a\xe0\x18\x8e\xe3\x12C\x1b\xae\xd6qB\xe6o\x9a\x95\xab8\x0b\xeb\x88\x018>\xcc.\xf4\x0f^}i\x7f \xd6\xd3\xf8\x01E\xcco\xc3u\x17E\nB0\xc4n\x90\xd1\xae\x80>l\xb1\x8e\x8dZv|\xcf\xc3j\xdak\xf0`\x9b\xf6\n\x8b0I\xae\xc2\xe8s+V.}d\x89{\xfdA\x07\xce\x17O:cW\xf1b\x86\xd7\x94\xf9P\x8a\x9e\x9a2C\x0c\xc3vw\x14\x90\x97\x0c\x90\x13\x83Z\xea\x04J\x86\xf9J\x0e\xbd\x1b\xc6W\n\xaf\xa8k\xff@\x12\x0d\xab\xe7\xc55\x9e\x16\xcb\x99\x90/\xb7\xf8+\x0c~|\xf5\xfa\xc5\xcf?}\xaa\xe5b\xa1`\x19:N\x848\x0d\xea07\xf1\xb5\xef\xf2\x80G\x01\xa4\x18\x97\xb6\x8e\xb3\xb1AyF\x9f\xab\x9c\x84\x9f\xdb\xaf\xba\x9c\xe1K\xada\xbd\xab\xc9f]q}\xa8\xa5/\x19\xc8\xfc9\xcf\xd2k`\x9e\x81\x08AD\x97x~\xce\x194\xe1\xbbP\xb3v]F\x01\xcc^\x81\x02vN\x0c\xd6N\xceM \xf3\xe5\x0b\xc8\x0d\xc9\xefz\x80\xa7\xc0\xb3\xb2\x1bN\xa8\x01*\x0dn\x9e\xd7\x916\x05XDn\x88\x83\xc6\x02\xdc,\xa7\x802N\xaf\x13\xc2g\xc8Mq=\xca\xa0\x95a\x9c\n\x98\xab\xbcm\xf9\xec!wA\x1e=\x8dl\xd3i\xd4\x81B\xb59P\xb8i\x9b\x81\xf4\xae5~q\x8f\xc9-\x84\xae\x01o1\xf4id\x89\x05\x1c?\xd6\x1d\xd3\x14\x11\x83\xcc\xa4\xb1M\x1bj\xab\xf8\xdb \xcaP2Ho\x05\xc6\xe4\x81Om\x16\xe9\x83}\xf9j\xcdl\xe9C\xac\x83\xad^},s\xee\x16\x06\xa1\x9b\xb2\xaf\x9a\x0e\xce\x0b\x8a$\x8e\x88{\xe8\xc3\xce\xa4o(\xdd\x0e\xf5{\xbb\xff+\x1d\xea\x87-\xeb?\x80\xd5\xf9\xb7:\xf7\xfb&?U\xe6\xdf\x12\xa7\x8f\xa3\xec\xb3\x9eC:@/+\xb7=\\7+\xf5\xf1\xa3&F\x1d4z\xfaQ\xcf\xd8\x91\x86\xda\xb8a\xfcJj\x19\xc3\xc1\xc8\xb21\xac`\xeaO8\xdc\x0e\xeeR\x81\x9e]G\xe6C\x1e\xaf\xe22\xbe\x19\xbcL*\xa1i\x04\x1d\xf8\xc2p\xbdX\xfc\xc5\xf6\x05a\xe5\xed#\xaeS\xb2FPW-\x16x\xe9\xcb\xfaG]\xed\xc1\xab\xddaR\xf7\xe0\xd0\x0b\xd8{\xb3@es\x0b\x06\x03\xe9\x8e\x1b(9-s=\x80\x08\x06\xf6\x97\x17o\x7fz%\xc2\xae9u\x82\xaa\xb0\xc8d\xdb\xc3U\x98\x7f\xe6\xa6?\xf8\x93\xc7V;mb%\xd1\xfat\xcd\xdc\x8a\xa7`be\x1ef\xb0p\x9bF\xcex\x02\x8c\xba\xa4\xc6b,\xf7\xa4\xe3\xf9\xf5\x90\xd7e\x95\x93\xf32\x8c>\x7f\xcaCth\xb4\xbc\x11\x86\x9cK9\x01X\x86q\x88\xb1\xac\xa05\xd1EYXhy\xbc\x8c\x0eY\xb2\xf6\xaa\xff\xca;,\x9c\xd8 \xe4HZ\xb9\xd5\xf2&W_\x8a\xb9\x0e\xa3U\xea}\x1a\x81s\x0c\x8e\x91f!h%\xd1\xb7 >l1\x07\x9dz\x1f(\x85C\x9a|$\xa6\xed\xd0s\x0b\xca\x94\xd6\xa0\x84\n\xbd\xf6\x026\xf7\x1d\x96\xcdK]\x95Z\x08>K\xdd\xe9x\xeaiV\xf7B\x01\x8a\xef\xf7w'\xe8\x88\xbe\xbf\xdb\xaa\xd7\xc8\xcb\xb1\xde.\xaf\xb7\xc7\xff\xdd\xe7\xff\x1ex\x92\xc5\xcbc\xc5\x9dv/\xc66(S\xcc\xda\xdc lCip,\xd4\xcc\xd6\xdc\xa9\xa5\x9ed\x00\xe7\xeeY\xeap3;Mm\xa0\xdd\x85!ru\xcd\xc4.\x17\x82\xcf\xb8\xa3Q\n#\xc8\xbd\xe6\x00\xef\x1e<>\xae\xce\xe3\x03\xfapV\xea\x11a\x89$%\x8a\x1e\xc4\x84\x87\xf7oE\x1f\xcax\xb9\xce\xb0n\x10=\x99\x05\x8c\xfdg\xf4\xe4\xea\x9bDO6\xdd\x8f\xbfOPa\xd3H\xf0ZF$N,7v\x91dY\xde7:\xcb\xd0\xe2\xe2]\xf8\x0e\x15\xce#\x14#\x8c\xe1\x18\\\xa1\xc1\xc81OZ\xbfD\xc1.\xaa\xe9\x0f\x10\xdcw@\xd5\x10\xb4|\xd4\x9a @X+\x18\xad\xb7\xba\xcc\x13xs\xf5h\xac\xe6_R\xe5\xb2!\x05\xdb\xf27\xfa\x18D\xd7]\xa6\x0b\xad1\xf4\xe4Nh\x0f\xc3\x1a\x9b\xdf6\x92\xdd\xe1#Ah\xb0\xe1`\x14E\xaf\xfc\x0c\x90N\xd6\x9dw0\x0e\"\x9b\x00\xb1\xa6\x12\xd8\x04\x1f\x0e\xbb.qoB\x99\xded2\x8f\x0dTf\x8f\xaefQ\xdaO\xc6\xbd\xb7\xce\x02\x0d\x1e\x15\xd6\xae\x8f^l\x85\xfc\xe2\xf2Z}\xf0\x0c+\xb62\x06VbNm\x19m\xea>\x16\xbe\xdc\xf0\xa8:\xa1k\xa4\xd7\xb0\xed\xca\x87\xc2\xe7\x99\xf0\x0c\x95(\x1e\x8efcC\x00\xe9\x04\xdf\xe8&G\xd9\xb0\xcc{\x1d\x9a/2+.\xba4\x9fZu\x83q\x80\xcf\x8c\x12xv\xbf\x96\xc5(\"\xcf\x98\x07\x00S\x1c\x17|X y\xc0\xe41\xf2\xab\xc2\x87)\x93\xb5\x9eu\xe3BhF\x96\xd4\xf8\x90q\x80\xfa@\xa0/\x16\xa9\xb1\x1d}6}\xc7Xn\x98\x91U\xbf=\x18\x15\xd0\x8f\xbf\x04\xc3.\x9f\xa2\xeb5y\xf01\xedo\x13p\xfd# \xa3\x92\x07L\xff?\x0e\xcf\x84\xec\x9c\xc0M\\\xc4%,\xcbr}\xfc\xe4\xc9\"\x8c\xc8U\x96}\x0e\xae\xe3rY]\x05q\xf6$\xa7\xdf=\x99gQ\xf1\x04?\xde\x99\x93(\x9b\x93>\x81\x9c\x999\xe6\xa3\x91\xc7,\xd5\x9d\xed0\xbf.f\x17X\x8f\xa4\xb4\x89\x9f?\xbey\x99\xad\xd6YJRY\xaf\x96\xc3\x08&\xba\xf2\x8c\xb5\xa1\x06\x7f\x17\xa2\x89,\x1f\x1e9\xbe\x89\x1a_\xf4\x87\x8b?i]\xff\x18\xe4\x10\xee\xba\xaa\x8e\xc1\xf4\xb83\xfa\xba\x0fq;\xacz\xdcs\xea\x06\x9d\x1b\x89\x82\xb2q4\x8f`\xe5\xebb\xf1I\x87\xf7\xcc <\xac^\xb8?\xb4\xff\x12\xeb,\xb7&\xc1\xb78(\x97a\xf9\x11[+\x98\xd8E)z\x1d&\x05Z>\xba\x18H[y\xf7)\xaf\xf8\xab\xb1\xfe\x8a+\x17r\x11\xcfW\xfdn\x19w\x9a\x8f\x88\xb9)\xf9\xf6\xb46^\xf0\x03>\x04\xa5\x9a\xfdO\xe0\x94\x1f\x94\x8d6P\x94v(\xa5\x9e|\xbf\xa5n\xd7\xf7\xf0iI\xe0\x8a 7W\xd9\xbcJ\x08,\xf2l\x05i6'\xc1\xaf\x85__D\xee\xf4\x1ah\xdf\xeb\xcd\xfd[X\x95\xcb,\x07\x80\xd7$\xcf\x8a\x02^\\e\xd5\xe7e8\x8f\x7f%Kx\xb6\xc0\xc2\x7fc\xff\x04Y~\xfd\x1c\x9e \x88\xd4\x94\xb5\x1a\x15\xf6H\x8aA\x12{\xf9\xa4uu\xb9\x1c\xaa\xc5?CC\\\xb4\xb2\xe4A\x93X\x0f\xef\x94\xf2\xb2\xbe\x10\xed\x98+\xd0le\x11|\xfa\xcb\x87W?^\xbe\xf8\xf8\xf1\xc5_.\xcf\x7f\xfe\xf0\xe1\xfd\xc7Op\x06\xd3\xc9\xde\xd3\xbd\xc3\xdd\x83\xbd\xa7p\x0c\x93\xf1\xd3\xdd\xa7{\x93\xc3\xa9\x96\xef\xd6\xd2ah\xc5\x95\x94\xe2\xa4\xc3yF_7\x86\x17\x1f\xc3\xf4Z\xf0\xc9\x14(%\xf1\x1cI\xd190Os\x865:\xcc+l\xb3p\x85\xbd\xd3\xcfqZ\x1e\nCc/\xb8\xbcDl\x7fy\x89!,\x1a\xf9\xea\xb1b*\x82l7o\x00}\x9c\xe8a\xe7\x18\x8c\xe5\xb8\xd3\xa1\x85y=\n\x1b\xc5\x06\xc2\x88\xcb5O\x80\x07\xc4\x97\x95 \x85\x9an\xa0i\xba\xbd6H\xde\x1b\x14\x0d6\x12\x0b\xeb\xb7\x15\x10\xcaN\x89MZ0\x1c\xc9=\x9d\x8b\xda,\xb9\\\x12\xe6\x86\xb2\x88\xf3\xa2\xac\x11?\xac\xaa\x02\xedgB(Z\xd1j\xe5G\x10A\xf6x\x08\x0f\xb63\x105\x01i\x0cr\x1c\xcb\xd6Db\xfd,\x0c\xaae\x0d\x89\xd9l\xe8;!\xb5Q\xe7\xcdm\x87BnR\xdf\x91~\xda\x9c\x89\x16\xcf-W\xe5lo\x03\x91\xcf\x83\xfc\xae\x1dK\xbb\x83\xedFW\xbf\xe0\xea\xae$?\xe1\x89\xf6\xd1\x0co\x0c\x98\xeb\xba)\x86g\x8d4K\xbf\xaa\xdfe\x8bEA\xca\xef\xe8\x11\xc8*4G\xbf\xca\xaat^\xd8vW\xef\x936\x0e#p1\xf7\xf0\xd8\xb3\xf6\xc3\xee\xdc\xf0~0\x00A#cI\xa5\x00n\xa7<\xf0o\x0b(\xd4F.\xd6*x\x81\x8fM\xc5t\x99\xcd#\xe9\x04L\xa4\x0b\x10\xd1\nk\x06H;\xaf\x8a\xc1\xd0O\xd9\xfdc\x93R\xb1\xc5\xd8tx \x1a>\xc7\x05\xad\xf3\xc9\xdf\xdf3\xe7P\xa7*\x17\x87][\xbfU\x04q\xf1\x8a\xc3\x0d7\xb58`\x7f\xe7\x08\xd0\xe2H`\x83!\x056\x94\x1a\xf6\x98n\x12H\xf8t\x0c\xf70g\x1bg\xf6\xd7\x02\x8e\\]\x16T\xa8d\x86\x8e\xb7y\\\x12\xd7\x02U\xd9'u\x96\x02\x97\xf9\x042#\xfc\xb1\x0f\xb1\xf7\xe8\xed\xf2\xfaL\x1f\xc5C\xd7\xb2\xa8\x15\xba\x141uH\xb3j\xd5\x08\xdc\xc3\xd2%\xc2\xe7\xc9\x166c\x08\x906\x9a]Iu\x82\xb8\xf8SLX\xda\xfdv\xb1\xc9\"L\xaa%\x8f\xb4!0\xdb\xa3\xad\xa9\x99-\xd5R\x0e\x11\x1dK\x1caX\xe2\x9b:\xd9f\xd7*pj\xb3\x1eIW(\xc2\x1c\xc3\xfb\x9d\x9cx\xb5\xa2\xcf\x8a Q\xbd\xe5\x84E\x14\xc7\x8eY\xc9\xc5j$a\x19\xa7\x93\xce*Wq\x1a\xe6w\x96* )w\xcd\xe8\x845\x82d^W/U\xb9\xd8\xe9\xac\xc1\x08\xed\xdeQ\xfc\xec\x96\x9eu\xc1\xa1\xe9.*\xa6\xdd\xe3\x89\x8a\x9d\x9e\x1a\xe5br\x90\x90\xbe:;\x1d\x95\xa0\x19\xf7\x14\xbe\xef^\xc1%\xf9\xd2\xdfJ\n\xcf\x9f?\x07\x83?\x114\xdb\x19\x16\xe4`\xaf\xbf\xa9\x1f\xfa\x16\xb2\xd37\x1c\xa0v\x0c\x19\xba1\xc0\x990\x96\xac\x86Ph\xf6SvK\xf2\x97aA0\x03\x19F\xa1k}\xaa\xebR\xcd\xe0\xeb\xa6\x8bc\x11w\xab\x9c\x11\x03\xec\xe7F\x14\x14\xfd\xf9\x02 \xe6\x83:\xbd\x93\x98*\x8b\xfe\xb8\x01\x01eM1\xf2\x05\xdb1l\xa3E\xdc\x92R\xee\x10\x85\x81\xdc?\x0eyNx.K\xe4\xce\xf0\x8d\"\xa2\xa3\xd8}\xa7.9D\x90F+Ie\x1ekp\x94\xfa\xdcB\x82\x852\xc6j1G\xce\xa5\x1ccQ\x88\x04D\xa5\xfa\xe5\x08i\xfd\x94\"\xc0\xb2#\x88\x82\x98e\xdc\xb9\x0e\xc0C\xe0\xc8]\xb7OF\x13\xf6h\\\x99\xc2J\x91\x86}\xda\x99\xc01\\k'\xcarB\x8c\xc2'\xde0\x81m\xa4u|\x8b\x9c\xc1\x86t\x1b\xf1\x85d\x10\xcac\xee\xc0\x19\x1e\x86\xae*\x8d\xe5\x0f\xe7Z\x8d\x95\x93\xb0(\xdfX>\xc0\xb9c\x12%\xfb\xec\x8d\xbc\xcbM\x98\xd4\x84\xbd`WD\xa0\x8a\x9c\x93W\xadP\x14\xe6\x1b\xad\xaf\xbf\x05\x98d,5\x8b%\xbc_(\x1d\\s\x8dB\xa2\x82\xcd[,\xa5\x16`\"\x05\x86\xd1\x18\xffM!\x01'\x04s\x0d\x8c\"=\xc4\x91\x1b\x17Za\x01\xc7ej\xd1\x8eTf\x95\x17\xc4,*\x91\xa0\xd8\xa7L\x18\xd8\xfc\xee\xbdWt\xa5\xa6>\x84\xf0\x04\xff-\xf8\xbf)\xfek\xb8o\xad\"M0k\x1b(\x1f\x06\x0b\x17U\x89\x8c]\xc7<{\xee\xcfo\xd2rr\xf0\xc3+\x97\xc0\xf7r\xb6\x11\xf1\x98\xef\xb9\xd5&H85\xda&\x8d4\x1d\xaaaN \x83g\x10\x9e@6\x1a\x99\x992\xe0\x9d\xe1\xf42\x0f\xc7\x1fQ\xf0\xc1C_-8\x1c\xce`\x07\x16\x9dr\x1d\xd1R\xfd\xa1\x88\xd2\x9dy>\xfb\x1cF|\x81\x8az\xdf\x16tA\xacMr \xbb\xc3\xc2\xd7\xb2\x163\xd89\xe5\xa3\xf1\xf9*X\x80\xb3}mR\x18A\x01\xcf!\xac1I\x08;P\xe08\xf9\xaa=Gf.\xdb\xd9\xe9\x9arM<'<\x88\xed\x9a\xf1\x80kx\x06\xc5 \xac\xbb\x16\x1d\x94\x85\x87\x11\xac=\x16\xa4\x97.\xfe\xbaw\xa5\x81\x9b\xc0\x98\xfc\xbb\xf5\x07\xe3\xeft\xd62\xcbq\x80\x0f1\xa9\xb7+3\xd6\xb3j@vt7k3\xe0[\xf5h\x07\xe8\x061o1J!\xdc\xdf\x9b\xf8\x18\xa1\x04\x97\x90\xb6\x81\xe2\xcd\x05-\xc3\x9b\xa3\x90\xe79\xc4x\x0chqLq\x01\xfea\xee!\xeb\x85\x9d\x19\xfc+L)/7\xb68r\x0bu\xe2\x92|\xe9P=\xe5\xf0\x1c2x\x02\xd3zh\xf8\xabK\xfeP\xb1\xb3W\xb1h\x87\xa3Q\xd5\x05>(\x9aX\x87yA\xde\xa4\xa5K\x82\xa2\xba*\xca\xdc\xa5|B\xe5\xc3\xd4\xf3ar\xd0!7g\xd4\x9a$(\xac\xccu\xcb\x19\xbdi\x98\x8a&\x1c\x00\xf4Dc\x83\x0e\xcde\xcf\xa1\xe1\x8d\xfd\xd5\xfd\x19s\nK\xc7\xc2C\x95\\\xdb\xa0\xd3\xd6\xd3\xd5\xd0\x9e\xec\x06\x03u\x9b\xb2\x11\xd2\xecB 8Q\xb3\xf2L\"\xc6\xb3\xed3\xc1Q\x19D<\xe4\xc4\x8b\xd2M{$\xfam\xc0\xf7\xc0dy\x9bL\xfav\xd8\xa4\x95\xb5\x19\xd4\xf0\x97a\x0d\xff\xd5\xfda\xf3A\x9f\x0fm{\x90VC\x0e\xec\xc0\x83\x93\xf2]\x93\xaeZ}\xb0\xb6\xb7a\xcbu \xc5NS\x0f9\x02~ \x19+!\xed_\xc5\xf9M\xcaO\xc3!\xcb\x84\x93R\xb0\xb1\x7f\xe0C\xc6\xb6=\xf6\xea?m\x9a<+H~\xf8\xda\x03\xff\xaa\x8b\x9fUY\x08\xf4\xe9TXL\xf4\xd5\xa7<\xc8\x0fw%\x91<\xa2[\x85\\E\x85\xfd\x0c\x1b\xd7\x8b\xaeq\xa5RL\xa1\x9af\x1c \xb2\xc5\x10\xf3\x18\x83\x1ab\x14\xddv\x81\xcd\x8c\x85\xf8\xf0E~\x93r\x16\x1bLS\xc5\x83N$\xc6L\x89\xe2A#V\xcaJ\xef\x1e\xc1\x19\xec\xc11\xfb5\xdd\x853\xd8\xe5\xbf&G\x138\x83)\x1c\xdbD/\x08\x91a\x04 \xad\x87[|\x83\xe1Z\x8c\xf8\xc5#\x8f\x8f\x81\x05\xf6kz\xe1kS\xc9p\xf4jY%\xcdh\xb2_\xcfh2\x85{p\xc5\x9c\xe4)Vt\x8a\xd3\xf1\xdeS\xfe\xdd3\xd8\xdf\x9f\x1e\x1dP\x92\x88\x92\xb3\xfbOw\xf7v\xbdo:\xff\xbd\xc7\xcf?\xac\x7f\xedn\xb0\x1ajYhY\xa1Cm\x85\xa4%\xab\xd4%\x0b\xe9\x92\x1d\xec\xef\xef\xee\x03\x06\xf4x\x06\x93\xc9do2\x99J\xcbd\x9c\xa2\x99$\xae\x8d\xb1(_\x84\x9f\xd3\xb6w}\xbc\xc9\x18tl!\xf7\xe7.(>\xa0?\x0f|\x11\xb5x\xc1\xc4\xa8c\xd8\x86\xc9x\xba\x0b\xf7l\x1397\xb3\x7f\xb0;\x1d\xc3={\xb5\xcd\x0c\xc2\xf9w\x1e\x05T\xa3SH\xda\x10\xdf\x06\xa5\xfb)\x12A\x8c\xd8\x15 \x14\xe3\x14\xbc\xbc\xafI>C8,\xee1\xc2\x13\x85\x1b\xf5\x16 \xe9.\x1c\xc7\x0e\x18s\xb32\x10\x04\xf4\x16\x06\xd3\xdcXz\xc0`8\xba\xc9}\xa6\x9a{\xdfCD\xa5\xedEv[\xe8S\xfeE\x82\xda\xb7\xbd\xf0\x81\x04\xe7Iv[\x97t\xef\xc3\xa8l\"\xab`,\xdc.\xbbBT\xdd\xb9#S\xa0\x837\xef\xce?\xbcz\xf9\xe9\xf2\xed\x8b\xff\xef\xf2\x87\xbf|zuN\xcf\xd3\xd8&\x8b;U\x93)\x9b\xcd\x82\xcc\xe5=\xb1\x13\xed\xf9\x8cn\xa4\x88o\x92\xc9\x92\x9e=G<\xb5\x02M\xb6J\xb2\xe3\xb4\xba\x96Y\x00\xd8\x81\xa8\xb3l@8H\xf1\xf0Q\xed\xb5\xe5G\xe21\xc3\x8e\x07\x1f\xf6\xa6\x9cVZd\x99\xebY\xc5\xa1%e\xc8\x98\xa5\xe9\xf6\xb6p\xeb\xad\xcb\xdc\x89\x0f\x13OR*\xb6\x8fjg\x0c4h\xe6\xb0e\x90\x9d\xa8\xe7\xca\xf5\xe8\xc9\xfa\xfc6\xfc\xc2-\xe4P\xc5L\xcf\xd4:\xcb\x92\xf3\xf8o\x14x\x1cN\x8e\xa6\xb4\xe82\xac\xae{M\xb6\xc1\xb6\xb1\x85\xe2\x0c\xa3\x1fo&\xd8\x1e\xe0u$\xb5\x1f5\xe9\x05\x0d\x16\x98\x1dBjW\x1a\x8b2F\xe3\xb9\xa237\xd6\xf1-\xf6\x93<\x9c\xcc\xf66\xff+@{U\xc2\xf3\xb8\xa9e\x17LbF_\x99\xc3\x9c\x16\xbe\xd6\x8a)\xe0)wh7S\xa3\x9d _\x1e\x98\x1a\x01\xc1\xcef\xab\xbf\x81\xed\xa7\xf8\x02Y>D4ca\xd6$\x1bB2\xf3\xbe3\x93\x05`\xde\xd4\x0f\x161\x0b\xea\x86\xc6\x86j\xa1Tb\x00\xf0}\xa7\x05\x17\xe1\xe7\xb4\x08\x17\x83\xe3\xafX2\xb5\xe9\xcdQl\xf1-\x9a\x94\"\xac\x0cjk\xcbmb\xa1\xdd\xdf\xc3V\x19\\\x8a&\x0c\xadG\xd9j\x1d\xe6\xa4\xcf!\x1bd\xf3\xca\xdar\x03\xdb\xd7\xf4QF \xd9\x8b:\xba\xb7P\xac\xb0/\x8c\xb6&\xcc\xf0Eu\\\xee2s\x90\x15{\x8c\x0d'\xf5\xaf\x98\xc5\xa1\xcfdN\x92\x99\xd2\"k\x98Q\x86\xde\xe2t\x8b\xc3\x98\xc5\x17xD\xc9,\xbe\xe8B\"\xa9\xe0\x1cY\xff\xad\x0c$\xf2c\x97\xddZ\x89>\xccw\"\x94zh\x8e\x04g0Q\xe2\xe1Bs^\x84\xf9k\xef\x89\x11l%W\xfe\x94-\xe5\x8fy\xc2}\x06\x06\xdf\xca\x84\xe3\xbf\xc1\x1ee\x80\x8d\xc3?\xa8\x01\x88) )\x0c1\xb3\x18L'\xf8u\xe6\xd5\xc1\xd0!\xb3\xa6\xbc\xfa\xceI\xe2\xa24\x99N\xf2\xe0{\x90-\x04P\xb0YQZ\x0c\x1f\x04\x01m\xa2\xb1\x11>\x98[S\x02$\x18W\x0b!\x0ca\x10\xa4C\xaa\x8b!\x89f\xe9\x85\x95\xdd\x12r)\x05=P\xbch\x86;f>IO\x1d\xa5\x8d\xc2N\x9cW\xdc\x18\xc5\xce\x06\xca \xbc\xfa\x9d\xf6\x8f>\x153\xe6FM8g|E\xf4\xd6\x9e\xb3\x08\xcd\xb9mEg+dg\x8fS\x98\xfb\xa0Pz\x12\xfa\xdc\x1a\xab\xef\x8a\xdbp=9\xe8\xf3\x0c\x17\x0c\x0e\xc6\x8c\xea\xd2\x13\x95F=\x91l\xae\xc9GRP\x12\xbb1\x1d^UI\x19\xaf\x13BWpr\xb0s\x15\x97F\xb4\xa8(\x1a\xc6'h\xbe[\x9e\xb0\xe37\xf5\xe0\x86\xbb&\x11Jm\x8dZ\xd9KA\"\xd1e\x17M\x10\x8b\xa8.\xcb\xee\xf4\x9b.\xcb\xdeW.\xcb\xee\xf4Q\xcb\xb2\xd7Z\x96]\xcfo\x8a\xe82\xb1\x7fLZ\xb8\x0dV\xeb`\xef\x9b\xae\xd6\xe1W\xae\xd6\xc1\xde\xa3V\xeb\xb0\xb5ZO\xcd\xabu\xa0\x15O\xd9?\xfbZ\xf1.\xfbg\xef\xf1kk\x8a\x1f\xd7\xb5\xbah\x9e\xdc\xb5\xc2\x8a\xa6\xa3\x8e\xaa\xc5~\xb6\x02\x08\x9c\xc1\x0b>\x9b1\xa5\xcc\x07\x84\x87\x92\xc7\x93wh\xf2\xe9F+\xf8\x07\x8d`\x98\xcd\x99\xb0\xfa\x1a#\xdb\xf4\\\x9eO\xe3Q\xe2\x0ck\x17\xfd\xa6R\xbd\x91\xda\xd4N*D3<\x8a7\xcda\xb69Y\xc1\x10j\x15\x06Q\xac\xe2\xe1\x9d\xbf\xd8\xa4\xf3.:W<\xbc\xdd_7i\xb7\x93:\x86a\x14\xb2xx\xff\x9f7\xe9\xbf\xd7v\x18\x9a\x86_m\xd2p\x075\x0e\x83(r\x18H\x95\xc3&\x9494\xb3y;l6\xbd\xc4:4v\xd1F\xc6\xfag\x1e\xf9Rx+\x1e\x83\xcd\xbd@~J\xe6\x8e8\x02\xc7\x19j6\x0dF\x9a\xec\x81\x8b\xe4\xd9dmA\xa5T\xa0N\xfeZ\x85Iw`\x170J\x1bzd\x0b\x122\x146\x9a\x9d\x88\x87\xe3\x80\xfb{\x0e,kY\x88\xd9/\\\x9bE\x9c\x16k-xr\x17f\xb2)F\x98\xffRK\xca\xdf9p\x81\x9f\x9es\xb3\xe9\x9a\xae\xa8\xddy\x10Fr\x7f\xc9`\x15\x96\xd1\xd2}\x12\xfc6}xr-2l\x80#\"\xe3\xd6\x8d\xf1\x10\x80,\xc8L\x10\x04\xe0x\x9e\x0f\xce3No\xd4\xe1r\x9e;]\xebb\x91'\xf5\x1a\xb5\x7f\xfb\xad\xd6y<\x05\xb3\xea\x9e\xdb\x0c!\xa2v\x84/\xc8\xb1^/\xaf\xed\xb6\xb4\x17\xcc\xd6,naT\"|\xdd\x11\x03\x8bv\xef\xefQ\x80\x83/b\x1d5\x9b)>\xee\x8f\x9e\xd3\"@\xfbh\xdb|sx\xce\xc7C\xe8_\x9dnBM\xfd^\x17\x02\xad1{-\xa4\x03|H\xeb\xbf\xf2\xfa\xaf\xb8\xfe\xab\xb9|\x83\xc4{\x19\xba\x0e\xec\xd0\xd3\x83!\xcd`\x87\x1e\xa7P\x96\xe8e>T\x1e7\xdf\xc0\x00\xc8B/\x18s\x15\xacb\x99\xc24\xbb\xe3\x13H\x98!\xedh\x94\xd8%\x80\xd1,a\x12\xc0\xc5,\xe9\x94\x00f\x18\xbc,\xe1:sZ\xdb\x0e\x83\x1f!\x01\xcc\xe0\x19\x1a!\xa3\x04\xb0\x82g\x90\xd9%\x802\x94\xc2(\xc2C\"\xbbI}q\xe3\\\\J\x91%\xd7.Ao[\xf7o\xd4\xd9\x9d\x1aR\x03\x03\xaavu\"\x99\xfc\x7fmG\x93\xce\x8e\xd0C\xdf\x0c\xc7l@L\x8b\xb9Y\x93\xb8L|$\xddt\x9f\xf3_\xadVj\x0f\x14\x1d@\x99\x83\xa6\xe4,J\xf9F\xad\x9b\x8f0\xc2\xe0\xb8x\x1d\xa7\x18\x97\xc03\x04d\xe1\xae\x92,r\x81p\x8c\x10\x84\x87\x0f,P\xc7\xcc\xe7\x91t.<\x16\xc9\x11\x92,\xbd\xa6\xfc\xaa\x88Fk\x0f\xa8q\xcf\x00\x85\x18D\xea\xc1\x19\x05\xcc\xac\xd8\x08\x899\x07Ay3\xd9\x9f\x89\xd5\x1db\x94_\xdb\x18K\xa8pGO\xea\n]\xacU,98\xc9\xc1{\x9e\xd7NM\"\xe2 \xe3\xef\xf0\xafA`_r\xeeeg1\xab\xca\"\x9e\xd7A\xa9\xec\xf1I\xf2:\xae\x805^\x86\x02^U'Q\xabJo\x08\xff\xc5/\xdbJ\x0b\x94c\xde\xf2^\xd6k\x18\xdb\xc5\xfb\xbc\xdc\xa0\xcf>\x8e\x8b7y\xb5A\x93_\xab\x8a\x80\xa6\xdb\xdb\x0d\xba\xed\xe5\xb1x\x9b_6h\xf3\x1fN\xd9q>h\xf0\xbd\xdc\x14Z\xf3o\xc4I\xd9,u\x01\x98A\x13s>\xd5\xbd\xa6\x98\xc2\xb1\xdf\xf9T\x97v\xfd\xdf\xf3\xf7\xef\xfa8\n\xbe\"\xe6\x1bJ\xdb9\x06\x11\x0c\xc4\xccr\xcc\xc32<\x06\xdd\x93\x0e\xe9\xa3&oFp\x19\xe6\xb9\x88\x0d\xe6\xf7\xc3R-\xf8*\x05,\xef\xe1\x14\xf6\xc6G\x07\xb6\x90q\xbfv\xe1l!A3I\x92\x1ec\x16\xac\x98\x03\xa3\xce\x97\xd9\x8c\x992@\xa2\xc1)js\xed\x0c\xe40\x87\xde\xcf\xff\xa8S\xfc\x16\x93{3drv\x1bDw\xcb&\xf5t\xb78r\x95\xd8\xa7\xbc\xc1\xb2\xa6+\xa9,\x82\xe3\xb0\xfbG\x98\xab\x1c.F\xe61}\xd3k\xb7\x9ce\x1dS\x8f\x07M\xfdm\xd7\xd4\x15St\x8d\xf1\x90\x877f\xc3\xcbk=^\xc659\xb1m\xd7\xf2Yv\x01#\x98\xee\x1f\xc0\xf7\x90\xcf2S\x90X\xd8t.\x9f\xba\xe6\"4\x12\x13\xd4H\xb0\xd8\x18\xf6H6\x0e#\x01E\x04\xef*NK\xbb}\xc7\x08\xc9 k\xdc\xb7O\xf9]\x9c^c`\x13Lj\x00W\xe4.K\xe7\x82\xf6ak6\xd0\x0b\xf7\xa5*\x82@\xa7\xc8\xc7K!\xbes\xd8\x18\x8ca\x80\xb8\xb0D\xc4\x0f\xb1i\xb2 \xba\xa8\xf1\xe3\x9fY\x03\x03\xe9\x91\xfe\xf4\xd8t\xb6\xe615\x88$t\xb0\xc7\xc1\x9c\x93/ \x8b\x17\x06\xae\xe8\x87\x1ef\x88\xd4>\xfd\x84\xdbS\xef\xe3\x86\x9b\xf5\x92\xca\xed\xd5\xadud\xaf\x17\x1f\xa6\xaa\xe1\x0ewG\x8b/\x00\xf5\x10\xdb\x18\x94\xe7\xd938\x84\xef)\xfd{\x061\x1c\xc3\x04v \xf6<\xb4\xd16\xbc\x184\xe1\x8f\x1bMxoz\xb4wt\xf0tz\xf4\x8df\xbdg\x9f5iOk\x17\xa7\xc5\x16c\xd0\xe4\xde\x0d\xbe\x1f_s\xb0lG\xb5\x03\x9e<\xfa|\xfe\xa4\xcc\xc88\x9dZ\xaer\x7f\xcf\x16`\xec\xb3\xa5\xf6!\xe6<\xae\xdc\xc6t\x97\xbd\xa3+\xb07h\x0c?>z\x0c\x87\x961\xecO\xd9;:\x86Cm\x0c\xf2\xafB\xa7\xeb\x86\xd8\xef\x08\xaf\xb8aJ\xeaS\xf8\xaf\xff*}=\x08&\xe1\xb9O\xfe\xeb\xbf\x88\xcf0\x05\x0bC9\xa2X\xbb\xbe!\xa5\x888RR\xc4^\x17\xe5^\x13\x92\x8c\xe5\xea\x92\xbe!\xe2\x1bR\x7fC\xa4o\xca\xba\x04\x93\x1d\x1b\x03\x985:\xcf\xda\xea\x1a\xd7\xc2\x1a s#\xf9IM\x81\xc1\x8e\x9eeE3\x86\x11\xec\xec\x101\xef\x13<\xda\xe3\x9e\xe9\xd2\x0f\xbe~\xc2\x87C\x00\x02o\x90\xd4s\x9c\xf8\x9a\x82\x83o\xdc\x90\x1e'\x07\xedc5\xa8\xd3\xa9\xa5Sn\xe9\x81\x8b2\xb9@\x9c?l\x1c\xed\xcd\xfe\xbaq \xb5\xa1\x0cf\xc88v\xa7\x8f\\\x8f=}\x1c\xae}A\xe4\xa2)\x16\xb18\x7f\x93\x83\xa7O\x9fN'\x94\x8b\xa8\xdf\xef\x0e\x1c\xf6#\x97\xaf5\xec\xd6\x18.D\xe2Li\x06\x93\x83\xf6\x14\x94Y\xed^t\x8a\xf0\xe9\xb0\xff\xd7A4x~\xca?\x9fL\x0f=.\n\xdf\xe1\xb4\xe3:\xbbu)\x95\x00\xdf\x03\x06\xf3\xec\x05\x07\x7f\x0f\xf0G\x94\x85\x91`[~q\x82\xe4e\x1b\nf\x1a\x14\xcc\xbb\x17)3,Rf]\xa4l\xc0\"}#\x90\x89\xbe\xd7\xf5\x89Gu\xde\xf7\x80\x11!v\xa4{0\x11\xa9\\\x07@\xd7\x0d\x80\xab\x15\x9a\xb5\xd7\xf1F\xf8UX\x81\x8bu\xedw\xa7O\x0f\xe8$S8c\x8c\xd0x\xf2\xf4`\x0c\xf7\x90\xc2q?\x05\xb2\x01\x8c~\xf4t\xd8$\xee\x15\x10\xfe\xfbM\xe7\xdb\x81\xfa\xcd \xbd\n'i\xd9to\xd0p\x87\xad\xfe\xf0\xe1b\xcf\xedA\x0f\x00\xee}\xc3}\x9dd\xa1\x01\xba?n\xb816\xd9(\x1a\xb6\xc6\x82\xeb\x1b4\x8co\xb5j\xadaL\x86\x0e\xe3\xc7\xac\xbaJ\xc8#\x97\xe3\xb0w\x1cc\xc1\x80\x0e\x1b\xc7#\xd7\xa3\x7f\x1c\x93!\xe3@\xe6\xd9\xca\xcdX\x848<\x9d\xa7\x82\xe0\x98\x15\x0b\xaam_\xea\x06\x04:2I=\x96t\xcc\xe6\x88\x12\xdbc\xfce\x1dN\x1fx!H\x13r\xba\x14\x94D\xdaB\x93\xac*#\"N\xa1\x84'\x1039\x90\x15\xbc\xd1\xca\x9dP\xac^I#\x99\xf0w\\\xc9\x14\xabXW\xd3`\xa4$\xad\xa6\x10\x9f\xd5+\xba\xb3\x13c\x808N*\x18\x964\x16K\x9a}\xb3%m\x11\x15\xdd\x16,\x86E\xd5\xd7\x92\x02\x8b\xfd}\x1f\xf5(\xd6|?\xb8;M\x06\\\xb7\xf4\x04\xb4\x96O\x197\xf9\x1f4\x11\x13\x05\xf2\xd5s\x99\xfaLr\xdc5\x9b3\xc3\xf5\xf0\x9b=\x9b\xb0=C\x11)\xa5\xa9>(\x1dl1\x1b\xfb\x91\x166\xd2>\xc9\xc1\x94\xf2\xef8I>\x1b}\x92|\xee\x86IN6\x9a\xa4\x89Z\xf9\xeaI\xee\xf9\x92H|\xd0L\x19\xcd\"f;\xdd\x93\xa6;m\xca'\x07\x96\xbd6\x1cg\xba2\x1f\xcd\xdb\xdfI\x16I+\xf3;l\xff\xe6+cY\x95\x89eU\xa6\xe63\xb3\xdb\xbd2\x93\xc1+\xb3!\x8a\x15\xd2cyY\xb6\xac\x06G\x02\xd4\xb7\xd0\x03\x86\x8e6\xcbN[\xb8%f\xa8d\xc7\xe0\xe6m\xb6\x07C\\lF,=Qz\x1f\x89\xc1+\x19\xdd\x08\x917wJb\x7f\nsL\x86\xdb\xe9\x84.\xf0\xcb\x10C\x14\xf9\x1a\xdew)\x96\xaa\xe0\xf9s\x18S<\x1a~\x13|\xb5!\x05\xf0?e\xa3;\xa8\x88\xaf\xdal\xb1\x17\x12\x81\x915\x04\xc6\xc6;>\xfa\xfb\xec\xf8\xefB\xa0L\xa6O}\xd8\x99L\x0f7\xa7Q\x14\x1d\x12]Z\xe6\x930\xf9\x1a\xfa\xe5w$_v\xa7O\x0f\xe8\\Q\x860\x0c\xb4\xff\x8e4\xcc\xefH\xc2\x04_K{0`\xca\xdd{;\x80\xc4QH\xa2\xaf\"h~Gz\xc6\xbeD\xea\xf5U\x8c$\xc4-\x1e\xb0\x8a\xff@\xc4\x8fE\xfe\xd4\xbd\x8a?i{\xd6\xe7U\xd1\xf4\xb4\xe9~i=M\x06\xf5d\x93\"uw\xf5\xe3c&e\x13\x14m\xd4U\xef\xac\xa2l}\xb7\x19\xdd\xd2\xa4\x9b\x1c\xa3Cd\xed\"\xd8\xd8\xd5\x97\x9a\xa7\x97\x94\xa5\xa41E\x90+\xd0\x0fI\xdd\"Wq\xe45 \x88\xce\x0b\xcc\xfb\xb2/\xbdS\xdc\x8a\x84\xd2\x0cP\x1eVO\x13\xa4\xcb\xf0\xa6\x0c\xf3kR\x9e\x97a^\xf6gC\xad\xcdx\x80\x19kj\xc30\xf7PdU\x1e\x91\x0dz\xc8\xbb\xc6\xcbZ{\x95\xce\xfb\xdb\xcaU\xe7\x8bz\xf5\xd5\x1d\x95\xec\xaf\x08\xc6^\xda\x916Jy92Z\xe5\"A\xcb\xf4[\xb99n=\x12\xc8\x8d\x1b*\x06]\xe6\xcaA\xec\xb1#$M\x0c,]\xc2\xe4\x04b\x9e\xd5`g\x07\xcd\xc2b\x18\x01\x03\x92\x14\xd6\xd1_\xa6\xb8/\xb5\x93\x11eA&d\x17X\x18\xaf\xcd\xb2\xfe\xb105\x9aY\xda\x06\xfd\x1b\xf3\xb9\x14\xa4\xac\xf3\xb8\x94\x8a\xa9N\xca\xcc\x9e2\xcf\x9c\x0bS\xe8\xfd\xba\x00\xc1\"\xc6\xf4\xf6\x1b\x00\x02\x83\xd3\xd5\xc6\x99\xadEz\x02\x0c\xa9\xc1\xd1\xa6vC\x8c\xe9s%\xb8\xd0\xfe\xc4\xe7Y7\xfa2#\x81\xec\xe2$\x07,\xb7Y\x1e\xd1\x87n\xe9t\xff\xa0F\xd4\x96\xf8h\xf6|\xabz\xb2\x19C><\x9b?{\x9d\xf1{h2o\xcb\xb2c\xbfj.\xe0\xdc\xe6Ul\xf3\xfch\xf5\xc7s\x97\x98\xf2\x9d\xf3\xc5b\xa9\x92\xacF\xbf\x1cF\xca\xe0\xe7\x19\xc3\x0dj\x91\xd5*\xfa\xfd`O`\x0c\xe7\xd1\xc4\xcf\xa3\xed\x9b\xa1Tf\x1bl\xe3\xcc\xab%\xba>SF{\xcc\x93\xc8\x8d}h\"{P,gL\x0bo\x87'\x06\x8b}\x04\"L\x93a\x01\"viB\x85\xb6|r\xacB\x96Q\xf8g7\x15)\xeds)\x01\xa6\xd7\x91\xbc\x99\xb2\xdc\"N\x95\xf9\x10\xd6\x13\xe0\xb6z\xe8\xa3\xacLB\xc0\xc5j\x96\xc1\xbfB\xb8\x81\xcd^\xd9\x8a\x91\xa3\x8e\x81N\xf6op\nOf\xff9\xfa\xe5\xc9x\xe7\xe8\xc5\xce\xff\x0bw\xfe\xb6sy\xf1\xe4\xda\xe6z\xf3\xba;\x84+\xa0r\xf6\x0c\x9c1:\xfd\xabiB\x8f\xb5\x02ul\x96\x0e\x7f\xb6*\x00o\xcc\x01\xda\x08\xf0\xa88\x13x\xd2\x9b\xe3\xb2q\x90\x89Ex~S^\x87\xee\x14*1\x0bl\xd3J\xec\xe0\xc1s\x8c\xe6\xbd/P\xf4\xfe\xd3\xdd\xbd\xbd.\x80\x1b\xf3\xfcp\xf6\x1aP_\xd2\xe7\xb0\x7f\xb0;9\xea\xabL\x1f\x96\x88b\x97\x8eggB\x07\xc3\x93ILw\x8f|\x98\x1cM|\x98\x1c\x1eu\x80u\xf1DYZ\xc6ie\xce\xa5$\x1e{\xf6 \xe0c\xaf@\xa4~\xb2J\xf5\xe4\xe7\x1fi\xf4\x98\x10\xaa\xb3Jo/\xdd\xd9\x95\xf0\x98\x1c\xecN\xad)\x04\xc53lU\xfc\xdfy\xc8)\xf7\xd18\x80\x11\xa5\xebvx\n\x82g\xcf`\xc2\x0c]v\xf8l\x8c-\x88\xb4\x89\x9c\xef\x190\x1f;&o\xeeo\xca\x12U\xf4\xdd3\xd6\xe1\x84eg\xe9K\x7f\xc0\x07\x93v\xcf\x83\xef\xdft\xbc7\xb0\xf7\xe9f\xbd\xc3\xf3\xe7\x98\xcb\x00\x03lcB\x83\x94\xfe\x9a\x1e\x0e\x1a\x16\xee\xd3\xb0q\xedn>.L\xba0\x9d\xee\xb1\x10\x1ep\x00\xdbt\x848\xba\x0d\xc6\xda\x03\x1aq\x1e(\x14!\x92\xb4&V\xd2\xdar\xf6\x99p\x86\x19X(i+\x93\xab\xfbu\xd6\x7fy\x8cw\xa6\xe3t'\x13>\xb5\x07\xbfS\xb8&h\xa8\xd4}\xea\x05,\xe8|\xd3q\x19\x90/\xeb,/\x8b:\x85\xf1\xe0\xd6\xf6\x0e5\x8a:f\xc5GZ1\xa5\xd3\x9cY\x86a\xf0y\xd0\xfb\x0b\xc7<\x02\xfb\x89\x15'\xa7\xc0\xefU\xc6\x8c\xae6\xfdb{\x1b\x90\x0d8=\x95\xee\xdd\xc3f\x93\xda\xdd\xf5\\\x16\xb1\xdf\x07'\xcaIX*~m_\xb1\\\xbbOw\x8d\xeb\xb5\xfbt\xcf\xb0`\xb4|_+\xafx\xf9\x81V\x1e\xf2\xf2\xa7\x9e\xc4\x0d\xd4\x07\xbbh/\xe6\x0d\x8f\x0e\xbac\xd0}\xa6\x1c?\x03\x0f\x9f)\xa7sV\xcfk\xad\n\x0d\xa2\x84\x84\xb9\x8b\x87\x9cX\xb3q\xddt\xa7\xd4FQ\x10)\xdd|6\xbe\xf0!\x9fMt\xbb\xff?\xb4\xffRd\xc0t\x0ctWT\x89\xd0\x9c$\x04c\xfc\xc4j\xf95\xa1\x102S\x0b\x97!\xdd\xd7J-,\xb0f\xe8+{_l\xb6\xf7O\xf7,gH\xf9\\_5c\xf8\xfb\x13HwvN\xda\xf0\x17\x05\xa8n9K/p\x01\xa5\xbc\xd1\x1aU\xc9K\xa5,\x9f\xe6+\"\x8ff\xf0\x90\x1b5\x92\x88y\xdad\xc9!\xf4/\xf2\xe8\x8b\xf9\xf4\xe81k\xd8,\xdf\xe5\xe5<,\xc3\xcbK\xe3j\xe4.\xf1\xe0\x0c\xd2\x99E\xbeW\x17\x1f\x83\xb3\x0c\x8b\xa5s\x01\xc7\x90\x06\xabp\xfd\xd8\xf9\xec\x8d-\xe0s\xa2_{\x06\x0e\xf0v\x8b\xa2\x8d`f\xc6D#9\xcb\xe8G!\xe5c\xc7<\xb1\x80\xb0\xc9d\xf7\xb1\x83CP#NH\xec6\xd2N\x8aY\xf3\xaf\x18\xeb\xd3\xb1a\xa8\x9a\xa8a\xd8Hmbbz\xbaY\x0c\x01q\xea\xdbb\x1bT\x12a\x14N\xe3\xb1s\xc6\xd8\"\xaa\x04\xe8\xd8\xe8\xbd\x81\x9d\x98\x1e\xb8\x9d1=l\x1b^\x17\xa7*XB\xf3\xa8\x94:lh\xc6\xd6\xf5\xd8\"\xc1\x0d\xc9\x0b\x8a'j\x0dS]TG\x86sn\xc6\x81\xe3u\xd7\x98\xd0\x1a\xb5]\x8b\xb9\xc6!\xads\xa6,{\x1bO\xa4\xe4K\xf9)\x8e>\xab\xb1\x98;bK\x82\xd8#Q_\x96B\x97\xb6\x08\x0f\x94\x8e\xba\n\xa3\xcf\xc6\x18\x0f\xa2%[\x98\xfb\x9b&\xab$\xb4\xc3J\x9b\xbf\x11\xb1\xb7\xc2.b\x1c\xa3&\x8d{\x02\xd5\xf6$\x80\x14\x16@\x81XI\xb7+X,\xb6\xd8\x93\xdf\xb1\xddb\xbd5}\xe2\x0f\xc0k\x86D+\xe7\xfa\xcd\xac\x83x\x1e\xfa\x86\xda\x93\xdb\xf1\x9b\x0e\xb5\x95{U\x7fzG\xdb\x93\x89\xf1[\x8f\xd6\xb7ir\xc4\xd35\xe0\xde\xd8Z \xcb\xc1\xe9}b\x1ci\x88\x16|\x8a\x1c6\x137\xc1\x83lV\x8dF\x17\xf2-\x99U\x1dq3\xe1[\xac\n\x8bX\xcc\xa5\xc4}\x0bb|\xdd\xc7\xe2? U\xdc\x801 N\xcb,\xda\xee\xde\xa6,\xda\x81\x89*\xc8y\x96B\x13y\x9f\xf5\x91\x8eqJ\x81 \x99q\xae3m\x14\x13\x0f\x86\xe6*\x9by\x86\xe0L\xeb\xf7R3\xe2\xaf\x98e{\xa3\x98\x9c\xa7\x1ek\xfe\xe4 \xb8\xf4\x02L\xa1\xa5\xa2\x84\x1c\x8e\xc1\xcd\xdc\x9cN\xcb\x9734V\x9e\x0f\x99\x1b\xb3H\xb0\xd5\xd0\xccr\x88\x1aL\x8a\xaa!\x01\x88\xd3\x8cc\x04\xde\x80gD\xe3\xa6E\xa1#\x1c\x9a~M\x19b/\xee2\xc5H6\x0fO\x1c\xab\xb8\x85\x01\xf8\xc0%5.1ghKYf\xe8\x98\x9fh\x9e\x13\x1a\x7fJ\x7f\x8f\x15?\xe4f\xee\x03\xb2\xae\xfd^so\xb6\xc6\xb4)\x03\xf3\xb7\xfd\xce\x83\xcb\xa5|\xa3\x1b\x93\xbafZO\xbeH\xa9\xbbwp\xe4\xb9\xce\"\xcb_\x85\x91\x08\xa5\xf5\xa8f%\x1e\xe0H\x17?p\x1e\xe0H\xe7\x0d2\xce\x1b\xe8\x10\x8d\x891\xf6\x9e\x1eJ\x8b\xe2n\xc6\xd0\xf9\x94\xfa\xe2 \xbd\x8d+\xdb\xca\xf4\xf1\x0c\xa6\x94~5\xd8)\x94p\xc6r\x15s\xf3\x8d\xd2g\xc9N\xab$\xa1'\xbcPP\xd7\xf4\xc2W\xa4#\xa8N\x0cy\xe2!\x16g\x15#\xd5\xa6\xa8P\x16v.N\xe4\xf0\x80\x91R\x19\xa1e\xa1Zv\x8b\x01\xd9##]\xcc\x93A\x1a\x12\xa2\xaa\x99 \xd3v\x05\x92V+\xc2_g\xed\xd7\xb7y\\\xb2\x97\xa1\xf2\xee\xc1\x87\x02\x19\xc7\xd8-\xe8\xb0\xe8\xcc\xa2\xe6\x90z\xc1\xf5\x90\xa8\xd3t\xc3\xf8V\xf9\xb00\xb3A\x96]\x89\x1a\xd3\x18\xf3\xe6D\xca\xe6\xecJ\x9bC\xc1\x99\x14\xba\xe8\x182\xce\xe1\xf3\xf7\x14\xae\xa5\xea\xfb\x149\x1c\xb9S\x1e\xc1\x87nh\xd4\x8cAz\xa3\x1d\x06q\x10\x8a\xe6 \x84\x86\x83P\xb4\x0e\x02\x8fa\xde\xde\xf4kR\x1a\xb7\xbc\xa0\xe5\x86\x9dV\x8fB\xd8}\x14Z\x89y\"\xbe\xdb\x11\x1d\x0ff\xc3\xf9\x16 I\x92\xe1\x1c\xdaD\xa9\xc1\x8f\xaf^\xbf\xf8\xf9\xa7O\x9c\xb0\xcc]\x0d\x0e\xb3 \xe7\xc70K\xdd\xfd]O\xcb\xdeO\xbe\xac\x938\x8aK\xfe\xfa)\xdd\x16w\x7f\xf7\x90\xff{\xe4I$\xcf \x18hgP\x05\x8d\x0c\xa9;m p./I\xf16\x9bWZ>\xd6AKG\xdb\x93\x05\\\x8a\xf5C\xea\xd6\x1abwz\xc0AI\xea\xee\x1eq\xaa;u\x0f<\xd7\x11&\x1b\x9f\xc2k\x01Z\x9c\x97\xe7\xe7\x1f\xab\x84\xfc\x14\x17\xa5\xff\xf2\xfc\xfc\xbc\xbcK\xc8\x8f$J\xc2<\xa4#\xa1e\x7f\xa2p\x85UHb\x92\x96\x1fIT\xe2\xcf\x1f\xdf\xbf\x95\xfff\x8d\x8b_\x9f\xb2\xcf$e?\xc22\xfc\x94\x87i\xb1 \xf9\x9b\x92\xac\xb0\xf0u\xcc;\xfd\xf7Oo\x7fz\x91$/\xb3$!8y,\xd1~\xbe\xce\xf2\xd5\xab\x84\xd0[\x8c\xbf\xcf }+J\xde\x92y\x1cbco\xe3\x15\xa1\xe8\x96\xa5\xe9}\x17\xae\xc8\xfc]6'o\xc3\xb5O\xff\xc5:\x1f\xc2\x98\xce\xe1\xaf\x15)\xd8\xd0?$\xd5u\x9c\xf2\x7f\xd8\x97\xe7\x7f\xfa#K&\x87\x15\xce\xff\xf4\xc7w\x88\xa5\xc5\xaf\x0fa\xb9<'\xd7\xf5\xcf,NK\xf1CZ\x85\xf3?\xfd\x91\xcd;\xcb\xd9\xa4\xcf\xd1D\x95\xa1sV@\x97\xfb|I\x08\xfb\xfc\x13eg\xf20\xfa\xfc\x92/x]\xc0~eU\x84#r\x82b\x9d\xc4\xa5\xeb\xf8\x02Z\x8cO0 ~X\xcb\x80\x8b\xd1\xc8\x04g\x11\x1e\xce\x8a\x8b\xf6\xbd\xa7\xe0%\x9fE\x867h0I\xe9\xf2E#\xf4V\xa14\xe6<\xdeJf\xd5\x05\x13\xd2%(\xf9\xa0@\"\x9bE\x94\xab\xc8\x02\\\xd7\x9e\x13\xaf3<\x14\x8e\xfe\xf6P[\x1am*\x96\x13\x02D\x0eH=\x1e\x86\xf5\xd0\x87\x9dI\x1f)e\xbb\xec\xdd\x94`m\"\xd7\x10\x80\x12\xf1\xf72L\xbf+\x81\x0e\x06V\xa4\\fs\xc8R0\xe6\xeaii+7\x1b$\x07-\x83Y\xca\xa9\x0d\xeav\xd2Y\xa8\xc7\xef\x13o\xa6\xbe\x1e\xa1\x87\x19\x16ZR\xa4s\xe3+\xb1\xe3B\xc8\x8b\x80Mlc\xd3\x9f\xa1\xe5\x8eF\x91\xbe\xff\xf4\xde1h\x1aeY\xcc\x83\xfa\xba\xd0^\xb7`\x0d\x1dl\xc9\xa9(w2=\xf4\\'^\xe4\xe1\x8a\xe8\x1d\x89'G\xe8b\x13\xab\"\x92$AA\xc1l0\x8f\x8bu\x12\xdeQ\xac\x97f)q|\x9c\xfb\xa1\x17\x84\xeb5I\xe7/\x97q2g\x99\xca\x83\"\xa7\x80\xd2\xf95\xbc \x8b(\x8f\xd7\xe5\xb1\xe33\xabV\x12DYZ\x92\xb4\xfcs\x9c\xce\xb3\xdb`\x9eEH\\zA\xb6&\xa9\x8bn\x03,j\xa7\xf3\x8c}\xfa\\T ^\x9f2\xc5\xf1\xb3_\x9e\xf0W\x98\x81)\x88\x92\x8cE\x8c/\xf08\xbd>\x81|g\xe7\xc4\x03\xae\x9a\x94t\x8d\xb3l\x96_\xd8\xad\x02\nWS\x89\x9a\xaf5O8\xcf\x94\xd7\x94\xa4\xed\xe7\xa7\x8c\xf0\x89\xabf\x04m\xdb\x0c\x93\xa2\x12\xb7\xf4\xfc:\xdce\xe8\x83\xfa\x9aK$)\xc68e\x0eX\xb4j\xe1\xaaY\x95\x08\xd2\xe0\xc7\x10\xbb\xa9/'\xe8\xed\x07\x87\x02}\xa0\xf7hDb-=~\xae8\x96\xf6\x01?\x9b\xa4\xabx\x17\xbe\xe3\x0e\xce\x1eW\x84\xbb%\xfa\xf5\xb0\x10\xa8\xa9\xb71\xcf.\x11t\xbb\x9e\xeb|&w\x85~\xf2\xd9\xa5U,\xcc7\x1av\x8e\xe1\xa3\xee\xc1\xc5?\x98\xec\xe7\xf1\xa34 #g\xce\xe5e\x94\xe5d\xe7\xd7\xe2\xb2X\x869\x99_^:\xa2O\xf3;\x8a\xe8\x1f;\xa1XL(f\x13\xfa\xed\xa1o:6\xc4\xe9DYZ\x94y\x15\x95Y\xee/\xc3\xe2\xfdm\xfa!\xcf\xd6$/\xef\xfc\xb8\xf8 \xce\xef\xfb\x85\xbf\xe6\xc5o\x8aW5\xbf\xe4\x97\xd9OY\x14&\x84a\x03_\xa0\x05\x9fc\x1e\x99j\xdbl\x95'{^\xb00\xcaTtQKf&\xf6\xfbV\xd6\xcc\x98\xa3\xcau+\xc6#\x9er\xdb\xf9\xb2\xb9\xc6\x18\xd0\x98\x99\xd4\xa0\xb8\xa5\x0d\xcdUfs\xcb\x10PA\xc8,\x94\x17\xbd\xfb\xb7!W9\x9d\x1cy\xee\x96\xec\xeeBq\xcb\xbe\xc7s\xde\xfb\xe0\xb0?\x1c\xbf\xe3\xb0\xa1\xfd\xc9%]\x8a:S>\xf7O\xbaD\x83\xaff\xc8\xbe\x1d\xc5I\xe8\x8d\xb7g\xb6\xaf\xe1\xed\x9a\xa1\xaebHvf\x17\x041@\xda\xee`\x9e\xa5*\xffI\x9f\x07\x06\xbc(\xe0\xc6\xe5m\xe66\x92\x8d\xeb\xad\x9d\x19&\xc2\xfb\x99X\xf7v\xc3[\xb071\xcb\x15[\x9cm\xebF\xd4r\xd7\x02\x89\xb7\xbc[]\xa4K\x08\xd5\xf1\xbb^\xefm2\xed:A\xfd[\xd5%d\xaf\xf3\x11\xff\x9c\xce\xc9\"N\xc9\xdc\xa1H\x84\xc9\x8f\xf8\xabwU\x928Fg1\xa4E;\x119\x0e8\xbf3\x94Jc)g\xc4\xe0\x98\x02QX\xa7\xe6\xd5\xf4\\\xe8\xd1\xca(\n\xbc\x12\xb1\xe7q\xac\x9d\xa1\xb0\x08\xb5\x00\x0e\xab\x80\xc3u+v\xca<\xcfFV\x03KBCP\xe3 m\xdd1T=\x80\xc1D\x02\x8c-\xa8?\x0f\xd3y\xb6r7\xdeM!\x92d\x86\x8a\xaeC \xc2(,]}\x17\xe9xK\x1f\x1c\xef\x92\xd2\x8e\xa3Q*\x92\x04q\xf8\xb1{\xf0x\xb4\xbbk\xbe\n\xfb^M\x8f\xb6/A\xee\xc6\x1c\\\xc7\x9c\xf4\xe3\xf2\x93\xc7\xae\x00\xdd_\xad)fA\xf4\x9bn\x8a7x^\x93\xddn\xaa\xe7\xa8\x9fS\xfd\xef\xa0z\xf6\x9fZ\xf0\xf1\xbe.\xf1\xcb\xcc \xaao\x12\xff\xbb\xf1\xf1\xc1\xc4\xb4\x00\xc1b\xc8>Rn\xc2^ $h\xdb\xe6\x92\x10\xa3\xad\xf3l\x15\x17\x843&\xa5+O\xc4\xea\xc5\xa4y\xb4\"\xd3$\xfdN\x0d\xd2\x9e\x1f\xc29|\xe0}Id\xa5=\xf3!\xea.\xd2\xdalX~\x1e\x04:\xceI\x91%7\x84\x03\xd0\xba\xf0W\x96\x858\xd7\xddZ\x1e\xbe\x82\xff\x98\xec\x99\xa5\x05\x93\xf1#O/\xb3?m\xb2JJk\xc5n\xc6\xffq\xd0L~\x04\x0e\xcc3R\xa4\xdf\x95\x98\xf7g]BN\xae\xc9\x97-\x8b\x8e\x94\x83\xd3\xaf\xba\xd0\xf4\x82b\x8e\xe4\xfe\xabiD\xeep\nO\x82'\x9a|\xc7\x88j\x9d'\xc1\x13\x07f\xe5\x85K\xb4\xbd\x128\xb6\xb5p0\x04o\x93Y~\x81J%\x1f\xb6\xac}@\x0f.7-\xef\xa6z\n\xf3\xe5'A\xa3\xfb@ e\x1b.Tn\xeaN\x0f\x0ft/\xdc\xb8~u\xa8\xbfB\xd2\xceD?\xc4\x01W\xc3 \x85\xd1\xf6\x08\xc8\xeb\xf7g=\xc0DPE\\\xe7\xa8\xed\xd8\xf1\xc0\xaf\xad\x84\x8e2\xd02\x90\xe0\x04\xcb*\xad\xbcFPS\x17I\xe2\x94\xb3f\x8e\xc7\x96\xa1\x9a\x0c\x83*+\x90\xe5\xc3\x91\xb6\x8c!\x9b\xf6\x0ckuWi9I\x0f\xd2\x11\x10\x93\xd9p\xd7N!s\xeb\x1d\xf3:\xb7\xccBPW2A\x9d)@\xb1s\x0f\xff\x1e\xfb\xb7\xc1\xd8\x87\\G\x82h5u\x0f6d\xb6L\x82\x9d\xd4\x9d\x1a\xc9\x9bC\xb3\x01\xc7dl\xf6CAi\xc6c\xc1l\xcc\x1d\x94\x98\xc0G\xfc8Eb\xf4\xb7\x0748j*\xfc\xa6[3:\x97l\xf7\xd0\xbd\x1bC`0\x0f\x84\x98\x87\x9f\x0e)\xf3[v\xb0\xb9U\xb0p\xb5\x08\x06\xbd\xd4Q{;\xb8\x00\xf6\x9a\x94\x92\x84\x89\x0d{C\xbf\x91\xdd\x03}K\x84\xcf\x90\x99\x12\xdd=\xd4\xad\xde\xb9\xcf\xd0\xa1\xceQp\x9f\xa1\xc3\xe9?}\x86\xfeA}\x86(\xaf\x94\xbaO=\x1f\x9c\xb7\xe1\xfa[9\xa1\x1d\xea\xde%\xdc\xebdj\xf6:\xd9\xdb\xd5\x0f ;P\xfa\xf1\x0by\xedG\xfb\x81\x18\xe1o\xc9\x11\x93|\xb628\x06'k\xe4\x0dR\xd5\x8a9\xba\xc4n\x89\xe7\xa1\xa4\xe7\x81\x82\x0c\xc6\xb6\x86\xfd\xc0U_3z\xae\x8f\xc6\xe3\xa7\x93\xa3\xa3\xe9\xfe\xde\xd3\xbd\xf1\xd1\xd1\xa4-nx\xf2\x9f\xee\xd9\xf1\xf8~6\xd99\xba\xf8e\xfe\xbd\xf7/O\xfa\xd6\xc0\xa2\x86\xc1\x10>|:FZxk\xcb%\xd2U\x13\xfa\x13\xc2\xb2\x9f\xc8F\xae13v\xe3hg\xeb\x94\xf9\xee\xe7AI\x8a\x12u\xba\x88\xb1\x84\x0b?\xcb\xffy\xcaC\x97\x96\xf0\xac\xd7\xefd\xc8J\xf5\xad\x82\xed$Xb\xeft\x0c\xf7T\nu:\x08m6\x17\xc2\xec\x84\xd5r\x1e\xa2\xb7\xe1\xc9/\xc1\xfd/3\xf7\xecx\xf6\x9f\xb3_..\xbe\xbfwg\xcew\x17\x9e{v\xec\x9em\xfd2\xf1f\xff\xf9\xcb/\x17\xf7\xbf\xfc\x12x\xdf\x9f\xfd2\xf1~\xb9x\xd2\xbe9O\xfe\xf3\x97\xdb\xef\x1fu@\xb8\x7f_\xa3o\xde\xd2\xc2\xdf\x8bm\xe8>A\x8a9k\xaa\x90bu\xc1U\x96%$L\x9b\x12\xc5Ik\x0bY1z\xbe*q\x9c0\xbaX&\xff\x12_\x10\xb6Cq*d\x88\x1b\xa9\xf9j|\xd4\x96\xe42\xf15\xb9!).\x9d\xf2\x13I\x03!\xe1^\x85_~\x8a\x8b\x92\xa4$o**\x855\xb3/\x8d\xac=\x84|C\xd0\xd5\xd9Xlo\xcc\x04\xda\x9a-8\xedi8\x1bD4k[\x00\xda9L}H\x83Wt-_\xad\xe2\xb2D\xdb{,k\x10\\\xb3\xf2\\\x0d\xa1\xbe\xd5\x16\xbd\xa9\xc3\xa9\xe3\xb7\xea\xfb\x89\xf6}A\xf4\x1av\xa8a3\xd1\x06\x91\xc9\x18\xdd\xc3\x99.\xd7$\x9cH%c\xeduV0K\x8cN\xabm\xf3\xb9\xf2\xd50N\x0f\xea\x8c\xc8*\xee\x8e\xc8 )\x11,\x96\xcd1\x8f&(\x1fsW\xbb\x06\xbf=Pr\x81\xd0\x999M\xd4AwK\xae\x16\xe0k\xee4\xdf*gF.\xedr\xe1\x97i\xa2\xd2x|\x0e\xd9\x14\x97b^\x91!9[\xb0\xb0\x1fb\xf1\x0dY7\xe9\xec\x17\\f\xc7\x1d\xf4~N\xa3\xb0\xba^\x96>Ti\xb1&Q\xbc\x88\xc9\xbc\x9e\x1b\x0e-\x00\xf7;\x9e}\xd7\xf1L\x927\xd6\xdf\x82\xd9t|)\x99 \xefB\xa9\xf6\xd0Z\xe3\xac\xc9\"\xcaW`V^\xd8\xc1.\x83\xcb\xa9\xe75\x0e~\x9a\xed\xb9i\xc9\xba\xfc\xf8\xd2&G\xbfE\x9ah \x7f\xd2\xe5\xca'5\xea\xab\xfb\xb4y\x17\x16\x17r\x82\xde\xb8\xaa}\x92\xb7,\"\xdcD4\xdb\xf6\x91\xed\x84\x92=\xa0J\x813)\xb9\xadG\xbf\xcd2\xe8!\xdct\x1d\xe9\x8d\x83\x0c|\xee\x92@\x0c\x89\x92\xfc\xcd/$\x87}\xfd\xfa2\xae@\xbb\xd2\"\xcaaS\xc4\xc2\x06\x11\x91\x9aOn\xe0\x14fZ\x91\x0f\xe4\xc2X\x91\xf8\xa6\xcet\xb0J\xbb\xbb\x0d\xf3\x94\xcc\x81\xa5\x0b8\xa5\xc8\xbb\x85ZP\xdbjD\x9b\xc7\x06D\x84\xddT\"\xf6\xb0\xde\x1d\xb7)x\x0e\x15vi\x19\x0dsa\x88\xb2\xb4\xc8\x12\xc2\x80\xbf\xeb\xb8i6'\x1e\xd0*\x18>s\x9d\x15E|\x95\x10P\xc8\x84\x15Ye\xf9\x1d$$\xfc\x0csR\x92\xa8$\xf3\x00\xfeu\x0eI=\xeap>\xa7e?\x17\x04\x08\xfbJ\xc7\xf6\xae\x07e\x06q\x1a\xe5\x84\x02\x9b$^\xc5e\xe0\xb4\xb6\xb4\x89\x93j\xa4\xbf\xc4\xf8\xcb<\x8c\x90\x08U\n\\\x91\x0e\xc9v\x932\x14i\x98\xaf\x96^\xb3?\xf9\xf67\xbaY\x82\xc2\xa7(Hy!\xd1\x95&dS25\xd2*\xbb!b\x0et\x98\xb1\xc7\xe3\xbb#\xc2\xa3\x9bNT\xf0#\xa0Y+\x82\x92\xfcKXi57\x10o\x00\xf6\xc9\x96#\xeeYkud}kyS\xfb\x7fQB\xe9w\x81`\xd8\x8c\x0e\xbf\xf4\xcb\xdb\x11w5^\xb0\xfbl$$j\x0c\x901a\x1a\xddQ\xa1s\xcc\xddT\x02k\x94\xea\x97V\xf5\x14\x83\xbdr\xd9T\x0b\x16)\x90T[Q\x15\x98\xaa/\x19<\xd5\xe3-\xab\xb8\xd0p\xa4jlX\x9d@\xb8\xb3C!\x8e!&\x0d\xf0\xc5Hg\xe1E3K\xfa\xab\x99\x17\x9d\xa5R\xc0'\xda\xeeS\xf5\xdf\xc4\xfe\xab\xf6\"I\x86\xf1Vf]{\xebz\xf4\\\x85\xad\x8e97!\xecYf\x1c\xddm\xf3Lg\xf4Q \xa0\xe3\xdc\xed\xed\xce{\xd1\x1e\x92\xb97\xebA'\xe8D\xaf\xccX\xdf\x1en8 \xb6\xb0\xbd\xd0nGLs\xdb'z'\xda\xf9\xc1\xe5\xd0`+\x18y\x9a\xdc\xc2\xd3X0\x83\x1e\xee\xbe Oi\xa1\x8bO\xea\xbbqbotV\xdf\x99\x1dh\xf1\x1d|%\xba\xb6\xd1v\xa8\x93Ag\xd9D\x96\xb6i$\x16'I\xbf\xc6g-\xe2\xcf@\xf9 \x1a\x1f\x8eav\xd17\xd6\x97Y\x95v\x0b\x04tv\xdf\xa6\x1e!\xed\x8dm\x9f\xb3\xc68\x83/\x83!u&z\xee\xd4\x15\x84\x05j?\xbc\xd1\xb8\x11\xfb\x0c;\xc2\x85\xa9_\xf5\x0b 5q.\xcf\xc5!{\xbeO\x0e\x9fz^p^\xe6$\\q\xd7\xdd\xe0# \xe7\xe1\x15Z(\xe0\xef?s\xbfg\xf6\xc1\xe4)\xfa\x86\xfcX\xad\x13\xf2\x85\xa9C1MLP;\xf9\xb1zGS,\xfd\x10\x16\xc5\xa7e\x9eU\xd7K\xa6\xfb\xd8?\x1c\xa4\x83\xed\x0d\xd1d\x0ett#\x92\x99\xb9\x18\x07MyW\x93\x7f\x06\x95?h\xc7\xc4$$\x89\x0b\x8c\xb4\x02\xc2o\x83!\xa1\xb4\xcc\xef\xd4\xa2E\x9c\xc6\xc5\xb2\xcf\xc7\x87>[\x9dK\xa0?\xb5\x96\x8fujG\xed\xa52*{=\x0e\x93r\xa3NQ~\x84\xd6%\x0fD8({\xa3\x80\xfa\xdd5I\xe7qz\x1d]\xed\xecP6\x8f't\x81\x1cW\xd0\xfam\x9b\xf2\x10\x0f \xa2,\xffL\xe6\xdcc\xb5x\x9d\xa3]\xac\xa9XlRIy\\\xd3g\xa7\x86\x00\xa8\xf4y@\xb5\xb7\xc1V\xa8\xe3r\xcb\xb7i\xd5fCB\xee\xe4N\x82\xab<\xbb-\x18\xf12sn\xc6\xc1d\xec\xf8@\xff8\n\x9c\x8b:\xfaW\x13\x0f\x8cA\xc9\xb1\x0f\xfb\x1e\x8f!\xcd\xbci\xb2:\xda\x8f\xda\xdb\xaa\xbe\xa6\xe7e\x88Z\xd9\xeb\xf6pP\xc8\xe2\xee\xeby\x04\xa3 N\x97$\x8f9L\xd8\xd5\xd36\x08\xb1\xa3\xf9\x90\xcc\xc9:'QX\x92c\xbc\xdeO\x0d\x0b\xd8V\x85'\x1c\xfa\xe8z%\xfa\xac\x99\xc6i\xec\xf1\x906\xed\x1aK4\x81h\xf2\xa6(\xde[\x1e\xfcfH\x0c0\xf7\xe1\x86\xf7i\x07\x0cw\xf8\xb1\xe5\xe5\xb5\x114\x03\x97\xaf\x85H\xb23X\xc8N\x1f\xaaW\xda\xf7D\xdcb\"\x0b~\x0dt:\x82\x12\xa6\xe5x\x9b\xcd\xd1\\l\xab\x94\n|\x16V\xd7m\xd7\xd3K(W\xb6\xc5\xfc\xf1\xe8\xf9x_\xbf1PZ\xb5~5X\xc6\xd7\xcb?\x87%\xc9\xdf\x86\xf9\xe7\xf6\x16\xd0'\xc2\x8a\xa2\xdd\x7f\xef\xff`a\x18\xdd\x19L\x0e\xe0\x18&\x07\xbb\x87{\x96UP\x86\x02\\k\xcbh\xd3\x18\xce \x86c\xbe\x16Q\xf3\"\xa2\xe4H\x04\xc7\xb0\xf0\xcd\x8d\xc8\x19\x15[\xef\xbd\x06\x94\x87\xc9\xcb0I\x98\xc0g\xe2\x0b4@\xe6?\xe6a\x9c\xca\x85\x0c\xe2i%\xeaw\x0c3\xa8esR\x94yv\xc7\x0b\xcd;\x92\xe0;\x9e\xe7fN\xa2l\xce\xbd\xablxJ\xa9C?N\xea\xdePB&R\xc1\x00kP-\xbb\xbf\x07\xa7*\x17\x87B\x98$spX@w\\\x9b*\x03\xb3R\x9d\xe2.\x8d\xb8\xb8\x04\x7f_\xe1U\xfe\x90g\x11)\n\xed\xe3,E_\xd1N:O<[\xdd\x94\x92\xfc\xdc41Moe\xd8h>\x9b\xe2\xc9\x99 \xfa.\x8d\xba\xeb1\xf7f\x1cxteG\x87\x94\\\xec\x9f\x95xJ}mE\x07\x0d\x85Q3\x07\xe2\xee\x91\x84\xa4\xbe\xf4\xb7\xe2\x86\xa5?\x0f\x88\x8a\x89g =\xba#G\x8aggGB\xee>\x1a\xe0\xbb\x0dNrc\x1fr\xcf\x97\xb0\x94\xfb\x8as\xe4~k\x1f\x98\xd0\x94 E\x85<\xb5\xe4\\=\xd3_\xd1\xc60f\xbfO\xc5\x1b\xcf\xf3!\x91T\xc5\x83\xf6\xf4R\x05\x8aL\x8en\xdae\"\x1f{\n>\xa4\xbbQ\x89\x9f\x1c\x9e\xa3\xe6@\xc2\x8b\xe8\xbc$V\x8aBN\"0!K*\xc1\xde\xb8\xac\xf7\xe6\x9d\xdc\xcad\xd0l\xae\xa4\xd9\x98&\x91B_\xf4\x03\xf1\x88\xb8\xc6\x1c\x07moc\xf4QA\x0ca\xda\x9b6q\xc4!\xf2\x9c\x969\x06(\xfc\xe0\x96\"\x86\xa5\xc26\xe6n\x03\xbb\x07\xcd\xf3\xd6:vb\xa4?\x0c\xd9\xb4\x04\xcd@t\xd0a\x16\x04\xd5\xdb\x87\xf2y\xa6\x8a\xa0\x98\xcf\xb6~5\xf1o\x84Lv\x82#\x069\x92ln\x89\x02\x02\\\xeao\xe2z\xcd\x98(k$\x05\xe6\nu|\xad\x90\x81\xcd\x82\xad\x1b\xda!\xc7\xa8\xae`&O\x98^\x0e\x95d\x05\x0b\xea\xc6\xa3^\xe0j\xf8\x10\xc2\xe8\xd4$L\xa3\x0f\xc69e\x88\x00\xcd\x7f\xfd\xfa\xf6\xb1\x1bSg4\xf3\xc1q(i\xc1\x10\x80z^F#\xac\xda\x81R\x18IB\xc9\x15\x8bP \xe3c\xcdd)\x8fg\x17\"0<\xc1\xce\xad\x0d\xcf\xb4\xcfz\x17\x05!d\xc4\x9d\xf2\x98\x9a\x8f\x0f\xa2e\x95Z\x18-\xf1\xa0\xb1P \xd29v\xd7M@\xc4\xeb\xe9\x16\xf0\xd0s_\xef\xd0\x04!\x93\xc2\xcd\xc11D\xf5\xa6E>e\xc0\x12\xed8\x98\x17\x8c\xde\xf9\x1a`z\x1b)\xa8\xe8S\xbb\x88\x0b@d?\x0d}2\x1e\x90@\x86\xf2\xado\x81$\xc3\xe0\xf0\x97n\xff(\xc1Abtx%\xab\xb10ld\x85\xfa\xb8\xd0d\xa2\xe1-\xd9O\xbe\x8c\x83\xc6un\x85\x9b%G\xa7\x0d\x0bc\x95Pj\xc0\x1b7A'\xc6SviU\x1aN\"\xda\xeb7\x8e\x05\xf2\xd3\xe7a\x182xe\x9d\x94\x80\xf1_\xbatM\xec\x10\x0d\xe46\xd59\xdd\xdf\x03Q$\x07\x14,Z\x88\x17N\xad T\xd2\x80\x99&{\x18+\\\xd59\xe7\xaa\x90;\x1a\xb8\xa4]\xa8W \xf6\x86\xe6fw\xc8\xd2j\xd3\xa4/\xd9\x94C\xeb\"5\x92EJ\xf2R0p\xad:\x8a\xd4A\xab;e\xe55\x16*\x85\x00I\xbb\x03,\x98\xc8\xec\xe2\x04\xca\x13\x8fN\xa3*\x96,4 \x12\x82t\xd9\xac;\xadyy\xb7\x81d\xaf\x18\xdf\xee\x96J\x1f\xee\xe6\xc4\xfc\xd7\x84\x9b\x93{-{\xac;l:\x8e\xc9\xe5J~0\xcc\xe9\"\xa8%\xae\x9b\x05|\x97U{\xf5\xd2\xbbv\xde\x10\x18\xc7\xe7hL7\x1b+\xc4E#\xf9\xe5\x96JZ\xc5f{)wC\xc2y\xe0\xf8\xe0\xfc\xf8\xea\xc3x<\xde\xb5\xa4F\x83\xf6\x05\xaf\x8b\xed.\xbb\xf8\xda\xb5\xb1\x08\xdc\x13n{\x9b\xff\x15,\xc3\xe2\x0d\xe7\xb7\xc0\xe6\xd3\xf8\x9a\x97IQ\xc7\xda__\xd0\x8bK\xef\xc6\xb0\xda\xbe\xe5,\xac|\xc3\xc8:\xdc\xef\xfa\xe5I\xb5#\xcc\\66-\x1b~\x93\xde\xf6\x15\xf0T\xcd\xdb-\xc9\x8a\xcc\x8f^\xf7a\xcb\x07\x84B\xf3^\xf1]\xedG*5^\xb6\x94\xf2>\xac$\x10\xb1\x8e\xd7\xa4\x0f:0 \x80\x8ah\x9a\x1c\x8a/\xc34\xcdJ\xa0\x0d\xf9\x18\xa7>\xe7\xeaM\x9d\x15\xd1zn\x8b$\xed\x1a:$\xebY\xe4Y\x03cn&\xbb*\xc6\x1e\x19\xdfa\x80\xe4X\xa6\xab\xea\x84\xfb>\xac\x9b\\\xce9nh./\xe8\xd2\x8e\xd2B$\x0d\xd6J*h\x91\xd9|\xf0\x91Zc>\x01\xdd\xfb\x13\x80\xe7\x10\xb4\\A6\x81T\n\x0eM\xa90\xca\x17\xb0\xf0\xd3\x02\x00Rj\x1b\xd1%sr\xd5$\xd3j\xeb[R\xf0}\xd1\xfa\x9d\xe7C\xcc\xe5\xeeg\xc3p\xb7\xa0\x06\xa4#\xc3\xb6>\\\x94$\x07\x92\xcem\xc1*L\xd4\x8d\x84\xa2\xf1\xb0\x98V \xefb\xca\xc3^\xeb\x9c\xb7\x9dK\x07I=c\nZ\"\x9e\xca\xa2H\x00\x89\xb8iH\xe53\xe6\xa9\xa8\x06\xe8\x7f\x1b\xde\xe1Ua\x0b\x81\xb5\x11\xf4\x14PfP\xa0\xb1\x80cM\xd6\xdf\x04\x05a= 9\xa4\xaa\xa3\\C\x9f\"\xd7i\x9a\xa5;\xac\xd9'\x1c\xd3 \x9f\x83\xc1\xbf\xb9A\xae\xb6\xee\x95\xba\xee9+\x89\x05\x1f\x1a[\xf7 f2S\xe6\xe6\xe7\xc6*\x01V\x19\xee~-\x0d\xb2\xed\x0f\xdaq\xf5*\xf1MM\xf7!\xf0R\xd7\xe8\x19\xd5A`\x8e\xdd\xdf\xdc)~}\xb1\xc7\x1e\xe9\xb4\x91<\x92\x9f\x87\xda\x08\xc3\xdeP\x8e\x06_U}A)\x11\x19K\x17\x9e\x99\x05T\x16\x8co\xbd\x03!J9Z|g\xde\x99Y\xaa\x16[\x8d\xac\x86\x91\xb4\xed\x02$ \xd73 \xaaf\xd0\xfc\x1d3\xdd\xd7d_c\xcb\xba\xa0\x05Q-\x18\xc4\xeb\xc1\x04\x0c}\xe7&b#k\xb3\xb5\x1d\xfa\n\x0b\x17\xdc}\xd8\xf0\xc6\x1d\x83A\xf3.?B\xacp\x0cq\x8f\xaa\x8c\"\x1cc\x1c~\xf9\x11\x92\x07c\xee\x05\xf9\xa17\x9d9;\xdb\x8f&\x0b\xd2\x1f Q\x8ey\x19\x8e\x8dL\xbe\xb1\xaeU\xc83:\x85\x89\xf9\xf02I\x8f,) \x1b\xf8\xd1 \x9e\x8b.\x88\x152\xce\x0f/\xb0/\x85\x82\x836 CO\xd5 \xe2I#\xdc\xd9i\x1c\x8d\xba\xda\xae\xd2!\xad+<\x9b\xda\x8bA\xa7!4a\x0c\xc8\xb3\x1f;;\xbe\xa4\x15\xa5\xe4\xab\xa4/\x93\xa4\x1e\xf8\xcb\xa8=k\x0bL\x98\xf6\x8c\x93\xc4\x9dD`A\xca\x1f[\x1a\xf3nZ)\xb6\xa5A\x14\xa4V\x19\x94\xd9O\xd9-\xc9_\x86\x05\xf3\xb0\xd8rg\xce\x92|\xa1\xdc\x11\xd7\xbb\xd3\x7fw\xf0\x8f\xb0\x88\xe2\x98\xfeq\x15\xa7a~\x87\x7f\x85\x059\xd8\xc3ZQ1\xe5\xff\xeeL\xf9g\x93\x83\x84\x88\x16\xc4\xdfyx+\x19\x19\xb9,\xd3\xa2\xa7\x8d\x03\xad\x8cp0\xb59\xe2\x90\xbbm\x8d[\xc1,\xae\x9bt5\x12{@ \xccM\x98 )\x10\xf7\xf6\xb6\x1c\x98\x8e\xb1\xb8\xb5\x8eZ\xc8\xbcr\x19\xde\xe4\x8d \x8bP\x1e3\x10\x8774\x17\xb2Y\xcan)@g\xc8J\x01\"\xe2\xc6>h\\\x0b7\xfdZX]\xb7y&\xd3\xb2)\xd3\x04fiDj\xa1[\x07\xe9F\x1a\x93\xa3\xb1/\x99f\xb5E\xd4 !\x95\xbc\xc5\xa8\x0c\xbc\x82\xb5\xe9\x92\xf1\xdamt\xad\xe4\xdd2\xa8\xb6k\x0bt\x1d\xa0\xf0\x01\xb4\xe7\xd6\xbe\xe6\x852\x1e+\x9fk\xe9\xde\xed\xec\x9f\x9e\xe1~1\x89z\xd3\x1a%\xf7\x8d\xf8[\xbb\xa6U*\xd7\xa9\x7fi\xb5\x9a:\xbd\xfc.\x93\x94\xa4s\xd7\xf3\x81\xb4\"8\xfd\xa1\x19\xa9\x9a\x9b\x11\xb3\xe8\x1f\x8d=\x8a\x0e\xdf\xacVd\x1e\x87%\xd9$\xb5~\x7f\x0e6\xfb\xbe\xf0\x03\xd2\x1b=\xe2\x9b\x0c#u\xf7\x0e\xf7<\xd7\x833\xee\xbf\x8c\xc9\x13\xd1\xb0\xf5p\xff+\xa6z\xd3\x84o>2\x87R\x99\x9a\xd3\xc2\xed\xea\xc1\xc3*\x83k5G\xec\xedPC\xfc\x1275\xb5h\xee\xca\x07\x850\x8a\x0c\xaf\n\xf5M\xf4Uy\x02n\xea\x90\x0d\x0b\x1f4k\xf4\xb8\x95=\xa5\xb2\xf8V\xaa\xdf\xa1B \xc5\x00\xb6\xcc\x1b\xd8k\xfc\\\x17Z\x84\x05\x86#h)\x0bo\xb1\x10Y\n\x16\xf0\xfc\x14\xb3\x14D\xee\x82\xa7\xfc^\xc6\x8d\x93\xd3\x0eDn\xe1.<\xef\x04X\xe4-\x18\x8d\x0c\xea(\xb4\xf3\x91\xa5\xac<\xccP\xc2Q\xe3\x8c\\\xf8\x90\xbb\x89\x94\x02E\xc3\x8f\xbc\xb47\xd3\xfc\xa0\x93\xa6xH\xb4\xb0\x91\x10Tj\x03\x18F\xd4\x9aDo\x96\x14\x8fHa\n\xc2\xc4\xeeA\n\x12]\xa5\xbcx`R\x82\xeeA5\x07\x8b\xd6\xad\xf3\x8b\xb0P\xcc\x9f\xc8\x97\xf2]6'\xaec\xcb\x99\x92ah\x01\xdbx\xb4\xb0\xb8]\x029\x0b\xfb\xcd\x1d\x858\x82g\xcau\x16#\x9bX\xf1w\xb7u\xa1\x90.\xb1!v0\xfdp\xaai\xe5\xc4c\x96\xa8\xa0\xcb\x9aJNY\xe4\xb8i\xe3\xc3\x08u\xfa?V\x1f1x\xe9Zf\x86\x176\x0e\xe6a\x19b\x98\xc2S\x18\x8d2\xf8W\x982s\x07l-(\x96\xf1\xa2t1\x04\x05\x17\xbf\x08\xafkN\xe1\x95\x06m\xd5\x83\x17dW\x05\xc9o\xd0R\xca\xbcx\xd12\xcc\xc3\xa8$\xf9\x8fa\x19\xb6\x82\xfe\xb3V,\x16\xeb\xbd\xf4\x02}X\x9a\x17\x0cai&X\x99\x94{F|(/P\xec\xc0\x15\x94\xa8\xbde\x04\xb0iq\x86\x88\xc5\x1e|3\x1c\xb6^\xe3v\xe4$$p\xec\xaa\xb0&\xc1\xb4\xe4\xf6f\xf6B\xe9\xe8D\xdcO\xdaM\x9d.\xa8C\x8cj\x1c\xca\xdb\xaa\xc4\x84|\xef\xd9\x8e7~\xb1\xb1\xdbze\xbf\x95\xc6\xa6\xffL\xae\xfe#.;:\xb0Th\x1f%\x1bH1\xdf\xa8\xde\xe0\xbb\x80\x8c_\xee\xea\xa2\n\x00\x16\xb8\xd5\xd8lA\xcaO\xf1\x8ad\x15J;\x0c\xdb!U\x182\x80\xa6\xba\xcb\x0e\xfb\xd8<\x98\x96T\xeeA\xba\xb2\x83\xe8\xcaoBeY3h\x9a\xb2f\xaay1\xa7l\\\xfb\xd3}\xfe\xef\xc1\xc6y1;F'\xd2S\x1e\x9a\x92\x8d\xa1\x86\x8f\xa7'P\xc3\x0e\xe7\xdda\x87\xd5X\xe9\x96|WV\xc8 \x84t\xed\x0e\x92,\xc2\xc3~\xdcJaF\x9fe\\\x94Y~g~\x99\xadI\xaa\xb2\x7f\x86J\x98\xf2\xab\xb7\xd6\xeb8\xd1+\xd9\xe6\x0b\xe2\x86K\xf1\x82\x9b3\x7f\x8b\xc9\xcal\x89\xfa\xccV\x1cta\xd8wmxr\xc3\x1dFm\xda\xb8\xb4C\xc5\x9b\xd7\xf1\xde\x0c\x82P\xab=Im\x08\x13\xf3\xb0Ih\x15$\x82B\xbb3\x87\xae\x95\xe3\x83\xf3C\x92]\xd1\x7f_g\xf9\x8a\"=\xe7\xc2;\x01\x16\x16\x13\x13\xf3U\x08\xc0]\xcf\x0b\xe6YJ\x90\xc4E\x8dE\x07\x92\x13z\x97\x98\xe5\x10\xb4\x93\x1f!\xc4)_3\xc693;QV2\x0b/\x86`5,\x91\x0d>\xec\x0b\x93;\x8c\xee\xe0P`\xe0\xd0k\xcb\x0b]=\xc9@\xaf;\xbb$\x1eW\xcf\\\x9f\xb8@h\xd6\xe7>\xdc\xf8p\xe7\xc3\xb5\xde|\x81y\x0f}\x98\x1b\xdc\x92W>\\\xfap\xe5\xc3m/\xbb\x08\x82\x83Z\x83\x08\xb6\xfa\xa2\xc6\x05/\x8c\xf1 \xe8#\xc2\x15v2\x00\x18\xef\x8fe\xec1\x87\xe0k*1C\x8a\x8ej\xd0\xacf/\xfbi\xf8\x86R8i\xad\xdd\xea\xfc\xca\xe2\xfce,\xdddD\xc3Gb\x00vmt\xf9\x05\xbd\xa5G\xe0\xc0\x1bq\xa0\xdb\x95\xce\xe1\xb4^[\n&n\xdaU^Y\xd0\xf1\x0bT\xca5\x82\xedV\x85\xf7p\n/f fNz1s\xfe\xed\xdf\xea\x8b\x85E\xe8\xfc\xf1bvcH\x1a\xfd+\x05\x86L\xdfxc\xe00?S\"\x00\xce\xe0\x1c\xce\xe0\xd6uHZ\xe61)\x10\xa2\xfd\n\xf6\xd4uoX2\xb7<\xbc\xc3\xa9\"\xa2z\x11\xf0\xafio\xef\xdb\x14\xd1\x1bD\xc5W\xf4\x96\xb8o\x18\x19\x8e\"\x0e\xcf\xf3P\xea\xae\x8b\ni\xf5+\xa6>G\xcfj\xf7\xca\x87/>%\x11(\xba\xa5<\x85\x89\xed\xb8\xe2\xabT\xd1\xea\x89\x0fK\xcf\xf3\xe1\x9c\xb6\xf0\x1e\xe1\x8c\xd8 \xec1H\xc3\x15\x93\xad\xbf\xe2x\xfc\xd7\x81P\xe6\xbd\xd5\x9f\xcb\xe3n\xf1[L\xf7\x8bW}\xeb\x15\xdb 1\xb4\x178\xb4_=\x1f\xc2\x19\xa1\x94\xc9\xaf\xf4\xaf/\xf4\xaf\xa5\x0f7f\x11\xdf\xcaj4\xc1\xe6t\x8c\x9bHw\xed\xd6\x15\xd3\xb4\xc8\x14(\x988\x86\xbb\xa6\xba)\xd3\x97x\xf8\xae\x1e\x83A\xb1\xe8\x9bl3A\x90\x89\x97\x14\xc2\xad<\xc0\x7f_\xd0\xa9gt\xea\x97>\xacf\x97\xa6\xf0\xa2,|\x91\x1b\x07\x1f`\x04q\xf0\x1a\xbe\x07wM\xbf{\xe5!\xfc]\x99c\x11\xad\xea\xc2A8\xf7FJH9\xb5\xd0\x0f]\xdfC\x1d\xa7\xa7\xd4\xd2\xe4\xda\x08{\x01\xc1\x8d\xba\xb9\xae\x08\xb3:\xcc\xeb4\xd2\x12}7,\xae\x05\xe4\xb5\x17\xbe+ mk\x0c\x1d\xd6\x81`\x1c\x06\xfd`\xa3\x91X\xe2\xd6\x9aF\xd2\xe30n\x1c\x8c\xd5\x1f\xb9+\xce\xca\x10\xf4S\xf7\xc64\x08DV\x1fX\x9a\x1etb\xe5\x93\xb9\x95\xba\x93}\x16\xa54u\xa7G\x9e]B\xccG\xf3\x14\xb6N-\xcaT\x91\xda{\x1e\xdf8\x9e\x0fN\xf8\xf5j\xd4\xa7m \xa1\xce\xdc\x0b\xc2f\xf2\x1b\x92\xfbS35|\xf4?3\xdd\xa2\xaa\xf6\x9bn\x9a\x19\xa8\x95s\x98\xab\xf1\xcc\xf9A\xa6\x93}\xcf\xdd\xd2)uc&\xf9\xbeu\xb1\xc7\xfa\x0cyB\xc76\")\xda @\x813\x163\x8d\xec\xe5\x9a\xb58\x85\xd0\x83\x94\x1e\xde\x8a\xed_\x88K\xb1\xbd\x0d\x11\x13^\xeb\xc1\x0d\xb8\xf3\"i\xc2\xe7\x16'\x1e\xff\x8e\x12p\xb3b4b\xf1}\xdd\xff\xca\xdc\x08[\xbb\xbfoZ3#\x97h\xb3M\xed\xdd\x9f}s\xaa\xe8\xcel\xfe\x95A\x93\xda\xc5\xf7\x06\xd7\xa4\x94\xb2d\xabV\"\x96c]\x8a\xbd\xe3y+\x91\xc5\x9de\x176\xf9\xae\x9ae\x8b\xf33\x8dW\x85\xf2\xf6L\xfd-\xd1x\xc7\xeag\x9c!?\x83J\x97\xe4n\xb8\xf8\x87\xe6\xc5o%\xe4no\xc5?s\x14\xd7\x03\xee\xcbu\xf8?;G\xb1\xf5\xec\x98\x12/\xfd\xcf\xcd\xa5\xdf\xb9\xcd\xbc\xb7\xf6.+\x16\x8b\xee\x04\xb6\xc1\x04\xd5\xb5<\xb6\xee\xd4RO\xd8,\xd1:{\x96:\xe6\x8c\xb7\x9b\xeda\x9f4m\xb2{\xd0N@\xbf\xfb\xf4\x9f \xe8\xa5\xe7\x7f@\x02\xfa}sR\xc4\x01\x19q-\xe7\xbf\xae`\xb3\x9f\xa4}\xf3@\xe6\xcd\xbe\xc7\x14.\x99y\xe6\x82g\x016\xbf\xa5TOhu\x14\xe1c*DJ\x9c\x82ns\x84 \xd6x6s\x8e\x03\x8e\xc1\xc5\x08\xdb\x98D\xf1e6'/J\xb7\xf0\xe4\xee\x9d\xe7\xc3\xdd\x1f\xa4\xa2e\xe7t\xa5\xdd\x91?r\xf8\x15\xc0!\xa4\xee\xde\xc4s\x13\x0f-i\xbb\x1aK\x1a\xd7\xcb\n\x83\xf4\xfa0\x91\xcc\xae\x1f(eI\xf7\xe1&H\xb3\xdb\xde\xd6\xb0\x96\xb5\xa19\x86\xce\x16\x06\x99\x94\xa2\x9c{\x01\x05zS\x1fb\xfcc\x12d\xe9\x8a]68\xa5\xd4\x07\xc6\xcap\xb3`\x9d\x15%\xbf\x85\x08h&\x18\x81i\x11\x84\xf39&\x1a\x94Se\x197Cj\x00\xc9\xbcE\x10\xafh\x8f\xe7Q\x1e\xaf\xcb\x82\x8e\xac{j\x0by\x0c\xdc\xa1\xdc\x07\xe7{)\xac\x17\x85\x94\xad\x11\xb9\x0e\x9f\x90\x83\xe4\xd4\x16\x1b9\xed\xcb\xc9\xd2\x9c\x84\xf3\xbb\xa2\x0cK\x12-\xc3\xf4\x9a [\x1d\xb9N\x81\xa3r\xbcNK\xf5\"\x08\xd7k\x92\xce_.\xe3d\xeeJ_yA\xbb\xe5\xbe3,\x123\xb1\xc6J\x16MY\xdcS\xab2\xb9\xd3\x94Q\xb2\xa0oN\x84bG\x8f\x99>%\xc4\xd7\xfa\xfe\x18\xd6\x1af\xa0\xb0\xfa\x18\x9a\xecC\x9b\xd1)\xf6\xc1\x9a\x95\x0fVy5},\xce\xf5\xf4\xb996{\xee\xa8\xeb\xd8i\xd7\xda\xdb\xb5\xc5\x04\x9bv\xdd\xd7q\xcf\xeamJ\xe9\xb4\x0c29\xa53\x1ed\xed\xa2O\xbe1u\x89]\xe6YH\x14\xe5\x1e\xea\x9bl\x9e\x857<\xb6U\x16,ZQ\xc4\x05!\x8c9\xc5sRd\xc9\x0d\xf10\x9c-F\xb1[\xc5\x05y\xec\xc2\xb4V\x80-\xcc\x9e\x9d\x04\\\xd1\xad\xef'\x00M\xd4\x9f\xd9\x99\xb2\x0en&9\x963O+N\xdemmQ\x02\xcf\xf9H\xae_}Y#h\x8c\x15\x0f\x9bAS\xb6\xdf\xd6\xda5#u\xa7\x87:A\xd7\xb8v(\xf2\xffA]\xca\x12V\xe3*\xeb\x9dq\x03\x84\xa3\xde\xc5\xb5Q\xd7\x88\xa1\x02\xae\x1b\xc6\xa46\x1eW\x8f\xb12J\x16\xb5\xaeX\x85\x84\x9d\xba5\x15\xcf\xfb\xcb\xb2A\xb9yp\x0e#\xc8\x91Y\xce\xba\xf5\xbc\xf4\x90(\x85\x98\xbf\x9dk*}9|\xd4\xa054\xcb\xae\x89\xecr#\xc2\xb5\xf3}\xec[(\x14\x8e\xba\x8a2\x9d\xd8B\xa9\xf0\x80\x84\x14\x97@\x08Q\x12\x16\x05\x84\x85\xe2%\xfb\xbbLG\x93\xd2\x0bO\xa4\xc9\xbe\xe9\xc4|{W$\xe3Z\xb6\xc8\n\xfe\x02J\xab^\xbc&oS\x96\x1a<\xc5\x18]\\\x9d\x03\xe9h\xd4E\xe8\xe7h\x89\x92Z\x08\xfd\"\xd2\x84\xac\xa0s\x01\x0f\xad\xaeB\xf6\x89\xe4\x95\xbd\x95\x07\x0b\xce\x97\xb1\x80J\xe5\x8c\\l\xb8_\x8f\x03%8WJY\x1d\xea\x1a\xdf\x98\xbf\xda\x1dO\xf5W\x19\x7fE\xe1\x8f\x9c\x86\xb0F|\x86\xdc\xa4\xb5\x89 \x0b\xd4,\x83\xa5\xb2\x1b,iA5\xfe\xd0\xfek#\xf8d\xb9\xea\";\xc1\x163\xc27\x12=\xe7\x14:\x01\xf9\xb2\xceIQ`\xd6\xa4\xaa(\x81\xc4\xe5\x92\xe4p\xc5c\xccf\xb9D\x05\xb1`\xcd\x0e\x8c6\x86J\x1a\xb8\x935s\xccc6\x96\xaa3\x8eJ\xc2\x8d\xed\xe5\x94\xd8-\xd3jC\xa7\xf5\x0d\x0c\x08@\x07\xaa\x91\x96\x85\x95\xd5\xcc\xbd\x0c1,\xd4\xdd\xc6\xfb\xc8\xa8\x11\xb1\xc7g8\xfd\\\xa1CD\xb2\xa1K\\\x83\xcbKJ!}\x93\xfb\xa3\x1aX\xef\x8e\xbfM\xfc\xa4\x03\x93}`\xea\xee\x99\xedz'-\xc5\x12zMS\xe09f\xe1\x07\x0e&\x9eb\x906e\xe5\xbb\xe3\x03\xe3\xf5\x0cMc\x06a\x97\xb6\xce\xb3u\xd1\x845\xa4\x98\xaa\xe4\x01HyIN\x16\x05K\x0d\xc5B\xcc\xad\xe7a\x89\xf9\x0f0Nr&\xad{\xbb\xef\xe2\xef\xd8w\xa4\xba\xdd\x87r\xf4\xa9\xe2# \xa3\xf2e\xb6Zg)\xc1\xbc7\xbf=\xf8J\x95\x82\x94\"EY'\x90\x91\x88\x11%n\xa69\xf4\x90\x04x\xd8\x8f\xdcu\x0e\xf7\xeb\xec\xef|~\x01I\xffZ\x91\x8a\x9c\xf31\xd4V\x15\xbe\x94\x87^\xab\xfb\x92\x87\xa2\x15\x11\x9d|p\xc4\x14T\x01\xa7<\xc9E\x96G\xe4gl\xa8[\xb6f\xe8\xf0u\xf3\xad\x906\x96\x03\x07W\xfa\xe0H]\xab\xe3\x8b\x14\xd8\x17\xcap\xaeP^Qp\x1d)\x85\xaa\x94 \n\x1fb\xb7\x90\x1b\x90Z\xf3\xd4/\xe3\xe2C\x95\x93\xd6\xa9\xe0 D,\x8cB]\xf3\x18B\xf5\xca\xd2\xc6\xa4\xb7\xc5\xb7\x00N\xa9{ ;\xaf\x0b\xf8\xa2\xe1\xbc\xe2mV\xa5%\x99\xf7\xc5\x0d\x14\x14\xb5fc\xa9NC\xdb\xbe6ae\xae/\x1d\x0dm\x18\xe6\xfa\x1f\xc9: #\x16\xa0ph\x1f\xe2n\x18\xea7\x8bm\x86\xec\xf9\xe3\xf7@,\xba\x1c\xac\xfe\x1b7\xfd\xdb\xb7\x1f\xb5\xfd\x04GU\x9e\xe3 \xdd\xdcu\xa2{\x16\xc3\xb2\x9a,\x98#H\xf3\xcburz\x05\x03\xc2\xd4\xf8\x0e\xfa\xdb\x1c\x8c'\xe3\xdd\xdfuQ\x9c\xf3W/?\xbe\xfat\xf9\xe3\xfb\xcbw\xef?]~xq~~\xf9\xe9\xdf\xdf\x9c_\xbe\xffx\xf9\x97\xf7?_\xfe\xf9\xcdO?]\xfe\xf0\xea\xf2\xf5\x9b\x8f\xaf~t\x86\xf4\xa9Q\x12\xd3\x897L*\xd1\x17!\xafu\x97\xcd~z\x14\xfc7T\xb7\xd1I\x8f\xd3\x7f\xba17\xa6\xbb\xba&\x14\n\xae\xb2\xf4\xd5\x97\x92\xa4\x94\xf8-0\xca\xf85)\xb5\x12RD\xe1\x9a\xfcH\xc8\xfa\xa78\xfd\xfc!\xc4\xa4\xcb\x84;\xbb\xb5\x8a\x8be\x98$\xd9\xed\xab\xbfVa\xf2\x1f\xe4\xae\xe0i\x05\xe3d.\x82\xbe\xb0jY^\xb2\xccz$\xb8*3^H\xf28L\xe2\xbf\x91s\x12\xe6\x11ko\x1d\xe6\x85\xfc\xfb\x9a\x94\xe7\xe1j\x9d\x90\xf3hIV\xec;L\xd1\x10\x96\xe4C\x98\x87+\xad\xa4,I\x9e*eo\xe3\xf4'\x91;Z*\x0d\xbf\x18J\xffX\xc5s\xa5\xe0\xc7\xb0$\x9f\xe2\x15Q\n\x99%\x8cR\xf4C\x96%$T;~\x1d'\xeawo\xd2\x92\\#\xad\xd3\x94\xbd\xabVWZ\xd1\xdb8\x8dW\xd5J\x1fn]Fi\xac\x97K\x12}\xe6\xdf\xad\xc8*\x8b\xff\xc6\xba\x8a\x8b7\xabU%\x84~\xa6\xd0>\xe2:_Q\xd6p\xfa\xd4d\xbd\x1e\xd7\xaf\x8fL\xaf3\xfe\xfap\xcf\xf4\xb6\x12\x1f\xef\xee\x9a^\x87\xf5kc\xd7\x05\x7f\xcd9S\xf9\x15\x9d\xdc\xff=\x7f\xff\x8e\xeb\x00\xfa\xec\x19\xec\x9eK\xc2*\x816\xc6\xce\x9b1\xb9-p~\x93\x85\xa4kb\x97\x0d\x11P\x15*+X+\xc6Z\x9d\xf4\xa4\x93\xb2\xa1\xf4:\xedD\xbc\xb8\xeb] \xde\xc8+\x17C\xd6|qy\xe4\x9a2\xfb\xbf\xe7.\xb2]\xaa\xdfj\xdd\xc3\xff\xcf\xde\x9fw\xb7\x8d#\x0f\xa3\xf0\xff\xcf\xa7(\xeb\xc9/C\xb6i\xc5r\x96N\x9c(\x9et\xe2\xa4\xdd\xd9z\xb2\xf42\x8a\xc6\x87\x96 \x8b\x1d\x89TH\xd0\xb62\xf2\xfb\xd9\xdf\x83\x02@\x82$\x00\x82\x8e\xbbg~\xf7^\x9e\xd3\x1d\x8b\x0b\x96B\xa1P{\x85i\x1a\xae;t@E\xb3\xe8\xd8\xaa\xfe\x8d\xbd\xbc\xf70@v4nv4K\x93\xe5O\xef\xdf\xa6S\x92\x125\xef7PO\xab|g\xabr\xe1\x11c*S(VN\xb1\x84,\xe5\x92\xf4\xd9\xbe\xb4}Z\xc0\x8b\x94\x19x\xa3\x8c\xcf\x04oM\x8a\xa6\xde\x93/\x1e\xf1\xfb\xcbp\xe5Q\xccd\x1fe\x14g[\xbe\"\xa6\xf5:\\\x95oB#\xc6 +;D\xf1\xf4C\xe2$\xa2\x80b\x16\xab\x1b\xb8\xa0jV\x0d\x159\xdb\xef\xcf\xa2\x05%J<\xa3\xb1 \x91hA\xefD\xa3\x8d\xf9\xf3\xd9i\x7f\x18N\xe6e\xeb\xc6\x1c\x01\xd2*0J\xc7h\x0dM\xc78{O\xe4^\xd7X#\x9a%\xfe\x18\xc8\xe2$]\xe2 \xc2qn\x08\xef\x03\xa4\x13\xcfcW\xa4m\xc9\xe8\\\xf4\x14e\x05\xdd9\x14}\xe4X\xfd\xf8\x9a{\x91\x13qj\xb6\x8a\x9bu\x97\x10A%^\x87+\x17t2\xa2LJ\xa6\xf9D)\xf2g\xcb\xfdP]W\xe2\xb1\x95\xe5\xa6\x9df&\xd8\xcb\xa0\x12\xd1\x08\xca\x90\xdfa\x97\x7f\xd9\xa8\xcfD=\xabr\xbc\x06\xcb\x9cP\xf7Z\x0f\x84\xa8\xed@\x88D\xa5\xa7\xdd\x00\xf2\xf2n\x1c@\xd4 L\xd9:\xa3d\xf9a\x9e\xc7\x9f_G\xd3\xe9\x82\x9c\x87\xa9]\xe4\x07\x9d\xe5\xce\x04\x13\xd2\x9fJ\xf7I\xc1\x85\xe9K*@\x97Fu/7\xf4H\x86\x0f\x8cyKc\x8fz\xe8\xbfE\x9c$\x8b\xe9\xc3\x1e/_\x8f\xff\xa9\xaf\xe2\xbd\xf1h\x05\x07\xb8v\xb7\xe1\x00\xf6`\x1f!|\x0f\x0e\xe0\x8e\xf8\x9b\xdd\xbf\x0d\xfb\xb0}\xeb_^\xe8\x9dd4\x0d't\xb3\x88\xc2l\x13O7\xd2y{\xc3\xf6\xec&\xf3\x96\x9b\x8c\xa4\xd4?\xd8\xe44\xf17'^\x98\x91\x0d9\x8d\xe2M\x92,<\x12\xc6\xfe\xc1&%\xe1\xe7\xcd\x9a\x12\x7f3\xc1\xc7\xec\xc0\xd9\xcc\xc3t\x83\xf2\xedt\xb3\x08\xb3l\xb3Hb\xb2I\x96\xab\xc5&\x893\xbaIb\x1a\xc59\xf17S\xe2\x9d\xe4\xa7\xa7$\xddL\xa2e\xb8\xd8L\x16aJ63\x8f\xed\xf1\x0dI\xfd\x83M\x14Gt\xb3\xf0\xc8iH\xc9\x86P\xe2\x1f\xf8\x9bi\xb2\x99&\xf9\xc9\x82l\x887\x99'\x9bEv\x10\xcd6\x8b\x8cx\xd1\xcc?`\xf3\x88\xb3<%\x9b8_n\xceHL7\x17\xde\x84\xac\xe8\x86L6+\x0fS4o\x92\x94\xfa\x1bJ\xbcx\x9amPs\xb2Ic\xdf\xf7Y\xd7\x8b\x05\x9d\xa7I~:\xdf\x84\x8b\x8cl\xb0l\xf9b\xcd\x86r\xc1\xa6\x93\x84\xeck\x8f\x84\x939\x9b}D\x18\xd8\x92\xe5&\x8f'\x1e\xdb\xbdl\x80\xa7\x8b\xe4$\\lN\x13\x9alN\xf30\x9dn\"o\xb6Y\xae<\x8e\x03\xd9F\x19D\xecEt3Y\xe4S\xe2\x1d'\xf1\x84\xf8\x07\x9bE\xc4\xa0\x95\xd3\x8d\x14}6\xd4#\xe9,\x9c\x90\x0dI\xe3p\xe1\x1f\xf8\x07\x9b\xcc\xdf,\xbcpy2\x0d7\x84n\x92\xc9\xe7M\x12\x9f\xfa\x9b\xa5\x17M\xd2\x04I\xe0\x06\xf5L\x1b\xaeK\xf07o\xc27\x9b\xd8\x0b\x97$[\xb1\x96B\x1a\x9d\x91\x0d\xb9\xa0\x1br\xbe\x89\x16\x9b\x84n\xf2\xc5\xc2\xdf$\x1e\xb2E\x9b\x15\x8f\xaf\xdc\xa4\x9b\x9cn\xceH\x9aFS\xe2oV^8\xf9\x1c\x9e\x92M\x98\x86\xcbl\x93Fgl]\xd2\x84\x92 %\x0c\x104\x99$\x8bM~\xb2\x88&\xfe&\xf5\xc2\x88a\x8c\x17N\x93x\xb1f\x0b7\xdb\x9cF\x19%\xe9fEB\xba\xf9\x92Gi9\xefl\x92\x93\x0d\xd7\xb3mh\xba\xde0\xaa\xe8\xfb\x9b\xcc;Y\xb3\xc5\x0f\x17d\xba!\x8b\xd9f\x9e\xa4t\x13\x9d\xc6d\xba\x89\xbe\"xB\x1aM6\xa8\xd3\xd9\xa0\xa9a\x93\x9fp\x97\x84M\xbe\"\xe9f\x1dO\xe6i\x12G_\xc9t\x83\xb1\xc4>\x83\xe8r\xb5`\x83\x9f\x93x3\x8f\xb2\xcd\xf7|L\xd1\xce\x06\x87\x11^\xf3z\x8a\xf6\xcc)E\xfb\x14\xab\xfc\xa2AB\xefGR\xbc\xdc\xf4\x86\x99\x06Pw\x06\xae_X\x8b\x8c1\xa6\xd6\xb7N\xf1\xadA\xcb[K\xc6\xd3z\xa7\x01\xc4\"\x83\xc9\x00K\xede\x84za\x00k[\x81\xe2&*H\xa1c\xc9\x84\x8e\\: .1\x19\n\x0fq[\xea\xb9A\x0d\xb1hMU\xdb(\x9a([0\x11\xa7\xc2\x9b\x8d{\x87\x95\x84\xbe$U\xa3\x81\x86\xb8H%\\\xa3\x08J\x80\xf6\xb5l\x12.\x9e\x86\x19\x1b\xd6\x93\xea\x9d\xe7b\x90\xad\xa0\x91\xeaG\x8f\xf6Sn\xe8\xf7n}\xea\x8f\xfe\xd5\xbf5\xfe\xee\xc6-&J4K\x7f\x92~\x16\xc6\x11\x8d\xbe\x92\x8f\xe9\xa2\xb5\x87H\xad_\xabz\xdb0a\xadW\x8b7\xd2\xc9\xd6\x8abp\xa6\xf6\xeck\x8f\xe0SB\x9fL\x18\x97\xcf\xb0%M\x16\x8b(>}G\xb2U\x12g\xed\xd0\xa8\x9dd\xa5\xc2\xbf\x1fe\x8a\xf6_Q\x87\xb0\xa51i\x0c\xaa\xc7\x9e\xfe\xcdR\xbf4\x8b\xe2\xa9\xd7\xaa\xac\x91Wq\xc2e4Li\xf6kD\xe7^o\xafW\xe8#U\x15*\x83\x89\xd7\x9b\xf0\xdd\xc3\xad\xf6\xff\xbe\xf4K,lz\xfe\x01\x98+X\x15\xaa\x1d\xaf'\xba\xe8\x89\xc4\x9b\x1a;\x89\xa1\x8d\x14\x9d\xe64\xe3\xd27\xe2\x17\xca7a\xea*\xb3\xa4\xc5\"O\xa2Y+\xc7\x9aM\x9bx2%d\xb5X\xbf\xa7i\xb4zI\xd65~\xcd\x927\xecZX\xaab\x99[\x94\x81:\xa7L=\xb6ut\xbb\xafZ51\x99N]K\xb7\xd9\xa8\xe4\x8f\xf1q\xb1\xcd\xd4&5\xef5e\xf8\xbf\x19\xb05d\xb1\x86\xa3\x91\xc6\xe4dVh\xe3\x98b\xee\xa1\x17a=D\xd4*\x8a\xc8mv\x87 5<\xa1\x0c\x15o\xe8\xd3V_\x9aU\x90\x91\x86\xec!\x15s\xb1\xa3F\x86\xa2\xdd\xa6\x94\xe2\x80^)\x0c\xb9A-\xeb\xcdp\xddp\xa6\x18\xad\x16\xb4m\xc1)\xb7Z\x94\xd5\x8dMn\xf5P%\xbeU7_n\xdf\xd3T\x94+\x98\x9d6\x83d\x91o\xb1\xd9\x84iM\x18L\xc4g\x1a\xd2\x1f\xa3\x03\xc6\x87\xa4p\xeapX#\xfe\x8da\x8d\x94\xde\x8chR3\xfdU\xdfc\x9bb\"\xfd \xee5\xfc\xfa\xa1\xc8\xbaq\xfbN=<\x05D\xee\x0d\xf4\xb0\xb83\xd0}\xba\x92-\x7f\xbf\xab{\xaa\x0f\x89\xaf\x16_e\x0f\xcf*\x07\x89\n-\xa3\x05\x19\xb3\x16\xf4\xa3\x18\xf5\xe3\x99\x17\x97\x0c\xb8N\xb7\x02\xaa'\x809:\xd7m\xa3\xc1\x01(\"A\x84A\x13\x11\x16Z5\xf2\\.hm\x8d\x95t\xf1<\xc0C\x9c\xe2\xa7Q\x93\x18p\xfe\xad\x9f%K\xd5s\xa2\x8d\xddd\xbd\xac\x95a\x8eb\xc6[\x8db\x8d\xdd\xeb\xb2\xbe%\x9a'\xdf[\x83\xdfc\xeb\xfe\x80\"\x10\xf01\x94\x02T\xef\x97p\x91\x13\x1e\xe8uB`A\xb2\x0c\xe8<\x8cA\xb4\xdck\x8e\xb1\xb9;\xfe0\xf8gv\x18\xd3#\xf3\x98NQ\xe5\x9e\x8aa\xf1\xc6\x9d\x86\xf5Y\xefI\xda~Z\xa0\xa4y\xeb_;\x07\x9f\xa6\xdb\xde\xa7>\xfb\xc7?\x90\xb6\x01EN\xad\x0d4\x04\xc1\xf8\xb8\x0c\xee\xc8\xe0\xfa\xdamt\x0e\x83\x8a!\xe2\x8d;\x0d\xeb\xb5\xceE\xd7mLx*\xd5\xf2+\xd4\xbc\n\xcd\x90\x9bE\x0b\xe24\xc0\x0f\x06\xbfb\xb71\xf6h\x9a\x13N\x1aD\xccR\xb8\xc8\xd4\x1b[\xbb\xca\xdf\x03\xc9\xca\x9bF}\xc2\xbbw\x1a\xf8S\xbd\x8f\xb4\xdb\xb8\xf9`5\n\x1f\xf3\xd8\xc4\xcb.C\xfb\xd9\xe4\xd3\xed68^\xb1\x9f}V\xb8\x0b[VZ6\xef4\xb2w:\xf7s\xb7QIqO\n\x1b}\x9a\xbcJ\xceI\xfa4\xcc\x88\xe7\x07\xb0u\xeb_\xa3\x7f{\xe3\x83\xd1\xee\xce\x83pg6\xfe\xf7\xfd\xcb\x9d\xe2\xef;\x0e\x7f\x0f\xf6.G\xfe\xe5\xd8\x890\xb0\x91;M\xf8\x8d\xd1\x0b\xdf\x9d\x98\x96\xbc\x89\x1b\x9d\xe7]8\x0d\xef\x951t\xa0\xfb\xf0:\x90\xfc\x0e#|f\x08xp\x1e\xdf\x16O\xebpzx\x81\x1e\xc9\xb6\xa5\x9d%\x8bEr\x0e+\xd1I\x0f\xb6u.\xec\xd53\xbc\x19\x9e\xd1:\xb2\xabr\xb67oV~\x9b\xb9Z\x13\xc7\x8b\xac\x1eR\x9e\x93d\xba\x16je\xae`\x8c\xe2\x1ew\x93\xc7_h\xc8:\xbeX.z\xc7\xd0\xf9LyS\xb0\x1e\x867\x17\xe5\x9b<\xc9\x85\xfe\xb5U\xf9\xda,I\x97!5\xbd8\xaf\x8cQ\xec\x00\xc3\xbb\xd3\xca(\xed\xef\x9e\x95\xef\n\xc4\xad\xa7\x1e\x01\x01G\xeet\x950\xa67\xb2f\xe6\\3\x91\xbdT\xcc\x0d\x01\xbf\x8c\xf4\xfd\x83Pe\xf4B\x99\xe0[\xbc_\x15\x9ay\x82\x97H\x16\xd306u\xackJot\x94MN\x92<\xa6&-:\xbbN0\x9c\x8fq$\xcal\xccl\x8d\xb9!\xd4eH&\xa1l\xcb\x8bx\xa6\".\x96X\x06r\xc1\xbe/\xb5i\x95\xcfw[\xbf\xc6\x94\xf1\x92\xf9\xeb\xfe\xf9\xa1\xc1\xc8\x0e\xd2\x00\xd7\xd0B,\xcc\x9e|V\xed\xaa\x9bdvhp\x08\x90\x17O\xef\xad\xd7\x11G6u\xac\xbc\x94\x80\xa7\xc8\x0fD\x7f\xc6/\xda\xed\xcf\xf2\x92\xb4\x88\x1b\xb8{H\xf7 ;\xde\xf88y\\bq\xf6\xe1\xf1\x80c\xe9\xf9\x81\xa1\xfc8h\xf5\xb9 \xb6\xe3\x13F\xd2\xd7\x01\x9c\x16\xb5#0\xb5\xfd\xfb\x00\x0e\xc75\xe1\xd5:\xf6R\xdf\xa4}E\xa7\xe6\x07\xb1\xd4 \xf2\xcfe\xf9 9\xf7w\x82\xd6\xc3,\"\x8b)D\x19\xe6\x0fY\xa5\xc9Y4\xc5\x13@G\xb1e\xa3g\xb6\xc1\xb2\x89\x7f\x85!<\xf3\xa2\x00\xce,N _\xd1\xc4\xc1\xc7\xf3\xd5\xd5\xd9\x00\xc4\x10\xe6\xe5\xd6\x99\xb7\x8d\xe69\x0c\xe1\x0d\x1b\xcd\xdc2\x9a\xe7\xcah\x9ew\x1d\xcd\xb4m\x08\x1fa\x08\xaf\xd8\x10\xea\xa5E\xd4\xeb\xa32\x84\x8f]\x87\x10\x96\x00 \xdbF\xf3\x03\x0c\xe1-\x1bMh\x19\xcd\x0f\xcah~\xe8:\x9aY9\x9aY\xdbh\xbe\xc0\x10\xfe`\xa3\x99YF\xf3E\x19\xcd\x97\xae\xa3\xa9\x1e\x89m\xe3\xf9\xdd\xe2\xb7$/\xe4n\xbc\xdfQC\x1eR\xb2C\x99\x1c\x85\xcd\xaf\xe0\x00~\xf6P\x85\xd6\xcb\x99\xb0Q\xdc}\xc7\xef>\xe5D\xd4\xcc\x17\xc9K\xcc\xf6w\x93\x1bKIf\xab\x07[\xdb\xfc~\x85!|\xf0\"\x0b\xb0qv\xbfv\x18\xe3\xaf\xedc\xac\x1c\x9emC\xfc\x05\x86\xf0\xb9}\x88\xbft\x18\xe2/\xedC\xac\x9e\xd0mc| C8j\x1f\xe3\xcb\x0ec|\xd9>F\x95\xc1j\x1b\xe1\x8b\x96\xa1\x1d#\xf3S\xb0a.\x03}!y\xd6\xa3\xd8\x1b\xf5\"J\x96Y/\x00\xceg\x8f\xfd\x00\xa2\xa6\xa1\xbb\xcd\xd7\x03\x14\xc1\xaam\xdb\xb1\xab\x82I/\xd0I\x82!\x0b\x06\xabV\x97P><\x12\x0fU*\xf0\x02\x190\xf6\xf4)\x13*\x03ap\xe7\xeb`\x1f,\xbb\xa2xJ.\xf6\xa1\xc5g\x90]$M\x93t_\x13/\xa7^\x97\x96x\xb0v\x9cP\x18\xe46\x94\xb8\x01Cx\xdd\x8e\xb47\\pA\x00\xeb\x86+56\xda\xbd5\xfe+\xcdl\nvNI:\x1a}\xbb\xbb\xb1\xc6\xd2 \xc2/\xa8\xab\xd8\xdf0h\xe9\"\xa0\x19\xbco],\x17BwE\x8c\xf2]\xc4\xbd\xae.\x96\x0b\xdc\xb6\xf8\x17\x166\xb2\xad9\xd7\xf3\xb0o\x98\x94/\xbe\xfd\xf7e\xc0\xbe\xbfq#%3\xd5\x1d`\xbdBO\x18\xda\xc7}\xcd\xff\x14%WD\xb9'\xda\x0f\xa7S\xf4M\x0c\x17?\x97O\x0e\xe0o\x8f\x0eX\xe3g$\xcd\xa2$\x1e\xf6\x06\xfd\xdd\x1e\x90x\x92L\xa3\xf8t\xd8\xfb\xf8\xe1\xf9\xce\xfd\xde\xc1\xe3O\xb1pl\x87\xdf^\xbf\x02r\x81K\x0c\x13\x9e\xe2\xf7\x84\xc0)\x89I\x1aR2\x05\x1e\xa4\xf47\xa3\xff\x93\xbc\xa4!LL\xa7\x8f\xa9\xb1\xbd[\x9f\xde\x7f\xf7\xe9\x96\xf7\xe9\xfd\xb6\x7f\xe3\x96\x05\xd9K \xc2\x10\xa2\xd1\xa0\x19\x8c\x08F\xc6B1\x16\x9eJK\xed\xf4)\xea\xcb~{\xfd\xea\x90\xcf\x8d;\x93\xb8\xf8\x80\xb0\x89$\xc2\xc3\xa8l\x8fo\x82\xe7i\xb2\xe4\x1bA\xb4\xd7\x9c\x91T\x8a\x99$\xbb\xa4M\xb2K\xb0\xbcm\xcd\x13&)=a`_\xc9y\x06Pxi\xaaYP\xac\x8e_g\xa2\x0eI=\xa9\x92\xbc\xd8\x12\x94\xe2\xfc\"\x99\x84\xac\xa9~\x86\x8d\x1b\xf4K\xa5\xde\xd2\xb4\xb5z\xa8\xa47\xee\x11y\xf0\x90~\x96\x9fd4\xf5\x06\xbe\xac\x17tS\xa7\x8d\x01\xd5C=\x85(\x86\xd8\x87\xb8^>%\xe5\x8e\x8a\x18g8J\xc7\xb2\xc5!&[\x1bM\xc9$\x99\x92\x8f\xef\x8e\x8a,]^:\xda\x1d\xfbc,\xdd;@u\xa1\xf6\x9d\xc1\x98\xdbU{.\xf8$\xb7us\xcd\x9a\xd9l\xec\xb4\xd5h\x15_\x86+\x07\x7f6\xf19\x12\x83\xea\x8c\x88\x0f\xdb\xd0\x1b\xa2\xb6\xb6\xf9\xb4\x9a\x99T^\x97~\xff\x8f$\x8aqy\x9aS\x13\x19{\xec\x83\x92\xf3\xa9d\xdd\xa0\"n\x17K\xd5yD1W\x04\xd0\xcb\xe9l\xe7~\xcf\xf7\xcb\xbb\xbd\x930#\xf7\xee\xe8\xc6Pf\x10jv\x9d`\xb8Y\x94\xc4\xd9{|\xcb\xe4\xb5\x13.V\xf3\xb0%\x97\xacz\x154\\j\x13\xe7=\x1f\xb7\xd0\x02S\xc1\x85)\xf1\x88\xfa\xccpd\xeb7\xe6\x92\xd0y2\xbd\xf2h\xf8\xe7\xa6\xf1\xc8\xa7\xceLDs\x8c4<\xfd\xb3\xc0Y\x1b\xb2\xf3 5\x98Y\xcb4\xe5\xc6\xce\xe8\x9cT\x94\x8c\xeeQ\x0cF\xbd\x91\xf4\xe6\xa5F\x0f\x11\x85m\xe1\xa5oz\xe5\xdf\xa2\xcc\xd1(\x0e\xd8\x06\x0dt\xfb3\xf5K\x9f\xfa\xff\xd9\xdb\xbdu\x1a@o\xbb\xe7\x8f\xc5\xfe\xd4-\xa9\x91J\x11\xdb\xa6\xd6d\xee\xaa\xac\xa4\xc1\xb1\xa6P\x9a1\xc25- W\xac8\xe5\xb4\xb9\x8ct\xf2\x18\xa9\x8e\xbc\ns\xa9\x143\xa4's\"\xc0:\x8f[d\xcaT:&\xcc\xd9\x98\xd4(\x8d\x96\x9e\xb2H\x9f2\\\xa3c\xb4\xd8\xf4z\xb6\xe1\x1a\x92\xab9\x0d\x93\xc1\xec\xb8\x84\xd9\xd7\xa6{Y\xa0I\xe7\xe6\xd44m\xe6\x9b\xb0\xecd\xf1\xd1\xad\x7f]\xec\x14\xccu\xeb\xb2\x05\xc6\x14t\x7f\xe6\x08\x85\xfdgS\xd8\x976\x85\xf5h#\xecb\x1ba\xf5r\x9f\xca\xff)\x1f\xf0\x94\xdfl\xa7x\xf7\xee\xfb\xfd\x1f\xf2\xd9\x8c\x08\x7fq[\xf5\xa3\xb3\"sSq\xf2\x95x\xa2\xa6\x19\xacX\x8c\xc0%S|o\xc49U\xfe\xe9\x18\x91:nT\x8cr\xca\x06\x89\x94\xae\x1cWjcD\xf59\x0eAaO\xf9T\x94d\xbc\x8bhBL^\x97\xc4\xb8\xbc<\xa4\xaa\x9aL[\xe4K\xe4\x14@-1\xe1c)+S.\xd9zZr\xfdP\xecx\x99\x97\xbe\xaf/\x9b%\xb9\xf4-\xa6\xd6\x16\xc3\xb2\xc5\x17\xae-F\xd6\x16\xb3\xb2\xc5\x1b\xae-&\xed\xb3\xbey\x13\xb6&e\xd3?\xba6\xadI-\xaf4\xbd\xe5mQ.\x87\x8f\x16c\xb7\x06C\xd7\x06\xeb\x898L\x0df\xae\x0d\xce\x1d\x1b\x9c\xb4\xaf\xf8f\x83\xdd:57s\x1d\xdf\xb41>\xf5\x17\xf1R^\x83\x85x\x91\xfc#\xe1\x7f\xc4\x8a3+\xcf\xd5\xcd\xee\xbc$kL\xcf\x17\x8a\x17\xe2)\xb9\xc0\x1b\x19\xbf\xf1$\xcb\x92I\x84\x99!\x00s\xb8\xc4e\x00\x1c`x~\xdc\x97m\xb0\xae\xfbe\x0bl\x00\xfd\xf7\x04k84\xe9\x07\xa6\x19\xf8\xfb\xdf\x8f\x8f\x8f^\xbf\xfe\xf8\xe1\xc9\x0f\xaf\x0e\x8f\x8f>\x1c\xbe\xc3?\x8e\xff\xfew\x8dji\xd5\xfc\xe2\xe5\xe1\xef\x87\xcf\x0c\xaf\xcf5\x1d\xbcyv\xf8\x9b\xf1\x83i\xf3\x83\xb7\xef\x9e\x1d\xbe3~p\x06C\xb8\xdb\xbc\xbd\x86!\x0c\xe0\xd1#]\xb5\xf3S\x18\xc2\x1av@\x93\xaa\x7fi\x90\xf7\x8f\xed5\xae\xf7\xeb\x89$A\xcf\xf9\x9f\\\xa5\x19\x13-?o9\xd8\xb9q\x18\x0b\xbb;\x92\xe4\x0b}\x8bT\x1c\x0dE\x83\xbbn\xdb\xe9=O*\xaf\x7fxh9\x89D\x84\x9bF\xaf^\xa9\x0e%\x0bH{\x98x\\\xa88w\xb0JH*r\x9e\xcb\x94\x05<\xd3\xc6\xeeCLw\x11?\x84h{\xdb\x87t\x14\xf1$\x89\x11\x13\xe8\xcd\xee\xf5\xa9\xd3l\xed\x01\x0d\xaa;:\x06\xa2\n\x98f<\\\x82\xf6\x8f\x8fy\xe9|\xe2\xfd\xc1OW\xf6\xc4\xa9\xe3\xb7\xd6Tb\x85\xf5A)\xe9a\x13\xc1P\xb9\x04\x8f\x1f?6\x995\x84\x92j\x1bb\x11C\xbd\xd9\xc0\x9d\xbd\x07w\x1e\xdc\xfb~\xef\xc1]\x9ca\x19\x99\xf8&|\xa3o\x85MZ\x93\x92\xcf\x04>\"\xcax#\x90\xb7Q\xf1\xe1\x06\x9c?l\xc5\xf2\xeb\xf9\x9c\x0dm|v\x90\xda<\x19jP\x16\x9d\xde\x92Q\x91\x14\x1e\x0da'\xae\x14,\x1cJ\xd0\xd5_&\xf0xXW\xc0\x9a\x06v\xd4\x96\xbd\xf1\x83\x18\xb9\xe3\x86}\xed\xda^\xbd\xaa\x8f\xa1\xbd\x0f\x0e\x80\xab\xc5i\xc4\x986\x97/\xb6\xba\xbf l\x03\x1a\xc5j\xb1\xb4\x8cC\x92\xe5\xe2\x99\xbc`\xac\xde\n\x02\xbf\x9f6\xabT\x83pd\xd6\x9c\x07\xef`\x08{\xcd\xdbo\x9c\xb3\xb6\xf3M\x9d\xa4\xcd6^\xf1\x93N\xbe\xa09\xda\x9e\xc1\x10\xde0\x1cye:\x02\xbe\x1a\x08\xf6<\xca0\xbb\x8833\xfe\\\xae\x94!\x99\xa7\xb4Z\x94\x0b\xc5\xb6\xe0\xa0\xb2l#\xf6\xbd\x85\x8a\xc2\x01\xa4\xc5\x19\x12\x89\xb2\xc0\xd6\xd3\xd0\xe0\x078Mb\xd3\x89\xebH\xab?\xda\xa8\x82uH\x1c\xfd\xac\xe3j\xad\xdcc\x18\xd4\x0fv\xees\xebWW6\xf6\x8b\x9d1\x00S\xd5h\x8a8\xe3\xd4\xc5\xefv5\xe0\xaf\xda\xf4\x1d\x05-\xe7Un\xb5\xc5\x96\xf5\xdd\xfdj\xef\x8e3(o\x90\xd6\x8e\xde`\xedR:ze\xcaM\xa4\x9d\xbb\x92\xb7\xdaiD\xbf8\xc0X\x13\xcc,\xb8\x14\xa7.^Z\xbb(\x92\x01\xa8G\x8e\xdc\x8e \xcf\x95-\x85\xe8>M0]\x83\xb5\x80\xb5\xbc$P\xd1y\xbd\x12\x167\xac\xd5\xe6!\xe7@\xa85\xc3\xfb\x96\xa9^\xd8\xe1\xc5\n3\xd3q\x06\x0d\x92\x14\")\x15 5K2\xe3[.\x0b\xd8\xd3\xcf(\xdd\xf0G\xfb\xe8.o\xeaV\xbb\x8a\xecj\xa6\x083\xc0\xfd\xc5\xb7\xc1\xbdO\x13\x94\xc5$\xc4\xc5\"\x84\xcd\xb5\xa0\x98\x9f\xfd0\xa6\xe9\xbax\x99\xba\x8e\xf2\xc6\xb7\x8dR30\xa2\x0e\x84\x8dSH\x91\xf2V\xe8<\xb6\x1f\xadc\xf3\xbe}pr4h\xe0\"\x14\xef\xd7F\xa6\xfe\xfa\xaa\xa8\xaa\xa8&\x1f\x81e\xb0\xbd\xd1\x918\xa0\xc75\x05t\x00_\xfb/\x0f\x7f\x7f\x0fCx\xca\xfe\xfe\xe5\xc9\xab\x8f\x87\xec\xd7\xcf\xec\xd7\xe1\x9b\x0f\xef\x8e\xf0\xe7\xbb\xa0\xd2\x7f\x14g+\x9e\xed\xbc6\xaa$O\xab\x99\xb9m\xf4\x85\x1d\xf0\xe6\xdc\x0bJ\xcb\xa3g\xe3\x0em\xd6\x1b\"\xdeK\xae\xb7x\xd9Of\x8e\xed\xbc\xf4\n'\x92\xc6\xc0^V\xa7L\xbe8\xb6\xa9\x1b\xdb\xcb\xab/*\x82\xef\xf8\xb84\x8e\xb2\x91\xfc\xbb\x17@\xef\xb2i\xcfQ\xfb\x99\x84\x939yG\xb2\x962\xc7JW[\xbc/\xfc\x10d\xc5\xafB\xd6\xfb\x18\xe3\x83)\x17\x06\x957\x87\xfc\xc5\x12\xeb\xcb\x8a\x0f\xa2\xfc\x99\x14\x1c\xcb\x8f\xc4\xd9\"^\xb0M\xa3\xe8\xdf%\x86HLdB\xcb\x82d\xbc\x02\xa8K\x0f\x89S\x00\xbe\xe8b\xd6\xda\x05\xf1^\x04\xf0\xd2\x0f\xe0Ee\xf1%\xbdu\\\x13=\xa6\xdf\xe0-\xdfp\xc7\xf4\x1b\x16L\xbfQ\x19`II\x1d\x9b\xd6\x0d\xf1\xc65#\xfc\x88!\xfc\xb8\x89\xf07\xae\x19S\xea\xb5\xdd\xf5=|\x13\xa64\xbb \xde\x8f|=\x7ft_\xcf\x1f-\xeb\xf9c\x8dr\xd1o[\xcb\x97\xfd(\xe3-D\x94\xfd\x92\xda[\x86\xdeB]\xcb\xc6\xaf(ro4\xb5\xb7?\x05\xf0\xcf\x00~\x0b\xe0\x1fM\xa5\xe9\xfb\xc3\x7f\xa0\xc2\xd4$9Rj\x11\x1d\x8fCQ+\x83\xd6\x88M\x17\xf6\x95\x18z\x90\xfc\xa50.}&\xebL\xcbC\xf2\x91$\xb26\x88\x1c\xca\xf1gQ\x0b\xab:4\xd2eh\xb1u\xf2Q\xa9\x9f7\xcc\x9f{\x16:+\xe8\xd2\xf6\xee\x84\xe1,\xa8\xdd{*\x0e\x83zm\x1fCG\x91\xa1#y\x16\x95\x06\x8c\x7f8\x1aX\x90\x1b36\xf8\x13k\xcd\xfbI\xe8Z)\xf5F\xe3Ff\x16}\xbby\x0brh\xd2\xe0\x88.\xa8\xdf\xe4\x9a\xbf\x94o\xa4\xfa7~(\xdf\x88\xf5oh\xa5\x9c\x83R\xc8)TOf\xcf\xbe\xabK:\xa3\xcf\x01\x9c\x8dAd\x8a\xed \xf1t\x92Y\xc3\x16\xa0gza\xee\xdb\xa7\xc7\x05\xb9k\x9aEfG\xf2_j\xd8\xa2A\x0f\x0d>\x14\xab\xeb4\x04v\xc29\xa9\xcb\xa8`\xcd\xf4@\x8dL\"xa\xe5H\xd8\x01QZ6\x06\x01\x864\xef>\x84\x1c\x1e\x0d!y\x08\xf9\xf6\xb6\xa9\x11\x10\xe3\x08\xd1S8f\xa2\x15\xec@\xced+\x83\x7f\x15\xc8\xc5\xe6z=\xe2\x85\xa3\xc18@\xc5]8\xda\x1d\xb3/\x03P\x02\xdas\xd8\x86\xa6\x12\x0e\x1a\xe2\x97\xbc\xe4g\x8d\x87\x96\x04s\x0dV\x99g\x83tZ\xa6\xd9\x9f\xbcL\xda\x152B\x96\xaf\x9c\x0d0\x0c\x1b\xbfzV\x96B^\xd2\xf9\xc3}a%\xf0\xb7\xb7\xe11:W\x9b\x1b\x077u\xa7\xbc\x8cjOy]\xc2>\xc7\xcc\xb9P\x1f\xa9i8s\xfbp\xa4E\xbe\xe2w5\x94r}\x8e\xf4z\xa8\xe9\x93j\xbe,\x03\xb8\x05\xbb\x85?\x8b\xf0{\xf1\x03\x89\xce\xf2C\xdb\xc1\xf6\xcfbh\xff\xd4#\xce?\x85\xcd\xa0e\xab\x99\xa0u\xda\x02-\xaa\xaa \xb8\x8a\xc0\xd1WhIm\xceB\xfa\xa5X\xd6\x96BiC\xbf\x1a\xa7\xd4\x13\xaeV\x01\xf4\x9e\xf2(\xde\x8c\x92\x15\x84\xf0.\x8cO \x9c\xaca\x17\x83\x1eAX'w\x83\xea*\xc9\xba#\xb8V~\xa0$\x01\xe0\x9eo\xa2\x1a#.ax\x92\xa1\xeb!\x81G\x82cco\xef\xc4\xd2\x84s\x8c\xc5\"T\xbd\x1f\x89\xa7\x8aj\xf3\x18\x87\x86\x83U\xb1FE\x0f\xfc{B\xa2\x85\xe7\x11\xd8a\x04\xf8\x16\xc4L\xb4\xf2\x99l\xde\x0dw~+`\xf9\x9b\x1ew~\xfb6\xdc9\xd6\xeb\x129\xbe(*\xa5'\xa2\xfaa\xdd2ah\xf6\x84\xda\xdcL\xcf\xadO/\xc4S\xf5\xa1b\xc6\x1a\xfdc,\n\x01\x11\x8f\xd2\x00n\xb0\x95S\xe3\x1eN\x89SIW\xc9\xb5\xb3U`\xe4\x91\xdb\xb4KM\xfb\xe8\xad4g\xf8c]\x05\xf3J\x9f\x9dL2\x15\x7fY\xa5G\xe1![Q-\x95\x1e\xb2CH\xb9\x8b\xac\x11W\x84\x8a\x88z\xf1\x88Q\xae\x14v\xd0\xa3+\x1a\xa3\xf0\xc7:*wf\xc4P\xd1H\xb5\x1bu\x1d\xb4\x93u\xb3\x0e\xe9&\xaa\x9dBc\xf2\xfa\x89\xea56\xdd\xb45\x05\x10\x1e\xa3\xfa\xc3\xc6\x819i\\\xac\xda\x16\xaei\xa1\\\x02/Wf{\x9b\xad\xcd\xf6\xb6C\x14 CuB\x03x\xc1\xe8\xd6\xd5Q\xbd\xee\xe5\xaaC}\xae\x1f\x1eQ-\xcaW\xfa\x9e\x87\xee\xf1lJ\xd3\xf5(wM}\xa2\xeb\xdcX\xbcS\xbe\xb3JSU \xd8ju\xa7%|\xa7%l\xa7E\x0f!1+q\xcfDY\xbc\x14\x173\x82\x1dH`\x1f\x12\x83\x9e\xaf\xb63\xf31V!\xae\xee\xc6D\xab\xb45\n\xa3\xcd\x14\n\xd7\xb5=\x05\xb8\x8c\xfbS\x01\xa1qw\xa6\xad{8\xb9\x8e=\xdcm\x15$\xe4P\xd3\x1a\xfdu{>g{>w\xdb\xe3\xca\"\x8e\xa6\xe5!\x17\x8bC.\xd6\xee\x8b\xc2[\xc5a\xad\x19*\x96\x121\xaeeEhR\x84\x0c\x03\xf7,\xb1\xe5w\xafj\x96\xb5\xd4\xb02\xe8$\xbex\xb1A\x06-vq\xf4\x10\xb6\xbc\x08O\x05\xb5*#(\xb9\xbc\xbdHT]\x84t{[\xec*]\xfdR1\xe5F\x8e -LK}\xf5\xb5\x025I;C\xd5\xa0\xce\xf9\xa2j\x89\xf9v\xf9hh\xd6\xb0\x02\xdd\xb7\x1aQ\xd6\xa1E\xcb\x81\x8b\xc4\x9d\xd1q\x0f\xe0\xd2\x08\x15\x9e\xd3F\xf0R\x81\xf2\xe9\x7f\x01\xcaW\xea\xc8\x17$\xb0\x08!\xe0\xb6\xaa\xa6\x83\x80z\xa0\x14\xc6\xa8\x87\x0e\xcc[4J\xc6\x01#T\x8dC\xc206\xb6KbEK\xc4w\x89\xb1\xf2\xbc\xa4\x9b\xb1M\x9b\x84&\xb6Q2\xe6\xe1\x90\xc5\xd8\xf2\xea\xc0NR\x12~n.\xa8 \xdb\x1a\xc7\x96vy\xffc\xbb\xaf\xb6\xb0F\x82\xa6[l=\x10\xafc\xef\xe1J\xc0\xe3\xf2XmS\x18\xb6oT\x90p\xe3En\x8b\x8dkQ,\xf2\xa0<\xb1\x87\xb5\xafY\xad\xcb\x92\xfdMG\xee\x0c\xefZ\xd0\x805\xbd\xba\x8b]M\xd0\x86\x03\xe8\xbd#+\x12R\x18\x8d{\xb0_\xfe\xe2^\x10\x8aZh\x1bz\xe5=\xfc\x96\xdd\xa1\xd1\x92d\xd0t:^_\x9d)\xd71\xe1|\x08\x1a\x06\xbc\xd2\x8f\xac\xf4\xe3\xca\x85O\xa9\xaa\xf8jFe\xd5\x9a\xc7\x94\x05.\x13\xa9\xec\x1f\x06*#\xca+1{|\xaa\"U\xd2\xba6\xb2\xd7\xa2\xba\xe4\x0e\x0f\xa6\xab3\n\xf5\x91\xa6\xe4\x8c\xa4Y\x177\xed\x16\xb8N\xc9\xc5\xdb\xd9\xd5\xc1\n\x07\xa81\xdc\x19X\xbbY\x84\x19=\xba\x86\xaeJ\x0cm\xed\xf2\xea\xc2\xd4\xeeC\x88\xe1\x91\xb2\xc4\x10;i\"*\xc3\x8d\xeb'ZlUB\xc4Ns\xe9.\xe5tbU\xbb\x11k\xc9f\xc2#\x88%\xc5)Y\xa0X@\xc27\xd6\xd9\x83\xeb\x12?\x1c(l\x05\x9a\xc2H\xe9\x88\x87\xb4\xaaz\x87\x83&f*S=k\xda\xfb\x19}_\n\xfa\xbe\xbcf\xfa\x8e*cI\xde\xf9\x0f\x85\xbas\xed\xee6\xf4\xfa\xfd~y\x97\xc4S\xd8\x06O\x08\x15\xf3B\xcd{\x00=8YW>'+\xcc{\x84I\xe74'\xc1\xf2zO\x029\xdcR\x17 \xdfU\x87\xd28#\x96W:#$\xe7\xe0Q\xd8Q\xfb\xf6\xe1\x96\xd2\x9fq\x7f`\x80\xf4.7\xc8+d\x82\xdf`k\x84:\xf1\xd9\"\xd1\xd8\x1ejCv>wj\x87J\xd1\xa9r\xb8\xa0K\x01\x9e!\xe5\xd3\x80\xdb\n\xf0\x8c)\xef\xfa\xf0hX\xf8\x96.\xa9\xb7\x1b\xc0\xae/\x8e\xa7\xa5@\xeeSB=\xd5* M\x06\xec>\xd1\xdcG\x905\xcf\xae\xe5U\x0e\x9b\xb3\"\xaa\xb2\xb2B\x0d\x85/\x18\x031.\xc3\x1c\xd4r\x07V\x87\x03\xe1Z\x89N\x96\xece\xeeSa\x19((x\xba\x0b\x1b\x93s\x14\x1e\xa1qY\x8d\xd3\x8b\xe1_C5G\xd1w@\xfd\x87\x0c1\x94\x9b\x0f}\xc0\xd7(\xdcR\xdf\xb5\x12\xdcC\xea9\xa5J\x8f\xea%]\x145b\x99\x9a\xffg\xaax\x99\xeb1\x0d\x94UxEG\xd4\x9e(\xb7\xea\xb1\xf2\x96ao\x00o8\xac\xdf\x89\x9c\x19\x14\xd3\xe1\xc0+\x9e\xe8\x1c\x9f3*\x8e\x8d\xb3\x83\xef*Y\x16`\x9fw\xd6 \xc7\xe7a6\x7f\x9aLU\xc8\xc8[:\xe5bT\xaf\nV~\xe8\x08B3\xe3\xf9\x9a\xd6\\M\x11~G\xdccM\xadPji\xa3\xfe5\x1d=\xa5c\xa7/\xb7>\x1b\xc7\x0d\xa6\xc6\xfb\xa2\xea\xc1\xfa(;\x8c\xf3\xa5\x08\xc0Bw8\xdd\x13\xa7\xb1\x98:k\x07\xaf\xfa\xb5p\x98\x8c\x93)\xf9\xb0^\x11@\xd2\x9e\x9dG\xbc\xfeYq\xbf\xad)vM\xc2\x8c\xc0`\xbf\xf5=Ph\x7f?\x8f\xa3/99zf\x9e\xa3\xbc\xb0\xf9\x07\x1d\x9b\x9f&\x13\x0c\x18>\\\x10\xf6\x0f\x9fl\xedf1\x06k\xd3z\xa56\x88-\xa5\xac\x96\xf6=\xfd\xd7l\xb9\xb6\xb7?\xd0@=\xfan\xc2\x07\xbe\xf7?\xe0\xde\xb7\x84\x88\xbc\xa6>\xc3\xfa\x8c\x18=\x1c\xc1\xc1\xd1\xb5\x8aB\x7f\xc8\xfa\xc8C\xfc\x81.\xcfu\x8f\xc1\xde\x9b$\xde!<\x95q\x19H\x98A\x98\x12,\xfa\x86\xd9\xb5\xc9\x14\xc2\x0c>\x93u\xd67\xd5=\x90\xdd\xb3\x0d%\xa2\x8dy9\x89\xd2#$\x80\xa7\xd4\x14W\"/R\xec\x9b}\xd8\xb2\x04x\xb1k\x92\xc4\xb3\xe84w|\xfb<\x8d\xa8\xdb\x9b\x82O\xd7/>\x80\xb9\xa4\x1e\xa8\xe5\x0d+N\xf5\xddH\x86`\x93\x95H\x12\x85\x83\xd7}\xe0\x1b\x1b\xb2\xab\xdb\xd4K\x95\xb5\xdd{\xee\x87\xab\xd5b-\xd8xCD\xbfz]\x06\x162\xc9\xce\xc0\x16\xc8\xb6\x13\xc1\x8aSzI\xf2\x1ax\xff1F\x08\xd1\x042B!\x84\x98\xed\x83\x12rr\x8c\x90\xc4bOXQ\x9f]T\xce\xc1<\xfb\x0e\xf4\xc4z\xeaw:\xed\xa5\xf2\xb5 k\x8caP2\xdah\xf3\x01\xd4\xa0\xc5\xcb)\xb3&y\xfddT\x93\x96\xa5y\x18\xf7@\xa6}G/\xd2\xb7\x06\xde\xbeP\xc7\x10\xce(\xa9\x16\niiG\x03\x05\xbep{\x00\xdf\xf1T\x85\xfd\xc9\x829\xf3Ld\x15\x16\xd6\x97)\xdc\xbdu\x9d\x11\xfcW6_r\x85\xa7\x92\x01\xeau\xb82\xa6<\xfb\xfa\x8d\x96\xc5\xe34IJ\xcd,\xfb\x81\xa2s\x11K\xc3\xf36\xf9:\x93b\xa5\xeb\xacS\xd7\xffP\x93B\xd9\xe7\x94\x11z\x14wh\x1a'\x92\xaf\xa6!%G\xf8\xf22h?c\xcd\xdc\x92}p)Y&g\xed\x92\xb6f\xd6K{\xc3S\xb2 l\x02\xaeM7f\xed:\xe5e\xd7)\xf3N\xea\x0bbO\x1c\xcdE\xc8F\x89\xcb\x03\xe1\n\xe2K\xe3L1\x81\x11\x1d\x8bF\x1d\xc6\xd2D\x0f\xc3h0\xd8\x15\x9d\"E,&Gq\x8b\x8flA\xa2]\x12I\x9c\x898P.\x80-\xcd:\xd1\xbc\xd5\x17\x8f\x91\xbb\\\xf8\xe1\x99\x89\xe2\x99H\x19\x93`\xf0Hk\xc5\xd8\x0c\x86\x10y\xb6\xb2\xdcb\xb92\xbe\\\xc2Y\xb7\x19C\x06F\xa9\xe3\x94z \x03\xb2\xc8\x1b\x9c\x11\x1a@/\x8ay\xb5\xfb\xcfd\xfd3V\x883Cf\x82%\x80-\x1e\xa8\xec\xa5\x99\x98\xf2\x92M\x19\xa9\xd5\x84\xed'\xf3\x07X\xa0\xd4\x9b\x95\x0bhU\x94r\xd6e&f\xcf\x7f-\xd9/\xb1\xdb\xbd \xc3W/)y\x19\xe2\xe3\xd91 `\xa1\xe1\x01\xc4\x9e\x8fc\xd4\xe9\x1a\"\x1eE\xdfi\xd1\x9b\xe0\x9a\xea\x96\xd9\xfa\x0e\x98,Hh-J\xa44\xdet\x8b\xa1\xdc\x1fB\x1c8\xc9yL\xd2\xa3gp BaE\x0c\xe3n\xa0\x9e\x14CQ\xb4S|\x83\xc1\xfb\xc3\xf2\xac\xe0w\xc3\x05\x15\xf5N\xb6\xc4M_pw\xd6\xc9,Iz\xda\xaat\x90\x90\"\x02\xae\xb2ks>\xc0f\x1f\xbfF\xd5\x92c\xb6\xf3\xa4\xe8\x08\xfd\x97\xea|\xd2\xa0\xe9\xc8\xd1\xec\xaeJ\xa0\xec\x86pM\x0fFl\xa9\xd2L\x12 \x84\x03\x07\xad\xaf\xf8\xde \xf0\xf3e8\x90\x7fI\x1d\x0d\x12\xd5}\x88Gj4^\xb3\xa8m\xcb\xf1\x81M>#\x18,\xdbi\x9d#\xd2m\x8dY\x1fN\xeb|%\xd0\x17\xc3J\x88\x87b\x85\xe3\x88\xfe7\xa2\x02\xae\xd6\x81\xfa\xebzQ\"KR\xea\xca\xe7\x1c\x11\xef\x17R\x98\xfd\xdb\xdb\xfda\xdd\x81uT\x1b'\xed\xedWd\xa0\xd6 \x14\xb2\x16[\xa90{\xcdu\x11:\x06@.)\"\x16\xe9\x9f\x87\xd9\x13NO=\x1f\x8f\xa1\xe3c\x12gyJ\xde2z\xedU\x89\xb7d\xa5\xac\x03/zw\xdc\x83\x8d\xf3\xa1zn\xa8\xa3a\xa2\xd8{;\xd8\xc2\xecHjb\xba\xf5\xaf\xf6\xd3\xb22\x05\xc8\xba\xf5 \xce-k\xdb\xdd\x1c\x9c\xa4F\x84\x9c\xc3\x0dw\x99\xa7\x93\x17\xda\xb7:1+\x87{\xe1m\x83r`3\xb3H\x0b\x11\xe1\xc1v\x1e\xc1\x043\x043\xca\xe8l\xee\x01/\xfb\xd4\x02\x01e\xb5[\xf7\x96\x9cI\xc9\xe0\xe8\xb0\x15\x0e\xe0\x9f\xb4dmT\xb6&(\xf3: K\x83\x1c^\xad!%\xf7\x83\xca\xe0\x0c\x04\x83\xa3\x99N\x941\xc9}\x08\xcf5\x9eC\x1fi\x00?\xd0f2\xe0\xd7O~6TO\xfb\xc2\xdeV\x81dR\x0f\xfenN\xfc\x81\xc3oNH$*j\x18\x1f\x8c5>\xac @\x0c\x9d\x9cDt\x89\xe0\x90\x90\x8f\x13\xee\x82\x1c;\xf5\xf9\xcbU\xfa\x9c$yL\xaf\xdc\xe5\xcb\xabt\xf9\x99\xac\x7f\xe4L1i@\xd7\xad\xdb\x17\xd7\xd7\xed\xda\xb9\xd3\x1b\xed\x9d\x1eS^j\xb4\xdc9E\x84M\\\xfa6\x87\x93\xcf\xc8\xbc\x14\x14\xe5'\xea\x89_n\xda\xd0\x1f[S<\xf2\nH\xa6}\xac\x0b\x025!\x0f\xad\xa9,$fGAA}\x10u\xa9FM\xd1\xd4Q\xf8X\xe4\x0c9\x84\x08w\x9bN_a\xc0G\x11%^\xe8\x97\xf8\x82\x06\x10Zy\x15&Qq\x89\xcd\xd3~\xba\xcf\x10Q\xac'e\xfc\xc8\x85\x17\xfa\x01\\x\x0cU\x18\xc4_\xc8\x1c\xae#\xf6\x99k:wB\xec;\xbeVy6\xf74\x9eEF\xf2\x92K\xa0En@\x8e\xac@.v=zm\x95j\x95\x9b7\x01\xb3\xb0V\xd4+<'c\x91\xd8\x97o\x7f7\xce<\xb1\xef\xeeR\x9433\x15\x002\\\x0cu\xf8Ue\x1a\x8e\xb7\x92\x8c\xba\xf2\x9c\xab\x84\xcc\x9ax<\xb9\x8a\xce\xadjx\x9e\x8d2\xf2\x85\x1e>jY9\x13@r\x97e\xe1\xdb\x1c-Cq\x7f\x16\xb1\x93\xc1\x01\xfd\x8a\x8f\xcb\xc4\xb9\xcdA\xfa\xbeb\xedb\x07\xb2\x9af\x17\xe9jy\x8am\x18\xa9\xc0\x94\x87\xca7W7\xb5\xa7\"\x1a\xaa\xf8\xc4\xb6\xe2\x80&pq\x1e\xa5U\xabi\xab\xf7pE\xfe^\x8a\x1a\xa3\x08x\xec\xd2\xf8\xad\xc6e\x02o\xabA0\xa6\xa5\x93\x17\x95n\x19\x86\xf4\xb1\x97\xd5z\xd2\x05A\xc3\xb2\xd2\xf1(\x1a\x17\x0e!\x9a\x81bf\xf2\xca\xd1\xe7\xc5\xa3]G\x89#l9iA\x84\x86x\xf7\xef\xde\x7f\xf0\xe0\xf6\x9d\xbb\x0fx,\xcf\xce\x10\x03ax\x1c\xcc\x9d\xdb\x83{w\xef~\x7f\xef\xae\xef3f\x0f\x1f\xec\xc1M(\xbeQ\xee\xdfa'\xd3\xde\xdd\xbd{w\xee\x0en\xdf\x0d\x80\xc2\xb6h\xea~\x00\x83\xbd\xefy\xf3\xf2\xde\xe0\x9e\xdb42\xe2(\x85\xa4\x02\xc5\x0fm\x15E\xa3\x11\x19\x0b\x01\xa3\xd6\xbb\xfa\xeb\x0b\xba\xba\x08\xde\xec\x0b\x15\xe6p\x18\xb2\xbf\xb9\x15.(\xffD\x9dz\xf1\xd2Q\x1c\xc0\xef-N\x11\xe6\xb9T\x0eCUz\x17\xc7\"g.\xa2\xf2X\x84G\x90\xf3\xd3\xd1HH\xa7\x88\x9e\xd1(\x193\xd4)s-\xb2\x1b\x03\xe7R\xe6\xb5Y\x19\xcd\xf0*\x1fi\x9d!\x16\x1b\xe1;6\xc0\xd3\xb9:\xdd \x9f\xee\x0c\xcfc9\xdd <\x02\x8cm\xda\x9abB\xe0l4\xc1I=\x84\xc9\xf6\xb6\x81![\xc0\x90\x7f\xa7\x17\xc8\x16p\xc0\x9b\x19\x8cq0\x11\xec3\xeeWQN\xea\xbf\xe3|\xb0\x17\xa2g\xd4\x02]\xc9.\xbc\x84IQaIH\xb3\x96\xec8\x18\xc4\x81\x0e~[!\xfb\x7f\xe1\x9a\xf0x\x08\x13]\x98\x8a\x15y\xe4\xc5\xa5Z\xe9\xb1\xf8\xdebp\xaf\xa0\x9b\xe0\xfah\x00\xe8\x88\x1a\xc0\x88u4\xf6+\x1c\x19q\xe1\xc8\xe4%\x9d\x0d\xc8\xc8\x94\x00O^\x11b\xb5 \xff\xb4\"\xa2\xe6\xa8h\xc9\x8d\xd5?@\xcbE\xc9K\"\xbb\x9e6\xb3\xae2\xabQ\x9eMa\x05\":LQ\xf0J9\xd3\xd81\x93\xf7V\x0c\xb7\x90\"em6\xff\x03\xe4\xaf'\xc2\xf6\xbf\x03\x038\x80y\x7f\x95\xf0J\x10\xf3\xd1\x84Q\xa3\xc6\x8d\x11\x1b9\xe3\xc7\xe7\x9c\xc1\xe4\xbf\xfd\x00{\xf6j\xda\xbfyi\n\x97\x02s\x00\xf36\x96\xf42\x80_\xafL\xce\xb4\xd1e\x88]\x86\xcd\x8aB=\x13W<\xafZ?\x9cG~R\x94}\x0c\x9a\x91D\xd2\x10\xae\xe95\x126\xd60\x93snr\xee\xae\x08\xcdF\xe5\xec($\xfc\x11fF\x1e\xf38..#\x11\x1d;Q\x07\xcf\x95\xe9b%3\xb4L\x00\xfd\x84z\xa9 T\x8a\x80H\x04\xcb\x13#\x90\x88E\xaa\xcc$|C\xfd\xf3I\x15\x86\xfa\x97f\x18S\xb95\x04o\x027A\x87\xdaH\xd7\x90PGue\x8e\x96\xa0J:\x1d\x12\xde$\x02_\xdf\xf9J\x8e\x10\x97K\xff\x0e\x1a\xdd\xe1\x00V\xa3\xc5\x18Z\n\xb1sE\xd9\x9c\x9b\xc5\xf8BW\xd7J?;\x1e%>w8(8\x1c0\x94|\xa5\x90\xf7\x99\x95\xbc[\xdc\xbc*\x15\xbf\x04C\xc0\xf63\xaf7\xb3\xf6\x03\xc4\x8c\xdd\x87\x82\xd5\x8f\x1fB\x88i~\x18n\x0ca\xe0C>\n\xc7\x88\x067Q\xb3@F\xc9\xf6\xf6\xd8R\xb3\x0e\x14\xa1t\x94\x8e\xb9\x8a\x8b\xf5\xc8M\"\x98\xe3A\x1f\xcc\xcf\x1e\xaf\x02\x98\x04\x10\x0605@R\x9c\xe7\xec\xffj\xb9z\xb5H\x7f\x93*\x11\xb4x\xb2\x04\xb6\"\x12\x0df\x81c\\\xeaWxS^q\x0eRQp.W\x88?{k\xe03V4\x1fc\x9ck\x0e\xdb\xc6\xd4\xb8\xd0~xs\xa8iA\xd6\xc2!\x15\x1c\xb6\x84\x9a1M \x14\nu\x84\xda\xb6@\xaa\xa8\x84\\!P\xb8\x80.\xa9\x80\x8e\xab\xd6\x10tb\xcf\x86\xf0\x08\"\xdc\xb1>\xbb%h\xbb\x97\xf0-\x1b\xf3\xd7w\x06\xa8\x9d\xe5\xf7\xe8(\x84m\x97rn\x86\xc2\x1f*\xee\x19\x8f\xcc\xe3\x82\x9d(\xac\xa8'5\x93\xe6y\x95\xbb\xe0&\xda\x93\x00\xce\x1b\xe7\xe5/\x7f-;aa$Z\xf8\x08\xce\x10Df\x11)\x81\x03Ht,\x82\xceo\xf2\x97\xffel\x82\x94\xcd\xb4/L\x1cNa\xc6&LF\xa1\x81Lg<\xf8\xc6\x911\xa0\xc4\x9bu=\xa2\x85#\xadC\x0f\x05O\x81\xf6z\xc3\xb1\xd2.\xc3\xed\xec\xac\xe0\x11,\xae,\xb7U\x08\xecn\xa0?\xe0cy\xc0s\xa1y\xc0%\xe5R,c\x14d\"\xce\xfc\x0c\x1e=\xc2#\xbf]L\x9b\xa1\x98\xa6[\xac\xca\x9beT0\x1e\xb3!\xfe\x89\xb4\xd1\x8b`3d\xc2T\xce\xf9 \x06yc[\xad\xf2ZIB\"-k\x01\x92\xbd\x98 \x87\x11\x1a\xcd\x8c\xab\xedm\xfd\x9a\xcf\xbb\x9e\xf2\x8cS\xcc\x88\xc7\x99\x99\x05\x93\x9c\x8cta^\x90K\xe9\x00\xb2\xaaQ\xcbi\x95ZrNj\xc5\x98\xa4:\xd9xyej\xf9\xdf\xacKz\xf9\x9f#\x86\x82\xae\xe9wy\\\xe6Z\x14\x86\xbab\x8e\xa1\x92\xc0\x8f+\x7f\xb8\xbe'&\x8a_\x1d\x0eZH\xe1\x9a1\x14K\xf2\xff }WXr\xee\xb3\x8a\xd5\xf4E\x99\x97P\xc0\x92M\x80\xb1\xee\x13\x93\xf1\xb4\xb3\xa6\xa5]\xcb\xf2\x1f\xd4\xb0\xbc\xd4\x00`\xde\xd8\xe0/\xae\xbc\xc1\xa5\x18\xc3\xa3B\x0b\x9f+\x86 2\xa2\x8e\xdf\x18\x8cu\x0c\xc9\x8b\xeb\xd9\x835U\xaev\x99\x90\xe4!\x06W\x87i\\./\xc3\xea\x19\x05\x12(\xf3\x08\xfd\xc6F\x0ce\xc0\n\xc3H\xd8\x87\x0c-\x01Z4\xaa\xac\x1a\xb68,\xca\x10\x89e\xd3\xe1\xadXv\xde\xa5f\xd7#\xd1)w~c\x91+\xba\xf3\xd2\xb9\xf6\xa5\xfeve\x0d\xac\xa4=n\xd0\x91\x94\xd3\x91\xa8V\xb6\xe8!\xa4\xa2\x84L\xea\x94\"9.\xea\x97\xa0\xe7\xc1X\xadwY\x9f\xdc\xaf\xfaY\xfcrm\x93\xe3L\xa6\xdb\xd4\x0c\xbcN!|\xd5\xe6\xa5\xe7w\x18(\x12(\xb3\xcf$\xfdJ9\x06\x13,@\xa7=}qE0H\x8a\xac\xa0k\x03\xad\x88w\x83\x06\xf0\xd5\x0f\xe0\x86\xdaKL.ZS;\x14P\xa6\x12\xca\xe8_\x19\x94A\x02\xdc\x99\xf2!\xd8\x8b6\x88\xfa\x13\x04\x17\xc9\xac\x0e\xc7\xd4\x98<\x0b\xaa\x8e#\x03)f\x8b\x89Z8\xd6\xa8\xa8\xadZ\n\xe1\xdcg3\xd5AI^\x97en\x9bT\xee\x96\xb6n\xb0\xbe\x99\xa8b!>Q\xf0\xce\xd7v\x1f\x91l\xc4\xc1'\xddS\x0f\xb0\xcc\x1e\xafy\xd6:6\xb5KD\xfbj\x87v\x95FR~f\x19\x83]\xd1\x91\xb4I\x0b\xf8\x92\\\xa6\n\x00\xe4]\xbb\x0cQ\xc3/\x18\xc2O\xd4K\x8c\xf6s\xb0\x8a\x0b\x93$\xa6Q\xdc\xa9\xf8C\xb3\x7f\xe5W\x9f\xfb\xcc\xb6\xecj(\xb7\xa7ic\xb4\xe6J5\xe6I\xad\x11\x90*0\xd9*c\x1e\xea5\xdc\x82;\xcd\x96g\xf2\xd9^\xf3\xd9\xa2\xf8\xce\xe4\xb9\xbf2x\x0c\x9c\x89\xd8\xa1\x0bc~=\x87<\x96\x9a\x88Z\xf6\xe5\x9cxJ\xcaI\x8d\xf0-O\x82\xc8\xa3\x96\x0c\xa3\xb1\xbd\xc6\x03\x1fL*t@\xde3~\\\xa7\xf0\x98g\x8dN\xe1\x11\xac\xe1\x00\xce\x89\xb7\x8b\x0c\xcfY \xe2L\xb1\x10\x04\xf1\xe2>M\xb8\xfc\xedcYZ\xd2\xd9-\x06\xfdD\xdeG_ \xf6\xacI\x03\xd2\xa6\xe9-4\xb5-\xfe&:/\x127O\x8b\xb9\xddaD\xc9\x032%-y@\xd8ArN\x19\x9bL\x1c\xf2\x80(\xc2\x87g\x8e\xb1\xe49\xbc\xc4\x11\xf7\xad9-^E\x19\x85Q/\x80\xde\xb8\x99\xd4\xa2\xd2\x93cR\x8bH\xd6\x8a/\x93\xe2\xfbEVrZ\xcdJn9M\x99\x00[\xb0\x96\xe8+\x83#O\xd2\xe842y\xb6I\x99\x8b\xf5\x14\xf7y\x99P\n7\xe1T\x13\ni\x02P#\xbbF\x05\x06\xdd\xb2k\xb8\xda/\x10d\x84\x83\x8c\xb3U\x95\xaa\xf9&\xbfo\xf4\x0d|\xac:\xb1\x11x\xa4d\x83\xed\xee\xb2\x06x,<\x82]8\x80\xb7\x82\xc7\xc3m\xb6+\"L\xdfJ\xa7\x04\xb4\x00\xf0gD\x1b]\x06`N\xb0Gp=\xe5b\xea\xdf)\xed9\xc74\x8c\x16v\x86J\xba\xf7\x1b_J\xac\x81\x02\x08\xc5\xcf\x18%0 W\xe1$\xa2kn\x10\x1f\xc2{t\xc2\xabG\x0dpy\x10E\xac\x88\xbf\x14\xd5^\xa2\xfd\xe3\x059#\x8b\xf2]\xf3\"n%\x8e\xe1\x06Q\xfa\xd0Z\xee\x00\xf8\xd8\xd6\xba\xd0\x13\x8e\xc6\xec$\xd3w\x13 \xbf\x0b\xae\x8a\xd4\xf7\"\xaa^\x98)y\x0e\xea(F6\x03\x16\x16\xa9\xcf\x19\xdd\xca+`F\xd8\xc2\x0e\xea8}\x1fG\x83o%\x15P5\xa9\xb2v\xc0\xdcJ\x169@9\x84!\x1c\x96\xb9\xb3\xf4\xf3\xdfJ\xf4*\x95\x8a\xe3\xc4\xeeC\xc8\xb8\x8bi\x86~\x92\x02\x16\xd9\xb8\x10\xbf\x8c\x049B7\x91\xb0\x80\x1e\xa3\xf1~\x00a\x9d\x82ip\xf4\xc9\x8c\x92\xc6\xf1\xde\x8a\xa2^\x15G1\xc8\xf8\x1b0UX?Q\xa8oA\xd8\xc8\x8e\xb0\xfaN\x9cp0\xa9\xe2\xa0\xc9\xa2\x848\x98b\xb2L\x86]*\x185(\x88/Ez\xc8\xa0\xf1\xab#r\xca\xcdbE9\xd1d.z\x13\xca\x8a\x08\x95|\x81\xf0k\xcb\x8bi2&\xca\x0f \xaf\"K\xf3x;%\x01,I\xc0\x98\x06[\x1a\xf5\x13\xf3iU\xf2\xea\xf2\x10\xd7BX(\n\x8b\x93]\xbf\x0c\x80J\xbe\xd4\x165\xc3\x0f}3|*\x89D\x04\xe3\xb0\xeb\xd7&\x06\x95\xb8g6\xb70\x00\xa3\x8d\xb5\xa2\xc7 +\xe5\xac\x0c\x9e&\xf2\x92\xc4$\x17\xfeK\x07\x12\xc1\xf8\xf1\xbe/\xa3\xdc\xf1\xa7\x99G\x05\xe1\x97\x92\x8b\xca\x87\xbb\xe8\x19\xbb\x03\xb9\xfd\x93 F\x9a\xee@n\xe0\x1b\xf1\x95\xc7\xb0F\xdca/\xdb\xec\xa1\x02\x08\xad<\xbc\xbc\"t\x9ce\xd3\x9e\x14\xfb\xe1\xd8Rt\x04\x14\xb5\x04V{\xdc\x99\xc0>\xa3\x9a\xf6OD\xcb\xe8\xd9\x15\x8e\xa8>W\nh\xb7\x1d\x80\x0c\xab\xab\xbb\xe5G\xa89nYV\x11 \xea\xbc\x80\x13$/\xd5\x05L\xe0\xf1c\x88\xec\xdf\xcd0\x00f\x9b\x1d\xeb\xf2\x03\xcb2\xcd\x8a\x05\x9d]\xf3\x82\xe2\xb9\xf6\xd0\xe8`\xa1^l\xed\xb5\x19]tW\xa1\x8b2 }\xf5+\x12E\xf6\x98\xa8\xd3\xa6\x90\xaf_\xa1P\x85\xb6\xbel\xb6\xe3\xcb\x8b\x0dcR\xf3%lCpP\x08&G\xf2\x19\xec\xc3\xa4\x0d\xc9A\x8c<\xe7\xae\xe8\x19f\xde\x8f\xf8\xa1\x940\xd4\x88\xd9\xa9\x1d\xf9f\xb7\x04\xb0N\xc9\xb27\x90.6\x1e\xbb%\x948\xd7&\xfb1\x1d\"a#;\xd7\x99E\xa3\x10J59;\x9b\xd98UU9\xfeTT\xe5\x04oH=y\x8c\xbf\xca\xacGa\xa1$\x8f\xf0\x87\"5&\xfc\x86\xd0\x97\xe7\xfcW5\xb9W\xe8\x04\x8a\x0bb\xd3\xa8\x9d\xa2i\xd0C\xc5\"\xb7\xeb3\xf1\xcd\xd1\x14\xfe\xbe e\x13\x88s\xee\x8f/\x92\xf3\xd8c*(w\x9a\x7f$\x89\x9bT\xcc6>@^\x18\xf1R\xf1\xa5\x88l\x1b\x93\xb3\x9c-\x9c\xdb\xa4F\\G\xa1%c\xce\x8c\x9b\xf8&\x1c\x0e|cHXX5I3~B\xc9\xbcQ\x9ed\xc3\xd0\xc6[t\xccXi}\xd8\xa0iE\xb3\xea\xc8\x8b\xe3\x9f\x96n\x99jWA\x05v\x1c\xf2(\xec4xK8(nJ\x13Y\xae\x8e\xb3\x19\x83`\xc2\x9bC3OW\xa8\xd9\xd0\x1f\xa0\x88\xc1\xa3\x8ag*\x15\x1e\xa8k\xe2\xf1\xfc\\\x82-E\xae\x94\x8d\x8a\x89\x97\x8d\x02P\xfa\x91<1\x8f\xa4\xb0\xa0\xd7l\xbf\xaaeU\xcf\x0f\xf2/\x1fq\x81F\xb2\x82\xb0\x0dg&\xa4\xab\xfarJ&R\xf0\xad\xf8\xf5C\xee\xb7\x80\xae8XXuX\xf80\xf0P\xad\x14=\x19\xd8G;C8\xb3\"^[\x99wcE/k\x92\x1e%\xe8EF\x9d\xf1r\xc7\xea\x13\x19\x7f`(o\xac\x98\xf5\xd5t;\x98\x9f\xc1\xcc\xb6\xb7\xb0\xff\x89\x0b\xfb\x8f1\x1e\xb0m*\xce\x10\x1623bc\x8c\xdc\xf4>\x9a\x8dv\xf1\xefm\x0c\x19c-h<\x16\x18>\xe4\xf5\xfd\x95\xb4\x91\xa9\x9c\xe1\x9e\x12s\xc0\x0d\xbf:N\xa5\x1a/Q\x88\x1e\x13\x15\x99f2\xe8t\x1bfl\xd4\x0f}|.\xf6\xd1\x84\x8dkR\xdd\xf1\x070\x92\xc6\xa3\xc9X\xec*&\xd8\xcd`[f\x1f\xc8\xd8\x9fg\xba\x11q\x99\x90=\x9e\x05\xbc\x8c\xfa\x8c\x1d\x00\xfc\xdf\x04\xff\xb5Md\xc1\xa5\xb1\x04#\x08\xf0\xcf\xd0\x7f\x08+\x06\x11\xec9c\xbb\xc9i\n\x95\xa1\xf3\xf1\xea\xf1n\xde\xe6N2\xc5 \x8aG\x18#\xc1\xc9F\xc8%\xee}60\xbc\xad\xa8\xb70\xba\xd1pda\x905\xff\xe6\xe6M\x8c\x03F\xd1l^SA\xb4\xd0\x8a5F\xb0 !\x9f\xf0\xe9-a\x08\xd9CX\xc2c8c\xff0J\xd0&K\x1c\xc3\x10\x16HA\x96z%\x89\xbcXwkAr\x8e\xc7\xbc\xdf\xf2\xb71\x81\x94\x9e\xbf\x93\x1f\xf2\x9e\xcf\x90v\xc1\x10\xe6-\x94 $\x83/A\xe6\xb1E\xc1(\xf6iEq\x92\"\x1b\x13\xfax\xd6=\x1e\xc2\xca\x87\x9c\x81c\x85\x8b\x86\xfff\xdcmaR8(4\x9a\x12z@\xde\x96.|\xb2pGf\xc2q\xc4(\x15\xe2\x87u\xe5\xc4>\x9cX\x85\x19\xb60'\\\xe8~\xfc\x98\x1d\xe8\xb6\x85a\x038A\xea\xba*_\xf7\xe1$%\xe1g\xf3W'BP\xdb\x1e\x82\xc7\xb7\x94\x0f\xdf\xc1 n\x92\x9d\x022b?\x8dN\xf4\xc2\xad~q'\x1c\xab\x1f\x0b5\"o\xa7\x0e\xd2\x8c\xad\xcc\x0e\xcc\xd8\x12M\xf8~x\xc4\xf7C\xe5\x83b93F \xc4\xfb\x92\xba\xec\x08\xaa\xb2\xa3\x8d\xa2\xec\x9c\x924D\xb5Fy\x9cp\xb6\x9bV\xd8\xf9\xb0\xd4\xed\x00\xc6q\x96\xeeU\x13\xd5\xbdj\xea\xea^\xc5\xc8\xc49\xf1r.\xee`\xa4f=\xba\xd1p\x1c\xff\xe1\x96/2U\xf3EV\"\xe8\xcb,k\xa1=\"\x04\x93b[\x99\xe0 Z\x01M\xe9{&\x1c\xc2\x8f\xc5\x9eMp}E\xa5\xbf\xdc\xcbxJI\xbe\xea\xd7\x9dR2\xe5\xf1h\x93\x0e\xe8\x91\xc0c\xe94y\xf3&O\x10Uz%'HR$\xe4\xebYn\x0c+\xf5\xb9-\xc5\x1cw\xab\xdeE\xa5\x9c\xd4Y\x9f\xb1My\xe6\xd4\xfe\x91\xbd}k\xa1\xc7\xa7\x9ce~M\xca\xfa\x8e\xecVg\xbf\x9b\xb3\xff\xf5\xf5\x1d_\xdb\xa1X\x94\xc2\x9c\xd5\x11\xce\xd4\xe0\x07\xd7\x94|U\xd5\xc3\x91bT1+!\xca\x14\xe1(\x02\xe1\x8f}\xb4\xdb\xf7\x8fy\xea \x9e;|\xc1\xed\xcb\x0e\xb9\xc3\x9d\xe6\xf4\xd4\xaaLXre\xc2\x92\x8d\xeb\x03\xf1xu\x9b\x0b\xe25B\xfd\x0c\xad\xffl\x970\x84i'\x90,\xbd1\xf5R.\xf8\xe0(3x\xfdb=6LIA\x0c\n\xff\xac\xe4\xf8\xd9\xd1\x1a\x9aT C\x9e\xb7I\x8f\xb7\\?\xd1\xa6(\xcc\x05y\x1cr\xedi\xf9s\x0f\xbe\x83D:n\xa2\x8d\x88\x1b+\x9b\xc9O\x0d\"\xac\xbcD\xff\xca|\x84\x8a\x05\xa55\xc3>\xf2\xfb4yI\xd6d\xfa\x9e|\xf1\xfc\xee\x94\x99\x8ev\x0d\\\x83\xdf\x9f-\xa2\x95\xc7:x\x1d\xf2|:\nn2\xa2\x9bVp\xb5\x8a\xb9\xaa\x933:\\\xa0\xf1L\x96}c\xd4%\xc2\xc3\x9c+1\x14\xe7\xde\\Q[0\"\x12J\xd1T\xa3\xbcTb\xcd\x8c\xb6\x99\x12\x01rD\xa5\xd0\x1f\x0d\xc6m\x8b\x9dr\xd5\x1e_G1\n\x9ej\xdd8\x08>?\xe1L\x9fK\x12Z\xb6\x90\x8bB)\xa2\x19#\xc90\xf1=\xa9,\xb4\")\x07\xf7\x0d\x17\x94#\xd2s2\x0c\x8c\x1f\x90\x93s\xcc\xbc\xfc\xae\xc5\xeb\x04\xdd\x95\x14\xaf\x93\xe3<#/\xc9:SJYH\x8a\xd7L\xe2k\xea\xf4\x8d\x81\xa6k{\xec\xde\xfc\xab?\xb7\xf9g\x7fn\xf3_[\xe2\xd8\xfeAl)b\x89:\x02R\xed\x9e\xdd`[\xbc\xcd\xabSi\x8e6\xb1?\xc0b\x8e\xb2xIkCgE\x99d\xf1\x91\xac\x7f\x86\xdeg\xb6\xbe\xdd\x07\x0b\xean\x12\xddx\x06F$\xd0U\x14as\x9a\x87Y\xab\x1b*\xa8\x1dE\xf1d\x91OIV\xafj_\xb4(_\xe8\xd6\xec<4\xb78 's\xf2\x8ed\xf9\x02\xf9\xdf8\x00\xc5\xa3\xf0c\x8c\x8f+e\xbbl\x11L\x85ZO\xebL\x01U\n\xd5\xa8g\xe5\xc8\x18\n\xafC\xf4\xb5\xa7fu\x84\xb1\xd8\x95\xe2\x9d\xdau~\\\xdf\xcb\x0e\x82wmR\xbd\xd4n\xca\xaex\xbbf1]\xb2\xf0nN\xac\xf2\x92v\xcd\xd4Z\xbeV^\xc8\xa5\xd0\xd6:\xb6\xf2*\xf7\x19\xba\xb9\x8ev[\xb2!\x01\x86u\xcaw\x95\x0f\x07\xe3@\xf9\xbb\xe1^X\xbf\xecfQ#\x19\x91\x97)\x8b\xb9\x1b>\xb2\x95\xc2\x15\xfe\x99\xc9L\xb0\x0f?\x1b\x11\xa9r\xd3D{\x9f\xb7s\xba\xad\x148\xad\x13\xdd\xb4;i1\xd3\x80\xb4\x1e\xd2\xe9RT\x99\x97%O\xcd\x85~\x0b\x19{(r\xd0G\x18&\x8c\xbe\xf6\xbc\xc4N\xaa\x15\xedp@V\x02\xe44\xbc\xab\x12\xa0\xa8\xc5\xd9\xa6J\x83R\xaf\x9c\x91\xfcXX\x04MD)j\x99\xb2\x9e(9\xcdY\xc5\xe1w\xe6\x14\xce\xdd)\x8d\x14_\x93V*\x83\x8ev\x82\xc0H\xf9\xd5\xfc\xf6\x99\xf0I\x8b8m\xb0\xbb\xa8\xa0o\x82\x95\x06I\xf9\x9dA+\x0c\x14d\xcb\x91\x02\x85\x0c\xdf\xb4\x0b\x00\x06uB\xa3*\xa2a\x8f\x7fl\xf7\\\xb3o\xf0Xe\xb1\xe2\xfan\x8f\xbb0G6.\x8br\xf6\x07-s\xce\x9c\x90<\x05\xbe\xeag\x00*w\xd5a\x9c\xa0\xeeE.%\x9a\xb6\x8c\xae\x8c\x07\x83J\x8dl\xd9\xd2 \x16=\xa1&@\xe4}\xdc\x19\xc0\x8e&\x855\x08\xee\xa1Nc\x8d\\A\x95\xc6V\x1a7\xb4|56\xae\x85;\x8c5\xbc\\\xac\x8f\x0e\xf9\x8f\xf3p-\xc5H.\x03\xd82\xc1N\x1f[d\x9b\x91\xf6\x8c7\xf7\xe0\xb4\xe5\x7fpU\xf9\xb5\x9c\xec\xb8\x19\xa3:\xaa\x19\xf1\xf8\xacH\xd4\xebv\xfcFxL-Y/[[%A\x8c,\xa7o\xf4\xe7\xb2\x03\xc5x\x9a\xbc\x80\xb0\xb5kJ\x0b\xf9\\\x87ia\nl\xde\x94gJ\x9c\x80\xf9\x8c \xf5Uy\xa1\x1d\xe1\x13\x8b[/H\xa9A\xe5\x13\xf0\x832\x91\xe2\xf6v\x00\x91\x87~ \x1c\x02hn6\xe7\xf9dS\xad\xfb\x84\x81\\<;\x1f\xe1\x04\xa6\x1a\x1f\x91X*/\xb6\x03\xad\x03\x9b\xe1\xe8\xfc)q.o\xe5F@\x06eT9\x92\xc4\xfe\x854\x84%.\\ \x08\x9bX6\xda\xb5X\xcd\xe4\x85\xd9,\xb5\x89A\xd5\xab\x8a/34\x15*9\x81\x9ecED\x91[\x1d\x91gfd8\xc1(\xf8\xe8\xf9\x1d7\xdb\xc0\x17W\xe2G\x0d\x11\xa7l\x86\x9d\xdc\x88\x98\x101\x80[\xe8\x83\x83\x81\x88\xe8\x93#\xde\xff,*\x98E\xady\x93\x18\xda\x1c\xf1:ff{\xc2k\xa4\x90\x86\x80\x1cF\xc0 \x81\xcd\x06r\xf6W^\xf4\xc8`\xd2\xa7 W\xa1+\x07\xb1\xe7\x97\x90\xd2\x0fJ8y\xe7\xb0\xa3\xc3\xcc\x0c\x86C\xee\xe9\xe7\xb1\xcd\x96 G\xa4]\xd8\xd7V\x9a8\x13^\x8d\xf6cg\"Y\xcc2\xdc \xc4\xcaZ\xd2\x18\x1a\x96\x06\xc4\x00\xb6\xf0\x94\x8a\xa4Y,,\xd2\xf8x\x93\xfaY\xe1p\x0c\xcb\x0c7\"\xdc\xb4L\nDDQE\xc9\xa4m3:\x89\xe9f4~l~\x00\x93o\xd3SEV\x1e'*\xb2\xea\x95\x8eY\x06B\x87\xd6\x81J8Nu\xfd\x95S\xc3\xa2\x03\x92\xd4\xd7\x12E\x9cqW\x02\xe3\xf3I+1\xbe\x12\xcb&|o7\x1b\xd8\xc2r\x90\xf9\xf66<\x82\xa4\xdcl\x13F\x83\n\xad\x9c8\xc7b,\xf8\x80\xe7X\x84h3\xe1\xe65\x031\n`\xa2\xa3G\x93oT\xd6 \x9b\x1e\xeb\xdfi\x89\xecz:\x896J\xabM\x15\x9fy}\x1c\x96\xf7\x9a\xcfR\xb9V\x0f}\x88ZOK\x06\xaf\xed\xed\x0c\x1e+(\xdfv\x12;E\xbfC[\x04<\xbb.\xedj\x024P\xb5N\xa1\xe0\xaa1 \x96\xd4\xe2Q\x0c\xb0'\x01\xaf\xa3\x13\x88'Oe\x92\\\xf4\xc6P5\x95]\x14\x04U\xac5\x1d\x98\xbf\xbb\x1e\x98v\xb2}M<\xb0\x99\x8c%.{\x84x\x16\x97\xf73\x11da\xa3S\xed\x88n\xe1\xb4'\xad\xa4\x8a\xa7\xe4\xc6\xd3\xb2\xceuO\xfc\x92je\x0d\xb6;\xb3\xb3\xdd~\x00\x9a@\xcbk\xe2\xb9\xbf}Y\x92\xd4e]\xba0\xf7\xdf~\xdet X\xb8\xc9q\x914\x89\xda\xe55MZ(R$\xb3\x0e\x86\x82V\xf8U\xd6\x1f)CT\xa3\x0cQ\xc0\x8f\xb0\xa8\x8d.\xb4\xcb\x0d\x8b\xd2\xeaa\x7f\x99q\xa2\x0b\xac\xe47\xc3\xbfX\x07\x9c\xcb\xcb*x;\x13\xf1L\x16\xf6\x1e\xce\xe7\xd1\x82\x80\xd1)\x0fTu\x00\xda\xae\xd4\x99'\xd8G'\x9a\xe7&$\xfcz-\x86\x8fo\xb6\x04X\xf0\x17\xe9\x94\xa1\xce\x91\x18@1\x1b\xeae-\xb4\xe7LT\x0d1oeve:\xca\x16\xb5(\x10@\xe1\x9e\xb7\xd0\xf3j\x02\x8f\xb0`\xcdM\xc8=\xac\xda\x87e\xf2'\x18\xa8\x0d\xfb2M7R\x84X\x94\x03HPR\xf4\x0bIbk\x17\x8bs\x9a\xf1\xca\xac*g\x0b\xcb\xben\x96P\xfa3L\x19\xa9Y\\\x03\xb1\x8a\xa3\x96B\xe7\xd7F\xa5\x04[\x958))\xa8\x93\xc9\x04\xe4\xb9%R\xcdw2\xcfN\\\xe9\x0d\x88^RA\x01\n\xf7\xeb\xd1`\xcc$T\xd4\x10z\xa1\x8c\xa7@\xecb\xc7h\xeeM\xca#3.\x08G\x1a\xf0\xf3s\xd2N\x16\xd9\x15r\xe7\xdcD\x94F\x9b4\x96\xd7\xda\x82\xf0\x8eJ\x90\xac\xa3g\x97\x19i\xdb(`\xdb\xaa]#C\xdb\x81\xa2\xba\x99\x99~\xb1RT\xee\x91\x89\xd1\xaa:\xf9E\x12\xdc\xd0\x986:2SK\xbe'\xa5v\xa3\xe2 HZ\x8a8 \xb8\x8fR\x1cy\xc4K/\x1e\x00\xffP\xb8\x97\x11\xa3\xfb`\x91e\xdaxD$\xfd,I\xa9\x9b4+>!\x1e\x1d\xdd\x1e\x07\x10\x8fn\x8f\x11\xcb\xe9ho\x0c;\x10\x8f\xf64\x19\x82\xfd\xb2 y-+\x83q\x97\x96;i\x08{\xcd6\xeb\x15\xfal\x0d1\xd0\x8f\x06\xba\x81q\xce\xf5\x85\xa8\xf1\xc1\xdd\xbao\xf0_?z5\x85\xa0 \xa7^Zq\x8a\xfb\xbb(x\xe5b7\xfa6\xed\x82,u\xe0\xdcRG\xe0\xcaK\x02\x99\xad\x0f;\x99\xe0w\x0fC\xd8K\x9fK\x86\xef\x96\x03\xff\xea\xfa6\x07\xf6\xbf\x03g\x88\xab\xd9*\x80\xa1n\x02\x973\xb9\"\xa0\x04\x16\xd8\x00\xc2\x13\x90\xf4\xb3dI\xae\xd2\x01C/K\xf3\xa2\xbe\xd4_\xc8H\xc9\xfc\x989\xe6\xc7\x14\xce\xbe\xa2\x1c\xc5U\xa1\x88\x03\xb4\xcd\xf2\xfa\x05\xe2\x1f[s!p\x13\x0b\xaf\xc9A\xfb\x93$\xceh\x9aOP\xb3\xecF\xdf\x7f28zGE6\x1b\x1e\x81\x84%F\xe8(6j\x0d\x810\x01\xc9\xcd\x818mI\x9c\xcc9\x88\x82\x04Zs\x8aq\x0bv\x14g4\x8c'$\x99)\x15\xcf-N\x11\x089D\x8f\xea\xa7\x95d\x9f\xa9gR=\x17MX9tv\xc5\xa8\x96j\xd7\xb2\xe6e(\xe5g\xb2\xce\x8c~\x89\xf2\xdar\xe3\xca\xd4\x8b\xa6k\x87\xb7\xd8E\xb4\x11\xaeN\x9d\xc8K\xcceJfQL~N\x93\x15I\xe9Zp\xbe\xee\xad\xb0\xeb\x94PE\xb4\xec2\x06y\xa9$\x88\x87Mvj\xe2\xb2\xdd F\xbd\xb2\xcax[\x8fo\xdduJk\x89\x98\x03\xe8=\x0d\xe38\xa1\xacuHb\x08c\x88\x8a\xf4\xbc)\x99$\xe9\xb4\xdf+H&\x8f\xb6\xb3\xb0\x98\xba\xab=s\x9b\xbc\x0c\xd1\x08\xf5\xeb\xb2\x7f\x12\xc5S\xaf\x8c\xbak\xff\xec\x12&!\x9d\xcc\x01\xc1f\x1f\xd0\xa5']\xd3\xe5\x11\x91\x0b\xfd\x04r\xfdq\x88\x81\xbcK\x93\xe5aL\xd35\xd7\x95*\xca\x9fv\\\xe9V(\x81\x0b\x7f\xc3F\x95\x04\x87\xfc\xda\xa4B\x14*\xdd\x1a\xcd\x08%!\x11KT\xfd\xc8\xbc\xacp\x00\x1f\x88p\xe5\xecPmA\x1e-D\xdd\xd9<\xef\x85F\xa2AHF\x99BH\x87\xf0\x9aT\xe1;\x9a\xca\xea\x06\x15\xa8\x17u\x0e4\xfb6\x00\xe2\xbd#\x01\xbc\xf0\x03xw\x05\n\xdc\x14\xfc\x90\x02\xeb0\xa1\xd2|-n\xa0\xb5\\\x1ao\x9b\x17M\xb36\x8c\xfa\x91\xf7\xe4K'\x9a\x81\x8d\xcb/\x9bt\xe1]\x15nN\xa1BgJEf=\xbe\xb1&>Jr\xb8\xa5K6X\x19\xa3L6\x80F\x0d\xe7i\xaa\xcd\x88yJ+\x8798\xfc\xd2o\x04\x89\xd6\x80\xc01\xb7\x15;T\xb2\xa8\x07\x02\xa3\x02\xcf+\x87M\x070\xa4W\x01C\\\x03\xc32\\i\xf0\x15\x04\x18\x1a\x85_\xde}\xdb\x19\x11XB\x94\x9a(Y\x1e\x13\xd5\xc9+\xe6<\x07\xc7e\xea\x11S\xcc\xd2%#P2\xdf\xf2?y7>\xcf\xd2S\xf4`T\x9d\x17\xcdG\x81\xc8\xd7\x1c\xc3>/\x06\xa4\xeb\xcao%\n\xdd\x8e&<\x1eT\xb0\xf8\x16\x08\xca\xe3I\x7f\\\xc4U\xddS\xc3\xa0aD\xdd:\xd8\x8c\x8b\xea\xa8\x90\x97\x96\xa1\xd8\xea}Q\x88 hP\xe1JCT4\xf3U\xc0\x82\xf8\xe8\x17V\x98Wt\xcba[\x8a\xf2$!\xde\x1b\x12\xc0\x0d?\x807\xeaR\xe9\x02\x01\x1d\x89x\x11\x0d\xd8\xa4\xe4o\xbems\xb5R\x1a\xf3\xfah7\x9d3o\x86;\x0cA\xee\xca\x92ig\xea\x86\xf7\xdf\x84\xb0\xd7\x82\xa1\xc4\x15C\x89\xc4P\"14\xe5\xa6\x10\x81\x97N5\xc3\x88\xf7\x8a\x04\xf0\xa3\x1f\xc0\xabo\xe7 ,\xc8\xf7\xeaZ\x90\xef\xcf\xc40\xe2\x8e_\xda\xc9\\\x1b~\xfd\x87\x91\xa8\xc4\x9f\x8e\x88\xf4Lp\xba\xcfT\xe8\x10!\xcc\xb4\xf1\x10\xcdu\x14,D\xbd\x9fg\xff\x95\x88\x84.1\xa6\x87\xec\xfa\x89x\xc6\"z\x8a\x93En}\xab@W,\xd1\x8f\xc2\x00:vr\xb1\xb5\xbc\xb9\xcbo\x1a\xa4Xv5\xf5rZD\xd7\x02\xfb\xbf\x06\xd1\x1d\"C\xdd\xf6\x02\x14\xe1\x95\x15\xb7p\x8b\xf3\xa4\\/\xd2\xe6e\x89\xde\x95\xb6\x11\x02G\x0e]\x18\xa0zI\xde%o}S\x0c\x1e\xf7r\x04\x07<\x91\x0bG\x89\x14Q\xa2\xbc9\xe07\x07\xcd|\xf9\xeaepYt\xa0 \x95s\xb8\x9a\x86\xe0\x9d\xf9\xd1+\xf3\xa3g\xe6G\x98\xa3\xcaK\xe3\x00N(\x13-b\xe5\xcdoT\xb0\x86\xb1\xe0A\xb7\xa1g\xd4\xb0V:\xec||V4\xea\xec\xf3\xb7\xe7qi\xf2\xb1w\xe6\xa8L\xe0i\x9e\xe6Eut\x1b\x9aW7oep#\xaa\x89S\xae\xcc\x85\x89\xaf\x07\xe5\xdfRg\xa1\x89\xd9\xac\xcf\xc4I\xf9[J&Z\x95\x15\xef\xff\xe6Me\x00\x15}\xae~\xb2R\x99\xa0\xda\x06\xcc\xd3\xec\x1f\x93\xe5\x8a\xaeQL.~\x0c!\x8f\x85\xa8\xfd\x1bm\xa6<\xadM\xd5Qc\xdc\\\xb4\xd2J\xcd-\xd4\x7fS\xacZy\xfc9N\xcec\xf8L\xd6\xd0\xfb\x1bl\x03\x85m\xf8[\x0f\x92\x18\xd8/\x89\xc7\x06#y\x05z[%\xf8D1\xfd\xb2\x16\x87\x16)\x1c\xf4\x86\x15cBu\x892\xa9\xd7j\xc1\xadJY\x08e4%\xce\xc1~\xb9\x0e\xcd:\xcc\x955pT\xae\x1b7\x8ey\xa6\xc48\xfb({\x8f\x9a\xf8I\xdcT\x01\xcd\xe2\x00\x16\x0c\xc7z\x7f\xff\xfb\xf1\xf1\xd1\xeb\xd7\x1f?<\xf9\xe1\xd5\xe1\xf1\xfb\xc3\x0f\xc7\xc7\x7f\xff{\xaf\xe9\x08\xb2bog\x0eJ\xa3y;\"\x18\xaa5\x91z\xb5& \x05Y([j\x88\x91\xcd\xe5\x87\xa6\xf4\x8eg\xa0^\xae\xe8\x9a\x87O\x17`tSDL\xdb\xf7bU\xc9\xb5\xb2\x04a\x94\xd9\xeck\xe5\xebb9-\xca\xb3z\x97kJ\\\x93p\x9fY\xe9\xd2\x0c\xf3\x0ex36\xdei\xec\xe9L5\x86v\xd7\xdf\xa0\xd2:\xe7*\xad\xd3\xb8\xd4d\x9d\xff\xbfM\x93uj\x87_\xa1\xee\xd3\x14XT\x7f\xad\xe2\xd1\"\x96\x0et+E\xa9\xb5*\x95Z\xab\xaa\x82I\xfe\xac>\x10\xac\xc1*VuV+\x17\x85\xcf\xca\xa6\xf0Y\xb5)|V\xb1\xdc\x870\x84\xb3X\xdc`[\x11Q2\x00\xe2\xadcF\x9c\xfc\x00\xd6\xd7\xa7\x11Z\xff)\x1a\xa1\xf5uj\x84\x84\xff\xbdM1\xb4\x8eK?}N\xb9O5\x94{\x19\x07p\xcc\xf6\xc9\xda\x81\x16\x9ft%l\xc7\xff!\xc2vn\x85\xe6\x92\x13\xb6%\x1b\xefI\xec=u/\xbby\xf1\x0d\x84\xed3'l\xef\x15\xc2\xc6n\xf5\xf38\x9bG3\xfad\xb1p\x8d\xe6\x7f\xef\xac\xe8~bWt\x1f\xc7\xa5\x83\xed\xb1\xba\xd7\xcecqC\xec\xb5\x13\xdck\x17q\x00\xe7\xd4\x0f\xe0\xe2\xfa\xf6\xda\xc5u\xee\x8a\xf74\x9c|\x86\x11\xdb\x10\xe3\xe6\x86\xb8\xb8\x82+H\xd5\x18?'\xe1\xb4\x89\xcf\xa8\xb7\xa2JRn\xea?\xe4\x89\xd7\xe9\xce\xceC\x1f\xbf\xe7^U\xe6\xbd\x00\x07 \x92\xd0\xe8\xe2\xfe*#_\x11\xf2\xb9\x13\x80\xd8\xa8K\xc3!\xfb\xa5\xc9\xde\xd1\xe8%\xcf\xe6m\xbd(9\xbe\xe5\xfa\xbai\x1d\nM_\xe1L\x82\xbb\x7f\xbb\xd1N\xa00\xc0l\xe0\x01\x02\xb3\xfe\x16\xec\xc0\x80A\xfc1W\x1b\xee\xec\xf8\xf8\x99\x89/\xc0\xcc*E\x1b\xa3\xd8\x90\xfb\x90-X}-\xd8\xa5I\xb4\\\xc5GC0e\xc1i\xe3z(\xf1V\x8d\x8a\xa1\xfcn\xad\xfc\xb9p\xed\xff#\xd6\x8b'\x8d\xc5{\xc2H\x91\x83`\"\xd4\xc9\x98\x1f\xda\xa3\xbe\xcf9\"\xfb\xfa\x959HZ\xa4\x16d\xc0\xf5\xd0m\xd9T\x05o_\x84\x07u\xe0\xd0\x08\xcf\x92gB\x01(\xd1\xc0P\xf5\x18\x8a\xf5o\xa6\xce\x87\x06\x19\xc5;E`\xaci\xfdIm\xfd\xe3\xab\xae\x7f\xd3\xfd\xba\xb1\xfeIke*\x15e\xb3E4!\xde\xc0\xde\xa68\xa6\xba\xb4\xcb\xd0\xd0Q\x1d\xa5\xeb\xca\x05\x83\xeb\xdd\xe9N\xd1Z\xeb\xdd\xa7\x91\xac\xae2\x8b.V\xa6o\x8d\xcf\x16(U\xc3\xa0.x\xc5X\x11;\xd8\x18\x92\xb8\x1c\x99\x8c\xa8|\x16\x8e\x1e\xc5`]\\\xc1b,.\xa2V\xe95h\xb8_{\x95\xa6\xab\x16\xaa\xa2\xa3sZ\x1f}\x99\xa6\xc7\x18\xe3W\x9cLi\xe5d\xc22gQ\x95d\xb1\x83\xe6\xa1\x8fw#\xfb\xe9n_\xc4\xb4\xb6\x88\xd1\x95\xd6\xef\x8fXWa\xba\xb6\x86\xdd\xd4V\x85.\xa9\xa9\xb9R\x10\x14\x0e\xf0L*\xa8\xbd2\x99\x8ea\xc8\xea\xcc\x06\x06=\xd4\xc5\x95\xb5\xa0\"\xee@]\x92\xf2hQ<\xbflH\x11\xf3=\x97\xd6\x10!\xad$\x13Le0H\xac$\x13\xc4o\xd2\x16&\xd0i\xb2n:R\xa7\xd9&z\x1db9S\xed\xd9\x97\xba\x9d\xdc\x8e\x91 \xad^\xff\x92\x9fH\xdb\xe2\x07D\xbf%\xa0\x03\xee\xd9\x8f\xcb`\xb2\xfa\xeag\xc8[je\x1e\xda\xb2\xf3Y3\xf3\xb9D\x05\\\xa0\xd6\x15\x85\x9a!\xbc\xd7H\xef\x87q\x00Otz\xd7\x0fO\x9e\xbe4h^\xdf\xb2\xf7/\x1c\xa4\xfd?\nw\xbd\x96\xfc\xa15\x8f=kF\x99\x92\x19\x8eTN8\xaa;\xeaE%\xfdK\xf9\xaf*upK\x19\xf8\xd9z\xea\x1er=\xc0!\x03\xc8\x1f\xb1\xd7pO14z\xd4..\x16ho4K*\x87\xd3\x08ut\xec\x9f&J\x18!\xa9\xa6\xef\"%o\x1c\xfb\x01\x94.\x93Jh\xc4\xfb\xf5\xf2$Y`\x85\x04\xdb\xf3z[\xb4\x06\x11\xf5\xd7\xdbx\xf4\xa4P/\xbeu\xd1\x06\xbe\xb5i\x03\xdf\xb6i\x03Y\x17\xaam\xed\x8b\x9aE%\x80\xb8\x7fT\x12\xc8\xaf\x01[\xa6X\x97\xfeK\xa4\xc4vH\xf3\xf5\x8cz6V\x04\xc4\x82S\x91\x1b\x97g\xda.\x8f\xf6\xcdFk\xa3\x87\x1acP\xe6{0\x98\xde\xac\xa6m*\xb0GOc\x1a+\x88w\x9b4\x81&G\xf1\x94\\\x90\xe9{\xf2\xc5\x010\n\x89\x7f#\xa2\xce\xddz\xf9\xe9\xbd{\xeb\x08\x1cm*l\x17\xcd\"W\x87pa\x84p\xefn\x1d{!\xa7,\xd2\x94]\xd2I!\x17;\xf6\xde\xa9\xdb\xec:\xbb\xed\xbcI^u\"\xa6\x9d\x9a\xcf\xaa\xb3R >\xce,\xac?/WY\xaa!\xe4\x9c\\ \x052\xae\xee#\xbc\xb86\xd0\xbf\x8a\xb2\x0eK\xbe\"\xd7\xd5/7C\xb8\xf7\xdc\x1b!\xc7r\xb2 \xe3\x9eK\x0f\xa5\xa9\xc3\xb1\xfc\x85Y\xbb\x04\xdb&\xc6\xf2\xba\x9f\xbe\xf2\x12\xc3\xcc\xb91\x8f\x97\xd9e\x94?\xc5\xb0\xc7}\xce\x14\xc2\x01\xe4\x98\x92|\x1fB\xea!\x7f\xd8\x8f2\xc1'J#\xe0\x88\x8e\xb5\x94[\xbd.}wOo\xf5*\x10\xc0\xe2\xf5\xad^\xa6\x8a\x1dP1\x16D\x0d+\x8f\xfd\xabA\xed+\xfb\xb8\xcfD%\x84h\xb4\xebP\xe79)\xed\xad\xb8\x08\xa1\x97\xa0\xc7\xae\x0c\xc4\xcd<\xa5\xd0j\xb3\xde\x96\xbc\xcc\xd9W\xcfD\x95(Q\xfdBW\xd7X^\x92\x92ci\xe9!L\xeaT\x14\xc7\xc4$N\xf9T\xd2S?\x90\xf7f\x8b\x90R\x12{[\xbb\xc2\x12\x83\xdaEM\xd1\x13\xebV\x00\x01\x1c%\xcd\xa8\x13\xba\xc8-\xc4\xfd\xa0\xec\xc0\x87f\x1fJ\x85X\xd86XN\xe4e\x06\xf8%\xaf\x8d\xd6,g\x8b\x0f\xa5\xfaV\xe3\x0e\xed\xc6\x8eH\x8f^\x97\xb4\xc9*\xbbV\xf5 v\x897\x98\xda\x12#k\x0b!4n\x91\x98\xa6Qe\xac.CU\xf4{\xef\xdc\xba9#\xe9\xda\xf1Lq\xe4\x82cK*\xf2\x16.8\x0d\xc0V\xf2\x13\x8a@s\x8e\x03\xbc\xd6\x11~\xa1\x14Z\xe3Z\xa2\xad\x81\x01\xf8uG\x12\xd0\x03\x86\x13]G\xc8\xd4O\xae\x1f\xd4|\x82\x9a\xf0'0\xf5\x19Ok=\xbaT\x8db\xc0d\x9fbNT\xcf`\xde\x00UOz\x80 M\xf4\xe5\xc15\xc3\xe2Z\xa1n\xb0\xa8 KP_q\xeei\x89y\xbb\x89\xaf/S\xa3\x19\x08\xe3@\\6o\xbd\xef\xc2\x92\xc2\xe9!\x1c@\x0f\x19\x1f\xd8\x87^\xd03c2#\xc1=\x8d\x1eU^\xdf\x82\xe96\x1c\x8fE\xa9\xfe\xad\x01\xba\xacn\xa3\xd2\x14\xffE7\xa3-YBJ\x99\x14\xaei\xe1E\x83gN\xaf\xc9Y\x82\xd8\x01N|\xdbg\xb2\xfe\x06\xf2\xf3\xd4iE\x97\x159\xd4\x01\xad\x8a-VM\xd9\xe9\xd4\x19?K;n\xb0\x00\"\xeb\x02\xd7p\xad\xe1\xa0\xf2\x08\xf60?\"\xc3\x14\xd8\xe7\xf9\x90\x1a\xdbAU\x03`\xcdZ\x1b\x01\x84\x03\xf0\"A\xe5\xb09_\xb4K\x8b\xd2\xb7\xbcb`b-\xc8\x9c\xba\x83\xec]t:\xa7\x1d\xe1& \x93\xca\x08\x95\x86(;}\x12\\\x8f0\xbd\xa7F\xbb;\x98\x06\x8d\xbd\xb8\xe3n\x81Tj2\\\xa7\xae\xd0\xb8|E\x0c\xfer\xb5C\x82q#\xddz\xe4yYx\xac\xdc\xbb\x18K\x85\xe9\xb2`\xe8\xbaJ\x9djL\xd4gf\x0c\xc8\x01}?(u\x7f\x03\xad\xf9\xd9\xa9\x97\x93\x9c\xbe\n\xbb\xa8\x07\xf8\xbeF\x0f\x99\xdd\x00v\x06N\xbdD\xd9\xe1rE]l\x0c\xa2\x17\xf5dR\xe4\xf4\xba\xe4\xbe/\x96\xb1\xca\x8c:\xf0\xa2&#\xa4\xd3l&I\x1e\xd7w~\xcb|\x9ex\xb4T%\xf1m/\x04X\xfeq\x07\xbd\n\xf6\xfe\x83+{*\xfaw\xa5R\xa0P\xaa\xaf\xd4\xf3K\x83\x94-\x03\x9eD\x0d\x1d\xf1nc]\xf1{\x917\xc1+\xeb\x94\xf3J\xe2lW\xaa9\x8f\x9d\xa46E\xe6\xd2\xb3\xbb\xf2\xb2\x94R\xc1\xb3@5\xb7\x19*\xe4]\xaa\xe7\xad\xcb\xea\x91/y\xb8\xe8\"l\x9d\xd1\x82l8\xb5/\xb2f:l5\xd5\xe1T\xbf\xb6\x18\xa8\xd5?\xc6ty\x95\xe2L\x94\x96\xf7\xed\x9cb\xb5z\xeb\xcf\xb1_S\xb5Z\xcf$\x0e\xc6A\x0b\x1d3\xc3@\xa2\xa0\x1b\x05\x8e\xaa\x94\xb7\xd5\xfc\xa4P\xb0\x00\x12OG\"\xe5e\x18\x7fgQc\x1ev\x913\x90\x0e\x89\x84\xcbK\x1eC\xb0t\xec\xe5\xa8\x0b\x0d\x97\xfdp\xaf\xd1.=E\xd9\xfb\xfc\xc4\xb1\xc0g!\x03\x0eM>aE\xa5\x14nu\xe6<\xba\xa2\x13r[\xda\xe2<.\x12\xe3t\xc8\xa7\xa5\x9f\xe2\x8a\xf1B]&\xe9\xd9f)`\xa6\xcc\xd2/n\xba\x9fj\x9f\xc9\xfa\xed\xac\xc3\x90\x8aC\x8d1s\x9d y\x0dFB\x1eq\xee~\xc4W\xb42lW?mH\xa9.\xdd.\xba\xab\xd1\x1a%\xbf\xfa\xc8\xcf\xba\xf7\xf7\xf2*\xebb\xe0\xbdq\x8d\xb5\xb9\xac\x9a}/\xc3\x8b\x0e\xbd\xbe$\x9dT\x18\xcb\xf0\xa2\xeb\x99\xfa\xb2\x92\x8f\xc8\xa9\x137\xa3Yc\x06p\x00ob\xee\xc2\xf2\xd5MPZF\xf1\xd5\xa7\xc3\xbb#\xbc;\xd7\xb9\xa5\xa43&jC\x1eA\xdf|\xf69Zu\x80\x9d\xd2\xfe\xeb\x90\xce\xfb\xcb\xf0\xc23T$6tV\x17\xbe]\xa5\x04\xc3\x1ecMzT\xb9\xe3<\x90_\xe7\xd1\xa2\xa3\x99\xa1\x18\xcc\xefW4l|\x8eV\x1fc\x1a-\xbau\xcb\x81.\x87\xdcM\x05\xc5\x13\x82u\xeb\xafi\xe5\xd0d\x06\x03}\x7f4\xfcL:,/\xad\x18 \xae\x80R\xac\xbfkF)\xd6dw\x94b_}\x0bJ]E\x92\xf8\x87\x13w\xab\x940\xfa\x18\xa3\x9a\xb7\x92\xbc\x0d#+[\x18^\xc9NS\xa3vY^L\xa4\x8b\xaa\xb1yJ\x81\x96J\x18\x08vlo\xedL\xd4\xf3o)\xfb_0n\x1a\xc1\x87\xa2J$l\x9b\xa1\xd2L)\xfd\x14\xdf\xde\xbc \xdb\xdb9\n\xa9\xa2AC\xa1ry]\xfa\x01\xe4\xc67.\x03P\xcb \xfd\x17\xadJ\x92vY\x16Z\xf1\xc6b\xdf\xd9\xe5Zv\x85\x16\x8f\x12y\x89q:FY\xaa\x17\xfaN\x85\xc5L\xdb?\x00\xf7\x88G\xf5\xb2F?\xaa\x97!VB\xbd\xa4\xe9&o-N%/\xae\xc3\xaf\x14\xa9\xb2x\xa9\xcaKF4R\x11\xc3\xdb\xfa\x01\xbb2\xe1\xac\xea\xf6\xf6\x04\xdf\x1e\xb4\xb8\xb6\x82n\xafM\x02\xc8P\xe3y\xc0H\xdbp\x08\xef\x84\x98\xf3\x9cad\x86/\xf04\x7f\xa1\xf0\x0c\xf9/X\xdc6\"`\xa5\x00\xda\x87\xdd5\xaf\xec\xe0\xb9*SQ\x1cZ\xdd\x98\n\x19C\xd0\x91/\xed.\x86\xcd\xc3l\xfe4\x99vpt\xa1\xf32\xbb\x00\xd6e\x9a\xab\xd9\x06\xday\x04(\xb6\x17wP\x1e\x0ea\x00\xb7`\xb7\xd8h\x16\xd2%\xcd\xa4\xb3V\x05\x9f\x9b+\x7f*\x8a\xdf\x0e\xf4Uo\x8b\xd7\xf8\xc0\x9c\x16\xbf\xf6\x0d\x1b\xed{\x14\xd2o\xdf\xb9\xbd\xf7`p\xff\xf6\xdd\xdb~P\xdc\x86G\x8f`p\x176@\xe0\xf1\xe3\xc7\xb03\xb8\x1b\xc0\x9d{\x83\xfbw\xee>\xd8\xfd\xbe\xfe\xdem\xe5\xbd\xdb\x01\xdc-\x9fc:w\x8f\xc06\xdc\xbe\x7f\xef\xce\xde\x83\xbd\xc1\x83{\xb0a0\xfd\x17\xdb\xd2\xff\x12\x9f\x0d\xee\x05\xb0\xb7w\xe7\xde\xfd\xbd\xbd\xbbE\xf3\x87\xe2s\xec\xa6x\xf3v\x00\xb7\xf7\xee\xdd\xbbs\xff\xc1\x83\xdd\x07\xbe\xda\x84e\xcby*\x7f\x10c\xad\xcb\x83\x8eP\x83!\xdc\x1e\xc0w\x90\xc26<\x8f\xbd'\x147\xcd\x13\xea\x11\xdfg32w\x0e\x8e\xbbS^\\+~\x85^\xaa\x93r\xe9\xa6\x98\x11v\xd4\xdaA\xb7\xc6\x1d\xdb\xf5\xb5\xe5\xac\xa1 \x88:RX\xb9SW\x06\xb3\xbd\xf8\x9a''Sr\x01\xa8o\xbc\x8eG\x0b\x19\xe0\xfd:\x1e=c\x7f\xbf\x16&\x8b\x8c\xdd\x12\xa1\xa3\xfc\xb6\x08\xac.\xee\xab\x81C0\x84W1>\x89\xe2l\xc5s\xe3\xe3'\xef\x93<\xad\xe6\x95\xd1\x81\xac\xa6D\x12\xee\xad\xd5\xd9a\xeb\x93y\x18\xc5\xbcma\xcb\xe4\xb7\x93\x98\x86\x11F\xa5\xe3\x10\xb8\xee\x12c\xc4S\xdd)9[D\x1dB#\x0b\x01\xe5+1\xae\x84N\xed\xb3:l\xb8\xf7\xbbZ\xff\xcdT15\xcb\x02V\xe1\xae\x93a\xb5\x90&\xa4\x93\xc4( \x1a\x9b\x8bO\x03p\xa3\xaab\x93t\x14\x1a\x97\xe1\xeae\xd5\x07\xd9\x15FW\x00\x02[\xf7:,\xda\xc4\x8c\x06,x4\x82\x05\x08\xd8\xc9Uv\xeb\x87\x18\x93\x9b\xb4f\xeexj\x06\x92<\xd5\xaa}\x19\xda\xf9\xb9\xb5\x9d\x11 \x80\x8e\x9d\x1a{g \x87\xf5\xb3\xb9e\xb3mQ\x97d\\\xd0\x84\xa7aXo\xaegX;\xd7<\xacW\xf6a\xf52\xa4\x81\x15\xe3\x07\x1c\xc0O\xef\xdf\xbe\xe9\xf3G\xd1l\xcd\xd5\xb6\x82Z:\xe6\x16}f%\xc0\x87\xc6L\x9e\x86\xe6\xbe\xb6b\x10\x85G\x05\x07G\xe11\xfe\xbd\x83\xec\x9cS\x07\xcf\x1d:`\xac\xcf6\xec\xdd\xbb{\xe7\xce\xed\xbb\xdf\xdf{\x00\xdb\xe0Q\xc6\x90\xdd\xf3\xf9\x9f\x8f\x1f\xc3^\xf3\xf4\xad.\x94h\xedCT\xaf\xc2h`\x95\xcb\xe5\x95|\xb3\xad\xaeu@J\x1b\xdeV\x82\xa5\x00\xf8\xba\xf2\xd0R&\xa2G\xbe\xaf$-\xc5f\xc5}k\xcb\x97\xac\xf7\xc0\x96GC\x85\xa8\xdel\xe7\x0c\xd2\x80[\xee*1~\xd8\x7f\xeb\xe4\xdd\xed\xa1W\xb0\x9f\x15\x90\x8d\x18ds\xf8\x1f&;\xb0\xad\xc7p \xa9\xb8\x00c\xcc\xef>\x7f\x07\x0e\xe09\x9b{\xce\xd3\x91\xa2\xd5F\xfe\x8cd\xca\xd86\xf0[\xad%\x86T\xe5%\x95p\xde\xc6\x0b\x12\x9e\xb9p^\xd2,7b]\x8c5\x87\xb2oY,\xb6/op\x02 \xf5/\x01\xdc\xe8'3t\xa65~\xc6\xf3\x93(\xde\xf9\xd6s\x96\x14\x1b\xdf+\x88\x81\xb8\xc7\xe8\x80\xc8H\x13\x94\x94\xc8\xcd\xc7\xa9\xab\xcb\xdd\x92z\xbbj\xcaj\x97>\xae\xe0_\xc7\x0e|\xc7\x08\xd5\xebv\xefq<\xf9\xbf^I\xafzC\xfe\xf1,\x0el\xc8\xe6<\x86_#:w9\xa7\xa4\xcc\xa3\xf6b\xc77\xc6\xd3\xc9\x00\x81\xe6\xf8M&\xcb\xca\x9dK\x9fQ\x842=\xec\\\xea\x1b\xd4\x9bE\xdd\x96#t\\o\x0e\xbf3\x8f\x85\x18\xc4kA\x0b\xb3\xb2\x93\x9cv\xd5|:\x9a\xaa\xd3p=\x9b\x0d\x9b/s\xb89@;Q\xf2l\xf3\x12\xda\x15+\x81\xfaX\xb1$\xa8\xb7+&\x85\x17\x81\xaa\xa4\xf5\xf1\xde\x8d\xca\xf2\xf1{?V\x9a\xe6\xf7N\xa8\xe6\xe3s\xaa\xf9\xfa\x82\xd6?oBE\xe6\x97\xdb\x87\xb8 W\x04\xea\xcb\xe6\xfd\xa7\xc9bA\x10\xd2\xfbp\xac)\x90\x81\x01b_5\x0f\xd4\xb4\x92G\x1a\xe7 \x9e\x97o\xa5y\"R\x05^hGI\xf7!\xd3\xe5{\xbb\xbb\xd3O\x9f\xf2\xe9\xfd\xdd\xdd\x1d\xf6\xefl6\xfb\xf4)\xdf\xbd\xcd\x7f\xee\xde\xbe\xc7~\xce\xc8\x1e\xfe\x9c\x91\xbd\x19~3\xc5\x9f{\xbb3\xfet\x97\xf0\x7ffc\xd3\xe0\xcc\x14\xad\x100(\xc9\xa8J\xc7.\xbb\xc1i\xb0\xfb\xa0\xc6\xeb0.\xb2wx\xb1\"\x13J\xa6\x10\x16\xed\xf4\x14c\x8f\xbc\x07\x89\x96\xb0G3\xf0\x94\xf8\x88-\xc5D\xb0\xd9\xc8\xecA\x1cE\xb4\xaf\x11\x1f\xe8\x9e\x864<>\x16\xd9F\x9bX\xa9h\xf1\x84\x14[\x83\x0c\xbb&\x9a\x1aTQP\xb9]\x14\x82M\xaa\xf7yQ\xc4\xbcz\x933\xc4a\xf5f\x86ofUB4\xe9\xb6:\xb7\x1f\xe8\x97\xe7\xce\x83\x96\xe3\x18\xa8\xc8\xcb\xc1Co\x1b\x8e\xeb\xca\xe6\x15\xc6\x0eOT\xe6\x04R\x9c\x80\xf2\xd1V\xc4\xb8\xab\x9b7\xd9\x1f\xb1\x8fJay8\xc6\xec\xaf\x98\x1dA\x95\xfe(\xeb\xf2\xca'\xfe\xed\x07\xb7\xb5\xb3\x1e|_G>\x81\x94\x0f\xeei\x90r\xd0\xc4\xc7\xbd6\xd2!k\xb9pG\xe1\x99\x0e\x15\x17\x98\xb5\xf8&\xe4\xcd\x03\x17\x0b\xb2\xca\xb2\x8c\x8d\xa7s\xc4H\x9dY\x8a\x11\xa8\x15\x03\xe4\x1c\x81\xec-\xd8?sx\x0c+;]F\x9d!\x0f\xd0\xf5\x9b-bAK\xfeX\xa9-6\xc5%n\xb6u\x06C\xd8\x194G\xbd\xe62t\xe3\xfe\xa9\x00C\x08\x07|'\x82\xf4\x8e\xae\xb6\x8dy\x01fx\xfc#\xa9\x0f\x80\xff \xbc\x06\xe8\xf6\xf6\x19<\x82\x956\x11\x00\x1b\xd6\x92\x81ttf\xe0n\x8e\xb1(\xcc\x99\xc6Q\x9c\x01 \xf3\xb1\x89\x13\x18\xc2\x02\x0e \xf3\x8e\x03X\x06p\xc6\x03\x91py\xf7!\xf3\x96\x01\x1c\xe3]\xbe\xfa3\x0d?SK\xe2{b\x92\xae\xd9{'>0\x018\x8aM)\x0b\x10\xa2\x03\xfd\xb3\x93\x94\x84\x9f\x1bO\x9a\xe7\n\xeb\xe8\xd46\n\xb6e;\xd8\x0c\xf0\x93\xc4;\xc5\xd7n\xde\x04oY\xe6\x8c\x9e0\x08Q\xb9-f~\x89K\xa7<\x16\xdf\x18\xdel\xeb\xd1\x06\x050B\x02\xb4\xd0\xb8\x04\xb2\xc8\x08Nb\x89\x0bt\x8c\xfbh\"\x96\xb6\x18\xb8a8\xdf\xba \xda\x13y&N\x10t\xba-~0\xfc_\xff\x9f\xea\x876n\xc8H\xa5\xeas\xa9\xd4_\xdb\x11 /%\x11\xa7\x98&o\xbf\xa0Ml\xdb\xc5\xf0\x08\xd2\x87\xcd\x95C\xd3\xb8GG\xf1\x18\x01\xa7r\x86\xbbZ\xfeOI\xef\xd4\x91\xcc\xdf\x19\xd4y\x83\xe2pkRyQ\x91\xa98^\x9b\xf4\x1e%\x19\xa5\\S\x93\xfc\xa3*\x08\x9f\x1de\x87q\xbe\xe4\x8a\x9f&{\x92\xda\xad\x1db\xe2\x85\xb8VE\x06\xcf\xf7\x85 \xde\xae\xec\x13\xad0\xe6\x9bak.X\xcc\x00z\xec\x0fBz\xfc\xc4\x0d\x9b\xf7\xab\xfd\xe9\x8f\xb4\xcce),\x99\xf2\x15\x06Qch\x10\xeb4\x18h\x9e%m*\x97-\xd2\x8f\x93)aB3\xdek6\x81\xab\x89\xa2w\xb3\x1d\xca\x8d\xd4\xac\x1dZiG\xa3sbk\x9es\xe0\x16\x90A\xc1\xe4\x00\xd2\xfe\x0f\xf9lF\xcaS\xab\xf95\x03\xa3\xc7\x8e\xb7\xb0\x1fe\xb5\xb7Q\x8a\x8d\xccJ\"E\xe2\xa9(\x89\xee\x0f\xfc\xc2X\xdc}\xdf\x1b\x988\xda?''\xabp\xf2\xf9\xe7d\xb1\x9eE\x8b\x05\x0fY\xe9O\xc9*%\x93Z\xedG&O0\x96t\x15\xd29k}4\xc6L\xf1\xf3h1MI,\xbe,~\xb2\xe7e\xb9\xb4)\x99E1\x91\xfb\x0bqr\x91\x84S2\xed\xe9\x14\xab\xa4\xd8a\xfbz\x0e\xa2K\xd1\x19\xda_4\x1e7\x95\xd4\xe6qF\x7f\xc9\x18#\x8716Wk\x08\x83J\x02\x9b\xced\xd4 #\x0c\xea\\t\"\xee\xdf\xd1p\xcb\xb8\xdf\x92~\x94\xb1\xfd4\xe5Q\n\x95\x97\xf8f:\x80\xc8\xcbQ\xe5\xa4\xa7;a\xb7\xb1\xdf\xdd\xbd\xaaZ\x91\xf2\x83\x8d\xd1\x81\xb4]\xb9\xd8\xbe\xb74g\xaa<\xc9\xe5;Z\x87\x17\xa9!\x10\xfa\x05\x91E\x90\x8e\x85;_\xcd\xdf\x84p\x8f\x92H\x16'\xf4\xe2\x9a\xa9\xeb\xf2\xaaX0\xb8_\x97\x818\x16|\x7f\xbf\x15\xc2m\xec\xc4.\xf72\xf0\xb8\x1a\x88\x07\xf1\x17\x9cD\xa1X\xe1\xd2\xe0#H\x1e\xfa<\x85\xe8(\xf2\xc8(\xde\xde\x1e\xfbc\xbdv\x8f\x7f!\x082-h\xebU!\xa0\xd7\xd9\x0d\x1a\xd8.v\xc1^\xfd`\xe3\x8a\x8c;\xdf_\x05^bJii\x18\x8c\xc4{\x07\xc0\x90a\x1f\x12/\xaf\xb8 9M\xae\x97g\x042\x9aF\x13\xaa\xa8\xf6*^X\x0d?\x11\xe9j\x13{\xdf?\xa8\xebF\x94\xe9\x1c7E@&\xbas\x98\xdd\xfb\xbe\xf6\xe5q\xff\x1d \xa7\x8cN\xbe\xa7\xfc@YV_`\x80\xbe\xeb\xf7\x0f\xcfHL\x0f\x97\x11\xa5$mv\x10\xb6\x81Q^%\xd1\x8f2Jb\x92b\xd1M\x8er\x8d\x0ft\x96{\xb1%\xea(\x01\"\xb88\xf6\xee\xef\xfa\x82\x03h\xbe1CA\xfdc\x14\xd3\xfbH\x07\xd9\x9e\xad\x9c\x9f\xcd\x99-85\x1b\xd4\xc0\xb6\xe8G\xf1\x9c\xa4\x11\x15J\xaf\xbb\x1a\xf3\xc0\x8a\xa3\xdd\xdd:\xb1\x06\xa12\xd0 \xd5\xec\xfe\x8am\x9fU\x7fJN\xf2\xd3Er\n\x07\xca\x0f\xaf\x97\xd1\x94\x84\xcb\x9e\x0f\xfbmC\x9f\x06(\xfb\xb3!\xd4w\n\x08\xe1\x88\x81\xb2\x8eK\xe5\xd4\x98X]7\xf9\xb3\x86O\x19\xf7\xd0#i\x9a\xa4=\xc6\xbd.\x92\x8c\xb0?\xa6$\xa3i\xb2f\x7f\xae\xc2\x9c\xdfKI\x96/Iol\x8a\xd6Y\x1a\xd1%\x01\xa1i\x8e\xbd\xbd\x81\xa8a\x81b\xab\xae\xbe\xa0$\x16\x04\xa28\xa3a\x94w\x86\xe5S\xdf\x0f \x13j\x85F\xb6?\x13 OJ\xe5\xb8)\xdaS\xe1!h\x0d\"M\xb0 \xdd\x147i{ym\x8f9q \xa8\xaa\xe2{X\xae\x93^\x89\xc7_\x14xfSJ\x9e\x15\xc5\xdd\xc4\xcb\xacu[*\x15\xce\xc3J\xaa\xc4\xa0N\x04\xdd\xe2\xaa\xd1\xd8\x0f\n\x9d?l\xb3\x86\xab\xd4\x17\xf6\x8b\xaf\x0dJT\xed]RR\xae\xdd\x00\x0e\xb5\x86I\x06\xba\x1c\xeb,zH\xb3\x11\xdf\x9d\xe0\x8aP\xd0\xcf9\xe5Uy&\x85F\xc4KQ\x15\x92\xaa\xdbf\x86\x94\xa6\x19}I\x94\xb8\x83a!\x0c\xd5NK\xcc\x12\\u\xaa\xe8\x1d\xc5g\xe1\"\x9aB\x9c\xc4;\xbc\xd9[\xe2p\x98\xcc\xf3\xf8s\xcf\xb7\xc5\xd3\x18&\"\xb6\xb5\x06n9: \x06\\*A\x02\xee\x15\\L\xc2\xe0\x99\xd7\x86,\x1c\x89\xc4*?\xc6\xc8\x1f\xcf4\xff\xfa\xc7e\xa5\xf9\x9f\xa5j\xf3\xed\xcc#<]\xb1bND\xd8\x10\xa7\xe4#bn\x13\x0c%\xd7\xe3\x06N0e\xa7\xb4z\xe45\xe7\xcb\x16B,\x02\xe7(\xfby\x9c\xcd\xa3\x19\xf5|\x08g\x94\xa4@\xe2)\x10\xc6\xf5\xf7\x10\xd7\xce\x11\xedd:;\x04\x16GU\x97\xb6q\xcb\xc8\x86\x0f\xdf>\xe7M6\x88C^\x1c\x19L\xfa\x8f\x19\xb4 &>\x92\x9b\xf6<\x8d\x84\xae\xbd\x0em!\x85\xcb\xb5:\xa8\x8cw\xc0z{[\xee\x9b\xea3\x9fW\x8fb\xcbP\x1d\x90\x0e\xfb\xea\xaa\x83\xb6\xb5\xda\xa2\x02LH\xb8\xab\xdc\x04n\x92\xa2HV\x8d9,\x99.j\xa4#\x97^\xeeF\xe3\xcf\x15\x1a\xaf\x1b0)\xb8\xa8\x9b7\xe5\x1eVh\xdf\x16\xe1l\xd1\x01\x9b\x02_\xebiHC\xb6\xd4\xa8\xf7b@\xf3v\xf9\x9a:\x12E\x8e\xa4\x05M\x95\xc8\x17\xb36t\x94\xb6\x02\xb8\xff?{\xff\xbe\xdc6\x924\n\xe2\xff\x7fO\x91\xc2o\xc6\x03|\x84h\x92\xba\xd8\xa6M\xeb\x93e\xb9\xc7\xd3\xed\xcbH\xb6\xbb{\xd8\xfa\xa9!\xb2H\xa2\x05\x02l\\(\xab\xc7:\xd1gw\xcf^#\xf6\x01\xf6\x9f=o\xb0O\xb0\xb1\x11\xe7MN\xef\x03\xec+lTV\x15P(T\x01\xa0,\xf7\xec9\xdf\x87\x88nS\xa8B]\xb2\xb2\xb22\xb3\xf2r\xef\x1e\x92F\xc7e\x8bJL\x9a\x16\xfa\xe85\x87\xe7\xd2}C.\xb8\x18\xd4\x9d\x1b\xa9\nU\x17$\x85\x7f\xb8wO\xf7\xba\xe0\xfc\xaaK\xac\x91\x81\xdb\x05\x0c6to\xd7\xf6OO\xf86F\xc3\xe7%\x83\n\xc1\x88\\\x8b\xdf\xe5\n\xe7Y(\xd7\xc9\xffRj\x15u\x1a\x0f3&\x0d vdA@\x11D\xe3\x06.7N\xeb\xb6ix]\x8es\xdf\xc8\xec\x08\xf5P\x19\xd1C\x91\xebN\x1b\xa9\x80.\x02\xd25f\xf1\xa6r\xf3,Hv\\f\xb8\xa9\xc0#\xc8>\xbbl'\x98\x99\xd1qyg\x8eK\x19\xb9\x92SB\xc5\x9fC\x81 \xdfs\x8d'\x0f\x9f\xa3\xd4<\x93 (\x87\xa2z\xc4+]\xf8\xc9[/K\xca.P5]l\xf5\x8b\x94_\n\x86r\xfaT\xd7YBd)\xa9\xd5\x9c\xda\xc91\x95\xcd\xa2\x885\x86z\xb2p\xc3j\x94G_U\xac|\x84\x11<\xdcy\xf8p\xbf\xf7\xd0\xa4/95\xa2n\xae>\x7f2b\xfe\x8dU:N\xf2#\xbb\x87d\xb6B\x9dS\xa6\xf0=(\x1f\x08\xd2\xa9\x9a\x93\xe6\x05\xf1\xa6]z\x08\x88\xb2aQm\x88a%\x80(\x07\x1ac\xa2U\x8dA3!\xcb'\xf6t\x04\x1fQ K\xff\xa5\x9dloSY\xeb\x13\x1d2F\xf7*\xfd5(\xfd\xb5[\xfa\xeba\xf9\xbb}\x17\xd2NG\x9bk\xe0\x86\x9d3\x08U \x0e\xe8!\x92CS\x9e9\xa9h\x0cz\x98\x9f\xb9\xd59}\xac\x87Bn(\xd7H\x8f\xaa\xbd\xf7\xe9\xe9\xa9*+(\xd6/l\x8b\xbe\x16\xef,\xb7XtG\xf7\x0d\x9bI\xce \xb0|\x1f\xef\xfc\xc9\xa5}\xc8#/\x1eV\xdceM\xf3<\xd4\xcf\x93\x0f \xc4$-\xe4.\x18\xc3!\xbf{\xd56\xa0\xcb\x1b\xe3n!%}\x08\xb2\xe0\xaa\x86\x04\x9d\x8e\xf2I\xfe\xa4u`2u\xfc\x93\xb1\xe3\xd2\x05Ln5FY,\xc1z2\x86K\xda\x7f[\xa4\xe0!I\xc10\xea\xf6\xd7\xc2\xb6\x96\xde\xf5\x05\xa1\xab\x86\xf3@\xf5B\xcf\x92\xd94\x17m\xfb\x8a\xce\x9d\xc7Ny0\x0d\xc0\x1a\xa9\x89\xbfL@\xb84\xaer\xae/\xa1\xe0M\xfd\xc9\xa5n\x9c\xad\xfax\xd9\xbc\xc2\x02\xdb\x99\xe6M\xd7\x13\xe2\xbb^1G\xaa\xca\xb4\x1c!Q\xb3\xcd\xd1\xd1\x05u\xc9\xa4\xe5\xdclJ\xaf>\x97\x08 \x8a-l\x8b\x8e\xa7\xb4\xad\x1f\x97\x07\x99\xa7R\xe6\xe3s\x1e+\x02\x8fi\x84\xef\x9a\x0e!\xe5\xe89`]!u\xac0J\xf9\x91\"\xc4\xcf!l\xa5\xec6\xf5i\xa9\x0d\xbb\xa4\xc0\x91\x0f\xa3\x9f\"?\xb4-\xbc\x13\xe9\xf3\x9eyI\xcd\xc1%\x0b\x1a\xdc\x9f\x92\x14>\xb1EQ@\xbc\xd8F\xd9&\xd4X\x94\xd6\xa9Z\x0c\x1a\x8a\x94\xed]\xf5\x00=\x00Lu$\x97H\x91B\\\xb9@[-u\xf2,\xc8\x1c\x06\x9a.\x88\x04\xe5p\x93\xf0\x96\x05\xc5\xa2\xad\xea/\"\xc4\x13Wmt\xd5\x07\xef1qlf\x15\\\n\xdb#\xf0\x8dDI<\x88\xed\x8f\x81\xc5r\xa4\xf4\xa46\xf7\x14\x08uf>\x80\xfa\x81\x82\xb8\x91\x81\xa7\x10\x15p\x8c\x8a\x13\xbf!\xb2\xb2?\x03;c\xd6I\xc5\xe7>\x95\x8e#\x18\xf2\x1f\xe5\x85f\x9b\xc7\xc6\xe9g\xb5\xa6\x96\xe2\xa9\xb4ow:\xb1\xcb\xc1\x81\xab\xbe`Zf\xfefX\xbc!\xdd\xd4\xf3\x03\xae\xe7\xe7\x02\xbc\xa8\xecr\x08A1\xc4\xcc\xa4\x91\x93\x1f\xb3\x85\xa7xn:\x1d}xc0jFA\xb2m\x17\x13\xddFw\xa0\xaam\x0e\x085)q6\x89\xab*p|\xd2\xf5\x82 \x9a\xbc\x0f\x13oF\xdaE\xe1m\xb1+(\xca\xd7\x98\xc5\xc6l\xa7N\xa2\xd55\xaa\xde\x04\xe7c\x97\x83\xe4\x8b\xe0\xbc\x1eSaS\x9c\xf7k\xc2]\xb8M\xc1\x974\xb9\xee\xf0+~\xde\xb9\xc5 K\x19E\xc3ev\xb9{\x13\x9bp\xf4\xb9\x8c\x0c\xbb\xde\xe1\x13\x7f\n=\xd95\x93)\x98\xffd\x910\x17Ql\xc7\x024\xa5\x9dB\x14\xe2\x9d\x02Y\xae\xd2k`J\xe8?i\xe6Bd%9\x13\x02\xe4\xfb\x17\x89\xfd\x7f\xabMrb\x8c\x1dj\xd6\\)=rU\xa1\x98$\xb3\xd2,_V\xf7\\\xce\xcbVD:\x9b\xce\xdej9\xa6\x93v\"I\x8fk\xbfr\xc9\x84\xd9\x93C\xd8\xe9\xe8/\xb20\x1a\xfa8\xe4vq\xc5\xbd\xaaQY\xb6\xadJ\x0f\xf2_\xb2B'f{\xb2^C\xc0\xa5 \x8b\x9d\x9d)\x8c`\xe5\xc5 y\x19\xa2[J_\x17\"e]\xf2;+\xe1\xa0\x9e\x12b\xa43=z\xf2\xf5\xe3\xca\x0d\x9dQ@N\xdd\x98\xffyE\x93-a\xf8\xa8\"\xd3}\xfa$\xd4\x0c\xc5\x8d5\x9f\xf1\x10*\xe2;k\xc7\xcd?qku@G\xec\x92\x18\x86pl\xf3\xcblJ\x10M\xf3\xe4\x04z$TP\x8e\xd4\x9ac`\xfc\xef\xdd\x13\xbd\x98\xdaF>\x99\xa5\x13-\x83\xc6\x88>\x0b\xdb\xa2\xf5\n%\x01\xe6\x15\x11#$\xd2N\"\xd2IS\x95\x97q\xfc\x0b\xdb\xe2u\x02\x92$\x90.\xbc\x10\xaeh\x8d\xa5\x17_Zl\\\xa8\\\x15`\xc3f\x85hw \xd6\x82\xfe\x11\xe1\x95\x19\xde!\xf8l\xe1\x91\xbf\xe3R\xf94\xc2\x01[\x8e+}_R\xa9pMQ\x05\x80:\x8dRI\xe3\xa8*\xd5\x1c\xb9\xc9\xbe\xab\x08\xc2l\x05C\\A\xbe*lic~\xc4\xf7\xe0 \x17\xf0\x86\xfc\x88<0\xe8\xb5\xd0\x0e\xc7\x91u\x7f\xdb\xa8\xec\xd4\xce\"\x07\xa0aFa\xb1\x95$\x85\x07\xc7\x1f1T\xd4\x8d\xe7\xd7(\xa5\xbb\xa8\xb8\x92w\\Q\x10\x9f\xb7\"(R\xc3\x9a\x0bM\x06q\x07\xfc\x04\xc2(\x05\x7f\xb9\n\xc8\x92\x84)\xa9\xd2a\xe5\x06\xc2_\x91\xd67\x10\xb5\x01\xd5\xa2\xb6\x97\x13\xc9\x95\x8f\xae\xc6\x91d8eb\xad&^B\xa07\xd4\x96\x01:\xe0\x0b{\xac\x1af\x0f\x99 }1\xb6\xdfo\xd3\xfe\x98\xfft!\xad\xc9\x13S\xd3\x15\xbfOi\xec\x8b] 5^wI_0\xd3\xb3\x0e\x95n\xe9\xce\xc7%\xc5 \xa0\xa3?N!Z\xa5\xc9\xe8\x8f?Yn\xa9\xb6\x9e\x1f\xa3\x8b\x8c^([\xcc\x90\xb0\xcf\x15r$\x9c\"YJ\xf9\x1dP\x92N\xa3,U\xde\x908\xa6\x92;\x0c\xe1\\\xb9%\x80\xb2\xc3\xb5\xce\x88X<\x0b\xdb\x8a\xc2,\xa4\x03\xb5\xd8m\x92\x08\x88\xca.\xdf\x99\x1e%\xee.\xbc\xe4=\xd6b7\xd8\xa5\x17\x8c\x06,lk\x12\x10/\xccVB\xa7\xb6\x8c\xd6\xdc\xf6\x8d\xc4vn\x1e:\xd7\x96\xce\xfc\xd0O\x16\x96\x0bKm\xf14\xf6\xfc\xd0r!\xd0\x96\x8a\xfdy\xad-\xe5\xb3saB\x89G\xf5\xe3\x90\x92\xeaYM\xd9\xb9\xb6\x8cS\x9b\xb5\xe3\xa2\x85/\xde\x82E\xb2\x96\x10\xaf\xf5\xcf\xafb?-]\xbcn\xa9/\x91\x08\xe6\x9f\x04\xfa\xa8\xf8\xe6\xf5\x9d\x19\xaf\xa2qm\x913d\x86{\xd3\xc68P\x808^2\x18\x91x_\xe4\x11\xc2n\x14N\x88\x00\x0dZ\xbeu\xa3\xb0\x04e=\x9e\x07\x8d\x14\x174v\x15Mrz;\x01B<|\xb3\xbe \x9fs|\x92\xd5\xba\x8e\xa2\xe5\xc5\xf3\xa7\xf8{{\xbb8\xcf\xca\xb58\xfc\x8c+\x8cQ1m\x886~(h\xc1\x7fc\xeb\x84-\x06\xe3b\x17\xe8A\x8cx\xa8\xd1-\xac\xb9+9-3#\xd2\xda\x9c\xab\x171\x89M\xd0\x05\xa1\x12\xe7\xd4*\xcd\xadq(\xfa\xb2\x83\xdd\xees\xa9\\\"\x97\xe8}\xc4\x89\xbb\xf0<.Ux\n}Z\x89\x87_=\xb1\x0b\xfa\xcf\xe3t\xae\x04\x135\xf3\x82\x84\x00v\x0b1IVQ\x98\x10\x17\x84\xady\xa8^\xc0\x96\x96\xb8\xa6\xb4\xd3\xe1\x93C.\xa4\x8b\xedm\xba\x1b\xaf\x1b\x80(H\x15q\\8\xb7\x1b\xa9\x19C8\x86`\xec=;\x17\x14\xc6D\x17L\xb1f\x90s\xe3\xb6j \xcc\xe7Z\nb\xeehYO\x9bx\xdb\x8d\xc7\xc5\xa6\xdd\x9e\xd7u[\x1cva\x97\xfdnw\xf6\x0by\x96\xed\xc4\x9c\xf8k\xbbi{;\x00P T%\x1b\xfb\xaeb\xb2\"\xe1T\x00\xa5\x08P\xae\x96\xb0h\xcd5*\xf4\xee9\x9a\xf0%\x0cy\xf8\x1fcr\x06\x07\x90\xd9\xf2\x0b\xf4n\x92\xfe.[d\x95>\x1d\xc18tK\xaf\xce\xb0\x8a\x08\x1e\xad'x\x12*\x8b\x03\x9b\x1d(e\xfe\x80\xbdS\xb8\x02\x86\xf4\xfc\x9c 1f\xa1 \xb4\xfcn\x0fY\xb1\xe2F.\xe4\xb7y\xb6S\xb9\xd4\xaf\x18\xc1T\x18\xf3Z\x9d\xd5&*\x03\xf3\xda\x17L\xd4P\xbdL\x15\x8f\xc6\xc9\xa5\x90\xc3I\x89\xa3\x17\xd8\xa1\x0d_O?\xea\xd7|T0\x97\xbc\x9c\x07\xccfV\x1cBb\xe4exT\x96\x1d3H\xc5+\xa3t\n\xf6\xb95\xbcX\xc4\x9c]Hy\xc4YnH\xaf\x1f\xf8Vmp\xd2\xb8\x18\x98Y\x83\xedCy\xe6\xfa\xcd\xb2\xe9\xac\xf4\xad\xe4\x8a4\x16\xe7\x1a\"x\x02\xfec\x88:\x1d\x07\xe2qtf\x82A\xad\xc2\xb6b8\x04Z2\xb5\xe61\xdcNlR\x9c\x9f5:8D\x89LZl\xfeY\x97eg\xb03\x17\x9d\x97K\x80\xd8F\xc9\xa7\x8aM\x9c\xf9\x11 \xe4\xbf\xc6\xbd3i\xf7\x9a\x16\xbensF\x95\x1b\xd7:\x899)}Y\xb8Ap\xc3\x0d=\x861\x8a\xce8\x13'gm\xcc\x06h\xb9\xeaA\x10\x18\x8dRY\x84,)lVD\xfb\xf5\xb8\xdcJ\xa8\x07\xbc+*+\x91c\x8d\xcb\x11\xdd\xb9\xba\xf7\xecB\xa4\xa2\xc9\x89\x0d\x0eM\xb1\xa4\xec\x8a%}\xceq\xae<\x94\x04\x85K\xbe\xa6\x9b\x1c\xabu\xeb\xefM\xf3\x93\x0eF\nf\xb8\x8a\xaa\x18m;Z\xc4cL\xdb\x02:?s\x95\xa3\xa68eR\x85\xddo\xc4T\xe0f)eC\x13a|T1?)\xdf@\xbc4GP.\xa2\x9c\xeb\xec\x0c\x15=\x14\xe5n\x9b\x00U\xa8Z\xe9.b\x1c6\xf0\xc92\x1dG\xcd\x16q\xdc\x96\xfb\x08\x0fnd\xde\x0d\x16\x94\xca9R(\xe6\xf8W-\xa6{\x15{\xab\x8dN\xf7\x9a\x1b\x80\xb6g\x7fl8\"\xf2\xe3\xc1\x07?\xe4\xa2\x1d\xd7B4\x89\xbd\x94\x9c,l\x8b\xcefE\xa6\xc0\x85\xfb\xb0\xec/!t\xf1\xf5\x92s\xca,\x1f\xda\xb9A\xf1\xb3[\xbe>0i\xcd\xc0x\x8dI$S\xed*\xf2\xe6\x9a\x04\xce[\xe7\xb00&\x1e\x94!!\x84\xd3\x12(l\xbf4G&\xa7\xfa\x14]\xb6B\xc5o$W*\xa3\xa6^\xb2\xde\xf7\x99Ho\xab\x1f`=a\x95\"\xc4~\x9c\x9f\xef0\xa2+t\xe3\xb9 \xa9\xdb\xb2\x0e\xdaLJ>S\x14\xbb\xc6\xfe\x19\x94\xe3\xd2JR\x01/\xb4EE \xa9\x9b\xdc\xed\x1b\xd1K\xaa\x9bR\xe6\x9f\x87\x81\xadM\xe5\x07\x065\x86\xaf\xbb.\xd7qF\xf3\xfc\x8a\x11\x19$D\x82\xf98:\x93vz\xf7\xc2\x0f\xa7\x9c\xba\xd1\xa2\x1a\x8f\x9cT\xf6\xa6l\x86\x8c\x84B\xe7\xfc\xfe\x908\xc2\xfb;\x16\x14\xa7\x10#\xaa\x13\xd5\xd3\x9e6\xee&\x82\x84\x94|\xbb\x9b\xa3\xd8hL\xaa6rM\xd1Q\xd8\xd2\xc5Qu\x8e\xe5\xd9\xa1\xdf\xc7\xf9,\x8e\x96\xf4T\x86\x11\xbc\xfb\xa7\xa2\xac\x1c1\xdb\xc50\xd8\xed\x02g\x97bpW\xa3M\xb4iB\x1fNc]\x84\xbaz\xa4\x8dI\xeakO\xea\x1a%\xcb\x8dv\xd0\xe5\xcf\xb9\x1bK\x0b\xbb\xa3[_\xf5@\x93\x1bQMd\x01\xfc\xac\xa2\x9c\xd6\xbc.Z3\xee9t\xb2\xce\x98\x9b\xde\x01\xfa\xe0\x14\xc6\x9b\xed\xfbA8\x97\xb8\xd9\x9c\xe7\xf1\x85\xb8 |,\xd0Z\xc7\x00\x91F\xcf&\xe9\xde\xb420\xbb\x16\x02\xe5\x8f\xf9k;\x8f(\xee\xb6Ppo\xf1$\\\x07\x94-\x97'\x18\xb2\xd9\x85\xbaA\xa9/\xcb\xb0\xc2A\xe1\xed+\x9e\xccZu\x96A\xcc*\xfd\x99;d5\xd0\x92[\xc3\xbd\xafg\xef\xe2j\xf4\x85\x8a\x0b\xcd\xb4\xb6\x05%\xaa\xc3\xe7,o_\xfb\xadf\x04\x95ru\n\xe5\nL\x95U\xdf\x86\xb2\xa8\xaaO\x95B~>?\xf6\x9f\xec\xa4\xc8\xb0\x12#H\x84\xec\xd4\x9a\xca\xe1\xf0\x13\x12\xcch\x15\xfc\xf7\xd3'\xb8\xf2\xc3itU\xa5/\xbe>\xb272\x12&_&}\x00\x7f\xc81\xcd\x9f\x16\xaeS\xdds4\xc4~\x816\xc8\x06\xf0\x00\xf2\x9a I\xdf\xf9K\x12eiK)'$W\x10\xd9>;\xc0\x8a\xaf1\x1cB\xc1\xff\xb8\x80\x03\xe0\x85\x15\xb5\x05\xf6\xfb2LI\xbc\xf6\x82[v,>\xd7\xf7,J5]\xcb#C\xfdK\xe9\x83F\xf1\x873\xf9\xa8\x88\xad&\x96\x8fJ\xda\xd2\x98\xcc\x94\xec/\xec\x8d<_\xe5#l\xb7 $\xa55f\x10\x89\xdd\x1c\x0f4s&a\x1c\x05A\x1b\xfd\x90\x0c\x1d;\xa5\xcd\x05\x84\xff\xf9r\x8a\xd2\x87\xfc\xaa\x8a_\xb4\xb7,\xd4\xf4w'\x9d\xa9\xd6p\xb4\xb7s\x84\xf3\xe1$\xf5\xd7\xe8'\xda\xf5\xc4\xcf\xcf\xe9\\\x7f?\xc8/R\xa5\xaa\x1a\x8dV\x91bQm\x15FPl\x99\xe6\\ri\xf7<\n\xc5\xe4\xd9\x9dD\xfe\xb7\xee\xb2G\xe3q\xe5bD\xab}G\xec\xb9\xe5\x92L}\x16\x9b\xa5\x99\x84\x95\xbfP\xb2e\xb2\x01\xa95(\x0e\xe6\xac\x8b\\\x98\xef\xbc\x0d\x87\xa0|\xa3\x1dD\xb5Ni\x18\xe5\xe2\xe2|\xb8M\xde\x9a&\xde\xd9\x14P\xcdGU\xa2\x9f\xc8Q\x88\xea\xd1S\xd8#\xe1\x8d\x82eA\x07R~\xab\x99F\xdfDW,W\x8em\xb4\xfeF\x13\"kA>Zz\xd3\x1eV\x8eq\x90\x1a*l\xd7\xd7\xf0\x92\x89\xef\xd7\xd6\xb8\xf0C/\xbe\xae\xaf\xe2%d\x7f\xb7~$\x93d\xd0Ta\xbb\xa1F:\xeb\xef\x07\xa4\xa9\xcevc\xa5\xd8\xbb2\x94\x83\xe4\x9fm\xc8+\xd9hq\x95\xfbwWwxys\x1b\xf2\xfc\xe8\x18\x19Ee+\x90\x0b\xf7\x07i\xeb\x07.(`3\xff.\xae\xa3\xf8T\x18\x9e5\\\x03\x91\xc7\x8f\x9db`u\xca\x97F\xdc\x85V\xf8+\x9e\x16\x83\x846h\x08\xadP\x11Z\xa2#\xb4EI\xf1H\xd3\xc0\xdaM3 \xbc\xd4\x0f\xfb\x8d\xbd\xd7\xee^\xf1\x88\xbey\x9bM]\xd7nwhEZ\xa0\x05\x8d\x13\x8fP\xe9\x98\x87\xd5\xb8'A8X\xd4\x87\xd8\x12\x0f\xa5\xd96'\xdaez\xcdbQl\xf5\xb4\x9f\xeb4\x84\xba{I\xbc/\x13\xd12\xb6\xca\xc1\xc5\xed\xd213\x1a\xf1X\x85,\xbdQ\xd5'\xc4z\x1f^\x86\xd1U\x08\x82\n\x0c\x81\x0d\xdb\xa8\xc7`\x07l\x99\x12\x15a\x1d\xf2\xb8t:\x8e\xab\x05\xdac#)\xf9(\x92\xc6\xb06)\xe74a\xa0\xd3Dh\x04\xb3\x89k#\xa9\xc0\x0ef~\x10|\xe3\xa1\x96\xce\xbb}/\xb5X-\xcfkV\x9aW\xc0z\xdc\xd9\xa8\xc7Z\x84\x95U\x98\xcc\xfek\x04+\x96f\xdc\x96:^\x98$g\x10\xe3\x0d\xbc$}MP\xce\x16\x81\x11\xe9\xabwQ\x8a\x82\x92\xfc\xeeh\xe11\x8f:\xd9\x1b\xb0\xa4\x0c\xcc\x7f\xe6gUV\x13\xd6\xfa\xc9\x08\xfa\x83\x07\"c\x03<}\n{0\x1a\xc1>\x1c\xc0@\xbc\xd9\xa5o\xfa\xbbp\x00;\xe2\xd5\x0e}\xb5\xd3\x83\x03\xd8\x15\xaf\xf6\xe9\xab\x01\x1c\xc0v\x1f\x86\xb0=\xa8\x1d\x92g8>\x852\xb0\x98\xfev\x19DU!\x7f\x13\x07h\xb4;\x19<\xa4{\xd9\xee?\x1a\xc0=L\x0f\xebH\xb6L\xe5\xa5\xb0\xfe\x9f\xff\xeb\xff4PY\xf40*\xaas{A\xc91\xac_w\xb4\xea\x06\xd27\x0d\xa4_;\x10\xd0\x0df\xa0\x0c\x06\xffV;\x1c\x98:\x1c\xf0\x0e\xdb\x13O\xae\x0f}\xacC2I\x90\x08\xd1\xbd~\xa8`\xfd\x13\xc9\xd7\x0c\xa3y\xa1Wf \xe5qY\xe5}@?t\x94}\x91\xa7l+\xf3[nuS\xb1\xa8`\xb5\x1d\x89\xcb4y?\xe7#\xde\x96\x02\xa0\xd5\xef\xbdD\xab\x01\xa0\xebe\xa7\x85'\x10q0!\xf9\x08\x1dWjt\xf2\xc5\x0cs\xf2n\xb6\"\xa9\x0f\x03\x80\x97\x91\x93\x85\x17\x1fESr\x98\xda\x92\x07\xac\x1aWZ<\xb4\xd1\x98J\xdd{{\x83G\xfb\x80f\xf9OF\xb0\xb7\xbf\xd3\x7fT2\xf8Rp\xa9B\xd0v\x95\x85\xe3)\x9a\xc7\x12D\x06gj\x9d~\xa5N\xff\xcc\x85\xb0pS\xd7\xe6\xd9\xae\xbc\xd1\x9bxh\x89\xa32\x93\xbef&\x83\xe6\x99\xf41\xe5\x85v\xe1\n4C\xa8\xd7\"R]\xaa:\x90\xef\xc3\x0f\xa4\x03\x89]~X\n\xe5@jQ\xdaH\x0d\xf7@fr\\\xc3\xbdtL\x9bS\x82@\xaf\x1a\x0eL\xb7\x12\xa4\x1623\xed\x16\x13\xe3\xafl\xb3\x1d-\x91\xeaq_\x93\x83\xd2ZqV\x83\xbb\x9d\xd9*F\xec\xc06\xde\x94\xa8X\xb1#\xec\xd1B\xb1\x1a\xb5\xf8Qj\xfa\xb3\xf6\x83\xe3\x1a\x86_\xc2\xb4\xb0\x81f\x05w\x87j\xda\xadtP\x8b\x1d\xf9\xa0{.\x02X\xc1\xd4a\x036\xac\xcc\xcc\x8e\xe1|\xa8\x07\xc6\xa2\x86yj\x82\x85\xd4\xb0\xf8E\xca\xd1\xdcX\xc6\xc7\xa8d\x1b\xe4\xa7\xf5\xc2\x7faq\x9b\x9fA\xb9`\xa8\x80\x1f\x97\xcdU\xdd\x9e[\xed\x7f\xbfHB\x87\x9e\x989k&\x98x&\xe7\x18:\x06\xd9\xba\xf12u\xbd\x84\x02>\x1e}\xae\x9a\xdeJ4\xb2\xbd\x8d\x83\xa1\xab\xb7=`bv\xdd\xc0\x90\xb1\x92F\xe6\xb4\x1e\xc3\xe0\xf7\x1f\x03o\x0bC\xef\x8cD\xca\xbc\xf2\xa8v\xf4\xa3\x12\x9d\x97\xb7\x8f\xd9\xb0\x98\xe9 \xcb[\xbeJ\x15E\xb8~\xf5\xeb\xca\xf9\x16V\xa9\x8c\x1c\x9e\x01\xb6\xc1\x0e+\x94[\xbf1\xb4,x\x8f\xf9M\xeb\x86FKL\x1bFR/\xd4S\xcf\xf2v|\xa2!\xa4\xfaq\xd5\xf3Bw*\xa0(+p\xeb\xe1\x14bLy\xd2\x92\x04\xa3\x9cR\xb7\xba\x99)e?/^\x17\x176\x035y\x1f\xcfq\xae\xcf\xcb\xac\xd1\xae#\n#\x04J\xd9T\xca9\x13\xa2j\xda\xf0\x92\xc9}n\x8b\x91\xc6^\x98\xcc\xa2x\xc9\x8c1tn1\x18\x17\xfc\x9d\xa8\xd7\xc2r\nT\xaeY\xe9E/T\x85\xdd\xbcV\xbd\x1fG!\xb5\xe1y3\xb90\x0bi[qY\x1c3\x06\x0e`\xcc\x06\x85\xd0\x857\xb9\x14qj\x96Y\x90\xfa\xab\x80@\xea/Ib\x8cw/\x06\xb2\xc8\xc2\xcb\xdcG%\x1f]\xf1\x86\xa7\xec*L\xadx\x1aWW\x93O[<\xe2\x80apl\xe1}\xe0+\x86;\xb6_ k.\xecc\xe1 \xf8\x9a\xa8\x1bEW\xb6Z\\\xe9\xf1\xa6\xb0\x01\xd58\xdd\xd1\x8e%\xc4\xd1\xd9H\xcak\xae\xaf\xc1\xc1\xc8\x82]\x98\x8a)\xe8kk\x14\xdafZ\xa9|\\\xe8\xad\x97t\x0154\xd5\xa4P\x1e\xb5\x89E\xf2\x89J\x06O\xc5\xbb\x91\\\xc3\x9cgd\x16d\xc9Bj\x80\xfd=\x12%\xc2\xe4\x1e\x0d\xb6W1\xc9\x1d\xf5\xb2&\xbd\xa8\x8e\x9d\x12\xbe\x18e<\xd3\x8fL\x1a\xcd\x81\xfcW)g\x9a\x96\x19\xf3r\xdaZ^\x14\xcaDz\x9c\\\x15\xfb\xa7~\x1e\x9e\x89\xeb+\xdd\xa4hLH\xabLB)\xb1`Z\xc4\xba\xaf\x84 \x10\xe7e\xe5\x9e\xe3\xc8\x0b\x02\xba\x0d\x8bE\x9eF!\x81\xab\x05 \xe1*\xcf\xa8\xb45\x82\x9e\xa5\xe9?U\x89f\x89:n\xd8]\x92\xfaAP\xdajj\x979d4\xbe\x00\x85\xcc\xe6W\xf2\xaa\xb9\xd2;;b\xdcJ\xb4adw\x99@\xab\x93.Q\x90\xdc\xe9\xa9\xdc~\xc5\x97\xac\x18yy0\xa5\xfd\xd6$(T\x00\\|m\x080c\xec\xb6*\xc9\xea\xbb,{\x9a\xd5\x9d\x99(\x9b\xc8\x07\x0c\x85J\xe9\x10J\xf37\xd2m;qa+V\x10I/\x1e\xb5>r\xecXY#<_\xbe\xd0\x89sc\x04\xb1\xeaYP\x7f\xa9R\x0b\xdb\xdc\xe7\x84\xc8\x10\xc5[\x04\x01p\x16B\xb8\xc4\xae`\x0c&\x95\x81\xe9U\xb8,[n\xd4\x15M\x16\xfc/\xe9\x96\xb9-f@\\\xdd\x06=#$Z\xe6i\x90\xf93\x95Q\xac\xb6\xa6l\xb1z{\x0c\x96{=\xe4D\x969\x90\xab\xc4]!.\xb7b\xb5%\x9eZ\x97\x89\x17sH\xcaBQ\x14\x1f{\x93E\xb9\xa2\x94\xe2|\x12\x93\x12.\xb4K\x8b+\xf0*bDSKU\xb9\x0din3\xda\x04@Lgz\xef\xde\x06\x8c\xb6\x9e\x15DK\x97\x10\xbd\xd9\x1c \x18\x04\x10\xd2qxV\xa9|c\xf3\xb4\xb8\x18\xc9X]+\xb7\xa4h\x84\xdb.\x97\x16\x9e\x0e\xfc\xfd3\x9a\x940`\xc7iZ93\xcd\xf5\xf5\xab\x96\xbc\xf6^\xdb\x98X\x16\x95\x18\x84\xa9/\xf0\xe2\xee\xde=\xae\xad\xd8\xc6\xc4\x0c>\x86\xb6\x1e\xe6\x8e\x95x#\xd4\x9c\x1d\xb9\xd5\x1c\xcb\xfe7\xbb\x0f\x06\x8eM\x87\xc4\x91\xd6K\x12\x7f\x1e\xc2\x10\x8bv>\xd7\xa2\xd0\x05\xdf\xc5Tr.x.\xcf\xe6:P\x13\xa4N\x9aH\x0b\xe8\xee+\xe8#\xe7\xcc\x8f\xaf\x95\xaf\xf4\xaeY\x13\x17x\x08@\xad\x07\xd6$\ng\xfe<\xab\xc9$.\x985\xbdl\xd1\xe4\xc1\xb5\xf6\x82\x8c\x0cA1\x02\x96\xd6\x15&^n>V\x9cN\xec\xcec\"]\xe5\xc6\x15\xc9\xba~\xe8\xe6a\x97\x87\\\x8c\x84\xc55\xd4B\xd1\xdd8\xa12\xa5h J\xa6\xb9*k\xc4s\x06\xa60\xa4\x87>B\x86\xb1\x14\xe8\xa7U\xacR,_\xaa\xe0m\x11\xcfn\xfc\xe8\xa1\xe3b:\xd4\xf1\x19\xcbl\xdd@U]\x9d\x02\x9cr>\xde8=\xcb\x99y\xfaG\xb9\n\x92=\x82\xfd<\x86t{\xfb\xb1#|\\-\xcf\x82\x0e\xd8\x9dN\xe8\x14\x1a\xa8\x9d}U\xae\x97\xf4(\xc2i\xc2\xb6f!K\x98\x8bE\xb9\xc4a\xd3\x06 \x0fq\xef\x82\xe5@\x87\xfe\xef\xef\xa2\x8dY(\xbc5\xf1\xec,\xdc\x06\x1e\xc3\xcd\xe32\xcb\xd8z\x8d4\x14\x1f\xe5\x1b\xc3\x9a\x15b\x8f\xc2\xe7\xe0\xa9E\x9c\x8a\xea\xa1\xba7\xe9\x93\xd9\xe8\nU\xde z\xf4\x07\xdd\xed\xf2\xcd\xe7\x12'&r\xe8\xb2\xad\xeb\x91\xbeTM:\xe7\xe7$}s\x15\x8aj\xcfI2\x89\xfdU\x1a)\xf6\xd3\x99\xe9\x83\xd7\xdeR\x0dh\xe2\x99\xea\x9e^//\xa2 iq2i\xd7\x98\x91`~4\xc76Q\xf1\x14\xe5D\xb9\x06\x86\x18\xc8\xec\xc4\x11\xccN!~kC\x0d\xeaW\x1a\x9b\xb6\x99\x87M\xc4\xc2\x14j\x14?\xf2\xd2k\x9b@\xee\xb2\xfa]\x19\x81L\xaa\x0e\x0f0\x82\xdb\x7fY3\x91\xed{r ]/g\xffS\xb9\x95\xcf\xdc\x15}\x1d\xff\x1b\xda\x0fUUs\xa4w\x03\xa3\xdc\xe9mq\x94\x9ek\x9a,xt\xfb\xe4\xc4n<8\xd3B!Fj\x85\x0b$w\xc4\xd8\x10O\xb7\x1a\xe18>C\x07'\xe1H\x91\xa1<\"\xbe\xa8\xacH\xd8\x00g\xb9\x8fv\xfc>\x1f\xfa\xd6\x16W\xf6\xb1\xf0\x03\xe5\x14r\x9f>\x19\xb4d\xc8\xd5\x9b\xf4\x83\x0b\xd24\xdaVX\xa1\xe7\xa3\x88\x0b\xd6\xf99I^E\xd3\x0c\x0dN\xd4\xa5D>G\x16+Yt!/N\xc8\xf7\xde28BnE\x93\x16\x7f]D\x88\x0e\xed\xbdAO\x83q\xc8\xfc\xb0\x80\x0dq\xb7\x18\x04\x1c@\x0cC\xcd\"\x0bSS5\\p\xd1\xa9n`\xb5\xa8\xaa'\x0f|-#\x91\xe3\xaf\x9bx3\xf2M\xe4M+ \xacjID\xce3\xb1\xd0\xc8q|\x88\x03I\xba!\xb9zG\x89@x\x1c\xc7v\xa1IB*\xad\x1c\x97\x1bz\x916\x11\x84\x9d\x87\x06q\x88\x8e\"\xb6\xcbs\xf0\xc3I\x90M\xc9\x10\xc6\xa1=\xe8\xed8g\x12\x12\xfcC\x07\xd3\x1f\x0c\x9c3\x85\xb0-W\x81?\xf1S,\xdf\x1b<\xc0P\x06{\x83\x87\xfc\xdfG\xec\xdf\x9d\xde\x1dM\xe2N7S\x10y\xcc[\x99t\xdf\xbd\xf9\xea\xabo\x8e\xcf\x8f\xde\xbc~\xf1\xf2\xabS|\xf5\xfe\xed\xf3\xc3w\xf2\xab\xda\x9d6\xe8\xed\xfdN;-[M\xbd\xaa\xf6\xd2@\x165\x07\xf3\xf5\x8a\x0c!\xab\x9e\x10+\xef\x9a\x02d\x08v\xcf-\xb6\xa0c\xff\xfdF\xd5\xe2\x02(\x9a?\xd2M\xa3\xf9<\xa87\x0ej\x18\x91&\xabJ>\xa2\xd4\xd4uy12\xfd\xbaYL\xb2K\xce\x19\xe4\xac*\xaf\xa8Y\xff\xfc#63K^\x81\x1cod\xad\x89n\xaeU\xad\n|\x1eA!2\x12\x8dJ\x0ef%l\xec\xef\xa9\x0c\xc8\x97\xc2F^\xa7\x85b'\xa7\xca~\xc8\xe2:\x94\xd1\x8c}U\x1d\x04\xdf\xbca\x83\xae@\xa3i\xd8H\x17\xa1\x18\xac\xa0\xa9\x16\x8b\xde\x19\xba\x9br\x87\x94\x1a\x10\xf9\x1c\x18\xdeQy\xa1\x8f\xb7\">\xdd\xd1\xd6%\xb9N\x90\x91&\xdc\xa3\xc2\xc2\x1d\\\xbc\xc3\xe47C\x16\x14w\x1c\x9e\x9d\x95t.\xa22\xdeZ\x1e\ny\x05%\x0c\x0e\xe9\xd8f]\xa0\x91\x86T\x1d\xc3\xd0\xa7\xb1O\xff\xd2\xe2O\xa3haT}7~\xb9\xd1\x01\xcc \x9a&\x18\xde4\n))\xda2\x1ew\xb7\x1c\x9d:4\xbf\x1cJyK\x96\x87\x98\x90\xfc\xeezE8o\x0c\x1d\xb0\xc4\xed\xaa\x977\xbae\xba\xafn\x18\xec\x86\x9b\xf8\x91~\x0f\xef\xedj\xb7\xf0#\x95\x05\xcbP\x18.\x1a\x0e\xed\xc1\xbecg\x94\xf2\xec;\xb6\xe5\xa7$\xf6\xd2(\xa6\xe8\xd3t\x94\xa7r\xf0\xb2\x1b\xa7F;\xa8\xbb\xba.h&\x8c \xa6#\xa8\xe2EH>\xa6t\x13i\x12\x91\xd3\xdd\x80m\xe3b\xbc\xcc\x87\xbd\x19\xb0%\xf5\x84\n?N\x1a\x1fh\xc1\xba\xdb3\x93\xc0=\xe9\xea\xa3\xc4\x94\xfb$i\xca%\xe8W\x14\x9dEf-\x17\xd7.B}\x04\xe5\xd02N\x81\x98\x06\xae\xf7\x18\x85\xbd\x07;\xbb;\xbc\x7fV\x1f;\xa2\xc8\x82\xce\xdf\xf4-\xf3\xc2L\\\xecd@\xcb2\xd8\xe6\xcdt\xe88\xb7\xf9\xa0\x9e<\x81~\xcf\x81\x0e\xec\xef\xed\xed\xec\xdf\xcd\xa6\xaf\x1c\xa9\xfc\xe0\x18\xf4\x8dg\xea\xc0\xe9\xceI*\x0e\xf9\xe6[Y\xa4\xf3\xeaIjd\xf1H\x03\x8b\x87<\xd1E@L\x0c^l\x13n{\xe4\xdcz'\xf6w\xf4\xd7#\nOV\xa10(\xa4\xb5\x03\xdb+\x92.\xa2z\x034\xc9\x8dl\x0b\xa3\xcd\x0b\x9a:\xf6\xcf0\xc0\xc5\xd8\xfa\x97\x7f\xc9\x87\x83\xaf\xa21\xa5Ng\x9b\xcd\x9b\xae\xf6\x0eJ\xbb\xfd\x1d&\xf5\x0evv\xf9\xbfLM:\xd8ej\xd2\xc1^\xaf\"\x0e\xf7\x1f9B\x14o\xd3Y#C\xad\xc3G\x99E\xf6\xc7\xa1\xddwlK\xdc\xc6\xbf\xf3\xe6\x96s\x06#\xb0~\xc1L\x8d\x1d\xba\xcf\xb7F`\x8d\xd9E\x0b\xfcrf1\x1d\xc1N\xcf\xe1VK\xa5\xe8\xbd\xa2\xa1\xba\xb0\xdd\x1c\xf2y\x9b\x16t\xe89\x80\x01L;`\x9d\x95\x9c\xe3\xb6\xda\xe9\x07d0n\x85\xf6\xee\x80%G\n\xed\xdd\x1d\xc7\x1cx\x8d\x8f\xe4\x01\x9d\xa2^\xd7\x1c\xda\x8f\x1e9\xb65\xf5\xd7Tl\xb0<\xad\x19\xccF\x81\x86\x1fT\n\xd5\x9b\xcc\xaeW\x00\xa0\xd5\xe4%]\xbf\x89\xd0\xd4\xb3\xe6\xe8\xaa\x81'\xb1\xdeV\x813\xe9~\x95\xea\x10\xd3\x95\x9a]\x8e\x13\xc0\x96#\xe6\xb1\xc7\x05I)|\xd1j\xe9\x99\xda(\xca\xd4of\x9b\xb7\xb9\xf5e\x86\xab\x92X\xeb\xc8\x0b\xff\x94\xc2$\n\xd7$N\x81\xa3y\x1a\xc1*\xf6\x97>\x06+\xc4)l*\xd25m\xf7\x81\xe1\xfc\xe9\xef\xe8%\xe8~O\xe5_\xaa\"t\xff\x01\x17\xa1\xfb\xff\xaaE\xe8\x87\x86\x83]}\xcf\x01\xbb\xab\x03,\x05x\xcf\xb1\xad\x97\xc7\xe7oO\xde\xbc{\xa3\x1ez\x9e\xaa\x9e*\x17\xab\xda\xab\n\x15U\xba/F\x8c>?\xf9\xe1>/b9FxXV&\x1e\xa7\xdd\x17\x8f!F\x8b\xb3) HJ\xe4\xac7\xe3h\x1c\x9fir\xa6\n.W\x8d\xed\xaa\xa7\xa3%c\xe5rP\xc7v\xa6b\xbc\xbb\xdc\xca\x1d\xefF<\x05\xdd\xd1\x80\x1b\xd8\x0d\xad\xe7B\xb9\x98{\xe3\x8c3\xb4'\xc6\xec\x93hzVX\xc0\x8c$}\xac\xcf\xb2\x19\xdf\x16\xf1\xf7\x0c\x14\xc5\x80\xf75\x1c\x1b=\x92\xff5(\x8f\xf6\xf4\xa4b_wEG\x99\xc2\xbeco\xb5\xa3\x16\xb78\xd99\x80<.5T\xe9\x00\x82\xa8\xfaz\xc2\xcc7\xab\x10Gsv\xcfaJ\xa2\x8c\x19Z{\x08\x8b{\xf7`\"\xfc\xb44\x1f>\x96\xa3@\xe1j\xe0w\x94,\xe0Z\xb0d!\xff.\xb2'\xd8\xda\xa7OEk\xfa\x05\x9a\xdcv\x81vM<\x12\xb7\xe3\xb3~\xb1\x1c\xba\xe1\x90\x01|\x99\x1c\xe7\xf7\x8ev\xaf\xc0\xe0\x12\xc2\x9a\x18\\\xce\nS.#f\x96\xec)&\x10Km\xcb\xa2\xfb6\xb7\xfa\xbf\xedT*H\xc5pmWg\x9c@ \xb6I\xb5\xdb8\x95\x92^\xe2\xdf\xf4\x94\xff\x15\xe9)\x0d\xe4j\xb0\xa3\xfa\x1dD-8\x18\xc9j7?\xb1j\xcf\xd19I\xdf\x8a\x8aof\xf5A\x92s\x90pZF\xf7\x94\x0b\x11n\xabqt\x06C\x93i\xdf$\n\x934\xce&i\xc4r\xe3\x83\xe4\xb7_.=(\xff-\x1d\xbb\xc3\xf2g\x9c\x08\x1c@\x06\x8aG\xf3\x86\xe0\xef\xdfzK\xcaV\xc7\x9b\xf5\x9e\x1f\x9d\xc2w\x07\xfdH\xf3\x03\xdc\x15\xda\x97\x9e\xe3\xf2\x93h\x8f\x1f\xad(\x0e\x08\xcf\x94\xdd]\xc7\xc5\xfdLe\x03\x177\xed\xa4,\"\x04\xecUI\xb9\xc0\xf2\x82'\xe2~wQq\xcc8:==\xc9XN\xbe\xaa\x19\xc7\xd1\xe9\xe9)eH\x9f\x93I\xe0\xc5\x1e\x9da\xd5E\xe3\xe8\xf4\xf4\x03\x15\xafx\x13ji\xe0\x930=!\x93T_\xfe\xfc\xcd\xab\xdaB6\x17c\xf1\xbb\xe8\x92\x84\xfa\xc1?\xf7R\x8fy\x11\x92\xf8eJ\x96\xfa6^\xf8\x81a\xe4\x7f~\xf7\xea\x9b\xc3 8\x8a\x82\x80L\xf4S\xa7U\x9a\xca_D\xf1\x92k\xbb\xf5\x15N \xfd\xdeX\xe5\x15\x99\xfa\x9e~\x86\xaf\xfc%\xa1b0.n\xf5\xcb\xd7\xde\x92L_GS\xf2\xca[iJ\xa3\xa9a\xd5\xdfz>]\xb1\x9f3\x92\x18\xd6\xe5m\x90\xcd}\xcd|\xd9{\xc3pN?|\xf5\x0d\x1eC\xfa6O?|\xf5:[^\x90\xd8X\xfc\xd6K\x17\xa7\xc4\x80\x0b\xb4<\xf2C\xc3\x80O?|U\x87H\xa7\x1f\xbe\xca\xfdM\x0d5\xa2,\x9e\x10\x16z\xdeP\x83n\x94\xd3\x05!\xa9\x1e\xaa\xef\xc8\xc7\xf4]\xecM.\x8fL[%\xafa(\x8e\xb2I\x0e\xbb\xbc\xe4\x86\xa5\x0b\xf7m\x0cY\xc98\xf05<\x81\xa9\x904a\xdd\xe9\xe8\xf8\xd4k\x17\xe60\x82\xe9x\xad\x18\x9d\xd2g #X\x8c\xe7\x9a\x92sd\xe7u%\x170\x82sJ\xf1\xcfu\xa7\x11\xf0c\x18\xdd\x89\xed\x0bz\xf6~\xfa\x04\x9e}\xe1\xc2\xcc\x85\x95\xe3\xc2\xc58(\xde\x05,\x07s2\x9e\x9f\xb1\xe8\xbaK\x8d/\x03R\xd6kz\xa2\xc7\x0e\\\x8c\xaf\x99\x1a\x99~~\xedB<\xbe>+\xf4\x99\xd0\x96Z7*}\xb4>9\xf4\xbd\xe1~_\xd5\x05e\x82\x954In\xfd\x9d\x07\xfff\xf9\xf4_\x8e\xe5\x93\x99\xd7pl+\x0b\x93I\xb4\xa2\xd2L\xa22o\x1a\xa7m \xdf\x84f\x01\xfcq|\xc6\xae\x00\xfa\x0f\x1c\xdbG\xef\x8f\xbf\x9b\xf5{\x15I~\x1c\x9f\x8d\xd33\xc5\x89^;\x11\x93~\xbf\x16\xf5\xf8\xa2\xea\xc4\x93\xbb5\xc4j\xbfMe\xb7^\xbe\xa1T\xa6;\x11lV\xe9-c\xae\xf6U\xab\xa8\x19\xbe\xae\xdc\xed\x04\x8ckS\xde\xae\xd8[U\xc3\xb0`M\xab\xaf\xa7\x9ct\xa8\xd6\x91k\xf6~W\x1d\xca5\x17,\xd5^\xe7\xfc\xfd\xae\xd3M\x88\xb2e\x97\xbc\xad=\xc7V\xbe:\xe7,\xb1*\xd5^\xf0\xd6T\xf8\\\xf1\xf7*\x01\xfc\x88\x1cf\xae\x8fW\x8eE\x91\x0c{B\x12\xc5\x91\xf0\x18\x8b\xf8\xfd[\xb9\xe8\x10F`\xf1\x8fp\x87\xcf\xecS\xa5\xd77\xf5\xea\xdb\x9f0\x92\xde\x08\xce\xbb\xb3r\x01\xa5\x84[[\xf5\xaa]\xb3\x7f\x9d\xa0\x8e\xc7\xdd\x98$Q\xb0&\xb6\xba\xa6\xf2CX ZY\xe6\x19\xd1\xdd\xcb\xaf\x01\x93\x15\x99 a9\xab\xdd\xc3\xea\x93\xdao\\xc\x96v5\xd9\xfaA\xb2\x0394zl\xf1\xa58!?1\x86\x163_\x8a\xac8\x0b\x12\xdao\x1cY*\xab\x8a\xe55\x1e\xb27*\xf6\xbdl\x9c\xf3\xba\x9aX\x05\xa4s\xc4\xde\xc2\x98\xaf\xe5\xc9\xe4w\xf1,p)\x0e\xdb\xc1)\xa8\x89\xb4J\x7f\xbej\xa2s \xae\xb4\xd2\xee\xb9Q B\xcb\x14\xc7\x01\xf9Y\xe7\xe1\xbc\xcf'\xfa\x1a\xcb\xe6\xa4U\xa0J\x94i\xf7|\xcd\xe4\xc9>.e\xf7\x1c\x00\xe9F\x97\x18\x94e\xe6\xf9\x9ahc\xea\x93\xe0\xc5\x03\xdf\x1b\xcd\xd5'\xbc:E\xb8\xe6\xda3\xac=\x8d\x96\x9e\xdf\x94 \xc4\xb8\x81\xe5\xc7c\xc1.>}b19)\xec0\xdc\xd8[\xc6E\xd1\xbfF\x18\xa4t\x8b)\xf9=d=Fh\xedoc\x0e\xadY\x97\x84)\x89m~\x81\xe0\xd91\x8a\xe6\x94\xc5\x9du\xc9G?\xb5\xb9P\xbf\xd5sX\x1d\x8c\xb4\xb3\xe2\xe6\xff\x070\xb1?\xda\x16\xdfw\xdb\x93\x85\xe7\x870\xb9\x9e\x04\xc4b\xa1\xea\xe9:\xbe\xb4)\x06\x1f\x087\xd0\xd0\x85\xc4\x85 -N\xb0d\x08\x13;6S\x03P\xf7e#Xp\xfc[\x19\x9f\x1f\x9f\xc4\xc4\x94f[<75\xf4\x08\xc2B\x19\x1d=v \xb3\xc3q\xd4\xe9\xe8\"\xc8\x8a\x87n\x12\x1e\xe1&p\xd4p\xad\x9a\xde\xde6\xf6\xb6)\xfe\xea\xb1QF\xac\x1c\xe8\x7ff\xaba \x9c\"\x1c\xa7\xf2\n|\xb9\xd8)\\\x83Rm\xd0I\xa0\x12\xddS\xad\xb7~\xedJ\x9d4\xc2n-\x05S\xab\xc2\x85t\xcf1S\xb4\x8d?X\x184\x84\x01\xe9\x9e_\xd1\x02\xe2t\xcf\xd7,F\x1d\xe9\x9e',{\x04\xe1+l\x13\x86y\xa4{>\xe1\xc6\x94\xf4\xa0xe\x13\xd4]\xd4\x8e\xfcu\xbb\x91\xbb\x86\xc8g X\x9a\xb0{\xae\x0d\x05\x0f\x18\xec5\x9f\x14\xde\x90\xf39\x19\x8e\xdf\xfac\x17\x03M\xb2\x00\xf6bc\x15\x87\x1fL\xd0\x88\xe7\x82\xeefd\x1e\xa6\xe0\xa7 f\xaa\xa9\xa4\xfc \x9c_\xa2%\xd5A[\xe6 $!\xbd\xf9,<\xbf\xd2zGV\xaaM\x87\xba\x84\x82\xf2c\xe0\xca\xc5\xd3\x8ec\x11\xe6\xa1\xf4<~\x8d\x07L\x1f\xcf\xe6\x13\xfe\xfb.\xd9\x80\x93\"\xf3\xed\xadO~g\x88y\xc39\xfa\x87\x0c\xfd\xfb\x14\xbfC\x17\xb6L\xe3m7N>\xbe\xfa\x89\xb4X\xbf\x86\xb5\xbb1\xce\xbf:o\x85\xc9(V\xfc\x12\xf7\xfaq\xed\x86\x9d\xf2\xa8I\xc7.\x88Ma\xb9`\x9d/,\xc7\xc5t\x14\xae\x1c\xd5\xbaU\x14\xa3\xd4F4a\xed\xe6\x98\"\xfeT\x88K-\xd0O\xca\xf1\xb4\xcb_\xe6\x7f\xdd\xb8\xec\x107O\x92\xa9\xf9r\xce\x0e\xff\x92O^\xf6&\x91U\x97\xe5l\xe5\xebJ\xe5\x85\\\x991\x8a\xc5\x80\x9c\xb2-\x8f=\xd8\xddw\xecc\xd9\x86V\x1d\x1f [\xc4\xfc\x16\xa2\xdcO\xb6\x88uu\xac\x0b\x97-\xac\x8f\xa8\x0c5\xd2\x8a\xa9\xec\xca\x19\xf7\x06\x15\xb0\xca\xb5F\xe5\xd4\x83\x94\x92s\xe9\x07\xd9\x18z\x16\xf3?\x87\nL&R\x08_\x0e\xe3<\xf0\xa8\xa7\x96a*\xdfW|\x1e\x98\xb8>\x14\x12Jy\x9d\xcb\xfb\x08\xd1\xa5\xce.\x03\xca\xd6\x89L\x85\x90\x8f\xd3\x88C\x8e\x12.\xcd\xa4\xa0\xc6x\x1a\x8f\xab\xd8%\xb8\xc2\"];?Q\xf0z\xf45\xc6[\xc8\xb3\xf33&\x05KNx\x89\x8c\xcd\xe7]*s\xfe\xd4\xe6\x828\xc5\x93\xed\x18\x97\x13\x7ff\x94\x83\xe6\xc1\xe9Q\x8d-\x1b\x9e8.\x04v\xd0\xfd\n:\x10t\xbf\xc5\xff\xbf\x80\x7f\x86\xadK\x15!\xdf\n\xa6\xe8\xb8\xf41\xb3&\xb5eZ\xc1\xad\xdd\x1f8\xb6\xfcJD\xa3\xcb\x0d\xddY\xc7\xa7\xa5.%z\xa3\xce\x8d\x82\xa7i\x91\x05\x83\xf4\x93\x8e2\x81\xa4z\xea\xb9\xb9\xb4\xef\xb0\xe8\x9bzD\xab\xc0\xa9\x18\xae\x8dl\xd3\xd6\xa5S;j\\\xef\xa6a\xf3Q]\xd9\xf9\xe6\xc8\xd7\xed\x98'\x93i\xc0S\x05\x92\xf6%\xd3\xd4\x0fv\x1fJV\xf0\x95\xbe\x8f\xbb\xcc\xc0\xb9\x8b;\xc8~#\xa3E\xdd\xb4\xbc h\x9a\x92\xcc\xaa\xeaO=F\xb5L\xf6BxsQ\xaf\xbe\xf1y\x15\xb3\xca&j/\xa9\n::\xd6\xdc'\xcaO\xa4\xb7\x9b\x93\x1f\x8a\xe8\x86\x14\n\xf4YSZN\x8f\x91\xf6zV\xb4\xb0\x82\x11D\x9dN3\x07\x98\xd4\xa4p\x10O\xc8(/#\x81tov:n\xa1-\xa3\x18\x81$\xb2\xfd\x08\x01;\xa6\xacE\"\x98\xf4\xb1w\xc6(\xdf\xf6vFKb;l\xe2\n\x8dB3p4\x97\x9a\xd2\xd6\xbb1o\xf9\xa8\x8bG\x97oG\xddu\xdb\x83%\xf6&\x8d{\xf7\xae\x10\xdd\x8c\xc5\xfe\x06X\xbc9nUW\xbd\xd8vP\xa3\xcd\xd3\x88\xb7P\xbf\x02>[\x81\xd8\xf6\xebV@\"A\xf8\xf3V\x97\x83L\xe9\xa5N\x9dgp)\xdd\x1c\xa0\xda^\n \xc84<S l\xc4\xe5\xb6\xa6m\xef\x97m\xe2\x81\x8d\x9fIN\xb38Z\xdaQ\x83\xad\x0c;7\x07F\x90\xe8ma[[\xd6\x17\x01T\xb6\x8a\xb4\xe3\xaa\x86Y\xe8\xcf\xd5\xf7z~A\x02\x9c\x9e\xd8\xa0g\xbf\x06\xa6\x90\x1f\xb9MP\x85:\x9f\x00\xf10\x0f\x80\xb0\xba\x00\xe2\xd1\x9cj.\x0el\x83\xee3]\x1b\xa9\x1d\xd5\xdczk\xe9\xfa\x9d\xa4\xa9\x90\xc8\xa5\x9e\xcbV=\x00\"-u\xe2\xf4\xa6\xa2.\xe4~\x0e\xbb\xfb\xd2\xba\xc5v\xdc}\x0b\x1d\x88\xbb'5wJ3?\xf4\x82\xe0\xba\xad\xba=\xe3\xb7\xc4~\x1e\xc1\x9aJ\xc2\xe2\x0f\x83\xae=4\xddjk\x98\xdd\xca}q(\xab&\x8d\x96\xd7\xfc3\x8fRGT\x84\x95/R\xea\xf8\xab\xca2\xcb\x8f\xce\x9a\x8c\x8al\x94\xad\xf8\xc2\xe3\xe2 u6\x1a\x96\xf9\xae\xf2\x0b\xa2n\xc5\x7fD\x84?\xd8S\xb0\xf1\xb4\x06\x0f\xd3\xb85\x0e\xd2C0\xd5g\xe0\x86<\xd1\x97\xce\x9eV\xdcB\x87]\x82\x86\xed\xfc\xee\x7fX\\\xc68v\x88\x97$\xcd\xd7\xd2m\xe0\x19\xda\x83\xbd\x01\x8f=\xb7\xc3\xff\xdd-\xc7\xaa\xdb{\xc0\xff\xe5\xb1\xea\xf6x\xac\xba\xfd\x1e\xff\x97\x7f\xbf\xcf\xbf\xdf\xe7\xb1\xed\xf6\xf9\xf7\xfb\xfb\xfc_\xde\xce>og\x9f\xb7\xf3\x80\xb7\xf3\xa0\xcf\xff\xe5\xed=\xe0\xed=\xe0\xed=\xe0\xed=\xe0\xed=\xe0\xed=\xe0\xed=x\xa4\x8d\x9d\xc7|j\xdb\xc0\xa2\x11\x8b*\xbeNQ\x1ep\x13\x8f\xe3#\x1e\xae\xb2J\x10\xe5J\xd1\x94\xa0\x17\xb0\x82xH\x06\xd1z`\x8b\xd9\xb5\xf71\x9eJ\x1e\x16#\x8f\x1dR!\x8fr\xa3M\x08\x9a3\xb4\xdc\xe4r|\xe6\xe2\x9c\xf3\xccPy\xa4\x9c\x8c\xf9\xe9\xc6\xf0\x142\xb3v\x80g\xb9\xeb\x14\x99\xa52\x8c\xa2\xe3Sj\xd2\xef\xf7w\xfb\xfd\xbe\xc3r\xf7\x8a;\x91\x13/\x9c\xf3K\x11R\x8e-\xbe\xf6\x02\x7f\n\x93hJ`E'c2\xab\xe4w\xd4\x04\x9e\xb0H\x9dp\x80\xb1~0B,\x8b\xe4\xd9\x01\xdb&\xb0=b\xe5\x0e<}\n\xfd\x1e\xca\x14\x7f\x84~o\xb0\x0b\x1d\x16\xffS\x97|\xcc\xb4'C\x9eSP\xcd\x9c\xbb\xe1\x8ek\xc22CT -\xa52`D\xec]\xb5\xc7\x03\x16;\xa3\x1b{W\\\x10\x8d\num\x1dnP\xcc\xf1\x18\x8e\x84\xf0\x14\xbc\xc7\x0edl]x\x08Z2\xf6:\x9d3\x07\xe3D\xdc\x87\x9eF\x8a\xb0\x8e\xa2,L\x0b\xe7\xac\x90\xcc\xbd\xd4_\x13U|\xe0\xc1\xf8\"x\xaa\x1ar\xf1\xc7\x8e\xe0\xe9\xd3\xa7#\xe8;\xdc\x9b\xb53B\xc3#zb2\x07\xd7\x90\xbdz\xac\xac\xd3\xef\xa7\x84\xdb\x948\x17 \xda\x9a6aQ\xb3n\x1b\x16\xb5\x9a6\xa2\x8eD\x97\xfa\xd0\xad\x00\xe2\x88o\xe7\x84r\x93\x1d\xea\xe6\xe1DM\x99/\xe2[\x10\xd6\x18\x97\xad \xac!\x15\x92(\xec\x84E\x0b%\xac\xf1g\x11\x07\x93dBW\xc5\x0b'\x8b(\xdeH2\xa9\xe5\x06\xf9b`\xd4z+\xf4\x96\xc4\xaaK\xec\xf9\xd9\xc3\xbf\xf0\xe7\x1b\x8d\xbd\xcd\xd0Y\x9b\x16\xfe\xf7\x05G\x1e\xf8\xe1\xe5\xdd\x8f\x9d\xb7\xfa\xc5G\x1f\x05\xd3\xbb\x1f\xfc\xef0\xf0\x99\xff\x91\xdc\xfd\xc8\xd3\xf4\xf7\x18z\x14\xa6\x93(\xf8\x12\xbb\x956MG/\x9a\xff\x82;\x96v\x95\xf8\xbf\x90/7 \xde\xfa\x17\x9c\x83\x9fz\x81?I6\x9aB\x9b\x19\xf8\xbf\x03\x16mLvZ\xc1\x1e\xc9\xfd\"&\xb3/\x0b\xf8d\xe9\x05\xc1F\xa3o3x\xd1\xea\x97\x06=}}\xb9\x19\xe2\xb7\x1a\xbeh\xf6\x8b\x8f?\xbb\xb8\xfb\xc1g\xbf\x07\xd5O\xb2\xd5\x17\x18\xf9\xea\x8eF\x1e\xda\xfb;\x8em-\xbdt\xb2\xb0\\\xe8\xd7\xd7\x96\xc62\xce\xebi\x15\x9dz\x88\x88GH\x02i\xddE\xa2/+\x1aP\xcf\x90\xe7_\x0b\xc7\xc4\x9c\xdaB2\x9b\xf7\xe1@\xd8\xd81\xcf\xa8!\x9a\xb7q}n\xe8\x8c\xc9\x99P\xd8\xc7\x95X\x1f\x10n\x9a\xd5\x9f\x03\x93\xeb\x14-\x17\x06\xb7\x00g\xecV\xdd.\xa0\x15D\xa3&\x88f%\x88\xc62D\xe3\x96\x10\x95\x04\x88\x18C\x95\xf9\x08T\xf6\x86\x832rX\xe8\xa5;\x03hB\xbc\xf8\xdf\xd0\xf3\xce\xa0\xb9\n\xfcT\x8b\x9c\x15\xcbI3\x98\xc4EFh\xf7wUc=\x10z\x8f\xeakv\xb9\x867eU\x8d\x885A\xe3\x14\xcb\xbb\xb8\x98X\x92\x89mYt\x8e\x1a\xa4is\x1d\x02\x92%\x9a\xd0\x01\xe8\x03\x01@\xd9\xd7f$\\\x8bx\x12\x9d\xdc\xceMM\x86\"\x7f\xbb\xe5\xcb\xa9\xd3\x8a\xa8x8:\xfdgkf\xc2\x9f\xb80\xc1p\xd3\x01\x0b\x8b_\xe7u\xbe`\xa1;\xfdy\x18\xc5\xe4\xc8\xc3`}\x96o\xc1\x90\x1ey\xd0\xa1e\xcb,H\xfd\xc0\x0f\xb1hY*\xcaB\x1f\xaf\xda\x0f\xc0\xcaJ\x05I\xeaO.\xaf\xe9\xfbk\xfe\xde<\x84i\xbd\xd3\xfb\xba\xbc\x9a\xb4\xb3\xdd\xc1\xa3\xddG\xfb\x0f\x06\x8f\xf6\xd0\x8e\xff\xe9\xd3\xa7u\x0d`4\xd9b\xbf\xa7\xdd\x04\x83\x9c\xbb\xb0\x80\x0eXs\x93\x85\x00\xaa\xfaX\xf0\xaa\xb8\xdc\x02\xbb\xcb\xbc\xe6\xed\xd0F\xfe`\x1fl\xfd\xf0C\xe2X.,t\xd7\xd0\xf9\x83\x0e\xec\xd7\x0c\x17y\xc0\xce-\xdb\x9e`(1\xd4*C\x07\x92q\xef,\xc7\xf0\xa70E\xad\xe1\x8aG3\xe1*\xa4\xa9+>p\x1c\x17\xb6\xd0h\xbf\xa4\xe0\xc2\xc4\x1f\xbd\xb3\xfc\xe2-v\xebY\x9f\xd2\x83S\x0f0\xd0\x00\x04\xf0\xa4\xaa\xe4\xde\x86\xc1c\x08:\x1dG^\x99B\xa3\x16\xa0\x15\xaf\x8d?FZ\xe5w\xe9\xb9q\xdc\xea\xe098\x9e\x141\x15\xf1\xf2\x9f9\x00\xad\xe8\x07\x0c\x12}\x87g\x89\x90\xc0\xc6b\xc5O\\X\xe5\xad\x8e`\xed8\x8f\x1d\xb8\xee\x06^\x92\xbe\xc4\xb6\xf1>\x83\xf7s\xef\x9e\\\xa4\xc6\xf4\x16\x0f\xdf\x8cSv%S\x84\xf5\xde\x9a\xb1\x06(\xc9\xc4,<\x9f>\x01_1\x96\x93G]>:\xe8bp\xb0\x86\x03X\xf1\xb2\x9e\x0bk\xfc\xa42\x02\xc5,\x99\xb9*X=A\x1a\x85\n\xb3\xe7H\x10\xb3[Q\xb6\xf2\x99\xa9\x92+8\x80\xf1\x19\x0c\x05\x0d\xcau\xb1\xaa\x14\xa8\xd7iK,\x82\x81\xe5\xba\x05Su+>@b\xaa\xc2\x82\xa9\x8a+LU\xa8c\xaa\xe2M\xd9\x80z\xe5|f\x87\xf6\xe0a_U3\xfb\xbchg0P\x8b\"^\xb4\xd7\x7fHIL^&\xc6\x80A\xf1\xf5\\\x1a.f\xda=?'\xc9\xabh\x9a\x05\x18G\x1e\x86\x9a\xa5\x98\x92\x99\x97\x05\xe9P\xbd\x9f\xff\xa7\xea/q\xd2\x8e\xfd.\xff\xca\x85\xa8\xf8i\xa46|L\xd5\xbe'\xd1r\x15\x85\x94\x80\xe8F\x06\x98{B\xf8.}\xe3]GYJ\x17\x8fw\xd8\xb4Y\x8a H\xa8\"_Ny\xb7_S}\x8eW\xe2\x82U@\xbcr\x0b\xc2\x03\xc7\xcb\xe1\xea\x9d*\x9aLl\xca\xf9=\xd4\xa1 \x16\xed\xf5th\xc2\x8a*\xc8\x95\xe5E;j\x91\x97\x17\xed\xabEI^\xf4@>\xda\xf0\xd5\xfe\x9e\x1e\x15'\xbf?*\xcej/\x18\xf3\x91\x91:\xc1\x9f\xd2\xde\x1c\x9b\x1dN\xe8\x88\xe3bA\xa6\x16\xd8\xa4{~\x8e\xce\xe7\xe7\xe7\xc8&\xf4\xdc\x02\x1f\x1d\x9b8\x0e?\xadX\xf5\xfcxTE\x0c\x1d\x98h[\x9e\xd4\x96\x0b)\x1fFTz;\xae\xce\xe5\x92\\\x0f\xc1\x8aI8%\xb1\xe6\xa6\x94\xe3]#3\xb0\x96\xf3c\xac\xe2he\x88?\x03\"UFwN\xd2#\xb1\x85\xcduYd\xf0dE&,!P\x14\xd74\x1c\xb3\xd0\x1fq\xdc\xa2.\xdd\x13\xc4\xb6\x8e\xa20\xf5\xfc\x90T\x1cn\xe4'buO\xa2\xab\xbaZ\x99h1\xa8\xab\xe5\xb1Z\x18\xb57\xb10\x9c\xa9\xb9\xf2\x84U~\x17\xad.\xbc\xb8\xa9\xf2\x8cU~\xe6%\x9c\xde5}\x10\xb0\x0f\xa2\x90r\xeb\x1f\xbc\xc0\x9fzi\x14?\xf3\xa6s\xd2\xf4)&t\xe8\x06\x917\xf5\xc3\xf9i\xea\xa5Y\xa2F\xb2\x97\x9f\x05z/S~\x89\xdd\x9f7\xb0\xf7\x94GZP\x04\xb1\xad%I\x12oN\x90+\xb24J\x01(6A\"P\x9d;T\xf2\xdcQ\xb6o\xf2\x94\xa4\xcf$\xf0\x92\xe4\xb5\xb7$C\xb0\x92+o>'\xf1v\xe6[\xda\xfa7.L\xe0\xc0\xd8\xcf\xc4\xc5$l\x0eO\xc6\xe6\x82\xc5\xe1c!_\xb4b|\xaa\xfe[\xcc\xed\xddv\x9c~8\x8b\x8c#\xbc\x93\x1e\xf8\xc0\xb7'\xf9\xee\xf8=\xba3t\xe2`\xf8\xb7\x99\xe7\x07d\xfa\xaf\x12\x94\x8b\xdd\xd6\xbd\xa5~\x1a\x10c\x0f\xd6\x0b\x04\"\xa4\x11\xd0a\xc1\xe1\xdb\x97\x80l\x88Oi{\xd7r\xcc\x83\xf08rKkq\x84\xae\x95_dE\xcc\xe4\x013A\x9b\x18>\xf1,\xbd\x8f\xdf\xfa\xd3t1\x04\xeb\xe1\xc3\xde\xeacM{\xacz<\xf7\xc3o\xc8,\x1d\x82\xe5ei]\xffE\xfd\x13\x7f\xbeh\xf9AJ>\xa6\x87\x81?\x0f\x87`M\xd0\xdf_\xbfDP9\xdf\xf3\xb7\xff\n\xb01&\xcb(%\x85\xc7n#NZ+\xcb\xe5\xa4v\x8a\x88\xb9\xb5B\xe5_\x92MD,\x8c\x06\xcc\x9cq\xac6\xf7\x11\x89\x1eL\x15\xb2\xa6\nA\xbes\xaa:\x0dE\xea8+\x85H\xba\xb1\x8b&sNIb\xa9\x89(m\x1bl\x8a\x8a\x90;\x15\x8f\xa5\x81\xd3\xd5\xe6Am\xd3\xa2d\xdc\xa7\xcf\xff\xd6\xdf\x91\xad\x96\xa9p\xf2\xc8\xb1\xadrGV\xb3\xf4g\xe6\xd4\xa5J\xbe\x92\x86\x14\xe06\x17o\x83\x87{\x1a\xc1J\x02\x93^\x1ely\x01\x12\xabb\x9f\xa8^\x8c\xb3\xcd0\x8ba\xf5U\xeb\xce\xc2\xabk\x8b\na\x94\\\xb3qWvmy$C\\\x1d\xa7;\xdb\x10b2\x10*\xed3\x89\x8c\x02U\xbd\x8d($\xbaas\x0e\xb6\xca\"=b\x0ey\x0f\xf7\xaa\xfew\xbd}\xa7;\x93\xfd\xe8\xdb\xb4\xd8r\x12\xaa\x01\xeb\xe7Mb\xf0\x88\xbb!>\xe2n\x86|V\x83G\x0ft\x9b\xf4\xf4zy\x11\x05m\x9an\xb2\xf34\xd8\xe1\xaa;\x98\xdby\x1a\xbc\xad\x0d\xce\xd6\x03\xb5q>\xfeG}\xa7\xfb\xf5\xf1\xf7\xe5\xb2 /S>\xe1\xa9\xe5\xd4\x1eXj\xb9G\xeaxXn\xb9=\xf55\xcf-\xa7\xbc\x9d\xe6HR~\xbf\xe6\xefU4\xbd\xe6#T=\xe4\xe6\xfc\xbd:F\x9eV\xae\x82\xed\xec\xb5\x1a\xfe\x92\xa5\x94\x1b\xe83\xcaU\xb0\xed#\x9b\xa8\x1a\xfb\xee\x94\x81E\x95\xd6\x8e\xf9\x08\xd5\xea\x87|U\xd5N\xdf\xb0\xf7j\xf5\x9f\xf0u\xc5\x0d\xf5\x12Fp\xa8\xe6\x90{ #x\xa3\xbe|\x85i\xe1\x94\x97\xefP\x1ed\x18].9\xc2\x92\xbf\x9c\xbey]~\xff\x16FpD\x8f\xf2\xa3n\x82\xaaW\x7fv]\xaeqB\x05G\xdb:_\xf8\xd3) U\x11\xfc5+M\xa3\xb7\xb1\xbf\xf4\x99\xadv\xb9\xc67\xe8\x00\xa6\xcd\xb9_\xae\xf8\x9c\x92{\xdbJp\xf4\xdb1\x99\xfbI\x1a_\xab\xcd\xfd\"\xd7\xaa\xa4\xb9|\xc1J\xa3\xd5\xb6\xa1\xc2{M\x12\xf3r\x8dg\xa6\xf8\x01\xef\xca\xf5~F\x88\xfe\x955V.\xfa\x1eF\xb0\xf53F\x0e\xffY\xca\x08\xa0\xfc\xdd\x9d\xf9\xe1\xf4h\xe1\x07\xd3\xf2\xd7\xdf\x02\x8f\xf18\xa9w\x8d\xe3G\xdf\x03\xd8\x1a\xc1\xa9\xfd\xd2\xfe\xfb\x0d7\x0f\xd33\x91\xed\xe2\xb1@\xd1\xf0K\xd9\xe4\xac^0\xe0\xda\xac\x07\xc6J7N\xd7\xd3\x16V\xd9\xf2\x1bG\xad{\xe3\xc8\xd1\x0f\x0c\x8c\x00H\xa4\xf8\xd2~\xaf\xbf\x9dE\xd7\xd5) HJ\xe0\xfd\x98\x9c\xb9t\x92\xbc=\x1e8,\xc5;\x8a\xf7\xf4\xe7Kl\xa6\x12 \xf9\x06\x86\xf0\xb2\xbcd\x1fj\xb5\x9e \xd9\xd0\xff\xc2|\x0dO\xedw\x05\"\x98\x0d\xd8 K\xa5\x9bV\"|\x96\xbb\xff\x1aF\xf0\x8c\x8e\x98o\x8b\x12\xd6v\xc5\x91]\x02b\x0dBi\x1aI+\x00h\xd5R)\n\xf3\xbb\xba\x19|\xd5\x82\xd5+5<\x12\x8b\xf4\x95\xfd\"_\xc0%\x8b\xf2\x0f#\xb8\xe2\x19\x8d\xe8;Z\xe2\xdb\xbf\xe0\x9d\xdb\x01\xc6c\xc8 \x10f\xe4\xa3\xfd\x9d\xb0\xbc\x93\xe3\x93\xb31a\xb7\xa6\xe2\xf7\x88\xe7\xa8\xc0E\x0bM\x1b\xa1hr\x08\x1f\xed\x1e&\xb6\xd0a6\x0c\x8b\x0e?}b\xd8w\xe2\xc2G\xbb\x8fyv)\x7fR\xf4K\x87\xffm\x0e\x0d\xfa\xed\xcb*_\x0bU`\xfe\xa1\xcd]\xe3R\xeb8\x91;\x93\x87\xcca\xfc\x9a'\x82#th>K}\xc2\xa21\x8a|\xdf\x11<\x05\xff\xb1\x03_\xd9)\x83R<\xf61n\x00\x19\x87\xba\x10\x96b\x05\xeb&\xf0\xe7\xd6\xdb\xe9\x9b\xd2](.|\xcaRY\x19{\xde\xc2\xda\x05\x02!j\xb0\xbc\xa3[>E\xa6\x94\x19\x04\xd8[6#\xd9\x85\x0b'\xff\xf3\x17\xf1[\x94p\xecY\xf8 ]\xbc\xf4\x0c\x0b\xd5k\xd9\xf2\x14\xff\xd2f\x8d\xfc\x19s\xdc\xbd\xd0\xe0\xb5\xa0S\xf9\x90\x08\x1f\xd2\x0b\x16bY\x8f\xa7\xc2n\xe6\xd2\xae\xb1_\x11\x80\n\xab\x8dW\xb6\xca\xa7O\xca\x8e\xe2x[\x8d$sS\x07\x8e\xbf5\xae\xb8\x1a\xee\xe2\x95}\xc1\x9c\xa0c\x1e\xc1 \xe2\x11\x0c\xba\xa5\xdc\x8fl\xf4\x94\xd9b) qe(e;\xc9\x7f%,T#\x0bDa\xc6\x9b\xb8n\xfc\xdfm<~N\xc2\xd8\xf8_a\xe0\xa1\x170\x04>\xa9\x88OJ\x84\xee(&\x95=v\xc4\x9a\xe0f\xcb\xc4\xacB\x8e\xc1\xef\xc5jElJ\xbf\x8cI\xcd>\x8c\xca\xb3*\xea=\xc3\xa5\xf5l\xfb]]\x14,\xc4P\xba\x9ddB_\x0d\x99n1\x96\xb4\x88\x0f\"\xe5(\xaeDN\x17W^+\x9d\xcfX\xaf\xe43\xd6\x93\xbc:\xdd\xca\x14\x89\x94\xd3\x01\xc9\x19\xa9\xac4\xca=\x04\x9b\xf4E)K\xc4\xffOr\xd3\x87\x98\xb4\xe8/.\x15Q`\x04_a\xc4\xa1\xbd]\x07\xff:\xc6\xff\xff\x8d\xbe\xdb\xe7\xaf\xfe\x8c\x15z\x0f\xd9_\xdf\xf1\xf4\x97[\xa1\xfd\xf0!\x02\xd5\xa3\xb3\xb7t\xe2\x82\xe5\xd2\x8f\x91\xbcL\xbb\xf5\x17\xcd|\xbc\x1f\xecEIuE\xc7\x9b\xd9\x19&B\xca0\x11R\xc6T:\xcfTh3\x84\x1dJ\\\x8bl\x17\x90o\xe6\xbfRaa\xe1%/9\xfa\xbb~r\x14\x85\x13/=]\xc5\xc4\x9b\xa2\x90#\xf8/\x17\xcd\xce]n\n\xe623_\x97\x87rt\xd1x\xc8\x95\xe4(W\xac\xcb;o\xee\xca\x99\xfd\xb9\x9d\x91\xe5Z\xf4\x18H\x19\x85\xf8k\xb1E\xd2\xf4\xb1\x03\x0b\xfb\xaf\xe34-'\xbd-HP\x8a\xd9J\x16\xdd$\x8dbB\xa95o\x85\xa4E3!mfm\x93t\x1c*\xedP\x08\x9e\x96`\xc7\xf7w5\xa0Q\x14\xb7d\x15}\xfb9=\xd3:#4^<\x80\xe7tO\x0d\xd9?\xa3j\xea]\x85\xfc^\x92\xeb\x17\xcd]\xa19\xe7\xd7h\xceY\x9b\xd3\xc1\x03\xc6\x01W(\x13\x94\xc3\xed\xf8!<\xd7\xdb\xd3\xd1\x9e\x9e#\x177\x92\xe3\xbb\xd72\xf1YBNI\x9a\x92\xb8AJ\xfb^\x17I\xb2\xd2\x92\xbf\\\x05M\xf6\x05\xdf\x97\xb3\xd7\x01\x94\xf5\xba\xaen\xa1\x0d:O\xa6\x9ao\x91\xca\xaej\xe2F\x99\xf0S\x1b\x93\x96\xfd\xc1>e\x9cN\xedb\xab\xfa\xd5\xafj\x8a}\x92\x0c\xe1\x0f\xe5\ns\x92\xbe\xb9\n\xc5\xf7\xcfI2\x89\xfdUJ\xd1\xe7/u\x15_{K\xda\xd8\xdf\xea\xea\xb0m\x90\x0c\xe1\xbb\x12\x1cQ\xc1R\x06\xa6\xbd\x85\x07l\x8d\x88/\x8e\xc1wjxL!\xa6\x8d\xc3,\x08\xce0\xfe\xcd[[p\x9d\xd6\xdfo\xf8\x9b*\xec\xbd\x8a\x11\x8f\xf2 [\\\x85b:.X\x7f9}\xf3Z\xe3@\xce\xf5EM\xfb\xae\xc4\xfap\x86-=\xe3Y\xe4\x1f\xebb7P\x81\x82sd\xc5a\xef\xebSx\xf3<\xaf\x9c\x1d\xea\x9f\xb9`\x9f\xdb\x95\x94?\x9c\xc1\xffZ6\xe6\x9e\xf3j6i\xc3\x8c\x8b\xbe\xb4\xba!\x16\x1a\x08\xf9\xcc\x8au\xa6\xe3\xd2~\x89c \x03\xc0\x91\x84\x8e\x9dN\xc3\x85\xb7\xdc`\xe9\xa8\xaaz(\xa1\x95\xa4B\x18\xbfFV<\xb4\x07\xfb\x8e\xacZp\xe1u\xa9\x1eK\xc2\xf2f\x86\xd9\xe4\xde\x15\x84\x1b\xff~\xe5\xa5\x0b\x17,\xfa\x0f\xb7S\x81\xc0\xe6J\xc3\x1c\x07\xb6z\xad4\xff\xd2\x0d\xd6\x9ec[K\x92z\xba\xd0\xbb\x1a\xe5m\xa4\xd7\x9a\x8b`\xa4\x8e\xaa\xf3\xf4\xaav\xebI\xa1\xe4\xf3\x93\xe3\x8f) \x13\x9f\xca&\x9f>\xd5\x13D!\xf8\xd4R\xd7 \xa5\x9a\xa8]o\xa5\x9eK\xec\\\xddH\xd6$L\xf9p\xa20\xb1\xa9\xc0\xaf\xec\xc7rW\xf5<\x0e\xe0Q\x9c\xa2\xf7\x91I\xdaC\xb5\x9c\xbe\x90>\xfe\x10\xac7\x16t\xa0\xd3\xf1\xaa\xbc\xa4x\xae\x86j\xb0Z\xf1\xe8\xb4wu\xb0\x0b\x94\x1cR\xd5\x91}}\xfc\xbd68\xf9\xeb\xe3\xe3\xe7C\xd8\xeaWKf^\x92~M\xae[\x9c=\xa0u\xe9\xd0\xa9\xbb\xb85$s$e\x86Fr\x99u\x8a\xde\x14o\xd1\xcd\xc2\x90C\x81e\x01\xc0\xe51J\xe3y\xbd\xa44\xa0\x17\x06{\xac\xbcz\xe1\xb9b\x1d\xd7\xd4\x9d\xa9\\\x93x\xf4\x8b)x\xfcq|\xd6\xad\xe6\xce\xd7\x84p\x9b\x93\xf4[\xe2]n\x02\xf9[\x01dK\x1f\xe3\xa5\xa8M\x8c\x11\xab\xe5\xe73\xc0q\xd5\x06\x1cQ\xf8\"&\xe4\x97\xc6d\x82P4>\xa1\xc7F\xd0\xa5\xc8\x8d\xe6\x146?\xa68\x98\xe8\xef\x19rD\xed\x0c\xab[\xd3\xe4\xca\xbd\x93\x08\x19\xa4'\xc6\xfb\xa6\xe4G\xe6\x89\n\x05]\xac\xcd\xd4\x16\xb2\xc0\xba\xe5\xb5\xc2\x83\xbc\xbaB9\xf7\x90\xb9\xfc2\x94\x02\x84\xf6\x1eug,\xa1J\xef1x\x05\xf30y\xec@\x92g.\xa7\xe7\x867\x9e\xa0\x96\x04\xe5{\xe4*2=O%\x19\x89l\x06\xd0\x87\xfb\x06\x08\xb1\x08\xef~\xc2RY\xc9\x07\x90If\xb5\xb0*\x92\x9c\xd8\xbe}\xa6\xab\xca\xed'_\xe2\xbd\xea \x1a\xb1\x1b:!oV\xcf]+b\\\xbfD\x06\xaf\xfcp\x1a]Q\x88\x16\xbf\ns\x17\x95m\x86\x83\x9aB\x9b\xb5@\x05\x80\xb1\xce+\xa0\x9d\xa8\x8f\x81v\xad1\x1b)|\x8bM\x9e\xe1\x88\xf3Di\x8d\x17 \xe6\xbc7\xb9\x94\xaa!!\xcd\xf9\xe3\xc5\x10\xb9kQ\xa3\xbd\x92\xcdS8\x97\xedn\xf4\x08\xe0\xc0\xdf\x1b-\"\xfa\xbd\x07\x8emy\xc9u8y\xb9\x91\xfd\x86\xf8\x94%GA\x1dL\xab\xef\xda\xd9}<\xba[\xbb\x8f\x9d^\xaf\xc6\x08+\xf9\x0c#\xac\xaa1\x90Y\x12.\xf73\xc4q\xf51\xa7U1\x9fV0\x94\xb6\xb2J\x95}\xbd5D\xd4F\x8c\xa1T\xd6G\x12\xba\x15S\xf9\xe7\xde=4\xa3+\x07v.\x14#\x84eCe\x11\xd9\x12\x92\x82\x97@.Ml\xa9\xe1\x18\xf44\xb0\x02\xa0!h\x17\x05e1+w\xe6\xb0\xc0\x0f\xe1\xef7\xd5\xbb_m\xca\x1b\xf3\xde\xb5\xf9\"R\xd1\xe8\x05o I\x82\xcb\x0d6\xba3\xbbb\x12\x00\xd28XF2\x188\x0e\x1d\xc0\xf8\x8c\xdf\xc5(Yf\x91l\xdf\x86:\x10}f\x8a*W\xc2\xc9\x88\x0c\x0d\xa3V[(\x95Y%\x96\x0f5\x95\x1ceF\x10\xc2\x90\xe5\xc0 \xdb\xf0\x17h]\xb0\xd5wL\xfa\xf6\xc9\x82L.\x87\xd2uB\xabM\xdb\x8aN\xecT\"\xe2}.\x9d\xd8\xfdlKD\xc3!\x14s\x1bUVg\xb3\x81\xdd\x8e\xdc\x08\xc5\x1bZ*\x15\x1d\xb6\xa20M\xf6l\xbb\x06\xdb\xd3==\x97\xb8S\xb1\xf2b2\xfbN_\xb5\xf2bl\xdc\x8e\xfa:\xe1\xd5u\xe9\x89\xe9{\xb5\xf9\x19\x7f\xaf\x0e'\xe0\xcd\xab8\xba\xc2Li%+\xe2r\x85\x85T\xe1\x857I\xa3X\xb1\x85\x9a\xb2\nA\x14\xea\x1bXW\xe3@\\7\xca\xf0mn\xc4\xe7Za\x19\x8d\x87b\x12\x9aD\xfc\xa5\xb7\x1aB\xd4]z+\xbdp?\x8b\xe2co\xb2\xa0u\xf8O}\xbdI\x94\x85):\x1e\xd3\x1f\xfa:i\x84\x04\x90\xd6\xe2?\xf5\xf5\xa20\xb8\x1e\x82&\xe7Y\xb5zn\x9c=\x04\xbf[\xe3\xd3\xf66\x8bI\xa9n\xe9E\xb5~ \x03\x86\xa0\x01\x8e\xbc\xc2C\x98V+\xf8 \xfau\xe5U\xbcn\xf9\x8df\x90q\xb4\xa2\xc7j2\x04\x8d\xf7\x1c\x1b\xd2Q\xe0%\xc9\x10f\xa6r\x8e\x93C\xd0\xac\x13\xab\xf1\xca\xff\xe8\x87C\xd0\xc0\xfe\xf9\x9bWC\xc8\xaa\xef\xd7$N\xfc(\x1c\xc2\xa4Zv~\x9e\xe05\xd6\x10\xd6e\xe4\xd4S\xc8V\xa99\xea\x89\x8e\xacQ3\xf4\x12\x7f~/\x94V\xe9y\xaa\nM\xe2\x02\xb0\x81\xb2\xf5T\x0e\x96\xa5\x13M\xaf\xa2C\xae\xb6~\x1bE\x81\x9a\x8e\x14g\xd1\x9dEY\\W\x8bR\xbd\xfb?\xdc\xef\xdc\x9f\xeb\\{gFA\xc8\xb6,\xe8@\xea\x94\x82\xbd\xff\xe1\xde}K>\x8f\xaa\x0d\x06\xdas\x0d/|i\x1df\x85\x86\x7fN\xa20e\xb9\xb9H\xfe&c7\x88\xb5=\xact\x0b\x05\xd2\xb2\xa4\xd8\x93f\xb3a\x19\xefV\x91\xdb\x99l\xe7c\xc3)\x1b\x88\x9c?]7\x8e\x85\x18\x87\x86\x93\xc4\xe9\xc4$a\xde\x1fb\xc6\x97\xe4\xfamLf\xfeGi\xce\x1c(a\x05(\xf1F@\x996\x03\x85\x0d\xa7\n\x96\x0cK\xf3\xb1U+x50Md\x98j\xa8 ;\xe8(l\x13\x05\xb6\xe5\x05(\xe97\xec \x95\xb1\xd7\x14\xe3b\x84o\xd4M\x17^z\x82\x88\x99\x08d\x17\x8e\x9c\xb05b\n0\xdbW\xa8'm\x87\xbe\x9f\xa0\x9a\x08\x89\xf1a8=a\xf8\xfc5\xb9\xa6\x1dd\xd0\x01{kB\xe7\xcf,yP\xb9C\xff\xc2\xe4\xf2\xf8\xeb\x00,\x0b\x860\xb3\xf1O\x87\x8a2\xf7Qg\x1b\xa2\xe1\x10S\x05M\x9cztYK\xe8\xe2V#g\xacy\xd4\x0c\xd5\x89V\xcc\x90\xdd\x0c\xa1hf\x87b\x08U\x83\x17\xbaV\xe8\x9a\x8b\xa4`j\x13\x8c\x8c\x81\x1d\x96+\xa3\xc6\x7f\xea\x82\xe7\xb8\xb0\xe8\xc6$ ^Bl\xaf~\x0e\xd7&,\xe34\x83\x0eVj@\xfc\n\xa4\x8b\xa3)\x11\x06;u\xf6@\xa5\xad\x81\xee[\xca\xee(\xbd\xacl\x10\xba(\xdetJa\xe0\x87\xf3w\x91\x1d\x88\x89\xdej \xf9F\x96z\x95\xf7\xb2\xf4\xfa\x0e\xc7\xbcp!Q\x04\x8c*\xfb\x96\xb3^u\xa7\x98xP3J\xf1\xa9dM\xa0\xb9x\x10D#(c\x92.\xc9:\xe2\xd1\nS\x17@\x90\xe3\x91z\xdfX\xa6\x0c\xc8O~\x91\x01\xeb\"p S\x01\x9b]q\xb1U\x10\xa6\xda\x0d\xc3|\x19\xa6\xd1\xb7~\xba\xf8Z\xac\xf6\xcb0%q\xe8\x05CX+\xc7,\xe3m\x1b\xf5&B\x87G+\\s\xd7\xc3\xbaA\xe4\xfcp=\xf3/\xf4\xe4M\x00 \x02\x00z\x92Z1\x10/\xf0\xf3\x8b\xf1j\xa1\xbd\xaf\xd31\xdb\xa1M%\xaf\x86y\x0b\xc3\xc1\xae\xd0\xa0Pl\xad (\x07\x12\xac\xaa\xdf\xad\xa2\x95)\xf3\xb5\xc0=\xdc\xbd<\x12|\x15^P\xa7p \xc9\x15~_1B\xaa\xd5\xbfi\x95T\xb2\xc2\x08\x0d\x0f?}\x82\xd8\xb6\x06{h\xcb%\xd16\xdbq5\xf3\xe4w\x1cOx8\x90(\nN\xfd_\x880>V`B\x0f\xb7z\xb3\xa9\x0c\x934\x97^yZAS\xa6o-\xf6\nH\x96\xc6\x86\xebQ\x01\xda\xd2\x98\xb9\xd1kXP/\xb4\xeb\xf8\xf4 2\xfa6\x9f/3:\xce\xff\x1c\xb1\x8cp\xa1\xa0b0\xa2g\xa7\xc6\x02\xb9\xca\xe7P\xce\xa2\xc4\x83\x0fU\x80\xd0\xa7\xc2\xcf\xb7\x84\xc1m\x90\x1cd\xd8m\x82\xe8\xa0Cv\x11\xa8P\x07\x0e\xd0\xe2<\xe8\xf0\xbeb\x92\x05zp\xa6\x8b\x98T\x00\xda\xe6\xc0\x80\xcf\x84V|'\xd0\x8a\x19\xb4tG\x8cx\xda\x03\xac\xe2\xa5\x01z\x98U\xe5\xc0*\xc8\x0c:o\xf8L\xa8\xf9w\x025?\x87\x1a\xe3&\xaa\xb6\x03\xb0)\xe0*\x86O\xd5\x16\x0c\xe7\xdag\xc4\x0fk>\xd7\xfa\x05\x1f\x15?f${\x1f^\xd7\n\xb3\xe5\x05\x89\xe57\x05Ty\x17\xa4\xfb\x87?\xf0\x91\xd1wE\xfe\xf4\x99\xcd8V\xcb\xca\x93\x87y\xd0\x81 \x9dp\x0f\xc5`\xc7\x05\x8d\xc5\n\x9dqM8\xd65\x8a\x9bR\x93CLd\x93\xe8\xa1R\x96\xd0\x89\xc6\x1f\x01d+\x8bkfOq\x0dO\xf2$<\x8f\xe1\xba\xd3q`\n\x9d\x11\xa4\xf6\x8a\x9e\xc9\xe3\xeb3\x17\xd68\x97\x95\x0b\xd7\x0e_\xbd\xea\x0808\xa6\x99C\x98\xb3,\xa5\x06rC\x87?o\"bK\x17\xdd\xc0\xe7\x9c\xbb\xab\xa1\\\xd8\x1c\xbb\xe8\xec\x920\x8d}\x92\xe8\x81!\x9e\x1c(\x17\x0c([\xf6\x12Fp\x8e\xa9\xe9m\xc7\xe9N\xa3\x90<.\x01f\xc9\x0c,%\xd8\\t:f\xe8\x88\x87B\xa9y$\xc6\x01\x98\x01$\x1e:\x89\xabb|\xe6\x91\x88\x07\x0d:lifWhZ\xbbF\x03fN.\xae\xc6\xbd3\x87\"\x9e\x98kO\xcc\xb4\x1e\xac\x06[B\x86+\xb8\x91K[\xac \x01>\x1a\x92\x91\xc9\xcfi\x11+\xba\x0eCb\xdb\xda\xe9[naG\xc2n\xdd\xce\xd8HN\xe1@\xec~\xb8\xf2\xd3\x05\\\x92\xeb\x04\xfenAG\xdcg\xd3\x176qx\x9a[\x17P\xd9d\xddX0\x84S\x17>\xb65?3J\"\xd3R\xc1\x0d\xa5\xb8\x96\xa5\xf2\x1a\xadn\x1b\xeb\x8f@\xad\x8d3\xf7\xe1\xbaw\x8f\xff\xca\x1d\x8b\xabg\xa5\xf5/\xff\x92\x07\n\xd1\x9f\xd3f9)\x97\xf2\x80\xc5\xcdEg\xc3\x18\xcd\x9b\xd3\xb1\xafZ\x80\x1b-\xb2\x89\xc6\xdc\xfa\x0e S\x1e+\xdb\x08me|=\x1a[#k\x08\xd6\xa8g\xc0`k\x88\xc5\x83j\xb8\xa7\x1b\xa3\xc6\xc0\xfa\x03\xc5\xc9\xcaE\xc0\xfd\xf1hxv\x7f\xde$\x9aK\x0d\x91qzV\xed\xb7^\xa6\x0c\xef\x06(=\x9c\xb6 (\xa3\x01-\x1en\x02\x14\x06\x0e\xdb\xea\xb2\xcd\x9c\x8e{\xe8\xe8Ma\xc5\xfe\xee\x9f\xa1\x8dD\x92]0.\xc0\x1e\xd0#Z~\xd1w\x1c \x9a\xf6\xa8\xf7i4p\xee\x1e\xa0\x05\xbe\xea\xf7\xce\xdd\xdc\x80\x0d\x9c\xba\x9bn_\xaf\x07\x18R\x12Y\xb1\xe4\xc7\xa2\x8b\x8b\x98\x95^\\h\x83~z\xd3iL\x92\x84\xd5a\xbf\xb5\xd5b\xc2{\x89\x89\xbe\xa38\xf5'\x01\xe1u\xf0\xb7\xb6Z\xe2Oy%\xfaK[%\x9b\xfa\x11\xabB\x7f\xe9\xaa\\`\xf1\x85\xb6\xc8KX\xfb\xf4\x87\xb6\xc2\xd4g\xe5S__\x1c\xf1b}\xcf\xfe\x9c\x15\xfbsmq\x10M.\x7f\xce\xa2\x94\x8f!\xffS[9\x9a^\xb3j\xd1\xb4\x12P\x05+\xb0\xa5\xd3/\xdcE\x96\xa6Q\xc8*\xe0O]\xa5\x89\x17\xae=\xb6\xb8\xec\xa7\xbe\xd2*\xf5yS\xfc\xb7\xb6\x9a\xcfgE\x7fh+D|i\xe9\x0f}\x85\x80\x97kc\xc6N\xa2`\x1eG\xd9J\xd4\xc1?t\x15\xa7^\xca\x90\x91\xfe0U\x08\xfc$\xcd+\xd1?\xb4\x15\xa7\xac\xcaT[H\xd8p\xa7D;\xdc)I=?Hx\x15\xfc\xad\xad6c\x90\x9d\xce\xb4P\x9d\xfa^\x101\x9cb?\xf5\x95\xd6\xbc\xc6Z[\xcc\xc7\xa9\x1f&\x87\x82v\xfed\x89\x85d\xa9/\xbc S^~A\xb4 \x9a\xf9$\x98\xa2\xe9`l[\xe2\x0f}\xc5\xb9\x8cf\xc5\x9f\x86\xcaYLD\xc5,\xd6\"\xd3,\x8a\xd0+\x93V\xc2\x9f\xfaJ\xf1\x92W\x89\xb5s\\\xf4\xb1x\xd1\xd7\x16\x0eX\xe1@[\xb8\xc3\nw\xb4\x85\xbb\xacpW[\xb8\xc7\n\xf7\xb4\x85\xfb\xacp_[\x88V\x1f\xb4\x98x\xda\xf5\xa0\xef9P\xd8Om\xa5b\x97-\x8c{l\xc1[\xd1\xb7\x90.\x19\xca\xd1\x1f\xba\n\x8c\xc4j \xac?\x8b1\\&-\xc7\x9f\xdaJK\xb6%\xfc\xa5v?\xf8\xe1*c8\x87\xbf\xf4U\x12^A\xbb+//\x18 //\xb4p\xbc$\xd7s\xc2P\x95\xfd\xd4U\n\xbc\x0bN!\xf0\x97\xb6\n\x99\x93\x90\xf5\xc4~j+1h\x05Zp\x05~x\xc9\x8b\xc3K]\x85\xa5\xe7\xb3\x81\xd2\x1f\xfa\n+^\xae]\xe8\xa5\x17_\xf2\xf2X\xdf\x01 3V\x81\x84\x99\xa9\x82\x9frR\"\xfe\xd0W\xe4t[\xe7w\xc8+p\xec\xc5_\xba*\xa1\xc7Ha\xe8iIa\x181\xbfaV\x87\xff\xa1\xab\xc8\x04F\xac\xc6\xc5Z]%\xb6\xbc\xfa\xe3*Z\xa5\xc5F\x12\x7f\x18*\n\xba\x17\x19i^\x94\xa5\x02\xa7\xd9O]%\xd6\x97\xb6\x93\x95\x17{l\x05\xf0\x97\xb6\x8a?I\x05]\xe5\xbf\xb5\xd5D\x15Sq4\xcf9F\xf1\x87\xae\xe2\xcfX\xe3g]Q\xcc&\x12kg\x123(\xc4Z\x08\xc4\xd9\x05\xe3\x99\xe8\x0f]\x056.\xed\x80\x12o\xc9\xfa\xa5?\xb4\x15\n\xd41#NB&\xf9r\xf2\xdf\xfaj\x81\xc0/\xf6S[i\xe9\x05\x0c\xc5X\nN]\x15L\xa3\xc4\xea\xe0Om\xa5\x95\xc7\x07\xb4\xf2\xf4\xa3I\xe3(d$\x95\xfd\xd4W\xba\xe6\x0c<\xfe\xd2V\xc9\x18\xeb\x9ddZ\xe6;\xc9\x96K/\xbe\xe6U\xf0\xb7\xbe\x1a_\x07\xfd~IY\x1c\x95\xd8\xb6R\xe6\xdb\xa2\xa9\x92\xf3\xce\xa9\x89yN\x19\xd9M\xb5$7%\x1f\xd3\\\xa4\x11\x7fh+R\xde\x82\xd5\xa2\xbf\xb4U\x16\xac\\\x9br=\xcd\x8f\xec\xd4tf\xa7>?\x0e\xe9\x0f}\x85T\xc0\x03#L\xeb\xaa0\xaa\x99jIf\x1a{\x93K^\xeeM\xb44\x9e\x11x-u\xcf\x18\x82fZ\xec\\{\xac\xe3\xb5\xa7\xedy\xedO \x13\xa7\xf0\x97\xae\xca\x15\x17r\xae\xf4R\xce\xc4\x8f\x85T\xc9~j+\x05\xfe\xea\xad\xc7\xd7A\xfc\xa1\xab8%3\xc1\xaf\xcf\xb4$\x82\x04\x81\xbf\xe2\x02$\xff\xad\xab\xc6v\x92\x9e5Yzs\xce\xdd,1\x93C\xb5J\xe0\x87\xac\x06\xfda\xaa\xe0\xc5_\xc5\xde\xd4G3f^\xb5x\xa5\xfbh\xe9%\xe2\x1cO\xb4k\xbc\x12\x10Z\x19\xa0\xb3\xf2\xd2\x94\xc4\xa1\xa8C\x7fk\xabE\xc1\xf5\x9c\x13@\xfe\xdbT-\x9f\xa9\xf8CW\x91\xce\xc9\x0bJ\xb3-\xbf\xd2~$\x88kl\"\xadi\xc4\x89L\x1a\xe9\x89\xfd\x9a\xd3\xc3\xb5v\x1d)Q\xc8\xa9\x83\xb6BNtSFuK5\x0c:\"v {\x07:\xa2:\xbbvn3\xdd7\xb9\x07\xfb\xc2\x9e\xecs\xc7\xd1\xdf\xdb\xd8\x01Yx\xe4\xd0\xfe\xe4`\x8cw\xa0\x03\xd6\xd8\x83s\x8f<\xf5\xf6\x97[\x8f\xebcYT\xdckx\xa8\xe7}5V\xb0\xf0\x8b1\xf9\x18\xd7\xda\xa2\x08[\x92\xcfQ\xe9\x03\xb7\x08\xd6\xab\xf5E/3Z\xe3\xc9\x13/\x8c\xc2\xebe\x94%O\x9fj\xb4\xb7\x81Q\xe5\xeb1s\xb9\xb5m\xe1/\xddN\x00\xd4eQ^ym\xe7\xf7\xba\x86zt\xbaX/\x9f\xb7\xa1\"\xbb\xe0\xc5\xaa\xfc\xae\xd7PQ0\xf2\xeb:F\x1e\xf2\xc08X\x91\xdf'\x9b*\xf2 ck\x11\xcf\xd8T\xd1\x0b\xaf\x870\xb5c\xd9\xf6\xef5^`\x9bA\xf9f\xd6\xa4\x82\x17\x8f\xb8\\*\xe2\x99\x14\xe6\xce.DM\xf7\x8b\xca\x15\xccVal\xe0\xc8\xf6\x1d\x0b\xdb\x12n\xdf\xf0\xa3\x05\x1d\x88\xa0\x03\xd6\x8f\x10\xcd\x8a\x94s\xac f\x05\x0b/\x01?\\S\xea\x93{\xcf@\x18\xa5\x98\xc0\x82\x8a\xdd\xfe\x94\x88\xa9vM\xe9C\xc5C\x11\x14\x13I\x8dCC\xb2W\xf1`D\x89\xf2\xa5yV\x1b\xb0B<\xb4\x0b4\xad\xacD\x17\xd0=e\xc8\xbc\xe4\xf3\xa4\xd3\xf71\x16\x99\x02\"\x0c \x8d\xef\x12\xf6.\xc9V\xab\xc0gi>$\xa8\xb9@>\xae\xc8$%S\xf0B\x06\x9d\xaeu\x9b\xebX\xf1\xe4w\xe0<\xd0\xc2\x04\x9e@\x96\x1b\x06L:\x9d\xb6\xa0\x99aj\xc9\x0c\x93\xe2r\xcc\xa2#\x1e\xd3\xb1O\xe8\xaf3\xcb\x05\xaf\x05\xe4\xe8\x02\xcddCJ\xf4T.\x8c.>c\xb2:sx\xf5\xb91\xdc\xe2\xea\xb7\"\x11\x1eb\xf9\xde\xfa\x82;qC$O7@l\xef\xcb#\xb6\xd7\x1a\xb1!\xf1\xc3y@\xe0\x84x\x93\x94s&\x9f\x87\xe5\x9f\xb3\xf0\xa6\xack\x02C\x7fWB\xbce\xd3\xc5/\x99\x19\xb7^c\xe6P\x14zK\x16)K?+\xf5\xf1\x1a\x8d\x9eM\x0f\xc3\xc1\xae\x14\n\x16\xe3\x0d\x97\xde\xe0h\x8a\xad\xdd\x8c}\xe2\x11vp\x95\xc6Z\xb5pc\x1b\xa2W\xab\xcf\x97Gv\xb1\x92\xf4s\xac\x91a\x8d\x7f\x1c\xba\x1b\xb8(\xbc\x92\xbb%\x91\xabu\xb0R\x1fD\x9bk;\x1d\x933Ge0\xe4\x05\x88\x8b\x05\xf0\x0d\xc0\x0e\xab\x94\x05I\xca\xebhJ\x1a9\x8a\xcf\x81\xa1\x89d0\xbe\xf2w%\x18\xff0\xceM\xcc\xb5\x11\xd0\xf2\xa9\xd6L\x93\xdaq`%+\xb3\xad\xd1\x08\x92:T\xbaC\x8e\x8c\xf5\xd98g\x89\xeb\xf2C\xc8\xea\xf7:\xf0 e\xdd\x85\x97H\xd1\x95\xecI+\xd2\x0f\xf5\x0cZ\x17\x19\xb4v\xac\x19|.{\x06\xff\x00\xd2\x15\x85\x1b\x1c\xd1\x1a\xe9@\x8aTW\x11\xd0jL\x0d?o\xeb\x16Q\xd1\xc4\xce`\x810\x1f\x83\x07O \xcd\x19tO\xf6\x866=tR+\xba\xf2\xe9\xd8\x93\x89j\xed\x04@\x12y\xfer\xfa\xe6u\x91?H\x9bYB~6\xdcih\xb2*\x1f~-\xb6Z\x14\xe2\x89\x99o\xcf\xba\xf3\xf2\x16\xe8B)\xda\xef\x8e2R\xe8i\x16\xad\xbb\xb4\xd2\xa4Y\x14\x13\xba\xa0T\x9b\xa9_~\x8c'C\x98\x0f<\xb2\xb7\xfa.\xe4\xab'\xe2\xf4\x96\xd6&\x87U\x17\x8eU\xb1\x14\x8f\x8f\x05\x99\\\xe6`L\\\xb8\xc8R\x88\xc9\x84\xf8k2\x85?&\xe0\xa5\xe0\x87S\xf2\x11\xfe\x98t-\x17\xce1\x99\x0bA\xe7m\x05l\xe6\xd5\xfd]\xb6`\xef1d\xa5\xe5\xc8\x9a\x97\x03\xa4\x1d\x94\x8e\xb3\x86%\x01(\xfb\xd5&\xe5\xd1R\x02\xed\xb4\xa2\x8e\xd0\x9a\xc6\xb6\xd9\x9f\x86\xadxw\xfb-Y\xb4\xb0&\x15\xcfg.\xe9\x7f=\xac\xc6\x8f\xac\xc7\x1f7\xe44Z p9\xb30\x9e\xb4\xc4\xd9Y\x9bf\x817\x1d`\xac\x84;\xe1C\x82\x1c\xd4\xf5\xdb\x01\x1a\xb7D\xbb\x0dswL \xf9\xe8M\xd2\xdf\x11\xeb\x93\xd6X?A\xacO6\xc5\xfa\xc9g`\xfd\xe4\xce\xb1^\xa0p\x86q\xed\x18\xff\xd4\xc4\xb5\xe4;%\xa0;\xa5\x15J\xd3\xda+\xdc)A\xcb\x9d\xb2\xb5\xda\x0cN\x97\x84\xcbdA=9\xfe!|\xe6M\xf3+\x0cZ\xa0\xf0l\x0c\x06,\xc6\x80\x05\xdcs\xe5\x87\x10/\xff\xd0\xd1E\xfb\x95\xec\xf7\x92:\xa5\xef[l\xd35\xf7s[\xd9\x89\x0bAu\xb7\x07\xedv;\x85\xdb4\x07\xdb\xf4\x1f\xb4\x8f+oo$\xafM\xa8\x06B\xd2\xe1\x8f\xd0Z\xe5\x891x\xf2\x02\xf8\xf4 \xfap\x1f\x0b\xf0\x07\x81!f\x00c^2\x84\xfeR\x03@\xe8\xfb^\x18\x02\x13,\xfc\xa4\xbb$I\xe2\xcd\x89\x14\xf8(I\xbd\xc9%\xbaW\xb5j|j\xc8\xff \xcaC\x9b\x11\xa5\xc8\x85\xcc\x85\x04)\xbc\xd6\xe5\x93>6=\x883\xa6\x89D\xa23\xc1\xa4V.\xb0X\xa5\x9e\xc3S.`b&dE\x8f\xbc \xf0\xc3y\x11j\x0dp\xe7xi\x14'0\xf5c2I\x83k\x91\xe4\x85n\x94(\xa6D\xe3\xe2\x1a\xd2\x05\x81\x1fWq\xb4\xda\xa6D'\xf9\x11V\xde\xe4\xd2\x9b\x93.\xbcO\x08\xfc\x987\xd8E\x865\xff\xd3v~\xa4\xfbl\xe2\x05\x01mb\xd9\x85\x13\xe2Ma\x19\xc5\x84r\xae\x8b4]\x0d\xef\xdf\x9f]t\x97\xe4~\x96\x90m\xfcz\xbb\xe8\xc7\xb8I$<\xc48\xd0\xe3\xe8\x0c\x0e\xd0\xd93\xf7W\x15\xef\x18\x91x\xb7 \x85\xacS\"\x9a~\x82\x86\x97\x94\xf1N &?g~\x8cZEY\x9eb|\xb7\x9f&\\\xd4\xf2\x13\xf8\x91vD\xe9(\x0c\xbf\\\x1f\xb9\xbf\xae\xe8\x88Nn\x08\xa9]\xc2\x91&Op\x90\xaf\xe6\xbb\x17~8\xb5\x19\x19\xda\xeak\xc0\x9b\x8b]~r\"F\xaa~\xd7\xabF\x981`\xfc\xba6\xa4\xa3\xe9@v!3a\xbd\xb8k1_\xe1\xf0\xb6\xe7\xb6\xe7p\xe2p\xd0\xee\xa8(\x1d\xa9K\xfay\xdbS\x95\xbeM\x05[\xcf\xd7\xa9\xba(\xaa\x17\x93\x1eb\xd7\xb6\x96\xf2%W>\x8b\x92\x9b{\xef\xe9\xe13\xf1\x12\x92;e\x0fk\xaa\xf0\x9b\xf7\xba*\x85\xbb\xb8\xbe\x16\x14\xd06\xa5 `\x0d S\x84\xe6f\x0c\x9e\xb7\xac\x19\xce.\x99[\xd1\xbas\x8b\xb6I\x97\xacI|m_7x@\x97=\xdeS\xb9\x89\xbaD\x0bk5Bc\xa3\xa8\xb0.9r\x86\xcc\x913\xe4\x8e\x9c\x93\xa6\xdb\x95\x8d\x1c;\xd5\xe7\xa6\xd1\x0f|+n\x953\x82\xce\xc1\x17)O[9\x98\xc7\x8a\x83y\x1b%\xc2c\xd8\xb2}LhPv\xec\xae\xfd\x12\x8a\xbb\x10\x9fyuK\x0b\xd97\x83f\x03gs\xdd\x98Zr\xbd\x18Z\xa8\xad\xb39*\xaf1\xf1\xc5\xb5\x9d\x8d\xfbg\xad&\x02mt;&\x8c\x16\xe1\xa5\x1b\xbf\xaf\xf6\x7f\xd3\x8a\xcc\xcd\xeb\xbd^\xc5=\x8b\xf1|R\xf5\x85p\x00\xdc.\n9?I\xbd~B\xe6\xc7\x1fW\x85k\xba\x05-\xa3\x13\xf1\x9e\xa4\xfc7\x9c\xd3\x14I\xa1\x18\x95\x18[\xff\xf2/R*B\x0b7p\x835\x19\x91\x07\xc8^W\xe1\xc8\"q\xd1\x81\x8b\x11T2W\x1a\x80\xbb4\xc7\x14\x93\x12\xcb\xe1\\rjW\\i1\xb7\xe8*\xe4\xc5\xda\xcc\xb5\xfa\xebJ\\\x82\xfa\xa8O2\x00\x9e{\xa9\x94\xb1g\xea\xa5\xc4\x90\xb4\xa7\xf2%[\xdb\xe2\xdb\x98\xcc\xc9\xc7\x95\xc6\xeb\xd9\x84F\xed\xe0y^\x8f\xac\xfaT\xd1\xe2\xc4n8\xaa\x19\xd2\xd6\x1d\xc3\x8d\xc7\x9e\x98\xbd\x17\"gS{\x86\xd6\x1f\xc5\xac\x0e\xae@]\x05\x0e\xe6\x16#\xaa\x1bP[\x1a\xd3\x14\x89\xae\xfc\x17\xffH\x8a\x88 #v\xc5&g/\x08\x14I\x05F\x94\x95\x0e\xba\xf2\x8b\xc0\x055\xe8\xe7\xad\xccb\xebb\x01\xe5W\xfaw\xd4\xbe\xd5\xdf\xeb\xeewy0\x84[\xb5\xb6.\xc2\xec\xef=tLa\xc5\xfdV\xf6\xcf>\x7fu\xf8\xfa{C\xbc\x87$\xf5R\x7f\xd2\xae\xee\xaa\x08\xb4\xde\xa26\x8f\xf2\xba\xc1\x07\x0b?\x98\x1em\xfa\xd5\x9c\xa4\xcf\x199\xa0;P\xf9\xe6\xfc\xd5\xf1\xc9W\xc7\xcf\xcd\x9f\xbe\x0c\xfd\xd4\xf7\x82\xd3\x14S=l\xf4\xe9\x914\xdcM>\x8dI\x88\xfe\xbd\xe2\x8b7\xaf\x8f\x8e\x8d \xe4[\xe8[?\x08^\xb1p\xaa-@\x92\x7f\xf6\xdc\x9f\xde\xe2+\xda\xd9 \xbb)\xd4\x80\xd4\x84G\x8b(\xa3\xe0\xe0m\xbc_MK\x10m;I\xf5\xbb6\xe3}\xeeOo\xf3\x19v\x17.[\xc3\xe7\xfd\xeb\xd3\xc3\x17\xc7\xe7\xb7\\\x13\xdd\xd7\x1b\x03Y\xd7\xc8\x06S\xcf\xb0\xaa\x94\xcf\xc1z\xf3\xe1\xf8\xe4\xe4\xe5\xf3\xe3\xf3g\x87\xa7\xc7\x1a\xe6\xa7\xda\xce\xc4Htp#\xc6\xfe\x9aLq7\xbd\x88\xa3e\xcd\x8el\xd3\xd7\xcc\xd8\xd7\xd4OV\x81\x87I\xceZ\xb2\xe4\x80\x84W\xfa\x0eT\xbd\xaex\x0c\xd7F\x82\xa6\xb6\xee\x8d\xb2\x9c\x9a\xd8\x9e\xf2\x93\xdf{\x84\xec\x9e;,\x85\x86\x0b;\x1d\x87k\xb4\xc7\xe1\xd9Fw\\\x1aR\xdaz\xdci\xb7\xf25f\x1b\xfc\xfb\x8d\xab+\xd3\x060\x85\x9a\xa1\xddzT\x86\x01}\xc6X*g\xc7\x06\xc3Q\xbe\xc5\x00G\xea\xbb\x11L\xed\xca[ly\xa8\xad\xbd\x11BJ\xa7\xf1\x06\xc3^Il\xaa\x00a\xfenS\xf8\xe5\xccC\xeb\x01l\xb5\xaf\n\xed\xf6\x10\x94\xf7\x91\x1f6\xb7*\x1e\xc1\xe85\x1b\xf5\x8b\x07\xc7\xa3\xda\x02\x86\xadm\x01A\xe8\xbd(\xbb\x88W\x9d\xed\xba\xa5Odo\xf9.\xfc \xadhy6\x9b\xef\xa3\x0c<\xbc\x10I\xc9r\x95\xfa\xe1\x1c\xd2\x88gi\x07\x0fb\x92\x90xM\xa6\x88)t\xa4.\xfc\xf8\xc7\xe4G\x17\xd2\x85\x97\xf2\x03;\xfc\xe1O)\\\x10\x88B\xbc\xa9\xb1\xf8\x8aZpI\xae\xbb\xf0\x9c5\xe5cn:/,,\xa6E\x8b\xf8\x86x\xd3\xc7\xb4\xce\x95\x1f\x04\x90\xa4\xf4\xff\x17\x04\xbc\xc9\x84$,94o\\\xb6\x17\xff\x93>t\xbe\xe9\x11z/\x04\x9a!\xee\xb5\xeeA\xf5\xd7&\xab\x03\x12\xcf=\xa9.4\x1c\xc0d\x1c\x9eqE}\xfbq@!^F\xb6\xee8D\xbd\x87\xe7\x82\xd5z}\xe9RR\xc8^GY,\x19\x0b\xe3\x0dY\xba\xf0B\x88\xc2 \xe9\xc2\xbb\x85\x9fP\xc8\xcf\x02\x7f\x92\xc2\xd2\xbb\xa6k3\xcd\x08m\xc9c\x87Z\xd7ba\x99\xd7\x91?\xb5Q\x8f\x8ct\x0bo\xad\xe3\x86\x80\x93\xf2S\x7f\x01,?\xbc\x13}\x1ch\xf5in\xd6\\\xe3\x86Q\x99Mh\x9a\x97\xa5\xd1\x85\x1fN\xcb&\xf7\x1b\xdcA\xeb\xd3\xfd\x80d$\x98\xa8\x88E(b%cbF\xacs\xcd'\xf7\xeeQd*\xb3p,tm \x8f0?\xc3\xcc\x9b\x10\x13BEk\x12\xc7\xfe\x94\xa3\xd4,\x8e\x96\x1c\xa9\xe8\xd7\x90\xac\xc8\xc4\x9f\xf9\x13\xb40\xef\xc2q\x98d\x0c\xc3RVkI\xd2E4\x85\x10\x93\xd1N#\xbc\x01\xa6-\x06\xde\x8a\x85\xf2\xc4\x91\xf0jhjH\x1c\x97\xdd\\\x94\xb7\x82\x08\xbb\xfb\xe9\x93\x96a\xbc\xcd\xcc\xbe\xc8V!\xedn\xe3\x90q3\xa7\xf00\x11\xa5\xc8`\x1cZ%\x0d\x7f\xaaL7K(\xd9/&\xc8\x160\x8a\x8bAQ2\xceg\x02/\x19\xe9v\xe1\xa7,I\xf9\xb71\x99g\x81\x17\x17\xb6\xf4.=w\x08\xda\x86n\xde\xff\xc6\xbd\xe9 \xea:\xcf\xd7T\xa8\xe1\x8c;\xde\xc7\xfb\xa4\xf3\xf3\x98\x0e\xf60K\xa3g~8}\xeb\xf9\xb1&\x863\xc8\xac\x83G\x8f\x96P\xddf\x19\xcb\x14\xdee\xdc?.)\xff\xedh\xa3\xd0\x8b\x07\xd7Xm\x8c\x19Vxx\x8d\xd5x*\xad\xb9ch8\xf6Z\x98\x8e\xadp\xda\x95\xfe\x9a/\x02\x03{\xc5\x12\x01\xcd\xaa_;0\x1b{gt\xd2\x93\x86\x96jbQ\xcb\x0f\x9d\xd3BG\x00\x9bF\nu\x86\xd3h\xbd\x82\x01\xc4W\xe8\xe6\xd6g\xa4\xa2+(y\xbb\x13\x0c-\xf5\x9b\x16E~\xd6<\xa4w2\xf6Zr\x8f\x80\xfb\x1b\x03\x9b\x9b\x99\x80k\x95\x00\xf2\xd7\xea\x0e|\x1f\xe6V\x04\x94D\xc3*\n\xfc\xc95\xfc1A\x94\xbe$\xf8\xf3jAB\xb6\x03\xe7\x14\xbd\x8b\xadI?Ab|\xcdV\xbff8\x07\x10\x8f=\xc6\x13\xd0\x1f\x14\x19`\xa8\x1b!\x8b*\xcc\xea\xae\xf3\xba\xed\xa0\xcfCT\xf3\xaf'\xcd\xf0d\x11\xadY*\x16\x8f\xf6\xe3\xe6\x1f\xd7~[\xc3+T\x8f\xf8V\x84~a<\xef\xcbbIds\x8b\xb2\x9a\xfc\x01\x9a\xf7\xc4\x05kI\xe29\x11\x89\x97^G\xcf\xb3U@\x0fd\xf25\xb9Nlg\x08G^H\x8f]\xac\x06a\x14n\xb3f\x12$\xe0\xc4\x01\x8d\xc8\xc2r\xa7\x95.\xf5\x90\xe1k\xec\xeb]\xcc-ZXo\xe9U\xc4\xe9w\xc2\x8e{\xca\xe9'\xde\x92P\x14\x1c\xe2\xd1\xdb\xead}LA\xb4\xc2\xa8\xb3\xf4L`Vr\xa2\xea\xc4\xcb\x12nNv\x15\xa9j[\xdb\xa1G\x9c\"L\xdb\x8e\xe088\xdfMw@i\x9c\xf4p\\\xd0\xb7\x97\xe4:\x11,0gL\x0d.\xaa\xc2\x86\xb0\x15ZL\x9bL\x11e\xf6\xd2x\xee\xa1OI\xd7[\xad\x82k\xccE\xe2\xe6\xde \x89\xc1\xd1\x91>(\xd4\x1a\xbe2\xdf\x8f\n\x9b\xb8\xc2\x11%n\xae\\\x18{\x84\xe6\xd3\x1bC\x1ek\xe2G\x83t\xebf\xfbl \xf0\x87>\xd9I\xbb\xfd\xb8\xfel\xc0\x1b\x01n\x04\xea-\x87z\xdd(*\x10f=\xa7\xbb%\x16`WzR[\xd1\xe77\x06\xfd5A#h@X\xb4\x9e\x9f\xfb ~\x84F~\x9a$\xeb\xa0'\xa9U\xa4]6\x0f\xb0\xa4\xaa\xbf\xf5\x18\xf5\x06/\xad\xc6xn\x1c#\x8fY\xce/\x90Z+\xb7p|L\x1f\x1fwI\xf8sF2r\"5\xc51lc\xe95\x9fpK8 c\x9c-\x15`\xb7\x87\xd5\x859\xd90HV\xa2\xf6\x85|\xab.\xf3\xf6p\xae!m\x05d\xeb\xc8%Q\xaeT\xe3\x1a{P(\xd0\xa4*,\x88|p\x94\xf9o\xecY<%/\xc2T\xdb\xaekP\xf5Cg\x04\x83\xa6\xf6A\xd1Y6\x8b\x05\xc0%\"2\x0e\xa1\x03\xfd\x16|*&\x84\x181\xca\xe4\xdf6\x10\xc2\x0d\xa2\xaf\xc8\xb3\xb7\xe2\xda\xedj\x96c\x91\xd07&3\x0cj\xe6\x96\xf6\x850R\x0f\x0b\x93\xf9T\xe4\x172ODh\xef\xf0\x13\x85U\x80\x03\xedk\xdbiT\xe8E\xb6\x865\xf3\xd0\xb0\xaelO\x86\xcc\xf4\x1f5]\x0caI%_\x8e\xfe\xb9\xbf:\xe5]h\xd7\x16=\\\xe4\xeb)*\x050~\x9fR\xc1\xc4\x97.\xee,G\x81\x88\xa7\xdf\xad\x0d\x12o\x8c\xca\xf2\x92\xb5KH\xae\xe0\xc2\x95_\x96\x82\x88`\x8ef\xb9P\x87\xe2<\xd5\xa0'\x12\xdf\xdb+\xd9\x02\x9c8\x8e\x0b+\x9b\xb80\x17?R\xf1c\x89'\xacz-\x82\xbe\x08\xdd\xa9rS\xa2V\xb3\x1d\xd4U\xc8\x83c\x17\xed.XR\nx\xbb\xdb\xedR\x86\xb9\xaa\xdab\xcb\xe3/W\xcc\x1c\x05<\xf8\x915\xf0#\xe7$\x91\x99N\x1cy\xfe\xd3E\xa64'\x13\x8fJ\xb4\xfc\x83A\x14\x92\xffJ\xcb~ \xca\xad\x8d`p5\x80e\xd1\n5\xa9\xd3Y\x80BM\xc1\x0c#\x12j\nD\x04BM\x91p\xd8\xd3\x14\x89(\x83\xba\"\x1eWPS\x84\x91\x04u\xefE\xc8@\x8d\xd62\x8fa\xa6\xf9N\x0er\xa5\xf9\x94\x85\x052N\xcc\xf0\x15\x8f\xc8a*a\xc1\x174\xa5\xdcU\\7\x05\xe6N\xab\x98\xc3jy\xbe\xb0j:\x19\xbb\x10\x96L'C9\x9f\xeag\x10\x0e\xee>\xc9n\x00\x8a[\x13\x17\xac\xf3s\x92\xbc\x8a\xa6Y@,WA?4\xaa\x1f\xca\xd2\xcc\x0d\x1eI\xfc\xf0\xa9\xa3\x1e|\x8aUt\xce\x85\x98dh`\xef\xdeE\xab\x0b/\x1eB$\xfa\xa9\xd42Y\xad\xde(\x84\xd2\xcd\x89\xfc\x8e\x86*\xda\x94\x90\xfa\xa8\xf9\x89\xbb\x05\x14\xe0\x00b\xd0\x8dMX\xd9V\x1c\xb6\xe0\x1f\xbe(\xd5\x03be\x87v\x7f\xf7\xa1\x9a\x03\xd4\x17E{=]^QVT\xc9\x1c\x9a\xe5E\x95l\xa4^^\xb4\xaf\x16%\xdcfU=\xa8&\xcc\x0fWy;\xa3+\x82-\xed\xef1\x9e\x88\xae\xdb\xae\xa3\xb6\x1a\xf0\xf3l\xdf\xd1\xa5*]\x19\xcfg\xd4'\xa6\xe5uN\xeb\xd7\xd9D\xcdoJ\xd0^\xd4r\x07\xd2\xb9a\xba\xff\xb2{.\xf8\x02\xd7\x1d.\xe9\xea\x9c\x7fho\x88\xb8=\x172\xf5\x03\x9br\x9f\xc8v\x9d\x9f#\x13\xd6s!.*\x11\xc7a^E\xb9 \x1d\xea\\B\xc5\xa5|7\n\xdf\xc7\xc1\xd1\xc2\x0b\xe7\xa4\x95+V!\xe6\xa5^<'i\x9dCN\xd4MH\xca\xc4\x00\xb3\x80\x97\xc5\x81JE\xc5\xa3\xf1\x8b\xbeq!\xea\x06\x917=]\x91I\xab\x01GL\x0e\xebR\xa6\xf7\x10\xeb\nA\xeb}\x1c\xa0\x87\xb9\xae\xc64\xba\ni7j\xba\xf3|\x0c\x08\xb7S\xcc\x8e\xd0j\x18z\xb8\xa1\xe7\x9ax\xb3\x88\x89\xc1.\xa6\x98\xb2Mp\xc0\x14\xae\xd87\x99\xd2Y\xe0\xcdrw\x15\x935 \x85t`\x1b\x06.f\xf6>\x0eZ\x0d\\\xea;b\x82W7\x8b\x83\x0d:\xc4\xb1z\xf1\xa4~\xff\x88G\xc0\x89\xa2u\xd0]yqB\xd8\xd7\x8e)\x834\x19[Y\x1cPq\xdb_z1\n\x91\xd6Y\x1ew\xd2\xac\x9c\xa5\\\xd8\x95\x1fN\xa3\xabn\x10\xf1k~\xdcW\x93\x08#\x1f\xdc\xbfoA\xa7Rc\x11%\xa9\xe6\xf5\xcaK\x17\xe6\xeeXmJ\x98\xf8w\x0b?I\xa3\xf8\xba\xfa\x06/v\x98\xcc^-\x93un\\\xac\xb4,\x97\xc5\x1c<\xa0\x83e@KH\xec{\x81\xffK\x0e8]\x86\xde\x9b*\x1am\xb4>b\xd3\xccIz\x14\x853\x7f\x9e\xd8\x0eE\x8c\x84\xa2\xf4\xd8\xa0p\xc1I\x11I\xc7\xc4n\x86r\x899\xef^\xe7\x12Pj\x88v\xc5]\xb2\xf0B\xa7\x0d\xa5\x81<\xb5 \x99\xbe\x0c\xa7\xe4\xe3\xd0\x90\xc2\x1e8\x03$\xe1\xae1\xcb\xb1\x89FE\xe1\x0b?HI\xfc\xc5H+\x03\x7f\xe0]GYZ\xa6k\xacc\x9d\xfd [t\xae<\xd1\x0f\x02\xc9q\x8a\xb4\x90\xa1F\x14'\x14\xd8\xa6\xf8\x92\n@\xab\xfap\xdag\xe9\xa5\xd6\xf9\x88b\xae'\x9dbL;B\xdfF\xa5\xb7\xe3\xea\xa8\xf1\xbe\xcd2\x1a\x98kl\xc29g\xd5\xbc\"L\xd9\xd4\x8cYf\xa0\xb5\xc6\x992\x88T^\x10\xf4\xf3D\x9du\x8b \xd6a\\\xcau\x86f\xa5*\x11Z\xc5\xea\x8e7\x7f\xc4.q\x9a\x08\x02\xde\xa8\xd1\x1d\x1cr\xa2P\xb7\xe9\x0b\x15\xb0\x86\xe0\x9bU\x981k\x7fc\x1a\x03Hg0v1F\xc7`|e\x0bl\x10OkZ\x03z\x9ch(j\xbc\xb7o\x81D\xe2\x06\xec\x8ep\xe86g\x02\xe7\xd7\xa53\x816\x94\xf3\x1c\xe9\xb8\xd0\xf8vK\x10=C>\xe4\xf6@`Z\xce;\x9dy\xc3\x1eb\x80\xd1z\x07\xca\x0f\xbb\xfb.\x11\x13s\xe5\xb8h\x18!n\xae\x89\xf7!\xb6\xf5\xcc\x98pU<\x11\xab\xf8\x8d!i\x9fx\xd0\xc9\x8f\xae\x93\x1f\xce\xb9\x95b\x97\xffIwHVK\x1e\xbc\x9a\x9bqk\xe6\xf9\x01\x99\x1a\xda\xc4\xf3\xde\xebN\xa2\x00\x15\xf3V\x8c\xd9=!S\xdf\xff\xff<\xcf\xab\xb3\xac\x0b\xd0\x11\x80\xe1\xa7y\x9c+\x83\x0f\xa2x\x16\xb5\xf72<`\\=I\x9bb\x17f\xfa\x15TIW\xd3-+}\xa6\xccFh\"\x8eO\x9e\x9aYh\xadE:?\xdd\xfeP\x1f\xdc/5\xb6\x87\xe2\xe1\x1b'\xa50\xad'v.\xe7\xcek\xac\xa4(\x03\xb6j\x98\x03\xcb]\xd94\x054\x07e.S<\x9f\xdd6\xff\xb0\xf6\xb3E\xba\x0c^Dq\xfeQ\xd5uK<7.\x18\x87\x88\xf9\x95\xf2(f\\`\xf4\xf0\n\x86\xa2\xad\xf9;\xd6g\xd3\xdc\xfci1\xbe\xfa\xe9L\xfd\xc4\xbb\x08\xc8t\x08Y}\xc5(d<\xeb\x90\x116I\xd0\xad\xff\x8e\xaf~PO\xb0\xeb\x808uLL63{[\x08b+\xc9\xb0\xcdH\xc2\xd2\xac\xd6\x01RF\x10\xd1\xf4v\x16\x07\xdb\xfcS\xe3\x87)\xaa\x8dY\x9a\xad\x1az\xaa\x01({c\xfeFl\xa5\x02\x94Y\x1c\x98\xab\xb7Z\\\x9e#\xd1pi\xea4\xef7\xffV@\xe4\x19\xbek\xe1\x13\xf8\x93\xcbaem\xf5\x03u\xc1:\xfe\xb8\n\xa2\x984\x05;3\xa2\xc4\xd4_\xb7F\x88\x14\xb5\xd4\xfa\xcd_\xb7\xf17\xe9\xe3*\xf6V+\xf2\x85;a\x13\xd9\xbem_\x91 b\xe6\x8d\xb6\x9c\xd7\x0efA\xfc\xf9\"\x1d\x82\xb5\xd3\xab\xc1\x86+\x7f\x9a.\x9a*%\xf1d\x0831\x90\x1a6#\xa0\xfd\x9d^y\xf39\x89\xe1\xfdK\xc3\xack q\x89\x80'\xac)\xcb\xa9\xfb\x04\x13v\xb7]\x96\xd2^\x11\x8bS\xb7YN\xb3\x8b\xa5\x9f\x0eaaZ\xc1Uw\xe9\xad\xda3\x0b\x92\x04\x9et'A\x14\x8a\x898\xf4\xd3\xfa\xe3\x87q\x06f\x9an\x92\x7f\x1d\x1d\xa5W8\xf73\xc7\x95\x9a\xbe\x91\xa8R\xceCK\xdb_\xbe\xacb\x90Qojd\x18\x94\x02\x80`J~\xccxy\x7f\x15\xce\x1f_x \xd9\xdfu\xfd\x0f\xcf\xde\x9c\\\xf5\xbe\xfej\x1e\x1d\x1e\x1e\x1e\xbe>}\xbf8~??<<|\xb6K\xff&G\x87\xaf\xe8\xbf\xaf\x1e\x04\xfb\x7f\xa5?\xbe\x7f\xf1\xec\xd5\x87\xe3\xf7\xb4\xc2\xfb\xd9\xd5\xad\xfe\xeb\x05\xbf<\xbb\x1f\xf6\x9e\xcd\x16\x1f\x9f\xad~\xba>\xea}\xdc\xbd\x7f\xff\xfe\xfd\xce\xcf\xeb\xdd\xa3\xbf\xac\xfa\xcf{\x8f:\x9dY\xbast\xff\x97\xbd\xfb_\xf7\xf7\xef\xbf\xdfy\xf0\xe8\xfd\xec\xea\xf9l\xef\xe1\xfd\x9f\x1f<\xea\xbc\x8f\x07\xcf\x07'G\x97\x8f\xe8x\xfe\xfc\xdd\xc9\xe9\xbb\xe0\xd5\xe1\xf1\xf1\xe1U\xf8\xe8\xfe\xfd_v\x0e\xe7\xeb\xdd\xfb\xeb\xef_>\xbf\xaf>\xef_\x91\x9f\xfc\xfe\xe5\xe1\xe1\xe1\xf3\x87\xa7\xefO\x9e}\xf8\xf3\xfcY\xf0\xb7W/\x0e\xa3\xbf^=?|w\xf2\xf1\xe2\xbbg\x0ff\x9d\xf5\xdb\xaf\xc3\xe0\xbb\xc3\xbf\x85\xfb\x97\x83\xc9l\xe7\xf0\xd1/\xf7\xdf\xce\xde\x1c=|\xf9\xf2\xfb\xd0\xdf{\xb1\\\x1e>{\xf5\xf0\xc5\xab\xc5\xd5\xbb\xfe\x83\xc9\xa3E\xb8\xf0\xff\xf6M\xff\xe8j}\xfcM?]\xbe}\xde\xfb\xf9\xf4\xeb\x9f\xf7\xe7\xdei\xfa\xed\xfd\xcbW\xdfy\xe1\x87\xe5\xe1\x87\x93\xe7\xef\x83?\xf7\xdf\xac\xb3\xec\xdd\xcb\xd7\xd1\xfe\xe5\xa3\xde\xe9\xc7\xd9\xc3\x9f\x937\xe9\x8b\xfd\xf9\xeel\xd6\x8f\x92\xb7;o\xc2W\x93\x0f\x0f\xa6\xbb\xab_\xa6/\xdf\xa7Y?:\xdc\xfd\xd0{\xfe\xb7\xe8\xeb\xe5\xc7ep\xfc\xfd:}\xfe\xfe\xa7\x9fNw\xd2\xe5\xd7\xcb\x9f\x9fuV\xdf_?\\=\xef\x7fx;{\xf0\xd3\xdb\xe3\xde\xcb\xdd\xde\x9f\xff<\xf1\x9e]\x85\x19\xd9\x9f}\xf5\xcb\xfc\xfat/\xfd\xee\xe5\xfbG\xfbo?<\x88/\x9f\x7f\xfb\xe7\xd7\xdf|\xe8=\xffz\xf7\xc5e\xf4\xf5\xf2\xc5\xea\xf5^\xf4>\\\xfb\x0f\xbf\x8e\xc8\xe1\xe0\xfe_\xbeK\x96\xdf\xfd5\x8b.?\xf6\x12\xff\xa4\xff\xd5\xc3\xf4\x9b\xcb\xd7\xfb\xe4\xd9\xa3\xe4\x9b\xab\xbf\xac\xee__/'\xd7\xde\xdb\xfb\xef\xe2\xb7\x9d\x93\xb7\xcb\x8bW\xaf\xfc\x8f\x93\xbf|\x98\xbf;\xe9{\xef\xff\xf6h'\xfa\xea\xbbd\xfe\xdd_\x0f\xbd\xaf\xf6\x8f\xaf\xe8\xb2\x1c\x9e\xbe\xff\xf0\xe6\xe4\xeb\xbd\xa3\xef_\xbe\x1c}F\xd0\x19\xd2\xbd\xb8N\xc97Lj\xae\xd3.\n\xad\xe2\xc4N5\xf2\x18\xaai\xc6=\x8d\x84\xc34-\xaa\xe9\x1c'\x16;\xf0\xcf`\x87\xd0\x81\xd8\x81\xfb\xb0\x0b\xdb\xd2]\xe9\x8d\x0b\xa4\x9bF\xcf\xaeS\x82\xa6a\xf5\xd7f\xb9\xe9 \xb3\x10\xc4Q2\xcb\x17:*\xe6\xfc:\xee\xf3\\\x14!\xb9\x82\xa8\x92\xe4\xa7\xc6N\x03\xc7I\xa0C+\xb1q*f\xc3x{\xe6BF\xe99%\x06=\x97\x05q\x86\xa7\xd0\xc3\x0b\xe2m\xd8\x85!\xad\x120\xfb\xc5\x00\x9e\xc0\x8c\xfe\xd3\x19\xc1\xae\x83\x90\xf5\xc7iw\xb2\xf0\xe2\xa3hJ\x0eS;p\xce\xe0\xc9\x13\xe8?\x84O\x95\"\xe8@\x9f\x17\x0f\xf4\xc5\x03V\xbc\xaf/\xddq($\xc6I\xa7\x83\xe6\xfa\xf0\xf4)\xf4\xf7\xe1\x1e\x0c\xf6\xf6\xd4\xf7\x0f+\xaf\x07{{pO\x0d-5@)\x9bI\xcf\xe6\xc9\x18\x06K\xe7\xf2\xf4)\xecV;Q\x18\xb3~\xab^\xfa\xbdZ\x90\xed\x9a!\xf6\xf4)\x0cZ\x03\xc0\xd1\xa2\xb4WF\xe0Y\x1c-o\x87\xc2B\x97\xc5\x8d\x12\xe0\x8f\xb0\xc3\xc2=\x8e9>\xf782\xc36\xf8,\xc7\x83G\xff\xe9\x8c\xa0\xbf\xbf\xf3p\xc7\x81\x88\xb1\xe13\x8a\xe0\x99\x8b\xd1n\xb1\x04\x9e\x82\x07\x07\xe0\xc1\xb0x\xa7\xb2\xc0\x0c\xd2>\x1c0@\xa7c\xda\x0d\xdd?\xbc\xd1x\x8c\xc0\x19\x9c\xd1\xcd;&\x0c\xae\xf7`\x7f\x87\xbe\xb0F#\xcbq`\xc8\xb1\xc2\xcf\xd7\xcbf\xed\x0cp\x1d\x1e:\xd016\xdc\xef\x89\x96)b\xe4-\xf3\xae\x06RW\x15\xee=\xbf\x93\xfe)\xf2C\xdb\x92\xec\xb4$E\x91d\xc5\xc9 \xea\xf3\x7f)\x84\xa5\xf8\xab\x92\x9f\xdc{?L\x1f\xb2u<\x90\xff\x18\xb2\x90\x88lQ\xac\xc3gG\xcf\x8f_|\xf5\xe7\x97\x7f\xf9\xfa\x9bW\xaf\xdf\xbc\xfd\xeb\xc9\xe9\xbb\xf7\x1f\xbe\xfd\xee\xfb\xbfy\x17\x93)\x99\xcd\x17\xfeO\x97\xc12\x8cV?\xc7I\x9a\xad\xaf\xfe_\xea\xde\xb4\xc9\x91d9\x0c\xb4\xdd/k\xf6\xfe\xc2~q\xa4\x86\xdd\x99\x83\x04\n@\xdd\xa8F\xd7\xeb\xd7\xd3#55\xd3\xfdl\xaa\x1f\x9fH\x00S\xcaJ\x04\n9\x0dd\x82yTW\xcdT\xafQ\xd2R\xa2H]\xdc\x95(R\x07\x0f\x1d\xe4.IQ\xa4\xb4\x07wy\x99\xed\x9b\xf9#\xfa\x03\xfb\x17\xd6\xc2#\"32#\"\x13\xa8\xaay\xd4\xc2\xac\xbb\x00\xcf\xc88=\xdc=\xdc=\xdc\xafo\xbe\xec\xf5\x07\xbb{\xfb\x07\x87G\xc7\xed\x1d\x8b\xa7\xcbat\xa4\xc8g\xe9\xc1\x13HN\xa0\xdd\xf6\x1cqS+\xc3+b\xc18\x93Q\xd9s\xe8#O\xe7\xec\xe0\x9b\xa9z\x9e\x1d\xa4\xf4\x14\xc35\xc0O\xc0\x1e%c\x0e\xa4\x8b8z\x87\xc4\x13\xa3\xba\x15Q}\x99\xc3W\x178\x1bAO\xd0\x0b\x02\x1e\xac\xb2e\x1a\xac\x97\x98\xf0f\xaf\xaaE\xbb\xca\xef\xe7`\"\x95\xd7s\x9b.\xa6v-;\xfcN\"\xb0x\xad#\xbc\x03=\x0eq\xa3\xe4\xf1\xc8\x87\x8c0\xd3\xfeN\x8b%\xd7\xcc\xc3\xdcD\xf1s\xa4\xe0\xa1\x90\x85+.m\x90\xad@H\xff\xb4G\xb0\xeb \xc2\xd8)] Jr(\xf5\xec\x1f\x1c\xf6\xfb\x07G=\x8a\xd7\xf4 \xba\x8c#\xa6St\xdd\x1f\xf0'\x8c|\xb0\xe7\x03*\x9df\x02\xf3\xed\x88y\x18Q\xfc?\x92p>B\xc8\xa0\n9\x90\x00\x07\xbb\xf0\x08\xa2\xea\xad+>}\x99f+\xe4\xdf\x82\xb1\xd5\xb1d\x0c\xea!\x06\x1d\x0c(jY\xe7\xbaG\xbbZyC\x9eM\xd2\x8d\x897\xab\x0b\xbb\xa7\xa0\x02\x0b\xabM\xe7\xfa\x08>\x84\x80\xca\x02\x942\xa8\x12\x05\xdd\x17v\x9f\xce\xab\xe7\xe8K\xf80\x82\x04\xe7L}F\xd9r\xe7P\x85\xa3\x9f\x10\x9cb\xc3}\x18BO-\xb2\xe6E:\xf4\xb9\xa6\xea\x05K`\x04m\xa8\xe6T@\xc4B^\xbff\x14f\x01\x8f\xf8\x18:s6\x08X\xc0\xd3\xa7#\xe8\xcc\xa9\xe4\xd0\xa6;\x18\xe6t\xdb\x9d`\xf9\xc1\xfe\x01|\x88\xe1\xb2E\x03.\x88\xfa\xe6\xd0\x19\xc1\x91\xa3i\x91\"p\xa4\xb6\x14\x95[\x8a\xf3\x96\xb2\xbc\xa5l\xf3\x96(\x91`7 #\x07\xfb\xda\x87N\xf5\x06\xaa\xe1~3}5\xc2W\x8b\xcc3\x19\x9c\xc2+\xef\x15\x9da\xd8\x81\x1e\x15\xbc\x16\xf9\x9ck\xf44\xc8\xf0>\xf5\xd2Ew\x1d\xbd\xb3\x07\xec\xee[D;Z\xbe\xc8\xaa7\x17KU\xe3\xa8?,U\x15Q$\x94\xf6\x0ce\xe8\xef\xe2 \xad^\x93\xa9\xcdiBq\x9b\"6\x0b\x19\xcf\xd1\x9b\xd6\x1c\xe8\x91w\x9e\xa3\xb7o@o\xf4\xb00\xa07\xc5\xd1\xc1n\xce\xbc\xe5\xd1t\x06{\xb4\xc2\x12\xe8\xf0\xd0\xd1\xe3:\xc5\xe5\x98\x93\xd5H\xdf\x8d\x19/B\xa7\xaf\xa3y~\x85\x12\xd4\x13\xe8\xc1\xed-\xbf#\x8b\x8e\x1b,K\xc4\x13\x14\x8cq\xa7i0\x97\xce0v\xd4\xbbH\xd0-)H^y\xafl\x82>\xf2\xcc\x90\xca\xd0\xe3\x14lJ2\xf2\xc7\xbcJF\xbc\xe7tp\xb8\x0b\xb0\xae\xf92\x8ab\x1b\xbf.\xa3KZz\x87=\xf8\xe4\xd5\xc0q\x81P\\K\xa0\x8cM\x9d\xccq\xe0 \xf4\x91\xf3d\x9d\x0ee\xcb\x1f\x8e\x80\x96\xa7\x07\x82\x11\xee\x94%<\xa5\xfd9\x855\xec@\x02CXW\x10\x89n\x89\xa5CQ,\xa1E\x07\xac\xb6v\x9b\xd6\xb6\xc3j\xcb\xeb\x99\x8b1\xc9\x83(\xb5\x82Om\x82\xb5u\x18\xe6\xca\x8d\x05\xac\xb6\x11,q\xf8\xc8\xbd*E\x96\xe6\xf7F\xd0s\x9c\x13\x08hcG'(\x9f\xb5aQ\x88\xbd\x1e\xa5T\xed\x11\xcc(\xad\xdeAzA\x85\xa7:\x12\x94Qd\x0e\xe0\x96\xbe\xeb\xd3w\x83\x13\xf0\x19\xc5Q\xaa\xcf\x8a\xea\xb3\xbcz_W=\x7f\x15:0\x9b\xc2\xed\x08\xfa\x03\xba\xb1\xae*\x1c\xae\xe1P,+p\xca\xdb6\xf7\xea\x0c\xed\xdd\xc1Q\xe5\xc8[x\x85\x96\x1dk7i\xb2\xb8\x921\xd08\xdb\xc6\xdd\x9f<{\xfd\n\x1d2\xf9W\x9d\x87M\x9e\xe6fXI{S&yMW8\xccwS\xf2\n\xf9\x85\xdd@{[w\xa3\xf1\x9a\xf4\x0e\x92g\xed\xa8\x14\x0d]LPd\x87\xf6\xee\xae\xe2w\x1c\xf0GG{\x8e\xd6\xa57\xfa\xf1\xba\xf4n\xe3\xdd\xde\xa8KU\xd3(H\xf9\x185q\xbbh\xf9\x8a\xe3.\xf3\x11\xa7\xef9\x1b7\x0b\x924^g\xa5\x8eq\xa5j\x94\xcaxM\xd8\xfc\x9c\x12\x03\x161\xc1\xe0\xc3\x11\xdf\xd4(\x8a\x8bP3\xeclT\xf5\x83vN\xa0\x85>\xfaH\xf2\x92Rv\x00f\xee\x0fy\xbc\x0b\x9e\x94\xc0\x85\x16z\xce\n\xa7!\x96\x1f\xc19\xe1\xe34\x18\x85\xde\x83\xef\xb1\x84 u\xda\xf0\x88M\x15\xcb\\n\xa8g\x1e\x84\xderY7\xe4\xfa \xa1\x9f\x16\xfa\x13%]\xbe\xd4\xd2w\x83\xd3\x18l\xd84\x08\xf9L\x9c\xfb2su\xfa\xf1i\xa1\xda[\xf7X\x9ca\xa7:\xe7\xc5\xa9\xf3\xcd\xcd\x9aTN\x9e<\x80\x12\x0bV\xc5\xeeYf1\x8b\xe1\x11\xa4$\xf6.\x96E\xc0\x7f\xe5\xc2V\xd14{\xf2 \xbcb\xb7\x1a\xdb\xfa>\xbc\"\xb4\x8f\xf6\x1d\x17B\xfb\xf8\x00=\xa5\x8b\x0e\xd0\x96\x06\x1bu\xbb\xe07\xfd]\x1d\xc7 \xed\x03\xc7\xb6p\xb6\xd2(\xaez\xea\xb0\xeb\x80\xbb\xa6x\xe1\x94\x89u\x83\xe4\xa5\x98\xebM4\xc89\x85\xd2\x9eUyD\x15\xdc\x8a\xe3\x80\xa5t\xf8\xeew\xf3\xee\xe1\x9d[L\xb7U\x8d\xc9\x12\x97|k7\x9a\xde\x0dWt\xefAWtww_Y\xcb\x81\xd3\xe5w{\xbc$ .\xc3Mj\x92\xd7U\x9a\xca\xd8\x8e\xbbg\xd0\x86\xb8\xfb\xb1\x0b\x16\xabU1\"\xb2V\xd8\xe8\x0e\xa4I\xdb\x08\xa1\x9an\x9a\xeeU\xaf\x94\xf2\xa8\xef\xbd\xaa\x14\xc5p\xeb\xa0:\xbd,F\xfd~5v\xbc\xc7j\x19T\x8b'9J\xf1\xc9\xd3cj\x0b\xbd\x07C{p\xec\xd8F>-\\\xf1\xbe\xd2\xc4e \x068e\x9a,\x91\x88\xceQ\x0d}\xc8t\x9a?K\x8b\xfd<\x80\xce!e\xe9\xc9z\x19\xa4\xb6e9\x1a\xc7-\x1d\xeb!\xe3t\xaap\x9b\xf7\x8e\x0b\x87\xd0\x1aA\xc2\x82\xd5:<\xcf\x91\x9c\x1e\x91=\"\x8e\x93\xab\x89\xe8\x0b\x92%\x86\x1e\xabj\x85\x88R \xe6\x0cm/t\xces\x911We\xd3\xf3o\x9f\xd9F\x82\xee\x9cYC\xa2\xee\xfc\x84\x9e\x8b\xc0\xd7\xe4\x15\xcak^\xbbx&\xf5\xec\xbc\xd2\xb1\xdfnO\x1d\x17\xcf\xa1\xf4\xd0\x14\xdb\x0b\xa7\xebG\xa1\xef\xa5\xf6\xdc^\xa0\x02\x9a\xc2\\<\x89\xce\xf2>\xdc0\x0b\xcc\x15<\x85\x9b\x13\x07\x96\xec\x9e\xd3\xc2\xc5\xb3\xf3l|Cke\xe2\xc2xM't1^\x1b\xf4j\xd2MK\x18B\xb2\xc9\xe6\xd9\x90\xe4<\xe4\x81\x83\xd6w\\Cr(\x0elRO\xb1\xc3\x95\xbd\x19\x88\x8d\x7f\"\xb5\xda\xdf;vl\x8b\xd6n\xb9[\x88\xc65f\xb8\xc0\x8e\xa9`[Fp M7\x19E=\xf5\xda\xf9\xdc\xfe\x89A\xefv\x928\x1f\xda_xW^\xe2\xc7\xc1:\xbd\x9dy\xa9\xe7\xec\x04+u\xd4;\xe3\xcf'\xd7\x83^gr}\xf8b\xbasY-\x12\xb1:\xc7\x9f\x0f\xa7mg\xb8s\xb9RI\xdd\xd8\xeaZ.X;\xb2\xef\xb9\x19K\x12/\x0c\xd2\xe0K\xf2\x83x\xd9t\xf3@\xd8\x92\x98R5\x15\xd7~\xe8Y\xce\xd2y\xb4n\xb4\x12 k\x95\x85\xde>\x1d\xf7\xa6\x0e<\x85\x8e&'\x95\xed9\xdc\xd6\x84\x8a{\xaf\xbb\xa2\xd2\xb3\x1d9\x8e\xb0-1\x0bm\xdcMI\x922\x15\x8e\xe5]DY:\xbcXz\xe1[\x0b\x86\xe0a\xc4<\x19hB\x81M0\xa0\xc0\xe3\xdd=\xbd@\xb4\xbb\xbf\xeblc\x1e\xc6`\xf8\xdd4\xfa$zG\xe2\xe7^Bl\x0c\xd1\xda\xa6C\xa6t \x03\x96W\xe3\x9e\x1a$\xaa`\xbb!\xec\xe9\xc3:\xf4\x0f\xef\x1e\x98\x027Yy4[\xcaUE\xf7\x0e\xaa h\xf8\x04\xefU\xb98\x93\x05\xaad\x8f\x89\x02\x87U\x81\xc2\x03\xae\xfeS%\x81\x98N\xb8\x14\x93e\xc8\x05\xcarIf 8\x85\xa4+\xf2\x87\xe5\x05\xebg\x0d\xb3\x12V\xe6\x0d\x03k\xf2\xa4\x8e\xfal\x80\xaa\xc2<\x92\x93\x1b\x06<\xdfX\x1b,K-\x9a\xc9E}8\x05_\xa4\xfb\xa3\x9b\xa2\xf2\x82\xe0\xc1DS\x19\xaf\xc2\xeaa/\xc3B\x15;\x1aA\xc7\xa3\xdb\xae\xd3\xa3\xbb\xad)~\x80\x89\x9dm.!t\xfa\xdc7\x83\x07\xc1K\xb9\xa2\xb9l\xf2f\n\x90\xd89\x81v;\x84'\x10\x9f8\x10\xf0\x00\x83<\xbcv\xa8\xe6\xc6\x16s\xfa\xa0\x18\xcb9\xa5!~.Z\xed*\xc7\x11\x15\x8f\x83\x1c\xd7TdfX+\xe5\xb2\xdb\x10\x1d\xcd\x87\xac\x88\xdf\xde\xc6\xf0\xa4\xa5\x12 \xae\x86(qW\xf5\xda\x86\x94G$5\xe8m\xc4\xccUB\xd8\x95\xb4$\xef\x95.\x06h\xdbf]\xd4/`\xcc\x9d\x06NE\x07B\x18\xc2\x8c,IJ\x10R\x8ap\xd8\x8c\xa8\x02\xf5\xaa+\x99O\xfa\xb6\x13-D@1\x88\xbb\xe2\xdb\xee^\x95\xe8 \n\xaeO\x92\xb5\xbb\xaf\xcb\x92\x85\x8c\xe0\x8eC\xc8\x0bhu\x83\x04%zSx\x01:\xa5\x01c\xda\x11\xa3H:r+>\xcc]\xe5\x149>\xe5\x88hZF\xb3\xb2\xbe|\xc2\xcb\xc7v\xe8B_:\x9e\xd0w\x93e\xe0\x13\xbb&\x91\xb27N\xa76\xa5\xaaI\x193\xef\xbeR&-H\x93\xa8 0^\xefe!0)\xdfd\xdc\xd7\xe1\x14\x02J\x8dQK\xf9\xe8\x11\x84\xf0\x94\xd9\xf4R<\xd7\x88\xa6\xb6\xd8\x03\xdbv9f\xa4Z\x99_\xf3P\x98YOx\xfbt\x08<\xc5\x1eS\xda\x1e@\x1b\xbd6P\n\x0c\xf9\x03\x1c\xa0\x93\xbf\x84a\xfc\x02\x87\x91\x7f\xfar\xc8_\x0e\xa1\x83\xceXO\xa1\xe7\xb2/#\xad\xd9\xf0\x8aG\xbc`\xac#@\xd6\x11\xc3\x13\x08N\x1c\x88Xh\xb1t\x1c\xd3\x9e\xe8\xfd\x11\xa3;\xe3\xc6~u\xb76\xed\xe2A#.\x19\xe5\xb3\x94m\xb7\x94\x1dp\x1bIO3\n\x18ZJ\x0b\x15\xc4\x16M\x08\xb2`\x8d'\x93lv\xd4\xebu\xe8\xdf\xf9|>\xad\xb8\xa3\xc7\xa2Po\x97\x15\xea\xed\x1e\xcc'\x93lN\x06\xf8sN\x06\xf4\xe7\xa07\xc3\x9f\x83\x9eZ\x05\x9dd\x0b\x9b\xd9\xf5\xc7\xac\x99\x0bSs\xe8\xd85\xfe\xbc\xa1S\xe8\xc3e\x9f\x0e\xe5Jg\xe4\x00\x8b\xcf\xe6\xf3\xa9\xf3\xd5\xe0\xbd\xa52\xf0\xf2`/\xe6\xf3)\x02|sC o(\xcfk~\x9b\xe7Fw,\x16\x89A\x95Y\xb1\x999\xe9\x11\xf6g>=\x15i\xefm\xde\xe9A\xaf7\xe3\xb5\x8e\xb9G\xcd\x94\xd3\xcd[\x0bEL\xc7X\x87\xe5|XU\xff\xce\xa5^\x8e#\xd1\xd5S+\x0f\xed\xe6BX\xad\xbf\xd2\xef%\x8cx\xb6X\x1bGg\x9f\x8e\x8a\x91\xe2\xa0\xe7\xd0\x06\xdf\x05\xeb\xd2\xba\xeb\x9eH\xf9\xa9r\xe9\xb0+\xc2w\xdf\xc6\xd5s\x898\x10V\xa3\x01\x8am\xac;\xb1\xf0\xd1Z\xe3\xc7\xff\xe5\xe7~mj\xddkd\xf5\xccY\xc8JvdS.\x9c\x1f\xf13<\xe2;\x18\xb7\xc72\xdb=\x1a\xf7rC\x02U\x13\x9f\xd31\x8d\xa8F\xde\xd7Pr\x14\xff\xa2\xdc\xdf/\x1d\xb7\xdb\xc1\x14\xe9y\x00O :q\xd81\x87\n\x06\xe98\x98\xa2\xeb\x8dA\x92l:\xcf\xd4`\x83A\xcfU=s\xa3\x96g<\xb9\xf6{\x9d\xc9\xf5\xec`r=;\xeaL\xae\xe7\x07\x93\xeb9~\x99O\xb2^\x9f\x92\x82\xac\xd7?\x9cOw.kpf[zx\x1f\xe4\xb2S\x14\xdfR\xc7a\x96q\x81>\x11]\xdb\n2\xdd}\x12\x0f\x9dJ\x90\x03\xebG?g\x0d\xc1zV!\x14\xd6\x8f\xfe\x96\x1e\xfc\xb7\xf5\xe0\xbf\xa3\x07\xff\x8fz\xf0\xcf\xeb\xc1\xbfI\xc1\x9e\x02\xfe-=\xf8\xdf\xe8\xc1\xffV\x0f\xfewz\xf0\xbf\xd7\x83\xff\x1e\x05?W\xc0\xbfC\xc1\xbe\x02\xfe'\x14\\M\x91j\xfd\xe8\x0f)x\xa6\x80\x7f\x81\x82\xab D\xad\x1f\xfd}=\xf8\x17\xf5\xe0_\xd2\x83\xff\x17\n&\n\xf8\x7f\xd5\x83\x7fW\x0f\xfe==\xf8\x1fP\xf0K\x05\xfc\x0f\xf5\xe0\x7f\xa4\x07\xffc=\xf8\xf7)8P\xc0\xffA\x0f\xfe\x03=\xf8?\xea\xc1\xbfL\xc1\xaf\x14\xf0\x1fQp\xf5\n\xab\xf5\xa3\xff\x89\x82_+\xe0\xffY\x0f\xfe\xa7z\xf0?\xd3\x83\x7fE\x0f\xfeU=\xf8?Qp\xa4\x80\xff\xb3\x1e\xfc\xbf\xe9\xc1\xff\xbb\x1e\xfc\x7f\xe8\xc1\x7f\xac\x07\xff\x1a\x05\xff@\x01\xff\x0b=\xf8_\xea\xc1\xffJ\x0f\xfe\xbf(8S\xc0\xff\xb7\x1e\xfc'z\xf0\x9f\xea\xc1\xff\x9a\x82\xab d\xad\x1f\xfd\x19\x05\xdf(\xe0\xbf\xd0\x83\xff.\x05?S\xb7\xc3oS\xb8\xa7\xc2\x7f\x9d\xc2\xdf,\x14\xf8\x9fSx\xaa\xc2\x7f\x83\xc2\x93jH#\xebk=Y\xfeZO\x7f\xbf\xd6\x13\xda\xaf\x91\x88+\xe4\xed\xeb\xbf\xa3\x07\xff\xbc\x1e\x8c3\xa0\x10\xc3\xaf\x7fA\x0f\xfeE=\xf8\x1f\xe8\xc1Hh\x15\x8a\xfa\xf5\xdf\xd7\x83\x7fI\x0f\xfe\x87z0\x92 \x85,\x7f\xad\xa7\xd6_#eR\xa8\xf5\xd7\xbf\xac\x07#\x99P\xe8\xef\xd7\xffT\x0f\xfe\x15=\xf8W\xf5\xe0\x7f\xa1\x07# R\xf0\xed\xeb\x7f\xa6\x07\xffs=\xf8\xd7\xf4\xe0\x7f\xa9\x07\xe3\x9e\xfd\xab\n\xf8\xd7\xf5\xe0\xdf\xd4\x83\xff\x8d\x1e\x8c\x9b\xf3R\x01\xff\x86\x1e\xfc[z\xf0\xbf\xd5\x83\x91\xd9\xff5\x05\xfc\xdbz0\xca\x00\xca\xc6\xfc\xfaw\xf4`d\xb1\n\x07\xfb\xfaw\xf5\xe0\xdf\xd7\x83\xff@\x0f\xfeC=\x18\xd9\xb7\xc2\xd8\xbe\xfe==X\xcf4\xbf\xd6s\xc7\xaf\xffH\x0fFv\xf2\x93\n\x18\xd9\xc9\x17\n\x18\xd9\xc9_W\xc0\xff'\x05\xbfU\xc0\x7f\xac\x07#'\xf8D\x01\xff\x89\x1e\xfcgz\xf0_h\xc1\xdf\xfc-}i\xe42\xd5\x981\xd6\xd7\x7f\xaa\x07\xff\xb9\x16\xfc\xcd\xcf\xe9\xc1\x7f[\x0fF\xd2\xabH#\xdf\xfc\xbc\x1e\xfc\xf7\xf4\xe0_\xd4\x83\x91 (\"\xcd7\x7fW\x0f\xfe\x05=\xf8\x97\xf4`\xa4\xdf\x8a\x90\xf2\xcd?\xd2\x83\xff\x89\x1e\x8c\x84Z\x91/\xbe\xf9\xc7z\xf0/\xeb\xc1Hc?S\xc0\xbf\xa2\x07\xff\xaa\x1e\x8cT\xb3\x1a\x93\xc1\xfa\xe6\x9f\xeb\xc1\xbf\xa6\x07#\xa1>S\xc0\xffJ\x0f\xfeu=\xf87\xf5`\xa4\xc8\x8aT\xf0\xcd\xbf\xd6\x83\x7fC\x0f\xfe-=\x18)\xf2\x1b\x05\xfc\xef\xf4\xe0\xdf\xd6\x83\x91\xf4VC\xe4X\xdf\xfc{=\xf8w\xf4`$\xa6\x8aP\xf8\xcd\xef\xea\xc1\xbf\xaf\x07\xff\x81\x1e\xfc\x87z\xf0\x7f\xd2\x83\x91\xc6*\"\xe47\xbf\xa7\x07\xff\x07=\xf8?\xea\xc1\x7f\xa4\x07\xffg=\x18I\xef\x0f\x150\x92\xdew\n\x18I\xaf\"\xe3~\x83\xa4W\x11f\xbf\xf9c}i$\xbd?\xa3\x80\xffD\x0f\xfe3=\x18\x89\xe9\x97\n\xf8O\xf5\xe0?\xd7\x82\xbf\xc6\xd5y\xa92\x1e\x9c\xab@\xe1<\xdf\xb0\xe3\x9a\"\xb9|\x83\xc2R\xa4\xc2Q\xb0|\xac\x927\xe4\x1bI\xe1\xcab\xf2\x08a\x8ex\xdb\xab\xe9\xee\xa3Q\x945u\xdc(5\x84tL\xa6\xa5\x17\x9aT\x895J!\x83_\xc8\x81>\x1d\x89\xa2q\xcbx\xf1~\xa3\xeaKo\xde\x12zc\xbcK\x92\xf2\xe4\xdd\xdc\xf2\xc6\x9c\x92\xe4\x81\xa3}\x93\xdb]\xb2\xc2\xee\x82\x1aL\xa6x&\x9b)\x9euv\x12\xf4 \xeb\xf5:\x93\xeb\xc1|r\xbd\xebu&\xd7{\xbd\xc9\xf5\xfeEgr}\xd0\x9b\\\x1f\xd2/\x87\xf3i{\xe7\xae6j\xd1\xc9\xf0>\x9d\xf4:_N\xc7\xcf:?3\xbd\xc5\xff\xbf\x1a\xb8\xef\x11v;\xeeu\x8e\xa7\xf4+{\xc8\xbf \xf4v\xfc9\xfb\xd9\xeb\x1c\xc3t\xe7\x8e\xdd\x0f\x99g\xd8Vv\xae\xdc\x085\x99\\{\xfedr}\xd1\x9fL\xaeg\x87\x93\xc9\xf5\x9c\xfe\x87\nV:\xe1l\xc6q\xca\xd9\x9c\xe3\xa4\xb3Y\x9f\\_0\x85k\x8f+\\\x0f\xe60\x99\xa4\xf4\xf5\x8b\xc9\x84\xbe\xeb\xf5P/;\x9fO&\xe1d\x12c\xa1\xc1\x11\xfbs<\x99d\xfd\x83#Z\xa2\x7f\x84\xd6\x16Z\x11\xfb\xd3g\x7f\x06\xec\xcf.\xfb\xb3\xc7\xfe\xec\xb3?\x07\xec\xcf!\xfb\xc3\xea\xec\x1d\xb3?\x1ek\x81un\x9f\xfe\xd9\xed\xf5\xaaq\xae\x98y\xcd\x826\x0b\xecm0\x9d\xcd\xda\x96\xba\xe1P\x0b=8\xe4\xc3>\xbc\xd0[\xc9\xe8R\xd3I\x9d\xd3\x99\x9a\x1fL\x98\xb6{r\xad\xda\xba<\xad\xe9Mt\x0d-A\x95\x06\x8dU?\xeb\xfc\xcc\x84)\xdaQ\xd3\xceT\xed\x93\xeb\x191\xd9\xd7\xb60\xe4\xf9w2\xe4\xa1\x89l\xbcq\xbf\x96\x92E-\xcb\xed~\x9e\xcer\xb6\x96\x8a\xce\xeb\x8b.x\xd1-\xcd\x07\xb7&\xdb\xa9S\xb5>\xce\x8c\xd6\xc7\x85\xc1\xfa\xa8\xb5\xb5\xe2\x1d\xe8\x8d\x0c\x92\x0b\xbdA\xf2\xaad\x90\xd4\xd7G\x9f\xcd\xca\xaf\xdd\x14&\x96\xf1<\x8fs\x8f\xf3\xdf\xa6\xd3\x86\x96:\xfbt8\xbb].oW\xb71\xb9Mn\xd3\xdb+\xe28\xa7\xdc^9\x8e]\x98\xbb`}`\xa9\xf6NX+\x15}t\xfb\xc9'\xb7\x9f\xde~\xf6\xe2\xf6\xec\xf6\xcd\xedO\xbd\xa8T\x04mX\x9a*+\xfa\xb7\xdc\xa4\x7f\xe2\x8d\xa6\xe6-\x17\xf7\xfb\x87\xf6\xe9\xb0\x7f\xf6\xe6v\xf0\xea\xa3\xdb\xdd\xcf>\xba\xb5O[\xe3\xfe`w\xeaL&\xb37\x7f\xcd\xb1OG\x93\xc9\x05\x92\xf1\xf3\xa9#\xbf\x93\xa4\xb7\x83pv\xbb\x1b\xcfJ\xef\xa4\x8b\xfc\x9dg\x9d\x9fa\xef\x04.\\I\x03\xbb\x97\x8dJ0\xaf\x9b\xcd\x98\x97Y\xe48\xa8\xe6\xf4a\"\xc7a\xd5\x05\x98'@\xeb7:\xd0V;\xcc\x82l\x06_\x12vw\x9b\xe7\xc6\x9cy\xa9w\xae\xcf\x7f\xba\xf0\x92\xc5\x10o\xb6\xc5\xae\xf2p\xe5\xad\xf1\x99\x1d\xd1q\x07\x1a\x0f)\x91f\x0b+(=\xbd\xbb\\\xa6\\\xc6\x11rYU^\xe3\xf6o\xc55\x97\x0bf\x8a\xdb\x8b\xc7\xe1\x03\xed\x9d\xdd\xc4\xec\xc8\xa8\xb3%\x87\xdb\xd9\x92Y\xd6\xcc%\xf1b\x1b-\xc8\x04\x03\xb9\xe8\xa4_1\x13T\xd2U\xfd\xcaD\x18\x7f;f\x1e\xeb\xe3\xfe\xb4\xde\xb4N?\x89\x9c\x0b\x92\xf6\x81e\xed\x92\xc1\xdc\xab\x11\x13x\xca\xf0K\x82\xf2i\x19\xb8\xf0(\x12fe`\x82%\xbd\xf2\x1d\x8f-/u\x1c6\xca\xd2Z\x84\x970\xb5\x9d\xf1d\xfa\xd5\xfb\xdb\xe9\xce%\xd2\xf1\x0f\x1eYR\xb1r3\xb7\xf9}\x07\xa7\xfb\xe1)R\xf4\x89\xed\xdc\xe2\x06\xea\xb69`\xea`M\x1f\xf4\xbb\x1f\x9e2~\xf5\xc1\x9d\xe9z\xcbn\xa1\x0b\x1b%n\xc2\x03\x01o\x1e`\x18\x8d!x\x0e\x13\xfb\xb3\xd2\x8d\x9f\xcdQ'\xcf\xe5\xa6$\xbe\xccs\xb9\xed\x8c?\xefN\xdb\x1f\xect\xc95\xf1m\x8cR\x16\xe0m\xa8\xe2[\xf7\xe5\x8b\xf3\xef\x7f\xf6\xfa\xcdk\xbc\x87j\xe1\xa5\x15\x8b\xdf\xf6Kb\xdf9\xefw\x99\x03W\xd9\x15\x7f\xbb\x99hE\xcc\xd9%\x08\xb7M\xfa)\xed^gl\x9d\x9f\xfbQL:_$\xe7\xc9\xc2\x8b\xc9\xec\xfc\xdct\xa7\xe8\xae*\x05\x8dc\xff\xc6\n\x83\xe6C\xdbf\xb3&\x18\x03\xd2\x96\x85\x87\xac\xe3\xd1\xa3\xdc5\\\xa6I\xe3T\xef\xe6Y\x90\xa5\x0e\x0b\x1e\xc6c\xc6\x90;\xcf\xbe\xce\xfb\xd3:?_F3/Y\x9cSF\x7f\x9e\xc7\x94;?\xd7\x1c\xb9\x14\xbf\xf4\xf2\xf6\xdc\x16\xb5J\x93$\xa6\xa3<\x17\xc1\x1cl\xc5\x83\x0b\xa4\xb33Q\xa6\x0fJ\xde\xca<\xc4P\xbe\xdau\x99\xf4\x85\x7f-\xbf\xba\x82\xd7]N\xd9\x8dU\xe12\xfe\xa0s\xff\xe3\x9f\xce\xfc\xda\xc2i\xf9\n;\x8e0\x90\xc6\xfd\xa0\xe3\xac\xc1\xb1\xa61j\xf6\xb2X\xf9\xe6a\x16;\xa8]\xde\x89L\x18\xeb\xbb\x10\xb2\xdb\xc8\xe8\xc7')\xd7\x08\xf7\xfa&L8\xb8/uh\x12I\xc6\xd3\x07\x12B\xb42\x08\x0b\xd5\"\x89a\xebe\xe0\x93\xa6\x89\xdf\x08\xb9\xf4Bo\xccPH\xbb$-;\x14\xc1\xb6l\xba;\x8b\x04i\x1d\x8c\x1aE\xba\xebh\x8d\xa9\xda\x0bl\xc4k\x15.t:\xf9\x1c\xb9\xd0\xbb\x13\xbb\x15\x93\xf4\x974\xf8\x90\xc7\x13+T\xb6\xe3p:\xee7q\x9f\x87\x1cI\xee\x8b[\x1e\n\xa5t\xa5\x9b\xb1\x0f\xdf\x93Mw\xb2:\xad\x18q\xca\xae\xb9E\xc7\xa7\xd5n\xb7%\x0c\xe1at\xc6\xb4\xe1)^\xb3\x0f\xc7\x01\x9dm\x96\xe0~\x83}m\x1e\xed~\xe3hM\x18\x14\x8bT\xa5\x0e?P\x99n\x96\xdd\x95\xfb7\x12#3r\xb3\x1b\xa1\xa9\xb6;\xf2\xd5Q\x8clb\xb1\xac\xdb\x12\x80e\xcd\x96\x00\x17Q\xb4$^\xc8!\xa7\x94\x0d\xf0T\xae\x16\xb2\x9d\x94\xae \x93\xc8F\xf7\x90)\xb7_\x8c\xd2&\xc0\xb5\xb8$\x1b\xa8\xee\xbf\xdd.0\xd6\xf4-v\xa1f\x03\x16\xdd\xd0\xef\xbe\x101QO\xd3P\xd7\x80\x95\xbbe\x86\x1brv6\xcaoW\xf5\xef\xb7\xedv\x8f\xf6\x1c;\xb4\xf7v\x0f\x9c\xad\x8c\x90\xe63{_\x7f\x1f\xeaPw\x18\x0b\xed\xc3\x83\xc696,s^\x80q\xb3\xcc$\xd0zE\xe0!\xdd]F*\x0c\xb7\x02\xbci\xad\xbe/\xeaH\x04\xb5\xdc\xd5\xd4\x00\xfc\xaed\x84\xe1*\xc3\xda\xbe\xcb\x1f>\x8e\xc4\xf6\xc6\xe9\x14/lx\x86l\x17\nT\x85\xd0^\xfa\x94\xe0\xe4\xd3a\x14\xe0}\xe4Jp\n\xde8AQ\xdc\xa7\x82\xaa\xaf\x91\xc7\x01\xee\xa3Q<2\xdc\xa1P\xe2\xf8p\xbd\xeb\xd1\xde\xd6\xa8 \xc8l`\xa2\xf8\xfd\x928\xf4\xe8\x11\xa6*\x18\x0f\xa6\xec\xd6*\xfd\xde\x9b\xba\x0c\xd8\x9fR~\x96\xb7\xa5\x18\x8e\xa1z\x04J)Af<\xd4Ub<\xdcu\xd6\xfa\x87\xd5\xfbF\xe2:\xa1N\xe5\xd5W\xd5]\x83\xa69\x14wx<\xddd&H\x98\xf8]|e\xf8\x18\xba+`i3b=\xe5\xa3\x0d{\x0e\x96\xbc\xc1(M\x0b\x17f.\xac\xd9\xaep\xe1\xca@1\x91\xee\xca]\xbeAO\x8b\x99\x0b\x0b\x17\"\xb8\xe5w\x0c\xaf\xe8\xa6\xbc\xa9\x1fA\xcd\n\x8a\xb7\xee~\xfak\xbc\xad[]\x91\xeaA\x94Yy\xb6:\x8b\xdeC\xdel>L\x91\x8d\x85dZ\x96\xcb\xfd\x0f\xdea\xb91\xd1\xdf\xcd$\xc6\x07j\xeb\x9e\xa2\xa1>|P\xbf\xaf\xf7b\xea\xf7\xaaV4$\xd5\xbd\xc6 \x1f\x9b\x1e\xf04\xc4\x17D\xf4\xcbh\xae\xde\xd7\x04I8\n\x0d\xb5@.\x1dQF\xe7 &\xfa\x042\x16C\x9aO\xabW:\x13\x96\x11\xbd\xdd\x0e9\x06Q\xa8Z\xbd2\x0e\x10)z<\x13?\x85F1YH\xc9\xf7\x13\x8c\xcd\x8cX/\xc8\xee\x1e\xeb=\xd5\xf6zz\x83\xe8^\xbf\x8a\x12\xc8{\x95@H>\x17\x8e\xaa\x885\xe7\xf0*\".U\xb1\x00\xbdI\x84\xad\xeb\x99\x08\xa2WuOY\x94K\xc5\xdeM\xb5\xc4L.\xc18v\xb5\xc8\xd5\xfd5\xb0B>\xb9q\xe1\xd2\x85\x95\x0e\xfd)\x9a$\xdalT\x17\xf8\x84h\x9e\xbc\x83\x11\x9c\xc3),`\x08\x9e\xf6\xddk\x18\xc1E^BW\xc7\x19e\xf4\xb4\xa2wT\xacY\xc3)\xcc`\x08\xef\x1c\xfak\xa6\x16\x7fA\x8b\xd3Z\xaf\xe5\xe2\xd7\xa6\xe2\xcfD\xc5\xd7\xean~F\xf9\xb9\x8f\xd62u#\xe3&\xf5\xe5`Q\xad\xbe\xba\xd7\xcey\\\xe23\x0c\xd5\\\xb3\xbb\xf2\xf6Zgy\x85+T.\xae\x04;s\\8\xa7\x909S\xfc\x06\x9aU\x1bB\xc4\xa1\xefJ\x0f\xd4\xb1\xb5\xec\x10\x1ea\x90|=\x8dz\x0d#8Cer\x1e\xd9\xc8:?g\x89\x0eg\xe7\xe7\xa6\x0c\xd3_\xc0\x08^H\xaf\x91\xeakzj\x87\xf6\xbe/\xea\x0e\x83o)\x8e\xc3)\xa4,\x984*Vk2H\xbe\x84\x11|\x81Z\xd8\xa28\xd1\xcbD\xc6\xc9\xbe\xb4\xdf\xba\xf0R\xcc\xe3J=&n\"\x03\xb5pQm\xb5\xf6L]\xbe;3F\x95\xd3qc\xec\xb1\xfe\xd4\xb7{\xbc\xaf\xf5\x0b\xc9\xbe}\xbf\x90\xaa\x8c&;\x88`\x01o6\xb3\xd31\x99V'\x83~2\x89\xbey\xb3\x19\x06\xb5* \x94#2\xaf\x8eLq\xe0\x88\xca\xbe\x1a\x99v~\xab\x93\x1b\xde\xcf\xe2\xb3\x91D\xc4\x99i\xe8l\xc48\x7f\x9cbXs[f\xf3t\x8aM\x90\xa6&\x8c\x08m\x8acx\xac\x8fi\xac\xb8\x9ad\x06\xa9\x81\xbbE\x1d\xeb\xa5\x80\xbd^\x95\xdf\xfb*_\xa7\"\xc0@\xe5\xfe9\x8b\xfe\x1e\xd3\x15WytI\x1c\xf8\xc8K\x15G\xd5\x92$\x80a\xd7k%\x81O\xbd\xb5N\x0c\xc8\x9f\xbfB\xa5v\xb5\xc8\x8d\\\x849\xb6T\x8b\\\xcaE\xce\x88\"l\xacJ\xcfQ\x97^-r^*\x82\xca\xf4j\x91\x0bE\xee\xf9^6\x9f\xab\x1d~W\x996\xef\xa7\x02\xf2\xaeZ\xe8z\xe3@\x94g(\x17\x9c\xc25c\x0b\xaf\xe7\x1b\x07\xfe\x13\xb4:v\xe1\xda\x85\x17.<\xab\xa2~\xf2.\xc0\x08|Z\x1d\x96\xef%\x04\xde\x0d\x158p\x06\x98\xcayA[\xa3r\x9e\xd0\xdb[`\xcf_\xcf\xe7 I\x8b\xe7\xecw\xad\x00B?)\x06\x10\xbb\xc0 vy\xf4T\xf6K-\x8f\x1d\xbd\xd0w4\xb7|6\xf5\xb6\xf5\xc2\xa6\xc4=\xc0\xab\x1e\xec\x1bqtY\xbf\xb1\xb5\xa5\xda\x1a\xc2\xd7\x06\xf8Um\xef\"\xbb\x9d\xba\xd0\xd6i\x9d\xf1\xedE\xed\xdbi7\xf4V\x84\xe9/\xf1\x1b\x06jY\x91$\xf1.9\x98\xff0T\x7fc\xe8\xf4\xaa\xbeYfYR\x83\x88\xe6\xef\xcf\xf4\xef\x0bQ\xcd3\xbcvi~\xed\x0b\xe6.P\xcd\x1d&>\xb9Xf\xd3\xfa\x13\x0ch\x8d'\xbd\x96\xd0P\xa0\xb4\xfaE#\xf6 \xe9\xed\x19\xd74\x98\x9b{\x9b\xd7\xf5\x16\xe7\xc3 \xaf\xc1\xed\x08\xe6.<+\x0e\xa2\xe6\x86_b8\xc5\xd7\x88\x88\xaf\xd1T m\xe0Zy\xf0Y\xa1\xb1q\xe1\xa5az\xcf\xcd;\xba\x10\xe3\xcfD\xccJ:\xa83\x11M\xb6\xf4\xa2^v\xbc\xbb\x11\xdb\xe9\x16 3\xf5\x94\xed\xae.i\xdb\xca\x87<\xad\x0e\"\x8cA\xf5\xa5\x89\xb7\xaf v\x85\x15\x8e\xdbm2\x85\x11:\xf5\xa7\x95\xcbq\xce\xb7\xa11\xfbv\x86W;65\xa1@\xd3\xb0\x8cx\xb0\xd7\xd3i\xcc\xfa\xaa\x08\xf5@\xda\x03\x9ewO7\x89\xa8Q\x81G\x10\xa8\xf38gv[\xcd\x89\x123\xef\x19S\xa5.1m\x82M\x1c\xc9\xd2\xd4\xf2\x8d\xf4\xa8Hm\x00#X\x9e\xc0\xba\xc6\xe4\x81\xb9\xb9\xc7k\x83]\xa0e\xfb\xa8\xb1\xc0\xdc(C\xc9\xcbn\xe1lh\xe3\xa0m\xcc\xd03YG\x13i\x1b3\x96[\x88>\x96T\x0c3\x0d]\x14\xe6\x82V%Bg\"+\xea\xd8\x0f\x8dCO>+T4\xf4\xe9il\x0dO`i\x9c\x99K\xb4\xa7\x88\xf91\x98UV\xe8\xce\xb80L_\xe6\xe4\xfa$\x1fox\xae\xf0\xfc\xbb@,J\x11\x7f\x86\x90\xd9\xf4H\x8cP\x86^\x89\xc9\x8c,\x9b3\xce\xe1\x94\xf6p4b\xc7y\x8fW\xc2P\x13\xeb=7\x9b\x9cQE\xa3\xe7 \x171\xf1\xde*OT\x83\xf0\x0d2L\x94\xb2\xfd\xc2\xb7\x1d\xfdF\x16u\x14\x1f\x0dI\x88\xbf7\xa6\x89\xbf@!N\xaaU?\xf5\xefP\xba\x93\x8a\xa9\x03\xba\xa0\xfb\xe6\x1dm\xad\xdc\xc9\x80\xa7lS\xa0\x8c\xd3\xdb\x96\xd8\xf0r\xd8\xf5\x0b\xfa\xecBV{#D[\x16\xdb|'\x97}\xc7\xfc\xd0\xd9\xd4o\xc0\x12\x13\x99)\xe7?(\x82o\x99\x88P\xa6\x91\xfa\xeb\x0e{=}\x0c\xca\xbb\xfbN`\x10\xe1\xc8\x85\xe0\xce\xc7\xe2\xbd\x9e\xfe\xbe\xd0Qc\x97\xd4ZE\xcd\x11\x8b\xefnpHc\xaa\xc6\x08o`G.\x84\x1b\xdc\x0ehf\xb2\x1a\xbd\x816^=)\xc5\xa7\xcf5KR|\xfat\x1c@\x1bX\x8c\xfaqh\xf0>\xbf\xfbl\x9b\xf2\xae\xe8\x8c\x11\n\x0b]s\xe6\xf92y\x11f+\x96\xb0K\xd5R\xf0\xd7.I*\xf1[vfNT\xddEV\xca\x0c\xa4#\x15\xc2J#\xa9\xe5\xc6S\x18V\x0c\xfe.\xc46\xcb\x1b\x94\xd7\xa6\x0dO \xd5XD\xb8'\x1aMh5K\x0c\x0c!\xd0\xe3\xa4\xf7-#M}\x92\x83\x9e\xc8\xe9/c\x91\x9e\xe0f,\x0f\xbf\x86\x89a\x8cN\xf4\xe2D\xea\x15\x8d\x83v\x1b\x13\xc4o@\xc1\x9aB^7N\x84\x81\xb8\xdc\xfd\xa6\xe6\x9eAy\xdc?\xd4_B\xd4'\x0dQme<\x81X\xbf*\x82&\x06\x1b\x9a\xee.\xd7\xf6r\xa8\x8e\xc4\x85\"\xec\x84\xb2\x92\xe8D\x83\xa99\x02\xa3\x00\xca\x9e\xb7\xd0\x19$\xd3\x96ZWJ\xb5\x96(\xbci\xcb.P\x0e\xbe\xbd\x859\xfdoI\xff[\xab\xa5f\x98\xb3\xfc\x94\xb2\x8c\x1c}\x99\xae\x8d\xca0\xba\x9c\xa1r\xce-\xa3\x84\x87~)<\xbe}\xcb\xcf74\xbb\xeb\x8b\xf2\xb3m\xb1*\x90m\xdf\xb0.\"8BUS\x01\xb6\xd6^LB\x0e\xc0\xf7\xd7\xac S,I\x05\x0b\xd5P\x05\xf8Z\xaa\xd2a\xe2\xda\x8d\x0bW\x0e~\x9f1\x03\xf7\x8d\x9e/\xcd\xee\xbb\x8b6&'\"-\xac\xa0\x17\xe9\x89\x03\xb1\xc8\x8a\x12\xea{\x17\xdfy+\xeasS\xec\xe96\xa2\xce\xb6\xdc\xb4?\x0c\xb4#\xe0w\xbab\xae\xa3\xf8\xb6h\xd4\xdd\x15\x1a\xa6\xa4\x1d\xfd\xaa\xec\x16\xe9',\xc3d\x82\xc5\xf4d\xe3|\xfa>^F^\xba;\xe0\xb6w$\xe3\x95\x87\x07{\xfa\x87/\x85\x86E\xf7\xa4\x7f`|dj\xacP\xd9\xe8\x1f=_z\xab5\x99\x99K\x98\xda\xa4\xcfJ\x8db\xa6\xdc\xb1\x0e\x83*o\xea\xeb+\xe9\xeb+\xcfr\xf3G\x05^\xe8\xee\xd5\x07D\x01r\xfbGu58\xae(\x0f\xd0\x18R\x81 \x03H\x05,<(*`a\x0b\xa9\x80\xd1\xfeQ\x85q\x9bG\x05\xfcC\xe2\xbd\xcd\xfb\xd1\xea\xbb\xdbm\xc1\x88o\xc1 '\xf8\xf8\xb3\xd5\xca\xc6tW61\xf7\xc6\x1d\xd9\xec\xcf]#L\xa6fu\xe5F\xfb\xb8F\xf3Ul\xf1\xbeb\xf3\x03\xbe\xcf-6\xc3\xa5d_tr\x18\x1b#\xdd0\x9a\x9177k\x06S\xab\xc0tQx&U\xeba)\xca\xb1\x9e\xb4T\x8f\xc6\xb5\x80\xd2\x10vs\xb8\x98\xe0\x11\xaf\x1a-O>I4~\xba^\x1da\x14\x9f\xfa\xc4\xd3W\xb6+\\Q\x95\xfe\xb1\x98S\\\x8b\xb3\xfbG}'?Zn\xce\x15\xfa\x86\x03Z\x7f\xa3\x03\xdav\xb2eu\xe9P\xf7\x14\xcb \xe3U\x7fx\xa1=\x1eO\x0d\"YHE\xb2\"\x85\xbct\xc8\nq\xff\x97U1-\x9eF\x8e\xb9:\x98\xa4\x8fm\xeeU]\x19\xd2tm;\x19b\xa0<\xe5\xbfQ\xfd$\x99\xbbF\xa0W(\x11>\xc2\xdc\x92{{\xdb\x9cv\xa9\x06E\x8eD\x8e~\x0c0\xe0\xf2\xa1nu\xed\xa6\x99\xba\x9a=!\xf22uW\x1bR\x9b\xca\x92\xf7\xa2\xb1\xd2\x90\x07\x86\x84\xd0\x067\xd9\xbdA\xd5W\x92\xfbP\x0e\xaa'4\xeeC9\xa8\n]\x89^F\xe3N\x94\x8as\x06=t\xf9v\\\x81b0\x0e\xbb\x1axg\x8d\xd0\xa8\x02] 4\xab@g\x08\xad\xe6\xdf\xa3\x07#\x89 \xb2L'\x1a\xb1\x84\xee\xae+4[\xc7\xf8\xbf$\xe4\xd8}\x87\x1dJ\x82\xd2\xbb\xc8\xed\x8b\xd7\x02,\x12\x95\x8a|?\x8eVABD1J\xae\x93hyElV_V*\x8c\xc2FQ_\xc6\xceD\xa5\"\xb9\x90Q\x14\xf3\x9cB\x87\xda\xbcA\xf5\x87\xd2P\xe7c*.;\x96\xb6sM\xc69\xc4>8\x05\x9f\xa2\xba\x9a*\x93\xc7?\x10^\x12Z\xfb\x1e\xdaT\xe7\xb5\x96r\xcd\xca\xa9\xdc\xce\xe4V\xa0\xab\x07\xa7\xd3P\x85\xc6\x03AWE\xbe\xca\x86j\xea]\x0e\xca\xebo\xa8\xc2`\xfe\xafV\x91\xe3\x87\x81\x94\x80\x96MT\x92U_mGovw\x1d;\xb4\x0f\x1d\x17,\xb1&\xa6(5[\xdej\x94j\xe6S\xfc\xf0\x15\x9f\x91\xf4\xe1+\xe5\xcb\xf0@\x15\xf7\x8f\x0c\xa1\xd4\xb6\xb7D\xe4\x82\x87\xb8\xbf\xe7\xf2\xdb)B\xb5\x1e\xd6\x18E#\xaeeW\xb7>p\xa6\x91\x8e#\x9d\xba\x94\xa9Kx~\xb4\xd8\xce\x1cSX[\xd8\\\x8a\xa9\xb9B`\xba\x01\xa9\x0f_\xb57\xd0)\x0b(\xbb\xd4\xc5\xaf\xd2\xad\x86PhV\xcb3\xfewXe\x8bs\xd5\x04\xbf\xdc\xf0\n\xa1A\xc6\xc8\xf8\xe1\xd1c\x99A\x13\xdb\xc7\x95%\xcdW+\x85\x9e;\xd0\x05%\x90Z\x90L\xac\xec\xd4\x90\x07\x17\x89\xd8\x9bh \"\xb8\xc0s\xb8\x85\xe5\x03\xc92\xfd\xa3\x8dn\x83\x1bL[\xb8\xf0\xba@I,\x9d\xa7^|\x96\x86\x1a\xc0)\xa6\xc1mJ|k\xe8\xfe\xce\xf8\xf3\xeex2\x9d\xb6o'c\xfbthwN'\xb3\xb6}:\x9ct'\xb3\xb6s\xea\xdc\xdac\xeb\xf1\xd4\xb1\xe9\xb3\xd3\xd6d\xe0\x8c?\x9fL\xa6\xb7\x93I\xd7\xf9\xf0\xd4\x99\x0c\x9c\xc9\xf4\xd6>\x1d\xe1\x1b\xb7\x93\xf1d\xea\x14_o?p\x9cj^3:\xdc\x9d\xc9\xc4\x9eL\x9c\xd3\xea3\x81\xebGN\x83\x1b\x8a\xe9\xc8\x02\xc5\x0c\xed\x1d\xb0\x9b\xb8\x98N\xf6y4#\x98RV:\x98X\x16r\x14\x11\xfa,.O\x17s\xa2\x8cLGa^GLq\xab\x94C\xff\x83>f\xa2E\xe5y\xaa3A\xc9!%\x18D\x8f:\xd16\x8bH \x8a\xce\x89f\xbf\xf9\x1a\x99I\x06C\xec\xab_\x05\x90,y\"\xf8\x00W5\x84\"\xb4\xa2[\xf1\x14\x026 \n\x8c\x11x\xdf\xf3\x17\xfa\xb8\x07w\xa6\xb4{\xbb\xfa\x83\xc6\xdench\xc3\x1ab\x86\x1b\xb6\xc5\x8f\x92\xe2\x8eK\xdct\x00\xbc\xcf\x11\xad\xd4\")\x9d\xc8\xef:5}\xc35\xfc-mj\x8a\xedL\xd8\xd4\xf4,\xe8\xf0\xae~\x00\xb9X\xe0s\xcb\x07\xe5Q6)\x82\x009\xb9\x15j\xc9\xbcd\xa0\xdd\xf6\xe1 \xcck\xafg'6\x19\xfbS\xa3\xdf\xceR\x90g1\xf7\xd8\xbf5=k\xa1\xbf\x8d\xfa^\xca/s\x97\x1eh\xc5\x074\xac\xd1>\xb6F0\x87SX\xc2\x10Z-{\x0ef\x031g\xa1s\xfc\x9b\xd9k\x17\xe6\xdc\xbekKq\x13\xef\x8d\x87\x06$\xbc\xbb\x97\xc2\xae\xde'doW\xef\xbf\xa2\xca5\xd9\xa6\xc8c\xe8z\xc4\x9cD\x98G\x01\x06\xbcj\xde9w\x9e\xa7\xbc@\x9d\xc2Z,1)\x87\xa8\xaaz\x8c\xdeu\xca7\x91J\xee\xd3\xfd\xb8\x12\xb9\x0e\xee\xd3\xd9\xbd\xdd\xaa2T\xa8\x83\xf4\xa9\xb2\xf7vu\xc4\xe8S/]tW\xdeu\xd3\xb0\xcd\xc2\x98W\xb3\xf5TMA\xcb\xcb\xd5\xaa\x9d\x8aO\xde\x95\x88\x98\xc1+\x13I\xcb#\x93B4\xc9\x13\x9e'\xe8\x0d\xeeA\x1b\x12\x0c\xbc\xe62^\x1c\xd0\xf9\xdeu\\H\xee\x8f\xb6\xc2\x15V\xd1o\xe44V\xf6eb\xde(!\xb4\x01\x05\x9e>\x0c\xa1\xd3wN\xf06K\xd4\xe9\xc0\x10\xda\xed\x88%TW\x90\x85N\x13\xb1\xe9\x91\x0b\xbd\xca$Et\xa4\x9d\x86\xbb\xc7D\xdb\xdbm\xce\xc4_#\xec\x98d\x12\xf8 \xe8\xeb%\x12\xb1w\xe9\xd2\x12\xe8\xa0\x10N`\xd8\x18\xc2\xc1<\x82=\x9d\xa8\xd2\x87\x9d\xaa\"\x0b\xe3\xbbt\x0f\x8f\x0f\x0f\x8ew\xfb\xbb{G\x07\x83\xdd\xfe\xfe!\xd9\xed\x1dm;\x01\xb9\xaa\xfb\x94\xf9^1S\x01\x13\xe3\xa8\x04\x8b_;\x01{\xcc\xc2\xbeu\xe8\xfa\xf7\x1d\xf8\x10\x1d\xeeR\xb1SR:r\xfc7\x92!w\x9d\x0b%^3\xd7&\xe8\xb4\xc3\xaf\xbcW*-\xd8\xf9|\x92\xb4o'I\xfb\x83\xea)\x83Ex\x1ew\xda\xd3\xde\xf5\xb8\xd79\xf6:\xf3i\xfb\x83\x9d@\x15Vv>\xef]\x8c{}\xcdS\x9f=\x8d\xc6\xbd\xce\xa1\xe61\xe5\xe0k/N\xc8\xcb0\xddvI\xe8\x8e\x91\xa3\xbd #`\xbeqR\x95\x10\x05\xb6yc\xa1J\xd3p=\\\xe0\xbf\xd6\xc6\x91\xe6\xd7\xcfN\x8b\xef\xecJ\xb3^\xe8\x89\xd9\xc9\x9e\xdd\x10\xa2\x9b\xa1T\xea\xbd:J\x11\xe4\xae\xa5\x19e\x19\x8f\xda\x95&\xd9e\xb1r2j\x95\x00\x87,\xac6K\x14\xa3\xdd\xc4xN\xf3E\x118\x85\xb9\x9dv\x93e\xe0\x13{\x80j\xa7S\x18\xc0\x10\x8e\xe8\xa8=\xa9X\x84}\xba+r\xf7\x15uK\x03\xb7\xdb\xab\x8a\xd8\x99V \xe7\xa6\x8f\xbdf!\xc9\xcc\x01\x19\xf7a\xb2\x12\xe5W\x86iC)4\xaf\x86\xb2-\x8aGL\x8c\xa1VE\xf1\xfcc\xd3\x172.\xdaf\xf0\x04\"\xe6\xe8\xd4\xc7\xb8q\x81\xed\x8d\xb3)\xbbH\xe6\x9c\x98\xf5\xd1\xa6\xd8\xe7\xdb\xae\x84\x9eN\x18\x82\x0d\xa9\xea\x98L\x08T\x1b\xac\xa7\x86)\xe0\nd\xf2\nT\xef\x1f\x89\x83\x93\xf0\x8d\xd0\xd2\xdeV\xab$\xd5x\x18\x1b\x86\xb1\x8e\x08\xf7e\xae\xe0\x18\x96\xa2\xdfz\xb9\xbe+\xe4\xee\x9f\xe1\x98L\xb7\x8f\x99ne \xc1\xec8~*\x99/\xb9\xd3\x05\x0b\x97!\x9clx<\x18\x92|\x1a\xcd\xb2%\xb1\\\x85\xc1,32,E\x8es\\\xbcs\xbd\x8a\x82/\xc9\xec\xcc[\xad\x97\xe4\xe38Z\x9d\xf9\x0b\xb2\xf2`$=|\x1e\x13/%\x7f\xe3\xd3O^\\c1\x16J\x0d\xbf\xfe\x8d\xd5\xb2\xf2R\x10\xceI,\xfdN\xd4\x9a\xb9\xa1\x1bH\xd7Wk^\x9eh\xf0\xa9\xaf\xa4H \x90\xe7\x87\xf6\xde>=n*H\x85\x8f\x0ev\x9dM\xa3\xb1\xc8|\"\xed\x16\x13\xc9e9\x95\x1a\xcc\xc8\xdc\xcb\x96\xe9\xb0z\xab\xf4;\xea7\x81kj%\"\xf3Q\x8e\x04&\xaa\xcc\xbb'\x90L)\xf3^= \xb2\xa2\xe7d\xe5\x05\xcb-Z\xc8\x12\x12\x7f\x97\xb0\xd5\xe8\xfa\xd1j\xa3\xb6x\xbf\xceg^J:i\xb0\"\xd6\xe6-\xa2\xaf\xc5G^J\x9cn\x1a\xbd<{\xcd\xbc@m\x8d\x1dBs\xda\xc5\xcd\xb9y[\xbd\xcd+=\x9f/#/}\xe0\xaa\x830%\x97\x0f\xdea\x1eD{X#T\x88\x8fX\xe5<\xee\xb6t\x8c\xe9r\x94fQ1\xf8\x0f\xb5\xfd2\xba\xab\x07\xd0\xfaN\\\xe5\xfel#\xb0{.\xc4]\xe6`\x11\xcco\x1c\xadB\x03rC\x8b\x9a\x82H|\x02|>\x8f\xe2\x95g\x88\\EI\x827\xc6\xfc\x91\xe7\x16\xb4!\x98\xa2\x0b\x90\xf6\x12\x92\xc0K\xec]\x90|\x9c\x85\xbecGx\x82\xb2\xd1\x1ek\xfd |\x1bF\xefBxs\xb3&C\xa0\xf5\xa5\xd8\xbb\xba\xa9\xf1M\xc40\xa7J\xa9^u)\x0e\x85\x9e\xf0%\x17\x97\xb2\x9fB\x1f\x8a\x9c\x14\x94\xc9\xe7E\xc6\xfd)\x15\xde\xe4\x9f\x98\xc7\xca8{\xcaR\xe8\xe2\xc5\x81\xf0\xf9\xadY\n\xb4yw9\xfd\xd0\x17\xf1\xb0\x08\xbf\xc4\x17\x10\x8dg/\xf0\xf9\n\xba\xdel\x16\xd0\xc9\xf1\x96\xdfo(?\xc7\xf2AJV\x86\x02h\x14\xe9\x06\xa1\xbf\xccf\xe43\xe2\xcd^\x87\xcb\x1b}\xd1\xb5\\\xf4\x87q\x90\x12ZV/\xe8I\xd3\x9f9e\xdc\x99\x11\xb2^\xdePz\xb6\xfe\xeb\xe4\xc6\xc1#\xff\x07\x1f\xc4dnma\xa5\x94\xe5\x8a\x92ou7\x08g\xe4\xfa\xf5\xdc\xb6\xfe\x8aU\xc9\xcc >\xefM\x16\xa2H\xef\x7f\x1c\xb0\xe0\xb7\x91\xe4\x1a\xae\x176kb\xec\x82hc.f\xc3 \xaf\x8a\xdb6^\x1c{7*\x97\x01\xedy\x01U0\x85\xb7\xf9\xc8l\xed\xbe\xe2\xc1\x06\x14\xcc\xae\xba1\xca\x9fY\xe56\x8b\xfc\xc9E\xf5+*\xd8-\x1cX\x8c\xaf\xa6t%\xe8\xdf\xee\x8c\xacc\xe2{)\x99\xe1\x8d/\xf9Q\xccq\x0d\xd8\x05\xb6\xea\xe3w\x02\xbf\xf0\xf9\x1a\xef\xb9\xcfh\x81\x11\xa46-A\x85B\x83\xd0\x8f\x13\xcd\xb4N\xbe\x03\xb3\xcav\xe9\xd7\x8c\x06W\x90\xbe\xee\xebQ\x01\xaa\x11\x0c\x94y\xf4\x1d\x97\xc5,\xb0o\\\x8c\xb2\xb6\x82\x11\xf4O`\x05O`\xef\x04V\xed\xb6\x03\xb3\xb1U\xee\x12\xa5\x95+:\xb4K}\xb78\xd2\xcfTT6\x91i\x8e?\x0c\x19\xe0\x94\xa7\xb2 \x12v\xbdl\xde\xf5\xc2\x9b\xd7s\xd4\x92\xb1\xaf\xdd\x95\xb7.<5\x9a\xee\xe6\xb2\xf8\xf3:\x9f\x08\x18*ME!\x11M\xe1\xd7\x07lj\x9c\xdas\xfa\x94\xd2q\xd2%a\xb6\xc2\x10\x8c\x82c\xcb\xdf\x87|\xa9B\xca\x0e\x97\xc1\x97\x04\xbb\xe7\xd8\xec5g\xdc\xa3uX\xf3`IX\x8a\x8d\x08\x1d\x9b\xd0\xa5I\x17/_U\x12\xdbU\x19\xbf\x9e\x96\x89\xe1u\x13V\xfe\xd1#\xa6\xb6\x17\x00\xf4h)\xb8\x01{\x8e\x1cF\"C\x8aO\xc6{\xd7x\x04\xd9\x88\xa1\xb2K\xcb\xdf\x1aO\x8d\xb6\xe1\xa9x\xff\xa5\x86\xa7z\xf8|\x13\x86\x19m\xc90\xa3&\x86\x19\xd5\xb3\xf25c\xba\x9b\xf0\xd4\x85\\4\xe7\xa9\xfa\xb23l\x99#\xb4\xbe\xc8\x15\xd26\xfd\xb3\x9b\x9ag\x97(\x86]\xaf\x96\xfa\xc7\x94\x86]b|2\xfd\xf3s|\xbe\x8e\xc9<\xb8\xd6\x97\xb8\xc8kH\xd6\x9eo\xa8\xe6\x1d\x9b\xda0[\xe9\x9f_\xe7\x87d\x03\x03\xcfj\x188\x9a\x07\x1c\x96\xda\xfc\xc7\xc1\xc5\xb3&.\x8e\xd1Y1l\x8c\x15F\xa9wI'\xc7b\xfe\xb1\xf69\x9c\xc29\x15\xcb\x87\x16\xba\xb6;\x94A\xb8p\xc1\xf4\xf37c\xfa\xdc\xba^-\xc3\x043e\x9f\xd3B\xf8\x13o\x03^\x18\x04\x1c\x99)\xa0[\xe5\xdcD|i\xe99\xc5\x07J8\xf0\xef\xed-\\\xd2\xff\xbez\xef2\x08\x0f\\'\xff\xa0e\x18\x96\xc0e\x97\xc7\xe0\xcd\x85\xbf+\xee\x95;u+\x1cbIy\xc3R\x8dZe\xe4\x0c\xf43\x17;\x90\xe5\xa4\xa2\x953?>\xe4\x08U\xfd\xbe\xf8h\xf8\xd3\x8c\xb6>\xdb\xbau\xc1V\xb6n]L\x03/9u\x01%\x9c\xa2\ns\xab\xe7^\x9a\xc6C\xb81T\xee\xc2\x95\x1e\x1b)e?3\xb8XB\xc1\x8a4\xabb\xdfsY\xce6\x9a\x15\x17\xce\x0c\xebb\xdfsa\xb6j\x9f\x97R\nm nk\xd3\x12\x01\x9f\xfa\x17zq\xbbA\x9c~F\xc5ii\xcf\xd0\x9d\xb8\x14\x1b\xf0\x85Y:\xa5}{Q\xb9jh?ct\xa3\xf5b\xfcL\x12\xbcooa-?(Dn*\x8c\x1b\xa6\xab\xd4\x0e}\x8b\x11\x89\xfc\xab\xe8!\xff\xdd\xa58\x1b\\di\xed\xb2\x89\xcf\x15\x8f.YF\x05\xac\x0b\xa54\xda\xd9\xfc\x971\x05K\xf5\xf3\x85\xe8_-\xd3\xae~\xde\x8a\xb78F\x99)\xbd\xf8\xdc\x8c\xf3Q\x0br\xf8l\x9a\xb3,\x14\x9b\xbe\xa0#\xf8\x82>\x91\x80\xcb\xf13<\xf7\xe0\xdf\xf2\xa3\xb7\x14\xfe\x96\x0214f\x82sQ\xbf0\xb5\xa9^\xe4O\xb9\xb3#P;\xef\xca\xce\xe9\xf2\x0cV\x84A1\x00\xbbT\x86\xc1Mv\x19\xe9s\xc5\xe3f\xa6lt\xcd/\x94\xd1\xe3%\xa5\x14|\xa7 \x19\xf5\xa3\xd0\xf7R\n\x1fJt\xf5e\xc3\xb4\xd5\x91Fq\x98\xe4\x0d5\x11\xea\xb2\xb49\x04\xebYx\x93.\x82\xf0\x12|/\x84\x0b\x02\x0b\x12\x13\x83T@;\xedo\xca\x11\xaa\x0d%\xa6s+%r\x0f\xc8g6\xa0\x91|\xe6\xae\xcb\xf8\xbf\xe4\xae\xb1\x12h\xc63&\x94\x17\xf5\x1d]\xd4w\xecT\x96\xb0\x80kl\x85o\xe0\x14\xc6\xfa\xbe\x1b\xfb\xfd\xde\x85kZ\xd1u\xb5\xeb\xef\xb5v\x90\xa5\xd9\x17\x81\xca;\xeci\x19K\xd1\x08Z\xd2s\x05\x82n8vX\xb5:\x01\x1aJ\xfc\xa5\x17{\xb4\xc1!\xb44\xd7\x1b\x83pF\xc2t\x08\xd6$\xad\xdc\xae\xab\x9a\xcb\x00o1\xd4X\xa5h\x7f\xa2\xa2?\xcb&\x13W\xa5<\xc7\xa9\x06\xab\\\x0d\x87\x96<\x05\xf6\xabn1PxK\xec\x0f\x9c\xeeY\x1a\x13O#\xfe\xa3N\x8c~\xb1\xa4\x15\x83\x8a\xf5Jo\xf5\x04\x919\x80\xd24\xcd\xc9\x01=\x05\xd0\xa5\x11\xc7\x1e0\xd1!\xbf\x92k\xb3\xf7\x9c\xee\x17Q\x10\xda\xe8KgYU\xdb\x9a\xf8$\x94\x8c\x19\x84oC4\x08\x1b\xbdD\xd3\xb1\x142\xe0-\xb9I\xec\xd4\x19\xf7\xa6SdyI\xf7\x9c,\xc9\xaa0\xdbr\x80\xa0\xdc\x91\x9bC\x02?\xcaB*\xfd\x84\x12\x0c1\x89\x0d\xab\x0c\xa3-{20%q\x9c\xadS\xcc\x00'\xc0\xfa\x19\xf3\x99\xd3\xbe.4\x14\xf0S2\x957\x95\x87\xf9z\xad\xcd:\xde\xf24l-\x02\"y\xab\xf5m\xa8~r3g\x1b\x1e\x8f\xac\xc7\xd0f\x0epmxl=6\xbe\xf8\x1e\xbd\xa6\xc7dj\x14,7 \x93\xe2z2\xc7\x08%\x94\xad\xf8\xe0\xa5\\\x81B\xfa\xbb\xb9Pv\xc6\x18\xd1\xca\x0c\xf7\x1a\xc4'\xe9\"\xcd\xa48\xb6\xb6\xf9\x0f\x0cty\xee\xcf\xbc\x14\x95RK6\x9d\xb6\xf5\xa45~\xfe\xd1\xb37\xcf\xc6\xf4\xc0)J8\xb9\xe3\xde\xced:\x99>\xdd\xb9t\xc1\x9aN\xa7\xd3\xa7y\xf1\xa7xx\xb5\xa6\xd3\xa7\x16V\xcdW\x13Q\xdf\xe7\xa1k\x96\xd2=\xaed\xc3\xf8\xc5\xf2G\xbb\xb7N\xc1\xc2\x01!T\xd9YpJ1\x90\x0f\x19\x86\xa2\x0b9\x15\x816\xf4\xf1r\x81\xbdd\x89\xb5]T%\xb5zyo\xd1\x13\xd3,T\xbc\xc77no\xa5\xc1\xd5\x8865\x0b%L\xea\xc6w\xf3\xfe$\x9a\xee\x189\xb3~F)E\x19B\xa4\xdf\xd49}\x18\xd2U\xd3\x16\xc9\xc5\xfdd\x08s\x83F.\nS\xe4l\x06e\x13#aC\x08M\x9d@\xca5\x04\xaf\xeey\xd5e\x15\x94\xa9xo\xe0#^\x1d\x1f)\x11\xf2\xc2HL$\x97&\x8a\xcf\xba\x08\xf1\x82 \x12\x89\xcc2\x0f|\x0c\x9fK\xa7$\xbf\x9d`\xa6\x9a\x81\xd14\xce\xd3X*\x95\xd5\xed\x1d\xe1$W\xbc\x94,\x82yZ\x0d\xa8#\x7f*\xc6=\xadKX\xb5|d\x07N\xb3\xc2\x8c~p\xf25gp\xf1\xd1K\xe9z([\n;F\xed\xf5)\xce;\xe3yB\xa1f\xf3\x94\x0b\xa7`=\xd9\xa1T\x8d\xffn\x83\xf5\xd4\x92Kq\x06\xfa\xe8\x11\xb4BZz\x12\xf2\xc7\xe8W\x8c\x17\xc9t\x1b\xcf\xbc\x8aQ\xa3\xd9\xa3\xd5\x92\xf1\x04\x9dr\x8b\xdf]o\xbd&\xe1\x8c\x8a\x0d\xae\x8cO]\x06\x0cJ@\x11\x1d\xccn\xf5\x1c\x17Z\xbdMH\x04]4\x8e\xc9\xf9\xac\x95\xe7K\x9a.i\xa2\x8a\xdd/,\x07\xa7`\x01++=CI\xca\x02\xcb)\xde\x8dq\x85D\xf5|\xfaqo\x08\xd8\x8eiM\xc4\x02\x97\x96\xa5\x15W\xb7\xa4xC.\xa8\"#\xae\x0c\xde\xbd3]\x87\x82\x1a\xa7;-\xcd\xd0\xd0\x0bD\x1a\xf4H6\xa8_9\x0d\x0b\xd5\xb52Q\x16\xf41\xc5\x08\x00\xdd\x04eh8e\x99Px\xaax\xb3\xb5\xc3\xb2\xcc\"\x9c\x89\xcc\x0bW\x00>\xa3\xfc|,A\"\xda\xac\xf894\xb6\xb1\xe0q\xe4\xcd[ef\xe6\xfe\x0b\x863\xe4:}\x13\xf8o\x99\x13J\xba\xe5N\xbc\xaa\x95\x0f+\xc4\x0e\xf5\x1e\xf6\x1c\xda#\x96\x8c\x12\xf2\xd8\xab(\xc9 \xb7\xc79\xe7\xd7V{\xa2\xd0\xb2\x89\x08\xe3\xc1\xd2L\x1agv\xa3g\x94\xf8\xf8]\xb2\nR\xdb\xa2\xd2\x99\xa5\xb5\x9c\x8a\x0f\x15P\xd8\xfaoHT\xeb\xe6\xf1\xa6v\x1e=\xfb\x8a'\xa0[\xbb\x98\"\x91\xb2\xbd\x9e\xa3\x0f\xed\\\xd3\xca\xa5q\xf8\xccf\xdf0\xcb\xe9\xb75\xcb)\x95\xf58\x88\x843\x0b\x7f\xc6\xc4\x9by\x17x\x00\xa7\x04H<\xf7\x97QB\x0c\x91\xee@\x7fl\x00\xc3rT!\xc2M\xa0y\x1c\x0b5=$p\x94\x08\xbb\x92j\x02q\x1b\x8f\xee2\xd4\xc5s\xae\xbe\xe6+\x12'\xa8\xd3\xb0\xfa\xdd\x9ea\xd7\x93\xd0\x8ff\xe8\xe1\x19w\xc5wFr)\xbd\xfa^\x8a\xd9\xd4%K\xb2b*\x85\x02\xf6\"\x87\xd5b\x9f\xd8\x87\xfa\xe1\xa2\xc2a\x08\x99\xcd\xb4\x81E\xecD\xbc\xc8\xc5\x82\x15\xe6\xbe\x06&%\x0c=\x0dm\xe2\xf5 \xc2\x9a\xcb\xf2@\xa2L\xe5@\xba\x88\xa3wH\xc61(\xacm\x85Q\n^\x92\x04\x97!\x99A\x1a\x81\x07,\x14uK'?\x88\xcf\x95\x94\xaa\xbb\xde\xdePdG\x96\x143\xe6\x8a=[\xea-'\xaa\xa1[\xaa\x81\xa9\x80\xdaT\xc0\x10\x94V\x0e\xbc\xdfD\xdb\x08\xaf\xdc\xd6\xc9\x8a\xe2c\xa2R\x86#\x1f\xa5y\x9b.\x89\xc4p\xd9\xee\xa1Ccv<\x91\x01\x9a\xca\xb9\xe2 \xed\xe9\xc6$S\x9dW!$\x96\x91=\xffU\x8a\x1a\xba\xbbg\x88\x18*\x0fG\xb0\xf3\xf2\x00\xadG\xd6\x10\xacG\xdej}R!\x8a\x8f\xad\xc7\xf4\xc9\xcffQZ}d=f/\xad\xa3Dy\xf4\x04\x1f-\xd5w\x9e\xe2\x83\xcb\xf4\xa4\xa0\xa3\xd2\xb0\xb7\xbal\xc5\x89\x17\xa7lH\xbcru\x8f=~d=y\xfax\xea\xec\\\xd6LF\xa5\xc2pL\xaaI\xb4`\xb8m(\x8a\xd2%\xba\x93\xd2\xbc\xf3[\x11\xfd}\xa7\xfb\xe2\x8a\x84\xe9\x8bU\x90\xa6$\xd6)\xf9\xd5\x83t\xccc\xa1.\x02\xe5Z>\xfd\x84\xf6\xee\xbec\x07.&\xd3\x0d\xba\x9f\x15\x14\x93\xb6x\x80\xc0\x1f\xc6A\x9a\x03\xf7\xf6\x8f\x11\xf8Q\xb6^\x92k\x06:\xe8!\xe8M\xec\x85\xc9<\x8aW\x1c\xdaG\xe8\xf7\xbd$y\xb3\x88\xa3\xecr\xc1\xe1\x03\x843\x9d8;\xd8\x05r\xc2\x8f\x00\x9d\xc1j'\xffJ\xca#o\xd2\x9c\x07\xfa\xd3h\x8a\x06a\x1c\x0e\xbb0\xc5X\x0dZ\x89\xe9\x1b\x18\x1bh\xede \x91\xbe*\xc7&}\x93\x91\x96\n\x85\x05\x1f\xc2\x1ac\x92d\xab\xd2\xf7\xdaSY\xd8\x8d\xc2\\$\x0b\xd0\x81\x0e\x01\xb1\x17\x84\x96\x0b\x11B\xce\x83\xe4,\x9d\x05\x11\x957\xe4\x81\x11$*\xb7\xb7`\xb3j\xa8\x18\xe7\x82\x87\x02\x11\xfd\xcd\xc46\x17\x92\xaa\x16\xef\x8a\x874k\xf5M\xf3\xebi\x07\x9bac\x19\xe7\xb8)\xa3c\x9b\xcd^\xb2A\x85\x86{\xe03\x92\xa4qt\xc366\xff\xb1i\xb3\xbe\x9en\xa3\xaf\x90\xed\xb8\xdcN\x1cw\x97A\x92\x92\x90\xc4\xcf)\x1f\xc2\xfd\xe4\x82E(3\xb5\x1c\xc1_\xab\xf4V\xdf\xe2\xdc\x88&\xab\xe8\x8a|\xc2\xdb\xa9\xac\xb9\xf2PZ\x7f\xf5Uy\x9d\xab\xcf\x8a5\xd7\xbe\x89#\xa2\xc2\x92\xaeU\xf9\xa9\xa9\xd5ym\xabsm\xbd\xc5\xd3\x9a\x9d \xc8-\xc3\xe4R?\xab\x10\x19\xdb\xe7\n\xb6\xcf\xf3w\xca\x10v\x94\xa1\x04\xc8b^\xceM4\xdca\x8ec5d]\x7f\xab\xaf\xa0\xeaG=\xa7\xcb\xc2\xe3\x96\x19\x9e0\x1e6\x86\xc8\xa9\xa2R\x8ee\xa9\x16\xcbZ\xcd\\\x0d\x84\x00i\xa7 %\x19#\x8e,E\xbe\xb9Y\x13.I>\xf7B*LR6\x03\x1e\xf8K/I\xc0K\xc0\xcb[\xd2\x1c\x0b\xdf\xf3\x0d\x94\xcb>\x0b\xe2\xcd\x80E\xa3\xe1\x90\xd4\x0b\x96e\x08?\x0e\x8c\xaa^\xcb:$I\xd5\x8c\xe6\xf5r\x9a\x10m\xf5\xf3A\xb7\xa21S~H\xaeS\xa6\x8eR\xc7\xa9\x8af\xf2P\x9eb\xc0\x92|\xb8\xa8\xf5\xc1\xdb\xc0\xc3\xd2\xac\x90\xf2\x94\x10\x17\xdam\xa9\x9a\xf2l\xb8\xa5\xb1g!\xea\xbe\xbf\xfd\xe1\xe7\xfd\xddd\x0ex\xec\x0ci&\xd0\x11\\\x1ec\x051\xb6\x19\xb32b\x13}\xe7\xe2xQk\xddy5\x15'\x1a\xda\xa3.\x9d\x91Z\xbf\xc3\xbe2\xc4\xd3\xd2\x80\xaa8^Y\xf2\xa2%:\xbd.t:RU\xda\x98\x85u3\x82\xb1\x0e\x9bf\xa4\xaew\x0d;\xb0\xdc\xda\x17Q\x106\"\x1c\x9b\xffQu\xfe\xc5E\x0f\x8d\x17s)\xean\xdeY\xe6Zl1m<\xae\nO\xcdM\xe7\xed\xc4\x81\x10\xda#4\x81\x13\xc3\x9a \xaeR;\x7f\xe8{u\xcf1\xc5]o\xb9\x8c|\xbbg\xf0cV0\xa6\xd0\xf57\xa0]13xj\x0eXl\x08\xde\xde\x0f\xc2\xc4\x9b\x13;\x85\xa7O\x9f\xa2v2+O\x9fG\x97\xf3\x04\xb2\x13\x07'.\xc36\xd8\xacF\xfc\xe2\x04^\xde\x8e\xd67,\xb0\x01}\xa5-\n\x96\xa2\x18dl\xd2MS\x1c)S\x9c\x03\xdeSI\x0b\x03s\x06\xdd L\xd6\xc4OK?\xba~\x96\xa4\xd1\x8a\x91\x89\\9\x93/\xd0\xb8ZpZ\x87\xecb7\xe7/i\xd4jlXC0\x92\x1c}\xb8\x1e,.\x05z\xcfMo\xec\xe2h1^\xe3\x89{c\x7f$\x1d\xfb.sw\xbd\xddF+\x90\x88\x0fS\x1cu\x13\x92\xbe\\\xad\xc8,\xf0\xcc\x1e\xae\xdc>\xc3|\x8cx\xcab5&\xb3\xfc\xf1k\xaej\x007\xdb\x98L3\xc0M7iw\x16\xf9\xa8(3\x97[\x97\x12B~_ \xc9k\xcc*\xa7}`\xcc\xa7N\xab\xc2\x8clk:'o\x82\x15\x89\xb2\x14NaM\xc9\xb5[D\x8c\xe7yk\xa6\xccq\xfa\xab\xf7\xdd4bW\xdb\xf9\xe9[$\xb6aQ\x8b\x9a\xe8\x88\xf8Hf\xa0Z\xca-\x7ff\xb6&\xaa\xaf\xf8\x98\xf4[0\x94Q\xa7\xae \xb4\xa1v\xd7Q\x92~\xca\xb3\xf9\xb3\xac?\xc1\x8an\xc93?\x0e\xd6\xa9\xd1\xddG|\x04\x11\xd79\x08V?x\xcc\xefF\xe1\x8a5Woh\xcf\x85\xbf\xbc|\x13\xd3\xab~\x88\xde\x84 \x7f\x18o(f\xc0\xb6,\x17\xac\x0f-~\xa8(\x1a\x0e\xab\xa1\x94K\xb5\xe8W\xc2vP!\xc5\xab~\xbe\xf0\xc2\x90,\xe1\x14l\x1b\xa3\xa7\x90wP~\xe4t\xe9\xbc\xf7\xf5\x03\xaeE\xae\x99\x9d\"\x057\xa9<\xb7\xc0\xd3\x08;1(M\x8a\x01\x0bQ5\x86\xc6E+\nc\xe2\xcdn\x92\xd4K\x89\xbf\xf0\xc2K\x82i\x92\x97\xa3\xddvD\xbe\x8b\xe2\x0e.Z\x06\x0d\x97\xbd@r\xfb\xaa\xdf\x85\x94\x1f_x\xfe[\xe3qV|\xbc\xf82\xd1\xf9\xdb\x89\x8f\xe1\xae=\x14l\xc8\x1f'S\xa6\xdf\x8e\xed\xc4q!i\xb7M\x08\xb7fG4y\xed\x16J\xd9:\x1f\x82\x85y\x89Yzw\xf0\xab\x81\x9b\xa1\xa1\xca\x1a\x1f\x15T\x8e::\"\xa1\x9f\x94\x86\xbb;\x02[h\x17\xeb}\xf4\x1a}\x9e\xe7\xdc\xf5\xa6\xaeL}\x9a@\xf1im\xb8{\xe4O~:\xed\n4k\x16p\xc4'\xc6\xf7(\xd6\xd5\xf7^|\xf2\x14P\x0d\xba\x0b\xdd\x07\xfd\xae{f\xdf[\xdd\x87\xd4\xf9O\xea>\x0d^\xda\xd5\x0f\xf6\xa9\xbfm\x9f\xe2qo\x93\xbbU\xf2\xe7.\xfd\x1a\xdc\xa5_.\xc4\xe3\xfe\x8f\xa3w\xbbw\xef\x1d\xfd\x7f\xf0-\xf7\xb1\xd1\xd5[\xf7A{\xfd\x12U\x0e\x1aw\x0f\xddG/Q\x97J\x98\x84\xa3\xbc\x00\xcc\x83\xd0[.7\xa1\x0f\xccp?\xdf\xe0\xbc`|\xba\xa9\xdfoE\xb7g[Y\xc8\x02\x02\xcedY(!\xcby\x11\xa9?\x0fN\xbc\x08\x12\x0c\x83=\xc4\x02\x92\x0d\xb8\x949\x14y\xb1\xd9\x15`\xf3[Q9\xfb0\x90M3\xf1E\xdd\x03\xe9.#\xdf[\x9e\xa5Q\xec]\x12)\xa2\xa3:)r\xfeTm\x855\xef*\x10aQ.\xb7\xaf\xe5GBa\xc8sn\xa07\x99\x95\xc6\x19a\x87\x7f\x1e\xd2.t\xbai\xf4I\xf4\x8e\xc4\xcf=\x8d\x01Y\xfe\xb5q\xf0R\x10wal+\x8c>\xe2A\x88\xd0\xc0b\x8a\xbd\x0d\x92\xb1\xa9\x1a\x15\x13\x8a\xb14\x9eapm\xb4ai\xe5\x12\xa1m\xa1\x85\xa8\xd2\xb5\xaa\xef\x91\xee\x1e\x81\xf8\xd0*b\xcf'\xa5*\xe0\x14\xfc(L\xa2%\xe9\xe2C\x16\xc0F\x80\xdeyq\x88g%\x1c\xa4\x1aD\x0f\x8c;-W\x170R\x93\xa2I\xaap\xc4j\xda\x87\xc6\xad\xb4\xd1\x1e\xd2+\xe2J\x19\x96\n\xb0\xe4\x06r\xac\xcb\xa3\x14\xda\xfb}\xed\xad\xcfH\xdd\x1e\xdc\xb6G\xe9\x82d\xde\x8b\n\x1c\xa2+\x15\xa9\x01\xc9\x0bG\x12MpS\xac\xb8\x1b\x84\x0b\x12\x07\xd8yt,q%\x98\x1d1'\x93H\xd2\xab\x9f\xa7\x92\xcbH\xddd\x01\xa2\x06\xb7DT\xdb\xde\xc2\xb3\x86.\xcf\xe1F\xcbS~k\xd0\xbf\xc3K\xfd\xfe\x81S8\xc5\xdc\xf1}\xc9}f\x93\x1a\x9a\xec\xcd\xfdc}\x16\xc4\xfe\xb1>\xcf\xcd\xdeAs\xac\xf6\xeaBqK\x04\x0bH-\xc7P\xd2\xeb\xcc\xb3\"zU\x8c\x97R\xd1*g\x13)\x8a5\xe6\xd6\xcb\n\xebWau\xe8z\xc9M\xe8\xf3\xe4\xadYw\x1d\x07\xab \x0d\xae\x08\x9c\xe6.0pZn\x02\x87u\xbc\xef`6\x0c\x1e\x03\xca\xd6\x948pl\x82w\xe5*\xcf\xa4zi\xb1C\x07S\x0e\xc8\xc0\xfd^\x9f\x01\xe9\xd7\x01V\x93w\x15\xfd~\xec\xfd\xde.\x82\xd6,!\xa7\x00\xee!p\x16$\xeb(\x07\xf6\xd1f\xd3]y\xd7\xcf.sX_\xc0\x04\x80\xbd\x19\x939\xba\xa7\x90X\xc0\x0f\xe8\x8e\xa3\x88\x92m\xb9k\x9a\x10i\xef@\x17\xb9\x1du>\xdeE\xa2\xa2\x12>\x99/#9\x97\xf5f\xe8\xc4\xd1$H^y\xafl\x8c\xfb\xcf\xd2x \x96\xa40\x82W\x18\xc3\x153H\x0d\xd8\x9e\x92\x07\xc6\xcb\xc9l\xfd\xe4\xe8\x02\xd9]\xb1 v\x89\x0b~y\x81\x03L\x9dBe\x1f\xbb\xc8?_&\xb9\x8eDv\x04\xb9\xd1\xb8\x83\xbf^\xd3\xc6\x13x\x8c\xa5\x1f\x83\x17\xce\xe01/\xfe\x18|\xe6\xe2sA K\xd0]\xfc\x92\xa4\x0b\x12W\xb5\xe5|\x19\xcbazr\xd1\xc8:?\x17\xd1\x19\xce\xcf-\x16\xaf>\xec\xce\xa3\x18\x9dp \x0cYf)\xcf.B\xe3\x93\xfc[X\x0c#\xe24\x9f]\x0c\xcbh\xd5 s\xd7\n\xa8\x8c\xd1(A\x87c\x82q]R\x1e\xa8\xddW\xee\x13\xb1T\xce\xe7\xe7\xeb8\x9a\x07K\x12\x9f\x9f\x03\x8f\x14^@0$\xa6\xdf\xcd\xd63/%/\xc2+\xbcJ\x9d\x87\x9fx\x90\xbd\xd3\x88\x93\xbb\xba\\\xbcBU+\x89Y\x17A8S\xb1TS\x90.\x95\x8a\xb6r\xe2\xff\xd2\xc3\xa4x(y[\xf1u\x7f\x99\xbc\x08\xb3\x15\x89\xbd\x8b%i\xa2\x07\x9b%j\xd0\xde\x84\xa2\x934g7\xd3\n\xbc\x1f\x18\xe27\xacK\xa5vk\x0ew\xc5n\n\xec\x90\xa58\xf3\xf9q\xdf\xb3)\xae\xa1Ux\xdeM\xa28\xb5\xb5\x04v\x8d\xa9W\x11\xf9\xd7\xb8\xdc\xc3\"\xfbL\x83\xc6}>N\xa7\xc8\xcf\x99\xc4\xed\xd2\x01\xca\x93e<\x88\xf1\xde'\xecE\x96R\xf8T\xd4\xe3\xbb\xb0t!\x1c\xa7S\x17R\x91gD{\xa3\xdctX}\x10\\\xde;\xacRR!\x81\xea\xf3E\x1c\xe9\xd3E\xec\x1d\xf5\x9d\xee\x8a\xa4\x8bh\x96\xe8(\xed\x9e\xf2\x1eg\xd6\xc7\xba\x04\xd3\x9a\xbd\x80g\xc2r\xc9\xf9\xa6\xbbfYl\x0cff,?\x96\x1c\x14J\x89\x1d\x94\xf0\x9d\x0b\x94\x81\xa3J\xcc\x80\x19B\xc9*hL\xdd\xa5?H\xa1o\xb7\x0bW.\xdc\xb8p\xe9\xc2\xca\x85s\x17.\\x\xe7\xc2\xb5\x0bg.\xbcp\xe1\x99\x0b\xaf]\xf8\xc2\x85\xb7.\x86\xb1Z\xe2\xe9KO\xf0\xaf\x98T\xdc\xe2\x020%\xe5\x9cw\xe7\xbai\xc6\xabS\x89\x9eK25\xc5\xfb3\xcct*\x831\xb8\xd3\x08\xce\xba\x97$e\xd1\x87\xcf\xba \xfd\xba\xc2\xaf\xcc\xac\xe1b\x94\xce3f>q\xdcB+\xd3\x8dI\x12-\xafH\xcc\x82\xcc\xbe\xe5\x9c%\x87\xd2=\xfd\x05\x8f\xbc\x144\x04a\xe1\xfc\x97\xfbU\xe5\x04D\xa5\x1e\x94\x1fcp3\xb4\xd6\xbf\xb5#\xa7\xe8\xd2\x88\xf1\xe8\x1b\n\xa4Et\\\xf2%]\xad\xfc\x1c\xfe\x82\x16\xcb\xb8W\xf2%I-\xdc\xb4\x11\xf3\xc5s\\x\xa9\x8dhO\xfb\xc0\xd2\xf2a\x94\xe4\xc2\xfbp\x9e\x93\x13v\x86\x8f\xc6\xbd)\xeaQ\xaap\xd1\xe7\x11\xcb}c\xd6\x08iF&D\x8b\xd8\xb6\x9e\x07\xb1\x9f-\xbd\x18\x82\xf0*\xe2\xaa\x1c\x17\xac\xe7/?{\xfe\x83O\x9e}v\xfe\xf2\xd5O\xbd~\xfe\xec\xcd\xcb\xd7\xafLVwZ\xeb\xa5\xad\x89_\xfe\xbe\x08i]3\x8d\x0f\xd4\x13\xbe\x1a/\x99=2p\xe1\x99\xbc.\x89X\x17n\xc1\xa7bH\x99|\xbap\xe5\xe4y\x07\xe9\xfe\xa8\xd5\xb6\xe1\xe1Y\xbf\xaa\x86\xa1\xb2{\x02\xb5h#\xae\x12\xe4\xa8[\xe0\x90\xc1\xa5\x10\x8dm\xba\xa0\xc9\xa7\n\xbe\x14\n3\x18V\x90\xccqMh\x9ew\xfa\x81\x17\x89\xf9\x03\xa0\xbf\xb0f\x99\xf2\xfb\xe3\xb8VD\xcdu.\xa7\xfa\x7fXR \xdf\xefD\x8e\xc7\xf5\xc4\xb8\x0b\x8d\xd3\x14\xd4.kP\xa6\x06\xba\xcc]\xb8M\xefK\x0dj:\xf7\xc0\xcb7\x0e\xe8\x1e\x0b\xb5\x8b\x17\x88u\xa3\xe2\x97\xe2\xae\x9bi-\xffQ\x1c\\\x06\xa1\xb7\xd4Z\xfb\x85\xb0>\x84/\xd4\x87\\\xd2\x7f\x85\x91\x83\x90\xdb\x8b\x9fj\xd9K\x92nr\x0d\x94\x0f\xf2m.\xe7\xbd\xb5S\x07\xb9\xdc)\xdc\xb0@\x0f\x1c)R\xba\x18*\xd5S[^x\xc9\x16-\x1b\xd6Q\xe3\xda\xa3i\x8a\xf1\xdbMZ3\x900`\xfd\xd5\xf7\x00\xe7\x04\xfd{W\xccM\nF\xf0\x12EU\xee\xbe\xc0~\xbc\x96\xd1\x82=\xb1P\x9a%\xba Q\xea PL\xd8 #\x8fP\xac\xbc\xd4\x0f\x03\xcf\x83\xe7\xf4\xc8'\x89Fn\xde1l\xc5\xdatb\xa3R2\x9f\x9aK9B\x9dC7\x7f\xae\x0ey\x81F\x0f\xccI&\x83\x9f\xe5`>K\x85\x1b\x95\xfdZD\xf1X\x94T\xfa\xfa\xb8\x15j\x7f\xe9\x18\x870S\x1f\xe4g\xe1\x0d&8e\x92-\xdf\x9ej\xb3\xd5\xed}\xa1\x8aj\xe6{,n9\x87\x8e\xba\x86l\x0b\x86\xb8\x05\xc3\xb2\x8cFP\x92 \x99\x8c\x96q)\xb3j7\xde\x92\xa7\xe7\x8an^\x1bg~\xe5*\xa1iki\xc8G\xc1T\x18\x17\xc9[\xa8\xa6=w1\n}P\xefF\x8cH\xdf8w\xbc\x1b\xc5\xd09\xcf\x1d\n~'Mk\xcaW\x8dNhA\xddB\xd6Y\xba\xa3U\xbd\xcb\xf5\xb7\xd6\xcf\xac\xbb\xf0\x121\xf7\xda\xee\x16XP\xd3q\x8e\x18\xb4\xaeT\x93pum\x7f\xa1\x0b\x8c*\xeb\xbe\x86\x10a\xd8*#\x89\x8d\xec\x0b\xcdSN\xbb\";\x13\xa7\x1d\xb5\x15\xe4D\x91\xfdN\xf7\x0cyEd_\xab}\xcer\xc8\x83\x9c\xf0\xfb\xc7\xba\xfc}\xf4\xe4\xaf?\xe1\x0ft'|\xd4Kv}o\x9df19K=\xff\xed\x9b\xd8\xf3%\xb6B\xe48\x1d\x8d\xf6\xa8\x90;#2u\xa7.\xf7\x98\x07\xe5\xfc\x1fj\x89\xa4\xa2c\xd2\x9e\x85#;\xe1\xa1\xb6<\xc6\xd4x4R\x91\xb8\x1f\xed1\x89\xc8\x14\xc9n\xe1F\xa2l\xd8\xf5\xa3\x19\x8a\xddxO\x87\"\x1a-CJ\x02\xcf=\xd6hs\xa3\x02\xe3\xc0\\I\xc1\xe2\x84ln[`\xb1l\x88\xad\x8f\x882\x8f\xa2!X\xb1\xf7\xa5U\xa5Qj\xd9\x0b\x8a\xf1\xd6\xec\x9d\xb7A\xd94\xfe\xf2f\x08\x16\xfdS\x0d-\xecb\x80\x9a\x08s\xb7]x1\xcb\xe1\x16\x7fy\x83\xb4\x81ve\xf6\xce\xc3\xf7\x1eXo\xbbgH\x8d\xaaU\xdc\xa2\x11g\xe5]o\xa0\xd41\x18\x08\x8a[8\x91\xe2o\xeb\xc2\xa0\"w\xa3\xa3n*+:Q\x1a-yhk5\x8df\x17\x9et\x1cS\xf9\x9d\x8cc\x8d\xabi\xa3\xbfN\xc8\x02\x15\xd0}\xdd\xe8{\xc1\x04\xfe\xfe d\xf0\x04\x92\x13h\xb73v\x7f\xad\xd8\xa0\xd9\xd4\xc5\x80\xb7yh\xa2jv\x82J\x1c\xb407\x8bh1\xfd\xdb0\x1c\x1e\xee3\xc3\xa1\xa4ag\xa6\xc3\xc3\x83o\xdbt\xa8_D>V9\xae\xac\x95\xdb\xd4-\x8c\xb4X^\x87\xdaE\xd5;`=\xb0>Y\xe1\x1eA\xd9d\xd1\xb4\x9d\xaa\x1d\x17\xe6f\x8c\x84\x9b\xaf\x0d;\x9em\xebzr\xa7\xbek(&oB\x1fR\x9d]A\x1b*Ks\xc7\x81\xe3\xb0\x1f=\x82`,\xec\x12\x98\xbe\xa1\xf5 f\xd6*\xfe\x1f3\xfc\xe7w\xe5J\x17nS/\x08\xf9n8\xea\xddc7\x88\xd9\x96\xc9\xfc\x96{\xa5\x8e\xd7\xc5E_1\xe7\x88\x08\x17\"\xa06r/\x91\x9d\xbb\xfal\x1eE\xd6\xc3\x18\xda\xc50\x95\xa9\xe4wa\xee\x8a\x0d\x95#b\xc9\xb6\\NDy\xdf\xceW\xee\x92\xba\"\x18\xbb\xc6\x04\xb4\xd4[E\xd7\x1b[r\x16\x9bZrf\xf5\x96\x9c+\x83%\xa7\xd2\xdc\xcd\xa6\x06\x9fK\x9dE\xb5\xac4)\xbf\xb0\xd2\x12\x0c?\n\xe7\xc1e\x86\xb6W=\xd1 \xb9mV\x1f\xf5Z\x04I\xaa#+j\x9akJ\xa2\xe2&a\x05\x84\xc0b<\xb3-\xd1\xa5\xe1RF=\xeb\xfc\x9c\x10t\x1b8\x95b\xcb!\x8c\x1e\xe5(h\xd5\xc5\xbc\xe70\x82\x99P\xc8\\U\xdeva\xe5\xb8RA^,\x1c\xa7S8\xd5\xc5[\xe7O\xe8\x1f\x16\xac\x0d=O\x11:\x821\xb3\xa5\x92i\x01\xe2\x91:\xca3V\x11\xf5B\x9f\x0c\x91\xd0o6K\xae\x1c\x0eL|J\x13\x15\x88\x88|\xcan\x0d7\xb9\x9f\xc8\x8d\xd4\x01{\x03\xaf\x91 \x97\x8df\x8fX\x8c\xadCg\xf7u\xe8\xe7\xf1|\xce\xcf7\x9c\x8a\xf9|\x88\xa2\xef\xa63\xc1i\x84^\xcd\xcd&\xa3\xa5G\x9bR,\x05\xfd\xfb-\xbb\x82X\xce8\x9dn\xf0\x9e\x8a6,\xb6(}[\x9d1\x10\x92w\xc4n\xbe\xd1\xc5\x8b\xc7\xd1\x94\x8a\xb0\x91\x03A\x11\x927\xd0\xcd+{J\xe5\xe4\x81\x88K%4\xfa\x1c\x05\xe3q\xc4]\xe40ie\xdcM\xd6x\xeb1r\xa1\xaf\xbb\xb7\x87\x96\xb4\xb8h6\xaem\x96kc\xc3:\xcf\xf8\xa6eg\n\xc4\xac\xf1~\xe2U\x1e\xd1\xa2v\xdd\x0dt\x82r\xe3\xa0\xbc\xa0\xe6\x15\xd1\xafc}\x1cx\\\xc5Pc#c\xb6!9\xd5\n\xbb\xebH\xd8\x89\x85\xc0\x13\x08\xe9r\x13\x07\xa21\xa1\x0f\xcb\x17\x1dI\xcd%8l4\xc0\xe0\x15\xec2+\xaf\xb7w\x82\x847\xa0/\xb3\xaa\xf9.\x8e\x0bC\x8e\xb6RnJ\x15\xb7\xc9\xaac\xa9\x9b\x80Mnl-\n\xe2\xb2\x08\x92\x86{F\x0d\xf7\x8a6\xb9\x89Un\xaf\"\xaf\xdc\xbf\xf5\x86\x9bVu\xad\xbb%\xdd\xd1\xfd\xfa\xb2\xd1\x8d\xaa\xbf\x14\xfc\xa4\x9fue\x16L\x98\xf7\x1d\xfd\xaf\xf7\xba@\xcch$\xb1\xab:O\xc6K\xe7vP\x85S\xc62\xb7#GGx\xe6\xb6\xec\x0b\xcd\xbc\x08o\xec\xaf\xde3]\x9c,\x1d\xd7_\xa1\x16\xaeb\xccU\x02\xad.3\xdbgq\x88\xf3C#\xadTn\x8c\x08\x9f%:\xa3\xdf\x81\xfb\n\xcc\xdc\xd5\xa9\xea\xd3_\xa3W\xd5\x88\xcd^\x9e\x9b\xb0\x12\x99\xb8h\xaf>p\x80D\xf7+i\xb05\xdeG\xd2\x0b\xe8,d\xa7\xe3\x10-\xcf\xf4o\x19%\x1c\x91\xf4\xce+\x19\xa5\xd5\xeb\xfb\xef\xdd\xedN5\xa8\xf6B}\xd7\x86iy\"~(\xce\x14\xcb\x8aC\xa5\xae\x8b ,\xc5]\xb9\xefQ\x88\xadS\xffX\xa3\x1d(%\x94\xbb\xe3\xa1.`\x9a\x8d\x94\x8a\x07\x0f\xd4\xed\x8d\xce\xd1B\xb3\xcc\x04S6\x92y\x1cUrq\xd5\x9d\xb6Y\xe8v\x14\xddq\x0d\xc7\xa8Gv\x99\x8ax\xea\xb8\xf0\xbd(Z\x12/\xb4Q\x94!E\xb8e,\xc0LA\xe8\x15\xfd\x10c\x96\xf4\xbcG\x07N7HI\xec\xa5\x91>\x90\xe3\xb1\xde}|O\xb9\xcd\xc5\xf6\xe8\xa0\xba\xa3=\xfd\xd6M\xf4\xead_\xbf\xff\xe7\xbc\xcdj\xe5\xcb*^mt\xacV\x0f\xcb\x8b\x878\x8cj\x9e\xcb\x87Q\xf5)\x1e\xe64\xf1\x17\xdf\x1bO\xf2\xe5\xa3\xfa\xb6\x9b\xa8\x10K\x8d\x1e\x94\x8d\xa6\xa4\x17\xb5\xa6$\x0c\xb2T(\xe6\x13\xa6\x98\xf7\xed3\xa4A\x9e}\xc6\x83#\x02\x8f\x16\x8eh\x8e\x0bG!\x11\x0b\xf6\xec\xe4q\xf2\xca\x95\x1bb1\xe0 \xe8\xcc$\xee\xa1S!\xde\xa0\xe1\xbb\x93y{\xda\x97P\xc4\xe9\xa7$\x85a\x11\xbf\xb9\xcdo\xeb\xd1\xf3\xb9}S\x928\xfa\x0e&+\x1bA\x8a\x17\xd1o\x0c\xd2\x10;\xd5\xd1V\x1b\xa4\xf0r\xed\xa5N\x95B\x8c\\R\xb1&t\xe0\x86\xf9\xf2\xa5Z\x07J\xf1\xe1#5$\x0cU\xa0*\xe4\x06\xb3\x05~\xc7\\\x08\xe7|\xa9\x98\x91A\xb5M\xd8\xef\xb0\xbb\xf1\xd48\x178\x0f\xe7\xe8\xe5\xfa\x8e_Ge~4\x94`\x8a\xf9\xa1\x07\xe4\x0b\x18\xc19\x06\x16\xb3\x8b\xc9i]tgQHN\x1c\xb4\xbf\x9f\xc1\xa9\x10\xe2\x983\xf0\x05\xd3\x98p7\xf6\xfc\x17\xe5\xdf\xf6\"\xd7\xa6\\\xbb0\xb3opg,\xf0\xae\x15\x9f\xe6\xebj\xa3\xed\xb6!a\x16]9Mv\xa0\xc2\xdbs^\x83\x0d8\x03\xf2\xda\xebF\x8f\xe3uQoW\xc1\x89k\x8e\x10\xbfz7\xa4\x82]#\x05\xbb*\xc7\x92\x1c\xa9\xb6\xc0\xa2\xd8vx0\xdb:\x9bt\xd5\xd8\x0c| f\x8c\x07\xd8\xb3\xa2\xfbn\x8d\xccW\x89\xb0\x1b3\n8\x1b\xa7,\xcb\x1f\xcb\x9e<=q\xa0\xdd\x8e\xb5\xd4\x0b\x8b\x8e\x80\x17\x9d\x8a\x9c\xab\xf6\x9a\xa9]\xac\xef~\x17\x03\xab\xb9\xe0u/\x13.:\xd5\x1fI\x0bo V\x13\xd3\xb5\x10\x17<&.\xe2\x93~\xf5\xb4Zry\x97\x83\xd8F\xb52/J\xa4J\xc4\x08}y\xfa\xf9\xf9\x8c\xb00\x94A\x14\x9e\x9f\x0f\xc1\xc3\xd0\xa2D\xe7\xccw\x1ez+R\x94\xb9\xb2\xab\x0e\xd0\xef\xcb\xea\x91\xb9\x1dT\x9b\x9cG1}\xbd\x1e\xcb\xf8\xa0\x17\xcc\x0e\x86\x7f\x86\xec\xcf\x08\x02;'\xe8\x8aR\xa4\xf4\xfb-\xb9\xf9x\x93\xc6\x0c\x8e\xe3\xb8\xf9\x08\x04!$(\xd3.\xcc:\xfc\xc5\x98L\x99\xa7s\xce\xc1Hm\xd7\x16^\xf2\x92c\x89\x98\xcb\x98YA\xa4'\xcc\x9f\xcf\x92 J\xaa\xf4 y\x8e\xaa\xaa\xb3\xb5H\xf6R\xa9N-\xc0kU\x1f\xa8\x95s6V\xad\x92\x83EE\xfc\xa7\xf2\xfa\x8a\x92\xc3\xca\xbb\x08\xe3/\xe2w\xe5-\x9e\x13\xa9\xf2\x9e\xc8\x9a\xc4\xde\xe4\xbf\x94w\x13\xe2\xc5J\x93\x0c\xc8\xdfd?\xd4\x17\xd7\xc4\x0fHR}\x93A\xc5\xab\xec\x97\xe6\xdde\x90*o.\x834\x7fo\x19\xa4\xca[\x92\x08PyWz\xc2k\x90 \x9azrAA\xa9'\x7f\x92\xd7\x93C\x94z\xb20\xf1\xa35E\x83\xea,HOx=\x12\xa4\xe4E\x82$F\xa2J\xd5\x9d/\x119\xdaFU{.\xba'\xda\xaf\xb5 \xcb\xba_A\x95*;\xae\xd2\xb1\xc0\xdc1\xb9\xe5MZ\x15\xe4\xdb\xc6\xec\xedL\xef\xd1\xad\x90Qh\x83\xe5(\x0e\xa1\xa5\xdfx\xa4x=\xdf\xb4\xd5\xa4\x92M\x0b\xd4Q.\xcb\xa3\x0cddr\x9b\xa6U\\>\xe1\xed\xe8\xb5\xa3\\\xee\xae\xe4\x86\xc7\xe0\x189\xc6\xd9r\xa7\xf4\xbd\xca\x11\x11{\xe5[\xae\x98S\x8b\xbd\x105\xbf\x10\x94\xe2\xf0\x97\x04f}\x15\xe5\x99\xd0UQH\xe5\xf7\x89\xa5%\xe9g\x8f{[G1b!\xcfP\xdf\xa0\x93\x1cR\x8c\xea\x9f\xcb\x0d\xfac\x90\xd8\x1c\xc52\xdc}4\x9b\xf5:?\n\xb1\xab>Z4\xb9\xbd\xa5\xcf\xe54\x05\xac\xecY^\x16#\x98V\xb3\x18\x9e\xf2\x8b{\xb4\x1d~'\x8ecj\x87\x87\xfe\xb0\xa3b\xd1=\\\xf4\x80\xa2=\xf3\x93\xc5X&\xe3\x1e\xf7q\xc7\x07\xf4E\x17\xbcq\x9f\x03\xbf\xc5\xae\xe7}\xefO\xc7\x11\xe2xvr\xaf~;\xae\xa8\x8c-\xe0\x1d\xf0\x97k8\xb5\x99\x16\xd5\xa1n\x17\x1b\x83\x07\x8f\xa9\xc1\xe4\xac\x1e\x93=\xee^^\x8f\xebyn>c)\x1f\xd9\xc1\x06{\x81\x0b[\x19\xc5.\xf3f\xa0\xaf`\x1a\xc0q\xb2 =\x8d$,\xdd\x9c\x9eJ\xd2\x7f\x86\xe8\xe0\x8d#\x89\x9e\xd6\x93R\x9f!J\xc6\xe24\xb1\xbe\xf6\xa7\xe3\x00\x91.\xba\x03a}\x90\x9e\xe5\x17q\xf3\xce\xd0\xf7\x85\xdf~\xe0\"B\xd3g%\xd0 \xb4\xb0\x18\xb7\x7f?z\x04\xbe n\x0e2\\\xbf\xbb\x8e\xd6\xb6\xe3\xb2E\xe1\xbf\x9c\x0dj\xdeb\xbbH\xd7\x016\xd9'\x9b\x86_\xe1r\x8a,\x97\xa8\xd5\x7fG\xff\xeb\x1eRY\xc5\xf0\x7f\xcco'\xb2\x90\xb4]\x0ci\xc7\x83:\xdf\xe7B\xe2VB\x9c\xdc\xf66G9\xb4w\xa7\xf6W\xef\x91P\xa6\xf6+\xef\x15\xbb\x83\x98\x16I\x1e\xe0\xe1fk\x03\xa9\xbf5z\x18=XYt\xbe\xe3\xb4n)\x1bW\x89\xe4C\x88\xc5\x12\xb9 .:\xc2\x19\xbc\xe0\xca\xc2[PHi\xe18\xd8h\xd7\x95\x85\xac\xa6\xe0\xa1,_6K\xac\xe3B\xc8~\xb5\xdb\xa9\xf3\xed\xf0BIc\x85\xf9\xa3\x90\xf1\xb7p\xa0\xec\x0c_&Va\xe9\xb7\x86*<\x0c\xd1\xd1\xc8+\xdf\x02\xbdy\xc8S\xa0^\xc9\xa0G\xf5\xd0(\x8a\x9a\xe48\xcd|hJF\xf7\n\xc7\x15\xcd\xe09\x82\xb8\x10\xa1\x7f\x01ECM\xd8\xe4\x0dh\xe1F\x18\xce\x8e\xb9L\xcag\x83\xa5d\xc9G5\x00\xe1\xc7\xbb;\xe3<;C\xf9x\x86j\x16M\x136#\x9e\xcb\xf3~\xf3S\x1aC\xfel\x0b\xe4\xe7\xbdi\xd5\xf6\xa6\xe1\xc8@\xe4\xe6=U\x90\xf54\"\xb2W\x16\x91\x93\xb2\x88\x9c\xe4\"\xb2W\xfc\xd2\x88\xc8j\xcd\xc6\x9er\x89\x98\xae\xd4\x86\xd3s\x0f\x96e&\xe4p\xc7\xed\xe5\xcaD\\\xed\xeaw\xf4\xbf\x1e\x86\x07j\xef;\x85v\xff\xb8\n\x8f8\xfcH\x7f\xbfM $..\xcfT\xef\xe0$\xa6\x8bo\xe5b\xdb\x05\x0870mL\x15\xc1\x93\x184\\x\xe7J\xd3\xa5\x0bk\x17\xfd+\xe7\xdcAQ\xa5/u\x0f\xaf\xd0\xba!\xc2\xce\xa9\xcfo\xf0\xb9\x08\xc1X\xc6\xe8\xe2=\xf4\x08\xaf\x97\xe5\x84\xa4QD\x17\xd6\xe2V\x8c\x91\xa1DJ\x07\xbcVj\xd4\xd4\xebC\xad\x80\x88\xd7\x1737\xbb$\x17\x9f{.t\xfa\x945\\\xf1\xcb'\xcb<&\xc2\x9a6\xab\xda\x9c6rX\x8eli\x02\xe1\xaa\xc6o\xf9}e\xfa\xa2P\x04\xe9m\x9e\xbb\xda\xdb\xed\xda\xfb\x93\x90\xbb\xbbI\x11\n\xb4s&;\xee\x8d`\xbc\xc0\x88\x15\xa1p\xe2c\xd4=t\x98\x0d\x0e\xa7V#\xbd\x89O\xcc\x18\x12\xdd\x95KF'\xd6LZ^b\x96|\xe1\x92\xdf\xe0D#>(\x7f\x98\xe9\xa8.R\xec\x8c'4@~=c\xc17\x8a\x80\xc8\xb8\xb7X4\xd8\x88\xf1+\x1e\xcb8\xc6T\nQ\x98\x92\xeb\x14\xf30\xc5\x97\x89\x93\xfbo\xc6,yD\xc00%*P\x88\xae\x89)Et#id\x99\xbe\xf9\xdej\x8a\xc2q\xc5\xeeEr\x9fp\xe3\xa6\x08\xe9\xd0\xd3rV-\x1e\xfeCT\x0f\xa9\x19a\x84\xfc\xccD\x8a\xb4\x1b\xcc\xcc\x9a?\x1e \x13jS\xf9\xd3\x82\x9c\xdd\xd1\xdaXO\x16\xe3\xa4\x08\xda\xcb~\x04\x85MF\xe9>\xbf3\x86X\xa1\xf4\x8a\xffX\xe2\x8f\x9cq\xc5\xdb\xf5e\x81\x0eZZ\x94\xc6\x1b 6-\xc0\x88\x8e\xc3\xa9\x0es*^8\x90u\xe9\xcf\x0dD\xa1\xc4\x9esa\x85\x8b\x14Z \xa5qJ\x12{\xad\xe3\x0fj\xefs\x1a\xc2\xa8\xa2\xe8\xaf\xf9x\xa6\xbd`\x9b\xe1M\xfb\x0d6\xc5g$\x8d\x03rE\n\x8a3\x8b\x08#D\xc1j\xbd$T(\x12h(\x90\xf8\xb1\x96*\x89\x0fk\xda\x9e\xbb\xa0\x1bqe|9\xb5\xff\xafq\x9c\xe5\xcdj\x1aoM\xdf\xf8\xfb\x0f\xd6\xbd\xbc?\xdb\xf5P\xac\x08\xe6n\xe0oh\xd1\xb1\x04)\x04\xaf\xaa\x8a\x81\x85\xca3q\x1a\x93\x8a\x01\xf9`\xbb\xad\x0f\xeaW\xe3\xe7D\x19\xc0R\xfb\x12\x88\x03\xfe\xa64I\x7f\x8e\xc7\xc1\xe8\xe9\x8e\xbeM\xcf\x8e\x1c\x93\x8c\x1f\xe1\\cVF\x9ct\x84x\xb3\x03I\x1elH\xf2\x7f\xd5\xefa\xe9\"\x1asj*\xee\x84y\xccO\xb1\xd5\xe9x\xe2\xe4R:\xac\xb4z\x98\x9fP{]L\xc3\xbf.I\xfa\x19G\xd0\x1f\xd38z\xc5 <\x16LV\xb3\xfd\xef\xa7\xd4\x92\xd2\x0f\xe96X\xe8B%DsXD\xecm\xf1\x88\xbd\x04\x86\"\xa5b#s@\xaf\xb2\xee\xf3\xb33\xba\x1c\xf8\xa5K\x12\xdf[\x17\xfaT\x19\xa8N\x95`,\xcd,H\xc4dP2z\x19\xbc\xd8\xfef\xd1\xec\xdf\x84\x98\xfcl\x16\xc4$\x01\xaf\x08}g\xf4X*\xc5\xbb\x96\x82L\xf1\x10La\x9ea\x81\x12\xcfN\x9f\x1d\x83)ya\xa2t)[\xc2 \xb4\xdb\x01<\x81\xf8\xc4\xc1\x19\xe6\xf9{\xe4B\x01\xde{\x8c\xa0Mg\xff\xe9\x08\xfa(\x05S\x01d\xb7\x8ftgp\x08\"\x03!N@\xc0\n<\x1d\xc1\xdeQ^v\xff\x10\xcb\xd6=\x7f\xf4\x08\xf6\xf6i\x81\x8c\x12\xc6\xc9\x04\x83F\x15\x96\x89\xfe\x01Zr\x80\x12K\x1b\xfb\x1a\xb0*[\xfdJ\xd8\x01\x82uup\xc4\x1f\x88\x0e\x1e\x17_\xf5=D\xe8\xc1~\x0e=\xee\xe5\xd0\xe3\xc3\x1c\xda\x1f\x0c\xf02(\xce\x13\xce\x11\xa5\xe0\xac\xcbe \xce\x9b\xf5\xff\xfe\xc5\x9fY\xb5\xfbPuz\xd78Q\xc8\x18\x8b\x1a\x18\xf6\x0dO\xdan \x91Y\x8a\xcfJt\xe5r\xec\xeeX\xd6\x1b\xbew\xf2\xdb:\xa1\xdd\xef\xdf'\xb0\xa76p=\xad\xd8:?'\xc9\xa7\xd1,[\x12\xabJ\xb5y\x9a 9\x8d\x82\xc3T=\x98K\xaf\xceQ\xc5x}9I\xbd\x94|\x7f\x99]\x06a24l\xdadM|\xd33\xfa\xf1\xb0\xcdd\x08\x99Y\xc8O\xc8\x92\xf8i\x14'C0\x04c\xd2\xbf\xcbR/\x19\xbb\x068\xb6Y\xe6\x13Zs\"\xa6\xc2\xdc\x8f\xbc\xaf\xd1F}\xf5\xf4}U\xf1\xf0;\xfa_\xefU\xf9mn\x87\xf6~\xffX\x89\x90\xcd\xed\x0c:\xbb\x84o\xd3'{J\xa0e\xfeh\x7f\xaf_}\xe4\xe5\x8f\x06J\x90i\xd1\x87\xbd]\xc79\xf9N\xfeL\xe0\x0e\xf8z\xc5O\xca\x98C\x81\x9f\x05s8\xa9\xa0)\xe3\x06_U6\xa7|+G\xa3\x10\x93b\xe6\x05!=\xb65\x1c\xac\x0bC\x1d\xa7eEF$\x93\x19\xbc\xd8(i\xd9\x8fC\x9d\x84\xb9\xd1\xbdB\x99\x07\x1e\xb4X'a\xb1\x1c\x97\xd5 \x93\xdfQ\xbf\xd1q/\x95[B\x97$\xfd$\xf2\xbd\xe5s\xdc\x04\x9b\xc5\xfa\xb3{\x18\x8c\xd8\x8b\x13\xf2\xd3\xde\x8a\xbf\xea\xd8\xb1\x18\xfcv^\x0erC2]|\xdc\xe9t&a\x16/\x87`-\xd2t\x9d\x0cwv\xd6$M\xd2(&\xdd\xe4\x9dwyI\xe2n\x10\xed\\\x0dv\xc4\xaf/\x92(\xb4&\xe1,Z\x9d\x07\xb3!X\x7f\x85?\xe8d\x815 \xd11\xddK\xa3\xf8\x07\xa5:\xa3p\x19\x84\xe5\x1aEAk\x12F^\x96.\x06\x9f\x91Y\x10\x13?-\xde\x1c\xee\xec,\xe9\xbc-\xa2$\x1d\xee\x0ez\xbd\x1dV\xb2\x13\xf3\xa2\xddE\xbaZZ\x93\xf0\xb1v\xd0\x1bQp\xc9\xb5c\xd07hR\xe3\x87\xa9^\x7f\xdc\xdb\xdf\xebi\xb7od\xc4\xdcZ\xf4Q\xbcH\x85\xb5\x120\xfe\xa6\x88\x15=#\xeb\x98\xf8^Jf\xe0\x853\xc9\x91&K\xc8\xac\xdb\xe0C\x03\xf2\xfct\xa9\x98\x87#\xe9\xc9IK\xbbg\xfe\x82\xac\x98uu\xf7\xa8\xf4\xe4\xe3g/?9{\xf6\xf1\x8b\xf3\xb3\xe7\x7f\xed\xc5\xa7\xcf\xb8\xc1vP*\xf3\x93g\xaf_\xc9\xcf\x07\xbd\xdd\xd2\xf3\xe7\xaf?{Q~^~\xff\xa3\x17\x1f?\xfb\xc1'o\xce\xab\xed\xec\xefj\x8b}\xfc\x83O>\x91\x8b\x1d\x95\x8b-#o\x86\xa1\x02\xe8\x97\xea\x83g\xf4P\xc1\x9f=c\x17\xce\xc4\xe3\xc4\x9b\x93O\xc4\xbb\xe2\x87\xae\x80\xa8C\xfa-\x17\x9be\xab5\xc6\x0c\xa4_\xaa\xef\x7f$\x1e\x8a\x1fr\x81\x9f~\xf6\xe9'/\xae}\x82!\xe89\x1e\x96\x86\xf6\xe9\xcbW/?}\xf6I\xddZl8\x87\xe6\xe9K|/D\xd5\x81E\xbfY\xa5gH\xe1\xd8C\xfcZ~\xeaG+\xee{\x12\xd9\x16\xffQ.\xe1\xcdf\xcf\xa5\xf0\xe1X\xb0\x0c\xb3\xee!\xdfI\xfe}\xd5\xab\xfcA>\x9b%0\xbfD\xa5h\xa0\xb3|\xeaJ`/\x9f\xaf\x128iVH\x97_\xf0U\x85\xf2\x1cF0(\x83(\x92\xed\x96A\x14u\xf6\xca\xa0\x85Z\xd7L\xad\xebJ\xad\xeb\x86\xb9\xc2]\xf7z\x9d\xc9u\xefhr\xdd\xfb\xde\xe4\xba\xf7|r\xdd{\xd1\x99\\\xf7?\x9e\\\x1f~\xdc\x99\\\x1f\xedM\xae\x8f\x0e:\x93\xeb\xe3\x8f'\xd9\xc7\x1f\x7f\xfc\x02\xff\xffxz;\x9ed\x1f\x1d\xd1\x97\xb3\x8f\xbe\xf7\xf1\xc7S\xfb\xb4E!\xcf\x19\x84\x96pn\xed\xd3\xe1\xf8\xf3r\xb1\xdb\xcf\x9dJ\xb1\x9dr\xb7.y\xb7\x8e\xf6\xcb\x1ez\xe5R+,\xe5N\xc6\x93\xe9\xe4\xab\xc9\xfb\xea\xe3s\xfa\xf8s\xfbt\xd8\xbam\xb5n[c\xaf\xf3\xe5\xa43m\xb7\x9c\x0fv\x82r\xc9\x8b\xa2\xe4\xf8\xf3\xa2>\xc7>\x1d\xfe\xc4\xb8\xd79\xf6:\xf3\xe9W\x83\xf7\xb7\xec\xfb\x97\x93\xce_9\x99\xecLN\x87\xdf}4\x9a\xb4'\x1f\xb8\xe7\x93n\xeb\x7f\x98|\xf8xbO\x1c\xfa\xf6\xd4\xf9\xf0\x83\x9d@\xc7\"\xde\x19YD\x9f_B\xc33\xe3.\xfb.\x11q\xb5\xaakcU\xc7EM\xbb\x83\x0dj:\xdb\xa6&\xec\xdf\xb6}}alao\xaf\xa8\xea\xb8/}\xdf\x95\x9a\x18\x94~\xeco\xd0\xe03\x83yG+\x9e\xee\x1d\xa1\xb9\x02\xa5K~\xd2>\xc5 9{G0\xa4\xc7\xea'\\\xef\xb0;\x80[`\xc9\x9c\xd91\xbb7@}O\x87\x16j\xd3i\x19B\xa7_\xdb\xb1\xd7\xe6\x998\xca\x15]\xd6\xa4g\xb1\x96s\xc8\x7f\x87\x00\xb9\xc8\x05\x85\xf4\xfb\x07\x12(\xc5BU@?_.\n\n\x19H\xae\xe9\nA\xbd\x81\x04\x9a\xb3R{\x12(f\xa5\xfa\x05\xe8\xbf\xa7\x90]\xe95\xd4}\xec\x16/=\xb6\x1e\xc3\x10\xf6\xa4a\xec`\x0f\xe5\x96&\x14r(u\xe7\xff\xf9y,\xb3/A~\x13\xcb\xc8#E\xaa@\xa1G\xbd\n\xf4\x98)\xabk\x17\xe1\x8b\x9a#\xc6\x93\x11\x1c\xec\xef\xef\xee\xc3)W\\a\x96\xe9\xe7\\\xdfd\xa7\x85\x03j\xf9\x01K\xe9\xd9\xa6\xa7\xb5\x0e\xd6p\x00O\x9fB\x9fJX\xfb\x07\xbb\x83^\xf9\xd1#:\xdf\xbb\x8a\x11\x15\xe4\xd3\xd8[\x90\x13\xd3\x0e\xf6\x0f\x1c\x17^j`\x9f\xb2\x84r\x9f\xc2\x13\x18\xec\x1f\x9c\xc0\xa7\xed\xb6\x03o\xc7\x9f\xd23\xd9k\xfbS\x87\xc7\x19\xe8\xb9\xf0\xb2\x00\xea\x88\xd3\x1b\xad\x1e_hb\xc9;\x08P\x01C\xdeQI\xb7;\x0f\x96$\xf4V\x84\xb2\xf6 \\g)\xde\xdb\x8f\x92 \xc5;\x96i\x97\x9e\x1fd\x18t8\xf0,\xf5\xe2\xb2\x9b\xbc\xda\x97\xe7\xda\xbe0Q\x99\xf7\xb3\xf6\xfd\xef\xeb\xdf\xefF\xe1\x0f\xbd8\x0c\xc2Kv\x96\xcc\x7f\xf2\xeb\xea\xe8y\xca\xeb\xd7-\x0e]\x97\xcf\x94\xd3\"\x15\xd9\x86\x8d\x16\x1a\xf1\xbe1d\x0b?\xa2\x8f \xed^\x918\xa1\xc3x\xf4\x88\xcd\x845\xcb\xd6\xcb\xc0\xf7R~3\xf5'h\x93\xc0\x8eT\x98Q\xca\xe5\x91\x0fC)`\x15{\xb3\\\x12<\x9f\x8a\x96 \x90k\xcfO\xf1b*\xc9U\xba\xb4\x9a\\\xe3n\xc7\x8c+R\xa67m;\x93\xae\xf8\xf6\xc1N\x97\\\x13\xdf\x0e\xc7=\x1e\x03\x8d5\x14,\x97\x9dy\x14\xafdw\xffh\x0e\xe9\x82\x80\xda[*\x8b\xa1\xf4\xf82L\xedx\xdc\x9f\xbal\xafDe\xf8@\xc0\xa5\xb8\x8e\xac\xb5,d#\xc1lhX\xbf\x983\xde\xe6,\xf2\xf3A\x15\x13:\x82\x90E-\xef\xfa\x0b\xe2\xbf\xfd$\x08\xc9\xf7b\xe2\xbd\xa5\xe2[Dw\x90h\n\xef\xdc\x0e\x8a\xaf\xdf\xe7\xad&\xd9\x9a\x8a\xb1d\xd6\xd0hiu+*\xb67\xcf\xfe\xeav\xe8\xa2\xe2\xca\xc0\xb0\xdao\x9e\xfd\xd5\x9a\xc5N\xdfE\x85\xfe\xdf\x12\ny\x16\xd1\x0e\xbf\xd1u8\xef\xa6$I\xed\x18\x03@(K\x9bz\x97\xb0\xf0\xc2\xd9\x92\x80=\x0f\xe2$\xcd+t\xc4$\x94\xfa@[\xc9C*\xa4\xde\xe5\xa7\xde\xda\x85\xb8@\x9b\xc7\xe9\x82\xc4\x84\x1ep=X\xc7\xe4*\x88\xb2dy\x033\xe2/\xbd\x98\xcc \xc9\xe6\xf3\xe0\x1a\xa9\xa2\xf5\x18\xda\x10C\x1b\x1e[R7\x1e;.\\\xb0.\x07\xe6.\xafcB\xab\xb1\x13\xe2G\xe1l\x83>\x8b\xce2\xbf\x87r\xe0\xfc\x92\x96Q\xa5=\xaf\xc4\x92\xe2@U)\xa4\xc8\xdf\xaa\xaa\xe9\x08<\xd1\xa3\x02\xbac\xb0\xd8;\x94\xd8\xf2+\x1e\x888\xb4\x19\xa5<\x08V\x120sz$E\xf5f\xf9\x08\"\xfa\xa7=\x82\xbe\xc3e\x06t\x0e\xf0\xaa\xb6\x15&\xfb=\x19AF\xd7,C\xb9\xa7\xdf\xdf\xeb\xf7\xfb\xc5d\x93\xeb5\xbb\x83\xcf\xa2\x1c\xfc\xe4\xd9\xebW@\xab\xf1\xfc\x94(\xb90A\xdc4\xbca\xab\xe6I4\x84.E\x92\xc6\xc4[\xa1\xc3\x81\x17\x84 \x84Q\xd8Y\xc7A\xc8\xb6z^m\xa2\xab7\xed\xc6$\xc9\x96\x98/\xd53\xad\x99f\xc9>)\x96Lqo\xb9\xe2 \x04\xd0-\xac\xe2,\x833\x1cw\x83\x84\xa7\xdb\x0f%\x0c\xe4\x1a\x9a\x15\x89/ \xac\xbc\xf5:\x08/\x93\x13\xc4\xb6u\x1c]\x053\x8a\xddQ\x16\xfb\x84\xe7o\xa6\x9b@&k\x96\x93\x87\xd8\xa4\x87E[\xf2*xKn\x12;t\x9c|A=x\x02>\xfd\xc3\x164\xc3\x80\x8f\xde\xd4\x95\xe2\x9ce\xd87\x9b\xb0\x90\x94!\xfa\xdb\x04\xecG\xabW\xcfM?\x920Z\xce?\xac\x9b*\xdf\x85\xb9\x8a\xd7Aa\x08\x0cd.\xc3S\xf2\x08#\x91\x95z\x97\xc3\x1bo\xb5\xecF\xf1\xa5;\xe8\xf5\x06C\x9c?\xe6q\xabAsZ7\xbb\xeb\x18$L(2E>\xc0\xa5\xe2\xae0\xf4\xa0\x1d\xe5s\xe7\xc3\x13\x98\xd3?l\xee\x04.Dc\x1fS\x90\x1b\xb07/\xa6\x96\xc1\xe7)\xea]\xe9\x94'y\x8cb\x9e\xde\xa9X\x13\x06\xb0\x99\\\x04t\x8f\xdd\xde\xeaD\xa7\x11x\xecI!`\x95\xe5\x022\x13(\x06o\xc9\x0d&\xe0#\xe3`\xcaB$\xe5\x97~\x83\xe6D>\xea\xe2\x7f\xb9\xd1Y\x8a\x1f2p)\x05\x8d\x92(I\xd1s\x87\xdd\xe8\x12?\xdbmz\xac\xd8\xe5\xc8p\n\xb6\xfc\xc8\xcd\x8f\x9a\xb552Y\xaex\x8d\xca\xe8lz<\xc0\x89\xbd\xa0,\x9en/A\xa8\x18\x85\xc7gmt3\x92$S\x1c\x80\xa8\xacvf>6\xf1\xee\\\x86\x97s\x0e\xd5\x0e\xe1\x84;\x10\x04\xda\xb8\xac\xdc+\xeb\xda\x0e\x1c\x1e}TS[\xbb-\xd7\xa7\xdd)\xb8\xdbv\xd9\xd1\xca\xe0!7\x8bj\x0c~\x9b\xb4\xac}\xf9=\xbc[\x04Td\xe8\xf7\nA\xae\xbf[|\xe7`C\xbf[\xef\x90\x15\xe12\xaa%pv\xbeD\x07\x83\xe6\x89v!\xa6x\xc5\xd6\xfbe8\xa3R*\x9e\x9f\xf8A\x96.\x80\xfc\x90\x16\xdez\xd8\xefu\xbb\x8c\x87\xb0\x0d\x8b\xe1\xc6\x0cq\xa5\x9e\xcd\x0c\x99\x06\x8f{\xc16\x08\xe3\xbe?\xc5\x89\xfb\xd2\x85V\x1f\xbd\xe3\\\xd1\x94@\x0e\xa7\xdc\xbfM\x1aw\x0bf\x8f\xb4 g\xf7|HO\xb9\x83\x10\x9f`\x87\xf3\xb1\x0bo&\x13\x01zj\xf1 !?\x9b\x91\xd0'@\xc24\xbe1\x8a\xd9\xcc\xc7\xacDd\x88\x96\x96\n\x12\xd0\xf28\x8e\xd0\x83\x13Kd$p\x07\xc5\x89\xb4\xfb6\x08g0\x02K\xf4\xc0r\x8b\xcd\x841\xc6\x9a\x04\xca\x9f6\xd3\xa8\\\xc4D\x8c\xd6\xef\x80*\xa6\xd3!\xee\xee\x16\x11\xc2\x1b\x04\x90\xdc\x7fBW\x8f\xb4a\xe8\xf8M\x1a\x18\x8f\x1f+\x99i\x87R\xe5\x03.\x01m\xc2-0\x12m\xc41~\xb3\x17\x86\xb0\xcb\xa4\xa4@D\xb1\xc58\\t\x19Z-k\xf3Z\xd8\x1b\x16\x0b6 \x0b\x94\x91N\xf20\x8a\x03\x9b4\xa7\xbc\x98\x8b\x01\x92\x14p00\xb2~\x89r<\xc9\xb3\xf8\xd1\xd1\xc7\xba\x83pi\x97m\xd2\xbdBL\xcc\xc2\xfc\x04K\xc2\x99\xd0 \xf0\x83\xe8\xbb ]\x04!xpE\xe2\x0b/\x0dVt\xe5\xab\n\x1eS\xa8#.\xb9I\xe3m\x9d1)._M\x96D\xe0T\x9c\x80\xbdK\xa1\xf3\xe0\x07H~\x10\x06r\xed/\xbd\x15C\xc0\x95\x17\xbfM\xac<\x0eqe.X\x16\x85\n\xdd\xcd\x15;\xf2\x195\xf4*:\x9dJ\x9bI\xe6/JGn\xe6\xa5I1\xaf\x8c>\x8c\xb4o6\xef\xeaB7\xaf\xe7*WJ\x15\xba\x02\xe3L\xcd\x97\xd1;J.\xe9v\x8d\xe2R\xff\xcb\xab\xa6#\x7f\xc8\xc8Z\x17\xfa\xf60\x99u\xfd\x1c\x0d\xd1m#F]\xe6)\x08\"\x1a\xc3PU\x83\x85\x8eT\"W8\x85STs\x0d\xe9.\xe5\\\xa2(Ea\xe2\xa9\xee\xb1z~\x16\xe5\x99\xb6-\x0bs\xcd\x9a\xb4\xea\xa8Y\x0bQ\xb3\xf6\x18=\xc1k\x89\xf7\x0f\xcd\xc4[C\x96\x8f\x18Y\x0e\xefA\x96\xcd\x82\x8c\x9e4\x87\xc0K\xc8\xe4\xd9\xd0\x81\x12fV\xb1Zl\xdc\x90o\\v\xd4l\xbd\xb0C\x07\x93\xc76\xd7\xa8\xe5\xb0\xd2\xb6\xc9u \xc5~,\x0f!\x8cf\x04VYR\xe0\x9b\x97\xc2\x92xI\x8a\xaa{I\xcbVb\xd3\xf5\xbb\xa9a\x81\x7fJ\xd2\x86i\xf8\xc2U~I\xf2\xc6\x85K\x17V.\x9c\xbbp\xe1\xc2kf\x8c\xd20\xed7\x06f\xfe}\x033\x97\x16{\x19$) I~Vb\xbfl+Zc\xd4\xd9T\xe8j\xa1\x88\x1e\x9d\xcf\x82\x00pyE\xfc\xcc%\x15\x06@\xb5'\x8c\xd0\x19b]\xc8eLA\x85A\xeb\x1f=R\x04Q\xfbM.\xaf\x96\xc578e\x93\x00\xc3\xca!\x93\x9f:\xd0\\W}\xf8\x84+\xc2>E\x97x\x07\x0d\x1e\xf4\x85O\x0d\xde\x9a'L\x82\xba\xbd\xc5\xcdx\xe2\x94\xbbwZ\xf4\xee\x86\xc9c\xdfJ'a\x88\xd5\xeb\xd6\x8f\x07j\x80\x11\xbc\xa1\x9d\x8cr\x0b\xce\xa7\xf4\xc1\x9ao*z\xea\xbb\x80\x11\xf8\xc5\xa4\xcfs\x92F\xf0<\xd6\xa6\x9c\xecu\x99\xd5\x94\xec\x88\xf9L\xc1)\xbf:\x8eg\xaf\xd789\xdb\xd8X\xdcB\xc9\x9b\x98Og\xc0=w\xcc'4\xe0^;_\xd5\x8475=\xcb\x91T\xfb\xf4\xaa\xf6\xe9M\xed\xd3K\xc3\x06\x04\xeeG\xa3\x0b\"|\x87\xf3\xe3\x92\xab\xac7;?z\xc6$D\x18\x84\xa8\xa9\x1e.\xd6D\xd2\xa1-\xab\xc8\xb4\x07\xecP\x80\x07\x9a\xfd#\xfe\xfd\xf6\x96\xd2\xf2\xb8\xf9\n%\xd2\xc1\xd0\xc5[\xaf\xec\x08h\xd4A\xc9\xefI\x07<\xadL-\x7fX\xaa\xdf\xa6\x91:'pm{t\x9f\x1b\x8a6\xc8W\xf2\x87\xf6p\x9f\xf9[x\x0e\x9c\x99\x1a\xafH\xca\xb9\xc4\xe8Q\x11\xfe\xffc\xee[\xbb\xdb\xb6\x95E\xbf\xf7W\x8cx{\x1c2\x92\x15I~$Qlk\xa5i\xd2z7ur\x9a\xa4\xfbt\xcbj\x16-A6\x1b\x89T\xf9\x88\xed\xbd\xdd\xf3\xed\xfe\xb1\xfb\xcb\xee\xc2\x0c\x00\x82$@\xd2N\xd2\xd6k\xb5\xa1@\x10\xcf\xc1`\xde\x93\xb2d\xe3\xcf\xb5\xdbG\x97\xad\x82\xbf\xe4%\x9c\x82\xfe\xc0\xae\xb7\xd1w\x02\x12\xb6\xf1c\xa4\xc6\x149}\xb6\x8a\xe6\x1f\xa4\xd4\x9a__\xc8l\xb9\xa8kX\xf5\xf2\xa88Z\xc4\x9b\x8f\x02K\x8b\xa2\xb5@r\x02\xb8\x91\xf8\xe4\xff.\xd4\xf9\xc5/$\xc2\xaf_\x97\x86\x9c\xcc\xf2\x0f\x01c\xad\xb9g\xd1\xd5\x93\x14\xee\x9d9\x07\x96\xfa\xee\xf8\x9f\xd2\x13aD\xd8\x98\xf9\x0b~\xf1\x07kN\xcd\x04\xa9\x12\xe8o\xfc ~\x02>\xcc\xa3U\x14\xf2\x95^\x07IR \x9bW\xfe3\xbbKC\x1d\xb3\xa2\xff}\xaey\x9a\xe6X\xdcz\x12_\xf0 \xae\xb3U\x1a\xe0\xd9\xf9\xc0\xaea\xed_\x830q\xd6W\x05\xd5\x1b\xf6\xb9\x19\xdf\x88\x19\xef\x13\xcb\xe5\xf3\x0b\xf2\xd3\x80Mp\xed\xe42yN\xedi08\xc8Y\xcb \x9cG\xeb\x0d\xea_\xd8\x95ec\xf9l\x91\xceS{\xfb\x04\xa2\x18\x96\xd1j\x15]\xb2\x05\x9c]\x83\x8fj\xd0\xd4?\xcbV\xa8\xeca\xebMz\x8d\xca\x0d\"\xfcr\x9c\xa8\xbc\xa6c\xf3\xc6P(\x11\x0dEYeP\xae\xa4\x037DZ\x04T\xca\xa7\xab\x1f+A\x06hB\xb1s\xbc\xd9+k{-b\xd9\x1b\x97\xb7(Hk\xc6\x88\x9e\x81\xa8Qr3\xbfVnV\x80;\x9b\x17c\x93\xe8\xac\xf2Q\x15\xf2\xc4\xd1AH\xb3\x01\xda\xba j\xab\x9c\xae\\\xd4&\xf1d\x81~\xc5\x16\n\xfd\xfe\x81\xc4O\x0f\xce\xbc*\x01d\xa3~\xcaZ]\xccY\xb3\xd4\x93\x88u,\xf9\xc6\x17\xf5\x84\xd2\xc7FB\xe9\xda\xe0\xad\x04\x02H\x859\xa8\xbbi\x86\x05\xd2\x89=\xde\xe9 98IbM\xe9\xc9k0\x1f\xefs8\"\x82ac\xe5EUmN>\x8f\xf6D\x8f\x03\xea\xf1?M\xfeip7\xb2*\xf6(\xc3T\xd3=- \xabM-a\xa5\x8e\x1a\xf3z\xad\x96W\xe8\x0b\xab\xec+i\xd2\x08v\x17\x05\xd8\xfd\xa8\xc1.\xc7\xb7\n~al\x13\x1b\xc7\xf6\xcb\xe4\"\xa7?\x08?\xc2>9\xc5\x9f\x04\xe1\xf9\x8a\xc1\xefY\xc4\xab\x8a\xbdGZ\xa2n\x96\x86\x83t\x1b6\xc3\xdc\xe9\xe78):\x83a95\xbb\x04\x1e-\xc4t\x9f\xff\xd4`\xe2m\xf3\xa9i1\x9eZ\xc9\x88\xf0]\xf5\xd5\xa0\x8d\x18m\xe0\x95\x87d\x03|\x14c\x8dd\x9b-\xce\xa2\xa9\xab\xcbv*\x1aO\x87~\xfb9TrM\x9f\xfcE9\xd0\x7f\x98\xfa3\xafp\xc1\x1c\xa3\xef\x88>\xc9\x16-Rp\xd1\x910\x83\xe3\x1c\x8b\xcf\xcf\xd2\x08]\x89\x1f*Vf\x17\xc6\xf0hO\xfd\xe4l\xc3\xc0\x83#\xfe\xbf\x16\xba\xb2\x80\x14\xda\x11\x19m\x07\xfc\xbb'\x10lo{\xd8\xfb\xd3\xb6k\xc5\x99\x14\x0c\x1b\x87~5\x07\x07\xb0\xebA\x172\xc5R\xa9\x13x\xc1\xae\xfc\x05\x9b\x07k\x7fU\xef\xd2\xa4\xff\xe9K\xf9\x9b\x1b\x95\xe0\xc5N\xb7\xd0ZJ,\xf0!\x8c.C\x10\x11\xd3\x94\xcc\xac\xa6\xeb\xea\xc9\xa8\xc7\xa4~\x8eI\xe9\xe8\xdb0i\xb5\xe1/\x84I\x17Qv\xd6\x06\x93\x96\x06\xd3\x82\x96\xb8\x0dj5\x8f\xc2\x88Z51NGC\xb26\x0c+\x0c\\\xcdXu\x97d\x18\xcd\x8a\xef6X\xd5\xd2H+s'2\x81{#\xac\xdf:\xcf\xdd\x98\xa3\xcd6-V\x07s+\x93\xa7U\xe0'\xb7\xb2x2\x18?\xf6\x8a\xa6N\x9aH\xbd\x14\x8eE7\x84\xbc\x97\x85J\x0c\xb0\x10\xe3(\x19\xc5iw\x92.\xa6\x0fge\xddU\x95\\\xe5`rWS\x14\x94\xba.\xa5\xbc\x95\xdf\x94v\xe1\x9c]\xd1\xcd\xc1\xeb\x8d\xbbl\x06,\xbe\"\xcf\xdd%\xb9}\x12\x92F\xa6w\xe7Q\xfe\xbc;\xd2\xcaw\xf2g)\xe8\xc3\x1f\xfbz\xa5\xc7\xda\xb3Vg\xe7\xa1V_+\x7fL\xa1\x1e\x96\xb5P\x8e7\xce\xbe\xd6\xbd\x10\x9b-IF\xff\xa6\xf9\x18 \xee\xec\xe6\x86\xec\xfb8\x98\xb78X\xcd\xe4J\x80\xbe\xe4ErWX\xad\x8b\x03\xb6\xac\xa5B\x84u\xc6\xb2\x89b\xb8\xe3\x14k\x98g-\x8f\xef\xce^\xdbA\xd4\x0f\x00}eZ\xf4\xd9$\x95h\xbcj\xf29.\x9b\xa5\x8f\xbc\xcdK\xac\xd8l\x05\xe1+1\x8bT\xd3h\xc6gsU@\"\x13\xed\xe6DdP\x14\xdc\x1c\xda\xb3t\xe9\x7f\x99\xc6\xbf\xdfYZ%\xfej\xe3\xb6\xcb?\xbb\xc0\x04\x8af\xf8\xc2\xff\x83\x8c\x078~\xd2wB\xe8\xaf\x0b27Kr\x01\xf9w\x179\x8e\xb9\x14\x15`D\xcb\x10\xfe\xec\x0c%-#\xc6\xbb\x0d\xbeWw8\xbd\x1e\\ \xcc\xe7\x16k\x08C3\xcbv4\xb8<\xd8n\xc4\xf2P;\x1d\x85F\xc8%X\xa0\x99\xa2\xc5\xea\xa6*Q!R\xa4'\xad( \xfd\xbd\x16 \x94\x07\xd0\x96\xde,\xca\xd8\xc0\x998(\x9b\xaa\xa9\xab\x95\x08\xcdnn\x07\x96\xdf\xd5\xc9E\x94\xad\x16h\xabs\xe1\x7fd\xe0\x87\xd7\xd2\xf2\x1a\x95\xb0\xd2\xdf\xbb\xb5\xba[\xe9\x15s\xd1\xd9\x8fjVh\xe4)l\xe1h\xf5\x91\xb9\xda\xd4\xeb\xf1\x84\x06\x13\xef\xfbs\x19;OwM\x93\xfb\xfc\x9e4\xccw\xdc\x82\xcf{~\x05\xb2\xcf=!\xae7\x8c\xbaFh\xbf\xb9\x01g\xe9\xafVg\xfe\xfc\x833\xeb\xc9\xed\x99\x80X\xb7\xda\xeaS\xac=+\xccT\xac\xd1\xd6\x16\xbc\xa7O\xa8\x18\x1f\xcd\xa1d\x10\xa2\xf1=\xdf\xfe\xce\x01\xc6\xe0\xc4\x95\xec\xc2\xbd#H\xfds\xd4< \x98?\x13\xbe\x13\xa2uN+\xf6\xf0 `i\x9a\x97\xdeC\xff\x9b\xca.\x93\xc3{\xd3N\xdeq\xebr#4\xa1'\x13\xdd\xa31\xd9\x82!\xbfS\x9a\xa1s\x94+\xe1\xd0\xcbI\xf7\x91\"~\x94W,\x7fdI(\xd5\xc2\x8a\x7f\xbe\x8a\x12&\xcc\xf8K'\x99_\xe8\x95\x89\xdf\xdc\xc0\xeb\xafr\xf8R\x8f\xcaw\xe1\x87v\x9e\x85\x1a\xfa\xaf\x00\xa9\xc9\xc3P\x90~Z\x18!\xe1KP\x0d#\x94\xf6W\xec\xdc\x9f_\xf7\x94K\x8f\xc8l\xa6m\x18\x99=I\xb1U\x0b\x97E\xdc\xf1\"\x9f\xd1\xfcU\x0f:nIs4\x10tw\x07-z\xcc\xd20\x9ck\x06\xed\x9d\x13m|d\xc1\xdf\xadMC5\xbc\xect\xd63\xfa\xba\x15\xd8=\x19\x0f\x05\x0e\xc8\x8d[\xb8\x07\xa9xH\xc8k\"kiR\x1b\xeb\xe6\xcc!PKNCd\x06\xf8L\xd1\x19\xa0\xa8\xa1\xad\xcd\xb1\xd4\xa8\xa3m3\x04;\xd26\xf8hR\xfc\x05\xfbUPC\xdd[gZ\x1b\xd2\x01\xe4\xb2~1\xc0\xe2\x7f\xb1t\xe7\xae\x81\xa8\x16\x04\x9d6&\xd2;\x8b\xeb\xed'\xe1\xe1\xf7\xd34\x9cI\x19\x1b\xc7\xa7\xaf\x85\xc4\x81\xf0\xa9\x12\x82\xe5`Z\x90<|e\xef\xbc\x88\x0f\x06\x1ak$\xce{\xee\x9e_\x8f(\xdaV\xa4x\x0e\xed+\x8f\xbcbD\x17\x11\xe1A\x1f7_\x90\xccpV\x13\x14\xd0\xad\xfd\xb8\x12\xb7\xe5\xe7\x9c\xa6\x17\xd3D;\x8d\x8df\x9cV\\\x98*\x92\xde\xda\x82sr\xf0,\xee}T\xdc{P\xa18\xc2(\xdc~\xfa\xe6\xd9\xf1\xb1\x16O&\x01?f\x10\x84)\x8b71C\xc7\x87\x04\xd9-\x15tNnmR \x1b\xd0\x82\x9f\x9d\xc0\xee~\xf3\"{\x82\x14hXa\xad\x82\xe6I\xbd\xadc\xc9\xaa<4\x8aQ\x16*\xc03\xf7\xe0(\xecG\xede\xfc\x9dk\x8c\xc2XL\n\xc3d\x86(~G\x0e$\xbd\xa0\xe2\xda\xc9\x901\xa5\x05\xc8\xa7\x80K b\xc9\xd4Wrs\xf3\x82\x1e\xec\xef\x8d\x1e\x8aX\xa9\xfaG\x03Y\x93\x97\x8b<\xfa^\x19\xf7Q\xb2\x04\n\xc5\xd9\xa8YK/\x82\x84\xb6\x100\xfd\x01\xfe\x96\xd131!\x92\xfa!H\x1eQ'\x91\xf1\xd8\x99|\xbc\xb9A\x9e\x9b\xbf\xcc\x03Y\x1eb\xda*\xf9\xab\xd8\x04Q\"XE<\xde\xdc\x90\xd5\x02\x7f\x8b\x01\xaa\xf8;\x19\xa9J\xbdQ\xe4\x1a~)\x7f\x14\xdb.01|j\xf9\x981\nx\xb0b\x8bcQG|\"\xe8wK\xe5\xb7\xf4V\x0d\x1d\xf7.\x07\x06Q\xae\xc9\"\x06j\xb4(\x8e\xd0\x7fJ\x89\x84^\xa6\x1b\x02a\xa1:\x9fH_\x14\x11-m\xa7\x81\x08\x0c\xc5^\"$\x0d\x1c\x158(\xac\x1e\xd3P\xbb\x80<\x08\xf5A\x90\x9bFX8\xb7&\x92\xf3\x89^\xe7 \x0f\xf8\xb8\x0d\xc3'\x1e\xfc\xe0Z<\x8c\xc3|n\xb5\x07\xf4k\x9b8Z\x13E\xc3!\x9d\xe3rW\xc8G\xcb\x96\x1c\xcc-B\xf9\x88\xf3\xfc$\x91aFZH\xac<\x04[\x0c\x07\x10\xf0\x7f(\x04\x1bs\xa3i<\xab\xc7-\xdf\x1b\x0f\x9c<\x99\xdf\x99\xf6/XJ\xaa&T\xc9\xaf\xaa\xe7\x95\xd7\x1a\x8a-\x95\xb5\xe4\xb2N\x07\x06\x9f\x82<\x81C\xe0\xe6\x8aC\xa5\xa1W\x184\x085\xec\xda\x83\xb3,\x85e\x94\xf1[.\x8a\xd9\xad\x128\xe4I\x0c\xbe\xeeU\x93\x1e|\xdf\xb3\xe6+h\xd2B\xb4\xd8S\x04\x99\xb8\xcf\xaeR\x16.\xdc\xea\xf2\xd1\xa1\x1eCV\x9c\x0f\xef\xac\xb4\x1d\x12\xf8\xee\xd8\xd8W\xdaOc\x02\x87Z\xcc,f\xf3\xfd]gS\x8d\x0f\xfc\xe9\xe9\nL\xc1D\x03\xb7\x10z\xb1r\x97r<&.\x12\x89e\xcf\xb2\xe5\x92Pw\x15e\x86E\x94\x19\x8b\x9f\xf3h\x95\xad\xc3B\xa0\xd3\x1c\xee\x02-\xa3\xc19K\xdf\x84\xc1f\xc3\xd2\xa6\x05\xae\x98\xabW\xcfbG\x1b\xae\xa7\x0b\x0dL\xbc7\x88\x00\xf0\xbb\x1a\xc5\xf0pOD\xc0\x91\xf1o\xf4\xd9\n\xeb\x00~\x9do\xd3yvN\x07\xa7\xf1i\xf8\xff\xfe\xaf\x9eU\xc0\xe9\x07\xe1\x82]\xbdZ\xba\xdah\x10\x8b?M\xdd\x80\xf4\x17\x96\x90U\x01lS\xf0\xc0\xc2\"oc\xbf\x0c\x1e\xc0\x88(\x0f3\xb3\x86\xe3\x86~\xbf\x0f8\xf8\xee!\xec\x99\xb9\x946\xeef\xb8Dz\x1e\xbd\xd2Jd\x9c\xec\xd3\xa6\x97\x93Ww^\x9a\xcc\xba,n&\xd0\xf8vieZ\xacJ\xa4\xafJ\xc6\xd7\xf7\x13VE@\x94/\xd7CL\x80\xa8\xba\x80\\\x11sSJ@1\x94\xe0\xbc|4\x00\xefR\xc0\xfcn\xb9\x16t\x0d{\xde\xd5\xee\x8b.8\xbf::\x82\xd2\xcf\x90L\x19\xd86\x1b\xb5\xe3\x18\xef\xf8\xfc\xe8s\x82\x15)\x88{A($\x8f\xea\x1dFK\xbe\x87\xaarN\xb1\xf8)q0\x0e\xc6\xa3W\x98\x00\xf9\xba.\x9f\x9b\xc0\x04\xf9{Q@*\x10\xd2M0\xb9\xa096p\x85\x88\x8az\x19\xd3\xaa1\xde\xad\x11M+L\xf3\x89Hs\xa0])z\xe3\xfc2\x8e]C4\x9c$\x8d+\xd9\xfd>\x04\xe1b\x9c\xabs\x0b\xef\x94\xf7\xd7lu\xdb\xc6\xcd#\xaf\xdb\x17\x91\xe7\xf1Mz\xbdbcp\xd4z9\x7f\xf5q?\x8b\xa2?\xf5\xb8\x1bL\xa7Z\x1f\xf7\xc2\xb1N\xe3\x8c\xe9\xc7\xf8m\xf9\xf7O\xef\x9e\xcbc\xcd\x0b\xf6\xf4\x8f\x97\xfe*)\xd4~Q)x\xfa\xf2\xcd\xf3\xbb\xa2\x85\xbas|\x9b\x81\x7fN\xfc\xe1LE&\x81o\xa2h\xc5\xfcpF}T\xf2\xd2I\nT\xa8\xe1k\xe7^\x8bmL8\xc1\x9a\x82\\\xd2\xad0\x91\x0b4\x06\xb1KmN\xb1 E\xb4\xea\x8b\x16{,\xf7\xbbM_&\x8c\xd1\xae/9\xaf\x17\x96y\xfd\x1d\x10\x88%3\xe2m\xb3\x9aV\xf2\xa6\xed\xe5\xe344\x94\xb5o\xe8\xa1\xd6\x90|*c\xba\xc0\x84\xe9\x820\xfd; :\x12\xd7\xe8\xb2k#\xe0\x04v\x87zS\xc3\xca\"\x17\xee\xe4FU\xe8\x1a_\xe7\xbfD3\xeed\\\xbc\xc7\xf3\x1e\xa8\xf2\xe9i\xdf\x9d\x8c\x83pys\xcc\xff;y\xe1\xddPQ\xe8\x877'\xfe\xc9\xcd\xc9\xd3\x13\xcf\xfbZ7\xb9\xc7\x80\xfc\x98\xadW\xeb\x9c=\xb0K \x8d\xbc\xf3r\x15\xf9_\x84{\xd6\x85\xdb\xa4\x15\xe1\x88\xd6\xedD\x82\x80\xf1t\xda'\x9d\xeaf{\xb3\xcfN\xd2\x18#\xc1\xc8\x11\xc2!H2BX\x1eW\xa8\x91~\x1a\xbd\x8c.\xe5\x89\xe6\xa4\x04L\xf8=>\x06\x11\xfcw:\xeb\x81\xd3\xdd\xceu\xe7\x0c\xe9\x95#q\xc1\xb8d\xf2\xa7h\x91\x1e\xf0\x9a\xcb\x9c\xf4\x10\xa6G0\x11wY\xff\xf5\xab7\xc7o\x8f\x7f~\xfe\xfe\xf8\xe4\xc5\xf1\xc9\xf1\xdb_`,_\x9d<\xff\xeei\xf9\x95\xd3\x0f\xfd0o\xee\xc4?\x811\xb0\"\x85!0\x9b\xcb\xeeFf\x04E2\xe3\x05\x07\x9cZBCX\xe7\xc5Dh\x04\xb7\xe8\x8aIB#\xe6\x9f\xdb \x8d\x10\xees\xb2y\x8c\x0f\xda\xa8\xd8\xdf\x89\xd4p\x89\xd6\xe8\x1c\x92\x1b\x86\x81\xd4hKk\x14\xf0\xa4\x0d\xe2C\xb3l(HN\xfc\x13\xde\x17$\x97A:\xbf\x00\xd7*;\x98\xfb \xd3\xe5\x90cc-\xd0\x16\x07\x81\xcf\xcc\x1dQcJ\x8a\xdb\xa6\xb1\x93\xa7'\xb5\x8d)1m\xab\xc6\xfc\x13\x83<6\xf7x\xb6\x1e7!\xf4\xfb\x12\xab\xc5O\xfeg[\xad\xe3\x93\x17\x9fo\xb5\x8e\xc3e\x9b\xd5\xaab\xa0/\xb7Z\xdb\x9fu\xb9\xb6?\xebzm7.\x98\xe9\xb4\xe7\x9f\x0f\xfa\x03\xc3X\xb4{\xa9H\xf6\xf6 S\xc9\xbc&\x10\xaak\xcaa\x0e\xbfP(\x02fX\x87L\xfe,]C\x99\xfc\n*\xe4\x97\xa2\x8e\xb4\xffy\xdb\xae\xed\xc7\xd7N#A\xd7\xd8\xe2\xa4\xf4\x8b\x93no\xd3\xd9\xcd\x14NO\xd3Y\xd7+\xbc\x1c\xeb\xbd\x17~\x10}H%\xf7=\"\x10\xb1\x85\xfb\xee\xbfn\\N\x8by\xe5n\n\xdf{\x13\xcf\x9b\x14(\xb9V\xea\xdc4X\xb3$\xf5\xd7V+\x96\xcfN\xac\xe5\xe1\xca\x83>\xbbbsA\xb3\xa9\xd2H\x96~\x01r\xcd\x10\x07\xc5\xa23\xd9\x08\xb7L\xf3\xb5\xa7\xf47H\x81\xa9yx\x8a(\xcb'\xa1\xe7'\xf74\xf3\xee\xe7q\x1c\xc5\xae\xf3\xad\x9f2\xe5K\xcbx\x99)(S \xf2\x89v\xd9t8#\xda\xa7\xcb\xa6\xa3\x19y+e\xf4sg\xd6\x83\x0e\x9b\xee\xcer\xf3Wv \xbc\x03\x97\xff\xaf\xff\xee\xed3W,\x83\xc9\xff.\x10\xe1)\xba\xbc \x8aN\xd1e\xd3\xbd\x19\xc5\xa5\xe8\xb2\xe9\xfe\xac\x07l\xfapfC\xc2(p\xc5\x80\xb7\xd3\x873A\x94\x0ez\xb0\xe3=\x81U\xeeK\xb9\xf3\xc4\x83\x15\x1a\xf6\x99\x90\x14\x88\xa8\xd1\xddU\x15\xfd\xd9\xc0\x8bM\x1f\xcfp\xe1\xf9\x9e\xed\xb3]\xb8\x0f\xee\xfe\x00\xee\xe3j\x0df\xd0\x85\xae\xcb\xa6\xc3\xe1\x8c\x83\xd9@\x8a\x00qC\xf4/\xb77\x9e\x88\xcb`]6\x0dzV\x1eFS\xdf\xda\x82e?a\xe9\xdb`\xcd\xdce\xff\\\x93?\n\x0d\xda\xa5\x0b\xce\xd3o\x9e}\xfb\xfc\xc5w\xdf\x1f\xff\xe3\x87\x97?\x9e\xbcz\xfd\xdf?\xbdy\xfb\xee\xe7\x7f\xfe\xcf/\xff\xf2\xcf\xe6\x0b\xb6<\xbf\x08~\xfb\xb0Z\x87\xd1\xe6\xf78I\xb3\x8f\x97W\xd7\xff\x1e\x0cG;\xbb{\xfb\x0f\x1f=\xee>8<\x0dOc\xe7\x96\xec; x\xbe\xc4\x86\xddY\xfbm\xc1\xd3A\xa3b\x9cc\xc7\xc8\xa2\x1e\n)\xf2_H\x1eCa\x9d\x8e\xa8\xe3\"b\xcfr3vi\xbcN1\x00a\x7f\xb7Qk\xc4\xe0\x00\x06\xad4?(\x13\xdf7\xbe\xb6\xe2\xc1\x18\xfe\x0b\x1e\xa1\xf0\xb9\x08\xf6\x9f|q\x06E\xe9\xc5\xf44>\x0d\x0fgB\x86a_\xf4\xa0v[|\x8c\xffc|\x95\xd8\xb7{n\xd1\x07)\xff\xee\xc1\x13\xe0\xab\x9c=\x01\xd6\xedz\xc0\xe0\xbf\xd0\n\x8c\xe4%\xa4\xce\x99\x8b\xfc\x10pt\x04\xc3}\xd8\x82\xd1\xde\x9e\xd7\x03\xbd\xf8Q\xb9t\xb4\xb7\x07[\x90p\xa4\x9f`\x12\x90\x83\x03\xd8\x87\x1b\xf0\x158\x04\x12\x1c\x98\xe9r\x15[4\x00\x19\x087\xc3\x81\xdd\x87}T\xd1|\xd2\x90`\x0c\xc3GJ\xd0Slk`lk$J\xf1S\xe1q\xc8\x97F\xaf\xb3\xab\xbe\x8c1\xe9\xc62\x8e\xd6\xea\xc1\x9d#O\x80\xe8\x1e\x1f\xe7u w[\xa9\x08\x06\xf6\xe0,\x0e!\xd0\xf6Z\x93\xb6\x00\x1d\x93s\x8b\x15\xa1X\x80/k\xc45~\x0d\xae\xb1@\xe7N :\xf1\xe4\xfb\xd3\x00\xb7\x8fo\xfa\xfe\x0eR|Z\xe9\xc8T\xba_*\xdc\xdf\x81-@s\x1c>#7\xe0\x10\xfb\xc8\x83.\xa4SfW\xa8\x16\x01t\x87\xf4\x87\x9fyD0\x86Q\x0e\xae\x85v\x06\xa6vv+\x85\x07\x07P\xeeq\x7f\x17\x1b\x1e\xe6\xc0\\h\xb9:\xc0\x83\x83J\xc3\xfb\xbb\xc5\xf6z\x10\x17\x01O\xfd\xfad\x02\xc2\xca\xceVd\x7f\xc58\x93U\x02\xc1*,\xbc%\x89\x16\xd5x2X\x9c9>\xf1\xca\xb7\x19\xf2\x97\x985\x12\x83[o\x03C\x80\xca\xfc\xb8\x91>z\xae\\\x83\xf9\xe1\x0b\x9f\x90 \xd8\xea6\x16\x88|\xa1\xf3)\x9b\xe5I\xc0\x94\xa8\x96\x16|\xe6\x08f\x15E\xb2q\xb3=\x87\x08\x84\x13\x84\x10\xd7\x1b\xf0\x04\xa2Id\xd3j\x08\nY\xdfo\xecZ\xfe\xdd\xc9P\x07i\x9f\xe6>x5a\x81\x90\xa8;1k^\x16\x11\xce\xa2U\xd2\x0e\x058\xc5SyG\xfa\xa6*\x9c\xf8\x93<\x8cZ\x1c\xfa;\x9e\xe1\x8d\x1f\xc4\xc9\xdf\xeb\x10\x0b\x7f\xdd\x9a\x83\x9a\x89\x19=\x8dc\xff\xda\xf5\xa5\xdb\xa3R\xf4\xf0\x13\xec\xdf\xed\x04\xfbx\x82\xcd'7h}r\x03\xf4\xe1G\x93!\x0d\xe1~`\xd7 \xff\xba\xec\xd6ok%\x9b\xb2\x19Ge\xd1t\xc0o\x19\xfcw6\xfb\xd3\xa1\xde\xb2\x8f&\x9a\xfac9\xd4\x99\xf0\x06\xb6\xeccT\xd8\xc7\xcc\xb8\x8f\x99m\x1f\xf9ne\xb8[Ae\x89{\x10\x89\xb5\x0b\xc4\xda\x05\xb8vV\"&\xfa\xeb\x0fp\xf1\xd6\xbe\xe51N\x98Uun\xf6)\xfcrg\xb8\xf6\x82\x0dB\xb0\xc4\xfe\xd2\xee\xb1\xb0'L\x10\x15\xa2\x0d\xa7lV{\\>/\xc4\xdb\xf0\xfc\xdf\xcd\x8f\xf2\xb7\xe4A\x16.\xd82\x08\xd9\xe2\x13%/5\xcbp\xfbE\xf5*\x19\xe6o\xcb\xcf}\x8c\x82\x85\x8c(V\xd7\xbb\x89\x93\xab\x13\xfa\xfd\xcd\xbc\xa1\x7fK\x1e\xc4\xec\x9c]}\x11U\xca-\xe4f\x01F\xa6\xc1zm.'\xe5Mg\xa6\xb19\nxp\xfa\xc0\x9d\x9e\x07\xeb\xd9}\xef\xeb\x07R\xb3a\xae\x1e\x1bb\x0c\x80\x18\x94\xf3@\x8a\xdd\x07V%\x02i:\xa4\x05o8\x1d\"\x1b&\xd5\x07G\x9c%mq]\xf3\x9e\xd0\x9aw\xcar\x03\xa0\xb8`\x0b\x947Si\xe5K\xdf\xc1\x7f\xce\x8a\xcbS\xa2-:\xa9\xdf\xca\xab[0\"\xea\x81e\xc5P\x93\x95kFY\xaf\xcc\xc7|\"\x92PT\x1au\xd0\xd6\x14\xe6\xb6\xf8\xa4vC\xf8Zu!\xed'Q\x16\xcf\x19ty\x81ua\xd3\xfe\xf9*:\xf3WB\xe7\xd7=\x04\xe7\x9cB\xf5\xe5\xa9\xe7\xf3Wkz\x15\x9c\x87Q\xcc\x9e\xf9\x89\xfe.\xe0\xef\xd8\x97BfO\xb4J\xea~\xd1\xa21]\x06\xe1\"\xbaT@A?\xfb,\xd9\xc4\xc1\xda/\x19\x06\x06\x8d\x98\xd1\xa8N\xf8-y \x07\xff\x17\xe3\xc6\xaa\xbaF\xfe)\x18p\x11\x06\xf8\xe6{\x16\x11!\xc8\xf48}4\x0e\xe3g\xa1\x9eM\x8f\xfd\xf0\x9c\x8dkyo[TQq8^\xc7\xd1y\xec\xaf\xe9P\x84\x18\xfb\x8e\xef\x98\x0c-v\x16-\xae\xb58<\xce\xf3+\x0e\xf9I\x10\x85oR?ek\x16\xa6\x8eVu:\x98\xa9&\\\xe7i\x1cG\x97/\xc4\n\xe7_\x96?`\xea\x0d}\x8bN\xcf\xb7\xfd\xca\xc0\xe6\xebZ\xb1\xba5hD\xd4\x9f\x84\x8eEt\x9c\xe6\xcd\x0f\xb4\x8d\x0f\xeb6\xbe~\xd3\xff\xb0`s\x9b\xc3\x0b\xdej\n\n\x88\x81\x95\xdb0\x14\xbfu(\xe0\xbbc\x84\x82\xbc\xaa\x82\x02^\xd7\n\x04\xc5\xfae \xe0\xc0v\xeb\xaf\x0cf\x10/\xfc`\xc5\x16\x90F\xca\x16B!\x0c\xbb6\xc5\xd8\xc1\xc6\x8f\xfdur\x0b\xab\xd0H\x06T\x0d\xfd\xb5 >\xc5\x0di\xec\x0cW\x1c7\xba\x07\xce7\xabh\xfe\xa1t\xde\xec_\xe1\xf2Mp\x0d\xe4\x02\xbaQ\x0fB\x199x\x8a\x96\x0b\xfc>\x9e\x0egt\x01\x0b\x95\x8b^\xdd\x91\x08\x02#F\xe5\x9f\xd2g\xf5&4w\xbe\xa1\xe5\x00\xfe\xd4;Z\xdd\xba\xcat\xed\xcb\xda8X<\x00\xf6F&\x8b1\xf7\xd1N\xa98\xa3\xda\xe5b\xbfN\xdaW\xac\x9a4\xcb\x15J\x08\x0f\x0e\xe1q\xb1h \x870,i\xb3Vp\x08;\xa3\x12(\xf0\xb2\x9db\xd9\x05/\xdb-\x96-x\xd9^\xb1\xec#/{X,\xbb\xe6e\x8f\x8ae\xe7\xbc\xac4\xbe5\x1c\xc2ni,\xefyY\xa9\xdf3^V\xea\xf7\x12\x0ea\xaf\xd4\xc7\x15\x1c\xc2~\xa9\xbd7\xbc\xac4\xb7\xe7\xbc\xac\xd4\xc7S\xbe|%7\xc4W\xbc\xac\xf4\xedo\xbcl\xbfX\xf6\x01\x93\x15\x96*\x1eca\xa9\x97\x1f\xb1\xb04\x95\xb7ph\x80\xf8\xc1\x18\x9c\xd3\xd3\x81\xe1\x1ez\x88o|\xc3\x9bG\xf8\xe6\xcc\xf0\xe61\xbeI\x0do\x86\xd4Qhz5\xc4W\x1fM\xafF\xf8jiz\xb5\x83\xaf\xca\xd4\x1c\xff\x1b\xd1\xd0\xcbBh\xfe\xb7\xb3;\x86{\xa7\xa7\xce=\xc3\xd8\xa9\xaf\xd3Scg\xd4\xdb\x89\xe9\xdd>M\xed\xbdi\xa5F;\xd4\xeaK\xf3Kj\xf5uI\xc6P\xac\xfa\x8c_\xd6\xce\xb5\xd3\x03\xe7\x17\xfe\xbfk\x96\xe0\xb3\xf8\xe7\xf9\x1b\xfe\x0f\xd2\xbc\xce+\xfa\xff \xff?>\xd2S\x84\x8f\xf4\xffWX{\xb9\xc4\x8a\xe2\x9f\x17/\x9c\x99)\x90\xc6\xeb*\x92\xcc\xc5\xb5%\x0d4Y\x9e\x1c\xd6z\x93\xf5(X\xc6ho\xcf#B\xe8\xca\xa1h\xbd\xa3b[\xca\x02\x19\xab\xef\xef\xed\xed\xc8\x0f2\xf1\xc1\xae\xe1\x033\xc9\xde\xa1FvG\x8fw\x1f\xef?\x1c=\xde\xf3\xbcb\xf8\xdby\xb4`\xb0\x89\x82Bz\\\x8av\xb8\xf6\xafe\xda\x85\xf3\x98\xf9)\x8b)\xf3\xc2\xe0\xea\x85\xf83\xd1\x0d8\xd0wb\xa0\x8f\x8a;[\xf8%o\xbc\xd3SG\xc4p\xcc\x836\x0e\xf0\xfbm\xc5'{\xd0\xd5\x987S\xb0\x92\x9f\xaa\x9b\xa5\x85\xac\xc6\x9d\xc9crG2\"\xb6\x0c0\xfd\xa3\x9f^\xf4\xd7\xfe\x95\x8b\xf9\xc1E\xf1\xcd\x0d\x8c<\x19\xda\xfbC\xb09\x0e?\xfa\xab`Ami\xbf\xf58\xdc\xcbUt\xf9\x92}d+\xa4`\x83\xe4$\xe2kz\xee\xa6\xf9\x1bO\xfa\x1fie\xb2\x97\xf4z%\xe2m\x17\xaeU\x1bE]\xcd\xffkH\xdfU\xe0\xdcrw\xfe\xff\xfca\x919\x87\"\xfb \x19iP\xc6\xd5\xb8\xa40`J'C\xce\xff\xd1\x13\x8a\x88:\xa4\x8c\xe4\xf14\x10Z]q\x16\xd84C\x0f\xeeN\x87\xc8\x99,7]\x1d\x91A/\xff\xcc\xc0\xd5r\xd0\xc8\x94\xff\xb6\xd7\x03\x97\x12\xb8\x95B\x90\xf7eV!\xde\x0foOdt\x98\xf7u7\xcb\x1e\xf8\xd4\x99\x8f\nk\xfd\xd5\xd4\xe7\xe3\x0b\xa7\xd9\x0c\x0e\xcb\x91oA\x13p\x17\xe1\xd9\xd5@\x8c\x03\x0e\xb6\x98H\xf3H\x05;Q\x9c\xfe\xc0\xae)\xd5\x8c\xfaQ\x8c\xde\x1e\xb2\x7f\x06\x0b\x19=]\xfd\xba\xb9\x81G2\xf6y\x18\xfd\xc4\x96\xd4\x86x\xd4[\x08\xa3g\xd1z\xe3\xa7?\xf2\xe3Lu\xb4\x02\xbd\xe6<\xe2\xd0\x8d\xeeV\x97b)\xb5\x02\xbd\xe6\x1d\xe2\xc5\xcb\\Du\x9f<\xbf*\x86\x98\xc7\x9cWa\x1e\xa6\xbe\x98I\x9a\x97,2\xfe\x85\x9f2a\xa7@\xa5Y\xc2\x16\xdf\xeao\n\xc1\xfdL8\xe2\xc4x\x98\x10\xe8\xc5i\n\xe0\xb0\x14:\x96y\"w1)\xe6\xb6\x87\x04\xd7|l\x89f\xaa\xf4\x04\"8\x80\xe4\x89\x879\x1a\xd0j]\xa6\xe6\x17n|\x98\xf8?\xf2\xd0\xda\x87\xfcCD\n\x0b\xd1A\x82\xa9\xdd\nox\x97\x14\xc65Bc!z\x0eu!\xc4\xa9\xe0\x03C\x01\xd7\xddC\x08<>\xc4\xeea\xd9\x9dL\x80\xb0_\xbbD/\xebbo\x9bc\xebJty\x1f4\xce\xce\xd4\xf6\xb7U\x14-\x19\x0e\\\xb1\x15\x87>z\x9c\xd76\xf4okC;\xa3b`\xaa\xe1h\x1f\x99\xf7\xfda9\xf2\xd5\xe8\xf1\x1e\xff\xc5)\x94\xdcm\x82\x93$\xe2\xd7\xcd\x0d\xec=\xdc\xd9\xdd-~\xc7/\xe3\x1d\xfe\x8b\x92Q\xa8\xaa\xbc|\xbf\xd4\xf5p\xb8;\x1c\x0ek'\xf2\xc2:\x11\x9cb\xa9\x1fl\x99?\xbe\xcf\x1f\x9f\xe6\x8f\xaf\xf2\xc7\x0f\xf9\xe3\x8f\xf9\xe3e\xfe\xb8\xa8\x1d\xd6;\xeb\xb0\x1e\xfcz\x1a\xde\x07\x19\xc8D\xdfn\xf9\xc4\x0f\xd27\xd5X#\xbfs2\xa7X\xf4\x0b\xe7U\x8aE\xff\xe4\xb4M\xb1\xe8g\xc0\x88\xd2\xd5A\xfeP\x1fg\x9d\x8f#\xd2\xed\x9b:\x86\xe8'sK\xf9\nO:\x85\xfa\xa8\xbe}Kx\xa0R\xce)\xd5\x7f\x8b\xec\xa3\x85\x04%\xa5\x9d\xc4x<\x9do]\xba\x8c|,;\xcb\x1f\xdf\xe4\x8f\x97\xf9\xe3\xfb\xfc\xf1i\xfe\xf8*\x7f\xfc\x90?\xfe\x98?.\xf2\xc7\xeb\xfcq\x9d?n\xf2\xc7\xe3\xfc\xf1*\x7f<\xcf\x1f/\xf2\xc7\x8f\xf9\xe3\xf3\xfc\xf1713{V\x17C\x82\x07\x839\x8a\x97\xbf\xed\x10\x0bb\xf2\x06\x0e[\xff\x13a\x05c\xdd\xef\xd7\x9a\xcdS\xff\xe3m'@\x91\xdd\x9a'\x02\xe2\xe6\x8a\xa7\xa3\x861\x83\xca\xffB\xb3\x9c\xa3\xfa'\xe2'=\x81.\xe7\xf50\x9b=_\x07Q\x01&\xfcqL\xc9\xeb\xa0\x0b\xffp\xe7\xc4L\xa2\xd2\xa2\xb63{\x98K\xc8A1\xb2V\xfa\x83\x83g\xe65A\xfb\xcf\x8d\xd0~\x0f3\x934+\xf7\xe4\x9fb\xa4s\xaa\\p\xcaV\x1aI\xc8LK\x84\xd0\x111h\xfb\x80\x0e;\x9c]\xdb\xdf\x19\"\x11P\x8dO\x1a!WL\xdf\xec\xef\x8c\x06\x90\x07+\xdd\xd9\xdd\xe1\xcc6\n\xa6^\xbb\xc3\xc1\x08\xbd\x96\x19lS\xeb\x949f[|\xd6%\x1e\x8e/\x1b\xa7\xdd\xc6$\xf3z+\xcce\xbb\x87\xd0AJ\xe6\xdf\xfc\xe2\x99@:\x8df0\xa6[\xee\xb5\xd9\x1bM\xff\x93\xba\xd4\xba=\xf3(}\xa8\xb9!\x11\xfc\xc1\xbee\x05\x99n\xb0\xdeDI\x12\x9c\xad\x84\xb7\xfb\x18\x02!\xaa$\x0b\x10\x8a=\xe64\x11v\x7f\xb8\xf5\xfc\xfc\xd7\xf64Rp(\xe95)\x00\xc4\x90k\x06-@\\D&\x85XRF\xf9E\xc8\xcf\x1b%\xd46\x7f7\"|\xa4\xde\xf1Q8]\x07\xb7K\x1e\xcam\xbalNC\xa7v\x86\xdf[\x19a\xdb\x909l\xe4(u{\x88\xb9/\xa9\xf4\x85a,\x8a\xf8\x99\xb2\xf1/E6\xfe{G\x98\xa2_\xd0\xfe1\xf8\xf39\xdb\xa4 \xaa\xde\xf0\x06^QN0\\\x81{M7MqZ\xd3\xd5\x8cff\xbfy\xecW\x8ad\x87cc\x95\xda\x90\xd3\x06\x83,#\x9b\xdf\xa9\x97\x8f\xfeOA\xc6G\x87\xbe\xcc\xb3\x17\xf4\x07r\xc8a\x8f\x8er\xd8\x83\xce\x10C\xdf\xa8\x9f\x03Cj\xe0\x04\x14\x94P\x13\xe5$\xad\n\xf9\xe9,\xed\x01E\x85+r\xb9\xe5\x14\xa6\xbc\xf9y\x0fV=\xb4\xff\xa8\xbaIq\x00Ea\x87z\x85\xbe=\xf2MU\\\x86\x02;W\x93P\n\x8dX\xae$Q\xbbM\"@-al~\x13\x18\xda\xd1\x8a\x1aZ\xd4?.\xa0:\xa5\xee\\g Z\x12\xf8pF\xa9n([y\x9d\x05\"\x14D\xacDB,\n\xfa\xb6\xec \xf1`C\x0fE\xf6\x9c\xd5\x10\x1b\xceW&\xe2@\xedb\x1c$\xa1\xd6\x12\x91%\xc2)'p\x16\xd3h6\xeb \x1cCf\x80>\xe5`\xa7\xff\x08\xee\xf1t\xb58A\x02\xf8\xf1l\xf0\xa7\xdc\x9b\x823\x1e2\xeb\xbb\xac\xb3\x14[\x875\x8b\xc9\xcc'\"r\xd3\x84\x13\xaa\xe2\x11\x1c\xe5\xf1MS-\x1d{?\xf1\x97\xec\xdb\x92\xb5B\x8d\xe5\x1eM1\xee\xb3\xab\x94\x85\x0b\xb7z\x8e\xc8Fs\x0cYq\xb7\xf0\xc6/\x8d\xeeN>?\x02\x90\xc85V\xba\xd6\xf0\x83\xed\xbc\x7f\xcf\x92\x1f\xa3E\xb6\xaa\xc6.\xfd\xe8\xaf\xb2\xa2w\x1f:\x8a\xf5\xcfY\xfa,\n\x97\xc1\xf97\xd7\xefb\x0c\x86\xdb_D\x97\xe1*\xf2\x17T\x0e\x87\"\x1eB>\x80\xdc\xe9h4\x18j;h\xf8\xd4\xae\xf1*\xdb\x16\x18\x15\xbd\xa2\x92;\xe0C]\x86\xfd%K\xe7\x17^\xc5E+\x9f\x93qJmvU\xd51\x92-\xca\x97\xb8\x9fl\xd8\xfc)\xd6L\xccH2\xf7\xe7\x0dJ\xcb\xe1\xa6^?\xbd`\xe8\x07\x17\xe9\xe9F\xe5\x9f:E\x91y\x14\x80\x9aSM\xbe\x8c\xce\x88\xa8.\xed'\xa9\x9ff \x1c\x1d\xc2\xee\x00\xd3[\x04\xfdl\xb3\xf0S\xf62\xf2\x17Ax\xfe\x06\xdf\xbb\xce\x12\x1d\x17i@\x9c\xb3\xb8e\xb5w\xf1\xcaux\xc1<\n\x93h\xc5\xfa\xa8\x14se\xffo\xd9U\xaa\x91'Y\xbc\xe2@\x86\x17\x07R\x89\xcc\xe5[)\xdcQ\x7f\xf1\xd7+\xea\xc1s\xc3~\xca\xae\xca!\xb4\xa1\xaaF\xfb[\x9d\x1f\x1d\xf2\xcfY\xda\x12\xd2R^\xf78t\xcbw\x15L\x80\xc1\x18\xa6l\xf6\xf7\xc2\x12\xa5s\xaf\x08w~\xfa\xf7\x0c^\x84H\x91\xcb\x1b<\xef\x0b&\x10\x83)9\x93\xd4\xc7\x96\x83\x17\x16[F5\x9a;\xdc\x7fT\xea1\x11#\xd9-\xe2!j\x93\x02I\x92\x0b\x06\x07\xbcL\xbe\xf0\xdc\xa0\x07I\xff\xdd\xebo\x9f\xbe}\xfe\xfe\xd9\xab\x93\x17\xc7\xdf\xbd\xe9\xb5\xdc>\x0c\x0e\x8d\x80\xeccp\xd1\x7f\xbc\xf1\\\xd6\xdf\xf8\xd7\xfc\xa8\xeb(\xde3\xf7\xfa\xf6\xd5w\xdf\xbdl\xdb\xab\xbc9U\x07f\xb5/\x02UEt\xa2\x86\x9c\xf0\x97=\xe8\xc4\xc5\xd1\x05\xc2\xf3t\xe6}\xc5\xf7\xf9\xc1\x83\xff\x03\x14J\xe2G\n\xdb\xf4\xee\xa7\x97\x87\xc9\xa5\x7f~\xce\xe2\xed,\xd8\xe6xg\xe1\xaf\xa2\x90m\xa3N$\xed\xff\x96\xf4\xd7\xfe\xe6\xff\x07\x00\x00\xff\xffPK\x07\x08v\xf2\x8aA\x86\xba\x01\x00\xc5\x87\x08\x00PK\x03\x04\x14\x00\x08\x00\x08\x00\x00\x00!(\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00 \x00swagger-ui.cssUT\x05\x00\x01\x80Cm8\xec\xfd{s\xdb8\xb27\x8e\xff\xff\xbc\n=\xbb\x95\x9a\x99\x1dS!EQ\x17\xabf\xeb\xc8\xb1\x93q6r\xc6\xcem\x92\xad\xad)\x8a\x84$\xda\xe0\xe5\x90\xd4\xcdz\xf6\xbd\xff\x8aw\\\x1a $;s\xf6\xf7\xad\xb3\xd9dl\xe2\xd3\x8dFw\x03h4\x00\xb2\x9bl\xed\xe5\x12\xc5\xda\xda;\xfc\x9fN\xe7\xe5\xdf\xfeo'\x08c\xdf\xc6\xde#\xea:I\xd2\xd9\x0c\xbbzW\xef\xfc\xbf\xce\xec\xfac\xe7\x9d\xe7\xa0 A\x9d\xff\xd7Yz\xe9j=\xef:\xa1\xff2@N\x88\xed\xe4%M\xf7\xb7\x97\x8b0H\xb5\x85\xed{x\x7f\x9e\xd8A\xa2%(\xf6\x16\x13'\xc4a|\xfeWs\xde7,\xe3\xdfD\xfd\x9dU\xea\xe3\x03\xf6\x02\xa4\xad\x90\xb7\\\xa5\xe7F\xd7\xb0&\x9a\x9fh)\xda\xa5Z\xe2=\"\xcdv\xef\xd7Izn\xe8\xfa\x8b\x89\xb6E\xf3\x07/\x85K)\xce\xf3\xd0\xdd\x1f|;^z\xc1\xb9N\x95\xd8q\xea9\x18\x9dQ\xcf\x12\xcf\xa5\x9f,\xc20E1\xf5h\x85l\x97y\x14\xd8\x1b\xea\xf7\x049\xa9\x17\x06\x07\xd7K\"l\xef\xcf\xe78t\x1e\xe8\x16\x1b\x87\\K\x99\xf0\xe7=\xe4OJ\x19\xbb\x83!\xf2;\xb4\xa4\x0bo\xe9\xd8Q\xc6\xf0\x8cy\xbc\x8eii}\xdb\x93UZPT\xea0\x90\xdf\xe9\xeb\xd1\x8e\x96+>T\xca\x9d\x87\xbbL\xe4\xdd2\x1f:\x16a\xec\xf3\xca\xfbg\xba\x8f\xd0/1JP\xfa\xaf3\xbe Y\xcf}\x8f)\x01*\xcbf\xb5\x92\xa2(\xfdW=\xb6\xdaQ\x84\xec\xd8\x0e\x1ct^\x14\x01\xd5\x974\xe7\xe7\x9a\x1f>j\x8b\xd0Y'\x9a\x17\x04\xcc\xd4C\x8a\xaa\x04-\x85o\xc1\x16\x95\xf3 \xde\xeb&\x91\xed\xba\xd9l\xa0K\xda\xd0\xb0\x89\xbd`)n@+\xae\x92^\x02,E\xa7\x11\x87p\x9df\xbevnD\xbbr\xec\xed\\\xe4\xc0\x8fh\x972\xb3$\xc2n\x82\xd2C\xd5\xb0\xaei!\xbf\xd3\x1d\xe6\xff\x0e\xb8a\x01\xa3%\n\\h\xda\xac\xe7\x14j\xd6$\x9e\x16\x83a5\xacW\xdd>\xb5\xe7\x18M|{\xa7m=7]\x15\x1d\xa5\xd6\xf2d\xbb\xf2R\xa4\xe5\x83\xf4y\x11y1Sl\xb8\x8cQ\x92\x80\x83\x8f\xd2(Xw\xe1\xbaw\xd9\xeb4\x04\xac\xeb\xac\x90\xf30\x0fwP\x1f\x89m\xd7\x0b\xffu\x92Vd\x0e\x15\xac\xfd9\x8a3\xef-\x19\xe7^\xa9%\x91\x17h@\x17\x14\x10\x85\xeb\x94&:\x94C\x90\xa0\xa1 \xb2cg\x05v\xdfLY\xb9\xc7LJ\x0f\xd3\xc2\xc5\"A\xe9\xb9\xd6cB+\x8aU#K\xf1@s2nX\xdc\x06\x11]\x13\\@\xd2q#[C\xbf\xf00\xd2\xd6\x11\x0em\xb7R\x82pt\xcaG\xed\xcaO\xe9X\x00\xa5\xb6\x87\x13:\nE\xc1Z\x12\x85&k\xdf\xb7\xe3}\x8d\xc0^\x92j^\xca\xf4*\xc7\x0e66\xec\xc4\xb4V\x8b \xed_\xcc$\xe4G\xd8N\x115\x93Rd]\x17\xcd\xd7\xcb\xce\xdf\xa8q! \xb1\xe7v\x96!v\x01\xac\x96\xf7;\x90\xe2\xaf\x8b\xc5\x02\xa2\x98c\xdby\x80)\xd8\xf8\xa7\xa4X\xc6\x9eK\x04Ndx\xdbY\xc7\xf8G\xd7N\xeds\xcf\xb7\x97\xe8e\x14,'Y\xf7\x1d\xf4\xcf\xbc\xcf\x17\xef\xef\xb6\xfa?\xde,\xc3\xe9t:\xbd\xf9\xf0iu\xf5i\x99\xfd\x98\xffs\xfdj\xfau:\x9d^^]\x0e\x07\xef\xb2\x07o~\xbf{\xfd\xe5\xd7\xbb\x8f\xf3\xde7\xdd\xed\xbd\xde\x7f\xbb\xbd\xb8\xf8\xf6f\xec}\xfbp\xf1v\xfe\xe5u\xf0\xed\xf3[\xfc\xf5\xcb\x9d\xe58\x18\xff\x96\x11\xecW\xd1\xe7\xd7+\xfd\xcb\x951{\xef\xdfl\xe6\x1f\xacU\x81\xb7\xfa\xf3\xdf\xa7\xc5\xff.\xb7/\xd1\xaf\x17\xab\xaf\xbd\x14\xbb\xaf.\xbco_\xdch~\xaf{\xc3\xe1\xfa\xe5\xb5w\x11}\xbb\xd4\xbd\xcf\x8f\x9fofW\xc6\xf6\xb6\xf79\xb4?\xad\x06\x8e\xff\xf9#z\xb0>}5\xa3\xf8\xeb#~\xb8\xbe\x1f\xfd|}\xb9\xeb\xbf\x0fV\xa9\xf3\xc6\xc0\xee\x9b\xab%zc$\xf3`6@\x97\xba\xf7\xf5\xcb\xdd\xe6\xab\xffi\x90\xfd>\xff\xf2Y\xff\xfaa\xe4]\xff\xba\x1c\xa07\xc6\xd6}\x93\x8c\xaf\x1f^?\xcc{o\xf1\xf5\xeb\xd5\xcd\xa7W\x17\x97s\xf3-\xbe\xbe\xfc\xb4\xbe\xf1\x8c\xfb\xd9\xc7\xab\xdd\xf5\xa5c\xbd\xbb\xbf2\xde_\xce\xf67\x1f\xb6\xcb\xd9\xfdtw\xf3a\xb4}\xffa\xb4\x9b\xbd\xd2\xb7\xb3\x8f\xe1nv\x19\xeeg\xaf\xa6\xcb\xeb\xea\xef}\x7f\xf9\xdb\xafo\x1f\xbe\xddG\x1f\xee\xae\xbe\xd6\xf28\xfe\x9d\xff\xdb\x87\xb7\xa1\xfb\xeb\xdd\xf6\xbd7\xda\xb8\xa6k\xbe\x0b\x9c\xc7w\xfex\xffm?\xda\xbd\xff\xf8`\xbd{\x9c\xee\xdf=^\xef\xdf\xfd\xfe\xf6\xe1\x9bg<\xa2/\x96\xfe\xf5\xf7e:\x0ff\xf7\x04\xdf\xabo\xbf\xdf\xdc;>\xde\xbao\xf0f\xee]\xec\xbf\xbd\xf9:\xf8\xfa\xe5\xed\xc6\xfd\xfdv|\xed]7:xcl?~\xd2\xc7\xd7\xfeJw\x7f\x9d\x0e\xde\xed\xc7kg_\xdb\xe2~\xde\xd37\xe8\xcd\xeb\xed\xbb\xc7\xab\xf5\xec\xd58\x9d\xe7\xfaY\xa5\xf37\xd6\xe3\xfb\xe0F\xff\xe4\x7f\xa6d\x9e\x07\xb3u\xa9\xd3\xf5\xd7\xde8}g\xaeV\xce\xab\xd1\xee\xdd\xfdt\xe3\x18w\x96\xf3\xe6\xd3\xe6\x93\xff\xf9qn~\xde\x7f\xed}\xfe\xf0\xed\xcb\xd7\xfbk\xef\xa2?\xff\xb2[;\x8fQf{EY\n9\x9c+\xe3\xe6\xfd\xc3\xdd\xe6\xab\xf99\xfd\xf6\xc5\xd2?|\xba\x1d_g\xb6~e=\xd8_n\x07\xb3\x8fw\x97\xef?~\xed\xdf\xe8\x9fz7\xfa\xe7\xd7\xb3\x8f\xaf_\xdf\xdc/{\xb3\xc7o\x97\xb7\xf7\x0f\xdb\x9b\x87\xdb\xfe\xec~\xb9\x9d]]\x13\xfc\xf0\xda1\xefVs\xff\x06\x13\xfc\"\x9a\xdf\xad\x1a\xbf\xcb\xe8\xd2\xf1?\xaf\xdc7\xe3\xfd\xe77\xe3\xcd\xfcR\xf7n\x0b\xfd,?\xbdYm\xdc7\xe3G\xfb\xcdx{}usy}y\xbd\x9d}\xfc\xb4\xfc\xc7\x95\xb1\xfa\xda\xc3\xeb\xbc\xec\xd5\x83\xf7\x9b7\x1d\x95v\x1a\xdc\xbd\xf9\xbc\xb7\x7f\xff\x86\xbf]}\xdb\xcf{\xfa\xd21\xef2\x1d\x0e\xec/\xd6\xa3\xfb\xe6\xf5\xfak\xef\xf3\xdb\xbbK\xdd\xcb\xf0\xef|\x1c}\xbb\x0c\xcd\x9b{g\x7f\xfbpk\xde\xdc\x7f5o\x1f?\xedf\x9f>\xf5n\xef\xdf\xbe\xba\xd5?\xedo.\xa7\xfd\xd9\xc7\xe9vv\x7fe\xce>\\\xd7\xfc\xbe\xbd\x19\xdf\xbb_\x0c<\x0f\xee\x08~w4\xbf\xc7V~\x9bL\xf6w&\xe0\x93\x99\xaf\xbe\x1a\xe7~\xf9\xe9\xe1\xeeM\x81+\xfa]\xde\x0f?\xf6\x97\xbf]\x8e\xfb\xce\x9b\xd7\xf7v\xef\xb3~\xfd\xe6\xf3:\xeb\xef\x8ew\xfd\xf2\xb7\xe4\xe2\xc3\xcfof\xd9\x08q\xff\xe1\xd3\xdd\xc5\xe7_\xef\xed\xaf\x9b\xc7\x97/\x1fG\x97\xef\x92\xcb\xfe\xd2y\xf3\xbb\xf7\xf5j\xfa\xe6\xe2\xfa\x1fo.\x02\xf4\xf2\xe5\xe2u\xb4\x9d.\xb7\xd3\x8b\xf1hj\xbf\xeeE\xf7\xf8\xd3mF~\xf1\xf6\xee\x93u\x15?\xbc].\x97\xbf\xfc\xf2S'F\x11\xb2\xd3\x8e\xde\x11\x8e\xa4\x9a1x\xc6\xc1\xf4\"\x1f\xe6n\x8b\xc1t\xba\x18\xbd\x1c\xaf\xfew0\xfd\xdf\xc1\xf4?u0}\x7f\xf9u\x7fw\xbf\xba\xba\xbb\xcc\x06\xd3\xaf\xfb\xd6\xc1\xafe0m\xf8\xdd\xaa\xf1\xfb\x0f\x1aLo?\xb6\x0e~G\x0d\xa6\xb7\xed\x83\xf3\xf7\x19L7\xaf>\xe8\xc6u6\x18\xcd\xea\xc1\xd4\xbf\xeb\xbf\xb4~\xbex\xfd\xdb\xc5b:{\xed\xbf\x9c],w\xa3\xbb\xe9\x9b/\xaf\x02c:\xf5?,\xcd\xfe\xed\xe0\xe1\xe2\xf2\x1f\xb37\xb3\xcbW\xdb\xebWhv\x8d\xfc\xd7/\xad[{{\xe5E\xd3/\xdbO\xab\xed\xd5\xfd\xecr3\x9f~\xc1_\x1e6\x9f/\xb6\xeb\xd1\xe6\xf6zz1\xbd\xda^\xbc\x8aV\xa3O\x03G\xcf\xc7\xa5+\xfc\xfa\xe3\xc3\x87\xf5\xad\xff\xea\x95\xd2\x00<\xd2\xf2x\x97\x1c\x85\xb3`\x99\x1d~\xef#T\x8f\xbf/\xc7\xf7/\xfb\xb7\xd3\xafw\xbf\xaf\xa2o\xcb\xe9\xf4\xc3\xa7\x87\xff.\x03\xd9\xe6\x7f\xbf\xbdL\xa6\x17\xaf\xaf\xdc/71\xba\xcdF\xe6\xdbj\xe0|\xd9\xbf\x9d\xed\xec_\xeft\xe72\xdc\xbc\xebY\x8f\xef\xfcb\x1c{\x97\x8f\xb5\xe3\xfe\xd7\xdf\xa7\x9b\xd9\x87\xfe\xf6\xddv:\xfa\xcd\\m\xbf~\xb9\x89\xbf\xfd~\xbb\xfc\xea\x7f\x0e\xec/\xfd\xf1\xf5\xfa\xe7\xe1f\x7f\xbd\xb4\xbf\xdc\x8e\xaf\xb1c|\xfcxq\xe3\\\xdd`\xfb\x0d\xbeF\xc1[\xfc\xc9\x8c\xde\x7f~s3\xb0{3\xeb\xdb\xab\xeb\x97\xb9\x8f^f\xfd\xf7\"\xfd\xf6\xfb\xdd\xaa\x19#\x96\xe3\xeb\xb2\xee\xf7\xbe\xf5\xf8\xde\xcf\xc7\xe0M\xd6\xe7\xf31\xf9\xd7\xbb\xf8\xb7\x0fo\xab\xb9\xe2\xeb\xc7\xcf\xd3\xe5mo\xbc\xff\xf6aj\xbc\xbb\xff\x9a~}\xbc\xda\xcd>L\xcd\xf7\x1f\xfa\xbb\x9b\x8f\xcb\xc7\xd9\xfd\xa7\xa4\xec'\x9b\xd9\xe5\xc3f\xf6q\x9a\xce.\xaf\x06\xb3\x8f\xd3\xc1\xec\x9e\x18c_]g\xe3~\xed_\x8d<\x99/\xea^\xad\x1b\xd35\xdd\xbde\xce\xf6\xd6\xc6\xf1\x9d\xcd\xec\xe3\x83\xf5\xfe\xc3h;\xf3F\xfb\x99gd\xf4\xa9cf}\xf1u\xff\xdd\x17\xeb\xf1z\xdf\xf0\xbd{\xf3\xf9\xf1\xab\xf96r~\xbd\x8b\xe6\xbd\xfe2\x1b\xbf\xdf\xfb\xaf\xbd\xb9\xf9Y\xff\xed\xc351Nf\xe3\x00Q\xa7\xcc\x1e\xfb\xff\xc0\xb1\xf9\xf7\xe9\xe0\xd6|\x8b\xbf\xfe~\xb7q\xf0\xddf\xde\xdb\x12\xf3\xe2E87\xef6No\xb5q^]\\\xde\xee\xa7\xfb\xd9\xe5\x95q\xfdju\xf3\xf5\xcbM4\x0f\xb2\xb2eT\xf0\xb9\xb8\xf9\xf81z;\x0fn\xf4\xaf_\xac\xfbo\x9f\xf0\xd5o\x1f\xdef\xfc\xd7\xf6\x17\xfc\xf0\xfe\xe1z7\xbb\xbf\xd6\xdf\x7ft\x1eo\xee\xddW\xb3\xc7\xab\xdd\xdd\xc7o\xaff\x0fo/\xef>^\xeb\xb3\xcb\xe5nv9\xdd\xcf>:;\x82\xdf\xd5\xbcwc\xcc\xbf|^\xbbW\x0d\xbfoo(~z+\xbf|\xee\xac\xe7\x13\xec\xf8\xb8\xf7\xed\xcb\xdd\x1b\xc7\x1f\xa7\xd7\xbf\x16\xba|\xef\x8b\xe7\x85\xdb\xfb\xab\xfd\xec\xfe\xd6\xbay\xbc\xea\xdd\xe8\xd7\x8f\xf9\xbc\xf0p\xbd\xbf}\xb8y=\xbb\xbf\xdd\xbe\xbf\xbc\xda\xce.\xafw7\x8fW^\xc3O\xde\xfa7\x97\xa3\xf0\x1f\x97\xe3_\x7f{\xfc\xf4\xb2\x8d\xa6\xfd\xef\xe2\xe5v:\xbd{5\x9d^O\xa7\xcb\xcb\xe9\x87\xeb\xe9tuu1\xdd]]\xbc\x1c\xddN\xbfd\xe3\xe6\xed\x14\xf8\xdf\xd7\x8b\xe9\xed\x15\xf0\xfc\xfa\xeajzu1\x9d\xce.\x98\x82\x8b\xe9\xe5\xd5\xab\xa9~u7\x9d^]^\xf0<\xef\xae?\xbe\xbe\xf8\xf4\xe5\xea\xc3\xf5\xe6\xa5=\x9dn/\xa7\xb7\xd3WW\xb7\xb3\xbb\xe9\xe5h\x1a\xbe\x0f>~6n?^\x0e\xdf\xbeMV\xbf\x99\x9b\x0f3\xf3\xb7\x97/\xbf)\xcd/\xc6@m\x829*\xbe\xcf\xe6\xd7W\xb7\x0f_\x96\xbd\xe9\xff\xc6\xf7\xff\x7f\x1d\xdf\xab\xce\x01t\x1c\x9e\x8d\xad\x8asV\xcfH\xc9y\xab\x8c!U\xe7\xad\xc7\xcf\xbf\xe2\xed\xb7\x0f\xe3\x0f\xdf~\xbf\xd9\xb8\xbf\xbf\xbd\xcf|\xe9\x9b7{\xb6\xf8Y%\xae\xbfy\xfcj\xce\x1e\xde^\x15I\x97\x99!\x1f\xbf\xdb\xd7\x1d\x0d\xbf\xaf\xad\xfc\x9e-\xbeoOn\x1c\x15\xdf\xdf]\xb6\xf2\xfbN\xf1=\x1a\xbc5\x1f\xb2\x11\xe2\x91M\x96\xe8\x9f.\x93\xd9vv\xff\xe1.\xfc\xfa\x9b\xf5\xe6\xbf\xfb\x1f~\xbb\x99\xdf\xdd\x7f\x9e]\xdd\x1a\x8bWw\x97\xcb\x9f\xbd\xe0\xe5\xe0\xe7\xb7\xc6\xf4\xed\xa7]\xb2\x9c^\xbd\x99NM\xe3b\xfav\xf6A\x7f\xf3\xb5\x18\xcf?|\xfa\xfc\xfe\xee\x1f\xd6\xab\xaf\xd7\xd7\x92\x04J\xb3\x15C\x1f\x8e\xa1\x7f\x03\x8e\xcf\xccCwO=\xe0N\"\xb8\xf4A\x04\xd7\xa3\xcf\xcd\xb8\x98\xfe\x95\xdeZ\xae6\xe6\xe8\x87\xfc\x01\x9dE\x18\xfb\xf4F\xacA\xff\xda\xa3\x7f5\xe9_\xfb\xf4\xaf\x16\xfd\xeb\x80\xfe\x95?\x0b\xb4J}\xba\x15\xf9Nu\xb1\x89\x83|\xdb\xc3\xff\x12\x95\x96\xdbT\xa2\xe2\xc8N\x92m\x18\xbbB@\x8a\xc4\xbcS\xb4K\x85\x85\xeb\x98!,\xb64\xe9G\x1e\xbd\xc7c{\xf4.UH7\x9a>'\x101\xe7\x94\xca\xf3Q\xd4\xb3|\xd7\x93~BKPmK\xd2\x0fW\xf4\xaf\xb4-\xd6\xf8\x94\x0dH\xba7\xd8I\x84\x9cT\xcb\xf7\xd8\x0e\xe2\xf3%b\"M3\x06\xbbq\xb5\x9b\\\x9d0\xb2\x06\xdd\x9e\xf5BF5\xde\x19\x03\x96\xca\x18\x0e\xbb\xc3\xa1\x94\xac\xbf3Y\xaa\xa1\xbc\"s\xd7\xe7\xea1\xcd\xaeiJ\xa9\x06<\xd5`\xd0\x1d\xb4\xc8\xc6\xb7\xc8\xd2\xa5$\xa3\x9d\xc5U\xd3\xeb\xca\x1bd\xedF\\5\x03y5C\xbe\x9a\xa1\xd1\xed\xf7Z\xea\x19r\xf5\xf4\xe5\xf5\x18;\x83#a\xcf,2$\xc5\xc9\xb5C\xedq\xf6< \xf1:E\x934\x8c\xce\xf5I\\zd\xc9M\x9f`\xb4\xc8~'\xce\x0eT\xe7k\xb2\x9f\x1f5/p\xd1.\xfb\xe5\xdf\xff\xe5#\xd7\xb3;\x89\x13#\x14t\xec\xc0\xed\xfc\xe8{Ay\xea\xc0\xd4\x91\xff\xd3A,W\x90<\xa17d\xd4'u\x08\x80P\xadO\x00\x84\xed\xdd\x02\xaaM\xa9g\x00\x84*\x9d\x03\xaa\xaf\xbd\x7f@\x95)t\x11\xa8\xb2\xf6^\x02\xe9Q\xa5\xa3@\xb5\xb5\xf7\x15\x88J\xa9\xbb\xe4\x84\xcf\xdfc\x14\xbaL\xf9\xb0>\xbd3h\xe9G\xfeS\xba\x91\x7fb/\xe2\xe8\x14;\x11G\xa7\xd0\x87\xf8\xba\xd4\xba\x10G\xa7\xd4\x83\xf8\xda\x14:\x10_\x95J\xff\xe1\xabR\xe8>\xbc\x06\x95z\x0f_\x97B\xe7\xe1\x89\xd4\xfa\x8e\xff\xe7w\x9d\xb6^\x82\x9f\xd2K\xf0\x89\xbd\x84\xa3S\xec%\x1c\x9dB/\xe1\xebR\xeb%\x1c\x9dR/\xe1kS\xe8%|U*\xbd\x84\xafJ\xa1\x97\xf0\x1aT\xea%|]\n\xbd\x84'R\xeb%\xf8\xbb\xf4\x12\xb2^\xcf_\x1e\xe8c\xa0\xb4XN\xb8A1y\xce>?W\x9d?\xfd\xbf\x9e\x1f\x85qj\x07)K\x12\xa4\xb6\x17\x00D\xf9s\x82\xac}\xa6;\xf0\xc2d\xd3\xee)\xf2\xc0t\xacH\n2)\xcc\xbe\x85\xa0\xfeirBd\xc7\x89)\x94\x08\x9f&\x11D\xc6IDQ\xce\x97\x9a\x83\x82\x94v\x9d\"\x19t\x1e\x84\xe5O\x13\xa2\xac\xf6sn\x90\x98/\xb54\x8c\x8e\xe6\x93\x86\x11\xc7'\xef4Gs\xe2;\xc5\xbc\xea\xc7G\xf3*\xc88nY\xe7=\x9a\xd7\xf1\x8b\xab\xda*L_P\xaaN`\x98SX ms\n3\x89yNa'\xb1\xd0)\xec\xda\x82\x12\xd5\x11\xa51\xdd\xf1N'\xb2\xdc\xf1\x9c\xc4\x86;\x9e\x97\xccn\xc7s\x93\x99\xedxnmV\x93\x1a\x08\x1f]\x9d\xc8@\xc7s\x12\x1b\xe8x^2\x03\x1d\xcfMf\xa0\xe3\xb91QL\xb7<\xfe\xce\x1f\x83\x07a\x1aqL\x1389O\x94\xc2\xe4zMt\xfc\x18\\\xf1\x08\x92\x13\x84\x05\xa9\x14\xe4%\xe9\xda|[uD\xaa\x98\xfb\xa7\xb4\x03 Ri\x86\xaf\xdc\n\x89\xc0\xf8\x14\x81\x01\"\x15\x811)0\xed\xfb6}\xcf-g9)\x1f\x95\xd18s\xbb\xa7;O+\x9alt\x00\xe8\xb2\xc7\"\xda\xfa^]1\x1e\x00\xd4E\x81\x88~N\xdf_\x86\x18\x94%\"\x0e\xb8\xe2\x90wz\x80>\x7f.\xa2\x0e\x80{\x81\x94\xba\x8e\xef\x8bs;\x9f\xd2\x8f7\x03Av\x8a%\x08\xf2S\x8dA\xb08\xdd\x1e\x04\x93\xd3L\xc2\xa9\x0f\xb2\x8a\x82Y\x14\x86\x9b\xb9\x9d\xcd\xe3'\x98\xca\x7f\x92\xa5\xfc'\x1b\xca\x7f\x06;\xf9O4\x93\xffT+\xc1\x06\xc1'\x19\x04?\xc9 \xf8\xc9\x06\xc1\xcf`\x90'\x0ee\xac\xe6@\x83\xd04Zq\xd5\xaf\xa2\x13\xbc\xe3 \xc3\x05\xc8\x8eA\xb0a\x18\x1c\xd8\xb5\xe3\x07m\x19\xdb{\x06k\x9a&\x87\xf5=\x17\x82Z\x96\xc5A\x01\xd8p8\xe4`\x89\x877\xcd\x85\xef\x128\x1e\x8f9 .\x8c\x0d\xc1m\xdb\xe6%\x0d\xc3\x00\x92\xc1q\x1c\x01k\x00\x8c\x10\x82u\x9b\xdf\xd2d\xc0\x8b~\xf6\x87\xc3\x83P\xf6&g\x85\xd3\xc6:\x0d]%\xd8\xfeQ?\xd3_\x9ce\xb1\xf8Yw\xfc\x93\x80p\xd4B8\x12\x11\x0e[\x08\x87\"\xc2A\x0b\xe1@Dh\xb5\x10Z\"\xc2~\x0ba_Dh\xb6\x10\x9a\"\xc2^\x0baODh\xb4\x10\x1a\"B\xdd\x92\x13\xeaB\xed\xe8\xbd6\xd2\x9e\x98\xd6h%6 \xea|\x8c\xe1\x9c6^\xces\xda3\x1dt\xd8\x82\x88uX\x92\x08p\xd6\x82\x88uV\x92\x08p\xd4\x82\x88uT\x92\x08p\xd2\x82\x88uR\x92H\xa8\x08\xd6AI\"\xc09\x0b\"\xd69I\"\xc01\x0b\"\xd61I\"\xc0)\x0b\"\xd6)I\"\xc0!\x0b\"\xd6!I\"\xc8\x19K*\xd6\x9f(2\xb1+\xf1\x8eH\x11\x82N\x98O`1r\xd9\xc1{\xa8\xf7u~\x9c\xe5\x81\x8bE\xdf0\x07\x82Y\x01\x82\x0f{\x16?\x89\x84\xb1\x1d,\xf9\x81~`\x02\xf3\xf32\xc4<\xd7\xf9\x10@\xee\x11\xc6\xe1\x96\xc6\xf2\xaf\x0e\xa8\xa5\x85\xe0\x7f]\xcc\x17\x86\xcdO\xa8\xd1:\x8e0+\xb0\x85z\x8e\xcdO\xe6\x05w\x90\xc2\xee\x0f\xccE\x0f6J\xe4\x05l\x04\xe2Z\xba>\xe2\xad\xb2\nS\x08\x9d\x99f\xce\xcf\xa9 r\xa4\x0b\xa7v\x10o\x9b.\x1f\x8e\x94\xc1\x10B\x01\x837\xcc\xe1\xd0\xe2\x9b B\xc7\xf6x\xc8\x0b]E\x19<\xc1\x18\xa1\xb9\xc3\xeb$\xb07l@\xa2\xeb\xc6\xbc\xcf\xb3\xce\xa5\x9e\xe35k\x1b]\xef\xf7\xc7|\x08\x03 Mk\x88\\\x91W\x01\xf8\xf1\xc0q\x80 &\xc7\xa3\x04$q\\\x04\x91l\xedd\x85\\\x88`1X,\x16\xbc\xf4%\x01\xa4H4Z\xb8\x0b\xde{K\n\xb8s,\x16\x0e\x9a\x8bH\xa0\xde\xef.\\\xbe\x15d:\x91\"\x10f\x88\xe6\x9aV\xbe\xea\x84&\x80\xde\x7f\xd2\x9d\xc7\xf5\xd0\x1d\xdb\xae\xb7N\xce\xd9\xa1\"6\x18@\xd7\xe8Y1b\xd3\xadq\x8f\x85\x81(\x93EA\xa0>\x032\x00\x8cf\xe8\xac\xe4@R9\xd6\"\x0fc\x067\x1e\x8f\xc7\xc0\xea\xaf\xdew+\xc0y\x92<[iUz!\xd7\x90\xc5:P\xa41\xad\xd8U,\xe0UV\x1bbU\x96\xb5q+\xf7\x16[\xe4\x82*\xe2y\x15\xdb\x81\xa2\x96\xc8\x05kO\xb6\x1cX\xe7\"\xd3Q\"\xff\xe21\"\x17\x03\x90\xb0\x97\x01@\xd0\xd1x\x9c\xc8\xd7\x00\xa4\xc8\xddx\xa8\xdc\xe3\x98\x8c\xdfS\x9c\x8eO\xdd=\xd9\xefT\xa4Sw=\x86\xdb1\xde\xa7\xe0~*\xb9\xbeX'\x12oB\x97d!B\x8f\xe4\x80\x02\x87\xe4p\xb0?\xb20\xa1;r@\xa17\xb2\xc8\x16g|\xb6\x01\x90\xcbN>\xdd\x15\xdbe;\xc2\x13\xfd\xef\xe3\x88\x02\x9fc'!\xc0\xe7X\x88\xd0\xe78\xa0\xc0\xe78\x1c\xecs,L\xe8s\x1cP\xe8s\xc7M\xb9,\xbc6oc \xa2\xa0<\x9e\x06\xfb\x1c\x9b\x80}\xba\xcf\xe1\xe7\xf49|\xb2\xcf\xd1\xfc4\xadx d\xc5\xaeH\xf5\x02/\xe5-\x82\xf8,\xe4d\xa0\xf93\x0eZ\xdeF&\x91\xc0&f\xb6\x84\x08\x03D\xe3\xf2w\xd4\xb5\x0f\xd1\x07\xb8!\xdcn\x8f\xb4-\xd8\x92a\xb5\xc8(\x1cDd\x17\x1e\x08\x9b\x86\xc7\x81\xd6\xe1`\xa0\x818\x14l#&\xee\x15\x9a\x89\xdb\xbe\x17Z\x8a\x0f\xf5\x85\xc6b\xf7\xe2\xebm\xc0v\x83\xa9\x0cl[\"\x1a\x15\x1a\xd1W\xb4!\x8b\x13\x98\x90\x85\xc1\x16\xf4U\x0c\xe8+\xd9\xcfW3\x9f\xafj=68\x16\x1b\xcf?\xc1v\x023\xe1V3aE3\xb18\x81\x99X\x18l&\xacb&\xacd&\xacf&\xacj&6\x9e\x14\x9b \xc3f\xa2\x80\xc9\xcav\xc3\xadf\xd0\xd7\xba\xf3\x87\xe7zG\xef\xf4\xa3]\xa7\x17\xed:\xf4\xa6\xcbD \x05\xd6\xd4\x13\xd54R\xaa F\x815\x99PM\xbd\x92\xbe\xbd]r$Xc_Vc&\xb9\xaeP\x1f\x84\x03k\xb3\xa0\xda\xfa\xa5\xc4m\xb5\xc9p\n\x83\xf0\x01t\xa2lT\xff\xd3\xfcHR\xd9\xf3\xbb\x92\xa0\xb2\xef\xebM-\x95\xb6\x99\xf8x\x87\x12T\xf8,>\xa5\xe0T\n3{\xedi\xfe\x9f\xe8h\xc2\xba\xbe\x83\x9f\x81u}g7\x93\xd6\xd9f\xf4\x13\xbc\x0c\xac\xefOp2\x99?\xe1?\xd1\x9f\x84u}\x07\x7f\x02\xeb\xfa\xce\xfe$\xad\xb3\xcd\xbe'\xf8\x13X\xdf\xf3\xf8\x13Ua\x14\xa3\xfa\x0b\x1e\xda.\xff\xb4E\xfdq.m_~\x08\xa8\xf9\\W\xe2\xc4!\xa6?%\xd2\xcdb@=\xff\xe6\x11\x13\xb0\x15Q\x9f~\x80S\x89E\xa4\xa7W\x9fRb\x8a\xf3\xf0N?\x14\xe9I\xbe>#\xaf\x8f\x0fa\x8b*\x8d\xb2J \xc4-j5\xaaZyD^\xb1QT\xcc\x97fu\xf7\xf2\xba\xf9\xc8\xb8\xa8\xbbW\xd6\x0dD\xceE\xdd\xbd\xaan\x1e\x91\xd7\xdd+\xea\xe6K\xb3\xba\xcb\x86k\xa2\x96\xd7M\x07\x10e\xfdM\xe3\x01L.A\xd5|\xa0<\x97\xa1P\x80&\xd2@\xad\x02\x00Q\xc9P+\x01\xc0\x142\x94j\x00\xca\xab{\xd4\x9a\xb6\xf00>HoS+\xcc\xd0\x07\xde\x99\xb3\x98\x01\xf0\xe7\xc2'\xb3B\xc8-Ko\xcf\x8a\xa5\x0e_\xa4 \x9f\xcf\x1d\xbb\xaa[\xe4\x99u\xf5B\xe7o$\x10\xfb?!\x84\xc0\xc9+9D^Z\xcb!\xec\x08\x8d\x1c\xe2\xbe@\xc8!r\xf8J\x10\x89\xcf75\xc9\xdc\x9e\xa8K\xec\xf9u\xb3\x84\xce_\xcb#\xf6\x7fB\x1eI\x17 \xe5\x11\xf6\x82F\x9e\xb6\x8eP;\xad\xb0/(t\x06\x85p\xb5\xe8!\xbe\xa4\x83\xf8\xd2\xfe\xe1\xb7t\x0f_\xda;|y\xe7\xf0\xdb\xfa\x86\xdf\xde5\xfc\xb6\x9e\xe1\xcb;\x86\xdf\xd6/\xfc\xf6n\xe1\xb7\xf6\n\xbf\xb5S\xf8*}\xc2W\xe8\x12~[\x8f\xf0[;\x84\xaf\xd2\x1f|\x85\xee\xe0\xab\xf6\x06\xffI\x9dA\xe8\xf7X\xe2\xf7X\xea\xf7\xb8\xc5\xef\xb1\xd4\xef\xb1\xdc\xefq\x9b\xdf\xe3v\xbf\xc7m~\x8f\xe5~\x8f\xdb\xfc\x1e\xb7\xfb=n\xf5{\xdc\xea\xf7X\xc5\xef\xb1\x82\xdf\xe36\xbf\xc7\xad~\x8fU\xfc\x1e+\xf8=V\xf5\xfb\xb6\x80\x88&v\x16\xe7\xf6\x82}5j\xf6t\x8e\x16a\x8c\x0e\xe5\xc7{\xcf\xff\xd2\xf9\x0b\xfd\xe5A\x98\xcd\xc1\xc1\xc8\x8e\xcf\xe7a\xbab\x01\x87\xbf=\x86\x99o1\xcfqI\x92I\xc7\x14U\xdc\xf2\x960esqMAYt\xd2N\xb9\x93O\xa3b\x91\x9aRP\xaa\xa6\x18\x12\xac)U\xd8 V\x9d\x8e\x9dl\xa8\x93\x08\xecK\xe5\xf5e\xe2\xfa\xea\xd2\xc2\x82\xc9\x8c[\x17\xc2\x82a\x99`\x98\x12\x8c*u\x03\xd9\xe7\xfc<\xe6S\x81L\xf1\\\xf2A\xc2\xae\xeb\xcd\xdb?4\xd8u\xbd\x94E\x01\xfd\xc5m@`\xa9C\x17k\x0eb\x17\xddn\xaa\xc5\xe1\x96\x81\xc5\xe1\x16Bi\xcb8\\G<\xb6x\xceQ8!^\xfb\x01+A\xfeP\x80\x05+ \x8b8:m\xe1\xed\x90{(\x90\xd8\xde\x87\xeb\xf4<\x7fD\xbc\xfeJ\xa1\x7f\x1c\x18\xdbg=Lf~\xb2\x1c\xf6\x00\x12\x01;\x01\xcfC\xe0\x07\x00\x1046\x89\x83\xbd\x81C\x08\x1d\x82GJ}\x02\x84K\xdd\x02\x10\xa5\xdd3DDR\xe7\xc8\xd73R\xffPp\x10\x85\x01\xd4\xcd\x06:\xa9\xd3\xf8m>\xe3\xb7\xb9\x0c\xcbA\xe41\x1c\x0ev\x18\xbf\xcd_|Uwa\x81ro\x01\xd0rg\xe1\xe4P\xf0\x15\x98F\xee*\xfe\x93<\x05v\n,w\n\xdc\xe6\x14\xb8\xcd)X\x0e\"\xa7\xe0p\xb0S\xe06\xa7\xc0\xaaN\xc1\x02\xe5N\x01\xa0\xe5N\xc1\xc9\xa1\xe0\x140\x8d\xdc)p\x9bSPt\x0b\x8cvu%D\xee\xbd\x0e{5?\xd12\x10\xf9,\xfb\x9dfS\x9a\x08\xe4V\x99\x99aJ\x90\x90E\xc4c^R\xcd^\xa7!\xb5E\x90==7&\x95\x94\xe7F\xc7\xe8\xe4\xd9|\xfa\xb7\xc6\xeb\xf5\xfc\xe7\xea\x85\xa9@\x15\xf9\xe1S\xae\n\xbd\xa9\"\x7f\xe7A\xfd\x13\xc0\xa1\x8c$H\x1ea\xece\xeb\x89\xea\x0b\xe3\x13\xb2\xcc\xf5\xe2\xe2\x95\xff\xe5\x17\xcb\xeb\x9a\x88\x92\x82\xe5\x04|\nH\x90\xc5H@\xf5\xab0\xf6\x1e\xc3 =A\x808\xdc\xb2\xb5s\xfd#/\xdf\xc6vt\xa8\x19d\xbf\x9dg\xffL\xe8_A\xbd\x03\xa4\xc5\xc3 \xfb@P\xaf\x16\xa3\x0d\x8a\x13\x04\xd4_\x15M\xe0\xc7B+6,\x8f\xb6fU\xa3\xd0\x9c\xb4L\xa2R\xd8\xbc2\xb9Z\xcd,\x91\x8c`\x0d\xd8\x1b\x96\xc9K\x91\x9fhIj\xc7)%N\xf1\x19\xfd\xfcyS\x15\xf90\xff9\xff\xbcy\x92\x8f)\x05\x0f\x889\n\\\x805\n\\\x96q\xf6\x88c\x8b\x02\x17bZ\xbe\xe8\x93\xe7[\x14\xb0\xac\xcb\xa7$\xf7\xe2\x11\xc4{n'(\x1b\xc8\x00\xeeU\x11\xcb\xbf~N\xd6P=\x845\x1e\xa3\xd4Y\x81:\xcfKx\xad\x17\x8f\xc9\n\xcag4\xff\x04\xe1Ee\xd0\x8aE\x06\x07\xac\x97A\x85\xc6\xcb\xf9\xe4\xb6\x03\xb84\xa6jxp\x96\xca9T\x86\x02\x98PF\xc9\xf9@6\xc9\xb94&\x01\xf80\xca\xcf9\xc1\xba/uS\xaa\x1e\xd4\x0e\xa9\xe5\x9c\x13\xa8\xe4\xfbu\x92z\x8b=\xd0q\"\xdby`\xfb\x0d\xf1\xac\"\xac\xb2T\"\xedW8\xb6\xf3\xe4\xac\xa8\xbeS?\x01YsF\xa9Q|\x07\xca9\xb1\xfd\x87|\xc8\xd6\x00\x99\xab\xc2\xccQ\xbaE(\xe0+(\x01L\x0d\xd5S\xb6\x8a$\xb2\x1dT1\x83k\xb2\xf3\xd74\x1eh~\xae\x97\xa4\xb17_\xa7H\xc0\xb2\xa0\xa29\x96\x08\xb6\xf7\xe4A\x0da\xc3\xc29\xda,X1\xa3\xbaP\xc3\xaa\xe9Ar{Ul\xd8~\xd4p\xa2\xba\x91\xcc4\x15\xab\xda4<\xaf\xca\x0c43\x89\x11*\x9e\xac\x11\x1a\x96\x84% \xaer;0=\x95\xb4\x04\xd9Qk\x96P_-\x0e\xdf\xea\xccl\xebz\x81\x8d\x8bh\x9c\x88A\xb5\x1c|\xaeO\xca\xffB\x9c\x0c \xa7\x1e\xcb\xc9(9\x19\x10\xa7\x9e\x84\x93\xc9r\xea\x95\x9cz\x10'S\xc2\xa9\xcfr2KN&\xc4\xa9/\xe1d\xb1\x9c\xfa%\xa7>\xc4\xc9\x92p\x1a\xb0\x9c\xac\x92\x93\x05q\x1aH8\x0dYN\x83\x92\xd3\x00\xe24\x94p\x1a\xb1\x9c\x86%\xa7!\xc4i$\xe14f9\x8dJN#\x88\x13\xb6\x93T\xe6\x9cz\xf6?\x96\xe38\xfb\xdf\x84\xf8\x19\x085\x97Y\xd4\xa7\xcb\xd6C\xe5\xbbm7\xe8\\\x9f\xd4$\xe0\xca*\xe7e\xc8\x96o\x0d/\x83\xe0e\x00\xbc\x92U\xec\x05\x0f\x99d\x15i\x80\x966)F\x81\x00\x05)\x89\x0d\x80\xd8\xa0\x88\x0d\x85\\\xdb\x81\xe7O\xe4\xfd\x88\xc6\x9e\xbe\xa4\x86\x18>\xf7\xaaZc\x0e\x0c/\xbe\xcb\xc2\x1a\xac\xe5\xf8\xb55\xcbFmA\xf6\x9c\xcbk\x81\x04\xadK\xafgZa\xe7\xd5W<\x8e^d\xf3\xd4\xa7\xad\xb3a)\x9e\xba\xd4>\xcd\xb8\x7f\xcaj\xfbT\xab\x7f\xbf\x057+\xd1\xf3\xae\xb9a\xee\xcf\xb2\xec\x86Y?\xe3\xca\x1b\xae\xe0\xb9\x17\xdf\"\xfd?\xd7\xfa\x9b\xeabOY\x82\x8b\x18\x1d\xbb\n\x17\xf19a!.bu\xdaZ\\\xac\xa9\x13\x96\xe3\xacY\x9f\x7fE\x0e\xd6\xf0|\x8br\x90\xfd3\xaf\xcb\xc1:\xbe\xd3\xd2\x9c\xb2\xee3\xad\xce)\x9eO^\xa0\x0b\xb8\x9d\xb6F\x170;u\x99.`\xf7\xc4\x95\xba\x80\xeb\xd3\x17\xebB\xc3\x1c\xbb^\xe7\xe7\xeb',\xd9\xe5\xcc\x8e\\\xb5\xcb\x99\x1d\xb9p\x973;r\xed.gv\xe4\xf2]\xce\xec\xc8\x15\xbc\x9c\xd9\x91\x8bx9\xb3#\xd7\xf1rf\xc7/\xe5[\xfc\xf6\x89\xaby\x96\xfb\xe2i\x0bz\x90\xddS\xd6\xf4T\xf7?aY\x0f\xd3\xb3+{\x85\xa5\xbd\xc21\x9a\x9c\xa7\xff\xcc\xcb}\x9e\xdf\xb3\xaf\xf6\xfd?c\xb1\x0fTr\xc2Z\xdf?a5\xf8\xacK}P\x80\xd65\xdfs\xad\xf4\xfd\xa7,\xf4Y\xe2\x13\xd7\xf9\x90\x0cO^\xe6\x9fb\xd7?g\x95\x7f\x9a\xc1\xbf\xe3\"\xdf\xff\x9ek|\x88\xf9\xf3,\xf1!\xce\xcf\xb9\xc2\x87\xf8?\xfb\x02\x1f\xd6\xfd\xb3\xad\xef\xfdgZ\xde\xc3|\x8e^\xdd\xc3lNY\xdc\xc3\x9cN\\\xdb\x8b\xb4t\xca\xd2\xde\xff\xde+{\xa0\x82g\\\xd8\x03\xdc\x9f{]\x0fT\xf1\xbd\x96\xf5\xfe\xf3\xaf\xea\xfd\xe7\\\xd4\x83\xccN\\\xd3\x83\xbcN^\xd2\x83\xdc\x9e\xba\xa2\x07\x99>\xc3\x82^`\x93\xa3\xd7\xf3\xec\xcc\xfc\x94\xe5\xbc\x8c\xd7\xb1\xaby\x19\xafc\x17\xf32^\xc7\xae\xe5e\xbc\x8e]\xca\xcbx\x1d\xbb\x92\x97\xf1:v!/\xe3u\xec:^\xc6\xeb\x84e\xbc\xd4]\x9f\xba\x8a\x97\xae\xae\x8e^\xc4K\x17\x84'\xac\xe1\xfd\xa7-\xe1!\xf2\xe3V\xf0\xa2\xc5:~\xe6\xc5:\xcf\xef\xd9\x17\xeb\xf8\xcfX\xac\x03\x95\x9c\xb0X\xc7',\xea\x9eu\xb1\x0e\n\xd0\xbav{\xae\xc5:~\xcab\x9d%>q\xb1\x0e\xc9\xf0\xe4\xc5\xfa)v\xfds\x16\xeb\xa7\x19\xfc;.\xd6\xf1\xf7\\\xacC\xcc\x9fg\xb1\x0eq~\xce\xc5:\xc4\xff\xd9\x17\xeb\xb0\xee\x9fm\xb1\x8e\x9fi\xb1\x0e\xf39z\xb1\x0e\xb39e\xb1\x0es:q\xb1.\xd2\xd2)\x8bu\xfc\xbd\x17\xeb@\x05\xcf\xb8X\x07\xb8?\xf7b\x1d\xa8\xe2{-\xd6\xf1\xf3/\xd6\xf1s.\xd6Af'.\xd6A^'/\xd6AnO]\xac\x83L\x9fa\xb1.\xb0\xc9\xd1\x8buvf~\xcab]\xc6\xeb\xd8\xc5\xba\x8c\xd7\xb1\x8bu\x19\xafc\x17\xeb2^\xc7.\xd6e\xbc\x8e]\xac\xcbx\x1d\xbbX\x97\xf1:v\xb1.\xe3u\xc2b]\xea\xaeO]\xacKWWG/\xd6\xa5\x0b\xc2\x13\x16\xeb\xf8i\x8bu\x88\x9c[\xac3\xf4\x87\x05\x0e\xed4\x7fG\xce\xe4\x0fz-\xcc@\xe3\x12\x9a\xbf1\xa7\x05\x1b\x94\xd8\x93\xde\x82\xb4\xc8\xdf\x82\xa4.W\x83V\x12\xad\x81+\xbcYH\xfd\xfc\x81\xe6\x1f#\xb2\x7f\x94\xc4\xbe\xba\xc0\xb0l\xc7\x98\xb9\x06\xab\xc9\x86)\xd9\xa8\xd2\xc4\x0e\x12-A\xb1\xb78,\xc2 \xd5\x16\xb6\xef\xe1\xfd\xb9fG\x11FZ\xb2OR\xe4\x9f]`/x\x98\xd9\xce\x87\xfc\xd7\xd7a\x90\x9e\xd9\x1b\x14xq'@\xbb\xea\xe7\xb3\x15\xc2\x1b\x94-r\x9b\x9f:\x01Z\xa3\xb3\xf5|\x1d\xa4\xeb\xb38\x9c\x87ix\x16d\xff$h\x19\xa2\xce\xda;\xb3c\xcf\xc6g\x8d\x14\x8ct\x9c`K\x14\xc6K\xcf>\x83\xc0\xb9t\x9a\xa0E\xc2*J*\x9e\x80\xc7:\xa1\x8b\xa8\xf7\xa0e\x0f(\xa2Wa\x90\x84\xd8N\xce\xfc0\xb0\x9d0\xfbO\x98G\x13,\xa3u\xec\xa1\x98!\xcd\x9fun2\x95\x96\x00\x11}\xad`\x8a\x03\xa3\xf6\xc6\x1e\xa2\xb6\x17\x86\xa3x\x00v\x15R\xa7+\x84\xed\x84&/\x9e\x9dI\xccT\x16\xa9Z5\xf5|D\xd7\x91?\x81\xa0\xf3\xd0\x0d\x03\x8f\xc2^\xe4\x8f:\xb3\x8f\x10\xde\xb1\xb1\x97\xa4!m\x85\xe2\x99\x80bi\xc7\xb6\x1f\x06.-|\xf9\x10\x14\xc9N\x1eP\xbc\xf10\xa6\xfd\x84x\x0e\x91\x95\x8d(>\xa1\xe5\xa56\xf6\x98\x0f_/\x12\xad\xc8\xc3\x91\xc0\xe2\x89\xc2`I\x8f=\xf9;\xafT\xebc\xb0e\x95\nu*\x0c\xd0^6\x88\xaa\xca\xe1\x1f-\x06X#V\xaf\x11\xd25\x8d%M\xb2-r\xc8}\xee\x93\xefT1\xf7E\xf8\xc5\xd6\xa0\x00\x06\x0f\xe8Q\x80\x1e\x0f0)\x00\xf7y\xfa\xc5\xb6/\x17q\xb1\xb5(\x80\xc5\x03\x06\x14`\xc0\x03\x86m\xcd\x1cQ\x80\x11\x0f\x18S\x80\xb1~\xfc\x9b\xba\x19\x8f\x15Z\x84E@Fa1\x90]X\x0cd\x1a\x16\x03Y\xa7U\xe2E\xf1\xb9\xb36\x1b\xb1\x18\xc8L\nm\x1f\xb1\x18\xc8X,&\xb3\x97\x82\xc1\x14F\x05\xba\xbf\x8b\x8d\xe8\xb7\xb5\xc3` \xa0 \xfdv\x0b\xfa\xed\x06l\x11v\x91\x7f\xed\xac\xd5|~\xbb\xf5Z\x1b=b \xa0\xed\xfc#M'\xb6R\xdb\xe0\xc7\x00@+\xe1v+\xe1v+\xe1v+\xb5\x08\xbb\xc8?v\xd6j%\xdcn\xa5\xd6F\x8f\x18\x08h%\xcc[\x89\xc2xA\xb4N\xb5\x18%\xa8\xb9\xdfnG\x11\xb2c;p\x8a/qN4?|d\x1f2&Z\xa7i\x18\x14l\xce\xcfs\xfc\"t\xd6\x89\xe6\x05\x01\xfb\x16`\xa2F\x1eZ~\x86\xed\\\x9fD\xb6\xebz\xc1\x92]\x18\xaf\x8cC\xb9\xd1\xca\xbf>y\xd5\xab\xca\xf8\xd7\x19\xaf\xcc\xaa\xac\xcf\x97\xf5\xab\xb2\x11_f\xd5\xf5\x0d\xf8B\xadW\x17\xf7\xac\x17l\xa1\xa5W\x85\x16\xfb\xa9\xe5\x956\xac)\x87<\xa5\xa1\xd7\xa4\xfcg\x9a\xf3\xcd\xe6\x1cBl;\xf3\xb0\x0d-\xddf\xc5\x15\x93\xf2\x01\xc5\xa4\x84@1-#\x0b\xc8D\xdb@R\xb2\xc0U\xf1\xce\xb9\x12\x90\xfd\xcc\x96{\xc1\n\xc5^ZA\xca_\x15\xe6\x89\x03\xe39\xd9t#q\x1e\xa2\x18\xf2\x1f\xa2\x18r!\xa2\x18\xf2\"\xb2n\xd8\x91\xc8\xea!_\"\xcaAw\"\xcaa\x8f\"E\x10;U\x86j\xf7+JX\xd0\xb5(qA\xef\xa2\x04\x86\x1d\x8c\x16Y\xecc\xbc\xd0\xb0\x9b\x11\xfc$\x9eF\xa0*gS\xf06\x85\xa8d\x95E\x132\x0f\xf4\xa5\x0e\xe8K\xfd\xcf\x97\xba\x9f\xdf\xe6}\xbe\xdc\xf9|\xb9\xef\xf9-\xae\xe7\xabx\x9e\xaf\xe2x~\x9b\xdf\xf9mn\xe7\xb7z\x9d\xaf\xe6t\xac\xbc\x02\x9f\xf3U\\\xce?\xce\xe3`\xe7\xc2R\xe7\xc2R\xe7\xc2R\xe7\xc2R\xe7\xc2m\xce\x85\xe5\xce\x85\xe5\xce\x85[\x9c\x0b\xab8\x17Vq.\xdc\xe6\\\xb8\xcd\xb9p\xabsa5\xe7b\xe5\x158\x17Vq.\xcc9\x17\x05Lc\xdby@\xee\x01\xa34E\xb1\x96D\xb6\x93E^]\x83\xfb>E\x01\xd4\xd2\x8c\x19\x0b\xd7\xba\xba%\"\xf0\xd1\xd2\xe6\xd8\xf72x\xfb\xb8z\x009\xe6\xdf/:F\\\x80\xa2Mb\xa8\x92\\h\x05\xa9\x15f\x83\xba\xaac[\xc2\x11\xb46\x84\xafB\xa1\x1d\x12\x91\xf1\xb1\"s\x04\xad\"\xf3U\x14\"S\x14x\xa5%!\xf6\xdcC\xbe\x8f^u\x16\x0e\x93z)F4\xa6\xdb\xb38\x98\x13F{\x06e)\x98\xfa\x00\x8a\x94;O\xbbT\x1cL$\x18\x0f\xb4\x9e\xc9\x0fk\x89}%\x81}EyY\\\x9b\xb82\xc9\xb0\x92dXQ2\x16g\xb1^\xe5\x05\x0f\x87\x14\xedR\xcdEN\x18\xdb\xe5 Vv\xd1\x9b\xc1\xce\xb8'\xe7\xb6\x93z\x1b\x04\x14\xe4\xcb\\\xe0\xf9*\xdc\xb0k\xe4\xfc\xb9\x80\xff\xc6K\xbc\x145o\x1cMc;H\xbc\xea\\g\x18w\xba\x86\x95t\x90\x9d \xcd\x0b&\xd2R\xbe=\x85\x90\x87p\x9df*:7\xa2]\xc7\x0d\xd3\x14\xb9\x1dg\x1d\xc7(H_eLX\xba$=d\xff\x14Yn-\xddGP\x8e\xc0\xdf\x16\xab\xc1\xda\x15\x81\xd9zk\x90\xe5\\,\xe1o{D9\x1f\xc6\xf8[\x93(\xe7\x03\x19\x7f\xdb'\xca\xf9P\xc6\xdfZd\xfd|0\xe3o\x07\x04\xc0\x84$\x18\x92\x12@U\x8c\x08\xc0\x00\x92qL\x00\xc6\x90\x0c\xc5+\xd4\x1b\xd0I\x9b\xf1\x859\xf2\x85\x93\xdc\"\x0c\x042\n\x0d\x01\xedBC@\xd3\xd0\x10\xd0:\x8c,\xa0\x81h\x0cl#F\x1a\xd0L4\x06\xb6\x14\x8d\x11\x1b\x8b\xc6)\xec\xf6\xab\x8e\xdd\xa5\x15\xfdV#\xfa\xad6\xf4[M\xe8\xb7Z\xd0o5\xa0\xdfn?\xbf\xdd|~\xbb\xf5\xfcv\xe3\xf9j\xb6\xf3\x8f3\x9d\xd8J\xb8\xd5J\xb8\xd5J\xb8\xd5J\xb8\xd5J\xb8\xd5J\xb8\xddJ\xb8\xddJ\xb8\xddJ\xb8\xddJX\xcdJ\x98\xb3\x12\x05\xdb\x1a\x07\x91Z\xb7\xbd\x83H\x9f[\xf3 R\xe4\xb6\x7f\x10ipk\x1d\x84\xaa\xcb<\xa1*e=`\xab\xf5\xaa\xb2\x1ePVq\xe5\xd6\xd0[\xcd\xac\xe8L\x9e\xce\xac\xda`\x9a|Y\xd5\x08\xb3\xcf\x95\xf5+\x9e}\x9e\xa7U\x95q\x0b\xf6\xad6\xa8\xca\x06|\xd9\xb0*\x1b\x02eU\xfb\xb8U\xfeV\x1bUt#\x9en\\\x95\x8d\xf9\xb2,\xe0\x10\xf5\xb7\xad\x96\xae\xbc\xd8\xad\x95\xd35\xb3\xff\xf1\xa0mX\x00\x93\xaaY\x83\xee`0\x18\x0c9d\x9e\xc7.0\xf9b\xbc}\x80?0.\x9aM\x13b/mJ!GmJ!_mJ!w%\xea\x85=\x96\x00@NKH\x06\xf9-Q\x0c\xb9nS\x0cz/Q\x0c90Q\x0c\xf90\xa1\x16\xc8\x8d\x9bb\xd0\x93\x9bb\xd0\x99\x9bb\xd0\x9f\x89b\xc8\xa5 \x9b@^\xdd\x14\xc3\x8eM\xdaD\xe0\xdb\xa4\xeaZ\xdd\x9bh\xab\xcc\xc3\x1bX\xee\xe4\n^\xae\x10\xc6\xe4\x01\x8a\xc4\xf3}\x99\xe3\xfb2\xbf\xf7en\xef\xb7x\xbd/uz_\xea\xf3\xbe\xd4\xe5}\xa9\xc7\xfbR\x87\xf7\xa5\xfe\xeeK\xdd\xdd\x97z\xbb/uv_\xea\xeb\xbe\xd4\xd5}\xa9\xa7\xfbrG\xf7[\xfd\xdc?\xc2\xcd}%/\xf7\xd5\x9d\x1c\xf6g,\xf3g,\xf3g,\xf3g,\xf3g\xdc\xe2\xcfX\xea\xcfX\xea\xcfX\xea\xcfX\xea\xcfX\xea\xcfX\xea\xcfX\xea\xcfX\xea\xcfX\xea\xcfX\xea\xcfX\xea\xcfX\xea\xcfX\xee\xcf\xb8\xd5\x9f\xf1\x11\xfe\x8c\x95\xfc\x19S\xfeL!\xc2\x0d\x8a\x178\xdcj\x1b/\xf1\xe6\x18\x1d\xaa\x07\xe7\xe5\x03\x01|\xe5\xb9.\n\x1at\xf1\xbb\x00\x9c8q\x88q\x03.~\x17\x80\xf3H\xaa\x86\xf2;\x1b5p\xc7\xc9\xac\xedZ\xa4\xde\xb1rk;\xb9\xe4;Vvm'\x97~G\xcb\xaf\xedd-\xd8\xf3-\xd8\xb7\xb4`\xcf\xb5`/o\xc1\x9ek\xc1^\xde\x82=\xd3\x82\xfdi\x01-\xebXY\xe8p\x94oQ\x04\n\xeeE\xe1[=\x8cB\xab8\x19I\xa0\xecg\x0c\x91\x92\xab14\n\xde\xc6P\xa88\x1cE\xa2\xeas\x0c\x91\x92\xdb14\n\x9e\xc7P(\xcc\xc1\xaa\x81&\xe7\x92\xfe\x91\x1e\xe9\x1f\xe7\x90\xfe1\xfe\xe8\x1f\xe9\x8e\xfe \xde\xe8\x1f\xef\x8c\xfe\xb1\xbe\xe8\x1f\xed\x8a\xfe \x9e\xe8\x1f\xef\x88\xfe\xb1~\xe8\x1f\xe9\x86*\x1e\x87\x8f\xf48|\x9c\xc7\x1d3\xc7\x92`%\x8f\xc3'x\x1c>\xde\xe3\x8e\x9dki\x02%\x8f\xc3'x\x1c>\xde\xe3\x8e\x9dsi\x02 XKR;\xf5\x9cCq\x055\xcc\xdf\x8d\x91\xb2\xb7Ob\x84\xf3;\xa2\x0d\xaazB\xe3\xecy\x12\xe2uJ\xe0\xaa'4\xae\xf8\xa8~\x0d\xca\x7fU\x18\x8e\x0f\x80\xe0\xd9\xc8\xae$;\x05\x94\x8bOA%-\xa0pE#\x14Z\xa10\xa9\x94M\xf3\x15[\xe6+7\xccWk\x97\x7f\\\xb3\xc4-\xc0\x8a-\xc0\xca-\xc0j-\xc0\\\x0b\xe8N\x92'r\xc3\xc8v\xbct\xcf\xbdu@\x1b7e\xdd1[8\"\n\xd9\xbb\xe9\xda\x90(d/\xc1k\x03\xa2\x90\xbdm\xafYD!{\xad_\xeb\x13\x85\xec\xfb\x034\x93(d_T\xa0\xf5\x88B\xf6\x8d\x08\x9aA\x14rJ\xd0\xad\xa6P\xe7$\xd2{d1{0\"\xd4\x1a\xce\xccy\xfb8L\xed\x14i}\x8b>o\xb0\x08c\xff\xbc(\xfb\xb1o\xb9h\xf9\xd3D\xf0\x1cd7\xd6\xc5\xec\xc6:\xcc\xaex\x0e\xb23L\x89x\x86)\x90\xaf,\x809\x8e$\x12\x1a#\x81\x88e\x01\xc8\xb1\xd7\x93\xc8\xd8\xeb d,\x0b`\x8eC\x89\x8c\xbd\xa1@\xc6\xb2\x00\xe4h\x1a\x12\x19MC cY\xa00\x96\x1e`\xd7\xd2\x88\x0f\x1c<\x8fwI9\x9e\xe6`R\x96\xa7\xfa\x98\x9c\xe9\x89n&ez\xaa\xa7\xc9\x99\x9e\xe8lR\xa6\xad\xfe\xa6\xe0p\n\x93w\xe3\x85\xfes;\xa1\x84\xe1\x89>(\xe1x\xb2\x0b\xcax\x9e\xea\x81\x12\x9e';\xa0\x8c\xe7\xa9\xfe'\xe1\xf9D\xf7\x93z\x1a~nO\x930<\xd1\xd3$\x1cO\xf64\x19\xcfS=M\xc2\xf3dO\x93\xf1<\xd5\xd3$<\xdb=\x8db:\xc7\xb6\xf3\x90EP\xf9y\xce\xf3x9\xb7\x7f\xd4\xcf\xb2?\xdd\xf1O\x10t\x04AG t\x08A\x87 t\x00A\x07 \xd4\x82\xa0\x16\x08\xedC\xd0>\x085!\xa8 B{\x10\xb4\x07B\x0d\x08j\x80P\xdd\x02\xa0:\xdb\xae\xed\xca+\x02\xde\x02\xbbJp\x8e}qf\xe8\xfa\x0b\xded\x05|$\x82\xb3f+\xe0C\x11\x9c5]\x01\x1f\x88\xe0\xac\xf9\n\xb8%\x82\xc3M\xed\x8b\xe0\xac\x19\x0b\xb8)\x82\xb3\xa6,\xe0=\x11\x9c5g\x017Dp\xd0\xa4%\xf6\xaf:{\x93:@v\xacQ\x10\xc3`V`\xae\x1d?h\xcb\xd8\xdeW\x08\xd3dVw\xbe\xe7R\x00\xcbb\x96ad\xe1p\xc8\xacG\x13\x0foP\\\x15s\xefB\xc3\xf95\x0b\x1ad\xdb6#A\x18\x06\x94\x08\x8e\xe3@lH\x08B\x08\xd0E\xae\xdd\n\xb2\xe8g\x7f\x00\xf5\xd7\x80\xc5\x02PV\x8c\xdc\xba\x92\xa1\xde\xd7\x19\x0cQ\xbcX\xf4\x0ds\x00IJ\x81\x86=\x8biN\x18\xdb\xc1\x92\x10c\xc0]\xe9_\x86\x98\xe00\xe7\xae\xd9\xef\x11\xc6\xe1\xb6Dd`H\n\n\xf4\xd7\xc5|a\xd8\x8cy\xa2u\x1c\xe1Z\x10\x0b\xf5\x1c\x9b\xbd\x9c\x90s\xa2qv\x7f`.z\x80\xea\"/\xa8=\xd1\xb5t}\xc4\xe8n\x15\xa6\x14&S\xe0\x9c\xb1\x10]>\xd2aW\xa0Q\xb6\xe9\x0eA\xb7G(\xa8{\x869\x1cZ=\xd6\xb3I\xc0\xd8\x1e\x0f\xfb\xb0\xdf\x11\xb01Bs\x87iW`o\xf6M'5\xe6\xfd> \xcd\x1c\xafQ\x03\xea\xf7\xc7\xec\xcb\n\x88r\xd3\x1a\"\x17\xb4)\x89\x1a\x0f\x1c\x87u\xe1\x1c\x85\x12\x1a\xe8\xb8\x88\x03n\xedd\x85\\\n\xb6\x18,\x16\x0b\x04\xc2(\x15\xa0\xd1\xc2]X \x8eq\xb9\xc5\xc2As\x10H\xf5\x10w\xe1ro'\xc3a\\_\xb1/\x80\xd5-AZkK\xad\x8e<\xe6\xb6\xf3\xb0,\xde\x91ZPH\x83\x90\x8ap\xd4B\xc8\x85$\x15\xe1\xb0\x85\x90\x0bP*\xc2A\x0b!\x17\xaeT\x84V\x0b!\x17\xbcT\x84\xfd\x16B.\x94\xa9\x08\xcd\x16B.\xb0\xa9\x08{-\x84\\\x98S\x11\x1a-\x84\xdc\x0cY\x11\xea\x96\x9c\x90\x0b\x81\xe6K\xad\x8e\x828\xca\xb6\x80\xa8&\x86\xdc\xa7-<\xaa\x89!\x17j\x0b\x96jb\xc8\x8d\xdaB\xa7\x9a\x18r\xa5\xb6@\xaa&\x86\xdc\xa9-\xac\xaa\x89!\x97j\x0b\xb2jb\xc8\xad\xdaB\xae\x9a\x18r\xad\xd6\x00\xact/\x9e\x92\x0f\xc7\xe6K\x8d\x88\xc8x\x02.8\x9b/\xb5&>\xe3\xf1\\\xa86_ju\xb4\xc6\xc3\xb9\xc0m\xbe\x14A\xb90n\xbe\xac\x824\x1e\xcc\x05u\xf3\xa5F\xc5u< \x17\xe2e\x92\xd7Q\x1e\x8f\xe7\x02\xbe\xba\n\x01\x01\x17\xfeU\xba/\x02<\x9e\x00\n\x06+\xc7\x80\xe0\xect9_\x16+\xe4\xc8\x8eQ\x90\xf2\x14D!l\xe3l\xc2\x03\xda\x01D\x98\xf3\xa5\x00\x0c\xc5\x9b\xb5\xa2D$|\xf49_je\x00\n\xe1\xf9X4s\xa3,\x1c\x85\xd0|d:_VA\x00\x87\xe7\xe3\xd4Zz\x11 \x18\xb5\xce\x97U@\nt\x02 \x86\xadk\x11RA\x11me\xb8<\xd4\xe4I\xa0\xf8v\xbe\xd4\xea\x10\x176\x1f\x1b\xedfM\x11\xa1\xf9\xd8\xb7i\x88\x88\x86\x8f\x84\x9b1&\x8b\xe0\x80A \x88\x8b\xf3\x81C\x00\x07\xa2d\xa2\xb3\xc2DP\xcc\x9cu\xd8,l\x86\xc6U>\x82\xaeZ\x91\x87\xab\x10 \x10O/Eh(\xba\xae\xdb \xa0\x81b\xed\x8a\xa6\x0e\xb7\x81\x81\x0d\x88\xbc\xb3a\x87\x08\xbe\x013\x02qxC$R2\x14\x957T\xe2\x0e\x06\xc4\xe8\x0d\x99hT\xe1#\xf6\xf9\xb2\x0e\xd79\x020r\xcf\xef\x97\x17s%t\x07\x9d,\xce\x7fn\xd6N\xec\xbb\xd7rd3\xf3\x8a\xb9\x11\x18\x8a%71\x17\xf0zn\x16sl \x14Cn\xe6.\xd0\xd5\xe4-\xe6W#(v\xdc\xcc^\x80\xe5\xacx6\xdc\xac_\x00\x8bY\\\xcc\xa8,\xa7Xq1A\x01%\xc3\x021C\nE\xb1\xe5\xe2\x86R+U\xe8 Q\\\x0d\xa1\x18r\x81\x05)\x81\x9c#\x81\xa1Xr\xa1\x07\xe1[y8\xd1\xe2\x7f\x05\x86b \x05'\x05E\x0bC\x88\x17;\xdc\x10\x1dI\x1b\xeb-]-C\x90\xecd+h\x92l\xd4\xcax$f\xcc.\x8fH\xb2a+\xe3\xa1\x981\xbbt\"\xc9\x06\xad\x8c\x07b\xc6\xec\xb2\x8a$\xb3Z\x19[b\xc6\xec\x92\x8b$\xeb\xb72\xee\x8b\x19\xb3\xcb1\x92\xcclel\x8a\x19\xb3K5\x92\xac\xd7\xca\xb8'f\xcc.\xe3H2\xa3\x95\xb1!f\xcc.\xf1\x88\xae$\xed 5\x82d\xdc\x96' Ie\x9d\xa4F\xc8\x98\xc3\x1d\xa5J%\xb41\x1f\xca\x99\xc3\x9d\xa5J5\xb41\x1f\xc8\x99\xc3\x1d\xa6JE\xb41\xb7\xe4\xcc\xe1NS\xa5*\xda\x98\xf7\xe5\xcc\xe1\x8eS\xa52\xda\x98\x9br\xe6p\xe7\xa9R\x1dm\xcc{r\xe6p\x07\xaaR!m\xcc\x0d9s\xb8\x13\x95\x81\x9e\x98w\x05 Y\xcb\xa2\xc3e[HW#\n\x8e\xd0\xd2\x00\x0c\x17\xa9\\\x8d\x94=\x174\x02\x8b\"8~$\xd3;\xd2*\xd8(\x12X\xb2\xc0\x01%\x91\x10\x92V\xc0\x84\x95\xc0\xb2\x19\x8e0\xcb\x0c\x92\x94\xb7\x94\xaf \xe4\xac\xd3MR\xceT\x84\x08,\xc9\xe0\x18\x94\xc9NIk\x00\"Q 9\x00\x07\xa5dJK\xae|&4\x05V\x89p\x94J%\xc1\x14\xda!\xadC\x10\xb6Ry\xb3\xf6~@\x06\x9c\xc0\xbaP\x18\xc7V\xa96i\x0d-\xcc\x05\x81-\x95\x98\x93\xf2'q\x82Z\x84i\xbc\x9a\x89B \xbddci\xae\x1a\x85\xb0z\xa9\x12Y/\xd9\xe0ZZ\x93 \xce^\xaa\x84\xdaK6\xda\x96\xd6$\x08\xbc\x97*\xb1\xf7\x92\x0d\xbf\xa55 \"\xf1\xa5J0\xbed\xe3qiM\x82\xd0|\xa9\x12\x9d/\xd9\x00]Z\x93 V_\xaa\x84\xebK6b\x97\xd6$\x08\xde\x97*\xf1\xfb\x92\x0d\xe1\xa55 \xa2\xf9\xa5J@\xbfdcziMpdBl\xf6\xb5\x8fA\x92\x9e\xab\x16\xef\x13\xbb\x83\n\xb5\x89{\xaf\xda\x02\x80\xd8NT\xa8M\xdc\x83\xd5V\x04\xc4\xfe\xa3Bm\xe2^\xac\xb6D 6,\x15j\x13\xf7d\xb55\x03\xb1\xc3\xa9P\x9b\xb87\xab-\"\x88-Q\x85\xda\xc4=ZmUA\xec\xa1*\xd4&\xee\xd5j\xcb\x0cb\xd3U\xa16q\xcfV[wT;l\xe2\xaajDQO\x15\x14\x01\xdbo\x05^\xca\x8c\xe3\x03\xed\xcc\x15\xd0zsN\xcc\xad\x810<\xf9\xad\xbb\x82\xa0\xd8\xbd\x133,\xcb\x19n\xfc\xc6^\x81^\x86X\"\\^\xcap\xe27\xfd\nl\xb1\xc7 \xe6U\x96\x93\xdc\xf8-AR'm\x0c)\x14-$\xb0mX\xd0\x14{\x80b\x9ee9\xc5\x0d\xdaT$%h\xe3I\xa1(\xce\xd0\xc6#\xe1\xb0\x91\xe0\x05\xbd,\x84\xe2 \x9f\xbc\xcb\x08\xaa\xcdI1\xcb\x1a\xc1\xb97\xbbsYjK\xca\x0d\xe2\xc4\xefjR:\x92\xf2#0\x0cW~\xdf\x93PQ\xbec\xd6\xa2\xc6\x02Cq\x85vF\xcbN!g\x08\xf1\x02\xb6M\xc96\xb5p$A\x14_hg\xb5 \xec\x8dd\xcd\x98\x97R\x9c\xa0]WB?s\xbc\x968x\x03ax\xf2\xdb\xb2\x05\x81\x9c\x1d\xcf \xda\xb2%U#\xe7G`h\xed\x01\x9b\xba\x04E\xb5\xaf\xdb\xc2\xb8\x86Q\xbc\xa1\x9d\xdf\x82\x88\xd8\xfc\x15s&A\xb4\xaf\x03\x9b\xc3\x14I\x8b+Q(\x8a3\xb4\x81L\xd1\xb4\x0d\xc74\x8c\x96\x1a\xd8e\xa6\x88\xa43$\x81a\xb8\xf2\xfb\xd0\xa5\x07-\x15b\x02\x12T\xf0\x05\xd2&\xc2\x08\xa18\xa6#\xe5.c,\x0e\x19\xc8#=R\xf6l\xe0\x00U\"\x8a!\xeaC@\xd2\x1a\xa8H\x02b/\n*\xca3CR\xe6Dh\x01\xb1\x16E\x19\xf5\x01#)s\xca 9\xf6\xa2\xb0\x839\x8f\xa4\xa0}y=\x928\xa4>\xc4$\xad\x84\x8a\x19x\xf6\xe2\xc0\x849\xf3\xa4\xd0\x92\x96\xaa\xc4\x91\nyP\xaa\xbd\xb3\x11\xb37_\x898t!\x8eVI\xeb`\x02\x18\xb8\xdf\xc1\xb1Ly\x16Kn\x0f9kQpC\x1d\xdcR\xb1\x85\xbc\x1aQ\xb4C\x9d\xf5j7\x059\x07\xf0\xd5\x88\xc3\x9f\xeax\x98\xbcw\xcb\x99\x0b\xe3!\xfa0\x99\x82\xae\xe4\x15\x89\x03\xa4\xf2\x00\x9a\xb4\x06\"L\xe2Y\x8b#&\xf2\xb4Z\xbb\x19\x889\x1e\xaaD\x18B-\xdb\xf9KY\x8bc*\xea0\x9c\x82 \xa4\xd5\x88\x83,\xf6\xfc\\{ML\xa8\xc5W&\x8e\xba\xe8Sw\xd2\xaa\xf8\xd8\x0b\xe8\x84\xc20\x8c9\xa9\xa7R\x93\xdc\x85\xc5q\x19{\xbcO\xa5\xae\xb6 K\x18\xa8Q\x87\x02Uj\x92\x07&\x92\xc8\xadu\x17\x99\xc0\x08*\x00\xf7\x94#[?\x08\xbe\xdf\x1a\xd9F]\xd4\xedY\xdc{j#\xbb\xd7\x94C\xc5f]\xcc\xbfY7\xb2\xfbu)\xffj\xdd\xc8\xb6\xeaR\xfe\xdd\xba\x91=\xa8K\xf9\x97\xebF\xf6\xb0\xa9\x97\x7f\xbbn\x84\xeb\x06k\x18-R\xae\xd5\xd8\xa0\xcb\xc1\xa6\xe3\x1e\x03\x820&\x8d\x01\x94\x80\xfb4\x04\xd0\x04\xb6h\x08\xa0\x0e<\xa0!\x80N\xf0\x90\x91\x05PL\xdc(&\xce\x06\x16N3\xb1\xc1\x00@\xd5\xc4=\x16\x05\x81L\x06\x04('\xee3\x18@;\xb1\xc5`\x00\xf5\xc4\x03\x06\x03\xe8'\x1e\xb2\xf2\x00\n\x9a7\n\x9a\x87i\x1a\xfa\x9c\x86\xe6\x06\x8b\x00U4\xefq0\x08e\xb2(@I\xf3>\x0b\x02\xb44\xb7X\x10\xa0\xa6\xf9\x80\x05\x01z\x9a\x0f9\x99\x00E\xa5\x8d\xa2\xd20\xe2\xb4\x94\x1aT1\xa8\xa2\xb4Gc \x88IA\x00\xe5\xa4}\n\x01h&\xb5(\x04\xa0\x96t@!\x00\x9d\xa4CZ\x0e@!\x1bF!\x93\x16?\xda@\x1ab\x89@\xbdm\x00\xbdq\x84\x10\x1d\xafL\x96\x0cP\xf0\x86W0K\x05(}\xc3+\x9d\xa5\x02\x0c\xb1\xe1\x0d\xc1R\x01\xc6\xd9\x00\xc6\xe1\x1a\x06Xl\xc5\xce\x125\x11<6\xae\xc0Y\x83!\x02-\xb6\x82\xa6\x12\x96\x10\xa2\x03\xa6\x17\x86\x0c\xb0\xd8\n\x98q\x18*\xc0b+`\x12b\xa8\x00\x8b\xad\x80y\x89\xa1\x02,\xb6\x82\xa6*\xb6a\xc0\xc7\x85l\xfd\xe0\xdb\xf1\xd2\x0bX\xdb\xf8\xb6Q\x95@\x06\xf0\xed^]\x0c\x95\x9aU)\xf0\x95'\xbb_\x15\x02\x9fU\xb2\xad\xaa\x10\xf8Z\x92=\xa8\n\x81\xaf-\xd9\xc3\xbaN\xa0\xa1\xb8j(\x18\xbf\xf8\xd8\xa0\x8a\xc1&\xe3\x1e\x8d\x81 &\x05\x01\x1a\x8f\xfb\x14\x02\xd0\x00\xb6(\x04\xa0\x06<\xa0\x10\x80.\xf0\x90\x96\x03PH\\+\x04\xec\x9b~l\xd0\xe5\xa0J\xe2\x1e\x03\x820&\x8d\x01\x94\x12\xf7i\x08\xa0\x95\xd8\xa2!\x80Z\xe2\x01\x0d\x01\xf4\x12\x0f\x19Y\x00\xc5\xcck\xc5\xc0\xf3\x8c?7\x18\x00\xa8\x9ay\x8fEA \x93\x01\x01\xca\x99\xf7\x19\x0c\xa0\x9d\xb9\xc5`\x00\xf5\xcc\x07\x0c\x06\xd0\xcf|\xc8\xca\x03((\xad\x15\x04\xc4)~j\x90\xa5\xa0j\xd2\x1e\x05\x81\x10&\x89\x00\x94\x92\xf6I\x00\xa0\x91\xd4\"\x01\x80:\xd2\x01 \x00t\x91\x0e)\x19\x00ElhEL\xe4n\xb3\x01\x143Qp\xa4\x0d\xaf-\x96\x0c\xa2\xe248i\xf5\xb4\x0d\xa7\xd4I\xab\xe7m8=OZ=q\xc3\xa9~\xd2\xea\x99\x1b\xde\x1al\x83\x00\x0b\xad\x98Q\xbf\"\x81\x87\xbc\x154 \xd0$\xa0\x85V\xc0\xc4\xc0\x90AT\xfc\\A\x13\x01\x16Z\xf1\xb3\x07M\x03Xh\xc5\xcf'4\x0d`\xa1\x15?\xc3\xd04\x80\x85V\xc0\x9c\xc34(\xb7P\xfb[-\xe9\xd7\nFv\xfer\xce2\x96\x01\xf2-d\xa9 \xe5BA \x84I\"\xc0\xc4\x0b \x00s/$\x00L\xbf\x90\x000\x03C\xc9\x00&a\x08\x84(\x0f\xc3A\x04\xa9\x18\x1e\x07\xc1L\x0e\x06&d8\x14\x98\x93\xe1P`Z\x86C\x81\x99\x19^.09C\xc2D\xf9\x19\x1e#H\xd1\x00@\x08g\xf280Q\xc3\xc3\xc0\\\x0d\x0f\x03\xd35<\x0c\xcc\xd8\x00\xb2\x81I\x1b\x12'\xcc\xdb\x00 A\xea\x06BB@\x13\x00\x82 \x1c\x00\x07\xe6p\x00\x1c\x98\xc6\x01p`&\x07\x92\x0fL\xe6\x90@8\x9f\xc3\"\x04)\x1d\x0e\x06\xa1L\x16\x05&vX\x10\x98\xdbaA`z\x87\x05\x81\x19\x1eN&0\xc9\xc3)\xaa=\xcf\x03kN1\xd5\x03\xeaS-\xdb\x03)Y)\xe1\x03)^)\xe7\x03\x19C)\xed\x03\x19H)\xf3\x03\x1aM-\xf9C\x92*\xe6\x7f8\x92cR@<1D\x0b\x91\xc2\xd3\x9aJ\"\x88#T\xcd\x05q\x84\xaa\xe9 \x8eP5#\xc4\xb7Q9)\xa4\xe5\xdfs\x8f\xe1\xbc\x10Q(H\x0d\x91\x08\x08`\x12\x000AD\x94\x839\"\xa2\x1cL\x13\x11\xe5`\xa6\x88\xac\x1fL\x165\x00Q\xbe\x88E\x08RF\x1c\x0cB\x99,\nL\x1c\xb1 0w\xc4\x82\xc0\xf4\x11\x0b\x023H\x9cL`\x12\x89@\x89\xf2H\x1cD\x90J\xe2q\x10\xcc\xe4``B\x89C\x819%\x0e\x05\xa6\x958\x14\x98Y\xe2\xe5\x02\x93K\x04L\x98_\xe21\x82\x14\x13\x00\x84p&\x8f\x03\x13M<\x0c\xcc5\xf100\xdd\xc4\xc3\xc0\x8c\x13 \x1b\x98t\"pp\xde\x89\x01\x08RO,\n\x02\x99\x0c\x08L@1\x180\x07\xc5`\xc04\x14\x83\x013Q\xac<`2\x8aUPk>\nT\x98ZJ\n\xd2\xa2RV\n\xd0\xacJb\nP\xb6Jn\n\xd0\xbfJz\n0\x89J\x86\n\xb2\x92R\x92\x8a T\xcbS\xb1\x04G\xa4\xaa8R\x80\x12\"\x04\xe7(\x85\x84\x15K\xa6\x98\xb3b\xc9\x14\xd3V,\x99b\xe6\x8ak\x9b(y\xa5\x90\xbdR\xf8&Kd\xeb\x9a_\xc5fPF\xab)\x14%\xb4\x08\x04\x040 \x00\x9c\xcej\xca\xe1lVS\x0e'\xb3\x9ar8\x97E\xd4\x0f\xa7\xb2|f\xad\xc0\"\x0c\x16!Jd\xb10\x08e\xb2(8\x8d\xe5\xf3\xb1=\x0b\xb2X\x10\x9c\xc4\xf2\xf9\x98\x9d\x05\x0d9\x99\xe0\x14V\x83\x12f\xb0X\x88(\x81\xc5\xe1 \x98\xc9\xc1\xe0\xf4\x15\x8b\x82\xb3W,\nN^\xb1(8w\xc5\xc9\x05\xa7\xae\x1a\x988s\xc5aD\x89+\x1e\x08\xe1L\x1e\x07\xa7\xad8\x18\x9c\xb5\xe2`p\xd2\x8a\x83\xc19+^68e\xd5\xe0\x04\x19+\x1a JX1(\x08d2 8]Ec\xe0l\x15\x8d\x81\x93U4\x06\xceU1\xf2\xc0\xa9*FA\n\x99*Hc\xaa\x89*@\x8f\x8ay*^\xb9ji*^\xe1jY*\xde\x08jI*\xde0j9*\xc0X\x8a)\xaa\x86R5C\xc5P\x1c\x95\xa0bi!R\x88\x12\x9c\xae\x94\xd2S\x0c\x9drv\x8a\xa1SNN1t\xca\xb9)\xb6}\xea\xa9)\xbf\x8c\xd4\xa0\xccT]&JL5\x00\xa8\xdcl\xca\xe1\xb4T]\x0cg\xa5\xeab8)U\x17\xc39\xa9\xa6n8%\xe5\xd3k\x04\x16`0\x00QB\xca\xe7\xc3\x7f\x16d2 8\x1d\xe5sq=\x8b\xb1\x18\x0c\x9c\x8c\xf2\xb9\x88\x9d\xc5\x0cYy\xe0TT\x0d\x12f\xa2\x18\x84(\x11\xc5\xc2 \x94\xc9\xa2\xe04\x14\x03\x82\xb3P\x0c\x08NB1 8\x07\xc5\xca\x04\xa7\xa0j\x948\x03\xc5BD (\x0e\x07\xc1L\x0e\x06\xa7\x9fX\x14\x9c}bQp\xf2\x89E\xc1\xb9'N.8\xf5T\xc3\x04\x99'\xaa\\\x94x\xa2A\x10\xc6\xa41p\xda\x89\x82\xc0Y'\n\x02'\x9d(\x08\x9cs\xa2e\x81SN\xb4b\xda3N\x80\xa2\x14\x13N\xbc\xf6\xd4\xf2M\x9cF\x95\xd2M\x9c\x92\x95\xb2M\x9c\xde\x95\x92M\x9c)\x94rM\xbcu\xd4RM5\x9db\xa6\x89\xc6\x1f\x93hb(\x01B\x88\x0e\x9a{T\xd2L4\x95j\x96\x89\xa6RM2\xd1T\xaa9&\xa6]\xa7\xa5\x98\x04\xd9$\\\x85SP6\xa9)\x14e\x93\x08\x04\x040 \x00\x9cMj\xca\xe1lRS\x0eg\x93\x9ar8\x9bD\xd4\x0fg\x930\x13\xd7\xb3\x08\x83E\x88\xb2I,\x0cB\x99,\n\xce&a>\x16gA\x16\x0b\x82\xb3I\x98\x8f\xb2Y\xd0\x90\x93 \xce&5(a6\x89\x85\x88\xb2I\x1c\x0e\x82\x99\x1c\x0c\xce&\xb1(8\x9b\xc4\xa2\xe0l\x12\x8b\x82\xb3I\x9c\\p6\xa9\x81\x89\xb3I\x1cF\x94M\xe2\x81\x10\xce\xe4qp6\x89\x83\xc1\xd9$\x0e\x06g\x938\x18\x9cM\xe2e\x83\xb3I\x0dN\x90M\xa2\x01\xa2l\x12\x83\x82@&\x03\x82\xb3I4\x06\xce&\xd1\x188\x9bDc\xe0l\x12#\x0f\x9cMb\x14\xa4\x90M\x824\xa6\x9aM\x02\xf4\xa8\x98M\xe2\x95\xab\x96M\xe2\x15\xae\x96M\xe2\x8d\xa0\x96M\xe2\x0d\xa3\x96M\x02\x8c\xa5\x98Mj(U\xb3I\x0c\xc5Q\xd9$\x96\x16\"\x85(\xc1\xe9J)\x9b\xc4\xd0)g\x93\x18:\xe5l\x12C\xa7\x9cMb\xdb\xa7\x9eM\xc2eP\x06e\x93\xea2Q6\xa9\x01@\xe5fS\x0eg\x93\xeab8\x9bT\x17\xc3\xd9\xa4\xba\x18\xce&5u\xc3\xd9$L\xaf\x03X\x80\xc1\x00D\xd9$\xcc\x07\xf9,\xc8d@p6 s\xf1;\x8b\xb1\x18\x0c\x9cM\xc2\\l\xceb\x86\xac{U\x1fl?w\x15\x1fV\x00w\x17\x1f\xd4\x00w\x19\x1fR\x01w\x1b\x1f\xd2\x01w\x1d\x1fR\x02w\x1f\x1f\xd2\x02w!\x1fT\x03}\xe7\x1e\xd6\x01}\xe9\x1eT\x00}\xeb\x1ej=}\xed\x1ej:}\xef\x1ej7}\xf1\x1ej4}\xf3\xbelq\xfb\xc1\xcb\x033f\x90\x17UD\xa3\x1d\x05\x01\x07<\x12\x01\x8ey$\x00\x1c\xf6H\x008\xf2\x91\x00p\xf0\xa3d\x00\xc7?\xf6\x00\xabh\x08\xe4q\xe0(\xc8\xc1\xc0\x81\x90C\x81c!\x87\x02\x87C\x0e\x05\x8e\x88\xbc\\\xe0\xa0H\xc0\xe4\xe3\"\x00\x04\x87F\x1e\x07\x8e\x8e<\x0c\x1c y\x188F\xf20p\x98\x04d\x03GJ\x02\xd72XBHp\xbc\x04\x80\xe0\x90 \xe0\xc0Q\x13\xc0\x81\x03'\x80\x03\xc7NH>p\xf8$\x80\xb2\x11\x94\x83\x81\x83(\x8b\x02\xc7Q\x16\x04\x0e\xa5,\x08\x1cMY\x108\xa0r2)l5\xaa\x9ef\x0f\xc8\x83W\xc2\x81\x96@\xc0\xe3l\x03\x80\x87\xd9\xa6\x1c\x1ee\x9brx\x90m\xca\xe11\x96\xa8\x1f\x1eb\xe9\xfd[\xe1\x08\xcb\xc2\xe0\x01\x96A\xc1\xe3+\x03\x82\x87W\x06\x04\x8f\xae\x0c\x08\x1e\\Y\x99\xe0\xb1\xd5gF\x1b\xd1\xd0\xca\xe1\xe0\x91\x95\x85\xc1\x03+\x8b\x82\xc7U\x16\x05\x0f\xab,\n\x1eU9\xb9\xe0A\xd5g\x07\x18\xd1\x98\xca\x03\xe1!\x95\xc3\xc1#*\x07\x83\x07T\x0e\x06\x8f\xa7\x1c\x0c\x1eNy\xd9\xe0\xd1\xd4\xa7\xc6\x1a\xd1`\xca\xa0\xe0\xb1\x94\x06\xc1C)\x8d\x81GR\x1a\x03\x0f\xa44\x06\x1eG\x19y\x14\x86Q\xc1\x88\x89\xeb\xe1F4b\x12\x08x\xc4l\x00\xf0\x88\xd9\x94\xc3#fS\x0e\x8f\x98M9\x96\xdc\xca\x05\xfajr\xc1\xa8\x10\xa6\x95C\xdb7\x12Kf\xae\x1d?\xb4\xf2\x92}I5\xe3\xf3\x80\x0e)\xda\xa5\x9a\x8b\x9c0\xb6S/\x0c\xce\xb1\x17 -]\xc5\xe1z\xb9\xa2 \xd6\x81\x8b\xe2\xac\x98\xa3\xa9K\x18\xc7\x0b51M\x10\x06Ha\xe9s\x00d\xce\xd6Q'\x88\x0d\x91)H\x0e\x91\xe5\xc2+H\xaf\xb0p+\x9b\xe4\x9f\xd4\"\x9eJ\xa5A<\x95B{\xc4\xa2\xe3\x93D\xe7\xa9TD\xe7\xa9\n\xd1)\x8a\xb4D\xd9\xd8[\x06\xe7YT\xc0\x94\xc7dy>Q2\x00\x87\x048(HQ\xac`\xed\x03#E\xed9bA\x18\x08(\x0b\x83)\xc5Q\x90G\xc1\xfbR\\y\x83DF\xbf]D\xffh aaZ-G#`a0$\x0c\x0d\xaa,\x9c\x7f!~\x11\xc6\xfe\xb9cG^jc\xef\x11\xb1P\xccBq\xb8E\xb1c'\x1cr\xcd\"\xd7Q\x04#\x03\x16y\xd2p\x98\x12\xce\xa1\xd4\x12\x00-n\x0c\x00\x16\xb7\x07\x00+\x0c*\xcan\xda\xb8\x98Z;9\xb0\xa4\x99\x1cV\xd2J\x0e\xab\xd0HA{8\xb7\x92\xb5\xe7\x08\x1f\xe4\xb1\x92\xf6pX`8]h\x833\xe6\xc1\n\xd9n>\xab/\xc2 \x8b\xf5\x1e\xd19\x1fR/4\x8b\xa5K\xd6s\x80\x94\x0f\xa1\x17\x06Ql\xf2\xc5=\xa2\xb8\x07\x05\xea\x0b\x93@\x18@\x90\xbe\xe8S\x00\x88\x85E\"\xf8\xe2\x01Q\xdc\x1d\x0d\x01\x06C\x12Q\x00\xda{\xc3\x81\xd5\xbd\x16$\"\xf5g\x9d\xae\xc5\x02\x005a\x04\x9a\x01d\x07\x1a\x01\x99\x82F\x08\xacA\x83`\x83\xb0\x18\xd0&\x0c\x080\x0b\x8d\x10X\x86\x01\x15\x18\x05\xeb(\x8cU\x99\xc9|\xa1\xc5\xfcV\x83q\xb4\xa4\xbd\xfc6s\xf9m\xd6\xf2\x15\x8c\xe5\xb7\xdb\xcaW0\x95\xdff)_\xc1P\xfe\xb1v\x12\x98\x04\x0bM\x82[M\xc2\xd1\x92&\xc1m&\xc1m&\xc1\n&\xc1\xed&\xc1\n&\xc1m&\xc1\n&\xc1\x80I(\x8c\x8f\xecd\x1d\xa3C\xd3O\xb2\xce\x03b\xb2r\n\xd8\x17\x01\x03;\x8e\xc3-\x01\xedq<\xbd\xc0EAZLi\xc5\xcf\xe7Fs\"+m?\xcf\x98\xf86\xc6\x9acG\xe5\xe8\xb0\xb1c\xcf\x0e\xd2\xf3\xe69\x8dO\xe3u\xe0\xd8):\xe4\xc9\x81<5\x82\xce\x83p\x1b\xdb\xd1$\xdc\xa0x\x91\x7f\x9c\xcfs]\x14Lr\xa9\xea\x87\x08c/J\xbcDa\xcc9\xc0\xeaH\x94\xd5\xcb`[4L\xa3EJ\xae\xe3\xbd'\xea\xb9\x1e\x88UU\x9d\x11\x9c\xaem\x05u+\x0c\xf1\x95\xc2|u\x13\xf8\xc7X\xc0W1\x80\xff<\xfa\xf7\x8fT\xbf\xff\xdd\xb4/Q4VW4>F\xd1XE\xd1\xf8y\x14\x8d\x8fT4~\x8a\xa2)\x96U\xb9\xe6\x84Aj{\x01\x8a\x0f\xf5\xa3\xfdy\xe2\xc4!\xc64E\xb1h\xa6\xb7\x12\xecu\x1aN\xc8\x9d\x96\xec\x01\xa3\xddX\xcb\x1e\xf2t\x0c\x0cS\xb0\x86Y{\xe7<\x00bj\xec\xd9\x1buIARPX\x8d9\xf4\x94\x03\x15\x04V\x18M\xcaV\xf8'7\x02\xa0\x84\xdb\xe0\x1f\xdb\x04\xb1\xb4\xf8di\x01JXZ\x0cHK\x8b\x82\xbd\xe8\x10\x85\x89\x97'\x02\x17\xde\x0e\xb9\xff\xd7\xf3\xa30N\xed \x9d\xfcQ\x97\xd8\xf3$\xc4\xeb\x14\x11\x85\x19\xe9y\x8c\x9c\xf4G#\xdau\x88\xbf?\xd1Eg\xc4\xdf\x9f\x14\xcc}\xe0\x04\xcc\x1c\xe7\xcf\x94QAH\x15\x9f\xcc$\xf7\xff\x83\x04\x17\xc9\x88\xff\\\x19)\x01\xb6\x89\x16\x84\xb1o\xb3#u\xf6\x88F\x16\xa370\xa0\xd3\xb0(\xa6#\xc9(>>'X\x0b\xc5\x07J\"\xb9\xe0\x90\x8a\x13\x8d\x85e\xd2)\x88\xa7\xe0m\x8d\xcclt!\x14\x19\nCx\x89\xfd#\x05\x96\xca\xa6jfp\xe6\xe6e\xc3\xbcl\x14f\xa3\xcd\xed\x04\x1d6(N=\xc7\xc6e:;{\xc6\xef\x91l4\xdfsY\xa8\xef\xb9.\xe6\x80i\x18\xb1\xc04\x8c\xb8\xaaS\x9f\xab9\x0fp\x14\x0c~\x00\x9a\x91\xf9\x8ezK\x00\xb4\xb01\x00\x16n\x0f$B\xd1$\x856)8q\xd9P^o\x92vr`q39\xa8\xa0\x95\"\xbb\x1d\xed\xf8e{\xf01\xed\xe1\xc0\xe2\xf6pPA{\xf8\xfa\xcb\xf6PX\xd7\xf3\x0fad;^\xba?7\xb8\xa23\xf6\x01\xf41\xfa\xecq\xf1\xfdym\x8b\xe6\x0f^\x99\x15/f\x90\x92w\xa7kXI\x07ez\xf1\x82IK9'\x86\xbc\xd6J\xfc\xae\xc5\x13\xdaN\xeamP\x03\x19M\x94d\x0c\xd7\xa9\\\xc8p\xcd\xec\x9e-q\xb8=\xe3\x9e@\x82\xe7\xcf\xbf\xa3\xbe\x14\xea\x15\x18|\x95-\x03\xf3S\x11\x9dn\xfe\x9f\x1a\xa8\xab\xa9\xedXQ\x9b\nKC\x95\xf5\x9e\x89Py\xb3\xda@y\x1b\xd9\x16\x18\xdf\xa7\x05\xcd\x06{^+\xa4w\x16R\x98 _\x7f\xb6\xef\xe1/\xe3p{\xd0\xfc\xf0Q\x0b\x93\x9dVd\x0f\xfd0LW^\xb0<_\xc6\xf6>ql\x8c\xea\xb6\xcdm\xe7aa;H\xdbx\x897\xf7p\xd6\xf2r\xc1+)\xa24\x93of\xe5?a;E\xdf~\xd4\x7f\x9a\x88\x9e\x03\x1a\xe5Xu\xba=A\xa7:\x02z:\xe4\xac\xa5\x16^\xdb`\xd7\x89\xe1.\x9b\xeb$\xb7\xc0\x8fFW\xb7HM\x11O\x81:\xcaaI\xc4\xac;\xe6Yu\xc7\x00#\x0d\xdb\xf1\x12\xfd\x7f\xc5A\xbc\xe0\x18\x1f\xe1\xd1OEI\x9d\xa5\x80\x88L \xf2\x9a\xb2\xb4\xcdwz\x90\xeb\xf4\x84\x06o\xf7\x1f\xc0\x17\xb3\x87L0\x1dzAZ\x8fH\xce:N\xc2\xf8\xbc|H#\x93\x95\xed\x86[\x0d\x02N\xea\xc5b\x8c\xb0\x9d\x89\x05\x99\xdd\xc6\xb8\xd3\xb5\x92\x8e\xb3\x9e{\x8e6G\x8f\x1e\x8a\x7f\xec\x1a\x03\xeb\xac;\xea\x9fu\xfb\xfd3\xe3\xa7\xc9\x91x\xb1\x88\xe7\xf6\"\xcd\x04\x0d\x83\x14\x05\xe9\xf9_\xfe\xd2\xf8\x7f\xb8\xd3\n\xe4\xb9\xde\xd1;\xc6 \xdauz\xd1\xaeC\x9e\xf7\xeb\xfd4Q\x86\xe5\x07;c\xdb\xf5\xd6\xc9\xb9\x17\xacP\xec\xa5\x93f\xd2\xe4\xd6\xd1\x93\"\xf3\x99\xe7e\xf4I\x11A\x1a\xba\xfeb\xb2ByN'\xff\xf91\xcf\x98\xee\xce5\xf9\x9cu\x846Ui$\x1a\xcd\xfd\xbb\xd0\xeb\x99\x18Ej_\x10d\xcc\x97\x9a\x1dx\xbe\x9d\xa23\xc1s\xa8/\x11\xa5\xc2\xd0\x89=\xc4IM\xdb\xec(\xd0\n\xa6\xa5~\xd4\xf4Ce\x17\x9d-2\xea\"\x83-\xea\xd5E=\xb6\xc8\xac\x8bL\xb6\xa8_\x17\xf5\xd9\"\xab.\xb2\xd8\xa2\xf1x\\\x17\x8e\xc7c\xa0\x98*\xe7\x00\xbe\xbdk\xa45\xfa\xc3\xfe\xc8\x1c\xf4\x87,\xaa\xf4\xf2\x1aY\xfe\xce\xc3\xbc\xd4\xb3q\x0d\xe3\xb3\x95\x8f\xda:HP\xc3(\xff\x8d\x86\x04(IQf\xa0h\xaf\x15\x11T\xdeM:!\xb3\xaf,\xc2Ej\xb05>\x10\xbf\x9e\x1b\xecB\xa2\xa4k6\xae \xda\x95\x01\xd6\x01c{G`\xcd#\xb0\xfd#\xb0\xd6\x11\xd8\x01\xa3\x17\xe8`\x7fA\x8f\xbd$\xd5b\x94 \xa1q\x08\xc4\x9a{\xf1\x1c\x99\xaf\xd6'94I\xf7\x18i\xe9>B\xc5\xd1*\xa1%\x8b\xed\xa5N\xf4sDm7u\x8f\xdbo\"9&(B\xb1\x9d\x86q\xce\x94\xe0at-A\xfb=\x7f\xd9\xf1\xfc\xe5\x81\x18\xd2\x9b\x9cG\xfe\xab\xeb%\x11\xb6\xf7\xe7s\x1c:\x0f\x02\x1d\x06\x0fI\xc7>\x94\xe7\xe1Mk\x88\\\x17\x9a\x02\xf8\x01k\"-\x95\xd5\x06\x0d\xb6\x0c\xa2\x9c\xf5\x0b\xa9\xc6\x03\xc7Y,\x9e_\xaamlG\x11\x8a\x05\n\xec\x0f\xf4hW\x1a\xf0\\\xef\xe4\x9b&\xa5\x0b\x9d\xeb\x9d^VH\xcd\xf0\xdecVRN\xcf\xf3p7\x01\x9f\xd2\x12\x84Qn\x1a-\xb5\x97Z\x82\x9cL\xeaCe4\x82ymH\xcdO\xb4\x05F;\xf2Y\xf6;%I\x18{\x993V\x99\x18\xaa\xcc\xf5\xe2\xa2\x9a2%:\xa98\x12%N\x88\xd7~0\x01\x9f\n\xc5\x7f\xba\xd8\xe4 \xe0F,\xeai\xfe\x8b\xe6\xa5\xc8O\xaaG\x95E\x0c=\x0b\x97\xb2\x7f\x8c\xea\x9f \x134\x8aB\xc4^\xc2E\x81\xbddR\x9b,\xef\xb9F\xb4\xeb$!\xf6\xdc\"\x1c\xb3\xc6g\x03\xebld\x9cu\xcd\x9f\x84*)\x9d\xb8\x99\xf5\xa9\x1b\x1e:\x1bj\x93\xca$\x8e\x18\xf5I'\xd4;V\xb4\x9b\xe4\xa5\x0b\xdb\xf7\xf0\xfe<\xb1\x83DKP\xec-&U\x1f\x9e\xf7\x0d\xcb\x10\xf2\xee\x06\xa1\xe6\xa2\xc4\xe9$\x91\x1d\x1cH\x03d\xfa>7j\xd5\x9f\x1b\x93\xe2?BV\x9dd\xb3\x84\x82\xa2\\\x85}^\xab\xfdD\xc2\xca\xb71u\xde\xa9_5t[\xcc\x04}]\x9f\xa8HK\xf4\xd1\xdc \x8eWVd\xc7\xb6\x8fR\x14\xff\xf1G6\x15\x90B\xf5\xa2]\xcd\xdf\x8av\x1d\x9db\xef\x87A\x98o\x10P\x82\x0ft]V\xdb\xc6C[\xad\x9a\x06\x1f\x0e\xfc\xca&\x9b\x04\xcch7\xa9\x0e>\x90\xfe`\xa9{\xb9\xc5\xdb\xc3\x82\xedq \xdc\xcd\xc8j(\xba\x02\xd1\x07\xfe\xaa\xeb:\xb3\x10\xe9\xb3\xc3a\xb3\x921\x99E\x8c1\xe6\x16;\x00\x04\x14\xad\xd3M\xedy\x1e8\xa0\xf8\xe9#\xceQ\x0eOV]\xfc\x9c\x8dC\x87\xc6\xdb\xfa\xfc\x90s\x04\xa3\xf3\x85\x17'\xa9\x16.\xf2\xf0\x83a\xdb\xd1;\xfa\x11\xbc\xbaebs\xd5/:9\xe7S\xa7\xf3*\xd7Y\xfc\"\xb3\xbe\xad\x999L\x1eSY\xfa\x8bj\xb5\xd9kV\x9b\x99\x9f\x00kd \x9b\xf3\xfb\x8f\x9a\xa5\xbf\x00\x13=U\x111\xb4.c{\x0f6\xab\xeb%Z\x18\xa1\xa0\x19n\x92\xb5\xef\xdb\xf1\xfe \x1a\xe13\xef\x16h\xa8fQL\x8a\x95'V\xd6\x1a\x95s\xd0\xc4\xf7\x82*\x82\xb5\xb2\xdf A\xd9\x1b\x83\xa3\x9f\xe0~c\x00\xcb\x7f\x83\xe980\xe6(\xd9\xcf\x8e\x01w\xb0=G\xf8\xe9\x1d\xef\xa4\xa9\xfe\xa8f\x95\x922C79,\x0fu\xbd\x1eG\xb9\xc30'\xcc\x1aJ\x02\x95\xfd\x91\x9a\xa1$\x9d[\xc0j\xd5g'J\x95Q\xadi\xeds4\xae\xe8C\x9a\x8f\xd2U\xe8\xca\xe6\xed\\\xcf\xf5\xd6\xe5H'f\xd0A\x16\xa8e\xe3\x05w\x03\x8c\x99\\L\xba\x0b\xe5\xd3ONC\xf5\x04\x9d\xed+\xf2v.\x16\x0b\xc5F\x86\xf9\xd2,3\x80\xe7\xb6\xf5\x97\x92$\xb2\xd3\xd5\x11\xd0?\xfepQ\x14#\xc7N\x11\xa5\xccAD\xf4\xacS{[n~\xbdq\x08\xbdc\x16\xab\x19\xfa\xb7'w\xd0\xc96\x8c]m\x1e#\xfb\xe1<\xffW\xb31\x96\x85c\xaa\xf1R\xb9\x19N\xec\xe8\x0f\x07\xa3h\xc7l\x81\xff\x07\x9a\xaf\x17\xed\xd8\xd3\x9d\xcal\xd8\xcd:,\xbc\xa6\xab\xd4p\xa6\x8b*r\xc8\x16\n\xb1\x17\xe5\xebR\x82\x81\xa9:\xe4<\xdfH\xf3?4\xe9\x90\xd1\xbeZp\xc7\xc8\xad\x18\xe0\xf7\xea\x00\x9f\x98\x95\x9e=\xb2\xe7\xa4\xab\xf6\xad\x19\x19\xcb\xb0m\xc4,5\xe0\xf8\xaab\x19\x85IJ\xbc\x8f\"3p\x7f\xec8c}\xc2\xae\x80\x87\xe6YO\xef\x9f\x19\xfd\xbe0\\\xa1\xb8\n\xa7\x1drN(\xea:\x81\x19(\xb3\n\x1f\xf5p\xf9h9\xd7\xac&\x17\x8em\x98\xbc&{V\xef\xcc\x18\x18g\xfd\x91\x82&\xd7j\x8a,\xaa:\x9e\x17(\xb1\x02\x9b\xd3\xd4\xa8\xc2\xdeE\x18\xa5\x88\x95kl\"\x13\xf1\x9a\xec\x8f\xcf\x06\xbd\xec\xff\xad\x8a,\xd8\xaa\xe92\xaf\xec$v\xa0\xd8j\x9cN\xd4\xa8B\x0dK\xc4:\xe6\xc0\xb0\x17\x0b^\x9d\xe3\xe1\x991\xb4\xcez\x96B\x17_\"5\xc7,\xaa:\x9e\x17(\xb1\x02\x9b\xd3\xd4\xa8\xc2>\xb2Sg\xc5\x88e\xe9\xc8tz\x9c\"G\xfaY\xaf7<3\xc6\n\x8a\xcc\xd9*\xa9\xb2\xa8\xec\x14n\xa0\xd4J\x8cNS\xa7J\x05\x19WF\xae\xb1n\xf4\x00\xb7\xcc\xa6\x1cc\xa4\xe6\x96\x19W%e\x16u\x9d\xc0\x0c\x94Y\x85\xcfi\xaaT\xe1\x1f\xe6\xb1^\xc2H\xa6\xbb\x96m\x0fym\x9agc\xfd\xcc\x18\x0c\xdb\x95Y\xf2U\xd2gQ\xdbi\xfc@\xc1\x15Y\x9d\xa6U\x95*\x88\xb0\xbe>\x15:\x98\xd0\xa2\xa2y\xf6\x07\xce\x14\x8d{\xc0\xab\xa5\xc4\x95(i\xb9\xa8\xefd\x96\x07Hzun\xa7\xe9ZR\x0b!\xa0\xb3B>J\xb8\xa4\x9c\x1aY\xa7[\xfe\xa0\xa5^\x8aQk\xaef\xe1\xe14kD\xb3\xd6*\x9eh^\x90Eq\xd4\xd6b\x1eI\xe7{T:\xb5oU%\xd8{M\n\xd2\x1d\xb9.b\xbc*\xb5\xe7\xa7\xad\x82\xa8\x9a\x8bex\xdd,b\xe3\x1b\xd8\xf3N\xedy\x07{l\x1a\x8d<\x89N\xf1b\x16,\xc7\xaf\xfe\x8a\xfa\xd8\\8\xb7bbv\xf2\x99\xcf\x96\xf5X[C\\\x85\x89\xecb\xdf\xbe`5\xa8WeF\xb4\xa3\xceK\x11)l\xc1\xfe\x1e\xbb\xbdW\x08Q\xfa\xf8\x81\xc9\x90\x81\xbeI\xae\xbe\xb5r\xaf\x1aLJhh\x97\xa28\xb0\xb1\xe6\x86N\"\x87\xe6^\xfdGy\x13\x8a\xb5+\xbd\xcdX\xbb\xa8U\xa5\xb5\x8f7\xa8\xa4)\xdc\x11\x12ik\x84h\xb2ALf\x14h\xd3\xf3\xb6 :\xa6\x01\x020%\x7f\xc4fR\x9f\x9e\xb3\x15\xaa\x939\x0fC\x13\xa3\x1dr\xd6)\xaa\xe0\xf50\x98\xbb\x81\xfc\x9d^\x0ci\xa7;O\x03r\x1c$\xc7\xe5>7.\xcfCw\xaf\xe5;\xb0u,r\xd2\x98\xf7?s \x82\x97\x9ez\x86\\/=P'\x16\xf4V\xfab#\x83T\x9a\"M'A\x189i\xb5\x9bkB\xb3W\x8c\x92(\x0c\x12\x94h^\x100f\x96\"\xb9\xee\xc8\x95[\x82\x9eXN\xa3\xa7u\xc6\xaa\x96,\xec\xf8#I\xedt\x9d\x80{\x0fOeJ<\\\x07n\xe8\xac}\x140\xb9]\xe3\xd8d\xf6X\xcf\xfeH\xaa\xce\xcf>1\x9f\x0f\xcd\xcf\x93UY\xef\xbe\x8e\xfc\xc9\xf36\xb78o\xf5?\xd1Zb<\xfd\xe3\x8f\xc2g\\o\xd3\xf5\xed\xf8\xc1\x0d\xb7\x01\xec]2\xca\x18\x05.\x8a\x91;+9\x80\x9b\x7fE\xa0\x93\xbf\xb9\xcd\xa1\x8f\xc75C-\x10\x9a\x91\xa7\x1c\xa8d\x9e\xd1\xef\xf7\xd1q\x9a\xe1\xf6\x9dT\x1aW\xa9\x85\x9dEThY\xc5t\xa2\x038\xad|g\xc9\xedg\x90\xdc>\x1c%\xf0h<_\xe8\xfd\x89\xe2\xbd'\x15\x89\x9a\xd6\x14\xa9\xf3\xe7h\x13}\xd8qd\xcc\x0d\xddy\x82d\xec\xce\x95\n1'T\xba:N\xd3\x8b\xc5BxbN\xb8\xd3\xaaeSW\xf3\x1b\x0e\xed|\xe4+\x0e\xdd\x93G!\xa9\x0ej6gl\x9b\xfd\xfa\x96\xb7TP\x15F1w\xa6\x0b\xee\xfb\xcc\x95\xef<\xa2)69\xb3\x9f\xca=\xce\xecwx\xe7\x93{\x98C\xab\xe0c\xb5\x8fV(H\n\xf1\xb3\xa0\x83z@\xfd\xa24\x06\xd5/\x89ae;\xd6\x8er\xcd\x15'\x18\x1at\xf3\x96\x86\x16\xban\xb1\xdc\xcf\xba\xddAr.y\xe5-W\xc5{\xc0\x9d\xd0\x05\xd6~2\xf4\xdf\xbb\xbe\xe7\xc4a\xfe\x80|iN\xe9!\xbb\xeaHN_g\xce\xe8\x0c\xd8\x13\xd6Y\x1f\xc8\xdcQ+\xd7y\x89\xf8\xc4S\xee)\xe5\xca\x138tJZj\xe8\x8ezc\x138\xed@n2\xf2\xc6&\x0d\xf8\xd1K=\x8c\xbd\xb5\xdf\xf9\x82\xe6g\xc4\x84/\xe9\x97L\xc4P\xb6\xd9\xd4\xeb\xc5\xed\x90\xdb\xdb+r \xc4+\x88\x88eT\x8f\\\xf3\x9bE6\x83\xdaG \x8ej\x83\xa7\x95\x98s\x1a\x96\xe0P\x13\x07\x93\x8bX'n\x9e\xbe^8i\xa7XQ\xba\xbf+\x1dLzr\x13\xbe\xe7\x92\xa7\x1a-\xb5\xe2\xb8\xb5U,,N\x88D[\x94T/`\xeat\x93a\xd6\xcb\xcf\xe6T\xa0\xe0\x85\xb9\xd5l\xd2\xf8p\xe5\xb3\xe5\x89J\xe2x\x7fq\xd1\"\x9bW\x9a1\xc1x\x8e\xa37\x91\xed\xbc_'\xa9\xb7\xd8W\xe3L\x8d}\xaa7\xfei\xce\xd0\xa2\xf4\xfaQ\xdbH.\xa6,3uD\x8f\xd1\x81\x1e\x03'\xf2,\xfdEs\x18\xb5\xce\xd9\x95\x8c\xa5\xa7O\xf3\x13\xa6g\xc2\x13\xa8T\xb1\xc0\x1fO\xe8\x11\x12-\xcc\xd1\"\x8c\x91 aI\xb5\x93\x8e\x9a\x88Dm5\xdb\x11G\xc8\xb5\xbcG\x01\x07r\xeb \xec<\x0e\xd3\xfc\x87\x8e\x91t\xbc`\xe1\x05^\x8a:\xd94n\xc7g\xc4%\xcf\xc9\xf1\x14\xcd{\x12\xb8\x04x\xb1\xf7i\x9d\x15\xff/\x0e\xbe\xe6\xf3b\x1aF\xe5\x9e\x039;\x0c\xd8{\xb1y\xa6\xa9\xf6\xf3S.\xa0\xff\xfb\xbf*\xf2\x07\xb4_\xc4\xb6\x8f\x92N\xd5\xb0C\x1a\x02\xf7\xa0\xf3R\xf4\xa3\x91\xae\xe3\x80t\x1a\xea\xf9\xbf\xff\xfd_\xcf\xccO\x14\xec\xe7&\xa5N\x93W\xc3\x9c\x02I7\xfb%\x0eq\xa2\xd9\x8e\x83\xa2\xb4\xda\xac)\x87dj\xf3g\x19#\x14<\x85g~\xf5\x83\xe0ED,\xdd!\xf2!K\xcc\xb1\x17<\xa0\xf8`\xe9/\x9a\x17\x86P\xba\x15 H1\xcbc\xb5\x9d\x95y8\xba\xab\xda\xdd \xcc\x93 u\xb8\xe1\x05\xdc\x92\xb2\x06\x9d\x81O\xcf3\xa7\x83\xce\xfaU\xb7\xba\x8b\xea\xeb\xdf$\xc7\xcf6(N\xbc0\xd0\xa2\xd8^\xfa\xf6\x81\xdc\xaa\xa8\x83K\xe4\xb3\xe9?\x9a\xea\x8f?|\x94$\xf6\x12==\x82:u\xde#\xe5&\x06\xfcn\x0f\xf9@\xd8\xcc\\\xa0E>q\xd8\xb4\xcb\xc5\xf4\x82\xc6\xfe\xdd\xf56\xc4\x8bE-\xcbY)\x9dmTb\xde\xc9\x171Mt\\m\x97\xba(\xfbS\x8b\xdb\x8fv\x9d~\x11\xf6\xb2\x8bN\xba\x9ay\x1a\xb4\x9d\xb5&\xaf'\xf5\xc8\x83\x9a\xec\x19A\x93?6h&\xfcH\xbc\x8c\xed\xbd|\x05\x9as\x89\xec\x18\x05\xe9s_e8a\n\x9d\xa7A\xf6WK|\xd1\xc5\xad~\xa9\x19\x8e\xee\x9f\xae\x97\xd8s\x8c\xdc\x7fU\xef\x9b\x08\xc2\xcc\xe5p\xb8En=[uM\x8e\x90y?\x00s\xb9\xc9b\x9aer\xd7\x9fx\x04\xdf&\xc7\x0e\x1c\x84\xd9Sa\x8b\x81> \x97_e\x01i\x12\xb9\n\x0b\x0e|u\xf6:]\x85\xb1\xf7\x88\xe8\xeb\xd8\x13z\xb4\xab\xb8T\x07=\xe5\xa7?y\xe1$\xf5\x16\x89\x86\x05\x0e\xed4\xff\xb6\x0cm>p/\x9e\xa1\xdf,\x0f\x0b\x0fc\xf8\xc8e\x86-w\xaa\x80\xfe\xd9\x1f\x8fu\xd4\x03\x92[T9\xc7Q\xcb\xb8D\xa7\x0d\x9f\xe4\x8aZ\xc0\xb8\xe8\xff\xc7\x0fN4\x83r\x1f\xbcxU\x15\xd7\xb13\xadv\xb8\x03\xe2\x0c\x07l\x0b\x18\xe4\xa4\xf9_F\xdd\x95Y\xec\"\xf3\x98\xb5\x83\xb9\x18P\x0e\x0e\xca\xa2\xd3\\3\x0f\x95s\xce}\x98\xb8\xf7Y\xf6B~w\x8ef\xcc\xa8V\x06-\x0f\x80\x13}E\xcf\xfe\xb4\x89-\xbc\xf5\x0bO*\x05\xeb\xa1\x9e\xfd\xa1X\xcf\xd7i\x1a\x06\xec\xdb}\xc2u\x9a\x0d.\xbc\x02\x0bx\xd7\x0b66\xf6\xdc\x03\xbfVIV\xf6\x03\xeat\xfbI\xc7\x98\xc0O\xdb\x0e\x03\xffu\x81\xb83Fe\xd0{\xc4\xc4\x9b\xa7\x18\xac\xea\x1e:\x7f\xbc\xa7\xcc\xd9\xca\x13\xbb\x8ba\xf6\xa7\xb3\x8e\xf1\x8f\xae\x9d\xda\xe7\x9eo/\xd1\xcbd\xb3\xfcy\xe7\xe3\xc9\xdcN\xd0\xa0\x7f\xf6\xdb\xaf7\xbdo\xfb\x8b\xfe\xfc\xcbn\xed<\xea\x9e\xfd\xeb\x9d\xee\\\x86\x9bw\xa6k\xba{\xcb\x9c\xed\xad\x8d\xe3;\x9b\xd9\xfdt;{5~t}\xc7\xbb\xfe\xf5[\xf4\xedw\xf7\xd5\xdc\\\x8e\xaf\xef\xa7\xcb\xd9\xab\xe9\xbe\xf8{\xfd\xf3\xf5\xab\xe9\xf2\xfar\xb7\xfd\xfa\xfb]x\xfd\xe6v|\xfd\xa0\xeff\xfb\xbe>\xfb\xb8\\\xde\xec\xfb\xfd\x9b\x8f\xf8\xfe\xdd\xfd\xb59\xfb\xa0\xafg\xf7_\xfb\xef\xee\x9d\xed\xfb\xfa\xe7\x07\xf3\xfd\xab\xe9\xf6\xfaU\x7f\x7f\xb3\xef\xefo\xee\x97\xeb\xd9\xbd\xb3\xcf0\xb3\x0f\xf9s\xeb\xe6\x1e'\xef>\xce\xd6\xef?N\xfb\xd7\x97\xb3\xf5\xfb\xcb\x9b\xfbw\x1fj|\x9aa\x9b\x9f\x1f\xcc\xf7\x1f\xa6\xdb\xf9+\xfd\xf1\xdd\xfd\xc3\xf6}\xfe\xdf\xe5\xe3\xd7}V\x9f\x93\xbe\xbb\xbf\xee\xdd\xd4?\x17u\xbc\xfb\x90\xd5\xf1\x90=\xdb\xe5|\xef\x97\xeb\x9b\xc7\xa9U\xfd\xfc\xfe\xa3\xd3\xbf\xbe\xbc\x98\xcd>N\x97\xb3\x8f\xaf\x93\xb2m\xe9l\xdf\xdf\xdd\\\xbe\x1e\\{\xa3\x9f\x7f+\xf4\xf4\xf3O\x9d<\xaf[\x9c\xfc*b\xceN\x10j1\x8a\x90\x9d\x92\xf3ZqS\x9f{#\x84<\xa3\xd9SK|f0\x95(\xa8Y\xb9G\x11\xb2\xe3,Z(F\xa4\xfcEm\xecC\xe6w\xc0\xdd\xff\xe9\xafq\xeaE\x18\xfd\xabJ\xfeZ\xd4\xc15\x0b\xf4V\x80\xd1\x9f\xde]\xe9\xbd\x07.\x89\xd8\xcbg\xd8\xa3\xee\x94 8\x19#\x9d\xbd\xe0\xa5\x94\xdd}\xea\x99\xa4\xfch\xe1?\xb3%\xf5/\xc8\xb7=\xfc\xaf3A\xe9\xc2\xc3HX\x18\xd9I\xb2\x0dcW\x08H\x90\x1d;+aq\xb6\x1e\xa3\x0b\xb3'v\x8clRE:\x91l\xa2\x1dh\xc4\x0c\x8f\xc4\x86\xa1;\xce\xfe\xb4\x0d\x8f\x8b\x85\x9a\x15\xff\xf3\xd5\xd5\xbct&\xdf\x8a\x91\x1b\xbb\xeaO\xd2V\xb4\x81\xea\xd6\xb4\x01\xcbV\xb5\xc1\xf2\xd6\x81\xa0\xaa\x95\x7f\xca0\x00d\x8ar6\x07C\x7fq6\xd6_\x00Y\xb6:\xa5k\xba?jF\xb4\xcbF]0\xe5K\x96\xff\xbb\xa7\xbf8\x1b\xb5\xf2\xeb\xc9\xd9U\xc5\xff6\xf5\x17g\x96\xfe\xe2l\xd8\xcaQ\xeb\xb7HX\x95\xff\xbb\xaf\xbf8\x1b\xb4\xf2kaWs#3k\xff\xab\xd1g\xd1(8\x1403\x07y|\xbc\xd9\x9a\xeaQ\xb7\xe8\xf9\xd5\x137l\x92\x01u\xcb\xbb(\x8e:-\x00\xccMUK\x8aw|\x1d\xf8\xd0\x17\xb8\x1fU\x0f\x11\xce:\xe6\x0f%\x13[r\xe4d\xc2\x9c\xd5\x88QN\"P\xc0\xb3\x9f\xd9rV\xc8y\x98\x87\xbb\x03\x19\xf5\x97+Y`mD\xeez\x08\x1eW*\xd5\xb3?peOx\xfd\x86\x80aD\x1dD\xef\xeb:\xf1\xd1\x8d\xc2\x0e\xe4y\xb9J\xf3,HU\x8bP\xba\xae\x16\x85\x98L\xaag\xff\xaa\x9b\xca/\xa5\xa5t?\xe7\x8a\xfa{\xb7xC\x8f\xf0\x8dJt.K#\xf7\xcb\xf27/Tn7 \xcf\x91\x8f\xca\xedn2\x0ef\xcf|\xd0[Q\x8c\xff\xa1Q\xf6G\xf4\xb2$=_\x02T i!\x97\x08\"\xde\xf1\x90\xf7\x83\xfa\xa7\x13U\xd7\xfe\xca_\x85WFKk;\xcf\x7fB.e0^Y\xf9\x1a\xf8/\xc0\"\xd8Y\xd9q\x82\xd2_\xd6\xe9B\x1b\x9d\xbd0_%\x9be'\xb7\xe0/?\x18\xfa\x0f\x9d\xc2\x82\xbf\xfc0\xfa\xa1\xb3\xf1\xd0\xf6\"\xdc\xfd\xf2\x83\xd9\x19v\x0c\xbd3\xfa\xa1\xb3\xf3q\x90\xfc\xf2\xc3*M\xa3\xf3\x97/\xb7\xdbmwkv\xc3x\xf9\xb2\xa7\xebzV\xc7\x0f/\xcc\xab\x17\xe6\xab\xc8NW\x9d\x85\x87\xf1/?\xbc\xe8\x99}\xa3?\xec_\xfd\x90?\xd0\xe25F\xbf\xfc\x806(\x08]\xf7\x87\x8e\xfb\xcb\x0f\xb3A\xd74\xcd\x8ea\xbd3;\x86\xd1\x1d\x0c\x86\xd8\xc8\x9eh\xd9\xbf\xfdN\xaf\xd3{W<\xce\xc40;\xa3\xac\xec\xf1\x87\x97EMY\xa5/\xcc\xab\xbf\xfc\xd4\xb1\xf4\x17\xcdZ\x93\xd6\xa8\xeb\xd98\\j\xeb\x1d\xf35\x9d \xf9\xa2U\xea\x1e\x8b^\x1dV\xaa^\x03,`\xd8\xe9f\xbaw\xe30\x02\xb8K\x19\x8an\xc1\x8c~\x12V\xe5\x87\xae\x8d\xa9z\xea-m\xae!\xd4\xfe63)\x16\xbf\x9a\xe5\xdcP\x7f\xf3\xc3\xe2\x86\xe2\x937\xf8\xf9\x05JuY\xafm\x81\"\xc8\x07\xe8\xd1\xaeS\x9c\x9c\x92\xbe\x04Z\x8ckUj\xb5\xb1&;\x06g\xf5\xc90\x82O*J\xd8\xd2\x17U\x80{6U\x9e\x9c\x9fk\x95V\xb8\xd2\xba\xe9K>#f\x81=h\x16\xd8O8\x9a\x04\xd5\xff\x94\xd7\xce\xd5\xb1J\xaf8/':*[:\x16\xe96'\x9d\xffQmM\xa7\xeb\xe00AZ\xfe\xf8\x88\x94\xfc\xf3e\x9bd\xc2\xad\xc8\x0f\x83\xf7\xd8c?\x03\xf2\x0d^\x8d\xe8\\\x1eN\xb4Ir\x82[\xf8\xa1+O\xef\x98\xfa\x91g\xea\x85\xb5t\xba\xc4}\xd9$\xb2\x99\x1b\x11<&u\xabc\xb9\xb6\x9e\xfd\x11\x9d\xcc\xe5(\xff\x9e\xba\xcc\x8dK\xf5w\x0f\xe5\xcc\xb44\\.1b\x8fh\xc1\x81\xd7@\x14x\x95\xa6\xccF\xa9N\xd7D\xbe\xc2\xebo\xb8\xe1]\xf8*`u\xe4\xa9\x08\xe8C\x0e$\x03~**\xcf\xf1\x8cu\x17-\x81\xf3=\xe5s\x8eN\x0bc/\xcf\xa6\xe9/\xb2(a\"*\x10\x1b\xaa\xeb\x84\x18\xdbQ\x82\\\xf1\xa9#\x81P\xf9c1\xe7\xf2\xac\x1et\x02\x8d\xdd\xc0\x12\\\xa1=*\xd2k\x0f\xe0\xaa`\xb0\xd7o\x82\xc1\xec\xe7:\x1a\xcc\x83\xea~\xa7\xd7'c\xbd,\x8c3\xf4\xce\xe0\xdd\xa8k\x8d;\xc3n\xdf\xe8\x18f\xd7\x18v\x8c\x1e\xd6\xfa]k\xd4\xe9w\xad\xf1;C\xef\x18#<\xd0\x06m\xf1\x1b\xb7W\x90\x05/\x90\x16\xef\xd7~\xa4\xa5a\xfe60`\xe1\";\x01\xc43\x10\xbfz\x8a:;\xa8u\xfb\\g\x03-\\\xdc\x87\x97\x1f\xe3$\xa0\xd5\xbb\xa5\x8aG+/H\x0f\xc4!\xbb\xfcG\xf6cc\x04T \xab\xd1\x1d!\x7f\xc2\x9f\xe3\xab\x86\xff\xae\x81\xfcN~\x14\x08\xf8\x1eo9<\xaa\x04od\xb85\x84\x1c\x9e\xb8D\x95\xad\xfb\x99\xc3F\xe5\xc9\xb2\x02\x9a\xd4W0ub\xf2\x97\xbdR\x9a\x97M\xc2\xbdz\xc1)1{\xeb\xfc\x0b\x0f`\x9a,\x96b\"7Qh\"\x7f\xef5\xcd\x9e \xd1\x9e\xe5-\x86'\x85Ap\xb2\xe8Y\xdf\x13.\x0f\"\x06:w\xbc\x86S\xd5\x13_\xa3\x0d\xf0;\xe9\xcd\xde\x1c\x9f\xe3\xde_\xce\x92[\xac\x07\x90\xddEo\xdd\xf6\x02\x0e\x0b05\xa8\x0d\x99\xf9\xeaQ\xda\x17*F\xc0e\x97\xfa\x82\xc3Q\x1f\x1c\x02\xde\xc6\xa7>\xd8\xb0\xdf\xeej\x91\xb5\xc5F\xc3\xe3\x98\xd1Q \xf1\xda\x90\xa3\xb8\xe4\xa7\x83\x18&\xad#\x12\xc7\xa6|\x90\x08\x0cLM\x0b\xa3\xfa\nVf\xab\xe6\x15;\x96B\x85\xf3pw\x90\x1e\xdai`T\xc2\x19\x8ca\x95\xcd\xcc\xbe\xcc\xa7\xae\xe4\x08\xb7\xe6Ni\xd5L\xba\xd0\x0b\x87,\xf1\xa4\xce\xf4Ty\xcf\xb4\xf4\xec\x0f\xc4\xac\xa9U\xdb\xdaq\xe0\x05K\x903\xb7|\xab^\xdcR\xddn\x17\x1fV\xe4_Q\x97\x8du\x7f\xcf\xfe)\xa7\xe5\xee<\xb6\x1d\xa4\xe5\xabZjF\x84\xceBEq\x18i\x81\xed\xb3\x87\xb8\xa9\x15I#\x1d@\x9c\xfbx\xa5\x18\xcb\x06\x10(X\xfb\xb2\x0b\x8f9(\x0b\xb1\xed\xf4 \x9e4\xba \x8a7(\x16\\\x1f{\xb6\x0bYd%\xa2\xebW\xf47f@\x06\x9dU\xbf[\x9d%\xaf\xee\x1e\x94\x01E\x8fUcE\x92\xdas\x8c:i\xf55\x16So\x01\xba\"\x9b\xd5\xd2eQ \xf8\x85\xdb u\x1f\x82H\x82i\xc4\x9dNy\xe5\xf0\xeb\xfaKWik\xa3\xdb\xe1^\x0eE\x1c|\x87I\xbbN\xe8G\xeb\xack\xadc\\\x0f\xcd\xfc\x91~\x10_\x1cC\x07\xf5E\x9c\xaa\x9d\x88&l\xce\xf5\x978\x9c\xdbX+\xea\xfa\x8f\xbe%*\x90\xb4\xd6S9\x00\x92g\x9c{\xd50$~=S\xf5\xaa/\xc0\xdd\xcb1C\xe0\xed\xb9\x03@/\xc3\xa12nZ\xb5>?\xaf~\xe0\x99\x94\xc3]\x9a\x9fLJ\xe3\xac?\xd4\xbcX\xafg?\xd6,`\xc0\xf8tu\"\xa5O\xbe\xe2\xab\xd8\x84\x82ZU\xde\xefN2IZ\x12dp\xa7|j\xda\xac\xec\\\x80B\xaa7\xb7)\xe9E\xa2\x91fl\xe9Q{\x0f\x03\xe2\xe6 \xf0V\x9f\x92m\xfe\xea\xc6\x9c\xed\x99\xact\xd5vz\x8cI%\x13\xd7b\xf2c\xf2\x8a\xeb\xb7\x9e\xda\xa9Bf\xae\xaa\xbe\x8c\x93\xb0/\x93\xe0\xce\x02\xc1\x1f\xd52\xf9\x17>Ix\xd2\x97\xcdJ\x86B\xfa?\xfe\xc8grI\xc4\xd1\xd7O\x99\x14\x99\n\xba1\xfa\xef\xb5\x17W\xaf\xc7\x11\x0d\x12\"*\xf86+\x1c\xe0i\x03\xfasCM\xca\xac\xe2\xf6\x97R\xf0\xf2e\xd0V1\n\x0e\xd8o\xae6\xb2\xa0]\x8a\x82\xc4\x0b\x99l2\x81\xf0\x14^\x9csLW\xe5?\xccBT&|m\xfe\x13+\x8d\x91+V\x81\x1f\xa5\xfb?66^\xa3?\xf8\xc4\xb5ID\x03\xe5\xda\x91\x8b\x0e\xb8\x17\x0cJ\xb9\x97\x93=\x15L\x0e\x8f\xe2\xd0\xad\xee%5\xc1<\xffjH\x8c\x80\xab\xee\xfc\xa6^\x1aFs\x9b\xfeb\x0dpE\xa7|s\x0eDZ\xfd\x17~\xcd`\x89\xb1O\xdb%{r\xbe\x07\x14\x98:U\x95\xe7\x06\xd9!U%WB\x8eb\xf9^3\xbbIR\x1c\xb9\x90\xaf_\xd8cD\x95\x84E\xca\x06\xd8\xcc\xe2#\xd1\xca\n\xf5+J\xd61\xae_\xd3\xf7d\xad\xe7m5\x9b\xd6\x9b\x93\xea \x01\xca/r\xa2\xc0e\xaevfO\xd8{\x9dy)\n\\\xf56\xb4\xcc$\xa5\x86\xf8seV\x7f\xb8\x80\xbeJV]h\x12\xdf*\x91\x8b\xd3-f!\xed\xf4\xb3WOw\xeb 8\x99\x0e\xa8\xe3p\xa76\xa9\xbcgG\xcf\x9aJ\x1d\x82\xf6\xd2<\xc0\x92\xbf\x19\xf2\x18\xa1\x8a\xa9\x9f\x93\xa3\xd7\xc8\xd1\x9b\x94\xff!\x94#t\x0b\xea\x04$\xb0\xee(\xcf\x0dR\xbf\x1f#<\xf5\xb4\xbc\xd5$\x89D\xc88\xae_\x1e\xf2\x90\x9c\xe1$\xae\xd5Q\x8b\xa8\xb2qG\x0e:^\xb0\x08\xeb;\x1d\xc0K(\xb3\xf2\xce*\xbf\xee\xd7\xf5m/`\x97urt\x87=\xc4\n\xc0\xb1w\xc6?\x8c\x80g\xc5z\x89\xe0w\xda+\x0f\x0b\x19\x0d\xa0\x02\xf6\xf3\xc8\xc5C\x13z\xd8\x87\x1eZ\xc7\xbf9\xa0\xa0,\xdenU\xad\x8f\x8b\xdbb\xea\xe9C\xdd:\xf2\xa4.\xf4\xee\xf7\\\x0e\x9b\xd5\xeeQ\x1b\x11-\xb6\x80\xae\xc9\x16\xb5\xd2\xef\xbc3\x16\x83\xb1\x03xay7\x9f\xdc\x9f\x02\x98u\xe7v\x824\xe0\xe80\xa9\x0b\x93:\xdbZ\xcf#G)Qh\xcc.\x9bF5\x07O{w/\xc1\x95\xff2\xaad\xc1`\xb5\x1c\xae(\xd6\xef\xe4\xcb\x9d{\xc5\xc0\xc2.\x8d\x93u\xc4\x1dd\xb5\x86\xcc\x01\xb7\xa1;\xea\x8f!\xf3\x92\x92\xe7\xaf\xdbST\x057T\xd9\xebt\xa5\xcd\xd3\xe0i\x01\x0e\xbd6\x7f\x8e\x17U\xc8\xa5,\xeeK\xbba\x80\x0e\xf2\x14rN\xf8\xa4\xa6)M\xd4\xcf\x1a\xbb\x912w\x88\xd7\x040)\xd0&4\xd1\x9a\x97\xe3\x01\x9c\xc0\xe4\xa1\xc1\xdeo(\xd2\x89-\xa7\xe6d\xdc\xe1M)a\x1dl8E3#v\xcd\xcbc\xffV\xb4\x13\x1d\xb7bH\xeb\x8f\x8e\xf3\xc1\xbe\x94\xae\xf5&\x9a\x84\xa0\x08\xa3\xd9\x1b\x90R)Q\x1c\x87q\xc2\x0e\xa8\xd4\x06\x18?Y=y0M\x9c0BIg\xd5{\xfa\x94\x9f\xb3\xd2\\\xb4\x90\x1f\x8b(\x1b\xaa1V\xe9\xc1\x0eXu$\xe2\x92\x9acc\xf4)b^\x80E>\xe5C\xd2\xea\xfaZ\xebd/\xf9&\x15-v\xf9;\xdb\nx\xd3\x0b$e\x8fl\x08\xdf=\x7f\x92]\x05U&\xc4\x8b\x9f\xc0M/\x86\xae\x882\x9f>P\x9e\xb4\x06S\x90\x8c\xd6a\x8f\xba\xac\xa44P+\xb99t\xc7\xb1\xf0\xb7\x03x9\xad\xbc\x971\x02\xeej\x8c~\x9a4\xaf\xc6\x02\xdfAV\x00\x0d\x9e\xd6hH\x0d\xfav\xe0\xff\xb4,\x94\x9d\xee\xf2kaq\xb7\no\x9aTZ\xe5\x1d\xf9J\xef\xff\xbc\xfc\xdb_;I\xb8\x8e\x1d4\xb3\xa3\xc8\x0b\x96\x9f\xee\xde\xfd\xd20\xea:I\xd2\xf5\xed\xe8o/\xff\x7f\x01\x00\x00\xff\xffPK\x07\x08_;\x94/\xe8Y\x00\x00\xa8X\x02\x00PK\x03\x04\x14\x00\x08\x00\x08\x00\x00\x00!(\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x00 \x00swagger.yamlUT\x05\x00\x01\x80Cm8\xec}\xe9r\xe3\xb6\xd6\xe0\x7f?\x05J\x99\x9aN*\xb1-\xc9\x92l\xb9&3\xe5\xb5\xdb\xe9\xf1\x8d\xd3v:\xf7\xe6\x8f\x1a\"!\n\x16 \xd0\x04\xa8\xc5\xa9T\xcds\xcc\x9fy\xc5y\x84\xaf\x08p\x01I\x90\")\xc9q/\xfa\xbe\xcauK8\x07\xc0\xd9\xcf\xc1\xb6\xbf\xbf\xbf\xc7\x16\xd0\xb2\x90w\nZ\xdd\x83vk\x0f\x93 =\xdd\x03`\x8e<\x86)9\x05\xad\xa3\xe0k\x008\xe66:\x05o!\x86\xfb\xff\x1bs\x04&\xd4\x03\x17\x949\x94\xed\x01`\"fx\xd8\xe5\x02\xe4\x0c|\xb8\xba\x7f\x00\x98p\xe4M\xa0!\x9b2\x0e9\x02O>\xf20b?\x01\xeeA\xc2\xa0\x11\x00\x00\x0b\x11\xe4A\xf1'$&\x18{\x14\x9a\x06d\x1c\x13\xeb`\x8fC\x8b\x05\x03\xda\x07\x04:\xe8\x14<$\x80A\xc7\x99\xae\xef\x11\xf4\x8c\xe9O\x00\x11\x83\x9a\xe8'@\xbd\x04\x9d\xda';PQ\"b\"\xcf\xc1\x84\x83\x0fw\x17y\xa4\xca\xefgw7\xec'\xc0|c\n \x13\xb3Y\x81\xb1M\x8dYzJLLd\x0emlBN=\x86\xb8\xd2\xdd\x99\xcf\xa7\xf9N\x82o\x11\xe1\xd8\x08\xc8\x04\x0d\x83\xfa\x843\x05\xea\x1c\x92Y\x1e\xea\xc2C\xa2\xbdJ\xb6\xd4@\x14\x0c\xf7\x1c\xce0\xb14D\xe3p\x86\x80CM\xdfFb\x86\n\xd0[:G\x1e\x81\xc4@y\xb8\xe4\xb7\x02\xe0{\x1b\xb2\xa9\xbe\xcb\xf0\x97\x02\xc0K\xcc\xb8\x87\xc7~\xd08\x0f|\x8d\x100\x95\x16E\xbd\xfb\xaek\xaf4}\x8b\xef\x0b\x80B\xb9W\xbe\xb9\xc5\x84\xe7\x91\x04\xdf\x16\x8f\xff\x163#\x0f\xf3\x9b\x10\x17\xe8\xbaq/\xcc\x98\"\x07\x85\xf2=\xe5\xdce{S\xca\xf8i\xa0-\x9e\x059:0\x84\x86\x1d\x10\xc4\x17\xd4\x9b\xed1d\xf8\x1e\xe6\xabK4\xc1\x04\x0b\x0e\x07\xc03G\xfc\x0f\x00|\xe5\xa2S0\x86\x0c\x1b{.\xe4S\xf1\xf5!\xa1&\x1aE\x9a\x0d\x80\x85\xb8\xfc#3\xbe\x1b2\xa1\x9e\x13*\xe2\x98\xfa\x1c\xf0)\x02\x06%\x04\x19\x1c\x99 @\x13\xc21\xdfq\xa0\xb7:\x05\x0fS\x04\\\x8f\xba\xc8\xe3\x181@'\xc50\x91&\xcb\xcf\xbeN\xed@\x80\xcb\xf4\x0d\x94j\x08]\xd7\x0e\xf4\x02Sr\xf8\xc8B\x89\x00\xc0C\xcc\xa5\x84\xa9m\xbb\xedv\xf2\x8f\xcc\xec\xfeEM$\xac\x90\xcf\x94&\x82\x03P\x05\x8a\x88H\xc7\x8f\xc8\xe0\xa9\x1f\x92\x89\xa6\x01\x80:\xc4Qd:3M\xca\xc0\x83\xcf\xd8\xc7\xb69J\x13I\xfd\xc8Q\x05R\x1f*T\xfac\xd8\x18\x11>\x12\xf2\xd7\x08\x9e:\x0e\xe6\x8d@-\xda\x08\xac\xf1P\x19\xf2\xe6\xc8k>\xd5B\x06\xad\x81\xcd\xa8\x91\xfa)g-6k\xf7\x15|\x1cJ\xf0\x0cy\x8d`\x01@K\xe8\xb8\x81\xcb\x8e\xdd\xd0~@1M[\xd7\xa3\x9c\x1a\xd4.\x96\\\xb0v\x8a\xa2E\xd7-\xfa\xa9\xc2x\x81:\xe6\xe3\x82&\xc2\xd7n\xab\x93N\xbb\xa0\x0dt\xb76\x11]\x17\xa11\xdf\x94\xafV\x10\x8auu\xaa<\x85\x84 \xbb\x99\x1d\xb11\xe3\x88\x8c\xa0in,x\x9da\xf7\xa0389\xe8\x0f\x0e:\xa7\xdd\xc1\xa0?\xa8\xab\x8cEaX\xe2\xa5\xf3\x9f\xea\xe3k\x1ft\xfa\x07:\x06Q>-R\xbb\xd4\x88\x1c\xea!\x80\x15\xafII44V26\x8dg\x89>\xeb\x95\x8c/G\x98\x98h\xb9-\x01-\xa0\"\x00\x9ek\x08)@\xacp,u\xfb\xe2\x86{zx\xd8>\x10\xff'$\"\xd1\xf3~\x89\xeb\xbe\x86\xd8F&\xe04\x8c\xb8I\xca\x95\x1f\xb2\x1510\xb1$\xb8\x12\xdc\xc4A\xca\xbdl\x10\xe6 tR;*I\x87\xbd\x88\x03,\xe3\x1c1\x10\xcc\x80\xe1{\x1e\"\xdc^\x01\xb6\"AO\x0b\xcc\xa7R\x8cD\x9bH\x1av\x1d\xdd(\xf3\xdcE\x94\x93\"\xb4\xfa \xc3NJm\x04I%\x96\xde\x0b\x1f.sD\x02m\x80<\x8fz\x013e6uhC\x8e\x18/fi\xc0\x84\x80\x03\xb2\x9d\xf4\x0bu8\xba;N<\xe8G\x05\n\xd8\xf0\xdf<49\x05\xad\xef\x0e\xcd$\xa4?<\x0f\x00E\xba\xd0\xda\n5\xff\x9a\"lM\xf9\xdf\xe5\xf4\x84r\xc0\x00\x06\x7f\x1a\xc8\xe3\x10\x13 !wDZ\x17z\xd0A\x1cy\xa9\xc6\x98\x9c\x82 yQf+\xd3\xaa\xd4X@\x96\x08\x82h\xf96\x1ez\xf2\xb1\x87\xccS\xc0=_\x0d\x7f\xa4\xd0\x12\xdf\x19#O\xf9z\xb9\x9f8\xb0\xe6\x12\xa0P\x92\xb9\xc8\xc0\x13l\xe4\x87\xb6\x91<\xf4\xda\xbd\xc2\x11|@O~,\x80a\xbf\xc0\xa4\x88\x917\\AP<\x85\x1b\"\xa2\xc6\xec\x90\x1b\xc9\xa0Z\x06\xa9\xad\xd810\x90E\x14\xb0\x03)l\xc0\xde\xd4\xb0\x026gmQ5f7\xb0\xc1\x02\xfbHb/2\xc4Z\x7f\x9c\xb0\xa1\x08\x0cz\x1e\\\xe5~\xc3\x1c9\xda\x08@+\xa9 />F\xfdmh\xc2\xd2\xe2S\xd5\x92e\x18\xf4\xcd\x9cmf\xcer\xf2\xae\x98\xb5o\xf2^$\xefe&\xfa,\xb3?\xaf\xd1\xba\x9c\x00*Zw~q~\xd5m_\x9d\\\xf6\x06\xc7\xfd\x93\xf3\xe1\xe0\xec\xaa\x7frrt~<\xec\x9e\xf4O\xba\xc3\xc1\xd9E{p\xd5\xef\xf4\x8e\xfa\xbda\xfb\xfa\xfc\xf2\xe2\xec\xaa\xdb?;\xee\x9e\x1f]\\\x1c\x0f\xce\x1b*\xedR\xe6 \\\xd6g\xe7\xd8DfvR\x95\xc3\x8f\x87e\x8dX\xf4&\x12\xaeP\xd8\xae\x14\x19\xcb W\x05\xe1I\xb28\xb1\xb6\x93]\xdd\xc8\xf5\xafi\x16H,\x9a#\xc2\xd9V\xe5J$\xa39\xc1r\x10c\xd0B\x07\xb2\xef\xf5\xa2\x92\x1a|KU 9\xe4x\xb5\xe9M\x1a\xf3\xcf\x0c\x11\xf3\x0dXL\xb11\x0d\xa4\xc3\xb79\x03\x98\x08\x8eO\xa8m\xd3E\xa0P\x88\x98.\xc5\x84\x9f\x827o\xaf\x1e\x04\x13\xfe\x97\x0eOK/\xbc\xad\xe0\xc7V\xady3a\x117\x99w \x14Rz%\xae5c\xff\xef\xe9\x9e\x7f\x96K&\x9d\xc1r\x85\x1c\x179\xae;\xec.\x87\xd3\xd5\xf3\xf3p\xe1Y\x93a\xcf\x1b<\x0e\xa7\xfdI{\xe0.\x97\xf3\xc2\x89\xd7\xc2R\x8dB.\xb4P\x11\x01\xee\xa0\x85\xf2\xce[\x92.0\xd7\xd6:\xa7^\xde\xb5\x8d\x1d\\\x18i\xdc\xc2%v|'\xec\x1e\xd0\x89\xf4\x81\xc0E^v\xcc5\x06T\xd3`\x9d\xd96\xe0K\x06\x1c\xc8\x0d\xb12\x98\xb2\\R\x15\x14\xd8\xca\xb6\xeb\x0eZ\x98@\x8eLa\xc2\x1e\x96Lu\xcf\xeb\x9d+\x93\xd6$\xd3\x7f\x13\xfb\x07\x80KY#\xc3w\x1e\xaf\xecB\xc0\xb0E\x90 \xf8rO\xd3\xb5\xb6!\xe0\x14@0\xf1m[-{\x19\x940\xdf\xa9f\x00\xb7a+\xc7\xd4\xccK%_\xc6#.\xa2f\x10|\xf2%p\xfc \xb1B\xc9\xbc\xee\xb9\xf9\xb0<\x10?3\xdfu\xa9\xc7\x91\xba\x04\xeeP\x13\x05\xd6\xd0\xb0}\x13\x81O-\x11E\xb6>}\xef!\xee{\x04\xc0 G^\x80W\xaez\xfd\xf0\x13\xf8\xd4b+b\xa8-\x90\x07.\xa6\xc8\x98=,\x7f\x10\xeb\xeb\x9fZ0\xdd\xc4\x13q\x1b\\\xc0\xd5\x0f\x07\xca\xf0\x0bC\x85-\x05\xc4\\S\xfa\xd5J\xbe Q+\xd36 LQ<\\P\xc6\x8d5[-g\xd5\xd4\xee jT\xb6u\x84\xfe\xaa\x89>\xc7\x12\xf3\xb0\xbc\x10\xcc\xfb Pm\x1e\x9b\x1c\xca=#\xa7\x1b\xa9\xea\x95\xc0\x91 m9\x15\xc6\xec\xcc\xc1\x84\x82\x05\xf6\xc4\x86\x18\x07r\x9d\nk\x11|\x1f\n=\xf5\x824\xe1\x070\xf1\xa8\x03~\xb9\xff\xf5_\x01\xea1dh\xd0\xdb\x97\xa37\xc3^\x18\xf20\xb4\xf1s\xa0\x14+\x1e\xd7\x9f_\x89\xd6\xafQvN\xc3\xfd;\xaf^\xab\xeaj\x81\x9c\xdf\x02\x8a\xa0\xce@\x8c\x05fy\x05L$y\x17\x98\x19\x0fE\xac|\x99IVS}Q\xd2\xd4\x08\xda~V\xd0\xc4^/.\xe6\x19c+\xf3\xb3\nI\x1chK\xbdP\xa6\xde8\x99\x95$\xddL\x99/\x91F\x17\x85\xeeUVg-\n\xad:WR\xe3@5\x02\xbd\xff\xdc\xd4Yr\xe3\x1fV\xe7j\x92~??\xc7\xffF\xbd\xf7wO\xf8\xf1?\x7f\xd2\xf7\xd7\xd7\xef\xae\x9e\x7f91\xba\xef\xee\xce&\xf3\xee\xd5\xf5\xef\xc6\xcdt\xd9^\xddAkq5}X\xb5\xe7wg?\xbe};\xbd\xb8b\xf6\xfb\x7f\xc3\xde\xd9\xa4\xed\x9f\xff\xe8L\xee\xa7\xf4\xf6\xc2\xfa\xf8l\xbe\xbd\xf6\xfe\xfcpsy\xfbp\xb6\xb8\xb2~\xfbm\xf1\x0b\xbd\x0d{\xdf\xae\xf5XC\xc4\xf5\xc6\xec\xe5\x15u\x0c\xc9\xecp\x0cmH\x0c\xc4\x0e\xff\nW\x9b\xd7\x94\xa0\x02\xdd\x0b\xf7G\x82\x08\xb6@\xb9\xe3=\x93[\x92\x7fm!)\x1cu\xd1\xe4\xcf\xc2\xa1\x86\xcd\x82\x0c}\x8c\x8c\xe9Q7m5\xc0fE\xa6Z\xd9j3\xf1;\xd3\xd3\x1c\x94*m\xbe\xc4\xaa-\xafj\x85\xf3\x82bR-\xac+\x17\xb0h3m\"`\x87\xc2\x1aOb\x0e\xab\x0eB)7\x11\x13\x18\x14\x13&\x0d4%\x89\xdc\x05)\x15\x11\xcb\xfb\xeb%\xef\xa5\x8d\xf4\x97%\xa4\xa5\xae'dG\xd1\xacDr(jB\"\xb2\xe2Ku\xafN\x95)m\xc9\x19\x05\xae}\xe4\xa1\xa7\xbcK\xd2g8\x90\xa1\x0f\xe8)\x9b\xb9A'\x98k\x91[\xdb\xc6Z\x86\xaapZ\xe3\xd0-\xf6\x0e\xaa_\x92n)\xdc\xd5\xbfs\xc7\x14Uj<\xb9\xe6\x1d7kd0\xa0\xcf\xa7\x1a\x83Q\xdd#ev\x83\x89\x94\xd9\x98B\x1c\xc9[\xd6P\xc4\x87\x01^\x8f\xf6W\xd1\x8c\xdd({C\x8f\x94\xa19\x8f\xb6_\xa8t\x07\xdbSg\x01R\xa0\x86E+\x91~!D\xc1f\xc0\xf2\x8d\x80\xa1\xb4\x8dd\xc5V\xd7bM\xb8\x0b@\xe9\xd6\xbe5\xb0\xc2+\x96A\xea\xad\x11(\xb3H\xa0\x8aUR?\xae?\xb6\xb11\x9a\xa1\x95\x1e\x9d\xbe\x1a,\x80\xde\xa3\x95\x0e#\x0b,\x081\xeal*\xafld\x90bd\x98<\x88sh\"\x1bYb\x85\xfa\xf0\xaf\xf8\xef3\xd3\xf4\xfe\x8e~\x8a\xcew\xe84^\xa3\xefR\xdbS\xa8\xf6\xb4C;\x97\xce\xfd\xcc0\xceB\x8fO'\xe02\x82\x8ba\n\xd4_K\x89\x8dT\xbfp\xb9\xd9\xb6\x81B\n\x19\x88\xc1d\x86!L\xd6\xa8\xaa'\x9dj\xd9\xd5\x9a\x06\xe8\xd7\xf7\xca/\xbb \x82/\xe3\xd9\xd7\xf3\x861\x89rV\xbdI}\xb4(D\xf6\xc7\x0e\xe6\n\x87\"\x8a\xd7\xab \xe4\xe0s\xe3\x12\xa7\x8c c\x0b\xea\x99\xd1\x19#%\x16\xf7\x90C\xe7()\xcd\xbc\xbf\xbd\xaf\xc4\x98Zf\x7f;Q\\\xcc\x97\xe2\xbd\xd5Zt\xa1\x9ef\xd1\xc5\x9b\\j\xa2\x8b7\xab\x14\xe0MXR\x11\xa1j\xa5\xcb\xd5q7\xf9\xd0\xb65\xb7\xd9\xdaC#\xcd\x04\xd4S\xe8\x1d\xc5\xb1iU\xe9\xb5;\x85\x88\xdf\xa3U\xa2\x1c\x98\x81\x85G+z\xa8\xc2\xe5\x90z\x1e\xea\xf0\xaf\xb9*N\x7f\x7f\x0d\x1e\xabd6)b\x94\xce\xe6W7\xc8\x90b%\x0c\xa6\x14\x03ogJsh\x07\xf6l\xed\xcc\xba\x8b\x1e\xe9\xda\x02\x8f\xce\x17\xcb\x93\xab\xe2d\xa7<\xe9\xa0\n\xec\x18\xf1\x05BD\xf5\xcb\"\xdf\x86\xb9\xc9\xbcZ?\xbd[\xd7\x1b(x\xb2\x81r\x1b\xfe\xb8\x8a\x82\xfadL\x89\x89\x895\xfa\x16L\xc6\xc1dL\x94\xaf<\xac\xfc=\xa2\xc3\xd6\x84|#y.\x8f/!\xd1\xf2-\xe2\xc3\xb7`\xf33\x0f6\xd9\x14z\xba:G\xb5\x05\xbbV\xa7\xdd\xfe\x16y6\xd2\xd9\xc01\xe94\xebs\x89A\xb5.\xee[4\x9a\x9a\xcd\x17\x1b\x8d\x16\xbb\xf3/5 \xd58\xed;\x88\xbd-\x18\x81\x1dE\xa7\x1e\xaa\x1cz\xa6\xb7-g\x14qKJ8\x816+\x15\xd9\xe2\xa1$\xae/\xf0\xfb\xa5\xe3\xf9\x08me<\xf7\x9e\xf1\xb1D\x89\xb62$Nk\x0c\xe8\x92\xf1\x0d\x06T\x16[\xa7\xb8\x0d\xbe\x9f`\x9b#\x0f\x8cW\xe1\xa1}\xc1y\xf6\xc3k\xd7\xbc\xcdc\xeb\x0f\n\x1d\xaa\xed_X\xabH%>\xb0\x86\x8e}\x19\xbe\xae4SH a$L\xbbH\x10\xaa\xec+\xf8:r\x01\xe6\xc5\xf7\x84T\xc7\xba.%H\xd0\x9b\x8c\xd7\x1c\xf1:\xdc_U\xba\xf1\n6fh#\x0eUO\xf5\xe9\xc6\xae\x0cf\xf6\\\xf0\x97m-\xcb\xe3\xe7\x84\x16\x80O\xc5\xa9\xee\x84Y\x98\x81 \xdc\x14\xf7\xeeT\x92\xf7\xdd \xf1\x0b8m\xed\xe9\xed\x06\xb2\xfd\x82\xe2\xfb-\xd1M\xcd\xa6z\xa2\x9b \x88\xb7;\x9b\xed\xe6\xb8Jf\xf6Y+\xe8Nun\x87\x19l\xd6Y\x94\xe5?\xc9\x10\x0cH\xcc\xe0O\xc4\x0e\xc0\xf9\n\x98h\x02}\x9b\x03\xcc\x81<:\xc8\x00%\xb6\\O\x0b9\x98\xf4\x13\x9fP\xafy\xec\xb3\xd2h`X\xd4M\xb1\xe1\xfa&\xc3\xc4\xb2\xd1g^\x04m\xe84v\xee\x1f\xb2\xd2\xb8\xd1\x16\xce/P2K\xb6s~6\x02\xb9\xb95l\xba\xdc\xfe\xf2\xe2\xbb\x9d\xed#_\xb0 \x97n%\xf9\x8aDz\xe3\xad$;\x92m\x97R\xfb\xb4\x94\x8b\xea~\xb6\xf8j\xe0\xe0\xcb\x10\x05\x08P|\x1e\x0c\xacUP\xb6)eh\xc4\xe9\x0c\xe9Nq\x94\x94Ae$\xdf\x04\x12\x93\x89-H1\xb2!\xe3#\x8euW\xf7W\x81\xaf\x05\x15\xa4`\xb2Cq\xcf\x0bc\xc1\x00<\xc4P\xbd\x9b\x04]\x0f\xcdG\xe1\xdck\x15\x8f7\x93\xdf\x8c\x95\xad(\xc5Rp#X \xce\x1e\x15\x9d\x8f\xfe\x9c\x858\x91(/\xe0\xb21\x85\xc4j(S#\x07\xd6\xbb.@\x81\xc4\xf5$\xd2\xa2\xd0\x0eE\xa9\x16\\\xe2\x8dk\xab\x8e\x03\x97\xa3l\x19#\x0f\x9aOSA\xa8\xf0#\x13\x11\xeaT\xec\xb2\x89\xc4\x7f\x07\x1e~\xbd\xfc\xf5\x14\xfc\x81\x00A\xf2\x9a\xf7\xb0\xe80\xc1K\xc0\xa7\x98\x01\x8f\xfa\x1c\x81\xc5\x14\xc9\xd3}\x89\xc7\xc0L\\\x9c9\xa1>\x11\xf7i@\xd3\x0c\x12\x1d\x1b\xb2\xa9ZU\x89\xee\xc53(\xe1\x1e48\xe0\x88\x89\xeb\xbc\xbe\x0b\x14.|\x8bH\x1f\x0d\xdd\xf9\xe3\xf7h\xf5\xf7!\xc3\x16 \xe8\x1f\xbd\xff\xf1\x1dHt\xf2;9\xdb\x94Z\x06\xedE\x12\x168\x15\x0b\xcf\x11I\x05\x05\xdfi\x08T\x1dLU\xd5\xef\"bk\xb55\xfc5\xd2|\xa5\xb1\xf28S\x845eq\x94\xa6\x19V\xc7\xbf\xe8#\xb9\x84\xea\xf2\x88\x1e\x98\xa1U\x1a*\x13\x1bJ\x12\xa7\x9b\xe4\"=\xe57%\xd6T\xbe\xd5\xc5{\x06%\xcc\xf5\xc7\x9dg\xe3\xd1\xf4\x91\xfb\xd4\x9e\xfb\xddgkf\xcdzC4\x81m\xf2\xb4x&&$O}\xa7g\x1c\xbb\xf0\xc8\xefA\xf7\xb9gu\xbd\xa1\xc5\xdc'k`\x0d\x0dv4\x1b\x1a\xfe$\xe9+e\xfb\xe2\xfeC\xf3WD\x1aa\x01\x95\x1f\x13#\xa8|Y\xb4\xe4&%\xef\x86LhK\x05\xe8\x95w\x99\x0f\xaf\xf4\xec\xe8\xafCS\xe4\xa7\"\xb5Q5c\x8d\xaf\xd2Hwz\x19jO3\x82\x1c\xa0\x16\xa4\x86\xf7\xca\xb9A\xf5\x99\xb2\xfa\x95\xd7\xed]\xebXx\xdcz\xbb\x85\xcc-\xdc\xf7Xe\xa4\xfd\xbd\xa8\xed.\x82\x85MR\x96\x8cF\xc9O\xbdT%\xd1%q\xe3\x15%q\xf2\x90\x93\xccf^q\x8d[\x8a\x92\xf4G\x88\xc3,G\xbb/\xe6w\xd1\x00@\xf0(\x9fP\xc9\xe6\xa5\xa9\xa1\x88\x1bO2\x17\xd7\xf9k\x10\xecf\x93C#\x0d\xad\xb2\xe0\x91sQ\xf9;\x0f\xca\n\x17%\x82\xaf\xb9|a\x1b\x15\x08 \xa6\x96\x9aC\xab\x95\x1b\xadd\xf3yz;\x93f\x87\xd3+\xbb\xe9d\xa3\xbb\xf4\xb6\xbc\xb1e+;\xecsr%\x1e \x0d\x89\x12\x03of\x0e\x1a\xe5\x85\xd1s\x9b pEM\xab\xae\xb35\xf9W\xd1\xcc\xd7\x12\xbf \xd5Asl\"b\xa0\x11\xac\x99\x0e\xcaK\xf9F\xf2\xc5\x9c\xd1\x02\x13\x93.j!p0\x19\x85H\\\xe45\xc1`R\x7fl#\x81d$3\xbe\x91\xe9{\x0d\xea\x1etA\x82\n\xc8\xde\xfa\x04\x0cH\xc0\x18\x81O-\x8e\x96\xbc\xf5\xe9\xa7\xa0I\x846,\xae\xc8o\x19\x9d\xf0\x05\xf4\xd0\xc8w-\x0f\x9a\xa8\xf5I\xe1O\x18\x10S\xc6Gq\x07\xe3\xcf\xcd+\x15l\xa0\x95\x0f`W\x13[\xf9Q9P\x07.\xc5\x9bZ\x90\xea>U\xc1H-f\xdd\x8dAu\xf6\xfe\x8a\xdf\xa1=2\x91K\x99\xee\xcd\xd8\xa2\x08\x1dl\xffJ\xb2\x97\x0b\x10\x1a\xec|\x8d\x18\xb9\xf9\xc6\xd6\xb2\xd5\xfe\xd8\xd4\xedi\x10f\x9a\xa4\xb6\x05\x88'\x16r\x11\xc1\xee-Sq\xda:\xa7<\x95f\xa6mX\xf0c\xe9%e\xe9\xc3+\x05\x9aR\xd6\x7f(\xd1\xb4p\x0cq\x83\xdd\x8e#\xb7\x99+5\x88X\xacd\xb3\x9fT\xeb\xce\x12K\x1e\x8e5\x08F05\xa5\xf5\x9eS\x8e\x89\x95\xfa\xca\x85\x8c\xa1\xf0o\x0f=\x8ag\xbbSF\xbd\xd6\xbcj*i\xc5(p\x93d\xff\x01-\xf9]H\xb1z\xea\xab\x9c[R\x15\xa4\x99\x06\xa7\xa3\x12\x19\xc5\xa7V-\xb4!\xca\xdb\xd0b\x05\xb1F\xbc\xa6#\xa1\x121P\xa2\x93=\xcd\x88\x1a\xe2x\xbd\xc1\x8c\xdc X4\x93\xc0\xd6\xca\xcd\xb2\x06%\x1cb\xc2D\xc10\x0b\x90O\xf9\xbf\x85-\xd1G}\x07\xe7.\xa0\x1b\xb8\x90\x11`\xa6e\xd3\x00'\xdd\xc3\xef\xae\x19H\xa7\x03\x97J\xedl7\x91\xcb\x0bG,\xd1'\x94\xb8]v+\xd8\x94\xe6RMS,.\xf8V\xf2\x9c/'x\xca\x98\xde\xbf\xa2?o\xcc\x92\x8b]\xa3\x0d\xf8e\xb9a\xb6\x0d\x18\xaf\x00\x8e\xe8\xb3{\xa3X\xa0a\xa15\x8b'\xa9\xfc\xd4\xb0z\xd9\xea6\x94\xa9\xb5\xee}\xcb\x1e;f\x04\xaev3}\x03\x899L[\xa2ua9\xd2V\xdae\x8b\xe8\xa9\x8c\xa8\xa5\xf8\"'q\xdf\xe4\xa8\xa9\x1c\xdd\x85tm(C7\x97;\x93\xa1\xd0\x0f\xb1u2\x14\xb5+\x96\xa1\xa8E`zr\xac\xfa&:\x15Dg\xf3\x0c\xe3R\xf2\xa0\xa1\x98mh\xaa\n\x12\x87pL@\xee\xd5\x93o\xc0\x95\xb92]\x99\xd3\\\x8f\xe3U% U\x16\x00ud\xdf\xad\xbcVY\xbf\x13\xa9G\x94\xaf\x7f)\x99G\\+\xa9\x88\xa6 f\x7f\x05\xef\x1el`]v\xb7\xd6\xa8H\xb2\xbcAV*\xeb?yeW\x05\x8fw\xf8W,\x16k\x83\xef\xb0\xe5\x9ef\x08\xa9\x06i\xdf'\xee\xe4(\xaa\xd3}\xcdF\xa8\xca\xc8\xc2\xfd\x11ee\xce\xe2Ji\xc3Q69\x05\xfe\"j\xba\xa9_W\xd4RC\xc9\xb2\xc7\xe1\xaf\xc5~VB3*\xb0}\xb5\x9cS\x8e\xd6F\xa1\xa2\xf0^\x12\x83\xca\xdfSK\x0b\xaf*\x1a\xfd\x87uo\xdb\xb2\xbay\xc0\xfa\x91r\xd4X\xaa7\x92\xc5\x82h5\x18P\x83\x00u\xae\x05\xfb\x16\x93\xae\x15\xc9\\L\x9a\xdb\x1f@\xc5\x0f\xadO`\x82\x91m&\x8bJ+\xc4\xe4R\x11\xa1\xd1\xff\x8e\x16\x98OGs\xc4i\xebS\xf4R\xf2\x98q\x88I\xd1\xde\x80\x80o_L\x98+\xac_E\x14\x05!\xae$v\x1eG\xc5\x95\xfe\x80'\xe1\xcf\xdb\xb65/\x16\xbe\nU~\xa5\xb1\xabp\x92\x87\x7f F\xaf\x0dZ\x83V{\x9a\x8e\x93_\x8b\x1c%\x08cW\xdd:\xf7\xd7l\xa8\xaa\x8c,\xda\xd7[\xb0E@\xbf\xbb\xa0\xe1\xe8^m\xbc\xba\x91[\x8f\x94\xb0a\xa0\xaa\x88\xfd\xf6\x15\x90C\xdb^\x15+\x9e8\x91\x1d\xcf\xe5\x0d\x03\xa2=\x90o\xcc\x03\x98\xde\n\xcb\xb1\xa3\xd5\xcf\xb7\x88\xb3zX\x0e\xc0\xcdD\xa9\xdf\x07Td\xc0E\xd1\x99\xf0\xb0.\xfb=>@\xe1F\x0d\xf0&\xcc(\xee\xc4\xf6\x8b7?\xa87\x02A\x02\x90\xe3\xf2U\xaa\xdb\x83\xaf\\\xfd_Dm\x1e\x02\x82o\xe8\xc2\xb6 \xfa1[\x0eS\xab\xd4\xc5\x9e\xc6\x8a9\x1b\x17Br{U4.\xa8\x14\xec \xba\xe5h\x94\xde=\x04|\x12\x083\xf4\x02\xef\x05\x08$\x94!\x83\x12\x93\xedBB\xb7\xcd\xf5\x06\xa1\xa1\x83\xc9Koo\x8c>y\xe2\x17\x8d`m`x2\xe8\xb5\x93O5\xe1\xfe\x1f\xe2Y\xe3Q\xa0\x9d\xff3:^\x1b\xdeg\x11n\x88\x8an\xebL)p%'Q(\xa6\xdb\xd1\x1ba91\xb1j(\x8e4\xb65\xd5\xa6\x00\xe85\xab@\xb1\xa4\xf3\xa9\x87\xd8\x94\xda\xcd\xa5\xac}\xd0\xd7\xc8\x98\xfc\x04Y\xe1\x06\x88\x8f\x8ez\x05\x88\x13v\x8c\\D\xa0\xcd5\xaf\x80V\xee\xa6\xddy=:R \\\xdb\xd1\x10\xb9\xfd\xb3\x86~H\x80\xba\n\x92\x83\x92n%\xb5\xf9\xf4\xb3\xf6(\xc5\xea\x94\x9acc\x91|m\x86\xbbH\x0c\x1aJ\xa5\x89\x03\n\x8c}\xc1\xc7\xd2\xbb\xed\x17\xd03C\x1a\xe7\xe3\xd6\xd7\x7f\xb1\xed\xf1b8\xe0\xe6\xdc\x81\xcfpf.f\x8b\xae\xdf?\xeev\x8f\x91\xe9\xfb6\xec\x1a\xab\xfeq\xd7\x9e\x14jct\x8a\x8fS\x0em\x10\x12\x03\x8c\xa1-\x94L\xde4\x95\xbeQM\xa7\x9d\x11\x16\xe6;\xd1\xe1\xf9\xe0\x9f\x11:\x04=\x82L0^\xa5\x9fPY%\xf7\x05f\x9f\xe1\xd8@1/\x15\xc6\xefH5\xcb\xae]\xa3\xdeC@\xca\x0fr\xea\xd5\xd4j77=\x17\xd4\xc1\xff\xc0|jzp\x11s)\xee\xf5\x0dK\xbf\xcf$f\xa0cw3\x14\x15\x18\xb5\x9b\xb2z\xf1 \x11\xed\xe3\x0c\xf1\xec<\xdd\x95\xf1u\x8d\xf5f\x05\xe0\x17\x91\xdc\xad\xd4Z\x8be\xf7\x85\x8b\xac5\x0d\xff\xc67\xbc\xbe\x1aGP\xa7V\xf85]\xa6\x18\xed\xa0\xce\x19\xa6=\xcd\xe4\xa2\xc6i\xbf\x94\xc0H\xaf\x95uW\x15L[\x0d{\xb5m\xa5\xdf|17]C\xd8\xcc\x1c4Q\xea\xb5\xae\xac\x1as\xf3\xed\xf5\x1e\xab\xe6e\xc6\xdf\x1c\xd9\x17\xed\xc82o\xa7\xff\x93\x0b\x88U}\xdb\"\xe4|\xfaU\xa3\xcf\xd1\xa9m'\xbb\x89\x12\x91\x88.\xd0\xce\x98%m6\xa3$+oJP\x1c\x80\x87)f\x01\x87\xc5+\xbe!10\x01\x8b)6\xa6\xe2K\x9f!\x0f,\xb0x\xc0\xce@x\x8e\x94Q\x81\x89O\xea\xc4\xc85\xec\xc5\x8b(]n\xbfA#%\xdbH/\n\xdc\xc3\x07\xe4\xda\xd0@\x0d$@\x85\xac(\x05\xe1\xc1\x1a\x82\x16\x80\x92\xf8\x8d\x86\n\xfc\xfc\xe6*\n6\xbd\xe8\x8d\xd8Zl\x19y|\x11\x1d\xd8\xb2\xe3\xa1^<\xf9W\x95M%Gg7\xce\x9a\xbe\xc0<#~5\x02\xa8D\xd3\xbc\xdb\xa8I8\x84\xa1)\x80\x12\x15\xb5\x0db\xd1\x1aV\xe3E\x94%\xa6S0\xd6M\xeeG\xdc\x86\xeb\xa8*\xe0\x87\xd4\xe7\x8cCy?r\xd3\x9a\xf1\x17(\xf4\xd7(#\xb8\n\x9dbo\xf9\xf9\n\xf0\xb6S\xe7\x9d\x8a\xe87\xb1\x8c\xc5\xf2\"\xbe\x8b_lwd\xc8\x9e\xec\xe7\x0b\xd3\xa5\x82Y`\xa5\x8d\xca\x98c\x845\x82\xc1/H\xd4_\xde\x96\xaf\xab\x12\xa5n\xce}\xc3*\xadpda\xb2\xfc\x0ed \x11\x89,\xce\n\x1c\xff\x16\xfe\x7f\xb6\x95\xa2b\xe9\xfd'\x83\xf4@\x1a}\x82\xf9jT\xfe:\xcdE\xd4NS\xdd\xa0\x0eM\xd0j\x01 _\xd7.z\xdf\xac\xb0;\x9bZ\xa5\xbf\xa7\x85F\x97\x0b\xe4\xf2\x00\xad>\xbf\xffx\x07qxw[$\xe0*\xd1@[%\x90\xf8\xaf2\xc2\xe0?Y\xfa\x04\x1dVMK4\x08S\x8a\xddz\xe8\x8c|F\xf0S\xc8\xa6k \xdfA6\x8d\x9b#lMy\xb1\x00I\x9eU\x9e\xf9\x0c\xadJEIDm\x85-n\x99\xa5\xf6\x14\x7f\x7f\xa6\xaeF\xe7\xb0\xa6l\xfaXV\xcd\x11 $\xcaLU\x89\xb2\x1b]L\xe4\xce\xfa=\xc3\x87\x8f\xd6\xec\x19\xc1\xc1\xb3k\xcd\x9e\x8e\x06\x9c<.\xcc\xe7y\x0fN\x8c#\xb3{\xbc\x07\x92U\xc6\x9d\x8c\xa3v\xf9=\x08/*3$\x937j=l< \xc6\xe1,\x8aJ\xb2\xf7\xb3\x95C\xb6\xfa\xe28\xcb\xbbX\xf8r\xcd\xe3\xa6WW\xfd\xeb\xa3^\xbb\xd7>\xea]\xf4\xbb\xbd~\xbb3\xe8\x0e\xcf\xfb\x83\xab\xf6\xe5\xe5\xc5\xd1\xc9\xf5\xd9\xe5\xa0\xdf\xb9n\xf7\xf6\x00xX\x8aE\x80\xca\x93M\xcb\xfe\x9a\x11_\xb6O\xfa\x9d\xa3\x93\xcba\xe7h8<\x1av\x86\xdda\xff\xfa\xbaw\xde>\x1bv\xda\xc7\xd7\x9d\xeb\xee\xc5\xe5U\xfb\xf2\xe8\xf8\xec\xe4\xf8\xe2\xaa=\xe8\xf5\xae\xba\x9d\xe3\x8b\xf3\xeb\xa3\xf3\xdep\xd0\x1f\x94kP\xe6q\xc0\xb8\xdb\xa3\xc1I\xf8\xe5Z\x05\xcf>\xa3\x15[ \xa0\xa3\x06(\xac!\xa4\xcc;(\"\x8c\xde\x9f\x944Wi\xd9\xcd\x1d\xe6\xcb\xbb\xb0\xaa\xa8\x06G\xfd\x9e\x8a)m\xaeA\x81\x07\x02\xb5\n\x91\x89'\xba\x83V\x102\"SH\xda\xc3\x92U\x166\x91L\x8c\x0c\x9d\x96\x141?z\xe4\xb1\x11\x90\x0b-4\x92\x8d\x1a\x81*\xd9cuH\xf1\xe0dU\xa0\xa3\xc8\xe5\xf2\xe5V\xe2\x85P\xfd\x036 ]\xa8\xcc\x1a\x87\xe5\x02\x9a&\xfd\xdf2+\x12\xc4 \xcay\xadJ\xbagA\xad\xec\xe64@w\x1b\xe6\xe6b\xae\xd6\xdb\x1d\xe4\x94G\x81\x0c[\x04r\xdfk6Q\x0dtA?\xf2\x13\x0b\xcd\xed\xd5\xef\x177\xbf]\xb6\xbb\x13vy\xe7\xc1\x93[>\xfe\xc0V\xe7\x9d\xc5\xf1\xf8\xe9\xe1\xb6\xdf\xff\xc3\xef\x1c\x9d<\xff6\xbe6\xfeX\xf6~\xbc\xb8^\x9d\xddX\xa8\xff\xc7\xbf\xee&\xefo\xfc\xf9\xf3\xf9\x9f\x83\xe1\xed\xea\xe9\x1d{\xba<\xb9\xef\xdc,\xf0\x95\xfb#\xfe}<\xf8xor\xdb\xb5\xfe\xf3\xb3\xd2\xab\xeb\x8fG\xa9\x00\x05\x14\xcd\x11\x94\x16d\x05H\xe6\xbb\x92\xa9\x82\xcc\xfbM\xc4D\x9e\x83 ?\x94\x0f$\xdf#\xc3\xed\xf6\x07\xb3Nv3^&V\x8a>\x15\xfb9\x9b?\xb7{\x1f\xa7\xfc\xfd/\xd3\x93\xb3\x8b\x8b\x8f\xcf\xf6\xcd |\xa0\xec\xed\xaa\x8dg\xd7\xff~\x7f\xf3\xf1\xddoG\x8f\xefo=\xca\xde\xa9=CCX\xa7\x9c\xa5)\xedZ9u\xad\xe2b\xe8\xc9G\xc4\xa8-\x13\x12\xcb\xb9M\x8d\xd9\xcdee\xad\xaf\x19\xf9\xba\xd0\xe393UI\xd63\x96\x14\x14\x19F\xa0\xce\xa9\xad|\x9d\x1e)X7ZA\x88w\x08\x9a\xa8z .\xea}#\x9cK\x0d\x8b\xc2!\x19\x8bN\xfd\xf1~7\"g\xad\xb8&r\x18\xe9G\x00\xcb\xfblu\xdb\x9d\xe3\xfdNw\xff\xa8\xfd\xd0\xee\x9f\xf6\x8fN\xdb\xc3\x83\xee\xc9\xf1\x8f\xed\xcei\x12M\x10\xdf\x19i\x1cJ\xd1@\":\xdb\x90q\xf9\xeac\x8a\n\xfa\xa5i)iQ\x8f\xd2\xb3\xd7\xe8\xf3\xa8\xafv*\xf6&\xf0QMq\x0c\xb2\xdd\xba0\xc9\xc6\xa4\xba\x90\x04-\xf9\xa89\xb8A C\x84\xf9\xb5\x01\xa1\xeb\xd6\x05\x114\x95\xe1o\xed\xee\xe2WCk\xc2\xc5k\xa2\xb9}\xd0U\xf6?\xcf\x91\xc7\xb0z\xf1_\x0d\xdb\"$\xb6\xae\xbd\xec\xa8\xc6\x05\xban]\xf8vdd*\x9b\x97\xa9b\x8d@\xa9ZI\xbb\x15\xabV\xed\xc8P3\xfa\x88\xab\x9bcR\xf4\xb59\xb7R\xf6\x05T\xb41\x12'\x92}o\x92\xdf\x14\xc6/e\x11\x8cb:\x8a\xb7\xfa\xaf 5\x12\x0c\x98\x98H\xb3>\xbc\x06\xbe0j\x90\x9f\xac\xfbI>\x9b`\xf5\xa8O4\x0b\xcb\x9b!\x0d|\x1e\xe3\xd0q7B\\\xc9\x19f\xf0\x16\xf6\xa7\x89D\xe4'\xee\xaf\x9b\xfbQ/\xcc\xf2SU\xa4\xe5\xa7 \x19\x90\x9f\xca\x049\xf6\x1f.\x8e{\xbf\xd93\xf2\xf4\x9f?\xae\x16\xd6\xf1G2\xb8=\xf9\xd59\xbe\xf6\xffl_\xfd\xda\x1b?\xce\xfd\xc7\x81\xb7x\xd7q\x1e~\xff\xc5\xfb\xe0\xdf\xde\xfe9?;{z\x18~|\xfc\x97u\xd7\xfepv\xf8p\xe9\x0e\xfc\xc3a\xf7\xec\xc9\xfbs\xf2\xef_\xee\xdd\xf3\xdf~\xfe9\x0e\xa9\xea\x15\x97$y\x1c\x94\xaf\xddW2\x15Y\x8b jXM\xb0\x91\xa9\xc9\xb8\x94b\x90\x96\\\xf5\x08\xf7Y\xc6\xe7\n?(\xfb\x82*\xd0\xa9\xc4\xb2h\xbb\xceVW\xa3ag\xb7#U\xb2\xf1\xa5i\xb0\xf6\xba\x90\xca\xf3Jm\xf5\xdel@\x85DNE\xa0\xdb\xe8)\x9az\xb8\xe1\xb3\xf2d'^\xf5\xaaq+\xac\xa7[C8\xf5\x06\xcb\xe9\x94\xf7=\xe7i\x8e\xc8\xa0{Bf\xf6\xd2\xf6\x9fW\xf3\x93\xe7\xe1\xe3\xd3\xa3\xe1\x18\x89L\xa7\xea\xe5\xf7\"-V\xcf\xff\xbeG\xab1dH\xac\xba\x03N\xe3\x87\xea\x00\xd4\xbcj\xb9\xb6\xba\xa1\x8e\xf7\x1e\x11\x0e\xe6\x18\x82\x0b1p\xf0\x91\xae\xa0\x85<\xf0\xff\xff\xdf\xff\xfd?q\x84[3\x7fjI\\\xfb\xef\xfcq\x1c\xeb\x16d\xd2k\x10\xc5\xb6>\x9f=\xaf\x81\x8c+\x08\xa9\xaa\xd3\x1a\xa0t\xe9\xd6\x82l\x04\xcdG\x9fq\x07\xd5\xa8\xfew\x0e\xe2\xbb='\x08mEG\xd4\xda\x15\xc3\x8eoC\x9e\xa3\xc4\x98R\x1bA\x92\x1fP\xfaE\xdb\x94\xa0]1\x8e\x9d@\x8c,\x18\x1d U\xaf\x9f\xff\xde\x80\x84P\x0e\xc6\xe2\x04\xb1 0 \x92\x9dG\x9f\x84\xaf'b>\x8d%qD\x89\xbd\xfaa\x0f\x80\x87\xb8\xa6\x13\x1b\xb3\xca\x9a\xb6\x99\x91\xcc\x95\xb4\xca\x19\x15\xaf8\x05 \x9c\xeb\x8f;\xcf\xc6\xa3\xe9#\xf7\xa9=\xf7\xbb\xcf\xd6\xcc\x9a\xf5\x86h\x02\xdb\xe4i\xf1LLH\x9e\xfaN\xcf8v\xe1\x91\xdf\x83\xees\xcf\xeazC\x8b\xb9O\xd6\xc0\x1a\x1a\xech64\xfcI\xd8ItA\x1a]\xd4\x10\xf5\x8e\"yq\xca\xe5z\x98z\x98W\x9eS\x8cE}_\xb02\xf9\xdd\x10@\xa3\xea\xe9U\xf4\xcc\x83\xab\x9a1\xa9bV\xd6.\xee2\x1d\xc2\x95\xb5\x94\x17\x0d\x97\xb6\x9d`\x12\xa0\x84\xb6\xbd\x1ae\x17\x8b\xf4\xd5\xf5\xfc\xfd\xb8\xcc\x1f;\x98\x8f\xd6\xd6pd\x81$w\x91\xeav\x94=\x94$\xc6\xa1\xb7f(\xd1C\x80\xdb`\xb6\x86\xee%\x82|\xa9N\xbdB\xc7\xfa\xc5\xd4M)Uu:\x9a\x17\xbb\xd6\x951\x14\xe1\xa8<\xc9U\xde\xf0\x17;\xb9\x83\xfc=\x88\xe1\xeb\x12\x1b\xe1 \xd5\xa3\x00=x\xf2\xeaEcD\x1fi\xe4\xa9*\x10-\xf3\xccD\x99\x11X\xc3\xe5\xeck\x13\x99&\xf5=\x13\x0dO\x1en\x18\xc7'\xb5B\xd7\x1f\xbf\n_\xf5\x08\xb1\x9d\xdf4\x95\x0e&\xf4\x167\xe3\x12\xc4\x03\x8akT/\x8c\xefGl\n\xbd5\nR\xe2@*\xa5\x98\x0e%xVq\xcd\x06\x9b\x88p\x9c\xbd^\xb7\xa0\xf1\x02\x8d\x19\xe6\xd5\x96q\x182\xfc\xc0}\x8f\xc43\xed\x86vM3\x07d\"\x0e\xb1\xcd\xd6\xb6\x1dSb\x8e\xf4\x0b\x13\xeb\xe3i\x01\x8c \xf7\xe0\x88/\xe5\xc2}^\xf5\xd2\x1c\xd6\xac+\xf8$\xc0\x13x\xa8\xa6\xe3H0\xacu\xb4\xa90gx\xdc\xdeow\xf6\xdb\x9d\x87v\xfbT\xfc\xff\x9f\x89\x8eE\xc7!\x1b \x8e\x07+2\xb7\xb0\x10\xe6\xc0\xe5h;X\xe49\x95- \xf3\xc5\xfb\xf3\x19\x1aWDTD\xeb$q\xaflE\x13\x0b\x903\xa3\x9a\x81\x94\x14O4\xad+\xd8\x94\xf0Z\xd95\xb6;\x8a*~\x8fD3\x99h\xad\xed\x7f\xbb\x9c,\"\xdc\xc3\xdb\xc9-\xe3i^I\x9c\xa9\xa9_\xa9\xfdT\x98\xb3\xc0\n\xedQ\x8e\xd2U\xb8\xa1icxH\x1e\x9d\xaa`_\x1cL\xca\x8d\x88\x86\xa1\x95'\xb6Kf\xbe0\xd1\xd2V\xbd\x88jI\xab\x0f\xc8|9z1\xcf\xa8 a2^ b\x8b*\xa3R\xa4\x95\xa1P\xa01\xd5\xeb\xe8\xb5Xe\xd0\xc0\"\x8b\xe6\xe5\x1c\x03;\x10*i^\x03j\x176\xcb]\xacS\x99\x0c[\x8a\xae\x19\xb2'\xe2\xbc\xe4h\x8b\xf5\xe9T:.69\x16\x85\x17\x9b`\xbf\xf3\xc766\xde\xa3\xea\xa2#\x9a\x94q\xac|{\xf9=\xb6\x08&V-6\xc92D\x05S,\x16AGt2a\xa8\xbc\xa1\xcc>F>\xe18W\xe2\xcf\x18w\xc6\x909\nO\xb6\x16\xc4\xab1\xc4\x1d\xf4\xa0s\xa1\x1c\xf2\xad29\x7f\xcc\\X\xa3\xc2\xcc8\x9ca\x12\xef\x8a\xac\x91\xcd\xb5n\xe12\x96a\xa6\x14\x9c\xea\xe0h\x95\xb19\x9e\xa9<\xceV\x99\x08[^k\xf9\xaf\x00\x00\x00\xff\xffPK\x07\x08\xa7j\"\x13n \x00\x00}\x0d\x01\x00PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00\x00\x00!(\xd4`4t\xc7\x01\x00\x00\xbd\x01\x00\x00\x11\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x00\x00\x00\x00favicon-16x16.pngUT\x05\x00\x01\x80Cm8PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00\x00\x00!(6B\xc8\xd7\x7f\x04\x00\x00u\x04\x00\x00\x11\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x0f\x02\x00\x00favicon-32x32.pngUT\x05\x00\x01\x80Cm8PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00\x00\x00!(\xb9\xb1\xf1mT\x02\x00\x008\x05\x00\x00\n\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\xd6\x06\x00\x00index.htmlUT\x05\x00\x01\x80Cm8PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00\x00\x00!(]\x12r 9\x03\x00\x00T \x00\x00\x14\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81k \x00\x00oauth2-redirect.htmlUT\x05\x00\x01\x80Cm8PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00\x00\x00!(-\xe3\xb5\x97=9\x05\x00\xf7\x0c\x1b\x00\x14\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\xef\x0c\x00\x00swagger-ui-bundle.jsUT\x05\x00\x01\x80Cm8PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00\x00\x00!(v\xf2\x8aA\x86\xba\x01\x00\xc5\x87\x08\x00\x1f\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81wF\x05\x00swagger-ui-standalone-preset.jsUT\x05\x00\x01\x80Cm8PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00\x00\x00!(_;\x94/\xe8Y\x00\x00\xa8X\x02\x00\x0e\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81S\x01\x07\x00swagger-ui.cssUT\x05\x00\x01\x80Cm8PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00\x00\x00!(\xa7j\"\x13n \x00\x00}\x0d\x01\x00\x0c\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x80[\x07\x00swagger.yamlUT\x05\x00\x01\x80Cm8PK\x05\x06\x00\x00\x00\x00\x08\x00\x08\x00E\x02\x00\x001|\x07\x00\x00\x00" + data := "PK\x03\x04\x14\x00\x08\x00\x08\x00\x00\x00!(\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x00 \x00favicon-16x16.pngUT\x05\x00\x01\x80Cm8\x00\xbd\x01B\xfe\x89PNG\x0d\n\x1a\n\x00\x00\x00\x0dIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1f\xf3\xffa\x00\x00\x01\x84IDATx\x01\x95S\x03Luq\x1c\xfd\x8c\xf1\xc3\xec0\xa7)\xcda\xb6k6\xb2\x9b\xf9\xb2k\xc85/\xdb\x8dqx\xc6\x94m\xcc{\xef\x7fO\xff\xf3l\xdc\xed\xf2\xe0\xfe\xf8\xc9\xffP\x14\x11/\x14[\xa3P\xc4\xa1\xbc?\xf1t>7\x12s\x13\x03\x85\xca7IR a\xb5j\x8f\xa71\xbe]\x88\xf6\xb9L\xf0\x1c\x93\xcf\xda\xe3)\x10\x93f\x8d\xe4\x06\x13\xcf\xde<\x9b\xd14\x95\x8a\x92\x81OA\xcfF\x89\xdd<\x9b M\xe6}L\xe4\x07\x15\xc5\xf5\xe3\xffI\x0c{\xd6\x8d\xffs\x994\xbasfh\xae?\xafk\x1aprw\x10 <\xb9\xdb\xc7\x86\xa6\xd1\x19I\n\xa8\xb1\xd7\x84y3g\x171T$\xb5c\x7fq\xfbbq\xbfk\x8e'\x1dQ\xb0\xc2,\x92\x0bx|;F\xe5\xf0\xef\x00\x83\xf2\xa1\x1fx|?q\xbd\xcb\xc2\x16\x80ZF\xf0\xc4J\xf3\xe3\xe4n1\xcc\x17k`:}\xcby\xe8\x98\xcbB\xc7|6z\x97r\xd14\x9d\x06\xd3\xf9\x8a\xe4\x94\x90\x8b\xb6\xd9\x0cP\xebc@\xd0|\xbe*\xc94\xc8\xa7\x98'\xcdh\x00\xe3\xd92\xa6vK}\x0cB\xa4\xf0+D\n\xc7\x81)\xb0\x10\x9a\xe3\xa9\xd8\x8bx\xe4(\xa2\xbb\x8dl\x0d\x01\xb6\x8a-\xf378\xbe\xdd\xc7\xa6\xb6\xc9\xd9\xc6d\xd8\\m\xf4\x0c\x92 uQ\x0e\xd2\xf5\xb3\xd1\xf1w\xdfQ\x16\xb34a$\xa1\xc4\xc4(V\xbcF\xd9\xdf\xa4\x91\xe9\xb0&,\x12+\xcd\x93\xcf\x1c\x1cb\xdc\xca\x00qt\xeb\xcc-\x14\x89\xfe\xfc\x0fm2j\x88\xec\xccs\x18\x00\x00\x00\x00IEND\xaeB`\x82\x01\x00\x00\xff\xffPK\x07\x08\xd4`4t\xc7\x01\x00\x00\xbd\x01\x00\x00PK\x03\x04\x14\x00\x08\x00\x08\x00\x00\x00!(\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x00 \x00favicon-32x32.pngUT\x05\x00\x01\x80Cm8\x00u\x04\x8a\xfb\x89PNG\x0d\n\x1a\n\x00\x00\x00\x0dIHDR\x00\x00\x00 \x00\x00\x00 \x08\x06\x00\x00\x00szz\xf4\x00\x00\x04|ID\xc4\xcf\xd0@\x04&%\xad\x1e\x16\x0f\xf7\x8d\x97AR\xfa\xca\xe7l\x87\x05\xf8\xd2\xfb\x0c\x84\x1d\x0dLVY\xdc/ju\x13\x1a\x88\xd2\xa0\xaaa\x82|nzp_\xf4\x03\xc8 \xd4;^\x8a9}\xeeu\x9a\x91 `\x04\x14s\xec\xe1\x0c\xc6]\xa3\x05``\xd1w\x12*~ \x00\xf3\xae\xd3\xa0\x9cb\x82\xa2bx(\xb3n\x1fqx\xd2\xf2\xda4\x1d\x8a}\x1ck\xd4>\x9cI+\xeb\xb3\xf4k\xc8u`L\x93\xf3]4\xb5\xd0\xc3\xe33\xd9\xee\xd7\xf2\xd9\x19\xea\x18\xc9\xc1Y:\x18\xfb(-\xadN\x82\x06e\xd5\x1f0\xa2\x1dV\xf8\xbe0\xc1\x985\x01\xf8\xd2~\\\xa6\xa5\xb5)&\xf6\x98V\x80l\xe4\x03\xf8\x03\x04\x00s\x9a^\xec\x85\x00\xf4+\x0b\x00\xe1:G\xf2p\x96\x0e\xc4,\xe46\x1e5\xbbP\xdd\x15J\x80}\xce\xa4\xe2\xc8{m\xa4\xe2\xc3\xc2\x01\x07\xc0\xdb\xa4\x18-\xa1\x931\xba\x10S\xfa%\xb6P`\x10\x19v\x99#|Gg\x9b \x10W\xf6\x8dI1\xba\x92\xd66\x17E\x12\xfa\xd9\xa8\xf3UTe\n\x1b\x95\x9d\x81f\xe5\x18\xa5umc\x81\x86\xa6\xeb\xec \x804\xcbg\x17\xa19\xfa\xc6\xf7<\xa3\xbd\xf2\x0e\x7f\x02\x80\x97Y\xc7\xac\x184$h\xa3v\xba! \xcc{\xcd\xb4!\xb1\xd8\x92%h\xe3\x93\xdc\xd3_\xda1\xe6\xaei\xcf\x83\xa6p\xbc$\xf0\xb2\xda\x94\xa2q\x14B@\x13\xdb\xff\xf3\xd7\x0d\xfaA\xb9\xc5n{\x8e\xd6Y\x08\x01u\xc1'~\x16\x8e\xe9\x04\xa2\xfbA+\xc74\x0c\x98\xab\xd7:\xfc0\xd1v\xaf$\xa2#\xb7\xf1\x08\xfdm!OXh8\x10j|g\xd1\xe0a\xb2\x99\x04\x9a[y\x9a\xbdk\xf24C$\xa0\x9e#\x9f\xa3\xa8\x001\xc6\x1a\"\xc0\xe4i\xa6\xcc0\xf3\xf7\xb7\xf5XE\xb8\xe0\xa1\xc9\xc2\x0c\x90\x83\x80$\x838\xdf\xd6\xe3\xd4\x82FNG\x0f\x876\x8a\xbf1\xa8d(\xa7@\x8cQX\x90\xdb\x19\x9f\xc5YG\xe9\x9e\x00\xa5y3]\x9aJ\xe1\"\x00\x00\x00\x00IEND\xaeB`\x82\x01\x00\x00\xff\xffPK\x07\x086B\xc8\xd7\x7f\x04\x00\x00u\x04\x00\x00PK\x03\x04\x14\x00\x08\x00\x08\x00\x00\x00!(\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\n\x00 \x00index.htmlUT\x05\x00\x01\x80Cm8\x9cT]k\xdc:\x10}\xdf_1Q\x1e\x92\\\"\xfb&\x81p\xf1\xb5\xfd\x90\xa6\xa5\x81\x94\x06\x92}(\xa5\x14\xd9\x1a{\xa7\x91\xa5E\x92\xf7#!\xff\xbdX\xf6\xae\xb7\xdd\x90BYX\x8f\xe7\x9c9\x1a\x1d\x8d\x9c\x1ep\x0e\x1f\x1f>\xddBe,8/<\x95 \xc9yKE\xeb\xc9h(Z-\x15B\xd1\x92\x92\xc0y>I\x0f\xae?\xbf{\xf8r\xf7\x1ef\xbeQ\xf9$\xed\x1e\xa0\x84\xae3\x86\x9a\xe5\x13\x80t\x86Bv\x01@\xda\xa0\x17P\xce\x84u\xe836}\xf8\xc0\xffc\x03\xe4\xc9+\xcc\xef\x97\xa2\xae\xd1\xc2\xf4&\x8d\xfbL\x8f*\xd2\x8f`Qe\xcc\xf9\xb5B7C\xf4\x0c\xfcz\x8e\x19\xf3\xb8\xf2q\xe9\x1c\x83\x99\xc5*c\xae\xd7\xe0-E!\xbb'A\xa5\xd1\x9bbjD\x8d\xf1\\\xd7\x9b\xeaJ,:\x9c_\x9c\xaf.\xce\xa3\x008zB\x97\xb1\x90a\x10\xff\x9d\xde\xd9\xe5\xea\xec\xf2\x17\xbd\x90\x19\xf5\xc2\xc6\xfa\x18\x82\x9bC\xf8<<\x01\n\xb3\xe2\x8e\x9eH\xd7 \x14\xc6J\xb4\xbc0\xab\xff\xb7\xb8Y\xa0\xad\x94Y&\xc0\x1b\xf3\xc4]i\x8dR\x85\xb0\x8e/\xd0z*\x85\xda\xe7\xf2u\x02=q\x83\xbdL\x86\xe0\x9f\xd3M\x90\x14X\x19\x8b\xe3\xbb\xa8<\xda7\xfb#=CK~O\xb40r\xbdW\xd8\x08[\x93N\xfe\x1d\xdb+D\xf9X[\xd3j\x99\xc0a%\xba\xdf(\xd5\xfd\xa7\xf1\xd6\xaf4\xee'\xac\x0b;\xf9\xc1OI\x0b \xb9;\x0e,OcI\x8b|2\x18^Z\x9a{p\xb6\xdc%\xf1~\xc6\xa3\x1f\x8e\xe5\xdd*\x81\x94\xbfY\xe1\xbc\xd0R(\xa3\x91\xcf-:\xf4o\x14\xf7/K\xd2\xd2,#\xa3\x95\x11\x122\xa8Z]v\x17\xec\xf8\x04\x9e7N\xc51\\\x85{&\xc0\xad\x9d\xc7f\xc8\x97F;\x0f-A\x06\xc3m\x99\xde\\\x85\x9e\x8fGG[\xab\x12`Q\xeb\x8c\xd8v\xfb_}K7\xd3F\xfe]\xb1\xa1\x82h%q{\x8b\x9b6\x88/\xc4i }\xc07u~}\xe5\xad\xfd\xc9\x98\xe7q\xd8_}o\xf1\x92%\x9dx\x15\x9f\xd3yO\xbdX]\x1aA\xc9>t\xd6o\x93\xd3\x92\xf2\x04l\xc5\x8d\x92jz\xc1jN\xd6\xf2\xa9\x87\xfa\xb5]\x05\xcc\xf9\x1acB\xa9,\x9f\xd0\x08\x05\xb7\x962\xec\xdb\xb6\xe2\x16b\xc6\xd5\x942H\x05KfI\x06\x7f\x9c\x98\xa8\xc0\xd5\x9c\xa2\x0c\x13\xa3\xe7U\x8e\xb55;'Nk\xe6\xd0\x9d;\xd4%^\x14\xbd\xd5\xf7\x92QN\x8e.\x1c`\x079m\xe3\x9e\x8a\xfe\xed\xa2\xad\xe0y>\xe6\xe23\xdc\xf8u\xa7=\xa3\xf6\xa1\x98\xb4\x17g\xa9\xf4\x1dA\xa8Z\xe4\xf6\x88_\xfc)\xf8\xd5N\xcf,\xea\xb4\xabS\xf2\xd2\xe0v\x10\x90\x82\xbd\xb3\xe1\xc1g\xc8>\x120\x0c{\x1d\xbd\x1c\xd1\x7fd\xb4\xbf\x82|\xf7\x9f\xd0\xa7\x1e\x82\xc5`H\xc0\x94F3p0$H.\x0f]v3\xaa\x9b\x1c\x83EW}\xba4\x12O`_\xb5!H5\xd1 \x9a\x0c\xaa\xcd\x04\x8cE\xe7M:\xe1\x08\xfe\xefQ\xab\x02\xfe\xb7A\xeb\xb6k\xbb\x05{\xef\x8e\xde\x84\xcb\x9c\xb2\x8f\x04\xd7U\xf9\x9aQ:\xbe\xf51\xf1\x1a\xaaW\x97uR\xdd\xe7\xf59\x974\xb7\xfc5s\xd0\xc4P\xdf\xdd\"\xd7\x96\xc2\xdab7x\xb8;\xfc\x01\xfa'\x00\x00\xff\xffPK\x07\x08]\x12r 9\x03\x00\x00T \x00\x00PK\x03\x04\x14\x00\x08\x00\x08\x00\x00\x00!(\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14\x00 \x00swagger-ui-bundle.jsUT\x05\x00\x01\x80Cm8\xec\xfdyw\xdb6\xf68\x8c\xff\xffy\x15\xd7\xfa\xf6\x9b!kZ\xb1\x9d\xa5\xad\x13\xc5\x93\xc5m\xb3g\xe2\xa4\xcb\xa8\x1a\x1fZ\x82,6\x14\xa8\x90\x90m\xb5\xf2\xef\xb5\xff\x0e.\x00\x12$\x01\x10r\xdc\x99\xf9<\xcf\xc3s\xdaX\\\xb0\\\\\\\xdc\xfdn\xc1tI\xc7,\xc9h@\"`!\xfc\xf9?\x00\x00\xbd\xec\xf4w2f=\x18\x0c\x80\xad\x16$\x9b\x02\xb9\\d9+\xe0\xd6-\xd3\xd3y6Y\xa6\x04\x0e\xe5\x1f}\xf5\xf6\x00X\x10\xc2\x01\xf4T7\xfaG\x132M(\xe1-\x8a\xbf\xfa\xf1|\x02\x87\xf2G0\x1c\xe1\x80\x0e\\\x839T\x7f\xf5\x8f/\xe2\xb33\x92\x7f|\xfedI'));&\xe6'\xffs\x15\xb0YRD\xd5\xf4\xd5\xd4s\xc2\x969\xd5\xc0\xa2\x1e\xf0\xeb<\xce\x81\xc1\x00\xfe\xbcz\xf0?\xe5M\xf5*\xd0 \xd7_\xe6W2\x85\x80\x0d\xf3Q\xa8\xda\xe5?\x14t\x1e\xd4^\xe5mg|t\xc3|\xc4\xbb\xa8=\xc4\xb6\x0e \x8fZw\xd3\x03\xd8\xdak\xdf\x96]\x1c\xc0\x9fW\xb5gW\xf5N\xe5\xa8\x08\x1f\xd58N\xd3 S\x83\x8b \x8b@\xfbEC\xfe3\x85\x01l\xedj\x0f\xca\xd6\xaand\x9b\xb4?\x87\x01\x90\x08h\x7f\xcc\xa7\xc5\xff\x98\xc0\xa0\x8ep\x11\xb4@F\xfb\x99\xc4\xc5\xf5\x1a\xde\xe2\xd2\xf7\x05J\xbc\xcb\xb3\x05\xc9\xd9J~\xd9\x86\xd08\xa3\xd3\xe4l\x99\xc7\xa7)\xb1\x80\x85.\xe7D=\xdfm??#\xec\x00\xf2:\xc4\xc2j\x8e|\x0e\xb46\x87\xe6\xe8\x15\x86 Z\x93\xfe\xc9 )^\xab\xbd\xd1\xc25\xfdR+\xc1\xe7\x1a/SV\x1f\x03\x1c\xf8}\xed\xb1\xd6\xb4? X\x04\xbd\xb8\xc7\x81\x1c\x01\xabO/k.Q\xb3;\xd9\x8c\\\x99E\x9e\xb1\x8c\xef\xca\xfe,.\xde^P\xb5F\x02\x9b\xf0\xfbz\xfb\x0b\x18@\xef\xf6$)X/\x02\x1a\xd0>'\x12w\xef\xde\x13\xaf]\x05\xc3\x06~P\xbd\xff\xde\xb2 P\xb0<\x19\xb3^59\x9d\xdc\xd0\xe0\x1b\xd5T\xd4D\xb5ZS\xf5\x8f\xbe\xbdw'\x0c\xbc\xbe3\x0f\x81\xe9+-\xb6\x08S+\xd9\x05PN#\xb6\x02\x02 -XL\xc7\x9c\xbe\xb10\x046\xcb\xb3\x0b\xa0\xe4\x02>\xac\x16\xe4(\xcf\xb3<\xe8=\x8d)\xcd\x18p\xe0B\x0c\xe34.\n\x88\x0b\x88\xcb\x1ezacG\xde\xcct\xaaG\x1c\xc1\xf3\x08)\x15\x0d\xf6\xef\xef\x87\xf5M\x94\xc0\x00\x82\x1c\x06\x90\x85|\x07\xe4\xf5\x1d\x90\xc3\x81\x01y%\x9cZ\x1bO\x1f\x8f\x01\x96M8\x96t\x98\x18\xc1\x8c\xafd9\x04|\x06|\x13\xef>\x00\n\x0f\x81\xf5SB\xcf\xd8\xec\x01\xd0\xedm\xd3G\xa0f\x8d\xc4\x99\x8e\x1e\x18\xdf\xc8\xfb\x15m\x81A\xfd\xe7z\xcd\x89\x11\xe4}\x9d@I4\xe9\x9d\xc7\xe9\x92\xf4 \xa1\x90s\x88\x05y\xff\"OX\xf9F\x18A\xb0\x1bA\xa2 \x10\xf2\xc9\xe5\xfdOd\xc5igk(\x0djo\xda\xb9%\x009.\x18\x08\xb0\xf6*E*\x16h\xdb\\\x1c\x04\xb9\xbc\xcf\xbf\xd6)H\xbd\xcf+\xbf\x1d\xa5\xef\xc4\xfaHJ\xc4\xa0\xc17\xf7\xef70\xadB,N\xca\xff\x9dX\x7f\xf7\xde\x7f\x0e\xe9\xad\x04\x84\xe8\x14\xe3=\x99\x92\x9c\xd0\xb1\"\x1b\x9c\xd7\x81Y\\\xd0\xbf18%\x84BB\x13\x96\xc4iR\x90 \xec@\xb1\\\x90<\x08kop\x12C&\xbd\xd0x\x86l1\x8e\xd3%c\xb65\x18@p\x9e%\x13\xd8\x85\x01\xe7\xd2\xe0\x10zK*N\xedI\x0f\x0e\x9a(\xcc\xe9\x1bg$+\xaep\xab\xe4\xed\xf8\xc7\x04\x0e\xf4s\xe9\xaf[R\x18@\x1cp\xec\xfa6l\xaci&\x1f\xdd\xb9\xfb]\xf3Q\"\x1f\xdd\xbd\x17\x86&>0n\xb3\x05\xea|6p\x05\xc4\x8d\x1e\xc4\xb6\xb9\xae\x87'\x16\x90\xdf\xba\x05t\x99\xa6\xb8\x92\xccr\xf6\x1cs,\xe1\x8ceN\x8a\x82\xcfs\xbe,\x18\x90\x84\xcdH\x0e\xa7D4\x90\xe5\xdaa\x14\x01?\xacz\xb0\xbd1v4\xd0\x8eT\x04\x88o5d@\xab\xd7\xf9\xe8k$\xca\xc8\x19\x16,_\x8eY\x96\x9b\xa0\x0d\x88\x0f\xe9\x92\x1c\x00i3\x85\xd0d\x1c\x0d\x8c%\xbf\x14\xdd6\xb3\x96\xd0fPw[/5\xc87'\xae\xf2PPk|\x88\xd3\xcfk\xc7\x01\x13\x92\xce\xc9 \xc2\xe0\xe4\x84\x1fT\x1b\xf2\x01\xb8\x1b*\xa0\xe7\xae\x83\xd6\xbc\xd5T+|\x85\x1e\xe7y\xbc\xd2x\xc3\"M\xc6D\xdb*\xa0o\x17f=\xae\xc5\xdc\xeb\x8b/\xf9\xceqNbV;\x99\xc20\xd2\xf1\xa4\xaf-9\xe7\xc7\x1b\xdb\xc8<\x14\x03C\x0f\xd5\xee\xc5}-6\xec\x8b\x80\x84^-\xe6\xce\x16\x97U\x8b\xbf\xfa\xb6\x989[,\xaa\x16_\xfa\xb6\x98t\xcf\xfa\xd6-\xd8J\xab\xa6\x7f\xf0m\xda@\n\xb5\xa6\xb7\x82-\xc1\x1c\x91\xe1t\xe4\xd7\xe0\xd2\xb7\xc1\x85g\x83\x85o\x83\x13\xcf\x06\xd3\xee\x15_\xaf\xb1[\xaf\xe6\xc6\xbe\xe3\x9b\xb5\xc6\xa7\xffbA.X7\x16d\xea\x8fD\xfcA\xfbI\xf1\x9c\x95\x9ck,\xee\xbc$+\xc2\xc5\xf5\xa5|\x81N\xc8%\xde(\xc4\x8d\xc7E\x91\x8d\x93\x98%\xe7\xfc\xa3T\xdc|\x9bOH\x8eo\x8d\xf9\x0d\xd5\x06\xef\xba_\xb5\xc0\x07\xd0?&\xfc\xbcJ\xda\xf4c\xca\x05\xc4\xbf\xff\xfd\xe4\xe4\xf9\xeb\xd7\x1f?<~\xf2\xea\xe8\xe4\xf9\x87\xa3\xf7\xf8\xc7\xc9\xdf\xff\xdekS\xd6E\xfb\x8b\x97G\xbf\x1e=\xb3\xbc>1t\xf0\xe6\xd9\xd1/\xd6\x0ff\xed\x0f\xde\xbe\x7fv\xf4\xde\xfa\xc19\x0c\xe0^\xfb\xf6\x1c\x06\xb0\x07\x0f\x1f\xc2\xb9A\xf1\x00\x03\x98\xc3\x0e\x18\x8e\x96\x15*\x9c\xda\xf7O\x8dZ\"\xa8\x8e\xb2\xad\xbd\xd6SC3'\xd7i\xc6F\xcb/\x9c\xd8J\xfa\xd8$g\xc4\xf6\"O\x92|dn\x91\xc8\xa3\xa1lp\xd7o;]\xf2\xd3\xcc\xf6\xf0\xd8q\x12q\xbee\xbd\x86\xdd\xb6\xf4W\x13*_\xc7l\xd6\x9f\xc7\x97\xfc\x90&R\xb2\x84\x1dT\xb4\xf0c\x88\xb3Tx8\x06\xa8O\x13Rh\x06\x0f\x81>\x80\x8c\x8b\x9f\xf90\x1b\xf1\xe3j\x98\xc160\x83\xac)A\x99{\xcd\xf6\xa9s94\x9e\x8c\xf4\x8b\xe4\x0f\x05S\xfcs\x80\x0cE\xc2\xe9\x02#\xc1cq\xba\xf2'^\x1d\x7f\xb2B\x12\x99P\xba\x9c\x9f\x92\xbc\xc6\x82\xba$o\x8a\xd0\x7f\xf4\xe8\x91 \xfc\xa0\x1a\xe5|&\x15\x1c,_\xa9\xbb\xfb\xdf\xdd\xfd\xee\xfe7\xfb\xdf\xdd\xc3\x19\xd2R\x05\xfb&~cn\x85/2m\xe3\xba\x0d|\x0c\x1e\xc2.\x1c\n o\x03\xab\xc9,\xe0\x00\xcec\x97\n\xaf\xc1\x14\xda\xdaxkb\xe2\x1aM\x05rm94\xe4Zs\xe8\x08\xa1\x1e\x1e\x0e`\x87\xe2\xc9^g\xce\x0d/3x\xc4\x01\xe85\xb0w\xd6\x95\x97\xa3z-G\xee\xb9a?\xf8\xb6\xc7\xfc\xda{\xed\x018}c\xc0!P\xce]\xcb\xc5\xd6\xf77\x83m \x9c\xf5n\x087\x9cC\x12\xef%\xa8di\x9d\xf4\xfa/\x8e\xdf\xcf9\x1dhS\xe6\xdf\xf9y\xd1\xbe\xfd\x06\x06\xb0\xdf\xbe\xfd\x9e\x9fR\x95tW\x19K\x8eW\xf3\xd3,\xe5\xeb(\xfe\xea\x8bM\x9d\x19\x8c \xcf\xc4I\xa7^0\x1cm\xaf`\x00\xef9\x8e<\xb3\x1d\x01\x1f\xcd4\x87\xcd\x92\xa2O\xc9%\xf3f\xc6?\xab\x95\xb2\xe8\xa8\x94\xc1\xa4Z(\xbe\x05\xf7j\xcb6\xe4\xdf;\xa8(\x1cB^\x9e!\x19\x1c \x91v\x9e\x86\x99Y\xb2\x9bd\xd4v\xe2z\xd2\xea\xef]T\xc19$\x81~\xcequJ\x9a\x96A\xfd\xe1\xe6>\xb7~\xf4ec\x9f\xb8\x19\x83\x866H\xb3\xf4!\xcexu\xf1\x93\xb9\x0be\x91\xe1C\xb5\"\x82\xd4!\x08\xa3\x85\xdf\x8c~tw'\x0e\xd3\xf7Hk\x87\xefG|\xcb\x90\xe1\xb3\x91a\x08\x0d\xb5\xcc@?\x13\xd5\xf0\xbcF\xf4\xb3\x07\x8c\xd5\xc9\xabCXp)^]\xbcpv\x81\x1a\xa0\xe6\x91\xa3\xb6cB\xd0 \xab\x84\xe8>\xcb\x8e\xc9g\xbc\xa5Z7\xb7\x0d\x1aP\x0b\"\xc5'\x93M\x18\x95X\xe4\x02\x181\xae4(M\xa9M\xbfut\xb9 cF&\x82A\x83,\x87DIE\xa27\xc8\xa6b\xcb\x15\x11\x7f\xfa \xa5\x1b\xf1\xe8\x00\xb5\\\xb6n\x8d\xab\xc8\xaf+_d\xfb\xf5\xcb\xe0\xdeg\x19\xcab\n\xe2r\x11\x96\xed\xb5 \xfdi\x9e\xcd\x8f(\xcbW\xe5\xcb\xc4w\x94/\xbfl\x94\x86\x81\x11} |\x9cR\x8aT\xb7\x96\xdec\xfb\xc19\xb6\xe0\xcb\x07\xa7F\x13\"4\x19\xdeo\x8cL\xff\xf5QSU\xb1\xec\x98\xe5 =s)\xdd\xb4\xc1\xf6\x86\xcf\xe5\x01=\xea\xd5{\x88\xe0c\xff\xe5\xd1\xaf\xc70\x80\xe7\xfc\xef\x9f\x1e\xbf\xfax\xc4\x7f\xfd\xce\x7f\x1d\xbd\xf9\xf0\xfe9\xfe|\x13\xd5\xfaOh\xc1Q\x1f\x06\xcdQe\xcb|Le\xf2\xd9\xb3M\xd3\xd8^\\\x7fQ\x11|''%\x00{|$\x7f\xf6\"\xe8]\xf5\x9cc\x1e\xc7\xe3\x19yO\x8a\x0e\xeb\xa8\xd6\xd5\x96\xe8\x0b?\xc4sOt-e\xbd\x8f\x14\x1fL\xf0\xfc\xd2\xdf\x1c\x88\x17+\xac\xef\xb3L\xc8\xb2a$\x1eI\xc1Q\xfbH\x9e-\xf2\x05\xd74\xca\xfe\xbb\xac\x18\xdaDR\"\xbdx\x04\xa3\xd8\xd2\x01\x98{\xc8\xf2\x0d\xba\x18wv\xc1\x82_#x\x11F\xf0km\xf1\x15\xbd\xf5\\\x133\xa6\xbf\x14-\xbf\xf4\xc7\xf4\x97\x0eL\x7fY\x1b`EI=\x9b6\x0d\xf1\xe5\x0d#\xfc\x90#\xfc\xa8\x8d\xf0/o\x18S\xf6\xbcz\xf8\"Liw\xc1\x82\x1f\xc4z\xfe\xe0\xbf\x9e?8\xd6\xf3\x87\x06\xe5b_\xb6\x96/\xfaI!Z\xc8\x08\xff\xa5\xb4\xb7\x1c\xbd\xa5\xba\x96\x8f_S\xe4\xbelko\xbf\x8a\xe0\x9f\x11\xfc\x12\xc1?\xdaJ\xd3\xe3\xa3\x7f\xa0\xc2\xd4&9\x12\xe2\x10\x1dOb\xe4\xca\xd0\xa3L'6\x1b\xb1\xaf\xcc\xd2\x83\xe2/\xa5q\xe9\x13Y\x15F\x1eR\x8cDr\x83\xd5PN\xf8\x07\xc2\xc7\xadF\x077\x19\x1auN>\xa9\xf4\xf3\x96\xf9\xa3\x80\xe1\xaf\xa0\xcb\xbb\xbb\x93\x86\xb3\xa8q\xef\xa9<\x0c\x86#\xaf\x8e2KG\xea,\xaa\x0c\x18\xff\xf04\xb0 7fm\xf0+\xdeZ\xf0\x95\xd4\xb5\x12\x12\x0cG\xa1_\xbbq\x07r\x08\xa3fR\x883\x0fy@\xd9\x05 \xdb\\\xf3\x93\xea\x8d\xdc\xfc\xc6\x1f\xd5\x1b\xd4\xfc\x86Q\xca9\xac\x84\x9cR\xf5d\x16*\xbfL\xd2\x19~\x8a\xe0|\x04\xfc\xb8O6\x92x6\x92Y\x97\x1d@/\xcc\xc2\xdc\x97OO\x08r74\x8b\xc2\x8d\xe4?7\xb0\xc5\x80\x1e\x06|(W\xd7k\x08)\xf1T\x97\x11\xc9\x9a\x99\x81\x9a\xd9D\xf0\xd2\xca\x91\xf0\x03\xa2\xb2l\xecE\x10\x0b3F\x0c\x0f\x07\x90<\x80\xd8\xeeF\x07r\x1cK\xde\xc6\x90r\xd1\nv \xe6\xb2\x95\xc5\xad\x0e\xd4b\x0b\xbd\x1e\x0b\x96\xc3\xbdQ\x84\x8a\xbb\xe5pw\xc4\xbf\x8c\x80\x84\xa5\xa6$\x86mh+\xe1\xa0%~\xa9K}\xd6zhU\xfb\x936\xab\x8c\x9et~Df\xfc\x17/\x93q\x85\xac\x90\x15+\xe7\x02\x0c\xc7\xc6\x8f\x81\x93\xa5P\x97r\xfe\xf0_X\x05\xfc\xedmx\x04 \x1c:\x1a\x07?u\xa7\xba\xacjOu]\xc1\x01|F\x07F.\xcaKL\x12\xe8L\x86{\x8d\x93\xa8\xfc\xa8}\xdb\x03M\xb2\xfc\x1ax2\xb5;\xb1*\xca\xa4y\x94\x0b_L\x8eR\x11XQ\x83\xe3M\xfd\x0c\xa3\xd5\xbe\x91\xba\xcf\x0c\x9bx\x19\xd0\xb0?\x8f\x17\xd5\xba\xbb\xda\x05m\xd2\x08Q\x0c\x1d\xa06\x10:Ts\x13b\x1d\xd2\xaf\xff\x81!\xa9-\xd0^t\xb4\xeaD\xd0\xeb\x99|\xcd\xf8\xd5\xeb5=\xf7\xf0;N\xd3\x17\xde*\xab\x85\xfbT1\xf0#/9\x1b\xc1\xa1\xb4 \\:\x7f\x95\x14\"\nfB\xc4\xf3_\xeb\xcf_\xc7\x0b\xa1\xbb\xf2\x1a\xce\xc4=\x1ce=\xae\xf9]\x0d\x14O\xdd\xd4\xaa\xe9\xaf\xf9Acf\xdf\x11\x1cwHe\xbe$\xb0%\xf5\xef\x0c-\xcc%Fm\xd9\x18%\xc1\x82j/\xeem\xa0\xa6\x97N\x08o\xa7V#\x06So\xb8\xb6f \xb8y\xf9f\x10\x868\xa1\x00=\x0f\xf4\xbb\x9bN\x10\xec\x93\xf4\xa7f[f\xc7Q\xd2'\x9f\x97qZ\xa0J\xde\xf4\x02\xd3^\xd8Ro\x07\xcc\x93#?\xf7Z\xf2\xee\xe5\x8d\x03\x11M\xa4\xd9\xb5+\x87\x07\xed&+o\xca\xc7\xda\xcd\xe6\xe7''\xb3\xb8\x98\xb5\x1a\xa8n\x97\xaf\xd4\x1e\xac\xd7B\x7f\xcco.\xe5\xb0\nu\xa3\x907\xc6\xea\xc6\x18=\xa5;\x90\xb2\xe9\xc1!\x0d\xd1\xf8\xdb \x1b\xe5Z\x81\x9e}\xe6\xb6\xf9H\\\xac\x06J\x88})#\x04\x1d\xe6\x8f>9'\xf9*\xe8T\xa8\xa8K\xb1B9\xda\x00\x83P\xec\x82Nv\"\xe3@\x98\x91 CNQ8/\x06\x94\xc3\x15o\xeeb\\\xa1\xed(\x00\xf4\xdf\x97\xfdq.\xc2c\x8f\xa8q\xda\x16\xa8\xe5gc\xee\xbc\xf1\xaaZ@\x0b\xcd\xd1\xd5\xbe\x88m\xda\x0d\xdbB\x90\xb4 \x0exg\x0d\x0f\xf9\xe6\xa5xK\xc7\x12\x10\xa9\x05\x81\x01$f\x08\x1b\xa17\x15\xc10\xc6/\x16 \xb6\x8frE*\xd1\xc7\x14<\xa8_\x1c\x9e\x9c\x13\xdd\xc2\xd8\xb4\x00\x9d\xa43\xfe{\x86<\x01\xe9\x9f\x11\xf4\x8a\\\x85\xfc \xbf\xab\xddB\x1cQ\x185\x95\x1ek\x06\x8a \x885V\xf1q\xaa\x11\x13\xbe\xa8\x0b/\xba7w\xd3\xbd-T4\xea\xf1bsM\x02\xe2\x1c\xbbj\xc0\x8c\x8fB\x9f\xa3\xbc\x1e\x1a\xfa\xa4\x86/\xcb\x1e\xdc\x86\xdd\xd2\x9fE\xfa\xbd\x84\x91zC}\xe8:\xd8\xfeY\x0e\xed\x9ff\xc4\xf9\xa7\xb4\x19tl5\x1b\xb4\xce:\xa0U\x8b\x8c\x11*\x02O_\xa1\x15q9\x0b\x99\x97b\xd5X\n\xad\x0d\xf3j\x9c\x91@\xbaZE\xa0\xe2\xfb\nF\x16\x10\xc3\xfb\x98\x9e\x118]\xc1n/\x8cpo\xe19\xb4\x1b\xd5W \x0d5\xe8[z\x1bv\xc3\x08i\xba\xf6\x02\xc5e\x94K\x18\x9f\x16\xe8z\xc8\xe0\xa1\xe4\xd8\xf8\xdb;T\x99pN\n\x16\xe75\xdd&\xa1\x13M\xb5y\x82C\xc3\xc1\xeaX\xa3\xa3\x07\xfe=&I\x1a\x04\x0cv8\x01\xbe\x0d\x94\x8bV!\x97\xcd7\xc3\x9d_JX\xfeb\xc6\x9d_\xbe\x0cwN\xcd\xbaD\x81/\x9aJ\xe9\xf1i\xc1\xf2x\xcc\x9a\x96 K\xb3'\xc4\xe5fz\xe1|z$\x9f\xea\x0f53\xd6\xf0\x1f#\x15`\x1a\x10\x12\xc1K\x8e\x19z\xdc\xc3\x19\xe9\x0c\x04\x82\x86\x15\x86\x93G\x94\x0f4M\xfb\xf0\x932g\x84\xa3\xb6gc\xa3\xcf\x8dL25\x7fY\xadG\xe9![S-U\x1e\xb2\x03\xc8\x85\x8b\xac\x15W\xa4\x8a\x88\x04t\xc80\xecn\x07=\xba\xb2\x11\n\x7f\xbc\xa3jgf\x1c\x15\xadT;\xf3\x9a\xac\x9fu\xc84Q\xe3\x14Z\x937\xbe\x95\x9956\x9bikJ \xaa7\xbd\\M\xa8/\xf4\xc3CbD\xf9Z\xdf\xb3\xb8p&\x02\x80\xa6\xa5S4\xdd\x08\x93o\xa9\x02\x1a\xbd|\xe9\xc6\x12\x9d\x8a\x9dU\x99\xaa\"\xc9V\xeb;-\x11;-\xe1;-{\x00\x89;\x16:\xe6\xdf\xe3bf\xb0\x03 \x1c@b\xd1\xf35vf<\x8a n\xee\xc6\xc4\xa8\xb4\xb5\n\xa3\x89\x17\xc8\xae\xb3=%\xb8\xac\xfbS\x03\xa1uw\xe6\x9d{8\xb9\x89=\xbc\xd9*(\xc8\xa1\xa65\xfb\xf7\xed\xf9\x98\xef\xf9\xd8o\x8fk\x8b8\x9cU\x87\x1c\x95\x87\x1c5\xee\x8b\xd2[\xc5c\xad\x91\xf7\x0dk\xbb\xb2&4iB\x86\x85{V\xd8\xf2SP7\xcb\x86v\x94\xb1\xe8$\x9e\x04\xd4\"\x83\x96\xbb8{\x00[\x01F\x9cKyT\x08\xa4\x18\x8b\xb7'\xb4\x10A&d\xe2\x08\xf2\xedm\xb9\xab\x1e\xd8\xa5\x91\xbc s#L+}\xf5\x8d\x025\xcb7\x86\xaaE\x9d\xf3D\xd7\x12\x8b\xed\xf2\xbd\xa5Y\xcb\nl\xbe\xd5\x98\xb6\x0e\x1dZ\x0e\\$\xe1\x8c\x8e{@,\x8dX(\xaf\x8d\x10\xe4\x12\xe5\xf3\xff\x02\x94\xaf\x0e\x15\xfd\x14)C\x08D\xca\xa2\xb6\x83\x80~\xa0\x94\xc6\xa8\x07\x1e\xcc[6LF\x11'T\xadC\xc226\xbeK\xa8\xa6%\x12\xbb\xe4A\x17\xdd\xa4.m\x12\x9a\xd8\x86\xc9H\x84C\x96c\x8b\xeb\x03;\xcdI\xfc\xa9\xbd\xa06lk\x1d[\xc6\xe5\xfd\x8f\xed\xbe\xc6\xc2Z \x9ai\xb1\x8d/\xdf\x08\xab\x8a+\x01\x8f\xaac\xb5Ka\xd8\xbdQA\xc1\x0d\x11\xa5\x02\x9eC\xb1(\x82\xf2\xe4\x1e6\xbe\xe6\xb4.+\xf67\x1f\xfa3\xbcsI\x03\xe6\xe4\xfa.v\x0dA\x1b\x0e\xa1\xf7\x9e,H\xcc`8\xea\xc1A\xf5\x0b\xbd \x98\xa6\x16\xda\x86^u\x0f\xbf\xe5wX2'\x05\xb4\x9d\x8e\xe7\xd7g\xcaML\xb8\x18\x82\x81\x01\xaf\xf5\x93\xd0q\xba\x9c\x10o.|Ft\xc5W;*\xab\xd1<\xa6,\xf0\x99Hm\xffpPYQ^\x8b\xd9\x13S\x85\x03\xa5\xad\xab\x8d\xec\x83\xb0\x13\xc3\x8e\x08\xa6k2\n\xcd\x91\xe6\xe4\x9c\xe4\xc5&n\xda\x1dp\x9d\x90\xcb\xb7\xd3\xeb\x83\x15\x0eQc\xb8\xb3\xe7\xec&\x8d\x0b\xf6\xfc\x06\xba\xaa0\xb4\xb3\xcb\xeb\x0bS*UT\xb9\xc4\x98+\xcaJ\xb0\xca\x03\xa36\\\xda<\xd1\xa8S A\xbd\xe6\xb2\xb9\x94\xb3\x11\xab\xba\x19\xb1Vl&<\x04\xaa(N\xc5\x02Q \x89\xd0\x98\xf0F]7\"~xP\xd8\x1a4\xa5\x91\xd2\x13\x0fI]\xf5\x0e\x87m\xcc\xd4\xa6z\xde\xb6\xf7s\xfa\xbe\x92\xf4}u\xc3\xf4\x1dU\xc6\x8a\xbc\x8b\x1f\x1au\x17\xda\xddm\xe8\xf5\xfb\xfd\xea.\xa1\x13\xd8\x86@\x08\x15\xeaE\xb2\xe0\xed\xc1\xe9\xaa\xf69Y\xf0\x86{!\x9e\x07\xed\x93`u\xb3'\x81\x1an\xa5\x8b\x84\xaf\xebCi\x9d\x11\xabk\x9d\x11\x8as\x08\x08\xec\xe8}\x87p[\xeb\xcf\xba?0@zW\x18\xe452!n\xf05B\x9d\xf84\xcd\x0c\xb6\x87\xc6\x90\xbd\xcf\x9d\xc6\xa1Rv\xaa\x1d.\xe8R \x02\xb2\xcb\xa7\x91\xb0\x15\xe0\x19S\xdd\x0d\xe1\xe1\xa0\xf4-]\x91`7\x82\xddP\x1eO+\x89\xdcg\x84\x05\xbaU@\x99\x0c\xf8}f\xb8\x8f k\x9f]\xab\xeb\x1c6\xe7eTemy,\xf6-\xf8\xbf:\x92\x0c\x06|.vi@d\x17p\xaf3\x94\xf6D\xb5\xd0\xb5\xf3 4\x13mp\x89\x03\xed\xc3j\xf5\x85\xe7#\x0eGB\xd4@sV7s\x16V\xd8\x8dz\xc3J$\xe0\x90\x93\xf2`k\x03S\xf8\x1a\xf3\xe0iw\xeb*G\xeaT9\xd6%\xc4\x08\x12\xa3\x06\xd1\xbcl\x19l\x8b\x11\xed\xf0\x01\xe4\xfe\x0b\xd4\x92\xd7\x8c\x00\xdc\xfc\x00\xae\x80g\x1co\x03\xa0\x969\xf9\x02\xd9\x0c\xce\x9b8\xec\x95 \x9d9\xd5!\x0d\xe8\xf3E\x7f\x84\x16\xc9\xbf\x98\x03P\xca\x17\x94\xd7c\x1f\x91kuC\x0c\xc1\x8a4\x16F\xf8}\xc8\x1fe\xb8\x1d\x9aU\xc5\x13\xfegy_\x92,\xf9 \x9eq\xe7ed\x91\x81\x8f8%*\x9d\xd3 \x89\xe0\x94\xe0\x9f\x17\xd5\x9fG\xea\xcfSRF\xf4\x887\xb5@\x1e\xf1\xbe\x0c\xf29jH0|\xa1/\x89-\xbb\x04\x9el\xc9|\x89 &v\xf6\xab\xd3\x8e\xdf\x0b\xaa$,\x11\xec\x87*\x7f\x06\xbe~\xe0\xbfk\xee\xdf\xbbw\xe7\x1e\xdc\xe2\xe7\xd9\x9a\x13s\xfb\xc6)\xdfd\xe2M;\x92\xe3^\xd9F\xb7\xbbG\x8f\x1e\xc1\xde\xfdP\xde\xe1O\x02V\xde|\xf8\x10\xf6\xee\x8b\xdc3!\xac\x9b\xce\xf8\xb6P\xa6\xe3._Il\x1en\xc1\xde\xee7w\xbe\xb9\xbb\xf7\xed\xfe]X\xc3\x9d\xfd\xfd\xbd\xfd\xfd{w\xbf\xe1O\xfc\x9c2\x9fZ:\xd2)&\xac\xd7\x8e\xe0\xeb\x92\x86Z4\xd5\xdd>\x8f\xaa\xa3\xb6\x07\xa3\xbb\xe3\xae\x9e\xb7\x9a#4Px\xc5\x18\xa8qY\xe6P\xa5=\x18\xd8}\xce\x12\xf4)\xdc\x92C\x15\x0e;\xc2\xa7\xc21P\xd0\xf0t\x17\xd66\xe7(q\xec\x8d\xe0\xbd\x80\xf5\x1b\x993\x83`:\x1cxF0\xf1\x19>\xe7T\x1c\x1b\xe7K}\x9d,\x0bp :\xdb\x08\xc7gq1{\x9aM\x88\x06\x19u\xcb\xa4\\\xc4\x96\xaa\x90-\x1d\xa4\x9e \xb43\x9e\x1f\x9a\xbe\xaa\x08\xbfw\xc2c\x8d\x84a\x97\x1a3\xa9\x9c\x0b\xcb\xaf\xc9\xf09\x19y}\xb9\xf5\xd6:n\xb05\xceOS\xb4q?/\x8e\xaaT\xd8\xe8\x0egz\xe25\x16[g\xdd\xe0\xd5\xbf\x96\xa3\xa0\xd9\x84|X-\xf8\x96\xdb\x0d\xa1\xb8H\xd8x\x06Au\xbf\xab)~\x8d\xe3\x82\xc0\xdeA\xe7{\xa0\xd1\xfe\xfe\x92&\x9f\x97\xe4\xf93\xfb\x1c\xd5\x85\xcd\x7f\xb7a\xf3\x93l\x8c\x01\xc3G)\xe1\xff\x88\xc96n\x96cp6mVj\x83\xdcR\xdaj\x19\xdf3\x7f\xcd\x97k{\xfb5\x89\xf4\xa3\xef\x16\xbc\x16{\xff5\xee}G\x88\xc8\x07\x12r\xac/\xa4,z=G\xd7\x06\n=V6\xd5\x01\xfe@\x97\xe7\xa6\xc7`\xefMFw\xc8%#\xb4H\xaa@\xc2\x02\xe2\x9c`\x92\xe38M\xb3\x0b2\x81\xb8\x80OdU\xf4\x9b\x89\xb3\x9b\xdd\xf3\x0de-n\xf1\xdc\x98\xc3X\xbf|\xd2\x11\xab\xab\xbb*\x86~iI\x8c;\xde\x94|\xbay\xf1\x01\xcc~\xb1\xea\xc2\x15j\xac\xc3\xa6$C\xb2\xc9Z$\x89\xc6\xc1\x9b>\x08\xad\x0d\xb9\xd5m\xfa\xa5\xcb\xda\xfe=\xf7\xe3\xc5\"]I6\xde\x12\xd1\xaf_W\x91\x83L\xf23\xb0\x03\xb2\xddD\xb0\xe6\x94^\x91\xbc\x16\xde\x7f\xa4\x08!\x96AA\x18\xc4@\xf9>\xa8 \xa7\xc6\x08\x19\x95{\xc2\x89\xfa\xfc*\xe7`\x9f\xfd\x06\xf4\xc4y\xeaot\xda+\xe5kI\xd68\xc3\xa0e\xb41\xe6\x03h@\xeb'4]\xf1&\x85\xd6\x14\xd5\xa4c\xe1\xd4{J\x80s\x0fd\xd2\xf7\xf4\"\xfdd\xe1\xedKu\x0c\x13\x8c\x92f\xa1 \xf5b\x16\xfc\x85;{\xf0\xb5HU\xd8\x1f\xcf\xe2\x9c3/\x8fY@Q\x98\xb1\x8aG\xc7\xa4\xed#\xad\xff\xe2\xbd?&U\xc6\x84\xa48*ic\x9bj\xbc\xf5\xdaa,_9\xf0V\xa9;\x8d4\xf3\xcf\xab\x08z\x7f\xefE\x82]\xb4\xea\x04\xc6\xb18\xe2]{\\\xf6cs\xf57\xa0Y\xd8\x16\x97\xdf\x91\x08>XE\xe6\x9fI\xfc\xe9u\xdc\xd02\n\x06/xGd\xe6\x02\xf9\x92\xa1qqF\xb6\xa1\xfc\x1c;<9I\xe6\xf3%\x92p\x8em''\x8d\x14\xed\x1d)\"\x03lE\xfc\x0e\x9e\x93&\xd2\xf3\xfe\x7f\xe7o\xec\xdd7$\xa6\xe4\x0f\xf6\xef\x192\x1f\xbf\xb7\x0cY\xb2\xf86)\xfa\x95e\x03\x9c\x91@\xc4f\xa1tV\xb9\xcd/H>\xcd\xf2\xb9P\x7f\xc7\xa2\x8d\x8b\x84\xcd \xa6\x90\xd0iB\x13F\xa0H\xfe \xbe;\xf0\xa3[\x8cw&\x0d\xfbE$\x0d\xfb\x8cMp\xfeb\x1c\x94\xf9\xd3\xf9\xb3>\x1f\xd9\xeb%\x8byO\x85\x16\xd6\xd2\xa5\xab\xce\xad\xe9\xed^\x91\x80*-?\xedO\xb3\xfc(\x1e\xcfj\xf1V\xc6@\x06u)R\x8a\xdc\x15m\xa9\x9b\xd4e\x8a\x82\xf6\x03\xe7g\xef\\ \x7f\x90\x8el\xe6\x1fI\x04'|\x9e\x1f\x89G2\x9d\xd2| B\x8a\xcb\x038r\xa9\x88\\\x8bd%!\x1d\x15\x86`{\x00\xfb]\xa2\x14\xda\x85\xe1Q\x95@\xc6p,\xbfN\x8a\"\xa1g\x82 \xc3^?\x91\x95\xc8f\xc1\x86\xd4\x94fR]\x82y\xe6/E\xfcU\xde\x97-\xdc\xbds\x9d\x11\xfc\xd76_\n\x85\xa7\x96\x01\xeau\xbc\xb0\xa6<\xfb\xf8\x85\x96\xc5\x93<\xcb*\x959\xff\x81\xa2s\x19K#\xf26\x85&\x93b\xad\xebb\xa3\xae\xff\xa1'\x85r\xcf\xa9 \xec9\xdd\xa0i\x9c\xc8r1\x89\x19y\x8e/\xaf\x0c\xd5\x0cm\xdfn\xba\xb29\x99g\xe7\xa4S\xd26\xccz\xe5nxBR\xc2'\xe0\xdbtk\xd6\xbeS^m:e\xd1IsA\xdc\x89\xa3\x85\x08Y\x92\x17\xa5G;\x94\xae \xa12\xce\x94\x13\x18\x92\x91l\xd4c,m\xf4\xb0\x8c\x06\x83]\xd1)R\xc6b\n\x14w\xf8\xc8\x96$\xda'\x91\xc4\xb9\x8c\x03\x15\xa6\x8d\x95]'\x1aw\xfa\xe2qr\x17K?<;Q<\x97)c\x12YM\xcbb\xd6RW\x01\x03\xc8\x82\xa5\x83\x06\xca\xe5*p\x02K\xe9\xac\xdb\x8e!\x03\xab\xd4qF\x82\x04cH\xd0p\xc3\xf7n\x04\xbd\x84\x9e\xc7i2\xe1\x94\xf8]\xccf69\x88\xcf&\x85\x01\xc4.\x0fT\xfe\xd2XNy\xc5\xa7\x8c\xd4*\xe5\xfb\xc9\xfe\x01?\x07I0\xae\x16\xd0\xa9(\x9d\xe2\xec\xc7r\xf6\xe2\xd7\x8a\xff\x92\xbb=H9\xbe\x06I\xc5\xcb\xb0\x10\xcf\x8e4\x82\xa9\x81\x07\x90{\x9eR\xd4\xe9Z\"\x1ee\xdfy\xd9\x9b\xe4\x9aZu\xd0\x1a;`\x9c\x92\xd8Y\x94Hk\xbc\xed\x16\xc3\x84?\x84Ym\xc0:\xea\x8d\xb3\xee\xf6k2P\xe7\x04J\x8b,_\xa9\xb8x-t\x11&\x06@\x8e\x86 b\xb1\xfeE\\<\x16\xf44@\x1f\xb6\xfe\xc9 \xa1\xc52'o9\xbd\x0e\xea\xc4[\xb1R\xce\x81\x97\xbd{\xee\xc1\xd6\xf9P?7\xf4\xd1pQ\xec\xd2\x0d\xb6\xb8x\xae41\x9b\xf5\xaf\xf7\xd3\xb12%\xc86\xebA\x9e[\xce\xb67spR\x1a\x11r\x01/\xfde\x9e\x8d\xbc\xd0\xbe\xd4\x89Y;\xdcKo\x1b\x94\x03\xdb\x99E:\x88\x08\xba3\x93\x80a\x82\x19\x86\x19eL6\xf7H\x94}\xea\x80\x80\xb6\xda\x9d{K\xed\x98\x8a\xc11`+?\xd2\xfeI*\xd6Fgk\xa2*\xaf\x03\xb24\xc8\xe15\x1a\xd2r?\xe8\x0c\xce\x9edp\x0c\xd3I\n.\xb9\x0f\xe0\xb3\xc1s\xe8{\x12\x01\xb2W\x8dd\xc0\xaf\x1f\xbf\xb3TO{\xc2\xdf\xd6\x81dS\x0f\xfedO\xfc\x81\xc3oOH&*j\x19\x1f\xac5>\x9c @,\x9d\x9c&l\x8e\xe0PN\xb14\x13.\xc8\xd4\xab\xcf\x9f\xaf\xd3\xe78[Rv\xed._\\\xa7\xcbOd\xf5\xa3`\x8aY\x0b\xba~\xdd\xfezs\xdd\xae\xbc;}\xd9\xdd\xe9 \x13\xa5FK\xa7\xe6*\xc2\x86V\xbe\xcd\xf1\xf8\x93H\xd3\xa9(\xcaW$\x90\xbf\xfc\xb4\xa1?t\xa6x\x14\x15\x90D\xc6\xaaVRJ[\xb3_u6k\xa6m\x1ce\xac\xe5o\xd1\xab\xf8\xc0\xe6\x8eyr\xb2\xc8\xc9\xb9\xc9\x14\xec\x97\x85\xe5\x9f\xbeIQ\xeb\xc5_\x9f8\xf2\xf6fJ\xaa#\x11d\xa5H\xc7\xf0\x87F\xe9\xa8\xb8!\xa5\xbb\\\xfc\xaa\x13\xbd\xcck\n\xbf8\x93R\x7f\x8fz\xed\xe0{>\xa0\x7f\x92`\xd73\xff\xdd?\x9c\xb8z.k\x92\x9b\x8d\x9c\n\x15-\xab\xadt8\x17\xc1\xa9\xc5\x9d\x12d~\xd8\x8b\xe0\xc4\xa1\xbc\xc1\x04pL\xf5\x86\x91/\n\xbc\x11h\xcaU\xb1\xb8I\x04q\x18\xc1\x96T}T~U\xe6\x0eD\x1e\\\x19~\x18$\xb2P\xd7!\xe7\x02\xa4\xf6`g\x0fK~\x1d4\xab\xc9\xf1\xeb\xcae\n\x17zvl\xc6g\x14{U\xf9\xc6\x9fp\x9bW\x93\x1cZ\xa1'\x8a\x8f\x19\x1f\x9b\x82@m\xc8C\xea*\x8b\xb2>c\x16\x95\xd4\x07Q\x97\xb4\xd5\x14\xa4\xa5\xa3@O\xb8\\p\x08\x19\xee6\x93\xbe\xc2\x82\x8f\xd2\xe9\xa6\xd4/\x89\x05\x8d`\xe9\xe4U\xb8D%$\xb6\xc0\xf8\xe9\x01GD\xb9\x9e\x84\xf3#G\xc12\x8c\xe0(\x881\xeb\xc3\x05?'D\x0e\xd7!\xff\xcc7\x9d;cn\x1e\xaa\x95\xa8\xf4W\xe1\xf6\xd9\xba\xff\xc2\xcf\x13\x976\x80c\xea[l\xcc\xf2\x08\x1b\x0c\xf8\x02h\xac\xf3\x8br\xa6\xb2\xbaP\x04\x99\xc9\x96\x83\xbbW$\xde\x0e\xaa$_U\xcb\x07\xda\xdf\x8f\x1e=\xe2\xf4\xe3\x16\x9c\x99\xf7\xf9\xb2\xde\x08\xba\xe9k\x1fY),\x1f\xef\x8f8^\xaci\x1b\xc3Z\xfc\xb1\xc4qI\xbd\xea\xb0\x82\nl\xc3\xb9\x84\xccH\xe8\x15\x07\xf5\xd5\xcdB\xfe\xe5C\xf1\x1d\xe1+\x0d\x070L\" \xbeK\x9e3\x17\xbd\xac\x12k`\xf5\x82Z\x86\x02Z\x9a\xe8:\x12\xdfph\xd1a2\xb2\xd3\xcc\x02M\xb46\xeds\x1c,\xd1-:\xe0\xaf\x15\xf5\x8c\xc6>~ \xd3V4\xa1\xba\xae\xc2\x90\x1f_\x8be1\x0b\x0c\x9eEV\xf2\x12+\xa0e~@\xce\x9c@.w=zmUj\x95[\xb7\x00\xb3\xb0\xd6\xd4+\"'c\x99\xd8Wl\x7f?\xce\x12\xc1S\x82\xc9h\x87\xbc\xa3QX\xe3\xc8\x98\x0fG\xa6.\xe5l\xc0\x86\xb6\x04x\xea\xca\x10\xab%\xf9'5\x115FEKl\xad\xfe\x01F.J]\n\xd9\xcd\xb4\x99wU8\x8d\xf2|\n\x0b\x90\xd1a\x9a\x82W\xc9\x99\xd6\x8e\xb9d\xb7\xe0\xb8\x85\x14\xa9\xe8\xb2\xf9\x1f\"\x7f\x9dJ\xdb\xff\x0e\xec\xc1!L\xfa\x8bLT\x82\x98\x0cSN\x8dZ7\x86|\xe4\x9c\x1f\x9f\x08\x06S\xfc\x0e#\xec9hh\xff&\x95)\\ \xcc\x11L\xbaX\xd2\xab\x08~\xbc693F\x97!vY6+\n\xf5\\\\ \x82z\xfdp\x11\xf9IP\xf6\xb1hF\x12EC\x84\xa6\xd7J\xd8x\xc3\\\xce\xb9%\xb8\xbb24\x1b\x95\xb3\xc3%\x13\x8f03\xf2H\xc4q \x19\x89\x99\xd8\x89&x\xaeM\x17k\x99\xa1U\x02\xe8\xa7$\xc8m\xa0\xd2\x04D&Y\x1e\x8a@b\x0e\xa9\xb2P\xf0]\x9a\x9f\xa7u\x18\x9a_\x1acL\xe5\xd6\x00\x82\x14n\x81 \xb5\x91\xae!\xa1\xce\x1a\xca\x1c3AUtz\xc9D\x93\x08|s\xe7\x0b5B\\.\xf3;|\xef\x8d\xe1\x10\x16\xc3\xe9\x08\xdc!\xeb3\xa1(\x9b\x08\x0b\x8cX\xe8\xfaZ\x99g'\xd4\x04\x13\x8f\x83B\xc0\x01E\x97\x85F\xde\xc7N\xf2\xeep\xf3\xaaU\xfc\x92\x0c\x01\xdf\xcf\xa2\xde\xcc<\x8c\x103v\x1fHV\x9f>\x80%\xa6\xf9\xe1\xb81\x80\xbd\x10\xe2\xe1r\x84hp\x0b5\x0bl\x98lo\x8f\x1c5\xeb@\x13J\x87\xf9H\xa8\xb8\x84/|\x80 \x05\xb7\xb1\xda\x98\x81\x90\xf0\xc7\x8b\x08\xd2\x08\x96\x11\xcc,\x90\x94\xe79\xff\xbf\x08S/\xa1\xc4\xe5?\x16,\x86{\xf0/\x98j\x9c\x8b\xba\xe3h\x0f?\xde357\xab\xda\x99\x99\x11\xf1tSr\x7f\"\xd1m\x86\x14\xfc\x00R\xf8\x17\x92\xfd\x14\xd6`\xc1\xd0\x0b\xed\x93\x82\x05\x8b\x08\xa6\x11\xcc\"8\x0d\x9b\x01\xf8\x1d\xe2\xc7yY\xed\xa3\xf2\x80\xb0\x1f\xb5B\xbdZ\xa6\xbf\xc9\xb5\x08Z!\xc5P\x80O\xb9\xa7\x1eb\x99=Q\xf3\xacslz\x97\x88\xf6\xf5\x0e\xdd*\x8d\xa4\xfa\xcc1\x06\xb7\xa2#\xe9\x92\x16\xf0%\xb5L5\x00\xa8\xbbn\x19\xa2\x81_0\x80\xafH\x90X\xed\xe7\xe0\x14\x17\xc6\x19e \xdd\xa8\xf8C\xbb\x7f\xedW_\xf8\xccv\xecj\xa8\xb6\xa7mct\xe6J\xb5\xe6Im\x10\x90:0\xf9*\xa7|\x06s\xb8\x0dw\xdb-\x8f\xd5\xb3\xfd\xf6\xb3i\xf9\x9d\xcds\x7fa\xf1\x188\x97\xb1CG\xc6\x80a\xe4\x9b\xbb\xf3XZ\xe4\xea \xe6\xc9+\xa9\x9d\x99/\xa4\x18:\xec\xaa\xe7D\xdd5\x1e\xc4`r\xa9\x03\n^\x89\xe3:\x87G\"kt\x0e\x0fa\x0e\x87p\x81\x99\x07\xf2\x08U\x0c\x18g\x8a\x85 X@\xfb,\x13\xf2w\x88ei\xd9\xc6n1\xe8'r\x9c\xfc!z6\xa4\x01\xe9\xd2\xf4\x96\x9a\xda\x0e\x7f\x13\x93\x17\x89\x9f\xa7\xc5\xc4\xed0\xa2\xe5\x01\x99\xb1\x8e< \x0b\x16\xc1\x05\xe1l2\xf3\xc8\x03\xa2 \x1f\x81=\xc6r\xc1\xb4#\xeeKsZ\xbcJ\n\x06\xc3^\x04\xbdQ;\xa9E\xad'\xcf\xa4\x16\x89\xaa\x15_%\xc5\x0f\xcb\xac\xe4\xa4\x9e\x95\xdcq\x9ar\x01\xb6d-1I3\x8e<\xcb\x93\xb3\xc4\xe6\xd9\xa6d.\xde\x13\xed\x8b2\xa1\x04n\xc1\x99!\x14\xd2\n '\x0c6\xcb\xae\xe1k\xbf@\x901\x04\x99d\xabjU\xf3\x1dE\xa00\xb1\x7f\xe5\xc4\xc6\xe0\xa1\x96\x0dvs\x975\xc0c\xe1!\xec\xc2!|\x92\x19\x0cq\x9b\xed\xca\x08SqsW\xa8\x1f\xf7\xc43f\x8c.\x03\xb0'\xd8c\xe8\xfb\xa4\x16\xd3\xfcNe\xcf9aq\x92\xba\x19*\xe5\xdeo})q\x06\n \x14\xdfb\x94\xc08^\xc4\xe3\x84\xad\x84A|\x00\x97Xo\xbb\x195 \xe4A\x14\xb12\xf1R\xd6x\x89\xf4ORrN\xd2\xea]\xfb\"n%~\xe1\x06\x89\x08\x9b\xa8BL\xcbuV^\xf6b\x14\x1c^\x9b\xb8\xdc;7\xd3\x05\x82E\xac\x14~\xad \xa4\xcf13z\x17^\xb9\xe2,k\xdbj\xb3\xf4-H \xcaJ\x1c\x9aU\x03 \xcb,\x992T\\h2\xaf\xcah\xaf^R\xba\x0d\xf1p\x91&c\xe4\xdb\xf6lQ\xbb\xb5\xc1&\xb4 \xf9&d\xa0\xd1\xcbn'8\xfe\x0d\xc9$tjZ\xfeTK\xab'\x9b\xc0\x15\xe6\xf8\xd3\xc8>!%%\x81j\xd7NE\xc1\x19)'(\x16\xcbb\xd6\x05 %\xbcU\x11\xfa\x96]\xae\xc1\xc9\xca \xe1\x1b\x16\xbai%\xe0\x9f\x90\x11\x91dQ\xd9R-;\xbe\xe6\x16\xbc\x8b2\xbb\x96\x16\x11%w*\xe8*l\xe3\x1e\x1e\xe6^%\xd9\xea`\xcb|\xf3:|R\x87\xecn\x04;{\xeeV\x97\x14wWW\xcb\xad\xf5\xb8\x16\xb0\xad\xa1a\x9f\xf0\xc8\xd9\xf1\x05\xb3#\xfbd\x99HnH7\x07\xb1\x17(\x9a@\xee\x00\xf0&\x89W\x1e\xfb'^i\xf7\xe1\x95\x90\xa3\xd9\x91o\xe2\x95vw\x1b\xe4\x19y\xec\x97g\xc4\xdc\x87\xd7\xb4\xce\xaf\x93\xd7\xe3qg\x9e\x91&\x9fx,\x08\xad\xd7\x89\xa6o\xc2v\x11\x8dz\xcb\xbe\xf5\x97\xce\xbf\xa8\xee_9\"Y\xe2\xaf\xac\xfa\xe7\x1e\xddfI\x19\xca\xedi\x17gOJ\xe4\xb3\xaf\xcd\x06\x05a0\x14\xb1\xabB.\x9e\xa8\xa7\xec\xdfW\x04\x86b\xd1\xd6\x8d)\xd0F\xd9)\x9aur\xa5\xfe\xd8 _\xbc\x02\xa1s@\xa1\x04\xc1\xa2\xd7w\xa6\xd7\xad\xec\xdc\x98\xc8_\x92d\xe2\x82\x05:\x9b\x135\xb8\x9c\x1a\x87\xa3s7\x91\xc6\xdcl\x94\x90\xc2\xb4\\I\x81\x12\xf6\x00&\xac\xad\xc1\x9a\xb1v\xe2\x89W\xcf\x8f?X2O\x9c\xa3\x05]\x83\x9cM\x7f5gV<\xc0\xb1\xa3h\xac%-\xa8f\xd2\x8cn\xd3\x7f\x9d\xb3\xe1\x8c\xa9`\x90sV\x05\x83\x9c\xb32\x18\xe4\x9c\x95\x89\"\x9f\xc8\x9c\x91\xda\xbbx\xbf|[\xbd\xa5~\xe1\x8b\xa5\xfd\xed\x89\xb2\xc5i\xb7\xd5\x17\xea\x17>\xaaR{=)\xf3|U\x0f\xcadOOj\xd9\x9f\xf0\x85f\xe2\xa0'\x0d\x89\x19_\xd2\x93\xf4<\xd1r\xf6\xc8\x87z\x0e\x9d'\xb5\xa4:\xa2\x0b=\x03\xce\x13=#N\x04\xf3\xb6\x08\xf4\x84L\xb3\xdcd}\xb4iZh\xe9\xd0\x84\xde\xcc\x0c#\xdb\xca\x8d\x81\xeb\\\x86^hL\x97Y\xbb\x88\xfaC\xe1\x13e\x0e\xad\x15\x0e\x80\x8f\\\xadK=\xe1p\xc4O2s7\x99\xf4\xbb\x10\xaaHs/LT\xbd\xb0S\xf2\x18\xf4Q\x0c]\x06,,R\x1fs\xba\x15\xd7\xc0\x8c\xb0\x85\x1d\xd4q\x86!\x8e\x06\xdfJj\xa0jSe\xe3\x80\x85\x95,\xf3\x80\xf2\x12\x06p\\\xe5\xce2\xcf\x7f+1\xabTj\x8e\x13\xbb\x0f\xa0\x10.\xa6\x05\xfaIJX\x14\xa3R\xfc\xb2\x12\xe4\x0c\xddD\x96%\xf48\x8d\x0f#X6)\x98\x01G\x1fO\x19i\x1d\xef\x9d(\x1a\xd4q\x14\x83\x8c\xbf\x00S\xa5\xf5\x13\x85\xfa\x0e\x84\xcd\xdc\x08k\xee\xc4\x0b\x07\x93:\x0e\xda,J\x88\x839&\xcb\xe4\xd8\xa5\x83\xd1\x80\x82\xf8Rf\x86\x0c\x1a\xbf6DN\xb5Y\x9c('\x9b\x8ceoRY\x91\xa1\x92/\x92~mq9M\xceD\x85\x11\xc4udi\x1fog,\x82\x15\x8b8\xd3\xe0J\xa3~b?\xad*^]\x1d\xe2F\x08KEay\xb2\x1b_\xc2\x04-,\xc8\x1dQ3Ryf\x87O-\x91\x88d\x1cv\xc3\xc6\xc4\xa0\x16\xf7\xcc\xe7\xb6\x8c\xc0jc\xad\xe9q\x96\xb5rV\x16O\x13u)b\x12K\xff\xa5C\x85`\xe2x?PQ\xee\xf8\xd3\xce\xa3\x82\xf4K\x89e\xe5\xc3]\xf4\x8c\xdd\x81\xd8\xfd \xaa\x18\xf9k\x16\xbe\x11_y\x04s\xc4\x1d\xfe\xf2\xdca\x0f\x95@\xe8\xe4\xe1\xd5\x95\xa0\xe3,\x9fvZ\xee\x87SG\xd1\x11\xd0\xd4\x12X\xedq'\x85\x03N5\xdd\x9f\xc8\x96\xd1\xb3k9$\xe6\\)`\xdcvx\x97/a\xd1t\xcb\xcfPs\xdc\xb1\xac\xc2\xa9\xd5\x7f\x01S$/\xf5\x05L\xe0\xd1#\xc8\xdc\xdf\x8d1\x00f\x9b\x1f\xeb\xea\x03\xc72\x8d\xcb\x05\x1d\xdf\xf0\x82\xe2\xb9\xf6\xc0\xea`\xa1_|\xed\x8d\x19]L\x97Z\xf4\xa5M\xe8k^\x89,\xb2\xc7E\x9d.\x85|\xf3ZJUh\xe7\xcbv;\xbe\xba\xf80\xd2\x86/a\x17\x82\x83.\xf5#\x92\x8f\xe1\x00\xd2.$\x079\xf2X\xb8\xa2\x17\x98y?\x13\x87R\xc2Q\x83\xf2S;\x0b\xedn \xe0\x9c\x92co ]l=\xf6K(qaL\xf6c;D\x96\xad\xec\\\xe7\x0e\x8d\xc2\xb2T\x93\xc3\x0e\x17\x92\x96\x9a\xaa\\\xfc\xd4T\xe5\x0co(=9\xc5_U\xd6\xa3e\xa9$\xcf\xf0\x87&5&\xe2\x86\xd4\x97\xc7\xe2W=\xb9\xd7\xd2\x0b\x14G\xcc\xa5Q;c\x18\x06}\xc6\x07$\xec\xfa\\|\xf34\x85_\xb6\xa1l\x03q,\xfc\xf1er\x1ewL\x05\x11N\xf3\x0f\x15qS\x8a\xd9\xd6\x07\xc8\x0b#^j\xbe\x14\x99kc\n\x96\xb3\x83sK\x1b\xc4u\xb8td\xcc\x19\x0b\x13\x9f\xb4\xe5\x89\x8d\xa1`\xe1\xd4$\x8d\xc5 \xa5\xf2F\x05\x92\x0d\x136\xde\xb2c\x18\xc0\xd8\x1c6h[\xd1\xa2>\xf2\xf2\xf8'\x95[\xa6\xdeUT\x83\x9d\x80<\n;-\xde\x12\x0e\xcb\x9b\xcaD\x16\xeb\xe3l\xc7 \xd8\xf0\xe6\xd8\xce\xd3\x95j6\xf4\x07(c\xf0\x88\xe6\x99J\xa4\x07\xea\x9c\x05\"?\x97dK\x91+\xe5\xa3\xe2\xe2\xa5g\x1a\xc3\xa7\xf6\x91\x94\x16\xf4\x86\xedW\xb7\xac\x9a\xf9A\xf1\xe5C!\xd0(V\x10\xb6\xe1\xdc\x86t5sD\xc9DJ\xbe\x15\xbf~ \xfc\x16\xd0\x15\x07\x0b\xab\x0eJ\x1f\x06\x11\xaa\x95\xa3'\x03\xffhg\x00\xe7N\xc4\xeb*\xf3n\xad\xe8\xe5L\xd2\xa3\x05\xbd\xa8\xa83Q\xeeX\x7f\xa2\xe2\x0f,\xe5\x8d5\xb3\xbe\x9en\x07\xf33\xd8\xd9\xf6\x0e\xf6?\xf1a\xff1\xc6\x03\xb6m\xc5\x19\x96\xa5\xcc\x8c\xd8H\x91\x9b>@\xb3\xd1.\xfe\xbd\x8d!c\xbc\x05\x83\xc7\x02\xc7\x87\xb8\xb9\xbf\x92.2\x15s\xdc[j\xd8\x86\x86_\x13\xa7R\x13\xfb+\xd1#\xd5\x91i\xac\x82N\xb7a\xccG\xfd \xc4\xe7r\x1fa\xf5\xac\xb4\xbe\xe3\x0fa\xa8\x8cG\xe9H\xee*.\xd8\x8da[e\x1f(\xf8\x9f\xe7\x86\x11\x8d\x85L\xc8\x1f\x8f#QF}\xcc\x0f\x00\xf1o\x82\xff\xba&2\x15\xd2X\x82\x11\x04\xf8\xe72|\x00\x0b\x0e\x11\xec\xb9\xe0\xbb\xc9k\n\xb5\xa1\x8b\xf1\x9a\xf1n\xd2\xe5N2\xc3 \x8a\x87\x18#!\xc8\xc6RH\xdc\x07|`x[Soat\xe3\xc4\xbc\xb2X0]|s\xeb\x16\xc6\x01\xa3h6i\xa8 :h\xc5\x1c#X\x90\x90\xa7bz\x9c\xdf(\x1e\xc0\n\x1e\xc19\xff\x87S\x82.Y\xe2\x14\x060E\n\xb22+I\xd4\xc5\xbb\x9bK\x92s:\x12\xfdV\xbf\xad \xa4\xcc\xfc\x9d\xfaP\xf4|\x8e\xb4\x0b\x060\xe9\xa0L\xa0\x18|\x05\xb2\x80/\n\xc6\xac\xcfj\x8a\x93\x1c\xd9\x98e\x88g\xdd\xa3\x01,B\x8898\x16\xb8h\xf8o!\xdc\x16*\x07\x85VSR\x0f(\xda2\x85O\x96\xee\xc8\\8\xce8\xa5B\xfcp\xae\x9c\xdc\x87\xa9S\x98\xe1\x0bs\"\x84\xeeG\x8f\xf8\x81\xeeZ\x18>\x80\x13\xa4\xae\x8b\xea\xf5\x10Ns\x12\x7f\xb2\x7fu\"\x05\xb5\xed\x01\x04bK\x85\xf05\x9c\xe0&\xd9)!#\xf7\xd3\xf0\xc4,\xdc\x9a\x177\x15X\xfdH\xaa\x11E;M\x90\x16|ev`\xcc\x97(\x15\xfb\xe1\xa1\xd8\x0f\xb5\x0f\xca\xe5,8%\x90\xef+\xea\xb2#\xa9\xca\x8e1\x8ar\xe3\x94\xa4KTkT\xc7\x89`\xbbI\x8d\x9d_V\xba\x1d\xc08\xce\xca\xbd*\xd5\xdd\xabf\xbe\xeeU\x9cL\\\xb0 \x16\xe2\x0eFj6\xa3\x1b-\xc7\xf1c\xbf|\x91\xb9\x9e/\xb2\x16A_eY[\xba#B0)\xb6\x93 F \xc6\x9a\xbe'\x15\x10~$\xf7l\x82\xeb++\xfd\xc5A!RJ\x8aU\xbf\xe9\x94\x92\xb9\x88GK7@\x8f\x04\x1e)\xa7\xc9[\xb7D\x82\xa8\xca+9A\x92\xa2 \xdf\xccrcY\xa9\xb7])\xe6\x84[\xf5.*\xe5\x94\xce\xfa\x9co\xcas\xaf\xf6\xdf\xb9\xdbw\x16z|.\xdc\xe1>\xb0\xaa\xbe#\xbf\xb5\xb1\xdf\xcd\xf9\xff\xfa\xfa\x8e\x1f\xdcP,Ka\x8e\x9b\x08gk\xf0\xb5oJ\xbe\xba\xea\xe1\x9dfT\xb1+!\xaa\x14\xe1(\x02\xe1\x8f\x03\xb4\xdb\xf7OD\xea \x91;<\x15\xf6e\x8f\xdc\xe1^sz\xeeT&\xac\x842a\xc5{|\xcd\x02Q\xdd\xe6\x88\x05\xadP?K\xeb\xbf\xbb%\x0ci\xda\x89\x14KoM\xbd\x14K>8)\x1c\xfc\xbcHI\xc1,\n\xff\xa2\xe2\xf8\xf9\xd1\xba\xb4\xa9\x12\x06\"o\x93\x19o\x85~\xa2KQ\x18K\xf28\x10\xda\xd3\xea\xe7>|\x0d\x89r\xdcD\x1b\x910V\xb6\x93\x9fZDXu\xc9\xfe\xb5\xf9H\x15\x0bJk\x96}\x14\xf6Y\xf6\x92\xac\xc8\xe4\x98|\x0e\xc2\xcd)3\x19\xeeZ\xb8\x86\xb0?M\x93E\xc0;x\x1d\x8b|:\x1anr\xa2\x9b\xd7p\xb5\x8e\xb9\xba\x933:\\\xa0\xf1L\x95}c\xa10\xfe)%\x86\xe6\xdc\x1bkj\x0bND\x96J45(/\xb5X3\xabm\xa6B\x80\x18Qi\x19\x0e\xf7F]\x8b\x9d\x0b\xd5\x9eXG9\n\x91j\xdd:\x081?\xe9L\x1f+\x12Z\xb5\x10\xcbB)\xb2\x19+\xc9\xb0\xf1=\xb9\xfc\x9e(\xca!|\xc3%\xe5\xc8\xcc\x9c\x0c\x07\xe3kt\x7f\xf7\xcc\xbc\xfc\xa6\xc3\xeb\x04\xdd\x954\xaf\x93\x93eA^\x92U\x01U)\x0bE\xf1\xdaI|m\x9d\xbe\xb7\xd0tc\x8f\x9b7\xff\xec\xafm\xfe\xd5_\xdb\xfc\xc7\x8e8\xb6\x7f0W\x8aXV\x1bA\xbd{~\x83o\xf1.\xafN\xad9CR\xe6\x08\x8b9\xaa\xe2%\x9d\x0d\x9d\x97e\x92\xe5G\xb2\xfe\x19\xfa^9\x15b\xfe\x83\x05}7\xc9n\x02\x0b#\x12\x99*\x8a\xf09\xcd\xe2\xa2\xd3\x0d\x15\xf4\x8e\x12:N\x97\x13R4\xab\xda\x97-\xaa\x176kv\x16\xdb[\x1c\xc7\xe3\x19yO\x8a%\x86Q\x12\x1aaE3\xe9Q\xf8\x91\xe2\xe3Z\xd9.W\x04\x93\x12C\xcc\xce\x14P\xa7P\xadzV\x9e\x8c\xa1\xf4:\x14\xbc\xa1]\x1da-v\xa5y\xa7n:?\xa1\xef\xe5\x07\xc1\x9b.\xa9^i7UW\xa2]\xbb\x98\xaeXx?'Vu)\xbbf\xee,_\xab.\xe4RHg\x1d[uU\xfb\x0c\xdd\\\x87\xbb\x1d\xd9\x90\x00\xc3:\xd5\xbb\xda\x87{\xa3H\xfb\xbb\xe5^\xd8\xbc\xdcfQ+\x19Q\x97-\x8b\xb9\x1f>\xf2\x95\xc2\x15\xfe\x9d\xcbLp\x00\xbf[\x11\xa9v\xd3F{?ws\xba\x9d\x148o\x12\xdd|s\xd2b\xa7\x01y3\xa4\xd3\xa7\xa82\xc6\x81bbz7\xc5\xadj\xa6d\x18&\x8c\xbe\xf6\xa2\xc4Nn\x14\xedp@N\x02\xe43\xbck\x13\xa0\xac\xc3\xd9\xa6N\x83\xf2\xa0\x9a\x91\xfaXZ\x04mD)\xeb\x98\xb2\x99(\xf9\xcc\xb9\x86\xc3o:\xeb*o@i\x94\xf8\x9atR\x19t\xb4\x93\x04F\xc9\xaf\xf6\xb7\xcf\xa5OZ&h\x83\xdbE\x05}\x13\x9c4H\xc9\xef\x1cZ\xcbHC\xb6\x18)\xd0\x92\xe3\x9bq\x01\xc0\xa2NhUE\xb4\xec\xf1\xef\xbb=\xd7\xdc\x1b\x9c\xea,\x16m\xeev\xba s\xe4\xe2\xb2\x88`\x7f\xd02\xe7\xcd \xa9S\xe0\xa3y\x06\xa0sW\x1b\x8c\x13\xf4\xbd(\xa4D\xdb\x961pW\xa8Yj\x90-W:\xc1\xb2'\xd4\x04\xc8\xbc\x8f;{\xb0cHa\x0d\x92{h\xd2X+WP\xa7\xb1\xb5\xc6--_\x8f\x8d\xeb\xe0\x0e\xa9\x81\x97\xa3\xe6\xe8\x90\xff8\x0f\xd7Q\x8c\xe4*\x82-\x1b\xec\xcc\xb1E\xae\x19\x19\xcfx{\x0f^[\xfe\x0f_\x95_\xc7\xc9\x8e\x9b1k\xa2\x9a\x15\x8f\xcf\xcbD\xbd~\xc7o\x86\xc7\xd4\x8a\xf7\xb2\xb5U\x11\xc4\xccq\xfaf\x7f-;P\x8e\xa7\xcd\x0bH[\xbb\xa1\xb4P(t\x98\x0e\xa6\xc0\xe5My\xae\xc5 \xd8\xcf\x98\xa5\xb9*/t#|\xe2p\xeb\x05%5\xe8|\x02~P%R\xdc\xde\x8e \xe3\x0d\xe5\x12\x02hn\xb6\xe7\xf9\xe4Sm\xfa\x84\x81Z<7\x1f\xe1\x03\xa6&\x1f\x918*/v\x03m\x036\xc3\xd3\xf9S\xe1\\\xdc\xc9\x8d\x80\n\xca\xa8s$\x89\xfb\x0be\x08K|\xb8\x12\x906\xb1b\xb8\xeb\xb0\x9a\xa9\x0b\xb3Y\x1a\x13\x83\xeaW\x1d_\xc6h*\xd4r\x02}\xc6\x8a\x882\xb7:\"\xcf\xd8\xcap\x82U\xf01\xf3;~\xb6\x81'\xbe\xc4\x8fX\"N\xf9\x0c7r#\xe2B\xc4\x1e\xdcF\x1f\x1c\x0cDD\x9f\x1c\xf9\xfe[Y\xc1,\xeb\xcc\x9b\xc4\xd1\xe6\x9d\xa8cf\xb7'|@\ni \xc8\xe1\x04\x0c\x12X\xaf!\xe6\x7f\xc5e\x8f\x1c&}\x96 \x15\xbav\x10\x07a\x05)\xf3\xa0\xa4\x93w\x0c;&\xcc,`0\x10\x9e~\x01\xdfl\x85tD\xda\x85\x03c\xa5\x89s\xe9\xd5\xe8>vR\xc5bV\xe1\x06K\xac\xac\xa5\x8c\xa1\xcb\xca\x80\x18\xc1\x16\x9eR\x992\x8b-\xcb4>A\xda<+<\x8ea\x99\xe1\x86\xc9p\xd3*)\x10\x93E\x15\x15\x93\xb6\xcd\xe9$\xa6\x9b1\xf8\xb1\x85\x11\xa4_\xa6\xa7\xca\x9c\xe09\x96!\xda\xa4\xc2\xbcf!F\x11\xb4\xdd\xe5\xaf\xf45\xbe\x9e\xb2N\xda\xf4x\xff^K\xe4\xd6\xd3)\xb4\xd1Zm\xab\xf8\xec\xeb\xe3\xb1\xbc7|\x96\xaa\xb5z\x10B\xd6yZrxmo\x17\xf0HC\xf9\xae\x93\xd8+\xfa\x1d\xba\"\xe0\xf9u\xe5V\x13\x10T\x13tM\xa1\xe4\xaa1 \x96\xd2\xe2\x11\x0c\xb0g\x91\xa8\xa3\x13\xc9'\xcfU\x92\\\xf4\xc6\xd05\x95\x9b(\x08\xeaXk;0\x7f\xf2=0\xddd\xfb\x86x`;\x19K|\xf6\x08 \x1c.\xef\xe72\xc8\xc2E\xa7\xba\x11\xdd\xc1i\xa7\x9d\xa4J\xa4\xe4\xc6\xd3\xb2\xc9u\xa7aE\xb5\x8a\x16\xdb]\xb8\xd9\xee0\x02C\xa0\xe5\xcd\xf0\xdc7\xb0,Y\xee\xb3.\x9b0\xf7_~\xdel@\xb0p\x93\xe3\"\x19\x12\xb5\xabk\x92uP\xa4De\x1d\\JZ\x11\xd6Y\x7f\xa4\x0cY\x832d\x918\xc2\xb2.\xba\xd0-7L+\xabG\x07\x8f\xcf1\x04+\xf9\x8d\xf1/\xde\x81\xe0\xf2\x8a\x1a\xde\x8ee<\x93\x83\xbd\x87\x8bY\x92\x12\xb0:\xe5\x81\xae\x0e@\xdb\x95>\xf3\x04\xfb\xd8\x88\xe6\xf9 ?\xde\x88\xe1\xe3\x8b-\x01\x0e\xfcE:e\xa9s$\x07P\xce\x86\x04E\x07\xed9WUC\xac[\x99_\x85\x89\xb2e\x1d\n\x04\xd0\xb8\xe7-\xf4\xbcJ\xe1!\x16\xac\xb9\x05q\x80U\xfb\x90(\xa7\x18\xa8\x0d\x07*M7R\x04*\xcb\x01$()\x86\xa5$\xb1\xb5\x8b\xc59\xedxeW\x95\xf3\x85\xe5_\xb7K(\xfd\x15\xa6\x8c\xdc.\xae\x81\\\xc5aG\xa1\xf3\x1b\xa3R\x92\xadJ\xbc\x94\x14\xc4\xcbd\x02\xea\xdc\x92\xa9\xe672\xcf\xa6\xbe\xf4\x06d/\xb9\xa4\x00\xa5\xfb\xf5po\xc4%T\xd4\x10\x06K\x15O\x81\xd8\xc5\x8f\xd18H\xab#\x93\x96\x84#\x8f\xc4\xf9\x99v\x93E~-\x85sn\"K\xa3\xa5\xad\xe5u\xb6\xa0\\\xb4\x90\xac\xa3g\x97\x1di\xbb(`\xd7\xaa\xdd C\xbb\x01E\xf533\xfd\xec\xa4\xa8\xc2#\x13]@M\xf2\x8b\"\xb8Kk\xda\xe8\xccN-\xc5\x9eT\xda\x8d\x9a\x83 \xeb(\xe2$\xe1>\xccq\xe4\x99(\xbdx\x08\xe2C\xe9^\xc6\xac\xee\x83e\x96i\xeb\x11\x91\xf4\x8b,g~\xd2\xacb\xa2\x022\xbc3\x8a\x80\x0e\xef\x8c\x10\xcb\xc9p\x7f\x04;@\x87\xfb\x86\x0c\xc1aU\x90\xbc\x91\x95\xc1j\xb1I\x86l\xa4v\xd2\x00\xf6\xdbm6+\xf4\xb9\x1a\xe2\xa0\x1f\xee\x99\x06&8\xd7_e\x8d\x0f\xe1\xd6\xfdR\xfc\xfa!h(\x04m8\xf5\xc2\x89S\xc2\xdfE\xc3+\x0f\xbb\xd1\x17\xe2 \x1fJ\x89\x1bV\xbc\xc8\xc9d9\xde@\x87![\xff\x15=+\x05;G\xd1\x87S(*,\xf9\xf2\xdd\xb6\x0c\xd4\x8a\xe5&\xdfWG@\xca&\x03\xaf\x0f:\x12\x89\xf9\xcc\xc3\xf5\xf4|\xff\xd5\x8b'\x13\xf5s\xec[N%\x8f\xbfu\x0b\xa8\xa6\xbf\xad\x85M\xae\xd7U4\x82\xf8\x05[\x03\xde\xedz-b[\xbd\xc6\xfb\xb2\x8a\xbf\xf8\x02\xa1Y\xea:\xf91OH\x90\xfbz8\x97k\xd6\xf2\xb3\x04\x81\x84\xf3\x84\x06u\xcb\x14\x0c\xfc\xf6u3\x0b\x9f\xf0\xf3\xac\xce\xc4\xdfE\xbcv&Bx\xb6T\xfd\x0bM\xa2\x81Z\xfa=i\xa9\x10\xe4\x95\xd9\x92\xf0\x81\x06\x94\xf6|\xba\x05Y\xe2\xc1\xb9\xe5\x9e\xc0U\x97\x022_\x1f~2\xc1O\x01\x86\xb0W>\x97\x1c\xdf\x1d\x07\xfe\xf5\xf5m\x1e\xec\xff\x06\x9c!\xaef\xa7\x00\x86\xba \\\xce\xe4\x9a\x80\x92X\xe0\x02\x88H@\xd2/\xb29\xb9N\x07\x1c\xbd\x1c\xcd\xcb\xfaR\xffFFJ\xe5\xc7\x8c\x11\xbb\xa5\xb3\xaf,Gq](\xe2\x00]\xb3\xbcy\x81\xf8\x87\xce\\\x08\xc2\xc4\"jr\x90\xfe8\xa3\x05\xcb\x97c\xd4,\xfb\xd1\xf7\xaf,\x8e\xdeI\x99\xcdFD a\x89\x116\xcb\xb3\x0bD\xf1\x0f\xab\x059\xca\xf3,\x0fzG\x97\x0b2fd\x02\xc3\x97\x11\xfc4\x02\xb6\\\xa4\xe4\x00z\xb0\xdd\xcaHk\x19\xc3?\xdd\xd1U\xaf\x88\x8cG\x08#x\xea\x1b`\xf5\x8b\xbb\xcd\xa5\x00[^\xb1A\x19\x17x\xbd\x9a\xfe\x87\xbb\xe9z\xc4V {\xfaUc\xb88\xb7\x15j\x81\\^\xbd\x12\x8f\xea\x1c\x9c\x14\xd7\\zT\xee\xf6\xd6\x13\xb41\xce\x9aY\xdd\xf1-\xe9\xa4/\xf3\xac\xbf\xd0\xb3\xcbW\xdf\x0bm\x13k\xa7.\xb5\x8c\x9eu\xe6\xba'\xf0Hf\xa3<\x10\xc5>\xe0\x10v\xf8\x0f\xbfs\x9fZ\xb6\xf2\xb9\xf4E\xfb\xc9x\xe0\xa3\x14m\xe7\xa5\xf9\xd3\x9f=0\x1f\x8f\xc0\xd3\x94@\x96\x03\x06E\xef\xa4\xc9\xa7r\x0f\x98I\xbc\x18\x14\x1f\xb5\x81@X\x97\xd9\x0b\x16yG\xe2d\xc1A\x94$\xd0\x99SLX\xb0\x13Z\xb0\x98\x8eI6\xd5*\x9e;\x9c\"\x10r\x88\x1e\xf5Ok\xc9>\xf3\xc0\xa6z.\x9bpr\xe8\xfc\xa2\xa8\x96\xea\xd6\xb2\xc6U(\xe5'\xb2*\xac~\x89\xea\xda\xf2\xe3\xca\xf4\x8b\xe5+\x8f\xb7\xf8\xc5\x8c\x11\xae^\x9d\xa8K\xceeB\xa6 %\xef\xf2lAr\xb6\x92\x9c\xaf\x7f+\xfc:#L\x13-7\x19\x83\xbat\x12$\xc2&7j\xe2\xaa\xdb F\xbf\x8a\xdax;\x8fo\xd3uF\x1a\x89\x98#\xe8=\x8d)\xcd\x18o\x1d2\n1\x85\xa4L\xcf\x9b\x93q\x96O\xfa\xbd\x92d\x8ah;\x07\x8bi\xba\xba3\xb7\xa9\xcb\x12\x8d\xd0\xbc\xae\xfa\xa7 \x9d\x04U\xd4]\xf7gW0\x8e\xd9x\x06\x086\xf7\x80\xae\x02\xe5\x9a\xae\x8e\x88X\xea'\x90\xeb\xa7\xf1\x9c\x94\xa1\xc3\x9fD(^\x8c?&d\x1a/S\xf6\x13\xe7\x960\xe7\x8c\xb5\x1b\xfb\x00\xc4\xea\x88\x80\xc3\x8f\xa4\xa9\x98P\x97\x05q2\x94)\xcaS\xab\x15C\x9d\x99t]\xa5\xe4\xa7\xb1P\"\xda\xb1\xa9h\xd3\x7f\xb1\xe0\x1d\x8b\xe0#gL\xde\xdd\\\x95\xaew7Y\xa5\xebm>!9\x99\xbc\x8e\x17\xf0g/\x82\xdeU\xbbV\xd7\xbbk\xd4\xea:\xd7k\x04\xf0\x95\x125\xfc\xed\x90\xadyh\xc9b:\x18F\x8a\x1f\xd2PT\xa6m\xd5\xd0z\xf7o\xaenS\x96\x9d\xe1S\x92I\x95\"}\xb4\xb5{\xa1\xcc\x88\xe0\x1c\xf5f\x95\xbf~g\xae\xdaG\xef\xae_\xfbHo\xb8]\x06\xb5\xd6p-\xf5\xb8\x0f\xb0+\x90U\x9f\x06\xa8\xb8\xd1 \xa7?rv\xbf\x91nDGD+\xf2i\xa30\xd8\xd2\xba\xdc\xe8E\xbe\xb9\x80\xa1\x0e\x90\xa1\x05\xd6\x12\xde\xe57/\xbf\x12\x17\xed\xa1O\xf3l~DY\xbe\x12\xbaRM\xf9\xd3\x8d+\x9b\x15J\x10\xc2\xdf\xa0U%\xc1#\xbf6\xab\x11\x85Z\xb7V3BEH\xe4\x12\xd5?\xb2.+\xdf\xd5\xaf\x99t\xe5$\xfe\xd5\x16\xd4\xd1\xc2\xf4\x9d-\xf2^\x18$\x1a\x84dRh\x84t\x00\x1fX\x1d\xbe\xc3\x99\xaanP\x83zY\xe7\xc0\xb0o#`\xc1\x1b\x16\xc1\xafa\x04o\xaeA\x81\xdb\x82\x1fR`\x13&\xd4\x9ao\xc4\x0dt\x96K\x13m\x8b\xa2i\xce\x86Q?rL>oD3\xb0q\xf5e\x9b.\xbc\xa9\xc3\xcd+T\xe8\\\xab\xc8l\xc67\x0e\xdf\xef\x159\xdc2%\x1b\xac\x8dQ%\x1b@\xa3\x86\xf74A\xd7\x1d\x89y*+\x87=8\xfc*l\x05\x896\x80 0\xb7\x13;t\xb2h\x06\x02\xa7\x02\x9fk\x87\xcd\x06`\xc8\xaf\x03\x06\xda\x00\xc3<^\x18\xf0\x15$\x18Z\x85_\xde|\xd9\x19\x119B\x94\xda(\xa99\xe0\xd6&\xaf\x99\xf3<\x1c\x97I\xc0l1KW\x9c@\xa9|\xcb\xff\x14\xeb\x10\x8a,=e\x0fV\xd5y\xd9|\x16\xc9|\xcd\x14\x0eD1 SWa'Q\xd8\xechB\x1b\x9f\x0e\x96\xd0\x01Au<\x99\x8f\x0bZ\xd7=\xb5\x0c\x1aV\xd4m\x82\xcd\xba\xa8\x9e\nye\x19\xa2N\xef\x8bRL@\x83\x8aP\x1a\xa2\xa2Y\xac\x02\x16\xc4G\xbf\xb0\xd2\xbcbZ\x0e\xd7RT' \x0b\xde\xb3\x08^\x86\x11\xbc\xd7\x97\xca\x14\x08\xe8I\xc4\xcbh\xc06%\x7f\xffe\x9b\xab\x93\xd2\xd8\xd7\xc7\xb8\xe9\xbcy3\xdca\x08r_\x96\xcc8S?\xbc\xff\"\x84\xbd\x11\x0ce\xbe\x18\xca\x14\x862\x85\xa1\xa2\xda\x96\xc2K\xaf\x9aa,x\xc6\"\xf8!\x8c\xe0\xd9\x97s\x10\x0e\xe4{v#\xc8\xf7Wb\x18\xf3\xc7/\xe3dn\x0c\xbf\xfe\xc3HT\xe1\xcf\x86\x88\xf4Jr\xba\xaft\xe8\x10)\xcct\xf1\x10\xedu\x94,D\xb3\x9fW\xff\x95\x88\x84\xc7\xa5\xed!\xbf\xbeb\x81\xb5\x88\x9e\xe6d\x11;\xdf*\xd1\x15K\xf4\xa30 \xaa\x12\xa3\xd8Z\xdd\xdc\x157-R,\xbf\xdaz9#\xa2\x1b\x81\xfd_\x83\xe8\x1e\x91\xa1~{\x01\xca\xf0\xca\x9a[\xb8\xa3\xa2\x86Z/\xd6\xe5e\x89\xde\x95\xae\x11\x82@\x0eS\x18\xa0~)\xde%\xee|S\x0e\x1e\xf7r\x06\x87\"\x91\x8b@\x89\x1cQ\xa2\xba\xb9'n\xee\xb5\xf3\xe5\xeb\x97\xc5e\xd1\x83&\xd4\xce\xe1z\x1a\x827\xf6G\xcf\xec\x8f^\xd9\x1fa\x8e\xaa \xa7\x11\x9c\x10.ZP\xed\xcd/T\xb0.\xa9\xe4A\xb7\xa1g\xd5\xb0\xd6:\xdc\xf8\xf8\xaci\xd4\xf9\xe7o/he\xf2qw\xe6\xa9L\x10v\xd0YY\x1d\xdd\x85\xe6\xf5\xcd[\x1b\xdc\x90\x18\xe2\x94ks\xe1\xe2\xeba\xf5\xb7\xd2Y\x18b6\x9b3\xf1R\xfeV\x92\x89Qe%\xfa\xbfuK\x1b@M\x9fk\x9eli\x1f\xd7l\x03v\x9dT\xff\x84\xcc\x17l\x85br\xf9c\x001\x95\xa2\xf6/\xa4\x9d\xf2\xb41UO\x8dq{\xd1*+\xb5\xb0P\xffM\xb3j-\xe9'\x9a]P\xf8DV\xd0\xfb\x1bl\x03\x81m\xf8[\x0f2\n\xfc\x97\xc2c\x8b\x91\xbc\x06\xbd\xad\n|\xb2\x98~Y\x8b\xc3\x8c\x14\x1ez\xc3\x9a1\xa1\xbeD\x85\xd2ku\xe0V\xad,\x846\x9a\n\xe7\xe0\xa0Z\x87v\x1d\xe6\xda\x1ax*\xd7\xed\x1b\xc7OCZ\x9f\xa9\xccS\xea\xca\xac\xd8\x9a)\xeb\x9ci\xfb\xe8\xae\xcd\xf4\x86\xb4\xfd\xce>\xae\xcf\x1eX!\x91\x07\x06\\k:jZ:\x00])e1Y_uk\xd8\x8dS\xbc9v\xf3\xdf8C\xe25\xc1\xff\x84 \xa1\xbeA62\x0dT\x1b@\x06\x0d\xf8\x1a\x04\x1ap\xa8w\x82\xcc\x16z\xd7j\xc0\xb1\x15\xa8\x8c\xc5\nuxO\xd7\xed\xd3\xf2\xd7\x19a\xefT\xf3o\xa7\x9c\xb4\xd8\x11E\x1b\x7f\xde\xcc\xe4\xed\x17(\xb2\xec(\x99--\xfe\xebu\xdd\xcb\xb0\xaf\xee\xf6\xde\xa3\x93D\xcf\xab\xb3\xc2\xdd\x993'\xfd9E\xff\xde\x94\xcacgk\x1c\x94\xc9\xe9\xf9\xb3k'\xa7O\xae\x9d\x9c\xde\xc5\xc1\x97\x92t<\x99\xd8\x8b\x11\x18\xb6\xa6\x17 S7 \xb7\x82-\x04\xe1\x16\x19N\x9b9\xa4\xeb,zF+[UFK\x0bUy\x1b\xeb`\x97\x0f\xda\xe5\xb73*Jdk\xd5\xb2\xab\x9b?'\x18\xd4\xa2\x1e\xf0\x9f\xd5\xc3V\xf9m\xf5\xe0\x19!\x8bF\xf1\xed\xfa\xc3F\xb3\xeaV\xfd%c\x01\xef\x8c\x1aJ\x8dg\xd4XA\xbc\xbc\xdd\xae \x9eQ\x8f:\xe0\x19\xed\xdb\xeb\x80\xe3CW\x1dp\x16\x144\x82#\x8ey\x05\xbd1\x07\x93\x82\xa2-Yf\xd0\xf6\x96D\x02Nq\xfb\x9f\x88\xb0?\x9bZ\xbd1\xa9\xaawL\x98U\x9a*\xbeH\x9a\xaa\xb8Vg\xbb\xf1d\xe2\xdb\xee\xa4\xc0\x9aq\xac\xac\xbcC\xb7\xb7CH\x026\xa4\xa3\xb0}\xec85\x8a\xe5\xb1\xcd\x8f\x1d\x8b\xfa\xc6x\xec(\x07\xa9Z$\xc1p\xb7yx4\x96>\xa1\x8c\xe4\x05\x19\xb3\x9b]\xfe*\xa3\x12\xf3\xab\xbd.0\xc4/\xbeC6\x94\x98NeS\x18\x9f\x17\xcb~-,0\xf0\x14N\xbfg\xd6'\xe7$_y\xb4\xac\xae\x12\x1dJ#\x8cE\xf5\x0b\x02 \x90\xcd\x93\xa4\xc5\xa6$\xeefZ\x1aHR,OY\x1e\xff\x7f8\xf2o\xc2\x91\xeb\xc6ry\xa2\x08&\xb2\xbai\x14Q<\xa4\xcf1\x85`\xc43G\xab\xe5\x10\x81\x93\xebi\xf4$9H7I=/K\xaf6\xd1q\xafCM\xd3\x1e\\[\xe7T\xdf!Y\xce|y\x819\x0d~.\xbdw:Nf\xde\xee\x93\x95\x8f^\xc2\xd08\xebn\xff/\xd2 \x15\x7f\xadz\x85iZ\x85\xb61\xcf#3t\x90c\xcc\xb9\xafa\xd88\x1d?\x85Xk\xc4\x9b\xea\x80L\xf9\xb0;\xd5[\xc5\x7f^\xfb\xb3\x99\xc2G\xf65\x8f?\x91\xe0\x0bu>8\xfb\xa48FM|J\xdb*\xa01\x8d`\xcaq\xac\xf7\xf7\xbf\x9f\x9c<\x7f\xfd\xfa\xe3\x87\xc7O^\x1d\x9d\x1c\x1f}89\xf9\xfb\xdf{mG\x90\x05\x7f\xbb\xf0P\x1aM:\x11\x81X\xaa5\xb1f\xb5&\x05\x05U([j\x88\xb1\x1c\x9c<4\xa5w<\xae\xf0|\xc1V\"|\xba\x04\xa3\x9f\"b\xd6\xbd\x17\xebJ\xae\x85#\x08\xa3\xcaf\xdf(_G\xd5\xb4\x88\xc8\xea]\xad)\xf3M\xc2}\xee\xa4Kc\xcc;\x10\x8c\xf9xg40\x99j,\xed\xce\xbf@\xa5u!TZg\xb4\xd2d]\xfc\xbfM\x93u\xe6\x86_\xa9\xee3\x14X\xd4\x7f-\xe8pJ\x95\x03\xddBSj-*\xa5\xd6\xa2\xae`R?\xeb\x0f$k\xb0\xa0\xba\xcej\xe1\xa3\xf0Y\xb8\x14>\x8b.\x85\xcf\x82\xaa}\x08\x038\xa7\xf2\x06\xdf\x8a\x88\x92\x11\xb0`N9q\n#\x98\xdf\x9cFh\xfe\x97h\x84\xe67\xa9\x11\x92\xfe\xf7.\xc5\xd0\x9cV~\xfa\x82r\x9f\x19(\xf7\x8aFp\xca\xf7\xc9\xdc\x83\x16\x9flJ\xd8N\xffC\x84\xed\xc2 \xcd\x95 l+>\xde\x13\x1a<\xf7/\xbby\xf4\x05\x84\xed\xad l\x97\x1aa\xe3\xb7\xfaKZ\xcc\x92){\x9c\xa6\xbe\xd1\xfc\x97\xde\x8a\xee\xa7nE\xf7)\xad\x1clO\xf5\xbdvA\xe5\x0d\xb9\xd7Np\xaf\x1d\xd1\x08.8\xb5<\xba\xb9\xbdvt\x93\xbb\xe2\x98\xc5\xe3O0\xe4\x1bb\xd4\xde\x10G\xd7p\x05\xa9\x1b\xe3g$6\x14\xaaG\xbd\x15\xd1\x92r\x93\xf0\x81H\xbcNvv\x1e\x84\xf8\xbd\xf0\xaa\xb2\xef\x058\x04\x99\x84\xc6\x14\xf7W\x1b\xf9\x82\x90O\x1b\x01\x88\x8f\xba2\x1c\xf2_\x86\xec\x1d\xad^\x96\xc5\xac\xab\x97J\xdbP\xae\xaf\x9f\xd6\xa1\xd4\xf4\x95\xce$\xb8\xfb\xb7[\xedD\x1a\x03\xcc\x07\x1e!0\x9bo\xc1\x0e\xecq\x88?\x12j\xc3\x9d\x9d\x10?\xb3\xf1\x05\x98Y\xa5lcH-\xb9\x0f\xf9\x825\xd7\x82_\x86D\xcbu|\xb4\x04S\x96\x9c6\xae\x87\x16o\xd5\xac\x18*\xef\xd6\xcb\x9f3\xe9\xda\xff\x98\x9a\xc5\x93\xd6\xe2=\xe6\xa4\xc8C0\x91\xead\xb4u\x05$\x0c\x05G\xe4^\xbf*\x07I\x87\xd4\x82\x0c\xb8\x19\xba\x1d\x9b\xaa\xe4\xed\xcb\xf0\xa0\x0d84&\xb2\xe4\xd9P\x00*4pT\xa7\x10\xeb\xdfN\x9d\x0f-2\x8aw\xca\xc0X\xdb\xfa\xb3\xc6\xfa\xd3\xeb\xae\x7f\xdb\xfd\xba\xb5\xfeYge*\x1de\x8b4\x19\x93`\xcf\xdd\xa6<\xa66i\x97\xa3\xa1\xa7:\xca\xd4\x95\x0f\x067\xbb3\x9d\xa2\x8d\xd67\x9fF\xb6\xb8\xce,6\xb12}i|\xb6D\xa9\x06\x06m\x82W\x9c\x15q\x83\x8d#\x89\xcf\x91\xc9\x89\xca[\xe9\xe8Q\x0e\xd6\xc7\x15\x8cbq\x11\xa2\x7fe\xd6p\x7f\x08jM\xd7-TeG\x17\xa49\xfa*M\x8f5\xc6\xaf<\x99\xf2\xda\xc9\x84e\xce\xb2:\xc9\xe2\x07\xcd\x83\x10\xeff\xee\xd3\xdd\xbd\x88yc\x11\xb3k\xad\xdfcj\xaa0\xddX\xc3\xcd\xd4V\xa5.\xa9\xad\xb9\xaa\x10\x94\xe3\xeacZMH\x9f\xcc\x86a\xc8\xfa\xcc\xf6,z\xa8\xa3kkAe\xdc\x81\xbe$\xd5\xd1\xa2y~\xb9\x90\x82\x8a=\x977\x10!\xaf%\x13\xccU0\x08\xd5\x92 \xe27y\x07\x13\xe85Y?\x1d\xa9\xd7l3\xb3\x0e\xb1\x9a\xa9\xf1\xec\xcb\xfdNn\xcf\xc8\x84N\xaf\x7f\xc5O\xe4]\xf1\x03\xb2\xdf\n\xd0\x91\xf0\xec\x17\xcb`Q\xd1\x98g(Z\xead\x1e\xba\xb2\xf393\xf3\xf9D\x05\x1c\xa1\xd6\x15\x85\x9a\x01\\\x1a\xa4\xf7c\x1a\xc1S\x93\xde\xf5\xc3\xe3\xa7/-\x9a\xd7O\xfc\xfd#\x0fi\xffq\xe9\xae\xd7\x91?\xb4.\xf3\x7frf\x94\xa9\x98\xe1L\xe7\x84\xb3\xa6\xa3^V\xd1\xbf\\\xfc\xaaS\x07\xbf\x94\x81o\x9d\xa7\xee\xb1\xd0\x03\x1cs\x80<\xa6A\xcb=\xc5\xd2\xe8\xbbnq\xb1D{\xabYR;\x9c\x86\xa8\xa3cCjH\x84k\x85\xa4\x9e\xbe\x8bU\xbc1\x0d#\xa8\\&\xb5\xd0\x88\xe3\xd5\xfc4K\xb1B\x82\xeby\xb3\xadf}|\xfd\xd7':|Z\xaa\x17?\xf9h\x03?\xb9\xb4\x81\x9f\xba\xb4\x81\xbc\x0b\xdd\xb6\xf6D\xb7\xb5E@\xfb\xcf+\x02\xf91\xe2\xcbDM\xe9\xbfdJl\x8f4_\xafH\xe0bE@.8\x91\xb9qE\xa6\xed\xeah_\xaf\x8d6zh0\x06U\xbe\x07\x8b\xe9\xcdi\xdaV\xd8c\xa61\xad\x15\xc4\xbbm\x9a\xc0\xb2\xe7tB.\xc9\xe4\x98|\xf6\x00\x8cF\xe2\xdf\xcb\xa8s\xbf^^\x1c\xfb\xb7\x8e\xc01\xa6\xc2\xf6\xd1\xccc\x82\xdf\x9e\xfa\xa4\x07\x9c\x85Y-H6\xc5\xfc\xda/\x8eQ\xe7\xc8\xff\x10\x16\x1e\x0b\xf8P\xbb\xc4\xdf\xf1\x9d\xde\xdb7\xff-\x13|\xfb\xa6\x9c\xe2\xdb779\xc9\x97du\x0dAC\xf8\x13\xd8\xfa\xa4\x93F\x8f\x1eU\xa3\x10\x98\xfcS\xcc\x89\x1aX\xcc\x1b\xa0\xebI\x0f1\xa1\x89\xb9<\xb8aXB+\xb4\x19,j\xc8\x125W\x9c\xa1\x84\x8ay\xbbYh.Sc\x18\x08\xe7@|6o\xa3oRZR\x04=\x84C\xe8aE\x028\x80^\xd4\xb3c2\x83\x01\xf4\x0czTu} \xa6\xbbp\x9c\xcaR\xfd[{\xe8\xb2\xba-,%\xfc_t3\xdaR%\xa4\xb4I\xe1\x9a\x96^4x\xe6\xf4\xda\x9c%\xc8\x1d\xe0\xc5\xb7}\"\xab/ ?\xcf\xbdVt^\x93C=\xd0\xaa\xdcb\xf5\x94\x9d^\x9d\x89\xb3t\xc3\x0d\x16A\xe6\\\xe0\x06\xae\xb5\x1cT\x1e\xc2>\xe6G\xe4\x98\x02\x07b\xc3\xb6\xb6\x83\xae\x06\xc0\x9a\xb5\x0e\xe4\xc8\xe0\x10\x82LR9l.\x94\xed\x92\xb2\xf4\xad\xa8\x18\x988\x0b2\xe7\xfe {\x9f\x9c\xcd\xd8\x86pS\x84Ig\x84*C\x94\x9b>I\xaeG\x9a\xdes\xab\xdd\x1dl\x83\xc6^\xfcq\xb7D*=\x19\xaeWWh\\\xbe&\x06?\xb9\xde!\xc1\xb9\x91\xcdz\x14yYD\xac\xdc\x1b\x8a\xa5\xc2LY0L]\xe5^5&\x9a3\xb3\x06\xe4\x80\xb9\x1f\x94\xba\xbf\x80\xd6\xfc\xee\xd5\xcb\xe9\x92\xbd\x8a7Q\x0f\x88}\x8d\x1e2\xbb\x11\xec\xecy\xf5\x92\x14G\xf3\x05\xf3\xb11\xc8^4\"\xae\xcb\xe9M\xc9\xfd@.c\x9d\x19\xf5\xe0EmFH\xaf\xd9\x8c\xb3%m\xee\xfc\x8e\xf9<\x0dH\xa5J\x12\xdb^\n\xb0\xe2\xe3\x0d\xf4*\xd8\xfb\x13_\xf6T\xf6\xefK\xa5@\xa3T\x1fI\x10V\x06)W\x06<%\xe5\x98\x88w\x17\xeb\x8a\xdf\xcb\xbc AU\xa7\\T\x12\xe7\xbbR\xcfy\xec%\xb5i2\x97\x99\xddU\x97\xa3\x94\n\x9e\x05\xba\xb9\xcdR!\xefJ?o}V\x8f|^\xc6\xe9&\xc2\xd69)\xc9\x86W\xfb2k\xa6\xc7V\xd3\x1dN\xcdk\x8b\x81Z\xfd\x13L\x97W+\xceDHu\xdf\xcd)\xd6\xab\xb7\xfeN\xc3\x86\xaa\xd5\xcd'\xd6\xaa\x1at\xf9\x8e5>&\xc6<\xa0\xea\xba\xf2\xe4\xf7\xc4.}\x93m\xb8\xdf\xa5\xf8\x81;|\xa3\xd3\xa5\x14Y6\xe7,,\xd5\";xn\xea']V\xc2%m\n\x97\xbc\xefa\x16\x01\x1d9\x05L/\xd6\x8aO\xff%\xf1%n5o\xf4M\x84=T\x8dQc\xa9]\xf3\x98\x1agd\xc7\x8a\xe8 7\xb3z8\xda\xb2\x99MF\xb1!rx\x0e\xa5\x02\xdc\xa6\xe3\xf1_-\xcf\xa1\xbc$r\x05\xfdF\x91o\xcc\xbc \xe8\x1f\xfb5\x9f\xc6\xec\xf5\xb5\xa51\xdf5\x02m\x13\xffb\xae\x93\xa4\xae&m\xabk\xea\xbb6\xb2\xd6Bn8k]\xc7\xa1\xae\x895o\xf1\x8d%O\xd9\xe2\x06ga \xd9\x1f5)\xc1WD\xd0\x8f\x12\x7f\x8c\xe1\xa7\xdd\xab\x0d\xcc\x90\xf5\x82y\x1e\xd8R\xa1\xa4.\xef\xfa\x14\x1f\x9fa]m\x9b>5\xaa\xfcd}\x07\xfe\x9cz\x0e\xddTnZ\xf8\x03c\xa1MUa:\xabU\x98\xee\xcc\xb6\x9c`\\\x90GV\xe4\x00}\x1a\xb1Z:\xc6-\xa9\xa4\xc4I\x04+\xceJ\xafB\x14\x13V\x95\xbf\xa7\x19D\xaee\xf1:\xad\xce\xf2l\xb9\xf8w\xb0\xe2~6\xbc@f\xbb{\xc7P\xd5\xc5\xf9wO\x06\xde\xc8\xb9w\xe9\\\xf8\x95\xb59w\xfe\x99\xe0\xdc\xbb\xf7\xb5~I\xf0\x04\"\x04r\xbd\x86\xe1(\xc4\x18\x06\xccY>\x8c#HFp\x00\x89\x87q\xd0A\xc7\xec0P(\xe8G\x81\xb3:\xe5\xed4?U\x14\x8cD\x90\x04&\x12\xa9.\xcb\xf87\x165f\xf1&r\x06\xd2!\x99py%b\x08V\x9e\xbd<\xdf\x84\x86\xab~\x9e\xd3M{J\x8a\xe3\xe5\xa9g\x81\xcfR\x06\x1c\xd8|\xc2\xcaJ)\xc2\xea,y\xf4J'\xe4\xb7\xb4\xe5y\\&\xc6\xd9 \x9f\x96y\x8a\x0b\xce\x0bm2\xc9\xc05K 3m\x96ay\xd3\xffT\xfbDVo\xa7\x1b\x0c\xa9<\xd483\xb7\x11$o\xc0H(\"\xce\xfd\x8f\xf8\x9aV\x86\xef\xea\xe7-)\xd5\xa7\xdbts5Z\xab\xe4W\x1f\xf9Y\xff\xfe^^g],\xbc7\xae\xb11\x97U\xbb\xefy|\xb9A\xaf/\xd8F*\x8cy|\xb9\xe9\x99\xfa\xa2\x96\x8f\xc8\xab\x13?\xa3Yk\x06p\x08\xef\xa9pa\xf9\xe8'(\xcd\x13z\xfd\xe9\x88\xee\x98\xe8\xcewn9\xd9\x18\x13\x8d!\x8f`n\xbe\xf8\x94,6\x80\x9d\xd6\xfe\xeb\x98\xcd\xfa\xf3\xf82\xb0T$\xb6t\xd6\x14\xbe}\xa5\x04\xcb\x1e\xe3M\x06D\xbb\xe3=\x90\x9fgI\xba\xa1\x99\xa1\x1c\xccO\xd74l|J\x16\x1f)K\xd2\xcd\xba\x15@WC\xdeL\x05%\x12\x82m\xd6_\xdb\xcaa\xc8\x0c\x06\xe6\xfeX\xfc\x89l\xb0\xbc\xacf\x80\xb8\x06J\xf1\xfen\x18\xa5x\x93\x9b\xa3\x14\xff\xeaKP\xea:\x92\xc4?\xbc\xb8[\xad\x84\xd1G\x8aj\xdeZ\xf26\x8c\xac\xec`x\x15;\xcd\xac\xdaeuq\x91.\xab\xc7\xe6i\x05Zja \xd8\xb1\xbb\xb5sY\xcf\xbf\xa3\xec\x7f\xc9\xb8\x19\x04\x1f\x82*\x91e\xd7\x0c\xb5f*\xe9\xa7\xfc\xf6\xd6-\xd8\xde\x8eQH\x95\x0dZ\n\x95\xab\xeb*\x8c \xb6\xbeq\x15\x81^\x06\xe9\xbfhU\xb2|\x93e!5o,\xfe\x9d[\xae\xe5\xd7\xd2\xe1Q\xa2.9N\xcf(K\xfdB\xdf\xa9e9\xd3\xee\x0f\xc0?\xe2Q\xbf\x9c\xd1\x8f\xfae\x89\x95\xd0/e\xba\x89;\x8bS\xa9K\xe8\xf0kE\xaa<\x1c\x1aUD\xa3\xac\xdf\xeb7\xd1B:\xab\xfa\xbd\x9d\xe2\xdb{\x1d\xae\xad`\xdaki\x04\x05j<\x0f9i\x1b\x0c\xe0\x8d\x14s>s\x8c,\xf0\x05\x91\xe6o)=C\xfe\x0b\x16\xb7\x8b\x088)\x80\xf1\xe1\xe6\x9aW~\xf0\\\x97\xa9(\x0f\xad\xcd\x98\n\x15C\xb0!_\xba\xb9\x186\x8b\x8b\xd9\xd3l\xb2\x81\xa3\x0b\x9bU\xd9\x05\xb0\x8a\xf3L\xcf6\xd0\xcd#@\xb9\xbd\x84\x83\xf2`\x00{p\x1bv\xcb\x8d\xe6 ]\xcaL:\xeeT\xf0\xf9\xb9\xf2\xa36\x16\x0ea\xcf\\\xf5\xb6|M\x0c\xcck\xf1\x1b\xdf\xf0\xd1^\xa2\x90~\xe7\xee\x9d\xfd\xef\xf6\xbe\xbds\xefN\x18\x95\xb7\xe1\xe1C\xd8\xbb\x07k`\xf0\xe8\xd1#\xd8\xd9\xbb\x17\xc1\xdd\xfb{\xdf\xde\xbd\xf7\xdd\xee7\xcd\xf7\xeeh\xef\xdd\x89\xe0^\xf5\x1c\xd3\xb9\x07\x0c\xb6\xe1\xce\xb7\xf7\xef\xee\x7f\xb7\xbf\xf7\xdd}Xs\x98\xfe\x8bo\xe9\x7f\xc9\xcf\xf6\xeeG\xb0\xbf\x7f\xf7\xfe\xb7\xfb\xfb\xf7\xca\xe6\x8f\xe5\xe7\xd8M\xf9\xe6\x9d\x08\xee\xec\xdf\xbf\x7f\xf7\xdb\xef\xbe\xdb\xfd.\xd4\x9bpl\xb9@\xe7\x0f(\xd6\xba<\xdc\x10j0\x80;{\xf05\xe4\xb0\x0d\x9fi\xf0\x94\xe0\xa6yJ\x02\x16\x86|F\xf6\xce\xc1sw\xaaKh\xc5\xaf\xd1K}R>\xdd\x943\xc2\x8e:;\xd8\xacq\xcfvCc9k( \xa2\x89\x14\xd6\xee4\x95\xc1|/~\x10\xc9\xc9\xb4\\\x00\xfa\x1b\x1f\xe8p\xaa\x02\xbc?\xd0\xe1+\xfe\xf7\x07i\xb2(\xf8-\x19:*n\xcb\xc0\xea\xf2\xbe\x1e8\x04\x03xF\xf1IB\x8b\x85\xc8\x8d\x8f\x9f\x1cg\xcb\xbc\x9eW\xc6\x04\xb2\x86\x12I\xba\xb7\xd6g\x87\xad\x8fgqBE\xdb\xd2\x96)ng\x94\xc5 F\xa5\xe3\x10\x84\xee\x12c\xc4s\xd3)9M\x93\x0dB#K\x01\xe5#\xb3\xae\x84I\xed\xb38j\xb9\xf7\xfbZ\xff\xedT1\xb7\xcb\x02N\xe1n#\xc3j)M('\x89a\x12A6\xb2\x17\x9f\x06\x10FU\xcd&\xe9)4\xce\xe3\xc5\xcb\xba\x0f\xb2/\x8c\xae\x01\x04\xbe\xeeMXt\x89\x19-X\x88h\x04\x07\x10\xb0\x93\xeb\xec\xd6\xd7\x14\x93\x9btf\xeexn\x07\x92\xdaI\xf5\xbe,\xed\xfc\xde\xd9\xce\x90E@F^\x8d\xbd\xb1\x90\xc3\xe6\xd9\xdc\xb1\xd9\xb6\x88O2.h\xc3\xd32\xac\xf773\xac\x9d\x1b\x1e\xd63\xf7\xb0z\x05\xd2\xc0\x9a\xf1\x03\x0e\xe1\xc5\xf1\xdb7}\xf1(\x99\xae\x84\xdaVRK\xcf\xdc\xa2\xaf\x9c\x04\xf8\xd8\x9a\xc9\xd3\xd2\xdc\xc7N\x0c\"\xf0\xb0\xe4\xe0\x08<\xc2\xbfw\x90\x9d\xf3\xea\xe0\xb3G\x07\x9c\xf5\xd9\x86\xfd\xfb\xf7\xee\xde\xbds\xef\x9b\xfb\xdf\xc16\x04\x843d\xf7C\xf1\xe7\xa3G\xb0\xdf>}\xeb\x0b%[{M\x87\x0bu$\xbe\xae\x8eD\x19\xa8\xc5\xef5\xceD\x91^\xa0|\xd08\x14;\x89\x9a\xec\xb6\xb1\xb0\x0c\xa3o\x0f0\xfc\x161\xa5>p<\xd82s\xf2\x93/M\xdf\xe0\xa73\xbf\xd1\xc0\xa9=\xbf\x93b\x9a\xd0 JO\x9e\xdd~\x817\xdd!:\xd3\xc1\x01\xec\xb4\xfd\xffLfN>*?\xc3\xd5\xb9\x9e>S\x99\xa8\x9c\xa3\xd1\xd2\x0c\x97{\xc7\xcb\xd53\x8d\x0b\xf6\xfc\x9a#+\x8dq\x7f\xd9\xe8n\"~\xc3\x13qn2~\xc3\xb7\xcb\xc5\x06}*Dm\x86\x15\xd9\x9d\x98\xf9:U\x96\x02.u\x8a\xa0Z\xb1\x10\x98\xf6j_\xfe\x89\x15\x8c;\xb23\xf2\x8b\xa8\xec\x8c\x9c`\xef*\xe7~t\xce\xafRDt\x04\x85VI\x15\x959\xa3\x03{J0\xef\xc9\xd1\x1eB\x0e\x07\x90\xab\xd0\xfdc=\x02x_94\x88\xd61\xc7\x81gP\xb0r\xee\xfc\"\xf2Qz\xab\xfe\x15$\xe4:\x8e\x9f\xa2\x9a\xbdW\xeb7\xe4\x9a\xe8\x89\xfd\x1b;\x0d6\xd2k\x87\x88\x82\xaa\x14]]\x0b\xa5e^\xafG\xd3\xdc\xba%\xf8\x8b\x99\x96dU\xe1\xed\xb5\xfc\x11EUmKV\xa5M\xdd\x117s^j\xc1\xe3\xd1\x00v1\x07\x85%\x90\xc8\x02(d\xbefUt\xd1\xce^\xf5\xa5<\xb4Z\xd5\x14\xc1v\xc61\x92/\xb2b\x13\xd3\xe6\xf5\x93|\xf8\x99\xf5\xaa\x12\x03%\n\xec\xc3\xd7\xea\xd7\x0e\xec\x89\x02\x03\x0e\xcb\x9f-\xf5\xa1~)\xa3\x01s\xca\xe5\xeaJ\xbe\xd8V\xd79 \xad\x8d`+\xc1R\x00b]Eh)\x17\xd1\xb30\xd4\x92\x96b\xb3\xf2\xbe\xb3\xe5+\xde{\xe4\xca\xa3\xa1C\xd4l\xb6\xf3\x06i\x84\xb0\xaa\x19\xd0~\xc7\xfe;'\xefo\x0f\xbd\x86\xfd\xac\x84l\xc6!\x1b\xc3\xff\xe5\xb2\x03\xdfz\x1c\x07\x92\x9a\x0b0\xc6\xfc\x1e\x88w\xe0\x10>\xf3\xb9\xc7\"\x1d)Zm\xd4\xcfL\xa5\x8c\xed\x02\xbf\xd3ZbIU^Q \xefm\x9c\x92\xf8\xdc\x87\xf3Rf\xb9!\xefbd8\x94C\xc7bq\x1e\xe5\xa5 \x00J\xff\x12\xc1\xcb~6EgZ\xebg\"?\x89\xe6\x9d\xef}\\\xc3\xbf\x8e\x1f\xf8\x9e\x11\xaa7\xed\xde\xe3y\xf2\xffq-\xbd\xeaK\xf5\xc7+\x1a\xb9\x90\xcd{\x0c?'l\xe6sN)\x99G\xef\xc5\x8do\x9c\xa7S\x01\x02\xed\xf1\xdbL\x96\xb5;W!\xa7\x08Uz\xd8\x89\xd27\xe87\xcb\xba-\xef\xd0q\xbd=\xfc\x8dy,\xc4 Q\x0bZ\x9a\x95\xbd\xe4\xb4\xeb\xe6\xd31T\x9d\x86\x9b\xd9l\xd8|\x95\xc3\xcd\x03\xda\x89\x96g[\x94\xd0\xaeY \xf4\xc7\x9a%A\xbf]3)\xfc\x1a\xe9J\xda\x10\xef\xbd\xac-\x9f\xb8\xf7C\xadiq\xef\x84\x18>\xbe \x86\xaf\x8fH\xf3\xf36TT~\xb9\x03\xa0m\xb8\"P_\xb4\xef?\xcd\xd2\x94 \xa4\x0f\xe0\xd4\xe0\x03\x81\x01b\x1f\x0d\x0f\xf4\xb4\x92\xefX\xfb\xb9\xc8\xcb\xb70<\x91\xa9\x02\x8f\x8c\xa3d\x07P\x18\x1e\xe8Y%\xe7\x86\xe7\xef\xc98\xcb'\x07\x90\x9b\x9e\xc5\xf4\x8c\x1c\xc0\xca0\x89\xf7dAb\xde\xa4\xe1YR\x1c\xc0\xccp\x7f\x9agsLmkK\x97|\x15\x01\xe9\x93\xcbE\x96\xb3\x02\x93\xc4 \xac\xbcr\xfb\xb4\xf5\x96\x05\x81\x82\xe5\xc9\x98i\xf9i\x94 ]\xdbn\x9a\x0f\x8d\xdeQ\xb3u\x15\xfb\x16G\xb0\x8c\xa0hn$L\xc6\x1e\xb00\x82-\xe3\x1e\xe6]\xa7m\xfa\xa7\xa5\x01C=OX&L;\xca\xf3,\x0fz\xaf\x13\x9aL\x132\x01r9&\x0b> \xc8\xc6\xe3e\x9e\x93\xc9\x03\xe0\x93d3\x024\xa3;s\xf5\xe2\x84\x9c\x03\xa1\xe7I\x9eQNu1\x02\x8b\xbf4]\xa6)\x10\xde*\xccIQ\xc4g\x04b:\x81x2Ix\xb3q\n3\x92.\xa6\xcb\x14.\xe2\x9c&\xf4\xac\xe8\xf7\x0c\x14\x9b\xa4\x05q\x90\xfc1\xe7i\x9a\xc0r\xf8\xf7L\xed\xfcfP\x07\x05\xeb\xe7d\x91\xc6c\x12\xdc\xfe\xbf\xc5\xed\xb3\xa8\x9b\xa8AE\xd8\xc6\xc3\xe9\xf6v;\x84\x17\x90\x8a\x85a\x9f\xc6s\x0c\x8dxN\xcf\xe3<\x89)\x83\x9f\x92,\xc5\xe4\xdb\x86\xfc\x92\xad;l\x96g\x17\x90\xf6\xa7y<'\xc5\x87\xec\x1dV\x91\xd9k\xa6b\xd3\xb0\xfa\xcb\x91\x98\x06w\xee\x86f\xdc\xcd\xaf\xdf\xba#K\xa2L~>!\xd3\x84\x12\x95\xfc\x9c\x8bE\xbd\x93\x13R\xbc\xce&\xcb\x94\xf4L\xa4T:I5\\\x9e0\x8f\x12\xe7\xbb\x9ef\xf3yF\x8f.\x19\xa1\x85\xcc\x7f\x8e\xf7\x1bwH1\x8e\x17XS\xf1UB?\xbd\x8b\xb1\xae\xa2J\x9d\xdf\xba]\xcc\xe24\xcd.\x8e>/\xe3TV#d\xfd\xd3e\x92N\xbe\xcf\xf2\xf9\xb3\x98\xc5\xe2\xb5,g$\x97OY&o\x92<\x89\xd3\xe4\x0frL\xe2|,\xda[\xc4y\xa1\xff>#\xec8\x9e/Rr<\x9e\x91\xb9\xf8\xee\xaf\x17\xc7o\xdf\x88\x9d\xd1\xe9\x01\xc6\xf2U\x07\xb3\x8c\xb6*D5\xab\x8eF\xe8\xa8o\xdd\x82^\x86\xbd\xf6D\x11\xb2\x86\xb1\xa0\xb7\xa4b\x9fNzp\x00\\\x82*\xf8\xc6\x8d\x97)\x0b\x03\x16\x86\x8ex\xd7+\x18\xc7l<\x03q8\xb6\x1e\xcb\xef\x1a\xd9\x1b\xae\xf8^\x16\x03J\xa6\xabNH\xc8F\x8e\x05\xc3|$\xf9f-\xa9<\x1c4\xfb\xc6\x1e\xe2<\x8fW\x1bt@d\xb3\xe8]\xa3\xff-\xeaI\n+\xefp\xd4\xeeH\xb0%\x92O\xd2z\x03b\x0eM\xe3\xabr\x84\x1eT\n\xae\xe6\xb3\x9eAB\x0b\x16\xd31\xc9\xa6\xb0RK\xd2\xe7[\xd2\xf5i /\xc6\x01U\xcf\x86\x8b\xb7\xd2\xb2)\xce\xb8\xcb\xb4\xbc$\xec\x8b\x8c\xce8\xdb\xea\x95\x8a\xd9\xac\xde4\xd5Nd\x98`\xf0Cv\xcc<\x0b\x05)\x15\xa3)\x87\xbb\xd2\xfd\xecF\xb0\xacP\x91\xb4\xb3\xf3v [\xe6\xf0\xc5!3$\xe80\x14\xbe\xeb*\xc6N\x879\x17\x0f\xc90\x1f\x89\xf4\x8at\x99\xa6fMt+\x13&\x82\x8cf\xf9\x1c\x0f\x0f\x81s\x03\xb8\x8c\x90N|O}\x91\xd6<\xc1vOIQ\xd2\x9dc\xd9\xc7\x92\x8eo\xbe\x175\x11\xaff\x9b\x99\x9a\x8dT\xe2u\xbc\xf0A'+\xca4\x93\xfa\xba\xf4\xa2\xf5ue\x01_Y\xa1\x8a5\xe5\xee\x84?\xdb\xa5\x84p\xc8\xef\xb1\xcb\x7f\xdb\xa8K\xc5x9^\xa7\xee$s\x1e\x08Y\xd7\x81 U\xda\xfcn\\\xdd\xa5\x18r\xb1\x01\x98\x8aU\xc1\xc8\xfc\xc3lI?\xbdN&\x93\x94\\\xc49\xf1E\x9c\xee\xfd\xcf\xfa\x93\xa4X\xf0\xb3I2\x8eH\x97\x9cp\xe9n\xd4\xf4\xb2\xd3\x82\x05\x1d[\x08\xcd\x93\x01 0\x959\x0b,\xbel`\x14#\xccw\x0d\xe7\xa0\\#\x0e\x80e\xf14\x9btC\xf9\xbcL\xb2\xa5\xaal[I4+55\xc1\x05?[.\xf8D\xfc\x93\xa8+\xe0\xec\xf7Ty\xd4m\xe8\xf5Bc\x06\xa5\x10\x19pK0\xf3\x95\\f~\x82\xf9l<\x8c\xce\xa9N9\xa5\xc0\xe1\xbc\xa7\xfc3\xd0\x8a)V/\x8a\x13\xb2\x0d\x0eu\x9a\x11\x99\x83\xc0p\xec2\xce>\xb0\x91\x1d\x96\xf5^\xfaI\x81\x9dQ\x91\xf8\xfe\xa05\x88\xf6\xfcg\xc9\xd9,M\xcef\xdd\xdc\xa5Z\xe1I6Fu\xab\x99\x01\xd9\xaa\xf8\x8c\x9e!s\xaf\x08N`\xe4\x92=\xcd(#\x94\xa94\xac\x8f\xe0\x1e\xb9S\xc5\x03\xe9\xafX'\xdf\x8d+\xb5\xec0\xba\xd2@\xa4\x83\xab\xfa\x88\x90\x0b\xdf\x8dP=\xb2\x1c\xee\x8e\"\xd44\xecE\xa8@ \xfd\x84R\x92\xff\xf8\xe1\xf5+\x91q\x18\x16\xa8V\x10r\xb2\xa8g\xbb\x80\x87\xf0\x0d\x92\xc9\xdf~\xc3\xfdJ\xa5\xe7\xdc\xd8\x99m\x86\x03\x84\xf7\x94\xaa\xae\xb7\xb7\x8b\x910\xafM+\xd8\xecE\xb05\x86\xf5\x1a\x16\xf0\x08\xbe\x15\xbd\x08\xaa\x80w\x87\xb7\x7f;\xbe\xddg\xa4`\xc18\x8c\xf8\xdb\xfc\x83\xdb\xc3\xaf~\xbb\x18i\xf7\x83\xdem9\xb2\xf5\xbal\x80\"iN\"\xf8[\xefo\xa0\xdcN\x92\x08z\x7f\xeb\xe9?\x97\xc3\x02v\xe0\xee\x08\xb6\xd1)\x9e\xf2g\xbd\x9d\x9d\xdf.\xefp\x99\xbc\xba\xf5\xf5\xed\xdeh\xb8\x18\xb9\x8de\xb8,SQ\x98\xa1\x1f/\x16\x84N\x9e\xce\x92t\x12\xc4\x9a\xc8}\x94\x12\x8efA\xafX\xc4\xb4\x17\x86\xfd\x82\xb0\xc7\x8c\xe5\xc9\xe9\x92\x91\xa0W\xb0\x15\xaa\x03\x86\xbdq\x96f\xf9\x01\xfc\x9f{\xf7\xee=\x80iF\xd9\xce\x05\x11 qO\xb3t\xf2\xa0\x17\xe1\x8a\xe1\x7f\xfa\xabxo4\\\xc0!\xae\xdd\x1d8\x84}8@\x08\xdf\x87C\xb8+\xff\xe6\xf7\xef\xc0\x01l\xdf\xfeW\x10\x07\xa7\x05\xcb\xe31[\xa7I\\\xac\xe9d\xadL\x0fk\xbeg\xd7E0_\x17$g\xe1\xe1z\xc9\xb2p}\x1a\xc4\x05Y\x93\xb3\x84\xae\xb3,\x0dHL\xc3\xc3uN\xe2O\xeb\x15#\xe1z\x8c\x8f\xf9\x81\xb3\x9e\xc5\xf9\x1aE\xdb\xc9:\x8d\x8bb\x9df\x94\xac\xb3\xf9\"]g\xb4`\xeb\x8c\xb2\x84.I\xb8\x9e\x90\xe0tyvF\xf2\xf58\x99\xc7\xe9z\x9c\xc69YO\x03\xbe\xc7\xd7$\x0f\x0f\xd7 M\xd8:\x0d\xc8Y\xcc\xc8\x9a0\x12\x1e\x86\xebI\xb6\x9ed\xcb\xd3\x94\xacI0\x9ee\xeb\xb48L\xa6\xeb\xb4 A2\x0d\x0f\xf9<\xb0\xf6\xe8\x9a.\xe7\xebsB\xd9\xfa2\x18\x93\x05[\x93\xf1z\x11\xa4\xc98a\xeb,g\xe1\x9a\x91\x80N\x8a5*M\xd69\x0d\xc3\x90w\x9d\xa6l\x96g\xcb\xb3\xd9:N\x0b\xb2Nh\x9c\x06\xe9\x8a\x0f\xe5\x92O'\x8b\xf9\xd7\x01\x89\xc73>\xfb\x84p\xb0e\xf3\xf5\x92\x8e\x03\xbe{\xf9\x00\xcf\xd2\xec4N\xd7g\x19\xcb\xd6g\xcb8\x9f\xac\x93`\xba\x9e/\x02\x81\x03\xc5Z\x1b\x04\x0d\x12\xb6F\x95~p\x92\xd11 \x0f\xd7i\xc2\xa1\xb5dk%\xfa\xacY@\xf2i<&k\x92\xd38\x0d\x0f\xc3\xc3u\x11\xae\xd3 \x9e\x9fN\xe25a\xebl\xfci\x9d\xd1\xb3p=\x0f\x92q\x9e! \\\xa3\x8ai-\xd4\x08\xe1\xfaM\xfcfM\x83xN\x8a\x05o)f\xc99Y\x93K\xb6&\x17\xeb$]gl\xbdL\xd3p\x9d\x05\xc8\x16\xad\x17\xc2\x10\xbe\xce\xd7K\xb6>'y\x9eLH\xb8^\x04\xf1\xf8S|F\xd6q\x1e\xcf\x8bu\x9e\x9c\xf3u\xc93F\xc6\x8cp@\xb0l\x9c\xa5\xeb\xe5i\x9a\x8c\xc3u\x1e\xc4 \xc7\x98 \x9ed4]\xf1\x85\x9b\xae\xcf\x92\x82\x91|\xbd 1[\x7f^&y5\xefb\xbc$k\xa1b[\xb3|\xb5\xe6T1\x0c\xd7Ep\xba\xe2\x8b\x1f\xa7d\xb2&\xe9t=\xcbr\xb6N\xce(\x99\xac\x93?\x10<1K\xc6kT\xe7\xacY\xbe\x1c\xb3\xf5\xf2\xb4\x18\xe7\xc9\x82\xad\x97\x0b\x92\xafWt<\xcb3\x9a\xfcA&\xeb\x8b\x84\x8dg!\x87\xe8|\x91\xf2\xc1\xcf\x08]\xcf\x92b=\xcb\xb3\x8b\xe2p\x9d\xc7\xb4H8\xd2\xe4K\xb2\xceW\xeb\xd5\x82\x041\xee\x8f \x99\xae\x93\xc9\x9a\xc6s\xb2\xce\xa6a\xb8^\x064\x18K4\x9f\x90i\xc0\xd9E\x8e'\x19]\xa7\xa4(\xd6\x85\x18#K\xd2p]\x90u\x91\xf0\x05:\x0f\xe2|\x9d\xe4l\x19\xa7\xeb,\x99\xacQm\xca\xd7\xe7\"\x18\xcf\xe2\xfc\x84\x89\x01\x91\x9c\xacgIJ\xd6 \x9b\x85\xeb\xcb,_\xaf\x12\x92N\xc2\xaf$\x01\x9cr~iw\x14r\x16T'9\x8a\xdc| \x97\xecM6!\xc14\x0cC\x91Al\xc1)\x94\xa0\xeb\x9cF\x1c\xf0\xf3c\xaa\x1d\x00{{\x0f`k\xb8\x17\xc1\xed\xe1o\xb7\xff\xbc\x1a\x06\xbf\xedl\x7f=x\xf8\xe8\xe0\xc1\xfa\xb7\xdf\xfa\xd1\xe1\xd6\xad\xbf\xff\xfft\xfa{{\xf8\xdb(\xac\xdfhPhI\xa0\xc7\xbc\xe3\x0cS\x93sR\xff\xb0\x07[x\xceH\x12=.\xa9\xf3\x98\x1fS\xdb\x90\xc26\x12\xe8m\xd8\x1b\x95\x7f\xee\x8f\x90 \xffvyg\xbc\xb5\xb3\xd3So\xf2{\xb7\xbf\xae\xff\xbc\xcdi\xe1\xff\x11-\x8e\x86;;\x8b\xd1\x03\x87\x07\xcf\x14\xb6\x070\xf6e.\x8d2\xda<^|\xc8\x1a|\x97M\xf5as\xb1\xe4\xc7b#\xc9~\xf9\xcapo\x04\x87\xf5\x9f\x07\xd0\xfbDV\x06\x96D)\x06\x0d\xed\xef[\xdb\xdf\xaf\xb7\xbf?\xaa1[\xaf\xe3\x85\x89\xe1k0\x90\xaf\xe3E?)\x84\x96\x04=\x81\x84\xf7\xc3\x06\x1cd\x9dc\xa4\xa2\x82\x0dE\x0b\x89\x89g\xe4\xfd\xd3*\xef\xfd^\xa5\x11\xea\xcfI~F\x02\x93\x14x.\xa3\xe5\xbbG\xc3\xdf\xe4\x8c\x155V\x07\xe2O\x0bK\xf4\xbc2\xecl\xed\x99\x9fM-:]p*=K\xe6o\x11\xc1\x04\x06(~&\x9a\x96RE\x06\x04!\xa6 \xe4\x83\x0b\xf8\xb6\x9e\xd4\x1c\x85\xc2\x07r\xd8..\x8e\xf72\xe3\x14\xc3'8\xfd\\\x8e%\xab\xc62C\x17Y\xe7Ws\x0e\x83\xceP\xf63|k\xaf\xe3\xad\x15\xe7i\x83\xb3\x08h\x99m'\x82\x9c3X\xc12\x82yS\x0d\xad_mTPB\xc7\x8a\x0b\x1d\xb1r\xfe\xc0\xec\x87\xb1H\x9a\xb72s\x83\x06b\xa1\xab\x86\x8d\xdf\x8c\xa5k\x05r\xe5\x86\xef\xa7\x9c\xfbHm\x18a\xc7\x15~ma \xdeI_n\n\xedo[\xe2\xe6\x8e\xee@\xf1\xf7\xa14\xe0M}\xe1\xd0\xba#\xc7\x14\xb7I)\xb9D\x8e\xf4\xfb$%o\xe29\xf9>\xcf\xe6R\xa6y\x96\x14\x8b\xac@\xe3\xeb\x8f$\x9ex\x94\x95W\"\xde\xedi\x92\x12~l\x0fz\xc1\xf0_\x0fF_\x87\x0f\x0e{\xb7\x93>\xb9$c\xa3\xe1\x00\xcb\x9e\x08\xdb\x00g\xea\xebm\x94MT-\xd8\x88\x93\xaa\x9e\x82\xcdh\xb2\xa1F\xaa\x8c\xf9\x19\x94\x12n\x99\xa6m\x08-\xe2b\x1c\xa7O\xe3\x82\xc0\x00\x9e\xd6\xef|/\x07\xd9 \x1a\xd9\xc3\xd3\x80Tf\xe2\xdf\xfa\xc3\x7f\xf5o\x8f\xbe\xfe\xea6\x17%B\x93\xc6*\xa6 K\xfe \x1f\xf3\xb4\xb3\x07\x0e\x802vlK\x8b\x1d\xe3\xc2\x9a\xd0u\xb8ekM18\xd6{\x0e\x8dG\xf0\x19a\x8f\xc7\x9c\xcb\xe7\xd8\x92gi\x9a\xd0\xb3\xf7\xa4Xd\xb4\xe8\x86F\xe3$\xab\x14\xfe\xfd\xa4\xd0\xb4\xff\x9a:\x84/\x8dMcP?\xf6\xccoV\xfa\xa5\xbaCx\x97Wry\xc2\x15,\xceY\xf1s\xc2fAo\xbfW\xea#u\x15*:\xe9\xf5\xc6b\xf7\xf4\xf04\xfd\xf3*\xac\xb0\xd0V\xa8\xc1LlK\xd5N\xd0\x93]\x88&\x8dv\x12K\x1b|\xcb\x06\xd40.s#a\xa9|\x93\xa6.5v\xa1\x0d2CVA\x887\x9b\xb7\xf1dB\xc8\"]\x1d\xb3\x8e\xbaLmJ\xf3\xdeP\x86\xffye\x0eLi\xe0hf09\xd9\x15\xdaU\x1cQ\x1edC6\xc2\xbdr\x08\x13\x92\x12F\x80\xdf\xe1B\x0d\xff\x87\xf3\x03\xe2\x0dj\xcce`\xcaV\xabl\x03\x06\xb2\xa7\xa2!\xbd\x08\x89)`\xd6\x95\x19HV We=\x95Y\xd7r\xa6X\xad\x16\xa4k\xc1\x89\xb0Z\x94\x87\x12 \x1d\x0c\x84F|s\xad\x89\x08\x84}o\xdf\x00R\xc5\xect\x19$\xcdQ\xc2\xe0\xe2\x13\x88#\x15\x03\xebS\xf4\xbd\xf8\x90\x95\xfe\x1c\x1ek$\xbe\xb1\xac\x91\xd6\x9b\x15M\x1a\xa6\xbf\xfa{\xe7\xb2\x92\xe7I@\x83oL>\x12ctH\xba\xf7\xcd\x9e\xe1\xd9T~x\xef\x1b\xa3{\xc5B\xb9f|\xbbkz<)\x1f\xdf5=\x9e\x95\x8f\x8d\xe3:\x97\x8f\xef\xdf36>W.%\xbb\xf7L\x8f\xcfpV{\xdf\x99x\xff\x95\xfc\xf4\x8eqR\xa7\nX\xfbw8\xe2\xd7\x9e\x97\x04\xfa\xa4\xc3w\xe1\xd6-\x0c\xe1P\xbeU\xd2\xb5\xd8\x8c\x8b\x12\xa5M\xa5\xea\x9bQ\xf3\xfa/\xbe\xb0\x170\x80\xf2\x08lO\xe5\xc8\xe0\xc0\xd3\xad\xd9o\xc9\xc8fsL{\xb06`]ndv\xae\n\x047&on\xfc\xd8\xd9\xf8\xd6\x16q\xdaW}(\x95c\x0dtO\xa9\x89\xfa\xc8\x06\x86\xa7\xce\x91\xf2~\x17U\xbf\xfc\xe7\xd4\x7f\x18u\x07\xaeN\x16\xce\xa1\xf8\xd9\x8c\x8b\x18Z\xc4a\x0b\x8br\xc7\xda\xf8\x9dz\xe3wD\xe3NN\xbcn\xa2\x97} \xefQ\x7f\xc8\xca\x87\xeb5 `\xcfk\xc7\x88\x0e-\xab\xfd\x18\x9d\x84\xab\xfc\xdf\xb4b\xbfM\x9a\x15\xd0\xfd\x00\x86\xd4\x92\xf6\xces\xa3\xc1!h\x02AR\x04\x182\xc5Q\xd5\xcaq\xf9\xa05\n?\xb6\x06|\xfc\x0e\xf0\x08'\xf8i\xd6&\x06\x82{k\xd4l\xeb*`\xb3\xc5{\x99k\xc3\x1cR\xceY\x0d\xa9\xc1\xeau\xd5\xdc\x12\xeds\xef\x93\xc5\xe1\xb1s\x7f\x80\xb2\xa7\xc2#\xa8\xc2\xc4{?\xc5\xe9\x92\xc0|Y08%\x90\x92\xa2\x006\x8b)\xc8\x96\xbd\xca\xd9?\xb68fn0\xa6\x87\xf61\x9d\xa1\xc2=\x97\xc3\x12\x8d{\x0d\xeb\xad\xd9\x85\xb4\xfb\xb4@9\xf3\xf6\xbfv\x0e\x7f\x9bl\x07\xbf\xf5\xf9?\xe1\xa1\xb2\x0chRjc\xa01H\xb6\xc7gp\xef,>\xaf\x9b\x8d\xcecP\x14#\x01\xcf<\x87\xf5\xc1\xe4\x9b\xeb7&<\x95\xb6\x02\xe2\xf0)\xb4Cn\x9a\xa4\xc4k\x80\xaf-\x0e\xc5~c\xec\xb1|Iz\xb2n0?D\xa7qZ\xe87\xb6v\xb5\xbf\xf7\x14#o\x1b\xf5\xa9\xe8\xdek\xe0\xcf\xcd\xce\xd1~\xe3\x16\x835\xa8{\xecc\x93/\xfb\x0c\xedw\x9b3\xb7\xdf\xe0\x92\xe2M\xfc&\xe0\x9f\x95\xce\xc2\x8e\x95V\xcd{\x8d\xec\x8d\xc9\xef\xdcoTJ\xd8S\xa2F\x9fe\xaf\xb2\x0b\x92?\x8d\x0b\x12\x84\x11l\xdd\xfe\xd7\xf0\xcf`t8\xdc\xdd\xf9.\xde\x99\x8e\xfe\xfc\xf6j\xa7\xfc\xfb\xae\xc7\xdf{\xfbW\xc3\xf0j\xe4E\x18\xf8\xc8\xbd&\xfc\xde\xea~\xefOL+\xde\xc4\x8f\xce\x8b.\xbc\x86\xf7\xcc\x1a3\xb0\xf9\xf06 \xf9\x1b\x8c\xf0\x95%\xd2\xc1{|[\x94\\\xc0{rvt\x89\xfe\xc8\xae\xa5\x9dfi\x9a]\xc0Bv\xd2\x83m\x93\x03{\xfd\x0co\xc7et\x8e\xec\xba\x9c\xed\xad[\xb5\xdfv\xae\xd6\xc6\xf1\"\xab\x87\x94\xe74\x9b\xac\xa4RY\xa8\x17\x13\xda\x13N\xf2\xf8\x0b\xcdX'\x97\xf3\xb4\x87\xee\xf2\xda\xcd\x9eEU\x99T\xea\xce\x9c\xa0\x9b\xc2\xc4\xf6j\x0c\xc2;J\xbe^`\x84\x8b\xe8\xc8\xa2\"\x8e\xcb\xd5\xca\xedv\xc7X47\x97|\x8e\xa5\xf3\xb1\xf6\xa6d=,oN\xab79q\xb6\xbd\xb6\xa8^\x9bf\xf9\x8f\xe0,\x82\xd3\x08N\"\xb8\x88\xe0(\x82\xcb\x08\x8eG\x0d\xe1\xd59\xf6J\xdfd|\xc5V\x92\x0eYB\xe4\x9f\x9f\x86\xcd\xb9\xbf\x97\xb4\x1e\xa6 I'\x90\x14@3\x06\x8b<;O&x\x02\x98(\xb6j\xf4\xdc5X>\xf1\x8f0\x80WA\x16\xc1\xb9\xc3%\xe1#\x1a8\xc4x>\xfa\xba\x1a\x80\x1c\xc2\xa4\xda:\x93\xae\xd1|\x86\x01\xbc\xe7\xa3\x998F\xf3Y\x1b\xcd\xe7MG3\xeb\x1a\xc2\xf70\x80g|\x083\xc7\x10\xbe\xd7\x86\xf0\xfd\xa6CXV\x00q\x96\x1d\xe1\xa3\xf9\x03S]a\x91\x11\xfbh\xfe\xd0F\xf3\xc7\xa6\xa3\x19W\xa3\x19w\x8d\xe6 \x0c\xe01\x1f\xcd\xd81\x9a'\xdah\x9el:\x9a\xfa\x91\xd85\x9e\x9f\x1c^K\xeaB\xee&\xf8 5\xe41#;\x8c\xcbQ\xd8\xfc\x02\x0e\xe1\xf7\x00Uh\xbd%\x176\xca\xbbo\xc4\xdd\xe7\x82\x88\xda\xf9\"u\xc9\xd9\xfedsb\xa9\xc8l\xfd`\xeb\x9a\xdf\x8f0\x80\xd7\x81\xab\xda\n\xce\xee\xc7\x0d\xc6\xf8c\xf7\x18k\x87g\xd7\x10\x7f\x86\x01\xbc\xed\x1e\xe2\xcf\x1b\x0c\xf1\xe7\xee!\xd6O\xe8\xae1\xbe\xc0\xec\x8d\x9dc|\xb1\xc1\x18_t\x8fQg\xb0\xbaF\xf8k\xc7\xd0N\x91\xf9)\xd90\x9f\x81\xfe\xaax\xd6\xe74\x18\xf6\x12F\xe6E/\x02\xc1g\x8f0\xc9N\xcb\xcc\xdd\xe5\xe9\x01\x9a`\xd5\xb5\xed\xf8U\xc3\xa4_\xd1E\x82#\x0b\x86\xaa\xd6\x97P=|'\x1f\xeaT\xe0Wd\xc0\xf8\xd3\xe7\\\xa8\x8c\xa4\xb9]\xac\x83{\xb0\xfcJDVKC\xde\x95\xe6\x85\x995\x0e,\x99\xc4\xd4\xe5\xac7\xdb\x89\x13\x1a\x83\xdc\x85\x12/a\x00\x1f\xba\x91\xf6\xa5\x0f.H`\xbd\xf4\xa5\xc6V\xab\xb7\xc1{\xa5\x9dF\xc1\xcd))7\xa3/w66X:Az\x05m*\xf6\xb7\x0cZ\xa6\xf8g\x0e\xef\xdb\x97\xf3T\xea\xae\x98U\xbeK\x84\xcf\xd5\xe5<\xc5m\x8b\x7fa~\x12\xd7\x9a\x0b=\x0f\xff\x86K\xf9\xf2\xdb?\xaf\"\xfe\xfdW_\xe5d\xaa;\x03\xac\x16\xe8\xb4F\xfa\xb8\xaf\xc5\x9f\x0b\x91\xcf#!\xf2w\x95\x16\xe6]\xf5\xe4\x10\xfe\xf6\xf0\x907~N\xf2\"\xc9\xe8\xa0\xb7\xd7\xdf\xed\x01\xa1\xe3l\x92\xd0\xb3A\xef\xe3\x87\xefw\xbe\xed\x1d>\xfa\x8dJ\xb7v\xf8\xe5\xf5+ \x97\xb8\xc40\x8e)g>O \x9c\x11\x8a\xc9\x19' B\x94\xfef\xf5~R\xd7yY^\n\xa7\xd3\x9fsQ \xb8\xfd\xdb\xf1\xd7\xbf\xdd\x0e~;\xde\x0e\xbf\xba\xed@\xf6\n\x88\xb2\x84\x94'*C\xddXx\xa6,\xb5\x93\xa7\xa8/\xfb\xe5\xf5\xab#17\xe1J\xe2\xe3\x01r.\xcb\xaa\xd5\xdb\x13\x9b\xe0\xfb<\x9b\x8b\x8d \xdbk\xcfH)\xc5l\x92]\xd2%\xd9%a\x08\x87M?\x98\xa4\xf2\x83\x81\x83F\x8eJ\xe9\xa3\xa9\xa7?q\xba}\x9d\xcb\xcc\x86\x7f\x1at\x85 \x93\x17V\xe2|\x9a\x8d1\xcbN\xbf\xc0\xc6-\xfa\xa5Joi\xdbZ=\xa1\xa4w)MD\x16\x94byZ\xb0<\xd8\x0b\xfb\xc5\"MX\xd0\xbbe\xd2\xc6\x80\xee\x9f\x9eCB\x81\x86@\xfb\xb3\xb8x{A\xcb\xdc7\xb9pS\xc4(\xc3a>R-\x0e\xb8XE\x86\x132\xce&\xe4\xe3\xfb\xe7O\xb3\xf9\"\xa3\x84\xb2 \x1f\xee\x8e\xc2\x11\x0c \xe7T\xe8\xd6-0\xbe\xb37\x12v\xd5\x9e\x0f>\xa9m\xdd^\xb3v\x1a\x1b7m\xb5Z\xc5\xfd\xca\x97\xab\x81\xd0\xd6\x8cD\xca\xfdA\x0f\xb6MO\xc9\x90\x19\x0d\xb3\xfd\xdf\xb3\x84\xe2\xf2\xb4\xa7&S\xf5\xb8\x07\xa5\xe6S\xcb\xb9\xa1r\x17Sr\x01$`\x9a\xb9\"\x82\xde\x92Mw\xbe\xed\x85au\xb7w\x1a\x17\xe4\xfe]\xd3\x18\xaa\xd4A\xed\xae3\x0c6K2Z\x1c\xe3[6\xaf\x9d8]\xccb\xcf\\\x83\xa0\xbb\x8f)m\xe2\xac\x17\xe2\x16J \x07h\x9c\xf3)i\xcf,G\xb6yc\xce \x9be\x93k\x8fF|n\x1b\x8fz\xea\xcdD\xb4\xc7\xc8\xe2\xb3\xbf\n\x9c\x8d!{\x0f\xd2\x80\x99\x8d\x14S~\xec\x8c\xc9I\xa5\x8a\x8d\xe6\xe4\xc7z\xfa+_^b\xf5\x10\xd1\xd8\x96\x1c5\x88\xbd\xeao&x\xbb!\x8d\xf8\x06\x8dL\xfb3\x0f\xb5\xc4k\xfb\xbb\xb7\xcf\"\xe8m\xf7\xc2\x91\xdc\x9f\xa6%\xb5R)\xe6\xda\xd4\x86\x94]\xb5\x95\xb48\xd6\x94J3N\xb8f\x15\xe1\xa2\x9aSN\x97\xcb\xc8F\x1e#\xf5\x91\xd7a\xae\x94b\x96\xbcd^\x04\xd8X\xa0\x063\x8ektL\x9a\xb31\xa5Q\x9e\xcc\x03m\x91~\xc3\xecx\xbd\x13\xb4\xd8\xf4z\xae\xe1Z\xb2\xaay\x0d\x93\xc3\xec\xb4\x82\xd9\xc7\xb6{Yd\xc8\xe3\xe6\xd54ig\x9b\xe8N\xc2z\xfb_\x97;%s\xdd\xb9l\x915\xf7\xdc_9Bi\xffY\x97\xf6\xa5ui=ZK\xbb\xd8ZZ\xbd\xfc\xa7\xf2?\xd5\x83\xb2\x90\x16\x0d\xee\xdd\x0d\xfbO\x96\xd3)\x91\xde\xe2\xd7\xca\x06hN\x88\xd9\x9cfI\xa9\x8c\x92\x99\xc8\x15\x0f\xff\x7f\xf2\xde\xbc\xbbm\x1cK\x14\xff\xbf?\xc55\xa7_\x8a,\xd3\xb4$\xaf\x91\xedx\xb28\xdd\x99\xc9\xf6b\xa7\xea\xd7\xa3\xf2xh\n\x92\xd8\xa1H\x15\x17;\xae\xb2\xe7\xb3\xff\x0e.\x00\x12\x04\x01\x92rR\xd3\xfd\xde\xe3\xc9\x89E\x12\xc4r\x01\\\xdc\xfd\x9e@\x15\xcb\xf2\x13\xf1\x83\x9c\xc7\xa2\xfc\x17$\x0b(\x81p\x047a\x16\xe6\xb0\xc8\xf3\xd5x{{\xe6\x07\xe4:I\xbex\xf30_\x14\xd7^\x98l\xa7\xf4\xbb\xedi\x12d\xdb\xf8\xf1\x16#\x9fRo\x91/\xa3\xd3P\xc4nd\x94\x86\xcb\xf3\xb9A\n\xc7\x90\x1fA\xba\xb9\xe9@\x0c\x9b'`=\xf1\xd3y6\xb94Q$\x157\x97\xa2\xcb\xaeB\x1f\xb2:\xeaq5ED\xcd$\xed\x1f\x94\xb3\n\xc8\x99uG\xe2l\xa2\x99\xa4\x16\x1dS\xe5\x15\x98C[\xd2\x1a\xd8\x12\xc58j\xc4\xca\xca\n\xef\xbb\xc4\xa8'\x14\xd8\xe7\xa4\x1f\xac\x932\x1a\xf1#\x9a\xacB\x19\xcbcf\x1d\xa8nz\xf5#\xcb\xfd\xe0\xcb#\xba\x80\x11\x98\xd9\xb8\xe9/:r\xfa\xb7W\x9b!\xb7\xd0}D\xb3\xc2\xb8\x17[\xd6\x18\xfd\xf6j?\xc5H\xcfk\xb5^\xd4\xb3\xbd\x88\xa8=\xad\xca\xa8\xf2\x84\xc84'\x04\x8b\xac\xc3\x8c\x102x\x06{p\n\x19l\xc1\x1e\x8c1\xf3R\x00'\xb0w\x04\x01\x1cCv\x04\x01E\xe3\xd1$\xa0\x05.\xe5\xda&AKb\xf0\x1b\xee\xa5n\xb6\xa3\x86R\xdb3\x93\xe9\xac\xd4c\xc1\xb0\x8d\xe2:q\xd1\x16\xd0\xd4\xc4\x9eux\x8a\x03\xb75 \xdb\xe5\xdf\x1c\xdcR,h\x8a\xc3\xa3p\x8afOSzb\xc2\x7f\xd1\x9f\x05\xfd\xf9_\x90\xcc\x90Zd\xcfV\xecYV\xacV\x11=\x7f\xf2\x84=O\xf0\xb9\x0b\xe4\xeb\n\x03\x9c\x80\x1fC\xe9\xd8\xe1\xfd=\xe3\xa1\xbf=\x8d\xe8A\\z)\x19\xc8\xb3\xbch\xe5X\xc4EK\xde \xe7\xb2\xe8H\xe9\xde\xa9\x8b\x16\x97\xb0\x8d\x99\x95\xd9\x03\xdb\xacN\xe4\x0b\x1d\xf3y\x1eJ\x91~h\xb2taQ\xaeo\n9\x8f\xc2pQfP\x88\xda<\xf1\xc5E;?/\xe5W\xf3\xd6\xf2f\xd8\x1a\x82\xc5\xf5\xda\xe4\xd9\xc2_\x911\xac\x9aoD\xa07\xed\xcb\xa5\xbfzY\xbe\xef\x8d\x1ef\x88\x9c\x1ew\x06F\x18\xe5>\xb3\xf5\xe7\xb6\xb6\x87X\xbc\xd9Z\xdb\xf9\x8a\x9f\xf4<+\xb5'#V\xd0<\xeb\xdaN6\xb9\xcd\xae\xb3\xcap2\xb1V\x0dg\x8d\xae\x9f\xbf\xf2~\xfe\xca\xfb\xf9+\xf6\xf3WM\xd9\x94\xc7\xfb\xcfl\x8b\xed\x7f\xcb\xed?\xe1D\x87.\x9b\xb3\xadi6,S,d\xf6\x9a\xc7\x99\xec&&z\n~\xb3\xaf\x82+\x11|t}\xbb\xf2\x11h\x9c\xc7\x84\xfeu\\\x1f\x1e\xb3R\xa5\xef\x85\xfc}\xac\x8e_\xf4\x97\x16\xaa0+r\x1ae\xcen\xbb\x14>\x03\x06F\xac\x05\xdf}\xd0\x8c\xac\xd00]\xe2]\xce\x8f\xe1\xb4\x0c\x9e\xa7\x9b\xb0\xb5N\xe0}~\x02\xefK'\xf0\xbe\xee\x04\xde\xef>\x81\x05\xd5\x00'\x80\xa6+)\x0b\x9e\xc7\x8c\x1c]\xe1\xbd\xcb\xe2\xb3\x9e\x02QQpm`2\xe2\xe5\xc9\xe8\xa5\xe3\xb14u\xa2\xc0\xf6\x1b\xe7\xe3\xad\xcfl\x9f\xb2\x15 \x18S\x16\xc6\xac@\x88\x05<\x94\x97\xb0\x86\xebk\xad\xb1\xa2\x98&A\n\x0f\xbc1t\xb4++\xf6\xc2\xac\xec\x96\xfa\xcd\xa0\x16\\U7\xed\x99\x96\xfco\xd2ar\xf4D\xed\xec\x8b\x89\xa7P6\xa9X\xec\xac\xd5\xe44B\xda\xa6#\x87\x8f\x81X \xdb\x89\x95\xa8/\xb1\xf2_\xa5\xac\xe0\xbft\x14\x8aQ\xec\xd8\x8c;\xe2\xb4\xc2=2\xc9\x1b\x9b\xa0\xaf\xe0\xaeI\n\x02\xf2\xc6\x8b\xb4\x1b/(7^\xc4I\xdfH\"}g\x8c\xf4\x9d\xc11DG0\xa3\x1b/\x98\xcc\x9a\xa4\xef\xcc\x10\xd0i\x85\xaa\xa6\xc44\xe7\xb1\xbdj\x9ds\xbaf\x0b3\xfd\x84F\xd0\xf6\xeaQKB\xa2_3\xcd\x92X\x18\x96D\xd8E\xbf\xa2K\x00#\xd5\xfa,\x10fW\xc1'S\xef\xe7\xa3\x19\x00-#\x1ce\x0d]\xc4y_\xa5\xc9\xea\xa2\x1cS\xd6\xe8{\xb9\xe2\xb4\x99V\xca\x95s\x83\x91\xab\xca\xc8\xf5.\x92\xb8\x03\x97\xd3\xac<\xa1-,\xe1\x18\xe6G\xb0\xa4\x8b\xc4<\xa5\x18ZJE\xb27.,\xcbEL{9\xa1\xfd]\xd2_\x97V\x89t\x03\x13\xb5K\x81x'\x9f\x82\x08\xae\x12\x80w\x1d\xf3\xd0\xb1\x19\x85xC\x17.\xbb\xb9\x1f[\xb7`\xa2\xdd\x82a\xb9\x05\x13\xc7\xe5 \x10\xc1\x87cH\x8e\xc0\xa7\xd0\x0c'~}\xbb\xf9\xe6s\x0eQ\x07vU\x01r\x88:]\x16\x7f \xf3\x8d\xb8r\xb7\xab!\xa2[\xae~\xfe\xcaq\x84\xdaq\xf8\xe58B\x8eJB \x95\x14\x0c\x95\x14p\x0c\xe1\x11\x14t\\\xfe\xa4h\xa2\x92\xc2\xa4E\xe2(\x8cLrC \xe3^\xca\xda\xf6\xd2\x17r\x97]H\xfb\xc9NV\\\x08\x9a\x91 \x89\xa7e\xd7\x9c\xe6V\x8bM[\xad\xc9\xe6\xb6o5\x90\xa1\x8b\xe1~\xe5H=\xe5\xbe\x9b\xb1}G\xb1jP\xee;\x8a\x9cW\x1c9\x9b9T\x81N3u\xef\x05.\xcc\xca\x99G\xa4\xb8\xf5\x8c\x02\xc5\xa6\xe3\x08&\xb3K\xfa\xcc\xa9v\xa1\xdf\xc6s2\x8bi\xe3Nl\x92\xe5\xa0\xc5\x8a\x0fNs\xf5\xea\x0f\x98l\x9d\x9d<3\xd3\xe7\x92\x05\x8bb\xb7U1\x060\xae\xbdk\x9eK\xb1\xa9\"\xb4\xd1\xd2r\x15\xb5:G\x97Z\"\xee\xff\xa5\xd3\xfe\xb1\xc7y\xd1~\x9cO\xff\x87\x8e\xf3\x9b2\xcec%\xffi=X\xbb4\xebK\xc4x7-\x18o\xd9\xb5\xeb\xe9)\xbdTw\xfd\xc2\x85\x9b\xda\x89\x8b\x1c\xe2M\xf7Y\x0b=%J\x9d\xc6\n\xed[u\xd5\xdc\xaa\x95|G\xfeT\xfc\x925\x85\xcc~\xecQ\x8a\xa3\xed\x1f\xcb\x9f\x8c\xc3\xde\xf2\xb3,\x9cWl\x92\x1d8p\x1e\xc6\xd3\x94\xc0y\x92.\x8a\n\x01\xfdk\x14\x06$\xce\x08\xbc{sQ>\xfcq\xbb\xfc)tR<\x8d\xd9\x9c\xe4\x92)\xd7\xf9\xdd\xf2:\x89\xb2\xa6\xae\x8a\x97\xae%\xb9\x94\xbek\xea\xae\x1a\x1fp\xcb\xca\xbb7\xd9Y\\,\x19\xda9\xd2\xc2\xcdH\xc4\xe8=\xa9pS\xf3\xe6\x18\x94Z\xc3\x89\xdcp\xbb<\xba\x83\x85u\x93\x7f\x1d\x98|\x11\xc9\x04\xb1\x8e5%\x96\x0b\xd6\x1e\xb34\xd4\xc2\xee\xbd\xbf$\x99M\x9c\xc9\xe0\xb2\xb5\x0355\xf1\xef\x0fL)<8\x82\x18\x8eaH\xffR\x84\x97O\xac+\xba\x15X\x0f1\x0f\xd3\xcb\x85\x9f\xbeL\xa6\xc4\x8e\xd1t.\xd6\xf7\xd7\x1a\x0cG;\xbb{\xfb\x07\x87O\x99}KK_s\xc5\xa6\xadK\xc4\x95\xabq\x84\x00$\x0b5\xab=\x8c\x8bXw-I\x91\xe8\xc9p3\xb4\xb6\xb2\xd2\xb6\xc2\x94\xd7\xc4\xbb\x9aE\xfe<\x83'PPZ\xe5\xa5\x1f,\x08K\xa5@[\xd1\xcbxo\xcaLG\x154\xe8\x17)\xd1$\x80\x06\x11\xa7\x82%m\xc2\x82M\x9c@\xc6\xb2\xb8\x02\xed\xe7\xb55!zV\xed\xea\xc3Vm\xfb\x0d\x8fx\x1fO\xc2\x8e8\xea\x19\x02\xddw\xbc\xabi\xb2|\xf3\xaa\x9d\xa2f\x16\xb2Z\xaeN\xbepTGU\xd4\xd1\xe4\x08\xa1\x91`P\xfa\xf3\xf0:\n\xe3\xb9Yy..\xda`d'\x94\x8b\xecjP\\3\xdbw\xa1\xcd\xa3K\xbe\x02\x9e\x91FC\x08\xa8\x97Y\xe7L\xaf\xd4\xb6vF\x16\xed\xa7\xb1\x98A5\xdd\\\x12bi\xde\x9f\xe8\xd7\xe6\x9f\xf4\xdf\xeb\xb6\xc0\xb4\xb9\xb5\x19\xd1\x9aU4(\xbd92\xec~&qa\x96\xd7\xb0\x81%M\xc4\x03w\x7f#\x98\xda\xdb[\xf9)\x89q\xc3:\xb2vA\xb3\x01p?U\xc5\x0d\x83\x83jI\x91\xd2U\x11\x87q\x84U\xa4\xde*Y\xd9\x8e\x83\xd8\x8a\xf6Y\x98U>y\x02+z\x96\xaa(E\x90\xac\x7fj\xb6%\xb8\xe3\xfa8\xe7$\x7f\x19%\x19\xc9rq\xc6\xbcN\x93%\xed\xf2\x18\xa6\xaeZ\xb4Y\xa6\x9d\xfc\x12\xf4\xfeT\x1b\x97^\x82 \xca\x0b\x99I\xba\x84\x13y\x18\xc2\x9c\xfb\x87\xd5\x81\xd8\xe8\x1c\xfd\x86vLt\xb2\xabsa=\xfb:\x91Z\xc6\x98\xcc\xd6\xce\x0e\xba\xf2T\xcf%7\xba\xf2Y\x07\xa7\xc3V\x98T\xdc\x11V\xf7\xa4\xaa\xfb#\xae\x13\xd4\x8f\xda\xd6\xce.\xb6\n'\xf5\xb7\x86v\x8e\xca@\xfcl\xc5\xe4b\xc5\xe01!\xf7\xdd\x08\x7f\xa9P\x1b\x84W) \xe8\x96\xadvl\xc3nD\x14\xe1KC!ub\xf9]\xafe\xd3\nf&L\xe7\xd1\xb2\xe9\xc9Y\x1b.\xdd/E\x14\x19\x8d\xa5\xf5<\xf8\x02\x9f\xaa\x04\xa4\xdc\xc5\xea\xb0\xac\xbeR\xce{\xe6\x1d9\x06k\xe4\xedy{\x96\xaeMM\xc0\xe6\xab+\x86\x01\xe8\xdf\x13q^~+);\xd0\x19\xe0N\xac/a<\xa5|}J\xb2$\xba!,\xf7Z\x9ca\xae)z#D\xc8\x1ff\xf4n\x95\x92i\x18\xf89a\x9f\xacR\x92\x91\x18\xcbq\xf3\xffs\x9e\xec\x8de}{\x1e\x85~F2\xeb\xb2I.O\xac,\xf0#?\xc5\xb2\xe4\xd7\x82\xc4\x01~\xb7\xf4W\xab0\x9e[\x97\x1d\x92\x11#y\xe5\x82__ \xe1\x8c\xe5\xb9\xc8\x85'\xac\xcc\xe1\xe6}\xc3\xb4\xd3Z\xb6x\xd8 \x0f\x9d\xc1?\xcc\xd0w\xb7b\x1bS\xfb\x87\xcf\xf1\x978\xb9\x8d\x81\xa9.\xc0\xfa\x81\x13\xa8?X\x10f\xb0$9%\x80\x90KD\x03oHf\xac\x0cae\xfe\xf6\xfc\xdd[\\\x04\xde\x0f\xcaju\\\xc8\x17a\xe6\xe5\xfe\x9c\xae8~G'\x0f7:\xfe\xe0\xf1\xed\xf9;>\xa1\xf8Z\xfc\xbe\xbf7\x8b\x96@b\xd3\x15\xb3\x07^c\xb9.\x98[Ky'\xd7\xda\xea*\xa1\xad\xb5Z`,\xbctu[\x1fO\xb9\xf4\x18f+\xef\xd4Q\xf35\xc9\xc7-\xee\xea\xa5\xe4\xc5\x8a\x05k\x0f\xeae\xe5\x85\x8c\xec\x1cs\x1e\x95\x9f\x96\x1f\xf8B\x9e%hB\x8c1 \xaf\xb7\xb8\xaf\x08'\x9e\x90\xcb\x9eK\x93^\xfe\xa4d\xc6LR\x9f\xc6\x82\xf2\x1d\x17\xf8\x92\x0e\xab%-\xd6\x95ii\xe3Rc\x0b\xbb\\\x82b\x81W\x165\xf4@\xea\\\xd9\xbdx\xf4\n\x85\x8dvG\x8em\xdd~\xc9\xd4\xf8j\x8c+\x1f\xee\x1b\xd8\xf2\x1d\xc7cR\xdd&s\xaeM\xdc+\x99\xe3\xda\xfd\xfc^\xf8\x02G\x91\xdb\xfd=\xd8\\\xf6\xe6\xd3\xd9\x0f\xc5C\x1f\xf5\xb0cH\x1c\xdbb\xfda\xc6`\x92\xb3\xd4\x83\xe3ey\x82\xa9\x92\xd3>\xb0\xd1#\xfd\\\x0e\x15_\x0f\xdc%\x80\x19\xda\xb1\xbd\xb7\x7f\xa8\x06\xacO\xf8\xab\xa7CG+7\x08\x8dC\xef\x1f\xa3\xde\x10\x9f\xfe\xe1O\xcd_\xe5\xbel\x13\x89\x0bmD\xdb\xc1\x00\x1c\x81\xab\xf6}\x15\x11\xa7\x17\x81)\xce\xf1\xa5\xf0\xae\xfa\xb0\xb3Y\x90\x08\x05S\xb0Gz\xa5,_\x96\xf1}\x88!\xe1\xcc\xef\xfd\x8e`*\xed1\xd8J:\xb5`bH%\xeb\x19\xc1\xbck\x98\xe3\xa6@\xd5u-\xef\x1a\xe3V\x18%[\xb0\xbcj\x94EbHW\x8e\xa4\x9e;G|\x9c\x06\xe6\xb5_`\xb7\x90\xa7\x16\xf3\xb5\x88\x0e\xa0_\xbe\xaf\xee\xa0t\x1b\xe8\x18\x9bIi\xc6\xb2\xf64c\xd0\xb3i\xe0\xcb+\x14(\xd67W\xa7\x1f\x9f\xf6\xa9\xe0\xa1\x1a/\x1f\xd8\xea\xd4\xd0\xcd:\x91\xb7\xd0\xe6\xfayN\x96\xab\x1c\xf2\x04\xa6\x84\x1d\xf5E\xca\xbc\xd9\x84\xbdni`\xa0*\x03\xaa\xcdl\xf7\xa2^%:u\xbf\x1d\xc9\x0f\xf7\xb5H~4\xfc\xbf\x16\xc9K\x07\xa0^\x1c=\xdc\xd3\x82d\xf7\xa9F\x1a\x1d\xdb\x0d!u\xc1\x1e\xab\xa9M\xfaz]\xa3\xf2\xc1\x05f\xbd\xb2\x02\x0c\xe0\x0d\x99\xf7Z\x8f\xaa\xa6e\x81\xbf\xe8\x0b,\xca\x02\xe7\xfa\x027e\x81\x8f\xfa\x02\xcb\xb2\xc0\x0b}\x81yY\xe0g}\x81;8\x81)\x9cB\"\x92.\xd1\x99\xe5\xd9\x97~7e\x11\xbb\xc6h&\xa5\xb6W_\xe8\x8a\xd7\x9c\xc2\x18\x16\xf4/\xcb\xecd\xa7\xbc\x95\xdf\x1f\x9c\xaa\n\x03\x9b\x8f\x9a\x9ei)\"\xca\x1d:1\x98\x9a|\x03\xf3\xe0^)\x11\x8a\xae&\x11\xd3\xb1\x14\xf6\x1d\xaa\x7f\xe8h(\xb1\x1d\xc0)\xbe\x841\xaa\x81\\\xb8c:!\xac[k\xbf\x85\xa5O\xb14\x8caI\xcb\xd1JB{\x86&yc\x98c\x07\xb0\x9a\x13\x98\xc1i\x07c\x00\x12\x83_\xd1\xb8z\x0b?\xf9B\x96n\x11f\xb5x\x1e]\xe2\xd3\x0c\xf3#\x83\xad\xea\xd6\xba\xbe\xa3W\xe0g\x04\x06\xe3\xcerP\xb7\x8f\xd1L\xa1za\xcd\xc3\xf5k\xb6u\xf8\\\xbd\xb0\xf2\xd1c*\xd7\xc60\x92\xaf\x0ea\xb1Z\x996W\x99\xb8\xccu\x95b)f5C\xe7\xdc\xad\x94\xa3\xfa\x1a5\xdau\x90\xc4\xa1\xd5\xfebr\xd9r\xc3\xea\x02\x88\xb3d\xd47\xca\x86\xa8N\x91\x19\xae\xfe\xd7\xfc\x0d\xaa5]\xc0of.\xfb\xcc\xb6\xef\xbc\x1b\x96\x14\x1b7^u\x87\xb8\xc4a[n\xe6r\x8c\xf4\x89~sM\xff\xdb\xb8\xa6\xaf\x9e<\x01\xdf\xbev\x01\xab5\xa7(\xc9\xbc\xd7\xcci;\xf3\xfe\x02'0\xa2?\xce\xe1\x04v\xe9\x8f\x8fp\x02\x87\xf4\xc7\x0bZf\x9f\xfe\xfa\x19N`\x07K}\x86\x13\xd8\xc7b\x9f\xe8\xdb\xd1\xa1[\x93\xb70Q\xfc\xbaR09\xeeT\x85=n\xc3x\x9a\xdc\xd2!\xb1_\xde;\x0c2q\x82ZL8\x15\xef\xc7\x86\xcf3\x12a\x10e\xfaW\xfd\x14\xdf\x8dAL\x84m\x89\xd9^\x84\x99\xe5\xc8\xa6_Zq\xdb\x9c\x8b\xdb\xe6\xdf(n\xeb\xe2\xbc\\~b\x8f\xf6\xd5\xd3\x16\x03\x81\xd1S\x9eE\xcaN\xeb\x9cT\xda\xceI\xa5\xa6e\xa1e\xa0\xda=\x1aPBEx`\xb0\xb0\x96\xd9(w\xb5\xc7\x7fT\x901h\xd4\x83\xa44r\x1ak9\x9b \x89g\xe1\xbch)q\x9b\x86\xb9x[\x1f\"\x86\xa0g\x07r\xec\xd6T\xb1\xd0=wfym \xd1\xd8\xde\xdb\xd9Q\xa6\xa8\x9a\x91Z\x7f\xf4M\xeavH\x8d\xfb\xd4\x8b7\xe3>\xfd\xff\xc6\xb5\xa7\x8e\xeb\x8f_z\xe52j\x17\x15\xd6\x94%\xc3#\xc8\xb5\x860\xb9\xde\x10\xe6F\xcd\xd4\xa0\xb5NoDr\xeb\xb0\xea+\x0dUx\x8072I/\xb9\xf7\x94\x89\xe3\x01\xbd\x89\x00=\xa8\xde\xef\xef\x0d\x06\x07\xec\xfd\xfe\xde\xde\xce\x1e]I\xfc\xd7\x13`\xf2&z\xb7\xaby.*\x1c\x94\x95\x1d\xb2\xe7\xc3a\x95]J\x14\x1a\xee\x96\xa5v\x86\xb5\xcf\x87\xa3\x83\xf2\xd5p\xef\xa9\x03<\xbf\xd63\x18\x0e\x87\xbb\xc3\xe1\xd0a\x97\x04\xd3&T4\xbe\xba!\xcf\x02\x87\x9d6\xa11\x8a\xfe\x18\xc06\xc1\xb6 l\x9d`\xf9}\x07\x9e=\x83\xa1\xca\xbe\x8b\x8b\"\xbf\xbd\xfd\x9d\xd1\x80~5\x1c\x8cv\x10&FM\xaf\xce\xac\xb6I\xf5k\xd1\x9a\xeeS\xad)\xf8\x0dw6\xdd~bO\xfc\xad\xdf\xfe\xe5\x92\xfe?\xd8zz\xf9\xfb\xd0\xdd\x19>8G\xdbs\xc5\xe0\x8dR\xc5\xdb\xff\xf9/\xb6}:\xfe:\xf1\xb7f\xbc\xf0\xe1\xc3\xfd\xa4\xfc\xe98\xdb\xcaW,\xe7\xec\xeep_+\xb4n7\xc5R\xc4\xa5|\x88\x89\x1d\xf0\x14\xcc\x01\xe3\xd0w\xf6PO\x92{\x01\x1f\xf1\xf3\xdc\x1e\xe0\xb2\x88Dx.F\xabc|\xab\xaf\xcc\x946\x9f\x0c/\xeb\xb9\xaf\xe0\x140\x80\xea\x9b8\xb7\xf3\xd2D\xcf\x85\xe1>\xa5h\x1a\xaf\x86\xf4\xd5\x00\xe3\xb4\x16v\x8cD\x8f\x01\xcc+\n\xb8\xc9\x93\xe3g\xd6\xe5v\x1d8S\xe9\xcd\xbc\xfe\xaai\x02B/\xeb\x895\x06\xeb\x89\xbf\\\x1diB#[\xc7\xf86\xca\xb5/\x9f\xe1\xcb\xb9\xf6\xe5\x0f\xd6\x0f\xf4\xe5\xafE\x92\x1f5b\xd15\xa7\xed\xc6\x88S\x16\xb2\x11\xb6\xac-\xe0V\xba=\x84x\x93K\x06a\x86\x1eK\x9a\xc1\x85\xe1:\xfa\xe0\xd6dVR2Lq\x0c\xe6z#c\xb4`\x149H\xf8W\x06\xe6\xbeKum\x0coH/2\x89/y\xe4\x1bm\x19]\x0c\x91\xfa<95Z\xdb\xc5l\xc0=\xd2\xe9q\xa0[\x1368\x8e@.y\x04\xf3V \x11\xff\xb4q<\nSW~\xbe5\xcd\xa9\xeb\xdd\\\xf8xN\xd3\x9fE\xcc\"\x1d\xbek\xcfgWJ\x1e\x84b\xd4\xfa\xe5\x17\xcb\x81c\x18p\xcd\x16)\xe3,\x86.X\x7f\x1eZ\x8e\n\x99\x9f\xfc(\x9c\x9e\xc5y\x98\xdf\xbddf(>}\x81x3\x99\x92\x8fI\x88j\xea\xc2e\x9ajZ\x17\x96\x0eI/A\xb4\xd4\xb5'\x86\x9ee\xae\x9c\x18\x08\xbb\xc5\x06\xff\xd7\x1c\x03\x84w\xb6\xb1\x12I\xd80\"\x83\xa8v\xea\xc2\x8d\x0e\x19\xb51Ak\xc9\xd8\xa5\xa0\xd6U\xe0\xcbS)\xc1;\x8c\xf5\xf2\x98\xae\x1e\x19E\xeb\x0dn\x8f1K\xfb\xeai\xcbD\xeb{\x87Z\xd1\xfa\x81Z \x13\xad\x0fGj-\x8f\x93\xad\xbb\x92\xf4\xdc ^_t\x89\xd7o\xba\xc4\xeb\xcb.\xf1\xfa\xbcK\xbc~\x07'L\xb6\x8d\x923.\xe3f\n\x13!A7\x8a\xbc\xcd\xa2\xf5\xc5\xba\xf2\xf8+8\x81kI\xd8G\xbf\xb9\xae \xff~\xd7\xa5Q\xaaD\xechY)\x89\xd8\xd1+\xd3f\x82v\x14\x91\xdfA]\xd0~\x87\x82\xf6S\xb8\x831\xc4\x0eJ\xd4\xe9\xb1\x8c\xc2\xa5\x00\x8fp!&G\xc9\xb9Q\xa0X\x98\x04\x8aw\x8c\xc4\xb8c\xe2@!2\xfc\xec\xb8\x80\xb2\xc2\x0d\x9ee,\xe4\x02\xc3\x15\x06\x08\x10\x02y\xf1\xd6\xbe\xe2\"G\xa301\xf5\x02\xa6\x9eJ\xdc\xffi\xc1\xa2Y\xf5\xa5*\xb3\xb8\xeak\xa0\xaa\xc4\xf8\x06Uw\"\xdd\xa0\xdb\x96J\x00\x15\x9a}hP=\xdc\xf0\xa8\x01\xdc\xcc&\xc4\x1c\"\xda\x85W``KtM0R\xdf<\xf22*\x95\xed\x82\x85\x11\x15~\xec?\x9c\xa0\xe1\x0coH\n\xba\xec\xbb%\xf9\xe4\xa0U\xcd\x0f\x0e\x8fF\xf6\xactu?\xde.}\"\x9e\x19\x03\xfe\xaegP\xa7\xf1X\x8b\x99\xea3\xb7\x0b\xc7\x85\xd4N\xbd\x8f\xb0 \xa9\xf7\x1a~\x84\xa4=\x02\x83\xe0o,\x0b&\xe4\xd2\xa6c0\x02)gF\x03\n\x05}\x7f\x0f9w\x88\xa3_K\xd9\xe0\xeb\xc3u0 #\xc6O\xae\xb15\xddG\x15\x8e\xba\xeaU\xdc\xc3\xfa$_\x84\x95\xd1\xfa\x83,on\x9a\x19\xd0\xfab:\x0c\xa3\xb4\x1aq\xd5\xc0\x05r\xe3G\x8em\xb1\xc7U\xf5F# \xcd\xb1Y\xc9\xdc\x11\x93\xb1[\x1d\xaf\xf6\x9d\xa4\x905Q\xe3S\xdd\xe6\xfc\xfe\xa2\xc6^\x9e\xb37\"\x19E\xa3\x01\x91xb\xacMT\xb1\x08\xb3SV\x160\xf1\xf0j\xb9\xd0\x84\xe7C\x91\xd89\xf6\xb2\x15 \xceIDh/2\xcd#\xbc\xfb\xb7,i\x15\xf7\x89\xa3\xcc\xf4\xad. \x8e\xb8x\xa7}\xbb\xa0\x0cmi \\\xd7\x1e\xd25\xa8XH\xff\xfe\x80\xb1lb\x9d\xa5\x80|}H\xc3\xb1\xc6\xdeF\\\x0f\x18\xd5\xd3\xd4l\xeeB\xd8\xf7x\x85j0\xe2\xd4\xb8\xf5\xd3\xd8\xb6p\x95\xde\xa6\xfejE\xd21\x04I\x11M\xe3\x1fr\x98\x13\x16\x17\xd4r\xdc\xa6\x9fa\xb3 \xad\x17\x99@dt{\x0c\xfe\xa1\x86\xf4\xcd\x86[\"\xe3\xf2\xcdGiZ\x7f\x15\xaa\x9bO0\xae\xcd\x944\xcc\xf9\xae\xbe\xc9v\xbc\x81g!\x8d\x9fW\x0c\xdan\x17\x13f\xe6\xfe\x0f\x9d.\xeeU\x1d\x15:\xc1\xa7h\xe3\xcf\x08\x91J\xde\x8eqCE\x02l?\xe6\"\xf7\x0d\xc3\x88\x1f-R\x1c\x1d\xa8RBLy\xd1\xe4\xd1d*\xa0\xa4\x06\x18\xda\x96\"\xb2\x887M\x8e*\xa5\xfcb\xd2\xcaQ\xea\xa1\xa7\x0f\xcf$\x8f\xa6\x1f\xaco\xfa\xc4V\x16\xae\xbdL\x03[\x03\x03\xed\xba\"\x0d[s\xa9tx?\xd6\xfc\xb2\xdb\xcc\x7f\xae\x8b\xf9E\x92D2\xb3\xd9\xab}I\x90\xac\xda\xa7\x0b\xab\x1bu1\x84\xdcv[uZ\xf2+k\x80\xfa\x99-\x9f\xb23\xa6\xf1\xdc\x95\xa2\xe6\xd4\x0b\xab\xd1s4\x87\x13\xba\xb4\xa3\xeb1\xda\xe8P\xb4\x8a\xe4Qj\xc7\x8ekN\xdb_\x1e\x0d\xa2\xdaZ\x89\x1a\xe1\xfe\xd0h\xcf\x9a\x93\xdcb\x91j\xe8\x9cg\xe2\xae\xb9I\xad\xe7A@\xb2\x8c\x9e\x7f\x18\xab\xb9X\xd19#S\xd36\xb5\x90d\xe1u3\x86\x8c\x99\x87\x95\x0e)kn\xe4~Vb\x0dw\x84\xb5\xac\xc4\x1e\xd7\xa4\xbab\xbe\xa5\xc9N\xb7a\x83\xcb\x81\xce\x88,\xb6w\xf6v\xb5\x8a\x91}Uz[\xf0\xe2\xaa\xe7\x02J\x9f\xecCu\xafD\xac\xd1]u\xe4L\xf1\xaf\x96\x9ei\\\xadV\x18\xb0\xb3\x0eS\xb4L\x9b\x93\xfcc\x92Dd\xaa\xe6\x87Xh\xe4\x1a7%2)\x1f\x97'\xeb\xb2\xc1\x1d\x9cy\x98\xde\xea\x13 \x928\x08#r\x91\xfaq\xe6\xb3\xd2O\x9e\xc0\x0d0'\xff\xe1h\xc72YOP\xeem\xa2l\xdb8\xccY6\xcfq;\xe3\xc5<]\xc34\xbf+i\xdb\x8ce\x18\xc3\xbc\x18\xecX\xae}\xa5\x88\xa54\x82\xabu\x1a\xd98\xa9\x9a\x81S\xb0g(\xb5\x0d\x08%\x19\xcd\x9f9.\xdc\xdaH\xfe\x95\xdf\x9e\x18\xc3\xb0?\xa8t\xe6z\xc0 \xfc(\xba\xf6\x83/\xff\xbb \x05\xf1R\x92\x91\\\x11{<\x16\"\xf5\x9a\xe3$\x0fgw\xcf\xa3H\xad\xbd\x1a\xc8\xa5nI\xdd5\xe3\xff1\x1f\xe7j\x98\xd2\x9a\xb2\x9d6\xb8\xf2\x95\xebj\xfa\xd7\xd8\x07\xa2\x19\xcd\xba=i[\xd5R%\x1b\x83v\xdb\xa8\xeb6\xe35\xe2]-\x93\"\xce1\x15\x06lA.\xdf\xb7V{\xd5F\xdej\xe1\xa2\x88G\xeb\xab\x96\xc5\xfe\x18\x8ev-\xc4\x9c\xe2\xb9C\x7ffI\x9a\xdb\xd7\x8e\x0b\xab\xcd\xcdz%Ud\xba*\xaca\xce\xa3\x1a6\xd7\x0b\x17tR\x04:\x9b\xc4\x06\x0fQ\x1f\xe7\xe8jE\xe2i\x18\xcf_\xf2\xd9\xcb\x9a\x0c\x1c\xba\x156\x0b\x96\xb3_xQ2\xbfHVo\xc9\x0d\x89>a\x88'c\xa0\xa3\x1b\x1e\xbd\xd6\x90\x9e(\xf4\xae\x82\"MI\x9cs\xc6\x0c\xf3\x89c\x9e\x03?\xc8E\x1b?3\x16\x0b\x8f\xe4\x88\x8d\xa2\x11g\xcba\n\x03\x8be\x03,VS?',\xb8WD\x97\xd4{\x7fI\xe8\xaa\x14\x0c\\\x1e.\x89\x9dt\x19\xab\x00\x87F\xe6\xadH:K\xd2\xe5g\xac\xf7\xcd\xec=\xa1\x84\x85\x9f\xde\xd9\xa1\x8bF\x0d\xcd\x85\xcct\xa7 *n\xa5F\xcf\xe2)\x8b\x0c\xae\xe7>{D\xbe#\nf \xf1\xaf\xf4\xaf\xedO\x82K\x97\xef\xc2\xe2:\n\x03\x11\xb8\xc6V}>\xfe\xd4\xfc\x95\xd8\xb2\xdf\x19D*R\x9c\x93\\\x1a\x1b\x9f\x90\xac\x03\x8d\xf1\xad8oC\x87\xc2-4I\xfb\xe0\xc4v\xb4\x14z)\x89\x88\x9f\x11\xbb\x89\xa0\x1c\x03\xd6b_\xb6!\xa4Z\x9d\xba\x99\xee@v]\xa1\x86\xf8\xd2\xea&\xb6\xa1\x02i$\x16$\xcf\xd1\x89>M\xc6N\x88\xc2-E\\\xd0\x93\xe2\xd5R\xa1k\xd6\xf3\xa7S\x8a\x9c\xc3x~\x91\xd8w\x8a8\xef\xb6M\xcc\xc9\xa3\x0b\x95h\xf1\xfe\x1e\x16\xc6(Y\xb3\x0e\xb7:\xa1\x88\xbb\x93\x8f\x1c=\x86!b\xf0\xf6\x95HKO\xd7\xc2]9\xad\xba\xd4v\xdaN\x19{\xc3\xa8<}\xf3\xe2\xe4\xd0\x04\xb5\x03-\xfd\x08\xb9|\xd4\xd7\xd6tWG\x8d\x82\xa4\xb3\x06/`\\\xed,2V}\x81^Sn\x8cL\x19\xee\xcb\x9a\xeb\xb4\xcc\x17\xd3\xb2`\x97t,7^\xbd\xaaf\x05m\xfb\x84\xe3\xb9\xcf\x1c\xb5\x97\xe75\xd1\xdbP\xf2\x16\xc3\xec\x05m3\x8c\xe7\xbcQFFb\xa0\x81\x9c\x0b\xe8PZ\xe0]\xb1C\x03\x8b\xbfGm\x08\x17Ji^\x9c`N\xbc!\xd2\x98\xdaQ\xb5\x8ed\x16\x15\xd9\xe2\x85\x02\xd5[\x85\x19\x8a)G\xceT\xca\xcd\xe5\x88/\xf5\xf3g\x16\xb1\x88\x8b\x94L\xc3\xbe\xe5\xb4\xe2>\xbd\xb6\xb0I^\xb0\xfe\x08@\x9f\xe7\xa9\x9f\x93\xf9\xddz}9\xa0}\xd1gOQ\x00\\\x92T\x87\xf8\xc95\xdd:\xbe\xf2Es\xda\xc5GO\xe9G7\xfa\x91\xb5M\x9a\x9f\xf9\xab\x1e\xa9T\x03[\xb3\xe6\\N\x97\xf0[\x8f\xd5\xf5\xd2\x8f\x7f\xc8\xc5\xb2\x06?\xc6&@\x1cP\x10\xc6\xe0c\xe8E\xf25\x87\xdb\x05II\xc1\x87\xe2c\x08\x85\x1c\xaeI\x18\xcf\xc5\xf6\xf4\xe8\xb8\xa6%5\x80\xfds\x19n2\xb2>z\x81\xd6\x19>]C\xce\xb0\x11\xdb{C\xc7l\xb4\xc3q\xc0\x01\x9d!\xbd*\xe9\xf7\x07\x17,\xbf\xa1B\x02FytP\x06r\x13]s\xeaxU\x9c\x8c\x87G\xa84\xc5\xd3.O9\xcc~@\xc1\xf2T\x17\x1f\x07_\x8d\x86\xea\xab\xd0\x14h\xa2\xd4b\xa0\xcd_\x861!\xe4\xf7\xa5\xf6\xa4\xd3[^\xc8tUSWz=@\xd7\x8e\x95\xf5\x0b\xdd\x1d%U|\xaf$\xe5Q\xcf\xe4\xd7,\xe2i\xa9\xa0\xa9\xcc*O\xab1\x8e\x0d]]\xcf\x83\xe8\xbb*D\xc4/\xd9;\xb1\x1b\x18\xd2\xac\x9d@hW\xfa\xae\xd6)\xe3\xfd\x97\xc3JR\xe8H\x86\x00c\xd4\x03U\xddk\x9d\xc3\x7f\xc4\xfc\xad\xd1\xf7\xc7oG\xb3\xd4\x93\xb3\x97J\xc4O}S&\xfc\xd6 \xd0\x9a^Bgx\xfe=\xc6( T\x0d\x86\xe6\xaa\x84\x94\x0bTu\xf2T;\xb6\x9f:.L\xaci\x98\xad\xe8\x01\xf2\x12=\xa9-\x17\xac\xab\xdcOylVz\x1b\xfbyx\xc3\xfc+1\x96c\xf6\x8a\xcd\xf7\xc7\x94\xd0gd\xca\x9eRT\xee\xcf\xd1\x08\xee\xa5\xa94B\x1f\xca\xdd%j\xd8p\xdf\x18K\xdb\x10\x1d\xad4\xfb\xd3ft\x03\\\xd4\xa7\xd8i\x96\x01\x8e{\xe3Y\x0c\x00\xec`\xf0y \x8f=D\xc5\xecX\xfa&\x9e\xf8\x9a\xdc!\x0d\xe8\x08Y\x1d\xe6B\xf5\xd4Y\x87S\xdd\xc31l\xb08\x8e1\xb7\xde\xfb\xa9i\xbc(i\x84\xbd&\"\x80\x13\xa0\xdcU\xd8\xb0\x9aR\xf6\x1bZY\x89\xc8\x9d\x1a\xc4\x81<\xb1\xbe\xfc\x9f\x9acN\xedL\x96\\\xd5\xa7l\xc5\xfa\xf6J\x9c\xea=$L\xcdAmh&\\H \xd4\xd5\xda,\xc9t\xd5\xc4\xabw\x05}\xa1\xea\x8fl\x87\xd9\xf8a\x88\xcc:7#M\x08\xafM~r\x02h\xadf\x9e\x95\xc6\x8c\xb4r\xa7Y\x9e\xac\xa4I\xe9\x00\xda\xfa\x80P\xeaGH(\xcfZ@\xc1\xb0\xea\x0bD\xbd\xbc\xc2\xda\xa3\x13\xa6\x80\xee\xbd\xb8:\xc1\xb1\"i\x86\x99\xc4\xbb\xd7N\x98}d\x85\x19\xdaj\xb4\xd3\xd6\x8c\xfc\xadv\xbf\xd4J\xf7\x96\x9a\xd6\xa6\xa7\x07\xae\x84z\x0c\x0d\x96\xd1\x0c\xf1\x0f\xd3\x84k\xa3\xd3\xeb\x94\x15\x95\xd0\x9aebB\x146\x89//\xb5\x12\xd1j_;.dU\xe7\x98kc\xe6\xf9\xc5|I\xe2\xfce\xe4g\xbd\x1dNd\xb8\xa8\xbe'5\x1f.\x84\x8d!b\xda\x0d\x8fn\x10\x93[\xf5\x18J\x99\xec\xbf\xfc\xd0\xa9\xdda\"\x16\xf9A\x9d\x98\x06\x8c\xa6.\x8f3E&\x18\xfbR>f<\x9e\x8b\x98\xa4\x19\x908H\xa6a<\xafgD\xc8\x17$\xc6\x8d\x87\xc9\xd2\xca\xc3\x0fD\xe0\x17\x1fx\x03\x06e\xb88c\xb9\xc1@/\xd57\xffF\x18\x19\x18\xcc\x04\xf4S\x13\xb5\x88\x85\xc0\x0cCC\x8c\x9b\x1f\x84}n}\xdc<\x9b\xa6\x0f\xac\xa2\x16gp\xbd\x03\x1d\xae\xdb\x17\x0c\xdb=y\x82LO\xb9\x1e\xe4w\xcdC\xbe\x85P\xc3\xd0>\xde\xf5]N\xde\xf2l\xdd1FWA\xcf\xf3\xea1\x1cWv\xcb\xeaV\xfd!\x99\xcd2\x92\xff@\x97@R\xe4\x90\xcc\xe0:)\xe2if\x9a]\xb5MZ9l\x82\x8d\xb6\xfd\x03\xc7\xd8\x0e\xdbs\xfd\xdb\xc9\xeb\x99\xd1\x99!juO!\xd5@\nuE\x80\xae\x08n\xe0\xb1\xee1\x05\xb3\xbe'\xad\x88)oCD\xb4\x00\xcf|\xd8\xbaU4J\xe2\xda\xec\x8f\xf5\xde,\xdd\x04\xa1\xb84\x9f#@\xcb\xe8\x0e\xf7\xf7\xcc\xed\xde*\xf2\xd9a\xdb\xd4od^\x98\x9dq\xbca\xc7\x8ei\x13 \xd4bIh\x83\x1d\n\xac+%\xee\xd1\xed$\x90\xce\xd3\x01\xdc\xc3\x82M\x9c\xde\xe2\x10\xf8\xe1\x8a\xd3\x81\xc7V\xea8\xdem\x1a\xe63/HX\xa7\xdcL\x8d\xe1\x98\x11\x91\x84rZ$\xb9)\x1bUJi\x08\xfag\xf3\x04\x86t`\x18\xbax\xb4\xb7\x07O \x9f\xa4\x1a=\xd7Z#\xd4$^\x85r\xdd<;\xa1\xbc\x95\x89jy^e\x96\xf1#\x0c\xbfB\xf8\xce\x82\xc8O\xe7\x842\xa8~\x0cK\xffk\xb8,\x96\x90\xa1;\xc7\xe0+\xe5\xb3}9\xcd\xf5p\xdfAWNJ6i)\x9e\x12a\xdf\xf7\x1c\xd4\xa2u%J'\x8b\x9c;JH\xcb\xf5\xdb\xb4\x0f\x92\xd6\xdasHe\xbc0\xfb)$,\xd0H\xf31\x9d\x88\xfb{ \x06\x14/\xf7\xb4\"0\x9b\xbd\xd5\xb8\xd6W\x8c\x9e\xa5\x13r\x80\xb4\x9c\xdb\xa1\xc0\xa9\xcd\xb2'\x9a\xedU[\xbe\x1b\xc3\xa3#\xa7\x14\x0d\x1bOB\x14\x88Z~\x16\x84\xa1\xa5\x17\x8b\xb2\x12\x91\x9f\x87\xf1\xb0\xb5\xc8u\x18\xfb\xe9\x9d\xa1\x08H\x12(\xfdq\xc2*A2\xaf\xad\x95\"\x9fm\xb5\x96`\x84vg/^\xdb\xc41\x02\x1c\xaa\xe6\x82l\xd4\xde\x9f \xdb\xea(\x91\xcf\x86\xfb\x11\xe9*\xb3\xd5R\x08\xaa~\x8f\xe0\xc7v\x08.\xc8\xd7\xeeZbx\xf6\xec\x19\x18\xac\xb6\xf9t\xfa\x19\xd9\xdf\xed\xae\xea\xb7.@\n\xa32cE\xa8\xedpzO\x0cp&\xcc\xc6\x1d\x95;\xf5\xe8f.\xcf\x8f\xd6\xf8T\x95\xbe\xeb\xd1\xd7M\x1b\xc7\"\xf6\x16\xd1F\xc6\xe7riz\xfc\xb9\xe2\x10L{5\xba\x94\x98*\x83\xc6\xa1B\x01\xa4\xa4\x189\xc0\xb64\xd3h\x10\xb7\xc4\x94;L\x99\xf0\x1cOn\xe49\xe1\x99,\x91;\xc575\x11\x1d=\xdd\xb7\xca'\x87 b\xa1I\xcf\x1cV\xe1f\xecB\x98\xbd\xf7\xdf\xdb\xb1S\x16K\xf8\xe1\\\xca\xb7\xb6`\xe8\x08\x91\x80(T\xbe\xdcDZ?\xa6\x07 \xe9p\x84@\xcb\x95V8\x00\x8f\xfe$7\xdd\\\x19@\xa2\x8c`m1\xa3\xd7\xcc\xcdm\xf4k\xafk\xf9A\x8bH\x8c\xd9\xdd#\xcf>K\x93%\xe5\x15S\x07\x15\xc35\xae\xac\xc6J\xe5\x15\xfb\xb45\x841\xcc\x95\x15eX!Z\xe1\x13\xaf8\x87'H\xeb\xb8\x069\x83\xe9\xd0\xad\xc4\x17\x92\xf6\x97\xc7\xd9\xc5\x08\xa4\xa7\xadE*\xf5\x04\xe7Z\xb5\x85#?\xcb\xdf\x18>\xc0\xb1O\xf2\xcb\xb6\xd1ky\x97\x1b?* {\xc1\xae0\x08Q\xce\x843Z\xfd\xe8q\x15\xfe\x06d\x12\xb2\xf0l\x86\xd8o\x85\xb4p\xf5%2\x89\n\xd6O\xb1\x14\\\x95\x89\x14\xd8\x89\xc6\xf8\xef\xb4\x8a\xc6\x99*h\x14\xe9!~\xb8q\xa1\x15>\xe0gY\xfd\xd1\x96\xf4\xcc(/@\xb2\xb6\xa2\xd8GL\x18X\xddw\xee+\x9fEO-`\x9bEQ\xe5\x7fc\xfc\xab\xd9o\x8dG\x8a`\xd6\xd4Q\xde\x8dai\x92FX\x00{\xe2\xa5\xc4\x9f~~\x13\xe7\xc3\xfd\x17gv\x0e?\xea\xdc\x18\xf5\xfb\xdc\xa8E\x16\xce\x8e\xa6A#M\x87j\x98#\x08\xe1\x18\x8a#\x0877\xf5L\x19\xf0\xc6px\xa1\x83\xfdG\xad4OQ\x1cp<\x1c\xc2\x16\x04\xadr\x1dQS\xf9!]9\xb4\x9b\xa1\xe3\xb2\xcfa\x93\x03(+\xe7-\xa0\x001V\xc9\x91\xec\x16K\"\xc1j\x0ca\xeb\x84\xf7\xc6\xe5P0 g3lb\xd8\x84\x0c\x9eAQ\x9e$\x05lA\xe60\x7f`\x84\xda3d\xe6\xc2\xad\xad\xb6!\x97\xc4\xf3\x8c\x07\x0b\\1\x1ep\x05\xc7\x90\x1d\xc1\xaa\x0d\xe8P\x03[{>\x1cCz\x04\x9b\x9b~\x1b\xfa\xa0\xc7\x84\x9c\xf7\xa2\xb8\xce\xf2\xd4\xa6|\x82\xef\x02O\x8d\xa1_X8H\xa4\xd6\x8a\x8a\xa0\xf0\xf5e\xc9\x84\xee4f\xba\xdb\x03\xe9\x89\xcaz-\x9a\xeb\x8eE\xc3+{a\xbf\xa6\x1bJ^\x16\x0e\xaa\xe4\x9a&@\xa6\x96\xae\xfa\xb6d6\x18(\xeb\x94smM.]Y\x14V\xb2\xf2L\"\x963\x87K&8\"r\x02\x94\xb8C\xa2\xafK\xa8\x98\xaf;\xe8\xdb~\x83\xae\xc1\xa6W\xc5g\xfd*~a\xff\xb6~\xa7\xbf\xf6\xad\xbb\x97V\xa3\x92W\x96\xde\xb6|\xd6\xa4\xadF\xa4\xa0\x15\x1b\xb6\x9d\xd3\xd3i\x84i!\x1c\xbe \x19+!\xcd\x9f\xcf\xf9M\xcaO\xc3!\x8f\xdaL\xd1\xc6\xde\xbe\x0b!\x9b\xf6\xc4)\x7f\x9a4yF\x94\xfc\xf0\xad\x0b\xfe\xbc\x8d\x9f\xad\xb3\x10t\xd8q\x8d\xc5\x84SH\x91\x07yq\x97\x13\x91\xf1\x9dbU\xf5!WQ\xe5u\x9b\xae\xb6~\xbdl\xeb\x17\x05\xf3;?_x\xcb0.i\xc6\x1e\"[:\x9f\xe8\x1aq\x04 \x8an\xdb\xd0&\xa5\xbd]\xb4\xafu1F\x07\x99$-\xc9\xe5\x03\x11,\xc1X\x82\x9e\xe0\x11e\xa5w\x9e\xc2)\xec\xc2\x98\xdd\x8dv\xe0\x14v\xf8\xdd\xf0\xe9\x10Na\x04c\x93\xe8\x05iE\xd8\x84\x19\x1c\xa3\xb0O\xc8\xeffm4D\x9f\x04\xb8\x11\x1c\xc3ptX\x12rQ\x8b^ \x04\x9da.\xd2'-.m\x8er\x19\xc3\xa7#x\xc2\x88X2\xa1\x83\x1b^:L8@\xd9\x17{g\x08O r\xe0\xf8\x18\xf6\xe1\x1e\xf6w\xe0 %^\x9f\x89\x0cb\xd8\xdd\xec;t\xd7`\xf6).\xb9\x7f<3>\xde\x8d.]e(!\xf6\xbe\xfe\xcc\x97F4\xdc+G4\x1c\xc1=\xd8bL\xf2\x10}:\xc4\xd1`\xf7\x80\x7fw\xcc\x13\x96\xdd\xdf#9+%x\xfb^\xe3\xdf}\xfc\xf8\x8b\xf2ng\x0dh\xd4\x9f\x15\x06\x08\x1d*\x10\x92@\xe6\xd7AV8\"\xef\x1b\xad\x89\x82\x8c\xa5\x92\x1bI`\xd2\x0eQO\x12\x97\xc6X\x94/\xc2\xcfi\xdd;.\xee\xe4!\xc5s\x81\xdc\x9e\x1d\x94i\xe4\\H\x19>\x0f\x98\x18u\x00O\x00\xf3\xc5\xdd\xb3I\xe4\xdc\x0c\xcb%w\x0f<\x95\x1cer\xc4w\x18\x1bg\xf3\x04fM\x8co\xc2\xd2\xdd\x14\xc9M\x19\xa7\xa9M|\x8a\x8aq\x8a^\xbe\x94$\x9f&\x1d\x1d\xb71>\xe7b\x10\x9d\xde\x02$\xdd\x85\xa5\xc9V&\xaeT\xaf\x0c\x04(\xc3\xa2\xa4\xa8=\xa4\xc7\xeb\xe6I\x9f\xce\xf0\xe3&u\x99j\xeeK\x07\x11\x157\x81l7\x8eO\xf9.\xf7\xb8b\xe9\x84\x1e\x0e\xb9w\x1e%\xb7\xe5\x93\xf6y\xd8$U\x84N\x82\x12V\x0dC\xc0\xba\x95y\xa8\xba\xb37\x1b\x1e8\x90{o\xde\x9f\x7f<{yq\xf5\xee\xf9\xffw\xf5\xe2o\x17g\xe7t=\x0dL\xb2\xb8\x139\x89\x0e1\x98\x05\xe9\x9fwy\xf6\x18\x83\xdf\x0b\xdf\x1a\xc5di\xd8a\xa2R\xb3J2\x9fie)\xbd\x00\xb0\xe5\x18N\x92\x1e\x01\x13\xc4\xc5{\xb5\xdb\x94\x1f\x89K\x8f;\x1e\\\xd8\x1dqZi\x96$\xb6c\x14\x87\x12\xca\x901K\xd3'O\x84'x\xf9\xcc\x1eb\xc2\xbcJ\xa9\xd8\\\xaa\x9d\xd9\x0d\xf8\x1864\xb2\x93\xfa\xbab\xf1u\xbe\xbc\xf3\xbf\x96\x91\xa3|\x1b\x05\xcb\xab$\x89\xce\xc3\xdf\xe8t\x1e\x0e\x9fb\xf2\xa1+\xeea\xd3\xb9\xe2\xb5\x13[sJT=\xbf\xb8`\xbb\x87\x1f\x8cT\x7fd\xf3\xf0EZ\x0b\xcc\x16!\xb5\xec Y\xeb\xa3v]\xd1\x91k\xcb\xb8\x06\xfb\xc9st\xf5\xa7\x0d\xb1_\x18\x1cJ+!\x13\xdetY\xa9Xa_hmM\x98\xe1K\xdd\xd5\xad\xcd\xccAV\xec16\x08\x02ZGc\xdf\xd43\xd0\xc9\xb5\xd5\\j\xb5\xd0B\x0c\x933\x0c\xd2\"\xd5\xa5\xbc\x07\x99\xc4\x97FvK\xc8\xa5j\xc7\x83\xad\xcb\xb3\x0f\xdcV\xdc\x84\xee\xcc\xbd0\x13\xe7>7F1\xb3\x812\n\xf7\xff\xa0\xf9\xa3\x97\xcf\x8c\xb9Q\x13\xce\x19_\xe1 \xdf\xb1\x16\xa1Z\xb7is\x91J\xce\x1e'\xb0p\xa1F\xe9I\xc7\xe7\xc6\xa0\xfe.\xbb\xf5W\xc3\xfd\xb6x\x9d\xa0\x06\x0fh\xd3\x13\x11\xad\x9eH6\xd7\xe4=\xc9(\x89]\x99\x0e/\x8b(\x0fW\x11\xa1\x10\x1c\xeeo]\x87\xb9\xf6X\xac)\x1a\x06Gh\xbeK\x8e\xd8\xf2\x1b9p#\xe2\x9f\xba\x98\xb4R\xc7\x7f e\x82\x1cB\x04\x04\x10\xeb`\xd9\x19}W\xb0\xec~#XvF\x8f\x02\xcbn\x03,;\x8e[=\xa2`b\x7ftZ\xb85\xa0\xb5\xbf\xfb]\xa1u\xf8\x8d\xd0\xda\xdf}\x14\xb4\x0e\x1b\xd0:\xd0Ck_y\x9d\xe8\xda\xf9\x83F0\xcc\xe6LX}a\xfc\x16x&\x8f\xa7\xf2(\xb1\xfa\xd5\x8b~S\xb1Z\x890\x90\x90\x1f\xa2\x19\x1e.\xba>M\xa0\xd9(\x96>>\xa1\xbd\xe5w\x9d\x1f\xe3\xeac \xa4\x89\xe4\xcc%\x19(\x1b\xa5\x1b\xd0\x83\xee\x14\x17\xef\xc5\xc7j1\x9b\x9c\xac\xa0\x0f\xb5\n\xbd(Vq\xf1\xc6_\xae\xd3x\x1b\x9d+.^\xef\xf3u\xeam\xa5\x8e\xa1\x1f\x85,.\xde\xfe\x87u\xda\xef\xb4\x1d\x86\xaa\xe2\xf3u*n\xa1\xc6\xa1\x17E\x0e=\xa9rX\x872\x87j4\x17\xfdF\xd3I\xac\x03\x94v\xd1Z\xc6\xfa3\x8b\x0eUz+\x8e\xb51\x14\xd4\x8b0w\xc4M\xb0\xac\xbef\xd3\xa0\xa5\xc9\x1eD\x0c\x12\x1c\xac)\x0cI\x1d\xa9\x93_\x0b?j\x8f\x1f\x01ZiC\x87lA:\x0c\x85\x8df\xeb\xc1\xc3\xcf\x80\xfb{\x8e,KY\x88\xde/\\\x19E\x18g+L+\xd6\xefd2)F\x98\xffRC\xca\xdf\xdaqq>=\xe3f\xd3%]Q\xba\xf3 \x8e\xe4\xfe\x92\xde\xd2\xcf\x83\x85\xbd\xed\xfd>z\xd8\x9e;\xde\xdf\x930\xb6-\xb0Dx\xb0\xb22\x9e\xec\x89\xa5P\xf7<\x0f,\xc7q\xc1:\xe6\xf4\x06\xae+]6\xf4:\\\x0c\xf2\xa4N\xa3\xf6\xef?\xd5*\x8fW;YU\xcfmf{\x8e\xda\x11\x0e\x90\xb1Z.-\xed\xb6\x94\x17\xcc\xd6,i\x9c\xa8\xb9\xf0u\xa7'pY\xef\xfd=\np\x06,\xd5\x9cr4\xeb)>\xee\x8f\x9e\xd2G\x80\xf6\xd1\xa6\xf1\xa6\xf0\x8c\xf7'\xa7\xbfZ\xdd\x84\xaa\xf2\x9d.\x04Je\xe6RH\x07\xb8\x10\x97\xbf\xd2\xf2WR\xfe\xaa6_/\xf1^\x88\xae\x03[t\xf5`\x0e,\xd8\xa2\xcb\xa9\x90%z\xa1\x0b\xbe\xc3\xcc7\x10\x9c\xa5^0\xe1*\xd8\x9ae\n\xd3\xec\x0e\x8e`\xc6\x0ci77gf `4\x991 `0\x99\xb5J\x00i7ia\xd6KZ\xda\x8c\x83\x1f!\x01\x0c\xe1\x18\x8d\x90Q\x02\xe8\xc31\x84f \xa0\x8c\xa5\x82\xa8\x98\x92>\xb1\xc6\xa4\xb6\xb8q.\x82\x92\x9b\xe3\xdbf z\xd3\xba\x7f\xad\xc6\x96\xf5\x90\x1a\x98:\xaf\xad\x11\xc9\xe4\xff[\x1b\x1a\xb66\x84\x1e\xfaz\x0cf=\xbdp\xdf\xd4E\x10\x86\x1cm}\xa5\x10?X\xac\x0f\xda0@\\X\"\xe2\x87\x984\xd99\xba\xa8\xf1\xe5\x1f\x1a\x03\x03\xa9\x91\xfe\xd4\xd8t\xa6\xeacz&IB\x07s\x1c\xcc)\xf9\n\xb2x\xa1'D\xff\xde\xc1\x0c\xe5\xa5O\x7f\xce\xed\xa9\xf7p\xc2\xf5z\xc9\xda\xeeU\xadud\xaf\x17\x17Fu\xc3\x1d\xee\x8e\x96\\\x02\xea!\x9e`P\x9e\xe3c8\x84\x1f)\xfd{\n \x8ca\x08[\x908\x0e\xdahk^\xf4\x1a\xf0\xfb\xb5\x06\xbc;z\xba\xfbt\xff`\xf4\xf4;\x8dz\xd7<\xea\xbc9\xac\x1d\x1c\x16\x03F\xaf\xc1}\xea\xbd?\xbeea\x99\x96j\x0b>y\xf4\xfa|U\x1bQ[J\xc6\x90\xeeB\x04\xc0\xc0e\xa0v!\xe1<\xae\\\xc7h\x87\xbd\xa3\x10\xd8\xed\xd5\x87\xb7\x8f\xee\xc3\xa1\xa1\x0f{#\xf6\x8e\xf6\xe1P\xe9\x83|\x97\xa9t]\x1f\xfb\x1d\xe1\x15\xd7OI}\x02\xff\xfd\xdf\xc4U\x83`\xe6p\x8a\xa9Z\xfe\xfb\xbfs\x97\x9d\x14,\x0c\xe5&=\xb5\xcb\x1dBD\xc4\x11B\x0f\xf6\xf2Q\xeaT!\xc9\xec\\\xf9&\x17\xdf\xe4\xe57\xb9\xf4\x0d)\x9f\x10\xc7`\x03\xecT:\xcf\xd2\xea\x1aaa\x0c\x90\xb9\x96\xfc\xa4\xa4\xc0`K\x8d\xcb/\xae\xb8\x0c\xf3\x9b\x08q\x86\x81\xbb\xa81\xe7\x9cNH8\x19\x13S\"\x80\x0d\x04)\x00\xd2\x95\n\x07\xaa\x85V\xf7\x80P\xd8\x0f\x11\xd5\xe0\xedYO\xb9\x1a\xe1\x92\x19!\xb8A\xaaM\x90\x13\xb2|\xa3\x05\xf7\x89\xe56!\xdcgoX\x12G\x9b\x9bt\xd89\x17\xae\xffxB\xe9\x1e\xe7\x88\x13\xb5\xec\x1b\xd8\x84\xf0\x12~\xd4\xb9v\xebIY\xfd\x88_\xfccF\x0c\x9b\xb0\xb5\x95\x8bq\x1f\xe1\xd2\x1et\x0c\x97~\xf0\xed\x03>\xec\x83\x10\x84\xc6\xa9\x1c\xe3\xd0U\x15\x1cl\xe2\xfa\xb48\xdco.\xab^\x8d\x8e\x0c\x8drK\x0f\x04\xca\xf0\x12\xcf\xfc~\xfdhN\xf6\xb7\xf5\x03\xa9\x8dZg\xfa\xf4cg\xf4Hx\xec\xaa\xfd\xb0\xcd\x00\x91\x1f\x8d\xf0\x11\x8b\xf37\xdc?88\x18\x0d)\x17Q\xbe\xdf\xe9\xd9\xedG\x82\xaf\xd1\xedF\x1f(gc+#\x18\xee7\x87P\x1b\xd5\xcee\xab\x08\x9fv\xfb\xff:\x8c\x06\xcfN\xf8\xe7\xc3\xd1\xa1\xc3E\xe1[\x9cv\\%\xb76\xa5\x12(X\x1d\xc7\xedF\x07\xff\x10\xf4W\x03\x8c\x84\xdb\xd2\xcb#$/\x9bX0T\xb0`\xda\x0e\xa4P\x03\xa4\xd0\x08\xa4\xb0\x07\x90\xbe\x13\xcaD\xdf\xebr\xc5\xa3:\xefG\xc0\x88\x10[\xd2>@\xaf\xd3\x9e\xd8u\x0d\xe4j\xc4fM8\xde\x88\xd8\xaaF\xe4b\x84\xfd\xce\xe8`\x9f\x0e2\x86S\xc6\x08\x0d\x86\x07\xfb\x03\xb8\x87\x18\xc6\xdd\x14\xc8\x1a8\xfa\xd1\xc3a\x83\xb8\xaf\xa1\xf0?n8\xdf\x0f\xd5\xaf\x87\xe9\xebx\x92>\x1b\xed\xf6\xean?\xe8\xf7\xef.\xb6\xdc\xect\x0f\xe4\xde\xd5\xdd\xd7Q\xe2k\xb0\xfb\xe3\xba\x9b`\x95\x95\xa2ac \xb8\xbe^\xdd\xf8^Pktc\xd8\xb7\x1b\xaf\x92\xe2:\"\x8f\x04\xc7ag?\x06\x82\x01\xed\xd7\x8fG\xc2\xa3\xbb\x1f\xc3>\xfd@\xe6\xd9\xc8\xcd\x18\x848\xc8\x86n\x92\xda\x01\xc7\xacXPm\xfbF5 P\x0f\x93\xd8\x81-\x8a\xf2M\x8e(\x899\xc6_\xd8\xe2\xf4\x81\x1b\"\xafBN\x13AI\xc4\x8dc\x92\x15eD\xc4 \x10\xd8\x86\x84\xc9\x81\x8c\xe8\x8d\x16n\xc5b%$\xb5d\xc2?\x10\x921\x161BSc\xa4$AS\x88\xcfJ\x88nm%\x18 \x8e\x93\n\x1a\x90&\x02\xa4\xe1w\x03i\x83\xa8h\xb7`\xd1\x00U\x85%E\x16{{.\xeaQ\x8c\xf9~pv\x10\xe4\xb3(IP\xd2\xcd\xb1\xb5\xbc\xca\xb8\xc9\x7f\xaf\x81\xe8(\x90o\x1e\xcb\xc8e\x92\xe3\xb6\xd1\x9cj\xb6\x87[\xcd\xd9\x90\xcd\x19\x8aH)M\xf5\xf7Z\x03,G*=|z\x0e\xb27\xa5\xfc\x07\x0e\x92\x8fF\x1d$\x1f\xbbf\x90\xc3\xb5\x06\xa9\xa3V\xbey\x90\xbb\xae$\x12\xef5RF\xb3\x88\xd1\x8ev\xa5\xe1\x8e\xaa\xe7\xc3}\xc3\\k\x963\x85\xcc{\xfd\xf4\xb7\x92E\x12d\xfe\x80\xe9_\x1f2\x06\xa8\x0c\x0dP\x19\xe9\xd7\xccN;d\x86\xbd!\xb3\xe6\x11+\xa4\xc72X6\x8c\x06G\x02\xd57\x8e\x07\x0c\x1d\xad\x97\x9d6\xce\x96\x84\x1d%[\x1a7o\xbd=\x18\x9e\xc5\xfa\x83\xa5#J\xef#Op_:n\x88\x10y3\x89z\xc1~\nsLv\xb6\xd3\x01]\xe2\x97\x05\x86(r\x95s\xdf\xa6\xa7\x94\x0f\xcf\x9e\xc1\x80\x9e\xa3\xc5w9\xaf\xd6\xa4\x00\xfeO\x99\xe8\x16*\xe2\x9b&[\xcc\x85D`\x84\x15\x81\xb1\xf6\x8co\xfecf\xfc\x0f!P\x86\xa3\x03\x17\xb6\x86\xa3\xc3\xb5i\x14R\xd3!Q\xd02\x9f\x84\xe1\xb7\xd0/\x7f \xf9\xb23:\xd8\xa7cE\x19B?\xd4\xfe\x07\xd20\x7f \xf3\x88\x81\xfe\x81t\xcc\x1fH\xc6T\xf9\x10\\%\xedA\x8f!\xb7\xcfm\x0f\x12\xa7F\x12}\x13A\xf3\x07\xd23f\x10\xd5\xb7o\xcdHB\xec\xe2\x1eP\xfc'\"~\x0c\xf2\xa7v(\xbeR\xe6\xac\xcb\xab\xa2ji\xdd\xf9RZ\x1a\xf6j\xc9$Ejo\xea\xedc\x06e\x12\x14\xad\xd5T\xe7\xa8\x82du\xb7\x1e\xddR\xa5\x9b\x1c\xa0Cd\xe9\"X\xd9\xd5\xe7\x8a\xa7\x97\x94\xa5\xa42E\x90\x0b\xd0\x0f\xf3\xb2F\xae\xe2HK\x12\x10\x9d\x17\x98\xf7eWz\xa7\xb0\x11 \xa5\xea\xa0\xdc\xad\x8e*\xf26\xc3\x9b\xdcO\xe7$?\xcf\xfd4\xef\xce\x86Z\x9a\xf1\x003\xd6T\xba\xa1o!K\x8a4 k\xb4\x90\xb6\xf5\x97\xd5v\x16O\xbb\xebJ\xeb\xce\x17%\xf4\xeb3*\xd9_\xe5\x18{iK\x9a\xa8\xda\xcbM\xadU.\x12\xb4L\xbf\x95\xea\xe3\xd6\xe3\x1cTn\xa8\x18t\x99+\x07\xb1\xc5\x96\x904 \xb0t \xc3#HxV\x83\xad-4\x0bK`\x13\x10I\"\xae\xa3w\xba\xb8/\xa5\x93\x11eA\x86d\x07X\x18\xaf\xf5\xb2\xfe\xb105\x8aY\xda\x1a\xedk\xf3\xb9d$\xaf\xf2\xb8\xd4Lubf\xf6\x14:\xfa\\\x98B\xef\xd7\x86\x08fa\x14\xad\x87\x084NWkg\xb6\x16\xe9 0\xa4\x06?6\x95\x1d\xa2M\x9f+\xe1\x85\xe6'.\xcf\xba\xd1\x95\x19 $\xde\xaa\x16\xb0\xdcdy\x04\x18\x80\xe8\x18m\x8c\xc5Am\x88\x8ff\xce\xb7\xaa&\x9b\xd1\xe4\xc33\xf9\xb3\x97\x19\xbf\xfb&\xf36\x80\x1d\xdb\xad\xe7\x02NM^\xc5&\xcf\x8fF{\x95\x12`:-\xc9\x9b)\xcb-\xe2T\xe9\x17a9\x00n\xab\x87>\xca\xb5A\x08\xbc\xe8OB\xf8_P\xaca\xb3\x977b\xe4\xd4\xfb@\x07\xfb\x19N`{\xf2\x9f\x9b\xbfl\x0f\xb6\x9e>\xdf\xfa\x0f\x7f\xeb\xb7\xad\xab\xcb\xed\xb9\xc9\xf5\xe6\xd7\xf6\x10\xae\x80\xca\xd9S\xb0\x06\xe8\xf4_O\x13:V\x1e\xd4\xfbfh\xf0\xb5Q\x01x\xa3\x0f\xd0\x96\x03\x8f\x8a3\x84\xed\xce\x1c\x97\x95\x83L\"\xc2\xf3\xeb\xf2:\xb4\xa7P Y`\x9bFb\x07\x07\x9ea4\xef=qD\xef\x1d\xec\xec\xee\xb6!\xdc\x90\xe7\x873\x97\x80r\x93>\x83\xbd\xfd\x9d\xe1\xd3\xae\xc2\xf4b\x89(vh\x7f\xb6\x86\xb43<\x99\xc4h\xe7\xa9\x0b\xc3\xa7C\x17\x86\x87O[\xd0\xba\xb8\x82$\xce\xc3\xb8\xd0\xe7R\x12\x979{\x10\xf0\xbe\xfb R?\x19\xa5z\xf2\xf5O\xd4{\\$\xed-u\xb6\xd2\x9e] \x97\xc9\xfe\xce\xc8\x98BP\\\xfd\xa0\xe2\xfe\xc1]\x8e\xb9\x8f\xc6>lR\xban\x8b\xa7 8>\x86!3t\xd9\xe2\xa3\xd1\xd6\xc0O\xc5\x84\xf3==\xc6c>\xc9\xab\xfd\x1b\xb3D\x15]\xfb\x8c58d\xd9Y\xba\xd2\x1f\xf0\xce\xc4\xad\xe3\x10\xf37\x1a\xec\xf6l}\xb4^\xeb\xf0\xec\x19\xe62\xc0\x00\xdb\x98\xd0 \xa6w\xa3\xc3^\xdd\xc2y\xea\xd7\xaf\x9d\xf5\xfb\x85I\x17F\xa3]\x16\xc2\x03\xf6\xe1 \xed!\xf6n\x8d\xbev\xa0F\x1c\x07O\xd9\xa0\x8b3 \xd2i\x05\xc9\x94\xc0*1x\x91\xc9U\xb2\xf1\xee>b\xbc\x87t\xbc\xbb\xe4\xeb*I\xf3\x0cN\xe0\xf7\x07\x89v,\xc1\x106<\xd2\x1b\x9b7#\xf9E\xb8$I\x91\xc3\xc2g~\xa0\xd7\x84\xc4 B\xe6W\xf0~\xd04\xe0w7\x10D\xc4O\xbf\xa1\x89\xa2\xb9\xe0\x19n\xc5\x18`e\xef\xab\xe8\xc2\xe5#\n>\x95o\x16T\xe3\xc9 \xf3\xe2\xda`\xf9\x8e5\xf5\xd0C\xb6z\xecv\xd4\xab\xcf\xb7!\xaab_\xd4\x97\x81\xc8\x0f\xa17\x955\xa6\xef\x10U\xb2\xa5SF\xcb\xd79\xfc\xb7\xb6\xd0\xac\xab\x94\xd2v\x07\x0f\xa8&l\xa3Z\xac\x8d\x95\xa0\x1d\x03f\x9d\x11\xdf\xc8\xbc\xa6\xb4\x10O\xe5\x9b\xb1\x8av[\x13k\xd0\xeaU4-\xdf\x19\xe6\xc9\xd4\xa9\xda\xe2=\xad\xdf\x8e\xd5,\x89\xad\x1d\xa3M\xa8Y\x15\xcb_\xb6\xb4\x9a\xe8\x1e\xe7\xa9\xcd&Jb\xb3\x00C\xbf\xd4\x9f\xcdx\x12\xda\xe6\xc6Y5f\x04\xb3\xb7b\x1a\x0b\x9bW\x05\xa5X\xe0\x14[\x14\x01\xc4\xed\x08\xc3\xa7b\xdd.D\x92\xecuj;\xed\xfbu\xdah\x16\x89\x88\xc0\xc4L\xd2\xb3\xad\xb0W\x1a\x8a\x01\xfb\xd8\xc6KR\xa6S\xf4\xed\x083\x11\xe9\xd79~@\xb1d$\xe0\x8aA\xc4x\xf6\"\x9e\xf2cv\xe9\xa5El\x9b<\xfc8(\xe4&;v \xf0D\xcfl\x8f\xea\xe6N\\\xfd\x8ev&T\xa7\x98K^\x86U\x1a_\xe9\xa1\xdd\x16P\x12Q \xab\xc8G\x14\xc8b5h+\xa5\xabV~\xe1\xf6o\xc6\x8c\xc2\xc4\x95\xda\x06\xf9\x12\xf4\xc2^\xe2\xean\x08d\xf2K\xc6\x9b\xe6\xe6a\xad.@\xa3\x01\x8eL;\x1a0\x8f^\xfb\xe6A\x05\xd8C\xebN\\h\x858(\x0b\x9c\x15(9\xe1B{\x96\xe6\xe8D\xcaZ\xaa\xab\xee\x86n\xec\xaa\xc5\xc4\x8b\xc9\xd7\xfc\"\x0c\xbe\xb4\x12\xa7b\x9fR\x8a\x80\xd1\xbc\x8d\xb8\xcdM\x93!\x94W\xa8\xc5\x9e\xc1\xb0 \xce\x12\x17\xc4\xcc'\x93\xb2*\xea\x97G\x10onRr-f\x86XR\xe8\xe8F\x98\xfd\x883\x1b\xe4V\x80\x0fe\xf7\x98\x15Z\xa2\x07\x03\xfa_aO%T\xe8\xc2B\xb6\xabG\x00\x9b\xcfF> <\x1c+[\x8e\xd5\\\xd4\xaaM\xbc<\xcc#\x0cJz\x9d&\xb7\x19I-\xfa\x90\xff\xe6a\xf2\x13\x8f\xc47H\x07\xd2\xdf~:\xbf\x11y5\xbd\x1b\x92ft\xfeX$\x93\xf2>+K\xe3\xbb\x1b\xfcn:}\x1bf9\x89\xb1\xde\x1b\xf6\x12\xdd\xd1\xd9\xef\xd9L\xfcL\xc92\xb9!ja\xf6\xf4y\x14\x89\x17\x99xC\x96a.~\xafR\xb2\"q\xa3%\xfe\xf8C\x1c4\xea\x8d\xa4\xea\xccK\x8d\xef\xc0\xc9e\x1dz\xd7a\xdc\x99\\\xa5A\xb5\xae\xd2$ YV~\xccC\xa4HA\xf1\xea\x8d\x04\xb7\xd3\xb6\xf9\x16\xac\xd2\xb6\xa5|\xb6\x98\x86\xe9\xe3z\xc6>\xed\xeaW\xb1\xf4\xb3/=z6\x90\xb6>h\xb8\x10E\xc5o\x15\x19AEO\x90KL\x9c\xcc\x90\x98G\x84\x1a\xa0\x8a\xd8\xda\x90Uu:}\x0f\x06\xb1\x15\x03\xf5\xcb\x8aU\x19C\x83k|\xc4@\x9aH/\xd5\xe2\xd0\xca\xbe\xe6\xa4\x0bk&f\x94\xd8\xc0p\xc7'0\xa4\x88E\xd2\xdeT\x98jx\xc9\x835\xc8\x8f\x9a\xf4DlLx+duZ\xb0\x19\xd7\x07\xa8\xc2{\xb5\xd7Lt\xcfP{\xea\xa8\x02|\x9fb\xdep\xe2\xd7\xb1\xaeof\x961\x17\xd6\x86\x88\xa2\x19\x0b\xd0 \xc3&\x91\xa1\xa1GnHzW\xcb\"\xdd\x95\xda\x0c\x19\xb7x\x92^j\xf8\x1bts\xb1\x19W\xcdp2\x9b\x04\x17B\xc7a:\xb5\xd05s\xf2Z\xde\xbb1\xf15\xc2\xb5 \xc7\xb8\x84cN\x0f;8\xc5\xe0\x14C\x1e\xd98e\x07\x1c\xcb\xb9 )\x85k3\xa9\x9d\xe4-\xa0\x16\x97\x00]\xfb\xa6\xef\x03}6\xc4Y\x9a,[Yv;4\xcc\xc3\x83\xf1\xb8\x8f\xbc\x94dE\x94\xbf.\xe2\x80\xae%\x17\x9f\x04\xc9rU\xe4~\xce\xd9\x94\xce\xcd&6Z\xe3\xe5\x03\xab/#\xf9\xa7GWJgH[q\xed\xa1L\x0c\x88_\xb9wuE\xb2w\xc9\xb4@\xf6\x8d\xf2i\x98:\xd6/\xa2\xfc\x1dY&,soB\x9f\"\xda$\x02\x8b\xbedH\x94\x11\x1d\xe5\xcb<-\x82\xbcH\xc9\xb4D\xb6}\x18\xefGP\x99\xbeBe6\x99s+\xc1<\xb8F\xea]\xc8\xfeM\x1dg\x87C\x06\xb30\xcd\xf2*^\";\x18\xfc\x18X\xf5p\xbb )\x01\xe2\x07\x0bX\xf1\\\xbb\x94\x11\xf0A\x9c%\x9a\xa3\xc3Gk\xb0\xb2SG\x0d\xa0\xd0\xbd\xc6\xd3\xf8~!wYC\x88UR\x8bq\x1dU\xb5\xf9\xc3\xd3\x0dY_\x0e\x8e\xdb\x93\xe4\"Z\x84\x9cW\x08\x81\xd3~\x03F\xfb\x11N\xfb\xe5\x93\xb4\x9d\xee\x03i(^J\xa6E@l\x85\x13\xea\"\x98\xc9\x84R\xcb\x97\xcc\x18R\xa3\x8es\xe1\xf7\x07E %\xb1\x9fu\x91\xb6\x8f\x04L}\x99\xd3\xf5m'z\xb5\x97\xc2\xa7 \xee#\xb6\x87\xc3\x03\xe5@D\xc6\xc6\x1e\xed\xee8zV4\xb6\x87\x83\x01\xa5\xfc\xda\x1a\x00Y\x84'\xd2'$6Z\xabK\x83\xea\x91TLZ\x12\xcc\x18tM\x96\xb4\x1a\xea\xc1\xaeaD\xed\xcc\xf5\x86\x1c\x0b\xd5\xc4G\x8b=\xb6\xf1H>Z\xedq\xac*$\xeb\xfb\x8e\xc9\x9c\xc6`\x8d\xbc=o\xcf\xd2\xad\x12\x8d\xfd\xe1\xd5\x153\xd4\xa4\x7fO\x84\xdb@o\xf0\x8d\x0e\x0e\xd6\x86\x9f\xcc\x85\xca)\xe7j\xb2\xeau\xa7Q\xbf`\xf7\x0ev\x95\xe7!\x7f\xbe\xa7<\xa7{\xc7\x9ap\x9c\xf8\xbe\x88\xa2K%Tx!\x17\xf8,\xd2\x9d\xab\xa524n?E\x13\x04f\x0fx\xe1\xcf\xcb\xcc\xde\xdf\x01R\xd2\x89Bo\x0b\xcc|2\xe6\n\x16\x08c\x8ev\x99q'\nF\xc6\xc8&?\x16\xb0{OGz\xc8>\xdd\xeb\x9cx\x0d\xbd,\x96q\xc2\xdej\xb7E\xca\xb2\\\xc4%\xd8\x1e\xdb\xf7\xd1Su\x96Y\xdf\xf7w\xd41\xb1Uqp\xd89$\xc3\x0c\x85\x0c\xde)\x83w\xb26\xbc\xf5\xb2> !\xef\x0e4#\x91NXJl\xb4\x93\xd4\x82V\x99h\xce0\x89s c\xa42\x84U\x98\xf9\xbc\xab\xbdx0\xc0\xad>\x96\x90\x1f\x14\xfbR\xb5\xa1\x17\xc6\x0b\x92\x86\xfc\x149\x1c:\xcd3-\xb6w\x06\xeaL\x16\xac\xae\xda*\xac\xea\xb2g.\xf8\xd2\x9br\x80\x19\xae\xbd\xa2\xd2\"\xf0\x14I\x83#\x88\xe0\x18*uFD \x80\xe6\xda\xa5\x04t6\x89\x14\x18\xce\xaa\xfa&\xc1%\x8a\xb9\x94G\x94)\x93\x1f\xb4\xebwg\x86C\x879\xc7\x88@\xda\xc9\x0cfU~IJ\x12\xce\x1a\x84\x96_W\x95\xb9P\xa8\x0f\x10\xfbo\x08\xd7\x89\x94\xf8S\xff:\xe2\xb1c\x17aV=9a^\x80\xf5\xf2\xb7i\x98\xd7\xcb\x97Oxy\xa6q\x89\xa2\xe4\xf6\xaf~4\xfb\xb0\"1'\xd3\xeb\x15\xd5K\x94\xb55>,\xabL\xe2\x80\xd8\x16\x89\xa7\x96\x0b\xabvp6\xb5\xf4\x9a\xba\x85\xc3\xc1\x95\x18\xc0y\xee\xe7\xc4#\xf1\x94L\xe9\xcb\xb4\xd4\xc5\xd9S\xd6\x85.\x1d}c\x0e\xb16[E\x0d\xf4\xe2;\x99\x1d*\x1f9\x19.\xaf!\x17,\xd1\xaf\xbf\x86\xf3\xc5\xcf~N\xd2w~\xfa\xc5r\xd56\xe2bIRZn\xdc\xd0\x85\xcfI>n\xa7\x98\xc5\xe6\xd6\x00b!7[\xdf\xfc\xd5\x80\x1c\xb7\xd7P\xa6$\xcb\xd3\xe4\x8eL\x1b\xdd\xef\xddE\xc9\x9f\x86\xf5V\xacS\xec-]@\x8d\x12\xb5\xf1TK\xac\xfe\xa5W\xf6\x0d\xbd\xce4\x80(\x0b(d\xb9B\x08\xd4\x06\xa2\xc7\xc8\x7f\xfc\x10*\xfd\xb3i\x10\xb4\x88Q\xe1M\x19,I\xe1z\xc5\xbf\xea:\xe4\xb1Av\x80\x14Q$6,\xae}W\xdeGyM{\xff]\x0e\xca\x9d\xe1\xc8\xb1\x1f{\x8a\x93\xca=\xabT\x91t\xd1\xe8k\xf6o\xff@w\x90\xb3\x10\xf7\xfe\xd7G\xf6;\xb1\x07.\xd2\x1e\xdf\x00\xccu\xcbk\xa9\x94\xa1flvl\x1f:]\xf2\xbe\x90;~z\xe2l\xfb\x98$\xc2\x16\xc0\xc4@\x0b\x82\xa6\xf9\x1d*8\xf4\xb2;\x19\xc1 \xc3Pz\n6\x05\xd6F\x0bez\xd0\xd2\xef\x1b\x86\"\x1a\x9a\xb2}\xd4D>\xca\xf1h\xa7\xe7\x8cm\x8d\xf6,t\xb7\xc5\xedVP.\xde\x16\x9bH\x03\x1f8\xe6\x1b.I\xa2\xf3\xf07R\xe2\xad:L\xe8vl\xa4o\xad\xdd\xfa((\xab=*\x1a\\&\x16\x9cNi\x9d\x94\xb9I\xc6\xed\xa8@\\%\xfb\xda:-q\xad\xcf\xdc\xba\"\xf6\xe6$\xa7\xf7\x88\xac\xd0\x01\xca\xa7O\xcb\xf1\xa2czu{\x02\xc3\x81C\x0b\xa4$\"~F\x98\x84\xaf)\xa1}\xd0\xa8oc\"\xd2\xa9b\x83\xe9X\x05\x08\xbd\xf2\xdbD-\xd5\x0b\x06\x8fY\xe4 \xeb\xa6\xd6Y\xe8\xa0[\xec1\x8b\x10\xe0\xe8\xc0\x01\xda5\x0f\xbauO\xab\xe8\x03\xce|\x91\x92\x06@\xbbD;\xe2\xfa\x16h\xa5\xdf\x05Zi\x19G\xa9\x114Z\\\xfd\x01\xd6\x88\xc8\x00z\x98\xcd\x92\"\xed\x02Y\x8bT\xf1[\xa0\x96|\x17\xa8%R\xf4\xa9\xd4Q\xf5\xf9\xe2Z\x0bp\xae\xd6\xf1\xb8\x8e\xca\xf4Gg\x81O\xdb\xe4ju\x03\x7fmq\xb3\x98tO\x95.%\xfcy\xb7l\xc4p\x94\xa7v\xb2\xfe9.\xf7\xe8\xd1-s\xb9\xd1#\xc8\x08\x89\xfa\xda\xd1\xcb\x8a\x0e\xb5\xe2\x96\xe1P}\xce\x98\xfd\xe1\xfe\x81c[Y\x1aX\x1a\x9e\xff5\xefH)_k\xca\xdfX\xfe\xc1\xc2\xf1\xb2U\x14\xe6\xb6%J\xcaR\xd8\xd8\xde\x1f8\"a\xf99F\xca\xe8\x03$\xce=\x93\x9a\x05\x98m\x94~\xe1\xda-tr\x84\xc8d\x0d\xafx4FH\xe4\x87\x14s[\xb1\xbf$\x16\x1a\xd1$\xd5=7\x9fDIxi\xd2cK\x9f\xf9\xd5\x17>/\x87\xf2\xd6M\xf6{\x0c\x19\xb3H\xe0\xde\xcb\xb9\xe3\xb0\xa8b,\xb6\xcbi)c\x871\x14\xe2\xb6\xf64\xa9\xd6\xc4\x18\xec)\x89HN\xf0\xbd+\xbd\x92\xd7\x94c\x97\x93(3\x85\xe54\xb5hu\xf84h!\x87\x04\x14\xa7}&>Ja$a\x87\xdc\xfeZH\xa1sM\x94z:9\xf4\xc1\xa9\xc4A\xc0\xb8\xcb^\xa5\xd76\xeb\xa4\xbe\xf5\x9bo\xb4o\x10\x81\xef\xeckw\xdf\xde\xaeJ\xc53Q\xdb\x81Z<\xe3\xc5UYj\xc4\x9f\xab\x12\xbb\x80?W\xeb\x99\xf1\xe7*2X\xa1\xd0\x8ci\xb3\xce\"B\x0f\xc4z\x81\xa9T\xe0\xb5O\xc9\xe4\xbbz\x81\x05+\x10%\xb1\xbe\x82\x1b8\x81\xb4\xfeh\xd9I\xb47t7\xd0<\xc8\xe7Z\xb2\xf9\xe5\"\x8c\xa6)\x89\xc7\x86sx\xe9\xaf\xc6\x10zK\x7f\xd5$\x0b\x80 1\xcf\xfc`A\xcb\xf0\x9f\xfarAR\xc49-\x85?\xf4e\xf2\x045\x9f\xb4\x14\xff\xa9/\x97\xc4\xd1\xdd\x18f\x8dw\x1a\xca\xe5e\xb2\\%1\xa1M'^y\xd3,\xf7\xb1HI\xadl\xedA\xb3|m\x05\x8cA\x03\x1cy\x86\xc7\xa0\x81J\x98\xfd\xe4G\xe1\xb4,Rx\xf5'\x9aN\xa6\xc9\xea\x82\x99De\xa6.\xbd\x8c\xfc,\x1bC`z\xcf\xd7\xe4\x18\xa6\xa6\x12\xef\xc2\xafa<\x86e\xf3\xfd\xab\x0f\xef\xc6\xe07\x9f\x97J>\x8d\xf1\xe9\xd5U\xb6J\x89?\x1d\xc3M}q\xea)\x829>\xfdc\x90Nc\x93\x87L\x12\xf0\x94\xb2\x1e\xf6h\x7f\xbf\x12\x14V\xe2\xa5\x85\x9f}\xb8\x8d\x85\xc8P\x8b\x9cF\xfb\xaa\x9eO\xcf\xa1~!wc\xd8\xd0XA\xa6d\xa6\x7fqu\x95\x91\xc8\xfc\x0e)\x84\xb1\x9a\xbeX\xeb\x10\x9a\x19O\nI\x9cG\xbc\x94T\xbbJ'?\x8e\xfaU\xf3\x85\xdcI\xd5\x88_BU\xa1\xe1\x1cX2C\x03Y\xd2\xd4*\xd3\xeb\xcf\x7ff'\x96vE\xe6\x98^\x994_\xe0\x1ch\xb6\x16NA\xdc|\xbeJ\x93U6\x86B\x03\xff\xe46\xa6|PhZ\xd6P\x01\xa7\x8a\x0b#\xbd\x0f\xea\xc7\x88\x060:`\xa4\xcc\xd0\xfaw\x1d\x97\x06&\x0b\xf0\x15\xe8,\xc0\xd1\x9b\x96\x11\x04:\xde\x19\xd5S)\x84t\xf1\xe4,3\xcf\nm9R2s\\\x88\xc4\xc3\x19:\x98\xc0&\xa0\xd2\xcfqky\x06=\xb6\x84\x05\xe91.\x9f4\x8b1z\xb7^\x10\x9f!\x1d\x14\x96\x921\xe6\xb5\xb6Q([\xd3\xe6\x99\x87}f\x1f\x93OR5\xe3.\x05\xdfTg\x18\xb5\x05\xa3&d\x98\x0eh\xea\x80\xef\x05\xfc\x8c\x84Fl\x8f2\xe2\xc3\x14\xbd\x944\xcb\xb4T\xf2-J\xc3\x9e)\x85\x11S\xef\xdd\xc01L\x8f\xe0fs\xd3\x81\xc5\xe4\xa6n\xd8s\x83\x811\x9b\\\xee\xc0\xad\xf7\xa9\xee\x8f\xf8\xd0\x18 \n\xdf\x88\xb0?\xa3\xf0\xcat=\xa5\x9d\\\xa21\x87\\\xb2\xd9|\xb5.\x96N\xcd\x96\x8c\x02^\x9a\x81e\xc3\xe0\xfeA\xb77\x02\xba\xdag.\xac0\xa9&z4\x05E\x9a\xd2\x03\x10\xfc\x1aK\x13\xd4\xc9\xaa^Fp\xca&C\xb7\x9e\xd2 P\xbbWs\x8f\"\x0f\xae\xa4P\x9a\xa7G\xfa\xf3x\xfa\x89\xc5F\xf8w\xd2\xa9t\xa8\xc6\xe81\x86\"w\x19\x96\xa5\x7f\xf8>\xa0?\xf8:'\x1e\xc3*\xf4\x17b\x1eu\xfc\x12M\xd1\x13_\xf8\x0c\xb8\x94\xa8\xb4\x7f\x7f\xa8*n\" \xd4\xba\xd0-\xdc|\xb5\x00~8h\xce~\x0cj\xdd2\x16\x8d\x87_\x17\xd2\xf1kHg!\x90\x0e\xdb5\xe5\xf2\x90q\xd0T\xc5A\x0c\xdel\xe1\xe39.\xaf\xe9\x12mi\xde9\n\xb6\xf1\x0d\xd8\x86=\xb7e$F\xf9\xbb\xba~\x8c\xe2\xbd\x15\xf3\x81\x99\xd1?cqG\xcbj\xb0\xd3rM\xec\xb4t`\xd5\x07;-;\xb1\xd3\xbc\xc4NK\xc7\x85;\x86\x9d\xee\xe0\x18\x96GpG\xb1\xd3|rW\xc7Nw\x06\xecT\xeb\xd0\xbc\xd7\xfe\xe7{c\xea\xc2B \x81\x9b\xba\xfe\x9c.\xfe:u\xfch&\xb8\xa6Gc\x0bD\x90\x12\x0c\x8d\xc9\xad\xca\xa4i\xf0'\xe8&M%\xb1\xd3\x81\xe3\x9d\xdf-\xaf\x93HO\xe9\xa6\xebU7:\xd4\x9b\x0d\x0d\x0f\xbf\xcd\xd6m\x83C!\xa9\x0c\xd0q\xc1\x7f\x8b\xdd\xdb\xc8 \x81|\xaa\xaa\x19\x19\xd3\xbf\xdf\xb0#bt\xf5\xfe\xb0sdf\x94+E\x12\xe4f]p\n\x13r\x89\x96g\xfe\xb7\xc8\x131\x1e~cxJ\xf8\xbb~\x13\x11\x1aB\x972\x95\x1b\xa9\xechH\x13W`\xe0b\xd8lD\xe1\x11k\x7f\xc0j\xa4\x93I\xfbF\xe8\xddV\x02\xa7`m\x0d,J_u\x8c\xbf\xc6p\xe9$E\x9cUb\xe7+F\x1c\xea9C\xc4\xcb\x8a\x15I\xaf\xb8yq\xc5lU\xd6c\xacR;\x97eqM\xec\x15$\xb1\xd0E\x9a\xc4\x17\x98\x98_\xcb @\x87]\x8a\xb8\x84\x89\x82\x9e\x0b\x03\xd6\x8dY8/D=\x1a\x9f\x81\xda\x93\x87\xbaU\xf1\xa3\xc0\xd6\\\x0e\xaa\xd7\xb9\xc2\x88\xc45(\xd7\xe0Z\x9f\x80\x98\xdc\xa2\xe9r-.w f\xf8\xfe\xb6\x07\xfb\x9d\x9b\\\xb7kj\xa6\xceJ\x98\xd8\x97~\x1c'9\xd0\x86\x11\xc5%)\x14q\x19sH\xbb[\xbe\xcb\xa0\x1a^\x1f\xcaxyt@\xfb\xa0\x81@P\x10\x91b\x04_\xba_S\xb9\"\xe6\xfb\xdb\\\xdd\x9ch\x19\xab\x99c\xe5\xfe\xf02\x9d\xd0\xec\xe3\xc9\xf4\x87x.\x89\x93\xa8>\x04\xdd\x0c\xd9\x03\x17B1 g\xed\xc3\xa9\xe7\x8c\xb9\x06\xa0\xb5\x18\x0d\xab;M\xf2\x99\x16f\xab\x18\xff\xf7\xc3\x8cr\xa8\x98X\xe6\xfe\xbeK\xceT\xc6\xd6\xe6Lm\xccX*\xd2dj\x1b\x10|\x048\xca\xc7\xa5\x9c'\xed\x92\xf30S\xef\xfb{a\x06\xde\xc4\x0b \xefg/\xcc\xde'\xf9\x82EcH\xdd\xda\x0b\x06\x8a>\x04K7=W\xf5An\x83\x0b\x93\xfb4\xa1\xee\x04NBpjbB\xc9\x079\xd5o\xad\x99\x94\xac\x88\xdfo\xdd0\xcf\x1e\xf5\xe8\xc6\xa5\x133\xda;f^\xd61lb\xd4L\xccP\x85\xc5\\\xefL\xcf\xc1\xe6F\xf4[e\x81\x1a\xcby1\x18/\x8c\x83\xa8\x98\x12\xa1\x95\xe9p\x1fG\xef\xe0\xb2\xad\xda\xeb\x07\xae\xc9\xed[S\xb3\\\x9bEM\xee\xe5\xfe\x9c\x9b[\xd3_O\x9eP\x1e>\xa4\x8b\x88\x89\x92\xe9O<\x13M!a\x1f\xd0\xaeJkJ\x86ofa\x94\x93\xd4n]\x91PAn\x8b\xc7J.\xb1v\xaeV*\xad\x93\xe6\x84i\xa2\x16r\xf3\x15\x9c\x0e\x14:\x88\xdf\xf7\xf7hK\xc6\xde/WQ\x18\x84,\x1dIy#\x97 _\xa5\x12\xe5\x8d\xae\x8e\x9e3\x85\xb2A/J\xfc\xe9\xbfs [Y\xe0G~jq1\xbex%\xd3Y\x89m]\xa0s&\xbac\xc6I\xbc\xc5\xbeA\x84LO\xbc|A\xa0\xec\x7f\x14f\x18\x07\xdf\x87,X\x90\xa5\xef\xc1\x1b\xf1*%Y\x12\xdd\xd0\x13!\x99AV\x04\x0b\xe6\xed\xdf\x08l\xe3Y\xcdIe\x86=\xc9r\x15Fd\xfa\xa6\x82\x9c\xcf]\x08,\xd1\x01\xcb\x85\xc9\xa5\xfa\xc1\xd9\xd7\xe6\x07\x02\x9e\xda\x0f(m\xf9\xce_)\x14v\x03\x9etK\xf2\x1d\xa4\xd5X\xd0\x8b\x01k\xac\x95\xdf\xe3{\xf2kA\xe2\x80\x98K,\xfd\xd5\ns\x1f\x98\n\xcc\xfc(\xba\xf6\x83/c9h\x97\xb8\x1e\x94H\xf3\xd0q\xea\x8b+\x9e\xb0\xadx9\xc1m\x8af\x16\x9eh\xa9z\xa6\xf1\x15m6GQ9a\xa8\\\xe7\xa7|\x84q\xed\xf3#\x16,v\xe8H2'R!!U\xae\x08Fj\xd2\xd6\xae\x16\xc3\x9aP\xc9Jz\x15\xde\xab\xb3\xd7\xcf?\xbf\xbd\x10\xfa\x95R\xc1\xdf\xb6\"\xc4j\xa8w3\xbb\x0d1\xb2\x9c:h\x1d\xdc\x03?#0\x1ck\xe7\x03\x83'\x8a~)p\x9c\x0c\x0c1\x02\x0c\xf1\x96\xb1\x9d\x91\xb9\x1d\xb9b\xb5)\xd5G\\\\\x86\xa6\x04\xd3\xa2\xfd\xa6\x86d~N\x93x\x0e\xcc3\x141\x88h\x12\xd7\xcf9\xc3&|\x16J\xe9D\x9b\xba!\xe4y.SA\x0e\xa2\x83u^{\x92;.l\x90^\xf1_\xc49+[K\x17\n\xa2R\xf0\xe6\xf9\x8a\x04\xe1,$\xd3\x12-\"C\xcfQc\x06v\x92RD\x19\xc6\xf3\x88\xf0\x11r_]\x07\x83\xc6\xfba,pn\xed\xad\xa72\xb5k\x84\xb1\xd1\x0d#\\w\x18\x7f{\xfe\xee-\xc7\xde\xb51P\xbci\x1a\x81\xf4\xae\xd1\x7f\xb1\x8f\xc9-\x14\xb6\xe6\xdcb\xc7\xa7V\xaa#\xf0\xf8X\xf5\x05\xac \x93\xbb\xad1\xd7$\xf6\x86\xc3\x9a\x19\xdf\xa1\x96\x96K\xda\xe4\x956\x81'\xf4\xa5\x1aXLn+\xd4\x1e+\xef>\x9f_\\}>?\xbb\xfa\xf8\xe9\xc3\xc7\xb3O\x17\x7f\x1b\xeb\x92\xa1\xfe\xf5\xf9\xf9\xd5\x8b\x0f\x1f\xde\x9e=\x7f\x7f\xf5\xd3\xf3\xb7\x9f\xcf\xc6\xb0\xab/\xf5\xfe\xf3\xbb\xb3Oo^\x8aR\x87\xfaR\x1f?\x9c\xbfA\xd6@)>2\xd4\xfa\xe1\xa7\xb3Oo?<\x7fu\xf6J\xed\xc6\xce\xa8\xf9E\x18\xd3\x85\xf1\xea\xc3;\xc1\x10\xbfD\x19[\x97\xf3\x12H\xb2\xd1P\x7f:\x02'v\x89\xc7\xab\x0e z8\x98NS\xe0\xe2h\xe2\xbd\xfa\xf0\xeey\x9e\xa7\xe1u\x91\x93\xf7\xfe\x92d+?\xe8\xfe6\xd3\x7f\xdb\xf5Y$>\x13\x00\xe8\xf5U \xbez\xc7\xe3\x9d\xbc#\xf9\"\x99\xf2\xef\xf4\x98\xba\x94W\xccP^\xe1\x85\xd9\xcb\"\xcb\x93e\xd9_J\x18\x16\xdeU\xe3\xb9\xb0\x97\xe4^U\x9a/\x9d\x16\xba\x1f\xf0`]\x95s\xa0\xea\xd7fL\x12f[\xbb\x87\x96\x0b\xb3\x16co\xdaw\xa4\xcd\xbc&Y\x98\x877\xc4X\xa7\x1e\xcb\xf5\xab\xfc\xc3\x0dI)\x07E\xa6\xc6\xe1\x9b\x90b\x93\xc9\x95/\xc3F\x06~\xf2/<\x05\xe2\xb0 \xf8L\x1e\xa5x\xa6\xefd\x19*(\xb5\xad\xbd\x01\xee?\x174[\xb4ms\x03\xdf\x9a7\xe8\x9c>\xeb\x08[\xb5\xf0j{\x02N\x14sA\xf9\xd2\xbbi\x00:\x96k\xb1\x88\xad\xd4\x8e;\x0es|\xcd(\xaf\x17\x19\xbf\x92w\x1b\x9c@\xc4\xca\x07\xc6\xf2\xf5\xcd\x06'\x10\xb0/dD7\x99]6lv\xc4\xa5\xe1\xd7jO4\xbeq\xd6\xf8\xf9\xd6\x7f\\\xf9[\xbf\xfd\xf2K1\x18\xbc\x1cl\xe1\xdfW\xfb\xec\xcf!\xbb}\xcdn_\xb3\xdb\xd1\xeb\xd7\xf4\xcf\xce\x01+\xbcs\xf0\x8a\xfdyMo\x87\xaf\xf1\xedh0x\xb9\xc5\xfe\xbe\xc2?\xac\xf0hx\x88o_\x0e\xd8\xed\xeb3z\xbb3\x18\x0c\xe9\xed\xab\x03\xfc\xf6\xf5S\xf6\xf6\xf5\xab\x97x\xfb\xea5\xbb}\xfd\xfa\x95&|Is\x05\xbdyu\xf5\xfc\xe2\xe2\xd3\x9b\x17\x9f/\xce\xae\xde?\x7fw6\x06k\xea\xe7\xfeVJ\xfc \x0f\xa7Vs\xfb}\xfa\xf0\xe1\xa2\xed\xa34Ir\xcdg\xf5/\xae\xce/\x9e\x7f\xba\xb8z\xf9\xd7\xe7\x9f\xb4F\x85Ji^\x0e6\xc1\xfa\xe5\x97-o\xb0\xf5\x14\x81\xfc\xe2\x00\xa19\xe0\xc0\xddg\xd0\xdcy\xcd\xa0\xb9;\xd0t\xa3Z\x1cz\xae\x1e]\x0d\xb3,d\x8e\xd2\xf1\xd4O\xa7\x0c\xff\xeb\x91y\xcbQ=n\xa4\x16\x00\xb4DV\xca\xf7\xa1\xb3\xea\xfa \xa6\xfai'\x13jj!3\xe2\xc00\xf5\x03\xb7\xbd\xb2I~\xe9\xc8\nr\x8d\xd6\x15\x8c\xa8B|3ln7\x13)\x8a\xe6\xcdFS\xcf\xef\xceO\x1c\x1c\xee\xd4\x18\x8a\x1df\xa3\xfc\xd4\xc0W4x\n\x8a\xef\xfc`\xf1\x89\xcc2.\xe1Bi\xc7\x157\x9d\xe264:a\x87\x9e\xcfX&E\x9cK\xf6\xf1\xea\xd8P\x98\x1f\xa2\xb5\x94^.V eZ\xaf\xc6\xae\x7fi\x94\xe7\x10\xb5\xdf\x92\xce\xa7\xf9\xd2K\xc9\x8cI\x91\xe7$\xffD7\xff;\xda\xea'\xe2O\xefl\xc7#\xf1\xaf\x05)\x08z\x04R\xcc\xdc\x86_\xe7$\xffk\x92\xe5\xef\x93i\xe7\x8e(\xbb*}c\xb7:6\x17q+P\xb5\x8dxSRN+3\xb1S&\x94>S+n\x08\xb0\xeb\xfd\xe0\xf1\xf3Z'74M+\xe3\x8c\x94^4'\x12\x95:(T\xc6\xc4\x13!\x97/_\x05I\x9c\x93\xafF\xdfdM\n\x10\x90\xd6S\xeae\x8b\xa4\x88\xa6\x9fWS?'\x08\x14_\x9ft\x18\xf0\xacA-B\x1d\x82\xbe\xc3\xec1\xeb \xb0\xc5\xa8]\xf6\xd5\xe3\x16`\xdcc\x016\x11P\xdbT\xadH:K\xd2%\x1b\xef\x9b\xd9{\x12\x90,\xf3\xd3\xbb~\xfe\xcb\xc4\xbb*\xf0\xcb\x17~\x1e,\x98\x86\x8f'\x8a\xc51\x9ajo\xac\x9f\nk\xe81`\xf8=0\xe0\xc8\x10\xedo\xb8\xfbT\xab?\x1b\x19\xfc6w\xf6\xd4\xf2\x183\xad2\x08\x91\"YN\x93\xa0\x10\xd3\xab J'^{\xe2\xc7\xbb\x84)q\xf4\xb5\xc5\xfeM8\xc7h\x9erf\xe5\x93\xe6{\xaf\xc8H\xfa|\xce\x1b\xde\xfe\xe5\xfal:'\xbfl\xff2\xdd\xf6r\x92\xe5\xb6\xa6\xa0\xf6\x1c\xd0\xf8x\xd0\x8d\xd7\xf0\xa9\x00\xd9\x82\xcc\x8b\x93\xa9\xc1:*\xe69V\x995\xa7~W\x8b8\xedz\x8e\xa5\x16?\x9e\xc7\xb1\x8cK:\x00\xc3Y\xb2,h\x93\xf4\xd2\xc5\x1d\xa5\xd9\xbch\xc5Z\xed\xb6E\xbe\x8c0\x8a\x1c\xda\x8e\xd1;\x07\xc6\xd2{\x8aP(\x1c}V\x00\xf1\x8bi\xfd\xd6\xd6]\x84Q)\xbbv\xd2p\xc8=\x16(\xdc\xf0?\x94db\x02\\\xdd\x0b:\xf7\x95\xd9B\xed=\xa5\xe1\xea2\x0bf\xeb\xc1\x03\xeb\x89\x92\x82a\xf9\xfc\xe9\x0d\xc6\x83\xd2C\xe1\x1c+\x10\x85\x84\xd2\x94A\x8e\xb7\xaf>\xbc\x93\x7f\xb3\xca\xc5\xddE\xf2\x85\xc4\xec\xc6\xcf\xfd\x8b\xd4\x8f\xb3\x19I\xdf\xe4d\x89\x0f_\x87\xbcQ\xba\x9d\x9fG\xd1\xcb$\x8a\x18\xc7\x8bO\x94\xdb\xd7I\xba\x14\x0e\xca\xf4\x9e\x85t\x16O\xde\x91i\xe8ce\xef\xc2%\x1e\x80\xcc\x8d\x9b\x9e\x03S\x8a\xce\xde\xf9+\x97\xfe\xc52\x1f\xfd\x90\x8e\xe1\xd7\x82d\xac\xeb\x1f\xa3b\x1e\xc6\xfc\x0f\xfb\xf2\xfc\xa7\xbf\xbc\xc5\xb5\x8e\x05\xce\x7f\xfa\x0b#\\\xc5\xddG?_\x9c\x93yy\x9b\x84q.n$(\x9c\xff\xf4\x176\xee$e\x83f\xd15^\x14\xb3\x99\xa8\x8b\x82\xfb|A\x08\xfb\x9c\xa2\xa1\x8b\xd4\x0f\xbe\xbc\xe4\x00/\x1f\xb0\xbb\xa4\x08\xb0G\x96\x88\xe7\xe1\xd2y\xcc\x18\x99\x93\xa1(Dl\xd1L\x1f\xb4\x93\xee\xccb\x92iv&\xddK)\xdd\x89\x8d73\xe0\xfb-\xa8,G\x15t\x81\xce\x1b3\xee\x8a\x94`\xc8Q\x17\"\xba\x10'\xd1%\xdd\xee\x1e\xc2\xb5c\xcd\xab8\x91\xa1\xa62\xbcI\x17\x024\x1c\xe9\xb1\x08T\xe2eQ\x18\x10\xfb\xd0\x85\xada\x97!\xafi\xbb\x9b[\xeb\xce3\xd5\x99c\xea{\x04\xc7\xeem\xd8o$xj\xee \xf6\x10\x9e\xd0s\xbf\xb9\\\xea\xee\x07\xf6\xc8PNrd\xb0w\x0de\xb8\xbb\x84\xa2;_\x0fAJ\xb8pG\xe5\xbd8\x0f\xb7o\x8a\xd8\xde;xp\xe5\xe5\xe3B\xd2\xb5\x84\x8c\x1d\xdc\x1d8\xdeL\xd7\xc3=},\xe6&\xee\xee\xda z&\x82E\x99M\xd0\x1e%\xe6&\xc6D\xf6\xc9\x08\xb9\xf6\x93\xa0l\xac\xb92T\x97\x93\xbe3\xb9&\xa4\xba\x98\xf4\xdd\xbd=\xc7\xde\x18\xd4D\x95\xa3\x9d\x03\x87\xc7\xedq\xc1jF\xcf\xd1\x9bG^QR\x8eG\xfb!\xc2\xfe\xee\xaa\x9e\x82\xe3\xa1%\x06\x8f\xb0\xb6\x12\xd1\xc2\xae4>\xfee\xb8\xba\xabPooRK\xfe}\xaa\xa5\xa8\x10\xa8<]L\xe3\xf54\x895\xe1\x18\x90\xdbB\xff\xdb\x9c\xf1Wbl\x9b'\xa5\xaf\x84n\x8e\xcd\xaeK\xbc\x9d\xa1qn\x1d\xed\xe4\xfe\x13!\xf5\x162n#\xb6\x87\x83\xa1c\x1b\xa7\x9a\xb7{@\x11\xbb>\xae\xef\xef\x0f.X~#\x8c/\xf4\n\xe5+7\xd1x\xa9\x88\xe7\x1c\xcf_\x07\xe8\xfd\xe0\xda\x9aQ|c\xa3!Vn\xcf>\xadU\x8ftat#\x89\xddk6e\xb3(\xdd\x01\xc0\x02\xcb\x86\xf1#\x17\x1c\x81g0@\x1e#ET\xf1t08\x18>}:\xda\xdb=\xd8\x1d<}:\xa4,\xc7\x9a4\xfd\xb7d\xb5lM\xa1\x07[0d\xe6\xc0\xd6\xbb0fVs(\x12\x06B\xc9\x0f\xf8\x17\x0cyFi\x90#\xb8 \xb30\x87E\x9e\xaf\xc6\xdb\xdb3? \xd7I\xf2\xc5\x9b\x87\xf9\xa2\xb8\xf6\xc2d\x1b\x15\x99\xdb\xd3$\xc8\xb6\xf1\xe3\xad) \x92)ar\x9f\xd30\xbe\xf1\xd3\xd0\x8f\xf3\x13\xac\xb2\x96:\xa6L\x1bHQ\x8e\xf5\xc4O\xe7\xd9\xe4\x92\x95\x8bi\x15\x9f?\xbd\xa9d\xdfRb\x19\xd8\x84\xa1\xeao\xc4\xea\xc0Qc\xae\xb6\"\x8a`I\xb2\xcc\x9f\x13t\xb4\xcb\x08>\x8f\x93xk)F<%7@\xe2\x9b0Mb\x14\xaf\xd2\x8f\xf1C\x1cG\x06~<\x05\x7f:\x0d)\x80\xfd\x08\x16$Z\xcd\x8a\x08n\xfd4\x0e\xe3y\xe6)n27<,d\x95oHM \xc0\xa8\xbc\x04\x85d\x14\xf6o\x04p\xe0\xa70\x89\x90\x9d\xc2\x8c\xb8\xb3\xd4_\x92\xec\"\xf9\x98\xac\xe0\x84\xceT\xf2\xc8\x8d\xd1\x87\xbe\xe3IC)]CJ\xb7\xeb\x1c\xc9\xd3\xf5Vk\x8bI\xa7x\x03\xedj\xaa\x86\xf7\x998\x03\x1a\x91\x04\xa1\x81\xf4r\xe1\x1d\xd5\xba+\xa4\xc6j.Up\xdat\xb1\x1aW)L\xf0\xd9%\x93\x94\xc6\xcd\xc8\xc0\xd887T\xe9\xdb\xbcu\xcd\xca\x9b\x932\xf2z\xdf\xa3\xdc\xb5_\xa5\x1a\xaf7\xa5\xa6\x0fi\x99\x8ee\xcdJMu2}M\xbf\xaa4\xda\x0bm\xadl\xd6{\xd7\xaaqU\xd7\xd6\x8aa\x0f\xfa\xd7\x8a\xc5;k]\x1b\x9e\xb2\xab\xa2\xae\xc2Od~\xf6u\xd5\xb7\xb6r\x8d\xb2\xcf:\x16i\x0f\xa7F\xb9\xee\xfe\x8e\x8dR\x1b\xaf\x14\x0f\x84^\xbd\xa7\x1fu\xf4\x1dq\xea\xda\x15\xe3WR\xcd\x0c\xcfIf\xe5X@\xd7\x9e0\xea\xe8\xdd\xa4(\xd5\xb9d>\xa6\xe1\x12\x0d\xfc\xfaV]\xedk\xd4\xeb\xe9P\x07\xbe\xd0l/|n\x88\xe5\xa0[\xe2P\xcf\xc4\xa7\xed?\x93O1\x970~S\x16{p\xca\x185\xb1\xbd\xb7\xebx\xec\xbd\x9e\n]\xdf\xfdWs\x8e\xe1\x04J\xc1K9'#\x0e\xd9\xbf=\x7f\xf7\xf6\xeck@V\xfcx\xc5\x97)\xf13\x9cY\xc2\x1f,\xfd\xf4\x0b\x0b\xfc\xc0n9\xe9pR%v\xa1\xe5)\xcc\xec\"\xfe\x12'\xb71\xb0g\x8e\xe5\xc0&/\x85\x95\x9c\x82\xc52\xfe\x89'\xe5)f\xe3\x99b9n\xd9\xe5U^\xa4\xe4<\xf7\x83/\x17\xa9\x8fQ\xc6\x0codk\x19)\xee\x01\xad\x10\x9fe\xb4$\x86\x0d\x14\xc4\x87\xc3\x9f\xd1.K\xe9\xcd\xca_iK|\x0b\xd6 9\xedOj\x8c\xbb\x90\xd6_\x8a\xb1\xb6\xae\xec\x1b9\x1b\x01\xce\xd3&Xc\xd0G\x0c\xc9)e\xd79 .lT\xc1\xfcq\x1e0\xe1\x07\xa3\nM\xd3\xe1(\xa1\xb4\xd6\x8e\x83\xd3%\x8884E\x91\xa0\xd3\x94*>$\xa5\xff\xc8$\xb6wv\x07\x8e\"h\x15\xbe\x83\xf8\xfe`o\x88\x96W\x07{#\xb5\\\xe5j\x82\xe5vx\xb9]\xfew\x8f\xff\xddw$w\xf1G\xecN\xf1T\xe6\xaat\xe9:b{\xd4Hu\x11r\x13\x08\xf5\xb90\x8dP\xa5\\E\x15\x103\xf5\xe6L\x14NX\x0c\xaf&\x92\xc8L\xd2-\xd1\xd3\xb61\xaaeso\x1af+\xca\xc82O\x0fo\xb5\xf032\xfdD\xe6a\x963\x05\x08Z\xeeNbs\x14\x89\xc2&\x8d\xa0\xec\x0f\xf4Y\xdc\xb4\nJ\x99\xaa\xdd\xbb\x12\xcd\x8a\xa1\xa2\x01\x8b\xf6\x05\x8b\x1c/\xbdy\xc3\xcf\xb6\xc6'\xe5\x0b\x17\xeaq\x86\x9a@\xd4\x04\xd4\x14\xe1\xfaz\xc1\x03\xa5\xfc^\x9e\xfa7$\xcd\xc8\xc5m\xf2\x91\x96\xb3\x89w\x95\xfb\xe9\x9c\xe4\xb4+.dJN\x9bf?\x02\xbd\x18}\xad\xbe\x98\xe6\x97\xd9\x99\xc8\x1dj\x14\x03!\x9e\xa3|=\xa6\xd6@\x05\xb8\x00$\xd3M7#X\xd2K3\xfaX\x1d1@]\xe6\xd1\x1c\xff\xcc\xb4H\xd1\xc8\x85\x99s)PH\x95\xf1\xb7-\xef\xce\x8f\xf5 \xa1\xfb\x9a\xafj\xcd\xc0\x1f\xb3\x84\x93o[\xc2\xd0 \xc8U\xdf\x05\xadB\x80\x16\x9a\xa9\x0bw\xa0I\xc6\x04\x1c\xae\xd3\x86\xce\xd7\x0f\x82bYD~^.\x85W\xbcM\x92u\x19pb\xf0\x83\xa8\xd5R\xb2\xad\xfa\xf3/\xe1\xea\x02;\xde\xab!U\x15nj\xe8U\x98\x92 _s\x14\xab\x9e\x95\x9f\xc59I\xdf\x12\xff\xc6\x00\xa6\xd2\xb4W\xd7R\xb5\xed\xaajlf\xcd;\xe3 ]L\xabF\x7fRO\xf1\xe97\x1f\x8d\x86\x93Q\x1fy\xaeyb\xf2\x88\xceC\xdd\xc9\xa8;I3\xc3I\x1aUI\xa6~Ws0a\xcc\xf9\x86\xc9\xd1\xacK\x8c\x04b+\xd9\xa1G\xbe\x92\xa0\xc8\xa5y{\x13\x7fH\xa7\x84\xd3\xedh\xfb\x95}$i\x86\x1b?\xb7\x193&\x13\x94\"\x0f\x91\xdd\xd8\xdd\xf5^\xf5f\x8f\x11\x81n\x0cZ+\xeb\xcd\xb9\xb3\xca\x86\xad\x95-\xfaVfy(\xe9\xf4\xae\xd2$A\x93\xaa7\xaf\xea\xf5\xd6\x17\xd2M\x03\xadH\x1e\x00\xcdF\xd8\xcb\xb3\x1b\x12\xe7\xccl\x01\xe7a\x0c\x89\xa7\x7f\xd3D\xf4\x8dr\xd9\x0b\xee\xde\xa7\xa9\x83\xbfk\x9d\xb2\xa2\xa4\xdb\xfa\x19\x06ku\xe51S@ZOw-\xfcR<\xd6\x1cD7\xdce`\xd1H\xf4I/;\x9a\xe4,\xfbh\xc4\"\x81\xfd\xfe\xe08\x93\x10#H\xe8\xeb\xc2\x94_\x8d\xf3\x81\xd9\xebd\xda0b>\x1a|z\xd3p\xfa\xb1\x1a\xbc\xeeY \x866\x00J\x84o\x0f\xa3|\xa1I\x8b\xb4=\xa3\xe4C\x9f9\x00)6\x84v1\x8b\x0b\x835XI\xfc2\n\x83/\x96>\x90B\xa3\xdcK\xc6\xe6\xf6(\xfe*)\xae#\xd2\xb7r\xa9t\xff&\xde%EF^%\xb7\xf1:e\xd7\xac\xfe]r\xb3V\xd95\xab\xff\xbc\xea_\xb2\xbbj\x90\xf4t\xf6\x06\x92\x8a\xfeu\xc4\x12\xbcbT\xc0\xdc\x05\xeb\xba\xc8s\xb6Cy2H+\x8cWE.?\xc8\xd0\x14K~\x92\x93\xaf\xb9\x9f\x12\x9f?sZ\xbc\xa8[#s\x88K\xf4\xb2\xe98\x05\xa0\xea \xc4\x85\x87s\xe3\xcd\x03\xb3\xceV]'DDJ\xf59\x8bY\xed\xc8b:=\xeeH\x8dx\xa8T\xf2SZ~\x92^\xb6a\x00\x96/\xe8\x11H`=\xb4\xc5\xf9\x8a\xdb0\x8a^\xd5Z4=g\xed\x9bG\xae\xc7AX\x1dO\x81\x94N(tz\x0c\xfey\x14\x95lC\x17\xd5)\x98<=\xe0\xeby\xbc\x15\x12[\\\x14O6\xfcpc\xb4\x82\x89&\xf1\xe5$\xbflC\x8ab\xfcf\xf0\xeb\xc4\x06\xe2B\xf8\xa4\x86i\xd0=\xb7\xb9\xa1<\x87)\xef`\x8f=\xf1\xa0J\x90\xf2\xd4\xe7\xc7{\x7f\xca\xbb\x84g\xe8\xf2\xa3r\xc5H\x83\x9a\xfd\xa1\xdff\x7f(.a\x87\xe8O2\x03|p^\xba@O \xda\xc8\xab\x8dF\x1e\x83\x19\xf2\xccv8D.7\xa4\\\x91~q4\x11K\xf3 \xdf\xdea+\xbc\x99\xebU\x13\xdefR;\xc0\xbe\x05\x1a.X!\xba\xd2$ Y\x86U\xffo\xdaHW\xf5b\xcf\x04M\xe8\x94\xfc\x01d\x88%\xe1\x14V0\x86\xa9\xe32\x80Q\xaa\x0c\x93\xb1\xfa^JP\xd5\xfd\xd2/\xe6\x8b\x9c\xe9\xc2[\xbbyu\xb5*\xd29\xe90\x81\x89*S\x0fc=\x12\x91\xf4\xc2\x8f\xbf\xf4\xcb\x8f\x1d\xd5\xeb,\xef\x0c,!\x0b\x01\xf0\x8d,a#\x85\x97` \xd5$A\xfa\xe8:7!\xb9\xed\x9aK(\x83\xe9\xd1\xd2U\xd0n\xbc\xd5\xaf~1\xfd\x89\x16e\x82\xf0\x99\xf4n\xc3x\x9a\xdc2\xcb\x81\xb2b\x8d\x87%H\x87P\xeea\xe2\x85W\xdcKM_\xb8<\x0eO!\x16!o\x7f\n\xc9-\xc6t\xe5\xfe'?\xb3\xc6\xc7\xc0z\xd1\xdc\x85MffJr?\x8c\xfa\x00\xac\x04\x12\xfb\x84\xb6\xdb\x199\xbb5B\xa6\x0b\x89\xda\x16oCRZIy@\x1bf\xa3\xf8\x85\xe7\x17s\n5\xcc\xa3e\xfb\xcc\x0bT^\x94\xfe\xb7/J\xb5\x93\xcb\xe4\xa6\x13_\x10\xcc\xa7\x1e\xe4o\xe2\x9c\xa4\xb1\x1f \x01\x1d\xdd&\xa8El\xdb\xae=\xc4R\xe5t\xe8\x9bi\xab}\xe1w\"\xd3\xbaF\x9e{\xff\xae\xdd\x90\x92\xbe\xde$#1C\xcah\xd7\xac\xc7?\xbdTS8\xa9\xd5\xf7\xdb?nH\x8d\xbcLVwi8_\xe4`\x07\x0e\x8c\x06\xc3}\xf872\x85\x9f\xfd\xdcT\xec\xefdz\xcb\xea\xabl\xc5\x02\xbaz\xd1E\xb0,\xff\xe3\xf6\xffQ}\xdc0\x1f(\xfa\xcd\x05u\xab\xd6:)\xa9D\xbd,\x91G3t\x02\xc8\x14\x16\xe1\xd9\xbe\xa5\x10\x17\xcdh\x95-\xe1,\xc4\x86\xafl\xeat\xf49plo\xcc\x9f\x0c\x92\x90\x85\xcbaR3Q\xa5$\x958\x81P1Y8\x81\xd0\x01\xc2\x9c\xfe\xda\xa8\xb32}L\xddb+u\xca\xaf\x13\xcf_\xad\xa2;\x9eP\xa9\x95\xbf,+\xaby\xc3\x86z\x82O\\\xe5D`F\xa0\xd4\x11\xc6\xc6\xa9\xc8\xcb\x93rG\x17\xde\x1f\xff\x9b\xe9G\xc2\xf2\xceZ\xd0\x1aKR\xc6c\xacy\x814\xeai0\x92\xd2\x85\x0eGk\xd7\xb4\xa2-x\xb2\x9e\x9e\xfa\x81C9\xc7\xd8\xb4(\xcb\xade\xf7\x95T\x9e\x0f\xf6zV\xc8\xdc.\xb8\x0f\x8a\xe3\x9e\x1b:\xd5\xf3?\x81A\xaf\xda]\x16*\xbc\xde\x9a\xe8i\xea\xc7\xd3diw\xfan\x18\xbak1\xf36\xdb\xf2\x82$\x0e\xfc\xdc\xae\x85\xc4\xc74\xc6cJeX\xce\x95\xe5\x82\xbd\xb9\x19\xc3&\xa4Ne\x0e\xb1\xb3\xff\xf8\xe43\x8dh\x06<\xb5e\xe39Sp\xec6\xe6\xcb\x07\x83\xd5|\x05\x8d\xdcc\xd9o\x87\x83\x81\x03\xa7\xfa\xd2\xd0-ZF\x94V\x06Y\x0d\xe9\xf2\xdd\x188.\xa46\xe5\x9d\x13\xa7\xdd\xd0\xdd\x14\x8c\\\xb6v\x7fh\xb4g\xcdInQ\\\xc1\xacW2q\xd7t\xfc\xb2\x9e\x07\x94aKR%\xdc\xb4\xc9\xf3\xcbBw\x0c^7\xe5\x0cE\xb2i\x0f_P\"\xf1\x11KTsP\x89\"\xeb\x9a\x17\xc7e\xce\x88F\\\x9f>=\xc1\x9d\x11\x9002l\x9aY\x94$iW\xef\x0c]\x0b\xb3\xf7\xfe{\xf4\x81\xd9\xc44\n\x03\xe6\x12\xc3v}\nc\x88\xd7O\xe8!\xe1\xa4Q\xaf\x87J\xe3>\xc3\x99\xa6\x91\x1b\xb4\xc4qn\xf4\xc1 \\R\xcaK\xddh\x98\xd6\x88\xcb\xd4\x93\x9d\xfe=\xd1\xb0n\x9aO\xea\x9d\xa91p\xf2\xa5\xf0\x8c\xba\x05\xd9\xe7\x0c&\xd5\xa9[\x92ofC\x08X\xe3\xd05\xef\x97\x7f\xa0\xe7\xaa\xd9Gr_\x9f\xc8b\xcf\xe4\xc3\xd9\x89\x0eR;Y?\xffZ\x97\x98gO/\xe69\xd0Iy\x98\x87Y\xf3\\\xc4A\xd5\x1f3\xbd\xff\xb0;\xc7\x9e\xd9\x14.cF<\x1ao[\x96\x94\xdeGk%\xcb\x82 \xb9\xd4\xb9\xf7\xa2\\\x7f`\xf0\x06\x8f\x1a\x11\xd8C\xb3\xe7\x1cH\x82']8`!^\x9ad\x97]\x84\xaaT\\\xe3%\xe72\xef<6\xa6f\x02\x0ds\xc21X\x1f,\xd8\x84\xcdMM\xf2oq\xddj\x93l@\xe3\xdc\xc1'\xad\x92\xf9\x99H\xeb\xa2\x8dfB\xaf\x7f?\xfb\xdb\x184\xf6#\xef\xcf\xce^\xe9\xd3\x17\xce\xfc,\xffw\xa2\x86\x873mg\xcc\x1a\x90\xc8A5\xb5n\x0b\xcc[]\x9f\xb6\xf2\x14\xacs\xca\xfdX\x1f\xd1X\x9f\x98e\x1d\x1b!NOk\x04a,\x97\xd5:\xf4\xdaj\x97{lT\xd4\x9bu\xd6R6P]_\xc4\xa5\x9fLq\x86N\xd2K/lNl\x13\xf2s\x92\xffL\xfc/\xeb@\xfeQ\x00\xd90\x84H\x84&<6\x86\x7f\x088zi\x05\x92\xf8uJ\xc8o\x9dBn\xa8*\x8f\xd0\x1e\xd4\xa3\x8b\x9b\xfe\xc2\xd8vO\x9e\x80\x00\x13\xfd\x1d\xd8u\xb6K\\:\x02\xb0\x8d6c\xfc\xee\xef\x0fe\xb8\xe77\xd9Y\x19yC\xfb\xf5Z\xb4\xc9\xef\xdf\"]\xd6W\xadw{\xcf]\xb0\xaa\xc8F\x0d\xf7w\x8e\xf2\xe4xG\x947\xf7^\xbe={\xfe\xe9\xea\xc5\xdfPs\x847\xf8\xeb\xfd\xd9\xcfW\xcf?_\xfc\xf5\xea\xecS\xf5\xe0\xfc\xe3\xd9K\xfa\xe0\xea\xc5\xf3\x8b\x97\x7fm<.\x1f\\\xfc\xf5\xd3\x87\x9f\xdfkJV/J\xc5\x05\xedCLn/(}\x1b\x9f\xa5\xed\x9eg|u4\x97\x0e\xc5A\xda\xa8\xcd+\xff.J\xfc\xe9\xb8%\x83$\xd4\x89y\xb5C\x18/\xf3[z\xa59@\xca^\x91\x8e^\x9c\xafH\xf0\x8d@\xc9\xbe\xbd\xf9o\x06\x81&\xbe^\xef>\xbf\xba\xa6;\xd7j2\x01\x0d\xc4]~\x9c\xadH\xa0i92\x1f\x02\x8dO\xb5\xad\x06\xbac\xa5\xfc\xd4/\xf2\x85\xa6\xd5Y\xedT\xc2\xd2\xb8\x80\x95b\xab\xaa\x18;\xc9\xaa\x92W\xd7w\xcc-\xb37_\xb6\xaf2X\\\xc6\xaeK\xdcY\xba?3\xa5\xc0\xe5\xda\xe1C\xdaH\xed\xfb{\xb4\x0fa6?\xc4\xa1\xef*\xeasMfs\x7f\xc7\xe1\xec\x96\x0b\x16s?5E\xaf\xeaE\x98H5\x0f\xf4\xee\x88\xfb\x0d\x19\x0bO\xf7?\xd03\xb0\xfb\x03\xbd\xf0e\x7f\xb0\xdb7\xdc\xb1\x10nli\x98\xa1\x98[U\x01W\xd3\x0c0\xe6\x16W\xe2\xd6\xd7\\\x92r?c\\@\xb6s\x04\x9b\x9b9\x1cCl\x0c\xb3\x99\x1a3\\3\xafa\x92\xdb)f\xcfK'\xc3\xcbv)\"\xbd2\xd9\x0b\x98\x9f@\xa9[{\xccm\x0fO \xa9?\x9f\x13\x96\xfc\xaa\xf6p\xe1\xa3\xe5J\xfda\x86%\x8b\xbauK\xb6\xde\xdc\x0f\x07{}$c*\xd8$\x93\xd0\x13)_x\xbc\xb5u\xd4\xe4C\xb8\x94~\x12_\xb2\xfc\x83\x92\x19\xb0\xf6\xac\xd8\x1a>z\x8f\x0c\xba\x93\xd1kFS\x0d\xe4\xeaj\xea\xe7\xfe\xd5\x95\xb6_\xa9\x9d;p\n\xf1D\xc3:\xe7\x94u\x16\x8f\xc7`-\xfcla\xd1\x134\xf6\x96\xfe\xea\xd1\xe31\xb8C\xed7\xe2\xf2\x89\xf0v\x06w\xa8]\xfd\xc6\xec\x11\n\xd7\x84\xeeD \x9dlA\xde\xa5!\x85\x86.:\xc6)\xf86*\x93\x12\x9b\xe0\xba tg\x89T\xddc\x94\xb8v\xc0M\xee\xdbZ\xbd'\xde-\xb9^\xf9\xc1\x97\x8fIt7\x0b\xa3\x88\xab\xe4\xa7d\x95\x92\xa0\x99\x17\x14=\xdeW~\xbe\xc8\xb8=I\x15z\x99\x7fY\xde\x9e\xb0\xf4\xb3z\x06\x8f\xb8`\xb1dM\xda\xd8f\xb5p\x91\x9a\xf0tk\xc5>#^\xd4x\xad0\xd6\xad\xfd\x0c\xffG\xfa\xa8\x11\xc64\xfa\xd8\x9c\xad\x13\x18>R_\xab\x9a&\xd4\x07@w\xdd\xf6\x7f\xda\xa7\xe3\xc1\xfdd\xb8\xf5\xf4\xf2\x97\xe9\x8f\xce\x9f\xb7\xbb\xb6\x88\x01\xa3$\x95\xb1\x8f>\xef\xfb\xc6\x86\xfd\xff\xb3\xf7\xef}q\xe3\xc8\xe20\xfe\xff\xbe\x8a\xc2\xe7\x9c\xac=\x18\x03I&\x97\xce\xb0,\x03\x9d\x1d\xce\x06\xc8\x0f\xc8\xcc\xce\xaf\xc3\x971\xb6\xba\xdb\x1b\xb7\xddk\xab\x9b\xb0\x9b<\xaf\xfd\xf9\xa8$\xd9\xb2,\xd9\x86\xb0{.\xcf\xd7\x7f@[\xd6]\xa5RU\xa9.T9\xd3\x18\n\xc9`\xc4*{\xf2\x04\\\xd5EI\xde\xf0A\xb2\xb1\xc7M\x87\x0b\x1e]\x80xX\x80\xc0\x1f`k\x97\xff\xfa\x0f\xf4e\xcfi}\x8c\xc5\xfb\x80\x99\xd2]L\xf5\xcd\x82\xed(\x17\xfa5\x8a\xe9\xa2\xf9z\x8b+\xd8\x18\xf1\n\x86\x03P\xba\x82*\xae}\xc8\xa1\x83\x90\xd2\xb1\xa1`\x1f^Y\xc8\x9dg\xfa\xfd\x99 w\x9e\xe9\x0e\xc6\x05V}\xa6\xd3\x99\xa5\x99*M\xc5%\x81^\x0d^\x18\xb9\x85\xd7&\xa4S7\xf7\xdats\xea&Zj\x8c\xa9\xa1\x96:\xc7\xd4\x95\x96\x8a\xe1\xdd\xea%q\xb9\xe1\x91\xe2m(\xfc9!\xb7W\x08vk\x97\xbb\xe3`\x7fQ\x97\x8c\xbb\xacqw=\xae\xd5\x947\xca\x9e\x84K\xb5X\xee\xf1\xd01j\x96\xf7E\xbeHJ\"\xb3%\x01\x0f*N\\^_\xd8\xc8|A\xa8Z_\x88YV\x8d,\xbf\x90\xf0\x93\xd6\xec\x8ao\x0fw=\x08ZK\xe3=_\xa62\n|c\\9r\xcf6\xfd\xbc\xd8\x9d\x8b\"\xf4\xc1>\xa4n\xc6\xdd\xdbh\xd7~\\\x81P*)\x18/\xf7\xf1Z>\xea\xbc\x967\xac\\\x9b\xa6\xc5z\xa6\xc3\xea\xc1\xe9\xb4T\xb1\x1cVE\xb5\xca\x96j\xe2a\xd5\xe0\xfa[\xaa\x98\x0f\xab\xa2\x82\x8fFn\xa3\x8a\x81\x8235\x05\xf2AV\x0d\n\x89\xfd\xecu/\x95e\xbf|\xce5\xaeG\x88nF`\xb4%\x13}W\xb4arq\xaa\xf49F\xb4v\xbf%T\xe1\xd8\xf2\xd5\xce\x90Au\xf2\x0d;\xdc\xb9>\x1e\x82\xe8[\x97x^\xcdJ\xc8x0l\xf3f\xf0\x03$o<\x94i\x91I\xee\xd2I\xb6\xb9y\xe5]\x19\x07\xcf\x8d\xf2\x90\xd7\x16\xf4\xa8\xa6_?h\x02\xccr\xfb\xfaZ\xb45\xb4\x0d\x1a\xacIQ&\xdc\xef\x92PE\x92IA\x92\xc5\xe4\xf3\xd9\xd4u\xd6;\x81\xe3u\xe7\xd8e9\x9e<\x11\x02:s\x8eW,\xcf~\xcf\x85cF>\xd3\xcb$\xd2n\xb1z\xf4u\xfaUX\x18V\xad\xd5X~\xefDa\x9a\xde\x84\xd1'\xa7\x92\x1eb\xf8Y\xb8!\x8aZ\xcb\xef-\xaa\xc5ka\x07\xc7c(\xb4\x94\xb3\x8de$\x8e4\x06F\x92\x0f\xa2\x85\x9d\x1e+_\x8b\xc2\x97|$*\x08\xe4LZ\x8d}\xa0G}K>\xed\x1a{ie\xf5\x11\x1aT\\]\xdb\xa2X&\x1f=\x10\x89\xfat\xe9w\xc9\xe7Q\xbbjU>\x93Ooo\x9f\xffk{k\xd5N\x93OW\x87\x07\xd9b#.D\x12SRS\xee\n\xb6\x90\xb3 \xb9\xb9B\xc8\xd0\x9e\xdc \x1e$\x93ps\xf3\xaaa\x8d\x10\xf6D\xe5\xfd\xe6YQ\xcd\x03zt\xfd\xbf\x0e\xbd\x81\xd68<\x14\xe3\xd5hL=wU\x07\x89\xdf{f\xcdx\xbb\xa6\xb5\x89\xcc/\x84\x97E\x93<2\xe9;\xb2\x92\x0c\x91\xe0$\xbb\xc2s(S\xfc\xc2u\xd9\xb5Y\x84\x10y\xf5]\xa9F\xfe\xca\x83i\x91/\x00\x9d\x83\x85i\x9aG\xca\xcf\x0fY\x19NI+\xe1\"\xcdo\xb5#\x81\x91\xa3n\xe2\x16\xdc\xa7\x0c\x0d*w\x94\xa1\xe7C\xe2\xe6<~b\xc8\xdb\xea\xa7G\xf0h0x\xce4\x1f\x0c\xceA\xe34\xc8rq\"\x88\n\xcc\x94\x8biRX\x0f\xf9\x1c\xdc\xb3\x8b\xbdg\x97\xd6\xc5\x8e\xeeI\xb0j\x9b{6I\xae\x0d\xc1\x14\x98\xc2\x05\xc2>\x14\xc14\x91Z\xc1\x8c\x86\x13\xaf\xcaoT\xb07\x8c],z\xaf\xf2\xe9?a\xec\xf5\xd2\x98\x16E\x01\xbe\xff\xc2\xce\x15\x01\xeb\x81`G{\x05\x87\x83h=u#e\xee\x8b\x97\xdf{\xae3\xcd\x8bq\x18\xcd\x9dA\xa8\xa8O\xe3\xf5\xd9\xaeY\x10\xf1\xcc\xe2\x06r\xf7\xb5.)\x10\x82\x88W\xaa\x18\xd7\x1dL\x8c#R\xc3\xf8$+T\xcfL\x8d3\xdb\xbaC\xfe\x01\x9e6\\\xe5n4\x84\xban)\x9c\xc3r\x97\xb1D\xb0/\x0c\xc2\xcb\xc6\xd1\xf5T\x04\x8c\x94\x8c\x0dFO[\xa1I\x13\xe7\x0b6\xd0n\x08\x93\xc3J\x7f\xd3\x89\x1c\x11\x93KI#2\x04\x97\x92v\xebx\x9e\xcf\x0d\xe1\x1b\xa3\x82Z\x91\xc6\xe0\xc6\xb0\x19\x96%kgP\xc5\x9fI\xfbs\x1d\xa2G\x8fK\x0c%\xdb\xfen\xee\x96\xac[ld\xb5x\xf6\xab\x17\xcc\x86\xf2\x83b\xa9|\xdd\xef@u\x0di^\x15\x945\xf1@\x06\xe6\xc5I\x1b\x8b\xf3LY\x1c\x86\xceh\xa5\xec\x03#H\xc4=\x88\xf8\x8e\x16\xe8\xcd\xef\x19\xb7qS\x1a\xe5\x1fqA\xd3\xba\x0f\xca\x17\x0d\x18$ \x945 \xac\x0c\x80P\xb6\x00\x01},\x98\x16\x1d\x05\xd3\x86%G\x9bd\xc3J7A\xc1\xa0\x01\xa4\x82B\xa9\xafv*V;\xf5D\x0c\xbd\xe8~(\xa9\xc6\x12\xadp\xb9\x02I<5_\x01={f2\x18\xcb\\\x8b\xb0rwW\x17nrt\xb7\xfbB\xc7M\xdc\xa7D[R\xa9\xaa\xbd\xb8TS\x82\xd5\x87\x88\xbe\x05\x97&\xb8\x8e}\x98\xfb\xb0\xf6a\xe1\xc3\x0c\xf6`\xa9\xaa\x89\xdbhU);n}dD\xa5Y\x94w\x87\xc2\x06\xde\x11\x06\xd9Oa\x04:\xbae\xcf\x0d\x92\xe0\xcd \xb6q\xc6\xb3\x1e\xe3\x8e\x84r8i\x99v\xb0\x1a\x13wf\xd4\x19E\xba3\xe6\xa6\x072F\xef\x1b\x88\xe1\x0fp\xf3\x06n67\xcd\xd46\xab\xd1]\x08G\xacwn\xe8\xce\x91T\xbd\xb9\xf2\xf0\x8em.\xee\xd8\xee\\L\xf3P\x06\x81\xb7_\x0b\x1e\x0b\xb2\xba\x9a]4!\x1a\xcd\x7f\xcd}\\\xc3\x1eTq'\xde\xc0\x066\xb9F\x8e\xc3\xf5\xbc \xce3b\xb8\x14\x06\xb5\xb3\xb9\xbb\xf6\xe1\xce\x879\xb7\xc5\xe3w\xc4\x03\xba\xf6\xd5\x0b~<\x1f\x1f\xfc\x99\xc7j\xa5\xc1\xf9\xf8\xf2\xc3\xf9)\xec\x89\xdd\xf6\x8d\xe7\xb3\xd5'u\x11\x1c\x8d\xdf\x1e|xw \xfd\xfe\xa9ww^\xf5\xf8\x9d~)\xfcL\xbf\x12\xff_\xdf\xdb\xdf\xb4BR<\xb7\xdcm\xec\xe8\xdb<1\\\xf1\xdc\xdf\x94\xd1rH\x85Fm\x8aD1pD\xee\xc5\x0d\xb1\x18\xddd\x83\x00\xad6a&\x1f\xec\x96\xd6+W\xa8\x869O_\xeaGCU\xcchc]}\xb5-\xdc\x0e\xa7}\xd9\x7f\xdep\x05\xa7\x07\x82\xc9\x8cxp\xf8\xda \xb39FQ\xde\xe2(\x10\xa6I\x16\xa6ig\xd7:;\x0eP\xb9&\xeb\xcf\x08r\xa4Q\x9a\x97b\x00\x9d\x05\x9aF\xe6\xdcu\xc5\xe0\n\x86\x0c\x0e\xba\xe6\xde\x93\xa8\x15{\x1a@\xba\xd2\xb0\xd9)\x81d-\xb0\x11s\x03a\xdbu\x8b|V\xed\xab\x05\x90\xd8\x81\xfb\x83GM?\xae\xff\x93U\xbcNh\xe7u*\xcffA$\xa0\xf8\x80\xbaa\xa7+\n\xae\x01\xd6\xa3T\xc5\x88,\xe7\xc9\xdfV9}\xd3\xe1\x8b\x83=7\x05 ?\xd9\xb3\xf0\xd6^\x0di-\\,\x1f\xa5\xb1\xd7C\x1a\xfb\xb7\xcfO_>Fk/:\x14\x0d\xa1j-}\x94i|\xd1\xa3b\xc8\xdb\x9a}k[\x83t\xd8\xa2<\xa3I\xb6j\xdf\x0c\x81\x95\xc5\xe3|0j\xf6\xbb l2\xfcX\xaen\xf8\xb5\xb5\xbb\xf2!\xf4\xe4e>\xe3@\x19+\xbc\xa9#:s\xe5b\xaf\xca\xfa\xf7Y\xc9v\xe50\xd2C\x0c<\x92\xbaH\x83\xea2\xfa\xa67\x851\x0b\x852\xb5\xd9@\xaf\xcd\\\x96\"\xbf\xce@ [\x92\x96FId\xb8\xb5\x9d\xa2p\xa1\x99\xb6l\xa3\xabvx>\xf6\xd0|yp\x93\x17t\x04N\xc8\xfe\x1b\xd0\x1f\xcb\x92%\x0b\x0c\xe11\xce\xe2\x11\x94\xae\x13\xca\x04\x92\xc5\\\xff\xb9\x99\xd4]\xcb1%<\"H\xb3\xaeD&\xeb5\xd6\x1f\xba\xeb\xbd\xa0!\x1b\x89Zg\xc9\x92\xf4\xfax\xa2\xb1\xae\x1f\xd3U1\x02\xe7&]\xe9&\xed\"\xc3a\x98\xbdO\xc3\xbb\x118Q\x98-\xd3\xf0\xae3\xdb\xe5\xbc\xc8W\xb3y\x9d\x9b\xf2\x04K\xa1y\x98\xcd\x08\xcb\x8c?,\x99RT\x01w\"\x8c e\xce\x92/\x96y\x99T\x0b\xe6Du\x82uu\x94Bb\x1e\xd5b\x1dS\xa6\x14\xfc\xb0\x8cQ&\xa0\x96\\a\x9a\xadhF\xc9gzB\xb2\x15\x16\xc2\xb7\x05\xc9V\xb6\xecK\x9c\xf8|i\x9b\xf5\x15v{e\xe9\xa9\x12\x1ek\x04N|\x93v\xcc\xe1Q\x11\xceX\xa6\"\x9c\xd93\xf0\xd9ey\xac\xd3\xca\xb3QRT\x19)\xb1\x80\x16f\xfd\x9cP\x99\xf3sb\x1bG\x11\xce0\xc0\xa3\xc8\x99\xb2\xdf\xf6\xacg\xeb\xaa\xf5|\xdd\xd5\xb8\\w\x96\xb3c\xc1\x8f\x8a|\x89\xb9\xf2\xa5%\xc3\x8ao\xd7\n\x9ec\x91\xd0\x05\xd7\xe3\xc5\x92&\x84\xcd'\xe1\xbf,\xd9\xb2\xa8\xb8[R\x9eQ\xfe\xb6e\x8dE\xb6\xd8\x9a\xa5(r67\x84\xfd7gy\x9bG\xabr\x04\xce\x94\xfd7g9\xce\x96\x08x<\x02\x981\xcb\x9f\xc9\xddQ~\x9b\x8d\xc0\xf9D\xee\xe2\xfc\xd6\x82\xca\xfeL\xee\xde\x17\xa4,y\xbe%\xfbi\xcd\xf8a\xc9s\xad,\xab\xf0\x0e-\x93\x19\x0f2\x92f\xca\x8cs\xe9\xca|Bh\x18\xab\x05\x16\"\xc1^H\xc2\x0c\xcb\xdf\x013U\xe0\xb8\x118\x0b\xf6\xdb>\x07U\x108\x99\x95qW\x1dY\xcfp\xee1gn\x9b~\x9e\x91\xef\x03\x9e\xd3\xba\x11D\x988\x99\xd16\xbb\xef\xc3\x121\xdd\x92\xfd\xb7eY\x95<\xcb\xaa\xb4e\xe1G\x89\xfd\x1ca\x19\x92l&\xf2$\x99\x05\x19\xbd/\xf2\x99\x80\x9b\xa5\xf8i\xcex\x1eRRm\xcb\"\xa4\xa4kKr \xdb\x08\x9c\x12\x7fX2\x11\xf2 \xb7Y\x89?\xec\x99\xf80J\xfe\xcb\x96-\xe5\x91=\xab.\x962\xa5\xb3\x9f4LS\xde\x07\xfe\xcb\x92mU. b\xec\x92\xff2g\xbb$\x9f\xa9\xdc\xd1T\xfe\xb6dM\x16\xa4:\xf3h\xb2 ]\x87\xdde\xbe\x8a\xe6\x87a\x16\x116\xa5\x94\xbdE\xf8\xd6\x91\x9d\x1f0\x98\xd7\xde_\xf6U\xec\x17\xcci\xdf/\x98U\xeeX\xcc\xdb\xb1e\xf1\xda/Q\xa9>Z\xa5\xd4d_3\xcdX\xd1\xcfy\xbaZ\xd4P\xb7\xc6\xd7\xae\xf5\xfc%L(\x87\x96[\xfe\xcb\x92mNp*o\xd9\x7f\xcd\x04\xb4Y`\xcex(\x1e\x85\xa6\n\xa2w|\xe4\xc0\xa6\x90\x18\xb9\x8d8\x04^P\xa6ID\xdc\xa7^\x93\x1dX\xa3j\xdb?\xbe\xa2VE\x93\x94>'2\xd2Z\x1d\xa4\xb0}\x990 p\xad\xa9\xa2~\xf99:\x8f\xf9)\xcc\xe2\x94\\\xe6\xcbwdMRw\x1d\xcc\x1b \x9e\x0f\xeb\xa0]=\xec\xf5{ll\x8e\xa2$t\x9ca@\xcc\xbe\xae\x19\xdb{\xf2\xc4\x98\x1e\xd4\xd5\xb6\\\x01j\xb3X\xb6\x9b7\xb5.5\x88\xdc\x0dc?\xbe|\x01\xe3\x87\xa0\xaa\xdf\xed\x0e1\x97b\x81\xcb|\x80S\xd1\x86\xa4\x98\xfa\xd0\xed;O>b\x00=j}\x95\x16\xde\\D\"\x99\xcc\xaf`\x0f\x96\x9b\x9b>D\x13\xf6&\x82\xfcV\xaf\xed\xe5\xe6\x11 `\x0f\x92V\xc0\xc6#\xc20%\xc9\xa2\x84\x94\x13r\xd50f\xcb\x87\x08\xb3P\xcb\x9d\xed\x1c\xabu[\xa1\xc7\x99\\\x89X2+\x1e\xa7\xd8\x91{\x9d\xcb\x86Wht/v\xbd\x07\xfbfp\xa2E\xb8\xfcqu\xc3\xd6\x11?(\xb5\xf8\x12e\x08\xb3\x9d\xd4\xe5G\xfd7\xd5\xa8\xd4 \xaa}@%Gg'H~\\\x88\xf3\x96W\xe4TGqc\x02\xe4\xa1\x0c\x1b;\x9d}\x16\x01o\x95\xf6\xaa\xea\xeb:\xee\xd9cC\x0d\xc6\xc2\xbf\x1c\x9f\x1e\x9d\xfdr\xfd\xd3\xc1\xe9\xd1\xbb\xb1\x1c\x0bR\xd4r(x\x86p\xbe\xbb\x1e\x9d\x9b\xba\x92\xde\x16\xa3s\xef1\xbc\xb7\xa2dUEf\xc1}\x96\xf2\xd8\x17_\n\x01 \xf3\x04\x90`uI\xe6\x08\x15\xd7\xc1\x93\xd5\xecO\x92\xf5\xf5\xa8U\x81\xec\x10\x96G\x1a\x97u\xca\x87\"\x10\x1f\x85N\n\xbeck\x98\xc0\xba\x1d\x9b\xf7\xd6\xb0\xb6W>\xc4\x93\xd5\x15\xef.n\xc7\xbdVHy\xe8;.\xf4Z\xfb\x03\xd5\x80b\x867\xa8\x9f-\x85bK7\x1aK\xfd8\xfdhB\xcf\x90\x8e\x88\xc86<4\xe9\xfbpF\xfe\xf2k\xcfA\x86\xb7\x17\xfa\xad\x1e+\xdd\xe9Kz-\x9c\x86\x9a\n\xba\x0e\xa2\x19\xfcm\xd2\xe3\x92\xf7$\xaa\xd3\x06UQ\xa0k|$+W\x85\xc0`?\x87\xe9\x8a\x9c\xe4YB\xf3\x02 \xba\xdeq*\xae.\x90T\xc0K\xdcu`\x984\x97\xed\x80\x0d\xcc\xb41\xed:|\xd8$\xac\x82\x82L\x0bR\xce\x95~\x95\x96\xfb@\xd3R/\xf8\x18\x94\xd2\xe8\xebzZ\x87\xecR\x1fm?To_-\x06\x08\x83<\x904\xc5\xd4Ur\xa5\xd1P\xb4\xe6\x94k\xb4^\x17\xab\x94\x94\xd7\xd7\x0d\xdd\xf0\xeb(\x8c\xe6\x04\x13-\xd7\x8b\x85Bp\\_O\x93,\xc6\xdcv\xaa\xa5\xad\xf7W5-\xc8\x04~\x8d\xb7\xb5\xfb\x06\xa8\xd5\xb1`\xb3\xe0ds3\xbbB\x85\x01\xae*s\x0fO\x83\xbe6\x82(_,\x93\x944\x07a\xbaB'\xa2\xfb\x06\x96\x83M\xa1\xe3hT\x0cQ\xc6)\xecI\xddn\xda\x8e\x04\x84\x13\x98\xfc~\xe3\xf5\x18\x07\xa8\x95\xa2\xae\xfe?\xd0\x07q\xaby[ OY\x92\xc7\xda\xe2\xae\xf3:\x86oD\xa9\xec\xc9\xd4)p\xd1!X\x86\x13!\x07G\xf9\xe0\xbe|\xd1Z\xe5#\xcd\x82if\x88M\xdd\x1a\xad\x0d\x1cB:\xd0\xf2\xa5\xa8a\x99o\x01\xa3\x11\x1a^\x12\xb1\xbe\xea>\xa3\x19Doq\xb5\x81B\xb5\x8c\x16V\xd1\xef\xc3\xa2$\x05\xb0\xe9C\xc3\xb2i\xbeB~\x1f6A7K\xd7\xf6Eq\x15L\xa5\xf1g\xebK\x98b$c\xfc\xff\xe5\xcb\x90]\xdf\x9c\x9d\x1b2\xcd\x0bb4\xf7k\xb9\xb1ZK\xcfx\xbd\x93\x94Hm\x9c\x8eI\xca\x1fs\x92\x82r\x89l|\xee\xc3\x8e\xc9\xf5!C+F\x13R\"\xd9K\x93C\xc4if4/\x0dS:\x82\xa4\x9e\xf2\xd6\xb6\xbb\xd7\n\x84SJ\x8a\xff=\x0b\xc0o~\xff\xa7-\x02\xc34\xf7@\x13F\x04\xa0M\x08\"/\xdb$\x18T[z'\xc10q8 \xc5cM\x02\xefA\x9f\xf2\x17\xcb\xd0\x0cJ\x8b\xae` \x8c\x00e\x06\xdc\xe3cs.\x86\x1dy\xf5Y\xd9\xd2\xa0\xe7\x87\xd9\xb0j4\xba\xa4\xda%fU!\xca\xce\x1e\xc3N8g]\x87E\x98\x853R\x8c \xc9\xd6a\x9a\xc4bg0\"\xc5\xb4'\xa0\x8d\xbd\xe9\x95:*=\x84\x13\xe6\xbe\xef:\xc5I\xd9Z(}\"\xdc\xeee\xf2\xfe\x17\xcc\xe5\xeec\xcc\xe5\x8cP\xde\xbb\x01jo\xc2\xcb\xc1\x9e\xdeB\x0d\xef\x15\xe1\xe9\xb6\xfa1!W\xda\x1e\xfd\xea\xdf\xdf\xf3{\xbf\xbb\x93\xce\xbd\xbb\xe6nC\nn1hq\xd6\x8e\x16\xc0\xc12/O\xc2\xcf\xed\xaf+\xf9\xb5\xfd\xa9\xc4OIy\x9c\xbd\x0boH\xda>x\x94\x8f^M\xc7\x9b\xf2\xa5,\xcf\x87l\x11\xd2hN\xe2\x8b(_\x92\xb2\x8e\x0dj\xfc\xbc\xb5\xe5\xb7*C>\x05{\x8bf\xf5x4)\x9d\x10\xa2\x14F\\\xed\xbe\xe1\xa3\x82\x1f 4z\x9ag\xfdz\xcd\x0fN7\x07\xa1\xca\xaf\xea\xecaq\xcf\xf3 \xdb\xdclCr\x15\x82\xfb\xf53\xe1\xdb\x11\xbd\x04\xb2\x9f[[V\xd2\x99\x0b{\xcc\xbc+\xea\x80\xb5\xbe\xb4u\xabP)\xb7$EP~J\x96\x97\xf9'\x92\xd9\xc3\xef\x80\xa2\x11\x0f\xfb\xdc\xc5\x19_l\xcb\xa4\xc3\x1e\xf7\x0cb\xfd\x9a\xc1\x16\x9ft\xbe\x06+}\xfeK\xff\xe1a\x15^\xdb\xa2`r)\xba\xeb\xfc\xdd\xf1\x8cq\xa5\\%\xb6r\xa7V\xaa\xd4w\xbd\xa8=B\x15\x02\x8f\"\xc1C]\xc7a\xc3\x17\x0d\xf6j\xa3\xa9\xf5\x0f\xd3\xb8m\xc8IL\xa1H\x9d\xc30\xfb=\x85(LSX\x10:\xcfc\xc830b\xd4\x96\xcb\x8d{\xcew+&\xa20S\xd8\xf5\x02)x\xd2no\xd0a\x87\x08\xe0\xe2\xe6M%\xf5^\x1f\xa4\x96\xc5H`\x1f\xb4\xaa\\\xf4:\xaf\xd8\xb1\xdd\x7f`}\x9d1 S\x14\xd5\x15jD8\xcdW\xb8\xc0\xb6y\x1b\xc1!\x8dd\xf2\x97\xedr\xedt\x19\xae\x9c\x87]+\x10\xe1\xc8\x18\xd3^\xdd\x9e\xa1\xe6\x8eJ\xd1?\xc7\xd9\xf4\xfeun\xfcs\xbak\x83\xe4<[\x93\x82\x82p\xfbKsX\x16\xc9\"\xa1\xc9\x9ap\xefON\xdf.\xd3\xd6\xb9\xe9\x0c\xec\xfb\x9d\xfb\xfa\xe5\xd0\xadpd\xd4w\xdd'\xb8\xf0\xf4\xf5B\xd7\x1f\x0dE\xfa\xae\xe7:\xc7\xe3\xeb\xf7\xe7g\x97gz\xd0\xd1U+jA\xe3s\xd9%\xc8\x02)\xcc\x12\x8e\x99\xdc\xdd\xef_x\xae\x93L\x8bpA\xf4\x86\xe4S\xe0\x05\xa0\xcdS+\x8f\xc2\x12\xa0I\x10#7\x97ix\x07{\xe0dyF\x1c\x1f\xa3R\xecx\x0d;\x17\xee\xa4\xb0,\"\x96\xed\xaf\xe1:\xe4VE#\xc7\xe7\xa4(\x0dP\xe3/\xa3\xbf$Y\x9c\xdfV\x08\xc3\x0b\xf2%\xc9\\\x1e*\xa0H(q\x9d\x1fx\xd1?T\xc2\xec\xb7{\x1c\xbf\xfe\xf0q[|r0?\x1a\xbc\xba\xc2\x95\x14 \xde\xbe\x81bk\xeb\x8d\x07\"<\x8b\x12oe\x92L\x8a+\xc3\x8d\xa4\x00\xcc\xd2\xd5\x0e\xc4\xaecE\xa0\x1eP\xa3\xb6Zi-#\x02\x16\xa2v\xe9.Kq\x8e\xcf\x8f\x17N\x91\xa0\x03t\x1f\x9a\x9f\x85\x93\xd3I\x88n,\xd1\xfe\x04=\x9fka\xd4\xa5\xe3h7\xfb\xff^D\xfa\x17O=\xd7\xf9D\xeeJs`\xdf\xdd\xdd\xfe83\x96\x8e\x17\x82\x86w\xf1\x07w(\xf9\xe0~>5\xd9$\x17\x13\x871\x11\x05\xd9\xfaky]\xce\xc3\x82\xc4\xd7\xd7\x8el\xd4\xfc\x0d\xef\xfb\x1f8\xa2\\\x8e(\xe7#\xfa\xc7\xd7\xbe\xf1\xd8\x10\xab\xa38\xd2\xf7\x9b\xd7\x90~R\xbe\x97 |6\xf5M\x04\x99O\xf3wy\x14\xa6\x84\x9f#\xbe\xe4\x9e'\xb0u\x82~\x07\xd1\xa1\xacsVG]B\xbb\xb2\x02\xcd\"-T\x18;\\\xc34%8be\xe9F\xc2\x12\x19\x1e\x008\xde5#8773\xd8\x84\xc2\xab\x18\x13F\xc4\xf7\x9dl\xd6\xbd\xf0\xd2\xe2\xea\xf7\xd9\xffx\xb6\xf7y\x0f\xa9\xf4\xe2\xe5C{\xfb\xa8\xa4\xd2\xee\xeeK/\x98\x9a\x899\x93\x07\x17\x13\x9e\xea\x1b\x87\xf9\xbe\x07\x95a6r$V3!='5A\xeeC\"\x03\x84\xa2\x03\xb6\xf6foz\xa25\xdd\xecH\x87\xc6\xcd\x8d~\xcf\xb9\xea\xf5\x80\xf3t\xd74\x03\x18{\xbdw-\x19#b\xcf\x04\n\xcem3X(\x03_\xf2\x18B\x82\xa7!\x0d\xdf\x11\xc6XI\xa0\x13L\x8c\xa5\xf9\xf2Eu\xd4\x9e\x19$a?\x86\xb1\x8cW\x04\n9ju\xcf\xc7=)g\x95\xec]}\xaa\xcb3\x11\xd5J\xa0\xd1*\x11e\x13\xe8\x8eVc\x1d\xbf\x81uy\xfa\xbdY\xd4\xf0\xbdM\xce\xd9\x07\xbe F\xefd\xc8\xbf5W|k\xfc\x9b\x03\x9b\x90\xa1\xbf\xdb8'e\xf6{\na\x14\x91%\x85\x82\xcc\xc8\xe7\x96\xd3[\x01\x11\x02\xa9~\xdb\xa6f[\x14\xa5\xc5\xfd\x9b\xd3x\xc6\xc3\x1el\x07\xdb\x9aH\xc9x\xe2:\xdb\xc1\xb6\x03\x13r\xe5jnu\xaa\xa3\xd6(\x80\xef=\xbe\xe9\xa4\xb8\xe2\xf6\xb8\xb0am\x03z\x8et\xd3\xfcn\xdc3\xe0\x11\xc5\x8d\x8c\xb4\xfd\x90\xec=L(\xb27F\xac\xda2Q\x16\xa2\xad\xd6 \xc9M\xa0\x9f\xefx\xc1\xf4\xa1k\x9b\x07\xfc\xcc\xe7\xec\xa9|\xe1\x81\xa1\xfe\xf1\x15\x83.\xd4\x19\xfe\xa1Gtq\xae\x91\xc4!xAs@\xdd\x1d\xd4\x97'\x90d\x1c\x93\xac0f\x95 c\x0b|\x1c\x06\xd3\xd65I\x1f\xac\xb7\x97DH\x8cf\x84*\xfc0\xef\xb6\xd9\x8d\x07\x0fXz\x7fT\xdf\xa1\xcd\xb5\xfd\xddFs\x90\xdf\xc1\x1fc\xc2\x05iI\x9e\xc19\x89VE\x99\xac\x89\x94\xb8\x92\xcf\x94dq\x92\xcdZ\xc5\xc2\x15\x9d\xe7\x05\xfc\x9c\x84\xd1\x9c\x94i\xb8\x86w9-\x17a\x96\xaf\xe1\x87T\xfe|\xf5\xfa\x8f\xb3E\x98\xa4A\x94/\xfe\xd0\xaa#M\"\x92\x95\x04N\x8e/\xb5oz\xd6\xcb9\xe6\x82w\xa2\x84{r|\xe9\xf5\x949\xcc\x97wE2\x9bSp#\x0f\x9e\xee\xec>\xdbz\xba\xb3\xfb\xca\xd8\xe5\x9e\xaa\xde\x93b\x91\x94\x18\x14,)aN\nrs\x07\xb3\"\xcc(\x89}\x98\x16\x84@>\x05\x06_3\xb6L9\x84\xd9\x1d,IQ\xe6\x19\xe474L\xb2$\x9bA\x08Q\xbe\xbc\x83|\xaaW\xcf\xce\x11(\xf3)\xbd\x0d\x0b\x02a\x16CX\x96y\x94\x84\x94\xc4\x95\x1e/Zf\xc04II .\x9d\x13p.D \xc7\xc36c\x12\xa6\x90d\xed\xca \xc8\x9cp\x9b\xd0y\xbeb(\x9d\x83M\x92g\xbe\xf0s\xcdz(?\xa7\xc9\"\x11\x0d\xb2\xe28\x8b%\xd0\\\xaf{U\x12\x1f\x07\xe5\xc3\"\x8f\x93)\xfbOp\x0e\x96\xab\x9b4)\xe7>\xc4 k\xe9fE\x89\x0f%K\xc4\x05\xf4\xd9(\xb7\xf3\x02J\x92\xa6\xac\x86\x84\x94\xc6\x89\xa9\xfb\x8eE\xf0\n\x80-\x06\x15\xd3\xcbz\x05\xb7\xf3|\xd1\x1cgR\xc2tUdI9'X&\xce\xa1\xcc}\xbd\xfarU\xdd+\xb0\xd2\xd3>\x1a\x1f\x81sp\x01\xc7\x17\x8e\x0f\xbf\x1c_\xfet\xf6\xe1\x12~98??8\xbd\xfc\x15\xce\xde\xc2\xc1\xe9\xaf\xf0\xe7\xe3\xd3#\x1f\xc6\x7fy\x7f>\xbe\xb8\x80\xb3s\xbd\xe6\xe3\x93\xf7\xef\x8e\xc7G>\x1c\x9f\x1e\xbe\xfbpt|\xfa'\xf8\xf1\xc3%\x9c\x9e]\xc2\xbb\xe3\x93\xe3\xcb\xf1\x11\\\x9ea\xfb\xa2\xe6\xe3\xf1\x05\xab\xfbd|~\xf8\xd3\xc1\xe9\xe5\xc1\x8f\xc7\xef\x8e/\x7f\xf5\xe1\xed\xf1\xe5\xe9\xf8\xe2B\xaf\xff\xed\xd99\x1c\xc0\xfb\x83\xf3\xcb\xe3\xc3\x0f\xef\x0e\xce\xe1\xfd\x87\xf3\xf7g\x17c88=\x82\xd3\xb3\xd3\xe3\xd3\xb7\xe7\xc7\xa7\x7f\x1a\x9f\x8cO/\x038>\x85\xd33\x18\xff<>\xbd\x84\x8b\x9f\x0e\xde\xbd\xc3\x96\x0f>\\\xfetvn\xea\xfd\xe1\xd9\xfb_\xcf\x8f\xff\xf4\xd3%\xfct\xf6\xeeh|~\x01?\x8e\xe1\xdd\xf1\xc1\x8f\xef\xc6\xbc\xe5\xd3_\xe1\xf0\xdd\xc1\xf1\x89\x0fG\x07'\x07\x7fb}?\x87\xb3\xcb\x9f\xc6\xe7\x98M\xf4\xfd\x97\x9f\xc6,\xa957\xa7pp\n\x07\x87\x97\xc7g\xa7l\xcc\x87g\xa7\x97\xe7\x07\x87\x97>\\\x9e\x9d_V5\xfdr|1\xf6\xe1\xe0\xfc\xf8\x82\xcd\xde\xdb\xf3\xb3\x13\x1f\xd8R\x9c\xbdeY\x8eO\xdb\x9d>=\x1d\xf3J\xd9\xaa5\x17\xf7\xec\x1c\xdf?\\\x8c\xeb\x9e\x1e\x8d\x0f\xde\x1d\x9f\xfe\xe9\x82uH\xcd\xacC\xcdv\xe3]\x9e%`!\xf7\xa5\xf4\x02\x92\x8c\xc1g\xc4\xe3\xfc\x8a\xf3\xb5J9\x12\x97$\x8d\xc4s2\x1b\x7fn:\xf1S\xe2oAS\xc7\xdd\xd88\xea\x874Z\xb6q\x10R&AE\x04\xaa}\xf9\xab\x0e\xca\x00#dI\xa8\x12\xa6\xc1XU\xa5x\xc26<\x1a\xd0\x19\xbc\x92\xf7w\x95M\x89\xa7\xb2U,\xc1E%\xa4\xcbdA\x1a\xd2.k%|\n\x1b\xd5\xf0$\xa3ZVK\x17\xebCF>/I\xc4N\x992\xa1+\xe1\x83e\xd0\x8a\xe4VI\x97\x14\xd3\\_#o|}\xedT\xf7PUh\x99\x96\xb0\xab9ak\xe1\x94\xcbH%\xda\x00\xc1\x10\xe0h\x17\xad\xccd\xd4\xfa:\xd0G\x1d g\xe7\xaa\xd3\x96\xc6R\xefS\xaf%\xab\x9c\xec\x18\xae\x14\xe5M,7\x9e\xec\xce+*\xe4jz\xb5N\x1aZ$\xf3\xeb\xf3\xaa\xbc\x0f\xbb\x06\x9d=k\x14M\xc3\x04\xa0\xf9]%\xe0\xc4\xb7\xa6~\xe0\nidA\xb2~\"w\xa5\xbb24iu\xa1\x0f\nc\x84\x12\x9f\x90\xfb\xa2G\xe1I\xee\xa2gz\x1e\x19$T\xc1\xc2\xd0S\xd2\xe8\xa9\x8c\x9c\xeb\x86\x93\xb2\xba\xf54h6\xaay*\x90%f\xeb\x06\xf5Y\x0b\xa5\xea\xc9\xd0x\x8cm\x03\ntN\xd5\xdd\n\xa8\x8b\xa2\x85G\xaf\xee\x83\xd9~i\x8e\x0c\xa35\xe5\xe2\xba\x97\x8bw\xb3F\xa2\x90\xf9\x8a\xb7\x04-\xd6\xd5\x94\xb6\xf7-\xf5\xf9\xea\xf9\x90[s|E\xdd\x96\x11?\x06\x9a\x13\\\x88O\x86\xd5\xa3\x8d\xd5\xa3m8\xa3ze\xbc\xd7\xbc\xc2f:\x0f,l\xec\xa0!d%\x1bMhA1\xcd\x80\x94\xcf=\x11Oq\x10\xbf|\x1f\xa5K\x9b\x00\xbb\xbd\xf4D\x89\x92\xc4\xd6\xd6b\x94\x88\xcc\xba\x01u\xb4\xd4{qZ'W(\x11n\xe7\xcf\xb8>\xba\x1et\x9a=\xea\x8e\xa7\x86\x1do\x0d7,Q6\x9d\xe4\x96\xbdc\x0c\xb9\x94\x08\xffqO\x9e\x98\xa6\x85\xf1\xf7[\xbb\\\xc6W[\x08M\xf2+6\xbcb\x92_a<\xf7\xc3\xa4\x88ViX\\90\x92\xa9\x04\xb3\xf9\x90 \x97\x0e;\x08P\xe2\xa3!\x00\xaa)\n\xac!\xf6#\xe56ih\x9f(\xcc\xd3D\xda\xd0\xf2\x0bR\x96\xe1LV!\xdf\xf6\xea/C+*i\x18}\x12\xd5\xf0\xdf{2\xd5P\x85\x14\xc57w\x04\x03\xf0 \x06\x922\xde\x06\xe1m\xca\xe4\xad\xf8\xc2-?\x84\x1f_\xe0~\xd5\xf2\xecn\x91\xafJ\xc7\x83Mpp\xfe\x1f\xacP\xf8\xfd+\xf35\xe3\x0bc\xc8#\x96n\xf2|\xcc\xd2\xf5k\x80\x95H\x7f\xed\x99\xcc'K\xbb\xd8\xc9\xa4\x10\x8d\xda8J\x84\xbb\x1d\xae\xf0j\xd0\x9d\xe2zS\xdc\x19? \x0b\xd7{\x03\x9b\x9b\x14~\x80\xcc\xa8S,g\xa2\x1do \xa4\xec\xbc$\xd4-0\xfeW1\xd9\xbd\xb2\xe9\xed\xd6\xbf\x14\xa5'\xde\x07\x86\xac\xfdF\xb2P\x8f\xc2`\x1ceS\x15\x9em\x94f\xe2{\xe9\xf9\xe0\x9c\x84K\x9b\x10x\x90V\xbc\"Un\x85\xd0\x13\x10e\xf1\xea\xf8\xc2\"\xd2|\xd1\x12\x81\n\x88\xda\xd5E\xf4\xa5H\x7fi\x84\xb4\xd4\x0ei\xc2< \x0ei\xc8\xad\x140\x1a\x99\xd1\xca\xaaL\xfe\xce\xf1\x05\xfbaX\xf4\xd4\xb0\xe8\xb9\xdfH\xae\x16=i\xa6\xf3E\x0f\x9b\x89|\xd1W\xcdD\xbe\xe8es\xd1S\xe3\xf2\xa8C\x1e\xacN\xdb\xf0\x9b\xb2\xb5\xcb\x1d\xa7\xd0\xca\x9c\x98\xeb\xdcK\x1f$\x9b\x9b\x19\xfc\x00\xc5\x1b\x0f\xc8$\x87M\xc0\xf81\xed\xb05\x92o\xd3\xe6l08\xbdx\xaa#\x1c\xa1\xf2\xfcZ\x07\x1bcL6\xa3\xaaS\x0b\xda\xba\x84\xc4m\x18\x0c\xd5\xe0\x8a]\xec\xb9\x8a\xb1\x90,@B\\Q\x1e(\xdc\x90\x1b\xb6[E\xc7Z\x8dj\x10\xb8V\xbe\xaf\xba\x03\x1dF\x83\x9a\xf7\xf4\xea\xbe\x8b`>%\x9e\xebkcZ\x83\xf6t'\x9a\x97\x8c\xf6\x14'\x03\x16\x0eq\xd37\xaa\xb6\x08u\xc7A\xab\x99\xb3\xaf<\xe8L\x15E\x15\xd56\xb8\x87\x92\x8dU;\xbd\xd9\x9ey)\x06!\xed\x0e\x1b\xb1z\x95\x9e\xe9\xab\x015\xf2m!e\x90\xbaB\x16\x8e\x08\xffl\xd0 \xcbcry\xb7D\xd2\xc9d\xfe\x88\xf7Af:\x92;\xa4\xc7zH\xa3\x1e\x83\xe9%\xdfW8\xbb\xd5\xd4\xec\xf1\xab&\x19t^\xb0&&\xbf\xe0l\x1e\xdd\x15\xec\xc3*HJ-7\xb2\xd4\x9a\xde{{\xfeAgPv\x9f=\xf7\xaa\xcb\xd5!z7\xafwv^\xee\xbe~\xfd\xf4\xfb\xe7/\x9f\xef\xbc~\xbd\xfbP6\xc5\xe4\xbf\x1d\xe7\xf1\x0f\x8c(\xc7_\xff\x81\xbe\xf1\xb93\x02\x02?\xec)\xa2\xb0\xfek\xb1{\xf5\xa6\x1b1I\xdc\xde\xba\xd4\xed\xe9\xceC\x80\xfb\xe9K\x9d\xc0\x04\x01\xdd\xdf\x08\xc1l\x13\xe4\x8f\x00\xc1\xd5NH\x1a\x10\x8cU\xa3\xb9cDJ\x83\xc5\x9env\xd0\xca\x00\x9d\xf7\xe0 \xe5]u\xeb\x05\xf9\xdb*)H\xe3\xc5uV4I\x1d/`\x03\xb3xb\x01U\xae\xfc\xe5\x8b\xdc\x8e7 \xdeD6^du\xc6zz\x02[}u=\xfbf\\=`3v(W\x99\xaf\xd6[FT\x0c\x04\xb6?\x06_>N\xdc\xfd\xd1\xe4\xffL>^]}\xf7\xc5\x9d8\xbf\xbf\xf2\xdc\xfd\x91\xbb\xbf\xf1q\xd7\x9b\xfc\x9f\x8f\x1f\xaf\xbe|\xfc\x18x\xdf\xed\x7f\xdc\xf5>\xea\x81Yx\x00\x98\x8f\xb7\xdf\xfd{oH\x07\x8b!S\xc3\x8eI\x17\x8bV\x92t\x01\x98F\"k\xc3\xad\xb0\xc7\xc6\x1ed\x08\xd4%R1JB\x158B\xa64\xdc\x0em\xa0F .?\x8f\x05\xc2\xa3\xc8n$\xea\x9b,A\xf9\xf6H\xa4\xd3<\xf7^\x86\x0e\xf7BD\xf7\xa4\x1f\xcd\xf2\"A\x99pm\xd3\xcaE\x17\xf5\xc1\xb9\xbe&\xe5I\x1e\xafR\xe2\xe8\x1a B\x1bAU\x08AC\x9b\x05Y\xe4\xc9\xdfI|\x11.\x96)y[\xe4\x8b\x8bhN\x16\xa1\x90*\xf0\x8f\x87\xa8,\xf8\x97\x93w\xe3\xcf\x98\x8d\xb3\x10\xf8\xf3/\x8bT+\x94dSR(\xefe\xbbfq\x00\x824\x81i\xd4\xac(z(\xec\x98\x89\x1b\x0b\xdd\xcc}\xf1\xfd\x0b\xcf\xb0\x0f\xf0\xd3\x8b\xd7\x9e\x91\x97\n\xed\xeb\x83\xa0\x10\xd4\xf3(T\xf5\xdaXKFF\xd0\xddZ\xfd\xae\xfdk-|\x19\xb6+\xe1\xa2\x99\xe1qm\xa5,\xa7\x95\xc7\x10F\x8bg\xbd&\x8b0I\xef\xd1\xc2\xaa$\xc5\x1f _\x8c \xca\x17\x83\xda\x12\xfdb,(\xd9\xa2\xc9\x828\xc3[t\xe5\xf5\x95\x17\xd0\xfc\xf8\xe2L\xa8\x84\x19\xf8\x02\x83<\x05\xd1\xc4\xf0\xb6\x06\xc5u\xe3\x95^O\xd3<\xa4\x8f\\u\x92Q2{\xf4\x0e\x0bT\xd8G\xff\x83\xb2\xca*\xf6\x94\xb88\x10 \x8dW\xad\xf2\xa5\xdd~\x13\xdc\xdb\xbcLw'\xa4\xcc\x82mt\x17\x9d\x0frr%\x99\xdeyF\xff3 \xc4f4h3a\xf2AO6\xc14/\x16\xa1\x812\x02\x81\x12V\x13\xd4O\xbcv`\x13\xb8\xa9\xcc\xca\x18\xd5S\xc2%\xf6.)\xdf\xae\xb2\xc8s\x13\xc6c%\\O\xda\xf9\x90}\xca\xf2\xdb\x0c\xb5 \x85K\x1b\xec]\xd7\xd4\xa46\\Xa%\xcb\x0d\x93<2[7\x89\x7f\x00\xa4\xa3\x15U\xd6\xfa\x8ep\xf7\n\xf6\x9b\xaf\xa3\x96)\xa8|r\xd3RP\xcbR \x99\xd9\xb1\x14\xca\x97\"P\xe1\x8035V\xb3Vg\xaa9\xef\x1c[\x16\x00m\xce\xb26\x844\x93\xcf\xa2\xe3\xdb\x0c\xc9\xb0\xcf\x0bC\xc0f\xf60\x1c6\xc3;j\xf3\xf7\x1b\xfc\xbe,\xc841x\xb4b\xcfuU\x03F\xab5g\xba\xe5S\x9b\xad\x16\xe6\xef\xe3\x8aG\xb6\x1c\xe0a\xc7\x01\xceN\x90\xd4C\xa8\xfa\x97\x9c\xe2a\xdf)\xee\xb2Y\xbd\xc3K\xff,\xa7\xe1\x8cM\x8e\xc3\xcd\xa5\xdc\x1b\xd8\x87\x1bF\x96\x8f\xd0>\x16u\x01\xee|\xb8\xe6\xde\xd2\x17\x13\xf6\xdd\xf9\xbcH\xb3r\xc4\xce\x8e\x1b\x96 _\xd1_\xc1\xb5\x85\xc0Q\x0f\x05\xc48\x91\x0d\xf9\xb2\xdc\x11\x83\x07\xd8\x03\xfe\xff\xcb\x17\x98qK\x10\x9f\xa7HU\x0d\xe5\x85\xe5\xe1P\x023\x11\xa9>\xae\x88\xbf\xf5$\x93nn\x9b'\x04\x9e\x0d\xd3\x81ns\xe5\x13\xc9\x1d\xc8\xfd\xb6\xb2\xca\x85\xdf^v\"\xe4V\x9d\xa6\xd6\xf94g\xad\xcf\xef\xdd\xba|\xb6\xac\x8b\xfb\x8d\x0bs\xaf\xf6E\xaeV\xa6\x01\xe4\xb6U;\x91M\xfd\x85\x99\xdc\xee!\xa7\x0f\x199\xad\xec\x19\xb4$\x95\x1b\xf0\xc2N\x9d\xb2\xbe]\xe8q\n\x0e9\xde\xd8\xb8\x98\x1c*\x84\xf7\x97/\xb0T?\xd4$7#\xc6-\xd3\xd5h\x87\x95\xe2H\xa2\xfa){(\xde\x03\x06\xb3h\xa9\xd2\xb5l\xf2a\x03\xff\xd4R\xbc\xc3\xba\x90Jc\x9d\xad\xde&;Wv\x96E}\x0ed\xff:\x0fm\xfd9\x93\xa5\x04D\xd91\xbd|\x16\x93j\xd4\x12\x1d\x1e^UG\x16\x92M\x07l\x04\x07\xd04\xb5\x9dN\x0e\x91\xef\xc1\xff\xcdOg,\xfd\x8c%~b\x7fJ\x9c\x8b\xee\x85\xf9\xdaw\x80\xc9\xa7\xd9\xd9=hw\xbe\xe1\xf3H\x9dA\x8d\x18\x94\x03p\x1byx\xba\x05\xce\xd5\x87\xad\xfa{d\x99.\x86\x15h\x82\xc7{Tw\xe5;\x05\xd1\xa8pa\xf0^\xa2[\x8e\x04\xde\xf7L[\x17j\x94\xcc\xa4h\xa8\x0fQ7\xa9\xcd\x118\x07\xd9\x1d\x9d\xa3\x0dT\x98\xc1\x0dAc7\x0bU\x80\xe1Q\x86\x9e\x08zC\xa5\x8doeH\xee\x11\xcf\x99\x018R\xcc\xdc\xb8 \xffSv\xd4W,\x15&\xcd\xd9\xf9\xdbB\xff\xb7lQo9WV\xa2]\xb8Xa\xc6\xe1M\xcc}\xb7\xf6\xfb\xab\x0fcV\xd1X\xef\xfaW\xe3=\xc8\xd4x\x89'\x05\x8e\x11\xff\xda\x84R\x86\x0d\xb3\x86\x9c+\x97x\xc3s3\x93\x19lL\xa24\x94\x81{M~\x0b\x92,\xc6\xc0*\xceG\xaa\x85c\xd3\xaf\xe1\x00\xcda;.\xa5X\x7f\x92\xba?\xd3\xbe\x1b.-\x7f\xda\xaf&Q\xcd][t\xcf\xd5\xf0\xc8\x9aq\x87\x95V\x9ex\x15\x87\x05O[\x84\x9f\xabxrU\xc6Fb\x85\x1b\x95 hw\xc1`\xd7$\x85\"2OCl\xd8YY~?\x8ds\xd5\xd8\xa0\xbb\xe2\xc4Z\xb1\xeaz\xc5\xb0\xd2\x0dGY>d\x01\x06W\x19/\x12\xca\xdd\xdcc\x9a\x12\xac\xa3\x9ayy\xbb\xd8\xf8\xaaMz\x9dG\xac\xfeI\xf3\xfb\xaeV\xbe$z\x0e\xbb\xd4\x03\xa9&\xe5\x06\x9b*\xc6(D\x06\xa8\x10\xbe\xebL\x1e\x152X\xacJ\xca\xd0g\x08<\x1e\xf2\x9a\x88[)\x8b\x1b\x05#\\\x11\x0eo\xf5\xcc6GD\x16 \xed\xb7\x9f\xe7\xfe\x8f|X\xf9P\xfa`\xf0\xc4\xac\x83\xb9\xabm\x03\x0c!'\"\xe5\n+\x1c$\xc4\xd4l\x01~F\x05'\xb7\x9d\xce\xd5\xd2\xda\xe9\xd2\xd0\xceDo\xb1\x9e\xa1\x8b#U^\xe3\xa9\xc6oc^5\x9f|\x03\xcd\xc3F\x1f eZ\xbe.\xbf\xff\x90E\xe1j6\xa7>\xac\xb2rI\xa2d\x9a\x90\xb8\x1a\x1bv-\x00\xf7\xf7\xb0\x89\x0e\xa2\x1d\xcf\xe4.\x84\xb7\x17\x05\"j5\xa7\xde\xa3&\xdak\xcdq\x82^\xa2\xd4\x19\x98\x90+\xbb\x92\x05\xd7\xc2\xc8<\x0f\xca\xdb\x04UXt9\x97i\xca\xa2\xb0$\xb0k\x8e\xf4/\\\xb0\xa2[t3\xd5\x82>\xa4\xdb\x9f\xb0\xd2\xa7\xbd\x95\xfa\xcdu\xba\x7f\x13\xcf\xee\xd9\x84\xfa\xf6\xf4\x9e\x0d\xca\x9b\x7fc\x99UE\xd4\xf7[\xe1\xb1\xfd\x18.\x97\xe9\x9d\xe8\xe0J\xd7{\xad\x84\xf4\xb9k\n\\\x83,\xd4\xfd\x1a\xc4C/\xc5\xeb-n\xda\xe2y\x95^t\xc9C4r\xc7\xe5Pnnz\x90N\xca+\xad\x8bF\xfc\xa3j\x954\xb1L\x18\xc7J\xcc\xd0N\xe5!\xb6\xe3\xc26$oX\xfc\xce\xa4\xb2\xda\x1aYV\xa7^\x17\x96\xecAU\x0d<\x93\x91[5\x02)~cx\xd3u\x94/\x0e\xfa\xff(\\\x1a\xc8.y(\x90\xaf:8\x02\xaaU\x94\x04\x08/\xa5\x9f\xf6\xae\x074\x87$\x8b\n\xc2\x90\x0d\xfa\xb7\x08\x9c\xd6\x92J\xe4\xea\x9b\xe9/\xd9\x7fZ\x84\x11\x1e\x82\x8d\x04\x0cL\xd7u^\xe7h\xe6\x00\x1b`\x15\xb9&<\xfa\x8du5\xd9\xc3\x03\x88d\x12\x83\xee\x83[\xfd\xdec\x8c\x8dyU\xd0\x08[F\xd8J8M\xf0\xad\xeb\xd4\xbf\x13\xfb\xb7\xdaA\x9a\x0e\xe3\xad\xd6F\x07\x81\xad\xed\xd1\xb3\x156:\xc6\\\x15\xe5\x9ci\xeb\x8ax_g\xf4\xd1\x87\x98~\xe6>y\xd2\xb9/\xda]2\xb7f\x05t\x8a\x0e\xc8\x1a#\xd6\x97G8\x02\x90K\xd8\x9eh\xa3\x0d\xb7J+\x19\x8a\xe8\x8dh\xf0#cC\xaa\x0b\x0eF\x9e\xa6\xb0\xf04\x96\x93!\xb3\xa1\x03\x83\xc6\x04N\xd0\x9bjo\xbc\xb1W:\xa9\xf6\xcc\x16\xb4\xf8\x0e1\x13]\xcbh\x03\xeat\x10,\x9b\xc8\xd26\x8d\xc4\xdd\xf1\xea\xdbx\xbfE\xfc\x19(?I\xe3\xc3H\x8b\x16e\xea\xeba\xbe\xca\xba\x05\x02:\xbboS\xae\xa0\xed\x85m\xc3YRy\x94\x14\xd3`q\xa0R\x87+\x96\x16\x9c\xfd\xf8F\xe3F\xec#4\x1c\xe6\x95\xbaJ\xa3T\xbfI\x80n\x0cD5\x0f4\x99\xfbl\xe7{\xcf\x0b.hA\xc2\x85\xa0H\x82s\x12\xc6\"\x02\x1b\xbe\xffR$T\xbcg\xee\xee\xeb\xefQ\x80y\xb4Z\xa6\xe437\x80\xe3)\x97E\x98\x95\xd3\xbcX\xf0\x8aww0\xf5}X\x96\x97\xf3\"_\xcd\xe6<\xf3\x8b\xe7\x83LMz\x1d\x01\xf28_&T,\xdc9>\xdf\xf1l\xf4\x9fA\xd7\x1e481II\x12\xc6|\xa1|\x84\x07\xaa\xe0\xa7PF\x8b\xbbf\xd24\xc9\x92f\xc0E\xdb9\xbd\xd19\x07\xfa#-\x0f\x08o\xd4~\xb6\x93F\xaf\xec\xf9\x04R*\x8c\xe6\xfb\xea\xb3\x16^d\nd\xe0o\xc2\xc8 \x82P\x1f\x1a,\xb9\x93\xc5\xe8fk\x8b\xf1y\x18v\x1d+`3h-k\xbe\x07\x02\xac1\xca\x8bO$>'\x7f[\x91\x92\x96o\x0b\xf4\xe9mJ\x96\x8bDP/\xcdPlO\xd3\xdb\x92\xcfW\xee\x91\xa5\xf5\xedk\xc7\xeeV\xb7\xd3]\x9b\x0fYq\x11\xc6\x06\x0dn\x8a\xfc\xb6\xe4\xd4\xcb\xc4Y\xef\x04\xbb;\x8e\x0f\xec\xc7\xeb\xc0\xb9\xaa]\x81\x04kR\x94I^y\xf9\xf0\xe1{\x8fk\xd2\n{\xda\x04\x87w\x99\xe8KpW\xed\xd3\x0b\x1a\xa2-\xfc\xac\xdd\x9dT\xd8\xad\xbc\xd0\x8e\x954H\xb29)\x12\x81\x15^\xed\x1aX\xaa\xc8h-\x02(|\x12z\xa6#\xdc\xe0\xcf\x06\x99IL\x05\xfe\xd1=\x0e\x80\xd4uvw\x9f\xefJG6\xed,\\u\xebC\x92\xd1W(i\x025`\x8d\xd7R1e\x03\x98\xfb\xa8\xa1\xc5\x1a}iE\x0d\x0b,l\xf983bg\x10\"6\xee\x82\x8a\xa3C\x0420\x84Q\x05e\x1fSU\xf6k \xd5\x11\x99\xf0\x8b\x8e\x93\xd9\x15\xfc\xeaz\x7f\xea/\x10\x19z\xb7\x0f\xbb/`\x04\xbb/\x9e\xbdzn\x99\x85FW\xd0\xaa\xf4\xcb\x17A\x0c\xe7\xb0\x0f9\x8c\xc4\\\xa4\xf5\x87\x94Q$)\x8c \xf2\xcd\x95\xd4\xb1~\xdc\xf6w\xafF\xe6az\x18\xa62,\xa7/\x0f\x02\x12\x1f\x15a\x92\xa9\x89\x1c\xe7i)\xcdr\xfclh\xa6\xc5\xa4\xa4E~'\x12\xcd+\x82\xf1\xf99\x7fE\x82\x98Dy,\xa2\xc9\xd8N\xaaF\x1eVxZ\xb5\x86B\xb2q\x16\xe5\xa2\xb7\xa4\x95\xf6\xe5\x0b8+:}%\xe5I*\x13\x87 l\xc5\xb5\xa1rD\xab\xe4)\xef\xb2HJL\xd8\xfb\x0dn\xe5\xf7\xdcZW+\x9cg\xa8\xff\xd2\xab\xb8\x0b\xedC\xb3\xef\xc4\xe4A\xdc\xaeoU\xec\xd8\xad\x84RpY\xf4]\x16u\xe7\xe3\x81\xe0\xb0\xe3\xd1\x8d\xfd@d\x14c\xff\xa8\xe4C\xb4\xb9%\xb2\x81\x8a\xc6 \x15\x7f \xf7\x1eII\xe6+\xbf\xd9\"X\x1b\xf9\x8a\x871\xf5\x0c\xc4\x87\x99\xa6\xd2\x9f\xad-\xe5x\xf71r\x80[\x9fJn\xeeC\xe1\xf9\xca9\xe5^\x08\xa6\xdco\xad\x03\x97\x9br\xb9\xa8\x14\xa9\x12\xc1\xd8\xf3+,V\x19\xe3\x15\xdc\xdc-\x1e\\\x81\x0f\x17\x1cT\xecZ(\xe89\x8aO\x00es\xd0A\\\xf5+\xf8\xe0\xad\x01\xec\xc1\xd8\xd5YD\xfd \xf1\xcc\x90{\x07\x7f\xb7\xb6 C\xde2\xb9\xa2dX\xea-gB}\x8cfZ\xba\xd78\xcd\xfcj4gsv\xed*\xef\xf6\x91\x1b\xbfXi!\x05\x01\xa8@Y'\n\xf8kl\xfa\xba\xdb\x8d\xfciX\xd2\x1f\xbb2T`\xa6\xd4\x88\x8a\xcem$\xaa\x03\xc2\xae\xb9\x03\x92\xdf\xdai`-\x8d<\xcc\xc8-\x84\xfcf\xb11\x016\xba\xe0\xce\xbc\xad\xb9\xe6s\x930\xd8p\xe7\xfc\x12\xec\x8ew\x00\x8d\xbe\xd9\x8f\x06-\xe05\x1c\xa0\xdeY|\x9f2n\xf6V#\xfaX~N\xa6(\xe1\xa2ok\x0e\x0e7\x08\x9e\x94f}\x0c\xbe\x86\xca\xc5\x87\xc4\xcb\xe2\x8b\xed\"A|^\xeb%\xd7u\xd1\xb5\xbd\xac8\x01\x95\xc22e\xaf\xfej/\x8eg\xb4R\x98\xbf\xef\xc9/\x9e\xe7\xc3T\xb9-\x1e\xb4\xa67M\xa4\xc8E\xe9\xc6k\x03\x15\xec\x19\xfaP\xf6F(_\x05>\xc7\xcb\x03\xe5\\\xc4\xa8+r\xa6\x18\xe6\xa4\xf2$\xe4a\x87\xf9\x17\x97\xb7^\x7fSk\xd9\x1d4\x9ake4\xa6Ad\xd0\x17\xf0Q>\"\x06\xa3<\x83\x9e<\x01\xaa\x10C\xb8\x06-\xe2Hb\xe4\x98\xa59\x06,\xfc\xd5\x15\x07\x84\xc68\x16n\x8d\xbb\x07\x8d\xf3\xd6\xdawj\xa4?\x0c\xb6\x0c\xeb\xca\xb1\xb2\x86:\xcc\xb2\xa0j\xf9PD\xcfo#\xd8\xc9g\x9b\xbf\x8a\xf87b&;\xc1\x91\x8b\xcd\xcd5\xf4\x8a\x0e\x83AtZi@l\xe6\x93(\xa9e\x05\xe6\x0c\x95R\xf4\x8a\xa3\xcd\x92\xcf\x1b:\xfd\xcb\xf1\xc6\x82k=\xa1w \xbc'\xc3\x1c\xbb2\xd0'\xce\x86\x0f+\xd8\xdc3\xc9\xd3\xd8\x93\x07a\x9a\xf2\x83\xa0\xe4^\xd8\xe4\xee\xe3;\xa6\xf2\x92\xe6\x83\xe30\xd2\x82\x1f\x00Mx\xd9\xdc\xc4\xac\x1dG\n'I\x18\xb9b\x11\x0b$\xa2\xaf\x89*\xe7\xf1\xecb\x04qN`?l\xe7L\x1b\xd6\xbb(\x08)&\xee\x94\xc8T\x9c|\x10\xcdW\x99\x85\xd1\x92\x0f\xea\x0b\x05DP\xf6\xddy\xb99r\xbf\x88\x87\xc1}\xb5B\xbb\x88\x99\x1a\xdc\x1c\x8c \xad\x16-\xf5\x19\x036\xd5\xc0\xc1\x0b\xae\n\xb9\xa3\x81S\xdau\xf4\xca\x83\xbd\xa6\xb9\xf9\x1e\xb2\xd4ZW\xa9\x87\x0bhn\xa4Z\xb4\xc8H^\x86\x06fM\x07\x9d\xc2\xa7\\\x8f\xb4\xbc:\x85*\xf1\x96\xb6\x07xx\xf0\xc9\xd5\x1b o<6\x0c\xb4=\x92\xa28\x9c6\xebJk\xe1\xe9\x0c\xc2\xca>A~\xb7\x171\xb3s$e\x1e|p\xf8pZ.\x92\xf4gF\xe8\x08\x0d\xad\x84\xc8\xb5\xdbI\xa3\xfe\xa8\xb7{\xd5\xd4\x1b\xdc\xda\xa8\xcfW\x1f\x1c\x8d\xe9\xe6}\x85\xa4\xacE\xbfBYI\xcbX//\xe3nH\x18\x07\x8e\x0f\xce\xd1\xf8\xfd\xce\xce\xce3\x8b\x8f3ho\xf0*\xb9\xd7\xfd\x99\x85E\x10\xb1\xb4\x9e<\x11\xbf\x82yX\x1e\x0b~\x0bl\xa1C\xa5\x9b\xe8z\x99&\xed\xd2Wh(\x07{\x03s\xfb\x16X\xb8\xf3\x0d=\xeb\x08\xe0\xd5/O\x92Z\x90\x1bsU\xdf\x94\xd4\xfc&\xdb\xed\x9c\xe3\x92\x0e\xa6\x9a\xbc\xa4\xc2\x8f\xce\xfaN\xcb\xaf\x88\x85\xe6\xbd\xe2;y\xce5\"\x9c\xb4\xee\xe5}P\x15G\x97\xc9\x92\xf4a\x07.\x01h\x1e4uP\x90\xc30\xcbr\n\xac\"\x1f\xd8\xafB\xdcp\xea\xac\x88\xd6r[$i\xbf\xa3C\xb2\x9e\x1b\xf0\x1b\x18s\xbb\x8d\xfd\x86\xc1#7\x88\x0b\x85\x8d\\\xa5\xab\xd01:W\xa1_V\xae8\xdd\x02\x17\xb4P'4\xb6\x1fi+$\x0d\x94\xe2\xdc\xed\xaa;L\xf0**Y\x06\xd3\"_\xe8\xf1\xe3\x00DH\x05\xcb\x16D\"\x85\xebWpT\x8dT\x18\xe3\x0b\xf6\xf1U\"@FmsEX\xbc\xe1\xd1$\xd3\xcd\xdak;\x86\xac\xaa}\xe1\xf9\x90\x0b\xb9\xfb\xfe\xb0\xb3[R\x03\n\xc8\xf0\xa5\x0f\xa7\x94\x14@\xb2\xd8\x16d\xd3D\xdd(G\xb4\xc5y\x86\xd8\x8b\x19\x9e\xdc\xab\x16\xe7m\xe7\xd2A\xb9\x9e1Y-\xc9'\xb4\\$\x80B\xdc\xd4\xa4\xf2>\xf7\nN\x1az\x80'\xe1\x1dn\x15>\x11\x98\x1bQ\x0fF'+Q_\xc0\xf1\x8c\xd1\xa3\xb9,A\xb1\xa3\xc989\xd4\xbc\x8er\x0dm\x1eg\xeb0Mb\xc8\xf2l\x8bW\xbb-N\x1a\xe4s\x1c\x0f\x95\xc5\xb9/\x8e\xe6\xbc\x87\xcdy/xJ.\xf9\xd0v\x10\x10\xb9\x069\x97\x99\xf2\x00\xd2n\xde$\xc0B\xc3\xde\xaf\xa4A\xb6\xf5AU\xae\xdek|S\xd5}\x078\xd1o\xf4\x8c\xd7Axw#\x17E\x8b[\x82{Jl_\xda\xe1\xc2G>F\xf2H}\xbeVz\x18\xf6\x8a\n\xee\xb2\xa4\xda\xa0\x8c\x88\xcc\x95\x0d\xcf\x15\x03,\xce#\xcc|\x9e\x94F\x18\xf8\xce\xc2\x18\xb9@>\x95\xd8j\xd3\xaa\x1b\xc9\xeaF\x0b\xb8:8\x12m\xde\x0c\x9a\xcb \xed\xfd\xa6\xeck\xa7\xc3GR-\x18\xc4\xed\xc1\x05\x0c}p\xc3=\xb6\x19\xd8Z\xfb\xfc\xdb\xb8\xe0n`\xc3\x1d7\x02\xc3\xcd\xbb\xfaH\xb1\xc2\x08\xf4P\x84\xda\x83\x07\xce\x08\xb2\x1eY\x85\x90<\x8c \xe9\xce\xc8v:\x8fgo\x07M\x1f-\x86S)\xca1O\xc3\xc8\xc8\xe4\x1b\xf3Z\x85<\x9b{\xd0vs\x06\xb5\xa4G\x95\x94\xacj\xfc\xd1\x89\x9e\xcb.\x8c\xb5\xf2A\xa2\x8cvL\xa0& \xc3\xa0j\x10\xf1\xa4\x11\xee\x1c\x1a77\xbb\xea^eCjo\xf0l\xcdV\xda3 \x1b\x16H\x9e\xbflm\xf9\xca\xad(:\x82\xac\xef\xcb\x14\xa9\x07\xbe\x19o\xcf\xda\x02\x13\xbc=\x93$q'\x11X\x12z\xd4\xba1\xef\xa6\x95\xd0\xd6\xd2\xe2\"O\xb8\x99\xa2\xf9\xbb\xfc\x96\x14\x87a\xc9\x8d,6\xdc\x893'\x9f\x19w$\xee\xdd\xd9\xff-\xfc\x11\x96Q\x92\xb0\x1f7I\x16\x16w\xf8+,\xc9\x8b\xe7\x98+*\x9f\x8a\xff[OE\xb1\xdd\x17\xe8k\x17k\x90\xbf\x8b\xf0VQ3r l\x82\xe3xZ?P\xcf\xa8\xb2\n\xd0Ng\xe9`\xb2\xde\xf3\xe8d\xb2G]W\x83+\x83\xf2\x81I3\xd7\xca&5X\xe6[\x93\xda\x89\x91\x83&U\x9c\x83\x91\x91\xe2F\xae\xba\x97\x93\xee\x18W\xe3\x80h\xef\xdd\xe6\xe8\xbc&\x84]\xdf\x87\xcf\xc8\\\x85J\x15\xd7C\x1e\xe3\xc4\x19\xb1\x96,\x96)Y\x90\x8c\x92\xb8\x87\xb5\xa9/\xe7\xb8h\\\xfdF\xb2x`g\xaa\xbb\x8c!{\xdb\x1a\x90 \xa9\x02\xc2\x055\xe2\xeeW\x11\xbd\xdf\x8b\x99\xa8\xcd\xbf\xa1\xe9$\x83{\xa8\xaf\xee\xa8\xa5\xcc\xabP\xf1MQ\xab\xb0\xc8\xcbc\x8e\xe2p\x87\x16R6\xcb\xd8\xad\x06\xd2\x192S\x80\x07q\xad\x1f\xb4S 7\xfdJX]\xd5\xb9\xaf\xd2\xb2\x19\xbf \xcc\xb3\x88TB\xb7\x0e\xd2\x8d\xd6*G;\xbe\xa2\x9a\xd5\x16Q\x83r\xa8\x14-Fe\xe0\x16\xacT\x97\x8c\xdb\xee^\xdbJY-\xd3\xd5v\xa5\x84\xae#\x14\xd1\x81\xf6\xd8\xda\xdb\xbcl\xf4\xc7\xca\xe7Z\x9aw;\xdb\xc7\xd8\x8d\xf7\xdc\xf9\xf5%\xf7Z\xfe\xd6\xb6\xe9*S\xf3ToZ\xae:O/\xbf\xcb%%Y\xecz>\xd0V\x0c\xf8\xdf\xd5=U\x03\n~\xcf\xa0\xd4}\xb6\xf3\xcac\xc7\xe1\xf1bA\xe2$\xa4\x04\x13w\x87\x85\x0ex\x8c(\x83F\x04\xf2\xbbf\xe7\xbf\xb9\x1b\x99\xfb\xe2\xf5\x8e\xe7z\x95\xdbN\xc6-a\x98\xc8\x17\xafw\xbfa\xa8\xeb\xcam\xfc\xcb\x1ds\xf0\x84\x17\xa6\x88?\x99\xfb\xea\xa9!\x86\x97n]-\x0e\xf6f\xc6\x95)jSWx\xa0R*E\x867\x9a\xff\xc5\xb4\xa1.y\xdf\x05\\W^\x1b\"_u\xa5\x0f\xb51\xa2\x12\x9f!\xb4\x98W6\xcb\xe1\x85@\x86\xc1W\xb9A\xb0W\x9b\xbaF\x9a\x93\x05~F\xa0sI\xf4p\x11y\"\xce]\x04\x7f\xd8\x83\x1d\xc6&\xb0\xb4\x914H\x96vN[\x90\xba\xa5\x1by\xde\x1b\xe0a\xee`s\xd3p\x1d\x85z>\xaa\x94\x95rq\xc2T\x1c\x8d\x13z\xe5C\xe1N\xbdz\x8c\x1a\xbf&R\x15w\xc9\xdf\x00\xcd\x0d#\x89\xd6i$\x05\x95Z\x07\x86\x11\xb5&\xd1\x1b1\xd3\x8bHaJ\xc2\xc4nD\n\x8aT\xb8\xf1\xe1+\x97\x12tw\xaa\x06,\x967\xce#\\r\x11\xc0\xe1\x92|\xa6\xa7yL\\\xc7\xe9p\x1cn\xd0\x00QT\xaf\x06\xdc\xaf \x83\xd3\xc1\xe6{\xf2\x80\xe7\x97\xeb\xdc=\x16\xb5\x9d\xdfC\xfc_f\xfd\xfe/\xb11\xe3W\xb3D\x05\xad\xd6\x9a\xe4\x94E\x8e[;Z\"B\xf3\xa3\xca\x8f'8\xd1c\xd0\xc8\x077l\x1e\xc4!\xe5\xe1|\xf6`s3\x81\xff\x80\xa7\\\xdd\x01k\x0b\xcay2\xa5.z\xa1\x10\xe2\x17ix-(\\6\x82 \xad\x96qH\xc9\xbb\xf0\x8e\xcd\xf3\x00*\xd7@\xb2cD\x0f\x83\x80u\x19\xde\xa5y\x18w\x84\xfb\xa9;\xf06I)\xe9>\xe5{:`\x10\xc9\x0e\xeb@9\xcfo\xfb\xc9C\xc6\xa0\xb6|B\xf5\xf8>\xe7\xc1\xb4\x94\x04#UE*\x17\xb0\xba\xfby\x06\xc5\xb6\xe1\xae:\x86ke\x1b\xb3\xd9\xc8\x14\xbf\x8e=l\x16\xb2\x91\xe1.\xc5f]\x88s\x17\xcd\xc3lF\x84UW\xff\x0c\xdes\xfe\xda\xbe\xe3\x1d\xe7\x11\xa70|\xe4)\\\xe41\xb9\xd7\x0c\x9a\xb8/c\xd0\xae\xf6\x06vR\xdc\xb1\xd7|\xf7\\\xf37\xa7\xcd\x9f\xb5\x91\x81Vr\x8a\x1b\xcfi\xb3p:Z\xd1\xca\xb1\xc1:m~\xae\xc2J2;\x83+\xee\xa2\xf2\xbf\x1ea\xe2\xf5mH\xc9\x8fd\x9a\x17d\xfc\x99D+\x14l\xd2 \n3\xf1\x8a~.y\"k\x0cOR%m\x1e\x96?\xe5\xe2\x12\xa6\xfa\xfeKB\xe7'\x84\xf2Y[\x86E\xb8 \x94\x14\xe6\xd4\xe3,JW%\xab\x94P\x9ad\xb3\xb7ya.\xf6\xe3\xddqL2\x9a\xd0;\xfc\x1e\xa6i~{Y\xdc\x1d\xd3\xb3\x15\x95\x85\x16\xec\xa8\xafn\x0ddj\xa1\xbf\x96\xcb<+\x89\xb9P\xa9\x16)\x1b\x05\xf8\x1b\x0dg3\x12\x9f\xc9\xb1\x96\xcd\xa1\x97\xac\xbb\x97\xe1\xac\xca{Dh\x98\xa4\xd5\xab)\xfby\x9e\xd3c\xaet\x87r)\xca\xa3Z\x88\xf6\xe6rzo\xc2\x92\xbc\x0f\xd1\xacO\x00@Rw`\x9ad\xf1Q\x95\xc6+!\xd1\xaaH\xe8\xdd\x91\x96U\xa6\xf3i.\xf2x\x15\x89\xa6\xa2<+W\xb2\xdd\xbc9\xc2eH\xe7\xb2\xfcb\xcd\xfd!I\xe3g\xfcM>SRdaz\x94G<_\x92M\xf9^M\xca\xb3\x83\x8bg\xbc\xec\x92D\xd5\x8f\xff,9\xa8\x9c\x932O\xd7$\xbeX\xdd\xd0\x82\x88\xe6Y\x06\xedC+\xbdQS\xf5r\x91\xaf\x8a\xa8\xce|Ay_WE}\x19\x8b,\xaf!>\x82\xa2\x15\x94\xb9\xafLA\xdaQ\xa5'GyA\xd1\x0c\xf1Wt\x87\xf8+\x9aH\xafn\x13cm\xbf\x97\xd0nVa\xb0\x1c\xfd\x08\x17\xecL\x9d\\1\x96bF\xe8q\xe6N\x9c\x05\xa1\xa1\xe3\x83\x83K\xe6T.\x9e5G\xb5\xd4\xf3a\xe2T\xdb\xact\xae<\x1f\x0f\x8d\x12Eh\xffy\xe1\xb9\x93+\xcfC\xc8\xea\xb1\x87\x94\x97\xa0\xc1I\xb8\x0c\x92\xf2$\\\nE%\xec\x93\xeb`\xb0\x06\xaf\xd6\xf4\x16\xc9I&\x12\xb5\xb9A2\x81\xf7\xe4$\\z*9\xea\xab\x98\xe1g\xae\xe0\xd2\x7f\xf7a\x9a\xae\xf7Bj%)\xbf \xb1O\x94\xe7\xf1\x0e+\x93%\xa7\xea]RR\xcf\xf5\xbc\xa0 l\x1f\xb9\x8d\xaet\xdd\xc1\xc8\x08\xa4\xb1\x081A\x959\xd9\x97o\x88\xb8\xaf?/R\x87[5\xd4\x89]r\x19F\x9c\xbbj}\x9b\xe0\x04\x0el\xca\n\xf8r0\xb0j\xce\xbb\xbe\xfc\xffP\xa3\xa87\xa7\xbe<\xe6AX\x8e\xb3\xff\x1a:\x87\xf1\x84|\xf2\x83\xa4d\xffT\x81$ \xca|A\xbe\x11f+\xe0\xd4\x94\x8d\xfbf\xe4\x92\x07\x1d\xba\xf49>\xa5$\xa3,\xc9\x0c\xabz\xc7\x14\x08}\xd3\x9aH6\xd5\xb1K\xbcj\x9f\xf7\xed\xef\xd6~f\x0b\xda&\xd5\xb8\x8b\x92\xfb\"\x8f\x81\x953Tz\"n\xceZ\x1fQ\xa7\xac\xb5\xb5x\\]r+vW\xbb\xd8\n\x1d\x93`1yb]\x8bM\x811\xd2\xcd_Fp\x89\xd1\xf30j\x15\xcb\xe8,V)M\x96aA\xb7\xa7y\xb1\xd8\x8aC\x1a:u\xb6\xbcX\x1c\xb1\x14\xcc\xcapE\x12\xe1q\xb8\xfdy\xeb\xf6\xf6v\x0b\x8b\xac\x8a\x14\xaf\xd7I\xecT~\xda\x8d\x04\xb96U\x06h\x14\n*\x15\xc0\x189\x1aI\x894\xf2\xe5\x9d\x00Z\x1d\xe3\x87\xf5\xe1\xde \x83&dy/\xb0c\xc7\x8a\x9c}\xc3\xa1\xd2\xc6*\xd1\xaa(HF\xdf\x0bR\x84\xd3e'\xcdS\x19A\xc5\xfd^\xbfrY\x99y\x04~1\xf4\xd2k\xd6\xc1\xce\xff\x893#\x14\xe1{\xc5\xff\xe5%\xfe\xe7\x1e\xba\xd8\xaf|\x89D\x0f\xfb9'a,\xf6B4g?\xd0\xcb\xa6\xa3E\xd2\x88z\xc5\xde\x15Wf;\xd7\x00Z\xf7\x9fS\x1e%M\xa5VX\xd1P\x08\xcb/HJ\"\x9a\x17\x9e\x1b\xf5\x05\x82\xac\xb0\"\xee\x8b\xaaBM\x9d\x9fs\x04\x9cHz\x94\x86V\x85\x1e\x15\x9d7Q\xd3d\x8f\xd2\x0c\xab\x8e\xa3\x0cG\xf7\xfc\xef\xeb\x04\xe1\xa35\xc8k\x14\xcdf9\xdd\"qB\xf3\xc2\xd6\x01A\x9e>J\xf3\x7f-\xf3\xac\xa2>8\x18\xe9\xb3\xacm\x86%\x87$\x8dp~\x94\xce\x14\xa2\xbe\x9e\x0e\xf9Vz\xbe\x97\\R\xdbC\xecSh\xccB\xf7\x11\xc5Qr\x8b\xce\x91\xcd\xca\x80\x89\xc3\xe8\x03~M\xa8\xa6d\xdc\x8f1\xce\x05\x8f\xca\x8a \"~b\x19\x9c\x151)H\xccg%X\x90bF\x18\xc3S\xd3\xa9#\xdd\x16K[\xbbx\x08\xb3\xf4mK\xd9\xdd\xd3\xa5\xdf\x00<\xcf\xd7\x97\xbeZ\x87\xf6\xaa7\xde\xe7*\xff7\xa8c\xd3\x96\xbaC\xb3\xc6\xb5\x88#)\xb9K\xf34\xcc\xfd\xee\x0b\x16\xd1\x98n\x0f\x8a0+8\xd8\xfe\x8a\xbb\x86\xf1Wi\xaf#\xc8\xcai\xde\x9e*m\xae\x16|d\x1aG\xfd\x98\xddP\xab6\xac\\\x83\xb57\xb7\xbb\x1e\xd8\xae\xda\xaa\xa8\xb3u,h\xc3\x9f \x84%\xe5\x0c\xe6\x0e,\x06v`{\xbd\xefNv\xb6^_}\xe7}\x0c\xda\xbf\xb6\x93\x80|&\x11#p\xb8\x0b\xb7]\xd3lH\xe9\x87\xb9+\xf1\xc0\xae\x10I\xeb2\x02\xaag\x12\xee\xdaB\x18s\xe3\xb3\xbe\xc6\xf1\x0e\x9a\x07\x0e \xca\xe4\xef\x04~\x80]\xaf\xb9\xfb\x05\x17\xdbf)%\x03\xd7\x93\xad\xb9\xd6\"\n\x1d\xec\x83K\xda!\xe9H\x87\xca]\xdd\xd5\x8d\xaad\xd5Uk\x18bc\x1bV\x83\x1c\x10F\xae\\\xb3\xb6\xf0d0\x15\x97K\xd9\xf0\x9a\xb7\x8f\\W\x1f\xb6\x9a\xbd\x9a\xf2\x0bB\xe7y\xdc\xab\x9f_-\xb7U\xa6.\x9f\x84U\xc6\x18\xfb-\xc6\xd8\x9bU\x07\x80\xc3\x95\xe5J\xdat/\x8f\x87\xf0\xa8\xb9\xda\xfanh\xbc\xdf\xe8r\xc3oCR\xbc\xe1\x0bB=\x974\xd9\xb8\xbe\xe3\xe5Z\x97f>vGd\xd5}\x1d\xb9\x95\xc8\xab\x12\xb2~[O$\xd5)\xeak \x9e\x0c\xc8\xca,\xf8}\xd4n(U\x1b\x89\xfc\x968\xba\x97\xd0\xab]\xbfY)=d\xd3\xeav}\xa0W\xbe\xd031\x82xS\xb0!\x08g[\x15v\xb5\"\xd4 F\x99D\xeb\xa6\xdcoI\xe2\x1fe\x96\xd5.\xda\x85\xa1P\xcd\xb6r3\xf0(\xed\xcb\xfa\x8cK+\xee#\x1e\xa5!V\x97\x99I\xac.@\x1e\xa5\x1dQ\xdd\x006\xa5\xfbf\xc6\xdc\x99;\x1fn|\xb8\xee\xbe\xceku\xac\x11\xd8\xdd\xaa\xc5Qe\xe7\xd7\x8c\xaeSu\xd0\xe9\x9b\x02\xf9\xa0\xd7\xa3\xae\x0c2\xd3FS\x18\xda\xaf\xb5\x06j\x07o\x13:\x97\xaa6\xe5\x80\x91\x19+\xd1p>'Z\xe4\xd0\xab\xf4\xa1#W\x1f\x03b\x17|\x8ekP\x11\xd5\x9f\xaf5\xe3S\x1f\x04\xcd\xdeU\xe9\x8f\xdc;\x83E\xb2\xfe|m\x85\xb6o\xe7\xb0~\xb6\xfbpnt\xca\x80|\xe4c$%\xb4\xbd\xa5\xa1h\xae\x97#\xeeC\x1fe\x8b\xb3\xbaz\x0f\xc7\xc6\xfbg\xd9\x87\xfa\x8a\xb6\xf7\x94\x92S\x82~\x81*\xc4\\]\x02q\xe5\x01W\xd9G\x83\xee\xcf\xa05\x1a\xe5\xc6\xcc\xa0?\xd1\x89\xc6\x9a\x83\xbc\xd0\xd8\x08\xe5z\xda<\xed\xb7>\x8c\xfd\xc1\x13A\x06\xdf{\x81r\xc6+`N\xab\xf3YEl|5\xaflJ\xb7\xf2d\x0e\"\xf4\xab\xcfH\xf8]\xf4\xcc'\xf7\xa2\x10\x02\xe9\xf0\xd0\x07QZ\xfdD\x06\xce\xb2@=\xc6A1\x8c\xbf\xd32\\G\xe8\xd9\x03\xfb\x08C\xfb \xf6\xed\xff\xd5\xea2\xf4^\xcbZuC\xb9w\x94w\x8c\x1d\xfb\x11TPn\xc8\x9fz6\xee!'\xb1\x0d\x8a\x18\x83\x10F\x95i\x10\x9c\xe2x\x0e\xf3l\x9a\xccJ\xb6<\xf6\x85\xc5\xcb,\x06\xb8\x17yAM>\xd0\xe5\xc3\xfd\x10\xd7{\x92\xe7\xef\x04\xf5\x0b\x94O\xe4\x05\xfd\xf1n\xd8\x9a(e\xcd\xee\x00\xba\x02\xd4\xea\x8f\x9c\x0f\xa3\xdej!t\x1fV\xd8?R\x94\xca\x1cL\nK\x14}P\xe9\xeb}\x90]\xe8\xb0\x11\xff\xea5)\xa6>\x0f\x0c\xf2\x9e\xdd\xd8g\xe9\x83\xbc\xee\xb3\xbe\x1a\x93\xbc'^z\x02{8t\x8aU\xb8\x05^\xd0\xf7\x0eV\xc1\xdb\xdd[\xbb>\x96F\xdc\xd9[\xd6\x01z\xa0\x8a\x0e\xca\x11$\xf7F\x04\x86\x9d\xd9\xdc\x82\xbe\xa6\x07e><\x86\xca\x9ck\x192\xaf\xf0~\x17\x1a\x9f\xf0LST\xb4\x1e\xa93\xbc\xbe>&\xa1\xf1~\x80]ik\x90=J\x8f\xb4j\xef\xd5\xb13\x8e#\x9b\xban\xf7\xe0O\x0e\x95\x1b_\x96U\xb2\xc9&\xa8P\xb4\xeb\xee\xd1\xc2\xa7\xc1-\x98\xb4\xfa\xee\xd1\xd0\xc1\xe0\x86\x0c:\x85U;\x1d\x0dh\xc6)M\xbd\x10\xa3\xfa\xe2\x90\xdeK\x04v\xef\xbbw\xa3JW\xf3|5\xa3\x92\xfcA\x8a \x03\x9b\xb4\xcaW\x8a\x81\x9c\xb0\x14E\xe7\xb89\xb2\x06\x9d,\x15\x9c2y\xc9\xe2\xd8\xc6\x08\xe2\xa4\x1eX\x0b\xa6\xcd\xc3r\xce\xc5\xac\xf8\xf30\x8f\x89q@\xa0\xe3y\xc3\xa5\x9aXq\x93\x11\xca\x03Y\x85JQI\xed\xb6Y\xf7NMi\xb7o^\xb7N,\xf3\x9ec\x99\x1ee^\x1d\xda-\xc2y\xe9)+\xab\x16\xc2@\x13\xa9c\x7f8\x98^'\xb2\xa3\x0c\xab\xe6\x0cf7\xf4{\x1f\xe3.\xbe\xffh\xfe\x19\xdb\xf7\x1b\x01\xa5\xb0\x80\xc7P\x90\xb0\xae\xca\x99\x98\x93\xdc0\x95&\xe5\xf0oD\x83\xbc\xd0\xd5c\xa1\xb8\x07T\x97\xd4\x9ah]\xba\xa1\x0d\x04\xd7y1\xa5N\xa4<\xac\x0c\xb8\x02p/Z\xd7\xc1\x8e}\xd0\xf7\x17\xf2i\xcd\x0e'\xfa>W\xf5\x93k\x1d\xff\x07Hj$\xdanH|\x8d:r\x06\x17<\xdc\xcc\xb1V\x1a\xc5\xf8\xcf\xce\xb6\x08K9\xd9Q\x02\x12\xaa\x11\xa2do\xe0\xd2\xde\x9f\xff\x81*\xa9lRz\x95R\x0d\xb3p\xf2\xaf\xd155\\\xa3\xa0\x99\xb2\xf4\xf1\xd2\xb9\xbd\x1f\x88\xd0\x85\xccU(y^y\x9d\xf7A\xb9T7\xe5#\xaa\xe5\xb5;\xbd\x97@x\xff\x83A\xac\x1a\xaa\xa0x\xa7\xd4\\\x8a\xdf\xb5\x7f\xb11\x1e7\xe5p\x95\x05M\x1f\nl\xcc\x8fP\xaa\x0b\x16!\x8d\xe6\xee\xf6\xffq'\xe1\xd6\xdf\xaf\xd8\x9f\x9d\xad\xd7\x9b\x1f\xb7\x82\xab\xef\xbc\xd1\xb6E\x0b\x97\xbb\xa0HJ\x19\x90\x80\xb1\xed\x1c\x92\xb3V\xd0\xc1\xd6)\xcb/P$\x8a\x14\x92\xef\xd6G\xe7Z\xac\x0f\x1f\x9e\xc33\xe6\x9ar^\xc3\xf6\xc1`h\xd47%\xa2s\x13gN\xe9\x12\xd54)]\x96\x8a\xb7\xac\xe3\xaa$\xf7\x90U\xb7\xdce\xf4\xd4)\x0d\xe9\xdd,zd\x8a\xc7\xa1S\xecF\x19-\x8d\x07\xdb\xe6Rp/z\xdf,M\x96\x03\x02\xcfJqj\xe5\xfa\xd1\xa0\x0b\x93\xa9\xeb\xd8\xc65\x7fm\xf7\xc4\x8c\xd6\xf61\xde#W\xf3> \x97\xda\xb6\xf9\xaf\xb7\x8d#\x8a5\x9c\xf8\xddp8\x98\xcf\xd4\xd7\x92p3\xf3\xa6W\xc2\x92\xd0\xd6+\xe7\xc7\xb9E\x12J\x80\xc7\x8b%\xbdC\xfb\x9f\x8az\xc6\xaf\x12N\xf1\x93\xb4\xa8\x92\x89\x9a\x16\xe0a\x18\xcd\xd5:M\x86S\x82O7\x7f\xc2\xb4\x0bi\x9c\xb5\x0c\x8b\x92\\\xe6\x95U\xd5\xc5\xf8\xf2\xfa\xe2\xf0\xa7\xf1I\xc3\x9c\xfa||q\xf6\xee\xe7\xf1\xd1\xf5\xc5\x87\x1f/\xcf\xc7\xc6oj\xda\xd9\xfb\xf1\xf9\xc1\xe5\xf1\xd9\xe9\xf5\xc9\xf8\xf2\xe0\xfa\xe7\x83w\x1fx\x99\xc3w\xe3\x83s\xf6~\x8c\xf9\xde\x1f\x9c\x1f\x9c\\(_\xce\xc7\xff\xbf\x0f\xe3\x8b\xcbF\xca\xc5\xfb\xb3\xd3\x0b^\xfc\xdd\xd9\x9f\x1aYXoO>\\\x1e\\\x8e\x8fZ\xe9\xedw\xa5\"S\x0fD\xdf\xc7'\xef/\x7f\xe5\xe9\xd7\xc7\xa7\x87\xef>\\\x1c\x9f\x9d\xaa\x19\xf0\x93\x9a\xf0\x9f\x17\xcd\x0c\x1f\xce\xdf\xa9\xaf\x17\xef\xc7\x876\x034\xd8\x83\x1b7s\x9f~\xaf\x93\x9d\xb9\xf8\xf2\xea\xb9\xfe%\x91e\x9e\xe9_B\xf1\xe5\xf9S\xfd\xcbJ\x96\xd9i\x15*\xc5\xa7g\xcf^\xe9\x9f\xd2\xea\xd3k\xfdS$\x9b\xfa\xdek\xd0\x8f\x1c&/\xfaT?%\xb6z\xc7\xe8\x8e\x82,\xd30\"\xee\xf6G\xba=\xf3\xc1\x01\xd0\xf1\x96\xcdkc\xad/\xd6Fsh/q\xdd>\x1f+3g\x8d\xaej\x9e\x1c\xcd\xbd\xf5-\xb6\xf9\xa7\x1d]\x18\xe0\x1c\xe0\x03j\xe9?\xb8\xf5\xdbok\x9d\xa1\x85\xde\xc5\xec\xe9\xc2\xf8\xa1]\xe0\x06\xf6\x88\x13\xcd\xbc\xb8! bO_>w\xf4\xc5\xcc\xa9q\x95?\x8b\x86\x9e8P,\xf7?x\xb4\x9f\x86\x0b2\x02K\xf0\xa8%?\n\xac*\x85I\xf9\x97E\xaa[\xfd\x00\x0crL\x80\xf3\xd6)\x89\xb4\x1b\x9b\xfe\x8b\xa6\x0f\x87o\x9d\x1c1\xb9\xddSS\xdcsjR\x12\x16?\xeb\xa7\xed\x83A\xfb\xf8A\xf3q\"\x14D\xdbj\x1c\x03\x96U\x9av\xa1\x91a\x1f)\xdb\xd3\xfd\xbf>\xa8\xfb}\xbb\xc1\xb2\x9c\x9f\xc8\xdd\x08tS\xbd\x87\xcc\x80\xb4\x1d\xfb\x1f:\x03\x1a\x1f{\xcf\x19`\xf0\xab\x10\x96\xdf2\xf6\xcb\xc7\x1d\xbbT{\xbe\x87\x0f\x10eD\x92r\xfe\x96\x01\x9d\xfc\xb7\x18PI\xe8}\xd9[\xdb\x80\x8e\xee= \xce\x9ew \\6^\x0bx\xca\xf1\x1ad\xc3\xb6\xf16\x89\xd9iEd\xbe4\xd9\xa5e\xaen\xd1\x19W\x05Z\xf4\xe5\\|\xda}\xd9\xfa\xb4\x96Ti\x9b\xcc]\x88O/_\xb4\xc8\xdcY\xf5\xa9Ej\xdfI\xc3R\x13\x93{c=\x14dh\x1e\xd51\x04\xe9v\x0ca%w\x1a\xf3xm`\x1e\xd0\x14Q\xfa\x9fA;\xc8\xe6\x18n\xdb\xfcG\xa3\xc8\xaaH\xb5\x12c\x03\x07\xd3(\xc2\x95\xa8\x1be>\x9b\xd8\xa0F!<\xd2\xb5R\x83\xb8\xabF-\x84\xf1\xc9\xbc\xae\xfa\xfaF\xab\xf5\xd0\xc2\xc7\xf1\x8a$\xf3l\xec\xd0'\x13O\xc8\xcb\x95\x84^\xcb\x8bt\xad\xd4\x81\x81\xb3T\x0b!\n\xd3\xca\x9cup\xa9uYq\xe9m\xa9\xe3\xbd\x81\xf3\xe5e\xd3|f)ca\xa0y1D\xb9\xb6Q\x9e\x18\x99\xf1fAS\x8b\xc7\x9d\xec\xbdZ\xbesi\xfe:@\x8a\xd0\x00\x95J\xccz\xbd 4\x14\x87j\xb3\xceS\x8b\xb4\xa2QOm\xde\xda({\xde#\x051\xd6q]r\x81\x8bV\xd7Q\x05\x0c\x95\x80\xc5a\xcb/e\xaa\x8d\xcc\xef\x86\xaa\xb8\xb9;>\xba\xa8\x16R\xc5J\xdc\xa6\x9bH\xab\\zS\xe8\xd3K\xfeV\x19:\xad9\xb8\xc5\xe7\x01\xe6,\xcdGLQe\x937J\x96\x8c\xdc\x99\x10)\x8a\xce\xea\xf8\x95\x9c027g \x85{R\x83\x1c\xd4\x1a\x16\x10\xc3@\xc0\x97/\x90\xb8\x18\xb0\n\xc1\xb6C\x87\xabD\x0bqF\xda\xb1i-\xda$\x1d{\xbez\"h\x91\\\xaa\xa0\x0c\xa7\xe4]\x1e\xc6\xc6h]j4=\xf3T\xf2\xa5a\xf4t\x9e\x8aX\xfb\xe8\xf1-\x0f2r\xcbx\xf6qq\x9fN\x9b\xa7\x8f=)Y\x93t\x042\xa0\x935\xdf\x82\x94e8c\xc4GP\x90\xb0\xcc;\xcc\xe4\xd2$\xc3|\x8b\xb0\xf8\xc4OQ\xf6+`\xc9\xa8\xdb[\xbfmb\xe4 .:\xb3\xcck{\xf2l[\x05\x03\x1d)\xde6\xf7\xc0Uba\x85\xb0\x0f\xce*\xe3\"et\xf2\xc1\xb6VTo\xad\xd0\xe3&\xe0M\xd1\x88\x1bz\xec\xd0\x1fH#}0\xc4\x95\xfb[\xa5\xbf\xa5Hf; a0\xecM\xab\x86d\xe5\x85\xa8\x7f\x7fBus6`\x8f\x82t\x83\xde\xbbO\xa1\xf2\xff2\xed\x00\x8a\x15\xecA\x18L \x8d\xe6\xf6L%f\x12S\xd5\x01`\x98\xed\xe0\xc2\xc0\xe3\xc8'\xaaD\xb2\xb8\xfa)\xec\xc3?\xbe\xc2\x08R{\x91\xa9\xbcT\x14:\xc2f\xb5\xa0\x0fh, 7\xe6mXd\xdc\x91\x84\x98\xa2\xc6:7\xc2tB\x99d\x11\x81\xf5\xb3`w'\xd8\x810\x8b\xe16IS\xb8!P\x90E\xbe&1$\x19\xac\x9f\x07;\xc1\xce\x1bX\x95\x04,r~\x11\xd0s\xc3\xf1|\x0ep\xb6XW\x0c4\x18i>\xedRv\x8e10\xd9\"\x8fI*/ZN\xc2\xa8\xe8\x88*5\xc7\x12\xd5\xcdVO\xee5\xe6\x16C9\xce()\"\xb2\xa4y\x87R\xf5B\x94\xe0\x04\x8cR\xc42\xcaz\x95\xeb8?y\xe5i\xc1\xad\x9dG\xf0\xfb\xf6\xca%x\x1e\xac\x8a\xd4\xaa\xfe\xc5&\x8fq\x15\x11\x83\x88wIFNW\x8b\x1bR\xbc\xcd\x0b\xb4\xcf\xdb\xb7}h\x86\xdd0\x84\xc2\x90\xcf]\xd5\xcd\x0bZ\xd8\\w\xcb\x1b\xb7\x0eT\x8f[\xca\xe8cH>\xac\x8dN3\xe4\x9b\xb0$Gyd\xe5\x1dA\xb8\x00mB\xc8\x08b{\xf6&x\x8c\xa0c\xd3\xb7ac\x04\xeb\xae\xec-\xc0\x18\xc1\xc2\x98\xfd\xab\x17\xd09\xc9\x06\xe8WA\xe3\x8e\x95M\x98\xbd\x03\xec\xe1\xf6\xad\xfc\x1a\xd6\xae*\x9eL\xc1Mz \x0c\xa8$\x02\x0e\xba\xf3\xcf\xcc$\x06\x082\xa3y\xfb\x9f\xe1\x1do\xa6(\xd6t\x0d\x11T\xe5\xbc\x81\xda\x9a\xeac%K\x08?\xcf\xd9\xa4LWi*\xb6\xc8\xcc\xbd\xf3\x95\x14i\x15\xc0\xd2\x96\xdc\xc8\xb5\x91\xbd~ \xfe\x9a'\x99\xeb\x04\x8eZ\x04)\x15FU\xcb\xd8\x93$\xa0\xdcE\x9b\x9c7\x1f\xb5s\x84\x8b iu\xccr\x9a\xef\x93\x89\x0f\x8e kz\xa3?\xcb\xa7\x11\xcf\xaa#\x10\xa8\xfa\x08\xb9! Dc\xbd\x85\x86X\x01\xda\xa1\x8e= #\x13/qV\xc6E\xf1#j\x99\xe4\xdf`9XhWfvS\xaaVr\xcb\xfc`r\xa5\x1dGo\x85>\xda\xa2&\xc6\xd8kZ\xbf\x96\x15Y\xcdh\xc7\nh\x81X\x03\xdfQ5b\xa8\x0f!\x0f\x80\xe2C\xec\xc3\xdc\x87\xb5\x0f\x0b\x1f*k\xdf[\x1f\xc6V\x85\xa1\xba\xed\xdbb\xd0\x86\xc1p\x0bo\xdexP\xde&\x9c\xca\x0f\x96\x05F\xfc\xe2\xc1\xd0\xbb6Z\x14\x96\x04vF\xddk;\xe5\xe7\xd7\xdf\x82\xf2\xae\xa4d1d\xe3\x12\x19\x8c\xf1y7\xdc\xb0\xe7\xa6 a;\x92\x9a\xfa\xd8\xc1\x05lH\xc2\x89\xc9\x8d\x00\x1e\xe9\x05`\x04q\x9e\xfd\x9e\xc2<\\\x13\x08\x81\x0f\x06h.\x0c`\x08\xe4\x99\x0f\xe1M^\xd0$\x9b\x05\xdcaQxS\xac\x96h\xe2\xc1\xda\xb0\x05\x07\x069\x93\xcf\xfbg2\xd3yQ\xc1\xc6\x92\xa2\xa8)d\xc1\xb1N3\x1fi\xe2\xbc\xa2\xf2\xf8P8\xef\x97#E\xaaS\x9e\xa1\xa4\xfc\xade\xee9\x04\x94\xd6\"R\xe8`\xacK\x0dw\xf3\xb6\x87U\x1eb\xe8\xd4\x14\x91\xf0\x12\x91\xf0\xa2\x1fh\xe1\x1bp\xb0\xe9\xf9\x16\xbclz\x86\xe0j\xd3S)\x14\x8au{\xeaw\x99\x1b\x9a\x1el\xf9\xe9\x83[\x0e9\x91K2\xea\x0b\xb6\xbc \xe5*\xa5'\xe1\xd2\x17\xbc5\x83\xf2_\x12:?\xe4\x0e=%\xcaV\xa0\xed\xa5\x0f\x89\x9b\xe2\xf9z\xbfi\x93O\xc5tL9\x1f6\x8c\x96\xd2\x1f\x13[r\xf7\xb0\xaat\x96\xe5\xe6a\xd5\x98\xd8\x19\x83\xa2\xd2\x90\xc7\xc8\xea\xdc\xde\xbb\xaa>bQ\x7f\x10\xbc^>\x18\xbc\"\x05\xbc\x96\x88x9\x9f\xc4\x8f\xba\x88sWP\x04a\x9a\xe2 R\xba\x1e\xf7f\x86\x8c\xcc\x10n\xc9\xf6\x0c\xe4\xa2lO\x9b\xbbZ\"w\xb5\xd4\xcc\x16\\.\xa1\xb8?\xfbdz*l`b\xa0\xe6\xee\xfa\x7f\x1b\x03ez\x1e\xc2T\x99\x9e{3Z\xa6\xa7\x9f\xf92=\xa8Pm`\xba\x16\xd2\xbd\xf6\xac>WW\x885\xe3\xf6\x87\xb4\xfa\xd0\xa2\x83\x1e:\xbd\x15f\xef\x94\x10u=\x96\xa3`\x04\xf6\x08\xf0\xb6\xe7A\x88h\xf7\xfb\xfba\",\xe4\x90,v\xeeW\x0e\xd4\xcdX\xd2|i\xf1\x91cz\xba\xa9g\xf9|\xc5\xe8\xf1&G\xb6\xc6\xdc6\xc9\xa4\xfa\xb4\xae\xf0z|)\xa8O5Xs\xd0\xcf\xde:\xba\x07\xfd\x95Q\xc3\xab\x8an\x13\xb8d\x00bW \xd6\x9d\x9a\x9c\x0d\xbb\x93\xab\xcac\xcfR\x9a\xd0\x074\xff\xcf\x8b!D\x84\x15\x9c\xa7\x8a\xc8X\xd4\xd6=\xc0\xae\xf5\xe1\x90\xdb\xc3~\x8e\x95\x83\x92{-\xafxz\x1f\xaf\x8dx0\x10I&>\xed\x06\x07\xe4\xf1\xfaz\xf4\xba\xbbG5c\xf1\x1aO\x87\x1d\xec!^V\xba\xbb\xbb\x9e\xafK\xfe\x02j\xbb{\x80\x8aL\xed\xa1Sc\xb3\xa1\x83\xcb\xc6>\xae \xd3\xdef\x9e\xd9\x9b\x19\x8a\x11\x86\xec\xfe6\xd0\xab\xbb\xda\x87\x89\xb1\xd4\x841j\xbb\xaf\xafZ\x1f\xaf\xda\x0e2\xe0\xd9\xf7\x0d\x9d{\xab\xb5\xc77^\xec\xffM\xc6\xc1\xf4+\xa8\x03\x0cC\xfaV\xf7LX\xbd}m\xdb\x02\xdc\xd3\x11x\x8fJ\xdcy{\xff~\x8b\x8e\x9fT\xd8l\xaf\x99m\x80\xfe\x10\xdb\x1c+o\xfdO\x1a\xdd\xc4\xe2\xc0F\x0cO\xc5\x83\xf7\x1bi\xcb0\xe9[\xd6\xee\xf0A\xa3\xab\xb4\xa5\xcdC\xe4.\xc1\xef\xbd\x84]\xf6X\xdf\xae'\x7f\xf1\xcf\x18\xe9#\x98\x13\xf0\xb058\xea\x9f\x85\xe9\xc2\xf0iS\xb7v\xd3\xbc\xed\xc1j\xae\x03&\xa5_=\xd7\xfc\xb9`'\xb6\xc9\xcd\x81e\xc9>uAK\xc3\xb8\xef\xbf\xe7h\xffv\xaf\xd1\x1e\xf4\x8c\xb6e\xe0\xf8\xbfa\xd0g]\x83n\x18y\xf6\x1e\x9c\x1d\xe34\x8c\x857\xff\xbe\xab\xf9\x96\xd9io\x17\x86*\xe5\xd9Tn\x8aa*{\xf9P\x95\xbd\x95&\xeb6\xe7\x12\xf1\x06\xc3\xf2YOu)\x12\x96\x0c<\x18\xca3\xe7\xe1r$qW`\xcc1\xc5\x1c\x95\x8e\xa8\x05m\xc2\x1e\xacl\x9c\xc1\xfd\xb4S\xac\x9a)\xe6\xec3\xbc0\xe0\xacD\x9b|M\xa6\xe0\xce\xe0\xc9\x13\x98)\xa1\xc7\xf4w)y\xd2\x93\x85{\xd2~\xf1\x93\xa4iY\x0d\x1bBK\x86{\xc7\xaa\xcf\x89\xf6\x1e3\x98\xa5w\xc6\x0b\xcf;\x1d\x07\xb9\x93\xd4\x87\xe8\x8am\x84\x8c\xad6\xd2X^\x17\x9bJ\xd4)\xd9k\xbe~\xf9b\x8d\x1f\x00\xca\xd6P\xcbLx\xc3\x1d\x1e\x0c\xdd\x0dt\x0e\x8e\xa1\xfcv\x84\x8b\xa52\xf9;w\xda\xe1\x9a\xea\x82=p\x0c\xbe\x97\xc0\xcc#\xa0H\x07\x83\xc8}\xa6\x1f\xaa\xc8Lq-\xfa\x91\xcaH\x01\xcd/\xd0\x12\x96\xb1\xcf\x02<*\x00?\x8eQ\xc8\xa7\xbe\xefi\xdfG\xbcP\xca\xfeD\xa2\xf3\xcd\xfcY\x90/\x8fcw\xc6\xefc<\xd4)\xe5d\x96k]\x136\xa97\xb0\x07)l\x823r`\x13\"\xf3\\2v\xb6\xe0\xb1>\xca\xa0D\x1c@\xe2\x0bLro\x90ko%w\xe8_]\x8bjX\xbe\x9f\xc3\" oR\xd2\xa5\n\x05\x18,\x9d\xe5\x1eU=\xe9\x96\x08\xb0\xa5,\x97aDFpc\xcd\xf8\xb5_\xbap\xfb\x08=\xedo\xbf{\xce\xabv+\xf7>\x15t]{\x12\x91\xec\xc35\x8c\xe0\xd6G5^=R\x1d\x0e\xa2\x9d\xec\"\xa0\xf0\"\xad\xa8u\xa2L+\x9d\x17B\x87!\xdfm\x7f\xe7\xd8\x17y\xac\xb6\xfac\x1es\x9c\xc4\x8b\x9bK\xb1\xc1\xdd\x05I\xf9\x9f\x17g\xa7\\0\xed\xb9cT\x8cW\xab\x81=`\x19\xb86\xbc;\xf6F0f\xfba\x8csi\xc8<\x16\x93\x0c\xa3\xf6\xa7\xf6\x86n\xa5\xb0\xa1|\x163\xaf\xb8\x01\xf9\x07z\xe6m\x8f\xe33\xee\xc4\x9bU\x92J2\xcc\xfd\xec\xf9P(\xc4\xa8\xab\x1c\x90\xf5A\x08\x9f\x0d\xb5\x11\xc3\x11\xa6R\x19\xbd\xfeq\xd7\x0d!\xe0\x84\xea*:\xea\x93\x9bG\x99u\xab0\x16m\xc2\xd32\xc0\xbc\xe1\x9bD>_U\xf8k\x0e\xd3p\x97\xcc\xc6u\x01{p\x14R\x12d\xf9mG\xa8\x9bLRg.\xd1\xd5\x05\xad\xd3F\x83x\xc5Qj\xa3\x0d\xd8\x82\x8bj\x0dyO-c4\xa8O}\xf5\x84\xa0\xad\xbfyuJ{\x1a\xea8c\xb9\xf6F\xd7}\x0b)\n.^\x98\xab~m\xccg\x9ei@\x8d$\x0b\xafI\xdan{\xf4aK\xf5\x04\x83\xa3\xaf\x1d\xab\xa3\xaf\x9d\xa6\xa3\xaf\x9d+T\xe37P\xef\x15%\xda\xfe\x96uR\xa0\x89\xd8\x07\xb9b\x9e\xc3}\xfeP\x0c1\xc9\xcb9Wf\x1fi\xdd\xa4\x9bT\xd2$\xc14\xebR\x9a\x0f+}\xd5\x01\xf4;\xe9\xe7\x07\xca\xea\xf6\xdf\x16\xa5\xce\xed>\x0c\xb9\xfa\x80\xe6\x1d\x8b_K\xd8\xa9\xfc\xb0\x1d_W8x\xednl\x8a\xf7\xc9\xed\x03\xcb\xce\x08D\xa6\xa3\xca\x9c\x9d\xd1J\xdb\x9f\x17\xe9v\x12P\x86\xac\xa6\x96N\xccq\x00\x15\x81\xd8\xe8\xbe\x0f\xb1\xfd\xec\x16\x80\xb0\xd2\xb8C\xd4},\x9a\xb85\xb1md\xa1\xfcm\xd1\xbf\xe7\x8a\xdf\x96\xa5\x96\xd8\xa2\xdfb\xd8V^\x92\xc4V\xednS,\xdc\xa9\xa5\xab\xc2\xb4\xd9b\x9fa\x0c\x97\xbb4\xa0\x1c+\xce\xc1_=\xce\xa8H@>/\xf3\x02\xfd>7\xe7\xbb\xb2\xf1\xcd\xdc\x97\xcf\x9ej\x90P\xdb\x087\xbdO\x19\x9b\xb4\xb57@,\x89\x91]\\n\x00\x12f\x11\xbaUD\nKA\x80\xe8\x11\xb4\x80$\x03\xe2\x01\xde\xea\x03\x9b,T\xb4p\xd1\x1f\xeb\x08\x92,\xca\x8b\x82D\x14\x92l\x9ds\x07x\x1b\x16W\x8e\xe4~3hv\xe7U\xd9(\xb9\xaf\x9f+\xcdT\xc3\x0f\xa6CD\"\x19\xb9\x1d\x805Y\x8f\xda{\x8d\xd15\xc1\xb2\xc8\x17 \x8a4YUdX\x9096\xe9\xca\xfcRm\xbe\xb3\xf6,;?\x861\xbc\x17mEyV\xd2b\xc50\xb3M\x97\x11O \x1f\x0f\x1b\x83\xbc\xd6\xf3y\xe7\xc5\x05*\xcb\x84\xbe\xe5D\"\xa3~1M\x0b.\xf3U\xb5;\x1c\xb4t\xf5\"}\xbfcZ\xa4\x01bB\xd4\xb0\xe3GW\x921\xd8D~\x9aLrv\x16\xe3\xbf=\xa0\xec\xdf\x08\nVG\xee\xe3\xeb\xbf\x04\xf2^>\xdf\xb5\x8c\xaax\x8c\xea_\xbd\xb0\xd4\xce@M\xd7g\"\x9f\x97i\x12%t\x04\x13\xd6\xb1\xe7\x8c\xe0u_>\xff^\xfc\x7f\xe1\xa9\xdeP\x1f\xde\xbb\x0eJR\x99\x97\x17\xbb\x167\x93\xec\x9b\x8e\xea@\xd0=\x9a\xc7\xca`s\xeb\xea\xbb\x91\xb7\xef~\xdc\xfe\xb8\xed\xed\xbb\x93\x8f\x17\x1fK\x0c\xc9\xd9.\x1eb\xf1\xc9\xc1\xd6\xff\x1f+\xe0\xffw\xb6^on\x05W\xdf\x8dX\x05\xdb\xedB\x8c|\xb1\\\xad:\xff\x86\x9e#\xc3r\xae\x87\xf3\xae\xb3\xec\xb3,\x7f[\x91\xe2\xce\x9eg[\xfatDG\xca\xd6l\x7fd\xd9\xc2\x15\x92x\xbb\xb6\\\xa7\xe1)\xeb\x13\x8fH.\xaf\x86w;\nl\x8f\xdc\x8f\xf1\xa6\xf7\xef\xdb\x18\xc8\xbch\x14\xebo\x04{\xac5\xd4*c\xa8\xa6}\xce\xc9\x87M\xe7\x08v\xcd-\xe3D\x8e`\xb7\xf5Q\xf5# \xaa\x9b\x8d\xd4\x8e\xaf3\xaepo\xb3\x94C\x015\xfa\x83s+\xc3m\x1a\xa4\xe2\xd4\xe2\xc2@\x8bp\xd5\xb9I\xf3\x9b\x91#d\x9e\xcb\"\xa7y\x94\xa7\x1e\x87{v\x96\xb8\xab\x8c\x94Q\xb8\x94\xbc\x13\x9bF\xcf7WH\xd2\x92\xe8\x8e\xea\xf6t\xf7\xd8\xf2A<\x981\x1cX\xb7E\xb0b\x1fJO\xeaz\x14\x93\xcc \x91\xac\x1bR-\x99\xad\xda\xd6uS\x84\xa1\xdb$\x03\x94\x90\xba\xacr6_\x93LG\xaf\xf2Ql\x14\x8a\xa0L\xc3rNP\xfc\xec\xd6o\x8c\xb0\xa5\x9cQ\x9f\x17dj\x8a\xfa\xd3J\x91\xbc\xe9\xef\x9a\xd9\xccp\x11u{;\xad\x02\xfaZ\x89g\xf3\xa4\xc8\xb5\x1e\x01\xe5\x0e\x9f\xd9\xbf\x80\xe6\xef\xf2[R\x1c\x86%A)\x8fc\xb1v\x17\xa3\x1f\xc1\xc6\x06\x9d<\xb5\xec\xbe\x82\x94\x94U\xff\xac\xbd\xd1\xf4+V\xf3\xd0\xa7\xb6C\x14*J\x8f\x1d\xf1*\xb17\xad\xbdPW0E\xcd\x82\x176\x83\xdc\xec\xa9\x94\x1a\xf7sn\xc1\xb0\x12\xc1\x91-\xdc\xcc\x02j\x97\xdd\xe6\x1c3\x96c\x9eX\xb8\x8a;\xd8\x83\x9dv\x7f\x10L+\x88f\x84\xd3\x02\xad\xf5\xe5f\xaaR\xb8=\x8e\x8f\xcb\xcf\x1d@s\"B \xfe\xb3Q\xf50\xabJ\xe4\\\xcc\xe7\xf1\x82)RH\xec\x9c\xdap\xd9q\x13\xb9\x84{.\xf6\xbc\n\x0f\xe0\x85H(A\xdd\x87Y\x03\xea\xe5\xef/_ \xe1\x1eu\x95\x8cU\x15\xc8\xf8\xc9\x17DL\xea\x9b\xe3\xf8\\l\xc1h7\xea7ku\xd7\x93\xa7l\x83N\xb6\xdd\xe0;o\xbbq\xf4xo\xe0\x0e~\x80\xb5\x10s\xbc\x81\xbb\xcdM\x0f\x91\xb5\xcbx\xd8\xf5\xe4\xee\xca\x9b\xec\\\xf9\xdc\x12{\xb2{\xe5C\xc9f\xa5\x84}\x98M\xe6\xb8\xef\x19|\xb7]j\xb2\x1c\xff\x8f\x1b\xa3,@\xfaX.=~\xc9\xe1dh\xfe\xa2f_\xb2>\xee\x83++\x15\xa0\xb3#tT\x95\xa4\x1861\xb7\x87A\x87\xb5\xfczf,\xcfs\xc6(\xfc\x15\xbb\x9c\xf7C\x14\x8eq\\z1\xdek\xcf\xf3\xe5@\xf1\x9f\\\xa5\xe5\xe4\xd9\x15\xae\x96Hd+\xb0\x9c<\xbfR\xebe\xff\x9a\xa8\xc0\xb0}8`\xcd\x02<\xe9\x90\x14\x12\xbf=\x84+\x15 @\xf1c?\xab\x8e\x91 \x9a\x87\xc5\x01uw\xc4\xdc\xea\xdfy\xef8GQ\x9f=\xa2\xd5*\xd3\x00?\x11\xa0\x92\xdd\x18\xe9\x0c9\x14g\xdb\xf1\x82r\x99&\xd4\xe5?\xe5\x0cn\xedz\xd2a5Q2x\xbep\"\xc1A\x8e\x1b\xbce\x93\x02\xb6\x18\xfd\xc1\xb7\xd2.7s\xdby\x03\xc5\xd6\xd6\x1b\x0f#{\xe0M\xd9\xa4\xb8B\xcf\x19\xac\xba\x08#\x13\xec\"~\x0d\x9a\x19\xdcf\x0e\x1fB\x06\xd6#\xee\xb7\xc3\xdd\xa9\x03Z\xb8 \xf7j\xe0C\xab\xc4\xd6V\xb7\x94\x19\xd7&\x0bVY9O\xa6\xd4u\x1c\xcf\xc7~\xb2\x89\xceq\xa9\x82\xea\xed\xcb\x17\xc8\xb8\x0e\x1cf\xcb\x84\xce\xfc\xb6)\xa2\x8a\xb2*\xbe\xbabl\xde\xd8\xb7\xbc\xa0*f\xe0\xfa\xa93\x19a\x97\xff\xe0\x85yf~{\xc8\xdeV%)\xc4b\xb36\xca\xf26/b\xfc\xcc\xbe2B\x13\xa7d\x89\xdf\xd9\xab\\\xb5Q\xab\xfcr\xb2S\x81}\xa3.\x86#\x04\x02d_\xf2\"\x99%\x19oP\xc1\x86\xa2\xbb\x88l\x93\x94\x8c*\x98\x95y\xf6\xd5\x97Mp\xb6\xb7\x1d\xd8\x94\xc5F\xe00|\x8dM3b\x01\xab\xaf/3\xb53Q}\x9b\xf2J\x85)B\x1b\xc4KBG\xbd\xac\xa7|\xf0\xe0\x13'\x94\x19R*\xeb\xaf\xae\x0bh\xae2\xca9\x86n\xa5\xd1\xdeX\x17\xd2\xdd\x84\x8b\xd4\xaa<\xa8x\xa0\x85d\x82\x17\xc9=\xe6_C4{9\xd7\xd0c\xee*Zc0K}H\x14p\xdd\x17~1\x12 \xb2I\x05\xb2\xd5\x95/\x0f(o\xc8Q\x8d\xc3\xe92\xd7\x84\xa1#\xa98\x9a\xa1\xa3I\xf8\x96\xe2\x13\xbd\xb9'\xba\xcbS\xd9$\xcb\x1e?\xc64#O7\xb4c\xdb\xa3\x8f\xf1\xe6\xbfos\x1a\x9a\xb2Yv\x85\xffxe\x0b'\x12!\xd0`\x99/\xdd\xaa\xc3bSS\x81\x96F\x8e\xa7\xcc\xbf\xfc\xa8\x14\x7f\x9c\xc9\x97 \xd17F\x95\x08\xa2\xcd\xf3\x94\xf5\xa9\xa6\xa56z\xa2N\x0f\xeb\x95\xa4\x8d\xfa\x94\xbcQ\x0c\xd0o\xf4=\xc8\xd6\x13\x0dW\xd9\xc4V\xad\x0b'3\xfbx\xe0\x8f\xc0\xf97\xcb\xb5\xb6\xfaHhP(\x82\x0da\x16\x1e\xb2M\x05&\xe5V\xf5\xf9*X\xc2\xc7@\x15R\x8c=\x08~\x8d\x99\xccF\x1f\x15\x05Rr\x02\xa1\x84\x1f`U\x91\xaf%;\xe7\xed\xf3\xcd\xca10ZM\xca\x0e\x0d\x9dT\xd2q\xc9$\x9d\xec^\xb1\x1e\x8a_\x1a5w\x8fnK\xa2\xa1>\x11\x93\xc6\x89\x98\x18O\xc4D=\x11\x13\xc3\x89\x98\xe8'b\"O\xc4\xa4\xa1\xde\xd3\x0e\xeei\xba\x9f\x14\x05F=\xb2o@\xd7vMNI\xf1\xa5\x8f\x04\x89\xf0\x8c\x84\xf5%\xd3\xbb\x0e\xcd\x1b\xca\xe5\xd1v>\x0f@\xc6\xc9\x95\xe3\xb7\xd0e\xd8%1s\x85\xdc\x04\x85<\x1c\xb7\x18\xa9\x88B\x07\x81\xb8;\xfa\xc4\xe3\xb4n\"\x1d)\xd0\xcb>\x9f\xf2\x91\x1d\xf9U\x97\xfc\x15\x9d\xc4 \xcc\xcd=%\x8d\x11\x7f\x15\xb9T}\xe7\xc7H\xfd\x05I\x7f\x96\xfeGG\xfe\xcc\xf8J\xf3\\\x92\x10\xcf\x87\x8d4X\xa6\xabY\x92\x95\x93\xec\xaa\x0biR\xb9\x86\xe35\xc9h)\xeby)\xeaQ\xab\xe9>5\xe4)G\x03\xb2\x167\xab\x1d\x1e\xad\x14D\x9fd\x10z\xb0r\xc3Iy\x85\xeb\\z\xb2\x17\xaf\x1c\x94;\x19<_\x82\x11\x17\xab\xd7\xb4\xed\x95\\\xd9h\xfe\x94w\xf94\\\x90\xa3\xa4\\\x864\x9a\x0b\xedd\xb6\x19\xcen\xb3\xcaP\x99{\xc9b]{\xed\xa0*BGY!8m\xceA\xad\x8f\xb1\x9c\x87%\x89\xcf\xc9,))\xd7q`uhS\xc6A\xcd\xb0|\xd5\xfc%l\xfe\xacR]\xaeS\xab\x0d\"\xf1<(\xdd|\x92\\\x89\xe9\xe8\xd9\xe9P\xa3?=\xae\xed\xefLy6HPh\xc3B\xfcR\xba\xed\x0f\xa2\x07>c\xd3;\x17\xaf\xb4/\x9e^'\xbfB/\x19\xf5\xc1\x17kwg\xa7\x02\xe7\x8e\xccH\x06\xb7s\x1c\x91%\xc9b\x92EI\x95M\x01\xf1Iv\x15\xc4J\x0ee\x10\xf2\x97\xa4K\x9a\xfd\x16\xfb\xaam\x95e\x83\xa7\xb6\xda\x91e,\xfd\x19\xd5!\xb5s/\xf3\xb2LnR\xd2\x82M\xe1\x01\xa0 \xa1\x19;\x9e\x10y\xbc\xc7\x11a\x8c\xc9>\"#\xafVf\x97\x9d\x81u0\xba\x8a\x83\xe7\x92&~0\xb0\x95\x0bu\xd6\xbf\xa7\x1b\xe5\x8fw\\)e\xc0M?\n\xa5,\xb2f.\x0e\xc3k\x11\xeb\x0e#m4\xd1G\xa7\xe6\xe2N\xc5\x8e!\x133\xeeI\x10\xadH\xb9\x93\x8b\xafr.\x9f\n\x9c\xc4\xf3\xe0\xad8\x17\x80\x0dD\x9fH\xa1\xf6L\xf4\x8c\x88 \xe6\xc0\xf66/p\xd2\x87\xce3 \xe2\x06T\xb7\xc7\x8flUk\x13V\x17\x16\xf6\x1d\xdc.\x84\xb2*\xb3[g]\x1b\xc3\x86\x8e\xbbNqn83\x08\x8f\xcb\xa7\x02)\xd4\xac1`^\xf9\xe0\xc9\xaeC@\xd1 V\xa0\x80\x96}\x96\xb2Iq\xd5\x01uP\x1f:b\xc2\xdbQ\x85\xe4\xd3u\xfe\xcaG\x92\xcd\xab4\xed\x82\xaa\xeb\x82\x94\xa4\xb1}Gv5Nh\x11[\xb9\xb8\xe4A\x8fg\xad\x8d\xc3\xe5\xe1\xe2\xb2\x94\x91]\xed\xe1Wd\x8e\xe4'\x8c\x97O\x12\x88\xedg~\x1f\x12\xa1\x1e\x0f\x9e\xdb\xde\xd7\xa2{\xd4\x88\x13$Yk]\xd6\x8evC\xbc>\xf6\xa0\xd0\xdb\x0d\xd5v\x8bI\xd8\xbc\x804j\xd9\xaa\xf4;_\xcf\x87S\xe9\xdc\xa3\xa2\x99VG/\xd0\xee\xd3\xdd\xa7\n\xdd+Hw\xf7\xb51\xfe\xc6\xaaC\xdd\xad\xa6\xb9P4\xfc\xe5\x0b8\xab\xecS\x96\xdff[\xb8\x8e\x9a\xf0\x85\x04\x11w\xe9p\x19\x163B\xf1biF\xe8i\x1e\x93\xb7E\xbe8\x16\xf7\xa8n\x81\x97\x84\xfb\x10\x06I\xb6\xce?\x91?\xad\xc2\"&\xf1a\x98\xa67a\xf4 }Cp\x7f\x99\xd8-\x82W\x14\xe6\xbcU\x16\xdf\xd0zc\xef4\xa9\x8a\xb6\xdeER\x8e\xb38)\xe7}\xf8X\xecK\x87\xe6\xcb\x93|U\x92\x0fK)\x94b\xd3C\xf3\xe5e\xbe\x8a\xe6\xe3,6%\x1f\xb2\xf1\xa7\xe2K\xd7\xb6N\xca\x93|M\x1e\xd0\x1dV\xcc\xd4\xb2\x92\xde\xdd\xee\x05\x0d\x0b\xfa\x80\x86\x8f\xf2\xdb\xcc\xd40\xd67\xa0e\xa1\x82{\x94\x14$\xa2\x129\xf4u\xa2>\x1c\xaf\xe5\xe9\xf8.))\xc9\x88M\x0b;k\xe6\x960i\xc0\x03M?T\x94\xd3\x10\x8cXx\xe6\x18\xa1\x8dA\xb4\x19\xde3\xcf\x18\x18\x18\x14\xfc\xc4\nS\x97\xd83J\x95<#\x90\xfb\xc6 0}\xac\xc6[},\x06-\n/M\xca\xe36\x95j\xb9\x16]WV\x80C\x97\xa6\x18\xbc4\xec\x9c\xd5\x9d0w\xe8\x01I4\xb6\xf3\x06r\xf8\xa1v\xd5\xfc\xe4 l\x90 )\x19b\x0fg\\[\x9e\xe6\xcb%\x89]\xef\x0d\xe4\x9b\x9b^\x8d\x1d'\xf9\x95\x0fE[U\x12\xa4\xc2\x10^X7\x90\xa9!\xe3\x03W\xe9!K\xc4Fr@/\x8b\xd5`J\xbe_\xbay\xff\xed\x06\xf7\xdar`\\[\xdaI\xbc)\x84!\xbf\x19\x87\x1f\x1a7\x7f\x1d+\\lnv;\x18B\x8azR\\\xb1Ue\xe4\x9f\xa2\xfd3)\xdajG\xa0\xdc\x15\xa0\x87\xe0'O\xd8\xa6\xe6\xc1\xb3e\xc1n!\xa9\xbe\xd8Xe\x97\xfaU\xe7\xde\xee\x847\xda\x05U\xf3\xb0\xac!\xaa\x0f\x80\x14\xf1E\xbb\xbd\xaeV0\x9e7\xef4C\x98\x0cq\x0el\xab\x08\x0ce\xf5@/\xed\xd6t\xd4|\x9f\xd6Zh\xbd\xbb\xb5\xa4<`k\x81\x0e#{\x91\xa5\xe4\x18\x82\xba\x14\xcf\xdb3\x9ew\xf9-Zw,\x16y\xf6\x90\xe6,U\x0cj\xfb}\xc8\xce\xa1{\xce$6\xd9,\xd93\x8f\xb4\x08\xd7\xa4(\xc9\xe5m\xfe\x9e1\x8c\xc3\x14\x11\xaa\xe6\xf4\xe2U\xa1!m\x8e3J\x8aw$\\\x1bZE\xd7\xe6FYu\xab\xed\xba\x1a\xadp'\xfc\xa0\\&\xc93\x93g\x0f\xfe\xf10_,\xf3\x8c\x11\x03\x05\xe9]\x00\x90'l\x1b\xbf\xb4Q7\xaf\x9fU{\xc9\xc7\x10\xa6C\xea\xcf\xcd\xf5\xff\xce\xfcfa\x8f8\xc6x8{\x042 U\x95\\\xf1:\xb9\x0dd\xcc\xb1\xaah\xcb\xa4\xa33j\x14kUQ\xa1\xc2\xc9\xee6\x86\x02\xe5^M\xe3FL\xccN\xcb\xca\xac\x9b}je/\x08\x1a\xca\x1c\x86\xab\xd9\x9c\n\xd7\xe1\x9d\xb2\x02v\x8aY\xcdr\xd6\xc2&\xd4\x12\x14\x86\xdb\xe4\x14\xf5Y\xf4\xadp\x91<\x1c.\xcc\x164&n\x97S7\x94\x13\xd7_\xbe\x00 \xca\"\x1a\xa7dA2|\xbfM\xb28\xbf}\xa3O+\xdb\xef4@\x9b\xaer\x99gq\x92\xcd>\x94D\x96\x93\xfaG\xd6\x1c\x9e\x0f\xcfxh\x9c \xcbc\x82F\xfd\xfb<\x8c\x1c\xc9\xf0\xe0i\xe8(|\xab5\x8e\xd0-t\x9f\xaa\x163y\x10\x85\xd9\x87\x92\x1c\x9d\x9dT\xe0\x1b\xe7\x11\x1a\xef\x06\xc9b\xc9{\xca/'\x9f<\xb1}\n\xe6a\xf9\x96\x84tUH\x7f'\x1b{\xd6z\x94\xcc\xae\xe3\xf8\xa8\x1d\xdc\x98\xd9\xed\xef\xbekB\xcdwp8'\xd1\xa7\x92Af\x98q\x81?$%\x94\xab%[_\x1e\xc0\x89\xce \x08.IP\xc7\xe82=['E\x9ea7\xb4J\xf56N\xcf.\xc7#\xb8\x9c'%\x8f\x0f\x95\xe5\x14n\xf3\xe2\x13\x08\xa3\xbd\xf4\x0e\xa9\xce,\xcf\xb6f\x8c\xc6I\"\xde\x13\xd6\x8fh\x0ea \xbf\xf1H\xca\xbf\xf9z\xd5\xbf\xa1\xb8\xee7\x1f~K\xf30f\xff\xd1\x08\xfc7\x1f\xa3Q\xfd\xc6\x1ds\xfc\xd6\xd7\xc1\x1f\xf3\xa2\xc8oK\x98\x16\xf9\x02N\xf2\x98\x14Y\xf2\xf7\xa2\xaf\xd4\x1f\xd1^\x14\xfe\xc1\xb5\x0f\xbe\xd6\xd7%\x17\xab\xe94\xf9\x0c(D\x84L\x98\xaf\xcf\x02p\xa24\x89>9z\xbdUE\xfb7y\x9e\x920chq\x89K\x8e\xab\xc3\x16\x07\xd7@$\xa2\x9c\xb7\xb1J\xed\x1a\xa51AU#c\\dE\xedenW\x90\xb036\x0b\xd3\xd6\x874\x89HV\x92z\x9a\xe0Y\xb0\x13\xec,\x0b\x02\xee\xe1\xaa\xa4\xf9\x02~\\%i\xec\xc1\x1789\xbe\xd4\xcao7\xde}\xbb-\x9e\x8eL\xd0~@\xddS_\xbe\xf0[\x82\x0d\xd7 \xe3\x18\xe7Z\xd2\xc8\x0e\x83Z\xb9GjVA\xbfY\x91\x1c\xb5\x93g\x0el\x9a\xfc`\xa1PP\xad\xecM\xbbOF\x92e-\xae\xa0\xab\x8d\x1a\x15$\xa4\x12=\xb9N\x9c\xacM\xea\x1daP\x12z@i\x91\xdc\xac(q3\x1f\x84\xb3\xe47\x8e\xd0\xfe7\xaa\xc2\x84\x93\xcc&2\x05\x85\x9d@Mb\xae\xbdr;'\x95\xd8\x0c\xa4~\xf2\x10\xac\xc2\xef\xe6\x03^\xde\x07\xe7Y\xb0\x83\xaa\xd6\xc9\xa3!\xd3\xd6\xd1}\x90\xd2\x118aJ\xffL\xee\xf4\x90\xbayF\x8b<\x1d\x81\x13\xd1\"m\x7f?!4\x1c\xa1\xdb\x82\xb0\xfd\xf1b\x9eLY\xcd\xa8W\xcd>\xd7C\xb0\xd0:\xb6\x03\x0e\x0dW\xb3\x90&k\x82\xf3\xd3\x86\x12\xf43v\x92\xc7\xc94!\xc5\x05\x0di}\x8d\xd4\xfe\xd4bO%\xa0\x16\xad\x1b\x83\x8aS\xc43dc\x83\xaa\x90PC\xc1\xb0\xf3\xbau\xcd\xf2\x08K\x99\xb9\xaf^\x1b\xd4_2\xf7e+=\xe1j1\xbb\xdcv\xf4\xd9k\xfc\xf7t\xf7\x95\x1e\xfd\x9a\x8b\xe4w\x9f\xeb\xe5W\x98\xfe\xec{\xb3X\xbe4b\x151d\x93h\x92S\x18\x93\xdd+!\\\xa7\xe8\xb5\xf8\"\xb9I\x93l\x86\x1eu\xa6IQ\xd2\xc3y\x92\xc6\x86)_\x8b\xab\xf6\xc4\xedc\xafH\x90d%)\xe8\x8fd\x9a\x17\xc2\xb1D]\xa1q0\x91\xad\xaeB\xd4\xc58\x0dQ_\x8b?3\xe94XM\xb7Z3\xb3ob\xdcl(07+\xeaTaK\xec\x840\x8fI\xa4\xcc\xb8]\xb8\x95\xba\xdc\xee\xba\xe0\xd7\xf7\xdc\x82\xbdCk4\xafh_\xf5\xd1\x88g\x1c\x1cZ$Q\xb4\xdaA\x91s:l2\x97\xd6\x03l\x88\x1c\xae\xba\xcf\x9d\xec\x1a\xee\xdfb\xac\x1b?\xef\\\xf1;v\x12\xf0`\x9b\x08\x89-\x0eK\x0355+\xed\x1eFl\x83\x89\x8e\xe5\xab\xc4\xef\xddK\x87|P\xcfR5\xfbZ\x0cc\xfc\xe6\x0861\xa3\x15\x8b|U\xa6w\xe7d\x99\x86\x11a$?\xe3\xe3N\xc2\xe2\xd3j\xd9DS\xeb\xb6k\x8c\x9e\xf2-\xef \x05\xcfuD\xd2d\x91P\x12_\x92\xcf\x03\x0d<\xe4\x84\x11\x8571K~\xf9\xbda\xe7\xb4\xe6\"\x1c\xe8>\x17\x9e\xa7n\xe1\xeb\x14\x08\xeb\x19\x8a\xf6\x18\xe4\xe4x=\x02\xfb\xe0\xae\xf0\xde\xcf\xf3!v\xf9u(E\xd5||\xeb\x95]-\x8b<\"e\xf9\x01=\x14\x97\x03\xc4e\x0d\xeb\xae\x9d7\x90)\"\xe67\x90\xd9u\xab+\xf0\xb2\xea\xabHS\x98\x02oXm\xf5@\xa5]\x7f|z1>\xbf\xbc>98\xff\xf3\x87\xf7=j\xf6\x88u\x0b\xe9\xd8\xc7\xe7GJ\x11\x84SJ\n6\xa7}\xd1\x0d\x06\xd9\x05\x9c\x9c\xfd<\xbe\x1e\xff\xe5\xf8\xe2\xf2\xf8\xf4O=\x1d\x9a\xf2\x0eL\x85\xb8\xf6\x9f\xd4\xa3\x8b\xf1\xc0\xf9 \x1b\xf3\xf3\x18M_\x8e\xffry}xvz9>\xbd\xeci|\xf5\xe8\x8d\x9f\x8fq-N\xcf\x8e\xc6=m/\x9b\xeb0T\xc9\xe9\x9e\xf2\x9a5\xa6>\x88\x1a\xb3{\x01\x9a\xd3\x05#\x9f\xe7\x94.G\xdb\xdb\xb7\xb7\xb7\xc1\xed\xb3 /f\xdb\xbb\xaf_\xbf\xde\xfe\xcc>kd\xf3\"\xa4s{\x99W\xdb'!\x9d\xe3\x9f\x93wZ\xc9r=3\x16{\xba\xb3\xb3\xb3]\xaeg\n\x01\xfe8C\xed%u\xd5\xe8\xe9\xb5\x0d\xf6\xc9\xc5\xc1r\xc9\x10(\xfe@S\xde\x0f\x19\x0f~\x1f\x85\xe9[y>*\x94P%\x826\xaa\xbfvV\xd3\x1f\xd6N^L\xa9\xad\xb4aI\x17\xac\x8e\x1e\xdb\xdb\x8cQ\x8d=s_\xed\xbc4\xd0\xf1\x99\xfb\xf4\xc5+\xcf\xcd\xdc\x97\xdf{AR\xfe\x1c\xa6I\\\xc9\xe6\x1a\xb9CE\x19\xdee4\x7f{\x12nV\x94\xe6\x99\xd9\xaf_4'\xd1\xa7\x9b\xfc\xb3\xf9k\xb2\xc0\xf8\xfe\xa6O\xf3$\x8e\x89\xa5\xd2\"\x8c\x93\xdc\xf2\x89\xa0\xed\xa6\xe9S\xb9\xbaY$t\xd4\xd2L\xb6i \xe9\xeb\x8d\xe2\xee\x0dv\xc8\xe3\xa0H\xfc.\xc9>10\xac?`x\x04\x99\\\xb8\xce\xab\x97N\xaf\xae\xb2\xde\xcc\n\x95X]\xadR\xa9\x9f\xc8\x93\xf2\xec\x10\xe5mR\xc7\xfc\xd5\xab\x9ev\x0c\xdePZ\xed\x88Q\xf5\xb4\xf4\xba\xd1\x92\xfc\xc5\xc002\x9a\xd2\x8a\x88\x11Ch-P\x18f2\xa1\xa8\x93\x19N\xb8.\xd6\x15\x17N\xcb\xee\xf0\xb7\x82\x84\xf1Y\x96\xde\xf1\xb78)\xc3\x9b\x94\xc4\x8c\xbcb\xfd\x1f\xa1\xcb\n\xe1 \xeb\xd7|%\xc3\x83\xc6\x10\xc2o\xd8\xad\xdfX\xd2\x12h\x0e!\xa3y\x160MH\x1a\xc3mB\xe7\xf9\x8aB\x98\xc1o\xb2\xc1\xdf`\x1efqJ\x8a@\x91\x93\x16$\x8bI\x01!\xb0\x8el\xe5\xac'XC\x00\xc7\\\x90\xc7\xeb+\xe7\xf9*\x8d\xe1\x86\xc0bEY\x171\xd4\xfeo\xc22\x0e\xbd\xf7\xfd\x16\xc0\x19\x9d\x93\xe26)\x19\x99@(\x90\x84\xbd\xab\x1d\xc8\x0b\xf8M\x8e\xf8\xb7\xc0d2n\xd9~$~\xf8\xfc?\xe2\x94\x8b\xbe\xfc\xb7\x98\xf4C\xd1\x97\x7f\xd2\xb4\xcb\xd2#H\x026\xf3\xbf\xeb\xc8?\xb5\xda\x13-\xdb\x9b\x16u\xc8m|\n\xbf\xcb\x99\x11\x94q\xdb\xfc\xbf\xd3J\xb0\xe5\x08\xe95\x9b31\xa9\xdc\xff\"\xe4S\xf8\x8d[~m\x82\xf3[\xd0\x0ckh\x94]::m\x00\xa2Oq\x0b) \x18\xbc/\xf2%\x1aE\x0c\x83\xcc\xa62td\x03^6\xbe\xc8\xa4\n-%\x16\xd1\xa4\xb8b\xc74\xe7\x9a\x1c\x06\x88\x8e/\xee\xeb\xf2\x0e\xcb\xa9D\xf5\x89\x83\xe0\xcd%\xdb\x89\x0c\xfb\xc7\xba5\xedV\xdb\x99T\x99\xafP\xd5\xdeN\xde.u!\x81|zI\xd4&d\xcd\x08\xfdY\xc7\xbe\xa6.V\x9a5\xf5\xf1\xb5\x8f68(\xbc\xa8\x12\xff_\xf6\xfew\xbdm\x1cY\x18\xc4\xbf\xf7U\x94\xf9;\xa7\x0f9\xa6\x15\xc9v\x9cD\x89\xe3\xe3v\xdc\xd3\x997\x89sbg\xfa\x9d\x9f\xc6G\x0f-A\x16'\x12\xa9CRv<\x93\x9c\xeb\xd8o{\x0d{\x01\xfb\xec%\xed^\xc2>(\x00$\x08\x14H\xcaq\xf7\xf4\xec;\xfc\x90X\x04\x88?\x85B\xa1\xaaP\x7f\xc4_\"X\xf5\x8d\x15\xc4\xdf\xee\xfb\xc4\xa6=\x8d\xbd\xeb\xa7\xea\x11\xaa\x8d\x84\xd9a\xf5Z\x1f\x81|\xdd4\x06i)vVn\xc6V\xc1\xb7+$T\x94Ql\xd7/\xe4\xfd\xa9\x1c^m|M\xb3q\xb4\"\xab\xc8vJ\xf2{\xa4\xfd\x10\xce.*\xf8\x1aFI\x10?\x1c;\xd5!\xb1\x08\xe8\xfd\x12|\xa7\xe4\x18\xb7\xcc2\xfb\xe2\x1f*\xf5\x8c\xa9\xc4\xb1]\x88\xa0\xd2f\xa0\xda)cI\xa9\xd5\xa0k7Z\x95T\x15N\xab\xcb\xd26|UO\xe5\x98\xb4/b*\x90\xb3@\x92L\x96\xc8h\x18\xc4\\@\x06\x8f#\x8a\xc4M\xb6\xc1\xc1\xaa\xa7\x95<\xd0X\xf0\x0dv\x06\n\x0bd\xae\xd6\xca%\xabN\x83\xdd\xa6)\x0e\xb9\x8f\x95\x8a2q\x9f\x8e\xcc\x87\x16\x0du\x00\x8f\xb0\x0e\xfeQ\xf0}\x82\xdc*\xda\x1f\xa2\xa0Xa>9\xe5FB\x80N-\xa2\xa4\xba\x9a\xec\xdbwFZl\xb1\x9a\xcf{i\x16#\xec\xc2\xedZE\xadV\xd1z\xff)\xa1\xfb\x89\xdd!%\xb2q\xdc\xa8cjW\x84\x87\x90\xb4\x10\x15\xe1\x04\xc4\x0fg\xcf\x9aK\x08*\x00#\xcd\x8a\xf89\x06Q\xb2\x071\x03\x7f+\xab\xdc\xb3G\x91H\x99\xb9\x95\xfal\xc4\x7f\xa1\xaa\x1e\xffp\xdf\xf8\x96\xd06\xd6\xef^\xc8\xd9y\xc1\x15\x9c\xeb\x0b\xb75\x10\x7f\x132\xa6^\xb7\xd0\xea\x12\x17\x8b\x18\x81'\xab\xaca\x85\xbd\x94\xbd\xceU\xd0I\xd7=\xb7B\x1e\x12b\xf5\x10\x91\x88wUl5\xfe\xe6\xa8^%\xb6\xaa\xc40\x84Z\xfcG\xbc\x8dV\xe9\x9a\xd1T\x07\xff\xc4\x97\x9f\xd8\x9d|\xf7\x89\xdd=\xc4Z\xd17\xcb\"Tf\x1bAV\xac/M\xaa\xbdCo\x08\xdea\xdf\x11y\xd1\x1bb\xf1\xae\x9d\xba\x9bH\xf8\xa3\x80\xfd/\x9c9\xf6=4J\x08\x14u\xf7\x1f\x8d\x0e\x87\x97\x8f\xae\xc3\x0e\xe7\x87\xbaZ\x1e1\"\x96c\xa3._\xc5\x0f\xfdV\xa0\xf4q\xda.\xa0\x1c\xee\xf2\xe2\xe1&@\x11\xe0\xf0U\x8466\xea\xa3\xb7)\x87\x95\xf8\x8dQ1Y/__ D\xf4w\x05\x83S\xbd\x18\x04\x81\x06M\xff\xb0\xff\xe5p7xx\x80V\xf8J\xd3\x8a\x07 \xce\xec\xe2\x8a\xf6\x0fP\x916\x18\xec\x9a\xd7\xe6\xf2z]\xde\xab\xef\xef\x05\x9d=\xda\"BN\xec\xb1\xe4\xbf\xd6l\xcd\x04\xdfP\x8f\xccm\xb7@h\xbbJ\xdb I\x94\x1a\xcf?\xfd\x14+\xe8C\x0csQ\xa9\xb8\xe4\x82\x8ah/z*B!\x11\x014\xb3\x8e@\x92\x04fF\x8a\x8e\xf2\xf7\x0b\xd8\xed\xe3\x95\xdb6x\xe0\xf3&\x86\xc0q5\x93a\xaeB\xf0\x02^\x16x\xa0g\xffs\x87\x16p\x9d\x1fh\xeb\xed\x1a^\xa2\x0e}\xad\x03\xbd\x01\xdb\xed?\xce\xdf\xa6\xeb\xa4h\x97\xa0\xd4R\xd1\xfd\x83n\x86RH3\x94\xdeXH\xfclZ\xdaT\xd77\x89!I d\xaa\xecr\xbb\x08\xed\x8b2\xd9k\xe9\xbc\x88U\xed\xe1\xa9mc\xaf-\x94\x9cEu\x84\xd2\xeeb\xbd\xf1\x8a\xa1\x95\xa9\xea,\x87#\xea\xad\x08\xbf\x88\"\x13\xf5\xcd!\x8c\x8a\xcb\x10\"\xebB\xbb\x11 \xaf\xa51^\x07\x11\x93\x91\x03%\xdej\x03\xa5\xbe)\x07\xda\xecM \x07\xfac\x9aM$-\xe8\x8aM\xf4bH\xe3\xder@Z\xc3(\x98\xf0\x11\x15fJ\x0crH\xf2\xe6\x1e-\xaa\xba!T3\x9aH#\xf4rd\xd8\xf0\x7f\xf0\x9e\x14\xac\xaa2\xbdo9l=\xc1\x82\xa6\xd4\x97\xbf|\x02\x99\x85\xf5_\xd5\x90\x17\x84\x9b\xa2a\xd2\x80\x86\xc9e \xf0\xb0\x0b0\xcfYA\x01\xd2\x05\xc5\xc4 E1[?\xa1\xc0\xf8\xe5\x0b\xd0\x05\x870\xba\x0c\x02\x85\xb0|\xd4\xa6{\"=jy\xe3\xe4\xd8=\x0e,\xa86\x8327\xc7h,\xac7\x96\xc9\x0e\xf9\xf9\xdb\xbe1\xcc\xe5\xec\x0093\xd6\x99.\xf7I]\xc0\xee\xae\x87#\xe7\x07\xea\x86l\xc77x\xc9'\xfe`/\xa0\xb8\x90\xbd}\x9a\x0b\xe1<\x86\xee\xaf\xa9\x8f#\xbd\xff8\xba\xdd\xed\xdeT\xc1\xdeP\x928I\xa7\x8c\x16j&\xf3(\xe3\xa5h/\xccP\x1b\xc0yI_(\xbaU)^M\x0d\x84?ARZ\x06\x0e\xf6\xf8\xde\x92\xc8P\xc0\xcbC\xd8\xdbE\xd5\xc1^\xa9[(`\x08\x1bJ\x9a\x15h\xad<\x15\xd2\xc5`\xf7)y\xdd\xbao\xde\xc2b\x98\xc7\x91`\xa1${si\xb0\xe3k8\x04u\x0d]\xe9V\xeaurB\xfbR\xaf\x81q\x0e\xcb \x80\xf5\xb2 \x86,\xa8+k\xec\xdb\x89\x85\x90\xeae\xde\xc3M\x97[\x18a\xf3\xf7\x18\xaa\x8b\x05|\xdfD\x8dJ\x0fdf,\xf2\x84\xe24\xa15\xe9\xd3\x0c\xe7\xa4\xd4Ex\xb5\x8c8\xa8$\xd2yO\x1a\xf7\xaam~X\x0f\xfe\x9e\xe8w\x01\xc2\x8eK\xf4\x94\x04\xbc\xea\xec\xbe\x08\xb5\xfb\xecI a\x8c>\x83j5\xcff!4\x82\xbe\x93\xbc\xa2\xf7\xe3\xcaJ\xd3\xb2eA&1\xd2a\xe7\xb3\xde\xd5]\xc1\xde\x08u\x12\xcd\xf8b6\x9a\"\xe8\xe5\xac\xf0\xc5\x0f\x0cb\xdd\xe6\xdec\x8e^\x05\x87\xc4\xf5\x9b\xc7yo*\xe6\xa5R \x0e!\xe2EJmm\x16\xba\xc1\xa0\x00\xaam\xfc\x01n\xf2G\xfa\xc6\xff\xef\xbe\xd8\xf8\xfa\xbeG\x94\xc4\xa8\x0b\xc5\xfc\x03\x9b\xac\xb3<\xc6$\x86\xebP\xf8r\xf1\xf7mWB\xb8w\x8d\x8dk\xedX\xc5\x95H\xaabs\xab\x9e\xa7|(\x84s\xb8f\x1c%\xe84z\xda\xce\xd2u\x82~\xbcY\x9a\x16\x8e\x9c\x98\xe6~\xc6I\xce\xa3\xfc\xa3BhmB\xc0\xec`\xf3q\x15\xc4\xb0\x99{\x16&B$fuq\x8e\x01\xcb{ \x94\xfe&u\xec\xc5c\x90\xfc\x1a\x14\xf4}\xe4\xc0\x02\x02\xd9\xd4\xf3\x95\xcc\\V^\x94\xb9\xc6\xa7\xae\xdbb\xdf\xb4u\xd5\x9f\x08\x15\xaar\xd4\xeeyjg|\xd4qV\xe9(\xb9l\x99\x18\xb9\xdb\xaa\xe4w_\xeb\xb2~3\xef^\xa2E\xa1\x19(;\"yH\xc3\x12\x91\x92\xbdL\xf9\xa9l\x9cD\x96,\xe1K\x89\xb9 \x12\xf9\x13\x0fl.\x89\xc8\xdfe.fyh\xf0wE\xc6\x98\xe5\xd8EN\x14\xcd\xb5Y]B\xf0q\xdbh{\xa3\xe8!w)l\xb1:\xc6\xd0\xa8d \xcb7Q\x08\xef\x83\xc7\xa6\xbeD\x08\xefOLY_\xba8\x0e\x1e\x93.\x8e\xcf\x06OZ%\xac\x86k\x04\xce\x06Q\x97\xc0\xbc\x81]G\x19\x17\xf2\xf7\x1ce\\\xc8\xdfw\x94q\xf1\xfe\xc0Q\xb6\x82Cx\x0c\xea:\x9cH\xa2<\x05y\xfd\xbd&iV9\xd9\"\xe4\xb4w\xde\xc8D\xdf\x84\xb0\x0c1\xd1\x1bnKL\xea\x96\xfa\xd7A\x08W\x98kv\x8d\xd9\xe4\xf6\x82\x10\xc6\xfcL\xf1\xef*6\xfbV\x90\x99S\xf4\x05?\x82)\xefo\xccE\xa4\\\xfd\xeaW\x06R\xcfa\x0c/\xe1\xf69\xdc\xba\xb6*\xdf\xa6\xfe\nc_p\xa2,\xa3\xe4/\xe1\x10\xae\xfc\x1b8\x84\xbb\xd1\xede\x08\xb7!\xf0\xc1\x99Z>\xb3\xa1$\x80\xd3\xd1-\xe7\xf5\x974\x11\xe1OI\xc5\x96A\xb7TA\xa0\x18\x9a\xbdf\xbf\x17\xd0\xcfjw\xff\xa0\x9a{\xdc\xb9\xb9\x9b\x0e\xad\x1dtn\xed\xb6Ck\xbb\xed\xad\x9d\ny\xe5\xc6\xbd$\xda\x891i\xe4\x7f\x14\n\xc3\x11\x17K\x86\x80\xd9\xf5&p\x04\x13\x18\xc2i\xad\xba\xe9\xeax/\xcd\xa9\x14\xdb\xc4a^j$\x8a\x10\xbc*\xd3\xb7g\xfa^H\xd3z\x9d\x0d\xe3T\x13Sv\xa5Y\xfcW\x95\xde\x1d\xcf\xdf\xf2\xe5\xf1\x04\xed\xca\xa4-\xda\x0fQ\x1eO\x8e\xd7\xc5\x9c%E\\\xa6bpV\xff1\xcd\x96\xef\xa3,Z\xe6F\xad\xd5jA~\xfe\xbeJ V\xf4V\x19;V\x05\xaf\x97\"!1\x16\x9c\x9c\xbd\xfb\xf1\xf5\xef?~8\x1d\x1f\x7f\xbc\xf8 _\xfd\xf1\xf8\xcd\xebW\xc7\x17\xa7\xf8\x83\xbf=\xfb\xf0\xfa\xff\x7f:>\xe3\x7f\xee\xe2\xcb\xf7\xb2\xbaU\xf0\xe6\xec\xf7g\x1f/\xea\x1f\xe2\xaf\xf3\x9f\xce~\xc6O\xc6\xef\xcf\xde\x7f|\x0f\x87\x8a(|W\x81T\x86\xcf\xf5\x13\x7f\xff\xb1yE\x9f\xca\x92\xdd=\xea\xf2\x1e\xbf\x19\x04\xb5C*\x9f\xa7\xb7\xaf\xf8\xa2\xc6\x1c4\x9d|\x9e\xecm_`\xea\xf9 A\xa1\xa3\xbbE\x1aM\x87\xcdbG\xb9\x16\xdf\xd2;A\xfe\xbb\xf5\xbeH\xaf\xd3u'V\xdf\xd5\xf5\xea\xbe]\x97\x13?\xe3\x7f\xed~\xcb\x18\xa6\xf7\x1d\xc3\x04\xa3=\xaf\x05\xe2\x7f\xcb\x08\xe6\xf7\x19A\x1d\xb1#\x85\xbe\xfdg&\xfe\xaee\xd1\x9ee\x96\x92\x0bV\xa7OZ\x9e\x10nEJn\x13&\x1e\x15\xf5\x92\x8a\x1c{zJ\xacv\xcf\xa26\x89\x89c'{|\xab\x8dW\xe9j\xbd\xf2\xec+\x8c:%\xf0J\xcc0\xaa\xae\xea\xf4\xc3\x13\xc8kT\x9ab\xcaK\x17\xf9\xf1V\x19\x1b\x97\xed\x8fSD=/\xa4\x89\x98gU4\xa0?\x17}i\xc4\xd0S\x17\x97\xd8\xa6E8\xbd\x12\xe1p\x10^\x8d\x1a9\xe8o+NV\x9c\x1c\xc5\x95\x94\xcay\xdcp\xc7X\xb3!\xe2m\xd1cY\xd6XKx\xd2\xf3\xc6\xe8\xf2H\xc4,K?\xb1\x84\xae ,\xa8\xa5[#]e!\xf2RM\xe6l\x19\xd15&\"\xc2E\xb4t\xf8\xfb\x8b\x9b\xb1kV\xf8\xdel\x91\xdeR\xe1\x82d\xc4\xf4uO\xe2x/\xbf\x8d\xae\xafY\xf6\xf1\xf5\x076\xc5\xb8\xcf\x822\x85\xe0E\xe51+t\x063\xcep\x88\x1c;\xbd\x84\xdd\xf2e;\xcd\xcc\xa4\xfe\xea\xe1\x8d\xbc\x9e\x92G\x04\x7f\xf2t\x9dM\xd8P\xe5\x90\xa7\xe1\xc1n\xd8b\x08\xdem\x94%qr\xed\xa8%%\xc1!x\n\x8f\xc4\x91\xbf\x8c\xee\xe0\x8a\xc1\x1a\xddgCXEy\xce\xa6\x90\xa3y\xc5m\x94\x83\x88\x0e\x86J\x8e\x9ce7,\x83\xf7F\x95\xe4\xdf\n\x89ml*\xc2|a\x1eRQ\x9b\xb0C\x0cB\x88z\x18J\x0c\xed+~M\x10a\xafm\x00\xf2\xfb!\xc4j\xdd\x03?\xa2<\x821\x13\x97qH5\x0c\xdf\no\xa8\x1e\xdc C\x88\x88.\\$U\xa7\n\x14\xaf\xf6\xeb\x92\x04\xd6\xb8\x11c\x11X\xc3\xb9\x11\x059(\x13\xab\x91u\xd62\x84\x87\x98\xa0\x9b$Tu.\xac\x8bt\xf5L\x84zu\x11\xb3\xa4x\xedhk\xa6\xd59g\x93\x8c92\x9b\xaf\x9c&\xba\xfc\xb9\xce\xa2\xa4\x18\x8b\xf3\xdfS\x03s`\x1e\x7f\xf2I\xca\xabrp\xa6+\x96K\xfbF |\x16\x01\xac+A\xf5\xa0\xc7\x9e\xa3l.}\x15\xcd\xf7JKy\xc5\xa5 A\xc0\x16p\x04\xf3^\x9dL\x1c\x82\x87\xf2\x06\x9a_\xf2\x1d\x92\xf7\xae\x8a4\n\xfc\xa8\xcc\xf8\xba\xc6\xbbM^\x96V\xbbgEy\x9d\xf3G-:\x89\xfc\xae\x8f\x14 \x87\xb0&\xe9\x8a\xcc\xc1[\xce\xc2\x9f\xa0\x06`*\x97s\x1cs\x08M\x82\x10f\xf5\xf79\xae3\xdf<\xe8\xba\xd5y\xf2\x93r\xf2\xb3\x00\xd3\xec\x99\xf2\x9b\x83&\\\xa5\xd3\xbb\xa1ji\x1d/\xa6\\8{\x15\x15Q\xe0\xaf\x1c\x8a\xcdu\xb6\x18\x8a\xe0\xce\xbe\x87T\xe3c\xb60Y\x0e\xf5\x08\xb8\xc6\x0eD`\xd1\x94e9\xc9\x96\xf2\x07AH\xb2\xcdPR3\xe2N\xdcI\xafB\xb7\xb0\xf9[\"U\xa9\xac\xc1w\xdf\xb7\x10\xb3f\xe2\xb2\xeeH\\l\x93b\xfd\xa9a\xe7\xb0\xcb\xce\xdc\x84\x8a\xd0\xc1\x00\xd4S#lr\xfbL26eI\x11G\x8b\xbc\x9d\xc4\xa5m\xb4\xcdI\xa3\x1eb{M\xee\xb3e6\xd9{r\x83\xb4\xec=\"r~\xc7\x0d\xe4\xd6\xe9\xb4\xdb\x00\xb98\xf3D\xba:\n\xc6\xf6c\xb6hV\n;m\x8f\xb3\xb2\x8fV!\xa1h\xe5\x1b\x8a\x96\xadVt\xd8j\xc57o\xb5\x1a\xbaG\xfa\xbe\x1bO8\xc7\xefF\xf7 f\x08(z\x13g\xd81\xac\xa5\x0e\xa6!8`\xa1\xd5\x12\xc7\xd4\x10\xd6\xee\x9aj\x11\xc7\xeb,\x1e\x12V\x04\xd0\xb8\xc3\xb2\x07\xd8af\xd2U\xf5\xb4\xef\xb0t\x93\x1df'\x9c\xbe\xd7\x0e\xa2\x95\xa8\xff\xdcJ\xb5\xe7a\xb6\xd2o\xe6\xd4\xfa\xbbm\xe3\xbf\xff\xe6\xbc\xff\xf1\xb7\xd9\xe6\xfc\xa5\x8e\xbf\xeaZ\xe4\xc1x\xc7\x99C\x13%\x90\xfe\x9a\x152\xeb\x1f]+\xef\xc6\x7f.:i\xcf\x84\x824\x8d\xf2\xbds\x0c\xae\x9e\xbaR\x15 \xbdh\xbeb\x93\x96\x8a\xabrx-\x15\xa7Ho8\xe68\x96\x0e\xcbQ6\xa0+\xdc\x94W2(}\xcd\xe1\x08\xfe\xf6\x15\x9cR\xc6\x12\xdb\x93\x08AW\xb9\xae\xb7\xb8T-.\xe9\xeaw-\xec\xf9\x95\xd05dD\xa4 \xfe\x8c[4\x97\xb7p\x08\xfeJ\xc3\x07\x1f\xad\xe2\xff\xf65\xe8E\xd3)\xde\x11E\x8b\xff\xe0\xf0\x11\xd6\xfa\x82-\xa3\xdb:%\xae\xaf\xf4\xb2Y/\xce\xcf\x8e\xcf\xf7\xfc\x80\xcb\xb0\xfd\x10\xa2J\xa0\xbe\na\xd2\x13\xb1\xf7\xd9\xf4\x1cul\xbe\xc8\xac\x0cC\xa2\xee\x8c\xcfXV\x08\xeb^\xe2\xbaU\xd1-\x1c\xd5\"\xf6\x89\xa6\xb2\xaa\xa9\xdb@\\\xa6\x9f\xca\xb4\xf4\x87`\x08\xfa\x7f\xfb\x1a\x82,\x0c\xe1\x96\xb2\xe3\xe3[\xee3\x1c\xc2i\xe9\xd1\xe0;\x88\xc89\xd1\xbc\x93\xa8\xf2\xf3|\x85a\xcc+\xd9\xf2\xd1_\xf24 \xa1`\x9f\x8bG\xabE\x14'!\xfc\xee\xd1\xef\x1a\xa8\xbcw\"\x82[\xee\\\xdc\xad\x98g4\xf6y\xe7\xf6\xf6vg\x96f\xcb\x9du\xb6` ?\n\xa6\xb6b\x13\x04\xb5\xba\xa6\\\xb3z3VL\xe6\x8eY }\xfd\xec\xd8'\x18\xd6i\x08\xde*\xcd\xcd\xdb\x0c\xf5\x94d\xf5\x9c.\x97\x12\xfd\x8dc_\xe0i\xe18\xf9e\x9c\x1bt\xf3\xe2`N\xb3!\xac\xfd\xa0g\xbfw}\x9f\xaf\xd2$gD\x03V\x81\xd5\xc0\xd7\xa0\xc7\xf92\xbf\x99[\x02\x8d+\xd3,KYo\xcaO<\xf7\x92#\xf5\x97.\x91B\x1b\xfd\xe5\x0bx\xaes\x0d\xd4\x15\x88\xfc\x02;9\xd5>\xa3\xed X/\xfd\x84\x0e\xcc_\xbe@\x06G\xb0hWw\x83\xa6\xf2v\xd0Z\xe8\xa8\xd2\x86\x8e\xeaqhP\x7f\x13\x16\x85\xa0T\xe0yG\x158\x94\x8c\xc1\xd8=\x00\xa9\n\xb7\xf9zP\xdd\xfd\x03\x00\x8f\xf5\xf2\"*\xd6\xf9\x05\xfb\xec\x9a\x08\x85\xe6\x98\xaai\x03<\xaf\xacQY\xa0l\xfch\x04D\xcb\xc5r\xb7\x89\x9b]\xf5K\xec\x90\x06\xae\xf9\xa6\x0c\x00P\xfb\xc4m\xf2C\xe7\xa6\xd2\x1f%\xdbh!M*\x17\xad#}\x03\x8bL\xa4\xcd\xe6E\x99\xdc\xb9\xc2sp\xfb\x10\xbc\x10\x98H\x16%\xc2\x04\xe0\x0ft\xee\xc5\xbf\xc6S\x96O\xb2x\x85b\x9e\xfe\x91\xf6\xbe\xf6\xa9\xfeA\x93m\x92\x96k\xcb\xf6\x0e\x02\xa0|\x86\x00\xfd\xec\x7f\xf3\x18\xbd\x01\x1a\xd7^\xfd\xf6l\xab\x10\xad\xfe\x14-\x17\x82\x81s\x99\x10\x95\x19\xa7\xc8\xe8\xbb\x98k*\x15!U\xeb&\x12Y\xb3\x89\x84\x91\xbb\xb6v\xb7o\x0d\xac\xd1\xd8\x94\xdedR\xea\x89\xab\x0bk\x0c\x87\x1cM-g\xea\xc6\xc4p\xb2\x19\x91\x0fT\x13X8\xa2^\xcc\xb3\xf46\xe1\xa8\xaa\xd3\x9f 4q\xfe\xb7\xb7\xf4\x8b4\x9a2a\xc8vq\xf6\xfb\xdf\xbf9\x1d\x0b\xeb\x8bs|\xf5\xf1\xfd\xab\xe3\x0b\xfdU3^\x98\x16\xc5\xbf\x14Z\xacUh\x86Flh\xb1=\"\xb4\x11\xa5\xed\x91q\xd2s\x0e\x9e\xd9 *PrH\x16\xe9\xf5\xf5\xe2\x9b\xcc\xd1\x08\xe5\xe5}\xac\xa1\x88e\x93\x064\xf9X@\x8ep\xc9&\x96\xbf\xfcH\xcc\xcc\xd3W\xa0D\x9br\xb2m\xba\x86\x1a\xfd\xbf\x07\xf6\x97\xafK;\xadL}D\x07AG\x03\xfd<\xc3\x8bmi\xae\xcf\x92\x9b\x9aA\x7f!\xcd\x17\x95\xc9?\x92\x1b\xe4e\x95}?\xe7\xbcr\xcd\xe0\x7f\x95\xe6\xc20[\xfdz\x1bq\xc1M\xf5%\xed\xb7e1\x9e\x9e\xd6Z\x90j\xe3\xf1U:\xbd\x1b#\xf6y\xb6,e5&\xb3T\x8d/\xfe\xf4\x9enN2Vx\xbfk4\x18\xd5\x1b<\x7f\x7f\xf6\xee\xfc\xb4\xa9E\xb1\xd3\x9b\x9a\\\xd7\xe1\xc5\xc14\xfe\xe3\xf1\x87\xd7\xc7?\xbc9%\xe6,\xa06\xbe\x91\x08/\xa7\x8d-\xde\xeb\xd8\xbf\xd1\x02\x95R1\xc2\x12\x7f\xb7O\xba\xc2\x0e\x1e\x9b\xf1\xad\x84/\xecc\xb3\xbap\x85}b\xbe\x16\xee$\xfb\x8f\xcd\xf0\xa8\x0b\xe19kjK&b,\xfbf\xf5\x99\x18\xcc\xb3\xc0\xf7\xe2\x82e\x11Fv\xaaWYq\xfe\xdf\x1f]b,\x14\x8c\x9c\x91p\x8e\x1a\xe2\x04\xe4K\xdf\xf4ui\x94\xd2@Sl\xcc\xe3\xbc\xbe-*\xc8:\xdd}Q\xfa\x9a\x87\xca\xd3\xd5l>\xf7\x13\xacdFQ\xe2+u\x17\xc2U\x08c\xe1\xea\xda\xae\xe0\xc50\x10\x98 \x0b\xf3R\x9c\x94\x9e\x8e'V~Z\xf5tr;\x15148\xe4\x1a\xf2\xad\x89J\x88\x9fM\xd5\x80\x96{\x1b\xebk\xdf$\xec\x16\x12\xe9\xa7\xee\xc8\xe7\xa6\x9eMT\xa9\x9b\x8c\xa8\xfbH\xec\xbe\x08\xf3\x13\xf4P\xc4\x10\xb5\xaf\x15B\xdb\x95>K\x07 \x0e[8<\xa4n\xe3\xce\x85\xd8k\xbd?\x11\xdc\x02\x1d#\x8e?\x9f\xe0\x10NF3\xcc\xfas2\xf2\xfe\xfd\xdf\xcb\x8d\x85\xafn8>\x9d\x8cn.\xed/\x8f\xe1\x10>\xa1\xc3\xb4\x7fC\xdc|\x9d\xc1!\xdc\xc0\x11|\x86#\xb8\xf5=\x96\x14Y\xccr/\x80!\x1c\x97~\xd9\xf6g\xe8\xd4\x85\xb1&\x84~\x1f\xfb\xef\xc9\xafyoF\x82@\x8e\xf5\xefQ\x1f?\x86C\x98\xf8\xefeT6v\x0b,\x08\x02\x8c\xe5i\x86\xbc\xe2\xd5\xc7\x98\xb3\x13?\\\xf8\xe3\x10N\xe55\xb7\xb8\x93S\xa8\xa0\xdf1\x8c%\x94\"^}\x16\xc24\x08B\xf8\xcc[\xc0\xbc_\xe5\x02\xf1\x1e?\x89X \xbc\xf5s\x19i\xf4\xb8#\x95\xf9T\x05c0\xb4i8\xba\xef\xbf\x87\xadk\x0c>\x8f[}\xeb\\,\x90\x1a\xda \x0e\xed8\x08a=*\xb8\xa8z\xcc\xff:\xe5\x7fMC |\xa49\xfc\xee\x9c\xf6ObNC\\D\xbej\xb7\xbe\x9a\xa6\xe3\xaeS\xc4Y^V\xd5\x91n8*\xcbU\x1d\xc2\x19\xb1U\xe0\x9a\xdeV(\xd8_I\x1f}\xfc\xff\x84O=\xe6S\xbf\n\xe1ntuI\\\xa8\xa2\x03x\xea\xa7\xbd\xf7\xb0\x0di\xefG\xf8\x1d\x08o\xff\xf3\x00\xe9\xef\x1d\x1d\x80e\xc3(\xf7\xfa)\xb0\x95\xf8\xfb\xfb\xa8\xd5\xddJ\xfc\xc7\x83\xc0\x9dQP\xf6\xf5\x04\xb6\x0e\x1d\x829?\x80\x0f\x02\x99\x9f>\x04/\xb2ds\x10\xc9w\x86\xedDL\xf5f\x83\xdc\xc0\xb6^\xe5\\!\xefg:\x07\xdaxLG\xc9|B\xe5\x85\xe1l\xc1^\xe0[9cd\xb0\x8d\x83A\xe0{\xafO\xc7\xef?\x9c]\x9cy\xf7\x0e\xb0\x11\"g\x92\x92\x894\x84\xc2\xd2z\xbdp\xc5M\xc3P\x82\xeb\x00\x12\x0ci\x89z{\x7f\x8d\xb0\xc0\xa8\x902\xc4/\xf1\xe1\xf32 \x0e\xbc\x84\xfcy \xbf\xe3G\xc0(\xdf\xde\xbe\x14f2\xff\x1d\xfb\x0bl\xed\xcb\x97\xaa5\x1a=\xcd\xa8\xe2\x9d\x17hw\x10\xf4T\nb\x1a\xa4\x99\xb8\x8fP\x95d\xd0\xdd\xcdzq\xa1\x01u\x0bb/\xb5\x8d\x0e&\x1d\xa7GN\x06\xd3\xac\x07\x8btj\xe4$\x8a\x08\xcdy\x8ca\xe8F\xf1%\x0c\xe9\x13\xc1\x0en\xaf\x07 \xad\x97\x1e\x19\x91\xef\xab\xc3hX\xffL\x86\x88:\x82\x08\x86T\xe4\xf8\xce\xd0\xdf\xdb#\xa0\x9f\x8d\xbc\xf1x\x92fl\xe7/\xf98\x9fG\x19\x9b\x8e\xc7\xe2\xa8\xf7]e\x87\xf0\xb7\xaf\xad\x1b\xcf\x01\xd2t$r8\xfa\xa9\xd0\x9c\xfe\xedk\xd02\x1f\x17=\xbd\x9fF\x91%\xeb%\xcb\xb8\xf04\x84-\x7f\x00\xdf\x03E\x01\x94\xf7\xb4\xaa\xb7\xeb\xa8w\x9b\xc5\x85\xaa\xb3\xef\xa8\xa3\x14#\xb5\x82o\xba\xd8\xa9Z.\xb7\xef\xfe\xe3\xc0\xdf\xd2\xb5\xd4\xfc\xddA\xe0\xcbh\xbf\xe0\x89?\xbc\xa6$\x1a\xa8g\x1e\x17p\x08\xd2\xa2\xaeT\xca\x8f\xe3\xfa\xcdG\xe8>U\xf8\x98\x98L}/\xda\xb3!Rj\xe0\xc71I\xc5\x12xyXQ\xc6#b\x15%L]<\xe34M\x98\x9d\xe0\x15\x86\x18\xcc\x0d2\x91\x7f\xa0\x9a\xdb\xf6a\x19V\x8f:Feg\x04\xaf,\xfb\x19\xd4\xfb\xd1\x10z\xc3cr0\xa0\x03R=\xde\xbb\xefv++4\x05\xd3\x8fC\x88\xc4y(\x17>\xf5\x0bS&V\x0f\x1e\x05~\xe2(\x15A\xa6]\xd1\xd2\xe4\x98rx\x01}\xe1\xd7\xfeR\xb8V28\x02\xcf+\x85\x00\xbeP1\xb6\xa4\x05/\xcc\x83\x00^\xc0\xe3\xc7\xbb\xcf\x0e\x90\xbd\x83\x97\xf0\xf8`o\xf0L4\xb4\x0d\x03\xe9\xa8\xc9iKd}\xcc+\x88\x06\x0e\xf6v\xb1\xf3\x887\xf0do\x7fO\xf6/\xeacG0\xc44H\xe2m\xbe\x88'\xcc\xcfC\xec\x04s\xd5D\xb0#\x9b\xd9\xe6\xe3\xdc\x91\x83z\xf1\x02\x06\xfd\x00\xb6\xe1\xe0\xf1\xe3\xbd\x83_v\xb7\x9b\xfa\x11\xa9\xab1\xb1G\x86-3\xe9\xbeT\xd5\x98\x1a\x9c\xb5\x0c\xf1a\x9e\xc6RWs@\xebj\x06\x96ng\"\xeb\x9b\x83\x94\xca\x9a'\xffT\xd6\x10\xcf?\x955\xfa\xf3Oe\x0d>\xffT\xd6\xfcSY\xf3Oe\xcd/\xa6\xacqjj\x06duw\x18\xd1\x03\xc7\xdd\xc9\xe3\xbe\x83o\xd3\xc2\xb3w\x12DQ\xfcL\xdb$\xa5\x0d\xf9\xca\xb7Q1\xef-\xa3\xcf6\xcf J\xe2\xa4\xc3 \xe9\x18\xb0d\xb4\x19\xf2\\}8\xe2b4l\x83\n\xc2\x19\xfb\xcc\x88\xc9\x0f\x1b\xac\x8f\x9e\xc8#4\xb2\x96\xc4\xb9\x9e1c%_\xbf\xceOK\xb9/,\xd27\xe9$Z0)\x1b\x95)Qpo\x9c\xcd\xbc^\xbeZ\xc4\x85\xef\x85\xde\x86\xec\xfb\xde\xde\xaf\xa2Dq\x04\xad\xdd\xa5\x95i\xc8o\xe5+6A\xfa}\x8f\x15\x95\xea\xb2H.hk\xca\x14\xcd\x13,\xc2CH\xfd\x16Q\x923?\nF\xf1e \x13\xef\xa4z\x92\xf3\xeeh-b\x17\x87J)h\xddR\n^v\xff\x89 \xab\\nL\x07/{`\xf2\xc4\x13Zs\xc2Y\xd9\x89\xca\xcdl\xb3\xb0\x93^\xce\x8a\xd7\xcb%\x9b\xc6Q\xc1l~u\xd2\x9b,X\x949j\xcc\xb1\xc6[a4\x7f2\x8f\x92\x84\x19~\x867X\xe3U\x9c\xaf\xa2bb\x98},m\xe5\xe55\x11\xca\xe7\xae\xed@CA\x1e\x0ea\x9b\x9fe6I\xe6'\xcf\xb5\x99:\x85\xce\x90\x01\x9a\xe1\xc5\xb5\x93\x9b\x95A\xd2x\x85\x10\n\x9f\xf0 \xa8\xbd1\xa6s\xd5\xcad\xdf\xc9\\ \xc2Q\xa5\xdeV5\"<\x96\xa7(D\xae\x1a\x9b\xac\xa5\xfd\x18]\n\xad\xed\xe09D\xd95n\xed\xbcR\xec&\xcf\x03\x95C\xa3,\x1d%\xdb\xdb\xe6I'\xf7\xcf\xf5h{{y\xd9\xb6\xd0\x02(\x7f\xe5\x0c&_\x87\x9b^\x92\xde\xb6\xb6\x86\xb5\x9c\x0d\xcd\xe1H(\x13|$\x93\xec\x16\xe6A\x8f\xd3\xbd\xdd\x10R\xfcc\xd0K\x93*\xb4\xf9\x95\x08T\x1f\xf9qo\x95\xe6\x85\xdc\x85Hk\x06\x18\xcfi\xd2\x8b\xa6\xd3\xd3\x1b\x96\x14o\xe2\xbc` C\x9aN.\x86\xd6\x00r{\x93^\xbc\xe4=\x9e\xa3\x17P\xceG\xd6<\xb5\x89>\x06<@=/\x04\xefw\xf54\x07\xf6\x88|ON\xc8C\xaejK\x8c\x1c]\xa5\xd2$c\xd1\xf4\x0e\x03\xee\x89p|(]/|O\xf8&a\xaa\x15\xf7\x88\xf2^\xb4Z\xb1d\x8a\xf9\xe8}\xed\xab\xa0g\xb7\xdc\x86\xc3y/c\xcb\xf4\x86\x89\xc6\x90g\x0e\xcb}\xea\xf4\x1c\x80\xa6\xcc\x959+.\xe2%K\xd7\x85\x86\x11\x9c\xe9\xa8\xbe\x0f\xeaF\xb3\xd6\xf7V\xa4Y\xa4\xd5C\x98VM\xe0_]\xb9\x15\xf7`\x1b\x9doh:\x8a\xeaF\x9a\x1f\xbf\x19\x02k'\x9b]\x1cv\xdc]\x13\"\x1f\xc8\xae\xdb:n\x81\xde\xa6\xec\xce\x13:D\xff\xe0I{V3G\x9e\x8f\x0cie\xea\x17vj8\x91\x90\xa8-\xb5q\xdc\x9b\xb9\xb2\xfe\xfa\xfd\x10\x92^\xc6\xf2tq\xc3\x02\x8cl\x8f\xa9\xfc\x96\xb1\x96\xdfjC\xc0X\x10\x10\x80yF+\x01\x91\x0dDg\x86v&\x90\xe2\x00\xe9|\xf3\x98\xc7\x8f\xcb\xc9Z\xdaT\x91wF\xb2x[[\x9c\xc9\xf3>\xb0\xeb\xd3\xcf+\xa4\x8di-%\xe6\x86s\xb6\xf8<\x95\xb0\x81\x9c\xf3\xe3{\xe1\x82ZN?\xed\xc9\xab7\x11\x9aA^\\\x89w\x9cK\xb10>\"\xc2\"F\xd2A\xc0O\xf0\x161\xeb\x9d\xa3C(\x17ac\xb7\x05\x00\x88l\x9e\xb6\nA&\x8c\xf1B\x88\xee\x0d\xc4g\xae\xdb\x84Zf\x97Nr\xa9\xa6\xeb\xc9\xea\xc9\xc57\x1a\xd1\xee\x9eC\xa69\xd8Cyc\x12\x15\xbe'\xf8)O0\x1dB\xc2\xab\x875\x9e\xd5\xeez5\xbe\xf4]\xb4d\xbf\x8e\x9c\xbdk\"\xa2\xdc\x934~Z\xe6\x0fR\x9aylj\xce\x854c\xdd\x9eKaf\xcf\x14Z\x16.@\xbc\x92\x0e\xc8\xba\xe4&\xe0&lS\x8e`\x01- peF$\xcc\x98'\xae\xf9\"\xbf\x90\xda\xb7\xd2\xccL|`\x1eH_\xad\xaedN\xa5\x92\xf4\xa6\xfeV\xd6\x9bii\xfdB`\xa3\xe2\xb2m\xc5\xcc\xe5Jp\xa7\x96\xb1C\x1el;\xa8D\xae\xf8\xc9\xa5\xe0\x8a-~\xa6\x13R\xb9Y\x94\xd2\xdd3\xf1\x1f\xef\x99\x18Ty\xeb\xd4\xfdr\xbat\xd9v\xed\xf4\xec\x80\xde\xa4O\xcc\xf7\xb1c3\x08\xf4\xb6\xac=\xe4\xbd\x93\x95tGS\x94Ey\x1e_;\xd4Q[\xb8\xb5[L\xaa\x944KE\xb4-\x1c\xef9\x92\x9c\xdf-\xaf\xd2\x05\x15[\x06\xb9\xe9\xe8j2e\xb3\xeby\xfc\x97O\x8be\x92\xae\xfe+\xcb\x0b\x8f<)e:\xd1'!dJ\xbf\xe4\x05\xbdY\x9a\x9dF\xad\xd1\x1a\nq\x86\x18\x0e\xadA(,\xc4r\xe1l\x1b\xf0\x0e\xca\xf3I\xdc\x95\x89\xa2\"\x08d\x98L\x0f\x93\xeeVn\x16_\xeb\xcc~\x9b\xd7\\\x84{\x9e\xc3\xdc\x94rC\xa49\x83PFK\x9f\x85\xa8!\x89{\xb3\xe7\x90\xc3KX<\xb7\xf9\xd2\xb2\xe5\x95\x90=\xd7\x9ap\xbc\xe0\xc2q(\x14!\\\xfe\xf3\xa7\xe510\xf1\xa7B\x98\xf1\xa7A\x88\x8a\x90y9\x86\xa5H\xc2u\x03/a\xf9<\x00I&\xa6!\xead\xe6\xa3eiQ\x95\x8cV\xa8S\x1f\xad\x1c2\xb8\x96a\x0d\x86\xdd\xb2J\xb5\xed\x9eA\x9f\xe6\xd7\x06\xa6nI\xec\x9e\xdd\x03j\xf7\xf8\xbc\xe0\x80s\x8f\xfe`\xf7 \xa8\xd9{<\xc5\xd7\x8f\xf7\x1e\x93)\x1a\xd6\xd4\x98\xa1t\xd7\xcc\xd2U\xae\xb9\xfdV)\xd4\x95_o\xc6f\xb9\xcc\xe2\xc7\x7f\n\xafh\x9c\x19\xea\xef5Jc\xf7\x9d\xff\x1d\xfb^\xd4\xdd\xa8\xd7\x9aof\x9c\x7f`\xd1\xa4\xd0\xf3\x10\xf2\xed\xa2W\xc9e>\xfd6\x9e\xb1\x8c\x85e\xe4\x82wg\x89\xc7\xbc\xbe[\x87e\xca\xf8\xa7\x8f\xbd\xa0>\xbf\x9e\x91\xd3\xbf\xbc\xaf\x0ceD\x05\xa2\xae\xcab\xafR\xb7\x85\xe0\xa9)\xd4u\x06\xfa$gi6a\x1f\xed\x00\x01\xe4j\x19\x1d\xfeX}\xab\x04x\xd6qp,\x04O\xeb\xba>\xbeE-\xab\xf1Z\xcfj\x9c\xd7\xf3#\xb3[X\xd4^\x1a)\x97s.\xd3\xe5z\x03ZkA\xfd\xcb8\x7f\xbf\xce\x98\x85\x15[\xfd&\x95AY\xd3r\xe5\xe2\x8di\xa5\xb9\x86\xa8p_\x82\x92\xf8\xcf\x02\x9b\xbc\x18\x0bc\xf5l\xfe\x90\xae\xafa\x861\x0c\xba\xfe\x07\x91\xcb\x13q\xb5k\x1fjk\x10\xf5+X;nb\xee\xbf\x04\n\xe8z\xc2\xb0\x07n\x9aT'\n^\x84\xef.\xf1\x17\xdf\xb8\xf5_\xbe\x97q\xdc\xed1q\xaf\xe4\xa1\xc9\xf0A\x7f\xd0\xdf\xfb\xc5F\x9a\xf8\x8f\xf7\xefm\x9d\x86\xe2\xd6\xd6`C\xd6\x98\x1eP\xed\x82\xf0\xfc\xf4\xe4\xc3\xe9\xc5\xf8\xd5\xd9\xf8\xdd\xd9\xc5\xf8\xfd\xf1\xf9\xf9\xf8\xe2\xa7\xd7\xe7\xe3\xb3\x0f\xe3?\x9d}\x1c\xff\xfc\xfa\xcd\x9b\xf1\x0f\xa7\xe3\x1f_\x7f8}\xf5\x0d\xees\x0f\xe65O\xc1u\xd7\x12\x0f\xa51\xe0\x01\xed\x92\xf7\xd82\xd0\x92v^\x074\xc3\xbd\xfb\xe4q\xdd^\xf4\xc9\xbe\xfe\xbb\x87)\x13=\x91k\xfe\xbcH3\xe65\x98}\xaa\x05\xed]i\xb3\n\xabV\xd2\xe5U\x9c\xb0\x0fl\xba\x9e\xa0\xd7gkKi\xcd\xdb\xa0j\xe9*N\xa6\"\x8c\xd0 \x1fY\xda\xa9\xb1\xd8\xd1X\xb4Z-\xee\xde\xc6\xd3\xe9\x82\xddF\x9d&\x189Z\x9ap2\x9fwia\xbd\xb1\x1b\x85\xe3 Ps\xe8\xd0g\\\x1bs\xd1\xd3o\xcb\x80\xc9|\xb0V\xf46\x8e\x8aFJO\x92.a\xf4\xb3\xda\xad/\xe7\xb1\x11\xf9\xc4\xb5\x98(38m-\x15\xf1\x16\xff\x88:\x9f0\xa5/\xc5BED*\xe5\xd3\xcf+\x8c\xf9\x00\xc5\x9c\x01K\xe6Q2a\x19\x14)\\1\x88\xca\xe9\xf6\xa8\xe8\x8ajq}\x16\x08C\xd9Z\x0d[+A\x8e\xa9h\x1bS&\xb0\xbf}H72\x99/\xa1g\xc6{j\xfb\xf5\x84pM\xe1\xef\xf1\x9e\xda~\xbd\x92\xa7W\xad\xa0D\x88)\xa9\x8e\x9c\xe1\xda\x8a\x1c(\xe2\xfa[X\xc6\x06&\xb0\xe8F\xe7MVS\x8bNM\xdc\xd0L\x8csAX\xd3\x82,\xd4\xe5]\xebj\x80v}M\xa5O\x95s\x98\xfaA\x08\xb32\x9a\x8dU\x0d\xb4\xa94\xda(\x8a\xd4\xdb\x0d\x15@\xea,\xb6\x06!\xef\xd5\x1e\x91\xfe(\xd9}&\xb23\x9f\xd9W\x14\xe63C\xfd\xc4\x84\xf9I\x08\x03\xda\x8a\x0b\xac]A\xbfu\xad\xe4\xd2\xbd\x92[Y/B;\x02k\xe9d\xf08X\xae\xf3\x82/\x19\xc6\xe2\x05!x\xe5=\xf8\x983\x98\xac\xf3\"]\xc2\xb2\xa4\xe8\xa8e\x88\xf2\xbbd\x02\x91\xf8\x9c\\^#-:\xeb\xa1l`\x0d\xe1\xdf\xca!Dw\x98\xb2}\x1e\xdd0\x88\x12(\x83\x1d\x83\x87jiPvG=\xf8\x89W\xb9K\xd7\xb0\x8c\xf3|\xc5\x16\x0b6\x85\x08PD\x89\x92\xe2\xe8\xdf\x1c\xa3Y\x11\x00P\xa7g\xd9\xfdT\x1a\x804\xce\xcd\x1dFs%E\x1bNSr\x7fA\x9a\xc2~\x85Y\x9cD\x8bEc\x1b\x03\xfb3\x9b|\xe8\xf6\x12\x9c\\\xcd\xc4\xd9 \x93\xa6k\x89\xe1\xb7\xb7]\xc8\x7f#3\xb6\x17\xa3\xc4aD\x92\xb6^\x80\x82\xa6\x92\xfb\xce]m\xe9\x0c\xc8\x15\xf7^\xbf{}Q\xff\x94V\"\xadI\xc3L\xb5hd\xec\xf1|}\x95O\xb2\xf8\x8a\x91\x11\x96\xafKq\x87\n\xf5\"\xe4'\x89$m\x92\x1f\xdc\x9bp\xf2\x93,a\x9f\x8b\x0f]O3\xf5H\x1d\x0f\x05Y\xf58!\xac\x1e*Th})BX\x8f\xd2^\xd4j?sS\xf9)\x11I\xacu+Fz\xb8\xdaJ\xb5C\x1a\x14\xb4 5\x91\x0e\xeb\x8b\xbb\x15\xa3\xe0\x9d^\xc9t\x89\x12\xd8\x8a\xec!\xac\x9d=\x96\xe4\xb6\xddJ\x9f\x95\xf6\xd4\xe2/\x7fn\x9e\xeb\xfaC\x93~@)\xa2\xe1pQ\xa2Ma9\xc3\xeaO\xa3\x0d\x82z\xd6\x89\x06\x7f;l\x90z\xba\x9cQ\xf8&\xe8\x843P\x0d\xcf\xf2&\x01\x81|\xcc\xc2\xc6\xf2\x05\x11)\x87\x0b]\xb4K\xecc\xeb\x0e0&Q\x91\xef\x94!x\xff\xfe\xef\x9c\xb9\xfc\xfc\x88\xff\xac\x07\x93\xff\x06\x89Z\x17\xf1\x1d~i\xd6\x9d\x8d\x14E\x1f\x9bWB\\\x1a(o\xc7\x84\xd8|I\x84\xc2Qfk.\x9f\x87\x9cp\xfa\xad\xd7\x10\x1eh\xa5Mo\xad\x8c\x1f;\xb9a\xb3X\xaf!\x92\xb9\xe2\xb5\x81\xe8\xa6v\xc1\x1c5\xea4\x90{\x89\x91{\x01\xcc\xd7\x8a\x7fm\xa1hS*\xdal^\xbc\xc0\x1b\x93\xc8b\xcbxs\xa8$\xe6\x1cIQ5\xd1\xb7\x9bH\x90\x1d\x17\x8e\x07a\xcd:\xda\xb3mY\xc8\xa3\xca-\xd7%\xba+2\xbe\x91\xf0I\x02^uV\xa1\xf7\x83 \xda\xe3~\xd0\x8bzB\xa3e\x82~cm\xd5\xa6\xf5\x9dkm.u\xc9\xcc0\xf2.\xacP\x97\xc7x_\xa6q9exIq\x19\xa8Y\x83^\xda\x8b/xQ\xc5\x18\x95\x08\xd0|\xda\xd0\xac\x8d\xdd\xf8\x80n\xbc\x18\xf5/I\x04)zBz\xf5k\xb0l\x18AWB\xca\xfc\xa2\x87j\x18\xc9\x80\x87\x15T\x88\x13\xc88\xec\x1fDq\xf8`J\xbc\x10\n\x15\x00\xb9\x8b\xf2S\\\x10\xd5(\xb7&}\xc0\x11xq\x12\x17q\xb4\x107P\n,*\xabr\x91\x82\xae\x9b\x83!\xa6\x1c\xbf\x89\xd3u.\xd3)gl\xc2\xe2\x1b6\x85\xab;]\xffP\x8b\xec\xaakM\xcb\xd1w\x81e\xb5g\x9f8\x9cQ-\xdb{y\xb1i\x1e\x19\xca\x84\x9frG\x1d\xc0#\xd3\x98]\xb8Q\x1cA=b\x02\xe5\x90\x86r\x0d\x1cA^\x1e\x07e\xc5j\xf5)}5GJ\x8a\xba\x13y\x06\n\x97Q \xaf\x1f\xfb5\xcb\x95\x82KXh\xc3kW\x8d\xf4\xaa\x0bL\xee!\xe8y\xc0\x17\xd6\xa3i~A4\xa6\x08z_\x18\x9fp\x1c\xe3@,\xf8\xaf\x9d5\xc7\xaa\x9d>G\x96d\xb3\xadS\xed{\xa7\xbd\x9c\x96\x0f\xa8\x84\x0e\x9e>\xe2\x08\x92\xb6t\x87\xa5G\x1f\xbe\xae\x0f^_\x0cm\x80Ay\xb6%\xfe\x9e2\xf0\xde\xdc\xfc\xb6\xcd\xbcag l\xbf\xe5\xa9\x8b\xb6\xf4}\x18j\xb1\x01\xd2\x92\xb0g\xc1s\xd8\xde\xe64={\x1e@*\xe8y\xe1\xb3Qr\x89\xcaT\x87\x1dh\xba\x19\xd4\xb5\x83\xf1\xc9A\xe0{E\xfaq\xb5b\xd9I\x943\x97\x15'}Hv\x02\x0eqA\xaf\x06\xb0C\xd8\x1c\x8bh\x97\x94\xaf\x7f\x81>_\"%\xc6!\xec\x14\xf0\x12R \xcb\x14\xb6\xd1h\x0b]\x81\x12Y\x90r|\x0c\xca\x8f\x12\xd8>\x844\x10\xe0\xe6\x1f'\xf2\xe3\x04v\xf8\xef\x97/1v7\xff\xe3\xd0\xcczU.h\\.U\x8aK\x95\xc1\x0bH\x9f\x07\x10\x8f2\xb4\xa5\x19e|$\xf4a\x17\xb7\xac\x92\xb9D|.\xc2\xc2\xd5\xf7F\x7f\xfe\xf3z\xb7\xdf\x9f\xfe\xf9\xcf\xeb\xe9\xd3~\x7f\x87\xff?\x9b\xcd\xfe\xfc\xe7u\x7fO\xfc\xec\xef\x1d\xf0\x9f3\xb6\x8b?glw\x86\xdfL\xf1\xe7n\x7f&J\xfbL\xfc7\xbb\xdc\xdc`W\xce#\xe9\x15,/\xdaM\xcf\xbabG\x08\x19\x85 \xa9\x03A\xe2\x86\xbdD\xac\x1a\xdee\xc6\x12\x03\xf8\nmo\xa7\x97\xb8v)\xbc\x80\xf8y h\x9e\xcfw\xd7(\xbdD\x0f0\xc76\xdb\x90\xb8U\xdbl\xf0\x9420\xae\x84\xf1J\xcdA\xc6\xd7\x8fI\"\xe3\xd6\xb3\xa0\xe1\x9a4\x04)\x9c\xf6\"\x05\xad\"H\x89[\x83\xa4M\x84US-\x99,ZQ-v\xde\x11(\xdeLXldhx5\xea\x13\xa6\xcf\xa0\xd6[\x04*\xb7\xc5{<\x0f\xb9\xec\xe5\xa7\xd5A\x17c\x1eHs\" \xc7)r`\xd7\x07`\xd7,q]e\x00\x88{9o\x14/\xb4\xbe|A'\xc1\xdaG_i\x94)\xbfO\xd8\xad\x1f\xf7N\xf0\x17\x97\xe38\x0bo\xe0\x13\x7fT\x15\xcc\x8e\xa0\xef\x9ax3\x94\xb3ng\x05\xfbd\x19\xf5\xc6\xba\x04}\x9c\xdf%\x13%,\x9b\x82tM\xd6vUZ\xeb\x95~\xcf\x12\x116\xc0U;\xd7k\xbf\xcf\xd2\xcfw\x97\x8e\xab\xf7\x16\xf9\x18\xad\xff\xdb\xc4\xe1\xcc\xe5F\x81\\\x0c:\x95\xe2_\xeb\xf2\xaf\xb8\xfc\xab\xcd\xc8\x86\xa2\xdd\xb6\xd6\xa1\xc52\xb8y\x92\xa5i\x17\xb5\x01\xdd\xeax\x0d\x11m\xff'\xfe\xb4d\x86jmY\xf8\x8fm\xd2\xecWj\x11\xf4\xd4\x10\x1b\xa2\xfa\xa0\x1f\xf8\x89\x7f\xb0\xff$\xd8\x88{ih\xd0\xdc%b\xf3\xec?i92\xcbKo\x19\xfa\xc8q\x80\nv\x15\xad\x0c\x95.\x06\x8a\x92h\xab\xa2-\xe53\xb4\x95\xfa\x89\xf0kV\xf4\x1c#\x02&h\xae\xaa\xf7\xc7x\x97m\xa7r\xc3\xacim\xdc\xee3\xda0\xe4\xc0\xca2\x14\xa1\xb1n\xed\x15\xa7\x07\xbbm\xd8\xae\xd8\x80<\x84E\x08\x13\x8a\x19@g\x02\xf8\x9e\x0c \xaf1\x8cv\xa9\xc8\xa8Dq\x07x\x1f\xc6\x019E \xfb3@\x1f\xdd\x97\xb0j&%\xc2\x8f\x9a\x9f0\x94nm\xce[\x11\xc5\x9a\xe85\xc7%\xb6\xdb\xbaq\xf08Kq\x87f\xbd\xbf\x96`\xe0\x12\x17?\xb63B\xf4\x04\xc5\xf9\xa0\xbb\xb8\xa0N\"!k!dE\xce\xfb\xdc\xc0\x0bX=w\x1d\xe5\x98\xa7\x96\x8c\xef\x02\xd2)\xba\x18\xdd\x10we\x1c\x00y\x80M\x8c\xf9\ns)\xd9\xbf\n\xe1\x0eC\x1d\x15\x88\xa1\x13\xcc\xca\xe8\x8b8F7\"\x9d\x13\x7fK\xb7\xa6\x99r\x8c]*\x1f^o\x1c`\xea\x9a8Y;\x92\x0c.\x0d\xcb:\xfd\xb9\xcaX\xf4\xc9*\xb1I!:\xa77\x8db\x0b\xa5\xf1V]V\xed\x93\xd8\xbf\xc6j\x9cA\xbd\x13\x9a\x1a\xbe\xfb\x17\xd2\xcdTl\x8bIP\xe1\xd2\xb50\x06p&\xbdl\xea\xb1 \n\xe0\x84\x04\x90\xd0\xf8*\xe2\xa7\xc4\x18+\x86/\xd0\x15\xee\xa3\x85\\\xdar\xe0\x8e\xe1|\xeb\x82\x90\x87\xc8\xa4'<\xcaQCZ\xfe(\xeaN\xe9\xf8\xd7\xbd\x84\x95o\x92\xf35\xc9\x9e\xc4\xac\x9a\x98\xefT\xcc\x97\x84\xa9e>N2\xbf\xf7$\xe8}\x8c\x93\xe2)\x8a\xb1\x0fr^\xee>\xa3B\x80r\xb1\x87\xbe\xc79\xd8\xbf\xaf\xe8)\xe2\xa5~\x93/\xddSz\xac\xbb\xedcr\xeb2b\xa1\xa5q(g\xf8l\x8e0\xf4_\xe6\xc7!$\x1dp\xa4D8x\xfc8\xf03\xc7\xd6M7\xebc\xd0\xa7\xa3RqN\xcd\xbf\n!'&v\x0d\x870\xf2X\x96\xa5\x99\x17\x827Y\x08\x7f5o\xca\xf2\"K\xef0\xb0N\xb4\x16\xef2\x96\xaf\x97\xcc\xbbt\xb9\x08\xdd9\x11&\x06y\x1b\xc3a\x88\xde\xe0ROf\xce\x154\x1aU\xe8F\x86\xb1]\x0f\xbd\xc9\xc5\xed\xd3\xdbt\xca\x9b\xdc\xdab\xda\x0b\x19Z\xd9\xb7\xeb\x99o\xbe|\xc1O3\xb9\x7f\xce\xca\x12\xc7\x1d\xa40r\x98\xc7\xd7\xf3\x9f\xa3\x82eo\xa3\xec\x93\xbd& id\xd5\xeeO\xed\x1f\xac\x89\xd1\x1d\xc1\xe0\x00\x8608\xd8{\xba\xef\x80Bm(\xfc,\xe0S\x12'\xa42\xa5\x10\xb0\x88\xaa\x82(\x90\xd9c\xd6!\xdd\x08\xc6\xfb\x9d-\xd24\xf3\xedr\x15\x96@\x08\x8a \\\xeeo\xca\x84\xed\x18\xe4R\xcb\xd8\x1e\x8b<\xe9\x9c\x8f\xd5_\x9d\xa4k\xf4\xa5W\xf5f\x8b\xf4V\xa4\x1a\xd7j\xb2D\xa4\xc8/\xf3\xb5\xb3d*\xe8W\xed-\x87\xb2\xf8\xb6|\x85.>\xc2\x9d\x05\x7f'\x8cM\x15\x91\xac5(Z\xa3\x8a\xd4\xda\x89 \x8aF\xfbbC\x9cO\xe6l\xba^\xd4G#\xf7\x8f\xf9\x12-\xe9N\x93I*\x87\xca\xacw\\\xae^\x17\xb3\xa7*\xe3|t\x1b\xc5\xc5\xab,\x8a\x13\x0dNr\xaeo\xd3\x8c\xd5\xdb\x9f\xa4S\x96\x99\xe0+{\x13oY\xf5\x8a\xa3\xc4\x1c/\xb2\xe6\x92\x82<\x0bzBE\xf1J\xb4\x15\xd8M\xb3[\x98\xfbU#\x81\xdd\x8fVX\xc3W\x97\xe7\xd7\x95\xdb\xf3\xcb\xa4\x1c[\x88\x8b:e\xb8\xaa8\x08>\xb4+\xd2\x95\x0dG8\xce\x8c\x03\x92\xd7\x17DK\x04\xa9\xa8\xad\xb8\n\xf1 \x14\"4\x03\xcc\xebV4\x06\xdb/w|\x10\xba\xd8f\x89\x1b\xda\x87\xea\xcdaU\x1a`\x14\nW\xdcx\x07 \xc7\xd5m\\\x16B\xeab\xe9%\x17\xc1\x0c\x88\xd8`\xabL\xcd\xe1\x08\xfc\xc8\xd8c\x9d\xf8\x04\xd4\x8d\x8b=\xac\xd6\xc9\xee\xa7\xaa(\xf1\xcc\xd5\x1ah\x9c{Y\x99\xb7\xde\xe4b\"\x94\x01\x8a*!\xd4%\xddRy\xd3\xc2*\xb1\xd06o\xb8N}aX\xb1\x91d'\xf6\xed\n\xa0\xb9xI\xb9\xfa!\x9c\x93\x97\xf7\x1ct\x11\x86.\xf2\x91f#\xbew\x82+B\x81\x9es&\xa2\xe4,zq.\xd8'?\x13\xce\x07\xfa\xb6A\xcd%e\xbb\nztn\xa5*1NKa\xa8W\xf7Mz\x9d\xdcD\x8bx\nI\x9a\xec\x88f\x1f\xc9\xc3a2_'\x9f<39\x9dz\xf0\xb8wLDnk\x02n\x11F\xb0\n!F\xe1\x93\x13p\xbf\xe4bb\xcc\xc7c\x0cY\x1a\x9c\x96\xf1\x97\xfb\x1c\xa3]\xf37?&\x93\xc5qi\x16\xb3\x0bi6\xc7\x1c6\xcdv\xde\xc6\xdc\x16\xbdY\x96.i\xdc\xc0 f\xfc\x94\xd6\x8f<{\xbe\x9aC\x9e\xe0({\xeb$\x9f\xc7\xb3\xc2\x0f \x9a\x15,\x03\x96L\x81\xdd`\xf0\x8f\x00s80\xb48\x10!\xfa\x10X\x02U\xbb\xb4\x8d[F5|z\xf6\xa3h\xd2\"\x0eQyd`nK\x0em\x8c\x0bXn\xda\xdb,\x96\x97{&\xb4\xa5\x8e\xaeJ\xf5\xa5\x8fw\xc0{\xfbT\xed\x9bz\x99\x0ci\x8c\xe9\x9ej\x03\xa2\xb0\xcfT,\xb6\xad\xd5\x16\x93`\xe2$\x84\xd5\xb9 \xdc$r\xc0/L\xe6\xb0b\xba\x98\x93\x8e|\xf5\xcd\xf8\xe3\x0e\x1a\x7f\xab\xd1xj\xc0E\xc9E}\xff=\xd4\xddEp)\n\xc1\x16\x1d\xf1)\x88\xb5\x9eFE\xc4\x97\x1ac s\xa0\xf9}\xb1\xa6\x1d\x89\xa2@\xd2\x92\xa6*\xe4Kx\x1b\x14\xa5\xad\x01\xee\xfb\xef\x914\x06\xa1XT3\x10d\xed\x17\xed\x94q\xa5\x87q\xf2J\xc6\xeb\xdb\x93\x9f\xea\nc\x82\x7fP\x01\xad\xea\xaf+\xce\xcf^bB\n\xae\x8d\xc7\x89\x80\x8e\xee\xfd\xc6\xfe\xf9 \xdf\xee,\x13\x82\x06\xbf^\xc5\x88,\xd5\xdf\xf5\n\xe3u\xa2\xd7)\x7f\x19\xb5\xaa:\xad\x87\x99\x90\x06\x10;\xd6\x8b\x05G\x10+\xccw\xbdq^\xb7K\xc37\"EE\x06\xe4\xf29\xc9AVG\xf4\x04\xcfoC{Th1\xdb|\xa4kxld&7/r\x15eu\x86\x9b\xa1;\xa1 \xfb\xc2\xba\x07U\xac\x9e\xf4\n\xc3\xa0\xa9\xe3*\x1c\x1a\x126;\xfcH\x1d&r\xcf\xb5\x9e\xe4\x97/_\xc2\xa0\xf6k\xb7\xf6k\xbf\xf6\xebi\xfd\xbb\x83\x10\xd8\xf6v`:]\x83\xe0\xb6\x03T>\xbd\xa8q\x17\x0c\xe7\xab\xa0\xa9\xcf\xbc\xb04\x06\xfd\x10\xfa\x1dc\xdb\x9c\xd3PPW*\xed\xc2\x97\xdd;\x97\xf3-e\x05\xc7\xfa\xa9\xef\xf1\xd7\xea\x9d\x17V\x8b\x1eP\xdfH\x9d\x88\xe2\x04\xd2*\xf5\xc6 \xba\xa3\x0d\xe1\xa4f\xe6\x02\x0d\xf3<\xa1\xe7)\x87\x04j\x92\x9e\xc8\xb0\x80\x0c\x87\xfe\xee\xc2N\xea@\xf7\xf3\xc9}\x82\xd4\xf4!\xc8\x82\x9b\x1a\x92~\xa8O\xf2X\x10\xd6\x8e\x13\xbb\xca!\x864\"\x01\x0bXV\x9c\x16\x17\x10\xce\x9c\xab\\\xeaK8x\x8bx\xf2\x89\x1ag\xa7>\xde\xb7\xaf\xb0\xc2v\xa1y\xa3zB|w(\xe6,eZ\x85\x90\xa8\xd9\x96\xe8\x18\x82\xb9d\xdarn6\xa5\x8bo%\x02\x88bS\xdf\xe3\xe3\xa9m\xeb\xe7\xf5AJ\x0b\x01\xa5|\xf2\x83\xe7\x86\xc0\xe3\x1a\xe1\xdb\xb6C\xc88z\x8eDWH\x1d-F\xa9{\xaf\xe3\x98\xdeu\x13I\xfaB\xfbU\xb9\xb0\x08\x07\x16\x0c7D\xe2\x15_$\x91\x93\xa4\x16^\x8a\xb8g\x92%;\xa6\xf4\xa0\xff\xd2\x15:\x99\xd8\x93\xcd\x1a\x02)Mx\xe2\xecd\x9a\x91$\x9f\xef\xc0\xb4\x95\x02\x0d\x01 \xa5\x0dM 1\x8a\x00\x8d\x9er\xfd\xa4r\x832\n(\xa9\x9b\xd0\xfeZ\x9al\x0d\xc3\x0f-\x99\xee\xcb\x17\xa5f\xa8n\xac\xe5\x8c\x87`\x89\xef\xa2\x9d\xb0\xfc$l\xd4\x01\xbd\x16\x97\xc40\x84s\x95q\x81\x13D\xd7<%\x81>T*\xa8@k-p0\xfe\xdf\x7f\xafzq\xb5\x8d|\xb2\x0c\xd0Q\x03\x8d\x13}\xa6\xbe\xc7\xebUJ\x82\x10C|\x18Q\xae\x04\xe4\xaa\x93\xc6\x96\x97q\xfcS\xe5\xf6\x00\x0b\x96\xe7P\xcc\xa3\x04ny\x8de\x94}\xf2\xc4\xb8P\xb9\xaa\xc0\x86\xcd*\xd1\xeeH\xad\x05\xff\x91\xe2\x95\x19\xde!\xa4b\xe1\x91\xbf\x93R\xf94\xc5\x01{A\xa8}_S\xa9HM\x91\x05@J\xa3T\xd38\x9aJ\xb5@or\x10\x1a\x82\xb0X\xc1\x04WP\xae\x8aX\xdaL\x1e\xf1}8*\x05\xbc\xa1<\"\x8f\x1cz-\xfe\x7f?\xd0u\x7f;\xa8\xec$gQ\x02\xd01\xa3\xa4\xdaJ\x9a\xc2C\xe2\x8f\x1a*\xea\xc6\xcbk\x94\xda]\x14?\xb0\xea\xa7\x9b\xa1 \x1ew\"(Z\xc3\xc4\x85\xa6\x80x\x00q\x8e\x81s\xe3\xe5JdH`6\x1d6n b\xcc2\xd2\xca\x8c\x96\x82\xd6\xf7B\xb8#\x8b\xa7Y\x14'^\x083\xb2T\xed\xcf%Y*g\x17\xc2\"\x109S\x8d\x8f\x13N\xaa'\x0deWd\x99\xa467AX\xc6\xbd\xde\x8au-!^\xeb\x8fo\xb3\xb8\xa8]\xbcn\x99/\x91\x08\x96\x9f\xcc\xa88\xb9_\x1b\xd6w\xe2\xbc\x8a\xc6\xb5E\xceP\x18\xeeM;\xc5\xb2\x8e\xeb\x06#\x1a\xef\x8b\x04\xf2\x8c\xab\x8cQ9^\\X\x17\"\xea!|\xeb\xc9X\xc6\x02\xc6\xd5.\xa0A\xac\xb20Pes 24\x00\xd4\xb2!8O\x05\xc4$1\xc1P\xb6\x14*j\xc5Jk\x1c\x8e\xbeBt\x91\xd1@k\xe4\x12\x1d&%qW\xa1\x0ej\x15^\xc2\x80W\xda\x11\xcd\xbe\xf3+\xfa/x\xcc\xad\x95b\xa2f\xd1\"g\x80\xddB\xc6\xf2U\x9a\xe4,\x04ek\x9e\x98\x17\xb0\xb5%n(\xdd\xde\x96\x93\xeb\x8bl\xca\xbc\xbdMw\xe3\xb2\x05\x88\x8aT\x15A\x08W~+5\x13\x08'\x10L\xbc\x17\xe7\x82\xc1\x98\x10\x11!\x9a\x06y\xed\xdcV-\x84\xf9\x8a\xa4 \xee\x8e\xee\x9ai\x93l\xbb\xf5\xb8\xd8\xb4\xdb\xab\xa6n\xab\xc3.\xe9\x89\xbf\xbb\x9d\xfdJ\x9e\x15;\xb1$\xfed7]o\x07\x00\xac`n\xba\xb1\xef*c+\x96L\x15P*/=\xb3D\xe4\x98iP\xa1\xf7\xc6h\xc2\x97\x0b\xe4\x91?F\xc5%\x1cA\xe4\xeb/\x02\xb4\xe3\xab~\xd7-\xb2j\x9f\x1e\xc2( k\xaf.\xb1\x8a\xf0\\J\x1c\x04OCeu`\x8b\x03\xa5\xce\x1f\x88w\x06W \x90^\x9e3|3\xc7%\xa1\x95w{\xc8\x8aU7r\x89\xbc\xcd\xf3\x03\xebR\xdf2\x82\xb1\x18\xf3&\x9d\xd5F*\x03\xf7\xdaWL\xd4\x90Jz\xc1\x1f\xc2\xc9%\xd6b9\xeb\x1c\xbdR\x11\xce\xe3\x9c\xfeh\xe0\xfe\x88U\xcc\xa5,\x87#lIXq(\x89Q\x96\xe1Qi8f\xd8^\x19\xfa)8\x90\xd6\xf0j\x11KvA\x18\x13%R\x92%p\x18\x9d\xfd\x9c\xfcB\xe9\xf0#\x0f\x0b'\xa8S\xa8\xcf\x9c\xde,\x9b\xce\x8an\xa5\x163\xb4\xff\x1cb\x0c\x15\n\xf1\xf6v\x00\xd9(\xbet\xc1\xa0Qak\x19\x0e\x01I\xa6nd\x9c\xc3w~Q\x9d\x9f\x0d:8D\x89H[l\xf9\x99\xca\xd9\x13\x850\x08\x0c@\xec\xa0\xe4cc\x93d~\x14\x08\xe5_\xa3\xfe\xa5\xb6{]\x0b\xdf\xb49S\xeb\xc6\xb5Ib\xcek_Vn\x10\xd2p\x83\xc60A\xd1\x05g\x12\x94\x82\x98\xdb\x00\xadT=(\x02C\xf0l*FRe\xb3\xa2\xdao\xc1\xe5.B=\xe0]Q]\x89\x9c\x11.G|\xe7R\xef\xc5\x85\x88\xa5\xc9\xc9\x1c\x0eM\x99\xa6\xec\xca4}\xcey\xa9<\xd4\x04\x853\xb9\xa6\x9b\x1c\xabM\xeb\x1fM\xcb\x93\x0e\x0e\x0d\xcc\x08\x0dU1\xdav\xb4\x98\x19\xde\xc8@\xfb\x9d\x00]\x9e\xb9\xc6QS\x9d2\xcc`\xf7[1\x15\xa4YJ\xdd\xd0D\x19\x1fY\xe6'\xf5\x1b\x88\xf7\xa4\x01\x12\xe0\xd9*\xd1<\x08(;CC\x0f\xc5\xb9\xdb6@U\xaaV\xbe\x8b\x04\x87\x0dr\xb2B\xc7\xd1\xb0E\x82\xb0\xe3>\xc2\x83\x1b\x99w\x87\x05e\xfd\x1c\xd1\x14s\xf2\xab\x0e\xd3\xbd\xcd\xa2\xd5F\xa7\xbb\xfb8\xef|\xf6g\x8e#\xa2<\x1eR\x8c\xc7\x83\x0c\xa5\x10\xa7[\xc5^NN\xa6\xbe\xc7g\xb3bS\x90\xc2}R\xf7\x97P\xba\xf8f\xc9\x99 \xcb\x87nnP\xf2\xec\xd6\xaf\x0f\\Z3p^c\x16\x9a\xa9\xb6\x8d\xbc\xa5&A\xf2\xd6%,HW4\xfe\xe8\x90P\xc2i\x0d\x14~Z\x9b\xa3\x90SS\x8e.[\x89\xe17R*\x95QS\xafY\xef\xa7B\xa4\xf7\xcd\x0f\xb0\x9e\xb2JQb?\xce/\x0d\x04\xd1U\xba\xf1R\x90\xa4\xb6l\x806\x93\xba\xcf\xd4<\xceG\xe9%\xd4c7kR\x81,\xf4UE\x0d\xa9\xdb\x1c\xee[\xd1K\xab\xcb8\xf3/B%3=\x85F\xc7\xf5\xfe\xca\xe1\xdc\x80\xfa\x1agt]^1\"\x83\x84Hp=\x8a/\xb5\x9d\xde\xbb\x8a\x93\xa9\xa4n\xbc\xa8\xc1#\xa7\xd0\xbd)\xdb!\xa3\xa1\xd0X\xde\x1f\x16\x81\xf2\xfe\xce\x14\xe7Z\x89\x11\xf6Di\xda\xd3\xc5\xddD\x91\x90\x9ao7\xe9z\xc2\x92\xf5\x92e\xbc.\x97\x13lj\xb3\x91k\nEak\x17G\xf6\x1c\xeb\xb3C\xbf\x8f\xf1,K\x97\xfcT\x86Cx\xfb]UV\xcf\xac\x10b\n\x1eG\x82\x05C0\xae\xe5j\xb0\xe3Mti\xa2-\x1b\x90\x88\x99Q\x16\x94\n\x83\x94<\xaa\x1b\xb4,_\xc9Q\xd7?\x97~,\x1d\x0c\x8f\xee}\xd7\x03m~D\xee\xd0\x02\xe23K;M\xbc\xaeZsn:\xf4\xb2\x8e\x84\x9f\xde\x11:\xe1\x94\xd6\x9b\x1b\xf4\x83p\xae\xb1\xb3%\xd3\x93*yA9Y\x08s\x9d{\xba6i\x17\xa7\xd6\xc0\xfcF\x08\xd4?\x96\xaf\xfd\xf2\x04 ;h\xb8\xb7\xe4=\xce\x11\xe7\xcb\xf5 &bv 5(\xf3e\x1dV8(\xbc~E\xd0\x92\xfa,\x87\x9cU\xfbYzd\xb5\x10\x93{\xc3}@\xf3w\x99\x1d~\xc1\xf2\xa1\x996\xb6`\x84u\xf8\x96\xe5\x1d\x90\xdf\x12#\xb0\xca\xcd)\xd4+\x08]Vs\x1b\xc6\xa2\x9aNU\x06\xf9\xe9\x9ca\x87\x0c\xc8\x96\x95\xa1g\xaa\xfbvDd\xafL>\xabG\xcf\xca\xd9B\x04\xb5\xe4\xff\x7f\xf9\x02\xb7q2Mom\xfa\x92\xd2\xe1\xef\x91\x93p93\xd1Y.\xa0\xc4\xb4xZ\xf9N\xf5\xc6h\x89\xfd#\xd2K\x07x\xf0\xcb^\xce\x8a\x8bx\xc9\xd2u\xd1Q\xccI\xd8-\xc4~*N\xb0\xeak\x8c\x87P1@!\xe0\x00d\xa1\xa5\xb7\xc0~_'\x05\xcbn\xa2\xc5=;V\x9f\xd3=\xabR\xa2k}d\xa8\x80\xa9}\xd0*\xffH.\x1f5\xb1\xbe\xd5|\\S\x97fl\x86\xb6\x91\xba\xec=3\xe6k|\x84\xed\xb6\x81\xa4\xb6\xc6\x02\"YX\xe2\x011g\x96d\xe9b\xd1EA\xa4C\xc7g\xbc\xb9\x05\x93?_OQ\xfc\xd0_\xd9\xf8\xc5{['D\x7f\x0f\xd2\x99i\x0e\xc7{\x1b#\x9c\x8f'E|#\xb4\xaf\x91\xfa\xf3[:\xa7/\x08\xe5M\xaaV\xd5\xaeW\xc0\xcbC\x99S\xc9l\x15\x0e\xa1\xda2~+/\xcaz\xe34Q\x93\x17\x97\x12\xe5o\xea\xb6\x87p\xb9\n1\xa4\xd5n\xa0\xf6\xdcr\xc9\xa6\xb1\x08\xce\xd2N\xc2\xea_Ta+*Rh\xd5\xe08X\xb2.za\xb9\xf36\x1c\x82\xf1\x0d9\x08\xbbNm\x18\xf5\xe2\xea|\xe8\x94\xe0lc\xe6\xd9\x11S-Eeb\x9c\xebq\x88\x9a\xf1SY$\xe1\x9d\x82\xe7\xc16\x17\x82q\xbeE\xfa&\xbd\x15 \xc9|\xa7\xfd7\x1a\x11ys\xf6\xd9\xa3\x8d{D9FBj\xa9\xb0\xd3\\#\xca'q\xdcX\xe3*N\xa2\xec\xae\xb9J\x94\xb3\x83\xfd\xe6\x91L\xf2\xdd\xb6\n;-5\x8a\xd9\xe0`\xc1\xda\xea\xec\xb4V\xca\xa2[G9h\x1e\xda\xfd{\xda\\\x95\x1e\xde\xf6\x16\xaf\xefnG6,\x8a\x931\x08\x95B.\xdc \xac\xab'\xb8\"\x81\xed\x0c\xbc\xba\x90\x92S\x11x\xd6r\x11T<\x7f\x1e\x94\x03s\xb6\x0c]p\x17:\xe1\xafz:\x0c\x12\xba\xa0!tBE\xe8\x88\x8e\xd0\x15%\xd5\xa3M\x03k\xb7\xcdd\x11\x15q2h\xed\xbdq\xf7\xaaG\xf5-\xdbl\xeb\xbaq\xbbC'\xd2\x02\x1dh\x9cz\x94\xba\xae\xc1\xe8\xa9mO\x82r\xb1h\x0e\xb2\xa5\x1eN\xb3}I\xb4\xeb\xf4ZD\xa3\xd0R\xd8\xea\x0f\xa5#\xa4n&\x1d\xd1{\xc5\xe5b\xed\x989<\x94\xd1\nE\x120\xdb+\xc4\xfb\x98|J\xd2\xdb\x04\x14\x15\x18\x82\x18\xb6[{\x88V{uJT\x05v(#\xd3Q,W\x07\xb4\xc7F\n\xf6\x99C)/\xdb\xe4\xac\xd3B\x80\x8e\x88\xd1\x08n#\xd7VR\x81\x1d\xcc\xe2\xc5\xe2M\x84z\xba\xf5\xfd{i\xc4j}^\x93\xda\xbcf\xa2\xc7\xbd\x8dzlDX]\x89),\xc0\x0ea\x15\"\xe7\xe4k\x1d\x9b\x92B\xed\x17\xd6[Dy\xf1\x8e\xa1\xa0\xadB#\xf2W\x17i\x81\x92\x92\xfe\xeed\x1e \x9f:\xdd\x1f\xb0\xa6\x0d,\xff,\xcf\xaa\xc8&\xf3\xa5\xa9\xc5\x8bC\x18\xec>QIb\xe0\xe5Kx\x0c\x87\x87p #B\xe3\x9b}\xfef\xb0\x0fG\xb0\xa7^\xed\xf1W{}8\x82}\xf5\xea\x80\xbf\xda\x85#\xd8\x19\xc0\x10vv\x1b\x87\xb4v\x1c\x9fJ\x1bXM\x7f\xa7\x0e\"[\xca\xdf\xc4\x05\x1a-Ov\x9f\xf2\xbd\xec\x0f\x9e\xed\xc2\xf7\x98\x14<\xd0\xac\x99\xeaK\xe1\xfd\xdf\xff\xd7\xff\xe9\xa0\xb2\xe8cTU\x97\x16\x83\x9ak\xd8\xa0\xe9h\xa5\x062p\x0dd\xd08\x10\xa0\x06\xb3k\x0c\x06\x7f\x9b\x1d\xee\xba:\xdc\x95\x1dv&\x9e\x85T\x88>\xa7\x90L\x93$\x12t\xb0\x1f\x1aX\xffB\xf36\xc3x^\xe8\x97YCy\\V}\x1f\xf0\x0f\x03c_\x94\x89\x0d\xeb\xfcVho*\x11\x17\xac\xa9\xa32\xc2\x99\xbe\x9f\xcb\x11\xefh!\xd0\x9a\xf7^N\xaa\x00\xf8z\x95\xd9T8\x8a\x07\xf0\xaf\xb0\xcb7P\xbfI)_\xa5n\xf4K\xf2\xee\xb6#i\x0e\x04\x80\xd7\x91\x93y\x94\x9d\xa4Sv\\\xf8\x9a\x0f\xac\x199Z=\x18b\x9f\x8b\xdd\x8f\x1f\xef>;\x004\xcc\x7fq\x08\x8f\x0f\xf6\x06\xcfj&_\x06.Y\x04m\xdfX\xb8Q_\xa4-\xd6 \xb2{i\xd6\x19Xu\x06\x97!$\x95\xa3\xfa\xce\xe0\xfeF\x1e\x14\xde\x9a3\x19\x103\xd9m\x9f \x1f\xa5c\xe1*4C\xa87\"\xd2\xc2M1\xeb7\xe2G\xda\x81$n?\xa8\x9c\xec\xf5\x8d\xd4r\x11\xe4&\xc7\x0d\xdc\xcb\xb6ksj\x10\xe8\xdb\x01\xc1\xc8\x95h\x84\xcc\x84\xdcbj\xfc\xd66\xdb#\x89T_z\x9b\x1c\xd5\xd6J\xb2\x1a\xd2\xf1\xcc71b\x0fv !\xb0bOY\xa4%j5\x1a\xf1\xa3\xd6\xf47\xed\x87 t\x0c\xbf\x86iI\x0b\xcd\x9a=\x1c\xaa\x91[\xe9\xa8\x11;\xcaA\xf7C\x04\xb0\x81\xa9\xc3\x16lX\xb9\x99\x1d\xc7\xf9\xd0\x0c\x8ci\x03\xf3\xd4\x06\x0b\xada\xf5WQ\x8f\xe7\x06\x87\x10\xd75\xd3\x8a\x91t\x0b\xff\x95\xcdmy\x06\x95\x82\xa1\x01~\\\xb6\xd0t|\xee\xb4\xff\xe3*\xef%\xfab\x96\xac\x99b\xe2\x85\x9c\xe3\xe8\x18t\x03%\xd5Mhs\xbb\xf5\xbd/\xec\x14\xd1\xe5\x9bD\xa3\x04c\x92V\x00\xd71\x89\xf3\xfc\x9c\x10$\x81\xe2/\xeao\xf0:I[\x91:\xd4\xa5\x88\xd0xK\xf5\xc0\xf8\x8f\x1cV\x1d\x9d\xebc\x92RL\xe3]\xc2\x8d\x99\x17\xbd\x81\x01\xae\xec\x93+\x8aAs\x0e\x19\xbc\xe0M(\xd2hW\xba\x91\xd9\x03\"\xbf\x18e\x97\x0e\xfe#E\x0d}\xd9L\x8a\x8e\xbcB_\xaf\xa1@\x8aG_\x08)\xdd\xc8\xce\x0e\x0e\x86\xaf\xde\xce\xae\x10\xb3\x9b\x06\x86\x8c\x956\xb2\xa0\xf3\x18v\x7f\xfd1\xc8\xb60\xf8\xce\xa1\xca\xd2Y\x1f\xd5\x1e=*\xd5y}\xfb\xb8M\x8bQOhly\x9b*\x96\x01\xfb\x8d\xaf\xad\xf3-\xb1\xa9\x8c\x1e\xa0\x01v\xc0O,\xcaMn\x0c\x9a\x05\xef\x0b\xcfijh\xf5|a\xf5\x0d\xa3\xa9\x17\x9a\xa9g};\xbe \x08\xa9C4h\xe4\x85\x1eT@\xa9C\xeb\xde\xc3\xd1\xc4\x98\xfa\xa45 \xc68\xa5\xeeu5\xa3\x9b\x1ei9Nn\xb4\\Pt\xa63LcS\x164\xa9\xd7\x11\x87\x11\x04\xb5\x84*\xf5\xb4 \xb1\x9d\x01\xabfu_Zc\x14Y\x94\xe4\xb34[\ns\x0c\xca3\x06C\x83_\xa8z\x1dl\xa7\xc0d\x9b\x8d^h\xa9*\xe9\x95\xb5\x9a]9*\xb1\x0d\x0f\x9c\xc9\x95[J\xdb\xca\xea\xf2\x983v\x80\xe068\x84\xae\xa2\xc9'\x15\xaaf\xb9^\x14\xf1j\xc1\xa0\x88\x97,w\x86\xbcW\x03\x99\xaf\x93O\xa5\x9bJ9\xba\xea\x8d\xcc\xfaW\x94W\x852ut\x88Y\xf8\xdc\x93M\xbb\xda\xc5\xf3'5Lw\xfc\xd4\x8al\xaeLd\xe1\x05\xa4D\xe0\x8d\xaa+\xdf,\xb6z\xfcZ\x99\x81Ri\x04\x19\x9bj\x88C\x99I\xeakN\xd7\x90`\x14\xf1.\\\xc5\x1c\xf4\x8d5*u3\xafT?/h\xfb%\xc2\x13\x83\xaa\xa6E\xf3h\xcc-RNT3y\xaa\xde\x1d\xea5\xdc\xa9Ff\x8bu>\xd7\x1a\x10\xbf\x0fU\x89\xb2\xbaG\x9b\xedU\xc6J_\xbd\xa8M1J\xf1S\xca\x1d\xa3\x8eg\xe4\xc8\xf4\xd1\x1c\xe9\xbfj\x99\xd3Hnl]\x12\xd7\xfa\xa2p.r-\xc9U\xb5\x7f\x9a\xe7\xb1v\xb1}\xb5\xab\x14\xc2\x88\xd4\xe6\x12j\x99GY\x15\xee\xde\x8a\x14\xa0\x0eL\xeb\xa2\xe3$Z,\xf86\xac\x16y\x9a&\x0cn\xe7,\x81\xdb2\xa9\xd2\xd6!\xf4\xcd\\\x86B\x8bi\x10\xcd\x1au\xdc\xb0\xbb\xbc\x88\x17\x8b\xdaV3\xbb,!C\xb8\x03TB[j\xa5V\x0b\xb5w~,\xd8\x95x\xc3\xe0\xee:\x816']\xa3 \xa5\xdfS\xbd}\xcb\x9d\xac\x1ay}0\xb5\xfd\xd6&)X\x00\xae\xbev\xc4\x98qvk\x8b\xb2t\x97ug\xb3\xa63\x13\x85\x13\xfd\x80\xe1P\xa9\x1dB\xac|\xa3]\xb7\x17!le\x06\"\xd1\xf2Q\xe7#\xc7\xcf\x8c5\xc2\xf3\xe5\x17:q\xbe:Al:\x174\xdf\xaa4\xc2\xb6t;)t\x88\xe25\x82\x02\xb8\x88\"\\cW0\x0c\x93\xc9\xc0\xf4-.\xcb\xd7\x1b\x0dU\x93\x15\x03\\\xf4\xea\xdc\x960!\xb6\xb7A\xdf \x89\x8e\xa9\x1at\xfe\xccd\x14\xed\xd6\x8c-\xd6l\x90Q\xf8\xc2fZ\x10Y\xe1Cn\x12w\x83\xb8\xdc\x8b\xd7\xd6\x98j3\xeb$G_\xcc#\xa9KEiv\x1aM\xe6\xf5\x8aq\x95\xdf~\x92\xb1\x1a.tK\xdf\xab\xf0*\x16D\x93\xa4\xaa\xd2\x8a\xb4\xb4\x1am\x03 \xe7\x069\x8eug\xb4iV\x10M]\x12\x99`\xbe\xc08\x80\xc0F\xc9\xa5U\xf9\xab/\xf3f\xa3\\`\xaeUX\xd34\xc2}\x97\x8b\x84g\x00\x7f\xfb\x86&5\x0c\xd0Sen\x92\xb7\x16\x89\x1d\xb9jq\xfe.z\xe7c\xfa_\xd4b\x14B\x7f\x817w\xdf\x7f/\xd5\x15;\x98\x9b!\xc5\xe8\xd6\xc32\xfc\n^ \xb5\xa7O\xef4\xc7\xba\x0b\xce\xc1\x93\xa7\x81\xcf\x87$\x916\xca\xf3\xf8:\x81!\x16=\xfbV\x9b\xc2\x10\xd2\x10\xb3\xc9\x85\xb0\x0eA\xf5h\xec\xadNv\xbd\xd6\x85\x05\x7f\xb4\xb8 Evg|E{g-B\x90Q\x00I'\xacI\x9a\xcc\xe2\xeb\xb5r\xc3\xea\xd3\xcc\x7f\xe4t\xd2js\xe2\xc2,\xd8C0\xcc\x80\xb5u\x85IT\xda\x8fU\xa7\x93\xb8\xf4Xhw\xb9\x99%Y7\x0f\xdd=\xec\xfa\x90\xab\x91\x88\xd0\x86$\x14\xc3\x8d\x13\xd4\xa35\x0cJ\xa6\xa5.\x0b\x1d!ez\x0d?\x13\xf9\xc1\x05K\x81\x9eZ\xd5*e\xfa\xad\n^\x17\xc9\xd4\xd2\x83\x83 \xc4\x8c\xa8\xa3\xcb\x10\xe2v\xaa\x1aR\x1ap\xce\xf9\xacG\xec\xb2d\xe6\xf9\x8fz\x15${\x05\xf6\xf3\x1c\xd8\xce\xce\xf3@\xb9\xb9z\x91\x07\xdb\xe0oo'A\xa5\x82\xda;0\xe5zM\x8f\xa2\xdc&|o\x96\x88\x9c\xb9XTJ\x1c>o\xb0\x90Q\xeeC\xf0\x02\xd8\xe6\xff\xfcM\xb51K\xa4\xc3\xa68;+\xc7\x81\xe7\xf0\xf5y\x9de\xec\xbcF\x04\xc5G\xf9\xc6\xb1f\xaeD\xf2 \x9eZE`\xa9\x1e\xec\xbd\xc9\x9f\xc8OB3\x01\x95\x03\xfd\x81\xba^\xfe\xfa\xad\xc4I\x88\x1cT&u\x1a\xe9\xeb\x00\xaa\xaa]\xb3\xe2\xec6Q\xd5^\xb1|\x92\xc5\xab\"5\x0c\xa8#\xd7\x07\xef\xa2\xa5\x19\xd3d\xed\xaa{~\xb7\xbcJ\x17y\x87\x93\x89\\cA\x82\xe5\xd1\x9c\xf9\x85\x89\xa7('\xea50\xca@\xe4\xe7\x81bv*\xf1\x9b\xce-G\xae4\x7fpOg\xa1H\xba\x9eQ>\xb6\xfa\xd2\x93M\xa0\xa1\x86\xfd]\x1d\x81\\\xaa\x0e\xcc\xe7\xbe\xfe\x07\x9b\x89n\xe0SJ\xe8\xb4\x9c\xfd]\xbd\x95o\xdc\x15\x8f)\xfe7\xf1\x07\xfb\xe6n\x89iO0\xce\x9e\xde\x17I\xf9\xc1Fd\xc2\xe3\xfb\xa7\xa4v\xa3\xddK\x12\x0c\x19\x92+\\!\xbd#\xc1\x87\xac\xa9\xe5HF\xd9%\xfa8)_\x8a\x08\x05\x12\xf5\x85\xb5$I\x0b\xa0\xf5>\xba1\xfcr\xe8[[R\xdb'B\x10\xd4\xd3\xc8}\xf9\xe2P\xe0![\xefR\x10\xceY\xdbh;\xa1\x05\xcdH\x15!x\xe31\xcb\xdf\xa6\xd35\x9a\x9c\x98K\x89\x8c\x8e.W\x06\"\xde<\xda}v\x81\x88\xbdX9\x17\xae\xdf/\xd6\xd7q\x92\x0f\x1d{\x8be\x99\xab\x08\xb0\xed\xe9z\xc2\xb2|\x08~\x9f\x0b\xbar\xe9\xcd\xe2E\xc1\xb2\xee\xc4\x80\xf5>\xb1\xbbs\xf6_~\xd0c7,\xd3\xc8\xb4\x13\xb4`u_\xb4d\x0bD\xa9mT4d6Q\xb2?z\xb8f\"\x16aw\xb2\xefDg\xd6[\xb2\xec\x9a\xf9N \x19\xc5T\";\xdc\x06X0\xfe\xe1O\x0f\x8d\x08\x9a\x1e\xa3\xf2 N~\x0dtH\xe8pZ\xbf\x06\x805)\xb2.\xc2\xc5B\xe5\xb6k^\x97\x89\xcb\x0f\xf3m%\x94\x0f:\x0b\xe5j2\xa6\\./e\xec\xc9\x95\xaa\x03\xc3{\xfa;\xfb/>\x83\x85uG\xc5\x19\x9b!\x18WS\x0bv\xc3\x16\xc32`|\xadl\xc9\xf2<\xba\xe6Go\xe9\xe6\x8d\xb5\x8c\x1e\xff\xbe\xa2\xb7K\xaf\xd5\xa4\xe1\xb4`\xfb\x97\xfc|\xc5&C(z\x9c\xc98W\xda$\xfc\xf5\x87\x04\xd6\x91\xb28f\xf35\xe8\xc0\xb1\xaaok\xa2\x80\xd8\xa1\xf8b\x15 \xbe\xc4l\xba\xc2G\x87\xf6\xf0\xc9\xae\xa9\xd4\x7fH\xed!Er\x08\xf7\xf8\xff\x15\xf4\x80 \x87\x8e7\xd3\x11\xd2\xe4]q\x8f\xc6\xff\xdc\xab\xfe\xdc\x0f\x02a:\xf3\xf7'_\xb4!\xa3\xeb\xc0\xe8\x80\xc67e\xb41\xc4ZI\xc7\xbd\xa0\x17'S\xf6\xf9l\xe6{\xd2\xe21\x9dA\x84g\xbd\x9f\x07\xa6\x11)\x947\xd1/a\xc7\xe9\xf6\x7fS:q\x1b] \x07ft \xa3:S\x96\xb6\x98\x05\xa1\xf0\xbd\x90\xea\x1e\xf4i\xe7z\xfb\xa1\xab\xc3>\x92\xd8\xed\x0ebB\xadqq3\xe1\x9b\x88\xd0\x90\xd7\xcdh\"\x91i\xdc*'4\xb1\xab\xe5\xef\x970\xc0\x83}\x1b\xbc4\xc3\x18)\x05\x0c!\x1b%\xb0\x0d\x83K\xa3\xea\xae\xac\x8a\xc0\x0b\xc1\xd3kj%X\x80\xbf\x9c\x03\xfc\x1a\x82\x97\xcf\xd3\xf5b\nW\x0c\"\x97Z\xc3O6\xc9$\xe0&~\xbf\xe9\xfdD\x9c\xbdEO\x1c\xfc$\xa1\xd1nu\x1dD}\xb0\xf7TCZ\x071\x0f\x91_\xfcMC\xe6\x1b(\x8dkw\xfa\x14\xf9\x11&@\x9e\xf2s\xeay\"e\xeaj\x11M\x98\x9f\xb0[\xf8\xc0\xaeO?\xaf\xfc$\x04\xef\x9aW\xf7\xbc\x80\xd2\x1b({\xa2\xdf:\x1e.\xa2\xbc@ss\x11Yr\xb1\xc0\x1fy\x19\x16\xd6@+R\xb4\x10\x98\xf6\xd8|\x1d[M\n\xa5\x8b0{U\x0cl\xd0q\xf5\xea\x80l\xd3\xb1\x94k\xae\x8b}JXU\x9a\x16cm\xaa\xa9\xd6\xc1B\x8f:n\x1aB\xd9=oG\xe3\xc8\xbf\xc5$\xe9A\x97\x9d\x90F\x1cs\xb0a\xdb\xe5\x92}\x11\xdd\xa5\xeb\xa2\xdb={)\x88\xfc\x03\xdc\xafS8\xfeP\x1c2}\xbf\xbe\xdb\xef\xbb\xef\xd7\x9fv\x16\xe5\xffW\xe0\xab\xff\xbe\xdb\xca\xc6\x99P\xaahvM\xa3\xa8HaM\xfc\xd0X\xb3& \xb4\xb0\xab\xe6\x98\xa4\xd3\xb8\n\x96hm\xaen\xe7\xa3J/\x90\x86\x90\xf7>\xbe\x7fu|q:~s\xfc\xa7\xb3\x8f\x17-\x8a\x82\xfaQ+\x88\x00\x9e\xa0R\xb9\xa7S\xc2\xc6\xde~|\xfd\xe6\xe2\xb4M\x91\\\xefM\x08\xde\x9b\xf5v\xfe\xd3\xd9\xcf-\x9dX\n\xca^>Oo\x13\x9b\x0e\xa9\xa3b]j\xed\xabO\x8ay\x9c\\\xbb\x1c\xe0\x94\x16\x1f\xdb\x95\x87T\xd5\xc8\xdf\xf8\xd8;\x1ev\x1c\x0e\x19\xe1\xd8\xd8\n\x07 \xf5\xb7g\xafN7\x06\x07\xce\x8d\x06GUi\x99N\x99c\xfa\x18\xea\xdc\x1fy\xbcJ\xee]\xaa\xfb\xab\x84\x0f5\x13\xb1C\xd0\xc6\xd9\xabO#\xfd\xad\x1c\xa5|\xd9\xce\xd7\xcbe\x94\xdd\xe1\x94o\xe7\x91\xc8\x0f\xc4\x7f\xc4\xf99_U\x11\x86}\x9de,)~D<\xd5\xdf\xb8\x98-u\xec<\xdd\xfbUO\x1d\x82\x95\x13de`Z\x97\xe5\x92\xda\xe8T\xa5\x9aS\x07\xf6\xe8Z#\x13\xda\xf2\x86\x04\xb4\xba\xb6&\xc9\x80S\xdd\xb50\xd6\xa5 {\xb4\xd6\x8brw'i\xb6\x8c\x16\xf1_\x19\xba{\x05\xd2\xfe\x1d\xfb\xd6wp\xae\xef\xe0\x00\xcb\xeb\xaf\xf9w 9\xcc\x1a\x0eu\xda\x8d\xa5\xdd\xab.\xa0\xd7SX\xe9\xa6\xb1pT\xff\xe9\x8e\x9e\xd3>kj\xef\x1a\xea\xe5\"0\xa6jo\x1bA\x94\xbaK\x06\xb6\xfc\xdb\x81\x1d\xdfBf\xc3c\xd3\xb8Hk\x18\xd2\x89\x94T\xf2\xcf\xdeAG\xd7/N\xa5\x8c\xa1\xd0jt9\xc0\x14\xf3\xe6d~\x12\x8c\xfa\x97!$\xa3\xc1%zc\xfa&EoTm\xab\xbb!\xd6\x13\xcd\xda\xc2\xa90\x14\xd7\x90#\x16\xfec\xd2\xc8Y\xa4\x0e\xac\xf7\xf8]\xfd\xaf\xce\xb0zb\xd2\x0c\xa9\x96x\x16\xf8^\\\xb0,\xc2\xa5\xb0\xc9\x9b\xe1K\xd9\x06o\xc7\x8a\x9b\xa1\xf4\xfd\xac\x87\x0dk\xc9\xc71{\xdaa\x8d\x9f\xddp\x8a\x8dsI\x8d\xb0\"\xf6\xfa\xab\xe5\x1a=\xb9\x1ce\x97f\xfe\xbdX.b\x93\xa4\x06\xaa\x1f#*Q(\xa1\xc8)NM^\xa5\x1a\x108\xb1[oA\x83 \xedx\xd3\xd9r_\xc4AB?\xe6*\x84\x93\x19oE\x913\xf3=\xbdi4\xc0\xd1R!?\xccb\x02\xa6X\x86Y\x97\xda\xa0\nMr\xb0z\xa6i\xc2\x86b\xdc\x9d\x83^\x878\xb0\x0d\xba\x8f\xa86\x98\x1f;\x08\x03\xeb\xe0\x1e\xd5\x05\xcb\x7f\x05\xfe\xe9\x97VE\xe4xk\xea^\xbe\xdb,Z\x1d+\xfdBC\xee\xe8\x7fH\x85\xc5\xde\xaf\xcb:.Paa\x99\x94\xaf\xcb\xa2\x81Y\x94\xcb\xa2\xbd\xfd\x03Z\x97AD_\xfd\xa7.\xe3\x97\xde\x97$:\xadHw\x81X\x95\xec\x99%\x91,yj\x954i),!c!\x9b\xd9\xb3\xba\x9eH\xb5\xc6\xc0x?\x93\xefwI\x84j\x08S\xfaK\xd8\xb9\xd4\xf4,\x99\xa6g\xd1\xac\x0f\xb3\x10fJ\x06?\x7f\x7fz\xd2M\xefQ\xe6G\xd0\xa2\")\x81\x1b\xa3\xe9\xa2Z\x04-Ru\xa5\x08\xe8\xa3V\n\x01\xc7`>~x\xd3m,\xb2\xb3u\xb6\xd0\xfb\"\xc4\xf6\x86\xce\xfep~\xf6n\xa3\xde\xfe\x92\xa7\xa6\xb4u\x96MY\xc6\xa6\x9a\xee%\xe8\xdc\xff\x87\xd3\xf3\xb37\x7f<}\xb5\xc1\x18P\xf8\xc9X\x9e.n\xd8\xd4\xbb|\xf8\xb1\x8c\xcf?\xfep\xf1\xe1tc\xad\x0c\xad\x8fI\x84\x13\xbd]\x98J\x13\xdab\xde\xa2\xa4Qs=__\x15\x193e>]\xad\x14\x04\x0ehd\xdd\xa1\xf0\xfe\xf8\xc3\xf1\xdb\x87\x9a:\x9f\x9d{\xe6Y\xb4|\x17- \xd0\xc4U\x85\xd7\x84\xd6o]\x15\xdb\x85y\x13\xcc1\x9cg/\xce\xff\xe7\x92\x88 7!tB\xea\xbd\xf0T\xe6\xe7\xcf\xfc$\x9d\"\xd1\xda\x8a\x05g\x0dG\xb0\x16\xaa\x88$Z2\xa17\xeby\xb0\xad\xde\xc6\x89|\xc7?\xde\x11\x05\xaa\x1d\x1f\xf3\xf7\x97_\xc4\xf61\xca\xe9\xea\x02\x8e\xc0\xc3\x19\x8d?/\x17\x1e\x0c\xe5/Z\x7f\xa0i\xf7\x18\xe6\xf3F\xeb$7\xd6dA\x08#\x0f\xa1\xc9\n\x86Wv\x93\x10f\x97A\x08yg\xac9}\xfb\xfe\xe2O\x02w\xc6\xaf\xdf\x9d\xbc\xf9x\xfe\xba\x95\xb0l\x84EoY1O\x89\x1a\x0f\x83Kq2Y\xac\xa7\xect\xb9*\xee\xfe\xc8Ak\xf3-\xc2\x1cx+.y\x1ee\xc2v\x1be\x89\xef\xfd\x1ce \x06\x1el\x02\x08L\xd0\xe4\"I\x0b\xb8f \x17^\x19D\x80c\xfb\x1f\xec\xae\x87\x16d6\n\xe4\x18\x1d\xd7\x81#\x0f\xb3\xe8c\x04@\xce\xd9g/\x84\x9c\xaf\xfd\xba}\xed\xffx\xfc\xe6uE3\xce\x7f\xbd\xe5\x8e\xf3\xb3\xe3\xf3=z\xad5\x05YGH\x04\x84\xfa\x9f0\"\xe7\xb4\xe3\xd1\xe7\xe5\xe2Q\xdc+X^\xf8\xb1\xd8\xde\x1c\x0d\xd6K\x96\x8f\xc5\x96\xa4\xbe\xe4{x\xd2\xe3\x9ca\xc4\xa1\xf3s\x8c\xf3\x8bd\xcc\x10ArB\x18\xb1\x86!6\xdfcl4]c\xb7_R\xd3\xefx\xfb1S\xd6\x8f\x1a\xed\x10m\x95\x8e\x15\x94\x01\x95K\xecV\x18\"\x8e\xb0\x9bh\x11\xf3\xc9\xbd\xe7\xad\xa3\x91\xfb\"\x84\xb4\x835\x18\x87FAR\xe4\xa2\xa2\xc8!(\x0b\x85Ks\xfe\xa4\xd1\x93\x1d\x15\xa5}\x7f\x08\x93\xfco\xdc%\xdavx(\x1cH\xdaq`t\xd9\x15\x07\xbaX\x03\x81\xc5F\xd6\xacCj\xdd\x12\xb0\xdf\x18\xf0\xe7\xa7\x17\x9c\x9b{\x7f\xf6\xee\xfc\xc1\xb8\xb8\xcc\x8c\x07\x035\x1e\xce.\xc3k\x9d\xde\xd2A\xc8\xd6\x0ef\xc3_\xa3\x13\x1d\xc2\x07\x8e\xc0\xd0\xea\xdb\xa0\x15\xd6\xd2dP,\x8e\xfcC\xd1V/!\xcf\xc6\xd2\x90_T\x92? \x9e\xaa\x88\x8au\xce\x19\x16U\xb5zS_\x9bP\x96g,_\xa5I\x8eY\x02\xb2\xa07g\xd1\x94\xa19\xd2\xba\xfc\xfb\xcb\x17K?\xc0\x17c\x824\\\xe3}\xb1\x1d\x8e*i\x08\x91\x8b\xdd_;(\xe4B\xc1\xae\xf7\xc3\"\xbd\x12\xda\x97iTDzPm\xbb\x8e?A\x8a\xed\x1aD\x08^\xc1>\x17\x9cr\x88\xd6\xf8\x112\xe9\x88\x95\xff\xf1\xf1\xf4\xbc\xedJ\x7f\x03\xa4\xfc\xaf\xcd\x902\xd6\x90\xb2U\xec\xf8\xaf5\xcb\x0b9\xe9\xd8\x05\xf9.\xa2\x05\x9f\xf9\xdb\x8f\x17\xc7\x17\xa7\xaf\xfe\x91 \xb0\\\x17Q\xc1\xa6\x1f\x1e\x0e\x10\x929<{\x7f\xfa\xe1\xf8\xe2\xf5\xd9\xbb\xf1\xdb\xd3\x8bc~B||0:\xd5$r9\xa4\"\x01\x92O\xec\x8e\x96\xa6F\xad,\x85\x83[\xeaz\x1eYN\xa0\xe5J(V\x0e\xb5\x0e\xae\xcf\xf3 \x080{dY\xbd\xd2\x0el\xfcI\xab\x90\x8d\x9f\x1eUX\xe2\xaa\xb7\xe0\x87ll\x9f\xaci\xd0M\x1b$\x98\x87\x87>\xc5\x9a\xb0\xa3qOL\xd9\x82I&C'\x87Y\x08\xe9e;\xde\xab\xc9<\xe8\xd6\x7f\x98\xb9\x94{\xbb\xe3T8-;?\xf9\xe9\xf4\xed\x83\xadI>\x993\xeat\xfe&*\x96\xf2s,\xd6\x11\xd5\x13\xfdTT,\x13\xca\x87/_\xb0\x9e\xbc\xb6\x1dR\x1fxc \x83s\xf1\xe6\xb2\x9e\x97$(\x7fv\xbe\xbf\xdd\xa3c\x99=\xdb'4\xdd\xf2\xb67_\xb1I\xccr\xaf\x8b\x1d\x00\xb9\x16!\xb2d\x99\xcf\xd0_?/\xb2\xf5\xa4H3\x12zZ*\xa8HK\x0f\x7fx\x08~\x82mD\x01\xdf\xdb\x98\xdbh\x08\xa9n+\xd0\xe9*\xe1\xa6\x16\x87\x15\xe7\xb8\xff\x8cV\xd8\xef\x99 \x91\x86\x85\xfb\x94\xce>\xf1\x07V\x948\xa9\xb1\xa7\x14\xf6\x93\xde*K',78\xdbU\xc9\xfd\x94\x89\xf6k\xe5S,\xafg\xc0\xaf\xd7\x98c\x8d\xb7\x82\x9f<\x99GI\xc2\x0c\x85\xdb\x0d\xd6x\x15\xe7\xab\xa80\xc35/1\x1di\xed\xd55\x11\x80\xee\xae\xed*\xf7F\xa67\xd8\xb6\xc3_\x83\xd4\xea\\\x1bWJ>s\xe6\xbeW\x97Z\xd7V(R\xf5\x08\xba\x82\x15B(|B\x92\xa9\xbd1\xa6s\xd5h\\\xc1\x1fu\xe1%x\xcez[\xd5\x88V|\xe7O1\xc6\xc1\xaa\xb1\xc9*G\xba\x8c\xd6\xcaQ{\xf0\x9c2lJ\xaa\xe8\xaa\x95\x11S\xb2\xbd\xed\xb8g\xbb\x1emo/[o\xda\xd7\x8e$\x1a\xf2\x06\xe8\xc7j\xe0\xa1\x15\xae:\x84\xcc_\x06!,\xbf\xd3^5\xc7\x86\xd7VG\xff\xc8\x93[\x00\x87\x90\xf8\xcf\xf6\x02\x7f\x16\xe0\xb5l#\xec\xd0\x94\xe1\"\x9e|\xf2#\xff\x0e\xe3\x94\x0ct\xfe\x0f\x86p\x83\xc6`\xbd$\xbdmm\x0dk9\x1b\xc2\xd0\xc2\xb12\x19N\xd8-\xcc\x83\x1e'{\xbb\xfct\xe2\x7f\x0czi\"\x8578\x84\xab\x10\xbb\x8b\xfc\xb8\xb7J\xf3B\xeeB$5\x03d>&\xbdh:=\xbdaI\xf1&\xce\x0b\x96\xb0\x0c\\\x01\x0b\xb5\x06P\xdb=\xe9\xc5K\xde\xe39\x86S\xcdU\xd0c\xf7\xd4&\xfa\x18|tt\xe3\x07\xca\xef\xea\xa6\x87\xf6\x88t\xa7\xa1\xab\x10\xb6\xc4\xc8y_^\x9ad,\x9a\xde\xa1\x1d\xc2d\x1e%\xd7\xcc\x838\x81\x85\xef\x89 \xaf\x1e_>\xf7\x88\xf2^\xb4Z\xb1dz2\x8f\x17S_\xfb*\xe8\xd9-\xb7\xe1p\xde\xcb\xd82\xbda\xa21\x91 \xa7\xdc\xa7\x06\xce\xd6\x16\xb5a|\xac\xb8\x88\x97,]\x17\x1aF\x84\xd0\xaf\x1f\xb8\xfa\xd1g}?\x84\x95q\x06pZ=\x84i\xd5\x04\xfe\xf5\xedq2\x1bM\xebh:\xea\x08\xc2\xcd\x9f\x9b!\xb0v\xb2\xd9\x18\xc9\xb5\xb5kBQ\x02\xb2\xeb\xb6\x8e[\xa0\xb7)\xb3\xb3\xfb\x94dvv\xfb\x8f\xef\xc3\xe2`\xb2\x10\xa4\x95\xa9_\x88|\x1b:\x9b#\xed\xedJK\x08[\xf1\x82\x91\xa2{3;\xa5\x98\xf8\x82\xf3\xc2\xa8\x05\xe3b\x92\xb4\xa4\xe5\xec\xc32\xce7\x8cs[\x8fu\xffd\xef[\x02\xda\x17\xba\xe5\xc0!l\xb9\xcc\xb9w\xfb\xbf\xa4Q\x8e>\x1eY\xa7\x8b\xa5d+\xf3\"\x9c%\x1d\xa1\xc5]\xa8\x8f\x89\xe1\xd40j\x8aw2\x9a\x13\xd8\xe3\x81\xccOC\x88\\\xb5\xa112\x85zn\xa4\xb3}1J/\xfd\x88\xd0\x10\x98\x8f\xd0\x0e\xa2\x8a\xc2Y\xb7=\x8a\xb3ztF\x9e\x0c$\xa3\x1e\xdb\xe0K=x\xeb\xb7\xeeM\xd3\xa4\xda7%`\xd5N\xf0\xf3\x00c\xfav\xd0\x80\xab'\xf3=\xce\x15\xcb\xc8\x1b\x89\x88\xd7 \xd2'\\\xb6exq\x918\xc2^\nM\xc0\xb7R_\x84\xc9\x8e\xe5\xff\x98\x0d\x87\x8b\xdb\x9b\xa1Q5\xe9\xc1>}\xca>1\xe5j\xa9R\xd83St\xca\xfc\x15\xe6\xa1,\xc4\xf0\xa7\xfd.g2\xba\x1f\xe4\xd4\xc9\xbc\x15\xa1d\xa9TP\xf5\x8dX\nb\\\x84\xdf\x19\x84(\xb2\xa3\xa7|\x8aQ\xe2\x82@Jb\xa1\x90\xdaa\x07\x06!J\xe9\xecy\x99o\x12\xc5\xbe\xed\xed\x05\xbc\x80\xc9s\xd7\x81\xc2%\xa4\xb5_\x8c\x16\x97\x0e\x82\xcc\x05w\xc2y\x81O\x01{\x995I\xc7\\\xa6_\x8d\xa6\x0e\xe9XO\xaf\xcd\xbb\xe1\xc2C\xee\xdf\x840\x0da\xc5\x99{QA\x98r\xceQ\x80\xb9\xe1\x9c\xfc\x0d\x0c!\xe6c\xc6@\x17\xfc\xcd\xe8\x92\x9f\xceT\xf8!\xebM\xe6\xaf\xb0\x83y \x00\xc6\x87\xf7\x9d\xfb\x13\xb5>\xf7E\xc2\xbd\xfdN\xbc\x1bq\x14{\xe31\x9a\xb9\x8e\xc7b\xaf\xe0\x9e\xe0\x8c\x88\xfc\xc0\x86z{V\x9cZ\x12\x19\xa2\\Z\xa1\x12V1Zb\x1a\xc3\xbf\x01\x95\xd7\xa3\x82\x0b\xf7\x1b\x9a\xb5k\xf4\xc9\xe4\xc5\xd261\xab9\x10\x16C\x95\x9c0\xc4\x0d\xc1\xab\x9b\xe2\xb6\xc5\x8f\xc10\x94\\&E\xb3\x07B\x06p\x9b\xf7\x7f\xf5\x1d\x8b\x9dv\x81\xc7/lN\x1cBQ7\xa1\xc8Q\x17\xcd>\xb3\xc9\xba`\xf2N\x0b_ \xfb\x81?\xe4ir\xbeb\x13\xed\x95\xfc\xe9\nJ\x11\xfb\x89\xbfO\x862\xe7%\x83=\x87\xa3<\x91\xecX\xad\xc5/c\x0b\\\x9bL\xa3\x0cU\xa9\xec\xf3\x15\x9bH\x07\x05R\x1aj\xc4VfX\xf6TL{(L\xd1rv\x91rx\xcbz\x89^\xc55\xa1\x90Z\xa9_c655\xa1\xa9\x1b\x0c+\xc71\x14 #\xcc\xe5\x04\x11\xbc\x80\xe29D\xdb\xdb\x01\xc4\xa3\xe8\xb2\x96&$\"\x0e\x08\x13d1\x82*N\x14\x06\x7f\xa8_\xcf\x9dD\x939\xa3\\\x8c\x94\xd4\x11\x8f\xfa\x0e\x07\xa5\xdc\x0eP\xbf\x0e\xab;\xce\x80\xb2K\xe0\x8f_\x8f\xb9I\xe5\xacq\xf2\xe9F\x7f9\x1a{\x05\xbd\x7f\xc9\xd8\x8c\xa3<\xdeb\xf3\xedh\xcc\xd2W\xa3\n\x81]n\xc2\x80\x87\xd4F\x7fh\\!\xcd\xb8\x94\x0c\xda[\xa4\xd7\xb2k\xe1\xb6\xea\x9b\x1a\xdc\xfah-J\xb5\xc1h\xcb\xb0\x8c\xf7\x1f/\xc3`\xc7\xd2\xae\xd0\x8aRcP\x95\xbf?]\xef\xa2c\xb8\xd1c\xbd\x9d\xa4\xcbU\x9a`VJ\x0b\x04e\x94\xb6\xf3\"\xcd\x1c\xd6\x01Z\xa0b\xbb\x02\xde\xaa\xd5z\xb1\xeb\x08\xab\xa6\x8c%S\x96\xd9\xa5\xb9\x0c\x1c\xfe\x89\xbd\x8dV+6=I\x93\"\x8a\x13\xaa\xea\xa2\xdc\xbeK\xb6L\xe3\xbf\xb2\xc0\x8fDvr\x91>:F\x1e\xdcJ\xa2\xe5T\x0bfiZ\xbcN\xf8\xda8\x9d\xd9\xf4\x99\x0d\x810\x1c\xe7\x0f1\xf8\xa19\xd0\xdc\x1e\xe8\x02\xc7J7)\xa05\x84\xb5\xfdYd\xdd\x88\x80\xc5\xcb\xba=\xd5Z/\x9a6r\xf6\x02\x0d\xd9(\xc2\xd9\xe2\xf4\x05\xbf\xa8\xe3\x17Tk\xeft\xfe\x02d\xe58\xf3\xfe\x94bf\xd0=\xea7\xb2\xf1uTD\xfa'p\x04\xff$0\xb0\x81y\xbb\xe6\xcc\xdbcj\xbe\xd7$[\x17\xcb\x12\xda\xe5\x0cK\xac\xd6\xd6\xaa5\xca\x01\x11?1\x0b\x16\xb2\xc0\xead\"\x0b\xac>f\xb2\xe0\xc0,X\xe1\xd2\x99\x97\xe4S\xac\xbe2\xde\xcee#O\x9eXC\xbd\x11\xe2\xffc\xf3\xfa|)?y\xfa\xf8\x19\xcd\xe6^\xff\xbal._W+\x1d\xb4C\xe5k\x13\x81\x06\xa3l \x8eR\xa7\"Y=\x9a&\xb9\xad*\xd4\xaf\x18\xf2\x8aM\x12\x1a\xefL\xda\xe1L\xcc\x02?\xeb\x952\xb3\x8a\xe8\xbf\xae\x19\x9594\xe7n\x0d)\x90:\x04\xfd\xd1F:\xab\x19\x06%r\x98\x8b\xda\xdbQ\xfb\xdc?\xb1\xbb!xb\x1f{\xf4A\xa0?\x9224r\xec\xd4#\x07>-\xf5\xd7\"\xee\xc7\xa9Hl\xcf\xe9\x91a\xbf\xf67\xf4u\x0fdn\xf3U\x96\xaer\xf9\xf7$M\n\xf6\xb9h\x81#\xb4\xc2\xf2\xebe\x10\x12\xe1\xd8\xcbb\x7f\xd5+\x89\x9dK9\x8d\x98KC-\x95\x9c\xc2\x0d\x1fp\xc2&\x85\x16\xdb\xa4-\x80\xeb\x8dL\x8eo\x9a_\x7fE31\xe6S\xd1'\xd5\xa3PD?\xbe\x96\xd1\ns\xd0_\xa4\xfc\x04@\xdb\xe7v\xa9\xc1h\xb0}\x9d\xf1\xde\x9a\xba\xc7\xd4\x1f\xf7\x9a|\x0d\xfc\xa4\x8c\xf1D\x146d\xf6Ij7\xee\x0d\xd4d#J\xb2\x01\x15\xf9\xadP\x107t\x1f\x96rl@5\xeeC1Z\xa8\xc5M\xef}\x96\xde\xc4\x9c\x97\xef\xd0\x18 j\xa6Y+j\x82\xe0\xb16\xa3Qn\xf2t_:\xdf@\x97Zh\xd2W\xb1\x81`h$\x0ci\xb4\xf4j\x8c(]r\xc6)\xe7\x8c\x1b=\xa7by\xd9JS&\xd2\xba'\x1670\xc9(\xbd\x0c!\xc3\x7f\x19\x99\x88\xa6i6c\xbc\xacp\xb0\x9f\xc44\x85\xcdc\x830\xde,\xb1C\x9d0\xb8x\x1c\xf58(\x82\x9b|\xeb\xa4\xff>\x14C\xa4\xac\xc5\xda8\xb6\xf6\x93\xe2\x8a\x03'\x12Z~\x8c\xb2G\xa3^\x13=\xb5\xa9J\xb1)U\x11\x14e\xa2\x90\xfb\xe7x\xb1\xf8\xc0&,\xbeA\xa1%o 2&\x81id%\xf9\xa3M\xb8\xda\xbd\x9b\xd2\xd4\xafM\xa4\xa7#y\xdc\x944\xaa\xcb\x06\x0e\xd8e\x1d7\x14 \x8a\xa4\xd3\x96\xa6\xee\x8b8A\x18\xb9n\xdc\xf4\xa7@a#\x0e\xc1\xcb\xd2\xb4p\xdd\\\xa8\xa7\x9d\xa5\xdb\xd8\xec\xc1A\xfa\x1a\xc8\xde\xd7P\x97B\xc9\xedn\xc5c\x03\x8db\xa9\xaaY\x08\xde\xf1j\xe55\xcc}\xde\xabl/x\x7f\xbek\xe6q\x88\xb7\xa2\x81\xc5\xcc\xb4\x1aUTJ\xb3$Z\x12z\x8e\x16\x90{\xd3\xf8\xc6\x92\xe5\xd5\x93\x17w\x0b\xd6\x14\x14i\x15M\xa7\xe8B\xee\x0d\xd8\xb2\x01k'\xe9\"\xcd\x86\xe0\xfd\xff\xa2(r\xe4\xbd\xb3W0\x04\xef\xff\xf9\xdf\xff\xb7\xff\x03<\xf7\xf9\xea\xc5\x9e\x00\\\x08\xdeI\xe9\xa8.\xd7\x96/\x0c\xe6\xbf>\x84\x02\x8e\xc0\xe38\x0f%\xb5\xf0`\xc8\x17\xd1\x0b!g\x0c\x8a9+\xbd\xe3=+\xe4w}b\xb7\xad\xca(\xb5&\xdd\x18f\xb9B[>\xab\xd8o!oW\xdcx\x9c\x7f`\xd1\xa4h\x17.\x9a\x0dI\xf5\xa7\xf3\xd1\xa5\x9e\xf2\x08k\xa7:\xd0\xc2\xdf&N\xfe6i<\xad\x92{\xf0\xb7\xd0*\xd5\xd1'RB\x9eHI+\x9f\x0b\xdd\x89\xb9z6%\xea\xea\xa9\xae\x02:\x9cI\xea\xe9 \xe1&n\x1a\xdcI\xc2\xc5\x1bwz\xda\xd2\xbd\xa8Dl\x01\xa3\x06\x0d\xa8Y\xb5\xed\xde\x1dZM\xfdJ\x06\x95\x91\xb7\x83Yy;\x88\x96\xa9\xe2v0\x85\x17\xc0\x9eC\xba\xbd\x1d \xd7Y\xbb\x1dt1\xb0\xa0\xdf.\xe9h\x9b9 \xd7\xc9TP\xb6XOG\xc5\x87\xea\"\x92\xe36\x89G:d;VL=\xc27\xbb\xc0c\xc6\x8d\x1f\x8e\x99Q\xd4\xddPgW0\xb4\x94\xc6\xf6\x19\x9d\x86\x10\x9b@\x8ag\xe0\x97\xc6[U\xe2\xbf4\x90A+\x13v\x0b\x17w+v*\x12x\xbdcl\n\x11\x88\x0fB(R\x981\x0e\xfd\xa8:#z\xf0s\x94\xc3u|\xc3\x12\x880\xd5\x8d\xaf\x99\x04\xa5\xfcPY'BM>\xe5\xe7\x89q\xe1\x9aZA08\xd6 \xa3-3*\x84\\U\xce\x8b\xc5\xbc]\xe4(\xb0\x1b\xfe\xf3N\xb1\x9f>\xfa\x14\xe0\xcf[?\xc2\x1f\xb7\x82[\xf3\x99\x1f\xf4\x16\xe9\xb5\x0c\xeeR\x9d\x86\xb38\x99j\xc7\x1e\xe70$\xb3Q\x0e\xa0\xd3%\xa1\xdb|_Nx\x08\x89\xff\xe4\x89i\xc8W\xe9\x8c\xeb\x97\x03]\xba\xa4\xaf'\xdc\x03\x99G9^\xb3\x0bG\x89w\xe9\x94\xe5C\x18\xddX\x12\xc2:\x04\xe1V\xa4\x90\xd5w\x10T4\xdb\x16\xb1\x93\x1c'\x838\x94\xd7x\n$x\np\xc4Jz\xf2,\x80\xa1\x8a_\x87\xb1\x89\x9d:\xee\x05\xca\x11\x92\xfd\xec)\xa4\xc6hl[\xfd\xc6\x03\xd0\x81\x8e\x8dwR4,\x0b\xa1U\xd1\x1b4\xb8@\xd26[g\xd0\x84\x1b\xec7\xf1\\\xf5Q\xcbKC\x93\xceO\xd1b\x8cz[\xc4K\xa2\xc4SE;\x8bt\x12-<\xbb\x06[F\xf1\xc2~\xbdL\x93bn\xbfN\xd6\xcb+F\x8ck\x15\xe5\xf9m\x9aM\xed\x92\x8c\xef\x07\xfbu\xce\xa2lBtP0b0\x9c\xef'\xde\x923^gD\x03\xb7\x8c}\xaak`\xdb\x94tN.W\\N*v\xb6\xfe\xab\xce\xb5\x92\xac\xae\xce\xe5\x16p\x04[[\xd9Hp\xce\x98b\x8e\xcf4\xcaX$+T\xe3}p\xfc\x12\xa9\x03\xcf'\\\x8c|\xc3f\xc5\xd0\x0c\xe1U\xabq\x91\xae\xac\n\x19\x9be,\x9f\x8b\n\xb8m\xf3\xb6}\x98\xf5\xac~Q:\xf8\x1c\x9aE\x17)\xfaK\xf7\xeejm\xb4\xee\xc3\xec\xdb\xe1\xe4R\x83\xfa\x83\xc7\xa6u\xbatM\xb7B\xc1E]\xd4W\x9c\x82\xb7\x86\xd6f\xbdY\x9c\xe5\x05\xaa\xf4\xddZ\x1b\x94\x9f\x12\x112\x06\xd3ic}\xferO\x8aS\x1cC/\xeeV\xd5\x89s\x93\xc6S_\xbc\xc7\xa5\x83\xc3v\x0f\x15@`k\xeaX\x8bU\xd2V\xc5T\xfbvW\xf9r\xae\xba\x15\x82{\"a]918\xe2\xc4]\x04\xd3AMy}j\x15\xde\x04F0\xa6o\xa0\xdc\xdd(\x07}\x1f\xcbz\xb3t\xb2\xce\xcds\x86v^~\xf0\xdd\x1f%\xf1\x12c\xdb\xbf.d\x90\xfb\x93t\x9d\x104\xf6*\xcd\xa6,{\xbd\x8c\xae\xd9\xd9\xba@\x06\xbf\xa1\xca\xf9\"\x9e\x10$Y\xab\xf1s<\xa5\x8e\x95\xab\xf4\xf3\x8f\x0b\xf6\xd9Y\xf0\xfb,]\xaf\xc8\xd2\xb3l\x1a'\xd1\xc2Qa\x92.\xd6K\xd7\xdcDan\x17\xcc\xc8\xa1\xcc\xc48n\xe9\x92\xf7i\x1e\x17\xf1\x0d1{^z>\xcf\xe2\xe4\x13]\xf6\x8e]G\xee/1\\\xb1]t\x9d\xc5\xd3\x0f\xd4Xd\xc1iB\x1c\xc5\xb2\xec|\x15%\xee\xc2\"\xca\x08X\xf1\xd2\x13\x84WS\x99\xb3WQ\xec\xeeX\x96\xd3}\xcf\xd2\xa4\xf8\x99\xc5\xd7s\xa2l\x11'\xecd\x11-\x89\xb5\xe7E?9>KW\xd1$.\xee\x88\x02\x1a\xdci\xb6\x9aG\x14\xaa\x14\xd1\xd5y\xfcWb\xedn\xe3izK|\xf0\xd7\xd7\xc9\x94\xc2\xae\xbf\xa6\xe9\x92\x98z\xbcX\x9c\xb9\xc6:[\xa4\xe9\xd4Y\xca\xb9\xd9\x86\xc2,\xfd\xc4^E\xf9<\xca\xb2\xa8\xb1B:\x9b\x91\xdb^\xd4x\x1b\x17,[\xc4\xcb\xd8Y\xa3e\x0c%A(\xcb\xbe\xda\x17p#\xefgv\xf5).\xbc\x10\xbce\xce\xff}\x9b\xfe\x95\xffw\xe6i\x9a\x1e\xa9\x89\xf9\xc4\xeer?\xeb\xe2\xee\x9d\xdauh\xa7\xe3Q\xeba\x0e\x9a:\x11\x13WL\xe6Qv\\\xf8\xfd\xa0W\xa4\x1f\xb90+5\x99\xbc,__ \xc3\x0b\x7f@\xd9\xa4\xa3!\xe8%gf\xf4\xd0\x97X\xa6\xa98\x8d{\xca\xd8\xa2\xf1q\xfe1\x89\x8b\x05\xcb\xf3w\x92i7\xdcs\xf3y\x9a\x15\xf3(\x99*\xad\xd5\xe9\xe7U\x94\xe4\"'\xa3=\xc5\xabh\xf2\xe9:K\xd7|\x8f\xd3\x00\xa8j\x1c\x17E4\x99/\x19Ev\xed\xda'\xb4\xaccW\xc4#\xa4KEA\x8d\xd3\xe4\x7fnR\xf9O]*\x7f`+\x16\x15C*\x8d)\xa1:\xb1;i\x87\xdd\xfd\xc7\xdeiD\x92\xc29F\x81\xa5\x8eC\xba^\xe9\\\x98\xc76W*W\xb6\xfb\xd0~H\x8b\x82\x93\xc2\xa6\x01\x8a:\x9d\x86)\xaav\x1a\xac\xa8z\x8f!\x0b\xf1\xa9i\xc0\xbcF\xa7\xe1\xf2\x8a\x9d\x06\xcb+\xdec\xa8\x1f\xc4y\xd84V\xac\xd2i\xb0X\xb3\xd3h\xb1\xe6=\x86\x8bbg\xd3`/\xd2U\xa7\xa1^\xa4\xabN\x03\xbdHW\x1b\x0d\x93\xf3&\xae\x11\xf2\xb2\x96Ny\x95?FY\x1c5\x11\xca&\xfeG\xafC3\"\xeaib\x87\xd4\xc3[\xf91Z\xc6\x8b\xbb\xae\xf3O\xd7\x05o\xd8\x05\x02Y\xdc\xb2D\xb2V\x0b\xacd\xad\x86\xe5\xf9\x8e\xfe\xe5P\x15\xc4\xf8\xf6\x9b\x84\xaa\xc4\x7fj\x06\xe3K\x85a\xd0`\x1f\xe3\x02\xee\x89\xf0\x80O\xfb\x96\x83\xbc4 \xc2rv\x0b\x1f\xd8\xf5\xe9\xe7\x95\xef\xfd\xe7\xc8\x83m\xc8z\xc7\x17\x17\x1f^\xff\xf0\xf1\xe2t\xfc\xee\xf8\xed\xe9\xf8\xfc\xe2\xf8\xc3\xc5\xf8\xe4\xa7\xe3\x0f\xb0\x0d\xde%]\xa9,\xfe\xdd\xbfXi\xcd\"\"\x1e\xfbZ\x06\x80(_\x96w\xa5\xb9\xf3\xaetkkmG`\xc7\x00\x81\x11\xf1\x9e\xcb\xfd2\xfb\x1a\x1a\xb4\xf9\xeb\x11\xbb\xc4\xb0\xaf\xa8\xdd\x85!\xf8\x91\xf6\xa6\x16H\x9bNs\xdc\xc5\x9e\x10\xf3\x84\xcc\xa3\xfc\x874]\xb0(\x11:\x80\xef\xbf\x87\xad\xaa\xe8\xddz\xc9\xb2xR\x16\xc5\xf9\xbb\xe8\x1dg\xfeT\x05%\xce\x99\x15\x0bx\x01\x83\xb2\xd6\xd9\x0d\xcb\x16i4eS\xab\xaf\x01\xa9\xc0\x03\x89<\x13[\x1f\x87V\xcbo\xa3\xec\xd3z\xf5c\x9a\xbd~\xd5\xaaJ\x13\xd3\xcez\xaf_\x8d\xeb\x88\xc0q\xe0\x90cHj\x85\xb4\xae#@\xce\x8a\xe3\xa2\xc8\xe2\xabu\xc1\xac>\x1d\x8c.f\x9b(\xbf\xf2\x89\xee\x89\xe0\xefM3\xfd\x90\xa6m\xd7\x95\xe5T?\x9c\x9d]\xd8\x93\xfd\xb7C\xcf\xfb\xb7\x0d\xe6i\xf4HB\xd7\x9a&\xd1uXK\xdcK\xf4k\xccT\xed\x8c\x0ePV\xea?\xbc\xfc\xe6\x1f\xc5,'\xf6\xd7Q\xad\xc2\x08U\xc8\xb4Q\x15j ]\x82\x0bF\x8b\x14.\x1f\xa5~\xd0\xf3huc\xe9\x07\xd6\x8b\x14tl\xb3\x0e\xf5\x94\xf6\xff\xe6n\xfc\xf2E\xbcl\xd8@\xfdRE\x1e\xab5\x86!\xfe\xad\x90\xbb\x93\xbe\xb2\xc4\x9d8?Y\xe7E\xba\xac\x16\x15\x01X\x91\x0d\xbc\xc1\x1a\xa2\xf8V\xf5 \x01\xba\xc1*\x1b\xbdtXl9\xc4\\RL\x15{\xa7\xc00#\xc6`<\xaf\x05\xd1\x11\x80ndk\x880\x92\xb6\xe0[a\xe1[\xd1\x8co\xa4\x1f!h8\x94\xf60cW\x9c&T\xbeD\xf5\xf0\xa6\xe2@hw]\x06~l\x913GgP\"x\x8a\xee\xbd\xba\x02\\\x98}\x89\xabb\x13pb\xb9\xe8\xeeT\x9b|\x02y\xf11/\xed>\xd0$Q\x81\xe8\x8eo\x8cK:@\xabzZ\x06\x0e\x9a\xbdQZ\xdfq4\x93\xa4?k\xfb\xa3|\x15M\x1c{\xb5\xfa\xea\xc8\xa0~\xef\xce\xfd\xb5\xc8\xa2\x877\xbc\xe8.O\xed\xe8\xb4\xd3\x8eN\xac\xf6}l:P\xa9\x8c\x8c\xf7\xd8\xa5s\xc4\x8e+|\x9b0\x08Hc\xd0}\x82\x14\x14\x06^Lz\xdaV\xd2(\x86\xdcA\x1d\xf7\xa0\x8b\x0886a.\xf3\x00\xf8\x8a& P\x89\x84\x15\xfaXmH\x15%\xa4\x1a\xc7V\xc7\xf4Mh\x145\x8c\xee==\xf0\xc9\xb71%r\x9e|\xa5\x85\x7fgJ\x94\x06\x9c\xad\nU\xf0\xe3\x06r\x84\x1d\xdb\x04\xc2\xbd\xd9\xab\xa3U' \xee\xddj\x1f\xabG\xc0F1\xb2\xd3\x03\x0c\xfb\x8b\x7f{\x0e\x9fc1J{a\x8d\x93\x9d8d\xc5\x97\xf4>\x12\x17\xe2m\xc8R\xfer\xc8f\"9\xe77\xcaf\x03*lq\xe2\xef\x0e\x1c\x11\xc6\xcdp\xeb2\xcf\x97\xd9\xca\xba\x92\xdc\xb6\x06\xa4\x91lnq\xb1x\xd7\x8bV\xccY\x9a\xa25\xcd\xebW\x95\x0dv\xcd\xdci\xc5\x92i\x9c\\\x7fD\xa3\"\n]\xda\xbe\xc1\xe5\xb7\xb1\xc6\xf0.\x10w\xed\xf2\xcaU\x06C \xf1\x04\xc3\x9aW\xf6B\x94\xfdL\xc5\xb1|\xff=(\x03>\x89\x98>\xeb-\xd7\x8b\"^-\xa8\xb4P\x15\x1e8\xc5=\x82X\xde\x94\xd9\xd8\"\xcc\x81B\x1b(\xf5\xd2UaGEu\xde\xba\xa3\xbbA&\xc4d\xdd\xe5 \xa9\xbb\x1cd#AhG\xe9\xe5\xff\xcb\xde\xbbv\xc7\x8d\x1b\x0d\xc2\xdf\xf3+J\xcc\xacCF4\xad\x8b\xc7c\xb7G\xd1\xeb\xb1\xe5\x8d\xb3\xe3\xcbZ\x9e\xe4\xeci+Z\xaa\x1b\xdd\xcd\x11\x9bdH\xb6de\xac\xe7\xb7\xbf\x07\x85\x0bA\x12 \xc0\xb6<\x93d\x1f|\xb0\xd5$\x88K\xa1P\xa8*\xd4\xe5\xac\x93\xc0\xa4\xd5\x92\xd2B\xdcn\xc1L\x89X\xd0\xcd\x0e\xb1\x8b\xa7\xf9\x197\xa4\xd2\x93\x02\xacPaLU2\xc7[\xf1\x0d\x9e\"\xed\xe7Gj\x82xQ:\x1a\x13\x137\"A\xc3\xa6\xde\x02O{r\xda\x01R\x907\xb3@&\xa0l\xdb!t\x87\xba\xa3#\xac\xb1\xe2k\xe2\xc7\xd3\xbd\xee\x17F\xcc\x12\x7f\xe9\x05\xef%\xa9\xff\x9cW5\x06Mq8\x9f\x84<\xc1b\x19\x99\xecA\xf3\x8c\xd9\x01Nz\xd6\x8c\xe2\x8d~\xb3q_xv\xb8\xf4\x97k\xf0\xc8]\xe7\x9b\xac\xfe\x1b\xeb\xcba\"\xe2\xa0U\xf6\xb6\x8e\xdd\xed\x8c\xbf\x07>QZ$\xc8\x9c1*\xc9\x92:\x89Sn\xb9*\x08\x07et2\x984!?\xf1\xbdI\x8f\xc9\x12\x8eU\xecs\x83\xaeP\xc2\x7fX\xcc\x17EXw\x8d%\x8e\xa20@\xf2\x10\xceoy\xe7\xec\"\xcf|~\xeb\x0e\x04\xdf\x85\xba\x9b\xd8\x0eP\xcd\xb9\xe3*.|\x1ec\xcb\x18\xd5\xe0\x96\x85\xaa5\xd9\xf9_\xc7\xd5kN\xbc'\x92\xa0\xd7\x0dA\xefch\xa8\xa6\x8d\xa8\xf9\x8eW\x13r\x1eu\x16\x99\xbe\xdc\xa0\xc9\xcfF\xb7\x8d\xc3\xee^e\xc1\xa3\xf1\xd3\xe7\xcc!\xc8\xb6\xc6\x06/\x0f\x15\x13\x87\xfa,\xf2\xaaf\xa0\xd7\xec-\xd3\xc6bVmZD\xb2n\xb1\xd6\xc8\x0cY\xe7\xa1e\"\xd6\xfe\\Y4{_Je8\xd2-\xb1\xbe\xdf\xd2N8\xc4\xde.\x99\x7f\xb6\x8da \xd9q\xaf\x19A\x08%Ztex\xb6i*42\xd3N\x0f\xbb\x8e\x07\x9amW\xa5]\x0c\xd5\x15?D>\x13\xaf\x17)G\xfe\xfa\xaaLm7\xb0m\xae\xe7u\x19O\xfbx\xbf\x1b\x91\x80g\xcdy\xd45q\xdc\xf0\xe7\xdd\xfb\x8c\x8a;:\xd3\x0e\x809<3\xdewx\x13 \x19\x93N<==\xb4\x96m\xd6\xab\xf7\x11\xcd\xfb<\x1c\x97\x91\x8fxz\xa2}\x91/\x8f\xee\x88\x98\xc7\x00\xf1\xd3\x0e^J\xb9\xccc\xd9\x92Zi\x8e\x86\xf4b\x86\xb3\x88)\xb1h\x03z\xb9S\xeb:\x84A\xfc4\xa1:z!=D\x11|\x8bI%\xbb\x17\xc2\x0cv]\xbc@Ax\xf9\x0eU\x80\x16\x0d\xa3\xbcu\xbc\xd6\xe6nP\x0bg\xab\x85\xf2\x18\x9e\xaf\xc8\xec\x12\x03K\xf1\xc05,\xf55\xe4\x0b\xf8\xbf\xe8\xa3\x05\xbb\xe0\xfd\xdfH/\x9a\x82Q\xb1\x03\x8a!\xb5A\xac\xf5\xf3\xe8<\xbf\xceHI \x87\xef\xed\x1f\xeeyMX\x89\x04\xd5\xc9\x13 \xf2\x10f6\xae\x98\x16MV,\xb6\xec\xc8\xb7\x1c\xc1\x86#\xdc\xab\xac&e\x16\xa72|\x8b\x8f\xc1%]<`\xc4\xac\x1a\x8cQ3p\xdd\xbb'NPf\xf5\xda\n\x95\xa5\xffF\x8dfK9\xc3&\xa4\x8c\xcb'%\x0b%(?\xea\x03\xc9g\x10\x088\x082r\x0d\x15\x9b\xae/~\xb3\x1a~\x1e\x04\x11\xe7\xb2)\xa3\x83\x87}\xd6zr\x04\x19C4\xbcr\xcb\xe7]r\xc16\xae)7\x99\xc7\x9c\x12\xba9\x89\xdb\x0b\xc3\x9d+s\x0c\x1c\xe1#\xb5G\xec\xd8\xf7\xc2\x86\x02\xb4q\\\xde^\x9c#\x00\xd1p\x8fy\x8f\xcbGk\x96\xc1\x97\xb9)w\xf3+\xd1\x92\xfb\x95\xea\xbf\x98t\x05\x86s\x16\xc9\xa1N0g\x8a\x1a\xe4l\x02\xcd\xadC7\x81,{\xf3uN\x92\xef\xbay\xd6\x94P\x17}\xd4\xfd\xf3\xdb\xd3\x0f=\xc7\x00Z\x9e\xbf}\xfd\xee\xed\xe9\xab\x0f'\x13\xd0\x88\x02'\xaf\xdf}\xf8?\x138\xe8\xbfY\x92\xfa\xc3M\xe1\xc4\xb8\xb7/~;'\x01\xdd\xe8\x11v\x83\xea\xea\xa4\xfak\x9c&s\x11\x15\n\xd1\xd6\xb0 \xf8\xbeN\"9\x05\x98@\x12\xd1\x99\x8a\xa4g\xa5\xef\x1d<\xd2'o\xec\x88\xd4\x067\xf1/\xb5=`\"x\x1f, f\xc68Y\x17\xf5\x8dD\xa4\x97\xf1\xac\xce\xcb\x1b'\x88R\x92o\x9bR\x1f;\xfa\x8d\xb1]\xe7\xd4\xa5\x90\xa7\xed\xb0l`\x90Dl\xa2\x94k8\x82<\xbcS\xd8\x9a7\x07\xdf\x05,Ve\x0f\nm\xf5\xf3\x95\xd6K\xdcpL\xd8\x00\xc5\x81\x94S\x04\xa7Tk\x9fR-\x86\xa9\xdc~\xc4v\xd5\xaf%\x83\x8e\xddb\x82ZK\xfbI\xf5\x01\xdd;\xc6M\xa8\x15\xc8&\x19l_\xac\xb7\xce\xd2\x88\xbd\xfc\x9f$#e2\x93cx\x9e\xc6\x95\xd5! \xf8\xd2j\xb0\xbeO\x9bX?\xad\x89:w\x92\xb8l-\xf9\xeb\xeby\x19\x9aQ\xfb\xe1#\xc6\xe1\xef\xf7rj\x08YB\x97\x81S\xec \xff\xa0\x9fiD\xd1\x94{\x91\xa7\x11,\xbc\x89\xe7.\x08H\x9c\xa1\xfc\x8b\x86\x7fW\xef\xceItIn\xe0\x18\xe2\x88T\xb3\xb8 >>\x08P\xc5T\xe7,G\xaa\x7f\xf8H57\x12\x7f\x8d\x89\xd9\xd51=\xa2\xc7\xc6\x9e\x92+\x9e\xa7\xa9\na\x16\xea\x13q\xd2E)BLr\xc2gQ\x1b\x04 %\xd2\x1e\xe5\x00\xd1\xb7\xcb\xbb`\x92\xaaxD\xf9\xaa\x9a\x13\xa2&\x94\x9a\x88\x94\xd10O\xbc\xae\xc26\x89'\x0dTy\x17u\xf4\xcd7|d\x18\xf4Or\xf83\x7f\x81 \xf1\x85p\xa2\x07\x8b\xc6\x0e\xa3\xf7\x84\x13\x94U\xeb\x05\x86\xda\xf0\xbc\xae\xb9\xc5\x97\xfaA\xb2\xd0\xa9h\xcb\xb2 \xa1\xc2tn3v(\xeeuo\x7f\x17\xec\xf6\xf7Q'\xe0%S\x7f\xe9N\xad\xc2\xec4\xfe\x92\xd7Q\x04lq\n\xf5\x177k\x02\xe4\x98\xf2\xa9\xf5?\xa2G\xbb\xb4!\xf6\x98\x07\x12\x06\x89\x0c\xa2\x92\x14i<#\xfe\x83\xe9\xc7\x8f\x7f\xff&\xfa\xe3\xee\xb1\x1fL?\x9e\xfdr\xfb\xf9\xec\xc12\x04\xef\xe3\xc7o\xeeyJ\xb5vW\x9f\xa5oT\x10\xfd\xf1\xd8?>\xfa\xf8\xf1\xa3\x1f|\xc6m\x1b\xed\xf2\x07g\x01\xb6\xf4\xcd~\xf4\xc7c\x86\x18\xdft\x03\xc2\xeb\xbd`\x85~\x8d\x8fV\xa7n\x96\x06|hF\xdc\x0d\x10?\x184X\xd8,\xef\xb7\xbf\xf9]\xff\xaf\x8e\xb2\xae\xe1*\xd8\x11\xb3(\xf3\xb5Qm\xf2:\xc6T\xde\x85\xff:.Z\x06|\xaf\xe3\xc2AQ\xd3\xaa\x85\xdbL\xb6\xd6y\x1e\x18\xdb8%5\xfb\xe8\x94\xd4\xad!\x9c\x92\xdaa\x08\xadZ\xca\x10\xfa\xcf{q\xa4\xaex\x92r*#\xbc\x8e\x8b>b\xae\xf8\xcbS\xd2am\x9c\x12\x9a\xcd\xa3\x8a\xd4\xecm{\x0d\xc3v\x0e\xea\xa1\xe5\x9fGK\xd2\xd7@\xb3D\xb8\xc3\x0d\xcc\xb9i\xa0\xe6\xe3\xd8\x16T\x8ew\xde\xe0\x8f?g4\xb4g\xa1\x85l\xf2\xf0@VQ<\x9fkF1\xecx\x0e<\x07\x83a\n\xd6\x98\x94\xfd)\xac\xf4Sh6\x94\x8e)\xba\xe2\x99\xe6\xbb\xee\x07\xc0\xb3\xf2\xe9\x9e/\xad\x13\x03Eg\x1a\xe9C\x1ai\xda\xbd\x19\xd3.&~~\x95\xd5>\xe1\x1e\x9b\xfe>ej\xf74\x8a\x8a-P[\\\xdf-\xb5T\xef\x8ae\xc8\xac\xc7c\xbd8s\xf4\xed\n\xab\x8bi}6~?\x0c7\xcd#.\xe9\x9av\xdd-*\xafq\x15D\xeb\xb8\xf0o\xb6\xd8.\xc3\xe3\\\xb3l\xf8\xddD\xf9.\xbb\xc9 \x00k\x0d\x00\\\xf7\x9a\n\x80\xb5\x1e\x00\xbf\xeb\xffE\x87E\x05\x85\xe9\x99\x8e/97\xf3%yo\x1eF\xf3\xa8+\x99\xc2y\xb6J\xd2\xf9\xab\x17:\x99\x0c\xc3Oe\xd2\xab\xfa|\x8c\xb5\xd7\xb5E\xc8\xf6>f\xd8G\xc6B\xd13\xcd\xffO\xd9e\x96_g\xc8s\xf8h\xc2\x0f~\\\x03c\x80\x16I\xca\xa2\xf2H\xd6\xe6\xef\xd1\x1f\xa7\x1f?~|p\xf6\x80Y\x1c\xef\x827au\xd3$#\xccM\x9a>\x0c<\x14<\xb19\xa69\x9b\xc3\xc5\x0d6\x9b\xc9\xf7\xaa\xf3\x87nB'}\xb8k\xf4\x05\xde\xef\xc9\xba\xa8o\xb0\xc1q\xf7\x1b\xde\xefk\xf2\xa96}(\xd4\xd8\xfc\x8f \xff#\x9a'U\x91\xc6hY\xca\xdc\x98\xf0i\xc6\x7fJ\x80\x0e\xce\xec\x93\x01\xa3B\xc4\x90Sz\xde\xbeh\xba\xd1Z\x97\x94\xa2b\xa3\x91\xefW\xcaE\xa5\xb7\xd7\x19)_\xbd\xe8a\xab\xd4\x8b\xa2\xe5\x8c\xae\xef<\x08B\xb8\xc6\xfc\x91\x80\xb1\xc8\xcf\xab|S\xce\xda\x1cE{'\x9d\xf6\xb4\xb6yvJXH\x9d\x92dcL\xab\xf4\xd6\x92\x14\xd03\xdf\xdb\x7f\x88\xd1\x923\xb9\xa1\xe8\xee\xeaW\x97\x92z\xc9$\xf5\xb2\xa5\xbe(\x87-\nY\x8e\xb9\xd2\x90Z\x1f\xb8\x0e/\xf7\x13\x93m\xa1\x1ck+:\x7f\xdc\x8cY\xaf\x8c\x8b#\xc2\x83\xf9(\xcch\xeb!6\xbaO\x1b\x8d\xa3\xa4z\x9do2\xba\xc9Xo\xdf\xed\xb7;+\xe2\x92d57\x90R~\x1ea\x8cr\xe5\x01^\x8e\xca\xd6\x0f<&\xec\xc9\xf7.\x176\x1d\xd5h\xf6\x03Y\xe4%y\xdd\xbaAu3\xe7/}c\xb8H\x0e\x87 h2\xaf\x03FSc\x03\x9e@\xa6\xaf\xc0\xec\x9e\xcc\xf6oby&05\xac\xbd\x84\xb9\xd9V\x8f\xc55\xe4\xc1s\xc6Z#\n\xc8\xfd\xc4\x1b\xd1\x83n\x9b\xddC1JA\x194\xfe\x91\x98\xd5\x8bb\xd5\x1b\x96y)\x87N|\xfd`\xea\xf6V\xae\x95a1\x97Va\xf1\xa6b\xf0\xc6r\x95\x92g\x030\xdbf\x8c\xa8\xc7m\x01\xac\x8e\x94\xb5\xdd\xdd\xb5\x8c&[\xdf)\xc8X\xa4\xc7\x16\xa4\xf6\xf5\x90\xaa|\xa2K\xc7x!\x82\xf7\x0f\x8d\xbb\xd8\x94K\xc2\x87N\xe6r\xf0\x95\xc5\xd5\x14\xc3j\x9eF\xe7EI\xaeHV\xbf\xdb\x94\xcb$3*j[\xc9\x94\xf6\x9e\x02\x81\xef\xe1B\xd2fb\xa6\xcd\xb4\x9c\xfb\x17Sr\xe6\xaa8\x03\x9c\xf8@\xd0\xfa\xe1[\xdaf\xb7\x7f\xc9\xe2 \x85\xcaN\x17\xa9\x86\xfa^\x92\xfa9\x8f\xecW\xc7\xb3\xcbg\xf39\xc9\xe6\x9b\xb5\xebHtVO\x836L\x82~\x9c\x0c\x86\xaf.\x99\xe5$Z\n\xe9\xcf\xbe\x1av\x8f\x18\xeb@\x1a\xae\x81s\x11\xd2*\xcav\x9e\x80\xa2\xe4Z\x88\x08\x87\x06\x8aL\xc1N\x9b\xcf\xa3\xf39\xb9\xd8,_\xbd0\xae\x00\x8e\x0d\x99\x9d\x16L\x7f\xb8y\xf5B\xc4\x9c\x17EcB\xdb\xfd\xc4\xb6\x14\x12\xcd\xf9z\x00y\x1a\xb0!|B\x8e\x9f\x08\xce\xeb\x1d\xdf\xbcC\xc8\xd3\x15i{\xb8\"\x8f.7\xfc\x18\xc4T*\x124\x12\x0b\xa6\xf5\xb4t\xaf0\x8f\xae#\xe8\xf0\xb1\x83\x839q\xf3)n\x1at\x1d\x84\x03\x18\xc4\x19\xe9\xd4=g\xb9]\xbbw\x87\x01\x12\x0e\xb6\xefpT\xecO\x89\xf2n\xa3{'\x19$\xb7\xe19@G\x1e\xcfk$Gi\xff\x15Y&UMJ\xc2\xe8U\xdc\xe5@\xaa\xd5\x9b<;\xad\xe3l\x1e\x97\xf3\xbf\xc5e\x96dK$\xbe\x0e\\\xb0\xf1FB\xa4>,I(\xf2\xc2N\xaat\xd8\xecH\xa2N2\x94;\xb5/\xc6\x86\xda?\xc5\xa7\xdb\x1b\x010G\x97\xeeu\xbf\xde\x9e\x969\x1b\xba\xe9{\xa09gH\x14\xcf\xe7'T\x80\xfc\x91{+2'\xa8\xeeSn\x1e\xb6\xb3\xaf\xb5\xadn\x1a]\xe7Wc\xd2\x8a\x08\xff{C_c1\x90\xc5\x9b\x881\xa4'6\xc9'\xd3<\xf0=\x8a\x00\xbb\x0c4w<\x959\xd1w\xb3\xcd,L~\xb5\xfd\xed?\x8b\x8bzS:\x06\xee\x80\xedW~\xef\xae\xc15\xb0\xf2\x9a\x8bKQ\x06`f\x1f]\xa9\xff\xd8\x05\xcc%\xe7\xa0^\x88$\xba\xeaL\x8d\xe6\xdf\xad\x84kwA\x0d\x1e\x1f\xe8\xc2\xf8\xd1\xe7\xfaP\x11\x87\x8f\xba\x99\x00\xb8[\xddw\x07A\xbb\xfd\x8d.M/\xf3aM\xf2\xecy\\\xc4\x17I\x9a\xd4\x89=u\xc2\xd5\x97&\xa0\x80\x8e\x14\xe6\xb7SQ\xdc\xbb\xc7\xb2Ox<\x8d\x00^\x1b}\xfe\xdcKI\xc1\x9e\x95\x1b\"*\xceXL\xff\x93yR\xc7\x17]\xa7`\x93\x03o\x92g\xaf\xb2E^\xb2(\xf4\x16\x0c\x17\x1a\xb6x`Jz4\xc5\x18\xfb\x04\xdd>\x8c)\xbe+1\xa0\xf7\xccc\x1c\x03\x1cj\x97\xc8G\xb7\x91M\xa4\xce\xc2'Zy\x1el'nI\xaa:/\x89l\xc7i\xf9\xd9\x05[lJ\xda\xc3tZ\xca\x9c\x0d\x13\xc6j\xedi\xeb\x14\xed;G\x9c\xe9\xc7\xab\xb52\x84\xdc7\xe5l`\xa1\xe30!\x90\x19z%\xd6\xd8D\x95\n\xbe2\x84*\x08!\xf1\xcb\xe1\xd0E*\xcc\x9d`\xa5\xd7\x1azr\xda\x18l\x1e\x13Q\x90\x007\x96\x1e\x83*\x16\x93^\x81\x17~\xa8\x87,\xc9\xe6\xad\xaa'\xd9\xbc\x8f\x15\xfd\x81I\xebP ^\xd9B\x7f\xb3\xab\xbb\xd6\xb4\xf1m\x12a\xbf\x1f\xee'\x87\xb8`\xf2\xf5\xcc\xb8\x8eD\x08*\x01\xf7\xb4\x12\x18b>)8\x10\xefg\x11=1\x10\x80\xbe7[\xc5e<\xabI\xe9\x85p\x9f\xa7\xf9\xe2\n\xee\x01\xb1\x04A\xcc\x1b\xa2\xcc\xe3`3\xdaV4Y\xfa\xb9\xddR-\xd2]\xbd\xc5\x98\xf7\xd5\xb0*\xe1\xf3\xe7a\x941\x98\xb8\xe3\x04F\xaa\xef+\x03\xf2[n\xd0\xea\xa82\xe3*3\xbb$\x99&\xd6\x15E\xc5V\xaa\x7f\x91\xb6\x9b2w\x86\x1d\xd4\xdd \xb4v\xd8\xd9\x0bp\x04\xaf\xe3z\x15\xad\x93\xccG\xa7\xad\xd6b\xfd\xc6\xfb\x02\x1dt\xf86\xf8@>\xd5\x83[!\x89fy\x9a\xc6EE|d\xe1\x12\x13bg\xf2e\x0fYs\xb8\xcf_\xb3Y\xe9\x12\xcf\x8aH[\x95\x82\x93CQ\x94\xf4<\x12\xcb/\xb8\x15\x8f\xe4\x96\xe2\xa6\x830>\x01\xee\x8d\xd9q\\\x11\x02\xa2XO8n\xfe\x14\xdcy\xd0\x84\xe2\xeb+B\xf5\xea\xa5\x86\xf7\x9e\xd5\xc9\x15Q\xf2\x08\x91\xe8\"\x9fwRH \x81z(\xbc\x8f\xee\xbb\xdf\xb5\xff\xda\n\x9cW6\xef\xdb\xc7z\x86\xb3\x17f:\xd6\xfb\xea\xb2(\x0e\xfb\xdfv\x1b\xafZ.^}\x0f\xaf\x94\xf5\xf2\xb0+\x15\xcf\xf8\xf3n?\xcc8\xfe\xf0\xdb\xee\xf3\x82\xcf\xad\x1bub\xce\xfa\x17\xe1\xb0\x1f>\xea\x0e`\xc5:z\xdcy|\x85\x8f\x0f\x0e\xba\xe3Z\x8364\xdb\x92u\xdf\xcb\xdfu\xc3\xb9\xf6n3\x17\xaa\x03\xdb\xfe\xc3'\xddQ\x9d\xf3\xee\xbb\xd3\xb9n\x1c\xdb\x92~\x00\xe4N\xe5\x13\x8cQ\xa6\x8b\x1f\xdc\xaa\xf6 \x8e\xba\x9e\xd2\xa7p\x04O\xda\x8f\x9e\xd3Z\x9dj\x97\xc68\xde\xcf\x8c&h\xcc4L&\xcf\xa2\xbb\xf6\x14\x1fu\x93qMZ)\xc8\xba\xac\xae\xce:\xec\xad\xb9Sz\xb6\xca\xa0\x80\x8c\x84\xabO\xfck\x96\x8ew\xd8\xfa\xec\x9d\xd8n!\xf2\xa4\xdd\xbe\x90\x96\xb7\xa9\x06%O\x8b\xa8\x9f5\xdbtv\xc6\xe6\xe8=\xec.\xd1\x14\xf2\x03\x8e\xc0C/~\x16\x8ck\xc2L\x155w$1\x1cC\x0c\x13\x88\xbb\xf6x1\x9a\xe2\x05\xa1T\x95\xd5\xc9\x9a\xf4\xaet{\x13\xa6\xfb~\xd5\x89\xf3@\xc1\x94\x85<6\x01w\xa9D\x07\x98n\xf8\xa8DU\xcd\xd1\xfe\xe8Q\x95`\xc8\x81s\x16\xbdC1\xa0\x88\xcek\x0eD\x1e\x0e\x89e\x87\xffQ\x8d\x88\xf0*\xabsLa\xbd\xc1\x85\"\xb8P\xd9\xb0\xb5\xe4\x07eUuKJ\xc9\xe3:B\xe0\xbe'\xb3<\x9b%)\xf9P\xc6Y\x153\xfeuI\xeawy\x9e\x92\xb9\xbf\x83\xcc\xc1,\xdaT\xe49\x9e\xe6|\x01;\xb3\xce\xa3\x82\x94T\x02\xf5\xdf \xb1\x11\xe4|\x10\xe1`\x7f%I \xe5)\xf2\xe1i\xbd6\xe9\x8d\xf0*d/\x84U\xb4\xc94\xeb\x86\xd6D\x9d\xed)\xf8\xec\x9e\xf4\x15<\x85\xbaI\xfb\xf74\x80\x9a\xab\x81\xf0\xb7\xaf\xbc\x1b\x1e\xec+\xb3\xa5\xf0\xb3\xf1\x96\xc2U\xa4\xcbj\xae\xf3Q\x13f%t\xe9>\x7f\x86\x9d,:_\xe5\x15\xbf\xdb\x18cC\xfc\xb3\x91\xf4\xec\xf8;\xdc\xdeU\x02u\x07\xfd\xde$\x1f)\x9f\x9dj\x9e=\x1f\x06\xdc\x1b3\xe0\x1c$U\x0e^=\x9b\xce.\x88\xef\xdd\x1b\x0fN\xdc\x06mX\xf20{\xfd\x9bW\x93e-\xbb\xf6\xc2\x16\x9e\xe7Y\x1d'\x19)_e\x8b\xbcO\x05z\x07\x83\xf8\x8bN\xf1}\xffl{a\xb3\x88\xc7\x08R%^\xbe\xc2\x11\xbc\xefZ\xa95\xc3}\xa1\xf8(%U;\x88\n\x0f\xe7\xf9\xa2\x15\xd9\x06\xe3\x11\x0d\xf4.\xe6N\x07\xa0\x10\xfdfn\xb4A\xde\xd3\x87\x1e1T#\x82\xd2\xb9\xff\xd8\x93\x8c;\xdfL\xe0E\x87\xeb\x10A\x11\xaa\x1fn\x18\x01B(L\xe0\xb2\xc3\xd4a\xa2\xd4\xd7y\x96\xd4\xb9K\xc4\xc7\xae\x84\xd1\x112\xcf\xd9\xbd8\xedl\xc0\xd2U\x7f\xe8B\x03\xb6\x1f\xa3\xd6\xb8\xfc2\xb4\xab\xaf\xaf\"\x92\xfdcC6\x82T\x8b\x00\x19\x92x\x86L\x08\x95\xf5\x9e\xc7iz\x11\xcf.\xd5\x8a\xb9F~\xa2\x87\xd8\xe0\x9c\x196\xbc!\xd7\xd6ik\xe7\xfc3\xcf\x19R\xfa\xde\xe1w^\x10\xc2&\"Y\xb5)\x89\x92\x14\x97\x03\x02\x93J\xf77\xab\x10=1\xde<\xc6\x13\xee\xd6XG\x17T`!sf\x0dQ\xf9\x1f\xd0\xacY\x8cJ\xdf$\x0b\x8c+1\x89o$#\xad\xb8\x9c\xc6g\xf4\x8bp8\n\x07\x83\xd6\xe9\xe6\xa2. \x9e\xf2\x92(8C\xacc\xc6\x82\\`\x11\xadbT\xaerH>\xa6\x90\xfcQ0\x1f\xba\xee\xd4N\x1c\xd6\xf7\x8bF|\x15]\xc5i\x82&#\x1c\xeb\xfc<\xe4|\xde\x8b\xb7\xaf9A\x11\x96\xec\xad0C\x0dr<\xf1B\x93\xad\x8c\x07\x94\xaa\x93\x18\x83\xa3\x15qU%\xd9\x12b`\x95!M. \xfca\x9e\\\xfd!\xc4\x97\x80\xfdr=\x85\xe8\x07\xdf\x07\x90\x97\xf0\xfd<\xb9\x82\x07\x7f\x8a\xd0-DL\xd0\xb1\xc7YJ\xdb\xc7\x0e_\xe6\xf9@w/\xf3\x9cu\xf62\xcfEg\x99\x1a\x03Z\x89U\xc6\xf9f\xec\xf5\xc3*\xa9`\x1d\xdf\xc0\x05\x81Y\xbc\xa9\x98W\xcd&K\xf0\x02!\xc9\xb38Mo \xcd\xe39\x1dP}\x9dC\x92\xcdIA\xe1\x9b\xd50\xcb\x8b\x84Tt\xc8lL\xdc\x07\xc7\xb0\xa5\x98\x9fX\xdc\x19\xf9\x0b\xd3m\x1bR\xf8 h\xe2\x9ci:\xb0\x9a\x9fRq\xbb\xe0n\xa7\x06\x05\x122H\xe7E\x99\xcfHU!o\xc6\xc3\x99\xfaUt>c\x7f\x1a\x15B\xf4\xeb\xa5~\xe2T\x92\x7f\xe3\xeb\xf2d`\x12\x8c\xa1QSa?\x1d\x12{\x0cSY\x80\x7f\xee\xcf\xd8\x15\x80Y\x07L{X\xb0\x1e\xfaB\x05\xe5\xde7\x17i2\x93\xf1\xbb-\x96)sa,k=[\xd4\x9237\xf3\x85\xf9\"\x14@\xab\xa1\x17E\x9eq\xba\xc3\xd2O1\xac@\x82\xa4d\x1e\x84\xb0\xd0\xb6\xa3\xbfk\xfd\xb1'\x07<\xc3\xd8xvS\x0e\xe0\xc0]!\x1f\x99\x19\x00\xb7\xa6\x12\"r\x84;o}\x93\x82\xfd\x06\x8e\xe0\x95\xb1\x89\x0b*\x82a\x13)\xfe\xab C\x00\\9\"\x89w\xf7d\xa5\"a\x16\xc2E\x08I\xe0\x88\x08\xc6C\x8b\x1bK\xe3\x92^\x07!\\\xdb\x8f.\xb7\xfb\xfcf\x95\x07N Ud\x1c\xce\x08\xa2_X\xdb%\xd6\xcf\xcd\x81\xf8p\xcfD\xe6j\xdc\xed:\"\x83\x8e\x0c\xc6T\xb5\xaf\xd0n{_Q\x96\x7f\xe0\x01\x020\xd4D\xa3\x9191\xd0/!V\xed; '\xaf\xcb\xddc/\xa7u\x8f/9\x0b\xfb\\\xcek\xa1;@\xeb\x98\x9e\xb7n\xeb\xa7F\xf7\xa0;\xde\x93\x10b\x1dD(\xac\x14N\x8e\xb9\xa5\x0d\x86c\xdd\xe0^\x1b\n\xee3\x8ffq\xf6\x9el*\x9e\x19\x8a\x8eb\xd3\xc92C\xc5\x0b2\x8bg+\xc2v:\xad\xa1oQP\xf6M[_6\x8f\x9e\xff\xf9\xe4\xf9\xff:\xfd\xe95\xaa\x16\x99\xf6Q\xdf\xc2\xa6\x97\x93c\xc4\xc7\xe2t\xd8D\xf9\xa6&\xe5\x9f?\xbc\xfe\xd1\xd4Ke\x1b_\x08\xdd\xa8\xbc\xa2\x88\x13b \xb5Q\xe1\xe2Y\xaf\x16\xe9\xba\x90\xa9\x97O\xe2\xce)\x94\x9e\x94A\xa8\xfaWf\xcc\xb1r\xb0e\x10\x8c\x80H\xf5\\\x06\x9c\xe1\x91\xbf\xe5j\x1b\x1c\xec\x85P\xc0.\x1c\xec\xa1S\xf4\xc7\x0c\xfc\x8a\x94W\xa4d\xd5g\xe6\xea\xfa\x99\xe9tWtg\x1dx!h\xaee\xfb4\x03\xb5K\x86F\x0e\x19\xaf\xdd\xd3\xef\x19P\x81\x07\x98r\xd5\x90\xe9'\x94GIV\x91\xb2\xfeP\x12\xc2\x1c\x1b}F\x9d\xe81`\xe4\xd3.X\n\x80P\xb3\xd3kE\xab>\xf2:\xefG|\xfa\x85\xf7O\x87\x8f\xbe\x0d\xf4\xcd\x9b\x8f\xa5\xc6\x0fH\x03$TM*\x1a\xe37|\xed\x98\x95@\xd9DS}\x1a\xa01\x8fN\xb9l\xd0A\xb1\x060\x00\xeb\xb1\xf6;\x98\xc8Z,\xe4+\xcf\xeb\xd7\xb3\xf8\xfb\x82\xab\xbb::?'\xd5\xeb|\xbeI\x89F\xcd\xc3C\xb2f~\xf7\xea\x0d\xc3\xe7b\xbc|4\x7f)\xd5f\x8e\xa1\xd4Z\xd8\xcd\x859\\\xdb\xb4\xeeV\x1d\x0d\xaf\x83r>\xff;\xaaVqA:f\xd3t\xe7\xce\xca\xe4\x82L\x94\x8at\xfa\xa8\xc2\xfa\xc7&)\xc9\xbc=\xe2yR\x15\xf4,v\xfe\x80\xf9\x94\xd5C=4+\x10\xdc\xe1\x12\x84-8\x98\x11W\x7f\x0b\xcd\xaf<\xc0\x14\x16I\\\x89\x90\xb2\xccK\xf5\x8e\x04\x1f\xf4\xb8.\xfd\xddt\xbd*\xf3k\x8c\x80t\xc2\xbfj/\xa9\xde\xbc\xdb O\x95\xcb\xe4\xc7\xdd\x1bJ~\x9b\xdc\xb3S\x14\xa9\xae\xba7\xa41\xaf\xdf\xc5\xde\x0d\x7f\xdem\xbf\xe2\xcf\xbb\x17\xc0\xfc\"\xb9\x97^\x80_$\xf7\xd2\x0b,\xf8\xf3\xee\xc5/\xbbH>x\xa2\xbbH\xce\xfc\xc3\xc7\xddy\xb1\xfb\xe3\xfd\xc3n\xfbW\xbc\xfd\xee\xb5\xfa\x9a_\xabw\xdbY\xf2\xe7\xddy\xb1\x1b\xe4\xde=\xf4\x05\x07\x7fw\xba\xe7\xbc\x99\xeep\xae\xf9\xf05W\xc4\xb4zw\x94\x9f\xf0y\xef\xda\xfa\xb4\xafN\x7f\x0eG\xddh\xda\x97p\x04\x0f\xdb\x8f\x9eQN@\x04\x00|V.\xf1\x12\xa9:\xebD\x18|\xab\xd6\x12\xa1\xeb\xba\x95\xde\xa9\x950\xf4n\\\xe7\xa5\xa9\xf6\x07\xb5\xb6\x88<\xd8\xae\xf2\x9a\xdfb\xcb\xdf\xd3gg\x94g\x9b*\x03.\xe3\x9b3O\xf7\xf4\x87\xcdbA\xca\xde\xbb\x17q\x1d\xff5!\xd7\xbd\x17<\xc7\x87\xee\x03\xd2{\xf82\xcd\xe3\xfa\xf0@\xdf=\xbe|\xf4P\xff\xf2UV?6\xbe\xd9\x7fd|e\xea\xecu\\\xf4\x9e1\x17\x14\xf1\xf8C\xe7-\x8b \xd8\xfb\xe8\x94\xd4\xfdg\xc8\xdf\xf5\x1f\xdf\xac/\xf2\xb4\xf7\xf8\xa7\xc487|\xf5<\x8d\xd7\x05\x99\x9bk\x98\xa6O\xdf\xb5\xe6O\xc9\xbc\xf2\x1e\xc9\xa8\xf8\xeam\xe7\xe3\xbf\x91\xf8R\x02ig?\xd4262,\xef\xab\x10~\x0e\xe1M\x08\xefu\xb7w/B\xbc\xbb\xc9\xe0\x1e\x9c\xf6\x99\xeb\x9f\xf8\xab\xe7\xfdW\xff\xe0\xaf.\xdb\xe7\x03ei_\xe1%\xee\x0b*\xb5\xc31\xbc\xa2\xe3\x90#\x98\xd0\xdfA\x10\xaa\xda\xd3\x17R\x84x\xd1ol\xe7Z\xcd[\xdaa\x9e\xe8\x0c^\xe2\xbdBWJ\xa5\x9f\xbe4\x89\xc1thW~M%\xee\x1fe\xd3\x18\xd5\xf7E\xf7\xe02\xc4\xbf\xa5\x1d\xff\x13\x8e`E[\xe9\xbd\xa5\xe5\x078\xa25\x8e\xe0-\x15\xb8\xf1\xafwz\x05\xc6\x85:\xc1\x8a\x8e\xe2G\x83\xaa\x03[\xf9 \xdb{F\xff\xfa\x01\xb5ToLr\x81\x98\xeeO\xac\xee1\xfcr\x0b\x13Xv'\xff\x13\x1c\xc3\x82v\xbd\xf1_0\x1d\xe7\x04f\xf4w\xcc\x7f\xf7\x1a7\x82F\xf4\xba\xf3z\xfa\xcf3\xd9\xc1\x1b\xee/\xfb\x8bA\xefH\xc7\xb8\xa6\x1d\xfe\x93N\xbf\xdf\xdb\xef\xcc\xbf\xde\xa3\x0d\xde{`!\x18\xcb\xa0\x8f\"\x7f\x85#x\x8f\x9aj\x1d\x9a\xfcU\x0e\xf2\xaf\xfd\x97\xef16#bF\x88~\xed\x0d*\xca\x08`\x92}\xe9\xd9t\x00\xde\xdcbXC\xbf\x14\xbb\xb1D&\xe7}\xd7\x12<\x08u\xe8\x7fn\xeb\xd2p\x9f\xf3\x02\xc7\x9d\x87\xa0t\x9c\xbbvLa\xf6g8\x82\x7f\xc01b\xc6\x1c&P\xc0\x04\xff\xbe$7\xd5\xab\x0c\x03\xe2\xf6:\xfd\x1b\x1c\xc1K8\x16{{\x02\x7f\xee\x01\\h5\xfd\xbf\xd1U\xab\x15\xde\xcf4\x93\xbf!5)1\xc6\x13z\xe8\x9e\xa1%\xfd\x0b\x9c\x8f\xdb\xec\xe4\x93\x91\x1c\xe7\xc1\x93.\x87$8N}\"\xaa\xef\x1e\x8f\x9669<\x12\xe6u\x81W~;\x18Z\xbc\x95\xeb`\xe4\xb8\xf7\x1f\x1b\x92\xc2\x1ety2\xce)?\xd6g\x85=x\xd2}\xbei\xc2\xf62\x0f[\x11A\x97\x1d\xa0\x15%#\x83\n\xdfV\x94\x8d\xe9\x19\x8b\xb2\x81\xce[\x14\x04<\xcc\xc6\xb0{{{}a\x02\xb1\x1e\xe8N\x06\xc1\xeab\xeb\x81v\xd8cX\xb9{\xd4\xf6\xab\x8d\xcb\x9c\xb4\xaeuG\xae\xf0\xe3\xc7z\xcc<\xec\xc9H|\xb0\x8f\x0f\xb7\x1dl\xe2+\xa9\xa0\x99\xc9\x18&\xec\xf7\xbe`\xf0]4\xcc\xa5\xde2\xfed\x1b\xa6\xfeF\xa3Q\xa3@\xaeZi\xd7\xa8L\xe1Z\xc6\xfb\xb0\x0f\x13\xc0\xe0\xfd}\xe2e\xbdc\x93\xa8KA\x1a\x0b\xb9\x82\xc5\xfd\xbc\xbf\xcf\xaebs?i:c\x1d\xa1\x14\xc9\x82\xf7o\x82\xa7\xb0\xbb\x1b\xc3\xf7\xb0y\x1a@\xc5\xcd\x11\xa65\xecB|\xa6?\x17Y\xe3\xfawr@\xa9\xec\x816\xb5/{\xa9\x9f\x06\x90\x8a^L=\x08\xf6\x87\x05\x0c\xcd\xfc\nS\x8a\x11\x96S3\x04\x9d\xdeo\xfb\x85\xefn%a\x0f\xbe\x1f\xf8\xa5\x01A\xbf\xc0\xf7\x91S*\xa6\x15i\x12\xab\x87\xe05*\x16\xaf{Y\xce\xb3\xd3*w1\xb7\x81A\x05c@B\x0d\xd5\xcbzZ\xae\xa6\xf5\xa7=H\x99\xf7$\xea\xe2\xd9\x0dV3\x05\xc9\x1f\x90\xfe1^w\x04N\xd1\x884M\xe9/\xafr\x9b\xc0\xbc^,q\xdayTs\\\x11\xb4\xdedQ}\xc94;3\xd8\xdb)\xb0\xa4k\xd9\x80\xc2\xcf\xfc\xfd'\x07\xc1\x17h\xcf\xbe\xf6\x92\x1bM \xf54\x03\xc3\x88\x18\xbd\xa4\x92l\x91k3\x87\xd1\x92\xe6Km\xee0\xc0\x94\xb5e6\x81C\xfdKT\xdcM\xe0a\xef\xa5\xc659\xb3\x1ao\x82\xb2nSrF\xb9\xb6\xfb\x9a\xfb\xd0~\xd3\xccOs\x96g\x8bdYEi\xbeDs\xc0~=F\x02J5\xdb\x00\xa8f\xa7\x89\x8d\x91`\x97Z\x92 \xcb[\xafDR\xc5\x12\xfe\x04\xfb\xa8\x87f'\x00\xa5\xca\x94\xb0\xee?\x05J&\xcb\xa7\x10\xef\xee\x06\x94F\xd2\ngjkZ\xb2\x89\xa0\xfa\xd3\x91\x12\x92\x95+M\x83)9\x8b\xe2\xa2H\x11\xe5\x06\x0d\xda\xc5\xe9\x1a\xd1\xb5D\xfd6&)f\x17\xee\x1e}\x88\xf7\xb3\\/\xdb}\x8fOY\x05\x8aD\xbd\xf7\xf4!{\x8d\x18\xd8{\x8fO=\xad[>^Vc\x0e\xa8\xca\xe4\x17\x8f\xa8\x99\xf4\x91\xc00]\xa7S\xc2\x9a\x07\x8e21]M\xe3\xd7\xb9vpc\x8f\xc4\xc6\x978\xae\xa5u\xfa\xb3\xc0\xc0`\x90\xce}\xc4:\xbe$\x7f\xae\xeb\xc2\xa7\xc4\x97\xbc\xa4\xaf)Y*\xf2\xaa\xc6\x1f\x06\xd5\xc3\xc5&I\xe7\xef\xc9?6\xa4\xaa\xd5\xe6\xd4\xe7\x06\xd2\xc1r{\xab\x1f\xf1G\xfa\xfa%\xa9\xf2\xf4\xaaU\x9f?\x1a\xac\xcfMM4\x9f\xf17\xfa\xaf+R&q\x9a\xfc\x93\xbc'\x95\xfa\xad\xfa\\\xffe^\xbc\x9a\xab_\xacHZ\x90\xb2\x8a\xe8\xf3\xbbEc7\xdc\x91\xc4\xad\xd6\xeb\x0c\xf0\x84\x9e\x96\x8d\xfa\x84\xfe\x10-\xf7\xe9\xd1\x15w\x1d\xa1\xb5\x8cGQ2\x81\xd2p\xd2\x98\xa3\xe3\xf2.'\xba\xa8<\x1aM\x8e\xe0C\xe8h\x91+\xc8\xc5\xa0Q>W~\xa1\x97N\x94r\xcd\xa7|a\x00=\xf0If\x1anF2\x15k\xceNDx\x0d\x83\xe7wGp\xd0\xb9\xdd\x00^\xb9\xe5\x9c\x7f\xf9\xfc\xd9\xc0A\xb0\xaf\xf5\x90e\xfb\x7fS\xc6\x17)\x19\x00e\xb6Y\x13Q\xc7\xc0\x10,I\x8f.\x01h\x82\x10C\x1d\xd9On\x01\xb0\x1e\xbf\xa8\n\xe9\x96#\x9f\x88-\xd3\x1f\x138Dl\x11\xad\x8c\xc0\x9d:\x9a\xfbY\x08^\xcc\xfd\x8a\xb3\xfe\xd4s\x17\xfb\x18\xde\x9c+\xef\xdaO\xbdRG\x05KL\x05\xb5_Gt?\x1f\x1c*\"\xaf?\x1d\x1c\x82J\x072\xff\xe1\x81\xf2e8<\xf8\xce\x97\xdfn\xfbek\xb4\xe3\xbe\xdc\xba\xcf\xc3\xc3\xc7\xe6O5R{\xfb\xd0o\xbd\x92$\xb2\xd4c\xb7@-\x0dr\x13c@\x1fy\xf6\xdb\x93T\xea\x07\x93\x1b\xf1M\xec\xb6.\x1f\n\x7f\x82\x83\x8e\xb5x\xc3\\\x1e\x9c\xc1q\xfb\xe7\xc4\x98\n\x8d\xb29\xbe\xa6\xf5Cc\xeb\x87\xed\xd6\x0f\xcfP\xff\x1eDW\x07o\x0bRbL\x9aWh^\x12\xd7 \xc6/\xb9y\x9d\xcf5\x1e\x9f*\xa8[\xa9\xddTE\x0b&kP,\x10&\xe8\xf87\x13\xf4#\xf0I\x10\xb0(Qy\xd39s\x84U\xd2r}\xac0\xc7\x96\x174\x86a\xab\xf6'\x01L \xe1W[\xfaE\x1e\x9e\x9e\x9e\xbej\xfd\xc5\xcc\x02\xc9@8K\xdd\x12\x8dC\x00\xfb\x12\x99\xc8\xad\xc0A\xbfnG\x84\x80]\xf0\xce1}P+QZ\xb5\xf3\xff\xfd\xfe\x9b\xff\xf1\xf7{\x7f\xf4\x83\xf3\xdd\xa3\xe9/\x1f\xcfn\x9fN\xbe\xff\xd3\xe7\xe8\xe3\x83\xe3\xf0\xe3\xc7?x\xde}\x96<\xed\\g\x99\x0b\x0df\xb0\\\xe8\xcc\xf3\xb0\xb1\xa1\xdbo\xfa\xad\x95~}\xff<\xf8\xe5 \xbc\x0dD\xd3J\xe6\x12\xff<\xf8\xa3@\x80\xe6\x83\xe9\xf9Y\xf0\xc7o\xf8s\xcb\xc6UF\x851X\xe7~M\x87\xd1\x0f\xa4nX\xdc\xd8v\xa0\xf0\x06\xbd\xfb\xfdtL\xa667\xb66+N\x1fw\xf6\x90\x03q\xc6\xc4\xcaDWA\xdc\xc1\xb1\xe0Vb\xcf\xeel\xb3g?\x7f\x86\x1d\x12\x15q\xbd\xaa\xfa\x8du\xaa\xb3jC\xb1-@Qs\xf1\xea\xfd\nR\xb6\xcf!\xc9\xa0\xd4\x9b\xa8*\xeaXZi\x9a\x1b\xa2\xcc\x03\x87\x85\xf7\xee\xd9\xfbg\xafO>\x9c\xbc?e\x83O\xa2:\xff\xa9(laSD\xb9\xe2\x0eg\xb4\xa7ibP\xa6\x8aB;\x8c\x07\xe9el\x83}\x1cX\x87\x04\xd0\x18j\xdbk\x8aR\x15df\x8c\x13\xa6+t\x95XX\xd1\xdc\xfd\xa35\xa9W9\n]-(\xbb7 i\xfed \x9c\xa8Z4:(]\xc1\x0c4\xbe\xc9\x06]-(\x85\xa1W\xb2D\xe8\xcd\xe0Gz\xa7\x97\xfe\x9b\xf6\xaf\xadT\x96\xa0U[b\xe3\x9a\x0bp*g\x95~\xe6\xef?\xee\x06\xff\x00n\xb6\x86o\xbby(\xea(\xa9\xde>;=t\x125\x98.$/H\x16\x17\x89\x91\x89\xe0Y\x15(\xae\x17\x0d\xae\xd3\xc9\x1ez\x1a\x16<\xa9N\xaf\xe3\xe5\x92\x94\x07#\xc6P\xb1O\xb6\x18\xc3\x81n\x0cy\xf1j\xce\x12\xf0\xd7Q2\x7fY\xe6\xebwq\xbdz\x8d\xf8\xcd\xdcI\xeb(%\xcbxv\xf3\xaa\xff6\xa6o\x97\xa4\x96\xc7\xf9\xfb\xf8z\x84\xf8\xc2\xd9[F}\x8f\xd9Ib\xd7\xd7J\xc9/\x12[\xd7\xbc5\x18!f\xbb\xd5\\+\x11\x8b\xcb&\xa1\xdf;x\xe2$\x83'Nb\xa3z\x89\x12\x19i\xc7p\xef%H^\xa2\xf2\x85\x83\x0c\xca4\xf7\x13\x19\xf0\"\xf6\xf9\x1f\x9b\xb3\xa8\xca\xd7\xc4\xb7\x03\x14\xba+\xc2\xee\x16\xb5uu\x91\xd7\x0c\xd9\x10\xd0>>\x9bK\xdc\x80#\xd8\xd0\x87$\x9e\xad\xd4\x87\x15\x8b\x93Q\xaeQ\xcb\xc5w\xc4\x98\x0dQ\x90\x99~mY\x005D/\xb3\xd4\xa1\xb3\xd9\xc1\xb5F\x96\xaf\x8e\xbe\xf9F\x8emn\xba\x8b\x82\xde\x89m\x0c2+\x0e\xda\xccx\xca\"\x9f\xbd\x17\xc2\xa2uZ\x0e\xac\x9d\xc0\x18\xcc\x92\x15\xafIMJ\x0d\xdb!\x8a\x1cgE\xc7\x19\x07\xb0\xe3\xb0\xe7D\x91r\xe0\x948\xf0\x08;\x9did\x0d\xf6{\xb3<\xab\x93lC4\xa9a\xd4r\xc5]qs\x9f9\x7f\x99\x9cqE\xa1\xddj\x83\x02uK9\xad\xa8tB\xffc\x91\xca3\x8a\xc6\xf8\xf4\x08\xa6\x99ev\xc0\x87\x86\x87\xcb\xb4r\xa8M\x076k\x84\xa6\xfd\x00f}{'\x13\xbd\xd4\x15\x12\x9d\x9f\xe7e\xb2L\xb28U\xc4)\xe6\x96\xa1}\x83\x12\x8cBT\xc2\xf6O\x96\xb7\x9f%L\xe7W\xed\xd6\x81\xe8\\\xab\xbbE\x86\x00Td\xc4\xac-\xf4\xba\xcd\x98\x02\xbc\x80#\x98M\xf7\x1c\x00NKa\x84\x91\xe9\x0d\x15P\xda0*:0\xaa\xac=\x9b\x19%\xfb[\xe4\xe5\x9bm\xcc\xce\x18\xeb\xb6\x04\x0e\x9d\xb9%U\x84ZV\x06\xda\xd7-\x92^\\QzQ\x07\xe0\x15e>\xdf\xcc\x08\x1f\xdc\x15\n\x02\xb3<\xab6\xeb\xf6\xb3\x8a\xcc6eR\xdf\x88g\x9f?\x83\xbf\x9a^\x9d\xa1\xb1\xdb\xd5Y\x08s\xb6\xf3V\xba\x0ca\xddB\x01\xb3A\xc6f\xa5\x909v\xa64\xed\xd0\xbf\xb97\xa0\x03\xc8\x80\x83m\xcd\x14\xf5N\xf5\x81{\x18\x98\x14\xe1\xbar\x03G\\Ab\x9f'X3pt\x8b\\\xa0\x8b\x10\x9d\x16(\xd1M\x1b\xa2;\x0f\x9e\xc2\x8eO\xa7\xe8_\xc0\x11\x9cG\x19\xf9T\xfbA\x10\xcd\xf3\x8c\x04O\xf9\xe4]\xc1%\n\xed\x8f\xb2z\x17,\x00\xa8\xdb\xbcD\x91#>\xa1(um'3\xdd\xc2n\x90N\xce\xc6\x8eZ\x94\xde.\xa3\x0c\xcf\xc9\xb6\xad\x01\x87\xc7\xa7\x91h\xa4+\xa7#QKW\x9e\x8fD7]\x19\x87\x82\xba\"\x17\xf92D\xa7\x95\x0eZ^\xd3\xe5\xa3\x98I\xa1\xe6_\xc2\x11<\xebb\xe6'\x8e\x99;\xf6\xab\x981\xe5\x8a\x87\"\xbf\xdc\x06uu\x85bb\x87\xd7v>\xc5mE\xde\x1be\x1e\x81\xb7\x19*p\xc4\\\n\xc4\xbcq\xfe\xd4q\x9d\xac\xb5\xb6\x150n\xfdJ\x0f\x1b\x8d\xf9K\xef\x89<\x89T\x85\x08G\x8e\xceMQ_E\xbb\xe0J\xd8\x87\xdf\xe9T\xb4\x85P\xd1\xf6\x82Z\x03\xf7\x17\xb6k(\xf8\xf0\x98\x07\xa4b\x11\xa1\\\x15rs\x08\x8d\x06\xab\xdf\xe9jL\xa7D\xb9w\xfc\xfb\xc7\xeb\xb3\x07\xcb\x84]\xfe\x0d\x80u\x9c\xe9\xc1\xe3'\x036\x16\xffo\x98\x1e\xdc\xcd\xd5s\x9a\xc7\xf3S\xa3\xc2\xb0\x94\x9c3\xd3R\xd0\xe6\x0d\xe9\xdb\xf5\xc9\xc6\xe4\xdb\xcb \x90(\xbf43\xf2\x9b2\xa5U6e\xca\\\xc5\x8c\x15\xab:\xae7\x15\xe6$\xc1\xbfl5Y\x8aPQ\x9b\xfe2\x7f\xb1\"\xf1\x9c\x94\xd5\x04\x12\x9fD\xfc\x87\x81B\xe8\x1b\x89\xe1\x08r\xf1\xe5\xd4\xe3y\x84\xee\xd3\x9d\xe7\x19\xf4\x10\x1b\xccC\xf9\xf93\x9c\xfb\xb1\xd9\x0f\xca\xdf\xa0kKM>\xb1\xf8\xe5\x17i~\xc1\x14X\x17\xe8'\x1e\x88\xcd\x1c\xd5+\x929(\xb9)\xc9\xceY{hH\x97G\xf3\xb8\x8e\xd9\xdf\x9b\xc0r\x00]\xf5\"\x01;(\xea\x84\xa63.\x8a4\x99\xa1\x02\xe9\xc1\xcf\x15\x8bO\xc1\\w\xfer\xfa\xf6MT\xc4eE|LA\xb4l\x8c>\xe3\x05\xf91\x8f\xe7C\x0c\xf4-\x1d\x85\x0e\x84\xa2\xe4\x98\x01\x01\x8e(\x85\xc8\xa3\xfc\xe2g0j\xf5\x9dX\x83\x9c\x8d\xf5\x84\xdbl\xeb\xb9\x01\xfd\xe9\xc3a\x91\xf7\xa9\x83\x9b\xe1B2\x9cT\xaaO\x19\xf6\x8c\x94a\xafM\x19\xf6\x18e\xd0\xe3\xaa\xce\xbf\x04\x94\xa5\x15\xe3SC\x8e\x10\xa1\xd6e\xf6@:\x1d\xaf\xf9r@ \xba9\xcd\xe8@\x85\xbf \x9a\xfaGI\xc5\x1d\xa1\xa6\xd9Y\x00\xc7\xac\xd2\x04\xa6\xf4\xff\xb3\x10\x7f\n\xb9\x8b\xe2\x93\xf0U\xd1@\x1d\xf1\xb7\x1b,s\xc0ld\xe0\xa4\xd0Gfy\x99\xf0#C\xc4\x89\x13\xcfd\x9c\xd1\xa3\xadl\xaeVm\xfb\x0dS\xe0\x17\x12\x15I\xf1\xa5\x06,\xcdM\xe3,Oy\xd6\x9a\x97\x98\xf0\xcc||\x90(N\xd3\xfc\xfad]\xd47\x18;\xd8|||\xd9\xcc\x8fE\xf2\x1dJ\x1f\xf5WX\xdd\x04@es\xfdb\xc8\xc8\x1f\xfb9\xcb\xdfp\xc1\xa2k\xa8 \xcd\xe5\xd7y\xff\xe3+\x91~'\x9b\xe5s\xf2\xd3\xfbW\x86\x80P\xa0p\x92\xa8\xcdM\xb8j\xe8\xa6\x99]\x1eX\x1dma\xd0\xfc\x16l\x81\x19\x95\xcf;\xf7\xe4:\xee0\x08\xcdW\xbe\xb9m\xa9rfd\xd4\xde\xbf8C\x97G\x18\xfe\x1d\x8e!\x8f\xd6q\xe1'A\xf4s\x9ed\xbe\x17zt\xf3z\xebMZ'\x0c}\xd4J0\xe9\xd4\xd7\x03`V]M\xc0\x0b\x0d\x06\x99\x15\xbe\xfd\x1f\x07{\x86\xf75{\xbf\xf7\xc4\xf0\x9en\xbfj\x02\xdeg\xaf\x0fP\xa4^\x94\xe9\xc0\x14\xd0\x9e\xe7\xb4M\xab\xe1{\xe0\xceU#\xda\x02\xce73U'7Dx\x85\xd1\xd64\x1b\xb8>\xa1\x9bvg\xa7\x8c\xaa\xcb\xa48\xa1\x88\x9ed\xcba\xab\x82\x9c\x87\xeb\xefo\x0bc\x88V\xe0l\x95\x1d\x83EQ9\xf6/\xa2)\xc6^ny\xe2\xbf\x9d6\x82v\xa3Q\x88\"6\xf84\xa1\xc7\xcf\xc6\x8f\x8d\xeeJ\xa2pc\x1fC\x1a\xd2\x10\xf2 \xd4\x05v\x0e)Oo$0\xeb\x86\x9dB\xa90Y\xa0\xe1\x91~\x14l\x85\xcc\x0e\x0eI6Of\x14\xa3u\xf1R\xbb9o`\x00\x8f\xd3\xdf\x8e\x95Aq\xc3*\xf9\x08\xee\xd4\xf3\xd0\x9d\\[=\xc7\xd6\xfe\xb1!\xa5!\x8203\xa9Y\xe4\xe5Z\x7f\xd0\x0c\x86fM\xfb\xfb9 \xc6X\xb3@\x83\x04\xb1\x9fL\xc9\x19;)\x07\x10|`3\x168\x15\x83\x8c\xc3d\x12\xf9\xf29\x7f\xf9\x01_\x9a\xed;P\xe8{\x80\xf4\xbb\x88\xcb\xfa\xe3\x03\n\xa9\xfbT\"y\x90D5\xa9j\xbf\xb0\x9a|\xf08j\xa6\xf8\x9d\x80J\x04.\x01d\xe4\x1a\xe6\xa1\x06\xa8=\xf6\xd4*\xd6\xb06\xa3\xb8(H6gAu\x92i}\x86\xf6\xbdC\x00\xd6om\xa6\xf4\x94\xe3\xac\xfc\xc40\x1d\x1ez\x98\xe1T\x7f\x07j\x91L\x1bq\x058\xf8V\x98)\xb2*\xd2\xa4\xf6\xbdco\x00\x01\xae\xa0g\x0b\xbc\n\xa1\x1b\x8aB-K\xba\x9b\xa6{\x03G ^ O\xf7\x07j\\\xa0=\x86\x19\x85nl\xf8q\x8e\xe9\x96\x04 db\xe6\xcd\x00\xb2t\x90#\xd7 \x87\xeb\xa6\xe3\x8bu>%f%6e\xab.ZCl\xa8\xf4\xf9PFmP\xa9u?\x0b\xa7(&\x8c3\"\xc4\xb5-\x9d\x8d(\xf2fSG\xb0C\x96\x0c\x08\xcfG\x12\xb0l\xbf{O!\x83\xef\x81<\x85lw7\x10bYC\xb8\x87\xac\x8d\x04gRG\x8b$\xadI9~1\xccZ\xfb[\xc1O\xde3\xb9@@\xd3LI\x8f\x84c\x0fv\xf1(\xf7\xfal\x1d \xa3p\x11BE\x99^}{L\xe1u\x04K\xd8\x85\xeb\xb0\xd9\xd4x\x928\xecj\xed\x94\xbe\xb2\xc1q\x08uT\xad\xf2M:\x7f\x91_gi\x1e\xcf\x9f\xa1Z\x8deg%\xe9\xc2p\xdd.\xed\xc3\xfc\xcc?\xe8eK\xa4Eh\xc5\xf7\x86\x94\xe2Z\xa3\xe6\xb9\xd0\xa7\xeb^\xae\x1a\x8b\xe7\xfe\xcb+\xf1Rc\x0f\xad\xba\x1a\x0b\x9b`\xf9\xec\xcf\xec\x8c\x136\xc1l\x07Ri\xf8m\xf9\xbf\xe9\xea K\xce5)\x97\xe4U\x86\xcf\xde\x96\xb4\x02\x1cA\x8ao\xb8\xc3\xb7C\xc0\x1bh\xd6Zz\xdf\xd8\x11\xdf,\x11\xb2]Y\x7fq3\xda\xfa\xb2E\xad\xfb\xad(B\xf2\xeeg\x90a \xbaK\xab\x9b\x03\xaa\x8c\xf5,2\x08\x82\xaa\x01\xbf_\xf2\xc8\xe85\xfe\x95\xf9\xa4\x97\xa8[6\xd1F}Z\xf9\xe0;\x8d\xc5\xfdZ\xa0\xb5\x169\x97\x02\xc5\xbe\xd5\xbd\xbd\x11\xdf\xf6Ru\x02?\xf5\xe4\xae\xd2\x83\xa3\xed(op\xda\xe8\x83a\x02\x9a\xf4\xee\xdd\x1d\xc0\x8f\"\xdbI \x88?=2\xaf\x14S+y\x94\xad\xe3\xf2RRj f\xae\nUL,!\x17Kn\xa0\x97\x01\xf6\x8d2\xc0~[\x06\xd8?\x1b\x08C(Ng9\xcc\xeb2.\x1c\x0f\x14\x16\x82\xfdi\x00\xd5u\xc2T\xc5QQ\x92+\xe4\x8d3\xf2\xc9\xca6\xce\xe2\x8a\xc0\xded\xb0\x0e\x08\xd3,\x93\x10[\xdb\x84X\x91\xc2\x1e5\x02\x14\x96u@O\x1c\x0c6\xbf\x92\x04\xac\xf9\xfb\xf3gL.\xa7\xdd6q\x10\xc2N\x1c\x95,\xa4\x04\xa6)\x9b\x91\xa2\xce\x07w\xb9Z\x18`\xe0\x08\xf6\x1d\x0d\xb1.J\x12_Zk\xda\xef\x87\xe5\xb5$\xef\xff\x11\x9d~\x7f\x1e\xda\xfb\x17\xb5\xe0\x9a=r[3\x12\xd5{\xcc\x1c\x9fdu\x08\xf4\xe7h8=\xf9u\xc1\xc4\x87\x1c;\x00\xe1\x89\x1d\x08,\xe3lmYjlm\xdfa\x1f(\xa7_<$|\xc6&\xe13\x1c\x96/y8+\xce\x81\x19\xbb\x90<\x9a\xb1\x1f~\xb8\x88\x08z\x92,\xec\x1f\x86\xca\x0ex\x14\x82\x8f\xf9\x1eJ\x8c\xed\x82\x071\x06y\xa1O\xcbt\xf8\"\x0b$\xe0\x1c\x90Q\xb2\xab*2\x8aa<\xa1{]=@|\x16\xaf\xd4\xadw\x07,\xa0[A\xed\x1a HU\xe4YE\xbe\x84\x82\x1c|\xf7\xebn\x8d.\x0598d$\xa47\x13\xa3\x0eP\x14\x84\xdc\xc1\xa1\x1b\xe4HT\xef\xb7\x89\xc8\xfexP=\xfauA\xc5\xc7l\xc9\x0f\xc3\xc0\xe0\x82\xbe\x8c\x8c\x18\x9c\xc3Da\xcd}goN\x82\xe5\xd0\x01\x83\x10$.\x1d;n\x04I\x0b\x0e\x9e\xe0b\x1e\xb0\xbb\xb4\xb8\x9e\xad\xfc\xfd\xc3\xc0\x10\xafFW\x9ai\x1c\xda\xa7\x01w\xb8\xba\xcc\xc4\x8b\x8e\xdd\x01.\x87\x0eh\xce\x1a\xf4s\xae\x94c\x19%J\xc5Z#\x08\xf8\x8f\xe7\xf9\x1c\xc3\xc5\xf2\x9fL]\xc5L@ \x97{Q\xde\xc6G\xf5A\xa8\xbb\x99S\x0b\x1b\xa5\x03\xda \x19\x8b\xf2\xcb\xd1\xeb\xf3\xd0\x02'Q\xeev}\xf0\x16\xd1\x0d\x9c\x89\x0e\x9c\x89\x04'}\x1cv\x93\xcfw\x0b\x82\xf1\xe1\x81\x1d\x8c\x92\x8c\xc6\x17\xe5\xa6\xa8}\x8f=\xf0\xc2^ \xefna]X\xf0 +y$\x9b{#\x86R\xd5y1`\"\xa9\x07\xf9-K\x93\x871S\xa7\xc6o\xa7\xf4\xcc?x\xa2\xd7\xf9i\x02\x18\xdc\xea\xd4D|\xa0v\x85t\x03\\\x16\x92\x10\x07'%![(\x8d\xdbnVB\xa125*{\x06%B>\x98\x07\xfe\xcfU\x9e}\xfe\xb4N?\xdf\xc4\xeb\xf43\xa6\x00\xfdx\xf1\x80\xf1\\_|\xb9\xd3\x8d\x10\xb2\xad9\xe1\xc3\xfd\xffxk\xc2\x81\xc1\xb4/1I\xa0\x06Q\xfe\x1eCi\xe2\xd5\x97\xf7\x00\x83\xa0\xe0M\xba]F\x16\xe6\x04\x99`\x02\xddkTS\xe3\xb3\x01\x13)#\xa3\x85\xbaR\xba9\xd8\xbc\x9b\x00\xcfti\xce\x95\xa5\x19GZ5S\x991+g\x9d9\xaa#i]\x0c3\x19\xeeW\xa4\xfc\x0b\x85\xf1\xd2\x8d\xcaiL\x85\x9d\xf1\x19i\x94ua6\xca2\x0db\xee0\x08Q\xb9e&\xeb\xd4\xfaJ\xdf:zAY\xf6\xb8\x88\x9b4x!\xe1\xc5\xf3\xb9\xb0\x8a\xff\xfc\x99\xb2#\xeb\xfc\x8a\xb4\x9f0\x06\xc5\x10\x99\xc6\xb8/;\xc6Z\xa6 ^\x0d\x82\x0f\xa7\xff\xf93\xd0\xb9\"$\xd7\x9b:\x16\x90D\xc9\xfb\xc6\xd1\xd4x=\xd8\xcf\x15o\xdfo\xe0AA\xd7\x07\x80|\x8a\xb7\x16\xbag/\x08)\x9a\xe7n8\xb4t\xc0\xa1\xaf\x8e\xc87Fcl\xb3\x87\x06\x1f\xe1\xa9\xbc\xd6Z\x92\x1aM\xaf\x7f\xb8y\x97'\x19\xa5\x08\xfd\x18\xb8\x00.n\x0f\x82\xbcw\xb2\x86\x86\xda\x88\xd1\xbf3\xff\xbas\xa3\x84\xbe\xecz1t\xeb\x7f\xce_\x1ej\x0d\x06\xae\x87\xec\x10N\xc4\xa7\xda\xdb\xdcO\xe26W\xf7\xf2T|\xaa\xb5~x>d\xc3p)>\xd5:\x0c>\x13o\x1f\xf7\x8d\x18\x9a+\xdc>4\xe3\xf9|2,'\x8b2(3\x81\x90\x9b\xe8>\x1d0\x1c\x1c\x92\x9b@\x91\x9d\xb4\x154\x08\xd6o\x89\x93\x85 $\xbaw\x94\x8a\xde\xe9|9a\xb6Ny\xfb !\xf5\xba\xab1S\xba\xe8\x1a'\x8a8\x899\x19\xca\x86\xa3\xe5\xdc\x06\xdd %\xad\xb7!L\x87\xb6\xa3\x89\x9a\x9b\x0e\x1ae=\xdb\x8a\x0b\xdd\x9a\xdaV\xf1\xaa!\xb6\xe6\x11f\xcc\xeb\xf85\xa9c\x1c\x1d\xa9\x00\x83}\xadI\x8d\xaa\xcd\xb5_3\xd5B\xc7\x8f\\\xd0\xfc\xcf\x9f[xEk^\xe9)\xd7U\xc8\x9b\x15\xe9l\xafl00\x9e\x85\xf5Y\x10\xde\xf1\xc8m\xc0\\v\x0e\xc7a<\xbb\xd0\x83`)A0\x1ee\x14\x06\xe0\xc2\xc8\x00h\x9f\x8a\xdd\xd7{\xa9a\xcf\x8a\xb8$Y\x8d\xa1\xba5<\xda\x10\x83\xd6\xf1\xf0\xac\xed\xf1\xaa\x95\x84\x9aG\x98B\x17\xf1\x95]\x9b0\xbf\x97\x92\xf9\xbd\x18aE\xfbE\x9f\x18\xd4\xc3\xa2s\xb0\xa5O\xf1\xba\xef\xfd\xa3\x01\xc6\"\x8d\xeb\x9ad\x13\xd0\x04}Yl\xd2\xf4\xe6\x8d\x08g\x84s\x1e\xe1;\xbe\xf0g~\xea\x93\xae\xf6\x1a\xf4\xe3\xc8:\xddh<1\x93\xea]\x99\xaf\x93\x8a\x8c\x18D\xc1\xb5\x86s\x9f`,\x14\xa7\xb1p\xcf\xae7\xe4\xda\x117\x86\xe3\xa3\xf0\xa1\xe0}m\xa5U\xb5\x01\xb8\xa8\xdb`\x08\xcf\xc1U\xc4j&\xf7\xaeL\xd6I\x9d8kA\xdcg\xb9\xf9\xcdg\x99T\x7f\xa9\xf2\x8c\xcb`+\xdd\xfb\xe7L\xde\xed\x89i\x16\x84\x92jn!/\x9b\xb4\xdc`\x1a\x18\xefQ\xe3\x1b\x9fT\xaf\xb9&b\x02W\xba\xd7\xcf\xe6s\\\xb0\xa6\xdaZW\xed\x7f\x92\x8c\x94q\x9d\x97#\xe6\xf5\\\x92d\xe5\xfb\x97\xcd\xd7ns\x13\x1fL@\x93P \xa9\x18\xdb=\x81B\xf7\xf2\x84\xe5\xaeu\x1eq+x\n~\xdc\x1fc\xeb \x95\xdf\x15C\x1f\xa9\x0c\xfd\x9dRap#t\xa3\x8e}A\xae\xb4'\xdb~\xba?\x94fm\xf8\xd3'{\x03\x86M\xb6O\xb7\xcebw\xb0\xf7\x9d\xf9\xd3\xff`s*q\xbfw\x07\xfeJz>\x8c\xe5o\xe8;\xae\xe8k\x97\xbcv\xcfF]_\x9d\x850\xb8N\xea\xd5\xf3\x92\xccIV'qZ\xc11xI6K7s\x82&`U\xbc&\xf7Y\x9cx\x8d+\xb6`\x03\xc4z\xdb\x14yd@hB\xe7\xbe\x81Pm\"p\x9d9\xbd&`G]XML\x01\xecX\xf5\x1e\xb0\x8cyTA\x8d\x177,\xfc=\x9b\xd1\xb6&\x9a\xd0g\xc6\xcf\x06\xd2\x1b\xcd\x9a\xe5\x99h\"\x88\x01\x8aw\xaea\xe0@\x95c/\xf2\xb9>x\xa7.\xcb\xc9\xef\xcc\xbf~\x85\xdb\xbdd\xe8\xb2,\x1e\xf0\xe9]\xc7\x97,\xb7\xf2_N\xdf\xbe\x11N\xbd\xb3\x94\xc4\xe5\xf3x\xb6\"6\xbb\xd6**\xd2\xcd2\xc9\xaa\xa8$\x8bJ\xf9\xb0cB|\xeb\x9aQ\x1eT\xc2R\x9b\x17J\x10\x97z\x95\x18\x92\x99\x9c\xa0X\xd8\x19\xe0<\x9f\xe1\xf0X\x14]\x12\x84\xdd\x19,TX\xf8\xd7C\xeae\xddf2\x84;\x01\xd3f\xba0\xe0\x97~JB\x8c\x9a\xb6\x07m\xd0i\n\xeb \x01N\xd5\xb0cI\x81\x931MM\xd3X\x13\xf2>\x08\xf5\xdf\xad\xf5\xdf1\x9cN\x08~\xc7\x8f.$\xec\x85\xb6~\x9c\xa6o\x17A\xd8\x8d\xf9n\x06\xb55k\x9b\xbc\x11\x1a\xa6<\x17qE^\xe4\xb3 \x9clCi\xf8\xf0\x07IfW[\xa1\xe5\xbdE\xa1\x82\xfe\x8b\xa4\x9aQ1$c\xec\xaa\x86\xebmj\xf3\xd5y\x1d\xcf\xca\\\xcb?\x8b\xb2\xce\xe7$\x15\x94\x86W\xefGE\x01\x854\x9e\xbb\xe4E\x86\x8eos\xdc\xac]b\xf4mv\xd5\x1b&\xdb\xb8\x1d\x8b\xf2\xa5\xee\xc7\xa2\xb8\xba!\x8b\"\xcf\x8a\x9e\x07\x87\xc9\x16\xb4[\x98\xeb\xa0[\x8fc\x1c:D\x91#\xb48v\x882\xac\xf2\xe6\x8e\x1e\xe6f\xb4>\x1b\xa283D\x9d\x0f\x9c}8D1(\xd2\xfd\x00&0\xeb%\x13\xb3\x9d\xe6\xa0\x90^\xc2N\x083\x8b9\x94pl1\x1cd\x8bE\x92\xa2{W\xff~\xde\xc4\x8fT(\x8c\xbe\xee\xaa\x1d\xb0\x0b3\x17\x19R\xdc\xb1]\xd2\xa3E\xfa\xcak9\xc66}\xd1\xd7^\xf2\xa6U\xc2\xa5\xaf\x89\xf1\xe3\x9dy\xf9\x0b^\xdb\x91\x97?g\xebr\x99\x14B\x97\x87<\xa7\xbe\xf25\x8b\xe7U\xd7\x1a\x19\x1d\xb8\xc1\x13\x89\xf8Ibd\xfai\xad\x13tc\x0e\xb1E\xbc\xd5\xbe\xa6\xffl\x04\x9d\x0b1fN\xed\x97\x18\x91\xd1\xcck\x8c\xe03\x1cy\x8c\xdb\xc0?\xe1t\xbf\x9b\xfa\xbd\xcfZn8\xf7\xa8\xb5\xb4\xe2\xd2\xfc\xbe\xe6\x15K\xbbY\x19Rnf\xfe\xd6\xba\x83\x83\xbd\xad\x93\xbb?\xd9Z\xfe\xdfZ\xfa\x1f\x18\xabU\xf6W\xdf\xdc\xb9\x10a\xe2\xc8\x0d\xfaOy\xa2\x9b\xd9\x03TAE\xb3\xb8\xa87%9\xad\xe3\xd9\xe5\x872\x9e\x1186\xbd\xe1\x04\x9d\xfe\x1b\xcd\xf2\xac\xaa\xcb\xcd\x0c\xdd\xdf'\xecYEkR^C\xfan\x06\xec\x99\xe5\xaaA\x1fx+k\x05\xde*Y\xe0\xad\x92\x05\xde*ww\x03\xc8\xa6e;\xf0Vi\xe0\xacqpkRU\xf1\x92`\xae\xc6\xbd\xb3\x90\x99\xd0\xd4\xad\x93J\xa7l7\x11\x8c\xac\xb9\x8bW\x9dUC\xf5\x05\xcf\xedC\x8f`\xf5\xa9\x02:\xfai\xd8q\xa8\x1a\xad\xf5\xfb\xed\xf12\xa9^\x96\x84\xa47o\xe25\xb1\xe7w\x90\x86\xe4S\xd2\xf2\xc7\xd1\xae\x1d;\xc4\xa5\x0b\x9d\x91\x80\x97Q\x92\xcd\xc9\xa7\xb7\x0b\xca\xa5\xfc \xee\xefS\xda\x9d\xcb\x87Y\xf30q\x0d=)WZ4BX#}$\xb1\x12e\xf4i\xf2\x1a\xb9K\x17M?\xc7:\xb80 \x1dX\xe5\x85\xa0f5\x0b\xc1\x13\xe7\x05\xfe\x10\xf9\xf8^\xb4\xbf\x98\x89\x90\xb4\xd5\x83j\xb6\"\xeb\xb8\xfb\xb4\xd5\x88\xf2\xbc\xdd\x95\xda\x0c\xef\xe8\x946\xa7\x1f{\x82cg\xfd= \x9f\xe2u\x91\x12\xefl\x0c\xc6v\xc8\xf7\xc3/ \xc3\xadW\xff\x96*X$G\xc6\xedp\x07\n\xda\xfe6B\xf3\x86~03\n\x87\x8cG\xf9\xc3`\xef\x8c\x9c\xed \xc5T\xef3r%\x91>\xb9F\xab\x8f~'\x1d!TP\xdd~E\xb1g\x90r\x97\xa4\xca\xd3+\xe2w\xb5\x82\x96}[G\xf3\xa4\x8a/R\xc6]-\xe2\x19\xc1\x00Q\xdd1\x84\x18]\xfb\x92<+\x92\xeaC\xbc\x94\xd9C\xfd:\xd0G)\x1e\xa2A\xb34!\x99\\\xc1Nt\xb7\xdfL\xcbxh\xd62\xfah\xed\xffm\x80\x91\xe4\x1e\x05\xba\x8a\x82\xa1\xd4\xa7\xf3\xa9\xc4[\xad\xb7A\x8a\xbb\xf9;\x03SY\xfa\xa9!\x8cb\xe6\xef?2\x06Q\\\x0cEP\xd4\x86\xb0[17\xf9'\x86\x00\x8a\x99\xff\xad\x8e#^s\xbe\xb7\x0d\xd8\x1ce\x0d48\x94\x82A\xae\x06CL\xe5\x8f\xe8\"\xc9\xe6~\xb6I\xd3\x90\x7f\x16\xf0X\x1f\x14\x9f1m\xad\xd2\x04\x7f|\xba\xb9\xa8KB\xdf\xce\xd5\xb7\xe4\x13\x99mj\xb4\xd0\x11\x7f\xd3\xc7\x9d\x18\x8fi\xebA\xabB\x13\xf01\xed=\xa4\x15\xdbJd\xe5g\xc82\x85\xb0\xb3\xe1\x87M\x92\xf2f\xae\xa2w\xcf\xde?{}\xf2\xe1\xe4\xfd\xf9\x0f?\xbd\xfa\xf1\xc5\xc9\xfbS\xd3f\x82#Xi_\xd0\x0f.h\x9b\xef\x99\xd4\x84\xed\xaa\x0f\x10r$-X\x9f\xfd\xdd\x90\x17\xaf\xe6\x13Xc\xe2\xfb\xf6\x86\xc0q+-\xc8\xac\xd1\xe2\xf1\xffY\xd8\x17\xfe\x00\x9d\xfc\x98 \xc5\xfe4\x99\x8e\xdao [\x14\xa5\xbd\xcbm\x17o*n\x0d \x84`\x1d(.\xe8y4\x96fe/l\xf4R\xc8\xc3xt\xef{\x83\xbe\xbb\x94\x08WRi\xcf\x02\x88\xd7\x06\xed/\x89Vy\x85\xbe\xba>\xff\xf3\x082\xfc#@ 3I\x80\xbf\x17\xbf\x8e`\xca\xc5\xdcY\x9e\xca\xe8(\xde\x84\x8a\x13^p\x86_^\xc4\x15y\x17\xd7+\xfe\xa9\xfcy\x04T\xba\xb3/\x80\xaa\x03\xc9\xc7\n\xca\x16e\xd3\xde\x80\xd01\xfc\xe9\xfe\x17\x98\xb8l\xadW{\xb2\xf7h\xdbO\x0f\x1fn\xad\x1f{\xb27` \xf4\xef%\x9a\xa9\xbf\xee\x9c\x1bG\x9bdv\x01\x89\xb8I \xd5\xeb\xb8\x18\x08.\x9e\xc3@\x84\xf0d\xc8\x1dX\x1a\x0chu\xbe\x9b![\x83j\xc8W8\x15\xedj\x87$\x82\xa1\x1fj\x9d\x85\x17C\x9e\xc42C\xa86h\xb4\xe0\xe5\x0f\xf6\x86\xdc\x81\x87Y2E\x14\xbd\xf6I@E\xc1\x02\x8d\xb6\xad\xaa\x1a\x11n\xfdP+5\x89x\xeb\xda\x81\x8b8\xda\x87\xda\xb7\"\x8e\xf6Cm\xc3\"\x8e\xf6C\xed2 o\xf0\x87Z\xafm\xe1\x0e\xfeP\xeb\x98\xed\x94\x08A\xb9\x00\x1e<\x80;\xf9\xb5\x98\x98K\x82^.\x12\xf6b\x98\xcdd,\x92g\xf1'\x99\x93\x8b\xcd\xf2GrE(\xe7\x98d\x8b\xdcR_\xde\xfaO-\xael\xac\xe2\x9f\x93\xaa\xce\xcb\x1b\xb3\xd5\x9a(\x8cy\xb07+|s\x1d\xaa\x16\xcc:|.Y:\xdb\x07U\x1dSi\xc46\xd4\xc2\xb5\xbd\xc6\x0c\xc3\xd2\"\xaf\xf8\xa1$d\x82\x9b\xea\xdc,4\xa9\xa5Z\xe5\xd7/\xe8\x02\x9a31\x89\x12\xa7\xa93\x1c\xd8\xd2Q2M\xa5 FY-h\x91&\x17\xafI\xbd\xca\xe7\xd5\xa4\x8b\xab\x9dd0\x14u\x035\x10\xbcu\xdc\x1d\xc6\\\x93RJ\x14\xca\xc1\x04\xfc\x06eI$\xb7w\xbe$5S\x16\xf0\xceE\x05n\xf3\xad\xd6\xe3\x8f\xfa\xd5Wq\xf5~\x93\xc9\xaa\xecg\xbf\xdau\x19\x17\x05\x99\xbfk\xce&\xfaT\x98\xfa\xac\xe3\xc2\x97\xd5X\x1d\xa5\x89@\x84\xe4\x91\xc0\x89\x1a\x13j\xd1\x01\xc7>fD\xd4T\x8c\xe7s\x7fz\x166\x1cp`\xf9\x80\xe3\\\xf3\x11\x7f \xbf\xdb\x14\xf3\xb8&\x1c\xec\xbe\xda\x94\xde\xd2`\xd0\x11\x87\"\xc1\xbcA\x02\x12\xc2\xd4L\xbd.\xc9\xcd\x04<\xa4L\x03h\xc7Y\x03\xbb\xee@\x14\xe4\xef\xe94\x1a\x9a\xc7\x8c\xf5m\x1f\x82z\x9bV\x87Z-1\xbbBc\x17j\x19\xaa\x8c\x8f!\x83\xfb\xb0\x0f\x13\xd8\x0bBd?\xf6\x9fB\x0e\xdfC\xf6\x14\xf2\xdd\xdd\x00\xcai\x8e73\xadK\xb6\xdc\xc1%\x17\xdd\xbfy\x94\x95 J\xf3e\x13\x86Jc\xbd\xa1\x16\xb39\x8b\xc1Fd\xe8\x90a\xcbtE\xca\x8b\xbc\x1a\x8a\x04\xb1\xd5B\xc9v\x99\xf3_{\xd9l\x0d\xc0\xbf\xcf\x82M\xbd)\x06\xce\x84]\xf0\xce(C\x7ff\x8b\xca&\xcaWX\xcb\x86*\x8dYNKx\x05P\x04dAE\\lk\xd4\x827\xb9\x83*\x13Qr\x83\x08\xd0-B\xfa\x99*\xf4\x99\x9ex\x98F\xb8d\xd70h\xf4\xde\xab\x10\xc0\x04t\x04\xda\xc7\xb0m9\xbf\xc9Qk0\xe9G\xc4\xab\xca\xad\xdcu\xb7\\m\x93P[\x14>\xd1\x9d^\x889\xcc\xc5G\xaeHy3\xce\xb1Y-R\x86<\xe2I\x98\x9d\xbe4$\x1bkU\xb1o*\xde\xb7T\xd4tL-K?\x0f\xc1\x988\xb1[0\x16D\x08\xb3\x10\x16!\x14\xe8\x14\xbf\na\x8d\xee\xab7\xf6\xb1\x80n\x85p\x1a\xc2\xf3\x10.Cx\x16\xc2\xdb\x10\xde\xb9A\xbe[,+\x11o;~\xd0\xadL,V&\xdeje\xbae\xdb\x95\xea\x16\xcch\xdd\xa7A\xf9\xa8\x00\x16C%\x96\xf9r\xb6[\xa4nq\x0fk1T\xec!*l\x85\xa5b\xb8$7x\xd3\xbf\x98.T#\x9a;\x07\xde\xc3\xff,\xe0\xf1\x9d\xd7L\x0f\xe3D\xe3\xd9\xe9\xa3>\xf9\x92\xdc \x0d1%.u-,\xe2\xff\x97o\x93f\xa4\x8f\xbfl@\xe0\x96\x11\xc4V\\\x93H\xd9\n\x9a\x89)\x98\x1b\xa2\xe2m1\x9d\x9f\x85\xa8G[H\xab+\xd5l*\x08Q\x8d\xa6>\xc2\x93\x1dC\xa9\xcc\xf1\xcfu\x88\x87B\xa2\x0dD1\x9b\xe6\xd17\xdf\x94dq\xc6\xb2\x95\xee\xec\x85\xa8=\xdb\xd9gf\xbf\"\xed\x91\xa4\x99\xfb\x0fC\xb4\x0d\xee\xb8\xbe\xd0\x9fU\xf3\xd3\x98 \xd3\xb58\xa7C\xb2\x15J\x1c0\xce\xc5'8\x82\x13\xc4\x1d?\x08\xa2y\x9e91r.Eb\xe4\xe1\x7f\x18m\xc0\xe8&p\x04\x9fD\x10\xf9\xe7p\x04\xf9\xf4\xf4,\xc4\xf8\x95\x0b!\xf7\x9c\x06!\x86\xac\xd4\x9c^\xcf\x83\x10\xdeb\x96\x17\xc4\xb2\x10\x06\xd3\xfa\x8e)\xf1\xd8\x84H\xb6\xf2\xaf\x04\xf5\x9dg\xff\x0d&K\x91^W:\xb2\xf6\x16\xe5\xb6\xd9\xf4\xed\x19\xd2\xb4\x80Y\xb8\xa5d\x19\xd7\xe4\xff$$\x9d\xfb\xa5\xcf\xd8\xd6\"\x08\xc1\xab\xf7\xbc\x10\x0e\x1e\xdd\x05\xcdr\xc9\x81e+\x18x\x9aJ{\xa7,d\x0c=\x83\xef\x1c\x1f\x0e-)\xb8\\\xcb\xbf\n>P\xa0\xbd\xc3\xcc\x06\x19\x8b\xd0\x96a$\xbbw\xff\x0d8K\xe9r\x80\x87\xfb\n\x0b\xf8\x1c%\xbcK\xcc\xddZ\xdc\xc5\xfe8tt\x15\x1c*\x82Q\x89\x9b\xf4\x8b_62\xb8CV\xf0\xf0Ny\\\xc7\xcc\xaaC\xe5\xce&v\x07\x94M\xb2\x91\x87\x98\xb3\x153\x0b\xc6\"c\xde\xc3\x80\xf3\x9e{\x8c\xf7\x8c\xadi\x02m\x85\xc9\x1cw \x9b\xcbq?Ty\xe1\x87\xfb!\xec\\P2s\x12\xf1]\xa4\xfc\xddM\xc05\xb68\xa5Hs)\x9426c>\x0ca\xe7\xfc\xce\x89\xe2\xc3;\xd8\x81\xf0/D\x14Y\xde\xbd\xeb/\x9b\x14[\xc1;\xd86\x92D/\x92,\xa9V\xfe\xc3\xc3;\xc1-\x87D\x89\xb6\xd2\x1b\xd9\xde\x9d\x8c\xec\xf1\x97\x8dl\x1b?sS\x913t\xf4?7\x95\xedp\xf26\x84\xd8\x9e\x98\xd0V\xa6Tj\xa7$\x97\x92\xaf\x87\x8f\x1dB\x1a\x9b\xca\x94\xd2\xbc\x10\xa9\xc8\xc3\xef\xdc\xee\x0e\xba\xc5\x10\x15r\xa8\xdc\xb2\xc4\xf1\x9d\x8b\x83\x9b D\x9b+\x0c\xc9\xcb\xcf\x8d\x82\xeb.\xe6\x8a\xeeBj\xe2\x1f\x852f\xac\xa2\xba\xc8uw\xf8\xdd8mc\xf5\x19\x88\x81[`1\xa5\xd5\x18\x84x\x8d\x1e\x02w\xa1\xae(%\x97\xb4\xa5zb;\x9a<\x1e\xdf\xf9N[\xc2\x11\xac\x85\xc6\xa1\xec\x88m7\xfeR\xbcZ\xf28\xa3K)\xc1\xed\xefo\xb3J\xfb[p\xa4\x02\xdd$l\xb7\xd0En\xc1\x97\xb1\xf1n\xc1`\xcaq\x1el\xc1Pn=\xd0-N>\xb9W\xf7\x1fQ\xe8\xb2\xd4\xd3\x9cA|\x14\xf0\xfd\xbd\xc7\xf6w9\x9a?d\x12\xfa\x16\xfc\xa0\x1c\xd6\x81JO\x0e(\xff\xb7\xa0<\xdfJ\xe1\xffV[\xf2\x7f\xce\x99\xc4\xbb\x85%3\x16c\xa2\xfc\xdd\xd6\xf7}\xe5\x97j\x8b~-Z\xc1\xf8\xb3\xf9\xb8An\xad\xa0\x91\xee\x8c\x9c\xcb9\x18\xcb\x7f9\xe73\xef\x96^\xcfc\xf9+\xd6\xf3\xc8\x93\xe8K\xf8'9\xe2\x91\xfc\x92\x1b\x0e\xdc\x86P\x8e\xe7\x87\xa6\x8fB$(t\xf7\x1e\x8ca\x7f\xa6\x07\xc8\xee\xd0Mu\xe0\xc8\xee8\xb07\x16k\x8a[\x9f\x04}\x03\xe2\x9c\x99\x1d\x96\x81\xcd\x8a\x18\xa4=\xe8\x9bxM&\xc0\xa3.|\xfe<\x14~Q\x94V\xe8Y\x95!\x92\x8f\xfd\xdc2\xfa\xd1Q\x8d\xecVN\x94(\x8d\xb6r\xb2\xd1@\xbbw\x9b(\x8aE\xe4\xaam\x16\xdb1\x1eU\xbc?\x9c\xcc\n\xa4\xf7\xd6\x92\xd4\x82\xd3\xac^\xe6%k\xce\xaf\xd5\x8c\xae\xbf\x0d\xd0U\x83\xec;\x84\xbd4\xec\xecX|\xb72\xd8J\xc9K`\xa1\x0c\xb9\xd2\xfb\xcc-u\xa7Z$\xe8q\xe8\x16\xe0~\x05\xe8. \xc7hno?\x02\xb8\xd6\xf9\xa9Q\x13\"\xd9\x11\xa5\x06>\xb1\x1c\x1f\xaa\xd7n\xcb\x1f`Z\xf3\xfc3_\x11\x14\xef7\xd9\xf3|\x93\x0de\xb0\x1a\x0d\x0buB]\x98\xfbDl\xb0\xaf8)\xde\xd7\x87d\xc8 \x7f\xf4\xb4\xf4K\xdc\xcc\xcbm\x951\xe2\xcf\xb4V\xedeX\xf2\xaa\xaf\x08\x0fA\xe7^es\xf2\xe9W\x03\xc9\x87\xa4\xc0\xe4\xcbj\xe7N0\xf2\xb2\xcd\xfa\x82\x94\x1e\xec4\xbe\xd9p\x0c\xf7\xf7\xc1\x94&\x0d\xee\x04Lt\xb7\xde%t$\xbdkX\x83\xbb\x1f=w@\xd8\x96\xae9\xd8\xc8\xb6\xcc\x92\xc7\x916_C\xd4\xb2\xb3\xb6\xbf\x87\xf2\x9c\xa7TG\x1f\x8c\xa1x\x91_\x08+v\x80}E(\x0d\x03\xa5a\xf1\xda\xe9;\xe8f\xe1y&F\x1e\xach\x8d\xd7\x0b\xec\x1f@\xc6\xbd\xcd\x19Dm\x8bE\x0bf\xd8\x19NY\xa1\x16\xb4\x9b\xd0\x1aqKV\x025\x82\x19sK\xf0\xbb+\x00\xde\xff\xcck\x88!\xcb\xb3\xfb,\x0f0\xf3\x1b\xf3Bp\x19-\xf0!d\x91\xf4\xf1b\xb1\x83\x1b?.1\xf5\xb0\xc5Ys\x1e\xcb'2=\x91\xf0\xd5\xec\xb19\xcd\xf7l\"\xad\xf7\x1fV$s\x82+h\x8cM\xd5\\\x1a\x1a\x88U\xd2\xcd\xca'\\\xed&\x86\xbb]\x7f\xe2\x14\xd0\xf4\xc5\x96E\xb2\xc3\xba\xcc\x15\xdd\xe2\x96\x93D-\xfd\x8c\xc7]\xfc\xb463,\xb0~\x0d\x8e\xbc\x03\x991D\xc3\x06\x97v\xe6\xebvL\x16\xb1\xd2hO\xd1qJP^!\x19\xd5\x19\xe3\x88Z\\\xf5\xae\xc8\xb4\xbf\xdc6xdA$q\xba+\xfesM\xe2)\xe6BW\xc75\xc1\xf0\xbev\x14p\x0c\x1ebY\xe1\xe1\x11\xb3\xc0\x14\xd8\xaet\x81mvp3dJ\xa7\xbf\x02\xb2\xb0\\\xc6\xdb\npV\x84iq[]:\xd5\xc4\x07\xb4\x81\xe8{\xd8\x13!n8U\xfeP&d\x0eu\xce\xf3;C\xdc\xf6\n\x86z\x15\xd7\x90T\xd9\x1fj\xa8W\xa4$;\x9e\x0c\xb7\xd9\x1dFU\xa4 \x95\x18C\xd8\xff\n\x00\xee\x11\xdf\xaf\x05^'>\xb5\xd9c\xfc\xafN\x14\x19''!\x11eN\xb7M]\xb6\x154S\xcd\xac\x95m\xfb\x070\xbe\x81\x06\x8d\xd9\xfe\xe9x\xbb\xda\xdc(\x03~\x890\x0e \xee\xfdkB\xa5\xaa\xe5k\x1c\x07\xaa\xd2h\x0c\xee90\x90\x8d\x97\x18\xa0\xe6p/\xd4\x0bBH\xe1\x04\x15h\xa8\x1c\x93'\x05\x95k\x9eW\xb8\x1f-\x01\xd8\xbf\x00\x1c\xcf7eI\xb2\xad\xa0\xe2\x08\x11!w\xe8\xb4u\xfc\x15\x1f\x04\x7f\xfa\x95tG\xfd\xfeG\xccu\x14\xf5\x89\xf4\x92\xbb\x95\xb6\x9b\x00\xe6\xd7\xb0\xfbU\xe8q\x17\xf4#\x00b\x83\x87:\x97\x99\xda\xc7W\x99\x05')o\x17\x1fn\x8aQ:\x80\x11\x1b[\xd8<|\xa5\x8d\xf8cr1b\xe0\x8e\x83F\xf07a+\xee~\xe0\xe7K\xf25t\x8f\x0d\xcb\x8a\xc9\xf1\xdb\xdc\xeaW\x80\xbf\x12\x14\xe3+\xcc\x86m\x82&\xfc \x9d\xd4\x90\xb8\xb4\xf54\xaa\xadf\xe1\xbe\x07z\x13\xa9\xe8D\xbe\xce\xd9\xc4\x83\x8f\x8c\x99\xc8\x98Y\xf44\xe8\xc6\xc3\x08\xfe\x04>;\xd1\xbf\xc6,gi\x9e\x8d\xa2X\x8e\x93\xfc\xcb\xe9\xdb7<@\x1feMsE6\xfd\x1a\xe7\xab\x88\x8d5b&\xb6\x89H\x97lb\x9f4-\x84 \xce-\x81W\x93\xcc\x97k.\xda\xac( a\xfbH\x14\xd09\xfe\xedW\xc6\x99sM\x19\xc0\xba\xb9\xcf\xb5\x19\xc9\xa0R\xcf\xc9\x11_D\x8ck:h\xf1\xec\x0e\xc2\x06\xed+\x97\xda\xa8\xdc1\xb8v\xb7\x88}i\x8a\xb0\xa6+}\xe9\xe4\xeb\xf6f\x87\x85\x88\x96\xed6\n5\xb6+\x9ekN_\x89\x00b\xf8\x1d\xfba\xfd\xce=\xca\x04\x1b\x8d\xaa\x8a\xf5\x13\x11\x0eI\xa0I\xa3\x9a\x0dB\xf5\x9e\x99\x07\xb3M\xbed\x131]0\xbbV@\x9a\x8c\x11C\xd5\xdfx\xd3\x16\xb6\x1f\xb2\x0c\x1e~\xef\x19Rl\xca8k\xea\xff \xf6\xf7\xb4\xd7\xe5\xd6\x98\xbc\xa2\xb0\xf5\xcb\\\x17O,\x9cT\x99r?P\x99\xf4\xc3\xf7\xfeF\xfepE\xa0$\xf1lE\xe6\x10\xc3*.\xe7\x90&\xeb\xa4\x86|A\xc7\xcbMT\xa0\xdcd\x95g\xa3V\x0eD\xa2DW\xb9>\x87.5\x93zK\x03\x97}&\x92\x08i\x9b\x19oy\x00\xe3\xac\x0f\xc0\x01\x00\x00\xd0_\xfe8M\xfd\xcd\x97\x8e\x0fi\xa0\x88\x97\x13\x82\x0cmfm\xe56p\xcdN\xd0-\xdb\x91\xb4/\xd8\xa9\xbc\xc3Q\x03\xcd:Xv\x04\xa5}\x89\xc4\xb9\x9aE\x1a]\x85o \xab'J\x8e\x0dtu-p\x1f\x1cla\xc7]\xa6\x95\xaa\xd9\x97\x0bPD\x11\x87\xc7P&_]\x89\x99\xf1\xfe\xa8o6\x8e\xd1\xa3\xd4\xe2\x0e\x06Qdh\xb2\x8a\x99 w\\\x08J\xbf\x0e\xd9\xaa\xfe\x98\\\xf8A\x10<\x85\x1d\x9fB\xc0\xaf0\xa9A\xcb\x8c\xff)\x87M\x00\xc4\xaf\xf8\xe5\x87\xf3`\xc6\xdft\x89\x12s\xcbi\n0;\xc5\x11\xe5\x16\x16I\x16\xa7\xe9X\x80\x8d\x071-; %\xd7\x85bL]Hc\xeaQ\x8dm;l\x10\xeer\x01\xb70\xde\x8c\xfa\xdc\xcd\x86\x15\x9ck\xde\xb2;p\xd2G0\xeb\xe7\x12Q\xac\xe2\xb0(\xed+Q\x8ck\xeeO-\x91A\x9d\x8cQEa'\xfe\x04\xfaY\xfeu\xe56p\xb1\xa4\x1d\xb9\xceRTj\x99K\x95cf\xd12!2%\xec\xee\x16\x97\xf8i\xd6\x1a\xd2,\xc0\xf1`\xbc\x1dxo\x90\x8d1&}\xef\xd5\xad\xeel:1J\x07%YT\x13X\x0b4\xd1\xd3sL\xa1<\x81\xe5p\xad&\x05\xd7\x04n,Ue\x04\x9c \\\x88\xaa\xfd\xa9\xb4O 5\x0c\xf9u;By\x93ay\\<\xf8\xc3\x87\x03\xf1\xe0\x87?=x\xfc\xdd\xb6\x9f>\xde:\xa5\xe4\xc1\xf6\x91\xef\xf7\xf7\xb6\xfdt\xff\xbb\xed\x13\x04\xec\x7fIF\xca\xd6+\xa9\x94\xf9\x8d\xe2\xed\xeb\x07\x93\x1b\x95\x98,2LT\x93\x8aY5\xe9\x07\x80\xb5jq\x80Q\x99\xecm\xebV\x9d\xe5Z\x8a\xa1$i\\'W\x04~z\xffc\x08\xd7I\xbd\xca75\xac\xe2\xab$[B\x0c\"\x13E\x84Y\xbe'\xf0\x07\x19\xf4\xf4\x0f\xf2\x1d\x7fZ\xe3S].Bh\xa0\xf8\xa9'\x97\xd6Z\xf5w\x9f2\x89ep\x82^b\x84\x9e \x9f\x0c \xcf\xf3M:\x87,\xaf%DJ\xb2 %\xc9f\x04.\xc8,\xa6X\x93/&\x80\xb3\x16\xb92\x11\xc3:c6\x0d$\x1e\xc4)\x1f!\xe9\x05h\xa3P\xfb\xde\xef=\xb7V7\xc6\xe9 \x9b\xbfwS\xa2\x89o\x8b\xda\x084\xe09\xd5\x98\x9eeA0\xc0\xb1 \xab\x80\x14\x99\x90\xe1U\xa6\x0c\xc2E\xc3 ,{\x8b>\xec\xbfr~\xce\x15\xabz\x1eA\x97\x91\xc6\xca\x10\xf3\x91\xa9C\xe1v\x81\xee\xb8W\xf9\xa4+\xce\xda\xfaKM\xf8\xed\xb6\xd0\x95\xbe\x03!B\xeaWY\x88\xcep\x0c\xbae\xae\x038\x86\x1a&\xd0_\x96:\x80 \xf8\xb4U8\x82W,G\xf8_N\xdf\xbe\xe9\xcf\xdb\xc8O\xf2\xcey\x1b\xb5>U`\x88\xef\xdd@\x90Zq}\xa6\xbd\x85f\x9a7.\x17\x7f\x0f\xfbR5V\xf7\xeb\n\xdc>\xed\xde\xd1\xe91\x1d\xcd\x18\x9b\xac\xe4e\x87\xca\xf6\x89J\x91'YMJNG\xe8\x9e\x87yN*\xacC>%U\x0dI\x06\xf3|\x86\xa1\xa9\xb5\xf9Th\x91\xadh\xce\x14\xcd(\xf9t\xbb\xc9\x16\xf5P\x9e\xe9\x11\xad\x95\xfe\xb21\xf9 \xea\x8c?\xdc\x14\x84\xeb\xfbN>\x15dV\xa3\xaa\x8f}\x14\xc2\x12\xadi\xe9\xbcU\x90\xd1\xc3\xd3\xdbd,\xaf\xcc\xdc\x03\x96|\xe0\xaau\xa3c\x9e\x92\xf7\x80Y(\x92\xe9\xde\x99\xbc!!Q\xb5\xb9\xa8\xea\x12s\xc1\x80\xe7\xc9~\xa6g0\xc1\x0cXHb\x1fx\x01\xd3\x86\xb9a\xdfb\x90~\xeb@\xc3\xd9\x82\x13\x89J\x9b\x8cT\xb3\xb8 >\x91\xc9\x9f\x1e\xfc\xd7\xfe\x83e\x88\xb9\x9d\x94g{\xf8\xec\xbf\xbazP\xd3\xd0\x8a\xc1\xa15\xfdkzg\x1d\xed\xa9\xbd\x7f|\xc0\x1e\xee\xbbv?\x1fdP~\xf6\xeb\xc6\xa4wG\xa3\x95\x11\x9b\x97D\xb3U\\>\xab\xfdZ\xda\x0b\xe9\xe9\n\xcb^\x86\xa6C\xf7u\x1e\xfe\xbc/\x8e_j\xdac\x8a!;\x98\xb9^ \x0e\xfb\xf1{\xfe\x03k\xd0_;t3;M~%\xf8\xcc\x10\xb4:1q\x0d\xf5\x01\xef\xc5K\xcdpsL\xf5\x95\xf3\xc0\x15\x1f\xf0\xda\xb9\x0cA\x1b2Sh\xd2\xec\xa7\x0e\xf4\x01\xc1)\xe01\xdd\x12\x13\x84\x00\xb22q\xe1\x17A\x93@Z\xdb\xda\xad\x9f\x19V#\x86#\xf0\xf1\xee\xc2\xfb\xbe*\xc8l\x1d\x17\xf7);\xf8'/\xa0\xd4\xed\xf7\xd8\x89\x9ep\xd6p\x84\xce\xfc\x1d\xdb\x81\xe9Y\x80i\xcf^\xe43\x0cZ\xea'\x98\xca\xd0\x86B\x1b8\x02\xcf3Q\xffq\x19\xadi[\x1b:|\x84Q\x81\xb7\xaa\xf9t\x83$\x86\xfe\xef\xda\x9c\xd2$n\x92\x18c\xb6\xcf\xfd\xd8h\xe8\xa1\xe3h\x86\xe7\x9eO\x13\xbc\"\xc2\xff\xb9\x93\n\xbf\x7f\x89\xbb\xfbW\xfdu\xe7 \xbd\xdaC\xa3Kr5\x94\x93k=\x94Xk9\x98\xb0K\xa6\x82\xd2~{1\x94X\xeb\x9c%\xba\xd5e\xb3\xbd\x16}jSH\x9d\x88>\xb5\xcd~\x1aL\xf2{:\x94\x13\xeb\xb9\x18\xae\x16J\x97B&\xef\xbfz\xc6\xd3\xea\xbf'\xcb\x93O\x85\xef\xfd\xdd\x9f\xc6\xf7\xffy\xb6;y\xf0\xe0\xf3\x83\x07\x81\x17\x82\x97x\x9a\xef\xder}\xf5\xf3\xe6\x8c\xf5(k\xf7\x9e,\xf0\xf0\xf6\xec2\xb4(x\x03&2M\xe2\xc7,_\x7f\x87\xebGk\x00\xe0\x17\x9c:\x04\xef\x0f\xf2\x1d#\x87\xbd\xe7\x1f\xf8\xa4\x07\x94?\xaf\x8d\x8a(f\xcd\xf1MI\x16\x06K\x0e\xa1\x91\xec\xce\xdf@\xdbE\xc1\x8b\x00\xbc\x86a\xa7\xd2^\x08\xda\x83I\x14\x94\xc8i\xad\xcb(\xa9^\x96\x84\xa47o\xe25\x99\x07~e\x0d\xeeN\xfb\xc2\xb4sJ\xf6#?\x93\x14\xd3~1\xaag\xe2\xda\xc20\x05\xd1\x04\xd6\x9b\xaa\x86\x0b\"Y8\xf0)\x9a\xdc\x7fO\x16\x81\x913U\x0bk\xc5\xe1\xfe\x98\x8f}\x02\x0e\xd9A\x16\x1b\xbc\xa3_\xd9,\xcamW\xa4\x14\x8e\x0b8B\xb1\xdc\xdek\x81\xa1\xb7\xf7\x1c\"E`\xd8\xee)\xf3\x9b\xb5en\xa3\xe5\xca\xf1\xbe\xca\xed\x02\x85\xb6\x96\xd2\xae\x0b8\x86\xdc/BH\xa9 gL.+\xca\xb8\xdb\x01\x8e, =-\xec\xb5A\x15X\xe6v\x88\xc0\x18\xd4\x01\x8e>\x0c%\xae\xdc>p\xc5!\xd0\x1f\xc8\xad\xd7V$[6\x91\xc7\xac\x9d\xdd8\"\x03\x12\x90\x95?\x0f\xe1*\x84\n\xcd\xbb\x1c\x16\x029\xa1M\x9aR\xb6\xeb\n\x8e\xc1\xbfA\x91y.\xfc\x07\x19\x9f\xe8/\x05u\xf1o\x02\xc62/9\xd1\x1dV\x93q\x99\xf6_\x06%\\)\n\x8c\xc6\x88\x80\xee\xa9%OhD\xe9(Bh\xe3_\x850\x0f\x82\x88+\xad\xe0\x18\x96\xf2\xef ,\xbb&]N[\x0ddl\xa3\x11\xbb\x0d\xb6\x00/\x8c\x051l\x01f\x18 j\xb0o@\xe0j\xa4\xa5\xc6\xc5\x98\xd3\xa9\xe9\xa9\xa2\xdeZ\xe7W\x84\n3\xb0t\xc8\xfaE\xf7\xefEK\x1b$\xa4\xe4\n\xd3\xdf\xb8-\xc77\x1c\xae\xd6\xca\xb63\x0b\x84\xc6\x89\xee\xca+\x14R\xd3f\x96\x17\xa12N\x91\x1b\xd0\x9acT\x14\xb9\x94W\xd6\xea\xb7\x81\x03\xe8\xdc\xce+\x10\xc4l\x9c\xc5\xb6Z\x84\xfa@\xab\x005\x15iST\xc4\xf5**\xc9|3#\xfe\xd6C\x00\xf52\x96ytNk\xbc:\x9d\xd6nA\xa2h\xc1\x8c\xfd\xee\xfb\x08F$\xa55\x15>hU7\xcc\x9d\xe4\xb9\xb2$S\xb5'\x7f:\x82=\xd4U\xec\x85\xcdmn\xe0\xd7AG\x1cv\xf2\xa4\xd3\x15q\xb1\xe3\xd7\xd3\xcc\xe1\xb2\xbf[\x86\xe2\xf2\xe8\xca\xad_\x8f1\xb7\xb9\xf5K\xe1\xa5q\xd1\x88\xe4\x17\xd6o\xed7\x12\xdd\"p\xc9\xc6\xb5\x81\x95\x011\xbf5\\\xf8\xf7\x9ejd\xb0W\\\x80T$\xbc\xd7&23\xcfg\xcf\xe3\xd9\x8aL\xe0\x9d\x1e\xb5\xe3\x8b*O75I\x167\x13\xc8\xf5uf)\x89K\xde\x8c\x9b\xd2\x85\xf33;\\\xf1;')\xa9 \xbb\x8a\x98t\xf1\xf7\xdd6\x91-\x94\x16\xcd 6\xa8x\xf4\x93TE\xf0 \xbc\xd5W\xba.\xe3\x82\xd7H\xf45\x96\xa4F2n0\xbfG\xdd\xf7\x04b\xfd[\xf2\xa9.\xe3Y\xfd\xb2\xcc\xd7\xd8\xc8F_M\xde\x06\xb9.\x87r\x19x\xce\xee\x920\x81\xec0\x88W$\x9e\xa3\xa1\x87}\xd3<\x9b\xcdHQO\xc0\x8b\x8b\"Mfh\x8f\xf3\xe0\xe7*\xcfBP\x9f\xdc\xc4\xeb\xd4\x1b\xde/\xc3\xf47\xcd\xe3\xf9)\xdaF\xef\x98\xe3\xaf\xdd:\xdf\x0c\x8a\"\xe8^\x84G\xf6\x80\x91\xce\xb6-_K\x02_\xc5\x0b\xf2c\x1e\xcf\x07=\xb4F\xe1-\xc7\x19#\x0fH\x97\xe1\x1dcF?\xe4\xe8\xa42\x81\x99\xbe\xaa\xb8\x1f\xf9\x8b\xfa\xc9%\xc9&\xb0\xe8\xd3\xa5\xa0k\xb9\xc3\xa7\x08G\xf0\xaa\xaf\x8a\xfc\xd9\xaa4\x17*V\xa2^\x0f\x10\xf5z\xa0cp\xd0\xeeD5J\xa9{\xe6FcMZ\x1enm\x0ds\xf0\xed\xf6\x9f>\xfa\x02C\x1a\xf5\xcd\xaf\xa0Z.\xad\xeb \xdb\x1a\xec\xc0\xb0\xd1\x0e\xe8\x8fI\x93\xc29\x17\n\\3\xba\xf6\x87\xc1\x14\x95h\x12\xa7Q!\x99\xb5\x94 ^1\xe8\xa7\x85lv\x1c\xadI\x1dS\xa4\xe6\x7f\xb24\\6\xe5\xe6f\x1b\xe5f\xdeUnn\xacZ\nf\xd0\xd4Isk\xfb\x08T\x0dl\xfb\x16\x1a!\xd8\xe813\x88i\x9b&\xc3$\xb5\x08;\x8fH\x88\xabL\xb1m\x89\x003\xf8Vhn],\xdag\x98\xee\x04\xb7\xc3\xf0X7[\xf0.\x80\x1d`B,8\x82Y\xcf\xfe\xa2[\xa8x\xcd\xf8\x1d\xfc\xc0\xdfca\xd89\xfb\xf4\xcbm\x08\xb3 \x88\x10\xd6n:\xd7i\"\xe5\xe8M\x08\xbf\xdc\x062c6\xe9\xf8\xa78\nb\x887I;\xc4\x97\xfd+\xe0_624\xe5\xb8\xed\xb8A\x0b.\xa4\xa3\x8b\x81\xa0W]\x13\x89\x94`\xfeqH2h#*\x8b\xbdT\xb9\xe0)(\xe6\x1d\x1d\\\xb5\x9bU;\x9b\x18'\xd1\x9a\x94K\xf2\x82\x90\x82\xae\x98E`\xba\xb5\xc5n\xe2\xad.\x98\xac\xdci|\x16\x04!\xcc\x18]\xa2\x84J\xd6\xe2\xba\x9b\xa9D\x96M\x08\x1eV\xf3\x02\xfaM\x9fG\x10\xc5Y\xd6i=\xc1XTc\x0eu\xeb\x19\xd9z%e\xf7\xdf\xc8\xd8T\xfd\xf5+\x1c\xd8\xf9\xd0\xadl\xd2\\\x90\x8e?&\x1b\x9b\xf0Qgei9+{\xd9\xd6q\x1d\xec^\x82\xe2\xbc\xec8\xa6O\xcf\xec\xea\x9d\xfe\x1d\xa2E\x1c\xe9wC\xa9q\xd2\xb1]+\xa3\xaa \xb3\x10\xaa\xa1})e\x90\xfey\xe2@\x84\xdd\xb4}\x9bi}\xa6,h\x19\xc9\xa5{\x1d\xcf\xca\xdcO\xed\xa4e\x94.E\xe0]\xe3\x87j\x0bR\x03\x0d$\xf2\x0e9\x1dv\xec\x18P\xb4\x04\xea\x8a\x88s/\x0bac\x10\xb3\xb4O%!\xd64d5\\\xfdoJ\xf6oB\xc9\x9a\xa4\xcd\xa3(\x99i/\xd0\xd1\xc6z\x1aa\xda\x08\xd2\xb1qC\xd9\x122d\x06NK<\xdd\xb4w\xf4:\x9f\x93T\xc0\x9d\xedjZ\xc7\x80\xeaN\xbbY\xe5\xed\xed\xbbx\x14\xe3>~\xaf\xc5\xff\x8f\xef5\xfd`\xcc.*\xd2T@\xdf\xf3l\x95\xa4\xf3\x92d\x13]\x8cq\x16e\xb0v3BM\x86l\x95\xe4\xe1&b\"\xca`\x0b$*\xca\xbc\xce\xff\xca\x9fgp\x8c\xbbe\xd3\xde-\x99R\xab\x89P\x8a\xc6\xc4W\xec\x99\xbf\xa7\x04\x8c\x08|\x12\x89\x99i\x94\xcb\xc6\xd3T\xb5\x84e_Ok\xc3\xa5V\xab\n\x1cAB\x913\x13\xa3\xd1\xba\x19t=\xf9~u\xc2\x19\x0fY\xfcm\xf8\xcbC\xdd\xcbJ\x98\xd7i-\xe8RA\x90\xb5\x0d\xcfTM\x91 \xf2\xae\x17i\x9d\xb4\xf6\xcc\xb0M\x86o-\xf3\x9cR\xc1\xdc7\x9a\xba\x81\x8d\xe8t\x1c\xc9I\x08S\xf3hd\\\xac\x11\x81\x89\\\xb8\xb9\xabnP\xf5\xb8$\x19\xc6\xc2\xda\xb1\xa5\x1bB\x1b\x13[\xfb\xa0\x08\xc5dJ\xd4t\x03v\xd5\x08p\xa3\xe3L\xee\x00;K\x17O\xcb38\x86\xc4\xa7\x7f\x0821a\x8fq\xbd\xe8\x83\xc1V\xb8\xe7u\xe2\xcb\x85f\xcdl\xd2t@\x91\xae_\x7f{\xc0\xa9;\x8e;G\x17\xc5\x97\xb1;\xa7g\x81\xd6\x19FL\xccE\xed$\xd9\x04\x19\x15\x92\x81$S\xd3,*\x7fS\x9ei\xef)\xe4\xf0}c\x87~\xef\x1e\xf8\x0c\x03\xf2\xb3\x10|D\xb8\x86lN\xcb\xb3\xe0)\xe4\xbb\xbb\x01\x0b\x911--\xd7\xfbb\x1a\x18\xe0E\xa1\xd7_eu\xd8\x8e\x18\xb3F\x0e\xdb\xaeu\x03A\x945\x82cfi4Q\x9f\x1e\x888\xc9Hu\xd0\xafE\x11\x1cu6\x0dN\xfb\x12Ui\x8dA\xa8\x05\x0f@\xdd\xc9#6\xa4\x98j9\xcd\xd0\xa8\x9eE\x8e-Y\xfe\x85\x1c\xad\xd4\xd0\xe8?\x04\xfalxg*\xc4w\xf4V4\xfa\xb7\x9b\x99\xf7\xd9X\x06o\xf8\xd6\xe5p\xc0\xf1\xf9\xdf\x8b5T\x7f\xfd\n\xdc\x84\x10\xc3\x1e\x0e\x89aZnB\xf0!\xfbZ\x8b{\xc1\x88\xeck\xe5;\xc9\x89<2q\"\x99\xff\xed\x00\xf6\x0cr\"W<\x03Y\x87\x99\x94\xa2\x1bKs\xab\xf2*\x03\x9b\x1a\xb7%f\x0b\x9e\x85\xb0\x08\xa1\x08a\x1e\xc2\nMF\xd7h\xbdv\x03G\x10\x97Kt5T2m\x1d\xa0uYc@!\xabL\x0f\xe8!\xda\xfaI\xf9v\xfdn\x97Z\x141\xf6\xeb\xd29\xf2\x14\x9e.O\x9f\x06P]'L>\x14\xd9, \x86\xce\xb1\xd11LW\xe8\x90\xd5S(\xce\xe1\x08nx\\\x99\x93\xacNJ\xf2\xa1$\x84\xa5\x18\xbe\x11\x86\xf5,\xb50\xad\xf6\x8f\x0d\xa9\xeaWYM\xca\x19)\xea\xbcd\xc9\x86\xe9\x9b\xaa\xc8\xb3\x8a\xb4^\x15\xf8\xaa\xad\xe7b\xd9Jo4\xb22\xcbGl'\xd2\x80\xa10\xea\xd5\x8b\xa4\x9a\x95\xc9:\xc9X~\xbe\xcc\x8d{\x92\xa6~\x06+\x90n\xe9O\xd9x\x83\xdf-\x1a\x98L`\xe1\xf6m\x1bh\x13(\xdc>\xebCu\x02s\xeb\x97\xb7!\xda\xce3\xf6[\xa6\xbe9\xbd\x8e\x97KR\x06\x0e!\xf3\xa0 {h\xadKe\xb15\x86\xf2d\x8aY\"\xb2\xac~\x1bv%\x8cN\xea\x0d*\x8c\xael\x863\xa2\xb0\xe1\xac\xdd\xc0\xd6\xcf\x80\xe1\x1a\xad\xab\xbaL\n\x11\x85\x14\xedl\x06\xadcD\xb1^\x12\xe1&\xfe\xd6y\x13/\x99\xe3/\xc9\xea\x10vJJ\xc2\xda\n|\xe6\xdb\x99\xa9\xcc\xe7\x12\xc1\xcfW]\x91\xf8\x97|Y2\xf4\xd6C\x16\x9f\xaeQ|Qn\x8a\xda\xf7X\x87^\x08K\x97\x19X2\xad\x8e\xc9\xac*\xb5\x18\x96L\xaaF\xc6\x960VI\xebb\xd8\x9f\x8a\xb8\xa5\x93j\x8b\x81\xc3F\x0e\x0d\x93\xb0p\xb9X\x9e\x14V\x9d\x99\x1f\x8ce\xaa\xfe\xbdX#\xfd`\xf2A&@s2\xef\x19O\xe6\xbd\xf6\xc9\xbcg:\x99{kjSE1\x0b\xe97\xf1z\xc0+\x809d\xaf1\n\xbb\xb9\x16\xc6\xe2\x8d(Yf\xe1\xb2\x0c\xb9\x9a\x9dG\x08|\x94\x89\x1eV\xfbFX\xed\xb7a\xb5?\xc4\xc5\x80\x8a\xdb\xe4\x13\x99mj\x16rZa\xcf\x86\x891#\xc2\x04I\x8ay\xc7\x86]\x1aDB\xf0\xfa\xe7\xae\x87O{G*}\xbc\xa9H\xf9\x92\xd4\xb3\x95g\x8d\xc1&V\xd4\xca0\xb0%\x9d@9\\M\x0d\xcaeI)\xac,\xffP\xa8\xb4\xdb\x10\x12\x831\xb7\xf5\xd6\xde\xac\x1f6\xed\xb6\x9a\x1d\x1d\x94\xe6k\xbb\xe4*\xd9\x0b\xfd\xdbF\xcd\xc1\x03\n\x1c\x03\x95\xd4\x0d\xa0\xcd\xb1-\xbe\xcc\x1f\xe2\xa5\xbeV\xd2n3\x87c\xf0\xf87\x1e\x18\xcd\xa4c\x96\xec\xe7\xe0m\x03\xe4\xe7\xf9\xba\x88\xeb\xe4\"I\x93\xfa\xe6u>7\xec\xe2\x8d\xc1\xdb\x96\x96\x05\xbe3\x92\x12\xc6\xaf\x90x\xb6\x92\xdd\x06\xf4\xa8\xb0s\xfa\x8d\xb6\xdbNb\x18\xd8l$&\xc5Z\x12\xc7\xf4[\xdaO\xa3:^Vp\x0c3\xfeg\x00\x13\x98&gc\xcd\xc0[\xce\xb4G\xaa3\xad]\xbb\x8a1\x1cX`\x1c\xfc\x8f\xddF\x0c~\x06\\\x97\xcd\x00\x9e\x17\xaf\xe6\x81\x9f\xe2\xfd_n\xdb\xf0\xa2\x0c\xa3\xc6\x04bk+:W\xedn)PDv\x1b\x11\xe7\x98\xed\x8d\xc2\x18\xba%\x8a\xa0_\x86\xfd\xd2-\x12q\x9c\xfd\xd9Z\xe4\xccL\xdeE\xb1\xf9wQ\x8c\xdaLgg\x01\xd0\x7fwwCH\xa6\x9e\x07\xbb0\x83]|D\xf1\xa5\x18n\x83\xa9\xa9\x9b\xb0D\xf4\xecK\xb0M\xfb\x8aP\xcc\xa4\xa2)\xed\x8a\xa2\xa4C\x04a\xacz\x04s\x16\x8a|\xfcp\x81wK\xe5^:L{m\xeeyA+\xb7:\x9c\xd3\xde\xcc\x89\x9bAQ\xe2\xb31\x17\xc6\xba\x06\x06Z\x7f\xa9\xd66;\xfb\xcaj\xb0\x10\xea\xa8\"\xe9\xc2\xe0'\xac\xde\xb2\x1d\xf6-\x10\xd6\xf1%9aL\x0c\x1cQ\xb2\xc1\x1e=+\x92\xeaC\xbc\x94\xb4\xa1\x92\x7f5\x95\x9d\xf4Vw\xc0\xb2\xea\xf7\x1dj\xce\xd4\xe1\x1b\x9d\xf63^\xb3hMh\x80\x1a\xd9h\xe2v\x07*t8?s\xad\xd9\x85Ic`\xa2\xb5\xa5\xe1@\x96w29$\x99\xe9>KVJh\xa5r\x9a\x9f\x0d*\x9c$\x81\xab\xb47\xf4\xc0x\xb5l\x9a\x9f\x05\xd8Xs\xf8V,,\x8d\xb9i\xceMO\xf0\xebi\xa2W\xf2\x9b\xf9\x0e}\xc3q\x91T\xba`\x81=\x1b\x0d=\xe6\xffK\"\xfaV \xf8\x8f\xd9\x03nK\xd9\x9e*=K\xfa\x84Q(\xf6\xbf\xd5\x9a T\\u\xdf\x7f\x93\xda\xb0\x02\x9a%\xd1\xbalj\xd6z6\xc6}\xa5g\x89\xca\xb4\x12:\xd7CMW\x0b\x16.\x8d\x1d\x1a\xfa~\xba\xf03:\x17*\x88\xa9\x13\xdf\x9a\xa5\x19w\x07\xf6\xe4` \xce\xf1\x7f\x86\xa6\xe7\x0b\x85O\x85\xd14\x1f\n>\x89*2\xdb\x94I\x9d\x90*\x04\"\xee*0JPV\x7f\xb8)\x08{\xca\x14\x08\xcac\xc3I\xc3\xa4\xaej\xb6\"&\xd9\x8c\x89\x9c\x9a;\x11m\xed\x8a\xd7\xee\xdf\x93h\xab\xcf\x98\xdc\xcd\"\x19\xfcT\x1ax\xf2\x05\xd6\x92\xea\x0f}\xa5\x82\x81\x87\x0f\xf4\x87|~\x13\xa2\xb6\xb8\xbc\"\xa5a\xf2s\xaeP\xa6U\xfe\x1a\x97I|\x91\x12\x83S\xed\n\xab\xae\xea\xdapE\xb1\xe4R\xaeP\x93\xe8k\xdd\xb4k\xfd\xb0I\xd2\xb9\xb1\xb2\x08\xe2\xf5)J\xaa\xb7\xcfN\x0f\x03\xbf\xd6\x1c\x147\xe8\xaeO\x1b~\x0b\xc7p.\xef!\x95\x88\xe8\x86 \x83\xef\x8c\xc4bS\xa6\x13cd\xa3YI\xe6$\xab\x938\xad&\x80Z\xf6Ut\x9d\xd4\xab\xe7\xcds8\x06/\xc9f\xe9fN0\x0ca\x15\xaf\xc9}\x16C\xcc\xd0h\xe3\x08l85gy~\x89q\xdeuF\x84\xfd\xf9\xc5\xa8\xfd\x7f\xa7A[z\xb4\x07!T\xb2B\x0fS\xe1\x08*\xca\xf4\xf3\x1a\x12\xed(=7\x80\xf2\x83\\\xaa%\xa9%\x91}\x1f_\x07CQew>\xa8\x91U\x9f\xfb^\xc3\xa4P\x89'\xc3\xd0\xb1Y^\xc3\"\xdfds\x9d\xab\x10\xed\xfb5F\x9e\x94\xd4C\x0f\xbeWmm\xd3k8\x86_na\x02\xaf\xf5\xd5\x7f\xc66\x87t1o\xb0\x86\x10\xd7\xf5\xf3{\x17m\xca\x14v\x8f\x8c\xa6\xa1\x83\xaa\x01F\x93\xcc\x01\x03$\xcd0\xdeT\xb2\x8dm\xbcU\xec\xec{c\x18\x9dF'\xf1\xc6pdr\x1d\xc4\xcf}\xcc\x0cB\xd8\xc9\xa4\xa5\x8d\x88(\x10ql\x0e\xe1]\x1fr\x12joBx\xc7\xd7\x80\xa2\x17J\xc1?\x07Q\x9d\xffT\x14\xa4|\x1eW\xc4\xc7\xa08G\xb0d\xca%=~\xbc\x97*\xfej\xfa\xe6\xccT\xb3\xe4\xd8\xce7b\x14\xa3\xbb=e\xa7\x0ch\xf7\x02\x8e\xe0\x99\xe2\xa9u\xea\xbfR\xc8_\x104\xcf\xdf\xb7\x9ek\x9a{1B+'4\x8a7S\x12%\xd9\x80-ai\x89\xb3\x85\xaa\xbd\x8b|~\xe3\xc9\x18\xb2\x8ca@\xbc\x8b\xd5\xbf\xa3\xc6h_Z\xb4-;\x11\xb5\xd0:\x8a}\x94\xc5k\xfck9e\x7f\x9fQn\xce\xf0>\xc1M\x1e\xb10\xadX\x19&p\xe9\xb3\xbfCx\x11tn;D\xc2\x96\xeb\xb8\xcc|\xef\x9d\x80+\x8f\xd4\xcf\x9a\xc6p\xfdI\x05\xf1\xfa\"Yn\xf2M%\x83\xdb\xd7+\x02<\n3\xee=X\xc5\x15\xac\xf3\x92\xbe\x893\xc83\xd2(\xfa1;\x00~\x91!\xee\xf7z\x88\xb39\xbe.\xe2\xaa\"\xf3\xfbI\xa6|\x8b\xba\x8d\n\xe6 \x8b#\xc6\xfa\x848\x83?$\xd9\x1f\xd8\xdb\xc8\x0bB\x11\\\xebh8\xf6bG\xd5%u\xeb\x8a8\x86\x91\xb9\x1bsCy\xf2\x85\xbd\n\x8cCHJ2\xa7\xbfvH\x84\xb7\xe2'\xeb\xa2\xbe\xf9+3\xf9nH2\xf7\xe2|/>h&\xd8\x06\x06\x856\x9dgQ\xe6W\xc9\x9chI\xb5:\x99\xb7]L\xf3\x98;\xa8@E\x8ev\xf5M\x81\x88\xa2\xd1@\x976\xaf\x0d\xe0[@I\xa3:\x90.\xdf\xcdK\x03d\xa02\x058M\xb48\xec\x85;\xb6vqA\x84\x97\x8c+\x1c\x91!\x041\x18\x15s\x80l\xf2\xbd{\x90Y\xb4\xce%\xf9\x871\x0e\x8d(rl\xd6@h\"3\xc1p-E\xa9\xfcj\xb8\xa6\xcdz\xc4\xd9\x9c\\\xa7f\xa6\xa4\xf1\xc7\xbe\xa9\xc3/\xcc*@\x0f6u\xe8N\x9d\xa0\x9d\xf1;\xcem\xd2\x9e\xae\x9b\x9e~\x0c\xe1]\xc0\x83\xef\x9ct\x1e\x07\xe2\xcc\xc3M\xda\xb6\x80\x97\xe7a`\xf1\xbd\xa43\xfc\xa9\x9f\x8aM\xf9~l\x98/q\x9c\xc8&\x8c\xde\x18\xa0J\x96\xbb\xe0cP\xfb{\xc8\xdeb\x18\xec&goE\xca\x04M\x8b\x06l\xceoC\xfa\x99\xbe\xa7\xe6\x10~\x8ec\x82#\xf8\xa9\xbf6\xfd\x13\x9c\x0d\xee\x9d\n\xe8>\xc3\xc1\x02#\xa17\xf6\xab\xec\x7foHy\xf3\xb6|\x99\x97\xeb\xc0\x7f\x17\x84\xf0\xeew\xed>Z?m\xf7\xac\xcama#\xb20\xb9\x97\x9e\x80ng\xbbMV\x06)/\xdbo\x14K\xa7\x1b\xc5\\\x11\x02\xcd\xb5\x12'A\x15\xa4\xbc\xec$TB+\x99!\x12\xffXp\xe6\x03\x86{\x15\xdf\x02J\x92\xb6:\x84\xa9\x87<\x9e\x87\xf7\x85~\xc9\x82\xd3Rv\xf1\xc7\xfc\xbaa\x17=6\xb0\xca;\x0bD\x9c\xb7\x81f\x1cj75\xcc\x03N1n\xbb\xf9\xfd\x8c\xc7\xd94sj9\xc5fDi\x97,\xae\x14\x91\n*\xc6\x8dL\x85*\xcd@6\xa59*\xdb\xd0\x0d_!c\xe9\xe5\x01\xfc \xee#\xcf\xe6\xa7\xec&\x86\xce\xb2\x9a\xaaUL>\x93;io\xba\xb2\xa1j\xbawF\xc7'\xda\xdb;\x0b(1\x14\x8dz\xbfxM\xcfn3o9zL\xcf\x98\x87\xc7\x83_\xfc\xe9\xdfo\xcfv\x83\xdb\x07K\xd5\xcf\xe3)\x0bs\x81\x862> \x9e\x06T\xb6\xd8T+\xbf\x9c\xee\x9f\xd9}6\x0d*`?\xdd\xe6f~\x16]\x89\xfd\x85\xbcq\xf3sJ\xac\x97\xa1b\xc2\xed\xaf\x86\x8fo\xe0\xc4g\xc3\xef\xf3\xa5\x0d\x9b\xfd\xb3\xb2\x13\xc9\xfd\x17\x99\x1c\xe6\xd6\x0b\xc1[\xda\x02\x81\xd0\xa5O\xa5\x97j9\xe8\xccd\xba\xdb\xd4\xf7\xd0\xb5\xc6\xb2m\xac;\xb9\x1c\xb1\x85\xcd\xae\xef\xc2\xe2\xcb\xd6 ]\xca\x95<\xb6\x19\x93l\x8b\xdfPj\xbe\xa9-\xdf\xd0\x13\xe6\x9d\xcf\x1dLgy\x8a\xb4\xf4\x9d_\xb6\x1f\xd8F\x9b\xe0\xbe[\xe5\x15z\x1e\x96\xf8\xd7\xf0\x17\xcc\x85\x8e\x92s\x14T\x1c\xfap\xc9\xac\xcb\xf1E\x84O\xf3\xe97H\x9e\x138\x86\x9cb\xf4\xe4\x01\xe6\xd4\xf0\x13\xd8\x85\x18\x9d\xf0\x82\xe9F\xf5\x00\x84c\xd8\xb4\\\x99`b\xc8\xbaz\xeb\xa7!hr\xb2\xdf\xfa\xe8\x9bk\xa7\x15\xe3x\x8a!=8H\x8e\xc2\x85\x0b\xc8\xdb\xc7z)R\xb2XX\x8c.j\xe5\x03\xa8E\x97\xb7}oT\xf3 T\x98\xf4K\xfc`;\x0e\xfd\xad\x8cma\xf4/\x8a!1\xc3\xcd\xa4\x83\x9b\xab\xba.\x06p\x87\x19\xf4\n\xdcL\xe4_C\xf8\x96\xe27\"\xb0\xbb\xad\xf6\xcc\x82\x99]\xac\x9caz\x17>\xc9\xae\x99+\x96\xf6\x89\xf0\x1b\x17&\xc6\xf2\xbfy\xf80E\xdd\xc4n\x98e\x8di&i\xa2\xe6nU\x03\x82\x7flH\xf9\x95V\xc86{ &\xb3\x8e\xbd\x8ep|\x08\x03\xf6\x17\x87\xc0\xce>w{\xbbw\x0f\xbc\x8b'?\xbd\x7f\xf5<_\x17yF\xb2\xda\xcf4\xbe\xa7:\xcb\xea\xbc\\\xbf\x88\xeb\xf8_\x12\x00~\xc64\xc1=\x0b\x16F\xa5\xe8\xd8\x11<\xf8\x87D\x13\xfa\xcbiC\x89-a\x1ee\xa7\xe3I\x7f,\xe6o]\xb6\xab\x1ei\x1d\xfc\x05\xfe\x93\x03\x0d\xa8\xbf\xee\x9c\xc5\xe8\xcb\xf9\xf9\x90\x12P\xc4`\xd2\x8a\xc8B-\xf9\xed\xe3q\x81r\xff\x05\x08\x8e\xb9bC\xa9\xcdu\x10*QU\xdf\xa4\x03\x95P/K\xd14\x1d\xf6\xae\xe9\xabr\x86%\x18\x8c_g\x1b!8moZp\x16\x13HP?_%\xeb\x82\"\xd4\xe0\x17|J\x13\xd8\xd0ol\x990X6\xa0 \xec\xec\x1b\xab\x99$\xcb!\xfa\x9f\x0b\xd2\xaf\x0bL\xf2\x1f\xc9\x98\x99\x19\xb06K5\xcc\x88l\xfa\x91\x0e\xbcM\xc6mF=n\xdb\xa5\x04+\xd2\x99\xb6\x8b\xe2\xcd )\xde*\x86\x8d|Op\xc3\xb1\\me\xa4\xb4\x0f\nq\xca\xacY!\xdb\\$\xc5\x8c\xa9\xbc}?\xf3\x86\x0fAQ\xf8n\x19\xb5\x15E\xc1-\xe9\x98r\x95\xf7\xe3\xe8\xce\xcew\xa7\ni\xb7\x0f\xc5\xb6\xe3\x07\xf6{\x82f\xb4\xf0\xd0IP\xcd\xc6\x1dJ\xee;e\xf4\xa1\xd0\xdf\x1e\xad'\xb7}U\x0b]\xdf\xa9\xc7S(K\xe6\x8c\x12\x9e\x9a\xbf\xec\x9ad\x11\x14\xbb\xa6g\xae\xdd\x81\xeat!\xc1\xb0\xff\xa8\xe3\xe5\xac\xdf`[t\xe2\xfd\x0f\x14\xfcM\xed\xfd\x9c'\x99\xefi\x9c\x13\x95w\xd0E\xd8_]#\x9b\x0cid\xe3F#\xdb\xd5\xb9\xb2[\x90\x17I\x85\\!\x99S\xfc\x88g5;\x01\xf3P\x1f\xc3\xdeb\xb8i8_\xb5VF\xf5X/\xb0Krcc\x04\x9cTl\x16M,3\xfd\xb42D\xcc\xafk\x88\x1e\x00W\xeb\xda\xe7(\n\x87\x13\xe6\xd6\xb2Ku\xe2(\x1c\x8e\xe1h8\x8f\xa0\x7f\xe6\x88\xc2\xa2\\2\xa6\x92\xb15M\xb6\xdc\xf1{lc\xca;/7Qhrv\xc1\x81\xa4\xf1\x05I\xbb\xe3`.\xf2_e4\xd1\xe0h\xd6q]&\x9f\xbe2X\xc6&r\xe1M\xb2,2 \x1c\xd3\x83\x84\xb9\xfbQ\x06\xef)\x05U\xcdX=\x0c#2a\xaa\xce\x10\x7f\xe9\xc70\xe0\x8e\x8a``\x8a\xb4#\x9b\xa7\xbe\x90`\x13\xee\x1c\xdb\x8ccB\xfb73\x9e[\xc0\x15\x1c`\x0b\xcaBkn\x02\xc0(\xed\xb3-Q\xc43\xf2\x82\xa4\xc9:\xa9)\x93\xee4\xfd\x94O_\x99\xf8o;o\x0f\x83\x15\x18RX\x0d\xcc\xbeH\x8a\xd1\x93\x9f\xfd\xcbM\xfe3\xc6\x0eu\x9dh\xde\x0d H\xeb\xa1AE\xc7\x1d\x92\xbe}\xc2\x1c\x92\x1e\xe9\x1d\x92\x985\xf9#]~\xff\xd4i%\x05\xec&\x0f\x8e\x7f?=\xfb\xffv\xbe\xb9\xf7\x07?\xf8\xe3n\xf8\xf4\xc8\x93\xf7\x19\xdcp\xb6?\x15\x8d&~L\xa7\x0f\xfe>\x8d\xef\xffs\xef\xfe\x93\x8f\xf7\xa3\xf3\xff:\xdb\xfd\xe6A\x12\xd5\xa4\xaau,\xd7\xb6~\x01O\x0e\xf7\xb7\xb7\xd1?\xd8\xfe\xd3\xc3/0\xefo\xbd\xfa\xb7\xd4\x8a\xca\x00\xa9f\x95\xa6\xdd5\xb5\xec[ a\xcc\x9a\xc1\x84(\x96\x08\x95\x9a|(\xd8\xe6`\"\x14\xb3\xdb\xef\xa2\xef=\x8bw\xa3\x86\xcbbtR\x8c\x84\xc2\x9d\x18\xdc{\xe7\xed1\x16b\x8c\x06\xdfeLx \x80\x89F[q\xeb\xd7\xd4\x10n\xe4\n\xb3-\xdc\xbb\x07;;\x1d\xfd\xea\\D\xc8\xd2\x7f\xb8\xee\xc7\xc6\x8aC\x98z3a\xf6\xac:\xfd\xde\x9c\xb2\xf0\x00<\xb6\xcfP*)\xe5\xa6l\xd1\xbd\\]H\xe3\xb4E\xdb8\xad3\xf42P\x14\xd8W\xf4\x1f\x16\xd3\xa6s}\xd5\xc0\x0bG\xd5\xfc\x94a\x7f\x8e\xc1_il4\x06X\x13\x19\xe0&\x83$\x1bN\xde\"8\x98\xf9t(\xb6$p\xa4^O\xb3\x01{\x0f\xb4\x07\xb0\x9d\xd3R\xa1\xcb\xf3\xd6\x7f\xfel\xbb\x10\x03\x8e\xfd9zN\x0c\x9b\x9b\xb0!X\x9bCy?.\x92\xffEx4\xcc8\x00\x0f\x17\x93\xdf3\xf2\xe0\x98\xfeB8\x19\xc8\xeb\xf0$\x08\xc1c(\xd1\xab+.\xcf;\xb5\xd9\x9dp\xaf\xb6\x08\xc0\xa6\xd6\x1e\x9e\x1d\xa8>\x18\xcc/^\x8c\xde\xce\xf2\x80\x8c\x01\x1aW\xc9L\x8c\x86\x85\xccp\xfd\x1e\x14\xae \xc1@\xc1\xf6[\xcfnAuYT\xc4Uu\x9d\x97\x03a\xcatE\xc8\xb3\x8a\x7f,\x0buA\xd9\xa3\xca\x01z\xa2\xc8\xb5\x8a\x9e\xa9w\x8ep\x04\xde\x0f\x14\xfcN\xf1\xbf\xbc\xe5\x81*-R\xae>R\xa1\xe0r\xf9\xb9\x87a\xdf\xe9\x06\x8eVq\xf5\xf6:\x13'`{x\xb9-_\xb2d\xb3 \xcf)Bi\xfa\xdeS\xa8\xe1{8\xf8\xf6\xd1S\xd8\xdd\xad\x03 ,\xda&\xf3\xca\xa1t\xff{\xd8\x7fD\xb9\xb1=\xc5\xf2\xb1\xe5\x17\xd4q\x0c2\xab\xef:>:\xbeR\xb3\x8ebJ:?\xe4l\xca\xb6\xb3V\x91\x18\x8e\x00s\xce\xd5Q\x91\xc6I\xc6>\xa7\x9c\x1a\x87\xdd\xac$qM\xfcl\x93b|y\xca\x0b\x96l\xda%|/\x1d\xb8\xe8\xdc\xcb@UV\x91iy\x86\xf8\x98\xd1?\xd8\xef\xee\x92sS\xe9f\xcd1)6)\x97\xa43\xfe,\xec;\x92\xa2\xba\xb6IC\xd9\xe1\xc3\xd9\x0d\x99T\x7f \x9d\x9b\xd6\x03\x81\xd6\xed\xc6\x0e\x96\xeb\xa8\xb3\xa5E*gVDk\xfa%r\x9cS:\x1d\x83\xe8\xe5\xe7\xedE\xf8\xfc\x99\x8a(i\x9a_\xbf\x13\x18\x8c\x0fw\xcah\x16\xa7\xa9\xdfEo\xba7\x18\x11 S\x0cv\xbb\xb37b\xc3\x0fy\x809LK&\xcd\xecBLp\x87D\xbb\xfa\xbd\xa0\xcd}\xef\xdf\x8c\xcd)A'\xd0\x16\x9aS\xdc@m\xa7\xae\x95^#\xc7\xe0g}\xc1:\x0b!\xd1*\xc0\x18\x8c \xbe>\x062M\x10\x9f\x15\xad\xb6\x84\x02}\xc5k\xfc\xff\xec\xbdk\x97\x1c\xc7\x95 \xf6]\xbf\"P3KU\x0d\n\x8d\xee\x06@\x11MAt\xa3\xbb\x014\xd4\xe8n\xf6\x03 \x00a\xa0\xac\xcc\xa8\xaaDge&\xf2Q\xdd\x8d\x11\xe6\x90#\x8a\xc2\x83;\xb3\xde\x91\xa8\x91=cy\xd6$H\x00\xb3^\xdb\xeb\xb5\xd7\xf6\x8e\xf7\x1c>\xd6>Gs\xa8\x99\xbf\x80?\xb0\xfe >\x117\"2\xf3\xde\xc8\xac\x02 R\x9c\x1d\xd59\x12\x1by\xe3\x1d7\xee+\xee\xbdqFcp[\xfcSc\xeeB\x81M\xe2o(X%\xf9B\x8e\x97\xbe\x9cjS\xf7\xf8a\xda\x0e\xada4\xd6\xe1j\xd2\x1b^\xf7\xebc6ms\xc2#v\xf4\x88\x01\xe8t1bT\xde.\x01\xbe\x90\xa6\xfe \x9cDs\xd4\x18\xca\xf3\xcb\xa6\x0f\x13\xd2H\n\x88\x9d]\x0foX\x06\xc6\xd1\xc0<.$\x95F'A\xfb\x8b\x93\xaa7\xa8_\xc9\xb1X\xce.|Tf\x17f-\x946\xc0<e\xbe\x9e\x9e5_O\x7f\xc7|\x9d\x9b\x9f\x97q\xc5G\xf5\xc0\xe4\xa0\xd8\x82\x80\xb2\xb9\xf9W40\x12\xd8\x0e_\xe7gO\x96>\xcf\x9d\x9eg\xb2\xd9\xef\xb1\x97o\xb0\xa3\xe2\xcb\xfc+\xecG\xec\xe5\x13\xec%f\xea\x9c:5\x7f\xfae\xd3\xff\xa9\xef\x9c8y\xb2hb~\xfe\xa4nbn\xbe\xdc\x06\xb4\xca^b/\x9f\xb07\xddND\x0bs]\xb9\xb0/\x9f:u\xe2e)S\xcc\xcd\xce\xcb\"\x1d\xf6\xdd\xef\xb2\xb9Y\xf6#\xa6\xbe\xa0\xb5\x97; C89k\x86\xf0\n\x19\xc2\xdc<\x19C\xf3\xd0:\x0d\xac\xc2\xce\xd5\xddh\x14;ns\x14n\xf5\xcd6\x8aaQ\xefV\xdd\xc5Cd\xbdr\xa0\xe2g\x9cD\xf1\x02kE\xd5\x0c{\x96fI\xeef\x91zH\xbb\xf4\xa1\xe8\xab\x16\"4\x85b|\xdfb_VaU3/\x16C \x1bTS=\xfe\xcf\xe6g\x8f\x0f\x8a\x16\xca\xf7\xc4\xd5\xc50\x97\xb2\xad\xadsK'N\xbf\xf22J\x1f\xd3\x97i\x89\xe1m \x8a\xbd[\xe7\x96\xe6\xbes\xe2\x95ib\x8c\x88\x90\x19uY\xeb\xa8-\xf3\x04\xa5\x13jh\xcf\xd1\xcd\xc4+\xe6j'f\x1e-\xf5W\x8b\xc0a\x00f\x95\x9eo_\xf5\x0e\x02E(6P\xbe\xbdF\xb7/l\x9f\x9e\xc3a4\xbe\xfa>\x8f\xbe\x9b0W\xb5\xbd\x93n\xfdY\xe9\x04H\xef\xc8P\xbf{\x02O\xb9H\xc7\xac6/;\x9b,;\x99<\x13\x19\xf9\xf8\x1a\xe33\x03\x9e\xed\xf8#\xde\xee@\xf5\xd2\xbf\x17T\xbc\xfe\x11x\x19\xcf\xa2!Vt\xa6\xe2\xbb\xcc\xf62\x03\xe7@\xca\x9f0\xb0\x05\xf9\x97\xfcc\x9aY2\xb5\xf0A\x97\xb9\xf5t;oC\n\x97\\\x12h\xb52G,~f\xba\x02/\xf6\x0fhp\xf1\xef\xa9\xea\xfb\xd2\x80\xa0\x0b\x1e\xf1\x85\"\xa03\xe3\xe8\xd3\xd1\x01\xf3\x91\xfag\xd6\xe92\xc7\xcc\xb4\x81\x07\xa5\xb2\xe9z&#\xad\"\xe94\x13ef\xb2\xca\xbc\x083E\xbaDSm\xc9\xd0\x02`bA\xc5\x18\x14\x1c=\xda|\xe7);\xbe\x1e\xdcP,.\xb81U\x87\xba\xc8\xb4\xe9\xfeX\xad~\xa7\x7fc\xf5\xe8W4\xf1\x8d\xd4X\x96\xcaj\\\xf6\xb4\xc67M\xd2\x8c\xba\xe4s\xb5{\xde/v\x88\xc5\xd3n\x90\xdc\x9c\xfeL\x1a%Y\xbb\xd3e\xb1\xf9K\x06\xea\x95\x9e\x88\x14{\xf7=\xd8\xc3c\xc7\xeawM\x0e\x04v\x8c\xc5\xd3l\x98\xc1\x8e/\xd8\x99\x8c\xed\xbb\x1e\xdc\xe8\xb2#N\x9b_wotY&\xff?\x9c\x8c\xdbZx\xd14\xa8\x90yi\xfa\xfd\xbb\xc5\xb1\xab\xc0\xee\x96\x1c\xa6\x8c\x7fR\xde,kHu\x9c\x15Y\x17\xcfT\x1e\xce\xbaki0\xadm\xf0H\x1bH\xab\x95\xa8\x8a\xef:\xffV\xe9\xbbA\x0e\xe9\xcc\xa9;\xa9(\xfb3n\x14\xcb\xb7\xf8j\xc0\x92_I\xf1\xa8\xa0\x0c\xea!d[\x8f\xd7go<\xaf\x04\xa49%=(\xc0\x0e\xe8u\xb3\x8d}\x9e8=ka\x9f\x13/\x98\xd5\xe2Fj`H\xad\xbbK\x19o\xd8\x9e?1[1\xb4_L\xa3pS\x1cw\xfd\xa0\x9b3S\xfc\x13\xacN<^\n\xa2P>*=s\xd3\xfc\xb3*\xee\xe5\xd6%p#\xfe[G\xc8s\xa9+\xd4\x11\xa2\\&O\xa9;\xdc\xf9\x8c\xf8o\xf5@\xd9\x14\xaa\xc0*\xa9Kw\x03\xd0K\xean5\xb5\xd5\x9e.\xa7d\x02\xa2w\x0b\x17P\xd4\x1f\x8f\xab\xfcO\xc3i\xe4Mt\x97\x85\xb0q\xa6\x8cM\x8bs\x95\x93JR\xe3\xa7R ~\xd3\xd2\xcf\x91\xb9\"\xbc\xeb\x8cN|.\x1f\x98?2\xdb\xe9\xaa\x82V--a\xaf\xb1Dp\xc2\xd9.\xe3\xf2\xeeDH[l\x81\xc5\xf2\xa3\xcc\xb8\xdcR\x179\x00\xa2\xab4V\x99\x0d\xed\xe8XAE\x8b\xa5\x95\"=x\xb0{\x9e\xee7\x8a\xcd\xce\xb93\xa5\xe6\xe4\x1d\x8a:\n\x16\x9b\x9dlF\x9d\xc7\xe7jJ\x8bl\xe2T\xd6\xb7,\xa5C\xd3\xacT\xa3\x05\x8eO\xd1\x93D\xd4\x10D\x94.\xc3\x0d\x89\xad\xaa\x0c\xa1S?\x06ql\xca\x1d\xdaw@\x9a@\xe4\x11cg\x04\xf75\x88\xd81Od\x01\xb8\xc3\xb2a\x12\xed\x8b-#\xcai\xbb\xb5#\x1a0\xce\xc1\xac\xef\xf8\x01\xf7Z]\xd6\xdaY\xd9\xde\xb9\xb9\xb1\xb9\xb2\xb5\xb8\xb3\xba\xb1~\xf3\xdc\xe2\xea\xda\xcarK\xa2T\xd8e|\x82\x18\x86\x16G\xac8E\x92\xba\xcd\xad\xae]i\xc5\xab[\x88\xb7:\x0f\xecf^\xd9\xaa<\xef\xb4\xcd\xb0\x90\x18j\xeb&\xcd+h\x1e\x81g?\x8c\xe2\x1f\xca\x8bL\x9ed\x87\xccOY\x18eL\xa8\xf9Q\xbfX\xe2\x94\xa9\xa8J\xe6\x87l\xeb\xdc\xd2\xb1\x97O\xcf\xce\x8b\x05/\xd6zc\xf3\xe6\xea\xfa\xe5\xc5\xb5\xd5\xe6\xf5\xd6\xcbR%V\x95\x7fE\xca\x92\x8fT)\x8eU)m\xe6l\x03=`\x90WW2\xd0\xac\xdd:\xde\xb2\xd8>a\x17\xc8\xe7!;\xc3,\x8f\x16\x8cKv>\x0b\xb31!b\x146h\x80\x1d\xd6\x84\xe3J\xd3\xe2\xa1|\x1a\xae\x8e:\nb\xf8\xaa\xf5\xcaWl\xf9@\xda\x16\x877\x14\x95-\x11a\x08\xde.\xc7\xb3]\x1f\xdc`\xaf\xc9)\xf4\xc18\xd6\x9e\xed\xb2\xa1N\xc5z\\f\xe7\x1b\x8a\xee\xc7\xec\x18\xe4\xe2o\x8f\x98\xa1\xbc\x95\x00^\xd9\xf8aA\xb8G\x82R\x0f\x8f\x1e\xc5\xf7\xc8^\xad\x89_\xe2\xfa1@\xf4AG.\x9e\xa7\xad\xee\xd6\n\x0d\xae\x8aL\xe3\xbf\xb4\xf6\x95\xa5\xd2A\xa7\xf9H\xac\x1c\xc4\xdc\xcd\xb8\xc7\x9c\x90\xe5a\xea\x0f\x04\xba\xf7\x9c\x94\x1f\x9b\x9be\xea9d\xa6\x08\xf3\xc8\xd9\xf3\xc3\x01\xcb\x86\\6\x96\xf0>Ox\xe8r\x0f\nH\x80\xf4\xe9c<\xe0\xf2\xa8\xef\xfb\xd9P~\xbe\xc3\x93\xe8\x98h\xd6\x03\x81\xb5z\x8a6\x17w.\xdc\\][[9\xbf\xb8vsqkk\xf1\xea\xcd\xd5\xf5\xe5\x957\xd4\x99\x02\xed\x8e5\xbd\xe5W\x9d\xb2\xdc9\xb1\xa0\x7f\xfc\xc7\x83iu\x1b\xa6\x96p\xc8\xbew\x86\x8d'\xdd\xcb\xc8\x85\xae\xf2H\xf1e\xc0\xbeg6q\x021\x1fr\x19\xc6\xe1\xf7}\xbd&\xec\xd2\xee\xf6\x0e[\xdf\xd8a=\xce\x06\xd2W7a\xd9\xd0 a\xc5\xa5\xc1V\xd0'\xb5\xb8\xa9\xa0Jf\xc9\xab\x0bzyqmw\xe5\xe6\xc6\xee\xce\xcd\x8ds7\xcfn\xec\xae/oO\xbf\x96\xf2\xde \xd8\x92\xb4\xdc\xa7\xd7\xc5\xf4n\xc0\xedV\xd8e^\x97\x0d\x04\x99\xeb|\xfd<\x8b\xd5\xd1R\xfd\xb3\x08\xccE \xc3@\xb9\xc5\x1c9\xc3\x06E\xaa\x83?n\x15\xf8\xe2\xcc\xe4!\xe4\x9a\xdct\xb2a\xe1)8\x90\xa7\xbb\x113\xf0\xaa\xe5\xdf\x9cU\xab]1\xbaZ\x1e\x032Y\xc3\xa8l\x02s\x7fz\x81\xd9&\x16\x13\x07\xe1\xe6\xa5\x91\x7f\xb3\x94\xdf\xce\x05\xe5a\xa3<\xcd\xc4qq\xc2\xe2\x18l\xaf\xbc\xbe\xbb\xb2\xbe\xb4rs}c\xe7\xe6\xe2:\x10\x14\x1c\xe12-\xbb5\x9e>\xf2F\x9f\xef3\x1d\xd6\xa4\x0e\xb9\xf2\x00\xebB>Msk\x9a\xb3\xef\xb2\xf4U\x96\x1f=\xdaa\xfe\xf5\\\x86`\xcau\xba\x9e\x0bN\x05\xf7\xf7\x12R\x16\x8d\xac\xda\x8bO\x054\xbfqC\xe2 \x1bRw\x0bU\xbd\xf6\xa2^\xf4\xd3IVJ\x96rB\xa6\xba\xa9\x10&\xb5%\x1bg/\xae,\xed\xb4\x00k\xc5z\xbcJFy$\xbf\xce\xc5\x01\x9a\xb6\xdf\xafD\xa2\xab\x1f\x9eq\xbe-_\xd9\x81\x826\xe5xEa:b\x87\xa9\x86-\x0cr\x8aa)\x9f(9\x92\x82\xc4\x1d\x07\x12\xa7>\x177\x81\x8dc\xfdv\xfdX\xe5\xa9K3'Q\x1c\xbeu\xbc\xf5\xed/6\xde\xb2\x1a\xc7\xa9\x1a\xc7\xa5\x02 X\xadm\xb9\xa5\x027\xedr\x8b\xc2t\xb9\xe3\x84\xa7\xe2X\xb5U\x88\\/\xe0\x025~(F\xf5C\xe6\x84\x1e\xfb\xa1\x18\xcd\x0fK(\xd4\xa9n\xcd\xb9\xad\x8dK7\xb7V^\xdf]\xddZ\x994W#/\x98\xa9V\xd4c\xf3\xb5P+\xcd\x02\x94o\xa1\xb5Eq\xca\x99\xcb\xd2\xd3O\xdd\xf1\xbc\x1fv\xd9\x0f\xd5\xc8\xd4\"\x88\x115,\x02\xc8\x1b_\xfd*83C'\xdd\xd5\xc9n\xdaz%\xbeyK\xb1\xb4\xb8.H\xdd\xd2\xc6\xfa\xce\xe2\xea\xfa\xcd\xdd\xf5\xe5\x95s\xab\xeb\x13\x96\xc6r%Q6\xc5\xa8e\xa87cB\xa0\xb4<\xe3\x85:\xd8\x98_\x83)kxD+\xd8E 1\x1e_\xd2\x98\x94\x1d\x05\x15I\xfd\xb3y\x0f\x96\x9cP.4OdT\xb2\xa3\x16\xb7$\xe48\x99\x14f=\x9e\xfa \xf7\xa4u\xcfB\x03\xd5\xba..\x97W\xb2I\xe6\xab\xc1\xad\xb2\xe5\xc2|,\x0c\x0fM+\xed\x83W\x99\xa3\xdc\xac\xa2\xe7\x9a\xb8\x98be\xce\x8e\x9c\xa9\x10\xf33\xe6E\x1c\xf0\x91\x1f\xf8if\x99\xfd\xee\xfa\xd6\xca\xf6\xc6\xda\xe5\xc5\xb3k+\xd3\xce\x7f\n\xfaZ\x8fQ\x81\x10\x07\xdb\x16\xff}\xfdk2\xd0\xea\x1f\x18j\x81\\O\xbc\xa3\xab\xc9}.~wo\xd0c\xa3\x7fb\xaa\xd2\xeb\xbdq\xc9\xe4\x9c\x03\x99\xf9\xe2K\xec\x9a\x98\xc7\xd4\xfb&\xd9\xc3\xd4\xfb\xd6(\xd7yZ\xae\xc3;f\xf7\x8b\x93B\xd4\xf3Iq/J\xb8\xd6\xdd\x87\x1d\xd6oW\xe4\xeb\xb0\xd3\xc5\x02\xb7\xd0\x03~\xf4#\xa1\x11\xd0F\x1aL\x1e\x89L\x19\xf6\xa3\x1f\xd5\xe5\x01\xac\x84t(\xd7\xfc\xc2\xab1\x12\x82y\xd2\xe6\xd7\xa3\x1b\xd2\xb79\xd4\xc6\x9dI1\x0b\xcd\xee\x81\x926\x94\xfdn\xf1\x1a\xd7]\x81\x88\x1f\xecLm0\x99\xf9K:\xed\xca\xf7\x92\xcf\x1enF~\x98I\x0f\xfa\xc0Du\x17\xfc\xee\x0cs\xcdW\xd8\xdb3\xaco\xbel\xc9p\xbd\x04\xc7\xe7\xe2y\xe9\x0b2u\x8bb\x91\xd4A\xebM\xbe>\xc5V\xadaR\xd6\x8c\x8a\x85\x12\x13\x1c;\x81\xef9\x99\xf4\xe9\x8aK\x1f\x84\xd6\xe5}K\x15\x9b\xc6\xb3-l\xcf\xbfR\xea\xbd\xd6w\xdb\xa6h\x1dI\x94\xb72\x9f\xb9\x99\x81{\xac^\x9e\x9d\xc3\x98\xab5Y\x0de@U\xe6\x0b\xa9#\xe1.\xf7\xc7<\xe92\xf3\x96\x84L)\"x\xe2\x11|\xcc4*!\x1c\xf9BQ\x0b_(\xad\x0cM)SN'Sr\ni\xcf\xcfw*\x8ew\x96<25\xbe\x93\xf4\x909\xfd\x8c'k\x91\xe3M\x13a \xafk\x93(\xcaVC\x08\xc4>C?\xe9w\xc9\xd1\xf7\x19?\xf4\xb3\x8d\xc5<\x1bB\xb2\x98<\x1b.\xca\xde\xd2\x197\n\xfb\xfe O\xb8\x80Zj\xc6 7)\xdc\x16e*(is\xee\xf9\xa1\xd7\x86\xcb\x0f\xe94\xdeT\x0d\xf2\x1a\x9dan\xb5\x16%O\x94\xa5\xa6\x99\x93\xf1\xcd \x1f\xf8\xa15\x0eD\xfcD?u0&W_\x12\x87t\x81Ez\xb3\xeay\xb7\x03\xcb\xd2\x185\x96\xf2\x80\xbbY$Z\xb4\xbf\x0fY\x93\x95\x16r\xdd\xd4\x0ft?q\xe2E\xdd\xbf\xfdQ\xae\x89\xee!U\xdaa\xdd\x05\x0c(v\xb5\x8a\xf0\x91B\xf8\x13\xa7O\xe2\x9c\x19>\xbc<\xd4\x9e?A\xb2M:\nt\xe2\xf4)\x0c\xca\x0dH\xe6\xd90\xb0&\xb7c`C(\xdbc\xd3\xed{&\xa3J(iWQW6\xbc#\x89\xea&$\xe80\x91D*\x05@\x06\xd1\xdf\xfczX\x93K\xa2L$x9\xff\xa7M6\nj}\xaf\xa7\xcfzY\x93\xf1\xb2Y(s5\x89\xb5\x18\xdb\n\x9d\xacL;\x0c\nQ|/\x1e\x0d\xd9\xd6\xa7\x85\x16\xca\xa5\xcdR\x14\x12\xdc\xd5r\xfaMz5?\xddX\xdc>\xd1\x91 \xcd&>\xb2\xc1\x16\xd8\xf5\x96%\xd3b\xcb\x12\xa6*\xd4\x82\xbc\xdd\x11r\xc8j\xd8\xben\xd2E\xa4]v=\xbbA\xd2\xc1\xc0F\x04\xec5\xe6\xcb\x07\x99\x13\x94\n\xb3![\x99\xfd\xdc\xebdq\xb5\xae5:u\x9c\xcd\xcf\xd2F0\xc5\"8\x0b,\x98\xc9\xa2\x8b\xdb\xe8=gHS+NB#\"\xf4\xeb\x1c\x8d4U\x98\x1a\x0b\xfci\xb0\xc0\x81\xb7[j\xb1 7O ~eX \xc3\x98-X\x907aA\xca^c\xd1\xf3b\x81\x0d\xcb\xd5\x96\xa5So\x19\xfb\xa6\x89F]\xed\n-\xa5#\xca+$\x84d^r\x14d\x8e<\x00\x90Kq\xf5;\xe8+$\x1b\x9e\xc3\x11\x16\x81\x8a\x87\x98\xb7\xf2\x14\xf7\xeb!\xa7\xfa\xaf2\xa9\x97\xfeT:'kT\xca\xc9\xdae\xc1\xcc\xf6\x85\x8d+7\x17ww.\xdc\xdc\xdc\xd8\xdc\xdd\x9c\x90oY\xfb\x95e3\xb1-\x9f\x9f\x9e\xd1L\xca\xb3v+\x1dF\xfbe\x84\x17\xa8Q\xda;\xfbx\xc4P6\xb6V\xaf\xad<\xefH(B'&Op?\x89F\x17\xb7;BW&\xa5\x80\x90\x0c\xc4\x80\x8b\x1c\xc1-x8CV\xbe\xe4\xc4\x1d\x1c\xf8n\xd4%\x1ef\xc9\xe16\xbf\xdd\x9e6\xe3\xba\x96\x0dP\xbaN\xdee8\xb0U\xff\xe4,\xaf\xcf\xd6\xe46H$t\xae\x06\nIe\x159i\xc1 \x17T*\x939\xcfjl\x0c\x95T\xab2\xc7H\xe9\xa5\x1d\xbf#W,\x92[\x1c\xda\xcdG\x85\xa9\xac\x94\xdf\xd4\x9a\x97\x87\x95\xc2}\x8aq\xca\x93.\x86\xa9\xb9R\xebFC\xfca`\xaf\xab\x19\x96u\x9aLm|\xdb\xccET\x0e\xbbL\xd5ot\x9f.xe^?*H3\xb7P\xce\xa6\n\x8f\x93\xf5\xb2\xc8)?\xdaS\xf7Ls\xa7S\x1e\x96\xda\xba\x1b]\x98j[\x7f\x98\x98\x11B\x066\xc3y,\xa1\xb7\x10\xad\xa6?\x8a77\xc4\x9f\xf3/\xe6D\x86\x92Q\xdb\xcfaX\x97,\xd9\xa9\xf1u2\xe7\x10\xde\xeb!o\xfd\n\xaa\x17u \xcfH\x95\x14$z]$\xd6T\x96\xc6\x81\x15\x96\x88\xd7\xb9\xd1-\xe7\x05\xac[\xaa\xb5\x8d\xf3\x1b\xbb;/f\x81,\xc4hf\xdf\xcf\x86\x97\xf2\x0c\xaeG\xa6\xc8\xa8h\xc9\xe4\xd5\xf8\x8c+\x9f\x81\xc0\xb2\xda\x10^\x0b\x9a\xd5\x98N,\xb8\x96L^\xc0\xa5\x8d\xf5s\xab\xe7w\xb7V$/z\xde\x85l\x1a \x18\x16,\xdcG\x8d\xea\xb7+\xc0t\xc1\xf6\xb8\x04\x83\x94s\xf2\xd3E\xb3x\x90\xd4\xad\xfaO\xaf`\xa9\xe7\xa2d\x0bLY\xe0\xbe\xa4\xd2\x0f\x94\x98\xee\xd9\xc3ug\xc4S\\q'2}H\x90`\xd5a\xa9\x9a\xe5\xb8i\xdbS\xde\x0e\xdb'\x89t\x15)\x08\x95\xa1 o\xc3),D9J\xb4z\xbe8\xe2\xafDV\x1a\xab\x04B\xf5\xc7\x8a\x9a\x05\xcb\x967\xcb\xe2\x01\x19\x82\xec\x90Z\xe5\xe8\x08enr\x1f\x8a\xbc#\xd9\xa9\x83p\xa6v/'\xf7\\\xd3\xf1tb\x0b\xd2\xa2l\x0f \xb4\x8d\xec\xe4\x80\xecT\xfb\xcaQh\xe4\xa05?\xcd\x88\x90\xc5\xca\x96\x8b\xe7\x16\xb4\x18\x12\xb6\xa2\xa9\x84-fD\xaa:\x81\x8b)\x9c\xae\x17\xbaXIYt\xac\xe2c\xb9T.\xc9T\xd2\x95/%\x86\xe0\x1b\x9b\xa7\xc3vn#\xb9]\x9c\x17\x91\x92\x12\xeb\xe1o$\xa7S#@H\x11\x80\xce\xcb\x8d\xc24\n\xf8\xcc\xbe\x93\x84\xed\xd6\x95\xc5\xad\xf5\xd5\xf5\xf3\x0b\xcc>2?e\x1e\x8f\x13\xee:\xe00\xeb\xb1}?\x08X\x8f\xeb0\x1e\xed\x91\x19\xf2\x83\x8c\x8d\x9c[Q\xc2\xc6\\g\x9aB7\xe2;\xd3\x04\xbb\x11\xe7\x99\xce`,I\x98?\xa1W\x1b\x8f\xc1\xbf\xca\x9b\x039PF\xa9\xba(\xd7\x95T\xd0\xbc\x97^b\xed6\xbcp\xa1$\xe3(\xe6i\xab\xd3\x99\xd9\xe3_h%\x99\xf4~v\xa30s\xfc0U\x17N\xb2\x87T\x8bI\xdc\"w\xeb\xdf]\xe5\xc1\x98+I(\x08\xa2}\xeem\xc3\xa8\xba,\xed\xa8\xe46\x99\x84\xfb]f9\xe9\xba\x1d\x1f\x9e\n\x95\xb9\xcd\xec\xf4\xc0\xaf\xa3\x07\xddI\xa2B\xfdbh|u\x92\x81\xbc\x08L\x0b\x07\xb79V\xcd\x15f\x8a\\\x9f\xbb\xc1^\xab\xfes\xa1\xe9TMEtT\xa16\x18\xfa\n\xaec\xe7~e\xc6\xa3\xfa\xecL\x9f\x84\xdc\x1c\xf14\x1a\xf1)\xc5fSG \x1e/\xe1\x9b\x9f\xa4Y\xbb\x06G\xac\xb2t\xd3.V\xe4\xbf\xc9\xfc}\x82da3rh\xa2\x84\xb8 \x92D_$\x13\xa9\xeeg1\xa6\x06\xe2\x0b\x9b:\xe3\xa7\xe2?\x10\x1b|\xe4H\xa6\x8c\x95\xcf\xbd\xcf*\x97#2\x9b\xf2\xce\xcc\xc8\x89\xa7h\xa5\xd4\xd2\x91#!\xec\x7f\xddv\x1b\xaf\xd1#s\xb6\xad\xd7\x87\x0b\x99W\x19E\x84\x8a\xa2\xf0\xa5\x11A+F\xe5]\xff\x16\xfbFhD\xfc\x80\xbb\xb9\xf4,\xb0j!]\x95\xe5f\xfe\x94E\xd7\x90\xd6\xceH2\x88\xa4\xaa($\xcd\x8aB5^\xb8\"\xe1\x17\xe3\x99R/\xad\xa0\xb7]\xcd\xcf\x9a\x04)|\x9aj\x9f\x83\x89\x94\x1a\\\xe7\x8e\xe8\xa8\x0c\xd6\xd90\xaayr,\x97%\xa6x\xc1M,C\x968\x0d\xcf\xc9\xd6\x1f\x95\xe2\x80/(\x03\x90>\xeeb\x9f\xaa_\xd4\x89\xae\x97\x1eJ\xd4\x7f\x81%5*\x88\xdc~+hb\xfb\xe5W\xdd\xca\x1d\xe0VMS\xf6s_K\xc8x\x1b[\xa9\xac\x0d\x80\x93_\xcd\x1by\xb0\xa3\x0b\xcc\xb1\x83K\x0f\xde\xd4\xd8(\xcb\xaf\xe6X^\xbf\x95rJ\x1d-\xfa\x86P\x89/\xe3\xf1\xd2\x0f\xebnB\xd3\xa1\x94\xd8Vn\xe7N\xf0}~\x08(\x86\xbe\xd1\xf5\xaa[*j?\x917G\xdf\x80\x15\xa4#K\xdba\xfb$y\xe7:2>\x16\x13\xfd\x8dj\x05I>\xd3\xb7\x10\x16{\x82\x02\xf1\xf3\xa2\xfd0\x98\xd2\x1d\x89Y\xc8emj\n\xfd+\xf4D\x9e$\xea\x02\xb9Y]aZQ\x9at\x8d\x8c\x7f\x8e\xa94u?\x10\xf8Tp\xfb\xc95\x02I\x9f\xfb\xa0\xc4v\xcc\xddv6\x93 ~'\xf4\x8a< \xda\x9d\"\x93\xbf.\xb6\x9b\x04u6\n\xfdk\x1e\xbbL\x14#8\xac\xea\xa2[7\xc6\x00\xfe ,\xdc\x0d\xb8\x934\xbc\x8d\xa1\x7f\xcf\x83dB\xfe\x0f\xa6h3O\x82\x05[\x9e\x16\xfc\x13\x03\xde\x96^\xd1G\x1a\x1e<\xd4?\xf5 \xe9j\x98\xf1\xc4\xe5q\x16%\x0b2=\x0f\xfe*\x96j:\xf9\xb5\xfc#w\x8du\xbf\x1a\xef\xee\xf2/\xe1i\x1c\x85)'C%\x9f\x7f\xfbcu\x13\xee\xf10\xf3\x9d ]`\xad\xd4\x19qEg\x1b\xe2\xe0\xf4O\x91\xb7&\xa7\xf6\xf2OP\xc98[\xa8\xbe\xe2y+\x8d\xc2\xee\x1f\x1c\xff\x83\xc9\xe4\xad\xf9\x94\xdc\xed\xccdC\x1e\xb6\xfb]\xd6o\xb8$\xb0Bj\x96\xc9r\xc8\xa6\xd5\x8c\xb4@x\x1d\xa2\x1d\xcc\xd1\xec\xb2V\x11*\xa4i\x8a\xf9\x08zG\xab\xe1\x0d\xf4\xaa\x1553&Nx\\N\xdf\x01r\x95\x11G\xfcg\x01\xc4p)\x90Ws h\xdf\xa8\x92\x1d6\xebLdT\xd9a,\xa8\x85\x90\xb5n\xc2\x02\xddT\x93\xbb B\xf8\x04\xbcQ\xae#\xb6\x04n\xfaW\xb3I\xe4\xab\xcd\xff\xb9V\xb7\x0d\xaa\xdbh7\xe3N\xb7\xb9\xc6)\xa2\xce\x8c_\xfe\xddm\xb2\x0c\x97\x7fU+qe\xb8pc@\xcc\xd4\xfag\xbb\xd9\xb0\xda5i\xe7\xd3\x04\xd8L\x8a[113\x8d\xd9!u\x10N3v\xd5\xa3\xd5B\xb3\x0d\xd8\xf6S\xb3\xb6\xbc.g<\x98 \xd1)]\xf0nQD\xe6;m&=\xf5\x98\xdc`\xed,\xa2\x88j\x1e\xa0\xa2\x9b\xfa-\xfb\xbf\x90\xb5k\x82\xe7O\xf5\xab \xca\x99\x9f:&\xe7\xab\xf2 \xfa\xed\xda\xe5\xbe\xace\xf3\x85\x9e\xa4\x1a\xf32\xab\xe2M\xdf\x8e7\xf6\xba\xea\xdai\xbaH\xb9t\xe6EG\xca}\xe9x6j7u\xdba\xfb\xf4 \x12\x9c\xa6\xee\xa8N\x9c\xb0\\R\xc9\x00NZ\xc5Q\xa0\x93\xb3\xb3\xb6P\x04\x00\x11\x0bm\xaa\xc6pr\xb6\xe6\xecXB\xb9\xfe\xe9\xc5\xb3}\xcd\x01\x18c\x95T\xb2\xda\xc8\x80gk\x91\xeb\x04 `-4\x9b\x03\xb5\xf7\x834K\xc4N\x92\xf2\xab\xceHU\xed\xb4\x0bi\xa9q,\xbf}bf\xec\xd8g\x0fw\x130Tk\xfb>|op6\x85\xf3S\xb9v\xc0U'^w7_\xa2\x96\x169\x9b\xe9\x87`C\xef`E\xb9\xee\"^O\xe9\xb9\\#\xac\x06*}\x99[\xb9*\xa0\xf2\xb7<\xb7\xe6\x9cFh9\xda\\)\x1f~\x97\xf96\x03\xbf9\x0d~\xfd\x1dIh5\xe2\x87U#>{\x8d\xb5\xa3&\xfb\xbdR!:\x02w\x9f\xab\xd8n\x12\xb4[\xe2CU\x89\x08KV\xfd\xc2\xa8?\x93'\x81@2x\x81]HH\x99\x8a\x84#\xe7%\x04\x03\x89ED\xfd\x06\x9f\x9f2\xe6\x0fx6%\xa6q\x15\x0d\x83\xdf\xdf\x94\xf6\xfc\x05\x19J\xf8\x0d\x9d\xa5v\xef\xe8*\xe1q\xde\xf6\xda\x9f\xf4\xf0\xf0\xbf\xbc\x87\x07e\xb0u\xb1~\x82U\xdb\xef>e\x00\x91\x8e\xad+\xc5sE]\x96\xce\xecn./\xee\xac\xdc\x84\xd8\x86\xed A\x0df\xef\xe0\xb9\xf1j\xb4J\xa1\x04\xd0P\n\xdc\xeb\xce\xc6\xf9\xf3k\xd3\xf6\xfa\\1)8U\x89\x19\xb2\x8a\x05;\x82\x02=\xa2o\xc2=\xf7\xf3\xc9\xd3\xd7\x0d[\xb5\xd9\x1f\xa6\x91\xad\xa7\x90o+ \x16\xea\x8b1e-\xe0\xf8\x15\x8d\xe7\xd09\x9f\xfb\xbe\x91C&\x1b\x95c\xb4[xtNa\xb2f%\x84\xda\xf7C/\xda/.3\x86NZ\x93\x00\x0d\xff\xb2\x99\xc09\x8c\xf2L\xc7uKJ\xbe\xccy\xbc\xe6\x87{\x17\x9ct8\xcd\xfd\xd2\x04\x1b]-\xf4K\x98|\xc4\xae\x9a\xfc\xb6\xb5\x1b[\xf2\xcc\x99\x90\x06\xc4$\x1d\xdaq\x06\x0b\x85\xbb\x10\x1dJ\xe5\xcb\xdd\"\xd1\xacEUq\xa4\x9a`UU\x00\xf4\xb2-|\x07@\xdf\xb1+\x17\xce\xd7'W\xff\xf6 \x89\xbc\xcc\xd8v\x93(\x08v\xc0\xf5.U\xffPw\xe0\xf2[\xc2\x1d\xefp'\x82r\x8a\xb8\"\x1c\xae\xd45!X\xcd\x0e\x8f\xfd\xda\xb8\xf6\xbe5\xf2\n\x0c-'g\xb1\x97d\xaej\x9c>AR\xa34\x86\xb6c\xde(\xdf\xa0l\x07V\xac\xe8\x7f}X\xc1\xd4*\xc5\xe5e\x9cH/\x0b\xc67\xc9\xcf\x06\x9c5\x81&5\xc4\xbdLKp+\xef\xf8c\x0f{\xd8h-\xafU\xde\xc2\xcfT\xee\xe3\x08r\x1f\x17\x9e\xf6y\x8d\x99\x1e\xb2*V\xa9y\xd4\xe9\xb2\xb0\xdd\x91\x8f0\nT\xf4\xc3Ag\x8aG`\xc5\xfeG\x13#D\\Yj\xae\xe1\xd6 0O@k\xa14\x10Bi \x84\xd2\xa0\xa1\x9eV\xa6\x13!\xef\x8b\xe3#+\x9fK\xa2\xd1j\xba=\x8c\xf6\xc3\xef\xf3C\x89\x88u\x0d\xc8\xdca}\xf4:ls\x7f1\x8d&\xeeO\x8e\xa5\xf1\xd8\x19\x16O\\\xa9\xa1,\xd5\xb4Rr\xc0n\xa7\xac\x9e:B\xcc\x12\x93\xef\xc8\xa4\xa2\xf5u\xe7\xe5\x9d\x8cyX\xf65\\\xbb-\xe3\xd0\xe1\xcaA\xd3\xa4M'\x83v\xd9Q\xe6Iw\x16\xf1\xd7P\xaaTs\xd5\xf6^z\xe9\xb9\x1b\xac\x8b\x84\x98\xea.\xbe\xaa\x07N\xff\xb2Z\x95hT7\xc4\xc3\xf4\xb7\xf9j\xa4\xd6\xd8\xca\x8a\x8b( \x107\xa1\xcd\x9bYTs\xfdd\xae\x9dp\x1eIE\x06\xafs\xfaTW\xe3T\x86\xb5\x0cf\xaa95[GX\x85RV\xe4\xb2z\x0c\x9f\x92`2\x85\xe6`z)\xa8p\xa7J\x9f$\xbbh\xc2\x8f\xb1\xc9\x06\x04\x0f\x90\xcc5\x1c\x8d\xd6\x11\xf08\x13\xc4\x8c\xe9\xcc\xf9\x91\xa9\xd8\xe9J\xc4o*\xd1L4|\x9c\xf9w\xfah\x12\xfd\xd3'\x9e\xebwhT\xba\xdd\xf6\xf1\x9b\xc7\x07]\xd6b\xad >\x1c\x13(\x94#\xe9\xa8o\xe8\xa6\xa0\xa2\xbb%\xaa\xda\xf6\x1b\xe6\x18J\xfe\xdav\xba\xf0\xdc@h\x8eP\xdby!\xe7rl\x95\x9f&2\xf3\xa9,l\xac\xe2\xf7\x8b\xd0S\xe0\x9f\x96\xeb\x043\xa9Y\x03\xd7xi\xf9i;\x01\xfd;0Z:\xef\x80\xe1:D\x1a\x0c\x92\x11%g\xc7e*\x92\xa5-t\xacq\xddF5\xb2\xe8\x8b[\xb9f!A\xca\xbd`&\xec\x87\xc5Zn:\x89\x98/\x17\x92\x8cY9u\xd7-\x0b\xc8G\x1eg\xb2\xa8\x96\xac\xff\xd68\xc4@\xae(\x96\xf7\xa7\xb1\xd7O\xc3%d\xbb\x8aWP\x87\x1340\xbb\xe5\xa9\xda\x8d=\x9e\x01m\xc4\x94f\x04M\xf0\x8d\x97\xaf\xfeC\xe1U3\xe5\x97\x84|\x14\xe7\x19\xf7\xb6\xb3\xc3@\xe6#\xae\xad \xd6\xb4\xe5\xf4\xd2(\xc83\x95S;\x99\x89\xa3T\xc6\xea\xd4W\x93\xf1\xf7\xec5v\xbc\xed\xe4Y\xf4#X\xc7\x1f\x0d}\xcf\xe3a\xe78[\xa8\x02:\xc7\xeb\x99O\xab\xef\x1fp\x0f\xf7\\\xbc\x90f\xafidx\x99^\xf0U\xf9\x1fG\xf0\xe0b\x91^\xad\xa7\xd221\xbdm\xa5\x9cN\x97\xb5\x8f\xc8wTZi\xe6d\xbe\x0b\xae\xd3\xe5\x81\xbd\xf4\x12\xf3eZ\xe0v2\x13\x8dy\xd2\x0f\xa2}v\x94\x15\xff\xb8Z\xf9\xd7\x1b\x9d\xc2\xdd\xde>\x17=\xd3IX\x88\x14\xc5 \x960\xc0\xf3\xdaT\xa9\x93\x8d_\x88\x96-\xb0\x86D\xe7\xba\xec\x02\xab\x89q\x13\xbf\xcaQ^`\x83\x06,.\xb3\x9f\x056\xae/I\xa4\xae\x056\xb4\x13\x1f{\x1b\xa5{\xe9\xfa\x95\xa8r\xa6i\x1d\xbf\x18\xc3\x9e\xccM\xef$\xf5UZ\xac\xed\x01\xb4_\xd4{\xa44\x8b&\xa9\x1e^;\xf1\xbb,\xb7SgDX\xb2\xa1\x9fvY\x9d]\xd5\x08\xc1\xa9\xd5\x90\xed\x1aCv\xda\xe9J\xeb\xed\xec\xab\xac\x0f\x8f\xf8\xf5\x8f\x1e\xed0\xf7z\xbfj\xc8\xee7\xbf\x16/\xd8\x9cO3\xa7\xc2 \xe5\xbb\x83\xc1\xcc\xcd\x9b\xd2\xb9\xec\xe6M\xed\x12]\xf2)\x0f:\x1d\xe9a\xa6L\xe2\xbc\xcb\xae\x8b\xba&\xc9\xb2\xdb\xe9\xc8\xf0\x99(\\\x8b\x1co\xa2\xfdL\xff4\x07\xf6g\xe2$\x8a\xd3\"\x93\xc2L\x16\xc1\xc1j\xca5\xc0\x14\x17F\x92G8\x939\x83\xae|\x04U}]\xf5\x1a8*\xbe2\xadH\xb0\x82?\xd4\xe9\xc4p\xc3\x10\x12G\x02{V\"J\x96K\xe6\xe9\xbc\xb4\xd2\xf06<\x92I\x82.\xaby\xf6hO\x88=\xad\x84\x87\x1eOj\xcc\xa6\x8a\xdaL\xbc]a\xc5\xa0Rdq0Q\xaai\xec\x84\x84\x9c\xd1F\xfa\x0b\xf0\x9c\x04\xe0Cm\xe1\xbb\xdd\xda\x9e\xb8z\x90B\"F\x1d?\xa7\xab|\xa3\xd3E)\x19\xee\xb6\x8b.\xcc\x15\xf37\xda\x87\xe7\x1bG\xfaCi\x176\xff\xfc\x1d\xd9/\xfd~G\xf6\xbf8\xd9\xb7\xe8\x85\x9a\x13d\xce\xe0\x0b\xd3\xec\xf0w4\xfbw4\xfb\xab\xa6\xd9\xcf\xe7\x1ag!?\xb5It\xa28='\x13\xb2=\x87\xe3R10\xc4Kt\xba\xaf\x93\xb3\xa7-L\xe3E\xe5\xfb\xfa\xe6\xeeG\xa3\xb7(\xc9{gy/\xa5TA\xbe\xd5~\x86\x85&`\x13\x87\x0f\xfc\x97\x85\xa1\x93\xcc\xd4l\x8a`\xa8)\xed\x19\xcc\x04\xeaB$\xf9tlD\xff\xa6\xf5\x1e\xc2?U/\x91\x0f\xc0w\x1b\xbc7'\xb6f7\x9a\x19h\xb3\n\x03\x13\xbf\x98F!\x9e\xfc\x146L\xf6%\xe6os\xe3jwf\xa2P\x90\xdc\x80g\x96G!m?\xb3\x8c/\xbd\xc4Zz\x10\xe5@\xcdP^\xec\xa6<\xdb\xf1G<\xca\xa5\xbb3<\xb8\x7f\x86\x1d\x99\xeb|\x95+_\x0b\xad1s\x92\xaf\xd3\xd2Y9\x15\xeb\xa1/\xefF\xf9\xbd\xc6\x96\xe7d\xce\x82?r\x06\xfcx:\x1e\x1c=\x18\x05\xaf\xf6\x9c\x94\xbf|\xb2\xbbya}\xfe\xda\xe1\xd9\x13\xce\x95\xadYgy\xd6\xbftkq\xdf\xbd0\xf0W\x97\xceF\xd7\xae\x04\xa1s\xe1\xf5\xd3\xab\xb7V\xf7/]8{r\xd5_\x1c\xf0\xf3si/\xbctzu4\x9c\xf5.,\xbe\xbcvx\xfa\x84w\xc2\xcd\xbd;\x97\xf2\xde\x89\x8b\xe1\xda\x9d\xd5\xfdK\xcb\x8bc\xf7\xc4\xb5p\xd5?;\xef\\\xb9|\xe2\xf5\xd1\xe9\x93\x9b\xdb\xab\xfb\xab\xcb\x8b\x83K;\x8b\xfb\xab\xcb+\xfb\x97\x96V\x07\xee\x85\x8b\x81;\x7f\xf9\xd0\x1b]>\xeb\x9e8\x1b\\=\xb1\xb5}\xf5\x8d\xad\xb8wg\xd6\xe7+s\xf1\xb5s\xc1\xbas\xe5u\x7f\xf5\xfczz\xf5\x8d\xf5;\x9b\xdb\x17\xd3k\x17.e\xee\xe8t\xda;\x1f\xe4\xd7\x0eW\x07\xee\x89\xadS\xbd\xf3\xbb\xa7WG\x17\x87W\xe7\xb3\xd0\x1d\x9d\x9e\xeb\x8d^\xcf\x9c+s\xc3k\xf3\xbb/\xaf\x9e?5\xee\x8dv\xbf\xb3z\xbe\nw\xcf\x9f\xbe\xe3\x88\xbe\xe6O\xbe\xbcz>\xc8\xc5\xdfW\xaf\xec\x0f\x9c+\xa7b\xef|0\xec-\xa7\x83\xab\xa3s\xb7\x9cy\xef\xb0w\xe2r~mi\xee\xf0\xda\x1bg\x83\xabo\xbc^W\xde\xdf\xbcup\xcby\xe3\xe2\xad\xde\xf9\xdd\xc1\xd5\x13\x83\xd3\xab\xb7v\xf7W\xfd\xb3\xb7\xf8\xce\xac\xbf\xbe\xb3\xe8\xaf\x9e\xbf\x16\xf7\xce\xef\x9f^\x1d\xc91\xf9\xab\xe7O\x85kW\xce\xcdz\x17V3\xf7\xc4\xd6ao>\x0b6\xb7/~\x87\xcf\xaf\x8f{\xa3k\xf1\xb5\xc3S\xb7z\xf3\x07c7\x9c;\xbd\xea\x9f\xcd\xaf\x1d\xce\x0d\xbd\x0b[\x87ko\xac\xcf\xba\xa3\xd3\xc9\xb5\xed9\xb3o\xfcDv\xab7\x7fj\xe4\\qso>\xd8\xf3\xce\x0fO\xf7\xb7W\x07\xbd\x91\x9b]}ck\xd6\xf5\xe7\x0eQ\xdb\x87W\xafl\xc5\xde\x1b\xeb\xb8\xdc\x1d\xef\xc2\xc5\xb13\xbf\x9b];\x7f\xee\x8es\xfe\xdc\xa1;:w\n\xd5\xdd\xbb\xfa\xc6zt\xf5\x8d\x8b\x87W\xdf\x08d\xfdb\xfc\xab\xb7\xd6wv\xe7\xc4\xffV\xfd\xb3\xa6-\x18\x93X\x93\x15\xb1&\x87\x9b\xdb\xabw\xd6K\xf5\xd6\xael\x0d\xdd\xf9\xe1\xd0\x0d/\x0e\xc5z]\xda\xb9:\xbbvk\xef\xce\xa5;W\x0f\xd6\x97/\x1d\\\xba\xf3\xfa\xfc\xfa\xf2\xca\xdc\xea\xf2\xee\xfc\xda\xad\xbd\x13\xebw\x06'.\xed\xbc~g\xfd\xce\xe0\xf0\xd2\xce\xa5\x93\xab\xb7N\xber\xf5\xca\xa9\xb8w\xe5\xdc\xec\xb5\xcb[\x87W\xaf\x9c\xbasmt\xfa\xb0\xb7}V\xae\x99s\xe5\xe2\x9cw\xfe\xf2\xc6\xd5+sb\x8dg\xdd\xd1\xb9\xdc\x9d\xbf6vG\xb3\xfe\xea\x85\xadS\xae\xc0\xa1\xf0\xe2\xd8;\x7fn\xf6\xda\xf6\xea\xe0\xea\xfc\xb9\xf4\xea\xec\xdc\xf8\x9a\xc4\xad\x83\xb87\xbau\xf9|\x90]{\xe3\xd2\xe9\xd5[\x8b\xdf\xb9\xb4\xbd:\xb8v\xe1\xb2\x98\xf3\x81{\xb8:\xb8:\xba\x1c:WN\x9e^\xbdu\xf6\x8eX\x0b\xc0\xab\xade\x81g\xde\xf2\xac\xef\\9\xb5w\xed\xca\xb5\xb87\n\xc4X\x8en.\x9d\x1e\xf6F\x81\xd8\x9f\xe0\xf2\x85\x8b\xc3^\xb8>\xea\x9d\xb8\x98m\xde\xda\x1f_\x9d\x0f\x0e\xaf\xce\x1f\x04\xe2oq\xe66\x07\xd1\x99\xd67D\"X\x8a\x82\xc0\x89Sx\xbab\xcd\x0f\xf7\xe4\x1f\xe0\xcb#\xff\\\x0d\xe3\x1c\xfe\xda\xe1\x07\xd9b\xc2!\x0d\xea\xd9<\xcb\"\xe0\x16[\xd2KX6\xa5\xfe+\xb3}\xcb\xb7{\xeb\x82\x11\xa5\xff51Ch\xcf\xecW\xac\xafS\xf6mF\x10G7f3i\xf4mF\x90T\x01H\xef\x81\x02\x10#\x88\xab\x00\x15#\x88\xf4\x13\xb7\x9b\xbf\xbf&\x87m\xdaqLx\xbd\xb10p\xab\x85!3\x16\x06\xae^L\x98}\x95\x85\xec\xbb\x8c\xbf\xca\xc2\xa3G;L\xc5\x0d\x17\x16\x86\x10\xa9\xe1jb\xd9tI\xa3U\xe9#G\xd0\xac:3\xb7\"?l\xb7X\xab3\x93%\xfe\xa8\x8dEg&\xb5\xfc2f\xd5wd\x96#\x9b\x14\nLl \x99R\xdbSb\x1c\xc9\xa8a\xa4|G\xdc\xe9(\x99\x05\x8a\x17\x12K]\xec+\x1aIPj\x0b\x9e\xdfE6\x85\xccj=\x98`9\x98\xd6j\xa0\x11\xa4\xd0\xd6\xebET\x95\x834\x0f\x82\xd4M\xb8\xed\x81)\xfd\x0bM\xc9\xfa2\x96\\q\xbc\xcb\xae\xb7\x8a\xf6e&\x9d<\x08j\xdf\x1e\x93\xc9\xec\x8cg\x8e[k\xf5\xe0 \x88B4\xaf\xad!\xed\x84\xd4J\xf7\x9d\xc1\x80'\xc7\\\x8dn2\xabN\xc8^c\xadcr(l\x81\xb5\xea\xbc\xc6\xa7\x1fG\x9b>3\xe97\x99e\xdc\xc0I\xd3u\xf9XZ\xdc\xf6g\xcc?+\xafj\x95\x7fw'\xbb>\xde\xe8Tb\xfd\xdb\xae\xc5\xceR\xa5\xde\x1e\xf1\x97\x1bE=?\xe0bI\xaa\xfb\x9c9\xbd\x80g\x0b\xacu\x0c\xfeB`\x8f\xa7{Y\x14\x0b\xb8\xfa\x13\x15\x08\x9cd \x9a=6\xf4JW\xb3\xafV\xe8A\xf0;J\x00\xbf\xdf\x1a%\x18\xfa^CV8\xa0\x01{\x9c\xc7K\x90\x8d\xb3\xa1=I\x0b\xf8\x0c\xa0\x93\xd0\x02\x01m\xba\xd2\x9bB\"\x88\xf8Sb\x05\xf1\xdb\x90DC\x0cE\x90\x8brw\xe2\xdf\xd0\xa2|\xabQ!\"k\x19\x94c-\xd9b\x8b< k\x86%\x93\xf1\xbe\xf4\x12;\x12NAe\xc0\xb6*C\xe8\x9b\xa9\xcc\xf5\x1a{\xb6\xe1\xd89\xf3C\xe65\xbb>z(\xedG;\xefL\xd2\xf6\xf5u\x83W\x1b\xec\xa4\x7f\xa2\x83\x1c\x1e\x0d2F\xdc)L :\xc8\xa9\xa85\xb1'\xa6z\x0b\xd8w\xd9\xdc4}0\x99\xd4Q\xbe\xe5\xd2\n\xa3\x90\x0b\x02=mT\xad\xa0\xea~\x98O\x91hob =\x84^\x10\xb9{0\x86\xae\xf9\xe8F\xc11\xf9(\xa5\xfc\xde\xd8\xd6\xf3\xda%t\x0cW\x8c\x0c%\xd7K\\\xc1\\\xca8u\x88=\x11\x97\xbf0\xa7J\xb3\xc3\xa0\xf6yl\xfd\xf3\xfc4\x0e\x9c\xc3\x05\xe9}\xacv\xd1\xf2nG\xf9\xd7`9+1\xc7\x9a\x14J/\x86\x19v\x8d\xc2\xf3;\xb6\xf3\xe2\xd8\xce$T\xf4\xfc\xb1\x1d\x0dK|jZ\xc9\xa9\xa8R\x16\xa1Z\xfb\x89\x13\xc7<\xa9u\xd2{!\xd8S\x1c\xc4vI\x85\xfe\x1d&}}\x98\xd4\x93\x8b\xfeU#\x93\xea\xe5+\xc5\xa5\x8e\xfe&\x98?\xcd\x91Y\x1af\xabF|.\x19t\xeaQp\xd2\x82f\xfc s\x12\xee\xb4*\xb7\xec2\xb5\x936\x1d}\xf1\xc6}\xd1\x02j\xb9r\x86\x8c\xa1j\xaa3Tw\xa1Ws\x80(\xdb\xd4\xe6\xab/z\xb0dV6(-\xc7b\xe9b\x08\x85lo\x81\xeb\xe8\xcc\xba\x17 \xd4jB\x00\xa7<02\x15&\xfc\xb5\xc0\xf8\xcc(\x0f2?\x96V\xa7\xeb\xad\x96\xf4\x0bo\x89S \xaf\xf6j\xb3\xac\xaa\xa3\x17Q\xa4\xedZ/~\xf5\xef\x1bC\x13\x9e_\xa9Q\x0f\x0d^\x16\x1d4\x14\x06\xedF\xafj}\xb9\xa4hte\x14g\x87\xb2\xdd\xfa\xe2\x91\x1e\xab\xdc\x17\xd8?\xf9<\x12{\xcd\xfe\xbd-\xb3u!\xc8\x17\x15\xfa\xc4\x81jt\x0f)Q\x16+\xf9\xab\xad\xa8\x17\xaa1\xab\xac\xc6\xb6\x86\xe5 \x97\x86N8\xe0\xc6?\x05\xfei-/P\x94\xbdV?\xdd(V\"n\xfdt\xd5\x80Z\xf6d\xd6w\xbb\xacu\xecX\xab\xa3DWA\xf6\xaaq\xca\xd3\x054|\x99\x012}R\x1a\xa2 Y1\x91m\x999\xb7)}\xfd\xddnQ\xe8\xb7\xc9\xc2\n|92\x87\xac\xfe\xd5\xa3T\xbd\xd7\xa8\xda\xab\x86\x93BM\xcb\xd4\x81\x9e\x99\n\x8a\x95\x9b\x9a\x18\xf2\xc9'\x91\x1a\x08\x9e\xd6m7\x93\x83p\n*\xe3K\xab\x02\x84\xd7+N3\x939\xc9\x80g3\x80Ei\x83\xf3\xb43\xe1\xa5\x1b\x01\x8f\xd8k\xcc\x9f\xce\xd0\xaf\x7f\xc6\xb7\x06\xe8\n\xb7\xfb\x91\xdd}\x9e\xe0~\xd3\xa4\xc4\xe7\x9a\xf6\x04=\xd4\x93\x97\xe5\xba\x103\x04\x81!\x13\x0f\xbbS\xd3l\x17\xdc\x1a\x12[\x88>\xc2\xff\xeaR\x8f\x85\xd0`.\xd8\x9a':A\xe8g\xbfe\xc1\x9f\x91\xb9\xb2\x17\xc2\xec\xd9d\x86\xcf\x9e\x83\xe9\xb3)\x88\xab\xf3e\xf4\x00\xe8 X`\xad0\x8ab\x1e\xf2\x84\x85Q\xc2\xfb\x9fCe\xd5e\xb0\xce\xb6\xd1\x8c\x98c\xf3\x04\x9d;\xf4\x03/\xe1\x96\x90\xeeIK\x0e\x9a\xbc}U'\x9a\x8d\x86\xdc\x1f\x0c\xe5c\x13ymR\x18\xf1\xebE\x89\xc7\x93\x05eUj\x10H\x9cd\xe0\x87\x0b\xac\xe1\xa1\x92\xd8\xf1\x95\xfa\xf2O\xc9\x04\xb0\x1ee\x8b\xa1?r2\xee} \xc9_\xdfN\x17'\xccO7\xc4Y\xf5\x1a\x84\xc2\xb1\x8e\x19,\x1fL\x85\xf0\x82\xb1\xd4\xe2v\x18\xa5n\xe2\xc7\x99\xbe\x00\x98@6\xef\xda\xce\xc1oO\xe5Q\xab=I\xdb\xd1\x0b8I\xdb\xa9'\x11\xac\xb41\xec5p:\x0e\x95\x8f1,\xfc\xc4\x9dI:F\xe3!\xe8by\xb3\xe3\xc5\x8b\xa6z\x15,\xa2\xa9\x1a\xc6\x82v\x00d\xec\x9b\xe1\xffK\x9dp\xbcZ'\x1c\xcf\xe6j\xe3\xeb*6\x1f\x1c\xcf\xe6j\x93+\x8057\xa2gs\xb5 \x14\x80\xe4\xecw\x15\xe0\xf4+\xa71\xa8\xaf@sd`\xb1\x86\xd8\xfdt\xbc\xaf\xc7OG\xffE\xb4\x91\xe7\xa5\xf5E\xfcQ\xd2\xb5\xa5 \xc1d\xbc\xd6\x8c5!\xee(\xa8\xc4\x1d\xb9\xe0\x15\xe4B\xdc\x91{\xf4h\x87\x05\xd7\xdd\xaaW\x90k\xb9\xe0SK)\xa8\x866\x99\xe5\x84\x11\x81\xdf\x19aF\x115\x9b\xd5\xc5\x1c\x052\xe6(\x99\x19\xf0\xecR\xe4\xf1@HO\x13E\xec\xd2\xf8\x94\x17?7^\xfc\xad\xdf;^z\x15\xfbxKf\x93+2\x87\xfd\xe1\xcc\x1f\xfc\xde\x0f\xca%~p\xfcx\x97\xb5\xa4\x05\xc0\xd6\x96k\xd2\xd8\x1eO\xdd!\x1f9\xa4\xc9\x9aB\xbaQ\xd0\xca\xc8\x14\xee\xaaIo\xf1\xfe\xb6\xac\xf2<\x93N\x14[\xab\xbc\xbf;\xd3\xf7C\xafx\xde\xdbf!\xb8\xdb\x85\x9c\x14\x84\xa1'\xc4 \xa5V8H\xad\xc2\x81\xf3<\xc2\xc1\xd7\xca\x18Uj!\xb9=\xcdJ:\x9f\x98\xff\x94)2\xca\xa7}\xf9\xd8\x81\xc2r\x83\xebK\xe5\xb2T\xc2o\xe7~\xd2\xc4\x99SY.l4\xd2\xb9\x8a\xcbo\xf1~}\xa1\xbe\x99\xc3f\xeds\xf9L\x11`>\xa3nz\x9b\x8d\x832\x8dd\xbb\x05\xecN\x9e\xe4V\x83\xb9b\x08\xa5%\x95\x9aXx\x0c\x857\x13\x7f\xe4g\xfe\x98O\xac0bgX+\x92#i\xd0\x1e\x06\x82\x04\xc2\xab\x902)\xd0\xef\xff~\xc2\xfbuna2 \xa9|\xccx\x00\xe1\x0f\x1a\x07\xcbt\xab=\x10\xb4\xec\x88S\x14sJ\xc5\xccIo\xa7P\xcc\xb8\xa3\x04\xb5\xd6\xdcI\xa1~\xe5[\xa2\x91\x18\x06\x93\xff\x7f,\xf3\xb3\x80\xd7Z<_`\x7f\xd0\xd3\xcd\x9b\x19?\xc8j\xfb\x8b\x05_\x10\xbc\xa8\xb6c\x7f4h\xec7M\xdc\x05\x16\xb6O\xce\xcd5!\x95V/\xe7g\xe3\x83\x86\x8d\xdf\xf7\xbdl8\xb9\xd8Du\x96\x19\x15t\x8d\xf7E\xbfs|4\xe9\xa5=\x95\xbcL\x92\xc2\xc0\x11\xd8<\xa1F/\xca\xb2h\xb4\xc0Zb\xb0\xb5%k\xe2_\xea\\G\x04\x15=\x94\x89\x1a\xfctcq\xfbD\xbbS:\x07\x1e\x8f\x13\xeeJ\xcd\xad\xa6z\xba\xef\xcbL\x84\xae1:J\xbe\xe9\n\xa5\x8c-\xb0#G\x06]y\x06\xcb\xa7+;\x8c9\xbc\x997j2\xf9\xb8N\xca\xcd\xd9]h\\\x99 \x87\xc7\xa3\xb6\xa1\xc6\xe6\x18Bo5\x86\xc6:\xcfelb*\xc0N\x90\xdc\x05\xd6@\x9d\xf5\xaf\xe0F\x8d\xf7)\xfa\x07\\\xa6\xf1\xa12\xfd\x0b\xe5\x14\xa7xL\xbf\xc0\x85\x05v8\xb9\xb8d;\x0b\xccm^\xb4\xa6\xcc\xb1\xb0\xff\x8e\xe0\x0b_n\xfb\x87_r\xfba\x08/v\xf7\xff\xf1m\xa8\x96I\xea\x1e\x8b\xd3\xbf)\xf6T\xbd\xf8X\xbf\xa9P,\xccG=\x9eL,\xe6\x87\x19\x1fLQ\xae\x17E\x01w\xc2\x86rZ\x03\xfc2\xc86\xfe\x92vh\xa6\x91C\xc9\xa9\x13\xef\x02\xd9\x7f\xe9\xd8d\x85O\x8c\xe7\xac\xb5\x0c\x95\xb0s(\xb7d\xe70\xe6\xd4,\xa4\xd7\xa8o\xf6YZ\xa2\xb9w\xc9\x89\xa5Lm\x93\xd0\xab\x1b\x17\x9b\xaaB\x97i\xae\xa46o\xca*\x15\x95\xa3\\\x0b8Um=\xd8\xcd\xa28\x1c\xc4j\x99\x92\x88?\xa9\xa8\xa2\xf1E!q\xc4\xaaE\x8a}n*\xc5\x0fbG(\xac\xb1`\x87EA \x00hx\xd3\x14*\xf1VS.\xf0\xd3\xf2\xc2\x14\xa8Q\x8d\xa6\x87L\xa5\xbf]\xfb\x9e\x18Q\xea\x08\xdd\xfd\x8e\x0c\x90\n\xa8\xc1/\xb7Y\xd6\x84\xe6\xda\xce\xc1J\xd6\x95EN\xce\x9d\xea\xd8\x8c\x7f\xb2\xd0\xec)\xab\xfdO\xc2\xe6N\xd8\x0dm\xf9\xd7kh36\xb0\x19\xc7\xf3.D\xd1^\xbb\xd5\xe3\xfd(\xe1\xdbjy\x14\xd9M\x1b\xd3:\x9a{\xe6a\xc2\xfb0\xcc\x94g\x8bY\x96\xf8\xbd<\xe3m!\x80\xb7\xba\xf6\xdb\xbfN\xb74LlzM\xa7q\x89;\xfe\x87\xd7\x17\x8f]\xfbA:{\xec\xf4\x91\xd7~0s\xe3\xe8\xef\x1f\x1f\xa8d\xc5Ug8\xba\xda\xf5i\x98\x8a\x85\xd1\x88\"\xf0\x94\xae\xf5\xe2\xf2\xf2\xcd\xc5\x9d\x9d\xad\x05v\xbd\x05\x97\xe8\xadj\x86P\x92\xda\x82\xd5\xe6c\xc2C).\x11\xd3(O\\\x8bE\x00\xee\x19\x1a\xfc\x89\xfcBm8s\x06\xee\x0eZ\xd2w\xbc*B\x08\x95;mgE\xd6\xe6\xa4N{\xac\xbb\x94\xach\xabN\xb2\xe7E\xfbaU\xa4\xbbK\x0d\xac\x10\xbbq\x86\x85|\xbf\xb0c\xd6\x08\x8f\xc3l\x14\x88clg}\xd9a\x1c\x0d\x12'\x1e\xf2\xa4\xbeP/\xe1\xce^Z\x0f\x0f\xfcp\xcf\xef\x1f6\x17\xd8\x91\x9b\xbc\xc0Z7{\x81\x13\xeeY\xd2\xa8w\xd4EK;\xb3(\xd0\xae\xcc\x12\x96\xa3\x850w\xff\xafI\x15\x05\xf8\x9fq\x8d\x91\xe3\x8aa\x7fJ\x86\xa6\x01\x04\xb1FN \xd6\xeb\xd9Gx\xd7\x17/m.\xb0\xd6K\xa4|l\xf9\xba\x18J\xccy\xfc\xe7\xb84|\xbf\xf7!\xfd\xae@\x8f\x7fNA\x00\xf8K\nH\x83H>)\xf1\xec\xf1_P\xe0X\x02\xfe\x1b\x02\x90\xb3\xbbGvDz\xa6\xb6\x9e=z\x9f\x02d\x94\xac\xb5\xca(\x85\xf9`,\x02\x90\xe3\xc8\x16?\xb2\x03{\x12\xf8\xd8\x0e\x94\x07\xf2\xd1\x13;P\xf6\xf9\xe8\xa9\x1d\x08\xb3\xf8\x1b;P\xe2\xfc\xa3\x7fm\x07\xca\x85y\xf4?\xda\x81\x12#\x1f\xfd\x1b\nL2\xb9\x02\xbf\xb2A\xc6r\x8e\x0f\x08]\x01\x18L\xe3\xaf(0\x05\xfc\xbfGhE8HEo\x9f\xfc\x84\x02\xee8\x89\xc0\xe7g\xff\xfc?`T\x8c\x06\xd2\xee\xfa)9\xd0\x1a\x80[[\x8c\xe2>\x1c\xf5\x7fO\xaa(\xc8\xcf\xff%\x86\x88S\xf0\xec\xfe=\xf2Y\x10>\x89\x88d\xe9bID\x1fcJ\xe6\x00F\xdf\x7f@\xbe\xfbr\xc1\xee?$\x80(]`\xado\xe3Y\xc4qpxN1#+\xa9s\xe28\x89\x0ej\xc6-@\xfc\xb6u$\x8b\x89\xf4\xac\xb2l\x83\x06|\x80k\xa4.\x10\xcf\x7fI\x0e\xb1\x81\xfco\xa4N\xea\x0f\xe4\xc0\xef\xff\x8cT\x12X\xf0\x07\xe4\xeb\xe1\xa8f\x17\x04DM\xe6\x9f\xe3n2?\xf0$\x8d&L\xd1@\xfe\x07\\'\x17\x02G\xeb\x13\x82Q\xea;!!\xfbn\x14\xfa!\x1c\x14\xcc2\x9d}\x05\xf9\x08S\xf5\x9e\xe3\xee\xb9\x11\xd0\xab\xfb\xefZ\x80Z\xcf\xee\xbdG\xa0\x89\xa4\xbaO1}\xef9\xc9\x98\xcb\xb1<\xc0\xfd\x9du\x92}.1\xfb]\xcc\xbb{\x05\x08\xa3\x1a\x80\x80dS`/\xd9\x13\x80?%\xf3\xee%{\x99\x06\x92%\xab]\xeb\xb3 s\x90\xfd\x81\xcf\x98\xe7\xf6\xbc\xdby$\x97\x1dK\n=\xee:y*W\x0e\x8f\xec\xac\x04q+\xac\xd7\x08\x1b\xc5\xd9\xa1\\\xf4G\x98\x92\xf4\x04~X\x91\x83'a\x94\x8b:oc>qV\x82\x82\xc0Ok\xc0\x99\x9430\xf9\xeb\xa9\xef\xff\x0b\xfd\x0e\xa2\x0c\x1dB\xb6\xcf9\x1co\xd2\x89\x96\xb4\xc8\xbej\x00f6=\x7f\xe0\x02\x05~\x88\x05O\x01\x02\xd1\xf3\xd9/0 \x16\xb0\x1c\xaa\xe1\xc3\xdf\xf3\x07\x91\x17\xc1\xb9\xc4\xb2\x93\x80\xc5\x01l\xe4GX~\x12\xc0\xcc\x1fq\x80ZF\x93\xdeV}~D\xd0\xdd\x1f\xa4\x99#\xb9\xc5_\x90\xa9\xfb\x83,\xf1\xa5,\"\xf4&Q\xe6=rr\x8b2\xd0\xc3{\x98\xd6\xf4\xfcAnF\x8e\xa9W\xcf\x1f\xa83\xfa\xd02)s\xda\x1e\x92\xe5\xd8s\x92h_\x80\xde\xc7\xd4\xa2\x178\xee^\x10\xdd\xe1J\xb8\xfa\x10\xcb,\xb2@z;w\x12 \x7f\x0f\x0b<\x12\xae'%K`5\xa1R\xc2,\x0d\x968*\xa5\x02\xb8\xb5}\xf6\x0b\xb2;\xe5R\x89\xbaT~\xf6\x1e\x96\x02\xa4\xae- \xff\x023\x86^\xb077/\xeb\x90\x03\x12\xec\xcd\x9d\x94\x10BE\x82\xbd\x13\x00\xc1\xc2\xb2LO !\x98\xa1\xf5B\xb1\x18g\x9e\xfd\x183\xda^\xc8o\xe7\xbe$\x07\xf7\xff\xda\x02^\x07\x94~\x8a%\xc0^\x08\x80w\xb1\xbau\xd6\xc8B\xff\x07\xaebd!2nh\xeb\x01\xe9]_i\xdb@\xfb\x99\x0f\xe8E\xe6\x1a\x1d\xf4@J\xf9\xf0>\x05-\xaf \xc8\xcf\x7fa\x81\x04\x12\x82YT/:\xf0\xa0\x0eV4\x04D\xd6\xf9\x19^\x04\xd1\xda\x96\xac\x83%\x11\x01\x91\x07\xd6\xb2\x08\x07\x1e\xd4!\xa8\x10\x1dx\xb2\xce\xcf\x08O\x8f\x0e.\xc8*\x96\x01H2\xfa3r\xf6\xa2\x83\x0b\xcb\xb2\nVo\x05D\xb2\xce\x9fciD4\x06u\xe8.\x1c\x0ce\x9d\x9fa\x92,Z\xdb\x95u\xb0\xbe\" \x92\x95\xfc\x9c\xf0\xfc\xe8`\x08u\xb0\x02$ \xb2\xce\xcf\xc8i\x8e\x0eF~\x08\x04\xea\x01\xa1\xf2\xd1\x81&^\x0f\x08k\x8d\x0e\x0c\xd5}\x80\x15\xb5^t\xb0\x0b{\x8e\x95\x0d\x01\x01<\xc1\x82i/:\xc8\xa1\xce\x7fk\x81\x00\x9e`\xa5S\xb4\x06{\x8e\xb5N\x01\x01<\xf9\xa5\xa55\xa8ci-\x07<\xb1`\xddeY\x85\xd0\x92\xe8@\x9e\xfd\x9f\x11\xca\x16\x1d\\\x06\xd4\xb2\xec\xece\x89[?'\xb49:\x18C\x1dB\x95\xa3\x831\xe0#V\xb6Dk\xb0j\x844F\x07\x97a\xa5\xb1V'Z\x83:XA\x11\x10Xi\x0b\x0e_\x86U\xb3\xec\xf5eXi\x0b\xfa\x8c\xa1\x8e\x05y\xc6\xb0\xd2\x04\x0b\xeae\xe8\xb3\xca\x98\xf6k\xb2o\xf5\x80qO\xb2\xf7\x8f\xf1a=\x0bZ\x10\x95\xb7zF=\xfa\xdf \x84\x8f\x84p\xf7\xec\xad?#\x90:\xc9>Us!R}/\x8d\xc4:\xff\xe0\x07\x96\xefR\x85\xff\x90\xc8#i\x14\x0c\xd3\\\x02\x7fEHv\x1e\xc8m{\x93lu\x1e@j1\x1bH)o\x7fj\x01HM\xf9 \xb6L\x08\x08\xe8\xcax \xce\xe6F\xdf\xb35\xa7@\xb8\xd6\x92\xb6E~\x8a%3\xd7@~J\xea\x80\xfc\x88\x89\xbc\x12G\xefar\xe9:\xb16ta\xf9\xcbu\xe2^\xa2d\xc3\xc7\x98\xd5\xb9N\xac\x9a|\x8c\xf5\x7f\x01R\xb5\xf0\xe8\\'VB\xecc\xcc9\x96\x9c\xd8\xcf\x9c`\xd9\xef\xf7y\xc2\xc3\xccw\x02\xc9\x14~\x82w\xdaubPY\x1e\xff\xe7\x7f\x8f\x1bq\x9d\x04\xb6\xf3-,1\xbaN\"\x15\xd3_\xd3\x05;\x0c\xf8!h\x17X\nqu_\x8f1\x82.\xe9\xf6>\xc5<\xd35\x10Z\x87{\xbe\xd4\xc7\xc9\xb2\x18\x08\xe6YKJW\xf8\x14\xa3\xb4\xab\x01xc\x96J\xaa=V\xc0\\7W\xf3\xa1\xa3\xce\xe34\x95\xc7\xf41f\xf6K\xb0e\x9fb\xb3\x8b\xab\xbe\x93\xfdW\x93\xf9\x18\xcb\xa9K\x02\x1086\x90[R\x1b\xb1\xce\xe6J\x7f\x86\xd6\xc7\xf8\x84.\xf10\xe3\xc9\xb2\x1c\xc4\xc7\x98\x1c\xb9\x12\xe8\xd9\x81K\xfd\xc4\xbe\xdfZ\x9f\xc3D|\xe9\x02\xa8\xd6x{\xdc\xa1\xfc\xfe\x0fdC\x87\x1c$\xe5\xbf\xc4b\x98\x84\x8c\x9c\xc4\x0e]\x1a\n\x12\xfa9\xedF\xaa\xcd\xa4\x17\xb0\xe4\xfd\x82l\x00\xa0\xc6\xaf \xd5\xf0\x13W\x91\x1a,\x9f\nP\xc0\x9d$\x89\xf6\xb56\xf2\xce\xffY_\xc6\xe8\"\xef\xfc_\xd6B\x1eX\xc4\x9e=\xc0\xb2\x8a\x02k\x0d\xf8\x01\x96K\x14\xdcS\x06\x9d\x07X>Z\x92\xf0e%\xd0c\xd9E\xd5\x16L\xf5cL\x9c\x15l[T\xfcs|\x9a\xa0\xd9KF\xd2\xc3B:\xc07\xb5\xb0\x87%u\x00\xef\x18y\xcf\xb2\xba\x92c|\x88\xb5z\xd7\x07=\xd3\xb6\x1f}}\x8c?\xc2\x07\xd2\xf5\x93\x11\xd8^\x9fb\x0b\x82\xeb'\xa9B\x8b\x0f\xb1\xcc\xb5$\xd4\xb7}?\xe5KQ\x98Ey\xb2\x1af|\x908\x923\xde\xc3\x87n)\x88R\xbe\x94'\xc1\xe1r\x94\xf7\x02\xfez\x1ee w\x90-1%\x8b2dc\x82\xbc'\x97\xe6\x97X\x0c\x93\x90\xdc\xcf\xac\xc0\xa5\x08\xac\x89\xcf\xee\x91\xe3\xad \x0b\xb6\x1ap\x03\x83Ey\xd7\x80\x88\xfd\x16@\xb7k`\xa3\x91 Y]\xdbw1\xec\xff\x8a\x02\x80\xd5\x12\x16\x14\x8d\xe2>L\x07Kb\xae|\x19a\xc4\x15\xdd\xb6\xd5\x0c\xf8\x01`\xd7\xdbx_\x8d\x99\x90p\xca(\x1chv\x8bI\xddR\x14\x0e\x92\\ux\x1f\x0b\xbaK\x05\x0f!\x18V\x80\xf0\x11\xb3\xe1\x15-#\xb5t\xdb,\xb4\xfaNw N\"\xb8\xd6\"\xacI\x82r7\xb3C76\xaf\nR@d\x9e(>\xac\xfb\x9e\x02g\xc0\xe7q)\xca\x05?i%\xa2e\xa6\x90\xec!\x99M\xee9I\"W\xe7}26 \x93\xeb\xf3>^\x1f7\xe7\xb1\x84<$s\xcdy*9\xc7C\xacM\xb9y\xa0\x97\x1b\xdbv\x01$\xa7\xf5>\xd6A\x96\x94\xbd\x95\xf0i\xf8~\x0f\xab\x9an.\x84b%\xf9\x126\x92\xc7J\xfe&\xd7:nn\xe4e\xc2\x96s#/\x13\x11+\xd7\xf2\xf2\x03K\x83\x11\\\xe4\x91c\xaf\x84\xbc{O,\x02rn\x90\x92\x90T \x92\"\xe0\xfbX\x8dv\x05y\xe7\xb7\xe3\x84\xbb5\xdb\"\xe1i\xee\xd6mN\x12\x1cjc.\xd6\x80$\xb00\xe7\x12\\\xcd\x93D\x1a\xe6?\xc6J\xb7\x9b'c$\xb3\xd0\xad\xd7E\n\x91\x85N\xbc~d\xea\xba\x87\x0e\xaa|\x83F\x04V}\x83v\x0f_\xc5\xb8\x87\x81\x9b \xda\xf3\xec]L\x90\x97e\xaep\x01z\x13Sc\xaf\x00a\xc1\xd4s\x02}\xa3\x81\x0f\xd8\xb2\xdeh\xd2\xdc\"\x00~\x8aq\xde\xd35(\x00\xc4\xb171QXv\xd2!\\\xb0\xe1\xbd\xf14\xe4\x01f\xea^\xc9>\x8f\x97\xd5\xeb\x05\xd2\xd3\xe0\xd7X\xc8X6Z\x15\xde#\xcf@pc\xcb \xb3cv\xe2\xc1g,\x1e,\xdb\xb5M\xf0\xf5\xf8 >\xb3\x9e\xd7\xb0]z\x1d\x7f\x8a\x8f\xf3\xf2r\x94%\x0e\x984\xdf\xc7\x94\xd7\xf3\xa2,\x05!\xe41FQ\x8f\x0b\x0e\xff1\xd6\xe7\x969p\x1e\xac\x18,\xf3\x00\xae\xbf\xc8\xdc5\x00\xcf\xde+\xe9_\x18i\xbd\xbe\x9f\xc2\xd1\xf9\x00\xbb\xe0,k\x85 \x8f\xc0\xd3\x00\xb28\x17\xe0B\xe9\x03l\xeb\xf5\x86\x0ep\x8a\x9fb!Y@`=\xb1\xcc\xb0\xec;n\xe2g\xbe\xeb\x04\x8bun[\xa52\xa06\xfc\x1a\x0b\xa7\x95\x12B\xd6\xd5mQ,,J\x9eW\x9eT?\xac/\xb2\xa3\xae\xeb\x7f\x8d\x8dx\x9e\xefH2\xfb\x10[\\\x96}g\x14\x815\x86\xc0\xbc\xc90#Gcs\x9e\x80\xa75\x10\xb9h\xd8 N\xad0\xe4\x00\xf8\x03\x07\x04\xe3\xdf\xe0U\xf2\xfc\xd4\x97b\xeeCL\x18=y\x13\xf4 \xc1n\x7f\xec\x83c\x83\x1d\x12\x85\xc6\x94\xfe\x90 \x9a?\x8e\xc2\x03+h\xf9\"\x9ct\x8c5\xde-P\xda\xb1\x1c\xe3\x05n\x94\xc8\x81\xbf\x8b\xf9\x9b\x17\xb8\x89|b\xe0\xd9\xbb\x98\x0f{Q\x10H\x94\xfe}\xdc\xbd\xb9\xa9\xc2:\xb2gD]\xacH*c\x06\xde\x0e\xaf\x06q\xa3Li\xc2?&(\x16eJ\x9f\xc1$[B\x94Pq\x1f\xd3\xa0\xe5([\xb9\x9d\x83>8+:f\x01S\x0c\xae\x01\xd8Z\xc1\xb5\x9d\xf4\xd9}\x8c\x1f+\xb0hX\x0d\xe5\xb0fX\xca\xe1\xcbJ\xd2 \xaa\xc9\x8a\xba\x05\xc2\x83\xd5Fz\"cpU\x01\x1fR8\x9f?\xc1R\x1c\xef\xeb\x860cZ\xd1:\x066\xc3p\x0d\xc07FR\x8bz\xf6\x04o\xc5\x8a \x8b -\x19\x08fy| \x89\xf7\x132\xedA\xaa\x8e\xca\x13l\xe4\x05e\xed \x96\xe2VJ\x86_\xd2\x7f\xe0\x87\x19OdW\x7f\x86 \x13\x87K\xed\xb71\x93\xe2\x01\x0c\x0d\xef8\x0f\xcc\xd0\xf0\xda\xaf\xe8\xe8\x0b\xbc\xc6\\\x03H'B_\x94c\xc6\x04IBR\xb8\x86%@\x99ky{\xe4\x04\xc1\xb6\x91\x08\x7f\x81\xe5\xe3B\x17\xb5\xd7\xbf\xcc\x13\xdc\xc6{\xd8Y\x84\x8fRI{\xdf\xc4\x9cS\x00\xe6NH\x10V\xa3$H\xba\xbe\xbdI\xfa]?\xbf\xc0Z\x9f\x91\x83'-\xef\x9f\xe1\x0b8\x1e\xaa\xce1G^\xd1.\xfe\x0474\x80`\x87\xd1\"\xb0M\x8e\x1b-\x82\xe0`\x0cT\xf4!\xc1\x80\xd8IR\xe0\n\xd8*\xc3\xb5\xf4\xfe\x18Sx\xe5\xb4\xfb9&\xd6+\xc6\xd9\xfbs\xda\x8f\x01\xe1Z\x02$\xb6\xf67\x04p[_\n\x12\xba\xc7o\xd7\x931~[y\x97\xdc\xc7k\xcdo\xa7\x81\x13f\x83,\xb1\x1fT\x00\x07<\xb5\x9f\x16\xa3\x07=\xa6#\xcd\x1dy\xc4\xce\xd8\xaah\xad\xdf6\xa0\x9c\xc3\xb5\xe8}\xcc\x92Vn\xe7~\xe0\xf7\x12?\x97s\xf9)\x16\x18JN\x946\x08\xd8\xae\x1ec\xa5\x81\xdf\x1e\x17\x1b\x8e\xa5h\xaeY\xe0\x07d\xc3\x13Mq\xf1\xa1_\xd1nA\xd8\x10\xc55\x00\xf3m\xaeI\x0e\xd1&W\xd4\xbe=\xc6\xd7&\xbcnCW\xc0tE\xf8\x06|&|i\xe7\x82\xa0\xdb\xb8[\xb0\x96~\x82'\xb0\xa2\"%\xc8IV\xdf y\xc9\x13\xe9R\xff'\xd8A\x8a\x1f\xb8\xa2\xc2\x11\xf2\xd9\x87\xad\xbf\x87\xe9\xd1\x8a\x80\xa4V\x10?\x88\xb9\x9b9:^\x86\xac\xfa\xca\x01${\xf0\x9d@^/S\xdeY\x14\xb03\xd7\xbe\x13\x04\xbe\xbc$T\x96G\xc2d\xcf\x81\x98\x80\xa5\xe6>\x88 \x98\x82\xf6\xf9Hu\xf5K|\xf3\xd0\xef\xfb\x10\xf8\xf8\x9f\xff\x06\xcf\xb3\xdf\xd7\x10Z)\xd0 \xdc\xd59\xcd\xe4\xb1\x9c\xd6\xd7\x00L\xe2\x8a\x01`5\xe2\x9c\x1f\x04\xdc\xc3l \x13\\(ec>X\xec\xea\xdf\x82\x9e\xfa\xb70 p\xc0B\x87\xc5\xaeb\x9e\x18\xeb\xfbA\x16J\xf4x\x0f\x9f\xd3~\x18 \x06\xf0\x9f\xc8\x96\x19\x96\x81\xf5\xb3\xbea\x19\xf8\x10\x9d\x8b\x92E\x10'\xee\x91=\x88\x12\xa7\x1e$\xfdX\x1eb\xc3\x87\x00\xc0\xbd\x00\xe6g\xe7\xa2<\xf1y\x92%p\x0bL\xe6\x14;I\xa6\xfd\x1e\xb0\x10\xdaO\x1cW\xba\xb3\x7fL&& \x92\xa9\xff\x04\xd3, \x12L\xfdc\xbc\x9f\x12rJV\xc2\xc4_\x82^\x96 <\x01 zE\x82\xb0\xe0.@\xf30\n\xb2 \x02\x04}aF$@\xd2\xe1\xfec\xac(I\x08T\xc2\xfb%A0\nl\xfa\x13\xa0\x93P\x0bK\x19\x02t\n\xa6\x85e` \x82\x06\xb1=W\x80\xbe\x03 l\x13\xe8'\x0e\xb0\x97\xb7\x08%HT\xe8\xc3\xbbX\x08?\xa7y\x05\xd9{\xa3\xfbb\x81p\xa0U\xaf\xff\x07\xf3\xe2\xf3\xca\x08\xfd9\xdevm\x9d\xfe\x1c\xb3\x17Y\xc3\x13\x12\x08^\xb8\x81\x81\xe0\x15\x18\xc0\xcd\xed\x13l\x970\xa2\xc9\x13L\xd6\x00$\xf9\xfb\x13L\x8e\x15\x0c\xe6\x8a\x91~\xc0S5Yz\xf3.`0\xc8'\x988\x9c\xd7\x1c\x0b\xab\x17\x03\x0d\xc0\xec\xf7\xbcTd\x1fb\xda4\x00? ,\xac\x0c\x065\xc5\xfd\x11l\xce\xdbXx:\xaf\xaeN0\xa7\x1e\xa8\xab\x13\x82qpc\x80\x9b\x19Hg\xcfgO\xc8\x1e\x83\xbc\xf2\x04s\xaeApK~\xc7\xd3\x1d\x84\xea\x00\x92\x05\n\x8b\x98a\x0b\x10\x10\x98\xec\xc5\x9ckud]\x96U}\xaf\x82\xcf\xb4\xaf\x01X\xc6\xf0G\x0eh^\xb6\xb6\x06~\xe8$\x87\xab\xf6\xd5\x199\x83@\x9d\xe8\xb71j\x0b`\xec@\xca$\xbaw#\x99\xc5\xb4\xf5)\xd6\xd4\xfd\x91\xb4<={\x80Y\xb8?\x8a\xa5\xc3\xec\x7f\xc2\xf8\xb4:\x8a\x03\x1f\xd4\x1f\xe2`\xe2\x87l\xc1v\xf9\xe5\x87\xae2\xb0\xbd\x8d\xafc\xcc\xde\xdd\xc3\x8a\xb7\x84\xa8\xd0\xfd\x0f\xb1\xbe\xec\x87*\x87\x06\x99\xd1\xaa\xc2\x12\x82q\xea;\xd9\x8d0s\x81\xc6<\xc0B\x9c\xca\x08\x0d\xb1\x1a\x98\x81V\x9c\x97,\x8d\xf2\xa4\xae\xd9Uy\x11\xc8M\xf6$\x92X\xc4\x0f\xb3\xc0I\x86\xd2 \xf7\x11\x16\xda\xfc0\xd3A\x14\x1fa!q5\x1c\xfb\xa9/\x1d\xac\xc0fb![\xba\x88\x89qz\x0bK\xe5\xab\x1b@I\xb0m\xd5\x8f@\xf4!X\xabo\xbc0\xc1\xf35\x00\xdf%\xac\x1a\xae\x86\xf9\x92o \xd8\xac\xb5\n'\xf9s\xcc\x07\xd5 \xff\x1c\x0b\x16~\xed*\xf9Z\xca\xfe\x18\xb3\xf9U\xcd\x15\xc9\xe12\\\x11k?\xdaC\x92\xe2|\xea\x87Z\xf0&49\xf5A\xc8}HF\x9d\xfa`#~\x88\xbd_%DZb\x1fb\xca$@c\xfb 2\xfb\x0e\xeb\xfcS\x9f\xe2\xcbp\xdf@\x08\xc1\xcc\xf7\x00-\xb0\xee\xe1+\xc0?`s\xe8\xaa\xbaq\xc1\xac\xdbW\xdf1V\\\xd4\")\x9e\xfa-\x0d\xc0\xeb\xa8l\x1b\x18%\xc0\xb4\xf1\xf7xm/j\x06\x86y\xff-\x0d\xc02\xca-E6\xff_L\x1d/\x1a4\xc5\x87\xe4\x96\x81`}\xea\xa2\xc1!,\x94\xde2\x10\x8c\x90\x17S\x9e\xc0d\xf0\xce\xde\xd2\x90\x7f\xc0\xf2\xc4E\xbdQ\xd8\xa6uKo\x14\xe6\xf8\xdfw\xe2X\x9e!|\xe6\xf64\x00\x930 \x90\x97\xbfX<\xf9\xbe1\x8abo\xa5=\x03\xc1\xab\xf9}\x18/\xe9\x1d>\xe3\xbe\xbf\xafw\x0b\x0b^{\x1a\x80\x91zo\x90@B\xa8O\xb1\x90\xf5}\x15\x0d\x8cwdOE\x03cn\xf5}\x85qX8\xd9S\xd64,\x7f|\xdf`\x03\xa6\xf1{\x06B\xea\x18l\xc0\x82\xd6\x9e\x86\xfc9&\x9b\xc1\xa2\xd6\\\xf0\"\xae\x99\xfc\x02\xf88\x04\x06\x82W8pJ1\x04\xf80\x06\xce q\xe0\x16\x13\xb3\xff5g\xd4\xf3$\xbe`\xdc\x0f\x0c\x04\xabOk*k\xe6\xaf\xb0\xf8\x14h\x00\xdeM\x01\x80\xfc\x8e\x98\x11\x05\xc6\xb3\xccR \xcc\x8exC\xd7\x1c\xf9\xe2\x9a\xbe\xc4\xc23\n\x1cH\xb8\xf61f\xf0kZ\xab\xc7RK\xa0\xed\x00\x98\x85\x98\x986\x1b@\xc6\xf6\xfd\x14\x8b\x18\x12\xd2\x97\xec\xe0}|\xf9 `\n\x84e#\x01\x02\xe1\x81\xa8\xa2\x02\x14\xc8\x95x\x07\xcfH\x06\xd6I\x81\xe5}\x8a)\x89\xb6\xe7|\x80y\x8f\x80e\xb2\xda;\x98\xcb\xa8\x1b\xd2'\xa4\xa7\xc5\xcc\xf1\xa1'\x8a'\x06\x84\x89z\xe0@D\xf2\x13,\xfe\x0b\x00\x98\xa8\xfe5\xb5\x18\x05g\xd5\xb2\xbf\x8f\xa9E\xd0\xd3\x10|\x98\x03\x9d\xe4\xef\xaf\xb0n\x10\xf4\x12\xb0:\xfc\x91\x0d \xea\\\xa7\x80=9\xecGX\xd1\x16\x904\x00D\xc6\x1c\x12`2\x8f\xd1#\xcc\xac\xd6\x8c\xb7!V\xd0\x03\x03\xc1B\xca\x9a!\xbd\xf8\xf8\x05\x06\x82\xa5\xa4\xc0\xe5\xb0\x13\xefb\xd6\x13\xb82\x16\x15\xaf\xc1\x1a\x90F\xb2\xa5\xf0\x99t\xec\xb9R@}\x1f\xb3\x89\xc0\xe48\xc4\x84QB\xc0\xe2AN\x9d\x97x\xda\xe1\x143\xf1\xc0K\xf2T\x03\xc9.x`\xd2x\x87l5\x18!1 \x06\xf2r\x1f\x9fT\xe9\xf2/\x88\xcfY\x81\x07\xe01GhP%.\x80\x90\x81\xb5\xb2\x0d\x89R\x8f\x8a\x85\xc9V\xb7\xec\xedN(\x89)\x80\"\x04\xb0,g\xba\xd1\xc7\x90\x1cj\xd1\xd2\x12\xf7\x03H\xc7J\x91C\xc0\xc1\xf9\xbf\xbc\x14x\x19\xa1\x94t\xd7.\xf9\x8dc\x0b\x85.Ur\x1b\xc7\xb6\x9ej\x11\xed5\x8ei\x87(u.\x88\xa0\x8dw\xb1\xe9VLZy\xe0\xeb,\x7f\xc4\x1f\xbeT\x06\x02|\xdf!\xe7\x85\xf73\xb3|\xa0\x1ec+5\x0d\xf8 FaQ\xa4j+$\xf6\x99\x80\x14!\xadT\x8b\xa4\xb5[-\xcb\xa8iA)r>t\xa9\xf4v\xee\x0f\x8a\x1e1\x11\xb6\x05'`\x8a[\x8a\x9e!\xa1\xa4\nV,\x8c\x0d\x83\xab\xd8\x82%\x1d1\xd4l\x98p^\x84\x98\xe1\xd9\xc8FJ)\x1f\x1f\xe0S_.\xa0\x90\xe9CL\x9c\xcbe\x8c}\xf2\x01\x16\x93D)\x08\x92)\x0d\x19\x0b,P\xa8:-|\xa7\x0feJ\xa1\x1aXG(\x17\xd0\x07\x00\xeb\x04(\xda\x03\xe3.\x8d\xf4 \x82\xd0\n8\\S\xfc\x80\x0bi\xba\x19p\xc1CD\x1a}\xf3C k\xc9'\x80\x9e\xbe\xb4\xee\xbb\xba\x99#\xf2\x9e\xf1 x\x8c\xd7+(\xf9\x04`\xedM\xc1\xe4\x1a<\xc1\xb4&\xe0\xa9\x9a\xacE\xce\xe0\xa9r\\x\x82o\xd4\x03\x9e\xa6\xa5\xab;,\x81\n\xb0\xb6\x13`\x0dZ\xc0\xf8m\xe5\xf7jYc\x01\xd5`\xb25kO\xaa*\x14\xa1U\xa2\x08\x12\xb0 \xe1\x8a\xeeHrA\x94\x80\"\x95\xb8\x0d&\xcdC$\xc7x\x00k\xd9\xb6|\x06\xd7\x92GD\x18\xd0~:T\x1eOJ\x04\x92X{\x12\xa5\xc0R\x01=1\xb4\x91\xec\x00\xa4\x00z\x93X>\x12E3\x1f\x10\xca\x98:Z\xf9\xc6\xf8\xb9\xa6\xafF\x88dh\x8c\x92X\x98ZS\xaa5\xa1\x95\xb5\xdfk\xa4\x81\xc08}ac\x88\x80\x80`J8vz\xbbg\xb3\xc7\xa4z\x82\x041Rc] B\x92vb\xf8\x8c\xc8\x8b\x06\x82\xed\xbbk;\x0b\xac\xf5]\xfcQ\"\x05\xe5\x9a\x99\xa5l\xa0\x9d\xce\x08\xdd6Ng\x84\x86d\xb5\x82\xa4T\x8c\x16l:QP\xa8K\x84=e\x9a\x9d\x7f@hQ\xc9U\x8d\x98v4K&t$K\xe0:\x97hK\x81\x0e1&\x89\xf3\x83,\xd1\xeerdRy\xe2\x19\xc3\x0e9\xb3ybB\x90\xc9\nV|\xd0>\xb2H\xf3\xda\x07\xcd\x02S\xb7\xfa\x1f\xe3\xdb+\x13.\x83g0r\x80\x16\xfc%\xd6\xec\x04\x80\xc3\xe3\x1b\x04v \xc4\x89\xf71\x91\x1e\xc1\xf7w\xf0\x94\n\xfeT\x032\x96\x0dl\x1e\x03\xb0a)Xa\x03\xb0\xb2y\xe0k\x92\x91\x93\xec\x01\xc5z\x0f\xdf\xfd\x8et\xb6\xc5g\x1fa\x99\xf9\x12H\xa0\xd8\xbc7\x82\xcf\x98\xbd\x8eL\xca*l\xe5\x18\xe9H\xe6{\x98\xb1\x8f\xb8\x93\xe6 \xf7\x8a\x07\xb6\xb0\xf2q\x89{~>2Ndoa\x82{\x89\x07\x81\x1f\xeak\x01l\xf4\xbe\xa4\xd5\x01l\x88\x1bi\x00>\xe2\xa3\xa1\xdc\x9c\xb7\xc9\xea\xfb\xae\x0c?\xfb\x18K:*-\xe8=l(\x19\xf9\x9e\xfd\x8d\xa2\x91\xef)\xba\xf0\x14\x13\xd6\x91\xef\xd5\xa4\xcf-\xb2\xc0`\xb2.!\xf0\xc6\x16^\x1b \x82\xd1a \x0e@R]\xf9\x08/\x81\xcc\xc9\xaa\x13\xaf\xde\xc3\x8cq\x14\xb8\x90\xad\x10\xdb\x8fG\x01\xb3\xb4g\x1e\x1a\xa3\xb0\x0c\x1e9\xf8%\xa6M\x12\x02f\x85:\x18\xf8\xfc`\x1f\xbb\xb0'\x9d\x8c?\xc6\xd4:,R\xcc\xd3\xb1\x97r\xc9S\xa0\xce$\x89\x97}]\xdf\xe5|\x86\xb7*4\x10lz_\xd7w9\x9fa\xae\x11\x1a\x08\x96:C\x93r\x96\xf6S\xce9k\x19\xb9Jt\x89Q|\x1d\xc88\xd6\x14B\xf8\x8c\x15\xca\xd0Pw|\xbaT\x82_\xb2\xd4\\{F\xbd\x8fYU\xc8\xf5\xdd+V*D% y\xc7\nQ\xaa\x02\x85\x99\x88g2\xfdu>p2\x7f\xcc\x11\x1fy\x13KW\xba\xdc\xce\xd0w\xf7\xa6*\x16N.u\x99'\x87\xcd%Ko\xf5`KS\xc8S\xaer\"a[AX\x04l[&\x9cf\xdc\xa3A%$\x82\x02\n\x96-\x7fD\xde]\xe7\xfb\xca1\xf9\x07!\x19\x82 \xaf&\xf4\x86\x17\xf1\xd5\x18\xb6\xae\xf9.6\xb8\x85\x1a\x80\x87\x19\xea\x988\x8a\xd9*,\x0e;\x16\x86:\xce\xcd\x06\xb8]\xdfX9\xd6\xcd\x06O\xeb@:4\xccRI\xef\x13\x96\x1aB\x1d\xd6b!\xc9\x03\x00a\xb95\xd4\xc6[\x028\x9f\x01\x06=\xa5\x030\xd1\x0eX\xb7\x0cM\xb8\x03!\xacCexx\x8a\xd5\xbbPj\x0b\xf7\x08\x0e\xc3Cq\x0f1\xf3\x0b}\x10>\x1eb\xa9/\x04\x8c'\x0d\xad+\x93'V\x11Be\xf2\xc4\xea^h|8\xb0\xba\x19\x1a'\x0eZGI)XD\x0e\xf5E2]Du\x97\x8c\xa5\xb5\xb0z\x13L\xc7P\xb9\n&\x03\xb1\xdc \x92M\xb2\\!\x92\xed\xd278dx\xc5\x15\x8emJ\xe5[\x1c\x1b\x19jM\xdbr\x0e@\x1b\xa3\xddh\xb5\xf5!&W\xa1\xd1[\x1fbkZ\xb8\xa6\xce\xc8\x13:8-\xc1c6\xb5\x1e\x9dM\xb8#Y\xd8[\x98\xbb\xadG\xa1\x04\xfa\xe1@\x13w\"l\xac\xebX\x11\"\x9d\x18\x01\x16K\xec\xfam62|\xd0\n\xf0\xe7\xf5(\xab&\x95\xc7\x86\xc9_\x01.\x06\x81)\x7fQ\x06\xc5b\xda\x86b\xe3\x9d\x0d\xe5\x0c\xf7\xc4V\x9e\xa2\x08\x0e\xcclh\xadX&\xcc2\xd6\xa3\x8c\x86\xe2\xd8ZB\xf18\x14\xe1\xa3L\xb9B\x13I\\@\x8c/\xb4\xbd\xa2r\x87\xb6\x03\xc7N}\xbb\xf0\x10\xf4C\xac\xd9\x02\x0cr\x98c\xe3\xd5z\x94aO\x00r\xe8Q\x19\xe3\x0c`[\x19\xabG\x00\xa1\x15\xb2`\x0d\x8dS\xb0by1\xd5U\x05\xca\xc8c\x1dHY\xea\xb2\x0f\x95^\xac\xd6\x95+p\x06\x93\xd7\xf5(\xab\x93\x07\x9f\xfc+[sT(|\xf2\xd7\xb6\xadV\xa2\x00\xf6\xc8\x93\x10\x85\x04v\x18 \x01\xd6\xa9\x01\x06H\x805\x8f\xf5(\xdbL\xb8\xcb=\xf5\xd2\x0b\xb6\xf3\x95\xe0f\xad\x9e\xfc\x1b\xdb\xe4t\xb1\xea\xba>\xb4P\xac->\xe6I\xca\xcbD\x0fOG\x94\x92\x195\xcb\xc8IdlTHc\xa7EOA%\x8b\xe1Y\xa86\xe4\xc1\xd9\xce{*\xe7\xdb\x03+\xb6\x97K\x15\xcdYX\x84.\x18\x8b9C\x83\xd6\x01V\xcb\x15Mb\xd3\x97(Z\x8c\xedO(k7\x05\n\xb7\x1c\xa2#\x8b\"\xae\xcb\xb9\x07\xbb\x8e\x0d\xfa%x\xb1\xeb\xd4XQ*\x86v\x1d\x1b\x1aK%\x8b\xf3\xf4\x1f\xed\x0d\x96\x16\xea\xc75\xb3Ck\xf4\xc0\xc23\x8bn,\x93\x93\xc0\x82\xccXx\xa2,Qeg\xc4Z\xa4J\x15=Y\x86\x81\x99?\xd1\xd6\xe3\x1a\xa9@\x00\x9c P \xf1mPH\xcd\xf1\xf4o\xe9+\xb4\xa1\x8e\x80\xbbG\xa5\x810\x8e\x02\x1d\\\x88M\xc9!?}\xc7Z &Id\xcc4\x8f\x1b\x88\xb2\x02\xabI\xd6T\xd6\x93\xb4\xf4\x9b\xa9|;D\xc8\xd7qx\x9f\x10\x8b\x96\x81\x10;T\xa6\xbc\xd1h/\xe8yr\xaa\xe2\x96K\xc0d\xa8\xaeK\x9e/\xa7\x07\xbfRD\xb5C\x04\x0dy\xa5A\xec\xc3\xf2+1\x0f\xcb,\x9a\xbfG\xbfrH\xda\xf86\xbe\x13\x0es\x9d-\x96\xd8\xb3\xc7\xfa='\xcb.^^\xd6\xcf\x14\x12+\xd8e\xf3\x82!\xb1\x18\x8cM-B\xe6\xc6\xa6\x16Y\xc6\xb1N\xbbe\x19\xc7\x18\xf2\xcf\xd8 \x17t\xb8\n9\xbc\xe3\"\xfe\x1d\xdf\\\x85cm\xcbz\x1f\xdb\xe9\xc3\xb1\x8ee\xb0\xf5\x06. v\x88\xb9\xc4\xb7\x815\x0b{\x9f\xd0\xdd\xb1\xe1\n\x0f\xfe\x9d\xad\xa6~[\xf8?X\x80\xfb\xc6\xe8Oh\xda\xbe\xe6\x99\x04\x15\xf65\xcf\xb4B\x14W\xa3\xb0P\x9b\xc7\xf1\xd5\xe1\x86I\x11\x81\xef*\"\x03\xc1W\x81Q\xdd\xf3\x99\x91\xba\xac%\xeffn\xe8\xf4\x11XF\x894\x00kc*\\\x1b\xef=Dk\xff=\xd6\x89\xa2\xda\x1797\xf4\x9bM\x9f\xe1k\xed\xc8@05\x8a\xe0!\x98g\x1fa\x9a\x13\xe9\xd7\xce\xb0\x93V\xe4\xa5\x91\n{\xc2\x96\xdd\x8d\x15H\xbd\xf0\x19\xde\xff\x88+\x00Y\xf8\xbeZ\xc6G\xd8\x95iC\x1b\xfeI[\x1a\x80\x0f\xa6\nV\xff5\xde\xa9\x0d\x93\xc4\x824e \xd8\xa4\x1d\x81\xb1\xfdC\xcc\xba\"\x9d\xa8\xe7\x116\xc3DC\x81\xfd\x9fc9&\xaa{\xa112\xa6hl\x06\x8f\x02\xbd&d\xeb\x03\xf3(\xe1#\xec\xb4\x13\xe9\xc4\x12o\xd2Z0\x17,\xcbn(O\x98\xcf\xb0\n\x1bi\x006]o\x8c\xf8\xc0\xb1\xceR\x01~\x83\x19\xe8\x86\xf4\x8f\x90\xe9\xa7\xb1M3*@x\xef#%R=\xc2\x86\x9fhT\xfb.\xec\x861\x9e\xe2+\xd2\xc8@\xb0\n`\\)\xb1\xf1i#\xe6\xa1\xf5\xc5U|\xbdo\n\x16E\xb0_Z\x14sx\xf0\xf0\x11\x96\x11\x8c\xef%y\xc5vC\x0e\xeb1\xa1 N\xe2k\xbf\xc8(\x17\x04)\xc0\xb3\xf01\xa6\x14Q\xe2\x81\xb5\xe7mL\x8b$\x04R\x8a\xd8`2\x13\x17\x16>\xa2\xc4\x13\xb8\xff1A\xe4\xc4\x1f\xa8\xec$d#\x13\xf5b\"\xde\xc6(I\x83\x08D\xb9\xc7\xf8>7J$\xa9zLH\xb1\xfd%\xe1\x0d\xa3\\\x90\x01k\xc7\x0fB\x89u\x8a\xa4O\xc8.\x1a\x08!\x94\xeau\x8f\x07\xb8\xca\x86\x11\xf4\xf0\xf6F\x06\x82\xa9\xc8F\xe1s\x8bq\xb2p\xc7%\x8f\x1a\x03\xc8\x81zx\xa97T\xb6\x06\xb2\xd2\xea;\xd9\x9a\xb1\"q\xefbanc\xccu|\x11!2\x12\xa6\x82k\x9f\xfd\x19fe\x1a\xaa\xc2 \xff\x94\xac\xfb\x98'\x9bN\xc2\xc3l\xc8S\xb86\xfc3|\xd4\xb42\x85M\x06B\xd7\x13\xd8\x87\xe7Q\xd1\x01-\x95\x94\xb8\xf2\x14s\xfc\x92}\x82B\x94m\x02\x016\x9d\xc4<\xcfF\x81\xc0\xc61\xf9\x8b\xe13&}1O\\\xc91\xfe\x19\x05\xf82\x1f\xca\x0c\x05\x8c \xd6\xf3Mlt\xd6\x94\xe7\x01\x99>O2\x1eJ\x81\xecM\xac\x85lj\xfe\x8ayu\xac\x01XX\xde\x84\xa7\xd2\xb1\x96\x1b\xc3S\xe9\x98\x1c\xc7Cxu\x00\x1f\x8ax\xa8^q\xa6\xfeX\xf1P=\x17\xfd\x17\xf8&tS\xf6\x8c\xe9z,;\xc6\xfc.\xf63wX\x9b';\x86Q\xe1S\x12\x07N\x08\xef\xc7\x93\xa4i\x00\x82\x84jx\\\x02\x06i\xb7-\xd5$\xd1?j\xf9\xec(\xc6\xff\x11\x16\x92\x05\x104\x7f|\xb2\x04D\xd7\xc2\xa6\x04\x01\xf3\xa4\x9aE\xde\x81\x93 p\xf3#\xb8\x11\xe4\xe0\xd3\xfa\x18\x0bE\x9bA\x9e\xea\x87\xd9?\xc6h#\xaa\x8d\xc2:\x88:l\x1f\x11\x1c \xf24\xdb\x97c\xfc\x08\x8b\xeb\xf1\xc8\xd6\xdaf\x04\xc9\xa8\xc4\n\xcba\x92\xcc\x83\xb1\x90\xb9\xb4\xa1\x10c\xd9\xa6\xbe|\xc5bml\xa4\x04l\xbf\x8a\xa3\\>\xf6\xf81\xde\x95M\xb9\xecO0\xd3\x05S\xe4}\xcc\x0d\xe3DE\x18a\xc2nL\x94\xf7\xb1<\x1d\xc3[\xf5O\xc8y\xd0\x96K\xfa\xdd\xad\xe9\x9b\xbb\xa50&:\x02\xee\xaaw\x83\xad\xe3(\xdf\xb3\x90\xb6-\x97,5%\xaa\x96\xf6\xda^\n\xab4f2e\xe3\xab\x05T\x8e\xd4\xc2\xb2\x96\x84+;\xce\x13\xccu%P\x87Ya\xe9J\x00\xb5\xc5\x10\x0fh3Q\x16\xc37\xe9\x16i\x08>E\x12\x92\xdaq0\xd1Qht\xf8p\xc1j\x19z\xc3\xc0\xd5S\xed\x98\x02m\x96\x1ej'\xd4)\x89\xfaN\xa0\x04\x00\xac\xb3\x08\xa0V3\xde\xc5\xca\x94\x00\xa698\\\xbfKx\x87z\x7f\xed\x1e\x96D7\x93(\x8e\x12\x9dI\xed\x1e\xc6\xcc\x02\xac\x12\xb5\xe1\xfa\xa2a\xf0\x9b\xb7\x80\xea\xb6-N\xf2\x04\x04\x83\x07\x98en\x1a\xa1\x11\xdb\xc6bc\x91\xc6\x86\xc9Mx\x95\x87\xac\xbf\xfc\xfc\x1b,\x96\xc6y\xe8*\x13\x17\x06\xbd\xae9,&\xd7\xb75\x00\xef\xc8\xed\xbal\x8b\xafk:\x87\xcd\x13\xb7\x0d\x9d\xc3\xec\xe2\xb6\xc1\xd9\xb7\xb0\x80\xf9\xbaY\x15\xact\xdf6\xab\x82\xf9\xfc\xed\xdc\xc9x\x12\xfa*3\x01\xc9\x8c*\xe0z\xf4\x98\xeb\xea\xd8\x94\xd7l\xdf\x15\x91\xc2\x02\xd5\xeb\xbb\x1b;\x0b\xec\xdb\xado\xe3*Qf\xf9\x9c\x98\x84KX\x9b\xd0B\xec\xbd\xbf\xfd;\xcc{\xb6\x8c/5\xde\xa0\xc4@0\xc3I\x1c\x0f\x12\x90\xde\xc3;\x91\x94\xb34a\xfa\xb1\xa5c;1\x1a&\x1a\x80u\xf0\xc4\xa4U\xc2'S@\xe4\x94\x1ea^\x9f\x14 \x97hs*s\x12fo[Z\xd9\xc4R\x97\xb9\xfc\xa2\xfd\xab\x1a6\x00\x10\xbc\x0f0]KLR%:\xe6\"\xa9\x12\x19Bq\x97f\x81\xa8JX\x84J\x8atKXQL\x8atK\x18\xf1\x13\x93n\xe9\x03L\x0f\x92R\xba%\xac\xe9l\x99tK\xefc\xa4O\x8aLLX\xd2(]\x03\x92E7 \x97\xb0\xc2\x94\x14\xb9\x98(\xeae>\x10M\xac5IH\xa8\xfd\xe7q\xbd-\x93\x8d [\x18\x13\x03\xc1\x1c%1y\x9a0\x05HL\x9e&\xb2[:O\xd3]\x1b@\xd4\xb9A\x01*O\x13\xa6\x84I)O\x13\x16\xd3\x93R\x9e&<\xa3-\xe3\xa7\x8f\x15\xfb\xc4@0\x03\xdf2~\xfads\x0d\x04\xd3\xd6\xc4\xe4i\xc2\xc6\xb3\x04\xf24\xe15\xd8\x02\xcd\x91\xe0>8\xc3b\xad'\xd1y\x9a0kM\xbc\xc0\xa4\\\"\x87\xdf\xe4p\"\xf8V\xe4p\xa2 \x15\x17Jh\x19\xc8\xe9\x04?9\xf0t+@g\xc9%\xd4\x99;\x81\xc9\x92k\xab\x08\x88K\xc6\xc6A\xdey\x0f\xeb\xae[+\xe7\x05\x91\xc3|5\x81W\xfe\xf1g\x8b\xff\x0fvV\xd6E\xd03r5\xc5vcT\x90<\xb7\x9a\x14\x890\xb0=\")\x12a\x90\xe6U\x0eh\xb2BZ\x90 \xdd\xe8\xc4\x16\xf8\x16\xdb\x84'\x93\x17\x7f\x13\x9d\xd8\xe2\xa7\x04\xe7\x8a\xc4\x16\x98ln\xc98\xba\xcf\xb1\x8e\x95\xc8\xcf\xbf\xa1]DR+'\x8cX\xc6\x88\xe3|]\x18\x8bQ$9\xe6>\xc8}\x820\xa7\xaa\xf7\x84\xb5v%g\x17fTE\x89J\xd4\xfbO\xf1\xfd_\xd1\x91I\xda\x85\xe9\xbfl\xaa\x9c\xb5\x0b\x93\nY\x80\xa6\xed\xc2*\xb5*\x86\xf3v\xe1\xd3b\x8a\x95\x12wa\xb3\x16*\xa3\xf3\x0ea\xf1G\x16;W\x8b\xa7\xe5\x04V:\xc2\x95\"Z\xa9\x10\xf8\x06P\x8c\x13EP\xf6.\xeb:\x97\xf2\x80A)\xc2.D)\x9c{\x8bPf\x9ff\xd4\xb2.\xa2N\x97\x85em\x0d,\xb0\x13[F,\xcfr\x13Z(\x8a\xa0\x8cYx:\xc4\x17\xf1\x01\xa1\xceVG\xc4\xa6B\x85\xf7\x1a\x96\xdad1\x925\x0bK\x04\xaaTur\x98R\xa9B\xa5\xa4WX\x8b\xab\x94\xd0\xf8\x87\x05s\x94\xd3\x8c N \xae\x9b\xc0\xbak\x02\x87\xee\xd7D\x88\xf2\xd3\xea\x83\x8d\xa4\xa2I\xa6CP1\xd0\xe9 \x08\xfa\x05\x90\xf3\x81HQEf\x1bL\x0c\x93jf\x1b\x02\xd6\x81\x0cO \x933 d0WLL\x02\x19\xbc\xe8\x89I \x83iKbn\xd3\xb0&\xb8\xa5uQ\xc2\x95\x8d.J\x04\xde\"/ \x1duqGB\xf0/\xcaC\xaf\x94\xe0\xfe\x03\xac\xde'0\xc6\x8e\xe53\xdc\xf8>\"\x9a]\\r;$<\xc2d\x03!\x04\x19\x85\xf0\x90\xb3[d\xea\xc0\x06\xb5-};E\xebh]\x1b\xfb\xc6l)\xc9\x8b\xec}\xedw\x99\\\x83\x08\xd1&\xb9\x06\x16l\x93\"\xb9\x06\x01\x15\xa9)\x082\x17t \xc7ni\xdf\xc3\xf7\xb0\xa5\xab\xe4db\x81H\xc2zE:\xe2\xc5\x93\xf7d\xbc\xb5\xe8:\xf2a0\xefR\x88\xdc\xc9'd'G*\xaf<65\x08\x00\x84\xaa\xfd\x0d\xcd\x02\xb5\xbdqn\x07\xce*\xa9\x16\xf538\xadX\x9c\x01G\x9f\xe3\xf4\xab$\xe3\x1fb!_\x00\xd4E\x1aa!F\xf0\xc5rQj d\xc9bG]\xc1\xfe\x92\xa0\x99\x04\xe9w\xfd,\xd0\xc4z\xf0\xd3\xdbJ\x96x@\x98\x9f\x80\x80\xaf\xd1\x9f\xd3\xb5Ko\xab\xdc!\x0f\xb0\xb0,!P\xefg\x965\xbf\xad\xfcg\x88\xd4t[\x076`\xb5\xa7\x08\x94x@(\xce\xedR\xf8\x82\xb5^\xe1\xd7o\xab\x0b3 \xb4\xd4D_<\xc04P\x82L \\\x0dPuH\xebJK\xd9{\x98\xd5\x97^\xae'R@=\x08j\xe1g\xa8\xc8.\xd2p\xc0\x86\x02\x85R\x8f\x17\xcb\x16\x06\xd8X\xa4h\x8a\xb0\x11Yn7\xd4#\xa6\xf8\x93;p\x83L\x1e\xf2Oo\xe75\x80\xda\xeb\xa5msk\x89u\xc8\xd4hR\x98#\xa7\x0d\x02I\x03mJ35\xee\x87\x98jogp\xfa\x08 U\x80\xbf\xb0\x01d[\x7fAD\xc6,q\x04\x9f\xe6q\xea\x07r \x7f\x83\x95$]D9_as\\\x9a%\xd2\xeeE\xb2\xdfm\xc3\x01|H\xf0Z\x1dL\xc2r\xf3\x9e~\xb3\x9b\xa8\x0e&\x16\x89\x02\xe0d\x91\x19\xe7=\x9d\xaa\xe7)\xe1\xbayo\x94\x83\x07\xf3S\"[\xe7=\x90\xfa\x9fb\xbb\xa2\x80@_\x84\xc0\xe6=\xcdE\x9f`\xb2\x9c\xe6=\xc3E\xb1^Z\x1c#\xdb\x1a\x990*+H\x11\x05\xcb\xb4\xcb\x11T\xd6\x0e\x8b\xb3d\xaf\xad\x12\n\xdb\xa6 \xd0\xdbu\xeb\xa3\xfd\x1f\xb1-A\x80`\xd3\x9f\x12\xec\x11 \xc8\xf2F8\x86\n\xf6\xa2\xfaj\xee\x96]\x8f\xb0\xd6*\xc0e\xd7#\x8cL\xe5`_\xd2\xb6%\xd2\xb7\xa6\x04r=\xaa\xeb\xa5\x14\xe1k\x19\xa7\x0eY\xb3\x80\xca\xaeGD5\x15p\xedzD\xd4S\x01\xacUPs\xb7^\x0b\xcd\xdd\xe1\xce\xd0\xb1_Bm\xc3e\xd2=\xc2\xf7j\xbf\x83!\xf0\x97\x98\xb8n\xc3v?\xa4\x15\x80}\xd2\xd3\x1a\xcf \xf2\x82OO\x9a\xc7\xf3\xe2;\x91M\xf3\xf8\x84\xf8N\x84\xc7<\xd6\xe4\x05[ \x05H#(\x11XM\x84 \x05\x009\xa0\xd8\x1e\x1b\xd2\x83\x05\xb8j@w\x0d\xb08\xa0\x96\xa6\x87\xca7\xfcWXQ\x9405 |!\x9c\xe6\xb1I\xdbJOSl\xa8!\xa55\xb1\xa2\x86Dp\xcdcE\x0d)\x1d\x8855|J\xc45#\xed\xd8\xb6\xbfn]*b\x90eI\xca\xe1\x94V\xa8\xa6h\x96\xa1\x96)\x9ae\x8e\x9a\xa2\x11\x9e\x9e\xc7z\xad\x89\xc0!@@\xd1\x08\xbb/b\xd6\x88\x19\xc6\xc4\xacachjb\xd6\xac\x90\x9a\xbc\xd7\xe9~\xa8\x8d'D\xba\xb9\x03\x91S\x9f`=q\xc7\x113\xfaA\x86>gN2\x80\x9dy\x17Oh\xc7\x91!\x9aX\xaf\xc8\xe4\xe7\xdf`\xe4\xcf\x94\x9d\x9f\xf8\xea\xef\x18k\"i\xc9@\xb0\xa6\xb1cl\x80\xd8\xfe\x92\x19\x08\x96\xa9\x94zF+H\xdd\x0c#\xbf\xce\x9c\xfcclw\xcdx\xa0\xbcb\xdf\xc5\xeclG\xdb\x8b\xf0 \xcc4\x00\xdb\xcd\xb3!O\xf8I\xd1\xd8=\xb2,\x02\xd4\x8f@b'\xd0\xac\x11\xba3\xe4\xf0\x06*\xa6g\x99\x06`\xb6)\x01\xe9\xa1\xc0\xf7\xdf\xe0\xc3)ac;\xc4w\xf7J\x197\xf1A\x91\xf0:cJ5\x03\xe2[\xbf\xa2/\xf5gC?T\x9e\x8d\x98\xdeU\xb3\x1dbh6\xdcS\xb1\xbdtD\xf5\xe3\xb9\xb0\xb1\xb5.N\x066\xc7d\xc3(\x11X\xf8 \xe6\x1c\x86\xbb\x93\xb6t<\xce\xaf\xb1%\x1a\xa5\xdb\xc0\xc4\xce\x92k\x03\x8bq(\xd1\x06\x99\xa0\xba!\xf9\x84\xe0\xa0\x00\x80\xec\x8d\x15z\x00\x01\xc1\xf8\x88\xa0\xa8\x00\xc2\xbb\xb9XP\xc9\xea\x1e\xe0\xce\"\x0e>B\xd8n\x99\x81\xd7\xee\x03r\xd2\xa3\xb8\x07\xe7\xed],\xd0dQ\xac\xd3\x18\xe3\xa1\xed\x18\xdb\x06\xa6\xed\x99\x81`\xca! *d\xe3)6\x1bdQ\n\xc3\xc6rSVx_\x93\xa3\xb6\xb5\xb8,\x99\xe4\xdb\x84\xb0$\x0e\xec\x91\x05R\\\x9f\xbf\x87\x15.\x0d\xd4\xde\x0b\xefaA\x0d\xc7\xee\x93\xac\xea4t\x9f\xa4W\xd7E@F\xc6HJ\xe2\xfa\xc9\xa5\x9a%\xac\x9f\\\xafe\x89zU\xe5\xd9/\xb0IL_\xc9\xd9z6\xb6\xc1\x8f\xb0\xdc\xbb\x93\xf8q\xc0\x97\xeb\xe8\xb2\x80\xaa\x9a\x96\xe1\x02\xea\x7f\x88]\x06\xb3\xc4\xcf\xd4\xd6~\x84e\xa3,\x89\xf9\x1d\xe5F\xf5gx\x0fw\x8c-\x00k\xbe\x99\xb1\x05\x10\xa2\xa5nz0\xfb\xcf\xd4U\x0f\x96_v\xb4\xf9\x9f\xa0\xb7\xb6\xff\xe3E\xd81\xcf\x0f\xd0>4\x04_\xc0d\xfb>\\\x8c\xdc'\xdb\xb4\x1f\x0d\xb9\xe3U\xf3K\x12\xea\x08\x85\x90w\x13&1\xbb& \x1e\x1f\xba\xdc@\xf0~\xefj\xd1\x07\x8b*\xb9\x96\x960?\xcau\x0d\x0c\x10M\xe9\x00\xfb\x0f\xf0\xb6\xec\xf6\xd4\x93\xca\xf8\xa67W\x80\x7f\xc0s\xde\xed%\\\xc6y\x7f\x86\x97,7\x10L\x13wu\xb4>\xde\xb3\\\x030\xfe\xed\xc2\xa8\xb0\x1c\x93\xc3\x98\xf0\xa9\xcf=\xed:\x809\xc6\xae \xd6\xc7\x04<7\x10LZs\xe3\xca\x89M]y\xe1?\x88\xf9\xe1\xae\x16s\xb0\xd8\x91k\x00V\xd7vM\xc0<\x16as\x03\xc1\x879\xd7\x9e\x85da\x86N\x02\xeen\x98d\xe6& -\x1ern\xde\xc5\xc2\xdaJ.\xdf\xa7\x12\xa0w1\x95\xca\xcbOWY\x80*6\xe5]l\x1e\xcd\xcdC\x18X\xfc\xda\xd5\x11\xf2X\\\xcf5\x00\xbb\xedC\xb0\xed\xc7\x98\xc1\xee\x86\x9e\x8e\xa9\xc5\xef\xe5\x00\xc8\x84\xd4\xe2Ce\xc0:\xa6\x16\xd3sY\x00\x07\xd5\xe2{(c\x8a}\x88\xf1SBt\xb6\xff\x07\xf8\xa8\xed\xaad\x0b\x9fa\x0c\xc95\x00k\xf4\xbb\x86\xc5c\xcd-7\x10L\x04\x9b.\x1cw\xe3\xc2\xb9\x86\xd0\x95\x02f\xa9Wv\xda|\x1f\xdb\x8c\x15\xb8r'KOh\\\xbd\xb3\xc5\x8a\xc5n,\xa4\x81b|\x18\x9eW\xe1\x96\xfa\xd8+\x98\x9c\xeaX91\x9aw?\xc8\x19\xd2%\x8a\xa7\xa4\xc8a\x8ak\xb77\x8e\xf1[MX\x9b\x94E\xd0\xad1\x96awU\x08\x14^\xe4\\}\xc7\xeb*\xbe\x0fm\x15v\x8d\xc1\xfbs, \xe6\x85-\x9cn\x93v\xbf\xc4\x95$\xa4\x187mSa\x10x\x7fb\x99=O\x0c\xa9\xc1\xe7)/?\x02e\x01jRC\x16\\9\x19~F6Z\x03\xb0\xd8\x92k\x0f\xaa_`\x82\xbbkD\x1d\xc2?\x8c\xa8\x83U\xb7\xdc\xbc<\x84\xeb\xecj\xdd\xe83L\xbbr\x03\xc1\xf2w\xae\x9d\xbb0M\xca\x8d\x0b\x17\x96ps-\x0b\x90\xd5\xdeUy\n\x08\xe1V\xdf\xb1.\x97\xef\x1ba\xfd\x11\x96\x9d\xc6N8\x80;\xc8G\xb8\xb9\xb1\x934\\\xab\x8c\x9dD(\xce\xd2c\x01\xaf\xd0\xd8I\xc2H\xe8\xbe\xf0\x9a\x06\xc6\xc2\xb1\x93\xd4\\\xc6\x08\x88o\x0b:\x17\x80\xfa\xb8\xc6\xb1\x16\xa7,\xed%Vz\"\x00\xe0`\x8f\xe5\x86\xb1\x93\x18O\x0clR\x11\xb0\xea\x1d\x03\xbd\xd2-\x97Q7\x0d5\x85*\xa6\xbd\xe62\xca\xc0g-\xa4-\"\xc4\xb6!`H\xd3\"\xaf\x03\x97\xca\x18\xaaH\xfc\xa1/+\xcd\xfa)f\xe1c\xc53\x9e\xe2\x83 \x002\x8a\xef)>\x08\x97A$\xc4\xe4l\x0c\x9f\xf1\xf0\x8a$f\xb8\xeb\"\x87\x19\xee\xa1HaFFe\xea`]H\xb6&%\xaf\xa7\x98\xe3^V\x9e\x9c\xf8\xa6m\x0c\xdfI\xea\x991\xe7j\xb9\x1e`qx\xcc\xb9\xd2W\xb1\n1\xe6A\xe0\xc3\xbd\x02&w\x97y\xa2\xda{\x93\x1c\n\x0d\xfa\x11\xad\x93\xd5\xd5\xc8j\xca\x97\x13\x9bb\xb9T\xc3\xd5\x13\x17u\xd5\xb7y\xec$\x8e\xf2+\xff+,B\xebR\x85\xe5\x07#3}\x04\x04\x13\xe5\xcbZ\x0c\xc7\xc2\xf6X\x030\xee\x8e\xb5\xc4JQ\xdf\xe4\x8e\xb4dz\x1c\x9b\x9c\x8b\x96\x0c\x89\x97\x8dx\x86\x95\xf1\xb1\x81\x10:[\x1b\xef=6o\x17\x92sg\xd8\x16!R\x86ma\xc5z\\\xba\x01\xb6\x90\x8b\xd2-\xb0\x15j\xeeKj\xa0\xbc\x8eZ].\x0e\x17\xd6\x00\xc6w\xfc\xc1\x1dG\xb2\x82G\x18\xf1\xafh\xbfV\xcc\xfd\xf65\x00\xf3\x9d}\xee\xa9\xf3\xf0\x18+\x00W\xb8\x07Q\xbd\x0f\xf1\xe8\xf65\xe4\x1e\xde\x17 \x81C\x89qj\x9f\xfb*[\xcc\xdb\x18\x97\xafht\xc3\xf3\xd9\xd7\x00<\x9f+\x063\xb0\xa0\xb3o \x98\x94\xec\xdb;\xdfO\xac\xa7g?\xe1N6\xb4\x82\xae\x18D\xc2\x87`\xdf \x12\xd6A\x0e\x94'\xd4C\xcc\x04\x0f\xd4\xce<\xfb\x05\x16\xc0\x0e\x94\x13\x14\xd1\x9c\x0e<-\xfe\xe0k\xe67\xf4za\x9b\xc2\x81\x06\xe0\xfd?\xd0\x0f\xb5\x90\xb7o\x0f\xb4\x8eL\x9e\xbb}Cf#\xc06\x90\x03\xf9\x15\xab\x00\x07:\xbd$y\xcb\xf7@\xdfA\x927|\x0f\xd4\xf3d\xe4!\xdd\x03\xfd\xe2\x0bf\x05\x07:\x99\xe0Gx\xaf\xde0\xe8\x80\x95\xef\x03\x03\xc1,\xef\xa0\x88\x0d\xc1l\xea 2\xd6A\xb2\x91:<\x9d\xbc\xdc{\xa0}>\xc8\x83\xbdo\x18L\xc2\xc4\xea\xc0`\x12&\x8a\x07\xc6;\xee#l\x1f<0\n\xd7G\xf8\xb6\xed\xc0\x88\xcc\xa4\xa7q\x0dK>\xd8\xaf%\x00W\x8d\x8d\x0e\x93\xdfC\x03\xc1\xb8yu\x11\x84\x12\x8c\xe6\x87\x0e\xd8\xaf\xf0\xfe\\\xd5$\x0b/\xda\xa1\x06`\xbc\xbc\n\x1d`\xd9\xe6\x10\xda\xc7\xa4\xfd\x90\xcbdBX5\xbb\xaaO\n\x96\xdf\x0f5\x00\x8f\xe7\xea*\xf4\x8b\xef\xa2\x0f}\xe8\x18+\xadW\x0d\xe2a?\x9fC\x03\xc1D\xff\xaaA\x14L \x0f\x0d\xa2`JxU\xd9\x0b\xb1\x08t\xa8\x0c\x86\xa4<\xe8;\x9f\xe1\x83z\xa8\xf4 l\x00\xb8fBQ0\xc2\xdf1\x10LT\xae\x99\x1b\\\x8c\x1ew\x0c\x04\x93\x90k0\x0d\xbc\x8cw\xe03F\x82k\xea\xe5vL\"\xee\xa8\xef\x98\xa6\xdc\xe1\\?\xe2\x89\x19\xc65\x9eDW|/\x1b\xd6?\xa3vM]\x9fb\xc9\xf0\x8e\xfa\x8eq\xe5\x9a\n\x9b\xc6]\xdd\xd1\xc8E\xa6\xa3,\xfe\xa4\x030\xf8\xff=\xee\xe0\x8e?0!c\xf8l^\xd3ar\xf8\xb6\xed\x8e\xc1;|v\xae\x19\xbc\xc3D\xfa\x8e\xc1;|p\xef\xec\xdf\x92k\x85 \xd7\x9d\xfd\x10\x00\xef\xb6\xcc\xf7\xbb\xf2\xaf\xbb]\xd6\xcfC\xe9g\xda\xe6]\x96uY\xd8a\x7fd\n\xb5\xf2\x94\xb34K|7k\xbdj\xbe\x8e\x9d\x84%\xec\x0c\x0b\xdb'\xe7^\xe9T\xbb\x8a\xe4\xf7\xf9\xeftf\xf2\x90\xa7\xae\x13\xf3K^Q\x93\xcf\xf0\x838J\xb2\x94\x9d\xa9\xf6[\xeeTw\x11v\x99\xdfeN\x97\xe5\xec\x0c\xcb\xaa\xdd\x88\x9fh\x84\xcf\xc4Qz\xc99x\xb5\x02\xf5\xfb\xac\xfd\xf2,;sF\x14H\x13w\xc6\x1d:\xc9R\xe4\xf1\xc5\xac\x9dup_\xe2\xd7\x8f\x12\xd6\xce\x8e\x1e}\x95e\xec\xbb,}\xd5VF\xb7<\x07-\xb7Cfo\xbe\xc3\x12\x9e\xe5I\xc8\x8e\xcc\xbdZ\xdb\xc8\xcb\xf3\xb2\x91\xd0\x14v\xd8\x19\x96\xb4\xa36\xb4\x98\x06\xbe\xcb\xdb9;\xca\xe6\xc4\xeat:]v\xe4\x08\x9f\x89\x9d$\xe5\xc9\xcc\xd8 |\xcf\xc9\xf8\x9a\x1f\xee\xb5\x9d\x0e{\xe9%\xd6\x96+!\x16\n\xea\xf0\x99\xc0\x0f\xf7\x96\xa20\xe3a\xc6\xce\x88e<2\xdb\xb1\x8f\xe7\xb4\x1a\x8bhGV\x17K\xc0^\x13\x7f\x9fa\xf3l\x81eG\x8f\x92\x8aw\xc9\x173\xebo\xd5\x97\x93\xeb\xec\xb33lV\xad\xb4\xe8\xf3\xc4<;\xd2\xb4\xa0\xa2\xcc\x91v\xc8\xbe\xc7^\x11\x7f\x86\xec\xbbl\xeed\xe7\xd5\x0e\x19\x81XX\xebd:j.t\xfe\xfe\x83\xf4\xe8\xf1A\x97\xb5X\xab3\x93E\xf2\x0eg\xc9Iy\xfb\x85\xe0\xf0F\xef\x16w\xb3\x19\x8f\xf7\xfd\x90o&Q\xcc\x93\xec\xb0\x9duY\xeb\xe6M\x9e^\x8a\xbc<\xe0\xad.\xc1\xd6 \xe7\x0b\xec\xc8l1\x82N\x97\xc9V\x9c<\xc8\xca\xd3\xac\x99%\xc5\x147\x1a\xc5Q\xc8\xc3,]`\x8en\x89\"\xfb~\xe2\xc4K\xa5\xa2y}\xd14s2\xbe\x19\xe4\x03?L\x17jXA\x1as\xb7\x0e\xc6Tw\xdb<\x90\xb9&\xd2\x05\x96\xd0^\xf4/-J\xf9\xd6Bw\xedu\x9d<\x1b>\xc7\x08\xa2\xe7i;r\xd2\x13Mm;r\x8f\xd2\x05\x96\xd6\xcf+\xe1^\xeer\xd1\xb5[\xbf\xd4\xfaWZ\x84\xc0>P\xf2\xf5n\xcd)\xbcK\xe9l\xdc\x0e\xdb'\xe7\xe7;\x16\xc9\x14@'0\xc87\xa0\x93\x18$\x88W_\x82NaP\xaeA'H\xadT58\x7f\xe2e\x0c\nt_'\xc9\x08]\xdd\xe0\xc9\x13\x9d\xce\xab\xdf20}JX\xbf\x9e\x1c\x08\x02\xc6g\x8a\xc3\xc8^c\x9c\xd96Um\xce\x02\xe3u+j\xe98\xa6\x1d\x0b\x92Mz-\x88t\x95\xd4j\x0e\xfeGw)\xbb \xf3 `G\xce0N\xe59\xc9P$\xcfc~\xc8xG\x93\xa18\x89\xb2(;\x8c\xf9\xcc\xd0I7\xf6CM\x90f\\'\x08\x04Q\x0bA\xd6\xc9\xae\x877\x04S\xb9\x1e\xde@|N\x0d\xb3L\x8b\x04-,-\x02\xfbF\x90J?\xdd\xdew\x06\x03\x9e\xcc\x0b\x8e7\xe3\xa7\x1b\x8b\xdb'\xe4\x9f)O\xc6\xb7\x1b(\x82\x103y\x91\x942\xc5#KtY.\xddJ\xa4\xec\xaa\x93\xe6\xc7\x03&\"\x99\xb0\x90\x00\n\x17^l\xb1\x97{fz\xaek\xcd\x03\xcc\x9f9o0\xefp\xde\xa4=/2+vD\x00\x01 \"\x80$)Y\xd5}\xb0\x96\xad$\"\x10\xd7\x1d;\xf6}'a\x00\x9b*\xfaf\xe7\xbe\x92\x1bl\xbf\x0d\xf1\xed\xd6\x8e\x12\xc6}-\x8cW[\xd1\xde\x07]=\x1d\x13W\x0d\xd8;#\xc5\xe1U^\x10z\x91R\x1c_aP\xfc\xeb\xbb\x9c6\xa2&\xday_\xf6\xa6\x0b!\xdf\x16\xc7\xce\x1cz\xec\xcb\x85\xcdc\xa7\x851\xd5\xf8\xec\xa3\xcc\x94\xf7t\xc8\xb0/\x9fq\x03\xf4\xc5L\xd94s\xb7\x89\x85\xf1o E\xe3\xdf\x12\xfe\xc6\xbfk\xdc\xce\xfe\xac\xd0\xfe\xddLI,e\xffvUw\x8f\x91C\x1d\x82\x83)\x84\x13\xbcXn\x86\x7f\x95\xb8\x17\x87\xed\x85\xf9K\x1f\x89\x15F\xfe\x18\xcee=\xbd\xce=\xfb\xb9MP\x0c\xed6\x93\xc4_\xbf?=#\xe1\x9f\xa3\xe4IY,\x92,\xfc\x99\x18\x88\x8a\x9cR\xd1JZ\x9e\x96\x8c\x1e\xa8Hy\x05!\xe2+ \x91\xd2D\x88\xe4\x9f\x86\xd8\x16\xbf\xe8\x84#\x0d\xaan.\x95-\xee\xceP\x7f7k\x87.\x83}\x7f\xed6\xccvq\xab\x8c'\xdc\x01\xc2+>t\xdf{\x11\xe6\x85\xd3\x06\xfe\xeav#q\x91]\x1d\x92\xbf\xdb\x8e7O\xb2\x03\x7f\xb60\xcc\x0d\xa4[\x93\x1d\x06\xbe\xee\x0e\x1d\xc7\xd8Q3\xa2\x14R\x8a\xe9\xe6\xb1\xba\x14u\x0e\xd3\x91\xa6\x94\xe2\xdf\x92Q\x01\x94\x0d\xb1\x14g\xd8J(\xcb>\xb6P\xbe\x84bn\xfe\xc1c\x7f\xf6}D\xf7|\xd2\x04\x00m\xfdk\x0d\x03\x11#\x03\x92\x96\xf9\xc2\x8e\xc9\x05\xf8\x14\x81\xf3\x1b\xbd\xda\xd6_\xaeQ\x056\xf3\xe6aT\x90l\x00|@}\x88\x18FE\x91-Q\xd6\xbdv\x1cG\xc1v8.X\x8b\xa2H-\xfc\x14!\xd7\xf2\xd3\xf0\xcf\xe4J\xbc\xa1\x84\xc2\n\xc3/;\xfd\xd0>\xe2?\xc8\x7f\xadt\xe5*\x99\xbfJV@o\x8d\x8a\xad\xf2\"\x12\x9f\x15\x0b&2\x7f\x92e\xfe\x95\x9d\xc1c\x18\xc1>d\xb0\x01#\x98\xc0\xa6\xe3\".\x18=\x82\x10\xbe\x82\xec\x11\x84\xeb\xeb\x0e$\xd3\x90V8\x96[\x9b\x86\xc7\xdd\xcd\xa4}\xfaws\xd9\x97\x155\xe3\xd3\xcb=j1\x8b\xd3\xe2\x98\x92\x8b3\xbf\xb0\x13\x87r\x93mV3\xd1^\xff\xac\xe0\xf7\xbf\xff[\xf2\x8c\x9a\x9a\xbdK\xa1\x82\xdc\x06W\x1f\x0f\xe3\xebVe\x91\xef\x84\x8d\\\x99\x81\xbd3\xd6y \x03+\x13%\xf5\x86\xa1Z\xa7GB\xa0\xd5\xe4E\x1d\xde\xd6\xc8\xd7\xe6m\xbev\x18\xf1\xb2\x12\x8f\xe3\xf6*#\xccK[\xe1\x9fB\x89\x7f\xe2\n\xff\x14\x1c\xff\x14\x12\xfe\xc9\x18\xfe\xc9\xe0+(\x1eAF\xf1O<\xcd\xba\xf8'\xd3\xe0\x9f\x04Ug\xb7\xc6?\x127E\xf1\x8f\xdfB/1\xc59]\xd1\x8e\xe9\x88\xaf\x84\xd7?)+E>gV\xa9\x8b\x07\x99\x0e\xa2\xa3MH\xaa\xa2\xfb*N\x88\x15u\x98\xa4Z\xa9\xf1P\xaf\xd4\xd8T)5X\xd1H%\xcdcEz\xa5\xc6\xd6\xef\xab\xd4\x10\xbfd\x91\x7f\xb3\xa1\xa7~\x14\x9d\xfa\xb3\xf7\xf9\xa4&b\x9as\xf9\xb6(\xd2'\xa8\x88\x8b\xd4\x15\xde\x12Lc\xf5u\x12\\Mj\xfa\xbcY\xe7\x90a#\xad\xfa\x92\x97?M\xe2\xc2\x0f\xd1\xdfL\xa3\xbc\x94:;\x08B\xf4V\xc8\xd55_\xa7\x84%\xff\xa9\xfa\xd6(\xe9\x12Q\xf1E\x18\xbf\x9f@(j}\xe6\x87\xc3\xb7c\xbb\xab\x9fKxI\x07\x90C\xbc\xbe\xec\xd8\xa6p\x8cUF\x14l\x91\xa8XQ'\xf1\xd1A\xb4\xff.%\xa8\xf5B\xc0\xedr-\xb1\xb8\x18*ex\xb7\x0e7\x0cI\xc9\xec\x8d_,\xba\xe5LJbU@TA\xa6\xa5\xb0)\x0b\xe7`\xaf\x15\x95\x1e\xb0:\x03\x9cH\xe0\xe9ul+O}J\xf5\xd0\xdb\xc4\x05\xebU\x02\xd5$\xda\xcc4\x9d'SI-\xfd\xb4\xa6-z\x94@\xda\x8e\x83\xf0\xbc\x03e\xe2yO\xae&\x12c\"\x9ekW\xdf\xdcb\\\xcd\"\xc6\xeb\xaf=\xc8\\\xc7\xaa\xf1\x81Z_|\x91\x91\xb9\x10\x13\xecc[0\xb9\xd9\xf8A\xcc!W\x16_\xab\xc6\x17\x99XI\xba\x9b\xf2\x00\xa3jc\xe90\xd5\x8c-\xf0=\x9bUR\xaaa\x02\x83\n\xf7LZ\n\x0c\xf9\xd1q\xd3\xd0\xbf\xf3\xa5\x0b\n\xfe\x94\x98\xd6\x12pX\x13\x98\x99\xc5\x01\xb8\xe4Q\x8f\xc8\x00\xfd\x86,s\xa5%)\x16I\xd0\xdbV\x8a\xee1=\xa2\x15q\x9e\xe9=\xc3\xd8t\x17r\xba\xdd=\x12\x99(J.\x8e\xb2\xab\xe7\xc5\xeb\xb2\x98\xb4\x8d9\xe5\xe7Z!<\xd0\xbdo\xbfko\xe3\xb0C\xcb\x8eY\xfey\x194uo\xa3Pu\xe7\xd0\xcb\xc8\x0e\xc5\x9d\x13\xf6\xdf9\xe1\xe7}\xe7d5\xf1\xa1\xbbu\xa4*\xdf\xd3\x85\xeb\xd6\x0b\x07\xdfNX'\x9e\x87g\n\xa8/\xab\xfb\xabb \xba\x95\x98\xb1\xf8<\xee\x96D\xec\x0ee\x06\x84GW\xa9b\x9c3\xac\x12\xe6\x07\x97dV\x16\x8a\n\xf3\x9e+4\xc5\xf2$~\xba\xf0\xe33\xc5\xf7\x01\x82\x8d\xf5\xd2\xcf\xde\x07\xc9E\xac\x92?.X\x95e\x12\x90\xe8\xe0\xd2_\xa6\x11QU;g\xd5:\xb4\xa1\xaa\xee\x12\xb85q\xc1\xe4\x01\x01\xc9gY\x98\xd2\xad\xb7*]f\xf7\xb3\xb3\xd6g|\xe9\xf8'\xe4\x02\x12\xefu\x16\x90\x8c\x04/\xfd\xb4y\xce\xe9ZG\xb4\xda\x99\xf7\x9e\x08\xe1w\x98\xe5E\x9bu\xa3\x80v\x05{p\x86]\xa8\x90\xd6)\xec\x81\x95\xe0)fw\xd3U\xcd\xef\xa3\n\xdar\x81\xc9f\xdb\xb6?H\xa2\\\x19n2\xbc\xf5(\xeb\x1b\xce\xf0B\xba\x97\xcc\nRl\xe4EF\xfc%\xbf\x08\xe9$\x98\x91k\xe4\x85q@._\xcfm+\\\xfag\xe4\x1e[\x88N\xa1_\x06a\xa2+<\x0f\x03B\x0bu,\xf0 \xdb\xd6\xe7qZ\x16*m\x03\x9f\xcb\x0c\xf6\xeb\x0b\xae\x85DOt7\x1d\x93f[\xf3\x90b\xecK\xf3;\xc1\x0e\xa1\x82V\x98t\n\xb5\xa3)\\lL;(.'\xd0\x8f*/\xae\"b\xb2^\x07\xf4\x1a\x880\x98\x07\x1d\x9d\xb6b\xf72\x026F\xeb\xdf\xfe\xf5\x8f\x96\x90}\xdf\x14\x07\x81\x0e:NN\xf0p\xea:/]\x88(\xc0\xdf|\x85\x1a\xbdfI\xba\xc1O\xb8v\xba\xf6\x17\xfc^p,\xe7#L7 iFf~\xa1\xdb\x0b\xca\x95\x0b\xbcQ\xd5\xa4\x97\x82\xfc\xb7\xd8\x0d\xd3\xf8nw\x88dj\xb8w\x9c\x12\xe1\xec\x1a\xa9\xb0\x06+\xab\xabta\x1a\xf6<6\xf2\xfeA\x98\xa7~1[<\x8f\xc3\"\xf4\xa3\xef9\xcb\xaa`J\xc4\xc3n\xff (\xf8\x12\xf1H\x13\x9c\xa0\x9f\x94\x05\x1b`\xc1\xbaz\x01\xb4\xcd\xc8\x9c\xde\x04B}E\xcehs\x13\x06\x8a\xcf\xe7\xb0\x0f\x01L`\xae\xffhU*\x15\x18\xa5\x8azu\x83\xfd\x86z\xef\x9d\n\x1f(\xa5\x1dZC<\x18p\x07\xc9 \xb24\x9d\xfd@\x05'yRf32\x81es\x04\x86\x83\xb2P5\xd3\xbbW5K>\x01_\xc1p\xcb\xfc\xf8\x04\xcan\x0dr\x99\xfaq\xf0\x8c\xa4\xc5b\x02#\x85t@\xf0\xdbJ\x01\x9c\x80\xda+a\xb8\x83$\xac\x02\xf8jA\xd8\x9c \xc2d\xe2WQ\x9f\x13&z.\xe4\\w:3Y\xfb\xa3!\x12j M\xd5\x15\x90\xd58B\x96L#\x06\xec\xdd\x19\xe8]\xe9 \xefz\x8c\xa7\x15\xe9\xa2\xad\xd2\x90\xbc\xc5\x14\xeb\x95\xb0\xaf\xad\x9e\x18g\xcc\x89\x9d\xee\xed\x05B\x98\xc8\x996\xedh\xd2L\x12\x03VJn\xf8\x17\x0b\x8dW-\xfa\xaf~\xb2\x19\xff\xd4\xd4\x81\\\xc9zS\x818X=f\xaf\xf2\x83\"i!\x04Y\xdbCQd2\x87Z\xd1nY\xbd\x8a\xd1\xc2\xcb\xd3(,l\xeb\xc7\xd8r\x86)\xd3\x15\xad\xc4\xf0\x186a\x9f\x1b\xb3\x11X\x87\x91\xe3\xfd\x94\x84\xb1m\x81\xe5\xc0:\x14`V\xe0\xf2\xcat\x10\xeaM\xa3\xb8\xaa\xa5\xa9\xf5\xc5\x06\x8d\x1d&/\xfa\xe5z\xd8\xb6\xa8\xa8\xf3\xe6=q\xdc4,\xb4#\xafF\x91\xb2\xe5#\xef\n\xf6 \xc5\xb7\x9f\x1b\xf13S\x918 /\xe8\x908!/\xe8\x908>/Pz\xbb\xcfT$N\xce\x0b:*\xcf\x88\xdb\xe9\xd6c\x9d *gf\xa0rf\x9f\x9e\xca1;e\xf6P9x\xa5\xbb=\xc2\x90U\xa1'L\xce\x18\xd3\xd3k\x88M\x9f\xd0\xcbI\xc1\xbe\xaa\xd5Hx\x06\x14gY\xee\xe3{?\x0b\xfd\xd3\x88\xa0\xc8c\x85\x0e\x85R;\xec#\xc8bn\xb3^(\xfa\xd3\x7f\x951O\xfc2\xcbH\xcc\xbf4\xd3j\xd5\xa4\xcfH\xf1\xa4(\xb2\xf0\xb4,\x88m\x05~\xe1o\x9c\xf3>\xfb\xe8\xac\xe6\xc2\xa9\xaf\x06K,\x8d\x05{\xd5\x8d\x82\x91pb\x83\xa9\x0e3\xa66\xc68AZ9\xd1\x97\x9f\xfb\xd1\x04|e\xf1\xb5f\x8f\xabE\x1f\xb4\xa3\x8c\xe3\xc0\xddd_R.\x97\x04\xac\x85\x8e\xe9/\xef\x04\xcd\xdc:\xdc\x00\xfa\xafh\x90\x08\xb4\xbd7T\x9cE8\x8c\xb3\xa8\\\x8b\x9f\x85\xc1\xcb\xa4\x8c\xdb\xc9\xff\xe0\xa32\x19\xdcB^\x0d'\xa4 \xbcH\xf9\xd3\x96\xebcZ\x08%>#\xc7\xcb,\xb2\xfa/^\x15Y\xd7Z\x8b\x1f\xc2(zKf$<\xc7\xcb2\x1f\xb0&\xbd\xa7|\xc8\xa2\xc4\xb2sJ\xdf\xc9^\x15\x1f$\x955{\xe3+\xf5\xdaS\xba\xaf\x1eqk#\xd0\xb5\xab\xf9\xceD\xc4\xd1\x15@/\x19o\x1e\xc6\x81D\xfc\x0d\xa4\xfc\niwyl\xc5F\xdf\xda6LF{h\x8c\x11Vdl\x0b\xb0b\x15`\xe9\x1b\xb3CVO`\xc9\xdc\xaa<>\xa2\x96:zu\xfa7\xb1[\xf3\xc5o>|\x80\xac\xc7\xb0\x11$\xac\xd9n\xa2\xf7Cf\x92\xda_\x0fqj\xa1P\xb7Zz\xe6\x0e\xd4\x08\xb7\xa7Ha\xb31\xf4`\xdf\xa9\xf8\xc4\x8c\xd3\xee\xfc\x98\x0f\xdc7\xcd\xe9\x1e `9\x98\xcf\xc9\xac\x08\xcf\x89\xf8\xd2\x88E\xd0\xfb\xaa}\x92{\xd5\x1d\xb2k\x94|\x92MgW{\x82\x06\x1e5\xb3\x04\x87\xc7\x14\xf4\xf2\xf0g\x0d\n\xe4c\xceo*\x14\x91\xd5|\xc2\x13L\x0d\xd8\xae\xbe\x93\xc8?%\x91\xb1\x9bE\xb1\x8c\xbeA%\xf3\x8d;aa\xd1\x8c\xbd\xd4\xea\x03\x04\xf0&y\xad\xeb0fT 3\xb7k\xda\xa2\x98\x00\xa6o\xe1\x13&p\xeb3\xa0\xe6g[\x8693:C\\!W\xd7\x03\xa7\xdb\xa8\xa7\xb3G\xf6\x8a\x841N\x8e\x905\xf5\x00\x1374\xbe\x0b\x88\xa3\xb4LY\x90`\x83\x8eP\xb7A\xd6S^\x0b\xde\xbd}1\xb1\x0c]7Dg\xa1\x9d\xe1\x8c\xb4\xb5\x17\xdb\xb5d\x8b\xd3\x0c\xd2y5|\xd8\xb4s\xd2Wk\xd89\xf9\xab\xdd\xa9}\xe0\xd5c\x89\x03z\x7f\x0d\xf1\x98\xce\x1a\xda\x06\xd4~\x1bC\xea\xf1\xdb\x95\xc4\xe5\x12\xcd\x11ns\x8e\xe9\xd3\xe2\xe8z\xaf\xf9\xfa\xec\x13\x13\xcfkZ\x8e\xc6\x14V@\x050`\xbf\x06\xa2\x03\xa8\xe2?\x92`B/\xf3\xbd=Hl$\xa6\xfa\xa9\x1c\x86\x1a\xfa\xeb \x9cc\xacH\xb1\x87\x89\xfaq`\xa2\x9fm\x88\x96\xb8}\x93\xe5\xa6\xb5\x05\xb9T\xf1s\xf2\xc3G\xccW\xa2\xcf&\x0e\x86\x83\x83\xb9\x91.\x0c\x9a\x16D\xeb\xf0Q[Ctj\xf4\x88[\xeb\x05\xee\x13\xbb\xce\xf1\xed\xe7&v\x8dtb\xd7H'v\x8dtb\xd7H'v\x8dtb\xd7\x88\x89]\xebQEL\xc0\xaa\x12\xabF\x9f^\xac:\xbb\x8dXU\x12\xac(\xa4\xa7]\xad\xadVy\xdc\x92Z\xdeJy|+\x11\xcf\x9dr?}\xbcM1\xc4)F\x19\xe9\xa3\xa6Q4\xb7\xa5\xeb\xb5\x10\xb2\xa5\x98\x81I\xdbMk\x1f\xa1w\xee1+\xa4p~\xe5\xd8\xed:\x15\xd2\x17\xb0>GI8\x962\x0fE4\xe5a\xf3\xe8\xe3\x9d\xb9\x8b\xdb\x0fYX\x90\xd7qt\xd5\xc0\xbc\xedG\xa7\xabp%\xb0\x1f\x0c\x08\x83\xa1\xb7W\xcc\xc0\x80\x96\xe9\xee\xaa\xd3g\x02\xd9\x85\x1f\x07\x11y\xbd\xea\x88[\xa0;\x14\xd0(\x10\xdf\xfb)O\xe2{\xa1W\x90\xbc\xb0\x0b\x16\xc0^\xb6\x1d\xe0yf`2\xc8\xa6\x00VY\xbe\xf6\xe17m\xaf\xbc\x91vlX\xc1\"9;\x8b\xc8\xf3\xfc \x08\x8b\xaf\x93K0$\x99\x91\x1f\x19\xbf\xb2\xb1\x0f[y\xe9\xdb~\xb9W(F5\x815\x8c'\xc0\xfe2~\xa7\xb6\xc0\x84\x1e\x98\xc7\xa46\x9d\x08W\xf2#\x8fE\xe1|!\x9e\x0e\x82\xd6W\xe5\xa7A\xa3p\xa4\xc3\xea\x14t'w{f\x1bV\xb2\xa9\x80\x15\xf8o\xfa\x08\x05u\xe3\x16\xaa/\xf1\xc1*S\x1d\xf6[\xdd\x02\x02V\xb1\x82\x001\x85\x16\x9e\xe0\xb6\x04\xf5\xdf_~\xa9\x9e\xaa-Ur\\X\x93\x1a\xab\\N\x18\x11\xd8\xf8\xb3\xd2\xeb\x0f@\x0b2d\xae\x8e\xf1o\xbc\xd4\xcf\xc2\xe0]\x1a\xf8\x85.\x08\xc2M\xd7X\xa2\x11\xf8*\xcbo\xb4\xeb\xac\xda\xa5;\x9a\xb2V\x10\x05+\x1e\x86a\xeaxXA%\x0f\x15ie\x88\xb6\"?\x99P\x9f\x0f\x101A\xa5\x9f\x1fx?\x86\x98O\xce\xfa\xba,\n\xb3c#p\xba+\xb3\xad#rY<\xc9\x88\xd2\x15M~JV}\x11\x9e-\xa2\xf0lQ0\xb0\x9a\xf4T\xe1\xee\xab\x97\x9ef\\zz\x13W\xe0\x81\xd2\xd3\x94U\xcc\x0c\xa3@\xf2\xad\x8f\"\x1f\xaa\xf0\xd5SK\x91M\xcer!9\xee\xd9'\xc7\x85s\x13\xa3a-vk\xab\xe7*o^`\x19XS\xbfo\x99fC\xe6%b\x11\xa8\x82R\xf4\xcf\xe9\xc6c\xab|\x13\xf8\x94\xdfqH\x9bX\xb8Rz\xfe\xb4\x15\x01\x15,\x17\xce\xf1_\n\xa2\x06 \x83y8\xbd|\x1e\xacd\x17\x0b\x9ck 3\x12\xe0\xed&\"b\xf6~\xc5\x08\xa2\xfa\xe0\xf5\x7f\xd1q\xae\xe8\x91\xc7\x00\xdb\xbb\xbb\xdc\xbc7~\x9e_$Y\xb0\xf2\xe6\xfd\x11\x9fO\xb1w7\xdb\x0d\xbf,\x12z\xddG\xa4\xa0\xbb\x12\x93\x8b\x8d\x94\xcfu\xc0\xd7\xb1\x08\"8\xf8\x0b\x0ea+|q\xf3\xdd_\xe8\xfdkz\xc2z\x88\xa7\x07\xdd\xe7C\xf6\x85>\x84^\x9e\x83,\xe4\xa1\nf\xda[\xd5\xe0\"\xc8\x8a\x0dF\xf4\xda\x12\x11\xb6\xe4\x94\xf8\x19\xc9\xf8\xbdj\x82\xf7\xdf\xe9\xc6\xc3\xe1\xdd\xea\xca\xbb\xf1u\x87\xd7B\xf0\xd9]u7\xba\xe6\xee\xf6\x8ac\x16\x89\x16.\xcf\xe7\x86\"\x87_m\xab\"\x9c\xbb@6w\x81h\x86#\x99\x01\x08\xc6\xe8\x7fl\xda\xa9a\x08\x81,\xfb\xeb\xd4\x11\xab\x12\x0c\xf6\xfe\xed\xd1\xd1\x1b\xccLK\xe2\x82\xcbR'P\xc6y\x99\xa6IV\x90\x80IR\x08\xa5\x97\xac\xffh\xc1:\xa4\xb0N\x7f\xddN\xfc[\x0f\xaf\x16\x017W8\xed\xb3e\x919\xf6.{\xd1\x002\xb9)c4r\xc6\xab7-\x98\xf4\x1b\xcf\xb4\xab\xccLH_+D\x0b\xb5\x1e\xd5$3c33\xf1e\x95\x82\x92\xaf\x1d\xcf\xe9\xc3\xc4e\xfd\x02$w\xb3\x00\x9d\x99\xa8\xb2\x92\x1b\xb3\xbe\xd1;'O}J\xe3\xd6\xab\xa7\x96\x1e*s\x9d\xd1\x01\x9d\x99\x00\xca\xb4\x9cd\xc8r2Q\xbby9\xd9\xc5=h9\xd9\xeau\x86l\x17\xd5\xec\x15\x06\xb7\xf54\xe5\x15\x87\x9e\x94\xbf\xe2\x11\xa4E\xefT3\x96g\xbe\x17r\xe2\x95\xa7*\x0f\xdbp\xdbK\xd0\x90\xd5\xd0\xa0\x1fL\x15\xe9G\x0d0tM\xb4k\xa9r\xbc\xfa\xf4\x07q\x05LT-\xa7j\xe4\x03\x82\xc8\x19h;\xe5)T\xc7\xa9Q\x07\x8d\xcb\xebxn\xd2\xd5\xe17\x12\x08B\x87\xa0\xba\xbd\xfa\xf2ws\xf6MZY~\xfbp\x03\x85\x82\xde\xaaYGW\xa7\x06 \x96\xf7\x95R>k\xf1\x80$\xa1\xe7\xbc\x8d+u\xe5;pKo\xea\xa2\x11[p\xb8;t\xdb\xa1\xba\x9eT6(\xc2\x9b\xd6\xa3Z4\xa4*U\xef\xfe\x8d\xe2Yw\xe5J\xffhB\x83\xed-\xbd\xd4`\xab\xc3\xd3\x87UQ\xc7\xad\xd9\xaf\x8a\x1e\xe8d\x07\xdb[\x0fu\xd2\x83\xedme\x8ckV\xf4yX\xf2\xc9\xfb\xd9lHX\x8dHym\x9aSyR\x16\x8b\xe7\x05YJ\xb9\xc7\x9b\x15\xea\xec\x0c\x93ZR\xd0\xacR\xa7\xa26\xa6<%3\x1e\xb6\xd0\x9ba?\x98\x90\xeb\xeb\xab\xe7\x01\x89\x8b\xb0\xc0\xa06b\x08\x7f&W\xa8*\xc2\xbe;\x8db`mQ\xf5i\x12\xe7\xe5\x92\xe4?0\x01\xd1JB\xfb\xdea\x17\x8aa\x8b\x0eQX\xe0\xd8Ek\xd0\x9a\xe12_\xcf#\xfft\xd0\x00\x05\n\x97\xd2\xf2\xb1\xbc\x0f\xb0\x8f\xd1\xe0z-%\xea\x0f\xbf\x0f\xf3\x10\x85'k\x9bj*\x8d>\x14FN\xfd\xd9\xfb\xba\xb2:\x1c\x14\xa2QK\xd4^uP\xdd^\x0cCR\xcd\xc00(FO\xab\xd7\xde\xec\xc2\xa5\x98\xbbzT\xca5U\xf6\xa8A\x1f\xf0\xb9j9\xf4\xbb04z\x04\xd3n%\xf1Qv\x95\x94\x05:\x07\xeb+'\xbc2\xf3g\xee\xa9\x1cr\xbd\x99X{}M\x96\xe5\xd2\x8f\xa2\xe4\xe2(\xbbz^\xbc.\x0d\x96P,\x87e\xc1\xeb\x1d\xc4\xfei\xa4\"\xd5\xc4\x83\xf1\x1f\xbc\xb9A\x0b\x12\xad\x10\x0e#\xa8\xebb\x1ag}\xcd\x05\xd6\x1c\x18L\xf6\xbc\xaa\xdc\x1b\x1fv\xc9\xb6`H(\xd9\xb3\xaa\xea\x80!\\UZ\xce\x97\xa8\xc5\xd4\xd7<\xad\x06\xfb\xc6\xa8\x13=a\xdd\x0b\xad\x8e\xbe\xe2\x05\x86e\xaeQf\x8f\xc3\xd8\x01\xab. \xa5?\xd2\xc8%\xfb\x80\x07\x85;BZZ_\xfb\x90\xd5~Z\xa1\xca\x1e\x0f\xb0\xa7\xac\xfe\xdb\xdaM\xbc\xef\x8b\xf7\xb0\x07%\xa5m\x0c>\x7fO(Q\xe5\x859e\xbe\xf4\xb5^\xc3\x1e\x9c0\x16ArS7\xcd\xee\x0d\xec\xc1\xa9\x97G\xe1\x8cP\x9c\xb51rx\x82\xef\xc6\xf7F\xe5\xdf\x8dS\xad\x1a\xb4oZ\xcd\xcd\xc7\xe8\xacO\x05w'}\x0eP\xf5\xdd\xb8\x9f\xd5\x838T>~\x155\xd3\xcc\x1c\xac\xfdX# \x02\xc5l\xc3\x82,\xc1\x82u\x9e}\x8b\xd9\x93v\xae^\n\xf7\x96\x8f\xaa\x1b]2S\xc3\xca\xac\xa0\x13\x1c\xa6\x04\xd5\xf6\xc4#2W>F\xf5ZQv\x86\x1f\xba\x9a\x9er\x0c\xd9x?\xd1~J\x83\xf9h\xdb\xd9\"\xb9\xfe17\xb3F\xedR\xcce\x17\xcd\x9bu-\x1c\x98\x06J\x18\x0d\xa2\x14\x8b\x88\xa7A3\x193=6H1]r 9K\xb3\xf1\xb4\xdd\x02*\xe5\xf5\xaf\x1b\x1e\x10r=\xf4fI\x19\x17\xf6\xad\xceD\x0b\x1c#2\xa0cmg\"7\xcf\xb0\xee$\xc4\xb8zO\x14\xe7W\xa0\xa6\xaf\x96\x0d\xa8\xb3\x18<\xe2Y\x12\xc1,\x89N\xd8\x85\x03\x8d\xdd\x8aN\xd0IK7\x13\xeb\x15\xbap}\x8aq\xc8nO\xda\xe1<\x93}\xa3\x1c\xe3\xb8\x1a\x99\x94\x06\x99P\x82\x8c:%\x9f \xee7\x9fV]\xbd\xf4S/\xcc_\xfa)\xf3\x17R\xd8\x1f\xd2\xe7\xda\x0e\xa5\x8e\x07&o\xd2\xcd\xe7\xa2\xcf\x8fh\x1e\x1bc\x95@G\xcaj\x88ZB\x1fA\xc1O\xe0\x94\xd1\x80}\xd9\x84j\xb6g\x02\x06\xfe\x80>\x99\x7f\x81W\xe6\x04z\xe2T\xa4\xac\xd6\xa2F]?\x84\xc8\x82\xf8\xb5|\xc9\xbe\xc2\xf4%\xc6v\x98\xdb\x94\xec\x94h\xae\xdf\xcc\x04\xd4\xe7\xa3#\x7f!\xa4H\xf2\x97-QV\xff\xbaK\xb2t\x03\x07%jsNo\x02\xe7}\x8b)\xb8\xb7 \xf4\x04\xd7\xaeBEN\xe0\xbd\xb6\xa2.^h#;\x1c\x06\xd8\xbb\x0b,\x7f\x13\xe31m\xc7i}\xdd\xbfJ m\x90o0\x01\xcbj\xdc\x9bm\xb2\xe6\x8e\xee\xad\x8a\"\xab\xef.\xb8\xcbY\x1e\x1a\x07\":\x9f\xf0\xb0\xe2\x98Z\xb2K\xb8\x1a\x0e\x8a\x8c!\x14,c\x1f\xc1y]-\xf5\x13\xdb\xa1\xa4\xe2\xeb:t\xab\x9e9\xb8\x93\x95\xff\x87d/oJ\x0f\xd7\xe0}\x82w=\xa3\xda_\xd7r\x01\x8c7\x80; \xfd\xa9\xbd\x81\xb9$\x03#%\x1a \x83\xa6\x87\xb1\xae\xda\xa5iN\\\xe6y&\xe2\xfb>\xade4\xdc\xff\xe8\xccmk\x8a\xafL + y\xf2 \xf05\x10\xe9\x00\x1c\xef=\xb9\xc2\x1b\xdfH\xa8\xf3\x8b\xa1_\xd8/\x9e\xa5\x97\x93\xe2mg\x06\x03r\x1c\x8bh\xf8fd\x0dm\xdcn\xacmr\x0f\x1e\xc6\xfeI\xd1<\xf9\xd2m\xa0\x06Zw\xcaM@r\x93\x83t\x17\xb8\xf1\xa9\xd1,\xb7Blo\xf4+\xd2\x08\xfc\xf8zP\xbd\xef[\xe0\\\xbd3\x01s\x9d\xf8\xa1/\xf9\xaf|i\xaf\x06\xc1\x03\xdc\xdc\xb5\xa6T\xedG\xa85W\x9be?\x84\x03W0\xcck\xea\xdb\x8e)\x0f\x19C\xe3\n3D\x9d\x12\x0f'\xb5\xe5sY\x0dr\xc0\xa9\x84\xd5h)\xf1\xf0\xc3\x9c\xd0^\x9f\xc7L5\xd4\xfba_\xa4\x90\xc1\x88g\x95 ~Fh\xa7F\x97\xab_\x03Z|t\x03\x8bo\x95\xa5\xf7\xb9\xe8M\x1dD\xb6%\xa9\xe9\xcb\xb5\xd4\x12\x01\xf5Uoi\xb8\xba\xda\xcd\x86\xbe\xac\xab\x92\x95\x94\xdb\x13\x98\xd6!SZ\xf1h\xe9\xaa\x06\x06\x1b\xaf\xf3\xcf\xd0\xa8\xc6e\xa6\x0b\x1d\x03\x16\xcc)\x95\xc1\x1e$H\xecdM\xd3\x91\xccl:\xd2\xf4\x93k\x81\xac_[\xe8\x89W\xab\x98)\x0e4\x94SZ\x83\x85\x83\x84\x9a\xbaZ\\?\xadod\xe9G\xea$\xedyq\x15\x11\x9de)%\xfb\xcf\xb2\xa4\x8c\x83\xa7I\x84\x19\xdc\xff\x7f\x0f\x1e\x9e\xce7\xb7\xbb\xf7t\xeb\xe4\x19\xc6\x92fj\x19\x9dL\"\x9c3\x1bx\xab\xdd\xa8E\x17\xdf\x92O\xfegj\x0d\xd6\x03E\xd9\x10(\xd2\xd8K5\x0dj?\xcf\xe9\x07\xdax\x16\x81\xce\x18.\xd0\x19\xc3\x05:c\xb8@g\x0c\x17\xacf\x0c\x17\xa8\x8d\xe1\x82\xda\x18\xae\xebd\x93r\x0f\x81-\xa5\xb1[\xf0\xe9\x8d\xdd\xcc)\xfe$c7\x15\xed'\x19\xbd(L\xde:\x9e\xc2\x83M\xdbn\x95Q\xf8\xf31\xbf\xe93\xae)jO\xe0\x1es\x11JPO-t\xde\xd98M.\xadc\x03}O!L\xeb%\xcc\xd7i\x8d\xf9M\x88\xe0\xc2\"\xeeX\x9a\x91\x99_\x08i\x80\x1dsI\x8e\\\xc0.\xd7>U\xda0\x86\x8e\xcd\xa7n}\xe3\xc2\xcf\xe20>3\x89\xffE\xdd\x89uW|e\xec\xfd\x94\x84\xb1m\x81^\xe8\x91\xe8{J\xbd\x97t\x16\x1d\xfa\xf3\x97kW\x86\x01\xc3Pd\xb9\xb9\xc9\xb6\x88\xa4\x94#5d\x0b#\x97\xa9\x1f\x07\xcfX\xbd\xbaoOzO\xcf\x9b:\x01\xd4\xcd\x1c!\xfb\x1c \x19_\xa6\xbf\xb3\x16\x9f\xe75\xf4\xef\x0e\x1a\x9f\xad\x83\x86\xc15C\xaf\xa8\x890\x91c\x97\x89\x02~\x93\x87\xde<\xc9\x96\xbe\xa2_\xee\x92\xc1\x03\x9a\xab\xfd1\x84K\xd7\xda\xde\x1eD\x18\xd9\xfb4\x8c\xfd\xec\x8a\xbd\xc1\xecB\xd6\xa9\x9f\x93\xddm\xf1F\xef\xa9\xc1@_\xef\xd2\xa0\xf4\xe4\xe0\x01\x12\xe7\xa12\xdd\x90\x84\xeaJ\x1eS\n\xf6\xc1\n\xe3s?\n\x03\x8b\xc9\xe0\xbbm\x86E\xd4\xfc\xa2\xd4\xd4\\E$\x9a\xdbU\xcaK:\xda|\xba\xa9\x08\xd2\xaf\x90\x07\x04a\xce\xd9\xdc\xc2\x0b\xf3g\xfc\xaf\xe6a\xf8\xcch{\xb7\xca\xbd\xdfL\xef\x0duR~\xe1\xe8\x9e+\xde\xd5u3\x92\xa7I\x9c\x13I\xea\x01R\xa6\\\xcd\xebJ\xde\xc3\xdbnEN\xd2\xb9\xcb\xc6\xf6}\x05\xd6\xd3\"\xb7P\x8b\xdc\x8c\x84R\x15\xf0\xacP\x06<\x8b\xab\x80g\x94\x88\xccX\xc0\xb3\x0c\xbe\x82\xe2\x11d\xeb\xeb\x0e\xc4\xd3\xac\x19\xf0,\xd3\x07<\xab\x15\xf0&\x92\xadJzwx\x95\x17di;M\xdb\\\xfc\xeb\xbb\x9cN\xc7HW1Z\x96\xd9e:v\xc6r\xbf2j\x96\xad8?\xde\x0d^L<\xad\xdb\xf6\x0f\xdd_\x8a\x8d\x0c\xcd\xd1J\x854\xb6\x80}\xc0\xd4\x18\xcd\x06\xacc`\x81t\x9b/\x95x\x0e)\xd5\xe7\xb1\x1d\xf3\xec\x05-XW\xc0]kl\n\x03\x88V\xd3Sag\xfa\xcc/|\x8b}\xe22\x85\x03\xcbZr\x8c}\xb78YWw\x18\xee\xaa\xffn\xe3\xa6\x81\xa8N\xeb\xdd\x8d\xa4\xd3\xba~(j\x84\xd2?\x14q\x1eT\xae\xcc\x98\xb8\xa1\xbe\xf0\x84\x0f\xb3\xd6\xc9:\x91P\x9b\x9are~\x00Ul*\xc59\xc6\x80\xa2\xfb0\x0d\x11|;s\xc2\x98\xcf.\xc4\x02\x94\xf5\x15\x9a\xe7\x0bH\x94\x13\x15S\x8b\xbc\x96\xa6\x9d\xa2\xdb\x8ei\x1b\xb3a{\x93\x0f?\xc8\x9f\xc9\xa6\xc4C6\xc5\xbc#\x03\xb7#6n\xc7\n{\x11W\xaa\xb4\xcc{\x9dq\x17\xf5\xd4\xb1\x1d\xe5\xd6t.\xed!\xfb\xe3Br\xbb\x9d {w\xc6\xef\xdb\x99\x84\xc5\xddeq>\xf7k\x84\xe2\x9b6\x8a%#\x17\xa8G_M\xb5e\x08Mn\x9d\x82\xa8\xa7\x89G\x9de\xa3\xb4}\xa2\xbcrl\xdah\xac\xd9\xb6\x81\xb1\xbai\xeb\xa5\x97\x914\xf2g\xc4\x8e\xc9\x05\xbc%g\x07\x97\xa9m\xfdb\xc1:`D\xc6k\xcb\x05\xeb\xccr:*9\n\x11\xa5\x04\x1f\xf8\xf3\xf7\xa5+\x95\xca\x8e\xd2\x8e\xedqG\n\x1a\xf2\x92Q'4\x0fSX\x8c\xb7v\x95T]\xf9;\xb2\xac\x14\xfb\xfer\xed\xb6\xa5\x82\x99\x0b\xbe\xf7\xee\xcd\xb3'G\x07'\x87\x07/\x0e\x9e\x1e\x1d<;9}\xfd\xea\xe8\xe0\xd5\xd1\xc9\xd1\xdf\xde\xfc\xfbZ\xaa\x88\xe0\xd5\x16\xf5\xf0\xcd\xebW\x87\x07\xbf\xcf\xaa\xeadR\xaa\x98\xac=\xeb\x91\xb8\x10\xeaH\xf1U\x16\x84a\xaf\x93\xef\x9f\xbc}\xfe\xe4\xeb\x17\x07w{du$\xc4 \x0c\x16{\xef\x89\xc2\xa8\xc5\x17K\xad\x069 \xef)\xef\xfe\xcc\x85\xd0H\x11b\x05\xe3V\x94.\xf8\xcd\xf5\xcdnq%\xd72\x8fQ[\xbd\x97\xf0\xd7;\x0f\xa4\xfb6\xa1\xcb\x82y\xf4\x92\xec\xc0\x9f-l\xbdh\x01\xe9>\xef^\x18\x07\xe4\xd2\xfb)gr?-\xd5Gw4\xb1U1\"\x88G.\xd3$+\xf2)#\x80R?\x9f\xf9\xd1S?'\xdf\x84\x11\xa1\xdb\xe8\xd8\x85s\x8c\x1b#.\xd1}\xe9w\xdbAH\xba~\x07-\\loo\xefR\xb2H\x8c\x03\xd7eg\xb43\xe8k\xc3\xb2\x0b\x1b\x8d\xad\xb1L\xd0\xd4\x11\xbd\xecU\x0c5*Z#\x93\xa6W P\xdfd\xc92\xcc\x91r\x89\xed\xed\x9d\xfb\x8e\x0b\x87H\x91\xd7\xa65^^\xf8Y\x91\xff\x102\x0dIlo?\xd8\x1d4\xc3\xd8~8FM\xef\xc3\x07\x9dU\xda\xde\x19\xd6F\x1fpno?TB\xe7\xf6\x8e\xca\xc0%\xb6\xef\xb7_3b\xef\xfeHZ\xe9\xe6H\xc7[\xf7\x1d\x1b\x05n.X\xf8\xaf\xd5\x83\x87P\xbbt\x82\xd2;\x9b\x08'\xb3\x13\xda\xff\xa6\xf8\xe3=ES\xf5~\x18\x92x4T\xa6'\n!|\x15\xac\xe0Da\xd7\x18W\x85\xe1\xfa\xba\x12{\xac\x11\xdcTxL\x19\x94J\x9cm\xd7s\x10\xa2\xb9\xc4\x1e\xa1MzB\x0f\x9bE\x0f;\x8b\xd3\xc6\x8d\x0cYZ\xd9\xfa\x1d\x992\x99C\xec\xe2O\x89;\xbav\xab\xcah]\xf3D\x08*Q\xd7\xc0W:\xb3Y\x17\x0e\xfe\xac\xabg\xb6E\xe2\"\x0b\x890\x9co\xc3\x8f\xbc~\xf2F\xca\x0b\xac\x8e\xd0\xd8\xfb\xa5j\xaf\xf9*\xaaP\x17\x8b\xb9\xda\xdd\x93 \x89)\xdb\xb2f\xa6\xfdoy.F;\xeas\xf1\xb0\x1d\x95\x91\x1d\x8b\x87m\xc1\xb6\x8f\x9c\xc6#\xe9,\xeflb4\xf3\xd8\x1e=tl+,H\xe6\x17\x98CV\x0f\xbb|q(,\xd5\xb3k\xa1\x82>y\x1b\xa9\x11\x11\xc6\xef\xf6U:\x9e\x98\\\x16\x142Gn;u\x00\xed.\xc4\xb6)+\x0b\xcf\xaba\xaf\xb6\xdc\x12\xc2Q\xdf\x86[\xbb\xeau\xdd\xd5\xe2\x95\xedm\x07\xf6\x95\x9coHr\xe81@N\xecv\xa2\xa1Jk\x10\xbb\xb8y!\xaa\x07\x90\xda\xadT\x079S\x16\x94\xf0\x18\xf2G\x0ed\xde\xdc&\\\x182\xcd\xd7\xd7\x8f](\xa6q[\x08!\xa8\x8c\x9b.\xd8\xfd\x91\x9a|\x18\xa9!q{g[\xb3duw\x1a8\xab)\x0e\x96wFGQ\x94l%\xf4q-#$9\x84\xcaES U\xa3\x14\x1c#\x05iBI\x1cv\xa9\xc2\xda\x9e\xde\xb5\x117\xed\x11D\xf0\x18f\x8f\xf46\xc0\xb45\x9bne>\x9d\xad\xaf\x1f;\xb4\xcd\xd2\xa9\xcdU:\x1f2\xe1S\x7f\x970[_\xef\xe9\x16\xaf\x87\x19\x841\xe4Ho\xe4\xd3\xd91\x0b+\xea\xd4r\x0f\xac\xf2\xe1\x03j\xa2\xaak\xe5\xcb/a\xa3\x19\xbbhE\x1c'a\xb3]\xd5\xa9{\xe9\x17\x0bo\xe9_v\xc1\x88\x95\x84q\x1f \xe9\x11\xba\xcd\xb0\x0dq\x1c\xf8\n6a\x9f\x9e8X\xa7C\xdc\xa4\x97 C)7F\"\xea\xf9P\xac\xbds'\xc0\xaf\x83\xfc\x10\x83\xb8SHbD\x9eM k\x0d|\xb3#\xa2\xf3k\x8dPp\xc8\x0e\x88B+\xc1\xc6\x94\xe3\xda}\xf8\x009%/\"\x14\x87\xf1X\xb4\x9c\x9a\x9d\x80\x8dr8o\xb6\xf0\xb3\xa7I@\x9e\x14v\x8ek\xbe\xb33~\xb8K\xbf\x0d\xe11\xec\xecn\x8d\x1e\xb2\x86\xd6a\x84\xe0\x87\xb6\x04\xb6\xdf\xf9\x98V`\x0d\xecn\x8d\xb1s\x9f6p\x7fk{\x8b\xf7\xcf\xeacGt'a\xc2\xdf2/\xbd\xdc\xc5N\xc6\xb4\xcc\x87\x0d\xde\xcc:\x1d\xe7\x06\x1f\xd4W_\xc1h\xd3\x81u\xd8\xdd\xd9\xd9\xda\xbd\x1b\x08\xef\xdc\x1f\x1c vu\xd8\x90\x02\x8b\x83\x12e~\xa5\x0d\x8a*\xdc\xbd7\x90\x19\x13\x1f\xb6\xc4\xf0\xc5\"K.\x802\xef\x98%\x1dO\x80\x05a\x0eqR\x00R\x00\xa7\x11Y\xd3X~dv\xc1\xa2\xf0\x11g\xc5sB/\x81\x07\xc88\x8c\xb7\xb7\xf1\xdf\xed\xdd\x87\xec\xdf\xfb[\xec\xdf\x07\xfc\xfd\x83\x9d\x0eg\xb1\xbb\xe9\x08\xaefHg\xbd\x84\xd4\xaejgd\xd2(\x99\xc6\xf6\xe8\xbec[E\xc2N\xd5\x91\x7ff!\xdbi\xfdlQVn\x9d\x82\xfc\xda\x1eX\xd3\x04o{\xf8\xf9\xd8b\x0c\xd7\xfd-\xc7\xe6\x14@\xed\xc9\x00UCV?mU\xb5\x89\xe9j\x90l\xa7\x90i\x1dK\x1ah\x0c\xa94d-\xe4\x85\\\xa3\x1c\xfe\xa6\xc32\xac\xd8\xa3\xcdQ\xbf\x0d\xf5}:I\xb5(\x9f\xae\xe3\x03\x87Y\x1e:.X\xbe\xd2\xfe\x10\x83ik{i\xf7\xd6)l\x99\x088\x9e_\xaf\xc1\xa0\xf9KDK?\x11\xa2\xb8;0)\x0d\xbb4\xc4\xd5\xf8\xa8s\x0c\xd5z0Le#\x9d\xc3*\x02\xb6\xcdTG\x02$\xd8\x86d6\x13U\x89\xf3U\xf5\xa7\xd2\xb0\xe9\x1bE\x1e\xe5\xf5|\xf56\xd7>\xcep\xdb\xf8\xc6z\xea\xc7\xff\xb1\x80Y\x12\x9f\x93\xac\x00\x0e\xe9E\x02i\x16.\xc3\"<'\x8c\xcdZ\x95\x9a\xef;\xf3\xdb\xbbm\xc91\xc3\xc6\xe3\xed-%\xcd:RJ\x15Z\xec\xd3\x03\xc1>\xdd\xff\xef\x99}\xd2\xb0\xa5\xdb\xbb\xea\x95\x1dw\xc48>\xc7\xca\x94 }~p\xf2\xe6\xed\xeb\xa3\xd7\xed\x80\x15e\x9b\xdfo\x16\xb7\xc5\x01\x9d\xf58g\xb9+\x0b\xde\x15E\\\xe1<3D\xc6@+\x0c-5\x84$w\xe1\xa1S\x90\x17\x84y\x1a\xf9W\xf4v\x88\x93\x18\xf3E\xdb\xe3\x9d\x11\x9a\xf5\x938x\xba\x08\xa3\x00Y\xb7\xc2\xcb3\xcacX?\xf9\xe7>\xf3\xe9\x9dXU\x16J\xee\xfb\xf7C\x18\x07\xc9\x85\x17$3\x14\xa18^\x92\x92\xd8F\x18\xb9\xc8\xc2\x82\xd8\xd6W\xec\xd3\xc7\xa2\x8a\xf7\xcd\x1eC\xd1_\xfdx\x8f\x17\xa1j\xd7\x9bEI\x8e\xe9\x0ds<\xc1\xdf<\x82lc\xe3\x91\x03\x01\x89HA \xaf\x01i\x1aN\xb3c\xbdMYn\xb7`H\x8dI\xf9E\xc1,8)\x9dfD\xad\x889\x95tF\\F\x11J\x90)\x15g\x97-x'\x0ecpcrA\xf9\xbef1s\xff\x8aYZ^\x82\xa6g\x98\xd5\xc2qei\xab\x90p%v|+\x9a\x7f\xa46\x1e\xec\x9c\x08\x0e\xf9\xdb\x0f\xf4\x94\x1f\xbd\x98\xff{\x90\x1d\x8cF\x0f\xd4d\xf1\xb8\x8d\xa0\xb9\xf0`w\xd7\xb1\xd7\xda\x02\x075\xca\xb8\xc1\xfd\xce\x97\xa8\xe4\x84t\x17\x17\xe0\"u_Sfiz\xacX\xf3\x98\xf2\xd5\xa5\xc3\xa4\x04>\x8a\xf31%<^\x9b\x91\x88,\xa4\xf8\xf0\x11\x14BX\xcb\xf7\x03\xbf\xa3\xa8\x01w\x83\xb9\xa8\xfc\xa7\xd0\x8e\xb0\xb5\x0f\x1f\xea\xd6\xd4[\x14\xddt\x8b\x1e>\xd4\xac$\x83N\xdb\xfa\xd9r\xd0\xd5\x82\xd2\x81\xcf\xf3\x83\xb8\\2\xbe\xc1\x96`\x18L\xe6\xd1\x82\xd2=\xac\x93\x83\xd0s\x8d\xe6;y\x1a\x85\x85ma\x8e}\xde!\xb9\xf9 \xed@\x95\xd0ti.\xa7m\xdd\xdc{'\xd3\xe0\xd6\xff]T\xf5\xdf\x92\xa8J\x83\xb2\xb6w\xdb\xef\xc3\x01\x94\x8c__\x94\xd5\xc5e\xbcN\xcfH\xf1FT|=o^\xab\x1aX$\x02\x9d\x01fp\x0e\xf1dMQ\x1b\xad\xa2\xf0)\xa9\x90\xc4y\x91\x95\xb3\"\xc9\xd0\xe4 \xc28/\xfcx\xd6-\xddo\xfe-\xdd\xbe\x93\xe6g\x1c\x0f\xec\x83\xdf6\x00_q\xfdw\xb6nz&9\xfe\xc8V\x17XT\xf7'g\x1f(;P\xb1\x0c\x0f( \xcd\x98\xca-\xc7\x15\xde\xf0[\xfc\x82E\xc6\x80'\x8f\xb5G\x9bc\xc7\xe5>\xb5\x94Z\xc0\x83\x1b\xb5\xb8\x05\xf6\xaa!kp\xd1s6\x17\xba\xb3\xa0\x13m\xe1\xe9\xe1\xe1\xdb2\"/\xc2\\\x11\xec\xe0\xe9\xe1\xe1!%M\x9f\x91Y\xe4\xb3x\xd3\xdd\x80 O\x0f\x0f\xd1\x14\x817\xd1.\x8dB\x12\x17o\xc9\xacP\x97?{\xfd\xd2X\xc8\xe6\xa2->J\xde\x93X=\xf8g~\xe1\x1fe~\x9c\xcfI\xf6\xbc Ku\x1b\xdf\x84\x91f\xe4\xdf\x1e\xbd|\xf1$\x8a\x9e&Q\xc4\"P\xa9\xab\xf4\x95\x7f\x93dK\xee\x85\xa4\xae\xc0\x9c%\xb4U^\x92 \xf4\xd53|\x19. e\x89qs\xbb_\xbe\xf2\x97$x\x95\x04\xe4\xa5\x9f*J\x93@\xb3\xebo\xfc0\x16\xe1O\xd4K\xf3&*\xcfB\xc5|\xd9{\xcdp\x0e\xbf\xff\xd3\x0b\xbc\x8a\xd4m\x1e~\xff\xa7W\xe5\xf2\x94d\xda\xe27\x98%X\x03\x0b\xb4< c\xcd\x80\x0f\xbf\xff\x93 \x90\x0e\xbf\xff\x13\x83\x94$\xd3\x80\xc9!f\\\xfb\xba\x9c\xcf\xb5\x03\xa4\x07\xe5pAH\xa1^\xd5#rY\x1ce\xfe\xec\xfdS\xddQ\xa9jh\x8a\x93rV\xad]Ur\xed\xa2+zb\x07\x945a\x94\xf89|\x05\x0b\xc1s\xc2\xf9\xfa\xba\x8aZ]\xba\x18\xc9~1=W\x18\xbcQ&4\x98\x9e)JN\x91\xacW\x95\x9c\xc0\x1e\x9cR\xa4\x7f\xaa\xba\x90\x80_\xc5'H~\x9e\xd0\xfb\xf7\xc3\x07(\xed\x13\x17f.\xa4\x8e\x0b'\xd3y\xfdn\xee\xc2\x19E~\xd33\xca\x80\xa5.\xa8\xe2\xd2 r]\xd2[=s\xe0d\xba\xc4\xcfC\xfa\xf9\xd2\x85l\xba<\xae\xc5\x9b0\x14a\xf7\n\x804J\xcb\xed\xfbj\xbe\x03\x11w\xe3\xbd_Q\x94:&n\xbc\xbd\xfb\xefv%\xff8v%z\x82\xef\xbec[e\x9c\xcf\x92\x14\xbdU\xda$\\\"\xfc\xf5T\x07\xa6\x123@2\xcd\x8e\x99R`\xe7\x01\x1a\xaff.\xfc\xa2\x97\xf6u\x98\xfaiv<%\xf4\x18\xc9\xf6\xf0\xca\x99\xe8$\xfeF\xd8\xfb\x0c\xed\\\x84\xb1\xa9/(\xa9\xf1v[\xc2\x92W\xc4V\xe35\xa7\xb0\xc6\xaa\xb8%*\x8d\xcf\x9c5\xdf\x16\xd4\xb0p%\xf7\xb7[\xaf\x03\xdez\x1b\x85,8\ni\xd7?\xe7\xef\xdb\xf6\x10K\xd6\xebN\x1b\xb5\x9c\xf1\xf7[\x8e\x97\x93\xd6\xba_\xb1\xb6\x1elvb\xe1\x9dr`m\x8f\xea\x84\xb7\xd6\x1e\xd5\x05\x7f\xdf\x1e\xd5\x01R\x9a\x95\x8c\xbeYx\x89\x85i\x96\xccH\xde\xf2D?\xc4\"\xae\x98k\x16=\x85=\xb0\xf8Gx\xceg\xf6e\xab\xd7\xf7f\x89\xee\x13\xb4\xb0\xdd\x83So\xde,xM\x0f\xc4\x9aY\xda[dW\x1a\x9eW\xe0\xc8C/#y\x12\x9d\x13\xbb\xbdz\xf2\x83\x1e\x1aM\xf6g\x8f\x1ea\xa1\x1e\xccS2C\xfcr<(\x1b\x96x\x88\xfd\xde\x85\xf7z\xd6\xf7\xba\xcb\xd2\x83d\xc7\xf0\x14\xfdQU|\x1c\xdf\x8b\xb7\xe4'F\xd9\x1e\x9c\x93\xb8p\x98\x0fK\xb1 \xb1\xfd\xde\x919\xb4\xa2\xd3\xcd5\xcc\xfcb\xb6\x00\x9cCK\xf9\xd6\x06\xbf7\xbdsF\x15\xb5V\xa8\xbcf\xaf\xa5\xf4\xbb\xe6d*m\xb5\xcd\xe21\xd0a;8\x85\xe6h[\xe0r\xd4\x87\xed@\xe8\xb9\x88w\xa2\x95\x88\xd02\xc4\xb7\xea\x0d8\xe7\xb6\xcb\xc4;\x99\xa9k\\\xe95\xaa\xf2\xd3\xe0.\x89wr\xcex\xcb\x11`\x8c\x9a\x93\x9c\xb1\x97\x9b\x8c\xb5\xac\x05K}p\xc5\x85\x995\x02M`\x1f\n/y\x0f\x13(\xbc\xb9\x1f\xf6\x84@\x87*A\x14?\x1c\xfd\xd5#^\x9d\x02\\\x7fm\x9649H\x96~\x18\xab\x17P<\xfa\x13,?%\xa5?\x124\x1b\x19\xf3\xb5[PP\xf9 \x89)\xfck\x0fF\x8e+\xe2\xff\x94H\x81\xec\xa1I\xb5\x8d\x81*f\x1e\x89\x0b\x92\xd9\\\xa7P\xda\x19\xf2\xe8\x98\xa1\xd8#\x97aas\x06\x7fm\xd3au\xf6\xd0\x1b\x81\xdbX\xefCd\x1f\xd8\x16?w\x1b\xb3\x85\x1f\xc60\xbb\x9aE\xc4B\n\x08Ma\xde\xd8\x14\x82\xf7!d\xda\xd2\x18\xfdK\"Z\x9cc\xc9\x04\"[\x91\x1dP~\x1a\xe7\xb2wYp\xfck>\x9f\x1f\x9fDd\xf7\x84\xdf\xbc6\xe0#\x88k\xd9t\xf8\xc8\x01\xdf\x8e\xa7\xe1\xfaz[9 ?\xf4\x90\xa0\x90\xdc\xad\x8e\xd5\xc8\x05\xd42\xaf\x89}z\xa9\x1b\x93\"z\xe6\xb5\xe9\xf8\xbf\xec\xc5Egl\xf1s\x03\xfd,\x1eD[(\xc4\xe5f\xfbxB\xb5\x13\xa5[\xfc\xbc\xa3\x80\xa9J\xe7\x14\x08(|\xc0C\xe0\xf0\xa3c\xea\xed\xa7\xde\xdeV\x85_54\xca\x80U-\xfa\xb7l7,\x01S\x05\x87\xa9\xaa\x02\xdf.v\x0b\x9b\x92u\x0e\x00'\x01J\xf4L\x0d>\xfa\xc6\x9dz\xd5\xbbv\xc2T\x8er\xaa\xddu)\xbc\x93\x00\xaf\x10\xfcA1\xbd\xcb\xd6\xa0\xf0N.hA\xe1x'\x94\xa2\xa7d\x85wB/\xc81\xfe\xf2\xc5W\xccG\xfdd\xc6\xed\x0d\xe9Eqd\x17(\xc40\x8e\xfc\xed\xb0\x91\xbb\x15o\xaeV\xf5\xac\xc5\xdeI\xa0\x03\x86\xb8\x9e\x14*\xcd\xf9\x9c4\xd7\xaf\xf9\xda\xa5\x9d\xb1\x1b\xb0:X\xf5\xe5\x073\xb4\xec9\xa5\xa7\x19\x89\x87\x00\xc2\"'\xd1\\\x97?\x8f>\xb8\xceo\xd0\xbcj\x7f(\xf1\x04\x12\xaf\xde\x7f\x17\x9e\\L\xc0\x90l\xb1\xaa\x16h\xd3\xb2\x8aGC\x95\x8bg\x18\xc5\"\x0c(\xe9}\xfc\x16/\x98\x11\xde\xcd\xaf\xf8\xef\xbb$\x03^\xb1\xbe\xb2\xde\xc0\xdb\x86\x9b\xdf\xa1wL\x05\xfe1\x03\xff\x11\x85\xef\xd8\x855\xddx\x87\x8d\x93\x8f\xcf<\x91\x01\xfb\xd7\xb3w\xd7\xda\xf9w\xe7\xdd\"2\xea\x1d\x7f\x8dg\xfd\xd0x`\x17<\x82\xe7\xa1\x0b\xe2PX.X'\x0b\xcbq1\xd4\xa9\x0bY\x9d\xc5\xbau*\xd4\xe0Cl\x04\x13\xd6n\x05)\xe2\xcf\x16r1.\xfa\xabf\xfe\xec\xe6\x97\xd5_\xd7.\xbb\xc4\xf5\x93d\xd2>A\xd9\xb1\xbf\xe4\x9b\x97\xbd\xc9e f h?\xfc\xeb\xbcSy!Wf\x84b= \xa7i\xdeco?\x189\xf6\xa1l[\xdb\x1e\x1f\x89\x07\x84\xfa\x17\xac\xdc\x13{)v\xcd\x9cS\xfc=\xec)\xd9T\xa6\x7f\xc6\xb3A\x19\xacf\xad\x9a3G\xba\x97br\xce\xfd \x19C\xefb\xfe\xe7\xa4\xb5&\xb3*\x07U\xb5\xc6\"Y\xcc\x89\xdf.\xcbi\xd9\x11\x9f\xc7\x1a\x05\x93Xp(\xcd}n\x9e#\x04\x97\xbe(v\x92\xc5\"\x13!\x88q\xeaa\x88kG{\xe5\xd41\xb9\x80\xecQ\x17\xba\x04U\xc8n\\\xfa\x86\xdf(\xa8'}\x8b \xd5GNU\x84Z\xe6=v2\xb0D\x86\xe6SoNwy\x88\xb2\x98\xe0\xcdv\x88\xdb\x89?}JA\x93\x0b\x16\xf4m\x82\n\xf5\xc6$\xe7\xf6\xdc\xfb\x13\xac\xc3\xdc\xfb\x01\xff\xff\x0d\xfc\x11\xd6^\xb7\x01\xf2\x8d \x8a\x0e\x1b\x1f3\x13S[\xc6\x15\xdc\xfe}\xec\xd8\xf2+\xa6v\x90L\xe0Y\xc7\x87\x8d.%|\xd3\x9e\x1b]\x9e\xbeM\x16\x04\xd2\x13\x15f\x02I\xf4\xb4\xe9V\xdc\xbe\xc3\x14\x16j@\xeb\xacS=\\\xbb\xa4+\xbc\xf6\xda1\x8e\x1a\xf7\xbbo\xd8|T\x17v)\x0eG\xb5o\x870\x81>\\\xd7\x19\xda\x9a\xfd\x9a\xc9\xeb\xb7\x1fl\x99\xa2\x85\x1ez\xcc\xea\xd9\xc3\x13d\xbf\x97\xc1\xc24-?\x8a\xfa\xa6$\x93\xaa\xea[\x8fa-\x9d\xf1\x10\x8b\x86`\x14\xdf$\xbc\x8a^d\x13\x0e\xe7T\x05\x1e\x9d\x1a\"4\x03o\xd2\x90$\x1f\xb8~m\xa4\xa7\xb1\xce).\xa7\xd7\xc8p9\xeb9\x0f\xb6\x14\xae\xaf\xf7S\x80\xe8!a\xe8\x1f\x90\x98F\xcc\xcbP =\x9b\xeb\xebn--\xa3\x10\x81(r\xf8\x08\x01;\xa6\xa4E.\x88\xf4iy\xcc0\xdf\xc6\x062\x18\x99\x1d\xf7Q\x85Z\xa6\x198\x98KM)\xeb]\xeb\x8f|\xe8\xa1-Ub\x87\xde\xf9\xd0\x8b%\xf3g\xbdg\xf7\xae\x00]\x0f\xc5\xc9\nP\xbc:luw\xbd>v`\x90\xe6i\x93\x08jw a;\x90\xd9\x89i\x07$\x14\x84?o\xa4\"dB\xaf\xf6\xd4\x91\xc7\xb4\x1b\xb6]\x05\x8a\xed\xb9\xaasmo\x0f\x98\x84\x07\xc2\xb8f\x0dk\xa7\x8f\x18\xd6\xc1\x9a@\x18\xcf\x92,\xa3\xb7u\x18\x9f'34K\xd2\xb9\x9a\xdd\xdc\xbe\xb8\xa3\x02\x14z~\xb5;\xf7\xf6}\x95\x9f\xbc\xc2\x86\xbb\xe4f\x01m\xcdc\xce\x9bi\xdb\x02F,\xb0W\xe3\xdd\xac\xe5C\xc2u\x1c\xa6\xdd\x98\xbb\x90\xaa\x08\xa8\xc0\x85\x85\x0b\xe7\xae\xb0\x07Ia\xbf_2\xd4Y\\\xf1\\\xa30Ze\xff|\xc5|Fq E-p\xeb\xd4;E\x13\x96\x0e\xdc(I\xe6\xb3\x9b\xfa!\xa20\xd5>sT\xf3C\x9dJ\x802|a\x9d\xe0<\x82\x00\x1e\xc3\xe9#8\xd5Y\x9a\xa2\x95\xe9\x92\x07\x8c\xbd\xb2}\x9b2#dzz\xecL7\x8f]XLG\x18+\xf0\xca\xc6wN\xed\xa7\xba\xc4\x9f\xb3\xca\x0cu\xd9<\x8ej\x13X\xa6\xf7\xc1da\xdcq\xea\x11\xaca\x97\xe7^L.\x0b\xdbq\xbc \x89\x89\xc6\x1a\xb7\x1alb\x9f\xbbp\xe5\xc2\x82\x07\x82\x82b\xd8\xd0\xae\x1d\xef\xeb\xb7\x07O\xfeL\xc9ezq\xbd=8z\xf7\xf6\x15\xec\xc1l\xb5C\xb6\xd3o%-\xe07\xe90\x90JFW\xe0:\xd8\x87\xc2\xa6\xf7\x14.\x7f\xcc\x97\xbfh_\\\x15\xafk\x8c,I<\xd6\xacB\xe6\x87\xe0'\xe1\xaf\x90\xa1\xd8\xb0rhs\xdb\xfa\xc6?4\x7f\x0d^\xab\xae!QR\x1b\x99Hf\xa0M@7Y\x98\x0c3\x1f\xe1+*\xcd\x11\xaf\x11;cv3L\x8c\x87\x86W\xd3\xe4\x98\x0b\xf5n&:\x8d\x1c/a\x98\xc3NuY\xa1f\x0b?\xf3g\x05\xc9\x9e\xf9\x85?Q\xba\x94q\xfb\x9c\xde\x85H\xbd\xc0/\xd0j\x8aNe\xde\x03\xdfJ$\\\xf5\xa1\x9a\x85'\xde\xdc.\xd0TOA\xf0a\x82\xb4\x12\xb9\xe0\xaeK\n\xac\x1aX\xa5\x90\xe3M\x88\xa7u\x14nLo\x18\x89\xfc\xa4%U\xed\xde\x7f\x82Y\x9b\xde?\x9ef\xc7m,\x1br\x16\xae\xef\xec'M3y`\x13`,\xd4\xac\xd3q H\x04\xe3\xaaB:\x1d\x1c\xc5\xd3\x12t\xfc\x01\xb8\xf3C#t\\fg\xde\x1bX\x87\xcc{kP1\xcd\xc3\xd8\x8f\xa2\xab\xa1\xd2w\x9f+\x8d\x93*j0\xe5\x88\xc5\x1f\x1a\xd1{\xacSr\xab\x92\xd9\xb4\xd5\xc7\xb1,\xa7\xd4\x1ab\xf3\xcfJ\xcchj;m\xbd\x8a\x89\xcc\xeal\xb4\xfc\xa8\x8c\xcb(\xebF\xa9\x8b\x8f<.\x86`V\x1b\x96^u\xf9\x11\x81\xb7\xebP\"\x02\xf7l\xb7\xc0\xf1\xd0\x00\x88E6\x18\x08\xf1\"\\\x84\xb9\x01\xdcB\xa5}\xad\xd0J\xc7\x1eACwn\x0b0\xa9\x953\x8e\x1d\xa3\xd2\xa4_M=dAc{\xfb\xc1}\xae\xa5\x7f\xc0\xff}\xd8\x8cj\xc7\xc3co?\xe4Q\xed\x1e\x8a\xf7;\xfc_\xfe\xfdC\xfe\xfdC\xf6\xfd\x0e%G\xf0\xdf\x11\xffw\xcc\xff\xdd\xe2\xffn\xf3\x7fw\xf8\xbf\xbb\xfc\xdf\xfb\xfc\xdf\x07\xfc_\xde\xde\x88\xb77\xe2\xed\x8dx{#\xde\xdeh[\x19e\x8f9\xdb\x0eY\x8b^0\x1aw\xc2x\x87U\x90J\xbc\x92\x9f\xf2\x10\x8f]\x94(WJ\x02\x82\xfe\xc1-\xc8CD\x88\xe6\x04k\xcc\xd0}\x84\xf1V\xaa\xa0\x19Ul\x91\x0e\x82\x94\x1b\xed\x83\xd0:o\x9f+\xb4\xdc8\xe9n\n?_$\xed{\x0c\xbeVL\xc0\xa2\xc2\xed\xc1z\x9d\xc8\xcf\xc78; \xc5'\xa3\xd1h{4\x1a9\"v>C\x18o\xfd\xf8\x8c\xebH\nYG\xe2\x03\xa6\xb3\x84Y\x12\x10H\xe9dtv\x96\\i]\xc0W,\xba%\xecc4 \x0cy\xca\xa2_\xae\x83m\x17\xb0\xb1\xc7\xca\x1dx\xfc\x18\x10~\n\xf8\x0f0\xda\x1co\xc3:\x8b\x99\xd9\x9b1\x17$\xfc\xcb\xb3\x0c[\xb7\xc3a\xbd`\xa6\x8b\x1b4\xda\xdcR`+\x0dPd\xfe\xc5pP`\xb15\xbc\xcc\xbf\xe0LiX\xcbnM\xe0A\x81\xa7d`\x12\xc3c(\x1f9\xc0-\xb9x\xe4\xd6bZ\xae\xaf\x1f;\x18F\xe2+&kiV\xa8\xc1\xa6<6X\xab\xf9w\xb3\xf4\xea\xeb\x83\xe2\xacM\xc7\xb6\x8a,\\Z&\x85y\x9b\x9bV-\xaa`\x059\x15\xb2u\xbb\x01\xf7\xc2\xca\x8e&\xd6\xdf\xa6:\xbc\xd4\xf6\xc3\xf6{\xba}\xd6\xd4\x82u\xf0YD\xce\xaeXS$\xdb\xfa\xff\xd3Z%\xff\xcf\xfac\x9b/\x8a\xea\xaau\xa5/\xda\xb5f\x03\xb8o\x90\x85\x12\x8aT\xb2\xc0\xc7\x1d\x0e#S\x04k\xb2\xe6O\xc9\xb1\xcd\xbc\xf3~\xfb\xf5\xff\xf8\xb7\xff\xc2\xe2\x9d\xf2\x9fX\xa6l\xe3Zs\x8b\xd3\xb5I\x98;s\x89J\xbe9\x86\xe3\xed0\xca\x807\xfe\x97_\x82\x9dLcZ;GWnA\xfbR\x94_\xca\x07\xb9e\xf9\xd2Z\x809\xec\xc1\xcc\xa3\xb0\xda\xc7\xa0\x81\x04\x8er0eT\x05\x8e\x803\xef6\xe1jE\x96]-w\xc1\xc2\xbc\xeccM\x85HTh\x11\x1ej\xc1\x82Z\x0b+\x8fT\xaem\xfdX\xfc\x18\xffx\xfe\xe3\xfc\xc7\x0c\xfe\xed_\xff\xeb\xff\xf5\xeb\x7f\xfd\xd7\xff\xf3\xb7_\x7f\xfd\xed\xd7\xff\xfc\xdb\xaf\xff\xc3o\xbf\xfe\x8f\xbf\xfd\xfa?\xfd\xf6\xeb\x7f\xf9\xed\xd7\xff\xf9\xb7_\xff\x97\xdf~\xfd_\x7f\xfb\xf5\x7f\xfb\xed\xd7\xff\xfd\xb7_\xff\x9f\xdf\xfe\xf3\xff\xfd\xff\xfe\xfa\xeb\x8f\xe5xs\xfc\x00\xff\xff\xf0\xc7rN\xe6sk\xc8\x19\xbb!M9\xde\xde\xc1(n-vF\x8f\x91g\xe2\x8a~\xd2{I\x0b\xd5q\xafm\xf3 $r\xc3 \xea\x02\x8a\x8d:\xe1%(n\xb1,\x8f\xc4\x01\xe6_Q1x\x14\xc8\xe9\xa7[\x8em\x89z\x96\x81\xa6\x11u\xfaVJ\\_\xa1X*\x17\xe4\xf6\x95\xe76V\xdcg\xf0\x18F\xb0/\xa5#\x1e\x1d\xd7\x06\xcc\xcaV2\x96\xf1\xc7\x1c\xd3\xacl\xe9Iy\xee\x1b\x11\xf9\xddN\xd0\xe493 \x18~j\x0d\xbc\x82O\xc7\xcdM\xe1\xd1\x0f\xb3DM \xf7\xdc)a\x03\xeaK\xbbd6\x15\xf9\xef\x02O\xf7\xc7J\xde_\x06\x8d0\x9eEe\xc0\x82]\xe8@C\xd4\xe9\x03\x8d\n\xed\xff\xa7D\x02\x8e\xba\x07\x0fS;\xbd\xc6\x08\x91\xab\x80\xc3\xed\x0ecc\x99\x06\xe3\x8e\x8c\xa4\xc4/&x\x83\xef:+v\xd9\xb7_\xa3\x91\x96\xb6\xb8\xa9\xb4\xb8\x0e\xdcO\x99`\x05x\xa3\xc0E\x91\x89>\xe4\xf1P[\"S\xf48\xe5a\xfaC\xd8\xdb\x83\x11\xdc\x83M\x05Ca=M\xca\xb8\xa8\x1d\xb7br\xe6\x17\xe19is\x12\x0f/\xc9\xdd\x0f\xbd(>\xc9\xd8\x93\xb8\x98%\xd1\xc78\xb2\xb4i:|\xd1\xfc\xc7<\xb6\xb4\xaf<\xfc\x99|\xbcY\xf0\xd6?\xe6$\xc2\xc2\x8f\xc2Y\xbe\xd2\x1c\x86L!\xfc\x14\x80\xb42\xf2\x19\xb4\xfa\x88\xf6\x17\x19\x99\x7f\xe4\xa5\xcf\x97~\x14\xad4\xfc!\xa3\x17\xad~\xf4\xc5\xa7\xef\xdf\xaf\x06\xfc\x83\xc6/\x9a\xfd\xf8\x13(O\xef~\xf4\xe5'\xc1\xfey\x99~\x84\xa1\xa7w4\xf4\xd8\x1e\x8d)\xb9\xbc\xf4\x8b\xd9\xc2rad\xae.\x0dfZ\xd5S\x8a?\xd5k\"\x1e\xc1\x19\x10\x93\x921\x91e\x0f(z\xa8\xd2\x99\xc5\xd3B\x9f\x19C2\xafO`_\xd8\xe11/\xaa \x9a\xc0q)o\xecL\x8bc!\xc8\xcf:qA >\xbe\xe1jrQ\xa3\xe5\xc2\xf8\x06\xeb\x99)<4`\xd0\x92\x86}K\xea7\x964\x93\x974\x1b\xb8\xa4\x12?\x91a\\\xb3\x04W\x95\xbd\xe1k\x19:,N\xd3\xdd\xadhN\xfc\xec\xdf\x01\xf4\xee\x963\x8d\xc2B \x9e\x1d\x03K\xfd: \x0dGl\x8fw\xda\xbe& D!\xdd\xd7L\xef\x86J\xb4\xae\x90\xc4\x9a\xa1\xf1\x8a\xe5\x9f\x9e\xce,\x9ew\xe2\x9e}\xea\xfc\xf1\x9eC\x99\xe3\x0f\x1f`\x1bu\x1e\x05\xc9\x8b\xba|\x7f\xe2\xdcsac$\xc2:\xd1zc\xac\xe7\x9f\xca\xb5|lH\xaa\xc4\x1a\xf3\xea:\xde\xbeC\xffkT\x92\xcb\x1d[*\xa3\xdc;-\xaf\x8a\xbd\xfd\xaaP\x05r\xe7\xdc\xf7Y\x12\xa8\xde\xb3\x9d\xfd\xfd{\x1e\xb9$3\xdb\xb2\xe8\x1c\x15P3DO\x02\x92\xad\x9a\xd0]\xaa\xe3\x06@\xd3'gOx!\xf14<\x95%\\;\x95\x8a\xfc\xedZ\"\xa7_\xab\x83\xe8\xe1\xe8\xd4\x9f\x9d3K\xff\xdc\x85\x08\xc3T\xcfY8}\x93\x93z\xc0B}\x86gq\x92\x91\xa7>\xc6\xf6\xb3B\x0b&\xf4\xda\x83uZ\xb6,\xa3\"\x8c\xc2\x18\x8b\x96\x8d\xa22\x0eQ\x11\xbf\x0fV\xd9(\xc8\x8bp\xf6\xfe\x8a\xbe\xbf\xe2\xef\xf5CX\x98}\xe4\xcf\x9b\xbbY\xc0>l\x8f\x1fn?\xdc\xbd?~\xb8\x83\xe6\xfe\x8f\x1f?65\x80\xd1g\xeb\x03O\xbc\x1c\x83\xa3\xbb\x10\xc0:Xg:\xfb\x01\x94\xfea\xd0\x06t\x8e\x90Z`J\xce%o\x876\xf2\x85\xbd\xbf\xf6\xe3\x8f\xb9c\xb9\x10\xa84\xd4\xd5\x83\xfe\xeeK\x06\x8b<\xbe\xe7\x9amG\x18y\x0cE\xcd\xb0\x0e\xf9t\xf3\xb8\x82\xf0\xc7\x80\xf1\xd5\xec\x94\x07?\xe12\xa5\x85+>p\x1c\x17\xd6\xd0\xb6\xbf!\xf1\xc2\xa4!\x9b\xc7\x95F.s\xcd\xe4O\xe3\xc1\xa9\xcf1.\x01\xcc\xe1\xab\xae\xe4{\x03\xc6\x8f`\xbe\xbe\xee\xc8;S\x8b\xd8\xe6h\xe8k\xe3\x8f=\xa5D\xbc\xf1\\;nw\xf0|9\xbe\xaaC0\xa2]\x00s\x14J\xe9\x07l%F\x0e\xcf.!-\x1b\x8b1\x1f\xb9\x90V\xad\xee\xc1\xb9\xe3|\x00\xbec,\xa3O{\xfb\xe8\xa0\xeb\xc1\xc19\xecC\xca\xcb6]8\xc7O:#hY.3\x8f\x06kS\xa0F!\xd3\xdct\xa4\x15\xb3\x07a\xb6\xe6\xa5\xd9FW\xb0\x0f\xd3c\x98\x08\x1cT g\xdb\xdc\xa0Z\xcc-\xd1\x08\x1a\xa2\xeb\x06d\xd5\x8d\x08\x01\x89\xac\x8ak\xb2*\xeb\x90U\xb1\x8a\xac\xcaV\xa5\x03\xcc\xf2\xfa\xd4\x8e\xed\xedQ[\xec\x9c\x88\x92q\xbb$\x14%;\xed\x12\x9f\x97\x8c\xee?h\x17\x95\xbchgk\xb3]\x94\xf3\xa2\xadNO\x11/\xb9?\xden\x17\xcdz\x03\xf7U)\x98\x88wrB\xf2\x97IPFD\x97C\x14$\x99\xff/\nW\x10\x8c\xbb\xc7r\xe2\xe9B\x99\xd5\xf9\xdex\x0c\x86v\x8a!o\xe1\xe7\xaf/b\x91\xbe\xb5\nC\x17s\x95\x0d3\xb6 \xdd\x84oP\x83\x10&\xa6\xf3\xcb\xa8\xe0\xa1\x99\x9a\xa0A7e\xbb\xb3Ts\xae|q\x1e\xfd\xa1z/\x96\x0eR-\x8b\xdaY;\xcc\xf4<\x18Y\xa3.E\x92\xd6Y0\xde\xdd\xd9\xdd\x1c\x05-E\x1b\xbdv\xad-o\xf4\xc0\x1b\xb7J\xe8}j\x9d\xfa\xf1OI\xab\xe0\x8c\x16\x1c\xfa\x85\x0b\xe3\x1dxR\x9e\xc1xs\xf4\x006\xefOv\xc6\x93\xf1.\xfc\xe9\xe5\x91t\x10\x86\xe9\ns\xb1\xf4\xde9\xc9\xf20\x89s\xbc*;/?|\x80_\xae]E\x89\x97_\xf8gg${\x17*\x9d\x97x\xb5 (\x02\xdd\x9e\x85\xc5[r\x1e\xb2\xf2\x85\xb2\xfcY\x98\x15W\x13\x08\xba\x85\xa7e\x18\x05G\xe1\x92\xe4\x85\xbfL'p\xd6\xad\xb2\xf4g\x8b0&\x93v\x0c\x85.\x07Ph\x1d\xaf\x82dy\x12\x06,\xcf\x94\x1ao\x06\xc9\xf2U\x12\x10S\x95<%\xb3\x89\xde\x88*\x8b&J5,/\xccMMG\xfeUR\x16\x13\xb0\xbe\xf6s\xf2\x02\xff\xd0\xb4\x14$\xb3\x83\xcb\xd4\x8f\xd9r[Q\x98\xebj.\xfd\xcbg,\xf5( \x8e\xfc3c\xff\xf30*Hf\xaa\x81\xe6\xa4~\x91d\xefp\x9e\x8b\xa2H\xf3\xc9\xbd{IL)^\x01=^\x98\xdc\xab*j\x86\xc5|\x97r\xfdB\xce\xca\xbcH\x96\xfar\x9eO\xf5uJX\xea\xaa\xe7A7\xa9N\xab.\xcfz\xf4\xac\xd4%\xbb\xaa\xea\x13\x92\xbe\x08\xe3\xf7a|\xa6\xaf\x94\xb1\xd6\x9e\xc7\x05\xc9f$-\x92\xacOc[\x7f\xc9\xb0\x97\xb2\x82f\xba\x19\xc9\xd3$\xce\xc9'\xea._$\x17\xe8\xd3M\x02\xbejj\x073\xa8q\xeb\xcb$ \xd1[\x12\x07$\xc3u\xb3\xc8\xa5\xbfL#\xa2\x83`\xe9+\x04\xe5\xe0\x19I\x8b\xc5\x04\xb4{R\xd7\xcf\x87|@\xa7ppY\x10<#\xb9~\x1fi\xbd\xa7\xc9r\x99\xc4\x83j\x97)\xc5\xc3$8,O\x97a\xc1\xa2M\xe4\x13\x98Zg\x04\xd5.i\xc9\xfeIr\xfc\x97e\xd1\xa5\xbf\x92\x94nU\x8e\xfa\x01\xe2\x07X\x89\xcb8\xad\"\xf3g\xc4\xd20\x9eiFrR\xd0>\"\x81\xb0u51C\x17\xad\xa9\xa9\x10\xc6a\x11\xfa\xd1!\xddX\xfd\xd1\x9a\xc7\x86c\x99,\xd3$\xa6|\xcb\xa4\xed<\x05jp\xa2\xfc?%\xd3\xe7^\xeag99D\xb9Y'M p\x82\x89x\x1c\x057\xf1:OF\xac)\xa5X?\xe5\xdd\xf8b\x8d\x1c\x9b\xdeq\x05\xd2\xde\xb1\xa2\xb7+\xed5\x91_\xe5\x05Y\xaa\xc8\x08\xf1T\xd8+\xf5\xf8\xcfU\x0eW\xb5M\xa9\xc7\xf7V\x03kl\x9b\xda\xb3\xd2\x8eJ\\\x1ff~U\xd4J=\xf6K\xdd\xb7x\xc4\x95\x90z\xec\x97\xb6\xb2f\xaeP\xdf\x98\xc6~X\x1d\xdd\xc5)\x1e\xbc]S\xaf\xcc\"\xfd84;\x01\xa9'C\x7f\x97@V\xc4&\xe8\xfb\xa4\xa2\xa7O)=\xdd\xaa\xdd\xfa\xbbEZ\xdb\xa7HRK\xfdS\x15\x9a\x078`\xb2\xdc#\xa5\xc0\x86\xb0\x073\xc7\x85\x13/'\x05\x1bCn\x97\x8e\x0b\x17\x02;=\xc1\x99\xe7^\x94\xf8\x01 0\x8fI\x9d=\x9d6\xb5\x16\xd3CE\x7fZ \xf2\x84\x16KQ\xb0\xe9BX\x8f\xb2\xc4y3^p\xd3\x85\xa4S\"%|ck$:.\xd3\xc0/\xc8\xbb,\xb2-\x0b\x07\xd6-|\x91\xf8A\x18\x9fQ\xe8/s\xdb\xca\xcb\x19\x06~\xd1\xd4>L\xc9\xcc\xa6\x83\xc8:\x83\xc0d)\xcdo\x82\xe4\"\xa6s\x07\x0c\xea\xc1g\xaa\x1d\"\xd6\xe8\xf4+\xda\xe0\xc5\xe8\x81#6\xc0\x81\x0b/C\xd2\xa7\xde\x14\x17\xac'i\xaa\x93\x97V\x91J\xb0\xfeI\xa8\x0d\xcd\x0f\x1c0s9\xb2\xc6\xdfK\x92] \xf8\xab\x9b\xd0\x8bR\xab\xe1\xe5bXj4\xc9\xa3\x89P\xe0\xc0T8\xbceL\x06\xd0x\x89`\xf7\xe1\x03\xf04\x1e\"k\xc7\xe1\xfb0MI\x00YM\x07\xc6 \xfc\x0bk\xe5_ \xc9\xf07\xfd\xf8_\xe0\xc2\xcf\x11\xed\x87\xf3\x90\x04\xbau\xe2x\xe8\xa2\x8b\x18\xba\xe7\xeb\x92bB\x0e\xf2L\xa6\xc8~\xbf\xcb\"\xa5\xac\x0d\xe5\x98\x8dM\xee\xbc\xa0G\x9b\x9d\xa8\xaf\xaf\xdeq\xb0Y3\xd6\xf8\xf0\xc1\xd8\x82\xe2\xfa\xc6K\xed\xb2;\x1d\nlo\xc92)\x08\xfb^M\x81\xab\xd8\x90\xd4\xeb\xbeU}\xa9`)\xe8\xa7\x9d\xd7M\x1c\xec\xc2\x01fb\xb0\x8d\xf3\xbc\xa4\xd5\\\xb8\xa0\x87\xf1@r\x03\xba\x96\x91,\xe9\xa5E\x1c2\xe1\xd8\xde\x19=\xe88\xf0\x8ev\x1c\x8f\x8b\xfd\xde\x93\xab|HC\xf5\xcau\xac\xa0\x99\xb6\xf5\xe1\xae4\xe1\xd8\x1e\xef\xdcwx\xbaM\x03\x95\xd1631\xbb\xed4\xb3s\x03\xacnX\"/C\xb3\xa3J8\x18\xdb;\x9d\xc0\xb0\xb5pq\xd2\x9fb\xb3\xb3\x03\xdc\x83\x1b\x1d\xbe[\xfbp\x7f\xdb\xf1\xe6rL\x94!-\x0e\x9cD{\x9bn7\x89\x9d1\xf3\x07\x1f\xdd\xe7~\xe4c\xeeW>\xbe\xaf\x04\xaf\xc3\xab\xe5i\x12\x0di\xbb\xd7J_\x9d\x8e\xb7\x13\n\x83G\xe9m\xe7\xb2\xe4\x913\xda[\xca\x83\xf4\xee\xb4\x83\xf1\xf2\x19\x8c\xb7\x1d\xef\xcf\x07\x7fk\x96\xb1\xd4\xa1;\xed\xf1\x88\xcc\xa1\xed\x011\x81\xf6\xc3vX\xa1\x94{\x87\xb4\x8d\x13x\xea\xd0\xb6O\xc2\xa2\x82\x94\xe6\xfbs\xfe^\x9d9tg\xdc\xae/2\x87\xb6'\xcc\xb2\x86n\xb5G\xc3R\x86\x8e\xdb\xb5Y\xc6\xd0N\xdc\x87\x0b\xbe\x9a\xed\xb9\x1e\xb0%h\x8f\xf1\x92Wo\xcf\xf5\x90\x8f\xbd]\xff)\x1bL'X\xca{\xb6\xe5\xed\xd7O\x04Bj\xbe~\x0d{\xf0\xb4\x9d$\xf4\x0d\xec\xc1\xfb\xf6\xcb#\xcc\xfb\xd9z\xf9\x12/\x08\x06\xd7\xcd\x92\xe7\xd5\xd5\xd1|\xff\x13\xec\xc1sJ.<\xafQz\xb3\x06\xbd`\x02\xdb:Y\x84A@\xe2\xb6\xca\xff-+-\x927Y\xb8\x0c\x99\xbfM\xb3\xc63\xd4\x03y)g(\x9f\xe7\x07q\xb9d!\x91\x9b\x15_\xd0\x1b\xd2\xb6r\x1c\xfd\x06c\x05\xb3\xabvs\xef\xe4Z\x9dd\xc6\x7fg\xa5I\xba\xa1\xa9\xf0\x0d\xecu\xb4I\xcd\x1a?\xeb\x02\xc2\xbcl\xd6\xfb\x1aW\xf4/\xac\xb1f\xd1\xf7\xb0\x07k_cf\x88\xaf\xa5\x8c/\xad\xbf\xbdy\x18\x07O\x17a\xd4R4|\x0b<\x82odvr\xe6w\xce}X\xdb\x83K\xfb\x0d\xf2fh\xd7\xab&\xd0\x87\xc5\xd8\x82\xba\xe17\xb2\xad\xb0Y*\xc2\x93,\xdf\xd7V\xbav\xbcn\xd0#P\x8aA\xae\x9dv\xddkG\x0eg\xa3\xb1]\x03 !\xbf\xb6\xbfQ\x9b\xd3d\x92\xac\xe2\x9biq\xec\xc2\x9b\xaa=\x1e\x10\x92 \xb7\xf9\x0d\xfd\xf9\x06\x9b\xe9\x04\xc0\xbf\x86 \xbcin\xd9\x0f\xbd|\xbb\xe0\xd9\xdf1\xaf\xf1K\xfbe\x0d\x08&\x1d%fL\xef\xaa'\x9b\xdd\x7f\x07{\xf032\xc5\x0c\xea\x1bP\xeb\x89\x9b\xbb\xb1\x88\x06\x80R4B:\x0b0\xa8\xa5F\x94\xfd\x97\xa6\x19\xfcm`l\x80\xaa\xe1=\xb1I\x7f\xb3\xff^m\xe0\x15\xcb\xe2\x02{p\xc13\xd6\xd1w\xb4$\xb1\xdf\xa1\x91\xc4>\xc6\xd7\xa9\x10\x10f\\\xa5\xfd\xbdby\x85\xa7\xaf\x8e\xa7\x053s\x11\xbf\xf7x\x0e\"\xdc\xb4Xw\x10\xea&)\x17\xb1\x89\x89\x8bT\x90\x0d\x93\xba\xc3\x0f\x1f\x18\xf4\xbdr\xe1\xc0\x1ea6uJ\xa6\xd4\xfd\xd2\xe1\x7f[\xad\x06\xfd\xb6\x86V\xd3b\xfey\x88q\xc8\x95\xd2\xf5\xad\xd6\xbc\xb3\xe0\x1fK\x9e\xe8\xb3\xa0CKXj+\x16e\x97IP\x98\x1fe\xf2\xc8\x81\xbf\xa1\xfe\x1d\xc3\x05&\x18\x06\xa60j\xdf\x8d)7\xfe4\xf88=k\x18\xaf\xe0\xc6\x13\x96\xaaP\xdb\xf3\x1a\xd6\xae\x01\x08A\x83\xe5\xf7\\K(0\x11f\xc1e\xaf\xd9\x05\xa2\xec\xda\x17\x9f\xff\xf9N\xfc\x16%\x0cz\xe8o\xbay\xe4\x18\x0b\xdbv4\xcd)~1d\x8f\x98\xdd\x05]\xff.\\\x0b)\x11\x89\xa9\x9e\x94\xff\xc8\x11{\x82\x87\xcd\x17\xb3\x8a9\x04\x7f#v+dSz7-\x0c\xe70l\xce\xaa\xae\xf73nmi\xdb/M\x81\x0d1\x08\x14=N2\xa2\xef&\xc4\xb0\x18IZ\x87{\x92\x92\xd0w\xf2b\x9c\xf3\x8cj\xa9\xca\xebw\xb3\xe1\xf5\xbb)\xf9\xe6\xbb\x9d)6\"B*\xaf\x13\xe0Y\xdajl\xc0SZ\xfe\x9d](\xcd\x03\xce\xfe\x9a\xbe:\x16\xf8\xc2\xae\x8f\xbc\xb8'\xbe\xad\x0d\xe9\x10\xa9\xab\xd2\x1d]+\xa5|H\xf2}O\xff\xf7-\xdd\xc3N.@\x18\x14I5\xa7T^\x8bXp\\\xf8\xa1\x99\xeeM\xce8h\x15I\xe5\xe3\xdd'\x04)0C\xdf\xfb?\xc8M?\xc5\xa4t_\xb8\x94E\x81=\xf8\x1bF\x90\xdby\xe8\xe0_\x87\xf8\xff\x7fF\xae|\xbc\xc3\xde\xfd\x89\xf1\xe8\xbb\xec\xaf\xbf\xf2\xfc\xc6k\x94\xdf\xdc\xc6e-\xe9\xfc-\x15\xc3`\xb9\xf4kD0\x0b\xfc\xbaWR\xf5\x83\x1d4$2t\xc4\xbe\xedc\xaa;\x1fS\xdd\xf9,[\xda\xcf\xed\xf5f ;\x91\xe8\x16Y\\V\x1d\xe7\xbfPva\xe1\xe7\xcf\xf9\x01p\xc3\xfci\x12\xcf\xfc\xe20\xcd\x88\x1f \x9b#(0\x17\x9d\x85\\n\xbd\xeb2\xd7\x0c\x97\x07\xe8u\xd1\xde\xd3\x958)W\xec\xcc\x91\x7f\xe6\x96q>KR\xda\\.LC-\xd7\xa2\x17\x01a8\xe2/\xf5!!\xe4\x91\x03\x81\xfd\x97)!\xcd\xb4\xe65\x12\"\x98\x8f*\xf0\xf2\"\xc9\xe8\xe5\x12\xf3V\nR7\x13\xd3f\xce\xed\x82L\xe3V;t\x05\x0f\x1bk\xc7Ox7B]\xbf\xfdG%;{Ao\xb5\xf5=\xb47\xdf\x87\x17\xf4TM\xd8?{\xdd\xe4\xea-\x04\xfc\x9e\\}\xd3\xdf\x15Z\xe0\x7f\x87\x16\xf8\xc6\x9c=>0\x1a\xb8\x83\x9b\xa0\x19<-\x8c\xe1\x85ZCA{z\x81t\xdc\x9e\x9c\xba\xc3H\xc6\x9799$\x05\xaa\xb1\x8d|\xda\xf7\xaa\xf0\xc0\x9d\x96\xc2e\x1a\x91!-5\x93\xcd^w\x8eJk\xa3\x19\xc3\xdb\x8dq\x84A\xd4\x07$+\xedZ%\x17\xb0\x0f\x976\xa6\xa5\xfc\xb3}\xc9h\x1d\xe3f\x07d\x1e\xc6D\xa8\xa8'\xf07CqH\xf2 \xfc\xb9Y\xe1\x8c\x14\x92\x8a\xfb\x19\xc9gY\xc8\xd4\n_\x98*\xbe\xf2\x97\xb4\xb1\x7f6\xd5a\xc7 \x9f\xc0_\x1b\xeb\x88\"\x96\xe6b\xdakx\xc5\x1a\x98|q\x11\xbel\xc7<\x16\x8c\xda4.\xa3\xe8\x18c\x99\xfdd\x0b\xba\xd3\xfa\xe5\x9a\xbf\xe9\xae\xbd\xdf1,m}\xc26\xb7\x851\x1d\x17\xac\xef\x0e_\xbfR\x04\x01\xa9\xb4\x0c+\x10?\x9cd#\xc7\x8c\xa3\x18=R\xc5\xe0\xa1,\x05\xa7\xc9\xea\xeb>ib!\xf1\xf0L\xde\x9c \x1a\x1d\xbb`\x9f\xda\x9d\xa4n\x9c\xc4\xffN\xf6\xbf9\xe3\xd5\xecb\x089.\xfaRJ\x87X\x987\xa44;\x06\xf5\x8eK\xfb-\x1c\x0d\x1a\x00\x0e$t\xect\x1a.\xfc\xc4\xb5*\xcf\xbb\xc2\x87\x06XIB\x84\xe9[$\xc6c{g\xd3\x91\x85\x0b.\xbcm\xd4cI\xb6^\xcf1_\xe8\xcb\x1aq\xb3\xbf\xfdb\xe1\x82E\xff\xb1\xf8=;\xe7j\xa6\x1a\x06\xd66\x07\xa9\x00j\xe9xG\xca)\xa2B\xa9\x93\xd8QBaU\xbd\x94\xe0\x073e\xda\xb7\x98\xc5\xe5\xed\x1a\xce(2HV\xa0\xea\xbb\\\x00O\xf1\x11\xed=\xf4\xe6,/\xcb\xe6#(kH\x8d\x1e9\x90W\x16\xe8\x94`/\xa7\x11\x12\xe5HN2\x10V\x1f`Ia\xb8\xda\x8av\x84\xdb\xc2\x9b\x90\x92]\xdd5\xfd\xe5\xda\x13\xa4D\xb3\x10\x83\x03\xd5\x86\x14\x02\x96/\xc28H.P\xc9\\\xfd\xe2BS\x05F\x84}C\xa1\xcdZ\xa0\xb8]v\x8b\xab\xb5\xa3\x83\xa88\x0c\x8akM\xd9H\xe1\x07l\xf2\x18G\\\xe58\xeb\x95n\xe9\x93\xd5T\x04\x88\xca\xda\xaa7\xf9\xbb\x18\"w\xf4Q4\xd1<\xc06\xcf\xbf\xdc\xd4\x14\x0e\x02\x00\xa6K\xb1-?\xbf\x8ag\xcfWR\xc8\x89OY\xfa\x12\xa4\xa5\x07}\xa7\xd6|\x15\xde\xe9UA^\xb0#0\xe4\\F\xdas\x89\xe9\xa5:%\x19\x96\xb4}:\xf9Ro\xd1\xdb\x13\x83/9p\x0f\xb6aC\xe2\xcd\xaf](\xbc\"\xf9\xfa\xaa <3\x9catm\x9e\xfd\xa4\xb0\xe7\xce1|\xf5\x15\x8c\x1e\xc0\x87N\x11\xac\xc3\x88\x17\x8f\xd5\xc5cV\xbc\xab.\xddr\xe8JL\xf3\xf5u\xbc\xa60\xb2\xf2.| \xe3\x9d\x9d\xf6\xfb\x07\x9d\xd7\xe3\x9d\x1d\xf8\x12Z\x89\xa4\xc6<\xc5\xb5\xb8:\xd5\x93\xd1\x0c\x96\xce\xe5\xf1c\xd8\xeev\xd2\xc2\xb6\xa3A\xbd\x8c6\x8dK\xb6\xad_\xb1\xc7\x8fa\xa6\x87wZ\xb0u\xfd\x12v\xb7\xe8\x0bko\xcfB)\xf7\x98\xb7\"\xf6\xcbf\xed\x8cq\x1f\x1e8\xb0\xaemx\xb4)Z\xa6\x80Q\xb5\xcc\xbb\x1aK]Y\xed\xa1\x0b)L7\xdc\xf4\xb5\x82\x7f\x16B\xc7D\x12>Ze\xcc8\x8f@N\x0f\xfb.\x8c\x8b\x07l\x1f\xf7\xe5?&,\x9f\x0b\xdb\x14\xeb\xc9\xd7O\x9f\x1d|\xf3\xa7o\x9f\x7f\xf7\xe7\x17/_\xbd~\xf3\x97\xb7\x87G\xef\xbe\xff\xe1\xaf\x7f\xfbg\xfft\x16\x90\xf9\xd9\"\xfc\xe9}\xb4\x8c\x93\xf4\xefY^\x94\xe7\x17\x97W?o\x8e\xc6[\xdb;\xbb\xf7\x1f<\\\xbfg\xf1h\xdc\x0c\x8f\xf8\x95t\xbe\x84\xaf \x7f\x04\xeb\xeb\xa5\x03\x19K\xc6\xedOK:\xf0\xa9/\x83r\xe9`,c\x95[[\xa4\xc7\xea\x02\xd8\xba\x84U\x01\xff\x01\xb6)\x1a\x13\x8c6E\x9e\\\x16\xf8\xc1vn\xc2\x84!f:^9mfw\x1df:\x8c_g\x8cB\xf7S9:z\xc1v \xa6\xff\xac\xef\xc1\x96\x83\x00c\x13\xba\x13\x14\xe5P\xec9\xda\xbd?\x1a\xed>\xd8d>\xf6\xd3\x92\x9e-\x06\xe9\x14\\w\xc6\xbc\x84\xa1\x0fV>>\xa6\xac\xb9\x80|;\xc4\x8cZ\x08\xff\x0f$\x98\x0f\xf1\xcd\xb8\xfdfWz\xb1\xbb\x05_B\xd8\xe6\xa9*\x8a\xa6{\x14\xaa_\xc9\xd4\xda\xb0d\x08\xdaD\x08\xda\x1dS\xd0\xb2NTE[JzC^\xcd\xc2\xcb\x88\x1f(T\x81<(\x8a\x02\x0cCW\x10\xea\x0f\xe0\x8f\x90PZ\x80b\x06\x85`\x94.\xfc\x88\xaek\xe9\xa8k\xa0\xbf>\xaeY\xb7\x8c^\xcb\x1b\xf7\xbb\xef\xd1~\x06\xf6\xb1\xe3\x11LT\x01\x0bR^e\x83\x96+\x9a\x0e\x10QR2a\xde\"w\xb8\xc3\xfe\xfa\x1e\xa4\x0c\xc3\x04\xf0%\x9f\xc3\xc6\x8cM\x02\x02x\xfcx\x0f6f\x94rX\xa7'\x18f\x18\xd8\x14\xeb\x8fwv\xe1\x8f\x10\"\xc2d\x1d\xb8 \xda\x9b\xc1\xc6\x1e\xcc_\xf9\xaf\xb8\x8c\xa7\xc0\xb6\x18x\xec\x83\x8dY\x04D1o\x92!\xef\x19j\xe9}\xd1\xd6R5\xcf?\x85\x0dX\x1c\xc3\x87=\x18\x8d\xe9\xc1:o\xddp7b\x8a\xb9\x10\xa4)\x9c\xb6\x0b\x17\xac\xda\xac\xb5#B\xe5\x96S\xb2\xb1\xab4bAj^)\xa3G$\xbcd\xac\x8c+\x81%[\xaa\xb8\x12X\xa2\x8a*A\x0b:_\xe4\xbc\xa0\x13l\x82\x99\x9a\x8e\xef\xb7U\xaf\xcc\xd6\xb4mf9\xc7ff\xad\xb7)o\\\x11\xe6\x82\xd9\x9a\xee\xec\xb6\x03]/\xaaO\x1e\xb6?\xe1\xf6\xa6\xe3v\xdfK1\xb7\xce\xac\x99\xc5\xa9&\xa0\xc3\xd5\xa7\x0f\xe8p:D\x1a&%\x1bm\x82\xca\x89IU_M\x8b(UA\x92t\x9e\xb15J\xe5{\xed\n\xb8\xd6\x88\x0d\xb4y\xdc\xd5\xcb\xab\x82\x7f\xb4\xdc\xc9\x84a\x8d\x8b\x05i\xbb@-p\xcb\xcd^\xc1\xbd\xce\xc5+\xb8\xcd\x9a\xbc\xe3L\xde\xc7\xd0\xf1@\xd6\xd7\xcb\x92\xa4x\x1eS\xd4\xd1S\x11\xe7\xfdF\xccN\xe1\xd4\x0c]M\x99xN\x932\x0e\x0e\xc5\xc45\x95\x8a$\x89N\x93K\x8d\xc34bz4\x00\xa8\\\x18\xe9\x1d\x81\x16\x01\xd5\x1b\xef4\x8c\x03\x1e\xf0\x87\x95\xa1\x82\x99\xdd<{p\xeaVn\xd63\x14r|w\xc8\xf6\x9ayUr\xe1[\xb3\x93\xfe\xb0\x85\xe2\xa9\x18s\xda\xfe\x99\xc7\xf6\xf9hQ\xc6\xef_\x86A\x10\x91\x0b?#\x8e\x1d;\x86\xc0i \x06\xf2\x12\xe1FNN\xde\x1e<{\xf7\xd7\x93g\x07\xdf\x1f\xbd~\xfd\xe2\xf0\xe4\xe0\xafG\x07\xaf\x0e\x9f\xbf~u\xf2\xf4\xf5\xcb7\xaf\x0f\x0fNNP\x87\xc7\xbcGsE$\x1c\x90\xc8\xc6M\x97\xd6D=\xe9!\xaa\xdd\xf9\x84\x12;b\xfa\x9ez\x98\\\xffS\xa5*wTf$6?\xaf\x8eXk\x0cO\xc2\xbdK\xd1\x1a\x05\xdfVN\xb5\xf8\x17?\x1e:\xadRk\xbce}$\x89\x0b\xd3\xee\xba\xbf'W\x13\xb0\xe8f\xd1\x19)\xdc\xa2\xf9\x05gTCC\xcb\xc2\x04a\xa6;\xdf\xe6\x90U\xe8\x81\x8dFLx\xc0hz}l\xd7\xd4\xa9\x07txp\xc4t\xb0\xf2\x0b=\xb0\xc9y\x80\x81\xd8&\xd0\x16\x0f\xe5}\x18t\x879\xa37\x1cJ\x91b\xc09\xfe\x1a\xc5JNC\xdb\xa8\x06KU\x9b\xdf\x94\xf1\xac\xf1-\xb1\x0b4\xa0\xd5y\xf9\xaa\x1aQ\x8c\xc0[\xfai-:\xd7jW\xe5\xa7\x1e@\xc7\xde\xb5\xfd\\;^F\x82rF\xec\x0b4\xa35\x0f\x957\xacA\xa0\xc0t4mTg\xeb\x02\x00^p\xfc\xc5qU\x8c,\x01\xb7\x06m\x1cH\x85\xfe\x03\x9a\xd7r\x1f\x00\x08\xfcF\x9b\xd6O\xf1\x9c\x07\x17U\xc0\xedX\x0b\xb7\xe3\xe6\xfd=>\xeeq\x0d\x07Nd&\xde\xc2\xcf_\xa0\xb7\xb6yD(T\xd0W\x19\n\xd3\xa8\x07T\xa9\xdf\x0b\xcf\x9f\x17${\xc1\x9d\xa7\x91\x83X\xdbt\xe1\xc0\x96J\x1cY3\x1f\x9bB:\x9a\xcf\x84\xdc\x0c?\x1e}\x1e\x12\xd52M\x14\xd9\x9f\xc5c\x82\xdc\xbb=`\xcd\x99dB\x18\xd1\x7f*\x07\xcd\x03\x00TY\x80\xeb\"\xfd4\x85\x95\x18\xb0z\xd3\xc5\xbb\xa1\xad\xf0\x18T\xba\xe3\xd13\x02\xceG\x16\x82K\xe2o\x06u\xfe|9\x81\xb9XZ}\xb5\xb7\xc4\x9f\x15\x93:H\xa2\x1as\nn\x8cqi\x12\xcf \x18\xc6\xe5\x96p\xce\xa7u{p\x92\x07\xa9\x8bX5xdw9\xb0\x01\xc2\x82!c\x87\xce\xf8\xbbo\x0c3\xcaW\x99\x91\x96\xb7Q\x0c\x14\xf6\x14q\xf7\x06\x0f\xab\x894\x07\x0c\xcdxE2b\xc4p\xef {(b`\x0bLmW\x97\x18\x9f\x99,.a\xbea\x8c|JN\x7fz\xe9\xa7\x0e\xbdA\xfa\x97\ndZ\x89\xf1\x18\x99fW\xb9\x87V+\xd6\x0f\xa9X\x93\x9a8\x1bB\xe6\xf7RH<\xc6-F\x82&\xd3\xf8x\x85H\xe0\x82\x10Y\x91\x0c\xe9J\xf8br\x013\xef\xa5\x9f\x9a\x19\x05\xe0\x84\x89\xcc\x15\xf7s\x93k\x99)\xc2\xb0\xfc\x08\x93\x80lZx\x94\x1d\x18\xd0x/\xa3\x0d\x12'u`\xc7\x8e\xc9_N~\xf8\x88\xab D \x97\x0c'\xc6/\xf5\xac(\xa8\xc4\xbe\xed\x07aO\x0d\x95\xc8\x0f\xbbm\xa8,\xe4\x08X\x9b.\x04\xde,Y\x9e\x86\xb18M\xb9\xc3r\xea\x9f\xf6&\xc97\xa3\xdf\xa3\xabt\x88L\xa8W\nC\xa6\x9b\xc7^\x91\xbcKS\x92=\xf5sb\xa3\x11P\x15+\xbeW\xec\x86\xa7\x9e\xcd\xcd\xb1\xf5H\xa2\x1aP\xacH\xe7!?\xe7<\xb6y\xac\xcc\xf8-\x1eTT;\xf28\x92&}\x9c\xc1:\xc5u\xa1\x9aU\xba\xcd\xa5L\xc9\x13A+\x0f\xd8\x80!\xb72\xdfN\xdb\xca\xab\x86o7@N\xef\xdfbx\x02\x915\xc7\xe7\xf3v\x07\x82\x05^\x06d\xc5\xcb\xa0\x03T\xc4`\xd6\xa2z\x1a\x02\x06\x8a^\x1c\x13\xa0\x14\x9dL\xe0\xf2\xa3a\xb5o ?j\xeel\xc0n\xf5\x9ef\xba]\xc3\x98\xd1\x06_\xa8\xf2W\x07\xdd\x86\xc6\xcd\xfd\xe8\xbfpi\xaf*\xac0\x8d\xeb\x0c\x0e\x1b\xf7\x9dc\xef\"\xf3S>\xa4\xdeK:\xe3\xf8U\x03h\x03\x04\xbe\xe2\x0e\xca\xa6q\xcf\xb5\xc6\xbbD\xe3K\x14\x10 A\x91\x9d0\x1f\x17\xb4UL\x8e\x1d\n]m\x9ad\xc8P@Z\xaa\xde\xa3\xd9~\xc4\xbd\x88\x87\xa3!\xaci\xa9:\x14Q\xc4t\x8fB\xbf\xd8~\x90\x90\x90\xcfY\xe6\xc8\x16\x89\x92\x87\xb2\xb4\xad\x10\x13\x12\xe4P$\x954\xaa\x96\xd2\x16\x0b\xbf\xe0\xafs\xf0\xb1\x91\xaa\xcc\x0e \x14\x0b\x02\x17\xec\xe4\x00CD\x8e\x0e\x11\xc9\x0f\xef\xe8\xc0\xcez$\xdd<\xf0\xe67\xbcO)\x88\x08\xbd\xafM$\x82\xb6\xf8n\xf1\xc4*\xd7\x8e Q\n\xa2\xce\x8c,\xb26\xb2\xa8%D\xfd\x01\x0e\x9a'S\xce\xa5\xa3J\xe7%?\xe2TN3 9<4)\x16A\xb87)qL\xc2\xd0J5\xf8^\xc4\x12v\x10K\xb1\xc2\xf0A\x16\xcaO\xb3a\x88\xc5\xef\"\x16\x9f!\x16\xb4x\xf5\x99M\xaa\x82\xd9\xe9\x1d\nH\x14\xd5\xca\x88\xa5\xb2\xbe\x0d\x15\x1c\x0d3Mb\x83\x0d\x1dn#\xcdlr\xc3GP\xae\xaf;h\x0e\xdd\xe0M\xca\x9e\xe5\x10\x8f@\xf1\xc8\xcf\x990\xda\x94\xcb\x8b\x9e\xc7v\xe2\x1cS\x8e{\xe6\x17\xb6\xaf \xad\xdb\xcfM\x10\\hBp\x02\xc0~?\x0c\x17\xf6\xa1\xb7\xc2\x80\xde\xd4<\x0e\x08\xf4\xa6a\x81n\x87\xdeP\xca7\x08\x99\x0d\x90\x94fM\x0b\x17\x15.X]^\xd0\x14\x08\x10\njL\xec\xad^\x0e\xf7v\xe2\xbe\xa6|\xfd\x1fg]\x06#\x16\xc1m\xb3C\xabr\x11\x15\xcf\xf5G\\\xe3o\xe2\x01K{c\x99\xe5\xc4+\x93\xc7z\xeaV\x83\x92\xaa\xb05<\xb6\xf9\xbe~\xf4\xd0\x96,\x8b\xb2[m\xce\x9d\xd2jJz\xaa\xd2\x98T\x14\x99\xb3\xa2\x84EEa\xf5RFz6\xb0\x97\xc1\xe1-\xf4\x1e/\xf9ix\x84u\xc9\x8f\xb0\"?2\xa7\x8a\xe6\xe4\xc3W\x90=\x02\x9f\x92\x1f\xe1\xd4o\x92\x1f\xfe\x00\xf2\xe3\x9c\xa7C=\xb0cAl`*$\x0d\xa9\x11\x1a\x93W\xf2\x87O^i\\\x81\x89(m\xd6c\xe9\xd8\x85\xcd\xa2\xca\x1b\xdb4X\xd7|\x14q\xc5] )\x08\xc6\xe6\xfa\xf0\xa1\xa3\xf1\x13jt\xf5R\xcah\xca\xab\x85[\xed\xc8\x1d\xe2Q\x9f\x18\x99\x84\x1f\x80nl4(<\x0d\xc5\xbc\x9ff\xc4\xa7\x07\xcd\xa9\x10\x17\x90\xc1\xa6 \xd2\xc6\xd7\xce\x8b\x85\x99\xcd\xe8k\x1a\xe4\xeb\xb4\xe8\xb3\xe1\x82\x017\x9b\xfc\x08\xe9\x1f\x05\xfd~\xf8\xd6\xbb\xff\xb7\x1f\x94(\xdeB*!\"\x06\x0cZ\x1e\xe0\x1d\x0e\xabI\x1f\xba5\x138\xf7^\x1d\xfcpr\xf4\xed\xdb\xd7?\xbc:9x\xfb\xb6_\x03#\x1e\xcc\x80\xa0\xcf\x92\xa5zR\xff*J\xfc\x80\xa5\xf8Y\xc8j\x84AM\x98\xb5\x1bX\x03\xe6a\xecG\xd1\xd0-\x12@\xd5[\xd9\xdc\xb5\xc9\x02\xb0p\xb42\xd7[b\xaa\x97~\xca(\xe8\xe4M\x96\xa4C\x90\xd5\x10\xf9\xb7\x11\xcf\xf4\xb6\x04M\xac\xd2\xb2\xe3!\x03H\x9a\xdb.\xc93\x8e^\x87\xaf\xca \x92q\xd8\xb2\x0c!\xee\xec\xa6\x87\x02\x8a\xe5\x0dVL\xc8\x81\xd5VG:P\xea[\xb6c\xfam\xf5\xea\xdaV:\xaa\\hCG\xddZ\xc5\xab2\x02-\xd4\x0d\x9b\xac\xa2\x1b\x0d\x8fT\xde!\x0dA\x860\x03\x95\xb4\"\x83\xea\xcbF\x9a\xcd\xea\x05\n\xd8j\x96\x04)\x9a\xd6\xd5\xd6\xaa2\x80Z\x15T*\x91\xc8r\xe6\x1a$\x91\xf0*\xf9\x1a\x067\xe8H\xe9\xf7\xc1n}\x89&\xb6\x9c\x8c\x9b\xc6\x14\x18x\xf4\xea\xf6`\xa7\xd91\x86\x95\xc1yu\x1b\x99&.\xc4\xc7\xc6\xaf\x9bp\xa7\xd0\x19\xb7\xbe\x91\x13\xfdk\x9a\xd5\xba\xee\xcb\x8c}w[\xdb\xbb\xaa\x8a\xa1Y;\xddC\x18\x9b]B\x98\xa261$\xe5ow\x18V\xa9\xa3\x1aoe\xd5\x8f6\xc2.\xc8\xb2\xd5a\xca\xa2j.%\x9d\x8b\xdfG6\x9c\xf3,K~\xaf\xa8\xb2 `9\x93\xd6\xd2O\xa7\xf9\xb1+$\x9fye\xb1\xde\xd8\x96\xee\x9bir\xac|)O\xb2\xb7\x02\xed\x13\xe3z\xf4Ub\xf3\x13\xb0\xdfW\xdd LU_\xf2}\x88W\x8d\xf4I#2\xa1*J\xc4\x81>Z\xc6\xaa\x9e$*\x9c\xe9xQr\x86\x02]\x850$\x96\x93\xa9\xef1Ij\xcb\xf7\xc3D\xec\x0b'F#\xb1\xa0'\xa3\xa5\xb0\x98*N8\xab8\xe1B\x84\x12\x7f\x04 |\x05\xc5#H('\x9cQ\xf8\x92W@wb\x05\x82GcpN\xa7\x13\x17\xa6\xf4\xba\xaf\x00&SY\xae\x0c\x8d\xe5\x85\x11C\x9a\x19\xc3\x08\xcfE\xd7\x036\xd7\x7f\xe8\xfe\x92\x13\x8d\x9f\xe0\xdb\xdeX];[c\x85\x17\xb0\x9c\x14\xa9.U\x07\xc8S{\xca \x9dE\xdbI\x99\xb4\xa3\xca_\x0f\x19g=\xae\xf1\xa64\xdc\xcc\xce0\xcce\xc6b\x86\xb2|7\xda\xb8\xa1\xedX\x9e\x98+\xc5\x9b\xd7#q\x86\x0c\x85.\xd9\xb6)\x87\x94\x9f\xe7\xe1Y<\xa4\xa9\xfeY\xe9'\xc3z\x99`\"\x98-g\xc59\x98\x93\x0c\xc9\xa7\xf2Z\xbd\xfb\xd9\xed{\xa1\xeb\xd8\xf6\x9ef\xb1\x055\xc1\x1a\xb7\xd4\xb9\x8cv\xb6\xdaYyJ\xcc\x1aP\\$O\xf8\x01\x7f\x93$\x11i\xa5{\xc3Yx\xf3\xa4\xccL\xb5\"\xd8\x83{?\xde[\xbfw\xa6\"\x86gZ\xbfi\xdb\xb2`\x1d\xd0\"\x13MG\xed\xc8\x05\xeb\x8b/\xefYf\x94>W\xca>Q\xd0C\xeb\xf0\xfc\x1c\xf4\xcfY\x12\x17\xe4\xb2`1<\xf9\x9b2\xa6\x7fo\x1a{Hu\xe7Ul\x0b\xc1\x9e\xba\x18_\xd0\x9e\xd8m\x0b\xd33_\x99\x84\x19\x0f\xb1\x81\xac\xaf\x9bg\x1aHaI\x94\xf3\xcdH\xce\xf0\x98\x98\xf1{r\xf5&#\xf3\xf0R\x9a3_\x94\xb8\xb3(\xd9J\x8b\xb2\xe8_\x146\x9c\xee\xb2\xf8XZ\x8d\xad[\xa14\xaci.\xafi\xb7\x98\x02_\xc9\xd66o\xadms\x03\x9a\xc4WD\xa9\xfbs\nq\x19\xaeo\xe8\x15\x0b\xbfx\xcb\xd4\xac\x02\xd8)\x05\xcf\x13\x9e\x02\xcb\xe1\x98xa\xfe\xbd\x1f\x85\xc1ADh\x0d\xda\x0e}\x1f1\xc6 Jb\xf2$\x0e\xde2x\xfe3\xb9\xa2\x1d\xf8\xb0\x0e\xf6ZD\xe7\xcf\xe2\x9e MF\xff\xa2T\x01{\xbf\x0f\x96\x05\x13\x98\xd9\xf8\xa7\x03\xeb`\xdd\xb3\x1c\x0cU\xe8\xb8\"\xf0n\xe4\x98\xc1\xe5\xdc\xee\x0f\xcf\x04{`Y\xcd\x85\x113dq\xb9h\x8d\x19e\xc0\xd9\x10\xba\x1c\x03\xdd\xab\x802\xd2\x88\n\x02\xbb\xc0([\xd8a\xb3\xb2O\x87\xb3p\xa1\xa4\\\x92\x97\x91\x88\xf89\xb1K\xf3\x1c\x96=We\xe3\xce\xaf\xef\xf4\xb9\x14P7 \"\x95\x81I\xcd\xd88\x1a(\xaco\x9d\x8e\xc6\xcb\xce\x01\xa1\x9b\xe2\x07\x01]\x830>;J\xec\xb9\x98\xe8\x8d\x06R\x1dd\xa9W\xf9,K\xaf\xefp\xcc\x81\x0by\x8b\xae9\xeb\xc8>\xe7Iv\xe0\xcf\x16\x93^b\x06\x84-7\xb3\xb5\x96\xa2\xac+\xec\xc5\xabk\xb4 I*\xb7f\x84\xa3\x94\x85\x84\x9aWp\xd4\x8e\xc3\xdc\xc4\x0cK?\xfdH\x03\x9e*\xa8`\xfe\x15\x9e\xbf\xcc\x15\xbb\xc0\x9c\x8f\x8diJ\x96~\xfa<.\x92\x1f\xc2b\xf1g\xb1\xdb\x98?5\xf6\xa3 \x9c7+\xe3\x8e\x0e\xd0\x00\xf2\xd1\xe0\xb2-\xd9h\x8ckU$\x88\x12\xfb$y\x82\x95\xe8[\x80B,\x80\x1a\xa5vRg\xd5\xf0\xa9\xa6\xa2\xce\xf0\xed-\xa9\xa8\xd1f\x9b.\xc2\xc0\x7f\xb1\xfd\xc0\xe9\xb34\x16)U<\x91R\x85B+g\xa3\x86H<\x9b\xdf\xa5I\xda\xa3\x83b\xa7\x17\xfdjY(\x16Epr\xdd\x06\xc4\xe4\x02\xbf\xef$gP\xd0\x8a\xe6Y7R\x85\xd1&1)\x8fm\x8dw0\xc7\x85\x84\xdb*\x1fN\xc5\xfaPv\x92\x16\xa5I\x12\x1d\x86?\xd7n\x9d\xcd5\xa1\x97\x9b9\x9d\x04\xa5 \x92.\x01\xdb\x1d\xb7\x8c\xdf\x06\x9c\x15\x90\xc5`\xc6m\x89\x1bc\xe61%\xe3\x1a{\x01g\xf0}\xfa\xb6\x9a/K\xc7T\xfd\xb9\x07#L\xc6$\xb0\x18\xec\xd1\xbbS\x91\x9bIAZ\xc6\xa4I\x83O\xda\x0bB\x9f\x0e=?p\x0dn\x02\xe4 \xad\xddJ\x80\x0e*`\x8fyl~\xd5r\x80\x12\xe6A\x05\xf7\x9dT\x15\xa0^\xceb\x91\x91\xce\x82\x0e\xb90\xe0\x96\xab\x95\xdd\xc9je\xae\xf0\xcb\xeb\\1\xe2\x19\xbe`\xcax\x1e\x8a5\xeb\xf2\x81\xdd%3\x98\x91\xdcf\xd5\x92;Y\xb5\xa4Z5FM\xa8\x9d\xc0VZ\xb8NB\x88n\x0b\x9a{\x8d\x99k|\xac{m\x9b\xa5Z\x1e\xef\xdeW\xc5\xa2\x8b\xed\x9d\xadv\"]\xbf\xbe\x10c{g\xbb\x13^\xaed\xe5\x0f\x1d\x17,\xaf\x9d\xc6\x95N\xc8\x9aX\x9ax\xc5\n\xc4#\x08-\x0c \xd2\xcdx\x80\xef\x05cB8\x8b\xe4{$\x9f\xf9)\xb1 c\x92&\x18Z\x9e\xe5Q\xb0\xb7v\xdb\xd22\xb8\x990\xae\xa2\x06y\xdc\xccj\"\x84\xc7w\x9a\xb90\xd7\x11H\xa9\x8bq\xf2\x84\xb9F\x1761_I#05\x86\x91\xfd\x12\xacSz\xa2\xfcX\xbc\x12YP\x90|sk\x07F\xbcd,\x16\xab\xd9\xc27X\xd7\x8a\xcb\xe5)\xc9\xe47\xf5\xaa\xf2.\n\xef\x8b/\xf8\xc8\xd0\x15\xb2\"wg\x94{)\\\xca\x83\xb2\x00\xcd\xfbP\xc2: \x05\xb2\x89L\xb0\xe3\xc2HM\x13/0\xc6\xa5\xf2\xc8\x9c#\xb3)59\x81\x18\xd6A\xa1y\xa1\xab\xd2\xe4\xcf\x0b\x8d\x06\xa1\x92j/\x99\xc4zII\x8c*\xbc\xf6r}\xdd\x81\x05\xac\xef\x01\xb1S\xba\x0f\xd3\xe5\xb1\x0b\xe78\x97\xd4\x85\xa5\xc3w\xaf;\x02Ml[\x90\xd8\xa2P\x99\x8d\x10\xf8\xf0\xcf\xfaP\xd8\x95\x8b\xd1\x04\xcf8m\xd7\x13Z\xe6\x0c\xc1\xa0\xf0H\\d!\xe91s\xa9\x16\xe5\x84-\xca\x9a}\x05{p\xea\xc5\xe4\xb2\xb0\x1d\xc7\x0b\x12L\x1d&-\xcc\x15K;#\xad\xcd\xc9\xfa\xba~u\xc4CW\xa9\x7f$\xda\x01\xe8\x17H\x91i\xd2\x8e\xe1\xae\xcdSU(\x92P\xdd\xc1\xca4\xc7\xca\x0e\xc2P\x0e_\x0d\xc6\xd6\x9e5\x01koS\x03\xc1\xd6\x04\x8b\xc7V\x17J\xb4\xf2\x02\xeb\x0b\n\x93\x1d5\xc0\xbd\xe9\xde\xe4\xf8\xdeY\x1fc.5TL\xc9q\xb7_#GY\xc6w\xb3(\x9b8m\xdd\xa2\xec\x8di\xf1d\x95Ea\xcba[\x1e;\xccd\xba\x89\x1az\xbaV\xeco\xd4D\x13//O\x19\x15`\x8f\xd1\x97Pz1r\x1ci5\xed\xbd\xcd\x0f{c\xe7\xee\x17\xb4\x86W\xf5\xd9\xb9\x13\xfd\xd7\xfd]\x87\xc7\xe8\xfc\xc6\x9f\x15Iv\xd5=\xc5\n)\xc0\x84\xa2H\xbfM\xa5b\xd1\xe9i\xc6JOO3e\x85 \xc8H\x9e\xb3:\xec\xb7\xb2ZFx/\x19Qw\x94\x15\xe1,\"\xbc\x0e\xfeVV\xcb\xc3\x80W\xa2\xbf\x94U\xca LX\x15\xfaKU\xe5\x14\x8bO\x95E~\xce\xda\xa7?\x94\x15\x82\x90\x95\x07\xa1\xba8\xe1\xc5\xea\x9e\xc33V\x1c\x9e)\x8b\xa3d\xf6\xfe\xefeR\xf01T\x7f*+'\xc1\x15\xab\x96\x04W\xca\nl\xeb\xd4\x1bwZ\x16E\x12\xb3\n\xf8SUi\xe6\xc7\xe7>\xdb\\\xf6S])\xa5\xe0\xcak\xe1oe\xb5\x90\xcf\x8a\xfePVH\xf8\xd6\xd2\x1f\xea\n\x11/\x8f4\xc5gYR\xa6\xa2\x0e\xfe\xa1\xaa\x18\xf8\x05\x03F\xfaCW!\n\xf3\xa2\xaaD\xffPV\x0cX\x95@YH\xd8p\x03\xa2\x1cn@\n?\x8cr^\x05\x7f+\xab\xcd\xd9\xca\x06s\xe5\xaa\x06\xa1\x1f%\x0c\xa6\xd8Ou\xa5s^\xe3\\Y\xcc\xc7\xa9\x1e&_\x05\xe5\xfc\xc9\x12\x0b\xc9R]xJ\x02^~J\x94K4\x0fI\x14`\xd2\xe7\xcc\xb6\xc4\x1f\xea\x8ag2\x98\xd5\x7fj*\x97\x19\x11\x15\xcbL L\xf3$\xc1\\\xb5\xff\x1f{o\xda\x1d7\x92$\x08\xbe\xdd\x8f\xf5+\x9c\xf1\xaa% \x03\x0c1H\x89\x94B\xa2\xd8J%\xb3[\xdd\x99\x92FRVMw0\x8a Fx0PB\x00Q8xdQ\xef\xf5\xcc\xec\xdc\xf7\xee\\=\xf7\xd9\xb3;\xf7\xb1\xc7\xec\xce\xf4\xf4\x87\xce\xfc#\xf3\x07\xf6/\xecs3w\xc0\x017\x07\x10$\x95U\xbbo\xf1\x81D\xf8\x05wssss3s3Q\x08^\xe9B\xc9R\x16I\xc81.\x86\x90\xbd\x18\x92\x99\xdb\x98\xb9Mf\xee`\xe6\x0e\x99y\x1f3\xef\x93\x99\x0f0\xf3\x01\x99\xb9\x8b\x99\xbbd&\xf7qB\xc4\x8b\xad\x80\x04\n\xbe\x92\x85\xcaU\xb6\xb0\xae\xb1\x85l\x85n![\"\xca\x89\x17\xaa\x00\x92X\x92\xc0\x06\xf3\xc4_\xe2\xe4\xe2+Yh\x89K\"X\x92\xeb!\x88V9\xe2\x1c\xbc\xd1ERY\x80\\\x95\xefO\x10\x90\xefOH8\xbe\xe7\x97\xa7\x1cQ\x15_\xa9B\xa1\x7f\")\x04\xbc\x91E\xf8)\x8f\xf0K\xf8J\x16Bh\x85$\xb8\xc2 z/\xb3\xa3\xf7T\x81\xa5\x1f`G\xc5\x0b]`%\xf3\xc9\x89^\xfa\xc9{\x99\x9f\xd0\x1f\xe0Q\x8e\x05x\x94\xdb\n\x04\x99$%\xea\x07]P\xd2m\xf1b) \xb1\x17\xde\xa8\"\x91\x8f\xa40\xf2IR\x18\xc5\x18M\x19\xcb\xc8\x1fTA<0B1y\xac\xa5\n\xe1\xf4\xd2\xdbU\xbc\xca\xca\x85\xa4~X\n*\xba\x17[i^\x9cg\n\xa7\xf1\x95*\x84\xdf\"?\xb2\xf2\x13\x1fg\x00\xde\xc8\"\xc14StU\xbe\x93\xc5T\x11[v|Zp\x8c\xea\x07U\xf0gP\xe2gTV\x82\x03I\xc8\x91$\x08\x85\x84\x84@\x92\x9f \xcf$^\xa8\x02\xd8/\xb2C\xa9\xbf\xc4\xef\x8a\x17\xb2@\x89:v\xc4I\xf9\xb4\x98N\xf9N\x17\x0b\x15~\xe1+Yh\xe9\x87\x88b\xf0F\x16\x89\xf3d\x8a\x13\x82\xafd\xa1\x95/;\xb4\xf2\xe9\xdedI\x1c!I\xc5W\xba\xd0\xa5d\xe0\xe1\x8d,\x92#\xeb\x9d\xe6$\xf3\x9d\xe6\xcb\xa5\x9f\\\xca\"\xf0N\x17\x93\xf3@\xaf\x97\xcc?\x91\xfd\xc80R,Q\xa4\xe0\x9d3\x1b\xf3\x9c!\xd9\xcdH\x92\x9b\xf1\x8b\xac8\xd2\xa8\x1fdA\xc1[`)\xf1F\x16Y`\xfe\x82\xceT[vf\xdb\xb3\xb3@n\x87\xe2\x85.\x90)x\x887\xb2\x08R\xcd\x8c$\x99Y\xe2O\xdf\xcb|\x7fJ\xd2x$\xf0$u\xcf\x11As\x12;\xcf|\xfc\xf0\x99O~\xf9,\x98qW\xfc\xfa\x9c$\x11<\x0c\x83\x95<@\xcaw\xaa\x18\xae$\x9a5Y\xfa\xa7\x92\xbb\x11oT\x910\x88\xb0\x84x\xb1\x15\xf0\x93_K\xfcY\xc0\xa3\xac(Z&Q\x95\x96~\xaa\xf6\xf1\x94\x9c\xe3\x95\x82\xd0\xca\x02\x9d\x95\x9fe<\x89T\x19\xf1N\x16\x8b\xc3\xcbSI\x00\xe5\xbb\xadX1R\xf5\x83*(\xc6\xe4\x87\x95\xd1V\x93\xc8J\x8a\xb8&6\xd2\x9a\xc5\x92\xc8d1M\xec\xcf$=<#\xe7Q\x10\x85\x82:\x90\x05\n\xa2\x9b!\xd5\xad\x94\xb0\xc8\x88P\x05{\x0b2\xa2\xaa]f\xb5w2\x1a\xfb\xae\x1e|\xac\xd2 eMv\xc3~\x18\xc6\xd7\xf8\xe1\xba\xe95j`)\xfdk\xe4\x0c\xeb\xe1\xb5r\xd9\xf7zq\xb4\xa8\x7fp\xff\xbeeL\x8df\x1f\xcal\xe3&\xf2s&\x8doi\x19\xba\xfa\xcaT\x94x\xf2\xc4\x8f\xe2\xe8r\x19\xe7\xe9\xd3\xa7\x84\xa8tn\x95\xaf\xfah\x99v\xe6\xf4\xe0\x8dB;\x06\x82#\xc1\x98\x9e9\x85\x12\xd5RN\x0c\x17\xca\x15\xe3\xb6\x14Dm*\x14\x95\x8aUKA\xc55\x9f5q\xcd\x0c\x19\x8e@0\x1cg\x8eR\xde\xda\n\x02\xd0\xb1 \xbc\xda\n\xfa\xd1\xe5\x88-\x9cD7\xb3{ \xdab;(_\xcd\xdb\xe4\xdd\xeaQ\x9a\x9c\xaa\x7f\x1fk|\xcc\xfaS\xd3wh\xb7\x9a\\\xdd\x94b\xe6\xf4\xd4U\x13\xf6u\x8f\xf5!8j\xefk\x16\xcf\xcbx]\x98\x91`\xc6\xc2OY \x03\x16\x8b\x9a\xef.W\x9cEq\xe6\x83\x8a>\x88\xd2`\xc6\xd5P\x07m~\xb0\xce\xe4\xbd\xc0\xac\xd5\x99#\xdcn\xad;[k\x83\x01\x93\x9f\x00+F\xc7\xef\xee\xf4CBF\x05f\x16\xc3\x8f\xc5\xf0\xeb \x12 \xc5\xb4\x14\xd3\xd2|\xb5\n\x03>cY\xacC\xcdc\xfcb\xc5\xa7\x19\x9f1?B\xe8\x0c\x08g\xb1\xfa\xd3|Q\xbfP8\x87\xa8p\x0e\xd9\x13-\xc8u\xd8\xefw\x05\x0d\xdc\xd6p|\x8f\x85\x05f\x89\x1e\x8fE\xdfC\xf16\xe9y,\xef\x0091AS\xddf\x11.\xe5\x95\x16\x0e7\x18,ey^\x7fl>T\xe8\xa5\xc8q\x93\xea\xe0Q\x80\xdd|%\xae\x89\xe4|\x0d\xc4\xce?>b\xe7\x9d\x11\x9b\xa5At\x1ar\x8c\xbf \xd9\x80\x9ba\xf9M&\xde\x16^Ja\xe8\xf7J\x887\x1cp\xba\xa6\xad\x0e\xdey\x8e\xf1\xeeN\xe4/\xc1\x98\x95\xb8\x9fC=y\xab}\xb1\xedA\x1c\x1cL\xe3\xa8\xb8;qu\xc5\xaa)\xd0\x9bri\xb7c\x9fz\x94\xd1\x99\xd1X\xa7\x16>\x00\x14\x7f)\x90]\xcd\xa4\xa8\x0e%|(\xf1\x8bCw\x0b\x17\x05\xfa\xafk\x12\xb9\xc6\xbbL\xf5\x07\xd0f\xe9\xf0q6q\xeb\x0c\x86>\x01I9\x01\xb1\x05\xd8\x91IY\x80\xa4\xbc\x8cg\xbc\x95\xa3\xb8 \x0cm$\x03\xf9\xca\xef\x95`\xfc\xc2875\xd6V@\xeb\xbbZ;M\xea\xc6\x81UL\xba6*\xf1\xec\xd7_\xcb\xebpd\xf8\xcd\xd61k\\\x17\xf8\xa5h\x1d\xb6\x18\x90?X\xf8\xe9\xab\xf3\xa8\xb8[\x1ev\"\xfd\xac\x99A\x1b\x00\x83\xd6\x8d5c7e\xcf\xd8/\x80t\xc5\xd1\x1a[4q:\xd0<\xe5\x18\x07\xb4\x06\xbb\xbe\x9b-\xdd\x02A\x8a\x95\xa1{X\xe6\x05\x83\x9e\xeb\x17\x8fm\x8f\x18\xd4J\xcc<\x07\x7f\x1e:\x8c\xdb\x97\xa6Xp\xbf\xf1\xf6\xd5\xcb\x01\x9eu\x83\xf9\xa55\\\x80z\xd6\\i`\x1f\xaao~\x1d\x96Z\x1c\xc1\x8eY,\xcf\xa6\xfd\xf2\x1a\xe8\xf2\xee\xb2\xdd\x9cL=\xb7\x862\x157\x1f[\x8fYV\x99\xe9\xac\xfd(\xa6dAb\xef\xec@\x1f\xa9\x9d!*:\x1e8\x1bC\x8f\x15\xb3\xa7\x9c\x87T\xe6\xa6\x80\xd5\x80\x1d\xd6\x8f\xa5\xb0},\xf8\xf4}\x01\xc6\xd4c'y\xc6\x12>\xe5\xc1\x19\x9f\xb1_I\x99\x9f\xb1 \x9a\xf1\x0b\xf6+\xe9\xa0\xe7\xb1\x13\xf4\xed\x05\xf7\xa4k`\xb3\xcf\xee\xf7\xb2\x04\xa5o\xd1r:\xfc\xf6\xe9`\xda\n\xe2\x9d\xbc\x8f\xeaWX\xd3jo\x05\x81v;QG\xd6\x99\xc6vY\x9f\x96\xa5x{\xeb-]t0\xddT\xcf\x0d\xa7\xf4\xff;\xac\xc6\xd7\xf8\xc5\xaf\xd7\xe44:\x1d\xe0\nfa\x1cv\xc4\xd9i\x97f\x99lz\x0en n\x85\x0f\x99\x17\xa0\x9e\xb7\xd6i^\x12\xdd\x16\xcc\xed1%\xfc\x02BK~oX\x9fv\xc6\xfa\x10\xb0\xbe\xee`\xae\xfe\x18X\x1f\xde\x00\xeb\xc3[\xc7z\x85\xc2>:\x93\x04\xfe\xa9\x8dk)V\xca\\\xac\x94N(-J\xaf`\xa5\xcc;\xae\x94\x8d\xd5zpz\xcf\xe5\x99l\xdeL\x8e\x8f\xa2O\xfdY\xa1\xc2\x10\x195\x9e\x0da\x80\xd7\xf9{L^\x139\x8a@\xd3\x06\xb7J\xc8Z\xfa%\x13\xe5\xa7K\xd6\xef\xb0L\xcf\xe4\xa5\xb2\x95\x93zln\xae\xf6y\xb7\xd5.\xe0\xb6(\xc0\xb6\xf8\x05\xadc#\xf5\x83vE\x92\x99>\x87(\xfcQR+y\xfd\xef\xa0pR\x7fu\xc5\x86\xec\x1ed\xc0K\xc6F\x8c\xc3\x85I\xb8\xed\x07\x0cZ\xa5\xb5\x0f\x96o\xcfhJ\x02\x17g\x97J\"\x81\xe8\x84\xe2=\xf0\xd8\x1c`\x92\xa37\x1ep\xb1\x13#+\xfa\xdc\x0f\xc3 :-D\x0e)\x83\x95\x03\x8e\xb9\xd9,H\xf84\x0b/Y\x90\xb2(F65N\x04\xd18\xb9\x84\xc0*_\xaf\x92x\xb5)\x88N\xfa5[\xf9\xd3\xf7\xfe)\x1f\xb0\xafR\xce\xbe.\x1a\x1c\x00\xc3Z\xfct\xdc\xaf\xc5:\x9b\xfaa(\x9aX\x0e\xd8\x1b\xee\xcf\xd82N\xb8\xe0\\\x17Y\xb6\x1a\xdd\xbb7?\x19,\xf9\xbd<\xe5\x9bP{\xb3\xfc\x8eu\x91hx(f<\x19\x07\x13v\x007+\x8b\xcb\xa1*\x0d\x89\xc4\xbb\x05/\xcf:\x15\xa2\x19\xa4`\xe5(\x18\xef\x94%\xfcgy\x90\x80TQ?O!\xdf\x1dd\xa9$\x067b\xdc\xa9\xe0H\xdb\xa5k\xa6+\xe61\xbc3\x92\xa1\x0d*\xb4^\xba\xd6B\x1co\x10\xd7\xdd\xd5#\xc6\x10c,\x91\xa4\xdbm\xee\xa4v\x9b\xbb\x8b\x10\xe11\xdb\x80\x10\x91A\xed\x16ucMV\xeaBb\xbcB\xadM\xe4\xd0\x0e\x9a5nvS}\xea\xc8\xf5\x82\x17\x9f\xae7\xbbAx-\xf0cc\xe9\xf8\xe3\xe1\xa4\xd3@X\x17\xd9\x8e\x0d\xa3\xa5[\xd8\xf6\x05k~\xbf\xeeu\x96&s\xa7\xcdWL\x95\x9e\xc5\xba?\xd5\xe5\x85\xec\x80I\xbb(\xe0\xfc4\xf1\xfa\x1b~zx\xb1*\xef\x81\xf7XGG@\xf2K\xca\xf4\x08\xaf\x9c\x82;\x89\xb7ZJ6\xee\xfd\xea\xaf*\xd7\x1b\xef\xfc\xd3\x1e,\xe0\x16k\xb2L\xef &\x9bpD\xa7W\xa2\xe3\xaa\x07\xf58r6\xe0^\xda\xddwiN\x98a,\x05\xb5+UZx\x07\xd9\x84\xbc\x9a\x9bSR~m8\x01ht\xb0T\x99\xa1\xcf\xfcL\xfb\xfa\xcc\xcfx\x8f\xc6J\xa3&\xcemY7\xe1\xa7\xfcbE\\1\xb6\xa1Q7x\x9e4#+-\xd0/v\xec\xe6\xad\x1a\x91\xb6i\x1bn\xdd\xf6\xd4\xe8\xfd\x088\x9b\xc6=\xb4y+\xc620\x03M\x05$\x98;\xf4\xa8\xa9C]iL\x9b\xd3\xb7\xea/YIs>\xc9\xf6Q\xc5V\xa6xl^;\xa9\xb0}\xc1J\xcf\x07z\xc2\xdc\xd3\xa4b7\xf0C\xd0\xe4x\xa7P\xe9\xdfR\xfb\xbd\xe1\x83\xc1\xee@z\x1e\xb8Vkg\xa5\x8f\xe9\xdd\xfb\xee\xa0\x88\x98@Y\xf3\xb6\x19\x1b\x07\xb2\x9d\x07\xa4}\xef\x83\xfb{\x16\x83]\xdfQ\x92\xb9\xdb\x18\x87aG\x8c\x9d\x1fn\xd3n\xa3\xeb&\xca\xa2\xb3\xbdep\x11Di\xc7I\xad/xuf\x19\x13\xd2\xc3\xd4j\xef\x8b\x9f\x1c\xb1\xdeg\x87\x9f\xbfxyx\xfc\xe5\xb3\x97\xbfe\xf1\xad\x90f~\x16L\xbb\x95])\x0c\xefTZ\xfaS]\xa3\xc2\"\x08g\xcf\xd7\xadu\xca\xb3\xcf\x90\x1a@\x84\x9dj\x9d\xe3/\x0f\xdf\xfc\xda\xe1g\xf6\xaa/\xa2 \x0b\xfc\x10\"\x17\xadY\xf5\xb9\xd6\xddu\xaa&<\x82\xbb\xb4\xaa\xc6\xab\x97\xcf\x0f\xad \x94+\xe8\xc7A\x18~\x89\x8eK;\x80\xa4\xa8\xf6Y0\xbbF-\xf1\xb17\xa8($@j\xc3\xa3E\x9c\x0bp\xc86\xbeZ\xcd*\x10\xed:\xc8z\xbd.\xfd\xfd,\x98]\xa7\x1a|.Zv\x86\xcfW/\xdf>\xfb\xfc\xf0\xf8\x9asB\xd5^\x1b\xc8T#k\x0c=\x87\xa2\xc5\x1c\x8dX\xef\xd5\x8f\x0e\xdf\xbcy\xf1\xd9\xe1\xf1\xa7\xcf\xde\x1e\x12\xbc\x8f\xd9Nh%:\xb0\x10\x93\xe0\x8c\xcf`5}\x9e\xc4\xcb\x86\x15\xd9\xe5[S\xeb\xb7fA\xba\n\xfd\xcb\x97p\xe3\xbb\x13G\xce\x80\xf0j\xf5X]\xac\xab\x1e\x8b\xd6H\xd1\xd4\xce_\x13\x1cgK(\xb9B\xed\x11\xa1\x9a;\xaa\xb8a\x8b\xfa}W\n\xb4\xc7\xd1d-\x15\x17AJ;\xf7\x9b\x0f\x8c\xda\xe2\x88.C\xa6\x19y\xa4\xabP\xd6\xd0\xb5k\xf7\xca\xd2\xa1\x1b\xf4\xc5\xd8;\xd6\xe8N\xad.8\x13\xaa\xa7\xed\xb3\x85c\xa4B\xcb#\xb2\xf4Z\x08\xa9\xed\xc6kt{\xa5q\xa9\n\x84E\xda\xba\xf0+\x98\x87\xce\x1d\xd8\xe8^\x94u[C\xac\xba\x8e\x82\xa8\xbdU\xf5(>\xaf\xdd\xa6_=\xd0\x9f\xba)`\xd4\xd9\x14\x90)\xb1\x97\xe0\x16A\xd3\xd9\xed\xb3\xe2 \x9c\x8d\xd8cw\xc1\x88\xf6y\xe8\xa7\xe9\x88\xfdV\x9c3\x1f\xf4!\x19_\xae\xb2 :eY,C\xcf0\x9f%<\xe5\xc9\x19\x9f\x01\xa6\x88\x9ez\xec\xeb_I\xbf\xf60\x16>n\xd8\xd1\xd1\xdd\x8c\x9dp\x06\x11\xf2A\xb4\x0b3\xdac\xef\xf9\xe5\x80}\x86M\x05\x19\xf3S\xe6G\xa5\xc1\xb4j\x11R\xb8?{,\xca\x9c\x07a\xc8\xd2L\xfc=\xe1\xcc\x9fNy\x9a\x06'a\xd1\xb8n.~\x97vRo{\x94\xd8\x0b\x80\xd6A\xea\xa5\x1e\x90~\xad3;L\xe3\xb9Cs\xa2\xd9\x01\x0b\xc7\xd1D\xca\xe9\xbb\xf7\x83\x95\xa7\xcb\xc0\xa1\xb6C\x10{\xe4\x1e\xebu\x9e_1\x95\x02\xb2\x97q\x9eh\xb6\xc2\xa0 \xcb\x16~\xc4\xe2h\xca\x07\xec\xdd\"H\x05\xe4\xe7a0\xcd\xd8\xd2\xbf\x14s3\xcb\xb9h\xc9\xc7Mm\xd0C\x07\xc8gq0s8\xc6\x95_\xc0\x8b\xc7\xa8\x80S\xb6\xa7Y\xff\xab?\xf2#\xb4\xc7\xe5\xfa\xd3\xde\xac\xbd\xc4\x07\xa42\xeb\xd04?\xcf\xe2\x93 \x9aU-\xee\xd7PA\xd3\x81u\x98f#\x98\xd6\x11+\x13\x88\x95\x8e3;b\x9d\x10U\xee\xdc\x11\xc8Te\xe1\xd0Ml\x05\x8f \x12\xc2\xdc\x9fr\x1bB\xc5g`\x87Q\x9a#\x86eXj\xc9\xb3ENDg\x9f\xe5Y\xfci\x10\xcd^\xfbAb\x89TY\x8dR\x19\xd5\x97\x99\x0f\xcbl:@\xee\x1f\xa6T\xbe\xbb\xa4\xbfw\xf5\xc0\x1c\xd7\x1bC\xbb\x8a\x1cC\"\xb6\xedJg\xf2^h4\xce;X\x8e\xad`\xd8\xc6\xf7\xda\xf5\x80sg\x85!w\xa6fm\x97M\xc7\xf9D\x0c:li\xa9\xc1\xef\xb3\xfe\x881\xcd(\x02\xd8\xd6S\xd6d7\x0d\xc6+\xe0\xac{\x05\xb7\xdc\x86H*\x06\x8a\x92w\xdb\xc1\xc0P\xbfmR\xf4\xe7L\xba\xcfN[\x03\x96\xeaO\xe0\x80\x13q;\x13\xb0\xac\x13@\x99\\_\x81_E\x85\x11\x81 \xd1l\x15\x87\xc1\xf4\x92\xfdJ\n(\xfd\x9e\xc3\xeb\xf9\x82G\xb8\x02O\x81\xdd,\x96\xa6\xa8\x02\xc4x\x89\xb3\xdf\xd0\x9d\x03\x96`\xe4\xd2\x85#^\x042\xb0\x11\xd5C\xf4\xe0\x8be\xcf\x8a\xb2\xdd\xa0/\xddA\xcb\xda\x1d8+(\x1ec\xd0\x93\\|\xc7+*7\xd6m\xe0\x15\xcc-\xbe\x13\xa1\x9fY\xf7\xfb\xea\xb1$p\xa4AY\x83\xaf~\"=\xf3Xo\xc9\x93S\xaeB\x1c\xbd\x8c?\xcbW\xa1\xd8\x90\xf9o\xf2\xcb\xd4qG\xec\xb9\x1f\x89m\x17\x8a\xb1(\x8e6\xb1\x99\x14\x08x\xe62\xe2\xc8\x82Q\xca*:=`\xf8Z\xbf\xf5.\x91\x06-\xf8\xb5\xec<\x96\xf4;\xc5\xed^p\xfa\xa9\xbf\xe4\x18\x06]l\xbd\x9dv\xd6\xc7\x02D+\xf0\xf0*\xf6\x044\x92SE\xa7~\x9eJk\xb2\xf3\xb8.\xb6u\\\xb1\xc5\xd5\x0e\xd3\x8e\xab8\x0e\xc9w\x8b\x15P\xe9\xa7\xd8\x1c\x17\"\xf5=\xbfL\x15\x0b,\x19S\xcb\x0dUeB\xd8 -\x16m\x96\x88:{i\xdd\xf70\xb04F\x83\x15\x10\xf1\xcaH\xb2\x96{\x8e\xe2\x81C\xad\xa5\x96]=\xaaL\xe2\xca{(I{\xe1\xd2\xd6#\xb2\xef\xde\xe0^\x98\xf0\xd5\xcc4\xa5\x9b\x13\xe3\x14\xc0\x0b\x1dV\xa4\xdbz<\xbb1\xe0\xad\x00\xb7\x02\xf5\x9a]]\xb6\x1e\x1524\x9e\xa3\x94\xc4\n\xec\xb5/\xd5[1C\xd1\xa9\x87P\x13\xb4\x82\x86)\x83\xd6\xe3\xe3 \x85J`\xe3\xb7\xb1E\x96&H\xaa\x89\xb4\x97\xed\x1d\xac\x88\xea\xaf\xddG\xda\xde\xa5S\x1fO\xac}\x94\xfe\xc1\xa5\x02\xa9\xb3p\x0b\xfa\x87\xf2\xf8d\xc0\xa3\x9f\xe5<\xe7o\xb4\xa6$\x86\xad}z-\x06\xdc\x11N\xca\x16g\xa3\x0e\xb0\xeb\xc3\xea\xd8\x1e\xd6\x97iF\xa2\xce\xb1\xaeT\xd7y{vB\x90\xb6\x12\xb2M\xe42\xab\xa9T\x93\x06sPV\xa2\x89yXP\x91\xd7\xee\xdc\xe9\xf0e\xf5T.\x11r\xb2]\xcf\"\xeag\xfd}\xb6\xdd\xd6>\xab\xc9,\xdb\x8f\x05L\x9e\x88\xb2q\xc4\xfal\xd8\x81O\x85\xe0\x0b\xfbH\x99\xe2\xeb\xfaA\xf8\x00\xe8\xab\"\xda\xad\xa4t\x9b[C\xe7&|\x0e\x0e\xc4\xbc\xca\xbaP6\xeaQi1\x9fq\x19\xcb\xc7>\x90\xc2\xcaWT\xa9\xb1\n\xec\x80Lv\xdcV\x81^\xe0\x10\xacY\x0evuUs2`\xa6\x7f\x85\xf8\xc4\x88-\xc5\xc9W\xa2\x7fq]]\xf0.\xe2\xd3=\xb1\xb9\xe8\xea)q\n@~_P\xc14\xd0\x14w=\xb7\x06\x91\x9c^\xad-'\xde\x04\x84\xe5\x15c\x97\x88\x9f\xb3cOO\xac\xf8\x10\xc1h\xc8Z&\x85\xe22\xa8_>\x90!O\x9d\x95n\x00\x9e\xb9\xae\xc7VN\xe6\xb1S\xf5\xc2\xd5\xcb%\xec\xb0u\xb5\x08\\EP\xc1\xe6\x0bMI\xbd\x98\xe3\x82\xacB\xef\x1c*\xda=\xd6\xc3\xc0\x07pnr\x06\x83\x81`\x98M\xd1\x16NO\xb0\\\xa15\n\xf3\xd9\xd7\xd8\xc0\xd7\x92\x93\x04f:u\xf5\xf1\xcb@%N-I\x86\x9bj\xe4w\x9a,\x93n`\xd0s\xd6\x12\xd3\x0c\x0co\xca\xe2\x91cs\xe6g\xa7zr\x00F\x0cg\xee\xca\xe0\x96\xc3\xfb;\x10\xdd\xf2v\xc7\xb3\xbdG\xdb\xe2)\x1b\x00\xb1\xd5\xc5.Ek\xfd\x12*5Z\x0b\xc1X\x1f\xeby\x96#$\x8f\xf2%O\xd0\x01\xfe\x86%\xd0\xe8)\xef*]Q[\xf3\x80\x96\xb5\x13b\x82\xc6\xbe\x07\xdf{\xbf\x83[\xe9\xb7D\x93\x8e\x9d'\x1b\xcf\xea\x08\xc4\xf6\xd9\xd0Bv\x18uz\xb8\xc1\xfao\xa3E\x80\xb7\x9e\x14A\xe3M\xa3*\xca\x927\x95\xe0&\xf5 >Iyr&\x86.\xce\xdcp\x0bXK\x1a\xc9\xa0\xbc\xe2P\xad\x12{\x10\xd1]+\xb4\x8fvr\x19:\xc7\xd6\n\x92;\xf0\xf7\x02\x91\x8a\x80\xc7\xf0\xcf\x00Bn\xa4\x98[\x8fYP\x11\xf0\x04\xb4\xcb\xa2\xb3\xc2)N@\xc8f\xb6<\x1a\xc4|\xecO\xf0\xe2\xa7xA\x07G\xb6\xbd\x8ai\"\x11\xbd\xc7u\xeb\xab-\x93\xd8\xa6\x16F\x8a\xe6\xbc6:\x08\xca\xaa +\x04\x04E\xc5F\x91\xe9\x99\xe6a\xabY\xf2\x85\x07C\xec\xbamm\xeaO\x06\x1e\xc7\x04;\xfb\xe2\xe5\x8bw\x8d\xc5?\xb4\\Q\xd5No\xb1\xcb\xb2E\x12\x9f\x83P\x05n\x119w\xdf\xf0Y>\xe5 \xeb\xdde}\x96\x81\x1b\x90\x9e\xc4`>c\xc5V\xc9fy\x82*[\x90 \x05\xdfH\xe3\x9b\x17sT\xaf\x81\xd8g\xe5\xa7)j\xe2DZ\"[\x0e\xd2\xb2\x19\x8f]\xc69\xca5\xf8\xc5*\x0c\xa6A\x16^\x16\x0bf\xc1U\xfb\xd8\xe0\x80\xbd\xab'\x81\xfe-\x8a\xc1B\xb0h\x15\xba!\x1a\x9e\xc5\xd1\xdd\x8c\x9d\xfbQ&:\x91\xf2\x8c\xf9\xd2\x01\x81X'\xa0\xbf\x93\xbd\xc2\x8eL\xfd\x08\x0c?\x80\xb9\x91\x86\x83,\x9ek-7\xb9\x96\x11\xd3\x1f -\x10\xad^\xdc{\xfd\xe6\xd5\xa7\x87\xc7_\xbd\xfc\xcd\x97\xaf~\xfc\xf2\xf8\xd9\xf3w/^\xbd<\xee\xb1>\xfb\xd2\xcf\x16\x83\xc4\x8ff\xf1\xd2q+\xa1\xcd\xb5\xe0\x9e{\xee ]\x85A\xe6\xf4z*\x80o\xe3\xe7k\x93\xdb\x15\xbd\x10\xb5\xe8\xed\x86\x01>\xdd\x00K@\xbb\xbfJ\xe2\x13\xf1\x1ed\x0b\xe63\x1c6|v\xc0>\x83 \x12\xcb5\x8b\xd9\xc2\x8ff!z\x99P\x98\xce\xfa\xec.\x8b\x13\x16g\x0b\x9e0\x1f\xd6 \x88\x18z\x08\xe1Ozh\xd6\xb5\xf2\xd1<\x8a_\x82\x8d\xd54\x06/\xa3 X\x96\x06g\x80:\x85yO\x81q\x1a\x9aM\xf3$\x01\xa3\x03\xc0)\x81\x1c~t\xc9\xf2\xe8}\x14\x9fG\xea\xbb\x1e\xcb\xa3\x90\xa7)\x0b\xb2\x1a\x12\x07\x11;_\x04\xd3\x05\xde \xa4>PAZ\x8f%\xfc\xd4Of\xd0X\x8c+\x06\xbf!\xc1\xd2\x0d\xcd\xd1\xa9\x86\xc0\xd9\x13D\xd9\xc1]\x8b&\x86\xd0\xfe95\xd3\xa0\xca\x01\xd3(\x0e\xc2\xf1\x06\xfa\xddEo)\x96\x87\xd83\x0b\x9d\xa4\xd2`\xc6\xb2\x12\x14\xc9\x80\x8f\xb2\xf8*/\xbd\xbc\x88\xceb4\xdcz\xed'>\x84u\xff\xb2\xf0\xb1\x9b\x15\xac\x84\xf4\xf4@\x124\xf0\x16$\xb6\xae]\x97\xd8\xbbD\xd6\x83]#+(\xb2\xf6\\\xf2X\xeb[\x95\xba\xd2v\xa4\xb2\xfey\xf3\xfa\xb7\x1e\xc0\xb5\x05_\x1bj\xa2\xe6\xd8[\x0bd\xb1^\x8d\x82\xff/1\xe9\x15\xbds\x04\xe5%\xa61P3L\xcdU\xf0}\xcf\x15E\x9c\xed\x8e\x9f\x82\x1a\x89\xa6\x0e\xb5\x1b\x81\xa4\xb9\xa5'\xbb\xb7Y\x9cp6\x8b9zc^\xf8g\x1c%\xf3\xc1L\xc9\x1c\x06\xecK\xff=g\xf2*//#\x8c\x94J\x85\xfa\xe6\x1b\xa4\xday\xf7|\x11\xa7\x1c\xa7&\x05\x99\xb0l7\x1d\x10\xc1k}I'\x0b\x14s\x0d\xed\x13\xba\x0d-\xb6\x84\x17\x19\xaaM\x07A\xaa^\xf5\xb8.\x85\xbbd\x1f$\xd8A\x8aB\x91\xe2\\\x9e\xd5\xa2\xa2\xa8\xc1e18&\x88*\x81\xdf^,\x979\xc4\x83/\xbeZ\xdec\x9a\xc7a\x18\x9f\x07\xd1\xa9rx\x10\x80S\xaa\xbb\xac\xcf\x02T\x1a\xdc\xedy\xacw\x17eL\x83\xbb\xe6\xd8\xe1\xc0%f\xef-\xff\x19(#\xf0\\\xe8\x0e\xe6A\x98\xf1\xa4\xe5\xa8 \xc7\xbba\xdc\xdf\xaa\x1da\xeaZ)Y/\xd7e\xc0\x07\xac\xa7]\x19\x04\x81\x04^\x94,J\x1d\xb0\x9e\xf2\xeb\xd0c\xa3\xe2G\xc0S\x14\x97\xe1\xc0ss\xe0l\x1e\xe7\x118\xa5\xbe\xab&E\x03\x7f\x16\xb3y\x10\x15a\x83\x04\\Q\xf0\xaf\xe4_\x853 \xbcC.\xc5\x1a\x0dp\xd6\xef>\x96\x9dD\xff\x13'\\J\xeaf\x83\xbbuw\xca\xb7\xbf\x1b\xde\x1aE\xf3\xd6\"\x0euo\x9c]tH\xa4d\x13UH\xa0\x1a\x12X\xaed\xa7\x97+)\x0bEQ\xe7\xad\xc8?\xeb\x02(M\xb6y+\x13\xa4W\xacB\xab\xa0\xd0b\xd7\xae\x07\x00/\xe7\xa9:#]>\x199\x8fP\xc4\xfd\xe8\xa1[\xedy\xe4<\xd8\xdb\xead\xe0Y\x1e\xa1\x87\x86\xafC\xe9l\xf0\x91\xeb\xf4\x8a\xd8\xe0\xa4\xad\xf3\xde\x96\xc5\x8a;r\x86\x0f\\\x8d\x8a\xaeq*\xb0\x1d\x084ER6\x8e\xd1c\xad\x16\xbb\x1c\xee\x14@4\x81:\xcdJ\x1c]~\xd7 \xc0\xcdV\x86\xf7~\xe2\xfc\xca\xf6\xd6\xd5Q\xea~\xe2\xfc\xd4?\xf3\xd3i\x12\xac\xb2\xab\x99\x9f\xf9\xee\xbd`i\xc2\xf2\xde\xf8'G\x17\xdb[\x9bG\x17{\x87\x93{\xa7\xf5\"\x01\xb69\xfe\xc9h\xd2wG\xf7N\x97\xe6qk\xdc\x1b\x08Bt\xaf7\xa1\xe1]\x05h\xeaGA\x16|\xc3\xbfJ\xc26a\xd5\x99\xb4\xb5\xf1\xe4\x8e!\xaf\x95\x89cA\x8fRKw\x12\x10j\x05\xfd\x010\xec\xaf\xe6\x0e\x1foM\\\xf6\x94m\x12\xee\x97\x9d\xdc\x95&\xe7N\x04\x12\xc0\xa5\x9fM\x17N\xe0\x8ad4\xd9\x11\x873\x96\x0c2\x9ef\xe8\xb6\xa4\xe7\x9f\xc4y6: \xfd\xe8\xbd\xd86r\xb8\x1d\xae'V\xbe\xb3\xa6\x15e\xb9<\x1e\xd8\xec\xff\x1f\x0e]#\xdci\xc3f\n.\xa2\x07Y\xfcE|\xce\x93\xe7~\xca\x1dpG\x02\xfa\xa3\x03&\x90\x94\x8d\x0c\x1f\x1f\x96\xe5\x15\xaf7\x84]\xca\x9e>r\xb6\x1f\xda\x96\xaf}z\x95\xb0\xdbI\x1c\xeeVG\xb3\xe6\x1a+\xbb\xb7W\x17]|/\xa6\xe4`H\xdelF\xde\x0d$g\xff\xbf1y1\xc7\xf5 \x8e\xba\xd9\x8cw\x03t!d\xb9\x96\xe5\xb8\xbe\xa2)\x84\x13\xeb\xc1r\xa3g\x8f\xf2\xaf\x0b\xcb\xea\x9aCh\x96\xf5\x80\xc5\x03\x19\x94@\x814F\x12\x18 \xd1\x90\xe2y\xa34\x93\xa8\x0e\x96\x91hd\x91\x0d\xa6\x0b?y\x969[\x16%L*\xcb'N\xe4\xb1\xa1\xb2P\x82\x08!\xd9 \x0d\x83)w\x1a\"\xb0\xe4c>\x01\xc5wU\xd8\x7fm\xda\xbb\xfd\xb0\x1d\xc4\xf6cl\x0c;\x9a\x14\xdf\x93\x98T,2\xe9\x02\xea\x80\xc5\x82w\xf7\xd8\x06\x98\x01D\xec\xe9>\x8b\x95Ux\xf1\xa9\xeb\x8e\xe6\xc1^\x9d l\xc1\xbb\x9b\xd0g\x8e\x08\x02\x97\xb4\x92\xf6\xc5b\xe3h[\xbf\xc4Ks\xb65>\xa1\x10\xb97>:\xcag\x0f\xb7\xb66\xc5\xff\xf9|^\xbf\xf4\x96\xa8B[;Xhkgw~t\x94\xcf\xf96\xfc\x9c\xf3m\xf1s{k\x06?\xb7\xb7\xcc&\xe0\xc6\x00|fg:\xc6\xcf\x9c\xd8>\x07\x86~\xe3\x9f\xb4t\n.\xf49\x07#\xbd\xd1\x19\xdf\x85\xe2\xb3\xf9|\xe2\xfe|\xfb\x03y\xc5Oo\xf7d>\x9f@\xc2\xd4\xfe\xa1T~\xa8\x08\xe1sU\x84\x01r\xc5[\xef\xa0V!T\x9f\x99\xf3-\x8e\xff\xe6\x93\x03\x15\xe1\xc9\x91\x9d\xde\xde\xda\x9a\xc9V\xc7\x18\x93)\x9f\xc8\x95~\x85A\xe2\\k\x1b=\xf7\x93\xfaY`\xaa\xf5r\x1c\xa8\xae\x1e\xf4\xf0\x1a<(\x08\xa3z\xfb\xb5~\xcf\xd9\xbe\x0c\x8c\xe0\xc0\xe8\x9c\x83\xfdr\xa40\xe8)F\x8a\xec\x9d\xf6\xae\xbb&\xb8\xe4*\xe7p_t<\xb9\xee2\xde~hc\x08m\xcb\x98\xf2%/G\xdb\x1b\xdf\xfdo\xbf\xf3\xbb\x93\xde\x8dF\xd6\xbc\x9d\xa8\xdd\xdd \x1c\xb1o\x14,\xbe\x0f,\xbe\x0b\xce\x1ez\xbd\x1b\xdd9\xd2h\x9c\x058\x06\x0b\n\x87\x9e\xf1\xd1\xc5T\x1c\x8bf\xbbG\x17\xb3\x87\x9bG\x17\xf3\xdd\xa3\x8b9\xbc\xcc\x8f\xf2\xad\xa1X\x19\xf9\xd6po>\xb9w\xda\x00\xc2u\xc9\xc3M`\xed\x80\xd0\x1a\xa4\x82 \xa9U\xd0\x0c<\x96\xd4a{} \xdew\x9d\xea\xd7{\x7f\xf8;\xbd\x11\xeb=\xab\xad\x9b\xde\x1f\xfe1:\xf9\x8f\xd3\xc9\x7f\x82N\xfe\x1f\xe8\xe4?I'\xffC\x91\xec\x1b\xc9\xff\x88N\xfe\xc7t\xf2?\xa1\x93\xff)\x9d\xfc\xcf\xe8\xe4?-\x92\x9f\x1b\xc9\xff\\$O\x8d\xe4\xbf\"\x92\xeb\xde\xf1{\x7f\xf8\xefD\xf2\xccH\xfe3\"\xb9\xee;\xbe\xf7\x87\x7f\x96N\xfest\xf2\x9f\xa7\x93\xffg\x91\xcc\x8d\xe4\xff\x85N\xfe\x17t\xf2\xbf\xa4\x93\xff\x82H~a$\xffE:\xf9/\xd1\xc9\x7f\x99N\xfeW\"90\x92\xff5\x9d\xfco\xe8\xe4\x7fK'\xffU\x91\xfc\xd2H\xfe\xf7\"92\x92\xffG\x91\xfc\xcaH\xfe\x9f\xe8\xe4\xbfF'\xffu:\xf9o\xd0\xc9\x7f\x8bN\xfe\x0f\"96\x92\xff#\x9d\xfc\xbf\xd2\xc9\xff\x1b\x9d\xfc\xbf\xd3\xc9\xff\x89N\xfe]\x91\xfc\x95\x91\xfc\xb7\xe9\xe4\xbfC'\xff]:\xf9\xff\x14\xc9\xb9\x91\xfc\x7f\xd1\xc9\xff\x99N\xfe/t\xf2\xdf\x13\xc9\xf5\xd8\x01\xbd?\xfc}\x91|i$\xff\x01\x9d\xfc\xa7D\xf23s9\xfc\x9eH\xf7\xcd\xf4\xbf/\xd2\xdf-\x8c\xf4\xff*\xd233\xfd\x1f\x88\xf44\xad\xa7\x7fK\x93\xe5oi\xfa\xfb-Mh\xbf\x05\"n\x90\xb7o\xff\x04\x9d\xfc'\xe9d\x80\x80A\x0c\xbf\xfd3t\xf2\x9f\xa3\x93\xff\x02\x9d\x0c\x84\xd6\xa0\xa8\xdf\xfeY:\xf9\xcf\xd3\xc9\x7f\x91N\x06\x12d\x90\xe5oij\xfd-P&\x83Z\x7f\xfbW\xe9d \x13\x06\xfd\xfd\xf6\xaf\xd1\xc9\x7f\x83N\xfe[t\xf2\xdf\xa6\x93\x81\x04\x19\xf8\xf6\xed_\xa7\x93\xff&\x9d\xfc\xbbt\xf2\xdf\xa1\x93a\xcd\xfe\x9a\x91\xfc\xf7\xe9\xe4\x7fH'\xffc:\x19\x16\xe7\xa9\x91\xfc\x0f\xe8\xe4\x7fD'\xff\x13:\x196\xfb_7\x92\x7f\x8fN\x06\x1e\xc0X\x98\xdf\xfes:\x19\xb6Xc\x07\xfb\xf6_\xd0\xc9\xff\x8aN\xfe7t\xf2\xbf\xa3\x93a\xfb66\xb6o\xff%\x9dLo\x9a\xdf\xd2\xbb\xe3\xb7\xff\x9eN\x86\xed\xe47\x8cd\xd8N~j$\xc3v\xf2\x9bF\xf2\xff!\x92\xdf\x1b\xc9\xff\x89N\x86\x9d\xe0\x0b#\xf9?\xd3\xc9\xbfO'\xff\x01\x99\xfc\xdd\x1f\xa3K\xc3.\x13\x1a\xc9\xff\x85N\xfe\xafd\xf2w\xbfC'\xffq:\x19H\xaf\xc1\x8d|\xf7'\xe9\xe4?M'\xff9:\x196\x01\x83\xa5\xf9\xeeO\xd1\xc9\x7f\x86N\xfe\xf3t2\xd0o\x83I\xf9\xee/\xd1\xc9\x7f\x85N\x06Bm\xf0\x17\xdf\xfde:\xf9\xaf\xd2\xc9@c\xdf\x18\xc9\x7f\x83N\xfe[t2P\xcd\xc4H\xfe\x9bt\xf2\xef\xd2\xc9@\xa8\xdf\x1a\xc9\x7f\x97N\xfe\xfbt\xf2?\xa4\x93\x81\"\x1b\\\xc1w\x7f\x8fN\xfe\x07t\xf2?\xa2\x93\x81\"\xbf3\x92\xff)\x9d\xfc{t2\x90\xde\xccH\xfegt\xf2?\xa7\x93\x81\x98\x1aL\xe1w\xff\x82N\xfeWt\xf2\xbf\xa1\x93\xff\x1d\x9d\xfc\x1f\xe8d\xa0\xb1\x06\x0b\xf9\xdd\xbf\xa4\x93\xff5\x9d\xfco\xe9\xe4\x7fO'\xffG:\x19H\xef\x8f\x8dd \xbd\xe7F2\x90^\x83\xc7\xfd\x0eH\xaf\xc1\xcc~\xf7\x9f\xe8\xd2@z\x7f\xdbH\xfe\xcft\xf2\xef\xd3\xc9@L\xbf1\x92\xff\x0b\x9d\xfc_\xc9\xe4oav^\x98\x1b\x0f\xc0*0v\x9e\xef\xf0\xb8fp.\xdf\x01\xb3\x14\x9b\xe9\xc0X\xde5\xc9\x1b\xec\x1bi\xa9\xd9\xb5)Hi\x8f>\xd7\x16rw\x12\xb0\x11\xce\xd4F`\xa3[\xa9p\x03\xc9Z=\xf6\xa3\x12;R\x96\xdf\x84\xc4M\x9am?l\xf7\xbcG\xabT\n\x0b\xc5}\xd0+x\xba\xea\x04u\xf4\xfa\xc0AA%\xd5\x10~\xa9\x86\x80\x00T(\x87\xcd\xba\xc9a)\xb5\x01\x18Tlmm\x1e]l\xcf\x8f.v\xfc\xcd\xa3\x8b\xfb[G\x17\x0fN6\x8f.v\xb7\x8e.\xf6\xc4\xcb\xde|\xd2\xbfw]%\xa3\xeadt\x93N\xfa\x9b\xdfL\xc6\xcf6\x7f{r\x05\x7f\x7f\xbe\xed}\x80\xb4\xab\xf1\xd6\xe6\xa3\x89x\xc5L\xf9\x02\xa9W\xe3\x9f\xe0\xcf\xad\xcdGlr\xef\x9a\xdd\x8f\xd0Pb-\xb5O\xa1\x939:\xba\xf0\xa7GG\x17'\xc3\xa3\xa3\x8b\xd9\xde\xd1\xd1\xc5\\\xfc\x01\x01\xab\x008B\x1c@\x8e0\x07\xa0#\xd4\x8f.NP\xe0\xba%\x05\xae\xbbsvt\x94\x89\xea'GG\xa2\xae\xbf\x05r\xd9\xf9\xfc\xe8(::J\xa0\xd0\xf6C\xfc\xf7\xe8\xe8(\x1f\xee>\x14%\x86\x0fA\xf9 \x1a\xc2\x7fC\xfc\xb7\x8d\xffv\xf0\xdf}\xfc\xf7\x00\xff\xed\xe2\xbf=\xfc\x87mn=\xc2\x7f>~\x01;\xf7@\xfc\xdb\xd9\xda\xda\xaa\x11\x18\xd46\xf5X\x9fE\xac\xcfz\x16M\xd2\xac\xdf3\x17\x1cH\xa1\xb7\xf7\xe4\xb0\xf7Nh\xa5\x91\x98j\x01\xd4\xb9\x80\xd4|\xf7\x08\xa5\xddG\x17\xa6\xea''5Q\xaak\xa0\x18\xa9}\xd0\xda\xf4\xb3\xcd\xdf>BA;H\xdaQ\xd4~t1\xe36u\xd3\x1az\xad\xf0Zz-\xd0\x18\x8d;\xf7k\xae)\x98\xfcB\x0d\x96S\x8a\xa4\x95Vt\xda\\t&\x8b\xae\xa9>\xb8\xb2\xa9\x12\xdd\xba2naU\xc6\xcd,\xca8R\xf5\xc8R\x8f\x85\x9d\xf4s3Z?wV\xd1\xcf\xd1\xed\x89\xbc\xda}\xcbe\xa9b\x19OQ\xa3\xa7\xe0\xdf\x17`\x03\xc5\x95s0\x9a]\x85\xe1\xd5\xf2*\xe1W\xe9Uvu\xc6]\xf7@\xaa\xef\xc6\x89\xc7\xa6\x1e\xeb\xfd\xb0g\xaa\xff\xd8\xcah\xe8\xb3\xab/\xbe\xb8\xfa\xf2\xea\xcd\xe1\xd5\xdb\xabwW?:\xac5\xc4\xfalnk\xac\xec\xdf\xbcK\xffT\x8d\xb6\xcf\xf79\xc0\x1d\xeb\x87\xd7\xa6\xec\x1b\xce\x06\xd8t \xea\xa6l\x10\xc0\x14\x97\x1d\xb0\x15\x18A#\xe3\xef\x17\x0eG\xd9Z\xa8S\xdc\xb5~d\xbdk}o\xfc\x93\xc1\xa4\xff\xc3{\x03~\xc1\xa7N,z\x10\xc35\xb1\xf2m\xf0\xe2\xf0\xf8\xf5\x9bW\xef^\x81\x91~\x0f\xac\xb8{\xe8\xc8\xd1I\x93\xa9{<\x1c\xa0E\xd3\x88\xf5z\xd7\x85\xc4F >\x18@`\xd6k\x8c\x14\x91~\xcf\x1d\xf7\x8e\x8f\xa7q\xc27\x7f\x9a\x1e\xa7\x0b?\xe1\xb3\xe3c\x9b\x95\xfdu\xa5\nv\xdf6\xed2\x83\xf6s[7\xb0\xa9\xad\x01\x88\xcb\xc2\x87\xcd\xe3\xce\x1de\xde[!JcN{\x05)\xe9\xd2\xe6>\xcb\xd8\x01\x1b\xb2\x11l\xda\xd7\x05\xbf\xa0\x9e\xc4 \xeb\xf88\x8cg~\xba8\x16{\xfdqqg\xe8\xf8\x988v\xb5\xb8OX\x17\xb9*PR\xf0\xa8\x02#\x983\xc7pZ\xcc\xb4\xf3sf\xc0\x8fULN\xf7\xd1\xa6\xb4\x98\xee\xa6@J\xb2VPx\x15\x86\x95.\xbeP\xd8\xfd\xde.\xf0\xbf\x7fx\x16\xc6\xe7\x07\xd5+>0\xc4X\x1b\xf8\xed\x0e\xb4\x01\xcb\xda\x06\xd9\xe4=\xacu\x9c\xe5\"\xeaW\x17#rdC\x8fEb\xe8\xfbh\x8d\xaf\x89\xd82i\x9d\x9c!\x83pS\x02\xd1\xc6\x96\x8c'\xb7\xc4\x88\x0cw(\xf6\x18\x83\xd7h\xcc\xd8*\x0c\xa6\xbc\x0d\xf2\x9d\xd0\x8bf}\x13D\"rN6\x9c\x88=A\xc7\x11N\x04\x9e\xa0\xd4\xd5\xd4M6\x14\xebm\xb0\x8a\xd1WD\x89\x8f`\x1e\xef\xb1\xcd\xcd\x02H\x1e\xdb\xba\xd6\x9e[@\xe9\x174z\x1c\xbb.\xba\x1dG\x93\xf1\xb0m\x0b\xba\xd5\xa1\x146\xaa\xd5\xb1\x08rW\xb91\xf6\x11\xba\xd2u5\x9b\x80\x8d\x01\xb0\x91\x15\xb0\xb1\x04\xac\xd3\xefkH\x12a\xec\xd0\xb1\xf8\xf0\xc4\x85\x08P\xe3X\xc0[F9j_\xdb\x0d\xc3\xddn\x1d\xae\x0d\x89\x12\x15\xf9\xcd\x95G+\xdb-\xa1\xebr\x01\xad\x14\xc9\x8e\xdf\xd2S\x1d\xd9\x9d\x1e\x9e\xe8\xd1\x81\x1b\xf0\x9bQ\xbe<\xe1\x89\x96\x90\x02\xe7\xa9%\x9c\xc4q\xc8}\xe9\xf4M\xf0\xa6\xc7\xc7@\x89\x8e\x8f{2\x10\xc0Hs\xce\xf7}\xceFe\x1d\xc0d\x9c\xf2\x0eb\xfc\x8f\xdc\x07\xdc\xa1>f\x1f\x1a\x16a\xd9\x0fz\x05F\x80\x8c4e\x03\xc1\x034\xeeU7\xdeHnk\xc8\x8a\xc9\x8d\xf7fK\x8f\xb6{7\xae\x8eI\xe5\xdc\xfdV\x90X\xa6\xa5(\x80{\x10\xe9u\xef\xac\xe2w\x9d\xbcI\x06\x8e/b's\xa9\xfa\xaa\x8dT\x11\xb8\x1d\xa2\x05&o\xaa\x05\xe0{(j\xec\xbb\xfe\xc8q\xa4N>\xe6\x13\xb8|\x90wu3k\xa6\x9cI\x8f\xbc\xbc\x00\x87\x95\xf3\x0ea'a\x07,\x1f\xa7\xc0C\x87\x82\xc1\x0c F\x9a\xb1\x1bH\x03w\x87\xf5[ \xf2\x02\x84!`AL\xd8~\xd4*A\xb2\x12\xc6\xd8F\xa3\x87\x15&\xe6\xce\x1d\x96\x8d\xb7&\xe3\xed \xde\x19\x14\xef[\x82\xbd\x13/\xc3\x89\xd8\x82\x8ao5\xdd`\x8e\xa4\x13Q\x88\xb6\x16QAB\xaf\x0d\xb5\xa1qwF]\x8d\xa3\xa064%U\xdbm0\xc4\xaf\x0bd#\x80\x99\x02\x1d\x91n4\x8d\xe1\x0b\x04K\xcd\xe4)\xdbg\x1b\xb9y8,\xce\xf4\x85\xdf\x98\x8dZ\xfc\n\x10\xb0\xf2\x8a\xc7\x03\x96nnZ\xa5\xabs\xd1\xbdqjq}=\x85`\xa18\xbbs\xc1G\xc0\x166\x9e\x8f\xb7&\x02\xb97\x1c\xf1\x06b\x92\xd2\x93\xcdFS\xac\x0f\xe8\xdec\xd6\xef\xa7\xec \x0b\xad\xbdZ\xb1}\xe6\xa8\xae\xb9V\xe7i3\x10\x0d\xaf,\xb9\x0b1IV\xaf\xde\xc5\xd0l\x04\xa5\xe6\x90\x04B\xdco8\xab\xe6\xd1\x8aG\xc6}\xb7\xd3\xbe3\x86Q)\x1bBQ\xe7.\x94\\\xb2}\x96;3\x8f-<\xb6\xc2U\xe1\xb13\x0b\xc5\x04\xba\xabwy f\x12\x0b\x8f\xcd<\x16\xb0+y_\xeeL,\xcae\xf3\x08\x1afP\xd5\xba\xc1\xa1\xad\xf5\xeai}J\xea\x07HT\xd1\xacu\x86\xbc\x01\x8b\xd8~\x04\xca:\xf3\xb5\xa2\xac\xe4\xd5o\xbd\xc3\xfa\xc7T\x7f\xbb\xf1x\xb7\xf4\xad\x9b\xf2r\x16\x8d\xe0C\xea~\x9fH\xaf\x97\x07b\xbd\xd5\xead\xa1\xeb\xa9\x8c \xbfLy\xd9\x8a\xe7ft1\xa6\xb1G\x91\xa5\x15V\xf0Gb\xab+\xdcT=a>\xdbd\xc3bM\xe6\x95\x83\\\x15\xd3\xfb\xfdH\xa2\x90H5\x9b7\xc6!\x17L\xe0\xe4\x1d\\M[\xf8Z\xc5\xd6\xde\x90\x93\xb5n\xc5u1\x9ade\xb7\xa9x\xa7\"\x9d\xd2\x1c \x14\xaa\xab?Sl\xbf\xaeq\x08ew\xea\xcdL%\xdfTO\x9f\x9b\x9c\xc1J\x0f\xac\xfaLy\xf0\xac\x9b\x97\xcc\xaa\xa5\x12\xff\xb2^b\xa1\x97\xc0M\xbb^\xe4\xec\xe6\xc2S\xc5\xa2,=v\xea\xb1K\n\xffO\x04+\xe2PG\xa1c\xc8\xc9\x88\x9cs\xb6\xcfN\xd8\x01\x9b\xb1\x11\xcb\xc9\xba\x87l\x9f\x1d\x17%\xa86.\xc4^/\x1a:\x17\x9c\xcd\x8a\x1d\xb0\x05\x1b\xb1sW\xfc\"8\xa6\xb7\xa2\xb8h\xf5P/~h+\xfe\\5|h.\xe7\xe7bK\x0fA\xd7e\xaedX\xa5!\x9cb\x8a\x8d\xd2\\l'\xe0+\xc5\x83A42>\xc5\xf76.\x8a\x06/A*x\xa964\xd7c'\"e\x8a\"\xdb\x98\x98\xb5\x11\x0bd\xeay%\xc3\x1c\xdb\x86\x13\xb1;lN\x0eM\xcc\xf6{\xb6\xcf.@\x0c\\\xb8\x96\xe9\x1d\x1f\x9f'\xfej\x05\x82jb\xa2\xc4\xf3\x8c\xed\xb3\xb7Z\xb5\xac^\x8d&w\xef\xc5\xb8\x9e5\x9d\x07_\xb1}\xf6\x9e\x1d0>\x00Wr \x11mp\x9a\xfe\x9a\xed\xb3g >-\x8bg4[d\x05\xf6\xa9\xf3\xcac\xaf\x15\x1c/\xdb|^\xd3l\xd0\x06L\xaac\xb6\xee\x9b\xd3w\xfd\xad\xd1\xd8\xea\xe4\xc1o\x9b6\x96\xd9\xdd\x1ev\xf5\xe3zv\xcbf\x1du.M\xb7\xef\x80\x02\xfel\xe6\x80w\xe1\x1a0\xc4\xe3k\xf4\xcd\x9f\xcd\xc0\xabP\x99\"\xb6D4\xca\xf0\x0d\xfb\x8b\xa0jj\xe1\x93\xf0\xad\x037\xba\x99\xae\xa6\x13O$w\xd3\xc8\xed\xb4s~\x9f\x8cX\xfb\xb7\xec\xbae\x00\xbb\x93\xb5}\xc2\x8a\xd06/I\x86\xb9\x93d\xf5\xb6(7\x17\x14\xdf\x90K\xfc\xafo\xf8\xa9L\xaf\xb7\x13\x9a\x1b\xbb\xe0\x01\xb6\xcd\xed\xbf\xd8\xa3?E o}\x93\xae\xf0\x03\x9f\xf9\x99aiZa\x05\xc0\xa3e#+\xf0\xa5\xbf\xa2\xf8\x00-\xd8\xfb\xf2\x84\x1bM,\xf5\"h\x97R/r\xaa\x17y\xcb\x0dn\xe3\xb2\x92\x0f\x12\xf0z\x91\x93J\x11\x10\x81\xd7\x8b\x1c\x1b\x8c\xcf\xa7\xf9|nv\xf8\xbc\x066\xffG\x01?\xaf\x17:,\x9c\xaa\x15\xeb\xde\xe2\x9b\xea\x02\x18\x83\x03v\x88\xfb\xc2\xabyg\xd7k\x8aX'\x1e;\xf4\xd8[\x8f=\xaf\xe3~z\x1e\x80\x0f4R\x8e\x05q\xdc\xceGF:\x93; \x1f\x9c\\f\xfc\x0bd\xf77\xc41P\xfb}u\xc50\xff\xd5|\x9e\xf2\xac\xcc\xc7\xdf\x8d\x1c\x88x8x\xa3:\x01\x00{\xd2\x1b \xfe2\xcbCG\x8f\xe9\x8e\x16:\xcb\xb6\xden\xbcu\x04u\x8f1\x18\x0c\xbce\xaeKl\xfe\xf0\xb5\xb9\xf95H_Y\xd2\xcf\x1a{\x178}\xee\xb1>%y\x86\xda\xb3\xc6\xda|\x10\x81Oq1&x\x03O+K\xe53\x1c\xc2\x9d\xe0\x0fK\xf3KK\xa7/\x9b?\x8b\xfa\xa0~\xc5(\xa9R\x7fA\xd7W\xbcZn\xa9vj\xaf\xf6\x0c5\xfd,\xb4\x8b\x8b\x80/sD\xfb)x{\x85\xb3\xde\x86\x12R\x00\xbb\xfa\xac\x15\xfb\x14\xfb\xf6\\\n\x1b\xec\x9f{U\xb4\xf5\n\xe0aa\xd8\xd8\xd5>\x9bz\xecyy\x14\xb5\x7f\xf858\xb4{\x0f\x88\xf8\x1eC\x15\x94\x0b\xb8\x91!|^\nm<\xf6\xda\x02\xde\x13\xfb\x8a.\xf9\xf8\x0b\xe55P\x0cJ\xfe\xb0J\xaf\x99\xb6\xce\xda\x94\xcf\xed[\xf4\xba\xec\x9c\x0c\xe1\x04\xd3K\xcb\xaa\xb8\x195\x82\n\xa5\x0e\x0d\x8e\xfb\xfdl\xc2\xf6\xc1\x86\x9e\xd7\xee\xa2\xb9\x1fC\xc4\xf5q\x86\xd786\xbe\xf6\xb0\xecv\xb3\x8f(\xf1\xc7\xd0\xe4xn\xe9\xb0\x8f\xf2\xde\x94\x02\"\x08@\xd8\x1d\x16\x9bp\x9c\x82f\x8e:\xcb\x0b6hJ\xf2\xffb=\xcc\x05\xe1H\x9c\xcc\xd5tC\x1b\xa1\x95z\x14\xd1\x8a\x04\xe34\x7f\xccV\x0dJ\n\xc1:M\xc7+\x8b$\x7f\xc3 A\xc0\x00^\x9aG\x9aA\xdb\xcc\xed\xa8\x95\x10\xdfX\x80\x190E\xc1\xc47`4\xa9\x0c\x87R4\xba \xa8\x98\x12\xf0o\xd4\xbc\xab\xa6\xba`-U\xf1P\xea\xdf*\xa0\"\x18\xb9P\x1c\x9eV\xec \x9b[!s\n\x1a\x10\x05\x1f\x8b\"\xe4\x12,\x07g\x16\xf0\xf9n!\xfe \xe1B\xe5%\x1cWg\x80E\x1c\xf0g\xc4|G\x9c`!\x15\xd1+\xb5)~u\x05\xc4 ;\x10=\xdc\xdf\xc7\xd3w.\x1bA\xd4\x84vO\xecJb\x90\xa8\xd0\x14\xfc$\xe1\xfe{#\xc7T\xe1.a{\x03\x9exZ\x1a\x92\x83m\xc6\xac\x89>\x83\xea\x07\xf0wi\x03\xfc1\xb0\\Z\xab4\xe8\xcf\x81\x17\xd3\x8a\x99\x03:\x16\xeb\xe6\\|\xad\xda\xc9@F\xec0R3\xd4D\x91\x01\x06\x8fE\xde\xb1.\xa6\x86\x14\xb2,|\xf3\\/{\x8eF\xdf\x08\xfa\x0e\x1bX\xaao\xa1\xc5\x0f\x81\xe0g?\xa8V\\\x9f\xf4\x13\x87\xcfJ|\xc7\xcd!F\x83\xb5 (\xd0\xdc|\x0b\x03>\x8e'b)E\xec K\xacK\xc9\x87\xa5T\x8fZ(\x9e\xcc\xf1\x01i\xd1\xac\xd9 \xc6q\xbf\x0f\xb1\x0e;\x80(\xf8\xde\x00\xa1\xa23\xaa\x91\xf2\xc7.K0(cf\x04'\x91\xbdKZzg7E\xa0\x05\xf9\xf7\xa9\xfb\xe2\x94\x94\xbcm\x0b\xb3\xc8\x1dbiZ\x9eHf\xeb\xc6\xd0\xb5|\xa7\x953[\x170C\xcbMz\x03`>\x84)-\xc1\xe3\x8f\x0b\xf0}\x1e\xc6~\xb6\xb3-\xb5\x08\x80\x80\xb5\xcc\xdd\xfbt\xe6\x8b({h\xcd\x19\xeeZ\xb3l\x1f\xfb*\xb06\x08Y\xcfC\x7f\xb9\xe23{ \xdb7E^\xe5\xa3\x1b[\x9e\x9e\xafaP\xad&\xdd^E\xf0P\xcb+\xe48\xb5\xf4R\x08afp#Q\nr\xea\xb3!q\xc5\xc8\x00\xa9N-MIrj\xc9J\x17TKVB\x9dZ2\x08r\xeaiRxSK\xfe1\xf7\xdf\x17\xfd\xd8\x18z\xeb-\xc1@.\xc1\xd8\xe1E\x94&\xb1\x1fm\xf8c\xb1*o`\xdaK\xfb\xa0\xd85\xac\xdfn\x81C\xae\x8f\x0dc5\xe9\xf1\x98L\xfb'u\xf6\x18O,,[$6\xe7\xc2\xec\xc6\xd5\x9c\xf6G\xae\xb9\x91o\x00\x03~\x87e\xa8\xea\xb5\x10\xe86\xcb\xd7\x86\xb3\xc6\x9e\xebh\x81\xb6<\xd93\x8b\xe9\x05}\xfd\xc8N\xe5v\\\x07\xae8y\xac\xa7\xd6\x8b\xed\xe2\xd9\x0d\x9a~\x9d\xc4\xcb \xe5\x1f\xa1\xe5\xb7<\xfb\x08\xad\xca\x95uK-o\x1b\x97v\xe5\x8aX\xdf\xc0\xb3\x12\x856.B8gE\x00\xda\xa8\xe1\xf4\x15\xc0\xf1!\xb2\x1c.\x90m\n(\xb6 \x99\x0f\xe9\x06\x96\x95\xd2E0\xcf\x9c\x06D\xd5.\xfe\x03k\xd1\xb64E\xf9\xc0\x89\x8b\xbd\xcb\xde\xb2x\x00\xf8q\xc3\xa2\xa2)-\x99\x8aS\xe1$\xec\xa9\xf4%\xa6\xf6\xbc\x91\xd8\xc0Y\x9f9\xd2\xc8\xfd\x80\xf5\x9e\xdc\x13TM\xfe\xee\xb3\xde\xd3\x9e^Jn\xa0\x82\xa1\x8aD\xe9\xa3Hf\x83\xa6\x10\xe4\xa0\xd4\xc2\xb3\xcfb`\xdf\xc2\xd4)kC\xc7\x138J\x96\xbf\x07\xfej\xc5#\xf0\xef\xe0\xe9\xf84\xc0\xc4\xb8\x92\xa8\xcc\x18\x9c\x0dq\x06\xdd\xd8\xeaB\"\xe0N\x06br\x01\xb5*\xbc4pi\x80*W\xbf2s=`=\x86e\xb5\x072\x0e\xd6\xabN/\x8a3\xe6\xa7ip\x1a\xf1\x19\xcbb\xe6\xb3\x95\x9f\xf0(\xdb\xa0\xf8\x07\xf5\x9ci\xfe\x91\xe8^\xaa\xa7\xf4H\xa3 f\xec\x0d\xe7\x8e\xd6[IT#\xaf\xd2\x02\x8a\x80\xfa\x82\xc1P\x94\xd6\xf5\x9agE\x7f\x14{\xe9P\xbc\xa2zlT\xca\xc2f\x08\x9a\xd7uJ\xb4\x0d\x17\x0d<\xc4\xd0\xe0\x84\xcb\x95\xd7\x1d\xc1\xe7\xaa\x1c\xd1\xd3\xce$\xd3*\xfa\xac]d+~}pK\xc7\xc3\xce\x83\x07\xf2\x80\xdd$\xe8W\xdbyu\x80\xbd;\xbd\x11\xeb\xdd\xf1\x97\xab\xc75\xa2x\xb7wW\xe4\xfc,\x8f\xb3zV\xef.VZ\xc5\xa9\x91\xf5\x04\xb2B\xb3\xceS\xc88\xcd\x1ek\xc1\xfa\xda\x04\xe3\x16\xa9\xb8$^\x92\xb2\x01\xf1*\xc4=\xce\xf8N\xef\xc9\xd3\xbb\x18c\xa1U\xd8\xa6\x04\xccFP>\xe0\xd9\xca\x8e\x92\xd0\xad\x91G}\x08\xf1\xe3\n\xdc\xa5\x19\xc1\xa3\x1dwpx\xc6\xa3\xecp\x19d\x19O(o\x1f\xe6A:\x913\xbd\x08\x0cu\xb5x\"\xe7\xe1\xd0ub\x0f\xfc\x97\xc4\x837%\xc5\x14_\xbc\x0f\x89?N\x82\xacH\xdc\xdd}\x00\x89\x9f\xe5\xab\x90_\xc8\xa4]Hz\x97\xf8Q:\x8f\x93\xa5L\xdd\x83\xd4\xd7~\x9a\xbe[$q~\xba\x90\xe9\x0f!\x1de\xe2x\xb0\x8bu\x97\x1f\xc1\x8a\xb7\xe97\xce4\xdf]6\xc9yL\x9fF\xf9\xe0\\\x0d\x07U \xb8\xd5\x88D.j\x80\xd5\xd8\xca\xcfS\xae\xbd\x1a\xc7&\xfa\x93\x01I\x85\xa2r\x1f\x82\x16\x13\x9e\xe6\xcb\xca{\xe3\xa9,\x1a\xc4Q\xc1\x92\xc5`,\x08 \x89\x1fD=\x8f\x05\x90r\x1c\xa4o\xb3Y\x00r\xfcL\x1b\x18\x1e\x9e\xc1\x119\xd4\x12l\x9c\xc7r`\x88\xc4od\xdb<\x96\xd6\xa5xg\xd2Ztch\x83oN\x0e\xd6\x87\x8f\xf9r\xc7\xe5H\xc7\xbaA/\xed\xd0 y\xa9\x8d\x0ff<\xcd\x92\xf8\x12\x17\xb6\xfc\xd1\xf5\xb3!M\xb7\xc5\x16:u\\OZ\x02$\x830H3\x1e\xf1\xe4\xb9\xd8\x87\xa4\x13\xe1\x1e\x17\x9bi\xcfU\xfbk\x9d\xde\xd2_\x9cZ\xd1d\x19\x9f\xf1/\xe4wjsndj\xf3oV\xd5\xe7\xb9\x9eW\xce9Y\x13F$\x98%\xea\xabz\xae\xed\xab\xd3\xc6\xafN\xc9v\xcb\xdc\x86\x95\xa0\xc8-br\xa5\x9f\xf5\x14\x1d\xdb\xa7\x06\xb6O\x8b:\xd5\x14<\xca\x08\x02\x04gL\xaf\x95\x86\xbb\x10`\xa9\x89\xac\xf7\x04!I\xb3$\x98f=\x92\xaa\xdf\x1f\xba\x03\xbc\xadDZ\x08\xec\xb6z\x9c\xaf\xe3R\x81f\x9cD\xb3\x8d\xf6m\x8d\x15\xa6\x91\x9ci7E3Wg#\xdf]\xae\xb8d%\x9f\xfb\x91\xe0&\xc5>\xc3|6\x0d\xfd4e~\xca\xfc\xe2K\xc4\xb9\xf0C\xe9\x86\x1b\x19\x9e\x05\xf7g\xd2LK\xa6d~\x10VS\xe4y`\xdf\xea\\\x99i\xbb\xbc\xe9E\xaa\x99QS\xbc\xad\xe5h\xe9g\xbe\xd5;Y\xc4/2\x94G\x99\xe34y3}(O\xc1\x16\xa9\x18.\x88}@Q>\xaa@%\xab\x82$\xf3\x98\x8c\x01\x80\xcdT\xa1\xe1U\xc6\x9eG \xfc\xfe\xf8\xc3/\xfa\xdb\x05\x062\x06\x89\x06 \x10\x06\xebc\xac!\xc6:c6Fl#\xf0R\x00V\xb6\xdat`\xe5\xeaH#z4\x10\x10\xa1\xcf3\x12\x01\x87\xc6\x10\x0f\xaa\x03\xaa\xe1x}\xca\x8b/ \xf0\x16\x91A\x949\x05a\xce\xde\x04\x11\x15\xf5\xae\x11\"M\xbdkY\x81\xd5\xaf\xfd4\x0e\xda\x1d\xb8#\xfc\xf7\xeb\xf0\x97\xd0\xa3|\xe6Tn4\x15\x9d\xc5kM=\x14\xc7\xc3\xacHoH\x02n\x8f]\x16\xb1\xfe>\xe8\xc03\xcb\x9c\xd1f\"5\xf8\xc5\xd1\xd4o_D\xcdcJ\x06~\x18\xc6Sg\xcbb\x8an`LQ\xb3\x0d\xedJ\xc8\xc0\xb19F\xb3)\xf9\xbd\xaf\xa2\xd4\x9fs\x87\xb3\xa7O\x9f\x82x\xd2\xaf\x82/\x17\xd3\xf9\x98\xf9\x8f]\x00\x9c\x0f\xdf@\xa8\x06x\xa3>\xf7@\x97\xb6\xbaD\x9b\x1fQ\xa5\xaf\nV\x0c||\x04\xba\x0d\xc4\x81\x01\xe2\"\xe1\x83`\xb5d\xf4\xb7 JW|\x9aU~\x0c\xa6y\x9a\xc5K \x13\xa5t\xa6\x98\xa0q\xbd\xe0\xa4 \xd9\xd5j.*\x11r5\x1c\xd6\x88YI\x8e\xe5\xf2\xa6(\xae]\xfa,to\xa0/\xd2\xc6k=rw6H\xa2\xb6\xef\xea\xeeN+nH\x8eD=\xb0\xefC0\xcb\x17\xcb%\x9f\x05~f\x95jH\x05\x0d\x1a\x19I\xbf3\xe6}7\xfd \xe1\xa2\xbb=\x7f\xda\xa0\x9baRw\xc3\x07\xb3x\n\x922{\xb9Uitt\xca\xb3\xd7\nI^\x81R\x83\xcc\xb0\xba\xb0\x12M\xad\xc0\x92D\xc0\xe4]\xb0\xe4q\x9e\xc9\xe8\x88\xdc+\xfd\x1c\xac\x92x\xca\xd3t\xd2\x835\xfc\xf3\x0fEpIy!x \x0b\xa0\xb1m\x1b\x1dQ\x8f\xa6\x07j\xa4\xdc\xfa\xb3p\x88\x0b_\xea\xb1 \xb8\xd8HG\x9d\xa6O\x80\x12u\xb0\x8a\xd3\xecK\xe9@M\x9c6\xf9 X\x8a%\xf9v\x9a\x04\xab\xccj\xef\xa3\x1eE\xc47\xb6\x9a\xa5\x88LJ\x12\x05\xb3nu\xd1\xa6?\x05\xf3W\x94o\xdb\xf4\xeaOF\xeb\x10\xf4\x07\xf7\x86\x12\x02N\xaf\xe7\xb1\xde'=y\xaa(?\x1c\xd5o\xd9UZ\xa1g\xc2qA\"%\x9b~\xbe\xf0\xa3\x88\x838\xdb\x01{J~\xce\xaaY\xee@\xc0}H\x0f\xb8\x11\xb9\x16\x0e\x07\nn\x93y\xae\x81\xa7\x01tb\xbb\x02\x14\x0b\x16\x82l\x0c\x16b/\x8e\x12\xee\xcf.\xd3\xcc\xcf\xf8t\xe1G\xa7\x1c|\xdd\xcc\x07\xd3\x84\xfb\x19\x97\xa2w\xa7\x97\x02R\xf5\x04`\xc0\x8eq^\x90\x00Yd\x9d\xae*\xd4\xb3~\xc5\x8e`\xd9\xc0\xec\xf1:\xe8%E\xbdt+\xc8d\xc5\xf2d\xfc|\x11\x8430s\xced\x9e\x1d\x8fD-\x94m\xabZv\xc0w\x87SI\xed\x9c\x85\xc7\xb6\x8c\x1bF\xea\x11\xa4\x03\xc43=}\xcf\xf8\xa1\xd8\xed\xe0\x16P\xe2G\xb3x\xe9\xc8@\xb5\xc8m\x14=h4a\xcc\x06i\x9c'S.ob\x08\x8c\xd1\x83sI\x1b\xa5\x812\xe9\x93|\x172%A4\xe3\x17\xaf\xe6\x8e\x0f\x02\xbd\x85\xd3\x97\xe9\xa0pq\x14\xd3b3q\x14\xeb\xd8\x9f\xcd@\xd8\xaad\x14\xb0*\xeb\x89NO.\xba\x1el\x7f\x1bC\x10\xfc\x0e\xfc,\xf3\xa7\x0b(\xe9\xf4\x8a\x85)\x052Ig\x00T\x89\x8c/XX\xa43\x96\xf9\xf5p\x93*&\xa1\xf3\\kR\xb5\x8d\x9a\x19/\x97DGy7q\x80\xd1\xe6MF\x7f\x156\xbd48.\x14\\\xea\x10\xb1 \x11\x0f#\xe4>#\xf6DwM\xd0\xef\xbb\xca\x97@Qo\x0c\xaaA\x8b\xdd>\xd3\xec\xbe\x9aW\xa1\xd8\x8fO\xfc\xe9\xfbF_\xe3\xe2\xf1\x93\xd3\x942\xb8S\x0fq\xacU\x8f\xdc\x86\xc2q:A\x01w\xe2\xa4\xae\xc7\xd2~\xdf\x86p+<\xa2\xe9sG\x1c\xa4\x1b\x8c\x08f\x0d\x16%\x18\x947\xac\xdfhd-M6\x18\xa9\x80t\xd4\xa5\x88\x04\x0d\x94\x86\xe88L#\xca!\x19\xebV=p\x85\xad\x8d\xc8N ?|\xf5'K.;p\x02\x1b\x1dW\x8f\xfe\xa8\x81\xa0RW\xa0Y;\x83\xa3\x9e\x04\xea \xack\xee\xbdz\x94\x91u\xd2\"\xbb\xa0\x1e0\xbc\xde\xb2\x1b\xdfRO\xa3\x01%\xf5\xb4\x98i\xd7\x1f\xe8\xd3p\xdd>%\xe3-\xeajw\xd3s\x9d~m_\xa7_\x1eK\xc6\xc3\xef\xa3w;\xd7\xef\x9d\xf8\xbb\xfd\x91\xfb\xd8j\xebM=\xa0\xb0\x0fA\xe4@\xd8{P\x0f\xcdQWJ\xd8\x98\xa3\xa2\x00\x9b\x07\x91\x1f\x86]\xe8\xc3\x0c\xd8\xb9i\x87\xf3\x825\xb7\xab\xe1oM\xb6\xe7\xf4\x8a\x98\x05:/\x94\xf2p^^aW\xf7W\xb3E\x90\xc2\x0d\xd7\x11\x14\xd0\x94\xc0\xba\x11\xc0\x0e\xec\xc5v[\x80\xee\xd7\xa2\x8a\xed\xc3B6\xed\xc4\x17\xadV\x06a<\xf5\xc3\xb7Y\x9c\xf8\xa7\xbc9\xe6\xda\xd4\x07\x02\xd8\xe6\x15\xa45\xda\x19\xd3U\xca\x95\xef7\xc6^\x97>#\xc0\x9c\xac\x97%9\xc7\xc3?\x9e\xfb\x9d\xc8\x1dd\xf1\x17\xf19O\x9e\xfb\x84\x06Y\xff\xd5\xf9^\x1fS\x97a\x9c^\x14\x7f\xc6W \x9f\x82\xe9ZO\xbb\x97g\xf6Wi\x9b(\xd7\xaa\xf5\x9b\x82M\x1b\xfe\x06ycS/\x119=\xd0\x10\xd5\xbaV7>\xb29\xf7f`\x90\xd0\xcb\x12\x7f\xca+M\xb0\x036\x8d\xa34\x0e\xf9\x002\x1d\xf0w\xa4\x92\xce\xfd$B7\xe0\xb0\xf7w\\SL\x17\x17 \xa9\xc9@%UZb\xb5\xadC\xebR\xea\xb4\x86hA\\\xc5\xf9N\x99\\j\x0cw\x86\x96+\xe5[\xbbd\x00\x98\xc0\\\x1f\xa8\xdc\x03\xc2\xa0\xe9\xf7\x82\x12\x890v\x98\xe1N\xbb4%!\x02\xe8\x8b'\x1e\x04\xd1\x82'A&\x1d\xc1\x0c\xc1\xd2C\xa59\x01\x9a\x99\x04\x9a`\xfd8\xd3\x8cF\x9a\xa0\xc5\x007\xf0\x94\xdc\xea/\xa4\xc1\xb6&r\x86\x8f\x1et\x9a\x9fj\xad\xdd\xebT\x1a>\xba\xef\x96f1\xd7\xac\xaf\x19\xd0ti\xa1M\xe3\xbc3\xa4\x02\xe8\x8bt\x8bK\x82\xbd\xf6[\xea\xf5\x89\x92\xaa\x08\xbc\xac]\x1e\xe0\x0c^H\xa2\x9b?\x88\xe2d\xe9\x87\xc17<\x81k\xa9\xa0\x96s2\xed\x8678.+\x95\x0d\xa5G\x0c\x7f\xe0\xa7\x97\xd1\xd4E\xcf\x04\xfe`\x95\x04\xcb \x0b\xce\xc4\xd6\xa7\x8c`\xd8A\xf5\x13p\xb1z\x0b\x0e\xeb\x19\\\xb3\xc0\xaaF\x89m\x17<\x7f\x8f\xea\xb5\xb5vE\xb1\x1d\x17bQU\x13\xf70Q\xbc>\x84f\x8a\xae\x82\xe5\x8f\xb3\xb7\xf5\xc8\x95Q\x8d\x96\x8146r\xf6\x86\xa0\x9f\x19\xcc\x82t\x15\x97\x89\xbb\x90\xb8\xf4/\x9e\x9d\x16i{*M&lc\xcd\x84\xcf\xc1@\x85'*}[\xac8\x81(\xfe\x9a\xab\xa6\x0d\x91v\xf7(D\x02\xa1\x8f\x7f\x92\x9a\xa8\x049\xf30\xd6\x1dbwC'\xa5>J_\xfa/\xd1_\x05\xba\xe8\x00,\x11Get\xa7\nN?\xee\xdcaA\xfay\x10\x05\xe0\xa2\x1a\x1c\x0dq\xf0\xf2\xe1\xc4\xd2\xdfP\x9bQG'0\xd4\x88\xc3\xde\xb6\x0b\x82[\x18c\x1a\x9cF0\xf5\xbb{;\x9d\x88F\xfb'\xac\xfb\xb3Re\x15\x1f&\x17\x18m6\x05h/\x0d\xe0\x9c!z\xa5\xdbT\xbf7\xb7\xb7\xd6u\xe7\xb1\xc60\xec\xb6\x99\xdadz\xe5\x8c\x03Q\xd0=\xb2pi:\x81>pn\xa3\x9f%b?\xa0\xbd\xd2\x0e\xef\xd7\xfd\xdaH\x02Y\xf7\x98$\x03V\xee\xd1\x01+\x05\x9dm\x86\x0e\xe3\xb4\xb3\x81\x08oCUgX\xec\xe5\xe8\x10\x03n^I\x97\n\x15\x9a\xebjtG\xd1\x1b\xc2\"\xfc\xd5J|\x1d\xf3 l\xe8\xca\x9f\xf4\xb4\xe6\xce\xa8\xe5\xcc\x9bbEt\xd8z\xa0\xda =6\xf7X4\xe6\x13\x88\xe9\x81Nx\xc8K\xe5\xb6\xe3\xea\xad\xe0\xf2\xae%\x16\xe0\xce\x90\xf6K9\xbco\x89 \xfcp\xcf\x1d,y\xb6\x88g)Ejw\x0d\xff\xc0\xa9\xe4\xec\xeaG\xa8\x90^\x0cp,\xac\x96\x9cv]6\xf3re\xa0\xa6\xb1\x9a\xad\xd9(\xa0(G\x12\xcb\x80\xd7\x86\x82!1\xe3\x9a\xdf\x80\x05\xa4\xf2e\x90uXX\xc4Q\n\xec\xbb=vVD*\xf5\xd8\x89\xc7\x8e!\xc8\xec\xa1\xc7.0\x9a\x96\xc7\xde{\xec\x99\xc7^y\x10tk\x0e\xe7/\x9a\xe2c\x00\x11y\xa1\x14i\xb9\xdc\xbd\x0b\xf14\xee\xd6\\#\xe8\x1aW-\x10\xff\x02\x9cu\xea\xc9\xae\x07Qq.\x06\xa7<\xf3 \xf2\xcd\xc5 \x15\xaf\x97\xf0\x8a\x9a\x0d\x0f\x02\xd9\\\xa0\x06\xc5\xf5J\xc1\xcc \xe1i\x1c\x9e\xf1$\x85\xe6_\xc9\xad\xa5H\x15\x8b\xfa\x19SA\xf3\xed\"-Vn\xc0\xd2\xb4\xaa\xa0 &\xf9\x10\x1b\xf2+\xf8\x1e\xf8\xbeq\x02\xb7\xec\xd2>n\xd2K\x91\x08\x8aIb\x9b|-f\xab8\x89C\xe0]_Z&\x9f\xf2\xac\x07\xab6@s<\xd7c\xaf\xc9\xe8%\xa2\x0f\xe8tO\xf0LAi\x808-\xe8 \x9e\xe2\x83\xf1\xd6DP\x80\xb0\x9e\xae\xfa\xbc\x8f\x9e\xa1\xecB!bd\x8a\xb7H\x9c\xde\xf3 \x99\xe6\xa1\x9f\xb0 :\x8b\xa54\xc7c\xbd\xe7/\xde<\xff\xea\x8bgo\x8e_\xbc\xfc\xd1\xab\xe7\xcf\xde\xbdx\xf5\xd2\xa6x\x17\xad\x9e:\x01!\x8bA\xa5\x92\xe8C\x03\x18o\xa9'r6^\xa3J2\xf6\xd8s}^R5/R\x89/\xf8\x90*\xfd\xf4\xd8\x99[x\x15\x14\xeb\xa3Q\xe0\x06\xc7gzV-C\xc5\xbb\x02\x8dh\xa3\xae\x13\x14\xa8[\xe2\x90\xc5\xaa\x10\xf4m:\xb2\x97xT\xc7\x97Rf\xc6F5$s=\x1b\x9a\x17\x9d\xbe\xe5IB\x93\x000\x19&\xa6\xa9\xb8C\x8eV\xad\xa6'l\xdd\x93\xfa\xed\x92\x02\xfd\x8e'lyRT\x0c\xab\xd0\n\xa6\xb8qZ\xe3*5\xa0\xfc\xda\xc12\xbd)5h\xe8\xdc-O\xdf8\x16k,\"'/V\xf3\x16U\x82\xf21\\c>\xa9\xfc\x8f\x93\xe04\x88\xfc\x90T\xf8+n}\xc4\x9e\x99\x99\x92\xd5\x7f \xde\x83`\xb7W?\xcd\xb2\xa7<\xebr\x15T\x0e\xf2U\xc1\xe8\xbdr\xb8\x0b\xbb\xdc\x01[\xa2\xb3\x07\x89\x14\\L\x86I\xf5\xcc//\xfct\x8d/[\xe6\x91r\x12o~\n\xf7\xdb._\xb3\x900\x86\xfd\xa5{\xc00\xaa\xfa\x9d;\xec\x12-\xa5\xd8>{\x0d\xbc\xaa\xb4`\xc0\x1f\xefu\xb4\xc0\x9c\x1e\x86\xa8\xa3\x1cE\x99\x83\x006a\xd4\xae\xf2P\xa2\x15\"N(\x83\x80\xc8w\xee\xb0\x13q\xe6\xd3X#\xaf\xe8\x18|\xa5\xd7\x15\xb0q4j?\xb52M\xa0#\x16\x7f!\x10y\x0bz\x0f6\x02\x1b\xac2\xf9y\x91,\xa1TZRA\xfcW\xf0\xe41\xab\x08\xf5i\xdf\x15f\x7f\xc5\x18Glaf\x14\x87\xe1\x0e\x00\xe6\xc8\xd9\xca\xe5i~\xb6\xbe\xbc\x8fMV\xcd~\x95\x05-\x8b\x1a\x883.A8\xe5\xe1\xf1\xae\xe4d2\xe0d\"\xe4\xd1\xfc2\xc6]\xbdC\xeb\xec\xe9\x85\xa8[\xb6&7\xbfj\x93\xacmi\x11\xe4\xa3\xdcTp\x17\xf1\xcb\x00}\xf5\xfe\x9e\x83\x14\xbd\x95\xf5\xe0\xad\xb0\x93\xdd(\x87.\xf7\xdc\x91\xda\xef4\xb0r9k\x02\xa0%u\x8b\xb0\xb3bE\x9b\x82\x97\xc3\x8f\xd6O\x1f\x82\xd8K\xd8\x93\xdd-\xb1\xa0\xa1\xe3\x1210\xe6\xbe\xd9\xff\x95\xf3\xcc#\xfa\xac\x0b\xbfF,\x00\xd7UV\x12\x1b8\xc7D\xae\xa4]\x81\xe3\xab\xd3\x8e\xf9\x15\xd8\x89\x02\xe7\x9c\xca\x83\xbd\"p\x0e\xcd>\xfbE\xca\xad\x1c\xf1w\x86T \x10q$\xb7h\x99\xea\xe2-\xb1\x97\x83`r0\xf5WY\x9e\xf0\xb7\x99?}\xff.\xf1\xa7\x9a(\xa9\xe2\xab\xa3U#\x15I{D\x94wR\xd1n\xf3\x8aphH\x88\x90\xd2\x9a\x90\x89<\x0b\x07N*\xddm\xe5\xb8\xa9I\x8f\xa4\xca\xa9=hdR\x19\xd50\xc2\x9b\xb8\x81*\x1b\x0d\xa6\xf1L\xe0^\x0eWu \x08D\x84\x8c\xea\x9a\x0e\xa8\xd7\x90\xc7\x93j\x05\xdc\x81\xa5\x90\x02}\x85t\xd7.H\xf7n\x0e\xed\x15e\x1e\xc7#\xd6K\xfcozu\x1ae\x96=\x11\x18\xdf\x9b\x9d\xfb\x1d\xcaf\xc97\x97#\xd6\x13\xffz\x06\x8a\xf3\xc1<\x8eY\x9f\xf1\xc1\x89\x9f\xc0\x7fQ\x0eh\x83\xe8\xca\xec\xdc\x87z\xb7,\xb8\xdd5\xa2B5Hn\xd7\x08\x9c`\xd1\x10\x94\x17q\x02\xc3\xe4\xd6c\xdb5\xbe\x1blu\xb9.\xe9\x04n\xb4b\xa4M\x8a\x1a\xedV<|\x9c@\xfc\xd1qBX\x9b\xb6\x9a\xecD\xe8\xac@\xac\xebV\xf3\x0bd\xf8\x87\x8f\x99\xcf\x9e\xb0\xf41\xeb\xf7}y\x85\xadX\xa0\xfe\xc4\xc3\xf8\xd4\xca=Q\xee\x9a\xea\x13\xcd5KT\xe8EHL\xff\x18\xaa\xc3\x87CT\x1dj\"vT\x1e>\xdc\xfe\xd8\xcaCz\x12\x15\x8f\xa1\xf9\x96\xed\x15Z\xf5\x1ex[\xac\xceC\xe3\xa4\xd26X\xb7-P\xa6\x94#\xda\x00\xda\x96S\xbd\xe3\xb2\xd31x\xc3-\xe6\x06\x8fg\xeb\x1a\x9f\\\xab\xef\x04\xc5\x94\x9f\x18\x91\x97\xa6\xf0\x16\xda\xc8\x98\x9ak\x0e\x1c\x86}\xe7\x0e\x8b\xc7J11\x11\xebr\xdd\x10\xb9\xed\xa8)\xd0\xfc\x01\xe2\xbf\xbc.W\xb9s\x9b\xf9A\xa4V\xc3\xee\x0dV\x83\x82\xb6N\xe6\xd7\\+M{]R\xf6Ulz\x1b\xcae\x88Ju`\xf7R\xbe\xeb\xeby\xf38\xee\xdd\x8e\xaa]\x0d\xd3\x00\xa5\xbc\x0es]l\xa8\x1d\x11+\xcae\xf6\xf46\xf5\xef\xb5\xeb\xa4\x9er\xc8N\xe9\x80\xe6\xb4^t\xd5Y\x953\xeb\xaa\xcaY4\xabr\xce,\xaa\x9c\xda\xe7\x96]5>\xa7\xed\xc1n\xab\x15.I\x8a1\x8d\xa3yp\x9a\x83\xf6\x95\xa6\x1a\xbc\xd0\xce\xd2\xae\xaf\x95\xa7\xa4&\xba\x92\x1b\xdf\x164*i\xe3V\x98\xe2X\xac\x87\xb69\x185\x9c\xea\xb8\xd7;>\xe6\x1c\x0c\x07\x0e4\x07s\x90&\xcer\"\xe9rp\xe6\x87\xb9\xe0h\x16J\"sV\xab\xed\xb1K\xd7\xd3\n\xcab\xd1\x98O\xd8\x01\xe5t]\xe6\x88\x7f\xe8\xb1\x0d\xacO!u\x9f\x8dQ\x9b\x9aM\xca$\xe9\xad\xa3\n\xb1\x1a\x8d\x8f\xa6|\x04\x94\xbe\x1b\x94<\xdd'\x98z*\x80\x8a\x95[>c\xb9F]\xee(J5u\x8c5\xe0*\x992\xdah\xb7\x8a\x05\x07;\x02\xba\xaf\xa2i\xe1\xd4\xe7\xf8\xb8#(\xe6\xf3\x11\xf0\xbe]!!\x89\x04-\xe7F`l\xd0hS\xf1\xa7@\xd7\x97q\x80J\xc4r\xc7|\xd2\xa1\x9e\x896\xe8`T\xd46!\xc6\x14\xeb\x1d\xe0\xed71y\xc98\x98\x08\x1e6pY\\\xfa\xe5\x8d)\xb8b\xae`\x94\xb7\x95s*%\xd2\x97(\x98\x8c\x03i%7\x14\x88\x99\x0c\xd2\x15\xdc|\x0c<6\xa4\xee\xee\x81*-)?\x9b4~V\x8ac\xa3&\xeb\xf8\xb6iG \xa2\xdfzG\xf1\xac\xf0j\xd18\xef\x16:!\xb6\xe3\xb8:\xa1\xf6\x19\xa1\xe7\xb1\xd9\x19<\xccbD(\xc9d\xac6-\xde\n\xdew\xcc\xf0\xc8\x92\xb1',\x12\xd3\x9d\xb9,\x18g\"\xb3z\xd91k\xb8\x08\x07\x1f\x8d\xc1\x81\x05^h\x95\xedn=\x06\xc2\x1b\x8b\xca\xd8\xb4\\\xc5I\xa9\xc9!\x1b\x95\xbaTu\xa3\xac>\x96&\x00t\xb9\xb55+\x88\x0b\xe8\xa9\xec\x03c\xedw\x8b\xba\xdc\xc6\xaa~\xaf\xc6\xb0\xdc\xfc\xeb-\xb7\xad\x9a\xbe\xeeU\x84G7\xebK\xa7[U\xbf\x10\xfc\x14\xcf\xaa\x06\x05\x1b\xe6\xfd\x80\xfe\xf5\x81\xf2\xc6,8\x8b\xa9S\x17z\xe2^:u\xe2z\xba\xd8X\xa6N\xe0R\x84g\xea\xe8\xe6\xd0hG\xb8t~\xfe\x01\x85q:{\xdc\xec\xf5G\x19\x8bi\xa1*\x17N\x88\xce\x88\x8bSc5T\xa4\xc72e\xb4\xc4\xf6Y\xfe\x03vS\x8eY\x9e\xa3\xea\xb1~\x1b\x04\xab\x04\xdb,\xf88\xd2=q\xf9\xbdf\xe7\x01\x1a\xdd\x1f,\xfdU\xbb#hU\x81\x1d\xb0\xcc\xe1\xe3\x08T\xcf\xe2\x7f\x15%\\\xe9|\xc9\xc9+Zi\xf3\n\xff\x07o\xbdc\x0d\xc8\xbd@\xe0\xd516O O\xc5\xbe\xa1Zq\x05\xd7u\x12D\xb3\xf6P\xb6\xddg\x16\x8f=\x8f(S9\x9c\xa8 \x85\xff\xd7<\xd5\xc5(\xda\xe0\x10\xce\xfdv\xba\xdd\xe9 \xadD\xcb\xc8\x98\xe2H\xe6I\\\x0b\xc8\xd5t\xdcF\xff\xed\xe0]\x00\xe6p\x0c\x82d\x0fe\xc4\x13\xd7c\x9f\xc6q\xc8\xfd\xc8\x01V&+}.C\x01\xd4\x05\x81]\xf4m\x8cY\x13\xe4<\xdav\x07A\xc6\x13?\x8big\x8e\xc6\\\xca%\xfa\xc8fAN\x1a\x90\x1bK7\xa5\xe5\xc9!\xbd\xfe\xa7\xf2\x9bur1\xaf\xe3U\xa7c\xb5yX\x9e\xdd\xc6a\x94\xc8\xd7\x0f\xa3f.\x1c\xe6\x08\x1f\x8c\x1f\xac'\xf9\xeaQ}\xddET\xb2\xa5V\x13\xcaV]\xd2\xdbF]\x128Z*%\xf3)J\xe6C\xe7B\x06\x08\xbf\x90\x0e\x12\x99t\x19\x0eh\x0e\x13'R\x02\xf4\xf8\xec\x16\xbe\xf2\xaa\x8d[\xfc1\xc0 \xe8\xc2zF\x9c3y\x89F\xaeN4\xf7tN\xb5\x10\xc5\x82\xa4 \x16\xc9\xdb\xdb\xf2\xc2\x9e8\x9f;\xcb\n\xc71t!b\xd9>\xe3p\x19}i\xe1\x86\xf0T'\xbe\xda\xc2\x85W[\xaft\xaa\xe2f\xe4T\xb05\x91\xcb\x96h\xcc\xc7I\x0bJ\xf5\xc8\x91.\xc9\x02\xe6\xa5R3e !\x03\x7f`/\x040\x9f\x1bzdf*'\x9cs\xe8n2\xb1\xc2\x02\xe0p\x02f\xae\xe7\xf2J*\x1a\xd2\x08\x82\xa9\xe0#\x0e\xc8\xe2l~\x02\xce\xc5\x9c\x128\x1b\xc7\x83Y\x1c\xf1\xc7.(\xe0/\xd8\x81b\xe2\xd0\x1a\xf8\x18%&\xd2\x90\xbd\xf8%\xf6ogVHS\x0e=\xb6p\x96\xb02fp\xddJ\x82\xf9\xb0\xfe\xd1~\xdf\x125K\xcc\x1c\x11\"\xa84\xf7\x9c6`\x03@\xe0\xb4\x123\xdb\x1c=\x8c\xd7\x03\xb9]\x0d'\x0e%B\xc8Py\"GZ%\xed\xb3\xc3\xc1t\xe1'\xcf\xe3\x19\x7f\x969[\xae\xcb\x9e\xee\xb3\x07\x0f\xb6\x1f\xed\x82\xc5\x12{\xb2\xcf\x1e\xec\xee\x0c\x1fA\xf9Cp:9\xee\xf7\xa3\x89\xb4g0\xc0y(\xedG\x0e\xad <+Ax&A\xd8\xef\x9f\xd9\x81v\xd6\x82\x8e\x1a:\x89=\xf0\xd4D\xb8\x02z\xbe\xa3\xad\x9d\x1a\x00\x9dS\x97^P\xe40%4\x15o\xd7\x1d_H~\x00\xbb2\xab\xc8\xee<\xb6,/\x89B\x8c\x90\xa2\xe6\x0d\xf6\xf5\x9a\x96\xe2\xd1\x8e\xd4R\\.O\xe2\x10U\x12\x8f\xee\xdf\x82J\xa2v\xc2)\xf48\xb5-\x1e>[\x91\xc3\xb6\xe9vH\xbe\xcb\xdcb\xc8{(8J\xcd\xf9Bm\xf7`\xfb\xb2\x88\xd3\xcbx\x9a\xc9\xee\xd5\x8d:i\xf5\xa22o\xac\x9b>\xddD\x89\xa8\x97\xd9H\xc6\x95Q\x14,\xd9\x04\x953F~\x16\xbfV\xdaM(B\x95\xc0N\xbf\xf3O'\xb7\xc74\xea\xba\x0e\x8b\x8aC!_\xfdZL\xd8\xac\x90\x98v\xd54\xcc\xbbi.V\x84B\xc2d\xfa\xc2\xfa\xed\x90\x1az\xed\x1b\xe8U;\x97\x14X\xb5\x06\x1a%\x8e+=\xda6i\xa5\xeb\xeaf&\xe7`\x81\x9b\x80\xb3(\xbb\xef50}57\xbb \x92\xc0\xc5\x98c\xac?\x8c\xa1q-wF\xe3\xca)\xb4z\x98\x8f\xbb\\\x8f5\x89[\xbd\xb3\xfc\xd6:\xeb\xc3\xcdrP\x04\x01\xf4CG\xf3j!\xc5h\xda^\x0b\x01\x1a{\xa5\x15\xa1\xe0B\xa6ND[ \xce8\xfa\xa2\x0c\xe2\xe8\xf8x\xc4r\xf0/\x9aQ\xe6|\xc7\x91\xbf\xe4e\x993\xa7n\x02\xfd\xa1*\x1f\x99:q\xfd\x93\xf38\x11\xd5\x9b\xb1L\x0ez\x86\x8a0\xf87\xc2\x7f\xfb,v\n\x8anHE*\xbf\xdf\xf3\xcb\xcf\xbb|\xccb:\x0e\x8b/cA\xc4R`jgv!\xfel\x9cM\xd0\xd6\xb9\xd4\xdc4vm\xe1\xa7/$\x96(X&\xa8\x06\xd1r\xd0\xa2\xaf\xa7\xa5\x18\x01\xd3\x83\xf49\xc8\xaa\xde\xaeT\xc8\x97Zsf\x01\xd9\xaa\x99a6.\xf7\xb1z\x932Y5$\x7f\x1a\xd5\x97\x82\x1c\xd6\xeaB\x9a\xac\x08\xefF-\x19\x19\xa9VO\xc5N\xc2\x9a\xf2\x97Q7\xe5~b|\x12\x13eM\xfcaV\\\xf1i\xc0\xd3zMLUU\xf1\x17Q7\x0c2\xa3f\x18dE\xbd0\xc8\x8cZ\x1a\x0fP\xab\xab\xe5\xc8\x16\xb4\x14\xa2\x9d\x82S0\xda)r\x8av\x8a\x14\xa3\x9dW\xddS\xdfoT!\xeb\xc2_E\x95j+\xae\xd6\xb1\xd8\xde1\xfd\xcb]\xbe\xaa\xc8\xb7\x031\xdcQ\xf01\xa8\x91Q\xd6g=\xd70 \xad\xfc\x863\xc5\xaby\xd7\xaf\xa6\xb5\x98Z\xcc\x1c\xe5\xbc:\xcaXG&\xaf\x0d\xac\xea\xfa\x89\xfc\x0e-\x1e\x95\x8cw-B<8\xc8(0\xce\xd1;E\xf7\xaa@D\xe8\xd5\xb4\xe7)\x98\xf6\xb0B\xd0^!\xae8\xe3\xafp\xcct\x13UHPM\x94l\xf9M\x1cj\xe9\x02\xda\xdd\xb5=\x19\xa1\xdf3\x108P\x9c\x03\xba\xf6/\xf8\x06\xfa\x1c$'\xeb\xd6\x8dG[E\xfc\x1b\x1bx\xd9\x87D\x93\xab+\x91\xaf\xc7*\xc0\xb2o\x8b\xb2\xe0\xc6\xb4\x1e\xca\xe0\xce\x1dV-2\xae\x16\xaa\xce\xfcm\x0cYM\xa0a\x12\xa5>U]\xc6`K\x81\x12\x88.\xcb\xb8\x10\xc0V\x17\xb2\xe3\xae\x8d*Uk9\xee\x02x\xe2_,\x04\"gg\xb8}\xed\xa1\xd8\xdd\x06\xfdR\x0d\xb2\x12\xf2|\xbd\x01\xa6\x86CqX\x18\x88\xe6\xa6)\x88\xf2\xcf\xa1\x1d)\xb0o\xa2R\x0d&\xee\xedY\xcc\x9e\xe9^`\xd6\x1d*\xc1N7O\xef\x01\xb1XR\x9e\x91\xd7g\xe1\xaeQ-\xea\x9d8\x12\xd1\x91\xa4\xa0t\xe2\xf0\xc1)'.\xd3i\x01R\x07)\x071a\x06/\xfbP'\xe5\x10\x9d\\\xdenC\x15\xa0\xfa\x81%\xf0\x07\xdc9\x93\x01\x8f\xb0\x90\n~$\xca\xe0\xad)\x88\xd1\x0d\xfd\x94\x1f\xc8\xd0\xc1Dv;\x14k\x8d\x89)\x04 J\xdej\x1eb\xb5\xa0\xff\xbd\xff\xbeW\xcd\x97\x87\xa2\xfd\xf2\xd20\xc8e'\xeec\xb6\xb9\x99@D\x9f\xfe>\xeb\xfdw V\x00q4\x89 \xd9\xf77j\xb5\x19\xea\xf7%Ik\xbfB\xd8\x12\x95\xc3\xcb\xf0\xd6`\x82\xf2{A\x02\xb8\x18h\xac\xc2<\xe1@\xb3q\xbf\x9f48\xf61\xd0\xb5\xcb>Q\x8b'\x7f\xcb\x17\x18\x86\x86\n8\xae\x8b\xf8Z\x00mc\x1f ]i\x06*)3=\x82\xd3\xbc\xdd\xc5\x8beA7\x9f\xe6\x99f\xc2JwG=\x01\xd8\x8bZ\xb3}\xeb\"QOPD\xdf\xf2\x8b\x15\x13\x8c}\xb8\xba Fe\xaf%>-J\xda\x06\xc0\x14>>f1{\xc2|\xb6\xc9\x86\x8f\x9b\n3\xd9\xb0t\xa7\x07\"\"\xb9?\x04\xa0\xed\xe4\xe3x\xe2j\x0eW\xad\xdd+Z\x83.\x0e'\xa0C\xe9\xf7ckaS\x05\xa9\x1e\xf9\xad\x96>\xb1\x03\x15\x8eN~N\x81\x8fl\x97\xfe\x9a6*#\x9f\xb8M\x9eV\xd0\xc8jo)\xd0(@ao\x03\x1a\xe5\xcdh\x04\xd2\xc4\x8eh\x94\xba,\xc7\x10\x0e\xfd\xbe%\xf0PK`\x03@\x1ah\xe3\xeaJ\xbe\xec\xb3q\xe3DS+\xb3\x9ao\xcd\x9e\xc8\xab{\xe2;\xf2V\x9c\xc4\xd4M\xe9\xfc\xc3 \xcaI\xcfa\xd2c\x81\xf6h(\x1b@\xd5-i\xe4\x0e\x19\xa2\xa2\xc7\xf2\xf1P&~\xc4\xae\x17}\x1fN\xc6\x01\xe0\xb8\xff\xf8F\xfdv=\xd5\x18N\xe05\xf0WJ8\xc9p\x8b\xe6P\xd7\xf3\x8e!\xdd\xc74`\xb2\xdf\x8c\xc9\xb9\xb4/o\xc6\xf5\\\xe9\xc1\xad\xa5B\xd8\x0e:\xac\x05\xc9l\xf9\x02\xbb\xec\x8bAT\x81X\x80\xe3\xb4\x0b=\x0d4,\xedNO5\xee\xdf\x07t\xc8\xc7\x81FO\x9bIi\x88\x88\xe2\xa3\xa7&\xec\xebp2\x8e\x01\xe9\x82k\x10\xd6[\xe9Yq\x15\xb7\xe8\x8c\xa8\xaf\x0c\xf7c\x0f\x10Z\xe4U\x92\x1e\xb3\x0d(&\x15\xe0w\xee\xb0P\x117\x176\xdcp\xb0\x8aW\x8e\xeb\xe1\xa4\xc8_n\x87\x96\xd7X.\xda}\x80.\xeb\xa4\xab\x03\x16\xc9\xa7\xe8|\x89\xd9\xfc\x0f\xe8_7\xe0\xca\xaa\x9a\xff\xbd-y?\x11\xdd\xd2\x0e\xc0\xa9\x9dt\xec|\x93+\x89k1q\xfa\xb7\xd79\xca\x81\xc2\x9b;?\xff\x00\x84\x92;/\xfd\x97x\x0b\x91;;\xf7\xbf\xcf\xb3N\xc1\xf5o\xec\xdf\x8e\x1c\xac\xca:_\x13\xack\xf2\xc6u\"y\x1bl\xb1F.2\x0f,\xe1,fpU\xe6-.\xb9\xb4h\x1cwZuU&\xab\xcd\x7fh\x8642\xc1\x03W\x84\xbf\xfa}\xee~\x9c\xbdP\x93XA\x10)\xd8\xf87`\xa0x\x86\xaf\x12\xab\xa8\xf2\x9b\xa0\n\xb7Ct\x08~\xe5#\xd0\x9b\xdb<\x05\xd2B\x06\x1a\xd5#++j\xe3\xe3\x08x\x10%\x83\x1b\x1e#\xad\xbe\xaf\n\x89@\xc1:\xa1\xa142\x11\xbc\x95\x89h\xdc\xa6\xb3\xca6\xddr \xeb\xc434\xb2\x96-\xfd(\x97\xb7\xfc\x8c\xf5\x10\xd6\xba\xd2\xad\xc7\xa9\x02\x9c\xd2\x00i\x0b\xaf\xdcD\x8fY\xae\x81\xb3\xe0\xc0\xfd\xb2\xa7\xa9\xe4\xc0s\xc5\x81\x8b\xbcT\xe3\xc0surH;\x9c\x1c\x9aN\x0d\x96\x13\x03\x9c\x16R\xf8\xe8p\x02N>\xfa\xfd\xbc\x0b\xdd\xbc\xce(\\O}\x06\xce\x11\x99\xc7\x02\xb0/\x10hHxN\xee@\x0b;a8\x1es\x91\xcb\xc7\xc1\n\xb2\x14\x82\x18 \x93\xc7\xbbk\xe3<\x9e\xa1B8C\xb5\xb3\xa6)B$W\xc1\xbf\xe5)\x0d\x91\xdf_\x03\xf9eo6\x1a{\xd3rd\xc8\xf4\xcf\xe7&#\x9b\x13,r^e\x91\xd3*\x8b\x9c\x16,r^\xfe\"Xd\xb3ekO%G,f\xaa#xn\xb0e\xd9 9\xbb\xe6\xf2\xf2t\"nv\xf5\x07\xf4\xaf[\xda\x03m\xbe\xc1\xe9\xcb3;C\xfa\x82\x9b\xe9K\\\x1aY\x1a\x17_R\xdb\xcd\xb7j\xb1\xf5\\\x84[6m\x88\x16!\xe3\x18\xb4\xdcx\x97B\xd3\xb9\xc7V\x1e\xd8WN\xa5\x81\xa21\x1f\x8b\xa6\xcc3\xd0n(\xc7sf\xfe\x12\xf2\x95\x13\xc6*F\x97\xf5\xc0$\xbc\x99\x97S\x9cF\xe9_\x98\xc4\xad\x04|C\xa9\xa8\x0ep\xaf\xd4*\xa9\xa7\x9d\xad0\xe5\xb1/A3\xbb\xb4`\x9f\xb7<\xb69\x14[\xc3\x99\xbc}2/\x9c\"\xac\xc4\x9b\xa9s\xead\xb1\x1c8\x1a\x00\xd9Y\x83\xe1\xf2\x87\x1a\xf8\xe2H\xb9\xe9m\x87]\xe3\xf5v\xf2\x02%+\xcc\xdd4\x17\x05$\xcct\xc3\xbd}6\x9e\x81\xcb\x8aH\x19\xf1!u\x8f\\\xd4\xc1\x01h \xeeM= nH`\x91\x89tb%}L@\xa8|e\x93\xdfbD\xa3\x1e\xe0?\xect\x94\xf2\x15\xbb\x901\x0d`\xbf^\xa0\xf7\x8d\xd2%2\xac-\xf4\x07\x1b\xe0~%\xbd\x19'\x10M!\x8e2~\x91A,\xa6\xe44u\x0b\xfb\xcd\x04\xe3G\xc4\x88)A\x89BbNlq\xa2[I#\x86\xfb\x96k\xab\xcd\x0d\xc7\x19^\x8c\x94F\xe1\xd6E\x11\x89\xa1\xf3jd-\xe9\xffC5\xcf\xb8\x1da\x14\xff\x8c,\x05\x1f\x043\xbb\xe4O\xfa\xc2d\x8d\xf1\xfc\x01\x03q\xbb\x13\xadaOf\xe3\xb4t\xdb\x8b?\xe2R'ct>\x03W\x9a\xa9t\x80\xc8\x0e\x98\xd2\xec:\xe0P\xdcY\xa0\xe0\xdc\xde \x86\xf6lbnG\xb8\xe2\x1b\x8bbh\xe7\x06Q_\x89Ri\x89R\xa9G\xaf\xaeXF6\x88\x8b;\xc9nCI\x14\xc3\xd5/\xc7C\xf5n\xd7\x90\xf5Gk\x8c\xb7\xdc\xb4gr\\\xe8)\xdc\xc2\xb5\xa1\x087wBy\x9b\xd9\xf4\xfeB\x1d\xb6q+\xa6\xa8\x00\x97\xbc\xb4\x94\xb3\xca\xae.U\xb3\x1c\xe2\x03NOp\xc9E\xb8\x00}\xcd\x05\xf9\xb2\xc5\xfd\xcc\x07OR\xd9\xb4\x03\x95\x85\x95#I\xe1\x1adr0=\xa9Q\xca\xc1\xf4\xc4-\x0d\xa0\xc5\xcf\x02\xd7\xf1G4\x08\xc4\x96)\x9d\xef\x001e\xa3\x12\xa9\x89\xeb\xe38\x8a\xc2\x9bu\xfbvA\xb0\xeb\x14\xb1\x9c\x01\xb1\xbc\xba\x02BY\xec\x9c\x0b\xdd\xabv\x95\x84b\xa2FEU$\x19 \x98 n\xb1\xf5^\xb9\xbcn\xa7r\xa2\x0bD\xff5>\xa6\xe8\x0f4\xaa\xba\x13\x0b\x8cl_\x1d\x92\xce\xc8\x9e\xf3\xa2\xe7&\xea\x1ac)~\xde\n3k2\xad\xc8\xcc\xee\x191\x18\x03\x99^\xbf\xc4\xed\xcb\xf4\xba7]\x15K\x8c\x0epc2\xb9\x1dn\x0c\xc5N/[p\xf0\xd8/\xfe\x8fd$d\xb8X\x1fG\\\xfd/\xd2\xdd:[\xabB\x19val\xb5\x0b7\xc6\xac\xc4M\x99s\xea\xa6\x11S\xa62[\xca\xec_]\x0e\xac\x96)\x14T\x1c\xfc\xa3\n\xf2\xb3\x01\x91\x96\xe8k!w{\xac\x0f\xde\x1eX\x9f\xf5\xee*3\xcf3?\x0cfL\x0dv\x19\xcf\xb8q\xf1\x8d\"I \xee\xeb\xb65\x11Z\x02\xf4\xc2\xb0r\xc7/ES1:X\xf5\xa5\xc9\x14\xb1Q%\xf4\xe14\xc2\x8aC\x8f\xcde\x13f\x19\xd1\x95i\xabS&\xbd4`\xee\x98\xb2\xb7Q\x8f\x18BH\x04\x9c\xfb\x12yj\xce\xb8\xf8=b\x9f\xf1\x8cO3>cy\x14'3\x9e\xf0\x19\x13\x88x%\xb0\x8e\xdd)\"sC\xf8\x9e\\t\xcec\xe7\x8b`\xba`A\xc4\x002K\xff=O\x19F\x1fc3hMpC\xf1\x9c\xa5\xf9t\xca\xd3\xf4\xde\xdc\x0f\xc2<\xe1,X\xae\xe24\x0dNB\xce\x9c\xf3\x05\x8fD\x13wu\xec\xbe\x0b\x13\xeb\x1eE\xcf\xe3(\x0df\x80N\x04m3*?\x1c7\x1f\x1b\xc6 \x15\xbd\xc8\x02\x89\xb5N\x0e\x84'T\x9dc\xac\xf0\x96:\xbbh9S$k\x9d)H\x13\x97\x8fz\x8a\xa8\x8b\xa6\xa5\x90\xe0#\xe9\x89\x9b\x14\xb7JOY\x06\x90k\x06[\x86\xe7\xe3\xfa\xc5\xfc\xea\xe5\xf3\x9b\x03\x88p}\xa5NYm\x91\x96\xad\x86*\xe8\xf9\xfdV\xe7Q\x9c\xca\xd6\xbf\xbd\xd1\xe8\xa2\x1f\xaf\xe28\xe5\x15\x19p\xe8\xa6]\xfc\xd3\xa2\x895H\xad\xcd\x89\xa3\x0eC\xaf\xfd4\xe5\xb3B\x10\xa3\x05\x84\xc6K4\xc1\x9c\xcf\xea\xf1\x8cn\x17~{\x86JG\xcc\xf3\xbd\xf1Qt\x94\x1c\xe5\xdb[\xdb\x0f\xe1\xef\xa3\xc9\xbd\xd3u\xc1\xac\xd0_\xcc:\x89\xfb\x85\xc2\xe2)\x1bnm1\xe5\x80.\x93\x0eX\xb7<\xf6\xe8\x11\x1c\x13\xff\xdb\xef\xfc^O\xde\xff\xcf\xd4=iAq\x9b\x97\x8a\xfc\xcao\xbc}\xf5r\xa0\xc0y\xe9pW6?\x04\xc5Fm\x19\xdd.p\xff_\x83\x9cJ\xcf1~\x19G\x9b\xd3\x98'S<\xc6e\xb1DD\x17o\xf2N>\xea\x85\x8d\xdb\x88\x11o\xd3&\x96\xdf\x0b\x06\xb3 ]\xc5\xa6L\x85p\xa9)\xfaV\xb3\x81\x08 6\xa5\xa2\x9dg\xa7]W\xe0\xcc\x03\xa7B\x1e\xab\xf93\x05\x89#\xf8\xe4AY\x0b\xdbg+\xc5\x96.@\x89P,\xd0\xd4\xb2@\xd3\xe2\xc7\x01\xeb\xe1za#\x06\xbea\ny#\xeb\x8b\xcf\x17\x1d%\xf1u\x86\x0e\xd6R\x9e\xbd\x0b\x96<\xce\xb3\xf6sO!\x00\x8aH\xe1\n\xb7\xe9\xbb\xc4\xa7\x06y\x94\xf0\xb9\x18@\xf9\xcb\x81\x88\xa7\xe0UNt\xe6\xce\x1d\xd6\x8b\xf8E\xf6.\x98\xbe\xef\x81u\x90J\x86\x05\xa4\xba)\x12E\xc5\xf5\xfb/\x8f,\xcb\xbasa\xd9\xff3[\xff\x97\x95\xfe/\xb5\xfe\xb7hpj\xf3@.\xfb\xca\xd8f\x18\xef\xbf\xd0\x98\x8a\xb3\x15B\xc8\x80\x0c\xa7 \xa3\xd7^\x92A\x15\x05.\xf1\xcf\xb9\xd8XE\xb3g\x18\x1ct\x7f\x7f_\xcf\xb9\xba\x92Q\xdb\xcb4\xb1m\x0fvvv\xd8\x88M\x9d\xb9\x83\xa6\xe8z>\x1aGmI\xcc^\xb2}\xf6\xf3\x0f\xd2\xaf\xd6\x90m\xb23\x97}\x82\xd2M%\xaa\xa8\x03\x07t\xde9\x05\"\x18\xec\xd5\x15\x83\x01\xb2}\x0dK<\x16\xb4O\xbbE\xda!\x1e\x0d\xaa\xfb\x1aT\x1d\x0d\x84\x9e\xae\xb0\xabl\xa1h\xbb\xe6\xc4\xae\x8b\nA\x08\xe8W\xb1\xb3\x91\xc6\x03\xd2b\xae\xb2\x8c}'@Hu\x12O\x84\x1e\x0b5 \x05\xfc\xa4$\x9c\xa6\xdf\xa7\xea\x1eT\x839\xbd\x0d\xcd\xdaP\x96\xd5\xd1\x96\xdc\x8b\xd0\\I \x01bp\xec,\xbb4\\Ctn`\xb9\xe5c\x88q\xc6\xf8\x8b\xdf\xb7\xb2\x05\x1a\xbe\x98\xd5\x11\xf3\xd1\xda\\\xb3\xe0\xca\xa4\x01\x87\xd8\x0e\x9e\xb2\xb8\xc9\xb7\x08\xbf\x98r>K\xd9\xd2\xbf\x08\x96\xf9\x92\x15z\x8b\x0c\xa1\xf2}9\x1b\xd9\x1e\xde\xdf\xbb\xffpg\xf7\xfe\xde\xf5\xdbk\x07\xe76\xad\x17\xdd\xd5\xafx\x04bG\xee\xb8\x1d\xcb8R\xc4^\x9c\x14{q.\xdd\xc0Kk\xf258\xe5\xe6\x8d\xd8G\x13\x9bf\xc4\xd7\xdd\xfb\x02\x8b0X\x04\x99\xeaZ\xbb\xc1\xc0i\xf9)b\x0b\x12\xa3W^\x11\x0cr\x00\x99\xd2\x1d\xc2m K\xcb\xe46(\x9f\x83\xf6xW\xeb\xae\xb1\xb32\x044q\xf3\x01\xc2F\x9a\xc9y)\xff23\xd3\xa6\xcc\x10\xda*R\x1f\xed\x15\xa9\xc3\xedm\xb8\x0f\np\x02\x18 \n\x8e]\xae&\x02\xdcz\xff\xf7\x1f\xfc~\xafq\x1d\x9av\xef\x84\x1d\x85\x8e\xb1 \x82\xc178j{\x15D\x96a>\xabK\xb5\xea\xbe;\xd1\x05\x87\x1f\xdc\xe2\xc2N\xe4\xec\x0co\xe2\xdb\x93\xf4]/\x1a\xee\x1d\x1f\xf3\xf4\xcbx\x96\x87\xbcW\xa7\xda2T\x90\x1eJ\xc1EY\x0f\xc4\xd3k\xb2UQF\x00\x89*\xec\xb1X\xbd\x96\x1b\xd0\x07\x93\xdd\x08\x1cq\xb8}Pw\xf3\x1b\xcb\xac\xfb\xdb\x10\x95\xb3\xc8S\x1d\xc0\x90cd\x1f8\x12\x99r\x9c\xd2\xef+\xb5Ca\x9c\xc0\xba\x9f\xbe\xf5\x88\xe9/\xc7\x04\xa8}\x87&\x8b\xd3x\xb9\x8a#A\x0e)8\xa8\xe7\xd9j5b\x97\xc5\x0cZ\xcb\xf9y\xb6\x88\x93\xe0\x1b_\xf4\xe4u\xbc\xcaW#v\xd2\xbd\x1a\xff4\x8bF\xecx\x8d\n\xafV<\x81\x8fA\xcd\xf3n5\xd3\x11;l/\xf9,\xcf\x16/2\xbe\x1c\xb1\x8b\xf6\xc2\xa2\xd9C4{{\xdb^:\x16\xc5\xb7G\xecY{Q\x7f\x15\xfc&\xbf\x14}\x19\xb1\xe7\xed\xc5O\xfc4\x98b\xe9\xf7\xed\xa5\xe5\x91\xe4U{\xc908\xe3ox\xba\x8a\xa3\x94\x8f\xd8\xeb\xf6\nA4\x8fG\xec\x8f\xb4\x17|\x11\xcd\xe3\xe7\x18\xd8\x9d'#\xc6y{\x95\xdf\xc8\x97\xabw\xf1k_\x8c2\xebP>\x8e\xc2 \xe2?\xf2\xc3`\xe6gq\xf2\xa9?;\xe5#\xf6\xaeCE\x85]\xe9\x88}\xb9F\xf1\x11\xfbi{\xe9\x02u\xdf\xe6\xcb\xa5\x9f\\\x8e\xd8\xcb\xf5+} A1G\xec\xcd\xfaU\x11~\x9f\xb5W\\\x04\xa7\x8b08]d\x82\xe1\x18\xb1\x9f\xb5\xd7H$\xa6\xa4#\xf6y\xf7\xd2#\xf6M\xf7\xc2\x9f\xc6\xb3\xcb\x11\xfb\xb4\xbd\xc2\xcaO\xfc%\xcfx\x92\x8e\xd8\x8f\xd6(\xfe&>\x1f\xb1\xdfh\xaf\xc0/\xf84\xcf\xf8\x88\xfdV{\xd9\x05\xf7g\xd0\x91\xdfl/\x0bF\xb4\xe9\x88\xfdZ{Q\xb8\xc5\x17e\x82y\x1d\xb1\x1f\xb6\x97\x8f\xcfxr\x16\xf0\xf3\x11\xfb\xed\xf6\xc2\xf38\xce\xc4\xc2\x8c:,\xb4\xcf\x830\xe3\x89\xb6\x9a\x93\x0e\x95^\x0b\x88\xe3t\xc6\x1d\x8aO\xf3$\x1c\xb1\xa0C\xc9t\xba\xe0K\x81\x83~\x87\xc2o\xb1\xb0\xd6\xf7\xbcC\xade<\xe3\xe1\xe1\x85\xbf\\\x85|\xc4\xc2\x0e5\xbe\x145~\x9c\xf8\xab\x95\xf8\xc6\xb4k\x8d\xe7q\x18\xfa+\xb1F\xd2\xaeUFl\xde\xb5h:b\xab\x0ee\x0f\xa3|)\x9b\x9eu(\x8e\x8c\x8e\xac\xb0\xe8P\x01\xcc6e\xf9\xb3\x0e\xe5\x0bg\xf7\xb2\xce\xb2S\x1dd\xb8F\xec\xb4C\xe9w\xc9\xe5\x8b\xecU\x9e}\x9ag\x99 \xeb\x97\x1d\xea|\xe9'\xefg\xf1y4b\x17\x1dJ\x7f\xea\xa7\xfc\x0b\xff2\xce\xb3\x11{\xdb\xa1\xfc\x8fx\x92\n\xde*\xf1O\x97>\xae\xb7\x11;\xe9^\xf1m\xe6/W#v\xdc\xa1F\xb1a\x1c^d#\xf6\xc5z\x15\x80|~\xd5^\xe7\xb5\xa2\xb7\xf0\x91__\xa3\xc2\x8bh\x1a\xe63~\xb8\\\x89\xd9\xfcq{\xcd\xa2{\x10i\xe4\xc5\x1a\x154\xaap\xda^\xed3\xceW_\x04\xd1\xfb\x11;\xef\x00e\xc1\xff|%H\xda\x1f\x1d\xc8\xd7\xe6\xb2\x02ap\xeb\xc6\n\xeaw\x03i;;}\x96\xa6\\p\xf8\x87E\x87\xc8\xd2\x9d\xe4\xd8\xb4\x9frV;K<\xef\xa4F\x88:\xb5\xf5\x9eh\x8b\xd4\x1c\x8dg\x05\xbc\xd9\xbc|M\xcbW\xbf|\x0d\xcaW\xeal\x8az@\xf9\x8a\x87\xbb\xb0L\x88<6-\x7f\xad\xca\xd7E\xf9zV\xbe.\xd5k\xe3\x89\xf7\x15\x87\xe0\x03\x8f\xa8#/\xe6m\xef\x1a\x11\x8e\x8a\xbc\x9d\xedz\x9e_\xe4\xdd\xdf3\xa2\xe5\x14y\x0f\xef\x1b\xf1\x80\xca<\xe3\xf8\x1d\x96yF_\xa6E\xde\xa3\x9dz\xde\xbc\xcc3\xfa\xb2*\xf3\x1e\xd6\xf3fe\x9e\x01\x97\x85\xca\xbb\xbfe|\xef\xac\xcc3\xda\\\x16y\xc3\xadz\xde\xa9\xca{\xb4c\x8c\xef\xb2\xcc3\xc6pR\xe6\x19\xdf;.\xf3\x8c1\x9c\x17y\xf7\x8d\xbe\x1c\x96y\xc3z\xdeE\x99g\xcc\xfb\xdb2\xcf\x80\xcb\xf32\xcf\x98\xf7\xf7e\x9e1\xef\xcf\xca<\x03.\xaf\xca\xdaq\x07\xdc\xebv\x11G\xab6\xcd5\xd9\x1amW\xc7\xceQzs\xa8\xc5\xe8=}\x10\xa0\xad\x1a\x04D\x10\xa0\xadj3b\x1a5w\xc9\x807\xbfU5\xb2\xf5x\xfd]ugDN48\x81\x1eD\x837\xf0\x03tX7#\xd7\x12\x8e\xa3\x00X)\x8d\xb3\xdb\x87.>\xaa\xdd\x02\xb2\xaaM\xf1\xc1\xaf\xf3\x14Y\x11\x8f\x84)\xc3\xf6\xd4j\x82\x10\xaf\xb4F\xf5\x98\x06z\xc2\xff\x8c\xf9H\xf5-\\j6\xaf\xbe&\x13\xc9\xd0\x19\x14&\xc5\x1b\xd3\xd1\x0c\xc6\xc2\x82D\xff\xda\xaalar\xad\xaf\xb54\xe7\x05ab\x9b\xe7\xac5\xd6\x1a\xec\xe4Y\xe5\xae\x1d\xb1s\xdd\xc7\x01n\x96\x06\xb8\xa9\x0c\x106]\xb7_$\xa9\x86;\xb8\xbfg0\x14.\xe7\xac\xa9\xcc\xb93D|\xc1\x83\x0c\x83\x9b\xd1\x1b\x98\xa3!G\xe2\xac\xf3\x00x\xcf!\x85\x97\xb0|\x0e\xcb^\xcf\x05\x8c\xea\xbe\xec\xc3\n&p\xed\xac\xa7\xcbY\x1f\x96\x8c\x8c\xb0\xaf\x86\x10+\xe6^\x99\xf4-\x0e\xc6\xb5p\xf7\xc7A<\x87\x0e:f,\x06!\xbdM\x1d\xd7E\x0f\n\xcd\x10\x88\xb3@\x17\xadi4\xc0\xab\xe8>\xb0\x01q\x8b)Q\xa4\x19\x944b\x924}\x9f5W\xc9%\xa6\xe0\xfd7!\x1b\xd5\x8d\xcd\xc9\xc6\xb3\x9d/<\xc10{6;\xc9\xe3\xc1B\xd4\x89\x9c!\xab\xc8\xa6NyT\xeb\x07\x12\xef\xd0\x19\xed\xed!)\x15\x14\xf5\xd9\xa6 \xac[\xe2\xef\x9e\xf8\xfbTKh?p\xf3\xc46]Y\xc0\x95\x87\xcd\xec\xcb0\xbf\xb5\x88i\xbc\xcb\x9a\x83A\xa0'\xd0\x92$VI\xe8BO\xb8\xd7\x82u\xa9\x14\xcf\xf9zU\x87r)\x1a\xa9\x96_\xf3N\xb7\xab\xe5+A\xe7\xab\xe5KQ\xbe\xe3\x0e\x12ZQ\xcb\xde Z\xbf\xe3:U^_\xf4^\x9d\xda\xb9h\xad*Y\xde\x88\xf2*;u\x88\xb1ws+\xb3\xf2\xc3[\x1eI;\x8e<\x9aT\x82q\x9e\xe0#\xb1\xee\xe5G\xaf\x18\x05\x17/!\x01\xf7\x9c\xdb*w_1\x0f\xa9(b\x0f`\x1fw\xc9\xc5`Q~p\xcc\xd8\x97\x8e\xdd\x04T\xef\xcf\x0e\x8a\xdd\xc9\xc9\x00\xa3\x8f]S\xa7\x8aG\xea\x87QC\xa7\x9cZ\x17\xed\xa6\xa6\xa13z\xe6*\xb9\xcbg\xad\xac\xfd\xe4\x87:W}\xb82\x1b\xc3\x1b\xa2\xe1\x08\xc2\xe5\xbcb\xf4]{>\x8a\xb5\xf8H\xff\xe0\x11\xd3\x0e\xafi\xc8M\xdb(w;\xbbr\xd5\x94\xa7\x9a\xa0\xf7\xe6 \xc8\x9f\xab\xe8\xf7\xa1q\xce\xd7\xf5\x8c\xa5P\xcc\xa3\xe3t\xd6\x0e\x8fi\xa9\x8b\xea\x84G\x11\x1f\xb6p\xa2)\x0f\xa7<\x98\xd3\xa6`\x85 M\xf0\xe9\xe0\\\xebM\x0bH\x83\xcfCt\xa7\xd4/\xc0\xb5\x08xH\x07\xe7\x9e\xbe\xc6]\xb3\xc5-\xa8\xd2#O\x18z~\xcd\xcd.\xd1\xd0\x91\x0e\xce\x93RZ\x8c\xbcE\xa37\xb9\xfc\x08c\xd8\x82|F\x18\x817\xba\xc2\x98\xa5\x0b\xe2[nq\xe4'\x11\xf1.ps4W\x0fDu\x86p\xcd\xb5=\xac=\x8fV\xc4oH\xede\xde\xc1\xea'c\xf2\x0c\x1at:\x9b\x02v\xe8\x14\xfb\x07\xda\xb5\xe2\xaf}tj\x15\x0e\xb2\xac>\x97\x83\xc6\xe0\xa0\xb9\xbd7\xa0aJcG\xf0\x1f\x19\xba\xbap\xdfPo@o\xfd\xd4\x11\xeed\x9d\xa1\xcb\xeb\xb0\xdd\xa6\xd8\xe2\x07\xce\xa1\xd3\x15\xfbn\xc3\xbb$~\x08\xde\x9d\x17\xd0.\x0fI\xcd\xd6\xf1\x83\x13rk\xd8<1N\"\x9cA\x13\x87\x9f\xd8\x81\x13\x9b\xa9\x01T\xf7e#Xp\xfc\x1d\"\xe6'&\x11\xe8\xdc.\xd5\x8f\xde\x95\x07\x9f\xd4\xf8\x8d\xc8\xb7\x08\xaf\xec\x89 O\xec\xa08uR\x94D\xad#\xff\xd8n\xe4\xfch\xd2\x0f\x9e{\x15\x0e\xce\x8d\x01=\xc3bR(`\x8b9\x19\x8e_\xfb\xb1\x8b:q\x19\x98\x99o\xac\xe2\xf0\x03\x8f\x84\x8f1\x8c\x98`\x1e\xe6\xe0\xa7 \x0d\x16\xb60\xba\x08\xe7\x0f\xe8&=i\xcb<\x81\"Z7\x9f\x85\xe77c\x08\x9b9\x93\xf3\xf9X\xcd\xf1\xaf\xfb\x18\xb8r\xf9i\xc7\xb1\xa4\xf9E@\xe0|\x14\x01\x9e\xd9\xf7#\xf1\xfd[\xb2\x01Gy\xbe\x8c/?\xf9]v\xc6\xe4\xe8\x1fr\xf4\x1f1\xfc\x0e\xfb\xd01\x8d\xb7\xdd8\xc5\xf8\xec\x13i\xb1~\x0dk\xf7\xd98\x7f\x8deQy\xbb*\xfe\x11\xb8\xd7O\xac\x1b\xf6RD.>\xe9\x83\xdc\x14\xdd>t\xcf/\xbbn\x1f\xe6\xdc\xd5Jx\xcc\\\xfaU\x17;=\xfaP\x07\xd1\x84\xb7\x9bc\x8a\xfcY!.V\xa0\x1f\x15=\xd7\xe0\xa1\xa8\xbb\xfa\xfc\x107O\x925Ppv\xfc\x97z\xf2\xf2\x92\x84\x8b/\xfc\xc7\\\xf2~\xf8\xeb\xbaV\xf9R\xad\xcc\x19\xc5b@nq\xa5&\xd4\x1d\xbb\xaes\xa2\xc4\x8c\xaa\x8d\x8f\x86\xe3fQP\x8ar\x07\xceJ\xae\x9ak\xd3\x15FWe\x9dtGI\xce\xca\xcey\xb67\x98\x80e\xd4\\\xe3\xd9\xc9jq\xe9\x07\xd9\x18v\x16\x8b\x9f\xe3\nL\xbc\"\x97\x8f\x841k\x80\x7f\xad>K\xd8\xb3S1\x8f\xceH\x0dTS^\xe7\xf2>Bti\xd2\xdc\xcb\xebH\xd6\x11\xaa\x10\xe48\xcd8$\x82\xe8\x18\x89\xb9\xd4\xc1\x84\xf4\xa6\xea\xb8\x89\xdd\x14\xe9\x07\xa8\x98\xa18Q0\x04\xecG\xbc\xaf\x1a\xb9\xf9#\xc6\xa4\xe0\x93#\xf1D\xc5\xe6\x8b\xc1\x82\xad\xb2\x15\xa5\x8b\x08\x0f\xfb\xfb\x80>r\xfc+a\x1c4\xbd\xe1\xbe[c\x0c-R\x9a\xe4\xc2Y\x0c~\x82\x1e,\x06\xbf\xe1\xffx\xbfr\\E\xc8\x0f\x92):)\xbd\x1c:\xcf\xf6\\G%\x15B\xbb\xba\xeb:j\x11\xa9*Xy\xbf'\xa5\x1e\x15rS\x9d\x1a\x83N\xd3\x1aK\xfe\xe8@G\x98@\xd1<1\xf4\x14\x10w\x1d\x1e\x8aD\x8bg50\x15\xc3u2\x06\xe0\xce\xb1k\x1d5.w\xd3\xb0\xc5\xa8n\x9cL\xee\x8d|\xd9Nro_+\x9aV \xe9\x1c\xb3\x86\x1ao\xc8N\x06x\x84\xbb\x03\xdc@\xce\x95\x8a\x15\xb6i\x91 h\x9a\x92\xca\xa9\xea\x0f=N\xb4R\x83\xd2\x92\xbb\xf2Z\xb57\x91\xa8b\xd6\xd8\xf8\xed\x05UIFm\xb9 A4iI\x90\x0f2\x96\x8b\x99\xc5\xbaf\xa4\x9c\x9d\"\xed\xd5\xac\x18|\x01\xf6\xc1\xef\xf5\x9a\x19\xc0\xc4\x90\xb6C\xfd\x88\xec\xc9\x9c\x02\xb2\xbd\xd9\xeb\xf5\x0be\x19\xc3\x88\x96\xa9\x0e\xd4O\x82\x9cE\x92'q\xc8D\x12\x89\x8d\x0d\x94/b'lb\n\x8d23\x084W\x9a\xd2\xd6\xd3eG\x90.\xc6\x03\x1e}\xc2\xf1\x07\xd7m\xcf\x95\x98x\x8d{\xf7[!\xba\x19\x8b\xa3\x07`\xf1\xc3q\xab\xbe\xea\xc5\xb6\x03\x8b2O#\xdd\x82}\x05\xa2\x81\x08\xc0\x1b\xd9V@!A\xf8\xf5KmMtgu\\\xdcuc\x94\xc1\xf2P\x93\x1b\x1f\xb9\xce4\x8f\\P\x87\x9cG\x12\n\xc3\xb1~%e\xb8\xa1 P\x8c%L\x85\x9aT\x03\x12lg\xd4\xa2\x9dt:\x9c\xa9m\xf5!\xd5gd\xc7\x167[\xb6\xc8Z\x19i\xda\x15\xe5\x86\xd6\xb7\x1e\xd4:\xfb\x7f\xd3\xd8\x87xj\xe8i\xfb\x0bzb\xffo5\xf4'\xea\x180N\xe9B\xc4=\xc66\x94SQ\x8b\x91f\xbb\xb1\xea\x8d\\d\xb9\x1d\xc5\x14\x84\x83\xf7Y\x8a.1\xc7\x17 \x8d\xaf)\x06v\x88\x07\xbf\xd1\x8b_\xfc\xb4\xfa\xac\xfc>O#\xad\xbd\xde\xcc\xf0\x91\xf6z3\xa9^o\x86\xce\xb3-\xd7!M\xd7\xf9ZNX\x1ay\xb5\xca+\x19\xf7ui\x13\xf0> \xa5\x00\x94\xde\x88\x90*\xa4\x06\x16o\x00\x9e\x035&\x98\xe6J\xeeE\xd8G\xbe\x9c\xa2\xdd\xc5\x97(\x88\"M\xd2\x0cPEScl4\xc8\xa3\xd5cl\x1c$\x04\xa9\")\xb6\x8d>V/)\xb5\"\x00\xc2\xaf|\xca\xf8\\\x9e\xaf\xbf\x00'qy\"D\xdb\x9a\x90\x81\x0cv\xe9\x04\xd6\x06\xf3D\x1e\x1d\x9fcgH\xae\xfd%I\xa5n<\xff9HR\x12\xceI\x10\x85\x1a\xad\x05\xc6\x7fC\x83\x1ey\xda\x98\x00z-\xf2\x7f\xe5\x15\x1d\x83\x1a\xaeq\x8a\xf2\xe3\x89\xc8\xa5\xadu)|\xce\xad\xda\x8frU\x95.M\xb5\x06\x92\xfa\xdd\xb1\xe0\\\x94\xb6\x8b5\xec\xc3<\xf2x\x94\x1c\x1e\xff\xeb\x94\xde\xa6G\xd1\x9c:]\x9d\x8e\x92\x8b~\x81;\x888\xe5p\xd6\xba\xb0Q\xec\xe3]\x92\x98x)\x8d_\x93\x94\x8c\xaby2@J|m\x00\xb1\x1e\xccI\x8a\xb7\xbel*\x8b\x06\xfc\xd6\x12\xe1\xbc\x0f\xedf\xbb\x16A\x08\xf5\xdd/\xc21\xc4\x06~\x0cS\xb2\xf2\x9d\xd4\xb4D\x80\xfb\x8e\xc7\xb2b\xef\xc1>\x86\xcf\xa5<\xfe\x0c\xcf\x0e\x1a\xa2\x9e\x1c\x1f\x19\xe6\xd4\xea\xdch2\xbd2\x9c&5\x93J_o\xa8\xc5\xc5\xef\x9a!\x8fLA\xae\xda\x804\xd0\xfe\xdaN\x95,\xb0>\xc1,\x8f\xa8\x15\xf1\x88Zq-D!W\x07\xe1ej\xcaD\x06\x8cf\xbapR\x0c\x93\xaaa\xc0\xa2p\xe1/\xb3\x98\\p#\xdb\xfa\x12/i\xda\"\x0c\xa0\xa2\x0djB\xcd\x07\x9e\xff\x8d\xeb\xa87\xa13\xaccm\xd5\x89\xc1\xf2*\xcbm\xa2\x8aNc'\x1e|\x80\x1e\xc4\x83\x8f\x16i^\xa4\xf7j+\xe8\x10\xa1\x9e\x8b$G\xc1\xf6\x82/\x7f\x18\xa4\x9c\xd0\x84\x1e\x9a\xa0c5E]\x08\x93blF\x93\x17\xf1\x1aOH\xe0\xb8U\x11\xd6v H\xe5\xa8\xb6\x82\xee\x1a\x8f1\x99}\xf8\xee\xe3\x12\x91\xd3\x1e4,\xb3\x96\xe8;\"o\xddt\xcf\xcfM\xf7\xca\xe8xbA\xc44n\x8d\x84\x11#\x11\x987\xda\x88n\xbe\xd6\x92A*\x00\xc3\x01E\x93\"\xa1u\x1d\x17r\xb0\xeb\x84(\x9f6k\x04\xdb\x00T\x82\xce\xba\xde&b\xf4\xd9A\xa32\x99_\xc2\xe9*\x15\xbb5+J\x0c\x01?\x88\xe9\x92\x864f\x0c\xd8\xc7,L\xfd\x15\n\xdd\xc2\xa9gIS\xc5\x95\xe7\x88\xach\xe2\xc4\xee\xc0\x0f\xe7\xf4\xf6x\xc1\xda\xaf\xbe\xdcu\xe1eM\xe3\xe5\x83\x08c\xa7\xeb\xae\x809&{\xd1\x0d\xa8\xe0c\xcb\xd6\xb7{\xec\xd4\xc2\xb4\xec\xfa\xb7\x94\xc8\xf9\xc8;\xd5yx\x11}S\xf7~\xb1p\xc6\xeb%\xeb`\x8b\xf7\xb5\xeb\xae\xb6\xa5\x18u\xd6\xeel\xf4;\x0c\n\xa37tU\xaf\xf8`\xd5\xb1\x9c/v\xd95\xab^\xcb7\x91\xdd\x93\xbb\xd5E\x14\xc0D~\x19\xd7\xccVA\x9c5\xfe\xc0O9@\xd0\xbe\xf1?\xffS\xfe\xec\xd6\xeb\xa3\x8e\x92\x87}}[~\xa9T\xa6y3\xc17e\xb0\xc3S\xb2\x14\xef)%\x9a\xb7\xf0\x92*BX\x95\xce\x94zMOX\xf7\x99\x91\x15\x04\xc2z.\x04\xc8\xf0\xa9\xa8\xe9\xb9\xad8w\xc7\xd4\x0d\xecC\x80\xb9\xa6d\x93\x0c\xde\xee\xe0&&\x8c\x99?\xaf\x93))\x03t\x93,Y\xd3pN\xe7')\x89S\x0d\x0c@H\x04E\xcd\xbf\xfa4\x98\x1bj\xa2C\n\x8f\xa9\xe4\x87:\x90\x820\x06\xefz\xd1j\xcd\xf6\x92\xa9\xa5k\x9ePA\xfbl\xa5qC\xc4\xf2)\x995\xd1Bhb\xce\xf4\xc0Z\x16\xbbfI\xd3\x0fr\xe3\x1c/\xf4#\xbc\x83}X\xb2e^:K\xe7\xbd3\x9d\xb9\xbaKS\xf48\xb9C\xb3(\x14n\x85pw\x87I\xb3ej\x91;\xcd\x8blD\x17h\x9c\xad\xde\xf9\x1e\x96~\x95\x028;+M+\xb7\xa5\xfa\x17\x15\xeb\xed\x93>\x9cT\x8an\xfbp2M\x18\x88o1MW@\x90\xc6\xb3\xe5\xfcIb\xa4(\xbf\xf8\xa5\xcf\xd7mp6\xc3\x83\xd2\x19\xb2\x0fW8m\x8c'\xaeu+\xb5!j$n\xe8\xaf\x9cs\xf5\x0d{dh\xed\xde`\xa7\xf9\x04\"t\xca\xe2\x1e]\x0f\xb9'\xcbU\xcb\"\x9f\x0e\xe5\x8e]Jk\xfa%\xd0\"\xf7+\xc4\x8f\x8b*vuY\xd97 \xb2}\xb8\xc8O\xe3\x074\xd6\x9d\xf2\xd3\x18\xf2\x01Ur\x1e\x82\\\xe0+z\xd7\x9c\x8a\x04\x14R35\xa46\xa8\xf9\xaf\xa7\xd2\xa8\xc4\xba\xbe\xec\x94\xbe\xa6qB\xab\\\xb4\xfa\x91\xa3\x83f;>\x91\xd9@\xde\x1d\x19\x15\xd4\xeaG\xca\x06\xe9`\x1d\xadMZM\xf5\x83\x0c\xb5\x98fn\xd0\xc3\x91\x08\xd3h\x84\x1c\xb5\xb8\x91\x92^l\x94\x1f\xb3\xa5\x1c(\x02q\xde\xde\xd0\xd6\x9e\x96Hx|`l\x91\xdf\xf7\xe1\xb4D\xe8\xf4\xa0Q\x0e\x8c1\x9c\xeaW%\xa6 m\xb4\x02\x91\x1f\xccz\xc1\xedp\xe8\xb5b\x9a%\x14y\xf2gBCy\x81;8\x17?B\xf1L\x81'\xffM\x03\xba$\x18\xa5\x84'\x92\xc4\xd2\x15\x86 \x95\xd9\xc0\xba\xa2\x94\xc4K\xa5\xa54\xbe;\x0c\xd3\xd8\xa7\x89\xcc\x97\xec|p\xfb\xd0i\xb0h,\xa2\x9d\xb3uG\x91\x17\xbaiWxo\x88P\xdbCW\xe1N\xb8v\x86;Kux\xea\xb4\x9eL\n;\x12 \x86X\x1d\xe1[i :z\xf0'i\xb4n\xa1\\\x03i\x00\x95\xa3\x8f\x19\xb7\xa5\x0dU\x05H\xd3\xe1l XP?\xb2\xb8\xd8`*}\xd4\x93p\x98\xd0\x01\x1eJ\xf2\n\x86-\x82\xf9eU\xd3\x14_\x93zb\x020\x83\x821\"L\x8c<\xbc\xf5\xe8:\xc5\xa8\xb4\x0f\xc4J\x06\x9c|\xa0v\x00\x156\xdf\xcd\xb4*vL\xa9\xf6\xd5\x8f\xd4J\x0d\xc4\x96\x140\xecC&\xf0\x16m\xc4\xc5NA\xef\x11\xae\x04\xaf\xa3\xba\xc4s\x86\xcc\x1d\x8b_\x85y\xe4\x12\xc5\xfd:\x1aHg\x9d\x0d\x18=\x07\x1fU\x11\xcfacC\x1b\x17B\xfd\\\x8b\x1c\xffU\xac\xf2\x1b\xcc{@H\xb1\xa4\x15\xf2\x81D\xc08\x8a\xc4\x9e$\xac\xb7w\x91\x97\x13\xe8\xd8\xe9\xd2pn3\x1d\x97\xad\xc8W\xe1\xc5>\xe4d\xabi\xa2 &\x8b\xb9kD6\xf4>tQ\xc3\xf1.\xf2\xba\x96\xd3M\xfd\x04\xe5\xd7\x85J\x18\x1bhw,\xe1\x9dm\xd0f\xb4P\xa3\xcc/0=/\x1f\xb0\x02\xb7\xa2\x10\x1d\x10\x9a\xc7\x01\xda\x96\x8b\xb9\x94\xdaV\x8a\x1b\x1b\xfe\\\\z&\xdfs\x8a\x8d\x0d\x7f6i\x1et\x1f\xbc\xa3\x0d\xd4\xfc\x1b\"\xf7F\x1a\xdfA\x92\x92\x94b\xd6\xf4\x1b?\xbd\x8c\xb2T(\xc5\xa2X\xde\x07\xb4Yy\xf8n\x10\xb7\xd6\xb0\x98\xf9?\x84\x84\x93\x8b8[\xa7-l\xac\xe5G\xe15\xed\x94*\xcc)\x95\xf1Z@~r&\xb0B\xa9B\x03\xbf+?\\\xb9\xaa\xa1\x18\n+\x10W\xb6rny-\x96*.-U3VI\"m\x10\xe8\xd5\xcfEL\xc9\xd57]D@}&\xa6)\xc5\xc6\xc5y\x8f\xfa\x02\x99>\xac+}z\xf0\x16Q\x01\x0e\xc8\xd4%\xbe2el\xcc\x17\xac\x9c\x05\xdb\xe5a\xe2s\xd7\xd7\xfc`@-^#wA\xe4\x11K\xfb@\xc4a\x99\xf6\xb11\xc7\xc2=\x8a\xa3W\x1do\x1f\xae]a\x0e,GA\x1d\xf2 \x06N\xbe\xf6\x00\xa4\xff\x16\x1cVi\xc58<4\xcb\xc6\x1fLJ\xf3\xc7\xf6a\x0c\xe2\xea\xa3R\xd3\xc9Y7\xb9\x83\x04\xf3\xc2\xfe\xd6\x98s\xd1D\x19\xc0\xfctf=\x84Q\xbc\"A\xa9\x07y5\xed\xa8o\xa4n\x1f\x0c\x1e\x7fz\xa0/\xfc\xd0O\x1a\xfd\x13\xf2\xda\x05\xc7o'2iNd\xda\xf9\xd3k\x88L\xda\x82\xc8\x84\xea\x8e\x11\xdbKe\x9csL\x0c\x95\xad\x81\xc9\x89\x17)\x8d\x19e\xe9\xa3\xe3\xb8 h\xf0P\xb2\xdd\xca\xdbC~\xfe\xfd\xa0)\xa8\x92\x80d;\xa2\xcb\x8d\x84\xdb\xb2\xa4\xa0\xd9\xb5\xb1\xd8\xb5\xcd\xfd\x81\xa26\x8b\xed\xbb[\xfd|0\xd9d\xab\x1f\xfb\xb1\x0e\x05\xc10\xcb\x11\xf0\x85GG\x8d\x0b\xf2\x03&\xca\x07\x82\xef!iJW\xeb\xb4\xfb j*\xb5\x01x\xe32\xae\xea%\xad&\x82\xea\x0eR\x94\n\xf6\xe5\x91Woc\x8c7`\xe7\xecc\x9adAzDVt\x0c\x0d\x01-\x18]{\x17yc\x83m\"p\x85\x0e?\x9d\xb8\xe2A\xa1\xab9u,\xc4@\x03q\xac\x95VM\xc0J?sy\xf6\xbcA\xcd+q\x95\x9f\xf1\x8a\x9eI\x89\x0fs(\xf2\xe6\x1d\xea\x01Q\xcb\xa7\xe9D\xaa\x82[\xfb\x0e\x11Z\xe5S\x07\xef8\xa7:[f\xb1\xc8\xfe\xe0\xdc\x0f\xaf#\x8c\x02j\xb3\x15P?\xb9\xdd\x80U\x8b\x99\xb7f\x8a\x95(?\\s\xc8\xd6n\xae\x11\x08rm-\xf8 \x90 \xa6d~\x07q\x16\x86~\xb8\xb4\x89\x01E\xabZc\xf9jU\x95\x1e\xe5\x19\xc6\x0d\xd9\xf0\xe5GL\xf4\xadA9\x0e\xcd\x9a\x85\xb0\xe0\x00\"<\x96\x10O\xfd\xe7\x8d*Z\xc9\xf6\x85\xf9\x06m&\xef\xa4\xa9Q\x10\x0dg\xe8\x14B\x18\x064\xd3W4\x96m\xd32\xc8\xca\x08\xe3\xeb\"\xafns\x1f\xa0(\x85\x1a+\x7f\xa9x\x06\x12\x13\nZ\"\x97\xc7\x85Pjb\xc3B\x0d\xdb|\xfe\xe4\x92\xb9\x8a]E\xa3\xcd0+\x90x!q\x92m\xbc\xcb~\x9b\xde\x01\x9d\xa9j\xba@\x07_m\xf0v\xe2C/1\xb6\xa1BU\xc3\x01\x97O\x9d\x82o\xe5\xad6l\x18\xd8\x87\xb9\xbd\x8a\xd4\x17\xdd\xe4D\xa8\x19\xb1K\xdcq\xd2\x9a\x99\x10\xc0\x957 \x13\xb8\x841\xac\xfb \x8e\x8b\x87\"i\xe3u\xa6\xfa\x11I\xfd\xb0\xabvZ06\xc6\xb1\x18k\xe3\x0b_\xb3\x07T\\MrQ\xc3\xc9\xf1\xae\x90Y\xa4ZV\xd2\xad\xc4\x8eX\x06F\xbaV\xfa\x99-}\xd8\x07\xe2\xf6+\xc97M\xc7\xf0\x8d\xed\xc42;S4\xaeX\x8ai\xb5$z\x99\xd7\x89\xc4\xcb\xdc\xb3\x07\x87\xd1v\xa6\x8d\x11\x1c\xda\x0eQ,E\xc3\x08\xdb\x0e\xab\x15\xd0\x0f1\x9e\xa0\xe1\xe1\xad\xed\xe1\x89\xed\xe1+=0\xa6R\x01\x91c\x9d$=\xb3\xfc\xce\xcal\xd8&?\"hg;\xf1Le\x83\x05\x93\x84v\xb2\xadW\xb7j\xee\xaa\x9f\xf0\x95\xc5\x9a\xb4Nu\xd4\xd1\xa83\xb1\x19\x1a\xe4]\xf9\xad,\x8d\xe9\x8dt\xa7W \xda\xc0\xc3A\xc9\xb2\x90\x07\xbc\x8ey\x90\xbc\xa6\xd7@\xe1:n\x1c:\x0dg\x18a n\xc9{Hr\xd5\xd9\xdf\x177Fm:\x04\xe5\xa8\xc9\xda\x13a\x10\xd7\x11 \xbf@n\x1e!\x14pE\xcb=\x8dE`\xa0(E\x03L\x05\x8bV/]\x17&r\x1dr\xef\xa2` \x9e>\xc8\xb8\xa3\xfaI\x1d\xb9\x99\xa8X\xa2V\xaf~~\x88\xeb\xae\xfaI\x9d|\xd3>\xacC\x17\xc6u\x10|\xd5\xd4\x93\xdc$\x01C\xc9'-\x07\xd2j\xc8\xcd\n\x04\xe2d-x/\xb1w\xd2Z\xb0\xf8R\xad\xb6T\x08\x14J\x06\"K;\x87\xa0\x8f{z\xcc\xa8B\x9dv\xb5\"]\x07\xd6\xc8/<\xec\xa6\xd4\x0bL\xe5\xfd\xacF\x11U\xb0\xb9F\x99\x13or\xea&\x0e*\xb3\x92\xb6`\xac}L:/\xc74\x10\x80\xa9^\x1f\x17\xca\xd8\xc2PB\xcc\xd5\xd0e\xaev\xbc6\xd3\x84T\xc3:\xe5\x1d\x943\xd0\x9f^\xd2\\\xa1\x02\xf3\x88&\x10F)\xac\xe3\xe8\xda\x9fS \xf0\x18\xdf\x7f\x0c\xbcA\x93b\xc8\x86\x0b\x9aH}\xdaE\x8c\x90*\xc7}e%\xc5\xa85\xf4\xb9&H\x0bz,\xf1\xcf\x02\x80Hh\xc5\xebK\xac\x81\xa8\xbc\xeb\x89\xf4B\x90Tm\xe0\x95\x88\xe0\xed\x9dt\x8a4D\xe8\x9dfx}!\xe2\x99\xa7\x85B_\xa8\x9b\n\xee\x02\xcf\x95\xb4\xa4P\xb2\xdb\x19\xe8f\xc0\xb3\xcd\x8f\xcb\xef6\xa0@\xbe\xfc|\xd0\xe0s\x1c !\x88#\xc4\xd4W\xab\x9d{lwa\xd1o \xae\x1d\x1e\x03\x9d\x0egu\xf4\xa9\xaf\xc3\x88\x9b\x9ar\xa0\xc9\xcbd\xcc\xc72\x9a\xb9}\xd8T\x1f\xabz|\xa0\xdc\x1d>\xd7\xd2c\xd1\xd6\xcc\xad\x9b+\xa19]\xdan\xce\x1f\xecs\xa6\xea\xed\xd9\xfd\xbd\xf6\xfa,\xcdMR\xa4L \xbd:R\x8e\xbf\xa5F\xf6\xab\xd1\x94\x0d\x03;\xd5\x0f\xac2W\xd8\x87\xa9}]\xb8\xa9G}e08\xacd\x92\x8f9\x10\x8b\xc8N M\x9d\xea\xfd\xbei\xa4\xef\xf5#E\xaaj\xd3\x16\"|\xa7\xc4p\x07\x81\xb4]\xa1\x12|\x7f R\x9fom\x8fJ\xcf_\x1d\x7f<,?/eU\x1a\xbc>|s\xf0\xe9\xdd\xe9y\xb5\x9fQ\xa5\x1fY\xef\xcd\xa7w\xefJ\xf5\xb6wJ\xf5\x82\x88\xcc\xf1\xc2\x94}\xa9>8\x08\x82\xfc\xd9\x01\xe3 \x8a\xc7 Y\xd0w\xf2]\xf9CWA\xb6\xa1\xfcV\xab\xcd\xb3\xd5\x1a\xb95\xf6\xa5\xfa\xfek\xf9P\xfeP+\xfc\xf5\xe0\xfd\xbb\\q-`\xb0W\x9a\xdb\xfb\xb7Go\xdf\x1f\xbc\xb3-G[0Z \x98x\x84\xbb\xedv\xd9\xb7n\xe9\xd9\x9a\xc4\x18F\xd1w\xba\xf8\xb5\xfc\x14\x93\x19\xcb\xe7\xe2G\xb9\x06\x99\xcf_\x95<\xa5|\xa7[.\xeb~\x93M\xfc\xb4\xea\x06\x1d\x15\x00-\x95\x8b\xb4Z\xdb\xfaDq\x08\xbdRyV\x80\xacT\x9eh\x9cE\xad^\xa1\x01F\xbd-\x15y\x18\x07\xbaL\xaba\x1f\xb6\xcaE\x0c\x81\xb6\xcbE\xf3z[\x97\xf5\xb6\xae\xebm\xad`\x1f\x9eL\xcfn\x87\xc3\x8d\xb3\xdb\xe1\xd3\xb3\xdb\xe1\x8fg\xb7\xc3Wg\xb7\xc3\xc3\x8d\xb3\xdb\xd1\x9b\xb3\xdb\xbd7\x1bg\xb7O\xb7\xcfn\x9f\xeen\x9c\xdd>{s\x96\xbdy\xf3\xe6\x10\xff\x7f3\xbb\x9f\x9ee\xaf\x9f\xb2\x97\xb3\xd7?\xbey3s&\x1dV\xf2\x8a\x97\xb0\x1a\xee\xbd3\x19O\x7f/W\xbb\xff\xdd\xadT{R\x1e\xd6R\x0c\xeb\xe9\xceY\xb69\xdc|\x8a\xff?\xab\xd6\xba\xc3Z\xfd\xb3\xe9\xd9\xec\xec\x1fg\x9f\xab\x8f/\xd8\xe3\xdf\x9d\xc9\xb8s\xdf\xe9\xdcw\xa6d\xe3\xefg\x1b\xb3^\xc7\xfd\xf3\x13\xbf\\\xf3\xbc\xa89\xfd\xbdh\xcfu&\xe3\xff\x98\x0e7\x9e\x91\x8d\xc5\xec\x1f\x9b\x9f\xef\xf9\xf7\xbf\x9fm\xfc_\xcf\xcf\x9e\x9cM\xc6\xff\xf9h\xff\xacw\xf6\xe7\xfe\xf9\xd9\xa0\xf3?g?<>s\xce\\\xf6\xf6\xcc\xfd\xe1\xcfO|\xddYqc<+F\xc3\xc2\x8an\xb4\xc5\xbf+\xd4\xbc\xde\xd4\xa1\xb1\xa9gEK[\x9b-Z\xba}HK8\xbe\x87\x8e\xf5\xc4\xd8\xc3\xf6v\xd1\xd4\xb3\x91\xf2}K\xe9b\xb3\xf4c\xa7E\x87\x1a\xbd\xbaF\xc5,\xc7\xf0\x14^\xec\x0bgI\xf6mg\x0f\x13Zn\xb0\x07cx\xb6\xc7\xca0\xaa\xf8\xd6&\xdc\x0b\x9bF4a\x1c\x0d7\xd1\x9ca\x83U\xea1\xb0\x8cacd\x1d\x98F\xff]\x8c\x82Or\x02\xdd\xb3a\x97\xf7\x9c\x97\xfc\xff\xb0@\xadr\xc1JF\xa3]\xa5(\xc5J\xd5\x82Q\xbe\\\xac(\xe4EjK\xd7X4\xdcT\x8a\x16\xbc\xd6\xb6R\x14\xf3Z\xa3\xa2\xe8\xff\xcfJ\xb6\x94\xd7\x00\x0b\x8a\x97\x1ew\x1f\xc3\x18\xb6\x95i<\xc1\x11\xaa=\x9d\xb1\x92=e8\xff\xe7\x7fc\x9d\x1d\xa5\xe4\xff\xc6:\xeaL\x91*\xb0\xd2\xa7\xc3J\xe93V\xda\xedZ\x17\xe1\xc0\xb8\x08\xb8\xfe\xbb;;[;0\x01\xeet\x87y\x0b_]\x92\xf8U4\xc7\x9c\xa8c\xed\x83\x9d\x9d\xcdg\xbb\xd0\x03\x87!\x0eka\x17^\xbe\x84\x11\xe3uvv\xb76\x87\xe5G\x8f\x18\xbc\xb7\x14o\xd9\x82_\xcb\xed\xe4\x8e\x85\x9a\x043\xee9\x9b;\x8c5\xfb\xa0);\x054\x97;\x85\x17\xb0\xb9\xb3\xfb\x1cN{=\x17\x8e\xa7\xa73\xd8\x87+\xe7\xd4\x85 \x8c`\x0c\xc3>|(\nu\xc4\xe9\xbdV\xc1\xa9\\\x94Dx\xdf\xc7\xc3\x17\x0f\x16~@C\xb2\xa2\xa8,\x0b\xd7Y\x8aN\xb4Q\xe2\xa7huH\x07\x81\x1fR\xb5\x0c6D!:\xd0\x97\xe6^\x1f\xcb[\xedX8\xcf,\xc6i}\xff\x0f\xed\xfbt\x10\x85\xbf\x918\xf4\xc3%w\x8d\xce\x7f\x8a@\x85\xa8U\x12\xed\xeb\x16\x87\xad\xcbQMe\xc4\x18\xb7\x9a\xd1\x99V\xb9{]$\xa4\xab\xcb\x8e\"7\xf0>\xd0\xc15\x8d\x136\x8dG\x8f8$\xba\xf3l\x1d\xf8\x1eF\x1d\x84h\x01\xff\xc1\xba\x84\xb9\x1fS/\xf5\xaf\x91\xc7\xe2IC\xf2\xa4:\xf9\x9b\xe5\x9a@<\xc6`&@o\x89\x97\x06w\xc0d]\x99\x03\x12\xe3E\xb3A\xb0-\x85w\xe0O~w\xd8\xa17\xeb\xb9g\x03\xf9\xed\xcfO\x06\xf4\x96zN8\x1d\xce\xb8\x17\x1b\xef\xc8\x0f\x82\x8dE\x14\xaf\x98\xa4\"\x1a\x04L\xb0I\xa1>Z\xc6\x8e!\x03\xf96L\x9d\x18\xc3B\xe2^\xf1\xcb\xe5\x9b\xb2\x9c\xcf.*z\xcbB>\x13r\x11\x88\xf6%\xccD\x9f20\x1b\xe7?\xe5\xc3}\x081\x12%\x1dx\x97\xd4\xbbz\xe7\x87\xf4\xc7\x98\x92+\x0c{\xc1v\x90\xec\n\x0d\xdc7\x8b\xaf\x7f\x88^\x93l\xcd8Y:o\xe8\xb4\xb4\xba\xd5\xccb\x07?=\x0c]\xea\xb8\xb2iX\xed\xd3\x83\x9f,\x8b\x9d\xdeDE\xc2O\x06\x988\x07\x08\xf2\xc7\xb8\x0e\x17\x83\x94&\xa9\x13\xa3\xa8][\xda\x94,\x81'o\x01g\xe1\xc7I\x9a7\xe8J \x94\xc6\xc0zI\x84\xeef\x90\x92\xe5{\xb2\xc6\xcb[9\xe2\xc7\xe9%\x8d)\x9a\xbb\xc1:\xa6\xd7~\x94%\xc1\x1d\xcc\xa9\x17\x90\x98\xce!\xc9\x16\x0b\xff\x16\xa9b\xf71\xf4 \x86\x1e<\xee*\xc3x\xec\xf6\xe1\x9c\x0f92\x0fy\x1dS\xd6\x8c\x93P/\n\xe7-\xc6,\x07;\x8dg\xb6xr::\xfa\xd1b'\x89\xb7\x0cy>\xb5\xf2\xba\xa2f\x10^\xe8QA\x18\x93Ib+\xdcH\x11q\x8c\xd1\x81\xf1(\x89\xb8\x83\xad\x8fw\xbfB\xed\x06\x11\xbc\x00\x9f\xfd\xe9\xed\xc3\xc8\x15<\x83C\xb0\x8e'\x8e\xb4\x03\x06PW\xf0~/\xf6y|8\x82|\xcfh\xb4=\x1a\x8d\n`\xd3\xdb5\xf5\xd8\x9e\xb8&\x81?\x87\xbf\x9c\x1c\x1f\x15\x11\x0cuv\x8bhp\xb5\xe2\xab\x96)4\x84-E\x92\xc6\x94\xac\xd0\x16\x89\xf8a\x02a\x14n\xacc?\xe4[=o6\xd1\xb6+n=\xd8\xbc2\xd3\x9ai\x96\xecu\xb1d5\x87M\xbc\x7f\xe1\xeb\xd5\x87\xa0\xdc'B8\x1e\xf8 \x17\xfd\x9cP\xc1@\xa1\xaaY\xd1xIaE\xd6k?\\&\xcf\x11\xdb\xc4\xdd\xd6\x1c\x92(\x8b=*.9\xd8&P\xc9\x1aC\xc3\x8c\xaf\x1e\x13\x16\x1d\xc58\xf6\x8a\xdea\xa2\xb7|A3x\x01\x01\xfb\xc3\x17\x14\x9dd\xa6\xd9,\xdf{)\xda&`r!\x1e\x95 \x9c\x12\xb6\xeb\xf9\x0fU#\xae\x03\xcf;\x05\xa3\xd5t\xaa:P\x05}\xf0\xeax\xcd\xb0\x90\xb3MN\xa4\x9e2y\xc4\x11\xf8\x07\xe6\x83N\xc9r|GV\xc1 \x8a\x97\xfd\xcd\xe1ps\x8c\xf0\x13\xa6\xf3u4gm\xf3\xf4\xd2~\xc2\x99\"\xdf\x96\x958\xe0\xe0\xf4\xf0BL\xc2.\x80\x17\xe0\xb1?\x1cv\x12\x17\xfci0\xd3\x9b\xe4!\xf6\xe6\xd5\xeau\xf09\x1d\xfc\x91\xf0\xbb\x95$\x8f\x82\xcc T\xa7X\x13^\xe0p\xbe\x08\xd8\x1e\xc3\x0c_5\xd6i\x1f2\xfe\xa4`\xb0\xca|\x01\x9dK\x14\x83+z\x87!M\xd2i\x84\x17\x7f\xf9\xadM8\x8dfZ\x01(\xb5.\xfe\xa7V\xb2\x94\x102D\x8aMN\xa3\x14JR\x8c\x1c\xf32\x15?{=&Vl d\x98\x80\xa3>\xea\xe7\xa2\xa6\xb5E\xce\xcb\x15\xaf1\x1e\x9d\x83\x87\x00\x02\x16\x9d\x9e\xd8\xf6\x92\x84\x8aSx|\xd6\xc3\xe4C\ng\x8a\x13\x90\x8dY!\xf37\xd3\xd9]J\xc69\x94\x19\xfflSx.\xb2~GZchqyr\xe8D\xees\xd7\xd4Z\xaf\xa7\xb6\xa7\xdd)\xb8\xdb\xb6\xb8he\x08\xf0?\x8f,\x979mz\xd6\xbe\xfc\x19n.}\xc62\x8c\x86\x05#7\xda*\xbe\x8bb\xc3\xb8;7x\x14\xe12\xd6k t>a\xf2\x90f@\xf7!fx\xc5\xd7\xfbm8\xe7\xe6\xcd\xc3\xe7R\x90e\x0b\xa0>d\x95\x1f<\xed\xcf\xba]\xb6!8\xf4b\xba1G\\e$/\xf8c\xcel\xce\xe9\xc2\xf7|V\xec\xe3S\xe4\xfe\x91k\xb3b\xe5\x1b\xc3~\xed\x8bD\xb3r\xc8ZR\xd0q\xb6wpl\xa6\x8d,2\xe7n\xefr[\x01\x0c\xfd$\x84\x96z]\xe81\x82\xdaTe\x93\x13\xc1\x90m\xc5\xad\xbe\x80MC\xff\x9d['u\x1bd\xc8\xbfke\xc0QNjTf\x81\xeb.R\xcc\xda\xcfc\xce\x15\xcf\xe2AL\xd7\x94\xa4N\xf7\x0c\xcdd`\xa3\x94(K\xd7\xf5\x8f\xda\xae\xafE\\A\x89Q)\xd1X\xe2\xf9\xdck2\xf4.\xaby\xb3A\xa8\xa5u\x99Q2M\xae\x11\xeetQ\x08\x95\xbcM1=\xfe\x831\xb8\xf2;;,\x88\x90 \xda\x11+lk\x9b\x93\x13\xfc~\xebX_Dtp5\x97\xbe\x92\xb9\xed\x0c\xfbP\xa6\xffHbY\xf1\xc6\xc8\xad\xef\x96}\x06c\x99\xbb*\x0b\x82v\xa3\xafu\x9f{.\xf0\x0d\xc2O\xdf\xdf\x04q_\xf0<\x1e\x1d\xcc\xce\xc2\xbb\x92\xc8\xe1\x96\xc7\xd7\xa6\xf3~q\xd8#-\xc8\x8f{1\xa5\x97\"^\x8c\x00\xb0+\xce\xb1\x0b2W\x89\x00\x93Z\x08$\xf4o\x19\x0d=\n4Lcm\x94\x80|b\x15\"\x93ji\xa9$\x01\x9dL\xe0\x08\x13\x9c\xd0W'\xc7\x1dd'\xe8\xe0\xca\x0f\xd1\xaaG\x8e\xa0\xdb/6\xd3>\xe3\x0c\x9b\x18\xca_\xcd4*g1\xf95\xbev\x07T1\x9dMq\x8b\x9f&N\xf3\x11P\xd8\x0f\xe8\xdaQ6\x0c\x9b\xbfI\x03C\x84X\xc9\xafv\x18U\xde\x15\x1cP\x9b\xd3\x82\xf1@\xc8\xcfw\xcc\xdcA\xe5\x851lq.)b\xef\x12%\x01g\xb7\xd3\xe9\xb6o\x85\xbf\xd1\xedC\x99\xd11\x98<\x1b\xd9\x816\xdd\xd5^\xcc\xd9\x00\x85\x0b\xd8\xdd4\x1e\xfd\n\xe5(lF\xd8\xecc\x9d \\\xdaem\x86W\xb0\x89Y\x98K\xb04\x9cK\x9d\x80\x10Do\xfc\xf4\xd2\x0f\x81\xc05\x8d/H\xea\xaf\xd8\xcaW\x15<\xa6p \x82sS\xe6\xdb\xb9\xe5\\\\\xbe\x9al\xaf\x11\x98H \x98,\xa5\xceC\x08\x90B\x10\x06z\xeb\x05d\xc5\x11pE\xe2\xab\xa4\x9b\xa7k\xae\xc0\x82\x1dP%\xf1\xa1\x87\xc9\xed\x84bG\x95QCR\xd1\xe9T\xfaL2\xef\xb2$r\xcb\xcc\xe5U\xf4\xe1\xa4\xbd\x1d\xdc\xeb\x0b\xdd\xbc\x9ew\xb9R\xaa\xd0\x15\x18!\xb5\x08\xa2\x1bF.\xd9v\x8d\xe2\xd2\xf8\xcb\xab\xa6#\x7fx\x90u\xce\xf5\xfd1x5\xc0h\x8c\xf6\x1b\xb1\xcb\x03KH\"\x1a\xc3\xb8\xae\x06\x0b]\xa5F\xaep\ng\xa8\xe6\x1a\xb3]*N\x89\xa2\x16+\x93Ou\x8f\xeb\xf2\xb3\xac\xcf\xb5mY\x98k\xd6\x94UG\xcdZ\x88\x9a\xb5\xc7\x98\xda\xdeJ\xbc\x7f6\x13o\x0dY~\xca\xc9r\xf8\x15d\xd9\xcc\xc8\xe8Is\x08\xa2\x86J\x9e\x0d\x03(af\x15\xab\xe5\xc6\x0d\xc5\xc6\xe5\xa2f\xe7\xc4 \xd9\x0en\xd3\xa2\xf6\x84U\xb6M\xae\x03)\xf6cy\na4\xa7\xb0\xca\x92\x02\xdfH\n\x01%I\x8a\xaa{E\xcbV:\xa6\xed\xbb\xa9a\x81\x7fS\xb4a\x9as\x01\xddqQ\x1b\xb6\xea\xc3\xb2\x0fw}\xb8\xe8\xc3y\x1f\xae\xf8e\x94\xe6\xd0~o8\xcc\xff0\x1c\xe6\xcab\x07~\x92\xd2\x90\xe6\xb2\x12\xff\xe5t\xa35\x0d1\xbfx?\xc7~~}\xa3@A\x16\x08~E\xfe\xcc9\x15^\x80jO\xd8Gc\x88u\xc1\x97-\xf8W\x11q\xad\xca\x88:\xefs~\xb5\xcc\xbe\xc1\x84\x03\x01\xd3_\xa9B\xa6\x90:\xf0\xba\xae\xfa\xf0\x85P\x84\x9d\xa2\xf1\xa5\x8b\x17\x1e\xec\x85\xd3\xfa\x19*N\x14\xe4\xa0\xee\xefq3>w\xcb\xc3\x9b\x14\xa3[q~\xec\xbb\x0c\x12\xc6\xd8\xbcn\xfdV \x832\xbfg\x83\xf4\xf3\x1b\x9cS\xf6`-6\x15\x93\xfa\xce1\"w\x0et/'i\x98\n\x80\x1d+}\xb8*\x1f5\xa5{\xc4\x1cR0\x01\xde+\xca^W\x08\x9c\x87\xdc\xb1\xf4\x0b%ob\x96\xce@X\xee\x98%4\xf6YXBr\xcf-\xcf.%Nj\x9f^[\x9f\xae\xacO\x97\x86\x0d\x08\xc2\x8eF\x97\xa7\xf2\x0b\xe4\xc7\x85PY\xb7\x93\x1f3\xa3\xe7\xbf\xf4Vn\x16'\xfbB`\xe6B\x1b\xa9\xf0\xb4\xbb\\(@\x81f\xe7\xa9\xf8~\x7f\xcfhyl\xb5\x84F\xad\x13\xd2\xc1\xb0\x0f^.\x02\x1auP\xea{\x8a\x80\xd7\xe8F\x880n\x03\xb1C'c\xfb\xdcP\xb5\x81\xbfR?l\x84;\xdc\xde\"s\xe1\xd6\xd4y\x85S\xce9F\xc2X\xf8\x94&k\xe2)\xa7\x8f\xaa[\x05td@\x0e\xfa\x8a\xdemp\xd3\xea\x84\xae \xf7\xf0\xc8\xd9\xe9\x8b \xf2\xae\xa4\xd6\x9a\x1d_(l9x\xd7\xb0\xe8\xc3\xbc\x0f\x97}\xb8\xe6w\x05n\x1f\xf7\xc6\xb5\xa0\xd2\xa2\xe8N\x109\x81\xdc\xc8|\xb2\xbf\x97\xf9\xfe\xc57$\xc1\xb7\xc3\xa5e\xf2+\xa6\x04\x88\x97vF\xe9\xba\x91Q2\xe5'a\x80\x17\xe6\xa0\xce\xba\x19\x17\xf8\x9d\xd8\xb3\xad\xbe\xd0\x83sM\xac.P\xbd\x85\xf2\xb1>G\x9b\x9caX\x1beQ\xf9a\x1d\x8e6wD\x8fC\xde\xe3?\xda8\xf4|\x01[\x15\xbb}0\x80\xa1|\xf2\x0b\xfc_[\x19\xab|\xab\xb1\xbd\xda\x06\xbc\xe2\xbe\xb0.\xbe\xf2\x9b4\x8e\xbb\x97%\xdc\xbdVp\x97\xd1\xdb\x1c\x7falR\x1b\xc7\xe6\xc3d^\xf0\x1f\x9c>\x82\x17\xadV\x04.hzC\xa9P\xf8xQ\x10P.\xc0R\xeeD\xc8H\xa3\xc7\xb6\x95H~\xc9\xc5=\x1f\xef\xd99\x9a\x88\x13a\x0dm//@F*%\xf6\xeb\x8a\xd4\xcdU\x0e\xe5\xeb\x84@\xb9N\xf0\n>%Q(h\xa9\x19\xe3\xc2\x97\x05z\x02\xf9\xe5H!\\ \x8ew\x8d\xe4Xj\x9b\xdb\xe0Qe\x04\xba\xb1/\xca$\x9f\xad1\xd2\xb8\x18\xe9\xbc\x874d\xc1]\x81'\x10\xf3{\x13\xac\xc0\x17A\xa9\xc3*\x89\nI\xb5ga\x1e\xde\nI'\xe0\xcc\x1f0G\xd6-\xd6\x1f\xb5\xd8\xb3\x0fQ\x13W\x90\xb1\xaasd-\x9d\xb3\xd1\xa2\xee\x83 \xd9<\xfdn[R]\x15T\xe7f!\xd5$\xf0y\x96g\x0b\x0c\x8a\xab}\xb4\x86Z\xfe9\xf9\xd1\xe9\x01 \xa7\xa9b\x11I\xf3\"\xba\x82\x87\x7f0\xe1\x16\xb7\x08\xa4\x15\xddntP\x04I\xa6\x95\xab.\x8f\x04$.S\xacnW\x12\\b\xf0deC\xdb\xde\xb2N\xbf.h\x89\x1bU\xe22\xfc\xdcg\xe4k\x82+-\x1a\"\xc8\x7f\x8d1\x80\x17\xc7K~=\xcd\x99\x1b\xef2Z!w\xb3B\x86\x92q-\xfe\xc2\xd7[\xe1A\xb3\xd8\x83b\x80\x83\xc4\x83\xbbI\xa0\xbc\xc8\x93ne\xb9\xb3D&\x9d%6F\xbfF\xf1`\xdf\x18\x11\xbe\x8e5\x0c^\x87\x0e1\xea\x16\xac\xe65m0D?\x0ey\xaf\x86]\x9b\xf9\xfe-\x89Y\xc6!X\xc7\x07_3FP\xc7\xd9\xb9q\x88r\xcf\xad\x19\x90aC*\x1b\xce0P\xc5\x1a\xa8j\xe4\xd37\x8d\xbe\x9d\xf2\xc4\xe9x5Y\xe9\x05;\xe4\x1e=\x92\xd6CDc=\xd4\x06b\xe6%\xebxP5{x \x0bdC\x169{\xc1\x1f\xb8}\xb8A\xd4[\xf7z_\xbc\xd9\xeb\xb3\xb3\xe3C\x82\xf3\xbe\xae\x98\xd3TLf\x02\xf4A\xe9\xc1\x1a\xc6\x8c\xb5\x1e\x8b\xb70\xc4\x88\xcc\xf1\xa8\xd8\xe2\x9c\x85M)\x0f\xecA\xed\xcd\xaa\x0fa\x11=\x01\xb6Q\x18\xc7\xb0\xca\xd9\xb8\x96\x83\xe7Zo\xf9\xe6\xc8\xfa\xe6Z\xf0\x8ccA\xed\xd60\xd1M\x17\x90\xee\xd8\xdaix^\x1e!\xb7\x16\xee\x0c%\xe9\xea\x8b\x83\xbbj\xfe\x05\xd5M\xf8\xdc\xfd\n\\e\x9f\x8fB_\xaaj`;\xa3\xb6\xa4\xd3(@W\x8ek\xc9A=P\xbc\xd53'[\xcf\xbe\xfez\x12\xdar\x0bUi!\xc6\xec\xbd\xfb\x9a\x0b\xc76\xe3\xb1\xb0\x1c[\xdc\xa0\xdf\x9a\xf2\x82\xd5\xfb(8\xf6\xd2\x821\xee\xbe\x01,e\x9e\xa5\x00\x8cE\x17\x18\x97\xe6Y\x85D\x19\n\x863\x0e\xa9\xd7\x8d\x83\xb7\xe6\xf9\xd0#1b4\xf6\xe3\xb2\xc3H\x88_u\xf0\xf2}\x94Kt\xfb\xfb\xfb%\xc3\xdfG\x8f\xb8\xf1\xe4\xc4\xca\xefK\x1f\x9f\x82\xe3O\xfcp\x19P\xf8[\x16\xb1\xaab\xedEBJ\xf3,5\x1b\xe9!b\x86\xbe\xd3o\xb1ST\x01\xc3\xb0k\xb69z\xb4P\xd3}\xfb]\x13\xa29\x85v\xd7\xb4\x18\x8fU3\"|W\xb3|\xd0Z\x8a6t\xabC2!>\xaa\xb16e\x9b-\xf6\xa2\xae\xab\x9bvW4\xae\x8a\xfd\xe6}\x98\xeb53\xee/\xca\x90\xfex\x9a\xcd\xdc\xd2\x01\xf3\x01}G\xd4I\xb6h\x11%\x9c\xd1\xa60\x83\xc3`\x93l/m\xa2+\xf1^.\xcal\xc3\x18\x9e\xee\xe4?\x99\xd80t\xe1%\xfb\xaf\xc5]Y\xc4/\xb4}n\xb4\x1d\xb1\xf7\x9eC\xb4\xb1\xe1b\xef\xaf\xda\xc2\x8a )0\xc1f\x1c\x1f^\xbc\x80m\x17z@r\x91*\xdf\x81\x97\xf4\x96\xcc\xa9\xe7\xafH`wiR?*(\x0f\x1c\xbf\x82/f\xbe\x85\xc3RR\x81\xab0\xba \x81&\x1eY\xd3\xdc\xd8\xd3\xd6u}g\xd8)iVPR\xbe\xf5M\x94\xb4\xde\xf0w\xa2\xa4\xf3(\xbbhCI+\x83i\xc1K<\x84\xb4\xeaG\xa1%\xad\x8a\x1aG\xc95o\x0e\xbd\xc6!\xad\xa7\xaa\xdb\\\x87\xd1|\xf1\xdd\x86\xaa\x1a\x1aie\xee\xc4M\xe0n\x85\xf5[\xe7\xc4\x89\x19\xd9l\xd3b}0\x0f2y\n|\x92<\xc8\xe2Ic\xfc\xd8/\x9b:)*\xf5J8\x16\xd5\x10\xf2q\x16\xe6j\x80\xb9\x18G\xc5(N9\x93T5}8\xab\xde]\xd5\xd9U\x86&_j\x8a\x82ZWO\xea[\xd9IiV\xce\x99/\xba\x19z\xdd:^3b1\x88\x9c8\x1ew\xfb\xe4D\x1a\x85\xde\xad\xa7\xc5\xf7\xedM\xa5|\xab\xf8.\x15}\xf8cW\xad\xf4L\xf9\xae\xd4\xd9\xdaS\xea+\xe5\xcfx\xa8\x07\xcf\x8a\xe5x\xe2\xec*\xdd\x0b\xb5\x99\xc7u\xf4\xb7\xcd\xdbHHg\xf7\xf7\xdc\xbe\x8f\xa1y\x8b\x8d\xd5\xcc\xaeD\xe8K^fw\x85\xd5\xba\xd8`\x9e\x95\x0b\x11\xd6\x19\xd6Dp|A\xbfh\x8a\x16\xe1YI\xaf\xb8\xb5\xd3v\x10\xf6\x01\xa0\xafL\x8b>\x9b\xb4\x12\x8dGM1G\xafY\xfb\xc8\xda\xbc\xc1\x8a\xcdV\x10Y\xaef\x91\xd74\x8a\xf1Y\x90\x17p\x95\x89rrn\x8cjw\xd4\xfb\xf6\x04o\xf2C\x14\xf9\xfd\x8b\xb5U\xe2#S:X+\xda\x839\xab\xc0\xe7\xfe\x1f\xdcx\x80\xd1'u%\xc4\xfduI\xe7\x16|{=\x8e\xbe\x14/\xc08/\xc3\xe9gg$y\x191\xde\x0d\xc8\\\xdb\xe6t\xfbp((\x9fS\xae!\x0c\xcd\x0c\xcb\xd1\xe0\xf2`:\x11\xabC\xedtr2\xc2]\x82\x05\x99Y\x94\xe8\xcb\xba\xaeQ\xe1\xacH_ZQr\xf2\xf7\x87@\xa1\xdc\xd1:\xf7f\xc9\x8d\x0d\xba\x93.\xea\xa6,u\x95\x12q\xb3[\xd8\x81\x15gur\x19e\xc1\x1cmu.\xc95\x05\x12\xdeI\xcbk\xbc\x84\x95\xfe\xde\xad\xaf\xbb\xf3{\xc5Buv\x9a\xcf\n\x8d<\x85\x8dg\xa5i1\xean\xa7[\x14\xe8\x9d\xcd\xba\x93n1S\xab&y\xc9ugw|\xed\x85\x11\xd2\xe9\xdd:OZ\xf7\x1c\x96\xf0\x02\xee\xd8\x1f\xf4\x1f\xb7\xd2\x1c\xe7\xa2\xde\xcet9s\x072\xe0\xbb2u;\x9dPp\xe2b\x90'lW]\xd3\xe4:_\xf0\x1b\xe6/\\\x82o\xbb\x7f\x05\xb1/\xb1t\xe7\xb6`T\x0b\x86N\x19\x13\xbfw\x16\xc7\xdb\x91\xf0\xf0;\x9a\x863\xa9cc\xf4\xf4\x0f\xa1q\xe0\xf44W\x82\x15hZ\xd2<\xfc\xc9\xdcy\x99\x1e\x0c\x15\xd1H\xec\xf7\xc2=\xdfN(\xdaV\xe4\xf1\x1c\xdaW\xdet\xcb\x11]D\x84\x07u\xdc\x0c D\xb3W\x13T\xd0\xadH\\\x8b\xdb\xf2[\xc1\xd3\x8bi\xa2\x9d\xc6Z1N+\x03\xa6N\xa4\x1f=\x82%w\xf0,\xaf\xbd_^{\xc8Cq\x84Q\xb8qp\xf2\xea\xed[%\x9eL\x02$\xa6\xe0\x87)\x8d\xd71E\xc7\x87\x04\xc5\xad<\xe8\x9c\\\xda\xa4\x166\xa0\x85<;\x81\xed\xddf \xbb\x82\x15h\x80\xb0RA\xf1\xa4\xdeP\xa9d]\x1f\x1a\xc5\xa8\x0b\x15\xe8Yxp\x94\xd6\xc3z\x18\xff\xd5\xd1Fa,bAQqv\xa0\xcc\xc3\xce\xc8\xa1\xe4\x17\xf2\xb8v2d\x0c-\x03\xa0\x98\x02\x82@\xc4\x92\xb1Wrhn^\xd0\x87\xdd\x9d\xcd=\x11+U}i(k\xb2r\x8e\x15#\xb7J\xfb\xaeE\xde\xe9\x90\xde4\xdf\xaca\xe6 \\B\xc0DL\xf8[F\xcfds/~\x08\x96G\xd4Id\\\xf6T~\xbd\xbfg27>,\x02Y\xb2\xe7\xc5\xafr\x13\x9c\x13\xc1*\xe2\xeb\xfd=W\xeb\xb3\xa7\x18\xa0\x8a=\x93\x91\xaa\xf2'9\xbb\x86o\xca\x1f\xe5\xb6KB\x8cL\xc2\xcd\x07\x8a\x81\xc0\xfd\x80\xce\xdf\x8a:2\x97 \xe7\xdf\x0d\x95O\xf9\xd3|\xe8\xb8v\x052\x88rE\x171\xccG\x8b\xea\x08\xf5\xa7\xd4H\xa8e\xaa!\x10O\xf7,\xf7'\xf2\x17eB\xcb\x97S\xc3\x04\x86b-\x11\x93\x86\xdd\xaev\xe5\x97s\x93t\xf2\xdc$EZ\x12_3#%$V\x11\x82-\x86\x17\x10\xb1?<\x04[\xea\xf8\xd3xf\xa7-?i7\x9c\xdc\x99\x7f\xd5\xad\x1f\x1b\xb1p\xe8\x96\xd9P4\xfb\x95\xd5\x1a\x89%\x95\xb5$X\xa7C\x8dOA\x91\xc9!r\x8a\x8b\xc3\xfc\x86>\xa7\xa0~\xa8P\xd7>\\d),\xa2\x8c\x9drQL\x1f\x94\xc9\xa1He\xf0K\xbf\x9e\xfa\xe0\xa7\xbe1kA\xd3-D\x8b5E\x94\x89\x07\xf46\xa5\xe1\xdc\xa9\x83\x8fo\xea1\x90\xf2|Xg\x95\xe5\x90\xc8\xf7\x85\x8d\xfdI\xf9\xa9M\xe3`\xa5\xccb6?}\xe9l\xea\xf1\x81\xbf>c\x81.\x98h\xe4\x94B/V\xa7\x81tL\x1c$\xf2l\xb9\xc8\x16\x0bN\xba\xeb$3,\x93\xccX\xfc\xf4\xa2 [\x85\xa5@\xa7\x05\xde))\xd8\x07K\x9a\x9e\x84\xfezM\xd3&\x00\xd7\xcc\xd5\xeb{\xb1\xa3\x0c\xd7U\x95\x06:\xd9\x1bD\x00\xf8m\x85c\xd8\xdb\x11\x11p\xc4\xadKi\xb6\xc2:\x80\x1d\xe7\x1b|?w\xcf\x86g\xf1Y\xf8\x7f\xfe\xb7\x9aU\xa0;\xf0\xc39\xbd=^8\xcah\x90\x8a\x1f\xa4N\xc4\xef/\x0c!\xab\"\xd8@2^\x06\xf2\x06\xf6\x9b\xc2\x13\xd8\xe4\x9c\x87^X\xc3q\xc3`0\x00\x1c|o\x1fv\xf4RJ\x1bw3\x04\x91/ A\xea\x90 \xf0B\xc5\x0d\x85\xbd\xfab\xd0\x10#X\x1c\"\xc8\xf8F\x052-\xa0\xe2\xabP!\x0c\xbe_\x01\x15\x81Q\x99\x84\x87\x98\x00\xe7\xea\"\xee\x8aX\x98R\x02\xaa\xa1\x84\xe4\x95\xa1\x01x\x8f\x07\xcc\xefUkAO\xb3\xe6=\xe5\xbc\xe8A\xf7\xf7\xaeJ\xa0\xd4=\x94F\x9c\xfb\xb5\xe6\xe6UB\xf6u\xbb\xda3\xbe\xd8\xfa\x8caE\x0e\xe2\xb1\x1fr\xe1\xb1x\x86\xd1\x92\x1f\xe3U9\xe3XH\xca%\x186)\xa7\xa0\x04(\xd7\xf5\xd8\xdc\x04%(\x9e\x8b\x02~\x05\x82;\x10\x85r|VP\x03G\xa8\xa8x/c\x0e5\xd4]j\xc9tNi\xbe\x92h\x8ev\x953Em\x9d\x9d\xc6\xb1\xa3 \x87\x93\xa4q\xb7_\x81\xf5\x95\x1f\xce\xc7\xc5}n\xe9Y\xae\x90\x1d7\x98w\xd4t\x9e\x98D\xa2\x94\x8b\x00\xca\x07\xbb\xfb/\x82\x00\xfd\x9b\x11\x02\xb9c\xde\xb7\x85A\x95\xb9\xfe\x97\xc3`E\xd6&\x18\xe4\x8e\xb6\xdf\x16\x04\x15\xd7\xd0\x7f=\x08\xd8\x08\x1f\xb4\x13\xc4\xedA\x13\x00|\x19\xbe\x07Ek\xabm\xf0u\x9e\x8cR\xc8\x01&h\xca\x98\x9d\x8f\x1eA\xf7\x7f\xc4\xcd\x1d\xf2\x02E\xb9\xd3\xc5 \x15\xcf\xbaG\xd5\xdf\x9f\xde\xbd\x13\xbf+\xbcv\xf3R7\xac\xb4\xad\xb9uL1\x10Y#\xe0T\xcc\xc1Q\xdaZ\x8d\xe9:\xa6 \x0d\xd3\xb1\xa6%\x8f\x84Q\xe8{$h\x98\x01\x14\xbdv\xffG\x93J\xb3~5\x12D74\xf6HB\x1f\xd02\xaeK\x9b\xc6\xb3\xf5\xfa\xc1\x8d\xe3\xa2\xb6i\xdc#+\x1a<\xb4q\xfd\xc8m\xeb2\xa7\x0b\x92\x05\xe9Iz\x17\xd01tsxu\xff\xe5\xfb\xfd\"\x8a\xfe\xa9\xfb]c?\xd5z\xbf\x97\xf6u\x1agT\xdd\xc7\xa7\xd5\xdf\x1f?\x1d\xca}\xcd\nv\xd4\x97\x17$HJ\xb5\xdf\xd4\n\x0e\xde\x9d\x1c~)]\xb0m\xe4\x87\x0c\xfc[\x12\x90\xeeT\xa4\x13\xf81\x8a\x02J\xc2\x19\xef\xa3\x96\x9cN\xb2\xa12\x03\xed\x17\x93\x1b\x1dQ0&\xc8\x95\xf6\xa00\x91\x00\x1a\x83X\xa56\xdbXG#Z\xf5\xc5\x81=\x96\xeb\xdd\xa6/\x1d\xc9h\xd7\x97\x9c\xd7\x1b\xc3\xbc\xfe\x1d(\x88)C\xe2\xee\x03\x93\x9c\xd6\xb2\xa7\xed\x14\x03\xd54D\xda7\xb4\xa74$\xbfUI]\xa4#u~\x98\xfe;P:\xae\xb4Q5\xd8Z\xcc\x89\xccn\xf5\xba\xa8\xde \x95'q\xa3ylw\x83\x1bB\xf1[\xd4i4C\x19\xad\xdb\x13y\xdesY\x8eN{\xbdh\xe6\xf6\xa1;\x14\x99\xfe\x8d\xe29j=z\x82!\x8b\x1b=\xbfp\x14\x17\xbcQ\xb5+S\xfb\x90\xbby\xf4z\xa4\x9fb\xe6\xb7\x959\x8ev\xddA\x1a}b\x02\xe9+\x92PG@\xa2\xb1\x9a\x0526\x1c\xab\xc8\x85b*\x15I&aO\x0f\x02\x9f$4\xb1\xe1\xe2t\xb3\x0f\xdd\x0b?\xecjR \xe4\x98>\xedC7\xf2R]\x95\x1c\x8e\xd3\xd1\x10\x13Uy\xbaZ%\x88OG\xbb}\xe8^\xd2\xdb\xee\xf7\xbd\x0b0\x8b\xb5\xe5b_\x08\x90\x1f\xe9\xf2\xf0v\xedt\x7fw&\xe3\xe9Fo6q&\xe3\xe1\xfdt\xb4\xf1l\xc6\x8e\xd8\xf3\xd9\x0f\xae3\x19\x9f\x9d\x0d\xe4/VaJ\x0fgXY\xa4\xc4\x9d\xdc\xe7\x15z\xda\xc7\xc5/\xd1\x8c3\x19\x97\x0f\xf2\xa2\x07^\xf9\xecl\xe0L\xc6~\xb8\xb8\x7f\xcb\xfe\x1d\xbdq\xefyQH\xc2\xfb#rt\x7ftp\xe4\xba\x7fV-\xef1.?&\xedU:\xa7O\xcczB\xad\xf0\xbc\x08\"\xf2]\xc4gU\xbf\xcdoF\x18\xa5u:\xbe\xe0`\\\x95\xf9\xa1S\xd5zo\xf6\xcdy\x1am@\x189B\xd8\x07\xc9G\x08\x03\xe4\x1a;2H\xa3w\xd1\x8d\xdc\xd2\x8c\x97\x80 ;\xc8\xc7 b\x00Og}\xe8\xf66\x94+tdX^\x8a\x13\x86\xdf\xa1\x16\xccH\x1fX\xcdE\xc1{\x08\x0b$\x98\x88\xc3l\xf0\xe1\xf8\xe4\xed\xe9\xdb_\x0f\xcf\xdf\x1e\xbdy{\xf4\xf6\xf4\xaf0\x96\x8f\x8e\x0e\x7f:\xa8>\xea\x0eB\x12\x16\xcd\x1d\x91#\x18CZf1\x04is\xd2/\xe33\xa22\x9f\xf1\x86!\x8e\x95\xd3\x10\xb6w1\xe74\xa2\x07t\x95JN#f\xaf\x9b9\x8d\x10~`|\xf3\x18\xbf(\xa3J\xff\x9dx\x0d\x873\x1b\x9d}\xee\x8d\xa1\xe15\xda2\x1b%Bi\xc2\xf8P\xaf\x1c\xf2\x93#r\xc4\xfa\x82\xe4\xc6O\xbdKp\x8c\xca\x03\x8f$T\xd5D\x8e\xb5\xb5@\x01\x0e\"\x9f^<\xe2\x8d\xe5z\xdc6\x8d\x1d\x1d\x1cY\x1b\xcb\x15\xb5\xad\x1a#G\x1a\x8dl\xe1\xf8l\xdcnB\xeb\xf7=\xa0\xc5v\xfe7\x83\xd6\xdb\xa37\xdf\x0eZo\xc3E\x1bh\xd5)\xd0\xf7\x83\xd6\xc67\x05\xd7\xc67\x85\xd7F#\xc0t\xbb\xbdx}8\x18j\xc6\xa2\x9cKe\xbe\xb7\x0f$\xcf\xe95\x810?\xa6\xba\xb4\xcb\x0e\x14\x1e\x083\xb4\x11\x93\x7f\xd6mC\x8d\xff\x8aj\xfcW\xce\x1e)\xff\xb9\x1b\x8e\xe9\xc7\x9f\xbb\x8d\x1c]c\x8b\x93\xca/\xc6\xbb\x9d\xa6\xb3\xfb)\x9c\x9d\xa5\xb3\x9e[z8V{/\xfd\xe0\x0c\"/\xf9\xc1\xe5\x1c\"\xb6\xf0\x83\xf3\xdf\xf7\x0ec\xc6\xdcj7\xa5\xf7\xdd\x89\xebNJ\xac\\\xab\x1b\xdd\xd4_\xd1$%+\xa3)\xcb7\xe7\xd6\x8a\xb0\xe5\xd1\x80\xdeRO0my\xa9/K\xbf\x03\xbf\xa6\x89\x87b\xb85Y\x0b\xf7L\xfd\xb9\x97\xdf\xe0 \x0b\x96\xcf\xc3\xcd\xb9\xb2b\x12j\x9erW1\xf3>\x8c\xe3(v\xba\xafIJs\x9fZ\xca\xcat\xc1\x99|\x91W\xb4\x97NG3\xce\xfc\xf4\xd2\xe9\xe6\x8c{-\x11\xfesk\xd6\x87N:\xdd\x9e\x15f\xb0\xf4\x06X\x07\x0e\xfbo\xf0\xe9\xf4\x95#\xc0\xa0\xf3\xc3\xf3E\x98\x8a\x1ek\x82G\xa9\xe8\xa5\xd3\x9d\x19\x8fO\xd1K\xa7\xbb\xb3>\xa4\xd3\xbd\x99\x89\n\xa3\xca\x15\x03\xdfN\xf7f\x82+\x1d\xf6a\xcb}\x0e\x8b\xc2\xa7r\xeb\xb9\x0b\x0b4\xf0\xd3Q)l\x87u\xb7\xa8\xd3?\x13z\xa5\xd3g3\x04<[\xb3]\xba\x0d?\x80\xb3;\x84\x1f\x10Z\xc3\x19\xf4\xa0\xe7\xa4\xd3\xd1h\xc6\xd0l(\x95\x80\xb8 \xea\x9b\x1bkW\xc4g0\x82M\xc1\x9e\x85\x8bQ\xd5\x1f=\x02o\x90\xd0\xf4\xd4_Q\xc7\x1b,\xc57\x1760\x88\xa6gCa?LR\x12z\xf4x1\xc6\xeeZph\x96M\xc6\x88\xfa\xdb\x93cA\xd7\x8d\x8e\x00\xdf\x8a\x10?\x90\xcc\xf0\x04\xfc\xdf\x8f\xc4t_\xbcP\xac\"L\xe6O\xdf\x0e\x0c\xc5\xcf4\xbe\xab\x0c\x8b\xc3hg\xdb\x1d\xfc\x88\xb6\xc2E\xaf\xe0\x11dd\xd8L>\x97\x1a\xb4(\x18\xba\x07?\xbez}\xf8\xe6\xa7\x9f\xdf\xfe\xe5\x97w\xef\x8f\x8e?\xfc\xd7\xc7\x93\xd3O\xbf\xfe\xf6\xbf\xfe\xfa\xdf\xe4\xc2\x9b\xd3\xc5\xf2\xd2\xff\xe3*X\x85\xd1\xfaoq\x92f\xd77\xb7w\x7f\x1f\x8e6\xb7\xb6wv\xf7\x9e>\xeb=\xd9?\x0b\xcf\xe2\xee\x03%x\xae\xe4\xf9\x1e+\xf6\xc57\xe0\x06J\x1d5^\x8e3\xfa\xe8\x1b\xae\x88B\x1e\x030\xe4\xbeC\xa1\xed\x9e\xa8\xe3 i'\xb9\xfcK\xa5\x19;\x8f\x06\x08\xbb\xdb\x8d7G)\xbc\x80a\xab\xdb\x1f\xd4\x8b\xefj\x1f\x1b)a\x0c\xff\x01OQ\x01]\xc6\xfb\xaf>:\xa3\xb2\x02cz\x16\x9f\x85\xfb3\xa1\xc60\x03=\xb2.K\x86\x91\x80\xb4\x8f\x12\xf3r\x07\x86;\xa1\xdc\xd3{\xf8\x1c\x18\x94\xc9sH{=\x17R\xf8\x0f4\x05\xe3*\x13~\xa5\x13\x88L\x11\xf0\xf2%\x8cv\xe1\x11l\xee\xec\xb8}P\x8b\x9fVK7wv\xe0\x11$\x8c\xec'\x98\x0e\xe4\xc5\x0b\xd8\x85{\xc8rt\x88$:\xa4\xba\xe3U,\xd1\x10dH\\\x82\x03\xfb\x01v\xf1\x9a\xe6\xab\x86\x04c\x18=\xcdu=\xe5\xb6\x86\xda\xb66E)\xbe*|\x0f\x19h\xd4:\xdb\xf9\x9b1\xa6\xdfX\xc4\xd1*\xff\xe2\x04(\x16 \xbd\xc7\xaf\xdf\xd4~\x15C|0)\x87S\xd0\xf67'm\x11:\xe6n.F\x82b@>\xd2Hk2\x0b\xad1`\xe7V\x05;q\xe7g\xd3\x08\x97\x8f-\xfa\xee\x16\xf2|J\xe9\xa6\xaet\xb7R\xb8\xbb\x05\x8f\x00Mr\xd8\x8c\x9c\x88a\xecS\x17z@\xa7\xa9\xf9R\xb5\x8c\xa0[\xfc\x0e\xf1\x1b\x8f\x08\xc6\xb0Y\xa0k\xa9\x9d\xa1\xae\x9d\xedZ\xe1\x8b\x17P\xedqw\x1b\x1b\x1e\x15\xc8\\j\xb9>\xc0\x17/j\x0d\xefn\x97\xdb\xebC\\F\xbc\xfc\xd7Ws\x10f\x89\xb6\xa6\xff+\x87\x9c\xacs\x08F\x85\xe1\x03\x99\xb4\xc8\xe2\xd1`\xf0\xea\xf8\xca3\xdfd\xcf_\x91\xd7\xb8*\xdcx\x1cP\xdb~\xe3\x97\xd2A\xee%\xccv_\xf8\x9c+\x83\xcd\x1ed\"uh0MgE>\xb0\\]\xcb\x01>\xeb\ny\x15\xd5\xb2q\xb3Q\x87\x88\x89\xe3\x87\x10\xdb\xadx\"\xd1$Jj\x16\x8eB\xd6\xcf\x1a\xbb\x96\x9f/\xb2\xd6A\xe6\xa7\xb9\x0fVM\x98!$\xf9\xa1H\x9a\xc1\"\"[\xb4\xca\xdf\x91#Ny[~!\x83S\xd7O\xfc\xb3\\\x8dZ\xec\xfa/\xdc\xc4k\xe2\xc7\xc9\xbf\xd7.\x16\xbe\xbb\x96\x9dJ\xc4\x8c\x0e\xe2\x98\xdc9\x99t\x81\xcco{\xd8\x16\xce\xbel\x0bg\xb8\x85\xf5[7j\xbdu}\xf4\xe7G\xc3!\x85\xe2^\xd1\xbb\x84\xbd]u\xf17\xb5B\xa6\xe9\x8c\xd12\x7f:d\xe7\x0c\xfe\x9d\xcd\xfe\xe9hoXG\x1dW}]\x0d{&R\xd1\x18\xd6\xd1/\xad#\xd1\xae#1\xad#[-\x82\xab\x15\xd5@\xdc\x07_\xc0.\x12\xb0\x8b\x10vF6\xc6\xff7\xd8\xc1\xe5s\xfb\x81\xfb8\xa1\xc6\x0bt\xbdw\xe1\xf7\xdb\xc4\xd6#\xd6\x0f\xc1\x10\x08L9\xc9\xc2\xbe\xb0D\xccIm8Mg\xd6\xfd\xf2mQ\xdeD\xe9\xff\xed<*\xffH\x9ed\xe1\x9c.\xfc\x90\xce\xbfR\xfbb\x81\xc3\xc3\xa1\xea\xd6\xf2\xcd?T\xa6\xbb\x8e\xfc\xb9\x8c/f\xeb]'\xcd\xd94\x7f\xffn\xae\xd1\x7f$Ob\xba\xa4\xb7\xdf\xe5F\xe5\x01\xca3\x1f\x03\xd5`\xbd6\xe7S\xeeW\xa7\xe7\xb3\x19\x11xr\xf6\xc4\x99.\xfd\xd5\xec\x07\xf7\xcfO\xe4\x05\x87\xbez\xac 9\x00\xd2z\xfa\x89\xd4\xbe\x0f\x8dw \xfc\xc2C\x9a\xf2\x86\xd3\x11\xcab\xf2\x16\xe1%\x93K[\x9c\xd8\xac'4\xeb\x9d\xa6\x85!P\\\xb2 *\x9a\xa9\xb5\xf2\xbd\x8f\xe1\x7f\x0e\xc4\xe56Q\x80\xceo\xe1\xaa\xd0-\x19\x13\xf5\xc1\x001\xbc\xd0*.H\xd3~U\x96\xf9J*\x913j\xbc\x83\xb6&1\x0f%(\xd6\x05a\xb0\xea\x01\x1d$Q\x16{\x14z\xac\xc0\x08X:X\x06\xd1\x05 \xc4\xd5_o\x1f\xbaK\x1e\xb9\xaf\xc8D_\x11\xf5\x9fV\xca3\x9b\xd2\xaf\\5i\xd6.\x94_\x08`\x1f\x9eU\xc8 \xec\xc3\xa8r\xad\xb5\x80}\xd8\xda\xac`\x03+\xdb*\x97\xcdY\xd9v\xb9\xec\x92\x95\xed\x94\xcb\xaeY\xd9^\xb9l\xc5\xca\x9e\x96\xcb\x96\xac\xac2\xbe;\xd8\x87\xed\xcaX.XY\xa5\xdfsVV\xe9\xf7\x06\xf6a\xa7\xd2\xc7!\xec\xc3n\xa5\xbd[VV\x99\xdb +\xab\xf4\xf1\x8a\x81\xaf\xe2\x93x\xc5\xca*\xef\x1e\xb0\xb2\xddr\xd91\xe6/\xacT\xfc\x80\x85\x95^N\xb1\xb02\x95\xf7\xb0\xafA\xfa\xe1\x18\xbaggC\xcdQ\xb4\x87O\x88\xe6\xc9S|r\xa1y\xf2\x0c\x9f\xa4\x9a'#\xdeQ\xa8{4\xc2G\xd7\xbaG\x9b\xf8h\xa1{\xb4\x85\x8f\xaa\x0c\x1d\xfbl\xf2\xa1Wu\xd1\xec\xb3\xb5=\x86\xc7gg\xdd\xc7\x9a\xb1\xf3\xbe\xce\xce\xb4\x9d\xf1\xde\x8et\xcfv\xf9\xd4\xceu\x90\xda\xdc\xe2\xad\xbe\xd3?\xe4\xad~\xa8(\x1a\xcaU\xdf\xb2\xf3\xba{\xd7\xedC\xf7\xaf\xec\xbf;\x9a\xe0w\xf1\xe7\xf0\x84\xfdA\xb6\xb7{\xcc\xff?b\xff\xe3W\xfe-\xc2\xaf\xfc\xffc\xac\xbdX`E\xf1\xe7\xcd\x9b\xeeL\x17U\xe3\x8f:\x9d,\xb4\xb6\x95\xabhn\x82\xb2ou-\xeb\xf3\xc8\x19\x9b;;.\xe7\x85n\xbb<\x80\xeff\xb9\xad\xdc\x1a\x19\xab\xef\xee\xecl\xc9\x172\xf1\xc2\xb6\xe6\x05=\xd7\xde\xe1\x8dlo>\xdb~\xb6\xbb\xb7\xf9l\xc7u\xcb\x11q\xbdhNa\x1d\xf9\xa5\x8c\xb9<\x00\xe2\x8a\xdc\xc9L\x0c\xcb\x98\x92\x94\xc6<\x19\xc3\xf0\xf6\x8d\xf8\xe8X\x07\x1c\xe8'1\xd0\xa7\xe5\x95-\xfd\x92\x87\xde\xd9YW\x84u,\xe28\x0e\xf1\xfd\x8d\\Vv\xa1\xa7\x08p\xba\xc8%G\xf5\xc5R\xa2X\xf3x\xe1y\x98n_\x06\xc9\x961\xa7\xdf\x93\xf4r\xb0\"\xb7\x0e\xa6\x0c\x17\xc5\xf7\xf7\xb0\xe9\xcah\xdfW\xfe\xfamxM\x02\x7f\xce\xdbR~\xab\xa1\xb9\x17At\xf3\x8e^\xd3\x00\x99X?9\x8a\x18L\x97\x0e-\x9e\xb8\xd2\x17I)\x93\xbd\xa4w\x81\x08\xc1]:YMLu=%p\x93Ym\xe1\xdb\xff\x8f\xcf\x06\xcds(\x12\xa2pk\x0d\x9e\x845\xae\xdc\x1b\xa4\xf9\xd5\x0c\x8f\x04\xe0?\xe7ARG\x90\x89\x86X?\xac=\x91\xe4!\x18\xa8>\x97}\xc8xg\x19^\\\xab\x8f\xa6\x19\x1b_8%3\xd8\xaf\x06\xc3\x05E\xcd]\xc6gGA1\x868\xd8b\"\x0d%s\xdc\x89\xe2\xf4\x17z\xc7\xb3\xcf\xe4?\xca\x01\xddC\xfa\x9b?\x97\x01\xd5\xf3_\xf7\xf7\xf0T\x86C\x0f\xa3\x8ft\xc1\xdb\x10_\xd5\x16\xc2\xe8U\xb4Z\x93\xf4=\xdb\xce\xbc\x8eR\xa0\xd6\xf4\"\x86\xdd\xe8zu#@\xa9\x14\xa85\xbf \x84\xbcLOd{\xe5\xf0\xb6\x1cu\x1e\xd3`\x85E\xe4\xfaR\xb6F,\x99g\xec\x0d\x92Ra\xaf\xc0K\xb3\x84\xce_\xabOJ\xb1\xfet4\xe2\xa3v3!\xd2\x8b\xdd\x14\xc1~%\x9al\xea\x8at\xc6\xfc~nc\xc4\xf1\x9a\x8d-Q\x83\xa5\x81\x0f/ y\xeeb\xda\x064`\x97\xd9\xfa\x85K\x1f;\xfb\xc1w\xd1\xec\x87\xfb\x8a\x88\xac\x16\xa2\x83\x04\xb3\xbd\x95\x9e\xb0.ydW\x1f\xad\x86\xf8\xf7P\xd5C\x9c Q0\x14x\xdd\xdb\x87\xc8eC\xec\xedW]\xcb\x04\ngV\x10\xbd\xb6\x85\xe3\xd6\x87\xdb\x95\xe4\xf2\x07H]k\xdb\xef\xea$Z\xca\x1c\x08\xb1\x05\xc3>\xfe\xd5\xbe\x8e\x9f\x8c\x0dmm\x96\xa3T\x8d6wQ~\xdf\x1dU\xc3`m>\xdba\xbf\x18\x87RxP0\x96D\xfc\xba\xbf\x87\x9d\xbd\xad\xed\xed\xf2{\xec0\xdeb\xbfx~\x8a\xbc*+\xdf\xadt=\x1am\x8fF#\xebD\xfef\x9c\x08N\xb1\xd2\x0f\xb6\xcc\xbe^\x14__\x15_\xaf\x8a\xaf\xc7\xc5\xd7\xd3\xe2\xebM\xf1\xf5\xd2:\xac7\xc6a=\xf9\xfd,\xfc\x01dT\x13u\xb9\xe57\xb6\x91\xfe^\x0f<\xf2#cs\xcaE\xbf2Y\xa5\\\xf43\xe3m\xcaE\xbf\x01\x06\x99\xae\x0f\xf2/\xf6\xd0\xebl\x1c\xbej\xe7\xd4\xd1\x84B \x0c\xe5\x0b\xdc\xe9<\xeeG\xfd\xe9{N\x07j\xe5\x8cS\xfd$\x12\x92\x96r\x96TV\x12\x83\xf3t\xde9\xfc0\xca\xb0\xec\xbc\xf8z[|\xbd)\xbe^\x14__\x15_\xaf\x8a\xaf\xc7\xc5\xd7\xd3\xe2\xebe\xf1uU|\xbd+\xbe\xae\x8b\xaf\x1f\x8a\xaf\x87\xc5\xd7e\xf1u^|\xbd.\xbe\x9e\x14_\x0f\xc4\xcc\xcc\x89^49\x1f\xd2\xbaJ(7y\x18r\xba\xaaP\xd9^\xcfv\xb3\xd5\xf9$\xc8\xae\xd2\xbf\xafD\x05\xfaM\xaf\x04f+\xf7\x96\x8d\xfdoZc)\x13\x83\xfd\xc5\xc3\xd4\x0e\x12 \x9f\xe7rd\x1d\xf6a\x01hQ\xcdX\x15\xe4Ya\x03\xde\xe3\xe9\xf2\x92[\xf1vA$\xd2\x9c\xbeg'\xc3\xac\x8f\x88\xe9\x1b\xf4\xdc\xb9P\xc1@\xf4\xb5\x00\xd1n$\x1c%\x0e\xbaq\xa8\x7f2\xb7&\xc6\x85\xdcM\x00\x13\x08\xe1%<\x83\"\xed\xd2o0\xc6\xf2\x9fa\x0c\xbf\xc2\x98\x8f\xb2\x13\xf1\x87\x7f\x871\xfch%m\x7fU\xa8Fu\x85\xe8`\x9e\xadJ\xbc\xb7\xe9.\x84\xdf\xfe\xa6\xd5\xdb\xdf\xee\xe3\xc7\x86\x9b\xd9N\x85!\xe3\xa1\xfd\x19H\xde\x16!\x08\x14W\xd3\xc7\x18\xa0\x1dz\xec\x9b\xfeF\xd9\xcf\xb9\x0b;\xe9\x94\xfc\x17'\xed\xf3$\xc6\xbeH\xdeL\x14\x85\xa3\xd1eY\x80\xb0Q~\x92\x1f)G\xe97\x02\x94\xdcYd\xc0H}\xa6\xd9\x90\x87D\xe3\xd9\x82\xccv\xa8 p\xa2\x9ah6\x9c\xe5\x19H\x15T0\xc5n\x04\xeb\xbd\x0d@\x9e$\xa9\xbe{\x8d\x96\xaf\xe8Q\xfd\xf7F?jM\x06{\x90o\xff\xd8\xf8\xb6\xc0\xed\xc2\xe7\xe51z\xbb<~\xdcuM\xf8\x0e\xb2\xf5_\x9b[\xbfg\xad\xff\xc2\xf3\x04r\xbca\xcd\xfe\xe4|dE\xbe)M\"\xb6\xfess\xeb/\x8d\xad\xb7\xc67(\xcb\xee\xb0\x0fO\x9c\xb3\xb0\xe7:\xd3\xdf\xcf\xc2\xd9\x0f\xee\x93\xa5~W\xa9\x1f\x94\xc9\xb3\x9a|\xe1r\xd9DP\x96\x0c&\x90\xa1\x9aA\xb8U@4\x08H\x92\xbeeo\xf0\xfc\xe0\x7f\xce#\xd3\x0d\xfb\x98\x7f;u\x0d{Z\xfd\xa0\xa8~\x16\xcaP0Ct\xffd$^\xfe6c,\x88\xc9k$l\xf5#b\x0c\xc6\xaa\x0b\xb01\xc1\xa7\xfaam'\xc0\xc3\xbc5O\x04\xc4\xc9\x15O7\x1b\xc6\x0cyJ\x18>\xcb\x00o\x80|\xb6\xd3\x13\xe81Y\x0f\x13\xdc38\x88\n0a_\xc7<\x9f\x1d\xf4\xe0\xcfN\xc0\x85I\xbc\xb5\xb0vf\x8ey \x05*\xfa\xc6J\x9f\x19z\x12\xb7 \xdb\x7fk\xc4\xf6\xc7\x98\xac\xa4\xf9~O~rA\xba\xe0\xca\x85\xa4l\xe4\x91\x84\xce\xb4\xc2\x08\xbd\xe4\x02\xda.\xa0\xe7\x0e\x13\xd7v\xb7F\xc8\x04\xd4\x83\x95\xfa(\x15\xf3wv\xb76\x87PD.\xdd\xda\xdeb\xc26*\xa6\xfepF\xc3Mt`Na\x83\xb7\xce\x93\xc9l\x88\xd7z\\\x86c`c\xbc\xdb\x98\xeb\xbc\xde\x0b\xab\xd9\xde>t\x90\x93\xf9\xe4`Zh:\xf5g0\xe6\xa7\xdc\x1fz\xb74\xf5#\xafSmk\xe6\xf2\x8c\xa2\xfa\x86D \x08\xf3\x92\x95t\xba\xfej\x1d%\x89\x7f\x11\x08\xc7\xf71\xf8BU\xc9\x8d@x \xb2n\x13c\xf7\xd9\xb1\xcb\xf3\xbf\x983K\xc1\xbe\xe4\xd7\xa4\x02\x10\xe3\xafin\x01\xe221)\xc5\x95\xd2\xea/B\xb6\xdfx\x8em\xfd{\x9b\x9c\x1e\xe5\xcf\xd8(\xba\xbd..\x97\xdc\x94\x1b\xfc\xb09\x0b\xbb\xd6\x19\xfed\x14\x84MCf\xb8Q\x90\xd4\x8d\x11\xa6\xf7\xb4\xf6\xf1g-\x14\xd1\x1aAq\xbcV\xc9k\xce\x1bTl\x87UE\x96\xe2CY+:\xae2\x90\x85*\x9d\xc0\x0b\x08\xd8\x1f=\x07\x89\xa2\xa3\xe31)oJf\xee\xa0\x88s\xc0P\xc4\x1b\xe4\xf6\x06\\\xcb\xdd\xf1*5\xba\xdc\xbc\x80aR\x9e9\x90\xd3XY/Z\x80\xfaR\xdeN\xder\xa5#F\xfal\x82.\x95\xea]\x98\x80\x87\xdf\xc7\xd0\x9dt\xfb\xe0\x0dr\xbb\x04\xdb\xb1\xc2\xdaXp\x95\xa8\xb8\x1a\x99b33>\x0e5>N\xdfh>\x91\xf1\xbb\x00\xb5K\xee\x13\xa1\x94\xb03sa\xa1\xe2\x06\x0d\x80\xfaA9/\xa9\xf5\x85\x11-\xca\xf4\x99'\xe8\xf7D\x82\xfe\xc7/1k\xbf\xe0\xfdc \x9eG\xd7i\x82Wo\xfc\x04\xe6i\xc2\x10\x02\x8f\x9bN\x9a\xf2\xb4\xa6\x8b\x19\x9f\x99\xf9\xe41OY\x8a\xc3\xb1\xb6\x8a5\xfe\xb4\xc6&K+\xe6w\xec\xfa\xd1\xffU\xd2\xf1\xf1M_\x95\xd9\xd5\xfb\x83|\xc8a\x9fo\xe5\xb0\x0f\x9d\x11F\xc1\xc9\x7f\x0e5\xd9\x82\x13\xc8\xb1\x847Q\xcd\xdb\x9a\x13?U\xa4}\xc1#\xc4\x95\xa5\xdcjVS\xd6|\xd0\x87E\x1f\xed?\xea\xdeR\x0cAQ\xd9\x91?B\x17\x1f\xf9\xa4\xae.C\x85\x9d\xa3h(\xc5\x8dXqI\x92\xcb\x04\xa1\x8b7f\x85o\x06\x02\xeb\xd1#\xb6\x05\x95\x02T\xdb\xdc\xdf\x83P\x84K\xa5\x02\x12\x86\x97 R.\xfb\xa8*u\x85Z\x8aVn_\xa6\xc1\xcc-\xa0\xdf\xfd!\xa6\x8bs\x86\xe3\x15\xf1\xderQ\x8d\xd3\xc2\xb6;\x9a\xc6q\x08\xba\xf2}\x9eR\xdc\x00W\x97\xaf\x1c\xcf*\xab\xde_\x8aU\x96\xc7\xcd\x04\x9cN\xcd\x96I\xa3!\x92\x9f\xb2r\xb9\xaf.\xb0\xc5\xa2\x95\xdf\x1c\xa7\xc4\"\xe0]V\xeeYM\xb9\xf1\x91\xd6H\x1f\x04y\xa5\xe8\xc2%~w\x9aT\x80J\x0e\xd9\xe2$\xd0\xb4\xa3\x145\xb4\xa8\xbe\\\"u\xf9u\xe7*K\xd0\x92\x80\xc0\x05O|\xc3\x13\x98\xdb\x8c\x10\xa1\xa4b\xe5,\xc4e\xe9\xbe\x8d<\xe72\xd8\xc8E\x95=\x135\xc4\x823\xc8\xf8\x0c\xa9\x1d\x0c\x89$\xae\xb5D\x88\x89p\xca\x18\x9c\xcb\xa9?\x9b\xf5\x05\x8d\xe1\x96\x80\x19O\xcb\xce\xffq\xbc\xc7\xdd\xd5b\x07 \xe4\xc7\xbd\xc1\xbe\x15\x1e\x15L\xf0\x90\x89\xe0e\x1dO,\x1d\xd6,\xe77\x9f\x88 N\x13\xc6\xa8\x8a\xaf\xd0\xc5\x8d\xd7\x93\xaf0\x0e\x83S\x81\xd2\xdc\xd4\xa9$|\x1a\xc1\x17\xf4<.z\x1eC\x97\xe1uo_\xed\xdd$\xedHZk\xa2\xee\x89}&g\xe4K\xda\xe2\x14t\xe4QNG\x90\xc9\xe3\x9d3\xd9\xac\xbe[m[\xb5b#\x914\xec\xd3\xa0y\x9fz-\xf7i5\xa7\xb6\x97\xa3o%\xa7vV\xbf\x8a\x9f\xa0\x00\x8eR\x93\xa0`\xfc\x18\xc2\xbb\xddn\x1fq\x02\x95 S\xb6?\xbci\\`3N\xb63\xe2\x87_\x01\xd22N*\x8dq\x04\xcb\x8a%f2\x96q8\xc8x\xa3eF\xbd\x0e\x17\xaf\xb099\x14R\x1e\n\xb2\xe6Y{lR\x8f\xf5\xee?X\xaf \xeb\xbf\x11\xa3\x9a\xd0\xa9\x0b]\x05\xa9\xeac(\xa8\xa5\xf6`.\x1d-e\xf0~\xc9iRx\x00\xdb03\x93\x98i\xc16\xc5l'4\xd9\xe8\xa8\x84\"D[\x1d\x95\xe4)$4B\x12J\xcad\xa6%1\xc1\xb7\xba\x1b\x0c!\xc4W\x9e5\xb8Xy\xfb\xc2g\xca\xc2\x13\xce!\xcd\x9a\x16\xfd\x9fAF\x1a\xd6\x88\xb4X#\x85\"\x84&\x8a\x90\xf3\xbe\xd3xV\xdeA*1\xf091h\xd8\x8c\xae\xd0U\xb6\x82;Q7\xdc\xb4+S-7\xc2\xbe \xf0\xad6\x9cY\x94\xcc\xb7!\xd7(\x89@\x03I\x93\xf4X2\xd5k\xf4m\x84\xaa*-\x0b\xb98F.\x02\x8a\x9eT\x10-\x801/|,i\x048W$Kz!K/'\x95\xf9\x87G\x8f\xf8\xc5\xa4DbT\xe0\xd6\xc1]+i\xe2K\xca\xab\xc1\xc5N*\xc4\xce\xeeKu=\xfed\xee\xa8.\xd2\xe9D\xb5\xff2+\x03sm\x94.\xd4\x8c\xce\x1d\x87\xc7\xbb\x94-\xa3\xfb\x97\x89~*\xb4\xb3\xbe\xa2\xb9\xe5c'O \xa6\xd1\x80\x98}\xec7\x94\xc0\x14\xa1zO[Xy\x15ia|\xdc\x9c1\xf7ui\xbc\x85\x0fy\xbd\xd4\xed\xf3ce\xe0'<\xb4C\xaa\x89\xce.?Uf851\xc3\xd4I\xa7\xfeL@\xcd<\x12{G\xd5X\x11\x15K\xb8\xc8\xd6y\xc4y\xeb\xb0\xee\xc4\xca\xd0$\xe2dZ\xb9R\xf5\x0d\x97\xa8\x90\xaar-\x82,\x9a\xfa\xd3p6\xabL+\xd5\x98\x03\xe6\xe12b\xbb\xd2\x8fR\xab\"\x9b\xb5s\xc43\x02\xb0S\xe8\x1fUOB\xa9\x97V\xcc2q3\x84\xc8\x03\x85}6GZ\x9c\xb0\x13\x08%\x8b\x85\xda\xcbR\x0e\xf2b\xe7\xe5n\x9fr\xfbR\xaadh\x1f$dA_W\xac\x15,\x96{|\x8a\xf1\x80\xde\xa64\x9c;\xf5}\xc4m4\xc7@\xca\xab\x85'~et_\xe4\xf6\xa3z\xb1Z\x07,\x0d\xe9\xd5\xac\x07x\xd9\xd6q(\xecC\x8f\x9aC\xcaX\xa3\x99\xf3h\xe1\x97i\xba\xd6\x04\n\xe7\x0fo\x12C\x0cq\xd1\xdfS\xc1\xec\xd57T\xd1\xb8\xae \xd9zC\xf3\xdb\xdb[\xf6\xf6\x17\xda\xb1+-l\x8e\xec\x0d,\xa3\xf5%\x8d\xedm\xec5Lr\xe1\x07\xa6P\xebzs\x04\xeda\":\xf9\x16\x98%\x1d\xca\x1a\x83\xc4\xd47~d\xbc\xde\x99S/\x9a\xd3O\x1f\xdf\xbe\x8aV\xeb(\xa4a\xea(Q:\xcfzh\xb2\xc0\x18+\xcd\xceM\x07\xdc\x7f\xc2_\xdc5!{NT\xaa\xf1\x05$\xed\xd1\x9e\x8c\xdcQ\xdc\x0f\xa1\xcb;R\x9d\xcd\xf95\x0dZOO\xd0#\xde\x85X(6\xd1H\xf2\xd1#\x10G\x0f\x0dkS\x8cP\xb2\xdbG\xb6\xa0\xfe\x94'\xf03\xd0\xbe\\\xf4I\xd1O\xf2\x8f\xc8\x0f\x9d\xee\xa3\xae[!o}H\xb9go 2U\xb0\x94.\x92\xd1@b\xfa\xfb\xfe\xe4\xd1\xac\xe7\xeeO\x9c\xe9\xef\x8f\xb8\x95\x04\xae\xfa?>?G(\x86V3\x01i0\x159\xe8\xb4i6\x8fb\x156\xabg\x0b \x9b\xe2\x87\xfc\xba\xd7\x89\xa7\xfe\x8c\xb1\xc9-x\xa6\xf8a\x08^\xf8FnU}\x1a\xb9o\xe4\xde\xee\xb6\xd67rk\xb8\xa9\xf1\x8d\xec\x1e\xde\xae\xa9\x97\xd2\xb9\xaag+W\xcb\x14\xdf\x97\xf2\x93$\x7f\xe2\x87-\xc8\xb8\xe1\xcaL\xdc\x94\xf5a\xdd\x87y\x1f.\xfb\xe8\xc9\xa8\x89\x01\xba2X\xe2.\x0d\xe5w\xa8\xf9-\xafSE\xb5Yl\x8a\x92?\xf4\xe9\xdd\x9ar\x9fh\xa2\xe6R\x06\x950\\\xe8\xcf\x10\xb9+\x03=\x02\xe1\xddK\x1du\x04.\x04\xec)\xec\x8bh=\x1c\x10)W\x1a\xd3\x01Y\xaf\x83;'\xeeW#>}6\x0c\xf0\xdc\xech\x8f\x16\x12\xb0\x01\xe6\xfc\xedJ\xbc\xa0Kn\xb7\xf2R\x90\xa1P\xdei\xa0\xe8\xc0Z\xb9f\xcf\x16\xad\xc6t\xa35\x97dC\xa2\xb8\xb3t\xbbj\x01\xce\xb9\x9ac\xe3\x90\xed\xe0Z\xb59\xec\x83\x08\x05\x1fe\xa9s\xd3oa\x94\"A\x91\xc2\x068\x08\x0f{\x00\x88%L a\xdc\xdaB\xbep\xed\xd6\xf3s\x00ga\xabn\xdf\x06\x88\x1cZ\x1d\xad\xe7\n2\xa0Av\x00\x13\xb8`\xaf\x8c\xf9\x9d\x8e\x8a-5 M\xdf\xe3m\xd3\x1a\xe81\x97\x01\xea\\\x0bz\xb6Bl,$^f+\x1a\xa6 \x0f\xe4\x9f^\xfaI\x1fo+\xa8Ei\xc2^V\x90\xad\x10\xbf\x9b\x97\x0f\x14t\xe5\xbd\xd4\x91\x80 $\xab\x02fkmC\x9f\x1d\xd3\xc2\xb3\xd1-]u5\xea\xcd_8\x97m\xe4\xf0\xfa\xc6BSyG\xd7\xa8\xdb\xaf\x8cT{r`\xaa\x0bF\x85\xee\xefQFrB\xae\xfbA:\xd9a\xe7-\x99\xfb\xe1\x92g\xdap\x18\x95\xec\xae\xc8\xedo\xc4O\xbbty\xbb\xb5PS\xe5~p\xa2{#\x97u\xff@ *\xdd\xeb9\xe1-]B\x0f\xab\xac\x05\x82\xe43\xa1\xaf\x0f\x9d\xd8\xa9\xc4\xcd\xccs\x08\x15\x0c\":`\x8c\xc1#\xe1\xe3\x94\xcd\x0dH\x02\xb9|\xd9\xa9\xd8O~\xd6\xef\xd0\x1a\x80\xc6\xa0]\x14\x14-\xba\xe7\xe7\xd8\xfe\xf99R\xe4\x7f|\x86I\x15LZ-\xa89\xe8\x16\x8fC\xe7l?s\x1di\x15\x85\xe2`\x9f\x81vw\xe8\x0e\x16NUp\xee\x832\x0c\\\xbc>l\xba.\xeb\x7f*\xc3\xd9u\x1c\xaa\xda\x8c\xa1\x9aM\xe78\xd5\x14y*\xd5G\xcd6\x9e\xb0*0\x8cl\x87\xa8\xebK%\\\x8aFx\xf9\x9c\xd0\x1cM\xd0@\xf6\xb8\xae\x06\xad\x9a\xc1\xfe\xe33\xbf|\x19\x8b\x83\xa6\x82z\xde%\xf5\xae\xc6\x8aEv\xebM\xab\x92\xf5\x02\xe5\x8b\x8d\xdb\x82\xe8\x1b\x8f\x1d\x0fC6\xf0:\x0f\x1b\xd9\x97\xed}\xde\xdf\x18\xc7\xff\xcc}\xe0~oV\x1a2p\xed|E[\nx\xab2\xb4\x90\xad\xf7\xb4I\x88\x9d\xad\xbd-m\xdc\xa1\xa7\xba\xb0C\xa1\xb3]\xad\xcd\x07\xfft\xbbZ=\x10\xe5\xd5\x83\xc0\x13\xbdVG\xb9\xe0\xf5w\x86\xa5\xd3\xf0\x99\xf2+\x1a\xf8![\x1a\xa7\x82U\xeb\x1a\x19Z\xf8\xe1\xfc\xf5\xf1\xfb\xa3hN\xc7Ui6\xa6\xe1\x9c\xc6c\xf0\x07\xfc[e\x92\xe1*\xca\xc24\xd7\n\x1d\xa4\xbc\x11\x7f\xa0\x7fR~\xfb\x9a\xc6\x89\x1f\x85cH\xaa\xad&x\xc3v~\xc1\xe8\x05\x9d\x7fZ\xcfIJ\x931d\x83r\x89\xe15>\xd2\x93\xec\"\x8d)}\x1b\xa6\xd1\xab(L\x89\x1f\xb2y\x14\xc2\xabB\xa1\xf5\x91\x1a\xcf\xcf?\x1e\x1e\xbc:=\x7f}\xf8\xeb\xe9\xf1\xf1\xbb\x93\xf3\x9f\xde\x1d\xffx\xf0\xee\xfc\xe7\xe3\xe3_\xce\xd1CWk9e\x7fM,\n{\xbbU\xc5\x8ar>\x87\xe7iL\xa9.i\xf8\x92\xa6\xaf\x82(\xa1I\xfaV\x10\xe47q\xb4\xe2\xab\x12\x0f\xccO5\xba\x16\x8aK\xc6*\xc8\xcaM1\xc3@\xb9b\x18\x88e\xa0\xf3|\xcc\xfc\x02\x921\xfbR/\n=?`\xcb_\\h|\xaepH\xeboAL\xf6\xf6\xaa\xd1\xca$5\xa9\xeewNM\xf6\x9e\xea4u\xac\xbc\x1a\xdd,\x13\xe5U\xaa$\x88\xe1\xd3j\xbf\x81(\xaf\xf6\xcb\xe9\xc9\xde3==\xa9\x11\xc35'3\xa3*Y\x9a\xf3\xf2\xcd\xea\xe1w)\xcaG\x95\xf2kQ^\x9d\xeeJ\x94W\xc9\xe4R\x94W\xc1p'\xca\xab`\xb8\xe0\xe5[\xd5\xf6\xcfEy\xb5\xfd\x1bQ^\x9d\xef!*\x18\xdb\xf0n|{6\xc4\xce>D>\xeeP\xb8p/\x07\x87\xd74L\x0fW~\x9a\xd2Xl\xf0\x8f\x94x)\x96\xbf\xf3\x93\x94\x864vVn^\xf7C\x90-\xfd\xf0\xe7\xecB\xd4V\n\x8f\xe39\x8d\x1dR\xad\xfb)\xf5\x83D\xd4.Q\x0bga\xab\xcaj\x9c\xc6\x84\x91d\x12\xa0\x80\xde<\x82\xe4\xc7\xbb#\xb2\xa2\x9a\xfbC\xf69\xf1W\xeb\x80*\xd5\xc7pS\xa72\xecs\x18\xa64~G\xc9u\xb9v\xa6\xaf\xfd\xea\x92\x84\xcbrMCv\xb3\x13\x1a\x94\x07<\x86s}\xcd\x1f\xe9\"\x8a\xe9\xdbp\x9d\x95\xab\xd7]\xb4>#d~\x8e\x92\x02\xb8\x020?\xb1\xb5\xf3\xbd\xbc\xf8U@\x92\xc4\xf1\x8c\xf5O\xe9mZ\xa9|\x89\x95_\x1f\xbf\x97\xd7T\xa2\xaaR\xf2*\n\x17\xfe\x1235\xb4\xab\x99\xb4\xaey\xc1\x17}\xb5f%\xe5\xb1\x96\x0b\xdf\x10/\x8d\xe2\xbb\x16\xb1>\xa5\xc2\x81\xde\xc0\xba\x1a\x98\xb2\x80\xa68\xcd\xf3\x0d!\xc8\xf5iL\xc2\x84\xf0\x1e\xee4\x15\x7fd\xbc\x80\x1f.O\xd2\x98\xa4ty\xe7\\c\xa5\xda\xd8\xc3k?\x8e\xc2\x15\x0dS'0K\xf3\xf8\xed\x8b\xc8\xbf\x99F\x08\x00\xfb\x8cw\xa9\x03\xa8Kb\x9flxY\x1c\xd30\xed\x8eu\xf7 \xbc\xca\x9c\xa6\xc4\x0f\x12k\x15?a\xac\xcf\xdcV\xe7\xd2\x9f\xcfih\xab!\xfc\x02mU\xae\xe8]r\x19\xc5\xa9\x97\xa5\xd6\x01\x05\xe4\x82\x06\xb6\nq\x14\xd09M\xbc\xd8_#\x07e\xa9J\xb24\xf2\"FMRj\xab\x87\x92\x97\x1d\x06\xf4vM\xc2y\x03\x9cH\xb2\x8e\xd6\xd9\xda:=zm\x9f\xde*\x9a\x13{\x05\x19\xb5\xbc\xb1R\x82d\x8c-\xaf\xadj\x14\xfb4LI\x13,\xf1\xce\xfa2\n\xe64\xb6V\x8bi\x92\xd8\xc1\x14S2\x8f\xc2\xe0\xce^\xe7o\x99\x1f\xdb\xdb\xe1\xd3k\xa8\x13\xc5\xd6\x1drM\x82\x8c\xae\xc8ms\x1d\xdf\n\x1d\xac\x13F7\x8duRzk\x1d\x10I\xa3\x95\xef\xd9j\\d\x89\x15t\x81\x7fm]\xef\x98\x06\xf4\x9a4\x10\x0eF\x7f\x16\x0b&\x9f[j-crqa\x87?\xa3\xc2\xd7\xb8]i8o\xe8\xd4\x8b\x02\x8f\xf1\xe1\x0du\xd0P\xae\xa1N\xb2&\xd6\xe5\xf2\xa20\x8d\xa3\x06\xca\x884\xe6\x82\xce/\xac\xe0F\xcf\xe8\x15M\x12\xb2\xb4\x82}\x11D7id]8F\xf9\x82\xa6\xfe\xa2\x9b\xd0:\xecu\x94\xf8aB\xadP\x8c\xa3\x9bFH\xc7\xd1M#\xa4\xe3\xe8\xa6 \xd2 M\x13\xff\xef\x08\x99R\x8d\x8a\x00\xf6\xfa\xf8\xfdA\x9a\xc6\xfeE\x96R\xc6\x1a\xb2s\xaf^E\xf2\x1dy\x8d\xbc\xc2W\x9c\xc2\x8aFgX\x95V\xc4\xd5\x81^\xa3\xb3\xb7W\xad.e\xb0\xaap#e\xb0\xaap\x83q\x08\x9f\xf5a\xb4\xd5\x87\xcd\xbd>lmV,[\x990\xb6\xb9\xa9 \x14\x1d\x0d<\x12~J\xe8\xeb\xe3\xf7\xa8O@\xde%\xf1\xd9\xcc\x91\x0fE\xbd/O\x11Q~\x19\xc5\xb5R\xda\xfcjS\xf3\xc8\xc3+\xda\xf7\xd1\x9cb3\xb2\x00\xa4\xc3\xa0,\x18\xa8U\xab\xca\"~\xd3Zm\x9c\xf1\xae\xd5\x01\xb2\x07\x1d\xee\xb2\xe7\xd4\x0dk1\xf5\xbbHv\xc1V\x9f\xb8F\x05\xcaz \x14C\xac\x06\x9a\x07\xbd\x0dS'/u\xdc>\x8c\x86.\x8f\xe7\xa7\x11?+cu:\x1e\xc8HT\x0b\xc0\xec\xbe\xec\x0b\x86\xe4\xabL\xf6Z\x13\xa6{\x95G-\xc5t\xbc\xaf\x84W\x03\xe35K\xf5\x96\xdax\xd2\x17\x85\\\xa1\xe3\x00\xd9g}I\x12:\xffH\x97~\xc2\xf8X?\n\xe5\xb6\xd0Vg\x9f\x8b\xec\x82\xf1zc\xe8F\xa1\"\xb9X\xbc\x10<\xb2N\xb3\xb8\xfe\xca+^^\xb7\xe5\x87\xfa\xde\x96\x9f9]\xd3pNC\x0f\xd9\xdai7\x8d\xd6*\xda\x86\xf3n\x1fX\xe1/\xf4\xee\x03\xe3\"\xc4O\x862b\x98\xf8\xfb\x03IR\xda\xd5$\xe5\xab\xf7\xea\x95\x9a\xffN\x80\xac\xce\xa1\x1d,\xcbo}#p\xfe\x18d\xb1\x80\x92 \xb2\xaf\xa3\x9bP\x0f\xe7_\xe8\xdd\xa7\xb5\xf8\xfe>\xca\x12\x8aU\x1f\n\xe7\x93\x94\xc4\xdf\x0be_U\xba\xf9\x02X\xe3{\xdf\x15\xdabd\xff,xs\xc9\xf6\xfb\x03\x9c\xf7\xf3\x05\x10\xe7/~W\x90\xcb\xb1}C\x98\x97J*\xe3\xbb\x13\xaa\xbe\xbc07\x9b\xba\xd0^\xa5I{r\xad\xb2\x83[C\xe7C\xb3ZD\xd7r\xf7\xa2G\xc5\xab\xf2\xe1\xabk\x18gim:o {\xd0D\xd3S\x9b\xe3\x105\x19\xa8\x97@k\xa9\x84ki\xb7\x00\xd7\xc4\xac\xb3F0j\xb2\x1c\xd7ymhL \xafe\xde\xb7\x01W\xa0\x94G!:1\x05A\xe9\xceIJ\x90\xbbIa\x02\xe9\x80\xfd\xac\xdeI\x14#b]\xdd\xe4,Y}t\x87\x92\x8f5\x84\xa6\xcd\xfa\xba\xd8\x0e\x1e\x86l\xb3\x99FC\x13^\x82\xbaT5\xf2\xd6\x18\xf3k9\xa8\x9e z\xe39]\x17\xec\xbczX\x07\x87\xe1\xbc}\xf3\x82Z<\xac\x07\xfeR\x13\x9d\xe0\xd7O7\xdc\x96\x10\x85\x8fG\"J|u\xb8h=\xd7df\"1M\xd9\xc4\"\x92\xd3\xa3G\xca\x8e-\x07\xba\x16\x031\xf7\x8e\xab\xe1\xf6AI\x18^\x16\x08\x00\xf9a\xf6.\xc6q\x17\xe1{kMp\x1c\xab>:\x0c\xd1j\x8f\xe7\xa9c\xf2\xcd\xcd`I\xd3\xd7$%\x8e\xcb\x81\xb3\x0f>\xdawEQ@\xe7NTu\x05`X\xbd\xc0,\xc4E\xa5\xac\xd8\x03udO\\X\xf0]V\x8bsbp\x05\x95\x97\xd9\xe7Z\x7f\xfb\xdc\x92GDH\x91m\xb7qn\x8c\x07\xc4\xf3\xb2U\x16\x90\x94\x9e\xdeD\x1f\xd8\xf1\xfb\xdaO\xd6x\xf9\x9c\xe0E\xca\xc2J\x8dn\x1b\xf6;\xa9\xcf\xbf\x83\xd1\xa2\xe6U\x13\x9fo\xb6\xe3[m\xc7s\xa7\x1a\xb0F~\xda\x1c\x1c\xf2\x93\x1fF7\x97\xbew\x89\x8bp\x0d\x13\xbe\"cp\xee\xc4u\xd8\xaa\xa9\xabBd0\xf7\x95\x1bv\xe3\xfa\xea\x1b\x04\xe5&\x02Q\x1dc_\xdf\x15C\n\xf5\xef5\x86\xd9S\xf6]3M\xc1\xad\xdc\x82\\0d\xb81\xad,:5\xd4\x17\xb6\x88\x0c\xd7\xf1\xd8\xdc\x04\x07cj\x05\x14\xc0)\x1b\xbb\x11z\xfe \xa6\x01% un\xdc~~\xe0\xf5\x0d\x01,\xf5\xae\xce\xeda\x06\x0fBu.O\xb6Z\xabo\x8e\xe1\x8f\x1eA\xa7\x85iD\xe5m\x87\x0e\xbc4\x0e~\xa1w\xb8\x1ayJ~\xd8\xd0\xd1\xa2\xcf\xd1s\x80\xf2\x83\xf7\xba\xf9\xbe\xb9t<]XD\xa8\xb1\xa8\xf8*\x1b \xba1\x8b\xdcQ\x1a\xda\xd6HX\x01J\x810\xc1\xaa\xac\x96\xbc\x0d\x1d\x9c\xdf\xc4d\xbd\xa6\xf1I*\xb2~\xa4\xe5\"\xf3\xd5\x01gT0\xd0\x980\xd7\x0d8\xaf\xd3\x0d\xb3\xd5\x05\x8d\xf3\x95c\x0b`\x19\x0b(\xacw\x97\xe7\x8c\xc3\x03\xcc\xdc3`\xf4\xb5%Ms\x93TG\x9cyn\x112\x17\x1d\xefk\x15\xb4+\"?\xfa{\x8dz)\x9eB\x81\xd1\xe1D\xafp}\x8f\xa5_)*\xef=\xd595\xab)\xde#q\xa4\x8a$\xe2V\xb4i\x197\xd5@\xe0\xf8\xe5\\L\x17\xf5\x85\x928\x18\xd60\xd7\xe2\xce\xaf\xcfV\x00\x13\xa0\x0e\x0f8\x92]\x04\xbe\x97SMd\x02\xe2\x01\x99\x17n\xa8\x07\xc9G\xba8\x8d0m_\xbf\x1ab\x0bp\xe1B.\xc8\x0d\xce\xa3\x9b\x90Vc\x96\x16K\xc8\xc4\xb7\xe42\xca\x02!\x06\xb5\x81\xa6\x84I]r\x03\xa9\xae\xac]a\xe4\xd0\xa7\x06\xe8c\xb9\xc8\x86\x16\xd3\x85LL)\x86_\xbf\x0f\x89\x8c\x03\xf0\xb5\x03P.W\xecX\x90\x13\xcb\x94\x8f\xc3\xc7\xafb\x1c}\x08\xf1m\x0c#\x9eG+,\xde\x8e\x90\xc0\xf1\xbdY\x062g\x89\xdb\x80\xf7\xff5\xc8\x8a<;\xe2fLW\xd15-\xa3';\xf9\xbf \x82~\x075\\)\xe2\x80Q\x03iP\x8a\xfc\xe6\xc1^\x0b\x13G\xedR\xa7\x91Xh\xf3\xfb\x1e\xe6\\\x9a@d\x89\xfc\xe2\xac\x8d\xc1V\xd8\xe73_\x81 W8z\xe6!\x8b\xf0\xa0\xfb\xfb\xe0\xb5\xc4\x94\xb9h\x16D\x92\xe4\x04\xc6|\xb05\xf5G`\xb8\x96\x07\x19uD\xb4\xe2Y[\xf1,\xad\\WlZ\xc9\xa0 P\x88\xd0\xb8S\x0ds\xc9ov\xf0\x9d\x80S'V\xcc\x17\x0c\xd3`]WVq_\x17\x95\x17\x04dV\xfa\xd1 \x81\xc60\xca\x96\xd1\x08\xd0\xaf\xca\x83\xa2\x9c\xb6\xb3\xe2\xbc\x7f\xf6\xab:\xa8y\xd9\xce\xa98D\x95{\xa9\xeb>\xac\xf8&w\xfb0e\xbf\x1a \xa9\xfe\x8c\xcf\xb0\xf4+\x0f\xd2Z\xf4\x1bv\x8e\xca\x00+~\x14\x0e\xde\x7f:9=\xfftrx\xfe\xe1\xe3\xf1\x87\xc3\x8f\xa7\x7f\xad\x9f\xafj\xf5\x9f\x0fN\xce\x7f<>~wxpt\xfe\xeb\xc1\xbbO\x87\xf5c\xb7Z\xfd\xe8\xd3\xfb\xc3\x8fo_\xe9\xaag\x9a\xea\x1f\x8eO\xde\x9e\xbe\xfd\xf5\xd0\xf6^\xa2y\xef\xf8\xd7\xc3\x8f\xef\x8e\x0f^\x1f\xbe\xb6\x0d0\xd0\x9eR~\xf2*K\xd2h\x95k;\xc6\xf0\x91.\x0fo\xd7J\x94\xfc\x94&\xe9\xe0\xc2\x0f\xe7NHo\xc4c\xa7\xfb\xbb3')\xb9'\xb1O\xdc\x0d\xcc\x01\x14\x0f\x0eNO?\xbe\xfd\xf1\xd3\xe9\xe1\xf9\xd1\xc1\xfb\xc3\xf3W?\x1f|\xc4\xbc@?\xfc\xb9\xab\xcb\x1ao\x0f\x85\xc1><\xb3\x8e\xd6\x07\xb9x\xfc\xea\x92\xc4\x185\xd1R+I~\xa1w\x96\x1a)\xc6\x1c3=\x0e\x82\xe8\xe6M\x16\x04'^L\xa99\xb6\x0c\xd6\xc3\x08%xjx\x96\x0e\x03\xcbp\x13\xcb\xa3\xbb\xd03w\x9f\xa5\xd1+\x11\x12\xc3\xdcD\x96F\x1f\x02rglE\\\xec\x9b\x9f\xd3 \xf8@\xe6s?\\\x1a;auN\xd6\xc4\xb3\xd6\xb9$\xf1\x89e\xd5\xbcK\x12\x04\x14-\x1c\x8c50\xb4\xc7\x18\"\xb87\x8e\xd6\xb7\xc0\xc2\x0bH\x92\xbc}m\x7f\xceYLS\x8d(H\x8cA\x89\xbc\x88\x01\xc1\x8cV^\x14\xa64\xb4@\x80??\x9c\xfb\x18\xe8\xc3^\xef6}O\xc3\xccZ'\xc6\xc1\x9a\x00%*\xbc\xf3\x13\xdb\x88\xa2xnFO/\x8e\x92\xe48\xf61L\x92\xa1\x0e\xb7\x0c2?\xa4\xa7\xbe\x05\xdey|\\\xc3,\xe6t\x81\x81 \x0dO\xfd\xd8\xdc\xb2\x08\x96c~9\xba \x83\x88\xcck\x91 \xf3\n1Y.\xad\x0bEC\x8f \x04\xc6\xe7\x8b(^Y\x1f\x1e\xd8\xe9\x14\xabr\xd8\xa2\x8f\xf74\xbd\x8c\xe6\xd6*G\xd1\xaf$\xf0\xb9\xff\xa9\x01 \xac\x1a\xe7\x0f\xcc-\xc5dE\x7f\x8cb\x8c\x16i\xa8sI\xc9\x9c\xc6f\xa4\xba\xa4\xfe\xf2\xd2\xdc\x05\x0f`d\x1c\xe4\xa5\xbf\xbc4\xbf\x1b\xd3\x85\xf5\xe1;b!`\x97\xe9*x\x13Y&\x96\xa6\xeb\xc3\xbfe\xfe\xb5\xb1\x86\xefY\x16\xd37/\x10\xden\xbd\xc7\xf0\x8d\xc6\x1a)]\xc6~j>\x81|3\xc4\xaf\xe8\xdd\x07\x12\x93\x95\xb5\x86\x15\xc9\xae\xfc\xd0d\xeet83ov*nd\xd9$e\xba]D(4\x7f2\xec\"~]\x19\x95\xea3\x08a\x08|\xda\xd7\xed\xbe\xca>3$WK\xbe\x052\xd5\xd0C\xe4\x87xVE2\x11\x9b\xf4\x99>?\x84.\xd9L\xac\xac\xe8\xa40\x9d\xe7\x89x\x04\x85r\xbas\xff\xfa\xffa\xefM\xdb\xdb\xc6\x91E\xe1\xef\xf3+`\xde9ij,)\x96\x9d\xc5Q\xe2\xf6u;\xce\xe9\xdc\xc9\xf6\xc6N/\xa3\xf6\xf8\xc0$$\xf1\x84\"8\\d\xbb;\xf9\xef\xef\x83\x02@\x82d\x81\xa4lgf\xeey.?\xd8\"P\x00\xb1\x16\xaa\n\xb58\xfa\xbe\xb7\xb9\xf2\x1e\xfe\xfd\xb7\xf4//\xdc\xdf\xae\xb6\x07\x0f\xf1Q\xe8\xa5\xdbX\xbb\xca\xcf\xc5\x9a\xa2\xee\xd6\x04\xd1DL:\xfd[\x91\x8ab\xf8\x8af\xde\xd2M\xdb/>\x01Ug\xb3\xc9yU\x1f\xbc9\xf1\xa8yVH\x94np\xe0\xd6u'\xe1\x82\x1bkd4\x0e\xa2\x88%b\xbb\x08\x9c<\x9b\x9c\x93m\xc2\xc86 g\xbb\xc8\n/B\x1a{\x00\xbds\xfe\x9cx\xa3\xd1\xf3\x81\xd4\x0c\x1d\x874\xcd`\xe1V\x17\xa6\\\xda\xd5O\xb1\xe6\x90\xce\xb5B\x98\x9a\xf4\xf4\x87\x9b3\xba\x80H\x0d\x8e\xf4\xb7^?a\xe7:`\xb3\x8c\x16\xadgkH\xb8;\x1f\x8c\xe7<9\xa1\xde\xd2\xcd\xeaF\x80E/br \x83~\x81\xfa\x89\x1b\x8d=\xd1x\xb1m\xd3\xc1s\xb3?\xa2\x87Z\xdfQn\xe42\x0f7\x99,\xf1\xfc\xd7\xfb\xd8\x7f\xfb\x96\xcdm_\x82\xaa\x1d\xedkT+7nI\xcd\x1cTC\xb7\xaa\xd0x`\x86#~\xf0\x808r\x06\xc05\x03T\xb2\xe5:)\xcb^G\x19K\xd64\x94\xe9\x83\x8a\xde\xbc\xa9\x13)p\xb3 \xcd\xe1\xf3r*\x82\x14\xfe\x8b\x06\x8bO{4\x0c\x19S\xf5\x83\xa9G\xc6V\xaa\xda\xea2\x13%\x0eI\xa3\x12 \xa2\xc0\xf6\xbf\xdb\x98\xa3\xdc\xaf6\x7f b'\xe1\x0d\xd5c\xb7U\xd5n\xb6\x85r\x86\xc3\x08\x16+20\x99\x91\xad\x0c.\xc1x\x81\x8c\xc8\xa4\x18 ]\x1c\x9d\x9c\xb1\x1c7\xa3\x9ez(\xf9AK\xbc=\xb5.d?\xcb[v\x18F\x15\x87\x1d\xc1Jf\x9c\xbc&UX\xec\xbaH\xef:7\x13[U\xfa\x9e\xe0\xe4\x05\xc9\x9e\x13\xbe\xbd= \xd1\x8c\x9f\x8bI\x98q\x04\x05i\xf5\x9c\xe6\xdcO\xc9\x8c\x9d\xdf\xef\xb6\xb3\x1c{XP\xa4\xbb\x1ec\xa0\x13\x89h\xed\xcd&C\xf2\xdd\x0b\xc9\x1f\x16\x02\xec\x03'Kr\xe6|\xff\xdd\x908/\x1e\xca\xcc\xef\x9d\xf3\xe6\xc1(J;/\x80\xb1\xfc\xde\x01`\xf5\x1b\xf1\xf4=\xdb+a_d\x97\xdc\xbf\xf9\xfeE\x96\xe8b\xc9\xf7/\x1e\xaaDK\x1d^\xd9\xda\xf5\x82\\\xaf\xc2(=\x00\x8eo\xfa\xf0\xe1\xd5\xd5\xd5\xf8jo\xcc\x93\xc5\xc3\xdd\x9d\x9d\x9d\x87\xe9zQ\xb4~\xbdhT5G\xa9x\xe7/\xceT\xf6\xe8\xf0\x85\x1f\xacU\xcb\xe0\xd7y\xf38\xa4 \xa3\n\xfc\xc5\x8a\xc6\n\x1a~!\xd0\x1e\x0f\xa7d\xb6\xdb\x1c\x01\xddi\x8f\x87\x8b\x84\xe7\xba\x9e\xe2\xd56\x1a\xe2 \xd9\x82E\xben\xc4<`\xa1\x9f\xb2L\xd5P\xbe\"%c\x9a\xd0\x95.(1\x8b*\xa6_\x90BY\x82vAM`\xeb\xdc\x11y\xb7\xb0\x90\"wDn\xcacy\xad\x8bdyT\xe5!l\x92\x1e&4\x13\x9a\x84\xe7\xcc9\xcf\xf0\x9c%\xb3\xdcog~#\x08\xa0,0\xad\xbb\xa7,w\xfa\xcc\xf1\x82\xc4\x0b\x81\xc5\xf5\xc2 \xfe@\xb3\xa5\xf8\xed\xb39\xb8n`a\x18\xc4)d/\xc4\x9f`E\xa5\xaf\x07\x08\x80\xa2\xfe\xd3\xe4?\x13\xea\x07,\x02-\xdd\x15M\xc1\x03D\xac\xaaR72\xf0\x93\x877\x0b^\xfc\xd4u\x88\xc244\xebHddJ'\xcd\xb8\xf4\x0d\xc1\xae\xa5\x060\x84;8/(\x1b\xfba6\x07\x0f>\xc4\x1b\x12*\x7f\x99\xc1xk^N:i\x88@\x9c6\\\x9e\"\xf3\xda)\xa2N?p!\xe4\xfcEpV\xd4\x02\x11T\xe8?\xe7/\xa5m\xb5\xf3\"\x0c\xa2\xcf\xe4\xe1\xf7\x0e\x99\x12\xe7\x85\xa3HP\xe7\xfb\x17\x0f\xcb\xdfN\xd9\x95`<\x0f\x12M}\xa9\xe4C\xd9e\xd4\xd3\xed]\x0f\x01T\xc8`Qwoe~q\xe1BO\xeeW\x1f\x9d\xb8\x82(\xe6\x83\x99\x80\xab\n%\xfb\xd0\x0e/\xa2>\xac$Nl\xde\xc1<\xa2S,\xd1p@\xa3\x19\xc9z$=-\x97\xa8\xcfI\x8eK7R5\x85x\x9c\xc1\x86\x02\xa6\n[\xfa\xa4\xce\xbe\xaa0\x83\x0dW>\xb1\xaa\xbe\x9e.\xe3\x0cN\x1e\xd7;+\xe3\x0c\xee=\xae\xc3\xaf\xf1\x15\xa5\xc2\x0c\xee\xd4;\xab\xc2\x0c\xee\xd4 \x91\x1b\xd5\xfc\xfa`\xaa0\x83\x0d\xbb\x8d\x0b)\xb5\xd9{6\x18B\xb8\xc4\x9d\xba\n\xa4\x8a7\xd8\x18\xbe\x13U\xf0\x11\x14\x9c\xf8\xeb\xebB\xa2`r\x0b\xa2\x85\x16{\xf7\xa8\x10\xf9;\xe4l\x19\xa4D\xd0\xf6\x82c%W4%:L,\xb9\xbc!\xff%\xce\xa9H\x9cS\xff5Fn6\xfed\x7f\xd3\x1f(Ka./\xde\xa1'\x83\xb4Z\xfd?36\xbe\xc8\xe8\xe2\\\x1a\xd7(s\xcfl\xac\x97\x85\x1e)\x99jY\x0c\x8a\x1fu&{O\x1dA\x1d\x88\n\x87\xf6\xc1?$\x0e\x81\x0btA\x8f\xa9\x91P\xaa;\x84\xcf \x9c\xda\x96\xb2\xe5\xc0\x8b\xe1\x1a\xc3\x91\x0f\xf6\x89]M\xb4uO6\xfc\xc9\x0eHu\x11\x9b\xd9\xb6\xfa\xce\xc0\xa3\xa4\x15B\x8a\x94\x9fL\x9cA\xa5\x81p\xcf^1\xd158\xf72W\x14\xddu\x86\xb0\xec\x07\xed.M>\xb6x\xdc\x90N\xb6\x133P\xfd\x15\xea!\x19\xf1\x88\xa8m\xa6\xd9\xf8b \xa1!\xda[\xe4\x05\xac\xf2\x07\x0f\xf4\xcfRN#h\xb6\xd7`\x99#a\xa6\xe2W\x87 \xd3\x91\x9b\x0dI\x00>\xb2\x16L\x06\x8e\x85\x88\xc7\x1f\x19\xf5o\xdc\x81v\xa6\xe5\xbe\xc4\xee\x0e\xa0QQ\x9aM \x12\xeb\x99\xa0\xb6v\x16\x97\x9a\xa1:3\xa6\x88\xdf\xe7\xafVKQd\xb6^6\\ \xcd\xc7q^\xc6\xc1\x05\xe7\x92\xa2\xcd\xca\xcfd\xbd\x85*Y\xb7\xa7}i\xbci|l5\x8ey*G\xf0g\xe9\xca\x02\xbe\xd8^\xcd\xa7F5\x97\xb7\xa9\xe6\x1f\x8dj\x16\xdd\xd5\xe8_b5\xbej\x1ca\x19\x8f\x8f.y\x02w\xd3\xe2\x7f\xed\xcc\xcbx|L#i\x0e\xe0x4\x8aCzc\x05)\xfc\xe1h\xc8L&4\x0b\xbc\xcc\xe5|\x1c+\x0f\x85\x8e\xaf\x12<\xcc\xab`\xc6\xe3\x93U\x9c\x05\xe0K\x90\xc9_\x08H\xe4%7q&\x81\xf4o\x0c\xccW >\x9a\x9d$p\xa3\x0e\x91\xfd\x9a\xd9o8\xf5\x99/\xfd\xd6:!\xbc@\xc8\x0f\x0b\xe0[\x96Q\xdf\x04^\xa9\x04\xbc\x80\x8a\x9f\x04\xb0)\x12\xe4\x08\x1c\x96\xe7\xa9\x18\xb0X\xfcG\xb2\xe5L\xe1\xd3$2\x81\x88\x80\xfc Z _$\xa0X\xe6\xc4\xeag\x13\xe8#\xcdX1s \xcd\x98m\xd6N\x19\x03\xf3\x0b'\x85\x1f8\x80lQ*\x7f! \x19\x0d\xa5\xcf\xc9T\xfeB@\xf24\x06I\x8f\x93\xca_M\x90\xb3`\xc5t\xb4$'\x0bV,\xc7B\x1ae<\xfe\x89\x87\xf9\xaa\xec\xdd\x1a^m\xfd\xfb\x99\x06\x99l\xfe\x95\xfce\xd0\x11\x18 \xf6{c\xff^\x8f\xb3\x84z\x9f{\xec\xfd\x1f\x1aeK_\xcb\x82\xe0~\xfdR\x1f\x98{\xf5\x8b\x1a\xb1\xf3\x199 \xea3\xd5\xcc\xc2W\xbe.\xfe\xc8)<\xf4ft\x81\x1du\xd2\xd3{\x00\xba\xfb\xd6 ?\xeap\xc6\xdd\xb5\xcb\xeaMW@\x05>\x06\xb9\xa9/\x86%\xfeA\xba\x1bU\x0e\xdc\xd4\x1e\x01\xb9\x8f\xfc\xcf\x06\x96k\xe0\xcb\x84\xd1\xcf\xcd,\xd9\xb0u\xe03nm6\xcd\xfd\x00\xcb%\xa6\x0c=+]a\xdb\xfbp>$\xaf\x06\xe4U]\x1e\x93\x01\xb1\xd7Vx\x1c\xe7\xe9\xd2E\x86 \x1b\x92W\xb3\xec\\t\xdcB7\xb7v\\j\xac\xdd\xef\x8c\x9cH4Y\xe0\xcb[\xceI\xb0Z|\xf3v\x0d\xc9\xb7\\Us\x9e\xac\xee\xb7\x0b\x1f\x19h\x88\x11'Q?Z\xbap\x9a_\xae\x02)\xb4\xd4\xbfn\xd7\x8d\xc0\x128E\xad \xe9*\xce\x1a\xd7\x8b]g4a\xf4~\xc7\xe1\xb5\n/>\x14\xad\xd3?\x99=$\x01\x82;\x7fj\xe0\xce\x1b\xa0\x9b\xe4\x89\xd0\x87p\xfa\x11\xe5\xfd\xe5%\x07&k\xb8\xa4\xe2\x94Fs\x12<\x1d\xae@\xb0\x0c\xb6\xba\x14\xc7\x1f\x96\xb5\xb4\xd4\x15\xac,\"\x90@\xc6\x14\xc5\xb2>\xb3\x9b\x05\x8b\xf0\xbc0\x88>\xe39\x82\x9e\xc1s\xd4\x1d\n\x96\xa5Ug\xb1<8\x0e\xf1\xac\xab\xcbN\xe1\xcd\xcf\xe84\x89Uf\x95\n\xc5\x89\xad%j5w}\xf3\xff\x80\xff\xbe\xe6WW,\xca\x83\x8c\xad\x90\xf2\xe4\xc7\x9ap\xedW\xd0\xa2\x99\xd1\xd1\xefG\xa3\xbf\x9d\xab\xff\xd3\x8b\xdf\xc6\xbf\x8d~\xf3\xcf\xff\xf2\xe7\x87U\xf0\xbf\"\xb7\x95\xff i\xb5\xd3\x06#B\xfe\x8cJ3\n\xedJ\x1d^\xd0\x199\x03\xf2\xfd\x01\xd9\xa9J0\x02[\xa4\x92\xbfA\xb0\x01\xe4{\xbf\xb4\xc5\xd8\x13|{\x15\x17u\x85\xc4\xf9Oy\x03\xfeW\xf03\xfb\xe5\x0bq\x7f\x05\xf3su\xcf!\x08\x98\xc7\nW\xfeU\xdf\xbd4\xdc\xbc\x16\x04NUFb\x86\x03\xc9\xe8\x824\\C\xea\xcc\x88\xaeX\x1aS\x8f}\xfa\xf8\x9aT\xe3ph\xb9\x94\xbee\xa8e\xc7 [\x07r\x9e\xb9e\x9dRZ[\x1a\xa4\x05,u%\xa99\x17\xb4\xbe\xa5\x9d*\xbcv\xee\xc6\x16\x08\xd5s\x18\x92\xd7Q\x90\x054\xd4t\xbb\xa0%\xe7C\x92\x0c\xc9\xd5@\xfa\xd8o\xfa\xf4\xfb\xda\xe6fP|\xfd\xa4\\\x98\xf0\x8d\xf71\x8b\xce\xe8B\x9a\xdd\x1cE\xfe\x87\xf2\xda*\x85\x0f\xb6,\xf6\xebZ]JA@\xd6\xa5[k\xe9\xa7h\xfe\xd6\xb5@)?\xce\x8a]yN\x0e\xc9\x89X\xdeR\xf3\xebD\xaet\xb2M\xae\xc5/\xb9\xfc\xadKC\x02\xf7@\xe0\x1b\x92\xaf]\x14O\xc7\xc9\xf2\xa68\x82\xe6c\x9ag\x1c\xc2\x88H\xd3\xba\xd6r\xc1x. M\xfe\xe3\x9fr\x14w4\xeb\xd3\xbfSwZ\xa9\" r\x99gY+-\xf7o\xd0\x8dNz\xb3\xa3Q\xff\xe8O\xbc(\x99J\xab\xbeN\x0f\xcc\xd0CCQ+\xd6\xc8\x03l\x83\xb3\xb0\xb8\xd2H\xe0J\x03?\xc7@\xa7\xa7~\x8f\x91t\xc6\x89\x06/\xee\xb3\xa4\xc5T\xcf\x0c)\x11\xd8\xcfP\x0d\xfa\x1ek\x03x\xa7\xfe\xa8N\xa1\x04\xe2\xa2\xd8\x0e\x04\xfdt8\x87\xd5\x8f\x03\xba$\x92\x96\x01\xcb.7P\x7f5&\xc6$6\xdc\xfd\xe3\xebP+\xa2\x08\xa2-\x80x\xf6r\x9a\xe5\xfc\xbe\xe2 \x94H\xdd@-\xa6\x8e\x06\x135\xa29\xc1\xdc\xeccOA'\x9b\xf4\xe4\x9fK,\x0c\xeb\xe8\x90\xbcm\x8e(\xc8\xd4\xc4\x87\xbcz\x9bk~ ]1\xd8\x10(\x01\x85.\xab\x94\xda'\xb9\xd4 \"\xdb\x07\xc4\x01\x15\xa5\xbc}\xc2\xfb\xc6\xcb0\xcc\xc2#\x9f%g\\\xf0\xf9\x81'\xdbA\x0eID\xa6\xfa\xf4\xa9\xd2\x1cf[\x1a\xad\x07\xfa\x03\xf4\x8eZ\x80^\xbfT\x15\x83\xech\xd0\xea\xd3\x1d;\xb5\xfb\xf9s_\x17\xe1Kp\xe2\x80\x93\x16\xb5\xad\xe6J1\xf7\x1c\x1f\x14\x0b\x85\x8f\xa5\xce#\xccRB\xca\x04divP=b\xc1\x7f\x98\x15\x1aYZUL\xd0\x1b\x86\xe2\x98M\x01R?T\xadu\xc0\x0df\x84p]\x83\x9d_)Q\n\x0c\xdc\x89\x1b\xb4\xd1\xc5f \xda\x86\xd3\x12\xbd\xef\xa5\xfcQ\x13\x8aT\xc5[\x18\xff7\x0f\"\xd7qng\xa7O\xca\xa5\xfc\xb3I\xa3 \xce\xf37\x15\x02,\x19{K\x9a\x1ce\xee\x8e\xd8\xbb\x90\xbcM\x1225\xe2^\x10\xeb\xca\xab\xd1\xb7\xbd\xa5\xa6Z\x89\xed~\x97X>\x86\xd3T\x94\x17\x08\xe2\x7f\xc6bs\xa4\x83\x89\xc0\xe8 \x84\x86\x06\x0c\xd8{\x05Z\x1bY\x9c\xd5i\xfbB\x94\xec\xca\xces\x12\x92\x17$\xd5\xb6\x94$\xdc\xde\x1e\xe8fI\x0e6\x19\x92t\x16\x9ew\x912\x8d\xe8\x14\x1e\x0b\x8c\xf0\x14\x9ba1\x8c6i\x0e\x0d\x06e\xdc\xceHv\xb0h\x81\x9b\xc1\xc9\xdf\x8czR7\xe8\xab\x16\xbb\xc5\x16\x00\x19=\xbe\x8c\x82o+\xd7\xefb\x8c\xb8M\xdc\xcb\x15 \x82f\xda\x96%\xb9\x17J\x9a\xdb\xa4\xb3\xbaMh\xe6\x9d\xda\xd4)\xba\xe56\xf1\xacn\x13\x9ay\xa76\xf5\xe0\x03\xb9M\xec\xaa[\x85f\"$\xb3\x9d\x01\x7fW\x14j\x13\xaapE@7`\n,\xa3 \xc4V\x19v\x8b\xf8\xfa-\xde\x95\xda\xd1\x15M\x8c!\xb9\xc6\x83\xe3\xde\x95\x03\xec1\x1f\x97X\x83\xee\xf0\xc9\xcee\xd9\xc1t\xfe\xd4\x8f\xe9\xac\x9f\xfc\xc8\x0co\x80\xade\x8cI\x0b\xcf\x98 >\x00\xf4\x03:\xf3\x08\xc3(Y~4Y\x1f\x7fl\x96 \xe7\x91Yq\x85+\xeb#YN\xed\xecZ;\x1f\x05\xfd\x0cD?\xd3\x01I\xeb\xed\x0e\xa4\xec\x1fX%pU\xf2\xc7\xd7\xc1,8\x07B\xbd\x83\x9d\xb33\x8f\xedW\x8e\x92Z@\xb8`r\x08\x03G L\xad\xdc\xe6\x89`\xcc*\x0c\x1fka\xf8f\xd8A\xecB\x11\xd1\xed9\x90\x81q\xc5dfn\xaa\xd1\xc4\x83M\xd6x\xebZ\x12\xe0\x10\x98\xa6\x87Pb.\xa6\xb0}\xf1\x0dI\xdc\xb5\xa7Hek\xc4\x03\xb2\x15#{\xe3\xcb\x172\x87\xb1\xc0\xf3n\xb5o\xaa_\x9e\x0f\xd0\xca\x1f< \xb1\xa8OL\xc1\\\xfc\xb0\xecR\x91\xd7!\x81\x90\xfbM\x14E\"\xfb\xe9\xa7\xa0\xe0Q\xe9\x94\x98\x1aC85\x07|;\x95k\xa3\xdc\xaa=j\xaf\xc9n\x06\xf6\x9d\x9c\xb2\xacm\x1b\xb7\xdf\x8d\x17\xdf\xdb`\xa3w\xa3`\xdf\xa6|^\x7f\xca\xddrX\xedI\xd1K_u\x81L\xed\xd8\xc5\xdf0\x10k3\x05\x84U\xd4l\x80\x12\xd8\x15\xe3\x98c'\xb2\xf5\xfc\xbd5\xd7]\xb0\xb6\xac\xc2\xda\xb2~\xac\xed\xdd\x99c\nZz-6|\xd6L\xc5\xd1\xe3\xd5\xe6m\x02\x05\xd0\x8f\xbfU\xb5\xa9\xc1\xc6\xf3\x92\x8d/G\x0b/\x16vq\xffx1\xaf\xf25\x03\xbd[\xbc\x07\xcf+\x9f1\xe0\x11\x1aKg\xa5\x05q\xa4B]e\x06\xff\xabIr\x89\xb8#uF{\xa2\xc8\x16 _\x03\xf8\x8c]gJ\xf8\xe8V,>\x03PF(\xe4\x16\xd6\"d\x9b\x04\x03\xe3\x98\xcc\xc9!\xa1P.\xaf\x95SW\x92\x8e\x14\xf2\x1aE\xc2\x1a`\xd1\x81\x10\x0bg]\xdbL\x8a\xffy\x07\x0e\x85\x8b]\x84\xed\x1d%F\xab\x1b\xd5 u\xe6\x91]\x95\x10\xabyC\x9e\xfd\xff\xe9\xe2\x19\x8f\xd6\xf9\x95c\x87[\x01\xd8\x0f\x07iV\xdezvT<\\\xed<'\x11yA\xb2B\xfa\x15mo\x0fH6\x8b\xce\x95\x0e\x87\xcd\xf2\x9c\xf4a\xe7\xda\xf8\xd9\xde<\xe6\xf58\xcdx|\x96P\xefs\x10-\xbaN\xc7\xce6\x81\xc3\x82\xb6&-\x19\xf5\xdboo\xb9\x7f\xd3\xd2\xde\xc4u\x9e6\x1f\xe93\\\xf6\xd9i*C\xea\xa7\x8f&\x8bA6\xe0\x07\xa2\xf4h|\xc7\x03\xf1\xe9\xb3\xba\xcb2\x0e\x86\x87\xa3U:\xea\xf4\xdc]_\xeaj\xeb&n\xe1e\xdd\xe5C\xe2\xac\xd2\x913\xa8\xe3\xda;\xb5\xfb\xe1\xc8\x1d\x0f\x1e.n\xd9\xbe\xb2u\xc9\xb0\x1b\x85kW\xe0\xe3\x8c\x7f\x12\x14$\xe2\x02\xfc\xeb\xbdv\xceF\xa5(\xaa!\x19\x07\xe9\xa7(\xc8B\x96\xa6\xef\xc0\x7f\xd9\xa0k\x1cZ]\x19iQ\x02h@9\x97\x9c\x87\x8cV\\\x17\xcb\x0c\xa5\xc0_z\xe0\xaa\xed\x04\xady\x11\xa4\xef\xe8;7\xab\xa1\x07\xbd2DU \xe80\x9c(s\xc4?\xe5\x83\x07\x84K/\x922\xd2\x05\x99\x82\x08\xbc\x11!\x80HG\xe3`\x96\x99\x04+\xd0\xcf\xca\xc4y\x13_7N\xf7;N\xca\xfe\x0e6)\x0f\xff~\xb7\x8d2\xa8\xec\x94\x11l\x95\xfbl\xf7Cwv4\xfa\xdb\xf9=m\x16g\xf4\xe7\x893\xb08\xc3\xbfCk\xfb\xb5H\xcb\x0b\xfe\xf8\x8a.\xae\xa2 z\xe6\x17\xdb\xb8\xb6\xd8\"y\xf9\x90\xcd\"pq-M\x89\xa5\x14>\x82\xd54\x8b\xec~\x05\xc8m;lpg\x8fw:\xf7\xafej\xbes\xbe#\xdb\xb0\x88\xc8\xb6x\xb9\xe7\x86M\xcc\x86i\x92\xa9\xda\x10q\x08\x87\xecL\xd9\xfcb\xa2l\x8e\xcdE\x97A7\x01?\xa9\xea\xa6\x1b\xdc>\xa4 !(|\xa7B\xda\xff\x07\xf7\xe0[\x13\x84\x9ft\x931\xbb\xce\x12\xeae\xbat\xd9\x1e+s\x8e\xcf\xc2\xbd\x84~\xd9}2\xc0\xec\xe09z\xe8h\x9e\xc1\xb2\xcc\xa3\x19\xabn\xc0s\xcc*=\x9a9?\xb3\xcb\xcfA\x06\xae\xff\x80\x1c\xb9*\xde3\xc8\x7f\xcb\x7f/3W\xf2E\xe6\xac\xd22\xe3\xedi\x99\xfe\xbeL\xe6\x90\xda\xf8jm \x12\xe3`hN3\x8d\x82\x15\xb8\xf8\x02OM\xdcu\x8et\x823$\xe5\xcbI\xe4c|KQ:\xc8\x98\xf4\x14\xd6R\xc7k\x0d\xd3Z\x93\n\xf5g\xad\x05\x9cqa5d\x89\xa0?\xcd\xae\x9c\x15)\xa2\x86\xf2\x0d:S]\x81My\x02\xe6v\xde\\\x0d\xa6k{q\x00\xe6\xfd\x18\xf6\xca\xa0\x8a}\x01Q\x1b\xae\x82\xc8\xe7W\x80\x04\xa5\xa8\x8d\x04csf\xca\x97!i\x02\x14\x83\xdf\x0e\x06#[\xbe\x0e\xaac\x82\xb4\xa5\xa8\xa22\xb4\xc6[o\x9f\xd9\x82\xc6\xa13v^P.\xe2\xe5y\x03d+0a\x90h(\xe2\xe4 \x1aE\x0d\x113\xce)\xa2\\b$5\\D\x91\xbc\xd2.P`\x88\xce\xd1\x8d_qIJ\xee\x8e\x946s\xfc\xdct\xc1,%_\xbb\x93\xba\x0f\xe3\x1c\x97:J\xc7\xcf\x8f\xf6\x8cCE\xbb#~\x86b\xc7\xb0\xdb\xbd\x19h\x13 zY\xc6@5\xeb\xf5\xac\x07\xaa\xe3-\x99\xf7\xf9\x92_\xebHU:,\x1c\xb8\x84\xe7\x95\xd4\xc3R;d\x0c\xc5\x98oj\x8c\x8c!R\x9b\x05\x1d6\xa3)\x98\xaa|\x1b\x88\x95\xe8x\xa1$ nf\x11\xed$\x1a\xecX6\xb2A\x9a\x93\xb2\xff\x98\xcf\x1a\xf1\xc8\xb0\x9aR\xe8f\xb9f\x850\xa8m\x10\x10(\xba\x15\x80^k\x80F\xfeWX\xddx\xe3Tx\x7f\xd5\xbd\xf6o(\xd8\x9fd\xd8\xc16H\x15\x99P\xcfg\xa4\xccFX\xed\x9e*\x90*\xf4P!^\x91\xa7\xdb\xa5\xabJ\xc8!h\xe8[\xaaR\xfd\xc0++\xddc\xd6K\xeb\x9c\xe6\xd0\xb5\x9e6\xa6\xd9\xff\x06\xeb.\x1b\x9b#\xd9\\O\xac\xa7\x8b\x8dj\x9f\xcb1\xca\x8a-uh\xfc\x9e\x96\xdfm\x1d%sR\xcc:aN\xa1F\xf9kJl\xb7\xffU\x8f\x1f]s\xd1M\xcc\x92\xc6m'\xa6\x11\xde.\x9b\x95\xfb\x9d]3/\xcf\xd8{\xf5q7k\xb7mK\xc74\xa5\xb1\x1bv\x1aI\xae\x0b\x85\xf6\x88\xaeZ,\xe4Azh`Ce\xfbk\xe8k\xa2\x14\xbf\xf9\x14G\xa68Xr\xfb=\xd1\x10\xee0\x82\xe7\xc43\xc2\xf7=\x1f@j%\xa9\xdf\xd7\xe6P\xec\x1f9KnNA\xf7\x96'Ga\xe8\xca\x9b\xdb\x99\xe8\xf5\x81\xa0i\xff\xcf\xe9\xfbwc)i\x08\xe67Re\x01D\xd8\xdf\x9d\x83\xda\xcc\x81\xea\xfd\xf9w\x03\xe9\x02`\xe79\x89\xc9\x8b\"\xf4\xd9s\x12oow\x0d\x01Q#\xee\x83\xd6Y\xdc!\xb3$j\xdc\xfdR'\xc3\x1f\xcfy\xb2\x82\x19\x08\xe0g\x9f/\x12\xf5\xd5\xa5\x1ew=\xdeb\xec\xe1\xd2\xb5\x1e;\xcd\xf6,\x95c\xadg\xe0\xe4\xbb\\d\xcbn\xc9*.\xfa\xec\xce\xb5\xe7\xa0\x01\xa8\xf4\xf3u|\x19D>\x1a\x9eO<\x1e\x8f\xb2\x84Ko\xb2\x1e\xa6N\xd0\xaaM]\xa1<\xba\xf0\xc0\xda\xea@\xbfe\xf3Kd\xab\x10`sn\xca\xe3\xe9\xc1\x03\x12\xa0\xdaq\xf8\x06\x13\xdc\xb4\xa3\xaa\x85;\x1b\x88}\x8b\xcc\xbe&\x17\xad\xd5\xe0\xb8\xb1N\x9b4+\xaeZ\x84\xe1x|N\\)'\xe4pG\xa1M\xde\x00{\x0f\xf4\x0f\xc1\x8d\xeeX\xc4\xf2\xc5MD\x11\xd2\xad\xc4Y]\xb8\x1aD\xec4I\xe5]\xa1\xab\xbe6$\x93\x1d\x90\x18\xb5\xdc\xc9\xb8\\\xeai)\x8f1RcK\xb7VbH0\xa9,\xdb/\x91\x0c\xbe\x80e'\xca\xe2\x1a\x1c\xaf\x039\x8b!\xd6\xa3\x16\xf2*x\x03_W\xcfr\xd9\xd4JJ\xf1\xc9&\xa4[\x03E\x01\xb5f\xd9\x81y\xaec\x0d8.\xf3\xca\x8au\xe2\x01\xd9\xda\xaaC\xb6\x926u/\xe8\xdfl\x7f\xda\xb6Fs*\ne\xb1\xd6\x05\xa8\xf4\xab\xa4\xd7\xd66\xed\x1c\xe9\x05\xb6\xc5d\xa5KA\x08\x02\xbd\xb7~\x02\x9a\x06\x1a\x85\xdc\xa3\xed*I+\x1ee\xcbv=\xaa\xae\xaf]1f\xd3n#\x10a\xb5\xdc2C\xe3-\xea\xa0i\xf5\xd32\xaa\xaa\x82>\xdf\x8ej\x0c\xa2~\x9a\xc7\\\xc1\xb0[(3eb*\xdd\x11H \xa99?,\xbbdl\xa2zZ_(\xfc3u\x05\xcd\xe2\xcd\"M\x9dC\xea\xad\x04\x17f5\xce\xe9\xc9\xf1\xc7\x93\xb3\x8b\x97\xef/\xde\xbd?\xbb\xf8ptzzq\xf6\xe3\xeb\xd3\x8b\xf7\x1f/~}\xff\xe9\xe2\xe7\xd7o\xde\\\xfcpr\xf1\xea\xf5\xc7\x93\x97\xce\xed\xbfi\x08K\xeaR\x11\x15o\xb9\x1e\x0d+\xc0\x85\x1f\x94\xe0q\xa0\xf2\xf2^\x0f\x8e\xdf\"\xb3\x90V\xa4\xf6{\x90\xfa\x15\x9c\xe6\xe2\xc7Z\xad\xae\x88K\xc7\x86\x1d\xc8\xaf\x90[\x10\xe9\x9f\xacq\xd3&\xc5 \xe5)Z\xa6\x1f\x92\x8cl\x8b\x92SiN\x01\xd2\xc8\xad\x9d\xba\x9c}0$Y\xb9:*#\x1c\xe2\xee\xd9\xb8\xe9K\xc2\xd0\xa5\x96\x94\x8b2\xf6\xab\x17,d3\x92!\x01\xc4\x03\xea\xd5\xd7\x99[\xbf\xa8 V\xe4\x10\x0c[\xbc\x80\x98=\xb7X@\x08\x90\xc0PDo2\xca\xdbb\xf7OI\xea\x96\xfa\xef\x03\xf9\xd1\xad\xc9\xb0\x16\xe0\xb7]7\xa9\xe0\xc6\x0c{\xf4\xa4b\x8fn-J4\xf7 .\x0ef\xe1\xb9\xe4~\xfa0>rEv\xb36\x80\xda[\xa1,\x8a\x1b\xa5Y\x90l\x9dl\xda\xed\xe5\"r\xbd\x08\xa6$\xefX\x04\xdf\x96\xe8\xb1s\x1c\x06!\x19X\xe8\x9f\x8a\x037\xd7\x01xg\xa8K\xb6\xd2n\xb7\x14\x87&\x16\xf9e9\x9cm\"\xbf2l[\x8b\x14\x12\xa1\xeaJ\x99oU$\xa7\xbf\xaaN\xcc\xe2\xd5\x0ei\xe1\xbf\xc0\xe7\xa3\xb9\xf7\xec\x02\\\xf5-\xaft5\xcd+\xd7r\xa4\xcf!-U\xee\xeez`nt\xbb\xd0\xbcE\xa0\xf8A\x9aoz\x8b\x90\xf6\xbaE\x08;n\x11\xf4/\xfc\xb8\xdap\xb9j\x81E\xc9\xff\xd8\xad\x9e\x12\xd7y6q \x82\xfe\x1fmRp%\xaf\xbe\x1f\xe1w\xb9\x13\x1c\x159nC\xa1\xf7\xbf\x8b\x9c:\xe8\xbe\x1f\xb1\x9c\xf8\xa6fT+\xc5@\x1b\xe2p\xbb\x187$\x07\x9d\x0ed*\x96QnE\xd7V\xac\x85]\xb1\x16\xaa'n(\xc5 \xa1:F\xc9\x8b\x032\xd1\xf2\xb9=G\xf9~ g;\xe7\x03\xe9\xdc\x16\xe644\xb8r\xa9\xc8K5\xd7\x00\xc2\x9b\xe6\xfc4R\xfa\x1efUq\xbc\x94S\xfc_&w\x0f6\x95\xbb\xab-\x9eK\xc9hZ8m\xec\x10Rv\x8c\xfa\xbfD\xfcH7\x92\xfc%\xf5]\xd7E\x92v\x10\xe3\x92\x9e\xc2\x07Z\xda(F%%\xe2\x96\xfc5\xafH\x9d\x1ar\xab\xa8.\xb7B\xa4o\xcd\x15o\x17\x995+\xac\xc9\xc0\xda\xe6\xf1\xb6D\xdbf3#E\xc9Yi\xc1\x89P2\xea\x82\xdb\x8e\xee\xa1\xafY)\xc5\xd8\x90\xfd\xff\x96\x94\xc5\xee.f\xcf\xe4\n\xf8]\x19\xe4X\xda\xf2l\xaeg\xa3A\x9f*v\xc3\xa85\xfd\x90\xf0\xa1\x9dQ\x04Y\xbfv\x90\xd6\xd6\xec\x14\x1cGgC8;i\xdd`\x99\x0dE-\xc5\xe7\xa4\x06\xa9\xbd\x86\xf28B\x17V\xc7\xaa\xe0bU\xd0\x86\x05q\x04\x12T\xd8\x0fQ}M\xf0\"\x9a\xf6d\xdffg\xa5\x95\xbeg\xaer+h_DR\x1d\xca9;\xf9\xe5\xec\xe2\xf8\xfd\xbb\xb3\x93wg\x16G\xacD]1\xc3\xd0X\xa2 \x8bg\x0e\x07\xb8\xcf\xae\xbb\xbcR\xce\xd5M}\x17\\\xc6{UG\xe7\x19K\xca\xfaP\xb8\xaf\x03\xcc\x1d\xa4m14\xdd\xd8\xfe\x8f_\x07\xa7'g\x17o\x8f>\xfe\xf5\xd3\x87\xff\xb7\nH\xdeq\x1c\xdbVCf\xf8\x16\xbc\x1dIp\xdb/\xd7\xcf\xc9\xea\"\xb4\x8f\x1aG\x14\xb5\xcd\x87v\x9c\x809r6W\x89\x19Wz0\xa5\x92\xa0\xb0\x9f\xcf\xe2\x1c\x84\xab\x97V\xe7wp\x0c\x0d\x0b\x973\xed'\x1f(6\xb5\x83\xf8\xdd \xcbn\x90\xb5\xf5\xe6B?\xb0\xe1=\xa9*\xddZ\x15\x0cC}\xcb{\x9d\xe4\x00Qc\xb3\"\xeav3\x99y=\xe8\x02\xf1,\x04E8\xf3z\xa8oIU\xad\x059$\xee\x1c\xa4\xb9su\xe4\x97\xc1cVC\xb2\x1eB$\x9e\xc1@\x86\xe3yK\xb3\xe5xE\xaf\xdd\x95y\xc0\x0b\x80!Y\xd5\xce\xfc\x18|\xf1\xad\x80\xb1h/\xabB:\x95M\xb8(\x11\xe8\x91\x04s\x17CBg\xcbs\xdd\xa2L\xd9B-\xb7\xb7\x07C\x12\x0b\xf2b\xad\xf9|\xed\x81\xc7E\x9c\x7f\x98\x8f]\x7f\xab\x9c`>h\x1a\x03zR\xbaUk\xb2\x89\xf5]\x980\xc2g\xde\xf9\xa0\xcdm>\xf8?\xd2\xe8}^\xfa\x0fi\xd2\xb5\xcdK\x17\x82\xf6\x00\xc3\x7f\x91\x95\\o=\x087<\x05\x9b\xe7^f\xfah\xb5\x84\x9c\xec\xd3\x81bA\xf6vLF\n7\x05\xe6\x92|!\x80\xeb\x96y\x1d\xa8\x98\x94\xf4g\xfb\x9eU'\xef\xdb\xf7?\x9d\\\x9c\xfc\xf2\xfa\xf4\xec\xf5\xbb\xffl9|\x89y\x00w#?\xe3\x1c\xae\xf4\xa9\xbb\x94{\xcd\xae\x11\xaf\xac\xc7E\n\xb1L\xed}\xcd\xeb\xc7\x13\xd8\xc3\xef\xde\xbf<\xe9;\xab\xdd\xe3\x7f\xd7\xfd\xdbB\xa2\x93\xfeT5\xe9IY\x93\x8em\xdbkV\x9bg\xf8-$a\x85\xc5w\x95\xb4H\xd4\xa9b\xe0\x05Qe\xd4\xbbm\xe6Q\xd5s\xcd\xe9\x0b<\xf8\xb0\x19b\x8f\xe1w\xf0\xc4\xde\xfcH\xbaBl\xb6\xf4O\xf8\x9bEt\xedA\xea\xadD\xd7\xa5\x9b'\xd4\xd6W\xb9\x17\xa8\xfb\xe1 \x86\xa7\xae\xfa-8)\xa5\xdb\xbb\xbb{ \x97\xde\xdd\xdd\xad\x0b\xb4\x89\xa1x\xb6_\x1b\xb4\xdau91\x85\xccy\xc7\x81\xbfV\xb6\x1b\x86\x17&\xd60Z$\xe6} \xa8\x89H\xa1\xb7\xb4\xb3\xe7\x82^i*\x89U\xc7FV\xbfu\xa0*x\x0fN \x11\x15\x0f\x81=.N\xde\xfd4%N\x9cp?\x87^ \xe8\xe4\xe7\x93\x1f>\x1c\x1d\xff\xf5\xe2\xf5\xbb7\xaf\xdf\x9d\\\x9c\x9e\xfd\xfa\xe6\xe4tJ\xb6&\xd5F\xd4FJ\x8b\x0b\x9b\xdfE\xa4\xd8\x1b\x13M\xfa\x8e\x8a\x0dL\xb5\x80v\xb9j\xdd0\\?Z\xbc.>\x9d\xcb@\x01\x1b\x88\xf1\xda\xba@\xa1\xc2\x14\xa2U{\xe0k\xd7\xde#\xf0\xe9\xd1y#+\xf8\x9c\x0e\x9e/n\xf1\xbd\xa4\x1f\xd4\xba6\xee\xcd\xf3 \x06\x15\xd8%\xb8\xd8b\xb3\xf8\x1c\xb8\x0d\xbf~G\xda\x8f\x1d\\\x83\xf5n_k\x1e\xbd9@?(p\x97C\xb2\x1e\x0cH2\xae\x07Sq}`\xc3\xf2!\xf8b\xca\xa4\x1f\xa2\x96\xb1\xd3O\x0f\xbfJ\xfa\x91*JTV\x9dT\xa8W\x1f\xdc.\xd4\xbd\xa2\x8a6mM\xfa\xc4(#\x06w\xcd\xdd5l\xfa~\xa5TOW\xfd\xa0\xc57\x16\xd0\xfaZKW\xf5\xa5\xdb\xaf\xbeH\x8a\xcf;\x98Z\xd2\xca\xd8\xb6\xe7\x96k\x9c\x0d\xc8V\xc3\xc7[\x0cV&\x80\xf8\x90\x05.\xcd\xf5\xc1[[|.\x98\xf5\x8d\xa7\x0em\xd7]Y\xdc\x96\x13\xbdj(o\xf1vG\x88\xc5\xe3]\xd4\xb9\xa55r\xc4O\"\xf3A\xc6\x84\xa3\xb4\x8c~\x90Q\xa9\xa4\xd4\xd0\xb1I5\x94\x17|_\x07\xca\xb5\x8c8\xac\x1f?V\x13p+z\xa2\xf3*\xdc\xa2d\xd7PV\xa7\x96\x8bs\xa5dW\xf7\x89\x99*U\xbd\xba#\x80P\xb5\xa5\x9e\xeeU|h\xee=y\\'P\xe68\xe5\x13\xcb\xfa\x1a>9}Y\xdf\xbe\xa2w&\xf5\xea\x96\xaa;\xf5v\xacK%\xfbzO\x05Z\xaa9\xce\x14Xd\x17\xbb\xd2\x07\xc7T\x7f`\xb7\xf2\x97\xe8\xca/\x15H\xcb\xe5rS:\x7fU\xd1 M\xdf\x15\x18u\xc8\xc8\x01 \xc5\xbe\x96:\x89xX\xe8\xc6\x02\x85\xbb\x0b\xe9\x94Z\xaa\xf7(\x12^*\x97Wbf\xd5c\x0d(*B\xf5\xa9\xa2\xb5_]\x82\x17\xcd\xb1\xbbB\xe9$\x8fGi\x96\xe4^\xaf\xebALM\xcb\x88\xf3eq\xf7\xeb\x89\xad\x9c\x06\x19;\xbb\x89YA\xf4\xcb\xbc@i\xc6\xd4\x92\x8d\xd0\x8f\xcd\x8c\xca%l-_\x0e\xdb\x0f4\xf3\x96\xd2\xffZ-?f\x91\x1fD\x8b\xb2\xedH&h\xd6\x80\x03#<\xff\xa3\xf4\xb9\xa5\x15\xeb\xb6&\xb5\xfcW<\xf1\x98\xbc-\xa8dk\xc1\x9f\x18!d(\n\xb9\xa0\xc6|\xb5|\xb5>j\xa9\x80,\xdf'r\xb1\x16C\x9e)\xafOJi \xef\xc71\x0d\xc3K\xea}N\xeb\x1f\xa2ah4\xe3\xe7 \x0c?I\xa4\x0c\xddi\xac\x0c\xabZD[\xe46\xab%z\xbd\xb3\x1c\xed\xe9\xc5\xf66\xbaV\xb2\xd6\x85b'\xdd\xe9\xd0\xb8\xf3\xe9\xaf\x83G\x14\xe6U\xe3\xaa\x14}\n+\x11{!\xcf\xf61\x1ce\xe8g\x0eJ\x82\x0b\x96\xc9\xe5%\xbdl\xb5|\xc6o\xf5\xbeS\x7f\x14v\xd9r\xb7X\x89\n\xc1\xfa\xd8x\x1f\x07)\x04\xbe*f\xb7\xe5lv\xbd\x96\xb6-\xcb!\xd08\xa8B\x08I\xca\xd0F\x13\xfafD\x86%1LV\x97\x1ay\x1f\xf6\xf2eF6\xe8\xf8\x87\x9d\xe9\xb3tl\xb2\xeb\xb6N\x05\xd2\xb8!\x91\x1e\x06b\x1eD\x99-\xa0\x07\xee\xaa^?E\xd4Vl\xa5V\x9b\x83#f\xed\xda>o=\x0e\xc6 \x97\xa4\x91K\x07u\x1c\x86\xee=7o\xd9\xf9\xa0\x96]\xadC#\xa7\n\xdd\xf0\xc1(Y/`2\ne\xaa\xc2\xc2\x83\x016\xbeV\xba\xb2\xc9bo\xed\x808\xa2\xd2\xeb;\x0fu\xdbZ\x0dn\xb9\x1ao\xb5\xf8\x8aq\xd6\xe3f\xa7IZ4_\x83\x12\x83 \x8a\xb8@|.\x96\xe1v,\x87\xa0\xc7\n\x08\xf4\xa4\x07\xe5<\x0f\x86\x15\xc1~\xa1\xaan\xce4\x90\x0543&\xdc\xb5 \x03\xd7\xca\xe5\xbd'\x90\xb78\xecQ\xcf\x18\xa4\xa1flp0H0,b\x08\xe6\xcd\x81\x07a|\x95|\x02i8\xdc\"x\xe3\x93\xb7\x1f\xce~m\xbf>\xb2,hI\x85\xcc\x11\x15\xdeD/\x92*\x81\xbe\x0cB\xdf\xa0\xd2\xb1(\xde\xc8z\xec\x1f\xd2\x8a\x187\xb3\x15\xb1\x9f\xa5\x03\xbd>\xbfi\xf4+\xa2E\xf0\x96ov\\\x02d\x8dmc\x97\xdcII\xbf\x87q\x8c\x0f\x1e\x90\xad\xac\x8d\xa7\xecs\x87\xd0\xc1\x92\xee\x0c\xdb\xef4\xf4S\xb9\xb8, \xbam\xe2\xa0mw\x07\x1d\x01\x05\x08\xe8w\x07\xd1\x9a\x7ff\xff\x99\xd3\xc4g\xbe\xe6\xa9A\x05\x00\xadU\x9a\x93e-!E )\xac\xd6\xf1*\xda\x82a\xd9\xb6\x08\xe8i51\xbf\x05\x1c\xd3W\xba\xa5\xd8\xa2&\xe1\xf9\xf6\x14r%\xdb&\xe3h\x95\x03\xe1\x92\x16\\\xb8e\x93\xb4\x84:p\x99\x8dE\xec\xb3\xe5/V4\xfd\xac\x10U\x9f\xed\xben3\xa7\x04\x1eVuM\xcc\xa3%\xec\x07\xf8\xdb-C \xc4v\xfc\x8e\xf9\xc1\xd6O5~N6 \xd1,9o\x0d`c\xf5\x14\x87\x8dKU\xd2\xb2\xf9\xd0\x18\xe3j=\xf2\xf4\x99\xb3Q\x83\x8c\x93\xa5w\xabL=\xfb\x8d\xa4AM\xca\xc6>\xa5\x81t3[6\x8f\xe8\xe8\x0c\x8d\x1c\x19\xa8\xa1\x0d\xa1VC\xf0 \\\xb5\xf2rpl\xac\xb6\x82\xa5~\xba9K=\x90\x1f\xc2j\xd5B\x8f\xfd\xcdj\x15g\xbe\x1d\x89\x96.w\xbf\x02\xdf\xdb{\x0f\x13\x83\x1d\xeb\xb5n\x80`7;\xd4_\xab\x0f\xf3\x81\xd1H\xaa_X\xf7\xaf~]Q\xbd\xef{\xe5\xceM\xa1\x9e\xe8T\x1b9\xd9\x86\x84\x95\xdeCyP\x011\xc7@I\xaa\x9f\xaa\xa4b\x1f\xe4\xd9\xf0z\xfe\x8e\x89\x0dJ\x93\x9b>\xfb\xb2P\x8e\xc1\xdayH\xe6ME\x80\xcc\xb0\x14\xab\xc2\x0f\xcb\xfb\x11M\xc7\x97\xce\xa8\x0f\xac\xa7\xe1\x97/\xf6\x83\xee\x10\x1f\xa3\xf2;\xd5\xd9jO\xad\\;\x99M\x94 \xb6\x1b\x95>SPk z\x0f\xd0a\xfdI{\xe2\xb8\xc8\xf4\x97 0\xc2\xde\xa6\xa2\xbb\x16\x16i\x08\xbc\xcc\xd6\xa4m1\x17D\xc3\x81\x0c\xd2\x9b\x83\x11\xb8N\x9dJ\xd7[jF\xab\xf7\x04\xc1@\xd5o\xd3\xbeX+\xc7&\x9dW\x11\x10\xe2\xd8\xe6\x1d\x88\xc0\xd5#X\xe5\x03\xeeW\x9f\x1cJ\x17\x98\xb4Ji~\x94\xeb\x1b\xbc\xa6td\xbb\x9e=\xa6\xd9Z\x07\xfe7\xfb]\xe1r\xa1\xb0\xbdGq\x8bw(\xeb\xf6\x80\xf8h\xe3t\xc9\xf3\xb0$K\x8b\xad\x13\xc3\xc4\xa0\xb9\xa25\xf3\xa1\x8c\x82\xacg\xb5\"\n?8 \xd2\x8c\x03\xda\xe5\xbb\xe1\x90x\xb0\xac\xb6|\xf1E\xd1\xa3!\x99\x03\x9f\xde\xbe{\x86$&\x87\x9a7\xeb$e\x01\x91\xd5\xdb\x1aI\x9d\x19\xb8(ab\x17\x81\x95 \xb6\xd5\xc57\x9b\xb4m0$\xb4\x10\xea{\xe2E\xcb$\xe6Cc\xe5\x1e`\xa6=-$\x909\xbb=\xd5O*|Y\x0f)My,5\xd0f\x1fb \xe1,\xect\x93\xb5\x08\xc6m \xcc\xccVii\x11\xb5]dHGo\x0f\x1e\x90\x89r\xa4+\x1d\xc6\x14\x85\x93\xd9\x8e\x85p6\x88\xb1\x03E\xb2\x08\xfc#\n\x88sF~T\xb9\x84\x13\x19\x132%;\xcfI^\xf1\xee\x96\xb7\xfb\xc5^\x1bf\xd9v\xb2\x89\xbbtH\x1c=\xe5\xa6'\xc2\x94\x1c\x92T\xea\xd8H\x8dE\xb9\x1c\xa6$\xbd\x05e\x85\xf8\xbf\xc1\x96#\xbakn\xa1y\xad\xaf\x87\x87\xda\x13A\xdfe*\xb0\xf1\x0f2d\x9b\x1bV\xee?d[,8\xd3#\xda\xe3O\xa8%\x809\xbc(\xf4\x02\xbe:\n\x91\xe0\x90\x845\x19\x81D \xe07\x0b\xc9(\xee\x03p\xaa\xc0\xd4\xe6\xa8\xa0\x8a\xb0@\x15\xd9P\xb7E\xe2\x95\xd0@\x15I\x15\xef}\xac\xcb\x06\\\x18\xe8\xa1\xec#o\xbf2\xc2\x86L\nO\xc2B\xe9Ut\xbf\x1fv\xb24\xe8V\x18\xaa).iEU\xd1m\xc8g\xbb,\xb7\x1d\xc5\xd9\xa4\xd7s\xe2.]\x10\x95\x0f0\xf2URb\xacMP\x9a\xd9\xa4\xc8\x1d\xca\xac\x1a5U%\xa16{Y\xf1 r\xaah\x88\xbb@\xd7OS\x92\x8d\xb9\xdb\xd6Ou\x1a\xbb\xa5\xd9d\x03\x896\xef'\xd1&-\xb2\xba\xd6\x90\xac\x9a\x18\xc4\xc4\xdd\xc5\xfc\x95:1fJ\xcd{E\xdbT\x8bm\xda\xddp8\x0d\xc5\xf0\xfd\x1cdK\xe9]@\x1c\x01!\xca\xa2\x91\xdeR/\xb4\xe2\xfe\x9c+\x1d\xe3-c\x1b\xd8\xd9Y\xf7\x9fy\xb9\xfb>i\x8az\xda0\x08\xeb\xc9\xcb\x14\xc62\xb2\x11\xee\xddZ\xdc\xb7q]4P\x95\x14\x16+|\xd1F2\xe4c\x85\xf4T\xa7[VS\xeb\x95\xafx\xba\xaf\xb8\xd0iA\x06N?_\xc9<\x88h\x18v}\xd9\xec\x05\xca\xf5\xea\xa7\xd5\xf9\xec\xad\xdb\xdf.*\xd5\xdaA\xcc\xd0\x0eb\xa8v\x10+\xb5\x83\x9em\xc8\x16\x0f\xfbI\xb2h\x96Qo\xf9\x91\xcdos\xa2.X\xf6!\xbf\x0c\x03\xafp\x94f\xe9\xb9\xe6\xf2#\xcd\xe5Ov\xda\x18w\x194\xa7w\xedn\xa4\x14\x99\x0e\x0e\x80=\xd3\xaf\xe4\x8f\xaf@I\x8b\xb7\x81\x0c\x04\xd7\xcbv\xc7g\xc8\x98\xd8\x06D\x05\xd5\xb3\x8d\x07||\xc6\xce\xfb|W\xcdl\xdf\x8d\x7f;\xe1s\xf3~\x10\xcc!*)\xe3B9\x86[\xdcQ\x15\xa8\xae\xa6\xae\xa6l+j\xa9\xacPbS\xf9\xfa\xb5\xaf@\xaa1\xb0\x1b\x8fQ/\xcc\x8d!L\xedc\x02\x96\xf0\xb4\xdf\xa6\xb2\x93\x19\x88\xcd\xaa\xc56R*X\xdd\xc9\x96a\x82\xd7l\x1d9\xcd\xb2no\x17\xc9_\xef\xde\n\x94\xb1<\xbdY]rp\xc7*\x7f\x8d\x057\\ys\x9dD\x8c\xdc\x98\xc9U\xed\x00\xba{\xb23\xd9\xd9\xc3{\x95\xfc\xb3Z*\xa3s\xf2\xa4:\xed\xe0W\xf3\x7f\xffo\x9dy\xeb8\xcc*\x04\x0c\xa8\xe6\xcd\x92s\xd8=3~^\xc3|\xe0\xb3\x1dkmy\x01X\x0f\x0cp\xab\x91i\xb1\xb2\x95V\xb2\xcf\x1b\x9d\x90F4\x9b\x19\xc7\xf2\x0e%;0_\x12CR\\Y\x19\xc1\x12\xda\xf6?\x18/\xb53^\x86^\x0e\xb7\x9a9\xed\x0c\xa5\xa9md\x1a\xdf\xba\\\xda\xddvG\xb8\xaa\x0e\xd2\xbf\xca\x04\xd7\x16\xdc\xd5r\xda\xe3\x96\xb4\x08\x02m\xbbS\xd6(\xc5\xd57@-\x8e\xd3\xbf\x891\x17\x1eb\xe4I\xdd3\xba\x0e1\xf2\x14\xb1\xe6*\xcd\xad\xf6'\x0d\x07\xa79x\xa4\xaa~\xbai\xd9\xacd#\xd5S\xabb\x1e_\xfc.6E\xd8D\x12p>%L9\x8f\x0d~g\x10\xef\x97\xaa\x1a\x87:_\x90\xaag\xfc4\xa3Y\xe0I\x1e\xca\x10\x0f\xe5);6\xa3\x19\x9b\xf2\xd0\xbc\xb4NP\xea\xe5\xb4\xd5k{\xd3\xdd\xa9\xe0\xe2\xcb6)\xe5\x8a\xb4\xe3\xb4V\x8b\xa4\xea!\xa8v\xac6EN\xfd*M;*5\x0c2\xfaUX\x1f\xa8\xb6\xfa}\xa6\xa9\xa8\xda\xccW\xc1J\xed\xcfV0\xad\xe6\xd9\xb2\x8a\nP7,\x0d \xc03\xaa7\x18\x12>\xa6\xbe\xff\x81\xf30\x88\x16g\xdc\x0dk\x18\xe1^\x1c \xef\xee>2\x10\xbfD\xfa&\x14o#@\x8a\xb5\xcf\x9a\xe7\x0d\xa9\xc5\xb8o\xe1Q@\x15\xc6eD\xd3|p.\x0eH\xb6L\xf8\x15\xacjA\xd8I\xfd_\xe7\x98F\x11\xcf\x88\xc0<\x84\x12/\xa4iJhJh\xf1%\x07\xc1\xee\xea\xd6\xb8\xd0\xb5\xca\xca%/\xce\x83\xea\x92\xa8\xce\xa1\xa6\x9bM\xf3\x14X\xd3\xac\xdb\xe6G\x9b\xbb\xd4\x10\xfb\xb0R\x9dB5Z\x81\xaa\x8e\xe9-\xf2\x97z7\xc6A\xfa:\xaa`\x17\xe0\xdc\xea\xb5\xe3\xb2\x19\xbcE\xd5k\xb2\xf6\x9en\xd8\x1c\xa3\xea\xba\xc3w\xbc-\xb5\x0b\xa1\xceU\xb5a{\xcc\xea\xdd\xa6\x1e\n\xde\xa6S\x96}\xab\xf6\xe8\xaa-m)1\x88\xc9a\x9b\xa8\x81\xdf\x07j\xb0\x9c\xc5\xfb\xb6\xb3\x189\x8a{\xac\x1a\xe4\x0e\xb5f\x87\xfa\x8e\xfbu\xa5\xc5[\xdb\xad\xfa|%\xf5\n\xab\x83jbbjb\xe2j\xa3\xbb\xcd-\xad\xbeb\xa8\xbc\xa0\x08\xfcc@\x1e\xc9\xf6v\x93\xf8\xaa6\x91\xa2\x9d\xdd\xd4\xf0R\x0b\xec\x1d\x02\xec\xd9\x88\xad\xe2\xecfJ B\xa5\xf1\xb9m\xe2\x10D\x0bW\xfa!\xa8\x93 m\x14|*\xfb\xc9\xaf\"\x96\xbc\xe4^\x0e\x12\x0e\xe55\x89\xaf@HfSb\xd06\x0b\xe38a\x1e\xf5\x96\xacP\xe5\x967P\xdcEn1\x9b\xf2\xc0\x9aT\xb7FX\x1d\xca0^\xceo\xd7{\xde\xd6h$\xc6!\x17\xbd\x1f\x8d~\xbb\xdecNm\xaf\xd5\xce\x02\xab\x8eW\xf3\xf0\xef\xaf\xc4^t\xdb\x1a\x04\xba\xadQ-\xda\xea(\x930\xce\xa3\xea\xd8\xd6j/qK\x8d\xda\xa0\xf7\x82R&\x15b\x03\x0f\x1b\xc0Q4\xea\x14\xb8\xc0\x01\xe7\x19J\xd0\xba\x07\xd1]j\x99\x99\x91Y]k\x86\x07\x0eP.\x06\x86\xf39\xe1\xcfI3\x80\x1d\x89\xea\x9b\xb4\x12\xb5{G\x1a\x03e\xcf }\x0e\xbfh\xb5t\x80\x96~N\"2\"\x01\xf9\x9e\xec<\x1f\x80\xbc\x8bU\xaf\x91\xa2\xd1\x08-\x16\x90\x11\x89T1@\x04\xd5b\x01ZL\xef\xfe\xe89\xc9G\xa3\xe7v^\x1dB\x02\xb71\x8dHK\x1b\xad\xb0\xac$R\x15\xa5\xff\xa9 a\xae\xb3j\x0b\x83\xf4(\xf2XZ\xa5\xc8m\xa7\xacm\x89$\xc9lr\xbe\x89\x96W\xdb\xdc\xf5gIk\xea\n\x06\xea\xb5\x88\x08\xda8\x07i\xe8\x88\xec\x0e\xbcS\x05\xd1\x01*\xf1v\xa6x\x1c\xb1\xeb\xec4\xb8\x0c\x83h\xf1\xdcJ\xa7\x93\xda\xc5X\xa6\x14Z\x9e\x14\xd6q\x12\xe9\x0e\x86d_2A\xe3H\xab)>x@j\xf8\xcc\x80\x90\x11\x0d[\xbeJ\xcaE\\\xc7 \x16c-\xfd\xb4G\xe0\xb6;\xd3\x94\x04\x981,=\x17\x8d\x9e:A\xe1U\x0fx\x1c\xab\x9d[\xcedVWa\xba\x9b\xa8\xe2vD\x81\xc0\xd0\xb7\x15q\xdc\xcb\x85\x8aEj\xfa\x08'\x07\xf1\x1bL\x19h\xb1:x\x16\xef\xcb\xfafqJh\xf3\xb0\x15\x83\xd7\xb5\xd7 (\x02\x07)\xd8\xce\x04\xd1B\x85M\xb4\xb8\xa0k\x9b_Qfv\xdb6\xf2\xf1<\xcc\xd3%\xb4\x82)-\xf4T\xaa\xa1\xf3\x86\x04Gv%+\xbb!e0\xc9`\x08\x85A\x17m\xee\xd6<\x91}%W\xcb d\xc4\xadKT\x8cX\x82 \x97\xe1\xe4E\xa5n-b\xe1 \xa1\x81\xc5Qd\xce\xf8\xf9\x90,\xc7\xcaC\xd7\x99\x9a\x03\x97U\xa6C:\xb53\x87j\xd8\x18;\x1c\x17\xc7v.\xde\xa6\xa9\xd1\x18&lu\x18$Du\x81\x18\x19\xf5\x01h\xde\x19\x96M\x06n\xb1\xa2\xaa!\xf8\xc5qv\xc5\x8f\x92\x05\xf0\xb5\"\xa7\xe2dx\xad\x1c\xefW\x1b|\xc1\"z\x192\x7f*0d5\xa7:\xc4X\xdc\x95\x9f_\xbf{\xf9\xfe\xe7\x8b\x1f\x8f\xde\xbd|s2%\xc1\xd8\xa3\xd1\xa7\x94\xbd|\xff\x96\x1c\x92\xab \xf2\xf9\x15\xc1\xca\xa5,\xfb\xb1Vy\xbb\xe4\xa81\xe1bQT\xc7\xa6\xf1\x85\x13\xdd\xb1\xce\xaa\xd5\x10\x88Sb\xab\xb5\xd6 mV\xdar\xfc\x96U\xb7U\x9a%4\xfeAJ\x1faQ\xf4\x13V\xeb\xdb\x0drH\xf8X\x06\xf0W\xb1\x89\x96\xa0Z-\x0e@\xa8N\x124r\x99\xb1\x81\x16\xd7v5\xe8X\x892o\xdb\"%\n\xbd\xaf&\xadx\x14d<9\xf5\x12\x1e\xca\x88\xe8]\xd3\xaaQf;\x94x\x98\xeb\xb9r\xad\"\x8e\x9b\xbeV\xdb\xda$<\x8a\xc1\x97U\x0c\x89\x93B#\x1dD\x8d\xa2\x8aN\xcc\x11\xe9)\xd3(\x17T\x1b\xd1$0f\x0c\x86\x06\x02\x05\xb4\xc6\xeei\xb7\xcfI\xc7U\"\xce\xf5\xedr\x81\x1eF7\xf18a!\xa3)so+\\(\xde,$\xd7\x12RoEr\xf5S\xc1.\xc4`?K\xe4\x067\x1d\x86\x0eY\x91q\x88\x8c\x03\xc4\xc5\x8a\xe9\x82\xfd\xf2~>O\x99\x0c\xd82\xf6\xb5\xc6\x82\xfe\xa1m4\xe4:z\xc3\xe6\x88\x00\xf5FW\xf5\xeb\x06U\x9d\xf1\xaaX\xf0+\xc1\x82\xceC+;\xbfm\xa9\xf1O\xd5_\xb7\x9a\x89\x92\xf8\xdd\xaf3\xaa\xea\x9acb!~\x1b\xd7\"\xed\x81\x16\xf6\x9e\xe0\x91\x16&\x8f\xeb\xf5\x84\n\xbe\xde\x1e\x0f\xa7\x97q\xbe\xc9\x10B\xd0q\x10\xfd7\x83qi\x8e\xef\xcb\xf7ou\xfc\x8d)I\xda OVqvcT\x9b\xb7\x02\x0b<\xf3!\xcc\x17A\xf4c~)\xb8\xdf~\xc0\x9f\xb2 L\xc5\xd9\xde\x05~\xb2\n\xb2\x8c%S\xf0\x9bg\x05\xfd\x11t\x88\x8a&\x87m\xb0\x05\xef\xe8\x95P\xd5\xf5\xf6/\xe0\xbc\x1e\xd7\x99\xa6\x00g\xb1\xa8e-\xa9\xb5\xf7\xb4\x9e\x9eV\xd4\xc8'\x8f\x9e\xd6\xd5\xc8\x15\x17\xb6[\xff\xbe\xd7-\x03\x01\x8e\xe0\x94\x85r\x08_G\x82\xd9\xa5\xf8\x98+\xd9H>N\x80\x16eE\xa9\xea\xc0c\xf1\xb9\xcd/v\xca\x7f\xb4\xbc\x97\x8e\x0b\xa2\xaa\xc3&\x92\x8eK\xa2\xce\x85X\xe3\xbd\x0c\xad\xea\x02)+\x1dP\xa9\x1f \x94S\x17D\xddu\x04\x94\xa4\xa8\xa2\xb0.F\x9da\xc6\xad=:\xb6\xd1w\"\x9e\x05\xf3\x9b\xa30\xc4\xbeU\xed(*\xf8B\x98\xfbv\xc9W\xbb\xe5Aa^Pk'\xa8Q\x94\x94Ldx\x99D\x8c\x14\x0c-\xd5\xca\x86\x8e\xef\xd5\x06\xc1\xab\xad\x83z\xc5\xb7\xb2A\xc0:\xdf\xf1\x9d\x8d\xcd\x12Z)l\x9b\x81\xc1&\x0d\xae\xf8\xa8n\xfb\x18b\xa6`W\x18hl\x11\xed\xca\xba\xa1\xc6]y\xed\xcd\xae\xf3\x82,\xc5>7\xb0.\xcc&\xcfR.\xbf\x12\x91%\xee\xdc\x14)\xa4C\x12\x0f\x86$\xa8\xf2\xee\xf3\xba\xe1\x15\x14\xbf\xe3\x01\xd6\x90\x05*]\xea\xddz\xdc\xa7@\x1dl{\xa8\x18\x8f\xb6h)\x94\xd78\xdap[*\xa8%\x96\x8d\x98KO\xe6\x85\x90\xe0\xc1\x03\xe2\xa4\xfa\x80\x01\x85/M\xb9\x8a\xac-\xd71\x8f-\xc8W\x8cZ\xf3\xe8l\xce\xeb\x82e\x928N\xa7$'\x87=N\x00\xcd3\x16tt\xd16u}\xff\x91F\x8b\xd6\xa0,`\xdb1\xce\xd8u\xa6d8vP\xb8\xb3\x1d\xfby\x1c\x06\x1e\xcd\xac\xd7\xb5 \x84\xaa?\xe3\n\xcb\x9dI\xb7\xa6C\x92\xc8\xd3\xca\xff\x00\xbb\xcd9\x89|@\xaaI\xe6\xd8\xb9=-rK\xcc\x16\xb6\x9e\xb9-\xbc\xa1\xf8VC\xed\xcf|X\xe4OA\x03\xa5\xe9\xf7\x95\xe0\xcc\x1e\xe9\xc2\x07\xc4\x98$\xb9\x12*\x84\x8dX4H\xb2mh\xe5-\xb1`\x9dv\xd4-k\"\xe6\x174mz\x86\x05\x95\xf3M#o\xc9!\xdep\xd7tKH\xb9,\xed\xb0\xd2\xb7\xc1\x9c{y\xda^iP\x02v\xd5\x99k\x7f \xb0\x86\x8f2\xd7\xe6\x91\xb0]$\x90\x8fa\xe2\x0b+\x80\xe2\xeazH\xf21\x8b\xfcf\x06>\xf9:XC\x9f\xd8=\xa8\x07\x00\x82.!b\x98\x04P\xb723\xf5\xd1\xaf\x8cpu\x14\x07\xe4\x90\xec\x10A\x04g\xfc\x14\xd40\xdcA\xe7~\x0eA\xf2\xee\x85<\xd2h\x02\x1f\xdfPa\x15\xf1]p\x06\x12e)\xec\xe8P\xedh\xb7>\xc6C=\xea\xaau\xf6\xe5\xe8)\x0d\xa7z\xf9\xd0,/^\xcd\x99R\xef\xd5\xae\x87\x9bt]\xf0\xbb\x1e\xd9&-\xee+c\x13\xadV\x90)\xde\x9bX\x0c\x06\xe03W\xb94\x8b\xf5\xf0p\xbb\x03#\xad\xd2\x14\x8f=\x1e\x864N\x99%`k_\xf4\xe6\x8bs\x83L\x89\xd7\x81\xe6\x04\x9c'\xd0W\xcfu\x8a\x90\xf3\xa9\xf5\xb8\xear\xb52\xd4\n\xcb]\xe7V\xf7icX\xbagbQ\x90CIL\x00\xf2\x801!\xd3\xe2\xd7\xf7\x05\x8c+\x01X\xe4\x0f\x15\xa2\x03\x08\xf0Zi\x94\xd5\x99,\xf2\xc1\xd4\x14?\xd9d\xba\x9c{\xc7[\xd2\x84z\x19K\x1ci\x19\xce[\x8e=^\x14\x16\xcb\xa4R4!\xa3\xa2\xb8\x18\x1a\x8c\xeb!=\x84\xb0D\x1d\x1b\xc8)\xd3\x86\xc8\xf4Q\x81\x1eN\xf6\xa5E\xd4\xb9\xc1f\x81;8\xef\xdc\x86DI\x1d\xde\xd2l9^\x05\x91[\x0e{\xc7G\xf2\xaa\x93\x03=\xad\x94L\xcd\xca\xe4\xf4\xb6\xa9\x95\x89\x035\x1a\xb3\xebL\x94\x7f\xf0\x80P\xf2=i\x0d\xc7C\x0c|\xdd\xe2\xa0\x8d\xa86Ri\xff\x92Z\x01\xed\x9aJZ9\x15\xb4\xd6i\xc7xx\x1a\xd0f7FTo\xc1\xe9\x87\xd7\xa7\x87\xf3\x0d\x11\xa0~\xe6%\"\x0c\xe1L\x15\xe8\x9aK\\=\x04\xc7Eb\xc1\x1f\x85!\xd4\x96\xba\x10/\xe8{\xc0 n$\xb8\x0c\xf9\x959\x00\xcb\x99q=U\x91\xa7+\x82\x8d:\xd7\x08\xb6\x91-\x8a\x1a5\xe1\xc2{b\x1d\xfeN\xb1>.\xc5\x93\xb3\xbc\x11\x13T$\x17\xdcKbWB\x00\xe1\xfdx\x1e$\xa9t\x91_(\"\x18I\x95\x82\x9a\xdb)\x12\xb1\xdb{n\xff\xa0\xdd\x16\xca\xd4\xa0+\xf5\x1a+\xea\x86\x8d\x82\xb2\xad\xa5\xeaCuH\xff\xd4\xfc\xd5\xdb\xb3G\xc5`-\x01\x9cl\x18\x9f\xed<'\x91\xb5'{\x92\x13,\x88\xbf6\x1cJ\xc1i\xed6\x89\x80\x1bQ\xa4\x90Fr$ /\x94\xea$%\xdf\x9b\x86b\xf6\xad\x16\x81\x96)\"\xd3\xd4\x8f\\\xceS\x92\x91\x11\x12\xa6\x8a\x90FHi\xfd\x04\x851b\x05\xb8\x91\"\x07\x8c\xbb\xd1\xe0\x9b\x9a\x7f\xec\xef\xedX\x8c\xb0\x8be(\xd5\x9c,\xfc\xfa\x96b{\xb6\"\xb0\x01WVe\x11$%n&\x13\x137\x1a\x14\xfaR\xc6:\x13\xb8\xc2\xf1$\xf1\x98*\xbb\xb6C\x88f#\x93D\xb1)\xd9\xda\x92\xf1mhR(\xda\x7f\xe0i\xa0\xb9\xb4\xad-w\xf2\x84< V 1\x84\x0d\x15\x8d;\x0f\xdb\xa4c\xd8\xac\x17~\x80F\x1e< {\xe0\xe9\xa6\xc9\xdb\xdc\xa1}\xfd\xda\xa1\xb9^\x97\x899\x19W\xec+\xe0\xf2\x8fL\x8b\xe3e0\xf6\xd9\x9c\xe6a\xf6S\xc0\xaeD\xa6$;Pd\xb6\xe5nI\x17\x83\x16_Qc0\xba9\xac\xder\xaa\xd4)\xeak \x84:\x118D\xaf\xa4W\x95\x9c\xa5v{\x13\xe0\x1d]\xb1\xfb\x9dwg\x99e\xf1\xf4\xe1\xc3\xab\xab\xab\xf1\xd5\xde\x98'\x8b\x87\x93g\xcf\x9e=\xbc\x0e\x83\xe8\xb3\xd3\x94\x90!\xf0\xbf\xbc}#\xca\xec?\x8c\xe8\x8a\xa51\xf5\x98\xd3\x94\xa05\xf1\x12\xf5<\x16e?\xb2`\xb1\xcc\xa6\xc4\x91\xaf\xa3%\xbc#>\x9a\xa8\xe7\xe5\xab<\x04O\xd6;H\xb6\xef\x07Y\xb0\xb6d\x86\xc1\"\x12s\xff\x03MY\x18DL|O\xa7\x8d.U\"\xf6\xd10\xe4W\x1f\x19O|\x96@\x99\xf2\x15\x85\x8e\x97\xf4\x92e\x81\x87\xb7b\x15\x87A\x96\xfb\x966&\xf42\xf0^\xf1d%>\x04/\xa39OV\xd8wR\x0fn\x07\xb1Z\xb2, .\xf3\x8cI7\x88N\xe5\x1d\xabJ\xe7\x8b\xa5g\xc2\x8bw\x0c>\xcf\xf8G\x06\xc6\x92\x02\xba|\xc3`\x7f\x0fVy\xb6D\xdb)\xc6\xfcU\xc2\xfe\x91\xb3\xc8\xbb\x99\x12\xa7\xf2\x8e\xd4%\xf2?$|\x1e\x84LA\xab7\x0b\xac\x98\xcf\xd3e0\xcf\x14\xb4x\x1f\xa5\"\x01+p\xc9\xaf\xf1V\xb2E\x10\xe19\x01M\xf1\x8c\x1b4\xd9\xa3\xa1\xf7\x16\x0e`G\xffD\x1a\xe2\xd1\xb8\xd8\x0f\x1e\x8d\xed\x9b\xc1\x0b\x83\x18\xffN\x18\xc4\x1f\xa8\x18tG\xfc\x1c\xc54[Z\xca\x7f\xcca,\x01,\xc9\xd1\x91\xd4\xb5}\x8a\x02\xc1w;\x95w\x0c\x9e\x87\xb3#\x1b?\x98\xcf\xf3\x94\x1ds\xe9\xabsJ\x9cZ\n\xd2\x1b?H$go\xa9\x11\xbc\x9eZ\xf2\xd6\x81m |\xbe\n\"Z\xc1\xef:\xa9\x0d\xbd\xfb\xb9\xa5:|\\}\xbca\xcc_0\xb5\xb7\xf5O\xe4[,dkj\xed\xb8\xd4[\xfb\x81z\x9f\x17 \xcf#_\xd4\x05I\xa3\xcb\"\x0d\xab4\xc2'U\xd0L\x91m\xda\x04\x9b\x9bD4\xfc\xc8R\x9e'\x1eK?\xb2\x7f\xe4A\xc2\xe0\xa3\xb6<\xe4\xe3\xf3 \x0c\xd1\x0f\x88\x8c\xf71\xf5\x02\xf0k#\xdeF\\\xbeZjQ\xa8\x08 -\xa8H\xeew\xdb\xe72\x96|d\xa9\xacB\xfe\xb6V\xa1q\x99\xf1\x86\xc1\x86\x9c\xfb\xc7\x02\x13\x08P\xf12\x02\xbc`\x035\xba\x0b\xc0-\xfd\xe5^\x9e\x8a\x99\xc5\xfb\xc2\xa3\xec\x15]\x05!T\xc5\xa3l4\x877\xb4\xa2(;\x05]\n \x98\x06\xbf\xa3\x03\xa7\xc0\x8e\xfc\xff\xce\xd3\xcc\x04\x1eQH\xb2\x95\xc9\x12\x96y\xcb\xa2\x80|\xb5\x02\xdf\x84eC\xc4\x8b\x05\xf0'\x9a\x04\x12U\x00\xe8Z\xbeZ\x80\x7f\xd6g!\xc0^\xd9\x0eC\xa9\xae\x83\x0fg\xc2Wx\x06\xbe\xc3\xe7\xf8\x0e_L\xf0\xe4]<9\xbc\x89\x97\x8a\xfe\x82\xdf\xa3\x08'\xbe \xf3}\x12\xb0(\x03\xcc\xf0#O\x82\xdf\x05\x9f\x18\x16%y\x99;Z\x16\xd9=\xea\xfa\x89%Y\xe0YjZ\xabL[=\xe0\xb8\xdb\xd1?1\xa8\x84\xfa\xa2:\xd0\x12\x99K\x9a\xb5\x91\xd6RNo\xc2\xca;\x02\xbf\xa4\xd1\x02Ned\x98a8\x8e\xfc\xf5/S\xe2\xc0\xef\x11\xf5\xd7\xa3k\xac\x16\x91\xfb> \x16AT\x02sxG\xe1\x03\x9f\xf1EB\xe3\xa5\x85\x90\x0fVt\xc1L\x92\x01\x12ZI\x86 \"xU\x11\xbe\x86\x80\xd8\xf1X\x8c/\xeb\xcfx*\xbeJ?\xe3_\xf8\xbc\x87'?\xc2\x93Y\x12\xb1\xf0-\xcd\x92\xe0zJ\x1c\xf3\x15\xe9\xad\xcc\x16\x93\xfa\x06\xe4UE\x892\xc9R\xca6\xd9\x9f\xd9\x0d\xdci\xa4P\x95\xfa\x8d\xd6qs\x1a\x8b\xd3^\x01\xaa\x17\x1c\xf2,Xi8\xf8\x89@Iy[\x81;\xcdW\x14:\xcbXr*p?\xac\x0b\xf9>Je\x02V@\xa040\xa6\x95'\x8d~\xb7\x1e6`\x8f\x0e\x05\"v\x14-\x00\xe96\xd2\xb0r\x1cp\x012\xb2+\x9a|f\xc9 \x90\x1c\xf2\xf7\x88\xa1\xb4\x86\xcc|\x1b\x18\x80\xab\xc0\x0ex*\xaf\x085h*o\xa1,\xc0\x05\xd7c\xbeZ\xa15\xf60\xde\xac\xb0?\x07>\xac?\xe3\x0d\x85M\xf1=U\x84\xcb-qV=\xc9R\x9d n\x87\xcb\x96lE\x15\xa2\xc6>\xcf-\xd2\x82(_\xbd\xf72\xba\x86\xf5[\xbe \xdf\xd0R]\xa4\x12\xae\x89\x164O\xbaa\xc73\xa5<\x04\xcd ld\xa7q\x00\xd9\xf2m\xdc6_\xb3d\x1e\xf2+k\xa6\xd8\xe4Z6:%\x8eN\x1a\xc5*\x0d\x1b\x17\x05s\xb6\x0c\xbc\xcf\x11KS\xb3\\\xa6\x13\x91\x821\x0d\xa2\xec\xbd\x92\x08\xc1\xcb\xc8&\x10\x8ai\xc4S6\x018\xf1k4A\x81\xb2e\x81&\xcb\x17\x1cRP\xe7\xb5\xf5\x88\xa4\xda\xcb\x9a\x07v=\xc9^\xaa\xf6)\xeb78\x1c[\xa0\xee\x0e\xe0\xf2}\xc4 \xc1V\x00\x97\xa3\xc8\xac\xa3\xec\x17]\x8f\xf8m\xad\xe2(\xfb\xd5\x80\xfb\xb5\x05\xeeo\x06\xdc\xdf0\xb8\x84\xa5,Y\xb3\xa30^R\xf0\x1bo\xbc\xb7\xc1\xa71\xf3\xb2\x8fby\x9b\xa5\xcaT\xb4,`\xee5+\xc6\xb7\x92\x80\x94\xc07\x9d \xa2r|\x18\x136\x17#(\xfea\xd5\xb1\xf9\xaf2\x17\x1b\xb2\x82\x9ey\x0d+\x0b\x00U\n\x08cP\xba=a1\xa3\x19(\x89A\x81\xe2\xcd\n\xfbR0\xe1N\xf1\x1b\x85\x93<\xe8\xc9u\xc6\xa24\xe0Q\n\x05\xea\x89-%_1\x9a\xe5 3\xcb\xe9$\xb4\x94\xd2oA\x074\xcdCK\x16\xcflR\x94\x04g7\x12\x1c\xf7\xa6\x1e\xb5\xb0\x87)c8\xc3\x9f.i\\!I!\xa1\x95$MC\x1e[\xbe\xa2 \x184\x8fyyH\x13C\xe8SO\xc2\xbe\xa5@N\n\xb9\x84SO\xc2K\xd9\xba\x1b'\x8c\xfaoY\xb6\xe4>\xd4U\xbeb\xf5\x94\xda]\x02\xb8|Ca\xfd\x97l\x1dh\xe1\xa5\xf9\x8aB\xb3\x15.\xe0\x169kKN\x90y\xcb\xb3 \x84\xe5h\xbc\xa1\xf5\xf3X\xd3\x86\xe2\xb7\x95.\x14\x99\xa5\x0c\x02@\xed\"\x884K\x82\xcf,[&<_,\x8dc\xb3\x92\xdevvV\x00\xcd\x03\xb4ZC\xdb)*o\xb8,\x03\x94\xf0\xcf\x96\x95 Y/i\xba\xa4IBeWE\xca\xc8\xd7I\xf8\xa7T!^\xae\x81\xa2\x14\xb7\xaf\x04\x01\xf3&\x88\x98G\xe3\xb2L(\x13Z\x0b\xfc7\x0f\xa2j \x91b-\xf26\xc8\x04\xdd\xb1\n\x8c\xa6\xad\x8a4k1s\xbe\xa1L\xeb\x8c\xf3\xcfL\xd3\xc2\n\xfc\xcaB\x0c\xa7y2\xa7\x1e;\x95X\xc81_1\xe8\x1b\xb1\xd4\xdf\xd0h\x91\xd3\x05\xc0W\x12\x90\x12\x19\xbd\x0c\xa5\xb7&\xb1d\x8c7\x146Y0 \x02\xd4/+\xcc\xaf\x05\x0cv\x96e\xec:;\x02\xfdV\x01\xc6\xae\xb3\x91\xd4v\xb5\x80\xbed\x1eO4\x0e\x00p\xbfH\xb1\x141\x91/\x94h\xc3\xbd\x02\xa0\xa0\xf9\xca\x17\x0c\x92\xa3\x1b!+\xe98$7\xc7%\x019. \xc8E;k\x14t\x91\xd6\x86\x06\n \x13\x05\x94%\xdb\xb6\x7f\x1e\x05\x9e\x8d\xb7Qy?\x04~\x00\xf5\xc1\xdb\xe82\xf0\x03{E\xa0|e@\x83\xaa:\x0e\x9e\xa5\x1fXr\xb2\x92\xc0Y:\x8a\x05\x85\x8a\x11\xbf\xeb#\xe3>\xd7Y\x8f\xca\xeb]\x0c\xf8G-\xaar\xd6#%\xb6\xc2\xc0^\x9b\xb2%g=2dM\x18\xf8\xdb\n\x87\xe8\xacG&\xcb\x88\x15P\xdb\n\x19\xd65\xf32\x9e\x9c\xcc\xe7\xcc\x13xF\xbe\x8e\x18\xbcc5\xb1$\xb5\xb1jk\x96dG\xfe\xfaW\xa8&\xc9@\xf0\x86\xa1\x1d\x91Y\xca\xdd\x00\xb4E\xecVB\xffZ\x83F\xeb\x0e\xd8\xd5\x0f\xfcZ@\xca_\x16\x983\xc0 \nL\xbe\xa0\x90ip\x19\x846n\x18P%>\xacW<\xf1K\x89\x8fxk\x91\xf7\\% \xa9Q\xb7E\xeam\xb4\xc2o\x8cp\x9a\xf1\xba\x90\x95\\\xdb\xef\x87\xafq\x04p\x8d#\x80\xeb\xe3%\x8d\"\x16J\xad[@\x91\xf5$\xec\x1ba\x10}>\xf2\xb2\x1c\x88^\x07^\xa7T\xbe[\xc1\x13/\xe1\xa1\x01.\xdfm\xe0?& \x88\x96\xb0\xcb\x04\x15EC\xe6G\xb3\xd2\xb6\x1aO\x97\xfc\xaa\x00L\x97\xfc\xca\x06x\x16dF\x95\x99x\xb3\x82\xca\xab\\\x05\x89_\xe2^\xaf\xc2\x1f\xc0\xd3\xb6s\xbd\n\xa7\x97\x14U\x98\xb8^\x85\x11\xbe\xc8 \xe7\x17\xf8\x00\xd4\x10\xa5SLAG\x81\x8a\xb3W})\xa4\xe8:\xbc^\x85b\xcd\xea\xf6`J;D\xfa2@\x1as\x83/\xae\x1b|q\xdd4\x17W= \xf9\xf2\xefh]\xbfs\xbe:\x8a\xfc\x0fT\x1cQ\xe5K\xab\x7fT\x8a*\x1f)\x17\x02\x81\xc0\x95\xf5@\x11Dz\x1982Ug`\x84R\xcc!\x04il\x85\xa4Y\x1dil\x806 \xb9\xec\xdb >v\xd6!\x17z\x1b\x84Z\xe1\xad \xb0\xb2m\x10zI[\x8c\xdc\x8a\x85h\xcfWk\xb0WH\xd9\xc6\x8cL\xcd\xc8]\xa4\xaa\x9d*#\x02\x8e?\xb3\x9b\xd4\x0d\x06\xe39ON\xa8\xb7t\xed\n\x84t\\\xae\x08\x19\xe7vgH\x02\xf1\xeb\xc1\x03\xe2\xd2q\xe3\xeb\x12H@\x18\xeax\xdf$@\xc7N\xddu\x02\xc7\xedW[\x82\xfe`\x0e\x15\xa4\xa3\x85Guk\xd7T\x81\xef\xe2>>\x1e\xe3>>vw\xeb\xd5\xcf\xc16\xbdj\xcb\xaa50\xdf\xea\xf8\x05\xa69k\xc3;\x8b\x80\"/\x0e\xc8\xa4\xe6=\xb1i\xaeN@2\x12\x02]\x83o\xd0xIS\xe6\x7fd\x8b \xcd$\x15\xaf\x97\x10\n.\x1e\xe5\xf1~J\x1c\x1eID\x85\xa0)\xfdh\xd7\xf6\x06\xb4r\x11\xe5\xa0e\x90\xf5M@\xd9&\x16LC\xe4\x01^\x9a9\x19\x8f\x7f\x08\xf3\xc4\x19\x12\x07\x04\x01\x10\x1b\xfb-\x8br\x95\xf2\x8a{y\xaa~\xff\x95\xdd\xbc\xe4WQ\xf9\xf6)V\xbf\xdf\xf2\x06\xe8I\xe47'\xab\xa9\xa2\xbf\xa1EV\x8b\x05q\x87\x0b\x12\xfbf*\x0dM\xa7=\x0d\x82Mc\xd4io\xd3\xe0\xc2du\xda\xcfB\xd8\xb0j\x9dV\x8d\\\xf1m\xdb\xb17\x88\x1a\xed\xa6\xa5a\xab\x85b\x0f\xdb\xc4[\x8e\xbb\xb4KP&\x84\xd3\xc2PA\x07\xc7o\xb1\xf3\x92Q\x12\xa4\xf1I\x0b\x14\x8f\x05\xd0%\xcf#\x1f|5\xc4v\xd8\x90\xcd3\x13\xf8\x0d\x9b\xdfn\x94\xbf\xba~m<\xc0\xb2n\x0d\x8a\xfa\x9e\xbb\x16\x07,6\xde\x80~\x9a\x03\xa9\xcd\xfes\xc3\x93J\xac\xe6aH\x96Cbq\x10\xa7\x06\x9fC\xb4xr\xa0]58C\x91\x04|\xa6\x98\xd7!I\xc6\xa5\xea\xba\x8e\xb8\xf3Ry\xb7c\xa9\x0bf\x99\xd5\xfe\xfd \xf9\x8c%N\x93h\xfce3X\xee\x9aE\xa0\x84\x9aNImF\xd8u\x96P/\xd3wtu\xca\xa4%|\xf4\xd6\xa2\xc3\xea_\x0fdF\x0em\xb1\xd3\x06d\x8a\x9a[\x88'\xbd\n\xdam\xde=\x9a2\xe3\xd8\x9bZW\x9a\x1b\xba\x1c\x82\x9d;Y\x923\xe9#\x9e\x8f\x95\xaa\xed\x89\x1f\x80\xc8Q\x9a\xf1\xf82\xb6\xc7R\xfa\xa2\xd5\x07T\x8b\xd1!\xb8\x82\xc7\xb3\x8b\xf6\xc1\x99mo^qd\x96\xc7d\xf1\xe5\xbb}\xb8<\xe9\xed_\x87\xe3\xd6\x12\x17\x8b\xf4\xfc\x8eI\x89\xe0_\xaa6\xe9S\xdc\xd2 \xb5\xa6\x14\x19@n\xa4E{G\x0b\xeaT\x8b\xbdz\xb1t\xe7\x83^\xdd\xd2$TG\x97$m\xd5\xd9!\xd5\x91\x0edFZ\x1c94\\b\xfa\x1f\xf2\xec\x0d\xf8\xd3d\xf5\xe8k\x16\xaf\xa3%\xf1*M\x97a\xd1\x03u\xb5c\xb5\xc1\xc3\x8d\xaf.!\xf5\xae\xcc\x0c\x1e\x99\xc9\xe6\xaf\xbb\xc9\xfbP\x9c\xc9\xc9\x95\x05\xdbc\x94\x9b\xd9\xdf\xab\xf3J!\xce\xfc(\x8f\xdd{u&g\xae\xd2\xeb\xf0\xb1jM=\xdd\x97\xf0\x8f\xea\xbdZ\xaa\xf4\xfa(\xacUz\x9d\xe9Z\xa9A\xab\xc3/\x14|\xdd\x07\xdf\x8d\x1c\xcd\xfa\xe8\\*\x1e\xad>\n\x17e\x84\xaa?\xbe\xd6\xf2\xaej\xe1\xe8g\x0e\xbd\xe4\xe0G\xc0\xa1Q \xdd\xe3\x9dD~\xe5\xfdu\xc6\xf4\x15\x89\x91\xaa\xfd\x0f8\x97\x8a\x95\xf1h\xf4!\xa47\xc6\xcf3ya\x08)a\xe0}\x86\x1fUn\xc7\xe3\xb1,\x91C]>\xcf/Cv\xac\x81\xfd\x84.\xf4\x7f\xd5*\xf9S\xfa7\x90/\xd7A\xa6\x7fC\x8c7\xfd\xf2~]\x02\x15\x8d\xf5\x13\x0e\x1c\x92\x9f\xcb.)<3$\x0e[\xc5Y\x00Q\xcc\x1c\x16y\xc9M\x9c\xe9\x17_\xfdH\x12\x0e\x15\xce5{\x16D\xb1lv\x10\xadi\x18\x00\xd4\xe7\x92_\xfb\xccn>$pO\x02\xbf%k\x16r\xea\xeb\xff\xcc\x7fI3Z\xbe\xbde\x19\xf5\x8d\x94\xa2\xd5+\x93\xd5\x83\x97\xb7\\v\x14^\xde\xe7%\x94\xee\xf5\xaa\xe4\x06c\x9afL\xfe\xc8S\xf9C\xcd\x93\xf8\x0f\x12m\xe2\xc4 _\xe8\xc6&4c\xe5\xc0\x80s>\xc7t\xf1\xeb\xa4\x8c}\x96\x83\"~\xa9\x1a\xd2\x8c\x86\xa1J\xcd/WrV\xd2<\x8d\x99\x9c\xb9,X\xa9P\xd4\xf0\xc6soy,\xc8\x87\xb0xUS\x0c\xbfu\x07\xe1\xa5\x18\x08\xb8\x1f\x0b\x8cE\xba\xe6a\xbe2\x1a{EA\xf6\x0e?\x97\x8c\x85\xcey\x0f)\x91f\x8d\xd8l\xe7|\x9c\xf1Oq\xcc\x92c\x9a2w@\xb6\x05c\x16\x06\x1es\xeb\x9b\x95(\xcbg\x87G\x10\xe3\xb7\x99\x0bv\x98\x19\x8f-\xd9\x1c\x15x\x90;\x8a5Z\x0c\xc1KiFD\xb6\x89s\x0f\x92\x8c\x04\x91*T\x0f\xe3\x0b)P\xe3Cr5K\xce\x8b\x80\xd9\x00Y\xf3\xd2~\xa2PS\x91X\x08\x07\xae\xad\x16\xca\xce\x18\xe2P\x8d/\x12\xce\x81.}\xfd\xb2\xac\x1f\xa9\xe9\xd4^\xd3e\x9ee\xd2\x0c\xf8@\x06\xe0T\xdb\xdbHH\x8d#W\xa6\x08TF\x13FU\x9a\xf1m\xfdK\xf4\xec\xb8\x95\x92\xbf\xd8\x90\x92\xe7(\x13D\x13B\x87pR\\\xcd\xd89.-\xd8\xba\xe9 \xf5\xfb\xd3\xeaGpjtPT\xc7\xeaD\xe8\x07\xa6O\x8b\x0e\xe8\x97U\xcc\xdd\x01}\xa2\xb0z\x17X\x81\xf1;\x01\xfd\x1e@pRt\x00\xbd\x86\xd5\xd5 $\x0f\x96\x0e\xb07\xe2P\xe9\x01\xa3\x0e\x9c^\x90\xc5a\xd4\x03Z\xe2\xe7\x0e\xc0\x0fp\xfat\x01\xf5X/\x1f\xd4\xa9\xd5\x05\xa6O\xb4\x0e\xb8\x8f\xe5i\xd7\x05 'a\x07\xd0\xa9<\x1b{@\xf5\xe8\xc3\xa9:S\xbb\xc0\xe4y\xdb %\xcf\xe2\x0e\xb0\xb3\xf2\x9c\xee\x80\xfc\xc9<|;`\x7fV\x07\xb3\x9d\xbf\x12<\xc0\x1d\x19\xe5\xbfj\x8a\xab\x9do\x94\xfe\x9e.\xdd\xa8M\x82\xac\x9f\xfbf#!\xb8\xd3\xdd\xba\xd9\"\x88(`\xba\x84)\xa2\x19\xde\xdd\x9a!\xc9\xf4\xf6\xa1\xdeU\xaeq\xe4\xe9\xba\xc9p\xbf4X\x81\x8e\xbev\xc9G\xaa\x80@Y\xf6\x01\xb4Nc\x15\xec}7\x1a\x7f[P\xe6\x1d\x80\xdd\x12\x18\xa2\xe6.\xbe\xdb\xdc\xbd\x14\x9cUGc^*\xae\xab\x17X\xd6\xdd\xb9\x97\x9a[\xeb\x01'9\xb9\x1e\x80}F\xf5e\xc1\x01v\x02\xf2\xae\xadkq\xadHz\x8e\xfb\x99\xc1\xf6t\xe1a\xcd\x12\xf5\x81\xeb\xb3\xa8\xcfJV\xaa\xbd\x8f\x16\xef\xb8\xa4g\x1f\x8fLABG\x9b\x8e\x9aB\x86\xbe%\xfa\xf4\xa4\xc5\xbb^\x9f\x9e\x9cU\xd8\xcd\xf6O\xad\xef\xf6)\x19\xe4\xa7\xe3\x1b\xab\xbb}\xe3g\xe0\x88\xdb?\x81\xf8\\\xd3O\x9fO\x1c\xf3\xb8\x93~;\xeeF\x98\x1f@d\xd1\xde\xd2\xa6?\xc4\xa6\x08\x96\n.-q\x9d\xfd'\x0e\x1e\xc8H\xf0M\x17\x10\x90\xa1\xbc%\xba)9\xadf\x01u\x80\x05\xed\xb7?\x17\x83!\xb9\xa8\x94\xbd\x07\xa1/\xdcV\xf3H\x1e\x89\xa5\xdcw\xeb\xd4e\xe3\x8b\x8c.\xd0\xdb1b\x08j\x05\x1fm\x17\x0f\x04z\x18\x90`\x83\xf8\xac\x9f\x08\x96\xfe\xcb\x17\xe2\x9e(\xde^G\x85\n\x0c\x89\xdf\x0d\x16_\xaamh\xae\x820|\xc9B\x961\xcb\xf0\xdc\xfb\xd8Djll\xbd\x8c\xce\x95\xc3Iw0$>4\x0dR\xbb\xfaU\xbcYd\xef\xc7\x90zG\xd9\xfb\xa3}\xd4\x81=o\x11\x18h\xf7nc\x8f\x86\xa1\x8a\xacn@\x97\xcd.~%c\x9aC\xbc\xf8\xe3\x90\xa6\xa9\xcb\xeba@\n\xa9\xb0\xf4\x8f\xd0\xd4\x06a\xd2/\xb1\xe0-\xb0\xec8e\xb9\xcf\xcb\x0b\xed\xca\xadhM\xfd\x8a\xdf\xd3\xa85o,\x9a+\xc4\x0b\x83\xf8\x92\xd3\x04\xf8\xe6>~\xda\xb54\xa9RP\xe9\x94\x1c\x126\xae\xa4\x17\xb7\xa6\xd5\xe4\xaee\x85Mw\xf0-\xa7;\x90^\x86\xcdI\x08\xeec\x12&\x93\xc9\xbf\xc1\xdaM\x98@\xe2\xbeV(\xff\xf6k\xafy\xf1\xc3-79\xb8\x87\xbd\xcf\xecf\n\xf7V\xf5[4\xa2<\x02d\xa0\xe0\xdf\xdce\xe2\xf1\xb2$\xfc+T\x80f\x83/\xb5\x96|\x1a\xb6\xe5\xaeXF[\xb2\xa51\xa8-\x17|\x19\xa0\xd8\x81\xc8\xb8\x16o\xb9\x1f\xcc\x03pA\x90 8wwR\xbf\x18\x14\x8f\xb7\xa4\xc9q5\xf4~\xe7v\xfd\xccnb\x10\x1cH9\xae\xd4\xfd8\x94nm\xa7\xb5x\xa4\x04\x17\x8f\x7ff7\xb7\xf8\xaa/\xb8V\xf3\xa3_\xbe@z\x1e\xd7\x9a\xc2\xc6\xea\x03}\xdbs\xb5\x0c\xbc\xe5\x86\xadi\x19\x83\xfbll%\x05Eg\xf4[b\x00:$\xc1\xb7P\xe9m\xee_\xfcP9I\xbd)qNR\x8f\xa26\x05\xa0=}I\x93)q\x08\x92\xfd\x06\xf4\xad\x9c\xa3$\xe1W\xe27\x02\xf2)\xd6\x00\x9f0\x83\xc6\x8f\xca\xd0\x04 >ZLM^\xf2\xabH\xc3\xc8\x9b\xc7&\x08\x0b\xa7\xc4\x91\xa4\x1a\x92\xfd3\x18K\xbe?E\xb2\xde\xb2(\x9f\x12\xa7\xa2\xf9\xda\x00:\x8a\xe3\xb4\x13H\xb2MS\xe2\xc8\x1fo\xb8\x87\x19O\xbc\xe5\xbf\x7fH\x82\x08\x14\x84\x00?9\x9f\xa2\xc0gQ&\xf0\x89\xdfjg\x80\xa3\xe0\xfd)q~\xa0\xdeg\x9b\x85\xc5\xb3)q\xce\xe8%\x923\xd9\x15}\n\x19\xc5\xcc#&{ba\xc8\xdb\xedf\xe6\x13\xd1M\x8b\xaf\xcb\xc9S5T \xc7\xec\xc7&\xa2\xc1G!ZR\xb4U\xca\xe6\x9b\x99\xbb;S\xb8(L-\x03\xbb\xfb\xb4m%\xef\xedZ\xd6\xf0\xde\x1e|s\xc1\xd0\xf5\xb9\xf7H\xe5Z\xd6\xdd\xdec\x18%\xcc$|O\x8c\xd1\x8f\x1cu\xcb\xb5\xf7\xb4c\xdb\xec\xed\xb7n\x9b\xbdg]{\xe6\xd1N\xc7\x8ey$Z\xfe:J\x19\xea3\xe7\xd1\x93\xb6\xed4\x81\x95\xf3\ns52\x81u\xf3j\x17\xcd\x12\x83\xf9j\x0f\xcd\x12\xady\xf5\x08\xcd\x12My\xf5\x18\xcd\x12\xc3\xf8\xea \x9a%\x06\xf0\xd5S4K\x0c\xde\xab}tC\x88Q{\xf5\x0c\xcd\x9a@\x97w\xd0<9\x1c\xe8x\xec\xc2xL\xd0\x01y$\x06\xe4]\xbe\xb2\xac\xe8 \xccQ+6\xd9\xdd\x15U\xbce\x19\xada\x0e\x9c\xcb\xb3\x9f\xc0\xd2\x0b\xfegvc\xbb\xd1\xcd\x04\xc99\x03\x90s\x19\xec\xf63\xbbir\xa9\xc0\xfcV0\x1ah\xc8\x97\xde\xe3\xab\n\xb9_\x1b\x8d@\xcf~[\xa3\xb4\x7f|\xabld\xa2\xfc\xe1\x93C\x8d\xcc\xc8\x94\xc8\xb0:\xe3y\xc2W\xc7\x8a@\xab\x07DF\x15d7\xa2;\x82YAy\xc0x\xd5\x06eJ\x9cr\xc6\xee\xc1\xc9\xb6\xd4\x11\xfb\xd7s0>\xcd\xa8t\xf7\xc3\x92\x7f\x1d\x03\xd3\\-\xa0\xbb\xc3R\x1bI/\xb5\xa9\xcf\xda\x81<\xb8]\xf4;\xa0\xee\xc4\x96\xdc\x91%\xb2q&\xd5\xb5\xfd?\x86i\xff\xb7X\xf1\xb1\n\x15\xfd\x7f\x8b\xb8\xe9\xdf\x04O\xb00\xa3\xbft\xf1\x84\x1a\xf1JhCv%\x13\x04\x16\x05\xd5\xba\x97\xd5\xfc\x11\x1b\x1b\xc9\x0d\xc6\xaf\x11\xa74\xcc\xe8\xaf\x1b5\xe5\xd7zS~\xad6\xe5W\xbc)5(\x1c\xa8Ws\xff\x86-%\xc8\x91\x86\xff\xdfj\x19 \xce\xf2\xf1\xa0\xb9\xac\x9eu\xd1\x1b\x88\xac\\\x1f\xe0\xcd\xb1\xbe\xc8x\xfc\x86\xadY\xa8\xe2\x02O b`u\x11\xf8\xe0\xf5KdO\x90\xecJ\x84\x8e\xa9\x8a\x91R\x84\xc0\x80 \xa9\" \xc2\xa9U\xa3y\xd8\xb0\xeb\x85\x8co\x83\xe8O^dta~B\xe0\x82q\xc6\xdf\xf0\xabB{\xd3^\xa9\xb6\xfd\xfe\xf4\xf1uQ\x87\x91F\xa6\x88\xda\xfesl{F\xb5}x\xab\x196\xa7\xaf:3\xf5x\xcfS\xb2U3\xa0\xcfS\xf6*\xb8\x14\x13\xb25\xb9\x8f\xb6\x18\x91c\x1e\xd5\x15\xe6\xc51\xff\xf0\xb7\x87\x87\xdf?\xac\xa6\x0b&\xf9\xe1\xdf_\xfc\xb6\xf5\xdb\xe8\xb7Q-\x0f7\xd4?\xfe\xf1\xe4\xf8\xaf\xa7\x9f\xde^\x1c\x9d\x9d}\xbcxw\xf4\xf6dJ\x1cA\xc7\x8c \xe4\xf0\x08b*\xa79\x1a&\xc3\xf7\x8fU\xee\x19\x97\xb1\xb4\xbb\xf0\x081\xe8i\x9ct%\xe6\xd5^\xc6\xd2LTt\x08\x01f\xd88aqH=&\x10\xaaC\x1c\xb2M\xe8\xb8\xd9~\xb2M\xbe;p\xbe#\xdb$\x13?\x9d??\xf8\xae_@s\x1a}dy\xca\x9a=\xe9\x8a\x80\xa8c\x9b\x16\x16\xec.\xd6\xae\xf6\xce\x8aJ 6QL\x93\x94\xbd\x8e \xf0\xe4dg0\x94\xc1\x7f\x80\x8eo\xf6\xc2\xb6/\xeeY\xa4\xf6\xe4\xf1\xe3\xddI\x17\x92\xab\x0fQ\x11\xc7KL\xf6d\x08=\xdc\x91\x91\"wdH/V\x84\xdb\x12ks\xf4\x88< \xc1s\xc2\xc9\x0bB\xd1\x10_E\x8d\xb9\x19f\x90\x93m\xf2h\xe7\xd9\x93!\xa1\x03Y:\x17\xff\xb6\x0f\xc8\xa3\x01\x89\xc4\x7f7\x13\x7f\xd9X\x0b\xa4\x8f2\x97\x0f\x06d\x1b\xcd \xdbd\xd2\x96\xb9\xdb\x96\xb97@f9#\xffq@\x121\x00\xffa\xc6\xa6&\x8d T\x91\xdaD\x17\xc48lo\xab\xf6c\xcdGq\xa0+?5 _\x88\x1b\xa9\x9f/^\x90\xc9\x93\xfb\xc0G\xe6\xac;\x93\xc7\xe3'\xe3]\xe7\xf6\xb5u\xd8,\xb9\x91\xfb\xe8\xc9`(m\x91p\xdb\xa5I\xdd\x9aG{bx40\x8f\xec}\xa8\xe5\xd9\xc6\xa1\xb7\x04;\x1e)kw\xd6\xa2/'\xe0&\x8a\xfb-\xe3\xce)pV\x85\xd5\xbb\x01\xac7\x1b\xe8O\xd4T\x8a\n\xdcL\x06\x11\x1e\x08\xf4\xc7\xed\xe6\x9e\xcd\x16\xa1\xa1\xb4\x04\xf2\x8c|&N\xfd\xc4u\x1e=rDY\xf1\xeb\xb13\xac\xb8\xf3\xb8\xe7\xf8WbB\xf6,\x83\x9f\xa86\x9d\xe6\x97Y\xc2\x04\xd2\xe3EX\xe0\xdb\x7f9\x1b_\\\xb0\xf4-\xf7\xf3\x90\x81!\xdeP\x86\x87\x8b\x98\x97\x01\xa6\xfe\x90\xf0u \x86BG\x1dm\xb6:p#w\xff\xf1n}\xe5\xf1\"\xeb\xd1\x00e#\x02\xabY\x83\x8a\xf7h4M\x1ejM,\xa7\xa2\xa7MIwL\xc5J_\x12\x1dw\xad\xda_\xae\x93\xefyDU\xad-\x83\x18\xb9u\xfb<\x0eK:r'\xd8\x96\x16\x19{O\x1f\x9b\x18T&=\xc1\xc7\x9a\xfes\xc7Z\x9f;-\x07\x9en\x99\n\x1a\x8d|o\xab\x1fU\x016\"n5\xe8\xdd`@\xb2e\xc2\xafH\xc4\xae\x88@2`\xdc\xe0:\xc74\x8axF\x04oJ(\xf1\x04\xc3IhJh\xf1%\x07\xa1~\x14\x17\x8b\x99\xdd\xaf\x95\x95y\xff\x862\xb3e\x1f\xd9\x9c%,\xf2t\xf3\xc4\x87\xc8\x92\xa6\xd1w\x19\xb9d,\"A\x14d\x01\x0d\x83\x94\xf9dD\xd2\xd3\x05\x1b\x93O)+\xeb\x1b\x83\xb4\xa2xu\x07$\xe3\xf2d\xcc\x96l5&\x1f\x19\xf5\xc9J`m\x9a\x11\x15hu~9^\xb1\x87y\xca\xa4\xa8cT~\xc5\xa9\xdf\x8a\xe1\xa3\x91\xb5-~\x1b]A`\xd0\xcb\x95 \xb8\xe1&\xaf\x80\x0b\x08\x95kn\x04C^r\x1e\xa2\x19\xa2\xb1h\x86\x8c\x94\x8bf\xc9\xa3\x15\xcd\xd2\xce\xc5\xb1\xac\x9b\xd5\xa5\xa5\x114\xc2[\x0d\xfdy?Ge\x8bLK\xdb\x90r\x9a:\xb2\x14\x95\xf2Jk\xc7,\xa5xd\xab\x0fr\xa4\xc7F$\x17\xe2\x01\xe0]\xb8\xa6b\x18kW\xbf(\xff\x1e\xd5\x160\x91r\x83\xb1\x99 \x0e\xec\xa2\xec\x1d\xf0F\x83\xa8o\xa2\x14u\x82\xd14\x0d\x16\x10\x9e\xbb\xaf\xb0\xe79\xc9\xc8\x0bB\x93\x05\x88\x94S%\xe6yN\xb2\xedml\xaf\xe8\xa5^\x14\x98e\x88\xe1t\xf1\x89\x84\x04\x91\xe8\xa1j^y,-i\xfa\xfe*R\x8e&o$-')qqN3\xa9\x1b\x1f\xcd\x92\xf3\x1e\xd7\xdd\x86 9~\xe8\xb4\x8d8Q\x9d\xf2\xccN\xa9Q \xdf\x93=\xd1\x1e\xc95\x01\x8e,\xfb\xbdwN\x0e\xab\xaf\xb8\xfb\xd4\x159 ?p\x1e2\x1a\xa1\xa6\x04\x0b\xa2\x0c\xe3\xe7\xcd\xbc\x1b\x84e\xd3\xe9x\x14n}S@\x0e\x89\xbb#\x0e=5\n\x03)\x81\x88\x9b\x88\x0b<\xa2\x80\x8b\xc0\xe6\xf7\x05\xbd\xe3\x8d\xe3H\xf2z\x1dNb\xdc\x99^u\xcd]Y\x8a\xe6\xd58\x00\xe5\xdb\xbdp\xd4\xeeJ\xcb\xd3\xe8\xcb\x17\xb2%\xe8oZ\xd2\xdf\xba\xce\x12j e$\xf5\xb2\x07\x82\x0d\xa8\xbb\xb2\xd5\x0f: \x95\x11\xbd\x8f1\xa9N\xd1\x1d\x87\xc5\xaf\xe0\xad\x96\x91\xa9\x00\x9a\x83\xe3\xd70\xdf\xa6\xe3\xf3\x96%\x0b\xe6\xdfit\xba$OX9\xb1_/\x8b\x02\xed\xacf\x8b\xf3j\xd2\x85\xa1H\xc1N\x1a\xcb\x08\x1b\xd3\xcd\xa6oKV\xb9*\x07O\xcc\xc8)L\x0b>\x81\x06\xa89}f\x0d\x9bL^\x90\x9e\xe6\x97\xa9\x97\x04\x97\xfd\xe7K\xb5\x1d\x97\xa9\x89\xc6\xe4Q\xaa+\xed\xd3\x86,\xb9)\x1a\xd1\xb7\x0d+p\xbeQ\xffZ9\x1ef\xe2\x81q\x1f8.\x92%\xdc\x92F~\xa8\xa8\xe2\xf1e\x10\xf9\x90<\x18\x0cI#\xdbE\xfc\x8c\x10\xb47\x9f*\x1f\xef\xd5\x9f^=qu\xb3\xaa\xbd\x13\xecd\xaf\xa6\x15\x92\x83\x97\x81\xff\x96\xe7Q\xe7]\xab~\xe0\xa3\xe64\xb9\x9b}\xef\xe7 \x0c?2\x8f\x05k\x84\x93h\xfb\xf0U\xcbN\x90[\x0c\xdc\xc3\xa8\xb9j\xf2@M\x7f\xe5\xfaik\xea\xa7hu\x9b\xd1\xf9\x84\xcc\x94)\xb3\xe8\xd5\x8e\x02~\xa3\xaf\xd7\xb17h\xa5\xd7\xcf\xc2jz\x15c\x18\x19\xb6q,\xb2\x9b\xecd5\x7fm\x9c\xf7?0\x16}H\x98GC\x0f\\\x19\xf9\xca[\x7f\xadi\x06H\xc0#\x10\xa3T\x1b%o\xe6\x99\xaf\xb4\xd4\xab\x99v\xa2\x0b\x01\xaa\xf1%\x0d-|\xfd\xd4&\xc6\xc4\x04}\xa7\x06\x14\x1fk\xfb\xb5\xcf\xa1VCY}\xf9[\x02:\xb9\x07\xc6\xd8\x8eK\xe9Z\xfb\xd9\x07\xec\x8b\x14'\x00\xd1\xd9\xd9L]\xe8\xaa\xc4\xc3m\x1c]\x9f\xea\x08&\xcd\xef\xa2\xf2\xebO\x96\xdcl\x00M\xcc\xab \x1a\xc7\xe1\x8dk\x11\xe2`\xcfW\xe2\xd1vo\xc6\xb6G}s9\x06y\x9a<\xb0\x97\xbdk\xb0\xcb\xb3\xccGQ+6r^\xee\x8a\x0e\x8aI?\xb0<\n\xe7\x9a\xfd\xcaDp\xd3\xb5\xc4\xc8o|\xb7\xab\xd1\x18\xf4\xc7#\xedb?\xd2k\xa8z\xe1\xb4T\xef\xc0~\xd3l\xca\xb4q\n\xc8|\xbe\xb6\xaf\xb8\x16\xe9e\x1f\xbc\xb5`\x99\xb4\xb7\xf2\xb5zu_\xec\xa59\x8c\xea\x15\xc7\xf5\x908g\x9cP\xcfci\n\x97\x12W\xb2\xfa\xe2\xf6kHnxN\"\xc6|\x92q\x88\xe0\x1f\xcco\xc8\x1fD]kNI\x96\xe4\x8c|%T\x16\x9f\xf3<\xc9\x96\xc5\xe50\x01\"\x12\xeeF\xe0~q\x00\xf7HcgP\x1c\x04\xf3t|U\xedQ\x9fq\xe8\xa7\xda\xa5\x1f}\xcdi;\x10\xdb\x11qT\x96l\xae\xab\xf6\xa2\x81\xf9\xd1\x96\xe5\xdf^\x0b\xad\x9c\x02\xb6=\xd7^G\xae\xeb\xa8\x1d\xbd\xf6\xdd_\x1cw\x16\nb\xd2AAL\xfa\xef\xfc\xcd(\x08\xaa\xefih\xbb`-\x95{\xbeuX\xc2\x8e0Hp \xe6\x80\xf5R\xad, /e\xba\xce\xc8!\xd4m\xc2\xb6\n\x88:\x84\x84\x1e\x12\x1d\xb1\xfe\xccU\xb4D[~@\x0ee=;dJ\x803u=\xbd*l\xe7\x8a+x\xa7\x10`\xe7UXT\x82\xe2\xb6]\xc5\x16L\xf2\xd6\x96\xeb\x81\xd6\x07\x8c\xe6\xa0\x18\"\xab\xe8\xc1\x95\xbcqN\x0eIN\xa6jY6i\xc8k\xa5\xf9\xc1\xd5\xf5\x99\xca\x01\x1e#q\xff\xf8\xda$\x95\xbb\xee\xd3d\xe0\xe9\x1a~\xc2#`\x10\xc0\xfd\x03\xd1\x88TX\xc7j\xc5\xd5U\xb4l\xac^um^\xb5\xdf\xaf\x16Z\x93\x03\xe5!\xe0~\xb4\x1e\x87v\xa5\xbez'\xc1K\x90ti[\xdcR\xd5\x8f8\xcd\x98U-\xea\x9a\xc7KR\x83\xa9#\x19\xb0>\xd4\x1a\x83\x82\xd3L\xd4K\xf9\xe5\xda\x81T\xa8G\xf2\xb2j\x9bj\xa44\xbf\xddyN\x02\xf2\x82D\x85zf\xb0\xbd\xdd\xc4\x91\xc0\xd3p\xa5\x194$\xd1,8\x07a\x12\x9b\x89\x9f\xe7\xf2\xeeE\xfe\xb6\xb6\xad\x18\xac\xda\x0e\xf9\xb6Sh\xd9\xe7\x05\x00\xca0\x1b\xd4|\x02\x82\xce#\x00\x06\xdb\x7f\x9e\xa4\xf2\xbc\xe9\x89&\x957\xc2\xa7J\xb4\xd6\xd1[(QV\xd0J\x83\xe3#C\x0c\xb9\x08\x8e\x04\x1a\xd6\nv5\x12\xaf\x17\x94\x1aw8v[\xa0\xcaS\xd2\x0e\xb4`\xd9\xcb^\xb5\x01`\x12\xac\x99\x0fd\xd5\xab\x84\xaf:J\xac\x82\xeb j\xc9/\xceS;H\x06\x8a\xdf\x08+\x8dh\xe7f\xd6\xf1\x8fZG@\xee\xc3\xd6f\xca\xed\xdc2k4\x0c\xc1\x05E[~K\xf9B\xf7\xb8\x0d$\xc8n\xfa\x0e\x85\x81\x0b}6\x0f\"V\xa0\xa0\xe6\xce+A\x17,3\xb0\x15\xc4\\k\xc2s\x1b\xfc)\x98 %\x02[\x89\x97,\xf5\x92 \xce0^\x8fV\n\x19\xdaMMPA\xcaPAEP\xa5'\x85[\xe9\x17\xb4H\xea\x86C\xe2\x0d\xc9\x1cCD\xa0['\x0d-L\xcd:\xcf\xc6\x8e\x0bx\xd4\x0eG?\x023\xc4`g\xeb\xb5\xf0\x12\xb1h\x7f\x0cX\x1d\xb83hc,\xda\x88\x16\xc1e+\xe2S>\xb8\xf8\xb0}\x8a\x13\x1d\x1d\xd8\x17\x84\xb1G3\x97\xbb\xde\xc0\xc6\xe5\x14\x87\xdbR\x9e[K\xf2\x82\xf8\xc5\xb9\xb5\xbd\xbd\xec\xea\xb8 \x1b\xfc\xd9\x121+\xd0\x8fRN\x9e\xad\xc1a]\xa6\xfe\xcfE;\xe7\xb3\xf5\xb9\xd5o\xbd~\xc4WV`\x1f\xee\x0d\xc9\xbaC`\xd8O\xfc\x1a\x89\xb1_\x0f\xc9\xaaC\xf2e\xcaW7\x16\x83\xa1\xa9j\xa56%\xfeMp\x14\xd48\x12\xab\xde\x97\x12\xb7\xd7Y\xd8\xed\x81\xa2^\x1aL\xd1\xf8\x90\x04\xb8A\x9a\xd6\xdcn\x0e:\x084\x9a\xb3%\n\x18\x96\x08\xd9@\xc6\xbaeWD)\xaf\xbe\x0d\"\xf0fH\xd8\xb5\xc7b\xd8\xcf\xdc\xf3\xf2$a\xfes\"\x9a\x9f-\x19\x89x4Zi@\x9f\xad \x8b\xd6A\xc2#\xe0\xab\xc5\xa2\x06\xc9^\x1e\x86\x04\x82\x9a\x92\x15KS\xba`\x84F>\xa1\xbe\x0f\x11OhH\x96,\x8c\xe7yH\xaeh\x12\x05\xd1\"\x1dc\xda\xe2,L\x99eQ\x89>\n\xcehV\x1f\xa6s\xbb\xe0\xc3\x83\x9d\x86f\xbb\xd5\xa1\xc8\n\xbf<\x0f\xff#}\xb8\x18\xf6\x13\x1d\xeau3\xf3\xb6\xb7\x9b\x01\x1c\x88d\xfa\x07\xd2\xee\xe1\x808\xaf\xa35M\x02\x1ae\xe4\xa7\x80K\xe1\x15b\x00\xd1H\x91\xf2\xact\xd2\xec\xcc\x1f_\xf1\x1d\x828Hi\x02\xea\xd5\x87\x89\xd0\xa4#\xa8l\xd8A\x95\x13C}L\xbaE\x91\xf6\xd1!\\k\x83<\xb04\xaf\x9a\x0c\x86\x98\x8d\xff`Hr\xd1QO0d\xa0h,\xc5o\xa2\x7f\xdc\x8d\x86\xe4\xe9\x90\xa4\xd8\x01T\x1c>s\xe3;\xcf\xc9|4z> \x01\xa8\xfc\xcd\xe6\xe7-R\xa2\xeaR\xb3\x99\xdd\xa2\x0b\xcf\x1c\x8c\xde\xbe\xe5\x8a\x06\x8b\xae\x8d&C\xa2E\xbc0U\xe4\x90\xec\x80Nvy|F\xe4\x05I\xe0\x86R\xe9\xd2\xb9l\x16\x9dK.~\xf0\x1c\xa7b\xea1V{o\x99\xc6\x9a\x96;\xe6\xc9\xa3.{d\xac\xab\xa6\xec\x06\xd6\x11w\xb3AE\x90u?\xad\xdb{\xba\xffo\xd1\xbcF\x88t\xd9\xbcI#\x02\xbbB7O\xea\x88\x82vK\x07\xba\xfa\x89\x9e\xad\x89\xcb\xca \x8eA\xc3\xb7\x91\xbe(\xe2\xa84D\xac\xd3\xd9\xb9E\x9e\x91\x835\xd0\xc0u\x0c\x1b\x0c\xa0\x88sP\xe0\x83\x8b\x00*\xe5\x13L\x9c\xfc \xd1\x8e\xc6q\x9e.\xdd\x1c_\xbb]\x06\xb4\xdd\xbb\xae>\x06\xba\x7f\xf5^\x14Hr\xeb\xa0.]%\xd5\x9d\x1aDj^` 3\xd9\xfe\xba\xaa\x9e\xc6\x81\x9b-\x9f\x8e\x88\xdb\xdaM\x1321\x1c\xe2j+c\xb3\x83\xaay\x8f\x8c\xebdx\x95\x14i8\xd3\x05\xd4>R\x8f\x14\xb9B=\xacR\x0ff%N\x943\x81\xa0\x9c\x90\x03Q\xf5!I\xc6?\xe4\xf39K\xc8T\x99}\xdaX\xb3CB\xc74\x0c\xb9\xf7)J\xe9\x9c\x15\xf0\xd5A\xee\xbd\xbb \xa9;\xed\xd21\xca\x91\xc3`]h\xa4+e\xe4\x06\x04QL0\xdc\xc6\xb8\x11h\"\xb3+\x02z\xdez\xe1\xa3\xba\xe3\xc5\xc7=\x1e\xdf\xb8\xc9`h\xf52\xf7uP\n\xf2\xdc\xc9\xde\xa3A\xe1\xeek\xf3-\x80\x0c\x88q\xe64\x1bi\xf4\x1d\xd9\xe9\x99TP#\x07\xe4(I\xa8\xe8\xc5\xa08\x99\x9e\x0fH6\x8b\xce!0|t~\x1f;\xa2\x13\xdfO\xf6\xefr\x1c%\"\x13P\x9d)+\xbc\x9f\x96\xed=\xedt\xdcqO-\xab7+\xba\xff\xa3C\xa3M\xfb\xa6H\x14\xabQ\xdd\x05\x16\xc9\x8a4\x82\xd5B\x13\x03\xcf\xccv\xce\xe5\xa9\xa0\x8f '\x88|v\xedH\xcd\xe0d\x0co\xd0\x0e\xf85$\")\xce3\x95\x14\xe7YeSm8\x93\xbb\xbb8\x93\xb0\xff\xb4N\xae\xabS\xfb)\xee\xdap\xff\xe9\x1e\xca%\xec?\xad\x9f\xf2b\xd4\x9d\x99D\xb8\xdaQ\xc0\xb9\xd3d\x19\n\x98\x974cu\x00\xcf\x04xK\xe3z\xfe\xdc\xcc\x7f\x07\x8eD\xea \xb1 \xf2\x91-N\xae\x1b\xb5\xf8&\xc8)\xcb\xea\xf9\xcbJ>Lm\x1dd]\x01\x01\xe9_\x1dde\x82\x00\x86\x91GF\x1dnQ\x1b\x14\xfaS\xc0\xae\xea@7&\xd0\xab\x90\xd3lo\x17\xea\xac\x03^6\x00\x9f\x01\xd4\xb1\xbbA\x1d\xe2\xef\xc4Z\xd3\xde\xc65\x89\xbf\xbb\xbd\xbc\xe7j+a1\xd6\xb7]\xa9\xfb\xb6\x1b\x90G\xf8R\x9d<\xc3tk\x04\x1b\xdbzH\x90\x9aL\xcd\xc9\xb8\x143;-\x91\x0c*^\xf5\x9aHH<}<\xfb)\x83\x07\xc1~\xe0\x00\xa6\xbb\xbf\x06@\xcd\"V\xb0i\x01\xbe\xf3\xf0\x18`\xdd\xbb\xc5\xb2O[93\xbd\x04,\xab\xa4{\xe3j\xd6h\x7f\xa76\xb2bYL\x9e4\x97\xc4K\x9a\xb1q\xc4\xaf6\xc5:\x9a\xdeA&0hj\xbf\xf5\xe9\xfbZ;\x02\xb5\xf9 \xc8\x01{\x8e\x88K\xc9\x08\xf5O+\x98L\x88\x86#\x0e\xa7\xef\xc9\x0e\xf6\x15\x0d\xb7\xbd\x9d\x91\xef\x0fHapnx\x8e\xdei\xaa\xd4}\x95\x1a\x82\x19\xae\xd7W\xdb\xb8\x9a\xcd,j\xbc'\x89\xe1\xe4\x11.\xe3hluEn?\xc3\xc9\xed\x06S\x9a\x93\x03T\x0d&\x85\xf4\x86\x16L\xd8}\x95Y-\xe0\x011\xde\x89G@ \xdb\xcd\xe0\xf0\x92\xb1\xbb\x80\xc6L\x95\xd6Os\xd8\xc5\x94\xa0\xf3[\xd5\x0c\xc9\x06$,\xf1\xb1\xe6|\x80D\xcafQ\x1d#[\xa8+o\xb3\xa9\xda\x7f\x86\xc7\x93\xd8\xdb\xe9\xbe\x1a\xb7R\xbc\x05\x08v\n\x13\xe3\xfb\x18iG\xf4\xbahU\xa1\x90\xfc\xaf$\xbf\xa2YPeL\xec\xbbR\x14\xd9\x85\"\xbb\xe7\x16\xc5\x10\xa2\xe7\x85\x1aW\xd6\xda\x9f;\xea\xe6Ip\xdan0\x1a\x81mu\xd1\x06\xa9Y\xcf]\xf3`\xcd\xe5U\xb4l\xfc\x0b\xb2g2\x06T\xdak\x81^c\xb1p\x05\x95A\xb6\xb7\x13\x08\x16h\xc3\x12\x9aP\x8ef\x89E\xf5\x1d\xcc\x95\x81\xdcNe4\x8f\xa6\x92\x92U\xb8V\x0bip\xeb\x83\xbeyp\xab\x95fa\xc2\xf7\xf6m\x11\xe5\xfap\x83\x81\xab\x83='bS\x92m\xe28\x1b6\xbd+\x12\xcb\xfe3\x1c\xcb\xed?{j \x1bWo+\xd8/\x03j\xf2xH\xaa\x8e\x8aB\x9a.e(\x882\x91\xe6\xd9\xb2\x9a\xb2\xe4i\xcd\xfd\x8f\x18\xa4&\x8cR\xb0\xae86Jku\xa5\x8c&^-\xed\x1f9Knj\x1f\xa0\xd9\xb2Y\x9dH\xad} asRs)T.\xb2l\x0c!P\xc9\x01\xb9\x1c\x92l\x9c\xb0\x94\x87\xebN\x97\xaejr\xc1\xc7\xdd\xd6\x04\xfc\xba\xe9\xa2\xa6\xaf\x9a\xafF\x95r\x1f\xf5\xac\x98\x91C\xb4\xf2b3V<\xac\xc3g\xe6\x0eRIl*y\x16H}.\xad\xd7D\x15\xdf\xf9\x01D\xe0\x96_\x81\x18\xcb\xa6\x1f\x0f\x99\xac\xafZ\xaa\x0d\xfb\x94\x88%\x15TW.\x85\xd0\xc1\xee\x8c\x8e~\xdf\x19=\x1bo\x8f\xce\xb7\xa7\x83\x87A\xf3\x98}8\x9d\xed\x8c\x9e\x9d\xff\xe5\xcf\x0f\x9bG\xed\xc3\xbf\xbb\xbf=\xfc\xed\xe1\xa1{\xb8\xf5\xdb\xc3\xc1\xec\xef\xbf\x1d\xfe\x96\x9e\xffe\xe0\xfev8\xfb;\xfc:\xac\x97\x02\xb3\x04\xe7\x0fgH\x9c\xaf\xe2\xcf\x17\xf1\xe7\xb7\xdf\xc4\xdf\xbf\x8b?\xff\xe5\x9ck\x03\xa1\x99\xf3B\xa4|\xef\x0c\xc9w\xcew\x90\x07q\x80E\x81\x04\xfeF\xf07s\xce\x07\xcd\xd3{\xe6|WV\x15\xd6\x00\xe6\x00\xf0\x1f\xa2\xf8C\xf1\xe7P\xfcy.\xfe\xfc\xaf\xb2\x90W+\x14C\xa1\x12\xfe\x7f95s\n\x1fFd\xb6-\x87\xf4h\xf4\xb7\x8b\xd1\xf9\x1f;\xc3'{_\xeb\xa3\xb0T\x83\x8f\x80\x0e\xdc\xf1_\x06u\xf85ja\xf8\xdftM\xa5!\x1b\xce\x958\x06\x80\xd3\xe0(j\xd6{\xabo\xff\x89\x05\xfa \x88\xcb\x84V.r,\x86\x89s[\x99\x05\x8f\x976\x83\xc8y`\xe3\xdf\x1ch\x84\xd3\x92\x99Zs\xe7-%Uk\xacEE\x83:\x87\xedF\x9d%\xfb\xe8Yri\x93q\xfc\xff\xec\xbd\xeb~\xdbF\x928\xfa}\x9e\xa2\x84\xec8@\x08R\xa4\xe4+mZ\xeb\xc8\xcaF3\x89\xedc\xd93\xbb\x87V\xf4\x87\xc8&\x89\x18\x048\x00\xa8K\xc6\xdeg9\xcfr\x9e\xec\xff\xeb\xaa\xeeF\x03\xe8\x06@\xdb\xc9dv\x07\x1fl\x11\xe8{\xd7\xbd\xab\xab\xe8\xfa:\x17<\x06a\xa6\\\x8d\xc9\xbc\xa2S\x95\xa6\xe4\xb5\xd2\x1b/4R\xa7\x94(\xb7\x1a@\xdde\x0e\xc7\xa1Q)I\xe9\xdb\xec3\xe2\x12\xbaF,-)\x05^\x05i\xb0f9K\xe1\xebm\x1a}M\x19\x05.\x19\x04\"gU-\x81\x80\xc9Q=,<\x01_.\\\xe7\xc81(s[\x94Q\x8b\x14g\\h\xd3\xea|\xe5xp\xc4\xe9\x02\x8c9a\xa8\xd7\x8f(S\xc6&\n\xf3\x9a\x97z4\x1d\x9e\xc3\x04\xff+\xaeV\xbd{\xb7\xbfD\xf2d\x18\xf0%\xa6\xfb\x99@4\xf89 \xe3Z{|\xf5x\x91\xcbA\x9e\x86k\xd7\xf3a\x0fS\x8d\xcb\xb4\xc54\n>\xe6\x06\xf3\x17\xef\xe7\x02&\x90\x91#\xc3\xa5Ew\xbd(\x07\xf0\x16\xcc\xff\xb2\xcc\xf9/\xeb\x02\xc3\x05J\xc1\x17\\\xf8>\x92\x81\xd0\xa4\xd4\xc1\xdfV\xa4\x8e\x1c\x8e\xe0V\x80\x9bV\x18\xc3\x96\xe6\xa9;\xf2T\x10n\xe3\x07(\xa2\xad\xc9N\x1c\xa7\xd2\xc5\xdf?\x8a82e\\\xac-\xfe5\xd7\xd6\xcd\x8b\x82\x91\xffl\x8by\x02\x13py\xe5\xeb\xe9\xf0\xdc\x1b\xe4\xc9\x0f\xc95K\x8f\x83\xcc\xe8>^\x15\x08O|\xa0-\x15\x13\xbb\xaey\x1f@m\xb4x\x19\x81\xab\xa6\x18\xc1\xf0r\xb0\xc6H\xea\xfb?q\x96=\xfd\xe9\xdf\xdf\xed\x9f\xf7\xfe]\xfc\xbfo\xbc\xef\xca\x87\x8dn\x83\xfb\xfb\x0e\xc2\x8e\xea~\xe8\xc3\x81a\xd4{7\xd4\xdd\x9d;\xb0\x9e^\xe3\x8dZ\xb74\xec\x03\xaf&\xd5V#\x91\xd6\xe7\xb0\x87m\xf1-,\x9a\xdf[N\xaf\xcd\x97t\x95&}\xe6\xc3\xb1\x8f\x9e\x87\xfd\x91\x8f\xde\x82\xc3\xc7\xf0\x0c\x9e\xc0F]\x85zfNP\xc6\x1f\x81\xec\xeeK\x1c\xbeD\xf4\xcd\xf4\xd9\xb9\x88/\xdc'tz\xcf\x87\xf4\x12\x9e\xc0{z\xcd\xfb{iP\xaa\xb8^J-\x1e\x13)\xa1\xcaGpY8\xffpJ\xf2\xef\x98\xa9\xbb\xf6\xd2\x87\xf7\xa2\xdf3ZO\xbcw0\xf4\xe1\xd8S\x90\x81\xaf\x8e1\xa1}YM\x98\xb3Y2go_\x9f\xaa E\xee\x99\xe7\xc9\xb5\xb1(\xbd\xda\x82-\xba,\x18_\xf2\x97\x8f\x8bi\x96\x17n\xf1y\x0bG\x15d\xb1K \xfce\xddG[\x95\xf7\x95Uy\xef)\x12\x94f\xec\xfb$\xcb]\xaf\xae\x14\x95\x7f\x7f\xf8\x00\x8e%\xb3\xd6+<\xd7&\x9c(U\x12\x8e\xe7\xce\xb9\xe9[\xe9\x974'\xf4adP\xd5\x11\xec_\x99\xef\x81+\x00\x7fS\x1d\xb2\xa0\xec\xfb\xef\x06\xfb\x9e\x0f?r\x82\x83\xbb\xe8\xc3\x1b\xb9b\xb4\xa1?6\xee$\x88Y\x9e\xc2\x04\xdeL\x9f\xb5\\\xa2?Et<\x15\xd4e\xdezq^\x0d\xffgA\x85_\xd0\x10_\xc3\x04N\x15\xa0\xbd\x80'\xf0\xfa1\xbc\xe0\xa3<\x1d\xccVAz\x9c\xcc\xd9\xb3\xdc}\xe1\xc1S\x18\x1d<\x80#\xf8\x19z\x13pn8\xcf\xc5?O\xa7/\x1a\xc6\nrY\x7f\xee\x97\x8b~ \x19\xc2\x198\x1e\xf4\xe0\xd2\x80\x15\xcf\x8b\x12\xedc\xb9LY\xf0\xbe\xb1T\xdd\xbc\xd4\xfc\xa5\xfe\xd6\x88GO\xe1\xe0\xde=\x99\xeeA\x1b\xbd\xe3H\xc9\xc0\x86\xe8eV\xec\xc3+-vvQ%\x1d\xe4\xc9\xb3\xb3\xe3\xd3\xd3\xf2\x17\xd3\x05b\x0e2\x7f\x93\xbd\xa0\x15\xe6\x08\x9c1\n\xa1\xea\xcd\x98\x83\xbeq\xbe\xdfu%D:\xe9\xfb\x0ez\xf07]\xe8\xeai\x8d\xf0))\x01\xc8\xba\nRb\xf2\xcd\xeb\xdb\x07\xce\xbb9\xccp\xea~)\x08\x9d\x06H\x97^+\x1f\xbf\x9a\x9e\x9c[.E\n:\xc5i\xd6\xac\xe06\xad\xa4\x8a/\xf5/\xbc\x8e\x95L\xf1\x8e\x05//\xb8\xd1/\x8d\xa8\xcf\x1b\xfd\x96\x8b\xd8q\x8dm\xfe\xd2\x80\x02\xdf\"\xc9\xff\x05\x97\x05\xabg\xb3`\xc3x_\x8a\x17!y\xfe\xc5#\x84\xfa\xd6L\xde\xeb\xf0^\x97A\xffR\xe2\xad\\\x92/\x18\xef_\xb4\xbd&\xcb\x9e\x92\xbe\xfeR\xe1\x8aC\x1f\xfeR\x05`\xde\xfc\xf7\xe5\xe6\x8f\xaa\x88\xaf\xad\xe9\xf7u\xf1]u\xf7\xbdW\x11\xb1\x8b/RH)\xc6*\xcb\x94\xa4||\xe9\xd5G\xfd\xfd\x8eb\xfdeQR\xd3A8\xb1[NO\x10\x90\xcb\xb8\xa1\x82w\xab\xd2\xa6\xfa\\9\xabj62\xbb\x18\x0d\xc8\x04e\x05e\xd0\xea\xd8\x04\x8d\xbf\xaa\x88\xb54\xc1&R t\xaf\xbfA\x0f\xfe\xda\x80\x89\xba\xba&\xf43\xfc[\x1a\x16+JP%^p\xdd\xc8i:eU\xd4\x05\x05P\xc3\xa0\x992~\xe2?\x06Lc\x9e\xa7\xc5\x199|\xb6\x1f\xfa\x9c\x88\x92 \x7f\x02\\N\xae\x03\xae\x8aM\xac4'\xec\xbbNhc\xf3&\xd4\x0b\xa6Z\xcc\xe2\x95\xadPh *\x1b @\x96\x87YP\xed#2\xcb\xdd!\xf5\x14+\xe6\x18#\xc1*\x9c\xd1\xb0.\x86\xe0p\xberD\xc0\xc7r]\x0ex\xfc[\x0f\x8f\xad\xb6r\xe2\x18\xa8\xabR\x94/\x14-\xca\x16ij\x0fB>Ht7/phz\xf4\xd5y)ZOSLQ#B\x96\x89\x8a\xc7\xe5E\xec{\xab:q\xber|p\xfexp\xe8\xe0\xd7\xd4FEL\x87<\x96\x83\x18\xdc\xa2\xf2\xe1\x8b~.\xe3)\xba\xd5\xd2\x97\xe1\xf4\xc7du\xac\x18\x1d\xcd6\x91\xdcl\x16\x85\xe24K\x1b\xa1O\xd4\xb0\x81\"\x97\xe2\xb7`\xbb\x14\xc2\xa5\x8aQ\x9e\x8f\x14e\xf8\x18\x02x\xa2\"\x84>\x86\xc0\x9ef\x1d\xfdO\xa6\x81\xc9\x83q\xba=\x17\x086\xdd\x9e7\x8c\x8eB\x93\nQ\x02\xbd&V>\x97\xaa\xc9\x96\xc89H\x11\x0cH\x1d\xf5i\xdc$\xae\xcb\x0eL\xe1\x1c\x85\x82\x90\xd4\xba\xd1\x9c\x93\xd5\xc3\xac\xa2Uu\xf8\x18\"x\x02E\xd6\xf9\xa8Y\\\x9c\xc1\x04\xb2id\x11\x17\x1d9\x16B\xb5\x19\xe1\xf1tF\xd1\x08f\x06\xf1\xd5z\\\xbe\x9c\xc6jf\xe2:zI\xc0\x88\xcb\xd2E\xacNN\xeb2\x86ya[6\xadXW@g_\xf5\x8bHU\xd3\xa2\xa3\xb4\xbe\x9c\x16u\xcem+Z\n\x96T\xdd\x9e\x0dm\xcf\xa6dB\xda\xb4\x1b\x1e0\x04\xf1t\xd3\xa0\xcc\xc7\xd39\xed\xc8\xdc\x12K\xcc\xf8\xb6\x11L;l,\xa1\x82f\x95-\x16\xc8\xe7\xb8\xc09\xf8\x87\x0f\xb0./\\i?\x99\xfaQ\x9f\\CD\xb7R@D\x97U\xc4\x16O\x9a\xf4\xf7\xb9\"\xb0\xd2X\xee\x9e\xcb\xa4\x8a\xb8\x1a\x90=\xc0\xabEx\x92O1\x83\xa2\x162*V\xd2E]V\xd6\xaf=$\x07\x1c\xa8VB+\\)\xe3\x03~]\xe9\xfe\xf8\xf5\xcf\xa5\xf5Y c\xc3\xbe!\xdf\xbbmC\x94\xf0\xcf\xc4\x9f\xbcM)\xff3\xfa\xcb\x17\xd8G4LL\x93+\x0b\xb14\x922\xfc\xc3\xd7\xb1tR\x999\x13\xeat,}+\x18\xfeQ\x9a\xc2\x87\x0f\x107H\xff @\xfc\xaa\x8c\xe8\x16\xc1R>x\x04\xd8\xa2\x03\xf0G\xd1\x90+\xe8\xc1m\x87\x05T\x18\xa1y\x99\xe8\x02\x91\xa2\xd4\x9f@\x83\xe4IU\x99\xce9\xe2(\xa1x[H3\xf5\x05\xb8(\xed\x173\xb6\xc4:\xb5t\x0d\x13\xb8\xe0\x8d\\\xd2\x16a\x9bD\x17E\xedz\x9d\x13\x98\xc0u\xfd\xf5MmR\xdad\nL\xe4\xfdL\x0d\x11\x17\xcf8\n\xafJ\xb4\xa0<\x90z\x1b\x1a\xb9\x06:\xfc\xd0X\x8bA9?\x13\x1c\xa5\x84\xa7\x1a\xdc\x92sN\xb1\x08\xae\xe0\xe77\x1c\x81\x8f\xe8\xbf\x89\xfc>\x86\x1b\x85\xb0\xf4\xca\xf34t\xe2\x0d\x97YM\x99@P_\xac\xdc5\xabu\xbd\xa2\xaeW\xd45\x93]\x17\xb4\x82\xa9\xae\x15q\xc2\x0c\x7f>n\xedu\xad-D\x135+^\xef\xc23\x13\x01)\xca\x90R\xa6\xba\x8e\x15\xb6[ B\xa9.\xbe<\xd2\x7f\x8c\xb5\xba>t%T\x1c\xbc*WY\x903\xf0\x8d]\xa9\x13[<\nso\xe8*\x8b\x0f7\x83M\xb2\xe1\x18\xc9\xdf\xdcH\x17\x96\x95\xd7\xb5[K\x7fx\x08\xffb\x1bE/\xd3\xb71Et\x9e\xbb\xb2\x19\xa3|\x8c\xe0\xe7\x95\x17M\xad\xfa\x8d\xe4A>\xb8\xaf\xb8\xd2\xbc\xe7\x16@H\x7f\x15\n\xed\xbf;\x1eyD\x17\xdf\x04b\xfc\xbb#\x8e\x92\x14\xf1~U4\xac:+\x0d\xe1U\xc1\xfd\x1a\x88`\x87\x85\xf2A.\x89[`=\x8eF{/\xe9?\xdf\"E\x93\xb5\xf2p\xa4\x13\x901g\xa2\xa8\xb1\xc9\x11\x1c\x15\x83\xc1\x8f\x9f*\x02\xee\xdd(xQ\x93\xdcT\xbd\xf6J\xbd\x8a\xb1\n\xad\xb5\x18D!\x9dJ\xd2\xd1*\xe9+\x99\xe5\x98v\x1e\x8dw\xfd\x91\x87^\xb0\xefiA\n\xca.\xff\xba)\x0c\xfaB_w\x06\x84e\xc7\x88q\x03\xf9\xcb\xd3\x10\xf0X\x9c\xef\xfa\xf0\x12\xfb\x92\xb2\xe6Kx\x8a\x12\xe8\xcb~\xdf\x03\xd9\x0e\x1e\xc0\xdeL_\x9e{\x9c\xd4!L\xcd\x98\xfbR\xdc\x7f+:\xe0J\x7f\xf9\xb3O\xa6\xe81<\xc3\x81\xd5>\xf6\xfb\x06Z\xbcG\xe7\xd5'\x16\xc3\xf7c^\xed1<\xf34*\xcb\xc7Pi\x89\xb2\x10\xead\x9a\xaf\x95\xb8\xfb\xf0\xf0\xfe\xdd\x07fM\x8ck\xfc\x87\xf7\xcd\xdff\x18f\xdc\xf8\x89\x83\xf9\x81\xa5\xda\x867\xf9\xd0\xfcm\x0e\x13xP\xbd\x13'\x1f\x8ez\x0f\x0e\xcc\xdf\xb8n9:\xb0\xb4\x8a\x91\xf1\xfa\x16]s\x89~\xc97q\xbf\xbfo.\xc0\x05\xa1\xfd\xe9O\xefn\x0e\x86\xfdw7\x0fN\xce-\xe5.\xb1\xdc\xbb\x9b\x83\x93w\xdb\xc3\xe1\xf0\xe0\xdd\xf6\xbb\xef\x86'\xfc\xdf\xfb\xa3\xf3\xfd\xa5\xb9\xd2\x855\x8f\n\x7f\x92+\x96.\xa2\xe4z\x0c\xceK\xf5'Em\x8c\x19\x9bgp\x1d\xceY\na\x9c\xb3%K3\xc8\x13\xd8\xa4\xc9\x8ceY\x83b\xed\xc4I\xde\xbf\x0c\xb2p\xe6\x8c\xc19\x8d\"\xb6\x0c\"\xd1*\x17\x1dn\x1e\x0e\xc1\x8d\x93\x1c\x02\xc0R\x80h\xb4I\xc28\xf7\x9a\x9a\x0d\xe3\xab \n\xe7}l \x9b\xa6\x17\xd4\xb49\xf1\x9d!\x9d\n\x08\xc55\x82>\xcc\xcc\x9f\xb9\x8e\xfac\x90\xaf\x06\x8b(\xb1\xe5\xae\xe4:\x01\x19\xb5\x07\x8b4Y\x1f\x0bo\x1a\xcd\x9dX>\xca\xad\xf8\xcc|<\x00*\xc6\xfe\xeb ^\n/\xdc\x8b)3\xdaE\xed\xad\x1f[o\xd4A\xd5\x1e\xaeB\x85\xa2I|z\xfe\x18b\x0c\xc4\x9eR\x84X\n]n1hI?\xe5\x9d\xc6\xf6\xbeql\xc5\xb0\n\x89\xc2\x0e\x07\xa9\xe1\x00P}\x93\x02y!\xef\x82<\xf8\x89\xb98\xd5\x03\xf4\xfbC\xceON=)\xf4\xe0\xd8\xa5\x13Su\xe6r\xe9s\xc9\xd6S6@\xca \xeb\x15N;;\xcd\xfe\x99}\xdf\xd5\xb6P\xac\x06\xda\x0e\x1f\xaf:\x0d}\xe1D-\x05\xef\x84\xae\xa9\xb9\xa4jk\xee[I\xaf\xe7y\x1c\xb5\xee\xdd;xt\x9f8\xc7\x93 \xdc\xbb\x7f8z\x84R\x0b\xaf\x08G\xfc\xc5\xc1\x10\xe3\xa2\xdc\xbf{ot\x00\xe24\xad\xde\x96G\x01\xce\xb8\xbc\xea\xba\xa3\xe1\xc1!\xdc\xe1\xbb\xf7\xe4 \x8c\x86(\xc5\x88w1\xffq\xff\xde\xbd\xc3\xfb(X\x89*9\x17\xa0\xb8r0\x06\xf5\xe6\x0b\xc2\xd2K\xfbj\x8a\xf6\x10\x13\x9a\x8f\xe4\xe4#O\x9el\x00\x05\xfa\xbd\xa1\xa78\xd7{\xa0\x0e}\n\xa3!\xdc\x01\\\x9e\x0f\xb4\x1dB\xa0\xa1\xb5\xff\x00b\xe5\x18\x1d*\xf2&\x0c!\xcd\x01\xcf\x02\x05\xb4\xed\x08l\xaf\x1aQM\xcd\xa5\x07\x07\x07\xd0\x83\x07\xf7\xe0\x1bp\x19<\x81\x83\xfb\x1e\xf4\xc1u\x87\x18\xcd\x0c7\xfb\xden=\xbf\xb1\xdd<\x90\xcf\x95\xb8\xfd`I\x89\x82\xb8\x80\x98 Gp\xe22\xd8\x879\x06\x95\x03\xbe\xae\xc2G\x81\xde\xe7\xdec\xdc\x8fk\xf8\x06\x16\xf8\xf91G\xe4 D\x1e\xae6\x95\xban\x06\xbb\x13\x97\xe3\xbe{\x8d~3\xf0\x0d\xf0*._\x99\x8d\xb7\xdb\xc4\x7f\xb4\xc3\x98\x86\xdaz\xce\x18L\x075\xf7a\xe9\xc3-9\xe2\x98\x8c\x9a\xf2\xb9\xd0I\xb6\xb5\xd4\xb5\xf9\x16\xbe|8\xbf\xba\xb2\x7f>\xae\x1b\xc8\xe4\x83\xfb\"(\x85\xeeA\xbd\xf6f\x82\x82\xd0\xf3\xe1\xc4\xbdF<\x86\xa7\xc0'xc\xe8\xea\x86\xf0\x9d\xca\xf1\x89\xfe\x11\xb3\x03_J\x0b\xd1u\xaf\x87\xa1\xa7n\xba\xfa\xfcA\x81\xfb/\xdd\xcb\xddp\xfc\xf4sq\xdc\x87\x0b\x9fC\x9b\xb8>QMr!\x1f\x04\xccK\xe9\xc3\xf5\x0c]\xb6\xa4\xb0\x96#\n\xa3\xa8$\x84\x83U\xc9{\xe1\x92c\\\xe0\x11tN\x83s\x8e\x9e\x02\xd5\xde\x13j\xdd\xb85\xaf\xa0R\xc7)\x06{\x99\xc0{\xd5g\xa2\xd5^{\x84\xd9\x97\xed\xa8\xc5\x91)k\x19\xdcS\x91\x81\xfc\x16\x9e\x88,\xe6\xbc\xd6m\x837\xa8h\xba\x0fy\x81\x1a1G\x0d\xf7\x02c\x82pBn\x02\xda\x98C\x12U\xe4\x84\xfe\x82\x96rk\x1a\x9f\xb5o\x10\xa6\xc7\xd2\xea\xe2\xf8{\xbd\x18\xa1\xb8\xde\xef-P\xda3\xfbb\xc9\x07g\xc6IK\xec\xa3\x8e\x1a=\x96\xc8\xcc\xd1q\xce\x919\x14\xc8<\xe7\x0b\x17j\xc8<\xc70(\xdec\x98\x0bd\xe68\xb8\x81>\x87<\xa9\xe8,\xfd\x02\x04^\xb9K.\xf3\xc2\x1f98\x0e=O8\x15\x9c\xb8\xc7\x0dF(O\xf9\xb4\x13OAj\xafW\x97\xf0\xf4\xe7c\xaf\x17\xf3R\xf5\x84S\xd0\x86\xc7\xef\x9b\x84\xa4\xea\x9b\xadU\x17\xbebi\x16&\xf1\x18\x1c4\xe6X\xb4\xd0\xed,;0\xe5\xb2\x96\x0f] \x1a\xc33;\x9b%\x1f\xb01\xbc4O\xd5b\xb4\x10\xed\xfeh\xfe,\xdb<5\x7f\x16.\xf6\xe3\x8e\x12\xb1\\\xd8\xee2\xb4V\xebv\x90\xb3,\xa7\x98|\xceM\xdc\xef;\xd0#\xd2iJ\x99-\x9f\x8f\x16\x02n\x9b\xcf\xdb8\xa4\x19w\x1b\xdfg\xcdh\xa9\xcd\xe8GW\xe6\xa6\xb9[\xb9k\xf8i\xf3\xab\x83\xac\x0fZ\xbeD\x94n\xac\xa6Y\xf9\x88qn\xeb\x8d\x15\xc1nP,g\x14\x02\xd3\xd5c}$\x15\xffC\xdd\xe3\xcf\x90\xe6\x86\xffy8\xb2d\xbb\xe9\x14\xdfC\xef\xbc<\x1f\xe9\"\xd8\xb6\xabb\xbe\xa6\x0c%\xe5\xb9\xf8\x95\xe6\xc9\x91\xaak\xf3\x16K\xab\x88\xf58i\xeb\xec\xc56\x8a:v%\"\x85vjR;1\xde\xad\xf5\x1dC\x89u\xda\xcb|@\x84 \x0d\xf8\xf2\x16z\xec>|\xf4\x88+\xb7\x03\"Kd\xdd\x97\xde\xc9@q\xaa\xba%\xf3.\xf7\xaa^+\x91,m\x8a5\xd2\x12\x99J%\xb1\xa9e\xf0\x81\x96\xb0\x87>\xd4l\xf8x\x84\x81G\x89w\x1cbzxC\xd8\x99\x18\xf2\x8a\x07\x86L\x90\xa19M1zC\x0c\x853D\xe5\xc89\xa8\xb7\x8cqE\xde\xf5\xf6+\xc29\xd3\x0ckU;\x8ct\x01\x1d\xb1\xc3\xca\x888\xac;1\xe6\xa3\xd1q \x1c\xac\x83\x9b?\xb3[\x14v0\x85\xa9zch:\xd2\xcdW\xa5\xaf\x99\x0c\xf5\x19I\xc9 \x13PV\x1bQ\xd61J\xa4\n3\x8c,\n\xbd\x9e1\x833zLJ\xa9{\xe5\xa3\xc9\x9eMg\xc5\xfd\xff-\xfaQ\x0fm\xc6\xc55\x17\xaf\xd5\x81\xa7)5\xc6\x1a\xed\xd7p\x04\xee\x02\xcb\x16gTk!D\xa9wk!\x8c\x8eEY\xfa\x8c\xc7\x94s\xf3\xed\xe1\x85\xe7\x83\xe5b\xf1\x86k\xd6n\xe0\xc3\xdc\xa3\xb0\xd3\xd39\x1e\xb4\xf3\xffI\x16[a\x1cTr\xe0\x9c\xf2\xff}X\x9d\x17\xafV\x16\xec\x87\x02a\x82\x02\x0f\x8a\x89\xe3\xf9\x97\xcc'6\x083\xfc\x9f\x83e\xab\x8by9Q\x90\xb8\xba[CJ\x19&\xb2\x1ecgw\x02\xa1\x8f9m\xf4IWYld\xf8\n\x030atO\x89\x94\xcdA>\xebpB\x95/)gTKm.)\xe5\xe9\x96a\x94\x8bE\x10e\xcc`\x8a\xa4\x06\x05>6\xe7B\xc9\xbe\x0b\xe30g$\xb1\xd0\xc1s\xbd\xbd9[\x04\xdb(ol\xc9q,@\xf3\xd1\xcc\xce\xeb\x84\xb2\x16sX\xb4l\xa7\x97\xbe\xc6\x0dA\xdef\"\x91\xc8\xb3\x1c\x7f\x1eA\xe8\x06(\x9b\xa8\x01\x046\xea\xc0I\xa4\xe1\x16F\xea\x06x\xb5\xc2\x90wW\x8c8qI\xe3\xe3\x9d\xf1\xbf\xba\x08\x92R0\x83\x9e\xb9Of\xb22\n\xa3/\x86\xc2\xb2\xd7\xe4c\xa9\xde\x1c)U<2W\xdc\xd24\x1bF\x84\xf0\xf2\xfb\xa2\x04\xe6`o&\xd6O\x0e\xfa\xeb`\xa3\xe5\x92\\\x07\x9b\x1a\xdb+\x9d\x85M\xcfKV\xcb\xe2\xb8%\xed\xf5<\x99\x035w\xd94\xe5\x05-\xfe*\xd5d\xa8\xa0q{\xcd\x81\xbfy\xbd\xae,\xf9O\xcba,\x99\xd7Y\xb6\xa1 \x97\xbfR\x1a\xd4\xda\xea\xef5\xeb*fb-\x9fn!0\xe5#\xc6\xee\x96\x82.\xe5\x82\xde\xc5\xec\x1ar\xb7\x80(\x97S\x8e\xcb0\x0e\xd2[\xc7\xf3\x8a\xd7\xcee\x90\xb1\xfbw[-\x07V\xa5\xe8\xde]O$M\xed$\xce^iY)\xcdA\xdd\x0f, \xcf\x0f\x87\xe6\x84\xe7\xf7;\x05\xf47\x1c\xc8(\xde3\x01\"\x9d1\x14\x19\x0bb\x91\xb1 uC7\xf6\xd0\xc2\xaa\xc4O_$ \xc6P\xacB\x17\x8e\xd1\xbeV\xb8\xe6 un\x81*}@\x9f6p\xc9 \x84\xbe\x8c\xd7o\x14\xc7`\xf0\x84\xe6\x81\xf0\xe0)\xad\x1a\xaf.j\xa5\x9eN\x14\xd4\x90\x13\xf4n\xc8p\xa5%\xfe5E\x84\x1f\xd57\xf3n\xdb\x86YfL\xb9\x16\xe0\x03\x84m2\x92\xde\xc0^C\xc3\x16\xed\nt2\x9b\x9bQ\xd0\xaa\xaf\xc8\x95-.\xfb\xf9\xb0?\xfd\x89\x02\xf2\xbd\xeb\x7f\xf5o\x7f\xbc\xf3\xf57\xbd\xc1\xbb\x9f.\xfe\xcf\x87\xff>\xdf\x0f\xa5m\xc5\x12\x88L\xfaw\xccVA\x1a\xccrtD\x81\x15\x0b\xe6,\x85E\xc8\xa29\xc4\xc1\x9a\x99\"h(\xf2_\xb2\xd2\x94\xd1\xda2\xe7\x8ef\x87\xb6iW\xf5msg\xa9\xb93\xc9 \xcc\xd4/f7\xba\x19\xc3F$Ak\x88I\x7fK\xbbqWL\xd0\xde\x16\x7f\xe6I\xcc\xc6\xba\x8d\xca\xe0\x10\xa8?\"6\xbb\xd9\xb0\x0b5Rk\x7fkH'%\x06\xbc\x1a\x849\x85\x88\xa7s\xf9)%/\xa5\xb7y\x92\x9e\xef`D\xab\x8f\x13\xe3\x97u\xda\xca\xc4\xbc\x95\xe8\x9f\xb8\x0e6\xa8\xf6\xfb\xe50\x81\x89\x0c>z\x12\xccV\xed\x81\xb1Us\xc1f\xc3\xe29%\xbb\xa9\x8f\x98n`\xa3G\xb5.\xab \x85\xc0\xd0]\x97\xbe\x18:\x98\xb3\xe9\xc8\xe4\x94T\xf4\x88{ \xc4\x93%\xcb5\xa1\xe4E\xb0f\x99\xcb\xbcz\xff\x9d\xe7:\xcd\x1b:\xef\xb4G\xa1\x9d\x9e\xb1\xc1e2\xbf}\x9b\xb1\xb9\x12\x1e_\xa5\xc9:\xcc\xd8 exC\xbaB\x9c\x9eE)\x0b\xe6\xb7\xc0\xffuL\x87jE\x8b\x18\x90\xad\xd3\x00\x83f[\x1e\xbb\x96\x83j\x0f\x02\x0e8\x84$\x8e\x92`\xde\x05\x05\xf8\xc3\xc5\xa6\x94e\xdb(\xb7Y\xe4\xb1I\xc6W\xa0k\x9b\xb1\xcb\x06X\xa1\xb3\x11\xbc\xdb^n\x9bI'_\xab\xef\xc2\x88\xbdFva\xa6R1\xca?&\xe7$I\x0f\x06|w\x9feZ\xb2c\x12\x97:\x8d0k\x826\x94\x9dj9\xef\xabn\xfdP\x99Q\x91b\xd8-\xa5\xe9l\x98A\xc6\x08t\xf5\xaa\x18\x82B\xa4j\xec4\x95\xa8)K\x05\xe2\xa9\x0e\xeb2\xdc\xd1E\x18\x87\xf9\xb7\xc9\xfc\xb6\x93P\xcf\xd7\x85\xaa\xf1\xb6N\xe3\x10\x19\x97\x91\xc6\xe9UL\x07\x01\x1e\x14\x0d\xbda7\xd8\x90\x9d\xf3i\x17\xc1.\xa3\x04\xc3\xda|\x1b%\x97\x9a~\x15f\xaf\xe4\xdf/\x17B^\x91\xed\xf3\xa2\x9d\xdb_$\xe9\xfay\x90\xa3\xf3\xf4w\xe2\xef\x8e\xfd\xc8\xe2\x9d\xfb\xa2\xcb\x05\x18\xcc\x15-\xaco_\xffp\xa6\xbd\xea\xd8\xad\\>M\x9d\xea\xd4{P\xa0\x0c\xe0\xf5d\xb9\xb4\xebJ\x07\x1an\xc1\x84\xe3\x8cL'\xeaC\x0d\x1a8\x1c\xf3\xf5v\xa7\xc6\xfa6\x97Uh\xbe\x07.\x1f\xbcXT\x1e\xf9\x87\x0f\xb0\xa7u\xd0\xb0f\x80WH+\xb2\xac`\x15\xdb8\xdbn\xb8\xa8\xcf\xe6\xf0\xad\x9c\x0d\xaf\xd9\x16\xfc\xada\x95\xecH!s\x94T\xb7\xd0\xe6\xe2H7(\x90Lf\x9ci\xbb\xce,\x89s\x16\xe7}\x1a\"\x1e\x1a\x9a\xb0LE\xc6\x11u\xb3Z]\x1f\x9c\x9c\xdd\xe4\xfb\x9b(\x08\xe3\xc7\\\x8c\xcfX>y\xfb\xe6\xbb\xfeCG\x05\x97-\xb0H\x86\x8cRo\x06\xbc\x95.\xdd\x18\xaayx\xd1\xf5\xd3\x91@\x8d\xa6qz\xc1f\x13\x85\xb3\x80S\xb6\xfd\x9b\xfe\xf5\xf5u\x9f\xa3x\x7f\x9bFda\x9bWgm\x94`\n\xec \nxI4\xa5\x95\xbf\xca\xeb9!\x8521\xef/\xf2\x1b[@j\xbdPy\x11\x0db\x90\xc8\x04P.\xd6\xa5=\x0dz\xad\xcd\xb6\xe2v\xa7\x9e$\x954`\xe1,\xd9r\x8d1\xc9QdS\xe4\x17x5\x082\xe0\x8bnC\xc8\x1d\xc6\xcc\xb1\xadj\x9d\x85BP-\x91\x97\x0e[\xac\xf3\xd8\x1a%8\x92;\xcfq\xd4\xbeO\xa5\xe5\x17X\xc7g\xebz\x83|\xc5bwk2D\x8b\xe1\xe6D\xfeZh\xd2m \x8ak\x05\x06\xc1Q\xda\xfb\xd85i\x88n^\x98\xf74Kx^\xb1\x84OQ\x956\\yq\xf3i#\xeb\x95\xda\x8b\xddU\x0b*+\xa6/D\xa7\x95\xfb\x0c\xb4\xe7\x00\xbe#\xda\x97\x91\xddB\xd1uQ\x8fj,\n \xae\x15\x9dt\xb4\xe7#\x94\xa8\xbah@\xd5\x9f\xb3$\xfe\x9c\xb6\xfft\xf6\xf2\x05\xf9qX\xa9W\xe9\xbdMY\x98Y-\x18\xf2\xcc\xc5U'\x80\x7f\xff\xe8\xa1\xeaP_\x7f\xa4\x15\xba\xb5\xc4x\xe6\x0f\x06\xf5\xddhK,\xab\xeb\x0d\x92\xd06%\xb7\x85m*S\xed\xccR6gq\x1e\x06QFn\xdf\xc5o\xaeF \xf9\x00\x8a\x00\xb7\xe2\x05\xa1X\xe22\xf9FE\xfe[\xb3|\x95\xcc\xb11\xfaS\xbe'\x87\x19\x86\x7f\xf8t*\xaa\x1cx4I\x18\xef\x1cC\xe9\x9d_\xb57\x18\xf6P\x13\x0ci\x96\xca`i^~\xc3\xec\xf3\xd2o\x19\x98\xb3\xf2\xceI\xd6a\xee\xf8\xb0W,NE\x98\xb2/Vn_\xacv\xd2W\x98;\xf3\xe4\xedfc\xcf\x04\x00\x05\x1a\xdc*\x8f\x0ftF\xef\x8f\xb8\xbcit\xe7\xfb\xe8\xe6r0r\xe2\xc5O\xe7?N\xde\xa8\xe8\x87k\xe9\xf8\x84\x7f\xa8\xc2\xe2\x87\x96\xc5)e\x0b\x96\xa6( \xd0[\x17\xdb)BRj\x1d|\x7f\xf2\xecy\xed\x0b]\xc7\xb7\xc0<\xaa\xdex\xd12\x8a\x92k6G\xb6\xf0\x1f'o I\x81\xb7\x06)\xfb\xdb\x96eyfB\x08\"rR\x83w\xe3nV\x99E\x07\xab\x8c \x83MV{L\xb1!/\xdf\xddq\x0cV\xc3F3B\xabxP\xbam8i\xbam\xc8\x9f\x94.\xdd\x93\x05]\xcb&\xd2\xc3l\"\xd0V\x1d\x0f\xf7\x04\xf3\x9b8\xc6\x06\xec\xcc3\x97\x16P\x83[\x10\xd7\x91\x0d\xaf\x13\x83\xf4 \x16S[W\xeb\xf6\xa6}_\x93\x86\x0d\x951\xf4\xd3\xa3w\xf1\xfe.\xbbY\xdb\xacq\xdb\xd5\xd0b\xa3\x08\x8a\xec\xe2C\xed\xb6\xbf\xfeH\x7f\x07\xb9qc\xa7\xb9A\xd0\xf7*\xf5\xab\x9e\xb5\xf2\xf9\x9c=\x98[\xf9*q\x84\\O\xb8B\xaa\xf3\x04\x1c\xe1\xea#\x95\xe4,\x0f\xf2-'\xb7\x0e\xfd\xe5`jLN\xf3\xe4\xa71\x1c\x0c\x87\xa2t\xf2^\xc5\x8b\xa5\x8fO'\xfc\xab\"\xe7\xe2\xed\x138TU\xe8\x95\xb49\x14\xbfj\x1da\x9118/\xff,\xc7f\xe7\x05\xbe\xce\xb5r\xfc_\x84\x9a\xab\x90\xa9j@\xd5\xd2/4\xf0\xb0\xc1\x82\xe5\xe68rW\"\x16\xa0\x19*tS\xc2\x18\x9c\x8a%\x01\xa7g\x08w\xc6\x1fy@5\x06\x87\x0e\xa7\xa80\xfaX\xcac*|E_\xcd\x8dp\x85m\x0cN\xa1\xd0h\x8dp\x0d\xa3\xf8\xd9*\x00\xf2'Oo[\xcca\xda\xa1\x03o\xdf7eO\x96\xcfG\x98\x05\xe8R\xd7\xd5\xad~odo\xcb\x8c8\xb6l\xc0R\xaa\xe6k#\xfel\xda\x0bM\xfd\x1e\x83\xa3)\x1aT\xa9\x8e\x9ef\xd1\xa8d&\xf4\x10r\xae0\x95\x9dtv:\x95\xfa\xd6\xb9\xe3\x17.P\x85\x1aV\x7f}\x1c\x05\xeb\x0d\x9b\xd7\xbf\x9e\xc6\xf9\xe8\xbe\xb9\x92\xe9\xfdi\x9c\x1f\x1e\x98\x8b\x9b\xde\x7f\x17%\x81\xfd\xc3\xfd\xbb\xe2\x83\xe5z\xea\xba\x93\\\x06\xba\xeb\xc6\x9d;\xc07\xe9/!\xbbn0\xbf\x99\x81\xc0<\x88\xa5\xf4K\x13V\xda0\xe3\x8d7;[\xe9\x8f>\xb4\xc2\x01\xb8\xd5E\x8d\xc4E\xf3@\xebP\x93h-\x11\x9b\xa8\xf8\xbbX\xd9\x11\xa3\x90\x0cB;\x8f\xdd\xd4\xc2\x82$\xcb\"\xf10\xd8L\x99\xe5\x8e\xa1V@$wO\xa0\x07\x8e\x8f\x81\xb1al\xba\x8f\xef\x97\xc6?g\x11\xcbY\xa7\xad\x17EU\x97|\"\x86\xbc\xda\xe5\xf6\x97,\xef\xd4\xb8\xda8\xb9@\xc4F\x82\x8c\x0e\xbb\xf5y\x8e\xcb\xa9R-\x1d\xaf\x82\x9d\x1c\xd0d\x07\x15\x07<77;w\x96\xfb\xca*\x93l\x80\x80\xf2\xea hk_\x08Ym\xb9Y\xe5SI\x96-z\xf4\xacs$\xe7B\xa6\xfc\xe1\xd4\x18\xe3s\xbaqT;\x957\x8c\x11\x9d\";\x98,\xa4u\xd1vkV\xdf\x8f\xba\x83A\xc3 9\xe0)\xb9p\x904\xa32\xfa\xde\x9bM\"\xfaT\xd0\xd5\xe57\x98L\x87\x99\xd8N\xef;\xce\x84\xc5y\x1a\xfe\x16S\xe9\xb6/S\x0eL\x06\xcf\x0fh\x99R\xc51H\x9b\xa1\xc9E\xc8\xb0\x00\x96\xb3\xf8[\xe4\xf3\xcfO~8ys\xc2\xf9%W\xd8}\xa1\x9e\xfb\xe0\xbc|\xf5\xe6\xf4\xe5\x8b3\xfe\xe7\xab\x97g\xf8\xe9\xd5\xdb7\x8ea\x81fZ\x97\xb3(\x89Y\x97\x15\xd7\xa4\xb2\x19ZP\xfc\x86\x15\xbcL\xe6\xb7\xfa)\xdbi\x1cZ\xee\xd8\x1aWP\xa4\xcb\xd7\xc6\xe9\xa9\x97\xf3\xd2\xcb\xf9gNe^9\xf9o\x9a\x14i\x0fc]\xdb\xb0k\x84\x85\xaa1\xae\xaa'\xf6JB\xeb\x18K5D\xd3M\x1a\x94\xcfm\x1a\x8d\x95\x9a\xb2\xc3*\xcf\x07\x9d\xfdi$\xba\xd1\x92\x91\xc5\xa8}\xa1\x1a\x82\x82\xe8\xcb\xe3X\"h5\x9b\xcf\x98R4q\x16N\xd5\xf3\x11\xcc\xd2\xd0\x95\x88c==\x1c\x8e|8\x1c\x1e\xf0\x7f\x0e\xf9?\x0f\xf8?\x0f\x0d\xe82\x1f\xa4l\x1e\xa6\x1d\xd2\x8d\xcb'\\\xa8\xfc.\x97\x9a\x95O\xb7\x96i\x11\xb7\x94\xbb\xa9Pjg\xc9\xdcz@_\x02\xdd\xae\xfb\xd0\x05\xe2\x9a\x95\xa7(\xa1\xa3\xe6\xc6\xcb\xc6;\x80\x1e\x1b|\xafT\xee\x84\xff|M\x06A\x98\xc0\x8c~f\x9b$\xc6{\x9ds\xfe\x1b5\xe7\xae\xab\xaf\xadQ\xcdi-n\x10v@\xb7\xbe \x99\xc3^\x9aml\xa1(\xfc\x9f?\xfe\xf0}\x9eo\xc4<\xec\xa6\x9apG\xcf8\xd0\xb0\xaf\xb9\x14h;\x1e\xb6\xd2\xa7r\x0dB\xc4\xb0\x13\x91\x92\x8f\x02\x9d\x8d\x1br\xc1\xf9Y\x14\xc9m\x13\x9b\xeb\x8a\xa8\xbev\x97\x110#\xa9\xfe0a|qR\xd1\xf8\xdb\xd7?\xa0\xca\x1c\xc2\x11\x84\x03\xed-\x8c\x81\x95\xfdI\xfe\xb3/\xf6\xa3\xcf+\xb5\xf8\xbcH\x93\xa2\xea\xc8\xd0\x0b\xe6\xe9\x97?\xf8257\x19\xbb\x82\xc7\xe0%x;\xe6\xf8\x08\x16\x9d\xa9\xb1|\xd2\xaak\xe8\x0b\x96_'\xe9{i^\x87E\x10Fln\xf2\xfd\x90\x8f\xe8:\x0f\xd7,\xd9v:o\x97\xcf\x17\xeb|\xc3b7Q\xc7Q \x9d\x7fa\xaa\x1d'\x8cg\xd1v\xce\xe8\xf0!)\x9d\xf6p\xc9*\x1c\\\x87\xf9\xea\xb8tND\x15\xd5\x16\xddn\xe46\x96|\xc1\\m\x17\x05\x17!/\x0c>\x00 B;\xf9G\xcb'\xe4\xea\x95\x80:B\x03\x8b\xbb\xb4|\xb8$\xc9+\xc5sWsoO\xb4C\xb7#:\x8a\x1b\xeb/mR\xa9\x99\xd8\"\xf9\x1cl\x92\xe8v\x11F\x91\xc9+X\xfd\xe5:[y\xd1_\xbfk\x90\xb1h\x01G\xf4\xdfXS\xb1>\xeb\xa2l\xec>\x1a\x9a\xae\xaf\xf0\xf7\x0f\xcd\x17\x92\x1e>\xb2\xdc<*\xef\n\x85!\xe6\x84\xb0\xdc\n\x1e2\x8f!)\xbfUQ\x02\xc6\xb5\x9c\xf7\x9f9\xbf\xc3\x87\xd5y$j\x1e\xf5\xf9\xd5!\xeb2\x0df\xef\x19\x9fHg\xd3\x00f\x84\x9b\x9e\xd7e*\x83\x0d+\x8c\xe7\xe1\x8c\x95Zo\xe7\xab\xd4\x01f\x96\xa3\xe4s]zJ\xd9\x86\x05\xad10@\xeb\xa5\xdej\x19d\xeb\xf7\xd2\x9e\x079+Y\xcdN\xcf^\x92\xe1\xac\\\xd6\x1c\x8dg\xce\xa2p\xcd\x15\xb31\xde\x0e\xae}\x97\xc1n\xf6\x0cR-}K\xc7\x90\x8a\xe0\x13\xb6\"\x7fA]\xfde\x1c\xdd\x8e\x8d9\x063\x96\x86A\x14\xfe\xc2\xf8\\vX\xad\xa0v{U>\x86\xbd\xc8\xde\x87\x9b\x17\xdb(\xca,c@p\xe6\x05\xbe\x0f\xe2y\x84\x91Q*V\xf3J\xa3\xba\xc6\x0eL\x04~Q\xf1\xc82\x1f\"\x9f\x8buE\x88\x04\xd3l\xa4%\xdb\xc0R\xd1\xdbZv\xa0{\x82F\x1eV\x89\xb8Xwe\xba !\xdd\x82\xaft\x7f\x0e\xbe\xb6Tq\xe36\xd6RW\xc2\xaf\x9a\x04\xfdP\xb9LQ\x06\xb4\x15\xa7\x93|D[\x01\x0c\xe8\xfbf\xb8\xe2\xcd\x9f+\xf4\x8fm\x81u\xb0{\x9c_\xa1\x84U\x8f\x97A\xefe \x80\xea\x87t\x10f\xe2V\xc1\x95\xa7\x0d\xff\x08\xa6s\x17#\xc4\xc3\xb8:\x07\x8f#\xfb\x84\xa3\xfd\xdc\xcd\xdc\xab\xd2\xa7s\x18\xf3\x9a\xb1^F\xb8x\\y\x9eA\xa5\xe2\x9b\xbd\xf6\xd1~n\xb2\xe0\xe0\x96\x15\xcc\xf0J\x0d\xd1\x10\xff\x8f\x97-\xdf7\x8a<\x0f\x8f\x07\"\xcb\xd6\xdaU\xdc\xdbJ\xda3\x13t\x808|\x98\xc1\x11\xdc\x0e\xb2$\xcd\xdd\x19\xdf\xe0. \x9a\x94\xa9\xf3\x92\xbc\xdd.\xe1 \xac\x95\xb7[\xafw\xd9\xa4\x7f_\xc0\x04\xd6\xd3K\x8b\xc1\x0b\xdd\xbd\n\x80\x9d^`&\x07wY\xbd9\xef^yp\x04K\x99S\x86\xb9\xbc\xa8\x0f FP\xf3Z\xd0\x96\xcf\xb3V5\x86\x1e\xb8\\8p\x06|\xe7/T\x9e\xd2\x0b\x95\x9b\xb4\xb9Q\x03\xd1\xaa\xbd\x91\xfb_&CfQ\xa0\x91\x99\xa9s\xfd:\xe1\x0b\x80n\xe5\xa6\x83 \xcb\xc2e\xec\xfe\xfd#606\xc6\xcdQ\x01\x99\x02\x89\x07x\x8aS\xdc\xf7-\xbd\xd7\xc8W!T\x05\x05\x810\xba\xd1\x9c\x88\xfa\xab\x00\x03\xa0_2\x08\xd4\xe4j9E\xaeD\xdc\x1b\x0do\x82\x81bjp\x04[\xed\xd7X\xffV_\x89\x19\n\xc4u\xe2\x11\x0c\xea\xcc\x01\x8e\xcc\xaf\xc7\xb05\xbc\xae\xf7\xb5\xb0\xf7%\xf9\x14u\xa1~a\xcb\xf2W\xbd\xc1\x8d\xb5A\x11\x18\xea\xa8\xf8s\xac\xa8X\xbd\x1d\xae\xa2\x1b\xb9N\xb1\xb1G\xda\xdfES\x86\x05]\xd9\xdb\xca(\xa5\xbc\xf8\x83N\x8b\xea\x0d\\\x15;K\xb0\x85\x9eU\xcf\x93\x1cy\x8e\xf6\xb3^u\xdd\xd0\xb7.n\xd0 Jop\xa5\xf57\xf5\xd6\x97-\xab]H<\xdaji/\x8be+^\xd6\x91\xad\x04\xd4$\xdc{\xea/4\xa2\x0bo\x93r\xd5\"\xf3U\xa7\xc8\x15\x89h0gi\xe6\x17\x1dY\xb0\xf3m\xfc>N\xaec\xa1k@\xb2A\xf1g\x93&W\xe1\x9c\xcd\x8d\xf8)\xc2\xb1\xe2\x80\x8b\xae\xa6\xb2\xa7\ni\xb7l\xda\"\x8c\x08\xa1\xd1\xa1\x95s\x12\xf9\xces1/\\\xfd\x06\xae*\x80\xba/&o\xd7\xab\xd5\x07z\xedc*\x82*oF!D\xc6\xc2)\xe8\x98\xee.:\xe1\xfd\x0bj]\xbd\xf8s\x8d\x9d\xa2\xff\xc2w\xb4h\xc2\xc0R~9\xe6\x8a?*&\xa8\xba\x07X@\xbc\xe1lF}\x1csE\x9f\xeb\x15\x8e^\xa7>\x9b\x1b\x98@8\xbd\xaeL\x06\x83\xc8\xb8U\x96\x1f{\x18\x0d\xeb\xce\x1d\xc9\xdc\xabw\x1c\x15\x0f?#\x1e~\x06O\xe0V\xe3\xe1g6\xe1\xf6\x18&p;=3\xf0\xefE\x89w\xc7\xd3c\xe2\xdd|\x07N$\xb7\xcd\\\xfe\x1e\xa3\xf8\xde(\x0e\nG0\x97$\x83C\xd6\xca\x87+\x9f\x0bV\x17>,\xab\x8c\xf5cm]\xdec\x07\xe8f\x16\x19\xcc\x9c\xcf\xd0P \x90.\x98\xcf\xff\x9f-Ko_\xa5l\x11\xde\xf0m8r\x0c1\x9e\xc4\xce\xbf/\xf2 \x0c\xe1\x08\x9eA\x0f\xdeW\"\xfc\xe0_\xbf\x8az\xdd\x82\xeb]\xf4nEN\xcd*\x12~Vn#\xb6B\x1c\xa4\x7f\xe0,v\x0c\x07\x06\xa5\x91\x1c(Qi\xa4?ME\x9au\xd29\xdb\xe4\xab1\xdc30\xc1 \x0d\xd6,g\xa9\x18\xc0\x88\x1d\x1a\nEA\x18\xd3j}1]0\xe8\x10L\x05\xda\xbce\xd5\x0ekl\xeeH\xcb\x92\xb1\xffn\xe0N\x7f\x1aL\xcf{\x1e:\xb2N\xffmt\x8e\xf7\xfa,\xbeW 6z\xdf}7\x9d\xfe4}w~\xfe\xcd\xb9gK\\\x03b\x16\xe5\xc2\x94h*m:\x86\xe3\xd4\x0d\xc5Gq\xa5\xda'\xb2\xc5n0!\x85\xbdb\xd6p\x8e\xcd\x97\xa9\x16\xcd\xacZ`/\x1e\xe8[ \x98/\x0c9Z\x15\x1504\x1a\xa5\xab\xae\xc0\xb0$\xdav\x83vF\xa7\xe2\x86;[`=\xfdQ\xc4R\xe4\xf6VB\xb3\x1b`\x08G\xb1\xa88\xa6\x08\x9e@<@\x90n\x0c\xf3\xcdg\x1cA\x0fC\xe7\xef2\xf3`::\x17[3\xf2\xa1/\x02v\x7f\xc6J\x04\xc6\xa0\x14`]\x0ci\xab\xe1\xdd\x8a&HQ\x92\x10\xa3\xc0E\xe8M\xd6\x01tA\xb0Ry\xb9\x0d\x1c\xa9r\xca\xf2\xa2%7\x1b\x89\xe4\x03\xc3\xc7\xd0\xef'm\x8d\x81@\xd0\x90\xa2\x98\xb3i\xd2\x90\xda[>(9LE\x0c\xb6\xc0Cl\xc44\x08\xd3sO\xb28\x9b{\x99\xfet\xb8M-\x1f\xb4\x18\x97\xc1\xe3H\xf2\x86Y\xca\x82\x9c\xa1\x0eg\xd2\xefl\xcf\x95\x08\xe5\xc7\xb7\x8d\xd8b\x91\x9f\x91+y\xe7\x95\xd7\x81\xb6\xc6\x1e\xc9\xd7\x1a\xfcq-\xcc\xbe\xc7\xd5\x87S 4_\x9f\xc6\xb9\xbb\xf5ad\n\xd9`z\xf6\xc2\xecE\xf0\xc2\xcdp\x88\x01b\x1f\x06\xbd\x17\x06\x9a\xcc\xc31\xe3\xab\x8c\xc2\x8c\x8a\x1c\xc8i\xc6P|\xcc\xe8\xd3\x13\xa4\xc7\x8a\xa9\xc1\x91\xda\xc0iv\x8eQ\xf0\xc7\x10N\xb7\xf8g\xeb\xc0\xcc\x18\xa2?\x1cT\xc3\xc6R\xcdm\x08l\xb3\x0f\xe5\xa3\x9b \xec\xa9\x15\xa9\x98\x9a?\xc3\xcc\xf0 \xf6\x84X\x88\x03U{B\xe9\xbd\xd1\x9e\xa0JX4\x96\xe7l\x07{\x02\x8ei\x10.\xe3$e\xba\xe4\xa7dB\xc3G\x1f\x87 \x8d\x0c\x13S\xacl\xbd\x80\xb0D\xbef\xcb\x93\x9b\x8d\xab}\xf10I\xa5n\xae\x085s\x85\xe4\x12\xbc\x83\xba\xe5S~\xc3?eI\x8c\x83=\x11\x9eZ\xc1\xa0\xf8\xe9#f\xb1\xcd\xb1\xf0B\x0e\x06\x17\xea'f\xa5\xc8f\xc1\x86\xbd\n\xf2\x95\xba0\x8b\xa5\x0c\xefy\xf1ml\xab`\xfcR\x1e\xfe\xd6\x90\xd7\xaf\xd5\xad^\xc0c\xbb\xcf\x01]\xd0\xbc\xccXzE\x1e\x9c\xd3syk\xf3\xf2g\xa8f\xfc\x80\xba<]\xbdQ\x17\xed<\xb4\xb6@\x95\x9cv]\x06\xb3\xf7\x14\xc8\xad4`\x98\x98\xa2mV\x07h\x8a\xfd=\xab/I)\x8b*\xe5\x9cJ1-\xb9\xa471<\x81\xf41\xc4\xbd^]\xcb@\xdb\xce4>\xa7e\xc3H\x0bd[\xb7N\x0d\x19VlQ\xb7/S\x16\xbco\x99\xd9\xc2\xcd\xe9\xbe\x88\xaf:\xe3\x7fm8\x14s\x11\x0b\xd3D\xa8\xdfR{E\xabJ\x81\xaaz\x1b\xa2\xa4\xe1\x08\x81R\xc8\x8a\xefF#q\xa8\x1b\x891\x94\xad,.`\x8a\x15\xfb\xa8n\xfc\xf0_n\x88\x89\xbf4jY\xdf\xac\x85\xab\xb2\x01\xd4,\x1a\x18b\x82\x92\xe9\x98\x96\xda(\xa4\xe7\x83<\xf9\xd3\xd9\xcb\x17@9X'\xea\x85k\n\x14\xa3\xe0\"D\x9epAK\xfdg\xce\x9ar\x8f\x84\xa1\xf2[\xe6\x91\x98\xb37\"\xde\x17\x94\xac3\x99\xb0\xced\xfd~\xa3X\x83\xe6\x18\xe4T\xd3\xec\xbc\xc1\xa2\xb8\x97\xd6.\x8e\xf9\xb0\xf1*\xd2g>\xdd\x9cWt\xd0\x08Mf$\xc0\x94\x8f\x98rO\xc5\xac\xb7\x9bg\x92\x0d\x1e\xd9\xac\x93+\xd6\x90o{\x13\xe4\xab1\xdd\x0c\xdc'\xf3\x98\x81\xe0\xb9\x1b\xfb\xc5\x1c\\HK\xae\xd7\x16\x03\xd2\x95\xc8\xf9\xc2\xe7n7\xaf\x18\xf2ADP$i\xa2\x1f\x86B3\xbd\xd0\x8c\x0b\x89.\x89\xa2\x1cJ[\xe7\xcb\x85\x1d2\x11`;\xee\xde\xd0o_r(\x96\x1d\x05\xf3\x86u\x87\x1d\xd6\xbe\xb9\x15\x11}9\xd5X\xa0;kr\x81\xedjF5\xfbEm9\xe0*j\xb2W`\x8f\xb9YDNMm\x08\x15\xb5\xcez\xbd&\xeb'\x07\x8e\x0d\x9e%f\x0d\xc0Q\xc3-f\xc3-\xae\xfau\xde\xbf`>\xff\x87\xed\x1d\x1fm\xd3\xf6u\xd8=\xcd\xc5X\xfd\xc5\xa5\x1c\xc1\x96\xdb\xeciZQ=+\x02\x97\x94:\xb6\x80\n,\x99\xbe\x9bE\x9cR\x08\xb3!\xf1\xf5\x82\xa1\xe7\x94`871tPL=\xd7\x98\xba\xd2\xe1\xf9\xeb\xf2\x9a\xd4\x02 \xf1\xda\x898\xdao\x95vJz\xb9\x90?\xb9bq\xfeC\x98\xe5,F\xfb\xa3\xed\x93\xeb\xac\x93m\xc6\xb6\x1b\x87\xac.\xd6b\xef\xd9m{!lk\x9e\\\xc7m\x05\xdf\xb3\xdb.\xc5f\xab ^2,\x85\x807Of\xdb5\x8b\xf3\x81\xfc\xe3$b\xf8;\xc8\xf3`\xb6\xc2\xda\xae\x93\xc4\xe59u\xad\xa5O\xb1k\x9d\xea\x8c\xbb\xd6+/@\xd7Z\xfazt0A\xc4\x15\xb9;\x16\xaa\x01iO\xb1\x99J\x9b\x80z\x86y[\x8c m\x84\xddV\x12\xa7\n~!R'\x1f\x03\xc9+\xf4\xc3\x12\xc9C\x9e\xadw%r\x80\xc7>\x8c,\x08\xc9 _\x87\xaehH\x02\xb1\x0d\x13\x0d_-\xc8h,i\xc0G{\x8bu\\\xb3\xb5\xa9J6\xe3\xdb\x9c}\n\xbeUju\xc27SO]0\xa7\xdeW1\xb5\n\xeap\x8eT\xc0\x01\x85n`\xd7@I\x99\xbcRD\xd6\x8fd\xad\x8aYJ&\xa8\x19\xff\x8dv\xbe\xb4\x9b\xa0bp \x91F\x90B\xb1Em\xbd\x9a\x01\xac\xc9h\xa8\xb4\xe3\xcfI\x02\xd69\xadW)\xe1\xafQ\xa9\xd63\x94\x1d\x95~\x8d!\xf6\x06\xd9*\\s\xf6\xdd:/\xb9dZ\xc6\xb7%\xeer\x86'\xf2v\xa2%\x06\xdd\x12q'\x90\xadi\x92\xa7\xd9DdH\xab#}!-Ck\x0d\xf6\xa3mo\xbd?C\xee\x17uK\xcb\xac\x82\xd2\xfb\xfa\xb1\x19\xd3\x8c=\x9d\x9ce\x99\x0f\x0e\xff\x831\x87\x1cij\xb56\xa2\xfciv\x12o\xd7\x14\x11\xc3P\xf7\xc3\x07\xdd\xa5\xec\xa3Kq4\x0b\xc8\x89\xe1\x08}\x0b\x12oPD\xb3\x9f@JVR\xfdUb\x04\x94\x9d|\n\x8d`JQ;p\xe12\x11F\xad\xfaQ\x85\xf4(\x1d\xa8Y\xf6F.y1ih\xba\xebU\xda\xd1\xe6\xf1\xb1\xc1,\x89\xb3<\xdd\xce\xd0\xc0=\x99\xe8\xdf\xd0t \x86\xabv \x8e\x8aI\x8d\x0d#3A\xb9\x1d\xea\xb4\x93\xcc#\x0ee\x11\xb6\xaa\x9fh\xf2\xf7\x1a_\x1c\xeb0:)9z\xd7\x8bR\xa2\xc8#Sz!\x07\xcf\xe5K\xed\xb5\xf4\x9b\xb6\xe1\x96!g\x8f\xc4e}\xc8 \x0d\x00\xb3\xc2\x8c\xd58\xb4/\x81[\xc9Bo\xea\xcc\x90\x7fG\xe9\\\xeb`\xe3\x86\xcdc5\xe4\xa4\x91\xf4\xdcz$,\xe9y\x15\xbdE\x80%7\x9f\xc6\xe7\x18W\x9dM\xe3Z\x10\xfc:\xb57\x8c\xca\x90\x87\xa6\xa4\\+\xbaZ\x18\x82G\x15\x83\xa3*2\x1d\x9d\xf3\xb5\xd4\x7f\x8eIX5;\xf0bT6\xb6\n\xae\xc2d\x9b\x8e\xc15\xf4u`\xed\xeb\xa0\xdc\xd7\xc19\x1e3z\x83r\xabx\xc5N\x9a\xd5J#Pg\xe4|\xeb\x9a\xad\x0d\n\xb91&u\xb9\x15\xcf'+:}\xf3\xa5\x13e\xc4\x85\\%\xf2F&Y\xb7\x94\xbf:\x9dF\xe7t\xda\xad\x1f\x91\xceD\xe2\xe8\xe1c\xd8\xc0\x13X\xa8\x067v#\x18o\x11#WL7\x0d\xa7\xe6+.\xf0L\xe7\x0d%\xae0\x97\xe3\xaa\xc1\x12\xb5\xc6\x12\xe1tn\x8b\xef^\xba\x8a\x80W\xde\xec\x12?\x96- \xe3\x13X7\xa9\x1b \xe6\x8a\x0e z'k8\x02>\xa8\x0e>\x83!%\xc0\xce\xd0\xebk\xba\xf4a\xeb\xae\xbcs\xa3\xbb\x99|D\x9clQs[\xbbz \x1fu\xadE\xa76m\xf3\xd7\x8av\x9a\xfb-\x1ex\xdb\x86 \x1f1V\x07O\xbd\x1d\xe1\x17VA\x13Z2\xe9+pk\xbe,)\x9f\xf2\x1a\xd8\x07\xa0\x97Z\xd5J\x18\xd5\\\xfd\xc0H5\xd3)\x17f#\xd5\"\x12$NA\x90\x84\x1dA\x8en\x1ecL\x1e\xcd)\xc1Hd6(R\x1a\xf0\x02\xe7zk\xd3\xd4,\xefg\xe4\x16Q\x8c\xdd/\x06=\x88\x93\x1f\xb7y\x907*\xe6j\xf0\xcc8\xf8\\\x0d^\xe6g\x18\x92\x1e\xcdH\x8f\x06\xc1\x07\x8a\x81V\x0f \xd5@\xc9\xbf\xd1<\xd2\xeb0_\xbd\xc4+R5\xdfI{\xba\xd5L}\xafl]\x8b\x8cg\x0f\x0c!\xf3\x8fC\xec>\x1a\xdd\xab\x10\xa0\x8b\x0b\x96\xfd\x98\xcc\xb7\x11^\xf3\xdf\xad\xcb\xd8\x1d=x\xc0\x17\xd0}t@\xff\x8d\xee\x8b\x9f#\xf1\xff\xa1\xe7\x97\x05[wt\xcf\x1b\xfc\x95\x05\xef\x7f\x0c6]\xfah\x10]}\x99\xc9\xf7p\xe4\xb9U?\x8ePtV\xbd,C^\x0e\xa3\x83\xbb\x95\xf7[j\xea~5Y0\x0d\xfa\xd1\xa8\x1a\xbb\"\xa2\xf2\xd5\xe6g\xf8\xfa^\xd5{d!\xbcG\x0e*\xef\xf1\xdcr\xb0d9_\x91\xf2\xa7y\xc1\xbb\xc2\xec\xe4&gq\x16^F\x95\xcb\x1e\x9c\xedd\x83\xed\"\xcb\x93\xb4\xf2\xe9\x8a,\xca\xa5w\xed\x01d\xab^\x076\xaa)Y\xb8\x88\x8ag\x904\x86%qbx\xaed\xd3V\xd7\xe3\xf2\x98\x97FYg\xc9:\x05\xd6\xc0{\x13(A\xdb\x89\xbf\xa4q\x1bcj\x06\xf9\x88 \x0b?\xe0\x1c\x8e`\xe5.\xc4\xec\x1d\x01\xcf\x8e\xe7a\x0c&\x94}1\xfa\xb6HU\x14\x16\xb37v`8\xf4\xab\x8b Yy\xca\xedAK\xb2\xc1\x9c-\x0c\x83\xf4\xd1?d\xc7m\xb8\xadj\xa8\xee\xa3\x83\xa1\xe7\xaaV\xf1\n\xde\x12o\xbb\xef\x0d1\x96Q\xb1\x963\xb7\xcd\x18\xf1\x00\xf6&\x80\x96\xa5[\x0fs\x7f\xc9\xbb,\x8b\x94\xb1_P\x18\xa4\x17\x9e{\xe5\xf9\xf0\x80\xd6Yc\xff\x1fI~\xdf\xba.\xa6l\xe3\x9f\x8f\x0b\xad\xd0]\x977I\xbb!\xb3\xf4|\x08\x06/NN\x9e\xe3\x01\xba\x0f\x89;u(\x8e\xae\xe3\x83\xb3\n2\xfe\xdf\x92\xe5\xfc\xbf\x8c\xe5\xce\xb9\xdf\x00w\x12\x96n\xb5.j\xeb\x8c>\xf2\xb5x\xc1!\xc6L\xd2\x1a\xcf\x0d^\x1c\xa0`:'\x03\xc4\x1c\x9d\x10\xcc`@\xb0\xb7(\xd2\x7f\\,\xc4\xe1TSP\xe3P\x065\xbeXL\xd99\x8d\xc2\\Zj\x86|U@\xe8\x9b\xbc&\x8c\x0d\x97\x18\xec\x0e\x91\"\xa8-\x02i^\x8b\xe5\xffQ\xdfc\xfa\xbbs\xa2\xf0G\xa3\x87\x96\xc8I\x8dh$\x07\xc6\xae]\xd4\xbe\xf5\x10\xaf\x9d\xf8b1\x82\x1a\x7f\x10\x1c\xab\xc6\x96\x04\xbbz\xe4\xb9N\xb6a\xb3\x90\x95\xd2\x84t\x93\xd8\x10\xf8\x8cb\nj\xe5\x1c?LW(\x84\xf1I3\xa2\xa0}\x8a\x9c\x85PJBHK\\\xcd\xce\xe5\xa9\x1c\x08\x82\xa6\xfb\x90\n\x90T\xe6\x10\xf2\x18\x9a\x86\xe7\x9e\xf2\x1f\x12\x85\x8b\x1c\xf1\x92\x96R7\xe3\xd6T\xf6\xdd\x85\x03Z\xe7\xe1}\xe3\xfas\xf6o\xe6\xba\xc2\xcd\xb3Z-0\xef\xa6\x10\x1a\x86UaBH:w\xab\xef#%\xaf\x18\xa5\x86\xaat\xd0$5DnU\x92\x9b\xe3\xdb\xea\xc8WxxT\x86\x93\xaeR\x00\x1b\\`\xea\x07\x17\xff \xd2\xb1\xae\x1e\x10\x94~\xae\xdbN\xcb\x90\xb2\x04hrojg\xd9\x86\xa3P\x8cr\xe3\xb2A\xd0D\x94+\xe5\x19\x17F\x10\xf0j\xa5\xaa\xd9\x90\x0b\x98Zk\xd6\xc3\xaa<\xd2A\x16\x91|a)\xe8\x9c5 \x94:\x83\xcb\xa7\xa3\xc6\x15Z\x05\xad\x01\xd2\xa4\xc8\xb2W\xf4\xda\xd4b7\xf9B\x1e;4\xcd$F\xe7yT\xf5r\x99\x021\x10\xf1\xa5Y=\xbete\x1c\xc4|\xdb&'WT\x043\xd6\x01\xa0M.\xca%\x00\x18\x9cv\x0d\xb3\x11\xb5\xfe;\x07\x99\x88%\x90\x07\xa2\xb9\x8f\x97\x08\xf6\xf6\xfe\xbb\x9aTF\xfd\xe57(fe!e\\#u>\x84\xb6\xa9\xa3\xdbc)J\xa35\xc4\xeb\x96\x7f\x8d\xb0E\xe7\"$g\xd7\x8b\x9c\xdcE\xd8\xe0\x82S\xbcU\xaf\xe7\x83@r\xa2\xcc~a$\x04\xbc|\x97\xb9)\x8e\x88M\xc3ss*|\xfb\xd2\xa5n\xa4\x8b\\\xe6av\xdbv\xf9\xa0Gg\x80\x92\xbd\x04\xf3\x91]x\x97@\x9b\xec \xe2s \xbeR\xd2s\xeey\"\x11\x03I\xf71_\x93\x99\x1b\xab\x9c8\xc8\xe4D\xfe\x85X\x89\xfd\xc6\xbe,\xee3\x1d0Z>\xff\x88\xd9\x8bD\x0f\xa6\xa9\x9bgi\x80\x10\x1f\xa2f\xcc_\xd4\x91\xc0\x86\x01)YK\xd1\xb7x\xcft/\xb8<\xa1\x14'\xc4H\xbb\xc8\xc5\xa5\x9bt\xcaP9\x9b d7\x0dM\xa8\xd8c\xb8*P\xfb\x0f\xf0\x05$\x94\xaa( \x04D\x8b9\xa3f\xb6\x08\xcc\xf6\x06\x12L\xeeU[\xc9,RQd\x91Wf\x16\xf9fa\x16\x876$uW\xc3\x9b\xce\xf1\xf5\xdd\xa17X\xd4e\x13\x8b\xf9\xe6\x8a\xea\xdcm\x15\x82%\xa5$\xed\xf3\xd6$\x13_\xe2y\x003\xd8\xe6/`\x02\x97\xf5\xd7\xd7\x9c\xbf\xe1!!\xa30;f?\xd4\x13\x98\xc0\x05G\x86\x8b&m\xef\xc6p\x1e%@\xf3\xcaz\xba\x89\xcd\xba\x18\xad\xe7D\xe5\x16\xe1Rx`W\xa5\xf9\x83*\xf4\x85'\x93*\xb8\x1ez\"\xb9U\x95\xca\x83#p/0\x91\x8b\xaen\x1aqm\xc6\xbf\\\xa0j\xea\\\xcc0\xeb\xe2\xe0b&\xa4\xc1K\x9dO a\xc0\xebsK\x1f\xf2\xe9\xf5y\xcd\xca\xc0)\xc0\xca\xe5\xcb\xe9\xa3\xc3\x94O\x04\xd3\x173\xf4\x97,\xf7WA\xe6g,\xf7\xdf\xb3\xdb\xcc\xa7<\x1f\xbe\x98\x8eO\xb7\x0f\x1c\x99\x9e\xce\xe7\xa3\xe9&&\xe0\x16\x82\xbcnZ\xa8\xacu\xb2\xc1 \x8c\xe1\x84\x9c\xcdq\x03\x1c\x1c**L\xa4Em]}\xc3K:{S\xa8uN\xb4e\x16 \xbe\x9e\x9cn\xa1LA\xfa\xd5\xc2\x8d\x0br\x8e\x06\x07\x1a\xae:\xaf\xb3\xab\xec*\x0f\xd1\xc5\x8c\xab\xec\x05\x05\x1frr\xed[\xd5})\x0f\x15z{R+W\x15\x89=\x9f\x82H\xcd\xcb\x8b\xe0d\xe1/\xcc1\xf1\xf6\xb2t\xdc&\x9a\xd1,\x06\xbc\xb5\xfaPjP<&(^W\xcd=dIY\xfap\xed\xf9\x90\x95G\x1a\xe3\xadOe\xf0\xf1|\xd8\xb8b;n(G\xd3\x85\x0f\x89\x9b\x0c\xfe\x03z\x90\x0c\xfe\x8a\xff~\xe7\xc3\x8d\x9c\xf9\x9a\xb3\x90\xb3\xc9J\x98\xa4\xcd\xb0\x16\xa1\x1eTy\xaf\xec#\xe72=O\xb5\xe7\xc3\xfe\xf4\xa7\xa0\xff\xcb\xb0\xff\xe8]\xff\xab\x7f\xfb\xe3\x9d\xaf\xbf\xe9\x0d\xde\xfdt\xf1\x7f>\xfc\xf7\xf9~8\xc8Y\x86\xb9\xd7\xcc\x81Wd\x82\x97\xd9*H\x83Y\xceR\xceW)\xcd\x00,B\x16\xcd!\x0e\xd6\xc6\x9c/\xca\xfa\x94'?$\xd72\xaftyq-sn\xb6\x84t\x9e6\xeb\xd4\x99\xc1\xf1\x11t'$#p\xc5\x98u\xa4\x95\xac\x82\xd6\x10\x93Iv[\x957{[\xfc\x99'1+9\x88\xb5$<\x11\xb7\xa2\xccI\xac\xc0\xa8\xe2\x99\xdf\x1a\xbcF\xc4\x80+i\xc3rS\xb2\xb0\xd6\xb5\x92\xb2C\xbd\xdf\xce\xd9~\x0d\xde}\xa0\xa5\x02\x14\x97sJ\x19\xf2\x13\x0c\xfd\xb1S\xbe\x0c2\x1eQ\xd6bs\x82\x0c\x91\xf9\xbf\x1e\xcd\x14\xbd\xeaL\xddu\xe9\x8bM\x87\xe7>0c\xe86\xadG\xdc\x03q\xee\xb6d\xb9\xe6\x1e\xf7\"X3\xae\xfd\xef\x90!\xaf:\xd7\xa9)\xab\xdcGS\xe6B\xdb\x1e\x19|\x13A]k\x90\xd9\xf8\x95\x04-\xb2 \x0dR\xc6\xe7S\xcd\xdb\xf2,JY0\xbf\x05\xfe\xafc\xba\xcc\\\xc9\xef\xdfi\x80\x06\x7fF(K0\xb5\xd4LM\x81\xec\xd8\x8eY\x93r\x97\xcf6\xdbF\xb6D)x\xff}\xb7\x8c;\xb1\xcb(aZw\x1bO\xa7\xa52\xf8n\x82F\xf1\xf8Z\x15\xb9\x97\xcdT*FW\xa9\xdc\xce?\xf2\x01\xdf\xddg\x99\x96\xac\x96\xdc}:\x8d\xd0\xe0\xc7 \n\xda0\x86\x8cvCP\x04\x9f1\x8cE\x9fQ\x91\x8f\x98\x03\xecm\xce~\xa0\x0b\xbb\x0d3\xc8\x18\x81\xae^\xd5C\x15\xfc\x12'\xd4i*QS| \xc4S\x1d\xd6G\xd54\xdf\xad\xa7E \x0f/JY\x05\xe9\"UC\x12\xa0\xd0\x9c\xdd\x81yZ\x0eE\x91\xd9\xdc\xa0\xa6\xcbG\xf9\x05\x16\x89\x8e\xbe\x8d\x92K\xcd%\xbf\x9a\xecXo\x9f\x17\xed\xdc\xbeL~\xcd\xfb\x90\xe1g:\xf6#\x8bw\xeeK\xcf\x7f\xce\xfb\xab$@\xef\xd8\xad\\>u\xc1\xa2I\x86\xd0z\xd7\xd2mC)\x87\xd4\xba\xd2\x81\x86[\xe8\xf7\xc9\x04\\\xca\xec\xc0:4\xc4\"\xb7\xb9;5\xd6\xb79\xbdB{\x00\x03\x90&\xf1\xf2\xc8?|\x80==S\xb5}\xcd\xd0\x00\xb3\xac\xc8\xb2\x82U\xe8\xd7-\xbe\x95\xb3\xe15\xdbr\xab5\xac\x92\x1d)\x84+hm\x0b\xab1\xa7\xe5\x83\x05K\xf9\xdffI\x9c\xb38\xef\xd3\x10\xf1\xf8\xd6\x12\x04\xadT7\xab\xd5\xf5\xc1\xc9\xd9M\xbe\x8f\x01\xa9\x1es1>c\xf9\xe4\xed\x9b\xef\xfa\x0f1\x04W\x05\x8b\xe4\xe1\x98z3\x10W-Z\xbb1T\xe3\xed\x7f\x0e\x12\xa8\xd14N/\xd8l\xa2\x90\x92<\xee\xdf\xf4\xaf\xaf\xaf\xfb\x1c\xc5\xfb\xdb4\xa2\xe8\xfc\xf3\xea\xac\x8d\x12\x8c\x96a\x8d\x88)\xd1\x94V\xfe*\x8d&!i\xcc\xe6\xfd\x0d)d\xb4\xe44\xf6B\xe5E4\x88AY\x12]\xb1j\xb1.\xedi\xd0km\xb6\x15\xb7;\xf5$\xa9\xa4\x01\x0bg\xc9\x96k\x8cI\x8e\"\x9b\"\xbf\x98t\x17\x82\x0c(\x93]\xa3e\xa2\xcb\x989\xb6\x9d\x9b\xb7\x99\x04\xda\x12&\xb7nq\xc9\xaaY\xa5\x04Gr\xe79\x8e\xda\xf7\xa9\xb4\xfc\x02\xeb\xf8l]o\x90\xafXl\x8aM\xfdQ\x92\xdf\x9c\x88G\xeb8\x7f\x13Pl\x17\"`G\x11P>vQP>\x15\x91\x90o\xb3A\x16\x94\xcf\xc7_\x0bM\xba-A\xc9\xf3\xbe&\xfd\x91\xbfzaS\xcde\xdc\x17\xf2\xba\x1f\n\xaf{u\xb5E:\xdf\x9f+\x1b\xc7`\x91&\xeb\xe3U\x90\x1e's\xe6\xe6\xd3F\xd6+\xb5\x17J\x99`\xcbk\xfa\xd1\xb2\x10\x9dV\xee3\xd0\x9e\x03\xf8\x8eh_Fv\x0bE\xd7E=\xaa\xb1($\xb8Vt\xd2\xd1>\xc7\xf37B\xd5E\x03\xaa\xfe\x9c%\xf1\xe7\xb4\xfd\xa7\xb3\x97/(\x06\xaf\x95z\x95\xde\xdb\x94\x85Y\xab\xe7\x0f\xf9\xf5\xd1\xfd,\x0fU\x87\xfa\xfa#\xad\xd0\xad%\xc6\x08\x94`P\xdf\x8d\xb6\xc4\xb2\xba\xde Q\xda\\F\xf9T\xf1\xcd\xac\x94)\x95\xe9\xbf\xb9\x1a%\xe4\x83\xc2Gv\xa5r4\xc7\x98\x8f\\e\xd7\xf5\xe4NQ\xd6VlL&p\xa5\xf7\xc9\x9c\xd1\xdbd\xce\xfcR\x82\x18`\x9a$\xcc\xbb\xc2l\\z\x06\xf6\x8a\xbd\xc1\xb0\x87\x9a`H\xb3T\x06K\xf3\xf2\x1bf\x9f\x97~\x7f\xf8P_\xa1\x0f\x1f\xc0I\xd6a\xee\xf8\xb0W,NE\x98\xb2/Vn_\xacv\xd2W\x98;\xf3\xe4\xedf#\xed\xbe\x8d\xc8}\xabe\x1a\x87\xa7\xd0\xa7{H\xa6\x8c\xdd\x1f\xdd\\\x0eFN\xbc\xf8\xe9\xfc\xc7\xc9\x1b\xc7+\xefcN\x7f\xa8\xc2\xe2\x07\xe5\x9d\xc1W)[\xb04EI\x80\xde\xba\xd8\x0e\x99V+\x1d|\x7f\xf2\xecy\xed\x0b\xf9\xcbZ`\x1eUoN\xf90&4\x9b#[\xf8\x8f\x937\x90\xa4\xc0[\x939\x873\x13B\x10\x91\x93\x1a|5\x8e\x8f\x0d\xf7\x17\x1d\xac2\x82\x0c6Y\xed\xd3p\xedz\xf2\x8c\xfe\x8ec\xb0\x1a6\x9a\x11Z\xc5\x03B\x1e\xd1~cxb\xfe\xe0\xf6H\x0b\xba\x96M\xa5\x87YT\xa0\xad:\x1e\xdc \xe67q\x8c\x0d\xd8\x99g.-\xa0\x14d\xf8\xed\xeb\xd3\"&\x19\xd7\x91\x0d\xaf\x93\xeeq\xe1:[\xb77\xed\xfb\x9a4l(\xad\xf4\xfe\xbb\xf4\xe8]\xbc\xbf\xcbn\xd66k\xdc\xb4\xda\xe5\x8d\"(\xb2\x8b\x0f\xdd2\xda\x8b\x8d\x1b;\xcd\x0d\x82\xbeWi\xed\x0e\x82|>g\x0f\xe6V\xbe\x9a+_\xfa\xbf\x17\x82\xbbH\xd0-\xae\xeeI%\x99R\xd5SXs\xfe\x17\xe6\nC\xf7\x0d\xf9i\x0c\x07\xc3\xa1\x8c\xfe\xfa^\xfa\x85\x88\x8fO'\xfc\xab\"\xe7\xe2\xed\x138TU\x8a\\\xf8E'\xfcW\xad#,2\x06\xe7\xe5\x9f\xe5\xd8\xec\xbc\xc0\xd7\xb9V\x8e\xffc\x8a\xfc\xaa\xa1\xb1j\x17)/7\x1axDZo\x1b4\xaf\xac\xc7n\xba)a\x0cN\xc5\x92\x80\xd3\xb3\xe4Q\x92\x07Tcp\xceD\xcc\x88P\x06\xa6\x90\xc7T\xf8\x8a\xbe\x9a\x1b\xe1\n\xdb\x18\x9cB\xa1\xd1\x1a\xe1\x1aF\xf1\xb3U\x00\xe4O\x9e\xde\xb6\x98\xc3\xb4C\x07\xde\xbe_=\xc3\xd0\x9f\x8f0\xc3\xe0\xd4\xcd\x94\x174\x97\xca\x91\xbd-3\xe2T\xa3\x1f\xcbGJ\xd5|m\xc4\x9fM{\xa1\xa9\xdfcp4E\x83*\xd5\xd1\xd3,\x1a\x95\xcc\x84\x1eB\xce\x15L`\xaa\xe2\xd5\x9cJ}\xeb\xdc\xf1\x8b(6\x85\x1aV\x7f}\x1c\x05\xeb\x0d\x9b\xd7\xbf\x9e\xc6\xf9\xe8\xbe\xb9\x92\xe9\xfdi\x9c\x1f\x1e\x98\x8b\x9b\xde\x7f\x17%\x81\xfd\xc3\xfd\xbb\xe2\x83%,A\xfbuP\xf9H^\xc0!\x94o\xd2_Bv\xdd`~3\x03\x81y\x10*[\xaf\xb0\xd2\x86\x19o\x9cS\x88\xdd\x87v\xa5\xc4\xc1\xd6\x10C$.\x9a\x07Z\x87\x9aDk\x89\xd8D\xc5 \xd5\xca\x8eP\x94D\xb5\x9d<\x83\x9a\xae\xde)?\xbeu\xb0\xb1:Di\x05`\x82\xa7\xd0\x18\xfd\xd4\xc7\xe8\xa706$\xff\xc1 ^\xc5\xf8\x85\x93z\x97\xad\x17EU\x97|\"u\x9f\xf6J\xfbK\x96wj\\m\x9c\\ b#\xe4f~T\x9a'\xa5{l\xebx\x154\xfbFU:\x96\x1d\xd4\xc2Bs\xe8h\xeb+\xabL\xb2\x01\x02\xca\xab'\x80\xa0\xad}\xe9\xf3\xdb\xe1\x1a\x14\xd4\x02\xdc\xc8\x1e=\xeb\x1c)\xdc\x8d\x88L\x95\xfb\xc5\x18\xe3st\xfc\xcak\xa7\xf2\x861b\xd0\xb2\x0e&\x0bi]\xb4\xe5\xfb\xd3\xf7\xa3\xee`\xd0\x92\xea\x8d\xc9\xc8lfT\xc6\x8b\x89f\x93\x88>\x15\xf23\xfe\xf5'\xd3a&\xb6\xd3\xfb\x8e3\x11\xae\xd2\xbf\xfeT\xba\xed\xcb4\xae\xdf\xf7\x92O\xd3\x94*\x8eA\xda\x0cM.B\x86\x05\xb0\x9c\xc5\xdf\"\x9f\x7f~\xf2\xc3\xc9\x9b\x13\xce/\xb9\xc2\xee\x0b\xf5\xdc\x07\xe7\xe5\xab7\xa7/_\x9c\xf1?_\xbd<\xc3O\xaf\xde\xbeq\x0c\x0b4\xd3\xba\x9c\x89\xf4\x17\xad+\xaeIe\xd2\x13\xdc\xbe\x82\x97\xc9\xfcV?e;\x8dC\xb3+\x96!\x16\xf5G\x1f\"Bnm\x9c\x9ez9/\xbd\x9c\x7f\xe6T\xe6\x95\x93\xff\xa6I\x91\xf60\xd6\xb5\x0d\xbbFX\xa8\x1a\xe3\xaazb\xaf$\xb4\x8e\xb1TC4\xdd\xa4A\xf9\xdc\xa6\xd1X\xa9);\xac\xf2|\xd0\xd9\x9fF\xa2\x1b-\x19Y\x8c\xda\x17\xca\x90D\xb7\\\x84\x96\xc7q,\x83nDm\xa6\x14M\x9c\x85S\xf5|\x04\xb34$/\xd5L\x0f\x87#\x1f\x0e\x87\x07\xfc\x9fC\xfe\xcf\x03\xfe\xcfC\x03\xba\xcc\x07)\x9b\x87)\x05\xd8\xed\xc4\xd2\xb8\xa0.RK]jV>\xddZ\xf6:\x88\x97UwS\xa1\xd4\xce\x92\xb9\xf5\x80\xbe\x04\xba]\xf7\xa1\x0b\xc45+OQBG\xcd&\xeb\xa4|,\xea\x93\x11\xf4\xd8\xe0{\xa5r'\xfc\xe7k2\x08\x02\x86^\xe5?\xb3M\x12g|{\xe7\xfc7j\xce]W_[\xa3\x9a\xd3Z\xd3%\x17\xd0\xad/H\xe6\xb0\x97f\x1b[(\n\xff\xe7\x8f?|\x9f\xe7\x1b1\x0f\xbb\xa9&\xdc\xd13\x0e4\xeck.\x05\xda\x8e\x87\xad\xf4\xa9\\\x83\x101\xecD\xa4\xe4\xa3@g\xe3bN\xa7gQ$\xb7Ml\xae\xeb\x91\xb1\xc4\xee2\x02f$\xd5\x1f&\x8c/N*\x1a\x7f\xfb\xfa\x07G&\xa2\x0f\x07\xda[\x18\x03+\xfb\x93\xfcg_\xecG\x9fWj\xf1y\x91&E\xd5\x91\xa1\x17L\x0f(\x7f\xf0ejn2v\x05\x8f\xf1\xc1$\x97\xcb\xe7\xa3\x8f`\xd1\x99\x1a\xcb'\xad\xba\x86\xbe`\xf9u\x92\xbe\x97\xe6uX\x04a\xc4\xe6&\xdf\x0f\xf9\x88\xaes\x8a\xfe\xfd\x0f\xe9|\xc3b7Q\xc7Q \x9d\x7f\xe1\xe5&'\x8cg\xd1v.\xe2\xd4%\xa5\xd3\x1e.Y\x85\x18\xa5\xec\xb8tND\x15\xd5\x16\xddn\xe46\x96|\xc1\\m\x17\x05\x17!/\x0c>\x00 B;\xf9G\xcb'\xe4\xea\x95\x80:B\x03\x8b\xbb\xb4|0j\xe4 c\xf1\\\x0f\xa6\x9ah\x87n*}\xa0\xf6\xd2&\x95\x9a\x89-\x92\xcf\xc1&\x89n\x17a\x14\x99\xbc\x82\xd5_\xae\x9e\xc1\x163[\x90lQ\x8d\x85\xf6\x07\xd1xiqv\xbai\x94\x9bn\x19\xdd\xbb\xeb\x0d\xc8\x98b\nd\x1b\x1a\xb7\xc0lQ\x14\\\xc0pLQ5\xd5J\x13\xa2Q'\x10\xcd\xa4*\x8d\x9b\xf4\xc6\xe5\x03\xd1|\x13m\xeb\xa9\xfe\xaa\xb6\xd0\xc6\xcd\n\xb5\x18\xef2\x89\xec\xdd\xf2`W\xf9Ml\xe9\x9eQF\xffE*KN\x910\xdc\x9a&\xe7J\xc4\x1b\xcd\xe0I\x11N\xfa\x88k\xd6\xc2\xbf\xe2Y\xee\xa2s\xfd\x8b\xe0E\x9d\xcee\xd7!\xae\x9a5\xdb\xfd,\xc8\x18\x0c\xc7V\xc0\x97\x0dX\x8f\xd7\xe5\x83\x0d\x1d>\xb0\xb7$\x1f-\xd9\x80\xb8z\xd5\x10Y@>\x98\x86\xad\xb9\x18\x0e\xe0\xeea\xfb\x00\xf0J\xac\xcb\xd7\xf4\xf0\xa0\x85\xdb\xc8\xc0\x86\xadm\x06\xd3\xa8\xd73'\xea\x94\x8fY\xf2\x82\xe6\xc9\xe1\xa4F\xf6\xfe\xb9\x0c\x1b\x92<6\x83\xa7\x13\xb8\xfb\x90On\xc6!\xeb\xde\x03\x0f\xd7z\x06}\xb8\xfb\xd0>O\xe5\x95\x8b\x0d\xdc\xbf\xa7\x1ax0,\x1a\xb8\x7f\x0fz0\xb2\xdc\x10\x86\x1d\x1ch\xa9\x97G\x0fT/\xa3\xe1Ac\xf0<\xf9\xa8\x15>|\xe0k\xcb-p\xab#\x045\x96\xb2o\x10\x08\xb0\xe5+\xf1\xe8\x01\xae\xc4'l3\x1f\xe8\x81}\xa0mPp\xd0\x0c\x05\x82\xc4\x98\xa0 \xfd\\(H\x7f\xe7P\x10\xea\x10\xf1\xeb\x83B\xfa\xd9\xa0\xa0F;\xba\x0f\xdf@\x0c=\x93Q\xfd\x0f\xf6_\x82\xdf\x05ER\xe2\x08\xfaz\xea\x94\x8f\xbe\xc6\xca\xf8\n\x15\xab\xa2XVP\xf2\xf2;\xb8w_2\xaa\xc7\xb0\x85'pp\xef\xfec\xe8\xf5\xb6\x1e\x04\xd3-\x86#\xfe\xa3\x03=p]\xfeqt\x1f\x8e\xc0\x19:\"]r\x0f\xb6\x05\x97\x1d\xdd\xf7<\x9b\x87\x8d\xcc\x9e\xd6hFo\xb8E\xd9\x9b\xf0\xfe\xca[\\\xf2ft\x9cR\xceP\xe1\xac\xc8\xb4T\xc5F\xcdRj\x94%\xb6j:I!\xf0=<$\xf9\x8fkNw\xefi\x7f\xdf/\xfe~\xa4\xbd\x1f\x1dh\x1f\x12\x0e\xfb\x87\x8f\xf8\x8c\x12\x0e\xfbw\x0f\xd4[B\xdc\x84\x10W\xbd%l\xc4\xb7\x8f\x86\xea-a\x0f\xbe\x1d\x1d\x1cX\x04xtd\x80>\xc4*\x1dh\xce\xd7P^(BE\x9b\x8b\xd3|K\x0f\x1e\x12\xbdO9T\xfb\x80\x05\x83ib\xb1\xdd*\x82\xc1\xeb\x1e\x0c\xef\x1a+\x8f\x1e\x1d\x00\x0e\xf7)\xdc?\x87\x1e\x7fs\xf0\x10>\xc0\xfdC\xb8\x03\x9dZ\xbew\xef\xe0\xd1}5\xe7{\x0f\x0e\xef\xde5utppWv4:\xd0{\xa2\xbe\xe1\x0e\xdc?\xdcm\x00\xcd\xd6\x87\xb0\xc1v\x80\x10\xd2\xeb\xe9pW2*\xbd}}*\x94\xb1\xb7\xafOa\x1dD\x8b$]3\xab\xdb!\x08\xfb\xc5hx\xc0\x07]\x81P\xdf\xb4\x18w\x87\xf0\x81\x12\xc5\xdd\xbfw\xef\xf0>b\xad\xa8\x9ex\xf0\xe4 \x8cx\x81\xd0\xf3p\xbd\x1e\xd6\xd6ktP[\xb0\xe6u4\x0e\xbc\x03\x01+\x02\x890\x8c\xfbT\x12qs\xe8\x15\x80\xea\x95c7\x96\x15\x95\x96\x88\x05\xd4\x97\xe5\x8e\n\xef\xd8\x94\xb9\x85#K\x98}\x17\xc6!E\xe4:\x02\x87\x93?,~\x99$\x11\x0b\xe2zSG\xe0\xe4\xe9\x96!Y\\\x04QF\x7f9\xfa\xb8\x0b:,\xf5\xa5hw}\xc9\xae\x1e5\xc51,8\x02F\x1e\x18vQ\x87h\xd1\xc2\xc5-&\x0c\xa4[+U\xa5\xc8\x9c\x0fX9\xf1:w\x04MF\x87UgR\xb9ht\xa5\x12\xfa\xd2\xd8\xca_\x89\x0e\xd8\xa2\x18%bD\xba\xe6H\x96\x03<\xb3\xa9\x7f\xe4\xf8B\x99b'\xf6d>\xa6%,qM=\xe3\x83\xcc1\x1c\xa8\x88$\\\xbd\xdbrvL\xd9\xf29GZ\x10+Z\xc0\x13\xd8r\x1e\xb4h2\xe1S\xaa\xe1EC\xa6\x879\xa5$n\xc9\x16\x11\xba\x19\xe6\xb7\xedU\xd3A\xca\x87\xafm\xf9\x12\xf8\xbcQ\x08Skp\x05\x13\x98\xab\xf9\xaea\x02W4\xdf%\xcds O\xe0\x8a\xcfs\xe9\xc1\x8c\xd3\xa4\x15\xf4p8\xf3\xe9\xf2\x9c\xf3\x1b^`-\xd4\xb0\xde\x04\x9a.V`\x08+\xbep\x91^\xdeLp\x88r\x97{\xe4\xdd\xb5W\xaf\x8bj\x02gf\xedDL\xc7o.v\xa1\x8f<\x024\x995\xbe<\xba\x04\x86\x88_\xa1-\xea\xc6\x87\x0f2[\x8fdFJ|,\xb7`\xa8\x9d\x17\"CM\xec\xba\x12)\xf1c \x08\xb5%$\x8fp\xdbW\x8e\x1b#vXn\x94P\xbdN\x8e\x93\xc1:\xb8\xf93\xbb\xcd\x94\xee\xae\xde\x18\x86\xc5\xd1m\x04\xfbU\xb5p\xa6\x84 ^`f\xa8\xb8\xc1m\x93T\xd2443\x15\xaa\xdb\xaf\xb0\x9b\x0d\x8e\xb3\xfe\xd1&\xc0r\xbc\xde m\n}D\xe1\xe9\xb9\x8f\xc86$,\x1b\n\x0c\xf3\xf1\x94\x99\x13\x96K\xf1\xff\x05\x9d\xc1\\\xd3\x7f'T\xe8\x86\xb0\xf1\xa6\"\x00\xdf\xd8\x04\xe0\xb3\xaa\x00|c\x11\x80\xcfp\x8c\xb9^tm\xa5\x1c\xbc\x82\x18<:]\xb9\x87\x0f\x10\x1c\xcf\xe0\x08\x07:\x821\x9c\xa8\x9d9+\xc4\xe0\xb3B\x0c>+\xc4\xe03RJ\xd5[\x12\x83\xcf\xa4\x12 G\xc0es\xe8\xf5(\xc2\xda5Y\x9b\xb1\x8f \x86\x91\xe6\xb4\xc7j\x0e\x035CJ\xba\xa2\xcdp\xd9\xaa\xa0\xf2\x8a\xbd\xde\x12\xabn=\xb8\x82'\xe0\xbe\x87 \xdc@\x1f\x96\\B\xa38\xd5\xb7\xba\x04~\xe5\xc3{N\xa2\xc4\x96]a\xf1^\x9bIl\x96\xc4y\x18ow=\xe6\x03\xe1\x0d7\xe4\x00\xf3\x9bo\xc5Ee+\xcc4\xdc\xf8\xf6\xee\xa1\x18'o\x077\x10\x8e\xc0\xe5\xebz\xa5\x86[]\xd6\x1b\x0f\xe3\xa9q\xd2\xf5\xc7\x83\xa1\xc0\x11\xea\xbfR\xf3\xd2T\xf3R\xaby-\x8f,\xd4\xf6\x188H\xa1\xb7\xf4zk\x1cn\xd6\xc4\xe5\x8f}\x90\xb0\xb1\xb6o8oN\xce\x97\xc3\xd3{\x1b\x04\xc1X\xfb^\x9d\x10B\x98\x8c\xf88\x81\xc8\xbd\xf5a\xc3\xdf]\x8b\xe2\xfc\xdd\xa5x'\x8e\xc4W\xeaH\xfc\xd6\xf3 \x98\xde\x9ec(KXMW\x82\x96\xf0\x17\x86\x9bY 4(\xf7\x18\xe5\x98\xdbsO\xbf\xa6\x85r\x06\x1c\xc1\xf1\xf4Xk\xe6\x12\xc6\xb2\x8b\xe9\xb1\x0f\x97\x16\xc5\x8c\xaf\x06\x06\xf5\xea\xf7\x17^\x93\xc1\x8cou\x99\x16\xdeb/D,\xd5.\x12UE\x8c\xa8\xef\xe7\x1f\xec\xbf\x16\nt\xaet\x95\xe5\xc3\x07X\xf2/^\xfd\x93\x0e\xb7\xe5\xdd\xe3;\xb7\x86'\x90\x19v\xce\xfb\xcc}\xe3Hb\xdd9D\x84\xcf\xd9\xa3\ns\x90B\xc5\x1f\xcak\xd69\x93\xc1#K*\x83\xc3\x87#\xaf\xfdtO\xba\x13\xc8\xebpp\x04\x7f\xffH \x0dAB\x8b\x91\xeb\xc7e\x9d2]\xea\x03\xaeF\xd5\x13\x03\x1e\xb6GI\xb4'\x85HE\xa7\xad~p\xa2|\xe2\xb2Z\xfa\xb3\xd6\xc8p\xd69\x8d\x0e-s\xba[M[D\x81\x05\x1f<\xea2U\xc3\x0cJ\xfaT\x7fD:\x94\x12\x16Qt\xfc\xfbG.\xad\x04\xa83\xd9D\x16\xbc\xf01\x0d,\x9a\x10\xe6\xe9\xe3#\x88\x0c\x82L\xec\xce\xf8\x07\xa0\x98\x81>\x84nDA:g6\xbd\x18\x8aU\xcfv[`\xf3\x19\xeb\xfe7{E\xdb\xdf\xc0,I\xde\x87L\x7fs\x9cln\xd3p\xb9\xca\xdd\x99\x07\x07\xc3\xd1A\xff`8\xba\x0b\xaf\x93u\x10\xc3\xd9*\xbf\x8d\xd6A\xdcT\xe1\x1e\x1d\x9e#\x0f\x99\xa3*O\xfcf\xc4\x99H)w\n\xc4\xd3\x0d\x95\xc3?&\xb0u\xe7>d\xed\xa1)M8SI\xe4\x9d\xb14\x0c\xa2\xf0\x17\x93~\\],E\xa0\xc4v\xd7WZ7O}\xf8P\xbdm\x88pY\xa8n\x05d\x86\x16\xc8L0\xa9\x1e\x88\x06\xc3\x0cB\xf2\xfe\xab\xee2\xeep\xd0\x12\xa8R\x81y\x1c\xac\x9b\x1a\x93\x1auX\x8b4A\x07|\x18\x9e\x9b\xfa\xda\xb6\xf6u\x15D-]\xe1uu\xe8\x813q\xa0\x07\xdbz\x8f\xc2R\x06)W\xb5\x9f-\xadW<#(\xca@\xdft\x18\x8b\xc7\xd4\xd9\x8b\xe0\x85\x1b\x99\" \x89\xaa\xd9\n\x831 \x0dxA&\x00\x03\x14g(\x98?\x86\x1f\x83\x9b\xfe\xb3%\xc3\xc1\xff\x18\xe4\xab\xc1\"J\x92\xd4\x8d\x9a\xa87\x1e\x87\x0c\xe6\xc9:\x08\x8d=\xe8o\xb0\xd7\xe4\x15$'(\xfa\x98\x9cUe\x9b\xea\xd3\xe6\xdd\xe0D\xc1\x8d\xb3C\x87?\x047\x9f\xd3\x9b\x90\xc5v\xe8\xf0sf\xd8\xeaF\xd4\x04\xf4j\xbfu\xa8\xaf\xb5\xd4\x81\xffj2k1L\xc9Y\xebF\xca\xba\x1aP?N\xa9\xab\x04\xfb\x8f\xe1\x9b\xfd\xf2k.\x9a\xed\xff4}\xb7\x1d\x0e\x87\x8f\xf8\xbf\x07\xc3>\xff\xef\x01\xe3\xff>\xa4\x1f\x8b\xc5y\xef\xdf\xf6M\xc7c\xdb\xdf\xeax\xac\x1a\x93\xb9\xfc\xd7'I\xf8\x1dC\xaa\x8b\xfek\xcb\xeb2-\x1c\xc4t\xefk\xd7\xfb\xe6|\x7f\xd9\x16\x8b\\\x1eK\xa0\xbbF\xc9\x9e;\xf4J^\x1ae'\x8d\xf2\xec\xdb4H\xbd\xe3n\xb3,\xb9i\xc8\x1c\xf32+\xb2\x92\xc7c\xbb<\x9eV\xcd\xd3\xb1E\xe4N\xd1U\x00\x1d\x07\xee\xdc\x81\x14m\x97\xf7\x0fG\xe8q\x11C\x0fF\xfa\xc9|\x83X^s\x08\xc1\xca\x16\xc1\x9a\x0e*\x9fbW\x07h\x1c\x12n\x1c\\un0\x1c\xcb\xe3\xcf\xd1\xf0\xe0.|C\xde\x1a8v\x0fz\x90\xf0\x1f\xd8^\x8f\x8e\xf2\xed\xe4'\xa7\xebp\x07w\x87ey(\x84}\xb8\x7f\xb7\xf8\xc7\xf3at\xf0\xd0Z\xc6\x83?\xc2\xfd\xbb\xd62\xe5\xcf!\xfeB\x1f\x84^\xa3\x1bg\xa3\xbd\xban\xf25\x9c\xc6Qh\x89\xbb\x0f1B\x04\xcd\xf4\xe0ny\x84i\xf3$S\xc3\x04R\x9a\x00\xe7\x97\xbc\x03\xfeR\xb5?zt`l\xa0^WTH;\xd8\x0d\xda\xd2O\xea\x90\xb2gw\xf3\xe7@\xc3la\xf9\xedF\xb2J\x91\x86\x0b\x96(\\\xa6z\xfe/\xcb\x19\xb2\xc4\x93\x86[d\xa1\xddAs\x9e\xb4`F\x80V!v\xc3f\x8d\xa9\xc5\x94\xb62\x99L h4\x0d\x83\xd2\xcbCx\x02\\\xbao)\x9c\x90S\xcd\xf0\\\x19\xa7\xc2^\xcf\x0c\xc8p\xbd\n#\xa6\x14'>\x14s\xbb\xd2v\xc7\x81N\xf3x\xe9\x8f\xcc\x19r\xfe`\xdfIK\x8a\x00\xd0\x9d\x04\x85v\xbaS\xbb\xc2\xach\xa3\x8eZz\x8d;\"\xbd\xc1\xd4\x99\xfet\xee\x9c\x97\xcd\x07d;\xe0\xa2l\xcd\x9e\xa3\xda\x12\xa4\xbd\xed\x92\xf0\x0ea\x81\xb0\x1a!%\x1bd\xc96\x9d\xd9\"Fx\xbe,\x18\xca\x82\xe48\x98\x0efI<\x0bD\x10Gv\x0d\xaf\xd9\xf2\xe4f\xe3\xa6\"\xe0\xcf\x07\xc7\xab\x99]\xc1H\xba\xd8`\x11\xc6\xf3\xe3U\x90\x9e\xc6sv\xd3fB\x93\x0f\x87\xd1\\\x87\x0f\x85\x89\xfd\x86\xb3\xa22\xceZ.>\x95,i\x89\xeb\xf9\x02E\x0b\xd7\x98X\xa2\x1c\xda\x1c\xdcx\x10\x05YN\xc3\x7f\n\xb9\xf7\xd8\xe38\xd0\xb8]\x86\xfc\xcc\xbeX\x8aoos\xb6\xd3R\xc8\xd9\xf0\xd5\xc0\x1b\xb4\xb4 \xe4\x95\x858\x83\xf5q&\xe6x\x8b\xc4\xc5\x9fu\xbe\x1a*\x17\x87n\xa6\xebc\xa6j\xf6\x0d\xe0\xd2\x0c\x9e\x88\xc6\xc6\xbd\xb3EY.\xe4\x1b\xe5\x98\xc9\x85\x8d\xea\x89\x88\xfe$\xe8t\x84\xfb\xd4\x92~KQ\xc6\x84\xeb\x8c\x94)?\x99\x0e\x8dq6tyg\x97\xd5j\xbd)\xa3?r\\Hc\n\xdc\x92(\xe8#\xb50\xee%\x7f>\xb6\xedA\x8a\x06W\xd9\x8b\xf1^\x0c\xd8D\xbc\x96\xa5$\xa9\xf2\xc9\x84\xbcA\x92B\xb4+\xcd\x89\x8f\x15}?\x87\x9e\xafdN\xe95\xca<\xa7\xd0=\xa8\x07\xee\xa2Q\xe0\x10\xde$\x9c\xf4\xbdJ\xc2\xb8\xc5\xe6!\x9f.\xb6\x0f\\\xdb\x99lW\xae\xb1\xc6=DjIU\xc4\x13\xd6\x12\xa1~j\xef\x1b\xa7o\xe1\xfajBo\x84\x85\xe8\x8bM\xac?\xb9\xcf\xd7\xf2\xf9w\xdf\x9d\x1b_\xeek\xbb\xfeQ\x1c\x16t=\x13\xf8\xba\xdf\xef\xbf\x8b1\x00\x96\xb3\xca\xf3M6\xde\xdf\xdf\xb0\x1c\xf3\xdd\x0f\xb2\xeb`\xb9d\xe9 L\xf6\xaf\x0e\xf6\xe5\xaf\x9f\xb3$v\xde\xc5\xf3d}\x11\xce\xc7\xe0|%>\xf4\xb7\xa1\xf3\x8e\x0e\xc1\x82\xd2>\xab\xa60\xf2\xc15-\x07\xf4a\xe6\xc1>$\x1dg\xa5?ie{\xb4\xa3\xc0\x0cz\x10\xc17d\xee\x1d\xdc\x83#8\xc08\x0e\xdf`$&\xfe\xbf{\x17\xfa\xf4\xd2C\x95\xd2\xa6\xe0\xd8\x9e\x02Py\x17#\x0e\xac\x08\\\xdf3t\xef\xf5\xf0\x00\xf2 \x10`\x0f\x88L\xd37.\xb1\xa0\x0b\x90\xbe\xd2\x81\x0f\x8f\x1eiPo\xc7\xce\xea\xf3\xd1\x87G\x1d\x8b\x7ft\x9b\xcb\xd9/%5\x90\x84h\x07S\x85|2wK\xf1\x9e\x8dG4\xf2\xb1\x84\xb4\x93\x8c\xc8N\xa4X\xbe\xdd\x8c\xbb[\xbb\xa1h\xd4\x1571\x91*y\xeap\x8c\x8fU|B\x87\xe6\xdcS\xc6\x9d\xdck\x8a\x1d)\x1f\xe1`\xf4|\x9b\x8a\x00\x90q;\xb8\xb3\xf9\x92\xbd\\,2\x96\x9bBz\xeb\xcf'\xed[\x9e\x8c\xc1\x92\xab\x80>\xff\xd7\xb8\x89\xd6\x85q\x9e\xfc%d\xd7\xe5u6]\x9c\xad>\x92Wc\x9c\xf0o\x93m<\x0f\xe3\xe5q\x14\xb28\x7f\xcdf\xb9\xeb\x0dV\x88'\xed+\x14H\x8a\xae\xf8Z\x0f\xc2\xf6j3YM\xe2j{\x95\xc5N\xbcc\xc3Q\x02zm\xa1n0\x05\xf2\x13Xp\x88\n\x91^<\x85\x19\x1cQ\xbc\x01Z\xc91\x04\xe2\xc3\x06\x8e s\x03N/\xf9\x9b\xa2\x00\xb1\xd2\x06\xccn\x80\x81\x19\x8bs\x96\xd6\xb60\xed\xb0\x8b\x99\xdb$]\x94I\xe1>\x1c@\x8f\xa3\x0b\xc7\xaa\x96]\xe7\x85=OL\xefS\xe6\x94\xe5\xc9f\x0c\x81\xbd\xc0:\xb9\n\xe3e\xc7\x0c\xfcP\xd0\x86\xbd\xbd\xfa!\x90|\x1a\xc6\xc3\x81f,\x80\xa7\xb1\x14.\xdfX[Jca\x833N\xbdUN\xb3\xa4\x14?\x90\x7f\x9cDl]s \x04\xc1G[\x17C,\x82\xd0E\x88\x9f\xfd\x17\x1a\x91\xc5\x8f7\xc9\xa6\xcb\xd0\xd0j\xef\x9a\xfb\xa0x\xd7j\xe0\xd4n\x18/\xc5\xc8yo\xea#/k^N\xa4\\\xddd\xe5\xd2l\xde$\x1c\x92wL]\x81\x9bkIN\xa9P\xa0#\xac\x95\x978\x8cc\x96\n\x89\x01\x97y\x86\xc8Bov\x1c\xa3\x00\xadn\x8b\"\xf5T+\xa2\xe6\xc9\x86\x93 \x14\xde\xe2A\x82,\xca\xb4\xfb`\x06W\x83\xb75\x06%\x0drv\x86\x1bQ\x8b\xeah\xa3G\xd2N\xd5\x08N\x96D2e(i \xcb\xaf \x9c\x03\xef\x8ek\xff_\xbb\xed>k@'h\xec\xe8S`M\xc9\xe7\xac\x04^~' \xdc\x15S>\x0d\nw\x86/\x01/\x7f\xa8\xbct\x82\xf9\xfc\xe4\x8a\xc5\xf9\x0fa\x96\xb3Xd\x0c*L.{b\xcaq\xf2\xff\xb2\x98\xcc/\xf8\x9a\xb9%\x9ac\xbc'&E\x1ag\x15fy\x92\xdeV\xad9\x9bm\xb6:\xcb\x83\x9c\xcc<\xa2\x90y\x9d\xb8L\x13\x92 \x08\xe1\xe05\xe3\x85Qj\xd4+\xd7%\x0b\xcaT*>\x0fj\x95\xf9\xe8\x82m\x9e8\x9e\xda\xdc\xea\x82\xb8N\x94\x04s\xc7o\x87 \xeakWE\xb1ql\xeb \xde\x06\x91%\x86=Wq\x1a\x86\xbdI6\x19\xaen\x9b\xe7\xb5|\x18\x86\xe8&K\xdc/,\x16\xdc\x8cRH\x15\x9f\x12T\xf1\xc4\x8bAQ\xce\x06\xf7\xb0\x87\x97\xf3\xc40e\xb0\xf7\xc1*\xc8\x10\x92v].iUL\x06\xa8\xd0\xb8\xde\xa0\xd0\x08\x9aO\x0dZ\xedC\xd2h\xa7 {\xc9\xa4x\xf0\xed\xed\xe9\xdc\xadM!e\x0b\x99\xc1\xef+\xc7\x9b\x8e\x9a\xf2\x05\x83t\x8ek\x1b\x05\xd4\x0c\x05$L&\x850\x99s\x1e\xc3:\x88\xdc \xe4\x98D\x08\xe9\x9c5\xb5+\xf4Cx2\x81\x14\xc8 \x1d\xd0\xff\xdc \x124\xa8\xa8\xd0\xac}\xd9\xa1\xd9D\xb6\xf6L\xae\xebW2\x8aO\xe1\x86\xe5\xb8?}x\xf7.\xf34J\xe5\xbe{\x97}\xf87\xcf\xe4\xc2i\xc5\x9aY\x14\xce\xdewB\x99\xd2\xb1!\x1b\xe4A\xbad\xf9c:\x89q\x9e9\"\xd8L\x1e,_\x04k\xf6\xd8\x13G\x9f\x9b eq\xfe\"\x997$\n\xdfs\xf7\x90\xb1\x8c(\xe0\xd7\xe0z\x15\xceV\xa4&`\x1a\xc8?\xb3[\xfa\xb5fy\xa0~\xcc\xf24R?\x82\x88\x97j\x8c\xfd\x82\x16\xc86h\x94\x90\xa8\xa8\x94\xa2\x10\xf5\x08d\xe52G\x95\xdf\xe3\x9a\x91\xbc\xfa\xc4\x1a5\xd1\x80\xb6\xb9R{\xca?\xd0\x88\xac\xb8\x96\x82\\\xc7\x8d\xeb\xe7k\xd5\xa7\x94\x02pW\x90\x06\xdd\xc5\x0b\xb3\x18\xe4y\x1a^ns\xe6:\x9cv8\"\x85A3\xd9\x12\xc6\xfe\xe2\xce\xf6W\x0e\xf9\xb7n\xc9C:\x1f\xcc\xa2 \xcb8\x90\xb5\x86\xfa\x91\x06\xdf\x06\xb7w\xf9D\x0d\x840-\xdcZ\xdcQ\x9b\x89\x10\x8fW\xber\xc4\xd1j\x87\xbdB\x0c\x88\xe4\xd1J;\xb9\xca$\xac\x10q\x8c>\x95.\x01egJ\x19'\x08\xcf\xc94\xd5\x06}W\xe2\xcac'\xd6\xa5?\x15^\x02\x93\x16c\x164\xab\xd3\xf2Y\xec\xcc\x19\xa9\x16]\xff,3\x9c\x0c\xfa\xb0@/\xeb;\"x\xd9N\xb3\x94(\xa7\xa4<\xf7\xef\\\xdet\x8c>^\xfa\xf3\x11C\xbb\xa2\x94\x91\xf9\"\x83\xf4\xac\xc1\xe8af'\x16V\xf2\x07{!\xe9\x07\xa7^~t\xcb\xdea\x18\x9e\xd1\x18J-\xc5[\xad\xc1f\x13\xdd\x92\xa7 \x8c9\xac\x7f\xf8\x00\xae~\xa2\x1c\x9a\x0f\xa0;\xdd\xc9\x13\xc1\x1b\xe9\x94\xb2\xc8\xc9\xe7\x83sq\xc1\xb2\x1f\x93\xf96\xe2\x92^y_0}\xdbX\xcf\xc8\xa0\xeb\x99\x926m\xdc\xd8\xbd\xeb\x19\x02\xa8\xf0\x0f\x07\xd5\x0f\xa1\xf8pX\xfd\x10\x88\x0f\xf7\xaa\x1f\xb6\xe2\xc3\xfd\xea\x07L\xf6\xe0\x0e+o#,^MJ\x85'G\xbc\x15\x94&\xf1\x0f\xb2\x88\xb9\x87\x0f\x1fT\x1b^P\x94\x17\xcft1\xd3\x90\xf4Y?\x83f\x83b=E\x9c\xd5:\xac\xcb\x9b\xb1-\x97/A,2E\xbdX\xb1h\xc3\xd2l\x90lN\xe7\xe5\xe1\xb6;\x02\xaa\xd1\x0b\x7f:\x0b\xfe\x91\x9c(F\xe7\x89Lj6\xcf:\xa9\x9e\xf1JA\xb5\x92\x9b\x0f..0\xfd\xd9\x05\xc5\\\x1b\xfa\x18\x19R\x16\xf2<\x91#\x11K\x93{g\xe3\xc1D8\xc8\x93\xe52bg\xab\xe4:\xeeJK\xa4\xb0\x1f\x0e6i\xb2i9c\xcc\x85\xd3\xeem\xb2\xcd\x9fa\xdb-\x15b!\xb7-\x9b\x8b\x91\x97\x1cG8$\xd5\xd5\xcd\xab>\xc25;\xc3\x896\x17E\xad\x96s\xae\xd7,K\xa2+6?\xdb^\xe6)k<\x0f\xc53P\xcd?'@;\xf9@$\xc6\xa95\x84!KV\xc9\xb5;u\xd4\x0c2\x87\xec\xd9\xe7>\xec\xd9\x9c\x9a)u\xcfq\x10\xcfXt\xccE\xe2\xae[\x869j\x04\xbdo\xde\xae\xf4\xf64\x7f\xb9\xcdO\xe2\xe02b\xf31\xec\x85B\xa7\xac|\xb1\xb6b\xc8H\x03\xc5\xd8\xdf\xa4\x1c\x10v\x1a\xfb'\x80[\xb6a\xb3\x1d\x80m\x13\x98b\x8a\xea\x0fA\x1be,j\x10\x0c\x7f\xcbU\xe60\x84.\x1b\x7f!\xbf$F\xc9\xc11\x87ejs\xab\xa3M8\xb9a\xb3m\xde)q\"\xec2-F\xed\x9e\xc6\xaf\xd2d\x99\xb2,\x1b7&\xf2n\x18c\x1d\xfb\xba\x0e\xf6\x13\xa1\xe5\x8cEl\x96'\xe9\xaf\x00/]\x08\x13\x1f\xc2\xab _\xd9aK\xdd\x07\xc0\xac\xf6\x1b6\xab\x12\x15.\x9b\xfd\xe9\xcc\xf5\xe8\x12\xb1\xa9\xc4\xd4\xe1\x03Wt\xa6a\xf9\xcdt\xebW\xde\x82_\x0da\x7f\x85\x0d\xb0\x10\xf6\xf2\x1eX\nu\xdf\x06R\xd1\x9b\xb2\x00\xd6 \xc9\xc8>[\x13zZr\x8a\xfb\xa6;\x97\xb57\xca\x11\xc1\x87\xad&\x85\xf8\xc2\x07\x81OA\x7f;5\xcf\xe3=\xbb\x1d\x83\xb3\x0e6Hb\xde$\\\x8c\xce\x1c\xf34\x84\xe8\xdc\xd9]B\x1aJ\xf2A\xb2i\x07\x98\\\xc8)\x1d\x89A\"\xc4\xb4\x9c\xdc\x1d\xe3E\xb8\xcc\xbc\xb63w\n&?Of'7\x9b \xce\xc2\xa4\x834\xc2\x85G\xb6\xf9!\x8c\xdf\x87q\x8bX\xb4\xa5\xe2a\xb6\x89\x82\xdb\x97]\xa5\xa3L\xaf%R\xd9I\xff\x8f\xe6\x9a\x11\xa9\xb6\xdb\x0d\xd7\xa6\x10\xc6\xd7a\xfe#\xa2]\xcb\xeaa'OO\x16\x83\x1f\x83M\xab\xd2\xfe\xb3\xd0\xf4\x17x\x13\xfcOg^\x0b\x8b\x03T4\xc6p\xda\xdc,\x7f\xf2`\xd9\xe9\x86\x05\xa7\xdfV\xef]\xfd\xc9\xa4\xee\x91[\x14-\xfa.\xf4,\xc7\xc2\xdd\xf4g\xce6)\x9b\x059\x17\xf1OI\xf3-^9B]3\xf6\xa5\x15\xa3\xee\x9a\xccS\xf2!\x0e4\x86\xa4\xbdh\xa1\xa7t\xb8JQ\xd6UZTi\xa8\xaa\x8a-j\x19\x96\xaf\xdb \xc4\x82u\xb7X\xb4\xf7R\xd2/;\\\xf0SzU\x8b.\ne\x15\xaaE\xf6\x80\xbaN\xd9B\xf2AW\x81Z\xf4O\xb0\xe8\xc6-\xda(4\xe8\xc7-B\x12X\xd5\xfd\x16\xce\x0ff\x89\x96\x04b<\xd2\xa9}mo\xb0f\xd6\xd5\x9a\xebzB\x04P\xf7_\xd7\x1fa-\x89\xa4\x89V\xb8\xb5\x0b\x8f\"\xf7\xc7\xb6\xabb\n\x9c\xc7\xf0s\xf3\x8c\nm\xba\xcdh\xdf\x11<\xba\x82\xb4v\xb6-\x96P{\xd3\\\xb5tR)*\x97\xde\xb5U\xd7\x0eiUu\xed][uqD\xa7\xaa\x8a\xdf\xcd\xd5\xa4<5\x86\xcb\xf6\x82\x82\x95\x8f\xe1\xba\xbd\xac\xe2\xe3c\xb8h\x19y!$\x8c\xe1e{Y\xad\xe5W\xcd\xa5K\xf2\xd0\x18\x8e\xbb\x94\xd6Z?k.\xaf Och\xd9\x9d\x92\xe44\x86g\xcd\xa5u\xc1r\x0c'\x1d\n\xa3T9\x86\x9b\xe6\xa2\x8bx\x0co\xac%l\x87\xab\xb5\xb7\x1f\xcf=\xbfrO\xe4\xa3\x9b\x0d^mSfJ1\xb9\x92\xe4\x02-\x1d\xb5\xb3\xa9\x12s\xda\xab84\x16t\x00\xdd\xc7J\xdf*\xbc\xa4Z\xd5\xc4\x0c\xaa\xb2\x84\x8d\xf2k\xc6\x05\xcc\x15#&\x00\x13\xa0\\\x14\xbf7\xc7\xaf\xc8\xe6\xf8\x15\xd9\x1c\xbf\"\x9b\xe3Wds\xfc\x8al\x8e_\xfc\xc3Pw\x1a\x8a\xc8\xb9\xcb\x92k\xfa\xb7\xf6\xd9\x9a5\xfadi\xfeX&k\x8cv\\ip\xc7\xf2?\xd9\xe5Jx\x18bq\x992\xa7\x9a\xd6\xc8\xe8\xd4\xf8\x19\x07\xa7d\xa0Z\xb2\xfc\x07$t\x06)\xbe\xab}j\x17\xdbT\xbe\x83\xaa\x1c\x9b\x14\xdf\xc1l\x9b\xa6\\\xbch\x10t\xd1>\xe9\xc6\x98T\xbc\xd1y\x0d\xef\xe8\xb6\xceO\xab\x90Yd\x1dg5r\xa4O\xeb\xd7\xf0\"\x11\xdc\x03D\xf0\x19\xbcS\xe0|\x8d\xe7\xf5_;\xf0ug\xd2Z\x86\x00\x93@\xd5bg\xfc\xa4=T@a\xb3\xe6\xb6\xac\x06\xa3\xa50\\\xfb(\xcf\xa7\xcc88\xd3\x90\xed\x99\x18\x87Nwg>\xccj|\x84Z\xff\x171\x16\xcf\xfftb\x8c \x8b(\x15\xfa\xd5|a\xb0\x8b\xd3\xac\xba\xf0\xc3WL\x91_\x15_?\x82 \xe5 u3\x8fr\xe8\x0f\x1f\xc3\x0c\x9e@\xf6\x18f\xbd\x9e\x07\xd1tv\xae\xd7\x9c\xce\x0ca\x01\xc5R\xc6x\xe1\xd1\xe6\x9c\x8b\x18\xd8\xca-fA\x14 \x96\xc1|\x98\xf2\xba\xe72\xf4b\x84IZ\xc3\xc1,J\xb2N\xeeV\xc2\xc5J\xb7\xfd\xa11\xfc9G\x85\x10\x7f\xbbU\xffz 4\xc3\x8bZ5\xa6\xc77\xe3\xb7\xe0\\_\x96\xe4ub[\x1d\x0d\x9eqwcj\xba\x03;\xa4\xd3\x15\x96\xa6\x1d\x86\x10\xeeb\xf1\x0e\x84\xf1t\xf0\xec\xec\x8d\xbd\x14\xdfm\xed\x04-\x90)m\x1b\xcc`\x98\x0e\x15\xa1)\xd6\xc1\xa9\x81sS\x8aT\x87\xaf]f\xcb\xd0\xd0\xc6\x8a\xe7\xe1U\x8dT\xeb\x8f\xbaV5\x06g\x1e\x06Q\xb2\xecoo\xacWq\xbfH7\x97\xc1\xec\xfd\x1f\xea\xe57Z<9\xa5>^\xcf\xff\x8d\xfaZ\xb1`\xfe)\x9d\xad\x0e\x95\x1c\xe8<\xbb\n\xc2(\xb8\x8c\x18\xea\xfbI\x1a\xfe\"\\\xb8\x9a6\xfbr\x9b\xe7h\xe0\xb5\x0f8\xbf\xdd P\x89\x92\x9d&\x86\xfc\xa0\x8f\xd3k\xa8\x91\xc4\xba\xb9 \xeb\xec\xbc\x02\xd9\xd5\xb2q\xf4\xd7\xe1<_\x8d\xc19\x186\x0cd%\xa2;\xf0R;\x8f`\x9b\xd5e5\xfdY\xa5l1\x06\xe7+\x9c_\xc3 n\xa20~\xff}\xa9\xb0\x05y\x91\xe9~Y\x00\x9c%q\xce\xe2\xdc:\xfbh\x80|\xee\x8c\xfd\xcd\xf5\x06\xeb`S\xcaI\xdex\xfd\xb7\x85~\xce\xda\xcc\xb6\xc8~[\x0e?\x9e\x9d\xbdi=\xf0\x98\x17,\xc1\x1a\xb7D>e\x13X\xcb\x19\x96\xce\"[\x0f\x81*\xa6\xb8\x96\x93\xdb\x92\x91\xaf\xc5\x00\\1{\xd6\xdd\xa1\xe5c\xb3\xb4y\xf8\xd4\xbe}9%\n\xdf\xfeK_\x12\xcf\xbf\xf4\xa5\xff\xc5\xfa\x92\xe0|]4\xa6\xce\x97S\xf2\xeez@\\\xd7/\x06\x1a}|\x93\xa8\x83g\x9bI&\xafim\xe6\xd4\x15\xffR\xda\xccO,\x80\xac\xac\x8dy\xa4\x8b(\xd9\xedU\xb2\xd9n\x1c4,6+u{{\xbb)>\x89\xa8\x13\x14\xee\xce\xde \x0b\x7f\xb1D\x13\xf9\x92:\x10\xef\xb2\x7f\x9d\x06\x9b\xcd\xa7\x08\xbc\x1d\xe4U\xad\xb3\x04\x8e\xc0\xb9\xccc%\x113\x88\x92\xd9{6w`\\\xfd\xb0\x8d\xc5\xa7\xae\xf2\xaa\xf8\xb5\xf3\x14\xb2M\x10kR\xbb\x1c@\xa3\x98\xfe\xcf\"\xe5\xe2\x82\x7f\xa5\xad\xf1W\x1d\x96U\x13|\x1b\xea\x9bG\x8c\xf4\x14\xddkm#\x8f\x85u\xf8_\x92\x0d\xfcK\xb2\x81\x7fI6\xbf\xbddc\xbd7\xc0\x06Y\x9el8\xd4\x07\xcb\x80\xf8\xb0\x99\xff\xc8\xcb\x05\xd2z,:\xb1\x88&\xe8lop\xa9\xff\x9f(\x8e\x94\x1c\xd5?\x8dy\xef\xc6R9\n\x96\x85\x94\x8b\x0b\xceH5\x9am\xf8\xda\x81\x0b8A\x1a\x06\xfd(\xb8d\x91c\xea\x06h\x9c\xd6\x8e\xe4\xf7\x0e]}!>\xfeO\xc2\x93\xd9g\xf2\xe4\x86\xfa\xe6\x11\xff/\xb4\"\xcc8K\xad\xf1\xd4D|\xa9q\xe1PV11\xdb\x99\x89\x0bo\xc5\x87\x1a\x17\xce\xc4\x87\x1a\x17\x8e\xc4\x87\x12\x17\x9e\xc9\xc8G3\x11\xf9\xc8\xc4\x8fg\xbf=?^t\xe5\xc7\xb6\xb0EU*l\xe5\xb9W\"\xafz\x95\x98[}g\x92:\x0fl W$\x16+\x18$1\xa7\xcd\xc7\xab ^\xb6g0\x02\x8d\xcf\xb1A\x1c\xac-\xbaXP\\[\xab\xb0\xe8\xbf\x7fDL`&\xf4\xe3\xfc.\xc3\xbb\xee|H\x9d\x06S\x0fb\xc7\x1b\xa9\x1f\xdf*\x15\xca\x0d\xc8\xe3\xd7\xd2}\x94,M\x91tv\xe8\xbfY8\x08\xda\x14t\x8a\xab\xd0\xc9@B\xc1\x154\x93H\xcd\xe6\xdd\x1a\x80U@\x819\xa25 \x1d\x19\xe4 \xc9w\x96\x99\xc5b\xcd\\s:\xd3\xa0~\xec\xbe\xc3b\x9a7\xb3\xe3Y|P\x84\xfa\xe0\xbf,8\x0ee\xd9)3\xcaN\xc1?@vj6\xe2t1\xf6\xc4U\x00i\x83\xa5\xee\x87\xeeyW\x1bR\x88\x85\xbb\x9d\xd0\x07t\xd2\xcd\x91\xff4g\xeb\xa6\xabH[*Jy\xe0\xda\x8cO\x19\x15\xfe\x96d\xc8\x96\xa3\xf6\xa4do\xb2\x97\xa5\xc0\x19\x8b0\xcaY\xfaIH\xb7\xb77\xc3k?\x96(\xea\x80\xd8g\xef\x7fc\xee\xbfc\xe7r\xe5D\xd4]\xbc~\x94\xdfnXC\x8c\xd8\xa6\xc1\xcc\xbf\xcc`&;\x0c\xa6Q\x8f\xb0\xdd\xbf\xd8\xdd\x088K\xe2<\x08\x9b\x0e\xd9\xf7\xf66h\x95\xe4b\x87\xb5\xdfE\x92\xae\x1b;Nb\x8a\xf2\"o\xa5(6h\xebvS\xa6\xf6mI\x97Z\x16&\xe8t\xc2\xd9v\xba7[\xb1u\xd0z`\x18\xe3\xf2\xb6\xb4\xb5\xd3\xe9\xa6.\xc3\x8c\x81\x95d\x9a\xe6\x9a\x81vy\xad\xe5\xdeK\xf9\x08\xf5\x13\x8e.\x0bN\xea\x7fA\x00\xbd\xcc\xe3VK\xb5\x00P\x8e^\x0b\xfa\xf3\xc8:\x82\xack\xef\\e\xa6\xa3yi\xa3\xee\xac\xcdjR\x96m\xc8\xce\x0fX\xc6\xf1`\xfciC\x15\x1e!\x84H\x1d=B\xeaS*\x00\xc4\xba\xb8e\xeb\xf8'\x8d\xb5e\x0c|\x8b\xe7I\xdc\xe4\x97\xb1\x83\x97\x8as\x8cn\x1bh\n\x9bs\xa25o\x03 \x01\x94t\x18\xf0E 7\x9b%\x1b\xd6\x9f\xb3E\x83/\x87\xa5\x9bMq,q\xc6[\xc9 H\x19l36\x87<\x81e\x1a\xc49\x041\x04\x9bM\x14\x8a\x80\xd3\xf3p\xb1`)\x8bs\x88\xd8\x15\x8b2H\x16\x10\xccf,\xcbx\x95y\x90\x07\x90\xc4p\xc9VA\xb4\xe0\xdf\xf2\x15\x03\x16\xcfy\xa3\xe9\x00N\x82\xd9\n\x9e\xbd:\x85up\x0bs6\x8bx\x7fI\xcc Ia\x9d\xa4\x0cp2\xd9\xa0i\xf7\xf5Q\xf3\xa6R\xf6\xb7m\x98\xb2\x0c\xbbZ$Q\x94\\\x87\xf1R\xb6\x04Dg\x80b\xe1'1\xcb\xe06\xd9\xc25\x9f\x9a\x9ac\x9e\xc0\x19\xa5\xd1\x85\xb7\xa7\x03\x07\xe3\x03\xef\xc6\x81?\x8d\xfb~\xac\xbb\xd64J<\x9f\xcb\x91A2\x9f\x06%\xc5\xbe\xf0\xdb\xb6\xa6w`\x00\x92\xbd\xb5\x05\x8dA\x10oR\xa9\xda\x19\x04\xa7z\x9ft] \xeal\xa3\xa2\xe4b\xbf7\x1b\xd5\xef\xf2<\xc8\xa7?,\x96\xa8\x7f\xb6\x93\xa1\xffy\x17\xb6\xbe\xa8\xda\xdd\xa6T\x8b\xd0\xaaH\x0b\x9aUo2\x905\xeb\xdc\xbb9\xbaw\x93kC\xe5\xe3\xd1\x16\x1a(\xd8\xc1}^h\xdc\xc1&\xfc3\xbb\xe5\xc3hR\xa4#*|\x19d\xe1\xac\xad\xecL9\xd17+\xdb\xb9\xce\x9a\xcc\xda_v\x1db\x06\x93E\x13C\x9a\x05\x19\x031\x0fgl-\x06bh\xb6\x83\x8dV\xce\x02\x1d\xb5&\xe8\xae9AW\xed j\xfaJ\x87\xc8\x1c:+\xec\x10\xf9c'\x0d\x0dHF\x15\x1a\x9a=\x8d&4\xe8\xf6\xf2\xb9LY`9V\x05\xb5\xbf\x08z\x9f\xb1\xbd\xd1\xbf\xb6\xf7\xf7\xb9\xbd\x92U~\xf2\xcev\x928A\xedn\xf3\\|p\xde\xc6\xef\xe3\xe4:Vas4'nTB\xc1\xf1a\xd1\xf5v+t8\x0bo\x1b?\x8d\x1bz\xe0\xf4\x7f\xde\xae7V\x15\xcb\x90h\xe6\x7f\xf8 \xe8\xefR\xba\xfc\x97L\xf9\xbfD\xa6\xe4\x82V\xd2@HU\x1c\x00\xd7A;E\x93\xd0\x14\x17e\xd7,\xcb\x82%k*\x9d\x16\xa5\xb3d\x9b\xce\xac\x02\xd4\xe7\x92\x1e\xdd\xc6\x83\xb3\xb5\x85m\x05\xcc\xd3}\x1b1\x13\xe4\xea\xcfe0{\xbfL\x93m\xd4)\xd5\xe7\xfbm\x80\x1e\xf5\x07\x97\xe7\x1f\x16\x98\xbay\xa7\xa1t#\xaa\xc9\x95\x16t\x7f\xea;w\x8a\xd4\x10\x9c\xe0\xe14\x1c[z\x9c\xfa\x92\xdbX\xd8\xef\"\x94w\x1b\xdc\x83.(u0\xb2\x81\x12\x95\xba\x99\xc4@\x19\xe6\xda\xf7.\xc44\x8d\xcei\xbc\xd9\xe6m1v\x03*\xfb:\xb9n+\xb9\xa5\x92\xc7I\xa3\xb0\x08*\xff$\x1e\x19\x9fp\xc1\xac\xad\xfc\x8c\xca\xff\x18\xa4\xef\xe7\xc9ukX`\xcaB\xe9\xfc C\x9d\xbe\n\xf2U\x9bO\x0e\x08\x17\x96\\\x04W\x12\xa4\xa9\xb9\xc2\x1c Y\x10E8\x85\xcc\xf5v;\xf0\x92\x8fdo$\x11\xf3%9\x9d;\x1e\x9e\x7f}\xba\xe9\xa2\xdb9W\xcb\x19\xea\xean{\x99Y2g\xaaT\xa2\xe2\x04\xbb\x0e\x07B<\x07t\xfe\xff\xff\x0f\\2pz\x8e\xbd\xa5E\x9b\x11\x84\xa2#OU\x16\x19\xcd\xe7\xce\xf1!9\xb7V\xc6\xb4\xb6\x9bF\x87\x98\xd5}\xc3\xf5\xb2y\xd3\x19j\xd0\xb62\xad\xb7\xf4I\xf7\x19\xcb\xf5\x9a\xb3l\x96\x86\x9b\x1c\xa3^7\xcf\xe5\x93\xc7\xa4\x1f\xfc\n\xbd\xa8\xeb\xd6\x96w\xf5\x8b\x8d\xe24\xde}\x0ca\xfc\xd9#\xa0;\x13j\x14\x88\xeec\x07\xc1\xa4\xc1\xf1\xa04\x18\x07\xbe\xc1\x07\x1a\x9dB\xb6mC \xdb\xc0Dx\x8ep\xe5\xabE\xcd*L\x9e\xf2\x92\x06\xfel\x82%\xcf\x87yS\x98\x8a\xae\xde\x83\x9f\xe4g\"\x1fT\xcd[\x0f\xb2\xa1\xfd\xe4\x1d\xc0\xea\xefD\x9f:\x0b\x1a\xa6\x80\xa9\xa6\xc3\xec\xf2\x907m\x97\xd3u\xc1\xa2N\xbbK\xbb\xa67e\xdd\x85+\x91\xfa\x8e\x15\x97\xbcZN\xe3\xc8[6\x0f\xd2%\xcbi\xe3\xede\xe5\xdd\xb7\x8a\xbf<#\x91\xbcmg\x85\xc0ega6\xf6\xc5\no\xfd\x10\xd3L\x87\xadz\xfc\xbf|\n\x8a\xe7\x93\xac\xbe\xffd>\x05\xb0\x9bN\xde\xe9f)\x88\x9e\x7f\x83\xc4\xdc\x0b*\x186\x8cb\xdb%|\x05\xdf\xd1m\xab\xde\x11a\xa9f\x9d`&\xf3a\x0b\xc1w\xb0\xcdXj\xbfP#v\xbfK\xf6RR\xce\x1b4o\xa9\x9c7\xccS*\xe7p\xd4Bs\xe4\xa8m\x8a<\x7f>r\xf0\xb4\x9a\x19\x7f\xeb\x94\xa8\xffp=\xbf\x8bc\x06\x94\\HZ\x95\x0e\xbaM,\xf5\xfcX\xd3\xf39\xda\xd8\xd6\xbe\xbe\xf0\xffK\xb5\xfdv\xed}\x978\x93\xf0;\xd0\xf6\xa3O\xd3\xf6wS\xdf\x17\xbb\x99\x08\x0c\xda\xbe\"z\xedj\x7f\xf2\xab\xaa\xfduc\xa3\xfetP\xfb[N\xccH#\xb1GH,\xd4~\xe7\xdb \x0bg\xe5\xe8\x88\x8e\xbdj\xab\xce\xdb\xac\xc3\xa7]tx\xfb\xb0\xad:\xbc\xadJ\xd0\xb6\x14\xad6\x89O\xd7\xe1?yLU\xdd\xf5\xad\xe4yR}\xb5V\xac\xa8\xaf\x8e\x0f\x1b\xfc\x9f\xeb\xaf\x0d~e\xcd\xc3\xf9\x82\xfa\xabpC\x9f#q\xa7?[j\x10\xafw$\xde\xfe*\xfa\xf1\x17\xdb\xa8WA\x96]'\xe9|\xe7\x8d\xd2\xed\x0c\xbf\xde>\xed\xbe\xfa\xc16O8g\x8bX\xcew!f\xd7\xfd\x8d\x98c\xb7}\xebXZ@P\xc7\xd2\x9f\xb6\xcb_\xc4\n\xf2Y\xde{\xff$V\x10\xd3\x11yy\xc8\x8b\xdf\xbf\x15$\xd5\xac \xf6R \xda\xf7;\x18I\xd2\x16\x99\x8d\x1c\x9b)\xb5\x176gf\xe0\xc14<\xe7\xb2\x85\xaf\x9b@\x9a\xe4V\x94q\x03\xf3n\xa2\xe5\x84Y\xa3\x0b\x94w\xf5\x9f\xc9\xc7aa\x8d\x1b\xb2\xb0\xf98,l>\x0e\x0b\x9b\x8f\xc3\xc2\xe6\xe3\xb0\xb0\xf98,\xc8\xb2R\xfe\xc0\x05Yw!M,\xfc\x8fGw\x1fxf#\xcb\xe2\xb77\xb2l\xbe\xa4\x91\xe5\xf7\xe6\xf80\xff]:>\x04\x9d\x14\xee\x85*\xd9A\xc3\xe3\xbb8\xe3 B\x17\xf8\xb3\x06\xc5\x07\xa3\x98\x0c\x8a\x04d\xae\xd0\xc8\xed5\xae`Bb\xf7\x86$\\%j\xb5f\x16]Wj\xce\xa2\x90\xc5\xf9\xa9H&\xba\x1a\xc8\xdfm\xed,\x8d\xed\x9c\xb1Y\xca\xf2r[\xf4\xae\xad\xbd\xdbJ{R\xacx\x8379\xb0\xb6\xc8Q\xd8\xbfL\xe6\xb7\xceg\xbb\xa7\x04\x9b\x0d\x9d\xb5\xad\x06\xe2O\xfb\xe0\xbe\x84+\x0b]\xdb\x1c\xc3\xf4\xbc\x01\x14\xc5\xe27\xa6\xdb\xd4W\xb51\xb9favkH\xea(\xd7y\xdc\xb8;\xfan\x8c\xe1\xd6X\xee\x1f\xe0\x8e\xf3\xab\x18\x9b\x9a%\xbd\xaeaU@\x85Vi\xa3?\x00\xbbEV\x81]\xa3\xab\xc0\x8e\x11V@\xb0\xe1\xbc\x83\xcdkKS\xec\x96/\x05\x8a0+\x9d\x8c^\"\xa9I\x07\xa3\xd7\x82Jv0zm\xba\x86y\x01\xe9J\xb2\x83\x85lE\xe5w\xb3\x90]Q\xa5\xae\x16\xb25\x9e\x1b\x84\xd9\xcbgg\x87\xcd%9\x89^\xbb^-\xfe\xe01\xd7c1\xea ^o\xc7\x9f\xcd-\xdd\x16-\x11\xf59N\xd9\x9c\xc5y\x18D\x19\xb5T\\\xa4oi\xea\xff\xb2\xf7\xef\xebm\x1b\xc9\xa28\xfa\xffz\x8a\x12fN\x06\x1c\x93\xb0(\xdf\x99(>\x89-\xef8c\xc7\xde\x96\x9d\xcc\xda\x1ao} \xd0$\x11\x83\x00\x02\x80\x944\x89\xdfe?\xcbz\xb2\xdf\xd7\xd5\xdd\xb8\xf6\x0d\x94l\xcb\x19c\xd6r(\xa0\x80\xbeUW\xd7\xbd\xe6\x98\x04\x06I\xfc\"6/\xeci\x0d\x8eu*I\xc8\xe2\xf9\xd9\x91\xc0\x9f\x14\xfc\x96\xfeSg\x98)\xba\x9d\xb9\x07\xdf\xf7\x0d/\x1e\xa1\x15\xe6Cj\x16\xe5\xc2\x82\xb8t9u\x80W\xc5\xdf;\xbaT\xa7\x9c\xad\x1fG![\xbff\x88\xbf\x08\x040\xf4\x0fsC\xe8;y\\/dK\x1dgT\x9a^\x99\xaf\x94?\x06\x07\xdc\x17\xdfm\xca\xd5\xc1\x18\xe8\xed\x16\x1a\x823\xd2\xb9\xbc\xacL\xca\x02\xbd\x0e\xd57\xe8P\xcb\xba\xca4\xe7Ft\x1e/\xab;\x0d\x9dj\xbd\xf5\xd0g\xa7\xff\xa5J\x9b\xc8\xde8\xd6\xb9\\mM\xc3\x14\xaaU\xd9Zj\x868\x86\xb3\x1d=\xbd\\'Z\xd3\x11F%\xc3\xcc9\xdd\xf8s\xfc\xb9\x1ci\xbf\x99\xf5?\xc9R}\xbcy\xf5l\x80{SRo\xd8\xea\x13o\xf2\x98\xe5F\xa9\x19\xd5~\xef\xea\x9f\x17\xd6\x1d}\x9d\xbe#\xac\x83\xd6\xfds\x1a\xb8\\\xd2\xd7\xab\xcei\x1b\xd4/s3F\x077\x88zm\xc7\xe0<\x89\xd3\xb3\xe13\xca6\x1e\xfa\"\xd6\x93\xb8\x87\x93\xf8\x10!5\x0e\\\x81i\xe7\x1b\x01*=\xb0~\"V\xe5:~\x82AB\x98\x01\xe5\xb4\x92\xb4\xb4\x13\xb2ij\xff\xcf\x068\xaf\xb57pe\xf9\x12;X\xf5\x19\xa3E\xa4\xf4\xe71\x15\x17\xa6\x9a\xf8y@UE\xf1\xaeL3\n\xa8\x1b\xa0r8\x11\xf2u\xa6\xdeDa\x7f>\x0dl\xb7\xb5\xb9\xc2 \xfd\xd2\x9f\xe0'/a\x83@\xfe\xd4JE\xfd\xb1\x11\xb0\xda*Z\x04\xcc\x9aV\x8d!\x08h\xe3=\xf9\xf9b\x9b\xa5\xb1b\x98i\xa3\x8dq\x96/}\x16\x18'\xc6r\x8a\xf94\xb4\x08\x87S6\x14\xd9\xda\xd4\xae\xa9d\xf8|(^\x81r\xafqR\x11 \xdb\xf3\xb9\x0bV\xbd6\xbf\xb8\x1bfiF\x98f\xdc\xbf@?B\xaeoi\xab\xe9\xb48\xf3\x8aA\x02B\xea\xf8\x95\x81=`i=\xb4M\xd7\x0e\x14W\xd9\xf0o\x1b\x92\x1b\xc6\xfc\xbf)\x08d~\xee\xafII\xf2\x02}\xe6)#\xc99E\xd4t\xaa9^|\xdce9\xbf\xfaJ\x8c\x19\xd9'\xc5\x96B\x1e\xd4\xdd;\xa3\x9f@f\xbc\x01'\x14\x8fZ>\xf5\xea\xe9\x0bk\xf642\x1cf\x15\xd8`\x02\xf3g=\xcd\xea\x89\xb3:\xc8,\xd8\xa6\x86\x9fA\x07\xbd\x0c\xda+\x86\xfa\x12\\\x1aB\xde*+\xc4\x87 m\xbd\xfduE{\xe9\xa3\xef\x93\x82YWl\xf6\n\x03\xfd\xb2_\xda\xfb\x85O\xe0n\x18\xcd,.W\xb5\xdfd\xf8\x7fl\xd3\xbdK\xec\x81=$\xfb\xa7\xf8\x8fe:W{-\x01W\xc2\xee\xb4\x92\x98\x9d\x9d\xe3 \xd3\xef\"\xe6\x9e\x0e\xcb^\x0df\xa5\xa1\xd1\x13\x12\xacS:]j\xe2\xa03y\xc1\x8a\x04\xef\xe6\xa9\xa2 \xb8\xb84\xadZEt1\x9cc^\xdfV\xe9\xc3\xe8\xdea9\xa2\x1c\xb8\x01s\xfc%\xba\x8a\xb7\x84\xfb\x8c\xd9PD\xaf0*(i\x08gpf\x06\xe6[\xa9\x9a\x19\xf3\x1b\xf5\xce ^\x9a \x1e\x19\xb6\x05p\xdd\xe4% 54\x89\xb5\xf5|\xed\xba\xd4\"\x9d\x8a\xb9OM\x0c\x8bJ]~\x170M\xc4.H\x8dTp\xe7Q\x9au\x94\xd0iO\xaf\x96\x03\xd6^r9\xbd(t\xdal\xea\xbfMM\x97\xf2\xb2\xd4\x15\x84$\xb5\xef\x18\x8e\xae\xc2\x03R5\xe0\xd0f\xb8\x1f\xcf\x03\xf2\x92\xf87<\xeb=\xb0\x859G\xc9H\xc7'eC\xda\xd6&\x887\x1e\xee\xbd\x0c\xf8\xba\x9e\xdb$\xc0\xff4}\xaf\xde\xd2v\xbf\x91\x15_\xb3\xfa\x97\x1d\x81Ej|\x18\x90\x1e\x1fx\xe7\xab\x14\xf9R(K\xc7\xddz\xcc*\xc7\xdd\xf0\n\x1cw{\xe5\x95\x94\x94\xa3\x94\x94W\"\xbb\x97Wj\xe3\x82i$\xc0GS\xd6n\xc3\xea%\x1b\\\x04\x8b\xe4\xb9\x112\xad\x1dq\xd0\x15O\x0d\x19\x0dq\xc1\xf1\xe1\x10R]\xe2\x92\x8d\x88\xf4\xac\\\x00\x15\x0en^\x10\x13?\xd7\xf8\x1f3\xc7\x82\x19\xe8Y2\xce]\xf9\xfa\x82\x1c\xc2\xd8\xcb\xe0\xe4h\xce\xbd\xb6\x02\x81\xc7#C\xdffU\xa4\xba\x16\x8c\xaf\x94\x96M\xad\x17T\x9b{6`S\xaa\xcd\x7fK\x9b|$\xe06\x8a\x91*\x11\xbc\xc5mZm3\xe1\x1covw\xcf\xd1q\x02\xb9H\x9doj\x8a`\x94\xc1/D\n\x019\x06E\x0bp\xb1\xcc\xf4d\xca==\x18K\xca\xcbJDIH\xce_,\xdctd\xf2\x97\x8b\xa0\xf72\xaf\xa0{\x92\xbe\xd5\xf8uXy\xd1C\xc3crx\x15\x1d qA`/g\x1e\xda\x8a\xf1\xc1\xb7t\n\x18\x84\xb9C\xa23\x9d\xcf\x0dv\xba\xa9\x9c\xc7\xf7\xb4\x89\x84\x94\xf5\x8148\xd8P\x04\\1\x0e\xb6\x91KOY0\xaa\xd5\x14\x9e\xe1\xcbsX\xa4cPE\xdf7\x16\xc9WO\x02\xe3\x98\xacF\xdf?\xe8\xd4\x1e\xe9\x89\xcdy\xc46\xaa\xd5y\xc4\xe6\xd3\xe6_\xfb\xe7\xca\xbf\xbe\xf2\xb2M\xb1r\x9d\x9c\x14Y\x9a\x14\x04\xed\xca\x87\xa8\xd3WP3E\xde|\xd6^ev\x1c\xd2\x1a\xba\x9c\xed\xd4\\\xdf\x95\xf8C\xcca\xcf\xf3y\xc8\xe0\xd8T\xb6^hS0\x87R\xa0d\xe9\xc0\xe1!\x92\xd1t\xc1\xa2X\xc4\xe7*C\xdd!\xaa\xff\x12\xfa\xc17\xaf\x9eV\xb2\x9e\x9bu\x03\xa5(A\xd9b.\x03Vr\xeb\x15 \xa3\x9c\x04\xe5\x9bZ\x9f\xd1\x13\xe8t\x0c+\xfe\xd1\xaf\x9c\xd1[\xf6\x93\x8bS\xa7\x95\x84\xe1\x8b\"9\xa6@\xb09\x8b\xe5\xd4\x19\x89\xba\x06\xa2y\x99Lp\xee \xcd\xe6q\x1a\xbc\xc3\x12\xeey\x1a\x9f\x9e\xceK]\x08c\xdbF\xc4\xff\x92B3\x0b\x11\xf1sI\\\x94\xb1\xde\x89\xa9\xce\xc9\xf5\xcc\xa1\x8aD_\x9a\x03\xe4Z\xd69\x19\xb3\x1f\x07X\x15\xd9\xbd\xf7y\x9c\x05\xd0\xd29\xad\x88\x1f\x92\\b\xf53\xed\x19\xbb\xe0\xc9F\x98\xa1\xa0=\xc0\x9b\xd4\x17\xb2\xce\x1b\xd9\xc1\xbb\x12L{\x81\xcc\xc9N\xea\xd1\x86\\d\xfc(\xc3e\xae\xe9\xa2I\xfb\xe1\x8e\xc1\x81u\xe1\xe8G\x1d\x1aGm8\xf3\xa1M\xa0%Y^\xc6;gr\xb1\xa9\xa7\x06=*\x06W\x9c\xdb\xa1X\xa5\x9b8\xac\x08\xe1\x9b,\xf4K\xdb|\xac6\x15\xcd\xeb$\x0e\x9e\xd0\xf9\xa0tI\xea?\xff\xf8\xa3 E\x0fq\x0e\x81?\xdbO\xd9\xf1\xcd\x9f\xf3?\xda\x10aTd\xb1\x7f\xc11\xeb\xb1P\x7f\xb07\xe4\x0f\xa5c\xf8\xdcR\xb2\x8a\xe9\xd4\xc3\x0eM\xca\x9a\xd6\xf0\x06C=T\xd5\x8e\xe5\x93\xac\x7f\xd3\xafx=\x0b3?T\xcax=\xc7\x07\xfc\xc8\x12\x98\xa2\x87\x0c\x98\xf3\x00\xba\\<\xdfPi8\x14\xe4\xe9!\xf8\xde\xbau\xebI\x9a\xbb\x9b1\x14#\x98\x81\xef\xe5\x9d\x9b\xfa\x86B\xa8\n(S\xa1{cL\xa9\xb0\xa2\xa7+\xcf@$\xd7\x974\xafm\xfd\xf9\xea\x10\xf1\xca\xf4\xc7cSE\x97u\xfdb\x92\x96\x8f\xd3\x00I\x12\x86\x87k\xdf[\xd6\xef\x11\x9b\xf4\x1d\x175<\xfa.\x1a\xc0\xe75x\xe3\x98\xd0\xber\xda\xb7{n-\xd2VlO\x1c\xca\x9f\x92\xa4\x9c`\xe4\xd8[JZ\xb6'\xce#~\x13\xa3\xc24y\x85\x80\xeb\x94\x12\xd7 ,\x16\xea\x9c\x81\x8a\x8d\xfb=\x0b\xcf\xd2\xber\x0c\x87]wm\xa3)\x1c,\x0enk_W\xe8p\xf9\x0c\xc3\xe2\xc8\xe8\xf5%.\xa4\x95z\xa7\\\xe0l=8\x98\xe3\xcc\xc1\x90\xf7\xed y\xcb\xa2\x15\xb5\xef\x9a\x92x<\xa2\xe24\x1e\x06\xc7\\\xe0\x96\x8b\x82`1iMn'\xd0E\xaa\x1c\x99f\x96\xd3\x0fm\xe2\xf6\xd1\x18V\xda\xf4\x06v\xcc\xd7\xed>\xf3\xf5\xe6\xd53-\xdf5\xd4)TD&\xd2-\xa0\x1e\x8f%\xa3\xb7\xd2\xa7Xh\x8e\xe7\x98\xe4[\x92\x83\xd8O\xda1a\xf0\xcc\xc0Q\xb1\xcf\x16\x13\xf6\xeeN#+\xe9~1\xafR\x99\xef\xd85\xb6\x1dw\xec[8\xa8\xd1 \x8d!H\xe3S\xd6d5\xeb\x13z\x8f\x1fk\xban8h$\xd4.\xd1\xd5\xf5\xc7\xca}\x9cv\xea1)\xfd(.\x0cy=J\x8c\xa4\xfdP\xab\xf8\xd1Vo\xe8\x92\x85cX_e(S\xd5\xfe& kfc\xa7\xd1G\x8d\xe0\xba7\x8d\xaf\x81S\xf9\xf8_1\xaa\xed\x84_K\xdd\xf4\xb5\xca\xf7\xb6\n\x8e\xc1\x0d<\x04\xe1\x86\xb8]\x95\x99\xae\x03\x18.4\x9f>7\x0e\x8e183\xb80\xb0\xc8\x0c\x8e\xa5'4\x04\x17m\xf2x\x06\x06\xe6\x9c\xf3\xa7\xda\xcc\x89\xf4j\xca+\xba\x98\xb1\xf7\xf5|<\xd2\xcc\x871\xb4\xb2\xea\xd7\xb1MS\x11=\x96\xe7\x97 k\x10|\xed\x0c\xe6\xe6\x06\xd5\xe1-\x97\xf0\x85\x97\xeb?C\xbc{\xdd\xf4\x9f+\xa5\xfe\x13\x9f\xf4\xb4\x96\x91x\"S\x80\xaed\x9a\xd1\x0d\x7f\xd0\xd3\x8c\x16\xfcA\xaf\x8d\x98?\xe8iF\x03\xfe\xa0\x97\x1dy!\x1a\xdf\x7f\xd0}\x94Q\xf1e%\xb4\xa7h}\xec@\x84\xa2\x83\x8a\x9aU\xab\x8f\xafO\xdd\xda\xda\xd6T\xa9\x94\xa5&*\x99\xfd\xac\x99B\xb9\xb0Q\xbcEm\xc5\x9bE\ne\xac\xd0\\\xc7]\xbc\xc9\xe3!\x96-\x9eU\xb9\xad\xce\x90\xcb\x19\xc2LG\xce`!z\xe9\x12o\x93\xc7.\xe6\xe5\x17;5N\x99\xa3\x00\x95\xe4\x99;\x87+\xd1\x14\xca\xe7*\xe5s\xd5\xd4\xe3\x8c\xdc\x91\xc7\x1d\x8f\xd2\xbc\xe7\xf3\x04`\x9d\xe3\x17\xc9|\x7f\xbaT\xba\x86f\x9b\xb3\xa6\xabd\n\x0f\xc1Y\x95eV\xccn\xdeL\x13*Q\n\xbf\x06/JoV\xef9 \xab\xaa\xd7K\x8a\xab\xb4\xb1\xc5\x0d\\\xa8\x15\xa6m\xcb\x9b\xd2\xc6\x16\x08z\xf9K\x14\xc7\xafH@\xa2-\xd2\xb6\xc2\xc2\xec\xa6\x94\xd3\x85\xe2}\xf8\x12\x81\x88;\xb2p\xac\xc7uB`\xdb\xa5\x02\xddr\x95\x03\x96K\x1eZ'\xf3\xb1o/\xa1\xec\xd4\xbc\"[\xa7\xd8\xa9t\xce\x1b\xba\xe3\xf6\xe4\xd3\xed\xab\x9e\x1a\xb1d\x99W\xf8t.\xffM\xde\xe41\xa3Bu\xb1\x83j\xf2TqF^\xb0\xc9s\x92\x94OXj\x08s\x85\x93-%I{\xcc\xf9\x03\x7f\xbb\x1b,4\x97f\x05\xff\xc6f\x0c\x18\x9f\x88~\x16{Q\xf1\x93\xff\x93\xbbB\xfd\xca\x8a)0\xc4K\x1b\xaf\x88\xa3\x80\xd0M\xb2\xd2U\xc9m\xf9dlzy\xc5|\x13\x9fDw\xc3F \x87\xeb\xa4\xd5:\xea\n\xba@=dU\xbf\xac\x12\x92\xb1\x9d]\xb5\x89\x89\xf5\x0c\xf5\xb5\x00\xb5 \xcb\x17\xf3_\xad\x12\x99\x95\xfeR\x9b-F\\\x9d\xdd\xa7\xcdB\xd3~\xa7\xca[\x93\x9a\xdf\xa8\xf7\x9f6\x8bC\x0b\xdc\xc2& \x8c\xe7\xe8\xae\xbei\xe9\xa1!,\xf0\xe5\xcf|L\xa3m|\x0d*\xb2\xc5\x8d\xc5\xe5*5:\xf1\x89+\xc5@M\x816\xcf\xa2\x82\x9e\x8b\xb4ez\x98&c\xc8u9g\xc4\xc5\xd1\x8f\xc7j\xba%\xaf\xa3\x85\xa5\xad2\x98\xc1bTi \xf3Q\xad\x16\xdc\xb9\xb0\xba\xb8XJ\xd1*3\xa4\x05\x9a\xd0\x8b\x9e\x1e/\xb1\xac\x90\x05\x96\xd0+\xcd\xac\xd0\x1b\xaarE\x169@\x01\x83\xb9\xe9JY\xa17T\xdb\xc7\x08\xaa\x91\x8c\xd8\xe3F>D%d\x13\x8a\"3\xa6\xb5\xfd\x06\xa6\xbaB\xde\xab[\x0d\xaf\x8c\x9fR\xa8\xc9\x17p\x856D \xce\xfe^]8\xe9R\x96mYy\xe6\xcf\xc9\xb2-\xad\xe1\x9b\xaaj\xf8F\xaa\x1a\xbe\xbe\xaa\x86\xefFU\xc3\xb7P\xd5\xf0\x8d{5|Y \xcf\x82K\x05m\xe8@\x04\xcb~\x16%~\x0d\\\xfb\xa7\xe4\xd8\xafi\x88\xe0\x10\xee\x9cq\xe6\x8c\x1bPC%\x02J\x0d\xc2\x8e\xb2`\x15\xc5aN4\x944\x1d\xc6\xa9GC\xb8t\xdf\x9aC\xdf\x0c\x90/\xb0p\xb2\x8e%_\xb0\xc38\x0d\x8e\xce3?)\xb4Q\x14\x19?\xb8I\xf6,J\xdeE\x89fFCQ\x04\xd8Y\xf8qAX\n\xfeL\x0dO\xb9\xf4\x0d\x96\xfd\x8c\xfd\x0c\x1dk\x95\xa0[\x06jSes\xcd@\x1f\xf3\x1e\xeb@\x97\x0c\xd4\x04V\x05\x164\xa1\x1aJ1\x9cb\xab\xb7\x15\xb5r\xc8\xe7yz\xa6\x19\xdcY\x14R\xd2\xe0\x1c\xec\xeb\xbccH\xb4\\\x95\x0cjpo7\x85>\x14\x88\xed\x08\\\xab\xbf\xc4\x14\xcf&\xd8\xe7 r8t\xa9\x9aw5\x9d<\x8f\xa3\xe4\xdd\x0f\x83>\xa6\"6:\xad\xa3\xb6\x86rT\xbc\xc8HB \xf6\x91j\x9er\xa3\xf9@\x92JC'xg\xe2)\x1a\xe6{\xce'BcX\xab\x9d\x16y\xba\xfe\xf1\xd8\xfd\xbd\x1b\xcd\x87\x1a\x0f\xa7\x9e\x94\xf7\xe3k\x97\xd0\xb4/\xd4g*\xa1>S \xf5\x99J\xa8\xcfTB}6,GS\xe6vc\x94\xa9\xe4\xeef:\x97\xf3\x05~\xed^sY\xb96@&\xecg\x1f_\xd8\xd7\x9b\xe9\xbe\x08\xfb\xe2\xfap\xc2\xbeP\xa4\xaa\xe1r\xcbT\x05)\x87\xc3@R\x0dc\xc9\xb4\x07\xe9r\x19\x13d1\xd5\xa0L\x82O\x93\xd79\x15\xf8\xf1\xb8T\x03o8\xf0#? Hl\x00.8\xf0\xd19 6\xba|\xfb\x0b\xa3\xe1.\x1b\xa0<\x08\xadU\x12\xabjq\x8cz\x8e\xed\x10s\xea\x1a\x81\xad2q/+P\x8b\xef^\xb0 \xf5\x8b[\xc6\xef\xce+P\x8b\xef\x9e\xb6\xdd\xce*\xc6J\xc3z`\xb8\xbd)w\x02\x15\x9f\xcf\xbc\x90d9 \xfcRW=\xe0\x1c!\xb98\xa4\x06;F0}n\x8bG\x08c\xcak\xf1\x0e\xa1R\x8dn\xe7;\x84\xd0*\xe0^\xf0\x8f\xf0\xe9\xd2\x95\x9c|\x89\xa0~\x1c\xa7g\xaf\xf3\x8b\xa7\xe5\x8b\x8d\x06\x83_\xb3y\x1b\x98-\xe49\xeb0\xff\xfa\x11\x13?\xd5\xe0O\x11\x9c\xb0\xbd\xf94y\x99\xa7\xcb\x9c\x14\x1a,\xf9\x15\x0e\xe1\x9d\xd7P\xea\xa8A\x7fB\xd0\xa6\xeeF\x0d\xfb\na1\xdd\xb7,\xa3\xb7\xb8\x1e#\xc6 %Q\x9ai\xb5@\xcf\xe0\x10\x1e3#_\x15\x02\xae\xd3\x8f\xbd\xa9\xe1\xb3<\x0d7\x81\x1e\xfc7\xee\x8f\x8c\xa9G\x9eEE9r\x1f\x8f\xe1\xc4iT\xd5\xd5\xf5\xee \x1c\xc2\xb6F\x9bc\x1c\xba{<\x86G\x9a\x97\xfe\xddQl9c\xf8n\x0c/4\xca\xab\xef\x9b\xbd<:/ \xeaI\x8b\x91\xfbX\xd3\xcc\xcf\xc8\x04\xd9\xcd\xda\x0f\x0c\xb6YKX\x0d\xfc\x0b\x03\xe6\xf8\xa6\x83\xfc\x91A\x06,w\x9d\x1a\xee\xbf\x19\x9c\x8d\xf2\xf5\x1f\x0c\xd4F\xf9\xfa\xbf\x18(\xc7G\x1d\xe4_\x19d\xe5\xd5\xc1\xb2,h_\xf9?\x9dW\x8e\xf4I^\xfe\xd9ma\xb3^\xfb\xb96\x17\xca\xfff\xaf\x98\x14\xc2\x84\xf2/!\xcf\xe9S\xe3\x86\xda\xa5\xf7\x19f\x8fe)d\xd1\xc4\xf9-\xec\x9b\xdc\x95\xd0\x9d~\xef\x19\xee+\x1e\x9a\x97{\xad\xec>,F\x87\x838\x9c{\xd3\xb9p\xe4\xe8\xe0R\xf43\xf1\x8c\xa1$\xb6\x16R\x10\x1e\x04\xb4\x7f't\xdfI\xd2\x84\x02\xd8\xe69\xb1\x12\xe6\x9b\xaa\xdb*\xe7c}2R\xf9\xf6\\\x06\xe2\xc0\x0dx\x047\xc0\x91\xe9x\xdbP\xea\xd5\x8e\xc2\x99F\x03\xfe\xefZ\x01\xaa\xd4\x80\xaa\xa6\xe0\x9fZ-\xb1\xc0[\x94ngp\xaa\xeea\x83S\xd5\xfa\x98\xb4}K4\xa7w\xab\x84\xd3Z\x0f\xd7\xf0\x9f\xd1\x1c\xf6\xb53\x84\xca!W=M\xffm\xa7x8\x1f:\xfdC0\xb0R\x8d\xab\xeb\xe2\xbf\x1f\xc3c\xba!\x1f\xb3-\xfe\xc7\x1f\xcc\xff\xe4\xf0\xf0\x10\x1e\xd7\xce(\xea\\\x13\x06?\xe8J\x15u\xeb \xd3\xd5S\x15z-\x03\x18\xbaU'\xee\xed\xe9TC\xe8d\x13\x10\xa7~\x18%\xcb\x89\x9fDk_c\x1f\x19\x8d\xe1H\x9bX\xc8`%\x91\xb5\x8d\xea\xcd\xd3$\xcd\xd7\xbe\"\x07\x10&x\xfa\xc5\xcf\x93(Y\xce\xe0qM\"Fc\xf8\xd5\"\xcf\xd1\xb0\xfe4\xd89}\xa9\xca\xab\xc6Bcf\x10M\x83\xff\xb01G\xfc\xaaX\xd4\xd1h\x0c?\xd1y\xfc \xc3=/\x91\xb6E6,\xc1\xf3N\xc24(v\x9f\xd1\x0f\x86YO\xa2$\x84u\x9a\x13\x08EF\x9f+^\xd8\xd6\x0c\x0c\x1f\xb91\xd0\xd5\xd8\xe6\xa99\xeb\xcceq\xeb\xa7\xa6\x18\xa4\xc23u\x1b\xff[\xd7\x86}\xb0\xac\xc5L\xc4\x91\xf6\x0bJ\x8b\xd6O\xda\xe8X\xf6\xb4\x91c\xa7yj\xa87\xd4\x0f\xbaa\xd7R\xc4\x0c~\xb3:\x85yA\x10;\xf1\xa3\xe2Ef\xf0X\x03\xc5+x\xff\x03\xdd%uj\xb8\xa6\xbaL\xeb\xaa\xdb\xd2\x95I\xeb]\x89\xab#\xb9\xcf\xe0\xb9\x86mi*\x12f\xf0R\x0d\xb9H\xa4Ev\xc4e\xcdP5\xb4d\xda\xecE-\x15\x996\x7fQ\xe6\x97\xab\xe7\xdc\xb1\x93q\xe1\x86nr\x17\xe4P\xb1\xe1*l|\xae\xc1\xc1\xbf\xeap\xd0z2\x98M\xfeX\x0d \x1cV5Ly\xda\x91\x1bgB\x03Q\x98\xe5H\xda~\xf5\xda\x16\x15b\x85;\x12\xda\x91\xe31T\x1f\xd1\xe9!\x96\x84\xbb\x83\x91\x90}l\x06s\xafh\xdd\xd1\xacs\xff\xe5\x0b\xafw\xd3\xf0>\x05\xf9\xd9\xcf#\x8a\xf0?3\xed;\xffH\xef\x89a\x18Mx6\x8ca_8Z,HPF[\">\x85\x9d\x11\xdf\xa9\x9e\xe2}3\xfe}\xf5\x15\xbc\xa4\xff\xbc\xc2\x7fLtq\xa7cV((T4Z\xd5\xd8\xff\xd2\x9eo\xec\xa33x\xf5aq\xdf\x96\x98\xf0H\x16\xa6!\x9b\xc1\x13\xc5\xcc\xd7S\x7f\x15S\xfc\xbcRu\xbc\xa4\x12\xf9\xbcL&\xcb<\xddd(ys\xfd\x95\x91\xb3{.\xdeW\xf5\xe8\x17+\xc9Y{Z\xd9\xce\xe20\x92|\xd9\xb5\xad\xec=3(\xacvJn\x9a\xaa\x1f\xb5(k9 \xf6C\xd3wz4\x86\xa7W\xb5\x97\x85 \x1aT\xc1dCw\xf3.\xcd)]'\xaaey\xa6\x19\xe0\xcf\xba\xd6*\xb5\xf1\x0c\x9e\xa9g\xbaJ\xea\xab\x89*\x11\xcc\x90(\xfb\xa0\x8d\xfd\xb0>\xb7[l\xc4Ul\x98\x86-N\x9b#\xd2\x1aK\xb9\xf5a\x06o\xcc@\xfc\x90\xda\x8a\x80\xbf\x97\xfc\xfe\x934w\x19C\xa59\xfc\xfb\x8c\xb4\x95\xce\xdf~\x1b\xa9A\xe4\x86\xad\x19\xbcV\xbf\x82\\\xac\x89\x9a\x10\xf4\xa0\xf8\xdet\xdc\xfe\x1f\x1d\x06\x93J\x17>\x83\xef\xad1\xce@2vq\x1bz\xb9\xc9\x89\xcce\xa8\xca|'w\x19j\x9c\x1c8)\xad\x87y\xb5\x99d\xcf\xf8\xa6\xec?\xaaQ\x85J\x8a\x0b\x8fY\xbc\xba>5\xcc6\xa1\xf3B\xfa\x12Z\xd4\x9e1\xa5\x17\xd2B\xee\x85\xb4\xa8\xbd\x90\xee5S\x19-4\xeeF_b\x8b\xfe\x03\xdd\x8d\xac\xfc~\x86\xc4\xfb\xe7\xf6\x0e-\xe9\x10\x87\x16\xe6\xa6\xd4\xb6\x13\xa9\xa1}K_\xaa\x0d\xd6\xd039\xa7\x14,\\\x9d\x91-5X\x80`QQ\x95=\xd5\xf0\x0d\x0b\x845\xb9\x9ed\x08\xa5s= Y\xd7V\xe9\xd9\xb1\xa9{+\xfe1\x0b\x17\x94-\x03\xcd\xa3e\x94\xf8\xf1\x0b\x9bW0\x12I8\xa2X\xbd\xb1\x84C\xc8\xcc\xb3z\x81K\xc4\xd5\x1d\xc1&\x8fJ\xadU{\xce\x12(Tu`\xab\xae|_j\x8d\xf9\xa7\x9d\xc4\x0b|:\x9f\x1b\x03\xbf\xcf\xe4/\xbe4\x04\x9a\xf3\x1a'?n\xd6\xd9\xeb\x14\x811;\xc4\x07\xb7.\xd7Z\x01\xd6O\xe8\xfc\x8d\x06b\x8d\x16\xb0\xae*(\x05\xd1\x08 \xa7\xba\x1e\n^P\xc5\xb9\xa9?{f\xaf\xa6\xd3\x05>v\x0c\xd0\x1a\xc3r\xcd\xe3\xc8\xe3\xc6ig\xc3\xab\x92\xfb\xba\xabcc\xafX\xd2\x83\xad\xa8\x99],\x8a\xedn\xe9\xdd\xd5\xc8\"{\xfen=\xab\x93\\D\x8a\x02\x04\xef\xc7 :Qg\xdc\xff\xea+\xb8\xf0\x82t\x93\x94\xae\xaeos\xbdY\xbc&\xb93\xd0d\xcc\x1a\x1e\xe3!N\xd4\x941\x94\x98\xef\x97JMT\"\x89r\xec[\xe1^\x982\x89 \x81\xae\x13\x06\x17\xae\xc2\x01\x05z\xacEu\xd7\xac\xb8\xd2V\xc8\xc9\xb4\x08{\x85B\x87!N\xa1\xbb\xcfL\"D\xb0\xb3\x08q=\x03\x19>i\xa6\xb2\x01\xc5\xa6?\xa32\xa3_\xc4\x04q\xed.&hK:\x9b\xb8\x8fK\x1d\x1b<\xb3\x8e\xf4\xdd\xf7c\x94P\xded\x19\xc9\x1f\xf9\x05\x91%W\xd9\x99P-\x86\x13\xaa\xfa\xbb\xe3\xcf\xa0\xc4\xf1g\xaa\xad\x10\x91S_\x94\x16\xff\xb1\xd4H\xcd\xc0\x95\x034\x11\x89Dc`\x14\xf5\xe9\xc6I\xac\xe2PR\x844\xc6\xa1D\x08\xa6\x8fC\xf1\x11F\x1b?\x82u\xf1\xed\x84\xf7\x82w\xecq\x9d\xc6\xc4\x18\xe1AO\xd8\xb2\x99G\xe4\xc3\x9f\x04y3'\x838\x0d\xe8<\x9d\x9e\xb6\x9d\x9d\xa5@\x83\xcd_\xdazUU\x02\x06\x9d\x02J$`\xd0\x98\xa2\xb2\x06\xdf\xca\x9ao\xfbO\xfbXy\x80J\xd8\x1b\x0d\x0e\xb2,\x0d\x91|\x84Wy\x04^7v\x99\x9e\xaa\xcd\x80\x078\xe4\xe5R\xfa\x87[D\xcf\x84\xfb\xb2\xd3-\xea\x96\xd0\x8f\xd8\xe9\";=\xa2\x8f\x7fz\xf8\x98\xc1\xa63J\xf5q\xb2\xad*\xca\xd7\xe6\xa6>\xe6$\xed\xd27b\xa5\xdb\xe1#\xaf\xd2\xb3\xee\xbe\xe6\x83M\x87j*\xa4\x0c\x9d,\x81\xcc\xfb\xf1\x95~\\Z\x9bS\xd7F\xb3\xb4i\x1d\xbb\xe2P^\xe3R\xfd\xc2\xf2\xa5*c\xbc\xaeC\xa2f*\xeb\x93\x1a\xacU\xe3T\x0d\x96[\xc0\xc8\xeb2\xaa\xcb~\xf6\x06\xe3<\x89H\x8cN\xe5\x1f\xb2\x114Q\xb3\xa2\xa1\xeafZECK\x8f$e~qL~\xc3\xec\xb7\xa6\xcc\xa0\xdbF\x8d\xa8f\x9d\x9f1\x1c(\x881=\xbb\xcb\x93}\x85\xb3!\xee\xe4\x93\xa9$ \xc8\xb0\xad\x12\xd5Q\x84\x0cUT\xa5\xdeT\xb8\x8a\x9e\xa3\xcb\xa9BAy\xfe\xb3\x1f\xcb\xf4<\x9d\x04\x96\xef\xdb\x05\x10\xdf\xcb\xcf\x04\xf6\x99\xebu&\xbcJ\xcf\x0c\xc7\xc2\xed\xe9\x9f\xe2X`\x03\xb59\x19(B\xc8\xcf\x04\xe2Q|\xe8?C\xa6\x14\x1eR\xa63\xfd\xf1\xb8\xfa\xe1\xa2\x92\x91+\x1a\x87\x9d\x14\xd6\x94\x88o]#1ap\x9d\xbd\x1a}&H\xdbG\xcc?Q\x02\x13\n\xf0\xe0\xee\xfe\x9f#g \n\x9f\x98\x949\x1a\xc3\xa6O\xca\x15\x82z\x1fp\x91\xe6\xe0\xd2\xaf\xd1 \xaf$p^Bn\x8c\x13\xceR\xff\x16\xa31N\xf4\xfe\xd7\x10\xc07P|\x0d\xc1\x8d\x1b#\x88O\x82\xb7\xcd7O\x02\xf5\xc1B\xb7v\xc4O\xb2\xbe\xb2\x00ei\xa3\xc2 \xf0\xe3\x98k\x0d\xc8\x18N\xe8\xbboE\x11\x87\x18O\xe1\xc8Cs\x85\x1fG\xff\xae\xa5\x07c\x19\x07zE\x1e\xa1\xe3\xed{?\xbfG\xadBz\x865y^\x936\xef\xab\xfa\x1a\xf3$\xaai\x00\xd7X\xe2\xbe\xa3\xdfc\x7f.\xa2\x98PN\x03S-\n\xef%\xaf|\x0b)Z\x0dY E\xac\xce\x9c\xc07\xacVa\n7 \x82o\x0f\x99;n\xc2\xe2\xbbqs\xf39}\xcc\xd6JV]u\xcc4\x19=E\x17\xdd}\x1fC[u\x95\xb5\xcf\x98\x9c\xbf\x8a\x96\xab\x98\xce9\xaf[I$\xc1P\x1d ]\xc6\xff\xf5\xbb\xf7&\x0b\xfd\x92\\\xaf\xfe}\x02e\xdfV\x1f\x90\xc1vV%h\xe87\x14\xa9\x88\x0f\x15\xc3\xb4:.,0\x86\xc4\xc4\xb9\"\x9f\xeaj!&A\x1a\xaa\xca2\x8eQ/v%\xed\x89\xa1Nx\xc5yY57q\xd5^\x1dt]\x9a\x14Z\xd5M\xe71\x07r\xcc\x96i'\xcb\xf5\xc9\x01YYN\xda\xb4\xe4\xc8\xd1\xf5\xfa\x97\x15!qU\x04KG\xd0\xd5_i\xcc\x19\x96=\x80uD\xbf\xa0\xae{\xfa\x9er\x00\xc6M\xd4W\xc3\x99Tpr\xa7\xd7\xe6N\"\x1e9\xcf\xd2\xbc,Z\xc7S\x9f\xbd\x85\x06\xe7\x99\x903\xf8>N\xe7\xee y+[\x83\xf2\"\xc3\x91ST\xa7\xfc@\xc4\x8ad\xdfL\x83\x92\x94\x93\xa2\xcc\x89\xbf\xeeH\xeb\x1d\xf6'ZT\xf5v\xf7\x0e\x0f\xe1,J\xc2\xf4\xccK\xfcm\xb4\xf4\xcb4\xf7\xd6\xc5\xb1\xbf%\xb4\x0f#\xddC7\xefsV$.\x88\x82k\xa3\x87\x1e\xff\xda\x9bW\xcf8\xc61\x0e\xfe\xcd\xabgn\xae\x91\xe9C\x9e\x0c\xa4\x8b\xa6\xbeL\xef\x1dyX/W\xb8\xb6\xc1!8I\x9aP|\x8e\xbcUN(G\x9c\xd2\xdf\x05)\xbf+\xcb<\x9aoJ\xe2V\x9b\xcfa\xb2N\xa3\x1cq\xcd\x00\xd13\xb3\xfb\x1ec$\x9cq\x15\xd3;\x1a\xd7\xdd\x9d\xa7\xe1\x05\xe5\xd9H\x12>ZEq\xe8F\xc8\xa6\x05t\xeb\xba=\xc0\x9c\xac\xd3-\xa9\x01\x1b\x93\x95\x93m\xfa\xae1Y\xa9\xea\xe8}/E\xc9\xeb L\xc9\x95\xbfR1+R\x89Y\xbeJ\xcc\xda\xa8\xc4\xacB%f\xc5\xfcAOb\nx\xca\xc7\xbe\x1cUKZYU\x12B\x98>+\xe0?\x81`\x95\x8f\xc1\x97\x0bV\xd1u\x14\xacr.Xml\x05\xabt\xa8`\x95{\"x\\\x84\xe1\xfc\xc2B\x04\xad\x84\x0e\xde\xd5\\T\x88\xac\xc3\x85\xbc\xa0\xf5QT\xa8\xba'\x02\x10M\x90\xd5k\xcc\xed\xe2-\xe5\x9f{\xad\xbcg]\x14\xf1T\x8f\x18\xfb\xf0\xfa\"#\xac\xd7V\xdd\xace#\xca~\xe4i\\|\x17\x04$+\x7f@\xf5\xaf\x89\x9f30})\xe6v2\xb0\x8f\x11\xba\xedY\xa5@\xf4\x11To\xa4\xdd \x8c\xceO\xa6\xac\x08\xbad\xea4EZ9\xd1\xd3\xe5\xb4d\xde{j\x00\xe1>\xbb\x91BH\xaa\x17\xbd\x1f3\xabs\xafp4\xdd\xad\x96\x82X!\x15\xc4|;A\xacX\xa5\x9b8\xacX\"ka\xc7\xb4/\x1a>M\xdd\xc0@\xe4NH\xff\xb6(\xbf\xcf\xde\xaab\xdb8x\xfdw\x1bN\x84\xd6q\xb0\xeaO9\x14n\xc6\x0e(\xbb\xd7\x86\x97\x07\xbc\xf1\x17\x15\x0f;-\xfa\xe5J4D\x7f\xb6\x9f2D\xe1\xcf\xd9\x1f}\xdch/\xffG\x92\x06\xf5$\xc1F^d\x1e\x19\xd5z\xe9)C\xd2\xc3\x03=yH,\xbdN65\xac!\xa5,\xf3\xd3\xb0\xcc\x13\x8bl\x841\xefm\xd2\xc6-5p\xc8\xdc\\\x06\xa6\x0d]U=\xd6G\xd5l\xf9\x11Zi\xed\x8e1\x89\xdf\xa34$#7\xd5x>\xac\xb1\x98\x8f\x13\xd4d\xd3T\xd1\xc6w\x9d8\xda\x12\xb1\x86\xa6\xca6~\x1d\xbbj\n\"\x91m\xf5\xaf\xbe\x92\xdd\x16Q\xa4\xb27f\xb5\x84\xf7\xb2\xf5D\xdd\xf8)\x1cB\xd1\xac\xf6\xc7\xa6rIJv\x82>b\xe7)\x95p\xc5\xb0\xe9\xacJ\xcd6\xe229\xee\x0c\xd1+T\x1b\xcc\x98\xd9\xe0J\x9a\xb3q\x01\x10\x971O\x16w\x05x\xd5\x88_n\xcf\xb5)q]\xec\xcfI]3\xc4\xe4\x08\xd5i\x0e8b\xa3\xcc\xad\xcb\xa6\xa5\xad\x16\xc3\x89\xab&(L\xb0\x97\\1\xa2\xe065\xc4\xa6\xde\x7f\xc5\x0c\xe6\x1a\xc0\xc6:\x89t\x17\xfc\xe5 \x8eQ\xbeJ#]\xc6\xabA\xc8Q\xe3b\x94\xe8\x92\"Df\xa5\x9a~E\xb5\xd5^\xea`i\xeb|\x94\x1a^\xae\x99y@\x93\x03\xaa\x93y@CP\x18\xf7\xd8a\x11\xcc\xbcd\x8fk\xd0\x1c'\x8a0}U\xfe\xa5\xe1\xdb\xd4B\xc9(\\k\x86b\x0e{o0=i\xbb\xe8\xa8\xc1\xf2\x1d\xba\xb4+\x8dS\xb8\xe1\x88K\xed\x8eS\xa1\xf0\x84\xde\xe39wU\xcd;\xf4 \xd7&\x03\xbc\xa2~\xd8\x04\xbb9\x8f\x1b@]j\xfe\xa1;\x18G\xc9;\xcd<=\xc3\xc7un\x07\xdd\x8c\xb5<\x9bR\xa5gS\xa9b\xa5\x81\xb3\xd3I\xdf\xc3\xa9T{8\x89\x0bYg\xa5\xa7\x93\xb8\xb0|\xc9\xc9\xd4\x00\x15\x027\x18F\xed\x0c\xcepx\x08)<\xac\xf1\xfc\x94'#A'_G\xce\xb8\x80\x99y\xb9\xd0\xad$\x08a\xc5P\x96\xb8\x8e:[\xb1\x1c':6\x15\xd0\x1d\xf8\xb1\xd0\xa6mQ\xafkh`\x91h#\x13\xa1\x8du\x1aZ\x8b\x90iH\x8cC\xaaO%M8/\x0c:I\x803\x07]u\xce\x8c\xa2\xc6\xe1\xa1.m30\xbe\xa4\xabK\x9aa\xd9\x0f\xa5\xaa\xc9\xdc\x15\x0e\xae\xe5\x87\xc0\xfeT\x85\xfeI\xad\x84U\x14\x85n\x15\x83\xde!\xa1K\x8d\xe7;$u\xe9'C\xeaGX\xd6\x99\x83\x98\x85\x98U\x8a\x1a\xb9'-\xfb\xcf\xaf\x85\xa4\x16\xa7\xea\xa0\xdf\x9b\xd6\x03\xf8\x1c2\xb9\x84*w\xacP\xe5\x8e\x15\xaa\xdc\xb1B\x95;V\xa8r\xc7\n\xa5\xe6\x8b\x98?\x91Z\x10\xdcP\xd8\n\xc2\xcaV\x80\xbf\xa6\xb7z\x05\xa4\x17R\x8b\x03\xaa\x07Te\xa5\xc3\x8fo\\X\xd9\x1a\x17\x88\xc4\xb6 C<\xb3hkjo);O)\x0e\x8d}\x914\xc1'+\xf2N%$n\x90\xba<2)\xb9\x12\xe6\xeb\xd3oF\xfd\ns%\x92\xd1m\xf9\x99\x8b*\xec\xe3\xd2/uJ\xeb\xbcO\xb2\xbbK/\xae\xf7h\xd82\n\xb4\x9a\x11\xc8\xcf\x9c\\\xd1Z\xef6\xfa{Q6\x84\xf4\xe8\xa5\xb8\xa4\xc3q\xfa\xac\x1d\xfd\x94\x02\xbf\xe1\n\xdd\x94\xaeF\xb3\xca\x08-Z\xe0RK\x1d*3\x9aP\xfeB\x0d\xc3\xac%\xe6\x02d\xccbb\xe1\x9a\x13\"\xa0Y\xaf\xb8B8\x9d\x12t\x8b\x10v\x9a\xdau\x0dk\xd0\xd4.\xab\xfeYhj/\xf8\x0cVx\xa4\x06\x9dW\xa0\xf6\xf6\xb1S8\x84\x95\x17%\x0b\x92c\xaeS\x8d\"\xe1\x0c\x0ea\xc9\xc5!5\xd4\x11\x1c\x82\xcf8u&\xe2h\x93\xfa\x9d\xd7\xd0\xe4\xdc_g\xb1>\x07\xe0q\x0d\xced%\x0d\xec#8\x84\xadU'\xdeqH\xe1P\xc5\xe5Q%\xfcw\x0c~\x9d\x86$>b\xbd\xd6\x81\xbf`\xe06%\x80^2\xd0*.\xd3TL\xe75\x83\xb7Tp?\x17\x9b\x16i\x97'\xa1Q\xf4\xc8\xbaPP\xf1\x05\xb8g\xee\xc8$/>\x15+\x84\xc5\xb2x\xc7\x9c1<\x7f;\xe6\x8a\xe7\xe7~6r\x7f\x7f\xdfe3\xba\xd7\xafp\x08O\xb9\xc4\x87\x88\xe9\xf4>\xa0\x16\xf1\xeaP?4M=ma\x98#\x94\xe0\x99W`m\xa0hq1r\xbb0T\xccf@KR\x1e\xe3M\xb6AF\xee\xaf\"\xec\xd70\x9b&A2J\x82x\x13\x92W\xc4\x0f_$\xf1E\x8b\xcb\xec^\xf4\xd0\xa3\xc7\xcd\xaf\xf0\x10\xcaJy\x95\xf0;\xa7U\x9fj\xc5V\xce\x9f\xb9\x8d\xcc\x89\xcd\x151\xf5]L\xfb[\xfaI\x85\xe6\x8d9T\xd1^\x9c\xba\xbe\xe8\x01k\xda\xf7V~Q\xad\x1d\x9d\xf2\x90g\xfb\xacnQ\xb9\x14\x07\x95T\x0b\xd2\x9b\xebd\x0c\xcfu\xf3(\x99C\xcdi\xc4\x80\x7f\xc9\xa3\x92hg\xfc\xbd\xde\xfcq\x8e\xbe\xcc\x94v\x9d[\x04\x8a\x89K\xb0\xc0\x94\x1d\xa2l/+&\xf5\xd7\xbf\xe6d\xe1\x08\x97.\xda\xae\x8a\xebQ\xe0;\xddu?Y8\xf05/a\xdcF\x0bTeo\x1a\x16\xff\xd6\xbc\x9a\xb1p\x0d3\xbe&\x16\xaey\xe5\xda\xb8\xb8\xe6\x95\xf2\x1893\xa4\xe0\xd0[{<5%V\xba\xa4YK\\\xc8t\xc9\xd9IqiMKw*\xcd]\xaeQ\xf2)\xe3\xfe\x9aW\xdb\xa4\xc2h\x9by\xf68[(\x8f\x19\x17\x97,v\xbc~V+-(J_\xd6^b\x1c\xeb\xf0q\n1A3\x06A\x05\xe4\x1b\x92\xa2\xf7\xf9\x18\xde\xed\x98\xdc`\x07M>8p\x03\xdc\x0ds#\xd7l,'\xf4K\x9f\xb9\x85+\x03\xff\xafN\xdd>D\xd7\x1f]\xa1\x9a\x7f\xb0n\x7f\xe7}-[\x8bn\xab\xa7\xa7z\x93\xa1\xaa\xf1\x17\xba\x86E\xd5\x1f_\x94)l\xd8&T\xa7\xc4\x18\xce\xcc\xbb\xcdj\xacL\x9dWQ\xf3\xe6\xd0\x1b6Y\xd3\xcet\x84@2\xf1Q\"\x11\xd6\xa8\x19\xcc5[o\xe84\xbe\xb60q\x1b8\x1e\xf5\x94\xb4\xec\xd7|-\x04#E9\x9b\xee-\xef\x1da\xc7(\x88\xc4\xd5\xc7\xe4\xb7^\xd2\xb9\xe6\xd51\xb1\xcb\xf4>\x8a\xf5\x1e\xc3\\\x9b\x83q\xed\xc7\xb5\x83\x81\xc3\x9d=\n\xd0E\xa1 \xe1\xa8^ar\xa43\x1a\x83\x03l\xe9\xbc\xda\x06Uq\x9b?i:\xf1\x9d\x16\xc5+K\x89u\x9a}MV\xfc\xa6Z^S{\xb1c\xa2\xd0\xd5^D>T\x88\x02L\xb5\xfd\"\x0fIN\xc2\x91\x9bhV\x94\x1fB3\xf8I\xb1p\xd5\xd4\x1di\xa6\xee\x91n\xea\xb8h;\x83#\xeb\x99\xd3\xf7e4\xae\x04\xfc+\xb5w\x0e0r\x1e\xc3C8\xf6\xcaT\xc6\x85v\xa2W\xba\x97\xe1\xc0}i\"T\xc8\xb5i\x14<\xf4JpP\x06 :B\xad\xfe\x11,\x17\x064\xa4p\xa4\xad\x87Yo\xdf\x9fR\xe0\xaa\x92j\x95{\x1f\xbc\x94\x05i\xa5\xb7 \xd5fCF \x85u\xe8\xf7\xf7]s\x89\xcc\x9a\xd7TL6T\xffm\x9b\xd0\xea\xbf\xf8\xcdke\x13Z)sG\xacTQ%+UT\xc9J\x15U\xb2RE\x95\xacTQ%+\xa5Mh%lB+\x8c\xc8\xbf-\xb5\x04\xb1g\xbd/W\xe6\xa0\xf6\xedP\xf4]\x91no\xf5\xf1\x0dE[[C\xd1\x97(\x94\x8e\xd1\xca\x14\x85\xa2\xb7\x88d~^\x90\x90oq\x85X\x85\x91\"\x1bt\xdd\x7f\xd9\x04\x1fd\xf2\x12!)\x9c\x1bSk3\x99\xff|\xa9\x16b)\x10S\x91@\x94\x14\xa5\x9f\x04$]\x00\x0b<4\xebC\x12\x1e,\xf9$\x8aQ=\xa52\x8f\x89+\xf1R\x16\xc6g\x91\xc3\xa0y\xe56\xe6\xb5\xe6\xd5] \xca\x0cobydn\xf3R\x9cD\xd5\xe31~\xca\x0f\xbf+^\x93\xf3\xd2\xd5L,\xd7\x1bZ\xf7\xbc\xd3\xe3\x92\xf2\x07\xac\xaa\xbbN\x03!C\xafO\x1b\xa4r\x95\xd9\x02PN\x90\xec\x15\xd7\xea\x88W\x07a\xec\x942@\xb9)\x95\xbd$b\x7f^\xa2\xabWc\xd5\xb4\xb4d\xd6\xc1g\x16YB\xad\xccu\xac^\xc9&\x97$T\x12\x17\xabR\xc2\xf9|5\x98_\x9b;Xz\x8d\x87\xf0\xfb{\xd0\xba\x0fo\x06d>-\xdav\xa3\xd6nT\xbf\x85\xf5A\x06X\xd5\xe8\xc1\\\xfb\xf2\xa1\xa6\x8b\x92\xcf\xc7~I\xb0\xbe\xe8\xebhMt\"\xf4\xba\x9a\x04\x8d4$\xc9\xf5\xd5\xbc(\xc5\xa7\xcb\x92\x8aL\x0d7\xffo\xc3\x87\xe9_\xad \xf6\x9b\x91W\x92\xa2t\x93\x11\x05\xf6O\x1c>#\x93\xc7Q\x91\xa5\x05f\xe6w\xde\xd2\xe3\xe3\xa6_\x96~\xb0\xa2\x07\xb5xI\x05.\xbe%4,\xa1\xdd\xb7\xa4\xe0\xbd~5\xb4G\xec[\xf4h\x82\xd7\xb9\x9f\x14\x0b\x92\xcb\xba\xd6|\xa3\xd75\xeb\xcfI\xdf\xd0(\x8f\xe9*8\xf4\x98u Jx\x9c\xb9\xe9$\xa4[\xf9\xa2\xca\xb1Q\x92\xf3\xf2\xe6\xaa\\\xc7\x16\xban\x0c\xce\xe9\x1e\xf0\xc2\xcaV%;(\xa5\xc9\x0ed\x17K\x80pa\x84\xed\xca?\xb2\xebT\x9f\x94`n\xf1\x8938\x84\x93\x0b\xca\xd0\x15\x9byQ\xe6n\xea\xc5~Q>MBr\xfeb\xe1:7\x9d\x11\xdc\x80\xe9h\x0c\xa7o\xbd_\xd3(q\x9d\x99n\x9b\x8a\x0b\xed\xfc*D\xd5l\x08=\x13\xd4\xc9\xfdpdZv\xe0K\x7f^\x99{\xc8y\x99\xfbA\xf9\x84\xe7oz\x92\xa7k\xde\x8fF7\x98W\xc4\xc8=2\x18\x84\xe8\x85!<\xb43\xcc\xeaG\xe7\xf3\xdc\xc0 i\x9fR\x1aTy]\xd6\x99+\xe8\xc7%\xb7yB\x8b\x17\xf9\x8b\x8c$\x1c3/eIq|\xa3\xc6\x16\xaa\xfa\xec\x06\x07\\\xd8\xa9\x06\x8a\xb88We3hw>\x863\xfd\xa4\x83q\xe2\x9bYf`\x11 #\xff\xb5\x9aM\x91\xcbc\x06g\x83\xc7\xa2|\x81\xb3\xdb\x14\xf1\x94\xe3`)u\xb8\xce\xa8\xfa2\xe7< $%\x96\xd6\x86\xf9\xa6\x84\x8bt\x93\xc3\xd7r/\xda\x99f\x96k\xda\xe7\x06'\x84\xa2\x81\xdbN~\xc8x\xd7\x9b\x14\xe8_7\xb3\xd8\x8f\x92\x9b\x8d\xd9\xff\xc8\x036\xf0k\xc2\x88\xa7\x181\xcc\xe0\xe6\xff\x8d\xd6\xfe\x92\xfc\xebf\x0b\x87\x12\x8f\xbb\xfd\x14\xaeSl\x97\x8e\xd6\xb0\xd1\xa4\xf9\x0e8\xa8Fv\xc0\xd1+\xdb\xd7K\xed!\x80\xf9\x9ed\x9a\xcb\xe6\xb5\xf6\xcf\x7f\x89\xc2r5\x03g\xba\xbf\xff\xff\x93c\" \xe5W7\x94\x073\x1d\xbb\xa8\xd0\xc8\xf0\xb9\xf37a\x94v\xe6\xce\xea\xb8P\x9f\x8d\xf4\x8bzC\x117G\xaa\x1d\xb1tA\xd1h\x1c\xd7O=\x9d\x11]\xado\x96\xacL\xb5\x89\xe8\xc48\xcc\x7f\x88n\x1f\x04O\x17P~\xfc\xbdQ\x9e\xcbtE\xe22o\x0d\xee\xe4\xf5-\xec\xc3C(lw\x80z\xf9\xad\xcd\x7f\x91:\x9c\xf1M\x92\x93 ]&\xd1\xbfIX\x99\x89p\x8e\xbf\x16\x81A\x94\x89\x10A\xee~\x81\xd4\xdd\xd3E\x8a~\xca\xd9/4\xa4\xf8\xd3M\xe4\x06K\x91@\x99\x8a)\xad\x8d\xf7Z\xb7\xa5\xe5\xa5q\xa4\xe1\xc5Vg,\xc0\xb0Tz\x9e*]\xab\xacm\x916UH\x98Yu'\xcb`\x95\xef\xd0}p\xf7\x8e\xc4\x88\xa7\xd7}\xd6\xbe\x9eY\x1c\x95\xeeM\xf7\x9b\x7f\xdd|x\xf2\x7f\xbf}{\xe3\xdb\xd1\xcd\xe5\xc8[DqIr\x0b\x0fK\xfe!\xc7\xa9\xb2\x0dEkY\"\xdc\x8e\xfa\xba\xdd\xdf\xc8\xb6\xbf7\xbf\xf9\xd7\xcd\x1b\xac\x9b\x9c\x11 \xda\x0f\xfb\xf6\x1f\xc6\xaf\xfe\xeb\xa6\xddw7\xb6\xdf\xb5\x9e@\xec\xc0\x9er\\\x80\xc8E0\xef\xf0^$~\xf8\xbdn\xd6\xf8!\xcf\x9d\xd9\xed\x850JuM|\xf0-Li\x13\x0d]Gm\xcb\x9b\xbe\x85\x87\xed?g\xf0\xbb\xe4\xdcg\xb1[\x82\x83\xed?G\xbd\xad'a\x89\xfb\xa01\x1c\xca\xf4\xa6\x01\x1c\xc2IGeSg\xb2\xa5\x7fu\xe2\xac\xe9x\x17c4\x07\xbb\x0b8\x042\x86\xd4]\xd8\xb8\x13\xf3uR)\xeau!]\xec\x14wK\xd6^\xe4\x96\x94uq\x1e\xc5i\x11%\xcb\xd7\xfe\xd2\x81\x19l\xf8\xdd\x17\x19I\xea\xbb>\xbf{L\xe2E\x1b\xdeyM\xe4\xb9\xbe\xe5\x01\x81\xed\xa3\xf7\xfdH\xe2\xba2\x86TeR\x8eLI\xeaX\xfdq\xa4\xe8\xbd\xe7\xad\x81R\x1e\xdf\xa7\x88\x15O&\xf2\x9e\xd2\xad\x95\xbb\xc9\x18b\x85\x92\x0fK\x89\xc3\x0d\x88\xfa\xef\xa3b\xb69\x83us7n\x8c\xa1\xd0\xd9Y(J\xa4'%L@\xe7\xbe\x1dVP\x07\nM\xa1|\xb8l\xb9\xf0\xef\x0c\xe7 ov\xbb\x1aV\x8f\x109\x1d\xac\x9c\x057 ds\x0f7 \xab~ET\xe8\xc4\x80\x05\xec\xcd\x18\xb0\xeb\xc6\xf0kh\xd0\xa6\x0eN\xb4\xc7\xc3\x81\x02o\x91\xe6G~\xb0\xb2\xdb\x1e\xd9 yK\xf7_\xf7\xe4\xa42jfw\xaa\xf0/\xed\xedu\xfc%F\\\xfb\xfb\xaf\xa6o\xe9%\x12\xb6\xde\xfc\xfb^\xdd\xc0\xdf!'\x19\xf1\xd1vB\x99\xbaoVe\x99\x15\xb3\x9b7\x97Q\xb9\xda\xcc\xbd ]\xdf\xfc5M\x8a`\x15G\xc9;\x92\x977[\xf0\xdf6\xbe\xd4\xfc\xe8\xa34\xbb\xc8\xa3\xe5\xaa\x047\x18\xc1\xc1\xfe\xf4\xf6\xe4`\x7fzg\x0c?\xa6 \x1cW\x1f\xf3\x9a\xef<\x8b\x02\x92\x14$\x84M\x12\x92\x1c\xca\x15\x81\xe7O_\x8b\xdbM\xd0\x9b\xd5od\x06X\xd4c3\xb3\x842\x7frw\xdeq\xe3\x08Ab\xaf\x12$\xc8\x08\xcaU\x9e\x9e\xa1\x9d\xe1\xf5EF\x8e\xf2<\xcd]\x87\x9cgL\xdd\xe6\x03\x7fI\x92\"y\x8a(]\x8e*^\xa3\x0fr\xd0\x05\x81\x1b]0\xe1\xa9@\xc4\xc1\xf4w(\xfb\x1f\xca\x19\xf7A\xa9~\xc3\xce\x98\x8fX\x16\xf4\xfe\xc4@S\x9d\x97Vg\xde!\xc5\x1b\xde\x97\xca\x1e\xb1O\xb1\xa9\xfd*z\xc7|\x8d\xa5\x00\xaa\x97\xd1\x0d\xe3[\x98~=\xa2''\x0b]qS\xb8q\x88F\xf8\x12\xbe\xfd\xf6\x10\xa6c:\xc4\xc3\xee\x18E\x8b\xf4P\xe2o\xb4\x1a\x1f\x86\xed5cxw:2\xe1\x82\xc2\xbb)w\xc9\xc8+\xd3g\xe9\x99\xa8D;\xac\x0f\x1f\xdd\x99\xed3,\xfe\xba\xa82\x1b\xd0_\xf7F\x7f\x8e\x82\xaf\xdb/\x05f\xd4\x05f\x84\x17\xfd\x80h8\x81\xe0\xb9\xaa\x8a\xf6\xa8\xe2\xa8\x8e\xceKM1\xef\xb4[\xb2;U\x97\xecN?\xbeZ\x88 t\x9d\xb1\x98-\x8b\xe6z\xddReh>t\xb7Jy\xa7\xd3Sr^\x92\xa4\xe8\x1d\xf6\xef\x99\xe7\xd4\x0c\x9c1\xf0\xa3)1\xd7\xda\x8e\xae\x1bB=e\x9ecG\xeb\xac\xbc0\x94\x89\xef\xc5\xd4\x8a*\xf1\x98S\xb5~'\x12\xfa\xc9\x88\xeb'\xafU\xc5x\xd5\xc8m\xf0\x10\xb1B\x85\x88Q\xc1\xbf(9\xea\x98\xf9S}\x02\xfb\xfc\x0b\x8f\xa3\x02)\x9d\x14\xa1\xf9\xb9\x8f4\x0f{\x8d\xda-\xf4\xf6\xbb\x0c\xaew\xf4\xa9-\xd4\xa7\xad\x9c\"\x0e\x9d\x96\xe9r\xa9\x11>B\xdesY\xfa\xe7\x9e\xeb\x86\xba\xbfQ\x92mJi#\xcc\x04\xee\x04+\x12\xbc\x9b\xa7\xe7\x12MY\xa3\x0b\xfd\x87\xf8\x1e\x1e!\xa8t\x90(tj^\xc9\xac\x9c\x8c\\Q\xc1\xda\xe3\x1f6\x1e\xb7\xa318\xc7$ \x01'\x95mL\xa7\xe7#\xf4Y\x95\xe8\xff\xa49\xa1\xe5&\x93Pj2Q\x94\x93T\xa4\x88\xbeu\xd0\xcb\x0b\xf0%\x17\xb4\xdc\xb0ag\xd4\xb0\xcd\x05-v\xe0.f\x82\xa1\xeeG_}\xd5\xfa[-F$&\x1bD\xc3\x02\x90TC\x18\xb9\x89'$\xc618\xcc9\x03\xad\xcb\x88\x13\xcc\xbaLD^\xc2\x84\xd5PB\x91\xbfOG\x9a\x96\x14\xebCK\\\xdbai\xb2\xad\x94\xc8y\xad\xc2W\x03\xa5\xd6\x9af\x1fS\x1aX\xc9\xb4\x9b\x1a\x94\x8a\xc4\xda\x05IxT6\xce\x15.\x04N\x1e\xe5\xe4\xdct\x0c\xfe\x186*S\x10\xe6\xf3\xe6\xd5*X\xcdA\x8b\x8c\x05\xc2\x00c\x9ci\xc6KX\xea\xf6\x13\x10u M\xd3\xc8\xca\xb5WHg\\\x18\xb5r\"\x19C\xae\x98\xdbF\xf4\"\x96\xf0`k!\x0e\xb3\xaf\xbe\x02\x07\xb5Y\xb8\xdf\xd2z\xa1t\xfa$\xc1\x9a\xe9\xa2\x96\x01\xcf\xc3\xa88>\xf3\x97K\x92\x1f\xa0N\xd6\x87\xaa\x8d\xf3I\x9d\xf9\xf6\x8f?\xd8]L\xcf\xcbi\x11\x8f\xed\xad\xefW w\xabT\x8aj\x88\xc67f\xd8\x0b\x9e=\xea\xab\xaf\xc0m\xf4A\xd1\x83\xddZ\xaa+`\xef \x07\xb0\x1e}tY8h\xb2Y\xcfI\xfe\x9a\xeb\xc7F\xae\xaf\x88\x93\xeb{q\xc90\xdd\x1d}\x9c|\xedU\x12\x86_\xa28~E\x02\x12m\x91;\x91\xd5\xdc\xb7\xce\xc5Ps\xea\x9fxw\x99R\x88G\x97\xda\x83Hd\xa2\x02 \x1b\xee\x84\x1cf*3\x9a\xcd\xeeJ\xab\xed\xe4F\xad|\xd4#q\xa8\x07,%\xf5h\xc4Q=\xd9\xac\x91w\xf5\x81\xe5b\x88:\xf7u\xad \x17\xcd\xc6{53lJoP\x18\x86\xd2\xd84\x1b\x8c\x03\xa1\xff\x9d\x893#'\xbfm\xa2\x9c\x84\x8cT\xe1\xae\xf2\xd9\x19L\xf72\xba\x89x\x8b(/J\xb7\xb3\x01\xb1\x90e\xc1?+jZ\xdam\xc7bTe\xd1\xee\xee\xb4\xfe\x86lo<\x99\x18\xf4\x01\xbc\x05\xec\xce+\xc3q\x9fX\xee\x8f|@V\x8e\xb4\x865\x98\xcb#.?sm\xaf\x9e\xd7 Z{\xfe\xa6%\xaa\x0b\x95\xb7\x1e#\xad\xe9M`Mo\xc2\xea\xb3\xe6\n\x0f\x85\x91\xde`\x95\x07cj\x11\xafX\xa5gGB\xdde(\xef\xc0\xa0\x1f\xa5\xebu\x9a\xd8\xbcs\x81^\xd9\xce\x8fE\x9a\xb0\xcc\xe7O\xd2|m*)\x9b\xbb\xcc\x98\xfc=\x0b\xaaQ\xc2\x9e\n\xc7\n\xc6n\xa8\x01\xcf\xe0\xb0\xc9\xa2\x9c\x9a\x0b\x98\xceM\xf6\xac\xb6\xc1\xc9`\x15Y$Zk6\xd4\xf6#\x83\x95)\xa8\xec3\x85W\x15S\x10\xd8\xea\x06\x06\xbbP\xd0\xf4\x8f\xa2\x9fh\xa4\xf3\xc1{\xf4\x135\xcd$E\xd9\xc8\\hot\x92\x91I\xbbwk\xf3\x93\xa1\xf4X\xc3\xc2\xa3\xc9\x05\x04\x83\x8b\xb65\x8dL\x81\x12R\x97\xe1\xe4\x88\xe1\xafm\x0d\x8ds\x06nSC\xe3\xb8\xb13\xb8\"\xddT&\xa4 \xde\x94!MEC\n-\x93\x12P\x89^\xfd\x81\xef\xea]\xb9H\xf3\xb5\xaf\xed\xe5\x0b8\x04\xf4\x81^!7Rv\x18\x11\xed\x86x \x87\xf0\x82\xbdP\x1a\x10\xf45%\x00\xb47\x8f\xfd\xd2wL5\xf8\x9eS\xe8'\x15t\x94\xd4\xa1\xe5\xea\x97\x9e\xd6\xc3\xae\x19\x0e5\xf8\xaf\xa2\xf3(\x0cD%Y\x17T\x16\xc0\x81t\xab\xc95\xaf\x9f\xe0\x10\xde\xc1Cx\xd7\xe5\xa1\x1cM$\xe7+8\xc4\xc0GW\xd4\xa2\xe8\x12\xf0\x91[Vy{\x95_y\x0c\x87\xb0n~e\xe0\xfb\xcf,\x12Y\xbd\xb1\x80\xf9\xcd\x02\xe6 \x1c\xc2\xdeT\xab)h0z\xcc\xe9\xfeY\x8dOl=:\xec\xe03:v\xda\xc1gM\xbew\x8c\xfd\xe1\xb7\x84(\x87\x86\xe37\xf5\xf7\x04h\xe3koh\x9bo\xea\xf0e\xda\x03\xec\xf5~\x1b\x8e\xf5\xed\xb7\xfa[U\x1b\xe3f\xccB\xd9\x15G\xb1\x02FWL\xd6z\xa4\xe8\xf3\xf6\xb3\xdc\xfbH\x17&\xa8\xb0\x99\xd9\xba$4\xdf\x8c\x12\xa7\xe5\xde }\xe9\ns\xf8\x0fq&\xba\nC\xffSx\xd82#\xd2\x06\xa1\xa2\x070\xeb=T\xf6\xa6=\xb9\xf8au\xc6\x00VF]\xddC\xabT\x0dA\x1ac\xbe\x10\xdaS\xf5\xd9\xa7\xea\xaf\xf3?\xff\xef\xefN\xc3\x8f\xee*f\xb39Y\x9a:\xe9cx9\x86_Q\x0fu\xe2\xc0\x0d\xf8\x15n\x80\xf3\xd6\x19\xc3w\x18\xc2\xb7\xf3\xac\xb5z\x92\xa7\xd9\x84\x9fg\xca)p\xffJ\x1b\x1d\x833\xd2o\xb5\x1d\xa7 $YN\x02\xbfT\xad\xcf\xfbq}\x96\xd6\xdb\xbf\xf1\x16\xc6\x846\xfe\xfep\xab\x15i\x9c\xe4\\g\xdcb\xdbq\xba\xc6\xb0\xa4}~%\x94\xe3\xaf\xae4G\xfa\xb1\x89\x9dgnW\x14o&\x14\x83\x0c\xeeR\xe7\xff\xb0H\xa9~\xfe\xb3\x1f\xeb\xcb\xb0\xc8g\xa8N\xa0\xbf\xa63\xf2X\xcc\xc8\xe3\xff\xf8\x19\xb9\xc2\x1a+;8wV\xdb\xa9\xe1\xe2\xa9!\xca\xe7Zz\xcc\xeb\x9f\xc8\xbei\xc2\x8a\xbd3\xd4\x0b\xc3\x1f\x7f\xc0\xde\x13\xb3$\xab\xed\x87\xca\xf9\x85\xb2+\xea\xb5\x14\xbdw\xbe\x89\xbe\xfdn\xebG1\xa6\xe2@V\xb4\xf8\xe6f\xf4-=\xe6\xe0\x06\xbc\xb1\x88\x8eo^\xc2|\xaa\xc1\x8f\xda7\x8f\x07\xf5\x8eU\xc9\xcd\xde\x8fZ3\xd5\xe0\x94~\xfb0s&\xd82\xbbi\xe3*A6i\x8d9\xfbM9\x98\xd7t,{\xcf\xb5'Z+\xcb\x13\xc6\xdc\xce\x0cY\xed*)\x07\xcb\xebP\x94\x8a\xcc\xd3\xa3\xad$o\xd0uX\xebM\xb8N\xf3'5\x84`\xabf\xf0T\x0d\xd4\xd8Z\xf2\xedVK\x9d\x8c\xd5\xa2\x14\x0f&\xd0p\xb9m\x83\xcfXx\xbd%\xef\xbb\xabV\x84\xd0\xc5+fB\xccc\x7f\xea\x1a\x12\xf5\\^(\x11\x087\xc3\x0b\x0d\xc5:\xd2-\xab\xf5\xba\xd5\x0e\x96\xdd\xba\x88\x06\xa4\xe0\x0e\xd9\x9a\xacVvZ\x1f{\x8d\x8f\x98\xb3\x8e\xd6A\xb3*\xa2\xf6\x8d<\x89\xa5\x84H\xefX\x01G\x816M\x1d\x8en\x9a\x84K\xda\xac\xa9\xc9\xa9\xec\xe0\xc7\xa4,\xa3d\xf9$\xcd\xdd\xa0'g4\x183\xcdD\xd4>k3\xf8\x89\xb96PY\xf5'\xe4U\xd4\xaf %\xa7~\xf6\xae\xca\x89\xf9\xfa\x97R T\xaeT\x81\xca\x95*P\xb9R\x05*W\xaa`\x98+U\xe0\x16\x8d\x8e\x06jO\xe2\xe0\xe3\xfb?-l\xfd\x9f\xbe\x04\x98\x0b@\xfb\x00\xf38\n\xde}j\x87\x17k?$R[?4goevS\xc30\xcb\xe0\x1aU\xferma\xe2m\xfd8\xe2\x85\x1e\xfcu\xe1\x9e\xa4c\xf0\x91\x02UO\xbe'\x8b4'\xfcp\x12\x00\xa8\xb7\xe3\xb3\xe4\xa5 \x7f\xca|::7\xdd\xd1\x18\x12\x8f\xf0?4\xc7\x82\x18\xb4\xf6\x04\xce\xf0\xf4\xd5\x9c\xa3kn\xe1\xe8\xfb\xec\x02\x12*\x837\xda\xcb<\x0d7\xc1\xb0\xb8\xfe\xca\xdb\x8f\x8d\\\x92r\x80\x7f\x94\x19\xc9O\x04 \xae^\xf5\x1a\xeb\xf8\xdb?i,\xbf)\xf6y\xce\xa2\xabme\x93y\x99\x00G)\x10\xe1G\xfc\xd8f\xa9\xa6\xae\xdb\xb1\x8d\x19X\xee\xab\xb2\xc6H+\xa0I\xd3\xc9\xf8\xaat2\x1bU:\x99B\x95N&\xe6\x0f\xe4\x15\xd0Z\xb9c\xaeY\xc6\x98\xfeG\x84\x1e\xfa/\x0f\x1e<\x90 \xe9\"M\xcac\xa6\xcfv\xa2\xd2\x8f\xa3\xa0\x1b\xa2\xd3\xfa34\xd2'\x03\xe3\x00m\x1a!)\x83\xd6\xab\xbb\xa4\xf6\x93\xee\x94\x1fc\xc72\x03\xaf\x18\x02#\xff\xdb\xe9\xd1\x8e\xa5\x9b\xc0L\xb9`\x00\xf5\x82\x81\xfeEP\xb1\x08\xc62@\xc0\x19\x04:\xac\xb6\x17\xd1\xc8u\xc4\xd6V\xf9\x05C#\x94\x06\x9ae\xe1wVyC\x87\xd0\xf2\xfe\xeb\xe39\x01\xf46&C>\x06\x90\xb7yz\xaaI\xca\x00\x9c>\xff\xc0\xcb\xa9\xea\xe3\xe4\x8dI\x06@\xde\x85\xdd\x86;$\xd3\xc0\xd0.M\xf2\xf4l\xd7^\xed\xd2\\\x90\xc6\xfa\x05\xb8l\x92\x02\xd8\xb1\xddV6\x82\x8f\xdf<\xf3\x1a\x1a\x90\x05\xa1\xf4HR\xe6\x17\xb2\x12\xb9&\xdd\xb1\xf0\x01\xee\xc8?d\x0c\x07\x06\xbf%\x10\xee\xbb'\xfb\x9ax\x10q\xa1\x0b\xef\xc9\xd4\xa2\xda\xcf\x9e$\x1f\x83\x1b\x8d\xaa<\x81\xeaL\xd5\xe2\x12N\xbc\x91\xd7\xf1\x19\x7f;\x12N\xb4\x1dOr\xee=\x02\xb3\xc6S\xa3G\x89\xb86\xb2\xa6Z\x0e\xec\xfa\xee\x9a\xd8W\x8b\xbd\x0c\xe2HJ\xb5`\x97\xf0\x0f\x10\xd7P|\x06\xd6lz \x13\x94\xb8vl:\x92(\xa3?]o|^Fb\xa39H\x13\x9b\xf6)\x97\x80\xb6CGx\xcb\x991\x95\xbe\x83\xa6D\x83\x97\xa0\x80\xe5\xdcb\xa6\x1f\x94F\xfdX\xc3t\x93CHS\xbd\x83\x94c\xeb\x88?x\xcbP\x82\xba)\n\x85x\xf7\xba\x89B\x9fT\x83\x19\xc8\x04\x1e* \xb9\x81\x10xP\xdc\xf93\xa8/\x1b\xfc\xbeDK\xd9g\xf9m#5m$\x90k\xaa/\x19\"m0I\x83\x84Q\x99\xe6F\x0d#SF\x92<\xb7P\\2md\xec_\xa4\x9b\xd2\x02\xbf\xb3p\xb9#\xcc \x884\xdcH\x18\xe55\xf8\xf3\xd5\x07\x84\xcaL\x04\x82gv\x8a\x8c\x04\xe6\xe1\x84W9\x9c+\xeb<\xf3\x0b\x93#\xc8h\xa7tj\xb6\xfc\xfc\xa2\xcdL\xeb\x93\xa7C+\xcc\x19gA>\x05\x0c?u\xc7;\x9e\x95\xa5\xe1h\x14\xec}\xd9<\xa2\x94V\xea\x9d\xf6jo\x9f\xaa\x8f\x9f\xf7c,Mgh\x86\xe9\x90\xf4\xa7\x87\xd031\x7f\x1fVg\xaf\xe9+\xcd\x99\x0fx\x08+\xb7\x03\xc5\x1c\xc3\x1a\xae_\x02\x16Co\xc4\xcd\xcc/W\xf8\xbe\xb2\x1f\xc5\xda\x8f\xe3F-F\xbf\x84\xee\xeb\x0d\x7fW\xf5gt\xce\xebFw\xff\xb3UT\x92\xe3\xcc\x0f\x98k;\x99\xe0\n\xabw\x95U\x15Gi\xaa\x01>\xb05)\n\x7fI\xb4\x07\x8b\x16]\x8cC\xc2\x8a\xa0\x93\x90\x04)3\x91;3p\xb0\x12\x8aah\xc1&/\xd0\xdc\x94\xa5QR*\xb9\x1f\xd9\xd8\xb0\xb6\xb5\x8e\xe6i\xaa(W\x07\x7f\xe2\xcd\xa3$t\x19:\xe4R\xbb\xb6\xf3\xe3f\x9dA\x99\x02\x1d\n\xc5\x96\xbc\xd6U\x88\x1fm\xb24\xd4\x04\xb6\x13m\x91C\xe5\xbc\x8c\x8f\x92ZtwJ\x8e%h\x9fEE\xe9E\x05\xfd\x8f\xdb\xd9\x0c\xf6\x9bI\xb2\x97\xb8\x9f\xb0\xc7v\xd5%>\xc4\xd2\x804\xc8!\xfa\xe3&\xe8\xe5\x91c\xcc\xa4\xdd\xa7\xd3\xa4Z\xc6\xd6\xe7v\xde\x19\x9f\x90\x90Z\x13I\x0c\x0fB\xc4\xfd\xc8$\xcd~3\xff\x99 \xd5\x95\xd2\xa86\xd6Z\xd1\xab\xf6+\x06\xda%\xd3\xd6\xad\x94\xda:\x17\xd3k9\xce\x88W\xa4t\xc0\xb1\xb1\x1d \x11\xfcd\xff\xadW\xa6o\xe8va\xf5\x8a\xe0\x06\x10\xaf\x88\xa3\x80\xb8\xd3N\xc7\x04-\x81^\x1d10\xa7\xccm\xf2\xa4-\xa51\xfb\xc2\x17\xbd.\xbf,\xf5\xbaA\x95\xbb\xefO\xa3\xe1\xfd\xe2\xa0jQ\x01\xe9\x12>\x87\xe2\x13u\x12O\xdc\n\xd7\xd0\x93\xb0\xca\x92\xf58\n\x9f\xa7\x9bD\x16Td\xab$\xaf\x95\xe3\xcdl\x1fE\x95\xce\xa837\n\xf0*?R\x7f\xb2\xda\xf3!;J>`\xea/\xd2\x1bT\xfbN\x9d\xe6\xa9s\xbf*\x9d\xcf+)0\x9dH\x13G\xa4\xc3\xbf\xc4\xf8?\x81\xb9\xa39\x04\x93\xb5\xa3\xe2\"M\xa6\x0e\xec\xaeV%\xddv\xb3\xda\x89\x89\x82^\xc8&\x8edR^dD\xb0\xb7\xc8f\xba ?\xfe\xa5\x9f\xd1\xe9\x11\x0b4\xd6\xec\xd4\x03s\xcd\xf4\x9c\xf5J\xab\xf7\xd5\xc4\x85\xa9\x06SZp6\xe22\xe9fR\xe6C`\xa5\x953\xe8\xdb\xf8\xa05\x81\x9bR\x8fm\x80\xaeE}\xc7\xda\xe9z\xa5\xdbB\xcf\x98I\x12@\x8fzU\xa9\xf9\x08\x93^~\x93\xe6\x16cI\xb5co\x91\xa7\xeb\x1f\x8fG\xee\x89C\x0f\xb5(@.\xff\xe6\xafE\x9a8o\x1b\x9c\xe3\xf8\xday:\xd3\x1e\xbd\x10!\x06\xcf\xa2\xe4\x9d&5\xfcug\x10\x13\xf7\xb6* \xfdg\xc9\x18^\x05?\x98H\xf9\xc1\xa8\xe2\x07\x93\x11\xe3|\xf6\xbf\x86\x0d|\x03\xc9\xd7\xb0\xa1\xfc`t\xb2i\xf3\x83\x1b ?(\xf8\xcd\x0f\xc5\x08F#M\x12i\xcc\xb2\xf8\xda_\xa2\x05\x17u1\xa7\x8d\x1bLx\xa5\xccn\xa1X,\xb8B\xe6\xad\xd9\xb2\xc5i\xaf3:5\x98\xb1\x96\xc7\x003\xfd)\xf2F\xb7\x87\xa8\xe6G\xe87^d\xd7\xb9\x87\x9f\x80c\x1a\x14\xadf\xed\xf4\x91\x0fq\xfaH\x07\xa4\xcad eK\x7f\xb9$aE\xb8\x0b]\xc6G\xcc\\lv 11\x0f\xf6\x8aB;\xee*\xdd\x92|\x1b\x913S\x8d\xc1\x17\x1c\xceA\xa1p\xb0\xf56\xad\xad\xb7U(\x9d6\xaa\x1e\xf8$\x9f4z\xe8/\x0bg\x0c\xa5\xc1Y\x98y\xcf\x08\xa7\x92\x08\x1dI\x8c\xb6\xe2\x9dye\xa86M\xd5OT\xc2*_\xb8\x84\x9f\x05\xec\xe4\xb6\x00\xf5(sF\x1d\xe8\x9cl\xd4\xee\n\x00=;F\xf7jbPL\xd9\x95\xe6\"\xe9}\xd3\x85\xef\xaa3A\xa7\x87\x1b\x0e\xf3\xa2S\xcd\x89o\x9a\x90\xda\xef\xc1\xe0\x93j\xf4}\x00\xd6\xc3t\x00\xab\x0f-\x0bN\x992\x86PG\x06\xc4U\xa7\xeb7\xc32b\xb36d\xb0\x15\x17\xf33\x8b, \xe9N1$G\x05\xce\xde%\x0d/\xad\xc6\x06\x1e\xc3\xc6\xd29}g_\x0b\x10\x1b\xcc\xa2\xa7\xc6\xf8[q\x898\\C\nSzE\xe1\x0c\xd2*\x19\x93\xc5\x0bt\x8b%Z/\x9c&\xe4\x8b\xec\xa9\x19u\x9b\xc0/s\xb2\x88\xce\xb1\xb0]\xbd\x0c\xc6\xb7W9Y\xcc\xc0\xf9K\xf5\x12\x8e\xc6\xa2\xd9\x8a\xde0\xda\xa1'\x1a\xb6\xfe\xdbR\xb0&\x08&\xca\x8f\xfeM\xe0\x1bVUDM1o5\x0c\xfa?\xa5u\x9cv\x01L*\x0b!J01\xc9\x1eHm&\xad;\x03\xe5[\x83SI_\xa4\xb3\x12D\xa4\x04\xc7Z\xe4\x10\xd2\xc6\xae^\xc9\xcd\xfa1\x1a\xbe?i$.H\xbcS\xfe\x077VQ!\xb0=\xaf\xff%\xf9\xc4\xe5\xf9}\xde\xea\xc7\xe5S\xf964\xb1\xa8\xed\xed*'\x91\xcc\xc3\x98\x8fb\xe4\x9e$\xc8\xdc\xc0\x1e{[V\xe4\xbf=\xab\xd7\x8a\x81\xd7\x1d8I#\xd7\x83\x89Y\xc7\xa1\x9b\x98tJ\xcev\xe2\x9fc\x8fnE\xdd\x99\xc3(\xa5\xe6\x0c1\x9a\x99\x81\x87J\xffB\xa2\xe5\xaa\x9cAN\xb9\x9dy\x1a\xb3,\xa4I\x9a\xaf}m\xfc\x9ez\xec\xb2\xe4\x00j\xf0\x96wl\x9c\x06\xef\xaad\x04\x94e\x1b\xee\x05l%z\x08\x9f\x0b;\xe9\x83\xce\xca$\xf6\xe7$\xc6\xf3HQ#|\x0cI\xdbT\xbc\xb3/\x03(\xdbW'\x1f\xb4\xb0=\xd8\x1c\x1b\xff\x05\xd7B\xcb\xf84Y\xa4o\xf2\x18\x8f'\xfa\xfb{\xbf /\xfdr\xa5Q8JS+\xa4\xaa\xd4\n\x91*\xb5\x82\xafJ\xad\xb0Q\xa5V(T\xa9\x15\xe2Vj\x05\xb4C\xb7\x01\xea\xdc\x0b\xdcR=\xdd\xbf\x16\xa9\x17zsn\xc5\x11h\xdc(\xbeD%5\xe1\x86\x9eY\xab\xb4\xd0\xe8x\xd8\xa95\xe7\x8b\xb5\xd3q3(\x16\x84\xb64\xd9\xe4jR\xe4\x9c\x00E\x1dx\xf3\xea\x19\x96\xc1-\xd1g\xc1\x81\xb7\xbb$\x80\xd11\xb6vn\xd1\x06\x0c\x85O\x8c\xa5\xd0\x9b\x05\xb8\x12l\x053\xc6\xc2\x00\xac\x85\x81\x98\x0b\x15\xf6\x86~i\x90\x89\x93\x01\x1aM\x00h:\x9e\xf3\x94\x9c\x7f\xfc\x01N\xb9\"\x10\x92-\x89\xe9\xc9c\x905\xd3\xfa\x0b\x14\x93-\x14|\x1c\x9a\xac\xfd\xc8\x08\xefc\xf2<\x87\xb2p\x16\xf1\x1fV\x8cL\xaa\x15/mX\x1e\xa3\x86\x8aq\x94.\x96\xf5*\xfc$*\xa3\x7f\x937y\x99%r\x90\xfb\xbb\x9d8\xc5\x14\x9e\x945\xd4\xb1\xf3L\xb5\xb9\xc9c\x1d\x10\xb3\xd3\x08\xee\xc4\xe4\xe5^\xa2\x0c\xa9\x83bR[S\xca\xd3A\xc7\xcc\xea\x83L\xee\x15x\xcdc\xee\x98\xbc\xcaV\xa8\xa6\xe1\xb1\x8e\x86\xd3\xdeh\xf99\xe4\x984\x829c\x085\x06\xbc\x9a\x19\xd4\x9cZ\xcd9\xd4\xba\x91\xb6\xcfA\x85\xa3\x8d\xfa\xa4\xb8\x949\xb9y8\xb0\xda\xfe\xd7\xedp(T\x87C\xa1:\x1c\n\xd5\xe1P\xa8\x0e\x87\x82\x1d\x0e2\x92_||\x92\xaf\xd7\xa0\x7f!\xf9\xe2\xb2%\xf9\xc2/v\x97 Z\xc6\x1cXo\xa1\xf8Zn\xa1\xeb\xc1_\xf5\xf7\xd6\x17v\xea\xcf\xb2\xb7v\xd6/4u\x0b\x8b4Ugp\xfa\x8f;\xf7\xae\xc7\xa6\x157\xffDB\xd1\x97\x94B\xda\x94BO0\x9f9K\xff`4\xe5\x03\x9fO\x1ed\xd7\xc8 $\x17\x06\"i\\\xf4&\x0b\xfd\x92\xb0\x86e\xc6\xdbO\x9e{\xe8\xd2d\xf2\x03K\x9d\x83\x82\xae\xa5\x96\xfdG\xa9\xd6\x90B\xe9\x8e\x13\xa7~\x18%K\x96\xd5\xb8\xf4\xf8\x9f\xc7\xa5_n\xb4B\"\xc5[g\xe1G1 \x07\xbf\x8bn\x85^\xb0\xc9s\x92\x94\x1cC\x0c\xd2\xeb\xef\xef\xb5\x82(\xba\xde\xb9\x1b\x0f\x0b\xea\xd1\x9e\xe5$tF\xdc\xdb\xb0y\xff/\xbe\xefk\xb3\xa07%W\xfa/\x8e\x0dmw{S\xfe\xbb\xaa\x1a\x7f5\x07$\x8e\x1f\xebU\xfaQ\xb2CN\xfa|XK rf\xaa'|\x9d\xce\xa3\x98\xcc`z0\xb4/N\x94d\x1b\xfbTCut$\x9f\x05\xfe\xba\xf2\xe5,\xf6\x03\xb2J\xe3\x90\xe43p\x18\xea\xc0\xfc\x02J\x7f\xa9y\xab\xbc\xc8\xd0\xbeE\xceu\xdf\xee%*j\x12M\xf5k\xd5\xc1_c\x8aS\xe6\x1b\xe2T\xd8\xe28\xa0U<\x84U\x81qs\x14\x94\xdcn\xf6\x81\x13x_O^*S\xf1R\x99\x8a\x97\xcaT\xbcT\xa6\xe2\xa5\xb2a%\xc53\xca\x15\xb4\xeeb`L\xa6\x89\x9cY\xe0\xc7\xa6\xfbR.,\xfb\xf8\\X\x08\x87\xf0\x84\xb7\xef!\xebAwO\xbb\xcf\xfa@\x1a\xe8\x84\xd7v\xf0\xa4yYse\xc0{\xa7\xe6\x96\xec8%\x11iK\xfb\xa4Wmn\x19|\xc4B\xa3K\xbf$\xd2\n\xae\xe2\x8a\x8a\xa30*\xbfO\xcfg\xb075\x12\x0bGI\xe4#\xc3.\x86+a\x80`P\x02F\x18\xc0\x13\x81H\x95\xc3\xd8?\xacq]4\xa7\xbef\x96\xac\xcdc\xaa\xd3dx\xb6E\x90\x8cD\x9boB;\x14U\xa2\xb7\xa1#\xf8d\xfel\x8c\xcf\x14\xe7\xde\xa34)6k]\xfeD\xa8\x9c\xd62?\xf7\xd7z@\xe6\xb5\x16\x15\xbcf\xb6\x1e8\x1a\xc2\x1eC\xe5\xb7\x96\xf9\xe5\xea\xb9E\x9a\x8e\xcd\x003\x0ep\n\xbfq\x9d\xefYE\x1c\x0dk\n\x9c\x82o\\\xe759/\xbf\xcb\x89o\x02\xcf\x18\xf8*Z\xae\xe2h\xb9*\x1f\xa5\xa1\xd1\x81,d\xef4R\xf0\x99\xde@\xef\xed\x08\x8bg\xe2Z\x91\x92\xe4\xbfD8[\xfe\xf7\x17OC\x92\x94Qy\xe1\xfa\xdc\xe7<\x1fyu\xd9\x94\xc2\x19s\xd3\xf7\xb3\xa8(Gn\xf7\xc8\xea^[,\xa7\xd9\xe8\x1c\xdb*\xae\xcf?\x9a\x93\xdf6\xa4(\x1f\xd9\xf7~\xddBb\xfai\xc4\xccN*Wq[\xf8,\xc8\xde\x98\xd5\x8c\x0c%\n\xd5\x03}\xfbK\xd1>\x12~=\xec\x05\x1c\xc2\x92\x89\xc7z\xc09\x02V\x07\x85\xd1[\xed\xca\xaa6\xcf\xd3\xf0b\x82X`\xf0zpB\xbf\xf4\x19\xe4\x04c6f\x907#8\xec\xdf\x8e\x92\xfa\xdd(\xd1\xd5\xfc\x1a\xc3\x9c.k\xaa\xa9\xae\xb9\xd8m\xb0\xa7\xa7\xc8\xf0\xc3\x0dpW\x0d\xeb\xa3\x03Q\xb2\xf5\xe3\x88e\x070\x0d\x8a\x93\xdf\x0b\x03\xadk\x8b\x0e+? c\xf2\x82\xdfT\x8f\x9d\xee\xbc\x0b:z\xd5\xc8\x8d\xce@\xaa\x91\x13\xab\n\xa3bp\x9a\x1ej\xca\xae\xee\x8e\x86\x13\x96\x91U_P[\x87\x11\x97i\x9b\x84Q\xa9mX\xd5h1\xa0\xc19\xa6\xa0(\x13\x08\xfc$ 1H\xd6\x86u\x04D%\xb50*\xd5PF\xeck\xa4\xa9(\xd3\xe52&O\x05\x99\xd1\xef\xbc\x87\xe0<\xc2\x1ebG\xe8+u\xd5\x02\xcd\xd2\xb3\x0c\x0e\xa6\xf9X\x95\xeb\xf8 \xd6q\xd8i\xbe\xdb\xf1N\xceKq\x8c\x89L\xb4\xc0\xca\x92\xa9?`\xf4U\xe3\xf8\xbf\xd5Oo;\xf1\xad\x89\xeb\xa9(\x81\xc1\xf9Z\x81\x9d\xad\xe4\xcb\x9a}\xa9L\xea\xd4\xbb\xab\xf0.k\xc7\x9c\xd4\x87\xd1\xaay\\\xf6D\x1eq|\n\xdf8m\x02\xe0\xf6\x04\xe0\xf8\xba\xef\xfd\xfe\xbe+\xbfW\xf3\x17\xca\x1f<\xaaz\x10V\xcf\xdf\xb7\x95\x03\xdb\xa6x\xda\xe5\x97\x9b\x98y\x05\x89\xd9\xfdY\xcdLDU\xde\x10T/\xa5B\xbd\xa4\xd0\x1cQ6\xf9\xe6\xf9:\xbe\x19y%)J*\xceJ\xe1(\x83\x8c\xcbf\x02D\xab\x08<\x84\x84\xc7\x80\xd0\x9e\x9e\x9e\xafYu\xb0\xe6M\x99\xe7P\xb4\x00\x97w~\xef\xf0\x10\n\x9db=\x86C\xd8C\x8e\x0f\x93\x17\xfe\xfe\x9e\x8e\xb2\x903M\xc4+HyLY5W'\x1c\xe1fW\xd4\xb0\x1e\x8d\x9b9\xf1\xf5\x9eH\xc5?\xd7\xb1V\xa1\xd7P\x06(\x12\x9cK\x94u@\xe2\x82\xe0\xdc\xb6\x92\xf3\x17x\x0c\xb8\x0e\xce\xb1\xaa[\xfa.i\xbb\x83L\x88\xacEMc\xda\xcf\xb5)\x0d\x17\xf8\xd97\xad7\x14\xd1I\xafXvK\xb7\xe3R\xae$J\xbcE\xe2E\xc9\x82\xe4\xc7X\xe2\x7f\xe4\xe6<\xdaF\x9dg\x8d\xbe\xb7\xa0h|\x8c=\x16/\xa6\xa8\xefT\xcc\x07+\xb0\xf0K\x1e\x95\xe4E\x12_H\xf3]*\xe6EL{kf\x14\n3\xa1\xf7Lj\x19B=~\n\xf4\xcf\xb5\xa44\x99q\xaf\xf0}\xa2\x90\x90\x0d\x8bOw\xd1i]bc\x0c\xa9|\xdc\xa7C\x06\xee\x92N\xed\x0e\xf8\xe3\x0f\x08G\x0c^\xfa\xf96\x03>\x14\xedl\xe8p\xde%\x98\x89\x82`\xa6\x1d\n\xac\x82\xa3\x84=\xa7Bl\xcb\xe0\xea\x95y\xb4vYA6\xbd!\xb6\xb1\x85\x95ek9\x99\xe8\xc7\xba(\xb0\xb3\xc3J\xea\x8eUh\xa8\xa6k\x0c3+\xd9\xf8;v\x8aURc\xbe\x14^\xc2\xfc\xa8\x0c\xc9\xef\xe5\x96\x8e\xeb\xe9J\x7f\xdd+\x10\xd0\x1f\x0f\xee\xdf\x1a\xfd9\x8a\x10\xfc\xf9\x1c\xc2\x189|\x92\x06\x9bK\x96 \xe2$\x88\x15\x94\xa1\x1cB\x98\x068\x0e\x8f\x9c\x93\xe0Q\xba^\xfbI\xe8:A\x9a]\x98Sd\xc9\xa8\xd4\x07\xf3\xcc\xf0\xb8\x12R\xcd\xb4\x95\x9ck\x88\xeb9%W\xe0\xfd\xae\x0e\xce\xac\x8bK:\x8fX\xee&\xd3\x17\xd5T\xb2]\xbf'\xa3\xd2dQ\xaa\xb3\xcb+\xdb)\xc9y\xe9\xe7D](\x11P\x14CTj)\xbb\xf0\x8ezrs\xe2\x87\x8c7b\xb6q5dk$tZ\xd4\xa0V\x89A[\xc52/\x91\x0bT\xb0E\xf2)\xfd\xa0\xe6\xf7\xebP0\xa7\x7f(m\xe8\xa14\x95\x9dJ\xf4\xc9\xf4\xbe\xecX\xa2O\x1eLUqlj\n$\xbc\xd1N$\xa5\x08(\xe3&\xab?U\xd9|\\gE\xfc\x90\xe4EW$\xa5\xe2h\xe9e\x9bb\xe52T\xc3\x84\x9d\xec\xef\xc9?\x9d\xb1x\x9d\xe5\xd1\xc5\x18N\xfe\xf8o\xce\xdf\xb0zf\x9d\xa1\x08n\xc0\xdf\x9c\xbf\x8dx|\xf4\x06M\x12*V\x93\x9e\xaa{\xfbrTC\xb1Wa@\x0e$9C\xc5U\xe6\x17\x8a\x8dP94.\xc6h{\xea\x9c\x1b\xdd)\xf2HR\xe6\x11)\xa8\x90\x04{.\x16\xba\xa1\xc7i\xe6%\xe4\xbctG#/L\x132\xfa\x9a\x8f\xc2d\x8e\xc4L`6\xd6\x91\x15\xefZ\xe3\xc8\x0d\xc7p`R\xcfS\x9e\xedd\xdfP\xa1b\x8dPS\x89#\xa6\xb8(\x12\xad\x1b\xab\xff\x038\xdd\xd5\xde\xc2\x0dpf\x98?m\xcdW[N\x0b\xfa\x84\x00\x02\xbf\x0cV\xa0>Yc\x86\x11\xb8\xc2}{\xc1{XD\x89\x1f\xc7\xaa\x15V\xaf=\xbd\x98\x12%\xf3\xf8\xa1\xd5\xf8\xed*\x06`h\x0e\xf8\xd6\x89GP\xae\xf2\xf4\x8c\xbb\x07u/\xc9<\xfc\x97\xfa/\xfaA\x8e\x8a\xf34\xbc\x90\xa5\xd6\xa1 \xcez\x13\x97Q\xe6\xe7\xe5\xcdE\x9a\xaf'\xa1_\xfa\xcc\xd1\nG\xe6\xbc|q\xfc\x9a\xfd\xdd\xdd\xbb\x1aNa\xa9\xd9\x8f\xc0-|:\xa7\x8e\xb9f_\x82q}\xaa\xfdy:\xc6\x8c\x1c\xf2\xfd\xc9&\x057\xe7\xc51\xf9\x8d\xefN\xdas\xf7\x14\x0e\xe1\xac\xbb;\x97\xc6\xdd |\xf4G\xfd\x8dw\xca7\xacq\xfb\x01\xcf\xf5qd\xdc\x82\xc0\xb7\xe1\x91v\x1b\x02\x9e\x08|\x0f>q0h>J\x8a\xd2O\x02\x92.j\xae\xdb{\x12\xa1\xb0\xd0\xda\xa0\xe7t\x83\x1e\xfe\xffq\x83z\x89\xbf&\xf4\xef\xaf\xcb\x8b\x8c\x1c\xb2{\xf4'\xdf\xb9(P\xf7\xde5\xeem\x90\xe25X\xedq\x10\x98\xb4?F\x8c\x91\xdb\x05m6\x9f\x1e\x9f\xe8\xb5\x87\xc1\xfcg\x8d=\x7f\xa6\xdf\xf3`\xd94\xf0}x!\xf6\xfe|\xe8\xabe\x0f\x1b\x94\xb7#E\xb5 \x84\x97\x13t\x07uo\xfe\xeb_\xc9\xcd\xe5\x18\x1c\xa7\xab\xd8\xe3\xe3/e\xe5\xac\xdb\x1c\x8d\xcf\xb9\x93[\x8aJz\x9b\x8f'\xc4^7F\xefK\xcc\xca\x97\x98\x95O\x11\xb32 Z%B\x95c\xb0\"k\xab\x9a\xd7\x0dp\xab\xcf\x0b\xf1#29\xd5 c\xa0.K\x1b\xb3\x072\xbeD\xc1/\xa0#\\U_\xb0\x1e\x19\xe2J~\x0dCiZ>\x98\x97\xad\xe3-Q\xde\x148\x01\n\xeb\x1f305\xd6\xff\x9aV\xf0n\xba\xa7\xb1\xd0\x17\x8e\x82H\x9b\xf8\x10\xebr\xdd*p\xcc\xa3\xdb\x1b\xb3x\xfd\xf2c\xff\x00\xca7\xbd\xd2\xad\xea\xbc~_\x91\xf64\xec\xa6\x993;\xae\xd4N+\xbcW\xc3\x95h\xc6\x94\xa3M\x1d\x17o\xc5T\x0e\xf2\x98wF[\x89\xc5\\\xe7[Q\x8c\xdb\xa8\xf6R\x16\x8a\xe1d\x16E\x92\x01u\xfcL\xebdY\xb2\x9b\xf7\xce\xa0Z`\x85\xbd\x95 \xb6%\xbbM[jw\x05\xdf\xf5\x8c\xaf\xf9\xc2\xf7} \xbe\xef\xcfg`\xfa\x14gF\xcd\"\x99\xce\x0d\xcb\xb0\x82|@\x90\x00s\xb1\xa8\xc2\x17\xf91\xac\xd1\x96D\xf8\x02'\xf6\xe6\xd8\xd8\x82\x04\x9b<*/\x1e\xd3}\x1d\x95\xa6Z\xc7t+\xe5\xc6x\xdf\x98A\xf9\x9br\x95\xe6\xd1\xbf\xc9\xf7%\xa5\xb0{\xdd@\xb6\xe6\x15\xb0W\xc4Qx\x05\xf60\x8c\xd4\xe5\xc5&\xff\xf8\x03\xfd\x9d\xae\xc4\xea\xc5\xbax\x890\xda\xcd\xb0\x96\x8a+\x89\xa3m\xce\x86z\"\x02m\xd7\x9a\\\x91>\x84\x94u\\\x9b\xdf\xaa\xb1\xad\xd4\xc6\xae\xcaAX\xb7z<~\xbaJq\xf5\x1f\x9b\xeb\xea\x93zo\xc8\xe3T\x03\xb7ht4P\x1f\xad\xd7\xd9wC\x15Xj\xad6\xd9~\xf8\x80\xd2\x88\xfbP\x89*\xf4\xa1\xc9\x87\n\x1a\xf94\xd2\xe45\xbe\xcchD\xfb\x9e+n\xac\xd3\x90\xc4\x942\x8da\x8f\x07\xaaz\xe4<\xf3\x93\x90\x84#\xa1\xea0\xb8\xc6\n\xf8Y\xff\x13\n\n\xd0\xdf\xc3\xf2\xe9\xdd\x98\xb4&\x18iW\xb5&\x87\x89\x11&\x10S\xc8\xe3\xc8\x94\x1a*S\xb8n=ZE\x9f\xba-\xcd F\x99[\xac\xfeK\xee$\xd8\x86\xeaOI7\x9a\xf7\xc3\xf0^6\x11\xbc\x1f\x8e\x0d[E!9&\xf1\xe2Er\x84\xd3j\xe2\xc5\xf4+\x0d\x15\x1bV\xa1\xb5B\xe7C\xf7D\xd2\x89\x07\xac\xf6F\xdes\x0c\x85!\x1a\x90\x0f\xad\xfd\x11s\x80N\xf0\xf5\x94T\xa3\x19\xb4cw\xd8\xaa\xb6\xf3\xf0 \xb8z\xd4\x82\x98p\x08\x991\x956P\x98|\xaa\xe8\xcd\xfe\xfc\xb2U\xe8b\xae.\xdcl\x88F'\xc1\x0c \xea\xf2\xb6\x0d\xb5\xde*\x8a\xc3\x9c$\x943\xfa(M\xebB\x0d\xcd\x0d\xc9\xc2\xcc\xaasM\xc3Q\xdaxi\x05\x9b\xbc@\xa5[\x96F\x892_\x1c\xf4\xb0\xb7\xba\xcb$\xe7?\xed\xe0v\x1fX\xab\x92\x04%\xaa\x1368\x8c\x8b\x95\xed\x12\x1eP\xe4\xd4\xc7\xa0\"|\x17S\xf6\xcb\xbf Ar\x985a\xbb\x87\xa7\x91J\xf5\x85\x02\x990\xb0h\x1d\xd1\x92\xe8\xb5\xee\xc1\xee\xfc\xeey\xde\xfb\x0e\x89k\xb0C\x1d\xaf\x0f$O\\\xf8i=\x10GO\x9b(v\xdc \xbb\x14\x87~\xbf\x1e\xd2\xf83\xf0\xf9\xbb\x96*\xc11\xfb\xa10\xdc_g\xe5\xe0\xe7!\xc1\xf8A\x19m\xc9k\x7f>\xc8VZ\x99aC\xbf\xf4\x0bR\xa2G\x8e\xfc\xc8\xb6\x92Q\xaa^\xa8\xd5\x12\xbd\xdb\x97\x13JP\x13\x98,\xa2\xa5\x02\x8a\x89%\x86\xc0\xce\x00\x13QW\xb9\x86\x9fS\n\xfc\n\xf9\xaa(Y*E\x18G\xc4\xef#\x8b\x18\xa0k\x1b\x12\xef\xc6\x0d\x97~\xba\x02\xb4HS\xd4\x98\xc1\x98R\xf9\xaa\x8d\x99\xc4\x83\xefc\x0b/W\xc9j7\xb2\xce\xb0-^\xffIg\xafq8\xb5\xe0ly\xef\xc6XG\xee\xc4\xd1\x90\xefG%Y#\x9fY\xd3\x9a\xc3\xc3ff\x9d\xc6\xd9\xf2\x10\x1c\xbe\xb3x^\x96\xc1}\xd3\x07\xadt\xba\x16G\xc9;U\x860\xa8\x92\xd9\xf0$8\x8e9\x9dJ[~\xa8\x86\xa5\x1aDD\xc7{\x14F%`\x8c)\xcb\xbe\xc1\x1a\xe1wX\x154\x8dqd\xd7\xa5\xe0\xe7\xc8\xf5Z\x08\xda\xb3\x88'\xe7i5n\xbbBlTW\xb6>l\xc7\xd6\xb9P\xcc\xb1Y<\x92\xcb\x8c\xe8_}\x05\xe9\x18\x8c\xcb\xa0\xa9\x84\xa65\x071b\xab\xad\x94\xd2.M\xa2\xa1\xf55 \xd5\xa6;h\x1d\x06\xda\xc4'\xa4\xa6\x993\xd0\x14\xb3\x14\x14Y\x97\xef\xb4\xf7\xc0(1~\xdef\xa4\x05\x15\xb1z\x12S\xca\x9f\xf4\xa4\xb2H\xbc\"\x13\xbe\x162\xa9l\xc3\x1f\xf4\xda(\xf8\x83\x9eT\x16K\x0dL(\xfe\xb8qS,W\x1b\x98\x16\x1f_<\xcbl\xc53\xbd\xcfn>\x06\xbf\x7f\x92wy\xdfk\xe3\xb3+\x92\x84ozb\xa2\xc2g7\xed\x8b\x8az\x9f\xdd\xbc6X\x1d\xb6\xb7\x8e\x8aG\xcde\x89\xe3\x01\xabE\xc92\xca\x17\xab\xf4\xcc=a\x94\xb3p\xc6@\xde\xd2o\xf7\xe9\xc0\x989Q\x8c\xbb\xe3\xa5+f\xe9\x0dSH\x85\x1a\xdfN\xa8\xb9\xe6\xbc\xbb\x0dc\x9c6\xf8V\xdd!\x1c\x19B\x9f\x9a\xda\xf8\xe6\x92V\xc7\x05J\xb2Q\xdb\xdb\xb7\x03\xe2E\xc5\xf1*=K\x9aK\xdf\x80\xa6\x1c\xc0[\xccB\xa0?\xa0\xed8\x12\xa6\"\x9d\xa7\xe7J\xdeX\xd5L:\xeejX~o\xa9\xfbu=h\x1e\xb4\xc6\xe3\x93\x84Z\x0f\x8e\x90\x9d\xae\x9ax\xb5ZYY2'P\xf6\xa7\xa9]~l\x97]C\x16\xde\xa7T\xa3\x9f\xf5\x06v<\xabc\xe3\x19\x9d\xe1]\xc3\x19\xed\xea\x1e\x82\xf2\x10\x07\xbe\xad\xd0^\xe2\xf06)g\n%\xc6\x9c\x89^\xcc\xa0c\x84\x16G5\xe7\x02\xfc\xa2\x88\x96h\x931\xeb,\xaa\xe3\x806<\xfd\x1aJ\xf8\xa6w*|\x0d%\xa5\xfcj4\xda\xf2<6\xf5\xa1Pj\x82\xed\xaa&s:\xb4d$\xba]%\xfd\xf6V~\xf1\xe2,\x11l\x0c\xd3\x16b\x04\x02\xeeZr\x92\xd3\x13(9\xc9\xdf\xdaF\xc2B\xe3x\xef\xe3D\x1f\x01S\x1bw\x89\xea\xc4&\xda\xc3\x06\x9aCN\xd8\x81\x9a\xc07PV\xb3\x9b\xe8g\x17\x1a+\\\x9e$\x860\xc6\xdc#\xc9fMr\x7f\x8e\xe7a\xebO,&1\xc6\x9a\x88t\xd3o\x04\xd0\xde\xfe\x18x\xf64\xba$X8\xd1\xcd\xbd\xb3<*+\x88\xd1X\xc1d\x12\xfa\xc1w\xe4B\x1a!\".\xdb\xa0<\xa8\x17\xaa\x9a\xff\x92\x87\x9fh\xa6\xa8\xe27(\xeb\xe66P\x89\xee=^ \x12\xd3B\xe5\xbd\x9c\x84\xe2\xea\xf7\xe5\xbd;\xeao\xb3\xc8\xa8\x8c\xae\xd0\"2\xd5\xb9\xb2\xe2U\x80G>\xee\xb9\xa4\x19\x92Z\x8eD$dB\xce\xe0\xf5EF\x8e\xf2<\xcd]\xe7\x91\x9f$i t\xcf\x80\xcf\x8e\x18\xf0\x0b\xf0\xab\xd6T\x825g\xcbT \xf8\xa014c\x87At\x9a4{\xf9\x8a,HN\x92@t\x956\x08+\xbfH\xfeV\xc2\x9c\x90\x04\xd0\xe5\xd4\x8f\xa3\x82\x840\x81b\x93\x91\xdc\x1d\xb5 \xe8\xb0H\xa8+\xb9\x0f\xf5\xfc\xee\x95h\x97N\x11m\x1d\xd8;\xc4\xcc\x9dt\xf2\x90\xc0V\x13\xd2z\xc2\x98}9\x8e@c\x9e\xdc\xa8\xcd\xba\xf2\xcd\xb1$\xe5K\x81|/\x16nd\xe9\x1e\x0dR\x0c\x1c\x82'\x18\xa5.\x1f\xd2W_\xb1\xc21\xa8\x84V\xa0\xcd1\x9dlz\xe0\xe6\xa4((\xf6\xae7E $*W$\x879a\x1fH\xf3\x06\x1e\x8d\x81\xe2\x99\x037\xaa\x86\x14\xabB\xea\xedX\x9fQ\x8c\x87q\xb1s\xad\xfd\xaaa\x97\xd2\xa4(\xf3\x0d\xe5\xcdL\x96o\xbb\xf8\x8c\x9a2\xea\x8b'\xd0K\xd0\xc2\x996b\x1fX7+\xda*M\xc9'.\x05M\x1cq\x87 \x97\xcfT\xd1\xc2(x\x08\xd2\xfb\x1c7f(\xb9\n\xb4<\x94\x8a)n4\x86\xa62b\x0c)\xbd\xa5-\xd7P\xac\xd2M\x1cV\xef\xbc\xc1l\xa5\x96\x95\x03\xb4\x019\x82\xf5\xc0\xed\xa1\x9d\xd7T\"\xaf\xc2\xb70\xa5s\xd5H\xeeY\xf3 \xd3\xb7\xf0\xb0\xfd\xe7\xacg\x1a\xef^Q+\x01;\xdd\xd7\xaa\x02P\xd0\xa03\xcc\x9f\x81\xa5p}\x910\x1f\x80\x9a$\xbc#\x17\x85\x9b#WNZu(F#\x8flI~Q\xb3\x8b\xdaC\xae\xd1b\xe2E\x05\xf2Ac\xb6y\xb2B\xc9\x0c\x01\xe2\x14\x1e\xfd\xedn\xa2\xb9I\xd1\xcf\x94\x9e\x03\xfd\xeeiW\x12:\xddKO\xa8\x9c\x1c\x9d\x10m\xc7\xe4{\xa0\x8f\xb4\x94S\xef\x18\x06\xbb\xc73\xf1\x9e\xae\xd7\x1b\xdc\xa5\xad$\xc3p\x08\xd1\x18H\x83\x89\x8f4\xbc\x8cNa\x06R\xa5\x19\xb4\x07\xf2\x9e%\x88t\xf7E\xdd\x1d|r\xdd\xb4z\xa14WR\xca\x9f\xdc\xef)\xe9\"\xfe\xa4\xa7\xef\xf3\xf9\x83\x9e\xbeo\xc3\x1f\xf4>U\xf0\x07=}_\xcc\x1f\xf4\xf4}\x81T\xdf\xb7@\xf0\xa0s7\xe3\x1f\xb9\xd7t*\x08\xd5\x8a\xc0\xf0\xe3+\x02\xf5e\x8c\x86(\x02\x15\xc1\xfb=\x97\x0c\xad\"0\x96*\x02\x83J\x11\x18\x8f\xc68\xd7\xfb_\xc3\x02\xbe\x81\xf8kXP\x81%8Y\xb4\x15\x81\x0b;E`a\xab\x08\x8c\xec\x15\x81\x01W\x04.yd\xb2\xff=\xaf\xa9n#\xc7\xf1>\n\xdd_\xcb\xaa\xe0E\xc5\x8b\xef\x8eoa\x01\x87\x93\xdak\xa0p\xc6<\x1e\xc7/\x1cz\xae\x9c8a\x1d1\xe5\xbc\xed\xb5\xf3\x9e\xf7\xeeQ\xc7\x13l@\xff\x1c\xe8\xab\x86\xf0\xb3,\x11\xde\x15h@\x15\x8aN\xce\x8f4\xe7G\xbc\xc0\x93\x1b\xbe\"E\x1aoIx\xbc\x99\x979!\xeeI\xb50\x1d\x85\xaed\x85\\\xbar\xf4\x900\xa5\x17(Z\nU\xdb\xf4\x02\xb1T\xa1\xba\xf9\x04\nU\xbd*\xd5F\xe5\xca\xb2\x1d:\xfaa3<\xcf\xfd\x80\xa0\x8d\x18\xb8#\xb9\xaa=F\xb8,\xa9\x90\x1dE\xb4\xebb\x94$$\x9f\x18z\xa7l\n\x1d&\xad\xdb\xda\x0d\xe1\x9c\x12k' z}\xa4\x99#\xa7\xcc\xb5\x9d\xb1\xcb|\x96\xc6\x98\xf8\xec/w\xef\xde5h\\\x17iR\x1e\xb3o:Q\xe9\xc7Q\xb0C\x9a4\xf5`\xc2\xfa\x90jp\x893GG\x99\x1a/\xa9`^h\xa7(\xdd\xe4\x01\x99\xc1\x91\xbc\xbb\xa3Q\x8d\x80\xe7\x94H\x9f\x8b<\xd0\xe7J\xc3\xb4\x95\x0fw\xc7i\xcf\xa2\x8e\x1b\x0bi2\xd9\xae\xd1=\xe9dj\x80\xa2\xf2\xe4\xa9\x8b\xa7\x8e/\xd8\xf2,'\x81_\xea\x99X\xe0\x02\xe6\nm\xa9^T\xa0I\xf5\x1d~\xe8\x9d\xc7\xad&\x85\x9b\x1b>\x91)\xf3\x1f5\xaf-\xe5\xdc\x03?\xfe.\x8e\x96\xc9\x0c\x9c2\xcd\x0c\xf8I\xaf\x8cr\xff\xc9\xf2\x15\xf7\x9c\xd8\xf7\x0e\xc8\xda\xc03\x1amQ,\x026\xf3(\xfe\xff\x82>\x19p\x08\xce<\x8dC=n\xeaw'\x08\xad\x84&\x0d\x04\xb4I\xca\x86G;Vk\xa5\xde~\xa6=\xa3\xef\x17\xa7\x1c\x99\xee\xfb9\xe7dv'\xcc`K\xa3\xa0A\xa7r\xdd\xb0AIy\x80\x1f<\x7f\xd7s:\xf6sc\xee\xb1\x0c\x81w\xef\xb9\xaa\xcb/\xc7\xddT\x00\x16(\xc7\x03\xbd\xd0V\x99\xc0\x0dp\xf0WN\x7f\x9d\xd2_\xbe\xae'F7\x07!\x0f\x1b-\xf1m\xbf\x00\x83\xd5\xab!\x9b\xf1:\x84\x0d\xcd\x00\x86+\x9a\xdb\xe2\x0e\x02\x81\xa1%\xeeIa\xf0 \xe0Q\xdc\x0b\xb8\xa1\xb3\xa8\x8dd\xd62\xf6\xa46\xa8U\x87\xcc\x99\xf1\xb8\xe7'\xe4\xff\xfc?\xa7\xfdV\xf9\xb1\x0f\xa4\xc4\xea@J\xf9\x81\xa4&\xb2\x18\x8dw>\xe1%b\xbd\"\x8e\x02B{s\xa0,\x08+\xae-/\n\x99\xc2CH\xbd2\xfd\xf1\xb8\xfa\x81S\x9a\xf2 \xb2\x8a\x80\xbc\x0c\x19\x07\xb1\xaf,\x1cU\xac\xc9\x074\x99\xb3{\xf7\xee\xe9i\x07h\xe9\x07\xd8\x1c \x0c\x97\x92K\x92G\x18:\xc6\xc1d\x12l\x86\xda\xf1\xfc\xf3U\xbb\x10\xd4\xbc\xaal\x7f\x1e\xd3\x13\xefX0\x816;\xd5f\xce\x9do\xe0\xef\xf0\xed\xa59]\xc9Q`\"\xd75\xa9\xd6EuZ\xd3\xe9>\x8d\x1e\xaa\x8c\xb5$\xd3\x82D\x1f\xabA\x8c\xe4\x19Is\xb5\xb2\xbf^\xe5z\xa2\x0e\x0c&\xdf\xda\xae\xe8\xaf\x1d\x8am\x88\x197\x91,\x1b\x1f)\xa4W\x9a\xd8\xed+E3\xb0F5\x18\x82n G9T@\xa2\x89\xd2\xdc\x8c\x19\xd5\xa0\x81n\x06\xa7 #\xca\x01(\x92\xad@W\xda\xfc\xe9*\xd1\x11U\xaa\x03\xd0\xf1\xa7/\xe8\xd8\xb8.\x89\x8eL\x9f\xfd\x99\xa3\xe3\xab\xabD\xc7$-\x07 \xa3\x01\xad>\xbf#\x11\x0d\x14Wv\x02\xbe\xba\xec XW\xff\xba\x94 \xa0\xaf\x08\x0e\xe2\xb4\xd0\x94K}\xef\xec\xe0G\x98\x19\xfd\x08\x99\xe1\xee\xba9Pe\xca\xcc\x90\x99\xd4M*\xe2O\xa41\xe4\x99*\x86^z\x971\xa8\xdc\xbc\xac\xdc\xc6\xa0\xf2\xf42\xbbR\x01W\xe1G\x83E\xffd&\xf4\xb7^\x94\x84\xe4\xfc\xc5\xc2\x95\xa4\x12j^\xa6\xd8\xa0%\xcf\xeci\xe1\xfa\x03\xdci\xac\x1c\xe0\xd6\x03\xdcw\xcc&y(p\xe7\xb1\xd2u\xc4\x81h\x02?\x83C\xd8R\xd2~\xb98\x17\xd8\xc5\xbb\x02\xe0\n\"l`wg\x06`\xedo/\x13\xe0d\xd5GK;3\xe8\xe7C\x1b\x9d\x0b\xb5\xeb\x82!\xc4\xaf\xf6L\xf0\xe1\x9bC\xd8\x18\xc8L\xbf\xc2\xd3\x89\xe7yo\xb5#pN\x9c1\xac\x85\xdem\xbd\x9b\xae\x1b:\xfa\xeef\x90\xa9Y\xdf\x0d\xd6:o\xa8\xcc\xb5:\xbd7\x98q\xc1\x18\x97\x05\x95\xe2\xb96\xe2\x98\xfbF\x8f\xd0\x7fX\xaa\xab)\xec\xcf~l\xb4R\nX\xceB\xc9+\x1d\x8aK\x91\xcb\x8a=\xaad\xce\x0c\x1e\xee\x1ej+\x0c\xfb\x1a\x13&m\xa9B\xa9K\xc5\x1b\xb6v\xa3\xa0\xda6C4\x11\x01=\xd4\xfc\x12\xe9\x8c\xc1>\xa51\xb4\xa4\xd8\x80K\xb1V\x078\x0bvN\xb4\x9ex\xd0\x10f\x0d\\\x87\x9dh\x0e\xb5\xe8\xeb\x1bU\x1fcpZ\xf17\xad\xe7\xbd\xbb\x1dy\x14o}\xb6\xb1mr\xc93UI\x9e\x91J\xf2\xf4U\x92\xe7F%y\x16*\xc9S]\xad \xeb\xc5qRy\xd4\xcd\xea0\x9c\xe9\xfe\xe7\"\x80\xde\x9d\xd3\xff]?\x19TR\x14\xa1/\xf4)e\xd0\xf4\x03\xc8\xa0;\xe6\xf8\x87\xeb\"\x83\xdaH\x89\xc9@i5\xddAZ5\xcb\x8a\xfe0Yqc+\xda\x16\x18D\xdb\x0d\x15\xd1{\x03\xb0d\xc4{\xe8\x9f\\E\xa4\x18J\x07\xa0\x06S\x9f\x0d$n\xc4yP\x81\xce\xc2K\x8d\x83/\xd2|\xedk\x95\xb6\xc0\xb7#\x7f\xe1|m\x94\xaa\xb654F\xaa\x1a\xc0\xd7\xd2 \x15\x9f\xfec\xc8\xa7\xb1\x1c\x1c|\x03\\\xa8d\xe1vKR\xd6\x0bG\xf7\xb6\xfeE\x94,\xafL\xf2\xc6\xa9\x19C%\x81\xf3\x95\xb8\x02\x11\x9cw\xf1\xa7\xb4\xdc\xb9\x97\x17\xde\xca/\xcc-\xe9\xe7\xeb\x14\x8fe\x18\x83i.)Y<_\xc7\xe8\xfa\xb7\xfa\x0f\xd9\x13vS\x07;m\x0c\xe3\x84\x83\x81\xf1h\xae\xbd\xf3?\xff\x8f\xfe\xcf\xc1\x14\xe2\xce\x0c\x9c1\x1c\x97y\x94,\xddT\xe7M\xdaL\x94T!\xe8Vw\xe6\x9e\x99&\x83K\xaa[\x03\xa7\xdf\xf2II4=\xbc\x9c\xc2\xcb\\\xfa\xeb:(\xbc\xc6Pz\xe2}I <}\x86\xa7k\x91\xe0I\x14Qj\x8d\xc3&\xd3\x13?\x1e\xfa\xd8\x92T\x8f\x7f\xf6%*\xd9\xb4z\x8c\x87\xc0\x15ef\xe2{\xb2\x97\x0d\xc9*\x05S\xd9\xd9yI3W\x92\x1c\xf9\xa2k\x80|}<\x8be:\xd5\x94?\xe8\xe9T#\xfe\xa0\xa7S\xf5\xf9\x83\x9eNu\xc3\x1f\xf4t\xaa\x05\x7f\xd0B\xf2X\x8d\xe4\xf1\xc7G\xf2\xe0\x8a\xb2\x14\xa5*\x05f\xcf\xbbF\xa6\xc0\xcc\x87+0\x95Y\x8a6R\xc5edR\\~\xb2,Ei\xf2:\xbfH7%\xa6\xdfV\x03'\x1c\xf8\x91\x9f\x04$6\x00\xe7\xcc\xab%\xf1\xe71 \xb5\x01\xfe\x86\xba\xdd\xea\xb3\xb1U\xa8<\xbf\x98\xa4\x1buT\xb7\xb6R\xfb|S\x96\xf6Y\xd1\x9dy\x99\x00o\xef\xf4\x94\xfe\x11\xe0\x84\xd8\x147\x97\x1f\xcb\x94\x0fd\x93\x8aa]\x1f\xaa\x9f6\x1dT\xd4\xfc\x1b\x83\xf3:\xbf\x80\xa8\x84tS\x82\xccdfp\xdd\xd4\x17\xf7\xaeX#V\x12\xaak?i\xe1\xe7\x0c\x9e\xf0\x1d\xd0\xa8\x86\xd6\x01o`\xa8\x19\x9c\xe3\xe8\x0c\xf6jc!&\xc8\xa8\x0f\x95\xebYp\xfc\xcb\xa1\xf2\xe5P\xb9\xbe\x87\xca\xfc\"\xf3\x0bC\x91\x16\xe2E\xc5\xf1\x99\xbf\\\x92\xfc\xc0t\x94\xb0\\?\x1a\x12\x86P~\\\xa4\xc7\xab\xf4L{\xe2\x94\xba\xc3\xa0\x19XP\x8f\xd6\x0bVQ\x1c\xe6$A\xa1\x0e\xcb\xfc\x98?bG\xa6\xb7$/\xa24\x99d\xb9\xbf\\\xfb\xca\x13,\x1d\x7f\x88\xe6NO\xd7\xa4(\xfc%\x01\xc5\xfd\xc9\xc4_\xcf\xa3\xe5&\xdd\xa8\x0b~X\xcd\xa5\x12hu\xab\x0e\x0ey\x83\xb4\x18\xca\x14\x18\xc6\xe2\n@]\xea\x06\x13\xc7\xa8>\x94\x99\xdb\n\xd2\x90\xd4\xad\x15\x0c\xf5X\"V? \xa9\xa4a\xf9j\x9a\x91\xc4\xcf\"\xf6\xea\"\"qXP6 IK\x98\x13\xc8rR\x90\xa4\xc4\x8a\xd4+\x02\x85\xbf&\xc0\xf1\x1c\xd2\x1c^d$\xf9\xee\xe5\xd3\xc6\xb8\xeeY\x8e\xdc9\xdedY\x9a\x97$\x14\x0b*z\xe7\xe7d\xc0\xf8\xf8\xd4\xa0\xf0\xf57\xe7\xc0\xdbw\xfeV\xcdR\xb9J\x0b\x02\xe5\xca/a\xed\x97\xc1j\xc0g\xf9\xb4\xcd\xe0\x96\xb7\xef%l\xf6\xdcE\x9a\x039\xf7\xd7YL\xc6\xbb~k\x1f\xbf5\xf2\x1c\x11\xd3BI\xb0\xc5\x16\xd5\xee\xf3\x0f\xb0\xdf\xae\xdf\xf6^GE\x11%\xcb\xcfgs;\xafWt\x87\xa5\xdb($a\xe3u\x08SR`\xad\xdd\"#A\xb4\xb8\x00\x9f\x1eoQg'X\xef$\xbe#\xa3$\x8c\x02\xbf$\xd5\xd7$\x1b\xb9\xdd\x00|\xd9\x83\x97\x11\x10Z5I\xed\x85\x04q\xf2\xcb<\x0e\xc5\xa6\x96=c|\xca\xe7\xc7\xfd_c\xd5\xe5\xe0\xdc\xf4l\x97\x0c\xd48\xae\xfd8\xae0Q \x96\xe5\xf2\x9cm\x12\x9a\xd9u\xb7\x03\x07\x13\xb6\xe3\x7f\xafY\x92v\x8a\xa0\x8f \xc9\x9eE\xc9\xbb\xcf]\xbd\xdd\x18\x87\x0d\xb2pq]\xa9\xde\x96F/1\xe1\xa0$\xe7\xe50$\xf3\x8d\xb8\x93\xa4\xa8\xe1\x96\x88V\xb5N\x05\x1e\x1a<5\xa11\xd9^\x96\x93-I\xca\xc7\xacG\xae\x84\x92*\xf3\x9b\xae\xb0\xa2[\x89\x15\xddn\xb2\xf4N\x0c\xb4\x8b\xd9&=>\xdbT\xe9g\xa9n\x1f\xe3j\xf7\x1d\x89)\xb6\xb9\xb8+F\xacLk\x0b\xa1s=B\xe7\xed\x19\x94O\x86R\x8a\xe6k\x1b\xd9\xb0RJ UU\xc1\xf3u\x9c\x143pVe\x99\xcdn\xde<;;\xf3\xcenyi\xbe\xbcy\xb0\xbf\xbf\x7f\x13_\x93\xbf\xf4\xcf8J\xdeI\xdf\x9c>x\xf0\xe0&\x16 \x94\xbc\xabM\xf0\x93\xa5\x05rc3p\xfcy\x91\xc6\x1be\xf9{^\x05QQ\xbcF\x94?\xdc\xef\xa3\x7f\x17\x99\xd5\xd3J\x16\x85\xc5\xbc^\xac\xe7i,\x9d\xdamD\xce\xbeO\xcfg\xe0\xec\xc3>\x1c\xd0\xff\x93\x0c\x06\x0bNm\x928\x0d\xdeu\xd3\xd3\xe9z\x97\xb1<\xe0\x12\xa4\x9b\x81\xf3|z\xc7\xbb\x0f\xf7\x7f\x98\xde\xfe\xf9\x8ew\xf7\xd1\xf46\x1cx\xf7\xf6o\xc1\xf4\xc0\xbb{\xf7\x0eLa\xba\x0fS\xb8\xe7\xdd\xbau\x1b\xa6p\x97?\xbd\x0bw\xbc\xbb?\xdf]\x1dl'\xde\xfd\xfd\xe9\xa3\xfbp\xcb\xbbw\xe76\xdc\xf7\xee=\xb8\x07\xb7\xe8K\xb7\x82\xa9w\xb0\x7f\x8b\x0e\x07\xf0\xd9\x01\x1cx\xd3\x07\x0f~\xbe\xff\xc3\xed`\xe2\xdd\xb9s\x0b\xf6'S\xf0\xee\xde\xbe;\x99\xc2\x14\x1fM\xef\x05\xfb\xe0\xdd\xb9\xfd\xc0\xbb}p\x9f\xde\xbb\xf5\xc0{p\x87>\xbd\xb5\x7f/\xa60\xf7\xbc[\xf7\xef=\xba\xe3\xdd\xbdw\x00\xd3\xfb\xde\xfd\xbbS\xb8\xeb\xdd\xb9\x03\xd3\x07p\xcf\x9b\xc2\xf4\xc1\xea\x8ew?\xa0\x9f\x80}\x98\xd2\xcfL\xe8W`J\xbf3\xa9>swB\xbf\x13xw\x0enO\xbc\xe9\xdd{\xde\x83;\xb7&\xde\xbd;\xec\x07m\xee\xee\xcf\x0fh\x97\x1eM\xef\xc1}\xdaG\x98\xde\xf5n\xdd9\x80\xfb\xc0&\xec\xdf\x9d\xf9\x1f\x8d>\xf8\xca_\x9bu\xff\x93\xac\xe0\xf3\xe9\x01\xdc\xff\xe1\xfe\xcfw\x10l\x10\n\x7f\x82\xd5\x97\xe4\xb9\xb8\xc4\xe2\xdf\xf6n\xdd\xbe\x0f\xd3\xdb\xde\xfd\xdb\x0f\x82\x89w\xfb\xee\x03\xfa\xff\x93\xa9wp ~\xdd}p\x0f\xf6\x9fQ4\x98z\xf7\xa7\x0f\xe2\xc9\x81w\xf7\xce\x94\n`\x07\xdaW\xf0Q\xe3\x1f\x04\xa0\x98B\x1f\xc7\x07\xde\xbd;\xf7'\xb7\xbc\xe9\x9d \xfd\xf9\x00\x7f\x1e\x04\xb2\x97\xee\x8b\x97\xaa\xdb\x80\xb7\xc5\xcf\xaa\x83\xf7\xbd\xe9\xfd[1vor\xcb\xdb\xbf5\x0dto\x80\xe8z\xf5\x9ca\x1a\xed\x1d\xf6\x89b\xc2\xf4\x0e]k\xf1;P\xbe\xf2)0AY,\xf7\x12\xf8p\xcb;\xb8\x03\xd3\xfdgw\xbd\xe9\xfe\x038\xf0\xee\xdc\x0f&\xde\xc1\xdd\xfb\x13\xef\xe0\x1e\xffqo\x1f\x17\xf7\xc1\xbd\x07\xe2\x81wo\x7f\x8a\xff}p\xf7\x01\xec\xc7\xf7\xbc\xfb\xb7\xe0\x9e\xf7`\xff~@!\xbc\x83{S\xfc\xef\xbd}:[\xf4\xc5x\xd2\x80\x99\x08 \xfa\xe9)\xb6\x83\xdf\x11\xed\xd2\x15\xec4\xfcL\xf4\xf3\xd3\xce\xfa\xa4\x1fyy\x89\xa9\xbf\xe7\xdd\x9e\xde\x07\x9c\xf8\xc0;\xb8w0\x11\x93\xc6~<\xb8\xf7\x00\xf6\x0b\x9c\xcc{\xfbS\x9c\xc8\xbb8\x91\x0f\xf6\xef\x03\x9d\xce\x00\x97@\xcc\x14\xfb\x81/q\xa0I\x05\xd4XQ\xfc\x14N8[\x81~\x93\xb8\xf3\xe9t\xc7\xd8\xc1\xc9=oz{\xfa\x81\xe6\xfd6\x1c\xdcV\xcd;/\xcbqe\xd3\xfd\x00\xeemo\xffp\xc7\xbb\x7f+\xbe\xe5!)\xba\xf3\xe0\xd9}\xb8\x1bO\xee\x02\xfb\xdf\xd4\xbb=\x9d\xd0\x7f\x9eQ(\x98\xde\xfa\xe1`\xfa\xf3\xbdO0t\x16\xf1~e#\xdf\x87\xe9\xfd\xd5\xed\xed\xe4`5\xb9\xbd=\xf8\xf7\xf3[pw{\xb0\x9a\xde\xff\xf9\xee\x0f\xb7\xfe\xbd\xbe\x05\xf7V\xd3\x83\xed\xe4\xe0\x87\xbb\xdb\xff\x8f\xbdw[r\xe4F\x16\x04\xdf\xfb+\x90l\x9d*\xb2x\xc9d\xd6E\x123\xb3\xb2\xd5j\xe9\xb4\xd6T\xdd2\xa9\xfa\xcc\xce\x90\xacj0\x08\x92\xa1\x8c\x9b\x10\x08ff 5\xd6\x0fk\xfb\x03\xbb\x0f;f\xbb/\xfb0k\xf3\xb2f\xfb\x0b\xf3)\xfd%kp\x07\x107D0\x98U\xea\xd3\xe7LS\xb2\xca\x08\x04.\x0e\xc0\xe1\xeep8\xdc\xcf\xeb\x9d\x1d|\x1c\xc5\x84Q\x18D\xfd\xf3O\x07\x13\x9a\xa6\xfe6\xaa\x9f+G\xfd\xe9\xd9Y\xd5\xa6\xd47\x1f\x9e9\xce\x95\xd5\x87\xe9s\xc7\xb9\xb2\xfa\xf0\xb4\xbaCK\xf1\xc3\xf3j\x13\x81\xf3F\xa5\xdd\x9b\xa9\xba\x9e}\xee0u\xdddA\x80\x9f\x9f\xbb\x82\xedxq\x18\xc6QH\xf9\x8d\xce4\xad\x1c\xc5\xba\xd4$\x9ekP\xd5\x0f\xce\x10R\xee\x91+\xf5\x19\xdeX\x04\xd1\xbb\xf5[\x0c\xd7\x95\xd0}\x8b~\xd6_D|\xc3\xe0\xc3|\xa9S\xfc(\xf0#\xf6*^3rEN\xa6\xa5T<\x0d\x85G\x9d\xbeR\"(\x1e\xba\xaa'\x9d\x8aJv\x86\xa7\xa7\xe6\xc5\xb4x\x9f\xc4[N\x93\x9d\xfe\\x/\xa0S\xbd\xf7\x1b\xe7-\xa9^\n\xe6y=rrE\xc4}\xc2\xe2\x0d\xea\x8c\xfa\xa0\xb1\x19\xc1\xc1qOOWoP\xedL\xc4nIV\xe9\x89J\xa3:\xcd\x8b\xb9\xc9\xe6\xd7\xbb\xa6\x92c\x93\x9c\x056-\xad\x8d\xba\xbd\x1e\xef\xc1\xd5\xc9\x8c\xb3~0gK\x03O\xcaD\x1f\xae\x1e\xfe\xfc\xbe\xba\xa4`\x08r\xf3\x11\x95\xb5UY\xc5\xfb\xc5\xa6G\x84\x15*\x1c\x95j\xb2\xa0tR~\xa9Z\xcb\xfa+\xb80\xc9\x06D\xecx|\x0b\xfd\xfe\x8a\xf3\x98\xf7{\xff\x81\xc7\xd1\x96\xfc\x993\x85\xdet\x15\xb0?\xe3\xa1\xa4\x18\x11o\xc7\xbc\x1b\xb8\x9c\x7f\xea\xa1\x13\x8e\xea\xbd0\x8b\x9f\x18\xabF\x8d\x8cM\x1a\x8c\x88\x02[\xab\xe7!\x87V\xe4\xdc\xb0\xfb\xb4_\xfc6\x98lb\xfe\x15\xf5v\xb9-{m\xd5`sy\x99y\xb4\x84i\xc4\xa6\xcd\x1b\xd7Z\xbf\xbe3+\xc4\xd2\xaa\x10\xc6\xa6\x01W\xd4\xef\x8a\xb4\xde\xf93\x8a\xb8\x82\xc1\x87zj\xaa1\xa1\xfcp\x9dj\x06#\x8d\x99\x9e\xae\x18\xf29\xd5\x91\x16\xedU3\x1eK\xd3~4\x18\x91H\xd3\x89&@\xf4\xa1Z\xb7\xde\x01:!\xb6W\xd6\x94~@\x14\x86\xcea=\xe5\xf5\xa4RZG\xe4\x1b\xb3\xbc?\xe2\xb8D\x15\xbax6\xfa\xa0\xa1\xea\x06\xe2\x03\x06\x0c+\xee2l\xe0\xf7+\xe6B\xd1\xa7M\xe1u\x92 ?H\x0dC\xfe\x15\xf9(|\xbd\x81\xa1?u\x1e\x07\xf85%\xa6%\xb1)D\xfeE!\x01\x9c\x8e\xc4\xa6\x97[&~\xcb\x19U\x14<\xb6/\x0ebZ\xec\xb6\xaf$\xa7nS\xe3\xe0\xba\x9b\x98\x93\xbe\xe9e\x0e\xe1Hk\xfc\x03\x16m\xc5n\x04B\xca\xd9\x08D\x92^\xef\x82\xc4\xe3\xf1\xc5\x80P2\xbc\"|\xce\xe6\xfeR1@\xb6T\x8d\xf8\xc3!\xb6\x84]r#\"-\xcea\x1d\xfa\x8f\x0b\xf7x\x9a\x03>\x1c\xfa\xe4\x92\xc4\x17\x03\xd2\xc3\xa5\x80\x8e\xf3m\x17\xc85\xf6\xaa\x80\xa0\x06\x19U\x16s\x0ej`\x9a5\x8c\xc1Q#\xf0\x91\xb0s\xb2\xa3\xa9\x0bC\xd5\xa7,b\xa9G\x13\xf6j\xed\x92=U\x0e\xce\x92\x80z\xec\xabH\xf8\xc2g\xa9K\x12U\xd9\xb0\x9a\xdf\x8b0\xa8\x8b\xa4?\x17\xb4\xfa\x19J\"?e\xb1`o!\xa6\xd5a\xed~\xef2/\xf3rQ\xd8\x88\xbe\x1f\x95\xeb\x03\x95QG\xb2\xd3\xbb<-\xd4\xda#C\x92b\xf6r\xed\x1eR\xc4.5\xb2\xb9Xj9\xeb\x9a\xf4.\x13\xce^^\xaa\xe2P9\xed\xc3g-\x17\xc0u\xe6\xcbS\xf8zy\xaar\x16\x00 3\xd2\xebR\xb02\x0e\x1b\x16y\xae\x85=R2`\xe0\xe2\x0f\xdeH\x91F\x08\x1d;\x17\x8ekjkX\x1b\x8e\xc305\xeb\x93\x80F\xdb\xef8\xdb\xf8wu\xc9)Q\xe4\x9a\x86\xa9K(Q\xdf\xc1\xc9\x0c\xf8\x9f\xd1\x19'i\x12\xf8\xa2\x7f\xbaH\x87\xa7\xdb\xc1@\x87\xf2\x86H\xde\xbc\x1f\xe0\x12\xc6\x1e\xbe\xf5\xb2T\xc4\xe1\x88x\xf3\xb3\xe5\xc0\xfa\xb1p\xe5\x99\xab,\xcb\xca8\xd4\xed\x17U7\x1f\xe3\xd1\xe3U\xef1\x19\x92\x1d\x0c\xbb\xdf\x8f\xfb\x9b\xc1@\x8d\xf8\xe3\xde\xe3R)\xa7)ia\xc6\xd5\xbc\xad\xd5L\xc1\x0c\xf6\xa3\xc9\xce\xdf\xee\x02\x88p\xf4\xe8\x11)\xbcj\xc3\xd5B\xca\x88\xcc\x133\xd90\xeb\x1e\x15}o\x80n)\xfa\xf6\xd3\xa0\x15\x83\x1c\x88\xa1\x87DK\xeb\xd9d\xc7\xe8\xda\x8f\xb6\xb5%\xd8\xbabv\xaa\x0d@\xc7\xdd\xb7l\xcf\x02\xecb\xb95S\xf1\x91k\xd1Yum\xad\xef\xbap\x00c\xda\x1bM\xeev\"\x0c\xfe\x98\xc1\xb1\xed\xe5\x8e\x93\xd3\x97=X\\;\xfe\x12<\n8\x87k\x95\x05\x01\x13o\x03?\x15\xdd T\x168\x08S\xa1\xa2#G#\x0b\x9a\xa7\x13\xea\xf3\x05\x0b\xbbC\x17\xf8\xd5Y\xca+\xa9A\xd6\x0cU\xe0\xd7;\x19s%\xaa\xad\xdd\xc3\xd5&\x98\xaa\xb9v2\xc0\xdee\x1c\xe8e\x03\x95\x93\x97dJ\xae\xc9c\x92\n\xca\x05\xaeP\xf3 \x96&FTu#L \xbc#'!n\x99\x04E\xb5`[\xdf\xa9\xcfE\x06!\x80\x0c\\\x93\x1e\xa2bR\x9d\x99\xbc\xe6N\xe0\x9a\xe1<\xe9\x17jW;\xe659\x07\xe1\xf1%\x05\x1b\x10\x03\x07R*\xce6\x06\x06\x0c\xf3\x15\xbb(\"\x8c\xc1\x11\xcb\x8cV+\xf0C\xba\xed\"\xb2\x9b\x01|LR\xee\x95 M\xb9\xa7\x01\xad\x8fS\xf6\xd0!oX\xbd~\xb85Q\xcf\xfa\x8f \x0d\xf4hc-4P\xf3\x80\xcc\xd5$\xa0]1.\xe1\xc7\xbd\xc7\xeaO\x86\xeb\xbfH\xbf\xc9i\xaf\xb0\xd0+#\x04\x11D\xbb\xd3C\xc8^'\x16X\xcb\x113\xd5T\x8f\xe2\x81G@\xa3\xb27\xd5r\x0c4\x0d\xf5\xac\xe2\xf5\xfd\x11\xd0\xa8\xecM\xb5\x1c\x03MC=\xfc\x08Pxm\x9e\xf9Q p\xd7\xa8v\xa2\xd8\x1d\xb8\x94\xd8i.E\x03\x7f\x1bi\x0eu\xaf\xd6\x8d`wb\x0c\xa93\xa43\x98\xa3\xca\xac\xea\x90\x1d\xd3\xb7]\xad|\x1d\xe5\x1e\xda\xb3\xf5G\xee\xd9qh\xbc\xae\x96O\x05\x8f\x1d\xa2jc\x15\x98\xbf\xa1\x96# q\xd7s\x8c\xe0\xc5BG\xe9# \xa8\x97_\xb3\xa0{\xf3k\x16\xb8\xca\x1f\x01\x80\xa3\x06?J\xbbC\xe0G\xa9\xab\xfc\x11\x108j\x08)\xaf\x0b\x15\x8d5\xa8\xdc\xce\x1a\x8e\x00\xc2UG\x9a\xad\x0e\xad\xb5\x1c#\xb3U\xf3f\x1e>V\xebN\x8e\xa8;i\xab\xbb&`\xee(_\xaf\xb4.\xf1\x90D\xa1\x1b\xa9\xec\xa4Vj'\xb5\x88P\x12\\9\x88l\x1ao\xc4\xd1M@\x81\x94\\whM=\xd6);\xbb\x13\x1d\x07\xad2T\x95\xf1\x11a`N\xcb\xbaTV\xac\xaa^\x93\xa0\xdb\x0f\xae\x87\xaeVu\xae\xd9R\xd3\xe3KU\xe2\xa0\x14\xf7\xf2\xb1\xa3\x99#\x16\x85\xca_SB\xc5\xb1\x88b\xc1\xder\xb69\x04\xad\xe1D\x7f\xc8\xc2\x15\xe3\x08\x9f\xbf&C2\x1dLD\xac\x1d\x938N\x97\x95\x88\xdb\xdbD\x9cm\xc0\x10\xdb\xc9\xc4P\xea\xcdV\xdf\xac\xc9Kr\x06G\xa6\x9c\x0c\xafHof\xf5\x0c\xf0u0\"\x8f\xd5\n2\xea\x1f\x03\xffX\xd5\xfe\xd2\n\xfd\xbf\xdeD\x8fuL\xdf\xc7=\xe2\xaf\xaf\xac\xc4\xff\xb8\xf7rn>\xf5\x96Jxw.:;.\x80Y]wD\xba3eI\xf8\xf1\xe5\x8eW\xc1M\xc7)Kz\xb0N\x14\x1fn\xce\xa22\xc0\xec_\xa6\x0c\x9a\xaeeSY.\xe3\xa0^\\m\xa1\xa1|k\xcf\x8e\xc0\x9f8PM\x9dj@\xeaT\xc4\xd6|\x14\xea\x07>\xcc\x0fNX;j\xe1l\xd6\xa6\xde\x17,\xac-\x0e\x0b\xcc\x11\x1dt\xe9Kl=4\xf2v\xf1\xc1CE\xb3Fr|o\xefR\xd7\xc5\x105-\x06\x92\xe3|\x01\xe3\xabC\xb4\xa2\xde\x0d\xac\x90\xbf\xfe\xaf\xffM\xe1|e\xb0\xd6\xc7\xc8(\x0e\xcd\xd9\xfa\x08\xcd\xdbZ\xd4D\x9c#\xf6^\xeb\x9a\xb0\xb9>N>rC\x7fL\x0d\xc2Q\xc3Q\x02\xf3\xba\xb2\xe9+\x1f\x03\xa5\xe4\x8ad\xc5\xf3\xc3.\xcb\xa8_\xe4\xa4\x84\xf5]\xc4\xa9\x90}8\x8c\xc8\xcb+\"\xf4\xe9\x1a\x19\x93s\xc5\xc7\x15\x9b.+\xcaP\x13\x05\xd6\x07F\x0b\x85/FmU\xd2X\x89\xb9B\xbf\x82\xc6\xea\xac\x9c\xac\x99\xa5iU\x15\xafh\xcf\x8a\xf5\x9c\x97\xda\xd4 Z\xab\x85=Tip\xc5\xb9\xd4\xcf\xf78P\x03ri\x8f\x0f\xa1\xa9\x8a\n\xd5*\xd9\xecya\xaf.\xa7\xe4SS<\xa8\xcd \xf5\x03\x0f\xfa\xea\xc6]1\xb9\"\xf3\xda\x94\xcd{@\xa8{\xe8\xdb\xff\xec\xf9\xc0q\xf03\xef)\xden\xb2\xbcpg\xe1l\xc38\x8b<\x08\x13\x0f\x19?ug\xd4S\xaa3}\xe6\xced\xe9\xa2\xa0~`\xf2~\xde\x0c\xdc\xb9\xce3=k\x82\x0e\x8e-C\x16 \x03\xdft\xea\xce\x9a\x86\x94\x0b8\x06\xb49\xcf\xdd9\x03?\xba\xf17\xf7&\xd7\xd3\xc1\xb2\x94iy\xc4q\xbf\xc3z\xaahd\xc5\xcb\x84\xdc\x1ej+\x92pvA\x18\xb9$\xb1F\xc6\x0b\xc2\x86\xc3A\xa1\n\x8c$\x12\xcf\xd9r~\xb6\x1c\x11x\x98.]\xa6W\xc5\x03vm\xe5Q\"\x10.n\x84Gi.\xf8\x04\x9a\x02D\xe66X\x01\xa2-\x13\xdfg\x01K\xfb\xbd\xde``\xe1\x16\xe4\x92D\x17D(\xf0\xf9\\,\xfb\xac\xd1\x84\xe3\x03n\xc3\x95,A\x1a\xbb\xc6\x8a\x160\xd7\x84i;\x17\x1c\xcb:\xe1SC6\xb3\xd4\xcae\x01\xa9\x830\xb1I\xca=s\x88\xde?]D\xa7[\xbc\xf6:\x11\xdc\x0f]\xe2m\xc0\xf6,p\xde\xdeRm\xa532?\x1b\x91\xa9\x03?\xf3\xbb\xd8\xf32^\x82CWm\xc2h\x0c\x8f\x14X\xa3\xa2\xbd$\x9b\xb0h?\xb2\x1d\xff\xd8\xc6\xafO\xab\xb6\xaa\xdaJ\xe6y\x93\x91\x0c3\xa7\xb6\xbe\x0b\x0b)\x9c\xe6\xa6#\x12\x8c\xe0\x18\xbb~\x04\xfd\xec\x9c\x9c(\x82<\xf1v\x94\x7f\x19\xaf\xd9\x17\xa2\x7f\x96\x9f\x17\x8f\xa7\xf5\"\x9fO\xebE\xa6\xedE\xb4G}f\x1d\xe4\xf7\x96\xb3^{\x11j\x96x\xa1\x8b#2_\x0eF\xa4\x9f\xc1\xd5b:\"S\xe07gDJ\xf2\xfc\xb3:T\x19\xc8}\x8d\xcd\xc0r\x0c\xc8\x15\xa1\x93$N_\xd1\xbb\x11\x8a\x01\x8a\xc1]\x90\x94\\\x92@\xb1\xb0\xe9\x19\xd4L\x01E\x0b\xb5\xa7\x83\x0b\x92\x0e\x87naR\x873\x0c|\x8f\xf5\xcfG$\x1b\x8c4[\x86C}\xf3\x05\x9a\x1a\x91\xd4\xa0\xb9Y\xf4\xe4\x9a\x8c\xa7dF\xfa>l7\xd9\xde\xa7H\x07\xa5\xac\xa7)\xda8\x18\xe9;\xd8\xd0F%\xc7\x1c%Xo 2m\xe3\xc7+\xb2\x19(X\x1c\x14\xb0\x1bq(\xd0=\xf0'\x82Q=p\xa1\xb8\xccF\x0b\xb4\xa4~\xc9\xd8\xd2\xca)\xd2J\x9aKM\xd3\x12M\xac\x954\x0d8\x85*Z=\xde+\x89R\xd4\xca%\x8dR\x92\xaa\xc0J[.a\xcf\xfc\xa0\x03jY\xd3\x82\xc6\xe2\x82\xf0\x82pt\xd2\xef\xab\xf5\xed\xf7\xf9\xa8`R]\xa56\x88\xe3\x83\x8b\x01\x10 \xaeQ'68S\xb7\xd40\xbfb\xc3\xaa\xe4(o\\\xe1Q>\x14 \xde\xa1=c\xde=\x9bx\xc8[\xef/N\xf9\\6W\xcf\xa6U{B\xaa\xd3\xab\x86\xf8h\xed\xff\xec\xfc\xccIA\xd3\x9c\xbc\xd4\xccp\x14t\x9apB\xe4\x80\xf5\x88\xecFd?\"\xe1\x88l\xbb\xd1\xc5\x03\xa4\xf4\x01t1\xa8\xd3\xc5\xd4\xd0E\x0f\xe8b0\"g\xedt\xd1\xeb@\x17\x13rE\x02K\x17\x15\xd1\xf2\x90.n\xc8%\xc6p\xe8?=G\x8a\xb6\x86\xac\x15\xea\xb8Ac\x9c)R\xa4\xf5\xe0\x82lj\xb4\x12\xc8\x80\xaf\x00\xde\x1c\x80f\x0fM(\xc1R\xc7m\x1ca\xfc)\x03\xa4\x82px\xa5(\xc3G\x04\x0fZ\xb6\xf5\xed`\x1c7\xea\x91\"\xc8\xe4\x9a\xf4\xc3:`\x16(%O@\x86^\x0fSw\x83\x02|\x1a<\x07d\x17\x03\x05\x8c\x93\xad\xd8\xd2\x9a)9J[\xde\xb1U\xbc\xacoX\xcdtD\xbcA\x99M\xa4\x93|s2\xdf\"w\xa8\xa6\xb9.\xbe\xe8\xb8\x9c\xa1\xc3\xe4\x0d\xfc?\xecK\xe9\x8a7m>\x1eS\xf1[\x99\n\x10\xccB\x17\xb4\xc7\x8eR\x92\xb6\xa1>\x92\xff\xf8\xc7\xf3\x9f\"g\xf1\x1b8K\xce\x99\xfc\x1agr\xf2\x1f\xffh\xfe\xe3\x1f\xe2?\xe9/\xc4\x7f\xfcv\xfe\xe3\xbb\xf8\x8f\xff7\xe5?\x0fA\xc1F\xfc\x83\x01\x8fpw\x07n>\xec\x0e.\"\x97\x84_\x90H\xed\xe0JX\x01\x08\x16\xcf\xa3\xe5\xc0\xce\xba\x99\x07\xbd\x03\x11f\x00]\xbb\x10\x91{\x8b\xfb\xd7\x1a\x0d\x90\xcaK\xdb\x0c\x18\x80\xfar\xc2{d\xb5\xf4\xa4b\xf8LJ\x0b\xd9\xaa\xd5\x816\xb1\xfc\xa2\x9a\xddx\xd6B}\xb5\xe8\xdfz\xc5c\x17\xa4\x06\x85\xf5\xc7\x8cB\n$t\x85\x8b\xe6F\x1cF2\x0f\xe8\x8a\x05#r2\x053\x1cGUE\xfdV\xb9\xae\xe9\x88$Z\xce\x0e\x14IMM5}`'z\xfb\xcc\x06#r\xb2\xa9^$\xd2\x93\x9d\x0f\x05\x18%\x0e\\\xdd\x04\x04\xa4\x96\xe4\x95K\x8c\x0en\xd6I\xbeaw\x9c\xc348Q\xd1\xdbpo8\xac}\x06/Q\xb9\xb2\x83:\x15\x1an0\xa0']\xe0%\x0e\x98[\xa0%\xfa\nmK\x90\xc3\x96\x0e\x11\xdd)\xdc% *^\x93>lG\xe7\xcbAG8+\xb4\xbf\x19\x12\x81\x0eh\xda\x82\xcdv\x006\xeb\x08V\xa3\x8e\xc6\xfc\xac\xae\xc6eEh~\x06\xa0\x96j\xac\xfa\xa50\x8c\x1f\x0c}\x95U~\x8cQ\x1d\x8f\xbd\x06\xb8\xe0\xe2\x8a\x82\x1eh\x02\xd0&\x886\xab\xd7x\xfei9\xc8\x97]\x91ji\x83\xf5l\x80\xf2\x8c\x9b\xd3\x9b\xdcs[,\x97@\xac\xf6<_$q\xd2\xcf\x03\xbe\xc4\xf9\xbe3\x8b\x04\x9cg]\x17\x13fJ\xac\xe1\xa8%\xe5p\xa3\x87p\xb5\x1c\x1f\xba\xe6\xf0\x98\xee\xe1\xab\x0e\x0e\xd6Z\xc3|\x1b\xccj\x98\x12\xb7\x14\xe2#G-\xf6\xc9\x1ft\xa3\x84\xc4\xd1\xcbC\xb8u\x10q\xea4\xb2\x96\xd2\x0567\x95n\x83\xae\x05\xb2\nT\x1f$W\xd9d\xbb\xbf\xe6\xcd^\xfdruo\x7f>\xee\x0f\x16\xf3\xc5\xf2\xe7\xf7\xc3\xeb'\x93O\x16o\xe4h\xf6\xeb\xcb\x93\xc5b9\x00E\xf0b\xf1\xc9\xb4\xf71\xf6\x10\x0ey\xa5\xb8\xbb\xef\xb0\xb7()\xcf\x1a\xb6\x0dy\xce\xef\xd9\xf6\xab\xbb\x04\xc4]\xb8&\xd4\x7f#\xe7=\x08\xd2\xb8\x88\xfa\x83\xf9\xf2\xf1\xa27\x19\x9d\\\x8f{\xfafO\xaf\x87\xc1\xb7\xb8\xb9\xdb\x83\xa6\x82\xcbA_\x95*_t\xaeC\xd31n\x97\x9d\x804[\xa5\x82\xf7\xa7\x0e\xbc\x1cL\xd2\x98w\x0cN\xaa\xeb+\x9ck\x9a\x13@W\xbd\xa5\xeeI\xec\xdf\xa0\xff\xc9\x03\xc7\xa5g\xe4\xa3\xc2h\xa3\x82\x04_\xfa\xeb\x11\xe9m{j\xe7\xbb\xb1\x92Q\x9e\x17E\x933$\x98\xbb\x92\xc0\x1e\xa3\xc0\xee\xa6+\xd5\xed\xdd\xce\x9c\xd5\xba\xf3\x93\xe2\x86\xb2\xafH>\x14\xb0\xd2{eo\xf9\x12\xe8\xb2\x18\x8f\x9bk#\x06\n\xc1\xee\x84\xdeLP\xbd\xd9\x1b\x1c\xdc\x1b\x9a\x9f\xd5\x80\x9f\x8d@OF\xf3\xdd\xc6f\x12\xd0T|\x13\xad\xd9\x1d~\xf7\xb4\x0c\xb7g\x81\x11\x8d/@|\xdfL\xd8\x1d\xf3\xfa\x19\xe8-\n\xa5^\xa2\xfa\xfc \x95-\xfe4e\x83N5\xd3\xd9\xe2\xcf\x8a%\x99\xde\x98\x06#\x92\xa0>\x8d\x0cI2\x9f.\xf5\xe0v\x08EG\x0e\xf1\x99\xe2\xef=\xb8q>\xbeo\xd6L\xadc\x07\xb5\xb6\xc5\xb1\xde\xb5\xb8\x91\xcc\xcf\x97\x1d\xa2\xe7\x91\xc3\xf2b\xf1\xf7\xd0\xee=d\xeaT\x0f\xba\x15\xf9\xdb\xcc\xce!>_\xfc\x1d\xe0\xf9\xc5\x9f\x82)\x80\x05\x93/\x921I\xe6O\x0d\x8a6\xabR\xcc/-ho\xfa\x01\xb9$Y!\xe1!\xfd}\xc8t\xd9\x95\xf6K,\xa9\x12aT\x04\x0d(\x8d\x91\x98}\xdd\xf4\xd9\x08\\\x1b\xa4#bR\x04\xea\xb4\xdb)\xe6\x07 7&\xd5\x1cZ\x9c.\x86c\xb9\x98,&rq\x8d\xff\xc9\x93\x93\x93\x139\x1a\xc9\xf1\xf8\xb4~\x98q\xba\xe8\xf7=)B\xc9e2X\x0cN\xb7~\xfd`\xa3>w\xde\x8c\xf4\xfe\xfb\x7fsL\x11W\x1f\xfe_\xc7\x87D}\xf8\x7f\x1c\x1fD8#\xbd\xbf\xfe/\xffw\xaf\xf4\xa5\xc1\xda\xa6\x8b4\x95\xcbQ.iIk\xab\x8a\xbe}\x1a\xe4\xa5\xd2\xde\xa8\xc8\nS\xcd\n\xd3&VXc\xc4v\xd3\x94v\xe7\xc7\x19)\x97;\xcc\x96I\x91\xed*,\xcd,\xdb\x85\x95 gQ9/U\xafx\xd0<\xc8Oz\xfa=<\xa3\xb9&\x01\x99\x91\xc0J\xc3\xf1\xa8\xdd\xf6\xac\xfa\xd3\xd2\x97?\x17\x13\x11\x7f\x1b\xdf2\xfe%MY\xbfbtS\xfc\xa9e\xc6'\x82\xa5\xa2O\x07\x16^Z0\xbf\x18\x8eA\xec\xfe\xef\xff_oPH\x9d\xfc|>z\x0f\x1f\xfe\xfa\x97\xffZ\xfc\xd2\x9f_\x9f,\x07\x7f\xfd\xcb\x7f\x85\x8f\x9fL'\x93\xfa\xd7\x9f\x9f\xe9\xb2\x9fL\xd5\x7f\xc5\x0c#[\xef\xa8T\xee\x8d\x9c\xbf\x19/\x07\xe3\xf1\xb8\xaf\x1e\xe4'\x83\xd3m\x085\xfc\xf5/\xff\xfb'\xe7\x95\xbc\x8bt0\x1e\xf7\x17i)\xdb\xffV\xcb6\x7f3^\xa4\xaa\xd2>>\xd5\xb3\x83\xff\x96\\mM?\x8an\xd5\x12\x8d\xf9\xe3\xde\xd2E\x1c }[\xa7\x08\xa7\xf3\xf1\"\xc5\xdd\xd1\xf2\xd4\xb5\xc3\xa2m\x16\x8a'}a\x0e\x02\x01\x7f\x8d`\x0e\xd3~\xe2#\x120\x85\xbc\x85N\xd6\xdb\xc8\x0e\x98^\xdb\xad\x04\xd0em\x10k\x13\x914WF\x91<\x80\xde\xf8\xceM\x9b=\x92\x1d\x91\xfb\x11Y\x8d\xc8\xdb\x11\xb9\xfd0\x82t\xab5\xbf\xab&\xc2\xb4\xd2\xc4`u.\xc5\x9a\xccFaK\xaer\x88a\xe8\xb60tx\xfct;\xdf\xea\x9c\xe4\xf2\x8al\x06\x17d;\x1e\xb7\x9c(\x99_a\x0c\xb6\n\xb9P\xae\xd2\x9b\x14\xd8_\xd9\x15<\xe8,[\xb1\x19v\xe1\x82(\xc1\xca\x03\xc2\x18\x97vAz\xe3\x13\xe3\x86\xc7\x1f\x0c.\xda\x87\xd9\xfc\xc0\xd7\x07\xb9\"'\xb4\xafPX\xefN\xc6d\xaa\x05\xc2\xd4\xeeW\xa6#rO\xaeH\xef1NL\n\xa6\x89\xa0:\xc0\xb2\x01\x1e[']\xe6\xc3\xfcT\xeb{U\xc3zDB\xf57\xe9\x06\xb5\xf9\xc1\xa0\xb4\xcdc_\xcd\x83\x9a\xcaQeJ\xc9f\xa0\xa7\xf4\xa8\x06\x89\x06z7I\xfdh\x1b0\x18\x8a{\xd5R\xa1r\x95\xb69f\x18\x8a\xbf\x1c\xe0{rM\xfao\xe7;\\j\xc5\xe3\xca\xcc\x91<\";\xb46\xc8\x89 Z\xc4\xce\xcf\x97\x15\xb6\x91\xf5\x0b\x02\x80\x9e`G\xb9\xa7K\xd0&\x7f\x0c\x10\xce\x1e\x08\xc2t\xa9X^qI\x1d^+\xae\x9fj\xca\x8f2V \xbe\xd1\xe5WW\x836\xfd\xf6\xe4\x9a\xdc\x1e\xb3\xcf1?\x18\xc5V\x1d\xb4\xeb\x97\xc4\xe9\xcc\x0e\xddQ%\x11ug\xc4\x11\x07\xbb\xed\xa7\xf7J\x9b\xce\x85\xc0j5T\x8b\x03VH\xff0\x02\xf4\xfe\xfa\x97\xff\xe2\x8a\xa0\xea\xfa\xbd',H\xd9G\xad\xfa\xa3\xee\xc1\xc0\xc0\xbc\xea\xf8\x15\xe4\xa9\xdb\xdb[\xf9\x1b\xb9\x98-N\x17\xa7N\xb9\xc9o\xd4L\x9f\xbe\xb9\\\x9c\xd2E\xfa\xe4\xe5\xa9\x91\x90\xda\xc5#Z3^7F\xe8s\x87^CX\x0b.7\x06\xab\xce&\xe82\xaa\xf9\x9c*\xe3\xc1\x8c\x9c4\xc4\xae`!\xf5[>\x8b[_\x08\xc6\x9b+\xd7\xf2\xf2\xd7Q!0g\xd3\xdd\x16\xf3Ko}\xe1\xed\x14\x92l\x99x}\x9f\xb0\xfeA\xa1\xc1\xa3)#\xbd\x8c\x07\xbd\xd9Add\xc7\xacy%\xb2\xccH4\x81\xc8dl\xfd\x9a\xddu\\\xf60\xaa\xd0\x83?\xf1\xc0\x11\xf9\xa6\xfak:w*\xfe\xe0\xc2n{6\x1c\x08\x98\xb5\xbf\xaf\xa1\xe8)\x90D\x0cjF\x18\x96\xafTB\xbf\xb0\xa3z\xa3s\x9c\xfa\xa3\x92[\x9b\xa6\x9f\xe3\x0c\xcc~j\xfcb63Sg\x8ez\xb9\xea\xb4\xe8\xf2\xf5\x11\x0b\xfc\xe8&\x9d\x11V\x1f\x12\x9a\x89X}U\xcb\xa4\x1c\x93\xda\x15L\xea\xd8\x8d\x0co:\x80*\xeee\n;\x80:|jg\x12eA\xab\xe2E\xdf\xc3i\xd8\xe3\x14,\x95\xee]\x96J\xce\xb1\xaemk\xee;\x1e|\x14\xb6+\xa0o\xb9\xffX\xe7\x1f\xb9\xdb\xa0\x1eXD\x822);\xea\x14\x04\xea\xd1\xb7\xd0\xb5\xdc\x9d\xabr\xb6 \x9f[Vw\xfa\xe6\x92\xce_.\xd2\xa5a\x0d\xdb\x01\x1a\x87\xea+\xa3\xbb\xf1xD\xfc~\x9a;\x18P\x89\xc3\xe1@\xc9\xc6\x90\x0bR\n\x9b\xaf\xbc\xad\x18k\xcc\xcbv\x01\x9e\xe8\x0e\xac\xe0\x90Q\xc9\xf9}\x85\x1b\x14.\x13(\xf4F\xa1\x7f5\xc91\xda\xee:l\xaf\xf6\xa5=e\x08\x05\xfb\x81\x82yo\x15\x06F\xbc;L\xf1\x88\x99tOo\xa3\xd7\xd0\x9a\xde\x11np\xc7\xba!\x97\xb6Y4\xbe\xcdM\xdf \xce%\x15\xec[\x05\xc6~\xbeYN2\x1e\xa0\xa6J\xdb%\x1b-\x1a|\xd4;T\xf5Y\xb5\xb4\x1e\x11\xef\x18\x12I\x1e\xa4\x0d'E\x8dx\x90\xab\xa5\x93\x8eJq\x92\x0b{\xebN\x05 \xb2\xc0C;f\x1d\x8c\x1d\xd1;m\xcc\xab\x87\xbf{9}`\xd5f&T\xfd\x99\x81\xe8p.E\xb4\x02\xf3\xa1#\xf1\xd0)\xb6\x98\xd6\xbd\xec\x91\xd3\xfb\xf0>\x15h\xe0\xd1\xd0\x8d\xc7\xdd\xe1\x0b\xd0\x92\x1eP=!\xc3|L\x0c\x91\xe8 \x0e\xa9_P8\xb4zh\x9f\x1f:\x8fG \xf2\xd1\xf3w_9\xbb\xcaJgWY\xf9\xec\xca\x1b\xd9\x834}vu\xb0\x9d\xf6m2\xee\xd5\x0eV\x82\xe7\x1e\xe3\xf1\x05pI\xadM9\xb9\xb2\x14\x9a\xe0\xadmC/\xe0Sf\xac\xd7/\x06\x8a-\xdb6:\xed\xe0\xf6:(\xe2\x88\xf89z\xc4\xfa\xe6+\x1a\xc0\xd9\xe2U\x8ew\xfa\xe4\xa4\xdc\xa1'\xe4\x0b\xcb\xc7&?\xa6\xd5\x8fg\x93\xe9\xf3\xc9\xd3Jj5\xd3\x97qr\xcf\xfd\xedN\xf4\xbd\x019?\x9b>'\xff\xcc\xd96\xe6\xf7\xe4\x7f\xa2^\xbcJ\xc9\xe5\x96\xb3\xedo\xd4?\xe3\x1f!e\xe2\xc5\xe1\xcbj5\xaf\xbeyM\xbe\xf5=\x16\xa5l=!\x85\x18\x86j\xdc\xd28\xe3\x1e\x83X\x86\x01\xe6IOC_\x8c\xf5\xcb$\xd9%\x07\xa0T\x15\xa6\xb3\xd3\xd3\xad/v\xd9JAp\xaa B\x80N\xdbF\xe1\xb4\xf4\x0e[\xd1Q\xd9\x80\xbd\xddF(\x9e\xfcI\xf8\x81q\xb0\xae\x9d\xe2W\xac\xc4\x9c\x02v\x9c_\x94v\x9fe\xc6Q*x\xe6\x89\x98\xcfH\\_\x88\x19\x0fR\xf7\xb6\xb5eG\x9b\xeff\x1d\x1f#v\xfb\x1f\xfch\x1d\xdf\xba?\x97\xb7\xda\xae\xcay\xa6\xd6.\x9b\xe9{3\xf5\x1c\xc5X\xac.'\xd0\"\x0c\xbe\xa3\x14\x9d\xf8\xe9\x97A\x9c\xa2\x13\x9ck\x18\x89WT\xec&!\xbd\xebGj\xaf2R\xd2\xfc\x0cvK#\xa2\x1d\nT\xfd\xd5\x17\x7f\xa0KC0\"\xe1\x8b{\x0b\xc51e\xf1\xeeV\xab.\x86\x98\xcb\x8bfz\xf5N\xf0\x07\xc1[\xdbP?\x0dJ\xd0\xb2OGX,\xcc\xce\x8cnV\xa5\xe9\x04\xb7F|\xb5\\\xef\xddX\x8d\xc0w\xc1mc\x8c\xa8\xb1\xfaU\xbe\xb6\nj\x0bf\x02w@\xa0,\xc8\xf3=\x94\xfb\x17\x1a\xe8\xa8\x03] s\x15\xef\x02#,=\xf74\x14\xc1\xb7j8bb\x19\x95\x93'\x1e\x0d\x02\x13%FS\xe9\xc1(\x8f\x86te\xa3! rM\x04\x99\x91\x13\xbco\n\xbe\\\xec\xe8\xa0V\x08\x8c\xc7\x05\xf1\xa3T\xd0\xc8S\x85\xe2\x89\" \xaf\xe9V\x15.\xfa\x83\x9a\xd9\xd1}m\x89R\x7f0Y\xa9\xa7>+\xfaY\xea2\x88%\xd23k\x16\x05\xcc\xcf\xa8V\x01\x86\x9c\xbc\xb6\x0e'\x83\xcd\xb1\xa3\x94 \xe0TH\x9a\xe4\xd0\x0cF\x8e\xb3\x0cw\x17^\x15i\xf8q}(\x90\xffc:Q(f{QH\x9b\x141\xbf\x99T \xcb\x85\n\xd5c3\xa9\xd5\x1c\x18r\xc2ssV\xcb\x91!\xb3~k\xce^b\xc2P\xa4\x90\xe2&.\x83#f\xe6u\x81q\x1e719\xcb=f^\xf2RvZ\xbe\x80\xdb\x11\x85\xc5\xd2<\x1f\x05\x81\x05j\xb3\xef-\xc3me\x14l_\xbf6\x17(\x88,H\x05\xcd\xfbQ\x83]Jy?\"1p\x99C\x9e\xb3H>n06}\x81j\xaa~U\xc0\x1c\x19t\xd6\xbe\x7f\xe2\xf2\xaa\xfd9\xcfPIS\xb2\xabS\xfa\xa4\xabTp\xea\x89WL\xec\xe2u\x07d\xc0\xa0f=S\xae\xd7\x05\xe1Ph\x9e\x1d\x1e\x04R\x94\xc3\"\xe2G*\x9b\x98\xech\xfa\xc7\xdb\xc8F\xa3\x8fP\x14a\xf3hI\xd0#X\x03\xfb6\xb8\xd8\x05Fv'X\xb4\xee\x08#\x80\x87\xf2\x1f\xcb\xc5\xfbf\xe4\xaan\xe7\xde7\xdc\xcc)m\x15\x1a\x16\x98\x91\x18AW]\x1b\x9b^a;\xd1\x1b\x00\x93*\xa4\x90\x0e\x13L@\xde)\x14\xd2\x81F\x90\x99R\xbe\xcd\xc01V\x83\x843(u\x01\xc2\x03\xb6\xce\x0d-\x81\x07q\x19\xe9$\xcd\x12\xc6a\x01\xe2\x0d\xe95\x0b\x98`\xe5\xae\x8c*;2\x8a\n\x84\xa8\xd3\\\x07\x81\x9f\xa4~:k\xdd\xa2\x17\x7f\xd6\xa4K\xebh^b\x90\x04\x98\x83(\x0b\x02%VD\xe4\x9a\xf4&\x93\x9e\x12~1\xbc\xa21\xf6Rl\x1f\xf4\xfcc\x12Y\xd5\xf1\x90D] \xb6V\xecvDN%\x0f\x7f\xc19\xbd/x\xe8\xd25\x0c\xf2\x8e\x18eq5r\x83\xf9\x15\x96\xa1\xdd\xeb\xb0\xceG\"\xc4\x9c\xbb\xc0\x1aU\xd2\x95m:j\xc5\x87q\xfd8\xcb1 p\xff\xe5\x8bh\xfd%MD\xc6\xd9\x11\x03s\"&\xdb ^\xd1\xc0\x11\x9e\xf1\xcfP\xed\xf7l\xcb\xee\xfeL\xc2,\x15dG\xf7\x8c\x88\x1d#\x8f\xb7\x8f\xc9&\xa0[\x92\xb2Z`F\xf3\xcbG\xac\xb23\xbc \xb8T\xc1@\x8a\x81\xcf\x00}\xb9\xb9\x80\x1f\xf1\x08\"\xe9\xad\xd9\xdd \xdf7Eh\xbf\x82\xe1(\x8c9\x94Jl\xb5\xdf\xb2\x1b\x8az#Pw}\x84\xeb\\\xc6H\xb9Wf\x99!}\xec\xe3m+W\xdc\xdc\xdb\x9d/X\x9aP\x8f\xc1\x08\xce\x08\x04dr\xec\x0f\x8a\xfa\x8e\xc3\xdb\x02\xb7\xde\xc5\x86+\x8d\x18W\xa0\x1a9#O\x90\xb2\x98\xf2\xfa\xd5\xb7\x9d\xf0\xcanw\xbb\x80V\xdc\x96\x08,\x86\xa1UE12\xa5\xf95\nb\x95\xe6\x8eiMJ\xd2\xeb\xc4\x81S&\xbe\x10\xe5\xbdb\x87\xbbkzC\xa3J\xa6\xfd\xc1\x9c-\xf30\xba]\x1a\xdd\xd6\x1b=\xba\xc5.\xed\xe8\xce\xa5]\x1a\xaa*xtK\xad\x0b\xa9\x82\x829\xfeu\x01n[\x07\xae\xcb PU\x06d\xe8\xc2\xebU)\x0c\xae\xf9\xb9G\xe4K\xc5>\xbb\x8cH\xb1U=\x92\xfd\x1e0\xdf^M\xc3I\x1a\xe4\xbb\xf5\xbass\xb9\x9a\x0d\xd5hf\"\xa0\x82\xfe`\x94\xc7^\xac\x10\x14\xd4\xaf\xe9\xb9\xd0\xdc\x0bo\x11D\xe0\xf8\x1d\xefDr\xb5\x13W\x94\x17\xef/\x98\xc4\x0b\x98\xf4l\x92\xee\xfc\x8d\xe8+\x12<&\xb8\xed\xf7QrP\xdc\x9c\"\xc1l\xe2\x88n\x1c\x9d\x189\x85\x16\x03\xcfu\xc5\x0e\xce\xc2x\xcf\xfe\xee\x07\x8f\x16oX\x95FR\x0de\xbbv\x13\\p\xe2 _\xc0\xa8\xc3\xb1\n\x8e\xb7j\xc1c\xfdtD\x1c\xd7m\xc9!\x8d\xd9G\x9d\x89m}\xc9tY1\xb5\xe6;\x93\xe4\x1dM;\xcf\xbb\x15\x8e\xd0\x9a\xa3GzdX\x9d|\xb8(\xdc+\xdc\xa5\x81LL'w\x81(e\xe2\x1b\xc3?\x8f\x80\xaa\xc6\x89\x8f\xe3\x80\xae&\x8fk\xb1\xf3\x90\x1b\x1d\\\x87\x96J:\x8f\xa2\x16\xbcE\xe5`\xb2\x83\xce\x0f\xb0\xe2\x07\xc1\x0f\xf0\x96y\xef\xb2\x87\xd1\x95 \xaa \xf5\xdcb`2\xd2{\xd9\xcb\xa3\xf8\xda\x91R+\xbdwy\x8a\x05{/{\xcb\xa3T\xc7%\xf0:\x0c\x05\x8a\xcd\x96\x0bYA\xbe\x1a\xc5\xcb\xfc\xaaC\xa7\xd7G\xfb\xc0\xcd\x97\x87\x84j\xe2G\x84\x0d\x08sk\x03\x84\x16\x98\xc9\x90<\xc6\x08\x0b\xb0\xf5\xc0\xa8`\xed\xf4<\xa7\x16\xf5\xd1+\xa5\xbcW\xa2xMou\x84\x88\xfcQD\xdf\xceS\xdc\xa5\x89\xa2\xd6\xc9\xc8\xfcm\xbe?\x8c\xb4\xda\xa3-f\x06\x14\xe5\x1d\x98\x7f<\x0d@\x14`\x85\xd3+T\xb5\xe3X\xfe\x9e\xb3M\x7f\xd0\x82 ~N\"\xa0R\xedoZ\xcf\x04\xbb\x13\xfdBm\xa8\xb7oROt\x19\xbd\x02\xcc\x1d\x05f\xb3On\x1e9bm\x87Dc\x1e\x07(\xe6g\xf9:\xc2\xf6e\x8a\xbcC\xed&\xdb\xe6\x95\x1b\x13u\xa3K1\x1b'\xabA\xd5\x190\xb6!\xb9\"\xbd\xb7\xab\x80F7\xbd\xae\xaa\x942<]P\xae$\x81[-k\xfb\x12\x85\x93\x9a\xa1\xa5\x8dC\xd2\x1b#s\x9bu\xa4\xfc5\x8c\xe9\x02\xa9Uek`\xd7\xf1k\xadF\xae*f\x89\xbb\xd5\xbc\xc0\x11\xcd\x19b\xa2uT\xf6X\xce\xa8\xb0\x15\xbb\xc3@\x1e\x93\xef\xfe\xf8\xc37\xaf\xbf\xf9\x97\xaf\xde~\xf3\x87\xaf\xbf\xf9\xc37\xaf\xffc7\n\xe6<\xd69\x82\x8c\xa9\xf2z\x8f\x0f\x1a\xfe\xd3\xfe\xf5\xac7\x7f\xd3[>\xb9\xee\xc9\xc7\xf37\x8f\x97O\xae\x1f\xcb\xf9\x9b\xc7\xbd\xab\xcb\x97\x7f^\xa4\xcb\xe1\xe0\x14\x19\xdc\xe9\xfc\xcd\"]\x9c\xf5\x1e\xbf\\\x9c^-\xee\xce\xa6\xe3\xc5\xdd\xf4\xeb\xc5\xdd\xa7_/\x87\xa7\x134\x0fQ\xb3\xdb\xbf\x9e-\x16\xe9\x93+\xf5O\x0foM\xdao\x83\xeb\xde\xa8\xe8\xcbd\xaer+Vy\xd9?\xf9\xdd\x1f\xbf|\xfd\x1f\xbf\xfbj\xa0^u\xeab\x91\x0e\xf3W1\"= \xeeQ\n\x15\xaa\xcf\x83'\x86\xdb\xe2\xbb,Tq\xd9?\x85F{\xe0o\xe6t~6\xfe\x9c\x8e\xdf}1\xfeO\xcb\xfcq\xb6|rZ\xad\xb3\x0c\x81\xb0\xad\xa8^\x9d^\x17\xda\xcb\xf9\xf7\x88\xf4\xb6~\xcfE\x0b\xd5\xa0\x7f\xb9\xa3\x9cz\x82q\x13Q\xddhZ\xfa\x8f\xa2U\x9a\\\xc8G\xbf\x9e\xbe8\xbb\x90\x8f\x02\xa1\x9e\xe1q\x8b\x8f\xe7\x17\xf2\xd1OY\x0c/O\x9f\xc1\xbf\x9f_\xd4\xaf\xdb\xab\x1f\x989tA\xd8\xd2n\xa4\xb0\xf7\xb0\xf8Q\xb2\x8c\x98//PUzb|]\x82\xf2g\xfe\xf4@nE\x10ON\xc4A7\x1bAE\x93\x1b\x8f\x88\xd0\x9a\xbaf\xab\x81\xc0\xaa\x87\x91c\xa91Ut\xe7\x8bh\x0d\x93w\xff\x87x\xcdR0'\xf6At\xd1Zv\x7fD\xa2\x81M\xec\x17h\xfeWh\xa4\xa1\xca\xf5\xb5\x8f\x81\x81\xd6\x0d\n\xab\x1b\xa4M>\x86H\xe3fJ\x89wq!@\xc9\xa1\xa9\xf0\xaa\xc3\xd12\n^\xb7Q\xf0\xdc\xa3pD'4\xed\xf4\xbbP\xe5\x06(\x8e\xc3x\xad\xdf\x8dr\xb2Y\xd1I[\xba\xdd\xbcp\xf5~]\xaf\x8f\xc8*\xd79Z\x0eA\xd0\xb1\xf3C\xd3\x01{\xf89\xef\xb02\xa29\x07/\xb2\xcd\xd3E\x0b\x92t\x01\xf3\xd4X!\xda)\x84\xcb\xdc\x99\xf2\x91\xecg\x0f\x99\xba\xbaX\xd4(m\x14V\xc2\xd1'85\xc3\x86\xe2\xb2j\x11|Adh9\xe1\xb3\x92q\xc5\xe1Ds \x0f\xad\xa8\xaa!\x83\xcc\xef\x18Q5\x1f\xfb.H\xdc8\x12\xf9\x0c\x1e\x1c\x88\x0f\x06\xd9\xe0\xd4\x87\x00l\xf1\xf2\xe3\x81\xfb\xabr\x06\x87\xb4\xa4\x1a^\x9e\x8e\xb4S\xb0I\xffz\xe6G\x82\xf1\x08\xbc\xf4\xd1@Z\xf2\xe7\xc7\x91z\x01\x92\x14\xf3T2\x95-\xe1~\xcaR\x99\xecb\x81^i\xeee\xc2\xe35fO\xe5&\xce\xa25\xd4$\xfd0\x8cW~\xe0\xb3H\xfa\xd1:S}`\xa9\x0ciD\xb7\xb0VU\xb9\x84q%tI\xc1\xbc]\x14\x07\xf1\xf6^z;\xee\xa7\"\xa4\xa9\xf4\xe20\xcc\"_\xdc\xcb\xb5\xcf\x99\x82\xe1^\xb2u\xe6a\xf5\xec\xa7\xccO\xa0\x1e?J\x85/2\xc1dH\xf9\x0d\x13~\xb4\x95i\x1cd\x08\xd1\x9eb\x81T\xae(\xdfR_=\xc4\x99\xf0\x7f\xca\x98\\\xa1\xa20\x95j\xfb\xaedf\xe9\x05\x8cF\xf8\x10\x8b\x1d<\xc4a\x92 \xc6\xe5\x9a\x85\xb1\xc7\xa9\x90k\x9f\x86q\xb4N%\xf4\xdf\xf7R\xb9\x8b\x83\xb5\x1fmS\x19\xf8\xdb\x1d\xb4\x9fP.\"Us\x12d\xe1\n \xca\x92$\x80\xber\xeaC\x13{\x16)y4\x95\xd4\xa3k\x16\xdeK\x8fr\x06\xd0\xc4aB\xa3{\xe9\xf1\x0c\x06{\x1d\x87\x007\xbbK\xe2\x94\xad\xe5\x06\x9aI\xe5&\x88\xd5X\xc9-\x0d\x02\xc6\xef\xe56\xf3\x05\xe5\x00\x8e\xbf\xa6\xf7\xf2\xc6WX\x11\xc9\x88e\xa9\xa0\\\xc67~Do\xa9\xe4\xcc\xf3\x13\x96J\xce\"A\x03\xf5w\xef\xb3\xdbT\xa6;\xff&\xddQ\x89\xce R\x009\xe6B\xa6\xf7\xa9`a*\xe9\x96E\xde\xbd\\1\x1e\xf8\x91\xf4h\xc88\x95\x1e\xa0\x85\xf4\xe2\xcd\x861\x85/\xeb8\x95\n\x05\xa2\xadd\xa9\xa0\x82I\xa6z\n\xe03.\xe4&\x13\xab8\x9074\xdb\xb0H\x06\xd9]\xc6\xefeH\xfd4\x8ed\x18G4\xdd\xc90KY\x16\xca\x88n\xe3{\x8a\xb8\xa6\xa0L\xa8\xcf\xd5\x1f\x80)\xf6|\x1a\xe0\xa8\xdeKA\x85\x88c)|\x16\xad\xa9\x1a\xe1=\x0b\xe4\xde\xa7?\xb2T\xee\xfd \xa0\xeaO\xaa\xd0f\x1f\x03d\xfb\xf8\x9en\x99\x04\xccF4P\xa3\xbfN\xa5\xb7c4\x91\x9e\xdaw\xc85\x8d<&a\xd1\xcam@S5\xb2Y\xaa\xd0,\xda\xc62\xf2\xa3\x1f)L\xb4^\x0e2\xdd\xc5j\xd4\xe2\x80r)b5\x03\"\xbe\xb9\x8f\xa5\x88\xe3 \x95\xb7j\x8d\xca\xdb\x98\xdf\xa4\x922\x1eK\xca\x13*i\xeaS\xb9b\xa9\x90+\xff\x86\xc9U\x00h\xf9\xee\x9d\x1a\xdeDzA\xb6\x92^\x1c\xabU\x19'rCy(7~\xba\x93[\x7f#\xe46\xe3\x99\xf4\xa3M,\x7f\x8cW\xa9\xbc\xf1o}y\xc3\xd9Z\x064Z\xcb\xc0\x0fc\x19\xf8\xd1\x8d\x0cY\x94I\xb5\x18e\x18\xaf\xa9\x8ch\xc8d\xa2\xf06Q_\x938\x15\xf2\xa7$\x8e$\xf7\xbd\x9d\xe4\xd9\x8e\xcb\x94\xdd\xddK\xe1'\xa9\x1a/\xa6\xfe\x89\xe5-\x8d\xb6\xf2V-\xe7[\xff\xc6\x97\xef\xe2\x88\xa9%%W\xfeZ\xae|\x05\xf0J\xad#\xe9\xb1Xa\xb0Z\xaar\x1b\xef\xa5\x1f y\xe3\x872\xf4\x03\x191!\xe3(\x901\xdf\xaa\xe5/\x93l%\x15\xc0\x82\x052\x8bby\xcb\xd6\xf2\xee\xeeN\xde\xdd\xbf\x93\xd4\x93t-)\x93t#\xe9VR_\xd2@\xd2P\xd2H\xd2X\xd2\x9f$\xe5\x92\xa6\x92\nI3Io%\xbd\x93\xf4\x9d\\Q\xb9Z\xc9\xd5Z\xae\x98\\m\xe4j+W;\xb9\xf2\xe5\xeaG\xb9\n\xe5*\x92\xabX\xae\xb8\\\xa5r%\xe4j/W\xb7ru/W\n|\xe9y\xd2[Ko#\xbd\xad\xf4v\xd2\xf3\xa5w#\xbd@z\xa1\xf4\x14)\x94\x1e\x97^&\xbd\xbd\xf4n\xa5w'\xbd{\xe9\xbd\x93k&\xd7?\xca\xf5\x8d\\\x87r\x1d\xcb\xf5;\xc9<\xc9\x98d[\xc9\xb8d\xa9dB\xb2Ln|\xb9\xf9Qnn\xe4&\x94\x9bXn\xb8\xdcR\xb9]\xc9\xedZn\x99\xdcn\xe4v+\xb7jb\xe56\x90\xdbPn#\xb9M\xe4\xf6'\xb9\xe5r\x9b\xca\xad\x9an\xb9\xbd\x95\xdb{\xb9\xbb\x91\xbbP\xee\"\xb9\xe3r'\xe4.\x93\xfeZ\xfaL\xfa\x81\xf4C\xe9G\xd2\x8f\xa5\xff\x93\xf4\xb9\xf4S\xe9\x0b\xf9#\x93?\x86\xf2\xc7X\xfe\x98\xc8\x1b&o\xb6\xf2f'o|y\x13\xca\x9bH\xde$\xf2\x86\xcb\x9b[ys/o\xde\xc9\x80\xca`%\x03O\x06\xbe\x0cnd\xc0e\x90\xca@\xc8 \x93\xc1^\x06j\xa9\xca\xd0\x93\xe1Z\x86L\x86[\x19\xeedx#\xc3@\x86\xa1\x0c\xd5\n\x96a\"\xc3\x9fd\xc8e\x98\xcaP\xc80\x93\xe1^\x86\xb72\xbc\x93\xe1\xbd\x0c\xdf\xc9\x88\xca\xc8\x93\x11\x93\xd1FF[\x19\xf92\nd\x14\xcb(\x91\x11\x97Q&\xa3w2\x0eeBe\xc2d\xb2\x91\xc9V&;\x99\xdc\xc8$\x90I(\x93H&\\&\xa9L\x84Lner/\x7fR4M\xf2X\xf2T\xf2L\xf2[\x99R\x99\xaed\xea\xc9t-S&\xd3\xadLw2\xf5e\xfa\xa3Lod\x1a\xc84\x94i$\xd3X\xa6\\\xa6B\xa6\x99L\xf72\xbd\x93\xe9\xbdL\xdfI\xe1I\xb1\x96b#\xc5V\x8a\x9d\x14?Jq#E E(E$E,E\"\x05\x97BH\xb1\x97\xe2V\x8aw2\xa32\xdb\xca\xecFf\xa9\xcc\xeee\xf6N\xee\xa9\xdc{r\xcf\xe4~+\xf7\xbe\xdcGr\x9f\xc9\xdb\x8d\xbcM\xe5=\x93\xf7B\xbe\xa3\xf2](\xdf\xdd\x0e\x16\xab\xd3\xaa\xe6\xb47\"\xe8\xffoq\xbb\x1c\xfc\xa6\xbf\xb8\xfdy:\x9a>\x7f?0\xba\xcc\xb2:\x14r_\xcf\xe6\x8b\xf1\xc5\xec\xd1\xd5b\xb8\xf8d\xb4\xb8]L\x96\xc3\xdf\x14\nD\xf6\x897Ub4\xa3\xb6B\x94\x19\x96\xf3\xf1dh\xc5\x87\xe5p\xd6\xbf>i\xfa\xb48]\x9c\x0e\xfa\xd7'\x8b\xf5pqz=\xe8_c\xca\xb5\x13\x90\xbaJ\xb7?\xb9>E\xa5\xaej\xff\xf6\xf6v19\xbadsG\xad\xf6\x17\xd4\xc5\x8b\xb1\x05|\xf8\xe87\xbf^\x9c\xfe\xd3\xd5\x7f~\xdb\x1f\xc8\xc7\x9f\x80@Tg\xe1O\xbc\x0du\xc8\x11\xb3@\x8c\x0f\xaf\x03y\x12=\x1a\x7f\xe2\x81&-''Y\xb7\"\xdf\xb3\x80\n\x7f\xcfl\xb9\xcd\x81S\xc8\xa3/\xfa\x117\x99$\x87NX\x9a\x87\xd0\xd2\xf7\x19I\x9a\xa1\xb54\x7fF\x1cZc\xf3\x0b\xb1\xdf\x0d\xc1~\xba\x10\xf7vj\xd4E\x08\x81\xdb\xe4\x03\xe3bX!\xf9\x17\xa2_\"W\x87\xf8\xb4\x00$\xc6\x95r\xba\xe8\x9fn\x0f\xdc\xb7\x8fJ\xf9\x07\xa7\xdb\x03<\x1b\xb9\x80\x0d\x0e#%9\x1b\x90K\xd2\x07\xf2\x14\x95\x92-!?9\xeb8\xa6$\x9fs\x87w8\x976\xf2UU0\xeb\xaa\x84\xf4#pK\xd5(X\xce\x17\xb7\xcb\x06\xc1rG\xd3\xaf\xb3 \xc8\x8b\x9a\"-\x12\xbf\xa3\x9a\x8c\xfb?x;\x16\xb2\x83\x15\xb8a\xf8\x0f1_\x7f\xa90d#\x18\xaf\x023\x9b\xbfY\xa4\xcb'\xd7\xa6JG\x15E\xe6\xdb]\x1e5\xd3S\x94\x06tM\x7f2\x1dR\xec\xca\xdcb\xc94!\xfa]\xcc\xd2?\xc4\xe2\xf7to)\xf6\x1f\xf9\xefb\xa1\xad\xd3Z\xb2\x7f!\xbee4\x15\x7f\x8c\x98\xe9q\xa5\x8c\x9f~S\x9b\xcc\x9c\x92\xf5]\xe7\xf1\xce\x13\x89r'\xba,\xd7\xea\x82\xd3](\xce\xeb`~\xb6,\x1f\xac\xb6J\xf1\xbd\x1f\xe9\x9e\xa6\x1e\xf7\x131Cg=0\xce\xbd\xfd\xaa\x9c\xd8\xa5G\x87\x86\xbe\xa3\x89\xa0\x9d\xf1\x13\x86\x8e\xe7\xd5\xfa\x07\xfb\x00\xc7:@\x9fw89c\x13A\xdb\x1avO\\\xded\xbbA^\xc7\x82\x87\x81\x7f\x827&NL\x0f\x9aWQ\xcdW\xac\xf99\x91\xa7\x0d\x05\xbb\xa0\x92\x01\xf3\x84\xd9\xf1m#Q\xcd\xc09\x88$\n#P\xf8\x08\n\xf9Q\xf6\xcf]\x06\xef\x01\xc7\xbc\xaf\x8abS\xd7C\xae\xc2\xbe\x18Jv\x84-7\xf5=\x06\xc2\xa2\xc1\xa6\xb3T\xe3<\xc1\x8e\xc3q\xf6W\x98\xc5\x8fs\xe6\x87\x1ej;\x8e\xc2W\xb8\x7f\xe9Zy\xbe\x1f\xecX\x7fq\x94\xbb6R\xf4g\xfb\xc0\x06\x1f\x80A\x0d\x8d4\xce\xa7\xde\x8a\xfd-fT\xef\xd5\xba\xce\xe9\xeb\xf2\xd6\xaek3E\x0d\x00\x96\xed\xd8\xde\x83\xe6\xd88N\xd3\x0d\x82\xe74;\xe1\x0f\x87\xe2\xb8\x89\xef\xfd\xa6k\x93\x8dh\xf0'\xfe\x80E\x9d\xf1\x00\xf7S\xb9\xc2\x13\xc6\xc3(\x8d\xfb\xa8\x00\xbe>uY\xc3VX\x91\xad\xa2A\x1e5\xf9\xbf\xe3,a\xd1\x9a\xad?\x96\xedI\xc6;S\x99?\xf1.4\xa6tO'\xe3\x0dJ\xa2\"\xb6:\xf7\xb8V\x80\xacn\x9ak\x1f\xec\x90\x94}\xc3d0\xa5=\xed+\x10\xcc\xbdGM\x05!\xf4}G\xaf \x0f\\*\xd0\xb2qv\x9e\xfb\xf4~D\xc3\xe4\x02\xe21=\xeav\xcd\xea\xd85R\xbd6\x05\xed?tN\x8c\xbe\xae\xa8P(\xe7\xc3\x05\xd1\x07\xe7XU\xb5\x83\xa3\xf8\x9f\xcc\x12\xc2\x12\xf6#^`}\xcd\xa9\x1f\xf8\xd1\xf6\x87\x80B\xcc\xf6.\xe3S\xae\xb6\x8bl\xe4V\xd1\x97\x17\xb7\xdb\xe1zS\xf3\xeeAy8,Nb\xd1\x19$\xc7X\x1e\x01J\xef\xb4M\xe1Q\xd4\xe0\x1a\x87\xab\xe3i'/F\x8a\xfa\xda\x94\xf7#\xedh\x11c$\xf16?\xa5\x1a\xb0x\x92\xfb\xe5\x84\xbb\xc0\xf9`\xbc7\xbeeFd\xbe\xc4(>\xfd\xa2\xdbx\x1d\x8a\xeaC\xa3a\x1b\x8c\xc8<\x0fa\xde\x1b\x91\x1e\x04\xa4\x86\xf02\xea-\xf0S\xd1s\x85(\x9d\x973Bm\x9f\x7f@m;\xaek9?\xfb\x80Z\xe0\x93\xaeg\xdaZ\x8f\xbb\xbc \xcbm\xea8\xaf\xd4\xd1\x00;\xa3k?\xda\x9aBO\x1f\xd0pP\xa9\xe3\x99{\xf6v\"\x0c\xa0.\x93\xef\xf9\x03\xda\x12t\x15\xd8\x1e~\xda\xa9\x87k\xb6)\x0em\x15m\xdc\x85\x8aPA\xb1\xcf+\x81\x0d\x97\xee\x98x\xd5\x05\x8a\x14<\x0b\xacW\xb6\x8a\xcb){\xdd\x81\xa1\x1b\x1bF.\x89o\xaf)\xb0\xe1pP\xa8BG\x92\x9f\xb3%\xc4\xe7\x82\x87\xe9\xd2%\x8e\xd1@\xcc\x08\xe6<\x87\xf3\x85\xf9r\xa0\xa9\xd2\xa0BzrJa\x9fh\xc1\xad\x11\x04\x82\xf0\xdf\xb1\xaa\x835\x87\xe6\xcd\xf6E{\xfb-\x00\xbee\xe2\xfb,`)\x1e\xa3\xa3\xa3\x04\xec$\xbaH\x10\xe8\x10\xe1dzA(\xb9\xd4GHl\x12\xf8\x91j\x98\"Q\xbd\xf1\x93\xaf\xc2D\xdc\x7f\xebG,\xedS\x08m@\xc9\xcb+\x12\xa1\x17\xfe\x93>\x9b\x88\x1fv\xfeF\xcc\xe9\x12\xae\xdb\xac\x82\x9bo\xa25\x8b\x84\xfb\xfa\x13\x00\xccq\xe0\xe1F\x08\xd4\x12\xcf\xf9Ru\x91\xc2\xf1\xe6\xc9tpA\xf8p\xe8\x90\x130\xea\x85\xf0\xb7;\xa1`\xcfF\x84M\xfc\x14@4\xb0[\xbe\x90\x19\xb9\xaa\x8f\x9dQ_\x07\xa6\xa7y1\xda\xa86W\x8da%#2\x1c\xdaAB\xaa\xa1\xb9RB9\x8b@\xe8\xad\xd7\xda\x12\x0e&\x1f\xe7\xda\xe7\n\x9f\xcaq\xa5\xcc\x0420S]D\x0bQ\x8b%\x99\x82q*W\x1f\xb3\xb3\xb3\xcf\x9e/\xe5|\x91\x9d?;\x7f\xb6\xc8\xce\xcf\xce?\xd3\x89\xd5R\x01\x94\xca\xce\xce\xe8\xd9i!,X\x111\xe1\x8e\x91\x03+G\x84W\xc7P\x81\xe8#\xa2\xb9<)\x03\x02\x94\x92\xe1>>\xb3\xc7\x02\xd5\x9b\xf3\xc0\xe55\xab7\xc2I0\x02'\x10\xb98\x9b\x8eHo\x11\xa9\x14\xabU\\\x88\xde \x8f^W.\x9f\x15\x18p\x93Z\x1b\xd6V}\x0e5\x94\xd3\xb3\x82p\xf2e\xbcf_\x88~4 \xd7:,,F\xf9\xf3t<\x14\x08\xfe\xa6P\xbf\xa7j\xe8i\xda\x00\xee\x85)\x19\x13o@\xfe\x89<3\xc7\xb5\x90\x08\xc5y\x95z\xe8\xd5\x8c>\x15\x99\xf1\x07k\xe6\xc1\xdc\xab\xd54\xa4\xef\x8f\x14q\xf3#f\xfe\xbe\xa2w\x05\x024*\x05\xb4Al\x1fz\x1epZ\x86U?@e\x18kM\x9a\xeb\xae\xae\x96\xab\xdf\x8a\x00\x9c\x0dj\xa8X\xac;\xdf7\xfd\xaa\x0e\x08/\xbaUD\x1e\xd6\x1a<\xa0\xb8Y\xc7\xfa\xe7li\xd5`(\x11\xb0\xa5\xa2\xbc\x85.\x14=\x9f\xbd\x1f\x95\xda,K\x1a\xadM\xd7]\xda\xeb\xfe\xa2(\x87g\x8f\xfdC\x90]V\x00\x1b\xa0\xe8w\xe1\xea%k\x83\xfa\x87\x84zGC\x9cr/\x978\x0d\xd0z\x15\xd9\x0c\x85%\xc8\x1e\x0c\xde\x97;\xca\xd3C\xaezKn1\x9d\x00F\xf6\xe4\xa9\x06\x19\x02\xfdA\xf0\xfd\x96z5w\xc2\x0e\x86\x0c\xd2\x1f\xb9\x04\x97\xf8\xa6n\x07\xdfP\x10\xbf$\x91#b/Z\xaa\x9d4\x0c\xf2x\xccr\xbb\x04\xa6\x96\xedq\xdd\xd92Q\xc7\xdeV \xa9j\x19\xa98]],b\xb0\x8c\x1a=\x14\xa9,\x81\x82\xb6\xe2\x92\xd4/\xaf\xffy\xa0V\x01F5\xf0\xf1\x10\xce,\x87`9\x02\xb7\xad\x8acpr]Z\x19Pjj\x1c\xc1\xdb\xc4Q>\x82(\xc7\xa8~\x0c\x1c\x93\x91iQ\x05|\xb7\xf6\x05\x19\x83\xe1\xac\xf6 \x1a(\xd4\xbf \x81\xa2\xbc\xf1p8\x80\x88ne\xc8\x06j*Ax\x03&?\x18\x01\x07;\xb3)gZ\x1c\xaa\xf54\xc5\xfe\xe0\xc8\xa8\x15&e\xf7\xcee\xf3xY\\\n\x8d}\xd4c\x9d\xd5}UUD+\xb4\x8d;J\xb42\xa9\xee\x90\x83\xee%b\xf6\x82\x0e,2c*\x96j\x12\n\"\xcd%y\x96\x9b\xe3L\x1ds\x18\x03^\\\x81\x8f\x9a)\xee\xdb\x9aVW\xbe\x03\xe2j-\xb9x~\x8b\xdd\x1fl\x02rHy\x15\xd2\x97W\xe4Y\xfb\xc6J\x81:\x1c\x1er\x06k\xf5\x9cZ\x86\xe3\xa3<\xf6{C\x8c*\x1d\x8b\nUf\xb5\xaf6\xe6TN\x05\xd4\x96\"\x1e\x91g\xe0\xe8\xc5va\x04[\xd2ZyP\xc2\xb8\xaf'*\x10\xd3\x19\x99\x8b\x91\x86\xd7\xa1<\xd1\xe1\xab\x18\xca\x8c\xa5\xcf\xef\x95\xf0\x96\x8bI\xef\x7f\x194\xecN\xdf\\\xc7F\xe8|C/^\xb1\x84\x11\xb3\xc8Z\xcf\xbe\x81\xec\xccd\xaf\xa3\xbaG\x86\xe4)yI6\x8dh\xadrM\xcf_\xa0\xd7\x96\x18u\x1def\xe0\xa1\x82\xe3s\xcc\x13\xb7\xd6\x04\x92\xf7\x08%\xe7\xbeg5'\xc0\xda\xfa\x9e\xda\x03\x0d\xc8\x98\xa4\x03rI\x9e\xb6V\xa45\x159\xc5\x01C\xf9\x89\xe0~\xd8/\xeej\xff\xac7\xb5\xad\x95\xf1\x82\x8d]\x03a\x16\x17\xe4\xa4?\x1cf\xa8\xd1A\xc1 :\x90\x16g$+\xcdH\xb6\x04\x9b\xbe\xd2$\xa84P\x7f\xd8<5]P\x03\xb5\xa8\x8d:0\xb1\xb8\xa2[\xca\\\x84\x00\x04\xf8\xe6\xd1\x06\xe5R9\x0b\x8aj0\xb5\x10\xb0\xbe\x81\n\x01\x9a\x9e\xb9\xe9\x0b\x90\x9en\xd4\xc5\x87vs<\xce\xc9MF\x86\x8ae_\x03\xeb\x81\x93\xbfn\xc4\x07\x94\xf1\x0e\xea\x93PN\xc3tFhG\xc2\x84\x8a\x85\x0c\x16\xa7\x93\x1c\xfd{\xa29\xf5\xb0\xbb\xc7Q\x9b\xf0\x10\xb5\xd9\x93\x97$l]\x89/\xce\xb5\xb1[\x05\xdb\xf7\xc3\xe1\xa0\xb5\xa0\x1e\\\x85\xeey\xac\xdf\x90\xde\xfd\x81\xa5\xc2\x8f\xb6\x1f\xb2\xfc\xf5f\xa3\x0e\x13\xac\xe4\xbd\x92\xc84\x11\xc8Y\x17\xab\xeaA \xeaaa,\x01\xc9\xf3\x91\xbd\"{\x14\xce X\xed\x9e\\\x92\x10\xc2\x11\x15\xd6\xe2~@fd\x0f\xd4,D\x81m^\x98\x0d\xa8/\x17[T\x1d\xe3b\x0b#\xcd\x0bP-TS|\x17\x8e6\x8cO)\x94`b\xb3\xa39\xe9\xf7K\xe8\x10\x97\xd0!^\x02`\xfd\x12\n\xc4\xcb\xc1\x00\x03\xa09IZ\xfb\\7\x8b=~\xabXc\x03+\x9fLGpW\xe7\x0c\xaf\xa6l\xec&-!\x97d}A\x92C\xb1\x0b6\xf3d\xa9/eE\xb0\xfa\xdbt6\x04\xaeA4SC\xf3sSE\xf3k\xf6\xd0\xb5k\xedtf\\\xfd\xdb\xc9Q{\x14\x93\x98\xcf\xd1\xa88c\xa0A{\xfa\xf4\xd3:\x8dF\xc1\xb3\x03\xde;\xdb-\xa2\xc8\xf1x}\x18\xe8\x12f\xc7K\xc7\x8a\x0dH\xf9\xc0aT>~\xb8\xaa\x9c{v\xe4)y\x99\xa6\xa0\xc1\x9a\x19@\x84g1\".wue^P \xed\xfb~0\xca\x97\xa8\xd5K#\x11\x8f\xbb3\xbf\x02\xa0M\xf1om\x9c\xdb&\xa6T\x190\xc5\x1b\xe6\xd3\xa5=\x1d\xd2K\x0b\x17\x13\xcd\x97\x16F\xac\xd6s\x93\x90!\x01Z\x94\xcd\x93\"}\xb2\xe9t\x9e,\xdd\x8a\x83\x12\xf9L\xff.xd\x99\x17:\x0cJ\x0eq\xbf~F\x86%9Gm\xd8\xd3V\xce\xf4\xec\xbcE\xee\xce\x80N>zD\x9e=G\xc9\x1b\xa4\xf0\xe7\x07\xa4pX jEN/HF.I\xea<|\xac\x88\xd8\xb5Vm{O\x11B\xda\xd8\x1e\x01\xbfrVT\xf5\xab(\xef\x9a\xfe\x93\xbe\x8f\x1b\x80G\x8fH\xff\xe4\x84k\xbb\x10-\x13j\xa1\xac\xe3b\xd8\xf1\xe6\x85\xfaaR\xdb\xa0z:}\x14N\xda\xe4\xcai\x90\x0b \xf5\xf9\x90s\xa9\xf4y\x9b\x90\x86\\9.\xa3\xe6\x80\\\x93\xb1\x12\xa8\x0dzE\xae\x89\xe6\x15\xf4\x02)\xe0\xd9S\xfd\xack\xe0\xe4\xb2\x84\x07\xf5Zlc\xbc0Z\xf5\xce\xc7\xad\x9d?N\x0e\x8d\x0f\xadD\xf0\x83\xa8F&_&c\xd7\x1e\xb3e\\.\xc9\xb3\xcf\x14ZF\xe4%y\xfeic5\xa8em\\b\xbc\x1d\x08b\x15=m\xa0\xa8\x1d\xdegj\x0e\"ry\xa5\x80i\x13\x9e\x9e\xa1\xee3R\xb0?{a\xa2\xa6\xb6\x88\x16\x16\xb4\xda\xd7\xa6\xe3\xf7B\xa9\x07\xa2\x87yj\xa7\xd7\xb534p\x87\xd9\xb2\x9b\x19)\x01c;\"\xf7#\xb2\x1a\x91\xb7#r;\"_\x8d\xc8\xdd\x88\xfc0\"_\x8e\xc8\xcd\x88|\xe1\x10\xe1\x00\x15\x94\x08\xa9q\xd4(\x14\xb6\x8e\xbc\x0d\x1a;=\x89\xaa\x12^\xaa\xa4\x95lB\x03\xd3\x96Q\xfe\xd0\x8dO\xe8B\xaa\xb5\xbe\xcf\xed\xb7\xef\x8aV\xb8gG\x12l\xace\xb6\xe4\x1a\xef\x017\xafV\xd8T\xa2\xffj\xad\xd4\xd07\xca\xd5<\x911I\xf0~fg\xfa\x1e\xf35\xe3l\xfd6\xf0S\xd1$\x97A\x9e\x19\xd972\x82\xdb\x87KlJz\xed\x08\xea*\x0b\x02&Z!\xfdpx\xac\xc9\xd2[\xbd\x07\xbak\xdb\xf7\x81\x81\xce\xe0\x82\x9c\xf4O\xfa`\xb6\x836\x98\xb0\x81\xea\xdfW\xd5AkD[K[\xe9Rkf\xee\xc9\x98\xac\x958\xf3\x0cX\xb6*\xadPhG.\xc9\xb4\x94\xa2\xa4\xa8uQ~\xa7\n?v\x9dg\x1b\xc6\xce\x17,<0\x80_}\xc8\x00\x06\xd5\xdd<\xea\xc5\xc0H\xc1\xec\xf5\x0b\x08\xbdq\xec6\x8a;\xf1\xfb\xeaN\xbc,\xdd\x82e\x965\x808\xab\xefU\xb4}`\xd3\xc6\x00\xf7\xa6y%j\xaf\xfe\x16f\x11\x88\x99\x1a\xf5\xb7Vn'c\"\xc8K\x9c\x14\xa7=X\x15\xba\xa0\xda\x9b\xb4\x08\xaeW\x83v\xf3\x80\xa9|\xf0&\x050\xbd\xb0'\xf9\n\xb7(tD\xee+\xd2:\xd1\xa6xj\\\x8a\xa6g\xf8~\xbc]\xde\x8d^\\?\xa0\x82\xe1KrE\xee\xec.\xe8\x07rI\xbe\xbc ?4)\x18\x14\xe9\xbd\x9b\xffP\xb4\xe3kW.\xdc\x1cP,4+\x15\xea\n\x05\xd5\xf8M#\xc7W_\xb7m\xf2C\xce\x08)HAg\x83&Eo\xeev#\xe7{\xe52\xee\xe6C\xb7\xa4\xb0\xd6\xf7\xf6\xeb\xad5\x1cXuAB\xc5\xaf\xca\x1c\x04q\x91T\xa8\xf5\x831\xf4\xd6bdn\xc7\xa8\xa4\x8cG\x8f\xda\xcd\x0cHY\xf2G\x1c\x07>?$\xe7\xf5q\x03\x9c\x8c\xf4\xde\xe8\xdc\x08\xcc%\xe6L\xc6\xe4\xbc\x14\xb7\xd3f\x98GKcAevi\xb9\x851\xd2Y\xad\x08\xca\xf3\x0bm\xc6\xd9\xcf\x13U\xcb\xcb\n!+\x14(\xa4G\xe8\xd8\xbc1k\x97\x82\xa1\x7fO\x9b\x8bv$\x08\x99\xb6g\x1b\x92sT+\xf43\xb3\x0b\xf4\x14\x17x\xfe\x99{\x08\x87\xc3lPVDd\xc3\xa1\xc2m\x16\xed'\xe6VCjn\xae\x94\xd2 \\c-\xeb\x84\xb3\x8d3?~\xd0\x85R+\x9a\xe3\xf1f\x80\x0b;S\xcb\xb8\xa1\xcey\x0f\xae\xf0\xa6Km\x1a\xd9\x8d\x04\xda\x9b\x19o9\xdb0\xce\"\xafY\xbdIW\x8a\xda9\xe2\xe1\x1f\x14\xa9\xe2*?\xae\x1d\xf9\xd1\x03RTI\x10\xcd\x06d\x8c\x82S\xf1\x08%+\x0b/\xc3+\xf2\xac.M\x15.\xa2\x14\x1b(1~C\xd9\xec\xd7\xe1U\xedx\xc7\xb6;.}k\xd1\xe0\xe6\x82Z \"Z\x86z\xac\xa1.\xf6\xdd\xaf\xf64\xfe\x90\xd9}03SR\xca\x07\xe9\xbcL\xea\x07Q\xe7\xe3\xe8\xf2A\xad,\x9c\xe8\xb7ka\x9f>o\xd3\xc2\xe2\xb5\xb5\x03\xd5\xe4ZW\xb3\x16\x1cd\xe6\x82<}\x9e\xf3`P\xce\x82\xca\x94\\^\x91\x17\x17\x03\xe2\x83\xf1Wci\x17\xd5;\xe9\xfb\xe4%y\x81\x10\xea\xfa\xb4.&.S\xb5\xd4\xae1kg\xd8OG\xe4\xa9\":\xf9\xcd\x90\xfa\xf7\xe7\xea\xbb\xda\xfae$7\xcc\xac\x01H\xf3\xcb&`=?(\x08DG\xeas\xf1:W\x13\x8d\xda}\x8bX\xec\xb8\xc9\xfd\x11\x94\xbev\x0c;\x02\xebG\xaa\x9dv+\xa8\x9c\xc6CH\x1fm\xc2r\x084\x18\xb3\x07u\xd1\xdb\xf9\xc1\x1a\x1ci\xcd\x97\xb5\x0ev\xec\x97\x99\x84&R\xd26\x0b\xbf\xacZ\xdd\xa4>\xc4\x12pd\xee\xe1\x88F\x8bV{\xa7K\xcb\x10\xcd{GG\x86\x8aa\x8e=\xe0\xe8\xf7K\xec\x91\x96\x88\x1a\xd5:|\xbfH\xc8\xe8R\xcb$\xfdg\xcf\xf3\x8b\xb8\xb5U\x17#mz\x81:_\x8eE\xe2\xf2B\xee\xc7x\x17\xc6BQ`\xb31l\xd7\xfcb\xb9F\xb5^\xe1>\xdc/\xb0\x9cM\x17\xb4\xbe\xe9\xfca\xa8\x7f\x00\xf7:\x82|\xdc\xa2\x06V\x9d\x1f\xbd|\xdc\xe5\xad\xa8\xea\xbf\xf2\x12\xef03\x87W\xfc\xe0# \x16\x85;\xdfg\xe7\xd5\xbb\xdd\n\x81O\xdf\\\xf6\xe7:x\x9fvu=_\xa4\x8b\xd3\x97U\xd7n>f^\x9c:\xb2\xbf\\\x9ev#4#B]\xb4&?\xa0\xa8H\xc5\xb5\xa1\xab\xd8o\xd63$e1\xba.\xbbxJvMF\xe4$\xdf\xdc\xedD\x18\xb4\xca;\x89\xa2M\x8apx\xb0[zyu\xc0<\xf4\xc5\x99{\xeb\xe4\xb5\xef<\x9f\xe2\xa6\xae\x9f\xb9H\x97\xa7w\xae\x8a|a\xbe\xaci_Y8{._rz\xdfv\x1c\xf3\xecS\x00\x1a\xa4\x96\x93\x96\x1b)\xe6g.\xa5<='\xb2z\xf5\xc0\xfc4\x18`t\xf9\xf9\xa7\xaaf\xa1d\xb7\xe9\xf9y-\xfb\xfb.\xdb\xdeg\x9f6\xf7\x9c\xd8c\xa5\xeaV\x11-a\xd1\x95\x9e?(\xb6R\x87\"W\xd2\xb5\xd7\x13\x0f\x0eC{\x82h\xc0\xe7\xe9|Zq\xd6\xb7o\x0b\xd5m\xfcm\xc6\xa1U\xb5\xb3e\x1c\x9fx\xa8\xfe\xee\xa6\xf0\xef9\xfc\xfb\x14\xfe}\x06\xff>\x87\x7f_\xc0\xbf\x8c\xae\xb1\xd4\xce\xc2\x03\x1e2z\xfe\x86\xd3P\xbb\xc1P\xff\x86\x14>\xc6\xe0\xd9\x0f\x9e\x00\xd28\x13I\x06\xef\xf09A`\x12\x1eo9K\xa1\xf3\xe8b\x12\x9e\x98g\xe0N\xc5=\x8e\xa6\xf1\x11\xd1\x13f\xd8\x04tY\xb0;A9\xa3\xf0\xbc\xc1\x0b\xaf=\x01~'\x04\xc7gF!g\x06p\xec\xfd5\x8b{\xcb\xc9&\xe6_Qo\xd7o\xb9\x808g\xcb\xf2\x0dP\xad\x95\xfa\x90\x1b76\xb9\x8b\xf9\x8aCr\xcc\x95)\xb5u\xc0\xdb\xb6\xecv\xf9\x16N\x8e\xc1BdL\"\x97\xb7\x88v\xf6\xdc\xf5\xcau\xd1\x8a\xa0\xce\xc8\x04\xb2\xc9\xc2];\x17\xbb\x0bJ[]\xe4\xd8Am\xd7\xd0RA\xbf\xa4\xfa\x08J\x12x\xb0,\x9f\xcc\x06\xcd\x14\xd7\x87\x0b\x1d\xa80\xd6\xbb\n\x87J#\xb7\xfb\x81\x1b\xbfZ;\xea\xb7\xd6J\xady\x030\xef\x1199}3\x1f\xcf$Y\x0e?9EW\x9b\xb4]$\x80\x1b\x08\x14C\xa9\xf6{\xb2\xa7\xf6\x1f\x10\x03\xb5M\xad\x92\xe8\xeb\xe7)Z$\xa6\xe4\x92\xe472[no\x9f\xc0\xb9\x947O\x97\xe6\xdaH\x1b\x9fE\xff\x05\xa0\xb8M\xe1\xd1+\xb9W2\xd7\xb2[\x05\x83\x83\xde\x98\x89\x01\xed\xf4\xcd\xecz<\x9c]\x9bq[\xb7\xb3\xdf\xe7\x9f\x01H\xeb\xd2\x81Y \xbek\x92 {se=S\xdf{\x18b\x0b\xce\xbe\xb8\xbf\xdd\x89\xde\x80\xcc\x9c5\x9f\x15\xaa\xeb\x05l\x839MB\xaf\xed\x06\xb7\xea\xdc\x18w\x0c\x05tq\xdc\xdb\x81\xb9o\xc1\x14D\x14\xeb\x9d\xed\xcdB\xca\x85\xfc\x04\xfc\xb3\xf5\x06\x05\x04\x1a\x91\xc4\x8c\xc3Ia\xd2Z\xeb\x8e\xdb-_:\x8a\x0b@\xe8\x0f\x98)\xec>\xc4L\xa1+\x1c\x8ao\x1c\x80C\xc1\x00\x8b\xf6\x97\x84\x83\xff\x92@4/\xfe\xae\xe0\xed\x9a\xc0\xa3\x81\xbf\x8df$\x99\xa7.\xc0>\x02\xec\x1d!<\xacw(\xd0\xb2\x8f\x00\xe9/\xa3W\x10\xbb\x87\x1e@|\xc0R\xe4\x0fm\xf3\x88n\xa9U\xf6\x8b\xb7\xa2d\xc6\x03\xcbh\x0f4\x05\x8f\x0b\x1fDW\x8c\xa0r\x8e\xdb+}\xfb\xa7Efy\xf4\xc88)\xcfiz\xe0\xa6\xe9p\x83\xbd\xd1\xaa\xa6;Q?4^\xa4\x0b\xdd!\x87F\x83|0q!\x058\x1a\x8909DdHW@7F\xa0\xc9\xc3\xf3+Q\x0f\xc4\x15\x95\\e\xe2p\xabrD\x9a\xf2\xc0{Y\x8a\xa8$\x91Y1\xc5j7\x8f\x19\x97F\xb2F\x8a\xa4\xad!\x8a\xca!\x8aE\xda\xa8\x16\xe9\xb8\xf8Hi\x12\x9b\xd689\xb4\xce\x89\x83\x8a\x11\xd8\xa2to\xbe\x99\x90\x91n\xcd\x97W{\xe9\xcdn\xad\x8e E\xbf8\xc1\x03!\xea\xc1\xad\xec\xd0\xfcj\x8f\x7f\x82QI\xed\xf3a\xea\x13\x9b\xdce\x03\\\xb0\xe2\xea|r\xedw\xd8\x06\xc7j\xd3\xe7\x1b\x13z{M\xdf}\x18d\xees\xe8\xbd\x1c7\xc5b\x14\xc7#\xd7\xe9\x8f\xce\x12\x95\xda\x89*\xe3F~\x91}\xb6\xb5\xd6o\x15\xd0\xfb,\xf7\x08\x06\x96\x85\x8f\x1e\xd9\x89x\xe9t\x9d\xb7)\xee\xc3\x8d\xaep\x03\x05\x87\xc3\xcd\xc1m\xbc\x9d\xb3\xcdQ{w\xdf0\xc6\x8d1\x81lm\x03\xd0\xf9h\x9b,m\xa7\\4\xfb\xeb\xbc\xd2\xd6\xc1\x01\xb9\"\xf8\x90\xbdJ\x866\xe9J<\xa8\xf8\xafc\xb3\xb6K2\xf0\xe9^\xdb\x0dn\xb5\xd1\xed\xa1\x1e\x91B\xaf\x1a-\xedIA$\xceF$\xfb\x10\xb6{\x04@\xdd\xb8]A\x03\xac`3\xd8Z\xf4\x8d2m>J$\x1d\x8f\x13I\xb7!\xf8\x98\xfcs\xddlKK\x0e\x11t\x82\xfc\xd3\x89'$_\x9d\x07A!\x05pZe2\x92\x8f\x8f\"k\xf3\x8d\x1b\xf9m\xd6C\xa8B\xf4x\xe1\xb5\x1b}\x9d`\x0d/\x86\x86\x8d\xf4\x89^a\xa6\xf7\xc5#>\xba\x1c\x81\xd2\xa0j)W4\xd9gE\x1f\x89E\xfb\x03\xd8\x12\x14\x13\x14M/\xdd\xc5\x18\x91\xf6\xab\x08\xb9\xb7b\xa7\x91\x1bu\xdfF\xd8\x82\x81\xd1\xbd\xb9\x8d\xb0\x05\xb0\xf4\xf15=x\x1b\xa1\x08\xee\xbe\x08`X\x83oW\x1d\x8adT\x1e\x8du7d%%\x0ciCX\xd2\x05i\x89\xd9F\xa0\x18\xb2\xb1\xfdW\x02\xfb\xcb\xfc\x02^\xd3\xb1\xe2\x01\xb6s\xb0\xac\x83\xf9\xb4\\\xf8\x03\x1a]_x\xb5\x14\xe4\xa5/\xdb\xee\x0f\xfa\xda-\xf0\xa6\xc8j\xb3f\xb7T\xa5\x8e\xd6<\xe3\xb4\x95\x82\x8d'\xd0\xc9\xc1a\x90J\x17@\x1e=\"t8\xcc/\x88t\x01\xadn\xec\xd3\x06\x9a\xef\xbe\xfdP\xca\xfc!\x92\xf8:x\xb8\x80\x1ch\x94,H\xc6\x9b\x11\xb9\xff\xc7\xfd\x04\xe7\xfd\x04\xef\xa3\x1d\xba6\x8a\xcb-\xdb\x87\xe2\xfd\x04\xb7\x91\x9a\x0f\x1e\xb6.\x8d,\xaf\x8f\xc5\x07\x95s\xf1\xd4\x11=\xceZ\xf37\xde\x14\xcc}\xce\x0fP\x13\x12\xd5\xaaE\x9dH#\x19*\xe8\x90R\x971\\\xdb\x0d(\xeb\\O\xc9\x7f>^\xba\x82%o\xd51>\xb9$\xf4\x82\xf8m^]\x88\xa1Is\x1f._\xa5]._\x99_\xdc\xc1\xbb\x0b9\xe8\xe1\x858i\xa9\xf9\xe9\xcdM\xd7\xfb\\\x9aN\xe0j*\xda\x0c\xa4\xcd\xd2b\xbe\xd0\xd3\x11\xe1f\xf1\x15\x97\xca\x01rSYzu\xa2\x03K\xc9\x1d\xf5\xa8\x8b\x19DY\x8c\xaaQ\xac\x8eP\x1eV\x96\xf3CMw\xb4\xc1\xfb\x85\xec\xef\xf2an\"\xeem\xe3\xdc6\x86\x1f\x8d\x88\x1d\x8e\xb0r\xfe\xf4\xb9#\xc0J\xd4?\xff\xb4\x92L\x1b\xe2\xae\x08vgbc<\x9d\xba#wD\xec\x16\xa7\x1as\x9d\xbbs\xb1\xd4\xa3\x89\xcd\xf4\xd4\x9diE\xbd\x1b\xe1{7&\x8a\xcb\xd3\x86`!k\x16\x98\x1c\xcf\xdd9\xfc\xc8\xd6\xf1\xc2\x9d#\xa4\xdc\xc4\x1ay\xda\x10Q\x86\x85\xc9\x8e\xa6\xbe\xad\xe93w\xb64[\x99\x1c\x9f7\xe5Ht\x8egg\xee\x1c\x81\x1f\xd9^?k\x18h{\x95\xc4\xac-\xcc\xdd0\xe0\xc5\x8b'&k\xc3\xb0S\x1d\x1e\xc8dk \xd1\"\xa8 \xe4\xf2\xaca\\Y$|qo2}\xd6%0J\xf6Q\x02\xa3\xe4^\x90\x9c\x81Q\xa8 \x8cB10JE\x11\x0c\xd9\xf7\x18\x81\x99}\xebG7\x8a@\x17\x16i\x1d\xea\xb4n\xe9\xb3\xb7\x81t\x91\xd8\xb7E\xcc\xd5\xbc\xc3\x1c\xc6\xabb\xbe9z\xf9J\x8d\xa1\xafXI\xf1\xf8f\xd63\xf1hU\x89\xb9\x0d\xa6\xdb\x1b\x15\xe3\xed\xf6\xc0H\x0bM\x9c\xd6T\xd0\xde\xd2\xd6 \xcc\x11\xce\xac7\x98\x9f-]\xe6:Y\xc5\xe7\xf5kE*[=\x86C\x9fG\xc6KLa\xd4KQ]j\x88\x02\x8ez\x8d\x8e\xac\xf6\x15u\xafI\x9c:4y([y\xd4\xdb\xb1\x7ff\xa2\xef\xc3\xe5\x97\xb3\x01\xe6W\xe8R\xd1o\xb9MP1l\x03b\x8f \x97$\xbe \xa2Mx\xe2s\x01\"\xcbI\xc1g\x08\x04\xe2\xd2\xa0\xfc\xa0@\x19!\x10\xce3\x86$N\xf1\xdeb={)w>\x17\xefG\xa5\xe90\x1b\xfd\x8e\xfe\xdb\x0fNIy\n\xf2!G\xf7\xf40\x98\x97\xc4o\xd6\nF8x\x91q1s\x02\xc3\xc9\xe7\x11\x8e\xd3t0\xc0}\x84{W\xd6\x18\xe8\x187z\xaa\xf5\x97`\xef\xd4z\xbb\x9dM\x12\x16\xad\xfdh\x8b7\x04S\xee\xcd\xf5H/\x1b\x06\x95\xe0d\xe8R\xa0\xf7P\xe4\xe1;L\xe8\x0f\x9aF\xff\xd8\x802\xcdaO\x1ct\xc7\xeap\xfcF\xa7\xdc\xd9\xaf\xc8\xb1bB\x9dd\xf1:\xc2\xa4\xb7\xbe\xf0v\xc4mw\xed\xd1\x94\x91\xe9\xd9\xcc\xfd\xe1\xf3\xf3\xa6\x0f/\x1a>m\x1a\xad\xa7\x9f65\xdf4(\xd3\xf3\xc6\x91o\x82\xebE\xd38>w\x8c\n)\x98\xd29vbk\xb6\xa1Y \xda\xcb5\xf9S\xeap\x94\xd5H\xec\"\xcb.\x80\x1c\x192\x06T\x89\xd7]7G\x83\xc1\xc5@\xd1&'G\x8e\xf4e\nE\x82\xd4\xb6L\xe8\xbb\xe2UJ\xa3\xad\xf4!\xa3Z\x87\x83Q\xce\x82\xca\xf6\xe2\x1f \xe2w\x1e\x8b\xaa2\xc8\xc9;\xa7\x0d\x17E\xe2v[?=\xbc\xd8\xff\x82\xf1\x81\xd1#\xe1h\x8f\xc8\x89p;\x9a\x85\xd3\xcb\xb3\xd2\xf5TSYyV\x9c\x88ck\x98\x1e\xacA\xbb(9\xa0\xc6\xb0\xf4\x19U^>\x9eS\x12\x7f<>\xac\xb9\xb0~\xd4\x1c\xcd\xfb\x9d\xd4\x189\"\x15\xab\xc9\xedE\xce\x14+\x1e\x92iC\xe8\xd9\xe2\xefC4\x1d\xec\x90\xfe\x9d\xe4[\xe1\x1d\xe5kh\xabE O\xdaw\xbd\xc5\xdf{\xf70\xd7Xzi|\n1SG\x87\x81\xd7\x80\xa7\xf1F\x1c\x02\xbc\x03\xd0N\xa3\x11\x0d\xeb\xc1\x13\xb7C0\x1ch\xdfiv\x17\x0f\x87\xe8\x19\x9a\x93\x96;\xdf\xb1\xa2rq\xe3\xfd\x1b$U\xf1\xc7RF\xd8\xa5\xc5\xb59\xb8\x0e\x9c\xa2\xc0<\x7f\xfe\x02\xfdP\x13\xbd\x19;+\xf4\xaa\xb7X\x9c,z\xbf\xfe\xe4\x9f\x1e=\xee\x0f\x9e\x0cG\x93\xd3\xd9\xc5\xe5\xd5\xcb\xeb\xdf\xcc\x97o\xde\xfe\xf9g\xf9\xfe?\x8f{f\xe3\xd2\x1bt\xbboQ6\xb4Z\x92\xabb$\xa9\xca\xe5\x8b.d\xd5\xd2\xd4\x96\xad\x8a\x92\x9bk\xa4\xf3\xf3\x06\xbf\x8b\x07(\xeep\x18\xe3\xc5\xdf:j\xf9\x8d\x8e1\xf1\xb6\xf0\xf9\xf3\x17\n)\xcc]\xb0(\xbf\x88\xd0\xc4\xc8\x8c\x8fg\x85\x10\xc3+r>r2w\xcd?\xb4\xc3J7\xca\xebM\x15\xf8\xf4\xea\xb6B\xbb\x90\x96N+\x14\xa2\xf2 \xb6\xf9\xc7/\n\xf3k]\x1c\xb6\xb1_5\xbf5\x0fuo\xb1\xe8\x99aV\x1b\xc1\x8f\xb3\xea\x8eE\xe4\xd29F\xb3\xa0\xa0c\x89\x1c\xe3*\xc8\xee \xb3\x11\x01\x0f=\xbc\xb4\xa1\xcc\x0c\xb5\xfa\xfcE\x93+\xa1\x8b\x81*\xe8\"w\xa4,rE\xe8\x12\xc3\xd7\xc1_\xb3\x0b\xb0\x84\xac\xdc\xa7)D \x81\x93\xbf\xe6\x8d,\x85sx\xb8\xceH\x0fAIU=\xd4\x85>>\\\xc0\x19+\xa8\xae\xf2\x00\xb6\xe5\xc5\xd7\x85_4\x84\xed!\xa4\xd9i\x85_\x08\x93?'\x8bh9\x04\x93]\xd2k7Q1\x91|\x9a,S\x0e1\xa6\\\xde\xa5\xb5u\xd2uU\xc4E\xca\x93G\xfd\xfd;Z\x1cJ\xb2\xadu>m\x91\xb1\xcf\x1b\xd6N\xdaN\xf2\xdb\xed\xd7R\xf4^\x06w\x91[\xb257\xfe\xcb9\"\xf3u \xce\x94\xbc$g\x18\\\xa0\xda6\xd8.\xcf\xc0)\x96\xd3\xa7\xb9\x82\xee|0\x02\x03\xca\xab\x83\xd7\xdcL\xaef\x9f\xe7~\xee\xed\x8c*\x9c\xd3|\xab\xb9\x00\xd0\x01\xaeC`\x9ec\xdc0\xb8\x99n\xda\xaa\x81\xcc\x15!\xa8\x05\x0d\xf3\xd1\xa74T\x93\xc7O\xb2\x08\xce\xc9\x98\xa4\xa3FF\xacWt:\"\x1c\x0f\x89\x1c@\x9a%\x97\xe2A~\x8c\x8e\xe4u\x0b\x10>.k\xf4v\xdd\xd8\x19TC\xb6\xf6\xd7\xb6\x80\xceH\x9c\xf7\x161\x0f\xda\x0dY[Xj\x96\n\\\xd2T\xc3\xea@\x11\x9b\x01\xd1\xc4\x82b\xef?\x9a\x8d\x17\xbc\xd8P\xa8\xd7$\x1e\x8f\xc9\xcc:\xc1/|\x84\xe7\x18\x1d6]\x82\xa7\xe7&\xa1%\xfa\xc0\x18J\x04wSxjou\xe6}\xd6\xc1\xd4;\"\xd7zF1\x06\xaa\xd6%T\xe6\xd8\xa2K\xbb\x15\nk6 m3\x8c{\xef\xf6\x98\xd6\xb6\xcb*\xb4\xf8@\xc3\x97\x02\xef\xb0\xdd\xd7\xd6qv02P\xa2\x90Y\x01\xe7A\xad\xfco\x963h\xdf\xfd\xff*\x8c\xa1\xb1\xed\x7f\x13|\xe1\xd9\xd3\x0elAg\xfa[p\x85g\x0d\xee0\xdb\x98\xc2\xc9\x95\xae\xe7\xef\x8e-4\xf5&\xe7\n\xad9\x8e`\n\x1a\x0b\x1f\xce\x13t\x05\xff` \x9dX\x82\x1f\xa5\x7fc\x96\xa0Z\xfc\x07K\xa8\xfcZX\xc2\x8b\x06w\xc3\x7f\x0b\x96\xd0\xd8\xf6\xbf \x96\xa0\xdd\x9e\xb5\xb3\x04\x9d\xe9o\xc1\x12tS\xffNXBSor\x96\xd0\x9a\xe3\x08\x96\xf0b\xfa\x81,AW\xf0\x0f\x96\xd0\x89%\x84\x94\xdf\xfc\x8dy\x024\xf9o\x8c)\xd8\xe46\xd3 \xb3f\x89\x0d\x00\xc50\x00\x14\xa8\xfaT\xea\x8b\xe76\xf5\xf33\x9b\x8a\x9e\xe9X\xd53\xdd\xd1Q\xb9\n\xfeR\xeb\x03\x9b\xa1-}-=mH\x0fZY\x98\xe7Z\xc6\xc2u4\x85\x97\x0c\x1a\xc8\xbb\xc8\xc9;\xeaZ\x03\x18\x89j6\x8a\xa1\x95=\x97\xaaU\x0f:\xdc\x16\x81\xd2`5\x0f\xf7\x9a\xfa\xa8\x10\x1e\xeb\xab\xa7\xcf\xc85\x8c\x02\xf4x\xaa\xf0\xe3i!\x9a\x1f\xb6\xee\x80\x91\x16U\x10H%bt;o\xda\xd1\xd5D\x85\x1c\x91u\xe1\x0c9>G\xa7\xb0\x1e\xc0\xc7\xfb\xda[\xad\xad\x80\xf7\xe3\xdc\x15\xf3\xc9t\xa0\xd0\xbc\xbe|<\x1a\xc1J\x9d\x91\xcc1!4\xc25\xe5t\x07\xbff\x81\x1f\xa63\xe27\x10\x97\x07\xd8Z\xe4RO\xf5\xdap+\xe2l\x9a\x0f\xce\x12\x17Nm\x06uF\xa9C*&\xb0\x01\xc0\xb1O>@\\\xfb\xbb\xdcW>z\x84\xfd\xd3s\xa4\xbax]7\xb7\xb0\x01\x05\x90\xad\xa3C\xea\xd3\xfe\x1b9\x7f\xb3X,\x07\xfd\xc5b\xb1\x18\x00\x83>9\xcc\xf9U\xb6(?K\xd5\xb1\xf8\x80\xcc\x18s\x08\xe3\xdc\xd4\xde\x07}p\xfc\xe1\xc0O\x9du\xe0\x87+2_\x0e\xcc\xee\xac\xfe\xbd\xe0V\xd4E\x0e\xe2\xc3\xe8Xv\x0cR\xa7\xcb\xeb\x87\x84\x8d\xac\xac\x1b\xdc=\xd6\x1c\xa1\xba\x17S\xbd\x93s\x7f\xa9\x06\xaf\xde\x03\xa8p\x96W\x9d&\xb8\x9d\xa9H\xfe\x95%ZXCqm\x07\x90\xd9\x08x\x1fc1\x1d\xbbhJa/\x9b\x17M\xcbU\x1d\xc5\xba\x9e\x92\x97\x07\x8c\\N\x1c\xf8ZM\x83 \xd6\xad\xb54EGo\xb9\x16\xd4\xa60\xc8~9K#k\xa7\x93\xe5v:\xf4\x82\xf0\xe3\xa3\xa3\xf3\xc3\x81\xd7\xa6\x0d\x02}\x87\xa2M\x81\xd5y\xf7\xc0\xeahG\x04\xfd\xd4\xe4\x8e\xab\xe1B\xd7\x8a}\xae\x96cT\x11k2\xe3\x05\x10\x05#-\x12\xe1\x1c5\xc65\x8f\x96\xcd\xe4\xaf\x1bMk\xaf\xfc\x12D9\xad\xaah%|\x0e\x82\x11\xbb \x86\x8e\x98\x1e\xb9\xb4\x08Y$f\xe4\xacN8\xda`\x84\xa8\xcd3\xe2\x82\xb1\x94\xb1\x99~\xcf\xe3\xe5\x04\xdan\xec\x08~\xd6\xd2\xc7\x87R\xf2\xd8\xc1\x80\xb3\xd57\x0f\xa0\xf1\x05\"\xcaK\x04\x94~\xc4\xc0\xe4\x05Y\xe4\xecY\xd5u\x99\xd1\x99|\xe6\xd0\x99\x14\xe2\x8a\x9e\x8d?\x9f\x9c\x80\xf2\xf4\xc9pqzum\x15\xa6\xc3\xdf\xe49\x96\xfd\xebY\xfe6^\xfe|6z1}_\xf8>\xb8\xee_\xcf\x16\x93\xa3J\x0c\x9e\x0c^\x9e\xd6\xf56\x05\xd8&\x8b\xf1\xf2\xe7\xe9\xe8\xfc\xf9\xfb\xc1\xac?\x7fs\xf9rqwv6^\xdc\x9d\x9f-U\xd9\x87\xf3\x91\x92n\xa7U\xc2z\xd1\xa8}\xd0\xd4\xa3_\xa5\x16\x9b\xa2\x13\xaa\x97\xbd\x82(\x04\xaa\x90H\xab\x0f)\xb8\xab?\xe9s\x9b9\xab\xc5\xa1,\x94U\xbb\xa1l~\xb6\xd4\x8dL\xf5\xd5~\x0f\xac\x08\x02\xb5\xe7:\xb1\x02C\xd1/W?(\x8ba\x1dd\xef\xd6\xfd\xc3\xc1]Be\x1d\x1c^\x96\x02|\xe69(\x8e\xd6[\xba\xc2S\xb2\xaa\xe3\xc3\xa3[\xed\xb2\xcb8\xb0\xb2\x87zF\xf2[\x98\x03E\xedN04i\x94\x874\xb5\x13\x986M`/\xa4~ b \x87m\x93\xe9\xfdc2K\xbf\x8f:\x99iu2?\x0e\x91.\xd2\xa6y\xcf\x8b1N\xe7:\xf6\xeb\x8e\xe8(\xa5\xfa\x0fD\xe6\xa4\xab\x18CwR\x0f\x0b\x99?>\x04\xd6\xf48\xfe\x05\xb7u\xf0\x17#\x94\xfa\x18\xffs\x0d>\x1d\xads\xbb\x8d\x80\xb2[\x16\xc3\x1f\xfdo\xb2\xd3\xd1E\x9f\x9ec\x04R\x81\xd9\xd4_(\xee\xd3;\xf8\xa3\x9b\xf6C\xfcW\xbfE\x1b\xa8\xc7O\xf0\x95\xfb\xa9\xf9;Y1f\x13'w\x89W|\xces\x05\xb7\xef\xd4s\xb0\xc6\nq\x19\xc0\x13\xf6-Lyb\xfeB\xa9P\xfc\x84 Y\xa2V\x85z\x8c\xd8-|\x8a6\xf8\xc7\xc7\x7f!\x16i\x14a\x7f\xe2\x84\xfe\x94\xb1 \xf6n`+\xa4\x92\x92\xd8DD\x85b\\\xa4\xf0\x9e2\xbe\xf7=\x86\x8fij\xe2\xa1\x9a\x81I}\xb6\xc7\x8f\xbe~G\xb8\xd2\x10\xffD!&\xc74\xb1C`_ \x0b\xfa\x84\xec p\xca\xa9\xfeD\x188V\xe8\x19\x12;?\x0dY\x9a\x82\x06\x8a\xf4D\xf4\xf4\xfc\xd33x\xc2\x16\x05\xccr\xc6\x01\xae=\x0bC\xe8/\x0e\xc1-\x86t\xbd\xf3\x10j\xf5w\x9c\xa5L#\xca]\x18\xf0\xc4\xb3`\x15^\xb1T\x88\xd3\xf8\xee\xe9\xe7\x93\xe7g<\x7fDd\\\xfbYx'8b\xe8&\xc1?\xf8 \xb1\x82j$\x16\x82z\xbb\x90E\xf8v\xab\xfe]\xb1tG1\xf4\xec\xca\x17^\xeccX\xde8\x80\xb9\xf6h\xa0g\xdd\xdb\xf1\x18\x83\xda\xe2\xd3\x98\xdd \x16\xa566o8f{\x16\x89\x15\xf7\x05\x1bS!X\xb4f\x98\x1d \x0c<\xee\x01\xa8u\x10\xd1q\x12\xd0\xfb\xd4\x8f\xb6\xda\xbf\xa3IR\xb9\xa9\x1f!\xea\xaf\x05T\xbe\xde\xaf\xd4\x1f\xb6>\xbfQ\x7f7\xd4c\xc2GX6\xcc\x84\xf9\x8d\xb6:\x84\xaf\x9f\x02zma*\xb7\xbe\xc0?\xef\xc28\xe1\xb1 \xc0\xbb\x154\x80\xbav\x1e\xae\x04=+~\x82\x7f\xb8^\x13\xde\x0b\xfd\x17\x97\x85@L\xfa\x91BK?\xe2\xdb\x0d\xbbO(\x16\x08h*60\xe0j\xd5\xe0\xa2\xa0[\x8dD\xa1M\xe17:%G\xa5\x10\xeb\n\xd3\xf1\x8e\x05zYE8wa\x16\xea8\xbf\xe1\x1e\xa0\x03\x19[=\xc4\x88; \x0dB\xfc\x9bPN\xdf\xbd\x03\xa4K\x02*L4\xe3\x84\xc7w\x10\x1f8I\xef\x01\xce\x9f2\xc6!\xc1,0\x96\xc6\x19\xc7\x95\xc5\x11iyz\x1fA^.\xf4\xb2a^\x1c\xad\x03\x7f\x83KL\xaf\x88t\x8bk\xf0\xe6>\xc1\xf4\x10\xa6*\x8d\x835\xc5\xc0\xc5I,\xfc\x0d4\x96\xe2\xc4\xa4\x82Q\x00+\xc5\xee\xa8\xd74\x01\xc7)\xb0\xc2\xa2-\xc0\x94\xad\xa1\x81,\xe2\x8c\xc2r\xcc\xc4\xf9\xd9\x19DaVx\xc6}D\xd0\xbd\xcfn\xc79\xf4\xb7l\xe5a\xf6[Aq\xf5\xdd{\xfe\xed= \xc3\xdd\xc6GD\xbf\xe3\xf0\xe9>L\xb7\xbc\xb7|8\xff( \xf9\x9f\x0e&\xbf\x7f\xfd\xea\xdb\xb7\xaf\xbf\xf8\xe7\xb7\xdf\x7f\xf5p\x01\xb8\xa2Eq+\x17+A\xf8I~CE+^\xc8Ic0}\n\xc7\x1aE3\x05\x14\x97\x9f\xea;\x8dN\x97\x0e\x06\x17\xa7\x15\x8d\\\x8a\xe5@u\x04\x98\xac3?\x9d\xbeW\x99\x1f\xce*\x8b\x97v\x1c\x04\xab\xc0\x0f\xeb\xfa\xf8\xa7\x9f\xb9\xb9\xa3w(Z8\xde8\xdd\xb8/\xa9<}\xee\xd6Iy\x9a}\xbai\xa6\xbf1f(9\x93\xf1\x0c'+\x1cI\xa0rA\xf1\xe7\xde\x1dF\xaa \xe6\xd3\xa5b %\xdd\x14\xb9&\xa0\xa1\xf8&\x12}\x95\xc1\xe85\x06#2}\x01\x01\xd6\x8b_Gd\x8aa\xb6\n\x97\x81\xfc~\xa4j\xa1}\xa0\xcc\xb4\xff\xe2\xf9\xf3\xa7OK;\xf2\xa0\xcc\xb6\xea\xc4\x1am6\xc0p\xa8\xb1k)2\xe9X\xf1\x01\x05J\xb5\xa7%\x98\xf8\\eY\xb6\x00\xe1\x14\x95\\\x0e\xec\x1e\xfd\xc2\xfe\xeb\xca\xb3\xac\x05\xb5\x99c\xf2\x95\xe0\xe1\xf6[v\xa7>\xfd1k\x88\xca\x01\x07*iC\xc4\x0e\x1am\xbf\xe3l\xe3\xdf\xcd\xd4\x8e$\xdaft\xcb\xc6.\xed\x8b\x1f\xdd\xf8\x9b\xfb\xc6\xf8*7\xaf)\xdf21sJ\x03\xe2>\x89!\xa8\x08\xe3\xee\n\x809\xa63\xd2\xfb\xeb_\xfe\xcf\xbf\xfe\xe5\xff\xfa\xeb_\xfe\x8f\xbf\xfe\xe5\xbf\xb8\xd4]\xfev\x17`\xfc\x91(\x0b\x1cJ\xa8\xfc\x8clF\xce\xab\xa7\x1c\xa5W/\x0e\x938b\x91p\x8e\xb5\x17s\xe6JW?\x9e\x05\x10\x8a\xa5\x07\x9e\xe4z\xa3<\xea\x8b\xda\x1c\x19+\x19|\x03\xc9E1\"x\xd7\x83\x88{\x1f\xca\x05v\xbb^\x8e\xaeV\xfc\\=\xd8\xa3\x0eA\xfd\xa0\xe7\x08\x83\xe8\x98mto\xd7\x05th\xbe72\xce\xf7\xd4\x06\xd9@`\x1aV\xcf;F\xd7\xc8 {;T2\x890\xb0}\x0f\n\x9fu\x90\xbeB\xd0\xa6\x91\x8e\xa5\xdb\x0dv\x1c\xc7\x83\xc0\x17\x02w\x94b\xa7\xe8\x00)\xc5\x00&y\\\x8e<\x14K5FH!\xc2\x87\x0dHR\x08\xef\x82\xbaP\x07\xfc\xbfr\xbf\xfd\x83,\x14?\xfe\xbb$\x0b-\xcb\xae\x0d\xab\xff\xce0\xc6q\x1d\xbe\x801\x8e\xaf\xff\xc0\x18\xf8=\x04cj\xe9\xe4(F\x82\x0c\xa1\x13\x0d\xfd8\xf4\xffCh~'0?\x94\xd4\x1f\xa2\xf1\xff\n4\x1d\xb6]\xf9\xd2\xe4\xc5}IU\x98w\xaffS\x0b\x83#&jf\x1e\xfez<\x8e\xeeQ?\xbf^s\x86\x07\x04\x943\xcc\xc5\x85\xef\xa1\xde\x97\xa6>N&\xcd\xd6>h=A\xc9\xbaZ\xfb\xf8\x07\x93|\x18\x99\x95\x1d\xda\x12:\xac\xe25\x8c&\xb6\xbc\xca\x84\xd0z{\x1a\xed\xf1D\xcb\xa3\x890\xca|\x16 T\xa6{~\x19\x9b\xbc8\xd0\x7f\xb6<\xce\xf0\xc4+W\xef\xe7\xa7]\x82\x1a\x1cZ\xe39\x18\xf3bNE\x8cZ}d\xe9k\xa6$ d\xf2\x1b\xd4\xf3\xfb\xf8\xdd\xc7\xc32\xcc\x05\xb5\xb0\x80\x99S\x0b\x06\x03\xb6\xf1Y\xb0N\x99\x8e\x11\xb5-\x00\xbf\xf1\xb7\x19\xd72\x01\x96P\xb2\x81>\x1b\xd0\n\xf1\xdd\x14\xfe\x05yl\x87\x87k\xa0X\xde=\x87\x7fA\xe9\xaf\xd6\x83\xf9\xab\x0f\xe2l\x9f\xf3\xf5\xa3\xfe\xc2,\xf8!\x0c\xbf\x1f%x.\x88a\xdbz7+\xa8\x04\xacw\xe0\x81mY\x84IP,\xa4x\xde\x12\x9aC6\x08\xe5\xa6\xfe\xfe\x94\xe1\xf1I\xc8\xa2\xcc\xfc\xf5\x05\xf6>d\xbaC\x11\x9e+F1\xce+\xceN\x9c\x08\x0bil\xc7%\xce\x84\x06\xcd\x9c\xad\xe1\x9fxk0\xef'\xf5\x0f\x9e\xe9q\xc8\xc8\xb3\x15\n\xb6\xf0\x0f\xb5\xe7\x00\xa6\xca\x94\x05\xfa<%\xdd\xd1u\x0c\xc7IiH\x03\x80\"\xd7\xc9\xa7 \xf5\x10\xdc4\xa1XPp\xff\x86\xe9\xa7\x18\x89N*\xee\x11\xdb1\x08]/\xcd\xc2\x90\xe2)\x05\x06\x9d\xd3R\xa7z0\xd8,`$\x05\x0b\x93@\x1f8*\"`V\x90P\x13\x0f\x0f(\xb4\x9a\x195gG\x82\xe3\xbf\x14)\xa0\x80\xbc0\xd6\x19\xf4`\x8f\xc7<{\x7f\x8d\x07\xb3\xb7+\xdes\x04\x8a\x03\xa3\xb0^\xba\x87^\xe0\xd2\x0d\xc46\xb8GQ\xd9<\xafQ.5\xaff&i\xe4\x87T0/\x0epm\xe8\xf706c\xac\x13\x04\xa7Qj\xd0\xd7\x92\x81\xc2\xea\xf5\xb9&\x16^\xe0' \xc5.\xaf\xd9F\x0b\xd1)\x9c\xe5\xb0 \xf0\x93\x14\x17\x87\x1f\xd8E\x81\xcb\x04\xcf\xcb\x0c\xdc\xf0`\x84\xe9\x1b\x86G\x9a\xda\xf6\x1e\xe8\xaf\xfdK\xf9\x96\xd3\xb5\xaf\x97'\x9cnq|J\x11\x97\x99\xa0\x862\x84\x06\xb2\xc2_\xa1+O\xe2\xe0~\x1b\xdbG\xcb5\xe9\xda\xa7A\xb1 n\x90N\xe01q\x8e9\x10\x01\n\x9e\xee\xc3U\xac\x0fq\xef\x84\xf9k\x1a\x05\xabzx\xd0\x1d\x14\x061\xed\\\xef}\x06\xe8\xbc\x87\xae;f=\x82Y\xdf\xb0\xdf\x06z=o\xd8\x97j\x12_Q\xc1\xfd;\x93\xa0\xc5\x88\xd70{z\xb819\xd5\x94U\xbdF\xfb8\xd8\xb3b\xc9\xdf\xf9\x9bM\x96\xb2o\x958\xa3\x99\xb2JL\xed\xde\xf3\x15\xd2\x0bH\x144\x12\x90\x13S\xbe\x0e\xe2XC\xf4u\x16y_\xe4\x8f\xbf\xcd\x1f\xff9\x7f\xfc\x1e\x1f\xff\x99fi\xea\xd3\xe8\xb7A\xa6\xe1|\xc5\xf8\x96\x15\x1e\xff`E\x8aW1Ovq\x10o\xef\xf1\xfd\x8f\x9b\x8d\xa1\xc5\xa87,\x80\xf3C\xc2\xbc,\xa0\xbc\xdc\x97\x1f\x92\xb8\x98\xe9\xb5\xb1\x84`\xaf3\xbe\xca\x02%\xb4\xb8F\x1d\"r\xf4B=\x8f!\x8b\xb4e\x89z\xe6\x1c\x97P\x08\"\x0f\x9a(l8\x05\xc4\x0f-^\xe3\xe9f\x08\x04\x99\xad\x91\x04\x84a\x16\xf8h\xea\x81\xa7\xb0H\x92\xd1\xd8!\xdektN\xe8z\xad\xabMv4\x121\x92b\xae\x89L\xc8\x91\x00\xea\x83\xdc\x04\xa8\x1e&\xfc\x84\xe44\xbc\xb7\x98\x1aj\"\x17j\xd2\xa6\xde\xcd\xa3%s!\x92\xb7\xd0\xa0p\xa8\xa1\xcd\"\xcd\x90\xf0 \x00t\x8cU\x0cc\xf5k\x14\x8b\x1c\xd2\x1a\n$\x9e\xc7\xb4m\x80%\xeb4\xf0\xb7\xfa\x01\xbfd\"V\x12q\xc0\xb4,A\xbd\x1b\xc5`\x10\xefW[K\xbcV1\xd7\x90y,\x08\xd4x\xe9\xf9V\xafj<\xcc\xeb\x8ey78\x94V\xc0\x08(2!/`Hvm\xad^\x8cB\x82\xfa\xab\x97\xa9\x17\xc7|\x8d\x89\x9a:A3\x8a!\x8cW4e\x86g\xd2\xd436>\xe6L\xcf \x84M00\xd3w~\x98!`\xaa\x8a\x8d\x9a \x16y\xf7&A\xd59Nw\xfe\x06\xea[1\xbd\xd2V>\n\x1e(!\x16\x96/ZB\xa9\xbfc\xc3o\xe1E\xed\xffz\x95u\x1d\xf3\xb1Z <\x89\x03j7\x1f\xf5\xe41\n+i\xfe9\xe1\xb11\x9e\xc3\x04\xce\x14)4\xf4\x05f\x07\xbb\x80\x8b\x1d\x12Pf\\#k\xf5\xe2\x08\x18'&\xf1\\\xa8]\x03\x97\xd5Y\xf7~\xaa\xf7,\xc8\x14\xd9z\xcbB\xcd\x06Y\xc0\xf6\x16j#\x04\xf8(\xfc\xaa\xbf\xe3XQ<\\\xf9\xf0nF\xa0 z)V=\xb6#\x82\xaf\xc5bq$\xc6\x1b\x1a\xfaA\xfejP\xdb\xbe\x8c\xe9\xfa\xc7,\x15y\x9a\xe0L\x8bA\xfa]c1\xbc\xed)\xf7i\x94\xe7\xbe\xb5h\xb6A\xd9\x03Z\xda\xc2\x06i\x0b\x1b$`\x9dc\x83?E\xb9\xd0\x08eY\xe4#\xe34 %i\xb5@8u9M\x1a\x950Y\x9e8D-?\x82va\x99\xdf\x00 7\x98\x00;\xb5\x1b\xd8\xa9)\xb1L\x17\xbaa\xf7\x89\x929R\xfd\x92&\x10X]\xbf)n\x00\xcf\x96\xd4\x02%\xcd\xc7,`\x8a\xd6\x8d\x0b\xecI\xd5\xcd\x82\xd0\x8ac\xf8\xae:\x99S\xe1@K3\xf9\xe4\x05\xb16P\x1c\xb3\x84\xef\xbc\x1d\x8d\"\x16\xa0\x00\x84=\xbdw\xa4Asw\xd0\x8f;\xe8\x07\xca\x1f*7\xfc\x03_\xee\xe1\x0b\x18|\xbf\x8b\xe3\x90Fk%09d\x94\xac \xa3\xf4P8\x81U\xaa\x97\xb4\x15{Vl\xcf\x02-k\xdbM\x9a\x17\x07Y\x18\xa56\x13\xbe[r\xad?kQm\xcd\xa28\xb4Y\xd7,\xd1:\x0d+\xcb\xe7l\x1a\x1es>\x07\xbbG\xf5\xc05ykbA\x81\xc2\x1f-q\x17H{\xc4\xc4\xce\xf7n\"\xad\x17\x0b\xecV.\xb0\xfaT\xb5\x05-\xef\x83T\x8a]g\xea\xc50j\xf5\\\xe0\xba!\xbd\xb3_\xfc\xc8>\xc6{\xb55\x81U\x03\x8dFqNL\xa3,\x1f\x07#\xad\xf3\xf8\xd6\xa6\xf1\xf8\xd6\x8e!\n\xcc\x06w\n\xe23\xb7\xbd\xe0\xb6\x17\xb8\xe7\x05\x03\xc5\xfc\xb5\x00\x95\xde\x13\xfb\xef\x98\xde[\xf8Z\x8f\x07\xe8e\xb5\x80 \xb5L\xc2\xbeh\xe2\x03\xa2\x88V\xe2\xe9 \xffV\x96L\xb3\xa4\x9ar\x1f\x86Lp\x1f\xe4\xf1}N}\x0e\x8b\xcex\x83\xe3.\xf0\xa3\x9b\x99\x99\xe3\xbb0\x98i\xebzH\xb7\xe2\xba\xfa`G\x03\xaa\x9cA\x8e\xde\xb2`?I\x8a&\x8f\x81\xd3\n\x89T#7\x9b\xab\x9d\x17$\x1a\x8f/\x06\xa8\xe8\x8c\xb6=ru\x05\xa6\xa6\xf1\x86\x88\xb9\xb9}:\x87[\x98\xeaO\xe5f\xd9\x88\xb0\xb9J^6x\xdf2\xa6\x9b\x95\x83\x0d7\xe4^\xbb-\xae\xebp\x93h\xf5\x16^\xa6\xad\xb7\xaf\xbdc\xfb\x11a\x03\xf2\xc7\xd5\x8f\xcc\x13\x85\xf0\xf2;\x9a\xfe\xf16\xfa\x8e+\xd1A\xdcO<\x1a\xc0\xe0i\xcf\xd1\xba\xd7l\x1e-\x1d\x9eT\x8c\xc9N\xc3\x91\x0d\xd1\x80o\xc0\xbb\xdc\xcf\x8b\x9f\xe7\x8bt\xf1\xc3\xf2\x89\xd4\x7f\x17\xef\x17\xefO\xb7a\xbdG\x89*p\xf9O\x95\xec\xff\xf4\xd2\x99y\x0d\xd6jk*\xe8x\xbe\x18/n'\x8b\xec\xec\xec\xb7\x9f\x8e\x17\xd9\xd7_\x7f\xfd\xf5\xf2\xd4q\xf2\x08%\xd4\x12\xc7\x12\xcb\xe1'\x8e\\{\xc8\xd5\xbf\x9e\xe1\xff\x1b\xb9\x13\x03\x91\xa4\xd7\x12o\xd6H\xc1\x02\x89\xd7-\xa4\xe7\xaf\xe5]\x98$\x83\x99\x9c\xbf\xa1\xe3wK9\xa7\xe3w\xc3\xc9b\xbc\x1c\xf6\xafg\x90\xa6\xdefK\xf9\xc9`P5\xb7#\xda\xb3\x154\xb6\xb8\x1d\xe2\"\x93`\x829se\xde\xaa\xccs\xd5\xcd\xb3\xb3\xb1\xfas~\xa6\xfe\xfd\xe2l\x91M_|\xa6\xfe\xfd\xec\xec\xabEv\x8e\x9f\xcf\xcf\xce?W\xff>\xdf,\xb2\xa7ggg\xcb\xd3m\xbd\xca{rEz\x06 \x8b\xf8\xff\x03hf\x15.\x18%m\xed\xe3D\xc9\x0f\x8a\x86\x90\xeb\x03\x16\xe5\xa4\x803XC\xdd\xa9\xee{2\xeb^\x0b\x03\xc0\xda\xe1f\x13\x10\xd1x\xa6\x18,\x18\xe1\x15\xbe\x81M\xa1\xee\x86]\x13\xe4:\xef\xec\xac\x05\xd2&\xea\xb3r\xc3\xedoH\xff\x0b%\xb5M\xfc\x14\xfe\xf6Y\xa3\x85\xa1%Sj\xd1\x9f\xe1=z]\xc6\x98\xb0_\x10\x01\x11\xe7\x0d \x13\xc3\xe1\x80Ds\x81\xebU,\xeb\xcb\x95\x14\xdc\xf5\xd5{\xd3\xb4\xba\x11\xe4\x0d\x8f\xc3vG\x80\n\xda\xb7m\x07\xae\x85:{J\x00\xd9\xf8\x11[\x17\xe7\xec\xd6\x8f\xd6\xf1-\xb9\x06{\x002\xd3\xef\xe5&\x9d6\x83v\xe4o\x9d\x8d*\xc8\xbe\"W\x84\xf2m\x06\x86`&\x92\xfcK\x8c\x0d_\xf0B`\xb3\xcc\xcf\x96\xe4\xba\xfc:#o\x9b\x02\x9a\xde\x95\x0c`\x9b&\x95\xe4\x10\xdfV\xc7\xd2\xfc\xde\xbb\xbd5\xdcM\xf6\x8c\xa7\xaa\x8bW\xa47\x9d\x9cM\xd4\xae\xfan\xc2Y\x18\xef\xd9Z\xc7\xbd>\xf9\n\x9ck|5Y\xc7\x1e\x80\xad^?\x87~\xe5i\x93(^\xb3\xd7\xf7 \xb3\xb6\x9bw\x13?\xfd!K\x92\x98\x0b\xa8\xead:\"wu0\xd4(\xfe@\x8aU\xb9\xc7\xe2\xcb\x06\xbf~\xeaw\xd3\xf2\xed\x8b\x0eu\xff\x11\xf2\xfcN\xe7\xf9\x9a\xd3ms\xde\xef \xef\xef_\xbf\xfa\xf6\xb5>p\xfc\nO\xa5\xdd\xd9_C\xf6?\xd4,\xad\xcd\xef\x95\xfd\xfe5\xe8\x83\xdc\xb9\xbe\xc1\\4dk\x95\xf5\x15M\xdc\xf9~\xb4\xfc\x1a(\xd27\xe4\xbaRLM\xddW\x93W\xf1;H\xfcB\x08\xae\x12g\xe4\x1bw}\x7f\x80v_\xb3\xbb\x86\xde}\x0f\xdf\xbfD\x8b|w\x96\xdf\xe1\xd8\xfe\xf1\xd5wp[\xda\x9d\xe9[\xc8\xf4?\xbf\xfa\xf6\xf7B$\xdf\xb3\x9f2\x966T\xf7\xa7r\x0f\xbf\x85\x1e\x96\x0b\x92\x19\xf9\xd6]\xf8'h\x86Ej\xff\xf6\xa7\xef\x1b\xfa\xfcu\xb9\x85\x9f\xa0\x05[\x86\xcc\xc8O\xee\xb5\xe4\xe4\x17\xdf5-Z\x85\xf6\xef\x14\xf5\xfd\xff\xd9\xfb\xda\xae\xb8m%\xe0\xef\xf7W\x0c~zR\xfb\xe05\x90\xa4\xb7\xed\x06\xc2!\xb0ii\x03\xe4\x02i\xdaK\xf3p\xcc\xaev\xd7\xc1k\xed\xe3\x17^z\xcb\x7f\x7f\x8eF\x92-\xdb\x92\xec%iz?\\\x7fHXk$K\xa3\x91\xe6E\xa3\x99`\x9c\x92\x8a\x88\xdc\xea\x18\xdb\x10\xc4\xff\x8f@\x98D\xd8\x16S\xfe\x08\xe8mBRI\xc1(c1\xc27\x94\xdb.\xd5\xc8\x87u\xf0\x15\xeb\xa0\x1eK\xbf\xc0\x0e\xbc\n\xa2\xc5\x92\xf7\x1b\x95\x14=\xe4\x8f\x08\xc9G\xc9\xa8\xf0P\xb0u=\xf4{\x84\x9e\x91\\ ${u\x7f\x1e\xce\x18\xb5\xea\xe1\x7fRZ\xef\xb7\x80\x7f\x83\x1d8c=\xa7in^\x97?\xa3T\xdc\x9e\x82\xe6\xae\xf6Kc\xa7\xffE\xf4\x85m\x10\xeat\xf0\xfdr\xaf\xdc\x88\x8e\xe8Ds\xf7\x8d!\xfd\x07\x8c\x8c\xa6\xed\xd4W\xb0\x03\x86\x95\xffo\xd8\x81\x89\xbe\xe8W\xd8\x81\xb9\xbe\xe8_\x18wM[D\x08\xec\x80F\xa4cON0(\xa0\xb6,aez\xcf;@F\x05;\x10\xbb\xffy\xf0\xe1\xe2\x03\xa3\xceq\x98\xbbW\x188\xeb\xca\xcd\xf1\xdf\x04\xffM\xf1_\xeay\x06\xdeH\xed\xdf\x89\xf4\xdf\x89\xb0\xd5\x10\xff-\xf0\xdf\xcc\xf8\x85\xd0\xfe\x85\xc2^\x9c\x11Cb\"\xc0[\x81\x96\xc21\xb1\xb0\xb3\xa9\xadpi+\x9c\xd8\n\xe7\xb6\xc2\x1b[\xe1\xc2V8\xb3\x15\xde\xdb\n\xafl\x18\xba\xb4\x15\xde\x12\x8bB;R\xc8\xa2r\xa0\x91.A\xd2\xa3\xa0\x8a\xf7PZ\x93T\xef\"\xe1\xe4\xc3\xbdD>\x98d7\xed\x97J\xcf\x12\xe1(V\xb9Gq\xa7\x1aSkg\xb5\xd6\xb8a\xb99}uh\xf8\x98R\xc6*\xb1\x97\x85ZI\xfb)\xa5LVB\xfaw\xde\x9d\x8d.\xdf\x9e\x9e\xbc>|3\x92\x9fz\xf2\x04\xa6\x81\xfa\xde\x17\x9b\x14\x0f\x82'\xfa}\xb9wz\xb8\x87\x0d\xfab\x9b\xaa\x17\x1f\xec\x9d\xcbb\xdc\xa8\xe4\xfbw\xc7?\x1f\x9f\xbc?f\x8d\x9f\x9f\xec\x9f\xbc9C\xa5a\xcb\xe7;\xd648\xdb{=\xba|}rz\xf9\xd3\xbf\xde\x8dN\x7f\x93\xa5\xcbF\xe9\xf9\xe8\xe8\xed\x9b\xbd\xf3QY}\xc2\x01\xde\xffx\xf2ftyp\xb2\xff\xeeht|.\x0b\x17\xbc\xf0tt\xfe\xee\xf4\xf8\xf2\xe0\xe4H\x16\xcc\x9a\x05\x97\xafO\xf7~P\xab\xde\xb7 \x0e\x8f\xde\x9e\x9c\x96\xe57\xbc\xfc\xf5\xc9\xe9\xfe\xe8\xf2\xd5\xc9A\xd9\xe3\xab\x1aR\xce\xf6\x8e\x0f\xcf\x0f\xff\xcd\xbav\xe4\x8b\x8dI\x96\xfd<\x1a\xbd\xbd\xdc?9>\x1f\x1d\x9f\xfb\x9ciV\xc4\xf1\xee\xf4\xf0\xf2t\xf4\xc3\xe8\xd7\xb7\xac\xe1\x9c *0\x0c\x11\x91i\xd5f\xfc\x05\xdfa7=\x9cZ\x0c\xecI\xb4\xbc\x0dy%\xa7OT\xdb\xf8Z\xb8%Uh\x80\xd8M\x88\x0f\x8c\xd7\xc6.%>D<\xb3\x97\x84\xcbnf\nX^\x82\x85\xe5_Y\xab\x02\xd7Z2\xa5^\xd2]\x8f\xed\xb3Gj\x97\xd2\x12\xb2P\xebx\xb8\x9a\x0e\xf8\xa2(\x87\xbe\xb3\xc3\xa4\x88\x12\x11c7!\x1e\xd6b-U\xf0UmF\xad\x08Oy\xed\x88\x94\xbf`\xecRQ\x9b\x12\x15\xbe\xaa\xcd&\n\xc9S6\x13\xbbgD[\xe8!\x01\xf0\x8e\x95.Wr\xee\xb8\x85\x94\x1b\x96RB\xfe \xb8*\xab\xb7\xc2\x82\xca\xcb\xdc\xa9\xe7\xf3\xadu\xaa\xdd\xfd\x0c\xdc\xed\x84\xf46\x18\x94J\xbe)&\x82\xfa\x08\xbf\xeb\xa1\xc6Z%\x9f\x07K\xce\xb1<\xbd\xb7\xf4\x04dv\x08\x92\xa0<.:\xb6?\x8f\xe2\x89\xc9\x9c\x01h\xd1\x1b\x87\xf9x\x8ey8\xbaZ\xa7ENR&\x92c\xe8rs\x93\xab \xfb-\xe9\xba\x9e\xac>\xdd8XiF\xd8S\xfa\xf0\x0c!g\x1a\xd3\x9e\xfc\xcd\xb0\xc8$\xea\xce\x16\xa6)]\x0c\x1bv\xf6\xe6\xf3\xd0c\x06\xac\x94\x06\x9f86\xb3p\xa1>\x9f:\x14\xf3\xc4\x89\xae\x97\xd85\x9a\xd8\xf4\x9d<\xef\xbf&\xa5a\x96K2\xf61\xdbNf\xe4\x13M\xc1\xbd\xe1\x1b\x12\xca\x04\xdb|$/\xb77\xc4\x1f\x0e\xac#7\xb8\xee\x9a\xbfn\xeae\x0f\xfb\xc8k\xdb\x92\x85&\xd1\x98\xd1\x0ej\xb4\x03r\x0b\xef\xcc\xc3dO\x1a\xa4$[\xd2$C\x1b$\x1b\xacT\xb4\x1d\x1f\xd2\x80.I\xe2:?\x8c\xce\x1dq/e\xc86\xe7\x0d\xc6\x18_\x8c\xe7a\x9a\x91|\xa7\xc8\xa7\x83\xef|D\x89/\xd2\x9a\x06\x19I&.#@\x8fGE\xa9>\xf3\x08Jb\xd3\xb1\xef\xf5\xc0%\xfb\x92\xcb\x06}\xe0\xf1\x18\x83\xafS\xba8\xc33D\xb6\xcf8e\xdf\x9d\x9ek\xd3\xdc\xa7\xf2v\xfc\x93'\x90\x97\xc6 !\xa8\xe3\x95y\x9e^\x94uIg\xdap\x1d\xc7\xf3\x82+:\xb9\xf7L[x\xa2\x16L\xa34\x93\xcdc1\x13\xc4k\xdb3\xa3\xc7\xf7\xfc\xbc0G\xe9oW\\\xb1\x81\xa1\xb8\xbf\xe4]l\xb6\xefw\x81\xde\xc8]7\xd70 \xd8v\x8c\x00\xca-\xads\xe2~\xbd\x9d\xdd\xcc^n\xcf\x80\xa2\x8f\xf0\x0e\x06~k\x0f\xd3\xf5\x9c\x97\xdb\x1b\xb3\x97\xdb\x1b\x0c\xfck\x03#$\x01\x86\xdb:\x13.\x19.j\x91\x18\x82\xc9\xbd\xe62\x82\xbe\x9e\x9d\\\xdczW\x97/\xb7Qo{\xb9\x1d-f\x90\xa5\xe3\x1dg{\xa3\xf1\xe6\x0eh\x82^\xf2;aL\xd2\xdc\xdd\xf266\x9c\x97_{\x9e\xa6\x83\xc0\xd4T\xae7\xed\xf3N\xea\x11o'\xb6\x07W36\x86\xe7\xa3\xfe{\xa3 \xd4\x1f\xc5Ir\xc3\xde\xf9\xe7\x9fl\xd1\x12\x1f\x8e\x82\xb3\x1fO\xde_\x8e\xde\x8c\xb8\xac/_\xec\x9f\x1c\xd5_\x9c\x8f~=\xf7\xbb\xa9\xa1\xf1\xf9\xa3\xe0\xf5\xe1\x9b\xf3\xd1\xe9\xe5\xde\xfe\xfe\xe8\xed\xb9y\xf5\xd5s.\xd5\x8b\xb4\xaf\x0fWFE\xa9\xfd\xee4\xb4\xdfs\x8d\xf6{\x8e\xb1l D\xe8U6&t\n\xe70\x14\x07\x9d\xa6\x86\x88\xa6!\xc2\xd5h')\x16W$UM\xdd\xa4<\x02\xe2\xc7\xba-\x9f\x07\x0ep\x1c.\x0c)O\xf5\x88\xf9\xd8\x12\xb3\x1a\x973\x9b\xcf\xcf\x17\x04]+\xd8\xff\xc1\x94\xa6\xa3pN<\x95\x0c\x8eQ\xfdT\xdf\x9cb\xe8/\x8d\xcfJ9\x7f\x86 \xce\x03\xc6\x99\xf6\xab\xe3 \xed\x91H\xaer\x07\xcewJi/S\xfb\xf1\xb1\xb3\x89R&\xb3@f\x8a`\\\x05\x969\xe1\xb9\x1al\xf9\x7f\xa5\xf4Q\x91m\xddA\xa7{J\x8a%M\x1a\x13\xc2\xe7\xa3\x83\xfd\xf3\xf3\x8e!\x18\x8eH\xe4\x13\xc61\xbd%\x93\xf3p\x96\x0d!\xb1\xa9f>\xac%\xe4\"\xfd\x80\x01\xff\xd8\x1f]\x8b\x80\x8d\x80\xab\xb2k#\xach\xc2/ \xa2$#i\xbe7\xf9\x18\x8eI\x923&\xdeG\xc4\x01\\i\xed\xba\xae\xb37\xcdI:Bg:\x06\x90p\xc1\xe0\xb3\xc9\x94\xcd\xf97c\xadk\xff]\x9b\x12\x1eT\xb0%\xd3\xf0\xd7\xca1]\xf9C\x0f\xbb\xb6\xb1\xbd1\x0br\x92\xe5.Q\x97\x10\x97\x0eV\xd2\x9d*M=\x18\xc74\xe1\xaa\xa0m\x03\xaba\x99'9\xa9:P\x06\xe8c\x1d\xf4\xc1y\x12\xe7/\x1c\xcf\x93\xa6*\x99\xeaA\xdd\xf7\xb9\xb8X\xfeS\x1fO\xd9\xde\x0f>8\xc0$G\xf9\xe2+\xfe\xc2\xafW\xa8\x82J~\x01,\xa8\xdf\xdd\x81\x84\x0d\x93-\xe2\x90\xd1\xa3}[\xddZ\x85\x0b\x9c\xae\xc8\x05V\xd6\x07\xedpiO8\xda\x13.\xea \x17\xf6\x84+\x1e\xcd\xf2\xca]\xbe>;<\x82j\xc5a\xba\xb6>\x86\xf4v\xcc\x15\xdd\xc3\xda\xe4\x1b\xb5.\xa0\x89\x0e\xfa\x970.z\x82_\x13\xb2d#\xd2\xc7ki>\x82\x15T(\x18\x0253\x04\xd0\xebJ\xea\x83\x8ebl.\xc2\xd2\x11\xac@_\xd6n\xb4\xc8\xec\x92(k\x84\x17\xc5\x07/H\xc2\x05\xf1\x91\xf4\xf2\x00\x0f\x98\x82<\x8d\x16\xae\xe7\xf3\xa0\x85u\xbe\xeaC\x16H\xd4\xf2\x04P\xfc7\"\x8f'\xeb\xc8\x02\x89\x1e\x91J\xb3\xc9m\xf7\x94\x18\x96hJ\xe6_W\x1a\x92\x07d\xb8\x85Q\xe4o\x87G?8\xca\x8e&\x05\x9d0\x88&\x1e\xd29\xfb\x8b\x13\x14w^\xab\xbc]1\xa0]\x10.\x97\xf1=\x1e.\xbf%.?\x8e#\xfcG\xc2\xff\n\xcbL\x12\x91\x07/\xa1\xe0\xbcA\x95PD\xb5\x88\xa3\xc9\"c\xc8\xc7\x90\x12Q\xf7\xa0\x93\xca\xe1\xf1\xdbw\xe7\xbaa\xf2\xbb\x0e\n:\xf0f\x1d\xb7\xb6\x0bs\xf9\x05E b\xad`\x7fy\x1eF\xc5\x8d\x92B\xe3\xc7\xa0{\xd8\xc8\xb0\xb9D3\xec\xc4\x07\xc7Qp\xd5\xd9\xa2\x9d\xcb\x83\x18\xaeB(\x18)\xf8\nY6\xf6d\xad\x1c(\xa7\x03\xfe\x9b\x0d\xcfM!J`\x8f\xfd\x8d\x7f]\x13\xcf\xe8P\xd9|\xd8G\x05#d\x04\x87\xff\xa4\x9dl\xcf\xc3\xa3\xb6'O\xe0\xdf\\\n\xa0^\x8f\x99\x079\xfb8P\xac\xfe\xebc\xaa\xf7\x1b\x18\x88\xc1\xad\x95d\xc0\xa9`E\"\x00\xd1\xcc\x19V\xee_\xa7\x1chN\xf8\x18+\xa4\x12\x82\xb4\xd3w\xcc\xa0\xb6\x86\x97~\x15RPn\x0eT\x04\xc1\x1d{\xaa,0\xdc\x80\xc8m7kw\xe4\xc2\xa4 |\xe8\xa6b\xf5\xc1\xb0\xa2\\\xe6\xfe\xd7g\x18#\xa8\xe3L\xaby\xea\xd5@\xf7\xea\x82N\xd3T\xf3i\xaf\xf8\xd4\xf3\xd5\x93\x01\xba\xb4\xc8h\xea\xb3\x82\xb8\x0f\x9d\x83\xb1\x97\xb6$@\xad\x94alb\xa5\x03\xa5\x03U2\x04b?\xd7\x92wM\xfa\xc8Tl\x13:b\xed\x99\xa9\x07\xf9}[\xa6:\xc3\x80>\x07'G\x0e7\x87\xb0\xc1\xbe\xc0\xef\xa6AB\xeer.X\xbf\xf0Z\x0c\x98W\x14\xa1B\x92R\x18;&n\xc2\xb5\x9a\xa4\xd4\x8f\x14\x8d\xff\x049CU\xe6\xf9p\xcajX:\xde\x9a ]\x97\xf5\xb3`\xbcxr\x17d\xa2\xb1\xbe'|}g\xa3\x8f\xf4\xddG\xf2\xee#u\x87\x1d\x924f#\xe4Qqa\x07\x9c\xdf\xef\x9e\x8d\xd7\x06\x83\xdf\xef\x9e\x11\xc6\x88K\xf3\xceZ\xa5\xeb\xe3\xdetH,\xf7\x0b\xa0\xed\x0b\xab\xd4\x0fr\xcaO1<\xc8\xe7)\xbd\xc5\x83\x1d\xa68\x8e\xd2\x94\xa6\xae#\x8b!\xca \xa19\x84%\xf2M\xce\xb0\xe5\xf7Z\xbd\xc5AU_t\x19\x0b\xd7~t\x12\xa5\xf9}\xf5E\xde\x90\x0f\xe1\x15M1N\x8d\x81x\x8c(]\xab\x1d9t\"J\xb5\xbd\xde\xbb#\xecp\x98GcnHa\xc2\x8a\xce\xec\xd2\x84\xeb\xb6\xe6\xe8\xec\xb1\xa55\xac\xde\x9c\xdb%w\xb2\xf6\x04\x19\x18\x1a\xa8NtV\xdd\x1b\xc1t\xb3M>f\xcc\xcf\x91\x9a\xf7\x08\xba\x916/1\xd4M\xdf\x1e\xf0,\xbb\\HK\xf8\x19J} x\xf5#\x06\xc5a\x98\xed\x04k\x9b\x9eW\xb7w\xbf:9\xf8M\x88\xcb\x95\\\xbd\xcb\xf7J\x18B\xc2\xb4\x03\x92L\xf8\x99Xj:$\xb2\x0bdH_\\\\_\x9b\xe0\x7f\x03\x99-\xb8\x14N\xb6\x1d%\x7f\xb7}\xd5\xac\xc9\x91\xa3\x80+\xea\xf0^\xf3\x9b2\x06W \xfd\x14\xf0\x93\xe6\x13\xb6}\xa3\x95\x8b\x1f\xef\xe9{P\xdeC*8kJ\xbc\x17\xb8\xef\x15u\xae\xc2\x0dL\xb4\x86h\xca]x\xd8T\x1f\x13\x97rnB\x8d\xdc\xe4\x80T\x85\x9c\x9dP\x91\x8c\x98\x1a\xfa\xc60\xb3\xb0\xdae\x18\xc4\xacCG\xc1\x11\xb2-\xf8'~\x9e\x904<\xf0_\x80\x8a\xa6\x17\x1e\x845\x02\xe9\x81C\x90\xf4\x82A\xfb\xcd0b^\xef\xb9V\xc2\x80\x7f\xe3]:\xf3e\xaaK\x1f\xc2\x15&Z4\x88G\xb3\xea\xd9-#\xf2\xd2\x94\xd8\xaa\xf9\xc0\xd6dF\xf2}\x9aL\xa3Y/\x1b\xd8\x1e7\xd2r\xdfdMly\xd6\"\x06\x8aj\xb7ij\xb2rW\x95.\xcf\xfaf\xc3\xc9\xe4GJ\xaf\xfb\xf2\x7f\xfd\xd9\x03\"\x1c\x8f\xa3v\xf8\xa9\xd4\x9f\x7f\xe2^\x84'Sh\xc6\xcc=\xcdU\x8cj\xf3ju\xc1\xf4\xfd\xda\x99\x97^\x90n4\x9b\xad\xd4\xae\x1c\xc5\x85F\xa7Q\x1a\xde\x8b\xe3V\xdb\xc6\xa6\xd1\x0fW\xdbZ\xed\xe5\x832\x16\x9e\xce\xb6\x0c\x8b\x9c\x8a\xa2G\xc5W\x16\xfev\xfcpS\xdeSvs\x1f\x9c\xcbK\x92\x1d\xd1 \x0f\xd3S\xef\xfc\x0d7\xe0\xa9\xa9\x02\x94\xd5)O\x8cb7q\x9f7o\x15PQ\xf0\xb4Y\x10\x89\x82g\xcd\x82P\x14|\xd3,(D\xc1?\x9b\x05\x99(\xd8T%f\xf6b\x8b\xbd(\xdf\x94:F\xdc\x9ey\xf5\x06, *T\xe0\xe9\xb1.\xa8\xaf\x88\xaf\xd6\xf4\x0dlF\xd8\x05\x81\x9f\xb1\x95\xee\xca\x9e\xe5\xb6k\x9e\xee\xa6\x0f4\x10\x1f\xf6\xdc|\x1ee\xdc]\x95\x15\x84\xcd\x027\x0f./\xd1Twy\x89\xccb\xd3\x87T\x01\xf2;\xd3\x88P\xd0%\xbb>\xba\xaf\xab\xe0\xc5\x82\x93\xb4\xb4\x88\x99 \"[/\xaa\x8554]\xc3\xe4`lM\x0dM7<\x01\x0f\x0e3z6\xa7\xb7f\x92[Zmh\xe6\x01,;\x87\x18\xf7Et\x94Li\xba\xe01 ;\x88\xc2\xd2\xa1\xb1\xeds\x0bz\x15\xc5d\x08[OWm\x96\x8aqz\x96\x91N:q1\xed\x84\x98wB\xc4rg\xf8D\x0cXx\x08\xc9\xaes\xba|\x0c\x9a\xc2\x1eh\xfa\xaf\x1e@Q\x0e@\xa7\xb3\xd5\xde<|\xf0|\xe5*\xc2\x83[\xb5Y\nS\n\xa3\xcbe)\xec\xc0\x18\xdf\xfe\xbd\n\x8d\x0fy\xf0SF\x13\x14\x15\xc2Kn\xa1D&\xad\xbc\xbd\xa24&a\xd2|\x8d\xe1\x03\x9b/\xb9\xe9\xb1\xf1\xf65M\x17\x1a.-u\xa8{\xa6*\xb5T\"*KZ:Q$JZzW(\xab\xe8\xb4\xa8{\x9d\xde\x95\x89\x82\xd67bQ\xd0\xd2\xbb\xb8\x94\xd7\x14\x88\xa6\x08>n\xbc]\x8aF\xb6\x9a\x8dp\x01\xed\xdb\xc6\xdb\xb9\x04\xdfj\xf5\xf3F\x16\xb5\x86\xb6\x90%\x9b\xdf\xb4\x061\x13\x89\x8a\xb5\n\xe1\xfd\x97U\x08\x97\xe5\xba`=\x08\xa2\xecT\x84\x85\xf6\x95\xa20\xb9\xf7\x1b\x90\x96bN\xad\x86\xa6x\xa1\x0f7\xe5\x9b8\xcar\x15\x82\x91\xb5\xedw\x98\xdc\xd7i\xf5\xaa\xe5*t\xa3w\xf2\xa1\xc9\xfe\xf9\x86\xb6]\xcd:\xff\x1c:\x7fK\xb5\x97:\x7f\xd6,\xd0\xe9\xfc\xaaF\xfe\xa9:\x7f\xac\xb4U\xe9\xfcuK\x80Q\xe7/\xd3J\x1dD\x93#\x1eG\xb6\x05\xf9\xd7\xa9\xff\x93([\x86\xf9x~\xc8t\x860\xe6\xceP\xc6:\xdc\npc\x07\xe2^\xd2\x92\xc0\xf5\x1a\x17\x1aCS7\xe9\xe4\x9d:\x16\xff\xf7\xd9J\x90\x84\xbb\xd0\xc3\x97Z\x17~:\x90\x18\xd5\x90h\x91\xd8W\xb0\xcb\x14\x08;5\x1c\x0e\xe4AN\x7f\xe2\xd7\xaa9{g?]\xd3a\xbb\xf4\x8b\xb4|.F\x17\xbb\xfc~i\xe9\xfe\x18a\xb8\x9a\xbf\xe0\xa6\x80>*\xa9\x0f\xb4=\xe3\x06\xc6\xd3\x06\xac\x9di6c\x02\xfa\xb88x\xa8\xc5\xc2\xe3\xf9\xaa7_\xc0\x18\xb6\xa1x\x01\xe3\xf5u\x0f\xe2\x8b\xf1\x07\xb5\xe6\xc5X\x13kQ\xc6Y\xc4S\xe5\x1d\x03\xf3\xc3=\xae\x93\x01\x8e\xc38\x16\\\x90\xf8p\xc1\xea\x96\xc1$\xb8\x9e\x96\x96\xdbQ\xaf\xc3\"\xe9\xae\xaez\x8er\x92\x17\xfbh \xa2`\x92\x80G\xec\x0e\x18\xa0\x88\x81X\xbeC\xba4,<\xd1\x9a\xec\x15\xe3\xb2\xf2\x9d\x90\x90\xb4\xc7Sl\x1c\xa3\xa4X\xac0\x16\x81\xe7\xd6\x17\xf5\x1f@\x9bvK\x14a\xf4\xf4%\xe4\x89\xbf\x81/\xf6c?+\x08\x0f]\x8c\x96\xf6b\xb4\x9c\x87J\x99\xb8\x8b\x87N\x08\x8f\xf3d\x8c\\\x07\x82\x85\xa6\x01I\x8a\x85\xd92\xcd:G93\xdd\x15\x7f\xb8\x1e\x0c\xf1\xac\xb7\xe82U#Ou\x1d~\"c\xf3s\xea`;V\xbe\x02u\x8b\x1a\x95\x91Jw\xc1\x89\x12\xcc\x07\x84\xd7\xab;\xee%`\x90\xa8Zm\xda\xa3\x96\xb8\x9b\x80\x82ff\xe5]P\xd1\xaceF@\xb69Z,\xf3{q\xa5b\xcd\xc2\xa2\xa0\xc6\xcb\x90\xc8\xd5\xfd\xc0X\xcft\xbb\xd3\xb8\x86b\xdc\xfch\xba8\x08\xf3Pn\x80\x11\xba\xbb\xaf\xb9\xce\xeb\xb2 JD\x0c\xda\x8e\x83\xa3\xdcu\x0e1\x91\xa4]\x10\xa9\xed\xb7b\x8b5Q\x89\xd5\x82\xc6\xea\x0eEs\x96\x9e}\x12\x1d\xadNC\xad\xa9\xeb\x92\x90e~\xaf!\xc4\xfa dk\xd3\x84\xa0\x85|\xdf\x03Q\xcb0\xcbni:\x91\xb8\xe7R-CFU2\x94\xb9\x07\xffk\xf0\xd9\xbd\xc2\x16Q\xf2\x06[\x1b\xda\xfcK'\xe4\x8a\x16\xc9\x98\x9cG\x0bB\x8b|\x08\xcf\xbe\xb1@+\xa1\xe7\xacb\xe9_0\xdb\xad\xd7\x9fU\x02\x95\x16\xcf^\x02(1\xdc]\xef-dJ\xf3\xe8c\xad\x1e<\xae\x06Bc_\xcc\xd1\xf7\xf5\xc2\xdf\xaa\xf2R\x1ady\x98\x0b!\xc0(\x9c\x1d\xe6D'\x9cY\x1c\xae\xd2 #\xf9\x19k\xba\xba\xdao\x8d\n :hg\x91ri\x88Kj\x19\xc9\xb98f\xacd\xf2\xefW\xb0g\x184w\x98b\x03\xef'\x8fj\xc6k\xbd\x1f\xb0\xcax\xe5\xa5<\x11\xce\xe4/\x19o8\x994\x07\xbb\xcaX\xfb\x04\xc4\x10T\x06;p\xe9J\x8a\xeb\x12\x8a\x04\x06\x048w\xcaslau\x1e\x8d\x80\xd5U\x10\x0d\x1az`\xa1\xdfx\xff\x82\x01\xe2B7^\x9c\x15\x1f\xaefF\xdbH\xed\xe5_\xa3-\x95\xd6\xd7\xf7Q\x1c\x9f\x921\x89n\xf0\xb4,\xeb\xa1@\x19\xe7J\x92\xde\xda\x8e\xd0\xa2\x94]\x8f\x89\x7f\xfc\x9d\x9cN\x9bB\xa0\x92\xa3~*:\xf9\xd9\x17\xb2\xa0\xdau\xc4>\xba$?=\xec\xa7KR\x84\xedV\xed\"\x84\xebR'C\x84\xeaR'\x0b\x842\x99OC\xbc\x11,\xb4\xbeP\xd5\xfa\xec\x06\xd4\"\x88\x92)I\xb9\xf8\xe0FA\x94\x93E\xd6\xedhV?Q\xe9\xe1s\xf6\x8ag\xf7\xef\xf0\x1f\xcbP\xb7\xb5\x88W\xd0\xa6h\xb3&\xbc\xec\xd2v\xe7\xd2\xd3\xed\x13\xb5\xddy\xd7\xc6\xaeH\xd5\xe1\xeaR5T\x92\xb5R;\xecQKf\xdf\xed\xbe\xb7/\xd6\x9c\x85\x96\xa1\xad=\x1b\xa2\xbf\xd7\xa0kz1\xfd\x9b\xf5\xe2\x8ey\x14\x0eW\xdc\xedc\x8dGC\x99\x04\x98]\x91\xfd-\xfet=\xd8\x86\xad\xea^\xca$X\x84KE\x10\xf2\x81v\x11^$\x84\xe6\xb4n\x96\xcf:.\x96\xc9\xd9\xb75\x0f\xe2\x13K\xdc\x10xZ\xd7\x9e\x92\x8b|J \x06\xaf\xf1\xf0[/\xd6J\xb6p\xab\x80'\xeb\x82j\xe5\x9d\x8f\x8b\xe5\xc5\xe6\x07\xbe\xe3\xc1:P\xcb\xdd\xe4\xce{Y\x1dsi\x1f-2\xa2\x0e\xa2T}\xbf>f4\x19\xf0\xed|\xc0\xf4\xeb\x01\xdb.\xad\x0e\x81\xa6\xeeY\xdd\xcd\xa0\xfbd\x05Z\xa7+\x1dF*)]\xf7]\x81\xfd\x04{\xf9\x94$\xa3\xaaO|)\xd8)\xc7\xde\x1dy\x9e\x13Y\x96\xbf\x19\xc7V\xf3\x124\xa6\xf6*O\xe0*O\x06\xd9\x02\xb4\xb3<\xe0\xfaH\xc7\x86K\x93\xfd8\x1a_\xf7\x10^\xd4\xa7\xc4^\xa5\x87\xb9]\x88\xb3\x11\x9d\x03\x03pL\x9e\xa8^\x90S~\xf4\xf3X\xd4\xad\x84\xb6p2\x01\x07\xd6\xab\xcd\xab\xc1\xf8\xb8\x1b\xa1\xf1[%B\x91#\x08\xbdM?06\xee\xbd\xc9\x04\xd8g\xb5\xc3\xef\xb4\xb4\xbc-R\xb2\x8a\xb5\xa5r;\xebeo\xf9\xdf\x81\xdf\xca\x07~\xabj\xa9\xff;(\xd3?\x7f\xd1AY\x97\xceB{\x1d\xa7\xd5\x0f\xca\x0c\xa7\x0bx\xf2%\xf4\x9b\xb4\x9f~\x13\xf69\xcc\xea\x10#\xc2\x9e\x1ba\xba\xbaX/Dz\xa5f\xda\xcfX.\x82\x08$\xb6\xdbFuA\x9d\xbb\xc6MS\xba\xf8\xe9\xccs)jYx\xff\xd3\xc9S\x9e`e\x1a\xc6\x999\xe1\x0b\xe8\xa5\xf9\xb2\x1d\xdb\x81\xd7\xaaB}\xb7I\xe1\xd3L\xe4\xa5\x07\xf1\xa3\xf7\xec\xde{\xb2\\\xa1\x9fl\x1f\xb7X\xc6\xd9\xc2\xc9H\x8esrN\xcf\xc2\xc52\xeee#\xaf\xbc\xbb\\\xf6\xe5\x19\xdb\x1cxm\x8e'\xcf%5w \xfd\xdd`\xa2\xb5\xcb\x1bEF\xd2\xf2\x990\xb4:\x0f\x93ILNVi\xfb\xa6\xccw\xdc\xed\xbb\xa1\x0c^\xe7\x03\xe8\x1b\xbd\x85\xe132\x80\xcf\xe9y\xb9V1\x81\x86\x9dO\x9d\xc3\xf2e\x9bdtw\xb4\xeb8\xf8B\x86\xbc\xffbN\x96\xbb\xce9\xb9\xcb\xf7R\x12>\x92\x9b\xd4\x0c\x0c& \xda\x93\xe50R\x9b+\x06\x04c\x1d\xf6\x08\x9e\xc4\xd8M\x16\xfda\x0d\xcfkF\xbddX\xac\x05d\xc3\x1fi\x94\xb8\x8c}x\xfd8\x97EGm\xb0\x89\xfa\x06\xa0\xad\xf5(w\xbe.\x11\x1f\x81\x1fu\xe3E\x1e\x86\xe2E\x87\x7fz\xc1\x818\x91F\xa7\x89\n,\xad\x17\xf0\x10\x92\xb58\x02\x8f\xef\xc2g\xbdt\xd3\xec\xa6\xe9n\x8c\xf8h\x98e\xd1,a\x8c\xcc.\xa6\xd7\x92>o\xf1\xfc\xceMuE\xe4y\xb6\xef\xf3\x95\xa6bJ\x03]~\n\x03'&=\xf3\xc2c(8\xb4Ta\xac\xe9\x1dH.R]\xa0\x89\xd6\x1b\xc9\x90\xeb$X\xa7x\xda\xc5\x9aK\xd1\x83XO\x9ck\x19\xfe7_@\x02\xdbj\xa2\x7f3\xf6@\x99\xb9\xfc\"1`\x0e\x90P\x99tG\xd2\xf0\n\x05\x8a\xdaO\x91|,e\n\xdb4\x9a\x15\x12hm\xb3L\xda\xc7P\xce\xe3\\\xa6\xc1m\x1a\xe5%D\x99}\xaaI\xa7\x845xM\xee\x19\xfe\xf5\x0b\xbe\xff$\xa8\xd6X>\xa1V\x85\x91\x07\x01u\x15\xd2\xe0\x99\xc3R\xf1\x9eG\x07l{\x157\xb6\x9b\xe6\xc5r\xa6\xd8\x14<\x02F\xbd \x14\x05[\x9b\xdf|\xab\x0f\x86Q|\x91\xbbOn{\x99\xf7\x92\x8a\xb5+{\xad\x9f\xb3\x04\x8f\xf5T\x8b\x80\x95\x9b\xc2\xa1\xed\x87IBs`\xeb\x12B\xce\xfb \xccj\xa1\xd8\xdas\xd2!\x90'}\xbd:\xb0\xa3D\xed\xd9)\x99\x92\x94$\xe32D\xdc<\xca`\x1ef\xc9\xd79\\\x11\x92@\xc4\xaf\xb1D\x19\x99\xc0\x00\xb2bIR\xd7\xabA\xb0\xa1\x90I\x87\xf8\xb0\x86\xc7\x0dJB\xc9Z\x10\x1fm8\xbb\\P\x81\x86F\x0d\xfa\x86X\x843\xc2\x98\x1f'\xfa\x93i\xcb-\xc7\xa2y$\xab9d\x93`I\xd2,\xcarSX\x05\xc9\x14\x92\xee\xd3\xbdd\xa5\xe3kU\x1f\xd0o,=s\xaf\xb0\x1e\xd2~=dO\xe9\x06\xf7\x92U\xe1\x82x\xe9\xcd\x86\xe1\xaa\x12\x9aGS\xbc\xe68,\xb7oxYU|\xf2\xa4\x02J\xf1\x88\xa8G\xbe\x066\xd8!\x08p1\xf8\xaeZP\xe1\xcb\x92\x91\x0e\xf4\xeayUd29\xb7\x89\x12\x13-%?\x93\xfb\x03zk7\xa0\xca\xa7\"\x0f\xa9C\x8a\xda\xfa pFI\xceS\xc20\xf1\xfe\x9a\xdcsdNi:&\xc7\x12\xed\xbe\xc85e0\x10\xb2.\xbe\x8a\x8b\xf4\x91\xfdcUM\xf4\xbbb?\xb8\x86\x80\xf0\x11\xe9\xd7\x1f\x1eQs\x1b6\xbd\x92\x86\xba\x84\x0f\xf9\xc8\x05^\xc4\x06/F\x83V-\x03\xfc\x8a\x84=\xb5\x0f'\xc1\x84\xf2\xf1Z*\xdb\x97^.L)\x8a\xed\xa5\x1b\x0d\xf2I\x82(\x13\xbc\x8e\xdf\xd1a\x02L\xd5)\xab\x9f\x19\xdb\x07\xcd\xcb\\\x87\xddGtg\xd3\xd7\xcf\xbf|\x90\x0e\xa6q\x91\xcd\xfbN#TS\x99\xf3\x9a\xb6\xb4\x13Hf\x8c!\xc7\xab\xb4\xafEk.\x1a\xb2}NOXz\xea\x97\x93\xd4\xa7cI\xc3\xc4$\xce\x18D|Z\xe5r\xad\xfeS\xca\xba\xec5\x9f\x98_\xa0\x86\x03\x1b\xc6J\x0c\xe3^$\x91d&--K\xec8\x81\x04\x0d\xb31\x7f!Wx\x14E\x9e\xa4\xac\x08\x0c\xa2X\xfe\xfeR\x0c\xe8\xf1i3{\x07\xdf\xc1\xa9\xee\xe5\"(\xdd\xe6\x98<\xd6f\x8c\xd8\x8en_\xa9Aj\xcd\x87\x9d\"\xa81r1\xb2\n\xf4=A\x07?\x83\xe8|\xc6\x84O w\xcb\x94d\x19\x93\xda\x17E\x96\x03\x89\xf29I\xe1\x8a\xf0\x06h\xaa\xc8\xd2>\x06\x1dv`\xbd\xfc\x90\x862I\xa5\"U\xba?\xe7N\xae\xc8\xdb\xa8\xe8Pz\xd4\x8ei\x92\xe5i1\xcei\xaaS[\xe4#g\xc0L\xef\x95F\xda\x8e8\xa0>R\xff\xb4\xbbA\xa9\xba\xec\xd0\x94\x8cICK\x92{\xbb\x02\x1bYM\xa2\x86]\xd0\xbe\x17\xf3>DUN\x8a\xe5l:\xeb\xa4\xc3t\xcf\xf2T\xa0a\xbd\xf2\x81\xf630\xbf\x8f\xe2\xf8S-\xcch\x95\xab\x8b!\xaeb`n\xdc\xbf\xe8\xb2\x97X\xac\xc9\x7f\x89K\xac\xdcH;\xb7\xd0D\\\xc6\xab\x8dF\xbf}\xe2\xe8k\x8b\xff\xcf?\xcb\x8c\x85\xb84+g[\xc5\x01\xb7Q\xd2[\x8f1\xddi\xf6!\xa9<}\xb5\x93Q~\xac1}I\xb7\x01\xb5\xe74\xbdK\x16\x9f\x83\xbc\xb8t#{k\x92Xzw\xf1o8\x97\x10\xb9\xbe\xec\xf4\xe5*\x91\x15J\x8a\x04R\xb1k\xbfM\x82\xec\x95\"\x9b\xbc\xbaG\xf5\xc6\xe68\xc3\xa3-TUNP\x1f\xb1\x9c\xef\x8a\x90\x0fB\xab2\x03\x16\x02\xd0\xde\\\x86PQ\xb2,\xf2S25\xc3\xc5}\xcd1\xf2\x916\x9c\xff\xf4I\x1aUZ\x7f\x89\x07y\x19\x96<\xf5\x98\xb8\xb3\xa9XA\xec&aR\x9a\x84\x13n\x12\xc6\xac\x85\xf6\xcfK\x1d\xca\x08\xf4\x80~/\x8e\xa0\x18\xc7\x07G\x12\x85S\x1aQ}pJ\xa2\xc0d\xd1u\xa2\xc0\x83\xfb\x16Q4\xde\xf2y\xe7\xed\x8b\xb9\xe5?\xe4k9G\xd6\xd3\xffqG\x0cKt\xf3\x86]\xcb\xdc\x95_/\x1d\x01\xc4o\xfd\xbe\x06C\x08\xfb\xb6g\x88\x17\x0eC#\x910\xba\x98v\x0c\x89\x95\xd3\x8e.0\x1c\x96\xe3a?\x8c=)z\xb5T\xadB\x99\xba\xb4(r\xaeueb\xe8\xba\"\xf3=\xd8\xd6\xdd\xd7\xad\xcd\x06D{\x93h\x8b\xc2\xad-\xa3\x0d\"w\n\xd9\xc1\n\x97\xf8W\xc7\x99\xa5\xe5\xae\xa0\xdc\xd3\x9d\xd1\xdd\x92\x8cs2QM\xfcmBIa\x07\x8e\xc3\xe3v\x01cz\xce\x85\xf0\xf09\xbb_\\\xd1\xf8\x83\xa6~\x04;\xb0\xf1\x7f\x7f\xcf\xd6\xff\xfc=[\xffjc\xd6\x86\x08\x11\xe2b\xb0\xfea\xf3\xeebs\xf0}8\x98~X\xffjC\xe3\xe6T \xe4\xe6\xd5\xc5\xe6\x96\x01\"\xe3\x10\xf4bs\xf0\xad\x01\x841A\xcc\xad\x7f\xa8\x93\x1d\xd8\xde\xaa\xa4f\xa9\xe9\x81B\xe7:\x11NM;R'\xc3\xd7\xed\xa6\xa6\xfa\xa62\x12OY\x0d\xf5\x7f}\x9b\xac\xa4\xdd,\xdb\x80\xc6x\xf6\xcb\xfey-\xe7\xd9\x91\xd6\xa7y\x949\x9e.\xec\xf2\xa4R\"+\x16,\xd3\xe4\xb4\xc1\xe7\xb0\x03Ga>\x0f\x16\xe1\x9dF\xac+K#\x8d\xf8\xd2\xef\xb6'\xef\xf028`\xdbNBou\xf2\xa7r^\x07\xea\xb9\xd8L\xaf\x7fH\xddC&\xba1\x1e\xa8\xac\xad\xf1\xac\x18\xb5 \xd2d\xddiz\xa7\xea{\xa3\x89\x9e\x08\xd2\xac\xa0\xc9\x97nK\xd3\xc2\xeat\xebX\xa2\xbe\x93\xe1\xba\xab5\xde\xed\x16\xd0hD\xa0BC\xaa\x066\xc0Z}\xf2\x04&B`\xf3@{i\xe5AM\x13\xa4\xb1\xcdc.\x15KF\xa9\x9b2\xa8PmBdF)\xdc\xbdQ\xe5/\xffF'U\x93\x17\x1a\xec\xc0\x8cm\x86\xbb\x90\xc3:\x8f)\xd6u\xc6\x0c\xcd\x0cJk\x9a)\xac\x12\xe6\x13\x18\xc2\xba\xe6\xf3D\xb8\xdc\xf2\x84~\x11\xe6\xf33\x1f\x97\x16\"\x1d\xb4\xe5,\x90\xcdp&\xc1`\x17bW\xe4!u\x9f\xa2\x86\xba\x0bOa\x08\xdf1l\x84\nX\x8a\xfdk\xd0\xb3\xfaK\xf5\x8ci0\x17\xed\xa1>\x1e\xd1\xf9\x10a6\x99\xc2\x87\x0c\x85\x13\xf4w\xd7\x0b\x1cSn\xb2\xd3\x96--e\x13\xb4\xd9\xebIH\x9fpLo\xa8K\xbc\xc6v\x02\xea\"\xbe\xea\xf6w\xb4\\_b|2\xb2Jv\x8ca*\xe9\xdbx\xa0\x17_\xa8x\xdcr\x9e26\xae\xa1Js\xa75\x91;\xe5#;M`\x00\xb1\xb5gJ\xc0\xbd\x98\x11W\xc2T\xb6\x9c\xff\xb5\xcdu\xb7%zB\xc0\x00\xc6\xac\xac\xad\x04\xd8\xfax\xdb\xa9\xf4/l\xe1\xff/k\xf9\xc6\x8c9\xca\x18\xd5f$\x17\x82\x99{\xeb\xf7\xdc\x05K_V\x18\x80\x8b\xb8\xea\xbe\x9c\xba\x84]\xb8q\x13\x1fBYi\xec\xa1\x05\xdf\xb8a\xae6\xab\xa3\xce\x9d?S\x08i\x02\x98\x1dk\x17\xae\xf89\x82\xdb\xa4\xb4b\xb5\xaf\xdf\xf5\x99/\xf3JHx\x1c\x06\xcb\x8cR\xd5\xa5\x8c\xe7\xe4\xe2.\x10L63EJQ\x1bP\x086\xf3\xdaV\xfe.\xb3\x86\xa80\xe6_k\x13N\xee\xf90\xad\xf0\xa9W\x14\x01g\xd6F,\xe2^\xb42c\xed\xcf\\\xb9\xa6\x00\xfb=\x17l\x86b\x8c\xaeq\xcf\xd7\xf4\xdc\xe8\xc5\x95c\xe4\xe8\x1ccbn\xfa0s\x85\x15\x06\xf7\xec\xb54\x88 \xe6f\xe0Y\xb0]\xb6[;\x8b\xf0\xee}\x18\xe5\xdc\xfd\x8cq\x98\xb9{\xef\xa6\x81x-[B\xc3{\xe8\xe3&\xee\xe4i\x18\xc5\xc8K\xd1em\x17\x9b\x96/a\x08\x13L\xe0\xd7\xffhT\xb1\x00#\"0)\x98\xc4B&o_\xf1\xebG\xb1X\x15\xd5\xd2ic\x87}\xbd\xf7\xb9\xafn2v\xa1\x80!\x8c\xdc\x85kH\xf0U{\xa9\xb8\x87IW \x1f\x12\xf7\xd9\x96\xa8\xdc\xa1\xe5I\xe7\xc2z\xf7\x9c`#\x8c\xe3\xe0c\xe6\x0c\xe1\xf9\xf3\xe7~\xab\xb0\xc8\xe7\x1b!6\x9aq\xa8\xa7\xcf\x9e\xea\xa1\xd0\x88\xc7a\x9e}\xffL\x0f\x93\x92I1&i&\xc1\x0c\x1f\xccd\xe2! \xf7\x8d\x01nI\xc6\x83\xdb4\\\x0ej]|\xf6\xfd?[\xf0\xfc\x10)k\x8e\xa5\xdd\x01 8'\xf1\xb2\xec\xe9\xd3g\xed\x01I\xc0\xda\xb8\xbf7\x82\xd5\x87\xfe|\xb3\x8dE \xd9\x18\xfd\xf3\xcd-3(C@mH\xcf\x9b&\x06'\xd8\x98\x10\xb2\x1c\xc4Qr\x1d%\xb3\xfa\xb8\x9eo\xb61[\x83V\x06\xf7|\xb3\x8d\x83\x1al\x1c\xde\xd3\"\x97\xc0m\xcc\xd6\x80\xcb|K\x83<\x9c\xe1\x1c.I\x1a|\xcc\xee\xb0\xf2\xb7}+7+\xb6'~Bo\x93\x98\x86\x93A\x91\xc6r\x96\xbekA\x914\xad\x93\xc6\xd6\xd3v\x1f\x18\x10\xdeG\x18\xe4i\x98dS\x9a.H\x9am\xcc)\xbd\x16-?mO\x95\xa1R\xedGB\xf3\x01\x9d\x0eP\xc9\x16\x0d\xb5\xc9\xa3OC\xcb0\x0d\x17$'\xe9\x80&\x84Nec\xed\x89\xeb\xd3\x18\xd3d\x96\x03\xe9\x0e*\xdbj\xcf+kK]\x04[\xedE\xc0@\x1ak\xffi\x9bN\x19Ts\xe9?m\x13(\x8f\x9dP'\xcd\xf6\x8c\n(\xba\xccxV* \xd9\xee\x1c\xa7\xdb\xc6\xce\xa0YF\x02N\x1d\xea\xd36\xbd \xa8\xe6h\xdb\xd4$\x00[\x03n\x0f%\xa6\x8dm\xe6\xbb6Rh\x98=knn\xed\xceq\xa8\"\x9f\x0f\xc8]N\x92\x8cAo\xe0\x06\xda\xdct44\x83\x95\xcb\xe3\xc5l\x83\xf1\xa0\xabp|\x9d\xc9\xd5\xa7\xc1F\xb3\xce<\xcf\x97\x03\xd6\x01YG\xc3M\x9au\xd4\x89\xd6\x90C\x13\xbc\xda\x1c\xd8vQ\xf6\xad\x8dVs\xc5\x8c\xa7X+\xfb\xd8\x8d\x8b\x94\xfc\xbf\x82d\xf9\xe0\x8aN\xee\x07d\x12\xe5\xb4\xdc\x93\x9e\xb5\xf7\x04[\xed\xb2\xc3m\x8aiV\x13\xdd\xac\xb2\x1d\x95\x9fl\x13\xaf\xa1n\xf9\xb5\xf6\xb2\xc0\x1a5n\xf1\xcc\x80\xfc\xda\x04\x19F\xdb`\x7f\xcf\x0d(m\x92\xe1s\x03y \xe3Sh\xb8E\xbe\xedmJ[OO\xfb\x86\x8f\"\xb0\x82C\\HQN\x16%\xde\x0d\x0b\xa0YQE\x98F\x04\xd1\xd6Q\xa38p\x1b\x93D\x91\x01\xe3\xcd\x06\x16az\xcd\x98\xa1\xfc\xaea2[\xd5\xe8\x84\xc4r\x80\xcf\x0d\x84\xd5\xacD\x938J\xc8\x00\xaf\xb6\x859M\x07W\xe1dF\xe4\x97\x0d\xb4\xd6l\xa4df\xd5B4\xac\x89f\xcd\x1b\x9e\x02r\x90\xe5\xe1bYV\xd6\xec\x00 \xd6\x8aINjs\xb2\xd5\x1ef\x86\xb71\xb3\x8d\xa9\xc0\xdf\xd6\xf7m\"\x910\xb5\xad\xba=\xbd\x8c\x06\x9b\xdcF\xd3\x18\x83R[\xd2\xec\x94\x08\xd3\xe04\x9a\xcd\n\xc1\x1aD\xfeT#U\"\x9cF\x9c~\xde&k\x99\xd5\xeecc\xb4m\xc8\"\x8f\xe2\xba\x8c\xdc\x9e\xc4\x9b\x88\xdc\xd6`\x9e\x1b`RJ\xf3A\x94|$\xe3\xbc\xec\xdcw%\xa46]\x0d5^\xd8I\xdc\xa8fly\xd0\xd4\x8e\xda\xb5\xa5\xad9\xbd \x8d[Z\xfc\x06M\x0e\xeb\xb0U\xbb8S\xbf43\x8d\x92 ,\xf8\x0d\xa1\xaf\x1dX\x07\x02\xeb\xe0|\x1d4\x0d\xbdR\xd7V\xfa'\xff\xa2\xc15\xb9\xb7\xe6O\x16\x95\xc5\x11\x0e\x83v\x95\xcb[\x0f>\xd0 %\x19\x8do\x08St\xeb\x17\x1d)+\x8d\x98\n\xbe\xb5\xf9\x0d\xc7\xee\xc3\x07\xef\x1f\x0f\xde\x8b\x7fll\xfc\x1f\xc8h\x91\x8e\xc9Q\xb8\\F\xc9\xec\xdd\xe9\x9b\x9d*\xc3\xe1\xe0\xaaH&1[\xe7\xc1\"\\\xfe\xff\x00\x00\x00\xff\xffPK\x07\x08-\xe3\xb5\x97=9\x05\x00\xf7\x0c\x1b\x00PK\x03\x04\x14\x00\x08\x00\x08\x00\x00\x00!(\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1f\x00 \x00swagger-ui-standalone-preset.jsUT\x05\x00\x01\x80Cm8\xec\xbdys\xdc6\x9a0\xfe\xff|\x8aG|w\x152M\xd1\xdd\xad\xc3:,k\x1d\xc7\x9e\xf5\xbb\xf1Q\x963\xf3\x9b\xb7\xa3UQl\xb4\x9a1\x9b\xec\xe1!Y\x13i?\xfb\xaf\xf0\x00 \x01\x10 \xd9\xb2\xb33\xbb5\xacT\xac\x06A\xdcx\xeec\x0b\x16U\x1a\x95q\x96\xba\xa5\x0f\xc4\x83\xdf\xfe\x00\x00\xe0dW\xbf\x92\xa8t\xe0\xf4\x14\xca\xbb5\xc9\x16@\xbe\xac\xb3\xbc,`{\xdb\xf4v\x95\xcd\xab\x84\xc0\x19\xff#\x10\xb5O\x81\xb8\x1e\x1c\x83#\xba\x91?\x9a\x93E\x9c\x12\xda\"\xfb+\x08Ws8\xe3?\xdc\xd9\x05\x0e\xe8\xb8k0g\xe2\xaf\xe0\xfc6\xbc\xbe&\xf9\xcfo\xce\xcb0\x9d\x87I\x96\x92\x0f9)HY\x0f\xa1\xec\xab\xf3\x87\x07\xb7\\\xc6\x85\xdf,\x89X\x8e\x9c\x94U\x9eJK%^\xd0\xe7&\xcc\x81\xc0)\xfc\xf6p\xf2\x87\xbaPT\x85\xd4\xcd\xe5\xca\xf4\x89\x17\xe0\x92Y~\xe1\x89v\xe9\x0f\xb1b'JU\xdavLG7\xcb/h\x17\xcaKl\xeb\x18r\xbfU\x9a\x1c\xc3\xd6\xa4]\xcc\xbb8\x86\xdf\x1e\x94w\x0fj\xa7|T%\x1dU\x14&\x89\x1b\x8b\xc1\xf9\x10\xfb \xfdJ=\xfa3\x81S\xd8\x1aK/\xea\xd6\x9anx\x9bi\xb0\x82S(}H\x83\x88N\x8b\xfe1\x87S\xf5\x10\xfa\xd0Z\xb24\xc8\xf8\xf9\xbc\xbf\x87\xf7x\x1c\x02vL>\xe4\xd9\x9a\xe4\xe5\x1d\xff\xb2\xbdBQ\x96.\xe2\xeb*\x0f\xaf\x12bY\x96\xb4Z\x11\xf1~\xdc~\x7fM\xcac\xc8\xd5\x15\xf3\x9a9\xd29\xa4\xca\x1c\xf4\xd1\x8b\x13R\xd2\xa3^\x06\x97\x97\xa4x+\xeeK\xeb\xac\xc9\x8f\xd8 :\xd7\xb0JJu\x0cp<\xec\xeb\x01{\x9d\x06s\x97\xf8\xe0\x84\x0e]d\x1f\x88:\xbdL\xdf\"\xbd;\xde\x0c\xdf\x99u\x9e\x95\x19\xbd\xa9\xc12,\xde\xdf\xa6b\x8f\xd8i\xc2\xef\xd5\xf6\xd7p\n\xce\x93y\\\x94\x8e\x0f\xa9\x9b\x06\x14pL\xc7\x07\xac\xda\x83;\xd3\xceG*\xf7\xefT\x05\x81\xa2\xcc\xe3\xa8tN\x94[\x99\xc3)\xa4\xee\xfe\xd4S\xf7\x94^\xa8\x99\xf39N\xe7\x8e\x0fNN\x8a,\xb9!\xf4\xcf(K\x8b2\xaf\":\n'N\x8b2L#\xf2~A\x7f\xads2\x8f\xa3\xb0$\xec\x935\x05\x1b)\xd6\xe3[s^\xde%\xf8\xb2\xa0\x7f\xbcH\xe2\xb0 \x85s\xa1\xf6\x9ca\xcfE\x14&a\x8eu\xc9_+\x92F\xf8\xdd*\\\xaf\xe3\xf4\xda\xb9h\xe6PJ`\xb4s\xf9\xe9dS\x1f\xaa\x936\x9c\xa1\xb7\x8c^\x9a\xdf\x1e|\xb1=\x9f\xc9]\xe1\x12/Xd\xf9\xab0Z\xbau\xd3\xadvE+;\x138==\x858\x88\xd39\xf9\xf2~\xe1\x12\xcf\x83r\x99g\xb7\x90\x92[\xc8\xdd\xef~N?\xa7\xd9m\n\xd9\x1a\xa1\x9e\xf3\x1d\x8c\x80\xc0\x08\xbes .`EJ\x88S\x06\xd8c\xac\x90-X\x9d\x92\xd5\xf9\xcb\x8b\xb7?!l\x0f\xbe\xf3\xb4\x8b\xe6\x03\x05\xcaA\x19^3\xc8\x81\xbf\xe8\xe6\xd1\x99\xb1?\xee\xef!\xad\x92\x84\xbf\xe3\x1b\x8a\xaf\xc5\xdf\xf7\xf7\x83\xae\xca\xd6X\xed\x9c\xb7X\x9f\x0bl\xb3\xf9%\xb7\xda\xba\xf4`\xbd\x81\xbc\xd5\xe6\x80a\xb3\xd2Ou>\xf5\xd1\xc3j\xcd/}\xd6\xfcL\xf2y\x8b_j-\xf9\xb0bE\xa5@\xad+\x1fd8\x057\xc5\x0f\x94\xd2\xfa\x83\n\xf1\x9f\x8f\xbf`\xeb\xf4\x14R\n\xea\xe4\xf3\x96\x1a\xce\x9bq\xcd\xd2Yy1\xf0h\xd2\xa7\x9a\x9d\x97y\x9c^\xbb\xc4\xa3\x18\xb2lUzh\x1f\xa8\xca\xf3\x81\x1f\xe9\xac>\xd2\xf5\xb9\xb2\x1dm\xd0F%\x1e:\xba\xc8\x87\x85\x0f\x89\x0fk\x1f\x96\x8c\x06\x81\"x\xdd\xa6r\xe83\xaf+\xfc\xd1\\\xe1\xa6\xaepn\xaepWW\xf8`\xaep]W\xf8\xc1\\\x81\x12\x88\x94\x0b\xc8\xe1\x18n\xe8\xbf3\"N\x17A\x1a\xf8\x81\x12\xf3\xae(\xfe\xed\xc1k\xe8\x0ds\x8b\x97\xbc\xc5\x98\x9eB\xd1Z\\\xb7f\xfe\xe8\nN\xe1\xb2i\x19\xbf\x91\x7f\xe3\xa7'\xadO\xe9\xf5w#Dvx\x98\x10hz\xb8?\x94Lv]\n\xec\xb7\x96\xf4\xdd\x8a\xfe\xef&\x8b\xe70F\x90\xb9\x9aE\x17\x1e\xe5\xa0\xe0\x18Ro\x16]\xf8@\xe9\xa2kZm\x01g\x10\xba R\xc6\xc7p\x87L\x98\xe9\x0e'X\xef5\x7f\x83\xf4\x96\x0f \xfd&\xf1Y\x87\x95\xbb\xf2\xe9\xa1\xa0P\x1e\xb7\xe1g\xcf\x87\xcbYt\x01[\xa7\x90\xe0\xcdu/\xb1\xc6\xda\xf3YOW\xf2[\x17\x7f\x9dB\xa2\x81\xd5f)\xf2 bw9\xf6\xe9I\x83S\x98\xd0?\xfeHI:\xfa\xc79\x9c\xc2\x1e\xfd\xe3\x03\x9c\xc2!\xfd\xe3\x07Z\xe7\x80\xfe\xf5g8\x85]\xac\xf53\x9c\xc2\x01V\xfbH\xdfN\x0f}\xe5\xc6\x17\x9b\xdd\xce]\xe3\xed\xdc\xd3\x8b\xf9\xed\xd4\xef\x1b\xbd\x9dO\x9c'\xd7\xed\xcb\xa9\xf7n`]@b\xe38\xaa\xca\xdc\xd2\xb3\x1c;\xda\xa8\xf3\x8c\x02H\xd2>\\\x1c\xde:N\x83b\xdd\x10F\xa7\xe0\x00\xfd\"\xa5\x18\xe7\x14\x91\x0f\xef(\xf7(%\x90\x84\x11q+\x1f\x9c\xed\xbfVYy\xe2x\x88\x99\xbe\xf3|\x08a\x04\xces\xfamL\xffz\xf6\xc4\xe1d\x9b\xf3\xdc\xb1m\xeffD)\xe7\x8b\xe5\xf2\x94a \xe2\x86\x9e\x0f\xb9\x9b\x07\x1f`\x04y\xf0\x1a\xbe\x87\xd8\xed\xa4\xd2\x04\x1f\xe580+/\\:\x07\xeb\"\x11\\#\x12\x94\xd9O\xd9-\xc9_\x86\x05q\x91{$A\xb1N\xe2\x12\xbf\x0e\x12\x92^\x97Kx\x0e\xbb\xeat=\x1f\x1c\xb6\x86\x94!\xe9C\xdc}\xe8\xc9\xa9R\xc6\xac\xce\xe9\xce\x89\xbbz\x1b\xa7\xf3\xec\x96n\"\xfb+x\x1b\x96Kz\x97\xf1\xdf3\xf1\xfe\xd8\xf2yA\x92\x05\xfd\x98\xfe\xab\x7f\x8a\xef\x8eA\xc0\x01\xd7\x11\x84\xe82.\x1c\xcf\xf5z\xf0\xe05\xc7\x83\xd7\x8f\xc0\x83G\x9d\xa4\xca\xbe\x8e&\xd9\x8d;\xfa\xdfC\xaa\xd8\x89\xb8\x03\x9d\x16\xa0Kb\x90m\xc9\x1b[o0#\xa5\x91d\xe5\x7f\xf27\xed\xe5\xcc\xe9\\b\xfa\xbf\x01\xfb/\xaf^6\xf8p\xbf\xc8\xf3\xf0.\x88\x0b\xfc\xd7\xdcX:\xb8\xb1\xff\xe57E\x9e\xf2\xb0\xb3J9nN\x17\xd0\xbe\x04;\xf2\xe9nM^\xe5y\x96\xbb\xce\xcb0\xfd\xae\x04\x8a\xdd)k\xbd\xcc\xe6\x90\xa5\x00\xec\xac\x9aey\x9bB\xb0\xa6\x15E\xb4e\xb9Vt\xb5\x9a\x1e\x94\xf3\x95\xdfi\x9f\xd0\xf6\xd2\xce\xd3\x89wq\xec\x03\xb9 \x13\xcfuXq\xd3\xfee\xd9\xc7\xbf\xcc\xfb\xf8\x97\x9b>\xfe\xe5\xae\x8f\x7fi\x18\x9c?\xdb\x19\x9c\xe5\xa6\xec\x08\xe5aV}\x8c\xce\x15o\x99\xb2Ns\xc1:\xd9x\xa5.\xdee\xa9\xf1.\x8ckY#3\xa0q-W\xc8\xb5loC\x88\x8c\x05\xbb\xbc\x94\xd5\xa1,\x0b\xf2\n\xc7\x90\"3\xb3b\x8c\xc3Rc^\x9a\xd3\x8f\xb5\xcf\xb0\xb6`rh#Y\xcd\xf7\\\xd7\xdc\xc8\xe9)\xb2:\xdd\x92$\x90H\xc6F\x90d\xa7\xd2\xc5C\xaf'\x05: Dr\xecf\xda?\xa0Oq\x1b#T\n\xf3\xebjE\xd2\xb2\xe0\xb4e\xdfw\xf4\x89\xc2\x82\xc0\xf8\xb8\xb7\x1eH\x02{r\x0be{\x0b\xf5\x07[\x9el\xde\xb2K\x0c\x94\xb5\xfe`\xe3\xd3\xc74\xae\xd0\xd4\xa6\xe7\xa1\xf3m\xab1\xba\xa1\xd6/\xecm\xd5\xea\x95p\xbdN\xee\xb8\xf2\xaf\xde@s\x8b\x0f\xe6u\x11\\\x87\"!\x904!\xb2J\xa5n\xcaE\xce\xfc\xa6\x93\x9b\xcfl\xdc<~\xe6\xba\xab\xe0&\xce\xcb*L\xf0\xe25\xbf\x10\x96x\x9cW\x17\xbc\xfeG\xfa\xcd%\xfd\xdf\x16\xb2\xfc(\x0f`\xdc~\xe2yV\x8e\xfe\x1f\x85\x8b\x9f\xeab3.dk\x953\x1cu\xa8#4\x8a\xa2\x8c\xca\xc3f\xaa$X\xb06\xf7=83W\x96\xd5n\x16\xccE!H\xee\x96\x9e\x8f\xb0'\xa3gtk\x8c\xdc.jL=\x03Y\x04\xcd!\xaa\xeaf\xd5\x0d\x91 \x9f\x87V\x7f\xce5)\x1d\n\xbc\x91\xb8r\n\xf1\xcb@>\xbe\x88\"R\x14Y\xce\x08\x8a\xa2Z\xd3\xfd \xf3-\x0bA\xe1\xdc\x84IEx\xdb\xf4\xd0\x95\x0cY\xa5\x01\xbe\xf0\xfcMI\x0e\xf9\x08l\xa5\xee\xf4\xc8\xb3\xf3\xfd|\x0cO)\x9e0+~\x7f{\xe0\x8a\xcb\xf6\x82\xa2\xe6\xb6S\xa4 w\xd1\xbe\xa0\xea\xfa{A\xd8\xcc\xb3\x9f\xd8o\xe4\x1f\x9a\x1a\xb4\x8f\\\xb4\xebWS\xa3\x06u\xc8\x92K\x82j\xcb%\xda\xdd\xb3\xb0\x85\xa9\xbb7\xf5\x14dk>\xf4\x82\xc5\x0e\x16\xbcF\xecNh5\x99t\xef\xbf:\xb5\xf1\x01;b\x1b\x9f-I\xe67\xb1L\xa8\x9b0\xdf\xa2\x17\xb7}iT\x1a<\x05\xc6k\xd8\xaeL\xdf\xa0\xfb\xf8`uX\xff\x8d\n\x8dne\xba\xb2rCd\x82\x88\x9bc\x1f2\x1f*\x1fB\x1f\n3\xa8\xa4@d\xcbHc!\x03\xd0\xc6\xb9\n\x8fL\xc9T\x88\xe8\x1c\xc9-p\x18\xf76N\x99B\x8e|\x89\x08SJgQT\xe59\x99\x9f\x00\x9dd\xb9$\x90f\xe9\xceJT\x9c\x93\x1b \xe9M\x9cg)\xc5\xffH\x0e\xd3J\x8b*I\x80\xd0VaE\x8a\"\xbc&\x10\xa6s\x08\xe7sTe\x87 ,I\xb2^T \xdc\x86y\x1a\xa7\xd7E\xa0\x9f\n\xfa\x90\xa4 \x1dD*E;3}\xb1.\xcct>}(\x86\x1f\x9bi\x11W]\nR\xcb\x80\x9f\xfck\xf1\xe4\xda`\xdedz\xf8A^\xcc\x92\xd1\xe8\xc2X\xeb\xc1\xf3\xbc \x0dW(\x91}\x93\xde\x84y\x1c\xa6%\xfc)\xce\x92\x10)\x99\xd6WmJ\x8c\xdd\xb2(X\xe4\xe1\x8a\x14\x9f\xb2\x0f\xd9\x9aQ\x1a\xd1\x1f\xcc\x1f\x0e\x82\x01}\x16!OM\x9c\xae\xa4\xac\xeeW\xec\x0b\xb6bvaa\xa3\xd8\xa5\x8eS\xca8\x90`]\x15K7\xed\x10V\xab\xb35_\xacD\x9d\nW\xf2\xca@.\x0b\xe2tI\xf2\x98\x83\xed\xdd}O\xfd\x84\xb1\xe8\x93C\x1d\x03p\x1e}\xf2\xd4\xd8\x16e\xbf*\xe9M=?\xdaK\xec\x86\x0d\x91\xeb\xf9x\x0b\xc7'\x10\xc13\x10\x1c\xd0 D\xa3\x91\xbe\x88\xe2\xc8\x17\xb3H[\xc2\xa4io\xb6`\xcc\xb1Vt\n\xa1R \xa3\xc2f\x94|\xff \xb1\x80\xf9\x16\x8b\x97x\x9e\xccY\xd0\xef\xd4\x91U\x1c\xfb\"\x9b@\x89\xbbP/@\xa9\xec\x16\xb3,(\x83\x9c\x84\xf3\xf0*a@\x98\x1bi\xf0\x92S\xd8\x9a\xb4\xea\xdf\xe6q\xa9\xd6\xafKD}Z\x18&Iv\xfb\xefa\xb2x\xbf&)7\xbdS\x1bRk\xd4\xad\xb5>\xac\x9b\xcc\xd2\x88\xb8\x0eA\x83\xa8u\xf7r\xae[P\xc3\xd0\xf6\xfd=+\xbd\x14\x138/\xc3\x92\x04$\x9d\x13\xb4\xd6\xc9\x83\x94|)?\xc5\xd1gw\xc9\x86\xd0\xdd\xe9\xb2\xbd\x87%m\xcd5\x89\xf2\xccTb\"\xf3b\x8e\x18\xd7\xbf\xc7\xd7\xcb?\x87%\xc9\xdf\x86\xf9\xe7\x16 \xa9\x18\x06j\x86\x83\xfd\xa4\xa5$\xd5\xd4\x17b)w\xab\xde\xfdfB\x9e?h*sR\x94yvG\xe6\xad\xe1\x0f\x1e\xa2$\xcea\xa3\x15\xe7\x14G\xab |\x0c\xf3i\x8e\x98\xfaeP\x8f\x8d\xd60-D]Acu4a\xa12\x113@\xfe\xfd\xa7\xd0X\x9f\xd9&A\xabx\x1d\xdb)m\\p\xc9\xbf\xea\xa3\xfc\xb1C\x86?\xaa$\x11\x17\x16\xcf\xbe/\xdf#\xe2\xcb}\x7f\x13499\xda\xb3\xea\x8a\xec\xbb!\x8e=\xaetN\xd7\xb56\n\xeb\xa3\x8a7\x1c\xdf\xde\xc1\x9e\x01\x8f\xbf\x0d\xcbe\xb0\n\xbfv\xeds7\xde|\x02\xd2\x80\xcc\xe3\xd9\xb73\x88LZ2\x90\xb5\xfb\x87a\x10\xa7\x87\x1b/\xf0\xdf\x85A\x1c64!\xaci+\xc1J8\x93\xee\xa0\xcd\x19\xe3\xdb\x8f\xa8S\xc8\xb5\xb5U\xba\x1d\xf2-\xebg\x9a\x85\xeec\xf7\xdeb\xaeg\x16$\xee\xeb\x06\x96\x8c\x90>:\xf4\\\xa7\xc8#\xdd\xd4\x81\x92\xd3\xb5\xd0\xb6\xcc\x98\x1dI[\xfd\xe5:\x0e\x8c \xf4\xb8=\x8a#j\xca'\x06-\x08\x838-\xd6$*\xcf\xb3*\x8f\xc8\x90C \x08S\xe9f\xf96K \xc1\xa5\x87&\x12=\xb2Y`\xa4\xea\xa9\x8e\x10\x7ffn\xea\x83CYB\x07\xf5@q\xf3\x9b\x1e \x8a\xbc\xe8\xadm\x8c\x97\xa4\xcf\xaa\xe6\x8b\x8a\xd7;\x03\\\xa1\x92i\xb1\x8a\xe0\xd7,N\xdd\xda\xda\xd7\xc3\xf6\x90\xe2\xcd\xe1\xac\x86\x07p\x0c\xa1\xf8\xa9\x94\xc6\xcd\x818\x06wN\x12R\x12|\xefK\xaf\x14K\x8fF\xf2.\xd3[\xf56u0\xd2\xe2.\x1a\xef\x19e;894\xab\x90\xc1\x91\xf8\x08\xb9\xffot\x0d\x7fo\xc0\xb01\xd66_\xbd\x03\x93\xa2\xd9M\xdd\x83\x03\xcf\xc7\xf7\xe3\x86 \xb69\x98\x18\xaf\xe9\xe4@7\xf3\x0b\x8d\xaeT\x9f\xc9\x9d\xd9\xff''\x0b\xf3\x8b\xcb\xcb\x82$\xf6wx]\x8f[ \xcb\xe4%VX\xb7M&[\x83\x9c,\xa4\xcdh7\x13\x0dk\xe63\xb9\xd3\xf6\x14$\x96\xbc\x0d\x1ar!\x962\xc2\x88\xb6\xbc\x92>\xff\xf2/\xec\xf8\x1cC\xd5^\x1c\xfa\xea\x18\xca\xf6\x0b\xdc\x03\x83v\x1b\xb7 m\x97\xaf\xf3l]\x1cChX\xff\xec6%\xf917j\x12\x8f\xd9\xfbI\xb2]\x91\xc4\x1cA\x94\x93\xb0$\xaf\x12\xb2bn\x15}\x94 \x9e\xf1\xda\x17\xa25\xa2\x84\x9e\xc6*I\x0c\xb3\xe0o\xd4\xc1QZ\x83\xdfNY\xdc/\x1e\x14\xc3\xe4\x10\xd3\xc3CP\x03\xef\xae\xb9\xef\xc7\xc2\xf3!\x12\x85 3\x98\x1c\x01\xa1\xfb\xee\xf9 \x8bM\x03v\x84\x05\x1c8\xaeK\xda\xd5\x18\xf2Q+b\x19\x02\xa5\x8c\x810\xe6\xbb\xb7\xbd\x0d[\xa1v5]V\xeeV\xcc\x93\x11\xfd\x1fOZ\xcb\xb7\x84S\xd05\xe8\xb0\x03\xd3\xf6\xca0Y\xc7\xd2\x83*\x88\x96q2\xcfQ\xa4\xa1\xa1%\x94\xb9\xd2\xdaKx\x0e\x13\x13YQ\x0b\xb3\xe6\xc2\xac\xcd]\xd25bb\xac\x1bx\x06\xcb\x13\xb8\x19\x8d<\x98\xcfn.\xe4\xd1\xcdn`\x04S\x83\xfco\xec\xabc\x9a\xab'\xb05\x13\xee\x15\xc8=q\xe8z\xb5\x84\xe4\xc0\x97\x07\x8dO\x94\x9a\x16\xf1#\x9e\x8b;O\xdeD\\xi\x07\xee\xe8\x0et\x0cM\x08\x80\xe9ig\xee\x03c\xfc/\x0eP\x8a\x9e\x96\x14g7\x17\xc7\xaf/\xcc\xeb0*\xb3\xfcn\x90G\xa4v\xc9\x82\xab8\x9d\xbb\xdc\x07\xc9L8\x93@(\xd75/\xc5E\x10%YJ^\xa4\xf3\x8fL\xdc\xfd\x1f\xa4\x97\xb9n\xe6\x18p%\xbd\xcf\xa0,\xfd\x87\xdf\x03\xfa\x07?\xe7e\xc0\xa0\x8a\xcf4\xfb\xebB\x9f?\x1d\xc0f\xf0\xa2\xaa\x0d\x9brTd\x8a\x86\xdb@\x02m\x9b\xe8\x15n\xbfB\xc1\x03\x0e\xbb}j(\x12\xed\x9a\x8b\xb79\xd0\xa9\x14\xa03\x17@\x87\xdd\x9a\xfax\xc80h\xa9\xc3 \xb6\xde\xec\xe0#\x1e\x97\xcft\x0d\xb6\x0c\xef<\x0d\xdaT\x16h\xc3\xca\x15\x15\x11%\xb6T9P\x02g\xb0\xa6\xc5\xa7\x90\xd0\x7f\x8e\xc5/Z\xd7\x00\x9d\xee6\x84Nw\x1e\xac\x87@\xa7\xbb^\xe8t]C'\xbaz+\x06\x9dV\xf0\x0c\xeeN`E\xa1\xd3\xf5l\xa5B\xa7\x95\x05:)\x03\xba\x1et\xff\xf9\xddX\xfa0\x17@\xe0F\x95\x13\xd3\xc3\x1f\x17\x7f\n\x93xn:\xfe\x9bP\xa4\x8a\xbc\x88\x1d\x10AJ00&\xf7\xaa\x10\xc0\x7f\x80~\xe2T\xd2\x0e\x1f\x98Y\xc0\xdd\x83~\xa9@\x87\xb3\x03c%\xcc\xa0+wS\x8f\"P8\xe6\x87\xb0\x99\x8aq\xec\xfa\xc09%\xa6\xab\x8a\x8d\x04ef\x10\xd3\x0b\xc3R\xae!-H\xf9)^\x91\xac*a\x192\xb1\xc5\x15!\xdcK\x97\xcc\x9dn\x91|\xd5\xdfA\x94\x900\xff\x8a.B\xb3\xfc%\xc5s\xd0\x8c\xbe\xd6\xda4Et\xf9\xc6\x06\xc8\xc6\xbf\xcd(\xd3\xb5\x95\"\x880\xb4C\xf7\xb1)\xf6{\xda\xed\x94r\xa4\xec\x0b\xf5\x9a 9\x87\xd1\xa7\xd5\xdc\x1c\xb4l@8\x92l\xb5\x0e\xbd=\xb4\xdb\xe2\n,s[\x16\x10\xf1\xb0eg\x7f\xcdsHm\xb2\x04\xe9 \x9e\xc9?Z\xc4{\xa7\x80(\xad=\x18\xea\xfa\x03\x06\x95\xdb\x06\xa5\x1c\xde3\xf5\xe7\xb1\x04\x85\xa0w`\xb4\x8b\xca\xb6\x8a\xae\xa6\xa2-\x98\nu\xa6i\xfe\xd1\xfeV\xd3@Q\x0c\xb931]\xfe\xb6\x8e\x8e\xf9? J\xe4M\xd5\xeaY:9z\xe0\x83(K\xa3\xb0t#\xb4/\xc4\xb6}\x88D\xa5\xedmX\xba^\x9f\x96\xcet]\xb7\x166j\x96\"\x89\xd0]\x1b\xd4\xe28F\x83uC\x8d\x0f)\x01\x18\xd5\xfaerb;\xe7\xf8\x01\x85\x92\x91X\xd7\x13\x18\x8d\x12x\x86\xdf\xe0\x82\x14\xb3\xe4\"\xc8\xab\xd4\xb5X\xbc\x8a\xa5\x90\xbb\xec\xb9%\xc0%|\xec\x8e\x9a\xf6N\x865\xbc\x92\x0b[Jk\xbd\x1d\xdeP\x85 \x90\xf1d\xc6F\xe9\xa9\x95_\xf8\xc3\xbb\xb1\x830\xf1\xe4n\xd9\x864\xe2\xe9\x87^\xe2\xe9\xef\x08d\xb5\x83\x0c7\xed\xdd\xc3FC\x80V\x07\xc2\x1a\xa0\xbb\x03\xfb\xec\x8do\x1e\xf4\x05{\xe8\xbc\x89s\xbb*qQ\xa5\x92&3\xa44%%x;\x9b\xbbq\x15\x8b\xd3\xb8\xd6:\x0e\xe2\xf1(E\xc0hW\x03\xed<1`\xe9V5J\x1d\xdba\x01\x9d\xcf\xe4\x04Rx\xd6\"\xceO \xa5\xc41\x99\xa5\xb4+\x95@N5\xe28\xe2ZVr+\x96\xcf\xf3a\x82th\x0d\x05\xef\xef\x01\xa3s\x84\xeeR\xa1~\xe7\x92D2\xaf:=\xa6\xc4&p\x9bs)\xde\x06\xee\x85\xd2l\x1c\x94q\x89\xd6\x1f\xceU\x9e\xdd\x16$wh!\xff\xbb\x89\xba\x94\xde\xf0\xf0\x1bq\x10\xe6\xd77\x0c\x7f@\x1cp\xbbAd\xbe\xa4\xdfE]\x1b\xdf\xdd\xe0w\xf3\xf9OqQ\x92\x14\xdb\xbda/Q\xd9\xc0\xfe^,\xc4\x9f9Ye7D\xaf\xccJ_$\x89xQ\x887d\x15\x97\xe2\xefuN\xd6$m\xf5\xc4\x8b\xdf\xa7Q\xab\xddDj\xae\x97\xa1\x98]\xa8\xabw\x15\xa7\xf38\xbd\xeeVR\xe9T\xeb:\xcf\"R\x14\xf5\xc7\xb1f%\xedh[\x14\xdd\xce\x07x\xc89O\x1c\xed\xb3\xe5\x0f\x18\xd9&\\\x88\x91R\xe22y&\xc8\x81\xb3\xe1\xbd\xf9\xd3\xab\xcb7\xef^\xbfy\xf7\xe6\xd3_\xb0\xc6\x04\x9e\xd8V\x9a|)I\xda\x8a\x8bh[\x02\xa6\x9dk\xd3Q6\xf9-.\x0d[:7S-\x9f]\xe2y\x0d\xed\x04\xcf o\xd6\xae\x9c\xc5\x94\xc5\x9e\xa5\x17LD\x1a_|\xfb+$J%9\x9d\xd9]\xa5\x15\xd4\x8fYj\x8c=\xd35\xac:5v\x063n1\x95 N\xa3\xa4\x9a\x93\xa1\xa1\xcb(\xa7_\xf7\xa5\xbc~\xe0\xc6\x0fC[2D@3\x8c_<\x84\x85\xc7C\xe5.\xfdk{[\x84\xc6ce\xf8\xe7\xf66\xe4\xc2\x12\xbd\xd5\n\x1d_\xca\xde\xea\x9c\x06\xbeY\xc4IIr\xb7\xf3-IN(\x11\x17\xa2\x17\n\xfb\x06\xc11z\x0d, \xd4\xe3\xa740d\x0b\x08\xa1\x88\x96d\x15\x06\xf0F\xbcb\xf1\x0d)>\xc8\x16PT\xd1\x12[(Z\xc4a\xe0\x18\x8e\xe3\x12C\x1b\xae\xd6qB\xe6o\x9a\x95\xab8\x0b\xeb\x88\x018>\xcc.\xf4\x0f^}i\x7f \xd6\xd3\xf8\x01E\xcco\xc3u\x17E\nB0\xc4n\x90\xd1\xae\x80>l\xb1\x8e\x8dZv|\xcf\xc3j\xdak\xf0`\x9b\xf6\n\x8b0I\xae\xc2\xe8s+V.}d\x89{\xfdA\x07\xce\x17O:cW\xf1b\x86\xd7\x94\xf9P\x8a\x9e\x9a2C\x0c\xc3vw\x14\x90\x97\x0c\x90\x13\x83Z\xea\x04J\x86\xf9J\x0e\xbd\x1b\xc6W\n\xaf\xa8k\xff@\x12\x0d\xab\xe7\xc55\x9e\x16\xcb\x99\x90/\xb7\xf8+\x0c~|\xf5\xfa\xc5\xcf?}\xaa\xe5b\xa1`\x19:N\x848\x0d\xea07\xf1\xb5\xef\xf2\x80G\x01\xa4\x18\x97\xb6\x8e\xb3\xb1AyF\x9f\xab\x9c\x84\x9f\xdb\xaf\xba\x9c\xe1K\xada\xbd\xab\xc9f]q}\xa8\xa5/\x19\xc8\xfc9\xcf\xd2k`\x9e\x81\x08AD\x97x~\xce\x194\xe1\xbbP\xb3v]F\x01\xcc^\x81\x02vN\x0c\xd6N\xceM \xf3\xe5\x0b\xc8\x0d\xc9\xefz\x80\xa7\xc0\xb3\xb2\x1bN\xa8\x01*\x0dn\x9e\xd7\x916\x05XDn\x88\x83\xc6\x02\xdc,\xa7\x802N\xaf\x13\xc2g\xc8Mq=\xca\xa0\x95a\x9c\n\x98\xab\xbcm\xf9\xec!wA\x1e=\x8dl\xd3i\xd4\x81B\xb59P\xb8i\x9b\x81\xf4\xae5~q\x8f\xc9-\x84\xae\x01o1\xf4id\x89\x05\x1c?\xd6\x1d\xd3\x14\x11\x83\xcc\xa4\xb1M\x1bj\xab\xf8\xdb \xcaP2Ho\x05\xc6\xe4\x81Om\x16\xe9\x83}\xf9j\xcdl\xe9C\xac\x83\xad^},s\xee\x16\x06\xa1\x9b\xb2\xaf\x9a\x0e\xce\x0b\x8a$\x8e\x88{\xe8\xc3\xce\xa4o(\xdd\x0e\xf5{\xbb\xff+\x1d\xea\x87-\xeb?\x80\xd5\xf9\xb7:\xf7\xfb&?U\xe6\xdf\x12\xa7\x8f\xa3\xec\xb3\x9eC:@/+\xb7=\\7+\xf5\xf1\xa3&F\x1d4z\xfaQ\xcf\xd8\x91\x86\xda\xb8a\xfcJj\x19\xc3\xc1\xc8\xb21\xac`\xeaO8\xdc\x0e\xeeR\x81\x9e]G\xe6C\x1e\xaf\xe22\xbe\x19\xbcL*\xa1i\x04\x1d\xf8\xc2p\xbdX\xfc\xc5\xf6\x05a\xe5\xed#\xaeS\xb2FPW-\x16x\xe9\xcb\xfaG]\xed\xc1\xab\xddaR\xf7\xe0\xd0\x0b\xd8{\xb3@es\x0b\x06\x03\xe9\x8e\x1b(9-s=\x80\x08\x06\xf6\x97\x17o\x7fz%\xc2\xae9u\x82\xaa\xb0\xc8d\xdb\xc3U\x98\x7f\xe6\xa6?\xf8\x93\xc7V;mb%\xd1\xfat\xcd\xdc\x8a\xa7`be\x1ef\xb0p\x9bF\xcex\x02\x8c\xba\xa4\xc6b,\xf7\xa4\xe3\xf9\xf5\x90\xd7e\x95\x93\xf32\x8c>\x7f\xcaCth\xb4\xbc\x11\x86\x9cK9\x01X\x86q\x88\xb1\xac\xa05\xd1EYXhy\xbc\x8c\x0eY\xb2\xf6\xaa\xff\xca;,\x9c\xd8 \xe4HZ\xb9\xd5\xf2&W_\x8a\xb9\x0e\xa3U\xea}\x1a\x81s\x0c\x8e\x91f!h%\xd1\xb7 >l1\x07\x9dz\x1f(\x85C\x9a|$\xa6\xed\xd0s\x0b\xca\x94\xd6\xa0\x84\n\xbd\xf6\x026\xf7\x1d\x96\xcdK]\x95Z\x08>K\xdd\xe9x\xeaiV\xf7B\x01\x8a\xef\xf7w'\xe8\x88\xbe\xbf\xdb\xaa\xd7\xc8\xcb\xb1\xde.\xaf\xb7\xc7\xff\xdd\xe7\xff\x1ex\x92\xc5\xcbc\xc5\x9dv/\xc66(S\xcc\xda\xdc lCip,\xd4\xcc\xd6\xdc\xa9\xa5\x9ed\x00\xe7\xeeY\xeap3;Mm\xa0\xdd\x85!ru\xcd\xc4.\x17\x82\xcf\xb8\xa3Q\n#\xc8\xbd\xe6\x00\xef\x1e<>\xae\xce\xe3\x03\xfapV\xea\x11a\x89$%\x8a\x1e\xc4\x84\x87\xf7oE\x1f\xcax\xb9\xce\xb0n\x10=\x99\x05\x8c\xfdg\xf4\xe4\xea\x9bDO6\xdd\x8f\xbfOPa\xd3H\xf0ZF$N,7v\x91dY\xde7:\xcb\xd0\xe2\xe2]\xf8\x0e\x15\xce#\x14#\x8c\xe1\x18\\\xa1\xc1\xc81OZ\xbfD\xc1.\xaa\xe9\x0f\x10\xdcw@\xd5\x10\xb4|\xd4\x9a @X+\x18\xad\xb7\xba\xcc\x13xs\xf5h\xac\xe6_R\xe5\xb2!\x05\xdb\xf27\xfa\x18D\xd7]\xa6\x0b\xad1\xf4\xe4Nh\x0f\xc3\x1a\x9b\xdf6\x92\xdd\xe1#Ah\xb0\xe1`\x14E\xaf\xfc\x0c\x90N\xd6\x9dw0\x0e\"\x9b\x00\xb1\xa6\x12\xd8\x04\x1f\x0e\xbb.qoB\x99\xded2\x8f\x0dTf\x8f\xaefQ\xdaO\xc6\xbd\xb7\xce\x02\x0d\x1e\x15\xd6\xae\x8f^l\x85\xfc\xe2\xf2Z}\xf0\x0c+\xb62\x06VbNm\x19m\xea>\x16\xbe\xdc\xf0\xa8:\xa1k\xa4\xd7\xb0\xed\xca\x87\xc2\xe7\x99\xf0\x0c\x95(\x1e\x8efcC\x00\xe9\x04\xdf\xe8&G\xd9\xb0\xcc{\x1d\x9a/2+.\xba4\x9fZu\x83q\x80\xcf\x8c\x12xv\xbf\x96\xc5(\"\xcf\x98\x07\x00S\x1c\x17|X y\xc0\xe41\xf2\xab\xc2\x87)\x93\xb5\x9eu\xe3BhF\x96\xd4\xf8\x90q\x80\xfa@\xa0/\x16\xa9\xb1\x1d}6}\xc7Xn\x98\x91U\xbf=\x18\x15\xd0\x8f\xbf\x04\xc3.\x9f\xa2\xeb5y\xf01\xedo\x13p\xfd# \xa3\x92\x07L\xff?\x0e\xcf\x84\xec\x9c\xc0M\\\xc4%,\xcbr}\xfc\xe4\xc9\"\x8c\xc8U\x96}\x0e\xae\xe3rY]\x05q\xf6$\xa7\xdf=\x99gQ\xf1\x04?\xde\x99\x93(\x9b\x93>\x81\x9c\x999\xe6\xa3\x91\xc7,\xd5\x9d\xed0\xbf.f\x17X\x8f\xa4\xb4\x89\x9f?\xbey\x99\xad\xd6YJRY\xaf\x96\xc3\x08&\xba\xf2\x8c\xb5\xa1\x06\x7f\x17\xa2\x89,\x1f\x1e9\xbe\x89\x1a_\xf4\x87\x8b?i]\xff\x18\xe4\x10\xee\xba\xaa\x8e\xc1\xf4\xb83\xfa\xba\x0fq;\xacz\xdcs\xea\x06\x9d\x1b\x89\x82\xb2q4\x8f`\xe5\xebb\xf1I\x87\xf7\xcc <\xac^\xb8?\xb4\xff\x12\xeb,\xb7&\xc1\xb78(\x97a\xf9\x11[+\x98\xd8E)z\x1d&\x05Z>\xba\x18H[y\xf7)\xaf\xf8\xab\xb1\xfe\x8a+\x17r\x11\xcfW\xfdn\x19w\x9a\x8f\x88\xb9)\xf9\xf6\xb46^\xf0\x03>\x04\xa5\x9a\xfdO\xe0\x94\x1f\x94\x8d6P\x94v(\xa5\x9e|\xbf\xa5n\xd7\xf7\xf0iI\xe0\x8a 7W\xd9\xbcJ\x08,\xf2l\x05i6'\xc1\xaf\x85__D\xee\xf4\x1ah\xdf\xeb\xcd\xfd[X\x95\xcb,\x07\x80\xd7$\xcf\x8a\x02^\\e\xd5\xe7e8\x8f\x7f%Kx\xb6\xc0\xc2\x7fc\xff\x04Y~\xfd\x1c\x9e \x88\xd4\x94\xb5\x1a\x15\xf6H\x8aA\x12{\xf9\xa4uu\xb9\x1c\xaa\xc5?CC\\\xb4\xb2\xe4A\x93X\x0f\xef\x94\xf2\xb2\xbe\x10\xed\x98+\xd0le\x11|\xfa\xcb\x87W?^\xbe\xf8\xf8\xf1\xc5_.\xcf\x7f\xfe\xf0\xe1\xfd\xc7Op\x06\xd3\xc9\xde\xd3\xbd\xc3\xdd\x83\xbd\xa7p\x0c\x93\xf1\xd3\xdd\xa7{\x93\xc3\xa9\x96\xef\xd6\xd2ah\xc5\x95\x94\xe2\xa4\xc3yF_7\x86\x17\x1f\xc3\xf4Z\xf0\xc9\x14(%\xf1\x1cI\xd190Os\x865:\xcc+l\xb3p\x85\xbd\xd3\xcfqZ\x1e\nCc/\xb8\xbcDl\x7fy\x89!,\x1a\xf9\xea\xb1b*\x82l7o\x00}\x9c\xe8a\xe7\x18\x8c\xe5\xb8\xd3\xa1\x85y=\n\x1b\xc5\x06\xc2\x88\xcb5O\x80\x07\xc4\x97\x95 \x85\x9an\xa0i\xba\xbd6H\xde\x1b\x14\x0d6\x12\x0b\xeb\xb7\x15\x10\xcaN\x89MZ0\x1c\xc9=\x9d\x8b\xda,\xb9\\\x12\xe6\x86\xb2\x88\xf3\xa2\xac\x11?\xac\xaa\x02\xedgB(Z\xd1j\xe5G\x10A\xf6x\x08\x0f\xb63\x105\x01i\x0cr\x1c\xcb\xd6Db\xfd,\x0c\xaae\x0d\x89\xd9l\xe8;!\xb5Q\xe7\xcdm\x87BnR\xdf\x91~\xda\x9c\x89\x16\xcf-W\xe5lo\x03\x91\xcf\x83\xfc\xae\x1dK\xbb\x83\xedFW\xbf\xe0\xea\xae$?\xe1\x89\xf6\xd1\x0co\x0c\x98\xeb\xba)\x86g\x8d4K\xbf\xaa\xdfe\x8bEA\xca\xef\xe8\x11\xc8*4G\xbf\xca\xaat^\xd8vW\xef\x936\x0e#p1\xf7\xf0\xd8\xb3\xf6\xc3\xee\xdc\xf0~0\x00A#cI\xa5\x00n\xa7<\xf0o\x0b(\xd4F.\xd6*x\x81\x8fM\xc5t\x99\xcd#\xe9\x04L\xa4\x0b\x10\xd1\nk\x06H;\xaf\x8a\xc1\xd0O\xd9\xfdc\x93R\xb1\xc5\xd8tx \x1a>\xc7\x05\xad\xf3\xc9\xdf\xdf3\xe7P\xa7*\x17\x87][\xbfU\x04q\xf1\x8a\xc3\x0d7\xb58`\x7f\xe7\x08\xd0\xe2H`\x83!\x056\x94\x1a\xf6\x98n\x12H\xf8t\x0c\xf70g\x1bg\xf6\xd7\x02\x8e\\]\x16T\xa8d\x86\x8e\xb7y\\\x12\xd7\x02U\xd9'u\x96\x02\x97\xf9\x042#\xfc\xb1\x0f\xb1\xf7\xe8\xed\xf2\xfaL\x1f\xc5C\xd7\xb2\xa8\x15\xba\x141uH\xb3j\xd5\x08\xdc\xc3\xd2%\xc2\xe7\xc9\x166c\x08\x906\x9a]Iu\x82\xb8\xf8SLX\xda\xfdv\xb1\xc9\"L\xaa%\x8f\xb4!0\xdb\xa3\xad\xa9\x99-\xd5R\x0e\x11\x1dK\x1caX\xe2\x9b:\xd9f\xd7*pj\xb3\x1eIW(\xc2\x1c\xc3\xfb\x9d\x9cx\xb5\xa2\xcf\x8a Q\xbd\xe5\x84E\x14\xc7\x8eY\xc9\xc5j$a\x19\xa7\x93\xce*Wq\x1a\xe6w\x96* )w\xcd\xe8\x845\x82d^W/U\xb9\xd8\xe9\xac\xc1\x08\xed\xdeQ\xfc\xec\x96\x9eu\xc1\xa1\xe9.*\xa6\xdd\xe3\x89\x8a\x9d\x9e\x1a\xe5br\x90\x90\xbe:;\x1d\x95\xa0\x19\xf7\x14\xbe\xef^\xc1%\xf9\xd2\xdfJ\n\xcf\x9f?\x07\x83?\x114\xdb\x19\x16\xe4`\xaf\xbf\xa9\x1f\xfa\x16\xb2\xd37\x1c\xa0v\x0c\x19\xba1\xc0\x990\x96\xac\x86Ph\xf6SvK\xf2\x97aA0\x03\x19F\xa1k}\xaa\xebR\xcd\xe0\xeb\xa6\x8bc\x11w\xab\x9c\x11\x03\xec\xe7F\x14\x14\xfd\xf9\x02 \xe6\x83:\xbd\x93\x98*\x8b\xfe\xb8\x01\x01eM1\xf2\x05\xdb1l\xa3E\xdc\x92R\xee\x10\x85\x81\xdc?\x0eyNx.K\xe4\xce\xf0\x8d\"\xa2\xa3\xd8}\xa7.9D\x90F+Ie\x1ekp\x94\xfa\xdcB\x82\x852\xc6j1G\xce\xa5\x1ccQ\x88\x04D\xa5\xfa\xe5\x08i\xfd\x94\"\xc0\xb2#\x88\x82\x98e\xdc\xb9\x0e\xc0C\xe0\xc8]\xb7OF\x13\xf6h\\\x99\xc2J\x91\x86}\xda\x99\xc01\\k'\xcarB\x8c\xc2'\xde0\x81m\xa4u|\x8b\x9c\xc1\x86t\x1b\xf1\x85d\x10\xcac\xee\xc0\x19\x1e\x86\xae*\x8d\xe5\x0f\xe7Z\x8d\x95\x93\xb0(\xdfX>\xc0\xb9c\x12%\xfb\xec\x8d\xbc\xcbM\x98\xd4\x84\xbd`WD\xa0\x8a\x9c\x93W\xadP\x14\xe6\x1b\xad\xaf\xbf\x05\x98d,5\x8b%\xbc_(\x1d\\s\x8dB\xa2\x82\xcd[,\xa5\x16`\"\x05\x86\xd1\x18\xffM!\x01'\x04s\x0d\x8c\"=\xc4\x91\x1b\x17Za\x01\xc7ej\xd1\x8eTf\x95\x17\xc4,*\x91\xa0\xd8\xa7L\x18\xd8\xfc\xee\xbdWt\xa5\xa6>\x84\xf0\x04\xff-\xf8\xbf)\xfek\xb8o\xad\"M0k\x1b(\x1f\x06\x0b\x17U\x89\x8c]\xc7<{\xee\xcfo\xd2rr\xf0\xc3+\x97\xc0\xf7r\xb6\x11\xf1\x98\xef\xb9\xd5&H85\xda&\x8d4\x1d\xaaaN \x83g\x10\x9e@6\x1a\x99\x992\xe0\x9d\xe1\xf42\x0f\xc7\x1fQ\xf0\xc1C_-8\x1c\xce`\x07\x16\x9dr\x1d\xd1R\xfd\xa1\x88\xd2\x9dy>\xfb\x1cF|\x81\x8az\xdf\x16tA\xacMr \xbb\xc3\xc2\xd7\xb2\x163\xd89\xe5\xa3\xf1\xf9*X\x80\xb3}mR\x18A\x01\xcf!\xac1I\x08;P\xe08\xf9\xaa=Gf.\xdb\xd9\xe9\x9arM<'<\x88\xed\x9a\xf1\x80kx\x06\xc5 \xac\xbb\x16\x1d\x94\x85\x87\x11\xac=\x16\xa4\x97.\xfe\xbaw\xa5\x81\x9b\xc0\x98\xfc\xbb\xf5\x07\xe3\xeft\xd62\xcbq\x80\x0f1\xa9\xb7+3\xd6\xb3j@vt7k3\xe0[\xf5h\x07\xe8\x061o1J!\xdc\xdf\x9b\xf8\x18\xa1\x04\x97\x90\xb6\x81\xe2\xcd\x05-\xc3\x9b\xa3\x90\xe79\xc4x\x0chqLq\x01\xfea\xee!\xeb\x85\x9d\x19\xfc+L)/7\xb68r\x0bu\xe2\x92|\xe9P=\xe5\xf0\x1c2x\x02\xd3zh\xf8\xabK\xfeP\xb1\xb3W\xb1h\x87\xa3Q\xd5\x05>(\x9aX\x87yA\xde\xa4\xa5K\x82\xa2\xba*\xca\xdc\xa5|B\xe5\xc3\xd4\xf3ar\xd0!7g\xd4\x9a$(\xac\xccu\xcb\x19\xbdi\x98\x8a&\x1c\x00\xf4Dc\x83\x0e\xcde\xcf\xa1\xe1\x8d\xfd\xd5\xfd\x19s\nK\xc7\xc2C\x95\\\xdb\xa0\xd3\xd6\xd3\xd5\xd0\x9e\xec\x06\x03u\x9b\xb2\x11\xd2\xecB 8Q\xb3\xf2L\"\xc6\xb3\xed3\xc1Q\x19D<\xe4\xc4\x8b\xd2M{$\xfam\xc0\xf7\xc0dy\x9bL\xfav\xd8\xa4\x95\xb5\x19\xd4\xf0\x97a\x0d\xff\xd5\xfda\xf3A\x9f\x0fm{\x90VC\x0e\xec\xc0\x83\x93\xf2]\x93\xaeZ}\xb0\xb6\xb7a\xcbu \xc5NS\x0f9\x02~ \x19+!\xed_\xc5\xf9M\xcaO\xc3!\xcb\x84\x93R\xb0\xb1\x7f\xe0C\xc6\xb6=\xf6\xea?m\x9a<+H~\xf8\xda\x03\xff\xaa\x8b\x9fUY\x08\xf4\xe9TXL\xf4\xd5\xa7<\xc8\x0fw%\x91<\xa2[\x85\\E\x85\xfd\x0c\x1b\xd7\x8b\xaeq\xa5RL\xa1\x9af\x1c \xb2\xc5\x10\xf3\x18\x83\x1ab\x14\xddv\x81\xcd\x8c\x85\xf8\xf0E~\x93r\x16\x1bLS\xc5\x83N$\xc6L\x89\xe2A#V\xcaJ\xef\x1e\xc1\x19\xec\xc11\xfb5\xdd\x853\xd8\xe5\xbf&G\x138\x83)\x1c\xdbD/\x08\x91a\x04 \xad\x87[|\x83\xe1Z\x8c\xf8\xc5#\x8f\x8f\x81\x05\xf6kz\xe1kS\xc9p\xf4jY%\xcdh\xb2_\xcfh2\x85{p\xc5\x9c\xe4)Vt\x8a\xd3\xf1\xdeS\xfe\xdd3\xd8\xdf\x9f\x1e\x1dP\x92\x88\x92\xb3\xfbOw\xf7v\xbdo:\xff\xbd\xc7\xcf?\xac\x7f\xedn\xb0\x1ajYhY\xa1Cm\x85\xa4%\xab\xd4%\x0b\xe9\x92\x1d\xec\xef\xef\xee\x03\x06\xf4x\x06\x93\xc9do2\x99J\xcbd\x9c\xa2\x99$\xae\x8d\xb1(_\x84\x9f\xd3\xb6w}\xbc\xc9\x18tl!\xf7\xe7.(>\xa0?\x0f|\x11\xb5x\xc1\xc4\xa8c\xd8\x86\xc9x\xba\x0b\xf7l\x1397\xb3\x7f\xb0;\x1d\xc3={\xb5\xcd\x0c\xc2\xf9w\x1e\x05T\xa3SH\xda\x10\xdf\x06\xa5\xfb)\x12A\x8c\xd8\x15 \x14\xe3\x14\xbc\xbc\xafI>C8,\xee1\xc2\x13\x85\x1b\xf5\x16 \xe9.\x1c\xc7\x0e\x18s\xb32\x10\x04\xf4\x16\x06\xd3\xdcXz\xc0`8\xba\xc9}\xa6\x9a{\xdfCD\xa5\xedEv[\xe8S\xfeE\x82\xda\xb7\xbd\xf0\x81\x04\xe7Iv[\x97t\xef\xc3\xa8l\"\xab`,\xdc.\xbbBT\xdd\xb9#S\xa0\x837\xef\xce?\xbcz\xf9\xe9\xf2\xed\x8b\xff\xef\xf2\x87\xbf|zuN\xcf\xd3\xd8&\x8b;U\x93)\x9b\xcd\x82\xcc\xe5=\xb1\x13\xed\xf9\x8cn\xa4\x88o\x92\xc9\x92\x9e=G<\xb5\x02M\xb6J\xb2\xe3\xb4\xba\x96Y\x00\xd8\x81\xa8\xb3l@8H\xf1\xf0Q\xed\xb5\xe5G\xe21\xc3\x8e\x07\x1f\xf6\xa6\x9cVZd\x99\xebY\xc5\xa1%e\xc8\x98\xa5\xe9\xf6\xb6p\xeb\xad\xcb\xdc\x89\x0f\x13OR*\xb6\x8fjg\x0c4h\xe6\xb0e\x90\x9d\xa8\xe7\xca\xf5\xe8\xc9\xfa\xfc6\xfc\xc2-\xe4P\xc5L\xcf\xd4:\xcb\x92\xf3\xf8o\x14x\x1cN\x8e\xa6\xb4\xe82\xac\xae{M\xb6\xc1\xb6\xb1\x85\xe2\x0c\xa3\x1fo&\xd8\x1e\xe0u$\xb5\x1f5\xe9\x05\x0d\x16\x98\x1dBjW\x1a\x8b2F\xe3\xb9\xa237\xd6\xf1-\xf6\x93<\x9c\xcc\xf66\xff+@{U\xc2\xf3\xb8\xa9e\x17LbF_\x99\xc3\x9c\x16\xbe\xd6\x8a)\xe0)wh7S\xa3\x9d _\x1e\x98\x1a\x01\xc1\xcef\xab\xbf\x81\xed\xa7\xf8\x02Y>D4ca\xd6$\x1bB2\xf3\xbe3\x93\x05`\xde\xd4\x0f\x161\x0b\xea\x86\xc6\x86j\xa1Tb\x00\xf0}\xa7\x05\x17\xe1\xe7\xb4\x08\x17\x83\xe3\xafX2\xb5\xe9\xcdQl\xf1-\x9a\x94\"\xac\x0cjk\xcbmb\xa1\xdd\xdf\xc3V\x19\\\x8a&\x0c\xadG\xd9j\x1d\xe6\xa4\xcf!\x1bd\xf3\xca\xdar\x03\xdb\xd7\xf4QF \xd9\x8b:\xba\xb7P\xac\xb0/\x8c\xb6&\xcc\xf0Eu\\\xee2s\x90\x15{\x8c\x0d'\xf5\xaf\x98\xc5\xa1\xcfdN\x92\x99\xd2\"k\x98Q\x86\xde\xe2t\x8b\xc3\x98\xc5\x17xD\xc9,\xbe\xe8B\"\xa9\xe0\x1cY\xff\xad\x0c$\xf2c\x97\xddZ\x89>\xccw\"\x94zh\x8e\x04g0Q\xe2\xe1Bs^\x84\xf9k\xef\x89\x11l%W\xfe\x94-\xe5\x8fy\xc2}\x06\x06\xdf\xca\x84\xe3\xbf\xc1\x1ee\x80\x8d\xc3?\xa8\x01\x88) )\x0c1\xb3\x18L'\xf8u\xe6\xd5\xc1\xd0!\xb3\xa6\xbc\xfa\xceI\xe2\xa24\x99N\xf2\xe0{\x90-\x04P\xb0YQZ\x0c\x1f\x04\x01m\xa2\xb1\x11>\x98[S\x02$\x18W\x0b!\x0ca\x10\xa4C\xaa\x8b!\x89f\xe9\x85\x95\xdd\x12r)\x05=P\xbch\x86;f>IO\x1d\xa5\x8d\xc2N\x9cW\xdc\x18\xc5\xce\x06\xca \xbc\xfa\x9d\xf6\x8f>\x153\xe6FM8g|E\xf4\xd6\x9e\xb3\x08\xcd\xb9mEg+dg\x8fS\x98\xfb\xa0Pz\x12\xfa\xdc\x1a\xab\xef\x8a\xdbp=9\xe8\xf3\x0c\x17\x0c\x0e\xc6\x8c\xea\xd2\x13\x95F=\x91l\xae\xc9GRP\x12\xbb1\x1d^UI\x19\xaf\x13BWpr\xb0s\x15\x97F\xb4\xa8(\x1a\xc6'h\xbe[\x9e\xb0\xe37\xf5\xe0\x86\xbb&\x11Jm\x8dZ\xd9KA\"\xd1e\x17M\x10\x8b\xa8.\xcb\xee\xf4\x9b.\xcb\xdeW.\xcb\xee\xf4Q\xcb\xb2\xd7Z\x96]\xcfo\x8a\xe82\xb1\x7fLZ\xb8\x0dV\xeb`\xef\x9b\xae\xd6\xe1W\xae\xd6\xc1\xde\xa3V\xeb\xb0\xb5ZO\xcd\xabu\xa0\x15O\xd9?\xfbZ\xf1.\xfbg\xef\xf1kk\x8a\x1f\xd7\xb5\xbah\x9e\xdc\xb5\xc2\x8a\xa6\xa3\x8e\xaa\xc5~\xb6\x02\x08\x9c\xc1\x0b>\x9b1\xa5\xcc\x07\x84\x87\x92\xc7\x93wh\xf2\xe9F+\xf8\x07\x8d`\x98\xcd\x99\xb0\xfa\x1a#\xdb\xf4\\\x9eO\xe3Q\xe2\x0ck\x17\xfd\xa6R\xbd\x91\xda\xd4N*D3<\x8a7\xcda\xb69Y\xc1\x10j\x15\x06Q\xac\xe2\xe1\x9d\xbf\xd8\xa4\xf3.:W<\xbc\xdd_7i\xb7\x93:\x86a\x14\xb2xx\xff\x9f7\xe9\xbf\xd7v\x18\x9a\x86_m\xd2p\x075\x0e\x83(r\x18H\x95\xc3&\x9494\xb3y;l6\xbd\xc4:4v\xd1F\xc6\xfag\x1e\xf9Rx+\x1e\x83\xcd\xbd@~J\xe6\x8e8\x02\xc7\x19j6\x0dF\x9a\xec\x81\x8b\xe4\xd9dmA\xa5T\xa0N\xfeZ\x85Iw`\x170J\x1bzd\x0b\x122\x146\x9a\x9d\x88\x87\xe3\x80\xfb{\x0e,kY\x88\xd9/\\\x9bE\x9c\x16k-xr\x17f\xb2)F\x98\xffRK\xca\xdf9p\x81\x9f\x9es\xb3\xe9\x9a\xae\xa8\xddy\x10Fr\x7f\xc9`\x15\x96\xd1\xd2}\x12\xfc6}xr-2l\x80#\"\xe3\xd6\x8d\xf1\x10\x80,\xc8L\x10\x04\xe0x\x9e\x0f\xce3No\xd4\xe1r\x9e;]\xebb\x91'\xf5\x1a\xb5\x7f\xfb\xad\xd6y<\x05\xb3\xea\x9e\xdb\x0c!\xa2v\x84/\xc8\xb1^/\xaf\xed\xb6\xb4\x17\xcc\xd6,naT\"|\xdd\x11\x03\x8bv\xef\xefQ\x80\x83/b\x1d5\x9b)>\xee\x8f\x9e\xd3\"@\xfbh\xdb|sx\xce\xc7C\xe8_\x9dnBM\xfd^\x17\x02\xad1{-\xa4\x03|H\xeb\xbf\xf2\xfa\xaf\xb8\xfe\xab\xb9|\x83\xc4{\x19\xba\x0e\xec\xd0\xd3\x83!\xcd`\x87\x1e\xa7P\x96\xe8e>T\x1e7\xdf\xc0\x00\xc8B/\x18s\x15\xacb\x99\xc24\xbb\xe3\x13H\x98!\xedh\x94\xd8%\x80\xd1,a\x12\xc0\xc5,\xe9\x94\x00f\x18\xbc,\xe1:sZ\xdb\x0e\x83\x1f!\x01\xcc\xe0\x19\x1a!\xa3\x04\xb0\x82g\x90\xd9%\x802\x94\xc2(\xc2C\"\xbbI}q\xe3\\\\J\x91%\xd7.Ao[\xf7o\xd4\xd9\x9d\x1aR\x03\x03\xaavu\"\x99\xfc\x7fmG\x93\xce\x8e\xd0C\xdf\x0c\xc7l@L\x8b\xb9Y\x93\xb8L|$\xddt\x9f\xf3_\xadVj\x0f\x14\x1d@\x99\x83\xa6\xe4,J\xf9F\xad\x9b\x8f0\xc2\xe0\xb8x\x1d\xa7\x18\x97\xc03\x04d\xe1\xae\x92,r\x81p\x8c\x10\x84\x87\x0f,P\xc7\xcc\xe7\x91t.<\x16\xc9\x11\x92,\xbd\xa6\xfc\xaa\x88Fk\x0f\xa8q\xcf\x00\x85\x18D\xea\xc1\x19\x05\xcc\xac\xd8\x08\x899\x07Ay3\xd9\x9f\x89\xd5\x1db\x94_\xdb\x18K\xa8pGO\xea\n]\xacU,98\xc9\xc1{\x9e\xd7NM\"\xe2 \xe3\xef\xf0\xafA`_r\xeeeg1\xab\xca\"\x9e\xd7A\xa9\xec\xf1I\xf2:\xae\x805^\x86\x02^U'Q\xabJo\x08\xff\xc5/\xdbJ\x0b\x94c\xde\xf2^\xd6k\x18\xdb\xc5\xfb\xbc\xdc\xa0\xcf>\x8e\x8b7y\xb5A\x93_\xab\x8a\x80\xa6\xdb\xdb\x0d\xba\xed\xe5\xb1x\x9b_6h\xf3\x1fN\xd9q>h\xf0\xbd\xdc\x14Z\xf3o\xc4I\xd9,u\x01\x98A\x13s>\xd5\xbd\xa6\x98\xc2\xb1\xdf\xf9T\x97v\xfd\xdf\xf3\xf7\xef\xfa8\n\xbe\"\xe6\x1bJ\xdb9\x06\x11\x0c\xc4\xccr\xcc\xc32<\x06\xdd\x93\x0e\xe9\xa3&oFp\x19\xe6\xb9\x88\x0d\xe6\xf7\xc3R-\xf8*\x05,\xef\xe1\x14\xf6\xc6G\x07\xb6\x90q\xbfv\xe1l!A3I\x92\x1ec\x16\xac\x98\x03\xa3\xce\x97\xd9\x8c\x992@\xa2\xc1)js\xed\x0c\xe40\x87\xde\xcf\xff\xa8S\xfc\x16\x93{3drv\x1bDw\xcb&\xf5t\xb78r\x95\xd8\xa7\xbc\xc1\xb2\xa6+\xa9,\x82\xe3\xb0\xfbG\x98\xab\x1c.F\xe61}\xd3k\xb7\x9ce\x1dS\x8f\x07M\xfdm\xd7\xd4\x15St\x8d\xf1\x90\x877f\xc3\xcbk=^\xc659\xb1m\xd7\xf2Yv\x01#\x98\xee\x1f\xc0\xf7\x90\xcf2S\x90X\xd8t.\x9f\xba\xe6\"4\x12\x13\xd4H\xb0\xd8\x18\xf6H6\x0e#\x01E\x04\xef*NK\xbb}\xc7\x08\xc9 k\xdc\xb7O\xf9]\x9c^c`\x13Lj\x00W\xe4.K\xe7\x82\xf6ak6\xd0\x0b\xf7\xa5*\x82@\xa7\xc8\xc7K!\xbes\xd8\x18\x8ca\x80\xb8\xb0D\xc4\x0f\xb1i\xb2 \xba\xa8\xf1\xe3\x9fY\x03\x03\xe9\x91\xfe\xf4\xd8t\xb6\xe615\x88$t\xb0\xc7\xc1\x9c\x93/ \x8b\x17\x06\xae\xe8\x87\x1ef\x88\xd4>\xfd\x84\xdbS\xef\xe3\x86\x9b\xf5\x92\xca\xed\xd5\xadud\xaf\x17\x1f\xa6\xaa\xe1\x0ewG\x8b/\x00\xf5\x10\xdb\x18\x94\xe7\xd938\x84\xef)\xfd{\x061\x1c\xc3\x04v \xf6<\xb4\xd16\xbc\x184\xe1\x8f\x1bMxoz\xb4wt\xf0tz\xf4\x8df\xbdg\x9f5iOk\x17\xa7\xc5\x16c\xd0\xe4\xde\x0d\xbe\x1f_s\xb0lG\xb5\x03\x9e<\xfa|\xfe\xa4\xcc\xc88\x9dZ\xaer\x7f\xcf\x16`\xec\xb3\xa5\xf6!\xe6<\xae\xdc\xc6t\x97\xbd\xa3+\xb07h\x0c?>z\x0c\x87\x961\xecO\xd9;:\x86Cm\x0c\xf2\xafB\xa7\xeb\x86\xd8\xef\x08\xaf\xb8aJ\xeaS\xf8\xaf\xff*}=\x08&\xe1\xb9O\xfe\xeb\xbf\x88\xcf0\x05\x0bC9\xa2X\xbb\xbe!\xa5\x888RR\xc4^\x17\xe5^\x13\x92\x8c\xe5\xea\x92\xbe!\xe2\x1bR\x7fC\xa4o\xca\xba\x04\x93\x1d\x1b\x03\x985:\xcf\xda\xea\x1a\xd7\xc2\x1a s#\xf9IM\x81\xc1\x8e\x9eeE3\x86\x11\xec\xec\x101\xef\x13<\xda\xe3\x9e\xe9\xd2\x0f\xbe~\xc2\x87C\x00\x02o\x90\xd4s\x9c\xf8\x9a\x82\x83o\xdc\x90\x1e'\x07\xedc5\xa8\xd3\xa9\xa5Sn\xe9\x81\x8b2\xb9@\x9c?l\x1c\xed\xcd\xfe\xbaq \xb5\xa1\x0cf\xc88v\xa7\x8f\\\x8f=}\x1c\xae}A\xe4\xa2)\x16\xb18\x7f\x93\x83\xa7O\x9fN'\x94\x8b\xa8\xdf\xef\x0e\x1c\xf6#\x97\xaf5\xec\xd6\x18.D\xe2Li\x06\x93\x83\xf6\x14\x94Y\xed^t\x8a\xf0\xe9\xb0\xff\xd7A4x~\xca?\x9fL\x0f=.\n\xdf\xe1\xb4\xe3:\xbbu)\x95\x00\xdf\x03\x06\xf3\xec\x05\x07\x7f\x0f\xf0G\x94\x85\x91`[~q\x82\xe4e\x1b\nf\x1a\x14\xcc\xbb\x17)3,Rf]\xa4l\xc0\"}#\x90\x89\xbe\xd7\xf5\x89Gu\xde\xf7\x80\x11!v\xa4{0\x11\xa9\\\x07@\xd7\x0d\x80\xab\x15\x9a\xb5\xd7\xf1F\xf8UX\x81\x8bu\xedw\xa7O\x0f\xe8$S8c\x8c\xd0x\xf2\xf4`\x0c\xf7\x90\xc2q?\x05\xb2\x01\x8c~\xf4t\xd8$\xee\x15\x10\xfe\xfbM\xe7\xdb\x81\xfa\xcd \xbd\n'i\xd9to\xd0p\x87\xad\xfe\xf0\xe1b\xcf\xedA\x0f\x00\xee}\xc3}\x9dd\xa1\x01\xba?n\xb816\xd9(\x1a\xb6\xc6\x82\xeb\x1b4\x8co\xb5j\xadaL\x86\x0e\xe3\xc7\xac\xbaJ\xc8#\x97\xe3\xb0w\x1cc\xc1\x80\x0e\x1b\xc7#\xd7\xa3\x7f\x1c\x93!\xe3@\xe6\xd9\xca\xcdX\x848<\x9d\xa7\x82\xe0\x98\x15\x0b\xaam_\xea\x06\x04:2I=\x96t\xcc\xe6\x88\x12\xdbc\xfce\x1dN\x1fx!H\x13r\xba\x14\x94D\xdaB\x93\xac*#\"N\xa1\x84'\x1039\x90\x15\xbc\xd1\xca\x9dP\xac^I#\x99\xf0w\\\xc9\x14\xabXW\xd3`\xa4$\xad\xa6\x10\x9f\xd5+\xba\xb3\x13c\x808N*\x18\x964\x16K\x9a}\xb3%m\x11\x15\xdd\x16,\x86E\xd5\xd7\x92\x02\x8b\xfd}\x1f\xf5(\xd6|?\xb8;M\x06\\\xb7\xf4\x04\xb4\x96O\x197\xf9\x1f4\x11\x13\x05\xf2\xd5s\x99\xfaLr\xdc5\x9b3\xc3\xf5\xf0\x9b=\x9b\xb0=C\x11)\xa5\xa9>(\x1dl1\x1b\xfb\x91\x166\xd2>\xc9\xc1\x94\xf2\xef8I>\x1b}\x92|\xee\x86IN6\x9a\xa4\x89Z\xf9\xeaI\xee\xf9\x92H|\xd0L\x19\xcd\"f;\xdd\x93\xa6;m\xca'\x07\x96\xbd6\x1cg\xba2\x1f\xcd\xdb\xdfI\x16I+\xf3;l\xff\xe6+cY\x95\x89eU\xa6\xe63\xb3\xdb\xbd2\x93\xc1+\xb3!\x8a\x15\xd2cyY\xb6\xac\x06G\x02\xd4\xb7\xd0\x03\x86\x8e6\xcbN[\xb8%f\xa8d\xc7\xe0\xe6m\xb6\x07C\\lF,=Qz\x1f\x89\xc1+\x19\xdd\x08\x917wJb\x7f\nsL\x86\xdb\xe9\x84.\xf0\xcb\x10C\x14\xf9\x1a\xdew)\x96\xaa\xe0\xf9s\x18S<\x1a~\x13|\xb5!\x05\xf0?e\xa3;\xa8\x88\xaf\xdal\xb1\x17\x12\x81\x915\x04\xc6\xc6;>\xfa\xfb\xec\xf8\xefB\xa0L\xa6O}\xd8\x99L\x0f7\xa7Q\x14\x1d\x12]Z\xe6\x930\xf9\x1a\xfa\xe5w$_v\xa7O\x0f\xe8\\Q\x860\x0c\xb4\xff\x8e4\xcc\xefH\xc2\x04_K{0`\xca\xdd{;\x80\xc4QH\xa2\xaf\"h~Gz\xc6\xbeD\xea\xf5U\x8c$\xc4-\x1e\xb0\x8a\xff@\xc4\x8fE\xfe\xd4\xbd\x8a?i{\xd6\xe7U\xd1\xf4\xb4\xe9~i=M\x06\xf5d\x93\"uw\xf5\xe3c&e\x13\x14m\xd4U\xef\xac\xa2l}\xb7\x19\xdd\xd2\xa4\x9b\x1c\xa3Cd\xed\"\xd8\xd8\xd5\x97\x9a\xa7\x97\x94\xa5\xa41E\x90+\xd0\x0fI\xdd\"Wq\xe45 \x88\xce\x0b\xcc\xfb\xb2/\xbdS\xdc\x8a\x84\xd2\x0cP\x1eVO\x13\xa4\xcb\xf0\xa6\x0c\xf3kR\x9e\x97a^\xf6gC\xad\xcdx\x80\x19kj\xc30\xf7PdU\x1e\x91\x0dz\xc8\xbb\xc6\xcbZ{\x95\xce\xfb\xdb\xcaU\xe7\x8bz\xf5\xd5\x1d\x95\xec\xaf\x08\xc6^\xda\x916Jy92Z\xe5\"A\xcb\xf4[\xb99n=\x12\xc8\x8d\x1b*\x06]\xe6\xcaA\xec\xb1#$M\x0c,]\xc2\xe4\x04b\x9e\xd5`g\x07\xcd\xc2b\x18\x01\x03\x92\x14\xd6\xd1_\xa6\xb8/\xb5\x93\x11eA&d\x17X\x18\xaf\xcd\xb2\xfe\xb105\x9aY\xda\x06\xfd\x1b\xf3\xb9\x14\xa4\xac\xf3\xb8\x94\x8a\xa9N\xca\xcc\x9e2\xcf\x9c\x0bS\xe8\xfd\xba\x00\xc1\"\xc6\xf4\xf6\x1b\x00\x02\x83\xd3\xd5\xc6\x99\xadEz\x02\x0c\xa9\xc1\xd1\xa6vC\x8c\xe9s%\xb8\xd0\xfe\xc4\xe7Y7\xfa2#\x81\xec\xe2$\x07,\xb7Y\x1e\xd1\x87n\xe9t\xff\xa0F\xd4\x96\xf8h\xf6|\xabz\xb2\x19C><\x9b?{\x9d\xf1{h2o\xcb\xb2c\xbfj.\xe0\xdc\xe6Ul\xf3\xfch\xf5\xc7s\x97\x98\xf2\x9d\xf3\xc5b\xa9\x92\xacF\xbf\x1cF\xca\xe0\xe7\x19\xc3\x0dj\x91\xd5*\xfa\xfd`O`\x0c\xe7\xd1\xc4\xcf\xa3\xed\x9b\xa1Tf\x1bl\xe3\xcc\xab%\xba>SF{\xcc\x93\xc8\x8d}h\"{P,gL\x0bo\x87'\x06\x8b}\x04\"L\x93a\x01\"viB\x85\xb6|r\xacB\x96Q\xf8g7\x15)\xeds)\x01\xa6\xd7\x91\xbc\x99\xb2\xdc\"N\x95\xf9\x10\xd6\x13\xe0\xb6z\xe8\xa3\xacLB\xc0\xc5j\x96\xc1\xbfB\xb8\x81\xcd^\xd9\x8a\x91\xa3\x8e\x81N\xf6op\nOf\xff9\xfa\xe5\xc9x\xe7\xe8\xc5\xce\xff\x0bw\xfe\xb6sy\xf1\xe4\xda\xe6z\xf3\xba;\x84+\xa0r\xf6\x0c\x9c1:\xfd\xabiB\x8f\xb5\x02ul\x96\x0e\x7f\xb6*\x00o\xcc\x01\xda\x08\xf0\xa88\x13x\xd2\x9b\xe3\xb2q\x90\x89Ex~S^\x87\xee\x14*1\x0bl\xd3J\xec\xe0\xc1s\x8c\xe6\xbd/P\xf4\xfe\xd3\xdd\xbd\xbd.\x80\x1b\xf3\xfcp\xf6\x1aP_\xd2\xe7\xb0\x7f\xb0;9\xea\xabL\x1f\x96\x88b\x97\x8eggB\x07\xc3\x93ILw\x8f|\x98\x1cM|\x98\x1c\x1eu\x80u\xf1DYZ\xc6ie\xce\xa5$\x1e{\xf6 \xe0c\xaf@\xa4~\xb2J\xf5\xe4\xe7\x1fi\xf4\x98\x10\xaa\xb3Jo/\xdd\xd9\x95\xf0\x98\x1c\xecN\xad)\x04\xc53lU\xfc\xdfy\xc8)\xf7\xd18\x80\x11\xa5\xebvx\n\x82g\xcf`\xc2\x0c]v\xf8l\x8c-\x88\xb4\x89\x9c\xef\x190\x1f;&o\xeeo\xca\x12U\xf4\xdd3\xd6\xe1\x84eg\xe9K\x7f\xc0\x07\x93v\xcf\x83\xef\xdft\xbc7\xb0\xf7\xe9f\xbd\xc3\xf3\xe7\x98\xcb\x00\x03lcB\x83\x94\xfe\x9a\x1e\x0e\x1a\x16\xee\xd3\xb0q\xedn>.L\xba0\x9d\xee\xb1\x10\x1ep\x00\xdbt\x848\xba\x0d\xc6\xda\x03\x1aq\x1e(\x14!\x92\xb4&V\xd2\xdar\xf6\x99p\x86\x19X(i+\x93\xab\xfbu\xd6\x7fy\x8cw\xa6\xe3t'\x13>\xb5\x07\xbfS\xb8&h\xa8\xd4}\xea\x05,\xe8|\xd3q\x19\x90/\xeb,/\x8b:\x85\xf1\xe0\xd6\xf6\x0e5\x8a:f\xc5GZ1\xa5\xd3\x9cY\x86a\xf0y\xd0\xfb\x0b\xc7<\x02\xfb\x89\x15'\xa7\xc0\xefU\xc6\x8c\xae6\xfdb{\x1b\x90\x0d8=\x95\xee\xdd\xc3f\x93\xda\xdd\xf5\\\x16\xb1\xdf\x07'\xcaIX*~m_\xb1\\\xbbOw\x8d\xeb\xb5\xfbt\xcf\xb0`\xb4|_+\xafx\xf9\x81V\x1e\xf2\xf2\xa7\x9e\xc4\x0d\xd4\x07\xbbh/\xe6\x0d\x8f\x0e\xbac\xd0}\xa6\x1c?\x03\x0f\x9f)\xa7sV\xcfk\xad\n\x0d\xa2\x84\x84\xb9\x8b\x87\x9cX\xb3q\xddt\xa7\xd4FQ\x10)\xdd|6\xbe\xf0!\x9fMt\xbb\xff?\xb4\xffRd\xc0t\x0ctWT\x89\xd0\x9c$\x04c\xfc\xc4j\xf95\xa1\x102S\x0b\x97!\xdd\xd7J-,\xb0f\xe8+{_l\xb6\xf7O\xf7,gH\xf9\\_5c\xf8\xfb\x13HwvN\xda\xf0\x17\x05\xa8n9K/p\x01\xa5\xbc\xd1\x1aU\xc9K\xa5,\x9f\xe6+\"\x8ff\xf0\x90\x1b5\x92\x88y\xdad\xc9!\xf4/\xf2\xe8\x8b\xf9\xf4\xe81k\xd8,\xdf\xe5\xe5<,\xc3\xcbK\xe3j\xe4.\xf1\xe0\x0c\xd2\x99E\xbeW\x17\x1f\x83\xb3\x0c\x8b\xa5s\x01\xc7\x90\x06\xabp\xfd\xd8\xf9\xec\x8d-\xe0s\xa2_{\x06\x0e\xf0v\x8b\xa2\x8d`f\xc6D#9\xcb\xe8G!\xe5c\xc7<\xb1\x80\xb0\xc9d\xf7\xb1\x83CP#NH\xec6\xd2N\x8aY\xf3\xaf\x18\xeb\xd3\xb1a\xa8\x9a\xa8a\xd8Hmbbz\xbaY\x0c\x01q\xea\xdbb\x1bT\x12a\x14N\xe3\xb1s\xc6\xd8\"\xaa\x04\xe8\xd8\xe8\xbd\x81\x9d\x98\x1e\xb8\x9d1=l\x1b^\x17\xa7*XB\xf3\xa8\x94:lh\xc6\xd6\xf5\xd8\"\xc1\x0d\xc9\x0b\x8a'j\x0dS]TG\x86sn\xc6\x81\xe3u\xd7\x98\xd0\x1a\xb5]\x8b\xb9\xc6!\xads\xa6,{\x1bO\xa4\xe4K\xf9)\x8e>\xab\xb1\x98;bK\x82\xd8#Q_\x96B\x97\xb6\x08\x0f\x94\x8e\xba\n\xa3\xcf\xc6\x18\x0f\xa2%[\x98\xfb\x9b&\xab$\xb4\xc3J\x9b\xbf\x11\xb1\xb7\xc2.b\x1c\xa3&\x8d{\x02\xd5\xf6$\x80\x14\x16@\x81XI\xb7+X,\xb6\xd8\x93\xdf\xb1\xddb\xbd5}\xe2\x0f\xc0k\x86D+\xe7\xfa\xcd\xac\x83x\x1e\xfa\x86\xda\x93\xdb\xf1\x9b\x0e\xb5\x95{U\x7fzG\xdb\x93\x89\xf1[\x8f\xd6\xb7ir\xc4\xd35\xe0\xde\xd8Z \xcb\xc1\xe9}b\x1ci\x88\x16|\x8a\x1c6\x137\xc1\x83lV\x8dF\x17\xf2-\x99U\x1dq3\xe1[\xac\n\x8bX\xcc\xa5\xc4}\x0bb|\xdd\xc7\xe2? U\xdc\x801 N\xcb,\xda\xee\xde\xa6,\xda\x81\x89*\xc8y\x96B\x13y\x9f\xf5\x91\x8eqJ\x81 \x99q\xae3m\x14\x13\x0f\x86\xe6*\x9by\x86\xe0L\xeb\xf7R3\xe2\xaf\x98e{\xa3\x98\x9c\xa7\x1ek\xfe\xe4 \xb8\xf4\x02L\xa1\xa5\xa2\x84\x1c\x8e\xc1\xcd\xdc\x9cN\xcb\x9734V\x9e\x0f\x99\x1b\xb3H\xb0\xd5\xd0\xccr\x88\x1aL\x8a\xaa!\x01\x88\xd3\x8cc\x04\xde\x80gD\xe3\xa6E\xa1#\x1c\x9a~M\x19b/\xee2\xc5H6\x0fO\x1c\xab\xb8\x85\x01\xf8\xc0%5.1ghKYf\xe8\x98\x9fh\x9e\x13\x1a\x7fJ\x7f\x8f\x15?\xe4f\xee\x03\xb2\xae\xfd^so\xb6\xc6\xb4)\x03\xf3\xb7\xfd\xce\x83\xcb\xa5|\xa3\x1b\x93\xbafZO\xbeH\xa9\xbbwp\xe4\xb9\xce\"\xcb_\x85\x91\x08\xa5\xf5\xa8f%\x1e\xe0H\x17?p\x1e\xe0H\xe7\x0d2\xce\x1b\xe8\x10\x8d\x891\xf6\x9e\x1eJ\x8b\xe2n\xc6\xd0\xf9\x94\xfa\xe2 \xbd\x8d+\xdb\xca\xf4\xf1\x0c\xa6\x94~5\xd8)\x94p\xc6r\x15s\xf3\x8d\xd2g\xc9N\xab$\xa1'\xbcPP\xd7\xf4\xc2W\xa4#\xa8N\x0cy\xe2!\x16g\x15#\xd5\xa6\xa8P\x16v.N\xe4\xf0\x80\x91R\x19\xa1e\xa1Zv\x8b\x01\xd9##]\xcc\x93A\x1a\x12\xa2\xaa\x99 \xd3v\x05\x92V+\xc2_g\xed\xd7\xb7y\\\xb2\x97\xa1\xf2\xee\xc1\x87\x02\x19\xc7\xd8-\xe8\xb0\xe8\xcc\xa2\xe6\x90z\xc1\xf5\x90\xa8\xd3t\xc3\xf8V\xf9\xb00\xb3A\x96]\x89\x1a\xd3\x18\xf3\xe6D\xca\xe6\xecJ\x9bC\xc1\x99\x14\xba\xe8\x182\xce\xe1\xf3\xf7\x14\xae\xa5\xea\xfb\x149\x1c\xb9S\x1e\xc1\x87nh\xd4\x8cAz\xa3\x1d\x06q\x10\x8a\xe6 \x84\x86\x83P\xb4\x0e\x02\x8fa\xde\xde\xf4kR\x1a\xb7\xbc\xa0\xe5\x86\x9dV\x8fB\xd8}\x14Z\x89y\"\xbe\xdb\x11\x1d\x0ff\xc3\xf9\x16 I\x92\xe1\x1c\xdaD\xa9\xc1\x8f\xaf^\xbf\xf8\xf9\xa7O\x9c\xb0\xcc]\x0d\x0e\xb3 \xe7\xc70K\xdd\xfd]O\xcb\xdeO\xbe\xac\x938\x8aK\xfe\xfa)\xdd\x16w\x7f\xf7\x90\xff{\xe4I$\xcf \x18hgP\x05\x8d\x0c\xa9;m p./I\xf16\x9bWZ>\xd6AKG\xdb\x93\x05\\\x8a\xf5C\xea\xd6\x1abwz\xc0AI\xea\xee\x1eq\xaa;u\x0f<\xd7\x11&\x1b\x9f\xc2k\x01Z\x9c\x97\xe7\xe7\x1f\xab\x84\xfc\x14\x17\xa5\xff\xf2\xfc\xfc\xbc\xbcK\xc8\x8f$J\xc2<\xa4#\xa1e\x7f\xa2p\x85UHb\x92\x96\x1fIT\xe2\xcf\x1f\xdf\xbf\x95\xfff\x8d\x8b_\x9f\xb2\xcf$e?\xc22\xfc\x94\x87i\xb1 \xf9\x9b\x92\xac\xb0\xf0u\xcc;\xfd\xf7Oo\x7fz\x91$/\xb3$!8y,\xd1~\xbe\xce\xf2\xd5\xab\x84\xd0[\x8c\xbf\xcf }+J\xde\x92y\x1cbco\xe3\x15\xa1\xe8\x96\xa5\xe9}\x17\xae\xc8\xfc]6'o\xc3\xb5O\xff\xc5:\x1f\xc2\x98\xce\xe1\xaf\x15)\xd8\xd0?$\xd5u\x9c\xf2\x7f\xd8\x97\xe7\x7f\xfa#K&\x87\x15\xce\xff\xf4\xc7w\x88\xa5\xc5\xaf\x0fa\xb9<'\xd7\xf5\xcf,NK\xf1CZ\x85\xf3?\xfd\x91\xcd;\xcb\xd9\xa4\xcf\xd1D\x95\xa1sV@\x97\xfb|I\x08\xfb\xfc\x13eg\xf20\xfa\xfc\x92/x]\xc0~eU\x84#r\x82b\x9d\xc4\xa5\xeb\xf8\x02Z\x8cO0 ~X\xcb\x80\x8b\xd1\xc8\x04g\x11\x1e\xce\x8a\x8b\xf6\xbd\xa7\xe0%\x9fE\x867h0I\xe9\xf2E#\xf4V\xa14\xe6<\xdeJf\xd5\x05\x13\xd2%(\xf9\xa0@\"\x9bE\x94\xab\xc8\x02\\\xd7\x9e\x13\xaf3<\x14\x8e\xfe\xf6P[\x1am*\x96\x13\x02D\x0eH=\x1e\x86\xf5\xd0\x87\x9dI\x1f)e\xbb\xec\xdd\x94`m\"\xd7\x10\x80\x12\xf1\xf72L\xbf+\x81\x0e\x06V\xa4\\fs\xc8R0\xe6\xeaii+7\x1b$\x07-\x83Y\xca\xa9\x0d\xeav\xd2Y\xa8\xc7\xef\x13o\xa6\xbe\x1e\xa1\x87\x19\x16ZR\xa4s\xe3+\xb1\xe3B\xc8\x8b\x80Mlc\xd3\x9f\xa1\xe5\x8eF\x91\xbe\xff\xf4\xde1h\x1aeY\xcc\x83\xfa\xba\xd0^\xb7`\x0d\x1dl\xc9\xa9(w2=\xf4\\'^\xe4\xe1\x8a\xe8\x1d\x89'G\xe8b\x13\xab\"\x92$AA\xc1l0\x8f\x8bu\x12\xdeQ\xac\x97f)q|\x9c\xfb\xa1\x17\x84\xeb5I\xe7/\x97q2g\x99\xca\x83\"\xa7\x80\xd2\xf95\xbc \x8b(\x8f\xd7\xe5\xb1\xe33\xabV\x12DYZ\x92\xb4\xfcs\x9c\xce\xb3\xdb`\x9eEH\\zA\xb6&\xa9\x8bn\x03,j\xa7\xf3\x8c}\xfa\\T ^\x9f2\xc5\xf1\xb3_\x9e\xf0W\x98\x81)\x88\x92\x8cE\x8c/\xf08\xbd>\x81|g\xe7\xc4\x03\xae\x9a\x94t\x8d\xb3l\x96_\xd8\xad\x02\nWS\x89\x9a\xaf5O8\xcf\x94\xd7\x94\xa4\xed\xe7\xa7\x8c\xf0\x89\xabf\x04m\xdb\x0c\x93\xa2\x12\xb7\xf4\xfc:\xdce\xe8\x83\xfa\x9aK$)\xc68e\x0eX\xb4j\xe1\xaaY\x95\x08\xd2\xe0\xc7\x10\xbb\xa9/'\xe8\xed\x07\x87\x02}\xa0\xf7hDb-=~\xae8\x96\xf6\x01?\x9b\xa4\xabx\x17\xbe\xe3\x0e\xce\x1eW\x84\xbb%\xfa\xf5\xb0\x10\xa8\xa9\xb71\xcf.\x11t\xbb\x9e\xeb|&w\x85~\xf2\xd9\xa5U,\xcc7\x1av\x8e\xe1\xa3\xee\xc1\xc5?\x98\xec\xe7\xf1\xa34 #g\xce\xe5e\x94\xe5d\xe7\xd7\xe2\xb2X\x869\x99_^:\xa2O\xf3;\x8a\xe8\x1f;\xa1XL(f\x13\xfa\xed\xa1o:6\xc4\xe9DYZ\x94y\x15\x95Y\xee/\xc3\xe2\xfdm\xfa!\xcf\xd6$/\xef\xfc\xb8\xf8 \xce\xef\xfb\x85\xbf\xe6\xc5o\x8aW5\xbf\xe4\x97\xd9OY\x14&\x84a\x03_\xa0\x05\x9fc\x1e\x99j\xdbl\x95'{^\xb00\xcaTtQKf&\xf6\xfbV\xd6\xcc\x98\xa3\xcau+\xc6#\x9er\xdb\xf9\xb2\xb9\xc6\x18\xd0\x98\x99\xd4\xa0\xb8\xa5\x0d\xcdUfs\xcb\x10PA\xc8,\x94\x17\xbd\xfb\xb7!W9\x9d\x1cy\xee\x96\xec\xeeBq\xcb\xbe\xc7s\xde\xfb\xe0\xb0?\x1c\xbf\xe3\xb0\xa1\xfd\xc9%]\x8a:S>\xf7O\xbaD\x83\xaff\xc8\xbe\x1d\xc5I\xe8\x8d\xb7g\xb6\xaf\xe1\xed\x9a\xa1\xaebHvf\x17\x041@\xda\xee`\x9e\xa5*\xffI\x9f\x07\x06\xbc(\xe0\xc6\xe5m\xe66\x92\x8d\xeb\xad\x9d\x19&\xc2\xfb\x99X\xf7v\xc3[\xb071\xcb\x15[\x9cm\xebF\xd4r\xd7\x02\x89\xb7\xbc[]\xa4K\x08\xd5\xf1\xbb^\xefm2\xed:A\xfd[\xd5%d\xaf\xf3\x11\xff\x9c\xce\xc9\"N\xc9\xdc\xa1H\x84\xc9\x8f\xf8\xabwU\x928Fg1\xa4E;\x119\x0e8\xbf3\x94Jc)g\xc4\xe0\x98\x02QX\xa7\xe6\xd5\xf4\\\xe8\xd1\xca(\n\xbc\x12\xb1\xe7q\xac\x9d\xa1\xb0\x08\xb5\x00\x0e\xab\x80\xc3u+v\xca<\xcfFV\x03KBCP\xe3 m\xdd1T=\x80\xc1D\x02\x8c-\xa8?\x0f\xd3y\xb6r7\xdeM!\x92d\x86\x8a\xaeC \xc2(,]}\x17\xe9xK\x1f\x1c\xef\x92\xd2\x8e\xa3Q*\x92\x04q\xf8\xb1{\xf0x\xb4\xbbk\xbe\n\xfb^M\x8f\xb6/A\xee\xc6\x1c\\\xc7\x9c\xf4\xe3\xf2\x93\xc7\xae\x00\xdd_\xad)fA\xf4\x9bn\x8a7x^\x93\xddn\xaa\xe7\xa8\x9fS\xfd\xef\xa0z\xf6\x9fZ\xf0\xf1\xbe.\xf1\xcb\xcc \xaao\x12\xff\xbb\xf1\xf1\xc1\xc4\xb4\x00\xc1b\xc8>Rn\xc2^ $h\xdb\xe6\x92\x10\xa3\xad\xf3l\x15\x17\x843&\xa5+O\xc4\xea\xc5\xa4y\xb4\"\xd3$\xfdN\x0d\xd2\x9e\x1f\xc29|\xe0}Id\xa5=\xf3!\xea.\xd2\xdalX~\x1e\x04:\xceI\x91%7\x84\x03\xd0\xba\xf0W\x96\x858\xd7\xddZ\x1e\xbe\x82\xff\x98\xec\x99\xa5\x05\x93\xf1#O/\xb3?m\xb2JJk\xc5n\xc6\xffq\xd0L~\x04\x0e\xcc3R\xa4\xdf\x95\x98\xf7g]BN\xae\xc9\x97-\x8b\x8e\x94\x83\xd3\xaf\xba\xd0\xf4\x82b\x8e\xe4\xfe\xabiD\xeep\nO\x82'\x9a|\xc7\x88j\x9d'\xc1\x13\x07f\xe5\x85K\xb4\xbd\x128\xb6\xb5p0\x04o\x93Y~\x81J%\x1f\xb6\xac}@\x0f.7-\xef\xa6z\n\xf3\xe5'A\xa3\xfb@ e\x1b.Tn\xeaN\x0f\x0ft/\xdc\xb8~u\xa8\xbfB\xd2\xceD?\xc4\x01W\xc3 \x85\xd1\xf6\x08\xc8\xeb\xf7g=\xc0DPE\\\xe7\xa8\xed\xd8\xf1\xc0\xaf\xad\x84\x8e2\xd02\x90\xe0\x04\xcb*\xad\xbcFPS\x17I\xe2\x94\xb3f\x8e\xc7\x96\xa1\x9a\x0c\x83*+\x90\xe5\xc3\x91\xb6\x8c!\x9b\xf6\x0ckuWi9I\x0f\xd2\x11\x10\x93\xd9p\xd7N!s\xeb\x1d\xf3:\xb7\xccBPW2A\x9d)@\xb1s\x0f\xff\x1e\xfb\xb7\xc1\xd8\x87\\G\x82h5u\x0f6d\xb6L\x82\x9d\xd4\x9d\x1a\xc9\x9bC\xb3\x01\xc7dl\xf6CAi\xc6c\xc1l\xcc\x1d\x94\x98\xc0G\xfc8Eb\xf4\xb7\x0748j*\xfc\xa6[3:\x97l\xf7\xd0\xbd\x1bC`0\x0f\x84\x98\x87\x9f\x0e)\xf3[v\xb0\xb9U\xb0p\xb5\x08\x06\xbd\xd4Q{;\xb8\x00\xf6\x9a\x94\x92\x84\x89\x0d{C\xbf\x91\xdd\x03}K\x84\xcf\x90\x99\x12\xdd=\xd4\xad\xde\xb9\xcf\xd0\xa1\xceQp\x9f\xa1\xc3\xe9?}\x86\xfeA}\x86(\xaf\x94\xbaO=\x1f\x9c\xb7\xe1\xfa[9\xa1\x1d\xea\xde%\xdc\xebdj\xf6:\xd9\xdb\xd5\x0f ;P\xfa\xf1\x0by\xedG\xfb\x81\x18\xe1o\xc9\x11\x93|\xb628\x06'k\xe4\x0dR\xd5\x8a9\xba\xc4n\x89\xe7\xa1\xa4\xe7\x81\x82\x0c\xc6\xb6\x86\xfd\xc0U_3z\xae\x8f\xc6\xe3\xa7\x93\xa3\xa3\xe9\xfe\xde\xd3\xbd\xf1\xd1\xd1\xa4-nx\xf2\x9f\xee\xd9\xf1\xf8~6\xd99\xba\xf8e\xfe\xbd\xf7/O\xfa\xd6\xc0\xa2\x86\xc1\x10>|:FZxk\xcb%\xd2U\x13\xfa\x13\xc2\xb2\x9f\xc8F\xae13v\xe3hg\xeb\x94\xf9\xee\xe7AI\x8a\x12u\xba\x88\xb1\x84\x0b?\xcb\xffy\xcaC\x97\x96\xf0\xac\xd7\xefd\xc8J\xf5\xad\x82\xed$Xb\xeft\x0c\xf7T\nu:\x08m6\x17\xc2\xec\x84\xd5r\x1e\xa2\xb7\xe1\xc9/\xc1\xfd/3\xf7\xecx\xf6\x9f\xb3_..\xbe\xbfwg\xcew\x17\x9e{v\xec\x9em\xfd2\xf1f\xff\xf9\xcb/\x17\xf7\xbf\xfc\x12x\xdf\x9f\xfd2\xf1~\xb9x\xd2\xbe9O\xfe\xf3\x97\xdb\xef\x1fu@\xb8\x7f_\xa3o\xde\xd2\xc2\xdf\x8bm\xe8>A\x8a9k\xaa\x90bu\xc1U\x96%$L\x9b\x12\xc5Ik\x0bY1z\xbe*q\x9c0\xbaX&\xff\x12_\x10\xb6Cq*d\x88\x1b\xa9\xf9j|\xd4\x96\xe42\xf15\xb9!).\x9d\xf2\x13I\x03!\xe1^\x85_~\x8a\x8b\x92\xa4$o**\x855\xb3/\x8d\xac=\x84|C\xd0\xd5\xd9Xlo\xcc\x04\xda\x9a-8\xedi8\x1bD4k[\x00\xda9L}H\x83Wt-_\xad\xe2\xb2D\xdb{,k\x10\\\xb3\xf2\\\x0d\xa1\xbe\xd5\x16\xbd\xa9\xc3\xa9\xe3\xb7\xea\xfb\x89\xf6}A\xf4\x1av\xa8a3\xd1\x06\x91\xc9\x18\xdd\xc3\x99.\xd7$\x9cH%c\xeduV0K\x8cN\xabm\xf3\xb9\xf2\xd50N\x0f\xea\x8c\xc8*\xee\x8e\xc8 )\x11,\x96\xcd1\x8f&(\x1fsW\xbb\x06\xbf=Pr\x81\xd0\x999M\xd4AwK\xae\x16\xe0k\xee4\xdf*gF.\xedr\xe1\x97i\xa2\xd2x|\x0e\xd9\x14\x97b^\x91!9[\xb0\xb0\x1fb\xf1\x0dY7\xe9\xec\x17\\f\xc7\x1d\xf4~N\xa3\xb0\xba^\x96>Ti\xb1&Q\xbc\x88\xc9\xbc\x9e\x1b\x0e-\x00\xf7;\x9e}\xd7\xf1L\x927\xd6\xdf\x82\xd9t|)\x99 \xefB\xa9\xf6\xd0Z\xe3\xac\xc9\"\xcaW`V^\xd8\xc1.\x83\xcb\xa9\xe75\x0e~\x9a\xed\xb9i\xc9\xba\xfc\xf8\xd2&G\xbfE\x9ah \x7f\xd2\xe5\xca'5\xea\xab\xfb\xb4y\x17\x16\x17r\x82\xde\xb8\xaa}\x92\xb7,\"\xdcD4\xdb\xf6\x91\xed\x84\x92=\xa0J\x813)\xb9\xadG\xbf\xcd2\xe8!\xdct\x1d\xe9\x8d\x83\x0c|\xee\x92@\x0c\x89\x92\xfc\xcd/$\x87}\xfd\xfa2\xae@\xbb\xd2\"\xcaaS\xc4\xc2\x06\x11\x91\x9aOn\xe0\x14fZ\x91\x0f\xe4\xc2X\x91\xf8\xa6\xcet\xb0J\xbb\xbb\x0d\xf3\x94\xcc\x81\xa5\x0b8\xa5\xc8\xbb\x85ZP\xdbjD\x9b\xc7\x06D\x84\xddT\"\xf6\xb0\xde\x1d\xb7)x\x0e\x15vi\x19\x0dsa\x88\xb2\xb4\xc8\x12\xc2\x80\xbf\xeb\xb8i6'\x1e\xd0*\x18>s\x9d\x15E|\x95\x10P\xc8\x84\x15Ye\xf9\x1d$$\xfc\x0csR\x92\xa8$\xf3\x00\xfeu\x0eI=\xeap>\xa7e?\x17\x04\x08\xfbJ\xc7\xf6\xae\x07e\x06q\x1a\xe5\x84\x02\x9b$^\xc5e\xe0\xb4\xb6\xb4\x89\x93j\xa4\xbf\xc4\xf8\xcb<\x8c\x90\x08U\n\\\x91\x0e\xc9v\x932\x14i\x98\xaf\x96^\xb3?\xf9\xf67\xbaY\x82\xc2\xa7(Hy!\xd1\x95&dS25\xd2*\xbb!b\x0et\x98\xb1\xc7\xe3\xbb#\xc2\xa3\x9bNT\xf0#\xa0Y+\x82\x92\xfcKXi57\x10o\x00\xf6\xc9\x96#\xeeYkud}kyS\xfb\x7fQB\xe9w\x81`\xd8\x8c\x0e\xbf\xf4\xcb\xdb\x11w5^\xb0\xfbl$$j\x0c\x901a\x1a\xddQ\xa1s\xcc\xddT\x02k\x94\xea\x97V\xf5\x14\x83\xbdr\xd9T\x0b\x16)\x90T[Q\x15\x98\xaa/\x19<\xd5\xe3-\xab\xb8\xd0p\xa4jlX\x9d@\xb8\xb3C!\x8e!&\x0d\xf0\xc5Hg\xe1E3K\xfa\xab\x99\x17\x9d\xa5R\xc0'\xda\xeeS\xf5\xdf\xc4\xfe\xab\xf6\"I\x86\xf1Vf]{\xebz\xf4\\\x85\xad\x8e97!\xecYf\x1c\xddm\xf3Lg\xf4Q \xa0\xe3\xdc\xed\xed\xce{\xd1\x1e\x92\xb97\xebA'\xe8D\xaf\xccX\xdf\x1en8 \xb6\xb0\xbd\xd0nGLs\xdb'z'\xda\xf9\xc1\xe5\xd0`+\x18y\x9a\xdc\xc2\xd3X0\x83\x1e\xee\xbe Oi\xa1\x8bO\xea\xbbqbotV\xdf\x99\x1dh\xf1\x1d|%\xba\xb6\xd1v\xa8\x93Ag\xd9D\x96\xb6i$\x16'I\xbf\xc6g-\xe2\xcf@\xf9 \x1a\x1f\x8eav\xd17\xd6\x97Y\x95v\x0b\x04tv\xdf\xa6\x1e!\xed\x8dm\x9f\xb3\xc68\x83/\x83!u&z\xee\xd4\x15\x84\x05j?\xbc\xd1\xb8\x11\xfb\x0c;\xc2\x85\xa9_\xf5\x0b 5q.\xcf\xc5!{\xbeO\x0e\x9fz^p^\xe6$\\q\xd7\xdd\xe0# \xe7\xe1\x15Z(\xe0\xef?s\xbfg\xf6\xc1\xe4)\xfa\x86\xfcX\xad\x13\xf2\x85\xa9C1MLP;\xf9\xb1zGS,\xfd\x10\x16\xc5\xa7e\x9eU\xd7K\xa6\xfb\xd8?\x1c\xa4\x83\xed\x0d\xd1d\x0ett#\x92\x99\xb9\x18\x07MyW\x93\x7f\x06\x95?h\xc7\xc4$$\x89\x0b\x8c\xb4\x02\xc2o\x83!\xa1\xb4\xcc\xef\xd4\xa2E\x9c\xc6\xc5\xb2\xcf\xc7\x87>[\x9dK\xa0?\xb5\x96\x8fujG\xed\xa52*{=\x0e\x93r\xa3NQ~\x84\xd6%\x0fD8({\xa3\x80\xfa\xdd5I\xe7qz\x1d]\xed\xecP6\x8f't\x81\x1cW\xd0\xfam\x9b\xf2\x10\x0f \xa2,\xffL\xe6\xdcc\xb5x\x9d\xa3]\xac\xa9XlRIy\\\xd3g\xa7\x86\x00\xa8\xf4y@\xb5\xb7\xc1V\xa8\xe3r\xcb\xb7i\xd5fCB\xee\xe4N\x82\xab<\xbb-\x18\xf12sn\xc6\xc1d\xec\xf8@\xff8\n\x9c\x8b:\xfaW\x13\x0f\x8cA\xc9\xb1\x0f\xfb\x1e\x8f!\xcd\xbci\xb2:\xda\x8f\xda\xdb\xaa\xbe\xa6\xe7e\x88Z\xd9\xeb\xf6pP\xc8\xe2\xee\xeby\x04\xa3 N\x97$\x8f9L\xd8\xd5\xd36\x08\xb1\xa3\xf9\x90\xcc\xc9:'QX\x92c\xbc\xdeO\x0d\x0b\xd8V\x85'\x1c\xfa\xe8z%\xfa\xac\x99\xc6i\xec\xf1\x906\xed\x1aK4\x81h\xf2\xa6(\xde[\x1e\xfcfH\x0c0\xf7\xe1\x86\xf7i\x07\x0cw\xf8\xb1\xe5\xe5\xb5\x114\x03\x97\xaf\x85H\xb23X\xc8N\x1f\xaaW\xda\xf7D\xdcb\"\x0b~\x0dt:\x82\x12\xa6\xe5x\x9b\xcd\xd1\\l\xab\x94\n|\x16V\xd7m\xd7\xd3K(W\xb6\xc5\xfc\xf1\xe8\xf9x_\xbf1PZ\xb5~5X\xc6\xd7\xcb?\x87%\xc9\xdf\x86\xf9\xe7\xf6\x16\xd0'\xc2\x8a\xa2\xdd\x7f\xef\xff`a\x18\xdd\x19L\x0e\xe0\x18&\x07\xbb\x87{\x96UP\x86\x02\\k\xcbh\xd3\x18\xce \x86c\xbe\x16Q\xf3\"\xa2\xe4H\x04\xc7\xb0\xf0\xcd\x8d\xc8\x19\x15[\xef\xbd\x06\x94\x87\xc9\xcb0I\x98\xc0g\xe2\x0b4@\xe6?\xe6a\x9c\xca\x85\x0c\xe2i%\xeaw\x0c3\xa8esR\x94yv\xc7\x0b\xcd;\x92\xe0;\x9e\xe7fN\xa2l\xce\xbd\xablxJ\xa9C?N\xea\xdePB&R\xc1\x00kP-\xbb\xbf\x07\xa7*\x17\x87B\x98$spX@w\\\x9b*\x03\xb3R\x9d\xe2.\x8d\xb8\xb8\x04\x7f_\xe1U\xfe\x90g\x11)\n\xed\xe3,E_\xd1N:O<[\xdd\x94\x92\xfc\xdc41Moe\xd8h>\x9b\xe2\xc9\x99 \xfa.\x8d\xba\xeb1\xf7f\x1cxteG\x87\x94\\\xec\x9f\x95xJ}mE\x07\x0d\x85Q3\x07\xe2\xee\x91\x84\xa4\xbe\xf4\xb7\xe2\x86\xa5?\x0f\x88\x8a\x89g =\xba#G\x8aggGB\xee>\x1a\xe0\xbb\x0dNrc\x1fr\xcf\x97\xb0\x94\xfb\x8as\xe4~k\x1f\x98\xd0\x94 E\x85<\xb5\xe4\\=\xd3_\xd1\xc60f\xbfO\xc5\x1b\xcf\xf3!\x91T\xc5\x83\xf6\xf4R\x05\x8aL\x8en\xdae\"\x1f{\n>\xa4\xbbQ\x89\x9f\x1c\x9e\xa3\xe6@\xc2\x8b\xe8\xbc$V\x8aBN\"0!K*\xc1\xde\xb8\xac\xf7\xe6\x9d\xdc\xcad\xd0l\xae\xa4\xd9\x98&\x91B_\xf4\x03\xf1\x88\xb8\xc6\x1c\x07moc\xf4QA\x0ca\xda\x9b6q\xc4!\xf2\x9c\x969\x06(\xfc\xe0\x96\"\x86\xa5\xc26\xe6n\x03\xbb\x07\xcd\xf3\xd6:vb\xa4?\x0c\xd9\xb4\x04\xcd@t\xd0a\x16\x04\xd5\xdb\x87\xf2y\xa6\x8a\xa0\x98\xcf\xb6~5\xf1o\x84Lv\x82#\x069\x92ln\x89\x02\x02\\\xeao\xe2z\xcd\x98(k$\x05\xe6\nu|\xad\x90\x81\xcd\x82\xad\x1b\xda!\xc7\xa8\xae`&O\x98^\x0e\x95d\x05\x0b\xea\xc6\xa3^\xe0j\xf8\x10\xc2\xe8\xd4$L\xa3\x0f\xc69e\x88\x00\xcd\x7f\xfd\xfa\xf6\xb1\x1bSg4\xf3\xc1q(i\xc1\x10\x80z^F#\xac\xda\x81R\x18IB\xc9\x15\x8bP \xe3c\xcdd)\x8fg\x17\"0<\xc1\xce\xad\x0d\xcf\xb4\xcfz\x17\x05!d\xc4\x9d\xf2\x98\x9a\x8f\x0f\xa2e\x95Z\x18-\xf1\xa0\xb1P \xd29v\xd7M@\xc4\xeb\xe9\x16\xf0\xd0s_\xef\xd0\x04!\x93\xc2\xcd\xc11D\xf5\xa6E>e\xc0\x12\xed8\x98\x17\x8c\xde\xf9\x1a`z\x1b)\xa8\xe8S\xbb\x88\x0b@d?\x0d}2\x1e\x90@\x86\xf2\xado\x81$\xc3\xe0\xf0\x97n\xff(\xc1Abtx%\xab\xb10ld\x85\xfa\xb8\xd0d\xa2\xe1-\xd9O\xbe\x8c\x83\xc6un\x85\x9b%G\xa7\x0d\x0bc\x95Pj\xc0\x1b7A'\xc6SviU\x1aN\"\xda\xeb7\x8e\x05\xf2\xd3\xe7a\x182xe\x9d\x94\x80\xf1_\xbatM\xec\x10\x0d\xe46\xd59\xdd\xdf\x03Q$\x07\x14,Z\x88\x17N\xad T\xd2\x80\x99&{\x18+\\\xd59\xe7\xaa\x90;\x1a\xb8\xa4]\xa8W \xf6\x86\xe6fw\xc8\xd2j\xd3\xa4/\xd9\x94C\xeb\"5\x92EJ\xf2R0p\xad:\x8a\xd4A\xab;e\xe55\x16*\x85\x00I\xbb\x03,\x98\xc8\xec\xe2\x04\xca\x13\x8fN\xa3*\x96,4 \x12\x82t\xd9\xac;\xadyy\xb7\x81d\xaf\x18\xdf\xee\x96J\x1f\xee\xe6\xc4\xfc\xd7\x84\x9b\x93{-{\xac;l:\x8e\xc9\xe5J~0\xcc\xe9\"\xa8%\xae\x9b\x05|\x97U{\xf5\xd2\xbbv\xde\x10\x18\xc7\xe7hL7\x1b+\xc4E#\xf9\xe5\x96JZ\xc5f{)wC\xc2y\xe0\xf8\xe0\xfc\xf8\xea\xc3x<\xde\xb5\xa4F\x83\xf6\x05\xaf\x8b\xed.\xbb\xf8\xda\xb5\xb1\x08\xdc\x13n{\x9b\xff\x15,\xc3\xe2\x0d\xe7\xb7\xc0\xe6\xd3\xf8\x9a\x97IQ\xc7\xda__\xd0\x8bK\xef\xc6\xb0\xda\xbe\xe5,\xac|\xc3\xc8:\xdc\xef\xfa\xe5I\xb5#\xcc\\66-\x1b~\x93\xde\xf6\x15\xf0T\xcd\xdb-\xc9\x8a\xcc\x8f^\xf7a\xcb\x07\x84B\xf3^\xf1]\xedG*5^\xb6\x94\xf2>\xac$\x10\xb1\x8e\xd7\xa4\x0f:0 \x80\x8ah\x9a\x1c\x8a/\xc34\xcdJ\xa0\x0d\xf9\x18\xa7>\xe7\xeaM\x9d\x15\xd1zn\x8b$\xed\x1a:$\xebY\xe4Y\x03cn&\xbb*\xc6\x1e\x19\xdfa\x80\xe4X\xa6\xab\xea\x84\xfb>\xac\x9b\\\xce9nh./\xe8\xd2\x8e\xd2B$\x0d\xd6J*h\x91\xd9|\xf0\x91Zc>\x01\xdd\xfb\x13\x80\xe7\x10\xb4\\A6\x81T\n\x0eM\xa90\xca\x17\xb0\xf0\xd3\x02\x00Rj\x1b\xd1%sr\xd5$\xd3j\xeb[R\xf0}\xd1\xfa\x9d\xe7C\xcc\xe5\xeeg\xc3p\xb7\xa0\x06\xa4#\xc3\xb6>\\\x94$\x07\x92\xcem\xc1*L\xd4\x8d\x84\xa2\xf1\xb0\x98V \xefb\xca\xc3^\xeb\x9c\xb7\x9dK\x07I=c\nZ\"\x9e\xca\xa2H\x00\x89\xb8iH\xe53\xe6\xa9\xa8\x06\xe8\x7f\x1b\xde\xe1Ua\x0b\x81\xb5\x11\xf4\x14PfP\xa0\xb1\x80cM\xd6\xdf\x04\x05a= 9\xa4\xaa\xa3\\C\x9f\"\xd7i\x9a\xa5;\xac\xd9'\x1c\xd3 \x9f\x83\xc1\xbf\xb9A\xae\xb6\xee\x95\xba\xee9+\x89\x05\x1f\x1a[\xf7 f2S\xe6\xe6\xe7\xc6*\x01V\x19\xee~-\x0d\xb2\xed\x0f\xdaq\xf5*\xf1MM\xf7!\xf0R\xd7\xe8\x19\xd5A`\x8e\xdd\xdf\xdc)~}\xb1\xc7\x1e\xe9\xb4\x91<\x92\x9f\x87\xda\x08\xc3\xdeP\x8e\x06_U}A)\x11\x19K\x17\x9e\x99\x05T\x16\x8co\xbd\x03!J9Z|g\xde\x99Y\xaa\x16[\x8d\xac\x86\x91\xb4\xed\x02$ \xd73 \xaaf\xd0\xfc\x1d3\xdd\xd7d_c\xcb\xba\xa0\x05Q-\x18\xc4\xeb\xc1\x04\x0c}\xe7&b#k\xb3\xb5\x1d\xfa\n\x0b\x17\xdc}\xd8\xf0\xc6\x1d\x83A\xf3.?B\xacp\x0cq\x8f\xaa\x8c\"\x1cc\x1c~\xf9\x11\x92\x07c\xee\x05\xf9\xa17\x9d9;\xdb\x8f&\x0b\xd2\x1f Q\x8ey\x19\x8e\x8dL\xbe\xb1\xaeU\xc83:\x85\x89\xf9\xf02I\x8f,) \x1b\xf8\xd1 \x9e\x8b.\x88\x152\xce\x0f/\xb0/\x85\x82\x836 CO\xd5 \xe2I#\xdc\xd9i\x1c\x8d\xba\xda\xae\xd2!\xad+<\x9b\xda\x8bA\xa7!4a\x0c\xc8\xb3\x1f;;\xbe\xa4\x15\xa5\xe4\xab\xa4/\x93\xa4\x1e\xf8\xcb\xa8=k\x0bL\x98\xf6\x8c\x93\xc4\x9dD`A\xca\x1f[\x1a\xf3nZ)\xb6\xa5A\x14\xa4V\x19\x94\xd9O\xd9-\xc9_\x86\x05\xf3\xb0\xd8rg\xce\x92|\xa1\xdc\x11\xd7\xbb\xd3\x7fw\xf0\x8f\xb0\x88\xe2\x98\xfeq\x15\xa7a~\x87\x7f\x85\x059\xd8\xc3ZQ1\xe5\xff\xeeL\xf9g\x93\x83\x84\x88\x16\xc4\xdfyx+\x19\x19\xb9,\xd3\xa2\xa7\x8d\x03\xad\x8cp0\xb59\xe2\x90\xbbm\x8d[\xc1,\xae\x9bt5\x12{@ \xccM\x98 )\x10\xf7\xf6\xb6\x1c\x98\x8e\xb1\xb8\xb5\x8eZ\xc8\xbcr\x19\xde\xe4\x8d \x8bP\x1e3\x10\x8774\x17\xb2Y\xcan)@g\xc8J\x01\"\xe2\xc6>h\\\x0b7\xfdZX]\xb7y&\xd3\xb2)\xd3\x04fiDj\xa1[\x07\xe9F\x1a\x93\xa3\xb1/\x99f\xb5E\xd4 !\x95\xbc\xc5\xa8\x0c\xbc\x82\xb5\xe9\x92\xf1\xdamt\xad\xe4\xdd2\xa8\xb6k\x0bt\x1d\xa0\xf0\x01\xb4\xe7\xd6\xbe\xe6\x852\x1e+\x9fk\xe9\xde\xed\xec\x9f\x9e\xe1~1\x89z\xd3\x1a%\xf7\x8d\xf8[\xbb\xa6U*\xd7\xa9\x7fi\xb5\x9a:\xbd\xfc.\x93\x94\xa4s\xd7\xf3\x81\xb4\"8\xfd\xa1\x19\xa9\x9a\x9b\x11\xb3\xe8\x1f\x8d=\x8a\x0e\xdf\xacVd\x1e\x87%\xd9$\xb5~\x7f\x0e6\xfb\xbe\xf0\x03\xd2\x1b=\xe2\x9b\x0c#u\xf7\x0e\xf7<\xd7\x833\xee\xbf\x8c\xc9\x13\xd1\xb0\xf5p\xff+\xa6z\xd3\x84o>2\x87R\x99\x9a\xd3\xc2\xed\xea\xc1\xc3*\x83k5G\xec\xedPC\xfc\x1275\xb5h\xee\xca\x07\x850\x8a\x0c\xaf\n\xf5M\xf4Uy\x02n\xea\x90\x0d\x0b\x1f4k\xf4\xb8\x95=\xa5\xb2\xf8V\xaa\xdf\xa1B \xc5\x00\xb6\xcc\x1b\xd8k\xfc\\\x17Z\x84\x05\x86#h)\x0bo\xb1\x10Y\n\x16\xf0\xfc\x14\xb3\x14D\xee\x82\xa7\xfc^\xc6\x8d\x93\xd3\x0eDn\xe1.<\xef\x04X\xe4-\x18\x8d\x0c\xea(\xb4\xf3\x91\xa5\xac<\xccP\xc2Q\xe3\x8c\\\xf8\x90\xbb\x89\x94\x02E\xc3\x8f\xbc\xb47\xd3\xfc\xa0\x93\xa6xH\xb4\xb0\x91\x10Tj\x03\x18F\xd4\x9aDo\x96\x14\x8fHa\n\xc2\xc4\xeeA\n\x12]\xa5\xbcx`R\x82\xeeA5\x07\x8b\xd6\xad\xf3\x8b\xb0P\xcc\x9f\xc8\x97\xf2]6'\xaec\xcb\x99\x92ah\x01\xdbx\xb4\xb0\xb8]\x029\x0b\xfb\xcd\x1d\x858\x82g\xcau\x16#\x9bX\xf1w\xb7u\xa1\x90.\xb1!v0\xfdp\xaai\xe5\xc4c\x96\xa8\xa0\xcb\x9aJNY\xe4\xb8i\xe3\xc3\x08u\xfa?V\x1f1x\xe9Zf\x86\x176\x0e\xe6a\x19b\x98\xc2S\x18\x8d2\xf8W\x982s\x07l-(\x96\xf1\xa2t1\x04\x05\x17\xbf\x08\xafkN\xe1\x95\x06m\xd5\x83\x17dW\x05\xc9o\xd0R\xca\xbcx\xd12\xcc\xc3\xa8$\xf9\x8fa\x19\xb6\x82\xfe\xb3V,\x16\xeb\xbd\xf4\x02}X\x9a\x17\x0cai&X\x99\x94{F|(/P\xec\xc0\x15\x94\xa8\xbde\x04\xb0iq\x86\x88\xc5\x1e|3\x1c\xb6^\xe3v\xe4$$p\xec\xaa\xb0&\xc1\xb4\xe4\xf6f\xf6B\xe9\xe8D\xdcO\xdaM\x9d.\xa8C\x8cj\x1c\xca\xdb\xaa\xc4\x84|\xef\xd9\x8e7~\xb1\xb1\xdbze\xbf\x95\xc6\xa6\xffL\xae\xfe#.;:\xb0Th\x1f%\x1bH1\xdf\xa8\xde\xe0\xbb\x80\x8c_\xee\xea\xa2\n\x00\x16\xb8\xd5\xd8lA\xcaO\xf1\x8ad\x15J;\x0c\xdb!U\x182\x80\xa6\xba\xcb\x0e\xfb\xd8<\x98\x96T\xeeA\xba\xb2\x83\xe8\xcaoBeY3h\x9a\xb2f\xaay1\xa7l\\\xfb\xd3}\xfe\xef\xc1\xc6y1;F'\xd2S\x1e\x9a\x92\x8d\xa1\x86\x8f\xa7'P\xc3\x0e\xe7\xdda\x87\xd5X\xe9\x96|WV\xc8 \x84t\xed\x0e\x92,\xc2\xc3~\xdcJaF\x9fe\\\x94Y~g~\x99\xadI\xaa\xb2\x7f\x86J\x98\xf2\xab\xb7\xd6\xeb8\xd1+\xd9\xe6\x0b\xe2\x86K\xf1\x82\x9b3\x7f\x8b\xc9\xcal\x89\xfa\xccV\x1cta\xd8wmxr\xc3\x1dFm\xda\xb8\xb4C\xc5\x9b\xd7\xf1\xde\x0c\x82P\xab=Im\x08\x13\xf3\xb0Ih\x15$\x82B\xbb3\x87\xae\x95\xe3\x83\xf3C\x92]\xd1\x7f_g\xf9\x8a\"=\xe7\xc2;\x01\x16\x16\x13\x13\xf3U\x08\xc0]\xcf\x0b\xe6YJ\x90\xc4E\x8dE\x07\x92\x13z\x97\x98\xe5\x10\xb4\x93\x1f!\xc4)_3\xc693;QV2\x0b/\x86`5,\x91\x0d>\xec\x0b\x93;\x8c\xee\xe0P`\xe0\xd0k\xcb\x0b]=\xc9@\xaf;\xbb$\x1eW\xcf\\\x9f\xb8@h\xd6\xe7>\xdc\xf8p\xe7\xc3\xb5\xde|\x81y\x0f}\x98\x1b\xdc\x92W>\\\xfap\xe5\xc3m/\xbb\x08\x82\x83Z\x83\x08\xb6\xfa\xa2\xc6\x05/\x8c\xf1 \xe8#\xc2\x15v2\x00\x18\xef\x8fe\xec1\x87\xe0k*1C\x8a\x8ej\xd0\xacf/\xfbi\xf8\x86R8i\xad\xdd\xea\xfc\xca\xe2\xfce,\xdddD\xc3Gb\x00vmt\xf9\x05\xbd\xa5G\xe0\xc0\x1bq\xa0\xdb\x95\xce\xe1\xb4^[\n&n\xdaU^Y\xd0\xf1\x0bT\xca5\x82\xedV\x85\xf7p\n/f fNz1s\xfe\xed\xdf\xea\x8b\x85E\xe8\xfc\xf1bvcH\x1a\xfd+\x05\x86L\xdfxc\xe00?S\"\x00\xce\xe0\x1c\xce\xe0\xd6uHZ\xe61)\x10\xa2\xfd\n\xf6\xd4uoX2\xb7<\xbc\xc3\xa9\"\xa2z\x11\xf0\xafio\xef\xdb\x14\xd1\x1bD\xc5W\xf4\x96\xb8o\x18\x19\x8e\"\x0e\xcf\xf3P\xea\xae\x8b\ni\xf5+\xa6>G\xcfj\xf7\xca\x87/>%\x11(\xba\xa5<\x85\x89\xed\xb8\xe2\xabT\xd1\xea\x89\x0fK\xcf\xf3\xe1\x9c\xb6\xf0\x1e\xe1\x8c\xd8 \xec1H\xc3\x15\x93\xad\xbf\xe2x\xfc\xd7\x81P\xe6\xbd\xd5\x9f\xcb\xe3n\xf1[L\xf7\x8bW}\xeb\x15\xdb 1\xb4\x178\xb4_=\x1f\xc2\x19\xa1\x94\xc9\xaf\xf4\xaf/\xf4\xaf\xa5\x0f7f\x11\xdf\xcaj4\xc1\xe6t\x8c\x9bHw\xed\xd6\x15\xd3\xb4\xc8\x14(\x988\x86\xbb\xa6\xba)\xd3\x97x\xf8\xae\x1e\x83A\xb1\xe8\x9bl3A\x90\x89\x97\x14\xc2\xad<\xc0\x7f_\xd0\xa9gt\xea\x97>\xacf\x97\xa6\xf0\xa2,|\x91\x1b\x07\x1f`\x04q\xf0\x1a\xbe\x07wM\xbf{\xe5!\xfc]\x99c\x11\xad\xea\xc2A8\xf7FJH9\xb5\xd0\x0f]\xdfC\x1d\xa7\xa7\xd4\xd2\xe4\xda\x08{\x01\xc1\x8d\xba\xb9\xae\x08\xb3:\xcc\xeb4\xd2\x12}7,\xae\x05\xe4\xb5\x17\xbe+ mk\x0c\x1d\xd6\x81`\x1c\x06\xfd`\xa3\x91X\xe2\xd6\x9aF\xd2\xe30n\x1c\x8c\xd5\x1f\xb9+\xce\xca\x10\xf4S\xf7\xc64\x08DV\x1fX\x9a\x1etb\xe5\x93\xb9\x95\xba\x93}\x16\xa54u\xa7G\x9e]B\xccG\xf3\x14\xb6N-\xcaT\x91\xda{\x1e\xdf8\x9e\x0fN\xf8\xf5j\xd4\xa7m \xa1\xce\xdc\x0b\xc2f\xf2\x1b\x92\xfbS35|\xf4?3\xdd\xa2\xaa\xf6\x9bn\x9a\x19\xa8\x95s\x98\xab\xf1\xcc\xf9A\xa6\x93}\xcf\xdd\xd2)uc&\xf9\xbeu\xb1\xc7\xfa\x0cyB\xc76\")\xda @\x813\x163\x8d\xec\xe5\x9a\xb58\x85\xd0\x83\x94\x1e\xde\x8a\xed_\x88K\xb1\xbd\x0d\x11\x13^\xeb\xc1\x0d\xb8\xf3\"i\xc2\xe7\x16'\x1e\xff\x8e\x12p\xb3b4b\xf1}\xdd\xff\xca\xdc\x08[\xbb\xbfoZ3#\x97h\xb3M\xed\xdd\x9f}s\xaa\xe8\xcel\xfe\x95A\x93\xda\xc5\xf7\x06\xd7\xa4\x94\xb2d\xabV\"\x96c]\x8a\xbd\xe3y+\x91\xc5\x9de\x176\xf9\xae\x9ae\x8b\xf33\x8dW\x85\xf2\xf6L\xfd-\xd1x\xc7\xeag\x9c!?\x83J\x97\xe4n\xb8\xf8\x87\xe6\xc5o%\xe4no\xc5?s\x14\xd7\x03\xee\xcbu\xf8?;G\xb1\xf5\xec\x98\x12/\xfd\xcf\xcd\xa5\xdf\xb9\xcd\xbc\xb7\xf6.+\x16\x8b\xee\x04\xb6\xc1\x04\xd5\xb5<\xb6\xee\xd4RO\xd8,\xd1:{\x96:\xe6\x8c\xb7\x9b\xeda\x9f4m\xb2{\xd0N@\xbf\xfb\xf4\x9f \xe8\xa5\xe7\x7f@\x02\xfa}sR\xc4\x01\x19q-\xe7\xbf\xae`\xb3\x9f\xa4}\xf3@\xe6\xcd\xbe\xc7\x14.\x99y\xe6\x82g\x016\xbf\xa5TOhu\x14\xe1c*DJ\x9c\x82ns\x84 \xd6x6s\x8e\x03\x8e\xc1\xc5\x08\xdb\x98D\xf1e6'/J\xb7\xf0\xe4\xee\x9d\xe7\xc3\xdd\x1f\xa4\xa2e\xe7t\xa5\xdd\x91?r\xf8\x15\xc0!\xa4\xee\xde\xc4s\x13\x0f-i\xbb\x1aK\x1a\xd7\xcb\n\x83\xf4\xfa0\x91\xcc\xae\x1f(eI\xf7\xe1&H\xb3\xdb\xde\xd6\xb0\x96\xb5\xa19\x86\xce\x16\x06\x99\x94\xa2\x9c{\x01\x05zS\x1fb\xfcc\x12d\xe9\x8a]68\xa5\xd4\x07\xc6\xcap\xb3`\x9d\x15%\xbf\x85\x08h&\x18\x81i\x11\x84\xf39&\x1a\x94Se\x197Cj\x00\xc9\xbcE\x10\xafh\x8f\xe7Q\x1e\xaf\xcb\x82\x8e\xac{j\x0by\x0c\xdc\xa1\xdc\x07\xe7{)\xac\x17\x85\x94\xad\x11\xb9\x0e\x9f\x90\x83\xe4\xd4\x16\x1b9\xed\xcb\xc9\xd2\x9c\x84\xf3\xbb\xa2\x0cK\x12-\xc3\xf4\x9a [\x1d\xb9N\x81\xa3r\xbcNK\xf5\"\x08\xd7k\x92\xce_.\xe3d\xeeJ_yA\xbb\xe5\xbe3,\x123\xb1\xc6J\x16MY\xdcS\xab2\xb9\xd3\x94Q\xb2\xa0oN\x84bG\x8f\x99>%\xc4\xd7\xfa\xfe\x18\xd6\x1af\xa0\xb0\xfa\x18\x9a\xecC\x9b\xd1)\xf6\xc1\x9a\x95\x0fVy5},\xce\xf5\xf4\xb996{\xee\xa8\xeb\xd8i\xd7\xda\xdb\xb5\xc5\x04\x9bv\xdd\xd7q\xcf\xeamJ\xe9\xb4\x0c29\xa53\x1ed\xed\xa2O\xbe1u\x89]\xe6YH\x14\xe5\x1e\xea\x9bl\x9e\x857<\xb6U\x16,ZQ\xc4\x05!\x8c9\xc5sRd\xc9\x0d\xf10\x9c-F\xb1[\xc5\x05y\xec\xc2\xb4V\x80-\xcc\x9e\x9d\x04\\\xd1\xad\xef'\x00M\xd4\x9f\xd9\x99\xb2\x0en&9\x963O+N\xdemmQ\x02\xcf\xf9H\xae_}Y#h\x8c\x15\x0f\x9bAS\xb6\xdf\xd6\xda5#u\xa7\x87:A\xd7\xb8v(\xf2\xffA]\xca\x12V\xe3*\xeb\x9dq\x03\x84\xa3\xde\xc5\xb5Q\xd7\x88\xa1\x02\xae\x1b\xc6\xa46\x1eW\x8f\xb12J\x16\xb5\xaeX\x85\x84\x9d\xba5\x15\xcf\xfb\xcb\xb2A\xb9yp\x0e#\xc8\x91Y\xce\xba\xf5\xbc\xf4\x90(\x85\x98\xbf\x9dk*}9|\xd4\xa054\xcb\xae\x89\xecr#\xc2\xb5\xf3}\xec[(\x14\x8e\xba\x8a2\x9d\xd8B\xa9\xf0\x80\x84\x14\x97@\x08Q\x12\x16\x05\x84\x85\xe2%\xfb\xbbLG\x93\xd2\x0bO\xa4\xc9\xbe\xe9\xc4|{W$\xe3Z\xb6\xc8\n\xfe\x02J\xab^\xbc&oS\x96\x1a<\xc5\x18]\\\x9d\x03\xe9h\xd4E\xe8\xe7h\x89\x92Z\x08\xfd\"\xd2\x84\xac\xa0s\x01\x0f\xad\xaeB\xf6\x89\xe4\x95\xbd\x95\x07\x0b\xce\x97\xb1\x80J\xe5\x8c\\l\xb8_\x8f\x03%8WJY\x1d\xea\x1a\xdf\x98\xbf\xda\x1dO\xf5W\x19\x7fE\xe1\x8f\x9c\x86\xb0F|\x86\xdc\xa4\xb5\x89 \x0b\xd4,\x83\xa5\xb2\x1b,iA5\xfe\xd0\xfek#\xf8d\xb9\xea\";\xc1\x163\xc27\x12=\xe7\x14:\x01\xf9\xb2\xceIQ`\xd6\xa4\xaa(\x81\xc4\xe5\x92\xe4p\xc5c\xccf\xb9D\x05\xb1`\xcd\x0e\x8c6\x86J\x1a\xb8\x935s\xccc6\x96\xaa3\x8eJ\xc2\x8d\xed\xe5\x94\xd8-\xd3jC\xa7\xf5\x0d\x0c\x08@\x07\xaa\x91\x96\x85\x95\xd5\xcc\xbd\x0c1,\xd4\xdd\xc6\xfb\xc8\xa8\x11\xb1\xc7g8\xfd\\\xa1CD\xb2\xa1K\\\x83\xcbKJ!}\x93\xfb\xa3\x1aX\xef\x8e\xbfM\xfc\xa4\x03\x93}`\xea\xee\x99\xedz'-\xc5\x12zMS\xe09f\xe1\x07\x0e&\x9eb\x906e\xe5\xbb\xe3\x03\xe3\xf5\x0cMc\x06a\x97\xb6\xce\xb3u\xd1\x845\xa4\x98\xaa\xe4\x01HyIN\x16\x05K\x0d\xc5B\xcc\xad\xe7a\x89\xf9\x0f0Nr&\xad{\xbb\xef\xe2\xef\xd8w\xa4\xba\xdd\x87r\xf4\xa9\xe2# \xa3\xf2e\xb6Zg)\xc1\xbc7\xbf=\xf8J\x95\x82\x94\"EY'\x90\x91\x88\x11%n\xa69\xf4\x90\x04x\xd8\x8f\xdcu\x0e\xf7\xeb\xec\xef|~\x01I\xffZ\x91\x8a\x9c\xf31\xd4V\x15\xbe\x94\x87^\xab\xfb\x92\x87\xa2\x15\x11\x9d|p\xc4\x14T\x01\xa7<\xc9E\x96G\xe4gl\xa8[\xb6f\xe8\xf0u\xf3\xad\x906\x96\x03\x07W\xfa\xe0H]\xab\xe3\x8b\x14\xd8\x17\xcap\xaeP^Qp\x1d)\x85\xaa\x94 \n\x1fb\xb7\x90\x1b\x90Z\xf3\xd4/\xe3\xe2C\x95\x93\xd6\xa9\xe0 D,\x8cB]\xf3\x18B\xf5\xca\xd2\xc6\xa4\xb7\xc5\xb7\x00N\xa9{ ;\xaf\x0b\xf8\xa2\xe1\xbc\xe2mV\xa5%\x99\xf7\xc5\x0d\x14\x14\xb5fc\xa9NC\xdb\xbe6ae\xae/\x1d\x0dm\x18\xe6\xfa\x1f\xc9: #\x16\xa0ph\x1f\xe2n\x18\xea7\x8bm\x86\xec\xf9\xe3\xf7@,\xba\x1c\xac\xfe\x1b7\xfd\xdb\xb7\x1f\xb5\xfd\x04GU\x9e\xe3 \xdd\xdcu\xa2{\x16\xc3\xb2\x9a,\x98#H\xf3\xcburz\x05\x03\xc2\xd4\xf8\x0e\xfa\xdb\x1c\x8c'\xe3\xdd\xdfuQ\x9c\xf3W/?\xbe\xfat\xf9\xe3\xfb\xcbw\xef?]~xq~~\xf9\xe9\xdf\xdf\x9c_\xbe\xffx\xf9\x97\xf7?_\xfe\xf9\xcdO?]\xfe\xf0\xea\xf2\xf5\x9b\x8f\xaf~t\x86\xf4\xa9Q\x12\xd3\x897L*\xd1\x17!\xafu\x97\xcd~z\x14\xfc7T\xb7\xd1I\x8f\xd3\x7f\xba17\xa6\xbb\xba&\x14\n\xae\xb2\xf4\xd5\x97\x92\xa4\x94\xf8-0\xca\xf85)\xb5\x12RD\xe1\x9a\xfcH\xc8\xfa\xa78\xfd\xfc!\xc4\xa4\xcb\x84;\xbb\xb5\x8a\x8be\x98$\xd9\xed\xab\xbfVa\xf2\x1f\xe4\xae\xe0i\x05\xe3d.\x82\xbe\xb0jY^\xb2\xccz$\xb8*3^H\xf28L\xe2\xbf\x91s\x12\xe6\x11ko\x1d\xe6\x85\xfc\xfb\x9a\x94\xe7\xe1j\x9d\x90\xf3hIV\xec;L\xd1\x10\x96\xe4C\x98\x87+\xad\xa4,I\x9e*eo\xe3\xf4'\x91;Z*\x0d\xbf\x18J\xffX\xc5s\xa5\xe0\xc7\xb0$\x9f\xe2\x15Q\n\x99%\x8cR\xf4C\x96%$T;~\x1d'\xeawo\xd2\x92\\#\xad\xd3\x94\xbd\xabVWZ\xd1\xdb8\x8dW\xd5J\x1fn]Fi\xac\x97K\x12}\xe6\xdf\xad\xc8*\x8b\xff\xc6\xba\x8a\x8b7\xabU%\x84~\xa6\xd0>\xe2:_Q\xd6p\xfa\xd4d\xbd\x1e\xd7\xaf\x8fL\xaf3\xfe\xfap\xcf\xf4\xb6\x12\x1f\xef\xee\x9a^\x87\xf5kc\xd7\x05\x7f\xcd9S\xf9\x15\x9d\xdc\xff=\x7f\xff\x8e\xeb\x00\xfa\xec\x19\xec\x9eK\xc2*\x816\xc6\xce\x9b1\xb9-p~\x93\x85\xa4kb\x97\x0d\x11P\x15*+X+\xc6Z\x9d\xf4\xa4\x93\xb2\xa1\xf4:\xedD\xbc\xb8\xeb] \xde\xc8+\x17C\xd6|qy\xe4\x9a2\xfb\xbf\xe7.\xb2]\xaa\xdfj\xdd\xc3\xff\xcf\xde\x9fw\xb7\x8d#\x0f\xa3\xf0\xff\xcf\xa7(\xeb\xc9/C\xb6i\xc5r\x96N\x9c(\x9et\xe2\xa4\xdd\xd9z\xb2\xf42\x8a\xc6\x87\x96 \x8b\x1d\x89TH\xd0\xb62\xf2\xfb\xd9\xdf\x83\x02@\x82$\x00\x82\x8e\xbbg~\xf7^\x9e\xd3\x1d\x8b\x0b\x96B\xa1P{\x85i\x1a\xae;t@E\xb3\xe8\xd8\xaa\xfe\x8d\xbd\xbc\xf70@v4nv4K\x93\xe5O\xef\xdf\xa6S\x92\x125\xef7PO\xab|g\xabr\xe1\x11c*S(VN\xb1\x84,\xe5\x92\xf4\xd9\xbe\xb4}Z\xc0\x8b\x94\x19x\xa3\x8c\xcf\x04oM\x8a\xa6\xde\x93/\x1e\xf1\xfb\xcbp\xe5Q\xccd\x1fe\x14g[\xbe\"\xa6\xf5:\\\x95oB#\xc6 +;D\xf1\xf4C\xe2$\xa2\x80b\x16\xab\x1b\xb8\xa0jV\x0d\x159\xdb\xef\xcf\xa2\x05%J<\xa3\xb1 \x91hA\xefD\xa3\x8d\xf9\xf3\xd9i\x7f\x18N\xe6e\xeb\xc6\x1c\x01\xd2*0J\xc7h\x0dM\xc78{O\xe4^\xd7X#\x9a%\xfe\x18\xc8\xe2$]\xe2 \xc2qn\x08\xef\x03\xa4\x13\xcfcW\xa4m\xc9\xe8\\\xf4\x14e\x05\xdd9\x14}\xe4X\xfd\xf8\x9a{\x91\x13qj\xb6\x8a\x9bu\x97\x10A%^\x87+\x17t2\xa2LJ\xa6\xf9D)\xf2g\xcb\xfdP]W\xe2\xb1\x95\xe5\xa6\x9df&\xd8\xcb\xa0\x12\xd1\x08\xca\x90\xdfa\x97\x7f\xd9\xa8\xcfD=\xabr\xbc\x06\xcb\x9cP\xf7Z\x0f\x84\xa8\xed@\x88D\xa5\xa7\xdd\x00\xf2\xf2n\x1c@\xd4 L\xd9:\xa3d\xf9a\x9e\xc7\x9f_G\xd3\xe9\x82\x9c\x87\xa9]\xe4\x07\x9d\xe5\xce\x04\x13\xd2\x9fJ\xf7I\xc1\x85\xe9K*@\x97Fu/7\xf4H\x86\x0f\x8cyKc\x8fz\xe8\xbfE\x9c$\x8b\xe9\xc3\x1e/_\x8f\xff\xa9\xaf\xe2\xbd\xf1h\x05\x07\xb8v\xb7\xe1\x00\xf6`\x1f!|\x0f\x0e\xe0\x8e\xf8\x9b\xdd\xbf\x0d\xfb\xb0}\xeb_^\xe8\x9dd4\x0d't\xb3\x88\xc2l\x13O7\xd2y{\xc3\xf6\xec&\xf3\x96\x9b\x8c\xa4\xd4?\xd8\xe44\xf17'^\x98\x91\x0d9\x8d\xe2M\x92,<\x12\xc6\xfe\xc1&%\xe1\xe7\xcd\x9a\x12\x7f3\xc1\xc7\xec\xc0\xd9\xcc\xc3t\x83\xf2\xedt\xb3\x08\xb3l\xb3Hb\xb2I\x96\xab\xc5&\x893\xbaIb\x1a\xc59\xf17S\xe2\x9d\xe4\xa7\xa7$\xddL\xa2e\xb8\xd8L\x16aJ63\x8f\xed\xf1\x0dI\xfd\x83M\x14Gt\xb3\xf0\xc8iH\xc9\x86P\xe2\x1f\xf8\x9bi\xb2\x99&\xf9\xc9\x82l\x887\x99'\x9bEv\x10\xcd6\x8b\x8cx\xd1\xcc?`\xf3\x88\xb3<%\x9b8_n\xceHL7\x17\xde\x84\xac\xe8\x86L6+\x0fS4o\x92\x94\xfa\x1bJ\xbcx\x9amPs\xb2Ic\xdf\xf7Y\xd7\x8b\x05\x9d\xa7I~:\xdf\x84\x8b\x8cl\xb0l\xf9b\xcd\x86r\xc1\xa6\x93\x84\xeck\x8f\x84\x939\x9b}D\x18\xd8\x92\xe5&\x8f'\x1e\xdb\xbdl\x80\xa7\x8b\xe4$\\lN\x13\x9alN\xf30\x9dn\"o\xb6Y\xae<\x8e\x03\xd9F\x19D\xecEt3Y\xe4S\xe2\x1d'\xf1\x84\xf8\x07\x9bE\xc4\xa0\x95\xd3\x8d\x14}6\xd4#\xe9,\x9c\x90\x0dI\xe3p\xe1\x1f\xf8\x07\x9b\xcc\xdf,\xbcpy2\x0d7\x84n\x92\xc9\xe7M\x12\x9f\xfa\x9b\xa5\x17M\xd2\x04I\xe0\x06\xf5L\x1b\xaeK\xf07o\xc27\x9b\xd8\x0b\x97$[\xb1\x96B\x1a\x9d\x91\x0d\xb9\xa0\x1br\xbe\x89\x16\x9b\x84n\xf2\xc5\xc2\xdf$\x1e\xb2E\x9b\x15\x8f\xaf\xdc\xa4\x9b\x9cn\xceH\x9aFS\xe2oV^8\xf9\x1c\x9e\x92M\x98\x86\xcbl\x93Fgl]\xd2\x84\x92 %\x0c\x104\x99$\x8bM~\xb2\x88&\xfe&\xf5\xc2\x88a\x8c\x17N\x93x\xb1f\x0b7\xdb\x9cF\x19%\xe9fEB\xba\xf9\x92Gi9\xefl\x92\x93\x0d\xd7\xb3mh\xba\xde0\xaa\xe8\xfb\x9b\xcc;Y\xb3\xc5\x0f\x17d\xba!\x8b\xd9f\x9e\xa4t\x13\x9d\xc6d\xba\x89\xbe\"xB\x1aM6\xa8\xd3\xd9\xa0\xa9a\x93\x9fp\x97\x84M\xbe\"\xe9f\x1dO\xe6i\x12G_\xc9t\x83\xb1\xc4>\x83\xe8r\xb5`\x83\x9f\x93x3\x8f\xb2\xcd\xf7|L\xd1\xce\x06\x87\x11^\xf3z\x8a\xf6\xcc)E\xfb\x14\xab\xfc\xa2AB\xefGR\xbc\xdc\xf4\x86\x99\x06Pw\x06\xae_X\x8b\x8c1\xa6\xd6\xb7N\xf1\xadA\xcb[K\xc6\xd3z\xa7\x01\xc4\"\x83\xc9\x00K\xede\x84za\x00k[\x81\xe2&*H\xa1c\xc9\x84\x8e\\: .1\x19\n\x0fq[\xea\xb9A\x0d\xb1hMU\xdb(\x9a([0\x11\xa7\xc2\x9b\x8d{\x87\x95\x84\xbe$U\xa3\x81\x86\xb8H%\\\xa3\x08J\x80\xf6\xb5l\x12.\x9e\x86\x19\x1b\xd6\x93\xea\x9d\xe7b\x90\xad\xa0\x91\xeaG\x8f\xf6Sn\xe8\xf7n}\xea\x8f\xfe\xd5\xbf5\xfe\xee\xc6-&J4K\x7f\x92~\x16\xc6\x11\x8d\xbe\x92\x8f\xe9\xa2\xb5\x87H\xad_\xabz\xdb0a\xadW\x8b7\xd2\xc9\xd6\x8abp\xa6\xf6\xeck\x8f\xe0SB\x9fL\x18\x97\xcf\xb0%M\x16\x8b(>}G\xb2U\x12g\xed\xd0\xa8\x9dd\xa5\xc2\xbf\x1fe\x8a\xf6_Q\x87\xb0\xa51i\x0c\xaa\xc7\x9e\xfe\xcdR\xbf4\x8b\xe2\xa9\xd7\xaa\xac\x91Wq\xc2e4Li\xf6kD\xe7^o\xafW\xe8#U\x15*\x83\x89\xd7\x9b\xf0\xdd\xc3\xad\xf6\xff\xbe\xf4K,lz\xfe\x01\x98+X\x15\xaa\x1d\xaf'\xba\xe8\x89\xc4\x9b\x1a;\x89\xa1\x8d\x14\x9d\xe64\xe3\xd27\xe2\x17\xca7a\xea*\xb3\xa4\xc5\"O\xa2Y+\xc7\x9aM\x9bx2%d\xb5X\xbf\xa7i\xb4zI\xd65~\xcd\x927\xecZX\xaab\x99[\x94\x81:\xa7L=\xb6ut\xbb\xafZ51\x99N]K\xb7\xd9\xa8\xe4\x8f\xf1q\xb1\xcd\xd4&5\xef5e\xf8\xbf\x19\xb05d\xb1\x86\xa3\x91\xc6\xe4dVh\xe3\x98b\xee\xa1\x17a=D\xd4*\x8a\xc8mv\x87 5<\xa1\x0c\x15o\xe8\xd3V_\x9aU\x90\x91\x86\xec!\x15s\xb1\xa3F\x86\xa2\xdd\xa6\x94\xe2\x80^)\x0c\xb9A-\xeb\xcdp\xddp\xa6\x18\xad\x16\xb4m\xc1)\xb7Z\x94\xd5\x8dMn\xf5P%\xbeU7_n\xdf\xd3T\x94+\x98\x9d6\x83d\x91o\xb1\xd9\x84iM\x18L\xc4g\x1a\xd2\x1f\xa3\x03\xc6\x87\xa4p\xeapX#\xfe\x8da\x8d\x94\xde\x8chR3\xfdU\xdfc\x9bb\"\xfd \xee5\xfc\xfa\xa1\xc8\xbaq\xfbN=<\x05D\xee\x0d\xf4\xb0\xb83\xd0}\xba\x92-\x7f\xbf\xab{\xaa\x0f\x89\xaf\x16_e\x0f\xcf*\x07\x89\n-\xa3\x05\x19\xb3\x16\xf4\xa3\x18\xf5\xe3\x99\x17\x97\x0c\xb8N\xb7\x02\xaa'\x809:\xd7m\xa3\xc1\x01(\"A\x84A\x13\x11\x16Z5\xf2\\.hm\x8d\x95t\xf1<\xc0C\x9c\xe2\xa7Q\x93\x18p\xfe\xad\x9f%K\xd5s\xa2\x8d\xddd\xbd\xac\x95a\x8eb\xc6[\x8db\x8d\xdd\xeb\xb2\xbe%\x9a'\xdf[\x83\xdfc\xeb\xfe\x80\"\x10\xf01\x94\x02T\xef\x97p\x91\x13\x1e\xe8uB`A\xb2\x0c\xe8<\x8cA\xb4\xdck\x8e\xb1\xb9;\xfe0\xf8gv\x18\xd3#\xf3\x98NQ\xe5\x9e\x8aa\xf1\xc6\x9d\x86\xf5Y\xefI\xda~Z\xa0\xa4y\xeb_;\x07\x9f\xa6\xdb\xde\xa7>\xfb\xc7?\x90\xb6\x01EN\xad\x0d4\x04\xc1\xf8\xb8\x0c\xee\xc8\xe0\xfa\xdamt\x0e\x83\x8a!\xe2\x8d;\x0d\xeb\xb5\xceE\xd7mLx*\xd5\xf2+\xd4\xbc\n\xcd\x90\x9bE\x0b\xe24\xc0\x0f\x06\xbfb\xb71\xf6h\x9a\x13N\x1aD\xccR\xb8\xc8\xd4\x1b[\xbb\xca\xdf\x03\xc9\xca\x9bF}\xc2\xbbw\x1a\xf8S\xbd\x8f\xb4\xdb\xb8\xf9`5\n\x1f\xf3\xd8\xc4\xcb.C\xfb\xd9\xe4\xd3\xed68^\xb1\x9f}V\xb8\x0b[VZ6\xef4\xb2w:\xf7s\xb7QIqO\n\x1b}\x9a\xbcJ\xceI\xfa4\xcc\x88\xe7\x07\xb0u\xeb_\xa3\x7f{\xe3\x83\xd1\xee\xce\x83pg6\xfe\xf7\xfd\xcb\x9d\xe2\xef;\x0e\x7f\x0f\xf6.G\xfe\xe5\xd8\x890\xb0\x91;M\xf8\x8d\xd1\x0b\xdf\x9d\x98\x96\xbc\x89\x1b\x9d\xe7]8\x0d\xef\x951t\xa0\xfb\xf0:\x90\xfc\x0e#|f\x08xp\x1e\xdf\x16O\xebpzx\x81\x1e\xc9\xb6\xa5\x9d%\x8bEr\x0e+\xd1I\x0f\xb6u.\xec\xd53\xbc\x19\x9e\xd1:\xb2\xabr\xb67oV~\x9b\xb9Z\x13\xc7\x8b\xac\x1eR\x9e\x93d\xba\x16je\xae`\x8c\xe2\x1ew\x93\xc7_h\xc8:\xbeX.z\xc7\xd0\xf9LyS\xb0\x1e\x867\x17\xe5\x9b<\xc9\x85\xfe\xb5U\xf9\xda,I\x97!5\xbd8\xaf\x8cQ\xec\x00\xc3\xbb\xd3\xca(\xed\xef\x9e\x95\xef\n\xc4\xad\xa7\x1e\x01\x01G\xeet\x950\xa67\xb2f\xe6\\3\x91\xbdT\xcc\x0d\x01\xbf\x8c\xf4\xfd\x83Pe\xf4B\x99\xe0[\xbc_\x15\x9ay\x82\x97H\x16\xd306u\xackJot\x94MN\x92<\xa6&-:\xbbN0\x9c\x8fq$\xcal\xccl\x8d\xb9!\xd4eH&\xa1l\xcb\x8bx\xa6\".\x96X\x06r\xc1\xbe/\xb5i\x95\xcfw[\xbf\xc6\x94\xf1\x92\xf9\xeb\xfe\xf9\xa1\xc1\xc8\x0e\xd2\x00\xd7\xd0B,\xcc\x9e|V\xed\xaa\x9bdvhp\x08\x90\x17O\xef\xad\xd7\x11G6u\xac\xbc\x94\x80\xa7\xc8\x0fD\x7f\xc6/\xda\xed\xcf\xf2\x92\xb4\x88\x1b\xb8{H\xf7 ;\xde\xf88y\\bq\xf6\xe1\xf1\x80c\xe9\xf9\x81\xa1\xfc8h\xf5\xb9 \xb6\xe3\x13F\xd2\xd7\x01\x9c\x16\xb5#0\xb5\xfd\xfb\x00\x0e\xc75\xe1\xd5:\xf6R\xdf\xa4}E\xa7\xe6\x07\xb1\xd4 \xf2\xcfe\xf9 9\xf7w\x82\xd6\xc3,\"\x8b)D\x19\xe6\x0fY\xa5\xc9Y4\xc5\x13@G\xb1e\xa3g\xb6\xc1\xb2\x89\x7f\x85!<\xf3\xa2\x00\xce,N _\xd1\xc4\xc1\xc7\xf3\xd5\xd5\xd9\x00\xc4\x10\xe6\xe5\xd6\x99\xb7\x8d\xe69\x0c\xe1\x0d\x1b\xcd\xdc2\x9a\xe7\xcah\x9ew\x1d\xcd\xb4m\x08\x1fa\x08\xaf\xd8\x10\xea\xa5E\xd4\xeb\xa32\x84\x8f]\x87\x10\x96\x00 \xdbF\xf3\x03\x0c\xe1-\x1bMh\x19\xcd\x0f\xcah~\xe8:\x9aY9\x9aY\xdbh\xbe\xc0\x10\xfe`\xa3\x99YF\xf3E\x19\xcd\x97\xae\xa3\xa9\x1e\x89m\xe3\xf9\xdd\xe2\xb7$/\xe4n\xbc\xdfQC\x1eR\xb2C\x99\x1c\x85\xcd\xaf\xe0\x00~\xf6P\x85\xd6\xcb\x99\xb0Q\xdc}\xc7\xef>\xe5D\xd4\xcc\x17\xc9K\xcc\xf6w\x93\x1bKIf\xab\x07[\xdb\xfc~\x85!|\xf0\"\x0b\xb0qv\xbfv\x18\xe3\xaf\xedc\xac\x1c\x9emC\xfc\x05\x86\xf0\xb9}\x88\xbft\x18\xe2/\xedC\xac\x9e\xd0mc| C8j\x1f\xe3\xcb\x0ec|\xd9>F\x95\xc1j\x1b\xe1\x8b\x96\xa1\x1d#\xf3S\xb0a.\x03}!y\xd6\xa3\xd8\x1b\xf5\"J\x96Y/\x00\xceg\x8f\xfd\x00\xa2\xa6\xa1\xbb\xcd\xd7\x03\x14\xc1\xaam\xdb\xb1\xab\x82I/\xd0I\x82!\x0b\x06\xabV\x97P><\x12\x0fU*\xf0\x02\x190\xf6\xf4)\x13*\x03ap\xe7\xeb`\x1f,\xbb\xa2xJ.\xf6\xa1\xc5g\x90]$M\x93t_\x13/\xa7^\x97\x96x\xb0v\x9cP\x18\xe46\x94\xb8\x01Cx\xdd\x8e\xb47\\pA\x00\xeb\x86+56\xda\xbd5\xfe+\xcdl\nvNI:\x1a}\xbb\xbb\xb1\xc6\xd2 \xc2/\xa8\xab\xd8\xdf0h\xe9\"\xa0\x19\xbco],\x17BwE\x8c\xf2]\xc4\xbd\xae.\x96\x0b\xdc\xb6\xf8\x17\x166\xb2\xad9\xd7\xf3\xb0o\x98\x94/\xbe\xfd\xf7e\xc0\xbe\xbfq#%3\xd5\x1d`\xbdBO\x18\xda\xc7}\xcd\xff\x14%WD\xb9'\xda\x0f\xa7S\xf4M\x0c\x17?\x97O\x0e\xe0o\x8f\x0eX\xe3g$\xcd\xa2$\x1e\xf6\x06\xfd\xdd\x1e\x90x\x92L\xa3\xf8t\xd8\xfb\xf8\xe1\xf9\xce\xfd\xde\xc1\xe3O\xb1pl\x87\xdf^\xbf\x02r\x81K\x0c\x13\x9e\xe2\xf7\x84\xc0)\x89I\x1aR2\x05\x1e\xa4\xf47\xa3\xff\x93\xbc\xa4!LL\xa7\x8f\xa9\xb1\xbd[\x9f\xde\x7f\xf7\xe9\x96\xf7\xe9\xfd\xb6\x7f\xe3\x96\x05\xd9K \xc2\x10\xa2\xd1\xa0\x19\x8c\x08F\xc6B1\x16\x9eJK\xed\xf4)\xea\xcb~{\xfd\xea\x90\xcf\x8d;\x93\xb8\xf8\x80\xb0\x89$\xc2\xc3\xa8l\x8fo\x82\xe7i\xb2\xe4\x1bA\xb4\xd7\x9c\x91T\x8a\x99$\xbb\xa4M\xb2K\xb0\xbcm\xcd\x13&)=a`_\xc9y\x06Pxi\xaaYP\xac\x8e_g\xa2\x0eI=\xa9\x92\xbc\xd8\x12\x94\xe2\xfc\"\x99\x84\xac\xa9~\x86\x8d\x1b\xf4K\xa5\xde\xd2\xb4\xb5z\xa8\xa47\xee\x11y\xf0\x90~\x96\x9fd4\xf5\x06\xbe\xac\x17tS\xa7\x8d\x01\xd5C=\x85(\x86\xd8\x87\xb8^>%\xe5\x8e\x8a\x18g8J\xc7\xb2\xc5!&[\x1bM\xc9$\x99\x92\x8f\xef\x8e\x8a,]^:\xda\x1d\xfbc,\xdd;@u\xa1\xf6\x9d\xc1\x98\xdbU{.\xf8$\xb7us\xcd\x9a\xd9l\xec\xb4\xd5h\x15_\x86+\x07\x7f6\xf19\x12\x83\xea\x8c\x88\x0f\xdb\xd0\x1b\xa2\xb6\xb6\xf9\xb4\x9a\x99T^\x97~\xff\x8f$\x8aqy\x9aS\x13\x19{\xec\x83\x92\xf3\xa9d\xdd\xa0\"n\x17K\xd5yD1W\x04\xd0\xcb\xe9l\xe7~\xcf\xf7\xcb\xbb\xbd\x930#\xf7\xee\xe8\xc6Pf\x10jv\x9d`\xb8Y\x94\xc4\xd9{|\xcb\xe4\xb5\x13.V\xf3\xb0%\x97\xacz\x154\\j\x13\xe7=\x1f\xb7\xd0\x02S\xc1\x85)\xf1\x88\xfa\xccpd\xeb7\xe6\x92\xd0y2\xbd\xf2h\xf8\xe7\xa6\xf1\xc8\xa7\xceLDs\x8c4<\xfd\xb3\xc0Y\x1b\xb2\xf3 5\x98Y\xcb4\xe5\xc6\xce\xe8\x9cT\x94\x8c\xeeQ\x0cF\xbd\x91\xf4\xe6\xa5F\x0f\x11\x85m\xe1\xa5oz\xe5\xdf\xa2\xcc\xd1(\x0e\xd8\x06\x0dt\xfb3\xf5K\x9f\xfa\xff\xd9\xdb\xbdu\x1a@o\xbb\xe7\x8f\xc5\xfe\xd4-\xa9\x91J\x11\xdb\xa6\xd6d\xee\xaa\xac\xa4\xc1\xb1\xa6P\x9a1\xc25- W\xac8\xe5\xb4\xb9\x8ct\xf2\x18\xa9\x8e\xbc\ns\xa9\x143\xa4's\"\xc0:\x8f[d\xcaT:&\xcc\xd9\x98\xd4(\x8d\x96\x9e\xb2H\x9f2\\\xa3c\xb4\xd8\xf4z\xb6\xe1\x1a\x92\xab9\x0d\x93\xc1\xec\xb8\x84\xd9\xd7\xa6{Y\xa0I\xe7\xe6\xd44m\xe6\x9b\xb0\xecd\xf1\xd1\xad\x7f]\xec\x14\xccu\xeb\xb2\x05\xc6\x14t\x7f\xe6\x08\x85\xfdgS\xd8\x976\x85\xf5h#\xecb\x1ba\xf5r\x9f\xca\xff)\x1f\xf0\x94\xdfl\xa7x\xf7\xee\xfb\xfd\x1f\xf2\xd9\x8c\x08\x7fq[\xf5\xa3\xb3\"sSq\xf2\x95x\xa2\xa6\x19\xacX\x8c\xc0%S|o\xc49U\xfe\xe9\x18\x91:nT\x8cr\xca\x06\x89\x94\xae\x1cWjcD\xf59\x0eAaO\xf9T\x94d\xbc\x8bhBL^\x97\xc4\xb8\xbc<\xa4\xaa\x9aL[\xe4K\xe4\x14@-1\xe1c)+S.\xd9zZr\xfdP\xecx\x99\x97\xbe\xaf/\x9b%\xb9\xf4-\xa6\xd6\x16\xc3\xb2\xc5\x17\xae-F\xd6\x16\xb3\xb2\xc5\x1b\xae-&\xed\xb3\xbey\x13\xb6&e\xd3?\xba6\xadI-\xaf4\xbd\xe5mQ.\x87\x8f\x16c\xb7\x06C\xd7\x06\xeb\x898L\x0df\xae\x0d\xce\x1d\x1b\x9c\xb4\xaf\xf8f\x83\xdd:57s\x1d\xdf\xb41>\xf5\x17\xf1R^\x83\x85x\x91\xfc#\xe1\x7f\xc4\x8a3+\xcf\xd5\xcd\xee\xbc$kL\xcf\x17\x8a\x17\xe2)\xb9\xc0\x1b\x19\xbf\xf1$\xcb\x92I\x84\x99!\x00s\xb8\xc4e\x00\x1c`x~\xdc\x97m\xb0\xae\xfbe\x0bl\x00\xfd\xf7\x04k84\xe9\x07\xa6\x19\xf8\xfb\xdf\x8f\x8f\x8f^\xbf\xfe\xf8\xe1\xc9\x0f\xaf\x0e\x8f\x8f>\x1c\xbe\xc3?\x8e\xff\xfew\x8dji\xd5\xfc\xe2\xe5\xe1\xef\x87\xcf\x0c\xaf\xcf5\x1d\xbcyv\xf8\x9b\xf1\x83i\xf3\x83\xb7\xef\x9e\x1d\xbe3~p\x06C\xb8\xdb\xbc\xbd\x86!\x0c\xe0\xd1#]\xb5\xf3S\x18\xc2\x1av@\x93\xaa\x7fi\x90\xf7\x8f\xed5\xae\xf7\xeb\x89$A\xcf\xf9\x9f\\\xa5\x19\x13-?o9\xd8\xb9q\x18\x0b\xbb;\x92\xe4\x0b}\x8bT\x1c\x0dE\x83\xbbn\xdb\xe9=O*\xaf\x7fxh9\x89D\x84\x9bF\xaf^\xa9\x0e%\x0bH{\x98x\\\xa88w\xb0JH*r\x9e\xcb\x94\x05<\xd3\xc6\xeeCLw\x11?\x84h{\xdb\x87t\x14\xf1$\x89\x11\x13\xe8\xcd\xee\xf5\xa9\xd3l\xed\x01\x0d\xaa;:\x06\xa2\n\x98f<\\\x82\xf6\x8f\x8fy\xe9|\xe2\xfd\xc1OW\xf6\xc4\xa9\xe3\xb7\xd6Tb\x85\xf5A)\xe9a\x13\xc1P\xb9\x04\x8f\x1f?6\x995\x84\x92j\x1bb\x11C\xbd\xd9\xc0\x9d\xbd\x07w\x1e\xdc\xfb~\xef\xc1]\x9ca\x19\x99\xf8&|\xa3o\x85MZ\x93\x92\xcf\x04>\"\xcax#\x90\xb7Q\xf1\xe1\x06\x9c?l\xc5\xf2\xeb\xf9\x9c\x0dm|v\x90\xda<\x19jP\x16\x9d\xde\x92Q\x91\x14\x1e\x0da'\xae\x14,\x1cJ\xd0\xd5_&\xf0xXW\xc0\x9a\x06v\xd4\x96\xbd\xf1\x83\x18\xb9\xe3\x86}\xed\xda^\xbd\xaa\x8f\xa1\xbd\x0f\x0e\x80\xab\xc5i\xc4\x986\x97/\xb6\xba\xbf l\x03\x1a\xc5j\xb1\xb4\x8cC\x92\xe5\xe2\x99\xbc`\xac\xde\n\x02\xbf\x9f6\xabT\x83pd\xd6\x9c\x07\xef`\x08{\xcd\xdbo\x9c\xb3\xb6\xf3M\x9d\xa4\xcd6^\xf1\x93N\xbe\xa09\xda\x9e\xc1\x10\xde0\x1cye:\x02\xbe\x1a\x08\xf6<\xca0\xbb\x8833\xfe\\\xae\x94!\x99\xa7\xb4Z\x94\x0b\xc5\xb6\xe0\xa0\xb2l#\xf6\xbd\x85\x8a\xc2\x01\xa4\xc5\x19\x12\x89\xb2\xc0\xd6\xd3\xd0\xe0\x078Mb\xd3\x89\xebH\xab?\xda\xa8\x82uH\x1c\xfd\xac\xe3j\xad\xdcc\x18\xd4\x0fv\xees\xebWW6\xf6\x8b\x9d1\x00S\xd5h\x8a8\xe3\xd4\xc5\xefv5\xe0\xaf\xda\xf4\x1d\x05-\xe7Un\xb5\xc5\x96\xf5\xdd\xfdj\xef\x8e3(o\x90\xd6\x8e\xde`\xedR:ze\xcaM\xa4\x9d\xbb\x92\xb7\xdaiD\xbf8\xc0X\x13\xcc,\xb8\x14\xa7.^Z\xbb(\x92\x01\xa8G\x8e\xdc\x8e \xcf\x95-\x85\xe8>M0]\x83\xb5\x80\xb5\xbc$P\xd1y\xbd\x12\x167\xac\xd5\xe6!\xe7@\xa85\xc3\xfb\x96\xa9^\xd8\xe1\xc5\n3\xd3q\x06\x0d\x92\x14\")\x15 5K2\xe3[.\x0b\xd8\xd3\xcf(\xdd\xf0G\xfb\xe8.o\xeaV\xbb\x8a\xecj\xa6\x083\xc0\xfd\xc5\xb7\xc1\xbdO\x13\x94\xc5$\xc4\xc5\"\x84\xcd\xb5\xa0\x98\x9f\xfd0\xa6\xe9\xbax\x99\xba\x8e\xf2\xc6\xb7\x8dR30\xa2\x0e\x84\x8dSH\x91\xf2V\xe8<\xb6\x1f\xadc\xf3\xbe}pr4h\xe0\"\x14\xef\xd7F\xa6\xfe\xfa\xaa\xa8\xaa\xa8&\x1f\x81e\xb0\xbd\xd1\x918\xa0\xc75\x05t\x00_\xfb/\x0f\x7f\x7f\x0fCx\xca\xfe\xfe\xe5\xc9\xab\x8f\x87\xec\xd7\xcf\xec\xd7\xe1\x9b\x0f\xef\x8e\xf0\xe7\xbb\xa0\xd2\x7f\x14g+\x9e\xed\xbc6\xaa$O\xab\x99\xb9m\xf4\x85\x1d\xf0\xe6\xdc\x0bJ\xcb\xa3g\xe3\x0em\xd6\x1b\"\xdeK\xae\xb7x\xd9Of\x8e\xed\xbc\xf4\n'\x92\xc6\xc0^V\xa7L\xbe8\xb6\xa9\x1b\xdb\xcb\xab/*\x82\xef\xf8\xb84\x8e\xb2\x91\xfc\xbb\x17@\xef\xb2i\xcfQ\xfb\x99\x84\x939yG\xb2\x962\xc7JW[\xbc/\xfc\x10d\xc5\xafB\xd6\xfb\x18\xe3\x83)\x17\x06\x957\x87\xfc\xc5\x12\xeb\xcb\x8a\x0f\xa2\xfc\x99\x14\x1c\xcb\x8f\xc4\xd9\"^\xb0M\xa3\xe8\xdf%\x86HLdB\xcb\x82d\xbc\x02\xa8K\x0f\x89S\x00\xbe\xe8b\xd6\xda\x05\xf1^\x04\xf0\xd2\x0f\xe0Ee\xf1%\xbdu\\\x13=\xa6\xdf\xe0-\xdfp\xc7\xf4\x1b\x16L\xbfQ\x19`II\x1d\x9b\xd6\x0d\xf1\xc65#\xfc\x88!\xfc\xb8\x89\xf07\xae\x19S\xea\xb5\xdd\xf5=|\x13\xa64\xbb \xde\x8f|=\x7ft_\xcf\x1f-\xeb\xf9c\x8dr\xd1o[\xcb\x97\xfd(\xe3-D\x94\xfd\x92\xda[\x86\xdeB]\xcb\xc6\xaf(ro4\xb5\xb7?\x05\xf0\xcf\x00~\x0b\xe0\x1fM\xa5\xe9\xfb\xc3\x7f\xa0\xc2\xd4$9Rj\x11\x1d\x8fCQ+\x83\xd6\x88M\x17\xf6\x95\x18z\x90\xfc\xa50.}&\xebL\xcbC\xf2\x91$\xb26\x88\x1c\xca\xf1gQ\x0b\xab:4\xd2eh\xb1u\xf2Q\xa9\x9f7\xcc\x9f{\x16:+\xe8\xd2\xf6\xee\x84\xe1,\xa8\xdd{*\x0e\x83zm\x1fCG\x91\xa1#y\x16\x95\x06\x8c\x7f8\x1aX\x90\x1b36\xf8\x13k\xcd\xfbI\xe8Z)\xf5F\xe3Ff\x16}\xbby\x0brh\xd2\xe0\x88.\xa8\xdf\xe4\x9a\xbf\x94o\xa4\xfa7~(\xdf\x88\xf5oh\xa5\x9c\x83R\xc8)TOf\xcf\xbe\xabK:\xa3\xcf\x01\x9c\x8dAd\x8a\xed \xf1t\x92Y\xc3\x16\xa0gza\xee\xdb\xa7\xc7\x05\xb9k\x9aEfG\xf2_j\xd8\xa2A\x0f\x0d>\x14\xab\xeb4\x04v\xc29\xa9\xcb\xa8`\xcd\xf4@\x8dL\"xa\xe5H\xd8\x01QZ6\x06\x01\x864\xef>\x84\x1c\x1e\x0d!y\x08\xf9\xf6\xb6\xa9\x11\x10\xe3\x08\xd1S8f\xa2\x15\xec@\xced+\x83\x7f\x15\xc8\xc5\xe6z=\xe2\x85\xa3\xc18@\xc5]8\xda\x1d\xb3/\x03P\x02\xdas\xd8\x86\xa6\x12\x0e\x1a\xe2\x97\xbc\xe4g\x8d\x87\x96\x04s\x0dV\x99g\x83tZ\xa6\xd9\x9f\xbcL\xda\x152B\x96\xaf\x9c\x0d0\x0c\x1b\xbfzV\x96B^\xd2\xf9\xc3}a%\xf0\xb7\xb7\xe11:W\x9b\x1b\x077u\xa7\xbc\x8cjOy]\xc2>\xc7\xcc\xb9P\x1f\xa9i8s\xfbp\xa4E\xbe\xe2w5\x94r}\x8e\xf4z\xa8\xe9\x93j\xbe,\x03\xb8\x05\xbb\x85?\x8b\xf0{\xf1\x03\x89\xce\xf2C\xdb\xc1\xf6\xcfbh\xff\xd4#\xce?\x85\xcd\xa0e\xab\x99\xa0u\xda\x02-\xaa\xaa \xb8\x8a\xc0\xd1WhIm\xceB\xfa\xa5X\xd6\x96BiC\xbf\x1a\xa7\xd4\x13\xaeV\x01\xf4\x9e\xf2(\xde\x8c\x92\x15\x84\xf0.\x8cO \x9c\xaca\x17\x83\x1eAX'w\x83\xea*\xc9\xba#\xb8V~\xa0$\x01\xe0\x9eo\xa2\x1a#.ax\x92\xa1\xeb!\x81G\x82cco\xef\xc4\xd2\x84s\x8c\xc5\"T\xbd\x1f\x89\xa7\x8aj\xf3\x18\x87\x86\x83U\xb1FE\x0f\xfc{B\xa2\x85\xe7\x11\xd8a\x04\xf8\x16\xc4L\xb4\xf2\x99l\xde\x0dw~+`\xf9\x9b\x1ew~\xfb6\xdc9\xd6\xeb\x129\xbe(*\xa5'\xa2\xfaa\xdd2ah\xf6\x84\xda\xdcL\xcf\xadO/\xc4S\xf5\xa1b\xc6\x1a\xfdc,\n\x01\x11\x8f\xd2\x00n\xb0\x95S\xe3\x1eN\x89SIW\xc9\xb5\xb3U`\xe4\x91\xdb\xb4KM\xfb\xe8\xad4g\xf8c]\x05\xf3J\x9f\x9dL2\x15\x7fY\xa5G\xe1![Q-\x95\x1e\xb2CH\xb9\x8b\xac\x11W\x84\x8a\x88z\xf1\x88Q\xae\x14v\xd0\xa3+\x1a\xa3\xf0\xc7:*wf\xc4P\xd1H\xb5\x1bu\x1d\xb4\x93u\xb3\x0e\xe9&\xaa\x9dBc\xf2\xfa\x89\xea56\xdd\xb45\x05\x10\x1e\xa3\xfa\xc3\xc6\x819i\\\xac\xda\x16\xaei\xa1\\\x02/Wf{\x9b\xad\xcd\xf6\xb6C\x14 CuB\x03x\xc1\xe8\xd6\xd5Q\xbd\xee\xe5\xaaC}\xae\x1f\x1eQ-\xcaW\xfa\x9e\x87\xee\xf1lJ\xd3\xf5(wM}\xa2\xeb\xdcX\xbcS\xbe\xb3JSU \xd8ju\xa7%|\xa7%l\xa7E\x0f!1+q\xcfDY\xbc\x14\x173\x82\x1dH`\x1f\x12\x83\x9e\xaf\xb63\xf31V!\xae\xee\xc6D\xab\xb45\n\xa3\xcd\x14\n\xd7\xb5=\x05\xb8\x8c\xfbS\x01\xa1qw\xa6\xad{8\xb9\x8e=\xdcm\x15$\xe4P\xd3\x1a\xfdu{>g{>w\xdb\xe3\xca\"\x8e\xa6\xe5!\x17\x8bC.\xd6\xee\x8b\xc2[\xc5a\xad\x19*\x96\x121\xaeeEhR\x84\x0c\x03\xf7,\xb1\xe5w\xafj\x96\xb5\xd4\xb02\xe8$\xbex\xb1A\x06-vq\xf4\x10\xb6\xbc\x08O\x05\xb5*#(\xb9\xbc\xbdHT]\x84t{[\xec*]\xfdR1\xe5F\x8e -LK}\xf5\xb5\x025I;C\xd5\xa0\xce\xf9\xa2j\x89\xf9v\xf9hh\xd6\xb0\x02\xdd\xb7\x1aQ\xd6\xa1E\xcb\x81\x8b\xc4\x9d\xd1q\x0f\xe0\xd2\x08\x15\x9e\xd3F\xf0R\x81\xf2\xe9\x7f\x01\xcaW\xea\xc8\x17$\xb0\x08!\xe0\xb6\xaa\xa6\x83\x80z\xa0\x14\xc6\xa8\x87\x0e\xcc[4J\xc6\x01#T\x8dC\xc206\xb6KbEK\xc4w\x89\xb1\xf2\xbc\xa4\x9b\xb1M\x9b\x84&\xb6Q2\xe6\xe1\x90\xc5\xd8\xf2\xea\xc0NR\x12~n.\xa8 \xdb\x1a\xc7\x96vy\xffc\xbb\xaf\xb6\xb0F\x82\xa6[l=\x10\xafc\xef\xe1J\xc0\xe3\xf2XmS\x18\xb6oT\x90p\xe3En\x8b\x8dkQ,\xf2\xa0<\xb1\x87\xb5\xafY\xad\xcb\x92\xfdMG\xee\x0c\xefZ\xd0\x805\xbd\xba\x8b]M\xd0\x86\x03\xe8\xbd#+\x12R\x18\x8d{\xb0_\xfe\xe2^\x10\x8aZh\x1bz\xe5=\xfc\x96\xdd\xa1\xd1\x92d\xd0t:^_\x9d)\xd71\xe1|\x08\x1a\x06\xbc\xd2\x8f\xac\xf4\xe3\xca\x85O\xa9\xaa\xf8jFe\xd5\x9a\xc7\x94\x05.\x13\xa9\xec\x1f\x06*#\xca+1{|\xaa\"U\xd2\xba6\xb2\xd7\xa2\xba\xe4\x0e\x0f\xa6\xab3\n\xf5\x91\xa6\xe4\x8c\xa4Y\x177\xed\x16\xb8N\xc9\xc5\xdb\xd9\xd5\xc1\n\x07\xa81\xdc\x19X\xbbY\x84\x19=\xba\x86\xaeJ\x0cm\xed\xf2\xea\xc2\xd4\xeeC\x88\xe1\x91\xb2\xc4\x10;i\"*\xc3\x8d\xeb'ZlUB\xc4Ns\xe9.\xe5tbU\xbb\x11k\xc9f\xc2#\x88%\xc5)Y\xa0X@\xc27\xd6\xd9\x83\xeb\x12?\x1c(l\x05\x9a\xc2H\xe9\x88\x87\xb4\xaaz\x87\x83&f*S=k\xda\xfb\x19}_\n\xfa\xbe\xbcf\xfa\x8e*cI\xde\xf9\x0f\x85\xbas\xed\xee6\xf4\xfa\xfd~y\x97\xc4S\xd8\x06O\x08\x15\xf3B\xcd{\x00=8YW>'+\xcc{\x84I\xe74'\xc1\xf2zO\x029\xdcR\x17 \xdfU\x87\xd28#\x96W:#$\xe7\xe0Q\xd8Q\xfb\xf6\xe1\x96\xd2\x9fq\x7f`\x80\xf4.7\xc8+d\x82\xdf`k\x84:\xf1\xd9\"\xd1\xd8\x1ejCv>wj\x87J\xd1\xa9r\xb8\xa0K\x01\x9e!\xe5\xd3\x80\xdb\n\xf0\x8c)\xef\xfa\xf0hX\xf8\x96.\xa9\xb7\x1b\xc0\xae/\x8e\xa7\xa5@\xeeSB=\xd5* M\x06\xec>\xd1\xdcG\x905\xcf\xae\xe5U\x0e\x9b\xb3\"\xaa\xb2\xb2B\x0d\x85/\x18\x031.\xc3\x1c\xd4r\x07V\x87\x03\xe1Z\x89N\x96\xece\xeeSa\x19((x\xba\x0b\x1b\x93s\x14\x1e\xa1qY\x8d\xd3\x8b\xe1_C5G\xd1w@\xfd\x87\x0c1\x94\x9b\x0f}\xc0\xd7(\xdcR\xdf\xb5\x12\xdcC\xea9\xa5J\x8f\xea%]\x145b\x99\x9a\xffg\xaax\x99\xeb1\x0d\x94UxEG\xd4\x9e(\xb7\xea\xb1\xf2\x96ao\x00o8\xac\xdf\x89\x9c\x19\x14\xd3\xe1\xc0+\x9e\xe8\x1c\x9f3*\x8e\x8d\xb3\x83\xef*Y\x16`\x9fw\xd6 \xc7\xe7a6\x7f\x9aLU\xc8\xc8[:\xe5bT\xaf\nV~\xe8\x08B3\xe3\xf9\x9a\xd6\\M\x11~G\xdccM\xadPji\xa3\xfe5\x1d=\xa5c\xa7/\xb7>\x1b\xc7\x0d\xa6\xc6\xfb\xa2\xea\xc1\xfa(;\x8c\xf3\xa5\x08\xc0Bw8\xdd\x13\xa7\xb1\x98:k\x07\xaf\xfa\xb5p\x98\x8c\x93)\xf9\xb0^\x11@\xd2\x9e\x9dG\xbc\xfeYq\xbf\xad)vM\xc2\x8c\xc0`\xbf\xf5=Ph\x7f?\x8f\xa3/99zf\x9e\xa3\xbc\xb0\xf9\x07\x1d\x9b\x9f&\x13\x0c\x18>\\\x10\xf6\x0f\x9fl\xedf1\x06k\xd3z\xa56\x88-\xa5\xac\x96\xf6=\xfd\xd7l\xb9\xb6\xb7?\xd0@=\xfan\xc2\x07\xbe\xf7?\xe0\xde\xb7\x84\x88\xbc\xa6>\xc3\xfa\x8c\x18=\x1c\xc1\xc1\xd1\xb5\x8aB\x7f\xc8\xfa\xc8C\xfc\x81.\xcfu\x8f\xc1\xde\x9b$\xde!<\x95q\x19H\x98A\x98\x12,\xfa\x86\xd9\xb5\xc9\x14\xc2\x0c>\x93u\xd67\xd5=\x90\xdd\xb3\x0d%\xa2\x8dy9\x89\xd2#$\x80\xa7\xd4\x14W\"/R\xec\x9b}\xd8\xb2\x04x\xb1k\x92\xc4\xb3\xe84w|\xfb<\x8d\xa8\xdb\x9b\x82O\xd7/>\x80\xb9\xa4\x1e\xa8\xe5\x0d+N\xf5\xddH\x86`\x93\x95H\x12\x85\x83\xd7}\xe0\x1b\x1b\xb2\xab\xdb\xd4K\x95\xb5\xdd{\xee\x87\xab\xd5b-\xd8xCD\xbfz]\x06\x162\xc9\xce\xc0\x16\xc8\xb6\x13\xc1\x8aSzI\xf2\x1ax\xff1F\x08\xd1\x042B!\x84\x98\xed\x83\x12rr\x8c\x90\xc4bOXQ\x9f]T\xce\xc1<\xfb\x0e\xf4\xc4z\xeaw:\xed\xa5\xf2\xb5 k\x8caP2\xdah\xf3\x01\xd4\xa0\xc5\xcb)\xb3&y\xfddT\x93\x96\xa5y\x18\xf7@\xa6}G/\xd2\xb7\x06\xde\xbeP\xc7\x10\xce(\xa9\x16\niiG\x03\x05\xbep{\x00\xdf\xf1T\x85\xfd\xc9\x829\xf3Ld\x15\x16\xd6\x97)\xdc\xbdu\x9d\x11\xfcW6_r\x85\xa7\x92\x01\xeau\xb82\xa6<\xfb\xfa\x8d\x96\xc5\xe34IJ\xcd,\xfb\x81\xa2s\x11K\xc3\xf36\xf9:\x93b\xa5\xeb\xacS\xd7\xffP\x93B\xd9\xe7\x94\x11z\x14wh\x1a'\x92\xaf\xa6!%G\xf8\xf22h?c\xcd\xdc\x92}p)Y&g\xed\x92\xb6f\xd6K{\xc3S\xb2 l\x02\xaeM7f\xed:\xe5e\xd7)\xf3N\xea\x0bbO\x1c\xcdE\xc8F\x89\xcb\x03\xe1\n\xe2K\xe3L1\x81\x11\x1d\x8bF\x1d\xc6\xd2D\x0f\xc3h0\xd8\x15\x9d\"E,&Gq\x8b\x8flA\xa2]\x12I\x9c\x898P.\x80-\xcd:\xd1\xbc\xd5\x17\x8f\x91\xbb\\\xf8\xe1\x99\x89\xe2\x99H\x19\x93`\xf0Hk\xc5\xd8\x0c\x86\x10y\xb6\xb2\xdcb\xb92\xbe\\\xc2Y\xb7\x19C\x06F\xa9\xe3\x94z \x03\xb2\xc8\x1b\x9c\x11\x1a@/\x8ay\xb5\xfb\xcfd\xfd3V\x883Cf\x82%\x80-\x1e\xa8\xec\xa5\x99\x98\xf2\x92M\x19\xa9\xd5\x84\xed'\xf3\x07X\xa0\xd4\x9b\x95\x0bhU\x94r\xd6e&f\xcf\x7f-\xd9/\xb1\xdb\xbd \xc3W/)y\x19\xe2\xe3\xd91 `\xa1\xe1\x01\xc4\x9e\x8fc\xd4\xe9\x1a\"\x1eE\xdfi\xd1\x9b\xe0\x9a\xea\x96\xd9\xfa\x0e\x98,Hh-J\xa44\xdet\x8b\xa1\xdc\x1fB\x1c8\xc9yL\xd2\xa3gp BaE\x0c\xe3n\xa0\x9e\x14CQ\xb4S|\x83\xc1\xfb\xc3\xf2\xac\xe0w\xc3\x05\x15\xf5N\xb6\xc4M_pw\xd6\xc9,Iz\xda\xaat\x90\x90\"\x02\xae\xb2ks>\xc0f\x1f\xbfF\xd5\x92c\xb6\xf3\xa4\xe8\x08\xfd\x97\xea|\xd2\xa0\xe9\xc8\xd1\xec\xaeJ\xa0\xec\x86pM\x0fFl\xa9\xd2L\x12 \x84\x03\x07\xad\xaf\xf8\xde \xf0\xf3e8\x90\x7fI\x1d\x0d\x12\xd5}\x88Gj4^\xb3\xa8m\xcb\xf1\x81M>#\x18,\xdbi\x9d#\xd2m\x8dY\x1fN\xeb|%\xd0\x17\xc3J\x88\x87b\x85\xe3\x88\xfe7\xa2\x02\xae\xd6\x81\xfa\xebzQ\"KR\xea\xca\xe7\x1c\x11\xef\x17R\x98\xfd\xdb\xdb\xfda\xdd\x81uT\x1b'\xed\xedWd\xa0\xd6 \x14\xb2\x16[\xa90{\xcdu\x11:\x06@.)\"\x16\xe9\x9f\x87\xd9\x13NO=\x1f\x8f\xa1\xe3c\x12gyJ\xde2z\xedU\x89\xb7d\xa5\xac\x03/zw\xdc\x83\x8d\xf3\xa1zn\xa8\xa3a\xa2\xd8{;\xd8\xc2\xecHjb\xba\xf5\xaf\xf6\xd3\xb22\x05\xc8\xba\xf5 \xce-k\xdb\xdd\x1c\x9c\xa4F\x84\x9c\xc3\x0dw\x99\xa7\x93\x17\xda\xb7:1+\x87{\xe1m\x83r`3\xb3H\x0b\x11\xe1\xc1v\x1e\xc1\x043\x043\xca\xe8l\xee\x01/\xfb\xd4\x02\x01e\xb5[\xf7\x96\x9cI\xc9\xe0\xe8\xb0\x15\x0e\xe0\x9f\xb4dmT\xb6&(\xf3: K\x83\x1c^\xad!%\xf7\x83\xca\xe0\x0c\x04\x83\xa3\x99N\x941\xc9}\x08\xcf5\x9eC\x1fi\x00?\xd0f2\xe0\xd7O~6TO\xfb\xc2\xdeV\x81dR\x0f\xfenN\xfc\x81\xc3oNH$*j\x18\x1f\x8c5>\xac @\x0c\x9d\x9cDt\x89\xe0\x90\x90\x8f\x13\xee\x82\x1c;\xf5\xf9\xcbU\xfa\x9c$yL\xaf\xdc\xe5\xcb\xabt\xf9\x99\xac\x7f\xe4L1i@\xd7\xad\xdb\x17\xd7\xd7\xed\xda\xb9\xd3\x1b\xed\x9d\x1eS^j\xb4\xdc9E\x84M\\\xfa6\x87\x93\xcf\xc8\xbc\x14\x14\xe5'\xea\x89_n\xda\xd0\x1f[S<\xf2\nH\xa6}\xac\x0b\x025!\x0f\xad\xa9,$fGAA}\x10u\xa9FM\xd1\xd4Q\xf8X\xe4\x0c9\x84\x08w\x9bN_a\xc0G\x11%^\xe8\x97\xf8\x82\x06\x10Zy\x15&Qq\x89\xcd\xd3~\xba\xcf\x10Q\xac'e\xfc\xc8\x85\x17\xfa\x01\\x\x0cU\x18\xc4_\xc8\x1c\xae#\xf6\x99k:wB\xec;\xbeVy6\xf74\x9eEF\xf2\x92K\xa0En@\x8e\xac@.v=zm\x95j\x95\x9b7\x01\xb3\xb0V\xd4+<'c\x91\xd8\x97o\x7f7\xce<\xb1\xef\xeeR\x9433\x15\x002\\\x0cu\xf8Ue\x1a\x8e\xb7\x92\x8c\xba\xf2\x9c\xab\x84\xcc\x9ax<\xb9\x8a\xce\xadjx\x9e\x8d2\xf2\x85\x1e>jY9\x13@r\x97e\xe1\xdb\x1c-Cq\x7f\x16\xb1\x93\xc1\x01\xfd\x8a\x8f\xcb\xc4\xb9\xcdA\xfa\xbeb\xedb\x07\xb2\x9af\x17\xe9jy\x8am\x18\xa9\xc0\x94\x87\xca7W7\xb5\xa7\"\x1a\xaa\xf8\xc4\xb6\xe2\x80&pq\x1e\xa5U\xabi\xab\xf7pE\xfe^\x8a\x1a\xa3\x08x\xec\xd2\xf8\xad\xc6e\x02o\xabA0\xa6\xa5\x93\x17\x95n\x19\x86\xf4\xb1\x97\xd5z\xd2\x05A\xc3\xb2\xd2\xf1(\x1a\x17\x0e!\x9a\x81bf\xf2\xca\xd1\xe7\xc5\xa3]G\x89#l9iA\x84\x86x\xf7\xef\xde\x7f\xf0\xe0\xf6\x9d\xbb\x0fx,\xcf\xce\x10\x03ax\x1c\xcc\x9d\xdb\x83{w\xef~\x7f\xef\xae\xef3f\x0f\x1f\xec\xc1M(\xbeQ\xee\xdfa'\xd3\xde\xdd\xbd{w\xee\x0en\xdf\x0d\x80\xc2\xb6h\xea~\x00\x83\xbd\xefy\xf3\xf2\xde\xe0\x9e\xdb42\xe2(\x85\xa4\x02\xc5\x0fm\x15E\xa3\x11\x19\x0b\x01\xa3\xd6\xbb\xfa\xeb\x0b\xba\xba\x08\xde\xec\x0b\x15\xe6p\x18\xb2\xbf\xb9\x15.(\xffD\x9dz\xf1\xd2Q\x1c\xc0\xef-N\x11\xe6\xb9T\x0eCUz\x17\xc7\"g.\xa2\xf2X\x84G\x90\xf3\xd3\xd1HH\xa7\x88\x9e\xd1(\x193\xd4)s-\xb2\x1b\x03\xe7R\xe6\xb5Y\x19\xcd\xf0*\x1fi\x9d!\x16\x1b\xe1;6\xc0\xd3\xb9:\xdd \x9f\xee\x0c\xcfc9\xdd <\x02\x8cm\xda\x9abB\xe0l4\xc1I=\x84\xc9\xf6\xb6\x81![\xc0\x90\x7f\xa7\x17\xc8\x16p\xc0\x9b\x19\x8cq0\x11\xec3\xeeWQN\xea\xbf\xe3|\xb0\x17\xa2g\xd4\x02]\xc9.\xbc\x84IQaIH\xb3\x96\xec8\x18\xc4\x81\x0e~[!\xfb\x7f\xe1\x9a\xf0x\x08\x13]\x98\x8a\x15y\xe4\xc5\xa5Z\xe9\xb1\xf8\xdebp\xaf\xa0\x9b\xe0\xfah\x00\xe8\x88\x1a\xc0\x88u4\xf6+\x1c\x19q\xe1\xc8\xe4%\x9d\x0d\xc8\xc8\x94\x00O^\x11b\xb5 \xff\xb4\"\xa2\xe6\xa8h\xc9\x8d\xd5?@\xcbE\xc9K\"\xbb\x9e6\xb3\xae2\xabQ\x9eMa\x05\":LQ\xf0J9\xd3\xd81\x93\xf7V\x0c\xb7\x90\"em6\xff\x03\xe4\xaf'\xc2\xf6\xbf\x03\x038\x80y\x7f\x95\xf0J\x10\xf3\xd1\x84Q\xa3\xc6\x8d\x11\x1b9\xe3\xc7\xe7\x9c\xc1\xe4\xbf\xfd\x00{\xf6j\xda\xbfyi\n\x97\x02s\x00\xf36\x96\xf42\x80_\xafL\xce\xb4\xd1e\x88]\x86\xcd\x8aB=\x13W<\xafZ?\x9cG~R\x94}\x0c\x9a\x91D\xd2\x10\xae\xe95\x126\xd60\x93snr\xee\xae\x08\xcdF\xe5\xec($\xfc\x11fF\x1e\xf38..#\x11\x1d;Q\x07\xcf\x95\xe9b%3\xb4L\x00\xfd\x84z\xa9 T\x8a\x80H\x04\xcb\x13#\x90\x88E\xaa\xcc$|C\xfd\xf3I\x15\x86\xfa\x97f\x18S\xb95\x04o\x027A\x87\xdaH\xd7\x90PGue\x8e\x96\xa0J:\x1d\x12\xde$\x02_\xdf\xf9J\x8e\x10\x97K\xff\x0e\x1a\xdd\xe1\x00V\xa3\xc5\x18Z\n\xb1sE\xd9\x9c\x9b\xc5\xf8BW\xd7J?;\x1e%>w8(8\x1c0\x94|\xa5\x90\xf7\x99\x95\xbc[\xdc\xbc*\x15\xbf\x04C\xc0\xf63\xaf7\xb3\xf6\x03\xc4\x8c\xdd\x87\x82\xd5\x8f\x1fB\x88i~\x18n\x0ca\xe0C>\n\xc7\x88\x067Q\xb3@F\xc9\xf6\xf6\xd8R\xb3\x0e\x14\xa1t\x94\x8e\xb9\x8a\x8b\xf5\xc8M\"\x98\xe3A\x1f\xcc\xcf\x1e\xaf\x02\x98\x04\x10\x0605@R\x9c\xe7\xec\xffj\xb9z\xb5H\x7f\x93*\x11\xb4x\xb2\x04\xb6\"\x12\x0df\x81c\\\xeaWxS^q\x0eRQp.W\x88?{k\xe03V4\x1fc\x9ck\x0e\xdb\xc6\xd4\xb8\xd0~xs\xa8iA\xd6\xc2!\x15\x1c\xb6\x84\x9a1M \x14\nu\x84\xda\xb6@\xaa\xa8\x84\\!P\xb8\x80.\xa9\x80\x8e\xab\xd6\x10tb\xcf\x86\xf0\x08\"\xdc\xb1>\xbb%h\xbb\x97\xf0-\x1b\xf3\xd7w\x06\xa8\x9d\xe5\xf7\xe8(\x84m\x97rn\x86\xc2\x1f*\xee\x19\x8f\xcc\xe3\x82\x9d(\xac\xa8'5\x93\xe6y\x95\xbb\xe0&\xda\x93\x00\xce\x1b\xe7\xe5/\x7f-;aa$Z\xf8\x08\xce\x10Df\x11)\x81\x03Ht,\x82\xceo\xf2\x97\xffel\x82\x94\xcd\xb4/L\x1cNa\xc6&LF\xa1\x81Lg<\xf8\xc6\x911\xa0\xc4\x9bu=\xa2\x85#\xadC\x0f\x05O\x81\xf6z\xc3\xb1\xd2.\xc3\xed\xec\xac\xe0\x11,\xae,\xb7U\x08\xecn\xa0?\xe0cy\xc0s\xa1y\xc0%\xe5R,c\x14d\"\xce\xfc\x0c\x1e=\xc2#\xbf]L\x9b\xa1\x98\xa6[\xac\xca\x9beT0\x1e\xb3!\xfe\x89\xb4\xd1\x8b`3d\xc2T\xce\xf9 \x06yc[\xad\xf2ZIB\"-k\x01\x92\xbd\x98 \x87\x11\x1a\xcd\x8c\xab\xedm\xfd\x9a\xcf\xbb\x9e\xf2\x8cS\xcc\x88\xc7\x99\x99\x05\x93\x9c\x8cta^\x90K\xe9\x00\xb2\xaaQ\xcbi\x95ZrNj\xc5\x98\xa4:\xd9xyej\xf9\xdf\xacKz\xf9\x9f#\x86\x82\xae\xe9wy\\\xe6Z\x14\x86\xbab\x8e\xa1\x92\xc0\x8f+\x7f\xb8\xbe'&\x8a_\x1d\x0eZH\xe1\x9a1\x14K\xf2\xff }WXr\xee\xb3\x8a\xd5\xf4E\x99\x97P\xc0\x92M\x80\xb1\xee\x13\x93\xf1\xb4\xb3\xa6\xa5]\xcb\xf2\x1f\xd4\xb0\xbc\xd4\x00`\xde\xd8\xe0/\xae\xbc\xc1\xa5\x18\xc3\xa3B\x0b\x9f+\x86 2\xa2\x8e\xdf\x18\x8cu\x0c\xc9\x8b\xeb\xd9\x835U\xaev\x99\x90\xe4!\x06W\x87i\\./\xc3\xea\x19\x05\x12(\xf3\x08\xfd\xc6F\x0ce\xc0\n\xc3H\xd8\x87\x0c-\x01Z4\xaa\xac\x1a\xb68,\xca\x10\x89e\xd3\xe1\xadXv\xde\xa5f\xd7#\xd1)w~c\x91+\xba\xf3\xd2\xb9\xf6\xa5\xfeve\x0d\xac\xa4=n\xd0\x91\x94\xd3\x91\xa8V\xb6\xe8!\xa4\xa2\x84L\xea\x94\"9.\xea\x97\xa0\xe7\xc1X\xadwY\x9f\xdc\xaf\xfaY\xfcrm\x93\xe3L\xa6\xdb\xd4\x0c\xbcN!|\xd5\xe6\xa5\xe7w\x18(\x12(\xb3\xcf$\xfdJ9\x06\x13,@\xa7=}qE0H\x8a\xac\xa0k\x03\xad\x88w\x83\x06\xf0\xd5\x0f\xe0\x86\xdaKL.ZS;\x14P\xa6\x12\xca\xe8_\x19\x94A\x02\xdc\x99\xf2!\xd8\x8b6\x88\xfa\x13\x04\x17\xc9\xac\x0e\xc7\xd4\x98<\x0b\xaa\x8e#\x03)f\x8b\x89Z8\xd6\xa8\xa8\xadZ\n\xe1\xdcg3\xd5AI^\x97en\x9bT\xee\x96\xb6n\xb0\xbe\x99\xa8b!>Q\xf0\xce\xd7v\x1f\x91l\xc4\xc1'\xddS\x0f\xb0\xcc\x1e\xafy\xd6:6\xb5KD\xfbj\x87v\x95FR~f\x19\x83]\xd1\x91\xb4I\x0b\xf8\x92\\\xa6\n\x00\xe4]\xbb\x0cQ\xc3/\x18\xc2O\xd4K\x8c\xf6s\xb0\x8a\x0b\x93$\xa6Q\xdc\xa9\xf8C\xb3\x7f\xe5W\x9f\xfb\xcc\xb6\xecj(\xb7\xa7ic\xb4\xe6J5\xe6I\xad\x11\x90*0\xd9*c\x1e\xea5\xdc\x82;\xcd\x96g\xf2\xd9^\xf3\xd9\xa2\xf8\xce\xe4\xb9\xbf2x\x0c\x9c\x89\xd8\xa1\x0bc~=\x87<\x96\x9a\x88Z\xf6\xe5\x9cxJ\xcaI\x8d\xf0-O\x82\xc8\xa3\x96\x0c\xa3\xb1\xbd\xc6\x03\x1fL*t@\xde3~\\\xa7\xf0\x98g\x8dN\xe1\x11\xac\xe1\x00\xce\x89\xb7\x8b\x0c\xcfY \xe2L\xb1\x10\x04\xf1\xe2>M\xb8\xfc\xedcYZ\xd2\xd9-\x06\xfdD\xdeG_ \xf6\xacI\x03\xd2\xa6\xe9-4\xb5-\xfe&:/\x127O\x8b\xb9\xddaD\xc9\x032%-y@\xd8ArN\x19\x9bL\x1c\xf2\x80(\xc2\x87g\x8e\xb1\xe49\xbc\xc4\x11\xf7\xad9-^E\x19\x85Q/\x80\xde\xb8\x99\xd4\xa2\xd2\x93cR\x8bH\xd6\x8a/\x93\xe2\xfbEVrZ\xcdJn9M\x99\x00[\xb0\x96\xe8+\x83#O\xd2\xe842y\xb6I\x99\x8b\xf5\x14\xf7y\x99P\n7\xe1T\x13\ni\x02P#\xbbF\x05\x06\xdd\xb2k\xb8\xda/\x10d\x84\x83\x8c\xb3U\x95\xaa\xf9&\xbfo\xf4\x0d|\xac:\xb1\x11x\xa4d\x83\xed\xee\xb2\x06x,<\x82]8\x80\xb7\x82\xc7\xc3m\xb6+\"L\xdfJ\xa7\x04\xb4\x00\xf0gD\x1b]\x06`N\xb0Gp=\xe5b\xea\xdf)\xed9\xc74\x8c\x16v\x86J\xba\xf7\x1b_J\xac\x81\x02\x08\xc5\xcf\x18%0 W\xe1$\xa2kn\x10\x1f\xc2{t\xc2\xabG\x0dpy\x10E\xac\x88\xbf\x14\xd5^\xa2\xfd\xe3\x059#\x8b\xf2]\xf3\"n%\x8e\xe1\x06Q\xfa\xd0Z\xee\x00\xf8\xd8\xd6\xba\xd0\x13\x8e\xc6\xec$\xd3w\x13 \xbf\x0b\xae\x8a\xd4\xf7\"\xaa^\x98)y\x0e\xea(F6\x03\x16\x16\xa9\xcf\x19\xdd\xca+`F\xd8\xc2\x0e\xea8}\x1fG\x83o%\x15P5\xa9\xb2v\xc0\xdcJ\x169@9\x84!\x1c\x96\xb9\xb3\xf4\xf3\xdfJ\xf4*\x95\x8a\xe3\xc4\xeeC\xc8\xb8\x8bi\x86~\x92\x02\x16\xd9\xb8\x10\xbf\x8c\x049B7\x91\xb0\x80\x1e\xa3\xf1~\x00a\x9d\x82ip\xf4\xc9\x8c\x92\xc6\xf1\xde\x8a\xa2^\x15G1\xc8\xf8\x1b0UX?Q\xa8oA\xd8\xc8\x8e\xb0\xfaN\x9cp0\xa9\xe2\xa0\xc9\xa2\x848\x98b\xb2L\x86]*\x185(\x88/Ez\xc8\xa0\xf1\xab#r\xca\xcdbE9\xd1d.z\x13\xca\x8a\x08\x95|\x81\xf0k\xcb\x8bi2&\xca\x0f \xaf\"K\xf3x;%\x01,I\xc0\x98\x06[\x1a\xf5\x13\xf3iU\xf2\xea\xf2\x10\xd7BX(\n\x8b\x93]\xbf\x0c\x80J\xbe\xd4\x165\xc3\x0f}3|*\x89D\x04\xe3\xb0\xeb\xd7&\x06\x95\xb8g6\xb70\x00\xa3\x8d\xb5\xa2\xc7 +\xe5\xac\x0c\x9e&\xf2\x92\xc4$\x17\xfeK\x07\x12\xc1\xf8\xf1\xbe/\xa3\xdc\xf1\xa7\x99G\x05\xe1\x97\x92\x8b\xca\x87\xbb\xe8\x19\xbb\x03\xb9\xfd\x93 F\x9a\xee@n\xe0\x1b\xf1\x95\xc7\xb0F\xdca/\xdb\xec\xa1\x02\x08\xad<\xbc\xbc\"t\x9ce\xd3\x9e\x14\xfb\xe1\xd8Rt\x04\x14\xb5\x04V{\xdc\x99\xc0>\xa3\x9a\xf6OD\xcb\xe8\xd9\x15\x8e\xa8>W\nh\xb7\x1d\x80\x0c\xab\xab\xbb\xe5G\xa89nYV\x11 \xea\xbc\x80\x13$/\xd5\x05L\xe0\xf1c\x88\xec\xdf\xcd0\x00f\x9b\x1d\xeb\xf2\x03\xcb2\xcd\x8a\x05\x9d]\xf3\x82\xe2\xb9\xf6\xd0\xe8`\xa1^l\xed\xb5\x19]tW\xa1\x8b2 }\xf5+\x12E\xf6\x98\xa8\xd3\xa6\x90\xaf_\xa1P\x85\xb6\xbel\xb6\xe3\xcb\x8b\x0dcR\xf3%lCpP\x08&G\xf2\x19\xec\xc3\xa4\x0d\xc9A\x8c<\xe7\xae\xe8\x19f\xde\x8f\xf8\xa1\x940\xd4\x88\xd9\xa9\x1d\xf9f\xb7\x04\xb0N\xc9\xb27\x90.6\x1e\xbb%\x948\xd7&\xfb1\x1d\"a#;\xd7\x99E\xa3\x10J59;\x9b\xd98UU9\xfeTT\xe5\x04oH=y\x8c\xbf\xca\xacGa\xa1$\x8f\xf0\x87\"5&\xfc\x86\xd0\x97\xe7\xfcW5\xb9W\xe8\x04\x8a\x0bb\xd3\xa8\x9d\xa2i\xd0C\xc5\"\xb7\xeb3\xf1\xcd\xd1\x14\xfe\xbe e\x13\x88s\xee\x8f/\x92\xf3\xd8c*(w\x9a\x7f$\x89\x9bT\xcc6>@^\x18\xf1R\xf1\xa5\x88l\x1b\x93\xb3\x9c-\x9c\xdb\xa4F\\G\xa1%c\xce\x8c\x9b\xf8&\x1c\x0e|cHXX5I3~B\xc9\xbcQ\x9ed\xc3\xd0\xc6[t\xccXi}\xd8\xa0iE\xb3\xea\xc8\x8b\xe3\x9f\x96n\x99jWA\x05v\x1c\xf2(\xec4xK8(nJ\x13Y\xae\x8e\xb3\x19\x83`\xc2\x9bC3OW\xa8\xd9\xd0\x1f\xa0\x88\xc1\xa3\x8ag*\x15\x1e\xa8k\xe2\xf1\xfc\\\x82-E\xae\x94\x8d\x8a\x89\x97\x8d\x02P\xfa\x91<1\x8f\xa4\xb0\xa0\xd7l\xbf\xaaeU\xcf\x0f\xf2/\x1fq\x81F\xb2\x82\xb0\x0dg&\xa4\xab\xfarJ&R\xf0\xad\xf8\xf5C\xee\xb7\x80\xae8XXuX\xf80\xf0P\xad\x14=\x19\xd8G;C8\xb3\"^[\x99wcE/k\x92\x1e%\xe8EF\x9d\xf1r\xc7\xea\x13\x19\x7f`(o\xac\x98\xf5\xd5t;\x98\x9f\xc1\xcc\xb6\xb7\xb0\xff\x89\x0b\xfb\x8f1\x1e\xb0m*\xce\x10\x1623bc\x8c\xdc\xf4>\x9a\x8dv\xf1\xefm\x0c\x19c-h<\x16\x18>\xe4\xf5\xfd\x95\xb4\x91\xa9\x9c\xe1\x9e\x12s\xc0\x0d\xbf:N\xa5\x1a/Q\x88\x1e\x13\x15\x99f2\xe8t\x1bfl\xd4\x0f}|.\xf6\xd1\x84\x8dkR\xdd\xf1\x070\x92\xc6\xa3\xc9X\xec*&\xd8\xcd`[f\x1f\xc8\xd8\x9fg\xba\x11q\x99\x90=\x9e\x05\xbc\x8c\xfa\x8c\x1d\x00\xfc\xdf\x04\xff\xb5Md\xc1\xa5\xb1\x04#\x08\xf0\xcf\xd0\x7f\x08+\x06\x11\xec9c\xbb\xc9i\n\x95\xa1\xf3\xf1\xea\xf1n\xde\xe6N2\xc5 \x8aG\x18#\xc1\xc9F\xc8%\xee}60\xbc\xad\xa8\xb70\xba\xd1pda\x905\xff\xe6\xe6M\x8c\x03F\xd1l^SA\xb4\xd0\x8a5F\xb0 !\x9f\xf0\xe9-a\x08\xd9CX\xc2c8c\xff0J\xd0&K\x1c\xc3\x10\x16HA\x96z%\x89\xbcXwkAr\x8e\xc7\xbc\xdf\xf2\xb71\x81\x94\x9e\xbf\x93\x1f\xf2\x9e\xcf\x90v\xc1\x10\xe6-\x94 $\x83/A\xe6\xb1E\xc1(\xf6iEq\x92\"\x1b\x13\xfax\xd6=\x1e\xc2\xca\x87\x9c\x81c\x85\x8b\x86\xfff\xdcmaR8(4\x9a\x12z@\xde\x96.|\xb2pGf\xc2q\xc4(\x15\xe2\x87u\xe5\xc4>\x9cX\x85\x19\xb60'\\\xe8~\xfc\x98\x1d\xe8\xb6\x85a\x038A\xea\xba*_\xf7\xe1$%\xe1g\xf3W'BP\xdb\x1e\x82\xc7\xb7\x94\x0f\xdf\xc1 n\x92\x9d\x022b?\x8dN\xf4\xc2\xad~q'\x1c\xab\x1f\x0b5\"o\xa7\x0e\xd2\x8c\xad\xcc\x0e\xcc\xd8\x12M\xf8~x\xc4\xf7C\xe5\x83b93F \xc4\xfb\x92\xba\xec\x08\xaa\xb2\xa3\x8d\xa2\xec\x9c\x924D\xb5Fy\x9cp\xb6\x9bV\xd8\xf9\xb0\xd4\xed\x00\xc6q\x96\xeeU\x13\xd5\xbdj\xea\xea^\xc5\xc8\xc49\xf1r.\xee`\xa4f=\xba\xd1p\x1c\xff\xe1\x96/2U\xf3EV\"\xe8\xcb,k\xa1=\"\x04\x93b[\x99\xe0 Z\x01M\xe9{&\x1c\xc2\x8f\xc5\x9eMp}E\xa5\xbf\xdc\xcbxJI\xbe\xea\xd7\x9dR2\xe5\xf1h\x93\x0e\xe8\x91\xc0c\xe94y\xf3&O\x10Uz%'HR$\xe4\xebYn\x0c+\xf5\xb9-\xc5\x1cw\xab\xdeE\xa5\x9c\xd4Y\x9f\xb1My\xe6\xd4\xfe\x91\xbd}k\xa1\xc7\xa7\x9ce~M\xca\xfa\x8e\xecVg\xbf\x9b\xb3\xff\xf5\xf5\x1d_\xdb\xa1X\x94\xc2\x9c\xd5\x11\xce\xd4\xe0\x07\xd7\x94|U\xd5\xc3\x91bT1+!\xca\x14\xe1(\x02\xe1\x8f}\xb4\xdb\xf7\x8fy\xea \x9e;|\xc1\xed\xcb\x0e\xb9\xc3\x9d\xe6\xf4\xd4\xaaLXre\xc2\x92\x8d\xeb\x03\xf1xu\x9b\x0b\xe25B\xfd\x0c\xad\xffl\x970\x84i'\x90,\xbd1\xf5R.\xf8\xe0(3x\xfdb=6LIA\x0c\n\xff\xac\xe4\xf8\xd9\xd1\x1a\x9aT C\x9e\xb7I\x8f\xb7\\?\xd1\xa6(\xcc\x05y\x1cr\xedi\xf9s\x0f\xbe\x83D:n\xa2\x8d\x88\x1b+\x9b\xc9O\x0d\"\xac\xbcD\xff\xca|\x84\x8a\x05\xa55\xc3>\xf2\xfb4yI\xd6d\xfa\x9e|\xf1\xfc\xee\x94\x99\x8ev\x0d\\\x83\xdf\x9f-\xa2\x95\xc7:x\x1d\xf2|:\nn2\xa2\x9bVp\xb5\x8a\xb9\xaa\x933:\\\xa0\xf1L\x96}c\xd4%\xc2\xc3\x9c+1\x14\xe7\xde\\Q[0\"\x12J\xd1T\xa3\xbcTb\xcd\x8c\xb6\x99\x12\x01rD\xa5\xd0\x1f\x0d\xc6m\x8b\x9dr\xd5\x1e_G1\n\x9ej\xdd8\x08>?\xe1L\x9fK\x12Z\xb6\x90\x8bB)\xa2\x19#\xc90\xf1=\xa9,\xb4\")\x07\xf7\x0d\x17\x94#\xd2s2\x0c\x8c\x1f\x90\x93s\xcc\xbc\xfc\xae\xc5\xeb\x04\xdd\x95\x14\xaf\x93\xe3<#/\xc9:SJYH\x8a\xd7L\xe2k\xea\xf4\x8d\x81\xa6k{\xec\xde\xfc\xab?\xb7\xf9g\x7fn\xf3_[\xe2\xd8\xfeAl)b\x89:\x02R\xed\x9e\xdd`[\xbc\xcd\xabSi\x8e6\xb1?\xc0b\x8e\xb2xIkCgE\x99d\xf1\x91\xac\x7f\x86\xdeg\xb6\xbe\xdd\x07\x0b\xean\x12\xddx\x06F$\xd0U\x14as\x9a\x87Y\xab\x1b*\xa8\x1dE\xf1d\x91OIV\xafj_\xb4(_\xe8\xd6\xec<4\xb78 's\xf2\x8ed\xf9\x02\xf9\xdf8\x00\xc5\xa3\xf0c\x8c\x8f+e\xbbl\x11L\x85ZO\xebL\x01U\n\xd5\xa8g\xe5\xc8\x18\n\xafC\xf4\xb5\xa7fu\x84\xb1\xd8\x95\xe2\x9d\xdau~\\\xdf\xcb\x0e\x82wmR\xbd\xd4n\xca\xaex\xbbf1]\xb2\xf0nN\xac\xf2\x92v\xcd\xd4Z\xbeV^\xc8\xa5\xd0\xd6:\xb6\xf2*\xf7\x19\xba\xb9\x8ev[\xb2!\x01\x86u\xcaw\x95\x0f\x07\xe3@\xf9\xbb\xe1^X\xbf\xecfQ#\x19\x91\x97)\x8b\xb9\x1b>\xb2\x95\xc2\x15\xfe\x99\xc9L\xb0\x0f?\x1b\x11\xa9r\xd3D{\x9f\xb7s\xba\xad\x148\xad\x13\xdd\xb4;i1\xd3\x80\xb4\x1e\xd2\xe9RT\x99\x97%O\xcd\x85~\x0b\x19{(r\xd0G\x18&\x8c\xbe\xf6\xbc\xc4N\xaa\x15\xedp@V\x02\xe44\xbc\xab\x12\xa0\xa8\xc5\xd9\xa6J\x83R\xaf\x9c\x91\xfcXX\x04MD)j\x99\xb2\x9e(9\xcdY\xc5\xe1w\xe6\x14\xce\xdd)\x8d\x14_\x93V*\x83\x8ev\x82\xc0H\xf9\xd5\xfc\xf6\x99\xf0I\x8b8m\xb0\xbb\xa8\xa0o\x82\x95\x06I\xf9\x9dA+\x0c\x14d\xcb\x91\x02\x85\x0c\xdf\xb4\x0b\x00\x06uB\xa3*\xa2a\x8f\x7fl\xf7\\\xb3o\xf0Xe\xb1\xe2\xfan\x8f\xbb0G6.\x8br\xf6\x07-s\xce\x9c\x90<\x05\xbe\xeag\x00*w\xd5a\x9c\xa0\xeeE.%\x9a\xb6\x8c\xae\x8c\x07\x83J\x8dl\xd9\xd2 \x16=\xa1&@\xe4}\xdc\x19\xc0\x8e&\x855\x08\xee\xa1Nc\x8d\\A\x95\xc6V\x1a7\xb4|56\xae\x85;\x8c5\xbc\\\xac\x8f\x0e\xf9\x8f\xf3p-\xc5H.\x03\xd82\xc1N\x1f[d\x9b\x91\xf6\x8c7\xf7\xe0\xb4\xe5\x7fpU\xf9\xb5\x9c\xec\xb8\x19\xa3:\xaa\x19\xf1\xf8\xacH\xd4\xebv\xfcFxL-Y/[[%A\x8c,\xa7o\xf4\xe7\xb2\x03\xc5x\x9a\xbc\x80\xb0\xb5kJ\x0b\xf9\\\x87ia\nl\xde\x94gJ\x9c\x80\xf9\x8c \xf5Uy\xa1\x1d\xe1\x13\x8b[/H\xa9A\xe5\x13\xf0\x832\x91\xe2\xf6v\x00\x91\x87~ \x1c\x02hn6\xe7\xf9dS\xad\xfb\x84\x81\\<;\x1f\xe1\x04\xa6\x1a\x1f\x91X*/\xb6\x03\xad\x03\x9b\xe1\xe8\xfc)q.o\xe5F@\x06eT9\x92\xc4\xfe\x854\x84%.\\ \x08\x9bX6\xda\xb5X\xcd\xe4\x85\xd9,\xb5\x89A\xd5\xab\x8a/34\x15*9\x81\x9ecED\x91[\x1d\x91gfd8\xc1(\xf8\xe8\xf9\x1d7\xdb\xc0\x17W\xe2G\x0d\x11\xa7l\x86\x9d\xdc\x88\x98\x101\x80[\xe8\x83\x83\x81\x88\xe8\x93#\xde\xff,*\x98E\xady\x93\x18\xda\x1c\xf1:ff{\xc2k\xa4\x90\x86\x80\x1cF\xc0 \x81\xcd\x06r\xf6W^\xf4\xc8`\xd2\xa7 W\xa1+\x07\xb1\xe7\x97\x90\xd2\x0fJ8y\xe7\xb0\xa3\xc3\xcc\x0c\x86C\xee\xe9\xe7\xb1\xcd\x96 G\xa4]\xd8\xd7V\x9a8\x13^\x8d\xf6cg\"Y\xcc2\xdc \xc4\xcaZ\xd2\x18\x1a\x96\x06\xc4\x00\xb6\xf0\x94\x8a\xa4Y,,\xd2\xf8x\x93\xfaY\xe1p\x0c\xcb\x0c7\"\xdc\xb4L\nDDQE\xc9\xa4m3:\x89\xe9f4~l~\x00\x93o\xd3SEV\x1e'*\xb2\xea\x95\x8eY\x06B\x87\xd6\x81J8Nu\xfd\x95S\xc3\xa2\x03\x92\xd4\xd7\x12E\x9cqW\x02\xe3\xf3I+1\xbe\x12\xcb&|o7\x1b\xd8\xc2r\x90\xf9\xf66<\x82\xa4\xdcl\x13F\x83\n\xad\x9c8\xc7b,\xf8\x80\xe7X\x84h3\xe1\xe65\x031\n`\xa2\xa3G\x93oT\xd6 \x9b\x1e\xeb\xdfi\x89\xecz:\x896J\xabM\x15\x9fy}\x1c\x96\xf7\x9a\xcfR\xb9V\x0f}\x88ZOK\x06\xaf\xed\xed\x0c\x1e+(\xdfv\x12;E\xbfC[\x04<\xbb.\xedj\x024P\xb5N\xa1\xe0\xaa1 \x96\xd4\xe2Q\x0c\xb0'\x01\xaf\xa3\x13\x88'Oe\x92\\\xf4\xc6P5\x95]\x14\x04U\xac5\x1d\x98\xbf\xbb\x1e\x98v\xb2}M<\xb0\x99\x8c%.{\x84x\x16\x97\xf73\x11da\xa3S\xed\x88n\xe1\xb4'\xad\xa4\x8a\xa7\xe4\xc6\xd3\xb2\xceuO\xfc\x92je\x0d\xb6;\xb3\xb3\xdd~\x00\x9a@\xcbk\xe2\xb9\xbf}Y\x92\xd4e]\xba0\xf7\xdf~\xdet X\xb8\xc9q\x914\x89\xda\xe55MZ(R$\xb3\x0e\x86\x82V\xf8U\xd6\x1f)CT\xa3\x0cQ\xc0\x8f\xb0\xa8\x8d.\xb4\xcb\x0d\x8b\xd2\xeaa\x7f\x99q\xa2\x0b\xac\xe47\xc3\xbfX\x07\x9c\xcb\xcb*x;\x13\xf1L\x16\xf6\x1e\xce\xe7\xd1\x82\x80\xd1)\x0fTu\x00\xda\xae\xd4\x99'\xd8G'\x9a\xe7&$\xfcz-\x86\x8fo\xb6\x04X\xf0\x17\xe9\x94\xa1\xce\x91\x18@1\x1b\xeae-\xb4\xe7LT\x0d1oeve:\xca\x16\xb5(\x10@\xe1\x9e\xb7\xd0\xf3j\x02\x8f\xb0`\xcdM\xc8=\xac\xda\x87e\xf2'\x18\xa8\x0d\xfb2M7R\x84X\x94\x03HPR\xf4\x0bIbk\x17\x8bs\x9a\xf1\xca\xac*g\x0b\xcb\xben\x96P\xfa3L\x19\xa9Y\\\x03\xb1\x8a\xa3\x96B\xe7\xd7F\xa5\x04[\x958))\xa8\x93\xc9\x04\xe4\xb9%R\xcdw2\xcfN\\\xe9\x0d\x88^RA\x01\n\xf7\xeb\xd1`\xcc$T\xd4\x10z\xa1\x8c\xa7@\xecb\xc7h\xeeM\xca#3.\x08G\x1a\xf0\xf3s\xd2N\x16\xd9\x15r\xe7\xdcD\x94F\x9b4\x96\xd7\xda\x82\xf0\x8eJ\x90\xac\xa3g\x97\x19i\xdb(`\xdb\xaa]#C\xdb\x81\xa2\xba\x99\x99~\xb1RT\xee\x91\x89\xd1\xaa:\xf9E\x12\xdc\xd0\x986:2SK\xbe'\xa5v\xa3\xe2 HZ\x8a8 \xb8\x8fR\x1cy\xc4K/\x1e\x00\xffP\xb8\x97\x11\xa3\xfb`\x91e\xdaxD$\xfd,I\xa9\x9b4+>!\x1e\x1d\xdd\x1e\x07\x10\x8fn\x8f\x11\xcb\xe9ho\x0c;\x10\x8f\xf64\x19\x82\xfd\xb2 y-+\x83q\x97\x96;i\x08{\xcd6\xeb\x15\xfal\x0d1\xd0\x8f\x06\xba\x81q\xce\xf5\x85\xa8\xf1\xc1\xdd\xbao\xf0_?z5\x85\xa0 \xa7^Zq\x8a\xfb\xbb(x\xe5b7\xfa6\xed\x82,u\xe0\xdcRG\xe0\xcaK\x02\x99\xad\x0f;\x99\xe0w\x0fC\xd8K\x9fK\x86\xef\x96\x03\xff\xea\xfa6\x07\xf6\xbf\x03g\x88\xab\xd9*\x80\xa1n\x02\x973\xb9\"\xa0\x04\x16\xd8\x00\xc2\x13\x90\xf4\xb3dI\xae\xd2\x01C/K\xf3\xa2\xbe\xd4_\xc8H\xc9\xfc\x989\xe6\xc7\x14\xce\xbe\xa2\x1c\xc5U\xa1\x88\x03\xb4\xcd\xf2\xfa\x05\xe2\x1f[s!p\x13\x0b\xaf\xc9A\xfb\x93$\xceh\x9aOP\xb3\xecF\xdf\x7f28zGE6\x1b\x1e\x81\x84%F\xe8(6j\x0d\x810\x01\xc9\xcd\x818mI\x9c\xcc9\x88\x82\x04Zs\x8aq\x0bv\x14g4\x8c'$\x99)\x15\xcf-N\x11\x089D\x8f\xea\xa7\x95d\x9f\xa9gR=\x17MX9tv\xc5\xa8\x96j\xd7\xb2\xe6e(\xe5g\xb2\xce\x8c~\x89\xf2\xdar\xe3\xca\xd4\x8b\xa6k\x87\xb7\xd8E\xb4\x11\xaeN\x9d\xc8K\xcceJfQL~N\x93\x15I\xe9Zp\xbe\xee\xad\xb0\xeb\x94PE\xb4\xec2\x06y\xa9$\x88\x87Mvj\xe2\xb2\xdd F\xbd\xb2\xcax[\x8fo\xdduJk\x89\x98\x03\xe8=\x0d\xe38\xa1\xacuHb\x08c\x88\x8a\xf4\xbc)\x99$\xe9\xb4\xdf+H&\x8f\xb6\xb3\xb0\x98\xba\xab=s\x9b\xbc\x0c\xd1\x08\xf5\xeb\xb2\x7f\x12\xc5S\xaf\x8c\xbak\xff\xec\x12&!\x9d\xcc\x01\xc1f\x1f\xd0\xa5']\xd3\xe5\x11\x91\x0b\xfd\x04r\xfdq\x88\x81\xbcK\x93\xe5aL\xd35\xd7\x95*\xca\x9fv\\\xe9V(\x81\x0b\x7f\xc3F\x95\x04\x87\xfc\xda\xa4B\x14*\xdd\x1a\xcd\x08%!\x11KT\xfd\xc8\xbc\xacp\x00\x1f\x88p\xe5\xecPmA\x1e-D\xdd\xd9<\xef\x85F\xa2AHF\x99BH\x87\xf0\x9aT\xe1;\x9a\xca\xea\x06\x15\xa8\x17u\x0e4\xfb6\x00\xe2\xbd#\x01\xbc\xf0\x03xw\x05\n\xdc\x14\xfc\x90\x02\xeb0\xa1\xd2|-n\xa0\xb5\\\x1ao\x9b\x17M\xb36\x8c\xfa\x91\xf7\xe4K'\x9a\x81\x8d\xcb/\x9bt\xe1]\x15nN\xa1BgJEf=\xbe\xb1&>Jr\xb8\xa5K6X\x19\xa3L6\x80F\x0d\xe7i\xaa\xcd\x88yJ+\x8798\xfc\xd2o\x04\x89\xd6\x80\xc01\xb7\x15;T\xb2\xa8\x07\x02\xa3\x02\xcf+\x87M\x070\xa4W\x01C\\\x03\xc32\\i\xf0\x15\x04\x18\x1a\x85_\xde}\xdb\x19\x11XB\x94\x9a(Y\x1e\x13\xd5\xc9+\xe6<\x07\xc7e\xea\x11S\xcc\xd2%#P2\xdf\xf2?y7>\xcf\xd2S\xf4`T\x9d\x17\xcdG\x81\xc8\xd7\x1c\xc3>/\x06\xa4\xeb\xcao%\n\xdd\x8e&<\x1eT\xb0\xf8\x16\x08\xca\xe3I\x7f\\\xc4U\xddS\xc3\xa0aD\xdd:\xd8\x8c\x8b\xea\xa8\x90\x97\x96\xa1\xd8\xea}Q\x88 hP\xe1JCT4\xf3U\xc0\x82\xf8\xe8\x17V\x98Wt\xcba[\x8a\xf2$!\xde\x1b\x12\xc0\x0d?\x807\xeaR\xe9\x02\x01\x1d\x89x\x11\x0d\xd8\xa4\xe4o\xbems\xb5R\x1a\xf3\xfah7\x9d3o\x86;\x0cA\xee\xca\x92ig\xea\x86\xf7\xdf\x84\xb0\xd7\x82\xa1\xc4\x15C\x89\xc4P\"14\xe5\xa6\x10\x81\x97N5\xc3\x88\xf7\x8a\x04\xf0\xa3\x1f\xc0\xabo\xe7 ,\xc8\xf7\xeaZ\x90\xef\xcf\xc40\xe2\x8e_\xda\xc9\\\x1b~\xfd\x87\x91\xa8\xc4\x9f\x8e\x88\xf4Lp\xba\xcfT\xe8\x10!\xcc\xb4\xf1\x10\xcdu\x14,D\xbd\x9fg\xff\x95\x88\x84.1\xa6\x87\xec\xfa\x89x\xc6\"z\x8a\x93En}\xab@W,\xd1\x8f\xc2\x00:vr\xb1\xb5\xbc\xb9\xcbo\x1a\xa4Xv5\xf5rZD\xd7\x02\xfb\xbf\x06\xd1\x1d\"C\xdd\xf6\x02\x14\xe1\x95\x15\xb7p\x8b\xf3\xa4\\/\xd2\xe6e\x89\xde\x95\xb6\x11\x02G\x0e]\x18\xa0zI\xde%o}S\x0c\x1e\xf7r\x04\x07<\x91\x0bG\x89\x14Q\xa2\xbc9\xe07\x07\xcd|\xf9\xeaepYt\xa0 \x95s\xb8\x9a\x86\xe0\x9d\xf9\xd1+\xf3\xa3g\xe6G\x98\xa3\xcaK\xe3\x00N(\x13-b\xe5\xcdoT\xb0\x86\xb1\xe0A\xb7\xa1g\xd4\xb0V:\xec||V4\xea\xec\xf3\xb7\xe7qi\xf2\xb1w\xe6\xa8L\xe0i\x9e\xe6Eut\x1b\x9aW7oep#\xaa\x89S\xae\xcc\x85\x89\xaf\x07\xe5\xdfRg\xa1\x89\xd9\xac\xcf\xc4I\xf9[J&Z\x95\x15\xef\xff\xe6Me\x00\x15}\xae~\xb2R\x99\xa0\xda\x06\xcc\xd3\xec\x1f\x93\xe5\x8a\xaeQL.~\x0c!\x8f\x85\xa8\xfd\x1bm\xa6<\xadM\xd5Qc\xdc\\\xb4\xd2J\xcd-\xd4\x7fS\xacZy\xfc9N\xcec\xf8L\xd6\xd0\xfb\x1bl\x03\x85m\xf8[\x0f\x92\x18\xd8/\x89\xc7\x06#y\x05z[%\xf8D1\xfd\xb2\x16\x87\x16)\x1c\xf4\x86\x15cBu\x892\xa9\xd7j\xc1\xadJY\x08e4%\xce\xc1~\xb9\x0e\xcd:\xcc\x955pT\xae\x1b7\x8ey\xa6\xc48\xfb({\x8f\x9a\xf8I\xdcT\x01\xcd\xe2\x00\x16\x0c\xc7z\x7f\xff\xfb\xf1\xf1\xd1\xeb\xd7\x1f?<\xf9\xe1\xd5\xe1\xf1\xfb\xc3\x0f\xc7\xc7\x7f\xff{\xaf\xe9\x08\xb2bog\x0eJ\xa3y;\"\x18\xaa5\x91z\xb5& \x05Y([j\x88\x91\xcd\xe5\x87\xa6\xf4\x8eg\xa0^\xae\xe8\x9a\x87O\x17`tSDL\xdb\xf7bU\xc9\xb5\xb2\x04a\x94\xd9\xeck\xe5\xebb9-\xca\xb3z\x97kJ\\\x93p\x9fY\xe9\xd2\x0c\xf3\x0ex36\xdei\xec\xe9L5\x86v\xd7\xdf\xa0\xd2:\xe7*\xad\xd3\xb8\xd4d\x9d\xff\xbfM\x93uj\x87_\xa1\xee\xd3\x14XT\x7f\xad\xe2\xd1\"\x96\x0et+E\xa9\xb5*\x95Z\xab\xaa\x82I\xfe\xac>\x10\xac\xc1*VuV+\x17\x85\xcf\xca\xa6\xf0Y\xb5)|V\xb1\xdc\x870\x84\xb3X\xdc`[\x11Q2\x00\xe2\xadcF\x9c\xfc\x00\xd6\xd7\xa7\x11Z\xff)\x1a\xa1\xf5uj\x84\x84\xff\xbdM1\xb4\x8eK?}N\xb9O5\x94{\x19\x07p\xcc\xf6\xc9\xda\x81\x16\x9ft%l\xc7\xff!\xc2vn\x85\xe6\x92\x13\xb6%\x1b\xefI\xec=u/\xbby\xf1\x0d\x84\xed3'l\xef\x15\xc2\xc6n\xf5\xf38\x9bG3\xfad\xb1p\x8d\xe6\x7f\xef\xac\xe8~bWt\x1f\xc7\xa5\x83\xed\xb1\xba\xd7\xcecqC\xec\xb5\x13\xdck\x17q\x00\xe7\xd4\x0f\xe0\xe2\xfa\xf6\xda\xc5u\xee\x8a\xf74\x9c|\x86\x11\xdb\x10\xe3\xe6\x86\xb8\xb8\x82+H\xd5\x18?'\xe1\xb4\x89\xcf\xa8\xb7\xa2JRn\xea?\xe4\x89\xd7\xe9\xce\xceC\x1f\xbf\xe7^U\xe6\xbd\x00\x07 \x92\xd0\xe8\xe2\xfe*#_\x11\xf2\xb9\x13\x80\xd8\xa8K\xc3!\xfb\xa5\xc9\xde\xd1\xe8%\xcf\xe6m\xbd(9\xbe\xe5\xfa\xbai\x1d\nM_\xe1L\x82\xbb\x7f\xbb\xd1N\xa00\xc0l\xe0\x01\x02\xb3\xfe\x16\xec\xc0\x80A\xfc1W\x1b\xee\xec\xf8\xf8\x99\x89/\xc0\xcc*E\x1b\xa3\xd8\x90\xfb\x90-X}-\xd8\xa5I\xb4\\\xc5GC0e\xc1i\xe3z(\xf1V\x8d\x8a\xa1\xfcn\xad\xfc\xb9p\xed\xff#\xd6\x8b'\x8d\xc5{\xc2H\x91\x83`\"\xd4\xc9\x98\x1f\xda\xa3\xbe\xcf9\"\xfb\xfa\x959HZ\xa4\x16d\xc0\xf5\xd0m\xd9T\x05o_\x84\x07u\xe0\xd0\x08\xcf\x92gB\x01(\xd1\xc0P\xf5\x18\x8a\xf5o\xa6\xce\x87\x06\x19\xc5;E`\xaci\xfdIm\xfd\xe3\xab\xae\x7f\xd3\xfd\xba\xb1\xfeIke*\x15e\xb3E4!\xde\xc0\xde\xa68\xa6\xba\xb4\xcb\xd0\xd0Q\x1d\xa5\xeb\xca\x05\x83\xeb\xdd\xe9N\xd1Z\xeb\xdd\xa7\x91\xac\xae2\x8b.V\xa6o\x8d\xcf\x16(U\xc3\xa0.x\xc5X\x11;\xd8\x18\x92\xb8\x1c\x99\x8c\xa8|\x16\x8e\x1e\xc5`]\\\xc1b,.\xa2V\xe95h\xb8_{\x95\xa6\xab\x16\xaa\xa2\xa3sZ\x1f}\x99\xa6\xc7\x18\xe3W\x9cLi\xe5d\xc22gQ\x95d\xb1\x83\xe6\xa1\x8fw#\xfb\xe9n_\xc4\xb4\xb6\x88\xd1\x95\xd6\xef\x8fXWa\xba\xb6\x86\xdd\xd4V\x85.\xa9\xa9\xb9R\x10\x14\x0e\xf0L*\xa8\xbd2\x99\x8ea\xc8\xea\xcc\x06\x06=\xd4\xc5\x95\xb5\xa0\"\xee@]\x92\xf2hQ<\xbflH\x11\xf3=\x97\xd6\x10!\xad$\x13Le0H\xac$\x13\xc4o\xd2\x16&\xd0i\xb2n:R\xa7\xd9&z\x1db9S\xed\xd9\x97\xba\x9d\xdc\x8e\x91 \xad^\xff\x92\x9fH\xdb\xe2\x07D\xbf%\xa0\x03\xee\xd9\x8f\xcb`\xb2\xfa\xeag\xc8[je\x1e\xda\xb2\xf3Y3\xf3\xb9D\x05\\\xa0\xd6\x15\x85\x9a!\xbc\xd7H\xef\x87q\x00Otz\xd7\x0fO\x9e\xbe4h^\xdf\xb2\xf7/\x1c\xa4\xfd?\nw\xbd\x96\xfc\xa15\x8f=kF\x99\x92\x19\x8eTN8\xaa;\xeaE%\xfdK\xf9\xaf*upK\x19\xf8\xd9z\xea\x1er=\xc0!\x03\xc8\x1f\xb1\xd7pO14z\xd4..\x16ho4K*\x87\xd3\x08ut\xec\x9f&J\x18!\xa9\xa6\xef\"%o\x1c\xfb\x01\x94.\x93Jh\xc4\xfb\xf5\xf2$Y`\x85\x04\xdb\xf3z[\xb4\x06\x11\xf5\xd7\xdbx\xf4\xa4P/\xbeu\xd1\x06\xbe\xb5i\x03\xdf\xb6i\x03Y\x17\xaam\xed\x8b\x9aE%\x80\xb8\x7fT\x12\xc8\xaf\x01[\xa6X\x97\xfeK\xa4\xc4vH\xf3\xf5\x8cz6V\x04\xc4\x82S\x91\x1b\x97g\xda.\x8f\xf6\xcdFk\xa3\x87\x1acP\xe6{0\x98\xde\xac\xa6m*\xb0GOc\x1a+\x88w\x9b4\x81&G\xf1\x94\\\x90\xe9{\xf2\xc5\x010\n\x89\x7f#\xa2\xce\xddz\xf9\xe9\xbd{\xeb\x08\x1cm*l\x17\xcd\"W\x87pa\x84p\xefn\x1d{!\xa7,\xd2\x94]\xd2I!\x17;\xf6\xde\xa9\xdb\xec:\xbb\xed\xbcI^u\"\xa6\x9d\x9a\xcf\xaa\xb3R >\xce,\xac?/WY\xaa!\xe4\x9c\\ \x052\xae\xee#\xbc\xb86\xd0\xbf\x8a\xb2\x0eK\xbe\"\xd7\xd5/7C\xb8\xf7\xdc\x1b!\xc7r\xb2 \xe3\x9eK\x0f\xa5\xa9\xc3\xb1\xfc\x85Y\xbb\x04\xdb&\xc6\xf2\xba\x9f\xbe\xf2\x12\xc3\xcc\xb91\x8f\x97\xd9e\x94?\xc5\xb0\xc7}\xce\x14\xc2\x01\xe4\x98\x92|\x1fB\xea!\x7f\xd8\x8f2\xc1'J#\xe0\x88\x8e\xb5\x94[\xbd.}wOo\xf5*\x10\xc0\xe2\xf5\xad^\xa6\x8a\x1dP1\x16D\x0d+\x8f\xfd\xabA\xed+\xfb\xb8\xcfD%\x84h\xb4\xebP\xe79)\xed\xad\xb8\x08\xa1\x97\xa0\xc7\xae\x0c\xc4\xcd<\xa5\xd0j\xb3\xde\x96\xbc\xcc\xd9W\xcfD\x95(Q\xfdBW\xd7X^\x92\x92ci\xe9!L\xeaT\x14\xc7\xc4$N\xf9T\xd2S?\x90\xf7f\x8b\x90R\x12{[\xbb\xc2\x12\x83\xdaEM\xd1\x13\xebV\x00\x01\x1c%\xcd\xa8\x13\xba\xc8-\xc4\xfd\xa0\xec\xc0\x87f\x1fJ\x85X\xd86XN\xe4e\x06\xf8%\xaf\x8d\xd6,g\x8b\x0f\xa5\xfaV\xe3\x0e\xed\xc6\x8eH\x8f^\x97\xb4\xc9*\xbbV\xf5 v\x897\x98\xda\x12#k\x0b!4n\x91\x98\xa6Qe\xac.CU\xf4{\xef\xdc\xba9#\xe9\xda\xf1Lq\xe4\x82cK*\xf2\x16.8\x0d\xc0V\xf2\x13\x8a@s\x8e\x03\xbc\xd6\x11~\xa1\x14Z\xe3Z\xa2\xad\x81\x01\xf8uG\x12\xd0\x03\x86\x13]G\xc8\xd4O\xae\x1f\xd4|\x82\x9a\xf0'0\xf5\x19Ok=\xbaT\x8db\xc0d\x9fbNT\xcf`\xde\x00UOz\x80 M\xf4\xe5\xc15\xc3\xe2Z\xa1n\xb0\xa8 KP_q\xeei\x89y\xbb\x89\xaf/S\xa3\x19\x08\xe3@\\6o\xbd\xef\xc2\x92\xc2\xe9!\x1c@\x0f\x19\x1f\xd8\x87^\xd03c2#\xc1=\x8d\x1eU^\xdf\x82\xe96\x1c\x8fE\xa9\xfe\xad\x01\xba\xacn\xa3\xd2\x14\xffE7\xa3-YBJ\x99\x14\xaei\xe1E\x83gN\xaf\xc9Y\x82\xd8\x01N|\xdbg\xb2\xfe\x06\xf2\xf3\xd4iE\x97\x159\xd4\x01\xad\x8a-VM\xd9\xe9\xd4\x19?K;n\xb0\x00\"\xeb\x02\xd7p\xad\xe1\xa0\xf2\x08\xf60?\"\xc3\x14\xd8\xe7\xf9\x90\x1a\xdbAU\x03`\xcdZ\x1b\x01\x84\x03\xf0\"A\xe5\xb09_\xb4K\x8b\xd2\xb7\xbcb`b-\xc8\x9c\xba\x83\xec]t:\xa7\x1d\xe1& \x93\xca\x08\x95\x86(;}\x12\\\x8f0\xbd\xa7F\xbb;\x98\x06\x8d\xbd\xb8\xe3n\x81Tj2\\\xa7\xae\xd0\xb8|E\x0c\xfer\xb5C\x82q#\xddz\xe4yYx\xac\xdc\xbb\x18K\x85\xe9\xb2`\xe8\xbaJ\x9djL\xd4gf\x0c\xc8\x01}?(u\x7f\x03\xad\xf9\xd9\xa9\x97\x93\x9c\xbe\n\xbb\xa8\x07\xf8\xbeF\x0f\x99\xdd\x00v\x06N\xbdD\xd9\xe1rE]l\x0c\xa2\x17\xf5dR\xe4\xf4\xba\xe4\xbe/\x96\xb1\xca\x8c:\xf0\xa2&#\xa4\xd3l&I\x1e\xd7w~\xcb|\x9ex\xb4T%\xf1m/\x04X\xfeq\x07\xbd\n\xf6\xfe\x83+{*\xfaw\xa5R\xa0P\xaa\xaf\xd4\xf3K\x83\x94-\x03\x9eD\x0d\x1d\xf1nc]\xf1{\x917\xc1+\xeb\x94\xf3J\xe2lW\xaa9\x8f\x9d\xa46E\xe6\xd2\xb3\xbb\xf2\xb2\x94R\xc1\xb3@5\xb7\x19*\xe4]\xaa\xe7\xad\xcb\xea\x91/y\xb8\xe8\"l\x9d\xd1\x82l8\xb5/\xb2f:l5\xd5\xe1T\xbf\xb6\x18\xa8\xd5?\xc6ty\x95\xe2L\x94\x96\xf7\xed\x9cb\xb5z\xeb\xcf\xb1_S\xb5Z\xcf$\x0e\xc6A\x0b\x1d3\xc3@\xa2\xa0\x1b\x05\x8e\xaa\x94\xb7\xd5\xfc\xa4P\xb0\x00\x12OG\"\xe5e\x18\x7fgQc\x1ev\x913\x90\x0e\x89\x84\xcbK\x1eC\xb0t\xec\xe5\xa8\x0b\x0d\x97\xfdp\xaf\xd1.=E\xd9\xfb\xfc\xc4\xb1\xc0g!\x03\x0eM>aE\xa5\x14nu\xe6<\xba\xa2\x13r[\xda\xe2<.\x12\xe3t\xc8\xa7\xa5\x9f\xe2\x8a\xf1B]&\xe9\xd9f)`\xa6\xcc\xd2/n\xba\x9fj\x9f\xc9\xfa\xed\xac\xc3\x90\x8aC\x8d1s\x9d y\x0dFB\x1eq\xee~\xc4W\xb42lW?mH\xa9.\xdd.\xba\xab\xd1\x1a%\xbf\xfa\xc8\xcf\xba\xf7\xf7\xf2*\xebb\xe0\xbdq\x8d\xb5\xb9\xac\x9a}/\xc3\x8b\x0e\xbd\xbe$\x9dT\x18\xcb\xf0\xa2\xeb\x99\xfa\xb2\x92\x8f\xc8\xa9\x137\xa3Yc\x06p\x00ob\xee\xc2\xf2\xd5MPZF\xf1\xd5\xa7\xc3\xbb#\xbc;\xd7\xb9\xa5\xa43&jC\x1eA\xdf|\xf69Zu\x80\x9d\xd2\xfe\xeb\x90\xce\xfb\xcb\xf0\xc23T$6tV\x17\xbe]\xa5\x04\xc3\x1ecMzT\xb9\xe3<\x90_\xe7\xd1\xa2\xa3\x99\xa1\x18\xcc\xefW4l|\x8eV\x1fc\x1a-\xbau\xcb\x81.\x87\xdcM\x05\xc5\x13\x82u\xeb\xafi\xe5\xd0d\x06\x03}\x7f4\xfcL:,/\xad\x18 \xae\x80R\xac\xbfkF)\xd6dw\x94b_}\x0bJ]E\x92\xf8\x87\x13w\xab\x940\xfa\x18\xa3\x9a\xb7\x92\xbc\x0d#+[\x18^\xc9NS\xa3vY^L\xa4\x8b\xaa\xb1yJ\x81\x96J\x18\x08vlo\xedL\xd4\xf3o)\xfb_0n\x1a\xc1\x87\xa2J$l\x9b\xa1\xd2L)\xfd\x14\xdf\xde\xbc \xdb\xdb9\n\xa9\xa2AC\xa1ry]\xfa\x01\xe4\xc67.\x03P\xcb \xfd\x17\xadJ\x92vY\x16Z\xf1\xc6b\xdf\xd9\xe5Zv\x85\x16\x8f\x12y\x89q:FY\xaa\x17\xfaN\x85\xc5L\xdb?\x00\xf7\x88G\xf5\xb2F?\xaa\x97!VB\xbd\xa4\xe9&o-N%/\xae\xc3\xaf\x14\xa9\xb2x\xa9\xcaKF4R\x11\xc3\xdb\xfa\x01\xbb2\xe1\xac\xea\xf6\xf6\x04\xdf\x1e\xb4\xb8\xb6\x82n\xafM\x02\xc8P\xe3y\xc0H\xdbp\x08\xef\x84\x98\xf3\x9cad\x86/\xf04\x7f\xa1\xf0\x0c\xf9/X\xdc6\"`\xa5\x00\xda\x87\xdd5\xaf\xec\xe0\xb9*SQ\x1cZ\xdd\x98\n\x19C\xd0\x91/\xed.\x86\xcd\xc3l\xfe4\x99vpt\xa1\xf32\xbb\x00\xd6e\x9a\xab\xd9\x06\xday\x04(\xb6\x17wP\x1e\x0ea\x00\xb7`\xb7\xd8h\x16\xd2%\xcd\xa4\xb3V\x05\x9f\x9b+\x7f*\x8a\xdf\x0e\xf4Uo\x8b\xd7\xf8\xc0\x9c\x16\xbf\xf6\x0d\x1b\xed{\x14\xd2o\xdf\xb9\xbd\xf7`p\xff\xf6\xdd\xdb~P\xdc\x86G\x8f`p\x176@\xe0\xf1\xe3\xc7\xb03\xb8\x1b\xc0\x9d{\x83\xfbw\xee>\xd8\xfd\xbe\xfe\xdem\xe5\xbd\xdb\x01\xdc-\x9fc:w\x8f\xc06\xdc\xbe\x7f\xef\xce\xde\x83\xbd\xc1\x83{\xb0a0\xfd\x17\xdb\xd2\xff\x12\x9f\x0d\xee\x05\xb0\xb7w\xe7\xde\xfd\xbd\xbd\xbbE\xf3\x87\xe2s\xec\xa6x\xf3v\x00\xb7\xf7\xee\xdd\xbbs\xff\xc1\x83\xdd\x07\xbe\xda\x84e\xcby*\x7f\x10c\xad\xcb\x83\x8eP\x83!\xdc\x1e\xc0w\x90\xc26<\x8f\xbd'\x147\xcd\x13\xea\x11\xdfg32w\x0e\x8e\xbbS^\\+~\x85^\xaa\x93r\xe9\xa6\x98\x11v\xd4\xdaA\xb7\xc6\x1d\xdb\xf5\xb5\xe5\xac\xa1 \x88:RX\xb9SW\x06\xb3\xbd\xf8\x9a''Sr\x01\xa8o\xbc\x8eG\x0b\x19\xe0\xfd:\x1e=c\x7f\xbf\x16&\x8b\x8c\xdd\x12\xa1\xa3\xfc\xb6\x08\xac.\xee\xab\x81C0\x84W1>\x89\xe2l\xc5s\xe3\xe3'\xef\x93<\xad\xe6\x95\xd1\x81\xac\xa6D\x12\xee\xad\xd5\xd9a\xeb\x93y\x18\xc5\xbcma\xcb\xe4\xb7\x93\x98\x86\x11F\xa5\xe3\x10\xb8\xee\x12c\xc4S\xdd)9[D\x1dB#\x0b\x01\xe5+1\xae\x84N\xed\xb3:l\xb8\xf7\xbbZ\xff\xcdT15\xcb\x02V\xe1\xae\x93a\xb5\x90&\xa4\x93\xc4( \x1a\x9b\x8bO\x03p\xa3\xaab\x93t\x14\x1a\x97\xe1\xeae\xd5\x07\xd9\x15FW\x00\x02[\xf7:,\xda\xc4\x8c\x06,x4\x82\x05\x08\xd8\xc9Uv\xeb\x87\x18\x93\x9b\xb4f\xeexj\x06\x92<\xd5\xaa}\x19\xda\xf9\xb9\xb5\x9d\x11 \x80\x8e\x9d\x1a{g \x87\xf5\xb3\xb9e\xb3mQ\x97d\\\xd0\x84\xa7aXo\xaegX;\xd7<\xacW\xf6a\xf52\xa4\x81\x15\xe3\x07\x1c\xc0O\xef\xdf\xbe\xe9\xf3G\xd1l\xcd\xd5\xb6\x82Z:\xe6\x16}f%\xc0\x87\xc6L\x9e\x86\xe6\xbe\xb6b\x10\x85G\x05\x07G\xe11\xfe\xbd\x83\xec\x9cS\x07\xcf\x1d:`\xac\xcf6\xec\xdd\xbb{\xe7\xce\xed\xbb\xdf\xdf{\x00\xdb\xe0Q\xc6\x90\xdd\xf3\xf9\x9f\x8f\x1f\xc3^\xf3\xf4\xad.\x94h\xedCT\xaf\xc2h`\x95\xcb\xe5\x95|\xb3\xad\xaeu@J\x1b\xdeV\x82\xa5\x00\xf8\xba\xf2\xd0R&\xa2G\xbe\xaf$-\xc5f\xc5}k\xcb\x97\xac\xf7\xc0\x96GC\x85\xa8\xdel\xe7\x0c\xd2\x80[\xee*1~\xd8\x7f\xeb\xe4\xdd\xed\xa1W\xb0\x9f\x15\x90\x8d\x18ds\xf8\x1f&;\xb0\xad\xc7p \xa9\xb8\x00c\xcc\xef>\x7f\x07\x0e\xe09\x9b{\xce\xd3\x91\xa2\xd5F\xfe\x8cd\xca\xd86\xf0[\xad%\x86T\xe5%\x95p\xde\xc6\x0b\x12\x9e\xb9p^\xd2,7b]\x8c5\x87\xb2oY,\xb6/op\x02 \xf5/\x01\xdc\xe8'3t\xa65~\xc6\xf3\x93(\xde\xf9\xd6s\x96\x14\x1b\xdf+\x88\x81\xb8\xc7\xe8\x80\xc8H\x13\x94\x94\xc8\xcd\xc7\xa9\xab\xcb\xdd\x92z\xbbj\xcaj\x97>\xae\xe0_\xc7\x0e|\xc7\x08\xd5\xebv\xefq<\xf9\xbf^I\xafzC\xfe\xf1,\x0el\xc8\xe6<\x86_#:w9\xa7\xa4\xcc\xa3\xf6b\xc77\xc6\xd3\xc9\x00\x81\xe6\xf8M&\xcb\xca\x9dK\x9fQ\x842=\xec\\\xea\x1b\xd4\x9bE\xdd\x96#t\\o\x0e\xbf3\x8f\x85\x18\xc4kA\x0b\xb3\xb2\x93\x9cv\xd5|:\x9a\xaa\xd3p=\x9b\x0d\x9b/s\xb89@;Q\xf2l\xf3\x12\xda\x15+\x81\xfaX\xb1$\xa8\xb7+&\x85\x17\x81\xaa\xa4\xf5\xf1\xde\x8d\xca\xf2\xf1{?V\x9a\xe6\xf7N\xa8\xe6\xe3s\xaa\xf9\xfa\x82\xd6?oBE\xe6\x97\xdb\x87\xb8 W\x04\xea\xcb\xe6\xfd\xa7\xc9bA\x10\xd2\xfbp\xac)\x90\x81\x01b_5\x0f\xd4\xb4\x92G\x1a\xe7 \x9e\x97o\xa5y\"R\x05^hGI\xf7!\xd3\xe5{\xbb\xbb\xd3O\x9f\xf2\xe9\xfd\xdd\xdd\x1d\xf6\xefl6\xfb\xf4)\xdf\xbd\xcd\x7f\xee\xde\xbe\xc7~\xce\xc8\x1e\xfe\x9c\x91\xbd\x19~3\xc5\x9f{\xbb3\xfet\x97\xf0\x7ffc\xd3\xe0\xcc\x14\xad\x100(\xc9\xa8J\xc7.\xbb\xc1i\xb0\xfb\xa0\xc6\xeb0.\xb2wx\xb1\"\x13J\xa6\x10\x16\xed\xf4\x14c\x8f\xbc\x07\x89\x96\xb0G3\xf0\x94\xf8\x88-\xc5D\xb0\xd9\xc8\xecA\x1cE\xb4\xaf\x11\x1f\xe8\x9e\x864<>\x16\xd9F\x9bX\xa9h\xf1\x84\x14[\x83\x0c\xbb&\x9a\x1aTQP\xb9]\x14\x82M\xaa\xf7yQ\xc4\xbcz\x933\xc4a\xf5f\x86ofUB4\xe9\xb6:\xb7\x1f\xe8\x97\xe7\xce\x83\x96\xe3\x18\xa8\xc8\xcb\xc1Co\x1b\x8e\xeb\xca\xe6\x15\xc6\x0eOT\xe6\x04R\x9c\x80\xf2\xd1V\xc4\xb8\xab\x9b7\xd9\x1f\xb1\x8fJay8\xc6\xec\xaf\x98\x1dA\x95\xfe(\xeb\xf2\xca'\xfe\xed\x07\xb7\xb5\xb3\x1e|_G>\x81\x94\x0f\xeei\x90r\xd0\xc4\xc7\xbd6\xd2!k\xb9pG\xe1\x99\x0e\x15\x17\x98\xb5\xf8&\xe4\xcd\x03\x17\x0b\xb2\xca\xb2\x8c\x8d\xa7s\xc4H\x9dY\x8a\x11\xa8\x15\x03\xe4\x1c\x81\xec-\xd8?sx\x0c+;]F\x9d!\x0f\xd0\xf5\x9b-bAK\xfeX\xa9-6\xc5%n\xb6u\x06C\xd8\x194G\xbd\xe62t\xe3\xfe\xa9\x00C\x08\x07|'\x82\xf4\x8e\xae\xb6\x8dy\x01fx\xfc#\xa9\x0f\x80\xff \xbc\x06\xe8\xf6\xf6\x19<\x82\x956\x11\x00\x1b\xd6\x92\x81ttf\xe0n\x8e\xb1(\xcc\x99\xc6Q\x9c\x01 \xf3\xb1\x89\x13\x18\xc2\x02\x0e \xf3\x8e\x03X\x06p\xc6\x03\x91py\xf7!\xf3\x96\x01\x1c\xe3]\xbe\xfa3\x0d?SK\xe2{b\x92\xae\xd9{'>0\x018\x8aM)\x0b\x10\xa2\x03\xfd\xb3\x93\x94\x84\x9f\x1bO\x9a\xe7\n\xeb\xe8\xd46\n\xb6e;\xd8\x0c\xf0\x93\xc4;\xc5\xd7n\xde\x04oY\xe6\x8c\x9e0\x08Q\xb9-f~\x89K\xa7<\x16\xdf\x18\xdel\xeb\xd1\x06\x050B\x02\xb4\xd0\xb8\x04\xb2\xc8\x08Nb\x89\x0bt\x8c\xfbh\"\x96\xb6\x18\xb8a8\xdf\xba \xda\x13y&N\x10t\xba-~0\xfc_\xff\x9f\xea\x876n\xc8H\xa5\xeas\xa9\xd4_\xdb\x11 /%\x11\xa7\x98&o\xbf\xa0Ml\xdb\xc5\xf0\x08\xd2\x87\xcd\x95C\xd3\xb8GG\xf1\x18\x01\xa7r\x86\xbbZ\xfeOI\xef\xd4\x91\xcc\xdf\x19\xd4y\x83\xe2pkRyQ\x91\xa98^\x9b\xf4\x1e%\x19\xa5\\S\x93\xfc\xa3*\x08\x9f\x1de\x87q\xbe\xe4\x8a\x9f&{\x92\xda\xad\x1db\xe2\x85\xb8VE\x06\xcf\xf7\x85 \xde\xae\xec\x13\xad0\xe6\x9bak.X\xcc\x00z\xec\x0fBz\xfc\xc4\x0d\x9b\xf7\xab\xfd\xe9\x8f\xb4\xcce),\x99\xf2\x15\x06Qch\x10\xeb4\x18h\x9e%m*\x97-\xd2\x8f\x93)aB3\xdek6\x81\xab\x89\xa2w\xb3\x1d\xca\x8d\xd4\xac\x1dZiG\xa3sbk\x9es\xe0\x16\x90A\xc1\xe4\x00\xd2\xfe\x0f\xf9lF\xcaS\xab\xf95\x03\xa3\xc7\x8e\xb7\xb0\x1fe\xb5\xb7Q\x8a\x8d\xccJ\"E\xe2\xa9(\x89\xee\x0f\xfc\xc2X\xdc}\xdf\x1b\x988\xda?''\xabp\xf2\xf9\xe7d\xb1\x9eE\x8b\x05\x0fY\xe9O\xc9*%\x93Z\xedG&O0\x96t\x15\xd29k}4\xc6L\xf1\xf3h1MI,\xbe,~\xb2\xe7e\xb9\xb4)\x99E1\x91\xfb\x0bqr\x91\x84S2\xed\xe9\x14\xab\xa4\xd8a\xfbz\x0e\xa2K\xd1\x19\xda_4\x1e7\x95\xd4\xe6qF\x7f\xc9\x18#\x8716Wk\x08\x83J\x02\x9b\xced\xd4 #\x0c\xea\\t\"\xee\xdf\xd1p\xcb\xb8\xdf\x92~\x94\xb1\xfd4\xe5Q\n\x95\x97\xf8f:\x80\xc8\xcbQ\xe5\xa4\xa7;a\xb7\xb1\xdf\xdd\xbd\xaaZ\x91\xf2\x83\x8d\xd1\x81\xb4]\xb9\xd8\xbe\xb74g\xaa<\xc9\xe5;Z\x87\x17\xa9!\x10\xfa\x05\x91E\x90\x8e\x85;_\xcd\xdf\x84p\x8f\x92H\x16'\xf4\xe2\x9a\xa9\xeb\xf2\xaaX0\xb8_\x97\x818\x16|\x7f\xbf\x15\xc2m\xec\xc4.\xf72\xf0\xb8\x1a\x88\x07\xf1\x17\x9cD\xa1X\xe1\xd2\xe0#H\x1e\xfa<\x85\xe8(\xf2\xc8(\xde\xde\x1e\xfbc\xbdv\x8f\x7f!\x082-h\xebU!\xa0\xd7\xd9\x0d\x1a\xd8.v\xc1^\xfd`\xe3\x8a\x8c;\xdf_\x05^bJii\x18\x8c\xc4{\x07\xc0\x90a\x1f\x12/\xaf\xb8 9M\xae\x97g\x042\x9aF\x13\xaa\xa8\xf6*^X\x0d?\x11\xe9j\x13{\xdf?\xa8\xebF\x94\xe9\x1c7E@&\xbas\x98\xdd\xfb\xbe\xf6\xe5q\xff\x1d \xa7\x8cN\xbe\xa7\xfc@YV_`\x80\xbe\xeb\xf7\x0f\xcfHL\x0f\x97\x11\xa5$mv\x10\xb6\x81Q^%\xd1\x8f2Jb\x92b\xd1M\x8er\x8d\x0ft\x96{\xb1%\xea(\x01\"\xb88\xf6\xee\xef\xfa\x82\x03h\xbe1CA\xfdc\x14\xd3\xfbH\x07\xd9\x9e\xad\x9c\x9f\xcd\x99-85\x1b\xd4\xc0\xb6\xe8G\xf1\x9c\xa4\x11\x15J\xaf\xbb\x1a\xf3\xc0\x8a\xa3\xdd\xdd:\xb1\x06\xa12\xd0 \xd5\xec\xfe\x8am\x9fU\x7fJN\xf2\xd3Er\n\x07\xca\x0f\xaf\x97\xd1\x94\x84\xcb\x9e\x0f\xfbmC\x9f\x06(\xfb\xb3!\xd4w\n\x08\xe1\x88\x81\xb2\x8eK\xe5\xd4\x98X]7\xf9\xb3\x86O\x19\xf7\xd0#i\x9a\xa4=\xc6\xbd.\x92\x8c\xb0?\xa6$\xa3i\xb2f\x7f\xae\xc2\x9c\xdfKI\x96/Iol\x8a\xd6Y\x1a\xd1%\x01\xa1i\x8e\xbd\xbd\x81\xa8a\x81b\xab\xae\xbe\xa0$\x16\x04\xa28\xa3a\x94w\x86\xe5S\xdf\x0f \x13j\x85F\xb6?\x13 OJ\xe5\xb8)\xdaS\xe1!h\x0d\"M\xb0 \xdd\x147i{ym\x8f9q \xa8\xaa\xe2{X\xae\x93^\x89\xc7_\x14xfSJ\x9e\x15\xc5\xdd\xc4\xcb\xacu[*\x15\xce\xc3J\xaa\xc4\xa0N\x04\xdd\xe2\xaa\xd1\xd8\x0f\n\x9d?l\xb3\x86\xab\xd4\x17\xf6\x8b\xaf\x0dJT\xed]RR\xae\xdd\x00\x0e\xb5\x86I\x06\xba\x1c\xeb,zH\xb3\x11\xdf\x9d\xe0\x8aP\xd0\xcf9\xe5Uy&\x85F\xc4KQ\x15\x92\xaa\xdbf\x86\x94\xa6\x19}I\x94\xb8\x83a!\x0c\xd5NK\xcc\x12\\u\xaa\xe8\x1d\xc5g\xe1\"\x9aB\x9c\xc4;\xbc\xd9[\xe2p\x98\xcc\xf3\xf8s\xcf\xb7\xc5\xd3\x18&\"\xb6\xb5\x06n9: \x06\\*A\x02\xee\x15\\L\xc2\xe0\x99\xd7\x86,\x1c\x89\xc4*?\xc6\xc8\x1f\xcf4\xff\xfa\xc7e\xa5\xf9\x9f\xa5j\xf3\xed\xcc#<]\xb1bND\xd8\x10\xa7\xe4#bn\x13\x0c%\xd7\xe3\x06N0e\xa7\xb4z\xe45\xe7\xcb\x16B,\x02\xe7(\xfby\x9c\xcd\xa3\x19\xf5|\x08g\x94\xa4@\xe2)\x10\xc6\xf5\xf7\x10\xd7\xce\x11\xedd:;\x04\x16GU\x97\xb6q\xcb\xc8\x86\x0f\xdf>\xe7M6\x88C^\x1c\x19L\xfa\x8f\x19\xb4 &>\x92\x9b\xf6<\x8d\x84\xae\xbd\x0em!\x85\xcb\xb5:\xa8\x8cw\xc0z{[\xee\x9b\xea3\x9fW\x8fb\xcbP\x1d\x90\x0e\xfb\xea\xaa\x83\xb6\xb5\xda\xa2\x02LH\xb8\xab\xdc\x04n\x92\xa2HV\x8d9,\x99.j\xa4#\x97^\xeeF\xe3\xcf\x15\x1a\xaf\x1b0)\xb8\xa8\x9b7\xe5\x1eVh\xdf\x16\xe1l\xd1\x01\x9b\x02_\xebiHC\xb6\xd4\xa8\xf7b@\xf3v\xf9\x9a:\x12E\x8e\xa4\x05M\x95\xc8\x17\xb36t\x94\xb6\x02\xb8\xff?{\xff\xbe\xdc6\x924\n\xe2\xff\x7fO\x91\xc2o\xc6\x03|\x84h\x92\xba\xd8\xa6M\xeb\x93e\xb9\xc7\xd3\xed\xcbH\xb6\xbb{\xd8\xfa\xa9!\xb2H\xa2\x05\x02l\\(\xab\xc7:\xd1gw\xcf^#\xf6\x01\xf6\x9f=o\xb0O\xb0\xb1\x11\xe7MN\xef\x03\xec+lTV\x15P(T\x01\xa0,\xf7\xec9\xdf\x87\x88nS\xa8B]\xb2\xb2\xb22\xb3\xf2r\xef\x1e\x92F\xc7e\x8bJL\x9a\x16\xfa\xe85\x87\xe7\xd2}C.\xb8\x18\xd4\x9d\x1b\xa9\nU\x17$\x85\x7f\xb8wO\xf7\xba\xe0\xfc\xaaK\xac\x91\x81\xdb\x05\x0c6to\xd7\xf6OO\xf86F\xc3\xe7%\x83\n\xc1\x88\\\x8b\xdf\xe5\n\xe7Y(\xd7\xc9\xffRj\x15u\x1a\x0f3&\x0d vdA@\x11D\xe3\x06.7N\xeb\xb6ix]\x8es\xdf\xc8\xec\x08\xf5P\x19\xd1C\x91\xebN\x1b\xa9\x80.\x02\xd25f\xf1\xa6r\xf3,Hv\\f\xb8\xa9\xc0#\xc8>\xbbl'\x98\x99\xd1qyg\x8eK\x19\xb9\x92SB\xc5\x9fC\x81 \xdfs\x8d'\x0f\x9f\xa3\xd4<\x93 (\x87\xa2z\xc4+]\xf8\xc9[/K\xca.P5]l\xf5\x8b\x94_\n\x86r\xfaT\xd7YBd)\xa9\xd5\x9c\xda\xc91\x95\xcd\xa2\x885\x86z\xb2p\xc3j\x94G_U\xac|\x84\x11<\xdcy\xf8p\xbf\xf7\xd0\xa4/95\xa2n\xae>\x7f2b\xfe\x8dU:N\xf2#\xbb\x87d\xb6B\x9dS\xa6\xf0=(\x1f\x08\xd2\xa9\x9a\x93\xe6\x05\xf1\xa6]z\x08\x88\xb2aQm\x88a%\x80(\x07\x1ac\xa2U\x8dA3!\xcb'\xf6t\x04\x1fQ K\xff\xa5\x9dloSY\xeb\x13\x1d2F\xf7*\xfd5(\xfd\xb5[\xfa\xeba\xf9\xbb}\x17\xd2NG\x9bk\xe0\x86\x9d3\x08U \x0e\xe8!\x92CS\x9e9\xa9h\x0cz\x98\x9f\xb9\xd59}\xac\x87Bn(\xd7H\x8f\xaa\xbd\xf7\xe9\xe9\xa9*+(\xd6/l\x8b\xbe\x16\xef,\xb7XtG\xf7\x0d\x9bI\xce \xb0|\x1f\xef\xfc\xc9\xa5}\xc8#/\x1eV\xdceM\xf3<\xd4\xcf\x93\x0f \xc4$-\xe4.\x18\xc3!\xbf{\xd56\xa0\xcb\x1b\xe3n!%}\x08\xb2\xe0\xaa\x86\x04\x9d\x8e\xf2I\xfe\xa4u`2u\xfc\x93\xb1\xe3\xd2\x05Ln5FY,\xc1z2\x86K\xda\x7f[\xa4\xe0!I\xc10\xea\xf6\xd7\xc2\xb6\x96\xde\xf5\x05\xa1\xab\x86\xf3@\xf5B\xcf\x92\xd94\x17m\xfb\x8a\xce\x9d\xc7Ny0\x0d\xc0\x1a\xa9\x89\xbfL@\xb84\xaer\xae/\xa1\xe0M\xfd\xc9\xa5n\x9c\xad\xfax\xd9\xbc\xc2\x02\xdb\x99\xe6M\xd7\x13\xe2\xbb^1G\xaa\xca\xb4\x1c!Q\xb3\xcd\xd1\xd1\x05u\xc9\xa4\xe5\xdclJ\xaf>\x97\x08 \x8a-l\x8b\x8e\xa7\xb4\xad\x1f\x97\x07\x99\xa7R\xe6\xe3s\x1e+\x02\x8fi\x84\xef\x9a\x0e!\xe5\xe89`]!u\xac0J\xf9\x91\"\xc4\xcf!l\xa5\xec6\xf5i\xa9\x0d\xbb\xa4\xc0\x91\x0f\xa3\x9f\"?\xb4-\xbc\x13\xe9\xf3\x9eyI\xcd\xc1%\x0b\x1a\xdc\x9f\x92\x14>\xb1EQ@\xbc\xd8F\xd9&\xd4X\x94\xd6\xa9Z\x0c\x1a\x8a\x94\xed]\xf5\x00=\x00Lu$\x97H\x91B\\\xb9@[-u\xf2,\xc8\x1c\x06\x9a.\x88\x04\xe5p\x93\xf0\x96\x05\xc5\xa2\xad\xea/\"\xc4\x13Wmt\xd5\x07\xef1qlf\x15\\\n\xdb#\xf0\x8dDI<\x88\xed\x8f\x81\xc5r\xa4\xf4\xa46\xf7\x14\x08uf>\x80\xfa\x81\x82\xb8\x91\x81\xa7\x10\x15p\x8c\x8a\x13\xbf!\xb2\xb2?\x03;c\xd6I\xc5\xe7>\x95\x8e#\x18\xf2\x1f\xe5\x85f\x9b\xc7\xc6\xe9g\xb5\xa6\x96\xe2\xa9\xb4ow:\xb1\xcb\xc1\x81\xab\xbe`Zf\xfefX\xbc!\xdd\xd4\xf3\x03\xae\xe7\xe7\x02\xbc\xa8\xecr\x08A1\xc4\xcc\xa4\x91\x93\x1f\xb3\x85\xa7xn:\x1d}xc0jFA\xb2m\x17\x13\xddFw\xa0\xaam\x0e\x085)q6\x89\xab*p|\xd2\xf5\x82 \x9a\xbc\x0f\x13oF\xdaE\xe1m\xb1+(\xca\xd7\x98\xc5\xc6l\xa7N\xa2\xd55\xaa\xde\x04\xe7c\x97\x83\xe4\x8b\xe0\xbc\x1eSaS\x9c\xf7k\xc2]\xb8M\xc1\x974\xb9\xee\xf0+~\xde\xb9\xc5 K\x19E\xc3ev\xb9{\x13\x9bp\xf4\xb9\x8c\x0c\xbb\xde\xe1\x13\x7f\n=\xd95\x93)\x98\xffd\x910\x17Ql\xc7\x024\xa5\x9dB\x14\xe2\x9d\x02Y\xae\xd2k`J\xe8?i\xe6Bd%9\x13\x02\xe4\xfb\x17\x89\xfd\x7f\xabMrb\x8c\x1dj\xd6\\)=rU\xa1\x98$\xb3\xd2,_V\xf7\\\xce\xcbVD:\x9b\xce\xdej9\xa6\x93v\"I\x8fk\xbfr\xc9\x84\xd9\x93C\xd8\xe9\xe8/\xb20\x1a\xfa8\xe4vq\xc5\xbd\xaaQY\xb6\xadJ\x0f\xf2_\xb2B'f{\xb2^C\xc0\xa5 \x8b\x9d\x9d)\x8c`\xe5\xc5 y\x19\xa2[J_\x17\"e]\xf2;+\xe1\xa0\x9e\x12b\xa43=z\xf2\xf5\xe3\xca\x0d\x9dQ@N\xdd\x98\xffyE\x93-a\xf8\xa8\"\xd3}\xfa$\xd4\x0c\xc5\x8d5\x9f\xf1\x10*\xe2;k\xc7\xcd?qku@G\xec\x92\x18\x86pl\xf3\xcblJ\x10M\xf3\xe4\x04z$TP\x8e\xd4\x9ac`\xfc\xef\xdd\x13\xbd\x98\xdaF>\x99\xa5\x13-\x83\xc6\x88>\x0b\xdb\xa2\xf5\n%\x01\xe6\x15\x11#$\xd2N\"\xd2IS\x95\x97q\xfc\x0b\xdb\xe2u\x02\x92$\x90.\xbc\x10\xaeh\x8d\xa5\x17_Zl\\\xa8\\\x15`\xc3f\x85hw \xd6\x82\xfe\x11\xe1\x95\x19\xde!\xf8l\xe1\x91\xbf\xe3R\xf94\xc2\x01[\x8e+}_R\xa9pMQ\x05\x80:\x8dRI\xe3\xa8*\xd5\x1c\xb9\xc9\xbe\xab\x08\xc2l\x05C\\A\xbe*lic~\xc4\xf7\xe0 \x17\xf0\x86\xfc\x88<0\xe8\xb5\xd0\x0e\xc7\x91u\x7f\xdb\xa8\xec\xd4\xce\"\x07\xa0aFa\xb1\x95$\x85\x07\xc7\x1f1T\xd4\x8d\xe7\xd7(\xa5\xbb\xa8\xb8\x92w\\Q\x10\x9f\xb7\"(R\xc3\x9a\x0bM\x06q\x07\xfc\x04\xc2(\x05\x7f\xb9\n\xc8\x92\x84)\xa9\xd2a\xe5\x06\xc2_\x91\xd67\x10\xb5\x01\xd5\xa2\xb6\x97\x13\xc9\x95\x8f\xae\xc6\x91d8eb\xad&^B\xa07\xd4\x96\x01:\xe0\x0b{\xac\x1af\x0f\x99 }1\xb6\xdfo\xd3\xfe\x98\xfft!\xad\xc9\x13S\xd3\x15\xbfOi\xec\x8b] 5^wI_0\xd3\xb3\x0e\x95n\xe9\xce\xc7%\xc5 \xa0\xa3?N!Z\xa5\xc9\xe8\x8f?Yn\xa9\xb6\x9e\x1f\xa3\x8b\x8c^([\xcc\x90\xb0\xcf\x15r$\x9c\"YJ\xf9\x1dP\x92N\xa3,U\xde\x908\xa6\x92;\x0c\xe1\\\xb9%\x80\xb2\xc3\xb5\xce\x88X<\x0b\xdb\x8a\xc2,\xa4\x03\xb5\xd8m\x92\x08\x88\xca.\xdf\x99\x1e%\xee.\xbc\xe4=\xd6b7\xd8\xa5\x17\x8c\x06,lk\x12\x10/\xccVB\xa7\xb6\x8c\xd6\xdc\xf6\x8d\xc4vn\x1e:\xd7\x96\xce\xfc\xd0O\x16\x96\x0bKm\xf14\xf6\xfc\xd0r!\xd0\x96\x8a\xfdy\xad-\xe5\xb3saB\x89G\xf5\xe3\x90\x92\xeaYM\xd9\xb9\xb6\x8cS\x9b\xb5\xe3\xa2\x85/\xde\x82E\xb2\x96\x10\xaf\xf5\xcf\xafb?-]\xbcn\xa9/\x91\x08\xe6\x9f\x04\xfa\xa8\xf8\xe6\xf5\x9d\x19\xaf\xa2qm\x913d\x86{\xd3\xc68P\x808^2\x18\x91x_\xe4\x11\xc2n\x14N\x88\x00\x0dZ\xbeu\xa3\xb0\x04e=\x9e\x07\x8d\x14\x174v\x15Mrz;\x01B<|\xb3\xbe \x9fs|\x92\xd5\xba\x8e\xa2\xe5\xc5\xf3\xa7\xf8{{\xbb8\xcf\xca\xb58\xfc\x8c+\x8cQ1m\x886~(h\xc1\x7fc\xeb\x84-\x06\xe3b\x17\xe8A\x8cx\xa8\xd1-\xac\xb9+9-3#\xd2\xda\x9c\xab\x171\x89M\xd0\x05\xa1\x12\xe7\xd4*\xcd\xadq(\xfa\xb2\x83\xdd\xees\xa9\\\"\x97\xe8}\xc4\x89\xbb\xf0<.Ux\n}Z\x89\x87_=\xb1\x0b\xfa\xcf\xe3t\xae\x04\x135\xf3\x82\x84\x00v\x0b1IVQ\x98\x10\x17\x84\xady\xa8^\xc0\x96\x96\xb8\xa6\xb4\xd3\xe1\x93C.\xa4\x8b\xedm\xba\x1b\xaf\x1b\x80(H\x15q\\8\xb7\x1b\xa9\x19C8\x86`\xec=;\x17\x14\xc6D\x17L\xb1f\x90s\xe3\xb6j \xcc\xe7Z\nb\xeehYO\x9bx\xdb\x8d\xc7\xc5\xa6\xdd\x9e\xd7u[\x1cva\x97\xfdnw\xf6\x0by\x96\xed\xc4\x9c\xf8k\xbbi{;\x00P T%\x1b\xfb\xaeb\xb2\"\xe1T\x00\xa5\x08P\xae\x96\xb0h\xcd5*\xf4\xee9\x9a\xf0%\x0cy\xf8\x1fcr\x06\x07\x90\xd9\xf2\x0b\xf4n\x92\xfe.[d\x95>\x1d\xc18tK\xaf\xce\xb0\x8a\x08\x1e\xad'x\x12*\x8b\x03\x9b\x1d(e\xfe\x80\xbdS\xb8\x02\x86\xf4\xfc\x9c 1f\xa1 \xb4\xfcn\x0fY\xb1\xe2F.\xe4\xb7y\xb6S\xb9\xd4\xaf\x18\xc1T\x18\xf3Z\x9d\xd5&*\x03\xf3\xda\x17L\xd4P\xbdL\x15\x8f\xc6\xc9\xa5\x90\xc3I\x89\xa3\x17\xd8\xa1\x0d_O?\xea\xd7|T0\x97\xbc\x9c\x07\xccfV\x1cBb\xe4exT\x96\x1d3H\xc5+\xa3t\n\xf6\xb95\xbcX\xc4\x9c]Hy\xc4YnH\xaf\x1f\xf8Vmp\xd2\xb8\x18\x98Y\x83\xedCy\xe6\xfa\xcd\xb2\xe9\xac\xf4\xad\xe4\x8a4\x16\xe7\x1a\"x\x02\xfec\x88:\x1d\x07\xe2qtf\x82A\xad\xc2\xb6b8\x04Z2\xb5\xe61\xdcNlR\x9c\x9f5:8D\x89LZl\xfeY\x97eg\xb03\x17\x9d\x97K\x80\xd8F\xc9\xa7\x8aM\x9c\xf9\x11 \xe4\xbf\xc6\xbd3i\xf7\x9a\x16\xbensF\x95\x1b\xd7:\x899)}Y\xb8Ap\xc3\x0d=\x861\x8a\xce8\x13'gm\xcc\x06h\xb9\xeaA\x10\x18\x8dRY\x84,)lVD\xfb\xf5\xb8\xdcJ\xa8\x07\xbc+*+\x91c\x8d\xcb\x11\xdd\xb9\xba\xf7\xecB\xa4\xa2\xc9\x89\x0d\x0eM\xb1\xa4\xec\x8a%}\xceq\xae<\x94\x04\x85K\xbe\xa6\x9b\x1c\xabu\xeb\xefM\xf3\x93\x0eF\nf\xb8\x8a\xaa\x18m;Z\xc4cL\xdb\x02:?s\x95\xa3\xa68eR\x85\xddo\xc4T\xe0f)eC\x13a|T1?)\xdf@\xbc4GP.\xa2\x9c\xeb\xec\x0c\x15=\x14\xe5n\x9b\x00U\xa8Z\xe9.b\x1c6\xf0\xc92\x1dG\xcd\x16q\xdc\x96\xfb\x08\x0fnd\xde\x0d\x16\x94\xca9R(\xe6\xf8W-\xa6{\x15{\xab\x8dN\xf7\x9a\x1b\x80\xb6g\x7fl8\"\xf2\xe3\xc1\x07?\xe4\xa2\x1d\xd7B4\x89\xbd\x94\x9c,l\x8b\xcefE\xa6\xc0\x85\xfb\xb0\xec/!t\xf1\xf5\x92s\xca,\x1f\xda\xb9A\xf1\xb3[\xbe>0i\xcd\xc0x\x8dI$S\xed*\xf2\xe6\x9a\x04\xce[\xe7\xb00&\x1e\x94!!\x84\xd3\x12(l\xbf4G&\xa7\xfa\x14]\xb6B\xc5o$W*\xa3\xa6^\xb2\xde\xf7\x99Ho\xab\x1f`=a\x95\"\xc4~\x9c\x9f\xef0\xa2+t\xe3\xb9 \xa9\xdb\xb2\x0e\xdaLJ>S\x14\xbb\xc6\xfe\x19\x94\xe3\xd2JR\x01/\xb4EE \xa9\x9b\xdc\xed\x1b\xd1K\xaa\x9bR\xe6\x9f\x87\x81\xadM\xe5\x07\x065\x86\xaf\xbb.\xd7qF\xf3\xfc\x8a\x11\x19$D\x82\xf98:\x93vz\xf7\xc2\x0f\xa7\x9c\xba\xd1\xa2\x1a\x8f\x9cT\xf6\xa6l\x86\x8c\x84B\xe7\xfc\xfe\x908\xc2\xfb;\x16\x14\xa7\x10#\xaa\x13\xd5\xd3\x9e6\xee&\x82\x84\x94|\xbb\x9b\xa3\xd8hL\xaa6rM\xd1Q\xd8\xd2\xc5Qu\x8e\xe5\xd9\xa1\xdf\xc7\xf9,\x8e\x96\xf4T\x86\x11\xbc\xfb\xa7\xa2\xac\x1c1\xdb\xc50\xd8\xed\x02g\x97bpW\xa3M\xb4iB\x1fNc]\x84\xbaz\xa4\x8dI\xeakO\xea\x1a%\xcb\x8dv\xd0\xe5\xcf\xb9\x1bK\x0b\xbb\xa3[_\xf5@\x93\x1bQMd\x01\xfc\xac\xa2\x9c\xd6\xbc.Z3\xee9t\xb2\xce\x98\x9b\xde\x01\xfa\xe0\x14\xc6\x9b\xed\xfbA8\x97\xb8\xd9\x9c\xe7\xf1\x85\xb8 |,\xd0Z\xc7\x00\x91F\xcf&\xe9\xde\xb420\xbb\x16\x02\xe5\x8f\xf9k;\x8f(\xee\xb6Ppo\xf1$\\\x07\x94-\x97'\x18\xb2\xd9\x85\xbaA\xa9/\xcb\xb0\xc2A\xe1\xed+\x9e\xccZu\x96A\xcc*\xfd\x99;d5\xd0\x92[\xc3\xbd\xafg\xef\xe2j\xf4\x85\x8a\x0b\xcd\xb4\xb6\x05%\xaa\xc3\xe7,o_\xfb\xadf\x04\x95ru\n\xe5\nL\x95U\xdf\x86\xb2\xa8\xaaO\x95B~>?\xf6\x9f\xec\xa4\xc8\xb0\x12#H\x84\xec\xd4\x9a\xca\xe1\xf0\x13\x12\xcch\x15\xfc\xf7\xd3'\xb8\xf2\xc3itU\xa5/\xbe>\xb272\x12&_&}\x00\x7f\xc81\xcd\x9f\x16\xaeS\xdds4\xc4~\x816\xc8\x06\xf0\x00\xf2\x9a I\xdf\xf9K\x12eiK)'$W\x10\xd9>;\xc0\x8a\xaf1\x1cB\xc1\xff\xb8\x80\x03\xe0\x85\x15\xb5\x05\xf6\xfb2LI\xbc\xf6\x82[v,>\xd7\xf7,J5]\xcb#C\xfdK\xe9\x83F\xf1\x873\xf9\xa8\x88\xad&\x96\x8fJ\xda\xd2\x98\xcc\x94\xec/\xec\x8d<_\xe5#l\xb7 $\xa55f\x10\x89\xdd\x1c\x0f4s&a\x1c\x05A\x1b\xfd\x90\x0c\x1d;\xa5\xcd\x05\x84\xff\xf9r\x8a\xd2\x87\xfc\xaa\x8a_\xb4\xb7,\xd4\xf4w'\x9d\xa9\xd6p\xb4\xb7s\x84\xf3\xe1$\xf5\xd7\xe8'\xda\xf5\xc4\xcf\xcf\xe9\\\x7f?\xc8/R\xa5\xaa\x1a\x8dV\x91bQm\x15FPl\x99\xe6\\ri\xf7<\n\xc5\xe4\xd9\x9dD\xfe\xb7\xee\xb2G\xe3q\xe5bD\xab}G\xec\xb9\xe5\x92L}\x16\x9b\xa5\x99\x84\x95\xbfP\xb2e\xb2\x01\xa95(\x0e\xe6\xac\x8b\\\x98\xef\xbc\x0d\x87\xa0|\xa3\x1dD\xb5Ni\x18\xe5\xe2\xe2|\xb8M\xde\x9a&\xde\xd9\x14P\xcdGU\xa2\x9f\xc8Q\x88\xea\xd1S\xd8#\xe1\x8d\x82eA\x07R~\xab\x99F\xdfDW,W\x8em\xb4\xfeF\x13\"kA>Zz\xd3\x1eV\x8eq\x90\x1a*l\xd7\xd7\xf0\x92\x89\xef\xd7\xd6\xb8\xf0C/\xbe\xae\xaf\xe2%d\x7f\xb7~$\x93d\xd0Ta\xbb\xa1F:\xeb\xef\x07\xa4\xa9\xcevc\xa5\xd8\xbb2\x94\x83\xe4\x9fm\xc8+\xd9hq\x95\xfbwWwxys\x1b\xf2\xfc\xe8\x18\x19Ee+\x90\x0b\xf7\x07i\xeb\x07.(`3\xff.\xae\xa3\xf8T\x18\x9e5\\\x03\x91\xc7\x8f\x9db`u\xca\x97F\xdc\x85V\xf8+\x9e\x16\x83\x846h\x08\xadP\x11Z\xa2#\xb4EI\xf1H\xd3\xc0\xdaM3 \xbc\xd4\x0f\xfb\x8d\xbd\xd7\xee^\xf1\x88\xbey\x9bM]\xd7nwhEZ\xa0\x05\x8d\x13\x8fP\xe9\x98\x87\xd5\xb8'A8X\xd4\x87\xd8\x12\x0f\xa5\xd96'\xdaez\xcdbQl\xf5\xb4\x9f\xeb4\x84\xba{I\xbc/\x13\xd12\xb6\xca\xc1\xc5\xed\xd213\x1a\xf1X\x85,\xbdQ\xd5'\xc4z\x1f^\x86\xd1U\x08\x82\n\x0c\x81\x0d\xdb\xa8\xc7`\x07l\x99\x12\x15a\x1d\xf2\xb8t:\x8e\xab\x05\xdac#)\xf9(\x92\xc6\xb06)\xe74a\xa0\xd3Dh\x04\xb3\x89k#\xa9\xc0\x0ef~\x10|\xe3\xa1\x96\xce\xbb}/\xb5X-\xcfkV\x9aW\xc0z\xdc\xd9\xa8\xc7Z\x84\x95U\x98\xcc\xfek\x04+\x96f\xdc\x96:^\x98$g\x10\xe3\x0d\xbc$}MP\xce\x16\x81\x11\xe9\xabwQ\x8a\x82\x92\xfc\xeeh\xe11\x8f:\xd9\x1b\xb0\xa4\x0c\xcc\x7f\xe6gUV\x13\xd6\xfa\xc9\x08\xfa\x83\x07\"c\x03<}\n{0\x1a\xc1>\x1c\xc0@\xbc\xd9\xa5o\xfa\xbbp\x00;\xe2\xd5\x0e}\xb5\xd3\x83\x03\xd8\x15\xaf\xf6\xe9\xab\x01\x1c\xc0v\x1f\x86\xb0=\xa8\x1d\x92g8>\x852\xb0\x98\xfev\x19DU!\x7f\x13\x07h\xb4;\x19<\xa4{\xd9\xee?\x1a\xc0=L\x0f\xebH\xb6L\xe5\xa5\xb0\xfe\x9f\xff\xeb\xff4PY\xf40*\xaas{A\xc91\xac_w\xb4\xea\x06\xd27\x0d\xa4_;\x10\xd0\x0df\xa0\x0c\x06\xffV;\x1c\x98:\x1c\xf0\x0e\xdb\x13O\xae\x0f}\xacC2I\x90\x08\xd1\xbd~\xa8`\xfd\x13\xc9\xd7\x0c\xa3y\xa1Wf \xe5qY\xe5}@?t\x94}\x91\xa7l+\xf3[nuS\xb1\xa8`\xb5\x1d\x89\xcb4y?\xe7#\xde\x96\x02\xa0\xd5\xef\xbdD\xab\x01\xa0\xebe\xa7\x85'\x10q0!\xf9\x08\x1dWjt\xf2\xc5\x0cs\xf2n\xb6\"\xa9\x0f\x03\x80\x97\x91\x93\x85\x17\x1fESr\x98\xda\x92\x07\xac\x1aWZ<\xb4\xd1\x98J\xdd{{\x83G\xfb\x80f\xf9OF\xb0\xb7\xbf\xd3\x7fT2\xf8Rp\xa9B\xd0v\x95\x85\xe3)\x9a\xc7\x12D\x06gj\x9d~\xa5N\xff\xcc\x85\xb0pS\xd7\xe6\xd9\xae\xbc\xd1\x9bxh\x89\xa32\x93\xbef&\x83\xe6\x99\xf41\xe5\x85v\xe1\n4C\xa8\xd7\"R]\xaa:\x90\xef\xc3\x0f\xa4\x03\x89]~X\n\xe5@jQ\xdaH\x0d\xf7@fr\\\xc3\xbdtL\x9bS\x82@\xaf\x1a\x0eL\xb7\x12\xa4\x1623\xed\x16\x13\xe3\xafl\xb3\x1d-\x91\xeaq_\x93\x83\xd2ZqV\x83\xbb\x9d\xd9*F\xec\xc06\xde\x94\xa8X\xb1#\xec\xd1B\xb1\x1a\xb5\xf8Qj\xfa\xb3\xf6\x83\xe3\x1a\x86_\xc2\xb4\xb0\x81f\x05w\x87j\xda\xadtP\x8b\x1d\xf9\xa0{.\x02X\xc1\xd4a\x036\xac\xcc\xcc\x8e\xe1|\xa8\x07\xc6\xa2\x86yj\x82\x85\xd4\xb0\xf8E\xca\xd1\xdcX\xc6\xc7\xa8d\x1b\xe4\xa7\xf5\xc2\x7faq\x9b\x9fA\xb9`\xa8\x80\x1f\x97\xcdU\xdd\x9e[\xed\x7f\xbfHB\x87\x9e\x989k&\x98x&\xe7\x18:\x06\xd9\xba\xf12u\xbd\x84\x02>\x1e}\xae\x9a\xdeJ4\xb2\xbd\x8d\x83\xa1\xab\xb7=`bv\xdd\xc0\x90\xb1\x92F\xe6\xb4\x1e\xc3\xe0\xf7\x1f\x03o\x0bC\xef\x8cD\xca\xbc\xf2\xa8v\xf4\xa3\x12\x9d\x97\xb7\x8f\xd9\xb0\x98\xe9 \xcb[\xbeJ\x15E\xb8~\xf5\xeb\xca\xf9\x16V\xa9\x8c\x1c\x9e\x01\xb6\xc1\x0e+\x94[\xbf1\xb4,x\x8f\xf9M\xeb\x86FKL\x1bFR/\xd4S\xcf\xf2v|\xa2!\xa4\xfaq\xd5\xf3Bw*\xa0(+p\xeb\xe1\x14bLy\xd2\x92\x04\xa3\x9cR\xb7\xba\x99)e?/^\x17\x176\x035y\x1f\xcfq\xae\xcf\xcb\xac\xd1\xae#\n#\x04J\xd9T\xca9\x13\xa2j\xda\xf0\x92\xc9}n\x8b\x91\xc6^\x98\xcc\xa2x\xc9\x8c1tn1\x18\x17\xfc\x9d\xa8\xd7\xc2r\nT\xaeY\xe9E/T\x85\xdd\xbcV\xbd\x1fG!\xb5\xe1y3\xb90\x0bi[qY\x1c3\x06\x0e`\xcc\x06\x85\xd0\x857\xb9\x14qj\x96Y\x90\xfa\xab\x80@\xea/Ib\x8cw/\x06\xb2\xc8\xc2\xcb\xdcG%\x1f]\xf1\x86\xa7\xec*L\xadx\x1aWW\x93O[<\xe2\x80apl\xe1}\xe0+\x86;\xb6_ k.\xecc\xe1 \xf8\x9a\xa8\x1bEW\xb6Z\\\xe9\xf1\xa6\xb0\x01\xd58\xdd\xd1\x8e%\xc4\xd1\xd9H\xcak\xae\xaf\xc1\xc1\xc8\x82]\x98\x8a)\xe8kk\x14\xdafZ\xa9|\\\xe8\xad\x97t\x0154\xd5\xa4P\x1e\xb5\x89E\xf2\x89J\x06O\xc5\xbb\x91\\\xc3\x9cgd\x16d\xc9Bj\x80\xfd=\x12%\xc2\xe4\x1e\x0d\xb6W1\xc9\x1d\xf5\xb2&\xbd\xa8\x8e\x9d\x12\xbe\x18e<\xd3\x8fL\x1a\xcd\x81\xfcW)g\x9a\x96\x19\xf3r\xdaZ^\x14\xcaDz\x9c\\\x15\xfb\xa7~\x1e\x9e\x89\xeb+\xdd\xa4hLH\xabLB)\xb1`Z\xc4\xba\xaf\x84 \x10\xe7e\xe5\x9e\xe3\xc8\x0b\x02\xba\x0d\x8bE\x9eF!\x81\xab\x05 \xe1*\xcf\xa8\xb45\x82\x9e\xa5\xe9?U\x89f\x89:n\xd8]\x92\xfaAP\xdajj\x979d4\xbe\x00\x85\xcc\xe6W\xf2\xaa\xb9\xd2;;b\xdcJ\xb4adw\x99@\xab\x93.Q\x90\xdc\xe9\xa9\xdc~\xc5\x97\xac\x18yy0\xa5\xfd\xd6$(T\x00\\|m\x080c\xec\xb6*\xc9\xea\xbb,{\x9a\xd5\x9d\x99(\x9b\xc8\x07\x0c\x85J\xe9\x10J\xf37\xd2m;qa+V\x10I/\x1e\xb5>r\xecXY#<_\xbe\xd0\x89sc\x04\xb1\xeaYP\x7f\xa9R\x0b\xdb\xdc\xe7\x84\xc8\x10\xc5[\x04\x01p\x16B\xb8\xc4\xae`\x0c&\x95\x81\xe9U\xb8,[n\xd4\x15M\x16\xfc/\xe9\x96\xb9-f@\\\xdd\x06=#$Z\xe6i\x90\xf93\x95Q\xac\xb6\xa6l\xb1z{\x0c\x96{=\xe4D\x969\x90\xab\xc4]!.\xb7b\xb5%\x9eZ\x97\x89\x17sH\xcaBQ\x14\x1f{\x93E\xb9\xa2\x94\xe2|\x12\x93\x12.\xb4K\x8b+\xf0*bDSKU\xb9\x0din3\xda\x04@Lgz\xef\xde\x06\x8c\xb6\x9e\x15DK\x97\x10\xbd\xd9\x1c \x18\x04\x10\xd2qxV\xa9|c\xf3\xb4\xb8\x18\xc9X]+\xb7\xa4h\x84\xdb.\x97\x16\x9e\x0e\xfc\xfd3\x9a\x940`\xc7iZ93\xcd\xf5\xf5\xab\x96\xbc\xf6^\xdb\x98X\x16\x95\x18\x84\xa9/\xf0\xe2\xee\xde=\xae\xad\xd8\xc6\xc4\x0c>\x86\xb6\x1e\xe6\x8e\x95x#\xd4\x9c\x1d\xb9\xd5\x1c\xcb\xfe7\xbb\x0f\x06\x8eM\x87\xc4\x91\xd6K\x12\x7f\x1e\xc2\x10\x8bv>\xd7\xa2\xd0\x05\xdf\xc5Tr.x.\xcf\xe6:P\x13\xa4N\x9aH\x0b\xe8\xee+\xe8#\xe7\xcc\x8f\xaf\x95\xaf\xf4\xaeY\x13\x17x\x08@\xad\x07\xd6$\ng\xfe<\xab\xc9$.\x985\xbdl\xd1\xe4\xc1\xb5\xf6\x82\x8c\x0cA1\x02\x96\xd6\x15&^n>V\x9cN\xec\xcec\"]\xe5\xc6\x15\xc9\xba~\xe8\xe6a\x97\x87\\\x8c\x84\xc55\xd4B\xd1\xdd8\xa12\xa5h J\xa6\xb9*k\xc4s\x06\xa60\xa4\x87>B\x86\xb1\x14\xe8\xa7U\xacR,_\xaa\xe0m\x11\xcfn\xfc\xe8\xa1\xe3b:\xd4\xf1\x19\xcbl\xdd@U]\x9d\x02\x9cr>\xde8=\xcb\x99y\xfaG\xb9\n\x92=\x82\xfd<\x86t{\xfb\xb1#|\\-\xcf\x82\x0e\xd8\x9dN\xe8\x14\x1a\xa8\x9d}U\xae\x97\xf4(\xc2i\xc2\xb6f!K\x98\x8bE\xb9\xc4a\xd3\x06 \x0fq\xef\x82\xe5@\x87\xfe\xef\xef\xa2\x8dY(\xbc5\xf1\xec,\xdc\x06\x1e\xc3\xcd\xe32\xcb\xd8z\x8d4\x14\x1f\xe5\x1b\xc3\x9a\x15b\x8f\xc2\xe7\xe0\xa9E\x9c\x8a\xea\xa1\xba7\xe9\x93\xd9\xe8\nU\xde z\xf4\x07\xdd\xed\xf2\xcd\xe7\x12'&r\xe8\xb2\xad\xeb\x91\xbeTM:\xe7\xe7$}s\x15\x8aj\xcfI2\x89\xfdU\x1a)\xf6\xd3\x99\xe9\x83\xd7\xdeR\x0dh\xe2\x99\xea\x9e^//\xa2 iq2i\xd7\x98\x91`~4\xc76Q\xf1\x14\xe5D\xb9\x06\x86\x18\xc8\xec\xc4\x11\xccN!~kC\x0d\xeaW\x1a\x9b\xb6\x99\x87M\xc4\xc2\x14j\x14?\xf2\xd2k\x9b@\xee\xb2\xfa]\x19\x81L\xaa\x0e\x0f0\x82\xdb\x7fY3\x91\xed{r ]/g\xffS\xb9\x95\xcf\xdc\x15}\x1d\xff\x1b\xda\x0fUUs\xa4w\x03\xa3\xdc\xe9mq\x94\x9ek\x9a,xt\xfb\xe4\xc4n<8\xd3B!Fj\x85\x0b$w\xc4\xd8\x10O\xb7\x1a\xe18>C\x07'\xe1H\x91\xa1<\"\xbe\xa8\xacH\xd8\x00g\xb9\x8fv\xfc>\x1f\xfa\xd6\x16W\xf6\xb1\xf0\x03\xe5\x14r\x9f>\x19\xb4d\xc8\xd5\x9b\xf4\x83\x0b\xd24\xdaVX\xa1\xe7\xa3\x88\x0b\xd6\xf99I^E\xd3\x0c\x0dN\xd4\xa5D>G\x16+Yt!/N\xc8\xf7\xde28BnE\x93\x16\x7f]D\x88\x0e\xed\xbdAO\x83q\xc8\xfc\xb0\x80\x0dq\xb7\x18\x04\x1c@\x0cC\xcd\"\x0bSS5\\p\xd1\xa9n`\xb5\xa8\xaa'\x0f|-#\x91\xe3\xaf\x9bx3\xf2M\xe4M+ \xacjID\xce3\xb1\xd0\xc8q|\x88\x03I\xba!\xb9zG\x89@x\x1c\xc7v\xa1IB*\xad\x1c\x97\x1bz\x916\x11\x84\x9d\x87\x06q\x88\x8e\"\xb6\xcbs\xf0\xc3I\x90M\xc9\x10\xc6\xa1=\xe8\xed8g\x12\x12\xfcC\x07\xd3\x1f\x0c\x9c3\x85\xb0-W\x81?\xf1S,\xdf\x1b<\xc0P\x06{\x83\x87\xfc\xdfG\xec\xdf\x9d\xde\x1dM\xe2N7S\x10y\xcc[\x99t\xdf\xbd\xf9\xea\xabo\x8e\xcf\x8f\xde\xbc~\xf1\xf2\xabS|\xf5\xfe\xed\xf3\xc3w\xf2\xab\xda\x9d6\xe8\xed\xfdN;-[M\xbd\xaa\xf6\xd2@\x165\x07\xf3\xf5\x8a\x0c!\xab\x9e\x10+\xef\x9a\x02d\x08v\xcf-\xb6\xa0c\xff\xfdF\xd5\xe2\x02(\x9a?\xd2M\xa3\xf9<\xa87\x0ej\x18\x91&\xabJ>\xa2\xd4\xd4uy12\xfd\xbaYL\xb2K\xce\x19\xe4\xac*\xaf\xa8Y\xff\xfc#63K^\x81\x1cod\xad\x89n\xaeU\xad\n|\x1eA!2\x12\x8dJ\x0ef%l\xec\xef\xa9\x0c\xc8\x97\xc2F^\xa7\x85b'\xa7\xca~\xc8\xe2:\x94\xd1\x8c}U\x1d\x04\xdf\xbca\x83\xae@\xa3i\xd8H\x17\xa1\x18\xac\xa0\xa9\x16\x8b\xde\x19\xba\x9br\x87\x94\x1a\x10\xf9\x1c\x18\xdeQy\xa1\x8f\xb7\">\xdd\xd1\xd6%\xb9N\x90\x91&\xdc\xa3\xc2\xc2\x1d\\\xbc\xc3\xe47C\x16\x14w\x1c\x9e\x9d\x95t.\xa22\xdeZ\x1e\ny\x05%\x0c\x0e\xe9\xd8f]\xa0\x91\x86T\x1d\xc3\xd0\xa7\xb1O\xff\xd2\xe2O\xa3haT}7~\xb9\xd1\x01\xcc \x9a&\x18\xde4\n))\xda2\x1ew\xb7\x1c\x9d:4\xbf\x1cJyK\x96\x87\x98\x90\xfc\xeezE8o\x0c\x1d\xb0\xc4\xed\xaa\x977\xbae\xba\xafn\x18\xec\x86\x9b\xf8\x91~\x0f\xef\xedj\xb7\xf0#\x95\x05\xcbP\x18.\x1a\x0e\xed\xc1\xbecg\x94\xf2\xec;\xb6\xe5\xa7$\xf6\xd2(\xa6\xe8\xd3t\x94\xa7r\xf0\xb2\x1b\xa7F;\xa8\xbb\xba.h&\x8c \xa6#\xa8\xe2EH>\xa6t\x13i\x12\x91\xd3\xdd\x80m\xe3b\xbc\xcc\x87\xbd\x19\xb0%\xf5\x84\n?N\x1a\x1fh\xc1\xba\xdb3\x93\xc0=\xe9\xea\xa3\xc4\x94\xfb$i\xca%\xe8W\x14\x9dEf-\x17\xd7.B}\x04\xe5\xd02N\x81\x98\x06\xae\xf7\x18\x85\xbd\x07;\xbb;\xbc\x7fV\x1f;\xa2\xc8\x82\xce\xdf\xf4-\xf3\xc2L\\\xecd@\xcb2\xd8\xe6\xcdt\xe88\xb7\xf9\xa0\x9e<\x81~\xcf\x81\x0e\xec\xef\xed\xed\xec\xdf\xcd\xa6\xaf\x1c\xa9\xfc\xe0\x18\xf4\x8dg\xea\xc0\xe9\xceI*\x0e\xf9\xe6[Y\xa4\xf3\xeaIjd\xf1H\x03\x8b\x87<\xd1E@L\x0c^l\x13n{\xe4\xdcz'\xf6w\xf4\xd7#\nOV\xa10(\xa4\xb5\x03\xdb+\x92.\xa2z\x034\xc9\x8dl\x0b\xa3\xcd\x0b\x9a:\xf6\xcf0\xc0\xc5\xd8\xfa\x97\x7f\xc9\x87\x83\xaf\xa21\xa5Ng\x9b\xcd\x9b\xae\xf6\x0eJ\xbb\xfd\x1d&\xf5\x0evv\xf9\xbfLM:\xd8ej\xd2\xc1^\xaf\"\x0e\xf7\x1f9B\x14o\xd3Y#C\xad\xc3G\x99E\xf6\xc7\xa1\xddwlK\xdc\xc6\xbf\xf3\xe6\x96s\x06#\xb0~\xc1L\x8d\x1d\xba\xcf\xb7F`\x8d\xd9E\x0b\xfcrf1\x1d\xc1N\xcf\xe1VK\xa5\xe8\xbd\xa2\xa1\xba\xb0\xdd\x1c\xf2y\x9b\x16t\xe89\x80\x01L;`\x9d\x95\x9c\xe3\xb6\xda\xe9\x07d0n\x85\xf6\xee\x80%G\n\xed\xdd\x1d\xc7\x1cx\x8d\x8f\xe4\x01\x9d\xa2^\xd7\x1c\xda\x8f\x1e9\xb65\xf5\xd7Tl\xb0<\xad\x19\xccF\x81\x86\x1fT\n\xd5\x9b\xcc\xaeW\x00\xa0\xd5\xe4%]\xbf\x89\xd0\xd4\xb3\xe6\xe8\xaa\x81'\xb1\xdeV\x813\xe9~\x95\xea\x10\xd3\x95\x9a]\x8e\x13\xc0\x96#\xe6\xb1\xc7\x05I)|\xd1j\xe9\x99\xda(\xca\xd4of\x9b\xb7\xb9\xf5e\x86\xab\x92X\xeb\xc8\x0b\xff\x94\xc2$\n\xd7$N\x81\xa3y\x1a\xc1*\xf6\x97>\x06+\xc4)l*\xd25m\xf7\x81\xe1\xfc\xe9\xef\xe8%\xe8~O\xe5_\xaa\"t\xff\x01\x17\xa1\xfb\xff\xaaE\xe8\x87\x86\x83]}\xcf\x01\xbb\xab\x03,\x05x\xcf\xb1\xad\x97\xc7\xe7oO\xde\xbc{\xa3\x1ez\x9e\xaa\x9e*\x17\xab\xda\xab\n\x15U\xba/F\x8c>?\xf9\xe1>/b9FxXV&\x1e\xa7\xdd\x17\x8f!F\x8b\xb3) HJ\xe4\xac7\xe3h\x1c\x9fir\xa6\n.W\x8d\xed\xaa\xa7\xa3%c\xe5rP\xc7v\xa6b\xbc\xbb\xdc\xca\x1d\xefF<\x05\xdd\xd1\x80\x1b\xd8\x0d\xad\xe7B\xb9\x98{\xe3\x8c3\xb4'\xc6\xec\x93hzVX\xc0\x8c$}\xac\xcf\xb2\x19\xdf\x16\xf1\xf7\x0c\x14\xc5\x80\xf75\x1c\x1b=\x92\xff5(\x8f\xf6\xf4\xa4b_wEG\x99\xc2\xbeco\xb5\xa3\x16\xb78\xd99\x80<.5T\xe9\x00\x82\xa8\xfaz\xc2\xcc7\xab\x10Gsv\xcfaJ\xa2\x8c\x19Z{\x08\x8b{\xf7`\"\xfc\xb44\x1f>\x96\xa3@\xe1j\xe0w\x94,\xe0Z\xb0d!\xff.\xb2'\xd8\xda\xa7OEk\xfa\x05\x9a\xdcv\x81vM<\x12\xb7\xe3\xb3~\xb1\x1c\xba\xe1\x90\x01|\x99\x1c\xe7\xf7\x8ev\xaf\xc0\xe0\x12\xc2\x9a\x18\\\xce\nS.#f\x96\xec)&\x10Km\xcb\xa2\xfb6\xb7\xfa\xbf\xedT*H\xc5pmWg\x9c@ \xb6I\xb5\xdb8\x95\x92^\xe2\xdf\xf4\x94\xff\x15\xe9)\x0d\xe4j\xb0\xa3\xfa\x1dD-8\x18\xc9j7?\xb1j\xcf\xd19I\xdf\x8a\x8aof\xf5A\x92s\x90pZF\xf7\x94\x0b\x11n\xabqt\x06C\x93i\xdf$\n\x934\xce&i\xc4r\xe3\x83\xe4\xb7_.=(\xff-\x1d\xbb\xc3\xf2g\x9c\x08\x1c@\x06\x8aG\xf3\x86\xe0\xef\xdfzK\xcaV\xc7\x9b\xf5\x9e\x1f\x9d\xc2w\x07\xfdH\xf3\x03\xdc\x15\xda\x97\x9e\xe3\xf2\x93h\x8f\x1f\xad(\x0e\x08\xcf\x94\xdd]\xc7\xc5\xfdLe\x03\x177\xed\xa4,\"\x04\xecUI\xb9\xc0\xf2\x82'\xe2~wQq\xcc8:==\xc9XN\xbe\xaa\x19\xc7\xd1\xe9\xe9)eH\x9f\x93I\xe0\xc5\x1e\x9da\xd5E\xe3\xe8\xf4\xf4\x03\x15\xafx\x13ji\xe0\x930=!\x93T_\xfe\xfc\xcd\xab\xdaB6\x17c\xf1\xbb\xe8\x92\x84\xfa\xc1?\xf7R\x8fy\x11\x92\xf8eJ\x96\xfa6^\xf8\x81a\xe4\x7f~\xf7\xea\x9b\xc3 8\x8a\x82\x80L\xf4S\xa7U\x9a\xca_D\xf1\x92k\xbb\xf5\x15N \xfd\xdeX\xe5\x15\x99\xfa\x9e~\x86\xaf\xfc%\xa1b0.n\xf5\xcb\xd7\xde\x92L_GS\xf2\xca[iJ\xa3\xa9a\xd5\xdfz>]\xb1\x9f3\x92\x18\xd6\xe5m\x90\xcd}\xcd|\xd9{\xc3pN?|\xf5\x0d\x1eC\xfa6O?|\xf5:[^\x90\xd8X\xfc\xd6K\x17\xa7\xc4\x80\x0b\xb4<\xf2C\xc3\x80O?|U\x87H\xa7\x1f\xbe\xca\xfdM\x0d5\xa2,\x9e\x10\x16z\xdeP\x83n\x94\xd3\x05!\xa9\x1e\xaa\xef\xc8\xc7\xf4]\xecM.\x8fL[%\xafa(\x8e\xb2I\x0e\xbb\xbc\xe4\x86\xa5\x0b\xf7m\x0cY\xc98\xf05<\x81\xa9\x904a\xdd\xe9\xe8\xf8\xd4k\x17\xe60\x82\xe9x\xad\x18\x9d\xd2g #X\x8c\xe7\x9a\x92sd\xe7u%\x170\x82sJ\xf1\xcfu\xa7\x11\xf0c\x18\xdd\x89\xed\x0bz\xf6~\xfa\x04\x9e}\xe1\xc2\xcc\x85\x95\xe3\xc2\xc58(\xde\x05,\x07s2\x9e\x9f\xb1\xe8\xbaK\x8d/\x03R\xd6kz\xa2\xc7\x0e\\\x8c\xaf\x99\x1a\x99~~\xedB<\xbe>+\xf4\x99\xd0\x96Z7*}\xb4>9\xf4\xbd\xe1~_\xd5\x05e\x82\x954In\xfd\x9d\x07\xfff\xf9\xf4_\x8e\xe5\x93\x99\xd7pl+\x0b\x93I\xb4\xa2\xd2L\xa22o\x1a\xa7m \xdf\x84f\x01\xfcq|\xc6\xae\x00\xfa\x0f\x1c\xdbG\xef\x8f\xbf\x9b\xf5{\x15I~\x1c\x9f\x8d\xd33\xc5\x89^;\x11\x93~\xbf\x16\xf5\xf8\xa2\xea\xc4\x93\xbb5\xc4j\xbfMe\xb7^\xbe\xa1T\xa6;\x11lV\xe9-c\xae\xf6U\xab\xa8\x19\xbe\xae\xdc\xed\x04\x8ckS\xde\xae\xd8[U\xc3\xb0`M\xab\xaf\xa7\x9ct\xa8\xd6\x91k\xf6~W\x1d\xca5\x17,\xd5^\xe7\xfc\xfd\xae\xd3M\x88\xb2e\x97\xbc\xad=\xc7V\xbe:\xe7,\xb1*\xd5^\xf0\xd6T\xf8\\\xf1\xf7*\x01\xfc\x88\x1cf\xae\x8fW\x8eE\x91\x0c{B\x12\xc5\x91\xf0\x18\x8b\xf8\xfd[\xb9\xe8\x10F`\xf1\x8fp\x87\xcf\xecS\xa5\xd77\xf5\xea\xdb\x9f0\x92\xde\x08\xce\xbb\xb3r\x01\xa5\x84[[\xf5\xaa]\xb3\x7f\x9d\xa0\x8e\xc7\xdd\x98$Q\xb0&\xb6\xba\xa6\xf2CX ZY\xe6\x19\xd1\xdd\xcb\xaf\x01\x93\x15\x99 a9\xab\xdd\xc3\xea\x93\xdao\\xc\x96v5\xd9\xfaA\xb2\x0394zl\xf1\xa58!?1\x86\x163_\x8a\xac8\x0b\x12\xdao\x1cY*\xab\x8a\xe55\x1e\xb27*\xf6\xbdl\x9c\xf3\xba\x9aX\x05\xa4s\xc4\xde\xc2\x98\xaf\xe5\xc9\xe4w\xf1,p)\x0e\xdb\xc1)\xa8\x89\xb4J\x7f\xbej\xa2s \xae\xb4\xd2\xee\xb9Q B\xcb\x14\xc7\x01\xf9Y\xe7\xe1\xbc\xcf'\xfa\x1a\xcb\xe6\xa4U\xa0J\x94i\xf7|\xcd\xe4\xc9>.e\xf7\x1c\x00\xe9F\x97\x18\x94e\xe6\xf9\x9ahc\xea\x93\xe0\xc5\x03\xdf\x1b\xcd\xd5'\xbc:E\xb8\xe6\xda3\xac=\x8d\x96\x9e\xdf\x94 \xc4\xb8\x81\xe5\xc7c\xc1.>}b19)\xec0\xdc\xd8[\xc6E\xd1\xbfF\x18\xa4t\x8b)\xf9=d=Fh\xedoc\x0e\xadY\x97\x84)\x89m~\x81\xe0\xd91\x8a\xe6\x94\xc5\x9du\xc9G?\xb5\xb9P\xbf\xd5sX\x1d\x8c\xb4\xb3\xe2\xe6\xff\x070\xb1?\xda\x16\xdfw\xdb\x93\x85\xe7\x870\xb9\x9e\x04\xc4b\xa1\xea\xe9:\xbe\xb4)\x06\x1f\x087\xd0\xd0\x85\xc4\x85 -N\xb0d\x08\x13;6S\x03P\xf7e#Xp\xfc[\x19\x9f\x1f\x9f\xc4\xc4\x94f[<75\xf4\x08\xc2B\x19\x1d=v \xb3\xc3q\xd4\xe9\xe8\"\xc8\x8a\x87n\x12\x1e\xe1&p\xd4p\xad\x9a\xde\xde6\xf6\xb6)\xfe\xea\xb1QF\xac\x1c\xe8\x7ff\xaba \x9c\"\x1c\xa7\xf2\n|\xb9\xd8)\\\x83Rm\xd0I\xa0\x12\xddS\xad\xb7~\xedJ\x9d4\xc2n-\x05S\xab\xc2\x85t\xcf1S\xb4\x8d?X\x184\x84\x01\xe9\x9e_\xd1\x02\xe2t\xcf\xd7,F\x1d\xe9\x9e',{\x04\xe1+l\x13\x86y\xa4{>\xe1\xc6\x94\xf4\xa0xe\x13\xd4]\xd4\x8e\xfcu\xbb\x91\xbb\x86\xc8g X\x9a\xb0{\xae\x0d\x05\x0f\x18\xec5\x9f\x14\xde\x90\xf39\x19\x8e\xdf\xfac\x17\x03M\xb2\x00\xf6bc\x15\x87\x1fL\xd0\x88\xe7\x82\xeefd\x1e\xa6\xe0\xa7 f\xaa\xa9\xa4\xfc \x9c_\xa2%\xd5A[\xe6 $!\xbd\xf9,<\xbf\xd2zGV\xaaM\x87\xba\x84\x82\xf2c\xe0\xca\xc5\xd3\x8ec\x11\xe6\xa1\xf4<~\x8d\x07L\x1f\xcf\xe6\x13\xfe\xfb.\xd9\x80\x93\"\xf3\xed\xadO~g\x88y\xc39\xfa\x87\x0c\xfd\xfb\x14\xbfC\x17\xb6L\xe3m7N>\xbe\xfa\x89\xb4X\xbf\x86\xb5\xbb1\xce\xbf:o\x85\xc9(V\xfc\x12\xf7\xfaq\xed\x86\x9d\xf2\xa8I\xc7.\x88Ma\xb9`\x9d/,\xc7\xc5t\x14\xae\x1c\xd5\xbaU\x14\xa3\xd4F4a\xed\xe6\x98\"\xfeT\x88K-\xd0O\xca\xf1\xb4\xcb_\xe6\x7f\xdd\xb8\xec\x107O\x92\xa9\xf9r\xce\x0e\xff\x92O^\xf6&\x91U\x97\xe5l\xe5\xebJ\xe5\x85\\\x991\x8a\xc5\x80\x9c\xb2-\x8f=\xd8\xddw\xecc\xd9\x86V\x1d\x1f [\xc4\xfc\x16\xa2\xdcO\xb6\x88uu\xac\x0b\x97-\xac\x8f\xa8\x0c5\xd2\x8a\xa9\xec\xca\x19\xf7\x06\x15\xb0\xca\xb5F\xe5\xd4\x83\x94\x92s\xe9\x07\xd9\x18z\x16\xf3?\x87\nL&R\x08_\x0e\xe3<\xf0\xa8\xa7\x96a*\xdfW|\x1e\x98\xb8>\x14\x12Jy\x9d\xcb\xfb\x08\xd1\xa5\xce.\x03\xca\xd6\x89L\x85\x90\x8f\xd3\x88C\x8e\x12.\xcd\xa4\xa0\xc6x\x1a\x8f\xab\xd8%\xb8\xc2\"];?Q\xf0z\xf45\xc6[\xc8\xb3\xf33&\x05KNx\x89\x8c\xcd\xe7]*s\xfe\xd4\xe6\x828\xc5\x93\xed\x18\x97\x13\x7ff\x94\x83\xe6\xc1\xe9Q\x8d-\x1b\x9e8.\x04v\xd0\xfd\n:\x10t\xbf\xc5\xff\xbf\x80\x7f\x86\xadK\x15!\xdf\n\xa6\xe8\xb8\xf41\xb3&\xb5eZ\xc1\xad\xdd\x1f8\xb6\xfcJD\xa3\xcb\x0d\xddY\xc7\xa7\xa5.%z\xa3\xce\x8d\x82\xa7i\x91\x05\x83\xf4\x93\x8e2\x81\xa4z\xea\xb9\xb9\xb4\xef\xb0\xe8\x9bzD\xab\xc0\xa9\x18\xae\x8dl\xd3\xd6\xa5S;j\\\xef\xa6a\xf3Q]\xd9\xf9\xe6\xc8\xd7\xed\x98'\x93i\xc0S\x05\x92\xf6%\xd3\xd4\x0fv\x1fJV\xf0\x95\xbe\x8f\xbb\xcc\xc0\xb9\x8b;\xc8~#\xa3E\xdd\xb4\xbc h\x9a\x92\xcc\xaa\xeaO=F\xb5L\xf6BxsQ\xaf\xbe\xf1y\x15\xb3\xca&j/\xa9\n::\xd6\xdc'\xcaO\xa4\xb7\x9b\x93\x1f\x8a\xe8\x86\x14\n\xf4YSZN\x8f\x91\xf6zV\xb4\xb0\x82\x11D\x9dN3\x07\x98\xd4\xa4p\x10O\xc8(/#\x81tov:n\xa1-\xa3\x18\x81$\xb2\xfd\x08\x01;\xa6\xacE\"\x98\xf4\xb1w\xc6(\xdf\xf6vFKb;l\xe2\n\x8dB3p4\x97\x9a\xd2\xd6\xbb1o\xf9\xa8\x8bG\x97oG\xddu\xdb\x83%\xf6&\x8d{\xf7\xae\x10\xdd\x8c\xc5\xfe\x06X\xbc9nUW\xbd\xd8vP\xa3\xcd\xd3\x88\xb7P\xbf\x02>[\x81\xd8\xf6\xebV@\"A\xf8\xf3V\x97\x83L\xe9\xa5N\x9dgp)\xdd\x1c\xa0\xda^\n \xc84<S l\xc4\xe5\xb6\xa6m\xef\x97m\xe2\x81\x8d\x9fIN\xb38Z\xdaQ\x83\xad\x0c;7\x07F\x90\xe8ma[[\xd6\x17\x01T\xb6\x8a\xb4\xe3\xaa\x86Y\xe8\xcf\xd5\xf7z~A\x02\x9c\x9e\xd8\xa0g\xbf\x06\xa6\x90\x1f\xb9MP\x85:\x9f\x00\xf10\x0f\x80\xb0\xba\x00\xe2\xd1\x9cj.\x0el\x83\xee3]\x1b\xa9\x1d\xd5\xdczk\xe9\xfa\x9d\xa4\xa9\x90\xc8\xa5\x9e\xcbV=\x00\"-u\xe2\xf4\xa6\xa2.\xe4~\x0e\xbb\xfb\xd2\xba\xc5v\xdc}\x0b\x1d\x88\xbb'5wJ3?\xf4\x82\xe0\xba\xad\xba=\xe3\xb7\xc4~\x1e\xc1\x9aJ\xc2\xe2\x0f\x83\xae=4\xddjk\x98\xdd\xca}q(\xab&\x8d\x96\xd7\xfc3\x8fRGT\x84\x95/R\xea\xf8\xab\xca2\xcb\x8f\xce\x9a\x8c\x8al\x94\xad\xf8\xc2\xe3\xe2 u6\x1a\x96\xf9\xae\xf2\x0b\xa2n\xc5\x7fD\x84?\xd8S\xb0\xf1\xb4\x06\x0f\xd3\xb85\x0e\xd2C0\xd5g\xe0\x86<\xd1\x97\xce\x9eV\xdcB\x87]\x82\x86\xed\xfc\xee\x7fX\\\xc68v\x88\x97$\xcd\xd7\xd2m\xe0\x19\xda\x83\xbd\x01\x8f=\xb7\xc3\xff\xdd-\xc7\xaa\xdb{\xc0\xff\xe5\xb1\xea\xf6x\xac\xba\xfd\x1e\xff\x97\x7f\xbf\xcf\xbf\xdf\xe7\xb1\xed\xf6\xf9\xf7\xfb\xfb\xfc_\xde\xce>og\x9f\xb7\xf3\x80\xb7\xf3\xa0\xcf\xff\xe5\xed=\xe0\xed=\xe0\xed=\xe0\xed=\xe0\xed=\xe0\xed=\xe0\xed=x\xa4\x8d\x9d\xc7|j\xdb\xc0\xa2\x11\x8b*\xbeNQ\x1ep\x13\x8f\xe3#\x1e\xae\xb2J\x10\xe5J\xd1\x94\xa0\x17\xb0\x82xH\x06\xd1z`\x8b\xd9\xb5\xf71\x9eJ\x1e\x16#\x8f\x1dR!\x8fr\xa3M\x08\x9a3\xb4\xdc\xe4r|\xe6\xe2\x9c\xf3\xccPy\xa4\x9c\x8c\xf9\xe9\xc6\xf0\x142\xb3v\x80g\xb9\xeb\x14\x99\xa52\x8c\xa2\xe3Sj\xd2\xef\xf7w\xfb\xfd\xbe\xc3r\xf7\x8a;\x91\x13/\x9c\xf3K\x11R\x8e-\xbe\xf6\x02\x7f\n\x93hJ`E'c2\xab\xe4w\xd4\x04\x9e\xb0H\x9dp\x80\xb1~0B,\x8b\xe4\xd9\x01\xdb&\xb0=b\xe5\x0e<}\n\xfd\x1e\xca\x14\x7f\x84~o\xb0\x0b\x1d\x16\xffS\x97|\xcc\xb4'C\x9eSP\xcd\x9c\xbb\xe1\x8ek\xc22CT -\xa52`D\xec]\xb5\xc7\x03\x16;\xa3\x1b{W\\\x10\x8d\num\x1dnP\xcc\xf1\x18\x8e\x84\xf0\x14\xbc\xc7\x0edl]x\x08Z2\xf6:\x9d3\x07\xe3D\xdc\x87\x9eF\x8a\xb0\x8e\xa2,L\x0b\xe7\xac\x90\xcc\xbd\xd4_\x13U|\xe0\xc1\xf8\"x\xaa\x1ar\xf1\xc7\x8e\xe0\xe9\xd3\xa7#\xe8;\xdc\x9b\xb53B\xc3#zb2\x07\xd7\x90\xbdz\xac\xac\xd3\xef\xa7\x84\xdb\x948\x17 \xda\x9a6aQ\xb3n\x1b\x16\xb5\x9a6\xa2\x8eD\x97\xfa\xd0\xad\x00\xe2\x88o\xe7\x84r\x93\x1d\xea\xe6\xe1DM\x99/\xe2[\x10\xd6\x18\x97\xad \xac!\x15\x92(\xec\x84E\x0b%\xac\xf1g\x11\x07\x93dBW\xc5\x0b'\x8b(\xdeH2\xa9\xe5\x06\xf9b`\xd4z+\xf4\x96\xc4\xaaK\xec\xf9\xd9\xc3\xbf\xf0\xe7\x1b\x8d\xbd\xcd\xd0Y\x9b\x16\xfe\xf7\x05G\x1e\xf8\xe1\xe5\xdd\x8f\x9d\xb7\xfa\xc5G\x1f\x05\xd3\xbb\x1f\xfc\xef0\xf0\x99\xff\x91\xdc\xfd\xc8\xd3\xf4\xf7\x18z\x14\xa6\x93(\xf8\x12\xbb\x956MG/\x9a\xff\x82;\x96v\x95\xf8\xbf\x90/7 \xde\xfa\x17\x9c\x83\x9fz\x81?I6\x9aB\x9b\x19\xf8\xbf\x03\x16mLvZ\xc1\x1e\xc9\xfd\"&\xb3/\x0b\xf8d\xe9\x05\xc1F\xa3o3x\xd1\xea\x97\x06=}}\xb9\x19\xe2\xb7\x1a\xbeh\xf6\x8b\x8f?\xbb\xb8\xfb\xc1g\xbf\x07\xd5O\xb2\xd5\x17\x18\xf9\xea\x8eF\x1e\xda\xfb;\x8em-\xbdt\xb2\xb0\\\xe8\xd7\xd7\x96\xc62\xce\xebi\x15\x9dz\x88\x88GH\x02i\xddE\xa2/+\x1aP\xcf\x90\xe7_\x0b\xc7\xc4\x9c\xdaB2\x9b\xf7\xe1@\xd8\xd81\xcf\xa8!\x9a\xb7q}n\xe8\x8c\xc9\x99P\xd8\xc7\x95X\x1f\x10n\x9a\xd5\x9f\x03\x93\xeb\x14-\x17\x06\xb7\x00g\xecV\xdd.\xa0\x15D\xa3&\x88f%\x88\xc62D\xe3\x96\x10\x95\x04\x88\x18C\x95\xf9\x08T\xf6\x86\x832rX\xe8\xa5;\x03hB\xbc\xf8\xdf\xd0\xf3\xce\xa0\xb9\n\xfcT\x8b\x9c\x15\xcbI3\x98\xc4EFh\xf7wUc=\x10z\x8f\xeakv\xb9\x867eU\x8d\x885A\xe3\x14\xcb\xbb\xb8\x98X\x92\x89mYt\x8e\x1a\xa4is\x1d\x02\x92%\x9a\xd0\x01\xe8\x03\x01@\xd9\xd7f$\\\x8bx\x12\x9d\xdc\xceMM\x86\"\x7f\xbb\xe5\xcb\xa9\xd3\x8a\xa8x8:\xfdgkf\xc2\x9f\xb80\xc1p\xd3\x01\x0b\x8b_\xe7u\xbe`\xa1;\xfdy\x18\xc5\xe4\xc8\xc3`}\x96o\xc1\x90\x1ey\xd0\xa1e\xcb,H\xfd\xc0\x0f\xb1hY*\xcaB\x1f\xaf\xda\x0f\xc0\xcaJ\x05I\xeaO.\xaf\xe9\xfbk\xfe\xde<\x84i\xbd\xd3\xfb\xba\xbc\x9a\xb4\xb3\xdd\xc1\xa3\xddG\xfb\x0f\x06\x8f\xf6\xd0\x8e\xff\xe9\xd3\xa7u\x0d`4\xd9b\xbf\xa7\xdd\x04\x83\x9c\xbb\xb0\x80\x0eXs\x93\x85\x00\xaa\xfaX\xf0\xaa\xb8\xdc\x02\xbb\xcb\xbc\xe6\xed\xd0F\xfe`\x1fl\xfd\xf0C\xe2X.,t\xd7\xd0\xf9\x83\x0e\xec\xd7\x0c\x17y\xc0\xce-\xdb\x9e`(1\xd4*C\x07\x92q\xef,\xc7\xf0\xa70E\xad\xe1\x8aG3\xe1*\xa4\xa9+>p\x1c\x17\xb6\xd0h\xbf\xa4\xe0\xc2\xc4\x1f\xbd\xb3\xfc\xe2-v\xebY\x9f\xd2\x83S\x0f0\xd0\x00\x04\xf0\xa4\xaa\xe4\xde\x86\xc1c\x08:\x1dG^\x99B\xa3\x16\xa0\x15\xaf\x8d?FZ\xe5w\xe9\xb9q\xdc\xea\xe098\x9e\x141\x15\xf1\xf2\x9f9\x00\xad\xe8\x07\x0c\x12}\x87g\x89\x90\xc0\xc6b\xc5O\\X\xe5\xad\x8e`\xed8\x8f\x1d\xb8\xee\x06^\x92\xbe\xc4\xb6\xf1>\x83\xf7s\xef\x9e\\\xa4\xc6\xf4\x16\x0f\xdf\x8cSv%S\x84\xf5\xde\x9a\xb1\x06(\xc9\xc4,<\x9f>\x01_1\x96\x93G]>:\xe8bp\xb0\x86\x03X\xf1\xb2\x9e\x0bk\xfc\xa42\x02\xc5,\x99\xb9*X=A\x1a\x85\n\xb3\xe7H\x10\xb3[Q\xb6\xf2\x99\xa9\x92+8\x80\xf1\x19\x0c\x05\x0d\xcau\xb1\xaa\x14\xa8\xd7iK,\x82\x81\xe5\xba\x05Su+>@b\xaa\xc2\x82\xa9\x8a+LU\xa8c\xaa\xe2M\xd9\x80z\xe5|f\x87\xf6\xe0a_U3\xfb\xbchg0P\x8b\"^\xb4\xd7\x7fHIL^&\xc6\x80A\xf1\xf5\\\x1a.f\xda=?'\xc9\xabh\x9a\x05\x18G\x1e\x86\x9a\xa5\x98\x92\x99\x97\x05\xe9P\xbd\x9f\xff\xa7\xea/q\xd2\x8e\xfd.\xff\xca\x85\xa8\xf8i\xa46|L\xd5\xbe'\xd1r\x15\x85\x94\x80\xe8F\x06\x98{B\xf8.}\xe3]GYJ\x17\x8fw\xd8\xb4Y\x8a H\xa8\"_Ny\xb7_S}\x8eW\xe2\x82U@\xbcr\x0b\xc2\x03\xc7\xcb\xe1\xea\x9d*\x9aLl\xca\xf9=\xd4\xa1 \x16\xed\xf5th\xc2\x8a*\xc8\x95\xe5E;j\x91\x97\x17\xed\xabEI^\xf4@>\xda\xf0\xd5\xfe\x9e\x1e\x15'\xbf?*\xcej/\x18\xf3\x91\x91:\xc1\x9f\xd2\xde\x1c\x9b\x1dN\xe8\x88\xe3bA\xa6\x16\xd8\xa4{~\x8e\xce\xe7\xe7\xe7\xc8&\xf4\xdc\x02\x1f\x1d\x9b8\x0e?\xadX\xf5\xfcxTE\x0c\x1d\x98h[\x9e\xd4\x96\x0b)\x1fFTz;\xae\xce\xe5\x92\\\x0f\xc1\x8aI8%\xb1\xe6\xa6\x94\xe3]#3\xb0\x96\xf3c\xac\xe2he\x88?\x03\"UFwN\xd2#\xb1\x85\xcduYd\xf0dE&,!P\x14\xd74\x1c\xb3\xd0\x1fq\xdc\xa2.\xdd\x13\xc4\xb6\x8e\xa20\xf5\xfc\x90T\x1cn\xe4'buO\xa2\xab\xbaZ\x99h1\xa8\xab\xe5\xb1Z\x18\xb57\xb10\x9c\xa9\xb9\xf2\x84U~\x17\xad.\xbc\xb8\xa9\xf2\x8cU~\xe6%\x9c\xde5}\x10\xb0\x0f\xa2\x90r\xeb\x1f\xbc\xc0\x9fzi\x14?\xf3\xa6s\xd2\xf4)&t\xe8\x06\x917\xf5\xc3\xf9i\xea\xa5Y\xa2F\xb2\x97\x9f\x05z/S~\x89\xdd\x9f7\xb0\xf7\x94GZP\x04\xb1\xad%I\x12oN\x90+\xb24J\x01(6A\"P\x9d;T\xf2\xdcQ\xb6o\xf2\x94\xa4\xcf$\xf0\x92\xe4\xb5\xb7$C\xb0\x92+o>'\xf1v\xe6[\xda\xfa7.L\xe0\xc0\xd8\xcf\xc4\xc5$l\x0eO\xc6\xe6\x82\xc5\xe1c!_\xb4b|\xaa\xfe[\xcc\xed\xddv\x9c~8\x8b\x8c#\xbc\x93\x1e\xf8\xc0\xb7'\xf9\xee\xf8=\xba3t\xe2`\xf8\xb7\x99\xe7\x07d\xfa\xaf\x12\x94\x8b\xdd\xd6\xbd\xa5~\x1a\x10c\x0f\xd6\x0b\x04\"\xa4\x11\xd0a\xc1\xe1\xdb\x97\x80l\x88Oi{\xd7r\xcc\x83\xf08rKkq\x84\xae\x95_dE\xcc\xe4\x013A\x9b\x18>\xf1,\xbd\x8f\xdf\xfa\xd3t1\x04\xeb\xe1\xc3\xde\xeacM{\xacz<\xf7\xc3o\xc8,\x1d\x82\xe5ei]\xffE\xfd\x13\x7f\xbeh\xf9AJ>\xa6\x87\x81?\x0f\x87`M\xd0\xdf_\xbfDP9\xdf\xf3\xb7\xff\n\xb01&\xcb(%\x85\xc7n#NZ+\xcb\xe5\xa4v\x8a\x88\xb9\xb5B\xe5_\x92MD,\x8c\x06\xcc\x9cq\xac6\xf7\x11\x89\x1eL\x15\xb2\xa6\nA\xbes\xaa:\x0dE\xea8+\x85H\xba\xb1\x8b&sNIb\xa9\x89(m\x1bl\x8a\x8a\x90;\x15\x8f\xa5\x81\xd3\xd5\xe6Am\xd3\xa2d\xdc\xa7\xcf\xff\xd6\xdf\x91\xad\x96\xa9p\xf2\xc8\xb1\xadrGV\xb3\xf4g\xe6\xd4\xa5J\xbe\x92\x86\x14\xe06\x17o\x83\x87{\x1a\xc1J\x02\x93^\x1ely\x01\x12\xabb\x9f\xa8^\x8c\xb3\xcd0\x8ba\xf5U\xeb\xce\xc2\xabk\x8b\na\x94\\\xb3qWvmy$C\\\x1d\xa7;\xdb\x10b2\x10*\xed3\x89\x8c\x02U\xbd\x8d($\xbaas\x0e\xb6\xca\"=b\x0ey\x0f\xf7\xaa\xfew\xbd}\xa7;\x93\xfd\xe8\xdb\xb4\xd8r\x12\xaa\x01\xeb\xe7Mb\xf0\x88\xbb!>\xe2n\x86|V\x83G\x0ft\x9b\xf4\xf4zy\x11\x05m\x9an\xb2\xf34\xd8\xe1\xaa;\x98\xdby\x1a\xbc\xad\x0d\xce\xd6\x03\xb5q>\xfeG}\xa7\xfb\xf5\xf1\xf7\xe5\xb2 /S>\xe1\xa9\xe5\xd4\x1eXj\xb9G\xeaxXn\xb9=\xf55\xcf-\xa7\xbc\x9d\xe6HR~\xbf\xe6\xefU4\xbd\xe6#T=\xe4\xe6\xfc\xbd:F\x9eV\xae\x82\xed\xec\xb5\x1a\xfe\x92\xa5\x94\x1b\xe83\xcaU\xb0\xed#\x9b\xa8\x1a\xfb\xee\x94\x81E\x95\xd6\x8e\xf9\x08\xd5\xea\x87|U\xd5N\xdf\xb0\xf7j\xf5\x9f\xf0u\xc5\x0d\xf5\x12Fp\xa8\xe6\x90{ #x\xa3\xbe|\x85i\xe1\x94\x97\xefP\x1ed\x18].9\xc2\x92\xbf\x9c\xbey]~\xff\x16FpD\x8f\xf2\xa3n\x82\xaaW\x7fv]\xaeqB\x05G\xdb:_\xf8\xd3) U\x11\xfc5+M\xa3\xb7\xb1\xbf\xf4\x99\xadv\xb9\xc67\xe8\x00\xa6\xcd\xb9_\xae\xf8\x9c\x92{\xdbJp\xf4\xdb1\x99\xfbI\x1a_\xab\xcd\xfd\"\xd7\xaa\xa4\xb9|\xc1J\xa3\xd5\xb6\xa1\xc2{M\x12\xf3r\x8dg\xa6\xf8\x01\xef\xca\xf5~F\x88\xfe\x955V.\xfa\x1eF\xb0\xf53F\x0e\xffY\xca\x08\xa0\xfc\xdd\x9d\xf9\xe1\xf4h\xe1\x07\xd3\xf2\xd7\xdf\x02\x8f\xf18\xa9w\x8d\xe3G\xdf\x03\xd8\x1a\xc1\xa9\xfd\xd2\xfe\xfb\x0d7\x0f\xd33\x91\xed\xe2\xb1@\xd1\xf0K\xd9\xe4\xac^0\xe0\xda\xac\x07\xc6J7N\xd7\xd3\x16V\xd9\xf2\x1bG\xad{\xe3\xc8\xd1\x0f\x0c\x8c\x00H\xa4\xf8\xd2~\xaf\xbf\x9dE\xd7\xd5) HJ\xe0\xfd\x98\x9c\xb9t\x92\xbc=\x1e8,\xc5;\x8a\xf7\xf4\xe7Kl\xa6\x12 \xf9\x06\x86\xf0\xb2\xbcd\x1fj\xb5\x9e \xd9\xd0\xff\xc2|\x0dO\xedw\x05\"\x98\x0d\xd8 K\xa5\x9bV\"|\x96\xbb\xff\x1aF\xf0\x8c\x8e\x98o\x8b\x12\xd6v\xc5\x91]\x02b\x0dBi\x1aI+\x00h\xd5R)\n\xf3\xbb\xba\x19|\xd5\x82\xd5+5<\x12\x8b\xf4\x95\xfd\"_\xc0%\x8b\xf2\x0f#\xb8\xe2\x19\x8d\xe8;Z\xe2\xdb\xbf\xe0\x9d\xdb\x01\xc6c\xc8 \x10f\xe4\xa3\xfd\x9d\xb0\xbc\x93\xe3\x93\xb31a\xb7\xa6\xe2\xf7\x88\xe7\xa8\xc0E\x0bM\x1b\xa1hr\x08\x1f\xed\x1e&\xb6\xd0a6\x0c\x8b\x0e?}b\xd8w\xe2\xc2G\xbb\x8fyv)\x7fR\xf4K\x87\xffm\x0e\x0d\xfa\xed\xcb*_\x0bU`\xfe\xa1\xcd]\xe3R\xeb8\x91;\x93\x87\xcca\xfc\x9a'\x82#th>K}\xc2\xa21\x8a|\xdf\x11<\x05\xff\xb1\x03_\xd9)\x83R<\xf61n\x00\x19\x87\xba\x10\x96b\x05\xeb&\xf0\xe7\xd6\xdb\xe9\x9b\xd2](.|\xcaRY\x19{\xde\xc2\xda\x05\x02!j\xb0\xbc\xa3[>E\xa6\x94\x19\x04\xd8[6#\xd9\x85\x0b'\xff\xf3\x17\xf1[\x94p\xecY\xf8 ]\xbc\xf4\x0c\x0b\xd5k\xd9\xf2\x14\xff\xd2f\x8d\xfc\x19s\xdc\xbd\xd0\xe0\xb5\xa0S\xf9\x90\x08\x1f\xd2\x0b\x16bY\x8f\xa7\xc2n\xe6\xd2\xae\xb1_\x11\x80\n\xab\x8dW\xb6\xca\xa7O\xca\x8e\xe2x[\x8d$sS\x07\x8e\xbf5\xae\xb8\x1a\xee\xe2\x95}\xc1\x9c\xa0c\x1e\xc1 \xe2\x11\x0c\xba\xa5\xdc\x8fl\xf4\x94\xd9b) qe(e;\xc9\x7f%,T#\x0bDa\xc6\x9b\xb8n\xfc\xdfm<~N\xc2\xd8\xf8_a\xe0\xa1\x170\x04>\xa9\x88OJ\x84\xee(&\x95=v\xc4\x9a\xe0f\xcb\xc4\xacB\x8e\xc1\xef\xc5jElJ\xbf\x8cI\xcd>\x8c\xca\xb3*\xea=\xc3\xa5\xf5l\xfb]]\x14,\xc4P\xba\x9ddB_\x0d\x99n1\x96\xb4\x88\x0f\"\xe5(\xaeDN\x17W^+\x9d\xcfX\xaf\xe43\xd6\x93\xbc:\xdd\xca\x14\x89\x94\xd3\x01\xc9\x19\xa9\xac4\xca=\x04\x9b\xf4E)K\xc4\xffOr\xd3\x87\x98\xb4\xe8/.\x15Q`\x04_a\xc4\xa1\xbd]\x07\xff:\xc6\xff\xff\x8d\xbe\xdb\xe7\xaf\xfe\x8c\x15z\x0f\xd9_\xdf\xf1\xf4\x97[\xa1\xfd\xf0!\x02\xd5\xa3\xb3\xb7t\xe2\x82\xe5\xd2\x8f\x91\xbcL\xbb\xf5\x17\xcd|\xbc\x1f\xecEIuE\xc7\x9b\xd9\x19&B\xca0\x11R\xc6T:\xcfTh3\x84\x1dJ\\\x8bl\x17\x90o\xe6\xbfRaa\xe1%/9\xfa\xbb~r\x14\x85\x13/=]\xc5\xc4\x9b\xa2\x90#\xf8/\x17\xcd\xce]n\n\xe623_\x97\x87rt\xd1x\xc8\x95\xe4(W\xac\xcb;o\xee\xca\x99\xfd\xb9\x9d\x91\xe5Z\xf4\x18H\x19\x85\xf8k\xb1E\xd2\xf4\xb1\x03\x0b\xfb\xaf\xe34-'\xbd-HP\x8a\xd9J\x16\xdd$\x8dbB\xa95o\x85\xa4E3!mfm\x93t\x1c*\xedP\x08\x9e\x96`\xc7\xf7w5\xa0Q\x14\xb7d\x15}\xfb9=\xd3:#4^<\x80\xe7tO\x0d\xd9?\xa3j\xea]\x85\xfc^\x92\xeb\x17\xcd]\xa19\xe7\xd7h\xceY\x9b\xd3\xc1\x03\xc6\x01W(\x13\x94\xc3\xed\xf8!<\xd7\xdb\xd3\xd1\x9e\x9e#\x177\x92\xe3\xbb\xd72\xf1YBNI\x9a\x92\xb8AJ\xfb^\x17I\xb2\xd2\x92\xbf\\\x05M\xf6\x05\xdf\x97\xb3\xd7\x01\x94\xf5\xba\xaen\xa1\x0d:O\xa6\x9ao\x91\xca\xaej\xe2F\x99\xf0S\x1b\x93\x96\xfd\xc1>e\x9cN\xedb\xab\xfa\xd5\xafj\x8a}\x92\x0c\xe1\x0f\xe5\ns\x92\xbe\xb9\n\xc5\xf7\xcfI2\x89\xfdUJ\xd1\xe7/u\x15_{K\xda\xd8\xdf\xea\xea\xb0m\x90\x0c\xe1\xbb\x12\x1cQ\xc1R\x06\xa6\xbd\x85\x07l\x8d\x88/\x8e\xc1wjxL!\xa6\x8d\xc3,\x08\xce0\xfe\xcd[[p\x9d\xd6\xdfo\xf8\x9b*\xec\xbd\x8a\x11\x8f\xf2 [\\\x85b:.X\x7f9}\xf3Z\xe3@\xce\xf5EM\xfb\xae\xc4\xfap\x86-=\xe3Y\xe4\x1f\xebb7P\x81\x82sd\xc5a\xef\xebSx\xf3<\xaf\x9c\x1d\xea\x9f\xb9`\x9f\xdb\x95\x94?\x9c\xc1\xffZ6\xe6\x9e\xf3j6i\xc3\x8c\x8b\xbe\xb4\xba!\x16\x1a\x08\xf9\xcc\x8au\xa6\xe3\xd2~\x89c \x03\xc0\x91\x84\x8e\x9dN\xc3\x85\xb7\xdc`\xe9\xa8\xaaz(\xa1\x95\xa4B\x18\xbfFV<\xb4\x07\xfb\x8e\xacZp\xe1u\xa9\x1eK\xc2\xf2f\x86\xd9\xe4\xde\x15\x84\x1b\xff~\xe5\xa5\x0b\x17,\xfa\x0f\xb7S\x81\xc0\xe6J\xc3\x1c\x07\xb6z\xad4\xff\xd2\x0d\xd6\x9ec[K\x92z\xba\xd0\xbb\x1a\xe5m\xa4\xd7\x9a\x8b`\xa4\x8e\xaa\xf3\xf4\xaav\xebI\xa1\xe4\xf3\x93\xe3\x8f) \x13\x9f\xca&\x9f>\xd5\x13D!\xf8\xd4R\xd7 \xa5\x9a\xa8]o\xa5\x9eK\xec\\\xddH\xd6$L\xf9p\xa20\xb1\xa9\xc0\xaf\xec\xc7rW\xf5<\x0e\xe0Q\x9c\xa2\xf7\x91I\xdaC\xb5\x9c\xbe\x90>\xfe\x10\xac7\x16t\xa0\xd3\xf1\xaa\xbc\xa4x\xae\x86j\xb0Z\xf1\xe8\xb4wu\xb0\x0b\x94\x1cR\xd5\x91}}\xfc\xbd68\xf9\xeb\xe3\xe3\xe7C\xd8\xeaWKf^\x92~M\xae[\x9c=\xa0u\xe9\xd0\xa9\xbb\xb85$s$e\x86Fr\x99u\x8a\xde\x14o\xd1\xcd\xc2\x90C\x81e\x01\xc0\xe51J\xe3y\xbd\xa44\xa0\x17\x06{\xac\xbcz\xe1\xb9b\x1d\xd7\xd4\x9d\xa9\\\x93x\xf4\x8b)x\xfcq|\xd6\xad\xe6\xce\xd7\x84p\x9b\x93\xf4[\xe2]n\x02\xf9[\x01dK\x1f\xe3\xa5\xa8M\x8c\x11\xab\xe5\xe73\xc0q\xd5\x06\x1cQ\xf8\"&\xe4\x97\xc6d\x82P4>\xa1\xc7F\xd0\xa5\xc8\x8d\xe6\x146?\xa68\x98\xe8\xef\x19rD\xed\x0c\xab[\xd3\xe4\xca\xbd\x93\x08\x19\xa4'\xc6\xfb\xa6\xe4G\xe6\x89\n\x05]\xac\xcd\xd4\x16\xb2\xc0\xba\xe5\xb5\xc2\x83\xbc\xbaB9\xf7\x90\xb9\xfc2\x94\x02\x84\xf6\x1eug,\xa1J\xef1x\x05\xf30y\xec@\x92g.\xa7\xe7\x867\x9e\xa0\x96\x04\xe5{\xe4*2=O%\x19\x89l\x06\xd0\x87\xfb\x06\x08\xb1\x08\xef~\xc2RY\xc9\x07\x90If\xb5\xb0*\x92\x9c\xd8\xbe}\xa6\xab\xca\xed'_\xe2\xbd\xea \x1a\xb1\x1b:!oV\xcf]+b\\\xbfD\x06\xaf\xfcp\x1a]Q\x88\x16\xbf\ns\x17\x95m\x86\x83\x9aB\x9b\xb5@\x05\x80\xb1\xce+\xa0\x9d\xa8\x8f\x81v\xad1\x1b)|\x8bM\x9e\xe1\x88\xf3Di\x8d\x17 \xe6\xbc7\xb9\x94\xaa!!\xcd\xf9\xe3\xc5\x10\xb9kQ\xa3\xbd\x92\xcdS8\x97\xedn\xf4\x08\xe0\xc0\xdf\x1b-\"\xfa\xbd\x07\x8emy\xc9u8y\xb9\x91\xfd\x86\xf8\x94%GA\x1dL\xab\xef\xda\xd9}<\xba[\xbb\x8f\x9d^\xaf\xc6\x08+\xf9\x0c#\xac\xaa1\x90Y\x12.\xf73\xc4q\xf51\xa7U1\x9fV0\x94\xb6\xb2J\x95}\xbd5D\xd4F\x8c\xa1T\xd6G\x12\xba\x15S\xf9\xe7\xde=4\xa3+\x07v.\x14#\x84eCe\x11\xd9\x12\x92\x82\x97@.Ml\xa9\xe1\x18\xf44\xb0\x02\xa0!h\x17\x05e1+w\xe6\xb0\xc0\x0f\xe1\xef7\xd5\xbb_m\xca\x1b\xf3\xde\xb5\xf9\"R\xd1\xe8\x05o I\x82\xcb\x0d6\xba3\xbbb\x12\x00\xd28XF2\x188\x0e\x1d\xc0\xf8\x8c\xdf\xc5(Yf\x91l\xdf\x86:\x10}f\x8a*W\xc2\xc9\x88\x0c\x0d\xa3V[(\x95Y%\x96\x0f5\x95\x1ceF\x10\xc2\x90\xe5\xc0 \xdb\xf0\x17h]\xb0\xd5wL\xfa\xf6\xc9\x82L.\x87\xd2uB\xabM\xdb\x8aN\xecT\"\xe2}.\x9d\xd8\xfdlKD\xc3!\x14s\x1bUVg\xb3\x81\xdd\x8e\xdc\x08\xc5\x1bZ*\x15\x1d\xb6\xa20M\xf6l\xbb\x06\xdb\xd3==\x97\xb8S\xb1\xf2b2\xfbN_\xb5\xf2bl\xdc\x8e\xfa:\xe1\xd5u\xe9\x89\xe9{\xb5\xf9\x19\x7f\xaf\x0e'\xe0\xcd\xab8\xba\xc2Li%+\xe2r\x85\x85T\xe1\x857I\xa3X\xb1\x85\x9a\xb2\nA\x14\xea\x1bXW\xe3@\\7\xca\xf0mn\xc4\xe7Za\x19\x8d\x87b\x12\x9aD\xfc\xa5\xb7\x1aB\xd4]z+\xbdp?\x8b\xe2co\xb2\xa0u\xf8O}\xbdI\x94\x85):\x1e\xd3\x1f\xfa:i\x84\x04\x90\xd6\xe2?\xf5\xf5\xa20\xb8\x1e\x82&\xe7Y\xb5zn\x9c=\x04\xbf[\xe3\xd3\xf66\x8bI\xa9n\xe9E\xb5~ \x03\x86\xa0\x01\x8e\xbc\xc2C\x98V+\xf8 \xfau\xe5U\xbcn\xf9\x8df\x90q\xb4\xa2\xc7j2\x04\x8d\xf7\x1c\x1b\xd2Q\xe0%\xc9\x10f\xa6r\x8e\x93C\xd0\xac\x13\xab\xf1\xca\xff\xe8\x87C\xd0\xc0\xfe\xf9\x9bWC\xc8\xaa\xef\xd7$N\xfc(\x1c\xc2\xa4Zv~\x9e\xe05\xd6\x10\xd6e\xe4\xd4S\xc8V\xa99\xea\x89\x8e\xacQ3\xf4\x12\x7f~/\x94V\xe9y\xaa\nM\xe2\x02\xb0\x81\xb2\xf5T\x0e\x96\xa5\x13M\xaf\xa2C\xae\xb6~\x1bE\x81\x9a\x8e\x14g\xd1\x9dEY\\W\x8bR\xbd\xfb?\xdc\xef\xdc\x9f\xeb\\{gFA\xc8\xb6,\xe8@\xea\x94\x82\xbd\xff\xe1\xde}K>\x8f\xaa\x0d\x06\xdas\x0d/|i\x1df\x85\x86\x7fN\xa20e\xb9\xb9H\xfe&c7\x88\xb5=\xact\x0b\x05\xd2\xb2\xa4\xd8\x93f\xb3a\x19\xefV\x91\xdb\x99l\xe7c\xc3)\x1b\x88\x9c?]7\x8e\x85\x18\x87\x86\x93\xc4\xe9\xc4$a\xde\x1fb\xc6\x97\xe4\xfamLf\xfeGi\xce\x1c(a\x05(\xf1F@\x996\x03\x85\x0d\xa7\n\x96\x0cK\xf3\xb1U+x50Md\x98j\xa8 ;\xe8(l\x13\x05\xb6\xe5\x05(\xe97\xec \x95\xb1\xd7\x14\xe3b\x84o\xd4M\x17^z\x82\x88\x99\x08d\x17\x8e\x9c\xb05b\n0\xdbW\xa8'm\x87\xbe\x9f\xa0\x9a\x08\x89\xf1a8=a\xf8\xfc5\xb9\xa6\x1dd\xd0\x01{kB\xe7\xcf,yP\xb9C\xff\xc2\xe4\xf2\xf8\xeb\x00,\x0b\x860\xb3\xf1O\x87\x8a2\xf7Qg\x1b\xa2\xe1\x10S\x05M\x9cztYK\xe8\xe2V#g\xacy\xd4\x0c\xd5\x89V\xcc\x90\xdd\x0c\xa1hf\x87b\x08U\x83\x17\xbaV\xe8\x9a\x8b\xa4`j\x13\x8c\x8c\x81\x1d\x96+\xa3\xc6\x7f\xea\x82\xe7\xb8\xb0\xe8\xc6$ ^Bl\xaf~\x0e\xd7&,\xe34\x83\x0eVj@\xfc\n\xa4\x8b\xa3)\x11\x06;u\xf6@\xa5\xad\x81\xee[\xca\xee(\xbd\xacl\x10\xba(\xdetJa\xe0\x87\xf3w\x91\x1d\x88\x89\xdej \xf9F\x96z\x95\xf7\xb2\xf4\xfa\x0e\xc7\xbcp!Q\x04\x8c*\xfb\x96\xb3^u\xa7\x98xP3J\xf1\xa9dM\xa0\xb9x\x10D#(c\x92.\xc9:\xe2\xd1\nS\x17@\x90\xe3\x91z\xdfX\xa6\x0c\xc8O~\x91\x01\xeb\"p S\x01\x9b]q\xb1U\x10\xa6\xda\x0d\xc3|\x19\xa6\xd1\xb7~\xba\xf8Z\xac\xf6\xcb0%q\xe8\x05CX+\xc7,\xe3m\x1b\xf5&B\x87G+\\s\xd7\xc3\xbaA\xe4\xfcp=\xf3/\xf4\xe4M\x00 \x02\x00z\x92Z1\x10/\xf0\xf3\x8b\xf1j\xa1\xbd\xaf\xd31\xdb\xa1M%\xaf\x86y\x0b\xc3\xc1\xae\xd0\xa0Pl\xad (\x07\x12\xac\xaa\xdf\xad\xa2\x95)\xf3\xb5\xc0=\xdc\xbd<\x12|\x15^P\xa7p \xc9\x15~_1B\xaa\xd5\xbfi\x95T\xb2\xc2\x08\x0d\x0f?}\x82\xd8\xb6\x06{h\xcb%\xd16\xdbq5\xf3\xe4w\x1cOx8\x90(\nN\xfd_\x880>V`B\x0f\xb7z\xb3\xa9\x0c\x934\x97^yZAS\xa6o-\xf6\nH\x96\xc6\x86\xebQ\x01\xda\xd2\x98\xb9\xd1kXP/\xb4\xeb\xf8\xf4 2\xfa6\x9f/3:\xce\xff\x1c\xb1\x8cp\xa1\xa0b0\xa2g\xa7\xc6\x02\xb9\xca\xe7P\xce\xa2\xc4\x83\x0fU\x80\xd0\xa7\xc2\xcf\xb7\x84\xc1m\x90\x1cd\xd8m\x82\xe8\xa0Cv\x11\xa8P\x07\x0e\xd0\xe2<\xe8\xf0\xbeb\x92\x05zp\xa6\x8b\x98T\x00\xda\xe6\xc0\x80\xcf\x84V|'\xd0\x8a\x19\xb4tG\x8cx\xda\x03\xac\xe2\xa5\x01z\x98U\xe5\xc0*\xc8\x0c:o\xf8L\xa8\xf9w\x025?\x87\x1a\xe3&\xaa\xb6\x03\xb0)\xe0*\x86O\xd5\x16\x0c\xe7\xdag\xc4\x0fk>\xd7\xfa\x05\x1f\x15?f${\x1f^\xd7\n\xb3\xe5\x05\x89\xe57\x05Ty\x17\xa4\xfb\x87?\xf0\x91\xd1wE\xfe\xf4\x99\xcd8V\xcb\xca\x93\x87y\xd0\x81 \x9dp\x0f\xc5`\xc7\x05\x8d\xc5\n\x9dqM8\xd65\x8a\x9bR\x93CLd\x93\xe8\xa1R\x96\xd0\x89\xc6\x1f\x01d+\x8bkfOq\x0dO\xf2$<\x8f\xe1\xba\xd3q`\n\x9d\x11\xa4\xf6\x8a\x9e\xc9\xe3\xeb3\x17\xd68\x97\x95\x0b\xd7\x0e_\xbd\xea\x0808\xa6\x99C\x98\xb3,\xa5\x06rC\x87?o\"bK\x17\xdd\xc0\xe7\x9c\xbb\xab\xa1\\\xd8\x1c\xbb\xe8\xec\x920\x8d}\x92\xe8\x81!\x9e\x1c(\x17\x0c([\xf6\x12Fp\x8e\xa9\xe9m\xc7\xe9N\xa3\x90<.\x01f\xc9\x0c,%\xd8\\t:f\xe8\x88\x87B\xa9y$\xc6\x01\x98\x01$\x1e:\x89\xabb|\xe6\x91\x88\x07\x0d:lifWhZ\xbbF\x03fN.\xae\xc6\xbd3\x87\"\x9e\x98kO\xcc\xb4\x1e\xac\x06[B\x86+\xb8\x91K[\xac \x01>\x1a\x92\x91\xc9\xcfi\x11+\xba\x0eCb\xdb\xda\xe9[naG\xc2n\xdd\xce\xd8HN\xe1@\xec~\xb8\xf2\xd3\x05\\\x92\xeb\x04\xfenAG\xdcg\xd3\x176qx\x9a[\x17P\xd9d\xddX0\x84S\x17>\xb65?3J\"\xd3R\xc1\x0d\xa5\xb8\x96\xa5\xf2\x1a\xadn\x1b\xeb\x8f@\xad\x8d3\xf7\xe1\xbaw\x8f\xff\xca\x1d\x8b\xabg\xa5\xf5/\xff\x92\x07\n\xd1\x9f\xd3f9)\x97\xf2\x80\xc5\xcdEg\xc3\x18\xcd\x9b\xd3\xb1\xafZ\x80\x1b-\xb2\x89\xc6\xdc\xfa\x0e S\x1e+\xdb\x08me|=\x1a[#k\x08\xd6\xa8g\xc0`k\x88\xc5\x83j\xb8\xa7\x1b\xa3\xc6\xc0\xfa\x03\xc5\xc9\xcaE\xc0\xfd\xf1hxv\x7f\xde$\x9aK\x0d\x91qzV\xed\xb7^\xa6\x0c\xef\x06(=\x9c\xb6 (\xa3\x01-\x1en\x02\x14\x06\x0e\xdb\xea\xb2\xcd\x9c\x8e{\xe8\xe8Ma\xc5\xfe\xee\x9f\xa1\x8dD\x92]0.\xc0\x1e\xd0#Z~\xd1w\x1c \x9a\xf6\xa8\xf7i4p\xee\x1e\xa0\x05\xbe\xea\xf7\xce\xdd\xdc\x80\x0d\x9c\xba\x9bn_\xaf\x07\x18R\x12Y\xb1\xe4\xc7\xa2\x8b\x8b\x98\x95^\\h\x83~z\xd3iL\x92\x84\xd5a\xbf\xb5\xd5b\xc2{\x89\x89\xbe\xa38\xf5'\x01\xe1u\xf0\xb7\xb6Z\xe2Oy%\xfaK[%\x9b\xfa\x11\xabB\x7f\xe9\xaa\\`\xf1\x85\xb6\xc8KX\xfb\xf4\x87\xb6\xc2\xd4g\xe5S__\x1c\xf1b}\xcf\xfe\x9c\x15\xfbsmq\x10M.\x7f\xce\xa2\x94\x8f!\xffS[9\x9a^\xb3j\xd1\xb4\x12P\x05+\xb0\xa5\xd3/\xdcE\x96\xa6Q\xc8*\xe0O]\xa5\x89\x17\xae=\xb6\xb8\xec\xa7\xbe\xd2*\xf5yS\xfc\xb7\xb6\x9a\xcfgE\x7fh+D|i\xe9\x0f}\x85\x80\x97kc\xc6N\xa2`\x1eG\xd9J\xd4\xc1?t\x15\xa7^\xca\x90\x91\xfe0U\x08\xfc$\xcd+\xd1?\xb4\x15\xa7\xac\xcaT[H\xd8p\xa7D;\xdc)I=?Hx\x15\xfc\xad\xad6c\x90\x9d\xce\xb4P\x9d\xfa^\x101\x9cb?\xf5\x95\xd6\xbc\xc6Z[\xcc\xc7\xa9\x1f&\x87\x82v\xfed\x89\x85d\xa9/\xbc S^~A\xb4 \x9a\xf9$\x98\xa2\xe9`l[\xe2\x0f}\xc5\xb9\x8cf\xc5\x9f\x86\xcaYLD\xc5,\xd6\"\xd3,\x8a\xd0+\x93V\xc2\x9f\xfaJ\xf1\x92W\x89\xb5s\\\xf4\xb1x\xd1\xd7\x16\x0eX\xe1@[\xb8\xc3\nw\xb4\x85\xbb\xacpW[\xb8\xc7\n\xf7\xb4\x85\xfb\xacp_[\x88V\x1f\xb4\x98x\xda\xf5\xa0\xef9P\xd8Om\xa5b\x97-\x8c{l\xc1[\xd1\xb7\x90.\x19\xca\xd1\x1f\xba\n\x8c\xc4j \xac?\x8b1\\&-\xc7\x9f\xdaJK\xb6%\xfc\xa5v?\xf8\xe1*c8\x87\xbf\xf4U\x12^A\xbb+//\x18 //\xb4p\xbc$\xd7s\xc2P\x95\xfd\xd4U\n\xbc\x0bN!\xf0\x97\xb6\n\x99\x93\x90\xf5\xc4~j+1h\x05Zp\x05~x\xc9\x8b\xc3K]\x85\xa5\xe7\xb3\x81\xd2\x1f\xfa\n+^\xae]\xe8\xa5\x17_\xf2\xf2X\xdf\x01 3V\x81\x84\x99\xa9\x82\x9frR\"\xfe\xd0W\xe4t[\xe7w\xc8+p\xec\xc5_\xba*\xa1\xc7Ha\xe8iIa\x181\xbfaV\x87\xff\xa1\xab\xc8\x04F\xac\xc6\xc5Z]%\xb6\xbc\xfa\xe3*Z\xa5\xc5F\x12\x7f\x18*\n\xba\x17\x19i^\x94\xa5\x02\xa7\xd9O]%\xd6\x97\xb6\x93\x95\x17{l\x05\xf0\x97\xb6\x8a?I\x05]\xe5\xbf\xb5\xd5D\x15Sq4\xcf9F\xf1\x87\xae\xe2\xcfX\xe3g]Q\xcc&\x12kg\x123(\xc4Z\x08\xc4\xd9\x05\xe3\x99\xe8\x0f]\x056.\xed\x80\x12o\xc9\xfa\xa5?\xb4\x15\n\xd41#NB&\xf9r\xf2\xdf\xfaj\x81\xc0/\xf6S[i\xe9\x05\x0c\xc5X\nN]\x15L\xa3\xc4\xea\xe0Om\xa5\x95\xc7\x07\xb4\xf2\xf4\xa3I\xe3(d$\x95\xfd\xd4W\xba\xe6\x0c<\xfe\xd2V\xc9\x18\xeb\x9ddZ\xe6;\xc9\x96K/\xbe\xe6U\xf0\xb7\xbe\x1a_\x07\xfd~IY\x1c\x95\xd8\xb6R\xe6\xdb\xa2\xa9\x92\xf3\xce\xa9\x89yN\x19\xd9M\xb5$7%\x1f\xd3\\\xa4\x11\x7fh+R\xde\x82\xd5\xa2\xbf\xb4U\x16\xac\\\x9br=\xcd\x8f\xec\xd4tf\xa7>?\x0e\xe9\x0f}\x85T\xc0\x03#L\xeb\xaa0\xaa\x99jIf\x1a{\x93K^\xeeM\xb44\x9e\x11x-u\xcf\x18\x82fZ\xec\\{\xac\xe3\xb5\xa7\xedy\xedO \x13\xa7\xf0\x97\xae\xca\x15\x17r\xae\xf4R\xce\xc4\x8f\x85T\xc9~j+\x05\xfe\xea\xad\xc7\xd7A\xfc\xa1\xab8%3\xc1\xaf\xcf\xb4$\x82\x04\x81\xbf\xe2\x02$\xff\xad\xab\xc6v\x92\x9e5Yzs\xce\xdd,1\x93C\xb5J\xe0\x87\xac\x06\xfda\xaa\xe0\xc5_\xc5\xde\xd4G3f^\xb5x\xa5\xfbh\xe9%\xe2\x1cO\xb4k\xbc\x12\x10Z\x19\xa0\xb3\xf2\xd2\x94\xc4\xa1\xa8C\x7fk\xabE\xc1\xf5\x9c\x13@\xfe\xdbT-\x9f\xa9\xf8CW\x91\xce\xc9\x0bJ\xb3-\xbf\xd2~$\x88kl\"\xadi\xc4\x89L\x1a\xe9\x89\xfd\x9a\xd3\xc3\xb5v\x1d)Q\xc8\xa9\x83\xb6BNtSFuK5\x0c:\"v {\x07:\xa2:\xbbvn3\xdd7\xb9\x07\xfb\xc2\x9e\xecs\xc7\xd1\xdf\xdb\xd8\x01Yx\xe4\xd0\xfe\xe4`\x8cw\xa0\x03\xd6\xd8\x83s\x8f<\xf5\xf6\x97[\x8f\xebcYT\xdckx\xa8\xe7}5V\xb0\xf0\x8b1\xf9\x18\xd7\xda\xa2\x08[\x92\xcfQ\xe9\x03\xb7\x08\xd6\xab\xf5E/3Z\xe3\xc9\x13/\x8c\xc2\xebe\x94%O\x9fj\xb4\xb7\x81Q\xe5\xeb1s\xb9\xb5m\xe1/\xddN\x00\xd4eQ^ym\xe7\xf7\xba\x86zt\xbaX/\x9f\xb7\xa1\"\xbb\xe0\xc5\xaa\xfc\xae\xd7PQ0\xf2\xeb:F\x1e\xf2\xc08X\x91\xdf'\x9b*\xf2 ck\x11\xcf\xd8T\xd1\x0b\xaf\x870\xb5c\xd9\xf6\xef5^`\x9bA\xf9f\xd6\xa4\x82\x17\x8f\xb8\\*\xe2\x99\x14\xe6\xce.DM\xf7\x8b\xca\x15\xccVal\xe0\xc8\xf6\x1d\x0b\xdb\x12n\xdf\xf0\xa3\x05\x1d\x88\xa0\x03\xd6\x8f\x10\xcd\x8a\x94s\xac f\x05\x0b/\x01?\\S\xea\x93{\xcf@\x18\xa5\x98\xc0\x82\x8a\xdd\xfe\x94\x88\xa9vM\xe9C\xc5C\x11\x14\x13I\x8dCC\xb2W\xf1`D\x89\xf2\xa5yV\x1b\xb0B<\xb4\x0b4\xad\xacD\x17\xd0=e\xc8\xbc\xe4\xf3\xa4\xd3\xf71\x16\x99\x02\"\x0c \x8d\xef\x12\xf6.\xc9V\xab\xc0gi>$\xa8\xb9@>\xae\xc8$%S\xf0B\x06\x9d\xaeu\x9b\xebX\xf1\xe4w\xe0<\xd0\xc2\x04\x9e@\x96\x1b\x06L:\x9d\xb6\xa0\x99aj\xc9\x0c\x93\xe2r\xcc\xa2#\x1e\xd3\xb1O\xe8\xaf3\xcb\x05\xaf\x05\xe4\xe8\x02\xcddCJ\xf4T.\x8c.>c\xb2:sx\xf5\xb91\xdc\xe2\xea\xb7\"\x11\x1eb\xf9\xde\xfa\x82;qC$O7@l\xef\xcb#\xb6\xd7\x1a\xb1!\xf1\xc3y@\xe0\x84x\x93\x94s&\x9f\x87\xe5\x9f\xb3\xf0\xa6\xack\x02C\x7fWB\xbce\xd3\xc5/\x99\x19\xb7^c\xe6P\x14zK\x16)K?+\xf5\xf1\x1a\x8d\x9eM\x0f\xc3\xc1\xae\x14\n\x16\xe3\x0d\x97\xde\xe0h\x8a\xad\xdd\x8c}\xe2\x11vp\x95\xc6Z\xb5pc\x1b\xa2W\xab\xcf\x97Gv\xb1\x92\xf4s\xac\x91a\x8d\x7f\x1c\xba\x1b\xb8(\xbc\x92\xbb%\x91\xabu\xb0R\x1fD\x9bk;\x1d\x933Ge0\xe4\x05\x88\x8b\x05\xf0\x0d\xc0\x0e\xab\x94\x05I\xca\xebhJ\x1a9\x8a\xcf\x81\xa1\x89d0\xbe\xf2w%\x18\xff0\xceM\xcc\xb5\x11\xd0\xf2\xa9\xd6L\x93\xdaq`%+\xb3\xad\xd1\x08\x92:T\xbaC\x8e\x8c\xf5\xd98g\x89\xeb\xf2C\xc8\xea\xf7:\xf0 e\xdd\x85\x97H\xd1\x95\xecI+\xd2\x0f\xf5\x0cZ\x17\x19\xb4v\xac\x19|.{\x06\xff\x00\xd2\x15\x85\x1b\x1c\xd1\x1a\xe9@\x8aTW\x11\xd0jL\x0d?o\xeb\x16Q\xd1\xc4\xce`\x810\x1f\x83\x07O \xcd\x19tO\xf6\x866=tR+\xba\xf2\xe9\xd8\x93\x89j\xed\x04@\x12y\xfer\xfa\xe6u\x91?H\x9bYB~6\xdcih\xb2*\x1f~-\xb6Z\x14\xe2\x89\x99o\xcf\xba\xf3\xf2\x16\xe8B)\xda\xef\x8e2R\xe8i\x16\xad\xbb\xb4\xd2\xa4Y\x14\x13\xba\xa0T\x9b\xa9_~\x8c'C\x98\x0f<\xb2\xb7\xfa.\xe4\xab'\xe2\xf4\x96\xd6&\x87U\x17\x8eU\xb1\x14\x8f\x8f\x05\x99\\\xe6`L\\\xb8\xc8R\x88\xc9\x84\xf8k2\x85?&\xe0\xa5\xe0\x87S\xf2\x11\xfe\x98t-\x17\xce1\x99\x0bA\xe7m\x05l\xe6\xd5\xfd]\xb6`\xef1d\xa5\xe5\xc8\x9a\x97\x03\xa4\x1d\x94\x8e\xb3\x86%\x01(\xfb\xd5&\xe5\xd1R\x02\xed\xb4\xa2\x8e\xd0\x9a\xc6\xb6\xd9\x9f\x86\xadxw\xfb-Y\xb4\xb0&\x15\xcfg.\xe9\x7f=\xac\xc6\x8f\xac\xc7\x1f7\xe44Z p9\xb30\x9e\xb4\xc4\xd9Y\x9bf\x817\x1d`\xac\x84;\xe1C\x82\x1c\xd4\xf5\xdb\x01\x1a\xb7D\xbb\x0dswL \xf9\xe8M\xd2\xdf\x11\xeb\x93\xd6X?A\xacO6\xc5\xfa\xc9g`\xfd\xe4\xce\xb1^\xa0p\x86q\xed\x18\xff\xd4\xc4\xb5\xe4;%\xa0;\xa5\x15J\xd3\xda+\xdc)A\xcb\x9d\xb2\xb5\xda\x0cN\x97\x84\xcbdA=9\xfe!|\xe6M\xf3+\x0cZ\xa0\xf0l\x0c\x06,\xc6\x80\x05\xdcs\xe5\x87\x10/\xff\xd0\xd1E\xfb\x95\xec\xf7\x92:\xa5\xef[l\xd35\xf7s[\xd9\x89\x0bAu\xb7\x07\xedv;\x85\xdb4\x07\xdb\xf4\x1f\xb4\x8f+oo$\xafM\xa8\x06B\xd2\xe1\x8f\xd0Z\xe5\x891x\xf2\x02\xf8\xf4 \xfap\x1f\x0b\xf0\x07\x81!f\x00c^2\x84\xfeR\x03@\xe8\xfb^\x18\x02\x13,\xfc\xa4\xbb$I\xe2\xcd\x89\x14\xf8(I\xbd\xc9%\xbaW\xb5j|j\xc8\xff \xcaC\x9b\x11\xa5\xc8\x85\xcc\x85\x04)\xbc\xd6\xe5\x93>6=\x883\xa6\x89D\xa23\xc1\xa4V.\xb0X\xa5\x9e\xc3S.`b&dE\x8f\xbc \xf0\xc3y\x11j\x0dp\xe7xi\x14'0\xf5c2I\x83k\x91\xe4\x85n\x94(\xa6D\xe3\xe2\x1a\xd2\x05\x81\x1fWq\xb4\xda\xa6D'\xf9\x11V\xde\xe4\xd2\x9b\x93.\xbcO\x08\xfc\x987\xd8E\x865\xff\xd3v~\xa4\xfbl\xe2\x05\x01mb\xd9\x85\x13\xe2Ma\x19\xc5\x84r\xae\x8b4]\x0d\xef\xdf\x9f]t\x97\xe4~\x96\x90m\xfcz\xbb\xe8\xc7\xb8I$<\xc48\xd0\xe3\xe8\x0c\x0e\xd0\xd93\xf7W\x15\xef\x18\x91x\xb7 \x85\xacS\"\x9a~\x82\x86\x97\x94\xf1N &?g~\x8cZEY\x9eb|\xb7\x9f&\\\xd4\xf2\x13\xf8\x91vD\xe9(\x0c\xbf\\\x1f\xb9\xbf\xae\xe8\x88Nn\x08\xa9]\xc2\x91&Op\x90\xaf\xe6\xbb\x17~8\xb5\x19\x19\xda\xeak\xc0\x9b\x8b]~r\"F\xaa~\xd7\xabF\x981`\xfc\xba6\xa4\xa3\xe9@v!3a\xbd\xb8k1_\xe1\xf0\xb6\xe7\xb6\xe7p\xe2p\xd0\xee\xa8(\x1d\xa9K\xfay\xdbS\x95\xbeM\x05[\xcf\xd7\xa9\xba(\xaa\x17\x93\x1eb\xd7\xb6\x96\xf2%W>\x8b\x92\x9b{\xef\xe9\xe13\xf1\x12\x92;e\x0fk\xaa\xf0\x9b\xf7\xba*\x85\xbb\xb8\xbe\x16\x14\xd06\xa5 `\x0d S\x84\xe6f\x0c\x9e\xb7\xac\x19\xce.\x99[\xd1\xbas\x8b\xb6I\x97\xacI|m_7x@\x97=\xdeS\xb9\x89\xbaD\x0bk5Bc\xa3\xa8\xb0.9r\x86\xcc\x913\xe4\x8e\x9c\x93\xa6\xdb\x95\x8d\x1c;\xd5\xe7\xa6\xd1\x0f|+n\x953\x82\xce\xc1\x17)O[9\x98\xc7\x8a\x83y\x1b%\xc2c\xd8\xb2}LhPv\xec\xae\xfd\x12\x8a\xbb\x10\x9fyuK\x0b\xd97\x83f\x03gs\xdd\x98Zr\xbd\x18Z\xa8\xad\xb39*\xaf1\xf1\xc5\xb5\x9d\x8d\xfbg\xad&\x02mt;&\x8c\x16\xe1\xa5\x1b\xbf\xaf\xf6\x7f\xd3\x8a\xcc\xcd\xeb\xbd^\xc5=\x8b\xf1|R\xf5\x85p\x00\xdc.\n9?I\xbd~B\xe6\xc7\x1fW\x85k\xba\x05-\xa3\x13\xf1\x9e\xa4\xfc7\x9c\xd3\x14I\xa1\x18\x95\x18[\xff\xf2/R*B\x0b7p\x835\x19\x91\x07\xc8^W\xe1\xc8\"q\xd1\x81\x8b\x11T2W\x1a\x80\xbb4\xc7\x14\x93\x12\xcb\xe1\\rjW\\i1\xb7\xe8*\xe4\xc5\xda\xcc\xb5\xfa\xebJ\\\x82\xfa\xa8O2\x00\x9e{\xa9\x94\xb1g\xea\xa5\xc4\x90\xb4\xa7\xf2%[\xdb\xe2\xdb\x98\xcc\xc9\xc7\x95\xc6\xeb\xd9\x84F\xed\xe0y^\x8f\xac\xfaT\xd1\xe2\xc4n8\xaa\x19\xd2\xd6\x1d\xc3\x8d\xc7\x9e\x98\xbd\x17\"gS{\x86\xd6\x1f\xc5\xac\x0e\xae@]\x05\x0e\xe6\x16#\xaa\x1bP[\x1a\xd3\x14\x89\xae\xfc\x17\xffH\x8a\x88 #v\xc5&g/\x08\x14I\x05F\x94\x95\x0e\xba\xf2\x8b\xc0\x055\xe8\xe7\xad\xccb\xebb\x01\xe5W\xfaw\xd4\xbe\xd5\xdf\xeb\xeewy0\x84[\xb5\xb6.\xc2\xec\xef=tLa\xc5\xfdV\xf6\xcf>\x7fu\xf8\xfa{C\xbc\x87$\xf5R\x7f\xd2\xae\xee\xaa\x08\xb4\xde\xa26\x8f\xf2\xba\xc1\x07\x0b?\x98\x1em\xfa\xd5\x9c\xa4\xcf\x199\xa0;P\xf9\xe6\xfc\xd5\xf1\xc9W\xc7\xcf\xcd\x9f\xbe\x0c\xfd\xd4\xf7\x82\xd3\x14S=l\xf4\xe9\x914\xdcM>\x8dI\x88\xfe\xbd\xe2\x8b7\xaf\x8f\x8e\x8d \xe4[\xe8[?\x08^\xb1p\xaa-@\x92\x7f\xf6\xdc\x9f\xde\xe2+\xda\xd9 \xbb)\xd4\x80\xd4\x84G\x8b(\xa3\xe0\xe0m\xbc_MK\x10m;I\xf5\xbb6\xe3}\xeeOo\xf3\x19v\x17.[\xc3\xe7\xfd\xeb\xd3\xc3\x17\xc7\xe7\xb7\\\x13\xdd\xd7\x1b\x03Y\xd7\xc8\x06S\xcf\xb0\xaa\x94\xcf\xc1z\xf3\xe1\xf8\xe4\xe4\xe5\xf3\xe3\xf3g\x87\xa7\xc7\x1a\xe6\xa7\xda\xce\xc4Htp#\xc6\xfe\x9aLq7\xbd\x88\xa3e\xcd\x8el\xd3\xd7\xcc\xd8\xd7\xd4OV\x81\x87I\xceZ\xb2\xe4\x80\x84W\xfa\x0eT\xbd\xaex\x0c\xd7F\x82\xa6\xb6\xee\x8d\xb2\x9c\x9a\xd8\x9e\xf2\x93\xdf{\x84\xec\x9e;,\x85\x86\x0b;\x1d\x87k\xb4\xc7\xe1\xd9Fw\\\x1aR\xdaz\xdci\xb7\xf25f\x1b\xfc\xfb\x8d\xab+\xd3\x060\x85\x9a\xa1\xddzT\x86\x01}\xc6X*g\xc7\x06\xc3Q\xbe\xc5\x00G\xea\xbb\x11L\xed\xca[ly\xa8\xad\xbd\x11BJ\xa7\xf1\x06\xc3^Il\xaa\x00a\xfenS\xf8\xe5\xccC\xeb\x01l\xb5\xaf\n\xed\xf6\x10\x94\xf7\x91\x1f6\xb7*\x1e\xc1\xe85\x1b\xf5\x8b\x07\xc7\xa3\xda\x02\x86\xadm\x01A\xe8\xbd(\xbb\x88W\x9d\xed\xba\xa5Odo\xf9.\xfc \xadhy6\x9b\xef\xa3\x0c<\xbc\x10I\xc9r\x95\xfa\xe1\x1c\xd2\x88gi\x07\x0fb\x92\x90xM\xa6\x88)t\xa4.\xfc\xf8\xc7\xe4G\x17\xd2\x85\x97\xf2\x03;\xfc\xe1O)\\\x10\x88B\xbc\xa9\xb1\xf8\x8aZpI\xae\xbb\xf0\x9c5\xe5cn:/,,\xa6E\x8b\xf8\x86x\xd3\xc7\xb4\xce\x95\x1f\x04\x90\xa4\xf4\xff\x17\x04\xbc\xc9\x84$,94o\\\xb6\x17\xff\x93>t\xbe\xe9\x11z/\x04\x9a!\xee\xb5\xeeA\xf5\xd7&\xab\x03\x12\xcf=\xa9.4\x1c\xc0d\x1c\x9eqE}\xfbq@!^F\xb6\xee8D\xbd\x87\xe7\x82\xd5z}\xe9RR\xc8^GY,\x19\x0b\xe3\x0dY\xba\xf0B\x88\xc2 \xe9\xc2\xbb\x85\x9fP\xc8\xcf\x02\x7f\x92\xc2\xd2\xbb\xa6k3\xcd\x08m\xc9c\x87Z\xd7ba\x99\xd7\x91?\xb5Q\x8f\x8ct\x0bo\xad\xe3\x86\x80\x93\xf2S\x7f\x01,?\xbc\x13}\x1ch\xf5in\xd6\\\xe3\x86Q\x99Mh\x9a\x97\xa5\xd1\x85\x1fN\xcb&\xf7\x1b\xdcA\xeb\xd3\xfd\x80d$\x98\xa8\x88E(b%cbF\xacs\xcd'\xf7\xeeQd*\xb3p,tm \x8f0?\xc3\xcc\x9b\x10\x13BEk\x12\xc7\xfe\x94\xa3\xd4,\x8e\x96\x1c\xa9\xe8\xd7\x90\xac\xc8\xc4\x9f\xf9\x13\xb40\xef\xc2q\x98d\x0c\xc3RVkI\xd2E4\x85\x10\x93\xd1N#\xbc\x01\xa6-\x06\xde\x8a\x85\xf2\xc4\x91\xf0jhjH\x1c\x97\xdd\\\x94\xb7\x82\x08\xbb\xfb\xe9\x93\x96a\xbc\xcd\xcc\xbe\xc8V!\xedn\xe3\x90q3\xa7\xf00\x11\xa5\xc8`\x1cZ%\x0d\x7f\xaaL7K(\xd9/&\xc8\x160\x8a\x8bAQ2\xceg\x02/\x19\xe9v\xe1\xa7,I\xf9\xb71\x99g\x81\x17\x17\xb6\xf4.=w\x08\xda\x86n\xde\xff\xc6\xbd\xe9 \xea:\xcf\xd7T\xa8\xe1\x8c;\xde\xc7\xfb\xa4\xf3\xf3\x98\x0e\xf60K\xa3g~8}\xeb\xf9\xb1&\x863\xc8\xac\x83G\x8f\x96P\xddf\x19\xcb\x14\xdee\xdc?.)\xff\xedh\xa3\xd0\x8b\x07\xd7Xm\x8c\x19Vxx\x8d\xd5x*\xad\xb9ch8\xf6Z\x98\x8e\xadp\xda\x95\xfe\x9a/\x02\x03{\xc5\x12\x01\xcd\xaa_;0\x1b{gt\xd2\x93\x86\x96jbQ\xcb\x0f\x9d\xd3BG\x00\x9bF\nu\x86\xd3h\xbd\x82\x01\xc4W\xe8\xe6\xd6g\xa4\xa2+(y\xbb\x13\x0c-\xf5\x9b\x16E~\xd6<\xa4w2\xf6Zr\x8f\x80\xfb\x1b\x03\x9b\x9b\x99\x80k\x95\x00\xf2\xd7\xea\x0e|\x1f\xe6V\x04\x94D\xc3*\n\xfc\xc95\xfc1A\x94\xbe$\xf8\xf3jAB\xb6\x03\xe7\x14\xbd\x8b\xadI?Ab|\xcdV\xbff8\x07\x10\x8f=\xc6\x13\xd0\x1f\x14\x19`\xa8\x1b!\x8b*\xcc\xea\xae\xf3\xba\xed\xa0\xcfCT\xf3\xaf'\xcd\xf0d\x11\xadY*\x16\x8f\xf6\xe3\xe6\x1f\xd7~[\xc3+T\x8f\xf8V\x84~a<\xef\xcbbIds\x8b\xb2\x9a\xfc\x01\x9a\xf7\xc4\x05kI\xe29\x11\x89\x97^G\xcf\xb3U@\x0fd\xf25\xb9Nlg\x08G^H\x8f]\xac\x06a\x14n\xb3f\x12$\xe0\xc4\x01\x8d\xc8\xc2r\xa7\x95.\xf5\x90\xe1k\xec\xeb]\xcc-ZXo\xe9U\xc4\xe9w\xc2\x8e{\xca\xe9'\xde\x92P\x14\x1c\xe2\xd1\xdb\xead}LA\xb4\xc2\xa8\xb3\xf4L`Vr\xa2\xea\xc4\xcb\x12nNv\x15\xa9j[\xdb\xa1G\x9c\"L\xdb\x8e\xe088\xdfMw@i\x9c\xf4p\\\xd0\xb7\x97\xe4:\x11,0gL\x0d.\xaa\xc2\x86\xb0\x15ZL\x9bL\x11e\xf6\xd2x\xee\xa1OI\xd7[\xad\x82k\xccE\xe2\xe6\xde \x89\xc1\xd1\x91>(\xd4\x1a\xbe2\xdf\x8f\n\x9b\xb8\xc2\x11%n\xae\\\x18{\x84\xe6\xd3\x1bC\x1ek\xe2G\x83t\xebf\xfbl \xf0\x87>\xd9I\xbb\xfd\xb8\xfel\xc0\x1b\x01n\x04\xea-\x87z\xdd(*\x10f=\xa7\xbb%\x16`WzR[\xd1\xe77\x06\xfd5A#h@X\xb4\x9e\x9f\xfb ~\x84F~\x9a$\xeb\xa0'\xa9U\xa4]6\x0f\xb0\xa4\xaa\xbf\xf5\x18\xf5\x06/\xad\xc6xn\x1c#\x8fY\xce/\x90Z+\xb7p|L\x1f\x1fwI\xf8sF2r\"5\xc51lc\xe95\x9fpK8 c\x9c-\x15`\xb7\x87\xd5\x859\xd90HV\xa2\xf6\x85|\xab.\xf3\xf6p\xae!m\x05d\xeb\xc8%Q\xaeT\xe3\x1a{P(\xd0\xa4*,\x88|p\x94\xf9o\xecY<%/\xc2T\xdb\xaekP\xf5Cg\x04\x83\xa6\xf6A\xd1Y6\x8b\x05\xc0%\"2\x0e\xa1\x03\xfd\x16|*&\x84\x181\xca\xe4\xdf6\x10\xc2\x0d\xa2\xaf\xc8\xb3\xb7\xe2\xda\xedj\x96c\x91\xd07&3\x0cj\xe6\x96\xf6\x850R\x0f\x0b\x93\xf9T\xe4\x172ODh\xef\xf0\x13\x85U\x80\x03\xedk\xdbiT\xe8E\xb6\x865\xf3\xd0\xb0\xaelO\x86\xcc\xf4\x1f5]\x0caI%_\x8e\xfe\xb9\xbf:\xe5]h\xd7\x16=\\\xe4\xeb)*\x050~\x9fR\xc1\xc4\x97.\xee,G\x81\x88\xa7\xdf\xad\x0d\x12o\x8c\xca\xf2\x92\xb5KH\xae\xe0\xc2\x95_\x96\x82\x88`\x8ef\xb9P\x87\xe2<\xd5\xa0'\x12\xdf\xdb+\xd9\x02\x9c8\x8e\x0b+\x9b\xb80\x17?R\xf1c\x89'\xacz-\x82\xbe\x08\xdd\xa9rS\xa2V\xb3\x1d\xd4U\xc8\x83c\x17\xed.XR\nx\xbb\xdb\xedR\x86\xb9\xaa\xdab\xcb\xe3/W\xcc\x1c\x05<\xf8\x915\xf0#\xe7$\x91\x99N\x1cy\xfe\xd3E\xa64'\x13\x8fJ\xb4\xfc\x83A\x14\x92\xffJ\xcb~ \xca\xad\x8d`p5\x80e\xd1\n5\xa9\xd3Y\x80BM\xc1\x0c#\x12j\nD\x04BM\x91p\xd8\xd3\x14\x89(\x83\xba\"\x1eWPS\x84\x91\x04u\xefE\xc8@\x8d\xd62\x8fa\xa6\xf9N\x0er\xa5\xf9\x94\x85\x052N\xcc\xf0\x15\x8f\xc8a*a\xc1\x174\xa5\xdcU\\7\x05\xe6N\xab\x98\xc3jy\xbe\xb0j:\x19\xbb\x10\x96L'C9\x9f\xeag\x10\x0e\xee>\xc9n\x00\x8a[\x13\x17\xac\xf3s\x92\xbc\x8a\xa6Y@,WA?4\xaa\x1f\xca\xd2\xcc\x0d\x1eI\xfc\xf0\xa9\xa3\x1e|\x8aUt\xce\x85\x98dh`\xef\xdeE\xab\x0b/\x1eB$\xfa\xa9\xd42Y\xad\xde(\x84\xd2\xcd\x89\xfc\x8e\x86*\xda\x94\x90\xfa\xa8\xf9\x89\xbb\x05\x14\xe0\x00b\xd0\x8dMX\xd9V\x1c\xb6\xe0\x1f\xbe(\xd5\x03be\x87v\x7f\xf7\xa1\x9a\x03\xd4\x17E{=]^QVT\xc9\x1c\x9a\xe5E\x95l\xa4^^\xb4\xaf\x16%\xdcfU=\xa8&\xcc\x0fWy;\xa3+\x82-\xed\xef1\x9e\x88\xae\xdb\xae\xa3\xb6\x1a\xf0\xf3l\xdf\xd1\xa5*]\x19\xcfg\xd4'\xa6\xe5uN\xeb\xd7\xd9D\xcdoJ\xd0^\xd4r\x07\xd2\xb9a\xba\xff\xb2{.\xf8\x02\xd7\x1d.\xe9\xea\x9c\x7fho\x88\xb8=\x172\xf5\x03\x9br\x9f\xc8v\x9d\x9f#\x13\xd6s!.*\x11\xc7a^E\xb9 \x1d\xea\\B\xc5\xa5|7\n\xdf\xc7\xc1\xd1\xc2\x0b\xe7\xa4\x95+V!\xe6\xa5^<'i\x9dCN\xd4MH\xca\xc4\x00\xb3\x80\x97\xc5\x81JE\xc5\xa3\xf1\x8b\xbeq!\xea\x06\x917=]\x91I\xab\x01GL\x0e\xebR\xa6\xf7\x10\xeb\nA\xeb}\x1c\xa0\x87\xb9\xae\xc64\xba\ni7j\xba\xf3|\x0c\x08\xb7S\xcc\x8e\xd0j\x18z\xb8\xa1\xe7\x9ax\xb3\x88\x89\xc1.\xa6\x98\xb2Mp\xc0\x14\xae\xd87\x99\xd2Y\xe0\xcdrw\x15\x935 \x85t`\x1b\x06.f\xf6>\x0eZ\x0d\\\xea;b\x82W7\x8b\x83\x0d:\xc4\xb1z\xf1\xa4~\xff\x88G\xc0\x89\xa2u\xd0]yqB\xd8\xd7\x8e)\x834\x19[Y\x1cPq\xdb_z1\n\x91\xd6Y\x1ew\xd2\xac\x9c\xa5\\\xd8\x95\x1fN\xa3\xabn\x10\xf1k~\xdcW\x93\x08#\x1f\xdc\xbfoA\xa7Rc\x11%\xa9\xe6\xf5\xcaK\x17\xe6\xeeXmJ\x98\xf8w\x0b?I\xa3\xf8\xba\xfa\x06/v\x98\xcc^-\x93un\\\xac\xb4,\x97\xc5\x1c<\xa0\x83e@KH\xec{\x81\xffK\x0e8]\x86\xde\x9b*\x1am\xb4>b\xd3\xccIz\x14\x853\x7f\x9e\xd8\x0eE\x8c\x84\xa2\xf4\xd8\xa0p\xc1I\x11I\xc7\xc4n\x86r\x899\xef^\xe7\x12Pj\x88v\xc5]\xb2\xf0B\xa7\x0d\xa5\x81<\xb5 \x99\xbe\x0c\xa7\xe4\xe3\xd0\x90\xc2\x1e8\x03$\xe1\xae1\xcb\xb1\x89FE\xe1\x0b?HI\xfc\xc5H+\x03\x7f\xe0]GYZ\xa6k\xacc\x9d\xfd [t\xae<\xd1\x0f\x02\xc9q\x8a\xb4\x90\xa1F\x14'\x14\xd8\xa6\xf8\x92\n@\xab\xfap\xdag\xe9\xa5\xd6\xf9\x88b\xae'\x9dbL;B\xdfF\xa5\xb7\xe3\xea\xa8\xf1\xbe\xcd2\x1a\x98kl\xc29g\xd5\xbc\"L\xd9\xd4\x8cYf\xa0\xb5\xc6\x992\x88T^\x10\xf4\xf3D\x9du\x8b \xd6a\\\xcau\x86f\xa5*\x11Z\xc5\xea\x8e7\x7f\xc4.q\x9a\x08\x02\xde\xa8\xd1\x1d\x1cr\xa2P\xb7\xe9\x0b\x15\xb0\x86\xe0\x9bU\x981k\x7fc\x1a\x03Hg0v1F\xc7`|e\x0bl\x10OkZ\x03z\x9ch(j\xbc\xb7o\x81D\xe2\x06\xec\x8ep\xe86g\x02\xe7\xd7\xa53\x816\x94\xf3\x1c\xe9\xb8\xd0\xf8vK\x10=C>\xe4\xf6@`Z\xce;\x9dy\xc3\x1eb\x80\xd1z\x07\xca\x0f\xbb\xfb.\x11\x13s\xe5\xb8h\x18!n\xae\x89\xf7!\xb6\xf5\xcc\x98pU<\x11\xab\xf8\x8d!i\x9fx\xd0\xc9\x8f\xae\x93\x1f\xce\xb9\x95b\x97\xffIwHVK\x1e\xbc\x9a\x9bqk\xe6\xf9\x01\x99\x1a\xda\xc4\xf3\xde\xebN\xa2\x00\x15\xf3V\x8c\xd9=!S\xdf\xff\xff<\xcf\xab\xb3\xac\x0b\xd0\x11\x80\xe1\xa7y\x9c+\x83\x0f\xa2x\x16\xb5\xf72<`\\=I\x9bb\x17f\xfa\x15TIW\xd3-+}\xa6\xccFh\"\x8eO\x9e\x9aYh\xadE:?\xdd\xfeP\x1f\xdc/5\xb6\x87\xe2\xe1\x1b'\xa50\xad'v.\xe7\xcek\xac\xa4(\x03\xb6j\x98\x03\xcb]\xd94\x054\x07e.S<\x9f\xdd6\xff\xb0\xf6\xb3E\xba\x0c^Dq\xfeQ\xd5uK<7.\x18\x87\x88\xf9\x95\xf2(f\\`\xf4\xf0\n\x86\xa2\xad\xf9;\xd6g\xd3\xdc\xfci1\xbe\xfa\xe9L\xfd\xc4\xbb\x08\xc8t\x08Y}\xc5(d<\xeb\x90\x116I\xd0\xad\xff\x8e\xaf~PO\xb0\xeb\x808uLL63{[\x08b+\xc9\xb0\xcdH\xc2\xd2\xac\xd6\x01RF\x10\xd1\xf4v\x16\x07\xdb\xfcS\xe3\x87)\xaa\x8dY\x9a\xad\x1az\xaa\x01({c\xfeFl\xa5\x02\x94Y\x1c\x98\xab\xb7Z\\\x9e#\xd1pi\xea4\xef7\xffV@\xe4\x19\xbek\xe1\x13\xf8\x93\xcbaem\xf5\x03u\xc1:\xfe\xb8\n\xa2\x984\x05;3\xa2\xc4\xd4_\xb7F\x88\x14\xb5\xd4\xfa\xcd_\xb7\xf17\xe9\xe3*\xf6V+\xf2\x85;a\x13\xd9\xbem_\x91 b\xe6\x8d\xb6\x9c\xd7\x0efA\xfc\xf9\"\x1d\x82\xb5\xd3\xab\xc1\x86+\x7f\x9a.\x9a*%\xf1d\x0831\x90\x1a6#\xa0\xfd\x9d^y\xf39\x89\xe1\xfdK\xc3\xack q\x89\x80'\xac)\xcb\xa9\xfb\x04\x13v\xb7]\x96\xd2^\x11\x8bS\xb7YN\xb3\x8b\xa5\x9f\x0eaaZ\xc1Uw\xe9\xad\xda3\x0b\x92\x04\x9et'A\x14\x8a\x898\xf4\xd3\xfa\xe3\x87q\x06f\x9an\x92\x7f\x1d\x1d\xa5W8\xf73\xc7\x95\x9a\xbe\x91\xa8R\xceCK\xdb_\xbe\xacb\x90Qojd\x18\x94\x02\x80`J~\xccxy\x7f\x15\xce\x1f_x \xd9\xdfu\xfd\x0f\xcf\xde\x9c\\\xf5\xbe\xfej\x1e\x1d\x1e\x1e\x1e\xbe>}\xbf8~??<<|\xb6K\xff&G\x87\xaf\xe8\xbf\xaf\x1e\x04\xfb\x7f\xa5?\xbe\x7f\xf1\xec\xd5\x87\xe3\xf7\xb4\xc2\xfb\xd9\xd5\xad\xfe\xeb\x05\xbf<\xbb\x1f\xf6\x9e\xcd\x16\x1f\x9f\xad~\xba>\xea}\xdc\xbd\x7f\xff\xfe\xfd\xce\xcf\xeb\xdd\xa3\xbf\xac\xfa\xcf{\x8f:\x9dY\xbast\xff\x97\xbd\xfb_\xf7\xf7\xef\xbf\xdfy\xf0\xe8\xfd\xec\xea\xf9l\xef\xe1\xfd\x9f\x1f<\xea\xbc\x8f\x07\xcf\x07'G\x97\x8f\xe8x\xfe\xfc\xdd\xc9\xe9\xbb\xe0\xd5\xe1\xf1\xf1\xe1U\xf8\xe8\xfe\xfd_v\x0e\xe7\xeb\xdd\xfb\xeb\xef_>\xbf\xaf>\xef_\x91\x9f\xfc\xfe\xe5\xe1\xe1\xe1\xf3\x87\xa7\xefO\x9e}\xf8\xf3\xfcY\xf0\xb7W/\x0e\xa3\xbf^=?|w\xf2\xf1\xe2\xbbg\x0ff\x9d\xf5\xdb\xaf\xc3\xe0\xbb\xc3\xbf\x85\xfb\x97\x83\xc9l\xe7\xf0\xd1/\xf7\xdf\xce\xde\x1c=|\xf9\xf2\xfb\xd0\xdf{\xb1\\\x1e>{\xf5\xf0\xc5\xab\xc5\xd5\xbb\xfe\x83\xc9\xa3E\xb8\xf0\xff\xf6M\xff\xe8j}\xfcM?]\xbe}\xde\xfb\xf9\xf4\xeb\x9f\xf7\xe7\xdei\xfa\xed\xfd\xcbW\xdfy\xe1\x87\xe5\xe1\x87\x93\xe7\xef\x83?\xf7\xdf\xac\xb3\xec\xdd\xcb\xd7\xd1\xfe\xe5\xa3\xde\xe9\xc7\xd9\xc3\x9f\x937\xe9\x8b\xfd\xf9\xeel\xd6\x8f\x92\xb7;o\xc2W\x93\x0f\x0f\xa6\xbb\xab_\xa6/\xdf\xa7Y?:\xdc\xfd\xd0{\xfe\xb7\xe8\xeb\xe5\xc7ep\xfc\xfd:}\xfe\xfe\xa7\x9fNw\xd2\xe5\xd7\xcb\x9f\x9fuV\xdf_?\\=\xef\x7fx;{\xf0\xd3\xdb\xe3\xde\xcb\xdd\xde\x9f\xff<\xf1\x9e]\x85\x19\xd9\x9f}\xf5\xcb\xfc\xfat/\xfd\xee\xe5\xfbG\xfbo?<\x88/\x9f\x7f\xfb\xe7\xd7\xdf|\xe8=\xffz\xf7\xc5e\xf4\xf5\xf2\xc5\xea\xf5^\xf4>\\\xfb\x0f\xbf\x8e\xc8\xe1\xe0\xfe_\xbeK\x96\xdf\xfd5\x8b.?\xf6\x12\xff\xa4\xff\xd5\xc3\xf4\x9b\xcb\xd7\xfb\xe4\xd9\xa3\xe4\x9b\xab\xbf\xac\xee__/'\xd7\xde\xdb\xfb\xef\xe2\xb7\x9d\x93\xb7\xcb\x8bW\xaf\xfc\x8f\x93\xbf|\x98\xbf;\xe9{\xef\xff\xf6h'\xfa\xea\xbbd\xfe\xdd_\x0f\xbd\xaf\xf6\x8f\xaf\xe8\xb2\x1c\x9e\xbe\xff\xf0\xe6\xe4\xeb\xbd\xa3\xef_\xbe\x1c}F\xd0\x19\xd2\xbd\xb8N\xc97Lj\xae\xd3.\n\xad\xe2\xc4N5\xf2\x18\xaai\xc6=\x8d\x84\xc34-\xaa\xe9\x1c'\x16;\xf0\xcf`\x87\xd0\x81\xd8\x81\xfb\xb0\x0b\xdb\xd2]\xe9\x8d\x0b\xa4\x9bF\xcf\xaeS\x82\xa6a\xf5\xd7f\xb9\xe9 \xb3\x10\xc4Q2\xcb\x17:*\xe6\xfc:\xee\xf3\\\x14!\xb9\x82\xa8\x92\xe4\xa7\xc6N\x03\xc7I\xa0C+\xb1q*f\xc3x{\xe6BF\xe99%\x06=\x97\x05q\x86\xa7\xd0\xc3\x0b\xe2m\xd8\x85!\xad\x120\xfb\xc5\x00\x9e\xc0\x8c\xfe\xd3\x19\xc1\xae\x83\x90\xf5\xc7iw\xb2\xf0\xe2\xa3hJ\x0eS;p\xce\xe0\xc9\x13\xe8?\x84O\x95\"\xe8@\x9f\x17\x0f\xf4\xc5\x03V\xbc\xaf/\xddq($\xc6I\xa7\x83\xe6\xfa\xf0\xf4)\xf4\xf7\xe1\x1e\x0c\xf6\xf6\xd4\xf7\x0f+\xaf\x07{{pO\x0d-5@)\x9bI\xcf\xe6\xc9\x18\x06K\xe7\xf2\xf4)\xecV;Q\x18\xb3~\xab^\xfa\xbdZ\x90\xed\x9a!\xf6\xf4)\x0cZ\x03\xc0\xd1\xa2\xb4WF\xe0Y\x1c-o\x87\xc2B\x97\xc5\x8d\x12\xe0\x8f\xb0\xc3\xc2=\x8e9>\xf782\xc36\xf8,\xc7\x83G\xff\xe9\x8c\xa0\xbf\xbf\xf3p\xc7\x81\x88\xb1\xe13\x8a\xe0\x99\x8b\xd1n\xb1\x04\x9e\x82\x07\x07\xe0\xc1\xb0x\xa7\xb2\xc0\x0c\xd2>\x1c0@\xa7c\xda\x0d\xdd?\xbc\xd1x\x8c\xc0\x19\x9c\xd1\xcd;&\x0c\xae\xf7`\x7f\x87\xbe\xb0F#\xcbq`\xc8\xb1\xc2\xcf\xd7\xcbf\xed\x0cp\x1d\x1e:\xd016\xdc\xef\x89\x96)b\xe4-\xf3\xae\x06RW\x15\xee=\xbf\x93\xfe)\xf2C\xdb\x92\xec\xb4$E\x91d\xc5\xc9 \xea\xf3\x7f)\x84\xa5\xf8\xab\x92\x9f\xdc{?L\x1f\xb2u<\x90\xff\x18\xb2\x90\x88lQ\xac\xc3gG\xcf\x8f_|\xf5\xe7\x97\x7f\xf9\xfa\x9bW\xaf\xdf\xbc\xfd\xeb\xc9\xe9\xbb\xf7\x1f\xbe\xfd\xee\xfb\xbfy\x17\x93)\x99\xcd\x17\xfeO\x97\xc12\x8cV?\xc7I\x9a\xad\xaf\xfe_\xea\xde\xb4\xc9\x91d9\x0c\xb4\xdd/k\xf6\xfe\xc2~q\xa4\x86\xdd\x99\x83\x04\n@\xdd\xa8F\xd7\xeb\xd7\xd3#55\xd3\xfdl\xaa\x1f\x9fH\x00S\xcaJ\x04\n9\x0dd\x82yTW\xcdT\xafQ\xd2R\xa2H]\xdc\x95(R\x07\x0f\x1d\xe4.IQ\xa4\xb4\x07wy\x99\xed\x9b\xf9#\xfa\x03\xfb\x17\xd6\xc2#\"32#\"\x13\xa8\xaay\xd4\xc2\xac\xbb\x00\xcf\xc88=\xdc=\xdc=\xdc\xafo\xbe\xec\xf5\x07\xbb{\xfb\x07\x87G\xc7\xed\x1d\x8b\xa7\xcbat\xa4\xc8g\xe9\xc1\x13HN\xa0\xdd\xf6\x1cqS+\xc3+b\xc18\x93Q\xd9s\xe8#O\xe7\xec\xe0\x9b\xa9z\x9e\x1d\xa4\xf4\x14\xc35\xc0O\xc0\x1e%c\x0e\xa4\x8b8z\x87\xc4\x13\xa3\xba\x15Q}\x99\xc3W\x178\x1bAO\xd0\x0b\x02\x1e\xac\xb2e\x1a\xac\x97\x98\xf0f\xaf\xaaE\xbb\xca\xef\xe7`\"\x95\xd7s\x9b.\xa6v-;\xfcN\"\xb0x\xad#\xbc\x03=\x0eq\xa3\xe4\xf1\xc8\x87\x8c0\xd3\xfeN\x8b%\xd7\xcc\xc3\xdcD\xf1s\xa4\xe0\xa1\x90\x85+.m\x90\xad@H\xff\xb4G\xb0\xeb \xc2\xd8)] Jr(\xf5\xec\x1f\x1c\xf6\xfb\x07G=\x8a\xd7\xf4 \xba\x8c#\xa6St\xdd\x1f\xf0'\x8c|\xb0\xe7\x03*\x9df\x02\xf3\xed\x88y\x18Q\xfc?\x92p>B\xc8\xa0\n9\x90\x00\x07\xbb\xf0\x08\xa2\xea\xad+>}\x99f+\xe4\xdf\x82\xb1\xd5\xb1d\x0c\xea!\x06\x1d\x0c(jY\xe7\xbaG\xbbZyC\x9eM\xd2\x8d\x897\xab\x0b\xbb\xa7\xa0\x02\x0b\xabM\xe7\xfa\x08>\x84\x80\xca\x02\x942\xa8\x12\x05\xdd\x17v\x9f\xce\xab\xe7\xe8K\xf80\x82\x04\xe7L}F\xd9r\xe7P\x85\xa3\x9f\x10\x9cb\xc3}\x18BO-\xb2\xe6E:\xf4\xb9\xa6\xea\x05K`\x04m\xa8\xe6T@\xc4B^\xbff\x14f\x01\x8f\xf8\x18:s6\x08X\xc0\xd3\xa7#\xe8\xcc\xa9\xe4\xd0\xa6;\x18\xe6t\xdb\x9d`\xf9\xc1\xfe\x01|\x88\xe1\xb2E\x03.\x88\xfa\xe6\xd0\x19\xc1\x91\xa3i\x91\"p\xa4\xb6\x14\x95[\x8a\xf3\x96\xb2\xbc\xa5l\xf3\x96(\x91`7 #\x07\xfb\xda\x87N\xf5\x06\xaa\xe1~3}5\xc2W\x8b\xcc3\x19\x9c\xc2+\xef\x15\x9da\xd8\x81\x1e\x15\xbc\x16\xf9\x9ck\xf44\xc8\xf0>\xf5\xd2Ew\x1d\xbd\xb3\x07\xec\xee[D;Z\xbe\xc8\xaa7\x17KU\xe3\xa8?,U\x15Q$\x94\xf6\x0ce\xe8\xef\xe2 \xad^\x93\xa9\xcdiBq\x9b\"6\x0b\x19\xcf\xd1\x9b\xd6\x1c\xe8\x91w\x9e\xa3\xb7o@o\xf4\xb00\xa07\xc5\xd1\xc1n\xce\xbc\xe5\xd1t\x06{\xb4\xc2\x12\xe8\xf0\xd0\xd1\xe3:\xc5\xe5\x98\x93\xd5H\xdf\x8d\x19/B\xa7\xaf\xa3y~\x85\x12\xd4\x13\xe8\xc1\xed-\xbf#\x8b\x8e\x1b,K\xc4\x13\x14\x8cq\xa7i0\x97\xce0v\xd4\xbbH\xd0-)H^y\xafl\x82>\xf2\xcc\x90\xca\xd0\xe3\x14lJ2\xf2\xc7\xbcJF\xbc\xe7tp\xb8\x0b\xb0\xae\xf92\x8ab\x1b\xbf.\xa3KZz\x87=\xf8\xe4\xd5\xc0q\x81P\\K\xa0\x8cM\x9d\xccq\xe0 \xf4\x91\xf3d\x9d\x0ee\xcb\x1f\x8e\x80\x96\xa7\x07\x82\x11\xee\x94%<\xa5\xfd9\x855\xec@\x02CXW\x10\x89n\x89\xa5CQ,\xa1E\x07\xac\xb6v\x9b\xd6\xb6\xc3j\xcb\xeb\x99\x8b1\xc9\x83(\xb5\x82Om\x82\xb5u\x18\xe6\xca\x8d\x05\xac\xb6\x11,q\xf8\xc8\xbd*E\x96\xe6\xf7F\xd0s\x9c\x13\x08hcG'(\x9f\xb5aQ\x88\xbd\x1e\xa5T\xed\x11\xcc(\xad\xdeAzA\x85\xa7:\x12\x94Qd\x0e\xe0\x96\xbe\xeb\xd3w\x83\x13\xf0\x19\xc5Q\xaa\xcf\x8a\xea\xb3\xbcz_W=\x7f\x15:0\x9b\xc2\xed\x08\xfa\x03\xba\xb1\xae*\x1c\xae\xe1P,+p\xca\xdb6\xf7\xea\x0c\xed\xdd\xc1Q\xe5\xc8[x\x85\x96\x1dk7i\xb2\xb8\x921\xd08\xdb\xc6\xdd\x9f<{\xfd\n\x1d2\xf9W\x9d\x87M\x9e\xe6fXI{S&yMW8\xccwS\xf2\n\xf9\x85\xdd@{[w\xa3\xf1\x9a\xf4\x0e\x92g\xed\xa8\x14\x0d]LPd\x87\xf6\xee\xae\xe2w\x1c\xf0GG{\x8e\xd6\xa57\xfa\xf1\xba\xf4n\xe3\xdd\xde\xa8KU\xd3(H\xf9\x185q\xbbh\xf9\x8a\xe3.\xf3\x11\xa7\xef9\x1b7\x0b\x924^g\xa5\x8eq\xa5j\x94\xcaxM\xd8\xfc\x9c\x12\x03\x161\xc1\xe0\xc3\x11\xdf\xd4(\x8a\x8bP3\xeclT\xf5\x83vN\xa0\x85>\xfaH\xf2\x92Rv\x00f\xee\x0fy\xbc\x0b\x9e\x94\xc0\x85\x16z\xce\n\xa7!\x96\x1f\xc19\xe1\xe34\x18\x85\xde\x83\xef\xb1\x84 u\xda\xf0\x88M\x15\xcb\\n\xa8g\x1e\x84\xderY7\xe4\xfa \xa1\x9f\x16\xfa\x13%]\xbe\xd4\xd2w\x83\xd3\x18l\xd84\x08\xf9L\x9c\xfb2su\xfa\xf1i\xa1\xda[\xf7X\x9ca\xa7:\xe7\xc5\xa9\xf3\xcd\xcd\x9aTN\x9e<\x80\x12\x0bV\xc5\xeeYf1\x8b\xe1\x11\xa4$\xf6.\x96E\xc0\x7f\xe5\xc2V\xd14{\xf2 \xbcb\xb7\x1a\xdb\xfa>\xbc\"\xb4\x8f\xf6\x1d\x17B\xfb\xf8\x00=\xa5\x8b\x0e\xd0\x96\x06\x1bu\xbb\xe07\xfd]\x1d\xc7 \xed\x03\xc7\xb6p\xb6\xd2(\xaez\xea\xb0\xeb\x80\xbb\xa6x\xe1\x94\x89u\x83\xe4\xa5\x98\xebM4\xc89\x85\xd2\x9eUyD\x15\xdc\x8a\xe3\x80\xa5t\xf8\xeew\xf3\xee\xe1\x9d[L\xb7U\x8d\xc9\x12\x97|k7\x9a\xde\x0dWt\xefAWtww_Y\xcb\x81\xd3\xe5w{\xbc$ .\xc3Mj\x92\xd7U\x9a\xca\xd8\x8e\xbbg\xd0\x86\xb8\xfb\xb1\x0b\x16\xabU1\"\xb2V\xd8\xe8\x0e\xa4I\xdb\x08\xa1\x9an\x9a\xeeU\xaf\x94\xf2\xa8\xef\xbd\xaa\x14\xc5p\xeb\xa0:\xbd,F\xfd~5v\xbc\xc7j\x19T\x8b'9J\xf1\xc9\xd3cj\x0b\xbd\x07C{p\xec\xd8F>-\\\xf1\xbe\xd2\xc4e \x068e\x9a,\x91\x88\xceQ\x0d}\xc8t\x9a?K\x8b\xfd<\x80\xce!e\xe9\xc9z\x19\xa4\xb6e9\x1a\xc7-\x1d\xeb!\xe3t\xaap\x9b\xf7\x8e\x0b\x87\xd0\x1aA\xc2\x82\xd5:<\xcf\x91\x9c\x1e\x91=\"\x8e\x93\xab\x89\xe8\x0b\x92%\x86\x1e\xabj\x85\x88R \xe6\x0cm/t\xces\x911We\xd3\xf3o\x9f\xd9F\x82\xee\x9cYC\xa2\xee\xfc\x84\x9e\x8b\xc0\xd7\xe4\x15\xcak^\xbbx&\xf5\xec\xbc\xd2\xb1\xdfnO\x1d\x17\xcf\xa1\xf4\xd0\x14\xdb\x0b\xa7\xebG\xa1\xef\xa5\xf6\xdc^\xa0\x02\x9a\xc2\\<\x89\xce\xf2>\xdc0\x0b\xcc\x15<\x85\x9b\x13\x07\x96\xec\x9e\xd3\xc2\xc5\xb3\xf3l|Cke\xe2\xc2xM't1^\x1b\xf4j\xd2MK\x18B\xb2\xc9\xe6\xd9\x90\xe4<\xe4\x81\x83\xd6w\\Cr(\x0elRO\xb1\xc3\x95\xbd\x19\x88\x8d\x7f\"\xb5\xda\xdf;vl\x8b\xd6n\xb9[\x88\xc65f\xb8\xc0\x8e\xa9`[Fp M7\x19E=\xf5\xda\xf9\xdc\xfe\x89A\xefv\x928\x1f\xda_xW^\xe2\xc7\xc1:\xbd\x9dy\xa9\xe7\xec\x04+u\xd4;\xe3\xcf'\xd7\x83^gr}\xf8b\xbasY-\x12\xb1:\xc7\x9f\x0f\xa7mg\xb8s\xb9RI\xdd\xd8\xeaZ.X;\xb2\xef\xb9\x19K\x12/\x0c\xd2\xe0K\xf2\x83x\xd9t\xf3@\xd8\x92\x98R5\x15\xd7~\xe8Y\xce\xd2y\xb4n\xb4\x12 k\x95\x85\xde>\x1d\xf7\xa6\x0e<\x85\x8e&'\x95\xed9\xdc\xd6\x84\x8a{\xaf\xbb\xa2\xd2\xb3\x1d9\x8e\xb0-1\x0bm\xdcMI\x922\x15\x8e\xe5]DY:\xbcXz\xe1[\x0b\x86\xe0a\xc4<\x19hB\x81M0\xa0\xc0\xe3\xdd=\xbd@\xb4\xbb\xbf\xeblc\x1e\xc6`\xf8\xdd4\xfa$zG\xe2\xe7^Bl\x0c\xd1\xda\xa6C\xa6t \x03\x96W\xe3\x9e\x1a$\xaa`\xbb!\xec\xe9\xc3:\xf4\x0f\xef\x1e\x98\x027Yy4[\xcaUE\xf7\x0e\xaa h\xf8\x04\xefU\xb98\x93\x05\xaad\x8f\x89\x02\x87U\x81\xc2\x03\xae\xfeS%\x81\x98N\xb8\x14\x93e\xc8\x05\xcarIf 8\x85\xa4+\xf2\x87\xe5\x05\xebg\x0d\xb3\x12V\xe6\x0d\x03k\xf2\xa4\x8e\xfal\x80\xaa\xc2<\x92\x93\x1b\x06<\xdfX\x1b,K-\x9a\xc9E}8\x05_\xa4\xfb\xa3\x9b\xa2\xf2\x82\xe0\xc1DS\x19\xaf\xc2\xeaa/\xc3B\x15;\x1aA\xc7\xa3\xdb\xae\xd3\xa3\xbb\xad)~\x80\x89\x9dm.!t\xfa\xdc7\x83\x07\xc1K\xb9\xa2\xb9l\xf2f\n\x90\xd89\x81v;\x84'\x10\x9f8\x10\xf0\x00\x83<\xbcv\xa8\xe6\xc6\x16s\xfa\xa0\x18\xcb9\xa5!~.Z\xed*\xc7\x11\x15\x8f\x83\x1c\xd7TdfX+\xe5\xb2\xdb\x10\x1d\xcd\x87\xac\x88\xdf\xde\xc6\xf0\xa4\xa5\x12 \xae\x86(qW\xf5\xda\x86\x94G$5\xe8m\xc4\xccUB\xd8\x95\xb4$\xef\x95.\x06h\xdbf]\xd4/`\xcc\x9d\x06NE\x07B\x18\xc2\x8c,IJ\x10R\x8ap\xd8\x8c\xa8\x02\xf5\xaa+\x99O\xfa\xb6\x13-D@1\x88\xbb\xe2\xdb\xee^\x95\xe8 \n\xaeO\x92\xb5\xbb\xaf\xcb\x92\x85\x8c\xe0\x8eC\xc8\x0bhu\x83\x04%zSx\x01:\xa5\x01c\xda\x11\xa3H:r+>\xcc]\xe5\x149>\xe5\x88hZF\xb3\xb2\xbe|\xc2\xcb\xc7v\xe8B_:\x9e\xd0w\x93e\xe0\x13\xbb&\x91\xb27N\xa76\xa5\xaaI\x193\xef\xbeR&-H\x93\xa8 0^\xefe!0)\xdfd\xdc\xd7\xe1\x14\x02J\x8dQK\xf9\xe8\x11\x84\xf0\x94\xd9\xf4R<\xd7\x88\xa6\xb6\xd8\x03\xdbv9f\xa4Z\x99_\xf3P\x98YOx\xfbt\x08<\xc5\x1eS\xda\x1e@\x1b\xbd6P\n\x0c\xf9\x03\x1c\xa0\x93\xbf\x84a\xfc\x02\x87\x91\x7f\xfar\xc8_\x0e\xa1\x83\xceXO\xa1\xe7\xb2/#\xad\xd9\xf0\x8aG\xbc`\xac#@\xd6\x11\xc3\x13\x08N\x1c\x88Xh\xb1t\x1c\xd3\x9e\xe8\xfd\x11\xa3;\xe3\xc6~u\xb76\xed\xe2A#.\x19\xe5\xb3\x94m\xb7\x94\x1dp\x1bIO3\n\x18ZJ\x0b\x15\xc4\x16M\x08\xb2`\x8d'\x93lv\xd4\xebu\xe8\xdf\xf9|>\xad\xb8\xa3\xc7\xa2Po\x97\x15\xea\xed\x1e\xcc'\x93lN\x06\xf8sN\x06\xf4\xe7\xa07\xc3\x9f\x83\x9eZ\x05\x9dd\x0b\x9b\xd9\xf5\xc7\xac\x99\x0bSs\xe8\xd85\xfe\xbc\xa1S\xe8\xc3e\x9f\x0e\xe5Jg\xe4\x00\x8b\xcf\xe6\xf3\xa9\xf3\xd5\xe0\xbd\xa52\xf0\xf2`/\xe6\xf3)\x02|sC o(\xcfk~\x9b\xe7Fw,\x16\x89A\x95Y\xb1\x999\xe9\x11\xf6g>=\x15i\xefm\xde\xe9A\xaf7\xe3\xb5\x8e\xb9G\xcd\x94\xd3\xcd[\x0bEL\xc7X\x87\xe5|XU\xff\xce\xa5^\x8e#\xd1\xd5S+\x0f\xed\xe6BX\xad\xbf\xd2\xef%\x8cx\xb6X\x1bGg\x9f\x8e\x8a\x91\xe2\xa0\xe7\xd0\x06\xdf\x05\xeb\xd2\xba\xeb\x9eH\xf9\xa9r\xe9\xb0+\xc2w\xdf\xc6\xd5s\x898\x10V\xa3\x01\x8am\xac;\xb1\xf0\xd1Z\xe3\xc7\xff\xe5\xe7~mj\xddkd\xf5\xccY\xc8JvdS.\x9c\x1f\xf13<\xe2;\x18\xb7\xc72\xdb=\x1a\xf7rC\x02U\x13\x9f\xd31\x8d\xa8F\xde\xd7Pr\x14\xff\xa2\xdc\xdf/\x1d\xb7\xdb\xc1\x14\xe9y\x00O :q\xd81\x87\n\x06\xe98\x98\xa2\xeb\x8dA\x92l:\xcf\xd4`\x83A\xcfU=s\xa3\x96g<\xb9\xf6{\x9d\xc9\xf5\xec`r=;\xeaL\xae\xe7\x07\x93\xeb9~\x99O\xb2^\x9f\x92\x82\xac\xd7?\x9cOw.kpf[zx\x1f\xe4\xb2S\x14\xdfR\xc7a\x96q\x81>\x11]\xdb\n2\xdd}\x12\x0f\x9dJ\x90\x03\xebG?g\x0d\xc1zV!\x14\xd6\x8f\xfe\x96\x1e\xfc\xb7\xf5\xe0\xbf\xa3\x07\xff\x8fz\xf0\xcf\xeb\xc1\xbfI\xc1\x9e\x02\xfe-=\xf8\xdf\xe8\xc1\xffV\x0f\xfewz\xf0\xbf\xd7\x83\xff\x1e\x05?W\xc0\xbfC\xc1\xbe\x02\xfe'\x14\\M\x91j\xfd\xe8\x0f)x\xa6\x80\x7f\x81\x82\xab D\xad\x1f\xfd}=\xf8\x17\xf5\xe0_\xd2\x83\xff\x17\n&\n\xf8\x7f\xd5\x83\x7fW\x0f\xfe==\xf8\x1fP\xf0K\x05\xfc\x0f\xf5\xe0\x7f\xa4\x07\xffc=\xf8\xf7)8P\xc0\xffA\x0f\xfe\x03=\xf8?\xea\xc1\xbfL\xc1\xaf\x14\xf0\x1fQp\xf5\n\xab\xf5\xa3\xff\x89\x82_+\xe0\xffY\x0f\xfe\xa7z\xf0?\xd3\x83\x7fE\x0f\xfeU=\xf8?Qp\xa4\x80\xff\xb3\x1e\xfc\xbf\xe9\xc1\xff\xbb\x1e\xfc\x7f\xe8\xc1\x7f\xac\x07\xff\x1a\x05\xff@\x01\xff\x0b=\xf8_\xea\xc1\xffJ\x0f\xfe\xbf(8S\xc0\xff\xb7\x1e\xfc'z\xf0\x9f\xea\xc1\xff\x9a\x82\xab d\xad\x1f\xfd\x19\x05\xdf(\xe0\xbf\xd0\x83\xff.\x05?S\xb7\xc3oS\xb8\xa7\xc2\x7f\x9d\xc2\xdf,\x14\xf8\x9fSx\xaa\xc2\x7f\x83\xc2\x93jH#\xebk=Y\xfeZO\x7f\xbf\xd6\x13\xda\xaf\x91\x88+\xe4\xed\xeb\xbf\xa3\x07\xff\xbc\x1e\x8c3\xa0\x10\xc3\xaf\x7fA\x0f\xfeE=\xf8\x1f\xe8\xc1Hh\x15\x8a\xfa\xf5\xdf\xd7\x83\x7fI\x0f\xfe\x87z0\x92 \x85,\x7f\xad\xa7\xd6_#eR\xa8\xf5\xd7\xbf\xac\x07#\x99P\xe8\xef\xd7\xffT\x0f\xfe\x15=\xf8W\xf5\xe0\x7f\xa1\x07# R\xf0\xed\xeb\x7f\xa6\x07\xffs=\xf8\xd7\xf4\xe0\x7f\xa9\x07\xe3\x9e\xfd\xab\n\xf8\xd7\xf5\xe0\xdf\xd4\x83\xff\x8d\x1e\x8c\x9b\xf3R\x01\xff\x86\x1e\xfc[z\xf0\xbf\xd5\x83\x91\xd9\xff5\x05\xfc\xdbz0\xca\x00\xca\xc6\xfc\xfaw\xf4`d\xb1\n\x07\xfb\xfaw\xf5\xe0\xdf\xd7\x83\xff@\x0f\xfeC=\x18\xd9\xb7\xc2\xd8\xbe\xfe==X\xcf4\xbf\xd6s\xc7\xaf\xffH\x0fFv\xf2\x93\n\x18\xd9\xc9\x17\n\x18\xd9\xc9_W\xc0\xff'\x05\xbfU\xc0\x7f\xac\x07#'\xf8D\x01\xff\x89\x1e\xfcgz\xf0_h\xc1\xdf\xfc-}i\xe42\xd5\x981\xd6\xd7\x7f\xaa\x07\xff\xb9\x16\xfc\xcd\xcf\xe9\xc1\x7f[\x0fF\xd2\xabH#\xdf\xfc\xbc\x1e\xfc\xf7\xf4\xe0_\xd4\x83\x91 (\"\xcd7\x7fW\x0f\xfe\x05=\xf8\x97\xf4`\xa4\xdf\x8a\x90\xf2\xcd?\xd2\x83\xff\x89\x1e\x8c\x84Z\x91/\xbe\xf9\xc7z\xf0/\xeb\xc1Hc?S\xc0\xbf\xa2\x07\xff\xaa\x1e\x8cT\xb3\x1a\x93\xc1\xfa\xe6\x9f\xeb\xc1\xbf\xa6\x07#\xa1>S\xc0\xffJ\x0f\xfeu=\xf87\xf5`\xa4\xc8\x8aT\xf0\xcd\xbf\xd6\x83\x7fC\x0f\xfe-=\x18)\xf2\x1b\x05\xfc\xef\xf4\xe0\xdf\xd6\x83\x91\xf4VC\xe4X\xdf\xfc{=\xf8w\xf4`$\xa6\x8aP\xf8\xcd\xef\xea\xc1\xbf\xaf\x07\xff\x81\x1e\xfc\x87z\xf0\x7f\xd2\x83\x91\xc6*\"\xe47\xbf\xa7\x07\xff\x07=\xf8?\xea\xc1\x7f\xa4\x07\xffg=\x18I\xef\x0f\x150\x92\xdew\n\x18I\xaf\"\xe3~\x83\xa4W\x11f\xbf\xf9c}i$\xbd?\xa3\x80\xffD\x0f\xfe3=\x18\x89\xe9\x97\n\xf8O\xf5\xe0?\xd7\x82\xbf\xc6\xd5y\xa92\x1e\x9c\xab@\xe1<\xdf\xb0\xe3\x9a\"\xb9|\x83\xc2R\xa4\xc2Q\xb0|\xac\x927\xe4\x1bI\xe1\xcab\xf2\x08a\x8ex\xdb\xab\xe9\xee\xa3Q\x945u\xdc(5\x84tL\xa6\xa5\x17\x9aT\x895J!\x83_\xc8\x81>\x1d\x89\xa2q\xcbx\xf1~\xa3\xeaKo\xde\x12zc\xbcK\x92\xf2\xe4\xdd\xdc\xf2\xc6\x9c\x92\xe4\x81\xa3}\x93\xdb]\xb2\xc2\xee\x82\x1aL\xa6x&\x9b)\x9euv\x12\xf4 \xeb\xf5:\x93\xeb\xc1|r\xbd\xebu&\xd7{\xbd\xc9\xf5\xfeEgr}\xd0\x9b\\\x1f\xd2/\x87\xf3i{\xe7\xae6j\xd1\xc9\xf0>\x9d\xf4:_N\xc7\xcf:?3\xbd\xc5\xff\xbf\x1a\xb8\xef\x11v;\xeeu\x8e\xa7\xf4+{\xc8\xbf \xf4v\xfc9\xfb\xd9\xeb\x1c\xc3t\xe7\x8e\xdd\x0f\x99g\xd8Vv\xae\xdc\x085\x99\\{\xfedr}\xd1\x9fL\xaeg\x87\x93\xc9\xf5\x9c\xfe\x87\nV:\xe1l\xc6q\xca\xd9\x9c\xe3\xa4\xb3Y\x9f\\_0\x85k\x8f+\\\x0f\xe60\x99\xa4\xf4\xf5\x8b\xc9\x84\xbe\xeb\xf5P/;\x9fO&\xe1d\x12c\xa1\xc1\x11\xfbs<\x99d\xfd\x83#Z\xa2\x7f\x84\xd6\x16Z\x11\xfb\xd3g\x7f\x06\xec\xcf.\xfb\xb3\xc7\xfe\xec\xb3?\x07\xec\xcf!\xfb\xc3\xea\xec\x1d\xb3?\x1ek\x81un\x9f\xfe\xd9\xed\xf5\xaaq\xae\x98y\xcd\x826\x0b\xecm0\x9d\xcd\xda\x96\xba\xe1P\x0b=8\xe4\xc3>\xbc\xd0[\xc9\xe8R\xd3I\x9d\xd3\x99\x9a\x1fL\x98\xb6{r\xad\xda\xba<\xad\xe9Mt\x0d-A\x95\x06\x8dU?\xeb\xfc\xcc\x84)\xdaQ\xd3\xceT\xed\x93\xeb\x191\xd9\xd7\xb60\xe4\xf9w2\xe4\xa1\x89l\xbcq\xbf\x96\x92E-\xcb\xed~\x9e\xcer\xb6\x96\x8a\xce\xeb\x8b.x\xd1-\xcd\x07\xb7&\xdb\xa9S\xb5>\xce\x8c\xd6\xc7\x85\xc1\xfa\xa8\xb5\xb5\xe2\x1d\xe8\x8d\x0c\x92\x0b\xbdA\xf2\xaad\x90\xd4\xd7G\x9f\xcd\xca\xaf\xdd\x14&\x96\xf1<\x8fs\x8f\xf3\xdf\xa6\xd3\x86\x96:\xfbt8\xbb].oW\xb71\xb9Mn\xd3\xdb+\xe28\xa7\xdc^9\x8e]\x98\xbb`}`\xa9\xf6NX+\x15}t\xfb\xc9'\xb7\x9f\xde~\xf6\xe2\xf6\xec\xf6\xcd\xedO\xbd\xa8T\x04mX\x9a*+\xfa\xb7\xdc\xa4\x7f\xe2\x8d\xa6\xe6-\x17\xf7\xfb\x87\xf6\xe9\xb0\x7f\xf6\xe6v\xf0\xea\xa3\xdb\xdd\xcf>\xba\xb5O[\xe3\xfe`w\xeaL&\xb37\x7f\xcd\xb1OG\x93\xc9\x05\x92\xf1\xf3\xa9#\xbf\x93\xa4\xb7\x83pv\xbb\x1b\xcfJ\xef\xa4\x8b\xfc\x9dg\x9d\x9fa\xef\x04.\\I\x03\xbb\x97\x8dJ0\xaf\x9b\xcd\x98\x97Y\xe48\xa8\xe6\xf4a\"\xc7a\xd5\x05\x98'@\xeb7:\xd0V;\xcc\x82l\x06_\x12vw\x9b\xe7\xc6\x9cy\xa9w\xae\xcf\x7f\xba\xf0\x92\xc5\x10o\xb6\xc5\xae\xf2p\xe5\xad\xf1\x99\x1d\xd1q\x07\x1a\x0f)\x91f\x0b+(=\xbd\xbb\\\xa6\\\xc6\x11rYU^\xe3\xf6o\xc55\x97\x0bf\x8a\xdb\x8b\xc7\xe1\x03\xed\x9d\xdd\xc4\xec\xc8\xa8\xb3%\x87\xdb\xd9\x92Y\xd6\xcc%\xf1b\x1b-\xc8\x04\x03\xb9\xe8\xa4_1\x13T\xd2U\xfd\xcaD\x18\x7f;f\x1e\xeb\xe3\xfe\xb4\xde\xb4N?\x89\x9c\x0b\x92\xf6\x81e\xed\x92\xc1\xdc\xab\x11\x13x\xca\xf0K\x82\xf2i\x19\xb8\xf0(\x12fe`\x82%\xbd\xf2\x1d\x8f-/u\x1c6\xca\xd2Z\x84\x970\xb5\x9d\xf1d\xfa\xd5\xfb\xdb\xe9\xce%\xd2\xf1\x0f\x1eYR\xb1r3\xb7\xf9}\x07\xa7\xfb\xe1)R\xf4\x89\xed\xdc\xe2\x06\xea\xb69`\xea`M\x1f\xf4\xbb\x1f\x9e2~\xf5\xc1\x9d\xe9z\xcbn\xa1\x0b\x1b%n\xc2\x03\x01o\x1e`\x18\x8d!x\x0e\x13\xfb\xb3\xd2\x8d\x9f\xcdQ'\xcf\xe5\xa6$\xbe\xccs\xb9\xed\x8c?\xefN\xdb\x1f\xect\xc95\xf1m\x8cR\x16\xe0m\xa8\xe2[\xf7\xe5\x8b\xf3\xef\x7f\xf6\xfa\xcdk\xbc\x87j\xe1\xa5\x15\x8b\xdf\xf6Kb\xdf9\xefw\x99\x03W\xd9\x15\x7f\xbb\x99hE\xcc\xd9%\x08\xb7M\xfa)\xed^gl\x9d\x9f\xfbQL:_$\xe7\xc9\xc2\x8b\xc9\xec\xfc\xdct\xa7\xe8\xae*\x05\x8dc\xff\xc6\n\x83\xe6C\xdbf\xb3&\x18\x03\xd2\x96\x85\x87\xac\xe3\xd1\xa3\xdc5\\\xa6I\xe3T\xef\xe6Y\x90\xa5\x0e\x0b\x1e\xc6c\xc6\x90;\xcf\xbe\xce\xfb\xd3:?_F3/Y\x9cSF\x7f\x9e\xc7\x94;?\xd7\x1c\xb9\x14\xbf\xf4\xf2\xf6\xdc\x16\xb5J\x93$\xa6\xa3<\x17\xc1\x1cl\xc5\x83\x0b\xa4\xb33Q\xa6\x0fJ\xde\xca<\xc4P\xbe\xdau\x99\xf4\x85\x7f-\xbf\xba\x82\xd7]N\xd9\x8dU\xe12\xfe\xa0s\xff\xe3\x9f\xce\xfc\xda\xc2i\xf9\n;\x8e0\x90\xc6\xfd\xa0\xe3\xac\xc1\xb1\xa61j\xf6\xb2X\xf9\xe6a\x16;\xa8]\xde\x89L\x18\xeb\xbb\x10\xb2\xdb\xc8\xe8\xc7')\xd7\x08\xf7\xfa&L8\xb8/uh\x12I\xc6\xd3\x07\x12B\xb42\x08\x0b\xd5\"\x89a\xebe\xe0\x93\xa6\x89\xdf\x08\xb9\xf4Bo\xccPH\xbb$-;\x14\xc1\xb6l\xba;\x8b\x04i\x1d\x8c\x1aE\xba\xebh\x8d\xa9\xda\x0bl\xc4k\x15.t:\xf9\x1c\xb9\xd0\xbb\x13\xbb\x15\x93\xf4\x974\xf8\x90\xc7\x13+T\xb6\xe3p:\xee7q\x9f\x87\x1cI\xee\x8b[\x1e\n\xa5t\xa5\x9b\xb1\x0f\xdf\x93Mw\xb2:\xad\x18q\xca\xae\xb9E\xc7\xa7\xd5n\xb7%\x0c\xe1at\xc6\xb4\xe1)^\xb3\x0f\xc7\x01\x9dm\x96\xe0~\x83}m\x1e\xed~\xe3hM\x18\x14\x8bT\xa5\x0e?P\x99n\x96\xdd\x95\xfb7\x12#3r\xb3\x1b\xa1\xa9\xb6;\xf2\xd5Q\x8clb\xb1\xac\xdb\x12\x80e\xcd\x96\x00\x17Q\xb4$^\xc8!\xa7\x94\x0d\xf0T\xae\x16\xb2\x9d\x94\xae \x93\xc8F\xf7\x90)\xb7_\x8c\xd2&\xc0\xb5\xb8$\x1b\xa8\xee\xbf\xdd.0\xd6\xf4-v\xa1f\x03\x16\xdd\xd0\xef\xbe\x101QO\xd3P\xd7\x80\x95\xbbe\x86\x1brv6\xcaoW\xf5\xef\xb7\xedv\x8f\xf6\x1c;\xb4\xf7v\x0f\x9c\xad\x8c\x90\xe63{_\x7f\x1f\xeaPw\x18\x0b\xed\xc3\x83\xc696,s^\x80q\xb3\xcc$\xd0zE\xe0!\xdd]F*\x0c\xb7\x02\xbci\xad\xbe/\xeaH\x04\xb5\xdc\xd5\xd4\x00\xfc\xaed\x84\xe1*\xc3\xda\xbe\xcb\x1f>\x8e\xc4\xf6\xc6\xe9\x14/lx\x86l\x17\nT\x85\xd0^\xfa\x94\xe0\xe4\xd3a\x14\xe0}\xe4Jp\n\xde8AQ\xdc\xa7\x82\xaa\xaf\x91\xc7\x01\xee\xa3Q<2\xdc\xa1P\xe2\xf8p\xbd\xeb\xd1\xde\xd6\xa8 \xc8l`\xa2\xf8\xfd\x928\xf4\xe8\x11\xa6*\x18\x0f\xa6\xec\xd6*\xfd\xde\x9b\xba\x0c\xd8\x9fR~\x96\xb7\xa5\x18\x8e\xa1z\x04J)Af<\xd4Ub<\xdcu\xd6\xfa\x87\xd5\xfbF\xe2:\xa1N\xe5\xd5W\xd5]\x83\xa69\x14wx<\xddd&H\x98\xf8]|e\xf8\x18\xba+`i3b=\xe5\xa3\x0d{\x0e\x96\xbc\xc1(M\x0b\x17f.\xac\xd9\xaep\xe1\xca@1\x91\xee\xca]\xbeAO\x8b\x99\x0b\x0b\x17\"\xb8\xe5w\x0c\xaf\xe8\xa6\xbc\xa9\x1fA\xcd\n\x8a\xb7\xee~\xfak\xbc\xad[]\x91\xeaA\x94Yy\xb6:\x8b\xdeC\xdel>L\x91\x8d\x85dZ\x96\xcb\xfd\x0f\xdea\xb91\xd1\xdf\xcd$\xc6\x07j\xeb\x9e\xa2\xa1>|P\xbf\xaf\xf7b\xea\xf7\xaaV4$\xd5\xbd\xc6 \x1f\x9b\x1e\xf04\xc4\x17D\xf4\xcbh\xae\xde\xd7\x04I8\n\x0d\xb5@.\x1dQF\xe7 &\xfa\x042\x16C\x9aO\xabW:\x13\x96\x11\xbd\xdd\x0e9\x06Q\xa8Z\xbd2\x0e\x10)z<\x13?\x85F1YH\xc9\xf7\x13\x8c\xcd\x8cX/\xc8\xee\x1e\xeb=\xd5\xf6zz\x83\xe8^\xbf\x8a\x12\xc8{\x95@H>\x17\x8e\xaa\x885\xe7\xf0*\".U\xb1\x00\xbdI\x84\xad\xeb\x99\x08\xa2WuOY\x94K\xc5\xdeM\xb5\xc4L.\xc18v\xb5\xc8\xd5\xfd5\xb0B>\xb9q\xe1\xd2\x85\x95\x0e\xfd)\x9a$\xdalT\x17\xf8\x84h\x9e\xbc\x83\x11\x9c\xc3),`\x08\x9e\xf6\xddk\x18\xc1E^BW\xc7\x19e\xf4\xb4\xa2wT\xacY\xc3)\xcc`\x08\xef\x1c\xfak\xa6\x16\x7fA\x8b\xd3Z\xaf\xe5\xe2\xd7\xa6\xe2\xcfD\xc5\xd7\xean~F\xf9\xb9\x8f\xd62u#\xe3&\xf5\xe5`Q\xad\xbe\xba\xd7\xcey\\\xe23\x0c\xd5\\\xb3\xbb\xf2\xf6Zgy\x85+T.\xae\x04;s\\8\xa7\x909S\xfc\x06\x9aU\x1bB\xc4\xa1\xefJ\x0f\xd4\xb1\xb5\xec\x10\x1ea\x90|=\x8dz\x0d#8Cer\x1e\xd9\xc8:?g\x89\x0eg\xe7\xe7\xa6\x0c\xd3_\xc0\x08^H\xaf\x91\xeakzj\x87\xf6\xbe/\xea\x0e\x83o)\x8e\xc3)\xa4,\x984*Vk2H\xbe\x84\x11|\x81Z\xd8\xa28\xd1\xcbD\xc6\xc9\xbe\xb4\xdf\xba\xf0R\xcc\xe3J=&n\"\x03\xb5pQm\xb5\xf6L]\xbe;3F\x95\xd3qc\xec\xb1\xfe\xd4\xb7{\xbc\xaf\xf5\x0b\xc9\xbe}\xbf\x90\xaa\x8c&;\x88`\x01o6\xb3\xd31\x99V'\x83~2\x89\xbey\xb3\x19\x06\xb5* \x94#2\xaf\x8eLq\xe0\x88\xca\xbe\x1a\x99v~\xab\x93\x1b\xde\xcf\xe2\xb3\x91D\xc4\x99i\xe8l\xc48\x7f\x9cbXs[f\xf3t\x8aM\x90\xa6&\x8c\x08m\x8acx\xac\x8fi\xac\xb8\x9ad\x06\xa9\x81\xbbE\x1d\xeb\xa5\x80\xbd^\x95\xdf\xfb*_\xa7\"\xc0@\xe5\xfe9\x8b\xfe\x1e\xd3\x15WytI\x1c\xf8\xc8K\x15G\xd5\x92$\x80a\xd7k%\x81O\xbd\xb5N\x0c\xc8\x9f\xbfB\xa5v\xb5\xc8\x8d\\\x849\xb6T\x8b\\\xcaE\xce\x88\"l\xacJ\xcfQ\x97^-r^*\x82\xca\xf4j\x91\x0bE\xee\xf9^6\x9f\xab\x1d~W\x996\xef\xa7\x02\xf2\xaeZ\xe8z\xe3@\x94g(\x17\x9c\xc25c\x0b\xaf\xe7\x1b\x07\xfe\x13\xb4:v\xe1\xda\x85\x17.<\xab\xa2~\xf2.\xc0\x08|Z\x1d\x96\xef%\x04\xde\x0d\x158p\x06\x98\xcayA[\xa3r\x9e\xd0\xdb[`\xcf_\xcf\xe7 I\x8b\xe7\xecw\xad\x00B?)\x06\x10\xbb\xc0 vy\xf4T\xf6K-\x8f\x1d\xbd\xd0w4\xb7|6\xf5\xb6\xf5\xc2\xa6\xc4=\xc0\xab\x1e\xec\x1bqtY\xbf\xb1\xb5\xa5\xda\x1a\xc2\xd7\x06\xf8Um\xef\"\xbb\x9d\xba\xd0\xd6i\x9d\xf1\xedE\xed\xdbi7\xf4V\x84\xe9/\xf1\x1b\x06jY\x91$\xf1.9\x98\xff0T\x7fc\xe8\xf4\xaa\xbeYfYR\x83\x88\xe6\xef\xcf\xf4\xef\x0bQ\xcd3\xbcvi~\xed\x0b\xe6.P\xcd\x1d&>\xb9Xf\xd3\xfa\x13\x0ch\x8d'\xbd\x96\xd0P\xa0\xb4\xfaE#\xf6 \xe9\xed\x19\xd74\x98\x9b{\x9b\xd7\xf5\x16\xe7\xc3 \xaf\xc1\xed\x08\xe6.<+\x0e\xa2\xe6\x86_b8\xc5\xd7\x88\x88\xaf\xd1T m\xe0Zy\xf0Y\xa1\xb1q\xe1\xa5az\xcf\xcd;\xba\x10\xe3\xcfD\xccJ:\xa83\x11M\xb6\xf4\xa2^v\xbc\xbb\x11\xdb\xe9\x16 3\xf5\x94\xed\xae.i\xdb\xca\x87<\xad\x0e\"\x8cA\xf5\xa5\x89\xb7\xaf v\x85\x15\x8e\xdbm2\x85\x11:\xf5\xa7\x95\xcbq\xce\xb7\xa11\xfbv\x86W;65\xa1@\xd3\xb0\x8cx\xb0\xd7\xd3i\xcc\xfa\xaa\x08\xf5@\xda\x03\x9ewO7\x89\xa8Q\x81G\x10\xa8\xf38gv[\xcd\x89\x123\xef\x19S\xa5.1m\x82M\x1c\xc9\xd2\xd4\xf2\x8d\xf4\xa8Hm\x00#X\x9e\xc0\xba\xc6\xe4\x81\xb9\xb9\xc7k\x83]\xa0e\xfb\xa8\xb1\xc0\xdc(C\xc9\xcbn\xe1lh\xe3\xa0m\xcc\xd03YG\x13i\x1b3\x96[\x88>\x96T\x0c3\x0d]\x14\xe6\x82V%Bg\"+\xea\xd8\x0f\x8dCO>+T4\xf4\xe9il\x0dO`i\x9c\x99K\xb4\xa7\x88\xf91\x98UV\xe8\xce\xb80L_\xe6\xe4\xfa$\x1fox\xae\xf0\xfc\xbb@,J\x11\x7f\x86\x90\xd9\xf4H\x8cP\x86^\x89\xc9\x8c,\x9b3\xce\xe1\x94\xf6p4b\xc7y\x8fW\xc2P\x13\xeb=7\x9b\x9cQE\xa3\xe7 \x171\xf1\xde*OT\x83\xf0\x0d2L\x94\xb2\xfd\xc2\xb7\x1d\xfdF\x16u\x14\x1f\x0dI\x88\xbf7\xa6\x89\xbf@!N\xaaU?\xf5\xefP\xba\x93\x8a\xa9\x03\xba\xa0\xfb\xe6\x1dm\xad\xdc\xc9\x80\xa7lS\xa0\x8c\xd3\xdb\x96\xd8\xf0r\xd8\xf5\x0b\xfa\xecBV{#D[\x16\xdb|'\x97}\xc7\xfc\xd0\xd9\xd4o\xc0\x12\x13\x99)\xe7?(\x82o\x99\x88P\xa6\x91\xfa\xeb\x0e{=}\x0c\xca\xbb\xfbN`\x10\xe1\xc8\x85\xe0\xce\xc7\xe2\xbd\x9e\xfe\xbe\xd0Qc\x97\xd4ZE\xcd\x11\x8b\xefnpHc\xaa\xc6\x08o`G.\x84\x1b\xdc\x0ehf\xb2\x1a\xbd\x816^=)\xc5\xa7\xcf5KR|\xfat\x1c@\x1bX\x8c\xfaqh\xf0>\xbf\xfbl\x9b\xf2\xae\xe8\x8c\x11\n\x0b]s\xe6\xf92y\x11f+\x96\xb0K\xd5R\xf0\xd7.I*\xf1[vfNT\xddEV\xca\x0c\xa4#\x15\xc2J#\xa9\xe5\xc6S\x18V\x0c\xfe.\xc46\xcb\x1b\x94\xd7\xa6\x0dO \xd5XD\xb8'\x1aMh5K\x0c\x0c!\xd0\xe3\xa4\xf7-#M}\x92\x83\x9e\xc8\xe9/c\x91\x9e\xe0f,\x0f\xbf\x86\x89a\x8cN\xf4\xe2D\xea\x15\x8d\x83v\x1b\x13\xc4o@\xc1\x9aB^7N\x84\x81\xb8\xdc\xfd\xa6\xe6\x9eAy\xdc?\xd4_B\xd4'\x0dQme<\x81X\xbf*\x82&\x06\x1b\x9a\xee.\xd7\xf6r\xa8\x8e\xc4\x85\"\xec\x84\xb2\x92\xe8D\x83\xa99\x02\xa3\x00\xca\x9e\xb7\xd0\x19$\xd3\x96ZWJ\xb5\x96(\xbci\xcb.P\x0e\xbe\xbd\x859\xfdoI\xff[\xab\xa5f\x98\xb3\xfc\x94\xb2\x8c\x1c}\x99\xae\x8d\xca0\xba\x9c\xa1r\xce-\xa3\x84\x87~)<\xbe}\xcb\xcf74\xbb\xeb\x8b\xf2\xb3m\xb1*\x90m\xdf\xb0.\"8BUS\x01\xb6\xd6^LB\x0e\xc0\xf7\xd7\xac S,I\x05\x0b\xd5P\x05\xf8Z\xaa\xd2a\xe2\xda\x8d\x0bW\x0e~\x9f1\x03\xf7\x8d\x9e/\xcd\xee\xbb\x8b6&'\"-\xac\xa0\x17\xe9\x89\x03\xb1\xc8\x8a\x12\xea{\x17\xdfy+\xeasS\xec\xe96\xa2\xce\xb6\xdc\xb4?\x0c\xb4#\xe0w\xbab\xae\xa3\xf8\xb6h\xd4\xdd\x15\x1a\xa6\xa4\x1d\xfd\xaa\xec\x16\xe9',\xc3d\x82\xc5\xf4d\xe3|\xfa>^F^\xba;\xe0\xb6w$\xe3\x95\x87\x07{\xfa\x87/\x85\x86E\xf7\xa4\x7f`|dj\xacP\xd9\xe8\x1f=_z\xab5\x99\x99K\x98\xda\xa4\xcfJ\x8db\xa6\xdc\xb1\x0e\x83*o\xea\xeb+\xe9\xeb+\xcfr\xf3G\x05^\xe8\xee\xd5\x07D\x01r\xfbGu58\xae(\x0f\xd0\x18R\x81 \x03H\x05,<(*`a\x0b\xa9\x80\xd1\xfeQ\x85q\x9bG\x05\xfcC\xe2\xbd\xcd\xfb\xd1\xea\xbb\xdbm\xc1\x88o\xc1 '\xf8\xf8\xb3\xd5\xca\xc6tW61\xf7\xc6\x1d\xd9\xec\xcf]#L\xa6fu\xe5F\xfb\xb8F\xf3Ul\xf1\xbeb\xf3\x03\xbe\xcf-6\xc3\xa5d_tr\x18\x1b#\xdd0\x9a\x9177k\x06S\xab\xc0tQx&U\xeba)\xca\xb1\x9e\xb4T\x8f\xc6\xb5\x80\xd2\x10vs\xb8\x98\xe0\x11\xaf\x1a-O>I4~\xba^\x1da\x14\x9f\xfa\xc4\xd3W\xb6+\\Q\x95\xfe\xb1\x98S\\\x8b\xb3\xfbG}'?Zn\xce\x15\xfa\x86\x03Z\x7f\xa3\x03\xdav\xb2eu\xe9P\xf7\x14\xcb \xe3U\x7fx\xa1=\x1eO\x0d\"YHE\xb2\"\x85\xbct\xc8\nq\xff\x97U1-\x9eF\x8e\xb9:\x98\xa4\x8fm\xeeU]\x19\xd2tm;\x19b\xa0<\xe5\xbfQ\xfd$\x99\xbbF\xa0W(\x11>\xc2\xdc\x92{{\xdb\x9cv\xa9\x06E\x8eD\x8e~\x0c0\xe0\xf2\xa1nu\xed\xa6\x99\xba\x9a=!\xf22uW\x1bR\x9b\xca\x92\xf7\xa2\xb1\xd2\x90\x07\x86\x84\xd0\x067\xd9\xbdA\xd5W\x92\xfbP\x0e\xaa'4\xeeC9\xa8\n]\x89^F\xe3N\x94\x8as\x06=t\xf9v\\\x81b0\x0e\xbb\x1axg\x8d\xd0\xa8\x02] 4\xab@g\x08\xad\xe6\xdf\xa3\x07#\x89 \xb2L'\x1a\xb1\x84\xee\xae+4[\xc7\xf8\xbf$\xe4\xd8}\x87\x1dJ\x82\xd2\xbb\xc8\xed\x8b\xd7\x02,\x12\x95\x8a|?\x8eVABD1J\xae\x93hyElV_V*\x8c\xc2FQ_\xc6\xceD\xa5\"\xb9\x90Q\x14\xf3\x9cB\x87\xda\xbcA\xf5\x87\xd2P\xe7c*.;\x96\xb6sM\xc69\xc4>8\x05\x9f\xa2\xba\x9a*\x93\xc7?\x10^\x12Z\xfb\x1e\xdaT\xe7\xb5\x96r\xcd\xca\xa9\xdc\xce\xe4V\xa0\xab\x07\xa7\xd3P\x85\xc6\x03AWE\xbe\xca\x86j\xea]\x0e\xca\xebo\xa8\xc2`\xfe\xafV\x91\xe3\x87\x81\x94\x80\x96MT\x92U_mGovw\x1d;\xb4\x0f\x1d\x17,\xb1&\xa6(5[\xdej\x94j\xe6S\xfc\xf0\x15\x9f\x91\xf4\xe1+\xe5\xcb\xf0@\x15\xf7\x8f\x0c\xa1\xd4\xb6\xb7D\xe4\x82\x87\xb8\xbf\xe7\xf2\xdb)B\xb5\x1e\xd6\x18E#\xaeeW\xb7>p\xa6\x91\x8e#\x9d\xba\x94\xa9Kx~\xb4\xd8\xce\x1cSX[\xd8\\\x8a\xa9\xb9B`\xba\x01\xa9\x0f_\xb57\xd0)\x0b(\xbb\xd4\xc5\xaf\xd2\xad\x86PhV\xcb3\xfewXe\x8bs\xd5\x04\xbf\xdc\xf0\n\xa1A\xc6\xc8\xf8\xe1\xd1c\x99A\x13\xdb\xc7\x95%\xcdW+\x85\x9e;\xd0\x05%\x90Z\x90L\xac\xec\xd4\x90\x07\x17\x89\xd8\x9bh \"\xb8\xc0s\xb8\x85\xe5\x03\xc92\xfd\xa3\x8dn\x83\x1bL[\xb8\xf0\xba@I,\x9d\xa7^|\x96\x86\x1a\xc0)\xa6\xc1mJ|k\xe8\xfe\xce\xf8\xf3\xeex2\x9d\xb6o'c\xfbthwN'\xb3\xb6}:\x9ct'\xb3\xb6s\xea\xdc\xdac\xeb\xf1\xd4\xb1\xe9\xb3\xd3\xd6d\xe0\x8c?\x9fL\xa6\xb7\x93I\xd7\xf9\xf0\xd4\x99\x0c\x9c\xc9\xf4\xd6>\x1d\xe1\x1b\xb7\x93\xf1d\xea\x14_o?p\x9cj^3:\xdc\x9d\xc9\xc4\x9eL\x9c\xd3\xea3\x81\xebGN\x83\x1b\x8a\xe9\xc8\x02\xc5\x0c\xed\x1d\xb0\x9b\xb8\x98N\xf6y4#\x98RV:\x98X\x16r\x14\x11\xfa,.O\x17s\xa2\x8cLGa^GLq\xab\x94C\xff\x83>f\xa2E\xe5y\xaa3A\xc9!%\x18D\x8f:\xd16\x8bH \x8a\xce\x89f\xbf\xf9\x1a\x99I\x06C\xec\xab_\x05\x90,y\"\xf8\x00W5\x84\"\xb4\xa2[\xf1\x14\x026 \n\x8c\x11x\xdf\xf3\x17\xfa\xb8\x07w\xa6\xb4{\xbb\xfa\x83\xc6\xdench\xc3\x1ab\x86\x1b\xb6\xc5\x8f\x92\xe2\x8eK\xdct\x00\xbc\xcf\x11\xad\xd4\")\x9d\xc8\xef:5}\xc35\xfc-mj\x8a\xedL\xd8\xd4\xf4,\xe8\xf0\xae~\x00\xb9X\xe0s\xcb\x07\xe5Q6)\x82\x009\xb9\x15j\xc9\xbcd\xa0\xdd\xf6\xe1 \xcck\xafg'6\x19\xfbS\xa3\xdf\xceR\x90g1\xf7\xd8\xbf5=k\xa1\xbf\x8d\xfa^\xca/s\x97\x1eh\xc5\x074\xac\xd1>\xb6F0\x87SX\xc2\x10Z-{\x0ef\x031g\xa1s\xfc\x9b\xd9k\x17\xe6\xdc\xbekKq\x13\xef\x8d\x87\x06$\xbc\xbb\x97\xc2\xae\xde'doW\xef\xbf\xa2\xca5\xd9\xa6\xc8c\xe8z\xc4\x9cD\x98G\x01\x06\xbcj\xde9w\x9e\xa7\xbc@\x9d\xc2Z,1)\x87\xa8\xaaz\x8c\xdeu\xca7\x91J\xee\xd3\xfd\xb8\x12\xb9\x0e\xee\xd3\xd9\xbd\xdd\xaa2T\xa8\x83\xf4\xa9\xb2\xf7vu\xc4\xe8S/]tW\xdeu\xd3\xb0\xcd\xc2\x98W\xb3\xf5TMA\xcb\xcb\xd5\xaa\x9d\x8aO\xde\x95\x88\x98\xc1+\x13I\xcb#\x93B4\xc9\x13\x9e'\xe8\x0d\xeeA\x1b\x12\x0c\xbc\xe62^\x1c\xd0\xf9\xdeu\\H\xee\x8f\xb6\xc2\x15V\xd1o\xe44V\xf6eb\xde(!\xb4\x01\x05\x9e>\x0c\xa1\xd3wN\xf06K\xd4\xe9\xc0\x10\xda\xed\x88%TW\x90\x85N\x13\xb1\xe9\x91\x0b\xbd\xca$Et\xa4\x9d\x86\xbb\xc7D\xdb\xdbm\xce\xc4_#\xec\x98d\x12\xf8 \xe8\xeb%\x12\xb1w\xe9\xd2\x12\xe8\xa0\x10N`\xd8\x18\xc2\xc1<\x82=\x9d\xa8\xd2\x87\x9d\xaa\"\x0b\xe3\xbbt\x0f\x8f\x0f\x0f\x8ew\xfb\xbb{G\x07\x83\xdd\xfe\xfe!\xd9\xed\x1dm;\x01\xb9\xaa\xfb\x94\xf9^1S\x01\x13\xe3\xa8\x04\x8b_;\x01{\xcc\xc2\xbeu\xe8\xfa\xf7\x1d\xf8\x10\x1d\xeeR\xb1SR:r\xfc7\x92!w\x9d\x0b%^3\xd7&\xe8\xb4\xc3\xaf\xbcW*-\xd8\xf9|\x92\xb4o'I\xfb\x83\xea)\x83Ex\x1ew\xda\xd3\xde\xf5\xb8\xd79\xf6:\xf3i\xfb\x83\x9d@\x15Vv>\xef]\x8c{}\xcdS\x9f=\x8d\xc6\xbd\xce\xa1\xe61\xe5\xe0k/N\xc8\xcb0\xddvI\xe8\x8e\x91\xa3\xbd #`\xbeqR\x95\x10\x05\xb6yc\xa1J\xd3p=\\\xe0\xbf\xd6\xc6\x91\xe6\xd7\xcfN\x8b\xef\xecJ\xb3^\xe8\x89\xd9\xc9\x9e\xdd\x10\xa2\x9b\xa1T\xea\xbd:J\x11\xe4\xae\xa5\x19e\x19\x8f\xda\x95&\xd9e\xb1r2j\x95\x00\x87,\xac6K\x14\xa3\xdd\xc4xN\xf3E\x118\x85\xb9\x9dv\x93e\xe0\x13{\x80j\xa7S\x18\xc0\x10\x8e\xe8\xa8=\xa9X\x84}\xba+r\xf7\x15uK\x03\xb7\xdb\xab\x8a\xd8\x99V \xe7\xa6\x8f\xbdf!\xc9\xcc\x01\x19\xf7a\xb2\x12\xe5W\x86iC)4\xaf\x86\xb2-\x8aGL\x8c\xa1VE\xf1\xfcc\xd3\x172.\xdaf\xf0\x04\"\xe6\xe8\xd4\xc7\xb8q\x81\xed\x8d\xb3)\xbbH\xe6\x9c\x98\xf5\xd1\xa6\xd8\xe7\xdb\xae\x84\x9eN\x18\x82\x0d\xa9\xea\x98L\x08T\x1b\xac\xa7\x86)\xe0\nd\xf2\nT\xef\x1f\x89\x83\x93\xf0\x8d\xd0\xd2\xdeV\xab$\xd5x\x18\x1b\x86\xb1\x8e\x08\xf7e\xae\xe0\x18\x96\xa2\xdfz\xb9\xbe+\xe4\xee\x9f\xe1\x98L\xb7\x8f\x99ne \xc1\xec8~*\x99/\xb9\xd3\x05\x0b\x97!\x9clx<\x18\x92|\x1a\xcd\xb2%\xb1\\\x85\xc1,32,E\x8es\\\xbcs\xbd\x8a\x82/\xc9\xec\xcc[\xad\x97\xe4\xe38Z\x9d\xf9\x0b\xb2\xf2`$=|\x1e\x13/%\x7f\xe3\xd3O^\\c1\x16J\x0d\xbf\xfe\x8d\xd5\xb2\xf2R\x10\xceI,\xfdN\xd4\x9a\xb9\xa1\x1bH\xd7Wk^\x9eh\xf0\xa9\xaf\xa4H \x90\xe7\x87\xf6\xde>=n*H\x85\x8f\x0ev\x9dM\xa3\xb1\xc8|\"\xed\x16\x13\xc9e9\x95\x1a\xcc\xc8\xdc\xcb\x96\xe9\xb0z\xab\xf4;\xea7\x81kj%\"\xf3Q\x8e\x04&\xaa\xcc\xbb'\x90L)\xf3^= \xb2\xa2\xe7d\xe5\x05\xcb-Z\xc8\x12\x12\x7f\x97\xb0\xd5\xe8\xfa\xd1j\xa3\xb6x\xbf\xceg^J:i\xb0\"\xd6\xe6-\xa2\xaf\xc5G^J\x9cn\x1a\xbd<{\xcd\xbc@m\x8d\x1dBs\xda\xc5\xcd\xb9y[\xbd\xcd+=\x9f/#/}\xe0\xaa\x830%\x97\x0f\xdea\x1eD{X#T\x88\x8fX\xe5<\xee\xb6t\x8c\xe9r\x94fQ1\xf8\x0f\xb5\xfd2\xba\xab\x07\xd0\xfaN\\\xe5\xfel#\xb0{.\xc4]\xe6`\x11\xcco\x1c\xadB\x03rC\x8b\x9a\x82H|\x02|>\x8f\xe2\x95g\x88\\EI\x827\xc6\xfc\x91\xe7\x16\xb4!\x98\xa2\x0b\x90\xf6\x12\x92\xc0K\xec]\x90|\x9c\x85\xbecGx\x82\xb2\xd1\x1ek\xfd |\x1bF\xefBxs\xb3&C\xa0\xf5\xa5\xd8\xbb\xba\xa9\xf1M\xc40\xa7J\xa9^u)\x0e\x85\x9e\xf0%\x17\x97\xb2\x9fB\x1f\x8a\x9c\x14\x94\xc9\xe7E\xc6\xfd)\x15\xde\xe4\x9f\x98\xc7\xca8{\xcaR\xe8\xe2\xc5\x81\xf0\xf9\xadY\n\xb4yw9\xfd\xd0\x17\xf1\xb0\x08\xbf\xc4\x17\x10\x8dg/\xf0\xf9\n\xba\xdel\x16\xd0\xc9\xf1\x96\xdfo(?\xc7\xf2AJV\x86\x02h\x14\xe9\x06\xa1\xbf\xccf\xe43\xe2\xcd^\x87\xcb\x1b}\xd1\xb5\\\xf4\x87q\x90\x12ZV/\xe8I\xd3\x9f9e\xdc\x99\x11\xb2^\xdePz\xb6\xfe\xeb\xe4\xc6\xc1#\xff\x07\x1f\xc4dnma\xa5\x94\xe5\x8a\x92ou7\x08g\xe4\xfa\xf5\xdc\xb6\xfe\x8aU\xc9\xcc >\xefM\x16\xa2H\xef\x7f\x1c\xb0\xe0\xb7\x91\xe4\x1a\xae\x176kb\xec\x82hc.f\xc3 \xaf\x8a\xdb6^\x1c{7*\x97\x01\xedy\x01U0\x85\xb7\xf9\xc8l\xed\xbe\xe2\xc1\x06\x14\xcc\xae\xba1\xca\x9fY\xe56\x8b\xfc\xc9E\xf5+*\xd8-\x1cX\x8c\xaf\xa6t%\xe8\xdf\xee\x8c\xacc\xe2{)\x99\xe1\x8d/\xf9Q\xccq\x0d\xd8\x05\xb6\xea\xe3w\x02\xbf\xf0\xf9\x1a\xef\xb9\xcfh\x81\x11\xa46-A\x85B\x83\xd0\x8f\x13\xcd\xb4N\xbe\x03\xb3\xcav\xe9\xd7\x8c\x06W\x90\xbe\xee\xebQ\x01\xaa\x11\x0c\x94y\xf4\x1d\x97\xc5,\xb0o\\\x8c\xb2\xb6\x82\x11\xf4O`\x05O`\xef\x04V\xed\xb6\x03\xb3\xb1U\xee\x12\xa5\x95+:\xb4K}\xb78\xd2\xcfTT6\x91i\x8e?\x0c\x19\xe0\x94\xa7\xb2 \x12v\xbdl\xde\xf5\xc2\x9b\xd7s\xd4\x92\xb1\xaf\xdd\x95\xb7.<5\x9a\xee\xe6\xb2\xf8\xf3:\x9f\x08\x18*ME!\x11M\xe1\xd7\x07lj\x9c\xdas\xfa\x94\xd2q\xd2%a\xb6\xc2\x10\x8c\x82c\xcb\xdf\x87|\xa9B\xca\x0e\x97\xc1\x97\x04\xbb\xe7\xd8\xec5g\xdc\xa3uX\xf3`IX\x8a\x8d\x08\x1d\x9b\xd0\xa5I\x17/_U\x12\xdbU\x19\xbf\x9e\x96\x89\xe1u\x13V\xfe\xd1#\xa6\xb6\x17\x00\xf4h)\xb8\x01{\x8e\x1cF\"C\x8aO\xc6{\xd7x\x04\xd9\x88\xa1\xb2K\xcb\xdf\x1aO\x8d\xb6\xe1\xa9x\xff\xa5\x86\xa7z\xf8|\x13\x86\x19m\xc90\xa3&\x86\x19\xd5\xb3\xf25c\xba\x9b\xf0\xd4\x85\\4\xe7\xa9\xfa\xb23l\x99#\xb4\xbe\xc8\x15\xd26\xfd\xb3\x9b\x9ag\x97(\x86]\xaf\x96\xfa\xc7\x94\x86]b|2\xfd\xf3s|\xbe\x8e\xc9<\xb8\xd6\x97\xb8\xc8kH\xd6\x9eo\xa8\xe6\x1d\x9b\xda0[\xe9\x9f_\xe7\x87d\x03\x03\xcfj\x188\x9a\x07\x1c\x96\xda\xfc\xc7\xc1\xc5\xb3&.\x8e\xd1Y1l\x8c\x15F\xa9wI'\xc7b\xfe\xb1\xf69\x9c\xc29\x15\xcb\x87\x16\xba\xb6;\x94A\xb8p\xc1\xf4\xf37c\xfa\xdc\xba^-\xc3\x043e\x9f\xd3B\xf8\x13o\x03^\x18\x04\x1c\x99)\xa0[\xe5\xdcD|i\xe99\xc5\x07J8\xf0\xef\xed-\\\xd2\xff\xbez\xef2\x08\x0f\\'\xff\xa0e\x18\x96\xc0e\x97\xc7\xe0\xcd\x85\xbf+\xee\x95;u+\x1cbIy\xc3R\x8dZe\xe4\x0c\xf43\x17;\x90\xe5\xa4\xa2\x953?>\xe4\x08U\xfd\xbe\xf8h\xf8\xd3\x8c\xb6>\xdb\xbau\xc1V\xb6n]L\x03/9u\x01%\x9c\xa2\ns\xab\xe7^\x9a\xc6C\xb81T\xee\xc2\x95\x1e\x1b)e?3\xb8XB\xc1\x8a4\xabb\xdfsY\xce6\x9a\x15\x17\xce\x0c\xebb\xdfsa\xb6j\x9f\x97R\nm nk\xd3\x12\x01\x9f\xfa\x17zq\xbbA\x9c~F\xc5ii\xcf\xd0\x9d\xb8\x14\x1b\xf0\x85Y:\xa5}{Q\xb9jh?ct\xa3\xf5b\xfcL\x12\xbcooa-?(Dn*\x8c\x1b\xa6\xab\xd4\x0e}\x8b\x11\x89\xfc\xab\xe8!\xff\xdd\xa58\x1b\\di\xed\xb2\x89\xcf\x15\x8f.YF\x05\xac\x0b\xa54\xda\xd9\xfc\x971\x05K\xf5\xf3\x85\xe8_-\xd3\xae~\xde\x8a\xb78F\x99)\xbd\xf8\xdc\x8c\xf3Q\x0br\xf8l\x9a\xb3,\x14\x9b\xbe\xa0#\xf8\x82>\x91\x80\xcb\xf13<\xf7\xe0\xdf\xf2\xa3\xb7\x14\xfe\x96\x0214f\x82sQ\xbf0\xb5\xa9^\xe4O\xb9\xb3#P;\xef\xca\xce\xe9\xf2\x0cV\x84A1\x00\xbbT\x86\xc1Mv\x19\xe9s\xc5\xe3f\xa6lt\xcd/\x94\xd1\xe3%\xa5\x14|\xa7 \x19\xf5\xa3\xd0\xf7R\n\x1fJt\xf5e\xc3\xb4\xd5\x91Fq\x98\xe4\x0d5\x11\xea\xb2\xb49\x04\xebYx\x93.\x82\xf0\x12|/\x84\x0b\x02\x0b\x12\x13\x83T@;\xedo\xca\x11\xaa\x0d%\xa6s+%r\x0f\xc8g6\xa0\x91|\xe6\xae\xcb\xf8\xbf\xe4\xae\xb1\x12h\xc63&\x94\x17\xf5\x1d]\xd4w\xecT\x96\xb0\x80kl\x85o\xe0\x14\xc6\xfa\xbe\x1b\xfb\xfd\xde\x85kZ\xd1u\xb5\xeb\xef\xb5v\x90\xa5\xd9\x17\x81\xca;\xeci\x19K\xd1\x08Z\xd2s\x05\x82n8vX\xb5:\x01\x1aJ\xfc\xa5\x17{\xb4\xc1!\xb44\xd7\x1b\x83pF\xc2t\x08\xd6$\xad\xdc\xae\xab\x9a\xcb\x00o1\xd4X\xa5h\x7f\xa2\xa2?\xcb&\x13W\xa5<\xc7\xa9\x06\xab\\\x0d\x87\x96<\x05\xf6\xabn1PxK\xec\x0f\x9c\xeeY\x1a\x13O#\xfe\xa3N\x8c~\xb1\xa4\x15\x83\x8a\xf5Jo\xf5\x04\x919\x80\xd24\xcd\xc9\x01=\x05\xd0\xa5\x11\xc7\x1e0\xd1!\xbf\x92k\xb3\xf7\x9c\xee\x17Q\x10\xda\xe8KgYU\xdb\x9a\xf8$\x94\x8c\x19\x84oC4\x08\x1b\xbdD\xd3\xb1\x142\xe0-\xb9I\xec\xd4\x19\xf7\xa6SdyI\xf7\x9c,\xc9\xaa0\xdbr\x80\xa0\xdc\x91\x9bC\x02?\xcaB*\xfd\x84\x12\x0c1\x89\x0d\xab\x0c\xa3-{20%q\x9c\xadS\xcc\x00'\xc0\xfa\x19\xf3\x99\xd3\xbe.4\x14\xf0S2\x957\x95\x87\xf9z\xad\xcd:\xde\xf24l-\x02\"y\xab\xf5m\xa8~r3g\x1b\x1e\x8f\xac\xc7\xd0f\x0epmxl=6\xbe\xf8\x1e\xbd\xa6\xc7dj\x14,7 \x93\xe2z2\xc7\x08%\x94\xad\xf8\xe0\xa5\\\x81B\xfa\xbb\xb9Pv\xc6\x18\xd1\xca\x0c\xf7\x1a\xc4'\xe9\"\xcd\xa48\xb6\xb6\xf9\x0f\x0cty\xee\xcf\xbc\x14\x95RK6\x9d\xb6\xf5\xa45~\xfe\xd1\xb37\xcf\xc6\xf4\xc0)J8\xb9\xe3\xde\xced:\x99>\xdd\xb9t\xc1\x9aN\xa7\xd3\xa7y\xf1\xa7xx\xb5\xa6\xd3\xa7\x16V\xcdW\x13Q\xdf\xe7\xa1k\x96\xd2=\xaed\xc3\xf8\xc5\xf2G\xbb\xb7N\xc1\xc2\x01!T\xd9YpJ1\x90\x0f\x19\x86\xa2\x0b9\x15\x816\xf4\xf1r\x81\xbdd\x89\xb5]T%\xb5zyo\xd1\x13\xd3,T\xbc\xc77no\xa5\xc1\xd5\x8865\x0b%L\xea\xc6w\xf3\xfe$\x9a\xee\x189\xb3~F)E\x19B\xa4\xdf\xd49}\x18\xd2U\xd3\x16\xc9\xc5\xfdd\x08s\x83F.\nS\xe4l\x06e\x13#aC\x08M\x9d@\xca5\x04\xaf\xeey\xd5e\x15\x94\xa9xo\xe0#^\x1d\x1f)\x11\xf2\xc2HL$\x97&\x8a\xcf\xba\x08\xf1\x82 \x12\x89\xcc2\x0f|\x0c\x9fK\xa7$\xbf\x9d`\xa6\x9a\x81\xd14\xce\xd3X*\x95\xd5\xed\x1d\xe1$W\xbc\x94,\x82yZ\x0d\xa8#\x7f*\xc6=\xadKX\xb5|d\x07N\xb3\xc2\x8c~p\xf25gp\xf1\xd1K\xe9z([\n;F\xed\xf5)\xce;\xe3yB\xa1f\xf3\x94\x0b\xa7`=\xd9\xa1T\x8d\xffn\x83\xf5\xd4\x92Kq\x06\xfa\xe8\x11\xb4BZz\x12\xf2\xc7\xe8W\x8c\x17\xc9t\x1b\xcf\xbc\x8aQ\xa3\xd9\xa3\xd5\x92\xf1\x04\x9dr\x8b\xdf]o\xbd&\xe1\x8c\x8a\x0d\xae\x8cO]\x06\x0cJ@\x11\x1d\xccn\xf5\x1c\x17Z\xbdMH\x04]4\x8e\xc9\xf9\xac\x95\xe7K\x9a.i\xa2\x8a\xdd/,\x07\xa7`\x01++=CI\xca\x02\xcb)\xde\x8dq\x85D\xf5|\xfaqo\x08\xd8\x8eiM\xc4\x02\x97\x96\xa5\x15W\xb7\xa4xC.\xa8\"#\xae\x0c\xde\xbd3]\x87\x82\x1a\xa7;-\xcd\xd0\xd0\x0bD\x1a\xf4H6\xa8_9\x0d\x0b\xd5\xb52Q\x16\xf41\xc5\x08\x00\xdd\x04eh8e\x99Px\xaax\xb3\xb5\xc3\xb2\xcc\"\x9c\x89\xcc\x0bW\x00>\xa3\xfc|,A\"\xda\xac\xf894\xb6\xb1\xe0q\xe4\xcd[ef\xe6\xfe\x0b\x863\xe4:}\x13\xf8o\x99\x13J\xba\xe5N\xbc\xaa\x95\x0f+\xc4\x0e\xf5\x1e\xf6\x1c\xda#\x96\x8c\x12\xf2\xd8\xab(\xc9 \xb7\xc79\xe7\xd7V{\xa2\xd0\xb2\x89\x08\xe3\xc1\xd2L\x1agv\xa3g\x94\xf8\xf8]\xb2\nR\xdb\xa2\xd2\x99\xa5\xb5\x9c\x8a\x0f\x15P\xd8\xfaoHT\xeb\xe6\xf1\xa6v\x1e=\xfb\x8a'\xa0[\xbb\x98\"\x91\xb2\xbd\x9e\xa3\x0f\xed\\\xd3\xca\xa5q\xf8\xccf\xdf0\xcb\xe9\xb75\xcb)\x95\xf58\x88\x843\x0b\x7f\xc6\xc4\x9by\x17x\x00\xa7\x04H<\xf7\x97QB\x0c\x91\xee@\x7fl\x00\xc3rT!\xc2M\xa0y\x1c\x0b5=$p\x94\x08\xbb\x92j\x02q\x1b\x8f\xee2\xd4\xc5s\xae\xbe\xe6+\x12'\xa8\xd3\xb0\xfa\xdd\x9ea\xd7\x93\xd0\x8ff\xe8\xe1\x19w\xc5wFr)\xbd\xfa^\x8a\xd9\xd4%K\xb2b*\x85\x02\xf6\"\x87\xd5b\x9f\xd8\x87\xfa\xe1\xa2\xc2a\x08\x99\xcd\xb4\x81E\xecD\xbc\xc8\xc5\x82\x15\xe6\xbe\x06&%\x0c=\x0dm\xe2\xf5 \xc2\x9a\xcb\xf2@\xa2L\xe5@\xba\x88\xa3wH\xc61(\xacm\x85Q\n^\x92\x04\x97!\x99A\x1a\x81\x07,\x14uK'?\x88\xcf\x95\x94\xaa\xbb\xde\xdePdG\x96\x143\xe6\x8a=[\xea-'\xaa\xa1[\xaa\x81\xa9\x80\xdaT\xc0\x10\x94V\x0e\xbc\xdfD\xdb\x08\xaf\xdc\xd6\xc9\x8a\xe2c\xa2R\x86#\x1f\xa5y\x9b.\x89\xc4p\xd9\xee\xa1Ccv<\x91\x01\x9a\xca\xb9\xe2 \xed\xe9\xc6$S\x9dW!$\x96\x91=\xffU\x8a\x1a\xba\xbbg\x88\x18*\x0fG\xb0\xf3\xf2\x00\xadG\xd6\x10\xacG\xdej}R!\x8a\x8f\xad\xc7\xf4\xc9\xcffQZ}d=f/\xad\xa3Dy\xf4\x04\x1f-\xd5w\x9e\xe2\x83\xcb\xf4\xa4\xa0\xa3\xd2\xb0\xb7\xbal\xc5\x89\x17\xa7lH\xbcru\x8f=~d=y\xfax\xea\xec\\\xd6LF\xa5\xc2pL\xaaI\xb4`\xb8m(\x8a\xd2%\xba\x93\xd2\xbc\xf3[\x11\xfd}\xa7\xfb\xe2\x8a\x84\xe9\x8bU\x90\xa6$\xd6)\xf9\xd5\x83t\xccc\xa1.\x02\xe5Z>\xfd\x84\xf6\xee\xbec\x07.&\xd3\x0d\xba\x9f\x15\x14\x93\xb6x\x80\xc0\x1f\xc6A\x9a\x03\xf7\xf6\x8f\x11\xf8Q\xb6^\x92k\x06:\xe8!\xe8M\xec\x85\xc9<\x8aW\x1c\xdaG\xe8\xf7\xbd$y\xb3\x88\xa3\xecr\xc1\xe1\x03\x843\x9d8;\xd8\x05r\xc2\x8f\x00\x9d\xc1j'\xffJ\xca#o\xd2\x9c\x07\xfa\xd3h\x8a\x06a\x1c\x0e\xbb0\xc5X\x0dZ\x89\xe9\x1b\x18\x1bh\xede \x91\xbe*\xc7&}\x93\x91\x96\n\x85\x05\x1f\xc2\x1ac\x92d\xab\xd2\xf7\xdaSY\xd8\x8d\xc2\\$\x0b\xd0\x81\x0e\x01\xb1\x17\x84\x96\x0b\x11B\xce\x83\xe4,\x9d\x05\x11\x957\xe4\x81\x11$*\xb7\xb7`\xb3j\xa8\x18\xe7\x82\x87\x02\x11\xfd\xcd\xc46\x17\x92\xaa\x16\xef\x8a\x874k\xf5M\xf3\xebi\x07\x9bac\x19\xe7\xb8)\xa3c\x9b\xcd^\xb2A\x85\x86{\xe03\x92\xa4qt\xc366\xff\xb1i\xb3\xbe\x9en\xa3\xaf\x90\xed\xb8\xdcN\x1cw\x97A\x92\x92\x90\xc4\xcf)\x1f\xc2\xfd\xe4\x82E(3\xb5\x1c\xc1_\xab\xf4V\xdf\xe2\xdc\x88&\xab\xe8\x8a|\xc2\xdb\xa9\xac\xb9\xf2PZ\x7f\xf5Uy\x9d\xab\xcf\x8a5\xd7\xbe\x89#\xa2\xc2\x92\xaeU\xf9\xa9\xa9\xd5ym\xabsm\xbd\xc5\xd3\x9a\x9d \xc8-\xc3\xe4R?\xab\x10\x19\xdb\xe7\n\xb6\xcf\xf3w\xca\x10v\x94\xa1\x04\xc8b^\xceM4\xdca\x8ec5d]\x7f\xab\xaf\xa0\xeaG=\xa7\xcb\xc2\xe3\x96\x19\x9e0\x1e6\x86\xc8\xa9\xa2R\x8ee\xa9\x16\xcbZ\xcd\\\x0d\x84\x00i\xa7 %\x19#\x8e,E\xbe\xb9Y\x13.I>\xf7B*LR6\x03\x1e\xf8K/I\xc0K\xc0\xcb[\xd2\x1c\x0b\xdf\xf3\x0d\x94\xcb>\x0b\xe2\xcd\x80E\xa3\xe1\x90\xd4\x0b\x96e\x08?\x0e\x8c\xaa^\xcb:$I\xd5\x8c\xe6\xf5r\x9a\x10m\xf5\xf3A\xb7\xa21S~H\xaeS\xa6\x8eR\xc7\xa9\x8af\xf2P\x9eb\xc0\x92|\xb8\xa8\xf5\xc1\xdb\xc0\xc3\xd2\xac\x90\xf2\x94\x10\x17\xdam\xa9\x9a\xf2l\xb8\xa5\xb1g!\xea\xbe\xbf\xfd\xe1\xe7\xfd\xddd\x0ex\xec\x0ci&\xd0\x11\\\x1ec\x051\xb6\x19\xb32b\x13}\xe7\xe2xQk\xddy5\x15'\x1a\xda\xa3.\x9d\x91Z\xbf\xc3\xbe2\xc4\xd3\xd2\x80\xaa8^Y\xf2\xa2%:\xbd.t:RU\xda\x98\x85u3\x82\xb1\x0e\x9bf\xa4\xaew\x0d;\xb0\xdc\xda\x17Q\x106\"\x1c\x9b\xffQu\xfe\xc5E\x0f\x8d\x17s)\xean\xdeY\xe6Zl1m<\xae\nO\xcdM\xe7\xed\xc4\x81\x10\xda#4\x81\x13\xc3\x9a \xaeR;\x7f\xe8{u\xcf1\xc5]o\xb9\x8c|\xbbg\xf0cV0\xa6\xd0\xf57\xa0]13xj\x0eXl\x08\xde\xde\x0f\xc2\xc4\x9b\x13;\x85\xa7O\x9f\xa2v2+O\x9fG\x97\xf3\x04\xb2\x13\x07'.\xc36\xd8\xacF\xfc\xe2\x04^\xde\x8e\xd67,\xb0\x01}\xa5-\n\x96\xa2\x18dl\xd2MS\x1c)S\x9c\x03\xdeSI\x0b\x03s\x06\xdd L\xd6\xc4OK?\xba~\x96\xa4\xd1\x8a\x91\x89\\9\x93/\xd0\xb8ZpZ\x87\xecb7\xe7/i\xd4jlXC0\x92\x1c}\xb8\x1e,.\x05z\xcfMo\xec\xe2h1^\xe3\x89{c\x7f$\x1d\xfb.sw\xbd\xddF+\x90\x88\x0fS\x1cu\x13\x92\xbe\\\xad\xc8,\xf0\xcc\x1e\xae\xdc>\xc3|\x8cx\xcab5&\xb3\xfc\xf1k\xaej\x007\xdb\x98L3\xc0M7iw\x16\xf9\xa8(3\x97[\x97\x12B~_ \xc9k\xcc*\xa7}`\xcc\xa7N\xab\xc2\x8clk:'o\x82\x15\x89\xb2\x14NaM\xc9\xb5[D\x8c\xe7yk\xa6\xccq\xfa\xab\xf7\xdd4bW\xdb\xf9\xe9[$\xb6aQ\x8b\x9a\xe8\x88\xf8Hf\xa0Z\xca-\x7ff\xb6&\xaa\xaf\xf8\x98\xf4[0\x94Q\xa7\xae \xb4\xa1v\xd7Q\x92~\xca\xb3\xf9\xb3\xac?\xc1\x8an\xc93?\x0e\xd6\xa9\xd1\xddG|\x04\x11\xd79\x08V?x\xcc\xefF\xe1\x8a5Woh\xcf\x85\xbf\xbc|\x13\xd3\xab~\x88\xde\x84 \x7f\x18o(f\xc0\xb6,\x17\xac\x0f-~\xa8(\x1a\x0e\xab\xa1\x94K\xb5\xe8W\xc2vP!\xc5\xab~\xbe\xf0\xc2\x90,\xe1\x14l\x1b\xa3\xa7\x90wP~\xe4t\xe9\xbc\xf7\xf5\x03\xaeE\xae\x99\x9d\"\x057\xa9<\xb7\xc0\xd3\x08;1(M\x8a\x01\x0bQ5\x86\xc6E+\nc\xe2\xcdn\x92\xd4K\x89\xbf\xf0\xc2K\x82i\x92\x97\xa3\xddvD\xbe\x8b\xe2\x0e.Z\x06\x0d\x97\xbd@r\xfb\xaa\xdf\x85\x94\x1f_x\xfe[\xe3qV|\xbc\xf82\xd1\xf9\xdb\x89\x8f\xe1\xae=\x14l\xc8\x1f'S\xa6\xdf\x8e\xed\xc4q!i\xb7M\x08\xb7fG4y\xed\x16J\xd9:\x1f\x82\x85y\x89Yzw\xf0\xab\x81\x9b\xa1\xa1\xca\x1a\x1f\x15T\x8e::\"\xa1\x9f\x94\x86\xbb;\x02[h\x17\xeb}\xf4\x1a}\x9e\xe7\xdc\xf5\xa6\xaeL}\x9a@\xf1im\xb8{\xe4O~:\xed\n4k\x16p\xc4'\xc6\xf7(\xd6\xd5\xf7^|\xf2\x14P\x0d\xba\x0b\xdd\x07\xfd\xae{f\xdf[\xdd\x87\xd4\xf9O\xea>\x0d^\xda\xd5\x0f\xf6\xa9\xbfm\x9f\xe2qo\x93\xbbU\xf2\xe7.\xfd\x1a\xdc\xa5_.\xc4\xe3\xfe\x8f\xa3w\xbbw\xef\x1d\xfd\x7f\xf0-\xf7\xb1\xd1\xd5[\xf7A{\xfd\x12U\x0e\x1aw\x0f\xddG/Q\x97J\x98\x84\xa3\xbc\x00\xcc\x83\xd0[.7\xa1\x0f\xccp?\xdf\xe0\xbc`|\xba\xa9\xdfoE\xb7g[Y\xc8\x02\x02\xcedY(!\xcby\x11\xa9?\x0fN\xbc\x08\x12\x0c\x83=\xc4\x02\x92\x0d\xb8\x949\x14y\xb1\xd9\x15`\xf3[Q9\xfb0\x90M3\xf1E\xdd\x03\xe9.#\xdf[\x9e\xa5Q\xec]\x12)\xa2\xa3:)r\xfeTm\x855\xef*\x10aQ.\xb7\xaf\xe5GBa\xc8sn\xa07\x99\x95\xc6\x19a\x87\x7f\x1e\xd2.t\xbai\xf4I\xf4\x8e\xc4\xcf=\x8d\x01Y\xfe\xb5q\xf0R\x10wal+\x8c>\xe2A\x88\xd0\xc0b\x8a\xbd\x0d\x92\xb1\xa9\x1a\x15\x13\x8a\xb14\x9eapm\xb4ai\xe5\x12\xa1m\xa1\x85\xa8\xd2\xb5\xaa\xef\x91\xee\x1e\x81\xf8\xd0*b\xcf'\xa5*\xe0\x14\xfc(L\xa2%\xe9\xe2C\x16\xc0F\x80\xdeyq\x88g%\x1c\xa4\x1aD\x0f\x8c;-W\x170R\x93\xa2I\xaap\xc4j\xda\x87\xc6\xad\xb4\xd1\x1e\xd2+\xe2J\x19\x96\n\xb0\xe4\x06r\xac\xcb\xa3\x14\xda\xfb}\xed\xad\xcfH\xdd\x1e\xdc\xb6G\xe9\x82d\xde\x8b\n\x1c\xa2+\x15\xa9\x01\xc9\x0bG\x12MpS\xac\xb8\x1b\x84\x0b\x12\x07\xd8yt,q%\x98\x1d1'\x93H\xd2\xab\x9f\xa7\x92\xcbH\xddd\x01\xa2\x06\xb7DT\xdb\xde\xc2\xb3\x86.\xcf\xe1F\xcbS~k\xd0\xbf\xc3K\xfd\xfe\x81S8\xc5\xdc\xf1}\xc9}f\x93\x1a\x9a\xec\xcd\xfdc}\x16\xc4\xfe\xb1>\xcf\xcd\xdeAs\xac\xf6\xeaBqK\x04\x0bH-\xc7P\xd2\xeb\xcc\xb3\"zU\x8c\x97R\xd1*g\x13)\x8a5\xe6\xd6\xcb\n\xebWau\xe8z\xc9M\xe8\xf3\xe4\xadYw\x1d\x07\xab \x0d\xae\x08\x9c\xe6.0pZn\x02\x87u\xbc\xef`6\x0c\x1e\x03\xca\xd6\x948pl\x82w\xe5*\xcf\xa4zi\xb1C\x07S\x0e\xc8\xc0\xfd^\x9f\x01\xe9\xd7\x01V\x93w\x15\xfd~\xec\xfd\xde.\x82\xd6,!\xa7\x00\xee!p\x16$\xeb(\x07\xf6\xd1f\xd3]y\xd7\xcf.sX_\xc0\x04\x80\xbd\x19\x939\xba\xa7\x90X\xc0\x0f\xe8\x8e\xa3\x88\x92m\xb9k\x9a\x10i\xef@\x17\xb9\x1du>\xdeE\xa2\xa2\x12>\x99/#9\x97\xf5f\xe8\xc4\xd1$H^y\xafl\x8c\xfb\xcf\xd2x \x96\xa40\x82W\x18\xc3\x153H\x0d\xd8\x9e\x92\x07\xc6\xcb\xc9l\xfd\xe4\xe8\x02\xd9]\xb1 v\x89\x0b~y\x81\x03L\x9dBe\x1f\xbb\xc8?_&\xb9\x8eDv\x04\xb9\xd1\xb8\x83\xbf^\xd3\xc6\x13x\x8c\xa5\x1f\x83\x17\xce\xe01/\xfe\x18|\xe6\xe2sA K\xd0]\xfc\x92\xa4\x0b\x12W\xb5\xe5|\x19\xcbazr\xd1\xc8:?\x17\xd1\x19\xce\xcf-\x16\xaf>\xec\xce\xa3\x18\x9dp \x0cYf)\xcf.B\xe3\x93\xfc[X\x0c#\xe24\x9f]\x0c\xcbh\xd5 s\xd7\n\xa8\x8c\xd1(A\x87c\x82q]R\x1e\xa8\xddW\xee\x13\xb1T\xce\xe7\xe7\xeb8\x9a\x07K\x12\x9f\x9f\x03\x8f\x14^@0$\xa6\xdf\xcd\xd63/%/\xc2+\xbcJ\x9d\x87\x9fx\x90\xbd\xd3\x88\x93\xbb\xba\\\xbcBU+\x89Y\x17A8S\xb1TS\x90.\x95\x8a\xb6r\xe2\xff\xd2\xc3\xa4x(y[\xf1u\x7f\x99\xbc\x08\xb3\x15\x89\xbd\x8b%i\xa2\x07\x9b%j\xd0\xde\x84\xa2\x934g7\xd3\n\xbc\x1f\x18\xe27\xacK\xa5vk\x0ew\xc5n\n\xec\x90\xa58\xf3\xf9q\xdf\xb3)\xae\xa1Ux\xdeM\xa28\xb5\xb5\x04v\x8d\xa9W\x11\xf9\xd7\xb8\xdc\xc3\"\xfbL\x83\xc6}>N\xa7\xc8\xcf\x99\xc4\xed\xd2\x01\xca\x93e<\x88\xf1\xde'\xecE\x96R\xf8T\xd4\xe3\xbb\xb0t!\x1c\xa7S\x17R\x91gD{\xa3\xdctX}\x10\\\xde;\xacRR!\x81\xea\xf3E\x1c\xe9\xd3E\xec\x1d\xf5\x9d\xee\x8a\xa4\x8bh\x96\xe8(\xed\x9e\xf2\x1eg\xd6\xc7\xba\x04\xd3\x9a\xbd\x80g\xc2r\xc9\xf9\xa6\xbbfYl\x0cff,?\x96\x1c\x14J\x89\x1d\x94\xf0\x9d\x0b\x94\x81\xa3J\xcc\x80\x19B\xc9*hL\xdd\xa5?H\xa1o\xb7\x0bW.\xdc\xb8p\xe9\xc2\xca\x85s\x17.\\x\xe7\xc2\xb5\x0bg.\xbcp\xe1\x99\x0b\xaf]\xf8\xc2\x85\xb7.\x86\xb1Z\xe2\xe9KO\xf0\xaf\x98T\xdc\xe2\x020%\xe5\x9cw\xe7\xbai\xc6\xabS\x89\x9eK25\xc5\xfb3\xcct*\x831\xb8\xd3\x08\xce\xba\x97$e\xd1\x87\xcf\xba \xfd\xba\xc2\xaf\xcc\xac\xe1b\x94\xce3f>q\xdcB+\xd3\x8dI\x12-\xafH\xcc\x82\xcc\xbe\xe5\x9c%\x87\xd2=\xfd\x05\x8f\xbc\x144\x04a\xe1\xfc\x97\xfbU\xe5\x04D\xa5\x1e\x94\x1fcp3\xb4\xd6\xbf\xb5#\xa7\xe8\xd2\x88\xf1\xe8\x1b\n\xa4Et\\\xf2%]\xad\xfc\x1c\xfe\x82\x16\xcb\xb8W\xf2%I-\xdc\xb4\x11\xf3\xc5s\\x\xa9\x8dhO\xfb\xc0\xd2\xf2a\x94\xe4\xc2\xfbp\x9e\x93\x13v\x86\x8f\xc6\xbd)\xeaQ\xaap\xd1\xe7\x11\xcb}c\xd6\x08iF&D\x8b\xd8\xb6\x9e\x07\xb1\x9f-\xbd\x18\x82\xf0*\xe2\xaa\x1c\x17\xac\xe7/?{\xfe\x83O\x9e}v\xfe\xf2\xd5O\xbd~\xfe\xec\xcd\xcb\xd7\xafLVwZ\xeb\xa5\xad\x89_\xfe\xbe\x08i]3\x8d\x0f\xd4\x13\xbe\x1a/\x99=2p\xe1\x99\xbc.\x89X\x17n\xc1\xa7bH\x99|\xbap\xe5\xe4y\x07\xe9\xfe\xa8\xd5\xb6\xe1\xe1Y\xbf\xaa\x86\xa1\xb2{\x02\xb5h#\xae\x12\xe4\xa8[\xe0\x90\xc1\xa5\x10\x8dm\xba\xa0\xc9\xa7\n\xbe\x14\n3\x18V\x90\xccqMh\x9ew\xfa\x81\x17\x89\xf9\x03\xa0\xbf\xb0f\x99\xf2\xfb\xe3\xb8VD\xcdu.\xa7\xfa\x7fXR \xdf\xefD\x8e\xc7\xf5\xc4\xb8\x0b\x8d\xd3\x14\xd4.kP\xa6\x06\xba\xcc]\xb8M\xefK\x0dj:\xf7\xc0\xcb7\x0e\xe8\x1e\x0b\xb5\x8b\x17\x88u\xa3\xe2\x97\xe2\xae\x9bi-\xffQ\x1c\\\x06\xa1\xb7\xd4Z\xfb\x85\xb0>\x84/\xd4\x87\\\xd2\x7f\x85\x91\x83\x90\xdb\x8b\x9fj\xd9K\x92nr\x0d\x94\x0f\xf2m.\xe7\xbd\xb5S\x07\xb9\xdc)\xdc\xb0@\x0f\x1c)R\xba\x18*\xd5S[^x\xc9\x16-\x1b\xd6Q\xe3\xda\xa3i\x8a\xf1\xdbMZ3\x900`\xfd\xd5\xf7\x00\xe7\x04\xfd{W\xccM\nF\xf0\x12EU\xee\xbe\xc0~\xbc\x96\xd1\x82=\xb1P\x9a%\xba Q\xea PL\xd8 #\x8fP\xac\xbc\xd4\x0f\x03\xcf\x83\xe7\xf4\xc8'\x89Fn\xde1l\xc5\xdatb\xa3R2\x9f\x9aK9B\x9dC7\x7f\xae\x0ey\x81F\x0f\xccI&\x83\x9f\xe5`>K\x85\x1b\x95\xfdZD\xf1X\x94T\xfa\xfa\xb8\x15j\x7f\xe9\x18\x870S\x1f\xe4g\xe1\x0d&8e\x92-\xdf\x9ej\xb3\xd5\xed}\xa1\x8aj\xe6{,n9\x87\x8e\xba\x86l\x0b\x86\xb8\x05\xc3\xb2\x8cFP\x92 \x99\x8c\x96q)\xb3j7\xde\x92\xa7\xe7\x8an^\x1bg~\xe5*\xa1iki\xc8G\xc1T\x18\x17\xc9[\xa8\xa6=w1\n}P\xefF\x8cH\xdf8w\xbc\x1b\xc5\xd09\xcf\x1d\n~'Mk\xcaW\x8dNhA\xddB\xd6Y\xba\xa3U\xbd\xcb\xf5\xb7\xd6\xcf\xac\xbb\xf0\x121\xf7\xda\xee\x16XP\xd3q\x8e\x18\xb4\xaeT\x93pum\x7f\xa1\x0b\x8c*\xeb\xbe\x86\x10a\xd8*#\x89\x8d\xec\x0b\xcdSN\xbb\";\x13\xa7\x1d\xb5\x15\xe4D\x91\xfdN\xf7\x0cyEd_\xab}\xcer\xc8\x83\x9c\xf0\xfb\xc7\xba\xfc}\xf4\xe4\xaf?\xe1\x0ft'|\xd4Kv}o\x9df19K=\xff\xed\x9b\xd8\xf3%\xb6B\xe48\x1d\x8d\xf6\xa8\x90;#2u\xa7.\xf7\x98\x07\xe5\xfc\x1fj\x89\xa4\xa2c\xd2\x9e\x85#;\xe1\xa1\xb6<\xc6\xd4x4R\x91\xb8\x1f\xed1\x89\xc8\x14\xc9n\xe1F\xa2l\xd8\xf5\xa3\x19\x8a\xddxO\x87\"\x1a-CJ\x02\xcf=\xd6hs\xa3\x02\xe3\xc0\\I\xc1\xe2\x84ln[`\xb1l\x88\xad\x8f\x882\x8f\xa2!X\xb1\xf7\xa5U\xa5Qj\xd9\x0b\x8a\xf1\xd6\xec\x9d\xb7A\xd94\xfe\xf2f\x08\x16\xfdS\x0d-\xecb\x80\x9a\x08s\xb7]x1\xcb\xe1\x16\x7fy\x83\xb4\x81ve\xf6\xce\xc3\xf7\x1eXo\xbbgH\x8d\xaaU\xdc\xa2\x11g\xe5]o\xa0\xd41\x18\x08\x8a[8\x91\xe2o\xeb\xc2\xa0\"w\xa3\xa3n*+:Q\x1a-yhk5\x8df\x17\x9et\x1cS\xf9\x9d\x8cc\x8d\xabi\xa3\xbfN\xc8\x02\x15\xd0}\xdd\xe8{\xc1\x04\xfe\xfe d\xf0\x04\x92\x13h\xb73v\x7f\xad\xd8\xa0\xd9\xd4\xc5\x80\xb7yh\xa2jv\x82J\x1c\xb407\x8bh1\xfd\xdb0\x1c\x1e\xee3\xc3\xa1\xa4ag\xa6\xc3\xc3\x83o\xdbt\xa8_D>V9\xae\xac\x95\xdb\xd4-\x8c\xb4X^\x87\xdaE\xd5;`=\xb0>Y\xe1\x1eA\xd9d\xd1\xb4\x9d\xaa\x1d\x17\xe6f\x8c\x84\x9b\xaf\x0d;\x9em\xebzr\xa7\xbek(&oB\x1fR\x9d]A\x1b*Ks\xc7\x81\xe3\xb0\x1f=\x82`,\xec\x12\x98\xbe\xa1\xf5 f\xd6*\xfe\x1f3\xfc\xe7w\xe5J\x17nS/\x08\xf9n8\xea\xddc7\x88\xd9\x96\xc9\xfc\x96{\xa5\x8e\xd7\xc5E_1\xe7\x88\x08\x17\"\xa06r/\x91\x9d\xbb\xfal\x1eE\xd6\xc3\x18\xda\xc50\x95\xa9\xe4wa\xee\x8a\x0d\x95#b\xc9\xb6\\NDy\xdf\xceW\xee\x92\xba\"\x18\xbb\xc6\x04\xb4\xd4[E\xd7\x1b[r\x16\x9bZrf\xf5\x96\x9c+\x83%\xa7\xd2\xdc\xcd\xa6\x06\x9fK\x9dE\xb5\xac4)\xbf\xb0\xd2\x12\x0c?\n\xe7\xc1e\x86\xb6W=\xd1 \xb9mV\x1f\xf5Z\x04I\xaa#+j\x9akJ\xa2\xe2&a\x05\x84\xc0b<\xb3-\xd1\xa5\xe1RF=\xeb\xfc\x9c\x10t\x1b8\x95b\xcb!\x8c\x1e\xe5(h\xd5\xc5\xbc\xe70\x82\x99P\xc8\\U\xdeva\xe5\xb8RA^,\x1c\xa7S8\xd5\xc5[\xe7O\xe8\x1f\x16\xac\x0d=O\x11:\x821\xb3\xa5\x92i\x01\xe2\x91:\xca3V\x11\xf5B\x9f\x0c\x91\xd0o6K\xae\x1c\x0eL|J\x13\x15\x88\x88|\xcan\x0d7\xb9\x9f\xc8\x8d\xd4\x01{\x03\xaf\x91 \x97\x8df\x8fX\x8c\xadCg\xf7u\xe8\xe7\xf1|\xce\xcf7\x9c\x8a\xf9|\x88\xa2\xef\xa63\xc1i\x84^\xcd\xcd&\xa3\xa5G\x9bR,\x05\xfd\xfb-\xbb\x82X\xce8\x9dn\xf0\x9e\x8a6,\xb6(}[\x9d1\x10\x92w\xc4n\xbe\xd1\xc5\x8b\xc7\xd1\x94\x8a\xb0\x91\x03A\x11\x927\xd0\xcd+{J\xe5\xe4\x81\x88K%4\xfa\x1c\x05\xe3q\xc4]\xe40ie\xdcM\xd6x\xeb1r\xa1\xaf\xbb\xb7\x87\x96\xb4\xb8h6\xaem\x96kc\xc3:\xcf\xf8\xa6eg\n\xc4\xac\xf1~\xe2U\x1e\xd1\xa2v\xdd\x0dt\x82r\xe3\xa0\xbc\xa0\xe6\x15\xd1\xafc}\x1cx\\\xc5Pc#c\xb6!9\xd5\n\xbb\xebH\xd8\x89\x85\xc0\x13\x08\xe9r\x13\x07\xa21\xa1\x0f\xcb\x17\x1dI\xcd%8l4\xc0\xe0\x15\xec2+\xaf\xb7w\x82\x847\xa0/\xb3\xaa\xf9.\x8e\x0bC\x8e\xb6RnJ\x15\xb7\xc9\xaac\xa9\x9b\x80Mnl-\n\xe2\xb2\x08\x92\x86{F\x0d\xf7\x8a6\xb9\x89Un\xaf\"\xaf\xdc\xbf\xf5\x86\x9bVu\xad\xbb%\xdd\xd1\xfd\xfa\xb2\xd1\x8d\xaa\xbf\x14\xfc\xa4\x9fue\x16L\x98\xf7\x1d\xfd\xaf\xf7\xba@\xcch$\xb1\xab:O\xc6K\xe7vP\x85S\xc62\xb7#GGx\xe6\xb6\xec\x0b\xcd\xbc\x08o\xec\xaf\xde3]\x9c,\x1d\xd7_\xa1\x16\xaeb\xccU\x02\xad.3\xdbgq\x88\xf3C#\xadTn\x8c\x08\x9f%:\xa3\xdf\x81\xfb\n\xcc\xdc\xd5\xa9\xea\xd3_\xa3W\xd5\x88\xcd^\x9e\x9b\xb0\x12\x99\xb8h\xaf>p\x80D\xf7+i\xb05\xdeG\xd2\x0b\xe8,d\xa7\xe3\x10-\xcf\xf4o\x19%\x1c\x91\xf4\xce+\x19\xa5\xd5\xeb\xfb\xef\xdd\xedN5\xa8\xf6B}\xd7\x86iy\"~(\xce\x14\xcb\x8aC\xa5\xae\x8b ,\xc5]\xb9\xefQ\x88\xadS\xffX\xa3\x1d(%\x94\xbb\xe3\xa1.`\x9a\x8d\x94\x8a\x07\x0f\xd4\xed\x8d\xce\xd1B\xb3\xcc\x04S6\x92y\x1cUrq\xd5\x9d\xb6Y\xe8v\x14\xddq\x0d\xc7\xa8Gv\x99\x8ax\xea\xb8\xf0\xbd(Z\x12/\xb4Q\x94!E\xb8e,\xc0LA\xe8\x15\xfd\x10c\x96\xf4\xbcG\x07N7HI\xec\xa5\x91>\x90\xe3\xb1\xde}|O\xb9\xcd\xc5\xf6\xe8\xa0\xba\xa3=\xfd\xd6M\xf4\xead_\xbf\xff\xe7\xbc\xcdj\xe5\xcb*^mt\xacV\x0f\xcb\x8b\x878\x8cj\x9e\xcb\x87Q\xf5)\x1e\xe64\xf1\x17\xdf\x1bO\xf2\xe5\xa3\xfa\xb6\x9b\xa8\x10K\x8d\x1e\x94\x8d\xa6\xa4\x17\xb5\xa6$\x0c\xb2T(\xe6\x13\xa6\x98\xf7\xed3\xa4A\x9e}\xc6\x83#\x02\x8f\x16\x8eh\x8e\x0bG!\x11\x0b\xf6\xec\xe4q\xf2\xca\x95\x1bb1\xe0 \xe8\xcc$\xee\xa1S!\xde\xa0\xe1\xbb\x93y{\xda\x97P\xc4\xe9\xa7$\x85a\x11\xbf\xb9\xcdo\xeb\xd1\xf3\xb9}S\x928\xfa\x0e&+\x1bA\x8a\x17\xd1o\x0c\xd2\x10;\xd5\xd1V\x1b\xa4\xf0r\xed\xa5N\x95B\x8c\\R\xb1&t\xe0\x86\xf9\xf2\xa5Z\x07J\xf1\xe1#5$\x0cU\xa0*\xe4\x06\xb3\x05~\xc7\\\x08\xe7|\xa9\x98\x91A\xb5M\xd8\xef\xb0\xbb\xf1\xd48\x178\x0f\xe7\xe8\xe5\xfa\x8e_Ge~4\x94`\x8a\xf9\xa1\x07\xe4\x0b\x18\xc19\x06\x16\xb3\x8b\xc9i]tgQHN\x1c\xb4\xbf\x9f\xc1\xa9\x10\xe2\x983\xf0\x05\xd3\x98p7\xf6\xfc\x17\xe5\xdf\xf6\"\xd7\xa6\\\xbb0\xb3opg,\xf0\xae\x15\x9f\xe6\xebj\xa3\xed\xb6!a\x16]9Mv\xa0\xc2\xdbs^\x83\x0d8\x03\xf2\xda\xebF\x8f\xe3uQoW\xc1\x89k\x8e\x10\xbfz7\xa4\x82]#\x05\xbb*\xc7\x92\x1c\xa9\xb6\xc0\xa2\xd8vx0\xdb:\x9bt\xd5\xd8\x0c| f\x8c\x07\xd8\xb3\xa2\xfbn\x8d\xccW\x89\xb0\x1b3\n8\x1b\xa7,\xcb\x1f\xcb\x9e<=q\xa0\xdd\x8e\xb5\xd4\x0b\x8b\x8e\x80\x17\x9d\x8a\x9c\xab\xf6\x9a\xa9]\xac\xef~\x17\x03\xab\xb9\xe0u/\x13.:\xd5\x1fI\x0bo V\x13\xd3\xb5\x10\x17<&.\xe2\x93~\xf5\xb4Zry\x97\x83\xd8F\xb52/J\xa4J\xc4\x08}y\xfa\xf9\xf9\x8c\xb00\x94A\x14\x9e\x9f\x0f\xc1\xc3\xd0\xa2D\xe7\xccw\x1ez+R\x94\xb9\xb2\xab\x0e\xd0\xef\xcb\xea\x91\xb9\x1dT\x9b\x9cG1}\xbd\x1e\xcb\xf8\xa0\x17\xcc\x0e\x86\x7f\x86\xec\xcf\x08\x02;'\xe8\x8aR\xa4\xf4\xfb-\xb9\xf9x\x93\xc6\x0c\x8e\xe3\xb8\xf9\x08\x04!$(\xd3.\xcc:\xfc\xc5\x98L\x99\xa7s\xce\xc1Hm\xd7\x16^\xf2\x92c\x89\x98\xcb\x98YA\xa4'\xcc\x9f\xcf\x92 J\xaa\xf4 y\x8e\xaa\xaa\xb3\xb5H\xf6R\xa9N-\xc0kU\x1f\xa8\x95s6V\xad\x92\x83EE\xfc\xa7\xf2\xfa\x8a\x92\xc3\xca\xbb\x08\xe3/\xe2w\xe5-\x9e\x13\xa9\xf2\x9e\xc8\x9a\xc4\xde\xe4\xbf\x94w\x13\xe2\xc5J\x93\x0c\xc8\xdfd?\xd4\x17\xd7\xc4\x0fHR}\x93A\xc5\xab\xec\x97\xe6\xdde\x90*o.\x834\x7fo\x19\xa4\xca[\x92\x08PyWz\xc2k\x90 \x9azrAA\xa9'\x7f\x92\xd7\x93C\x94z\xb20\xf1\xa35E\x83\xea,HOx=\x12\xa4\xe4E\x82$F\xa2J\xd5\x9d/\x119\xdaFU{.\xba'\xda\xaf\xb5 \xcb\xba_A\x95*;\xae\xd2\xb1\xc0\xdc1\xb9\xe5MZ\x15\xe4\xdb\xc6\xec\xedL\xef\xd1\xad\x90Qh\x83\xe5(\x0e\xa1\xa5\xdfx\xa4x=\xdf\xb4\xd5\xa4\x92M\x0b\xd4Q.\xcb\xa3\x0cddr\x9b\xa6U\\>\xe1\xed\xe8\xb5\xa3\\\xee\xae\xe4\x86\xc7\xe0\x189\xc6\xd9r\xa7\xf4\xbd\xca\x11\x11{\xe5[\xae\x98S\x8b\xbd\x105\xbf\x10\x94\xe2\xf0\x97\x04f}\x15\xe5\x99\xd0UQH\xe5\xf7\x89\xa5%\xe9g\x8f{[G1b!\xcfP\xdf\xa0\x93\x1cR\x8c\xea\x9f\xcb\x0d\xfac\x90\xd8\x1c\xc52\xdc}4\x9b\xf5:?\n\xb1\xab>Z4\xb9\xbd\xa5\xcf\xe54\x05\xac\xecY^\x16#\x98V\xb3\x18\x9e\xf2\x8b{\xb4\x1d~'\x8ecj\x87\x87\xfe\xb0\xa3b\xd1=\\\xf4\x80\xa2=\xf3\x93\xc5X&\xe3\x1e\xf7q\xc7\x07\xf4E\x17\xbcq\x9f\x03\xbf\xc5\xae\xe7}\xefO\xc7\x11\xe2xvr\xaf~;\xae\xa8\x8c-\xe0\x1d\xf0\x97k8\xb5\x99\x16\xd5\xa1n\x17\x1b\x83\x07\x8f\xa9\xc1\xe4\xac\x1e\x93=\xee^^\x8f\xebyn>c)\x1f\xd9\xc1\x06{\x81\x0b[\x19\xc5.\xf3f\xa0\xaf`\x1a\xc0q\xb2 =\x8d$,\xdd\x9c\x9eJ\xd2\x7f\x86\xe8\xe0\x8d#\x89\x9e\xd6\x93R\x9f!J\xc6\xe24\xb1\xbe\xf6\xa7\xe3\x00\x91.\xba\x03a}\x90\x9e\xe5\x17q\xf3\xce\xd0\xf7\x85\xdf~\xe0\"B\xd3g%\xd0 \xb4\xb0\x18\xb7\x7f?z\x04\xbe n\x0e2\\\xbf\xbb\x8e\xd6\xb6\xe3\xb2E\xe1\xbf\x9c\x0dj\xdeb\xbbH\xd7\x016\xd9'\x9b\x86_\xe1r\x8a,\x97\xa8\xd5\x7fG\xff\xeb\x1eRY\xc5\xf0\x7f\xcco'\xb2\x90\xb4]\x0ci\xc7\x83:\xdf\xe7B\xe2VB\x9c\xdc\xf66G9\xb4w\xa7\xf6W\xef\x91P\xa6\xf6+\xef\x15\xbb\x83\x98\x16I\x1e\xe0\xe1fk\x03\xa9\xbf5z\x18=XYt\xbe\xe3\xb4n)\x1bW\x89\xe4C\x88\xc5\x12\xb9 .:\xc2\x19\xbc\xe0\xca\xc2[PHi\xe18\xd8h\xd7\x95\x85\xac\xa6\xe0\xa1,_6K\xac\xe3B\xc8~\xb5\xdb\xa9\xf3\xed\xf0BIc\x85\xf9\xa3\x90\xf1\xb7p\xa0\xec\x0c_&Va\xe9\xb7\x86*<\x0c\xd1\xd1\xc8+\xdf\x02\xbdy\xc8S\xa0^\xc9\xa0G\xf5\xd0(\x8a\x9a\xe48\xcd|hJF\xf7\n\xc7\x15\xcd\xe09\x82\xb8\x10\xa1\x7f\x01ECM\xd8\xe4\x0dh\xe1F\x18\xce\x8e\xb9L\xcag\x83\xa5d\xc9G5\x00\xe1\xc7\xbb;\xe3<;C\xf9x\x86j\x16M\x136#\x9e\xcb\xf3~\xf3S\x1aC\xfel\x0b\xe4\xe7\xbdi\xd5\xf6\xa6\xe1\xc8@\xe4\xe6=U\x90\xf54\"\xb2W\x16\x91\x93\xb2\x88\x9c\xe4\"\xb2W\xfc\xd2\x88\xc8j\xcd\xc6\x9er\x89\x98\xae\xd4\x86\xd3s\x0f\x96e&\xe4p\xc7\xed\xe5\xcaD\\\xed\xeaw\xf4\xbf\x1e\x86\x07j\xef;\x85v\xff\xb8\n\x8f8\xfcH\x7f\xbfM $..\xcfT\xef\xe0$\xa6\x8bo\xe5b\xdb\x05\x0870mL\x15\xc1\x93\x184\\x\xe7J\xd3\xa5\x0bk\x17\xfd+\xe7\xdcAQ\xa5/u\x0f\xaf\xd0\xba!\xc2\xce\xa9\xcfo\xf0\xb9\x08\xc1X\xc6\xe8\xe2=\xf4\x08\xaf\x97\xe5\x84\xa4QD\x17\xd6\xe2V\x8c\x91\xa1DJ\x07\xbcVj\xd4\xd4\xebC\xad\x80\x88\xd7\x1737\xbb$\x17\x9f{.t\xfa\x945\\\xf1\xcb'\xcb<&\xc2\x9a6\xab\xda\x9c6rX\x8eli\x02\xe1\xaa\xc6o\xf9}e\xfa\xa2P\x04\xe9m\x9e\xbb\xda\xdb\xed\xda\xfb\x93\x90\xbb\xbbI\x11\n\xb4s&;\xee\x8d`\xbc\xc0\x88\x15\xa1p\xe2c\xd4=t\x98\x0d\x0e\xa7V#\xbd\x89O\xcc\x18\x12\xdd\x95KF'\xd6LZ^b\x96|\xe1\x92\xdf\xe0D#>(\x7f\x98\xe9\xa8.R\xec\x8c'4@~=c\xc17\x8a\x80\xc8\xb8\xb7X4\xd8\x88\xf1+\x1e\xcb8\xc6T\nQ\x98\x92\xeb\x14\xf30\xc5\x97\x89\x93\xfbo\xc6,yD\xc00%*P\x88\xae\x89)Et#id\x99\xbe\xf9\xdej\x8a\xc2q\xc5\xeeEr\x9fp\xe3\xa6\x08\xe9\xd0\xd3rV-\x1e\xfeCT\x0f\xa9\x19a\x84\xfc\xccD\x8a\xb4\x1b\xcc\xcc\x9a?\x1e \x13jS\xf9\xd3\x82\x9c\xdd\xd1\xdaXO\x16\xe3\xa4\x08\xda\xcb~\x04\x85MF\xe9>\xbf3\x86X\xa1\xf4\x8a\xffX\xe2\x8f\x9cq\xc5\xdb\xf5e\x81\x0eZZ\x94\xc6\x1b 6-\xc0\x88\x8e\xc3\xa9\x0es*^8\x90u\xe9\xcf\x0dD\xa1\xc4\x9esa\x85\x8b\x14Z \xa5qJ\x12{\xad\xe3\x0fj\xefs\x1a\xc2\xa8\xa2\xe8\xaf\xf9x\xa6\xbd`\x9b\xe1M\xfb\x0d6\xc5g$\x8d\x03rE\n\x8a3\x8b\x08#D\xc1j\xbd$T(\x12h(\x90\xf8\xb1\x96*\x89\x0fk\xda\x9e\xbb\xa0\x1bqe|9\xb5\xff\xafq\x9c\xe5\xcdj\x1aoM\xdf\xf8\xfb\x0f\xd6\xbd\xbc?\xdb\xf5P\xac\x08\xe6n\xe0oh\xd1\xb1\x04)\x04\xaf\xaa\x8a\x81\x85\xca3q\x1a\x93\x8a\x01\xf9`\xbb\xad\x0f\xeaW\xe3\xe7D\x19\xc0R\xfb\x12\x88\x03\xfe\xa64I\x7f\x8e\xc7\xc1\xe8\xe9\x8e\xbeM\xcf\x8e\x1c\x93\x8c\x1f\xe1\\cVF\x9ct\x84x\xb3\x03I\x1elH\xf2\x7f\xd5\xefa\xe9\"\x1asj*\xee\x84y\xccO\xb1\xd5\xe9x\xe2\xe4R:\xac\xb4z\x98\x9fP{]L\xc3\xbf.I\xfa\x19G\xd0\x1f\xd38z\xc5 <\x16LV\xb3\xfd\xef\xa7\xd4\x92\xd2\x0f\xe96X\xe8B%DsXD\xecm\xf1\x88\xbd\x04\x86\"\xa5b#s@\xaf\xb2\xee\xf3\xb33\xba\x1c\xf8\xa5K\x12\xdf[\x17\xfaT\x19\xa8N\x95`,\xcd,H\xc4dP2z\x19\xbc\xd8\xfef\xd1\xec\xdf\x84\x98\xfcl\x16\xc4$\x01\xaf\x08}g\xf4X*\xc5\xbb\x96\x82L\xf1\x10La\x9ea\x81\x12\xcfN\x9f\x1d\x83)ya\xa2t)[\xc2 \xb4\xdb\x01<\x81\xf8\xc4\xc1\x19\xe6\xf9{\xe4B\x01\xde{\x8c\xa0Mg\xff\xe9\x08\xfa(\x05S\x01d\xb7\x8ftgp\x08\"\x03!N@\xc0\n<\x1d\xc1\xdeQ^v\xff\x10\xcb\xd6=\x7f\xf4\x08\xf6\xf6i\x81\x8c\x12\xc6\xc9\x04\x83F\x15\x96\x89\xfe\x01Zr\x80\x12K\x1b\xfb\x1a\xb0*[\xfdJ\xd8\x01\x82uup\xc4\x1f\x88\x0e\x1e\x17_\xf5=D\xe8\xc1~\x0e=\xee\xe5\xd0\xe3\xc3\x1c\xda\x1f\x0c\xf02(\xce\x13\xce\x11\xa5\xe0\xac\xcbe \xce\x9b\xf5\xff\xfe\xc5\x9fY\xb5\xfbPuz\xd78Q\xc8\x18\x8b\x1a\x18\xf6\x0dO\xdan \x91Y\x8a\xcfJt\xe5r\xec\xeeX\xd6\x1b\xbew\xf2\xdb:\xa1\xdd\xef\xdf'\xb0\xa76p=\xad\xd8:?'\xc9\xa7\xd1,[\x12\xabJ\xb5y\x9a 9\x8d\x82\xc3T=\x98K\xaf\xceQ\xc5x}9I\xbd\x94|\x7f\x99]\x06a24l\xdadM|\xd33\xfa\xf1\xb0\xcdd\x08\x99Y\xc8O\xc8\x92\xf8i\x14'C0\x04c\xd2\xbf\xcbR/\x19\xbb\x068\xb6Y\xe6\x13Zs\"\xa6\xc2\xdc\x8f\xbc\xaf\xd1F}\xf5\xf4}U\xf1\xf0;\xfa_\xefU\xf9mn\x87\xf6~\xffX\x89\x90\xcd\xed\x0c:\xbb\x84o\xd3'{J\xa0e\xfeh\x7f\xaf_}\xe4\xe5\x8f\x06J\x90i\xd1\x87\xbd]\xc79\xf9N\xfeL\xe0\x0e\xf8z\xc5O\xca\x98C\x81\x9f\x05s8\xa9\xa0)\xe3\x06_U6\xa7|+G\xa3\x10\x93b\xe6\x05!=\xb65\x1c\xac\x0bC\x1d\xa7eEF$\x93\x19\xbc\xd8(i\xd9\x8fC\x9d\x84\xb9\xd1\xbdB\x99\x07\x1e\xb4X'a\xb1\x1c\x97\xd5 \x93\xdfQ\xbf\xd1q/\x95[B\x97$\xfd$\xf2\xbd\xe5s\xdc\x04\x9b\xc5\xfa\xb3{\x18\x8c\xd8\x8b\x13\xf2\xd3\xde\x8a\xbf\xea\xd8\xb1\x18\xfcv^\x0erC2]|\xdc\xe9t&a\x16/\x87`-\xd2t\x9d\x0cwv\xd6$M\xd2(&\xdd\xe4\x9dwyI\xe2n\x10\xed\\\x0dv\xc4\xaf/\x92(\xb4&\xe1,Z\x9d\x07\xb3!X\x7f\x85?\xe8d\x815 \xd11\xddK\xa3\xf8\x07\xa5:\xa3p\x19\x84\xe5\x1aEAk\x12F^\x96.\x06\x9f\x91Y\x10\x13?-\xde\x1c\xee\xec,\xe9\xbc-\xa2$\x1d\xee\x0ez\xbd\x1dV\xb2\x13\xf3\xa2\xddE\xbaZZ\x93\xf0\xb1v\xd0\x1bQp\xc9\xb5c\xd07hR\xe3\x87\xa9^\x7f\xdc\xdb\xdf\xebi\xb7od\xc4\xdcZ\xf4Q\xbcH\x85\xb5\x120\xfe\xa6\x88\x15=#\xeb\x98\xf8^Jf\xe0\x853\xc9\x91&K\xc8\xac\xdb\xe0C\x03\xf2\xfct\xa9\x98\x87#\xe9\xc9IK\xbbg\xfe\x82\xac\x98uu\xf7\xa8\xf4\xe4\xe3g/?9{\xf6\xf1\x8b\xf3\xb3\xe7\x7f\xed\xc5\xa7\xcf\xb8\xc1vP*\xf3\x93g\xaf_\xc9\xcf\x07\xbd\xdd\xd2\xf3\xe7\xaf?{Q~^~\xff\xa3\x17\x1f?\xfb\xc1'o\xce\xab\xed\xec\xefj\x8b}\xfc\x83O>\x91\x8b\x1d\x95\x8b-#o\x86\xa1\x02\xe8\x97\xea\x83g\xf4P\xc1\x9f=c\x17\xce\xc4\xe3\xc4\x9b\x93O\xc4\xbb\xe2\x87\xae\x80\xa8C\xfa-\x17\x9be\xab5\xc6\x0c\xa4_\xaa\xef\x7f$\x1e\x8a\x1fr\x81\x9f~\xf6\xe9'/\xae}\x82!\xe89\x1e\x96\x86\xf6\xe9\xcbW/?}\xf6I\xddZl8\x87\xe6\xe9K|/D\xd5\x81E\xbfY\xa5gH\xe1\xd8C\xfcZ~\xeaG+\xee{\x12\xd9\x16\xffQ.\xe1\xcdf\xcf\xa5\xf0\xe1X\xb0\x0c\xb3\xee!\xdfI\xfe}\xd5\xab\xfcA>\x9b%0\xbfD\xa5h\xa0\xb3|\xeaJ`/\x9f\xaf\x128iVH\x97_\xf0U\x85\xf2\x1cF0(\x83(\x92\xed\x96A\x14u\xf6\xca\xa0\x85Z\xd7L\xad\xebJ\xad\xeb\x86\xb9\xc2]\xf7z\x9d\xc9u\xefhr\xdd\xfb\xde\xe4\xba\xf7|r\xdd{\xd1\x99\\\xf7?\x9e\\\x1f~\xdc\x99\\\x1f\xedM\xae\x8f\x0e:\x93\xeb\xe3\x8f'\xd9\xc7\x1f\x7f\xfc\x02\xff\xffxz;\x9ed\x1f\x1d\xd1\x97\xb3\x8f\xbe\xf7\xf1\xc7S\xfb\xb4E!\xcf\x19\x84\x96pn\xed\xd3\xe1\xf8\xf3r\xb1\xdb\xcf\x9dJ\xb1\x9dr\xb7.y\xb7\x8e\xf6\xcb\x1ez\xe5R+,\xe5N\xc6\x93\xe9\xe4\xab\xc9\xfb\xea\xe3s\xfa\xf8s\xfbt\xd8\xbam\xb5n[c\xaf\xf3\xe5\xa43m\xb7\x9c\x0fv\x82r\xc9\x8b\xa2\xe4\xf8\xf3\xa2>\xc7>\x1d\xfe\xc4\xb8\xd79\xf6:\xf3\xe9W\x83\xf7\xb7\xec\xfb\x97\x93\xce_9\x99\xecLN\x87\xdf}4\x9a\xb4'\x1f\xb8\xe7\x93n\xeb\x7f\x98|\xf8xbO\x1c\xfa\xf6\xd4\xf9\xf0\x83\x9d@\xc7\"\xde\x19YD\x9f_B\xc33\xe3.\xfb.\x11q\xb5\xaakcU\xc7EM\xbb\x83\x0dj:\xdb\xa6&\xec\xdf\xb6}}alao\xaf\xa8\xea\xb8/}\xdf\x95\x9a\x18\x94~\xeco\xd0\xe03\x83yG+\x9e\xee\x1d\xa1\xb9\x02\xa5K~\xd2>\xc5 9{G0\xa4\xc7\xea'\\\xef\xb0;\x80[`\xc9\x9c\xd91\xbb7@}O\x87\x16j\xd3i\x19B\xa7_\xdb\xb1\xd7\xe6\x998\xca\x15]\xd6\xa4g\xb1\x96s\xc8\x7f\x87\x00\xb9\xc8\x05\x85\xf4\xfb\x07\x12(\xc5BU@?_.\n\n\x19H\xae\xe9\nA\xbd\x81\x04\x9a\xb3R{\x12(f\xa5\xfa\x05\xe8\xbf\xa7\x90]\xe95\xd4}\xec\x16/=\xb6\x1e\xc3\x10\xf6\xa4a\xec`\x0f\xe5\x96&\x14r(u\xe7\xff\xf9y,\xb3/A~\x13\xcb\xc8#E\xaa@\xa1G\xbd\n\xf4\x98)\xabk\x17\xe1\x8b\x9a#\xc6\x93\x11\x1c\xec\xef\xef\xee\xc3)W\\a\x96\xe9\xe7\\\xdfd\xa7\x85\x03j\xf9\x01K\xe9\xd9\xa6\xa7\xb5\x0e\xd6p\x00O\x9fB\x9fJX\xfb\x07\xbb\x83^\xf9\xd1#:\xdf\xbb\x8a\x11\x15\xe4\xd3\xd8[\x90\x13\xd3\x0e\xf6\x0f\x1c\x17^j`\x9f\xb2\x84r\x9f\xc2\x13\x18\xec\x1f\x9c\xc0\xa7\xed\xb6\x03o\xc7\x9f\xd23\xd9k\xfbS\x87\xc7\x19\xe8\xb9\xf0\xb2\x00\xea\x88\xd3\x1b\xad\x1e_hb\xc9;\x08P\x01C\xdeQI\xb7;\x0f\x96$\xf4V\x84\xb2\xf6 \\g)\xde\xdb\x8f\x92 \xc5;\x96i\x97\x9e\x1fd\x18t8\xf0,\xf5\xe2\xb2\x9b\xbc\xda\x97\xe7\xda\xbe0Q\x99\xf7\xb3\xf6\xfd\xef\xeb\xdf\xefF\xe1\x0f\xbd8\x0c\xc2Kv\x96\xcc\x7f\xf2\xeb\xea\xe8y\xca\xeb\xd7-\x0e]\x97\xcf\x94\xd3\"\x15\xd9\x86\x8d\x16\x1a\xf1\xbe1d\x0b?\xa2\x8f \xed^\x918\xa1\xc3x\xf4\x88\xcd\x845\xcb\xd6\xcb\xc0\xf7R~3\xf5'h\x93\xc0\x8eT\x98Q\xca\xe5\x91\x0fC)`\x15{\xb3\\\x12<\x9f\x8a\x96 \x90k\xcfO\xf1b*\xc9U\xba\xb4\x9a\\\xe3n\xc7\x8c+R\xa67m;\x93\xae\xf8\xf6\xc1N\x97\\\x13\xdf\x0e\xc7=\x1e\x03\x8d5\x14,\x97\x9dy\x14\xafdw\xffh\x0e\xe9\x82\x80\xda[*\x8b\xa1\xf4\xf82L\xedx\xdc\x9f\xbal\xafDe\xf8@\xc0\xa5\xb8\x8e\xac\xb5,d#\xc1lhX\xbf\x983\xde\xe6,\xf2\xf3A\x15\x13:\x82\x90E-\xef\xfa\x0b\xe2\xbf\xfd$\x08\xc9\xf7b\xe2\xbd\xa5\xe2[Dw\x90h\n\xef\xdc\x0e\x8a\xaf\xdf\xe7\xad&\xd9\x9a\x8a\xb1d\xd6\xd0hiu+*\xb67\xcf\xfe\xeav\xe8\xa2\xe2\xca\xc0\xb0\xdao\x9e\xfd\xd5\x9a\xc5N\xdfE\x85\xfe\xdf\x12\ny\x16\xd1\x0e\xbf\xd1u8\xef\xa6$I\xed\x18\x03@(K\x9bz\x97\xb0\xf0\xc2\xd9\x92\x80=\x0f\xe2$\xcd+t\xc4$\x94\xfa@[\xc9C*\xa4\xde\xe5\xa7\xde\xda\x85\xb8@\x9b\xc7\xe9\x82\xc4\x84\x1ep=X\xc7\xe4*\x88\xb2dy\x033\xe2/\xbd\x98\xcc \xc9\xe6\xf3\xe0\x1a\xa9\xa2\xf5\x18\xda\x10C\x1b\x1e[R7\x1e;.\\\xb0.\x07\xe6.\xafcB\xab\xb1\x13\xe2G\xe1l\x83>\x8b\xce2\xbf\x87r\xe0\xfc\x92\x96Q\xa5=\xaf\xc4\x92\xe2@U)\xa4\xc8\xdf\xaa\xaa\xe9\x08<\xd1\xa3\x02\xbac\xb0\xd8;\x94\xd8\xf2+\x1e\x888\xb4\x19\xa5<\x08V\x120sz$E\xf5f\xf9\x08\"\xfa\xa7=\x82\xbe\xc3e\x06t\x0e\xf0\xaa\xb6\x15&\xfb=\x19AF\xd7,C\xb9\xa7\xdf\xdf\xeb\xf7\xfb\xc5d\x93\xeb5\xbb\x83\xcf\xa2\x1c\xfc\xe4\xd9\xebW@\xab\xf1\xfc\x94(\xb90A\xdc4\xbca\xab\xe6I4\x84.E\x92\xc6\xc4[\xa1\xc3\x81\x17\x84 \x84Q\xd8Y\xc7A\xc8\xb6z^m\xa2\xab7\xed\xc6$\xc9\x96\x98/\xd53\xad\x99f\xc9>)\x96Lqo\xb9\xe2 \x04\xd0-\xac\xe2,\x833\x1cw\x83\x84\xa7\xdb\x0f%\x0c\xe4\x1a\x9a\x15\x89/ \xac\xbc\xf5:\x08/\x93\x13\xc4\xb6u\x1c]\x053\x8a\xddQ\x16\xfb\x84\xe7o\xa6\x9b@&k\x96\x93\x87\xd8\xa4\x87E[\xf2*xKn\x12;t\x9c|A=x\x02>\xfd\xc3\x164\xc3\x80\x8f\xde\xd4\x95\xe2\x9ce\xd87\x9b\xb0\x90\x94!\xfa\xdb\x04\xecG\xabW\xcfM?\x920Z\xce?\xac\x9b*\xdf\x85\xb9\x8a\xd7Aa\x08\x0cd.\xc3S\xf2\x08#\x91\x95z\x97\xc3\x1bo\xb5\xecF\xf1\xa5;\xe8\xf5\x06C\x9c?\xe6q\xabAsZ7\xbb\xeb\x18$L(2E>\xc0\xa5\xe2\xae0\xf4\xa0\x1d\xe5s\xe7\xc3\x13\x98\xd3?l\xee\x04.Dc\x1fS\x90\x1b\xb07/\xa6\x96\xc1\xe7)\xea]\xe9\x94'y\x8cb\x9e\xde\xa9X\x13\x06\xb0\x99\\\x04t\x8f\xdd\xde\xeaD\xa7\x11x\xecI!`\x95\xe5\x022\x13(\x06o\xc9\x0d&\xe0#\xe3`\xcaB$\xe5\x97~\x83\xe6D>\xea\xe2\x7f\xb9\xd1Y\x8a\x1f2p)\x05\x8d\x92(I\xd1s\x87\xdd\xe8\x12?\xdbmz\xac\xd8\xe5\xc8p\n\xb6\xfc\xc8\xcd\x8f\x9a\xb552Y\xaex\x8d\xca\xe8lz<\xc0\x89\xbd\xa0,\x9en/A\xa8\x18\x85\xc7gmt3\x92$S\x1c\x80\xa8\xacvf>6\xf1\xee\\\x86\x97s\x0e\xd5\x0e\xe1\x84;\x10\x04\xda\xb8\xac\xdc+\xeb\xda\x0e\x1c\x1e}TS[\xbb-\xd7\xa7\xdd)\xb8\xdbv\xd9\xd1\xca\xe0!7\x8bj\x0c~\x9b\xb4\xac}\xf9=\xbc[\x04Td\xe8\xf7\nA\xae\xbf[|\xe7`C\xbf[\xef\x90\x15\xe12\xaa%pv\xbeD\x07\x83\xe6\x89v!\xa6x\xc5\xd6\xfbe8\xa3R*\x9e\x9f\xf8A\x96.\x80\xfc\x90\x16\xdez\xd8\xefu\xbb\x8c\x87\xb0\x0d\x8b\xe1\xc6\x0cq\xa5\x9e\xcd\x0c\x99\x06\x8f{\xc16\x08\xe3\xbe?\xc5\x89\xfb\xd2\x85V\x1f\xbd\xe3\\\xd1\x94@\x0e\xa7\xdc\xbfM\x1aw\x0bf\x8f\xb4 g\xf7|HO\xb9\x83\x10\x9f`\x87\xf3\xb1\x0bo&\x13\x01zj\xf1 !?\x9b\x91\xd0'@\xc24\xbe1\x8a\xd9\xcc\xc7\xacDd\x88\x96\x96\n\x12\xd0\xf28\x8e\xd0\x83\x13Kd$p\x07\xc5\x89\xb4\xfb6\x08g0\x02K\xf4\xc0r\x8b\xcd\x841\xc6\x9a\x04\xca\x9f6\xd3\xa8\\\xc4D\x8c\xd6\xef\x80*\xa6\xd3!\xee\xee\x16\x11\xc2\x1b\x04\x90\xdc\x7fBW\x8f\xb4a\xe8\xf8M\x1a\x18\x8f\x1f+\x99i\x87R\xe5\x03.\x01m\xc2-0\x12m\xc41~\xb3\x17\x86\xb0\xcb\xa4\xa4@D\xb1\xc58\\t\x19Z-k\xf3Z\xd8\x1b\x16\x0b6 \x0b\x94\x91N\xf20\x8a\x03\x9b4\xa7\xbc\x98\x8b\x01\x92\x14p00\xb2~\x89r<\xc9\xb3\xf8\xd1\xd1\xc7\xba\x83pi\x97m\xd2\xbdBL\xcc\xc2\xfc\x04K\xc2\x99\xd0 \xf0\x83\xe8\xbb ]\x04!xpE\xe2\x0b/\x0dVt\xe5\xab\n\x1eS\xa8#.\xb9I\xe3m\x9d1)._M\x96D\xe0T\x9c\x80\xbdK\xa1\xf3\xe0\x07H~\x10\x06r\xed/\xbd\x15C\xc0\x95\x17\xbfM\xac<\x0eqe.X\x16\x85\n\xdd\xcd\x15;\xf2\x195\xf4*:\x9dJ\x9bI\xe6/JGn\xe6\xa5I1\xaf\x8c>\x8c\xb4o6\xef\xeaB7\xaf\xe7*WJ\x15\xba\x02\xe3L\xcd\x97\xd1;J.\xe9v\x8d\xe2R\xff\xcb\xab\xa6#\x7f\xc8\xc8Z\x17\xfa\xf60\x99u\xfd\x1c\x0d\xd1m#F]\xe6)\x08\"\x1a\xc3PU\x83\x85\x8eT\"W8\x85STs\x0d\xe9.\xe5\\\xa2(Ea\xe2\xa9\xee\xb1z~\x16\xe5\x99\xb6-\x0bs\xcd\x9a\xb4\xea\xa8Y\x0bQ\xb3\xf6\x18=\xc1k\x89\xf7\x0f\xcd\xc4[C\x96\x8f\x18Y\x0e\xefA\x96\xcd\x82\x8c\x9e4\x87\xc0K\xc8\xe4\xd9\xd0\x81\x12fV\xb1Zl\xdc\x90o\\v\xd4l\xbd\xb0C\x07\x93\xc76\xd7\xa8\xe5\xb0\xd2\xb6\xc9u \xc5~,\x0f!\x8cf\x04VYR\xe0\x9b\x97\xc2\x92xI\x8a\xaa{I\xcbVb\xd3\xf5\xbb\xa9a\x81\x7fJ\xd2\x86i\xf8\xc2U~I\xf2\xc6\x85K\x17V.\x9c\xbbp\xe1\xc2kf\x8c\xd20\xed7\x06f\xfe}\x033\x97\x16{\x19$) I~Vb\xbfl+Zc\xd4\xd9T\xe8j\xa1\x88\x1e\x9d\xcf\x82\x00pyE\xfc\xcc%\x15\x06@\xb5'\x8c\xd0\x19b]\xc8eLA\x85A\xeb\x1f=R\x04Q\xfbM.\xaf\x96\xc578e\x93\x00\xc3\xca!\x93\x9f:\xd0\\W}\xf8\x84+\xc2>E\x97x\x07\x0d\x1e\xf4\x85O\x0d\xde\x9a'L\x82\xba\xbd\xc5\xcdx\xe2\x94\xbbwZ\xf4\xee\x86\xc9c\xdfJ'a\x88\xd5\xeb\xd6\x8f\x07j\x80\x11\xbc\xa1\x9d\x8cr\x0b\xce\xa7\xf4\xc1\x9ao*z\xea\xbb\x80\x11\xf8\xc5\xa4\xcfs\x92F\xf0<\xd6\xa6\x9c\xecu\x99\xd5\x94\xec\x88\xf9L\xc1)\xbf:\x8eg\xaf\xd789\xdb\xd8X\xdcB\xc9\x9b\x98Og\xc0=w\xcc'4\xe0^;_\xd5\x8475=\xcb\x91T\xfb\xf4\xaa\xf6\xe9M\xed\xd3K\xc3\x06\x04\xeeG\xa3\x0b\"|\x87\xf3\xe3\x92\xab\xac7;?z\xc6$D\x18\x84\xa8\xa9\x1e.\xd6D\xd2\xa1-\xab\xc8\xb4\x07\xecP\x80\x07\x9a\xfd#\xfe\xfd\xf6\x96\xd2\xf2\xb8\xf9\n%\xd2\xc1\xd0\xc5[\xaf\xec\x08h\xd4A\xc9\xefI\x07<\xadL-\x7fX\xaa\xdf\xa6\x91:'pm{t\x9f\x1b\x8a6\xc8W\xf2\x87\xf6p\x9f\xf9[x\x0e\x9c\x99\x1a\xafH\xca\xb9\xc4\xe8Q\x11\xfe\xffc\xee[\xbb\xdb\xb6\x95E\xbf\xf7W\x8cx{\x1c2\x92\x15I~$Qlk\xa5i\xd2z7ur\x9a\xa4\xfbt\xcbj\x16-A6\x1b\x89T\xf9\x88\xed\xbd\xdd\xf3\xed\xfe\xb1\xfb\xcb\xee\xc2\x0c\x00\x82$@\xd2N\xd2\xd6k\xb5\xa1@\x10\xcf\xc1`\xde\x93\xb2d\xe3\xcf\xb5\xdbG\x97\xad\x82\xbf\xe4%\x9c\x82\xfe\xc0\xae\xb7\xd1w\x02\x12\xb6\xf1c\xa4\xc6\x149}\xb6\x8a\xe6\x1f\xa4\xd4\x9a__\xc8l\xb9\xa8kX\xf5\xf2\xa88Z\xc4\x9b\x8f\x02K\x8b\xa2\xb5@r\x02\xb8\x91\xf8\xe4\xff.\xd4\xf9\xc5/$\xc2\xaf_\x97\x86\x9c\xcc\xf2\x0f\x01c\xad\xb9g\xd1\xd5\x93\x14\xee\x9d9\x07\x96\xfa\xee\xf8\x9f\xd2\x13aD\xd8\x98\xf9\x0b~\xf1\x07kN\xcd\x04\xa9\x12\xe8o\xfc ~\x02>\xcc\xa3U\x14\xf2\x95^\x07IR \x9bW\xfe3\xbbKC\x1d\xb3\xa2\xff}\xaey\x9a\xe6X\xdcz\x12_\xf0 \xae\xb3U\x1a\xe0\xd9\xf9\xc0\xaea\xed_\x830q\xd6W\x05\xd5\x1b\xf6\xb9\x19\xdf\x88\x19\xef\x13\xcb\xe5\xf3\x0b\xf2\xd3\x80Mp\xed\xe42yN\xedi08\xc8Y\xcb \x9cG\xeb\x0d\xea_\xd8\x95ec\xf9l\x91\xceS{\xfb\x04\xa2\x18\x96\xd1j\x15]\xb2\x05\x9c]\x83\x8fj\xd0\xd4?\xcbV\xa8\xeca\xebMz\x8d\xca\x0d\"\xfcr\x9c\xa8\xbc\xa6c\xf3\xc6P(\x11\x0dEYeP\xae\xa4\x037DZ\x04T\xca\xa7\xab\x1f+A\x06hB\xb1s\xbc\xd9+k{-b\xd9\x1b\x97\xb7(Hk\xc6\x88\x9e\x81\xa8Qr3\xbfVnV\x80;\x9b\x17c\x93\xe8\xac\xf2Q\x15\xf2\xc4\xd1AH\xb3\x01\xda\xba j\xab\x9c\xae\\\xd4&\xf1d\x81~\xc5\x16\n\xfd\xfe\x81\xc4O\x0f\xce\xbc*\x01d\xa3~\xcaZ]\xccY\xb3\xd4\x93\x88u,\xf9\xc6\x17\xf5\x84\xd2\xc7FB\xe9\xda\xe0\xad\x04\x02H\x859\xa8\xbbi\x86\x05\xd2\x89=\xde\xe9 98IbM\xe9\xc9k0\x1f\xefs8\"\x82ac\xe5EUmN>\x8f\xf6D\x8f\x03\xea\xf1?M\xfeip7\xb2*\xf6(\xc3T\xd3=- \xabM-a\xa5\x8e\x1a\xf3z\xad\x96W\xe8\x0b\xab\xec+i\xd2\x08v\x17\x05\xd8\xfd\xa8\xc1.\xc7\xb7\n~al\x13\x1b\xc7\xf6\xcb\xe4\"\xa7?\x08?\xc2>9\xc5\x9f\x04\xe1\xf9\x8a\xc1\xefY\xc4\xab\x8a\xbdGZ\xa2n\x96\x86\x83t\x1b6\xc3\xdc\xe9\xe78):\x83a95\xbb\x04\x1e-\xc4t\x9f\xff\xd4`\xe2m\xf3\xa9i1\x9eZ\xc9\x88\xf0]\xf5\xd5\xa0\x8d\x18m\xe0\x95\x87d\x03|\x14c\x8dd\x9b-\xce\xa2\xa9\xab\xcbv*\x1aO\x87~\xfb9TrM\x9f\xfcE9\xd0\x7f\x98\xfa3\xafp\xc1\x1c\xa3\xef\x88>\xc9\x16-Rp\xd1\x910\x83\xe3\x1c\x8b\xcf\xcf\xd2\x08]\x89\x1f*Vf\x17\xc6\xf0hO\xfd\xe4l\xc3\xc0\x83#\xfe\xbf\x16\xba\xb2\x80\x14\xda\x11\x19m\x07\xfc\xbb'\x10lo{\xd8\xfb\xd3\xb6k\xc5\x99\x14\x0c\x1b\x87~5\x07\x07\xb0\xebA\x172\xc5R\xa9\x13x\xc1\xae\xfc\x05\x9b\x07k\x7fU\xef\xd2\xa4\xff\xe9K\xf9\x9b\x1b\x95\xe0\xc5N\xb7\xd0ZJ,\xf0!\x8c.C\x10\x11\xd3\x94\xcc\xac\xa6\xeb\xea\xc9\xa8\xc7\xa4~\x8eI\xe9\xe8\xdb0i\xb5\xe1/\x84I\x17Qv\xd6\x06\x93\x96\x06\xd3\x82\x96\xb8\x0dj5\x8f\xc2\x88Z51NGC\xb26\x0c+\x0c\\\xcdXu\x97d\x18\xcd\x8a\xef6X\xd5\xd2H+s'2\x81{#\xac\xdf:\xcf\xdd\x98\xa3\xcd6-V\x07s+\x93\xa7U\xe0'\xb7\xb2x2\x18?\xf6\x8a\xa6N\x9aH\xbd\x14\x8eE7\x84\xbc\x97\x85J\x0c\xb0\x10\xe3(\x19\xc5iw\x92.\xa6\x0fge\xddU\x95\\\xe5`rWS\x14\x94\xba.\xa5\xbc\x95\xdf\x94v\xe1\x9c]\xd1\xcd\xc1\xeb\x8d\xbbl\x06,\xbe\"\xcf\xdd%\xb9}\x12\x92F\xa6w\xe7Q\xfe\xbc;\xd2\xcaw\xf2g)\xe8\xc3\x1f\xfbz\xa5\xc7\xda\xb3Vg\xe7\xa1V_+\x7fL\xa1\x1e\x96\xb5P\x8e7\xce\xbe\xd6\xbd\x10\x9b-IF\xff\xa6\xf9\x18 \xee\xec\xe6\x86\xec\xfb8\x98\xb78X\xcd\xe4J\x80\xbe\xe4ErWX\xad\x8b\x03\xb6\xac\xa5B\x84u\xc6\xb2\x89b\xb8\xe3\x14k\x98g-\x8f\xef\xce^\xdbA\xd4\x0f\x00}eZ\xf4\xd9$\x95h\xbcj\xf29.\x9b\xa5\x8f\xbc\xcdK\xac\xd8l\x05\xe1+1\x8bT\xd3h\xc6gsU@\"\x13\xed\xe6DdP\x14\xdc\x1c\xda\xb3t\xe9\x7f\x99\xc6\xbf\xdfYZ%\xfej\xe3\xb6\xcb?\xbb\xc0\x04\x8af\xf8\xc2\xff\x83\x8c\x078~\xd2wB\xe8\xaf\x0b27Kr\x01\xf9w\x179\x8e\xb9\x14\x15`D\xcb\x10\xfe\xec\x0c%-#\xc6\xbb\x0d\xbeWw8\xbd\x1e\\ \xcc\xe7\x16k\x08C3\xcbv4\xb8<\xd8n\xc4\xf2P;\x1d\x85F\xc8%X\xa0\x99\xa2\xc5\xea\xa6*Q!R\xa4'\xad( \xfd\xbd\x16 \x94\x07\xd0\x96\xde,\xca\xd8\xc0\x998(\x9b\xaa\xa9\xab\x95\x08\xcdnn\x07\x96\xdf\xd5\xc9E\x94\xad\x16h\xabs\xe1\x7fd\xe0\x87\xd7\xd2\xf2\x1a\x95\xb0\xd2\xdf\xbb\xb5\xba[\xe9\x15s\xd1\xd9\x8fjVh\xe4)l\xe1h\xf5\x91\xb9\xda\xd4\xeb\xf1\x84\x06\x13\xef\xfbs\x19;OwM\x93\xfb\xfc\x9e4\xccw\xdc\x82\xcf{~\x05\xb2\xcf=!\xae7\x8c\xbaFh\xbf\xb9\x01g\xe9\xafVg\xfe\xfc\x833\xeb\xc9\xed\x99\x80X\xb7\xda\xeaS\xac=+\xccT\xac\xd1\xd6\x16\xbc\xa7O\xa8\x18\x1f\xcd\xa1d\x10\xa2\xf1=\xdf\xfe\xce\x01\xc6\xe0\xc4\x95\xec\xc2\xbd#H\xfds\xd4< \x98?\x13\xbe\x13\xa2uN+\xf6\xf0 `i\x9a\x97\xdeC\xff\x9b\xca.\x93\xc3{\xd3N\xdeq\xebr#4\xa1'\x13\xdd\xa31\xd9\x82!\xbfS\x9a\xa1s\x94+\xe1\xd0\xcbI\xf7\x91\"~\x94W,\x7fdI(\xd5\xc2\x8a\x7f\xbe\x8a\x12&\xcc\xf8K'\x99_\xe8\x95\x89\xdf\xdc\xc0\xeb\xafr\xf8R\x8f\xcaw\xe1\x87v\x9e\x85\x1a\xfa\xaf\x00\xa9\xc9\xc3P\x90~Z\x18!\xe1KP\x0d#\x94\xf6W\xec\xdc\x9f_\xf7\x94K\x8f\xc8l\xa6m\x18\x99=I\xb1U\x0b\x97E\xdc\xf1\"\x9f\xd1\xfcU\x0f:nIs4\x10tw\x07-z\xcc\xd20\x9ck\x06\xed\x9d\x13m|d\xc1\xdf\xadMC5\xbc\xect\xd63\xfa\xba\x15\xd8=\x19\x0f\x05\x0e\xc8\x8d[\xb8\x07\xa9xH\xc8k\"kiR\x1b\xeb\xe6\xcc!PKNCd\x06\xf8L\xd1\x19\xa0\xa8\xa1\xad\xcd\xb1\xd4\xa8\xa3m3\x04;\xd26\xf8hR\xfc\x05\xfbUPC\xdd[gZ\x1b\xd2\x01\xe4\xb2~1\xc0\xe2\x7f\xb1t\xe7\xae\x81\xa8\x16\x04\x9d6&\xd2;\x8b\xeb\xed'\xe1\xe1\xf7\xd34\x9cI\x19\x1b\xc7\xa7\xaf\x85\xc4\x81\xf0\xa9\x12\x82\xe5`Z\x90<|e\xef\xbc\x88\x0f\x06\x1ak$\xce{\xee\x9e_\x8f(\xdaV\xa4x\x0e\xed+\x8f\xbcbD\x17\x11\xe1A\x1f7_\x90\xccpV\x13\x14\xd0\xad\xfd\xb8\x12\xb7\xe5\xe7\x9c\xa6\x17\xd3D;\x8d\x8df\x9cV\\\x98*\x92\xde\xda\x82sr\xf0,\xee}T\xdc{P\xa18\xc2(\xdc~\xfa\xe6\xd9\xf1\xb1\x16O&\x01?f\x10\x84)\x8b71C\xc7\x87\x04\xd9-\x15tNnmR \x1b\xd0\x82\x9f\x9d\xc0\xee~\xf3\"{\x82\x14hXa\xad\x82\xe6I\xbd\xadc\xc9\xaa<4\x8aQ\x16*\xc03\xf7\xe0(\xecG\xede\xfc\x9dk\x8c\xc2XL\n\xc3d\x86(~G\x0e$\xbd\xa0\xe2\xda\xc9\x901\xa5\x05\xc8\xa7\x80K b\xc9\xd4Wrs\xf3\x82\x1e\xec\xef\x8d\x1e\x8aX\xa9\xfaG\x03Y\x93\x97\x8b<\xfa^\x19\xf7Q\xb2\x04\n\xc5\xd9\xa8YK/\x82\x84\xb6\x100\xfd\x01\xfe\x96\xd131!\x92\xfa!H\x1eQ'\x91\xf1\xd8\x99|\xbc\xb9A\x9e\x9b\xbf\xcc\x03Y\x1eb\xda*\xf9\xab\xd8\x04Q\"XE<\xde\xdc\x90\xd5\x02\x7f\x8b\x01\xaa\xf8;\x19\xa9J\xbdQ\xe4\x1a~)\x7f\x14\xdb.01|j\xf9\x981\nx\xb0b\x8bcQG|\"\xe8wK\xe5\xb7\xf4V\x0d\x1d\xf7.\x07\x06Q\xae\xc9\"\x06j\xb4(\x8e\xd0\x7fJ\x89\x84^\xa6\x1b\x02a\xa1:\x9fH_\x14\x11-m\xa7\x81\x08\x0c\xc5^\"$\x0d\x1c\x158(\xac\x1e\xd3P\xbb\x80<\x08\xf5A\x90\x9bFX8\xb7&\x92\xf3\x89^\xe7 \x0f\xf8\xb8\x0d\xc3'\x1e\xfc\xe0Z<\x8c\xc3|n\xb5\x07\xf4k\x9b8Z\x13E\xc3!\x9d\xe3rW\xc8G\xcb\x96\x1c\xcc-B\xf9\x88\xf3\xfc$\x91aFZH\xac<\x04[\x0c\x07\x10\xf0\x7f(\x04\x1bs\xa3i<\xab\xc7-\xdf\x1b\x0f\x9c<\x99\xdf\x99\xf6/XJ\xaa&T\xc9\xaf\xaa\xe7\x95\xd7\x1a\x8a-\x95\xb5\xe4\xb2N\x07\x06\x9f\x82<\x81C\xe0\xe6\x8aC\xa5\xa1W\x184\x085\xec\xda\x83\xb3,\x85e\x94\xf1[.\x8a\xd9\xad\x128\xe4I\x0c\xbe\xeeU\x93\x1e|\xdf\xb3\xe6+h\xd2B\xb4\xd8S\x04\x99\xb8\xcf\xaeR\x16.\xdc\xea\xf2\xd1\xa1\x1eCV\x9c\x0f\xef\xac\xb4\x1d\x12\xf8\xee\xd8\xd8W\xdaOc\x02\x87Z\xcc,f\xf3\xfd]gS\x8d\x0f\xfc\xe9\xe9\nL\xc1D\x03\xb7\x10z\xb1r\x97r<&.\x12\x89e\xcf\xb2\xe5\x92Pw\x15e\x86E\x94\x19\x8b\x9f\xf3h\x95\xad\xc3B\xa0\xd3\x1c\xee\x02-\xa3\xc19K\xdf\x84\xc1f\xc3\xd2\xa6\x05\xae\x98\xabW\xcfbG\x1b\xae\xa7\x0b\x0dL\xbc7\x88\x00\xf0\xbb\x1a\xc5\xf0pOD\xc0\x91\xf1o\xf4\xd9\n\xeb\x00~\x9do\xd3yvN\x07\xa7\xf1i\xf8\xff\xfe\xaf\x9eU\xc0\xe9\x07\xe1\x82]\xbdZ\xba\xdah\x10\x8b?M\xdd\x80\xf4\x17\x96\x90U\x01lS\xf0\xc0\xc2\"oc\xbf\x0c\x1e\xc0\x88(\x0f3\xb3\x86\xe3\x86~\xbf\x0f8\xf8\xee!\xec\x99\xb9\x946\xeef\xb8Dz\x1e\xbd\xd2Jd\x9c\xec\xd3\xa6\x97\x93Ww^\x9a\xcc\xba,n&\xd0\xf8vieZ\xacJ\xa4\xafJ\xc6\xd7\xf7\x13VE@\x94/\xd7CL\x80\xa8\xba\x80\\\x11sSJ@1\x94\xe0\xbc|4\x00\xefR\xc0\xfcn\xb9\x16t\x0d{\xde\xd5\xee\x8b.8\xbf::\x82\xd2\xcf\x90L\x19\xd86\x1b\xb5\xe3\x18\xef\xf8\xfc\xe8s\x82\x15)\x88{A($\x8f\xea\x1dFK\xbe\x87\xaarN\xb1\xf8)q0\x0e\xc6\xa3W\x98\x00\xf9\xba.\x9f\x9b\xc0\x04\xf9{Q@*\x10\xd2M0\xb9\xa096p\x85\x88\x8az\x19\xd3\xaa1\xde\xad\x11M+L\xf3\x89Hs\xa0])z\xe3\xfc2\x8e]C4\x9c$\x8d+\xd9\xfd>\x04\xe1b\x9c\xabs\x0b\xef\x94\xf7\xd7lu\xdb\xc6\xcd#\xaf\xdb\x17\x91\xe7\xf1Mz\xbdbcp\xd4z9\x7f\xf5q?\x8b\xa2?\xf5\xb8\x1bL\xa7Z\x1f\xf7\xc2\xb1N\xe3\x8c\xe9\xc7\xf8m\xf9\xf7O\xef\x9e\xcbc\xcd\x0b\xf6\xf4\x8f\x97\xfe*)\xd4~Q)x\xfa\xf2\xcd\xf3\xbb\xa2\x85\xbas|\x9b\x81\x7fN\xfc\xe1LE&\x81o\xa2h\xc5\xfcpF}T\xf2\xd2I\nT\xa8\xe1k\xe7^\x8bmL8\xc1\x9a\x82\\\xd2\xad0\x91\x0b4\x06\xb1KmN\xb1 E\xb4\xea\x8b\x16{,\xf7\xbbM_&\x8c\xd1\xae/9\xaf\x17\x96y\xfd\x1d\x10\x88%3\xe2m\xb3\x9aV\xf2\xa6\xed\xe5\xe344\x94\xb5o\xe8\xa1\xd6\x90|*c\xba\xc0\x84\xe9\x820\xfd; :\x12\xd7\xe8\xb2k#\xe0\x04v\x87zS\xc3\xca\"\x17\xee\xe4FU\xe8\x1a_\xe7\xbfD3\xeed\\\xbc\xc7\xf3\x1e\xa8\xf2\xe9i\xdf\x9d\x8c\x83pys\xcc\xff;y\xe1\xddPQ\xe8\x877'\xfe\xc9\xcd\xc9\xd3\x13\xcf\xfbZ7\xb9\xc7\x80\xfc\x98\xadW\xeb\x9c=\xb0K \x8d\xbc\xf3r\x15\xf9_\x84{\xd6\x85\xdb\xa4\x15\xe1\x88\xd6\xedD\x82\x80\xf1t\xda'\x9d\xeaf{\xb3\xcfN\xd2\x18#\xc1\xc8\x11\xc2!H2BX\x1eW\xa8\x91~\x1a\xbd\x8c.\xe5\x89\xe6\xa4\x04L\xf8=>\x06\x11\xfcw:\xeb\x81\xd3\xdd\xceu\xe7\x0c\xe9\x95#q\xc1\xb8d\xf2\xa7h\x91\x1e\xf0\x9a\xcb\x9c\xf4\x10\xa6G0\x11wY\xff\xf5\xab7\xc7o\x8f\x7f~\xfe\xfe\xf8\xe4\xc5\xf1\xc9\xf1\xdb_`,_\x9d<\xff\xeei\xf9\x95\xd3\x0f\xfd0o\xee\xc4?\x811\xb0\"\x85!0\x9b\xcb\xeeFf\x04E2\xe3\x05\x07\x9cZBCX\xe7\xc5Dh\x04\xb7\xe8\x8aIB#\xe6\x9f\xdb \x8d\x10\xees\xb2y\x8c\x0f\xda\xa8\xd8\xdf\x89\xd4p\x89\xd6\xe8\x1c\x92\x1b\x86\x81\xd4hKk\x14\xf0\xa4\x0d\xe2C\xb3l(HN\xfc\x13\xde\x17$\x97A:\xbf\x00\xd7*;\x98\xfb \xd3\xe5\x90cc-\xd0\x16\x07\x81\xcf\xcc\x1dQcJ\x8a\xdb\xa6\xb1\x93\xa7'\xb5\x8d)1m\xab\xc6\xfc\x13\x83<6\xf7x\xb6\x1e7!\xf4\xfb\x12\xab\xc5O\xfeg[\xad\xe3\x93\x17\x9fo\xb5\x8e\xc3e\x9b\xd5\xaab\xa0/\xb7Z\xdb\x9fu\xb9\xb6?\xebzm7.\x98\xe9\xb4\xe7\x9f\x0f\xfa\x03\xc3X\xb4{\xa9H\xf6\xf6 S\xc9\xbc&\x10\xaak\xcaa\x0e\xbfP(\x02fX\x87L\xfe,]C\x99\xfc\n*\xe4\x97\xa2\x8e\xb4\xffy\xdb\xae\xed\xc7\xd7N#A\xd7\xd8\xe2\xa4\xf4\x8b\x93no\xd3\xd9\xcd\x14NO\xd3Y\xd7+\xbc\x1c\xeb\xbd\x17~\x10}H%\xf7=\"\x10\xb1\x85\xfb\xee\xbfn\\N\x8by\xe5n\n\xdf{\x13\xcf\x9b\x14(\xb9V\xea\xdc4X\xb3$\xf5\xd7V+\x96\xcfN\xac\xe5\xe1\xca\x83>\xbbbsA\xb3\xa9\xd2H\x96~\x01r\xcd\x10\x07\xc5\xa23\xd9\x08\xb7L\xf3\xb5\xa7\xf47H\x81\xa9yx\x8a(\xcb'\xa1\xe7'\xf74\xf3\xee\xe7q\x1c\xc5\xae\xf3\xad\x9f2\xe5K\xcbx\x99)(S \xf2\x89v\xd9t8#\xda\xa7\xcb\xa6\xa3\x19y+e\xf4sg\xd6\x83\x0e\x9b\xee\xcer\xf3Wv \xbc\x03\x97\xff\xaf\xff\xee\xed3W,\x83\xc9\xff.\x10\xe1)\xba\xbc \x8aN\xd1e\xd3\xbd\x19\xc5\xa5\xe8\xb2\xe9\xfe\xac\x07l\xfapfC\xc2(p\xc5\x80\xb7\xd3\x873A\x94\x0ez\xb0\xe3=\x81U\xeeK\xb9\xf3\xc4\x83\x15\x1a\xf6\x99\x90\x14\x88\xa8\xd1\xddU\x15\xfd\xd9\xc0\x8bM\x1f\xcfp\xe1\xf9\x9e\xed\xb3]\xb8\x0f\xee\xfe\x00\xee\xe3j\x0df\xd0\x85\xae\xcb\xa6\xc3\xe1\x8c\x83\xd9@\x8a\x00qC\xf4/\xb77\x9e\x88\xcb`]6\x0dzV\x1eFS\xdf\xda\x82e?a\xe9\xdb`\xcd\xdce\xff\\\x93?\n\x0d\xda\xa5\x0b\xce\xd3o\x9e}\xfb\xfc\xc5w\xdf\x1f\xff\xe3\x87\x97?\x9e\xbcz\xfd\xdf?\xbdy\xfb\xee\xe7\x7f\xfe\xcf/\xff\xf2\xcf\xe6\x0b\xb6<\xbf\x08~\xfb\xb0Z\x87\xd1\xe6\xf78I\xb3\x8f\x97W\xd7\xff\x1e\x0cG;\xbb{\xfb\x0f\x1f=\xee>8<\x0dOc\xe7\x96\xec; x\xbe\xc4\x86\xddY\xfbm\xc1\xd3A\xa3b\x9cc\xc7\xc8\xa2\x1e\n)\xf2_H\x1eCa\x9d\x8e\xa8\xe3\"b\xcfr3vi\xbcN1\x00a\x7f\xb7Qk\xc4\xe0\x00\x06\xad4?(\x13\xdf7\xbe\xb6\xe2\xc1\x18\xfe\x0b\x1e\xa1\xf0\xb9\x08\xf6\x9f|q\x06E\xe9\xc5\xf44>\x0d\x0fgB\x86a_\xf4\xa0v[|\x8c\xffc|\x95\xd8\xb7{n\xd1\x07)\xff\xee\xc1\x13\xe0\xab\x9c=\x01\xd6\xedz\xc0\xe0\xbf\xd0\n\x8c\xe4%\xa4\xce\x99\x8b\xfc\x10pt\x04\xc3}\xd8\x82\xd1\xde\x9e\xd7\x03\xbd\xf8Q\xb9t\xb4\xb7\x07[\x90p\xa4\x9f`\x12\x90\x83\x03\xd8\x87\x1b\xf0\x158\x04\x12\x1c\x98\xe9r\x15[4\x00\x19\x087\xc3\x81\xdd\x87}T\xd1|\xd2\x90`\x0c\xc3GJ\xd0Slk`lk$J\xf1S\xe1q\xc8\x97F\xaf\xb3\xab\xbe\x8c1\xe9\xc62\x8e\xd6\xea\xc1\x9d#O\x80\xe8\x1e\x1f\xe7u w[\xa9\x08\x06\xf6\xe0,\x0e!\xd0\xf6Z\x93\xb6\x00\x1d\x93s\x8b\x15\xa1X\x80/k\xc45~\x0d\xae\xb1@\xe7N :\xf1\xe4\xfb\xd3\x00\xb7\x8fo\xfa\xfe\x0eR|Z\xe9\xc8T\xba_*\xdc\xdf\x81-@s\x1c>#7\xe0\x10\xfb\xc8\x83.\xa4SfW\xa8\x16\x01t\x87\xf4\x87\x9fyD0\x86Q\x0e\xae\x85v\x06\xa6vv+\x85\x07\x07P\xeeq\x7f\x17\x1b\x1e\xe6\xc0\\h\xb9:\xc0\x83\x83J\xc3\xfb\xbb\xc5\xf6z\x10\x17\x01O\xfd\xfad\x02\xc2\xca\xceVd\x7f\xc58\x93U\x02\xc1*,\xbc%\x89\x16\xd5x2X\x9c9>\xf1\xca\xb7\x19\xf2\x97\x985\x12\x83[o\x03C\x80\xca\xfc\xb8\x91>z\xae\\\x83\xf9\xe1\x0b\x9f\x90 \xd8\xea6\x16\x88|\xa1\xf3)\x9b\xe5I\xc0\x94\xa8\x96\x16|\xe6\x08f\x15E\xb2q\xb3=\x87\x08\x84\x13\x84\x10\xd7\x1b\xf0\x04\xa2Id\xd3j\x08\nY\xdfo\xecZ\xfe\xdd\xc9P\x07i\x9f\xe6>x5a\x81\x90\xa8;1k^\x16\x11\xce\xa2U\xd2\x0e\x058\xc5SyG\xfa\xa6*\x9c\xf8\x93<\x8cZ\x1c\xfa;\x9e\xe1\x8d\x1f\xc4\xc9\xdf\xeb\x10\x0b\x7f\xdd\x9a\x83\x9a\x89\x19=\x8dc\xff\xda\xf5\xa5\xdb\xa3R\xf4\xf0\x13\xec\xdf\xed\x04\xfbx\x82\xcd'7h}r\x03\xf4\xe1G\x93!\x0d\xe1~`\xd7 \xff\xba\xec\xd6ok%\x9b\xb2\x19Ge\xd1t\xc0o\x19\xfcw6\xfb\xd3\xa1\xde\xb2\x8f&\x9a\xfac9\xd4\x99\xf0\x06\xb6\xeccT\xd8\xc7\xcc\xb8\x8f\x99m\x1f\xf9ne\xb8[Ae\x89{\x10\x89\xb5\x0b\xc4\xda\x05\xb8vV\"&\xfa\xeb\x0fp\xf1\xd6\xbe\xe51N\x98Uun\xf6)\xfcrg\xb8\xf6\x82\x0dB\xb0\xc4\xfe\xd2\xee\xb1\xb0'L\x10\x15\xa2\x0d\xa7lV{\\>/\xc4\xdb\xf0\xfc\xdf\xcd\x8f\xf2\xb7\xe4A\x16.\xd82\x08\xd9\xe2\x13%/5\xcbp\xfbE\xf5*\x19\xe6o\xcb\xcf}\x8c\x82\x85\x8c(V\xd7\xbb\x89\x93\xab\x13\xfa\xfd\xcd\xbc\xa1\x7fK\x1e\xc4\xec\x9c]}\x11U\xca-\xe4f\x01F\xa6\xc1zm.'\xe5Mg\xa6\xb19\nxp\xfa\xc0\x9d\x9e\x07\xeb\xd9}\xef\xeb\x07R\xb3a\xae\x1e\x1bb\x0c\x80\x18\x94\xf3@\x8a\xdd\x07V%\x02i:\xa4\x05o8\x1d\"\x1b&\xd5\x07G\x9c%mq]\xf3\x9e\xd0\x9aw\xcar\x03\xa0\xb8`\x0b\x947Si\xe5K\xdf\xc1\x7f\xce\x8a\xcbS\xa2-:\xa9\xdf\xca\xab[0\"\xea\x81e\xc5P\x93\x95kFY\xaf\xcc\xc7|\"\x92PT\x1au\xd0\xd6\x14\xe6\xb6\xf8\xa4vC\xf8Zu!\xed'Q\x16\xcf\x19ty\x81ua\xd3\xfe\xf9*:\xf3WB\xe7\xd7=\x04\xe7\x9cB\xf5\xe5\xa9\xe7\xf3Wkz\x15\x9c\x87Q\xcc\x9e\xf9\x89\xfe.\xe0\xef\xd8\x97BfO\xb4J\xea~\xd1\xa21]\x06\xe1\"\xbaT@A?\xfb,\xd9\xc4\xc1\xda/\x19\x06\x06\x8d\x98\xd1\xa8N\xf8-y \x07\xff\x17\xe3\xc6\xaa\xbaF\xfe)\x18p\x11\x06\xf8\xe6{\x16\x11!\xc8\xf48}4\x0e\xe3g\xa1\x9eM\x8f\xfd\xf0\x9c\x8dkyo[TQq8^\xc7\xd1y\xec\xaf\xe9P\x84\x18\xfb\x8e\xef\x98\x0c-v\x16-\xae\xb58<\xce\xf3+\x0e\xf9I\x10\x85oR?ek\x16\xa6\x8eVu:\x98\xa9&\\\xe7i\x1cG\x97/\xc4\n\xe7_\x96?`\xea\x0d}\x8bN\xcf\xb7\xfd\xca\xc0\xe6\xebZ\xb1\xba5hD\xd4\x9f\x84\x8eEt\x9c\xe6\xcd\x0f\xb4\x8d\x0f\xeb6\xbe~\xd3\xff\xb0`s\x9b\xc3\x0b\xdej\n\n\x88\x81\x95\xdb0\x14\xbfu(\xe0\xbbc\x84\x82\xbc\xaa\x82\x02^\xd7\n\x04\xc5\xfae \xe0\xc0v\xeb\xaf\x0cf\x10/\xfc`\xc5\x16\x90F\xca\x16B!\x0c\xbb6\xc5\xd8\xc1\xc6\x8f\xfdur\x0b\xab\xd0H\x06T\x0d\xfd\xb5 >\xc5\x0di\xec\x0cW\x1c7\xba\x07\xce7\xabh\xfe\xa1t\xde\xec_\xe1\xf2Mp\x0d\xe4\x02\xbaQ\x0fB\x199x\x8a\x96\x0b\xfc>\x9e\x0egt\x01\x0b\x95\x8b^\xdd\x91\x08\x02#F\xe5\x9f\xd2g\xf5&4w\xbe\xa1\xe5\x00\xfe\xd4;Z\xdd\xba\xcat\xed\xcb\xda8X<\x00\xf6F&\x8b1\xf7\xd1N\xa98\xa3\xda\xe5b\xbfN\xdaW\xac\x9a4\xcb\x15J\x08\x0f\x0e\xe1q\xb1h \x870,i\xb3Vp\x08;\xa3\x12(\xf0\xb2\x9db\xd9\x05/\xdb-\x96-x\xd9^\xb1\xec#/{X,\xbb\xe6e\x8f\x8ae\xe7\xbc\xac4\xbe5\x1c\xc2ni,\xefyY\xa9\xdf3^V\xea\xf7\x12\x0ea\xaf\xd4\xc7\x15\x1c\xc2~\xa9\xbd7\xbc\xac4\xb7\xe7\xbc\xac\xd4\xc7S\xbe|%7\xc4W\xbc\xac\xf4\xedo\xbcl\xbfX\xf6\x01\x93\x15\x96*\x1eca\xa9\x97\x1f\xb1\xb04\x95\xb7ph\x80\xf8\xc1\x18\x9c\xd3\xd3\x81\xe1\x1ez\x88o|\xc3\x9bG\xf8\xe6\xcc\xf0\xe61\xbeI\x0do\x86\xd4Qhz5\xc4W\x1fM\xafF\xf8jiz\xb5\x83\xaf\xca\xd4\x1c\xff\x1b\xd1\xd0\xcbBh\xfe\xb7\xb3;\x86{\xa7\xa7\xce=\xc3\xd8\xa9\xaf\xd3Scg\xd4\xdb\x89\xe9\xdd>M\xed\xbdi\xa5F;\xd4\xeaK\xf3Kj\xf5uI\xc6P\xac\xfa\x8c_\xd6\xce\xb5\xd3\x03\xe7\x17\xfe\xbfk\x96\xe0\xb3\xf8\xe7\xf9\x1b\xfe\x0f\xd2\xbc\xce+\xfa\xff \xff?>\xd2S\x84\x8f\xf4\xffWX{\xb9\xc4\x8a\xe2\x9f\x17/\x9c\x99)\x90\xc6\xeb*\x92\xcc\xc5\xb5%\x0d4Y\x9e\x1c\xd6z\x93\xf5(X\xc6ho\xcf#B\xe8\xca\xa1h\xbd\xa3b[\xca\x02\x19\xab\xef\xef\xed\xed\xc8\x0f2\xf1\xc1\xae\xe1\x033\xc9\xde\xa1FvG\x8fw\x1f\xef?\x1c=\xde\xf3\xbcb\xf8\xdby\xb4`\xb0\x89\x82Bz\\\x8av\xb8\xf6\xafe\xda\x85\xf3\x98\xf9)\x8b)\xf3\xc2\xe0\xea\x85\xf83\xd1\x0d8\xd0wb\xa0\x8f\x8a;[\xf8%o\xbc\xd3SG\xc4p\xcc\x836\x0e\xf0\xfbm\xc5'{\xd0\xd5\x987S\xb0\x92\x9f\xaa\x9b\xa5\x85\xac\xc6\x9d\xc9crG2\"\xb6\x0c0\xfd\xa3\x9f^\xf4\xd7\xfe\x95\x8b\xf9\xc1E\xf1\xcd\x0d\x8c<\x19\xda\xfbC\xb09\x0e?\xfa\xab`Ami\xbf\xf58\xdc\xcbUt\xf9\x92}d+\xa4`\x83\xe4$\xe2kz\xee\xa6\xf9\x1bO\xfa\x1fie\xb2\x97\xf4z%\xe2m\x17\xaeU\x1bE]\xcd\xffkH\xdfU\xe0\xdcrw\xfe\xff\xfca\x919\x87\"\xfb \x19iP\xc6\xd5\xb8\xa40`J'C\xce\xff\xd1\x13\x8a\x88:\xa4\x8c\xe4\xf14\x10Z]q\x16\xd84C\x0f\xeeN\x87\xc8\x99,7]\x1d\x91A/\xff\xcc\xc0\xd5r\xd0\xc8\x94\xff\xb6\xd7\x03\x97\x12\xb8\x95B\x90\xf7eV!\xde\x0foOdt\x98\xf7u7\xcb\x1e\xf8\xd4\x99\x8f\nk\xfd\xd5\xd4\xe7\xe3\x0b\xa7\xd9\x0c\x0e\xcb\x91oA\x13p\x17\xe1\xd9\xd5@\x8c\x03\x0e\xb6\x98H\xf3H\x05;Q\x9c\xfe\xc0\xae)\xd5\x8c\xfaQ\x8c\xde\x1e\xb2\x7f\x06\x0b\x19=]\xfd\xba\xb9\x81G2\xf6y\x18\xfd\xc4\x96\xd4\x86x\xd4[\x08\xa3g\xd1z\xe3\xa7?\xf2\xe3Lu\xb4\x02\xbd\xe6<\xe2\xd0\x8d\xeeV\x97b)\xb5\x02\xbd\xe6\x1d\xe2\xc5\xcb\\Du\x9f<\xbf*\x86\x98\xc7\x9cWa\x1e\xa6\xbe\x98I\x9a\x97,2\xfe\x85\x9f2a\xa7@\xa5Y\xc2\x16\xdf\xeao\n\xc1\xfdL8\xe2\xc4x\x98\x10\xe8\xc5i\n\xe0\xb0\x14:\x96y\"w1)\xe6\xb6\x87\x04\xd7|l\x89f\xaa\xf4\x04\"8\x80\xe4\x89\x879\x1a\xd0j]\xa6\xe6\x17n|\x98\xf8?\xf2\xd0\xda\x87\xfcCD\n\x0b\xd1A\x82\xa9\xdd\nox\x97\x14\xc65Bc!z\x0eu!\xc4\xa9\xe0\x03C\x01\xd7\xddC\x08<>\xc4\xeea\xd9\x9dL\x80\xb0_\xbbD/\xebbo\x9bc\xebJty\x1f4\xce\xce\xd4\xf6\xb7U\x14-\x19\x0e\\\xb1\x15\x87>z\x9c\xd76\xf4okC;\xa3b`\xaa\xe1h\x1f\x99\xf7\xfda9\xf2\xd5\xe8\xf1\x1e\xff\xc5)\x94\xdcm\x82\x93$\xe2\xd7\xcd\x0d\xec=\xdc\xd9\xdd-~\xc7/\xe3\x1d\xfe\x8b\x92Q\xa8\xaa\xbc|\xbf\xd4\xf5p\xb8;\x1c\x0ek'\xf2\xc2:\x11\x9cb\xa9\x1fl\x99?\xbe\xcf\x1f\x9f\xe6\x8f\xaf\xf2\xc7\x0f\xf9\xe3\x8f\xf9\xe3e\xfe\xb8\xa8\x1d\xd6;\xeb\xb0\x1e\xfcz\x1a\xde\x07\x19\xc8D\xdfn\xf9\xc4\x0f\xd27\xd5X#\xbfs2\xa7X\xf4\x0b\xe7U\x8aE\xff\xe4\xb4M\xb1\xe8g\xc0\x88\xd2\xd5A\xfeP\x1fg\x9d\x8f#\xd2\xed\x9b:\x86\xe8'sK\xf9\nO:\x85\xfa\xa8\xbe}Kx\xa0R\xce)\xd5\x7f\x8b\xec\xa3\x85\x04%\xa5\x9d\xc4x<\x9do]\xba\x8c|,;\xcb\x1f\xdf\xe4\x8f\x97\xf9\xe3\xfb\xfc\xf1i\xfe\xf8*\x7f\xfc\x90?\xfe\x98?.\xf2\xc7\xeb\xfcq\x9d?n\xf2\xc7\xe3\xfc\xf1*\x7f<\xcf\x1f/\xf2\xc7\x8f\xf9\xe3\xf3\xfc\xf1713{V\x17C\x82\x07\x839\x8a\x97\xbf\xed\x10\x0bb\xf2\x06\x0e[\xff\x13a\x05c\xdd\xef\xd7\x9a\xcdS\xff\xe3m'@\x91\xdd\x9a'\x02\xe2\xe6\x8a\xa7\xa3\x861\x83\xca\xffB\xb3\x9c\xa3\xfa'\xe2'=\x81.\xe7\xf50\x9b=_\x07Q\x01&\xfcqL\xc9\xeb\xa0\x0b\xffp\xe7\xc4L\xa2\xd2\xa2\xb63{\x98K\xc8A1\xb2V\xfa\x83\x83g\xe65A\xfb\xcf\x8d\xd0~\x0f3\x934+\xf7\xe4\x9fb\xa4s\xaa\\p\xcaV\x1aI\xc8LK\x84\xd0\x111h\xfb\x80\x0e;\x9c]\xdb\xdf\x19\"\x11P\x8dO\x1a!WL\xdf\xec\xef\x8c\x06\x90\x07+\xdd\xd9\xdd\xe1\xcc6\n\xa6^\xbb\xc3\xc1\x08\xbd\x96\x19lS\xeb\x949f[|\xd6%\x1e\x8e/\x1b\xa7\xdd\xc6$\xf3z+\xcce\xbb\x87\xd0AJ\xe6\xdf\xfc\xe2\x99@:\x8df0\xa6[\xee\xb5\xd9\x1bM\xff\x93\xba\xd4\xba=\xf3(}\xa8\xb9!\x11\xfc\xc1\xbee\x05\x99n\xb0\xdeDI\x12\x9c\xad\x84\xb7\xfb\x18\x02!\xaa$\x0b\x10\x8a=\xe64\x11v\x7f\xb8\xf5\xfc\xfc\xd7\xf64Rp(\xe95)\x00\xc4\x90k\x06-@\\D&\x85XRF\xf9E\xc8\xcf\x1b%\xd46\x7f7\"|\xa4\xde\xf1Q8]\x07\xb7K\x1e\xcam\xbalNC\xa7v\x86\xdf[\x19a\xdb\x909l\xe4(u{\x88\xb9/\xa9\xf4\x85a,\x8a\xf8\x99\xb2\xf1/E6\xfe{G\x98\xa2_\xd0\xfe1\xf8\xf39\xdb\xa4 \xaa\xde\xf0\x06^QN0\\\x81{M7MqZ\xd3\xd5\x8cff\xbfy\xecW\x8ad\x87cc\x95\xda\x90\xd3\x06\x83,#\x9b\xdf\xa9\x97\x8f\xfeOA\xc6G\x87\xbe\xcc\xb3\x17\xf4\x07r\xc8a\x8f\x8er\xd8\x83\xce\x10C\xdf\xa8\x9f\x03Cj\xe0\x04\x14\x94P\x13\xe5$\xad\n\xf9\xe9,\xed\x01E\x85+r\xb9\xe5\x14\xa6\xbc\xf9y\x0fV=\xb4\xff\xa8\xbaIq\x00Ea\x87z\x85\xbe=\xf2MU\\\x86\x02;W\x93P\n\x8dX\xae$Q\xbbM\"@-al~\x13\x18\xda\xd1\x8a\x1aZ\xd4?.\xa0:\xa5\xee\\g Z\x12\xf8pF\xa9n([y\x9d\x05\"\x14D\xacDB,\n\xfa\xb6\xec \xf1`C\x0fE\xf6\x9c\xd5\x10\x1b\xceW&\xe2@\xedb\x1c$\xa1\xd6\x12\x91%\xc2)'p\x16\xd3h6\xeb \x1cCf\x80>\xe5`\xa7\xff\x08\xee\xf1t\xb58A\x02\xf8\xf1l\xf0\xa7\xdc\x9b\x823\x1e2\xeb\xbb\xac\xb3\x14[\x875\x8b\xc9\xcc'\"r\xd3\x84\x13\xaa\xe2\x11\x1c\xe5\xf1MS-\x1d{?\xf1\x97\xec\xdb\x92\xb5B\x8d\xe5\x1eM1\xee\xb3\xab\x94\x85\x0b\xb7z\x8e\xc8Fs\x0cYq\xb7\xf0\xc6/\x8d\xeeN>?\x02\x90\xc85V\xba\xd6\xf0\x83\xed\xbc\x7f\xcf\x92\x1f\xa3E\xb6\xaa\xc6.\xfd\xe8\xaf\xb2\xa2w\x1f:\x8a\xf5\xcfY\xfa,\n\x97\xc1\xf97\xd7\xefb\x0c\x86\xdb_D\x97\xe1*\xf2\x17T\x0e\x87\"\x1eB>\x80\xdc\xe9h4\x18j;h\xf8\xd4\xae\xf1*\xdb\x16\x18\x15\xbd\xa2\x92;\xe0C]\x86\xfd%K\xe7\x17^\xc5E+\x9f\x93qJmvU\xd51\x92-\xca\x97\xb8\x9fl\xd8\xfc)\xd6L\xccH2\xf7\xe7\x0dJ\xcb\xe1\xa6^?\xbd`\xe8\x07\x17\xe9\xe9F\xe5\x9f:E\x91y\x14\x80\x9aSM\xbe\x8c\xce\x88\xa8.\xed'\xa9\x9ff \x1c\x1d\xc2\xee\x00\xd3[\x04\xfdl\xb3\xf0S\xf62\xf2\x17Ax\xfe\x06\xdf\xbb\xce\x12\x1d\x17i@\x9c\xb3\xb8e\xb5w\xf1\xcaux\xc1<\n\x93h\xc5\xfa\xa8\x14se\xffo\xd9U\xaa\x91'Y\xbc\xe2@\x86\x17\x07R\x89\xcc\xe5[)\xdcQ\x7f\xf1\xd7+\xea\xc1s\xc3~\xca\xae\xca!\xb4\xa1\xaaF\xfb[\x9d\x1f\x1d\xf2\xcfY\xda\x12\xd2R^\xf78t\xcbw\x15L\x80\xc1\x18\xa6l\xf6\xf7\xc2\x12\xa5s\xaf\x08w~\xfa\xf7\x0c^\x84H\x91\xcb\x1b<\xef\x0b&\x10\x83)9\x93\xd4\xc7\x96\x83\x17\x16[F5\x9a;\xdc\x7fT\xea1\x11#\xd9-\xe2!j\x93\x02I\x92\x0b\x06\x07\xbcL\xbe\xf0\xdc\xa0\x07I\xff\xdd\xebo\x9f\xbe}\xfe\xfe\xd9\xab\x93\x17\xc7\xdf\xbd\xe9\xb5\xdc>\x0c\x0e\x8d\x80\xeccp\xd1\x7f\xbc\xf1\\\xd6\xdf\xf8\xd7\xfc\xa8\xeb(\xde3\xf7\xfa\xf6\xd5w\xdf\xbdl\xdb\xab\xbc9U\x07f\xb5/\x02UEt\xa2\x86\x9c\xf0\x97=\xe8\xc4\xc5\xd1\x05\xc2\xf3t\xe6}\xc5\xf7\xf9\xc1\x83\xff\x03\x14J\xe2G\n\xdb\xf4\xee\xa7\x97\x87\xc9\xa5\x7f~\xce\xe2\xed,\xd8\xe6xg\xe1\xaf\xa2\x90m\xa3N$\xed\xff\x96\xf4\xd7\xfe\xe6\xff\x07\x00\x00\xff\xffPK\x07\x08v\xf2\x8aA\x86\xba\x01\x00\xc5\x87\x08\x00PK\x03\x04\x14\x00\x08\x00\x08\x00\x00\x00!(\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00 \x00swagger-ui.cssUT\x05\x00\x01\x80Cm8\xec\xfd{s\xdb8\xb27\x8e\xff\xff\xbc\n=\xbb\x95\x9a\x99\x1dS!EQ\x17\xabf\xeb\xc8\xb1\x93q6r\xc6\xcem\x92\xad\xad)\x8a\x84$\xda\xe0\xe5\x90\xd4\xcdz\xf6\xbd\xff\x8aw\\\x1a $;s\xf6\xf7\xad\xb3\xd9dl\xe2\xd3\x8dFw\x03h4\x00\xb2\x9bl\xed\xe5\x12\xc5\xda\xda;\xfc\x9fN\xe7\xe5\xdf\xfeo'\x08c\xdf\xc6\xde#\xea:I\xd2\xd9\x0c\xbbzW\xef\xfc\xbf\xce\xec\xfac\xe7\x9d\xe7\xa0 A\x9d\xff\xd7Yz\xe9j=\xef:\xa1\xff2@N\x88\xed\xe4%M\xf7\xb7\x97\x8b0H\xb5\x85\xed{x\x7f\x9e\xd8A\xa2%(\xf6\x16\x13'\xc4a|\xfeWs\xde7,\xe3\xdfD\xfd\x9dU\xea\xe3\x03\xf6\x02\xa4\xad\x90\xb7\\\xa5\xe7F\xd7\xb0&\x9a\x9fh)\xda\xa5Z\xe2=\"\xcdv\xef\xd7Izn\xe8\xfa\x8b\x89\xb6E\xf3\x07/\x85K)\xce\xf3\xd0\xdd\x1f|;^z\xc1\xb9N\x95\xd8q\xea9\x18\x9dQ\xcf\x12\xcf\xa5\x9f,\xc20E1\xf5h\x85l\x97y\x14\xd8\x1b\xea\xf7\x049\xa9\x17\x06\x07\xd7K\"l\xef\xcf\xe78t\x1e\xe8\x16\x1b\x87\\K\x99\xf0\xe7=\xe4OJ\x19\xbb\x83!\xf2;\xb4\xa4\x0bo\xe9\xd8Q\xc6\xf0\x8cy\xbc\x8eii}\xdb\x93UZPT\xea0\x90\xdf\xe9\xeb\xd1\x8e\x96+>T\xca\x9d\x87\xbbL\xe4\xdd2\x1f:\x16a\xec\xf3\xca\xfbg\xba\x8f\xd0/1JP\xfa\xaf3\xbe Y\xcf}\x8f)\x01*\xcbf\xb5\x92\xa2(\xfdW=\xb6\xdaQ\x84\xec\xd8\x0e\x1ct^\x14\x01\xd5\x974\xe7\xe7\x9a\x1f>j\x8b\xd0Y'\x9a\x17\x04\xcc\xd4C\x8a\xaa\x04-\x85o\xc1\x16\x95\xf3 \xde\xeb&\x91\xed\xba\xd9l\xa0K\xda\xd0\xb0\x89\xbd`)n@+\xae\x92^\x02,E\xa7\x11\x87p\x9df\xbevnD\xbbr\xec\xed\\\xe4\xc0\x8fh\x972\xb3$\xc2n\x82\xd2C\xd5\xb0\xaei!\xbf\xd3\x1d\xe6\xff\x0e\xb8a\x01\xa3%\n\\h\xda\xac\xe7\x14j\xd6$\x9e\x16\x83a5\xacW\xdd>\xb5\xe7\x18M|{\xa7m=7]\x15\x1d\xa5\xd6\xf2d\xbb\xf2R\xa4\xe5\x83\xf4y\x11y1Sl\xb8\x8cQ\x92\x80\x83\x8f\xd2(Xw\xe1\xbaw\xd9\xeb4\x04\xac\xeb\xac\x90\xf30\x0fwP\x1f\x89m\xd7\x0b\xffu\x92Vd\x0e\x15\xac\xfd9\x8a3\xef-\x19\xe7^\xa9%\x91\x17h@\x17\x14\x10\x85\xeb\x94&:\x94C\x90\xa0\xa1 \xb2cg\x05v\xdfLY\xb9\xc7LJ\x0f\xd3\xc2\xc5\"A\xe9\xb9\xd6cB+\x8aU#K\xf1@s2nX\xdc\x06\x11]\x13\\@\xd2q#[C\xbf\xf00\xd2\xd6\x11\x0em\xb7R\x82pt\xcaG\xed\xcaO\xe9X\x00\xa5\xb6\x87\x13:\nE\xc1Z\x12\x85&k\xdf\xb7\xe3}\x8d\xc0^\x92j^\xca\xf4*\xc7\x0e66\xec\xc4\xb4V\x8b \xed_\xcc$\xe4G\xd8N\x115\x93Rd]\x17\xcd\xd7\xcb\xce\xdf\xa8q! \xb1\xe7v\x96!v\x01\xac\x96\xf7;\x90\xe2\xaf\x8b\xc5\x02\xa2\x98c\xdby\x80)\xd8\xf8\xa7\xa4X\xc6\x9eK\x04Ndx\xdbY\xc7\xf8G\xd7N\xeds\xcf\xb7\x97\xe8e\x14,'Y\xf7\x1d\xf4\xcf\xbc\xcf\x17\xef\xef\xb6\xfa?\xde,\xc3\xe9t:\xbd\xf9\xf0iu\xf5i\x99\xfd\x98\xffs\xfdj\xfau:\x9d^^]\x0e\x07\xef\xb2\x07o~\xbf{\xfd\xe5\xd7\xbb\x8f\xf3\xde7\xdd\xed\xbd\xde\x7f\xbb\xbd\xb8\xf8\xf6f\xec}\xfbp\xf1v\xfe\xe5u\xf0\xed\xf3[\xfc\xf5\xcb\x9d\xe58\x18\xff\x96\x11\xecW\xd1\xe7\xd7+\xfd\xcb\x951{\xef\xdfl\xe6\x1f\xacU\x81\xb7\xfa\xf3\xdf\xa7\xc5\xff.\xb7/\xd1\xaf\x17\xab\xaf\xbd\x14\xbb\xaf.\xbco_\xdch~\xaf{\xc3\xe1\xfa\xe5\xb5w\x11}\xbb\xd4\xbd\xcf\x8f\x9fofW\xc6\xf6\xb6\xf79\xb4?\xad\x06\x8e\xff\xf9#z\xb0>}5\xa3\xf8\xeb#~\xb8\xbe\x1f\xfd|}\xb9\xeb\xbf\x0fV\xa9\xf3\xc6\xc0\xee\x9b\xab%zc$\xf3`6@\x97\xba\xf7\xf5\xcb\xdd\xe6\xab\xffi\x90\xfd>\xff\xf2Y\xff\xfaa\xe4]\xff\xba\x1c\xa07\xc6\xd6}\x93\x8c\xaf\x1f^?\xcc{o\xf1\xf5\xeb\xd5\xcd\xa7W\x17\x97s\xf3-\xbe\xbe\xfc\xb4\xbe\xf1\x8c\xfb\xd9\xc7\xab\xdd\xf5\xa5c\xbd\xbb\xbf2\xde_\xce\xf67\x1f\xb6\xcb\xd9\xfdtw\xf3a\xb4}\xffa\xb4\x9b\xbd\xd2\xb7\xb3\x8f\xe1nv\x19\xeeg\xaf\xa6\xcb\xeb\xea\xef}\x7f\xf9\xdb\xafo\x1f\xbe\xddG\x1f\xee\xae\xbe\xd6\xf28\xfe\x9d\xff\xdb\x87\xb7\xa1\xfb\xeb\xdd\xf6\xbd7\xda\xb8\xa6k\xbe\x0b\x9c\xc7w\xfex\xffm?\xda\xbd\xff\xf8`\xbd{\x9c\xee\xdf=^\xef\xdf\xfd\xfe\xf6\xe1\x9bg<\xa2/\x96\xfe\xf5\xf7e:\x0ff\xf7\x04\xdf\xabo\xbf\xdf\xdc;>\xde\xbao\xf0f\xee]\xec\xbf\xbd\xf9:\xf8\xfa\xe5\xed\xc6\xfd\xfdv|\xed]7:xcl?~\xd2\xc7\xd7\xfeJw\x7f\x9d\x0e\xde\xed\xc7kg_\xdb\xe2~\xde\xd37\xe8\xcd\xeb\xed\xbb\xc7\xab\xf5\xec\xd58\x9d\xe7\xfaY\xa5\xf37\xd6\xe3\xfb\xe0F\xff\xe4\x7f\xa6d\x9e\x07\xb3u\xa9\xd3\xf5\xd7\xde8}g\xaeV\xce\xab\xd1\xee\xdd\xfdt\xe3\x18w\x96\xf3\xe6\xd3\xe6\x93\xff\xf9qn~\xde\x7f\xed}\xfe\xf0\xed\xcb\xd7\xfbk\xef\xa2?\xff\xb2[;\x8fQf{EY\n9\x9c+\xe3\xe6\xfd\xc3\xdd\xe6\xab\xf99\xfd\xf6\xc5\xd2?|\xba\x1d_g\xb6~e=\xd8_n\x07\xb3\x8fw\x97\xef?~\xed\xdf\xe8\x9fz7\xfa\xe7\xd7\xb3\x8f\xaf_\xdf\xdc/{\xb3\xc7o\x97\xb7\xf7\x0f\xdb\x9b\x87\xdb\xfe\xec~\xb9\x9d]]\x13\xfc\xf0\xda1\xefVs\xff\x06\x13\xfc\"\x9a\xdf\xad\x1a\xbf\xcb\xe8\xd2\xf1?\xaf\xdc7\xe3\xfd\xe77\xe3\xcd\xfcR\xf7n\x0b\xfd,?\xbdYm\xdc7\xe3G\xfb\xcdx{}usy}y\xbd\x9d}\xfc\xb4\xfc\xc7\x95\xb1\xfa\xda\xc3\xeb\xbc\xec\xd5\x83\xf7\x9b7\x1d\x95v\x1a\xdc\xbd\xf9\xbc\xb7\x7f\xff\x86\xbf]}\xdb\xcf{\xfa\xd21\xef2\x1d\x0e\xec/\xd6\xa3\xfb\xe6\xf5\xfak\xef\xf3\xdb\xbbK\xdd\xcb\xf0\xef|\x1c}\xbb\x0c\xcd\x9b{g\x7f\xfbpk\xde\xdc\x7f5o\x1f?\xedf\x9f>\xf5n\xef\xdf\xbe\xba\xd5?\xedo.\xa7\xfd\xd9\xc7\xe9vv\x7fe\xce>\\\xd7\xfc\xbe\xbd\x19\xdf\xbb_\x0c<\x0f\xee\x08~w4\xbf\xc7V~\x9bL\xf6w&\xe0\x93\x99\xaf\xbe\x1a\xe7~\xf9\xe9\xe1\xeeM\x81+\xfa]\xde\x0f?\xf6\x97\xbf]\x8e\xfb\xce\x9b\xd7\xf7v\xef\xb3~\xfd\xe6\xf3:\xeb\xef\x8ew\xfd\xf2\xb7\xe4\xe2\xc3\xcfof\xd9\x08q\xff\xe1\xd3\xdd\xc5\xe7_\xef\xed\xaf\x9b\xc7\x97/\x1fG\x97\xef\x92\xcb\xfe\xd2y\xf3\xbb\xf7\xf5j\xfa\xe6\xe2\xfa\x1fo.\x02\xf4\xf2\xe5\xe2u\xb4\x9d.\xb7\xd3\x8b\xf1hj\xbf\xeeE\xf7\xf8\xd3mF~\xf1\xf6\xee\x93u\x15?\xbc].\x97\xbf\xfc\xf2S'F\x11\xb2\xd3\x8e\xde\x11\x8e\xa4\x9a1x\xc6\xc1\xf4\"\x1f\xe6n\x8b\xc1t\xba\x18\xbd\x1c\xaf\xfew0\xfd\xdf\xc1\xf4?u0}\x7f\xf9u\x7fw\xbf\xba\xba\xbb\xcc\x06\xd3\xaf\xfb\xd6\xc1\xafe0m\xf8\xdd\xaa\xf1\xfb\x0f\x1aLo?\xb6\x0e~G\x0d\xa6\xb7\xed\x83\xf3\xf7\x19L7\xaf>\xe8\xc6u6\x18\xcd\xea\xc1\xd4\xbf\xeb\xbf\xb4~\xbex\xfd\xdb\xc5b:{\xed\xbf\x9c],w\xa3\xbb\xe9\x9b/\xaf\x02c:\xf5?,\xcd\xfe\xed\xe0\xe1\xe2\xf2\x1f\xb37\xb3\xcbW\xdb\xebWhv\x8d\xfc\xd7/\xad[{{\xe5E\xd3/\xdbO\xab\xed\xd5\xfd\xecr3\x9f~\xc1_\x1e6\x9f/\xb6\xeb\xd1\xe6\xf6zz1\xbd\xda^\xbc\x8aV\xa3O\x03G\xcf\xc7\xa5+\xfc\xfa\xe3\xc3\x87\xf5\xad\xff\xea\x95\xd2\x00<\xd2\xf2x\x97\x1c\x85\xb3`\x99\x1d~\xef#T\x8f\xbf/\xc7\xf7/\xfb\xb7\xd3\xafw\xbf\xaf\xa2o\xcb\xe9\xf4\xc3\xa7\x87\xff.\x03\xd9\xe6\x7f\xbf\xbdL\xa6\x17\xaf\xaf\xdc/71\xba\xcdF\xe6\xdbj\xe0|\xd9\xbf\x9d\xed\xec_\xeft\xe72\xdc\xbc\xebY\x8f\xef\xfcb\x1c{\x97\x8f\xb5\xe3\xfe\xd7\xdf\xa7\x9b\xd9\x87\xfe\xf6\xddv:\xfa\xcd\\m\xbf~\xb9\x89\xbf\xfd~\xbb\xfc\xea\x7f\x0e\xec/\xfd\xf1\xf5\xfa\xe7\xe1f\x7f\xbd\xb4\xbf\xdc\x8e\xaf\xb1c|\xfcxq\xe3\\\xdd`\xfb\x0d\xbeF\xc1[\xfc\xc9\x8c\xde\x7f~s3\xb0{3\xeb\xdb\xab\xeb\x97\xb9\x8f^f\xfd\xf7\"\xfd\xf6\xfb\xdd\xaa\x19#\x96\xe3\xeb\xb2\xee\xf7\xbe\xf5\xf8\xde\xcf\xc7\xe0M\xd6\xe7\xf31\xf9\xd7\xbb\xf8\xb7\x0fo\xab\xb9\xe2\xeb\xc7\xcf\xd3\xe5mo\xbc\xff\xf6aj\xbc\xbb\xff\x9a~}\xbc\xda\xcd>L\xcd\xf7\x1f\xfa\xbb\x9b\x8f\xcb\xc7\xd9\xfd\xa7\xa4\xec'\x9b\xd9\xe5\xc3f\xf6q\x9a\xce.\xaf\x06\xb3\x8f\xd3\xc1\xec\x9e\x18c_]g\xe3~\xed_\x8d<\x99/\xea^\xad\x1b\xd35\xdd\xbde\xce\xf6\xd6\xc6\xf1\x9d\xcd\xec\xe3\x83\xf5\xfe\xc3h;\xf3F\xfb\x99gd\xf4\xa9cf}\xf1u\xff\xdd\x17\xeb\xf1z\xdf\xf0\xbd{\xf3\xf9\xf1\xab\xf96r~\xbd\x8b\xe6\xbd\xfe2\x1b\xbf\xdf\xfb\xaf\xbd\xb9\xf9Y\xff\xed\xc351Nf\xe3\x00Q\xa7\xcc\x1e\xfb\xff\xc0\xb1\xf9\xf7\xe9\xe0\xd6|\x8b\xbf\xfe~\xb7q\xf0\xddf\xde\xdb\x12\xf3\xe2E87\xef6No\xb5q^]\\\xde\xee\xa7\xfb\xd9\xe5\x95q\xfdju\xf3\xf5\xcbM4\x0f\xb2\xb2eT\xf0\xb9\xb8\xf9\xf81z;\x0fn\xf4\xaf_\xac\xfbo\x9f\xf0\xd5o\x1f\xdef\xfc\xd7\xf6\x17\xfc\xf0\xfe\xe1z7\xbb\xbf\xd6\xdf\x7ft\x1eo\xee\xddW\xb3\xc7\xab\xdd\xdd\xc7o\xaff\x0fo/\xef>^\xeb\xb3\xcb\xe5nv9\xdd\xcf>:;\x82\xdf\xd5\xbcwc\xcc\xbf|^\xbbW\x0d\xbfoo(~z+\xbf|\xee\xac\xe7\x13\xec\xf8\xb8\xf7\xed\xcb\xdd\x1b\xc7\x1f\xa7\xd7\xbf\x16\xba|\xef\x8b\xe7\x85\xdb\xfb\xab\xfd\xec\xfe\xd6\xbay\xbc\xea\xdd\xe8\xd7\x8f\xf9\xbc\xf0p\xbd\xbf}\xb8y=\xbb\xbf\xdd\xbe\xbf\xbc\xda\xce.\xafw7\x8fW^\xc3O\xde\xfa7\x97\xa3\xf0\x1f\x97\xe3_\x7f{\xfc\xf4\xb2\x8d\xa6\xfd\xef\xe2\xe5v:\xbd{5\x9d^O\xa7\xcb\xcb\xe9\x87\xeb\xe9tuu1\xdd]]\xbc\x1c\xddN\xbfd\xe3\xe6\xed\x14\xf8\xdf\xd7\x8b\xe9\xed\x15\xf0\xfc\xfa\xeajzu1\x9d\xce.\x98\x82\x8b\xe9\xe5\xd5\xab\xa9~u7\x9d^]^\xf0<\xef\xae?\xbe\xbe\xf8\xf4\xe5\xea\xc3\xf5\xe6\xa5=\x9dn/\xa7\xb7\xd3WW\xb7\xb3\xbb\xe9\xe5h\x1a\xbe\x0f>~6n?^\x0e\xdf\xbeMV\xbf\x99\x9b\x0f3\xf3\xb7\x97/\xbf)\xcd/\xc6@m\x829*\xbe\xcf\xe6\xd7W\xb7\x0f_\x96\xbd\xe9\xff\xc6\xf7\xff\x7f\x1d\xdf\xab\xce\x01t\x1c\x9e\x8d\xad\x8asV\xcfH\xc9y\xab\x8c!U\xe7\xad\xc7\xcf\xbf\xe2\xed\xb7\x0f\xe3\x0f\xdf~\xbf\xd9\xb8\xbf\xbf\xbd\xcf|\xe9\x9b7{\xb6\xf8Y%\xae\xbfy\xfcj\xce\x1e\xde^\x15I\x97\x99!\x1f\xbf\xdb\xd7\x1d\x0d\xbf\xaf\xad\xfc\x9e-\xbeoOn\x1c\x15\xdf\xdf]\xb6\xf2\xfbN\xf1=\x1a\xbc5\x1f\xb2\x11\xe2\x91M\x96\xe8\x9f.\x93\xd9vv\xff\xe1.\xfc\xfa\x9b\xf5\xe6\xbf\xfb\x1f~\xbb\x99\xdf\xdd\x7f\x9e]\xdd\x1a\x8bWw\x97\xcb\x9f\xbd\xe0\xe5\xe0\xe7\xb7\xc6\xf4\xed\xa7]\xb2\x9c^\xbd\x99NM\xe3b\xfav\xf6A\x7f\xf3\xb5\x18\xcf?|\xfa\xfc\xfe\xee\x1f\xd6\xab\xaf\xd7\xd7\x92\x04J\xb3\x15C\x1f\x8e\xa1\x7f\x03\x8e\xcf\xccCwO=\xe0N\"\xb8\xf4A\x04\xd7\xa3\xcf\xcd\xb8\x98\xfe\x95\xdeZ\xae6\xe6\xe8\x87\xfc\x01\x9dE\x18\xfb\xf4F\xacA\xff\xda\xa3\x7f5\xe9_\xfb\xf4\xaf\x16\xfd\xeb\x80\xfe\x95?\x0b\xb4J}\xba\x15\xf9Nu\xb1\x89\x83|\xdb\xc3\xff\x12\x95\x96\xdbT\xa2\xe2\xc8N\x92m\x18\xbbB@\x8a\xc4\xbcS\xb4K\x85\x85\xeb\x98!,\xb64\xe9G\x1e\xbd\xc7c{\xf4.UH7\x9a>'\x101\xe7\x94\xca\xf3Q\xd4\xb3|\xd7\x93~BKPmK\xd2\x0fW\xf4\xaf\xb4-\xd6\xf8\x94\x0dH\xba7\xd8I\x84\x9cT\xcb\xf7\xd8\x0e\xe2\xf3%b\"M3\x06\xbbq\xb5\x9b\\\x9d0\xb2\x06\xdd\x9e\xf5BF5\xde\x19\x03\x96\xca\x18\x0e\xbb\xc3\xa1\x94\xac\xbf3Y\xaa\xa1\xbc\"s\xd7\xe7\xea1\xcd\xaeiJ\xa9\x06<\xd5`\xd0\x1d\xb4\xc8\xc6\xb7\xc8\xd2\xa5$\xa3\x9d\xc5U\xd3\xeb\xca\x1bd\xedF\\5\x03y5C\xbe\x9a\xa1\xd1\xed\xf7Z\xea\x19r\xf5\xf4\xe5\xf5\x18;\x83#a\xcf,2$\xc5\xc9\xb5C\xedq\xf6< \xf1:E\x934\x8c\xce\xf5I\\zd\xc9M\x9f`\xb4\xc8~'\xce\x0eT\xe7k\xb2\x9f\x1f5/p\xd1.\xfb\xe5\xdf\xff\xe5#\xd7\xb3;\x89\x13#\x14t\xec\xc0\xed\xfc\xe8{Ay\xea\xc0\xd4\x91\xff\xd3A,W\x90<\xa17d\xd4'u\x08\x80P\xadO\x00\x84\xed\xdd\x02\xaaM\xa9g\x00\x84*\x9d\x03\xaa\xaf\xbd\x7f@\x95)t\x11\xa8\xb2\xf6^\x02\xe9Q\xa5\xa3@\xb5\xb5\xf7\x15\x88J\xa9\xbb\xe4\x84\xcf\xdfc\x14\xbaL\xf9\xb0>\xbd3h\xe9G\xfeS\xba\x91\x7fb/\xe2\xe8\x14;\x11G\xa7\xd0\x87\xf8\xba\xd4\xba\x10G\xa7\xd4\x83\xf8\xda\x14:\x10_\x95J\xff\xe1\xabR\xe8>\xbc\x06\x95z\x0f_\x97B\xe7\xe1\x89\xd4\xfa\x8e\xff\xe7w\x9d\xb6^\x82\x9f\xd2K\xf0\x89\xbd\x84\xa3S\xec%\x1c\x9dB/\xe1\xebR\xeb%\x1c\x9dR/\xe1kS\xe8%|U*\xbd\x84\xafJ\xa1\x97\xf0\x1aT\xea%|]\n\xbd\x84'R\xeb%\xf8\xbb\xf4\x12\xb2^\xcf_\x1e\xe8c\xa0\xb4XN\xb8A1y\xce>?W\x9d?\xfd\xbf\x9e\x1f\x85qj\x07)K\x12\xa4\xb6\x17\x00D\xf9s\x82\xac}\xa6;\xf0\xc2d\xd3\xee)\xf2\xc0t\xacH\n2)\xcc\xbe\x85\xa0\xfeirBd\xc7\x89)\x94\x08\x9f&\x11D\xc6IDQ\xce\x97\x9a\x83\x82\x94v\x9d\"\x19t\x1e\x84\xe5O\x13\xa2\xac\xf6sn\x90\x98/\xb54\x8c\x8e\xe6\x93\x86\x11\xc7'\xef4Gs\xe2;\xc5\xbc\xea\xc7G\xf3*\xc88nY\xe7=\x9a\xd7\xf1\x8b\xab\xda*L_P\xaaN`\x98SX ms\n3\x89yNa'\xb1\xd0)\xec\xda\x82\x12\xd5\x11\xa51\xdd\xf1N'\xb2\xdc\xf1\x9c\xc4\x86;\x9e\x97\xccn\xc7s\x93\x99\xedxnmV\x93\x1a\x08\x1f]\x9d\xc8@\xc7s\x12\x1b\xe8x^2\x03\x1d\xcfMf\xa0\xe3\xb91QL\xb7<\xfe\xce\x1f\x83\x07a\x1aqL\x1389O\x94\xc2\xe4zMt\xfc\x18\\\xf1\x08\x92\x13\x84\x05\xa9\x14\xe4%\xe9\xda|[uD\xaa\x98\xfb\xa7\xb4\x03 Ri\x86\xaf\xdc\n\x89\xc0\xf8\x14\x81\x01\"\x15\x811)0\xed\xfb6}\xcf-g9)\x1f\x95\xd18s\xbb\xa7;O+\x9alt\x00\xe8\xb2\xc7\"\xda\xfa^]1\x1e\x00\xd4E\x81\x88~N\xdf_\x86\x18\x94%\"\x0e\xb8\xe2\x90wz\x80>\x7f.\xa2\x0e\x80{\x81\x94\xba\x8e\xef\x8bs;\x9f\xd2\x8f7\x03Av\x8a%\x08\xf2S\x8dA\xb08\xdd\x1e\x04\x93\xd3L\xc2\xa9\x0f\xb2\x8a\x82Y\x14\x86\x9b\xb9\x9d\xcd\xe3'\x98\xca\x7f\x92\xa5\xfc'\x1b\xca\x7f\x06;\xf9O4\x93\xffT+\xc1\x06\xc1'\x19\x04?\xc9 \xf8\xc9\x06\xc1\xcf`\x90'\x0ee\xac\xe6@\x83\xd04Zq\xd5\xaf\xa2\x13\xbc\xe3 \xc3\x05\xc8\x8eA\xb0a\x18\x1c\xd8\xb5\xe3\x07m\x19\xdb{\x06k\x9a&\x87\xf5=\x17\x82Z\x96\xc5A\x01\xd8p8\xe4`\x89\x877\xcd\x85\xef\x128\x1e\x8f9 .\x8c\x0d\xc1m\xdb\xe6%\x0d\xc3\x00\x92\xc1q\x1c\x01k\x00\x8c\x10\x82u\x9b\xdf\xd2d\xc0\x8b~\xf6\x87\xc3\x83P\xf6&g\x85\xd3\xc6:\x0d]%\xd8\xfeQ?\xd3_\x9ce\xb1\xf8Yw\xfc\x93\x80p\xd4B8\x12\x11\x0e[\x08\x87\"\xc2A\x0b\xe1@Dh\xb5\x10Z\"\xc2~\x0ba_Dh\xb6\x10\x9a\"\xc2^\x0baODh\xb4\x10\x1a\"B\xdd\x92\x13\xeaB\xed\xe8\xbd6\xd2\x9e\x98\xd6h%6 \xea|\x8c\xe1\x9c6^\xces\xda3\x1dt\xd8\x82\x88uX\x92\x08p\xd6\x82\x88uV\x92\x08p\xd4\x82\x88uT\x92\x08p\xd2\x82\x88uR\x92H\xa8\x08\xd6AI\"\xc09\x0b\"\xd69I\"\xc01\x0b\"\xd61I\"\xc0)\x0b\"\xd6)I\"\xc0!\x0b\"\xd6!I\"\xc8\x19K*\xd6\x9f(2\xb1+\xf1\x8eH\x11\x82N\x98O`1r\xd9\xc1{\xa8\xf7u~\x9c\xe5\x81\x8bE\xdf0\x07\x82Y\x01\x82\x0f{\x16?\x89\x84\xb1\x1d,\xf9\x81~`\x02\xf3\xf32\xc4<\xd7\xf9\x10@\xee\x11\xc6\xe1\x96\xc6\xf2\xaf\x0e\xa8\xa5\x85\xe0\x7f]\xcc\x17\x86\xcdO\xa8\xd1:\x8e0+\xb0\x85z\x8e\xcdO\xe6\x05w\x90\xc2\xee\x0f\xccE\x0f6J\xe4\x05l\x04\xe2Z\xba>\xe2\xad\xb2\nS\x08\x9d\x99f\xce\xcf\xa9 r\xa4\x0b\xa7v\x10o\x9b.\x1f\x8e\x94\xc1\x10B\x01\x837\xcc\xe1\xd0\xe2\x9b B\xc7\xf6x\xc8\x0b]E\x19<\xc1\x18\xa1\xb9\xc3\xeb$\xb07l@\xa2\xeb\xc6\xbc\xcf\xb3\xce\xa5\x9e\xe35k\x1b]\xef\xf7\xc7|\x08\x03 Mk\x88\\\x91W\x01\xf8\xf1\xc0q\x80 &\xc7\xa3\x04$q\\\x04\x91l\xedd\x85\\\x88`1X,\x16\xbc\xf4%\x01\xa4H4Z\xb8\x0b\xde{K\n\xb8s,\x16\x0e\x9a\x8bH\xa0\xde\xef.\\\xbe\x15d:\x91\"\x10f\x88\xe6\x9aV\xbe\xea\x84&\x80\xde\x7f\xd2\x9d\xc7\xf5\xd0\x1d\xdb\xae\xb7N\xce\xd9\xa1\"6\x18@\xd7\xe8Y1b\xd3\xadq\x8f\x85\x81(\x93EA\xa0>\x032\x00\x8cf\xe8\xac\xe4@R9\xd6\"\x0fc\x067\x1e\x8f\xc7\xc0\xea\xaf\xdew+\xc0y\x92<[iUz!\xd7\x90\xc5:P\xa41\xad\xd8U,\xe0UV\x1bbU\x96\xb5q+\xf7\x16[\xe4\x82*\xe2y\x15\xdb\x81\xa2\x96\xc8\x05kO\xb6\x1cX\xe7\"\xd3Q\"\xff\xe21\"\x17\x03\x90\xb0\x97\x01@\xd0\xd1x\x9c\xc8\xd7\x00\xa4\xc8\xddx\xa8\xdc\xe3\x98\x8c\xdfS\x9c\x8eO\xdd=\xd9\xefT\xa4Sw=\x86\xdb1\xde\xa7\xe0~*\xb9\xbeX'\x12oB\x97d!B\x8f\xe4\x80\x02\x87\xe4p\xb0?\xb20\xa1;r@\xa17\xb2\xc8\x16g|\xb6\x01\x90\xcbN>\xdd\x15\xdbe;\xc2\x13\xfd\xef\xe3\x88\x02\x9fc'!\xc0\xe7X\x88\xd0\xe78\xa0\xc0\xe78\x1c\xecs,L\xe8s\x1cP\xe8s\xc7M\xb9,\xbc6oc \xa2\xa0<\x9e\x06\xfb\x1c\x9b\x80}\xba\xcf\xe1\xe7\xf49|\xb2\xcf\xd1\xfc4\xadx d\xc5\xaeH\xf5\x02/\xe5-\x82\xf8,\xe4d\xa0\xf93\x0eZ\xdeF&\x91\xc0&f\xb6\x84\x08\x03D\xe3\xf2w\xd4\xb5\x0f\xd1\x07\xb8!\xdcn\x8f\xb4-\xd8\x92a\xb5\xc8(\x1cDd\x17\x1e\x08\x9b\x86\xc7\x81\xd6\xe1`\xa0\x818\x14l#&\xee\x15\x9a\x89\xdb\xbe\x17Z\x8a\x0f\xf5\x85\xc6b\xf7\xe2\xebm\xc0v\x83\xa9\x0cl[\"\x1a\x15\x1a\xd1W\xb4!\x8b\x13\x98\x90\x85\xc1\x16\xf4U\x0c\xe8+\xd9\xcfW3\x9f\xafj=68\x16\x1b\xcf?\xc1v\x023\xe1V3aE3\xb18\x81\x99X\x18l&\xacb&\xacd&\xacf&\xacj&6\x9e\x14\x9b \xc3f\xa2\x80\xc9\xcav\xc3\xadf\xd0\xd7\xba\xf3\x87\xe7zG\xef\xf4\xa3]\xa7\x17\xed:\xf4\xa6\xcbD \x05\xd6\xd4\x13\xd54R\xaa F\x815\x99PM\xbd\x92\xbe\xbd]r$Xc_Vc&\xb9\xaeP\x1f\x84\x03k\xb3\xa0\xda\xfa\xa5\xc4m\xb5\xc9p\n\x83\xf0\x01t\xa2lT\xff\xd3\xfcHR\xd9\xf3\xbb\x92\xa0\xb2\xef\xebM-\x95\xb6\x99\xf8x\x87\x12T\xf8,>\xa5\xe0T\n3{\xedi\xfe\x9f\xe8h\xc2\xba\xbe\x83\x9f\x81u}g7\x93\xd6\xd9f\xf4\x13\xbc\x0c\xac\xefOp2\x99?\xe1?\xd1\x9f\x84u}\x07\x7f\x02\xeb\xfa\xce\xfe$\xad\xb3\xcd\xbe'\xf8\x13X\xdf\xf3\xf8\x13Ua\x14\xa3\xfa\x0b\x1e\xda.\xff\xb4E\xfdq.m_~\x08\xa8\xf9\\W\xe2\xc4!\xa6?%\xd2\xcdb@=\xff\xe6\x11\x13\xb0\x15Q\x9f~\x80S\x89E\xa4\xa7W\x9fRb\x8a\xf3\xf0N?\x14\xe9I\xbe>#\xaf\x8f\x0fa\x8b*\x8d\xb2J \xc4-j5\xaaZyD^\xb1QT\xcc\x97fu\xf7\xf2\xba\xf9\xc8\xb8\xa8\xbbW\xd6\x0dD\xceE\xdd\xbd\xaan\x1e\x91\xd7\xdd+\xea\xe6K\xb3\xba\xcb\x86k\xa2\x96\xd7M\x07\x10e\xfdM\xe3\x01L.A\xd5|\xa0<\x97\xa1P\x80&\xd2@\xad\x02\x00Q\xc9P+\x01\xc0\x142\x94j\x00\xca\xab{\xd4\x9a\xb6\xf00>HoS+\xcc\xd0\x07\xde\x99\xb3\x98\x01\xf0\xe7\xc2'\xb3B\xc8-Ko\xcf\x8a\xa5\x0e_\xa4 \x9f\xcf\x1d\xbb\xaa[\xe4\x99u\xf5B\xe7o$\x10\xfb?!\x84\xc0\xc9+9D^Z\xcb!\xec\x08\x8d\x1c\xe2\xbe@\xc8!r\xf8J\x10\x89\xcf75\xc9\xdc\x9e\xa8K\xec\xf9u\xb3\x84\xce_\xcb#\xf6\x7fB\x1eI\x17 \xe5\x11\xf6\x82F\x9e\xb6\x8eP;\xad\xb0/(t\x06\x85p\xb5\xe8!\xbe\xa4\x83\xf8\xd2\xfe\xe1\xb7t\x0f_\xda;|y\xe7\xf0\xdb\xfa\x86\xdf\xde5\xfc\xb6\x9e\xe1\xcb;\x86\xdf\xd6/\xfc\xf6n\xe1\xb7\xf6\n\xbf\xb5S\xf8*}\xc2W\xe8\x12~[\x8f\xf0[;\x84\xaf\xd2\x1f|\x85\xee\xe0\xab\xf6\x06\xffI\x9dA\xe8\xf7X\xe2\xf7X\xea\xf7\xb8\xc5\xef\xb1\xd4\xef\xb1\xdc\xefq\x9b\xdf\xe3v\xbf\xc7m~\x8f\xe5~\x8f\xdb\xfc\x1e\xb7\xfb=n\xf5{\xdc\xea\xf7X\xc5\xef\xb1\x82\xdf\xe36\xbf\xc7\xad~\x8fU\xfc\x1e+\xf8=V\xf5\xfb\xb6\x80\x88&v\x16\xe7\xf6\x82}5j\xf6t\x8e\x16a\x8c\x0e\xe5\xc7{\xcf\xff\xd2\xf9\x0b\xfd\xe5A\x98\xcd\xc1\xc1\xc8\x8e\xcf\xe7a\xbab\x01\x87\xbf=\x86\x99o1\xcfqI\x92I\xc7\x14U\xdc\xf2\x960esqMAYt\xd2N\xb9\x93O\xa3b\x91\x9aRP\xaa\xa6\x18\x12\xac)U\xd8 V\x9d\x8e\x9dl\xa8\x93\x08\xecK\xe5\xf5e\xe2\xfa\xea\xd2\xc2\x82\xc9\x8c[\x17\xc2\x82a\x99`\x98\x12\x8c*u\x03\xd9\xe7\xfc<\xe6S\x81L\xf1\\\xf2A\xc2\xae\xeb\xcd\xdb?4\xd8u\xbd\x94E\x01\xfd\xc5m@`\xa9C\x17k\x0eb\x17\xddn\xaa\xc5\xe1\x96\x81\xc5\xe1\x16Bi\xcb8\\G<\xb6x\xceQ8!^\xfb\x01+A\xfeP\x80\x05+ \x8b8:m\xe1\xed\x90{(\x90\xd8\xde\x87\xeb\xf4<\x7fD\xbc\xfeJ\xa1\x7f\x1c\x18\xdbg=Lf~\xb2\x1c\xf6\x00\x12\x01;\x01\xcfC\xe0\x07\x00\x1046\x89\x83\xbd\x81C\x08\x1d\x82GJ}\x02\x84K\xdd\x02\x10\xa5\xdd3DDR\xe7\xc8\xd73R\xffPp\x10\x85\x01\xd4\xcd\x06:\xa9\xd3\xf8m>\xe3\xb7\xb9\x0c\xcbA\xe41\x1c\x0ev\x18\xbf\xcd_|Uwa\x81ro\x01\xd0rg\xe1\xe4P\xf0\x15\x98F\xee*\xfe\x93<\x05v\n,w\n\xdc\xe6\x14\xb8\xcd)X\x0e\"\xa7\xe0p\xb0S\xe06\xa7\xc0\xaaN\xc1\x02\xe5N\x01\xa0\xe5N\xc1\xc9\xa1\xe0\x140\x8d\xdc)p\x9bSPt\x0b\x8cvu%D\xee\xbd\x0e{5?\xd12\x10\xf9,\xfb\x9dfS\x9a\x08\xe4V\x99\x99aJ\x90\x90E\xc4c^R\xcd^\xa7!\xb5E\x90==7&\x95\x94\xe7F\xc7\xe8\xe4\xd9|\xfa\xb7\xc6\xeb\xf5\xfc\xe7\xea\x85\xa9@\x15\xf9\xe1S\xae\n\xbd\xa9\"\x7f\xe7A\xfd\x13\xc0\xa1\x8c$H\x1ea\xece\xeb\x89\xea\x0b\xe3\x13\xb2\xcc\xf5\xe2\xe2\x95\xff\xe5\x17\xcb\xeb\x9a\x88\x92\x82\xe5\x04|\nH\x90\xc5H@\xf5\xab0\xf6\x1e\xc3 =A\x808\xdc\xb2\xb5s\xfd#/\xdf\xc6vt\xa8\x19d\xbf\x9dg\xffL\xe8_A\xbd\x03\xa4\xc5\xc3 \xfb@P\xaf\x16\xa3\x0d\x8a\x13\x04\xd4_\x15M\xe0\xc7B+6,\x8f\xb6fU\xa3\xd0\x9c\xb4L\xa2R\xd8\xbc2\xb9Z\xcd,\x91\x8c`\x0d\xd8\x1b\x96\xc9K\x91\x9fhIj\xc7)%N\xf1\x19\xfd\xfcyS\x15\xf90\xff9\xff\xbcy\x92\x8f)\x05\x0f\x889\n\\\x805\n\\\x96q\xf6\x88c\x8b\x02\x17bZ\xbe\xe8\x93\xe7[\x14\xb0\xac\xcb\xa7$\xf7\xe2\x11\xc4{n'(\x1b\xc8\x00\xeeU\x11\xcb\xbf~N\xd6P=\x845\x1e\xa3\xd4Y\x81:\xcfKx\xad\x17\x8f\xc9\n\xcag4\xff\x04\xe1Ee\xd0\x8aE\x06\x07\xac\x97A\x85\xc6\xcb\xf9\xe4\xb6\x03\xb84\xa6jxp\x96\xca9T\x86\x02\x98PF\xc9\xf9@6\xc9\xb94&\x01\xf80\xca\xcf9\xc1\xba/uS\xaa\x1e\xd4\x0e\xa9\xe5\x9c\x13\xa8\xe4\xfbu\x92z\x8b=\xd0q\"\xdby`\xfb\x0d\xf1\xac\"\xac\xb2T\"\xedW8\xb6\xf3\xe4\xac\xa8\xbeS?\x01YsF\xa9Q|\x07\xca9\xb1\xfd\x87|\xc8\xd6\x00\x99\xab\xc2\xccQ\xbaE(\xe0+(\x01L\x0d\xd5S\xb6\x8a$\xb2\x1dT1\x83k\xb2\xf3\xd74\x1eh~\xae\x97\xa4\xb17_\xa7H\xc0\xb2\xa0\xa29\x96\x08\xb6\xf7\xe4A\x0da\xc3\xc29\xda,X1\xa3\xbaP\xc3\xaa\xe9Ar{Ul\xd8~\xd4p\xa2\xba\x91\xcc4\x15\xab\xda4<\xaf\xca\x0c43\x89\x11*\x9e\xac\x11\x1a\x96\x84% \xaer;0=\x95\xb4\x04\xd9Qk\x96P_-\x0e\xdf\xea\xccl\xebz\x81\x8d\x8bh\x9c\x88A\xb5\x1c|\xaeO\xca\xffB\x9c\x0c \xa7\x1e\xcb\xc9(9\x19\x10\xa7\x9e\x84\x93\xc9r\xea\x95\x9cz\x10'S\xc2\xa9\xcfr2KN&\xc4\xa9/\xe1d\xb1\x9c\xfa%\xa7>\xc4\xc9\x92p\x1a\xb0\x9c\xac\x92\x93\x05q\x1aH8\x0dYN\x83\x92\xd3\x00\xe24\x94p\x1a\xb1\x9c\x86%\xa7!\xc4i$\xe14f9\x8dJN#\x88\x13\xb6\x93T\xe6\x9cz\xf6?\x96\xe38\xfb\xdf\x84\xf8\x19\x085\x97Y\xd4\xa7\xcb\xd6C\xe5\xbbm7\xe8\\\x9f\xd4$\xe0\xca*\xe7e\xc8\x96o\x0d/\x83\xe0e\x00\xbc\x92U\xec\x05\x0f\x99d\x15i\x80\x966)F\x81\x00\x05)\x89\x0d\x80\xd8\xa0\x88\x0d\x85\\\xdb\x81\xe7O\xe4\xfd\x88\xc6\x9e\xbe\xa4\x86\x18>\xf7\xaaZc\x0e\x0c/\xbe\xcb\xc2\x1a\xac\xe5\xf8\xb55\xcbFmA\xf6\x9c\xcbk\x81\x04\xadK\xafgZa\xe7\xd5W<\x8e^d\xf3\xd4\xa7\xad\xb3a)\x9e\xba\xd4>\xcd\xb8\x7f\xcaj\xfbT\xab\x7f\xbf\x057+\xd1\xf3\xae\xb9a\xee\xcf\xb2\xec\x86Y?\xe3\xca\x1b\xae\xe0\xb9\x17\xdf\"\xfd?\xd7\xfa\x9b\xeabOY\x82\x8b\x18\x1d\xbb\n\x17\xf19a!.bu\xdaZ\\\xac\xa9\x13\x96\xe3\xacY\x9f\x7fE\x0e\xd6\xf0|\x8br\x90\xfd3\xaf\xcb\xc1:\xbe\xd3\xd2\x9c\xb2\xee3\xad\xce)\x9eO^\xa0\x0b\xb8\x9d\xb6F\x170;u\x99.`\xf7\xc4\x95\xba\x80\xeb\xd3\x17\xebB\xc3\x1c\xbb^\xe7\xe7\xeb',\xd9\xe5\xcc\x8e\\\xb5\xcb\x99\x1d\xb9p\x973;r\xed.gv\xe4\xf2]\xce\xec\xc8\x15\xbc\x9c\xd9\x91\x8bx9\xb3#\xd7\xf1rf\xc7/\xe5[\xfc\xf6\x89\xaby\x96\xfb\xe2i\x0bz\x90\xddS\xd6\xf4T\xf7?aY\x0f\xd3\xb3+{\x85\xa5\xbd\xc21\x9a\x9c\xa7\xff\xcc\xcb}\x9e\xdf\xb3\xaf\xf6\xfd?c\xb1\x0fTr\xc2Z\xdf?a5\xf8\xacK}P\x80\xd65\xdfs\xad\xf4\xfd\xa7,\xf4Y\xe2\x13\xd7\xf9\x90\x0cO^\xe6\x9fb\xd7?g\x95\x7f\x9a\xc1\xbf\xe3\"\xdf\xff\x9ek|\x88\xf9\xf3,\xf1!\xce\xcf\xb9\xc2\x87\xf8?\xfb\x02\x1f\xd6\xfd\xb3\xad\xef\xfdgZ\xde\xc3|\x8e^\xdd\xc3lNY\xdc\xc3\x9cN\\\xdb\x8b\xb4t\xca\xd2\xde\xff\xde+{\xa0\x82g\\\xd8\x03\xdc\x9f{]\x0fT\xf1\xbd\x96\xf5\xfe\xf3\xaf\xea\xfd\xe7\\\xd4\x83\xccN\\\xd3\x83\xbcN^\xd2\x83\xdc\x9e\xba\xa2\x07\x99>\xc3\x82^`\x93\xa3\xd7\xf3\xec\xcc\xfc\x94\xe5\xbc\x8c\xd7\xb1\xaby\x19\xafc\x17\xf32^\xc7\xae\xe5e\xbc\x8e]\xca\xcbx\x1d\xbb\x92\x97\xf1:v!/\xe3u\xec:^\xc6\xeb\x84e\xbc\xd4]\x9f\xba\x8a\x97\xae\xae\x8e^\xc4K\x17\x84'\xac\xe1\xfd\xa7-\xe1!\xf2\xe3V\xf0\xa2\xc5:~\xe6\xc5:\xcf\xef\xd9\x17\xeb\xf8\xcfX\xac\x03\x95\x9c\xb0X\xc7',\xea\x9eu\xb1\x0e\n\xd0\xbav{\xae\xc5:~\xcab\x9d%>q\xb1\x0e\xc9\xf0\xe4\xc5\xfa)v\xfds\x16\xeb\xa7\x19\xfc;.\xd6\xf1\xf7\\\xacC\xcc\x9fg\xb1\x0eq~\xce\xc5:\xc4\xff\xd9\x17\xeb\xb0\xee\x9fm\xb1\x8e\x9fi\xb1\x0e\xf39z\xb1\x0e\xb39e\xb1\x0es:q\xb1.\xd2\xd2)\x8bu\xfc\xbd\x17\xeb@\x05\xcf\xb8X\x07\xb8?\xf7b\x1d\xa8\xe2{-\xd6\xf1\xf3/\xd6\xf1s.\xd6Af'.\xd6A^'/\xd6AnO]\xac\x83L\x9fa\xb1.\xb0\xc9\xd1\x8buvf~\xcab]\xc6\xeb\xd8\xc5\xba\x8c\xd7\xb1\x8bu\x19\xafc\x17\xeb2^\xc7.\xd6e\xbc\x8e]\xac\xcbx\x1d\xbbX\x97\xf1:v\xb1.\xe3u\xc2b]\xea\xaeO]\xacKWWG/\xd6\xa5\x0b\xc2\x13\x16\xeb\xf8i\x8bu\x88\x9c[\xac3\xf4\x87\x05\x0e\xed4\x7fG\xce\xe4\x0fz-\xcc@\xe3\x12\x9a\xbf1\xa7\x05\x1b\x94\xd8\x93\xde\x82\xb4\xc8\xdf\x82\xa4.W\x83V\x12\xad\x81+\xbcYH\xfd\xfc\x81\xe6\x1f#\xb2\x7f\x94\xc4\xbe\xba\xc0\xb0l\xc7\x98\xb9\x06\xab\xc9\x86)\xd9\xa8\xd2\xc4\x0e\x12-A\xb1\xb78,\xc2 \xd5\x16\xb6\xef\xe1\xfd\xb9fG\x11FZ\xb2OR\xe4\x9f]`/x\x98\xd9\xce\x87\xfc\xd7\xd7a\x90\x9e\xd9\x1b\x14xq'@\xbb\xea\xe7\xb3\x15\xc2\x1b\x94-r\x9b\x9f:\x01Z\xa3\xb3\xf5|\x1d\xa4\xeb\xb38\x9c\x87ix\x16d\xff$h\x19\xa2\xce\xda;\xb3c\xcf\xc6g\x8d\x14\x8ct\x9c`K\x14\xc6K\xcf>\x83\xc0\xb9t\x9a\xa0E\xc2*J*\x9e\x80\xc7:\xa1\x8b\xa8\xf7\xa0e\x0f(\xa2Wa\x90\x84\xd8N\xce\xfc0\xb0\x9d0\xfbO\x98G\x13,\xa3u\xec\xa1\x98!\xcd\x9fun2\x95\x96\x00\x11}\xad`\x8a\x03\xa3\xf6\xc6\x1e\xa2\xb6\x17\x86\xa3x\x00v\x15R\xa7+\x84\xed\x84&/\x9e\x9dI\xccT\x16\xa9Z5\xf5|D\xd7\x91?\x81\xa0\xf3\xd0\x0d\x03\x8f\xc2^\xe4\x8f:\xb3\x8f\x10\xde\xb1\xb1\x97\xa4!m\x85\xe2\x99\x80bi\xc7\xb6\x1f\x06.-|\xf9\x10\x14\xc9N\x1eP\xbc\xf10\xa6\xfd\x84x\x0e\x91\x95\x8d(>\xa1\xe5\xa56\xf6\x98\x0f_/\x12\xad\xc8\xc3\x91\xc0\xe2\x89\xc2`I\x8f=\xf9;\xafT\xebc\xb0e\x95\nu*\x0c\xd0^6\x88\xaa\xca\xe1\x1f-\x06X#V\xaf\x11\xd25\x8d%M\xb2-r\xc8}\xee\x93\xefT1\xf7E\xf8\xc5\xd6\xa0\x00\x06\x0f\xe8Q\x80\x1e\x0f0)\x00\xf7y\xfa\xc5\xb6/\x17q\xb1\xb5(\x80\xc5\x03\x06\x14`\xc0\x03\x86m\xcd\x1cQ\x80\x11\x0f\x18S\x80\xb1~\xfc\x9b\xba\x19\x8f\x15Z\x84E@Fa1\x90]X\x0cd\x1a\x16\x03Y\xa7U\xe2E\xf1\xb9\xb36\x1b\xb1\x18\xc8L\nm\x1f\xb1\x18\xc8X,&\xb3\x97\x82\xc1\x14F\x05\xba\xbf\x8b\x8d\xe8\xb7\xb5\xc3` \xa0 \xfdv\x0b\xfa\xed\x06l\x11v\x91\x7f\xed\xac\xd5|~\xbb\xf5Z\x1b=b \xa0\xed\xfc#M'\xb6R\xdb\xe0\xc7\x00@+\xe1v+\xe1v+\xe1v+\xb5\x08\xbb\xc8?v\xd6j%\xdcn\xa5\xd6F\x8f\x18\x08h%\xcc[\x89\xc2xA\xb4N\xb5\x18%\xa8\xb9\xdfnG\x11\xb2c;p\x8a/qN4?|d\x1f2&Z\xa7i\x18\x14l\xce\xcfs\xfc\"t\xd6\x89\xe6\x05\x01\xfb\x16`\xa2F\x1eZ~\x86\xed\\\x9fD\xb6\xebz\xc1\x92]\x18\xaf\x8cC\xb9\xd1\xca\xbf>y\xd5\xab\xca\xf8\xd7\x19\xaf\xcc\xaa\xac\xcf\x97\xf5\xab\xb2\x11_f\xd5\xf5\x0d\xf8B\xadW\x17\xf7\xac\x17l\xa1\xa5W\x85\x16\xfb\xa9\xe5\x956\xac)\x87<\xa5\xa1\xd7\xa4\xfcg\x9a\xf3\xcd\xe6\x1cBl;\xf3\xb0\x0d-\xddf\xc5\x15\x93\xf2\x01\xc5\xa4\x84@1-#\x0b\xc8D\xdb@R\xb2\xc0U\xf1\xce\xb9\x12\x90\xfd\xcc\x96{\xc1\n\xc5^ZA\xca_\x15\xe6\x89\x03\xe39\xd9t#q\x1e\xa2\x18\xf2\x1f\xa2\x18r!\xa2\x18\xf2\"\xb2n\xd8\x91\xc8\xea!_\"\xcaAw\"\xcaa\x8f\"E\x10;U\x86j\xf7+JX\xd0\xb5(qA\xef\xa2\x04\x86\x1d\x8c\x16Y\xecc\xbc\xd0\xb0\x9b\x11\xfc$\x9eF\xa0*gS\xf06\x85\xa8d\x95E\x132\x0f\xf4\xa5\x0e\xe8K\xfd\xcf\x97\xba\x9f\xdf\xe6}\xbe\xdc\xf9|\xb9\xef\xf9-\xae\xe7\xabx\x9e\xaf\xe2x~\x9b\xdf\xf9mn\xe7\xb7z\x9d\xaf\xe6t\xac\xbc\x02\x9f\xf3U\\\xce?\xce\xe3`\xe7\xc2R\xe7\xc2R\xe7\xc2R\xe7\xc2R\xe7\xc2m\xce\x85\xe5\xce\x85\xe5\xce\x85[\x9c\x0b\xab8\x17Vq.\xdc\xe6\\\xb8\xcd\xb9p\xabsa5\xe7b\xe5\x158\x17Vq.\xcc9\x17\x05Lc\xdby@\xee\x01\xa34E\xb1\x96D\xb6\x93E^]\x83\xfb>E\x01\xd4\xd2\x8c\x19\x0b\xd7\xba\xba%\"\xf0\xd1\xd2\xe6\xd8\xf72x\xfb\xb8z\x009\xe6\xdf/:F\\\x80\xa2Mb\xa8\x92\\h\x05\xa9\x15f\x83\xba\xaac[\xc2\x11\xb46\x84\xafB\xa1\x1d\x12\x91\xf1\xb1\"s\x04\xad\"\xf3U\x14\"S\x14x\xa5%!\xf6\xdcC\xbe\x8f^u\x16\x0e\x93z)F4\xa6\xdb\xb38\x98\x13F{\x06e)\x98\xfa\x00\x8a\x94;O\xbbT\x1cL$\x18\x0f\xb4\x9e\xc9\x0fk\x89}%\x81}EyY\\\x9b\xb82\xc9\xb0\x92dXQ2\x16g\xb1^\xe5\x05\x0f\x87\x14\xedR\xcdEN\x18\xdb\xe5 Vv\xd1\x9b\xc1\xce\xb8'\xe7\xb6\x93z\x1b\x04\x14\xe4\xcb\\\xe0\xf9*\xdc\xb0k\xe4\xfc\xb9\x80\xff\xc6K\xbc\x145o\x1cMc;H\xbc\xea\\g\x18w\xba\x86\x95t\x90\x9d \xcd\x0b&\xd2R\xbe=\x85\x90\x87p\x9df*:7\xa2]\xc7\x0d\xd3\x14\xb9\x1dg\x1d\xc7(H_eLX\xba$=d\xff\x14Yn-\xddGP\x8e\xc0\xdf\x16\xab\xc1\xda\x15\x81\xd9zk\x90\xe5\\,\xe1o{D9\x1f\xc6\xf8[\x93(\xe7\x03\x19\x7f\xdb'\xca\xf9P\xc6\xdfZd\xfd|0\xe3o\x07\x04\xc0\x84$\x18\x92\x12@U\x8c\x08\xc0\x00\x92qL\x00\xc6\x90\x0c\xc5+\xd4\x1b\xd0I\x9b\xf1\x859\xf2\x85\x93\xdc\"\x0c\x042\n\x0d\x01\xedBC@\xd3\xd0\x10\xd0:\x8c,\xa0\x81h\x0cl#F\x1a\xd0L4\x06\xb6\x14\x8d\x11\x1b\x8b\xc6)\xec\xf6\xab\x8e\xdd\xa5\x15\xfdV#\xfa\xad6\xf4[M\xe8\xb7Z\xd0o5\xa0\xdfn?\xbf\xdd|~\xbb\xf5\xfcv\xe3\xf9j\xb6\xf3\x8f3\x9d\xd8J\xb8\xd5J\xb8\xd5J\xb8\xd5J\xb8\xd5J\xb8\xd5J\xb8\xddJ\xb8\xddJ\xb8\xddJ\xb8\xddJX\xcdJ\x98\xb3\x12\x05\xdb\x1a\x07\x91Z\xb7\xbd\x83H\x9f[\xf3 R\xe4\xb6\x7f\x10ipk\x1d\x84\xaa\xcb<\xa1*e=`\xab\xf5\xaa\xb2\x1ePVq\xe5\xd6\xd0[\xcd\xac\xe8L\x9e\xce\xac\xda`\x9a|Y\xd5\x08\xb3\xcf\x95\xf5+\x9e}\x9e\xa7U\x95q\x0b\xf6\xad6\xa8\xca\x06|\xd9\xb0*\x1b\x02eU\xfb\xb8U\xfeV\x1bUt#\x9en\\\x95\x8d\xf9\xb2,\xe0\x10\xf5\xb7\xad\x96\xae\xbc\xd8\xad\x95\xd35\xb3\xff\xf1\xa0mX\x00\x93\xaaY\x83\xee`0\x18\x0c9d\x9e\xc7.0\xf9b\xbc}\x80?0.\x9aM\x13b/mJ!GmJ!_mJ!w%\xea\x85=\x96\x00@NKH\x06\xf9-Q\x0c\xb9nS\x0cz/Q\x0c90Q\x0c\xf90\xa1\x16\xc8\x8d\x9bb\xd0\x93\x9bb\xd0\x99\x9bb\xd0\x9f\x89b\xc8\xa5 \x9b@^\xdd\x14\xc3\x8eM\xdaD\xe0\xdb\xa4\xeaZ\xdd\x9bh\xab\xcc\xc3\x1bX\xee\xe4\n^\xae\x10\xc6\xe4\x01\x8a\xc4\xf3}\x99\xe3\xfb2\xbf\xf7en\xef\xb7x\xbd/uz_\xea\xf3\xbe\xd4\xe5}\xa9\xc7\xfbR\x87\xf7\xa5\xfe\xeeK\xdd\xdd\x97z\xbb/uv_\xea\xeb\xbe\xd4\xd5}\xa9\xa7\xfbrG\xf7[\xfd\xdc?\xc2\xcd}%/\xf7\xd5\x9d\x1c\xf6g,\xf3g,\xf3g,\xf3g,\xf3g\xdc\xe2\xcfX\xea\xcfX\xea\xcfX\xea\xcfX\xea\xcfX\xea\xcfX\xea\xcfX\xea\xcfX\xea\xcfX\xea\xcfX\xea\xcfX\xea\xcfX\xea\xcfX\xee\xcf\xb8\xd5\x9f\xf1\x11\xfe\x8c\x95\xfc\x19S\xfeL!\xc2\x0d\x8a\x178\xdcj\x1b/\xf1\xe6\x18\x1d\xaa\x07\xe7\xe5\x03\x01|\xe5\xb9.\n\x1at\xf1\xbb\x00\x9c8q\x88q\x03.~\x17\x80\xf3H\xaa\x86\xf2;\x1b5p\xc7\xc9\xac\xedZ\xa4\xde\xb1rk;\xb9\xe4;Vvm'\x97~G\xcb\xaf\xedd-\xd8\xf3-\xd8\xb7\xb4`\xcf\xb5`/o\xc1\x9ek\xc1^\xde\x82=\xd3\x82\xfdi\x01-\xebXY\xe8p\x94oQ\x04\n\xeeE\xe1[=\x8cB\xab8\x19I\xa0\xecg\x0c\x91\x92\xab14\n\xde\xc6P\xa88\x1cE\xa2\xeas\x0c\x91\x92\xdb14\n\x9e\xc7P(\xcc\xc1\xaa\x81&\xe7\x92\xfe\x91\x1e\xe9\x1f\xe7\x90\xfe1\xfe\xe8\x1f\xe9\x8e\xfe \xde\xe8\x1f\xef\x8c\xfe\xb1\xbe\xe8\x1f\xed\x8a\xfe \x9e\xe8\x1f\xef\x88\xfe\xb1~\xe8\x1f\xe9\x86*\x1e\x87\x8f\xf48|\x9c\xc7\x1d3\xc7\x92`%\x8f\xc3'x\x1c>\xde\xe3\x8e\x9dki\x02%\x8f\xc3'x\x1c>\xde\xe3\x8e\x9dsi\x02 XKR;\xf5\x9cCq\x055\xcc\xdf\x8d\x91\xb2\xb7Ob\x84\xf3;\xa2\x0d\xaazB\xe3\xecy\x12\xe2uJ\xe0\xaa'4\xae\xf8\xa8~\x0d\xca\x7fU\x18\x8e\x0f\x80\xe0\xd9\xc8\xae$;\x05\x94\x8bOA%-\xa0pE#\x14Z\xa10\xa9\x94M\xf3\x15[\xe6+7\xccWk\x97\x7f\\\xb3\xc4-\xc0\x8a-\xc0\xca-\xc0j-\xc0\\\x0b\xe8N\x92'r\xc3\xc8v\xbct\xcf\xbdu@\x1b7e\xdd1[8\"\n\xd9\xbb\xe9\xda\x90(d/\xc1k\x03\xa2\x90\xbdm\xafYD!{\xad_\xeb\x13\x85\xec\xfb\x034\x93(d_T\xa0\xf5\x88B\xf6\x8d\x08\x9aA\x14rJ\xd0\xad\xa6P\xe7$\xd2{d1{0\"\xd4\x1a\xce\xccy\xfb8L\xed\x14i}\x8b>o\xb0\x08c\xff\xbc(\xfb\xb1o\xb9h\xf9\xd3D\xf0\x1cd7\xd6\xc5\xec\xc6:\xcc\xaex\x0e\xb23L\x89x\x86)\x90\xaf,\x809\x8e$\x12\x1a#\x81\x88e\x01\xc8\xb1\xd7\x93\xc8\xd8\xeb d,\x0b`\x8eC\x89\x8c\xbd\xa1@\xc6\xb2\x00\xe4h\x1a\x12\x19MC cY\xa00\x96\x1e`\xd7\xd2\x88\x0f\x1c<\x8fwI9\x9e\xe6`R\x96\xa7\xfa\x98\x9c\xe9\x89n&ez\xaa\xa7\xc9\x99\x9e\xe8lR\xa6\xad\xfe\xa6\xe0p\n\x93w\xe3\x85\xfes;\xa1\x84\xe1\x89>(\xe1x\xb2\x0b\xcax\x9e\xea\x81\x12\x9e';\xa0\x8c\xe7\xa9\xfe'\xe1\xf9D\xf7\x93z\x1a~nO\x930<\xd1\xd3$\x1cO\xf64\x19\xcfS=M\xc2\xf3dO\x93\xf1<\xd5\xd3$<\xdb=\x8db:\xc7\xb6\xf3\x90EP\xf9y\xce\xf3x9\xb7\x7f\xd4\xcf\xb2?\xdd\xf1O\x10t\x04AG t\x08A\x87 t\x00A\x07 \xd4\x82\xa0\x16\x08\xedC\xd0>\x085!\xa8 B{\x10\xb4\x07B\x0d\x08j\x80P\xdd\x02\xa0:\xdb\xae\xed\xca+\x02\xde\x02\xbbJp\x8e}qf\xe8\xfa\x0b\xded\x05|$\x82\xb3f+\xe0C\x11\x9c5]\x01\x1f\x88\xe0\xac\xf9\n\xb8%\x82\xc3M\xed\x8b\xe0\xac\x19\x0b\xb8)\x82\xb3\xa6,\xe0=\x11\x9c5g\x017Dp\xd0\xa4%\xf6\xaf:{\x93:@v\xacQ\x10\xc3`V`\xae\x1d?h\xcb\xd8\xdeW\x08\xd3dVw\xbe\xe7R\x00\xcbb\x96ad\xe1p\xc8\xacG\x13\x0foP\\\x15s\xefB\xc3\xf95\x0b\x1ad\xdb6#A\x18\x06\x94\x08\x8e\xe3@lH\x08B\x08\xd0E\xae\xdd\n\xb2\xe8g\x7f\x00\xf5\xd7\x80\xc5\x02PV\x8c\xdc\xba\x92\xa1\xde\xd7\x19\x0cQ\xbcX\xf4\x0ds\x00IJ\x81\x86=\x8biN\x18\xdb\xc1\x92\x10c\xc0]\xe9_\x86\x98\xe00\xe7\xae\xd9\xef\x11\xc6\xe1\xb6Dd`H\n\n\xf4\xd7\xc5|a\xd8\x8cy\xa2u\x1c\xe1Z\x10\x0b\xf5\x1c\x9b\xbd\x9c\x90s\xa2qv\x7f`.z\x80\xea\"/\xa8=\xd1\xb5t}\xc4\xe8n\x15\xa6\x14&S\xe0\x9c\xb1\x10]>\xd2aW\xa0Q\xb6\xe9\x0eA\xb7G(\xa8{\x869\x1cZ=\xd6\xb3I\xc0\xd8\x1e\x0f\xfb\xb0\xdf\x11\xb01Bs\x87iW`o\xf6M'5\xe6\xfd> \xcd\x1c\xafQ\x03\xea\xf7\xc7\xec\xcb\n\x88r\xd3\x1a\"\x17\xb4)\x89\x1a\x0f\x1c\x87u\xe1\x1c\x85\x12\x1a\xe8\xb8\x88\x03n\xedd\x85\\\n\xb6\x18,\x16\x0b\x04\xc2(\x15\xa0\xd1\xc2]X \x8eq\xb9\xc5\xc2As\x10H\xf5\x10w\xe1ro'\xc3a\\_\xb1/\x80\xd5-AZkK\xad\x8e<\xe6\xb6\xf3\xb0,\xde\x91ZPH\x83\x90\x8ap\xd4B\xc8\x85$\x15\xe1\xb0\x85\x90\x0bP*\xc2A\x0b!\x17\xaeT\x84V\x0b!\x17\xbcT\x84\xfd\x16B.\x94\xa9\x08\xcd\x16B.\xb0\xa9\x08{-\x84\\\x98S\x11\x1a-\x84\xdc\x0cY\x11\xea\x96\x9c\x90\x0b\x81\xe6K\xad\x8e\x828\xca\xb6\x80\xa8&\x86\xdc\xa7-<\xaa\x89!\x17j\x0b\x96jb\xc8\x8d\xdaB\xa7\x9a\x18r\xa5\xb6@\xaa&\x86\xdc\xa9-\xac\xaa\x89!\x97j\x0b\xb2jb\xc8\xad\xdaB\xae\x9a\x18r\xad\xd6\x00\xact/\x9e\x92\x0f\xc7\xe6K\x8d\x88\xc8x\x02.8\x9b/\xb5&>\xe3\xf1\\\xa86_ju\xb4\xc6\xc3\xb9\xc0m\xbe\x14A\xb90n\xbe\xac\x824\x1e\xcc\x05u\xf3\xa5F\xc5u< \x17\xe2e\x92\xd7Q\x1e\x8f\xe7\x02\xbe\xba\n\x01\x01\x17\xfeU\xba/\x02<\x9e\x00\n\x06+\xc7\x80\xe0\xect9_\x16+\xe4\xc8\x8eQ\x90\xf2\x14D!l\xe3l\xc2\x03\xda\x01D\x98\xf3\xa5\x00\x0c\xc5\x9b\xb5\xa2D$|\xf49_je\x00\n\xe1\xf9X4s\xa3,\x1c\x85\xd0|d:_VA\x00\x87\xe7\xe3\xd4Zz\x11 \x18\xb5\xce\x97U@\nt\x02 \x86\xadk\x11RA\x11me\xb8<\xd4\xe4I\xa0\xf8v\xbe\xd4\xea\x10\x176\x1f\x1b\xedfM\x11\xa1\xf9\xd8\xb7i\x88\x88\x86\x8f\x84\x9b1&\x8b\xe0\x80A \x88\x8b\xf3\x81C\x00\x07\xa2d\xa2\xb3\xc2DP\xcc\x9cu\xd8,l\x86\xc6U>\x82\xaeZ\x91\x87\xab\x10 \x10O/Eh(\xba\xae\xdb \xa0\x81b\xed\x8a\xa6\x0e\xb7\x81\x81\x0d\x88\xbc\xb3a\x87\x08\xbe\x013\x02qxC$R2\x14\x957T\xe2\x0e\x06\xc4\xe8\x0d\x99hT\xe1#\xf6\xf9\xb2\x0e\xd79\x020r\xcf\xef\x97\x17s%t\x07\x9d,\xce\x7fn\xd6N\xec\xbb\xd7rd3\xf3\x8a\xb9\x11\x18\x8a%71\x17\xf0zn\x16sl \x14Cn\xe6.\xd0\xd5\xe4-\xe6W#(v\xdc\xcc^\x80\xe5\xacx6\xdc\xac_\x00\x8bY\\\xcc\xa8,\xa7Xq1A\x01%\xc3\x021C\nE\xb1\xe5\xe2\x86R+U\xe8 Q\\\x0d\xa1\x18r\x81\x05)\x81\x9c#\x81\xa1Xr\xa1\x07\xe1[y8\xd1\xe2\x7f\x05\x86b \x05'\x05E\x0bC\x88\x17;\xdc\x10\x1dI\x1b\xeb-]-C\x90\xecd+h\x92l\xd4\xcax$f\xcc.\x8fH\xb2a+\xe3\xa1\x981\xbbt\"\xc9\x06\xad\x8c\x07b\xc6\xec\xb2\x8a$\xb3Z\x19[b\xc6\xec\x92\x8b$\xeb\xb72\xee\x8b\x19\xb3\xcb1\x92\xcclel\x8a\x19\xb3K5\x92\xac\xd7\xca\xb8'f\xcc.\xe3H2\xa3\x95\xb1!f\xcc.\xf1\x88\xae$\xed 5\x82d\xdc\x96' Ie\x9d\xa4F\xc8\x98\xc3\x1d\xa5J%\xb41\x1f\xca\x99\xc3\x9d\xa5J5\xb41\x1f\xc8\x99\xc3\x1d\xa6JE\xb41\xb7\xe4\xcc\xe1NS\xa5*\xda\x98\xf7\xe5\xcc\xe1\x8eS\xa52\xda\x98\x9br\xe6p\xe7\xa9R\x1dm\xcc{r\xe6p\x07\xaaR!m\xcc\x0d9s\xb8\x13\x95\x81\x9e\x98w\x05 Y\xcb\xa2\xc3e[HW#\n\x8e\xd0\xd2\x00\x0c\x17\xa9\\\x8d\x94=\x174\x02\x8b\"8~$\xd3;\xd2*\xd8(\x12X\xb2\xc0\x01%\x91\x10\x92V\xc0\x84\x95\xc0\xb2\x19\x8e0\xcb\x0c\x92\x94\xb7\x94\xaf \xe4\xac\xd3MR\xceT\x84\x08,\xc9\xe0\x18\x94\xc9NIk\x00\"Q 9\x00\x07\xa5dJK\xae|&4\x05V\x89p\x94J%\xc1\x14\xda!\xadC\x10\xb6Ry\xb3\xf6~@\x06\x9c\xc0\xbaP\x18\xc7V\xa96i\x0d-\xcc\x05\x81-\x95\x98\x93\xf2'q\x82Z\x84i\xbc\x9a\x89B \xbddci\xae\x1a\x85\xb0z\xa9\x12Y/\xd9\xe0ZZ\x93 \xce^\xaa\x84\xdaK6\xda\x96\xd6$\x08\xbc\x97*\xb1\xf7\x92\x0d\xbf\xa55 \"\xf1\xa5J0\xbed\xe3qiM\x82\xd0|\xa9\x12\x9d/\xd9\x00]Z\x93 V_\xaa\x84\xebK6b\x97\xd6$\x08\xde\x97*\xf1\xfb\x92\x0d\xe1\xa55 \xa2\xf9\xa5J@\xbfdcziMpdBl\xf6\xb5\x8fA\x92\x9e\xab\x16\xef\x13\xbb\x83\n\xb5\x89{\xaf\xda\x02\x80\xd8NT\xa8M\xdc\x83\xd5V\x04\xc4\xfe\xa3Bm\xe2^\xac\xb6D 6,\x15j\x13\xf7d\xb55\x03\xb1\xc3\xa9P\x9b\xb87\xab-\"\x88-Q\x85\xda\xc4=ZmUA\xec\xa1*\xd4&\xee\xd5j\xcb\x0cb\xd3U\xa16q\xcfV[wT;l\xe2\xaajDQO\x15\x14\x01\xdbo\x05^\xca\x8c\xe3\x03\xed\xcc\x15\xd0zsN\xcc\xad\x810<\xf9\xad\xbb\x82\xa0\xd8\xbd\x133,\xcb\x19n\xfc\xc6^\x81^\x86X\"\\^\xcap\xe27\xfd\nl\xb1\xc7 \xe6U\x96\x93\xdc\xf8-AR'm\x0c)\x14-$\xb0mX\xd0\x14{\x80b\x9ee9\xc5\x0d\xdaT$%h\xe3I\xa1(\xce\xd0\xc6#\xe1\xb0\x91\xe0\x05\xbd,\x84\xe2 \x9f\xbc\xcb\x08\xaa\xcdI1\xcb\x1a\xc1\xb97\xbbsYjK\xca\x0d\xe2\xc4\xefjR:\x92\xf2#0\x0cW~\xdf\x93PQ\xbec\xd6\xa2\xc6\x02Cq\x85vF\xcbN!g\x08\xf1\x02\xb6M\xc96\xb5p$A\x14_hg\xb5 \xec\x8dd\xcd\x98\x97R\x9c\xa0]WB?s\xbc\x968x\x03ax\xf2\xdb\xb2\x05\x81\x9c\x1d\xcf \xda\xb2%U#\xe7G`h\xed\x01\x9b\xba\x04E\xb5\xaf\xdb\xc2\xb8\x86Q\xbc\xa1\x9d\xdf\x82\x88\xd8\xfc\x15s&A\xb4\xaf\x03\x9b\xc3\x14I\x8b+Q(\x8a3\xb4\x81L\xd1\xb4\x0d\xc74\x8c\x96\x1a\xd8e\xa6\x88\xa43$\x81a\xb8\xf2\xfb\xd0\xa5\x07-\x15b\x02\x12T\xf0\x05\xd2&\xc2\x08\xa18\xa6#\xe5.c,\x0e\x19\xc8#=R\xf6l\xe0\x00U\"\x8a!\xeaC@\xd2\x1a\xa8H\x02b/\n*\xca3CR\xe6Dh\x01\xb1\x16E\x19\xf5\x01#)s\xca 9\xf6\xa2\xb0\x839\x8f\xa4\xa0}y=\x928\xa4>\xc4$\xad\x84\x8a\x19x\xf6\xe2\xc0\x849\xf3\xa4\xd0\x92\x96\xaa\xc4\x91\nyP\xaa\xbd\xb3\x11\xb37_\x898t!\x8eVI\xeb`\x02\x18\xb8\xdf\xc1\xb1Ly\x16Kn\x0f9kQpC\x1d\xdcR\xb1\x85\xbc\x1aQ\xb4C\x9d\xf5j7\x059\x07\xf0\xd5\x88\xc3\x9f\xeax\x98\xbcw\xcb\x99\x0b\xe3!\xfa0\x99\x82\xae\xe4\x15\x89\x03\xa4\xf2\x00\x9a\xb4\x06\"L\xe2Y\x8b#&\xf2\xb4Z\xbb\x19\x889\x1e\xaaD\x18B-\xdb\xf9KY\x8bc*\xea0\x9c\x82 \xa4\xd5\x88\x83,\xf6\xfc\\{ML\xa8\xc5W&\x8e\xba\xe8Sw\xd2\xaa\xf8\xd8\x0b\xe8\x84\xc20\x8c9\xa9\xa7R\x93\xdc\x85\xc5q\x19{\xbcO\xa5\xae\xb6 K\x18\xa8Q\x87\x02Uj\x92\x07&\x92\xc8\xadu\x17\x99\xc0\x08*\x00\xf7\x94#[?\x08\xbe\xdf\x1a\xd9F]\xd4\xedY\xdc{j#\xbb\xd7\x94C\xc5f]\xcc\xbfY7\xb2\xfbu)\xffj\xdd\xc8\xb6\xeaR\xfe\xdd\xba\x91=\xa8K\xf9\x97\xebF\xf6\xb0\xa9\x97\x7f\xbbn\x84\xeb\x06k\x18-R\xae\xd5\xd8\xa0\xcb\xc1\xa6\xe3\x1e\x03\x820&\x8d\x01\x94\x80\xfb4\x04\xd0\x04\xb6h\x08\xa0\x0e<\xa0!\x80N\xf0\x90\x91\x05PL\xdc(&\xce\x06\x16N3\xb1\xc1\x00@\xd5\xc4=\x16\x05\x81L\x06\x04('\xee3\x18@;\xb1\xc5`\x00\xf5\xc4\x03\x06\x03\xe8'\x1e\xb2\xf2\x00\n\x9a7\n\x9a\x87i\x1a\xfa\x9c\x86\xe6\x06\x8b\x00U4\xefq0\x08e\xb2(@I\xf3>\x0b\x02\xb44\xb7X\x10\xa0\xa6\xf9\x80\x05\x01z\x9a\x0f9\x99\x00E\xa5\x8d\xa2\xd20\xe2\xb4\x94\x1aT1\xa8\xa2\xb4Gc \x88IA\x00\xe5\xa4}\n\x01h&\xb5(\x04\xa0\x96t@!\x00\x9d\xa4CZ\x0e@!\x1bF!\x93\x16?\xda@\x1ab\x89@\xbdm\x00\xbdq\x84\x10\x1d\xafL\x96\x0cP\xf0\x86W0K\x05(}\xc3+\x9d\xa5\x02\x0c\xb1\xe1\x0d\xc1R\x01\xc6\xd9\x00\xc6\xe1\x1a\x06Xl\xc5\xce\x125\x11<6\xae\xc0Y\x83!\x02-\xb6\x82\xa6\x12\x96\x10\xa2\x03\xa6\x17\x86\x0c\xb0\xd8\n\x98q\x18*\xc0b+`\x12b\xa8\x00\x8b\xad\x80y\x89\xa1\x02,\xb6\x82\xa6*\xb6a\xc0\xc7\x85l\xfd\xe0\xdb\xf1\xd2\x0bX\xdb\xf8\xb6Q\x95@\x06\xf0\xed^]\x0c\x95\x9aU)\xf0\x95'\xbb_\x15\x02\x9fU\xb2\xad\xaa\x10\xf8Z\x92=\xa8\n\x81\xaf-\xd9\xc3\xbaN\xa0\xa1\xb8j(\x18\xbf\xf8\xd8\xa0\x8a\xc1&\xe3\x1e\x8d\x81 &\x05\x01\x1a\x8f\xfb\x14\x02\xd0\x00\xb6(\x04\xa0\x06<\xa0\x10\x80.\xf0\x90\x96\x03PH\\+\x04\xec\x9b~l\xd0\xe5\xa0J\xe2\x1e\x03\x820&\x8d\x01\x94\x12\xf7i\x08\xa0\x95\xd8\xa2!\x80Z\xe2\x01\x0d\x01\xf4\x12\x0f\x19Y\x00\xc5\xcck\xc5\xc0\xf3\x8c?7\x18\x00\xa8\x9ay\x8fEA \x93\x01\x01\xca\x99\xf7\x19\x0c\xa0\x9d\xb9\xc5`\x00\xf5\xcc\x07\x0c\x06\xd0\xcf|\xc8\xca\x03((\xad\x15\x04\xc4)~j\x90\xa5\xa0j\xd2\x1e\x05\x81\x10&\x89\x00\x94\x92\xf6I\x00\xa0\x91\xd4\"\x01\x80:\xd2\x01 \x00t\x91\x0e)\x19\x00ElhEL\xe4n\xb3\x01\x143Qp\xa4\x0d\xaf-\x96\x0c\xa2\xe248i\xf5\xb4\x0d\xa7\xd4I\xab\xe7m8=OZ=q\xc3\xa9~\xd2\xea\x99\x1b\xde\x1al\x83\x00\x0b\xad\x98Q\xbf\"\x81\x87\xbc\x154 \xd0$\xa0\x85V\xc0\xc4\xc0\x90AT\xfc\\A\x13\x01\x16Z\xf1\xb3\x07M\x03Xh\xc5\xcf'4\x0d`\xa1\x15?\xc3\xd04\x80\x85V\xc0\x9c\xc34(\xb7P\xfb[-\xe9\xd7\nFv\xfer\xce2\x96\x01\xf2-d\xa9 \xe5BA \x84I\"\xc0\xc4\x0b \x00s/$\x00L\xbf\x90\x000\x03C\xc9\x00&a\x08\x84(\x0f\xc3A\x04\xa9\x18\x1e\x07\xc1L\x0e\x06&d8\x14\x98\x93\xe1P`Z\x86C\x81\x99\x19^.09C\xc2D\xf9\x19\x1e#H\xd1\x00@\x08g\xf280Q\xc3\xc3\xc0\\\x0d\x0f\x03\xd35<\x0c\xcc\xd8\x00\xb2\x81I\x1b\x12'\xcc\xdb\x00 A\xea\x06BB@\x13\x00\x82 \x1c\x00\x07\xe6p\x00\x1c\x98\xc6\x01p`&\x07\x92\x0fL\xe6\x90@8\x9f\xc3\"\x04)\x1d\x0e\x06\xa1L\x16\x05&vX\x10\x98\xdbaA`z\x87\x05\x81\x19\x1eN&0\xc9\xc3)\xaa=\xcf\x03kN1\xd5\x03\xeaS-\xdb\x03)Y)\xe1\x03)^)\xe7\x03\x19C)\xed\x03\x19H)\xf3\x03\x1aM-\xf9C\x92*\xe6\x7f8\x92cR@<1D\x0b\x91\xc2\xd3\x9aJ\"\x88#T\xcd\x05q\x84\xaa\xe9 \x8eP5#\xc4\xb7Q9)\xa4\xe5\xdfs\x8f\xe1\xbc\x10Q(H\x0d\x91\x08\x08`\x12\x000AD\x94\x839\"\xa2\x1cL\x13\x11\xe5`\xa6\x88\xac\x1fL\x165\x00Q\xbe\x88E\x08RF\x1c\x0cB\x99,\nL\x1c\xb1 0w\xc4\x82\xc0\xf4\x11\x0b\x023H\x9cL`\x12\x89@\x89\xf2H\x1cD\x90J\xe2q\x10\xcc\xe4``B\x89C\x819%\x0e\x05\xa6\x958\x14\x98Y\xe2\xe5\x02\x93K\x04L\x98_\xe21\x82\x14\x13\x00\x84p&\x8f\x03\x13M<\x0c\xcc5\xf100\xdd\xc4\xc3\xc0\x8c\x13 \x1b\x98t\"pp\xde\x89\x01\x08RO,\n\x02\x99\x0c\x08L@1\x180\x07\xc5`\xc04\x14\x83\x013Q\xac<`2\x8aUPk>\nT\x98ZJ\n\xd2\xa2RV\n\xd0\xacJb\nP\xb6Jn\n\xd0\xbfJz\n0\x89J\x86\n\xb2\x92R\x92\x8a T\xcbS\xb1\x04G\xa4\xaa8R\x80\x12\"\x04\xe7(\x85\x84\x15K\xa6\x98\xb3b\xc9\x14\xd3V,\x99b\xe6\x8ak\x9b(y\xa5\x90\xbdR\xf8&Kd\xeb\x9a_\xc5fPF\xab)\x14%\xb4\x08\x04\x040 \x00\x9c\xcej\xca\xe1lVS\x0e'\xb3\x9ar8\x97E\xd4\x0f\xa7\xb2|f\xad\xc0\"\x0c\x16!Jd\xb10\x08e\xb2(8\x8d\xe5\xf3\xb1=\x0b\xb2X\x10\x9c\xc4\xf2\xf9\x98\x9d\x05\x0d9\x99\xe0\x14V\x83\x12f\xb0X\x88(\x81\xc5\xe1 \x98\xc9\xc1\xe0\xf4\x15\x8b\x82\xb3W,\nN^\xb1(8w\xc5\xc9\x05\xa7\xae\x1a\x988s\xc5aD\x89+\x1e\x08\xe1L\x1e\x07\xa7\xad8\x18\x9c\xb5\xe2`p\xd2\x8a\x83\xc19+^68e\xd5\xe0\x04\x19+\x1a JX1(\x08d2 8]Ec\xe0l\x15\x8d\x81\x93U4\x06\xceU1\xf2\xc0\xa9*FA\n\x99*Hc\xaa\x89*@\x8f\x8ay*^\xb9ji*^\xe1jY*\xde\x08jI*\xde0j9*\xc0X\x8a)\xaa\x86R5C\xc5P\x1c\x95\xa0bi!R\x88\x12\x9c\xae\x94\xd2S\x0c\x9drv\x8a\xa1SNN1t\xca\xb9)\xb6}\xea\xa9)\xbf\x8c\xd4\xa0\xccT]&JL5\x00\xa8\xdcl\xca\xe1\xb4T]\x0cg\xa5\xeab8)U\x17\xc39\xa9\xa6n8%\xe5\xd3k\x04\x16`0\x00QB\xca\xe7\xc3\x7f\x16d2 8\x1d\xe5sq=\x8b\xb1\x18\x0c\x9c\x8c\xf2\xb9\x88\x9d\xc5\x0cYy\xe0TT\x0d\x12f\xa2\x18\x84(\x11\xc5\xc2 \x94\xc9\xa2\xe04\x14\x03\x82\xb3P\x0c\x08NB1 8\x07\xc5\xca\x04\xa7\xa0j\x948\x03\xc5BD (\x0e\x07\xc1L\x0e\x06\xa7\x9fX\x14\x9c}bQp\xf2\x89E\xc1\xb9'N.8\xf5T\xc3\x04\x99'\xaa\\\x94x\xa2A\x10\xc6\xa41p\xda\x89\x82\xc0Y'\n\x02'\x9d(\x08\x9cs\xa2e\x81SN\xb4b\xda3N\x80\xa2\x14\x13N\xbc\xf6\xd4\xf2M\x9cF\x95\xd2M\x9c\x92\x95\xb2M\x9c\xde\x95\x92M\x9c)\x94rM\xbcu\xd4RM5\x9db\xa6\x89\xc6\x1f\x93hb(\x01B\x88\x0e\x9a{T\xd2L4\x95j\x96\x89\xa6RM2\xd1T\xaa9&\xa6]\xa7\xa5\x98\x04\xd9$\\\x85SP6\xa9)\x14e\x93\x08\x04\x040 \x00\x9cMj\xca\xe1lRS\x0eg\x93\x9ar8\x9bD\xd4\x0fg\x930\x13\xd7\xb3\x08\x83E\x88\xb2I,\x0cB\x99,\n\xce&a>\x16gA\x16\x0b\x82\xb3I\x98\x8f\xb2Y\xd0\x90\x93 \xce&5(a6\x89\x85\x88\xb2I\x1c\x0e\x82\x99\x1c\x0c\xce&\xb1(8\x9b\xc4\xa2\xe0l\x12\x8b\x82\xb3I\x9c\\p6\xa9\x81\x89\xb3I\x1cF\x94M\xe2\x81\x10\xce\xe4qp6\x89\x83\xc1\xd9$\x0e\x06g\x938\x18\x9cM\xe2e\x83\xb3I\x0dN\x90M\xa2\x01\xa2l\x12\x83\x82@&\x03\x82\xb3I4\x06\xce&\xd1\x188\x9bDc\xe0l\x12#\x0f\x9cMb\x14\xa4\x90M\x824\xa6\x9aM\x02\xf4\xa8\x98M\xe2\x95\xab\x96M\xe2\x15\xae\x96M\xe2\x8d\xa0\x96M\xe2\x0d\xa3\x96M\x02\x8c\xa5\x98Mj(U\xb3I\x0c\xc5Q\xd9$\x96\x16\"\x85(\xc1\xe9J)\x9b\xc4\xd0)g\x93\x18:\xe5l\x12C\xa7\x9cMb\xdb\xa7\x9eM\xc2eP\x06e\x93\xea2Q6\xa9\x01@\xe5fS\x0eg\x93\xeab8\x9bT\x17\xc3\xd9\xa4\xba\x18\xce&5u\xc3\xd9$L\xaf\x03X\x80\xc1\x00D\xd9$\xcc\x07\xf9,\xc8d@p6 s\xf1;\x8b\xb1\x18\x0c\x9cM\xc2\\l\xceb\x86\xac{U\x1fl?w\x15\x1fV\x00w\x17\x1f\xd4\x00w\x19\x1fR\x01w\x1b\x1f\xd2\x01w\x1d\x1fR\x02w\x1f\x1f\xd2\x02w!\x1fT\x03}\xe7\x1e\xd6\x01}\xe9\x1eT\x00}\xeb\x1ej=}\xed\x1ej:}\xef\x1ej7}\xf1\x1ej4}\xf3\xbelq\xfb\xc1\xcb\x033f\x90\x17UD\xa3\x1d\x05\x01\x07<\x12\x01\x8ey$\x00\x1c\xf6H\x008\xf2\x91\x00p\xf0\xa3d\x00\xc7?\xf6\x00\xabh\x08\xe4q\xe0(\xc8\xc1\xc0\x81\x90C\x81c!\x87\x02\x87C\x0e\x05\x8e\x88\xbc\\\xe0\xa0H\xc0\xe4\xe3\"\x00\x04\x87F\x1e\x07\x8e\x8e<\x0c\x1c y\x188F\xf20p\x98\x04d\x03GJ\x02\xd72XBHp\xbc\x04\x80\xe0\x90 \xe0\xc0Q\x13\xc0\x81\x03'\x80\x03\xc7NH>p\xf8$\x80\xb2\x11\x94\x83\x81\x83(\x8b\x02\xc7Q\x16\x04\x0e\xa5,\x08\x1cMY\x108\xa0r2)l5\xaa\x9ef\x0f\xc8\x83W\xc2\x81\x96@\xc0\xe3l\x03\x80\x87\xd9\xa6\x1c\x1ee\x9brx\x90m\xca\xe11\x96\xa8\x1f\x1eb\xe9\xfd[\xe1\x08\xcb\xc2\xe0\x01\x96A\xc1\xe3+\x03\x82\x87W\x06\x04\x8f\xae\x0c\x08\x1e\\Y\x99\xe0\xb1\xd5gF\x1b\xd1\xd0\xca\xe1\xe0\x91\x95\x85\xc1\x03+\x8b\x82\xc7U\x16\x05\x0f\xab,\n\x1eU9\xb9\xe0A\xd5g\x07\x18\xd1\x98\xca\x03\xe1!\x95\xc3\xc1#*\x07\x83\x07T\x0e\x06\x8f\xa7\x1c\x0c\x1eNy\xd9\xe0\xd1\xd4\xa7\xc6\x1a\xd1`\xca\xa0\xe0\xb1\x94\x06\xc1C)\x8d\x81GR\x1a\x03\x0f\xa44\x06\x1eG\x19y\x14\x86Q\xc1\x88\x89\xeb\xe1F4b\x12\x08x\xc4l\x00\xf0\x88\xd9\x94\xc3#fS\x0e\x8f\x98M9\x96\xdc\xca\x05\xfajr\xc1\xa8\x10\xa6\x95C\xdb7\x12Kf\xae\x1d?\xb4\xf2\x92}I5\xe3\xf3\x80\x0e)\xda\xa5\x9a\x8b\x9c0\xb6S/\x0c\xce\xb1\x17 -]\xc5\xe1z\xb9\xa2 \xd6\x81\x8b\xe2\xac\x98\xa3\xa9K\x18\xc7\x0b51M\x10\x06Ha\xe9s\x00d\xce\xd6Q'\x88\x0d\x91)H\x0e\x91\xe5\xc2+H\xaf\xb0p+\x9b\xe4\x9f\xd4\"\x9eJ\xa5A<\x95B{\xc4\xa2\xe3\x93D\xe7\xa9TD\xe7\xa9\n\xd1)\x8a\xb4D\xd9\xd8[\x06\xe7YT\xc0\x94\xc7dy>Q2\x00\x87\x048(HQ\xac`\xed\x03#E\xed9bA\x18\x08(\x0b\x83)\xc5Q\x90G\xc1\xfbR\\y\x83DF\xbf]D\xffh aaZ-G#`a0$\x0c\x0d\xaa,\x9c\x7f!~\x11\xc6\xfe\xb9cG^jc\xef\x11\xb1P\xccBq\xb8E\xb1c'\x1cr\xcd\"\xd7Q\x04#\x03\x16y\xd2p\x98\x12\xce\xa1\xd4\x12\x00-n\x0c\x00\x16\xb7\x07\x00+\x0c*\xcan\xda\xb8\x98Z;9\xb0\xa4\x99\x1cV\xd2J\x0e\xab\xd0HA{8\xb7\x92\xb5\xe7\x08\x1f\xe4\xb1\x92\xf6pX`8]h\x833\xe6\xc1\n\xd9n>\xab/\xc2 \x8b\xf5\x1e\xd19\x1fR/4\x8b\xa5K\xd6s\x80\x94\x0f\xa1\x17\x06Ql\xf2\xc5=\xa2\xb8\x07\x05\xea\x0b\x93@\x18@\x90\xbe\xe8S\x00\x88\x85E\"\xf8\xe2\x01Q\xdc\x1d\x0d\x01\x06C\x12Q\x00\xda{\xc3\x81\xd5\xbd\x16$\"\xf5g\x9d\xae\xc5\x02\x005a\x04\x9a\x01d\x07\x1a\x01\x99\x82F\x08\xacA\x83`\x83\xb0\x18\xd0&\x0c\x080\x0b\x8d\x10X\x86\x01\x15\x18\x05\xeb(\x8cU\x99\xc9|\xa1\xc5\xfcV\x83q\xb4\xa4\xbd\xfc6s\xf9m\xd6\xf2\x15\x8c\xe5\xb7\xdb\xcaW0\x95\xdff)_\xc1P\xfe\xb1v\x12\x98\x04\x0bM\x82[M\xc2\xd1\x92&\xc1m&\xc1m&\xc1\n&\xc1\xed&\xc1\n&\xc1m&\xc1\n&\xc1\x80I(\x8c\x8f\xecd\x1d\xa3C\xd3O\xb2\xce\x03b\xb2r\n\xd8\x17\x01\x03;\x8e\xc3-\x01\xedq<\xbd\xc0EAZLi\xc5\xcf\xe7Fs\"+m?\xcf\x98\xf86\xc6\x9acG\xe5\xe8\xb0\xb1c\xcf\x0e\xd2\xf3\xe69\x8dO\xe3u\xe0\xd8):\xe4\xc9\x81<5\x82\xce\x83p\x1b\xdb\xd1$\xdc\xa0x\x91\x7f\x9c\xcfs]\x14Lr\xa9\xea\x87\x08c/J\xbcDa\xcc9\xc0\xeaH\x94\xd5\xcb`[4L\xa3EJ\xae\xe3\xbd'\xea\xb9\x1e\x88UU\x9d\x11\x9c\xaem\x05u+\x0c\xf1\x95\xc2|u\x13\xf8\xc7X\xc0W1\x80\xff<\xfa\xf7\x8fT\xbf\xff\xdd\xb4/Q4VW4>F\xd1XE\xd1\xf8y\x14\x8d\x8fT4~\x8a\xa2)\x96U\xb9\xe6\x84Aj{\x01\x8a\x0f\xf5\xa3\xfdy\xe2\xc4!\xc64E\xb1h\xa6\xb7\x12\xecu\x1aN\xc8\x9d\x96\xec\x01\xa3\xddX\xcb\x1e\xf2t\x0c\x0cS\xb0\x86Y{\xe7<\x00bj\xec\xd9\x1buIARPX\x8d9\xf4\x94\x03\x15\x04V\x18M\xcaV\xf8'7\x02\xa0\x84\xdb\xe0\x1f\xdb\x04\xb1\xb4\xf8di\x01JXZ\x0cHK\x8b\x82\xbd\xe8\x10\x85\x89\x97'\x02\x17\xde\x0e\xb9\xff\xd7\xf3\xa30N\xed \x9d\xfcQ\x97\xd8\xf3$\xc4\xeb\x14\x11\x85\x19\xe9y\x8c\x9c\xf4G#\xdau\x88\xbf?\xd1Eg\xc4\xdf\x9f\x14\xcc}\xe0\x04\xcc\x1c\xe7\xcf\x94QAH\x15\x9f\xcc$\xf7\xff\x83\x04\x17\xc9\x88\xff\\\x19)\x01\xb6\x89\x16\x84\xb1o\xb3#u\xf6\x88F\x16\xa370\xa0\xd3\xb0(\xa6#\xc9(>>'X\x0b\xc5\x07J\"\xb9\xe0\x90\x8a\x13\x8d\x85e\xd2)\x88\xa7\xe0m\x8d\xcclt!\x14\x19\nCx\x89\xfd#\x05\x96\xca\xa6jfp\xe6\xe6e\xc3\xbcl\x14f\xa3\xcd\xed\x04\x1d6(N=\xc7\xc6e:;{\xc6\xef\x91l4\xdfsY\xa8\xef\xb9.\xe6\x80i\x18\xb1\xc04\x8c\xb8\xaaS\x9f\xab9\x0fp\x14\x0c~\x00\x9a\x91\xf9\x8ezK\x00\xb4\xb01\x00\x16n\x0f$B\xd1$\x856)8q\xd9P^o\x92vr`q39\xa8\xa0\x95\"\xbb\x1d\xed\xf8e{\xf01\xed\xe1\xc0\xe2\xf6pPA{\xf8\xfa\xcb\xf6PX\xd7\xf3\x0fad;^\xba?7\xb8\xa23\xf6\x01\xf41\xfa\xecq\xf1\xfdym\x8b\xe6\x0f^\x99\x15/f\x90\x92w\xa7kXI\x07ez\xf1\x82IK9'\x86\xbc\xd6J\xfc\xae\xc5\x13\xdaN\xeamP\x03\x19M\x94d\x0c\xd7\xa9\\\xc8p\xcd\xec\x9e-q\xb8=\xe3\x9e@\x82\xe7\xcf\xbf\xa3\xbe\x14\xea\x15\x18|\x95-\x03\xf3S\x11\x9dn\xfe\x9f\x1a\xa8\xab\xa9\xedXQ\x9b\nKC\x95\xf5\x9e\x89Py\xb3\xda@y\x1b\xd9\x16\x18\xdf\xa7\x05\xcd\x06{^+\xa4w\x16R\x98 _\x7f\xb6\xef\xe1/\xe3p{\xd0\xfc\xf0Q\x0b\x93\x9dVd\x0f\xfd0LW^\xb0<_\xc6\xf6>ql\x8c\xea\xb6\xcdm\xe7aa;H\xdbx\x897\xf7p\xd6\xf2r\xc1+)\xa24\x93of\xe5?a;E\xdf~\xd4\x7f\x9a\x88\x9e\x03\x1a\xe5Xu\xba=A\xa7:\x02z:\xe4\xac\xa5\x16^\xdb`\xd7\x89\xe1.\x9b\xeb$\xb7\xc0\x8fFW\xb7HM\x11O\x81:\xcaaI\xc4\xac;\xe6Yu\xc7\x00#\x0d\xdb\xf1\x12\xfd\x7f\xc5A\xbc\xe0\x18\x1f\xe1\xd1OEI\x9d\xa5\x80\x88L \xf2\x9a\xb2\xb4\xcdwz\x90\xeb\xf4\x84\x06o\xf7\x1f\xc0\x17\xb3\x87L0\x1dzAZ\x8fH\xce:N\xc2\xf8\xbc|H#\x93\x95\xed\x86[\x0d\x02N\xea\xc5b\x8c\xb0\x9d\x89\x05\x99\xdd\xc6\xb8\xd3\xb5\x92\x8e\xb3\x9e{\x8e6G\x8f\x1e\x8a\x7f\xec\x1a\x03\xeb\xac;\xea\x9fu\xfb\xfd3\xe3\xa7\xc9\x91x\xb1\x88\xe7\xf6\"\xcd\x04\x0d\x83\x14\x05\xe9\xf9_\xfe\xd2\xf8\x7f\xb8\xd3\n\xe4\xb9\xde\xd1;\xc6 \xdauz\xd1\xaeC\x9e\xf7\xeb\xfd4Q\x86\xe5\x07;c\xdb\xf5\xd6\xc9\xb9\x17\xacP\xec\xa5\x93f\xd2\xe4\xd6\xd1\x93\"\xf3\x99\xe7e\xf4I\x11A\x1a\xba\xfeb\xb2ByN'\xff\xf91\xcf\x98\xee\xce5\xf9\x9cu\x846Ui$\x1a\xcd\xfd\xbb\xd0\xeb\x99\x18Ej_\x10d\xcc\x97\x9a\x1dx\xbe\x9d\xa23\xc1s\xa8/\x11\xa5\xc2\xd0\x89=\xc4IM\xdb\xec(\xd0\n\xa6\xa5~\xd4\xf4Ce\x17\x9d-2\xea\"\x83-\xea\xd5E=\xb6\xc8\xac\x8bL\xb6\xa8_\x17\xf5\xd9\"\xab.\xb2\xd8\xa2\xf1x\\\x17\x8e\xc7c\xa0\x98*\xe7\x00\xbe\xbdk\xa45\xfa\xc3\xfe\xc8\x1c\xf4\x87,\xaa\xf4\xf2\x1aY\xfe\xce\xc3\xbc\xd4\xb3q\x0d\xe3\xb3\x95\x8f\xda:HP\xc3(\xff\x8d\x86\x04(IQf\xa0h\xaf\x15\x11T\xdeM:!\xb3\xaf,\xc2Ej\xb05>\x10\xbf\x9e\x1b\xecB\xa2\xa4k6\xae \xda\x95\x01\xd6\x01c{G`\xcd#\xb0\xfd#\xb0\xd6\x11\xd8\x01\xa3\x17\xe8`\x7fA\x8f\xbd$\xd5b\x94 \xa1q\x08\xc4\x9a{\xf1\x1c\x99\xaf\xd6'94I\xf7\x18i\xe9>B\xc5\xd1*\xa1%\x8b\xed\xa5N\xf4sDm7u\x8f\xdbo\"9&(B\xb1\x9d\x86q\xce\x94\xe0at-A\xfb=\x7f\xd9\xf1\xfc\xe5\x81\x18\xd2\x9b\x9cG\xfe\xab\xeb%\x11\xb6\xf7\xe7s\x1c:\x0f\x02\x1d\x06\x0fI\xc7>\x94\xe7\xe1Mk\x88\\\x17\x9a\x02\xf8\x01k\"-\x95\xd5\x06\x0d\xb6\x0c\xa2\x9c\xf5\x0b\xa9\xc6\x03\xc7Y,\x9e_\xaamlG\x11\x8a\x05\n\xec\x0f\xf4hW\x1a\xf0\\\xef\xe4\x9b&\xa5\x0b\x9d\xeb\x9d^VH\xcd\xf0\xdecVRN\xcf\xf3p7\x01\x9f\xd2\x12\x84Qn\x1a-\xb5\x97Z\x82\x9cL\xeaCe4\x82ymH\xcdO\xb4\x05F;\xf2Y\xf6;%I\x18{\x993V\x99\x18\xaa\xcc\xf5\xe2\xa2\x9a2%:\xa98\x12%N\x88\xd7~0\x01\x9f\n\xc5\x7f\xba\xd8\xe4 \xe0F,\xeai\xfe\x8b\xe6\xa5\xc8O\xaaG\x95E\x0c=\x0b\x97\xb2\x7f\x8c\xea\x9f \x134\x8aB\xc4^\xc2E\x81\xbddR\x9b,\xef\xb9F\xb4\xeb$!\xf6\xdc\"\x1c\xb3\xc6g\x03\xebld\x9cu\xcd\x9f\x84*)\x9d\xb8\x99\xf5\xa9\x1b\x1e:\x1bj\x93\xca$\x8e\x18\xf5I'\xd4;V\xb4\x9b\xe4\xa5\x0b\xdb\xf7\xf0\xfe<\xb1\x83DKP\xec-&U\x1f\x9e\xf7\x0d\xcb\x10\xf2\xee\x06\xa1\xe6\xa2\xc4\xe9$\x91\x1d\x1cH\x03d\xfa>7j\xd5\x9f\x1b\x93\xe2?BV\x9dd\xb3\x84\x82\xa2\\\x85}^\xab\xfdD\xc2\xca\xb71u\xde\xa9_5t[\xcc\x04}]\x9f\xa8HK\xf4\xd1\xdc \x8eWVd\xc7\xb6\x8fR\x14\xff\xf1G6\x15\x90B\xf5\xa2]\xcd\xdf\x8av\x1d\x9db\xef\x87A\x98o\x10P\x82\x0ft]V\xdb\xc6C[\xad\x9a\x06\x1f\x0e\xfc\xca&\x9b\x04\xcch7\xa9\x0e>\x90\xfe`\xa9{\xb9\xc5\xdb\xc3\x82\xedq \xdc\xcd\xc8j(\xba\x02\xd1\x07\xfe\xaa\xeb:\xb3\x10\xe9\xb3\xc3a\xb3\x921\x99E\x8c1\xe6\x16;\x00\x04\x14\xad\xd3M\xedy\x1e8\xa0\xf8\xe9#\xceQ\x0eOV]\xfc\x9c\x8dC\x87\xc6\xdb\xfa\xfc\x90s\x04\xa3\xf3\x85\x17'\xa9\x16.\xf2\xf0\x83a\xdb\xd1;\xfa\x11\xbc\xbaebs\xd5/:9\xe7S\xa7\xf3*\xd7Y\xfc\"\xb3\xbe\xad\x999L\x1eSY\xfa\x8bj\xb5\xd9kV\x9b\x99\x9f\x00kd \x9b\xf3\xfb\x8f\x9a\xa5\xbf\x00\x13=U\x111\xb4.c{\x0f6\xab\xeb%Z\x18\xa1\xa0\x19n\x92\xb5\xef\xdb\xf1\xfe \x1a\xe13\xef\x16h\xa8fQL\x8a\x95'V\xd6\x1a\x95s\xd0\xc4\xf7\x82*\x82\xb5\xb2\xdf A\xd9\x1b\x83\xa3\x9f\xe0~c\x00\xcb\x7f\x83\xe980\xe6(\xd9\xcf\x8e\x01w\xb0=G\xf8\xe9\x1d\xef\xa4\xa9\xfe\xa8f\x95\x922C79,\x0fu\xbd\x1eG\xb9\xc30'\xcc\x1aJ\x02\x95\xfd\x91\x9a\xa1$\x9d[\xc0j\xd5g'J\x95Q\xadi\xeds4\xae\xe8C\x9a\x8f\xd2U\xe8\xca\xe6\xed\\\xcf\xf5\xd6\xe5H'f\xd0A\x16\xa8e\xe3\x05w\x03\x8c\x99\\L\xba\x0b\xe5\xd3ONC\xf5\x04\x9d\xed+\xf2v.\x16\x0b\xc5F\x86\xf9\xd2,3\x80\xe7\xb6\xf5\x97\x92$\xb2\xd3\xd5\x11\xd0?\xfepQ\x14#\xc7N\x11\xa5\xccAD\xf4\xacS{[n~\xbdq\x08\xbdc\x16\xab\x19\xfa\xb7'w\xd0\xc96\x8c]m\x1e#\xfb\xe1<\xffW\xb31\x96\x85c\xaa\xf1R\xb9\x19N\xec\xe8\x0f\x07\xa3h\xc7l\x81\xff\x07\x9a\xaf\x17\xed\xd8\xd3\x9d\xcal\xd8\xcd:,\xbc\xa6\xab\xd4p\xa6\x8b*r\xc8\x16\n\xb1\x17\xe5\xebR\x82\x81\xa9:\xe4<\xdfH\xf3?4\xe9\x90\xd1\xbeZp\xc7\xc8\xad\x18\xe0\xf7\xea\x00\x9f\x98\x95\x9e=\xb2\xe7\xa4\xab\xf6\xad\x19\x19\xcb\xb0m\xc4,5\xe0\xf8\xaab\x19\x85IJ\xbc\x8f\"3p\x7f\xec8c}\xc2\xae\x80\x87\xe6YO\xef\x9f\x19\xfd\xbe0\\\xa1\xb8\n\xa7\x1drN(\xea:\x81\x19(\xb3\n\x1f\xf5p\xf9h9\xd7\xac&\x17\x8em\x98\xbc&{V\xef\xcc\x18\x18g\xfd\x91\x82&\xd7j\x8a,\xaa:\x9e\x17(\xb1\x02\x9b\xd3\xd4\xa8\xc2\xdeE\x18\xa5\x88\x95kl\"\x13\xf1\x9a\xec\x8f\xcf\x06\xbd\xec\xff\xad\x8a,\xd8\xaa\xe92\xaf\xec$v\xa0\xd8j\x9cN\xd4\xa8B\x0dK\xc4:\xe6\xc0\xb0\x17\x0b^\x9d\xe3\xe1\x991\xb4\xcez\x96B\x17_\"5\xc7,\xaa:\x9e\x17(\xb1\x02\x9b\xd3\xd4\xa8\xc2>\xb2Sg\xc5\x88e\xe9\xc8tz\x9c\"G\xfaY\xaf7<3\xc6\n\x8a\xcc\xd9*\xa9\xb2\xa8\xec\x14n\xa0\xd4J\x8cNS\xa7J\x05\x19WF\xae\xb1n\xf4\x00\xb7\xcc\xa6\x1cc\xa4\xe6\x96\x19W%e\x16u\x9d\xc0\x0c\x94Y\x85\xcfi\xaaT\xe1\x1f\xe6\xb1^\xc2H\xa6\xbb\x96m\x0fym\x9agc\xfd\xcc\x18\x0c\xdb\x95Y\xf2U\xd2gQ\xdbi\xfc@\xc1\x15Y\x9d\xa6U\x95*\x88\xb0\xbe>\x15:\x98\xd0\xa2\xa2y\xf6\x07\xce\x14\x8d{\xc0\xab\xa5\xc4\x95(i\xb9\xa8\xefd\x96\x07Hzun\xa7\xe9ZR\x0b!\xa0\xb3B>J\xb8\xa4\x9c\x1aY\xa7[\xfe\xa0\xa5^\x8aQk\xaef\xe1\xe14kD\xb3\xd6*\x9eh^\x90Eq\xd4\xd6b\x1eI\xe7{T:\xb5oU%\xd8{M\n\xd2\x1d\xb9.b\xbc*\xb5\xe7\xa7\xad\x82\xa8\x9a\x8bex\xdd,b\xe3\x1b\xd8\xf3N\xedy\x07{l\x1a\x8d<\x89N\xf1b\x16,\xc7\xaf\xfe\x8a\xfa\xd8\\8\xb7bbv\xf2\x99\xcf\x96\xf5X[C\\\x85\x89\xecb\xdf\xbe`5\xa8WeF\xb4\xa3\xceK\x11)l\xc1\xfe\x1e\xbb\xbdW\x08Q\xfa\xf8\x81\xc9\x90\x81\xbeI\xae\xbe\xb5r\xaf\x1aLJhh\x97\xa28\xb0\xb1\xe6\x86N\"\x87\xe6^\xfdGy\x13\x8a\xb5+\xbd\xcdX\xbb\xa8U\xa5\xb5\x8f7\xa8\xa4)\xdc\x11\x12ik\x84h\xb2ALf\x14h\xd3\xf3\xb6 :\xa6\x01\x020%\x7f\xc4fR\x9f\x9e\xb3\x15\xaa\x939\x0fC\x13\xa3\x1dr\xd6)\xaa\xe0\xf50\x98\xbb\x81\xfc\x9d^\x0ci\xa7;O\x03r\x1c$\xc7\xe5>7.\xcfCw\xaf\xe5;\xb0u,r\xd2\x98\xf7?s \x82\x97\x9ez\x86\\/=P'\x16\xf4V\xfab#\x83T\x9a\"M'A\x189i\xb5\x9bkB\xb3W\x8c\x92(\x0c\x12\x94h^\x100f\x96\"\xb9\xee\xc8\x95[\x82\x9eXN\xa3\xa7u\xc6\xaa\x96,\xec\xf8#I\xedt\x9d\x80{\x0fOeJ<\\\x07n\xe8\xac}\x140\xb9]\xe3\xd8d\xf6X\xcf\xfeH\xaa\xce\xcf>1\x9f\x0f\xcd\xcf\x93UY\xef\xbe\x8e\xfc\xc9\xf36\xb78o\xf5?\xd1Zb<\xfd\xe3\x8f\xc2g\\o\xd3\xf5\xed\xf8\xc1\x0d\xb7\x01\xec]2\xca\x18\x05.\x8a\x91;+9\x80\x9b\x7fE\xa0\x93\xbf\xb9\xcd\xa1\x8f\xc75C-\x10\x9a\x91\xa7\x1c\xa8d\x9e\xd1\xef\xf7\xd1q\x9a\xe1\xf6\x9dT\x1aW\xa9\x85\x9dEThY\xc5t\xa2\x038\xad|g\xc9\xedg\x90\xdc>\x1c%\xf0h<_\xe8\xfd\x89\xe2\xbd'\x15\x89\x9a\xd6\x14\xa9\xf3\xe7h\x13}\xd8qd\xcc\x0d\xddy\x82d\xec\xce\x95\n1'T\xba:N\xd3\x8b\xc5BxbN\xb8\xd3\xaaeSW\xf3\x1b\x0e\xed|\xe4+\x0e\xdd\x93G!\xa9\x0ej6gl\x9b\xfd\xfa\x96\xb7TP\x15F1w\xa6\x0b\xee\xfb\xcc\x95\xef<\xa2)69\xb3\x9f\xca=\xce\xecwx\xe7\x93{\x98C\xab\xe0c\xb5\x8fV(H\n\xf1\xb3\xa0\x83z@\xfd\xa24\x06\xd5/\x89ae;\xd6\x8er\xcd\x15'\x18\x1at\xf3\x96\x86\x16\xban\xb1\xdc\xcf\xba\xddAr.y\xe5-W\xc5{\xc0\x9d\xd0\x05\xd6~2\xf4\xdf\xbb\xbe\xe7\xc4a\xfe\x80|iN\xe9!\xbb\xeaHN_g\xce\xe8\x0c\xd8\x13\xd6Y\x1f\xc8\xdcQ+\xd7y\x89\xf8\xc4S\xee)\xe5\xca\x138tJZj\xe8\x8ezc\x138\xed@n2\xf2\xc6&\x0d\xf8\xd1K=\x8c\xbd\xb5\xdf\xf9\x82\xe6g\xc4\x84/\xe9\x97L\xc4P\xb6\xd9\xd4\xeb\xc5\xed\x90\xdb\xdb+r \xc4+\x88\x88eT\x8f\\\xf3\x9bE6\x83\xdaG \x8ej\x83\xa7\x95\x98s\x1a\x96\xe0P\x13\x07\x93\x8bX'n\x9e\xbe^8i\xa7XQ\xba\xbf+\x1dLzr\x13\xbe\xe7\x92\xa7\x1a-\xb5\xe2\xb8\xb5U,,N\x88D[\x94T/`\xeat\x93a\xd6\xcb\xcf\xe6T\xa0\xe0\x85\xb9\xd5l\xd2\xf8p\xe5\xb3\xe5\x89J\xe2x\x7fq\xd1\"\x9bW\x9a1\xc1x\x8e\xa37\x91\xed\xbc_'\xa9\xb7\xd8W\xe3L\x8d}\xaa7\xfei\xce\xd0\xa2\xf4\xfaQ\xdbH.\xa6,3uD\x8f\xd1\x81\x1e\x03'\xf2,\xfdEs\x18\xb5\xce\xd9\x95\x8c\xa5\xa7O\xf3\x13\xa6g\xc2\x13\xa8T\xb1\xc0\x1fO\xe8\x11\x12-\xcc\xd1\"\x8c\x91 aI\xb5\x93\x8e\x9a\x88Dm5\xdb\x11G\xc8\xb5\xbcG\x01\x07r\xeb \xec<\x0e\xd3\xfc\x87\x8e\x91t\xbc`\xe1\x05^\x8a:\xd94n\xc7g\xc4%\xcf\xc9\xf1\x14\xcd{\x12\xb8\x04x\xb1\xf7i\x9d\x15\xff/\x0e\xbe\xe6\xf3b\x1aF\xe5\x9e\x039;\x0c\xd8{\xb1y\xa6\xa9\xf6\xf3S.\xa0\xff\xfb\xbf*\xf2\x07\xb4_\xc4\xb6\x8f\x92N\xd5\xb0C\x1a\x02\xf7\xa0\xf3R\xf4\xa3\x91\xae\xe3\x80t\x1a\xea\xf9\xbf\xff\xfd_\xcf\xccO\x14\xec\xe7&\xa5N\x93W\xc3\x9c\x02I7\xfb%\x0eq\xa2\xd9\x8e\x83\xa2\xb4\xda\xac)\x87dj\xf3g\x19#\x14<\x85g~\xf5\x83\xe0ED,\xdd!\xf2!K\xcc\xb1\x17<\xa0\xf8`\xe9/\x9a\x17\x86P\xba\x15 H1\xcbc\xb5\x9d\x95y8\xba\xab\xda\xdd \xcc\x93 u\xb8\xe1\x05\xdc\x92\xb2\x06\x9d\x81O\xcf3\xa7\x83\xce\xfaU\xb7\xba\x8b\xea\xeb\xdf$\xc7\xcf6(N\xbc0\xd0\xa2\xd8^\xfa\xf6\x81\xdc\xaa\xa8\x83K\xe4\xb3\xe9?\x9a\xea\x8f?|\x94$\xf6\x12==\x82:u\xde#\xe5&\x06\xfcn\x0f\xf9@\xd8\xcc\\\xa0E>q\xd8\xb4\xcb\xc5\xf4\x82\xc6\xfe\xdd\xf56\xc4\x8bE-\xcbY)\x9dmTb\xde\xc9\x171Mt\\m\x97\xba(\xfbS\x8b\xdb\x8fv\x9d~\x11\xf6\xb2\x8bN\xba\x9ay\x1a\xb4\x9d\xb5&\xaf'\xf5\xc8\x83\x9a\xec\x19A\x93?6h&\xfcH\xbc\x8c\xed\xbd|\x05\x9as\x89\xec\x18\x05\xe9s_e8a\n\x9d\xa7A\xf6WK|\xd1\xc5\xad~\xa9\x19\x8e\xee\x9f\xae\x97\xd8s\x8c\xdc\x7fU\xef\x9b\x08\xc2\xcc\xe5p\xb8En=[uM\x8e\x90y?\x00s\xb9\xc9b\x9aer\xd7\x9fx\x04\xdf&\xc7\x0e\x1c\x84\xd9Sa\x8b\x81> \x97_e\x01i\x12\xb9\n\x0b\x0e|u\xf6:]\x85\xb1\xf7\x88\xe8\xeb\xd8\x13z\xb4\xab\xb8T\x07=\xe5\xa7?y\xe1$\xf5\x16\x89\x86\x05\x0e\xed4\xff\xb6\x0cm>p/\x9e\xa1\xdf,\x0f\x0b\x0fc\xf8\xc8e\x86-w\xaa\x80\xfe\xd9\x1f\x8fu\xd4\x03\x92[T9\xc7Q\xcb\xb8D\xa7\x0d\x9f\xe4\x8aZ\xc0\xb8\xe8\xff\xc7\x0fN4\x83r\x1f\xbcxU\x15\xd7\xb13\xadv\xb8\x03\xe2\x0c\x07l\x0b\x18\xe4\xa4\xf9_F\xdd\x95Y\xec\"\xf3\x98\xb5\x83\xb9\x18P\x0e\x0e\xca\xa2\xd3\\3\x0f\x95s\xce}\x98\xb8\xf7Y\xf6B~w\x8ef\xcc\xa8V\x06-\x0f\x80\x13}E\xcf\xfe\xb4\x89-\xbc\xf5\x0bO*\x05\xeb\xa1\x9e\xfd\xa1X\xcf\xd7i\x1a\x06\xec\xdb}\xc2u\x9a\x0d.\xbc\x02\x0bx\xd7\x0b66\xf6\xdc\x03\xbfVIV\xf6\x03\xeat\xfbI\xc7\x98\xc0O\xdb\x0e\x03\xffu\x81\xb83Fe\xd0{\xc4\xc4\x9b\xa7\x18\xac\xea\x1e:\x7f\xbc\xa7\xcc\xd9\xca\x13\xbb\x8ba\xf6\xa7\xb3\x8e\xf1\x8f\xae\x9d\xda\xe7\x9eo/\xd1\xcbd\xb3\xfcy\xe7\xe3\xc9\xdcN\xd0\xa0\x7f\xf6\xdb\xaf7\xbdo\xfb\x8b\xfe\xfc\xcbn\xed<\xea\x9e\xfd\xeb\x9d\xee\\\x86\x9bw\xa6k\xba{\xcb\x9c\xed\xad\x8d\xe3;\x9b\xd9\xfdt;{5~t}\xc7\xbb\xfe\xf5[\xf4\xedw\xf7\xd5\xdc\\\x8e\xaf\xef\xa7\xcb\xd9\xab\xe9\xbe\xf8{\xfd\xf3\xf5\xab\xe9\xf2\xfar\xb7\xfd\xfa\xfb]x\xfd\xe6v|\xfd\xa0\xeff\xfb\xbe>\xfb\xb8\\\xde\xec\xfb\xfd\x9b\x8f\xf8\xfe\xdd\xfd\xb59\xfb\xa0\xafg\xf7_\xfb\xef\xee\x9d\xed\xfb\xfa\xe7\x07\xf3\xfd\xab\xe9\xf6\xfaU\x7f\x7f\xb3\xef\xefo\xee\x97\xeb\xd9\xbd\xb3\xcf0\xb3\x0f\xf9s\xeb\xe6\x1e'\xef>\xce\xd6\xef?N\xfb\xd7\x97\xb3\xf5\xfb\xcb\x9b\xfbw\x1fj|\x9aa\x9b\x9f\x1f\xcc\xf7\x1f\xa6\xdb\xf9+\xfd\xf1\xdd\xfd\xc3\xf6}\xfe\xdf\xe5\xe3\xd7}V\x9f\x93\xbe\xbb\xbf\xee\xdd\xd4?\x17u\xbc\xfb\x90\xd5\xf1\x90=\xdb\xe5|\xef\x97\xeb\x9b\xc7\xa9U\xfd\xfc\xfe\xa3\xd3\xbf\xbe\xbc\x98\xcd>N\x97\xb3\x8f\xaf\x93\xb2m\xe9l\xdf\xdf\xdd\\\xbe\x1e\\{\xa3\x9f\x7f+\xf4\xf4\xf3O\x9d<\xaf[\x9c\xfc*b\xceN\x10j1\x8a\x90\x9d\x92\xf3ZqS\x9f{#\x84<\xa3\xd9SK|f0\x95(\xa8Y\xb9G\x11\xb2\xe3,Z(F\xa4\xfcEm\xecC\xe6w\xc0\xdd\xff\xe9\xafq\xeaE\x18\xfd\xabJ\xfeZ\xd4\xc15\x0b\xf4V\x80\xd1\x9f\xde]\xe9\xbd\x07.\x89\xd8\xcbg\xd8\xa3\xee\x94 8\x19#\x9d\xbd\xe0\xa5\x94\xdd}\xea\x99\xa4\xfch\xe1?\xb3%\xf5/\xc8\xb7=\xfc\xaf3A\xe9\xc2\xc3HX\x18\xd9I\xb2\x0dcW\x08H\x90\x1d;+aq\xb6\x1e\xa3\x0b\xb3'v\x8clRE:\x91l\xa2\x1dh\xc4\x0c\x8f\xc4\x86\xa1;\xce\xfe\xb4\x0d\x8f\x8b\x85\x9a\x15\xff\xf3\xd5\xd5\xbct&\xdf\x8a\x91\x1b\xbb\xeaO\xd2V\xb4\x81\xea\xd6\xb4\x01\xcbV\xb5\xc1\xf2\xd6\x81\xa0\xaa\x95\x7f\xca0\x00d\x8ar6\x07C\x7fq6\xd6_\x00Y\xb6:\xa5k\xba?jF\xb4\xcbF]0\xe5K\x96\xff\xbb\xa7\xbf8\x1b\xb5\xf2\xeb\xc9\xd9U\xc5\xff6\xf5\x17g\x96\xfe\xe2l\xd8\xcaQ\xeb\xb7HX\x95\xff\xbb\xaf\xbf8\x1b\xb4\xf2kaWs#3k\xff\xab\xd1g\xd1(8\x1403\x07y|\xbc\xd9\x9a\xeaQ\xb7\xe8\xf9\xd5\x137l\x92\x01u\xcb\xbb(\x8e:-\x00\xccMUK\x8aw|\x1d\xf8\xd0\x17\xb8\x1fU\x0f\x11\xce:\xe6\x0f%\x13[r\xe4d\xc2\x9c\xd5\x88QN\"P\xc0\xb3\x9f\xd9rV\xc8y\x98\x87\xbb\x03\x19\xf5\x97+Y`mD\xeez\x08\x1eW*\xd5\xb3?peOx\xfd\x86\x80aD\x1dD\xef\xeb:\xf1\xd1\x8d\xc2\x0e\xe4y\xb9J\xf3,HU\x8bP\xba\xae\x16\x85\x98L\xaag\xff\xaa\x9b\xca/\xa5\xa5t?\xe7\x8a\xfa{\xb7xC\x8f\xf0\x8dJt.K#\xf7\xcb\xf27/Tn7 \xcf\x91\x8f\xca\xedn2\x0ef\xcf|\xd0[Q\x8c\xff\xa1Q\xf6G\xf4\xb2$=_\x02T i!\x97\x08\"\xde\xf1\x90\xf7\x83\xfa\xa7\x13U\xd7\xfe\xca_\x85WFKk;\xcf\x7fB.e0^Y\xf9\x1a\xf8/\xc0\"\xd8Y\xd9q\x82\xd2_\xd6\xe9B\x1b\x9d\xbd0_%\x9be'\xb7\xe0/?\x18\xfa\x0f\x9d\xc2\x82\xbf\xfc0\xfa\xa1\xb3\xf1\xd0\xf6\"\xdc\xfd\xf2\x83\xd9\x19v\x0c\xbd3\xfa\xa1\xb3\xf3q\x90\xfc\xf2\xc3*M\xa3\xf3\x97/\xb7\xdbmwkv\xc3x\xf9\xb2\xa7\xebzV\xc7\x0f/\xcc\xab\x17\xe6\xab\xc8NW\x9d\x85\x87\xf1/?\xbc\xe8\x99}\xa3?\xec_\xfd\x90?\xd0\xe25F\xbf\xfc\x806(\x08]\xf7\x87\x8e\xfb\xcb\x0f\xb3A\xd74\xcd\x8ea\xbd3;\x86\xd1\x1d\x0c\x86\xd8\xc8\x9eh\xd9\xbf\xfdN\xaf\xd3{W<\xce\xc40;\xa3\xac\xec\xf1\x87\x97EMY\xa5/\xcc\xab\xbf\xfc\xd4\xb1\xf4\x17\xcdZ\x93\xd6\xa8\xeb\xd98\\j\xeb\x1d\xf35\x9d \xf9\xa2U\xea\x1e\x8b^\x1dV\xaa^\x03,`\xd8\xe9f\xbaw\xe30\x02\xb8K\x19\x8an\xc1\x8c~\x12V\xe5\x87\xae\x8d\xa9z\xea-m\xae!\xd4\xfe63)\x16\xbf\x9a\xe5\xdcP\x7f\xf3\xc3\xe2\x86\xe2\x937\xf8\xf9\x05JuY\xafm\x81\"\xc8\x07\xe8\xd1\xaeS\x9c\x9c\x92\xbe\x04Z\x8ckUj\xb5\xb1&;\x06g\xf5\xc90\x82O*J\xd8\xd2\x17U\x80{6U\x9e\x9c\x9fk\x95V\xb8\xd2\xba\xe9K>#f\x81=h\x16\xd8O8\x9a\x04\xd5\xff\x94\xd7\xce\xd5\xb1J\xaf8/':*[:\x16\xe96'\x9d\xffQmM\xa7\xeb\xe00AZ\xfe\xf8\x88\x94\xfc\xf3e\x9bd\xc2\xad\xc8\x0f\x83\xf7\xd8c?\x03\xf2\x0d^\x8d\xe8\\\x1eN\xb4Ir\x82[\xf8\xa1+O\xef\x98\xfa\x91g\xea\x85\xb5t\xba\xc4}\xd9$\xb2\x99\x1b\x11<&u\xabc\xb9\xb6\x9e\xfd\x11\x9d\xcc\xe5(\xff\x9e\xba\xcc\x8dK\xf5w\x0f\xe5\xcc\xb44\\.1b\x8fh\xc1\x81\xd7@\x14x\x95\xa6\xccF\xa9N\xd7D\xbe\xc2\xebo\xb8\xe1]\xf8*`u\xe4\xa9\x08\xe8C\x0e$\x03~**\xcf\xf1\x8cu\x17-\x81\xf3=\xe5s\x8eN\x0bc/\xcf\xa6\xe9/\xb2(a\"*\x10\x1b\xaa\xeb\x84\x18\xdbQ\x82\\\xf1\xa9#\x81P\xf9c1\xe7\xf2\xac\x1et\x02\x8d\xdd\xc0\x12\\\xa1=*\xd2k\x0f\xe0\xaa`\xb0\xd7o\x82\xc1\xec\xe7:\x1a\xcc\x83\xea~\xa7\xd7'c\xbd,\x8c3\xf4\xce\xe0\xdd\xa8k\x8d;\xc3n\xdf\xe8\x18f\xd7\x18v\x8c\x1e\xd6\xfa]k\xd4\xe9w\xad\xf1;C\xef\x18#<\xd0\x06m\xf1\x1b\xb7W\x90\x05/\x90\x16\xef\xd7~\xa4\xa5a\xfe60`\xe1\";\x01\xc43\x10\xbfz\x8a:;\xa8u\xfb\\g\x03-\\\xdc\x87\x97\x1f\xe3$\xa0\xd5\xbb\xa5\x8aG+/H\x0f\xc4!\xbb\xfcG\xf6cc\x04T \xab\xd1\x1d!\x7f\xc2\x9f\xe3\xab\x86\xff\xae\x81\xfcN~\x14\x08\xf8\x1eo9<\xaa\x04od\xb85\x84\x1c\x9e\xb8D\x95\xad\xfb\x99\xc3F\xe5\xc9\xb2\x02\x9a\xd4W0ub\xf2\x97\xbdR\x9a\x97M\xc2\xbdz\xc1)1{\xeb\xfc\x0b\x0f`\x9a,\x96b\"7Qh\"\x7f\xef5\xcd\x9e \xd1\x9e\xe5-\x86'\x85Ap\xb2\xe8Y\xdf\x13.\x0f\"\x06:w\xbc\x86S\xd5\x13_\xa3\x0d\xf0;\xe9\xcd\xde\x1c\x9f\xe3\xde_\xce\x92[\xac\x07\x90\xddEo\xdd\xf6\x02\x0e\x0b05\xa8\x0d\x99\xf9\xeaQ\xda\x17*F\xc0e\x97\xfa\x82\xc3Q\x1f\x1c\x02\xde\xc6\xa7>\xd8\xb0\xdf\xeej\x91\xb5\xc5F\xc3\xe3\x98\xd1Q \xf1\xda\x90\xa3\xb8\xe4\xa7\x83\x18&\xad#\x12\xc7\xa6|\x90\x08\x0cLM\x0b\xa3\xfa\nVf\xab\xe6\x15;\x96B\x85\xf3pw\x90\x1e\xdai`T\xc2\x19\x8ca\x95\xcd\xcc\xbe\xcc\xa7\xae\xe4\x08\xb7\xe6Ni\xd5L\xba\xd0\x0b\x87,\xf1\xa4\xce\xf4Ty\xcf\xb4\xf4\xec\x0f\xc4\xac\xa9U\xdb\xdaq\xe0\x05K\x903\xb7|\xab^\xdcR\xddn\x17\x1fV\xe4_Q\x97\x8du\x7f\xcf\xfe)\xa7\xe5\xee<\xb6\x1d\xa4\xe5\xabZjF\x84\xceBEq\x18i\x81\xed\xb3\x87\xb8\xa9\x15I#\x1d@\x9c\xfbx\xa5\x18\xcb\x06\x10(X\xfb\xb2\x0b\x8f9(\x0b\xb1\xed\xf4 \x9e4\xba \x8a7(\x16\\\x1f{\xb6\x0bYd%\xa2\xebW\xf47f@\x06\x9dU\xbf[\x9d%\xaf\xee\x1e\x94\x01E\x8fUcE\x92\xdas\x8c:i\xf55\x16So\x01\xba\"\x9b\xd5\xd2eQ \xf8\x85\xdb u\x1f\x82H\x82i\xc4\x9dNy\xe5\xf0\xeb\xfaKWik\xa3\xdb\xe1^\x0eE\x1c|\x87I\xbbN\xe8G\xeb\xack\xadc\\\x0f\xcd\xfc\x91~\x10_\x1cC\x07\xf5E\x9c\xaa\x9d\x88&l\xce\xf5\x978\x9c\xdbX+\xea\xfa\x8f\xbe%*\x90\xb4\xd6S9\x00\x92g\x9c{\xd50$~=S\xf5\xaa/\xc0\xdd\xcb1C\xe0\xed\xb9\x03@/\xc3\xa12nZ\xb5>?\xaf~\xe0\x99\x94\xc3]\x9a\x9fLJ\xe3\xac?\xd4\xbcX\xafg?\xd6,`\xc0\xf8tu\"\xa5O\xbe\xe2\xab\xd8\x84\x82ZU\xde\xefN2IZ\x12dp\xa7|j\xda\xac\xec\\\x80B\xaa7\xb7)\xe9E\xa2\x91fl\xe9Q{\x0f\x03\xe2\xe6 \xf0V\x9f\x92m\xfe\xea\xc6\x9c\xed\x99\xact\xd5vz\x8cI%\x13\xd7b\xf2c\xf2\x8a\xeb\xb7\x9e\xda\xa9Bf\xae\xaa\xbe\x8c\x93\xb0/\x93\xe0\xce\x02\xc1\x1f\xd52\xf9\x17>Ix\xd2\x97\xcdJ\x86B\xfa?\xfe\xc8grI\xc4\xd1\xd7O\x99\x14\x99\n\xba1\xfa\xef\xb5\x17W\xaf\xc7\x11\x0d\x12\"*\xf86+\x1c\xe0i\x03\xfasCM\xca\xac\xe2\xf6\x97R\xf0\xf2e\xd0V1\n\x0e\xd8o\xae6\xb2\xa0]\x8a\x82\xc4\x0b\x99l2\x81\xf0\x14^\x9csLW\xe5?\xccBT&|m\xfe\x13+\x8d\x91+V\x81\x1f\xa5\xfb?66^\xa3?\xf8\xc4\xb5ID\x03\xe5\xda\x91\x8b\x0e\xb8\x17\x0cJ\xb9\x97\x93=\x15L\x0e\x8f\xe2\xd0\xad\xee%5\xc1<\xffjH\x8c\x80\xab\xee\xfc\xa6^\x1aFs\x9b\xfeb\x0dpE\xa7|s\x0eDZ\xfd\x17~\xcd`\x89\xb1O\xdb%{r\xbe\x07\x14\x98:U\x95\xe7\x06\xd9!U%WB\x8eb\xf9^3\xbbIR\x1c\xb9\x90\xaf_\xd8cD\x95\x84E\xca\x06\xd8\xcc\xe2#\xd1\xca\n\xf5+J\xd61\xae_\xd3\xf7d\xad\xe7m5\x9b\xd6\x9b\x93\xea \x01\xca/r\xa2\xc0e\xaevfO\xd8{\x9dy)\n\\\xf56\xb4\xcc$\xa5\x86\xf8seV\x7f\xb8\x80\xbeJV]h\x12\xdf*\x91\x8b\xd3-f!\xed\xf4\xb3WOw\xeb 8\x99\x0e\xa8\xe3p\xa76\xa9\xbcgG\xcf\x9aJ\x1d\x82\xf6\xd2<\xc0\x92\xbf\x19\xf2\x18\xa1\x8a\xa9\x9f\x93\xa3\xd7\xc8\xd1\x9b\x94\xff!\x94#t\x0b\xea\x04$\xb0\xee(\xcf\x0dR\xbf\x1f#<\xf5\xb4\xbc\xd5$\x89D\xc88\xae_\x1e\xf2\x90\x9c\xe1$\xae\xd5Q\x8b\xa8\xb2qG\x0e:^\xb0\x08\xeb;\x1d\xc0K(\xb3\xf2\xce*\xbf\xee\xd7\xf5m/`\x97urt\x87=\xc4\n\xc0\xb1w\xc6?\x8c\x80g\xc5z\x89\xe0w\xda+\x0f\x0b\x19\x0d\xa0\x02\xf6\xf3\xc8\xc5C\x13z\xd8\x87\x1eZ\xc7\xbf9\xa0\xa0,\xdenU\xad\x8f\x8b\xdbb\xea\xe9C\xdd:\xf2\xa4.\xf4\xee\xf7\\\x0e\x9b\xd5\xeeQ\x1b\x11-\xb6\x80\xae\xc9\x16\xb5\xd2\xef\xbc3\x16\x83\xb1\x03xay7\x9f\xdc\x9f\x02\x98u\xe7v\x824\xe0\xe80\xa9\x0b\x93:\xdbZ\xcf#G)Qh\xcc.\x9bF5\x07O{w/\xc1\x95\xff2\xaad\xc1`\xb5\x1c\xae(\xd6\xef\xe4\xcb\x9d{\xc5\xc0\xc2.\x8d\x93u\xc4\x1dd\xb5\x86\xcc\x01\xb7\xa1;\xea\x8f!\xf3\x92\x92\xe7\xaf\xdbST\x057T\xd9\xebt\xa5\xcd\xd3\xe0i\x01\x0e\xbd6\x7f\x8e\x17U\xc8\xa5,\xeeK\xbba\x80\x0e\xf2\x14rN\xf8\xa4\xa6)M\xd4\xcf\x1a\xbb\x912w\x88\xd7\x040)\xd0&4\xd1\x9a\x97\xe3\x01\x9c\xc0\xe4\xa1\xc1\xdeo(\xd2\x89-\xa7\xe6d\xdc\xe1M)a\x1dl8E3#v\xcd\xcbc\xffV\xb4\x13\x1d\xb7bH\xeb\x8f\x8e\xf3\xc1\xbe\x94\xae\xf5&\x9a\x84\xa0\x08\xa3\xd9\x1b\x90R)Q\x1c\x87q\xc2\x0e\xa8\xd4\x06\x18?Y=y0M\x9c0BIg\xd5{\xfa\x94\x9f\xb3\xd2\\\xb4\x90\x1f\x8b(\x1b\xaa1V\xe9\xc1\x0eXu$\xe2\x92\x9acc\xf4)b^\x80E>\xe5C\xd2\xea\xfaZ\xebd/\xf9&\x15-v\xf9;\xdb\nx\xd3\x0b$e\x8fl\x08\xdf=\x7f\x92]\x05U&\xc4\x8b\x9f\xc0M/\x86\xae\x882\x9f>P\x9e\xb4\x06S\x90\x8c\xd6a\x8f\xba\xac\xa44P+\xb99t\xc7\xb1\xf0\xb7\x03x9\xad\xbc\x971\x02\xeej\x8c~\x9a4\xaf\xc6\x02\xdfAV\x00\x0d\x9e\xd6hH\x0d\xfav\xe0\xff\xb4,\x94\x9d\xee\xf2kaq\xb7\no\x9aTZ\xe5\x1d\xf9J\xef\xff\xbc\xfc\xdb_;I\xb8\x8e\x1d4\xb3\xa3\xc8\x0b\x96\x9f\xee\xde\xfd\xd20\xea:I\xd2\xf5\xed\xe8o/\xff\x7f\x01\x00\x00\xff\xffPK\x07\x08_;\x94/\xe8Y\x00\x00\xa8X\x02\x00PK\x03\x04\x14\x00\x08\x00\x08\x00\x00\x00!(\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x00 \x00swagger.yamlUT\x05\x00\x01\x80Cm8\xec}\xdbr\xe38\xb2\xe0\xbb\xbf\x02\xe1\xde\xd8\x9a\x8ei\xdb\xb2|w\xec\xec\x86\xaf\xdd\xee\xda\x9av\x97\xdd\xd53\xfd\xa2\x82HHb\x99\x02h\x02\xd4\xc5\x15\x13\xb1\xdf\xb1/\xfb\x8b\xfb '\x00\xf0\x02\x92\x00\x05R\x94Kv\x99\xe7\xc4\xb4KD&\x12\x89\xbc!\x91\x04\xb6\xb6\xb66\xe8\x14\x0e\x87(<\x05\x9b\xdd\xed\xce\xe6\x86\x87\x07\xe4t\x03\x80 \n\xa9G\xf0)\xd8\xdc\xe3?\x03\xc0<\xe6\xa3S\xf03\xf4\xe0\xd6\xff\xf6\x18\x02\x03\x12\x82\x0bB\xc7\x84n\x00\xe0\"\xea\x84^\xc0\x04\xc8\x19\xf8xuw\x0f<\xccP8\x80\x8elJ\x19d\x08\x12#T\x80~&\x13\x14b\x88\x1dT\x86\xcb\xde\x19\x80\xef|HG\xfa.\xe37\x06\xc0K\x8f\xb2\xd0\xebG\xbcq\x19\xf8\x1a!\xe0*-\x0cHn\xce5sys~a\"6\n\x02\x7f\xae!U\xfcn\x00\x8a\xd5D\xf9\xe5\x83\x87Y\x19 \xff\xd5<\xdc\x0f\x1eu\xca0\xbf\x0b\xe9\x82A\x90\xf6B\x9d\x11\x1a\xa3X\x1dF\x8c\x05tcD(;\xe5\xca\x15\x0e!C\xdb\x8eP\xc8m\x8c\xd8\x94\x84\x0f\x1b\x149Q\xe8\xb1\xf9%\x1ax\xd8\x13\x02\xc1\x81\x1f\xc6\xe2?\x00\xb0y\x80NA\x1fR\xcf\xd9\x08 \x1b\x89\x9fw0qQ/1\x04\x00\x0c\x11\x93\x7f\x14Y\x89\x07$\x1c\xc7z\xdb'\x11\x03l\x84\x80C0F\x0eC.\xe0hb8\x1a\x8d\xc70\x9c\x9f\x82\xfb\x11\x02AH\x02\x142\x0fQ@\x06f\x98D\xf1\xe5\xb3\xa5\xd3R\xc0q\xb9\x91\x83r\x0da\x10\xf8\\\x8d<\x82w\xbe\xd0X\x80\x00\x08\x11\x0d\x08\xa6j\xdbn\xa7\x93\xfd\xa30\xba\x7f\x12\x17 \xa3\x15Q\xa5\x89\x98\x01\xa8\x02%L$\xfd/\xc8a\xb9\x17\xd9@\xf3\x00@%\xb1\x97X\xdaB\x93*p\xfe\xf4#\xcfw{y&\xa9\x8f\xa4\x8a+I\xac\x7f\xf9\xc7\xf1=\x84YO\xc8_#x2\x1e{\xac\x11\xe8\x904\x02kL*E\xe1\x04\x85\xcd\x87j\x9c\xa0\x05\xb0\x055R\x9f\xea\xa9\xf5\xdc\xda}\xf1gL\xb0\xf7\x80\xc2F\xb0\x00\xa0\x19\x1c\x07\xdc\xc3\xa7^k\x8bsL\xd36\x08 #\x0e\xf1\xcd\x92\x0b\x16\x0eQ\xb4\xe8\x06\xa6W\x16\xf4\x02\x95\xe6#C\x13\xe1\x9a\xdb\xead\xb7ch\x03\x83\xd6\x06\xa2\xeb\"6\xe6\xcb\xce\xeb\x90Gn]\x9d*\x8f \xc6\xc8ofG|\x8f2\x84{\xd0u\x97\x16\xbc\xdd\x93\xee\xf6\xee\xe1\xf1\xf6\xc1\xe1\xf6\xeei\xf7\xf0\xf0\xe0\xb0\xae2\x9a\xa2\xb6\xccK\x97\x1f{\xfa:\xdb\xbb\x07\xdb\xba \"ldR\xbb\x1cEc\x12\"\xe0)^\x93\xe0\x844ZA\x9b\xc6\xb3$\xcfb%c\xb3\x9e\x87]4kK@\x0d\\\x04 \x0c\x1c!\x05\x88\x1ai\xa9\xdb\x17s\x82\xd3\x9d\x9d\xce\xb6\xf8?!\x11\x99\x9e\x1fT\xb8\xeek\xe8\xf9\xc8\x05\x8c\xc4\x01:\xce\xb9\xf2\x1d:\xc7\x8e\x87\x87\x12\\ n\xd2 \xe5N6\x88\x97,dP;*\xc9G\xc9\x88\x01O\xc69\x82\x10\x8f\x02'\nC\x84\x99?\x07t\x8eyOS\x8f\x8d\xa4\x18\x896\x894\xac:\xbaQ\xc6\xb9\x8a('\xc7h\xf5\x89\xc3NB|\x04\xb1\xd5\x94\xde \x1f.\x97\x94\x18\xfa\x00\x85! \xf9d\xca\xc5\xd7\x8e\x0f\x19\xa2\xcc<\xa5|\x12\xf8\x0c\xc8v\xd2/\xd4\x99\xd1\xd5\xcd\xc4\xbd\x9e*`\x98\x86\xff\x16\xa2\xc1)\xd8\xfca\xc7\xcdB\xfa\x9ds\x0e(\x96\x0b\x9b\xadp\xf3\xeb\x08y\xc3\x11\xfbO5?\xa1$\x18@\xfe\xa7\x83B\x06=\x0c$\xe4\x8aX\x1b\xc0\x10\x8e\x11Ca\xae\xb1\x87O\x01_\xbc(\xa3\x95\xcb\xaa\x1c-\xa0\xc8\x04\xc1\xb4r\x9b\x10=F^\x88\xdcS\xc0\xc2H\x0d\x7f\xa4\xd0\xe2h\xdcG\xa1\xf2\xf3l+s`\xcd%@\xe1$\x0d\x90\xe3\x0d<\xa7L\xdaR\xf2\xb0\xdf\xd97R\xf0\x11=F\xa9\x00\xc6\xfd\x02\x97 \x8a\xdf1\x05\x81y\x087XD\x8dE\x92\x1b\xc9\xa0\x9a5\xa9\xad\xd8)0\x909\x17\xb0\x02)l0\xbd9\xb2\xf84\x17m\x91\xddd7\xb0\xc1\x02{Ob7\x19b\xad?\xce\xa6\xc1\x04\x06\xc3\x10\xceK\xef<\x86\xc6\xda\x08@+\xa9\xd9\\|J\xfa[\xd2\x84\xe5\xc5\xc7\xd6\x92\x15&\xe8\xcd\x9c-g\xceJ\xf2\xae\x98\xb57y7\xc9{\x95\x89>O\x1cDl\x9d1a\x00N\xa0\xe7\xc3\xbe\x8f\x14\x0c\xcfc\xa3\xd9\x8c\xab\x16\xa4\xa3\x85\x8au?\x03\xfd9\xe0MMJT\xcc\xe7\x97|\x13\x0b=4A\x00\xe6\xf6\x0c\"\xca#W\x8fQ\x81{{\xf5\xca\x97\x8d\xa0D\xe2\xfd\xac\xf8z\x81\xd6\x95\x04P\xd1\xba\xf3\x8b\xf3\xabn\xe7\xea\xf8r\xff\xf0\xe8\xe0\xf8\xfc\xe4\xf0\xec\xea\xe0\xf8x\xef\xfc\xe8\xa4{|p\xdc=9<\xbb\xe8\x1c^\x1d\xec\xee\xef\x1d\xec\x9ft\xae\xcf//\xce\xae\xba\x07gG\xdd\xf3\xbd\x8b\x8b\xa3\xc3\xf3\x86J;\x93k\x10&\xf3\xb3\x13\xcfEnqP\xd6\xe1\xc7\xfd\xacF,z\x93\x08W,lW\x8a\x8c\x95\x84\xcbBx\xb2U\x9c\xd8\n*n\x86\x94\xfa\xd74\xe3\x12\x8b&\x083\xda\xaa\\\x89\xc5hI\xb0\xc6\x88R8D\xdb\xb2\xef\xc5\xa2\x92#~SU Ir\xba9\xf5.\x8f\xf9\x1f\x14a\xf7\x1d\x98\x8e \xbeO\xa6\\\xa1\x10v\x03\xe2av\n\xde\xfd|u/&\xe1\x7f\xe9\xf0ls\x03\x84\x00\x1bA\x06\x10tF\xc9\xc6\x86K\x9ch,\xc8\xe0\xaaI\xa6 U\xdb\xc0'\xe4Al\x04\xcef\xbd\xf8\xb7\xb1\x9b\x10\xe0\x90P\n\xac\xcb\x89\x90\x9b\x18[\xd4}\xd8q\x89Cw\xb8\xeb\x00\xae\x17\"\x87\x11U\xacrz\xb3\xc9\xe9\xda\xac\xc5r*\x8c\xf12,\xe7\xf2(\x15G\xe2Z\xc0\xb6\xff\x9e\xef\xf9\x1fr\xa0\xbb\x87\xb39\x1a\x07h\x1c\x04'\xdd\xd9\xc9h\xfe\xf4t2\x0d\x87\x83\x93\xfd\xf0\xf0\xcb\xc9\xe8`\xd09\x0cf\xb3\xc9;\xd3\xc0ka\xb1\xe3P\x00\x87\xc8\xc4\x80[8D\xe5\xb8A\xb2\x8e{\x8a\xe1\xa2x\xa2\xbak\xdf\x1b{\xc6 \xe7\x03\x9cy\xe3h\x1cw\x0f\xc8@\xba_\x10\xa0\xb0Hs\x0d\x82j\xda\xca3\xdf\x07lF\xc1\x182G\xeca\xe6\x8c\xa6\x94m\x05\xd6\xdal\xde\xc2\xa1\x87!C\xae\xb0\x9e\xf73\xaaF\x06\x8b\xfd:\x95\x86\xac\xd0\x7f\x13\xd3\x0b@@h#\x9b{\x9e\xeeAC@\xbd!F.`\xb3\x0dM\xd7\xda\x86\x80\x11\x00\xc1 \xf2}5\xe3\xe6\x10L\xa3\xb1\x9d\xedm\xc3L\xf7\x89[\x96J6K)6q\x93\xc7\xbdl\x06\xc6\x11_\xd3\xa1l\\w\xcc\xbd\x9fm\x8b\xd74\n\x02\x122\xa4n\xd6\x8f\x89\x8b\xb8!v\xfc\xc8E\xe0\xf3\xa6\x08`7?\xff-D,\n1\x80\x03\x86B\x8eWn\xb8\xfd\xf8\x13\xf8\xbcI\xe7\xd8Q[\xa0\x10\\\x8c\x90\xf3p?\xfbQT\x02|\xde\x84\xf9&\xa1\x08\x19\xe1\x14\xce\x7f\xdcV\xc87F)-\xc5\xe2L\x93u\xd6J\xbe`\xd1f\xa1-g\x8c)\x147d\x90S\xcdV3i5\xb5\x9b\x07\xacJ\x01J\xec*\x9b\xe8s*1\xf7\xb3\x0b1y\x1f\x05\xaa\xe5\xc3\xa2\x1dY\xddr\xba\x94\xaa^ \x1c\x85\xa8\x9a\x11a\xcc\xce\xc6\x1e&`\xea\x85\xa2tg\x0c\x99N\x85\xb5\x08\xfe\x16\x0b= y\x80\xf0#\x18\x84d\x0c~\xbd\xfb\xed\x9f\x1cu\x1fRt\xb8\xbf%\xa9w\xe3^(\n=\xe8{O\\)\xe6,M}\xaf\x89\xd6/PvF\xe2J\xa3\xb5\xd7\xaa\xbaZ \xc77\x85\"\x9et\x10\xa5\xdc,\xcf\x81\x8b\xe4\xdcq3\x13\xa2d*\x9fg\x90v\xaa/\xb2\xa9\x1aA\xdb*\n\x9a\x08F\x99\x18g\x8a\xad\xca\xcf*,\x19C_\xea\x852\xf4\xc6\xebh\xc9\xd2\xe5\x94\xf9\x12itQ\xe8\x9e\xb5:kQh\xd5\xd9J\x8d\xb9jp\xbd\x7fi\xea,g\xe3\x1b\xab\xb3\x9d\xa4\xdfM\xce\xbd\x7f\xa1\xfd\xf7\xb7\x8f\xde\x97\x7f\xffE\xde__\xffr\xf5\xf4\xeb\xb1\xd3\xfd\xe5\xf6l0\xe9^]\xff\xe1\xdc\x8cf\x9d\xf9-\x1cN\xafF\xf7\xf3\xce\xe4\xf6\xec\xef?\xff<\xba\xb8\xa2\xfe\xfb\x7f\xc1\xfd\xb3A':\xff\xfbxp7\"\x1f.\x86\x9f\x9e\xdc\x9f\xaf\xc3\xbf>\xde\\~\xb8?\x9b^\x0d\x7f\xff}\xfa+\xf9\x10\xf7\xde\xae\xf5X\xc0\xc4\xc5\xc6\xec\xf9\x15\xb5\x0f\xf1\xc3N\x1f\xfa\x10;\x88\xee|\x8d7\xba\x17d\xbf\xb8\xee\xc5\x95\x9c \x815(wZ\xdd\xd9\x92\xfcksX1\xd5\xa6\xc1\x9f\xc5\xa4\xc6\xcd\xf8\xda\xbc\x8f\x9c\xd1^7o5\xc0r\xf9\xadZ\xab\xd5f\xe2w\xa6\xe79\xa8T\xdarvW\x9b\xd9\xd5\n\xe7\x05\xf1\xb0]XW-`I\xd9o&`;\xc2\x1a\x0f\xd2\x19V\x1d\x84\x92\xe9\xc2.p\x88\x87\xa94\xd0\x04gr\xc7\x97TXT\x16,\x96\xbc\xe76\xd2\xafKH+]O<\x1d\xa6Q\x89\xc5\xa1\xc8 \x89\xc8\x8a\xcd\xd42!\x9b!\xb5\xe4\x8c\xb8k\xef\x85\xe8\xb1\xec\x92\xf4+\x1cH\xd1G\xf4X\\\xb9\xc11\x1f\xab\xc9\xad\xb5\xb1\x8d\xa2*\x9c\xd68t\xcd\xdeA\xf5K\xd2-\xc5\xdf\x1f\xac\xdc1%\x99\x9aPn\xb7\xa7\xcd\x1a\x19\x0c\x18\xb1\x91\xc6`\xd8{\xa4B!\x9aX2;#\xe8%\xf2V4\x14\xe9g\x0b\xeb\xa3\xfd6\x9a\xb1\x1aeo\xe8\x91\n\x19\x80\xcb\x04.\x851\xa8\xbf\x96\x13K\xa9\xbeq\xa7\xdb\xf7\x81\xc2\n\x19\x88\xc1l\x841L\xd1\xa8\xaa\xdfd\xd5\xb2\xab5\x0d\xd0o\xef\x957\xab \x82/\xd3\xd1\xd7\xf3\x86)\x8bJV\xbdI~\xd4\x14\"G\xfd\xb1\xc7\x94\x19J8^/\x83P\x82/\xd1%>p\x82\x94NI\xe8&\x9f7)\xb1x\x88\xc6d\x82\xb2\xd4\xcc\xfb\x0fwV\x13S\xcb\xec\xb7\x13\xc5\xa5\xf3b.\xeb\xd6\xa2\x8b\xf5\xb4\x88.\xad\xaf\xa9\x89.\xad\x931\xe0\xcd\xa6\xc4\x12\xa1j\xa5\xab\xd5q5\xeb\xa1\xb65\xb7\xd9\xdeC#\xcd\x04$T\xf8\x9d\xc4\xb1yU\xd9\xef\xec\x1a\x11\xbfG\xf3L9<\n\xa6!\xb1\xf4P\xc6\xed\x90z\x1ej\xe7\xebD\x15\xa7\xff|\x0f\x1e\xabb49fT\x8e\xe6\xb7\x80\xaf\x90R%\xe4CJ\x81\xdb\x19\xd2\x04\xfa\xdc\x9e-\x1cYw\xba\x8f\xbb\xbe\xc0\xa3\xf3\xc5\xf2\xa3YQS\"?\xb2P\x05\xb6\x8f\xd8\x14!\xac\xfae\xb1\xde\x86\xa5\xc1\xac\xad\x9f^\xad\xeb\xe5\n\x9e\xd5n\xb6\xe1\x8fm\x144\xc2}Y\xf9\xd3{\x0b&\xd3`2e\xcaw\x1eV\xfe\x91\xf0\xa15!_J\x9e\xab\xe3K\x88\xb5\xf3\x96\xcc\xc3[\xb0\xf9\xc2\x83M:\x82\xa1.\xcfa\xb7a\xb7\xb9\xdb\xe9\xbcE\x9e\x8dt\x96;&\x9df\xbd\x94\x18T\xeb\xe2\xde\xa2\xd1\xdch^m4jv\xe7\xaf5 \xd58\xed[\xe8\x85-\x18\x81\x15E\xa7!\xb2\x0e=\xf3e\xcb\x05ElI \x07\xd0\xa7\x95\"k&%s}\xdc\xefW\xd2\xf3 \xfa\n=w\xa1\xf3\xa9B\x89Z!\x89\x91\x1a\x04]R\xb6\x04AU\xb1un\xb6\xc1\xdf\x06\x9e\xcfP\x08\xfa\xf3\xf8\xbc\x001\xf3\xf4\xc7u\xd7\xbc\xe5c\xeb\x8f\n\x1f\xec\xea\x17\x16*R\x85\x0f\xac\xa1c\xaf\xc3\xd7U\xae\x14rB\x98\x08\xd3*\x16\x086u\x05\xdf\xc7Z\x80\x86\xe9\x11%\xf6X\x17- 2\xf4.e5)^\x84\xfb\xbbZn\xacAa\x866\xe2P\xf5T\xbf\xdcX\x95\xc1,~\x92\xfc\xba\xadeu\xfc\x9c\xf1B~t\xa8F\xcc\x1e\x05<\xdc\x14G\xfeX\xc9\xfb\xea\x84\xf8\x19\x9c\xb6\xf6\xc3\xf1\x06\xb2\xfd\x8c\xe2\xfb\xb6\xd0\xcd\x8d\xc6~\xa1[\x08\x88\xdb\x1dM\xbbk\\ee\xf6\xa2\x15t\xa5:\xb7\xc2\x15l\xd1YT\xad\x7f2\x12\x1c\x88]\xfe'\xa2\xdb\xe0|\x0e\\4\x80\x91\xcf\x80\xc7\x80\xfct\x90\x02\x82}\xb9\x9f\x16\xcf`\xd6O\xfaq|\xcd/\xdeK\xc7\x8d\x19\xc2\x99R$\x9b\x91\xcdi\x89\xf1l\x83\x0f\xf1\x17\x97\xc8\x13\x07\xa8\xbd\x93\x84\xbe\xfb \xbc\x93I\x17\xf17 \x93\x7fzx\xf8N\xfd\nR\xd1\x0b\xd9\xdaj\x10U_H\xcb\xb4|\xfa\x95\xf4vi\xa8V_%W\xf7_\xf9\x994'`\xbc\xe0S\xe9\x86T\xad\xad\xde\xae\xc4\xb1\xb6\xa4\x91K\xfb?{\x8f\xf1\xc2R\xa3\xdc\xb0\xa8E\xb1\xf1\xfe&\xf5\xf0\xd0G/< \xda\xd0i\xac\xdc?\x14\xa5q\xa9\x12\xceW(\x99\x15\xe5\x9c/F \x97\xb7\x86M\xb7\xdb\x9f_|\xdb)\x1fy\xc5\x82\\YJ\xf2\x1d\x89\xf4\xd2\xa5$+\x92\xed\x80\x10\xff\xb4r\x16\xd5z\xb6\xf4Tb\xfec\x8c\x02p\x14/c\x02k%\x94}B(\xea1\xf2\x80t_qT\xa4Ae$\xdf\x04\xd2\xc3\x03_\xb0\xa2\xe7C\xcaz\xcc\xd3\xdd\x1a`\x03_\x0b\x8a/\xc1d\x87\xe2\x9c\x17J9\x01!\xa2\xa8\xde!\x86A\x88&\xbdx\xec\xb5\x92\xc7\xcb\xc9o\xc1\xcaZJ\xb1\x14\xdc\x04\x16\x88o\x8fL\xdfG\xbfd!\xce$*\xe4\xb3\xec\x8c \x1e6\x94\xa9\xde\x18\xd6;.@\x81\xf4\xeaI\xe4\x90@?\x16\xa5Zp\x997\xae\xad:c8\xeb\x15\xd3\x18e\xd0\xf22\x15\xc4\n\xdfs\x11&c\xcb.\x9bH\xfc\x0f\xe0\xfe\xb7\xcb\xdfN\xc1\x9f\x08`$O\x98\x8f\x93\x0e\x03o\x06\xd8\xc8\xa3 $\x11C`:B\xf2\xeb\xbe\xcccxT\x9c\xd99 \x11\x16\xe7i@\xd7\xe5\x0b\x1d\x1f\xd2\x91\x9aU\xc9N\xc4\xc3,\x84\x0e\x03\x0cQq\x9c\xd7\x0f\\\xe1\xe2[\x93\xf4\xd1\xd0m\xd4\x7f\x8f\xe6\xff\xd9\xa1\xde\x10s\xfe'W\x8f\xfc\x002\x9d\xfcA\x8e6\xa7\x96\xbc\xbdX\x84q\xa72\xf4&\x08\xe7\x82\x82\x1f4\x0c\xb2\x07SU\xf5\x87\x84\xd9Zm\x8d\xdf&\x9a\xaf4V\xae\x91J\xb0\xe6,\x8e\xd2\xb40\xd5\xe9\x1b}$\x97q]~\xa2\x07\x1e\xd0<\x0fU\x88\x0d%\x8b\xf3MJ\x91\x9e\xf2N\x895\x95_u\xf1\x9eC0\x0d\xa2\xfe\xee\x93\xf3\xc5\x8dP\xf0\xd8\x99D\xdd\xa7\xe1\xc3\xf0a\xff\x04\x0d`\x07?N\x9f\xb0\x0b\xf1\xe3\xc1x\xdf9\n\xe0^\xb4\x0f\x83\xa7\xfda7<\x19\xd2\xe0qx8*\x91Q|n\xd7B\x1b\xa2\xfc\x1c[,\x1ek\xa4{:\x12*\x13\x03%:\xd9\xd0P\xd4\x10\xc7\xfa\x063\xb2\x12\xd04\x12nke\xb1\xacC0\x83\x1e\xa6\"aX\x04(/\xf9\xdf\xc2\x96\xe4Q\xef\xc1\xb9\xe5|\x03\x172\x02,\xb4l\x1a\xe0\xe4{\xf8#p\xb9t\x8e\xe1L\xc9\x9d\xad&ry\xe6\x88%yb\x89[e\xb7b\x9a\xf2\xb3T\xd3\x14\x8b\x03\xbe\x95u\xce\xeb \x9e\n\xa6\xf7k\xf2\xe7\x8d[q\xb0kR\x80_\xb56,\xb6\x01\xfd9\xf0\x12\xfe\xac\xde(\x1a4,\xb6f\xe9 \x95W\x0d\xb3\x97\x9b\xdd\x862\xb5\xd0\xbd\xb7\xec\xb1\xd3\x89\xf0\xecN\xa6o 1;yK\xb4(,G\xdaL\xbbl\x91\\\x95\x91\xb4\x14?\x94$\xeeM\x8e\x9a\xca\xd1m\xcc\xd7\x862ts\xb92\x19\x8a\xfd\x10]$CI;\xb3\x0c%-\xb8\xe9)M\xd5\x9b\xe8X\x88\xce\xf2+\x8cK9\x07\x0d\xc5lISeX8\xc44\x01Y\xab'\xef\x80\xabre\xba4\xa7\xbb\x18\xc7Z-\x12l6\x00ul_\xad\xbc\xda\xec\xdf\x89\xa5G\xb2^\x7f-+\x8f4Wb\x89\xc6\x10\xb3\xaf\xc1\xbd\x07KX\x97\xd5\xed5*\x92,O\x90\x95\xca\xfa-\x8f\xec\xb2\xf0x;_S\xb1X\x18|\xc7-74$\xe4\x1a\xe4}\x9f8\x93\xc3\x94\xa7\xfb\x9e\x8d\x90\x0deq}DU\x9a\xd3\x9c)mHe\x93\xaf\xc0\x9fEM\x97\xf5\xeb\x8aZj8Yu/\xfd\xb5\xa8g\xc5\xa4\xa0\x02\xed\xab\xe5\x840\xb40\n\x15\x89\xf7\x8a\x18T\xbe\xcfm-\xacU4\xfa\x8du\xafmY]>`\xfdD\x18j,\xd5K\xc9\xa2!Z\xe5\x045\x08P'Z\xb0\xb7\x98t\xa1H\x96b\xd2R}\x00\x11/6?\x83\x81\x87|7\xdbT\x9a#*\xb7\x8a0I\xfe\xdb\x9bzl\xd4\x9b F6?'7%\xf7)\x83\x1e6\xd5\x06\xf0y{5a\xae\xb0~\x96(\x0c!\xaedv\x19\x87\xe5N?\x9f\x93\xf8u\xdb\xb6\xe6\xd9\xc2W\xa1\xcak\x1a\xbb\n'\xb9\xf3UL\xf4\xc2\xa0\x95\xb7\xda\xd0t\x9c\xbd59J\x10\xc7\xae\xba}\xee\xef\xd9P\xd9P\x96\xd4\xf5\x1aJ\x04\xf4\xd5\x05\x0d\xa9[\xdbxu)\xb7\x9e(a\xc3@U\x11\xfb\xf6\x15\x90A\xdf\x9f\x9b\x15O|\x91\x9d\x8e\xe5\x1d\x05\xa2=\x90w\xcc\x03\x98/\x85e\xdeX\xab\x9f?#F\xeba\xd9\x067\x03%\x7f\xcf\xb9HA\x80\x92o\xc2\xe3\xbc\xec\xdf\xbcm\x14\x17j\x80w\xf1\x8a\xe2V\x94_\xbc\xfbQ=\x11\x08b\x80\xc6\x01\x9b\xe7\xba\xdd\xfe\xce\xd5\xffY\xd4\xe6\x9e3|I\x17\xd6\x82\xe8\xa7\xd3\xb2\x93\xdb\xa56{\x9aa:\xb3i\"\xa4T\xab\xa2qA\x95`\xdb\xc9)G\xbd|\xf5\x10\x880\x17f\x18r\xef\x050\xc4\x84\"\x87`\x97\xaeBB\xdb\x9e\xf5\x06\xa1\xe1\xd8\xc3\xcf]\xde\x98\xd3\xdc\x02j\xddMgw}t\xc4 \\\xedh\x88,\xff\xac\xa1\x1f\x12\xa0\xae\x82\x94\xa0\xa4[\xc9\x15\x9f\xbeh\x8fbV\xa7\xdc\x18\x1b\x8b\xe4\xba\x19n\x93\x184\x94J\xd7\xe3\x1c\xe8Gb\x1e+\xcf\xb6\x9f\xc2\xd0\x8dy\\\x8e[\xd7\xff`\xdb\xa3\xe9\xc9!s'c\xf8\x04\x1f\xdc\xe9\xc3\xb4\x1b\x1d\x1cu\xbbG\xc8\x8d\"\x1fv\x9d\xf9\xc1Q\xd7\x1f\x18\xb51\xf9\x8a\x8f\x11\x06}\x103\x03\xf4\xa1/\x94L\x9e4\x95?QM\xa7\x9d \x16\x1a\x8d\x93\x8f\xe7\xf9?\x13t\x08\x86\x18\xb9\xa0?\xcf_\xa12\xcf\xce\x0b,^\xc3\xb1\x84b^*\x13\xbf\"\xd5\xac:v\x8d\x84\xf7\x9c\x95\x1f\xe5\xd0\xed\xd4j5'=\x1b\xf2\xe0\x7fzl\xe4\x86p\x9a\xceR\xda\xeb;\x9a\xbf\x9fI\x8c@7\xdd\xcdPXL\xd4j\xd2\xea\xe6/D\xb4\x973\xa4\xa3\x0buG\xc6\xd75\xd6\xcb%\x80\x9fEr[\xc9\xb5\x9ae\xf7\x99\x93\xac5\x0d\xff\xd2'\xbc\xae\x8d#\xa8\x93+\xfc\x9e\x0eSL*\xa8K\x86iC3\xb8\xa4q\xde/e0\xd2k\x15\xdd\x95\x85i\xaba\xaf\xdaV\xfa\xe57s\xf39\x84\xe5\xccA\x13\xa5^\xe8\xca\xec&\xb7\xdc^\xef\xb1j\x1ef\xfc\xe6\xc8^\xb5#+\xdc\x9d\xfe-7\x10m}\xdb4\x9e\xf9\xfc\xadF/\xd1\xa9\xb5\xb3\xbaI\x16\" _\xa0_0K\xda\xd5\x8c\xb2XyW\x81b\x1b\xdc\x8f<\xcagX\xdc\xe2\x1b3\xc3\xc3`:\xf2\x9c\x91\xf81\xa2(\x04SO\\`\xe7 o\x82\x14\xaa\xc0 \xc2ub\xe4\x1a\xf6\xe2Y\x94\xaeTo\xd0H\xc9\x96\xd2\x0b\x83{\xf8\x88\x02\x1f:\xa8\x81\x04\xa8\x90\x96R\x10\x7fX\x83\xd1\x14\x10\x9c\xde\xd1`1\x9fo\xae\xc2P\xf4\xa27b\x0b\xb1\x15\xe4\xf1Yt\xa0e\xc7C\xc2t\xf0k\xb5\x9a\xca>\x9d]z\xd5\xf4\n\xd7\x19\xe9\xad\x11@e\x9a\xe6\xdeF\xcd\x82C\x18\x1a\x03\x94\xc8\xa8-\x11\x8b\xd6\xb0\x1a\xcf\xa2,)\x9f8\xad\xcb\x9c\x8f\xd8\x86\xeb\xb0\x15\xf0\x1d\x121\xca\xa0<\x1f\xb9i\xce\xf8\x15\n\xfd5*\x08\xae\xc2\xa7\xd4[\xbe\\\x01n{\xe9\xbcR\x11}\x13\xcbT,/\xd2\xb3\xf8E\xb9#E\xfe`\xab\x9c\x98\xae\x14L\x83\x95v\xac1\xa7\x08k\x04\x83\xafH\xd4\x9f\xdf\x96/\xca\x12\xe5N\xce}G\xadv8\x8a0\xc5\xf9\xe62\x90\x89D\x11\xa7\xc5\x8c\xbf\x85\xff/6Sd\x96\xdeo\x19\xa4si\x8c\xb0\xc7\xe6\xbd\xea\xdbi.\x92v\xe2\n\x9a\xf2\xbe\xbb\x85\xec\xd6\x10\xc8\xb6g\xb5mk\xb5<\xdf\x8b*g\x15-\xbd0\xae/\xd0yY\xac\x8a\xc28@.\xeb\x7fEiJ\x9f\xe0\x88.\x85!\x13|f}\xd7J\xa3i\x1f{\x98\xd9\x9e\x92\xfcA\xb6\x05c\xe2F>Z<\xdf\xbc\xfd:\xcf3\x1f{\xad\xdbZ\xe4\xf3}\xdd\xa4\x13\x9f\xef\x1c\xa0\xb07GP\xf3\xe1V\xfb\xb2X\xb8\xbcJk\xf0\xe3\xef\nb\x90\x8c/\xf2\x9b\xbc\xb5\x16\xc8\xf6\x19\x061\x8e\xa0\xbf\x15\x84d\xe2\x89\xd0\xcd\x9eq\x12\x14d\xa0\xdf\x15\x03\xbd\xbe\xb3\xe3\xf8\x1e\xc2\x8c\xee|\x95\x7fly\xee\x7fvx \x8b0\x8d\xe8\x96\xb8\xe7\xce\xccN\xb9\x96\xe2\x90\xe2\xf8D\x15\xc8\xc0\xc2\x9b\xf3\x8b\xfa\x1c4\x87\xc0\x85\xafBd\x08\x9c\x8e\xc4\xc4\x90\x0b\xd1@=\xb1\xa9\xe2\xe3\x13\x83qP\x96\xbb^\xdf\x91]z\x96\xd7V\x87d\x82L\xb4\xdd\x86\x84\x0c\xf8\x9aS~\xd2S\"\xa4O\x88\x8f \xd6S\xa2\x9e\xb8\xba\x1a\xb1\xab\xf5YD*\x12=E\x8e\xd4\xc7\x10\xcd\xc5Pw\x1c\xa8\xb8\x95\x10p\xfeXb\x12\xbc\xd4\"\x10u\xafu\xb0\xdcB6\xd2c\x1a!o82~\xf6Q\xbc\x0b\xc7f1\"\x85i\xe9\xcf\x84\x8c\xda-\xff\xb4V\xed\xe4\xba\xcb\xb8\xc5\x9bF\x7f\xcf\x1a-\xb8RO\x9d\x05\xc8\x9b.'\xcdZ\xd5\xe5\x90\x10\xfe\x8b\xa4{\xe1\xc7\xe611\x1c(n\xf0}+\xb3\x96<\xc9K\x13m\x1f a\xe5&\x0b\xa8+\xdd\xe8V\xfb\x82\xb6\xd5\x19\x18\x85\xe05\xb0/\\4-U\x99\xcf\xc4\xf7lP\x00 \x8b\x82\xd8\xd8\xb4\x8c\x10t\x17\x1fQ+[\xc5\xefZ\xb1\x1cmK\x9cv\x8a~\x11d/\x99\x1f\xe4\\\xc2\xc4Eva\x13o\xb9\xca\x05\xd1\xb3\xf0\xcd\x14\x877\xe6_\xa6Vf\xce\xdd\x9c_\xa8fy-\xb9\xb5\x92\x05\xb8\x04\xd6\xeez]\x84\x082\x14k~\xfcr5{M\x15\xec\xae\xb7\x0b\xb5\x99\xa39\xb7\x17\xa5\x1a\xca\x97qdS\x1c\xf4z\xf52\x87\x0b\x17\xbf\xc6\xf1\x80\xca1\xa5\xa0\x9a\xdf+ \xe2\x8f\xc8n\xe9!k\xd8\x80\xb6\x15J\xdbu\xe1\x0e\x80e\xf5+\x176G\xe2\x0e\x89\n\x95\x8b/\x99XS\x95[\xf3\xb0Zo\x11r,}\xe1\x16A\x8d\x97\x16\xe2\xc8\xc7\x1f\xdfBwj\xc5\x95i\xc3V5n\xec\xd1>\x1a\xc1\x89G\xa2\xb0B\xef\xe2;\x16\xd5\xd6q\x937\xed[J\xfb4\x8c}\xe1:\x98\xdc\xdcj\x89\xe5*n\xfe=\xe9!\xc1\x189\x92\x92\xaf\xd9?\xb8>J\x84\x15\x99\xa2\xb4\xf5bE\xb1\xd7\xb6\xba:\xa5\x92l\xd4\xab\xb4Q\xab\xba\x95b}\xd5\x19`S\xcc\x17\x8f\xfdc\xdc]M \xcef\xa4\x15)\xd6x\x13E\xb2\xed%9\xae\x11\xcd\xc5t\xdfD\xac\xd7\xc6U\xbc~Q\x16\xe3\xce\x04\x9a6\x94\xe8\xd5\xd8d\x12 \xbc\xc5i\x95\xa8\xf4k\xffL\x99\xd2\xe6q\x9b\xf5\x89\x88\x0c)\x00\x0d\xe9/<\xe6\xc8f\xafv6\xa0a\x0e!\xe2\xc2\x14\xc0\x90\xcd{m\xa0hN\xbf\x8a&\x08\xd1\xc0\xd3Tn\x192\xe4\xbc\xf1\xb7\x0c\xbb\xdaSV\x16\xcek\xe8*K\x8d\xebKSU\xa6\x1c\xff\xf5\xa6\xa9VP\xafNS\xb5\xf8&(T*\xec\xd4GRT\xf3\x94\xd3\x8aa\xc8\xfd\xb3\xcc;\x96\xc1\xd6;sZ\xb1\xbd\x98f\x86_\xdd\xc8\xeamw\xca'\xcb\x93\xd7\x81~\xb1~\xa4\xb0\x10\x97~\x05:\x0f5\xfc\nt\x1e\xe2&\xeb\xe3W^\xd0\x02\xde\xce\x05B\xe7\xe1\x85\xbb@\xa9\x92i\xc8\xa2>/\xdc\xcc\xbc\x19P\xf5if@\x93'\xf6\xe8&\xa0\xdc\xa0\xbf\x85\xd1\xb5Z\x9f\xb7\x9cqZd\xae\x1d\x82\x07^8\xaea\xb2c\x88\xb8\xd9\x9b\xd9\xce~n\xd9l\xc7\x8c~\x15\xa6;\x8d\n\xd4\xe7;2p\xdf\x89\xb9 H\xc8\xe8\xceW\xfe\x1f\x99\xdc\x1eA\x8c\x91\xcfm\x8f\xfc\xcbj\xc3F6\x8d_~\x8b\xb4vL\xbf\x89\x05\xb7$l5\xa5-\xbf\xc2\xe4\x9d\xda\x10\x97q\xd2D\xdf\x85l\xd1&\x89q\xa7\xdfa\xda]\x0e\xbcY\xb2\x9dOi\\\xde\x1a3\xb0\x15-K\xb5\xca*\xeb\x1ew\xfc\xe2R\xeeE\xba_\xba\x1f$a\xfd4\x9a\xe4A]\xb0:qp\xf2$]\x91P[\x0dT\x05\x99\xa5\xf7F$x\x86tZ>+\xd8\x84\xad\xb9\xecd=\x1e?\x8b\xd1i-Y\x933\x14\x0b2\xfe\xaa\xbe\xbd\xa0t\x7f\x81\xec7+a\x0b\xf6f%j h\xc8c\xdd\x86C-\x04\xafx\xeb`\xdd\x97O\x8d\xad\xae\xd5\"\xc8*Y\xae\xda\xb6\x17\x93)\x7f[<\xd9.\x9e,<\xda\xcbO\xdd\xb7d\x02_c\xee\x7f\xdd-\xe07\\\xe2\xd6\xb0\xa1\x16\x19lU\xa3^T\xfa\xfa\xcd\x96\xb6hK\xdf\xf2\xe9o\xe6\x10\xbcfs\xe8\xf8\x84\"\xdb|`\xd68n\xf1f\n\xbf\x0bS\x98\xcd\xfb\x0b5\x84\xdfB\xf5\x9fEq\xed\x03\x99\\\xfb\xb8\xd1\x9b\xfa~G\xea\xfb\x9aB\x99\xb7\xe4\xd670hk\x1f\xcb`4c[\x94\x8b7v\xd0V\x88\x9c\x89\xec\xad\xe2\xa0\x1a4c \x81Hn4\x8b\x9b\xbe\x15\x11\xa4\xcf\x1aY\xbc\xb6\x05_\xa7\\/@\xd4Y\x081\x1d\xa0\xaa\xb3\x04\xee\xe3&\x80\x91\x07\x94\xc8\xe3\x9b\xc7\x7f\xe1\xf2_\xed\xf1\xf3s\xfe\xc2]=\x1c\x93\x08\x1b\xfda\xcd]?}\xa1N\xee\xe2\x04\xf9\xc4N\xa0\xdeN%%Q\xa8;\x8aA\x82\xe4\xab\x93\xda\xb6`\xeb\xee\xba\xa1\xf3\x80\x18\xdd\x89\xf9Za\xb0>\xc6\x17\x8aJ\x88\xf8\xed\xfa\x18,\xbd\xc6\xe5\x89~\xe1\x1a'\x07a\x89\xe3V4\xd6\x86\xb2\x1a\x0dlOi\xb5\x11\xf4\xba\xc7\xce\x8d\xd4\x87FA\xe0\xcfw\x18a\xb0\xe2\xf6\x9b{\xfe\x1a\xc8\xb6\x80\x0c\x80C<,.\xed\x15w|\x8d\xa0g\x12\xfa;\x01R_y\x9e\x87\x7f\x82\xb8\x16\x19\xb8\xf3U\xdc\xf5\xe1a1\x9e\xfa\xd7|\xaa\xd0\x1bZ2\xb87\xd173h\xbf\xd6\xa1(\xee?\x82\x8c\x8c\xad\xe7=\xbd\xfe\xcd1\xd0\xb1\xae\xf3\xafe\x83\x8d\xc72\x0d\xb4\x89\xb4(\xb2\xc7!/F\xc8y\xb8\x9f\xc9\xbb\xb4$\xaa\x92U.[c\x87\xb8J\x10\xa0\xb3=.d\xb0\xd8\"7\xf2!\xa4\xbd\x88\xaa\xb7\xb4\xe8\xd0\xf0VS\x88\xd9\xa2v\x1e\x1e\x90\xca\xee|2\xac|\x9f\x97\x19\x9d\x11/\x19o\xad:\xbf\xfft\x0b\xbd\xf8\x10\xb8D\xbeU\xa6\x81\x8e\xca \xf1\xbf\n\x85\xfc\x7f\x8a\xfc\xe1s\xdc)\xb3\x03\xecv\xb2\xdf\xc5\xf0\xc5\xffj\x87\xb3\x0567\x8b\xff\xb8D>\x8f\xfe\xde\xa6\xfe\xf9\xa6\xfe`M\xa6\xdep\x93\x9e\xbd\x08p\x9b\xd1c\xcaq\x03\x86\xaf\x03\x14\xd3\x92\x10\xe1J\xb1[\x0c]\x90\xcf\x04~\x04\xe9h\x01\xe4/\x90\xa6\xa7t\x17\xc3\xa5\xa2\x00\xc99\xb3\x1e\xf9\x03\x9aW\x8aR!IZh\xf1\x81\x0e\xd5\x9e\xd2\xdf\xcf\xd4\xcb\xd2KXs6\xbd//uE\x98K\x94\x9b\xbb\xc40\xf5\xa6\xf2V\xd6]\x17\x05\x0f\x07\xfbN\x04\xbf\x0c\x1f\x9e\x10<|\n\x86\x0f\x8f{\x87\x0c\x7f\x99\xbaO\x93}8p\xf6\xdc\xee\xd1\x06\xc8.\xc1^ \x1d\xb5o\x87\xe5\xd1\x85\xf5\x84\x14\xae5\xd3z\xd8\x94 \xca\xe0C\x12\x94\x14\xd7\xdc\xd5\x90\x9b\x07\x1d.Q\xbf\xa4\xc2Wj\x9e6\xbd\xba:\xb8\xde\xdb\xef\xecw\xf6\xf6/\x0e\xba\xfb\x07\x9d\xdd\xc3\xee\xc9\xf9\xc1\xe1U\xe7\xf2\xf2b\xef\xf8\xfa\xec\xf2\xf0`\xf7\xba\xb3\xbf\x01\xc0\xfdL$g\xad\x07\x9b\x97\xfd\x05\x14_v\x8e\x0fv\xf7\x8e/Ov\xf7NN\xf6NvO\xba'\x07\xd7\xd7\xfb\xe7\x9d\xb3\x93\xdd\xce\xd1\xf5\xeeu\xf7\xe2\xf2\xaas\xb9wtv|tq\xd59\xdc\xdf\xbf\xea\xee\x1e]\x9c_\xef\x9d\xef\x9f\x1c\x1e\x1cVkP\xe1\xa6\x83\xb4\xdb\xbd\xc3\xe3\xf8\xc7\x85\n\x9e[8\x84\x8a\x05\x02:n\x00\xe3\xaa0g\xde\x81\x891z\x7fR\xd1\\\xe5e\x97\xdb\xdb\xcef\x01Y\xde\x85\xd9\xa2:\xdc;\xd8W1\xe5\xcd50x P\xeb\x9e\xcc\xcc\x13\xdd\xc2!\x0f\x19\x91+$\xed~F\xad\x85M\xac%z\x8eNKL\x93\x9f\\q\xd1\x08(\x80C\xd4\x93\x8d\x1a\x81*\x8bG{H\xdf\x1b{\xd6\x94\xee%.\x97\xcdZ\x89\x17b\xf5\xe7\xd3$t\xc1zj\xc6\xb4\x14\xd04\xe9\xff\x03\x1d&\x828@%\xafe\xa5{C\xa8\x95\xdd\x92\x06\xe82\x9c\xcb\x8b\xb9\x9a\xd5\x1c\xa3qu\x14H\xbd!\x86,\n\x9b\x0dT\x03m\xe8G>\xa9\xd0|\xb8\xfa\xe3\xe2\xe6\xf7\xcbNw@/oCx\xfc\x81\xf5?\xd2\xf9\xf9\xee\xf4\xa8\xffx\xff\xe1\xe0\xe0\xcfhw\xef\xf8\xe9\xf7\xfe\xb5\xf3\xe7l\xff\xef\x17\xd7\xf3\xb3\x9b!:\xf8\xf3\x9f\xb7\x83\xf77\xd1\xe4\xe9\xfc\xaf\xc3\x93\x0f\xf3\xc7_\xe8\xe3\xe5\xf1\xdd\xee\xcd\xd4\xbb\n\xfe\xee\xfd\xd1?\xfct\xe72?\x18\xfe\xfb\x1fJ\xafA\xd4\xef\xe5\x02\x14`\x1a#\xa8L\xb1 \x90\xc2o\x15C\x059\xfb\xc6\x10vQ8\xf60\xdb\xb9\x8d\xfa\xef\xd1\xfc\x0e9A\xf7\xe0\xf0a\xb7\x98\xc92l([\xf6s6y\xea\xec\x7f\x1a\xb1\xf7\xbf\x8e\x8e\xcf..>=\xf97\xc7\xf0\x9e\xd0\x9f\xe7\x1d\xef\xe1\xfa_\xefo>\xfd\xf2\xfb\xde\x97\xf7\x1fBB\x7fQ{\x86\x8e\xb0N%KS\xd9u\xd6m\xce $\xfb\xa9\xcd\xb0\x9c\xfb\xc4y\xb8\xb9\xb4\xd6\xfa\x9a\x91o\x00CV2SV\xb2^\xb0\xa4\xc0d\x18\x81:\xa6\x8e\xf2s\x9eR\xb0\x88Z\xc1\x88_\x94\x93\xd6-\x98!\xd2}\xb9\x0f\x8e\xaa\xc3!\x19\x8b\x8e\xa2\xfeV7ag\xad\xb8&q\x18\xcc\x1b\x9b\xe3\xfb\x02\xccf\xb7\xb3{\xb4\xb5\xdb\xdd\xda\xeb\xdcw\x0eN\x0f\xf6N;'\xdb\xdd\xe3\xa3\xbfwvO\xb3h\x02G\xe3\x9e\xc6\xa1\x98\x08I\xf8\xecC\xcaz\xe2\xd2\xda\x1c\x17\xf4Ip)iI\x8f\xd2\xb3\xd7\xe8s\xef@\xedT\\\x9d\xcfz5\xc5\x91\xafv\xeb\xc2\xa4\x97\xb5\xd3\xba\x90\x18\xcdX\xaf9\xb8r\xd2N=@\x18\x04uA\x04Oe\xf8[\xbb\xbb\xe4h\xf4\xbapAre7TW|F\xd0x]\x98NK\xf1;\x95\x1a\xb6EHl]{\xb9\xab\x1a\x17\x18\x04u\xe1;\x89\x91\xb16/\xc5{\x1f\xccj\x95\xbf\xf4\xa1~d\xa8\xa1\xbe|\xe0}SL\x8a\xbe6\x9f\xad\xd2g\x9d66F\xe2D\xb2\xefe\xd67\xc6\xf8\xa5\xba\xd0-\xd5\xfd\xb2\x88gOe\xa8\x91a\xf0\xb0\x8b4Gk.\x807F\x0d\xf21\xed\xe3-\x875$\x11\xd6|\x84\xbb\x1cR\xee\xf3(\x83\xe3`)\xc4V\xce\xb0\x80\xd7\xd8\x9f&\x12\x91O\xda_\xb7\xf4R/\xcc\xf2\xb1\x15i\xf9\x18\x16\x03\xf2\xb1f\xc8Qt\x7fq\xb4\xff\xbb\xff\x80\x1f\xff\xfd\xe7\xd5tx\xf4 \x1f~8\xfem|t\x1d\xfd\xd5\xb9\xfam\xbf\xffe\x12}9\x0c\xa7\xbf\xec\x8e\xef\xff\xf85\xfc\x18}\xf8\xf0\xd7\xe4\xec\xec\xf1\xfe\xe4\xd3\x97\x7f\x0eo;\x1f\xcfv\xee/\x83\xc3h\xe7\xa4{\xf6\x18\xfe5\xf8\xd7\xafw\xc1\xf9\xef\xff\xf8G\x1aR\xd5K.I\xf6\x8cQ9woe*t7\xe5\xd8ZM\xb0\x94\xa9)\xb8\x143\xc8\xa6\xdc\xf5@C\xb1\x85\x16\xffE\xc2\x8fh\nC\xd7\x9aO\x15\x96E\xdbu1\xbb\x9a\x90\x1d*\xdd\x02[\x1b_\xb9\x0cNG$6L\xe5\xb0\xa8\xf5\xb8B\xb5\xfdr\x04\x19\x99\x9c\x8b@\xdb\xe8)\x19z\\\xe6a=\xd8Ah\x9f5\xde\x8c\xf3\xe9\xc3\x138\n\x0fg\xa3\x11;\x08\xc7\x8f\x13\x84\x0f\xbb\xc7\xf8\xc1\x9f\xf9\xd1\xd3|r\xfct\xf2\xe5\xf1\x8b3v2\x99\xce\xe5\xcb\xef\xc4\xb28\xc9\x93\x03\x12\x82\xf7h\xde\x87\x14\x89Mw\xc0\x08\x18\"\x8cB\xc8\x10\x80@\xd4\x0c\x9e\xf6\x87\xdd\xf0dH\x83\xc7\xe1\xe1\xf0\xc4\xa1{\x0f'N4\x88;\x99\x10\xe6\xe1a/ \xd3\x1a\xa2\xbe\xabH^\xba\xe4\nB\x8f\x84\x1e\xb3\x1eS\x8a\xe5\x1e\xcd\xd8\xad\xc0\x92\xd8N\x0b\xf6\x071\x80F\xd5\xf3\xbb\xe8\xccc~\xb5*\xaabV\xd5.\xed2\x1f\xc2U\xb5\xa4\x0c\xb2\xa8Z\xa7\x07\x1e\xe6(\xa1\xef\xcf{\xc5\xcd\"}v\x9d7\xcd\xef\x1dSq7Zoa\x0eG&H\\\x14\x10Z^8-\xab\xec\xb1$Q\x06\xc3\x05\xa4\xdc\xc6\"\xd3\xc6dk\xf8^!\xc8\x97\xea\xd0-:\xd6o\xa6.\xcb)\xdb\xe1\xc4\x13E\x16\xad\xd7\x15\xdb\xa2\x08\x87\xf5 \xe7e\xc3ovr\xdb\x9d\xf4I\xfde\x9f2\xe8U\xeb\xce\"\x1c\xd8>\n\xd0\x83\xf7\xb8\x85\xefM\x10k\x8e\xe8\x13I<\x95\x05\xd3&\x84-0\x98\xb6\xb3L\xaa-O}\xcf\xc4\xff\xddB\x1c\x9f\xe5\n\x83\xa8\xbf\x16\xbe\xea\x0b\xf4\xfcr\xd1T>\x98\xd0[\xdc\x82K \x0f\x08W\xcb\xbc\x9b\xc4\xf7=:\x82\xe1\x02\x05\xa9p VK\xcc1\xc1\xde\x83\xe5\x9e\x8d\xe7\"\xccr^\xb6\xa2\xf1\x14\xf5\xa9W\xbc\xb9\xd9\xd0\x96\"'\xe2\xee\xbb\xe7\x10\xcc\xa0\xa3\xdd\xd3,\x01\xb9\x88A\xcf\xa7\x0b\xdb\xf6 vK_G.R\xcfM\x15\xd8\xc3,\x84=6\xeb\xc5'\x0bU\xcf\xb0f_!\xc2\x1c\x0f\xf7PM\xe9\xc80,t\xb4\xb90\xe7\xe4\xa8\xb3\xd5\xd9\xdd\xea\xec\xdew:\xa7\xe2\xff\xff\xcatl<\xf6h\xe3\xa4sX\xba\x96\xdb0O\xc6D\xd8\x18\xcez\xed`qF\x10\x0fQ\x0b\xc8\xe4\xd5\xd6\x05\x1e[\"2\xf1:[\xb8[[\xd1\xcc\x02\x94\xcc\xa8\x86\x90\x8a\xe4\x89\xa6\xb5\x85M\xe9C\x1f\xe6\xd6\x90\x95Q\xc5\x1f\x89hf\x03\xadU\xfe\xb7\xca\xc1\"\xccB\xaf\x9d\xb5e:\xcc+\x8937\xf4+\xb5\x1f\x8b1\x0b\xac\xd0\xef\x958m3\x1b\x9a6N\x88\x04\xe3m\xec\xcb\xd8\xc3\xd5FD3\xa1\xd6\x03[\xe5d>3\xd3\xf2V\xdd\xc4\xb5\xac\xd5G\xe4>\x1f\xbfh\xe8\xd4\x84p)\xb3\x82hQeT\x8el\x168\xc45\xc6>\x8f^k\xaa\x1c\xc2-\xb2h^=c`\x05B%\xcd+\xe7\xb6\xb1Y\x1a\xf4^z\x94\xdd\xa4\x85\xf6\x16lh)\xba\xa6\xc8\x1f\xf4Dd\xd3b~:\xb7\x1c\x17E\x8e\xa6\xf0b\x19\xec\xb7Q\xdf\xf7\x9c\xf7\xc8^tD\x93\xaa\x19\xab./\xbf\xf3\x86\xd8\xc3\xc3Z\xd3$\xd3\x10\x16\xa6Xl\x82\xf6\xc8`@QuC\xb9\xfa\xe8E\x98y\xa5\x14\x7f\xc1\xb8S\x8a\\Y\xc3BM\xf1j\nq\x0bC8\xbe\x10\xc1\x93\xfd\xe0\xa2>\x0d`\x8d\x0c3e\xf0\xc1\xc3iUd\x8d\xd5\xdc\xe6\x078Ke\x98* \xa7:86\xab\xa69\x1d\xa9\xfc\x9a\xcd\x9a \xad\xef\xb5\xdc\x9c_\xd4_l/g\x05\x0ci`\xab\xe0?\xafT\xc04\x0b\xdazD\x9d\n~\xfbD\xf0E\x92q\xb8c\xb0F*\xc6j\xcb\xc7\xc6i\x85\x84,J\xbe~$$\xcd\xba\xe6k\xb1z9\xfbQ-\x05w\xf2\xab\xeb\x8fi\x7f\x16\xa3lfC\xad$\xa9\\\xd6X\xb4Q\xca%\xac\xdf\x96\xd4\x07\xa4\xbf\x12\xb6\xd0\x89\xcaik\xb2\xb3\xb2\xba6\xac\x8ajM\x8a*\xb2@N\x8a\xa0\xf2\x12\xf8zJ\xb1@\x1d\x06!yB\xa5\xa8 K\xa5\x89O\xf4\xad;\x0b\xb2\xd6Z\x08=\x14\x10\xd1\x14\xd5M\xe4jk\xa8\xca\x96S\xf9\xbdl?\xe5S*@\xb7\x80\xc9\x7f0j\x04\xbaP\n\xd9,\xb8\xdd\xac8VW\xb4f%\xdd\x06&\x9b\x18\xbc\xb0@\xcd\xc8\xb1\x05\x85i\x15\x9c6d\x92L\xc5hM0i\x0b\xd0\x9a 2\x16\x9dY!\xabQl\xa6\x93r\xd9\x87\xb6\xc8,\xed#_`f*.\xb3\x119\xf9\x18\x8b\xca\xac\x06\xbc\xcab2\xbe\xae@n\xcd\x02\xfd\xa6\x15\xb4\xc5jUC(\xca\x1bq\x90\x9aT\xad\xd0\xe5\x96\xb9\x94<\xda!\xa8\xcdUA0\x04JF<\xc5`)y\xaa\xa2.kd\xd9\xa5\x9b\xc9\x15o\xd6\x9c\xce\xae\xb4Y8\x97IC\xc5\xfd\xabnR\x0b\x95;\x1bG\x9e*\x19@\xb6\xa8\x06^@\xddB6\xcaC.\nz/\nc\xb1\x18>e\x9az\x9e\x9c\xa49\"ZY\x14\x8f\xab\x17DX3\xf2B\x01J\xd7\x94\xa5\x0b\xfdkx5\xc5\x05\xeb\xfa\xb0\xe6\x8a\xed\x98\xd3\xdb\x90\x16\x162\xe4C\xdc\x1a\xeaj\x19!\xa7\x12c=F\x818'\x8a5\x18m\x1d>\x88\xa3zr\xbfT8\n\x84\x1d}[E\xc4\xc5\xccd\xd3K\x97Px1\xfc%\x05\x0d\xac\xa5\x1d\x90\xa7\xc5\xd5g\x8d\x84[\xa4\xbf\xb2\xd5\xfaZAu\x14\x16\xa3^l\x02\xc5Ei\x1e\xae>\x9d\xa5\x96\x05,\xdb=\xe3\xd5jM\xa5\xd2\xf0\xf5Sf\"%\x9b\x1a\xd9\xc7\xd2Ml:~H\xfcU\xcdn\x95\xd3\xed,z\x15M\xaa\xbal\x1e\x14U}![\xbe\xa6\x9e\xc7\xfc$\xd2\x96T\x94\x1b\xcb\x93(\xc5\xe5u:\x80\x92\x19\x8c\xdb\x97t\xb1\x02\xc4E\x94\xc5\x07n\xd9\xf7\xa3\x02\xd5\xea\xac\xb4\x08.4\xfc\x01\xdc\xffv\xf9\xdb)\xb8\x8c\xe4ae\xe8\x13a\xe8*\xfeVl\x03\xe8\x7fW\x85 \xc5\xa4{\xf9\xad$\xa4\x82\xea\xe4\xd1\xea\xba\x16N\x0d\x80\xcb\xe9N`f\xfe\x04\xfa\xc5\x94.\xa8\x12TQ \xba\x10\xe0\xbf\x02\x00\x00\xff\xffPK\x07\x08+\x96\x8a\xd7X(\x00\x00\xf2\x83\x01\x00PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00\x00\x00!(\xd4`4t\xc7\x01\x00\x00\xbd\x01\x00\x00\x11\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x00\x00\x00\x00favicon-16x16.pngUT\x05\x00\x01\x80Cm8PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00\x00\x00!(6B\xc8\xd7\x7f\x04\x00\x00u\x04\x00\x00\x11\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x0f\x02\x00\x00favicon-32x32.pngUT\x05\x00\x01\x80Cm8PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00\x00\x00!(\xb9\xb1\xf1mT\x02\x00\x008\x05\x00\x00\n\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\xd6\x06\x00\x00index.htmlUT\x05\x00\x01\x80Cm8PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00\x00\x00!(]\x12r 9\x03\x00\x00T \x00\x00\x14\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81k \x00\x00oauth2-redirect.htmlUT\x05\x00\x01\x80Cm8PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00\x00\x00!(-\xe3\xb5\x97=9\x05\x00\xf7\x0c\x1b\x00\x14\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\xef\x0c\x00\x00swagger-ui-bundle.jsUT\x05\x00\x01\x80Cm8PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00\x00\x00!(v\xf2\x8aA\x86\xba\x01\x00\xc5\x87\x08\x00\x1f\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81wF\x05\x00swagger-ui-standalone-preset.jsUT\x05\x00\x01\x80Cm8PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00\x00\x00!(_;\x94/\xe8Y\x00\x00\xa8X\x02\x00\x0e\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81S\x01\x07\x00swagger-ui.cssUT\x05\x00\x01\x80Cm8PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00\x00\x00!(+\x96\x8a\xd7X(\x00\x00\xf2\x83\x01\x00\x0c\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x80[\x07\x00swagger.yamlUT\x05\x00\x01\x80Cm8PK\x05\x06\x00\x00\x00\x00\x08\x00\x08\x00E\x02\x00\x00\x1b\x84\x07\x00\x00\x00" fs.Register(data) } diff --git a/client/lcd/swagger-ui/swagger.yaml b/client/lcd/swagger-ui/swagger.yaml index 0b246d4b466d..573b40dce5dd 100644 --- a/client/lcd/swagger-ui/swagger.yaml +++ b/client/lcd/swagger-ui/swagger.yaml @@ -21,6 +21,8 @@ tags: description: Slashing module APIs - name: Distribution description: Fee distribution module APIs + - name: IBC + description: IBC module APIs - name: Supply description: Supply module APIs - name: version @@ -1886,6 +1888,931 @@ paths: type: string 500: description: Internal Server Error + /ibc/clients/{client-id}/consensus-state: + get: + summary: Query cliet consensus-state + tags: + - IBC + produces: + - application/json + parameters: + - in: path + name: client-id + description: Client ID + required: true + type: string + x-example: ibcclientid + - in: query + name: prove + description: Proof of result + type: boolean + x-example: false + responses: + 200: + description: OK + schema: + type: object + properties: + consensus_state: + $ref: "#/definitions/ConsensusState" + proof: + $ref: "#/definitions/Proof" + proof_path: + $ref: "#/definitions/ProofPath" + proof_height: + type: integer + 400: + description: Invalid client id + 500: + description: Internal Server Error + /ibc/clients/{client-id}/client-state: + get: + summary: Query client state + tags: + - IBC + produces: + - application/json + parameters: + - in: path + name: client-id + description: Client ID + required: true + type: string + x-example: ibcclientid + - in: query + name: prove + description: Proof of result + type: boolean + x-example: false + responses: + 200: + description: OK + schema: + type: object + properties: + client_state: + $ref: "#/definitions/ClientState" + proof: + $ref: "#/definitions/Proof" + proof_path: + $ref: "#/definitions/ProofPath" + proof_height: + type: integer + 400: + description: Invalid client id + 500: + description: Internal Server Error + /ibc/clients/{client-id}/roots/{height}: + get: + summary: Query client root + tags: + - IBC + produces: + - application/json + parameters: + - in: path + name: client-id + description: Client ID + required: true + type: string + x-example: ibcclientid + - in: path + name: height + description: Root height + required: true + type: number + x-example: 1 + - in: query + name: prove + description: Proof of result + type: boolean + x-example: true + responses: + 200: + description: OK + schema: + type: object + properties: + root: + $ref: "#/definitions/Root" + proof: + $ref: "#/definitions/Proof" + proof_path: + $ref: "#/definitions/ProofPath" + proof_height: + type: integer + 400: + description: Invalid client id or height + 500: + description: Internal Server Error + /ibc/header: + get: + summary: Query header + tags: + - IBC + produces: + - application/json + responses: + 200: + description: OK + schema: + $ref: "#/definitions/Header" + 500: + description: Internal Server Error + /ibc/node-state: + get: + summary: Query node consensus-state + tags: + - IBC + produces: + - application/json + responses: + 200: + description: OK + schema: + $ref: "#/definitions/ConsensusState" + 500: + description: Internal Server Error + /ibc/path: + get: + summary: Query IBC path + tags: + - IBC + produces: + - application/json + responses: + 200: + description: OK + schema: + type: string + 500: + description: Internal Server Error + /ibc/clients: + post: + summary: Create client + consumes: + - application/json + produces: + - application/json + tags: + - IBC + parameters: + - in: body + name: "Create client request body" + required: true + schema: + type: object + properties: + base_req: + $ref: "#/definitions/BaseReq" + client_id: + type: string + consensus_state: + type: object + properties: + type: + type: string + value: + $ref: "#/definitions/ConsensusState" + responses: + 200: + description: OK + schema: + $ref: "#/definitions/StdTx" + 500: + description: Internal Server Error + /ibc/clients/{client-id}/update: + post: + summary: Update client + consumes: + - application/json + produces: + - application/json + tags: + - IBC + parameters: + - in: path + name: client-id + description: Client ID + required: true + type: string + x-example: ibcclientid + - in: body + name: "Update client request body" + required: true + schema: + type: object + properties: + base_req: + $ref: "#/definitions/BaseReq" + header: + $ref: "#/definitions/Header" + responses: + 200: + description: OK + schema: + $ref: "#/definitions/StdTx" + 400: + description: Invalid client id + 500: + description: Internal Server Error + /ibc/clients/{client-id}/misbehaviour: + post: + summary: Submit misbehaviour + consumes: + - application/json + produces: + - application/json + tags: + - IBC + parameters: + - in: path + name: client-id + description: Client ID + required: true + type: string + x-example: ibcclientid + - in: body + name: "Submit misbehaviour request body" + required: true + schema: + type: object + properties: + base_req: + $ref: "#/definitions/BaseReq" + evidence: + $ref: "#/definitions/Evidence" + responses: + 200: + description: OK + schema: + $ref: "#/definitions/StdTx" + 400: + description: Invalid client id + 500: + description: Internal Server Error + /ibc/connections/{connection-id}: + get: + summary: Query connection + tags: + - IBC + produces: + - application/json + parameters: + - in: path + name: connection-id + description: Connection ID + required: true + type: string + x-example: ibcconnectionid + - in: query + name: prove + description: Proof of result + type: boolean + x-example: false + responses: + 200: + description: OK + schema: + $ref: "#/definitions/ConnectionResponse" + 400: + description: Invalid connection id + 500: + description: Internal Server Error + /ibc/clients/{client-id}/connections: + get: + summary: Query connections of a client + tags: + - IBC + produces: + - application/json + parameters: + - in: path + name: client-id + description: Client ID + required: true + type: string + x-example: ibcclientid + - in: query + name: prove + description: Proof of result + type: boolean + x-example: false + responses: + 200: + description: OK + schema: + $ref: "#/definitions/ClientConnectionsResponse" + 400: + description: Invalid client id + 500: + description: Internal Server Error + /ibc/connections/open-init: + post: + summary: Connection open-init + consumes: + - application/json + produces: + - application/json + tags: + - IBC + parameters: + - in: body + name: "Connection open-init request body" + required: true + schema: + type: object + properties: + base_req: + $ref: "#/definitions/BaseReq" + connection_id: + type: string + client_id: + type: string + counterparty_client_id: + type: string + counterparty_connection_id: + type: string + counterparty_prefix: + $ref: "#/definitions/Prefix" + responses: + 200: + description: OK + schema: + $ref: "#/definitions/StdTx" + 500: + description: Internal Server Error + /ibc/connections/open-try: + post: + summary: Connection open-try + consumes: + - application/json + produces: + - application/json + tags: + - IBC + parameters: + - in: body + name: "Connection open-try request body" + required: true + schema: + type: object + properties: + base_req: + $ref: "#/definitions/BaseReq" + connection_id: + type: string + client_id: + type: string + counterparty_client_id: + type: string + counterparty_connection_id: + type: string + counterparty_prefix: + $ref: "#/definitions/Prefix" + counterparty_versions: + type: array + items: + type: string + proof_init: + type: object + properties: + type: + type: string + value: + $ref: "#/definitions/Proof" + proof_consensus: + type: object + properties: + type: + type: string + value: + $ref: "#/definitions/Proof" + proof_height: + type: integer + consensus_height: + type: integer + responses: + 200: + description: OK + schema: + $ref: "#/definitions/StdTx" + 500: + description: Internal Server Error + /ibc/connections/{connection-id}/open-ack: + post: + summary: Connection open-ack + consumes: + - application/json + produces: + - application/json + tags: + - IBC + parameters: + - in: path + name: connection-id + description: Connection ID + required: true + type: string + x-example: ibcconnectionid + - in: body + name: "Connection open-ack request body" + required: true + schema: + type: object + properties: + base_req: + $ref: "#/definitions/BaseReq" + proof_try: + type: object + properties: + type: + type: string + value: + $ref: "#/definitions/Proof" + proof_consensus: + type: object + properties: + type: + type: string + value: + $ref: "#/definitions/Proof" + proof_height: + type: integer + consensus_height: + type: integer + version: + type: string + responses: + 200: + description: OK + schema: + $ref: "#/definitions/StdTx" + 400: + description: Invalid connection id + 500: + description: Internal Server Error + /ibc/connections/{connection-id}/open-confirm: + post: + summary: Connection open-confirm + consumes: + - application/json + produces: + - application/json + tags: + - IBC + parameters: + - in: path + name: connection-id + description: Connection ID + required: true + type: string + x-example: ibcconnectionid + - in: body + name: "Connection open-confirm request body" + required: true + schema: + type: object + properties: + base_req: + $ref: "#/definitions/BaseReq" + proof_ack: + type: object + properties: + type: + type: string + value: + $ref: "#/definitions/Proof" + proof_height: + type: integer + responses: + 200: + description: OK + schema: + $ref: "#/definitions/StdTx" + 400: + description: Invalid connection id + 500: + description: Internal Server Error + /ibc/ports/{port-id}/channels/{channel-id}: + get: + summary: Query channel + tags: + - IBC + produces: + - application/json + parameters: + - in: path + name: port-id + description: Port ID + required: true + type: string + x-example: ibcmoduleport + - in: path + name: channel-id + description: Channel ID + required: true + type: string + x-example: ibcchannelid + - in: query + name: prove + description: Proof of result + type: boolean + x-example: false + responses: + 200: + description: OK + schema: + $ref: "#/definitions/ChannelResponse" + 400: + description: Invalid port id or channel id + 500: + description: Internal Server Error + /ibc/channels/open-init: + post: + summary: Channel open-init + consumes: + - application/json + produces: + - application/json + tags: + - IBC + parameters: + - in: body + name: "Channel open-init request body" + required: true + schema: + type: object + properties: + base_req: + $ref: "#/definitions/BaseReq" + port_id: + type: string + channel_id: + type: string + version: + type: string + channel_order: + type: string + connection_hops: + type: array + items: + type: string + counterparty_port_id: + type: string + counterparty_channel_id: + type: string + responses: + 200: + description: OK + schema: + $ref: "#/definitions/StdTx" + 500: + description: Internal Server Error + /ibc/channels/open-try: + post: + summary: Channel open-try + consumes: + - application/json + produces: + - application/json + tags: + - IBC + parameters: + - in: body + name: "Channel open-try request body" + required: true + schema: + type: object + properties: + base_req: + $ref: "#/definitions/BaseReq" + port_id: + type: string + channel_id: + type: string + version: + type: string + channel_order: + type: string + connection_hops: + type: array + items: + type: string + counterparty_port_id: + type: string + counterparty_channel_id: + type: string + counterparty_version: + type: string + proof_init: + type: object + properties: + type: + type: string + value: + $ref: "#/definitions/Proof" + proof_height: + type: integer + responses: + 200: + description: OK + schema: + $ref: "#/definitions/StdTx" + 500: + description: Internal Server Error + /ibc/ports/{port-id}/channels/{channel-id}/open-ack: + post: + summary: Channel open-ack + consumes: + - application/json + produces: + - application/json + tags: + - IBC + parameters: + - in: path + name: port-id + description: Port ID + required: true + type: string + x-example: ibcmoduleport + - in: path + name: channel-id + description: Channel ID + required: true + type: string + x-example: ibcchannelid + - in: body + name: "Channel open-ack request body" + required: true + schema: + type: object + properties: + base_req: + $ref: "#/definitions/BaseReq" + counterparty_version: + type: string + proof_try: + type: object + properties: + type: + type: string + value: + $ref: "#/definitions/Proof" + proof_height: + type: integer + responses: + 200: + description: OK + schema: + $ref: "#/definitions/StdTx" + 400: + description: Invalid port id or channel id + 500: + description: Internal Server Error + /ibc/ports/{port-id}/channels/{channel-id}/open-confirm: + post: + summary: Channel open-confirm + consumes: + - application/json + produces: + - application/json + tags: + - IBC + parameters: + - in: path + name: port-id + description: Port ID + required: true + type: string + x-example: ibcmoduleport + - in: path + name: channel-id + description: Channel ID + required: true + type: string + x-example: ibcchannelid + - in: body + name: "Channel open-confirm request body" + required: true + schema: + type: object + properties: + base_req: + $ref: "#/definitions/BaseReq" + proof_ack: + type: object + properties: + type: + type: string + value: + $ref: "#/definitions/Proof" + proof_height: + type: integer + responses: + 200: + description: OK + schema: + $ref: "#/definitions/StdTx" + 400: + description: Invalid port id or channel id + 500: + description: Internal Server Error + /ibc/ports/{port-id}/channels/{channel-id}/close-init: + post: + summary: Channel close-init + consumes: + - application/json + produces: + - application/json + tags: + - IBC + parameters: + - in: path + name: port-id + description: Port ID + required: true + type: string + x-example: ibcmoduleport + - in: path + name: channel-id + description: Channel ID + required: true + type: string + x-example: ibcchannelid + - in: body + name: "Channel close-init request body" + required: true + schema: + type: object + properties: + base_req: + $ref: "#/definitions/BaseReq" + responses: + 200: + description: OK + schema: + $ref: "#/definitions/StdTx" + 500: + description: Internal Server Error + /ibc/ports/{port-id}/channels/{channel-id}/close-confirm: + post: + summary: Channel close-confirm + consumes: + - application/json + produces: + - application/json + tags: + - IBC + parameters: + - in: path + name: port-id + description: Port ID + required: true + type: string + x-example: ibcmoduleport + - in: path + name: channel-id + description: Channel ID + required: true + type: string + x-example: ibcchannelid + - in: body + name: "Channel close-confirm request body" + required: true + schema: + type: object + properties: + base_req: + $ref: "#/definitions/BaseReq" + proof_init: + type: object + properties: + type: + type: string + value: + $ref: "#/definitions/Proof" + proof_height: + type: integer + responses: + 200: + description: OK + schema: + $ref: "#/definitions/StdTx" + 400: + description: Invalid port id or channel id + 500: + description: Internal Server Error + /ibc/ports/{port-id}/channels/{channel-id}/next-sequence-recv: + get: + summary: Query next sequence receive + tags: + - IBC + produces: + - application/json + parameters: + - in: path + name: port-id + description: Port ID + required: true + type: string + x-example: ibcmoduleport + - in: path + name: channel-id + description: Channel ID + required: true + type: string + x-example: ibcchannelid + responses: + 200: + description: OK + schema: + type: integer + 400: + description: Invalid port id or channel id + 500: + description: Internal Server Error + /ibc/ports/{port-id}/channels/{channel-id}/transfer: + post: + summary: Transfer token + consumes: + - application/json + produces: + - application/json + tags: + - IBC + parameters: + - in: path + name: port-id + description: Port ID + required: true + type: string + x-example: ibcmoduleport + - in: path + name: channel-id + description: Channel ID + required: true + type: string + x-example: ibcchannelid + - in: body + name: "Transfer token request body" + required: true + schema: + type: object + properties: + base_req: + $ref: "#/definitions/BaseReq" + amount: + type: array + items: + $ref: "#/definitions/Coin" + receiver: + type: string + source: + type: boolean + responses: + 200: + description: OK + schema: + $ref: "#/definitions/StdTx" + 400: + description: Invalid port id or channel id + 500: + description: Internal Server Error + /ibc/packets/receive: + post: + summary: Receive packet + consumes: + - application/json + produces: + - application/json + tags: + - IBC + parameters: + - in: body + name: "Receive packet request body" + required: true + schema: + type: object + properties: + base_req: + $ref: "#/definitions/BaseReq" + packet: + $ref: "#/definitions/Packet" + proofs: + type: array + items: + $ref: "#/definitions/Proof" + height: + type: integer + responses: + 200: + description: OK + schema: + $ref: "#/definitions/StdTx" + 500: + description: Internal Server Error /supply/total: get: summary: Total supply of coins in the chain @@ -1918,7 +2845,7 @@ paths: 200: description: OK schema: - type: string + type: string 400: description: Invalid coin denomination 500: @@ -2540,3 +3467,273 @@ definitions: type: array items: $ref: "#/definitions/Coin" + IBCValidator: + type: object + properties: + address: + $ref: "#/definitions/ValidatorAddress" + pub_key: + type: object + properties: + type: + type: string + value: + type: string + voting_power: + type: string + example: "1000" + proposer_priority: + type: string + example: "1000" + ConsensusState: + type: object + properties: + chain_id: + type: string + height: + type: integer + root: + $ref: "#/definitions/Root" + next_validator_set: + $ref: "#/definitions/ValidatorSet" + Root: + type: object + properties: + type: + type: string + value: + type: object + properties: + hash: + type: string + Prefix: + type: object + properties: + type: + type: string + value: + type: object + properties: + key_prefix: + type: string + ValidatorSet: + type: object + properties: + validators: + type: array + items: + $ref: "#/definitions/IBCValidator" + proposer: + $ref: "#/definitions/IBCValidator" + ClientState: + type: object + properties: + id: + type: string + frozen: + type: boolean + Proof: + type: object + properties: + proof: + type: object + properties: + ops: + type: array + items: + type: object + properties: + type: + type: string + key: + type: string + data: + type: string + Commit: + type: object + properties: + block_id: + $ref: "#/definitions/BlockID" + precommits: + type: array + items: + type: object + properties: + validator_address: + type: string + validator_index: + type: string + example: "0" + height: + type: string + example: "0" + round: + type: string + example: "0" + timestamp: + type: string + example: "2017-12-30T05:53:09.287+01:00" + type: + type: number + example: 2 + block_id: + $ref: "#/definitions/BlockID" + signature: + type: string + example: "7uTC74QlknqYWEwg7Vn6M8Om7FuZ0EO4bjvuj6rwH1mTUJrRuMMZvAAqT9VjNgP0RA/TDp6u/92AqrZfXJSpBQ==" + SignedHeader: + type: object + properties: + header: + $ref: "#/definitions/BlockHeader" + commit: + $ref: "#/definitions/Commit" + Header: + type: object + properties: + type: + type: string + value: + type: object + properties: + SignedHeader: + $ref: "#/definitions/SignedHeader" + validator_set: + $ref: "#/definitions/ValidatorSet" + next_validator_set: + $ref: "#/definitions/ValidatorSet" + ConnectionResponse: + type: object + properties: + connection: + $ref: "#/definitions/Connection" + proof: + $ref: "#/definitions/Proof" + proof_path: + $ref: "#/definitions/ProofPath" + proof_height: + type: integer + Connection: + type: object + properties: + state: + type: string + client_id: + type: string + counterparty: + $ref: "#/definitions/ConnectionCounterparty" + versions: + type: array + items: + type: string + ConnectionCounterparty: + type: object + properties: + client_id: + type: string + connection_id: + type: string + prefix: + type: object + properties: + key_prefix: + type: string + ProofPath: + type: object + properties: + key_path: + type: array + items: + type: object + properties: + name: + type: string + enc: + type: integer + ClientConnectionsResponse: + type: object + properties: + connection_paths: + type: array + items: + type: string + proof: + $ref: "#/definitions/Proof" + proof_path: + $ref: "#/definitions/ProofPath" + proof_height: + type: integer + ChannelResponse: + type: object + properties: + channel: + $ref: "#/definitions/Channel" + proof: + $ref: "#/definitions/Proof" + proof_path: + $ref: "#/definitions/ProofPath" + proof_height: + type: integer + Channel: + type: object + properties: + state: + type: string + ordering: + type: string + counterparty: + $ref: "#/definitions/Counterparty" + connection_hops: + type: array + items: + type: string + version: + type: string + ChannelCounterparty: + type: object + properties: + port_id: + type: string + channel_id: + type: string + Packet: + type: object + properties: + type: + type: string + value: + type: object + properties: + sequence: + type: integer + timeout: + type: integer + source_port: + type: string + source_channel: + type: string + destination_port: + type: string + destination_channel: + type: string + data: + type: string + # TODO: DuplicateVoteEvidence + DuplicateVoteEvidence: + type: string + Evidence: + type: object + properties: + type: + type: string + value: + type: object + properties: + DuplicateVoteEvidence: + $ref: "#/definitions/DuplicateVoteEvidence" + chain_id: + type: string + val_power: + type: integer + total_power: + type: integer diff --git a/docs/architecture/adr-003-dynamic-capability-store.md b/docs/architecture/adr-003-dynamic-capability-store.md index 20ef7dee8335..104deb109660 100644 --- a/docs/architecture/adr-003-dynamic-capability-store.md +++ b/docs/architecture/adr-003-dynamic-capability-store.md @@ -3,6 +3,7 @@ ## Changelog - 12 December 2019: Initial version +- 02 April 2020: Memory Store Revisions ## Context @@ -15,20 +16,33 @@ At present, the Cosmos SDK does not have the ability to do this. Object-capabili and passed to Keepers as fixed arguments ([example](https://github.com/cosmos/gaia/blob/dcbddd9f04b3086c0ad07ee65de16e7adedc7da4/app/app.go#L160)). Keepers cannot create or store capability keys during transaction execution — although they could call `NewKVStoreKey` and take the memory address of the returned struct, storing this in the Merklised store would result in a consensus fault, since the memory address will be different on each machine (this is intentional — were this not the case, the keys would be predictable and couldn't serve as object capabilities). -Keepers need a way to keep a private map of store keys which can be altered during transacton execution, along with a suitable mechanism for regenerating the unique memory addresses (capability keys) in this map whenever the application is started or restarted. +Keepers need a way to keep a private map of store keys which can be altered during transaction execution, along with a suitable mechanism for regenerating the unique memory addresses (capability keys) in this map whenever the application is started or restarted. This ADR proposes such an interface & mechanism. ## Decision -The SDK will include a new `CapabilityKeeper` abstraction, which is responsible for provisioning, tracking, and authenticating capabilities at runtime. During application initialisation in `app.go`, the `CapabilityKeeper` will -be hooked up to modules through unique function references (by calling `ScopeToModule`, defined below) so that it can identify the calling module when later invoked. When the initial state is loaded from disk, the `CapabilityKeeper`'s `Initialise` function will create new capability keys -for all previously allocated capability identifiers (allocated during execution of past transactions and assigned to particular modes), and keep them in a memory-only store while the chain is running. The SDK will include a new `MemoryStore` store type, similar -to the existing `TransientStore` but without erasure on `Commit()`, which this `CapabilityKeeper` will use to privately store capability keys. +The SDK will include a new `CapabilityKeeper` abstraction, which is responsible for provisioning, +tracking, and authenticating capabilities at runtime. During application initialisation in `app.go`, +the `CapabilityKeeper` will be hooked up to modules through unique function references +(by calling `ScopeToModule`, defined below) so that it can identify the calling module when later +invoked. -The `CapabilityKeeper` will use two stores: a regular, persistent `KVStore`, which will track what capabilities have been created by each module, and an in-memory `MemoryStore` (described below), which will -store the actual capabilities. The `CapabilityKeeper` will define the following types & functions: +When the initial state is loaded from disk, the `CapabilityKeeper`'s `Initialise` function will create +new capability keys for all previously allocated capability identifiers (allocated during execution of +past transactions and assigned to particular modes), and keep them in a memory-only store while the +chain is running. -The `Capability` interface is similar to `StoreKey`, but has a globally unique `Index()` instead of a name. A `String()` method is provided for debugging. +The `CapabilityKeeper` will include an ephemeral in-memory `CapabilityStore`, which internally maintains +two maps, one for forward mappings that map from module name, capability tuples to capability names and +one for reverse mappings that map from module name, capability name to capabilities. The reverse +mapping contains the actual capability objects by reference. + +In addition to the `CapabilityStore`, the `CapabilityKeeper` will use a persistent `KVStore`, which +will track what capabilities have been created by each module. The `CapabilityKeeper` will define the +following types & functions: + +The `Capability` interface is similar to `StoreKey`, but has a globally unique `Index()` instead of +a name. A `String()` method is provided for debugging. ```golang type Capability interface { @@ -50,25 +64,28 @@ A `CapabilityKeeper` contains a persistent store key, memory store key, and mapp ```golang type CapabilityKeeper struct { persistentKey StoreKey - memoryKey MemoryStoreKey - moduleNames map[string]interface{} - sealed bool + capStore CapabilityStore + moduleNames map[string]interface{} + sealed bool } ``` -The `CapabilityKeeper` provides the ability to create *scoped* sub-keepers which are tied to a particular module name. These `ScopedCapabilityKeeper`s must be created at application -initialisation and passed to modules, which can then use them to claim capabilities they receive and retrieve capabilities which they own by name, in addition -to creating new capabilities & authenticating capabilities passed by other modules. +The `CapabilityKeeper` provides the ability to create *scoped* sub-keepers which are tied to a +particular module name. These `ScopedCapabilityKeeper`s must be created at application initialisation +and passed to modules, which can then use them to claim capabilities they receive and retrieve +capabilities which they own by name, in addition to creating new capabilities & authenticating capabilities +passed by other modules. ```golang type ScopedCapabilityKeeper struct { persistentKey StoreKey - memoryKey MemoryStoreKey - moduleName string + capStore CapabilityStore + moduleName string } ``` -`ScopeToModule` is used to create a scoped sub-keeper with a particular name, which must be unique. It MUST be called before `InitialiseAndSeal`. +`ScopeToModule` is used to create a scoped sub-keeper with a particular name, which must be unique. +It MUST be called before `InitialiseAndSeal`. ```golang func (ck CapabilityKeeper) ScopeToModule(moduleName string) ScopedCapabilityKeeper { @@ -78,35 +95,41 @@ func (ck CapabilityKeeper) ScopeToModule(moduleName string) ScopedCapabilityKeep if _, present := ck.moduleNames[moduleName]; present { panic("cannot create multiple scoped capability keepers for the same module name") } + ck.moduleNames[moduleName] = struct{}{} + return ScopedCapabilityKeeper{ persistentKey: ck.persistentKey, - memoryKey: ck.memoryKey, - moduleName: moduleName + capStore: ck.capStore, + moduleName: moduleName, } } ``` -`InitialiseAndSeal` MUST be called exactly once, after loading the initial state and creating all necessary `ScopedCapabilityKeeper`s, -in order to populate the memory store with newly-created capability keys in accordance with the keys previously claimed by particular modules -and prevent the creation of any new `ScopedCapabilityKeeper`s. +`InitialiseAndSeal` MUST be called exactly once, after loading the initial state and creating all +necessary `ScopedCapabilityKeeper`s, in order to populate the memory store with newly-created +capability keys in accordance with the keys previously claimed by particular modules and prevent the +creation of any new `ScopedCapabilityKeeper`s. ```golang func (ck CapabilityKeeper) InitialiseAndSeal(ctx Context) { if ck.sealed { panic("capability keeper is sealed") } + persistentStore := ctx.KVStore(ck.persistentKey) - memoryStore := ctx.KVStore(ck.memoryKey) + // initialise memory store for all names in persistent store for index, value := range persistentStore.Iter() { capability = &CapabilityKey{index: index} + for moduleAndCapability := range value { moduleName, capabilityName := moduleAndCapability.Split("/") - memoryStore.Set(moduleName + "/fwd/" + capability, capabilityName) - memoryStore.Set(moduleName + "/rev/" + capabilityName, capability) + capStore.Set(moduleName + "/fwd/" + capability, capabilityName) + capStore.Set(moduleName + "/rev/" + capabilityName, capability) } } + ck.sealed = true } ``` @@ -117,24 +140,30 @@ call `ClaimCapability`. ```golang func (sck ScopedCapabilityKeeper) NewCapability(ctx Context, name string) (Capability, error) { - memoryStore := ctx.KVStore(sck.memoryKey) // check name not taken in memory store - if memoryStore.Get("rev/" + name) != nil { + if capStore.Get("rev/" + name) != nil { return nil, errors.New("name already taken") } + // fetch the current index index := persistentStore.Get("index") + // create a new capability capability := &CapabilityKey{index: index} + // set persistent store persistentStore.Set(index, Set.singleton(sck.moduleName + "/" + name)) + // update the index index++ persistentStore.Set("index", index) + // set forward mapping in memory store from capability to name - memoryStore.Set(sck.moduleName + "/fwd/" + capability, name) + capStore.Set(sck.moduleName + "/fwd/" + capability, name) + // set reverse mapping in memory store from name to capability - memoryStore.Set(sck.moduleName + "/rev/" + name, capability) + capStore.Set(sck.moduleName + "/rev/" + name, capability) + // return the newly created capability return capability } @@ -146,24 +175,28 @@ with which the calling module previously associated it. ```golang func (sck ScopedCapabilityKeeper) AuthenticateCapability(name string, capability Capability) bool { - memoryStore := ctx.KVStore(sck.memoryKey) // return whether forward mapping in memory store matches name - return memoryStore.Get(sck.moduleName + "/fwd/" + capability) === name + return capStore.Get(sck.moduleName + "/fwd/" + capability) === name } ``` -`ClaimCapability` allows a module to claim a capability key which it has received from another module so that future `GetCapability` calls will succeed. +`ClaimCapability` allows a module to claim a capability key which it has received from another module +so that future `GetCapability` calls will succeed. -`ClaimCapability` MUST be called if a module which receives a capability wishes to access it by name in the future. Capabilities are multi-owner, so if multiple modules have a single `Capability` reference, they will all own it. +`ClaimCapability` MUST be called if a module which receives a capability wishes to access it by name +in the future. Capabilities are multi-owner, so if multiple modules have a single `Capability` reference, +they will all own it. ```golang func (sck ScopedCapabilityKeeper) ClaimCapability(ctx Context, capability Capability, name string) error { persistentStore := ctx.KVStore(sck.persistentKey) - memoryStore := ctx.KVStore(sck.memoryKey) + // set forward mapping in memory store from capability to name - memoryStore.Set(sck.moduleName + "/fwd/" + capability, name) + capStore.Set(sck.moduleName + "/fwd/" + capability, name) + // set reverse mapping in memory store from name to capability - memoryStore.Set(sck.moduleName + "/rev/" + name, capability) + capStore.Set(sck.moduleName + "/rev/" + name, capability) + // update owner set in persistent store owners := persistentStore.Get(capability.Index()) owners.add(sck.moduleName + "/" + name) @@ -171,33 +204,37 @@ func (sck ScopedCapabilityKeeper) ClaimCapability(ctx Context, capability Capabi } ``` -`GetCapability` allows a module to fetch a capability which it has previously claimed by name. The module is not allowed to retrieve capabilities which it does not own. If another module -claims a capability, the previously owning module will no longer be able to claim it. +`GetCapability` allows a module to fetch a capability which it has previously claimed by name. +The module is not allowed to retrieve capabilities which it does not own. ```golang func (sck ScopedCapabilityKeeper) GetCapability(ctx Context, name string) (Capability, error) { - memoryStore := ctx.KVStore(sck.memoryKey) // fetch capability from memory store - capability := memoryStore.Get(sck.moduleName + "/rev/" + name) + capability := capStore.Get(sck.moduleName + "/rev/" + name) + // return the capability return capability } ``` -`ReleaseCapability` allows a module to release a capability which it had previously claimed. If no more owners exist, the capability will be deleted globally. +`ReleaseCapability` allows a module to release a capability which it had previously claimed. If no +more owners exist, the capability will be deleted globally. ```golang func (sck ScopedCapabilityKeeper) ReleaseCapability(ctx Context, capability Capability) err { persistentStore := ctx.KVStore(sck.persistentKey) - memoryStore := ctx.KVStore(sck.memoryKey) - name := memoryStore.Get(sck.moduleName + "/fwd/" + capability) + + name := capStore.Get(sck.moduleName + "/fwd/" + capability) if name == nil { return error("capability not owned by module") } + // delete forward mapping in memory store memoryStore.Delete(sck.moduleName + "/fwd/" + capability, name) + // delete reverse mapping in memory store memoryStore.Delete(sck.moduleName + "/rev/" + name, capability) + // update owner set in persistent store owners := persistentStore.Get(capability.Index()) owners.remove(sck.moduleName + "/" + name) @@ -211,14 +248,6 @@ func (sck ScopedCapabilityKeeper) ReleaseCapability(ctx Context, capability Capa } ``` -### Memory store - -A new store key type, `MemoryStoreKey`, will be added to the `store` package. The `MemoryStoreKey`s work just like `StoreKey`s. - -The memory store will work just like the current transient store, except that it will not create a new `dbadapter.Store` when `Commit()` is called, but instead retain the current one (so that state will persist across blocks). - -Initially the memory store will only be used by the `CapabilityKeeper`, but it could be used by other modules in the future. - ### Usage patterns #### Initialisation diff --git a/docs/architecture/adr-015-ibc-packet-receiver.md b/docs/architecture/adr-015-ibc-packet-receiver.md index 2ea26dcb5bae..924ddc7eb648 100644 --- a/docs/architecture/adr-015-ibc-packet-receiver.md +++ b/docs/architecture/adr-015-ibc-packet-receiver.md @@ -192,22 +192,7 @@ func NewAnteHandler( } ``` -The implementation of this ADR will also change the `Data` field of the `Packet` type from `[]byte` (i.e. arbitrary data) to `PacketDataI`. We want to make application modules be able to register custom packet data type which is automatically unmarshaled at `TxDecoder` time and can be simply type switched inside the application handler. Also, by having `GetCommitment()` method instead of manually generate the commitment inside the IBC keeper, the applications can define their own commitment method, including bare bytes, hashing, etc. - -This also removes the `Timeout` field from the `Packet` struct. This is because the `PacketDataI` interface now contains this information. You can see details about this in [ICS04](https://github.com/cosmos/ics/tree/master/spec/ics-004-channel-and-packet-semantics#definitions). - -The `PacketDataI` is the application specific interface that provides information for the execution of the application packet. In the case of ICS20 this would be `denom`, `amount` and `address` - -```go -// PacketDataI defines the standard interface for IBC packet data -type PacketDataI interface { - GetCommitment() []byte // Commitment form that will be stored in the state. - GetTimeoutHeight() uint64 - - ValidateBasic() error - Type() string -} -``` +The implementation of this ADR will also create a `Data` field of the `Packet` of type `[]byte`, which can be deserialised by the receiving module into its own private type. It is up to the application modules to do this according to their own interpretation, not by the IBC keeper. This is crucial for dynamic IBC. Example application-side usage: @@ -234,15 +219,17 @@ func NewHandler(k Keeper) Handler { case MsgTransfer: return handleMsgTransfer(ctx, k, msg) case ibc.MsgPacket: - switch data := msg.Packet.Data.(type) { - case PacketDataTransfer: // i.e fulfills the PacketDataI interface - return handlePacketDataTransfer(ctx, k, msg.Packet, data) + var data PacketDataTransfer + if err := types.ModuleCodec.UnmarshalBinaryBare(msg.GetData(), &data); err != nil { + return err } - case ibc.MsgTimeoutPacket: - switch packet := msg.Packet.Data.(type) { - case PacketDataTransfer: // i.e fulfills the PacketDataI interface - return handleTimeoutPacketDataTransfer(ctx, k, msg.Packet) + return handlePacketDataTransfer(ctx, k, msg, data) + case ibc.MsgTimeoutPacket: + var data PacketDataTransfer + if err := types.ModuleCodec.UnmarshalBinaryBare(msg.GetData(), &data); err != nil { + return err } + return handleTimeoutPacketDataTransfer(ctx, k, packet) // interface { PortID() string; ChannelID() string; Channel() ibc.Channel } // MsgChanInit, MsgChanTry implements ibc.MsgChannelOpen case ibc.MsgChannelOpen: diff --git a/docs/package-lock.json b/docs/package-lock.json index fd136c2262c5..6299944f6859 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -10661,4 +10661,4 @@ "integrity": "sha1-4Se9nmb9hGvl6rSME5SIL3wOT5g=" } } -} +} \ No newline at end of file diff --git a/docs/spec/ibc/README.md b/docs/spec/ibc/README.md deleted file mode 100644 index e763c2760caa..000000000000 --- a/docs/spec/ibc/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Cosmos Inter-Blockchain Communication (IBC) Protocol - -__Disclaimer__ This module has been removed from the repository for the time being. If you would like to follow the process of IBC, go to [ICS repo](https://github.com/cosmos/ics), there you will find the standard and updates. \ No newline at end of file diff --git a/simapp/app.go b/simapp/app.go index 90e75741399b..47611b3f408c 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -18,11 +18,16 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/auth/ante" "github.com/cosmos/cosmos-sdk/x/bank" + "github.com/cosmos/cosmos-sdk/x/capability" "github.com/cosmos/cosmos-sdk/x/crisis" distr "github.com/cosmos/cosmos-sdk/x/distribution" "github.com/cosmos/cosmos-sdk/x/evidence" "github.com/cosmos/cosmos-sdk/x/genutil" "github.com/cosmos/cosmos-sdk/x/gov" + "github.com/cosmos/cosmos-sdk/x/ibc" + ibcclient "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + port "github.com/cosmos/cosmos-sdk/x/ibc/05-port" + transfer "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer" "github.com/cosmos/cosmos-sdk/x/mint" "github.com/cosmos/cosmos-sdk/x/params" paramsclient "github.com/cosmos/cosmos-sdk/x/params/client" @@ -51,6 +56,7 @@ var ( supply.AppModuleBasic{}, genutil.AppModuleBasic{}, bank.AppModuleBasic{}, + capability.AppModuleBasic{}, staking.AppModuleBasic{}, mint.AppModuleBasic{}, distr.AppModuleBasic{}, @@ -60,18 +66,21 @@ var ( params.AppModuleBasic{}, crisis.AppModuleBasic{}, slashing.AppModuleBasic{}, + ibc.AppModuleBasic{}, upgrade.AppModuleBasic{}, evidence.AppModuleBasic{}, + transfer.AppModuleBasic{}, ) // module account permissions maccPerms = map[string][]string{ - auth.FeeCollectorName: nil, - distr.ModuleName: nil, - mint.ModuleName: {supply.Minter}, - staking.BondedPoolName: {supply.Burner, supply.Staking}, - staking.NotBondedPoolName: {supply.Burner, supply.Staking}, - gov.ModuleName: {supply.Burner}, + auth.FeeCollectorName: nil, + distr.ModuleName: nil, + mint.ModuleName: {supply.Minter}, + staking.BondedPoolName: {supply.Burner, supply.Staking}, + staking.NotBondedPoolName: {supply.Burner, supply.Staking}, + gov.ModuleName: {supply.Burner}, + transfer.GetModuleAccountName(): {supply.Minter, supply.Burner}, } // module accounts that are allowed to receive tokens @@ -99,18 +108,25 @@ type SimApp struct { subspaces map[string]params.Subspace // keepers - AccountKeeper auth.AccountKeeper - BankKeeper bank.Keeper - SupplyKeeper supply.Keeper - StakingKeeper staking.Keeper - SlashingKeeper slashing.Keeper - MintKeeper mint.Keeper - DistrKeeper distr.Keeper - GovKeeper gov.Keeper - CrisisKeeper crisis.Keeper - UpgradeKeeper upgrade.Keeper - ParamsKeeper params.Keeper - EvidenceKeeper evidence.Keeper + AccountKeeper auth.AccountKeeper + BankKeeper bank.Keeper + CapabilityKeeper *capability.Keeper + SupplyKeeper supply.Keeper + StakingKeeper staking.Keeper + SlashingKeeper slashing.Keeper + MintKeeper mint.Keeper + DistrKeeper distr.Keeper + GovKeeper gov.Keeper + CrisisKeeper crisis.Keeper + UpgradeKeeper upgrade.Keeper + ParamsKeeper params.Keeper + IBCKeeper *ibc.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly + EvidenceKeeper evidence.Keeper + TransferKeeper transfer.Keeper + + // make scoped keepers public for test purposes + ScopedIBCKeeper capability.ScopedKeeper + ScopedTransferKeeper capability.ScopedKeeper // the module manager mm *module.Manager @@ -136,7 +152,8 @@ func NewSimApp( keys := sdk.NewKVStoreKeys( bam.MainStoreKey, auth.StoreKey, bank.StoreKey, staking.StoreKey, supply.StoreKey, mint.StoreKey, distr.StoreKey, slashing.StoreKey, - gov.StoreKey, params.StoreKey, upgrade.StoreKey, evidence.StoreKey, + gov.StoreKey, params.StoreKey, ibc.StoreKey, upgrade.StoreKey, + evidence.StoreKey, transfer.StoreKey, capability.StoreKey, ) tkeys := sdk.NewTransientStoreKeys(params.TStoreKey) @@ -161,6 +178,11 @@ func NewSimApp( app.subspaces[crisis.ModuleName] = app.ParamsKeeper.Subspace(crisis.DefaultParamspace) app.subspaces[evidence.ModuleName] = app.ParamsKeeper.Subspace(evidence.DefaultParamspace) + // add capability keeper and ScopeToModule for ibc module + app.CapabilityKeeper = capability.NewKeeper(appCodec, keys[capability.StoreKey]) + scopedIBCKeeper := app.CapabilityKeeper.ScopeToModule(ibc.ModuleName) + scopedTransferKeeper := app.CapabilityKeeper.ScopeToModule(transfer.ModuleName) + // add keepers app.AccountKeeper = auth.NewAccountKeeper( appCodec, keys[auth.StoreKey], app.subspaces[auth.ModuleName], auth.ProtoBaseAccount, @@ -190,15 +212,6 @@ func NewSimApp( ) app.UpgradeKeeper = upgrade.NewKeeper(skipUpgradeHeights, keys[upgrade.StoreKey], appCodec, homePath) - // create evidence keeper with router - evidenceKeeper := evidence.NewKeeper( - appCodec, keys[evidence.StoreKey], app.subspaces[evidence.ModuleName], &app.StakingKeeper, app.SlashingKeeper, - ) - evidenceRouter := evidence.NewRouter() - // TODO: Register evidence routes. - evidenceKeeper.SetRouter(evidenceRouter) - app.EvidenceKeeper = *evidenceKeeper - // register the proposal types govRouter := gov.NewRouter() govRouter.AddRoute(gov.RouterKey, gov.ProposalHandler). @@ -216,12 +229,42 @@ func NewSimApp( staking.NewMultiStakingHooks(app.DistrKeeper.Hooks(), app.SlashingKeeper.Hooks()), ) + // Create IBC Keeper + app.IBCKeeper = ibc.NewKeeper( + app.cdc, keys[ibc.StoreKey], app.StakingKeeper, scopedIBCKeeper, + ) + + // Create Transfer Keepers + app.TransferKeeper = transfer.NewKeeper( + app.cdc, keys[transfer.StoreKey], + app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, + app.BankKeeper, app.SupplyKeeper, + scopedTransferKeeper, + ) + transferModule := transfer.NewAppModule(app.TransferKeeper) + + // Create static IBC router, add transfer route, then set and seal it + ibcRouter := port.NewRouter() + ibcRouter.AddRoute(transfer.ModuleName, transferModule) + app.IBCKeeper.SetRouter(ibcRouter) + + // create evidence keeper with router + evidenceKeeper := evidence.NewKeeper( + appCodec, keys[evidence.StoreKey], app.subspaces[evidence.ModuleName], &app.StakingKeeper, app.SlashingKeeper, + ) + evidenceRouter := evidence.NewRouter(). + AddRoute(ibcclient.RouterKey, ibcclient.HandlerClientMisbehaviour(app.IBCKeeper.ClientKeeper)) + + evidenceKeeper.SetRouter(evidenceRouter) + app.EvidenceKeeper = *evidenceKeeper + // NOTE: Any module instantiated in the module manager that is later modified // must be passed by reference here. app.mm = module.NewManager( genutil.NewAppModule(app.AccountKeeper, app.StakingKeeper, app.BaseApp.DeliverTx), auth.NewAppModule(app.AccountKeeper, app.SupplyKeeper), bank.NewAppModule(app.BankKeeper, app.AccountKeeper), + capability.NewAppModule(*app.CapabilityKeeper), crisis.NewAppModule(&app.CrisisKeeper), supply.NewAppModule(app.SupplyKeeper, app.BankKeeper, app.AccountKeeper), gov.NewAppModule(app.GovKeeper, app.AccountKeeper, app.BankKeeper, app.SupplyKeeper), @@ -231,6 +274,8 @@ func NewSimApp( staking.NewAppModule(app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.SupplyKeeper), upgrade.NewAppModule(app.UpgradeKeeper), evidence.NewAppModule(app.EvidenceKeeper), + ibc.NewAppModule(app.IBCKeeper), + transferModule, ) // During begin block slashing happens after distr.BeginBlocker so that @@ -244,7 +289,8 @@ func NewSimApp( app.mm.SetOrderInitGenesis( auth.ModuleName, distr.ModuleName, staking.ModuleName, bank.ModuleName, slashing.ModuleName, gov.ModuleName, mint.ModuleName, supply.ModuleName, - crisis.ModuleName, genutil.ModuleName, evidence.ModuleName, + crisis.ModuleName, ibc.ModuleName, genutil.ModuleName, evidence.ModuleName, + transfer.ModuleName, ) app.mm.RegisterInvariants(&app.CrisisKeeper) @@ -275,7 +321,12 @@ func NewSimApp( // initialize BaseApp app.SetInitChainer(app.InitChainer) app.SetBeginBlocker(app.BeginBlocker) - app.SetAnteHandler(ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, auth.DefaultSigVerificationGasConsumer)) + app.SetAnteHandler( + ante.NewAnteHandler( + app.AccountKeeper, app.SupplyKeeper, *app.IBCKeeper, + ante.DefaultSigVerificationGasConsumer, + ), + ) app.SetEndBlocker(app.EndBlocker) if loadLatest { @@ -285,6 +336,15 @@ func NewSimApp( } } + // Initialize and seal the capability keeper so all persistent capabilities + // are loaded in-memory and prevent any further modules from creating scoped + // sub-keepers. + ctx := app.BaseApp.NewContext(true, abci.Header{}) + app.CapabilityKeeper.InitializeAndSeal(ctx) + + app.ScopedIBCKeeper = scopedIBCKeeper + app.ScopedTransferKeeper = scopedTransferKeeper + return app } diff --git a/store/rootmulti/store.go b/store/rootmulti/store.go index a4dfbb71abfe..21d26aacf342 100644 --- a/store/rootmulti/store.go +++ b/store/rootmulti/store.go @@ -169,12 +169,13 @@ func (rs *Store) loadVersion(ver int64, upgrades *types.StoreUpgrades) error { // load each Store (note this doesn't panic on unmounted keys now) var newStores = make(map[types.StoreKey]types.CommitKVStore) + for key, storeParams := range rs.storesParams { - // Load it store, err := rs.loadCommitStoreFromParams(key, rs.getCommitID(infos, key.Name()), storeParams) if err != nil { return errors.Wrap(err, "failed to load store") } + newStores[key] = store // If it was deleted, remove all data diff --git a/store/types/store.go b/store/types/store.go index 72575baa6a89..f22742863c97 100644 --- a/store/types/store.go +++ b/store/types/store.go @@ -275,6 +275,24 @@ const ( StoreTypeTransient ) +func (st StoreType) String() string { + switch st { + case StoreTypeMulti: + return "StoreTypeMulti" + + case StoreTypeDB: + return "StoreTypeDB" + + case StoreTypeIAVL: + return "StoreTypeIAVL" + + case StoreTypeTransient: + return "StoreTypeTransient" + } + + return "unknown store type" +} + //---------------------------------------- // Keys for accessing substores diff --git a/types/coin.go b/types/coin.go index 6a759d569387..8f51f640872c 100644 --- a/types/coin.go +++ b/types/coin.go @@ -580,8 +580,8 @@ func (coins Coins) Sort() Coins { // Parsing var ( - // Denominations can be 3 ~ 32 characters long. - reDnmString = `[a-z][a-z0-9/]{2,31}` + // Denominations can be 3 ~ 64 characters long. + reDnmString = `[a-z][a-z0-9/]{2,63}` reAmt = `[[:digit:]]+` reDecAmt = `[[:digit:]]*\.[[:digit:]]+` reSpc = `[[:space:]]*` diff --git a/types/store.go b/types/store.go index 6057526c80e9..ecf4c48dd8e4 100644 --- a/types/store.go +++ b/types/store.go @@ -99,6 +99,7 @@ func NewKVStoreKeys(names ...string) map[string]*KVStoreKey { for _, name := range names { keys[name] = NewKVStoreKey(name) } + return keys } @@ -115,6 +116,7 @@ func NewTransientStoreKeys(names ...string) map[string]*TransientStoreKey { for _, name := range names { keys[name] = NewTransientStoreKey(name) } + return keys } diff --git a/types/utils.go b/types/utils.go index be33160261d5..f1ef6090b7f3 100644 --- a/types/utils.go +++ b/types/utils.go @@ -49,6 +49,16 @@ func Uint64ToBigEndian(i uint64) []byte { return b } +// BigEndianToUint64 returns an uint64 from big endian encoded bytes. If encoding +// is empty, zero is returned. +func BigEndianToUint64(bz []byte) uint64 { + if len(bz) == 0 { + return 0 + } + + return binary.BigEndian.Uint64(bz) +} + // Slight modification of the RFC3339Nano but it right pads all zeros and drops the time zone info const SortableTimeFormat = "2006-01-02T15:04:05.000000000" diff --git a/types/utils_test.go b/types/utils_test.go index 4ffc67c6101c..1c451f185b34 100644 --- a/types/utils_test.go +++ b/types/utils_test.go @@ -87,7 +87,7 @@ func TestUint64ToBigEndian(t *testing.T) { func TestFormatTimeBytes(t *testing.T) { t.Parallel() - tm, err := time.Parse("Jan 2, 2006 at 3:04pm (MST)", "Mar 3, 2020 at 7:54pm (PST)") + tm, err := time.Parse("Jan 2, 2006 at 3:04pm (MST)", "Mar 3, 2020 at 7:54pm (UTC)") require.NoError(t, err) require.Equal(t, "2020-03-03T19:54:00.000000000", string(sdk.FormatTimeBytes(tm))) } diff --git a/x/auth/ante/ante.go b/x/auth/ante/ante.go index bdf24823f137..54c3b8017eb7 100644 --- a/x/auth/ante/ante.go +++ b/x/auth/ante/ante.go @@ -4,12 +4,17 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth/keeper" "github.com/cosmos/cosmos-sdk/x/auth/types" + ibcante "github.com/cosmos/cosmos-sdk/x/ibc/ante" + ibckeeper "github.com/cosmos/cosmos-sdk/x/ibc/keeper" ) // NewAnteHandler returns an AnteHandler that checks and increments sequence // numbers, checks signatures & account numbers, and deducts fees from the first // signer. -func NewAnteHandler(ak keeper.AccountKeeper, supplyKeeper types.SupplyKeeper, sigGasConsumer SignatureVerificationGasConsumer) sdk.AnteHandler { +func NewAnteHandler( + ak keeper.AccountKeeper, supplyKeeper types.SupplyKeeper, ibcKeeper ibckeeper.Keeper, + sigGasConsumer SignatureVerificationGasConsumer, +) sdk.AnteHandler { return sdk.ChainAnteDecorators( NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first NewMempoolFeeDecorator(), @@ -21,6 +26,7 @@ func NewAnteHandler(ak keeper.AccountKeeper, supplyKeeper types.SupplyKeeper, si NewDeductFeeDecorator(ak, supplyKeeper), NewSigGasConsumeDecorator(ak, sigGasConsumer), NewSigVerificationDecorator(ak), - NewIncrementSequenceDecorator(ak), // innermost AnteDecorator + NewIncrementSequenceDecorator(ak), + ibcante.NewProofVerificationDecorator(ibcKeeper.ClientKeeper, ibcKeeper.ChannelKeeper), // innermost AnteDecorator ) } diff --git a/x/auth/ante/ante_test.go b/x/auth/ante/ante_test.go index 23318f2d6d35..25b6b2ed33e0 100644 --- a/x/auth/ante/ante_test.go +++ b/x/auth/ante/ante_test.go @@ -38,7 +38,7 @@ func TestSimulateGasCost(t *testing.T) { // setup app, ctx := createTestApp(true) ctx = ctx.WithBlockHeight(1) - anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, ante.DefaultSigVerificationGasConsumer) + anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, *app.IBCKeeper, ante.DefaultSigVerificationGasConsumer) // keys and addresses priv1, _, addr1 := types.KeyTestPubAddr() @@ -92,7 +92,7 @@ func TestSimulateGasCost(t *testing.T) { func TestAnteHandlerSigErrors(t *testing.T) { // setup app, ctx := createTestApp(true) - anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, ante.DefaultSigVerificationGasConsumer) + anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, *app.IBCKeeper, ante.DefaultSigVerificationGasConsumer) // keys and addresses priv1, _, addr1 := types.KeyTestPubAddr() @@ -142,7 +142,7 @@ func TestAnteHandlerAccountNumbers(t *testing.T) { // setup app, ctx := createTestApp(false) ctx = ctx.WithBlockHeight(1) - anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, ante.DefaultSigVerificationGasConsumer) + anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, *app.IBCKeeper, ante.DefaultSigVerificationGasConsumer) // keys and addresses priv1, _, addr1 := types.KeyTestPubAddr() @@ -201,7 +201,7 @@ func TestAnteHandlerAccountNumbersAtBlockHeightZero(t *testing.T) { // setup app, ctx := createTestApp(false) ctx = ctx.WithBlockHeight(0) - anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, ante.DefaultSigVerificationGasConsumer) + anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, *app.IBCKeeper, ante.DefaultSigVerificationGasConsumer) // keys and addresses priv1, _, addr1 := types.KeyTestPubAddr() @@ -259,7 +259,7 @@ func TestAnteHandlerSequences(t *testing.T) { // setup app, ctx := createTestApp(false) ctx = ctx.WithBlockHeight(1) - anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, ante.DefaultSigVerificationGasConsumer) + anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, *app.IBCKeeper, ante.DefaultSigVerificationGasConsumer) // keys and addresses priv1, _, addr1 := types.KeyTestPubAddr() @@ -335,7 +335,7 @@ func TestAnteHandlerSequences(t *testing.T) { func TestAnteHandlerFees(t *testing.T) { // setup app, ctx := createTestApp(true) - anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, ante.DefaultSigVerificationGasConsumer) + anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, *app.IBCKeeper, ante.DefaultSigVerificationGasConsumer) // keys and addresses priv1, _, addr1 := types.KeyTestPubAddr() @@ -377,7 +377,7 @@ func TestAnteHandlerMemoGas(t *testing.T) { // setup app, ctx := createTestApp(true) ctx = ctx.WithBlockHeight(1) - anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, ante.DefaultSigVerificationGasConsumer) + anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, *app.IBCKeeper, ante.DefaultSigVerificationGasConsumer) // keys and addresses priv1, _, addr1 := types.KeyTestPubAddr() @@ -417,7 +417,7 @@ func TestAnteHandlerMultiSigner(t *testing.T) { // setup app, ctx := createTestApp(false) ctx = ctx.WithBlockHeight(1) - anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, ante.DefaultSigVerificationGasConsumer) + anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, *app.IBCKeeper, ante.DefaultSigVerificationGasConsumer) // keys and addresses priv1, _, addr1 := types.KeyTestPubAddr() @@ -467,7 +467,7 @@ func TestAnteHandlerBadSignBytes(t *testing.T) { // setup app, ctx := createTestApp(true) ctx = ctx.WithBlockHeight(1) - anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, ante.DefaultSigVerificationGasConsumer) + anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, *app.IBCKeeper, ante.DefaultSigVerificationGasConsumer) // keys and addresses priv1, _, addr1 := types.KeyTestPubAddr() @@ -544,7 +544,7 @@ func TestAnteHandlerSetPubKey(t *testing.T) { // setup app, ctx := createTestApp(true) ctx = ctx.WithBlockHeight(1) - anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, ante.DefaultSigVerificationGasConsumer) + anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, *app.IBCKeeper, ante.DefaultSigVerificationGasConsumer) // keys and addresses priv1, _, addr1 := types.KeyTestPubAddr() @@ -662,7 +662,7 @@ func TestAnteHandlerSigLimitExceeded(t *testing.T) { // setup app, ctx := createTestApp(true) ctx = ctx.WithBlockHeight(1) - anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, ante.DefaultSigVerificationGasConsumer) + anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, *app.IBCKeeper, ante.DefaultSigVerificationGasConsumer) // keys and addresses priv1, _, addr1 := types.KeyTestPubAddr() @@ -703,7 +703,7 @@ func TestCustomSignatureVerificationGasConsumer(t *testing.T) { app, ctx := createTestApp(true) ctx = ctx.WithBlockHeight(1) // setup an ante handler that only accepts PubKeyEd25519 - anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, func(meter sdk.GasMeter, sig []byte, pubkey crypto.PubKey, params types.Params) error { + anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, *app.IBCKeeper, func(meter sdk.GasMeter, sig []byte, pubkey crypto.PubKey, params types.Params) error { switch pubkey := pubkey.(type) { case ed25519.PubKeyEd25519: meter.ConsumeGas(params.SigVerifyCostED25519, "ante verify: ed25519") @@ -761,7 +761,7 @@ func TestAnteHandlerReCheck(t *testing.T) { app.AccountKeeper.SetAccount(ctx, acc1) app.BankKeeper.SetBalances(ctx, addr1, types.NewTestCoins()) - antehandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, ante.DefaultSigVerificationGasConsumer) + antehandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, *app.IBCKeeper, ante.DefaultSigVerificationGasConsumer) // test that operations skipped on recheck do not run diff --git a/x/auth/keeper/keeper.go b/x/auth/keeper/keeper.go index e07e9dfba902..3a0c7d5a921c 100644 --- a/x/auth/keeper/keeper.go +++ b/x/auth/keeper/keeper.go @@ -31,11 +31,16 @@ func NewAccountKeeper( cdc types.Codec, key sdk.StoreKey, paramstore paramtypes.Subspace, proto func() exported.Account, ) AccountKeeper { + // set KeyTable if it has not already been set + if !paramstore.HasKeyTable() { + paramstore = paramstore.WithKeyTable(types.ParamKeyTable()) + } + return AccountKeeper{ key: key, proto: proto, cdc: cdc, - paramSubspace: paramstore.WithKeyTable(types.ParamKeyTable()), + paramSubspace: paramstore, } } diff --git a/x/auth/types/querier.go b/x/auth/types/querier.go index 35a7e0ccf32a..a512152114c0 100644 --- a/x/auth/types/querier.go +++ b/x/auth/types/querier.go @@ -12,7 +12,7 @@ const ( // QueryAccountParams defines the params for querying accounts. type QueryAccountParams struct { - Address sdk.AccAddress + Address sdk.AccAddress `json:"account"` } // NewQueryAccountParams creates a new instance of QueryAccountParams. diff --git a/x/bank/keeper/keeper.go b/x/bank/keeper/keeper.go index 5cfdd7187908..423f6a0bf44a 100644 --- a/x/bank/keeper/keeper.go +++ b/x/bank/keeper/keeper.go @@ -38,11 +38,15 @@ func NewBaseKeeper( cdc codec.Marshaler, storeKey sdk.StoreKey, ak types.AccountKeeper, paramSpace paramtypes.Subspace, blacklistedAddrs map[string]bool, ) BaseKeeper { - ps := paramSpace.WithKeyTable(types.ParamKeyTable()) + // set KeyTable if it has not already been set + if !paramSpace.HasKeyTable() { + paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable()) + } + return BaseKeeper{ - BaseSendKeeper: NewBaseSendKeeper(cdc, storeKey, ak, ps, blacklistedAddrs), + BaseSendKeeper: NewBaseSendKeeper(cdc, storeKey, ak, paramSpace, blacklistedAddrs), ak: ak, - paramSpace: ps, + paramSpace: paramSpace, } } diff --git a/x/capability/alias.go b/x/capability/alias.go new file mode 100644 index 000000000000..3c7b743d9fbb --- /dev/null +++ b/x/capability/alias.go @@ -0,0 +1,42 @@ +package capability + +import ( + "github.com/cosmos/cosmos-sdk/x/capability/keeper" + "github.com/cosmos/cosmos-sdk/x/capability/types" +) + +// DONTCOVER + +// nolint +const ( + ModuleName = types.ModuleName + StoreKey = types.StoreKey + MemStoreKey = types.MemStoreKey +) + +// nolint +var ( + NewKeeper = keeper.NewKeeper + NewCapability = types.NewCapability + RevCapabilityKey = types.RevCapabilityKey + FwdCapabilityKey = types.FwdCapabilityKey + KeyIndex = types.KeyIndex + KeyPrefixIndexCapability = types.KeyPrefixIndexCapability + ErrCapabilityTaken = types.ErrCapabilityTaken + ErrOwnerClaimed = types.ErrOwnerClaimed + ErrCapabilityNotOwned = types.ErrCapabilityNotOwned + RegisterCodec = types.RegisterCodec + ModuleCdc = types.ModuleCdc + NewOwner = types.NewOwner + NewCapabilityOwners = types.NewCapabilityOwners + NewCapabilityStore = types.NewCapabilityStore +) + +// nolint +type ( + Keeper = keeper.Keeper + ScopedKeeper = keeper.ScopedKeeper + Capability = types.Capability + CapabilityOwners = types.CapabilityOwners + CapabilityStore = types.CapabilityStore +) diff --git a/x/capability/docs/README.md b/x/capability/docs/README.md new file mode 100644 index 000000000000..a280743d7edf --- /dev/null +++ b/x/capability/docs/README.md @@ -0,0 +1,89 @@ +# x/capability + +## Abstract + +`x/capability` is an implementation of a Cosmos SDK module, per [ADR 003](./../../../docs/architecture/adr-003-dynamic-capability-store.md), +that allows for provisioning, tracking, and authenticating multi-owner capabilities +at runtime. + +The keeper maintains two states: persistent and ephemeral in-memory. The persistent +store maintains a globally unique auto-incrementing index and a mapping from +capability index to a set of capability owners that are defined as a module and +capability name tuple. The in-memory ephemeral state keeps track of the actual +capabilities, represented as addresses in local memory, with both forward and reverse indexes. +The forward index maps module name and capability tuples to the capability name. The +reverse index maps between the module and capability name and the capability itself. + +The keeper allows the creation of "scoped" sub-keepers which are tied to a particular +module by name. Scoped keepers must be created at application initialization and +passed to modules, which can then use them to claim capabilities they receive and +retrieve capabilities which they own by name, in addition to creating new capabilities +& authenticating capabilities passed by other modules. A scoped keeper cannot escape its scope, +so a module cannot interfere with or inspect capabilities owned by other modules. + +The keeper provides no other core functionality that can be found in other modules +like queriers, REST and CLI handlers, and genesis state. + +## Initialization + +During application initialization, the keeper must be instantiated with a persistent +store key and an in-memory store key. + +```go +type App struct { + // ... + + capabilityKeeper *capability.Keeper +} + +func NewApp(...) *App { + // ... + + app.capabilityKeeper = capability.NewKeeper(codec, persistentStoreKey, memStoreKey) +} +``` + +After the keeper is created, it can be used to create scoped sub-keepers which +are passed to other modules that can create, authenticate, and claim capabilities. +After all the necessary scoped keepers are created and the state is loaded, the +main capability keeper must be initialized and sealed to populate the in-memory +state and to prevent further scoped keepers from being created. + +```go +func NewApp(...) *App { + // ... + + // Initialize and seal the capability keeper so all persistent capabilities + // are loaded in-memory and prevent any further modules from creating scoped + // sub-keepers. + ctx := app.BaseApp.NewContext(true, abci.Header{}) + app.capabilityKeeper.InitializeAndSeal(ctx) + + return app +} +``` + +## Capabilities + +Capabilities are multi-owner. A scoped keeper can create a capability via `NewCapability` +which creates a new unique, unforgeable object-capability reference. The newly +created capability is automatically persisted; the calling module need not call +`ClaimCapability`. Calling `NewCapability` will create the capability with the +calling module and name as a tuple to be treated the capabilities first owner. + +Capabilities can be claimed by other modules which add them as owners. `ClaimCapability` +allows a module to claim a capability key which it has received from another +module so that future `GetCapability` calls will succeed. `ClaimCapability` MUST +be called if a module which receives a capability wishes to access it by name in +the future. Again, capabilities are multi-owner, so if multiple modules have a +single Capability reference, they will all own it. If a module receives a capability +from another module but does not call `ClaimCapability`, it may use it in the executing +transaction but will not be able to access it afterwards. + +`AuthenticateCapability` can be called by any module to check that a capability +does in fact correspond to a particular name (the name can be un-trusted user input) +with which the calling module previously associated it. + +`GetCapability` allows a module to fetch a capability which it has previously +claimed by name. The module is not allowed to retrieve capabilities which it does +not own. diff --git a/x/capability/keeper/keeper.go b/x/capability/keeper/keeper.go new file mode 100644 index 000000000000..42b7ce5f3d09 --- /dev/null +++ b/x/capability/keeper/keeper.go @@ -0,0 +1,325 @@ +package keeper + +import ( + "fmt" + + "github.com/tendermint/tendermint/libs/log" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/capability/types" +) + +type ( + // Keeper defines the capability module's keeper. It is responsible for provisioning, + // tracking, and authenticating capabilities at runtime. During application + // initialization, the keeper can be hooked up to modules through unique function + // references so that it can identify the calling module when later invoked. + // + // When the initial state is loaded from disk, the keeper allows the ability to + // create new capability keys for all previously allocated capability identifiers + // (allocated during execution of past transactions and assigned to particular modes), + // and keep them in a memory-only store while the chain is running. + // + // The keeper allows the ability to create scoped sub-keepers which are tied to + // a single specific module. + Keeper struct { + cdc codec.Marshaler + storeKey sdk.StoreKey + capStore types.CapabilityStore + scopedModules map[string]struct{} + sealed bool + } + + // ScopedKeeper defines a scoped sub-keeper which is tied to a single specific + // module provisioned by the capability keeper. Scoped keepers must be created + // at application initialization and passed to modules, which can then use them + // to claim capabilities they receive and retrieve capabilities which they own + // by name, in addition to creating new capabilities & authenticating capabilities + // passed by other modules. + ScopedKeeper struct { + cdc codec.Marshaler + storeKey sdk.StoreKey + capStore types.CapabilityStore // shared amongst all scoped keepers + module string + } +) + +func NewKeeper(cdc codec.Marshaler, storeKey sdk.StoreKey) *Keeper { + return &Keeper{ + cdc: cdc, + storeKey: storeKey, + capStore: types.NewCapabilityStore(), + scopedModules: make(map[string]struct{}), + sealed: false, + } +} + +// ScopeToModule attempts to create and return a ScopedKeeper for a given module +// by name. It will panic if the keeper is already sealed or if the module name +// already has a ScopedKeeper. +func (k *Keeper) ScopeToModule(moduleName string) ScopedKeeper { + if k.sealed { + panic("cannot scope to module via a sealed capability keeper") + } + + if _, ok := k.scopedModules[moduleName]; ok { + panic(fmt.Sprintf("cannot create multiple scoped keepers for the same module name: %s", moduleName)) + } + + k.scopedModules[moduleName] = struct{}{} + + return ScopedKeeper{ + cdc: k.cdc, + storeKey: k.storeKey, + capStore: k.capStore, + module: moduleName, + } +} + +// InitializeAndSeal loads all capabilities from the persistent KVStore into the +// in-memory store and seals the keeper to prevent further modules from creating +// a scoped keeper. InitializeAndSeal must be called once after the application +// state is loaded. +func (k *Keeper) InitializeAndSeal(ctx sdk.Context) { + if k.sealed { + panic("cannot initialize and seal an already sealed capability keeper") + } + + prefixStore := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixIndexCapability) + iterator := sdk.KVStorePrefixIterator(prefixStore, nil) + + // initialize the in-memory store for all persisted capabilities + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + index := types.IndexFromKey(iterator.Key()) + cap := types.NewCapability(index) + + var capOwners types.CapabilityOwners + k.cdc.MustUnmarshalBinaryBare(iterator.Value(), &capOwners) + + for _, owner := range capOwners.Owners { + // Set the forward mapping between the module and capability tuple and the + // capability name in the in-memory store. + k.capStore.SetCapabilityName(owner.Module, owner.Name, cap) + + // Set the reverse mapping between the module and capability name and the + // capability in the in-memory store. + k.capStore.SetCapability(owner.Module, owner.Name, cap) + } + } + + k.sealed = true +} + +// GetLatestIndex returns the latest index of the CapabilityKeeper +func (k Keeper) GetLatestIndex(ctx sdk.Context) uint64 { + store := ctx.KVStore(k.storeKey) + return types.IndexFromKey(store.Get(types.KeyIndex)) +} + +// NewCapability attempts to create a new capability with a given name. If the +// capability already exists in the in-memory store, an error will be returned. +// Otherwise, a new capability is created with the current global unique index. +// The newly created capability has the scoped module name and capability name +// tuple set as the initial owner. Finally, the global index is incremented along +// with forward and reverse indexes set in the in-memory store. +// +// Note, namespacing is completely local, which is safe since records are prefixed +// with the module name and no two ScopedKeeper can have the same module name. +func (sk ScopedKeeper) NewCapability(ctx sdk.Context, name string) (*types.Capability, error) { + store := ctx.KVStore(sk.storeKey) + + if cap := sk.capStore.GetCapability(sk.module, name); cap != nil { + return nil, sdkerrors.Wrapf(types.ErrCapabilityTaken, fmt.Sprintf("module: %s, name: %s", sk.module, name)) + + } + + // create new capability with the current global index + index := types.IndexFromKey(store.Get(types.KeyIndex)) + cap := types.NewCapability(index) + + // update capability owner set + if err := sk.addOwner(ctx, cap, name); err != nil { + return nil, err + } + + // increment global index + store.Set(types.KeyIndex, types.IndexToKey(index+1)) + + // Set the forward mapping between the module and capability tuple and the + // capability name in the in-memory store. + sk.capStore.SetCapabilityName(sk.module, name, cap) + + // Set the reverse mapping between the module and capability name and the + // capability in the in-memory store. + sk.capStore.SetCapability(sk.module, name, cap) + + logger(ctx).Info("created new capability", "module", sk.module, "name", name) + return cap, nil +} + +// AuthenticateCapability attempts to authenticate a given capability and name +// from a caller. It allows for a caller to check that a capability does in fact +// correspond to a particular name. The scoped keeper will lookup the capability +// from the internal in-memory store and check against the provided name. It returns +// true upon success and false upon failure. +// +// Note, the capability's forward mapping is indexed by a string which should +// contain its unique memory reference. +func (sk ScopedKeeper) AuthenticateCapability(ctx sdk.Context, cap *types.Capability, name string) bool { + return sk.capStore.GetCapabilityName(sk.module, cap) == name +} + +// ClaimCapability attempts to claim a given Capability. The provided name and +// the scoped module's name tuple are treated as the owner. It will attempt +// to add the owner to the persistent set of capability owners for the capability +// index. If the owner already exists, it will return an error. Otherwise, it will +// also set a forward and reverse index for the capability and capability name. +func (sk ScopedKeeper) ClaimCapability(ctx sdk.Context, cap *types.Capability, name string) error { + // update capability owner set + if err := sk.addOwner(ctx, cap, name); err != nil { + return err + } + + // Set the forward mapping between the module and capability tuple and the + // capability name in the in-memory store. + sk.capStore.SetCapabilityName(sk.module, name, cap) + + // Set the reverse mapping between the module and capability name and the + // capability in the in-memory store. + sk.capStore.SetCapability(sk.module, name, cap) + + logger(ctx).Info("claimed capability", "module", sk.module, "name", name, "capability", cap.GetIndex()) + return nil +} + +// ReleaseCapability allows a scoped module to release a capability which it had +// previously claimed or created. After releasing the capability, if no more +// owners exist, the capability will be globally removed. +func (sk ScopedKeeper) ReleaseCapability(ctx sdk.Context, cap *types.Capability) error { + name := sk.capStore.GetCapabilityName(sk.module, cap) + if len(name) == 0 { + return sdkerrors.Wrap(types.ErrCapabilityNotOwned, sk.module) + } + + // Remove the forward mapping between the module and capability tuple and the + // capability name in the in-memory store. + sk.capStore.DeleteCapabilityName(sk.module, cap) + + // Remove the reverse mapping between the module and capability name and the + // capability in the in-memory store. + sk.capStore.DeleteCapability(sk.module, name) + + // remove owner + capOwners := sk.getOwners(ctx, cap) + capOwners.Remove(types.NewOwner(sk.module, name)) + + prefixStore := prefix.NewStore(ctx.KVStore(sk.storeKey), types.KeyPrefixIndexCapability) + indexKey := types.IndexToKey(cap.GetIndex()) + + if len(capOwners.Owners) == 0 { + // remove capability owner set + prefixStore.Delete(indexKey) + } else { + // update capability owner set + prefixStore.Set(indexKey, sk.cdc.MustMarshalBinaryBare(capOwners)) + } + + return nil +} + +// GetCapability allows a module to fetch a capability which it previously claimed +// by name. The module is not allowed to retrieve capabilities which it does not +// own. +func (sk ScopedKeeper) GetCapability(ctx sdk.Context, name string) (*types.Capability, bool) { + cap := sk.capStore.GetCapability(sk.module, name) + if cap == nil { + return nil, false + } + + return cap, true +} + +// Get all the Owners that own the capability associated with the name this ScopedKeeper uses +// to refer to the capability +func (sk ScopedKeeper) GetOwners(ctx sdk.Context, name string) (*types.CapabilityOwners, bool) { + cap, ok := sk.GetCapability(ctx, name) + if !ok { + return nil, false + } + + prefixStore := prefix.NewStore(ctx.KVStore(sk.storeKey), types.KeyPrefixIndexCapability) + indexKey := types.IndexToKey(cap.GetIndex()) + + var capOwners types.CapabilityOwners + + bz := prefixStore.Get(indexKey) + if len(bz) == 0 { + return nil, false + } + + sk.cdc.MustUnmarshalBinaryBare(bz, &capOwners) + return &capOwners, true + +} + +// LookupModules returns all the module owners for a given capability +// as a string array, the capability is also returned along with a boolean success flag +func (sk ScopedKeeper) LookupModules(ctx sdk.Context, name string) ([]string, *types.Capability, bool) { + cap, ok := sk.GetCapability(ctx, name) + if !ok { + return nil, nil, false + } + + capOwners, ok := sk.GetOwners(ctx, name) + if !ok { + return nil, nil, false + } + + mods := make([]string, len(capOwners.Owners)) + for i, co := range capOwners.Owners { + mods[i] = co.Module + } + return mods, cap, true + +} + +func (sk ScopedKeeper) addOwner(ctx sdk.Context, cap *types.Capability, name string) error { + prefixStore := prefix.NewStore(ctx.KVStore(sk.storeKey), types.KeyPrefixIndexCapability) + indexKey := types.IndexToKey(cap.GetIndex()) + + capOwners := sk.getOwners(ctx, cap) + + if err := capOwners.Set(types.NewOwner(sk.module, name)); err != nil { + return err + } + + // update capability owner set + prefixStore.Set(indexKey, sk.cdc.MustMarshalBinaryBare(capOwners)) + return nil +} + +func (sk ScopedKeeper) getOwners(ctx sdk.Context, cap *types.Capability) *types.CapabilityOwners { + prefixStore := prefix.NewStore(ctx.KVStore(sk.storeKey), types.KeyPrefixIndexCapability) + indexKey := types.IndexToKey(cap.GetIndex()) + + bz := prefixStore.Get(indexKey) + + var owners *types.CapabilityOwners + if len(bz) == 0 { + owners = types.NewCapabilityOwners() + } else { + var capOwners types.CapabilityOwners + sk.cdc.MustUnmarshalBinaryBare(bz, &capOwners) + owners = &capOwners + } + + return owners +} + +func logger(ctx sdk.Context) log.Logger { + return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) +} diff --git a/x/capability/keeper/keeper_test.go b/x/capability/keeper/keeper_test.go new file mode 100644 index 000000000000..d1c0fd10b411 --- /dev/null +++ b/x/capability/keeper/keeper_test.go @@ -0,0 +1,245 @@ +package keeper_test + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/suite" + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/simapp" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/bank" + "github.com/cosmos/cosmos-sdk/x/capability" + "github.com/cosmos/cosmos-sdk/x/capability/keeper" + "github.com/cosmos/cosmos-sdk/x/capability/types" + "github.com/cosmos/cosmos-sdk/x/staking" +) + +type KeeperTestSuite struct { + suite.Suite + + ctx sdk.Context + keeper *keeper.Keeper +} + +func (suite *KeeperTestSuite) SetupTest() { + checkTx := false + app := simapp.Setup(checkTx) + cdc := codec.NewHybridCodec(app.Codec()) + + // create new keeper so we can define custom scoping before init and seal + keeper := keeper.NewKeeper(cdc, app.GetKey(capability.StoreKey)) + + suite.ctx = app.BaseApp.NewContext(checkTx, abci.Header{Height: 1}) + suite.keeper = keeper +} + +func (suite *KeeperTestSuite) TestInitializeAndSeal() { + sk := suite.keeper.ScopeToModule(bank.ModuleName) + + caps := make([]*types.Capability, 5) + // Get Latest Index before creating new ones to sychronize indices correctly + prevIndex := suite.keeper.GetLatestIndex(suite.ctx) + + for i := range caps { + cap, err := sk.NewCapability(suite.ctx, fmt.Sprintf("transfer-%d", i)) + suite.Require().NoError(err) + suite.Require().NotNil(cap) + suite.Require().Equal(uint64(i)+prevIndex, cap.GetIndex()) + + caps[i] = cap + } + + suite.Require().NotPanics(func() { + suite.keeper.InitializeAndSeal(suite.ctx) + }) + + for i, cap := range caps { + got, ok := sk.GetCapability(suite.ctx, fmt.Sprintf("transfer-%d", i)) + suite.Require().True(ok) + suite.Require().Equal(cap, got) + suite.Require().Equal(uint64(i)+prevIndex, got.GetIndex()) + } + + suite.Require().Panics(func() { + suite.keeper.InitializeAndSeal(suite.ctx) + }) + + suite.Require().Panics(func() { + _ = suite.keeper.ScopeToModule(staking.ModuleName) + }) +} + +func (suite *KeeperTestSuite) TestNewCapability() { + sk := suite.keeper.ScopeToModule(bank.ModuleName) + + cap, err := sk.NewCapability(suite.ctx, "transfer") + suite.Require().NoError(err) + suite.Require().NotNil(cap) + + got, ok := sk.GetCapability(suite.ctx, "transfer") + suite.Require().True(ok) + suite.Require().Equal(cap, got) + suite.Require().True(cap == got, "expected memory addresses to be equal") + + got, ok = sk.GetCapability(suite.ctx, "invalid") + suite.Require().False(ok) + suite.Require().Nil(got) + + cap, err = sk.NewCapability(suite.ctx, "transfer") + suite.Require().Error(err) + suite.Require().Nil(cap) +} + +func (suite *KeeperTestSuite) TestAuthenticateCapability() { + sk1 := suite.keeper.ScopeToModule(bank.ModuleName) + sk2 := suite.keeper.ScopeToModule(staking.ModuleName) + + cap1, err := sk1.NewCapability(suite.ctx, "transfer") + suite.Require().NoError(err) + suite.Require().NotNil(cap1) + + forgedCap := types.NewCapability(0) // index should be the same index as the first capability + suite.Require().False(sk2.AuthenticateCapability(suite.ctx, forgedCap, "transfer")) + + cap2, err := sk2.NewCapability(suite.ctx, "bond") + suite.Require().NoError(err) + suite.Require().NotNil(cap2) + + got, ok := sk1.GetCapability(suite.ctx, "transfer") + suite.Require().True(ok) + + suite.Require().True(sk1.AuthenticateCapability(suite.ctx, cap1, "transfer")) + suite.Require().True(sk1.AuthenticateCapability(suite.ctx, got, "transfer")) + suite.Require().False(sk1.AuthenticateCapability(suite.ctx, cap1, "invalid")) + suite.Require().False(sk1.AuthenticateCapability(suite.ctx, cap2, "transfer")) + + suite.Require().True(sk2.AuthenticateCapability(suite.ctx, cap2, "bond")) + suite.Require().False(sk2.AuthenticateCapability(suite.ctx, cap2, "invalid")) + suite.Require().False(sk2.AuthenticateCapability(suite.ctx, cap1, "bond")) + + sk2.ReleaseCapability(suite.ctx, cap2) + suite.Require().False(sk2.AuthenticateCapability(suite.ctx, cap2, "bond")) + + badCap := types.NewCapability(100) + suite.Require().False(sk1.AuthenticateCapability(suite.ctx, badCap, "transfer")) + suite.Require().False(sk2.AuthenticateCapability(suite.ctx, badCap, "bond")) +} + +func (suite *KeeperTestSuite) TestClaimCapability() { + sk1 := suite.keeper.ScopeToModule(bank.ModuleName) + sk2 := suite.keeper.ScopeToModule(staking.ModuleName) + + cap, err := sk1.NewCapability(suite.ctx, "transfer") + suite.Require().NoError(err) + suite.Require().NotNil(cap) + + suite.Require().Error(sk1.ClaimCapability(suite.ctx, cap, "transfer")) + suite.Require().NoError(sk2.ClaimCapability(suite.ctx, cap, "transfer")) + + got, ok := sk1.GetCapability(suite.ctx, "transfer") + suite.Require().True(ok) + suite.Require().Equal(cap, got) + + got, ok = sk2.GetCapability(suite.ctx, "transfer") + suite.Require().True(ok) + suite.Require().Equal(cap, got) +} + +func (suite *KeeperTestSuite) TestGetOwners() { + sk1 := suite.keeper.ScopeToModule(bank.ModuleName) + sk2 := suite.keeper.ScopeToModule(staking.ModuleName) + sk3 := suite.keeper.ScopeToModule("foo") + + sks := []keeper.ScopedKeeper{sk1, sk2, sk3} + + cap, err := sk1.NewCapability(suite.ctx, "transfer") + suite.Require().NoError(err) + suite.Require().NotNil(cap) + + suite.Require().NoError(sk2.ClaimCapability(suite.ctx, cap, "transfer")) + suite.Require().NoError(sk3.ClaimCapability(suite.ctx, cap, "transfer")) + + expectedOrder := []string{bank.ModuleName, "foo", staking.ModuleName} + // Ensure all scoped keepers can get owners + for _, sk := range sks { + owners, ok := sk.GetOwners(suite.ctx, "transfer") + mods, cap, mok := sk.LookupModules(suite.ctx, "transfer") + + suite.Require().True(ok, "could not retrieve owners") + suite.Require().NotNil(owners, "owners is nil") + + suite.Require().True(mok, "could not retrieve modules") + suite.Require().NotNil(cap, "capability is nil") + suite.Require().NotNil(mods, "modules is nil") + + suite.Require().Equal(len(expectedOrder), len(owners.Owners), "length of owners is unexpected") + for i, o := range owners.Owners { + // Require owner is in expected position + suite.Require().Equal(expectedOrder[i], o.Module, "module is unexpected") + suite.Require().Equal(expectedOrder[i], mods[i], "module in lookup is unexpected") + } + } + + // foo module releases capability + err = sk3.ReleaseCapability(suite.ctx, cap) + suite.Require().Nil(err, "could not release capability") + + // new expected order and scoped capabilities + expectedOrder = []string{bank.ModuleName, staking.ModuleName} + sks = []keeper.ScopedKeeper{sk1, sk2} + + // Ensure all scoped keepers can get owners + for _, sk := range sks { + owners, ok := sk.GetOwners(suite.ctx, "transfer") + mods, cap, mok := sk.LookupModules(suite.ctx, "transfer") + + suite.Require().True(ok, "could not retrieve owners") + suite.Require().NotNil(owners, "owners is nil") + + suite.Require().True(mok, "could not retrieve modules") + suite.Require().NotNil(cap, "capability is nil") + suite.Require().NotNil(mods, "modules is nil") + + suite.Require().Equal(len(expectedOrder), len(owners.Owners), "length of owners is unexpected") + for i, o := range owners.Owners { + // Require owner is in expected position + suite.Require().Equal(expectedOrder[i], o.Module, "module is unexpected") + suite.Require().Equal(expectedOrder[i], mods[i], "module in lookup is unexpected") + } + } + +} + +func (suite *KeeperTestSuite) TestReleaseCapability() { + sk1 := suite.keeper.ScopeToModule(bank.ModuleName) + sk2 := suite.keeper.ScopeToModule(staking.ModuleName) + + cap1, err := sk1.NewCapability(suite.ctx, "transfer") + suite.Require().NoError(err) + suite.Require().NotNil(cap1) + + suite.Require().NoError(sk2.ClaimCapability(suite.ctx, cap1, "transfer")) + + cap2, err := sk2.NewCapability(suite.ctx, "bond") + suite.Require().NoError(err) + suite.Require().NotNil(cap2) + + suite.Require().Error(sk1.ReleaseCapability(suite.ctx, cap2)) + + suite.Require().NoError(sk2.ReleaseCapability(suite.ctx, cap1)) + got, ok := sk2.GetCapability(suite.ctx, "transfer") + suite.Require().False(ok) + suite.Require().Nil(got) + + suite.Require().NoError(sk1.ReleaseCapability(suite.ctx, cap1)) + got, ok = sk1.GetCapability(suite.ctx, "transfer") + suite.Require().False(ok) + suite.Require().Nil(got) +} + +func TestKeeperTestSuite(t *testing.T) { + suite.Run(t, new(KeeperTestSuite)) +} diff --git a/x/capability/module.go b/x/capability/module.go new file mode 100644 index 000000000000..1ee89573c4b4 --- /dev/null +++ b/x/capability/module.go @@ -0,0 +1,117 @@ +package capability + +import ( + "encoding/json" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + + "github.com/gorilla/mux" + "github.com/spf13/cobra" + abci "github.com/tendermint/tendermint/abci/types" +) + +var ( + _ module.AppModule = AppModule{} + _ module.AppModuleBasic = AppModuleBasic{} + + // TODO: Enable simulation once concrete types are defined. + // _ module.AppModuleSimulation = AppModuleSimulation{} +) + +// ---------------------------------------------------------------------------- +// AppModuleBasic +// ---------------------------------------------------------------------------- + +// AppModuleBasic implements the AppModuleBasic interface for the capability module. +type AppModuleBasic struct { +} + +func NewAppModuleBasic() AppModuleBasic { + return AppModuleBasic{} +} + +// Name returns the capability module's name. +func (AppModuleBasic) Name() string { + return ModuleName +} + +// RegisterCodec registers the capability module's types to the provided codec. +func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) { + RegisterCodec(cdc) +} + +// DefaultGenesis returns the capability module's default genesis state. +func (AppModuleBasic) DefaultGenesis(_ codec.JSONMarshaler) json.RawMessage { return []byte("{}") } + +// ValidateGenesis performs genesis state validation for the capability module. +func (AppModuleBasic) ValidateGenesis(_ codec.JSONMarshaler, _ json.RawMessage) error { return nil } + +// RegisterRESTRoutes registers the capability module's REST service handlers. +func (a AppModuleBasic) RegisterRESTRoutes(_ context.CLIContext, _ *mux.Router) {} + +// GetTxCmd returns the capability module's root tx command. +func (a AppModuleBasic) GetTxCmd(_ *codec.Codec) *cobra.Command { return nil } + +// GetTxCmd returns the capability module's root query command. +func (AppModuleBasic) GetQueryCmd(_ *codec.Codec) *cobra.Command { return nil } + +// ---------------------------------------------------------------------------- +// AppModule +// ---------------------------------------------------------------------------- + +// AppModule implements the AppModule interface for the capability module. +type AppModule struct { + AppModuleBasic + + keeper Keeper +} + +func NewAppModule(keeper Keeper) AppModule { + return AppModule{ + AppModuleBasic: NewAppModuleBasic(), + keeper: keeper, + } +} + +// Name returns the capability module's name. +func (am AppModule) Name() string { + return am.AppModuleBasic.Name() +} + +// Route returns the capability module's message routing key. +func (AppModule) Route() string { return "" } + +// QuerierRoute returns the capability module's query routing key. +func (AppModule) QuerierRoute() string { return "" } + +// NewHandler returns the capability module's message Handler. +func (am AppModule) NewHandler() sdk.Handler { return nil } + +// NewQuerierHandler returns the capability module's Querier. +func (am AppModule) NewQuerierHandler() sdk.Querier { return nil } + +// RegisterInvariants registers the capability module's invariants. +func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} + +// InitGenesis performs the capability module's genesis initialization It returns +// no validator updates. +func (am AppModule) InitGenesis(_ sdk.Context, _ codec.JSONMarshaler, _ json.RawMessage) []abci.ValidatorUpdate { + return []abci.ValidatorUpdate{} +} + +// ExportGenesis returns the capability module's exported genesis state as raw JSON bytes. +func (am AppModule) ExportGenesis(_ sdk.Context, cdc codec.JSONMarshaler) json.RawMessage { + return am.DefaultGenesis(cdc) +} + +// BeginBlock executes all ABCI BeginBlock logic respective to the capability module. +func (am AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {} + +// EndBlock executes all ABCI EndBlock logic respective to the capability module. It +// returns no validator updates. +func (am AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { + return []abci.ValidatorUpdate{} +} diff --git a/x/capability/types/codec.go b/x/capability/types/codec.go new file mode 100644 index 000000000000..c12a54b6fb6a --- /dev/null +++ b/x/capability/types/codec.go @@ -0,0 +1,30 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" +) + +// RegisterCodec registers all the necessary types and interfaces for the +// capability module. +func RegisterCodec(cdc *codec.Codec) { + cdc.RegisterConcrete(&Capability{}, "cosmos-sdk/Capability", nil) + cdc.RegisterConcrete(Owner{}, "cosmos-sdk/Owner", nil) + cdc.RegisterConcrete(&CapabilityOwners{}, "cosmos-sdk/CapabilityOwners", nil) +} + +var ( + amino = codec.New() + + // ModuleCdc references the global x/capability module codec. Note, the codec should + // ONLY be used in certain instances of tests and for JSON encoding as Amino is + // still used for that purpose. + // + // The actual codec used for serialization should be provided to x/capability and + // defined at the application level. + ModuleCdc = codec.NewHybridCodec(amino) +) + +func init() { + RegisterCodec(amino) + amino.Seal() +} diff --git a/x/capability/types/errors.go b/x/capability/types/errors.go new file mode 100644 index 000000000000..bc3354789ca1 --- /dev/null +++ b/x/capability/types/errors.go @@ -0,0 +1,14 @@ +package types + +// DONTCOVER + +import ( + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +// x/capability module sentinel errors +var ( + ErrCapabilityTaken = sdkerrors.Register(ModuleName, 2, "capability name already taken") + ErrOwnerClaimed = sdkerrors.Register(ModuleName, 3, "given owner already claimed capability") + ErrCapabilityNotOwned = sdkerrors.Register(ModuleName, 4, "capability not owned by module") +) diff --git a/x/capability/types/keys.go b/x/capability/types/keys.go new file mode 100644 index 000000000000..5f171e28a7f4 --- /dev/null +++ b/x/capability/types/keys.go @@ -0,0 +1,51 @@ +package types + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +const ( + // ModuleName defines the module name + ModuleName = "capability" + + // StoreKey defines the primary module store key + StoreKey = ModuleName + + // MemStoreKey defines the in-memory store key + MemStoreKey = "mem_capability" +) + +var ( + // KeyIndex defines the key that stores the current globally unique capability + // index. + KeyIndex = []byte("index") + + // KeyPrefixIndexCapability defines a key prefix that stores index to capability + // name mappings. + KeyPrefixIndexCapability = []byte("capability_index") +) + +// RevCapabilityKey returns a reverse lookup key for a given module and capability +// name. +func RevCapabilityKey(module, name string) []byte { + return []byte(fmt.Sprintf("%s/rev/%s", module, name)) +} + +// FwdCapabilityKey returns a forward lookup key for a given module and capability +// reference. +func FwdCapabilityKey(module string, cap *Capability) []byte { + return []byte(fmt.Sprintf("%s/fwd/%p", module, cap)) +} + +// IndexToKey returns bytes to be used as a key for a given capability index. +func IndexToKey(index uint64) []byte { + return sdk.Uint64ToBigEndian(index) +} + +// IndexFromKey returns an index from a call to IndexToKey for a given capability +// index. +func IndexFromKey(key []byte) uint64 { + return sdk.BigEndianToUint64(key) +} diff --git a/x/capability/types/keys_test.go b/x/capability/types/keys_test.go new file mode 100644 index 000000000000..e767c3d34222 --- /dev/null +++ b/x/capability/types/keys_test.go @@ -0,0 +1,29 @@ +package types_test + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/x/capability/types" +) + +func TestRevCapabilityKey(t *testing.T) { + expected := []byte("bank/rev/send") + require.Equal(t, expected, types.RevCapabilityKey("bank", "send")) +} + +func TestFwdCapabilityKey(t *testing.T) { + cap := types.NewCapability(23) + expected := []byte(fmt.Sprintf("bank/fwd/%p", cap)) + require.Equal(t, expected, types.FwdCapabilityKey("bank", cap)) +} + +func TestIndexToKey(t *testing.T) { + require.Equal(t, []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0x5a}, types.IndexToKey(3162)) +} + +func TestIndexFromKey(t *testing.T) { + require.Equal(t, uint64(3162), types.IndexFromKey([]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0x5a})) +} diff --git a/x/capability/types/store.go b/x/capability/types/store.go new file mode 100644 index 000000000000..0354ca2b0ba4 --- /dev/null +++ b/x/capability/types/store.go @@ -0,0 +1,56 @@ +package types + +// CapabilityStore defines an ephemeral in-memory object capability store. +type CapabilityStore struct { + revMemStore map[string]*Capability + fwdMemStore map[string]string +} + +func NewCapabilityStore() CapabilityStore { + return CapabilityStore{ + revMemStore: make(map[string]*Capability), + fwdMemStore: make(map[string]string), + } +} + +// GetCapability returns a Capability by module and name tuple. If no Capability +// exists, nil will be returned. +func (cs CapabilityStore) GetCapability(module, name string) *Capability { + key := RevCapabilityKey(module, name) + return cs.revMemStore[string(key)] +} + +// GetCapabilityName returns a Capability name by module and Capability tuple. If +// no Capability name exists for the given tuple, an empty string is returned. +func (cs CapabilityStore) GetCapabilityName(module string, cap *Capability) string { + key := FwdCapabilityKey(module, cap) + return cs.fwdMemStore[string(key)] +} + +// SetCapability sets the reverse mapping between the module and capability name +// and the capability in the in-memory store. +func (cs CapabilityStore) SetCapability(module, name string, cap *Capability) { + key := RevCapabilityKey(module, name) + cs.revMemStore[string(key)] = cap +} + +// SetCapabilityName sets the forward mapping between the module and capability +// tuple and the capability name in the in-memory store. +func (cs CapabilityStore) SetCapabilityName(module, name string, cap *Capability) { + key := FwdCapabilityKey(module, cap) + cs.fwdMemStore[string(key)] = name +} + +// DeleteCapability removes the reverse mapping between the module and capability +// name and the capability in the in-memory store. +func (cs CapabilityStore) DeleteCapability(module, name string) { + key := RevCapabilityKey(module, name) + delete(cs.revMemStore, string(key)) +} + +// DeleteCapabilityName removes the forward mapping between the module and capability +// tuple and the capability name in the in-memory store. +func (cs CapabilityStore) DeleteCapabilityName(module string, cap *Capability) { + key := FwdCapabilityKey(module, cap) + delete(cs.fwdMemStore, string(key)) +} diff --git a/x/capability/types/types.go b/x/capability/types/types.go new file mode 100644 index 000000000000..e53efa5c4a1c --- /dev/null +++ b/x/capability/types/types.go @@ -0,0 +1,87 @@ +package types + +import ( + "fmt" + "sort" + + "gopkg.in/yaml.v2" + + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +// NewCapability returns a reference to a new Capability to be used as an +// actual capability. +func NewCapability(index uint64) *Capability { + return &Capability{Index: index} +} + +// String returns the string representation of a Capability. The string contains +// the Capability's memory reference as the string is to be used in a composite +// key and to authenticate capabilities. +func (ck *Capability) String() string { + return fmt.Sprintf("Capability{%p, %d}", ck, ck.Index) +} + +func NewOwner(module, name string) Owner { + return Owner{Module: module, Name: name} +} + +// Key returns a composite key for an Owner. +func (o Owner) Key() string { + return fmt.Sprintf("%s/%s", o.Module, o.Name) +} + +func (o Owner) String() string { + bz, _ := yaml.Marshal(o) + return string(bz) +} + +func NewCapabilityOwners() *CapabilityOwners { + return &CapabilityOwners{Owners: make([]Owner, 0)} +} + +// Set attempts to add a given owner to the CapabilityOwners. If the owner +// already exists, an error will be returned. Set runs in O(log n) average time +// and O(n) in the worst case. +func (co *CapabilityOwners) Set(owner Owner) error { + i, ok := co.Get(owner) + if ok { + // owner already exists at co.Owners[i] + return sdkerrors.Wrapf(ErrOwnerClaimed, owner.String()) + } + + // owner does not exist in the set of owners, so we insert at position i + co.Owners = append(co.Owners, Owner{}) // expand by 1 in amortized O(1) / O(n) worst case + copy(co.Owners[i+1:], co.Owners[i:]) + co.Owners[i] = owner + + return nil +} + +// Remove removes a provided owner from the CapabilityOwners if it exists. If the +// owner does not exist, Remove is considered a no-op. +func (co *CapabilityOwners) Remove(owner Owner) { + if len(co.Owners) == 0 { + return + } + + i, ok := co.Get(owner) + if ok { + // owner exists at co.Owners[i] + co.Owners = append(co.Owners[:i], co.Owners[i+1:]...) + } +} + +// Get returns (i, true) of the provided owner in the CapabilityOwners if the +// owner exists, where i indicates the owner's index in the set. Otherwise +// (i, false) where i indicates where in the set the owner should be added. +func (co *CapabilityOwners) Get(owner Owner) (int, bool) { + // find smallest index s.t. co.Owners[i] >= owner in O(log n) time + i := sort.Search(len(co.Owners), func(i int) bool { return co.Owners[i].Key() >= owner.Key() }) + if i < len(co.Owners) && co.Owners[i].Key() == owner.Key() { + // owner exists at co.Owners[i] + return i, true + } + + return i, false +} diff --git a/x/capability/types/types.pb.go b/x/capability/types/types.pb.go new file mode 100644 index 000000000000..30edfedddac9 --- /dev/null +++ b/x/capability/types/types.pb.go @@ -0,0 +1,710 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: x/capability/types/types.proto + +package types + +import ( + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// Capability defines an implementation of an object capability. The index provided to +// a Capability must be globally unique. +type Capability struct { + Index uint64 `protobuf:"varint,1,opt,name=index,proto3" json:"index,omitempty" yaml:"index"` +} + +func (m *Capability) Reset() { *m = Capability{} } +func (*Capability) ProtoMessage() {} +func (*Capability) Descriptor() ([]byte, []int) { + return fileDescriptor_d73d5c48b3550cdd, []int{0} +} +func (m *Capability) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Capability) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Capability.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 *Capability) XXX_Merge(src proto.Message) { + xxx_messageInfo_Capability.Merge(m, src) +} +func (m *Capability) XXX_Size() int { + return m.Size() +} +func (m *Capability) XXX_DiscardUnknown() { + xxx_messageInfo_Capability.DiscardUnknown(m) +} + +var xxx_messageInfo_Capability proto.InternalMessageInfo + +func (m *Capability) GetIndex() uint64 { + if m != nil { + return m.Index + } + return 0 +} + +// Owner defines a single capability owner. An owner is defined by the name of +// capability and the module name. +type Owner struct { + Module string `protobuf:"bytes,1,opt,name=module,proto3" json:"module,omitempty" yaml:"module"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty" yaml:"name"` +} + +func (m *Owner) Reset() { *m = Owner{} } +func (*Owner) ProtoMessage() {} +func (*Owner) Descriptor() ([]byte, []int) { + return fileDescriptor_d73d5c48b3550cdd, []int{1} +} +func (m *Owner) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Owner) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Owner.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 *Owner) XXX_Merge(src proto.Message) { + xxx_messageInfo_Owner.Merge(m, src) +} +func (m *Owner) XXX_Size() int { + return m.Size() +} +func (m *Owner) XXX_DiscardUnknown() { + xxx_messageInfo_Owner.DiscardUnknown(m) +} + +var xxx_messageInfo_Owner proto.InternalMessageInfo + +// CapabilityOwners defines a set of owners of a single Capability. The set of +// owners must be unique. +type CapabilityOwners struct { + Owners []Owner `protobuf:"bytes,1,rep,name=owners,proto3" json:"owners"` +} + +func (m *CapabilityOwners) Reset() { *m = CapabilityOwners{} } +func (m *CapabilityOwners) String() string { return proto.CompactTextString(m) } +func (*CapabilityOwners) ProtoMessage() {} +func (*CapabilityOwners) Descriptor() ([]byte, []int) { + return fileDescriptor_d73d5c48b3550cdd, []int{2} +} +func (m *CapabilityOwners) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CapabilityOwners) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CapabilityOwners.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 *CapabilityOwners) XXX_Merge(src proto.Message) { + xxx_messageInfo_CapabilityOwners.Merge(m, src) +} +func (m *CapabilityOwners) XXX_Size() int { + return m.Size() +} +func (m *CapabilityOwners) XXX_DiscardUnknown() { + xxx_messageInfo_CapabilityOwners.DiscardUnknown(m) +} + +var xxx_messageInfo_CapabilityOwners proto.InternalMessageInfo + +func (m *CapabilityOwners) GetOwners() []Owner { + if m != nil { + return m.Owners + } + return nil +} + +func init() { + proto.RegisterType((*Capability)(nil), "cosmos_sdk.x.capability.v1.Capability") + proto.RegisterType((*Owner)(nil), "cosmos_sdk.x.capability.v1.Owner") + proto.RegisterType((*CapabilityOwners)(nil), "cosmos_sdk.x.capability.v1.CapabilityOwners") +} + +func init() { proto.RegisterFile("x/capability/types/types.proto", fileDescriptor_d73d5c48b3550cdd) } + +var fileDescriptor_d73d5c48b3550cdd = []byte{ + // 308 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xab, 0xd0, 0x4f, 0x4e, + 0x2c, 0x48, 0x4c, 0xca, 0xcc, 0xc9, 0x2c, 0xa9, 0xd4, 0x2f, 0xa9, 0x2c, 0x48, 0x2d, 0x86, 0x90, + 0x7a, 0x05, 0x45, 0xf9, 0x25, 0xf9, 0x42, 0x52, 0xc9, 0xf9, 0xc5, 0xb9, 0xf9, 0xc5, 0xf1, 0xc5, + 0x29, 0xd9, 0x7a, 0x15, 0x7a, 0x08, 0xa5, 0x7a, 0x65, 0x86, 0x52, 0x6a, 0x25, 0x19, 0x99, 0x45, + 0x29, 0xf1, 0x05, 0x89, 0x45, 0x25, 0x95, 0xfa, 0x60, 0xe5, 0xfa, 0xe9, 0xf9, 0xe9, 0xf9, 0x08, + 0x16, 0xc4, 0x0c, 0x25, 0x2b, 0x2e, 0x2e, 0x67, 0xb8, 0x46, 0x21, 0x35, 0x2e, 0xd6, 0xcc, 0xbc, + 0x94, 0xd4, 0x0a, 0x09, 0x46, 0x05, 0x46, 0x0d, 0x16, 0x27, 0x81, 0x4f, 0xf7, 0xe4, 0x79, 0x2a, + 0x13, 0x73, 0x73, 0xac, 0x94, 0xc0, 0xc2, 0x4a, 0x41, 0x10, 0x69, 0x2b, 0x96, 0x19, 0x0b, 0xe4, + 0x19, 0x94, 0x12, 0xb9, 0x58, 0xfd, 0xcb, 0xf3, 0x52, 0x8b, 0x84, 0x34, 0xb9, 0xd8, 0x72, 0xf3, + 0x53, 0x4a, 0x73, 0x52, 0xc1, 0xfa, 0x38, 0x9d, 0x04, 0x3f, 0xdd, 0x93, 0xe7, 0x85, 0xe8, 0x83, + 0x88, 0x2b, 0x05, 0x41, 0x15, 0x08, 0x29, 0x73, 0xb1, 0xe4, 0x25, 0xe6, 0xa6, 0x4a, 0x30, 0x81, + 0x15, 0xf2, 0x7f, 0xba, 0x27, 0xcf, 0x0d, 0x51, 0x08, 0x12, 0x55, 0x0a, 0x02, 0x4b, 0x5a, 0x71, + 0x74, 0x2c, 0x90, 0x67, 0x00, 0x5b, 0x11, 0xcc, 0x25, 0x80, 0x70, 0x1e, 0xd8, 0xb2, 0x62, 0x21, + 0x7b, 0x2e, 0xb6, 0x7c, 0x30, 0x4b, 0x82, 0x51, 0x81, 0x59, 0x83, 0xdb, 0x48, 0x51, 0x0f, 0x77, + 0x38, 0xe8, 0x81, 0xf5, 0x38, 0xb1, 0x9c, 0xb8, 0x27, 0xcf, 0x10, 0x04, 0xd5, 0xe6, 0xe4, 0x79, + 0xe2, 0x91, 0x1c, 0xe3, 0x85, 0x47, 0x72, 0x8c, 0x0f, 0x1e, 0xc9, 0x31, 0x4e, 0x78, 0x2c, 0xc7, + 0x70, 0xe1, 0xb1, 0x1c, 0xc3, 0x8d, 0xc7, 0x72, 0x0c, 0x51, 0xfa, 0xe9, 0x99, 0x25, 0x19, 0xa5, + 0x49, 0x7a, 0xc9, 0xf9, 0xb9, 0xfa, 0x10, 0x43, 0xa1, 0x94, 0x6e, 0x71, 0x4a, 0xb6, 0x3e, 0x66, + 0x74, 0x24, 0xb1, 0x81, 0x43, 0xd1, 0x18, 0x10, 0x00, 0x00, 0xff, 0xff, 0x0b, 0x14, 0xb2, 0xaf, + 0xab, 0x01, 0x00, 0x00, +} + +func (m *Capability) 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 *Capability) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Capability) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Index != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.Index)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *Owner) 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 *Owner) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Owner) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0x12 + } + if len(m.Module) > 0 { + i -= len(m.Module) + copy(dAtA[i:], m.Module) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Module))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *CapabilityOwners) 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 *CapabilityOwners) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CapabilityOwners) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Owners) > 0 { + for iNdEx := len(m.Owners) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Owners[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarintTypes(dAtA []byte, offset int, v uint64) int { + offset -= sovTypes(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Capability) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Index != 0 { + n += 1 + sovTypes(uint64(m.Index)) + } + return n +} + +func (m *Owner) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Module) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.Name) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + +func (m *CapabilityOwners) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Owners) > 0 { + for _, e := range m.Owners { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + return n +} + +func sovTypes(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTypes(x uint64) (n int) { + return sovTypes(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Capability) 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 ErrIntOverflowTypes + } + 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: Capability: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Capability: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Index", wireType) + } + m.Index = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Index |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Owner) 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 ErrIntOverflowTypes + } + 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: Owner: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Owner: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Module", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Module = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *CapabilityOwners) 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 ErrIntOverflowTypes + } + 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: CapabilityOwners: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CapabilityOwners: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Owners", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Owners = append(m.Owners, Owner{}) + if err := m.Owners[len(m.Owners)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTypes(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthTypes + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTypes + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTypes + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTypes = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTypes = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTypes = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/capability/types/types.proto b/x/capability/types/types.proto new file mode 100644 index 000000000000..1468d4f5ba5e --- /dev/null +++ b/x/capability/types/types.proto @@ -0,0 +1,33 @@ +syntax = "proto3"; + +package cosmos_sdk.x.capability.v1; + +option go_package = "github.com/cosmos/cosmos-sdk/x/capability/types"; + +import "third_party/proto/gogoproto/gogo.proto"; + +// Capability defines an implementation of an object capability. The index provided to +// a Capability must be globally unique. +message Capability { + option (gogoproto.goproto_stringer) = false; + + uint64 index = 1 [(gogoproto.moretags) = "yaml:\"index\""]; +} + +// Owner defines a single capability owner. An owner is defined by the name of +// capability and the module name. +message Owner { + option (gogoproto.goproto_stringer) = false; + option (gogoproto.goproto_getters) = false; + + string module = 1 [(gogoproto.moretags) = "yaml:\"module\""]; + string name = 2 [(gogoproto.moretags) = "yaml:\"name\""]; +} + +// CapabilityOwners defines a set of owners of a single Capability. The set of +// owners must be unique. +message CapabilityOwners { + repeated Owner owners = 1 [ + (gogoproto.nullable) = false + ]; +} diff --git a/x/capability/types/types_test.go b/x/capability/types/types_test.go new file mode 100644 index 000000000000..8cec569d2faf --- /dev/null +++ b/x/capability/types/types_test.go @@ -0,0 +1,69 @@ +package types_test + +import ( + "fmt" + "sort" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/x/capability/types" +) + +func TestCapabilityKey(t *testing.T) { + idx := uint64(3162) + cap := types.NewCapability(idx) + require.Equal(t, idx, cap.GetIndex()) + require.Equal(t, fmt.Sprintf("Capability{%p, %d}", cap, idx), cap.String()) +} + +func TestOwner(t *testing.T) { + o := types.NewOwner("bank", "send") + require.Equal(t, "bank/send", o.Key()) + require.Equal(t, "module: bank\nname: send\n", o.String()) +} + +func TestCapabilityOwners_Set(t *testing.T) { + co := types.NewCapabilityOwners() + + owners := make([]types.Owner, 1024) + for i := range owners { + var owner types.Owner + + if i%2 == 0 { + owner = types.NewOwner("bank", fmt.Sprintf("send-%d", i)) + } else { + owner = types.NewOwner("slashing", fmt.Sprintf("slash-%d", i)) + } + + owners[i] = owner + require.NoError(t, co.Set(owner)) + } + + sort.Slice(owners, func(i, j int) bool { return owners[i].Key() < owners[j].Key() }) + require.Equal(t, owners, co.Owners) + + for _, owner := range owners { + require.Error(t, co.Set(owner)) + } +} + +func TestCapabilityOwners_Remove(t *testing.T) { + co := types.NewCapabilityOwners() + + co.Remove(types.NewOwner("bank", "send-0")) + require.Len(t, co.Owners, 0) + + for i := 0; i < 5; i++ { + require.NoError(t, co.Set(types.NewOwner("bank", fmt.Sprintf("send-%d", i)))) + } + + require.Len(t, co.Owners, 5) + + for i := 0; i < 5; i++ { + co.Remove(types.NewOwner("bank", fmt.Sprintf("send-%d", i))) + require.Len(t, co.Owners, 5-(i+1)) + } + + require.Len(t, co.Owners, 0) +} diff --git a/x/crisis/keeper/keeper.go b/x/crisis/keeper/keeper.go index 1a29064dde95..86136981ddfa 100644 --- a/x/crisis/keeper/keeper.go +++ b/x/crisis/keeper/keeper.go @@ -28,9 +28,14 @@ func NewKeeper( feeCollectorName string, ) Keeper { + // set KeyTable if it has not already been set + if !paramSpace.HasKeyTable() { + paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable()) + } + return Keeper{ routes: make([]types.InvarRoute, 0), - paramSpace: paramSpace.WithKeyTable(types.ParamKeyTable()), + paramSpace: paramSpace, invCheckPeriod: invCheckPeriod, supplyKeeper: supplyKeeper, feeCollectorName: feeCollectorName, diff --git a/x/evidence/exported/evidence.go b/x/evidence/exported/evidence.go index b8b6d9ef39eb..121529a7c9df 100644 --- a/x/evidence/exported/evidence.go +++ b/x/evidence/exported/evidence.go @@ -15,11 +15,17 @@ type Evidence interface { Hash() tmbytes.HexBytes ValidateBasic() error - // The consensus address of the malicious validator at time of infraction - GetConsensusAddress() sdk.ConsAddress - // Height at which the infraction occurred GetHeight() int64 +} + +// ValidatorEvidence extends Evidence interface to define contract +// for evidence against malicious validators +type ValidatorEvidence interface { + Evidence + + // The consensus address of the malicious validator at time of infraction + GetConsensusAddress() sdk.ConsAddress // The total power of the malicious validator at time of infraction GetValidatorPower() int64 diff --git a/x/ibc/02-client/alias.go b/x/ibc/02-client/alias.go new file mode 100644 index 000000000000..762cb695ab26 --- /dev/null +++ b/x/ibc/02-client/alias.go @@ -0,0 +1,51 @@ +package client + +// nolint +// autogenerated code using github.com/rigelrozanski/multitool +// aliases generated for the following subdirectories: +// ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/02-client/keeper +// ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/02-client/types + +import ( + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/keeper" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" +) + +const ( + AttributeKeyClientID = types.AttributeKeyClientID + AttrbuteKeyClientType = types.AttributeKeyClientType + SubModuleName = types.SubModuleName + RouterKey = types.RouterKey + QuerierRoute = types.QuerierRoute + QueryAllClients = types.QueryAllClients + QueryClientState = types.QueryClientState + QueryConsensusState = types.QueryConsensusState +) + +var ( + // functions aliases + NewKeeper = keeper.NewKeeper + QuerierClients = keeper.QuerierClients + RegisterCodec = types.RegisterCodec + ErrClientExists = types.ErrClientExists + ErrClientNotFound = types.ErrClientNotFound + ErrClientFrozen = types.ErrClientFrozen + ErrConsensusStateNotFound = types.ErrConsensusStateNotFound + ErrInvalidConsensus = types.ErrInvalidConsensus + ErrClientTypeNotFound = types.ErrClientTypeNotFound + ErrInvalidClientType = types.ErrInvalidClientType + ErrRootNotFound = types.ErrRootNotFound + ErrInvalidHeader = types.ErrInvalidHeader + ErrInvalidEvidence = types.ErrInvalidEvidence + + // variable aliases + SubModuleCdc = types.SubModuleCdc + EventTypeCreateClient = types.EventTypeCreateClient + EventTypeUpdateClient = types.EventTypeUpdateClient + AttributeValueCategory = types.AttributeValueCategory +) + +type ( + Keeper = keeper.Keeper + StakingKeeper = types.StakingKeeper +) diff --git a/x/ibc/02-client/client/cli/cli.go b/x/ibc/02-client/client/cli/cli.go new file mode 100644 index 000000000000..bd9d8d361be2 --- /dev/null +++ b/x/ibc/02-client/client/cli/cli.go @@ -0,0 +1,28 @@ +package cli + +import ( + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/codec" +) + +// GetQueryCmd returns the query commands for IBC clients +func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { + ics02ClientQueryCmd := &cobra.Command{ + Use: "client", + Short: "IBC client query subcommands", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + } + + ics02ClientQueryCmd.AddCommand(flags.GetCommands( + GetCmdQueryClientStates(queryRoute, cdc), + GetCmdQueryClientState(queryRoute, cdc), + GetCmdQueryConsensusState(queryRoute, cdc), + GetCmdQueryHeader(cdc), + GetCmdNodeConsensusState(queryRoute, cdc), + GetCmdQueryPath(queryRoute, cdc), + )...) + return ics02ClientQueryCmd +} diff --git a/x/ibc/02-client/client/cli/query.go b/x/ibc/02-client/client/cli/query.go new file mode 100644 index 000000000000..e77f82f4a0c3 --- /dev/null +++ b/x/ibc/02-client/client/cli/query.go @@ -0,0 +1,180 @@ +package cli + +import ( + "errors" + "fmt" + "strconv" + "strings" + + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/version" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/client/utils" + commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" +) + +// GetCmdQueryClientStates defines the command to query all the light clients +// that this chain mantains. +func GetCmdQueryClientStates(queryRoute string, cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "states", + Short: "Query all available light clients", + Long: strings.TrimSpace( + fmt.Sprintf(`Query all available light clients + +Example: +$ %s query ibc client states + `, version.ClientName), + ), + Example: fmt.Sprintf("%s query ibc client states", version.ClientName), + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + page := viper.GetInt(flags.FlagPage) + limit := viper.GetInt(flags.FlagLimit) + + clientStates, _, err := utils.QueryAllClientStates(cliCtx, page, limit) + if err != nil { + return err + } + + return cliCtx.PrintOutput(clientStates) + }, + } + cmd.Flags().Int(flags.FlagPage, 1, "pagination page of light clients to to query for") + cmd.Flags().Int(flags.FlagLimit, 100, "pagination limit of light clients to query for") + return cmd +} + +// GetCmdQueryClientState defines the command to query the state of a client with +// a given id as defined in https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#query +func GetCmdQueryClientState(queryRoute string, cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "state [client-id]", + Short: "Query a client state", + Long: strings.TrimSpace( + fmt.Sprintf(`Query stored client state + +Example: +$ %s query ibc client state [client-id] + `, version.ClientName), + ), + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + clientID := args[0] + if strings.TrimSpace(clientID) == "" { + return errors.New("client ID can't be blank") + } + + prove := viper.GetBool(flags.FlagProve) + + clientStateRes, err := utils.QueryClientState(cliCtx, clientID, prove) + if err != nil { + return err + } + + return cliCtx.PrintOutput(clientStateRes) + }, + } + cmd.Flags().Bool(flags.FlagProve, true, "show proofs for the query results") + return cmd +} + +// GetCmdQueryConsensusState defines the command to query the consensus state of +// the chain as defined in https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#query +func GetCmdQueryConsensusState(queryRoute string, cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "consensus-state [client-id] [height]", + Short: "Query the consensus state of a client at a given height", + Long: "Query the consensus state for a particular light client at a given height", + Example: fmt.Sprintf("%s query ibc client consensus-state [client-id] [height]", version.ClientName), + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + clientID := args[0] + if strings.TrimSpace(clientID) == "" { + return errors.New("client ID can't be blank") + } + + height, err := strconv.ParseUint(args[1], 10, 64) + if err != nil { + return fmt.Errorf("expected integer height, got: %s", args[1]) + } + + prove := viper.GetBool(flags.FlagProve) + + csRes, err := utils.QueryConsensusState(cliCtx, clientID, height, prove) + if err != nil { + return err + } + + return cliCtx.PrintOutput(csRes) + }, + } + cmd.Flags().Bool(flags.FlagProve, true, "show proofs for the query results") + return cmd +} + +// GetCmdQueryHeader defines the command to query the latest header on the chain +func GetCmdQueryHeader(cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "header", + Short: "Query the latest header of the running chain", + Long: "Query the latest Tendermint header of the running chain", + Example: fmt.Sprintf("%s query ibc client header", version.ClientName), + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + + header, _, err := utils.QueryTendermintHeader(cliCtx) + if err != nil { + return err + } + + return cliCtx.PrintOutput(header) + }, + } +} + +// GetCmdNodeConsensusState defines the command to query the latest consensus state of a node +// The result is feed to client creation +func GetCmdNodeConsensusState(queryRoute string, cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "node-state", + Short: "Query a node consensus state", + Long: strings.TrimSpace( + fmt.Sprintf(`Query a node consensus state. This result is feed to the client creation transaction. + +Example: +$ %s query ibc client node-state + `, version.ClientName), + ), + Args: cobra.ExactArgs(0), + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + + state, _, err := utils.QueryNodeConsensusState(cliCtx) + if err != nil { + return err + } + + return cliCtx.PrintOutput(state) + }, + } +} + +// GetCmdQueryPath defines the command to query the commitment path. +func GetCmdQueryPath(storeName string, cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "path", + Short: "Query the commitment path of the running chain", + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.NewCLIContext().WithCodec(cdc) + path := commitmenttypes.NewMerklePrefix([]byte("ibc")) + return ctx.PrintOutput(path) + }, + } +} diff --git a/x/ibc/02-client/client/rest/query.go b/x/ibc/02-client/client/rest/query.go new file mode 100644 index 000000000000..f3d00b8bf8ac --- /dev/null +++ b/x/ibc/02-client/client/rest/query.go @@ -0,0 +1,172 @@ +package rest + +import ( + "fmt" + "net/http" + "strconv" + + "github.com/gorilla/mux" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/types/rest" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/client/utils" +) + +func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router) { + r.HandleFunc("/ibc/clients", queryAllClientStatesFn(cliCtx)).Methods("GET") + r.HandleFunc(fmt.Sprintf("/ibc/clients/{%s}/client-state", RestClientID), queryClientStateHandlerFn(cliCtx)).Methods("GET") + r.HandleFunc(fmt.Sprintf("/ibc/clients/{%s}/consensus-state", RestClientID), queryConsensusStateHandlerFn(cliCtx)).Methods("GET") + r.HandleFunc("/ibc/header", queryHeaderHandlerFn(cliCtx)).Methods("GET") + r.HandleFunc("/ibc/node-state", queryNodeConsensusStateHandlerFn(cliCtx)).Methods("GET") +} + +// queryAllClientStatesFn queries all available light clients +// +// @Summary Query client states +// @Tags IBC +// @Produce json +// @Param page query int false "The page number to query" default(1) +// @Param limit query int false "The number of results per page" default(100) +// @Success 200 {object} QueryClientState "OK" +// @Failure 500 {object} rest.ErrorResponse "Internal Server Error" +// @Router /ibc/clients [get] +func queryAllClientStatesFn(cliCtx context.CLIContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + _, page, limit, err := rest.ParseHTTPArgsWithLimit(r, 0) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) + if !ok { + return + } + + clients, height, err := utils.QueryAllClientStates(cliCtx, page, limit) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + + cliCtx = cliCtx.WithHeight(height) + rest.PostProcessResponse(w, cliCtx, clients) + } +} + +// queryClientStateHandlerFn implements a client state querying route +// +// @Summary Query client state +// @Tags IBC +// @Produce json +// @Param client-id path string true "Client ID" +// @Param prove query boolean false "Proof of result" +// @Success 200 {object} QueryClientState "OK" +// @Failure 400 {object} rest.ErrorResponse "Invalid client id" +// @Failure 500 {object} rest.ErrorResponse "Internal Server Error" +// @Router /ibc/clients/{client-id}/client-state [get] +func queryClientStateHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + clientID := vars[RestClientID] + prove := rest.ParseQueryParamBool(r, flags.FlagProve) + + cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) + if !ok { + return + } + + clientStateRes, err := utils.QueryClientState(cliCtx, clientID, prove) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + + cliCtx = cliCtx.WithHeight(int64(clientStateRes.ProofHeight)) + rest.PostProcessResponse(w, cliCtx, clientStateRes) + } +} + +// queryConsensusStateHandlerFn implements a consensus state querying route +// +// @Summary Query cliet consensus-state +// @Tags IBC +// @Produce json +// @Param client-id path string true "Client ID" +// @Param height path number true "Height" +// @Param prove query boolean false "Proof of result" +// @Success 200 {object} QueryConsensusState "OK" +// @Failure 400 {object} rest.ErrorResponse "Invalid client id" +// @Failure 500 {object} rest.ErrorResponse "Internal Server Error" +// @Router /ibc/clients/{client-id}/consensus-state [get] +func queryConsensusStateHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + clientID := vars[RestClientID] + height, err := strconv.ParseUint(vars[RestRootHeight], 10, 64) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + prove := rest.ParseQueryParamBool(r, flags.FlagProve) + + cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) + if !ok { + return + } + + csRes, err := utils.QueryConsensusState(cliCtx, clientID, height, prove) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + + cliCtx = cliCtx.WithHeight(int64(csRes.ProofHeight)) + rest.PostProcessResponse(w, cliCtx, csRes) + } +} + +// queryHeaderHandlerFn implements a header querying route +// +// @Summary Query header +// @Tags IBC +// @Produce json +// @Success 200 {object} QueryHeader "OK" +// @Failure 500 {object} rest.ErrorResponse "Internal Server Error" +// @Router /ibc/header [get] +func queryHeaderHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + header, height, err := utils.QueryTendermintHeader(cliCtx) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + + res := cliCtx.Codec.MustMarshalJSON(header) + cliCtx = cliCtx.WithHeight(height) + rest.PostProcessResponse(w, cliCtx, res) + } +} + +// queryNodeConsensusStateHandlerFn implements a node consensus state querying route +// +// @Summary Query node consensus-state +// @Tags IBC +// @Produce json +// @Success 200 {object} QueryNodeConsensusState "OK" +// @Failure 500 {object} rest.ErrorResponse "Internal Server Error" +// @Router /ibc/node-state [get] +func queryNodeConsensusStateHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + state, height, err := utils.QueryNodeConsensusState(cliCtx) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + } + + res := cliCtx.Codec.MustMarshalJSON(state) + cliCtx = cliCtx.WithHeight(height) + rest.PostProcessResponse(w, cliCtx, res) + } +} diff --git a/x/ibc/02-client/client/rest/rest.go b/x/ibc/02-client/client/rest/rest.go new file mode 100644 index 000000000000..a6b8b215b2c3 --- /dev/null +++ b/x/ibc/02-client/client/rest/rest.go @@ -0,0 +1,18 @@ +package rest + +import ( + "github.com/gorilla/mux" + + "github.com/cosmos/cosmos-sdk/client/context" +) + +// REST client flags +const ( + RestClientID = "client-id" + RestRootHeight = "height" +) + +// RegisterRoutes - Central function to define routes that get registered by the main application +func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, queryRoute string) { + registerQueryRoutes(cliCtx, r) +} diff --git a/x/ibc/02-client/client/utils/utils.go b/x/ibc/02-client/client/utils/utils.go new file mode 100644 index 000000000000..c267978ddd83 --- /dev/null +++ b/x/ibc/02-client/client/utils/utils.go @@ -0,0 +1,157 @@ +package utils + +import ( + "fmt" + + abci "github.com/tendermint/tendermint/abci/types" + tmtypes "github.com/tendermint/tendermint/types" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + "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" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +// QueryAllClientStates returns all the light client states. It _does not_ return +// any merkle proof. +func QueryAllClientStates(cliCtx context.CLIContext, page, limit int) ([]exported.ClientState, int64, error) { + params := types.NewQueryAllClientsParams(page, limit) + bz, err := cliCtx.Codec.MarshalJSON(params) + if err != nil { + return nil, 0, fmt.Errorf("failed to marshal query params: %w", err) + } + + route := fmt.Sprintf("custom/%s/%s/%s", "ibc", types.QuerierRoute, types.QueryAllClients) + res, height, err := cliCtx.QueryWithData(route, bz) + if err != nil { + return nil, 0, err + } + + var clients []exported.ClientState + err = cliCtx.Codec.UnmarshalJSON(res, &clients) + if err != nil { + return nil, 0, fmt.Errorf("failed to unmarshal light clients: %w", err) + } + return clients, height, nil +} + +// QueryClientState queries the store to get the light client state and a merkle +// proof. +func QueryClientState( + cliCtx context.CLIContext, clientID string, prove bool, +) (types.StateResponse, error) { + req := abci.RequestQuery{ + Path: "store/ibc/key", + Data: ibctypes.KeyClientState(clientID), + Prove: prove, + } + + res, err := cliCtx.QueryABCI(req) + if err != nil { + return types.StateResponse{}, err + } + + var clientState exported.ClientState + if err := cliCtx.Codec.UnmarshalBinaryLengthPrefixed(res.Value, &clientState); err != nil { + return types.StateResponse{}, err + } + + clientStateRes := types.NewClientStateResponse(clientID, clientState, res.Proof, res.Height) + + return clientStateRes, nil +} + +// QueryConsensusState queries the store to get the consensus state and a merkle +// proof. +func QueryConsensusState( + cliCtx context.CLIContext, clientID string, height uint64, prove bool, +) (types.ConsensusStateResponse, error) { + var conStateRes types.ConsensusStateResponse + + req := abci.RequestQuery{ + Path: "store/ibc/key", + Data: ibctypes.KeyConsensusState(clientID, height), + Prove: prove, + } + + res, err := cliCtx.QueryABCI(req) + if err != nil { + return conStateRes, err + } + + var cs exported.ConsensusState + if err := cliCtx.Codec.UnmarshalBinaryLengthPrefixed(res.Value, &cs); err != nil { + return conStateRes, err + } + + return types.NewConsensusStateResponse(clientID, cs, res.Proof, res.Height), nil +} + +// QueryTendermintHeader takes a client context and returns the appropriate +// tendermint header +func QueryTendermintHeader(cliCtx context.CLIContext) (ibctmtypes.Header, int64, error) { + node, err := cliCtx.GetNode() + if err != nil { + return ibctmtypes.Header{}, 0, err + } + + info, err := node.ABCIInfo() + if err != nil { + return ibctmtypes.Header{}, 0, err + } + + height := info.Response.LastBlockHeight + + commit, err := node.Commit(&height) + if err != nil { + return ibctmtypes.Header{}, 0, err + } + + validators, err := node.Validators(&height, 0, 10000) + if err != nil { + return ibctmtypes.Header{}, 0, err + } + + header := ibctmtypes.Header{ + SignedHeader: commit.SignedHeader, + ValidatorSet: tmtypes.NewValidatorSet(validators.Validators), + } + + return header, height, nil +} + +// QueryNodeConsensusState takes a client context and returns the appropriate +// tendermint consensus state +func QueryNodeConsensusState(cliCtx context.CLIContext) (ibctmtypes.ConsensusState, int64, error) { + node, err := cliCtx.GetNode() + if err != nil { + return ibctmtypes.ConsensusState{}, 0, err + } + + info, err := node.ABCIInfo() + if err != nil { + return ibctmtypes.ConsensusState{}, 0, err + } + + height := info.Response.LastBlockHeight + + commit, err := node.Commit(&height) + if err != nil { + return ibctmtypes.ConsensusState{}, 0, err + } + + validators, err := node.Validators(&height, 0, 10000) + if err != nil { + return ibctmtypes.ConsensusState{}, 0, err + } + + state := ibctmtypes.ConsensusState{ + Timestamp: commit.Time, + Root: commitmenttypes.NewMerkleRoot(commit.AppHash), + ValidatorSet: tmtypes.NewValidatorSet(validators.Validators), + } + + return state, height, nil +} diff --git a/x/ibc/02-client/doc.go b/x/ibc/02-client/doc.go new file mode 100644 index 000000000000..cfe3c76c6af7 --- /dev/null +++ b/x/ibc/02-client/doc.go @@ -0,0 +1,10 @@ +/* +Package client implements the ICS 02 - Client Semantics specification +https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics. This +concrete implementations defines types and method to store and update light +clients which tracks on other chain's state. + +The main type is `Client`, which provides `commitment.Root` to verify state proofs and `ConsensusState` to +verify header proofs. +*/ +package client diff --git a/x/ibc/02-client/exported/exported.go b/x/ibc/02-client/exported/exported.go new file mode 100644 index 000000000000..83ca5be502c0 --- /dev/null +++ b/x/ibc/02-client/exported/exported.go @@ -0,0 +1,193 @@ +package exported + +import ( + "encoding/json" + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/cosmos-sdk/codec" + evidenceexported "github.com/cosmos/cosmos-sdk/x/evidence/exported" + connectionexported "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported" + channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" +) + +// ClientState defines the required common functions for light clients. +type ClientState interface { + GetID() string + GetChainID() string + ClientType() ClientType + GetLatestHeight() uint64 + IsFrozen() bool + + // State verification functions + + VerifyClientConsensusState( + cdc *codec.Codec, + root commitmentexported.Root, + height uint64, + counterpartyClientIdentifier string, + consensusHeight uint64, + prefix commitmentexported.Prefix, + proof commitmentexported.Proof, + consensusState ConsensusState, + ) error + VerifyConnectionState( + cdc *codec.Codec, + height uint64, + prefix commitmentexported.Prefix, + proof commitmentexported.Proof, + connectionID string, + connectionEnd connectionexported.ConnectionI, + consensusState ConsensusState, + ) error + VerifyChannelState( + cdc *codec.Codec, + height uint64, + prefix commitmentexported.Prefix, + proof commitmentexported.Proof, + portID, + channelID string, + channel channelexported.ChannelI, + consensusState ConsensusState, + ) error + VerifyPacketCommitment( + height uint64, + prefix commitmentexported.Prefix, + proof commitmentexported.Proof, + portID, + channelID string, + sequence uint64, + commitmentBytes []byte, + consensusState ConsensusState, + ) error + VerifyPacketAcknowledgement( + height uint64, + prefix commitmentexported.Prefix, + proof commitmentexported.Proof, + portID, + channelID string, + sequence uint64, + acknowledgement []byte, + consensusState ConsensusState, + ) error + VerifyPacketAcknowledgementAbsence( + height uint64, + prefix commitmentexported.Prefix, + proof commitmentexported.Proof, + portID, + channelID string, + sequence uint64, + consensusState ConsensusState, + ) error + VerifyNextSequenceRecv( + height uint64, + prefix commitmentexported.Prefix, + proof commitmentexported.Proof, + portID, + channelID string, + nextSequenceRecv uint64, + consensusState ConsensusState, + ) error +} + +// ConsensusState is the state of the consensus process +type ConsensusState interface { + ClientType() ClientType // Consensus kind + + // GetHeight returns the height of the consensus state + GetHeight() uint64 + + // GetRoot returns the commitment root of the consensus state, + // which is used for key-value pair verification. + GetRoot() commitmentexported.Root + + ValidateBasic() error +} + +// Misbehaviour defines a specific consensus kind and an evidence +type Misbehaviour interface { + evidenceexported.Evidence + ClientType() ClientType + GetClientID() string +} + +// Header is the consensus state update information +type Header interface { + ClientType() ClientType + GetHeight() uint64 +} + +// MsgCreateClient defines the msg interface that the +// CreateClient Handler expects +type MsgCreateClient interface { + sdk.Msg + GetClientID() string + GetClientType() string + GetConsensusState() ConsensusState +} + +// MsgUpdateClient defines the msg interface that the +// UpdateClient Handler expects +type MsgUpdateClient interface { + sdk.Msg + GetClientID() string + GetHeader() Header +} + +// ClientType defines the type of the consensus algorithm +type ClientType byte + +// available client types +const ( + Tendermint ClientType = iota + 1 // 1 +) + +// string representation of the client types +const ( + ClientTypeTendermint string = "tendermint" +) + +func (ct ClientType) String() string { + switch ct { + case Tendermint: + return ClientTypeTendermint + default: + return "" + } +} + +// MarshalJSON marshal to JSON using string. +func (ct ClientType) MarshalJSON() ([]byte, error) { + return json.Marshal(ct.String()) +} + +// UnmarshalJSON decodes from JSON. +func (ct *ClientType) UnmarshalJSON(data []byte) error { + var s string + err := json.Unmarshal(data, &s) + if err != nil { + return err + } + + clientType := ClientTypeFromString(s) + if clientType == 0 { + return fmt.Errorf("invalid client type '%s'", s) + } + + *ct = clientType + return nil +} + +// ClientTypeFromString returns a byte that corresponds to the registered client +// type. It returns 0 if the type is not found/registered. +func ClientTypeFromString(clientType string) ClientType { + switch clientType { + case ClientTypeTendermint: + return Tendermint + + default: + return 0 + } +} diff --git a/x/ibc/02-client/exported/exported_test.go b/x/ibc/02-client/exported/exported_test.go new file mode 100644 index 000000000000..f0eb1fc4d182 --- /dev/null +++ b/x/ibc/02-client/exported/exported_test.go @@ -0,0 +1,49 @@ +package exported + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestClientTypeString(t *testing.T) { + cases := []struct { + msg string + name string + clientType ClientType + }{ + {"tendermint client", ClientTypeTendermint, Tendermint}, + {"empty type", "", 0}, + } + + for _, tt := range cases { + tt := tt + require.Equal(t, tt.clientType, ClientTypeFromString(tt.name), tt.msg) + require.Equal(t, tt.name, tt.clientType.String(), tt.msg) + } +} + +func TestClientTypeMarshalJSON(t *testing.T) { + cases := []struct { + msg string + name string + clientType ClientType + expectPass bool + }{ + {"tendermint client should have passed", ClientTypeTendermint, Tendermint, true}, + {"empty type should have failed", "", 0, false}, + } + + for _, tt := range cases { + tt := tt + bz, err := tt.clientType.MarshalJSON() + require.NoError(t, err) + var ct ClientType + if tt.expectPass { + require.NoError(t, ct.UnmarshalJSON(bz), tt.msg) + require.Equal(t, tt.name, ct.String(), tt.msg) + } else { + require.Error(t, ct.UnmarshalJSON(bz), tt.msg) + } + } +} diff --git a/x/ibc/02-client/handler.go b/x/ibc/02-client/handler.go new file mode 100644 index 000000000000..df6f41e3a72d --- /dev/null +++ b/x/ibc/02-client/handler.go @@ -0,0 +1,104 @@ +package client + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/evidence" + evidenceexported "github.com/cosmos/cosmos-sdk/x/evidence/exported" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" +) + +// HandleMsgCreateClient defines the sdk.Handler for MsgCreateClient +func HandleMsgCreateClient(ctx sdk.Context, k Keeper, msg exported.MsgCreateClient) (*sdk.Result, error) { + clientType := exported.ClientTypeFromString(msg.GetClientType()) + var clientState exported.ClientState + switch clientType { + case 0: + return nil, sdkerrors.Wrap(ErrInvalidClientType, msg.GetClientType()) + case exported.Tendermint: + tmMsg, ok := msg.(ibctmtypes.MsgCreateClient) + if !ok { + return nil, sdkerrors.Wrap(ErrInvalidClientType, "Msg is not a Tendermint CreateClient msg") + } + var err error + clientState, err = ibctmtypes.InitializeFromMsg(tmMsg) + if err != nil { + return nil, err + } + default: + return nil, sdkerrors.Wrap(ErrInvalidClientType, msg.GetClientType()) + } + + _, err := k.CreateClient( + ctx, clientState, msg.GetConsensusState(), + ) + if err != nil { + return nil, err + } + + attributes := make([]sdk.Attribute, len(msg.GetSigners())+1) + attributes[0] = sdk.NewAttribute(sdk.AttributeKeyModule, AttributeValueCategory) + for i, signer := range msg.GetSigners() { + attributes[i+1] = sdk.NewAttribute(sdk.AttributeKeySender, signer.String()) + } + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + EventTypeCreateClient, + sdk.NewAttribute(AttributeKeyClientID, msg.GetClientID()), + sdk.NewAttribute(AttrbuteKeyClientType, msg.GetClientType()), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + attributes..., + ), + }) + + return &sdk.Result{ + Events: ctx.EventManager().Events().ToABCIEvents(), + }, nil +} + +// HandleMsgUpdateClient defines the sdk.Handler for MsgUpdateClient +func HandleMsgUpdateClient(ctx sdk.Context, k Keeper, msg exported.MsgUpdateClient) (*sdk.Result, error) { + if err := k.UpdateClient(ctx, msg.GetClientID(), msg.GetHeader()); err != nil { + return nil, err + } + + attributes := make([]sdk.Attribute, len(msg.GetSigners())+1) + attributes[0] = sdk.NewAttribute(sdk.AttributeKeyModule, AttributeValueCategory) + for i, signer := range msg.GetSigners() { + attributes[i+1] = sdk.NewAttribute(sdk.AttributeKeySender, signer.String()) + } + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + EventTypeUpdateClient, + sdk.NewAttribute(AttributeKeyClientID, msg.GetClientID()), + sdk.NewAttribute(AttrbuteKeyClientType, msg.GetHeader().ClientType().String()), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + attributes..., + ), + }) + + return &sdk.Result{ + Events: ctx.EventManager().Events().ToABCIEvents(), + }, nil +} + +// HandlerClientMisbehaviour defines the Evidence module handler for submitting a +// light client misbehaviour. +func HandlerClientMisbehaviour(k Keeper) evidence.Handler { + return func(ctx sdk.Context, evidence evidenceexported.Evidence) error { + misbehaviour, ok := evidence.(exported.Misbehaviour) + if !ok { + return types.ErrInvalidEvidence + } + + return k.CheckMisbehaviourAndUpdateState(ctx, misbehaviour) + } +} diff --git a/x/ibc/02-client/keeper/client.go b/x/ibc/02-client/keeper/client.go new file mode 100644 index 000000000000..98f2220727ef --- /dev/null +++ b/x/ibc/02-client/keeper/client.go @@ -0,0 +1,153 @@ +package keeper + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" + tendermint "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" +) + +// CreateClient creates a new client state and populates it with a given consensus +// state as defined in https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#create +// +// CONTRACT: ClientState was constructed correctly from given initial consensusState +func (k Keeper) CreateClient( + ctx sdk.Context, clientState exported.ClientState, consensusState exported.ConsensusState, +) (exported.ClientState, error) { + clientID := clientState.GetID() + _, found := k.GetClientState(ctx, clientID) + if found { + return nil, sdkerrors.Wrapf(types.ErrClientExists, "cannot create client with ID %s", clientID) + } + + _, found = k.GetClientType(ctx, clientID) + if found { + panic(fmt.Sprintf("client type is already defined for client %s", clientID)) + } + + height := consensusState.GetHeight() + if consensusState != nil { + k.SetClientConsensusState(ctx, clientID, height, consensusState) + } + + k.SetClientState(ctx, clientState) + k.SetClientType(ctx, clientID, clientState.ClientType()) + k.Logger(ctx).Info(fmt.Sprintf("client %s created at height %d", clientID, clientState.GetLatestHeight())) + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeCreateClient, + sdk.NewAttribute(types.AttributeKeyClientID, clientID), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + ), + }) + + return clientState, nil +} + +// UpdateClient updates the consensus state and the state root from a provided header +func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, header exported.Header) error { + clientType, found := k.GetClientType(ctx, clientID) + if !found { + return sdkerrors.Wrapf(types.ErrClientTypeNotFound, "cannot update client with ID %s", clientID) + } + + // check that the header consensus matches the client one + if header.ClientType() != clientType { + return sdkerrors.Wrapf(types.ErrInvalidConsensus, "cannot update client with ID %s", clientID) + } + + clientState, found := k.GetClientState(ctx, clientID) + if !found { + return sdkerrors.Wrapf(types.ErrClientNotFound, "cannot update client with ID %s", clientID) + } + + // addittion to spec: prevent update if the client is frozen + if clientState.IsFrozen() { + return sdkerrors.Wrapf(types.ErrClientFrozen, "cannot update client with ID %s", clientID) + } + + var ( + consensusState exported.ConsensusState + err error + ) + + switch clientType { + case exported.Tendermint: + clientState, consensusState, err = tendermint.CheckValidityAndUpdateState( + clientState, header, ctx.BlockTime(), + ) + default: + err = types.ErrInvalidClientType + } + + if err != nil { + return sdkerrors.Wrapf(err, "cannot update client with ID %s", clientID) + } + + k.SetClientState(ctx, clientState) + k.SetClientConsensusState(ctx, clientID, header.GetHeight(), consensusState) + k.Logger(ctx).Info(fmt.Sprintf("client %s updated to height %d", clientID, header.GetHeight())) + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeUpdateClient, + sdk.NewAttribute(types.AttributeKeyClientID, clientID), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + ), + }) + + return nil +} + +// CheckMisbehaviourAndUpdateState checks for client misbehaviour and freezes the +// client if so. +func (k Keeper) CheckMisbehaviourAndUpdateState(ctx sdk.Context, misbehaviour exported.Misbehaviour) error { + clientState, found := k.GetClientState(ctx, misbehaviour.GetClientID()) + if !found { + return sdkerrors.Wrap(types.ErrClientNotFound, misbehaviour.GetClientID()) + } + + consensusState, found := k.GetClientConsensusStateLTE(ctx, misbehaviour.GetClientID(), uint64(misbehaviour.GetHeight())) + if !found { + return sdkerrors.Wrap(types.ErrConsensusStateNotFound, misbehaviour.GetClientID()) + } + + var err error + switch e := misbehaviour.(type) { + case ibctmtypes.Evidence: + clientState, err = tendermint.CheckMisbehaviourAndUpdateState( + clientState, consensusState, misbehaviour, consensusState.GetHeight(), ctx.BlockTime(), + ) + + default: + err = sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized IBC client evidence type: %T", e) + } + + if err != nil { + return err + } + + k.SetClientState(ctx, clientState) + k.Logger(ctx).Info(fmt.Sprintf("client %s frozen due to misbehaviour", misbehaviour.GetClientID())) + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeSubmitMisbehaviour, + sdk.NewAttribute(types.AttributeKeyClientID, misbehaviour.GetClientID()), + sdk.NewAttribute(types.AttributeKeyClientType, misbehaviour.ClientType().String()), + ), + ) + + return nil +} diff --git a/x/ibc/02-client/keeper/client_test.go b/x/ibc/02-client/keeper/client_test.go new file mode 100644 index 000000000000..bea5392a3df8 --- /dev/null +++ b/x/ibc/02-client/keeper/client_test.go @@ -0,0 +1,316 @@ +package keeper_test + +import ( + "bytes" + "fmt" + "time" + + tmtypes "github.com/tendermint/tendermint/types" + + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" + + commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" +) + +const ( + invalidClientType exported.ClientType = 0 +) + +func (suite *KeeperTestSuite) TestCreateClient() { + suite.keeper.SetClientType(suite.ctx, testClientID2, exported.Tendermint) + + cases := []struct { + msg string + clientID string + expPass bool + expPanic bool + }{ + {"success", testClientID, true, false}, + {"client ID exists", testClientID, false, false}, + {"client type exists", testClientID2, false, true}, + } + + for i, tc := range cases { + tc := tc + i := i + if tc.expPanic { + suite.Require().Panics(func() { + clientState, err := ibctmtypes.Initialize(tc.clientID, trustingPeriod, ubdPeriod, suite.header) + suite.Require().NoError(err, "err on client state initialization") + suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState) + }, "Msg %d didn't panic: %s", i, tc.msg) + } else { + clientState, err := ibctmtypes.Initialize(tc.clientID, trustingPeriod, ubdPeriod, suite.header) + if tc.expPass { + suite.Require().NoError(err, "errored on initialization") + suite.Require().NotNil(clientState, "valid test case %d failed: %s", i, tc.msg) + } + // If we were able to initialize clientstate successfully, try persisting it to state + if err == nil { + _, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState) + } + + if tc.expPass { + suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg) + } else { + suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg) + } + } + } +} + +func (suite *KeeperTestSuite) TestUpdateClient() { + // Must create header creation functions since suite.header gets recreated on each test case + createValidUpdateFn := func(s *KeeperTestSuite) ibctmtypes.Header { + return ibctmtypes.CreateTestHeader(testClientID, suite.header.Height+1, suite.header.Time.Add(time.Minute), + suite.valSet, []tmtypes.PrivValidator{suite.privVal}) + } + createInvalidUpdateFn := func(s *KeeperTestSuite) ibctmtypes.Header { + return ibctmtypes.CreateTestHeader(testClientID, suite.header.Height-3, suite.header.Time.Add(time.Minute), + suite.valSet, []tmtypes.PrivValidator{suite.privVal}) + } + var updateHeader ibctmtypes.Header + + cases := []struct { + name string + malleate func() error + expPass bool + }{ + {"valid update", func() error { + clientState, err := ibctmtypes.Initialize(testClientID, trustingPeriod, ubdPeriod, suite.header) + if err != nil { + return err + } + _, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState) + updateHeader = createValidUpdateFn(suite) + return err + }, true}, + {"client type not found", func() error { + updateHeader = createValidUpdateFn(suite) + + return nil + }, false}, + {"client type and header type mismatch", func() error { + suite.keeper.SetClientType(suite.ctx, testClientID, invalidClientType) + updateHeader = createValidUpdateFn(suite) + + return nil + }, false}, + {"client state not found", func() error { + suite.keeper.SetClientType(suite.ctx, testClientID, exported.Tendermint) + updateHeader = createValidUpdateFn(suite) + + return nil + }, false}, + {"frozen client", func() error { + clientState := ibctmtypes.ClientState{FrozenHeight: 1, ID: testClientID, LastHeader: suite.header} + suite.keeper.SetClientState(suite.ctx, clientState) + suite.keeper.SetClientType(suite.ctx, testClientID, exported.Tendermint) + updateHeader = createValidUpdateFn(suite) + + return nil + }, false}, + {"invalid header", func() error { + clientState, err := ibctmtypes.Initialize(testClientID, trustingPeriod, ubdPeriod, suite.header) + if err != nil { + return err + } + _, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState) + if err != nil { + return err + } + updateHeader = createInvalidUpdateFn(suite) + + return nil + }, false}, + } + + for i, tc := range cases { + tc := tc + i := i + suite.Run(fmt.Sprintf("Case %s", tc.name), func() { + suite.SetupTest() + + err := tc.malleate() + suite.Require().NoError(err) + + suite.ctx = suite.ctx.WithBlockTime(updateHeader.Time.Add(time.Minute)) + + err = suite.keeper.UpdateClient(suite.ctx, testClientID, updateHeader) + + if tc.expPass { + suite.Require().NoError(err, err) + + expConsensusState := ibctmtypes.ConsensusState{ + Height: updateHeader.GetHeight(), + Timestamp: updateHeader.Time, + Root: commitmenttypes.NewMerkleRoot(updateHeader.AppHash), + ValidatorSet: updateHeader.ValidatorSet, + } + + clientState, found := suite.keeper.GetClientState(suite.ctx, testClientID) + suite.Require().True(found, "valid test case %d failed: %s", i, tc.name) + + consensusState, found := suite.keeper.GetClientConsensusState(suite.ctx, testClientID, updateHeader.GetHeight()) + suite.Require().True(found, "valid test case %d failed: %s", i, tc.name) + tmConsState, ok := consensusState.(ibctmtypes.ConsensusState) + suite.Require().True(ok, "consensus state is not a tendermint consensus state") + // recalculate cached totalVotingPower field for equality check + tmConsState.ValidatorSet.TotalVotingPower() + + suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name) + suite.Require().Equal(updateHeader.GetHeight(), clientState.GetLatestHeight(), "client state height not updated correctly on case %s", tc.name) + suite.Require().Equal(expConsensusState, consensusState, "consensus state should have been updated on case %s", tc.name) + } else { + suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name) + } + }) + } +} + +func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { + altPrivVal := tmtypes.NewMockPV() + altVal := tmtypes.NewValidator(altPrivVal.GetPubKey(), 4) + + // Create bothValSet with both suite validator and altVal + bothValSet := tmtypes.NewValidatorSet(append(suite.valSet.Validators, altVal)) + // Create alternative validator set with only altVal + altValSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{altVal}) + + // Create signer array and ensure it is in same order as bothValSet + var bothSigners []tmtypes.PrivValidator + if bytes.Compare(altPrivVal.GetPubKey().Address(), suite.privVal.GetPubKey().Address()) == -1 { + bothSigners = []tmtypes.PrivValidator{altPrivVal, suite.privVal} + } else { + bothSigners = []tmtypes.PrivValidator{suite.privVal, altPrivVal} + } + + altSigners := []tmtypes.PrivValidator{altPrivVal} + + testCases := []struct { + name string + evidence ibctmtypes.Evidence + malleate func() error + expPass bool + }{ + { + "trusting period misbehavior should pass", + ibctmtypes.Evidence{ + Header1: ibctmtypes.CreateTestHeader(testClientID, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothSigners), + Header2: ibctmtypes.CreateTestHeader(testClientID, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothSigners), + ChainID: testClientID, + ClientID: testClientID, + }, + func() error { + suite.consensusState.ValidatorSet = bothValSet + clientState, err := ibctmtypes.Initialize(testClientID, trustingPeriod, ubdPeriod, suite.header) + if err != nil { + return err + } + _, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState) + + return err + }, + true, + }, + { + "misbehavior at later height should pass", + ibctmtypes.Evidence{ + Header1: ibctmtypes.CreateTestHeader(testClientID, testClientHeight+5, suite.ctx.BlockTime(), bothValSet, bothSigners), + Header2: ibctmtypes.CreateTestHeader(testClientID, testClientHeight+5, suite.ctx.BlockTime(), bothValSet, bothSigners), + ChainID: testClientID, + ClientID: testClientID, + }, + func() error { + suite.consensusState.ValidatorSet = bothValSet + clientState, err := ibctmtypes.Initialize(testClientID, trustingPeriod, ubdPeriod, suite.header) + if err != nil { + return err + } + _, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState) + + return err + }, + true, + }, + { + "client state not found", + ibctmtypes.Evidence{}, + func() error { return nil }, + false, + }, + { + "consensus state not found", + ibctmtypes.Evidence{ + Header1: ibctmtypes.CreateTestHeader(testClientID, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothSigners), + Header2: ibctmtypes.CreateTestHeader(testClientID, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothSigners), + ChainID: testClientID, + ClientID: testClientID, + }, + func() error { + clientState := ibctmtypes.ClientState{FrozenHeight: 1, ID: testClientID, LastHeader: suite.header} + suite.keeper.SetClientState(suite.ctx, clientState) + return nil + }, + false, + }, + { + "consensus state not found", + ibctmtypes.Evidence{ + Header1: ibctmtypes.CreateTestHeader(testClientID, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothSigners), + Header2: ibctmtypes.CreateTestHeader(testClientID, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothSigners), + ChainID: testClientID, + ClientID: testClientID, + }, + func() error { + clientState := ibctmtypes.ClientState{FrozenHeight: 1, ID: testClientID, LastHeader: suite.header} + suite.keeper.SetClientState(suite.ctx, clientState) + return nil + }, + false, + }, + { + "misbehaviour check failed", + ibctmtypes.Evidence{ + Header1: ibctmtypes.CreateTestHeader(testClientID, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothSigners), + Header2: ibctmtypes.CreateTestHeader(testClientID, testClientHeight, suite.ctx.BlockTime(), altValSet, altSigners), + ChainID: testClientID, + ClientID: testClientID, + }, + func() error { + clientState, err := ibctmtypes.Initialize(testClientID, trustingPeriod, ubdPeriod, suite.header) + if err != nil { + return err + } + _, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState) + + return err + }, + false, + }, + } + + for i, tc := range testCases { + tc := tc + i := i + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + err := tc.malleate() + suite.Require().NoError(err) + + err = suite.keeper.CheckMisbehaviourAndUpdateState(suite.ctx, tc.evidence) + + if tc.expPass { + suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name) + + clientState, found := suite.keeper.GetClientState(suite.ctx, testClientID) + suite.Require().True(found, "valid test case %d failed: %s", i, tc.name) + suite.Require().True(clientState.IsFrozen(), "valid test case %d failed: %s", i, tc.name) + } else { + suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name) + } + }) + } +} diff --git a/x/ibc/02-client/keeper/keeper.go b/x/ibc/02-client/keeper/keeper.go new file mode 100644 index 000000000000..32a80d8af43a --- /dev/null +++ b/x/ibc/02-client/keeper/keeper.go @@ -0,0 +1,171 @@ +package keeper + +import ( + "fmt" + + "github.com/tendermint/tendermint/libs/log" + tmtypes "github.com/tendermint/tendermint/types" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + "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" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" +) + +// Keeper represents a type that grants read and write permissions to any client +// state information +type Keeper struct { + storeKey sdk.StoreKey + cdc *codec.Codec + stakingKeeper types.StakingKeeper +} + +// NewKeeper creates a new NewKeeper instance +func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, sk types.StakingKeeper) Keeper { + return Keeper{ + storeKey: key, + cdc: cdc, + stakingKeeper: sk, + } +} + +// Logger returns a module-specific logger. +func (k Keeper) Logger(ctx sdk.Context) log.Logger { + return ctx.Logger().With("module", fmt.Sprintf("x/%s/%s", ibctypes.ModuleName, types.SubModuleName)) +} + +// GetClientState gets a particular client from the store +func (k Keeper) GetClientState(ctx sdk.Context, clientID string) (exported.ClientState, bool) { + store := ctx.KVStore(k.storeKey) + bz := store.Get(ibctypes.KeyClientState(clientID)) + if bz == nil { + return nil, false + } + + var clientState exported.ClientState + k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &clientState) + return clientState, true +} + +// SetClientState sets a particular Client to the store +func (k Keeper) SetClientState(ctx sdk.Context, clientState exported.ClientState) { + store := ctx.KVStore(k.storeKey) + bz := k.cdc.MustMarshalBinaryLengthPrefixed(clientState) + store.Set(ibctypes.KeyClientState(clientState.GetID()), bz) +} + +// GetClientType gets the consensus type for a specific client +func (k Keeper) GetClientType(ctx sdk.Context, clientID string) (exported.ClientType, bool) { + store := ctx.KVStore(k.storeKey) + bz := store.Get(ibctypes.KeyClientType(clientID)) + if bz == nil { + return 0, false + } + + return exported.ClientType(bz[0]), true +} + +// SetClientType sets the specific client consensus type to the provable store +func (k Keeper) SetClientType(ctx sdk.Context, clientID string, clientType exported.ClientType) { + store := ctx.KVStore(k.storeKey) + store.Set(ibctypes.KeyClientType(clientID), []byte{byte(clientType)}) +} + +// GetClientConsensusState gets the stored consensus state from a client at a given height. +func (k Keeper) GetClientConsensusState(ctx sdk.Context, clientID string, height uint64) (exported.ConsensusState, bool) { + store := ctx.KVStore(k.storeKey) + bz := store.Get(ibctypes.KeyConsensusState(clientID, height)) + if bz == nil { + return nil, false + } + + var consensusState exported.ConsensusState + k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &consensusState) + return consensusState, true +} + +// SetClientConsensusState sets a ConsensusState to a particular client at the given +// height +func (k Keeper) SetClientConsensusState(ctx sdk.Context, clientID string, height uint64, consensusState exported.ConsensusState) { + store := ctx.KVStore(k.storeKey) + bz := k.cdc.MustMarshalBinaryLengthPrefixed(consensusState) + store.Set(ibctypes.KeyConsensusState(clientID, height), bz) +} + +// HasClientConsensusState returns if keeper has a ConsensusState for a particular +// client at the given height +func (k Keeper) HasClientConsensusState(ctx sdk.Context, clientID string, height uint64) bool { + store := ctx.KVStore(k.storeKey) + return store.Has(ibctypes.KeyConsensusState(clientID, height)) +} + +// GetLatestClientConsensusState gets the latest ConsensusState stored for a given client +func (k Keeper) GetLatestClientConsensusState(ctx sdk.Context, clientID string) (exported.ConsensusState, bool) { + clientState, ok := k.GetClientState(ctx, clientID) + if !ok { + return nil, false + } + return k.GetClientConsensusState(ctx, clientID, clientState.GetLatestHeight()) +} + +// GetClientConsensusStatelTE will get the latest ConsensusState of a particular client at the latest height +// less than or equal to the given height +func (k Keeper) GetClientConsensusStateLTE(ctx sdk.Context, clientID string, maxHeight uint64) (exported.ConsensusState, bool) { + for i := maxHeight; i > 0; i-- { + found := k.HasClientConsensusState(ctx, clientID, i) + if found { + return k.GetClientConsensusState(ctx, clientID, i) + } + } + return nil, false +} + +// GetSelfConsensusState introspects the (self) past historical info at a given height +// and returns the expected consensus state at that height. +func (k Keeper) GetSelfConsensusState(ctx sdk.Context, height uint64) (exported.ConsensusState, bool) { + histInfo, found := k.stakingKeeper.GetHistoricalInfo(ctx, int64(height)) + if !found { + return nil, false + } + + valSet := stakingtypes.Validators(histInfo.Valset) + + consensusState := ibctmtypes.ConsensusState{ + Height: height, + Timestamp: histInfo.Header.Time, + Root: commitmenttypes.NewMerkleRoot(histInfo.Header.AppHash), + ValidatorSet: tmtypes.NewValidatorSet(valSet.ToTmValidators()), + } + return consensusState, true +} + +// IterateClients provides an iterator over all stored light client State +// objects. For each State object, cb will be called. If the cb returns true, +// the iterator will close and stop. +func (k Keeper) IterateClients(ctx sdk.Context, cb func(exported.ClientState) bool) { + store := ctx.KVStore(k.storeKey) + iterator := sdk.KVStorePrefixIterator(store, ibctypes.KeyClientPrefix) + + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + var clientState exported.ClientState + k.cdc.MustUnmarshalBinaryLengthPrefixed(iterator.Value(), &clientState) + + if cb(clientState) { + break + } + } +} + +// GetAllClients returns all stored light client State objects. +func (k Keeper) GetAllClients(ctx sdk.Context) (states []exported.ClientState) { + k.IterateClients(ctx, func(state exported.ClientState) bool { + states = append(states, state) + return false + }) + return states +} diff --git a/x/ibc/02-client/keeper/keeper_test.go b/x/ibc/02-client/keeper/keeper_test.go new file mode 100644 index 000000000000..b636d6a85702 --- /dev/null +++ b/x/ibc/02-client/keeper/keeper_test.go @@ -0,0 +1,188 @@ +package keeper_test + +import ( + "math/rand" + "testing" + "time" + + "github.com/stretchr/testify/suite" + + abci "github.com/tendermint/tendermint/abci/types" + tmtypes "github.com/tendermint/tendermint/types" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/simapp" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/keeper" + 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/staking" +) + +const ( + testClientID = "gaia" + testClientID2 = "ethbridge" + testClientID3 = "ethermint" + + testClientHeight = 5 + + trustingPeriod time.Duration = time.Hour * 24 * 7 * 2 + ubdPeriod time.Duration = time.Hour * 24 * 7 * 3 +) + +type KeeperTestSuite struct { + suite.Suite + + cdc *codec.Codec + ctx sdk.Context + keeper *keeper.Keeper + consensusState ibctmtypes.ConsensusState + header ibctmtypes.Header + valSet *tmtypes.ValidatorSet + privVal tmtypes.PrivValidator + now time.Time +} + +func (suite *KeeperTestSuite) SetupTest() { + isCheckTx := false + suite.now = time.Date(2020, 1, 2, 0, 0, 0, 0, time.UTC) + now2 := suite.now.Add(time.Hour) + app := simapp.Setup(isCheckTx) + + suite.cdc = app.Codec() + suite.ctx = app.BaseApp.NewContext(isCheckTx, abci.Header{Height: testClientHeight, ChainID: testClientID, Time: now2}) + suite.keeper = &app.IBCKeeper.ClientKeeper + suite.privVal = tmtypes.NewMockPV() + validator := tmtypes.NewValidator(suite.privVal.GetPubKey(), 1) + suite.valSet = tmtypes.NewValidatorSet([]*tmtypes.Validator{validator}) + suite.header = ibctmtypes.CreateTestHeader(testClientID, testClientHeight, now2, suite.valSet, []tmtypes.PrivValidator{suite.privVal}) + suite.consensusState = ibctmtypes.ConsensusState{ + Height: testClientHeight, + Timestamp: suite.now, + Root: commitmenttypes.NewMerkleRoot([]byte("hash")), + ValidatorSet: suite.valSet, + } + + var validators staking.Validators + for i := 1; i < 11; i++ { + privVal := tmtypes.NewMockPV() + pk := privVal.GetPubKey() + val := staking.NewValidator(sdk.ValAddress(pk.Address()), pk, staking.Description{}) + val.Status = sdk.Bonded + val.Tokens = sdk.NewInt(rand.Int63()) + validators = append(validators, val) + + app.StakingKeeper.SetHistoricalInfo(suite.ctx, int64(i), staking.NewHistoricalInfo(suite.ctx.BlockHeader(), validators)) + } +} + +func TestKeeperTestSuite(t *testing.T) { + suite.Run(t, new(KeeperTestSuite)) +} + +func (suite *KeeperTestSuite) TestSetClientState() { + clientState := ibctmtypes.NewClientState(testClientID, trustingPeriod, ubdPeriod, ibctmtypes.Header{}) + suite.keeper.SetClientState(suite.ctx, clientState) + + retrievedState, found := suite.keeper.GetClientState(suite.ctx, testClientID) + suite.Require().True(found, "GetClientState failed") + suite.Require().Equal(clientState, retrievedState, "Client states are not equal") +} + +func (suite *KeeperTestSuite) TestSetClientType() { + suite.keeper.SetClientType(suite.ctx, testClientID, exported.Tendermint) + clientType, found := suite.keeper.GetClientType(suite.ctx, testClientID) + + suite.Require().True(found, "GetClientType failed") + suite.Require().Equal(exported.Tendermint, clientType, "ClientTypes not stored correctly") +} + +func (suite *KeeperTestSuite) TestSetClientConsensusState() { + suite.keeper.SetClientConsensusState(suite.ctx, testClientID, testClientHeight, suite.consensusState) + + retrievedConsState, found := suite.keeper.GetClientConsensusState(suite.ctx, testClientID, testClientHeight) + suite.Require().True(found, "GetConsensusState failed") + + tmConsState, ok := retrievedConsState.(ibctmtypes.ConsensusState) + // recalculate cached totalVotingPower field for equality check + tmConsState.ValidatorSet.TotalVotingPower() + suite.Require().True(ok) + suite.Require().Equal(suite.consensusState, tmConsState, "ConsensusState not stored correctly") +} + +func (suite KeeperTestSuite) TestGetAllClients() { + expClients := []exported.ClientState{ + ibctmtypes.NewClientState(testClientID2, trustingPeriod, ubdPeriod, ibctmtypes.Header{}), + ibctmtypes.NewClientState(testClientID3, trustingPeriod, ubdPeriod, ibctmtypes.Header{}), + ibctmtypes.NewClientState(testClientID, trustingPeriod, ubdPeriod, ibctmtypes.Header{}), + } + + for i := range expClients { + suite.keeper.SetClientState(suite.ctx, expClients[i]) + } + + clients := suite.keeper.GetAllClients(suite.ctx) + suite.Require().Len(clients, len(expClients)) + suite.Require().Equal(expClients, clients) +} + +func (suite KeeperTestSuite) TestGetConsensusState() { + suite.ctx = suite.ctx.WithBlockHeight(10) + cases := []struct { + name string + height uint64 + expPass bool + }{ + {"zero height", 0, false}, + {"height > latest height", uint64(suite.ctx.BlockHeight()) + 1, false}, + {"latest height - 1", uint64(suite.ctx.BlockHeight()) - 1, true}, + {"latest height", uint64(suite.ctx.BlockHeight()), true}, + } + + for i, tc := range cases { + tc := tc + cs, found := suite.keeper.GetSelfConsensusState(suite.ctx, tc.height) + if tc.expPass { + suite.Require().True(found, "Case %d should have passed: %s", i, tc.name) + suite.Require().NotNil(cs, "Case %d should have passed: %s", i, tc.name) + } else { + suite.Require().False(found, "Case %d should have failed: %s", i, tc.name) + suite.Require().Nil(cs, "Case %d should have failed: %s", i, tc.name) + } + } +} + +func (suite KeeperTestSuite) TestConsensusStateHelpers() { + // initial setup + clientState, _ := ibctmtypes.Initialize(testClientID, trustingPeriod, ubdPeriod, suite.header) + suite.keeper.SetClientState(suite.ctx, clientState) + suite.keeper.SetClientConsensusState(suite.ctx, testClientID, testClientHeight, suite.consensusState) + + nextState := ibctmtypes.ConsensusState{ + Height: testClientHeight + 5, + Timestamp: suite.now, + Root: commitmenttypes.NewMerkleRoot([]byte("next")), + ValidatorSet: suite.valSet, + } + + header := ibctmtypes.CreateTestHeader(testClientID, testClientHeight+5, suite.header.Time.Add(time.Minute), suite.valSet, []tmtypes.PrivValidator{suite.privVal}) + + // mock update functionality + clientState.LastHeader = header + suite.keeper.SetClientConsensusState(suite.ctx, testClientID, testClientHeight+5, nextState) + suite.keeper.SetClientState(suite.ctx, clientState) + + latest, ok := suite.keeper.GetLatestClientConsensusState(suite.ctx, testClientID) + // recalculate cached totalVotingPower for equality check + latest.(ibctmtypes.ConsensusState).ValidatorSet.TotalVotingPower() + suite.Require().True(ok) + suite.Require().Equal(nextState, latest, "Latest client not returned correctly") + + // Should return existing consensusState at latestClientHeight + lte, ok := suite.keeper.GetClientConsensusStateLTE(suite.ctx, testClientID, testClientHeight+3) + // recalculate cached totalVotingPower for equality check + lte.(ibctmtypes.ConsensusState).ValidatorSet.TotalVotingPower() + suite.Require().True(ok) + suite.Require().Equal(suite.consensusState, lte, "LTE helper function did not return latest client state below height: %d", testClientHeight+3) +} diff --git a/x/ibc/02-client/keeper/querier.go b/x/ibc/02-client/keeper/querier.go new file mode 100644 index 000000000000..7cadac9fe426 --- /dev/null +++ b/x/ibc/02-client/keeper/querier.go @@ -0,0 +1,37 @@ +package keeper + +import ( + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" +) + +// QuerierClients defines the sdk.Querier to query all the light client states. +func QuerierClients(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { + var params types.QueryAllClientsParams + + if err := k.cdc.UnmarshalJSON(req.Data, ¶ms); err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) + } + + clients := k.GetAllClients(ctx) + + start, end := client.Paginate(len(clients), params.Page, params.Limit, 100) + if start < 0 || end < 0 { + clients = []exported.ClientState{} + } else { + clients = clients[start:end] + } + + res, err := codec.MarshalJSONIndent(k.cdc, clients) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) + } + + return res, nil +} diff --git a/x/ibc/02-client/module.go b/x/ibc/02-client/module.go new file mode 100644 index 000000000000..fd1fd48c06b2 --- /dev/null +++ b/x/ibc/02-client/module.go @@ -0,0 +1,28 @@ +package client + +import ( + "fmt" + + "github.com/gorilla/mux" + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/client/cli" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/client/rest" +) + +// Name returns the IBC client name +func Name() string { + return SubModuleName +} + +// RegisterRESTRoutes registers the REST routes for the IBC client +func RegisterRESTRoutes(ctx context.CLIContext, rtr *mux.Router, queryRoute string) { + rest.RegisterRoutes(ctx, rtr, fmt.Sprintf("%s/%s", queryRoute, SubModuleName)) +} + +// GetQueryCmd returns no root query command for the IBC client +func GetQueryCmd(cdc *codec.Codec, queryRoute string) *cobra.Command { + return cli.GetQueryCmd(fmt.Sprintf("%s/%s", queryRoute, SubModuleName), cdc) +} diff --git a/x/ibc/02-client/types/codec.go b/x/ibc/02-client/types/codec.go new file mode 100644 index 000000000000..b8c0eed6ee61 --- /dev/null +++ b/x/ibc/02-client/types/codec.go @@ -0,0 +1,25 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" +) + +// SubModuleCdc defines the IBC client codec. +var SubModuleCdc *codec.Codec + +// RegisterCodec registers the IBC client interfaces and types +func RegisterCodec(cdc *codec.Codec) { + cdc.RegisterInterface((*exported.ClientState)(nil), nil) + cdc.RegisterInterface((*exported.MsgCreateClient)(nil), nil) + cdc.RegisterInterface((*exported.MsgUpdateClient)(nil), nil) + cdc.RegisterInterface((*exported.ConsensusState)(nil), nil) + cdc.RegisterInterface((*exported.Header)(nil), nil) + cdc.RegisterInterface((*exported.Misbehaviour)(nil), nil) + + SetSubModuleCodec(cdc) +} + +func SetSubModuleCodec(cdc *codec.Codec) { + SubModuleCdc = cdc +} diff --git a/x/ibc/02-client/types/errors.go b/x/ibc/02-client/types/errors.go new file mode 100644 index 000000000000..d1c8d317a4f1 --- /dev/null +++ b/x/ibc/02-client/types/errors.go @@ -0,0 +1,27 @@ +package types + +import ( + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +// IBC client sentinel errors +var ( + ErrClientExists = sdkerrors.Register(SubModuleName, 1, "light client already exists") + ErrClientNotFound = sdkerrors.Register(SubModuleName, 2, "light client not found") + ErrClientFrozen = sdkerrors.Register(SubModuleName, 3, "light client is frozen due to misbehaviour") + ErrConsensusStateNotFound = sdkerrors.Register(SubModuleName, 4, "consensus state not found") + ErrInvalidConsensus = sdkerrors.Register(SubModuleName, 5, "invalid consensus state") + ErrClientTypeNotFound = sdkerrors.Register(SubModuleName, 6, "client type not found") + ErrInvalidClientType = sdkerrors.Register(SubModuleName, 7, "invalid client type") + ErrRootNotFound = sdkerrors.Register(SubModuleName, 8, "commitment root not found") + ErrInvalidHeader = sdkerrors.Register(SubModuleName, 9, "invalid block header") + ErrInvalidEvidence = sdkerrors.Register(SubModuleName, 10, "invalid light client misbehaviour evidence") + ErrFailedClientConsensusStateVerification = sdkerrors.Register(SubModuleName, 13, "client consensus state verification failed") + ErrFailedConnectionStateVerification = sdkerrors.Register(SubModuleName, 14, "connection state verification failed") + ErrFailedChannelStateVerification = sdkerrors.Register(SubModuleName, 15, "channel state verification failed") + ErrFailedPacketCommitmentVerification = sdkerrors.Register(SubModuleName, 16, "packet commitment verification failed") + ErrFailedPacketAckVerification = sdkerrors.Register(SubModuleName, 17, "packet acknowledgement verification failed") + ErrFailedPacketAckAbsenceVerification = sdkerrors.Register(SubModuleName, 18, "packet acknowledgement absence verification failed") + ErrFailedNextSeqRecvVerification = sdkerrors.Register(SubModuleName, 19, "next sequence receive verification failed") + ErrSelfConsensusStateNotFound = sdkerrors.Register(SubModuleName, 20, "self consensus state not found") +) diff --git a/x/ibc/02-client/types/events.go b/x/ibc/02-client/types/events.go new file mode 100644 index 000000000000..9692cd389232 --- /dev/null +++ b/x/ibc/02-client/types/events.go @@ -0,0 +1,22 @@ +package types + +import ( + "fmt" + + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +// IBC client events +const ( + AttributeKeyClientID = "client_id" + AttributeKeyClientType = "client_type" +) + +// IBC client events vars +var ( + EventTypeCreateClient = "create_client" + EventTypeUpdateClient = "update_client" + EventTypeSubmitMisbehaviour = "client_misbehaviour" + + AttributeValueCategory = fmt.Sprintf("%s_%s", ibctypes.ModuleName, SubModuleName) +) diff --git a/x/ibc/02-client/types/expected_keepers.go b/x/ibc/02-client/types/expected_keepers.go new file mode 100644 index 000000000000..defc81506b1d --- /dev/null +++ b/x/ibc/02-client/types/expected_keepers.go @@ -0,0 +1,14 @@ +package types + +import ( + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" +) + +// StakingKeeper expected staking keeper +type StakingKeeper interface { + GetHistoricalInfo(ctx sdk.Context, height int64) (stakingtypes.HistoricalInfo, bool) + UnbondingTime(ctx sdk.Context) time.Duration +} diff --git a/x/ibc/02-client/types/keys.go b/x/ibc/02-client/types/keys.go new file mode 100644 index 000000000000..f360393335d5 --- /dev/null +++ b/x/ibc/02-client/types/keys.go @@ -0,0 +1,12 @@ +package types + +const ( + // SubModuleName defines the IBC client name + SubModuleName string = "client" + + // RouterKey is the message route for IBC client + RouterKey string = SubModuleName + + // QuerierRoute is the querier route for IBC client + QuerierRoute string = SubModuleName +) diff --git a/x/ibc/02-client/types/querier.go b/x/ibc/02-client/types/querier.go new file mode 100644 index 000000000000..892349f7104b --- /dev/null +++ b/x/ibc/02-client/types/querier.go @@ -0,0 +1,75 @@ +package types + +import ( + "strings" + + "github.com/tendermint/tendermint/crypto/merkle" + + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +// query routes supported by the IBC client Querier +const ( + QueryAllClients = "client_states" + QueryClientState = "client_state" + QueryConsensusState = "consensus_state" +) + +// QueryAllClientsParams defines the parameters necessary for querying for all +// light client states. +type QueryAllClientsParams struct { + Page int `json:"page" yaml:"page"` + Limit int `json:"limit" yaml:"limit"` +} + +// NewQueryAllClientsParams creates a new QueryAllClientsParams instance. +func NewQueryAllClientsParams(page, limit int) QueryAllClientsParams { + return QueryAllClientsParams{ + Page: page, + Limit: limit, + } +} + +// StateResponse defines the client response for a client state query. +// It includes the commitment proof and the height of the proof. +type StateResponse struct { + ClientState exported.ClientState `json:"client_state" yaml:"client_state"` + Proof commitmenttypes.MerkleProof `json:"proof,omitempty" yaml:"proof,omitempty"` + ProofPath commitmenttypes.MerklePath `json:"proof_path,omitempty" yaml:"proof_path,omitempty"` + ProofHeight uint64 `json:"proof_height,omitempty" yaml:"proof_height,omitempty"` +} + +// NewClientStateResponse creates a new StateResponse instance. +func NewClientStateResponse( + clientID string, clientState exported.ClientState, proof *merkle.Proof, height int64, +) StateResponse { + return StateResponse{ + ClientState: clientState, + Proof: commitmenttypes.MerkleProof{Proof: proof}, + ProofPath: commitmenttypes.NewMerklePath(strings.Split(ibctypes.ClientStatePath(clientID), "/")), + ProofHeight: uint64(height), + } +} + +// ConsensusStateResponse defines the client response for a Consensus state query. +// It includes the commitment proof and the height of the proof. +type ConsensusStateResponse struct { + ConsensusState exported.ConsensusState `json:"consensus_state" yaml:"consensus_state"` + Proof commitmenttypes.MerkleProof `json:"proof,omitempty" yaml:"proof,omitempty"` + ProofPath commitmenttypes.MerklePath `json:"proof_path,omitempty" yaml:"proof_path,omitempty"` + ProofHeight uint64 `json:"proof_height,omitempty" yaml:"proof_height,omitempty"` +} + +// NewConsensusStateResponse creates a new ConsensusStateResponse instance. +func NewConsensusStateResponse( + clientID string, cs exported.ConsensusState, proof *merkle.Proof, height int64, +) ConsensusStateResponse { + return ConsensusStateResponse{ + ConsensusState: cs, + Proof: commitmenttypes.MerkleProof{Proof: proof}, + ProofPath: commitmenttypes.NewMerklePath(strings.Split(ibctypes.ConsensusStatePath(clientID, uint64(height)), "/")), + ProofHeight: uint64(height), + } +} diff --git a/x/ibc/03-connection/alias.go b/x/ibc/03-connection/alias.go new file mode 100644 index 000000000000..7ffb090107ba --- /dev/null +++ b/x/ibc/03-connection/alias.go @@ -0,0 +1,72 @@ +package connection + +// nolint +// autogenerated code using github.com/rigelrozanski/multitool +// aliases generated for the following subdirectories: +// ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/03-connection/keeper +// ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types + +import ( + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/keeper" + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" +) + +const ( + AttributeKeyConnectionID = types.AttributeKeyConnectionID + AttributeKeyCounterpartyClientID = types.AttributeKeyCounterpartyClientID + SubModuleName = types.SubModuleName + StoreKey = types.StoreKey + RouterKey = types.RouterKey + QuerierRoute = types.QuerierRoute + QueryAllConnections = types.QueryAllConnections + QueryClientConnections = types.QueryClientConnections +) + +var ( + // functions aliases + NewKeeper = keeper.NewKeeper + QuerierConnections = keeper.QuerierConnections + QuerierClientConnections = keeper.QuerierClientConnections + RegisterCodec = types.RegisterCodec + NewConnectionEnd = types.NewConnectionEnd + NewCounterparty = types.NewCounterparty + ErrConnectionExists = types.ErrConnectionExists + ErrConnectionNotFound = types.ErrConnectionNotFound + ErrClientConnectionPathsNotFound = types.ErrClientConnectionPathsNotFound + ErrConnectionPath = types.ErrConnectionPath + ErrInvalidConnectionState = types.ErrInvalidConnectionState + ErrInvalidCounterparty = types.ErrInvalidCounterparty + NewMsgConnectionOpenInit = types.NewMsgConnectionOpenInit + NewMsgConnectionOpenTry = types.NewMsgConnectionOpenTry + NewMsgConnectionOpenAck = types.NewMsgConnectionOpenAck + NewMsgConnectionOpenConfirm = types.NewMsgConnectionOpenConfirm + NewConnectionResponse = types.NewConnectionResponse + NewClientConnectionsResponse = types.NewClientConnectionsResponse + NewQueryClientConnectionsParams = types.NewQueryClientConnectionsParams + GetCompatibleVersions = types.GetCompatibleVersions + LatestVersion = types.LatestVersion + PickVersion = types.PickVersion + + // variable aliases + SubModuleCdc = types.SubModuleCdc + EventTypeConnectionOpenInit = types.EventTypeConnectionOpenInit + EventTypeConnectionOpenTry = types.EventTypeConnectionOpenTry + EventTypeConnectionOpenAck = types.EventTypeConnectionOpenAck + EventTypeConnectionOpenConfirm = types.EventTypeConnectionOpenConfirm + AttributeValueCategory = types.AttributeValueCategory +) + +// nolint: golint +type ( + Keeper = keeper.Keeper + ConnectionEnd = types.ConnectionEnd + Counterparty = types.Counterparty + ClientKeeper = types.ClientKeeper + MsgConnectionOpenInit = types.MsgConnectionOpenInit + MsgConnectionOpenTry = types.MsgConnectionOpenTry + MsgConnectionOpenAck = types.MsgConnectionOpenAck + MsgConnectionOpenConfirm = types.MsgConnectionOpenConfirm + ConnectionResponse = types.ConnectionResponse + ClientConnectionsResponse = types.ClientConnectionsResponse + QueryClientConnectionsParams = types.QueryClientConnectionsParams +) diff --git a/x/ibc/03-connection/client/cli/cli.go b/x/ibc/03-connection/client/cli/cli.go new file mode 100644 index 000000000000..92c3fa8cc901 --- /dev/null +++ b/x/ibc/03-connection/client/cli/cli.go @@ -0,0 +1,41 @@ +package cli + +import ( + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/codec" +) + +// GetQueryCmd returns the query commands for IBC connections +func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { + ics03ConnectionQueryCmd := &cobra.Command{ + Use: "connection", + Short: "IBC connection query subcommands", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + } + + ics03ConnectionQueryCmd.AddCommand(flags.GetCommands( + GetCmdQueryConnections(queryRoute, cdc), + GetCmdQueryConnection(queryRoute, cdc), + )...) + return ics03ConnectionQueryCmd +} + +// GetTxCmd returns the transaction commands for IBC connections +func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { + ics03ConnectionTxCmd := &cobra.Command{ + Use: "connection", + Short: "IBC connection transaction subcommands", + } + + ics03ConnectionTxCmd.AddCommand(flags.PostCommands( + GetCmdConnectionOpenInit(storeKey, cdc), + GetCmdConnectionOpenTry(storeKey, cdc), + GetCmdConnectionOpenAck(storeKey, cdc), + GetCmdConnectionOpenConfirm(storeKey, cdc), + )...) + + return ics03ConnectionTxCmd +} diff --git a/x/ibc/03-connection/client/cli/query.go b/x/ibc/03-connection/client/cli/query.go new file mode 100644 index 000000000000..b3cc8fa0ea80 --- /dev/null +++ b/x/ibc/03-connection/client/cli/query.go @@ -0,0 +1,107 @@ +package cli + +import ( + "fmt" + "strings" + + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/version" + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/client/utils" +) + +// GetCmdQueryConnections defines the command to query all the connection ends +// that this chain mantains. +func GetCmdQueryConnections(queryRoute string, cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "connections", + Short: "Query all available light clients", + Long: strings.TrimSpace( + fmt.Sprintf(`Query all available connections + +Example: +$ %s query ibc connection connections + `, version.ClientName), + ), + Example: fmt.Sprintf("%s query ibc connection connections", version.ClientName), + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + page := viper.GetInt(flags.FlagPage) + limit := viper.GetInt(flags.FlagLimit) + + connections, _, err := utils.QueryAllConnections(cliCtx, page, limit) + if err != nil { + return err + } + + return cliCtx.PrintOutput(connections) + }, + } + cmd.Flags().Int(flags.FlagPage, 1, "pagination page of light clients to to query for") + cmd.Flags().Int(flags.FlagLimit, 100, "pagination limit of light clients to query for") + return cmd +} + +// GetCmdQueryConnection defines the command to query a connection end +func GetCmdQueryConnection(queryRoute string, cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "end [connection-id]", + Short: "Query stored connection end", + Long: strings.TrimSpace(fmt.Sprintf(`Query stored connection end + +Example: +$ %s query ibc connection end [connection-id] + `, version.ClientName), + ), + Example: fmt.Sprintf("%s query ibc connection end [connection-id]", version.ClientName), + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + connectionID := args[0] + prove := viper.GetBool(flags.FlagProve) + + connRes, err := utils.QueryConnection(cliCtx, connectionID, prove) + if err != nil { + return err + } + + return cliCtx.PrintOutput(connRes) + }, + } + cmd.Flags().Bool(flags.FlagProve, true, "show proofs for the query results") + + return cmd +} + +// GetCmdQueryClientConnections defines the command to query a client connections +func GetCmdQueryClientConnections(queryRoute string, cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "client [client-id]", + Short: "Query stored client connection paths", + Long: strings.TrimSpace(fmt.Sprintf(`Query stored client connection paths + +Example: +$ %s query ibc connection client [client-id] + `, version.ClientName), + ), + Example: fmt.Sprintf("%s query ibc connection client [client-id]", version.ClientName), + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + clientID := args[0] + prove := viper.GetBool(flags.FlagProve) + + connPathsRes, err := utils.QueryClientConnections(cliCtx, clientID, prove) + if err != nil { + return err + } + + return cliCtx.PrintOutput(connPathsRes) + }, + } +} diff --git a/x/ibc/03-connection/client/cli/tx.go b/x/ibc/03-connection/client/cli/tx.go new file mode 100644 index 000000000000..44caac4bf106 --- /dev/null +++ b/x/ibc/03-connection/client/cli/tx.go @@ -0,0 +1,251 @@ +package cli + +import ( + "bufio" + "fmt" + "strings" + + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/version" + authclient "github.com/cosmos/cosmos-sdk/x/auth/client" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/client/utils" + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" +) + +// Connection Handshake flags +const ( + FlagNode1 = "node1" + FlagNode2 = "node2" + FlagFrom1 = "from1" + FlagFrom2 = "from2" + FlagChainID2 = "chain-id2" +) + +// GetCmdConnectionOpenInit defines the command to initialize a connection on +// chain A with a given counterparty chain B +func GetCmdConnectionOpenInit(storeKey string, cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: strings.TrimSpace(`open-init [connection-id] [client-id] [counterparty-connection-id] [counterparty-client-id] [path/to/counterparty_prefix.json]`), + Short: "initialize connection on chain A", + Long: strings.TrimSpace( + fmt.Sprintf(`initialize a connection on chain A with a given counterparty chain B: + +Example: +$ %s tx ibc connection open-init [connection-id] [client-id] \ +[counterparty-connection-id] [counterparty-client-id] \ +[path/to/counterparty_prefix.json] + `, version.ClientName), + ), + Args: cobra.ExactArgs(5), + RunE: func(cmd *cobra.Command, args []string) error { + inBuf := bufio.NewReader(cmd.InOrStdin()) + txBldr := authtypes.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) + cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) + + connectionID := args[0] + clientID := args[1] + counterpartyConnectionID := args[2] + counterpartyClientID := args[3] + + counterpartyPrefix, err := utils.ParsePrefix(cliCtx.Codec, args[4]) + if err != nil { + return err + } + + msg := types.NewMsgConnectionOpenInit( + connectionID, clientID, counterpartyConnectionID, counterpartyClientID, + counterpartyPrefix, cliCtx.GetFromAddress(), + ) + + if err := msg.ValidateBasic(); err != nil { + return err + } + + return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } + return cmd +} + +// GetCmdConnectionOpenTry defines the command to relay a try open a connection on +// chain B +func GetCmdConnectionOpenTry(storeKey string, cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: strings.TrimSpace(`open-try [connection-id] [client-id] +[counterparty-connection-id] [counterparty-client-id] [path/to/counterparty_prefix.json] +[counterparty-versions] [path/to/proof_init.json]`), + Short: "initiate connection handshake between two chains", + Long: strings.TrimSpace( + fmt.Sprintf(`initialize a connection on chain A with a given counterparty chain B: + +Example: +$ %s tx ibc connection open-try connection-id] [client-id] \ +[counterparty-connection-id] [counterparty-client-id] [path/to/counterparty_prefix.json] \ +[counterparty-versions] [path/to/proof_init.json] + `, version.ClientName), + ), + Args: cobra.ExactArgs(7), + RunE: func(cmd *cobra.Command, args []string) error { + inBuf := bufio.NewReader(cmd.InOrStdin()) + txBldr := authtypes.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) + cliCtx := context.NewCLIContextWithInput(inBuf). + WithCodec(cdc). + WithHeight(viper.GetInt64(flags.FlagHeight)) + + connectionID := args[0] + clientID := args[1] + counterpartyConnectionID := args[2] + counterpartyClientID := args[3] + + counterpartyPrefix, err := utils.ParsePrefix(cliCtx.Codec, args[4]) + if err != nil { + return err + } + + // TODO: parse strings? + counterpartyVersions := args[5] + + proofInit, err := utils.ParseProof(cliCtx.Codec, args[1]) + if err != nil { + return err + } + + proofHeight := uint64(cliCtx.Height) + consensusHeight, err := lastHeight(cliCtx) + if err != nil { + return err + } + + msg := types.NewMsgConnectionOpenTry( + connectionID, clientID, counterpartyConnectionID, counterpartyClientID, + counterpartyPrefix, []string{counterpartyVersions}, proofInit, proofInit, proofHeight, + consensusHeight, cliCtx.GetFromAddress(), + ) + + if err := msg.ValidateBasic(); err != nil { + return err + } + + return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } + return cmd +} + +// GetCmdConnectionOpenAck defines the command to relay the acceptance of a +// connection open attempt from chain B to chain A +func GetCmdConnectionOpenAck(storeKey string, cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "open-ack [connection-id] [path/to/proof_try.json] [version]", + Short: "relay the acceptance of a connection open attempt from chain B to chain A", + Long: strings.TrimSpace( + fmt.Sprintf(`relay the acceptance of a connection open attempt from chain B to chain A: + +Example: +$ %s tx ibc connection open-ack [connection-id] [path/to/proof_try.json] [version] + `, version.ClientName), + ), + Args: cobra.ExactArgs(3), + RunE: func(cmd *cobra.Command, args []string) error { + inBuf := bufio.NewReader(cmd.InOrStdin()) + txBldr := authtypes.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) + cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) + + connectionID := args[0] + + proofTry, err := utils.ParseProof(cliCtx.Codec, args[1]) + if err != nil { + return err + } + + proofHeight := uint64(cliCtx.Height) + consensusHeight, err := lastHeight(cliCtx) + if err != nil { + return err + } + + version := args[4] + + msg := types.NewMsgConnectionOpenAck( + connectionID, proofTry, proofTry, proofHeight, + consensusHeight, version, cliCtx.GetFromAddress(), + ) + + if err := msg.ValidateBasic(); err != nil { + return err + } + + return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } + return cmd +} + +// GetCmdConnectionOpenConfirm defines the command to initialize a connection on +// chain A with a given counterparty chain B +func GetCmdConnectionOpenConfirm(storeKey string, cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "open-confirm [connection-id] [path/to/proof_ack.json]", + Short: "confirm to chain B that connection is open on chain A", + Long: strings.TrimSpace( + fmt.Sprintf(`confirm to chain B that connection is open on chain A: + +Example: +$ %s tx ibc connection open-confirm [connection-id] [path/to/proof_ack.json] + `, version.ClientName), + ), + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + inBuf := bufio.NewReader(cmd.InOrStdin()) + txBldr := authtypes.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) + cliCtx := context.NewCLIContextWithInput(inBuf). + WithCodec(cdc). + WithHeight(viper.GetInt64(flags.FlagHeight)) + + connectionID := args[0] + + proofAck, err := utils.ParseProof(cliCtx.Codec, args[1]) + if err != nil { + return err + } + + proofHeight := uint64(cliCtx.Height) + if err != nil { + return err + } + + msg := types.NewMsgConnectionOpenConfirm( + connectionID, proofAck, proofHeight, cliCtx.GetFromAddress(), + ) + + if err := msg.ValidateBasic(); err != nil { + return err + } + + return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } + return cmd +} + +// lastHeight util function to get the consensus height from the node +func lastHeight(cliCtx context.CLIContext) (uint64, error) { + node, err := cliCtx.GetNode() + if err != nil { + return 0, err + } + + info, err := node.ABCIInfo() + if err != nil { + return 0, err + } + + return uint64(info.Response.LastBlockHeight), nil +} diff --git a/x/ibc/03-connection/client/rest/query.go b/x/ibc/03-connection/client/rest/query.go new file mode 100644 index 000000000000..2a780c91f76b --- /dev/null +++ b/x/ibc/03-connection/client/rest/query.go @@ -0,0 +1,84 @@ +package rest + +import ( + "fmt" + "net/http" + + "github.com/gorilla/mux" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/types/rest" + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/client/utils" +) + +func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router, queryRoute string) { + r.HandleFunc(fmt.Sprintf("/ibc/connections/{%s}", RestConnectionID), queryConnectionHandlerFn(cliCtx, queryRoute)).Methods("GET") + r.HandleFunc(fmt.Sprintf("/ibc/clients/{%s}/connections", RestClientID), queryClientConnectionsHandlerFn(cliCtx, queryRoute)).Methods("GET") +} + +// queryConnectionHandlerFn implements a connection querying route +// +// @Summary Query connection +// @Tags IBC +// @Produce json +// @Param connection-id path string true "Client ID" +// @Param prove query boolean false "Proof of result" +// @Success 200 {object} QueryConnection "OK" +// @Failure 400 {object} rest.ErrorResponse "Invalid connection id" +// @Failure 500 {object} rest.ErrorResponse "Internal Server Error" +// @Router /ibc/connections/{connection-id} [get] +func queryConnectionHandlerFn(cliCtx context.CLIContext, queryRoute string) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + connectionID := vars[RestConnectionID] + prove := rest.ParseQueryParamBool(r, flags.FlagProve) + + cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) + if !ok { + return + } + + connRes, err := utils.QueryConnection(cliCtx, connectionID, prove) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + + cliCtx = cliCtx.WithHeight(int64(connRes.ProofHeight)) + rest.PostProcessResponse(w, cliCtx, connRes) + } +} + +// queryClientConnectionsHandlerFn implements a client connections querying route +// +// @Summary Query connections of a client +// @Tags IBC +// @Produce json +// @Param client-id path string true "Client ID" +// @Param prove query boolean false "Proof of result" +// @Success 200 {object} QueryClientConnections "OK" +// @Failure 400 {object} rest.ErrorResponse "Invalid client id" +// @Failure 500 {object} rest.ErrorResponse "Internal Server Error" +// @Router /ibc/clients/{client-id}/connections [get] +func queryClientConnectionsHandlerFn(cliCtx context.CLIContext, queryRoute string) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + clientID := vars[RestClientID] + prove := rest.ParseQueryParamBool(r, flags.FlagProve) + + cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) + if !ok { + return + } + + connPathsRes, err := utils.QueryClientConnections(cliCtx, clientID, prove) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + + cliCtx = cliCtx.WithHeight(int64(connPathsRes.ProofHeight)) + rest.PostProcessResponse(w, cliCtx, connPathsRes) + } +} diff --git a/x/ibc/03-connection/client/rest/rest.go b/x/ibc/03-connection/client/rest/rest.go new file mode 100644 index 000000000000..a3d3c5613de1 --- /dev/null +++ b/x/ibc/03-connection/client/rest/rest.go @@ -0,0 +1,62 @@ +package rest + +import ( + "github.com/gorilla/mux" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/types/rest" + commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" +) + +const ( + RestConnectionID = "connection-id" + RestClientID = "client-id" +) + +// RegisterRoutes - Central function to define routes that get registered by the main application +func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, queryRoute string) { + registerQueryRoutes(cliCtx, r, queryRoute) + registerTxRoutes(cliCtx, r) +} + +// ConnectionOpenInitReq defines the properties of a connection open init request's body. +type ConnectionOpenInitReq struct { + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + ConnectionID string `json:"connection_id" yaml:"connection_id"` + ClientID string `json:"client_id" yaml:"client_id"` + CounterpartyClientID string `json:"counterparty_client_id" yaml:"counterparty_client_id"` + CounterpartyConnectionID string `json:"counterparty_connection_id" yaml:"counterparty_connection_id"` + CounterpartyPrefix commitmentexported.Prefix `json:"counterparty_prefix" yaml:"counterparty_prefix"` +} + +// ConnectionOpenTryReq defines the properties of a connection open try request's body. +type ConnectionOpenTryReq struct { + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + ConnectionID string `json:"connection_id" yaml:"connection_id"` + ClientID string `json:"client_id" yaml:"client_id"` + CounterpartyClientID string `json:"counterparty_client_id" yaml:"counterparty_client_id"` + CounterpartyConnectionID string `json:"counterparty_connection_id" yaml:"counterparty_connection_id"` + CounterpartyPrefix commitmentexported.Prefix `json:"counterparty_prefix" yaml:"counterparty_prefix"` + CounterpartyVersions []string `json:"counterparty_versions" yaml:"counterparty_versions"` + ProofInit commitmentexported.Proof `json:"proof_init" yaml:"proof_init"` + ProofConsensus commitmentexported.Proof `json:"proof_consensus" yaml:"proof_consensus"` + ProofHeight uint64 `json:"proof_height" yaml:"proof_height"` + ConsensusHeight uint64 `json:"consensus_height" yaml:"consensus_height"` +} + +// ConnectionOpenAckReq defines the properties of a connection open ack request's body. +type ConnectionOpenAckReq struct { + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + ProofTry commitmentexported.Proof `json:"proof_try" yaml:"proof_try"` + ProofConsensus commitmentexported.Proof `json:"proof_consensus" yaml:"proof_consensus"` + ProofHeight uint64 `json:"proof_height" yaml:"proof_height"` + ConsensusHeight uint64 `json:"consensus_height" yaml:"consensus_height"` + Version string `json:"version" yaml:"version"` +} + +// ConnectionOpenConfirmReq defines the properties of a connection open confirm request's body. +type ConnectionOpenConfirmReq struct { + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + ProofAck commitmentexported.Proof `json:"proof_ack" yaml:"proof_ack"` + ProofHeight uint64 `json:"proof_height" yaml:"proof_height"` +} diff --git a/x/ibc/03-connection/client/rest/tx.go b/x/ibc/03-connection/client/rest/tx.go new file mode 100644 index 000000000000..d119fde64785 --- /dev/null +++ b/x/ibc/03-connection/client/rest/tx.go @@ -0,0 +1,204 @@ +package rest + +import ( + "fmt" + "net/http" + + "github.com/gorilla/mux" + + "github.com/cosmos/cosmos-sdk/client/context" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/rest" + authclient "github.com/cosmos/cosmos-sdk/x/auth/client" + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" +) + +func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router) { + r.HandleFunc("/ibc/connections/open-init", connectionOpenInitHandlerFn(cliCtx)).Methods("POST") + r.HandleFunc("/ibc/connections/open-try", connectionOpenTryHandlerFn(cliCtx)).Methods("POST") + r.HandleFunc(fmt.Sprintf("/ibc/connections/{%s}/open-ack", RestConnectionID), connectionOpenAckHandlerFn(cliCtx)).Methods("POST") + r.HandleFunc(fmt.Sprintf("/ibc/connections/{%s}/open-confirm", RestConnectionID), connectionOpenConfirmHandlerFn(cliCtx)).Methods("POST") +} + +// connectionOpenInitHandlerFn implements a connection open init handler +// +// @Summary Connection open-init +// @Tags IBC +// @Accept json +// @Produce json +// @Param body body rest.ConnectionOpenInitReq true "Connection open-init request body" +// @Success 200 {object} PostConnectionOpenInit "OK" +// @Failure 500 {object} rest.ErrorResponse "Internal Server Error" +// @Router /ibc/connections/open-init [post] +func connectionOpenInitHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req ConnectionOpenInitReq + if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) { + return + } + + req.BaseReq = req.BaseReq.Sanitize() + if !req.BaseReq.ValidateBasic(w) { + return + } + + fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + // create the message + msg := types.NewMsgConnectionOpenInit( + req.ConnectionID, req.ClientID, req.CounterpartyConnectionID, + req.CounterpartyClientID, req.CounterpartyPrefix, fromAddr, + ) + + if err := msg.ValidateBasic(); err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) + } +} + +// connectionOpenTryHandlerFn implements a connection open try handler +// +// @Summary Connection open-try +// @Tags IBC +// @Accept json +// @Produce json +// @Param body body rest.ConnectionOpenTryReq true "Connection open-try request body" +// @Success 200 {object} PostConnectionOpenTry "OK" +// @Failure 500 {object} rest.ErrorResponse "Internal Server Error" +// @Router /ibc/connections/open-try [post] +func connectionOpenTryHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req ConnectionOpenTryReq + if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) { + return + } + + req.BaseReq = req.BaseReq.Sanitize() + if !req.BaseReq.ValidateBasic(w) { + return + } + + fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + // create the message + msg := types.NewMsgConnectionOpenTry( + req.ConnectionID, req.ClientID, req.CounterpartyConnectionID, + req.CounterpartyClientID, req.CounterpartyPrefix, req.CounterpartyVersions, + req.ProofInit, req.ProofConsensus, req.ProofHeight, + req.ConsensusHeight, fromAddr, + ) + + if err := msg.ValidateBasic(); err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) + } +} + +// connectionOpenAckHandlerFn implements a connection open ack handler +// +// @Summary Connection open-ack +// @Tags IBC +// @Accept json +// @Produce json +// @Param connection-id path string true "Connection ID" +// @Param body body rest.ConnectionOpenAckReq true "Connection open-ack request body" +// @Success 200 {object} PostConnectionOpenAck "OK" +// @Failure 400 {object} rest.ErrorResponse "Invalid connection id" +// @Failure 500 {object} rest.ErrorResponse "Internal Server Error" +// @Router /ibc/connections/{connection-id}/open-ack [post] +func connectionOpenAckHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + connectionID := vars[RestConnectionID] + + var req ConnectionOpenAckReq + if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) { + return + } + + req.BaseReq = req.BaseReq.Sanitize() + if !req.BaseReq.ValidateBasic(w) { + return + } + + fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + // create the message + msg := types.NewMsgConnectionOpenAck( + connectionID, req.ProofTry, req.ProofConsensus, req.ProofHeight, + req.ConsensusHeight, req.Version, fromAddr, + ) + + if err := msg.ValidateBasic(); err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) + } +} + +// connectionOpenConfirmHandlerFn implements a connection open confirm handler +// +// @Summary Connection open-confirm +// @Tags IBC +// @Accept json +// @Produce json +// @Param connection-id path string true "Connection ID" +// @Param body body rest.ConnectionOpenConfirmReq true "Connection open-confirm request body" +// @Success 200 {object} PostConnectionOpenConfirm "OK" +// @Failure 400 {object} rest.ErrorResponse "Invalid connection id" +// @Failure 500 {object} rest.ErrorResponse "Internal Server Error" +// @Router /ibc/connections/{connection-id}/open-confirm [post] +func connectionOpenConfirmHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + connectionID := vars[RestConnectionID] + + var req ConnectionOpenConfirmReq + if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) { + return + } + + req.BaseReq = req.BaseReq.Sanitize() + if !req.BaseReq.ValidateBasic(w) { + return + } + + fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + // create the message + msg := types.NewMsgConnectionOpenConfirm( + connectionID, req.ProofAck, req.ProofHeight, fromAddr, + ) + + if err := msg.ValidateBasic(); err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) + } +} diff --git a/x/ibc/03-connection/client/utils/utils.go b/x/ibc/03-connection/client/utils/utils.go new file mode 100644 index 000000000000..0334ad0b5393 --- /dev/null +++ b/x/ibc/03-connection/client/utils/utils.go @@ -0,0 +1,124 @@ +package utils + +import ( + "fmt" + "io/ioutil" + + "github.com/pkg/errors" + + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" + commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +// QueryAllConnections returns all the connections. It _does not_ return +// any merkle proof. +func QueryAllConnections(cliCtx context.CLIContext, page, limit int) ([]types.IdentifiedConnectionEnd, int64, error) { + params := types.NewQueryAllConnectionsParams(page, limit) + bz, err := cliCtx.Codec.MarshalJSON(params) + if err != nil { + return nil, 0, fmt.Errorf("failed to marshal query params: %w", err) + } + + route := fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryAllConnections) + res, height, err := cliCtx.QueryWithData(route, bz) + if err != nil { + return nil, 0, err + } + + var connections []types.IdentifiedConnectionEnd + err = cliCtx.Codec.UnmarshalJSON(res, &connections) + if err != nil { + return nil, 0, fmt.Errorf("failed to unmarshal connections: %w", err) + } + return connections, height, nil +} + +// QueryConnection queries the store to get a connection end and a merkle +// proof. +func QueryConnection( + cliCtx context.CLIContext, connectionID string, prove bool, +) (types.ConnectionResponse, error) { + req := abci.RequestQuery{ + Path: "store/ibc/key", + Data: ibctypes.KeyConnection(connectionID), + Prove: prove, + } + + res, err := cliCtx.QueryABCI(req) + if err != nil { + return types.ConnectionResponse{}, err + } + + var connection types.ConnectionEnd + if err := cliCtx.Codec.UnmarshalBinaryLengthPrefixed(res.Value, &connection); err != nil { + return types.ConnectionResponse{}, err + } + + connRes := types.NewConnectionResponse(connectionID, connection, res.Proof, res.Height) + + return connRes, nil +} + +// QueryClientConnections queries the store to get the registered connection paths +// registered for a particular client and a merkle proof. +func QueryClientConnections( + cliCtx context.CLIContext, clientID string, prove bool, +) (types.ClientConnectionsResponse, error) { + req := abci.RequestQuery{ + Path: "store/ibc/key", + Data: ibctypes.KeyClientConnections(clientID), + Prove: prove, + } + + res, err := cliCtx.QueryABCI(req) + if err != nil { + return types.ClientConnectionsResponse{}, err + } + + var paths []string + if err := cliCtx.Codec.UnmarshalBinaryLengthPrefixed(res.Value, &paths); err != nil { + return types.ClientConnectionsResponse{}, err + } + + connPathsRes := types.NewClientConnectionsResponse(clientID, paths, res.Proof, res.Height) + return connPathsRes, nil +} + +// ParsePrefix unmarshals an cmd input argument from a JSON string to a commitment +// Prefix. If the input is not a JSON, it looks for a path to the JSON file. +func ParsePrefix(cdc *codec.Codec, arg string) (commitmenttypes.MerklePrefix, error) { + var prefix commitmenttypes.MerklePrefix + if err := cdc.UnmarshalJSON([]byte(arg), &prefix); err != nil { + // check for file path if JSON input is not provided + contents, err := ioutil.ReadFile(arg) + if err != nil { + return commitmenttypes.MerklePrefix{}, errors.New("neither JSON input nor path to .json file were provided") + } + if err := cdc.UnmarshalJSON(contents, &prefix); err != nil { + return commitmenttypes.MerklePrefix{}, errors.Wrap(err, "error unmarshalling commitment prefix") + } + } + return prefix, nil +} + +// ParseProof unmarshals an cmd input argument from a JSON string to a commitment +// Proof. If the input is not a JSON, it looks for a path to the JSON file. +func ParseProof(cdc *codec.Codec, arg string) (commitmenttypes.MerkleProof, error) { + var proof commitmenttypes.MerkleProof + if err := cdc.UnmarshalJSON([]byte(arg), &proof); err != nil { + // check for file path if JSON input is not provided + contents, err := ioutil.ReadFile(arg) + if err != nil { + return commitmenttypes.MerkleProof{}, errors.New("neither JSON input nor path to .json file were provided") + } + if err := cdc.UnmarshalJSON(contents, &proof); err != nil { + return commitmenttypes.MerkleProof{}, errors.Wrap(err, "error unmarshalling commitment proof") + } + } + return proof, nil +} diff --git a/x/ibc/03-connection/exported/exported.go b/x/ibc/03-connection/exported/exported.go new file mode 100644 index 000000000000..8f1591f2f6e6 --- /dev/null +++ b/x/ibc/03-connection/exported/exported.go @@ -0,0 +1,89 @@ +package exported + +import ( + "encoding/json" + + commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" +) + +// ConnectionI describes the required methods for a connection. +type ConnectionI interface { + GetState() State + GetClientID() string + GetCounterparty() CounterpartyI + GetVersions() []string + ValidateBasic() error +} + +// CounterpartyI describes the required methods for a counterparty connection. +type CounterpartyI interface { + GetClientID() string + GetConnectionID() string + GetPrefix() commitmentexported.Prefix + ValidateBasic() error +} + +// State defines the state of a connection between two disctinct +// chains +type State byte + +// available connection states +const ( + UNINITIALIZED State = iota // default State + INIT + TRYOPEN + OPEN +) + +// string representation of the connection states +const ( + StateUninitialized string = "UNINITIALIZED" + StateInit string = "INIT" + StateTryOpen string = "TRYOPEN" + StateOpen string = "OPEN" +) + +// String implements the Stringer interface +func (s State) String() string { + switch s { + case INIT: + return StateInit + case TRYOPEN: + return StateTryOpen + case OPEN: + return StateOpen + default: + return StateUninitialized + } +} + +// StateFromString parses a string into a connection state +func StateFromString(state string) State { + switch state { + case StateInit: + return INIT + case StateTryOpen: + return TRYOPEN + case StateOpen: + return OPEN + default: + return UNINITIALIZED + } +} + +// MarshalJSON marshal to JSON using string. +func (s State) MarshalJSON() ([]byte, error) { + return json.Marshal(s.String()) +} + +// UnmarshalJSON decodes from JSON assuming Bech32 encoding. +func (s *State) UnmarshalJSON(data []byte) error { + var str string + err := json.Unmarshal(data, &str) + if err != nil { + return err + } + + *s = StateFromString(str) + return nil +} diff --git a/x/ibc/03-connection/exported/exported_test.go b/x/ibc/03-connection/exported/exported_test.go new file mode 100644 index 000000000000..c45dfe6cca2b --- /dev/null +++ b/x/ibc/03-connection/exported/exported_test.go @@ -0,0 +1,46 @@ +package exported + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestConnectionStateString(t *testing.T) { + cases := []struct { + name string + state State + }{ + {StateUninitialized, UNINITIALIZED}, + {StateInit, INIT}, + {StateTryOpen, TRYOPEN}, + {StateOpen, OPEN}, + } + + for _, tt := range cases { + tt := tt + require.Equal(t, tt.state, StateFromString(tt.name)) + require.Equal(t, tt.name, tt.state.String()) + } +} + +func TestConnectionlStateMarshalJSON(t *testing.T) { + cases := []struct { + name string + state State + }{ + {StateUninitialized, UNINITIALIZED}, + {StateInit, INIT}, + {StateTryOpen, TRYOPEN}, + {StateOpen, OPEN}, + } + + for _, tt := range cases { + tt := tt + bz, err := tt.state.MarshalJSON() + require.NoError(t, err) + var state State + require.NoError(t, state.UnmarshalJSON(bz)) + require.Equal(t, tt.name, state.String()) + } +} diff --git a/x/ibc/03-connection/handler.go b/x/ibc/03-connection/handler.go new file mode 100644 index 000000000000..42da0f7de72f --- /dev/null +++ b/x/ibc/03-connection/handler.go @@ -0,0 +1,113 @@ +package connection + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" +) + +// HandleMsgConnectionOpenInit defines the sdk.Handler for MsgConnectionOpenInit +func HandleMsgConnectionOpenInit(ctx sdk.Context, k Keeper, msg MsgConnectionOpenInit) (*sdk.Result, error) { + if err := k.ConnOpenInit( + ctx, msg.ConnectionID, msg.ClientID, msg.Counterparty, + ); err != nil { + return nil, err + } + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeConnectionOpenInit, + sdk.NewAttribute(types.AttributeKeyConnectionID, msg.ConnectionID), + sdk.NewAttribute(types.AttributeKeyClientID, msg.ClientID), + sdk.NewAttribute(types.AttributeKeyCounterpartyClientID, msg.Counterparty.ClientID), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, AttributeValueCategory), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), + ), + }) + + return &sdk.Result{ + Events: ctx.EventManager().Events().ToABCIEvents(), + }, nil +} + +// HandleMsgConnectionOpenTry defines the sdk.Handler for MsgConnectionOpenTry +func HandleMsgConnectionOpenTry(ctx sdk.Context, k Keeper, msg MsgConnectionOpenTry) (*sdk.Result, error) { + if err := k.ConnOpenTry( + ctx, msg.ConnectionID, msg.Counterparty, msg.ClientID, + msg.CounterpartyVersions, msg.ProofInit, msg.ProofConsensus, + msg.ProofHeight, msg.ConsensusHeight, + ); err != nil { + return nil, err + } + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeConnectionOpenTry, + sdk.NewAttribute(types.AttributeKeyConnectionID, msg.ConnectionID), + sdk.NewAttribute(types.AttributeKeyClientID, msg.ClientID), + sdk.NewAttribute(types.AttributeKeyCounterpartyClientID, msg.Counterparty.ClientID), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, AttributeValueCategory), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), + ), + }) + + return &sdk.Result{ + Events: ctx.EventManager().Events().ToABCIEvents(), + }, nil +} + +// HandleMsgConnectionOpenAck defines the sdk.Handler for MsgConnectionOpenAck +func HandleMsgConnectionOpenAck(ctx sdk.Context, k Keeper, msg MsgConnectionOpenAck) (*sdk.Result, error) { + if err := k.ConnOpenAck( + ctx, msg.ConnectionID, msg.Version, msg.ProofTry, msg.ProofConsensus, + msg.ProofHeight, msg.ConsensusHeight, + ); err != nil { + return nil, err + } + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + EventTypeConnectionOpenAck, + sdk.NewAttribute(AttributeKeyConnectionID, msg.ConnectionID), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, AttributeValueCategory), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), + ), + }) + + return &sdk.Result{ + Events: ctx.EventManager().Events().ToABCIEvents(), + }, nil +} + +// HandleMsgConnectionOpenConfirm defines the sdk.Handler for MsgConnectionOpenConfirm +func HandleMsgConnectionOpenConfirm(ctx sdk.Context, k Keeper, msg MsgConnectionOpenConfirm) (*sdk.Result, error) { + if err := k.ConnOpenConfirm( + ctx, msg.ConnectionID, msg.ProofAck, msg.ProofHeight, + ); err != nil { + return nil, err + } + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + EventTypeConnectionOpenConfirm, + sdk.NewAttribute(AttributeKeyConnectionID, msg.ConnectionID), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, AttributeValueCategory), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), + ), + }) + + return &sdk.Result{ + Events: ctx.EventManager().Events().ToABCIEvents(), + }, nil +} diff --git a/x/ibc/03-connection/keeper/handshake.go b/x/ibc/03-connection/keeper/handshake.go new file mode 100644 index 000000000000..e7cc6b796dfe --- /dev/null +++ b/x/ibc/03-connection/keeper/handshake.go @@ -0,0 +1,234 @@ +package keeper + +import ( + "bytes" + "fmt" + + 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" + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported" + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" + commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +// ConnOpenInit initialises a connection attempt on chain A. +// +// NOTE: Identifiers are checked on msg validation. +func (k Keeper) ConnOpenInit( + ctx sdk.Context, + connectionID, // identifier + clientID string, + counterparty types.Counterparty, // desiredCounterpartyConnectionIdentifier, counterpartyPrefix, counterpartyClientIdentifier +) error { + _, found := k.GetConnection(ctx, connectionID) + if found { + return sdkerrors.Wrap(types.ErrConnectionExists, "cannot initialize connection") + } + + // connection defines chain A's ConnectionEnd + connection := types.NewConnectionEnd(exported.INIT, clientID, counterparty, types.GetCompatibleVersions()) + k.SetConnection(ctx, connectionID, connection) + + if err := k.addConnectionToClient(ctx, clientID, connectionID); err != nil { + return sdkerrors.Wrap(err, "cannot initialize connection") + } + + k.Logger(ctx).Info(fmt.Sprintf("connection %s state updated: NONE -> INIT", connectionID)) + return nil +} + +// ConnOpenTry relays notice of a connection attempt on chain A to chain B (this +// code is executed on chain B). +// +// NOTE: +// - Here chain A acts as the counterparty +// - Identifiers are checked on msg validation +func (k Keeper) ConnOpenTry( + ctx sdk.Context, + connectionID string, // desiredIdentifier + counterparty types.Counterparty, // counterpartyConnectionIdentifier, counterpartyPrefix and counterpartyClientIdentifier + clientID string, // clientID of chainA + counterpartyVersions []string, // supported versions of chain A + proofInit commitmentexported.Proof, // proof that chainA stored connectionEnd in state (on ConnOpenInit) + proofConsensus commitmentexported.Proof, // proof that chainA stored chainB's consensus state at consensus height + proofHeight uint64, // height at which relayer constructs proof of A storing connectionEnd in state + consensusHeight uint64, // latest height of chain B which chain A has stored in its chain B client +) error { + if consensusHeight > uint64(ctx.BlockHeight()) { + return sdkerrors.Wrap(ibctypes.ErrInvalidHeight, "invalid consensus height") + } + + expectedConsensusState, found := k.clientKeeper.GetSelfConsensusState(ctx, consensusHeight) + if !found { + return clienttypes.ErrSelfConsensusStateNotFound + } + + // expectedConnection defines Chain A's ConnectionEnd + // NOTE: chain A's counterparty is chain B (i.e where this code is executed) + prefix := k.GetCommitmentPrefix() + expectedCounterparty := types.NewCounterparty(clientID, connectionID, prefix) + expectedConnection := types.NewConnectionEnd(exported.INIT, counterparty.ClientID, expectedCounterparty, counterpartyVersions) + + // chain B picks a version from Chain A's available versions that is compatible + // with the supported IBC versions + version := types.PickVersion(counterpartyVersions, types.GetCompatibleVersions()) + + // connection defines chain B's ConnectionEnd + connection := types.NewConnectionEnd(exported.UNINITIALIZED, clientID, counterparty, []string{version}) + + // Check that ChainA committed expectedConnectionEnd to its state + if err := k.VerifyConnectionState( + ctx, connection, proofHeight, proofInit, counterparty.ConnectionID, + expectedConnection, + ); err != nil { + return err + } + + // Check that ChainA stored the correct ConsensusState of chainB at the given consensusHeight + if err := k.VerifyClientConsensusState( + ctx, connection, proofHeight, consensusHeight, proofConsensus, expectedConsensusState, + ); err != nil { + return err + } + + // If connection already exists for connectionID, ensure that the existing connection's counterparty + // is chainA and connection is on INIT stage + // Check that existing connection version is on desired version of current handshake + previousConnection, found := k.GetConnection(ctx, connectionID) + if found && !(previousConnection.State == exported.INIT && + previousConnection.Counterparty.ConnectionID == counterparty.ConnectionID && + bytes.Equal(previousConnection.Counterparty.Prefix.Bytes(), counterparty.Prefix.Bytes()) && + previousConnection.ClientID == clientID && + previousConnection.Counterparty.ClientID == counterparty.ClientID && + previousConnection.Versions[0] == version) { + return sdkerrors.Wrap(types.ErrInvalidConnection, "cannot relay connection attempt") + } + + // Set connection state to TRYOPEN and store in chainB state + connection.State = exported.TRYOPEN + if err := k.addConnectionToClient(ctx, clientID, connectionID); err != nil { + return sdkerrors.Wrap(err, "cannot relay connection attempt") + } + + k.SetConnection(ctx, connectionID, connection) + k.Logger(ctx).Info(fmt.Sprintf("connection %s state updated: NONE -> TRYOPEN ", connectionID)) + return nil +} + +// ConnOpenAck relays acceptance of a connection open attempt from chain B back +// to chain A (this code is executed on chain A). +// +// NOTE: Identifiers are checked on msg validation. +func (k Keeper) ConnOpenAck( + ctx sdk.Context, + connectionID string, + version string, // version that ChainB chose in ConnOpenTry + proofTry commitmentexported.Proof, // proof that connectionEnd was added to ChainB state in ConnOpenTry + proofConsensus commitmentexported.Proof, // proof that chainB has stored ConsensusState of chainA on its client + proofHeight uint64, // height that relayer constructed proofTry + consensusHeight uint64, // latest height of chainA that chainB has stored on its chainA client +) error { + // Check that chainB client hasn't stored invalid height + if consensusHeight > uint64(ctx.BlockHeight()) { + return sdkerrors.Wrap(ibctypes.ErrInvalidHeight, "invalid consensus height") + } + + // Retrieve connection + connection, found := k.GetConnection(ctx, connectionID) + if !found { + return sdkerrors.Wrap(types.ErrConnectionNotFound, "cannot relay ACK of open attempt") + } + + // Check connection on ChainA is on correct state: INIT + if connection.State != exported.INIT { + return sdkerrors.Wrapf( + types.ErrInvalidConnectionState, + "connection state is not INIT (got %s)", connection.State.String(), + ) + } + + // Check that ChainB's proposed version is one of chainA's accepted versions + if types.LatestVersion(connection.Versions) != version { + return sdkerrors.Wrapf( + ibctypes.ErrInvalidVersion, + "connection version does't match provided one (%s ≠ %s)", types.LatestVersion(connection.Versions), version, + ) + } + + // Retrieve chainA's consensus state at consensusheight + expectedConsensusState, found := k.clientKeeper.GetSelfConsensusState(ctx, consensusHeight) + if !found { + return clienttypes.ErrSelfConsensusStateNotFound + } + + prefix := k.GetCommitmentPrefix() + expectedCounterparty := types.NewCounterparty(connection.ClientID, connectionID, prefix) + expectedConnection := types.NewConnectionEnd(exported.TRYOPEN, connection.Counterparty.ClientID, expectedCounterparty, []string{version}) + + // Ensure that ChainB stored expected connectionEnd in its state during ConnOpenTry + if err := k.VerifyConnectionState( + ctx, connection, proofHeight, proofTry, connection.Counterparty.ConnectionID, + expectedConnection, + ); err != nil { + return err + } + + // Ensure that ChainB has stored the correct ConsensusState for chainA at the consensusHeight + if err := k.VerifyClientConsensusState( + ctx, connection, proofHeight, consensusHeight, proofConsensus, expectedConsensusState, + ); err != nil { + return err + } + + // Update connection state to Open + connection.State = exported.OPEN + connection.Versions = []string{version} + k.SetConnection(ctx, connectionID, connection) + k.Logger(ctx).Info(fmt.Sprintf("connection %s state updated: INIT -> OPEN ", connectionID)) + return nil +} + +// ConnOpenConfirm confirms opening of a connection on chain A to chain B, after +// which the connection is open on both chains (this code is executed on chain B). +// +// NOTE: Identifiers are checked on msg validation. +func (k Keeper) ConnOpenConfirm( + ctx sdk.Context, + connectionID string, + proofAck commitmentexported.Proof, // proof that connection opened on ChainA during ConnOpenAck + proofHeight uint64, // height that relayer constructed proofAck +) error { + // Retrieve connection + connection, found := k.GetConnection(ctx, connectionID) + if !found { + return sdkerrors.Wrap(types.ErrConnectionNotFound, "cannot relay ACK of open attempt") + } + + // Check that connection state on ChainB is on state: TRYOPEN + if connection.State != exported.TRYOPEN { + return sdkerrors.Wrapf( + types.ErrInvalidConnectionState, + "connection state is not TRYOPEN (got %s)", connection.State.String(), + ) + } + + prefix := k.GetCommitmentPrefix() + expectedCounterparty := types.NewCounterparty(connection.ClientID, connectionID, prefix) + expectedConnection := types.NewConnectionEnd(exported.OPEN, connection.Counterparty.ClientID, expectedCounterparty, connection.Versions) + + // Check that connection on ChainA is open + if err := k.VerifyConnectionState( + ctx, connection, proofHeight, proofAck, connection.Counterparty.ConnectionID, + expectedConnection, + ); err != nil { + return err + } + + // Update ChainB's connection to Open + connection.State = exported.OPEN + k.SetConnection(ctx, connectionID, connection) + k.Logger(ctx).Info(fmt.Sprintf("connection %s state updated: TRYOPEN -> OPEN ", connectionID)) + return nil +} diff --git a/x/ibc/03-connection/keeper/handshake_test.go b/x/ibc/03-connection/keeper/handshake_test.go new file mode 100644 index 000000000000..36a51389580d --- /dev/null +++ b/x/ibc/03-connection/keeper/handshake_test.go @@ -0,0 +1,286 @@ +package keeper_test + +import ( + "fmt" + + connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +// TestConnOpenInit - Chain A (ID #1) initializes (INIT state) a connection with +// Chain B (ID #2) which is yet UNINITIALIZED +func (suite *KeeperTestSuite) TestConnOpenInit() { + testCases := []struct { + msg string + malleate func() + expPass bool + }{ + {"success", func() { + suite.chainA.CreateClient(suite.chainB) + }, true}, + {"connection already exists", func() { + suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, exported.INIT) + }, false}, + {"couldn't add connection to client", func() {}, false}, + } + + counterparty := connection.NewCounterparty(testClientIDA, testConnectionIDB, suite.chainA.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix()) + + for i, tc := range testCases { + tc := tc + i := i + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + suite.SetupTest() // reset + + tc.malleate() + err := suite.chainA.App.IBCKeeper.ConnectionKeeper.ConnOpenInit(suite.chainA.GetContext(), testConnectionIDA, testClientIDB, counterparty) + + if tc.expPass { + suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg) + } else { + suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg) + } + }) + } +} + +// TestConnOpenTry - Chain B (ID #2) calls ConnOpenTry to verify the state of +// connection on Chain A (ID #1) is INIT +func (suite *KeeperTestSuite) TestConnOpenTry() { + // counterparty for A on B + counterparty := connection.NewCounterparty( + testClientIDB, testConnectionIDA, suite.chainB.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix(), + ) + + testCases := []struct { + msg string + malleate func() uint64 + expPass bool + }{ + {"success", func() uint64 { + suite.chainB.CreateClient(suite.chainA) + suite.chainA.CreateClient(suite.chainB) + suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, exported.INIT) + suite.chainB.updateClient(suite.chainA) + suite.chainA.updateClient(suite.chainB) + suite.chainB.updateClient(suite.chainA) + suite.chainA.updateClient(suite.chainB) + return uint64(suite.chainB.Header.Height - 1) + }, true}, + {"consensus height > latest height", func() uint64 { + return 0 + }, false}, + {"self consensus state not found", func() uint64 { + //suite.ctx = suite.ctx.WithBlockHeight(100) + return 100 + }, false}, + {"connection state verification invalid", func() uint64 { + suite.chainB.CreateClient(suite.chainA) + suite.chainA.CreateClient(suite.chainB) + suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, exported.UNINITIALIZED) + suite.chainB.updateClient(suite.chainA) + return 0 + }, false}, + {"consensus state verification invalid", func() uint64 { + suite.chainB.CreateClient(suite.chainA) + suite.chainA.CreateClient(suite.chainB) + suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, exported.INIT) + suite.chainB.updateClient(suite.chainA) + suite.chainA.updateClient(suite.chainB) + return uint64(suite.chainB.Header.Height) + }, false}, + {"invalid previous connection", func() uint64 { + suite.chainB.CreateClient(suite.chainA) + suite.chainA.CreateClient(suite.chainB) + suite.chainB.createConnection(testConnectionIDB, testConnectionIDA, testClientIDA, testClientIDB, exported.UNINITIALIZED) + suite.chainB.updateClient(suite.chainA) + suite.chainA.updateClient(suite.chainB) + return 0 + }, false}, + {"couldn't add connection to client", func() uint64 { + suite.chainB.CreateClient(suite.chainA) + suite.chainA.createConnection(testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, exported.UNINITIALIZED) + suite.chainB.updateClient(suite.chainA) + suite.chainA.updateClient(suite.chainB) + return 0 + }, false}, + } + + for i, tc := range testCases { + tc := tc + i := i + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + suite.SetupTest() // reset + + consensusHeight := tc.malleate() + + connectionKey := ibctypes.KeyConnection(testConnectionIDA) + proofInit, proofHeight := queryProof(suite.chainA, connectionKey) + + consensusKey := ibctypes.KeyConsensusState(testClientIDB, consensusHeight) + proofConsensus, _ := queryProof(suite.chainA, consensusKey) + + err := suite.chainB.App.IBCKeeper.ConnectionKeeper.ConnOpenTry( + suite.chainB.GetContext(), testConnectionIDB, counterparty, testClientIDA, + connection.GetCompatibleVersions(), proofInit, proofConsensus, + proofHeight+1, consensusHeight, + ) + + if tc.expPass { + suite.Require().NoError(err, "valid test case %d failed with consensus height %d and proof height %d: %s", i, consensusHeight, proofHeight, tc.msg) + } else { + suite.Require().Error(err, "invalid test case %d passed with consensus height %d and proof height %d: %s", i, consensusHeight, proofHeight, tc.msg) + } + }) + } +} + +// TestConnOpenAck - Chain A (ID #1) calls TestConnOpenAck to acknowledge (ACK state) +// the initialization (TRYINIT) of the connection on Chain B (ID #2). +func (suite *KeeperTestSuite) TestConnOpenAck() { + version := connection.GetCompatibleVersions()[0] + + testCases := []struct { + msg string + version string + malleate func() uint64 + expPass bool + }{ + {"success", version, func() uint64 { + suite.chainA.CreateClient(suite.chainB) + suite.chainB.CreateClient(suite.chainA) + suite.chainB.createConnection(testConnectionIDB, testConnectionIDA, testClientIDA, testClientIDB, exported.TRYOPEN) + suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, exported.INIT) + suite.chainB.updateClient(suite.chainA) + suite.chainA.updateClient(suite.chainB) + return uint64(suite.chainB.Header.Height) + }, true}, + {"consensus height > latest height", version, func() uint64 { + return 10 + }, false}, + {"connection not found", version, func() uint64 { + return 2 + }, false}, + {"connection state is not INIT", version, func() uint64 { + suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, exported.UNINITIALIZED) + suite.chainB.updateClient(suite.chainA) + return uint64(suite.chainB.Header.Height) + }, false}, + {"incompatible IBC versions", "2.0", func() uint64 { + suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, exported.INIT) + suite.chainB.updateClient(suite.chainA) + return uint64(suite.chainB.Header.Height) + }, false}, + {"self consensus state not found", version, func() uint64 { + suite.chainB.CreateClient(suite.chainA) + suite.chainA.CreateClient(suite.chainB) + suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, exported.INIT) + suite.chainB.createConnection(testConnectionIDB, testConnectionIDA, testClientIDA, testClientIDB, exported.TRYOPEN) + suite.chainB.updateClient(suite.chainA) + return uint64(suite.chainB.Header.Height) + }, false}, + {"connection state verification failed", version, func() uint64 { + suite.chainB.CreateClient(suite.chainA) + suite.chainA.CreateClient(suite.chainB) + suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, exported.INIT) + suite.chainB.createConnection(testConnectionIDB, testConnectionIDA, testClientIDA, testClientIDB, exported.UNINITIALIZED) + suite.chainB.updateClient(suite.chainA) + return uint64(suite.chainB.Header.Height) + }, false}, + {"consensus state verification failed", version, func() uint64 { + suite.chainB.CreateClient(suite.chainA) + suite.chainA.CreateClient(suite.chainB) + suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, exported.INIT) + suite.chainB.createConnection(testConnectionIDB, testConnectionIDA, testClientIDA, testClientIDB, exported.UNINITIALIZED) + suite.chainB.updateClient(suite.chainA) + return uint64(suite.chainB.Header.Height) + }, false}, + } + + for i, tc := range testCases { + tc := tc + i := i + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + suite.SetupTest() // reset + + consensusHeight := tc.malleate() + + connectionKey := ibctypes.KeyConnection(testConnectionIDB) + proofTry, proofHeight := queryProof(suite.chainB, connectionKey) + + consensusKey := ibctypes.KeyConsensusState(testClientIDA, consensusHeight) + proofConsensus, _ := queryProof(suite.chainB, consensusKey) + + err := suite.chainA.App.IBCKeeper.ConnectionKeeper.ConnOpenAck( + suite.chainA.GetContext(), testConnectionIDA, tc.version, proofTry, proofConsensus, + proofHeight+1, consensusHeight, + ) + + if tc.expPass { + suite.Require().NoError(err, "valid test case %d failed with consensus height %d: %s", i, consensusHeight, tc.msg) + } else { + suite.Require().Error(err, "invalid test case %d passed with consensus height %d: %s", i, consensusHeight, tc.msg) + } + }) + } +} + +// TestConnOpenConfirm - Chain B (ID #2) calls ConnOpenConfirm to confirm that +// Chain A (ID #1) state is now OPEN. +func (suite *KeeperTestSuite) TestConnOpenConfirm() { + testCases := []testCase{ + {"success", func() { + suite.chainB.CreateClient(suite.chainA) + suite.chainA.CreateClient(suite.chainB) + suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, exported.OPEN) + suite.chainB.createConnection(testConnectionIDB, testConnectionIDA, testClientIDA, testClientIDB, exported.TRYOPEN) + suite.chainB.updateClient(suite.chainA) + }, true}, + {"connection not found", func() {}, false}, + {"chain B's connection state is not TRYOPEN", func() { + suite.chainB.createConnection(testConnectionIDB, testConnectionIDA, testClientIDA, testClientIDB, exported.UNINITIALIZED) + suite.chainA.createConnection(testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, exported.OPEN) + suite.chainA.updateClient(suite.chainB) + }, false}, + {"connection state verification failed", func() { + suite.chainB.CreateClient(suite.chainA) + suite.chainA.CreateClient(suite.chainB) + suite.chainB.updateClient(suite.chainA) + suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, exported.INIT) + suite.chainB.createConnection(testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, exported.TRYOPEN) + suite.chainA.updateClient(suite.chainA) + }, false}, + } + + for i, tc := range testCases { + tc := tc + i := i + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + suite.SetupTest() // reset + + tc.malleate() + + connectionKey := ibctypes.KeyConnection(testConnectionIDA) + proofAck, proofHeight := queryProof(suite.chainA, connectionKey) + + if tc.expPass { + err := suite.chainB.App.IBCKeeper.ConnectionKeeper.ConnOpenConfirm( + suite.chainB.GetContext(), testConnectionIDB, proofAck, proofHeight+1, + ) + suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg) + } else { + err := suite.chainB.App.IBCKeeper.ConnectionKeeper.ConnOpenConfirm( + suite.chainB.GetContext(), testConnectionIDB, proofAck, proofHeight+1, + ) + suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg) + } + }) + } +} + +type testCase = struct { + msg string + malleate func() + expPass bool +} diff --git a/x/ibc/03-connection/keeper/keeper.go b/x/ibc/03-connection/keeper/keeper.go new file mode 100644 index 000000000000..9b2d5d7d48df --- /dev/null +++ b/x/ibc/03-connection/keeper/keeper.go @@ -0,0 +1,156 @@ +package keeper + +import ( + "fmt" + + "github.com/tendermint/tendermint/libs/log" + + "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" + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" + commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" + commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" + host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +// Keeper defines the IBC connection keeper +type Keeper struct { + storeKey sdk.StoreKey + cdc *codec.Codec + clientKeeper types.ClientKeeper +} + +// NewKeeper creates a new IBC connection Keeper instance +func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, ck types.ClientKeeper) Keeper { + return Keeper{ + storeKey: key, + cdc: cdc, + clientKeeper: ck, + } +} + +// Logger returns a module-specific logger. +func (k Keeper) Logger(ctx sdk.Context) log.Logger { + return ctx.Logger().With("module", fmt.Sprintf("x/%s/%s", ibctypes.ModuleName, types.SubModuleName)) +} + +// GetCommitmentPrefix returns the IBC connection store prefix as a commitment +// Prefix +func (k Keeper) GetCommitmentPrefix() commitmentexported.Prefix { + return commitmenttypes.NewMerklePrefix([]byte(k.storeKey.Name())) +} + +// GetConnection returns a connection with a particular identifier +func (k Keeper) GetConnection(ctx sdk.Context, connectionID string) (types.ConnectionEnd, bool) { + store := ctx.KVStore(k.storeKey) + bz := store.Get(ibctypes.KeyConnection(connectionID)) + if bz == nil { + return types.ConnectionEnd{}, false + } + + var connection types.ConnectionEnd + k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &connection) + return connection, true +} + +// SetConnection sets a connection to the store +func (k Keeper) SetConnection(ctx sdk.Context, connectionID string, connection types.ConnectionEnd) { + store := ctx.KVStore(k.storeKey) + bz := k.cdc.MustMarshalBinaryLengthPrefixed(connection) + store.Set(ibctypes.KeyConnection(connectionID), bz) +} + +// GetClientConnectionPaths returns all the connection paths stored under a +// particular client +func (k Keeper) GetClientConnectionPaths(ctx sdk.Context, clientID string) ([]string, bool) { + store := ctx.KVStore(k.storeKey) + bz := store.Get(ibctypes.KeyClientConnections(clientID)) + if bz == nil { + return nil, false + } + + var paths []string + k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &paths) + return paths, true +} + +// SetClientConnectionPaths sets the connections paths for client +func (k Keeper) SetClientConnectionPaths(ctx sdk.Context, clientID string, paths []string) { + store := ctx.KVStore(k.storeKey) + bz := k.cdc.MustMarshalBinaryLengthPrefixed(paths) + store.Set(ibctypes.KeyClientConnections(clientID), bz) +} + +// IterateConnections provides an iterator over all ConnectionEnd objects. +// For each ConnectionEnd, cb will be called. If the cb returns true, the +// iterator will close and stop. +func (k Keeper) IterateConnections(ctx sdk.Context, cb func(types.IdentifiedConnectionEnd) bool) { + store := ctx.KVStore(k.storeKey) + iterator := sdk.KVStorePrefixIterator(store, ibctypes.KeyConnectionPrefix) + + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + var connection types.ConnectionEnd + k.cdc.MustUnmarshalBinaryLengthPrefixed(iterator.Value(), &connection) + identifier := string(iterator.Key()[len(ibctypes.KeyConnectionPrefix)+1:]) + + conn := types.IdentifiedConnectionEnd{ + Connection: connection, + Identifier: identifier, + } + + if cb(conn) { + break + } + } +} + +// GetAllConnections returns all stored ConnectionEnd objects. +func (k Keeper) GetAllConnections(ctx sdk.Context) (connections []types.IdentifiedConnectionEnd) { + k.IterateConnections(ctx, func(connection types.IdentifiedConnectionEnd) bool { + connections = append(connections, connection) + return false + }) + return connections +} + +// addConnectionToClient is used to add a connection identifier to the set of +// connections associated with a client. +func (k Keeper) addConnectionToClient(ctx sdk.Context, clientID, connectionID string) error { + _, found := k.clientKeeper.GetClientState(ctx, clientID) + if !found { + return clienttypes.ErrClientNotFound + } + + conns, found := k.GetClientConnectionPaths(ctx, clientID) + if !found { + conns = []string{} + } + + conns = append(conns, connectionID) + k.SetClientConnectionPaths(ctx, clientID, conns) + return nil +} + +// removeConnectionFromClient is used to remove a connection identifier from the +// set of connections associated with a client. +// +// CONTRACT: client must already exist +// nolint: unused +func (k Keeper) removeConnectionFromClient(ctx sdk.Context, clientID, connectionID string) error { + conns, found := k.GetClientConnectionPaths(ctx, clientID) + if !found { + return sdkerrors.Wrap(types.ErrClientConnectionPathsNotFound, clientID) + } + + conns, ok := host.RemovePath(conns, connectionID) + if !ok { + return sdkerrors.Wrap(types.ErrConnectionPath, clientID) + } + + k.SetClientConnectionPaths(ctx, clientID, conns) + return nil +} diff --git a/x/ibc/03-connection/keeper/keeper_test.go b/x/ibc/03-connection/keeper/keeper_test.go new file mode 100644 index 000000000000..0317e107d7be --- /dev/null +++ b/x/ibc/03-connection/keeper/keeper_test.go @@ -0,0 +1,318 @@ +package keeper_test + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/suite" + abci "github.com/tendermint/tendermint/abci/types" + tmtypes "github.com/tendermint/tendermint/types" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/simapp" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported" + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" + channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" + commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" + "github.com/cosmos/cosmos-sdk/x/staking" +) + +const ( + storeKey = ibctypes.StoreKey + + testClientIDA = "testclientida" // chainid for chainA also chainB's clientID for A's liteclient + testConnectionIDA = "connectionidatob" + + testClientIDB = "testclientidb" // chainid for chainB also chainA's clientID for B's liteclient + testConnectionIDB = "connectionidbtoa" + + testClientID3 = "testclientidthree" + testConnectionID3 = "connectionidthree" + + trustingPeriod time.Duration = time.Hour * 24 * 7 * 2 + ubdPeriod time.Duration = time.Hour * 24 * 7 * 3 +) + +type KeeperTestSuite struct { + suite.Suite + + cdc *codec.Codec + + // ChainA testing fields + chainA *TestChain + + // ChainB testing fields + chainB *TestChain +} + +func (suite *KeeperTestSuite) SetupTest() { + suite.chainA = NewTestChain(testClientIDA) + suite.chainB = NewTestChain(testClientIDB) + + suite.cdc = suite.chainA.App.Codec() +} + +// nolint: unused +func queryProof(chain *TestChain, key []byte) (commitmenttypes.MerkleProof, uint64) { + res := chain.App.Query(abci.RequestQuery{ + Path: fmt.Sprintf("store/%s/key", storeKey), + Height: chain.App.LastBlockHeight(), + Data: key, + Prove: true, + }) + + proof := commitmenttypes.MerkleProof{ + Proof: res.Proof, + } + + return proof, uint64(res.Height) +} +func TestKeeperTestSuite(t *testing.T) { + suite.Run(t, new(KeeperTestSuite)) +} + +func (suite *KeeperTestSuite) TestSetAndGetConnection() { + _, existed := suite.chainA.App.IBCKeeper.ConnectionKeeper.GetConnection(suite.chainA.GetContext(), testConnectionIDA) + suite.Require().False(existed) + + counterparty := types.NewCounterparty(testClientIDA, testConnectionIDA, suite.chainA.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix()) + expConn := types.NewConnectionEnd(exported.INIT, testClientIDB, counterparty, types.GetCompatibleVersions()) + suite.chainA.App.IBCKeeper.ConnectionKeeper.SetConnection(suite.chainA.GetContext(), testConnectionIDA, expConn) + conn, existed := suite.chainA.App.IBCKeeper.ConnectionKeeper.GetConnection(suite.chainA.GetContext(), testConnectionIDA) + suite.Require().True(existed) + suite.Require().EqualValues(expConn, conn) +} + +func (suite *KeeperTestSuite) TestSetAndGetClientConnectionPaths() { + _, existed := suite.chainA.App.IBCKeeper.ConnectionKeeper.GetClientConnectionPaths(suite.chainA.GetContext(), testClientIDA) + suite.False(existed) + + suite.chainA.App.IBCKeeper.ConnectionKeeper.SetClientConnectionPaths(suite.chainA.GetContext(), testClientIDB, types.GetCompatibleVersions()) + paths, existed := suite.chainA.App.IBCKeeper.ConnectionKeeper.GetClientConnectionPaths(suite.chainA.GetContext(), testClientIDB) + suite.True(existed) + suite.EqualValues(types.GetCompatibleVersions(), paths) +} + +func (suite KeeperTestSuite) TestGetAllConnections() { + // Connection (Counterparty): A(C) -> C(B) -> B(A) + counterparty1 := types.NewCounterparty(testClientIDA, testConnectionIDA, suite.chainA.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix()) + counterparty2 := types.NewCounterparty(testClientIDB, testConnectionIDB, suite.chainA.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix()) + counterparty3 := types.NewCounterparty(testClientID3, testConnectionID3, suite.chainA.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix()) + + conn1 := types.NewConnectionEnd(exported.INIT, testClientIDA, counterparty3, types.GetCompatibleVersions()) + conn2 := types.NewConnectionEnd(exported.INIT, testClientIDB, counterparty1, types.GetCompatibleVersions()) + conn3 := types.NewConnectionEnd(exported.UNINITIALIZED, testClientID3, counterparty2, types.GetCompatibleVersions()) + + expConnections := []types.IdentifiedConnectionEnd{ + {Connection: conn1, Identifier: testConnectionIDA}, + {Connection: conn2, Identifier: testConnectionIDB}, + {Connection: conn3, Identifier: testConnectionID3}, + } + + suite.chainA.App.IBCKeeper.ConnectionKeeper.SetConnection(suite.chainA.GetContext(), testConnectionIDA, conn1) + suite.chainA.App.IBCKeeper.ConnectionKeeper.SetConnection(suite.chainA.GetContext(), testConnectionIDB, conn2) + suite.chainA.App.IBCKeeper.ConnectionKeeper.SetConnection(suite.chainA.GetContext(), testConnectionID3, conn3) + + connections := suite.chainA.App.IBCKeeper.ConnectionKeeper.GetAllConnections(suite.chainA.GetContext()) + suite.Require().Len(connections, len(expConnections)) + suite.Require().ElementsMatch(expConnections, connections) +} + +// TestChain is a testing struct that wraps a simapp with the latest Header, Vals and Signers +// It also contains a field called ClientID. This is the clientID that *other* chains use +// to refer to this TestChain. For simplicity's sake it is also the chainID on the TestChain Header +type TestChain struct { + ClientID string + App *simapp.SimApp + Header ibctmtypes.Header + Vals *tmtypes.ValidatorSet + Signers []tmtypes.PrivValidator +} + +func NewTestChain(clientID string) *TestChain { + privVal := tmtypes.NewMockPV() + validator := tmtypes.NewValidator(privVal.GetPubKey(), 1) + valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator}) + signers := []tmtypes.PrivValidator{privVal} + now := time.Now() + + header := ibctmtypes.CreateTestHeader(clientID, 1, now, valSet, signers) + + return &TestChain{ + ClientID: clientID, + App: simapp.Setup(false), + Header: header, + Vals: valSet, + Signers: signers, + } +} + +// Creates simple context for testing purposes +func (chain *TestChain) GetContext() sdk.Context { + return chain.App.BaseApp.NewContext(false, abci.Header{ChainID: chain.Header.ChainID, Height: chain.Header.Height}) +} + +// createClient will create a client for clientChain on targetChain +func (chain *TestChain) CreateClient(client *TestChain) error { + client.Header = nextHeader(client) + // Commit and create a new block on appTarget to get a fresh CommitID + client.App.Commit() + commitID := client.App.LastCommitID() + client.App.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: client.Header.Height, Time: client.Header.Time}}) + + // Set HistoricalInfo on client chain after Commit + ctxClient := client.GetContext() + validator := staking.NewValidator( + sdk.ValAddress(client.Vals.Validators[0].Address), client.Vals.Validators[0].PubKey, staking.Description{}, + ) + validator.Status = sdk.Bonded + validator.Tokens = sdk.NewInt(1000000) // get one voting power + validators := []staking.Validator{validator} + histInfo := staking.HistoricalInfo{ + Header: abci.Header{ + Time: client.Header.Time, + AppHash: commitID.Hash, + }, + Valset: validators, + } + client.App.StakingKeeper.SetHistoricalInfo(ctxClient, client.Header.Height, histInfo) + + // also set staking params + stakingParams := staking.DefaultParams() + stakingParams.HistoricalEntries = 10 + client.App.StakingKeeper.SetParams(ctxClient, stakingParams) + + // Create target ctx + ctxTarget := chain.GetContext() + + // create client + clientState, err := ibctmtypes.Initialize(client.ClientID, trustingPeriod, ubdPeriod, client.Header) + if err != nil { + return err + } + _, err = chain.App.IBCKeeper.ClientKeeper.CreateClient(ctxTarget, clientState, client.Header.ConsensusState()) + if err != nil { + return err + } + return nil + + // _, _, err := simapp.SignCheckDeliver( + // suite.T(), + // suite.cdc, + // suite.app.BaseApp, + // suite.ctx.BlockHeader(), + // []sdk.Msg{clienttypes.NewMsgCreateClient(clientID, clientexported.ClientTypeTendermint, consState, accountAddress)}, + // []uint64{baseAccount.GetAccountNumber()}, + // []uint64{baseAccount.GetSequence()}, + // true, true, accountPrivKey, + // ) +} + +func (chain *TestChain) updateClient(client *TestChain) { + // Create chain ctx + ctxTarget := chain.GetContext() + + // if clientState does not already exist, return without updating + _, found := chain.App.IBCKeeper.ClientKeeper.GetClientState( + ctxTarget, client.ClientID, + ) + if !found { + return + } + + // always commit when updateClient and begin a new block + client.App.Commit() + commitID := client.App.LastCommitID() + client.Header = nextHeader(client) + + /* + err := chain.App.IBCKeeper.ClientKeeper.UpdateClient(ctxTarget, client.ClientID, client.Header) + if err != nil { + panic(err) + } + */ + + client.App.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: client.Header.Height, Time: client.Header.Time}}) + + // Set HistoricalInfo on client chain after Commit + ctxClient := client.GetContext() + validator := staking.NewValidator( + sdk.ValAddress(client.Vals.Validators[0].Address), client.Vals.Validators[0].PubKey, staking.Description{}, + ) + validator.Status = sdk.Bonded + validator.Tokens = sdk.NewInt(1000000) + validators := []staking.Validator{validator} + histInfo := staking.HistoricalInfo{ + Header: abci.Header{ + Time: client.Header.Time, + AppHash: commitID.Hash, + }, + Valset: validators, + } + client.App.StakingKeeper.SetHistoricalInfo(ctxClient, client.Header.Height, histInfo) + + consensusState := ibctmtypes.ConsensusState{ + Height: uint64(client.Header.Height), + Timestamp: client.Header.Time, + Root: commitmenttypes.NewMerkleRoot(commitID.Hash), + ValidatorSet: client.Vals, + } + + chain.App.IBCKeeper.ClientKeeper.SetClientConsensusState( + ctxTarget, client.ClientID, uint64(client.Header.Height), consensusState, + ) + chain.App.IBCKeeper.ClientKeeper.SetClientState( + ctxTarget, ibctmtypes.NewClientState(client.ClientID, trustingPeriod, ubdPeriod, client.Header), + ) + + // _, _, err := simapp.SignCheckDeliver( + // suite.T(), + // suite.cdc, + // suite.app.BaseApp, + // suite.ctx.BlockHeader(), + // []sdk.Msg{clienttypes.NewMsgUpdateClient(clientID, suite.header, accountAddress)}, + // []uint64{baseAccount.GetAccountNumber()}, + // []uint64{baseAccount.GetSequence()}, + // true, true, accountPrivKey, + // ) + // suite.Require().NoError(err) +} + +func (chain *TestChain) createConnection( + connID, counterpartyConnID, clientID, counterpartyClientID string, + state exported.State, +) types.ConnectionEnd { + counterparty := types.NewCounterparty(counterpartyClientID, counterpartyConnID, chain.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix()) + connection := types.ConnectionEnd{ + State: state, + ClientID: clientID, + Counterparty: counterparty, + Versions: types.GetCompatibleVersions(), + } + ctx := chain.GetContext() + chain.App.IBCKeeper.ConnectionKeeper.SetConnection(ctx, connID, connection) + return connection +} + +func (chain *TestChain) createChannel( + portID, channelID, counterpartyPortID, counterpartyChannelID string, + state channelexported.State, order channelexported.Order, connectionID string, +) channeltypes.Channel { + counterparty := channeltypes.NewCounterparty(counterpartyPortID, counterpartyChannelID) + channel := channeltypes.NewChannel(state, order, counterparty, + []string{connectionID}, "1.0", + ) + ctx := chain.GetContext() + chain.App.IBCKeeper.ChannelKeeper.SetChannel(ctx, portID, channelID, channel) + return channel +} + +func nextHeader(chain *TestChain) ibctmtypes.Header { + return ibctmtypes.CreateTestHeader(chain.Header.ChainID, chain.Header.Height+1, + time.Now(), chain.Vals, chain.Signers) +} diff --git a/x/ibc/03-connection/keeper/querier.go b/x/ibc/03-connection/keeper/querier.go new file mode 100644 index 000000000000..1eebee214bd5 --- /dev/null +++ b/x/ibc/03-connection/keeper/querier.go @@ -0,0 +1,57 @@ +package keeper + +import ( + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" +) + +// QuerierConnections defines the sdk.Querier to query all the connections. +func QuerierConnections(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { + var params types.QueryAllConnectionsParams + + if err := k.cdc.UnmarshalJSON(req.Data, ¶ms); err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) + } + + connections := k.GetAllConnections(ctx) + + start, end := client.Paginate(len(connections), params.Page, params.Limit, 100) + if start < 0 || end < 0 { + connections = []types.IdentifiedConnectionEnd{} + } else { + connections = connections[start:end] + } + + res, err := codec.MarshalJSONIndent(k.cdc, connections) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) + } + + return res, nil +} + +// QuerierClientConnections defines the sdk.Querier to query the client connections +func QuerierClientConnections(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { + var params types.QueryClientConnectionsParams + + if err := k.cdc.UnmarshalJSON(req.Data, ¶ms); err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) + } + + clientConnectionPaths, found := k.GetClientConnectionPaths(ctx, params.ClientID) + if !found { + return nil, sdkerrors.Wrap(types.ErrClientConnectionPathsNotFound, params.ClientID) + } + + bz, err := types.SubModuleCdc.MarshalJSON(clientConnectionPaths) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) + } + + return bz, nil +} diff --git a/x/ibc/03-connection/keeper/verify.go b/x/ibc/03-connection/keeper/verify.go new file mode 100644 index 000000000000..699ef5db15d6 --- /dev/null +++ b/x/ibc/03-connection/keeper/verify.go @@ -0,0 +1,236 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported" + channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" +) + +// VerifyClientConsensusState verifies a proof of the consensus state of the +// specified client stored on the target machine. +func (k Keeper) VerifyClientConsensusState( + ctx sdk.Context, + connection exported.ConnectionI, + height uint64, + consensusHeight uint64, + proof commitmentexported.Proof, + consensusState clientexported.ConsensusState, +) error { + clientID := connection.GetClientID() + clientState, found := k.clientKeeper.GetClientState(ctx, clientID) + if !found { + return sdkerrors.Wrap(clienttypes.ErrClientNotFound, clientID) + } + + targetConsState, found := k.clientKeeper.GetClientConsensusState(ctx, clientID, height) + if !found { + return sdkerrors.Wrapf(clienttypes.ErrConsensusStateNotFound, "clientID: %s with height: %d", clientID, height) + } + + return clientState.VerifyClientConsensusState( + k.cdc, targetConsState.GetRoot(), height, connection.GetCounterparty().GetClientID(), consensusHeight, connection.GetCounterparty().GetPrefix(), proof, consensusState, + ) +} + +// VerifyConnectionState verifies a proof of the connection state of the +// specified connection end stored on the target machine. +func (k Keeper) VerifyConnectionState( + ctx sdk.Context, + connection exported.ConnectionI, + height uint64, + proof commitmentexported.Proof, + connectionID string, + connectionEnd exported.ConnectionI, // opposite connection +) error { + clientState, found := k.clientKeeper.GetClientState(ctx, connection.GetClientID()) + if !found { + return sdkerrors.Wrap(clienttypes.ErrClientNotFound, connection.GetClientID()) + } + + // TODO: move to specific clients; blocked by #5502 + consensusState, found := k.clientKeeper.GetClientConsensusState( + ctx, connection.GetClientID(), height, + ) + if !found { + return sdkerrors.Wrapf( + clienttypes.ErrConsensusStateNotFound, + "clientID (%s), height (%d)", connection.GetClientID(), height, + ) + } + + return clientState.VerifyConnectionState( + k.cdc, height, connection.GetCounterparty().GetPrefix(), proof, connectionID, connectionEnd, consensusState, + ) +} + +// VerifyChannelState verifies a proof of the channel state of the specified +// channel end, under the specified port, stored on the target machine. +func (k Keeper) VerifyChannelState( + ctx sdk.Context, + connection exported.ConnectionI, + height uint64, + proof commitmentexported.Proof, + portID, + channelID string, + channel channelexported.ChannelI, +) error { + clientState, found := k.clientKeeper.GetClientState(ctx, connection.GetClientID()) + if !found { + return sdkerrors.Wrap(clienttypes.ErrClientNotFound, connection.GetClientID()) + } + + // TODO: move to specific clients; blocked by #5502 + consensusState, found := k.clientKeeper.GetClientConsensusState( + ctx, connection.GetClientID(), height, + ) + if !found { + return sdkerrors.Wrapf( + clienttypes.ErrConsensusStateNotFound, + "clientID (%s), height (%d)", connection.GetClientID(), height, + ) + } + + return clientState.VerifyChannelState( + k.cdc, height, connection.GetCounterparty().GetPrefix(), proof, + portID, channelID, channel, consensusState, + ) +} + +// VerifyPacketCommitment verifies a proof of an outgoing packet commitment at +// the specified port, specified channel, and specified sequence. +func (k Keeper) VerifyPacketCommitment( + ctx sdk.Context, + connection exported.ConnectionI, + height uint64, + proof commitmentexported.Proof, + portID, + channelID string, + sequence uint64, + commitmentBytes []byte, +) error { + clientState, found := k.clientKeeper.GetClientState(ctx, connection.GetClientID()) + if !found { + return sdkerrors.Wrap(clienttypes.ErrClientNotFound, connection.GetClientID()) + } + + // TODO: move to specific clients; blocked by #5502 + consensusState, found := k.clientKeeper.GetClientConsensusState( + ctx, connection.GetClientID(), height, + ) + if !found { + return sdkerrors.Wrapf( + clienttypes.ErrConsensusStateNotFound, + "clientID (%s), height (%d)", connection.GetClientID(), height, + ) + } + + return clientState.VerifyPacketCommitment( + height, connection.GetCounterparty().GetPrefix(), proof, portID, channelID, + sequence, commitmentBytes, consensusState, + ) +} + +// VerifyPacketAcknowledgement verifies a proof of an incoming packet +// acknowledgement at the specified port, specified channel, and specified sequence. +func (k Keeper) VerifyPacketAcknowledgement( + ctx sdk.Context, + connection exported.ConnectionI, + height uint64, + proof commitmentexported.Proof, + portID, + channelID string, + sequence uint64, + acknowledgement []byte, +) error { + clientState, found := k.clientKeeper.GetClientState(ctx, connection.GetClientID()) + if !found { + return sdkerrors.Wrap(clienttypes.ErrClientNotFound, connection.GetClientID()) + } + + // TODO: move to specific clients; blocked by #5502 + consensusState, found := k.clientKeeper.GetClientConsensusState( + ctx, connection.GetClientID(), height, + ) + if !found { + return sdkerrors.Wrapf( + clienttypes.ErrConsensusStateNotFound, + "clientID (%s), height (%d)", connection.GetClientID(), height, + ) + } + + return clientState.VerifyPacketAcknowledgement( + height, connection.GetCounterparty().GetPrefix(), proof, portID, channelID, + sequence, acknowledgement, consensusState, + ) +} + +// VerifyPacketAcknowledgementAbsence verifies a proof of the absence of an +// incoming packet acknowledgement at the specified port, specified channel, and +// specified sequence. +func (k Keeper) VerifyPacketAcknowledgementAbsence( + ctx sdk.Context, + connection exported.ConnectionI, + height uint64, + proof commitmentexported.Proof, + portID, + channelID string, + sequence uint64, +) error { + clientState, found := k.clientKeeper.GetClientState(ctx, connection.GetClientID()) + if !found { + return sdkerrors.Wrap(clienttypes.ErrClientNotFound, connection.GetClientID()) + } + + // TODO: move to specific clients; blocked by #5502 + consensusState, found := k.clientKeeper.GetClientConsensusState( + ctx, connection.GetClientID(), height, + ) + if !found { + return sdkerrors.Wrapf( + clienttypes.ErrConsensusStateNotFound, + "clientID (%s), height (%d)", connection.GetClientID(), height, + ) + } + + return clientState.VerifyPacketAcknowledgementAbsence( + height, connection.GetCounterparty().GetPrefix(), proof, portID, channelID, + sequence, consensusState, + ) +} + +// VerifyNextSequenceRecv verifies a proof of the next sequence number to be +// received of the specified channel at the specified port. +func (k Keeper) VerifyNextSequenceRecv( + ctx sdk.Context, + connection exported.ConnectionI, + height uint64, + proof commitmentexported.Proof, + portID, + channelID string, + nextSequenceRecv uint64, +) error { + clientState, found := k.clientKeeper.GetClientState(ctx, connection.GetClientID()) + if !found { + return sdkerrors.Wrap(clienttypes.ErrClientNotFound, connection.GetClientID()) + } + + // TODO: move to specific clients; blocked by #5502 + consensusState, found := k.clientKeeper.GetClientConsensusState( + ctx, connection.GetClientID(), height, + ) + if !found { + return sdkerrors.Wrapf( + clienttypes.ErrConsensusStateNotFound, + "clientID (%s), height (%d)", connection.GetClientID(), height, + ) + } + + return clientState.VerifyNextSequenceRecv( + height, connection.GetCounterparty().GetPrefix(), proof, portID, channelID, + nextSequenceRecv, consensusState, + ) +} diff --git a/x/ibc/03-connection/keeper/verify_test.go b/x/ibc/03-connection/keeper/verify_test.go new file mode 100644 index 000000000000..152999348001 --- /dev/null +++ b/x/ibc/03-connection/keeper/verify_test.go @@ -0,0 +1,427 @@ +package keeper_test + +import ( + "fmt" + + clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported" + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" + channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +const ( + testPort1 = "firstport" + testPort2 = "secondport" + + testChannel1 = "firstchannel" + testChannel2 = "secondchannel" +) + +func (suite *KeeperTestSuite) TestVerifyClientConsensusState() { + // create connection on chainA to chainB + counterparty := types.NewCounterparty( + testClientIDA, testConnectionIDA, + suite.chainA.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix(), + ) + connection1 := types.NewConnectionEnd( + exported.UNINITIALIZED, testClientIDB, counterparty, + types.GetCompatibleVersions(), + ) + + cases := []struct { + msg string + connection types.ConnectionEnd + malleate func() clientexported.ConsensusState + expPass bool + }{ + {"verification success", connection1, func() clientexported.ConsensusState { + suite.chainA.CreateClient(suite.chainB) + suite.chainB.CreateClient(suite.chainA) + consState := suite.chainA.Header.ConsensusState() + return consState + }, true}, + {"client state not found", connection1, func() clientexported.ConsensusState { + return suite.chainB.Header.ConsensusState() + }, false}, + {"verification failed", connection1, func() clientexported.ConsensusState { + suite.chainA.CreateClient(suite.chainA) + return suite.chainA.Header.ConsensusState() + }, false}, + } + + // Create Client of chain B on Chain App + // Check that we can verify B's consensus state on chain A + for i, tc := range cases { + tc := tc + i := i + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + suite.SetupTest() // reset + + consState := tc.malleate() + + // perform a couple updates of chain B on chain A + suite.chainA.updateClient(suite.chainB) + suite.chainA.updateClient(suite.chainB) + + // TODO: is this the right consensus height + consensusHeight := uint64(suite.chainA.Header.Height) + consensusKey := ibctypes.KeyConsensusState(testClientIDA, consensusHeight) + + // get proof that chainB stored chainA' consensus state + proof, proofHeight := queryProof(suite.chainB, consensusKey) + + err := suite.chainA.App.IBCKeeper.ConnectionKeeper.VerifyClientConsensusState( + suite.chainA.GetContext(), tc.connection, proofHeight+1, consensusHeight, proof, consState, + ) + + if tc.expPass { + suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg) + } else { + suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg) + } + }) + } +} + +func (suite *KeeperTestSuite) TestVerifyConnectionState() { + connectionKey := ibctypes.KeyConnection(testConnectionIDA) + var invalidProofHeight uint64 + cases := []struct { + msg string + malleate func() + expPass bool + }{ + {"verification success", func() { + suite.chainA.CreateClient(suite.chainB) + suite.chainB.CreateClient(suite.chainA) + invalidProofHeight = 0 // don't use this + }, true}, + {"client state not found", func() {}, false}, + {"verification failed", func() { + suite.chainA.CreateClient(suite.chainB) + suite.chainB.CreateClient(suite.chainA) + invalidProofHeight = 10 // make proofHeight incorrect + }, false}, + } + + // Chains A and B create clients for each other + // A creates connectionEnd for chain B and stores it in state + // Check that B can verify connection is stored after some updates + for i, tc := range cases { + tc := tc + i := i + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + suite.SetupTest() // reset + + tc.malleate() + + // create and store connection on chain A + expectedConnection := suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, exported.OPEN) + + // // create expected connection + // TODO: why is this commented + // expectedConnection := types.NewConnectionEnd(exported.INIT, testClientIDB, counterparty, []string{"1.0.0"}) + + // perform a couple updates of chain A on chain B + suite.chainB.updateClient(suite.chainA) + suite.chainB.updateClient(suite.chainA) + proof, proofHeight := queryProof(suite.chainA, connectionKey) + // if invalidProofHeight has been set, use that value instead + if invalidProofHeight != 0 { + proofHeight = invalidProofHeight + } + + // Create B's connection to A + counterparty := types.NewCounterparty(testClientIDB, testConnectionIDA, commitmenttypes.NewMerklePrefix([]byte("ibc"))) + connection := types.NewConnectionEnd(exported.UNINITIALIZED, testClientIDA, counterparty, []string{"1.0.0"}) + // Ensure chain B can verify connection exists in chain A + err := suite.chainB.App.IBCKeeper.ConnectionKeeper.VerifyConnectionState( + suite.chainB.GetContext(), connection, proofHeight+1, proof, testConnectionIDA, expectedConnection, + ) + + if tc.expPass { + suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg) + } else { + suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg) + } + }) + } +} + +func (suite *KeeperTestSuite) TestVerifyChannelState() { + channelKey := ibctypes.KeyChannel(testPort1, testChannel1) + + // create connection of chainB to pass into verify function + counterparty := types.NewCounterparty( + testClientIDB, testConnectionIDB, + suite.chainA.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix(), + ) + + connection := types.NewConnectionEnd( + exported.UNINITIALIZED, testClientIDA, counterparty, + types.GetCompatibleVersions(), + ) + + cases := []struct { + msg string + proofHeight uint64 + malleate func() + expPass bool + }{ + {"verification success", 0, func() { + suite.chainB.CreateClient(suite.chainA) + }, true}, + {"client state not found", 0, func() {}, false}, + {"consensus state not found", 100, func() { + suite.chainB.CreateClient(suite.chainA) + }, false}, + {"verification failed", 7, func() { + suite.chainB.CreateClient(suite.chainB) + }, false}, + } + + // Chain A creates channel for chain B and stores in its state + // Check that chainB can verify channel is stored in chain A + for i, tc := range cases { + tc := tc + i := i + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + suite.SetupTest() // reset + + tc.malleate() + // Create and store channel on chain A + channel := suite.chainA.createChannel( + testPort1, testChannel1, testPort2, testChannel2, + channelexported.OPEN, channelexported.ORDERED, testConnectionIDA, + ) + + // Update chainA client on chainB + suite.chainB.updateClient(suite.chainA) + + // Check that Chain B can verify channel is stored on chainA + proof, proofHeight := queryProof(suite.chainA, channelKey) + // if testcase proofHeight is not 0, replace proofHeight with this value + if tc.proofHeight != 0 { + proofHeight = tc.proofHeight + } + + err := suite.chainB.App.IBCKeeper.ConnectionKeeper.VerifyChannelState( + suite.chainB.GetContext(), connection, proofHeight+1, proof, testPort1, + testChannel1, channel, + ) + + if tc.expPass { + suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg) + } else { + suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg) + } + }) + } +} + +func (suite *KeeperTestSuite) TestVerifyPacketCommitment() { + commitmentKey := ibctypes.KeyPacketCommitment(testPort1, testChannel1, 1) + commitmentBz := []byte("commitment") + + cases := []struct { + msg string + proofHeight uint64 + malleate func() + expPass bool + }{ + {"verification success", 0, func() { + suite.chainB.CreateClient(suite.chainA) + }, true}, + {"client state not found", 0, func() {}, false}, + {"consensus state not found", 100, func() { + suite.chainB.CreateClient(suite.chainA) + }, false}, + } + + // ChainA sets packet commitment on channel with chainB in its state + // Check that ChainB can verify the PacketCommitment + for i, tc := range cases { + tc := tc + i := i + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + suite.SetupTest() // reset + + tc.malleate() + + // Set PacketCommitment on chainA + connection := suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, exported.OPEN) + suite.chainA.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainA.GetContext(), testPort1, testChannel1, 1, commitmentBz) + + // Update ChainA client on chainB + suite.chainB.updateClient(suite.chainA) + + // Check that ChainB can verify PacketCommitment stored in chainA + proof, proofHeight := queryProof(suite.chainA, commitmentKey) + // if testcase proofHeight is not 0, replace proofHeight with this value + if tc.proofHeight != 0 { + proofHeight = tc.proofHeight + } + + err := suite.chainB.App.IBCKeeper.ConnectionKeeper.VerifyPacketCommitment( + suite.chainB.GetContext(), connection, proofHeight+1, proof, testPort1, + testChannel1, 1, commitmentBz, + ) + + if tc.expPass { + suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg) + } else { + suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg) + } + }) + } +} + +func (suite *KeeperTestSuite) TestVerifyPacketAcknowledgement() { + packetAckKey := ibctypes.KeyPacketAcknowledgement(testPort1, testChannel1, 1) + ack := []byte("acknowledgement") + + cases := []struct { + msg string + proofHeight uint64 + malleate func() + expPass bool + }{ + {"verification success", 0, func() { + suite.chainB.CreateClient(suite.chainA) + }, true}, + {"client state not found", 0, func() {}, false}, + {"consensus state not found", 100, func() { + suite.chainB.CreateClient(suite.chainA) + }, false}, + } + + for i, tc := range cases { + tc := tc + i := i + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + suite.SetupTest() // reset + + tc.malleate() + connection := suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, exported.OPEN) + suite.chainA.App.IBCKeeper.ChannelKeeper.SetPacketAcknowledgement(suite.chainA.GetContext(), testPort1, testChannel1, 1, ack) + suite.chainB.updateClient(suite.chainA) + + // TODO check this proof height + proof, proofHeight := queryProof(suite.chainA, packetAckKey) + // if testcase proofHeight is not 0, replace proofHeight with this value + if tc.proofHeight != 0 { + proofHeight = tc.proofHeight + } + + err := suite.chainB.App.IBCKeeper.ConnectionKeeper.VerifyPacketAcknowledgement( + suite.chainB.GetContext(), connection, proofHeight+1, proof, testPort1, + testChannel1, 1, ack, + ) + + if tc.expPass { + suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg) + } else { + suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg) + } + }) + } +} + +func (suite *KeeperTestSuite) TestVerifyPacketAcknowledgementAbsence() { + packetAckKey := ibctypes.KeyPacketAcknowledgement(testPort1, testChannel1, 1) + + cases := []struct { + msg string + proofHeight uint64 + malleate func() + expPass bool + }{ + {"verification success", 0, func() { + suite.chainB.CreateClient(suite.chainA) + }, true}, + {"client state not found", 0, func() {}, false}, + {"consensus state not found", 100, func() { + suite.chainB.CreateClient(suite.chainA) + }, false}, + } + + for i, tc := range cases { + tc := tc + i := i + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + suite.SetupTest() // reset + + tc.malleate() + connection := suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, exported.OPEN) + suite.chainB.updateClient(suite.chainA) + + proof, proofHeight := queryProof(suite.chainA, packetAckKey) + // if testcase proofHeight is not 0, replace proofHeight with this value + if tc.proofHeight != 0 { + proofHeight = tc.proofHeight + } + + err := suite.chainB.App.IBCKeeper.ConnectionKeeper.VerifyPacketAcknowledgementAbsence( + suite.chainB.GetContext(), connection, proofHeight+1, proof, testPort1, + testChannel1, 1, + ) + + if tc.expPass { + suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg) + } else { + suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg) + } + }) + } +} + +func (suite *KeeperTestSuite) TestVerifyNextSequenceRecv() { + nextSeqRcvKey := ibctypes.KeyNextSequenceRecv(testPort1, testChannel1) + + cases := []struct { + msg string + proofHeight uint64 + malleate func() + expPass bool + }{ + {"verification success", uint64(0), func() { + suite.chainB.CreateClient(suite.chainA) + }, true}, + {"client state not found", uint64(0), func() {}, false}, + {"consensus state not found", uint64(100), func() { + suite.chainB.CreateClient(suite.chainA) + }, false}, + } + + for i, tc := range cases { + tc := tc + i := i + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + suite.SetupTest() // reset + + tc.malleate() + connection := suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, exported.OPEN) + suite.chainA.App.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(suite.chainA.GetContext(), testPort1, testChannel1, 1) + suite.chainB.updateClient(suite.chainA) + + proof, proofHeight := queryProof(suite.chainA, nextSeqRcvKey) + // if testcase proofHeight is not 0, replace proofHeight with this value + if tc.proofHeight != 0 { + proofHeight = tc.proofHeight + } + + err := suite.chainB.App.IBCKeeper.ConnectionKeeper.VerifyNextSequenceRecv( + suite.chainB.GetContext(), connection, proofHeight+1, proof, testPort1, + testChannel1, 1, + ) + + if tc.expPass { + suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg) + } else { + suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg) + } + }) + } +} diff --git a/x/ibc/03-connection/module.go b/x/ibc/03-connection/module.go new file mode 100644 index 000000000000..d4d7d931c97b --- /dev/null +++ b/x/ibc/03-connection/module.go @@ -0,0 +1,33 @@ +package connection + +import ( + "fmt" + + "github.com/gorilla/mux" + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/client/cli" + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/client/rest" +) + +// Name returns the IBC connection ICS name +func Name() string { + return SubModuleName +} + +// GetTxCmd returns the root tx command for the IBC connections. +func GetTxCmd(cdc *codec.Codec, storeKey string) *cobra.Command { + return cli.GetTxCmd(fmt.Sprintf("%s/%s", storeKey, SubModuleName), cdc) +} + +// GetQueryCmd returns no root query command for the IBC connections. +func GetQueryCmd(cdc *codec.Codec, queryRoute string) *cobra.Command { + return cli.GetQueryCmd(fmt.Sprintf("%s/%s", queryRoute, SubModuleName), cdc) +} + +// RegisterRESTRoutes registers the REST routes for the IBC connections. +func RegisterRESTRoutes(ctx context.CLIContext, rtr *mux.Router, queryRoute string) { + rest.RegisterRoutes(ctx, rtr, fmt.Sprintf("%s/%s", queryRoute, SubModuleName)) +} diff --git a/x/ibc/03-connection/types/codec.go b/x/ibc/03-connection/types/codec.go new file mode 100644 index 000000000000..263ec4c3f4ae --- /dev/null +++ b/x/ibc/03-connection/types/codec.go @@ -0,0 +1,28 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported" +) + +// SubModuleCdc defines the IBC connection codec. +var SubModuleCdc *codec.Codec + +// RegisterCodec registers the IBC connection types +func RegisterCodec(cdc *codec.Codec) { + cdc.RegisterInterface((*exported.ConnectionI)(nil), nil) + cdc.RegisterInterface((*exported.CounterpartyI)(nil), nil) + cdc.RegisterConcrete(ConnectionEnd{}, "ibc/connection/ConnectionEnd", nil) + + cdc.RegisterConcrete(MsgConnectionOpenInit{}, "ibc/connection/MsgConnectionOpenInit", nil) + cdc.RegisterConcrete(MsgConnectionOpenTry{}, "ibc/connection/MsgConnectionOpenTry", nil) + cdc.RegisterConcrete(MsgConnectionOpenAck{}, "ibc/connection/MsgConnectionOpenAck", nil) + cdc.RegisterConcrete(MsgConnectionOpenConfirm{}, "ibc/connection/MsgConnectionOpenConfirm", nil) + + SetSubModuleCodec(cdc) +} + +// SetSubModuleCodec sets the ibc connection codec +func SetSubModuleCodec(cdc *codec.Codec) { + SubModuleCdc = cdc +} diff --git a/x/ibc/03-connection/types/connection.go b/x/ibc/03-connection/types/connection.go new file mode 100644 index 000000000000..27b5d0d9021b --- /dev/null +++ b/x/ibc/03-connection/types/connection.go @@ -0,0 +1,133 @@ +package types + +import ( + "strings" + + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported" + commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" + host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +var _ exported.ConnectionI = ConnectionEnd{} + +// ICS03 - Connection Data Structures as defined in https://github.com/cosmos/ics/tree/master/spec/ics-003-connection-semantics#data-structures + +// ConnectionEnd defines a stateful object on a chain connected to another separate +// one. +// NOTE: there must only be 2 defined ConnectionEnds to establish a connection +// between two chains. +type ConnectionEnd struct { + State exported.State `json:"state" yaml:"state"` + ClientID string `json:"client_id" yaml:"client_id"` + + // Counterparty chain associated with this connection. + Counterparty Counterparty `json:"counterparty" yaml:"counterparty"` + // Version is utilised to determine encodings or protocols for channels or + // packets utilising this connection. + Versions []string `json:"versions" yaml:"versions"` +} + +// NewConnectionEnd creates a new ConnectionEnd instance. +func NewConnectionEnd(state exported.State, clientID string, counterparty Counterparty, versions []string) ConnectionEnd { + return ConnectionEnd{ + State: state, + ClientID: clientID, + Counterparty: counterparty, + Versions: versions, + } +} + +// GetState implements the Connection interface +func (c ConnectionEnd) GetState() exported.State { + return c.State +} + +// GetClientID implements the Connection interface +func (c ConnectionEnd) GetClientID() string { + return c.ClientID +} + +// GetCounterparty implements the Connection interface +func (c ConnectionEnd) GetCounterparty() exported.CounterpartyI { + return c.Counterparty +} + +// GetVersions implements the Connection interface +func (c ConnectionEnd) GetVersions() []string { + return c.Versions +} + +// ValidateBasic implements the Connection interface +func (c ConnectionEnd) ValidateBasic() error { + if err := host.DefaultClientIdentifierValidator(c.ClientID); err != nil { + return sdkerrors.Wrapf(err, "invalid client ID: %s", c.ClientID) + } + if len(c.Versions) == 0 { + return sdkerrors.Wrap(ibctypes.ErrInvalidVersion, "missing connection versions") + } + for _, version := range c.Versions { + if strings.TrimSpace(version) == "" { + return sdkerrors.Wrap(ibctypes.ErrInvalidVersion, "version can't be blank") + } + } + return c.Counterparty.ValidateBasic() +} + +var _ exported.CounterpartyI = Counterparty{} + +// Counterparty defines the counterparty chain associated with a connection end. +type Counterparty struct { + ClientID string `json:"client_id" yaml:"client_id"` + ConnectionID string `json:"connection_id" yaml:"connection_id"` + Prefix commitmentexported.Prefix `json:"prefix" yaml:"prefix"` +} + +// NewCounterparty creates a new Counterparty instance. +func NewCounterparty(clientID, connectionID string, prefix commitmentexported.Prefix) Counterparty { + return Counterparty{ + ClientID: clientID, + ConnectionID: connectionID, + Prefix: prefix, + } +} + +// GetClientID implements the CounterpartyI interface +func (c Counterparty) GetClientID() string { + return c.ClientID +} + +// GetConnectionID implements the CounterpartyI interface +func (c Counterparty) GetConnectionID() string { + return c.ConnectionID +} + +// GetPrefix implements the CounterpartyI interface +func (c Counterparty) GetPrefix() commitmentexported.Prefix { + return c.Prefix +} + +// ValidateBasic performs a basic validation check of the identifiers and prefix +func (c Counterparty) ValidateBasic() error { + if err := host.DefaultConnectionIdentifierValidator(c.ConnectionID); err != nil { + return sdkerrors.Wrap(err, + sdkerrors.Wrapf( + ErrInvalidCounterparty, + "invalid counterparty connection ID %s", c.ConnectionID, + ).Error(), + ) + } + if err := host.DefaultClientIdentifierValidator(c.ClientID); err != nil { + return sdkerrors.Wrap(err, + sdkerrors.Wrapf( + ErrInvalidCounterparty, + "invalid counterparty client ID %s", c.ClientID, + ).Error(), + ) + } + if c.Prefix == nil || len(c.Prefix.Bytes()) == 0 { + return sdkerrors.Wrap(ErrInvalidCounterparty, "invalid counterparty prefix") + } + return nil +} diff --git a/x/ibc/03-connection/types/connection_test.go b/x/ibc/03-connection/types/connection_test.go new file mode 100644 index 000000000000..92605a7ea61e --- /dev/null +++ b/x/ibc/03-connection/types/connection_test.go @@ -0,0 +1,79 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported" + commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" +) + +func TestConnectionValidateBasic(t *testing.T) { + testCases := []struct { + name string + connection ConnectionEnd + expPass bool + }{ + { + "valid connection", + ConnectionEnd{exported.INIT, "clientidone", Counterparty{"clientidtwo", "connectionidone", commitmenttypes.NewMerklePrefix([]byte("prefix"))}, []string{"1.0.0"}}, + true, + }, + { + "invalid client id", + ConnectionEnd{exported.INIT, "ClientIDTwo", Counterparty{"clientidtwo", "connectionidone", commitmenttypes.NewMerklePrefix([]byte("prefix"))}, []string{"1.0.0"}}, + false, + }, + { + "empty versions", + ConnectionEnd{exported.INIT, "clientidone", Counterparty{"clientidtwo", "connectionidone", commitmenttypes.NewMerklePrefix([]byte("prefix"))}, nil}, + false, + }, + { + "invalid version", + ConnectionEnd{exported.INIT, "clientidone", Counterparty{"clientidtwo", "connectionidone", commitmenttypes.NewMerklePrefix([]byte("prefix"))}, []string{""}}, + false, + }, + { + "invalid counterparty", + ConnectionEnd{exported.INIT, "clientidone", Counterparty{"clientidtwo", "connectionidone", nil}, []string{"1.0.0"}}, + false, + }, + } + + for i, tc := range testCases { + tc := tc + + err := tc.connection.ValidateBasic() + if tc.expPass { + require.NoError(t, err, "valid test case %d failed: %s", i, tc.name) + } else { + require.Error(t, err, "invalid test case %d passed: %s", i, tc.name) + } + } +} + +func TestCounterpartyValidateBasic(t *testing.T) { + testCases := []struct { + name string + counterparty Counterparty + expPass bool + }{ + {"valid counterparty", Counterparty{"clientidone", "connectionidone", commitmenttypes.NewMerklePrefix([]byte("prefix"))}, true}, + {"invalid client id", Counterparty{"InvalidClient", "channelidone", commitmenttypes.NewMerklePrefix([]byte("prefix"))}, false}, + {"invalid connection id", Counterparty{"clientidone", "InvalidConnection", commitmenttypes.NewMerklePrefix([]byte("prefix"))}, false}, + {"invalid prefix", Counterparty{"clientidone", "connectionidone", nil}, false}, + } + + for i, tc := range testCases { + tc := tc + + err := tc.counterparty.ValidateBasic() + if tc.expPass { + require.NoError(t, err, "valid test case %d failed: %s", i, tc.name) + } else { + require.Error(t, err, "invalid test case %d passed: %s", i, tc.name) + } + } +} diff --git a/x/ibc/03-connection/types/errors.go b/x/ibc/03-connection/types/errors.go new file mode 100644 index 000000000000..a738f9956762 --- /dev/null +++ b/x/ibc/03-connection/types/errors.go @@ -0,0 +1,16 @@ +package types + +import ( + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +// IBC connection sentinel errors +var ( + ErrConnectionExists = sdkerrors.Register(SubModuleName, 1, "connection already exists") + ErrConnectionNotFound = sdkerrors.Register(SubModuleName, 2, "connection not found") + ErrClientConnectionPathsNotFound = sdkerrors.Register(SubModuleName, 3, "light client connection paths not found") + ErrConnectionPath = sdkerrors.Register(SubModuleName, 4, "connection path is not associated to the given light client") + ErrInvalidConnectionState = sdkerrors.Register(SubModuleName, 5, "invalid connection state") + ErrInvalidCounterparty = sdkerrors.Register(SubModuleName, 6, "invalid counterparty connection") + ErrInvalidConnection = sdkerrors.Register(SubModuleName, 7, "invalid connection") +) diff --git a/x/ibc/03-connection/types/events.go b/x/ibc/03-connection/types/events.go new file mode 100644 index 000000000000..92a73afbebd3 --- /dev/null +++ b/x/ibc/03-connection/types/events.go @@ -0,0 +1,24 @@ +package types + +import ( + "fmt" + + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +// IBC connection events +const ( + AttributeKeyConnectionID = "connection_id" + AttributeKeyClientID = "client_id" + AttributeKeyCounterpartyClientID = "counterparty_client_id" +) + +// IBC connection events vars +var ( + EventTypeConnectionOpenInit = MsgConnectionOpenInit{}.Type() + EventTypeConnectionOpenTry = MsgConnectionOpenTry{}.Type() + EventTypeConnectionOpenAck = MsgConnectionOpenAck{}.Type() + EventTypeConnectionOpenConfirm = MsgConnectionOpenConfirm{}.Type() + + AttributeValueCategory = fmt.Sprintf("%s_%s", ibctypes.ModuleName, SubModuleName) +) diff --git a/x/ibc/03-connection/types/expected_keepers.go b/x/ibc/03-connection/types/expected_keepers.go new file mode 100644 index 000000000000..c91519e0dfb3 --- /dev/null +++ b/x/ibc/03-connection/types/expected_keepers.go @@ -0,0 +1,13 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" +) + +// ClientKeeper expected account IBC client keeper +type ClientKeeper interface { + GetClientState(ctx sdk.Context, clientID string) (clientexported.ClientState, bool) + GetClientConsensusState(ctx sdk.Context, clientID string, height uint64) (clientexported.ConsensusState, bool) + GetSelfConsensusState(ctx sdk.Context, height uint64) (clientexported.ConsensusState, bool) +} diff --git a/x/ibc/03-connection/types/keys.go b/x/ibc/03-connection/types/keys.go new file mode 100644 index 000000000000..23478ec7591a --- /dev/null +++ b/x/ibc/03-connection/types/keys.go @@ -0,0 +1,15 @@ +package types + +const ( + // SubModuleName defines the IBC connection name + SubModuleName = "connection" + + // StoreKey is the store key string for IBC connections + StoreKey = SubModuleName + + // RouterKey is the message route for IBC connections + RouterKey = SubModuleName + + // QuerierRoute is the querier route for IBC connections + QuerierRoute = SubModuleName +) diff --git a/x/ibc/03-connection/types/msgs.go b/x/ibc/03-connection/types/msgs.go new file mode 100644 index 000000000000..9fb96cc3734e --- /dev/null +++ b/x/ibc/03-connection/types/msgs.go @@ -0,0 +1,310 @@ +package types + +import ( + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" + commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" + host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +var _ sdk.Msg = MsgConnectionOpenInit{} + +// MsgConnectionOpenInit defines the msg sent by an account on Chain A to +// initialize a connection with Chain B. +type MsgConnectionOpenInit struct { + ConnectionID string `json:"connection_id"` + ClientID string `json:"client_id"` + Counterparty Counterparty `json:"counterparty"` + Signer sdk.AccAddress `json:"signer"` +} + +// NewMsgConnectionOpenInit creates a new MsgConnectionOpenInit instance +func NewMsgConnectionOpenInit( + connectionID, clientID, counterpartyConnectionID, + counterpartyClientID string, counterpartyPrefix commitmentexported.Prefix, + signer sdk.AccAddress, +) MsgConnectionOpenInit { + counterparty := NewCounterparty(counterpartyClientID, counterpartyConnectionID, counterpartyPrefix) + return MsgConnectionOpenInit{ + ConnectionID: connectionID, + ClientID: clientID, + Counterparty: counterparty, + Signer: signer, + } +} + +// Route implements sdk.Msg +func (msg MsgConnectionOpenInit) Route() string { + return ibctypes.RouterKey +} + +// Type implements sdk.Msg +func (msg MsgConnectionOpenInit) Type() string { + return "connection_open_init" +} + +// ValidateBasic implements sdk.Msg +func (msg MsgConnectionOpenInit) ValidateBasic() error { + if err := host.DefaultConnectionIdentifierValidator(msg.ConnectionID); err != nil { + return sdkerrors.Wrapf(err, "invalid connection ID: %s", msg.ConnectionID) + } + if err := host.DefaultClientIdentifierValidator(msg.ClientID); err != nil { + return sdkerrors.Wrapf(err, "invalid client ID: %s", msg.ClientID) + } + if msg.Signer.Empty() { + return sdkerrors.ErrInvalidAddress + } + return msg.Counterparty.ValidateBasic() +} + +// GetSignBytes implements sdk.Msg +func (msg MsgConnectionOpenInit) GetSignBytes() []byte { + return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg)) +} + +// GetSigners implements sdk.Msg +func (msg MsgConnectionOpenInit) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} + +var _ sdk.Msg = MsgConnectionOpenTry{} + +// MsgConnectionOpenTry defines a msg sent by a Relayer to try to open a connection +// on Chain B. +type MsgConnectionOpenTry struct { + ConnectionID string `json:"connection_id"` + ClientID string `json:"client_id"` + Counterparty Counterparty `json:"counterparty"` + CounterpartyVersions []string `json:"counterparty_versions"` + ProofInit commitmentexported.Proof `json:"proof_init"` // proof of the initialization the connection on Chain A: `none -> INIT` + ProofConsensus commitmentexported.Proof `json:"proof_consensus"` // proof of client consensus state + ProofHeight uint64 `json:"proof_height"` + ConsensusHeight uint64 `json:"consensus_height"` + Signer sdk.AccAddress `json:"signer"` +} + +// NewMsgConnectionOpenTry creates a new MsgConnectionOpenTry instance +func NewMsgConnectionOpenTry( + connectionID, clientID, counterpartyConnectionID, + counterpartyClientID string, counterpartyPrefix commitmentexported.Prefix, + counterpartyVersions []string, proofInit, proofConsensus commitmentexported.Proof, + proofHeight, consensusHeight uint64, signer sdk.AccAddress, +) MsgConnectionOpenTry { + counterparty := NewCounterparty(counterpartyClientID, counterpartyConnectionID, counterpartyPrefix) + return MsgConnectionOpenTry{ + ConnectionID: connectionID, + ClientID: clientID, + Counterparty: counterparty, + CounterpartyVersions: counterpartyVersions, + ProofInit: proofInit, + ProofConsensus: proofConsensus, + ProofHeight: proofHeight, + ConsensusHeight: consensusHeight, + Signer: signer, + } +} + +// Route implements sdk.Msg +func (msg MsgConnectionOpenTry) Route() string { + return ibctypes.RouterKey +} + +// Type implements sdk.Msg +func (msg MsgConnectionOpenTry) Type() string { + return "connection_open_try" +} + +// ValidateBasic implements sdk.Msg +func (msg MsgConnectionOpenTry) ValidateBasic() error { + if err := host.DefaultConnectionIdentifierValidator(msg.ConnectionID); err != nil { + return sdkerrors.Wrapf(err, "invalid connection ID: %s", msg.ConnectionID) + } + if err := host.DefaultClientIdentifierValidator(msg.ClientID); err != nil { + return sdkerrors.Wrapf(err, "invalid client ID: %s", msg.ClientID) + } + if len(msg.CounterpartyVersions) == 0 { + return sdkerrors.Wrap(ibctypes.ErrInvalidVersion, "missing counterparty versions") + } + for _, version := range msg.CounterpartyVersions { + if strings.TrimSpace(version) == "" { + return sdkerrors.Wrap(ibctypes.ErrInvalidVersion, "version can't be blank") + } + } + if msg.ProofInit == nil || msg.ProofConsensus == nil { + return sdkerrors.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty proof") + } + if err := msg.ProofInit.ValidateBasic(); err != nil { + return sdkerrors.Wrap(err, "proof init cannot be nil") + } + if err := msg.ProofConsensus.ValidateBasic(); err != nil { + return sdkerrors.Wrap(err, "proof consensus cannot be nil") + } + if msg.ProofHeight == 0 { + return sdkerrors.Wrap(ibctypes.ErrInvalidHeight, "proof height must be > 0") + } + if msg.ConsensusHeight == 0 { + return sdkerrors.Wrap(ibctypes.ErrInvalidHeight, "consensus height must be > 0") + } + if msg.Signer.Empty() { + return sdkerrors.ErrInvalidAddress + } + return msg.Counterparty.ValidateBasic() +} + +// GetSignBytes implements sdk.Msg +func (msg MsgConnectionOpenTry) GetSignBytes() []byte { + return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg)) +} + +// GetSigners implements sdk.Msg +func (msg MsgConnectionOpenTry) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} + +var _ sdk.Msg = MsgConnectionOpenAck{} + +// MsgConnectionOpenAck defines a msg sent by a Relayer to Chain A to acknowledge +// the change of connection state to TRYOPEN on Chain B. +type MsgConnectionOpenAck struct { + ConnectionID string `json:"connection_id"` + ProofTry commitmentexported.Proof `json:"proof_try"` // proof for the change of the connection state on Chain B: `none -> TRYOPEN` + ProofConsensus commitmentexported.Proof `json:"proof_consensus"` // proof of client consensus state + ProofHeight uint64 `json:"proof_height"` + ConsensusHeight uint64 `json:"consensus_height"` + Version string `json:"version"` + Signer sdk.AccAddress `json:"signer"` +} + +// NewMsgConnectionOpenAck creates a new MsgConnectionOpenAck instance +func NewMsgConnectionOpenAck( + connectionID string, proofTry, proofConsensus commitmentexported.Proof, + proofHeight, consensusHeight uint64, version string, + signer sdk.AccAddress, +) MsgConnectionOpenAck { + return MsgConnectionOpenAck{ + ConnectionID: connectionID, + ProofTry: proofTry, + ProofConsensus: proofConsensus, + ProofHeight: proofHeight, + ConsensusHeight: consensusHeight, + Version: version, + Signer: signer, + } +} + +// Route implements sdk.Msg +func (msg MsgConnectionOpenAck) Route() string { + return ibctypes.RouterKey +} + +// Type implements sdk.Msg +func (msg MsgConnectionOpenAck) Type() string { + return "connection_open_ack" +} + +// ValidateBasic implements sdk.Msg +func (msg MsgConnectionOpenAck) ValidateBasic() error { + if err := host.DefaultConnectionIdentifierValidator(msg.ConnectionID); err != nil { + return sdkerrors.Wrap(err, "invalid connection ID") + } + if strings.TrimSpace(msg.Version) == "" { + return sdkerrors.Wrap(ibctypes.ErrInvalidVersion, "version can't be blank") + } + if msg.ProofTry == nil || msg.ProofConsensus == nil { + return sdkerrors.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty proof") + } + if err := msg.ProofTry.ValidateBasic(); err != nil { + return sdkerrors.Wrap(err, "proof try cannot be nil") + } + if err := msg.ProofConsensus.ValidateBasic(); err != nil { + return sdkerrors.Wrap(err, "proof consensus cannot be nil") + } + if msg.ProofHeight == 0 { + return sdkerrors.Wrap(ibctypes.ErrInvalidHeight, "proof height must be > 0") + } + if msg.ConsensusHeight == 0 { + return sdkerrors.Wrap(ibctypes.ErrInvalidHeight, "consensus height must be > 0") + } + if msg.Signer.Empty() { + return sdkerrors.ErrInvalidAddress + } + return nil +} + +// GetSignBytes implements sdk.Msg +func (msg MsgConnectionOpenAck) GetSignBytes() []byte { + return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg)) +} + +// GetSigners implements sdk.Msg +func (msg MsgConnectionOpenAck) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} + +var _ sdk.Msg = MsgConnectionOpenConfirm{} + +// MsgConnectionOpenConfirm defines a msg sent by a Relayer to Chain B to acknowledge +// the change of connection state to OPEN on Chain A. +type MsgConnectionOpenConfirm struct { + ConnectionID string `json:"connection_id"` + ProofAck commitmentexported.Proof `json:"proof_ack"` // proof for the change of the connection state on Chain A: `INIT -> OPEN` + ProofHeight uint64 `json:"proof_height"` + Signer sdk.AccAddress `json:"signer"` +} + +// NewMsgConnectionOpenConfirm creates a new MsgConnectionOpenConfirm instance +func NewMsgConnectionOpenConfirm( + connectionID string, proofAck commitmentexported.Proof, proofHeight uint64, + signer sdk.AccAddress, +) MsgConnectionOpenConfirm { + return MsgConnectionOpenConfirm{ + ConnectionID: connectionID, + ProofAck: proofAck, + ProofHeight: proofHeight, + Signer: signer, + } +} + +// Route implements sdk.Msg +func (msg MsgConnectionOpenConfirm) Route() string { + return ibctypes.RouterKey +} + +// Type implements sdk.Msg +func (msg MsgConnectionOpenConfirm) Type() string { + return "connection_open_confirm" +} + +// ValidateBasic implements sdk.Msg +func (msg MsgConnectionOpenConfirm) ValidateBasic() error { + if err := host.DefaultConnectionIdentifierValidator(msg.ConnectionID); err != nil { + return sdkerrors.Wrap(err, "invalid connection ID") + } + if msg.ProofAck == nil { + return sdkerrors.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty proof") + } + if err := msg.ProofAck.ValidateBasic(); err != nil { + return sdkerrors.Wrap(err, "proof ack cannot be nil") + } + if msg.ProofHeight == 0 { + return sdkerrors.Wrap(ibctypes.ErrInvalidHeight, "proof height must be > 0") + } + if msg.Signer.Empty() { + return sdkerrors.ErrInvalidAddress + } + return nil +} + +// GetSignBytes implements sdk.Msg +func (msg MsgConnectionOpenConfirm) GetSignBytes() []byte { + return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg)) +} + +// GetSigners implements sdk.Msg +func (msg MsgConnectionOpenConfirm) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} diff --git a/x/ibc/03-connection/types/msgs_test.go b/x/ibc/03-connection/types/msgs_test.go new file mode 100644 index 000000000000..26c88868837f --- /dev/null +++ b/x/ibc/03-connection/types/msgs_test.go @@ -0,0 +1,215 @@ +package types + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/suite" + + abci "github.com/tendermint/tendermint/abci/types" + dbm "github.com/tendermint/tm-db" + + "github.com/cosmos/cosmos-sdk/store/iavl" + "github.com/cosmos/cosmos-sdk/store/rootmulti" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" +) + +type MsgTestSuite struct { + suite.Suite + + proof commitmenttypes.MerkleProof +} + +func (suite *MsgTestSuite) SetupTest() { + db := dbm.NewMemDB() + store := rootmulti.NewStore(db) + storeKey := storetypes.NewKVStoreKey("iavlStoreKey") + + store.MountStoreWithDB(storeKey, storetypes.StoreTypeIAVL, nil) + store.LoadVersion(0) + iavlStore := store.GetCommitStore(storeKey).(*iavl.Store) + + iavlStore.Set([]byte("KEY"), []byte("VALUE")) + _ = store.Commit() + + res := store.Query(abci.RequestQuery{ + Path: fmt.Sprintf("/%s/key", storeKey.Name()), // required path to get key/value+proof + Data: []byte("KEY"), + Prove: true, + }) + + suite.proof = commitmenttypes.MerkleProof{Proof: res.Proof} +} + +func TestMsgTestSuite(t *testing.T) { + suite.Run(t, new(MsgTestSuite)) +} + +func (suite *MsgTestSuite) TestNewMsgConnectionOpenInit() { + prefix := commitmenttypes.NewMerklePrefix([]byte("storePrefixKey")) + signer, _ := sdk.AccAddressFromBech32("cosmos1ckgw5d7jfj7wwxjzs9fdrdev9vc8dzcw3n2lht") + + testMsgs := []MsgConnectionOpenInit{ + NewMsgConnectionOpenInit("test/conn1", "clienttotesta", "connectiontotest", "clienttotest", prefix, signer), + NewMsgConnectionOpenInit("ibcconntest", "test/iris", "connectiontotest", "clienttotest", prefix, signer), + NewMsgConnectionOpenInit("ibcconntest", "clienttotest", "test/conn1", "clienttotest", prefix, signer), + NewMsgConnectionOpenInit("ibcconntest", "clienttotest", "connectiontotest", "test/conn1", prefix, signer), + NewMsgConnectionOpenInit("ibcconntest", "clienttotest", "connectiontotest", "clienttotest", nil, signer), + NewMsgConnectionOpenInit("ibcconntest", "clienttotest", "connectiontotest", "clienttotest", prefix, nil), + NewMsgConnectionOpenInit("ibcconntest", "clienttotest", "connectiontotest", "clienttotest", prefix, signer), + } + + var testCases = []struct { + msg MsgConnectionOpenInit + expPass bool + errMsg string + }{ + {testMsgs[0], false, "invalid connection ID"}, + {testMsgs[1], false, "invalid client ID"}, + {testMsgs[2], false, "invalid counterparty client ID"}, + {testMsgs[3], false, "invalid counterparty connection ID"}, + {testMsgs[4], false, "empty counterparty prefix"}, + {testMsgs[5], false, "empty singer"}, + {testMsgs[6], true, "success"}, + } + + for i, tc := range testCases { + err := tc.msg.ValidateBasic() + if tc.expPass { + suite.Require().NoError(err, "Msg %d failed: %v", i, err) + } else { + suite.Require().Error(err, "Invalid Msg %d passed: %s", i, tc.errMsg) + } + } +} + +func (suite *MsgTestSuite) TestNewMsgConnectionOpenTry() { + prefix := commitmenttypes.NewMerklePrefix([]byte("storePrefixKey")) + signer, _ := sdk.AccAddressFromBech32("cosmos1ckgw5d7jfj7wwxjzs9fdrdev9vc8dzcw3n2lht") + + testMsgs := []MsgConnectionOpenTry{ + NewMsgConnectionOpenTry("test/conn1", "clienttotesta", "connectiontotest", "clienttotest", prefix, []string{"1.0.0"}, suite.proof, suite.proof, 10, 10, signer), + NewMsgConnectionOpenTry("ibcconntest", "test/iris", "connectiontotest", "clienttotest", prefix, []string{"1.0.0"}, suite.proof, suite.proof, 10, 10, signer), + NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "ibc/test", "clienttotest", prefix, []string{"1.0.0"}, suite.proof, suite.proof, 10, 10, signer), + NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "connectiontotest", "test/conn1", prefix, []string{"1.0.0"}, suite.proof, suite.proof, 10, 10, signer), + NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "connectiontotest", "clienttotest", nil, []string{"1.0.0"}, suite.proof, suite.proof, 10, 10, signer), + NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "connectiontotest", "clienttotest", prefix, []string{}, suite.proof, suite.proof, 10, 10, signer), + NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "connectiontotest", "clienttotest", prefix, []string{"1.0.0"}, nil, suite.proof, 10, 10, signer), + NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "connectiontotest", "clienttotest", prefix, []string{"1.0.0"}, commitmenttypes.MerkleProof{Proof: nil}, suite.proof, 10, 10, signer), + NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "connectiontotest", "clienttotest", prefix, []string{"1.0.0"}, suite.proof, nil, 10, 10, signer), + NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "connectiontotest", "clienttotest", prefix, []string{"1.0.0"}, suite.proof, commitmenttypes.MerkleProof{Proof: nil}, 10, 10, signer), + NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "connectiontotest", "clienttotest", prefix, []string{"1.0.0"}, suite.proof, suite.proof, 0, 10, signer), + NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "connectiontotest", "clienttotest", prefix, []string{"1.0.0"}, suite.proof, suite.proof, 10, 0, signer), + NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "connectiontotest", "clienttotest", prefix, []string{"1.0.0"}, suite.proof, suite.proof, 10, 10, nil), + NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "connectiontotest", "clienttotest", prefix, []string{"1.0.0"}, suite.proof, suite.proof, 10, 10, signer), + } + + var testCases = []struct { + msg MsgConnectionOpenTry + expPass bool + errMsg string + }{ + {testMsgs[0], false, "invalid connection ID"}, + {testMsgs[1], false, "invalid client ID"}, + {testMsgs[2], false, "invalid counterparty connection ID"}, + {testMsgs[3], false, "invalid counterparty client ID"}, + {testMsgs[4], false, "empty counterparty prefix"}, + {testMsgs[5], false, "empty counterpartyVersions"}, + {testMsgs[6], false, "empty proofInit"}, + {testMsgs[7], false, "empty proofInit"}, + {testMsgs[8], false, "empty proofConsensus"}, + {testMsgs[9], false, "empty proofConsensus"}, + {testMsgs[10], false, "invalid proofHeight"}, + {testMsgs[11], false, "invalid consensusHeight"}, + {testMsgs[12], false, "empty singer"}, + {testMsgs[13], true, "success"}, + } + + for i, tc := range testCases { + err := tc.msg.ValidateBasic() + if tc.expPass { + suite.Require().NoError(err, "Msg %d failed: %s", i, tc.errMsg) + } else { + suite.Require().Error(err, "Invalid Msg %d passed: %s", i, tc.errMsg) + } + } +} + +func (suite *MsgTestSuite) TestNewMsgConnectionOpenAck() { + signer, _ := sdk.AccAddressFromBech32("cosmos1ckgw5d7jfj7wwxjzs9fdrdev9vc8dzcw3n2lht") + + testMsgs := []MsgConnectionOpenAck{ + NewMsgConnectionOpenAck("test/conn1", suite.proof, suite.proof, 10, 10, "1.0.0", signer), + NewMsgConnectionOpenAck("ibcconntest", nil, suite.proof, 10, 10, "1.0.0", signer), + NewMsgConnectionOpenAck("ibcconntest", commitmenttypes.MerkleProof{Proof: nil}, suite.proof, 10, 10, "1.0.0", signer), + NewMsgConnectionOpenAck("ibcconntest", suite.proof, nil, 10, 10, "1.0.0", signer), + NewMsgConnectionOpenAck("ibcconntest", suite.proof, commitmenttypes.MerkleProof{Proof: nil}, 10, 10, "1.0.0", signer), + NewMsgConnectionOpenAck("ibcconntest", suite.proof, suite.proof, 0, 10, "1.0.0", signer), + NewMsgConnectionOpenAck("ibcconntest", suite.proof, suite.proof, 10, 0, "1.0.0", signer), + NewMsgConnectionOpenAck("ibcconntest", suite.proof, suite.proof, 10, 10, "", signer), + NewMsgConnectionOpenAck("ibcconntest", suite.proof, suite.proof, 10, 10, "1.0.0", nil), + NewMsgConnectionOpenAck("ibcconntest", suite.proof, suite.proof, 10, 10, "1.0.0", signer), + } + var testCases = []struct { + msg MsgConnectionOpenAck + expPass bool + errMsg string + }{ + {testMsgs[0], false, "invalid connection ID"}, + {testMsgs[1], false, "empty proofTry"}, + {testMsgs[2], false, "empty proofTry"}, + {testMsgs[3], false, "empty proofConsensus"}, + {testMsgs[4], false, "empty proofConsensus"}, + {testMsgs[5], false, "invalid proofHeight"}, + {testMsgs[6], false, "invalid consensusHeight"}, + {testMsgs[7], false, "invalid version"}, + {testMsgs[8], false, "empty signer"}, + {testMsgs[9], true, "success"}, + } + + for i, tc := range testCases { + err := tc.msg.ValidateBasic() + if tc.expPass { + suite.Require().NoError(err, "Msg %d failed: %s", i, tc.errMsg) + } else { + suite.Require().Error(err, "Invalid Msg %d passed: %s", i, tc.errMsg) + } + } +} + +func (suite *MsgTestSuite) TestNewMsgConnectionOpenConfirm() { + signer, _ := sdk.AccAddressFromBech32("cosmos1ckgw5d7jfj7wwxjzs9fdrdev9vc8dzcw3n2lht") + + testMsgs := []MsgConnectionOpenConfirm{ + NewMsgConnectionOpenConfirm("test/conn1", suite.proof, 10, signer), + NewMsgConnectionOpenConfirm("ibcconntest", nil, 10, signer), + NewMsgConnectionOpenConfirm("ibcconntest", commitmenttypes.MerkleProof{Proof: nil}, 10, signer), + NewMsgConnectionOpenConfirm("ibcconntest", suite.proof, 0, signer), + NewMsgConnectionOpenConfirm("ibcconntest", suite.proof, 10, nil), + NewMsgConnectionOpenConfirm("ibcconntest", suite.proof, 10, signer), + } + + var testCases = []struct { + msg MsgConnectionOpenConfirm + expPass bool + errMsg string + }{ + {testMsgs[0], false, "invalid connection ID"}, + {testMsgs[1], false, "empty proofTry"}, + {testMsgs[2], false, "empty proofTry"}, + {testMsgs[3], false, "invalid proofHeight"}, + {testMsgs[4], false, "empty signer"}, + {testMsgs[5], true, "success"}, + } + + for i, tc := range testCases { + err := tc.msg.ValidateBasic() + if tc.expPass { + suite.Require().NoError(err, "Msg %d failed: %s", i, tc.errMsg) + } else { + suite.Require().Error(err, "Invalid Msg %d passed: %s", i, tc.errMsg) + } + } +} diff --git a/x/ibc/03-connection/types/querier.go b/x/ibc/03-connection/types/querier.go new file mode 100644 index 000000000000..a283f37641f9 --- /dev/null +++ b/x/ibc/03-connection/types/querier.go @@ -0,0 +1,93 @@ +package types + +import ( + "strings" + + "github.com/tendermint/tendermint/crypto/merkle" + + commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +// query routes supported by the IBC connection Querier +const ( + QueryAllConnections = "connections" + QueryClientConnections = "client_connections" +) + +// IdentifiedConnectionEnd defines the union of a connection end & an identifier. +type IdentifiedConnectionEnd struct { + Connection ConnectionEnd `json:"connection_end" yaml:"connection_end"` + Identifier string `json:"identifier" yaml:"identifier"` +} + +// ConnectionResponse defines the client query response for a connection which +// also includes a proof and the height from which the proof was retrieved. +type ConnectionResponse struct { + Connection IdentifiedConnectionEnd `json:"connection" yaml:"connection"` + Proof commitmenttypes.MerkleProof `json:"proof,omitempty" yaml:"proof,omitempty"` + ProofPath commitmenttypes.MerklePath `json:"proof_path,omitempty" yaml:"proof_path,omitempty"` + ProofHeight uint64 `json:"proof_height,omitempty" yaml:"proof_height,omitempty"` +} + +// NewConnectionResponse creates a new ConnectionResponse instance +func NewConnectionResponse( + connectionID string, connection ConnectionEnd, proof *merkle.Proof, height int64, +) ConnectionResponse { + return ConnectionResponse{ + Connection: IdentifiedConnectionEnd{connection, connectionID}, + Proof: commitmenttypes.MerkleProof{Proof: proof}, + ProofPath: commitmenttypes.NewMerklePath(strings.Split(ibctypes.ConnectionPath(connectionID), "/")), + ProofHeight: uint64(height), + } +} + +// QueryAllConnectionsParams defines the parameters necessary for querying for all +// connections. +type QueryAllConnectionsParams struct { + Page int `json:"page" yaml:"page"` + Limit int `json:"limit" yaml:"limit"` +} + +// NewQueryAllConnectionsParams creates a new QueryAllConnectionsParams instance. +func NewQueryAllConnectionsParams(page, limit int) QueryAllConnectionsParams { + return QueryAllConnectionsParams{ + Page: page, + Limit: limit, + } +} + +// ClientConnectionsResponse defines the client query response for a client +// connection paths which also includes a proof and the height from which the +// proof was retrieved. +type ClientConnectionsResponse struct { + ConnectionPaths []string `json:"connection_paths" yaml:"connection_paths"` + Proof commitmenttypes.MerkleProof `json:"proof,omitempty" yaml:"proof,omitempty"` + ProofPath commitmenttypes.MerklePath `json:"proof_path,omitempty" yaml:"proof_path,omitempty"` + ProofHeight uint64 `json:"proof_height,omitempty" yaml:"proof_height,omitempty"` +} + +// NewClientConnectionsResponse creates a new ConnectionPaths instance +func NewClientConnectionsResponse( + clientID string, connectionPaths []string, proof *merkle.Proof, height int64, +) ClientConnectionsResponse { + return ClientConnectionsResponse{ + ConnectionPaths: connectionPaths, + Proof: commitmenttypes.MerkleProof{Proof: proof}, + ProofPath: commitmenttypes.NewMerklePath(strings.Split(ibctypes.ClientConnectionsPath(clientID), "/")), + ProofHeight: uint64(height), + } +} + +// QueryClientConnectionsParams defines the params for the following queries: +// - 'custom/ibc/client//connections' +type QueryClientConnectionsParams struct { + ClientID string +} + +// NewQueryClientConnectionsParams creates a new QueryClientConnectionsParams instance +func NewQueryClientConnectionsParams(clientID string) QueryClientConnectionsParams { + return QueryClientConnectionsParams{ + ClientID: clientID, + } +} diff --git a/x/ibc/03-connection/types/version.go b/x/ibc/03-connection/types/version.go new file mode 100644 index 000000000000..bf74a52dae92 --- /dev/null +++ b/x/ibc/03-connection/types/version.go @@ -0,0 +1,96 @@ +package types + +// GetCompatibleVersions returns an ordered set of compatible IBC versions for the +// caller chain's connection end. +func GetCompatibleVersions() []string { + return []string{"1.0.0"} +} + +// LatestVersion gets the latest version of a connection protocol +// +// CONTRACT: version array MUST be already sorted. +func LatestVersion(versions []string) string { + if len(versions) == 0 { + return "" + } + return versions[len(versions)-1] +} + +// PickVersion picks the counterparty latest version that is matches the list +// of compatible versions for the connection. +func PickVersion(counterpartyVersions, compatibleVersions []string) string { + + n := len(counterpartyVersions) + m := len(compatibleVersions) + + // aux hash maps to lookup already seen versions + counterpartyVerLookup := make(map[string]bool) + compatibleVerLookup := make(map[string]bool) + + // versions suported + var supportedVersions []string + + switch { + case n == 0 || m == 0: + return "" + case n == m: + for i := n - 1; i >= 0; i-- { + counterpartyVerLookup[counterpartyVersions[i]] = true + compatibleVerLookup[compatibleVersions[i]] = true + + // check if we've seen any of the versions + if _, ok := compatibleVerLookup[counterpartyVersions[i]]; ok { + supportedVersions = append(supportedVersions, counterpartyVersions[i]) + } + + if _, ok := counterpartyVerLookup[compatibleVersions[i]]; ok { + // TODO: check if the version is already in the array + supportedVersions = append(supportedVersions, compatibleVersions[i]) + } + } + case n > m: + for i := n - 1; i >= m; i-- { + counterpartyVerLookup[compatibleVersions[i]] = true + } + + for i := m - 1; i >= 0; i-- { + counterpartyVerLookup[counterpartyVersions[i]] = true + compatibleVerLookup[compatibleVersions[i]] = true + + // check if we've seen any of the versions + if _, ok := compatibleVerLookup[counterpartyVersions[i]]; ok { + supportedVersions = append(supportedVersions, counterpartyVersions[i]) + } + + if _, ok := counterpartyVerLookup[compatibleVersions[i]]; ok { + supportedVersions = append(supportedVersions, compatibleVersions[i]) + } + } + + case n < m: + for i := m - 1; i >= n; i-- { + compatibleVerLookup[compatibleVersions[i]] = true + } + + for i := n - 1; i >= 0; i-- { + counterpartyVerLookup[counterpartyVersions[i]] = true + compatibleVerLookup[compatibleVersions[i]] = true + + // check if we've seen any of the versions + if _, ok := compatibleVerLookup[counterpartyVersions[i]]; ok { + supportedVersions = append(supportedVersions, counterpartyVersions[i]) + } + + if _, ok := counterpartyVerLookup[compatibleVersions[i]]; ok { + supportedVersions = append(supportedVersions, compatibleVersions[i]) + } + } + } + + if len(supportedVersions) == 0 { + return "" + } + + // TODO: compare latest version before appending + return supportedVersions[len(supportedVersions)-1] +} diff --git a/x/ibc/04-channel/alias.go b/x/ibc/04-channel/alias.go new file mode 100644 index 000000000000..ee12c61e248c --- /dev/null +++ b/x/ibc/04-channel/alias.go @@ -0,0 +1,85 @@ +package channel + +// nolint +// autogenerated code using github.com/rigelrozanski/multitool +// aliases generated for the following subdirectories: +// ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/04-channel/keeper +// ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types + +import ( + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/keeper" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" +) + +const ( + SubModuleName = types.SubModuleName + StoreKey = types.StoreKey + RouterKey = types.RouterKey + QuerierRoute = types.QuerierRoute + QueryAllChannels = types.QueryAllChannels + QueryConnectionChannels = types.QueryConnectionChannels + QueryChannel = types.QueryChannel +) + +var ( + // functions aliases + NewKeeper = keeper.NewKeeper + QuerierChannels = keeper.QuerierChannels + QuerierConnectionChannels = keeper.QuerierConnectionChannels + NewChannel = types.NewChannel + NewCounterparty = types.NewCounterparty + RegisterCodec = types.RegisterCodec + ErrChannelExists = types.ErrChannelExists + ErrChannelNotFound = types.ErrChannelNotFound + ErrInvalidCounterparty = types.ErrInvalidCounterparty + ErrChannelCapabilityNotFound = types.ErrChannelCapabilityNotFound + ErrInvalidPacket = types.ErrInvalidPacket + ErrSequenceSendNotFound = types.ErrSequenceSendNotFound + ErrSequenceReceiveNotFound = types.ErrSequenceReceiveNotFound + ErrPacketTimeout = types.ErrPacketTimeout + ErrInvalidChannel = types.ErrInvalidChannel + ErrInvalidChannelState = types.ErrInvalidChannelState + ErrAcknowledgementTooLong = types.ErrAcknowledgementTooLong + NewMsgChannelOpenInit = types.NewMsgChannelOpenInit + NewMsgChannelOpenTry = types.NewMsgChannelOpenTry + NewMsgChannelOpenAck = types.NewMsgChannelOpenAck + NewMsgChannelOpenConfirm = types.NewMsgChannelOpenConfirm + NewMsgChannelCloseInit = types.NewMsgChannelCloseInit + NewMsgChannelCloseConfirm = types.NewMsgChannelCloseConfirm + NewMsgPacket = types.NewMsgPacket + NewMsgTimeout = types.NewMsgTimeout + NewMsgAcknowledgement = types.NewMsgAcknowledgement + NewPacket = types.NewPacket + NewChannelResponse = types.NewChannelResponse + + // variable aliases + SubModuleCdc = types.SubModuleCdc + EventTypeChannelOpenInit = types.EventTypeChannelOpenInit + EventTypeChannelOpenTry = types.EventTypeChannelOpenTry + EventTypeChannelOpenAck = types.EventTypeChannelOpenAck + EventTypeChannelOpenConfirm = types.EventTypeChannelOpenConfirm + EventTypeChannelCloseInit = types.EventTypeChannelCloseInit + EventTypeChannelCloseConfirm = types.EventTypeChannelCloseConfirm + AttributeValueCategory = types.AttributeValueCategory +) + +// nolint: golint +type ( + Keeper = keeper.Keeper + Channel = types.Channel + Counterparty = types.Counterparty + ClientKeeper = types.ClientKeeper + ConnectionKeeper = types.ConnectionKeeper + PortKeeper = types.PortKeeper + MsgChannelOpenInit = types.MsgChannelOpenInit + MsgChannelOpenTry = types.MsgChannelOpenTry + MsgChannelOpenAck = types.MsgChannelOpenAck + MsgChannelOpenConfirm = types.MsgChannelOpenConfirm + MsgChannelCloseInit = types.MsgChannelCloseInit + MsgChannelCloseConfirm = types.MsgChannelCloseConfirm + MsgPacket = types.MsgPacket + MsgAcknowledgement = types.MsgAcknowledgement + MsgTimeout = types.MsgTimeout + Packet = types.Packet + ChannelResponse = types.ChannelResponse +) diff --git a/x/ibc/04-channel/client/cli/cli.go b/x/ibc/04-channel/client/cli/cli.go new file mode 100644 index 000000000000..7c24dff1e95f --- /dev/null +++ b/x/ibc/04-channel/client/cli/cli.go @@ -0,0 +1,42 @@ +package cli + +import ( + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/codec" +) + +// GetQueryCmd returns the query commands for IBC channels +func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { + ics04ChannelQueryCmd := &cobra.Command{ + Use: "channel", + Short: "IBC channel query subcommands", + DisableFlagParsing: true, + } + + ics04ChannelQueryCmd.AddCommand(flags.GetCommands( + GetCmdQueryChannel(storeKey, cdc), + )...) + + return ics04ChannelQueryCmd +} + +// GetTxCmd returns the transaction commands for IBC channels +func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { + ics04ChannelTxCmd := &cobra.Command{ + Use: "channel", + Short: "IBC channel transaction subcommands", + } + + ics04ChannelTxCmd.AddCommand(flags.PostCommands( + GetMsgChannelOpenInitCmd(storeKey, cdc), + GetMsgChannelOpenTryCmd(storeKey, cdc), + GetMsgChannelOpenAckCmd(storeKey, cdc), + GetMsgChannelOpenConfirmCmd(storeKey, cdc), + GetMsgChannelCloseInitCmd(storeKey, cdc), + GetMsgChannelCloseConfirmCmd(storeKey, cdc), + )...) + + return ics04ChannelTxCmd +} diff --git a/x/ibc/04-channel/client/cli/query.go b/x/ibc/04-channel/client/cli/query.go new file mode 100644 index 000000000000..e04e943d33e8 --- /dev/null +++ b/x/ibc/04-channel/client/cli/query.go @@ -0,0 +1,47 @@ +package cli + +import ( + "fmt" + "strings" + + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/version" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/client/utils" +) + +// GetCmdQueryChannel defines the command to query a channel end +func GetCmdQueryChannel(queryRoute string, cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "end [port-id] [channel-id]", + Short: "Query a channel end", + Long: strings.TrimSpace(fmt.Sprintf(`Query an IBC channel end + +Example: +$ %s query ibc channel end [port-id] [channel-id] + `, version.ClientName), + ), + Example: fmt.Sprintf("%s query ibc channel end [port-id] [channel-id]", version.ClientName), + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + portID := args[0] + channelID := args[1] + prove := viper.GetBool(flags.FlagProve) + + channelRes, err := utils.QueryChannel(cliCtx, portID, channelID, prove) + if err != nil { + return err + } + + return cliCtx.PrintOutput(channelRes) + }, + } + cmd.Flags().Bool(flags.FlagProve, true, "show proofs for the query results") + + return cmd +} diff --git a/x/ibc/04-channel/client/cli/tx.go b/x/ibc/04-channel/client/cli/tx.go new file mode 100644 index 000000000000..16183ae2ec04 --- /dev/null +++ b/x/ibc/04-channel/client/cli/tx.go @@ -0,0 +1,251 @@ +package cli + +import ( + "bufio" + "strconv" + "strings" + + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + authclient "github.com/cosmos/cosmos-sdk/x/auth/client" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + connectionutils "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/client/utils" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" +) + +// IBC Channel flags +const ( + FlagOrdered = "ordered" + FlagIBCVersion = "ibc-version" +) + +// GetMsgChannelOpenInitCmd returns the command to create a MsgChannelOpenInit transaction +func GetMsgChannelOpenInitCmd(storeKey string, cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "open-init [port-id] [channel-id] [counterparty-port-id] [counterparty-channel-id] [connection-hops]", + Short: "Creates and sends a ChannelOpenInit message", + Args: cobra.ExactArgs(5), + RunE: func(cmd *cobra.Command, args []string) error { + inBuf := bufio.NewReader(cmd.InOrStdin()) + txBldr := authtypes.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) + cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) + + portID := args[0] + channelID := args[1] + counterpartyPortID := args[2] + counterpartyChannelID := args[3] + hops := strings.Split(args[4], "/") + order := channelOrder() + version := viper.GetString(FlagIBCVersion) + + msg := types.NewMsgChannelOpenInit( + portID, channelID, version, order, hops, + counterpartyPortID, counterpartyChannelID, cliCtx.GetFromAddress(), + ) + if err := msg.ValidateBasic(); err != nil { + return err + } + + return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } + + cmd.Flags().Bool(FlagOrdered, true, "Pass flag for opening ordered channels") + cmd.Flags().String(FlagIBCVersion, "1.0.0", "supported IBC version") + + return cmd +} + +// GetMsgChannelOpenTryCmd returns the command to create a MsgChannelOpenTry transaction +func GetMsgChannelOpenTryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "open-try [port-id] [channel-id] [counterparty-port-id] [counterparty-channel-id] [connection-hops] [/path/to/proof_init.json] [proof-height]", + Short: "Creates and sends a ChannelOpenTry message", + Args: cobra.ExactArgs(7), + RunE: func(cmd *cobra.Command, args []string) error { + inBuf := bufio.NewReader(cmd.InOrStdin()) + txBldr := authtypes.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) + cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) + + portID := args[0] + channelID := args[1] + counterpartyPortID := args[2] + counterpartyChannelID := args[3] + hops := strings.Split(args[4], "/") + order := channelOrder() + version := viper.GetString(FlagIBCVersion) // TODO: diferenciate between channel and counterparty versions + + proofInit, err := connectionutils.ParseProof(cliCtx.Codec, args[5]) + if err != nil { + return err + } + + proofHeight, err := strconv.ParseInt(args[6], 10, 64) + if err != nil { + return err + } + + msg := types.NewMsgChannelOpenTry( + portID, channelID, version, order, hops, + counterpartyPortID, counterpartyChannelID, version, + proofInit, uint64(proofHeight), cliCtx.GetFromAddress(), + ) + if err := msg.ValidateBasic(); err != nil { + return err + } + + return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } + cmd.Flags().Bool(FlagOrdered, true, "Pass flag for opening ordered channels") + cmd.Flags().String(FlagIBCVersion, "1.0.0", "supported IBC version") + + return cmd +} + +// GetMsgChannelOpenAckCmd returns the command to create a MsgChannelOpenAck transaction +func GetMsgChannelOpenAckCmd(storeKey string, cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "open-ack [port-id] [channel-id] [/path/to/proof_try.json] [proof-height]", + Short: "Creates and sends a ChannelOpenAck message", + Args: cobra.ExactArgs(4), + RunE: func(cmd *cobra.Command, args []string) error { + inBuf := bufio.NewReader(cmd.InOrStdin()) + txBldr := authtypes.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) + cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) + + portID := args[0] + channelID := args[1] + version := viper.GetString(FlagIBCVersion) // TODO: diferenciate between channel and counterparty versions + + proofTry, err := connectionutils.ParseProof(cliCtx.Codec, args[5]) + if err != nil { + return err + } + + proofHeight, err := strconv.ParseInt(args[3], 10, 64) + if err != nil { + return err + } + + msg := types.NewMsgChannelOpenAck( + portID, channelID, version, proofTry, uint64(proofHeight), cliCtx.GetFromAddress(), + ) + if err := msg.ValidateBasic(); err != nil { + return err + } + + return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } + cmd.Flags().String(FlagIBCVersion, "1.0.0", "supported IBC version") + return cmd +} + +// GetMsgChannelOpenConfirmCmd returns the command to create a MsgChannelOpenConfirm transaction +func GetMsgChannelOpenConfirmCmd(storeKey string, cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "open-confirm [port-id] [channel-id] [/path/to/proof_ack.json] [proof-height]", + Short: "Creates and sends a ChannelOpenConfirm message", + Args: cobra.ExactArgs(4), + RunE: func(cmd *cobra.Command, args []string) error { + inBuf := bufio.NewReader(cmd.InOrStdin()) + txBldr := authtypes.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) + cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) + + portID := args[0] + channelID := args[1] + + proofAck, err := connectionutils.ParseProof(cliCtx.Codec, args[5]) + if err != nil { + return err + } + + proofHeight, err := strconv.ParseInt(args[3], 10, 64) + if err != nil { + return err + } + + msg := types.NewMsgChannelOpenConfirm( + portID, channelID, proofAck, uint64(proofHeight), cliCtx.GetFromAddress(), + ) + if err := msg.ValidateBasic(); err != nil { + return err + } + + return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } +} + +// GetMsgChannelCloseInitCmd returns the command to create a MsgChannelCloseInit transaction +func GetMsgChannelCloseInitCmd(storeKey string, cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "close-init [port-id] [channel-id]", + Short: "Creates and sends a ChannelCloseInit message", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + inBuf := bufio.NewReader(cmd.InOrStdin()) + txBldr := authtypes.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) + cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) + + portID := args[0] + channelID := args[1] + + msg := types.NewMsgChannelCloseInit(portID, channelID, cliCtx.GetFromAddress()) + if err := msg.ValidateBasic(); err != nil { + return err + } + + return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } +} + +// GetMsgChannelCloseConfirmCmd returns the command to create a MsgChannelCloseConfirm transaction +func GetMsgChannelCloseConfirmCmd(storeKey string, cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "close-confirm [port-id] [channel-id] [/path/to/proof_init.json] [proof-height]", + Short: "Creates and sends a ChannelCloseConfirm message", + Args: cobra.ExactArgs(4), + RunE: func(cmd *cobra.Command, args []string) error { + inBuf := bufio.NewReader(cmd.InOrStdin()) + txBldr := authtypes.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) + cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) + + portID := args[0] + channelID := args[1] + + proofInit, err := connectionutils.ParseProof(cliCtx.Codec, args[5]) + if err != nil { + return err + } + + proofHeight, err := strconv.ParseInt(args[3], 10, 64) + if err != nil { + return err + } + + msg := types.NewMsgChannelCloseConfirm( + portID, channelID, proofInit, uint64(proofHeight), cliCtx.GetFromAddress(), + ) + if err := msg.ValidateBasic(); err != nil { + return err + } + + return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } +} + +func channelOrder() exported.Order { + if viper.GetBool(FlagOrdered) { + return exported.ORDERED + } + return exported.UNORDERED +} diff --git a/x/ibc/04-channel/client/rest/query.go b/x/ibc/04-channel/client/rest/query.go new file mode 100644 index 000000000000..df39614679e4 --- /dev/null +++ b/x/ibc/04-channel/client/rest/query.go @@ -0,0 +1,52 @@ +package rest + +import ( + "fmt" + "net/http" + + "github.com/gorilla/mux" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/types/rest" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/client/utils" +) + +func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router, queryRoute string) { + r.HandleFunc(fmt.Sprintf("/ibc/ports/{%s}/channels/{%s}", RestPortID, RestChannelID), queryChannelHandlerFn(cliCtx, queryRoute)).Methods("GET") +} + +// queryChannelHandlerFn implements a channel querying route +// +// @Summary Query channel +// @Tags IBC +// @Produce json +// @Param port-id path string true "Port ID" +// @Param channel-id path string true "Channel ID" +// @Param prove query boolean false "Proof of result" +// @Success 200 {object} QueryChannel "OK" +// @Failure 400 {object} rest.ErrorResponse "Invalid port id or channel id" +// @Failure 500 {object} rest.ErrorResponse "Internal Server Error" +// @Router /ibc/ports/{port-id}/channels/{channel-id} [get] +func queryChannelHandlerFn(cliCtx context.CLIContext, queryRoute string) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + portID := vars[RestPortID] + channelID := vars[RestChannelID] + prove := rest.ParseQueryParamBool(r, flags.FlagProve) + + cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) + if !ok { + return + } + + channelRes, err := utils.QueryChannel(cliCtx, portID, channelID, prove) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + + cliCtx = cliCtx.WithHeight(int64(channelRes.ProofHeight)) + rest.PostProcessResponse(w, cliCtx, channelRes) + } +} diff --git a/x/ibc/04-channel/client/rest/rest.go b/x/ibc/04-channel/client/rest/rest.go new file mode 100644 index 000000000000..2d65fc2d5817 --- /dev/null +++ b/x/ibc/04-channel/client/rest/rest.go @@ -0,0 +1,84 @@ +package rest + +import ( + "github.com/gorilla/mux" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/types/rest" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" + commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" +) + +const ( + RestChannelID = "channel-id" + RestPortID = "port-id" +) + +// RegisterRoutes - Central function to define routes that get registered by the main application +func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, queryRoute string) { + registerQueryRoutes(cliCtx, r, queryRoute) + registerTxRoutes(cliCtx, r) +} + +// ChannelOpenInitReq defines the properties of a channel open init request's body. +type ChannelOpenInitReq struct { + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + PortID string `json:"port_id" yaml:"port_id"` + ChannelID string `json:"channel_id" yaml:"channel_id"` + Version string `json:"version" yaml:"version"` + ChannelOrder exported.Order `json:"channel_order" yaml:"channel_order"` + ConnectionHops []string `json:"connection_hops" yaml:"connection_hops"` + CounterpartyPortID string `json:"counterparty_port_id" yaml:"counterparty_port_id"` + CounterpartyChannelID string `json:"counterparty_channel_id" yaml:"counterparty_channel_id"` +} + +// ChannelOpenTryReq defines the properties of a channel open try request's body. +type ChannelOpenTryReq struct { + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + PortID string `json:"port_id" yaml:"port_id"` + ChannelID string `json:"channel_id" yaml:"channel_id"` + Version string `json:"version" yaml:"version"` + ChannelOrder exported.Order `json:"channel_order" yaml:"channel_order"` + ConnectionHops []string `json:"connection_hops" yaml:"connection_hops"` + CounterpartyPortID string `json:"counterparty_port_id" yaml:"counterparty_port_id"` + CounterpartyChannelID string `json:"counterparty_channel_id" yaml:"counterparty_channel_id"` + CounterpartyVersion string `json:"counterparty_version" yaml:"counterparty_version"` + ProofInit commitmentexported.Proof `json:"proof_init" yaml:"proof_init"` + ProofHeight uint64 `json:"proof_height" yaml:"proof_height"` +} + +// ChannelOpenAckReq defines the properties of a channel open ack request's body. +type ChannelOpenAckReq struct { + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + CounterpartyVersion string `json:"counterparty_version" yaml:"counterparty_version"` + ProofTry commitmentexported.Proof `json:"proof_try" yaml:"proof_try"` + ProofHeight uint64 `json:"proof_height" yaml:"proof_height"` +} + +// ChannelOpenConfirmReq defines the properties of a channel open confirm request's body. +type ChannelOpenConfirmReq struct { + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + ProofAck commitmentexported.Proof `json:"proof_ack" yaml:"proof_ack"` + ProofHeight uint64 `json:"proof_height" yaml:"proof_height"` +} + +// ConnectionOpenInitReq defines the properties of a channel close init request's body. +type ChannelCloseInitReq struct { + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` +} + +// ChannelCloseConfirmReq defines the properties of a channel close confirm request's body. +type ChannelCloseConfirmReq struct { + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + ProofInit commitmentexported.Proof `json:"proof_init" yaml:"proof_init"` + ProofHeight uint64 `json:"proof_height" yaml:"proof_height"` +} + +// RecvPacketReq defines the properties of a receive packet request's body. +type RecvPacketReq struct { + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + Packet types.Packet `json:"packet" yaml:"packet"` + Proofs commitmentexported.Proof `json:"proofs" yaml:"proofs"` + Height uint64 `json:"height" yaml:"height"` +} diff --git a/x/ibc/04-channel/client/rest/tx.go b/x/ibc/04-channel/client/rest/tx.go new file mode 100644 index 000000000000..c48784dca1d7 --- /dev/null +++ b/x/ibc/04-channel/client/rest/tx.go @@ -0,0 +1,382 @@ +package rest + +import ( + "fmt" + "net/http" + + "github.com/gorilla/mux" + + "github.com/cosmos/cosmos-sdk/client/context" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/rest" + authclient "github.com/cosmos/cosmos-sdk/x/auth/client" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" +) + +// RegisterRoutes - Central function to define routes that get registered by the main application +func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router) { + r.HandleFunc("/ibc/channels/open-init", channelOpenInitHandlerFn(cliCtx)).Methods("POST") + r.HandleFunc("/ibc/channels/open-try", channelOpenTryHandlerFn(cliCtx)).Methods("POST") + r.HandleFunc(fmt.Sprintf("/ibc/ports/{%s}/channels/{%s}/open-ack", RestPortID, RestChannelID), channelOpenAckHandlerFn(cliCtx)).Methods("POST") + r.HandleFunc(fmt.Sprintf("/ibc/ports/{%s}/channels/{%s}/open-confirm", RestPortID, RestChannelID), channelOpenConfirmHandlerFn(cliCtx)).Methods("POST") + r.HandleFunc(fmt.Sprintf("/ibc/ports/{%s}/channels/{%s}/close-init", RestPortID, RestChannelID), channelCloseInitHandlerFn(cliCtx)).Methods("POST") + r.HandleFunc(fmt.Sprintf("/ibc/ports/{%s}/channels/{%s}/close-confirm", RestPortID, RestChannelID), channelCloseConfirmHandlerFn(cliCtx)).Methods("POST") + r.HandleFunc(fmt.Sprintf("/ibc/packets/receive"), recvPacketHandlerFn(cliCtx)).Methods("POST") +} + +// channelOpenInitHandlerFn implements a channel open init handler +// +// @Summary Channel open-init +// @Tags IBC +// @Accept json +// @Produce json +// @Param body body rest.ChannelOpenInitReq true "Channel open-init request body" +// @Success 200 {object} PostChannelOpenInit "OK" +// @Failure 500 {object} rest.ErrorResponse "Internal Server Error" +// @Router /ibc/channels/open-init [post] +func channelOpenInitHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req ChannelOpenInitReq + if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) { + return + } + + req.BaseReq = req.BaseReq.Sanitize() + if !req.BaseReq.ValidateBasic(w) { + return + } + + fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + // create the message + msg := types.NewMsgChannelOpenInit( + req.PortID, + req.ChannelID, + req.Version, + req.ChannelOrder, + req.ConnectionHops, + req.CounterpartyPortID, + req.CounterpartyChannelID, + fromAddr, + ) + + if err := msg.ValidateBasic(); err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) + } +} + +// channelOpenTryHandlerFn implements a channel open try handler +// +// @Summary Channel open-try +// @Tags IBC +// @Accept json +// @Produce json +// @Param body body rest.ChannelOpenTryReq true "Channel open-try request body" +// @Success 200 {object} PostChannelOpenTry "OK" +// @Failure 500 {object} rest.ErrorResponse "Internal Server Error" +// @Router /ibc/channels/open-try [post] +func channelOpenTryHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req ChannelOpenTryReq + if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) { + return + } + + req.BaseReq = req.BaseReq.Sanitize() + if !req.BaseReq.ValidateBasic(w) { + return + } + + fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + // create the message + msg := types.NewMsgChannelOpenTry( + req.PortID, + req.ChannelID, + req.Version, + req.ChannelOrder, + req.ConnectionHops, + req.CounterpartyPortID, + req.CounterpartyChannelID, + req.CounterpartyVersion, + req.ProofInit, + req.ProofHeight, + fromAddr, + ) + + if err := msg.ValidateBasic(); err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) + } +} + +// channelOpenAckHandlerFn implements a channel open ack handler +// +// @Summary Channel open-ack +// @Tags IBC +// @Accept json +// @Produce json +// @Param port-id path string true "Port ID" +// @Param channel-id path string true "Channel ID" +// @Param body body rest.ChannelOpenAckReq true "Channel open-ack request body" +// @Success 200 {object} PostChannelOpenAck "OK" +// @Failure 400 {object} rest.ErrorResponse "Invalid port id or channel id" +// @Failure 500 {object} rest.ErrorResponse "Internal Server Error" +// @Router /ibc/ports/{port-id}/channels/{channel-id}/open-ack [post] +func channelOpenAckHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + portID := vars[RestPortID] + channelID := vars[RestChannelID] + + var req ChannelOpenAckReq + if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) { + return + } + + req.BaseReq = req.BaseReq.Sanitize() + if !req.BaseReq.ValidateBasic(w) { + return + } + + fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + // create the message + msg := types.NewMsgChannelOpenAck( + portID, + channelID, + req.CounterpartyVersion, + req.ProofTry, + req.ProofHeight, + fromAddr, + ) + + if err := msg.ValidateBasic(); err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) + } +} + +// channelOpenConfirmHandlerFn implements a channel open confirm handler +// +// @Summary Channel open-confirm +// @Tags IBC +// @Accept json +// @Produce json +// @Param port-id path string true "Port ID" +// @Param channel-id path string true "Channel ID" +// @Param body body rest.ChannelOpenConfirmReq true "Channel open-confirm request body" +// @Success 200 {object} PostChannelOpenConfirm "OK" +// @Failure 400 {object} rest.ErrorResponse "Invalid port id or channel id" +// @Failure 500 {object} rest.ErrorResponse "Internal Server Error" +// @Router /ibc/ports/{port-id}/channels/{channel-id}/open-confirm [post] +func channelOpenConfirmHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + portID := vars[RestPortID] + channelID := vars[RestChannelID] + + var req ChannelOpenConfirmReq + if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) { + return + } + + req.BaseReq = req.BaseReq.Sanitize() + if !req.BaseReq.ValidateBasic(w) { + return + } + + fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + // create the message + msg := types.NewMsgChannelOpenConfirm( + portID, + channelID, + req.ProofAck, + req.ProofHeight, + fromAddr, + ) + + if err := msg.ValidateBasic(); err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) + } +} + +// channelCloseInitHandlerFn implements a channel close init handler +// +// @Summary Channel close-init +// @Tags IBC +// @Accept json +// @Produce json +// @Param port-id path string true "Port ID" +// @Param channel-id path string true "Channel ID" +// @Param body body rest.ChannelCloseInitReq true "Channel close-init request body" +// @Success 200 {object} PostChannelCloseInit "OK" +// @Failure 400 {object} rest.ErrorResponse "Invalid port id or channel id" +// @Failure 500 {object} rest.ErrorResponse "Internal Server Error" +// @Router /ibc/ports/{port-id}/channels/{channel-id}/close-init [post] +func channelCloseInitHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + portID := vars[RestPortID] + channelID := vars[RestChannelID] + + var req ChannelCloseInitReq + if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) { + return + } + + req.BaseReq = req.BaseReq.Sanitize() + if !req.BaseReq.ValidateBasic(w) { + return + } + + fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + // create the message + msg := types.NewMsgChannelCloseInit( + portID, + channelID, + fromAddr, + ) + + if err := msg.ValidateBasic(); err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) + } +} + +// channelCloseConfirmHandlerFn implements a channel close confirm handler +// +// @Summary Channel close-confirm +// @Tags IBC +// @Accept json +// @Produce json +// @Param port-id path string true "Port ID" +// @Param channel-id path string true "Channel ID" +// @Param body body rest.ChannelCloseConfirmReq true "Channel close-confirm request body" +// @Success 200 {object} PostChannelCloseConfirm "OK" +// @Failure 400 {object} rest.ErrorResponse "Invalid port id or channel id" +// @Failure 500 {object} rest.ErrorResponse "Internal Server Error" +// @Router /ibc/ports/{port-id}/channels/{channel-id}/close-confirm [post] +func channelCloseConfirmHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + portID := vars[RestPortID] + channelID := vars[RestChannelID] + + var req ChannelCloseConfirmReq + if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) { + return + } + + req.BaseReq = req.BaseReq.Sanitize() + if !req.BaseReq.ValidateBasic(w) { + return + } + + fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + // create the message + msg := types.NewMsgChannelCloseConfirm( + portID, + channelID, + req.ProofInit, + req.ProofHeight, + fromAddr, + ) + + if err := msg.ValidateBasic(); err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) + } +} + +// recvPacketHandlerFn implements a receive packet handler +// +// @Summary Receive packet +// @Tags IBC +// @Accept json +// @Produce json +// @Param body body rest.RecvPacketReq true "Receive packet request body" +// @Success 200 {object} PostRecvPacket "OK" +// @Failure 500 {object} rest.ErrorResponse "Internal Server Error" +// @Router /ibc/packets/receive [post] +func recvPacketHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req RecvPacketReq + if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) { + return + } + + req.BaseReq = req.BaseReq.Sanitize() + if !req.BaseReq.ValidateBasic(w) { + return + } + + fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + // create the message + msg := types.NewMsgPacket( + req.Packet, + req.Proofs, + req.Height, + fromAddr, + ) + + if err := msg.ValidateBasic(); err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) + } +} diff --git a/x/ibc/04-channel/client/utils/utils.go b/x/ibc/04-channel/client/utils/utils.go new file mode 100644 index 000000000000..729fad9d1d2e --- /dev/null +++ b/x/ibc/04-channel/client/utils/utils.go @@ -0,0 +1,69 @@ +package utils + +import ( + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +// QueryPacket returns a packet from the store +func QueryPacket( + ctx context.CLIContext, portID, channelID string, + sequence, timeout uint64, prove bool, +) (types.PacketResponse, error) { + req := abci.RequestQuery{ + Path: "store/ibc/key", + Data: ibctypes.KeyPacketCommitment(portID, channelID, sequence), + Prove: prove, + } + + res, err := ctx.QueryABCI(req) + if err != nil { + return types.PacketResponse{}, err + } + + channelRes, err := QueryChannel(ctx, portID, channelID, prove) + if err != nil { + return types.PacketResponse{}, err + } + + destPortID := channelRes.Channel.Channel.Counterparty.PortID + destChannelID := channelRes.Channel.Channel.Counterparty.ChannelID + + packet := types.NewPacket( + res.Value, + sequence, + portID, + channelID, + destPortID, + destChannelID, + timeout, + ) + + // FIXME: res.Height+1 is hack, fix later + return types.NewPacketResponse(portID, channelID, sequence, packet, res.Proof, res.Height+1), nil +} + +// QueryChannel queries the store to get a channel and a merkle proof. +func QueryChannel( + ctx context.CLIContext, portID, channelID string, prove bool, +) (types.ChannelResponse, error) { + req := abci.RequestQuery{ + Path: "store/ibc/key", + Data: ibctypes.KeyChannel(portID, channelID), + Prove: prove, + } + + res, err := ctx.QueryABCI(req) + if res.Value == nil || err != nil { + return types.ChannelResponse{}, err + } + + var channel types.Channel + if err := ctx.Codec.UnmarshalBinaryLengthPrefixed(res.Value, &channel); err != nil { + return types.ChannelResponse{}, err + } + return types.NewChannelResponse(portID, channelID, channel, res.Proof, res.Height), nil +} diff --git a/x/ibc/04-channel/exported/exported.go b/x/ibc/04-channel/exported/exported.go new file mode 100644 index 000000000000..850b13d7dc3e --- /dev/null +++ b/x/ibc/04-channel/exported/exported.go @@ -0,0 +1,170 @@ +package exported + +import ( + "encoding/json" + "fmt" +) + +// ChannelI defines the standard interface for a channel end. +type ChannelI interface { + GetState() State + GetOrdering() Order + GetCounterparty() CounterpartyI + GetConnectionHops() []string + GetVersion() string + ValidateBasic() error +} + +// CounterpartyI defines the standard interface for a channel end's +// counterparty. +type CounterpartyI interface { + GetPortID() string + GetChannelID() string + ValidateBasic() error +} + +// PacketI defines the standard interface for IBC packets +type PacketI interface { + GetSequence() uint64 + GetTimeoutHeight() uint64 + GetSourcePort() string + GetSourceChannel() string + GetDestPort() string + GetDestChannel() string + GetData() []byte + ValidateBasic() error +} + +// Order defines if a channel is ORDERED or UNORDERED +type Order byte + +// string representation of the channel ordering +const ( + NONE Order = iota // zero-value for channel ordering + UNORDERED // packets can be delivered in any order, which may differ from the order in which they were sent. + ORDERED // packets are delivered exactly in the order which they were sent +) + +// channel order types +const ( + OrderNone string = "" + OrderUnordered string = "UNORDERED" + OrderOrdered string = "ORDERED" +) + +// String implements the Stringer interface +func (o Order) String() string { + switch o { + case UNORDERED: + return OrderUnordered + case ORDERED: + return OrderOrdered + default: + return OrderNone + } +} + +// MarshalJSON marshal to JSON using string. +func (o Order) MarshalJSON() ([]byte, error) { + return json.Marshal(o.String()) +} + +// UnmarshalJSON decodes from JSON. +func (o *Order) UnmarshalJSON(data []byte) error { + var s string + err := json.Unmarshal(data, &s) + if err != nil { + return err + } + + order := OrderFromString(s) + if order == 0 { + return fmt.Errorf("invalid order '%s'", s) + } + + *o = order + return nil +} + +// OrderFromString parses a string into a channel order byte +func OrderFromString(order string) Order { + switch order { + case OrderUnordered: + return UNORDERED + case OrderOrdered: + return ORDERED + default: + return NONE + } +} + +// State defines if a channel is in one of the following states: +// CLOSED, INIT, OPENTRY or OPEN +type State byte + +// channel state types +const ( + UNINITIALIZED State = iota // Default State + INIT // A channel end has just started the opening handshake. + TRYOPEN // A channel end has acknowledged the handshake step on the counterparty chain. + OPEN // A channel end has completed the handshake and is ready to send and receive packets. + CLOSED // A channel end has been closed and can no longer be used to send or receive packets. +) + +// string representation of the channel states +const ( + StateUninitialized string = "UNINITIALIZED" + StateInit string = "INIT" + StateTryOpen string = "TRYOPEN" + StateOpen string = "OPEN" + StateClosed string = "CLOSED" +) + +// String implements the Stringer interface +func (s State) String() string { + switch s { + case INIT: + return StateInit + case TRYOPEN: + return StateTryOpen + case OPEN: + return StateOpen + case CLOSED: + return StateClosed + default: + return StateUninitialized + } +} + +// MarshalJSON marshal to JSON using string. +func (s State) MarshalJSON() ([]byte, error) { + return json.Marshal(s.String()) +} + +// UnmarshalJSON decodes from JSON. +func (s *State) UnmarshalJSON(data []byte) error { + var stateStr string + err := json.Unmarshal(data, &stateStr) + if err != nil { + return err + } + + *s = StateFromString(stateStr) + return nil +} + +// StateFromString parses a string into a channel state byte +func StateFromString(state string) State { + switch state { + case StateClosed: + return CLOSED + case StateInit: + return INIT + case StateTryOpen: + return TRYOPEN + case StateOpen: + return OPEN + default: + return UNINITIALIZED + } +} diff --git a/x/ibc/04-channel/exported/exported_test.go b/x/ibc/04-channel/exported/exported_test.go new file mode 100644 index 000000000000..51d94bfdebb1 --- /dev/null +++ b/x/ibc/04-channel/exported/exported_test.go @@ -0,0 +1,91 @@ +package exported + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestChannelStateString(t *testing.T) { + cases := []struct { + name string + state State + }{ + {StateUninitialized, UNINITIALIZED}, + {StateInit, INIT}, + {StateTryOpen, TRYOPEN}, + {StateOpen, OPEN}, + {StateClosed, CLOSED}, + } + + for _, tt := range cases { + tt := tt + require.Equal(t, tt.state, StateFromString(tt.name)) + require.Equal(t, tt.name, tt.state.String()) + } +} + +func TestChannelStateMarshalJSON(t *testing.T) { + cases := []struct { + name string + state State + }{ + {StateUninitialized, UNINITIALIZED}, + {StateInit, INIT}, + {StateTryOpen, TRYOPEN}, + {StateOpen, OPEN}, + {StateClosed, CLOSED}, + } + + for _, tt := range cases { + tt := tt + bz, err := tt.state.MarshalJSON() + require.NoError(t, err) + var state State + require.NoError(t, state.UnmarshalJSON(bz)) + require.Equal(t, tt.name, state.String()) + } +} + +func TestOrderString(t *testing.T) { + cases := []struct { + name string + order Order + }{ + {OrderNone, NONE}, + {OrderUnordered, UNORDERED}, + {OrderOrdered, ORDERED}, + } + + for _, tt := range cases { + tt := tt + require.Equal(t, tt.order, OrderFromString(tt.name)) + require.Equal(t, tt.name, tt.order.String()) + } +} + +func TestOrderMarshalJSON(t *testing.T) { + cases := []struct { + msg string + name string + order Order + expectPass bool + }{ + {"none ordering should have failed", OrderNone, NONE, false}, + {"unordered should have passed", OrderUnordered, UNORDERED, true}, + {"ordered should have passed", OrderOrdered, ORDERED, true}, + } + + for _, tt := range cases { + tt := tt + bz, err := tt.order.MarshalJSON() + require.NoError(t, err) + var order Order + if tt.expectPass { + require.NoError(t, order.UnmarshalJSON(bz), tt.msg) + require.Equal(t, tt.name, order.String(), tt.msg) + } else { + require.Error(t, order.UnmarshalJSON(bz), tt.msg) + } + } +} diff --git a/x/ibc/04-channel/handler.go b/x/ibc/04-channel/handler.go new file mode 100644 index 000000000000..4b1c27c0e3d7 --- /dev/null +++ b/x/ibc/04-channel/handler.go @@ -0,0 +1,171 @@ +package channel + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/capability" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/keeper" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" +) + +// HandleMsgChannelOpenInit defines the sdk.Handler for MsgChannelOpenInit +func HandleMsgChannelOpenInit(ctx sdk.Context, k keeper.Keeper, portCap *capability.Capability, msg types.MsgChannelOpenInit) (*sdk.Result, *capability.Capability, error) { + capKey, err := k.ChanOpenInit( + ctx, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.PortID, msg.ChannelID, + portCap, msg.Channel.Counterparty, msg.Channel.Version, + ) + if err != nil { + return nil, nil, err + } + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeChannelOpenInit, + sdk.NewAttribute(types.AttributeKeyPortID, msg.PortID), + sdk.NewAttribute(types.AttributeKeyChannelID, msg.ChannelID), + sdk.NewAttribute(types.AttributeCounterpartyPortID, msg.Channel.Counterparty.PortID), + sdk.NewAttribute(types.AttributeCounterpartyChannelID, msg.Channel.Counterparty.ChannelID), + sdk.NewAttribute(types.AttributeKeyConnectionID, msg.Channel.ConnectionHops[0]), // TODO: iterate + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), + ), + }) + + return &sdk.Result{ + Events: ctx.EventManager().Events().ToABCIEvents(), + }, capKey, nil +} + +// HandleMsgChannelOpenTry defines the sdk.Handler for MsgChannelOpenTry +func HandleMsgChannelOpenTry(ctx sdk.Context, k keeper.Keeper, portCap *capability.Capability, msg types.MsgChannelOpenTry) (*sdk.Result, *capability.Capability, error) { + capKey, err := k.ChanOpenTry(ctx, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.PortID, msg.ChannelID, + portCap, msg.Channel.Counterparty, msg.Channel.Version, msg.CounterpartyVersion, msg.ProofInit, msg.ProofHeight, + ) + if err != nil { + return nil, nil, err + } + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeChannelOpenTry, + sdk.NewAttribute(types.AttributeKeyPortID, msg.PortID), + sdk.NewAttribute(types.AttributeKeyChannelID, msg.ChannelID), + sdk.NewAttribute(types.AttributeCounterpartyPortID, msg.Channel.Counterparty.PortID), + sdk.NewAttribute(types.AttributeCounterpartyChannelID, msg.Channel.Counterparty.ChannelID), + sdk.NewAttribute(types.AttributeKeyConnectionID, msg.Channel.ConnectionHops[0]), // TODO: iterate + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), + ), + }) + + return &sdk.Result{ + Events: ctx.EventManager().Events().ToABCIEvents(), + }, capKey, nil +} + +// HandleMsgChannelOpenAck defines the sdk.Handler for MsgChannelOpenAck +func HandleMsgChannelOpenAck(ctx sdk.Context, k keeper.Keeper, channelCap *capability.Capability, msg types.MsgChannelOpenAck) (*sdk.Result, error) { + err := k.ChanOpenAck( + ctx, msg.PortID, msg.ChannelID, channelCap, msg.CounterpartyVersion, msg.ProofTry, msg.ProofHeight, + ) + if err != nil { + return nil, err + } + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeChannelOpenAck, + sdk.NewAttribute(types.AttributeKeyPortID, msg.PortID), + sdk.NewAttribute(types.AttributeKeyChannelID, msg.ChannelID), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), + ), + }) + + return &sdk.Result{ + Events: ctx.EventManager().Events().ToABCIEvents(), + }, nil +} + +// HandleMsgChannelOpenConfirm defines the sdk.Handler for MsgChannelOpenConfirm +func HandleMsgChannelOpenConfirm(ctx sdk.Context, k keeper.Keeper, channelCap *capability.Capability, msg types.MsgChannelOpenConfirm) (*sdk.Result, error) { + err := k.ChanOpenConfirm(ctx, msg.PortID, msg.ChannelID, channelCap, msg.ProofAck, msg.ProofHeight) + if err != nil { + return nil, err + } + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeChannelOpenConfirm, + sdk.NewAttribute(types.AttributeKeyPortID, msg.PortID), + sdk.NewAttribute(types.AttributeKeyChannelID, msg.ChannelID), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), + ), + }) + + return &sdk.Result{ + Events: ctx.EventManager().Events().ToABCIEvents(), + }, nil +} + +// HandleMsgChannelCloseInit defines the sdk.Handler for MsgChannelCloseInit +func HandleMsgChannelCloseInit(ctx sdk.Context, k keeper.Keeper, channelCap *capability.Capability, msg types.MsgChannelCloseInit) (*sdk.Result, error) { + err := k.ChanCloseInit(ctx, msg.PortID, msg.ChannelID, channelCap) + if err != nil { + return nil, err + } + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeChannelCloseInit, + sdk.NewAttribute(types.AttributeKeyPortID, msg.PortID), + sdk.NewAttribute(types.AttributeKeyChannelID, msg.ChannelID), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), + ), + }) + + return &sdk.Result{ + Events: ctx.EventManager().Events().ToABCIEvents(), + }, nil +} + +// HandleMsgChannelCloseConfirm defines the sdk.Handler for MsgChannelCloseConfirm +func HandleMsgChannelCloseConfirm(ctx sdk.Context, k keeper.Keeper, channelCap *capability.Capability, msg types.MsgChannelCloseConfirm) (*sdk.Result, error) { + err := k.ChanCloseConfirm(ctx, msg.PortID, msg.ChannelID, channelCap, msg.ProofInit, msg.ProofHeight) + if err != nil { + return nil, err + } + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeChannelCloseConfirm, + sdk.NewAttribute(types.AttributeKeyPortID, msg.PortID), + sdk.NewAttribute(types.AttributeKeyChannelID, msg.ChannelID), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), + ), + }) + + return &sdk.Result{ + Events: ctx.EventManager().Events().ToABCIEvents(), + }, nil +} diff --git a/x/ibc/04-channel/keeper/handshake.go b/x/ibc/04-channel/keeper/handshake.go new file mode 100644 index 000000000000..c836314c1836 --- /dev/null +++ b/x/ibc/04-channel/keeper/handshake.go @@ -0,0 +1,393 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/capability" + connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" + connectionexported "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported" + + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" + porttypes "github.com/cosmos/cosmos-sdk/x/ibc/05-port/types" + commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +// CounterpartyHops returns the connection hops of the counterparty channel. +// The counterparty hops are stored in the inverse order as the channel's. +func (k Keeper) CounterpartyHops(ctx sdk.Context, ch types.Channel) ([]string, bool) { + counterPartyHops := make([]string, len(ch.ConnectionHops)) + for i, hop := range ch.ConnectionHops { + connection, found := k.connectionKeeper.GetConnection(ctx, hop) + if !found { + return []string{}, false + } + counterPartyHops[len(counterPartyHops)-1-i] = connection.GetCounterparty().GetConnectionID() + } + return counterPartyHops, true +} + +// ChanOpenInit is called by a module to initiate a channel opening handshake with +// a module on another chain. +func (k Keeper) ChanOpenInit( + ctx sdk.Context, + order exported.Order, + connectionHops []string, + portID, + channelID string, + portCap *capability.Capability, + counterparty types.Counterparty, + version string, +) (*capability.Capability, error) { + // channel identifier and connection hop length checked on msg.ValidateBasic() + + _, found := k.GetChannel(ctx, portID, channelID) + if found { + return nil, sdkerrors.Wrap(types.ErrChannelExists, channelID) + } + + connectionEnd, found := k.connectionKeeper.GetConnection(ctx, connectionHops[0]) + if !found { + return nil, sdkerrors.Wrap(connection.ErrConnectionNotFound, connectionHops[0]) + } + + if connectionEnd.GetState() == connectionexported.UNINITIALIZED { + return nil, sdkerrors.Wrap( + connection.ErrInvalidConnectionState, + "connection state cannot be UNINITIALIZED", + ) + } + + if !k.portKeeper.Authenticate(ctx, portCap, portID) { + return nil, sdkerrors.Wrap(porttypes.ErrInvalidPort, "caller does not own port capability") + } + + channel := types.NewChannel(exported.INIT, order, counterparty, connectionHops, version) + k.SetChannel(ctx, portID, channelID, channel) + + capKey, err := k.scopedKeeper.NewCapability(ctx, ibctypes.ChannelCapabilityPath(portID, channelID)) + if err != nil { + return nil, sdkerrors.Wrap(types.ErrInvalidChannelCapability, err.Error()) + } + k.SetNextSequenceSend(ctx, portID, channelID, 1) + k.SetNextSequenceRecv(ctx, portID, channelID, 1) + + return capKey, nil +} + +// ChanOpenTry is called by a module to accept the first step of a channel opening +// handshake initiated by a module on another chain. +func (k Keeper) ChanOpenTry( + ctx sdk.Context, + order exported.Order, + connectionHops []string, + portID, + channelID string, + portCap *capability.Capability, + counterparty types.Counterparty, + version, + counterpartyVersion string, + proofInit commitmentexported.Proof, + proofHeight uint64, +) (*capability.Capability, error) { + // channel identifier and connection hop length checked on msg.ValidateBasic() + + previousChannel, found := k.GetChannel(ctx, portID, channelID) + if found && !(previousChannel.State == exported.INIT && + previousChannel.Ordering == order && + previousChannel.Counterparty.PortID == counterparty.PortID && + previousChannel.Counterparty.ChannelID == counterparty.ChannelID && + previousChannel.ConnectionHops[0] == connectionHops[0] && + previousChannel.Version == version) { + sdkerrors.Wrap(types.ErrInvalidChannel, "cannot relay connection attempt") + } + + if !k.portKeeper.Authenticate(ctx, portCap, portID) { + return nil, sdkerrors.Wrap(porttypes.ErrInvalidPort, "caller does not own port capability") + } + + connectionEnd, found := k.connectionKeeper.GetConnection(ctx, connectionHops[0]) + if !found { + return nil, sdkerrors.Wrap(connection.ErrConnectionNotFound, connectionHops[0]) + } + + if connectionEnd.GetState() != connectionexported.OPEN { + return nil, sdkerrors.Wrapf( + connection.ErrInvalidConnectionState, + "connection state is not OPEN (got %s)", connectionEnd.GetState().String(), + ) + } + + // NOTE: this step has been switched with the one below to reverse the connection + // hops + channel := types.NewChannel(exported.TRYOPEN, order, counterparty, connectionHops, version) + + counterpartyHops, found := k.CounterpartyHops(ctx, channel) + if !found { + // should not reach here, connectionEnd was able to be retrieved above + panic("cannot find connection") + } + + // expectedCounterpaty is the counterparty of the counterparty's channel end + // (i.e self) + expectedCounterparty := types.NewCounterparty(portID, channelID) + expectedChannel := types.NewChannel( + exported.INIT, channel.Ordering, expectedCounterparty, + counterpartyHops, channel.Version, + ) + + if err := k.connectionKeeper.VerifyChannelState( + ctx, connectionEnd, proofHeight, proofInit, + counterparty.PortID, counterparty.ChannelID, expectedChannel, + ); err != nil { + return nil, err + } + + k.SetChannel(ctx, portID, channelID, channel) + + capKey, err := k.scopedKeeper.NewCapability(ctx, ibctypes.ChannelCapabilityPath(portID, channelID)) + if err != nil { + return nil, sdkerrors.Wrap(types.ErrInvalidChannelCapability, err.Error()) + } + k.SetNextSequenceSend(ctx, portID, channelID, 1) + k.SetNextSequenceRecv(ctx, portID, channelID, 1) + + return capKey, nil +} + +// ChanOpenAck is called by the handshake-originating module to acknowledge the +// acceptance of the initial request by the counterparty module on the other chain. +func (k Keeper) ChanOpenAck( + ctx sdk.Context, + portID, + channelID string, + chanCap *capability.Capability, + counterpartyVersion string, + proofTry commitmentexported.Proof, + proofHeight uint64, +) error { + channel, found := k.GetChannel(ctx, portID, channelID) + if !found { + return sdkerrors.Wrap(types.ErrChannelNotFound, channelID) + } + + if !(channel.State == exported.INIT || channel.State == exported.TRYOPEN) { + return sdkerrors.Wrapf( + types.ErrInvalidChannelState, + "channel state should be INIT or TRYOPEN (got %s)", channel.State.String(), + ) + } + + if !k.scopedKeeper.AuthenticateCapability(ctx, chanCap, ibctypes.ChannelCapabilityPath(portID, channelID)) { + return sdkerrors.Wrap(types.ErrChannelCapabilityNotFound, "caller does not own capability for channel") + } + + connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) + if !found { + return sdkerrors.Wrap(connection.ErrConnectionNotFound, channel.ConnectionHops[0]) + } + + if connectionEnd.GetState() != connectionexported.OPEN { + return sdkerrors.Wrapf( + connection.ErrInvalidConnectionState, + "connection state is not OPEN (got %s)", connectionEnd.GetState().String(), + ) + } + + counterpartyHops, found := k.CounterpartyHops(ctx, channel) + if !found { + // should not reach here, connectionEnd was able to be retrieved above + panic("cannot find connection") + } + + // counterparty of the counterparty channel end (i.e self) + counterparty := types.NewCounterparty(portID, channelID) + expectedChannel := types.NewChannel( + exported.TRYOPEN, channel.Ordering, counterparty, + counterpartyHops, channel.Version, + ) + + if err := k.connectionKeeper.VerifyChannelState( + ctx, connectionEnd, proofHeight, proofTry, + channel.Counterparty.PortID, channel.Counterparty.ChannelID, + expectedChannel, + ); err != nil { + return err + } + + channel.State = exported.OPEN + channel.Version = counterpartyVersion + k.SetChannel(ctx, portID, channelID, channel) + + return nil +} + +// ChanOpenConfirm is called by the counterparty module to close their end of the +// channel, since the other end has been closed. +func (k Keeper) ChanOpenConfirm( + ctx sdk.Context, + portID, + channelID string, + chanCap *capability.Capability, + proofAck commitmentexported.Proof, + proofHeight uint64, +) error { + channel, found := k.GetChannel(ctx, portID, channelID) + if !found { + return sdkerrors.Wrap(types.ErrChannelNotFound, channelID) + } + + if channel.State != exported.TRYOPEN { + return sdkerrors.Wrapf( + types.ErrInvalidChannelState, + "channel state is not TRYOPEN (got %s)", channel.State.String(), + ) + } + + if !k.scopedKeeper.AuthenticateCapability(ctx, chanCap, ibctypes.ChannelCapabilityPath(portID, channelID)) { + return sdkerrors.Wrap(types.ErrChannelCapabilityNotFound, "caller does not own capability for channel") + } + + connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) + if !found { + return sdkerrors.Wrap(connection.ErrConnectionNotFound, channel.ConnectionHops[0]) + } + + if connectionEnd.GetState() != connectionexported.OPEN { + return sdkerrors.Wrapf( + connection.ErrInvalidConnectionState, + "connection state is not OPEN (got %s)", connectionEnd.GetState().String(), + ) + } + + counterpartyHops, found := k.CounterpartyHops(ctx, channel) + if !found { + // Should not reach here, connectionEnd was able to be retrieved above + panic("cannot find connection") + } + + counterparty := types.NewCounterparty(portID, channelID) + expectedChannel := types.NewChannel( + exported.OPEN, channel.Ordering, counterparty, + counterpartyHops, channel.Version, + ) + + if err := k.connectionKeeper.VerifyChannelState( + ctx, connectionEnd, proofHeight, proofAck, + channel.Counterparty.PortID, channel.Counterparty.ChannelID, + expectedChannel, + ); err != nil { + return err + } + + channel.State = exported.OPEN + k.SetChannel(ctx, portID, channelID, channel) + + return nil +} + +// Closing Handshake +// +// This section defines the set of functions required to close a channel handshake +// as defined in https://github.com/cosmos/ics/tree/master/spec/ics-004-channel-and-packet-semantics#closing-handshake + +// ChanCloseInit is called by either module to close their end of the channel. Once +// closed, channels cannot be reopened. +func (k Keeper) ChanCloseInit( + ctx sdk.Context, + portID, + channelID string, + chanCap *capability.Capability, +) error { + if !k.scopedKeeper.AuthenticateCapability(ctx, chanCap, ibctypes.ChannelCapabilityPath(portID, channelID)) { + return sdkerrors.Wrap(types.ErrChannelCapabilityNotFound, "caller does not own capability for channel") + } + + channel, found := k.GetChannel(ctx, portID, channelID) + if !found { + return sdkerrors.Wrap(types.ErrChannelNotFound, channelID) + } + + if channel.State == exported.CLOSED { + return sdkerrors.Wrap(types.ErrInvalidChannelState, "channel is already CLOSED") + } + + connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) + if !found { + return sdkerrors.Wrap(connection.ErrConnectionNotFound, channel.ConnectionHops[0]) + } + + if connectionEnd.GetState() != connectionexported.OPEN { + return sdkerrors.Wrapf( + connection.ErrInvalidConnectionState, + "connection state is not OPEN (got %s)", connectionEnd.GetState().String(), + ) + } + + channel.State = exported.CLOSED + k.SetChannel(ctx, portID, channelID, channel) + k.Logger(ctx).Info("channel close initialized: portID (%s), channelID (%s)", portID, channelID) + return nil +} + +// ChanCloseConfirm is called by the counterparty module to close their end of the +// channel, since the other end has been closed. +func (k Keeper) ChanCloseConfirm( + ctx sdk.Context, + portID, + channelID string, + chanCap *capability.Capability, + proofInit commitmentexported.Proof, + proofHeight uint64, +) error { + if !k.scopedKeeper.AuthenticateCapability(ctx, chanCap, ibctypes.ChannelCapabilityPath(portID, channelID)) { + return sdkerrors.Wrap(types.ErrChannelCapabilityNotFound, "caller does not own capability for channel") + } + + channel, found := k.GetChannel(ctx, portID, channelID) + if !found { + return sdkerrors.Wrap(types.ErrChannelNotFound, channelID) + } + + if channel.State == exported.CLOSED { + return sdkerrors.Wrap(types.ErrInvalidChannelState, "channel is already CLOSED") + } + + connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) + if !found { + return sdkerrors.Wrap(connection.ErrConnectionNotFound, channel.ConnectionHops[0]) + } + + if connectionEnd.GetState() != connectionexported.OPEN { + return sdkerrors.Wrapf( + connection.ErrInvalidConnectionState, + "connection state is not OPEN (got %s)", connectionEnd.GetState().String(), + ) + } + + counterpartyHops, found := k.CounterpartyHops(ctx, channel) + if !found { + // Should not reach here, connectionEnd was able to be retrieved above + panic("cannot find connection") + } + + counterparty := types.NewCounterparty(portID, channelID) + expectedChannel := types.NewChannel( + exported.CLOSED, channel.Ordering, counterparty, + counterpartyHops, channel.Version, + ) + + if err := k.connectionKeeper.VerifyChannelState( + ctx, connectionEnd, proofHeight, proofInit, + channel.Counterparty.PortID, channel.Counterparty.ChannelID, + expectedChannel, + ); err != nil { + return err + } + + channel.State = exported.CLOSED + k.SetChannel(ctx, portID, channelID, channel) + + return nil +} diff --git a/x/ibc/04-channel/keeper/handshake_test.go b/x/ibc/04-channel/keeper/handshake_test.go new file mode 100644 index 000000000000..eefb7a30cf4d --- /dev/null +++ b/x/ibc/04-channel/keeper/handshake_test.go @@ -0,0 +1,629 @@ +package keeper_test + +import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/x/capability" + connectionexported "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" + porttypes "github.com/cosmos/cosmos-sdk/x/ibc/05-port/types" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +func (suite *KeeperTestSuite) TestChanOpenInit() { + counterparty := types.NewCounterparty(testPort2, testChannel2) + + var portCap *capability.Capability + testCases := []testCase{ + {"success", func() { + suite.chainA.createConnection( + testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, + connectionexported.INIT, + ) + }, true}, + {"channel already exists", func() { + suite.chainA.createChannel( + testPort1, testChannel1, testPort2, testChannel2, exported.INIT, + exported.ORDERED, testConnectionIDA, + ) + }, false}, + {"connection doesn't exist", func() {}, false}, + {"connection is UNINITIALIZED", func() { + suite.chainA.createConnection( + testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, + connectionexported.UNINITIALIZED, + ) + }, false}, + {"capability is incorrect", func() { + suite.chainA.createConnection( + testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, + connectionexported.INIT, + ) + portCap = capability.NewCapability(3) + }, false}, + } + + for i, tc := range testCases { + tc := tc + i := i + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + suite.SetupTest() // reset + + var err error + portCap, err = suite.chainA.App.ScopedIBCKeeper.NewCapability( + suite.chainA.GetContext(), porttypes.PortPath(testPort1), + ) + suite.Require().NoError(err, "could not create capability") + + tc.malleate() + cap, err := suite.chainA.App.IBCKeeper.ChannelKeeper.ChanOpenInit( + suite.chainA.GetContext(), exported.ORDERED, []string{testConnectionIDA}, + testPort1, testChannel1, portCap, counterparty, testChannelVersion, + ) + + if tc.expPass { + suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg) + suite.Require().NotNil(cap) + chanCap, ok := suite.chainA.App.ScopedIBCKeeper.GetCapability( + suite.chainA.GetContext(), + ibctypes.ChannelCapabilityPath(testPort1, testChannel1), + ) + suite.Require().True(ok, "could not retrieve channel capapbility after successful ChanOpenInit") + suite.Require().Equal(chanCap.String(), cap.String(), "channel capability is not correct") + } else { + suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg) + } + }) + } +} + +func (suite *KeeperTestSuite) TestChanOpenTry() { + counterparty := types.NewCounterparty(testPort1, testChannel1) + channelKey := ibctypes.KeyChannel(testPort1, testChannel1) + + var portCap *capability.Capability + testCases := []testCase{ + {"success", func() { + suite.chainA.CreateClient(suite.chainB) + suite.chainB.CreateClient(suite.chainA) + _ = suite.chainA.createConnection( + testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, + connectionexported.OPEN, + ) + suite.chainB.createConnection( + testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.INIT, exported.ORDERED, testConnectionIDA) + }, true}, + {"previous channel with invalid state", func() { + _ = suite.chainA.createChannel( + testPort2, testChannel2, testPort1, testChannel1, exported.UNINITIALIZED, + exported.ORDERED, testConnectionIDB, + ) + }, false}, + {"connection doesn't exist", func() {}, false}, + {"connection is not OPEN", func() { + _ = suite.chainA.createConnection( + testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, + connectionexported.INIT, + ) + }, false}, + {"consensus state not found", func() { + _ = suite.chainA.createConnection( + testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, + connectionexported.OPEN, + ) + }, false}, + {"channel verification failed", func() { + suite.chainA.CreateClient(suite.chainB) + _ = suite.chainA.createConnection( + testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, + connectionexported.OPEN, + ) + }, false}, + {"port capability not found", func() { + suite.chainA.CreateClient(suite.chainB) + suite.chainB.CreateClient(suite.chainA) + _ = suite.chainA.createConnection( + testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, + connectionexported.OPEN, + ) + suite.chainB.createConnection( + testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.INIT, exported.ORDERED, testConnectionIDA) + portCap = capability.NewCapability(3) + }, false}, + } + + for i, tc := range testCases { + tc := tc + i := i + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + suite.SetupTest() // reset + + var err error + portCap, err = suite.chainA.App.ScopedIBCKeeper.NewCapability(suite.chainA.GetContext(), porttypes.PortPath(testPort2)) + suite.Require().NoError(err, "could not create capability") + + tc.malleate() + + suite.chainA.updateClient(suite.chainB) + suite.chainB.updateClient(suite.chainA) + proof, proofHeight := queryProof(suite.chainB, channelKey) + + if tc.expPass { + cap, err := suite.chainA.App.IBCKeeper.ChannelKeeper.ChanOpenTry( + suite.chainA.GetContext(), exported.ORDERED, []string{testConnectionIDB}, + testPort2, testChannel2, portCap, counterparty, testChannelVersion, testChannelVersion, + proof, proofHeight+1, + ) + suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg) + suite.Require().NotNil(cap) + chanCap, ok := suite.chainA.App.ScopedIBCKeeper.GetCapability( + suite.chainA.GetContext(), + ibctypes.ChannelCapabilityPath(testPort2, testChannel2), + ) + suite.Require().True(ok, "could not retrieve channel capapbility after successful ChanOpenInit") + suite.Require().Equal(chanCap.String(), cap.String(), "channel capability is not correct") + } else { + _, err := suite.chainA.App.IBCKeeper.ChannelKeeper.ChanOpenTry( + suite.chainA.GetContext(), exported.ORDERED, []string{testConnectionIDB}, + testPort2, testChannel2, portCap, counterparty, testChannelVersion, testChannelVersion, + invalidProof{}, proofHeight, + ) + suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg) + } + }) + } +} + +func (suite *KeeperTestSuite) TestChanOpenAck() { + channelKey := ibctypes.KeyChannel(testPort2, testChannel2) + + var channelCap *capability.Capability + testCases := []testCase{ + {"success", func() { + suite.chainA.CreateClient(suite.chainB) + suite.chainB.CreateClient(suite.chainA) + suite.chainA.createConnection( + testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, + connectionexported.OPEN, + ) + _ = suite.chainB.createConnection( + testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, + connectionexported.OPEN, + ) + _ = suite.chainA.createChannel( + testPort1, testChannel1, testPort2, testChannel2, exported.INIT, + exported.ORDERED, testConnectionIDB, + ) + suite.chainB.createChannel( + testPort2, testChannel2, testPort1, testChannel1, exported.TRYOPEN, + exported.ORDERED, testConnectionIDA, + ) + }, true}, + {"channel doesn't exist", func() {}, false}, + {"channel state is not INIT or TRYOPEN", func() { + _ = suite.chainB.createChannel( + testPort1, testChannel1, testPort2, testChannel2, exported.UNINITIALIZED, + exported.ORDERED, testConnectionIDA, + ) + }, false}, + {"connection not found", func() { + _ = suite.chainB.createChannel( + testPort1, testChannel1, testPort2, testChannel2, exported.TRYOPEN, + exported.ORDERED, testConnectionIDA, + ) + }, false}, + {"connection is not OPEN", func() { + _ = suite.chainB.createConnection( + testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, + connectionexported.TRYOPEN, + ) + _ = suite.chainB.createChannel( + testPort1, testChannel1, testPort2, testChannel2, exported.TRYOPEN, + exported.ORDERED, testConnectionIDA, + ) + }, false}, + {"consensus state not found", func() { + _ = suite.chainB.createConnection( + testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, + connectionexported.OPEN, + ) + _ = suite.chainB.createChannel( + testPort1, testChannel1, testPort2, testChannel2, exported.TRYOPEN, + exported.ORDERED, testConnectionIDA, + ) + }, false}, + {"channel verification failed", func() { + suite.chainB.CreateClient(suite.chainA) + _ = suite.chainB.createConnection( + testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, + connectionexported.OPEN, + ) + _ = suite.chainB.createChannel( + testPort1, testChannel1, testPort2, testChannel2, exported.TRYOPEN, + exported.ORDERED, testConnectionIDA, + ) + }, false}, + {"channel capability not found", func() { + suite.chainA.CreateClient(suite.chainB) + suite.chainB.CreateClient(suite.chainA) + suite.chainA.createConnection( + testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, + connectionexported.OPEN, + ) + _ = suite.chainB.createConnection( + testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, + connectionexported.OPEN, + ) + _ = suite.chainA.createChannel( + testPort1, testChannel1, testPort2, testChannel2, exported.INIT, + exported.ORDERED, testConnectionIDB, + ) + suite.chainB.createChannel( + testPort2, testChannel2, testPort1, testChannel1, exported.TRYOPEN, + exported.ORDERED, testConnectionIDA, + ) + channelCap = capability.NewCapability(3) + }, false}, + } + + for i, tc := range testCases { + tc := tc + i := i + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + suite.SetupTest() // reset + + var err error + channelCap, err = suite.chainA.App.ScopedIBCKeeper.NewCapability(suite.chainA.GetContext(), ibctypes.ChannelCapabilityPath(testPort1, testChannel1)) + suite.Require().NoError(err, "could not create capability") + + tc.malleate() + + suite.chainA.updateClient(suite.chainB) + suite.chainB.updateClient(suite.chainA) + proof, proofHeight := queryProof(suite.chainB, channelKey) + + if tc.expPass { + err := suite.chainA.App.IBCKeeper.ChannelKeeper.ChanOpenAck( + suite.chainA.GetContext(), testPort1, testChannel1, channelCap, testChannelVersion, + proof, proofHeight+1, + ) + suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg) + } else { + err := suite.chainA.App.IBCKeeper.ChannelKeeper.ChanOpenAck( + suite.chainA.GetContext(), testPort1, testChannel1, channelCap, testChannelVersion, + invalidProof{}, proofHeight+1, + ) + suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg) + } + }) + } +} + +func (suite *KeeperTestSuite) TestChanOpenConfirm() { + channelKey := ibctypes.KeyChannel(testPort2, testChannel2) + + var channelCap *capability.Capability + testCases := []testCase{ + {"success", func() { + suite.chainA.CreateClient(suite.chainB) + suite.chainB.CreateClient(suite.chainA) + _ = suite.chainA.createConnection( + testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, + connectionexported.TRYOPEN, + ) + suite.chainB.createConnection( + testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, + connectionexported.OPEN, + ) + _ = suite.chainA.createChannel( + testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, + exported.ORDERED, testConnectionIDB, + ) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, + exported.TRYOPEN, exported.ORDERED, testConnectionIDA) + }, true}, + {"channel doesn't exist", func() {}, false}, + {"channel state is not TRYOPEN", func() { + _ = suite.chainA.createChannel( + testPort1, testChannel1, testPort2, testChannel2, exported.UNINITIALIZED, + exported.ORDERED, testConnectionIDB, + ) + }, false}, + {"connection not found", func() { + _ = suite.chainA.createChannel( + testPort2, testChannel2, testPort1, testChannel1, exported.TRYOPEN, + exported.ORDERED, testConnectionIDB, + ) + }, false}, + {"connection is not OPEN", func() { + _ = suite.chainA.createConnection( + testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, + connectionexported.TRYOPEN, + ) + _ = suite.chainA.createChannel( + testPort2, testChannel2, testPort1, testChannel1, exported.TRYOPEN, + exported.ORDERED, testConnectionIDB, + ) + }, false}, + {"consensus state not found", func() { + _ = suite.chainA.createConnection( + testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, + connectionexported.OPEN, + ) + _ = suite.chainA.createChannel( + testPort2, testChannel2, testPort1, testChannel1, exported.TRYOPEN, + exported.ORDERED, testConnectionIDB, + ) + }, false}, + {"channel verification failed", func() { + suite.chainA.CreateClient(suite.chainB) + _ = suite.chainA.createConnection( + testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, + connectionexported.OPEN, + ) + _ = suite.chainA.createChannel( + testPort2, testChannel2, testPort1, testChannel1, exported.TRYOPEN, + exported.ORDERED, testConnectionIDB, + ) + }, false}, + {"channel capability not found", func() { + suite.chainA.CreateClient(suite.chainB) + suite.chainB.CreateClient(suite.chainA) + _ = suite.chainA.createConnection( + testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, + connectionexported.TRYOPEN, + ) + suite.chainB.createConnection( + testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, + connectionexported.OPEN, + ) + _ = suite.chainA.createChannel( + testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, + exported.ORDERED, testConnectionIDB, + ) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, + exported.TRYOPEN, exported.ORDERED, testConnectionIDA) + channelCap = capability.NewCapability(3) + }, false}, + } + + for i, tc := range testCases { + tc := tc + i := i + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + suite.SetupTest() // reset + + var err error + channelCap, err = suite.chainB.App.ScopedIBCKeeper.NewCapability(suite.chainB.GetContext(), ibctypes.ChannelCapabilityPath(testPort1, testChannel1)) + suite.Require().NoError(err, "could not create capability") + + tc.malleate() + + suite.chainA.updateClient(suite.chainB) + suite.chainB.updateClient(suite.chainA) + proof, proofHeight := queryProof(suite.chainA, channelKey) + + if tc.expPass { + err := suite.chainB.App.IBCKeeper.ChannelKeeper.ChanOpenConfirm( + suite.chainB.GetContext(), testPort1, testChannel1, + channelCap, proof, proofHeight+1, + ) + suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg) + } else { + err := suite.chainB.App.IBCKeeper.ChannelKeeper.ChanOpenConfirm( + suite.chainB.GetContext(), testPort1, testChannel1, channelCap, + invalidProof{}, proofHeight+1, + ) + suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg) + } + }) + } +} + +func (suite *KeeperTestSuite) TestChanCloseInit() { + var channelCap *capability.Capability + testCases := []testCase{ + {"success", func() { + suite.chainB.CreateClient(suite.chainA) + _ = suite.chainA.createConnection( + testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, + connectionexported.OPEN, + ) + _ = suite.chainA.createChannel( + testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, + exported.ORDERED, testConnectionIDA, + ) + }, true}, + {"channel doesn't exist", func() {}, false}, + {"channel state is CLOSED", func() { + _ = suite.chainA.createChannel( + testPort1, testChannel1, testPort2, testChannel2, exported.CLOSED, + exported.ORDERED, testConnectionIDB, + ) + }, false}, + {"connection not found", func() { + _ = suite.chainA.createChannel( + testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, + exported.ORDERED, testConnectionIDA, + ) + }, false}, + {"connection is not OPEN", func() { + _ = suite.chainA.createConnection( + testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, + connectionexported.TRYOPEN, + ) + _ = suite.chainA.createChannel( + testPort1, testChannel1, testPort2, testChannel2, exported.UNINITIALIZED, + exported.ORDERED, testConnectionIDA, + ) + }, false}, + {"channel capability not found", func() { + suite.chainB.CreateClient(suite.chainA) + _ = suite.chainA.createConnection( + testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, + connectionexported.OPEN, + ) + _ = suite.chainA.createChannel( + testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, + exported.ORDERED, testConnectionIDA, + ) + channelCap = capability.NewCapability(3) + }, false}, + } + + for i, tc := range testCases { + tc := tc + i := i + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + suite.SetupTest() // reset + + var err error + channelCap, err = suite.chainA.App.ScopedIBCKeeper.NewCapability(suite.chainA.GetContext(), ibctypes.ChannelCapabilityPath(testPort1, testChannel1)) + suite.Require().NoError(err, "could not create capability") + + tc.malleate() + err = suite.chainA.App.IBCKeeper.ChannelKeeper.ChanCloseInit( + suite.chainA.GetContext(), testPort1, testChannel1, channelCap, + ) + + if tc.expPass { + suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg) + } else { + suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg) + } + }) + } +} + +func (suite *KeeperTestSuite) TestChanCloseConfirm() { + channelKey := ibctypes.KeyChannel(testPort1, testChannel1) + + var channelCap *capability.Capability + testCases := []testCase{ + {"success", func() { + suite.chainA.CreateClient(suite.chainB) + suite.chainB.CreateClient(suite.chainA) + _ = suite.chainB.createConnection( + testConnectionIDB, testConnectionIDA, testClientIDA, testClientIDB, + connectionexported.OPEN, + ) + suite.chainA.createConnection( + testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, + connectionexported.OPEN, + ) + _ = suite.chainB.createChannel( + testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, + exported.ORDERED, testConnectionIDB, + ) + suite.chainA.createChannel( + testPort1, testChannel1, testPort2, testChannel2, exported.CLOSED, + exported.ORDERED, testConnectionIDA, + ) + }, true}, + {"channel doesn't exist", func() {}, false}, + {"channel state is CLOSED", func() { + _ = suite.chainB.createChannel( + testPort2, testChannel2, testPort1, testChannel1, exported.CLOSED, + exported.ORDERED, testConnectionIDB, + ) + }, false}, + {"connection not found", func() { + _ = suite.chainB.createChannel( + testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, + exported.ORDERED, testConnectionIDA, + ) + }, false}, + {"connection is not OPEN", func() { + _ = suite.chainB.createConnection( + testConnectionIDB, testConnectionIDA, testClientIDA, testClientIDB, + connectionexported.TRYOPEN, + ) + _ = suite.chainB.createChannel( + testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, + exported.ORDERED, testConnectionIDB, + ) + }, false}, + {"consensus state not found", func() { + _ = suite.chainB.createConnection( + testConnectionIDB, testConnectionIDA, testClientIDA, testClientIDB, + connectionexported.OPEN, + ) + _ = suite.chainB.createChannel( + testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, + exported.ORDERED, testConnectionIDB, + ) + }, false}, + {"channel verification failed", func() { + suite.chainB.CreateClient(suite.chainA) + _ = suite.chainB.createConnection( + testConnectionIDB, testConnectionIDA, testClientIDA, testClientIDB, + connectionexported.OPEN, + ) + _ = suite.chainB.createChannel( + testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, + exported.ORDERED, testConnectionIDB, + ) + }, false}, + {"channel capability not found", func() { + suite.chainA.CreateClient(suite.chainB) + suite.chainB.CreateClient(suite.chainA) + _ = suite.chainB.createConnection( + testConnectionIDB, testConnectionIDA, testClientIDA, testClientIDB, + connectionexported.OPEN, + ) + suite.chainA.createConnection( + testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, + connectionexported.OPEN, + ) + _ = suite.chainB.createChannel( + testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, + exported.ORDERED, testConnectionIDB, + ) + suite.chainA.createChannel( + testPort1, testChannel1, testPort2, testChannel2, exported.CLOSED, + exported.ORDERED, testConnectionIDA, + ) + }, false}, + } + + for i, tc := range testCases { + tc := tc + i := i + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + suite.SetupTest() // reset + + var err error + channelCap, err = suite.chainB.App.ScopedIBCKeeper.NewCapability(suite.chainB.GetContext(), ibctypes.ChannelCapabilityPath(testPort2, testChannel2)) + suite.Require().NoError(err, "could not create capability") + + tc.malleate() + + suite.chainA.updateClient(suite.chainB) + suite.chainB.updateClient(suite.chainA) + proof, proofHeight := queryProof(suite.chainA, channelKey) + + if tc.expPass { + err := suite.chainB.App.IBCKeeper.ChannelKeeper.ChanCloseConfirm( + suite.chainB.GetContext(), testPort2, testChannel2, channelCap, + proof, proofHeight+1, + ) + suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg) + } else { + err := suite.chainB.App.IBCKeeper.ChannelKeeper.ChanCloseConfirm( + suite.chainB.GetContext(), testPort2, testChannel2, channelCap, + invalidProof{}, proofHeight, + ) + suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg) + } + }) + } +} + +type testCase = struct { + msg string + malleate func() + expPass bool +} diff --git a/x/ibc/04-channel/keeper/keeper.go b/x/ibc/04-channel/keeper/keeper.go new file mode 100644 index 000000000000..1774cbf0c51f --- /dev/null +++ b/x/ibc/04-channel/keeper/keeper.go @@ -0,0 +1,173 @@ +package keeper + +import ( + "encoding/binary" + "fmt" + + "github.com/tendermint/tendermint/libs/log" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/capability" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +// Keeper defines the IBC channel keeper +type Keeper struct { + storeKey sdk.StoreKey + cdc *codec.Codec + clientKeeper types.ClientKeeper + connectionKeeper types.ConnectionKeeper + portKeeper types.PortKeeper + scopedKeeper capability.ScopedKeeper +} + +// NewKeeper creates a new IBC channel Keeper instance +func NewKeeper( + cdc *codec.Codec, key sdk.StoreKey, + clientKeeper types.ClientKeeper, connectionKeeper types.ConnectionKeeper, + portKeeper types.PortKeeper, scopedKeeper capability.ScopedKeeper, +) Keeper { + return Keeper{ + storeKey: key, + cdc: cdc, + clientKeeper: clientKeeper, + connectionKeeper: connectionKeeper, + portKeeper: portKeeper, + scopedKeeper: scopedKeeper, + } +} + +// Logger returns a module-specific logger. +func (k Keeper) Logger(ctx sdk.Context) log.Logger { + return ctx.Logger().With("module", fmt.Sprintf("x/%s/%s", ibctypes.ModuleName, types.SubModuleName)) +} + +// GetChannel returns a channel with a particular identifier binded to a specific port +func (k Keeper) GetChannel(ctx sdk.Context, portID, channelID string) (types.Channel, bool) { + store := ctx.KVStore(k.storeKey) + bz := store.Get(ibctypes.KeyChannel(portID, channelID)) + if bz == nil { + return types.Channel{}, false + } + + var channel types.Channel + k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &channel) + return channel, true +} + +// SetChannel sets a channel to the store +func (k Keeper) SetChannel(ctx sdk.Context, portID, channelID string, channel types.Channel) { + store := ctx.KVStore(k.storeKey) + bz := k.cdc.MustMarshalBinaryLengthPrefixed(channel) + store.Set(ibctypes.KeyChannel(portID, channelID), bz) +} + +// GetNextSequenceSend gets a channel's next send sequence from the store +func (k Keeper) GetNextSequenceSend(ctx sdk.Context, portID, channelID string) (uint64, bool) { + store := ctx.KVStore(k.storeKey) + bz := store.Get(ibctypes.KeyNextSequenceSend(portID, channelID)) + if bz == nil { + return 0, false + } + + return binary.BigEndian.Uint64(bz), true +} + +// SetNextSequenceSend sets a channel's next send sequence to the store +func (k Keeper) SetNextSequenceSend(ctx sdk.Context, portID, channelID string, sequence uint64) { + store := ctx.KVStore(k.storeKey) + bz := sdk.Uint64ToBigEndian(sequence) + store.Set(ibctypes.KeyNextSequenceSend(portID, channelID), bz) +} + +// GetNextSequenceRecv gets a channel's next receive sequence from the store +func (k Keeper) GetNextSequenceRecv(ctx sdk.Context, portID, channelID string) (uint64, bool) { + store := ctx.KVStore(k.storeKey) + bz := store.Get(ibctypes.KeyNextSequenceRecv(portID, channelID)) + if bz == nil { + return 0, false + } + + return binary.BigEndian.Uint64(bz), true +} + +// SetNextSequenceRecv sets a channel's next receive sequence to the store +func (k Keeper) SetNextSequenceRecv(ctx sdk.Context, portID, channelID string, sequence uint64) { + store := ctx.KVStore(k.storeKey) + bz := sdk.Uint64ToBigEndian(sequence) + store.Set(ibctypes.KeyNextSequenceRecv(portID, channelID), bz) +} + +// GetPacketCommitment gets the packet commitment hash from the store +func (k Keeper) GetPacketCommitment(ctx sdk.Context, portID, channelID string, sequence uint64) []byte { + store := ctx.KVStore(k.storeKey) + bz := store.Get(ibctypes.KeyPacketCommitment(portID, channelID, sequence)) + return bz +} + +// SetPacketCommitment sets the packet commitment hash to the store +func (k Keeper) SetPacketCommitment(ctx sdk.Context, portID, channelID string, sequence uint64, commitmentHash []byte) { + store := ctx.KVStore(k.storeKey) + store.Set(ibctypes.KeyPacketCommitment(portID, channelID, sequence), commitmentHash) +} + +func (k Keeper) deletePacketCommitment(ctx sdk.Context, portID, channelID string, sequence uint64) { + store := ctx.KVStore(k.storeKey) + store.Delete(ibctypes.KeyPacketCommitment(portID, channelID, sequence)) +} + +// SetPacketAcknowledgement sets the packet ack hash to the store +func (k Keeper) SetPacketAcknowledgement(ctx sdk.Context, portID, channelID string, sequence uint64, ackHash []byte) { + store := ctx.KVStore(k.storeKey) + store.Set(ibctypes.KeyPacketAcknowledgement(portID, channelID, sequence), ackHash) +} + +// GetPacketAcknowledgement gets the packet ack hash from the store +func (k Keeper) GetPacketAcknowledgement(ctx sdk.Context, portID, channelID string, sequence uint64) ([]byte, bool) { + store := ctx.KVStore(k.storeKey) + bz := store.Get(ibctypes.KeyPacketAcknowledgement(portID, channelID, sequence)) + if bz == nil { + return nil, false + } + return bz, true +} + +// IterateChannels provides an iterator over all Channel objects. For each +// Channel, cb will be called. If the cb returns true, the iterator will close +// and stop. +func (k Keeper) IterateChannels(ctx sdk.Context, cb func(types.IdentifiedChannel) bool) { + store := ctx.KVStore(k.storeKey) + iterator := sdk.KVStorePrefixIterator(store, ibctypes.GetChannelPortsKeysPrefix(ibctypes.KeyChannelPrefix)) + + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + var channel types.Channel + k.cdc.MustUnmarshalBinaryLengthPrefixed(iterator.Value(), &channel) + portID, channelID := ibctypes.MustParseChannelPath(string(iterator.Key())) + + if cb(types.IdentifiedChannel{Channel: channel, PortIdentifier: portID, ChannelIdentifier: channelID}) { + break + } + } +} + +// GetAllChannels returns all stored Channel objects. +func (k Keeper) GetAllChannels(ctx sdk.Context) (channels []types.IdentifiedChannel) { + k.IterateChannels(ctx, func(channel types.IdentifiedChannel) bool { + channels = append(channels, channel) + return false + }) + return channels +} + +// LookupModuleByChannel will return the IBCModule along with the capability associated with a given channel defined by its portID and channelID +func (k Keeper) LookupModuleByChannel(ctx sdk.Context, portID, channelID string) (string, *capability.Capability, bool) { + modules, cap, ok := k.scopedKeeper.LookupModules(ctx, ibctypes.ChannelCapabilityPath(portID, channelID)) + if !ok { + return "", nil, false + } + + return ibctypes.GetModuleOwner(modules), cap, true +} diff --git a/x/ibc/04-channel/keeper/keeper_test.go b/x/ibc/04-channel/keeper/keeper_test.go new file mode 100644 index 000000000000..1f8bcb5c5cbd --- /dev/null +++ b/x/ibc/04-channel/keeper/keeper_test.go @@ -0,0 +1,452 @@ +package keeper_test + +import ( + "bytes" + "errors" + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/suite" + abci "github.com/tendermint/tendermint/abci/types" + tmtypes "github.com/tendermint/tendermint/types" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/simapp" + sdk "github.com/cosmos/cosmos-sdk/types" + connectionexported "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported" + connectiontypes "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" + commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" + commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" + "github.com/cosmos/cosmos-sdk/x/staking" +) + +// define constants used for testing +const ( + testClientIDA = "testclientida" + testConnectionIDA = "connectionidatob" + + testClientIDB = "testclientidb" + testConnectionIDB = "connectionidbtoa" + + testPort1 = "firstport" + testPort2 = "secondport" + testPort3 = "thirdport" + + testChannel1 = "firstchannel" + testChannel2 = "secondchannel" + testChannel3 = "thirdchannel" + + testChannelOrder = exported.ORDERED + testChannelVersion = "1.0" + + trustingPeriod time.Duration = time.Hour * 24 * 7 * 2 + ubdPeriod time.Duration = time.Hour * 24 * 7 * 3 +) + +type KeeperTestSuite struct { + suite.Suite + + cdc *codec.Codec + + chainA *TestChain + chainB *TestChain +} + +func (suite *KeeperTestSuite) SetupTest() { + suite.chainA = NewTestChain(testClientIDA) + suite.chainB = NewTestChain(testClientIDB) + + suite.cdc = suite.chainA.App.Codec() +} + +func (suite *KeeperTestSuite) TestSetChannel() { + ctx := suite.chainB.GetContext() + _, found := suite.chainB.App.IBCKeeper.ChannelKeeper.GetChannel(ctx, testPort1, testChannel1) + suite.False(found) + + channel := types.Channel{ + State: exported.OPEN, + Ordering: testChannelOrder, + Counterparty: types.Counterparty{ + PortID: testPort2, + ChannelID: testChannel2, + }, + ConnectionHops: []string{testConnectionIDA}, + Version: testChannelVersion, + } + suite.chainB.App.IBCKeeper.ChannelKeeper.SetChannel(ctx, testPort1, testChannel1, channel) + + storedChannel, found := suite.chainB.App.IBCKeeper.ChannelKeeper.GetChannel(ctx, testPort1, testChannel1) + suite.True(found) + suite.Equal(channel, storedChannel) +} + +func (suite KeeperTestSuite) TestGetAllChannels() { + // Channel (Counterparty): A(C) -> C(B) -> B(A) + counterparty1 := types.NewCounterparty(testPort1, testChannel1) + counterparty2 := types.NewCounterparty(testPort2, testChannel2) + counterparty3 := types.NewCounterparty(testPort3, testChannel3) + + channel1 := types.Channel{ + State: exported.INIT, + Ordering: testChannelOrder, + Counterparty: counterparty3, + ConnectionHops: []string{testConnectionIDA}, + Version: testChannelVersion, + } + + channel2 := types.Channel{ + State: exported.INIT, + Ordering: testChannelOrder, + Counterparty: counterparty1, + ConnectionHops: []string{testConnectionIDA}, + Version: testChannelVersion, + } + + channel3 := types.Channel{ + State: exported.CLOSED, + Ordering: testChannelOrder, + Counterparty: counterparty2, + ConnectionHops: []string{testConnectionIDA}, + Version: testChannelVersion, + } + + expChannels := []types.IdentifiedChannel{ + {Channel: channel1, PortIdentifier: testPort1, ChannelIdentifier: testChannel1}, + {Channel: channel2, PortIdentifier: testPort2, ChannelIdentifier: testChannel2}, + {Channel: channel3, PortIdentifier: testPort3, ChannelIdentifier: testChannel3}, + } + + ctx := suite.chainB.GetContext() + suite.chainB.App.IBCKeeper.ChannelKeeper.SetChannel(ctx, testPort1, testChannel1, channel1) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetChannel(ctx, testPort2, testChannel2, channel2) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetChannel(ctx, testPort3, testChannel3, channel3) + + channels := suite.chainB.App.IBCKeeper.ChannelKeeper.GetAllChannels(ctx) + suite.Require().Len(channels, len(expChannels)) + suite.Require().Equal(expChannels, channels) +} + +func (suite *KeeperTestSuite) TestSetSequence() { + ctx := suite.chainB.GetContext() + _, found := suite.chainB.App.IBCKeeper.ChannelKeeper.GetNextSequenceSend(ctx, testPort1, testChannel1) + suite.False(found) + + _, found = suite.chainB.App.IBCKeeper.ChannelKeeper.GetNextSequenceRecv(ctx, testPort1, testChannel1) + suite.False(found) + + nextSeqSend, nextSeqRecv := uint64(10), uint64(10) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetNextSequenceSend(ctx, testPort1, testChannel1, nextSeqSend) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(ctx, testPort1, testChannel1, nextSeqRecv) + + storedNextSeqSend, found := suite.chainB.App.IBCKeeper.ChannelKeeper.GetNextSequenceSend(ctx, testPort1, testChannel1) + suite.True(found) + suite.Equal(nextSeqSend, storedNextSeqSend) + + storedNextSeqRecv, found := suite.chainB.App.IBCKeeper.ChannelKeeper.GetNextSequenceSend(ctx, testPort1, testChannel1) + suite.True(found) + suite.Equal(nextSeqRecv, storedNextSeqRecv) +} + +func (suite *KeeperTestSuite) TestPackageCommitment() { + ctx := suite.chainB.GetContext() + seq := uint64(10) + storedCommitment := suite.chainB.App.IBCKeeper.ChannelKeeper.GetPacketCommitment(ctx, testPort1, testChannel1, seq) + suite.Equal([]byte(nil), storedCommitment) + + commitment := []byte("commitment") + suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(ctx, testPort1, testChannel1, seq, commitment) + + storedCommitment = suite.chainB.App.IBCKeeper.ChannelKeeper.GetPacketCommitment(ctx, testPort1, testChannel1, seq) + suite.Equal(commitment, storedCommitment) +} + +func (suite *KeeperTestSuite) TestSetPacketAcknowledgement() { + ctx := suite.chainB.GetContext() + seq := uint64(10) + + storedAckHash, found := suite.chainB.App.IBCKeeper.ChannelKeeper.GetPacketAcknowledgement(ctx, testPort1, testChannel1, seq) + suite.False(found) + suite.Nil(storedAckHash) + + ackHash := []byte("ackhash") + suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketAcknowledgement(ctx, testPort1, testChannel1, seq, ackHash) + + storedAckHash, found = suite.chainB.App.IBCKeeper.ChannelKeeper.GetPacketAcknowledgement(ctx, testPort1, testChannel1, seq) + suite.True(found) + suite.Equal(ackHash, storedAckHash) +} + +func TestKeeperTestSuite(t *testing.T) { + suite.Run(t, new(KeeperTestSuite)) +} + +func commitNBlocks(chain *TestChain, n int) { + for i := 0; i < n; i++ { + chain.App.Commit() + chain.App.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: chain.App.LastBlockHeight() + 1}}) + } +} + +// nolint: unused +func queryProof(chain *TestChain, key []byte) (commitmenttypes.MerkleProof, uint64) { + res := chain.App.Query(abci.RequestQuery{ + Path: fmt.Sprintf("store/%s/key", ibctypes.StoreKey), + Height: chain.App.LastBlockHeight(), + Data: key, + Prove: true, + }) + + proof := commitmenttypes.MerkleProof{ + Proof: res.Proof, + } + + return proof, uint64(res.Height) +} + +type TestChain struct { + ClientID string + App *simapp.SimApp + Header ibctmtypes.Header + Vals *tmtypes.ValidatorSet + Signers []tmtypes.PrivValidator +} + +func NewTestChain(clientID string) *TestChain { + privVal := tmtypes.NewMockPV() + validator := tmtypes.NewValidator(privVal.GetPubKey(), 1) + valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator}) + signers := []tmtypes.PrivValidator{privVal} + now := time.Date(2020, 1, 2, 0, 0, 0, 0, time.UTC) + + header := ibctmtypes.CreateTestHeader(clientID, 1, now, valSet, signers) + + return &TestChain{ + ClientID: clientID, + App: simapp.Setup(false), + Header: header, + Vals: valSet, + Signers: signers, + } +} + +// Creates simple context for testing purposes +func (chain *TestChain) GetContext() sdk.Context { + return chain.App.BaseApp.NewContext(false, abci.Header{ChainID: chain.Header.ChainID, Height: chain.Header.Height}) +} + +// createClient will create a client for clientChain on targetChain +func (chain *TestChain) CreateClient(client *TestChain) error { + client.Header = nextHeader(client) + // Commit and create a new block on appTarget to get a fresh CommitID + client.App.Commit() + commitID := client.App.LastCommitID() + client.App.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: client.Header.Height, Time: client.Header.Time}}) + + // Set HistoricalInfo on client chain after Commit + ctxClient := client.GetContext() + validator := staking.NewValidator( + sdk.ValAddress(client.Vals.Validators[0].Address), client.Vals.Validators[0].PubKey, staking.Description{}, + ) + validator.Status = sdk.Bonded + validator.Tokens = sdk.NewInt(1000000) // get one voting power + validators := []staking.Validator{validator} + histInfo := staking.HistoricalInfo{ + Header: abci.Header{ + AppHash: commitID.Hash, + }, + Valset: validators, + } + client.App.StakingKeeper.SetHistoricalInfo(ctxClient, client.Header.Height, histInfo) + + // Create target ctx + ctxTarget := chain.GetContext() + + // create client + clientState, err := ibctmtypes.Initialize(client.ClientID, trustingPeriod, ubdPeriod, client.Header) + if err != nil { + return err + } + _, err = chain.App.IBCKeeper.ClientKeeper.CreateClient(ctxTarget, clientState, client.Header.ConsensusState()) + if err != nil { + return err + } + return nil + + // _, _, err := simapp.SignCheckDeliver( + // suite.T(), + // suite.cdc, + // suite.app.BaseApp, + // ctx.BlockHeader(), + // []sdk.Msg{clienttypes.NewMsgCreateClient(clientID, clientexported.ClientTypeTendermint, consState, accountAddress)}, + // []uint64{baseAccount.GetAccountNumber()}, + // []uint64{baseAccount.GetSequence()}, + // true, true, accountPrivKey, + // ) +} + +func (chain *TestChain) updateClient(client *TestChain) { + // Create target ctx + ctxTarget := chain.GetContext() + + // if clientState does not already exist, return without updating + _, found := chain.App.IBCKeeper.ClientKeeper.GetClientState( + ctxTarget, client.ClientID, + ) + if !found { + return + } + + // always commit when updateClient and begin a new block + client.App.Commit() + commitID := client.App.LastCommitID() + + client.Header = nextHeader(client) + client.App.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: client.Header.Height, Time: client.Header.Time}}) + + // Set HistoricalInfo on client chain after Commit + ctxClient := client.GetContext() + validator := staking.NewValidator( + sdk.ValAddress(client.Vals.Validators[0].Address), client.Vals.Validators[0].PubKey, staking.Description{}, + ) + validator.Status = sdk.Bonded + validator.Tokens = sdk.NewInt(1000000) + validators := []staking.Validator{validator} + histInfo := staking.HistoricalInfo{ + Header: abci.Header{ + AppHash: commitID.Hash, + }, + Valset: validators, + } + client.App.StakingKeeper.SetHistoricalInfo(ctxClient, client.Header.Height, histInfo) + + consensusState := ibctmtypes.ConsensusState{ + Height: uint64(client.Header.Height), + Timestamp: client.Header.Time, + Root: commitmenttypes.NewMerkleRoot(commitID.Hash), + ValidatorSet: client.Vals, + } + + chain.App.IBCKeeper.ClientKeeper.SetClientConsensusState( + ctxTarget, client.ClientID, uint64(client.Header.Height), consensusState, + ) + chain.App.IBCKeeper.ClientKeeper.SetClientState( + ctxTarget, ibctmtypes.NewClientState(client.ClientID, trustingPeriod, ubdPeriod, client.Header), + ) + + // _, _, err := simapp.SignCheckDeliver( + // suite.T(), + // suite.cdc, + // suite.app.BaseApp, + // ctx.BlockHeader(), + // []sdk.Msg{clienttypes.NewMsgUpdateClient(clientID, suite.header, accountAddress)}, + // []uint64{baseAccount.GetAccountNumber()}, + // []uint64{baseAccount.GetSequence()}, + // true, true, accountPrivKey, + // ) + // suite.Require().NoError(err) +} + +func (chain *TestChain) createConnection( + connID, counterpartyConnID, clientID, counterpartyClientID string, + state connectionexported.State, +) connectiontypes.ConnectionEnd { + counterparty := connectiontypes.NewCounterparty(counterpartyClientID, counterpartyConnID, chain.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix()) + connection := connectiontypes.ConnectionEnd{ + State: state, + ClientID: clientID, + Counterparty: counterparty, + Versions: connectiontypes.GetCompatibleVersions(), + } + ctx := chain.GetContext() + chain.App.IBCKeeper.ConnectionKeeper.SetConnection(ctx, connID, connection) + return connection +} + +func (chain *TestChain) createChannel( + portID, channelID, counterpartyPortID, counterpartyChannelID string, + state exported.State, order exported.Order, connectionID string, +) types.Channel { + counterparty := types.NewCounterparty(counterpartyPortID, counterpartyChannelID) + channel := types.NewChannel(state, order, counterparty, + []string{connectionID}, "1.0", + ) + ctx := chain.GetContext() + chain.App.IBCKeeper.ChannelKeeper.SetChannel(ctx, portID, channelID, channel) + return channel +} + +func nextHeader(chain *TestChain) ibctmtypes.Header { + return ibctmtypes.CreateTestHeader(chain.Header.ChainID, chain.Header.Height+1, + chain.Header.Time.Add(time.Minute), chain.Vals, chain.Signers) +} + +// Mocked types +// TODO: fix tests and replace for real proofs + +var ( + _ commitmentexported.Proof = validProof{nil, nil, nil} + _ commitmentexported.Proof = invalidProof{} +) + +type ( + validProof struct { + root commitmentexported.Root + path commitmentexported.Path + value []byte + } + invalidProof struct{} +) + +func (validProof) GetCommitmentType() commitmentexported.Type { + return commitmentexported.Merkle +} + +func (proof validProof) VerifyMembership( + root commitmentexported.Root, path commitmentexported.Path, value []byte, +) error { + if bytes.Equal(root.GetHash(), proof.root.GetHash()) && + path.String() == proof.path.String() && + bytes.Equal(value, proof.value) { + return nil + } + return errors.New("invalid proof") +} + +func (validProof) VerifyNonMembership(root commitmentexported.Root, path commitmentexported.Path) error { + return nil +} + +func (validProof) ValidateBasic() error { + return nil +} + +func (validProof) IsEmpty() bool { + return false +} + +func (invalidProof) GetCommitmentType() commitmentexported.Type { + return commitmentexported.Merkle +} + +func (invalidProof) VerifyMembership( + root commitmentexported.Root, path commitmentexported.Path, value []byte) error { + return errors.New("proof failed") +} + +func (invalidProof) VerifyNonMembership(root commitmentexported.Root, path commitmentexported.Path) error { + return errors.New("proof failed") +} + +func (invalidProof) ValidateBasic() error { + return errors.New("invalid proof") +} + +func (invalidProof) IsEmpty() bool { + return true +} diff --git a/x/ibc/04-channel/keeper/packet.go b/x/ibc/04-channel/keeper/packet.go new file mode 100644 index 000000000000..1475d68c9a3f --- /dev/null +++ b/x/ibc/04-channel/keeper/packet.go @@ -0,0 +1,451 @@ +package keeper + +import ( + "bytes" + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/capability" + client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" + connectionexported "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" + commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +// SendPacket is called by a module in order to send an IBC packet on a channel +// end owned by the calling module to the corresponding module on the counterparty +// chain. +func (k Keeper) SendPacket( + ctx sdk.Context, + channelCap *capability.Capability, + packet exported.PacketI, +) error { + if err := packet.ValidateBasic(); err != nil { + return err + } + + channel, found := k.GetChannel(ctx, packet.GetSourcePort(), packet.GetSourceChannel()) + if !found { + return sdkerrors.Wrap(types.ErrChannelNotFound, packet.GetSourceChannel()) + } + + if channel.State == exported.CLOSED { + return sdkerrors.Wrapf( + types.ErrInvalidChannelState, + "channel is CLOSED (got %s)", channel.State.String(), + ) + } + + if !k.scopedKeeper.AuthenticateCapability(ctx, channelCap, ibctypes.ChannelCapabilityPath(packet.GetSourcePort(), packet.GetSourceChannel())) { + return sdkerrors.Wrap(types.ErrChannelCapabilityNotFound, "caller does not own capability for channel") + } + + if packet.GetDestPort() != channel.Counterparty.PortID { + return sdkerrors.Wrapf( + types.ErrInvalidPacket, + "packet destination port doesn't match the counterparty's port (%s ≠ %s)", packet.GetDestPort(), channel.Counterparty.PortID, + ) + } + + if packet.GetDestChannel() != channel.Counterparty.ChannelID { + return sdkerrors.Wrapf( + types.ErrInvalidPacket, + "packet destination channel doesn't match the counterparty's channel (%s ≠ %s)", packet.GetDestChannel(), channel.Counterparty.ChannelID, + ) + } + + connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) + if !found { + return sdkerrors.Wrap(connection.ErrConnectionNotFound, channel.ConnectionHops[0]) + } + + // NOTE: assume UNINITIALIZED is a closed connection + if connectionEnd.GetState() == connectionexported.UNINITIALIZED { + return sdkerrors.Wrap( + connection.ErrInvalidConnectionState, + "connection is closed (i.e NONE)", + ) + } + + clientState, found := k.clientKeeper.GetClientState(ctx, connectionEnd.GetClientID()) + if !found { + return client.ErrConsensusStateNotFound + } + + // check if packet timeouted on the receiving chain + if clientState.GetLatestHeight() >= packet.GetTimeoutHeight() { + return sdkerrors.Wrap(types.ErrPacketTimeout, "timeout already passed ond the receiving chain") + } + + nextSequenceSend, found := k.GetNextSequenceSend(ctx, packet.GetSourcePort(), packet.GetSourceChannel()) + if !found { + return types.ErrSequenceSendNotFound + } + + if packet.GetSequence() != nextSequenceSend { + return sdkerrors.Wrapf( + types.ErrInvalidPacket, + "packet sequence ≠ next send sequence (%d ≠ %d)", packet.GetSequence(), nextSequenceSend, + ) + } + + nextSequenceSend++ + k.SetNextSequenceSend(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), nextSequenceSend) + k.SetPacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence(), types.CommitPacket(packet)) + + // Emit Event with Packet data along with other packet information for relayer to pick up + // and relay to other chain + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeSendPacket, + sdk.NewAttribute(types.AttributeKeyData, string(packet.GetData())), + sdk.NewAttribute(types.AttributeKeyTimeout, fmt.Sprintf("%d", packet.GetTimeoutHeight())), + sdk.NewAttribute(types.AttributeKeySequence, fmt.Sprintf("%d", packet.GetSequence())), + sdk.NewAttribute(types.AttributeKeySrcPort, packet.GetSourcePort()), + sdk.NewAttribute(types.AttributeKeySrcChannel, packet.GetSourceChannel()), + sdk.NewAttribute(types.AttributeKeyDstPort, packet.GetDestPort()), + sdk.NewAttribute(types.AttributeKeyDstChannel, packet.GetDestChannel()), + ), + }) + + k.Logger(ctx).Info(fmt.Sprintf("packet sent: %v", packet)) + return nil +} + +// RecvPacket is called by a module in order to receive & process an IBC packet +// sent on the corresponding channel end on the counterparty chain. +func (k Keeper) RecvPacket( + ctx sdk.Context, + packet exported.PacketI, + proof commitmentexported.Proof, + proofHeight uint64, +) (exported.PacketI, error) { + channel, found := k.GetChannel(ctx, packet.GetDestPort(), packet.GetDestChannel()) + if !found { + return nil, sdkerrors.Wrap(types.ErrChannelNotFound, packet.GetDestChannel()) + } + + if channel.State != exported.OPEN { + return nil, sdkerrors.Wrapf( + types.ErrInvalidChannelState, + "channel state is not OPEN (got %s)", channel.State.String(), + ) + } + + // NOTE: RecvPacket is called by the AnteHandler which acts upon the packet.Route(), + // so the capability authentication can be omitted here + + // packet must come from the channel's counterparty + if packet.GetSourcePort() != channel.Counterparty.PortID { + return nil, sdkerrors.Wrapf( + types.ErrInvalidPacket, + "packet source port doesn't match the counterparty's port (%s ≠ %s)", packet.GetSourcePort(), channel.Counterparty.PortID, + ) + } + + if packet.GetSourceChannel() != channel.Counterparty.ChannelID { + return nil, sdkerrors.Wrapf( + types.ErrInvalidPacket, + "packet source channel doesn't match the counterparty's channel (%s ≠ %s)", packet.GetSourceChannel(), channel.Counterparty.ChannelID, + ) + } + + connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) + if !found { + return nil, sdkerrors.Wrap(connection.ErrConnectionNotFound, channel.ConnectionHops[0]) + } + + if connectionEnd.GetState() != connectionexported.OPEN { + return nil, sdkerrors.Wrapf( + connection.ErrInvalidConnectionState, + "connection state is not OPEN (got %s)", connectionEnd.GetState().String(), + ) + } + + // check if packet timeouted by comparing it with the latest height of the chain + if uint64(ctx.BlockHeight()) >= packet.GetTimeoutHeight() { + return nil, types.ErrPacketTimeout + } + + if err := k.connectionKeeper.VerifyPacketCommitment( + ctx, connectionEnd, proofHeight, proof, + packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence(), + types.CommitPacket(packet), + ); err != nil { + return nil, sdkerrors.Wrap(err, "couldn't verify counterparty packet commitment") + } + + return packet, nil +} + +// PacketExecuted writes the packet execution acknowledgement to the state, +// which will be verified by the counterparty chain using AcknowledgePacket. +// CONTRACT: each packet handler function should call WriteAcknowledgement at the end of the execution +func (k Keeper) PacketExecuted( + ctx sdk.Context, + packet exported.PacketI, + acknowledgement []byte, +) error { + channel, found := k.GetChannel(ctx, packet.GetDestPort(), packet.GetDestChannel()) + if !found { + return sdkerrors.Wrapf(types.ErrChannelNotFound, packet.GetDestChannel()) + } + + // sanity check + if channel.State != exported.OPEN { + return sdkerrors.Wrapf( + types.ErrInvalidChannelState, + "channel state is not OPEN (got %s)", channel.State.String(), + ) + } + + if acknowledgement != nil || channel.Ordering == exported.UNORDERED { + k.SetPacketAcknowledgement( + ctx, packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence(), + types.CommitAcknowledgement(acknowledgement), + ) + } + + if channel.Ordering == exported.ORDERED { + nextSequenceRecv, found := k.GetNextSequenceRecv(ctx, packet.GetDestPort(), packet.GetDestChannel()) + if !found { + return types.ErrSequenceReceiveNotFound + } + + if packet.GetSequence() != nextSequenceRecv { + return sdkerrors.Wrapf( + types.ErrInvalidPacket, + "packet sequence ≠ next receive sequence (%d ≠ %d)", packet.GetSequence(), nextSequenceRecv, + ) + } + + nextSequenceRecv++ + + k.SetNextSequenceRecv(ctx, packet.GetDestPort(), packet.GetDestChannel(), nextSequenceRecv) + } + + // log that a packet has been received & executed + k.Logger(ctx).Info(fmt.Sprintf("packet received & executed: %v", packet)) + + // emit an event that the relayer can query for + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeRecvPacket, + sdk.NewAttribute(types.AttributeKeyData, string(acknowledgement)), + sdk.NewAttribute(types.AttributeKeyTimeout, fmt.Sprintf("%d", packet.GetTimeoutHeight())), + sdk.NewAttribute(types.AttributeKeySequence, fmt.Sprintf("%d", packet.GetSequence())), + sdk.NewAttribute(types.AttributeKeySrcPort, packet.GetSourcePort()), + sdk.NewAttribute(types.AttributeKeySrcChannel, packet.GetSourceChannel()), + sdk.NewAttribute(types.AttributeKeyDstPort, packet.GetDestPort()), + sdk.NewAttribute(types.AttributeKeyDstChannel, packet.GetDestChannel()), + ), + }) + + return nil +} + +// AcknowledgePacket is called by a module to process the acknowledgement of a +// packet previously sent by the calling module on a channel to a counterparty +// module on the counterparty chain. acknowledgePacket also cleans up the packet +// commitment, which is no longer necessary since the packet has been received +// and acted upon. +func (k Keeper) AcknowledgePacket( + ctx sdk.Context, + packet exported.PacketI, + acknowledgement []byte, + proof commitmentexported.Proof, + proofHeight uint64, +) (exported.PacketI, error) { + channel, found := k.GetChannel(ctx, packet.GetSourcePort(), packet.GetSourceChannel()) + if !found { + return nil, sdkerrors.Wrap(types.ErrChannelNotFound, packet.GetSourceChannel()) + } + + if channel.State != exported.OPEN { + return nil, sdkerrors.Wrapf( + types.ErrInvalidChannelState, + "channel state is not OPEN (got %s)", channel.State.String(), + ) + } + + // NOTE: RecvPacket is called by the AnteHandler which acts upon the packet.Route(), + // so the capability authentication can be omitted here + + // packet must have been sent to the channel's counterparty + if packet.GetDestPort() != channel.Counterparty.PortID { + return nil, sdkerrors.Wrapf( + types.ErrInvalidPacket, + "packet destination port doesn't match the counterparty's port (%s ≠ %s)", packet.GetDestPort(), channel.Counterparty.PortID, + ) + } + + if packet.GetDestChannel() != channel.Counterparty.ChannelID { + return nil, sdkerrors.Wrapf( + types.ErrInvalidPacket, + "packet destination channel doesn't match the counterparty's channel (%s ≠ %s)", packet.GetDestChannel(), channel.Counterparty.ChannelID, + ) + } + + connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) + if !found { + return nil, sdkerrors.Wrap(connection.ErrConnectionNotFound, channel.ConnectionHops[0]) + } + + if connectionEnd.GetState() != connectionexported.OPEN { + return nil, sdkerrors.Wrapf( + connection.ErrInvalidConnectionState, + "connection state is not OPEN (got %s)", connectionEnd.GetState().String(), + ) + } + + commitment := k.GetPacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) + + // verify we sent the packet and haven't cleared it out yet + if !bytes.Equal(commitment, types.CommitPacket(packet)) { + return nil, sdkerrors.Wrap(types.ErrInvalidPacket, "packet hasn't been sent") + } + + if err := k.connectionKeeper.VerifyPacketAcknowledgement( + ctx, connectionEnd, proofHeight, proof, packet.GetDestPort(), packet.GetDestChannel(), + packet.GetSequence(), acknowledgement, + ); err != nil { + return nil, sdkerrors.Wrap(err, "invalid acknowledgement on counterparty chain") + } + + // log that a packet has been acknowledged + k.Logger(ctx).Info(fmt.Sprintf("packet acknowledged: %v", packet)) + + // emit an event marking that we have processed the acknowledgement + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeAcknowledgePacket, + sdk.NewAttribute(types.AttributeKeyTimeout, fmt.Sprintf("%d", packet.GetTimeoutHeight())), + sdk.NewAttribute(types.AttributeKeySequence, fmt.Sprintf("%d", packet.GetSequence())), + sdk.NewAttribute(types.AttributeKeySrcPort, packet.GetSourcePort()), + sdk.NewAttribute(types.AttributeKeySrcChannel, packet.GetSourceChannel()), + sdk.NewAttribute(types.AttributeKeyDstPort, packet.GetDestPort()), + sdk.NewAttribute(types.AttributeKeyDstChannel, packet.GetDestChannel()), + ), + }) + + return packet, nil +} + +// CleanupPacket is called by a module to remove a received packet commitment +// from storage. The receiving end must have already processed the packet +// (whether regularly or past timeout). +// +// In the ORDERED channel case, CleanupPacket cleans-up a packet on an ordered +// channel by proving that the packet has been received on the other end. +// +// In the UNORDERED channel case, CleanupPacket cleans-up a packet on an +// unordered channel by proving that the associated acknowledgement has been +//written. +func (k Keeper) CleanupPacket( + ctx sdk.Context, + packet exported.PacketI, + proof commitmentexported.Proof, + proofHeight, + nextSequenceRecv uint64, + acknowledgement []byte, +) (exported.PacketI, error) { + channel, found := k.GetChannel(ctx, packet.GetSourcePort(), packet.GetSourceChannel()) + if !found { + return nil, sdkerrors.Wrap(types.ErrChannelNotFound, packet.GetSourceChannel()) + } + + if channel.State != exported.OPEN { + return nil, sdkerrors.Wrapf( + types.ErrInvalidChannelState, + "channel state is not OPEN (got %s)", channel.State.String(), + ) + } + + // TODO: blocked by #5542 + // capKey, found := k.GetChannelCapability(ctx, packet.GetSourcePort(), packet.GetSourceChannel()) + // if !found { + // return nil, types.ErrChannelCapabilityNotFound + // } + + // portCapabilityKey := sdk.NewKVStoreKey(capKey) + + // if !k.portKeeper.Authenticate(portCapabilityKey, packet.GetSourcePort()) { + // return nil, sdkerrors.Wrapf(port.ErrInvalidPort, "invalid source port: %s", packet.GetSourcePort()) + // } + + if packet.GetDestPort() != channel.Counterparty.PortID { + return nil, sdkerrors.Wrapf(types.ErrInvalidPacket, + "packet destination port doesn't match the counterparty's port (%s ≠ %s)", packet.GetDestPort(), channel.Counterparty.PortID, + ) + } + + if packet.GetDestChannel() != channel.Counterparty.ChannelID { + return nil, sdkerrors.Wrapf( + types.ErrInvalidPacket, + "packet destination channel doesn't match the counterparty's channel (%s ≠ %s)", packet.GetDestChannel(), channel.Counterparty.ChannelID, + ) + } + + connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) + if !found { + return nil, sdkerrors.Wrap(connection.ErrConnectionNotFound, channel.ConnectionHops[0]) + } + + // check that packet has been received on the other end + if nextSequenceRecv <= packet.GetSequence() { + return nil, sdkerrors.Wrap(types.ErrInvalidPacket, "packet already received") + } + + commitment := k.GetPacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) + + // verify we sent the packet and haven't cleared it out yet + if !bytes.Equal(commitment, types.CommitPacket(packet)) { + return nil, sdkerrors.Wrap(types.ErrInvalidPacket, "packet hasn't been sent") + } + + var err error + switch channel.Ordering { + case exported.ORDERED: + // check that the recv sequence is as claimed + err = k.connectionKeeper.VerifyNextSequenceRecv( + ctx, connectionEnd, proofHeight, proof, + packet.GetDestPort(), packet.GetDestChannel(), nextSequenceRecv, + ) + case exported.UNORDERED: + err = k.connectionKeeper.VerifyPacketAcknowledgement( + ctx, connectionEnd, proofHeight, proof, + packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence(), + acknowledgement, + ) + default: + panic(sdkerrors.Wrapf(types.ErrInvalidChannelOrdering, channel.Ordering.String())) + } + + if err != nil { + return nil, sdkerrors.Wrap(err, "packet verification failed") + } + + k.deletePacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) + + // log that a packet has been acknowledged + k.Logger(ctx).Info(fmt.Sprintf("packet cleaned-up: %v", packet)) + + // emit an event marking that we have cleaned up the packet + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeCleanupPacket, + sdk.NewAttribute(types.AttributeKeyTimeout, fmt.Sprintf("%d", packet.GetTimeoutHeight())), + sdk.NewAttribute(types.AttributeKeySequence, fmt.Sprintf("%d", packet.GetSequence())), + sdk.NewAttribute(types.AttributeKeySrcPort, packet.GetSourcePort()), + sdk.NewAttribute(types.AttributeKeySrcChannel, packet.GetSourceChannel()), + sdk.NewAttribute(types.AttributeKeyDstPort, packet.GetDestPort()), + sdk.NewAttribute(types.AttributeKeyDstChannel, packet.GetDestChannel()), + ), + }) + + return packet, nil +} diff --git a/x/ibc/04-channel/keeper/packet_test.go b/x/ibc/04-channel/keeper/packet_test.go new file mode 100644 index 000000000000..c38d68961ec0 --- /dev/null +++ b/x/ibc/04-channel/keeper/packet_test.go @@ -0,0 +1,423 @@ +package keeper_test + +import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/x/capability" + connectionexported "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" + + transfertypes "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/types" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +func (suite *KeeperTestSuite) TestSendPacket() { + counterparty := types.NewCounterparty(testPort2, testChannel2) + var packet exported.PacketI + + var channelCap *capability.Capability + testCases := []testCase{ + {"success", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.CreateClient(suite.chainA) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetNextSequenceSend(suite.chainB.GetContext(), testPort1, testChannel1, 1) + }, true}, + {"packet basic validation failed", func() { + packet = types.NewPacket(mockFailPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + }, false}, + {"channel not found", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + }, false}, + {"channel closed", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.CLOSED, exported.ORDERED, testConnectionIDA) + }, false}, + {"packet dest port ≠ channel counterparty port", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, testPort3, counterparty.GetChannelID(), 100) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + }, false}, + {"packet dest channel ID ≠ channel counterparty channel ID", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), testChannel3, 100) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + }, false}, + {"connection not found", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + }, false}, + {"connection is UNINITIALIZED", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.UNINITIALIZED) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + }, false}, + {"client state not found", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + }, false}, + {"timeout height passed", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + commitNBlocks(suite.chainB, 10) + suite.chainB.CreateClient(suite.chainA) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + }, false}, + {"next sequence send not found", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.CreateClient(suite.chainA) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + }, false}, + {"next sequence wrong", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.CreateClient(suite.chainA) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetNextSequenceSend(suite.chainB.GetContext(), testPort1, testChannel1, 5) + }, false}, + {"channel capability not found", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.CreateClient(suite.chainA) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetNextSequenceSend(suite.chainB.GetContext(), testPort1, testChannel1, 1) + channelCap = capability.NewCapability(3) + }, false}, + } + + for i, tc := range testCases { + tc := tc + suite.Run(fmt.Sprintf("Case %s, %d/%d tests", tc.msg, i, len(testCases)), func() { + suite.SetupTest() // reset + + var err error + channelCap, err = suite.chainB.App.ScopedIBCKeeper.NewCapability(suite.chainB.GetContext(), ibctypes.ChannelCapabilityPath(testPort1, testChannel1)) + suite.Require().Nil(err, "could not create capability") + + tc.malleate() + + err = suite.chainB.App.IBCKeeper.ChannelKeeper.SendPacket(suite.chainB.GetContext(), channelCap, packet) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } + +} + +func (suite *KeeperTestSuite) TestRecvPacket() { + counterparty := types.NewCounterparty(testPort1, testChannel1) + packetKey := ibctypes.KeyPacketCommitment(testPort2, testChannel2, 1) + + var packet exported.PacketI + + testCases := []testCase{ + {"success", func() { + suite.chainB.CreateClient(suite.chainA) + suite.chainA.CreateClient(suite.chainB) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainA.createConnection(testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + suite.chainA.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, exported.ORDERED, testConnectionIDB) + suite.chainA.App.IBCKeeper.ChannelKeeper.SetNextSequenceSend(suite.chainA.GetContext(), testPort2, testChannel2, 1) + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort2, testChannel2, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainA.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainA.GetContext(), testPort2, testChannel2, 1, types.CommitPacket(packet)) + + }, true}, + {"channel not found", func() {}, false}, + {"channel not open", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.INIT, exported.ORDERED, testConnectionIDA) + }, false}, + {"packet source port ≠ channel counterparty port", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.createChannel(testPort2, testChannel2, testPort3, testChannel1, exported.OPEN, exported.ORDERED, testConnectionIDA) + }, false}, + {"packet source channel ID ≠ channel counterparty channel ID", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.createChannel(testPort2, testChannel2, testPort1, testChannel3, exported.OPEN, exported.ORDERED, testConnectionIDA) + }, false}, + {"connection not found", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, exported.ORDERED, testConnectionIDA) + }, false}, + {"connection not OPEN", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.INIT) + suite.chainB.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, exported.ORDERED, testConnectionIDA) + }, false}, + {"timeout passed", func() { + commitNBlocks(suite.chainB, 10) + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, exported.ORDERED, testConnectionIDA) + }, false}, + {"validation failed", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, exported.ORDERED, testConnectionIDA) + }, false}, + } + + for i, tc := range testCases { + tc := tc + suite.Run(fmt.Sprintf("Case %s, %d/%d tests", tc.msg, i, len(testCases)), func() { + suite.SetupTest() // reset + tc.malleate() + + ctx := suite.chainB.GetContext() + + suite.chainB.updateClient(suite.chainA) + suite.chainA.updateClient(suite.chainB) + proof, proofHeight := queryProof(suite.chainA, packetKey) + + var err error + if tc.expPass { + _, err = suite.chainB.App.IBCKeeper.ChannelKeeper.RecvPacket(ctx, packet, proof, proofHeight+1) + suite.Require().NoError(err) + } else { + packet, err = suite.chainB.App.IBCKeeper.ChannelKeeper.RecvPacket(ctx, packet, ibctypes.InvalidProof{}, proofHeight) + suite.Require().Error(err) + } + }) + } + +} + +func (suite *KeeperTestSuite) TestPacketExecuted() { + counterparty := types.NewCounterparty(testPort2, testChannel2) + var packet types.Packet + + testCases := []testCase{ + {"success: UNORDERED", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainA.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, exported.UNORDERED, testConnectionIDA) + suite.chainA.App.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(suite.chainA.GetContext(), testPort2, testChannel2, 1) + }, true}, + {"success: ORDERED", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainA.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, exported.ORDERED, testConnectionIDA) + suite.chainA.App.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(suite.chainA.GetContext(), testPort2, testChannel2, 1) + }, true}, + {"channel not found", func() {}, false}, + {"channel not OPEN", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainA.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.CLOSED, exported.ORDERED, testConnectionIDA) + }, false}, + {"next sequence receive not found", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainA.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, exported.ORDERED, testConnectionIDA) + }, false}, + {"packet sequence ≠ next sequence receive", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainA.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, exported.ORDERED, testConnectionIDA) + suite.chainA.App.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(suite.chainA.GetContext(), testPort2, testChannel2, 5) + }, false}, + } + + for i, tc := range testCases { + tc := tc + suite.Run(fmt.Sprintf("Case %s, %d/%d tests", tc.msg, i, len(testCases)), func() { + suite.SetupTest() // reset + tc.malleate() + + err := suite.chainA.App.IBCKeeper.ChannelKeeper.PacketExecuted(suite.chainA.GetContext(), packet, mockSuccessPacket{}.GetBytes()) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *KeeperTestSuite) TestAcknowledgePacket() { + counterparty := types.NewCounterparty(testPort2, testChannel2) + var packet types.Packet + packetKey := ibctypes.KeyPacketAcknowledgement(testPort2, testChannel2, 1) + + ack := transfertypes.AckDataTransfer{}.GetBytes() + + testCases := []testCase{ + {"success", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.CreateClient(suite.chainA) + suite.chainA.CreateClient(suite.chainB) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainA.createConnection(testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + suite.chainA.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, exported.ORDERED, testConnectionIDB) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 1, types.CommitPacket(packet)) + suite.chainA.App.IBCKeeper.ChannelKeeper.SetPacketAcknowledgement(suite.chainA.GetContext(), testPort2, testChannel2, 1, ack) + }, true}, + {"channel not found", func() {}, false}, + {"channel not open", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.CLOSED, exported.ORDERED, testConnectionIDA) + }, false}, + {"packet source port ≠ channel counterparty port", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.createChannel(testPort1, testChannel1, testPort3, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + }, false}, + {"packet source channel ID ≠ channel counterparty channel ID", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel3, exported.OPEN, exported.ORDERED, testConnectionIDA) + }, false}, + {"connection not found", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + }, false}, + {"connection not OPEN", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.INIT) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + }, false}, + {"packet hasn't been sent", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + }, false}, + {"packet ack verification failed", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 1, types.CommitPacket(packet)) + }, false}, + } + + for i, tc := range testCases { + tc := tc + suite.Run(fmt.Sprintf("Case %s, %d/%d tests", tc.msg, i, len(testCases)), func() { + suite.SetupTest() // reset + tc.malleate() + + suite.chainA.updateClient(suite.chainB) + suite.chainB.updateClient(suite.chainA) + proof, proofHeight := queryProof(suite.chainA, packetKey) + + ctx := suite.chainB.GetContext() + if tc.expPass { + packetOut, err := suite.chainB.App.IBCKeeper.ChannelKeeper.AcknowledgePacket(ctx, packet, ack, proof, proofHeight+1) + suite.Require().NoError(err) + suite.Require().NotNil(packetOut) + } else { + packetOut, err := suite.chainB.App.IBCKeeper.ChannelKeeper.AcknowledgePacket(ctx, packet, ack, proof, proofHeight+1) + suite.Require().Error(err) + suite.Require().Nil(packetOut) + } + }) + } +} + +func (suite *KeeperTestSuite) TestCleanupPacket() { + counterparty := types.NewCounterparty(testPort2, testChannel2) + packetKey := ibctypes.KeyPacketAcknowledgement(testPort2, testChannel2, 1) + var ( + packet types.Packet + nextSeqRecv uint64 + ) + + ack := []byte("ack") + + testCases := []testCase{ + {"success", func() { + nextSeqRecv = 10 + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainA.CreateClient(suite.chainB) + suite.chainB.CreateClient(suite.chainA) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainA.createConnection(testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.UNORDERED, testConnectionIDA) + suite.chainA.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, exported.UNORDERED, testConnectionIDB) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 1, types.CommitPacket(packet)) + suite.chainA.App.IBCKeeper.ChannelKeeper.SetPacketAcknowledgement(suite.chainA.GetContext(), testPort2, testChannel2, 1, ack) + }, true}, + {"channel not found", func() {}, false}, + {"channel not open", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.CLOSED, exported.ORDERED, testConnectionIDA) + }, false}, + {"packet source port ≠ channel counterparty port", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.createChannel(testPort1, testChannel1, testPort3, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + }, false}, + {"packet source channel ID ≠ channel counterparty channel ID", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel3, exported.OPEN, exported.ORDERED, testConnectionIDA) + }, false}, + {"connection not found", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + }, false}, + {"connection not OPEN", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.INIT) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + }, false}, + {"packet already received ", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 10, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + }, false}, + {"packet hasn't been sent", func() { + nextSeqRecv = 10 + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + }, false}, + {"next seq receive verification failed", func() { + nextSeqRecv = 10 + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 1, types.CommitPacket(packet)) + }, false}, + {"packet ack verification failed", func() { + nextSeqRecv = 10 + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.UNORDERED, testConnectionIDA) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 1, types.CommitPacket(packet)) + }, false}, + } + + for i, tc := range testCases { + tc := tc + suite.Run(fmt.Sprintf("Case %s, %d/%d tests", tc.msg, i, len(testCases)), func() { + suite.SetupTest() // reset + tc.malleate() + + ctx := suite.chainB.GetContext() + + suite.chainB.updateClient(suite.chainA) + suite.chainA.updateClient(suite.chainB) + proof, proofHeight := queryProof(suite.chainA, packetKey) + + if tc.expPass { + packetOut, err := suite.chainB.App.IBCKeeper.ChannelKeeper.CleanupPacket(ctx, packet, proof, proofHeight+1, nextSeqRecv, ack) + suite.Require().NoError(err) + suite.Require().NotNil(packetOut) + } else { + packetOut, err := suite.chainB.App.IBCKeeper.ChannelKeeper.CleanupPacket(ctx, packet, ibctypes.InvalidProof{}, proofHeight+1, nextSeqRecv, ack) + suite.Require().Error(err) + suite.Require().Nil(packetOut) + } + }) + } +} + +type mockSuccessPacket struct{} + +// GetBytes returns the serialised packet data +func (mp mockSuccessPacket) GetBytes() []byte { return []byte("THIS IS A SUCCESS PACKET") } + +type mockFailPacket struct{} + +// GetBytes returns the serialised packet data (without timeout) +func (mp mockFailPacket) GetBytes() []byte { return []byte("THIS IS A FAILURE PACKET") } diff --git a/x/ibc/04-channel/keeper/querier.go b/x/ibc/04-channel/keeper/querier.go new file mode 100644 index 000000000000..91dfce5ec5ed --- /dev/null +++ b/x/ibc/04-channel/keeper/querier.go @@ -0,0 +1,68 @@ +package keeper + +import ( + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" +) + +// QuerierChannels defines the sdk.Querier to query all the channels. +func QuerierChannels(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { + var params types.QueryAllChannelsParams + + if err := k.cdc.UnmarshalJSON(req.Data, ¶ms); err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) + } + + channels := k.GetAllChannels(ctx) + + start, end := client.Paginate(len(channels), params.Page, params.Limit, 100) + if start < 0 || end < 0 { + channels = []types.IdentifiedChannel{} + } else { + channels = channels[start:end] + } + + res, err := codec.MarshalJSONIndent(k.cdc, channels) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) + } + + return res, nil +} + +// QuerierConnectionChannels defines the sdk.Querier to query all the channels for a connection. +func QuerierConnectionChannels(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { + var params types.QueryConnectionChannelsParams + + if err := k.cdc.UnmarshalJSON(req.Data, ¶ms); err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) + } + + channels := k.GetAllChannels(ctx) + + connectionChannels := []types.IdentifiedChannel{} + for _, channel := range channels { + if channel.Channel.ConnectionHops[0] == params.Connection { + connectionChannels = append(connectionChannels, channel) + } + } + + start, end := client.Paginate(len(connectionChannels), params.Page, params.Limit, 100) + if start < 0 || end < 0 { + connectionChannels = []types.IdentifiedChannel{} + } else { + connectionChannels = channels[start:end] + } + + res, err := codec.MarshalJSONIndent(k.cdc, connectionChannels) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) + } + + return res, nil +} diff --git a/x/ibc/04-channel/keeper/timeout.go b/x/ibc/04-channel/keeper/timeout.go new file mode 100644 index 000000000000..21234f9a26b1 --- /dev/null +++ b/x/ibc/04-channel/keeper/timeout.go @@ -0,0 +1,260 @@ +package keeper + +import ( + "bytes" + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" + commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" +) + +// TimeoutPacket is called by a module which originally attempted to send a +// packet to a counterparty module, where the timeout height has passed on the +// counterparty chain without the packet being committed, to prove that the +// packet can no longer be executed and to allow the calling module to safely +// perform appropriate state transitions. +func (k Keeper) TimeoutPacket( + ctx sdk.Context, + packet exported.PacketI, + proof commitmentexported.Proof, + proofHeight, + nextSequenceRecv uint64, +) (exported.PacketI, error) { + channel, found := k.GetChannel(ctx, packet.GetSourcePort(), packet.GetSourceChannel()) + if !found { + return nil, sdkerrors.Wrapf( + types.ErrChannelNotFound, + packet.GetSourcePort(), packet.GetSourceChannel(), + ) + } + + if channel.State != exported.OPEN { + return nil, sdkerrors.Wrapf( + types.ErrInvalidChannelState, + "channel state is not OPEN (got %s)", channel.State.String(), + ) + } + + // NOTE: TimeoutPacket is called by the AnteHandler which acts upon the packet.Route(), + // so the capability authentication can be omitted here + + if packet.GetDestPort() != channel.Counterparty.PortID { + return nil, sdkerrors.Wrapf( + types.ErrInvalidPacket, + "packet destination port doesn't match the counterparty's port (%s ≠ %s)", packet.GetDestPort(), channel.Counterparty.PortID, + ) + } + + if packet.GetDestChannel() != channel.Counterparty.ChannelID { + return nil, sdkerrors.Wrapf( + types.ErrInvalidPacket, + "packet destination channel doesn't match the counterparty's channel (%s ≠ %s)", packet.GetDestChannel(), channel.Counterparty.ChannelID, + ) + } + + connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) + if !found { + return nil, sdkerrors.Wrap( + connection.ErrConnectionNotFound, + channel.ConnectionHops[0], + ) + } + + // check that timeout height has passed on the other end + if proofHeight < packet.GetTimeoutHeight() { + return nil, types.ErrPacketTimeout + } + + // check that packet has not been received + if nextSequenceRecv >= packet.GetSequence() { + return nil, sdkerrors.Wrap(types.ErrInvalidPacket, "packet already received") + } + + commitment := k.GetPacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) + + // verify we sent the packet and haven't cleared it out yet + if !bytes.Equal(commitment, types.CommitPacket(packet)) { + return nil, sdkerrors.Wrap(types.ErrInvalidPacket, "packet hasn't been sent") + } + + var err error + switch channel.Ordering { + case exported.ORDERED: + // check that the recv sequence is as claimed + err = k.connectionKeeper.VerifyNextSequenceRecv( + ctx, connectionEnd, proofHeight, proof, + packet.GetDestPort(), packet.GetDestChannel(), nextSequenceRecv, + ) + case exported.UNORDERED: + err = k.connectionKeeper.VerifyPacketAcknowledgementAbsence( + ctx, connectionEnd, proofHeight, proof, + packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence(), + ) + default: + panic(sdkerrors.Wrapf(types.ErrInvalidChannelOrdering, channel.Ordering.String())) + } + + if err != nil { + return nil, err + } + + k.Logger(ctx).Info(fmt.Sprintf("packet timed-out: %v", packet)) + + // emit an event marking that we have processed the timeout + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeTimeoutPacket, + sdk.NewAttribute(types.AttributeKeyTimeout, fmt.Sprintf("%d", packet.GetTimeoutHeight())), + sdk.NewAttribute(types.AttributeKeySequence, fmt.Sprintf("%d", packet.GetSequence())), + sdk.NewAttribute(types.AttributeKeySrcPort, packet.GetSourcePort()), + sdk.NewAttribute(types.AttributeKeySrcChannel, packet.GetSourceChannel()), + sdk.NewAttribute(types.AttributeKeyDstPort, packet.GetDestPort()), + sdk.NewAttribute(types.AttributeKeyDstChannel, packet.GetDestChannel()), + ), + }) + + // NOTE: the remaining code is located on the TimeoutExecuted function + return packet, nil +} + +// TimeoutExecuted deletes the commitment send from this chain after it verifies timeout +func (k Keeper) TimeoutExecuted(ctx sdk.Context, packet exported.PacketI) error { + channel, found := k.GetChannel(ctx, packet.GetSourcePort(), packet.GetSourceChannel()) + if !found { + return sdkerrors.Wrapf(types.ErrChannelNotFound, packet.GetSourcePort(), packet.GetSourceChannel()) + } + + // TODO: blocked by #5542 + // _, found = k.GetChannelCapability(ctx, packet.GetSourcePort(), packet.GetSourceChannel()) + // if !found { + // return types.ErrChannelCapabilityNotFound + // } + + k.deletePacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) + + if channel.Ordering == exported.ORDERED { + channel.State = exported.CLOSED + k.SetChannel(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), channel) + } + + return nil +} + +// TimeoutOnClose is called by a module in order to prove that the channel to +// which an unreceived packet was addressed has been closed, so the packet will +// never be received (even if the timeoutHeight has not yet been reached). +func (k Keeper) TimeoutOnClose( + ctx sdk.Context, + packet types.Packet, // nolint: interfacer + proof, + proofClosed commitmentexported.Proof, + proofHeight, + nextSequenceRecv uint64, +) (exported.PacketI, error) { + channel, found := k.GetChannel(ctx, packet.GetSourcePort(), packet.GetSourceChannel()) + if !found { + return nil, sdkerrors.Wrapf(types.ErrChannelNotFound, packet.GetSourcePort(), packet.GetSourceChannel()) + } + + // TODO: blocked by #5542 + // capKey, found := k.GetChannelCapability(ctx, packet.GetSourcePort(), packet.GetSourceChannel()) + // if !found { + // return nil, types.ErrChannelCapabilityNotFound + // } + + // portCapabilityKey := sdk.NewKVStoreKey(capKey) + + // if !k.portKeeper.Authenticate(portCapabilityKey, packet.GetSourcePort()) { + // return nil, sdkerrors.Wrap(port.ErrInvalidPort, packet.GetSourcePort()) + // } + + if packet.GetDestPort() != channel.Counterparty.PortID { + return nil, sdkerrors.Wrapf( + types.ErrInvalidPacket, + "packet destination port doesn't match the counterparty's port (%s ≠ %s)", packet.GetDestPort(), channel.Counterparty.PortID, + ) + } + + if packet.GetDestChannel() != channel.Counterparty.ChannelID { + return nil, sdkerrors.Wrapf( + types.ErrInvalidPacket, + "packet destination channel doesn't match the counterparty's channel (%s ≠ %s)", packet.GetDestChannel(), channel.Counterparty.ChannelID, + ) + } + + connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) + if !found { + return nil, sdkerrors.Wrap(connection.ErrConnectionNotFound, channel.ConnectionHops[0]) + } + + commitment := k.GetPacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) + + // verify we sent the packet and haven't cleared it out yet + if !bytes.Equal(commitment, types.CommitPacket(packet)) { + return nil, sdkerrors.Wrap(types.ErrInvalidPacket, "packet hasn't been sent") + } + + counterpartyHops, found := k.CounterpartyHops(ctx, channel) + if !found { + // Should not reach here, connectionEnd was able to be retrieved above + panic("cannot find connection") + } + + counterparty := types.NewCounterparty(packet.GetSourcePort(), packet.GetSourceChannel()) + expectedChannel := types.NewChannel( + exported.CLOSED, channel.Ordering, counterparty, counterpartyHops, channel.Version, + ) + + // check that the opposing channel end has closed + if err := k.connectionKeeper.VerifyChannelState( + ctx, connectionEnd, proofHeight, proofClosed, + channel.Counterparty.PortID, channel.Counterparty.ChannelID, + expectedChannel, + ); err != nil { + return nil, err + } + + var err error + switch channel.Ordering { + case exported.ORDERED: + // check that the recv sequence is as claimed + err = k.connectionKeeper.VerifyNextSequenceRecv( + ctx, connectionEnd, proofHeight, proof, + packet.GetDestPort(), packet.GetDestChannel(), nextSequenceRecv, + ) + case exported.UNORDERED: + err = k.connectionKeeper.VerifyPacketAcknowledgementAbsence( + ctx, connectionEnd, proofHeight, proof, + packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence(), + ) + default: + panic(sdkerrors.Wrapf(types.ErrInvalidChannelOrdering, channel.Ordering.String())) + } + + if err != nil { + return nil, err + } + + k.deletePacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) + + k.Logger(ctx).Info(fmt.Sprintf("packet timed-out on close: %v", packet)) + + // emit an event marking that we have processed the timeout + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeTimeoutPacket, + sdk.NewAttribute(types.AttributeKeyTimeout, fmt.Sprintf("%d", packet.GetTimeoutHeight())), + sdk.NewAttribute(types.AttributeKeySequence, fmt.Sprintf("%d", packet.GetSequence())), + sdk.NewAttribute(types.AttributeKeySrcPort, packet.GetSourcePort()), + sdk.NewAttribute(types.AttributeKeySrcChannel, packet.GetSourceChannel()), + sdk.NewAttribute(types.AttributeKeyDstPort, packet.GetDestPort()), + sdk.NewAttribute(types.AttributeKeyDstChannel, packet.GetDestChannel()), + ), + }) + + return packet, nil +} diff --git a/x/ibc/04-channel/keeper/timeout_test.go b/x/ibc/04-channel/keeper/timeout_test.go new file mode 100644 index 000000000000..06bd8a76601a --- /dev/null +++ b/x/ibc/04-channel/keeper/timeout_test.go @@ -0,0 +1,233 @@ +package keeper_test + +import ( + "fmt" + + connectionexported "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +func (suite *KeeperTestSuite) TestTimeoutPacket() { + counterparty := types.NewCounterparty(testPort2, testChannel2) + packetKey := ibctypes.KeyPacketAcknowledgement(testPort2, testChannel2, 2) + var ( + packet types.Packet + nextSeqRecv uint64 + ) + + testCases := []testCase{ + {"success", func() { + nextSeqRecv = 1 + packet = types.NewPacket(newMockTimeoutPacket().GetBytes(), 2, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 1) + suite.chainB.CreateClient(suite.chainA) + suite.chainA.CreateClient(suite.chainB) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.UNORDERED, testConnectionIDA) + suite.chainA.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, exported.UNORDERED, testConnectionIDB) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 2, types.CommitPacket(packet)) + }, true}, + {"channel not found", func() {}, false}, + {"channel not open", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.CLOSED, exported.ORDERED, testConnectionIDA) + }, false}, + {"packet source port ≠ channel counterparty port", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.createChannel(testPort1, testChannel1, testPort3, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + }, false}, + {"packet source channel ID ≠ channel counterparty channel ID", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel3, exported.OPEN, exported.ORDERED, testConnectionIDA) + }, false}, + {"connection not found", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + }, false}, + {"timeout", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 10, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + }, false}, + {"packet already received ", func() { + nextSeqRecv = 2 + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + }, false}, + {"packet hasn't been sent", func() { + nextSeqRecv = 1 + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 2, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + }, false}, + {"next seq receive verification failed", func() { + nextSeqRecv = 1 + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 2, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 2, types.CommitPacket(packet)) + }, false}, + {"packet ack verification failed", func() { + nextSeqRecv = 1 + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 2, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.UNORDERED, testConnectionIDA) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 2, types.CommitPacket(packet)) + }, false}, + } + + for i, tc := range testCases { + tc := tc + suite.Run(fmt.Sprintf("Case %s, %d/%d tests", tc.msg, i, len(testCases)), func() { + suite.SetupTest() // reset + tc.malleate() + + ctx := suite.chainB.GetContext() + + suite.chainB.updateClient(suite.chainA) + suite.chainA.updateClient(suite.chainB) + proof, proofHeight := queryProof(suite.chainA, packetKey) + + if tc.expPass { + packetOut, err := suite.chainB.App.IBCKeeper.ChannelKeeper.TimeoutPacket(ctx, packet, proof, proofHeight+1, nextSeqRecv) + suite.Require().NoError(err) + suite.Require().NotNil(packetOut) + } else { + packetOut, err := suite.chainB.App.IBCKeeper.ChannelKeeper.TimeoutPacket(ctx, packet, ibctypes.InvalidProof{}, proofHeight+1, nextSeqRecv) + suite.Require().Error(err) + suite.Require().Nil(packetOut) + } + }) + } +} + +func (suite *KeeperTestSuite) TestTimeoutExecuted() { + var packet types.Packet + + testCases := []testCase{ + {"success ORDERED", func() { + packet = types.NewPacket(newMockTimeoutPacket().GetBytes(), 1, testPort1, testChannel1, testPort2, testChannel2, 3) + suite.chainA.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + }, true}, + {"channel not found", func() {}, false}, + } + + for i, tc := range testCases { + tc := tc + suite.Run(fmt.Sprintf("Case %s, %d/%d tests", tc.msg, i, len(testCases)), func() { + suite.SetupTest() // reset + tc.malleate() + + err := suite.chainA.App.IBCKeeper.ChannelKeeper.TimeoutExecuted(suite.chainA.GetContext(), packet) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *KeeperTestSuite) TestTimeoutOnClose() { + channelKey := ibctypes.KeyChannel(testPort2, testChannel2) + packetKey := ibctypes.KeyPacketAcknowledgement(testPort1, testChannel1, 2) + counterparty := types.NewCounterparty(testPort2, testChannel2) + var ( + packet types.Packet + nextSeqRecv uint64 + ) + + testCases := []testCase{ + {"success", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 2, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.CreateClient(suite.chainA) + suite.chainA.CreateClient(suite.chainB) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainA.createConnection(testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.UNORDERED, testConnectionIDA) + suite.chainA.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.CLOSED, exported.UNORDERED, testConnectionIDB) // channel on chainA is closed + suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 2, types.CommitPacket(packet)) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(suite.chainB.GetContext(), testPort1, testChannel1, nextSeqRecv) + }, true}, + {"channel not found", func() {}, false}, + {"packet dest port ≠ channel counterparty port", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.createChannel(testPort1, testChannel1, testPort3, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + }, false}, + {"packet dest channel ID ≠ channel counterparty channel ID", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel3, exported.OPEN, exported.ORDERED, testConnectionIDA) + }, false}, + {"connection not found", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + }, false}, + {"packet hasn't been sent", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 2, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + }, false}, + {"channel verification failed", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 2, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.CreateClient(suite.chainA) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.UNORDERED, testConnectionIDA) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 2, types.CommitPacket(packet)) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(suite.chainB.GetContext(), testPort1, testChannel1, nextSeqRecv) + }, false}, + {"next seq receive verification failed", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 2, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.CreateClient(suite.chainA) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 2, types.CommitPacket(packet)) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(suite.chainB.GetContext(), testPort1, testChannel1, nextSeqRecv) + }, false}, + {"packet ack verification failed", func() { + packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 2, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 100) + suite.chainB.CreateClient(suite.chainA) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.UNORDERED, testConnectionIDA) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 2, types.CommitPacket(packet)) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(suite.chainB.GetContext(), testPort1, testChannel1, nextSeqRecv) + }, false}, + } + + for i, tc := range testCases { + tc := tc + suite.Run(fmt.Sprintf("Case %s, %d/%d tests", tc.msg, i, len(testCases)), func() { + suite.SetupTest() // reset + tc.malleate() + + suite.chainB.updateClient(suite.chainA) + suite.chainA.updateClient(suite.chainB) + proofClosed, proofHeight := queryProof(suite.chainA, channelKey) + proofAckAbsence, _ := queryProof(suite.chainA, packetKey) + + ctx := suite.chainB.GetContext() + if tc.expPass { + packetOut, err := suite.chainB.App.IBCKeeper.ChannelKeeper.TimeoutOnClose(ctx, packet, proofAckAbsence, proofClosed, proofHeight+1, nextSeqRecv) + suite.Require().NoError(err) + suite.Require().NotNil(packetOut) + } else { + packetOut, err := suite.chainB.App.IBCKeeper.ChannelKeeper.TimeoutOnClose(ctx, packet, invalidProof{}, invalidProof{}, proofHeight+1, nextSeqRecv) + suite.Require().Error(err) + suite.Require().Nil(packetOut) + } + }) + } + +} + +type mockTimeoutPacket struct{} + +func newMockTimeoutPacket() mockTimeoutPacket { + return mockTimeoutPacket{} +} + +// GetBytes returns the serialised packet data (without timeout) +func (mp mockTimeoutPacket) GetBytes() []byte { return []byte("THIS IS A TIMEOUT PACKET") } diff --git a/x/ibc/04-channel/module.go b/x/ibc/04-channel/module.go new file mode 100644 index 000000000000..7fb21535e948 --- /dev/null +++ b/x/ibc/04-channel/module.go @@ -0,0 +1,33 @@ +package channel + +import ( + "fmt" + + "github.com/gorilla/mux" + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/client/cli" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/client/rest" +) + +// Name returns the IBC connection ICS name +func Name() string { + return SubModuleName +} + +// RegisterRESTRoutes registers the REST routes for the IBC channel +func RegisterRESTRoutes(ctx context.CLIContext, rtr *mux.Router, queryRoute string) { + rest.RegisterRoutes(ctx, rtr, fmt.Sprintf("%s/%s", queryRoute, SubModuleName)) +} + +// GetTxCmd returns the root tx command for the IBC connections. +func GetTxCmd(cdc *codec.Codec, storeKey string) *cobra.Command { + return cli.GetTxCmd(fmt.Sprintf("%s/%s", storeKey, SubModuleName), cdc) +} + +// GetQueryCmd returns no root query command for the IBC connections. +func GetQueryCmd(cdc *codec.Codec, queryRoute string) *cobra.Command { + return cli.GetQueryCmd(fmt.Sprintf("%s/%s", queryRoute, SubModuleName), cdc) +} diff --git a/x/ibc/04-channel/types/channel.go b/x/ibc/04-channel/types/channel.go new file mode 100644 index 000000000000..ebb026bc86ef --- /dev/null +++ b/x/ibc/04-channel/types/channel.go @@ -0,0 +1,128 @@ +package types + +import ( + "strings" + + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +// Channel defines... +type Channel struct { + State exported.State `json:"state" yaml:"state"` + Ordering exported.Order `json:"ordering" yaml:"ordering"` + Counterparty Counterparty `json:"counterparty" yaml:"counterparty"` + ConnectionHops []string `json:"connection_hops" yaml:"connection_hops"` + Version string `json:"version" yaml:"version "` +} + +// NewChannel creates a new Channel instance +func NewChannel( + state exported.State, ordering exported.Order, counterparty Counterparty, + hops []string, version string, +) Channel { + return Channel{ + State: state, + Ordering: ordering, + Counterparty: counterparty, + ConnectionHops: hops, + Version: version, + } +} + +// GetState implements Channel interface. +func (ch Channel) GetState() exported.State { + return ch.State +} + +// GetOrdering implements Channel interface. +func (ch Channel) GetOrdering() exported.Order { + return ch.Ordering +} + +// GetCounterparty implements Channel interface. +func (ch Channel) GetCounterparty() exported.CounterpartyI { + return ch.Counterparty +} + +// GetConnectionHops implements Channel interface. +func (ch Channel) GetConnectionHops() []string { + return ch.ConnectionHops +} + +// GetVersion implements Channel interface. +func (ch Channel) GetVersion() string { + return ch.Version +} + +// ValidateBasic performs a basic validation of the channel fields +func (ch Channel) ValidateBasic() error { + if ch.State.String() == "" { + return sdkerrors.Wrap(ErrInvalidChannel, ErrInvalidChannelState.Error()) + } + if ch.Ordering.String() == "" { + return sdkerrors.Wrap(ErrInvalidChannel, ErrInvalidChannelOrdering.Error()) + } + if len(ch.ConnectionHops) != 1 { + return sdkerrors.Wrap( + ErrInvalidChannel, + sdkerrors.Wrap(ErrTooManyConnectionHops, "IBC v1.0 only supports one connection hop").Error(), + ) + } + if err := host.DefaultConnectionIdentifierValidator(ch.ConnectionHops[0]); err != nil { + return sdkerrors.Wrap( + ErrInvalidChannel, + sdkerrors.Wrap(err, "invalid connection hop ID").Error(), + ) + } + if strings.TrimSpace(ch.Version) == "" { + return sdkerrors.Wrap( + ErrInvalidChannel, + sdkerrors.Wrap(ibctypes.ErrInvalidVersion, "channel version can't be blank").Error(), + ) + } + return ch.Counterparty.ValidateBasic() +} + +// Counterparty defines the counterparty chain's channel and port identifiers +type Counterparty struct { + PortID string `json:"port_id" yaml:"port_id"` + ChannelID string `json:"channel_id" yaml:"channel_id"` +} + +// NewCounterparty returns a new Counterparty instance +func NewCounterparty(portID, channelID string) Counterparty { + return Counterparty{ + PortID: portID, + ChannelID: channelID, + } +} + +// GetPortID implements CounterpartyI interface +func (c Counterparty) GetPortID() string { + return c.PortID +} + +// GetChannelID implements CounterpartyI interface +func (c Counterparty) GetChannelID() string { + return c.ChannelID +} + +// ValidateBasic performs a basic validation check of the identifiers +func (c Counterparty) ValidateBasic() error { + if err := host.DefaultPortIdentifierValidator(c.PortID); err != nil { + return sdkerrors.Wrap( + ErrInvalidCounterparty, + sdkerrors.Wrap(err, "invalid counterparty connection ID").Error(), + ) + } + if err := host.DefaultChannelIdentifierValidator(c.ChannelID); err != nil { + return sdkerrors.Wrap( + ErrInvalidCounterparty, + sdkerrors.Wrap(err, "invalid counterparty client ID").Error(), + ) + } + return nil +} diff --git a/x/ibc/04-channel/types/channel_test.go b/x/ibc/04-channel/types/channel_test.go new file mode 100644 index 000000000000..ba1ccb10bf39 --- /dev/null +++ b/x/ibc/04-channel/types/channel_test.go @@ -0,0 +1,30 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestCounterpartyValidateBasic(t *testing.T) { + testCases := []struct { + name string + counterparty Counterparty + expPass bool + }{ + {"valid counterparty", Counterparty{"portidone", "channelidone"}, true}, + {"invalid port id", Counterparty{"InvalidPort", "channelidone"}, false}, + {"invalid channel id", Counterparty{"portidone", "InvalidChannel"}, false}, + } + + for i, tc := range testCases { + tc := tc + + err := tc.counterparty.ValidateBasic() + if tc.expPass { + require.NoError(t, err, "valid test case %d failed: %s", i, tc.name) + } else { + require.Error(t, err, "invalid test case %d passed: %s", i, tc.name) + } + } +} diff --git a/x/ibc/04-channel/types/codec.go b/x/ibc/04-channel/types/codec.go new file mode 100644 index 000000000000..270852973248 --- /dev/null +++ b/x/ibc/04-channel/types/codec.go @@ -0,0 +1,42 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" + client "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" +) + +// SubModuleCdc defines the IBC channel codec. +var SubModuleCdc *codec.Codec + +func init() { + SubModuleCdc = codec.New() + commitmenttypes.RegisterCodec(SubModuleCdc) + client.RegisterCodec(SubModuleCdc) + RegisterCodec(SubModuleCdc) +} + +// RegisterCodec registers all the necessary types and interfaces for the +// IBC channel. +func RegisterCodec(cdc *codec.Codec) { + cdc.RegisterInterface((*exported.PacketI)(nil), nil) + cdc.RegisterConcrete(Channel{}, "ibc/channel/Channel", nil) + cdc.RegisterConcrete(Packet{}, "ibc/channel/Packet", nil) + + cdc.RegisterConcrete(MsgChannelOpenInit{}, "ibc/channel/MsgChannelOpenInit", nil) + cdc.RegisterConcrete(MsgChannelOpenTry{}, "ibc/channel/MsgChannelOpenTry", nil) + cdc.RegisterConcrete(MsgChannelOpenAck{}, "ibc/channel/MsgChannelOpenAck", nil) + cdc.RegisterConcrete(MsgChannelOpenConfirm{}, "ibc/channel/MsgChannelOpenConfirm", nil) + cdc.RegisterConcrete(MsgChannelCloseInit{}, "ibc/channel/MsgChannelCloseInit", nil) + cdc.RegisterConcrete(MsgChannelCloseConfirm{}, "ibc/channel/MsgChannelCloseConfirm", nil) + + cdc.RegisterConcrete(MsgPacket{}, "ibc/channel/MsgPacket", nil) + + SetSubModuleCodec(cdc) +} + +// SetSubModuleCodec sets the ibc channel codec +func SetSubModuleCodec(cdc *codec.Codec) { + SubModuleCdc = cdc +} diff --git a/x/ibc/04-channel/types/errors.go b/x/ibc/04-channel/types/errors.go new file mode 100644 index 000000000000..1def7a4d004e --- /dev/null +++ b/x/ibc/04-channel/types/errors.go @@ -0,0 +1,23 @@ +package types + +import ( + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +// IBC channel sentinel errors +var ( + ErrChannelExists = sdkerrors.Register(SubModuleName, 1, "channel already exists") + ErrChannelNotFound = sdkerrors.Register(SubModuleName, 2, "channel not found") + ErrInvalidChannel = sdkerrors.Register(SubModuleName, 3, "invalid channel") + ErrInvalidChannelState = sdkerrors.Register(SubModuleName, 4, "invalid channel state") + ErrInvalidChannelOrdering = sdkerrors.Register(SubModuleName, 5, "invalid channel ordering") + ErrInvalidCounterparty = sdkerrors.Register(SubModuleName, 6, "invalid counterparty channel") + ErrInvalidChannelCapability = sdkerrors.Register(SubModuleName, 7, "invalid channel capability") + ErrChannelCapabilityNotFound = sdkerrors.Register(SubModuleName, 8, "channel capability not found") + ErrSequenceSendNotFound = sdkerrors.Register(SubModuleName, 9, "sequence send not found") + ErrSequenceReceiveNotFound = sdkerrors.Register(SubModuleName, 10, "sequence receive not found") + ErrInvalidPacket = sdkerrors.Register(SubModuleName, 11, "invalid packet") + ErrPacketTimeout = sdkerrors.Register(SubModuleName, 12, "packet timeout") + ErrTooManyConnectionHops = sdkerrors.Register(SubModuleName, 13, "too many connection hops") + ErrAcknowledgementTooLong = sdkerrors.Register(SubModuleName, 14, "acknowledgement too long") +) diff --git a/x/ibc/04-channel/types/events.go b/x/ibc/04-channel/types/events.go new file mode 100644 index 000000000000..6896b225b142 --- /dev/null +++ b/x/ibc/04-channel/types/events.go @@ -0,0 +1,42 @@ +package types + +import ( + "fmt" + + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +// IBC channel events +const ( + AttributeKeyConnectionID = "connection_id" + AttributeKeyPortID = "port_id" + AttributeKeyChannelID = "channel_id" + AttributeCounterpartyPortID = "counterparty_port_id" + AttributeCounterpartyChannelID = "counterparty_channel_id" + + EventTypeSendPacket = "send_packet" + EventTypeRecvPacket = "recv_packet" + EventTypeAcknowledgePacket = "acknowledge_packet" + EventTypeCleanupPacket = "cleanup_packet" + EventTypeTimeoutPacket = "timeout_packet" + + AttributeKeyData = "packet_data" + AttributeKeyTimeout = "packet_timeout" + AttributeKeySequence = "packet_sequence" + AttributeKeySrcPort = "packet_src_port" + AttributeKeySrcChannel = "packet_src_channel" + AttributeKeyDstPort = "packet_dst_port" + AttributeKeyDstChannel = "packet_dst_channel" +) + +// IBC channel events vars +var ( + EventTypeChannelOpenInit = MsgChannelOpenInit{}.Type() + EventTypeChannelOpenTry = MsgChannelOpenTry{}.Type() + EventTypeChannelOpenAck = MsgChannelOpenAck{}.Type() + EventTypeChannelOpenConfirm = MsgChannelOpenConfirm{}.Type() + EventTypeChannelCloseInit = MsgChannelCloseInit{}.Type() + EventTypeChannelCloseConfirm = MsgChannelCloseConfirm{}.Type() + + AttributeValueCategory = fmt.Sprintf("%s_%s", ibctypes.ModuleName, SubModuleName) +) diff --git a/x/ibc/04-channel/types/expected_keepers.go b/x/ibc/04-channel/types/expected_keepers.go new file mode 100644 index 000000000000..cbc663528198 --- /dev/null +++ b/x/ibc/04-channel/types/expected_keepers.go @@ -0,0 +1,73 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/capability" + clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + connectionexported "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported" + connectiontypes "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" +) + +// ClientKeeper expected account IBC client keeper +type ClientKeeper interface { + GetClientState(ctx sdk.Context, clientID string) (clientexported.ClientState, bool) +} + +// ConnectionKeeper expected account IBC connection keeper +type ConnectionKeeper interface { + GetConnection(ctx sdk.Context, connectionID string) (connectiontypes.ConnectionEnd, bool) + VerifyChannelState( + ctx sdk.Context, + connection connectionexported.ConnectionI, + height uint64, + proof commitmentexported.Proof, + portID, + channelID string, + channel exported.ChannelI, + ) error + VerifyPacketCommitment( + ctx sdk.Context, + connection connectionexported.ConnectionI, + height uint64, + proof commitmentexported.Proof, + portID, + channelID string, + sequence uint64, + commitmentBytes []byte, + ) error + VerifyPacketAcknowledgement( + ctx sdk.Context, + connection connectionexported.ConnectionI, + height uint64, + proof commitmentexported.Proof, + portID, + channelID string, + sequence uint64, + acknowledgement []byte, + ) error + VerifyPacketAcknowledgementAbsence( + ctx sdk.Context, + connection connectionexported.ConnectionI, + height uint64, + proof commitmentexported.Proof, + portID, + channelID string, + sequence uint64, + ) error + VerifyNextSequenceRecv( + ctx sdk.Context, + connection connectionexported.ConnectionI, + height uint64, + proof commitmentexported.Proof, + portID, + channelID string, + nextSequenceRecv uint64, + ) error +} + +// PortKeeper expected account IBC port keeper +type PortKeeper interface { + Authenticate(ctx sdk.Context, key *capability.Capability, portID string) bool +} diff --git a/x/ibc/04-channel/types/keys.go b/x/ibc/04-channel/types/keys.go new file mode 100644 index 000000000000..21372dc48d99 --- /dev/null +++ b/x/ibc/04-channel/types/keys.go @@ -0,0 +1,15 @@ +package types + +const ( + // SubModuleName defines the IBC channels name + SubModuleName = "channels" + + // StoreKey is the store key string for IBC channels + StoreKey = SubModuleName + + // RouterKey is the message route for IBC channels + RouterKey = SubModuleName + + // QuerierRoute is the querier route for IBC channels + QuerierRoute = SubModuleName +) diff --git a/x/ibc/04-channel/types/msgs.go b/x/ibc/04-channel/types/msgs.go new file mode 100644 index 000000000000..f003bdafb627 --- /dev/null +++ b/x/ibc/04-channel/types/msgs.go @@ -0,0 +1,582 @@ +package types + +import ( + "encoding/base64" + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" + commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" + host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +var _ sdk.Msg = MsgChannelOpenInit{} + +type MsgChannelOpenInit struct { + PortID string `json:"port_id"` + ChannelID string `json:"channel_id"` + Channel Channel `json:"channel"` + Signer sdk.AccAddress `json:"signer"` +} + +// NewMsgChannelOpenInit creates a new MsgChannelCloseInit MsgChannelOpenInit +func NewMsgChannelOpenInit( + portID, channelID string, version string, channelOrder exported.Order, connectionHops []string, + counterpartyPortID, counterpartyChannelID string, signer sdk.AccAddress, +) MsgChannelOpenInit { + counterparty := NewCounterparty(counterpartyPortID, counterpartyChannelID) + channel := NewChannel(exported.INIT, channelOrder, counterparty, connectionHops, version) + return MsgChannelOpenInit{ + PortID: portID, + ChannelID: channelID, + Channel: channel, + Signer: signer, + } +} + +// Route implements sdk.Msg +func (msg MsgChannelOpenInit) Route() string { + return ibctypes.RouterKey +} + +// Type implements sdk.Msg +func (msg MsgChannelOpenInit) Type() string { + return "channel_open_init" +} + +// ValidateBasic implements sdk.Msg +func (msg MsgChannelOpenInit) ValidateBasic() error { + if err := host.DefaultPortIdentifierValidator(msg.PortID); err != nil { + return sdkerrors.Wrap(err, "invalid port ID") + } + if err := host.DefaultChannelIdentifierValidator(msg.ChannelID); err != nil { + return sdkerrors.Wrap(err, "invalid channel ID") + } + // Signer can be empty + return msg.Channel.ValidateBasic() +} + +// GetSignBytes implements sdk.Msg +func (msg MsgChannelOpenInit) GetSignBytes() []byte { + return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg)) +} + +// GetSigners implements sdk.Msg +func (msg MsgChannelOpenInit) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} + +var _ sdk.Msg = MsgChannelOpenTry{} + +type MsgChannelOpenTry struct { + PortID string `json:"port_id"` + ChannelID string `json:"channel_id"` + Channel Channel `json:"channel"` + CounterpartyVersion string `json:"counterparty_version"` + ProofInit commitmentexported.Proof `json:"proof_init"` + ProofHeight uint64 `json:"proof_height"` + Signer sdk.AccAddress `json:"signer"` +} + +// NewMsgChannelOpenTry creates a new MsgChannelOpenTry instance +func NewMsgChannelOpenTry( + portID, channelID, version string, channelOrder exported.Order, connectionHops []string, + counterpartyPortID, counterpartyChannelID, counterpartyVersion string, + proofInit commitmentexported.Proof, proofHeight uint64, signer sdk.AccAddress, +) MsgChannelOpenTry { + counterparty := NewCounterparty(counterpartyPortID, counterpartyChannelID) + channel := NewChannel(exported.INIT, channelOrder, counterparty, connectionHops, version) + return MsgChannelOpenTry{ + PortID: portID, + ChannelID: channelID, + Channel: channel, + CounterpartyVersion: counterpartyVersion, + ProofInit: proofInit, + ProofHeight: proofHeight, + Signer: signer, + } +} + +// Route implements sdk.Msg +func (msg MsgChannelOpenTry) Route() string { + return ibctypes.RouterKey +} + +// Type implements sdk.Msg +func (msg MsgChannelOpenTry) Type() string { + return "channel_open_try" +} + +// ValidateBasic implements sdk.Msg +func (msg MsgChannelOpenTry) ValidateBasic() error { + if err := host.DefaultPortIdentifierValidator(msg.PortID); err != nil { + return sdkerrors.Wrap(err, "invalid port ID") + } + if err := host.DefaultChannelIdentifierValidator(msg.ChannelID); err != nil { + return sdkerrors.Wrap(err, "invalid channel ID") + } + if strings.TrimSpace(msg.CounterpartyVersion) == "" { + return sdkerrors.Wrap(ErrInvalidCounterparty, "counterparty version cannot be blank") + } + if msg.ProofInit == nil { + return sdkerrors.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty proof") + } + if err := msg.ProofInit.ValidateBasic(); err != nil { + return sdkerrors.Wrap(err, "proof init cannot be nil") + } + if msg.ProofHeight == 0 { + return sdkerrors.Wrap(ibctypes.ErrInvalidHeight, "proof height must be > 0") + } + // Signer can be empty + return msg.Channel.ValidateBasic() +} + +// GetSignBytes implements sdk.Msg +func (msg MsgChannelOpenTry) GetSignBytes() []byte { + return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg)) +} + +// GetSigners implements sdk.Msg +func (msg MsgChannelOpenTry) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} + +var _ sdk.Msg = MsgChannelOpenAck{} + +type MsgChannelOpenAck struct { + PortID string `json:"port_id"` + ChannelID string `json:"channel_id"` + CounterpartyVersion string `json:"counterparty_version"` + ProofTry commitmentexported.Proof `json:"proof_try"` + ProofHeight uint64 `json:"proof_height"` + Signer sdk.AccAddress `json:"signer"` +} + +// NewMsgChannelOpenAck creates a new MsgChannelOpenAck instance +func NewMsgChannelOpenAck( + portID, channelID string, cpv string, proofTry commitmentexported.Proof, proofHeight uint64, + signer sdk.AccAddress, +) MsgChannelOpenAck { + return MsgChannelOpenAck{ + PortID: portID, + ChannelID: channelID, + CounterpartyVersion: cpv, + ProofTry: proofTry, + ProofHeight: proofHeight, + Signer: signer, + } +} + +// Route implements sdk.Msg +func (msg MsgChannelOpenAck) Route() string { + return ibctypes.RouterKey +} + +// Type implements sdk.Msg +func (msg MsgChannelOpenAck) Type() string { + return "channel_open_ack" +} + +// ValidateBasic implements sdk.Msg +func (msg MsgChannelOpenAck) ValidateBasic() error { + if err := host.DefaultPortIdentifierValidator(msg.PortID); err != nil { + return sdkerrors.Wrap(err, "invalid port ID") + } + if err := host.DefaultChannelIdentifierValidator(msg.ChannelID); err != nil { + return sdkerrors.Wrap(err, "invalid channel ID") + } + if strings.TrimSpace(msg.CounterpartyVersion) == "" { + return sdkerrors.Wrap(ErrInvalidCounterparty, "counterparty version cannot be blank") + } + if msg.ProofTry == nil { + return sdkerrors.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty proof") + } + if err := msg.ProofTry.ValidateBasic(); err != nil { + return sdkerrors.Wrap(err, "proof try cannot be nil") + } + if msg.ProofHeight == 0 { + return sdkerrors.Wrap(ibctypes.ErrInvalidHeight, "proof height must be > 0") + } + // Signer can be empty + return nil +} + +// GetSignBytes implements sdk.Msg +func (msg MsgChannelOpenAck) GetSignBytes() []byte { + return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg)) +} + +// GetSigners implements sdk.Msg +func (msg MsgChannelOpenAck) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} + +var _ sdk.Msg = MsgChannelOpenConfirm{} + +type MsgChannelOpenConfirm struct { + PortID string `json:"port_id"` + ChannelID string `json:"channel_id"` + ProofAck commitmentexported.Proof `json:"proof_ack"` + ProofHeight uint64 `json:"proof_height"` + Signer sdk.AccAddress `json:"signer"` +} + +// NewMsgChannelOpenConfirm creates a new MsgChannelOpenConfirm instance +func NewMsgChannelOpenConfirm( + portID, channelID string, proofAck commitmentexported.Proof, proofHeight uint64, + signer sdk.AccAddress, +) MsgChannelOpenConfirm { + return MsgChannelOpenConfirm{ + PortID: portID, + ChannelID: channelID, + ProofAck: proofAck, + ProofHeight: proofHeight, + Signer: signer, + } +} + +// Route implements sdk.Msg +func (msg MsgChannelOpenConfirm) Route() string { + return ibctypes.RouterKey +} + +// Type implements sdk.Msg +func (msg MsgChannelOpenConfirm) Type() string { + return "channel_open_confirm" +} + +// ValidateBasic implements sdk.Msg +func (msg MsgChannelOpenConfirm) ValidateBasic() error { + if err := host.DefaultPortIdentifierValidator(msg.PortID); err != nil { + return sdkerrors.Wrap(err, "invalid port ID") + } + if err := host.DefaultChannelIdentifierValidator(msg.ChannelID); err != nil { + return sdkerrors.Wrap(err, "invalid channel ID") + } + if msg.ProofAck == nil { + return sdkerrors.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty proof") + } + if err := msg.ProofAck.ValidateBasic(); err != nil { + return sdkerrors.Wrap(err, "proof ack cannot be nil") + } + if msg.ProofHeight == 0 { + return sdkerrors.Wrap(ibctypes.ErrInvalidHeight, "proof height must be > 0") + } + // Signer can be empty + return nil +} + +// GetSignBytes implements sdk.Msg +func (msg MsgChannelOpenConfirm) GetSignBytes() []byte { + return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg)) +} + +// GetSigners implements sdk.Msg +func (msg MsgChannelOpenConfirm) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} + +var _ sdk.Msg = MsgChannelCloseInit{} + +type MsgChannelCloseInit struct { + PortID string `json:"port_id"` + ChannelID string `json:"channel_id"` + Signer sdk.AccAddress `json:"signer"` +} + +// NewMsgChannelCloseInit creates a new MsgChannelCloseInit instance +func NewMsgChannelCloseInit(portID string, channelID string, signer sdk.AccAddress) MsgChannelCloseInit { + return MsgChannelCloseInit{ + PortID: portID, + ChannelID: channelID, + Signer: signer, + } +} + +// Route implements sdk.Msg +func (msg MsgChannelCloseInit) Route() string { + return ibctypes.RouterKey +} + +// Type implements sdk.Msg +func (msg MsgChannelCloseInit) Type() string { + return "channel_close_init" +} + +// ValidateBasic implements sdk.Msg +func (msg MsgChannelCloseInit) ValidateBasic() error { + if err := host.DefaultPortIdentifierValidator(msg.PortID); err != nil { + return sdkerrors.Wrap(err, "invalid port ID") + } + if err := host.DefaultChannelIdentifierValidator(msg.ChannelID); err != nil { + return sdkerrors.Wrap(err, "invalid channel ID") + } + // Signer can be empty + return nil +} + +// GetSignBytes implements sdk.Msg +func (msg MsgChannelCloseInit) GetSignBytes() []byte { + return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg)) +} + +// GetSigners implements sdk.Msg +func (msg MsgChannelCloseInit) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} + +var _ sdk.Msg = MsgChannelCloseConfirm{} + +type MsgChannelCloseConfirm struct { + PortID string `json:"port_id"` + ChannelID string `json:"channel_id"` + ProofInit commitmentexported.Proof `json:"proof_init"` + ProofHeight uint64 `json:"proof_height"` + Signer sdk.AccAddress `json:"signer"` +} + +// NewMsgChannelCloseConfirm creates a new MsgChannelCloseConfirm instance +func NewMsgChannelCloseConfirm( + portID, channelID string, proofInit commitmentexported.Proof, proofHeight uint64, + signer sdk.AccAddress, +) MsgChannelCloseConfirm { + return MsgChannelCloseConfirm{ + PortID: portID, + ChannelID: channelID, + ProofInit: proofInit, + ProofHeight: proofHeight, + Signer: signer, + } +} + +// Route implements sdk.Msg +func (msg MsgChannelCloseConfirm) Route() string { + return ibctypes.RouterKey +} + +// Type implements sdk.Msg +func (msg MsgChannelCloseConfirm) Type() string { + return "channel_close_confirm" +} + +// ValidateBasic implements sdk.Msg +func (msg MsgChannelCloseConfirm) ValidateBasic() error { + if err := host.DefaultPortIdentifierValidator(msg.PortID); err != nil { + return sdkerrors.Wrap(err, "invalid port ID") + } + if err := host.DefaultChannelIdentifierValidator(msg.ChannelID); err != nil { + return sdkerrors.Wrap(err, "invalid channel ID") + } + if msg.ProofInit == nil { + return sdkerrors.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty proof") + } + if err := msg.ProofInit.ValidateBasic(); err != nil { + return sdkerrors.Wrap(err, "proof init cannot be nil") + } + if msg.ProofHeight == 0 { + return sdkerrors.Wrap(ibctypes.ErrInvalidHeight, "proof height must be > 0") + } + // Signer can be empty + return nil +} + +// GetSignBytes implements sdk.Msg +func (msg MsgChannelCloseConfirm) GetSignBytes() []byte { + return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg)) +} + +// GetSigners implements sdk.Msg +func (msg MsgChannelCloseConfirm) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} + +// MsgPacket receives incoming IBC packet +type MsgPacket struct { + Packet `json:"packet" yaml:"packet"` + Proof commitmentexported.Proof `json:"proof" yaml:"proof"` + ProofHeight uint64 `json:"proof_height" yaml:"proof_height"` + Signer sdk.AccAddress `json:"signer" yaml:"signer"` +} + +var _ sdk.Msg = MsgPacket{} + +// NewMsgPacket constructs new MsgPacket +func NewMsgPacket(packet Packet, proof commitmentexported.Proof, proofHeight uint64, signer sdk.AccAddress) MsgPacket { + return MsgPacket{ + Packet: packet, + Proof: proof, + ProofHeight: proofHeight, + Signer: signer, + } +} + +// Route implements sdk.Msg +func (msg MsgPacket) Route() string { + return ibctypes.RouterKey +} + +// ValidateBasic implements sdk.Msg +func (msg MsgPacket) ValidateBasic() error { + if msg.Proof == nil { + return sdkerrors.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty proof") + } + if err := msg.Proof.ValidateBasic(); err != nil { + return sdkerrors.Wrap(err, "proof ack cannot be nil") + } + if msg.ProofHeight == 0 { + return sdkerrors.Wrap(ibctypes.ErrInvalidHeight, "proof height must be > 0") + } + if msg.Signer.Empty() { + return sdkerrors.ErrInvalidAddress + } + + return msg.Packet.ValidateBasic() +} + +// GetSignBytes implements sdk.Msg +func (msg MsgPacket) GetSignBytes() []byte { + return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg)) +} + +// GetDataSignBytes returns the base64-encoded bytes used for the +// data field when signing the packet. +func (msg MsgPacket) GetDataSignBytes() []byte { + s := "\"" + base64.StdEncoding.EncodeToString(msg.Data) + "\"" + return []byte(s) +} + +// GetSigners implements sdk.Msg +func (msg MsgPacket) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} + +// Type implements sdk.Msg +func (msg MsgPacket) Type() string { + return "ics04/opaque" +} + +var _ sdk.Msg = MsgTimeout{} + +// MsgTimeout receives timed-out packet +type MsgTimeout struct { + Packet `json:"packet" yaml:"packet"` + NextSequenceRecv uint64 `json:"next_sequence_recv" yaml:"next_sequence_recv"` + Proof commitmentexported.Proof `json:"proof" yaml:"proof"` + ProofHeight uint64 `json:"proof_height" yaml:"proof_height"` + Signer sdk.AccAddress `json:"signer" yaml:"signer"` +} + +// NewMsgTimeout constructs new MsgTimeout +func NewMsgTimeout(packet Packet, nextSequenceRecv uint64, proof commitmentexported.Proof, proofHeight uint64, signer sdk.AccAddress) MsgTimeout { + return MsgTimeout{ + Packet: packet, + NextSequenceRecv: nextSequenceRecv, + Proof: proof, + ProofHeight: proofHeight, + Signer: signer, + } +} + +// Route implements sdk.Msg +func (msg MsgTimeout) Route() string { + return ibctypes.RouterKey +} + +// ValidateBasic implements sdk.Msg +func (msg MsgTimeout) ValidateBasic() error { + if msg.Proof == nil { + return sdkerrors.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty proof") + } + if err := msg.Proof.ValidateBasic(); err != nil { + return sdkerrors.Wrap(err, "proof ack cannot be nil") + } + if msg.ProofHeight == 0 { + return sdkerrors.Wrap(ibctypes.ErrInvalidHeight, "proof height must be > 0") + } + if msg.Signer.Empty() { + return sdkerrors.ErrInvalidAddress + } + + return msg.Packet.ValidateBasic() +} + +// GetSignBytes implements sdk.Msg +func (msg MsgTimeout) GetSignBytes() []byte { + return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg)) +} + +// GetSigners implements sdk.Msg +func (msg MsgTimeout) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} + +// Type implements sdk.Msg +func (msg MsgTimeout) Type() string { + return "ics04/timeout" +} + +var _ sdk.Msg = MsgAcknowledgement{} + +// MsgAcknowledgement receives incoming IBC acknowledgement +type MsgAcknowledgement struct { + Packet `json:"packet" yaml:"packet"` + Acknowledgement []byte `json:"acknowledgement" yaml:"acknowledgement"` + Proof commitmentexported.Proof `json:"proof" yaml:"proof"` + ProofHeight uint64 `json:"proof_height" yaml:"proof_height"` + Signer sdk.AccAddress `json:"signer" yaml:"signer"` +} + +// NewMsgAcknowledgement constructs a new MsgAcknowledgement +func NewMsgAcknowledgement(packet Packet, ack []byte, proof commitmentexported.Proof, proofHeight uint64, signer sdk.AccAddress) MsgAcknowledgement { + return MsgAcknowledgement{ + Packet: packet, + Acknowledgement: ack, + Proof: proof, + ProofHeight: proofHeight, + Signer: signer, + } +} + +// Route implements sdk.Msg +func (msg MsgAcknowledgement) Route() string { + return ibctypes.RouterKey +} + +// ValidateBasic implements sdk.Msg +func (msg MsgAcknowledgement) ValidateBasic() error { + if msg.Proof == nil { + return sdkerrors.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty proof") + } + if err := msg.Proof.ValidateBasic(); err != nil { + return sdkerrors.Wrap(err, "proof ack cannot be nil") + } + if len(msg.Acknowledgement) > 100 { + return sdkerrors.Wrap(ErrAcknowledgementTooLong, "acknowledgement cannot exceed 100 bytes") + } + if msg.ProofHeight == 0 { + return sdkerrors.Wrap(ibctypes.ErrInvalidHeight, "proof height must be > 0") + } + if msg.Signer.Empty() { + return sdkerrors.ErrInvalidAddress + } + + return msg.Packet.ValidateBasic() +} + +// GetSignBytes implements sdk.Msg +func (msg MsgAcknowledgement) GetSignBytes() []byte { + return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg)) +} + +// GetSigners implements sdk.Msg +func (msg MsgAcknowledgement) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} + +// Type implements sdk.Msg +func (msg MsgAcknowledgement) Type() string { + return "ics04/opaque" +} diff --git a/x/ibc/04-channel/types/msgs_test.go b/x/ibc/04-channel/types/msgs_test.go new file mode 100644 index 000000000000..81237978f9ea --- /dev/null +++ b/x/ibc/04-channel/types/msgs_test.go @@ -0,0 +1,511 @@ +package types + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto/merkle" + dbm "github.com/tendermint/tm-db" + + "github.com/cosmos/cosmos-sdk/store/iavl" + "github.com/cosmos/cosmos-sdk/store/rootmulti" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" + commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" +) + +// define constants used for testing +const ( + invalidPort = "invalidport1" + invalidShortPort = "p" + invalidLongPort = "invalidlongportinvalidlongport" + + invalidChannel = "invalidchannel1" + invalidShortChannel = "invalidch" + invalidLongChannel = "invalidlongchannelinvalidlongchannel" + + invalidConnection = "invalidconnection1" + invalidShortConnection = "invalidcn" + invalidLongConnection = "invalidlongconnection" +) + +// define variables used for testing +var ( + connHops = []string{"testconnection"} + invalidConnHops = []string{"testconnection", "testconnection"} + invalidShortConnHops = []string{invalidShortConnection} + invalidLongConnHops = []string{invalidLongConnection} + + proof = commitmenttypes.MerkleProof{Proof: &merkle.Proof{}} + + addr = sdk.AccAddress("testaddr") +) + +type MsgTestSuite struct { + suite.Suite + + proof commitmenttypes.MerkleProof +} + +func (suite *MsgTestSuite) SetupTest() { + db := dbm.NewMemDB() + store := rootmulti.NewStore(db) + storeKey := storetypes.NewKVStoreKey("iavlStoreKey") + + store.MountStoreWithDB(storeKey, storetypes.StoreTypeIAVL, nil) + store.LoadVersion(0) + iavlStore := store.GetCommitStore(storeKey).(*iavl.Store) + + iavlStore.Set([]byte("KEY"), []byte("VALUE")) + _ = store.Commit() + + res := store.Query(abci.RequestQuery{ + Path: fmt.Sprintf("/%s/key", storeKey.Name()), // required path to get key/value+proof + Data: []byte("KEY"), + Prove: true, + }) + + suite.proof = commitmenttypes.MerkleProof{Proof: res.Proof} +} + +func TestMsgTestSuite(t *testing.T) { + suite.Run(t, new(MsgTestSuite)) +} + +// TestMsgChannelOpenInit tests ValidateBasic for MsgChannelOpenInit +func (suite *MsgTestSuite) TestMsgChannelOpenInit() { + testMsgs := []MsgChannelOpenInit{ + NewMsgChannelOpenInit("testportid", "testchannel", "1.0", exported.ORDERED, connHops, "testcpport", "testcpchannel", addr), // valid msg + NewMsgChannelOpenInit(invalidShortPort, "testchannel", "1.0", exported.ORDERED, connHops, "testcpport", "testcpchannel", addr), // too short port id + NewMsgChannelOpenInit(invalidLongPort, "testchannel", "1.0", exported.ORDERED, connHops, "testcpport", "testcpchannel", addr), // too long port id + NewMsgChannelOpenInit(invalidPort, "testchannel", "1.0", exported.ORDERED, connHops, "testcpport", "testcpchannel", addr), // port id contains non-alpha + NewMsgChannelOpenInit("testportid", invalidShortChannel, "1.0", exported.ORDERED, connHops, "testcpport", "testcpchannel", addr), // too short channel id + NewMsgChannelOpenInit("testportid", invalidLongChannel, "1.0", exported.ORDERED, connHops, "testcpport", "testcpchannel", addr), // too long channel id + NewMsgChannelOpenInit("testportid", invalidChannel, "1.0", exported.ORDERED, connHops, "testcpport", "testcpchannel", addr), // channel id contains non-alpha + NewMsgChannelOpenInit("testportid", "testchannel", "1.0", exported.Order(3), connHops, "testcpport", "testcpchannel", addr), // invalid channel order + NewMsgChannelOpenInit("testportid", "testchannel", "1.0", exported.ORDERED, invalidConnHops, "testcpport", "testcpchannel", addr), // connection hops more than 1 + NewMsgChannelOpenInit("testportid", "testchannel", "1.0", exported.UNORDERED, invalidShortConnHops, "testcpport", "testcpchannel", addr), // too short connection id + NewMsgChannelOpenInit("testportid", "testchannel", "1.0", exported.UNORDERED, invalidLongConnHops, "testcpport", "testcpchannel", addr), // too long connection id + NewMsgChannelOpenInit("testportid", "testchannel", "1.0", exported.UNORDERED, []string{invalidConnection}, "testcpport", "testcpchannel", addr), // connection id contains non-alpha + NewMsgChannelOpenInit("testportid", "testchannel", "", exported.UNORDERED, connHops, "testcpport", "testcpchannel", addr), // empty channel version + NewMsgChannelOpenInit("testportid", "testchannel", "1.0", exported.UNORDERED, connHops, invalidPort, "testcpchannel", addr), // invalid counterparty port id + NewMsgChannelOpenInit("testportid", "testchannel", "1.0", exported.UNORDERED, connHops, "testcpport", invalidChannel, addr), // invalid counterparty channel id + } + + testCases := []struct { + msg MsgChannelOpenInit + expPass bool + errMsg string + }{ + {testMsgs[0], true, ""}, + {testMsgs[1], false, "too short port id"}, + {testMsgs[2], false, "too long port id"}, + {testMsgs[3], false, "port id contains non-alpha"}, + {testMsgs[4], false, "too short channel id"}, + {testMsgs[5], false, "too long channel id"}, + {testMsgs[6], false, "channel id contains non-alpha"}, + {testMsgs[7], false, "invalid channel order"}, + {testMsgs[8], false, "connection hops more than 1 "}, + {testMsgs[9], false, "too short connection id"}, + {testMsgs[10], false, "too long connection id"}, + {testMsgs[11], false, "connection id contains non-alpha"}, + {testMsgs[12], false, "empty channel version"}, + {testMsgs[13], false, "invalid counterparty port id"}, + {testMsgs[14], false, "invalid counterparty channel id"}, + } + + for i, tc := range testCases { + err := tc.msg.ValidateBasic() + if tc.expPass { + suite.Require().NoError(err, "Msg %d failed: %s", i, tc.errMsg) + } else { + suite.Require().Error(err, "Invalid Msg %d passed: %s", i, tc.errMsg) + } + } +} + +// TestMsgChannelOpenTry tests ValidateBasic for MsgChannelOpenTry +func (suite *MsgTestSuite) TestMsgChannelOpenTry() { + testMsgs := []MsgChannelOpenTry{ + NewMsgChannelOpenTry("testportid", "testchannel", "1.0", exported.ORDERED, connHops, "testcpport", "testcpchannel", "1.0", suite.proof, 1, addr), // valid msg + NewMsgChannelOpenTry(invalidShortPort, "testchannel", "1.0", exported.ORDERED, connHops, "testcpport", "testcpchannel", "1.0", suite.proof, 1, addr), // too short port id + NewMsgChannelOpenTry(invalidLongPort, "testchannel", "1.0", exported.ORDERED, connHops, "testcpport", "testcpchannel", "1.0", suite.proof, 1, addr), // too long port id + NewMsgChannelOpenTry(invalidPort, "testchannel", "1.0", exported.ORDERED, connHops, "testcpport", "testcpchannel", "1.0", suite.proof, 1, addr), // port id contains non-alpha + NewMsgChannelOpenTry("testportid", invalidShortChannel, "1.0", exported.ORDERED, connHops, "testcpport", "testcpchannel", "1.0", suite.proof, 1, addr), // too short channel id + NewMsgChannelOpenTry("testportid", invalidLongChannel, "1.0", exported.ORDERED, connHops, "testcpport", "testcpchannel", "1.0", suite.proof, 1, addr), // too long channel id + NewMsgChannelOpenTry("testportid", invalidChannel, "1.0", exported.ORDERED, connHops, "testcpport", "testcpchannel", "1.0", suite.proof, 1, addr), // channel id contains non-alpha + NewMsgChannelOpenTry("testportid", "testchannel", "1.0", exported.ORDERED, connHops, "testcpport", "testcpchannel", "", suite.proof, 1, addr), // empty counterparty version + NewMsgChannelOpenTry("testportid", "testchannel", "1.0", exported.ORDERED, connHops, "testcpport", "testcpchannel", "1.0", nil, 1, addr), // empty suite.proof + NewMsgChannelOpenTry("testportid", "testchannel", "1.0", exported.ORDERED, connHops, "testcpport", "testcpchannel", "1.0", suite.proof, 0, addr), // suite.proof height is zero + NewMsgChannelOpenTry("testportid", "testchannel", "1.0", exported.Order(4), connHops, "testcpport", "testcpchannel", "1.0", suite.proof, 1, addr), // invalid channel order + NewMsgChannelOpenTry("testportid", "testchannel", "1.0", exported.UNORDERED, invalidConnHops, "testcpport", "testcpchannel", "1.0", suite.proof, 1, addr), // connection hops more than 1 + NewMsgChannelOpenTry("testportid", "testchannel", "1.0", exported.UNORDERED, invalidShortConnHops, "testcpport", "testcpchannel", "1.0", suite.proof, 1, addr), // too short connection id + NewMsgChannelOpenTry("testportid", "testchannel", "1.0", exported.UNORDERED, invalidLongConnHops, "testcpport", "testcpchannel", "1.0", suite.proof, 1, addr), // too long connection id + NewMsgChannelOpenTry("testportid", "testchannel", "1.0", exported.UNORDERED, []string{invalidConnection}, "testcpport", "testcpchannel", "1.0", suite.proof, 1, addr), // connection id contains non-alpha + NewMsgChannelOpenTry("testportid", "testchannel", "", exported.UNORDERED, connHops, "testcpport", "testcpchannel", "1.0", suite.proof, 1, addr), // empty channel version + NewMsgChannelOpenTry("testportid", "testchannel", "1.0", exported.UNORDERED, connHops, invalidPort, "testcpchannel", "1.0", suite.proof, 1, addr), // invalid counterparty port id + NewMsgChannelOpenTry("testportid", "testchannel", "1.0", exported.UNORDERED, connHops, "testcpport", invalidChannel, "1.0", suite.proof, 1, addr), // invalid counterparty channel id + } + + testCases := []struct { + msg MsgChannelOpenTry + expPass bool + errMsg string + }{ + {testMsgs[0], true, ""}, + {testMsgs[1], false, "too short port id"}, + {testMsgs[2], false, "too long port id"}, + {testMsgs[3], false, "port id contains non-alpha"}, + {testMsgs[4], false, "too short channel id"}, + {testMsgs[5], false, "too long channel id"}, + {testMsgs[6], false, "channel id contains non-alpha"}, + {testMsgs[7], false, "empty counterparty version"}, + {testMsgs[8], false, "empty proof"}, + {testMsgs[9], false, "proof height is zero"}, + {testMsgs[10], false, "invalid channel order"}, + {testMsgs[11], false, "connection hops more than 1 "}, + {testMsgs[12], false, "too short connection id"}, + {testMsgs[13], false, "too long connection id"}, + {testMsgs[14], false, "connection id contains non-alpha"}, + {testMsgs[15], false, "empty channel version"}, + {testMsgs[16], false, "invalid counterparty port id"}, + {testMsgs[17], false, "invalid counterparty channel id"}, + } + + for i, tc := range testCases { + err := tc.msg.ValidateBasic() + if tc.expPass { + suite.Require().NoError(err, "Msg %d failed: %s", i, tc.errMsg) + } else { + suite.Require().Error(err, "Invalid Msg %d passed: %s", i, tc.errMsg) + } + } +} + +// TestMsgChannelOpenAck tests ValidateBasic for MsgChannelOpenAck +func (suite *MsgTestSuite) TestMsgChannelOpenAck() { + testMsgs := []MsgChannelOpenAck{ + NewMsgChannelOpenAck("testportid", "testchannel", "1.0", suite.proof, 1, addr), // valid msg + NewMsgChannelOpenAck(invalidShortPort, "testchannel", "1.0", suite.proof, 1, addr), // too short port id + NewMsgChannelOpenAck(invalidLongPort, "testchannel", "1.0", suite.proof, 1, addr), // too long port id + NewMsgChannelOpenAck(invalidPort, "testchannel", "1.0", suite.proof, 1, addr), // port id contains non-alpha + NewMsgChannelOpenAck("testportid", invalidShortChannel, "1.0", suite.proof, 1, addr), // too short channel id + NewMsgChannelOpenAck("testportid", invalidLongChannel, "1.0", suite.proof, 1, addr), // too long channel id + NewMsgChannelOpenAck("testportid", invalidChannel, "1.0", suite.proof, 1, addr), // channel id contains non-alpha + NewMsgChannelOpenAck("testportid", "testchannel", "", suite.proof, 1, addr), // empty counterparty version + NewMsgChannelOpenAck("testportid", "testchannel", "1.0", nil, 1, addr), // empty proof + NewMsgChannelOpenAck("testportid", "testchannel", "1.0", commitmenttypes.MerkleProof{Proof: nil}, 1, addr), // empty proof + NewMsgChannelOpenAck("testportid", "testchannel", "1.0", suite.proof, 0, addr), // proof height is zero + } + + testCases := []struct { + msg MsgChannelOpenAck + expPass bool + errMsg string + }{ + {testMsgs[0], true, ""}, + {testMsgs[1], false, "too short port id"}, + {testMsgs[2], false, "too long port id"}, + {testMsgs[3], false, "port id contains non-alpha"}, + {testMsgs[4], false, "too short channel id"}, + {testMsgs[5], false, "too long channel id"}, + {testMsgs[6], false, "channel id contains non-alpha"}, + {testMsgs[7], false, "empty counterparty version"}, + {testMsgs[8], false, "empty proof"}, + {testMsgs[9], false, "empty proof"}, + {testMsgs[10], false, "proof height is zero"}, + } + + for i, tc := range testCases { + err := tc.msg.ValidateBasic() + if tc.expPass { + suite.Require().NoError(err, "Msg %d failed: %s", i, tc.errMsg) + } else { + suite.Require().Error(err, "Invalid Msg %d passed: %s", i, tc.errMsg) + } + } +} + +// TestMsgChannelOpenConfirm tests ValidateBasic for MsgChannelOpenConfirm +func (suite *MsgTestSuite) TestMsgChannelOpenConfirm() { + testMsgs := []MsgChannelOpenConfirm{ + NewMsgChannelOpenConfirm("testportid", "testchannel", suite.proof, 1, addr), // valid msg + NewMsgChannelOpenConfirm(invalidShortPort, "testchannel", suite.proof, 1, addr), // too short port id + NewMsgChannelOpenConfirm(invalidLongPort, "testchannel", suite.proof, 1, addr), // too long port id + NewMsgChannelOpenConfirm(invalidPort, "testchannel", suite.proof, 1, addr), // port id contains non-alpha + NewMsgChannelOpenConfirm("testportid", invalidShortChannel, suite.proof, 1, addr), // too short channel id + NewMsgChannelOpenConfirm("testportid", invalidLongChannel, suite.proof, 1, addr), // too long channel id + NewMsgChannelOpenConfirm("testportid", invalidChannel, suite.proof, 1, addr), // channel id contains non-alpha + NewMsgChannelOpenConfirm("testportid", "testchannel", nil, 1, addr), // empty proof + NewMsgChannelOpenConfirm("testportid", "testchannel", commitmenttypes.MerkleProof{Proof: nil}, 1, addr), // empty proof + NewMsgChannelOpenConfirm("testportid", "testchannel", suite.proof, 0, addr), // proof height is zero + } + + testCases := []struct { + msg MsgChannelOpenConfirm + expPass bool + errMsg string + }{ + {testMsgs[0], true, ""}, + {testMsgs[1], false, "too short port id"}, + {testMsgs[2], false, "too long port id"}, + {testMsgs[3], false, "port id contains non-alpha"}, + {testMsgs[4], false, "too short channel id"}, + {testMsgs[5], false, "too long channel id"}, + {testMsgs[6], false, "channel id contains non-alpha"}, + {testMsgs[7], false, "empty proof"}, + {testMsgs[8], false, "empty proof"}, + {testMsgs[9], false, "proof height is zero"}, + } + + for i, tc := range testCases { + err := tc.msg.ValidateBasic() + if tc.expPass { + suite.Require().NoError(err, "Msg %d failed: %s", i, tc.errMsg) + } else { + suite.Require().Error(err, "Invalid Msg %d passed: %s", i, tc.errMsg) + } + } +} + +// TestMsgChannelCloseInit tests ValidateBasic for MsgChannelCloseInit +func (suite *MsgTestSuite) TestMsgChannelCloseInit() { + testMsgs := []MsgChannelCloseInit{ + NewMsgChannelCloseInit("testportid", "testchannel", addr), // valid msg + NewMsgChannelCloseInit(invalidShortPort, "testchannel", addr), // too short port id + NewMsgChannelCloseInit(invalidLongPort, "testchannel", addr), // too long port id + NewMsgChannelCloseInit(invalidPort, "testchannel", addr), // port id contains non-alpha + NewMsgChannelCloseInit("testportid", invalidShortChannel, addr), // too short channel id + NewMsgChannelCloseInit("testportid", invalidLongChannel, addr), // too long channel id + NewMsgChannelCloseInit("testportid", invalidChannel, addr), // channel id contains non-alpha + } + + testCases := []struct { + msg MsgChannelCloseInit + expPass bool + errMsg string + }{ + {testMsgs[0], true, ""}, + {testMsgs[1], false, "too short port id"}, + {testMsgs[2], false, "too long port id"}, + {testMsgs[3], false, "port id contains non-alpha"}, + {testMsgs[4], false, "too short channel id"}, + {testMsgs[5], false, "too long channel id"}, + {testMsgs[6], false, "channel id contains non-alpha"}, + } + + for i, tc := range testCases { + err := tc.msg.ValidateBasic() + if tc.expPass { + suite.Require().NoError(err, "Msg %d failed: %s", i, tc.errMsg) + } else { + suite.Require().Error(err, "Invalid Msg %d passed: %s", i, tc.errMsg) + } + } +} + +// TestMsgChannelCloseConfirm tests ValidateBasic for MsgChannelCloseConfirm +func (suite *MsgTestSuite) TestMsgChannelCloseConfirm() { + testMsgs := []MsgChannelCloseConfirm{ + NewMsgChannelCloseConfirm("testportid", "testchannel", suite.proof, 1, addr), // valid msg + NewMsgChannelCloseConfirm(invalidShortPort, "testchannel", suite.proof, 1, addr), // too short port id + NewMsgChannelCloseConfirm(invalidLongPort, "testchannel", suite.proof, 1, addr), // too long port id + NewMsgChannelCloseConfirm(invalidPort, "testchannel", suite.proof, 1, addr), // port id contains non-alpha + NewMsgChannelCloseConfirm("testportid", invalidShortChannel, suite.proof, 1, addr), // too short channel id + NewMsgChannelCloseConfirm("testportid", invalidLongChannel, suite.proof, 1, addr), // too long channel id + NewMsgChannelCloseConfirm("testportid", invalidChannel, suite.proof, 1, addr), // channel id contains non-alpha + NewMsgChannelCloseConfirm("testportid", "testchannel", nil, 1, addr), // empty proof + NewMsgChannelCloseConfirm("testportid", "testchannel", commitmenttypes.MerkleProof{Proof: nil}, 1, addr), // empty proof + NewMsgChannelCloseConfirm("testportid", "testchannel", suite.proof, 0, addr), // proof height is zero + } + + testCases := []struct { + msg MsgChannelCloseConfirm + expPass bool + errMsg string + }{ + {testMsgs[0], true, ""}, + {testMsgs[1], false, "too short port id"}, + {testMsgs[2], false, "too long port id"}, + {testMsgs[3], false, "port id contains non-alpha"}, + {testMsgs[4], false, "too short channel id"}, + {testMsgs[5], false, "too long channel id"}, + {testMsgs[6], false, "channel id contains non-alpha"}, + {testMsgs[7], false, "empty proof"}, + {testMsgs[8], false, "empty proof"}, + {testMsgs[9], false, "proof height is zero"}, + } + + for i, tc := range testCases { + err := tc.msg.ValidateBasic() + if tc.expPass { + suite.Require().NoError(err, "Msg %d failed: %s", i, tc.errMsg) + } else { + suite.Require().Error(err, "Invalid Msg %d passed: %s", i, tc.errMsg) + } + } +} + +// define variables used for testing +var ( + timeout = uint64(100) + validPacketData = []byte("testdata") + unknownPacketData = []byte("unknown") + invalidAckData = []byte("123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890") + + packet = NewPacket(validPacketData, 1, portid, chanid, cpportid, cpchanid, 100) + unknownPacket = NewPacket(unknownPacketData, 0, portid, chanid, cpportid, cpchanid, 100) + invalidAck = invalidAckData + + emptyProof = commitmenttypes.MerkleProof{Proof: nil} + invalidProofs1 = commitmentexported.Proof(nil) + invalidProofs2 = emptyProof + + addr1 = sdk.AccAddress("testaddr1") + emptyAddr sdk.AccAddress + + portid = "testportid" + chanid = "testchannel" + cpportid = "testcpport" + cpchanid = "testcpchannel" +) + +// TestMsgPacketType tests Type for MsgPacket +func TestMsgPacketType(t *testing.T) { + msg := NewMsgPacket(packet, proof, 1, addr1) + + require.Equal(t, []byte("testdata"), msg.GetData()) +} + +// TestMsgPacketValidation tests ValidateBasic for MsgPacket +func TestMsgPacketValidation(t *testing.T) { + testMsgs := []MsgPacket{ + NewMsgPacket(packet, proof, 1, addr1), // valid msg + NewMsgPacket(packet, proof, 0, addr1), // proof height is zero + NewMsgPacket(packet, nil, 1, addr1), // missing proof + NewMsgPacket(packet, invalidProofs1, 1, addr1), // missing proof + NewMsgPacket(packet, invalidProofs2, 1, addr1), // proof contain empty proof + NewMsgPacket(packet, proof, 1, emptyAddr), // missing signer address + NewMsgPacket(unknownPacket, proof, 1, addr1), // unknown packet + } + + testCases := []struct { + msg MsgPacket + expPass bool + errMsg string + }{ + {testMsgs[0], true, ""}, + {testMsgs[1], false, "proof height is zero"}, + {testMsgs[2], false, "missing proof"}, + {testMsgs[3], false, "missing proof"}, + {testMsgs[4], false, "proof contain empty proof"}, + {testMsgs[5], false, "missing signer address"}, + {testMsgs[6], false, "invalid packet"}, + } + + for i, tc := range testCases { + err := tc.msg.ValidateBasic() + if tc.expPass { + require.NoError(t, err, "Msg %d failed: %v", i, err) + } else { + require.Error(t, err, "Invalid Msg %d passed: %s", i, tc.errMsg) + } + } +} + +// TestMsgPacketGetSignBytes tests GetSignBytes for MsgPacket +func TestMsgPacketGetSignBytes(t *testing.T) { + msg := NewMsgPacket(packet, proof, 1, addr1) + res := msg.GetSignBytes() + + expected := fmt.Sprintf( + `{"type":"ibc/channel/MsgPacket","value":{"packet":{"data":%s,"destination_channel":"testcpchannel","destination_port":"testcpport","sequence":"1","source_channel":"testchannel","source_port":"testportid","timeout_height":"100"},"proof":{"type":"ibc/commitment/MerkleProof","value":{"proof":{"ops":[]}}},"proof_height":"1","signer":"cosmos1w3jhxarpv3j8yvg4ufs4x"}}`, + string(msg.GetDataSignBytes()), + ) + require.Equal(t, expected, string(res)) +} + +// TestMsgPacketGetSigners tests GetSigners for MsgPacket +func TestMsgPacketGetSigners(t *testing.T) { + msg := NewMsgPacket(packet, proof, 1, addr1) + res := msg.GetSigners() + + expected := "[746573746164647231]" + require.Equal(t, expected, fmt.Sprintf("%v", res)) +} + +// TestMsgTimeout tests ValidateBasic for MsgTimeout +func (suite *MsgTestSuite) TestMsgTimeout() { + testMsgs := []MsgTimeout{ + NewMsgTimeout(packet, 0, proof, 1, addr), + NewMsgTimeout(packet, 0, proof, 0, addr), + NewMsgTimeout(packet, 0, proof, 1, emptyAddr), + NewMsgTimeout(packet, 0, emptyProof, 1, addr), + NewMsgTimeout(unknownPacket, 0, proof, 1, addr), + NewMsgTimeout(packet, 0, invalidProofs1, 1, addr), + } + + testCases := []struct { + msg MsgTimeout + expPass bool + errMsg string + }{ + {testMsgs[0], true, ""}, + {testMsgs[1], false, "proof height must be > 0"}, + {testMsgs[2], false, "missing signer address"}, + {testMsgs[3], false, "cannot submit an empty proof"}, + {testMsgs[4], false, "invalid packet"}, + {testMsgs[5], false, "cannot submit an invalid proof"}, + } + + for i, tc := range testCases { + err := tc.msg.ValidateBasic() + if tc.expPass { + suite.Require().NoError(err, "Msg %d failed: %s", i, tc.errMsg) + } else { + suite.Require().Error(err, "Invalid Msg %d passed: %s", i, tc.errMsg) + } + } +} + +// TestMsgAcknowledgement tests ValidateBasic for MsgAcknowledgement +func (suite *MsgTestSuite) TestMsgAcknowledgement() { + testMsgs := []MsgAcknowledgement{ + NewMsgAcknowledgement(packet, packet.GetData(), proof, 1, addr), + NewMsgAcknowledgement(packet, packet.GetData(), proof, 0, addr), + NewMsgAcknowledgement(packet, packet.GetData(), proof, 1, emptyAddr), + NewMsgAcknowledgement(packet, packet.GetData(), emptyProof, 1, addr), + NewMsgAcknowledgement(unknownPacket, packet.GetData(), proof, 1, addr), + NewMsgAcknowledgement(packet, invalidAck, proof, 1, addr), + NewMsgAcknowledgement(packet, packet.GetData(), invalidProofs1, 1, addr), + } + + testCases := []struct { + msg MsgAcknowledgement + expPass bool + errMsg string + }{ + {testMsgs[0], true, ""}, + {testMsgs[1], false, "proof height must be > 0"}, + {testMsgs[2], false, "missing signer address"}, + {testMsgs[3], false, "cannot submit an empty proof"}, + {testMsgs[4], false, "invalid packet"}, + {testMsgs[5], false, "invalid acknowledgement"}, + {testMsgs[6], false, "cannot submit an invalid proof"}, + } + + for i, tc := range testCases { + err := tc.msg.ValidateBasic() + if tc.expPass { + suite.Require().NoError(err, "Msg %d failed: %s", i, tc.errMsg) + } else { + suite.Require().Error(err, "Invalid Msg %d passed: %s", i, tc.errMsg) + } + } +} diff --git a/x/ibc/04-channel/types/packet.go b/x/ibc/04-channel/types/packet.go new file mode 100644 index 000000000000..d302f3414511 --- /dev/null +++ b/x/ibc/04-channel/types/packet.go @@ -0,0 +1,115 @@ +package types + +import ( + "github.com/tendermint/tendermint/crypto/tmhash" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" +) + +// CommitPacket return the hash of commitment bytes +// TODO: no specification for packet commitment currently, +// make it spec compatible once we have it +func CommitPacket(packet exported.PacketI) []byte { + buf := sdk.Uint64ToBigEndian(packet.GetTimeoutHeight()) + buf = append(buf, packet.GetData()...) + return tmhash.Sum(buf) +} + +// CommitAcknowledgement returns the hash of commitment bytes +func CommitAcknowledgement(data []byte) []byte { + return tmhash.Sum(data) +} + +var _ exported.PacketI = Packet{} + +// Packet defines a type that carries data across different chains through IBC +type Packet struct { + Data []byte `json:"data" yaml:"data"` // Actual opaque bytes transferred directly to the application module + + Sequence uint64 `json:"sequence" yaml:"sequence"` // number corresponds to the order of sends and receives, where a Packet with an earlier sequence number must be sent and received before a Packet with a later sequence number. + SourcePort string `json:"source_port" yaml:"source_port"` // identifies the port on the sending chain. + SourceChannel string `json:"source_channel" yaml:"source_channel"` // identifies the channel end on the sending chain. + DestinationPort string `json:"destination_port" yaml:"destination_port"` // identifies the port on the receiving chain. + DestinationChannel string `json:"destination_channel" yaml:"destination_channel"` // identifies the channel end on the receiving chain. + TimeoutHeight uint64 `json:"timeout_height" yaml:"timeout_height"` // block height after which the packet times out +} + +// NewPacket creates a new Packet instance +func NewPacket( + data []byte, + sequence uint64, sourcePort, sourceChannel, + destinationPort, destinationChannel string, + timeoutHeight uint64, +) Packet { + return Packet{ + Data: data, + Sequence: sequence, + SourcePort: sourcePort, + SourceChannel: sourceChannel, + DestinationPort: destinationPort, + DestinationChannel: destinationChannel, + TimeoutHeight: timeoutHeight, + } +} + +// GetSequence implements PacketI interface +func (p Packet) GetSequence() uint64 { return p.Sequence } + +// GetSourcePort implements PacketI interface +func (p Packet) GetSourcePort() string { return p.SourcePort } + +// GetSourceChannel implements PacketI interface +func (p Packet) GetSourceChannel() string { return p.SourceChannel } + +// GetDestPort implements PacketI interface +func (p Packet) GetDestPort() string { return p.DestinationPort } + +// GetDestChannel implements PacketI interface +func (p Packet) GetDestChannel() string { return p.DestinationChannel } + +// GetData implements PacketI interface +func (p Packet) GetData() []byte { return p.Data } + +// GetTimeoutHeight implements PacketI interface +func (p Packet) GetTimeoutHeight() uint64 { return p.TimeoutHeight } + +// ValidateBasic implements PacketI interface +func (p Packet) ValidateBasic() error { + if err := host.DefaultPortIdentifierValidator(p.SourcePort); err != nil { + return sdkerrors.Wrapf( + ErrInvalidPacket, + sdkerrors.Wrapf(err, "invalid source port ID: %s", p.SourcePort).Error(), + ) + } + if err := host.DefaultPortIdentifierValidator(p.DestinationPort); err != nil { + return sdkerrors.Wrapf( + ErrInvalidPacket, + sdkerrors.Wrapf(err, "invalid destination port ID: %s", p.DestinationPort).Error(), + ) + } + if err := host.DefaultChannelIdentifierValidator(p.SourceChannel); err != nil { + return sdkerrors.Wrapf( + ErrInvalidPacket, + sdkerrors.Wrapf(err, "invalid source channel ID: %s", p.SourceChannel).Error(), + ) + } + if err := host.DefaultChannelIdentifierValidator(p.DestinationChannel); err != nil { + return sdkerrors.Wrapf( + ErrInvalidPacket, + sdkerrors.Wrapf(err, "invalid destination channel ID: %s", p.DestinationChannel).Error(), + ) + } + if p.Sequence == 0 { + return sdkerrors.Wrap(ErrInvalidPacket, "packet sequence cannot be 0") + } + if p.TimeoutHeight == 0 { + return sdkerrors.Wrap(ErrInvalidPacket, "packet timeout cannot be 0") + } + if len(p.Data) == 0 { + return sdkerrors.Wrap(ErrInvalidPacket, "packet data bytes cannot be empty") + } + return nil +} diff --git a/x/ibc/04-channel/types/packet_test.go b/x/ibc/04-channel/types/packet_test.go new file mode 100644 index 000000000000..3efc7158db87 --- /dev/null +++ b/x/ibc/04-channel/types/packet_test.go @@ -0,0 +1,32 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestPacketValidateBasic(t *testing.T) { + testCases := []struct { + packet Packet + expPass bool + errMsg string + }{ + {NewPacket(validPacketData, 1, portid, chanid, cpportid, cpchanid, timeout), true, ""}, + {NewPacket(validPacketData, 0, portid, chanid, cpportid, cpchanid, timeout), false, "invalid sequence"}, + {NewPacket(validPacketData, 1, invalidPort, chanid, cpportid, cpchanid, timeout), false, "invalid source port"}, + {NewPacket(validPacketData, 1, portid, invalidChannel, cpportid, cpchanid, timeout), false, "invalid source channel"}, + {NewPacket(validPacketData, 1, portid, chanid, invalidPort, cpchanid, timeout), false, "invalid destination port"}, + {NewPacket(validPacketData, 1, portid, chanid, cpportid, invalidChannel, timeout), false, "invalid destination channel"}, + {NewPacket(unknownPacketData, 1, portid, chanid, cpportid, cpchanid, timeout), true, ""}, + } + + for i, tc := range testCases { + err := tc.packet.ValidateBasic() + if tc.expPass { + require.NoError(t, err, "Msg %d failed: %s", i, tc.errMsg) + } else { + require.Error(t, err, "Invalid Msg %d passed: %s", i, tc.errMsg) + } + } +} diff --git a/x/ibc/04-channel/types/querier.go b/x/ibc/04-channel/types/querier.go new file mode 100644 index 000000000000..289a5bfc3cc6 --- /dev/null +++ b/x/ibc/04-channel/types/querier.go @@ -0,0 +1,119 @@ +package types + +import ( + "strings" + + "github.com/tendermint/tendermint/crypto/merkle" + + commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +// query routes supported by the IBC channel Querier +const ( + QueryAllChannels = "channels" + QueryChannel = "channel" + QueryConnectionChannels = "connection-channels" +) + +type IdentifiedChannel struct { + Channel Channel `json:"channel_end" yaml:"channel_end"` + PortIdentifier string `json:"port_identifier" yaml:"port_identifier"` + ChannelIdentifier string `json:"channel_identifier" yaml:"channel_identifier"` +} + +// ChannelResponse defines the client query response for a channel which also +// includes a proof,its path and the height from which the proof was retrieved. +type ChannelResponse struct { + Channel IdentifiedChannel `json:"channel" yaml:"channel"` + Proof commitmenttypes.MerkleProof `json:"proof,omitempty" yaml:"proof,omitempty"` + ProofPath commitmenttypes.MerklePath `json:"proof_path,omitempty" yaml:"proof_path,omitempty"` + ProofHeight uint64 `json:"proof_height,omitempty" yaml:"proof_height,omitempty"` +} + +// NewChannelResponse creates a new ChannelResponse instance +func NewChannelResponse( + portID, channelID string, channel Channel, proof *merkle.Proof, height int64, +) ChannelResponse { + return ChannelResponse{ + Channel: IdentifiedChannel{Channel: channel, PortIdentifier: portID, ChannelIdentifier: channelID}, + Proof: commitmenttypes.MerkleProof{Proof: proof}, + ProofPath: commitmenttypes.NewMerklePath(strings.Split(ibctypes.ChannelPath(portID, channelID), "/")), + ProofHeight: uint64(height), + } +} + +// QueryAllChannelsParams defines the parameters necessary for querying for all +// channels. +type QueryAllChannelsParams struct { + Page int `json:"page" yaml:"page"` + Limit int `json:"limit" yaml:"limit"` +} + +// NewQueryAllChannelsParams creates a new QueryAllChannelsParams instance. +func NewQueryAllChannelsParams(page, limit int) QueryAllChannelsParams { + return QueryAllChannelsParams{ + Page: page, + Limit: limit, + } +} + +// QueryConnectionChannelsParams defines the parameters necessary for querying +// for all channels associated with a given connection. +type QueryConnectionChannelsParams struct { + Connection string `json:"connection" yaml:"connection"` + Page int `json:"page" yaml:"page"` + Limit int `json:"limit" yaml:"limit"` +} + +// NewQueryConnectionChannelsParams creates a new QueryConnectionChannelsParams instance. +func NewQueryConnectionChannelsParams(connection string, page, limit int) QueryConnectionChannelsParams { + return QueryConnectionChannelsParams{ + Connection: connection, + Page: page, + Limit: limit, + } +} + +// PacketResponse defines the client query response for a packet which also +// includes a proof, its path and the height form which the proof was retrieved +type PacketResponse struct { + Packet Packet `json:"packet" yaml:"packet"` + Proof commitmenttypes.MerkleProof `json:"proof,omitempty" yaml:"proof,omitempty"` + ProofPath commitmenttypes.MerklePath `json:"proof_path,omitempty" yaml:"proof_path,omitempty"` + ProofHeight uint64 `json:"proof_height,omitempty" yaml:"proof_height,omitempty"` +} + +// NewPacketResponse creates a new PacketResponswe instance +func NewPacketResponse( + portID, channelID string, sequence uint64, packet Packet, proof *merkle.Proof, height int64, +) PacketResponse { + return PacketResponse{ + Packet: packet, + Proof: commitmenttypes.MerkleProof{Proof: proof}, + ProofPath: commitmenttypes.NewMerklePath(strings.Split(ibctypes.PacketCommitmentPath(portID, channelID, sequence), "/")), + ProofHeight: uint64(height), + } +} + +// RecvResponse defines the client query response for the next receive sequence +// number which also includes a proof, its path and the height form which the +// proof was retrieved +type RecvResponse struct { + NextSequenceRecv uint64 `json:"next_sequence_recv" yaml:"next_sequence_recv"` + Proof commitmenttypes.MerkleProof `json:"proof,omitempty" yaml:"proof,omitempty"` + ProofPath commitmenttypes.MerklePath `json:"proof_path,omitempty" yaml:"proof_path,omitempty"` + ProofHeight uint64 `json:"proof_height,omitempty" yaml:"proof_height,omitempty"` +} + +// NewRecvResponse creates a new RecvResponse instance +func NewRecvResponse( + portID, channelID string, sequenceRecv uint64, proof *merkle.Proof, height int64, +) RecvResponse { + return RecvResponse{ + NextSequenceRecv: sequenceRecv, + Proof: commitmenttypes.MerkleProof{Proof: proof}, + ProofPath: commitmenttypes.NewMerklePath(strings.Split(ibctypes.NextSequenceRecvPath(portID, channelID), "/")), + ProofHeight: uint64(height), + } +} diff --git a/x/ibc/05-port/alias.go b/x/ibc/05-port/alias.go new file mode 100644 index 000000000000..31dd696ea206 --- /dev/null +++ b/x/ibc/05-port/alias.go @@ -0,0 +1,37 @@ +package port + +// nolint +// autogenerated code using github.com/rigelrozanski/multitool +// aliases generated for the following subdirectories: +// ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/05-port/keeper +// ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/05-port/types + +import ( + "github.com/cosmos/cosmos-sdk/x/ibc/05-port/keeper" + "github.com/cosmos/cosmos-sdk/x/ibc/05-port/types" +) + +const ( + SubModuleName = types.SubModuleName + StoreKey = types.StoreKey + RouterKey = types.RouterKey + QuerierRoute = types.QuerierRoute +) + +var ( + // functions aliases + NewKeeper = keeper.NewKeeper + NewRouter = types.NewRouter + ErrPortExists = types.ErrPortExists + ErrPortNotFound = types.ErrPortNotFound + ErrInvalidPort = types.ErrInvalidPort + ErrInvalidRoute = types.ErrInvalidRoute + PortPath = types.PortPath + KeyPort = types.KeyPort +) + +type ( + Keeper = keeper.Keeper + Router = types.Router + IBCModule = types.IBCModule +) diff --git a/x/ibc/05-port/keeper/keeper.go b/x/ibc/05-port/keeper/keeper.go new file mode 100644 index 000000000000..cb0749e35c90 --- /dev/null +++ b/x/ibc/05-port/keeper/keeper.go @@ -0,0 +1,73 @@ +package keeper + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/capability" + "github.com/cosmos/cosmos-sdk/x/ibc/05-port/types" + host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +// Keeper defines the IBC connection keeper +type Keeper struct { + scopedKeeper capability.ScopedKeeper +} + +// NewKeeper creates a new IBC connection Keeper instance +func NewKeeper(sck capability.ScopedKeeper) Keeper { + return Keeper{ + scopedKeeper: sck, + } +} + +// isBounded checks a given port ID is already bounded. +func (k Keeper) isBound(ctx sdk.Context, portID string) bool { + _, ok := k.scopedKeeper.GetCapability(ctx, types.PortPath(portID)) + return ok +} + +// BindPort binds to a port and returns the associated capability. +// Ports must be bound statically when the chain starts in `app.go`. +// The capability must then be passed to a module which will need to pass +// it as an extra parameter when calling functions on the IBC module. +func (k *Keeper) BindPort(ctx sdk.Context, portID string) *capability.Capability { + if err := host.DefaultPortIdentifierValidator(portID); err != nil { + panic(err.Error()) + } + + if k.isBound(ctx, portID) { + panic(fmt.Sprintf("port %s is already bound", portID)) + } + + key, err := k.scopedKeeper.NewCapability(ctx, types.PortPath(portID)) + if err != nil { + panic(err.Error()) + } + + return key +} + +// Authenticate authenticates a capability key against a port ID +// by checking if the memory address of the capability was previously +// generated and bound to the port (provided as a parameter) which the capability +// is being authenticated against. +func (k Keeper) Authenticate(ctx sdk.Context, key *capability.Capability, portID string) bool { + if err := host.DefaultPortIdentifierValidator(portID); err != nil { + panic(err.Error()) + } + + return k.scopedKeeper.AuthenticateCapability(ctx, key, types.PortPath(portID)) +} + +// LookupModuleByPort will return the IBCModule along with the capability associated with a given portID +func (k Keeper) LookupModuleByPort(ctx sdk.Context, portID string) (string, *capability.Capability, bool) { + modules, cap, ok := k.scopedKeeper.LookupModules(ctx, types.PortPath(portID)) + if !ok { + return "", nil, false + } + + return ibctypes.GetModuleOwner(modules), cap, true + +} diff --git a/x/ibc/05-port/keeper/keeper_test.go b/x/ibc/05-port/keeper/keeper_test.go new file mode 100644 index 000000000000..8afa3295c2b7 --- /dev/null +++ b/x/ibc/05-port/keeper/keeper_test.go @@ -0,0 +1,74 @@ +package keeper_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/simapp" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc/05-port/keeper" +) + +var ( + validPort = "validportid" + invalidPort = "invalidPortID" +) + +type KeeperTestSuite struct { + suite.Suite + + cdc *codec.Codec + ctx sdk.Context + keeper *keeper.Keeper +} + +func (suite *KeeperTestSuite) SetupTest() { + isCheckTx := false + app := simapp.Setup(isCheckTx) + + suite.cdc = app.Codec() + suite.ctx = app.BaseApp.NewContext(isCheckTx, abci.Header{}) + suite.keeper = &app.IBCKeeper.PortKeeper +} + +func TestKeeperTestSuite(t *testing.T) { + suite.Run(t, new(KeeperTestSuite)) +} + +func (suite *KeeperTestSuite) TestBind() { + // Test that invalid portID causes panic + require.Panics(suite.T(), func() { suite.keeper.BindPort(suite.ctx, invalidPort) }, "Did not panic on invalid portID") + + // Test that valid BindPort returns capability key + capKey := suite.keeper.BindPort(suite.ctx, validPort) + require.NotNil(suite.T(), capKey, "capabilityKey is nil on valid BindPort") + + // Test that rebinding the same portid causes panic + require.Panics(suite.T(), func() { suite.keeper.BindPort(suite.ctx, validPort) }, "did not panic on re-binding the same port") +} + +func (suite *KeeperTestSuite) TestAuthenticate() { + capKey := suite.keeper.BindPort(suite.ctx, validPort) + + // Require that passing in invalid portID causes panic + require.Panics(suite.T(), func() { suite.keeper.Authenticate(suite.ctx, capKey, invalidPort) }, "did not panic on invalid portID") + + // Valid authentication should return true + auth := suite.keeper.Authenticate(suite.ctx, capKey, validPort) + require.True(suite.T(), auth, "valid authentication failed") + + // Test that authenticating against incorrect portid fails + auth = suite.keeper.Authenticate(suite.ctx, capKey, "wrongportid") + require.False(suite.T(), auth, "invalid authentication failed") + + // Test that authenticating port against different valid + // capability key fails + capKey2 := suite.keeper.BindPort(suite.ctx, "otherportid") + auth = suite.keeper.Authenticate(suite.ctx, capKey2, validPort) + require.False(suite.T(), auth, "invalid authentication for different capKey failed") +} diff --git a/x/ibc/05-port/types/errors.go b/x/ibc/05-port/types/errors.go new file mode 100644 index 000000000000..cad4f8551fb1 --- /dev/null +++ b/x/ibc/05-port/types/errors.go @@ -0,0 +1,13 @@ +package types + +import ( + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +// IBC port sentinel errors +var ( + ErrPortExists = sdkerrors.Register(SubModuleName, 1, "port is already binded") + ErrPortNotFound = sdkerrors.Register(SubModuleName, 2, "port not found") + ErrInvalidPort = sdkerrors.Register(SubModuleName, 3, "invalid port") + ErrInvalidRoute = sdkerrors.Register(SubModuleName, 4, "route not found") +) diff --git a/x/ibc/05-port/types/keys.go b/x/ibc/05-port/types/keys.go new file mode 100644 index 000000000000..b1250e0e4463 --- /dev/null +++ b/x/ibc/05-port/types/keys.go @@ -0,0 +1,31 @@ +package types + +import ( + "fmt" +) + +const ( + // SubModuleName defines the IBC port name + SubModuleName = "port" + + // StoreKey is the store key string for IBC ports + StoreKey = SubModuleName + + // RouterKey is the message route for IBC ports + RouterKey = SubModuleName + + // QuerierRoute is the querier route for IBC ports + QuerierRoute = SubModuleName +) + +// The following paths are the keys to the store as defined in https://github.com/cosmos/ics/tree/master/spec/ics-005-port-allocation#store-paths + +// PortPath defines the path under which ports paths are stored +func PortPath(portID string) string { + return fmt.Sprintf("ports/%s", portID) +} + +// KeyPort returns the store key for a particular port +func KeyPort(portID string) []byte { + return []byte(PortPath(portID)) +} diff --git a/x/ibc/05-port/types/module.go b/x/ibc/05-port/types/module.go new file mode 100644 index 000000000000..013fac6a37b3 --- /dev/null +++ b/x/ibc/05-port/types/module.go @@ -0,0 +1,77 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/cosmos-sdk/x/capability" + channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" +) + +// IBCModule defines an interface that implements all the callbacks +// that modules must define as specified in ICS-26 +type IBCModule interface { + OnChanOpenInit( + ctx sdk.Context, + order channelexported.Order, + connectionHops []string, + portID string, + channelID string, + channelCap *capability.Capability, + counterParty channeltypes.Counterparty, + version string, + ) error + + OnChanOpenTry( + ctx sdk.Context, + order channelexported.Order, + connectionHops []string, + portID, + channelID string, + channelCap *capability.Capability, + counterparty channeltypes.Counterparty, + version, + counterpartyVersion string, + ) error + + OnChanOpenAck( + ctx sdk.Context, + portID, + channelID string, + counterpartyVersion string, + ) error + + OnChanOpenConfirm( + ctx sdk.Context, + portID, + channelID string, + ) error + + OnChanCloseInit( + ctx sdk.Context, + portID, + channelID string, + ) error + + OnChanCloseConfirm( + ctx sdk.Context, + portID, + channelID string, + ) error + + OnRecvPacket( + ctx sdk.Context, + packet channeltypes.Packet, + ) (*sdk.Result, error) + + OnAcknowledgementPacket( + ctx sdk.Context, + packet channeltypes.Packet, + acknowledgement []byte, + ) (*sdk.Result, error) + + OnTimeoutPacket( + ctx sdk.Context, + packet channeltypes.Packet, + ) (*sdk.Result, error) +} diff --git a/x/ibc/05-port/types/router.go b/x/ibc/05-port/types/router.go new file mode 100644 index 000000000000..6bfba9076abd --- /dev/null +++ b/x/ibc/05-port/types/router.go @@ -0,0 +1,65 @@ +package types + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// The router is a map from module name to the IBCModule +// which contains all the module-defined callbacks required by ICS-26 +type Router struct { + routes map[string]IBCModule + sealed bool +} + +func NewRouter() *Router { + return &Router{ + routes: make(map[string]IBCModule), + } +} + +// Seal prevents the Router from any subsequent route handlers to be registered. +// Seal will panic if called more than once. +func (rtr *Router) Seal() { + if rtr.sealed { + panic("router already sealed") + } + rtr.sealed = true +} + +// Sealed returns a boolean signifying if the Router is sealed or not. +func (rtr Router) Sealed() bool { + return rtr.sealed +} + +// AddRoute adds IBCModule for a given module name. It returns the Router +// so AddRoute calls can be linked. It will panic if the Router is sealed. +func (rtr *Router) AddRoute(module string, cbs IBCModule) *Router { + if rtr.sealed { + panic(fmt.Sprintf("router sealed; cannot register %s route callbacks", module)) + } + if !sdk.IsAlphaNumeric(module) { + panic("route expressions can only contain alphanumeric characters") + } + if rtr.HasRoute(module) { + panic(fmt.Sprintf("route %s has already been registered", module)) + } + + rtr.routes[module] = cbs + return rtr +} + +// HasRoute returns true if the Router has a module registered or false otherwise. +func (rtr *Router) HasRoute(module string) bool { + _, ok := rtr.routes[module] + return ok +} + +// GetRoute returns a IBCModule for a given module. +func (rtr *Router) GetRoute(module string) (IBCModule, bool) { + if !rtr.HasRoute(module) { + return nil, false + } + return rtr.routes[module], true +} diff --git a/x/ibc/07-tendermint/client/cli/cli.go b/x/ibc/07-tendermint/client/cli/cli.go new file mode 100644 index 000000000000..e25dd98536ed --- /dev/null +++ b/x/ibc/07-tendermint/client/cli/cli.go @@ -0,0 +1,26 @@ +package cli + +import ( + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/codec" +) + +// GetTxCmd returns the transaction commands for IBC clients +func GetTxCmd(cdc *codec.Codec, storeKey string) *cobra.Command { + ics07TendermintTxCmd := &cobra.Command{ + Use: "tendermint", + Short: "Tendermint transaction subcommands", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + } + + ics07TendermintTxCmd.AddCommand(flags.PostCommands( + GetCmdCreateClient(cdc), + GetCmdUpdateClient(cdc), + GetCmdSubmitMisbehaviour(cdc), + )...) + + return ics07TendermintTxCmd +} diff --git a/x/ibc/07-tendermint/client/cli/tx.go b/x/ibc/07-tendermint/client/cli/tx.go new file mode 100644 index 000000000000..26bab9996521 --- /dev/null +++ b/x/ibc/07-tendermint/client/cli/tx.go @@ -0,0 +1,162 @@ +package cli + +import ( + "bufio" + "fmt" + "io/ioutil" + "strings" + "time" + + "github.com/pkg/errors" + + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/version" + authclient "github.com/cosmos/cosmos-sdk/x/auth/client" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + evidenceexported "github.com/cosmos/cosmos-sdk/x/evidence/exported" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" +) + +// GetCmdCreateClient defines the command to create a new IBC Client as defined +// in https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#create +func GetCmdCreateClient(cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "create [client-id] [path/to/consensus_state.json] [trusting_period] [unbonding_period]", + Short: "create new client with a consensus state", + Long: strings.TrimSpace(fmt.Sprintf(`create new client with a specified identifier and consensus state: + +Example: +$ %s tx ibc client create [client-id] [path/to/consensus_state.json] [trusting_period] [unbonding_period] --from node0 --home ../node0/cli --chain-id $CID + `, version.ClientName), + ), + Args: cobra.ExactArgs(4), + RunE: func(cmd *cobra.Command, args []string) error { + inBuf := bufio.NewReader(cmd.InOrStdin()) + txBldr := authtypes.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) + cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc).WithBroadcastMode(flags.BroadcastBlock) + + clientID := args[0] + + var header ibctmtypes.Header + if err := cdc.UnmarshalJSON([]byte(args[1]), &header); err != nil { + // check for file path if JSON input is not provided + contents, err := ioutil.ReadFile(args[1]) + if err != nil { + return errors.New("neither JSON input nor path to .json file were provided") + } + if err := cdc.UnmarshalJSON(contents, &header); err != nil { + return errors.Wrap(err, "error unmarshalling consensus header file") + } + } + + trustingPeriod, err := time.ParseDuration(args[2]) + if err != nil { + return err + } + + ubdPeriod, err := time.ParseDuration(args[3]) + if err != nil { + return err + } + + msg := ibctmtypes.NewMsgCreateClient(clientID, header, trustingPeriod, ubdPeriod, cliCtx.GetFromAddress()) + + if err := msg.ValidateBasic(); err != nil { + return err + } + + return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } + return cmd +} + +// GetCmdUpdateClient defines the command to update a client as defined in +// https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#update +func GetCmdUpdateClient(cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "update [client-id] [path/to/header.json]", + Short: "update existing client with a header", + Long: strings.TrimSpace(fmt.Sprintf(`update existing client with a header: + +Example: +$ %s tx ibc client update [client-id] [path/to/header.json] --from node0 --home ../node0/cli --chain-id $CID + `, version.ClientName), + ), + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + inBuf := bufio.NewReader(cmd.InOrStdin()) + txBldr := authtypes.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) + cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) + + clientID := args[0] + + var header ibctmtypes.Header + if err := cdc.UnmarshalJSON([]byte(args[1]), &header); err != nil { + // check for file path if JSON input is not provided + contents, err := ioutil.ReadFile(args[1]) + if err != nil { + return errors.New("neither JSON input nor path to .json file were provided") + } + if err := cdc.UnmarshalJSON(contents, &header); err != nil { + return errors.Wrap(err, "error unmarshalling header file") + } + } + + msg := ibctmtypes.NewMsgUpdateClient(clientID, header, cliCtx.GetFromAddress()) + if err := msg.ValidateBasic(); err != nil { + return err + } + + return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } + return cmd +} + +// GetCmdSubmitMisbehaviour defines the command to submit a misbehaviour to invalidate +// previous state roots and prevent future updates as defined in +// https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#misbehaviour +func GetCmdSubmitMisbehaviour(cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "misbehaviour [path/to/evidence.json]", + Short: "submit a client misbehaviour", + Long: strings.TrimSpace(fmt.Sprintf(`submit a client misbehaviour to invalidate to invalidate previous state roots and prevent future updates: + +Example: +$ %s tx ibc client misbehaviour [path/to/evidence.json] --from node0 --home ../node0/cli --chain-id $CID + `, version.ClientName), + ), + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + inBuf := bufio.NewReader(cmd.InOrStdin()) + txBldr := authtypes.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) + cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) + + var ev evidenceexported.Evidence + if err := cdc.UnmarshalJSON([]byte(args[0]), &ev); err != nil { + // check for file path if JSON input is not provided + contents, err := ioutil.ReadFile(args[0]) + if err != nil { + return errors.New("neither JSON input nor path to .json file were provided") + } + if err := cdc.UnmarshalJSON(contents, &ev); err != nil { + return errors.Wrap(err, "error unmarshalling evidence file") + } + } + + msg := ibctmtypes.NewMsgSubmitClientMisbehaviour(ev, cliCtx.GetFromAddress()) + if err := msg.ValidateBasic(); err != nil { + return err + } + + return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } + return cmd +} diff --git a/x/ibc/07-tendermint/client/rest/rest.go b/x/ibc/07-tendermint/client/rest/rest.go new file mode 100644 index 000000000000..6a5f50dea877 --- /dev/null +++ b/x/ibc/07-tendermint/client/rest/rest.go @@ -0,0 +1,45 @@ +package rest + +import ( + "time" + + "github.com/gorilla/mux" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/types/rest" + evidenceexported "github.com/cosmos/cosmos-sdk/x/evidence/exported" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" +) + +// REST client flags +const ( + RestClientID = "client-id" + RestRootHeight = "height" +) + +// RegisterRoutes - Central function to define routes that get registered by the main application +func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, queryRoute string) { + registerTxRoutes(cliCtx, r) +} + +// CreateClientReq defines the properties of a create client request's body. +type CreateClientReq struct { + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + ClientID string `json:"client_id" yaml:"client_id"` + ChainID string `json:"chain_id" yaml:"chain_id"` + Header ibctmtypes.Header `json:"consensus_state" yaml:"consensus_state"` + TrustingPeriod time.Duration `json:"trusting_period" yaml:"trusting_period"` + UnbondingPeriod time.Duration `json:"unbonding_period" yaml:"unbonding_period"` +} + +// UpdateClientReq defines the properties of a update client request's body. +type UpdateClientReq struct { + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + Header ibctmtypes.Header `json:"header" yaml:"header"` +} + +// SubmitMisbehaviourReq defines the properties of a submit misbehaviour request's body. +type SubmitMisbehaviourReq struct { + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + Evidence evidenceexported.Evidence `json:"evidence" yaml:"evidence"` +} diff --git a/x/ibc/07-tendermint/client/rest/tx.go b/x/ibc/07-tendermint/client/rest/tx.go new file mode 100644 index 000000000000..855fce80c674 --- /dev/null +++ b/x/ibc/07-tendermint/client/rest/tx.go @@ -0,0 +1,155 @@ +package rest + +import ( + "fmt" + "net/http" + + "github.com/gorilla/mux" + + "github.com/cosmos/cosmos-sdk/client/context" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/rest" + authclient "github.com/cosmos/cosmos-sdk/x/auth/client" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" +) + +// RegisterRoutes - Central function to define routes that get registered by the main application +func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router) { + r.HandleFunc("/ibc/clients", createClientHandlerFn(cliCtx)).Methods("POST") + r.HandleFunc(fmt.Sprintf("/ibc/clients/{%s}/update", RestClientID), updateClientHandlerFn(cliCtx)).Methods("POST") + r.HandleFunc("/ibc/clients/{%s}/misbehaviour", submitMisbehaviourHandlerFn(cliCtx)).Methods("POST") +} + +// createClientHandlerFn implements a create client handler +// +// @Summary Create client +// @Tags IBC +// @Accept json +// @Produce json +// @Param body body rest.CreateClientReq true "Create client request body" +// @Success 200 {object} PostCreateClient "OK" +// @Failure 500 {object} rest.ErrorResponse "Internal Server Error" +// @Router /ibc/clients [post] +func createClientHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req CreateClientReq + if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) { + return + } + + req.BaseReq = req.BaseReq.Sanitize() + if !req.BaseReq.ValidateBasic(w) { + return + } + + fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + // create the message + msg := ibctmtypes.NewMsgCreateClient( + req.ClientID, + req.Header, + req.TrustingPeriod, req.UnbondingPeriod, + fromAddr, + ) + + if err := msg.ValidateBasic(); err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) + } +} + +// updateClientHandlerFn implements a update client handler +// +// @Summary update client +// @Tags IBC +// @Accept json +// @Produce json +// @Param client-id path string true "Client ID" +// @Param body body rest.UpdateClientReq true "Update client request body" +// @Success 200 {object} PostUpdateClient "OK" +// @Failure 400 {object} rest.ErrorResponse "Invalid client id" +// @Failure 500 {object} rest.ErrorResponse "Internal Server Error" +// @Router /ibc/clients/{client-id}/update [post] +func updateClientHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + clientID := vars[RestClientID] + + var req UpdateClientReq + if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) { + return + } + + req.BaseReq = req.BaseReq.Sanitize() + if !req.BaseReq.ValidateBasic(w) { + return + } + + fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + // create the message + msg := ibctmtypes.NewMsgUpdateClient( + clientID, + req.Header, + fromAddr, + ) + + if err := msg.ValidateBasic(); err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) + } +} + +// submitMisbehaviourHandlerFn implements a submit misbehaviour handler +// +// @Summary Submit misbehaviour +// @Tags IBC +// @Accept json +// @Produce json +// @Param body body rest.SubmitMisbehaviourReq true "Submit misbehaviour request body" +// @Success 200 {object} PostSubmitMisbehaviour "OK" +// @Failure 400 {object} rest.ErrorResponse "Invalid client id" +// @Failure 500 {object} rest.ErrorResponse "Internal Server Error" +// @Router /ibc/clients/{client-id}/misbehaviour [post] +func submitMisbehaviourHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req SubmitMisbehaviourReq + if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) { + return + } + + req.BaseReq = req.BaseReq.Sanitize() + if !req.BaseReq.ValidateBasic(w) { + return + } + + fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + // create the message + msg := ibctmtypes.NewMsgSubmitClientMisbehaviour(req.Evidence, fromAddr) + if err := msg.ValidateBasic(); err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) + } +} diff --git a/x/ibc/07-tendermint/doc.go b/x/ibc/07-tendermint/doc.go new file mode 100644 index 000000000000..26aa430a82da --- /dev/null +++ b/x/ibc/07-tendermint/doc.go @@ -0,0 +1,5 @@ +/* +Package tendermint implements a concrete `ConsensusState`, `Header`, +`Misbehaviour` and `Equivocation` types for the Tendermint consensus light client. +*/ +package tendermint diff --git a/x/ibc/07-tendermint/misbehaviour.go b/x/ibc/07-tendermint/misbehaviour.go new file mode 100644 index 000000000000..d373e2e5afd1 --- /dev/null +++ b/x/ibc/07-tendermint/misbehaviour.go @@ -0,0 +1,103 @@ +package tendermint + +import ( + "errors" + "fmt" + "time" + + lite "github.com/tendermint/tendermint/lite2" + + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" + "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +// CheckMisbehaviourAndUpdateState determines whether or not two conflicting +// headers at the same height would have convinced the light client. +// +// NOTE: assumes provided height is the height at which the consensusState is +// stored. +func CheckMisbehaviourAndUpdateState( + clientState clientexported.ClientState, + consensusState clientexported.ConsensusState, + misbehaviour clientexported.Misbehaviour, + height uint64, // height at which the consensus state was loaded + currentTimestamp time.Time, +) (clientexported.ClientState, error) { + + // cast the interface to specific types before checking for misbehaviour + tmClientState, ok := clientState.(types.ClientState) + if !ok { + return nil, sdkerrors.Wrap(clienttypes.ErrInvalidClientType, "client state type is not Tendermint") + } + + // If client is already frozen at earlier height than evidence, return with error + if tmClientState.IsFrozen() && tmClientState.FrozenHeight <= uint64(misbehaviour.GetHeight()) { + return nil, sdkerrors.Wrapf(clienttypes.ErrInvalidEvidence, + "client is already frozen at earlier height %d than misbehaviour height %d", tmClientState.FrozenHeight, misbehaviour.GetHeight()) + } + + tmConsensusState, ok := consensusState.(types.ConsensusState) + if !ok { + return nil, sdkerrors.Wrap(clienttypes.ErrInvalidClientType, "consensus state is not Tendermint") + } + + tmEvidence, ok := misbehaviour.(types.Evidence) + if !ok { + return nil, sdkerrors.Wrap(clienttypes.ErrInvalidClientType, "evidence type is not Tendermint") + } + + if err := checkMisbehaviour( + tmClientState, tmConsensusState, tmEvidence, height, currentTimestamp, + ); err != nil { + return nil, sdkerrors.Wrap(clienttypes.ErrInvalidEvidence, err.Error()) + } + + tmClientState.FrozenHeight = uint64(tmEvidence.GetHeight()) + return tmClientState, nil +} + +// checkMisbehaviour checks if the evidence provided is a valid light client misbehaviour +func checkMisbehaviour( + clientState types.ClientState, consensusState types.ConsensusState, evidence types.Evidence, + height uint64, currentTimestamp time.Time, +) error { + // check if provided height matches the headers' height + if height > uint64(evidence.GetHeight()) { + return sdkerrors.Wrapf( + ibctypes.ErrInvalidHeight, + "height > evidence header height (%d > %d)", height, evidence.GetHeight(), + ) + } + + // NOTE: header height and commitment root assertions are checked with the + // evidence and msg ValidateBasic functions at the AnteHandler level. + + // assert that the timestamp is not from more than an unbonding period ago + if currentTimestamp.Sub(consensusState.Timestamp) >= clientState.UnbondingPeriod { + return errors.New("unbonding period since last consensus state timestamp is over") + } + + // TODO: Evidence must be within trusting period + // Blocked on https://github.com/cosmos/ics/issues/379 + + // - ValidatorSet must have 2/3 similarity with trusted FromValidatorSet + // - ValidatorSets on both headers are valid given the last trusted ValidatorSet + if err := consensusState.ValidatorSet.VerifyCommitTrusting( + evidence.ChainID, evidence.Header1.Commit.BlockID, evidence.Header1.Height, + evidence.Header1.Commit, lite.DefaultTrustLevel, + ); err != nil { + return fmt.Errorf("validator set in header 1 has too much change from last known validator set: %v", err) + } + + if err := consensusState.ValidatorSet.VerifyCommitTrusting( + evidence.ChainID, evidence.Header2.Commit.BlockID, evidence.Header2.Height, + evidence.Header2.Commit, lite.DefaultTrustLevel, + ); err != nil { + return fmt.Errorf("validator set in header 2 has too much change from last known validator set: %v", err) + } + + return nil +} diff --git a/x/ibc/07-tendermint/misbehaviour_test.go b/x/ibc/07-tendermint/misbehaviour_test.go new file mode 100644 index 000000000000..655ce135df48 --- /dev/null +++ b/x/ibc/07-tendermint/misbehaviour_test.go @@ -0,0 +1,136 @@ +package tendermint_test + +import ( + "bytes" + "time" + + "github.com/tendermint/tendermint/crypto/tmhash" + tmtypes "github.com/tendermint/tendermint/types" + + tendermint "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" + commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" +) + +func (suite *TendermintTestSuite) TestCheckMisbehaviour() { + altPrivVal := tmtypes.NewMockPV() + altVal := tmtypes.NewValidator(altPrivVal.GetPubKey(), 4) + + // Create bothValSet with both suite validator and altVal + bothValSet := tmtypes.NewValidatorSet(append(suite.valSet.Validators, altVal)) + // Create alternative validator set with only altVal + altValSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{altVal}) + + // Create signer array and ensure it is in same order as bothValSet + var bothSigners []tmtypes.PrivValidator + if bytes.Compare(altPrivVal.GetPubKey().Address(), suite.privVal.GetPubKey().Address()) == -1 { + bothSigners = []tmtypes.PrivValidator{altPrivVal, suite.privVal} + } else { + bothSigners = []tmtypes.PrivValidator{suite.privVal, altPrivVal} + } + + altSigners := []tmtypes.PrivValidator{altPrivVal} + + testCases := []struct { + name string + clientState ibctmtypes.ClientState + consensusState ibctmtypes.ConsensusState + evidence ibctmtypes.Evidence + height uint64 + expPass bool + }{ + { + "valid misbehavior evidence", + ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), + ibctmtypes.ConsensusState{Timestamp: suite.now, Root: commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), ValidatorSet: bothValSet}, + ibctmtypes.Evidence{ + Header1: ibctmtypes.CreateTestHeader(chainID, height, suite.now, bothValSet, bothSigners), + Header2: ibctmtypes.CreateTestHeader(chainID, height, suite.now.Add(time.Minute), bothValSet, bothSigners), + ChainID: chainID, + ClientID: chainID, + }, + height, + true, + }, + { + "valid misbehavior at height greater than last consensusState", + ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), + ibctmtypes.ConsensusState{Timestamp: suite.now, Height: height - 1, Root: commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), ValidatorSet: bothValSet}, + ibctmtypes.Evidence{ + Header1: ibctmtypes.CreateTestHeader(chainID, height, suite.now, bothValSet, bothSigners), + Header2: ibctmtypes.CreateTestHeader(chainID, height, suite.now.Add(time.Minute), bothValSet, bothSigners), + ChainID: chainID, + ClientID: chainID, + }, + height - 1, + true, + }, + { + "consensus state's valset hash different from evidence should still pass", + ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), + ibctmtypes.ConsensusState{Timestamp: suite.now, Height: height - 1, Root: commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), ValidatorSet: suite.valSet}, + ibctmtypes.Evidence{ + Header1: ibctmtypes.CreateTestHeader(chainID, height, suite.now, bothValSet, bothSigners), + Header2: ibctmtypes.CreateTestHeader(chainID, height, suite.now.Add(time.Minute), bothValSet, bothSigners), + ChainID: chainID, + ClientID: chainID, + }, + height - 1, + true, + }, + { + "first valset has too much change", + ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), + ibctmtypes.ConsensusState{Timestamp: suite.now, Root: commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), ValidatorSet: bothValSet}, + ibctmtypes.Evidence{ + Header1: ibctmtypes.CreateTestHeader(chainID, height, suite.now, altValSet, altSigners), + Header2: ibctmtypes.CreateTestHeader(chainID, height, suite.now.Add(time.Minute), bothValSet, bothSigners), + ChainID: chainID, + ClientID: chainID, + }, + height, + false, + }, + { + "second valset has too much change", + ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), + ibctmtypes.ConsensusState{Timestamp: suite.now, Root: commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), ValidatorSet: bothValSet}, + ibctmtypes.Evidence{ + Header1: ibctmtypes.CreateTestHeader(chainID, height, suite.now, bothValSet, bothSigners), + Header2: ibctmtypes.CreateTestHeader(chainID, height, suite.now.Add(time.Minute), altValSet, altSigners), + ChainID: chainID, + ClientID: chainID, + }, + height, + false, + }, + { + "both valsets have too much change", + ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), + ibctmtypes.ConsensusState{Timestamp: suite.now, Root: commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), ValidatorSet: bothValSet}, + ibctmtypes.Evidence{ + Header1: ibctmtypes.CreateTestHeader(chainID, height, suite.now, altValSet, altSigners), + Header2: ibctmtypes.CreateTestHeader(chainID, height, suite.now.Add(time.Minute), altValSet, altSigners), + ChainID: chainID, + ClientID: chainID, + }, + height, + false, + }, + } + + for i, tc := range testCases { + tc := tc + + clientState, err := tendermint.CheckMisbehaviourAndUpdateState(tc.clientState, tc.consensusState, tc.evidence, tc.height, suite.now) + + if tc.expPass { + suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name) + suite.Require().NotNil(clientState, "valid test case %d failed: %s", i, tc.name) + suite.Require().True(clientState.IsFrozen(), "valid test case %d failed: %s", i, tc.name) + } else { + suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name) + suite.Require().Nil(clientState, "invalid test case %d passed: %s", i, tc.name) + } + } +} diff --git a/x/ibc/07-tendermint/module.go b/x/ibc/07-tendermint/module.go new file mode 100644 index 000000000000..4f5b32cea681 --- /dev/null +++ b/x/ibc/07-tendermint/module.go @@ -0,0 +1,29 @@ +package tendermint + +import ( + "fmt" + + "github.com/gorilla/mux" + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/client/cli" + "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/client/rest" + "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" +) + +// Name returns the IBC client name +func Name() string { + return types.SubModuleName +} + +// RegisterRESTRoutes registers the REST routes for the IBC client +func RegisterRESTRoutes(ctx context.CLIContext, rtr *mux.Router, queryRoute string) { + rest.RegisterRoutes(ctx, rtr, fmt.Sprintf("%s/%s", queryRoute, types.SubModuleName)) +} + +// GetTxCmd returns the root tx command for the IBC client +func GetTxCmd(cdc *codec.Codec, storeKey string) *cobra.Command { + return cli.GetTxCmd(cdc, fmt.Sprintf("%s/%s", storeKey, types.SubModuleName)) +} diff --git a/x/ibc/07-tendermint/tendermint_test.go b/x/ibc/07-tendermint/tendermint_test.go new file mode 100644 index 000000000000..c5f9b6d0d455 --- /dev/null +++ b/x/ibc/07-tendermint/tendermint_test.go @@ -0,0 +1,57 @@ +package tendermint_test + +import ( + "testing" + "time" + + "github.com/stretchr/testify/suite" + + tmtypes "github.com/tendermint/tendermint/types" + + "github.com/cosmos/cosmos-sdk/codec" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" + commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" +) + +const ( + chainID = "gaia" + height = 4 + trustingPeriod time.Duration = time.Hour * 24 * 7 * 2 + ubdPeriod time.Duration = time.Hour * 24 * 7 * 3 +) + +type TendermintTestSuite struct { + suite.Suite + + cdc *codec.Codec + privVal tmtypes.PrivValidator + valSet *tmtypes.ValidatorSet + header ibctmtypes.Header + now time.Time + clientTime time.Time + headerTime time.Time +} + +func (suite *TendermintTestSuite) SetupTest() { + suite.cdc = codec.New() + codec.RegisterCrypto(suite.cdc) + ibctmtypes.RegisterCodec(suite.cdc) + commitmenttypes.RegisterCodec(suite.cdc) + + // now is the time of the current chain, must be after the updating header + // mocks ctx.BlockTime() + suite.now = time.Date(2020, 1, 3, 0, 0, 0, 0, time.UTC) + suite.clientTime = time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC) + // Header time is intended to be time for any new header used for updates + suite.headerTime = time.Date(2020, 1, 2, 0, 0, 0, 0, time.UTC) + suite.privVal = tmtypes.NewMockPV() + val := tmtypes.NewValidator(suite.privVal.GetPubKey(), 10) + suite.valSet = tmtypes.NewValidatorSet([]*tmtypes.Validator{val}) + // Suite header is intended to be header passed in for initial ClientState + // Thus it should have same height and time as ClientState + suite.header = ibctmtypes.CreateTestHeader(chainID, height, suite.clientTime, suite.valSet, []tmtypes.PrivValidator{suite.privVal}) +} + +func TestTendermintTestSuite(t *testing.T) { + suite.Run(t, new(TendermintTestSuite)) +} diff --git a/x/ibc/07-tendermint/types/client_state.go b/x/ibc/07-tendermint/types/client_state.go new file mode 100644 index 000000000000..ca42a181ea8c --- /dev/null +++ b/x/ibc/07-tendermint/types/client_state.go @@ -0,0 +1,344 @@ +package types + +import ( + "errors" + "fmt" + "time" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" + connectionexported "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported" + channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" + commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +var _ clientexported.ClientState = ClientState{} + +// ClientState from Tendermint tracks the current validator set, latest height, +// and a possible frozen height. +type ClientState struct { + // Client ID + ID string `json:"id" yaml:"id"` + // Duration of the period since the LastestTimestamp during which the + // submitted headers are valid for upgrade + TrustingPeriod time.Duration `json:"trusting_period" yaml:"trusting_period"` + // Duration of the staking unbonding period + UnbondingPeriod time.Duration `json:"unbonding_period" yaml:"unbonding_period"` + // Block height when the client was frozen due to a misbehaviour + FrozenHeight uint64 `json:"frozen_height" yaml:"frozen_height"` + // Last Header that was stored by client + LastHeader Header +} + +// InitializeFromMsg creates a tendermint client state from a CreateClientMsg +func InitializeFromMsg( + msg MsgCreateClient, +) (ClientState, error) { + return Initialize(msg.GetClientID(), msg.TrustingPeriod, msg.UnbondingPeriod, msg.Header) +} + +// Initialize creates a client state and validates its contents, checking that +// the provided consensus state is from the same client type. +func Initialize( + id string, trustingPeriod, ubdPeriod time.Duration, + header Header, +) (ClientState, error) { + if trustingPeriod >= ubdPeriod { + return ClientState{}, errors.New("trusting period should be < unbonding period") + } + + clientState := NewClientState( + id, trustingPeriod, ubdPeriod, header, + ) + return clientState, nil +} + +// NewClientState creates a new ClientState instance +func NewClientState( + id string, trustingPeriod, ubdPeriod time.Duration, + header Header, +) ClientState { + return ClientState{ + ID: id, + TrustingPeriod: trustingPeriod, + UnbondingPeriod: ubdPeriod, + LastHeader: header, + FrozenHeight: 0, + } +} + +// GetID returns the tendermint client state identifier. +func (cs ClientState) GetID() string { + return cs.ID +} + +// GetChainID returns the chain-id from the last header +func (cs ClientState) GetChainID() string { + return cs.LastHeader.ChainID +} + +// ClientType is tendermint. +func (cs ClientState) ClientType() clientexported.ClientType { + return clientexported.Tendermint +} + +// GetLatestHeight returns latest block height. +func (cs ClientState) GetLatestHeight() uint64 { + return uint64(cs.LastHeader.Height) +} + +// GetLatestTimestamp returns latest block time. +func (cs ClientState) GetLatestTimestamp() time.Time { + return cs.LastHeader.Time +} + +// IsFrozen returns true if the frozen height has been set. +func (cs ClientState) IsFrozen() bool { + return cs.FrozenHeight != 0 +} + +// VerifyClientConsensusState verifies a proof of the consensus state of the +// Tendermint client stored on the target machine. +func (cs ClientState) VerifyClientConsensusState( + cdc *codec.Codec, + provingRoot commitmentexported.Root, + height uint64, + counterpartyClientIdentifier string, + consensusHeight uint64, + prefix commitmentexported.Prefix, + proof commitmentexported.Proof, + consensusState clientexported.ConsensusState, +) error { + path, err := commitmenttypes.ApplyPrefix(prefix, ibctypes.ConsensusStatePath(counterpartyClientIdentifier, consensusHeight)) + if err != nil { + return err + } + + if err := validateVerificationArgs(cs, height, proof, consensusState); err != nil { + return err + } + + bz, err := cdc.MarshalBinaryLengthPrefixed(consensusState) + if err != nil { + return err + } + + if err := proof.VerifyMembership(provingRoot, path, bz); err != nil { + return sdkerrors.Wrap(clienttypes.ErrFailedClientConsensusStateVerification, err.Error()) + } + + return nil +} + +// VerifyConnectionState verifies a proof of the connection state of the +// specified connection end stored on the target machine. +func (cs ClientState) VerifyConnectionState( + cdc *codec.Codec, + height uint64, + prefix commitmentexported.Prefix, + proof commitmentexported.Proof, + connectionID string, + connectionEnd connectionexported.ConnectionI, + consensusState clientexported.ConsensusState, +) error { + path, err := commitmenttypes.ApplyPrefix(prefix, ibctypes.ConnectionPath(connectionID)) + if err != nil { + return err + } + + if err := validateVerificationArgs(cs, height, proof, consensusState); err != nil { + return err + } + + bz, err := cdc.MarshalBinaryLengthPrefixed(connectionEnd) + if err != nil { + return err + } + + if err := proof.VerifyMembership(consensusState.GetRoot(), path, bz); err != nil { + return sdkerrors.Wrap(clienttypes.ErrFailedConnectionStateVerification, err.Error()) + } + + return nil +} + +// VerifyChannelState verifies a proof of the channel state of the specified +// channel end, under the specified port, stored on the target machine. +func (cs ClientState) VerifyChannelState( + cdc *codec.Codec, + height uint64, + prefix commitmentexported.Prefix, + proof commitmentexported.Proof, + portID, + channelID string, + channel channelexported.ChannelI, + consensusState clientexported.ConsensusState, +) error { + path, err := commitmenttypes.ApplyPrefix(prefix, ibctypes.ChannelPath(portID, channelID)) + if err != nil { + return err + } + + if err := validateVerificationArgs(cs, height, proof, consensusState); err != nil { + return err + } + + bz, err := cdc.MarshalBinaryLengthPrefixed(channel) + if err != nil { + return err + } + + if err := proof.VerifyMembership(consensusState.GetRoot(), path, bz); err != nil { + return sdkerrors.Wrap(clienttypes.ErrFailedChannelStateVerification, err.Error()) + } + + return nil +} + +// VerifyPacketCommitment verifies a proof of an outgoing packet commitment at +// the specified port, specified channel, and specified sequence. +func (cs ClientState) VerifyPacketCommitment( + height uint64, + prefix commitmentexported.Prefix, + proof commitmentexported.Proof, + portID, + channelID string, + sequence uint64, + commitmentBytes []byte, + consensusState clientexported.ConsensusState, +) error { + path, err := commitmenttypes.ApplyPrefix(prefix, ibctypes.PacketCommitmentPath(portID, channelID, sequence)) + if err != nil { + return err + } + + if err := validateVerificationArgs(cs, height, proof, consensusState); err != nil { + return err + } + + if err := proof.VerifyMembership(consensusState.GetRoot(), path, commitmentBytes); err != nil { + return sdkerrors.Wrap(clienttypes.ErrFailedPacketCommitmentVerification, err.Error()) + } + + return nil +} + +// VerifyPacketAcknowledgement verifies a proof of an incoming packet +// acknowledgement at the specified port, specified channel, and specified sequence. +func (cs ClientState) VerifyPacketAcknowledgement( + height uint64, + prefix commitmentexported.Prefix, + proof commitmentexported.Proof, + portID, + channelID string, + sequence uint64, + acknowledgement []byte, + consensusState clientexported.ConsensusState, +) error { + path, err := commitmenttypes.ApplyPrefix(prefix, ibctypes.PacketAcknowledgementPath(portID, channelID, sequence)) + if err != nil { + return err + } + + if err := validateVerificationArgs(cs, height, proof, consensusState); err != nil { + return err + } + + if err := proof.VerifyMembership(consensusState.GetRoot(), path, acknowledgement); err != nil { + return sdkerrors.Wrap(clienttypes.ErrFailedPacketAckVerification, err.Error()) + } + + return nil +} + +// VerifyPacketAcknowledgementAbsence verifies a proof of the absence of an +// incoming packet acknowledgement at the specified port, specified channel, and +// specified sequence. +func (cs ClientState) VerifyPacketAcknowledgementAbsence( + height uint64, + prefix commitmentexported.Prefix, + proof commitmentexported.Proof, + portID, + channelID string, + sequence uint64, + consensusState clientexported.ConsensusState, +) error { + path, err := commitmenttypes.ApplyPrefix(prefix, ibctypes.PacketAcknowledgementPath(portID, channelID, sequence)) + if err != nil { + return err + } + + if err := validateVerificationArgs(cs, height, proof, consensusState); err != nil { + return err + } + + if err := proof.VerifyNonMembership(consensusState.GetRoot(), path); err != nil { + return sdkerrors.Wrap(clienttypes.ErrFailedPacketAckAbsenceVerification, err.Error()) + } + + return nil +} + +// VerifyNextSequenceRecv verifies a proof of the next sequence number to be +// received of the specified channel at the specified port. +func (cs ClientState) VerifyNextSequenceRecv( + height uint64, + prefix commitmentexported.Prefix, + proof commitmentexported.Proof, + portID, + channelID string, + nextSequenceRecv uint64, + consensusState clientexported.ConsensusState, +) error { + path, err := commitmenttypes.ApplyPrefix(prefix, ibctypes.NextSequenceRecvPath(portID, channelID)) + if err != nil { + return err + } + + if err := validateVerificationArgs(cs, height, proof, consensusState); err != nil { + return err + } + + bz := sdk.Uint64ToBigEndian(nextSequenceRecv) + + if err := proof.VerifyMembership(consensusState.GetRoot(), path, bz); err != nil { + return sdkerrors.Wrap(clienttypes.ErrFailedNextSeqRecvVerification, err.Error()) + } + + return nil +} + +// validateVerificationArgs perfoms the basic checks on the arguments that are +// shared between the verification functions. +func validateVerificationArgs( + cs ClientState, + height uint64, + proof commitmentexported.Proof, + consensusState clientexported.ConsensusState, +) error { + if cs.GetLatestHeight() < height { + return sdkerrors.Wrap( + ibctypes.ErrInvalidHeight, + fmt.Sprintf("client state (%s) height < proof height (%d < %d)", cs.ID, cs.GetLatestHeight(), height), + ) + } + + if cs.IsFrozen() && cs.FrozenHeight <= height { + return clienttypes.ErrClientFrozen + } + + if proof == nil { + return sdkerrors.Wrap(commitmenttypes.ErrInvalidProof, "proof cannot be empty") + } + + if consensusState == nil { + return sdkerrors.Wrap(clienttypes.ErrInvalidConsensus, "consensus state cannot be empty") + } + + return nil +} diff --git a/x/ibc/07-tendermint/types/client_state_test.go b/x/ibc/07-tendermint/types/client_state_test.go new file mode 100644 index 000000000000..b5d37ca06ad2 --- /dev/null +++ b/x/ibc/07-tendermint/types/client_state_test.go @@ -0,0 +1,567 @@ +package types_test + +import ( + connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" + connectionexported "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported" + channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" + channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" + commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" +) + +const ( + testConnectionID = "connectionid" + testPortID = "testportid" + testChannelID = "testchannelid" + testSequence = 1 +) + +func (suite *TendermintTestSuite) TestVerifyClientConsensusState() { + testCases := []struct { + name string + clientState ibctmtypes.ClientState + consensusState ibctmtypes.ConsensusState + prefix commitmenttypes.MerklePrefix + proof commitmenttypes.MerkleProof + expPass bool + }{ + // FIXME: uncomment + // { + // name: "successful verification", + // clientState: ibctmtypes.NewClientState(chainID, chainID, height), + // consensusState: ibctmtypes.ConsensusState{ + // Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash), + // }, + // prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")), + // expPass: true, + // }, + { + name: "ApplyPrefix failed", + clientState: ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), + consensusState: ibctmtypes.ConsensusState{ + Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash), + }, + prefix: commitmenttypes.MerklePrefix{}, + expPass: false, + }, + { + name: "latest client height < height", + clientState: ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), + consensusState: ibctmtypes.ConsensusState{ + Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash), + }, + prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")), + expPass: false, + }, + { + name: "client is frozen", + clientState: ibctmtypes.ClientState{ID: chainID, LastHeader: suite.header, FrozenHeight: height - 1}, + consensusState: ibctmtypes.ConsensusState{ + Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash), + }, + prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")), + expPass: false, + }, + { + name: "proof verification failed", + clientState: ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), + consensusState: ibctmtypes.ConsensusState{ + Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash), + ValidatorSet: suite.valSet, + }, + prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")), + proof: commitmenttypes.MerkleProof{}, + expPass: false, + }, + } + + for i, tc := range testCases { + tc := tc + + err := tc.clientState.VerifyClientConsensusState( + suite.cdc, tc.consensusState.Root, height, "chainA", tc.consensusState.GetHeight(), tc.prefix, tc.proof, tc.consensusState, + ) + + if tc.expPass { + suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name) + } else { + suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name) + } + } +} + +func (suite *TendermintTestSuite) TestVerifyConnectionState() { + counterparty := connection.NewCounterparty("clientB", testConnectionID, commitmenttypes.NewMerklePrefix([]byte("ibc"))) + conn := connection.NewConnectionEnd(connectionexported.OPEN, "clientA", counterparty, []string{"1.0.0"}) + + testCases := []struct { + name string + clientState ibctmtypes.ClientState + connection connection.ConnectionEnd + consensusState ibctmtypes.ConsensusState + prefix commitmenttypes.MerklePrefix + proof commitmenttypes.MerkleProof + expPass bool + }{ + // FIXME: uncomment + // { + // name: "successful verification", + // clientState: ibctmtypes.NewClientState(chainID, chainID, height), + // connection: conn, + // consensusState: ibctmtypes.ConsensusState{ + // Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash), + // }, + // prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")), + // expPass: true, + // }, + { + name: "ApplyPrefix failed", + clientState: ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), + connection: conn, + consensusState: ibctmtypes.ConsensusState{ + Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash), + }, + prefix: commitmenttypes.MerklePrefix{}, + expPass: false, + }, + { + name: "latest client height < height", + clientState: ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), + connection: conn, + consensusState: ibctmtypes.ConsensusState{ + Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash), + }, + prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")), + expPass: false, + }, + { + name: "client is frozen", + clientState: ibctmtypes.ClientState{ID: chainID, LastHeader: suite.header, FrozenHeight: height - 1}, + connection: conn, + consensusState: ibctmtypes.ConsensusState{ + Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash), + }, + prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")), + expPass: false, + }, + { + name: "proof verification failed", + clientState: ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), + connection: conn, + consensusState: ibctmtypes.ConsensusState{ + Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash), + ValidatorSet: suite.valSet, + }, + prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")), + proof: commitmenttypes.MerkleProof{}, + expPass: false, + }, + } + + for i, tc := range testCases { + tc := tc + + err := tc.clientState.VerifyConnectionState( + suite.cdc, height, tc.prefix, tc.proof, testConnectionID, tc.connection, tc.consensusState, + ) + + if tc.expPass { + suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name) + } else { + suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name) + } + } +} + +func (suite *TendermintTestSuite) TestVerifyChannelState() { + counterparty := channel.NewCounterparty(testPortID, testChannelID) + ch := channel.NewChannel(channelexported.OPEN, channelexported.ORDERED, counterparty, []string{testConnectionID}, "1.0.0") + + testCases := []struct { + name string + clientState ibctmtypes.ClientState + channel channel.Channel + consensusState ibctmtypes.ConsensusState + prefix commitmenttypes.MerklePrefix + proof commitmenttypes.MerkleProof + expPass bool + }{ + // FIXME: uncomment + // { + // name: "successful verification", + // clientState: ibctmtypes.NewClientState(chainID, height), + // connection: conn, + // consensusState: ibctmtypes.ConsensusState{ + // Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash), + // }, + // prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")), + // expPass: true, + // }, + { + name: "ApplyPrefix failed", + clientState: ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), + channel: ch, + consensusState: ibctmtypes.ConsensusState{ + Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash), + }, + prefix: commitmenttypes.MerklePrefix{}, + expPass: false, + }, + { + name: "latest client height < height", + clientState: ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), + channel: ch, + consensusState: ibctmtypes.ConsensusState{ + Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash), + }, + prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")), + expPass: false, + }, + { + name: "client is frozen", + clientState: ibctmtypes.ClientState{ID: chainID, LastHeader: suite.header, FrozenHeight: height - 1}, + channel: ch, + consensusState: ibctmtypes.ConsensusState{ + Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash), + }, + prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")), + expPass: false, + }, + { + name: "proof verification failed", + clientState: ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), + channel: ch, + consensusState: ibctmtypes.ConsensusState{ + Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash), + ValidatorSet: suite.valSet, + }, + prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")), + proof: commitmenttypes.MerkleProof{}, + expPass: false, + }, + } + + for i, tc := range testCases { + tc := tc + + err := tc.clientState.VerifyChannelState( + suite.cdc, height, tc.prefix, tc.proof, testPortID, testChannelID, tc.channel, tc.consensusState, + ) + + if tc.expPass { + suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name) + } else { + suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name) + } + } +} + +func (suite *TendermintTestSuite) TestVerifyPacketCommitment() { + testCases := []struct { + name string + clientState ibctmtypes.ClientState + commitment []byte + consensusState ibctmtypes.ConsensusState + prefix commitmenttypes.MerklePrefix + proof commitmenttypes.MerkleProof + expPass bool + }{ + // FIXME: uncomment + // { + // name: "successful verification", + // clientState: ibctmtypes.NewClientState(chainID, height), + // connection: conn, + // consensusState: ibctmtypes.ConsensusState{ + // Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash), + // }, + // prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")), + // expPass: true, + // }, + { + name: "ApplyPrefix failed", + clientState: ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), + commitment: []byte{}, + consensusState: ibctmtypes.ConsensusState{ + Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash), + }, + prefix: commitmenttypes.MerklePrefix{}, + expPass: false, + }, + { + name: "latest client height < height", + clientState: ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), + commitment: []byte{}, + consensusState: ibctmtypes.ConsensusState{ + Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash), + }, + prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")), + expPass: false, + }, + { + name: "client is frozen", + clientState: ibctmtypes.ClientState{ID: chainID, LastHeader: suite.header, FrozenHeight: height - 1}, + commitment: []byte{}, + consensusState: ibctmtypes.ConsensusState{ + Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash), + }, + prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")), + expPass: false, + }, + { + name: "proof verification failed", + clientState: ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), + commitment: []byte{}, + consensusState: ibctmtypes.ConsensusState{ + Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash), + ValidatorSet: suite.valSet, + }, + prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")), + proof: commitmenttypes.MerkleProof{}, + expPass: false, + }, + } + + for i, tc := range testCases { + tc := tc + + err := tc.clientState.VerifyPacketCommitment( + height, tc.prefix, tc.proof, testPortID, testChannelID, testSequence, tc.commitment, tc.consensusState, + ) + + if tc.expPass { + suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name) + } else { + suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name) + } + } +} + +func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgement() { + testCases := []struct { + name string + clientState ibctmtypes.ClientState + ack []byte + consensusState ibctmtypes.ConsensusState + prefix commitmenttypes.MerklePrefix + proof commitmenttypes.MerkleProof + expPass bool + }{ + // FIXME: uncomment + // { + // name: "successful verification", + // clientState: ibctmtypes.NewClientState(chainID, chainID, height), + // connection: conn, + // consensusState: ibctmtypes.ConsensusState{ + // Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash), + // }, + // prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")), + // expPass: true, + // }, + { + name: "ApplyPrefix failed", + clientState: ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), + ack: []byte{}, + consensusState: ibctmtypes.ConsensusState{ + Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash), + }, + prefix: commitmenttypes.MerklePrefix{}, + expPass: false, + }, + { + name: "latest client height < height", + clientState: ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), + ack: []byte{}, + consensusState: ibctmtypes.ConsensusState{ + Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash), + }, + prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")), + expPass: false, + }, + { + name: "client is frozen", + clientState: ibctmtypes.ClientState{ID: chainID, LastHeader: suite.header, FrozenHeight: height - 1}, + ack: []byte{}, + consensusState: ibctmtypes.ConsensusState{ + Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash), + }, + prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")), + expPass: false, + }, + { + name: "proof verification failed", + clientState: ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), + ack: []byte{}, + consensusState: ibctmtypes.ConsensusState{ + Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash), + ValidatorSet: suite.valSet, + }, + prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")), + proof: commitmenttypes.MerkleProof{}, + expPass: false, + }, + } + + for i, tc := range testCases { + tc := tc + + err := tc.clientState.VerifyPacketAcknowledgement( + height, tc.prefix, tc.proof, testPortID, testChannelID, testSequence, tc.ack, tc.consensusState, + ) + + if tc.expPass { + suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name) + } else { + suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name) + } + } +} + +func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgementAbsence() { + testCases := []struct { + name string + clientState ibctmtypes.ClientState + consensusState ibctmtypes.ConsensusState + prefix commitmenttypes.MerklePrefix + proof commitmenttypes.MerkleProof + expPass bool + }{ + // FIXME: uncomment + // { + // name: "successful verification", + // clientState: ibctmtypes.NewClientState(chainID, chainID, height), + // connection: conn, + // consensusState: ibctmtypes.ConsensusState{ + // Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash), + // }, + // prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")), + // expPass: true, + // }, + { + name: "ApplyPrefix failed", + clientState: ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), + consensusState: ibctmtypes.ConsensusState{ + Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash), + }, + prefix: commitmenttypes.MerklePrefix{}, + expPass: false, + }, + { + name: "latest client height < height", + clientState: ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), + consensusState: ibctmtypes.ConsensusState{ + Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash), + }, + prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")), + expPass: false, + }, + { + name: "client is frozen", + clientState: ibctmtypes.ClientState{ID: chainID, LastHeader: suite.header, FrozenHeight: height - 1}, + consensusState: ibctmtypes.ConsensusState{ + Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash), + }, + prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")), + expPass: false, + }, + { + name: "proof verification failed", + clientState: ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), + consensusState: ibctmtypes.ConsensusState{ + Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash), + ValidatorSet: suite.valSet, + }, + prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")), + proof: commitmenttypes.MerkleProof{}, + expPass: false, + }, + } + + for i, tc := range testCases { + tc := tc + + err := tc.clientState.VerifyPacketAcknowledgementAbsence( + height, tc.prefix, tc.proof, testPortID, testChannelID, testSequence, tc.consensusState, + ) + + if tc.expPass { + suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name) + } else { + suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name) + } + } +} + +func (suite *TendermintTestSuite) TestVerifyNextSeqRecv() { + testCases := []struct { + name string + clientState ibctmtypes.ClientState + consensusState ibctmtypes.ConsensusState + prefix commitmenttypes.MerklePrefix + proof commitmenttypes.MerkleProof + expPass bool + }{ + // FIXME: uncomment + // { + // name: "successful verification", + // clientState: ibctmtypes.NewClientState(chainID, chainID, height), + // connection: conn, + // consensusState: ibctmtypes.ConsensusState{ + // Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash), + // }, + // prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")), + // expPass: true, + // }, + { + name: "ApplyPrefix failed", + clientState: ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), + consensusState: ibctmtypes.ConsensusState{ + Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash), + }, + prefix: commitmenttypes.MerklePrefix{}, + expPass: false, + }, + { + name: "latest client height < height", + clientState: ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), + consensusState: ibctmtypes.ConsensusState{ + Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash), + }, + prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")), + expPass: false, + }, + { + name: "client is frozen", + clientState: ibctmtypes.ClientState{ID: chainID, LastHeader: suite.header, FrozenHeight: height - 1}, + consensusState: ibctmtypes.ConsensusState{ + Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash), + }, + prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")), + expPass: false, + }, + { + name: "proof verification failed", + clientState: ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), + consensusState: ibctmtypes.ConsensusState{ + Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash), + ValidatorSet: suite.valSet, + }, + prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")), + proof: commitmenttypes.MerkleProof{}, + expPass: false, + }, + } + + for i, tc := range testCases { + tc := tc + + err := tc.clientState.VerifyNextSequenceRecv( + height, tc.prefix, tc.proof, testPortID, testChannelID, testSequence, tc.consensusState, + ) + + if tc.expPass { + suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name) + } else { + suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name) + } + } +} diff --git a/x/ibc/07-tendermint/types/codec.go b/x/ibc/07-tendermint/types/codec.go new file mode 100644 index 000000000000..4221c58eda4a --- /dev/null +++ b/x/ibc/07-tendermint/types/codec.go @@ -0,0 +1,26 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" +) + +// SubModuleCdc defines the IBC tendermint client codec. +var SubModuleCdc *codec.Codec + +// RegisterCodec registers the Tendermint types +func RegisterCodec(cdc *codec.Codec) { + cdc.RegisterConcrete(ClientState{}, "ibc/client/tendermint/ClientState", nil) + cdc.RegisterConcrete(ConsensusState{}, "ibc/client/tendermint/ConsensusState", nil) + cdc.RegisterConcrete(Header{}, "ibc/client/tendermint/Header", nil) + cdc.RegisterConcrete(Evidence{}, "ibc/client/tendermint/Evidence", nil) + cdc.RegisterConcrete(MsgCreateClient{}, "ibc/client/MsgCreateClient", nil) + cdc.RegisterConcrete(MsgUpdateClient{}, "ibc/client/MsgUpdateClient", nil) + cdc.RegisterConcrete(MsgSubmitClientMisbehaviour{}, "ibc/client/MsgSubmitClientMisbehaviour", nil) + + SetSubModuleCodec(cdc) +} + +// SetSubModuleCodec sets the ibc tendermint client codec +func SetSubModuleCodec(cdc *codec.Codec) { + SubModuleCdc = cdc +} diff --git a/x/ibc/07-tendermint/types/consensus_state.go b/x/ibc/07-tendermint/types/consensus_state.go new file mode 100644 index 000000000000..801fc768f181 --- /dev/null +++ b/x/ibc/07-tendermint/types/consensus_state.go @@ -0,0 +1,57 @@ +package types + +import ( + "time" + + tmtypes "github.com/tendermint/tendermint/types" + + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" + commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" +) + +// ConsensusState defines a Tendermint consensus state +type ConsensusState struct { + Timestamp time.Time `json:"timestamp" yaml:"timestamp"` + Root commitmentexported.Root `json:"root" yaml:"root"` + Height uint64 `json:"height" yaml:"height"` + ValidatorSet *tmtypes.ValidatorSet `json:"validator_set" yaml:"validator_set"` +} + +// ClientType returns Tendermint +func (ConsensusState) ClientType() clientexported.ClientType { + return clientexported.Tendermint +} + +// GetRoot returns the commitment Root for the specific +func (cs ConsensusState) GetRoot() commitmentexported.Root { + return cs.Root +} + +// GetHeight returns the height for the specific consensus state +func (cs ConsensusState) GetHeight() uint64 { + return cs.Height +} + +// GetTimestamp returns block time at which the consensus state was stored +func (cs ConsensusState) GetTimestamp() time.Time { + return cs.Timestamp +} + +// ValidateBasic defines a basic validation for the tendermint consensus state. +func (cs ConsensusState) ValidateBasic() error { + if cs.Root == nil || cs.Root.IsEmpty() { + return sdkerrors.Wrap(clienttypes.ErrInvalidConsensus, "root cannot be empty") + } + if cs.ValidatorSet == nil { + return sdkerrors.Wrap(clienttypes.ErrInvalidConsensus, "validator set cannot be nil") + } + if cs.Height == 0 { + return sdkerrors.Wrap(clienttypes.ErrInvalidConsensus, "height cannot be 0") + } + if cs.Timestamp.IsZero() { + return sdkerrors.Wrap(clienttypes.ErrInvalidConsensus, "timestamp cannot be zero Unix time") + } + return nil +} diff --git a/x/ibc/07-tendermint/types/consensus_state_test.go b/x/ibc/07-tendermint/types/consensus_state_test.go new file mode 100644 index 000000000000..ac1229b40568 --- /dev/null +++ b/x/ibc/07-tendermint/types/consensus_state_test.go @@ -0,0 +1,79 @@ +package types_test + +import ( + "time" + + clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" + commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" +) + +func (suite *TendermintTestSuite) TestConsensusStateValidateBasic() { + testCases := []struct { + msg string + consensusState ibctmtypes.ConsensusState + expectPass bool + }{ + {"success", + ibctmtypes.ConsensusState{ + Timestamp: suite.now, + Height: height, + Root: commitmenttypes.NewMerkleRoot([]byte("app_hash")), + ValidatorSet: suite.valSet, + }, + true}, + {"root is nil", + ibctmtypes.ConsensusState{ + Timestamp: suite.now, + Height: height, + Root: nil, + ValidatorSet: suite.valSet, + }, + false}, + {"root is empty", + ibctmtypes.ConsensusState{ + Timestamp: suite.now, + Height: height, + Root: commitmenttypes.MerkleRoot{}, + ValidatorSet: suite.valSet, + }, + false}, + {"valset is nil", + ibctmtypes.ConsensusState{ + Timestamp: suite.now, + Height: height, + Root: commitmenttypes.NewMerkleRoot([]byte("app_hash")), + ValidatorSet: nil, + }, + false}, + {"height is 0", + ibctmtypes.ConsensusState{ + Timestamp: suite.now, + Height: 0, + Root: commitmenttypes.NewMerkleRoot([]byte("app_hash")), + ValidatorSet: suite.valSet, + }, + false}, + {"timestamp is zero", + ibctmtypes.ConsensusState{ + Timestamp: time.Time{}, + Height: height, + Root: commitmenttypes.NewMerkleRoot([]byte("app_hash")), + ValidatorSet: suite.valSet, + }, + false}, + } + + for i, tc := range testCases { + tc := tc + + suite.Require().Equal(tc.consensusState.ClientType(), clientexported.Tendermint) + suite.Require().Equal(tc.consensusState.GetRoot(), tc.consensusState.Root) + + if tc.expectPass { + suite.Require().NoError(tc.consensusState.ValidateBasic(), "valid test case %d failed: %s", i, tc.msg) + } else { + suite.Require().Error(tc.consensusState.ValidateBasic(), "invalid test case %d passed: %s", i, tc.msg) + } + } +} diff --git a/x/ibc/07-tendermint/types/errors.go b/x/ibc/07-tendermint/types/errors.go new file mode 100644 index 000000000000..58c97a0ebe4b --- /dev/null +++ b/x/ibc/07-tendermint/types/errors.go @@ -0,0 +1,15 @@ +package types + +import ( + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +const ( + SubModuleName = "tendermint" +) + +var ( + ErrInvalidTrustingPeriod = sdkerrors.Register(SubModuleName, 1, "invalid trusting period") + ErrInvalidUnbondingPeriod = sdkerrors.Register(SubModuleName, 2, "invalid unbonding period") + ErrInvalidHeader = sdkerrors.Register(SubModuleName, 3, "invalid header") +) diff --git a/x/ibc/07-tendermint/types/evidence.go b/x/ibc/07-tendermint/types/evidence.go new file mode 100644 index 000000000000..d161c10ed5dc --- /dev/null +++ b/x/ibc/07-tendermint/types/evidence.go @@ -0,0 +1,135 @@ +package types + +import ( + "math" + + yaml "gopkg.in/yaml.v2" + + "github.com/tendermint/tendermint/crypto/tmhash" + tmbytes "github.com/tendermint/tendermint/libs/bytes" + tmtypes "github.com/tendermint/tendermint/types" + + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + evidenceexported "github.com/cosmos/cosmos-sdk/x/evidence/exported" + clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" + host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" +) + +var ( + _ evidenceexported.Evidence = Evidence{} + _ clientexported.Misbehaviour = Evidence{} +) + +// Evidence is a wrapper over tendermint's DuplicateVoteEvidence +// that implements Evidence interface expected by ICS-02 +type Evidence struct { + ClientID string `json:"client_id" yaml:"client_id"` + Header1 Header `json:"header1" yaml:"header1"` + Header2 Header `json:"header2" yaml:"header2"` + ChainID string `json:"chain_id" yaml:"chain_id"` +} + +// ClientType is Tendermint light client +func (ev Evidence) ClientType() clientexported.ClientType { + return clientexported.Tendermint +} + +// GetClientID returns the ID of the client that committed a misbehaviour. +func (ev Evidence) GetClientID() string { + return ev.ClientID +} + +// Route implements Evidence interface +func (ev Evidence) Route() string { + return clienttypes.SubModuleName +} + +// Type implements Evidence interface +func (ev Evidence) Type() string { + return "client_misbehaviour" +} + +// String implements Evidence interface +func (ev Evidence) String() string { + // FIXME: implement custom marshaller + bz, err := yaml.Marshal(ev) + if err != nil { + panic(err) + } + return string(bz) +} + +// Hash implements Evidence interface +func (ev Evidence) Hash() tmbytes.HexBytes { + bz := SubModuleCdc.MustMarshalBinaryBare(ev) + return tmhash.Sum(bz) +} + +// GetHeight returns the height at which misbehaviour occurred +// +// NOTE: assumes that evidence headers have the same height +func (ev Evidence) GetHeight() int64 { + return int64(math.Min(float64(ev.Header1.Height), float64(ev.Header2.Height))) +} + +// ValidateBasic implements Evidence interface +func (ev Evidence) ValidateBasic() error { + if err := host.DefaultClientIdentifierValidator(ev.ClientID); err != nil { + return sdkerrors.Wrap(clienttypes.ErrInvalidEvidence, err.Error()) + } + + // ValidateBasic on both validators + if err := ev.Header1.ValidateBasic(ev.ChainID); err != nil { + return sdkerrors.Wrap( + clienttypes.ErrInvalidEvidence, + sdkerrors.Wrap(err, "header 1 failed validation").Error(), + ) + } + if err := ev.Header2.ValidateBasic(ev.ChainID); err != nil { + return sdkerrors.Wrap( + clienttypes.ErrInvalidEvidence, + sdkerrors.Wrap(err, "header 2 failed validation").Error(), + ) + } + // Ensure that Heights are the same + if ev.Header1.Height != ev.Header2.Height { + return sdkerrors.Wrapf(clienttypes.ErrInvalidEvidence, "headers in evidence are on different heights (%d ≠ %d)", ev.Header1.Height, ev.Header2.Height) + } + // Ensure that Commit Hashes are different + if ev.Header1.Commit.BlockID.Equals(ev.Header2.Commit.BlockID) { + return sdkerrors.Wrap(clienttypes.ErrInvalidEvidence, "headers commit to same blockID") + } + if err := ValidCommit(ev.ChainID, ev.Header1.Commit, ev.Header1.ValidatorSet); err != nil { + return err + } + if err := ValidCommit(ev.ChainID, ev.Header2.Commit, ev.Header2.ValidatorSet); err != nil { + return err + } + return nil +} + +// ValidCommit checks if the given commit is a valid commit from the passed-in validatorset +// +// CommitToVoteSet will panic if the commit cannot be converted to a valid voteset given the validatorset +// This implies that someone tried to submit evidence that wasn't actually committed by the validatorset +// thus we should return an error here and reject the evidence rather than panicing. +func ValidCommit(chainID string, commit *tmtypes.Commit, valSet *tmtypes.ValidatorSet) (err error) { + defer func() { + if r := recover(); r != nil { + err = sdkerrors.Wrapf(clienttypes.ErrInvalidEvidence, "invalid commit: %v", r) + } + }() + + // Convert commits to vote-sets given the validator set so we can check if they both have 2/3 power + voteSet := tmtypes.CommitToVoteSet(chainID, commit, valSet) + + blockID, ok := voteSet.TwoThirdsMajority() + + // Check that ValidatorSet did indeed commit to blockID in Commit + if !ok || !blockID.Equals(commit.BlockID) { + return sdkerrors.Wrap(clienttypes.ErrInvalidEvidence, "validator set did not commit to header 1") + } + + return nil +} diff --git a/x/ibc/07-tendermint/types/evidence_test.go b/x/ibc/07-tendermint/types/evidence_test.go new file mode 100644 index 000000000000..0f363827cdfa --- /dev/null +++ b/x/ibc/07-tendermint/types/evidence_test.go @@ -0,0 +1,187 @@ +package types_test + +import ( + "bytes" + "time" + + "github.com/tendermint/tendermint/crypto/tmhash" + tmbytes "github.com/tendermint/tendermint/libs/bytes" + tmtypes "github.com/tendermint/tendermint/types" + + clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" +) + +func (suite *TendermintTestSuite) TestEvidence() { + signers := []tmtypes.PrivValidator{suite.privVal} + + ev := ibctmtypes.Evidence{ + Header1: suite.header, + Header2: ibctmtypes.CreateTestHeader(chainID, height, suite.now, suite.valSet, signers), + ChainID: chainID, + ClientID: "gaiamainnet", + } + + suite.Require().Equal(ev.ClientType(), clientexported.Tendermint) + suite.Require().Equal(ev.GetClientID(), "gaiamainnet") + suite.Require().Equal(ev.Route(), "client") + suite.Require().Equal(ev.Type(), "client_misbehaviour") + suite.Require().Equal(ev.Hash(), tmbytes.HexBytes(tmhash.Sum(ibctmtypes.SubModuleCdc.MustMarshalBinaryBare(ev)))) + suite.Require().Equal(ev.GetHeight(), int64(height)) +} + +func (suite *TendermintTestSuite) TestEvidenceValidateBasic() { + altPrivVal := tmtypes.NewMockPV() + altVal := tmtypes.NewValidator(altPrivVal.GetPubKey(), height) + + // Create bothValSet with both suite validator and altVal + bothValSet := tmtypes.NewValidatorSet(append(suite.valSet.Validators, altVal)) + // Create alternative validator set with only altVal + altValSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{altVal}) + + signers := []tmtypes.PrivValidator{suite.privVal} + // Create signer array and ensure it is in same order as bothValSet + var bothSigners []tmtypes.PrivValidator + if bytes.Compare(altPrivVal.GetPubKey().Address(), suite.privVal.GetPubKey().Address()) == -1 { + bothSigners = []tmtypes.PrivValidator{altPrivVal, suite.privVal} + } else { + bothSigners = []tmtypes.PrivValidator{suite.privVal, altPrivVal} + } + + altSigners := []tmtypes.PrivValidator{altPrivVal} + + testCases := []struct { + name string + evidence ibctmtypes.Evidence + malleateEvidence func(ev *ibctmtypes.Evidence) error + expPass bool + }{ + { + "valid evidence", + ibctmtypes.Evidence{ + Header1: suite.header, + Header2: ibctmtypes.CreateTestHeader(chainID, height, suite.now.Add(time.Minute), suite.valSet, signers), + ChainID: chainID, + ClientID: "gaiamainnet", + }, + func(ev *ibctmtypes.Evidence) error { return nil }, + true, + }, + { + "invalid client ID ", + ibctmtypes.Evidence{ + Header1: suite.header, + Header2: ibctmtypes.CreateTestHeader(chainID, height, suite.now, suite.valSet, signers), + ChainID: chainID, + ClientID: "GAIA", + }, + func(ev *ibctmtypes.Evidence) error { return nil }, + false, + }, + { + "wrong chainID on header1", + ibctmtypes.Evidence{ + Header1: suite.header, + Header2: ibctmtypes.CreateTestHeader("ethermint", height, suite.now, suite.valSet, signers), + ChainID: "ethermint", + ClientID: "gaiamainnet", + }, + func(ev *ibctmtypes.Evidence) error { return nil }, + false, + }, + { + "wrong chainID on header2", + ibctmtypes.Evidence{ + Header1: suite.header, + Header2: ibctmtypes.CreateTestHeader("ethermint", height, suite.now, suite.valSet, signers), + ChainID: chainID, + ClientID: "gaiamainnet", + }, + func(ev *ibctmtypes.Evidence) error { return nil }, + false, + }, + { + "mismatched heights", + ibctmtypes.Evidence{ + Header1: suite.header, + Header2: ibctmtypes.CreateTestHeader(chainID, 6, suite.now, suite.valSet, signers), + ChainID: chainID, + ClientID: "gaiamainnet", + }, + func(ev *ibctmtypes.Evidence) error { return nil }, + false, + }, + { + "same block id", + ibctmtypes.Evidence{ + Header1: suite.header, + Header2: suite.header, + ChainID: chainID, + ClientID: "gaiamainnet", + }, + func(ev *ibctmtypes.Evidence) error { return nil }, + false, + }, + { + "header 1 doesn't have 2/3 majority", + ibctmtypes.Evidence{ + Header1: ibctmtypes.CreateTestHeader(chainID, height, suite.now, bothValSet, bothSigners), + Header2: suite.header, + ChainID: chainID, + ClientID: "gaiamainnet", + }, + func(ev *ibctmtypes.Evidence) error { + // voteSet contains only altVal which is less than 2/3 of total power (height/1height) + wrongVoteSet := tmtypes.NewVoteSet(chainID, ev.Header1.Height, 1, tmtypes.PrecommitType, altValSet) + var err error + ev.Header1.Commit, err = tmtypes.MakeCommit(ev.Header1.Commit.BlockID, ev.Header2.Height, ev.Header1.Commit.Round, wrongVoteSet, altSigners, suite.now) + return err + }, + false, + }, + { + "header 2 doesn't have 2/3 majority", + ibctmtypes.Evidence{ + Header1: suite.header, + Header2: ibctmtypes.CreateTestHeader(chainID, height, suite.now, bothValSet, bothSigners), + ChainID: chainID, + ClientID: "gaiamainnet", + }, + func(ev *ibctmtypes.Evidence) error { + // voteSet contains only altVal which is less than 2/3 of total power (height/1height) + wrongVoteSet := tmtypes.NewVoteSet(chainID, ev.Header2.Height, 1, tmtypes.PrecommitType, altValSet) + var err error + ev.Header2.Commit, err = tmtypes.MakeCommit(ev.Header2.Commit.BlockID, ev.Header2.Height, ev.Header2.Commit.Round, wrongVoteSet, altSigners, suite.now) + return err + }, + false, + }, + { + "validators sign off on wrong commit", + ibctmtypes.Evidence{ + Header1: suite.header, + Header2: ibctmtypes.CreateTestHeader(chainID, height, suite.now, bothValSet, bothSigners), + ChainID: chainID, + ClientID: "gaiamainnet", + }, + func(ev *ibctmtypes.Evidence) error { + ev.Header2.Commit.BlockID = ibctmtypes.MakeBlockID(tmhash.Sum([]byte("other_hash")), 3, tmhash.Sum([]byte("other_partset"))) + return nil + }, + false, + }, + } + + for i, tc := range testCases { + tc := tc + + err := tc.malleateEvidence(&tc.evidence) + suite.Require().NoError(err) + + if tc.expPass { + suite.Require().NoError(tc.evidence.ValidateBasic(), "valid test case %d failed: %s", i, tc.name) + } else { + suite.Require().Error(tc.evidence.ValidateBasic(), "invalid test case %d passed: %s", i, tc.name) + } + } +} diff --git a/x/ibc/07-tendermint/types/header.go b/x/ibc/07-tendermint/types/header.go new file mode 100644 index 000000000000..17e266a3cccf --- /dev/null +++ b/x/ibc/07-tendermint/types/header.go @@ -0,0 +1,64 @@ +package types + +import ( + "bytes" + + abci "github.com/tendermint/tendermint/abci/types" + tmtypes "github.com/tendermint/tendermint/types" + + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" + commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" +) + +var _ clientexported.Header = Header{} + +// Header defines the Tendermint consensus Header +type Header struct { + tmtypes.SignedHeader // contains the commitment root + ValidatorSet *tmtypes.ValidatorSet `json:"validator_set" yaml:"validator_set"` +} + +// ClientType defines that the Header is a Tendermint consensus algorithm +func (h Header) ClientType() clientexported.ClientType { + return clientexported.Tendermint +} + +// ConsensusState returns the consensus state associated with the header +func (h Header) ConsensusState() ConsensusState { + return ConsensusState{ + Height: uint64(h.Height), + Timestamp: h.Time, + Root: commitmenttypes.NewMerkleRoot(h.AppHash), + ValidatorSet: h.ValidatorSet, + } +} + +// GetHeight returns the current height +// +// NOTE: also referred as `sequence` +func (h Header) GetHeight() uint64 { + return uint64(h.Height) +} + +// ValidateBasic calls the SignedHeader ValidateBasic function +// and checks that validatorsets are not nil +func (h Header) ValidateBasic(chainID string) error { + if err := h.SignedHeader.ValidateBasic(chainID); err != nil { + return sdkerrors.Wrap(clienttypes.ErrInvalidHeader, err.Error()) + } + if h.ValidatorSet == nil { + return sdkerrors.Wrap(clienttypes.ErrInvalidHeader, "validator set is nil") + } + if !bytes.Equal(h.ValidatorsHash, h.ValidatorSet.Hash()) { + return sdkerrors.Wrap(clienttypes.ErrInvalidHeader, "validator set does not match hash") + } + return nil +} + +// ToABCIHeader parses the header to an ABCI header type. +// NOTE: only for testing use. +func (h Header) ToABCIHeader() abci.Header { + return tmtypes.TM2PB.Header(h.SignedHeader.Header) +} diff --git a/x/ibc/07-tendermint/types/header_test.go b/x/ibc/07-tendermint/types/header_test.go new file mode 100644 index 000000000000..c5c004028a7f --- /dev/null +++ b/x/ibc/07-tendermint/types/header_test.go @@ -0,0 +1,30 @@ +package types_test + +import ( + clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" +) + +func (suite *TendermintTestSuite) TestHeaderValidateBasic() { + testCases := []struct { + name string + header ibctmtypes.Header + chainID string + expPass bool + }{ + {"valid header", suite.header, chainID, true}, + {"signed header basic validation failed", suite.header, "chainID", false}, + {"validator set nil", ibctmtypes.Header{suite.header.SignedHeader, nil}, chainID, false}, + } + + suite.Require().Equal(clientexported.Tendermint, suite.header.ClientType()) + + for i, tc := range testCases { + tc := tc + if tc.expPass { + suite.Require().NoError(tc.header.ValidateBasic(tc.chainID), "valid test case %d failed: %s", i, tc.name) + } else { + suite.Require().Error(tc.header.ValidateBasic(tc.chainID), "invalid test case %d passed: %s", i, tc.name) + } + } +} diff --git a/x/ibc/07-tendermint/types/msgs.go b/x/ibc/07-tendermint/types/msgs.go new file mode 100644 index 000000000000..170c69d2e60a --- /dev/null +++ b/x/ibc/07-tendermint/types/msgs.go @@ -0,0 +1,217 @@ +package types + +import ( + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + evidenceexported "github.com/cosmos/cosmos-sdk/x/evidence/exported" + evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" + clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" + host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +// Message types for the IBC client +const ( + TypeMsgCreateClient string = "create_client" + TypeMsgUpdateClient string = "update_client" + TypeMsgSubmitClientMisbehaviour string = "submit_client_misbehaviour" +) + +var ( + _ clientexported.MsgCreateClient = MsgCreateClient{} + _ clientexported.MsgUpdateClient = MsgUpdateClient{} + _ evidenceexported.MsgSubmitEvidence = MsgSubmitClientMisbehaviour{} +) + +// MsgCreateClient defines a message to create an IBC client +type MsgCreateClient struct { + ClientID string `json:"client_id" yaml:"client_id"` + Header Header `json:"header" yaml:"header"` + TrustingPeriod time.Duration `json:"trusting_period" yaml:"trusting_period"` + UnbondingPeriod time.Duration `json:"unbonding_period" yaml:"unbonding_period"` + Signer sdk.AccAddress `json:"address" yaml:"address"` +} + +// NewMsgCreateClient creates a new MsgCreateClient instance +func NewMsgCreateClient( + id string, header Header, + trustingPeriod, unbondingPeriod time.Duration, signer sdk.AccAddress, +) MsgCreateClient { + return MsgCreateClient{ + ClientID: id, + Header: header, + TrustingPeriod: trustingPeriod, + UnbondingPeriod: unbondingPeriod, + Signer: signer, + } +} + +// Route implements sdk.Msg +func (msg MsgCreateClient) Route() string { + return ibctypes.RouterKey +} + +// Type implements sdk.Msg +func (msg MsgCreateClient) Type() string { + return TypeMsgCreateClient +} + +// ValidateBasic implements sdk.Msg +func (msg MsgCreateClient) ValidateBasic() error { + if msg.TrustingPeriod == 0 { + return sdkerrors.Wrap(ErrInvalidTrustingPeriod, "duration cannot be 0") + } + if msg.UnbondingPeriod == 0 { + return sdkerrors.Wrap(ErrInvalidUnbondingPeriod, "duration cannot be 0") + } + if msg.Signer.Empty() { + return sdkerrors.ErrInvalidAddress + } + // ValidateBasic of provided header with self-attested chain-id + if err := msg.Header.ValidateBasic(msg.Header.ChainID); err != nil { + return sdkerrors.Wrapf(ErrInvalidHeader, "header failed validatebasic with its own chain-id: %v", err) + } + return host.DefaultClientIdentifierValidator(msg.ClientID) +} + +// GetSignBytes implements sdk.Msg +func (msg MsgCreateClient) GetSignBytes() []byte { + return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg)) +} + +// GetSigners implements sdk.Msg +func (msg MsgCreateClient) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} + +// GetClientID implements clientexported.MsgCreateClient +func (msg MsgCreateClient) GetClientID() string { + return msg.ClientID +} + +// GetClientType implements clientexported.MsgCreateClient +func (msg MsgCreateClient) GetClientType() string { + return clientexported.ClientTypeTendermint +} + +// GetConsensusState implements clientexported.MsgCreateClient +func (msg MsgCreateClient) GetConsensusState() clientexported.ConsensusState { + // Construct initial consensus state from provided Header + root := commitmenttypes.NewMerkleRoot(msg.Header.AppHash) + return ConsensusState{ + Timestamp: msg.Header.Time, + Root: root, + Height: uint64(msg.Header.Height), + ValidatorSet: msg.Header.ValidatorSet, + } +} + +// MsgUpdateClient defines a message to update an IBC client +type MsgUpdateClient struct { + ClientID string `json:"client_id" yaml:"client_id"` + Header Header `json:"header" yaml:"header"` + Signer sdk.AccAddress `json:"address" yaml:"address"` +} + +// NewMsgUpdateClient creates a new MsgUpdateClient instance +func NewMsgUpdateClient(id string, header Header, signer sdk.AccAddress) MsgUpdateClient { + return MsgUpdateClient{ + ClientID: id, + Header: header, + Signer: signer, + } +} + +// Route implements sdk.Msg +func (msg MsgUpdateClient) Route() string { + return ibctypes.RouterKey +} + +// Type implements sdk.Msg +func (msg MsgUpdateClient) Type() string { + return TypeMsgUpdateClient +} + +// ValidateBasic implements sdk.Msg +func (msg MsgUpdateClient) ValidateBasic() error { + if msg.Signer.Empty() { + return sdkerrors.ErrInvalidAddress + } + return host.DefaultClientIdentifierValidator(msg.ClientID) +} + +// GetSignBytes implements sdk.Msg +func (msg MsgUpdateClient) GetSignBytes() []byte { + return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg)) +} + +// GetSigners implements sdk.Msg +func (msg MsgUpdateClient) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} + +// GetClientID implements clientexported.MsgUpdateClient +func (msg MsgUpdateClient) GetClientID() string { + return msg.ClientID +} + +// GetHeader implements clientexported.MsgUpdateClient +func (msg MsgUpdateClient) GetHeader() clientexported.Header { + return msg.Header +} + +// MsgSubmitClientMisbehaviour defines an sdk.Msg type that supports submitting +// Evidence for client misbehaviour. +type MsgSubmitClientMisbehaviour struct { + Evidence evidenceexported.Evidence `json:"evidence" yaml:"evidence"` + Submitter sdk.AccAddress `json:"submitter" yaml:"submitter"` +} + +// NewMsgSubmitClientMisbehaviour creates a new MsgSubmitClientMisbehaviour +// instance. +func NewMsgSubmitClientMisbehaviour(e evidenceexported.Evidence, s sdk.AccAddress) MsgSubmitClientMisbehaviour { + return MsgSubmitClientMisbehaviour{Evidence: e, Submitter: s} +} + +// Route returns the MsgSubmitClientMisbehaviour's route. +func (msg MsgSubmitClientMisbehaviour) Route() string { return ibctypes.RouterKey } + +// Type returns the MsgSubmitClientMisbehaviour's type. +func (msg MsgSubmitClientMisbehaviour) Type() string { return TypeMsgSubmitClientMisbehaviour } + +// ValidateBasic performs basic (non-state-dependant) validation on a MsgSubmitClientMisbehaviour. +func (msg MsgSubmitClientMisbehaviour) ValidateBasic() error { + if msg.Evidence == nil { + return sdkerrors.Wrap(evidencetypes.ErrInvalidEvidence, "missing evidence") + } + if err := msg.Evidence.ValidateBasic(); err != nil { + return err + } + if msg.Submitter.Empty() { + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Submitter.String()) + } + + return nil +} + +// GetSignBytes returns the raw bytes a signer is expected to sign when submitting +// a MsgSubmitClientMisbehaviour message. +func (msg MsgSubmitClientMisbehaviour) GetSignBytes() []byte { + return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg)) +} + +// GetSigners returns the single expected signer for a MsgSubmitClientMisbehaviour. +func (msg MsgSubmitClientMisbehaviour) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Submitter} +} + +func (msg MsgSubmitClientMisbehaviour) GetEvidence() evidenceexported.Evidence { + return msg.Evidence +} + +func (msg MsgSubmitClientMisbehaviour) GetSubmitter() sdk.AccAddress { + return msg.Submitter +} diff --git a/x/ibc/07-tendermint/types/msgs_test.go b/x/ibc/07-tendermint/types/msgs_test.go new file mode 100644 index 000000000000..d00561d99d26 --- /dev/null +++ b/x/ibc/07-tendermint/types/msgs_test.go @@ -0,0 +1,62 @@ +package types_test + +import ( + "github.com/tendermint/tendermint/crypto/secp256k1" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" +) + +func (suite *TendermintTestSuite) TestMsgCreateClientValidateBasic() { + privKey := secp256k1.GenPrivKey() + signer := sdk.AccAddress(privKey.PubKey().Address()) + + cases := []struct { + msg ibctmtypes.MsgCreateClient + expPass bool + errMsg string + }{ + {ibctmtypes.NewMsgCreateClient(exported.ClientTypeTendermint, suite.header, trustingPeriod, ubdPeriod, signer), true, "success msg should pass"}, + {ibctmtypes.NewMsgCreateClient("BADCHAIN", suite.header, trustingPeriod, ubdPeriod, signer), false, "invalid client id passed"}, + {ibctmtypes.NewMsgCreateClient("goodchain", suite.header, trustingPeriod, ubdPeriod, signer), false, "unregistered client type passed"}, + {ibctmtypes.NewMsgCreateClient("goodchain", suite.header, trustingPeriod, ubdPeriod, signer), false, "invalid Consensus State in msg passed"}, + {ibctmtypes.NewMsgCreateClient("goodchain", suite.header, 0, ubdPeriod, signer), false, "zero trusting period passed"}, + {ibctmtypes.NewMsgCreateClient("goodchain", suite.header, trustingPeriod, 0, signer), false, "zero unbonding period passed"}, + {ibctmtypes.NewMsgCreateClient("goodchain", suite.header, trustingPeriod, ubdPeriod, nil), false, "Empty address passed"}, + {ibctmtypes.NewMsgCreateClient("goodchain", suite.header, trustingPeriod, ubdPeriod, nil), false, "Empty chain ID"}, + } + + for i, tc := range cases { + err := tc.msg.ValidateBasic() + if tc.expPass { + suite.Require().NoError(err, "Msg %d failed: %v", i, err) + } else { + suite.Require().Error(err, "Invalid Msg %d passed: %s", i, tc.errMsg) + } + } +} + +func (suite *TendermintTestSuite) TestMsgUpdateClient() { + privKey := secp256k1.GenPrivKey() + signer := sdk.AccAddress(privKey.PubKey().Address()) + + cases := []struct { + msg ibctmtypes.MsgUpdateClient + expPass bool + errMsg string + }{ + {ibctmtypes.NewMsgUpdateClient(exported.ClientTypeTendermint, ibctmtypes.Header{}, signer), true, "success msg should pass"}, + {ibctmtypes.NewMsgUpdateClient("badClient", ibctmtypes.Header{}, signer), false, "invalid client id passed"}, + {ibctmtypes.NewMsgUpdateClient(exported.ClientTypeTendermint, ibctmtypes.Header{}, nil), false, "Empty address passed"}, + } + + for i, tc := range cases { + err := tc.msg.ValidateBasic() + if tc.expPass { + suite.Require().NoError(err, "Msg %d failed: %v", i, err) + } else { + suite.Require().Error(err, "Invalid Msg %d passed: %s", i, tc.errMsg) + } + } +} diff --git a/x/ibc/07-tendermint/types/tendermint_test.go b/x/ibc/07-tendermint/types/tendermint_test.go new file mode 100644 index 000000000000..d12c3fd1f95b --- /dev/null +++ b/x/ibc/07-tendermint/types/tendermint_test.go @@ -0,0 +1,48 @@ +package types_test + +import ( + "testing" + "time" + + "github.com/stretchr/testify/suite" + + tmtypes "github.com/tendermint/tendermint/types" + + "github.com/cosmos/cosmos-sdk/codec" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" + commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" +) + +const ( + chainID = "gaia" + height = 4 + trustingPeriod time.Duration = time.Hour * 24 * 7 * 2 + ubdPeriod time.Duration = time.Hour * 24 * 7 * 3 +) + +type TendermintTestSuite struct { + suite.Suite + + cdc *codec.Codec + privVal tmtypes.PrivValidator + valSet *tmtypes.ValidatorSet + header ibctmtypes.Header + now time.Time +} + +func (suite *TendermintTestSuite) SetupTest() { + suite.cdc = codec.New() + codec.RegisterCrypto(suite.cdc) + ibctmtypes.RegisterCodec(suite.cdc) + commitmenttypes.RegisterCodec(suite.cdc) + + suite.now = time.Date(2020, 1, 2, 0, 0, 0, 0, time.UTC) + suite.privVal = tmtypes.NewMockPV() + val := tmtypes.NewValidator(suite.privVal.GetPubKey(), 10) + suite.valSet = tmtypes.NewValidatorSet([]*tmtypes.Validator{val}) + suite.header = ibctmtypes.CreateTestHeader(chainID, height, suite.now, suite.valSet, []tmtypes.PrivValidator{suite.privVal}) +} + +func TestTendermintTestSuite(t *testing.T) { + suite.Run(t, new(TendermintTestSuite)) +} diff --git a/x/ibc/07-tendermint/types/test_utils.go b/x/ibc/07-tendermint/types/test_utils.go new file mode 100644 index 000000000000..2a2491b14847 --- /dev/null +++ b/x/ibc/07-tendermint/types/test_utils.go @@ -0,0 +1,59 @@ +package types + +import ( + "math" + "time" + + "github.com/tendermint/tendermint/crypto/tmhash" + tmtypes "github.com/tendermint/tendermint/types" + "github.com/tendermint/tendermint/version" +) + +// Copied unimported test functions from tmtypes to use them here +func MakeBlockID(hash []byte, partSetSize int, partSetHash []byte) tmtypes.BlockID { + return tmtypes.BlockID{ + Hash: hash, + PartsHeader: tmtypes.PartSetHeader{ + Total: partSetSize, + Hash: partSetHash, + }, + } +} + +// CreateTestHeader creates a mock header for testing only. +func CreateTestHeader(chainID string, height int64, timestamp time.Time, valSet *tmtypes.ValidatorSet, signers []tmtypes.PrivValidator) Header { + vsetHash := valSet.Hash() + tmHeader := tmtypes.Header{ + Version: version.Consensus{Block: 2, App: 2}, + ChainID: chainID, + Height: height, + Time: timestamp, + LastBlockID: MakeBlockID(make([]byte, tmhash.Size), math.MaxInt64, make([]byte, tmhash.Size)), + LastCommitHash: tmhash.Sum([]byte("last_commit_hash")), + DataHash: tmhash.Sum([]byte("data_hash")), + ValidatorsHash: vsetHash, + NextValidatorsHash: vsetHash, + ConsensusHash: tmhash.Sum([]byte("consensus_hash")), + AppHash: tmhash.Sum([]byte("app_hash")), + LastResultsHash: tmhash.Sum([]byte("last_results_hash")), + EvidenceHash: tmhash.Sum([]byte("evidence_hash")), + ProposerAddress: valSet.Proposer.Address, + } + hhash := tmHeader.Hash() + blockID := MakeBlockID(hhash, 3, tmhash.Sum([]byte("part_set"))) + voteSet := tmtypes.NewVoteSet(chainID, height, 1, tmtypes.PrecommitType, valSet) + commit, err := tmtypes.MakeCommit(blockID, height, 1, voteSet, signers, timestamp) + if err != nil { + panic(err) + } + + signedHeader := tmtypes.SignedHeader{ + Header: &tmHeader, + Commit: commit, + } + + return Header{ + SignedHeader: signedHeader, + ValidatorSet: valSet, + } +} diff --git a/x/ibc/07-tendermint/update.go b/x/ibc/07-tendermint/update.go new file mode 100644 index 000000000000..4233e8934607 --- /dev/null +++ b/x/ibc/07-tendermint/update.go @@ -0,0 +1,107 @@ +package tendermint + +import ( + "errors" + "time" + + lite "github.com/tendermint/tendermint/lite2" + + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" + "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" + commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" +) + +// CheckValidityAndUpdateState checks if the provided header is valid and updates +// the consensus state if appropriate. It returns an error if: +// - the client or header provided are not parseable to tendermint types +// - the header is invalid +// - header height is lower than the latest client height +// - header valset commit verification fails +// +// Tendermint client validity checking uses the bisection algorithm described +// in the [Tendermint spec](https://github.com/tendermint/spec/blob/master/spec/consensus/light-client.md). +func CheckValidityAndUpdateState( + clientState clientexported.ClientState, header clientexported.Header, + currentTimestamp time.Time, +) (clientexported.ClientState, clientexported.ConsensusState, error) { + tmClientState, ok := clientState.(types.ClientState) + if !ok { + return nil, nil, sdkerrors.Wrap( + clienttypes.ErrInvalidClientType, "light client is not from Tendermint", + ) + } + + tmHeader, ok := header.(types.Header) + if !ok { + return nil, nil, sdkerrors.Wrap( + clienttypes.ErrInvalidHeader, "header is not from Tendermint", + ) + } + + if err := checkValidity(tmClientState, tmHeader, currentTimestamp); err != nil { + return nil, nil, err + } + + tmClientState, consensusState := update(tmClientState, tmHeader) + return tmClientState, consensusState, nil +} + +// checkValidity checks if the Tendermint header is valid. +// +// CONTRACT: assumes header.Height > consensusState.Height +func checkValidity( + clientState types.ClientState, header types.Header, currentTimestamp time.Time, +) error { + // assert trusting period has not yet passed + if currentTimestamp.Sub(clientState.GetLatestTimestamp()) >= clientState.TrustingPeriod { + return errors.New("trusting period since last client timestamp already passed") + } + + // assert header timestamp is not past the trusting period + if header.Time.Sub(clientState.GetLatestTimestamp()) >= clientState.TrustingPeriod { + return sdkerrors.Wrap( + clienttypes.ErrInvalidHeader, + "header blocktime is outside trusting period from last client timestamp", + ) + } + + // assert header timestamp is past latest clientstate timestamp + if header.Time.Unix() <= clientState.GetLatestTimestamp().Unix() { + return sdkerrors.Wrapf( + clienttypes.ErrInvalidHeader, + "header blocktime ≤ latest client state block time (%s ≤ %s)", + header.Time.String(), clientState.GetLatestTimestamp().String(), + ) + } + + // assert header height is newer than any we know + if header.GetHeight() <= clientState.GetLatestHeight() { + return sdkerrors.Wrapf( + clienttypes.ErrInvalidHeader, + "header height ≤ latest client state height (%d ≤ %d)", header.GetHeight(), clientState.GetLatestHeight(), + ) + } + + // Verify next header with the last header's validatorset as trusted validatorset + err := lite.Verify(clientState.GetChainID(), &clientState.LastHeader.SignedHeader, clientState.LastHeader.ValidatorSet, + &header.SignedHeader, header.ValidatorSet, clientState.TrustingPeriod, currentTimestamp, lite.DefaultTrustLevel) + if err != nil { + return sdkerrors.Wrap(clienttypes.ErrInvalidHeader, err.Error()) + } + return nil +} + +// update the consensus state from a new header +func update(clientState types.ClientState, header types.Header) (types.ClientState, types.ConsensusState) { + clientState.LastHeader = header + consensusState := types.ConsensusState{ + Height: uint64(header.Height), + Timestamp: header.Time, + Root: commitmenttypes.NewMerkleRoot(header.AppHash), + ValidatorSet: header.ValidatorSet, + } + + return clientState, consensusState +} diff --git a/x/ibc/07-tendermint/update_test.go b/x/ibc/07-tendermint/update_test.go new file mode 100644 index 000000000000..3cc190ece6f3 --- /dev/null +++ b/x/ibc/07-tendermint/update_test.go @@ -0,0 +1,158 @@ +package tendermint_test + +import ( + "bytes" + "time" + + tmtypes "github.com/tendermint/tendermint/types" + + tendermint "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" + commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" +) + +func (suite *TendermintTestSuite) TestCheckValidity() { + var ( + clientState ibctmtypes.ClientState + newHeader ibctmtypes.Header + currentTime time.Time + ) + + // Setup different validators and signers for testing different types of updates + altPrivVal := tmtypes.NewMockPV() + altVal := tmtypes.NewValidator(altPrivVal.GetPubKey(), height) + + // Create bothValSet with both suite validator and altVal. Would be valid update + bothValSet := tmtypes.NewValidatorSet(append(suite.valSet.Validators, altVal)) + // Create alternative validator set with only altVal, invalid update (too much change in valSet) + altValSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{altVal}) + + signers := []tmtypes.PrivValidator{suite.privVal} + // Create signer array and ensure it is in same order as bothValSet + var bothSigners []tmtypes.PrivValidator + if bytes.Compare(altPrivVal.GetPubKey().Address(), suite.privVal.GetPubKey().Address()) == -1 { + bothSigners = []tmtypes.PrivValidator{altPrivVal, suite.privVal} + } else { + bothSigners = []tmtypes.PrivValidator{suite.privVal, altPrivVal} + } + + altSigners := []tmtypes.PrivValidator{altPrivVal} + + testCases := []struct { + name string + setup func() + expPass bool + }{ + { + name: "successful update with next height and same validator set", + setup: func() { + clientState = ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header) + newHeader = ibctmtypes.CreateTestHeader(chainID, height+1, suite.headerTime, suite.valSet, signers) + currentTime = suite.now + }, + expPass: true, + }, + { + name: "successful update with future height and different validator set", + setup: func() { + clientState = ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header) + newHeader = ibctmtypes.CreateTestHeader(chainID, height+5, suite.headerTime, bothValSet, bothSigners) + currentTime = suite.now + }, + expPass: true, + }, + { + name: "unsuccessful update with next height: update header mismatches nextValSetHash", + setup: func() { + clientState = ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header) + newHeader = ibctmtypes.CreateTestHeader(chainID, height+1, suite.headerTime, bothValSet, bothSigners) + currentTime = suite.now + }, + expPass: false, + }, + { + name: "unsuccessful update with future height: too much change in validator set", + setup: func() { + clientState = ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header) + newHeader = ibctmtypes.CreateTestHeader(chainID, height+5, suite.headerTime, altValSet, altSigners) + currentTime = suite.now + }, + expPass: false, + }, + { + name: "unsuccessful update: trusting period has passed since last client timestamp", + setup: func() { + clientState = ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header) + newHeader = ibctmtypes.CreateTestHeader(chainID, height+1, suite.headerTime, suite.valSet, signers) + // make current time pass trusting period from last timestamp on clientstate + currentTime = suite.now.Add(ubdPeriod) + }, + expPass: false, + }, + { + name: "unsuccessful update: header timestamp is past current timestamp", + setup: func() { + clientState = ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header) + newHeader = ibctmtypes.CreateTestHeader(chainID, height+1, suite.now.Add(time.Minute), suite.valSet, signers) + currentTime = suite.now + }, + expPass: false, + }, + { + name: "unsuccessful update: header timestamp is not past last client timestamp", + setup: func() { + clientState = ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header) + newHeader = ibctmtypes.CreateTestHeader(chainID, height+1, suite.clientTime, suite.valSet, signers) + currentTime = suite.now + }, + expPass: false, + }, + { + name: "header basic validation failed", + setup: func() { + clientState = ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header) + newHeader = ibctmtypes.CreateTestHeader(chainID, height+1, suite.headerTime, suite.valSet, signers) + // cause new header to fail validatebasic by changing commit height to mismatch header height + newHeader.SignedHeader.Commit.Height = height - 1 + currentTime = suite.now + }, + expPass: false, + }, + { + name: "header height < latest client height", + setup: func() { + clientState = ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header) + // Make new header at height less than latest client state + newHeader = ibctmtypes.CreateTestHeader(chainID, height-1, suite.headerTime, suite.valSet, signers) + currentTime = suite.now + }, + + expPass: false, + }, + } + + for i, tc := range testCases { + tc := tc + // setup test + tc.setup() + + expectedConsensus := ibctmtypes.ConsensusState{ + Height: uint64(newHeader.Height), + Timestamp: newHeader.Time, + Root: commitmenttypes.NewMerkleRoot(newHeader.AppHash), + ValidatorSet: newHeader.ValidatorSet, + } + + clientState, consensusState, err := tendermint.CheckValidityAndUpdateState(clientState, newHeader, currentTime) + + if tc.expPass { + suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name) + suite.Require().Equal(newHeader.GetHeight(), clientState.GetLatestHeight(), "valid test case %d failed: %s", i, tc.name) + suite.Require().Equal(expectedConsensus, consensusState, "valid test case %d failed: %s", i, tc.name) + } else { + suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name) + suite.Require().Nil(clientState, "invalid test case %d passed: %s", i, tc.name) + suite.Require().Nil(consensusState, "invalid test case %d passed: %s", i, tc.name) + } + } +} diff --git a/x/ibc/20-transfer/alias.go b/x/ibc/20-transfer/alias.go new file mode 100644 index 000000000000..033d9b18611a --- /dev/null +++ b/x/ibc/20-transfer/alias.go @@ -0,0 +1,47 @@ +package transfer + +// nolint +// autogenerated code using github.com/rigelrozanski/multitool +// aliases generated for the following subdirectories: +// ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/keeper +// ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/types + +import ( + "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/keeper" + "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/types" +) + +const ( + DefaultPacketTimeout = keeper.DefaultPacketTimeout + AttributeKeyReceiver = types.AttributeKeyReceiver + ModuleName = types.ModuleName + StoreKey = types.StoreKey + RouterKey = types.RouterKey + QuerierRoute = types.QuerierRoute +) + +var ( + // functions aliases + NewKeeper = keeper.NewKeeper + RegisterCodec = types.RegisterCodec + GetEscrowAddress = types.GetEscrowAddress + GetDenomPrefix = types.GetDenomPrefix + GetModuleAccountName = types.GetModuleAccountName + NewMsgTransfer = types.NewMsgTransfer + + // variable aliases + ModuleCdc = types.ModuleCdc + AttributeValueCategory = types.AttributeValueCategory +) + +type ( + Keeper = keeper.Keeper + BankKeeper = types.BankKeeper + ChannelKeeper = types.ChannelKeeper + ClientKeeper = types.ClientKeeper + ConnectionKeeper = types.ConnectionKeeper + SupplyKeeper = types.SupplyKeeper + FungibleTokenPacketData = types.FungibleTokenPacketData + MsgTransfer = types.MsgTransfer + AckDataTransfer = types.AckDataTransfer +) diff --git a/x/ibc/20-transfer/client/cli/cli.go b/x/ibc/20-transfer/client/cli/cli.go new file mode 100644 index 000000000000..03b26c5cb2b6 --- /dev/null +++ b/x/ibc/20-transfer/client/cli/cli.go @@ -0,0 +1,36 @@ +package cli + +import ( + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/codec" +) + +// GetQueryCmd returns the query commands for IBC fungible token transfer +func GetQueryCmd(cdc *codec.Codec, queryRoute string) *cobra.Command { + ics20TransferQueryCmd := &cobra.Command{ + Use: "transfer", + Short: "IBC fungible token transfer query subcommands", + } + + ics20TransferQueryCmd.AddCommand(flags.GetCommands( + GetCmdQueryNextSequence(cdc, queryRoute), + )...) + + return ics20TransferQueryCmd +} + +// GetTxCmd returns the transaction commands for IBC fungible token transfer +func GetTxCmd(cdc *codec.Codec) *cobra.Command { + ics20TransferTxCmd := &cobra.Command{ + Use: "transfer", + Short: "IBC fungible token transfer transaction subcommands", + } + + ics20TransferTxCmd.AddCommand(flags.PostCommands( + GetTransferTxCmd(cdc), + )...) + + return ics20TransferTxCmd +} diff --git a/x/ibc/20-transfer/client/cli/query.go b/x/ibc/20-transfer/client/cli/query.go new file mode 100644 index 000000000000..6c431ea1ee12 --- /dev/null +++ b/x/ibc/20-transfer/client/cli/query.go @@ -0,0 +1,47 @@ +package cli + +import ( + "fmt" + "strings" + + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/version" + "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/client/utils" +) + +// GetCmdQueryNextSequence defines the command to query a next receive sequence +func GetCmdQueryNextSequence(cdc *codec.Codec, queryRoute string) *cobra.Command { + cmd := &cobra.Command{ + Use: "next-recv [port-id] [channel-id]", + Short: "Query a next receive sequence", + Long: strings.TrimSpace(fmt.Sprintf(`Query an IBC channel end + +Example: +$ %s query ibc channel next-recv [port-id] [channel-id] + `, version.ClientName), + ), + Example: fmt.Sprintf("%s query ibc channel next-recv [port-id] [channel-id]", version.ClientName), + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + portID := args[0] + channelID := args[1] + prove := viper.GetBool(flags.FlagProve) + + sequenceRes, err := utils.QueryNextSequenceRecv(cliCtx, portID, channelID, prove) + if err != nil { + return err + } + + return cliCtx.PrintOutput(sequenceRes) + }, + } + cmd.Flags().Bool(flags.FlagProve, true, "show proofs for the query results") + + return cmd +} diff --git a/x/ibc/20-transfer/client/cli/tx.go b/x/ibc/20-transfer/client/cli/tx.go new file mode 100644 index 000000000000..d249a881809b --- /dev/null +++ b/x/ibc/20-transfer/client/cli/tx.go @@ -0,0 +1,67 @@ +package cli + +import ( + "bufio" + "strconv" + + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + authclient "github.com/cosmos/cosmos-sdk/x/auth/client" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/types" +) + +// IBC transfer flags +var ( + FlagNode1 = "node1" + FlagNode2 = "node2" + FlagFrom1 = "from1" + FlagFrom2 = "from2" + FlagChainID2 = "chain-id2" + FlagSequence = "packet-sequence" + FlagTimeout = "timeout" +) + +// GetTransferTxCmd returns the command to create a NewMsgTransfer transaction +func GetTransferTxCmd(cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "transfer [src-port] [src-channel] [dest-height] [receiver] [amount]", + Short: "Transfer fungible token through IBC", + Args: cobra.ExactArgs(5), + RunE: func(cmd *cobra.Command, args []string) error { + inBuf := bufio.NewReader(cmd.InOrStdin()) + txBldr := authtypes.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) + cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc).WithBroadcastMode(flags.BroadcastBlock) + + sender := cliCtx.GetFromAddress() + srcPort := args[0] + srcChannel := args[1] + destHeight, err := strconv.Atoi(args[2]) + if err != nil { + return err + } + receiver, err := sdk.AccAddressFromBech32(args[3]) + if err != nil { + return err + } + + // parse coin trying to be sent + coins, err := sdk.ParseCoins(args[4]) + if err != nil { + return err + } + + msg := types.NewMsgTransfer(srcPort, srcChannel, uint64(destHeight), coins, sender, receiver) + if err := msg.ValidateBasic(); err != nil { + return err + } + + return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } + return cmd +} diff --git a/x/ibc/20-transfer/client/rest/query.go b/x/ibc/20-transfer/client/rest/query.go new file mode 100644 index 000000000000..4a18ee172b9d --- /dev/null +++ b/x/ibc/20-transfer/client/rest/query.go @@ -0,0 +1,51 @@ +package rest + +import ( + "fmt" + "net/http" + + "github.com/gorilla/mux" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/types/rest" + "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/client/utils" +) + +func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router) { + r.HandleFunc(fmt.Sprintf("/ibc/ports/{%s}/channels/{%s}/next-sequence-recv", RestPortID, RestChannelID), queryNextSequenceRecvHandlerFn(cliCtx)).Methods("GET") +} + +// queryNextSequenceRecvHandlerFn implements a next sequence receive querying route +// +// @Summary Query next sequence receive +// @Tags IBC +// @Produce json +// @Param port-id path string true "Port ID" +// @Param channel-id path string true "Channel ID" +// @Success 200 {object} QueryNextSequenceRecv "OK" +// @Failure 400 {object} rest.ErrorResponse "Invalid port id or channel id" +// @Failure 500 {object} rest.ErrorResponse "Internal Server Error" +// @Router /ibc/ports/{port-id}/channels/{channel-id}/next-sequence-recv [get] +func queryNextSequenceRecvHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + portID := vars[RestPortID] + channelID := vars[RestChannelID] + prove := rest.ParseQueryParamBool(r, flags.FlagProve) + + cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) + if !ok { + return + } + + sequenceRes, err := utils.QueryNextSequenceRecv(cliCtx, portID, channelID, prove) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + + cliCtx = cliCtx.WithHeight(int64(sequenceRes.ProofHeight)) + rest.PostProcessResponse(w, cliCtx, sequenceRes) + } +} diff --git a/x/ibc/20-transfer/client/rest/rest.go b/x/ibc/20-transfer/client/rest/rest.go new file mode 100644 index 000000000000..a49761f846d2 --- /dev/null +++ b/x/ibc/20-transfer/client/rest/rest.go @@ -0,0 +1,28 @@ +package rest + +import ( + "github.com/gorilla/mux" + + "github.com/cosmos/cosmos-sdk/client/context" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/rest" +) + +const ( + RestChannelID = "channel-id" + RestPortID = "port-id" +) + +// RegisterRoutes - Central function to define routes that get registered by the main application +func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router) { + registerQueryRoutes(cliCtx, r) + registerTxRoutes(cliCtx, r) +} + +// TransferTxReq defines the properties of a transfer tx request's body. +type TransferTxReq struct { + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + DestHeight uint64 `json:"dest_height" yaml:"dest_height"` + Amount sdk.Coins `json:"amount" yaml:"amount"` + Receiver sdk.AccAddress `json:"receiver" yaml:"receiver"` +} diff --git a/x/ibc/20-transfer/client/rest/tx.go b/x/ibc/20-transfer/client/rest/tx.go new file mode 100644 index 000000000000..554a0ae19b1e --- /dev/null +++ b/x/ibc/20-transfer/client/rest/tx.go @@ -0,0 +1,72 @@ +package rest + +import ( + "fmt" + "net/http" + + "github.com/gorilla/mux" + + "github.com/cosmos/cosmos-sdk/client/context" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/rest" + authclient "github.com/cosmos/cosmos-sdk/x/auth/client" + "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/types" +) + +func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router) { + r.HandleFunc(fmt.Sprintf("/ibc/ports/{%s}/channels/{%s}/transfer", RestPortID, RestChannelID), transferHandlerFn(cliCtx)).Methods("POST") +} + +// transferHandlerFn implements a transfer handler +// +// @Summary Transfer token +// @Tags IBC +// @Accept json +// @Produce json +// @Param port-id path string true "Port ID" +// @Param channel-id path string true "Channel ID" +// @Param body body rest.TransferTxReq true "Transfer token request body" +// @Success 200 {object} PostTransfer "OK" +// @Failure 400 {object} rest.ErrorResponse "Invalid port id or channel id" +// @Failure 500 {object} rest.ErrorResponse "Internal Server Error" +// @Router /ibc/ports/{port-id}/channels/{channel-id}/transfer [post] +func transferHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + portID := vars[RestPortID] + channelID := vars[RestChannelID] + + var req TransferTxReq + if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) { + return + } + + req.BaseReq = req.BaseReq.Sanitize() + if !req.BaseReq.ValidateBasic(w) { + return + } + + fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + // create the message + msg := types.NewMsgTransfer( + portID, + channelID, + req.DestHeight, + req.Amount, + fromAddr, + req.Receiver, + ) + + if err := msg.ValidateBasic(); err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) + } +} diff --git a/x/ibc/20-transfer/client/utils/utils.go b/x/ibc/20-transfer/client/utils/utils.go new file mode 100644 index 000000000000..b2fe98034b5a --- /dev/null +++ b/x/ibc/20-transfer/client/utils/utils.go @@ -0,0 +1,33 @@ +package utils + +import ( + "encoding/binary" + + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/client/context" + channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +// QueryNextSequenceRecv queries the store to get the next receive sequence and +// a merkle proof. +func QueryNextSequenceRecv( + cliCtx context.CLIContext, portID, channelID string, prove bool, +) (channeltypes.RecvResponse, error) { + req := abci.RequestQuery{ + Path: "store/ibc/key", + Data: ibctypes.KeyNextSequenceRecv(portID, channelID), + Prove: prove, + } + + res, err := cliCtx.QueryABCI(req) + if err != nil { + return channeltypes.RecvResponse{}, err + } + + sequence := binary.BigEndian.Uint64(res.Value) + sequenceRes := channeltypes.NewRecvResponse(portID, channelID, sequence, res.Proof, res.Height) + + return sequenceRes, nil +} diff --git a/x/ibc/20-transfer/genesis.go b/x/ibc/20-transfer/genesis.go new file mode 100644 index 000000000000..eefeedd812cd --- /dev/null +++ b/x/ibc/20-transfer/genesis.go @@ -0,0 +1,35 @@ +package transfer + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/types" +) + +// GenesisState is currently only used to ensure that the InitGenesis gets run +// by the module manager +type GenesisState struct { + Version string `json:"version,omitempty" yaml:"version,omitempty"` +} + +func DefaultGenesis() GenesisState { + return GenesisState{ + Version: types.Version, + } +} + +// InitGenesis sets distribution information for genesis +func InitGenesis(ctx sdk.Context, keeper Keeper) { + // transfer module binds to the transfer port on InitChain + // and claims the returned capability + err := keeper.BindPort(ctx, types.PortID) + if err != nil { + panic(fmt.Sprintf("could not claim port capability: %v", err)) + } + // check if the module account exists + moduleAcc := keeper.GetTransferAccount(ctx) + if moduleAcc == nil { + panic(fmt.Sprintf("%s module account has not been set", types.GetModuleAccountName())) + } +} diff --git a/x/ibc/20-transfer/handler.go b/x/ibc/20-transfer/handler.go new file mode 100644 index 000000000000..09935da0608b --- /dev/null +++ b/x/ibc/20-transfer/handler.go @@ -0,0 +1,97 @@ +package transfer + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" +) + +// NewHandler returns sdk.Handler for IBC token transfer module messages +func NewHandler(k Keeper) sdk.Handler { + return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { + switch msg := msg.(type) { + case MsgTransfer: + return handleMsgTransfer(ctx, k, msg) + default: + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized ICS-20 transfer message type: %T", msg) + } + } +} + +// See createOutgoingPacket in spec:https://github.com/cosmos/ics/tree/master/spec/ics-020-fungible-token-transfer#packet-relay +func handleMsgTransfer(ctx sdk.Context, k Keeper, msg MsgTransfer) (*sdk.Result, error) { + if err := k.SendTransfer( + ctx, msg.SourcePort, msg.SourceChannel, msg.DestHeight, msg.Amount, msg.Sender, msg.Receiver, + ); err != nil { + return nil, err + } + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, AttributeValueCategory), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender.String()), + sdk.NewAttribute(AttributeKeyReceiver, msg.Receiver.String()), + ), + ) + + return &sdk.Result{ + Events: ctx.EventManager().Events().ToABCIEvents(), + }, nil +} + +// See onRecvPacket in spec: https://github.com/cosmos/ics/tree/master/spec/ics-020-fungible-token-transfer#packet-relay +func handlePacketDataTransfer( + ctx sdk.Context, k Keeper, packet channeltypes.Packet, data FungibleTokenPacketData, +) (*sdk.Result, error) { + if err := k.ReceiveTransfer(ctx, packet, data); err != nil { + // NOTE (cwgoes): How do we want to handle this case? Maybe we should be more lenient, + // it's safe to leave the channel open I think. + + // TODO: handle packet receipt that due to an error (specify) + // the receiving chain couldn't process the transfer + + // source chain sent invalid packet, shutdown our channel end + if err := k.ChanCloseInit(ctx, packet.DestinationPort, packet.DestinationChannel); err != nil { + return nil, err + } + return nil, err + } + + acknowledgement := AckDataTransfer{} + if err := k.PacketExecuted(ctx, packet, acknowledgement.GetBytes()); err != nil { + return nil, err + } + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, AttributeValueCategory), + ), + ) + + return &sdk.Result{ + Events: ctx.EventManager().Events().ToABCIEvents(), + }, nil +} + +// See onTimeoutPacket in spec: https://github.com/cosmos/ics/tree/master/spec/ics-020-fungible-token-transfer#packet-relay +func handleTimeoutDataTransfer( + ctx sdk.Context, k Keeper, packet channeltypes.Packet, data FungibleTokenPacketData, +) (*sdk.Result, error) { + if err := k.TimeoutTransfer(ctx, packet, data); err != nil { + // This shouldn't happen, since we've already validated that we've sent the packet. + panic(err) + } + + if err := k.TimeoutExecuted(ctx, packet); err != nil { + // This shouldn't happen, since we've already validated that we've sent the packet. + // TODO: Figure out what happens if the capability authorisation changes. + panic(err) + } + + return &sdk.Result{ + Events: ctx.EventManager().Events().ToABCIEvents(), + }, nil +} diff --git a/x/ibc/20-transfer/handler_test.go b/x/ibc/20-transfer/handler_test.go new file mode 100644 index 000000000000..93097a06bfd6 --- /dev/null +++ b/x/ibc/20-transfer/handler_test.go @@ -0,0 +1,304 @@ +package transfer_test + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/suite" + abci "github.com/tendermint/tendermint/abci/types" + tmtypes "github.com/tendermint/tendermint/types" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/simapp" + sdk "github.com/cosmos/cosmos-sdk/types" + connectionexported "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported" + connectiontypes "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" + transfer "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer" + "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/types" + commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" + "github.com/cosmos/cosmos-sdk/x/staking" + "github.com/cosmos/cosmos-sdk/x/supply" +) + +// define constants used for testing +const ( + testClientIDA = "testclientida" + testClientIDB = "testclientidb" + + testConnection = "testconnection" + testPort1 = "bank" + testPort2 = "testportid" + testChannel1 = "firstchannel" + testChannel2 = "secondchannel" + + trustingPeriod time.Duration = time.Hour * 24 * 7 * 2 + ubdPeriod time.Duration = time.Hour * 24 * 7 * 3 +) + +// define variables used for testing +var ( + testAddr1 = sdk.AccAddress([]byte("testaddr1")) + testAddr2 = sdk.AccAddress([]byte("testaddr2")) + + testCoins, _ = sdk.ParseCoins("100atom") + testPrefixedCoins1, _ = sdk.ParseCoins(fmt.Sprintf("100%satom", types.GetDenomPrefix(testPort1, testChannel1))) + testPrefixedCoins2, _ = sdk.ParseCoins(fmt.Sprintf("100%satom", types.GetDenomPrefix(testPort2, testChannel2))) +) + +type HandlerTestSuite struct { + suite.Suite + + cdc *codec.Codec + + chainA *TestChain + chainB *TestChain +} + +func (suite *HandlerTestSuite) SetupTest() { + suite.chainA = NewTestChain(testClientIDA) + suite.chainB = NewTestChain(testClientIDB) + + suite.cdc = suite.chainA.App.Codec() +} + +func (suite *HandlerTestSuite) TestHandleMsgTransfer() { + handler := transfer.NewHandler(suite.chainA.App.TransferKeeper) + + // create channel capability from ibc scoped keeper and claim with transfer scoped keeper + capName := ibctypes.ChannelCapabilityPath(testPort1, testChannel1) + cap, err := suite.chainA.App.ScopedIBCKeeper.NewCapability(suite.chainA.GetContext(), capName) + suite.Require().Nil(err, "could not create capability") + err = suite.chainA.App.ScopedTransferKeeper.ClaimCapability(suite.chainA.GetContext(), cap, capName) + suite.Require().Nil(err, "transfer module could not claim capability") + + ctx := suite.chainA.GetContext() + msg := transfer.NewMsgTransfer(testPort1, testChannel1, 10, testPrefixedCoins2, testAddr1, testAddr2) + res, err := handler(ctx, msg) + suite.Require().Error(err) + suite.Require().Nil(res, "%+v", res) // channel does not exist + + // Setup channel from A to B + suite.chainA.CreateClient(suite.chainB) + suite.chainA.createConnection(testConnection, testConnection, testClientIDB, testClientIDA, connectionexported.OPEN) + suite.chainA.createChannel(testPort1, testChannel1, testPort2, testChannel2, channelexported.OPEN, channelexported.ORDERED, testConnection) + + res, err = handler(ctx, msg) + suite.Require().Error(err) + suite.Require().Nil(res, "%+v", res) // next send sequence not found + + nextSeqSend := uint64(1) + suite.chainA.App.IBCKeeper.ChannelKeeper.SetNextSequenceSend(ctx, testPort1, testChannel1, nextSeqSend) + res, err = handler(ctx, msg) + suite.Require().Error(err) + suite.Require().Nil(res, "%+v", res) // sender has insufficient coins + + _ = suite.chainA.App.BankKeeper.SetBalances(ctx, testAddr1, testCoins) + res, err = handler(ctx, msg) + suite.Require().NoError(err) + suite.Require().NotNil(res, "%+v", res) // successfully executed + + // test when the source is false + msg = transfer.NewMsgTransfer(testPort1, testChannel1, 10, testPrefixedCoins2, testAddr1, testAddr2) + _ = suite.chainA.App.BankKeeper.SetBalances(ctx, testAddr1, testPrefixedCoins2) + + res, err = handler(ctx, msg) + suite.Require().Error(err) + suite.Require().Nil(res, "%+v", res) // incorrect denom prefix + + msg = transfer.NewMsgTransfer(testPort1, testChannel1, 10, testPrefixedCoins1, testAddr1, testAddr2) + suite.chainA.App.SupplyKeeper.SetSupply(ctx, supply.NewSupply(testPrefixedCoins1)) + _ = suite.chainA.App.BankKeeper.SetBalances(ctx, testAddr1, testPrefixedCoins1) + + res, err = handler(ctx, msg) + suite.Require().NoError(err) + suite.Require().NotNil(res, "%+v", res) // successfully executed +} + +func TestHandlerTestSuite(t *testing.T) { + suite.Run(t, new(HandlerTestSuite)) +} + +type TestChain struct { + ClientID string + App *simapp.SimApp + Header ibctmtypes.Header + Vals *tmtypes.ValidatorSet + Signers []tmtypes.PrivValidator +} + +func NewTestChain(clientID string) *TestChain { + privVal := tmtypes.NewMockPV() + validator := tmtypes.NewValidator(privVal.GetPubKey(), 1) + valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator}) + signers := []tmtypes.PrivValidator{privVal} + now := time.Date(2020, 1, 2, 0, 0, 0, 0, time.UTC) + + header := ibctmtypes.CreateTestHeader(clientID, 1, now, valSet, signers) + + return &TestChain{ + ClientID: clientID, + App: simapp.Setup(false), + Header: header, + Vals: valSet, + Signers: signers, + } +} + +// Creates simple context for testing purposes +func (chain *TestChain) GetContext() sdk.Context { + return chain.App.BaseApp.NewContext(false, abci.Header{ChainID: chain.Header.ChainID, Height: chain.Header.Height}) +} + +// createClient will create a client for clientChain on targetChain +func (chain *TestChain) CreateClient(client *TestChain) error { + client.Header = nextHeader(client) + // Commit and create a new block on appTarget to get a fresh CommitID + client.App.Commit() + commitID := client.App.LastCommitID() + client.App.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: client.Header.Height, Time: client.Header.Time}}) + + // Set HistoricalInfo on client chain after Commit + ctxClient := client.GetContext() + validator := staking.NewValidator( + sdk.ValAddress(client.Vals.Validators[0].Address), client.Vals.Validators[0].PubKey, staking.Description{}, + ) + validator.Status = sdk.Bonded + validator.Tokens = sdk.NewInt(1000000) // get one voting power + validators := []staking.Validator{validator} + histInfo := staking.HistoricalInfo{ + Header: abci.Header{ + AppHash: commitID.Hash, + }, + Valset: validators, + } + client.App.StakingKeeper.SetHistoricalInfo(ctxClient, client.Header.Height, histInfo) + + // Create target ctx + ctxTarget := chain.GetContext() + + // create client + clientState, err := ibctmtypes.Initialize(client.ClientID, trustingPeriod, ubdPeriod, client.Header) + if err != nil { + return err + } + _, err = chain.App.IBCKeeper.ClientKeeper.CreateClient(ctxTarget, clientState, client.Header.ConsensusState()) + if err != nil { + return err + } + return nil + + // _, _, err := simapp.SignCheckDeliver( + // suite.T(), + // suite.cdc, + // suite.app.BaseApp, + // ctx.BlockHeader(), + // []sdk.Msg{clienttypes.NewMsgCreateClient(clientID, clientexported.ClientTypeTendermint, consState, accountAddress)}, + // []uint64{baseAccount.GetAccountNumber()}, + // []uint64{baseAccount.GetSequence()}, + // true, true, accountPrivKey, + // ) +} + +// nolint: unused +func (chain *TestChain) updateClient(client *TestChain) { + // Create target ctx + ctxTarget := chain.GetContext() + + // if clientState does not already exist, return without updating + _, found := chain.App.IBCKeeper.ClientKeeper.GetClientState( + ctxTarget, client.ClientID, + ) + if !found { + return + } + + // always commit when updateClient and begin a new block + client.App.Commit() + commitID := client.App.LastCommitID() + + client.Header = nextHeader(client) + client.App.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: client.Header.Height, Time: client.Header.Time}}) + + // Set HistoricalInfo on client chain after Commit + ctxClient := client.GetContext() + validator := staking.NewValidator( + sdk.ValAddress(client.Vals.Validators[0].Address), client.Vals.Validators[0].PubKey, staking.Description{}, + ) + validator.Status = sdk.Bonded + validator.Tokens = sdk.NewInt(1000000) + validators := []staking.Validator{validator} + histInfo := staking.HistoricalInfo{ + Header: abci.Header{ + AppHash: commitID.Hash, + }, + Valset: validators, + } + client.App.StakingKeeper.SetHistoricalInfo(ctxClient, client.Header.Height, histInfo) + + consensusState := ibctmtypes.ConsensusState{ + Height: uint64(client.Header.Height), + Timestamp: client.Header.Time, + Root: commitmenttypes.NewMerkleRoot(commitID.Hash), + ValidatorSet: client.Vals, + } + + chain.App.IBCKeeper.ClientKeeper.SetClientConsensusState( + ctxTarget, client.ClientID, uint64(client.Header.Height), consensusState, + ) + chain.App.IBCKeeper.ClientKeeper.SetClientState( + ctxTarget, ibctmtypes.NewClientState(client.ClientID, trustingPeriod, ubdPeriod, client.Header), + ) + + // _, _, err := simapp.SignCheckDeliver( + // suite.T(), + // suite.cdc, + // suite.app.BaseApp, + // ctx.BlockHeader(), + // []sdk.Msg{clienttypes.NewMsgUpdateClient(clientID, suite.header, accountAddress)}, + // []uint64{baseAccount.GetAccountNumber()}, + // []uint64{baseAccount.GetSequence()}, + // true, true, accountPrivKey, + // ) + // suite.Require().NoError(err) +} + +func (chain *TestChain) createConnection( + connID, counterpartyConnID, clientID, counterpartyClientID string, + state connectionexported.State, +) connectiontypes.ConnectionEnd { + counterparty := connectiontypes.NewCounterparty(counterpartyClientID, counterpartyConnID, chain.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix()) + connection := connectiontypes.ConnectionEnd{ + State: state, + ClientID: clientID, + Counterparty: counterparty, + Versions: connectiontypes.GetCompatibleVersions(), + } + ctx := chain.GetContext() + chain.App.IBCKeeper.ConnectionKeeper.SetConnection(ctx, connID, connection) + return connection +} + +// nolint: unused +func (chain *TestChain) createChannel( + portID, channelID, counterpartyPortID, counterpartyChannelID string, + state channelexported.State, order exported.Order, connectionID string, +) channeltypes.Channel { + counterparty := channeltypes.NewCounterparty(counterpartyPortID, counterpartyChannelID) + channel := channeltypes.NewChannel(state, order, counterparty, + []string{connectionID}, "1.0", + ) + ctx := chain.GetContext() + chain.App.IBCKeeper.ChannelKeeper.SetChannel(ctx, portID, channelID, channel) + return channel +} + +func nextHeader(chain *TestChain) ibctmtypes.Header { + return ibctmtypes.CreateTestHeader(chain.Header.ChainID, chain.Header.Height+1, + chain.Header.Time.Add(time.Minute), chain.Vals, chain.Signers) +} diff --git a/x/ibc/20-transfer/keeper/keeper.go b/x/ibc/20-transfer/keeper/keeper.go new file mode 100644 index 000000000000..ffc6550a47a9 --- /dev/null +++ b/x/ibc/20-transfer/keeper/keeper.go @@ -0,0 +1,105 @@ +package keeper + +import ( + "fmt" + + "github.com/tendermint/tendermint/libs/log" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/capability" + channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" + channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + porttypes "github.com/cosmos/cosmos-sdk/x/ibc/05-port/types" + "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/types" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" + supplyexported "github.com/cosmos/cosmos-sdk/x/supply/exported" +) + +// DefaultPacketTimeout is the default packet timeout relative to the current block height +const ( + DefaultPacketTimeout = 1000 // NOTE: in blocks +) + +// Keeper defines the IBC transfer keeper +type Keeper struct { + storeKey sdk.StoreKey + cdc *codec.Codec + + channelKeeper types.ChannelKeeper + portKeeper types.PortKeeper + bankKeeper types.BankKeeper + supplyKeeper types.SupplyKeeper + scopedKeeper capability.ScopedKeeper +} + +// NewKeeper creates a new IBC transfer Keeper instance +func NewKeeper( + cdc *codec.Codec, key sdk.StoreKey, + channelKeeper types.ChannelKeeper, portKeeper types.PortKeeper, + bankKeeper types.BankKeeper, supplyKeeper types.SupplyKeeper, + scopedKeeper capability.ScopedKeeper, +) Keeper { + + // ensure ibc transfer module account is set + if addr := supplyKeeper.GetModuleAddress(types.GetModuleAccountName()); addr == nil { + panic("the IBC transfer module account has not been set") + } + + return Keeper{ + storeKey: key, + cdc: cdc, + channelKeeper: channelKeeper, + portKeeper: portKeeper, + bankKeeper: bankKeeper, + supplyKeeper: supplyKeeper, + scopedKeeper: scopedKeeper, + } +} + +// Logger returns a module-specific logger. +func (k Keeper) Logger(ctx sdk.Context) log.Logger { + return ctx.Logger().With("module", fmt.Sprintf("x/%s/%s", ibctypes.ModuleName, types.ModuleName)) +} + +// GetTransferAccount returns the ICS20 - transfers ModuleAccount +func (k Keeper) GetTransferAccount(ctx sdk.Context) supplyexported.ModuleAccountI { + return k.supplyKeeper.GetModuleAccount(ctx, types.GetModuleAccountName()) +} + +// PacketExecuted defines a wrapper function for the channel Keeper's function +// in order to expose it to the ICS20 transfer handler. +func (k Keeper) PacketExecuted(ctx sdk.Context, packet channelexported.PacketI, acknowledgement []byte) error { + return k.channelKeeper.PacketExecuted(ctx, packet, acknowledgement) +} + +// ChanCloseInit defines a wrapper function for the channel Keeper's function +// in order to expose it to the ICS20 trasfer handler. +func (k Keeper) ChanCloseInit(ctx sdk.Context, portID, channelID string) error { + capName := ibctypes.ChannelCapabilityPath(portID, channelID) + chanCap, ok := k.scopedKeeper.GetCapability(ctx, capName) + if !ok { + return sdkerrors.Wrapf(channel.ErrChannelCapabilityNotFound, "could not retrieve channel capability at: %s", capName) + } + return k.channelKeeper.ChanCloseInit(ctx, portID, channelID, chanCap) +} + +// BindPort defines a wrapper function for the ort Keeper's function in +// order to expose it to module's InitGenesis function +func (k Keeper) BindPort(ctx sdk.Context, portID string) error { + cap := k.portKeeper.BindPort(ctx, portID) + return k.ClaimCapability(ctx, cap, porttypes.PortPath(portID)) +} + +// TimeoutExecuted defines a wrapper function for the channel Keeper's function +// in order to expose it to the ICS20 transfer handler. +func (k Keeper) TimeoutExecuted(ctx sdk.Context, packet channelexported.PacketI) error { + return k.channelKeeper.TimeoutExecuted(ctx, packet) +} + +// ClaimCapability allows the transfer module that can claim a capability that IBC module +// passes to it +func (k Keeper) ClaimCapability(ctx sdk.Context, cap *capability.Capability, name string) error { + return k.scopedKeeper.ClaimCapability(ctx, cap, name) +} diff --git a/x/ibc/20-transfer/keeper/keeper_test.go b/x/ibc/20-transfer/keeper/keeper_test.go new file mode 100644 index 000000000000..9ddbd3b2f385 --- /dev/null +++ b/x/ibc/20-transfer/keeper/keeper_test.go @@ -0,0 +1,276 @@ +package keeper_test + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/suite" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto" + tmtypes "github.com/tendermint/tendermint/types" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/simapp" + sdk "github.com/cosmos/cosmos-sdk/types" + connectionexported "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported" + connectiontypes "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" + "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/types" + commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" + "github.com/cosmos/cosmos-sdk/x/staking" +) + +// define constants used for testing +const ( + testClientIDA = "testclientIDA" + testClientIDB = "testClientIDb" + + testConnection = "testconnectionatob" + testPort1 = "bank" + testPort2 = "testportid" + testChannel1 = "firstchannel" + testChannel2 = "secondchannel" + + trustingPeriod time.Duration = time.Hour * 24 * 7 * 2 + ubdPeriod time.Duration = time.Hour * 24 * 7 * 3 +) + +// define variables used for testing +var ( + testAddr1 = sdk.AccAddress([]byte("testaddr1")) + testAddr2 = sdk.AccAddress([]byte("testaddr2")) + + testCoins, _ = sdk.ParseCoins("100atom") + prefixCoins = sdk.NewCoins(sdk.NewCoin("bank/firstchannel/atom", sdk.NewInt(100))) + prefixCoins2 = sdk.NewCoins(sdk.NewCoin("testportid/secondchannel/atom", sdk.NewInt(100))) +) + +type KeeperTestSuite struct { + suite.Suite + + cdc *codec.Codec + + chainA *TestChain + chainB *TestChain +} + +func (suite *KeeperTestSuite) SetupTest() { + suite.chainA = NewTestChain(testClientIDA) + suite.chainB = NewTestChain(testClientIDB) + + suite.cdc = suite.chainA.App.Codec() +} + +// nolint: unused +func (suite *KeeperTestSuite) queryProof(key []byte) (proof commitmenttypes.MerkleProof, height int64) { + res := suite.chainA.App.Query(abci.RequestQuery{ + Path: fmt.Sprintf("store/%s/key", ibctypes.StoreKey), + Data: key, + Prove: true, + }) + + height = res.Height + proof = commitmenttypes.MerkleProof{ + Proof: res.Proof, + } + + return +} + +func (suite *KeeperTestSuite) TestGetTransferAccount() { + expectedMaccName := types.GetModuleAccountName() + expectedMaccAddr := sdk.AccAddress(crypto.AddressHash([]byte(expectedMaccName))) + + macc := suite.chainA.App.TransferKeeper.GetTransferAccount(suite.chainA.GetContext()) + + suite.NotNil(macc) + suite.Equal(expectedMaccName, macc.GetName()) + suite.Equal(expectedMaccAddr, macc.GetAddress()) +} + +func TestKeeperTestSuite(t *testing.T) { + suite.Run(t, new(KeeperTestSuite)) +} + +type TestChain struct { + ClientID string + App *simapp.SimApp + Header ibctmtypes.Header + Vals *tmtypes.ValidatorSet + Signers []tmtypes.PrivValidator +} + +func NewTestChain(clientID string) *TestChain { + privVal := tmtypes.NewMockPV() + validator := tmtypes.NewValidator(privVal.GetPubKey(), 1) + valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator}) + signers := []tmtypes.PrivValidator{privVal} + now := time.Date(2020, 1, 2, 0, 0, 0, 0, time.UTC) + + header := ibctmtypes.CreateTestHeader(clientID, 1, now, valSet, signers) + + return &TestChain{ + ClientID: clientID, + App: simapp.Setup(false), + Header: header, + Vals: valSet, + Signers: signers, + } +} + +// Creates simple context for testing purposes +func (chain *TestChain) GetContext() sdk.Context { + return chain.App.BaseApp.NewContext(false, abci.Header{ChainID: chain.Header.ChainID, Height: chain.Header.Height}) +} + +// createClient will create a client for clientChain on targetChain +func (chain *TestChain) CreateClient(client *TestChain) error { + client.Header = nextHeader(client) + // Commit and create a new block on appTarget to get a fresh CommitID + client.App.Commit() + commitID := client.App.LastCommitID() + client.App.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: client.Header.Height, Time: client.Header.Time}}) + + // Set HistoricalInfo on client chain after Commit + ctxClient := client.GetContext() + validator := staking.NewValidator( + sdk.ValAddress(client.Vals.Validators[0].Address), client.Vals.Validators[0].PubKey, staking.Description{}, + ) + validator.Status = sdk.Bonded + validator.Tokens = sdk.NewInt(1000000) // get one voting power + validators := []staking.Validator{validator} + histInfo := staking.HistoricalInfo{ + Header: abci.Header{ + AppHash: commitID.Hash, + }, + Valset: validators, + } + client.App.StakingKeeper.SetHistoricalInfo(ctxClient, client.Header.Height, histInfo) + + // Create target ctx + ctxTarget := chain.GetContext() + + // create client + clientState, err := ibctmtypes.Initialize(client.ClientID, trustingPeriod, ubdPeriod, client.Header) + if err != nil { + return err + } + _, err = chain.App.IBCKeeper.ClientKeeper.CreateClient(ctxTarget, clientState, client.Header.ConsensusState()) + if err != nil { + return err + } + return nil + + // _, _, err := simapp.SignCheckDeliver( + // suite.T(), + // suite.cdc, + // suite.app.BaseApp, + // ctx.BlockHeader(), + // []sdk.Msg{clienttypes.NewMsgCreateClient(clientID, clientexported.ClientTypeTendermint, consState, accountAddress)}, + // []uint64{baseAccount.GetAccountNumber()}, + // []uint64{baseAccount.GetSequence()}, + // true, true, accountPrivKey, + // ) +} + +// nolint: unused +func (chain *TestChain) updateClient(client *TestChain) { + // Create target ctx + ctxTarget := chain.GetContext() + + // if clientState does not already exist, return without updating + _, found := chain.App.IBCKeeper.ClientKeeper.GetClientState( + ctxTarget, client.ClientID, + ) + if !found { + return + } + + // always commit when updateClient and begin a new block + client.App.Commit() + commitID := client.App.LastCommitID() + + client.Header = nextHeader(client) + client.App.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: client.Header.Height, Time: client.Header.Time}}) + + // Set HistoricalInfo on client chain after Commit + ctxClient := client.GetContext() + validator := staking.NewValidator( + sdk.ValAddress(client.Vals.Validators[0].Address), client.Vals.Validators[0].PubKey, staking.Description{}, + ) + validator.Status = sdk.Bonded + validator.Tokens = sdk.NewInt(1000000) + validators := []staking.Validator{validator} + histInfo := staking.HistoricalInfo{ + Header: abci.Header{ + AppHash: commitID.Hash, + }, + Valset: validators, + } + client.App.StakingKeeper.SetHistoricalInfo(ctxClient, client.Header.Height, histInfo) + + consensusState := ibctmtypes.ConsensusState{ + Height: uint64(client.Header.Height), + Timestamp: client.Header.Time, + Root: commitmenttypes.NewMerkleRoot(commitID.Hash), + ValidatorSet: client.Vals, + } + + chain.App.IBCKeeper.ClientKeeper.SetClientConsensusState( + ctxTarget, client.ClientID, uint64(client.Header.Height), consensusState, + ) + chain.App.IBCKeeper.ClientKeeper.SetClientState( + ctxTarget, ibctmtypes.NewClientState(client.ClientID, trustingPeriod, ubdPeriod, client.Header), + ) + + // _, _, err := simapp.SignCheckDeliver( + // suite.T(), + // suite.cdc, + // suite.app.BaseApp, + // ctx.BlockHeader(), + // []sdk.Msg{clienttypes.NewMsgUpdateClient(clientID, suite.header, accountAddress)}, + // []uint64{baseAccount.GetAccountNumber()}, + // []uint64{baseAccount.GetSequence()}, + // true, true, accountPrivKey, + // ) + // suite.Require().NoError(err) +} + +func (chain *TestChain) createConnection( + connID, counterpartyConnID, clientID, counterpartyClientID string, + state connectionexported.State, +) connectiontypes.ConnectionEnd { + counterparty := connectiontypes.NewCounterparty(counterpartyClientID, counterpartyConnID, chain.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix()) + connection := connectiontypes.ConnectionEnd{ + State: state, + ClientID: clientID, + Counterparty: counterparty, + Versions: connectiontypes.GetCompatibleVersions(), + } + ctx := chain.GetContext() + chain.App.IBCKeeper.ConnectionKeeper.SetConnection(ctx, connID, connection) + return connection +} + +func (chain *TestChain) createChannel( + portID, channelID, counterpartyPortID, counterpartyChannelID string, + state channelexported.State, order exported.Order, connectionID string, +) channeltypes.Channel { + counterparty := channeltypes.NewCounterparty(counterpartyPortID, counterpartyChannelID) + channel := channeltypes.NewChannel(state, order, counterparty, + []string{connectionID}, "1.0", + ) + ctx := chain.GetContext() + chain.App.IBCKeeper.ChannelKeeper.SetChannel(ctx, portID, channelID, channel) + return channel +} + +func nextHeader(chain *TestChain) ibctmtypes.Header { + return ibctmtypes.CreateTestHeader(chain.Header.ChainID, chain.Header.Height+1, + chain.Header.Time.Add(time.Minute), chain.Vals, chain.Signers) +} diff --git a/x/ibc/20-transfer/keeper/relay.go b/x/ibc/20-transfer/keeper/relay.go new file mode 100644 index 000000000000..cf7d8be4daad --- /dev/null +++ b/x/ibc/20-transfer/keeper/relay.go @@ -0,0 +1,228 @@ +package keeper + +import ( + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" + "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/types" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +// SendTransfer handles transfer sending logic. There are 2 possible cases: +// +// 1. Sender chain is the source chain of the coins (i.e where they were minted): the coins +// are transferred to an escrow address (i.e locked) on the sender chain and then +// transferred to the destination chain (i.e not the source chain) via a packet +// with the corresponding fungible token data. +// +// 2. Coins are not native from the sender chain (i.e tokens sent where transferred over +// through IBC already): the coins are burned and then a packet is sent to the +// source chain of the tokens. +func (k Keeper) SendTransfer( + ctx sdk.Context, + sourcePort, + sourceChannel string, + destHeight uint64, + amount sdk.Coins, + sender, + receiver sdk.AccAddress, +) error { + sourceChannelEnd, found := k.channelKeeper.GetChannel(ctx, sourcePort, sourceChannel) + if !found { + return sdkerrors.Wrap(channel.ErrChannelNotFound, sourceChannel) + } + + destinationPort := sourceChannelEnd.Counterparty.PortID + destinationChannel := sourceChannelEnd.Counterparty.ChannelID + + // get the next sequence + sequence, found := k.channelKeeper.GetNextSequenceSend(ctx, sourcePort, sourceChannel) + if !found { + return channel.ErrSequenceSendNotFound + } + + return k.createOutgoingPacket(ctx, sequence, sourcePort, sourceChannel, destinationPort, destinationChannel, destHeight, amount, sender, receiver) +} + +// ReceiveTransfer handles transfer receiving logic. +func (k Keeper) ReceiveTransfer(ctx sdk.Context, packet channel.Packet, data types.FungibleTokenPacketData) error { + return k.onRecvPacket(ctx, packet, data) +} + +// TimeoutTransfer handles transfer timeout logic. +func (k Keeper) TimeoutTransfer(ctx sdk.Context, packet channel.Packet, data types.FungibleTokenPacketData) error { + return k.onTimeoutPacket(ctx, packet, data) +} + +// See spec for this function: https://github.com/cosmos/ics/tree/master/spec/ics-020-fungible-token-transfer#packet-relay +func (k Keeper) createOutgoingPacket( + ctx sdk.Context, + seq uint64, + sourcePort, sourceChannel, + destinationPort, destinationChannel string, + destHeight uint64, + amount sdk.Coins, + sender, receiver sdk.AccAddress, +) error { + channelCap, ok := k.scopedKeeper.GetCapability(ctx, ibctypes.ChannelCapabilityPath(sourcePort, sourceChannel)) + if !ok { + return sdkerrors.Wrap(channel.ErrChannelCapabilityNotFound, "module does not own channel capability") + } + // NOTE: + // - Coins transferred from the destination chain should have their denomination + // prefixed with source port and channel IDs. + // - Coins transferred from the source chain can have their denomination + // clear from prefixes when transferred to the escrow account (i.e when they are + // locked) BUT MUST have the destination port and channel ID when constructing + // the packet data. + if len(amount) != 1 { + return sdkerrors.Wrapf(types.ErrOnlyOneDenomAllowed, "%d denoms included", len(amount)) + } + + prefix := types.GetDenomPrefix(destinationPort, destinationChannel) + source := strings.HasPrefix(amount[0].Denom, prefix) + + if source { + // clear the denomination from the prefix to send the coins to the escrow account + coins := make(sdk.Coins, len(amount)) + for i, coin := range amount { + if strings.HasPrefix(coin.Denom, prefix) { + coins[i] = sdk.NewCoin(coin.Denom[len(prefix):], coin.Amount) + } else { + coins[i] = coin + } + } + + // escrow tokens if the destination chain is the same as the sender's + escrowAddress := types.GetEscrowAddress(sourcePort, sourceChannel) + + // escrow source tokens. It fails if balance insufficient. + if err := k.bankKeeper.SendCoins( + ctx, sender, escrowAddress, coins, + ); err != nil { + return err + } + + } else { + // build the receiving denomination prefix if it's not present + prefix = types.GetDenomPrefix(sourcePort, sourceChannel) + for _, coin := range amount { + if !strings.HasPrefix(coin.Denom, prefix) { + return sdkerrors.Wrapf(types.ErrInvalidDenomForTransfer, "denom was: %s", coin.Denom) + } + } + + // transfer the coins to the module account and burn them + if err := k.supplyKeeper.SendCoinsFromAccountToModule( + ctx, sender, types.GetModuleAccountName(), amount, + ); err != nil { + return err + } + + // burn vouchers from the sender's balance if the source is from another chain + if err := k.supplyKeeper.BurnCoins( + ctx, types.GetModuleAccountName(), amount, + ); err != nil { + // NOTE: should not happen as the module account was + // retrieved on the step above and it has enough balace + // to burn. + return err + } + } + + packetData := types.NewFungibleTokenPacketData( + amount, sender, receiver, + ) + + packet := channel.NewPacket( + packetData.GetBytes(), + seq, + sourcePort, + sourceChannel, + destinationPort, + destinationChannel, + destHeight+DefaultPacketTimeout, + ) + + return k.channelKeeper.SendPacket(ctx, channelCap, packet) +} + +func (k Keeper) onRecvPacket(ctx sdk.Context, packet channel.Packet, data types.FungibleTokenPacketData) error { + // NOTE: packet data type already checked in handler.go + + if len(data.Amount) != 1 { + return sdkerrors.Wrapf(types.ErrOnlyOneDenomAllowed, "%d denoms included", len(data.Amount)) + } + + prefix := types.GetDenomPrefix(packet.GetDestPort(), packet.GetDestChannel()) + source := strings.HasPrefix(data.Amount[0].Denom, prefix) + + if source { + // mint new tokens if the source of the transfer is the same chain + if err := k.supplyKeeper.MintCoins( + ctx, types.GetModuleAccountName(), data.Amount, + ); err != nil { + return err + } + + // send to receiver + return k.supplyKeeper.SendCoinsFromModuleToAccount( + ctx, types.GetModuleAccountName(), data.Receiver, data.Amount, + ) + } + + // check the denom prefix + prefix = types.GetDenomPrefix(packet.GetSourcePort(), packet.GetSourceChannel()) + coins := make(sdk.Coins, len(data.Amount)) + for i, coin := range data.Amount { + if !strings.HasPrefix(coin.Denom, prefix) { + return sdkerrors.Wrapf( + sdkerrors.ErrInvalidCoins, + "%s doesn't contain the prefix '%s'", coin.Denom, prefix, + ) + } + coins[i] = sdk.NewCoin(coin.Denom[len(prefix):], coin.Amount) + } + + // unescrow tokens + escrowAddress := types.GetEscrowAddress(packet.GetDestPort(), packet.GetDestChannel()) + return k.bankKeeper.SendCoins(ctx, escrowAddress, data.Receiver, coins) +} + +func (k Keeper) onTimeoutPacket(ctx sdk.Context, packet channel.Packet, data types.FungibleTokenPacketData) error { + // NOTE: packet data type already checked in handler.go + + if len(data.Amount) != 1 { + return sdkerrors.Wrapf(types.ErrOnlyOneDenomAllowed, "%d denoms included", len(data.Amount)) + } + + // check the denom prefix + prefix := types.GetDenomPrefix(packet.GetSourcePort(), packet.GetSourceChannel()) + source := strings.HasPrefix(data.Amount[0].Denom, prefix) + + if source { + coins := make(sdk.Coins, len(data.Amount)) + for i, coin := range data.Amount { + coin := coin + if !strings.HasPrefix(coin.Denom, prefix) { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "%s doesn't contain the prefix '%s'", coin.Denom, prefix) + } + coins[i] = sdk.NewCoin(coin.Denom[len(prefix):], coin.Amount) + } + + // unescrow tokens back to sender + escrowAddress := types.GetEscrowAddress(packet.GetDestPort(), packet.GetDestChannel()) + return k.bankKeeper.SendCoins(ctx, escrowAddress, data.Sender, coins) + } + + // mint vouchers back to sender + if err := k.supplyKeeper.MintCoins( + ctx, types.GetModuleAccountName(), data.Amount, + ); err != nil { + return err + } + + return k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.GetModuleAccountName(), data.Sender, data.Amount) +} diff --git a/x/ibc/20-transfer/keeper/relay_test.go b/x/ibc/20-transfer/keeper/relay_test.go new file mode 100644 index 000000000000..df878f8fe629 --- /dev/null +++ b/x/ibc/20-transfer/keeper/relay_test.go @@ -0,0 +1,215 @@ +package keeper_test + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + connectionexported "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported" + channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" + "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/types" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" + "github.com/cosmos/cosmos-sdk/x/supply" +) + +func (suite *KeeperTestSuite) TestSendTransfer() { + testCoins2 := sdk.NewCoins(sdk.NewCoin("testportid/secondchannel/atom", sdk.NewInt(100))) + capName := ibctypes.ChannelCapabilityPath(testPort1, testChannel1) + + testCases := []struct { + msg string + amount sdk.Coins + malleate func() + isSourceChain bool + expPass bool + }{ + {"successful transfer from source chain", testCoins2, + func() { + suite.chainA.App.BankKeeper.AddCoins(suite.chainA.GetContext(), testAddr1, testCoins) + suite.chainA.CreateClient(suite.chainB) + suite.chainA.createConnection(testConnection, testConnection, testClientIDB, testClientIDA, connectionexported.OPEN) + suite.chainA.createChannel(testPort1, testChannel1, testPort2, testChannel2, channelexported.OPEN, channelexported.ORDERED, testConnection) + suite.chainA.App.IBCKeeper.ChannelKeeper.SetNextSequenceSend(suite.chainA.GetContext(), testPort1, testChannel1, 1) + }, true, true}, + {"successful transfer from external chain", prefixCoins, + func() { + suite.chainA.App.SupplyKeeper.SetSupply(suite.chainA.GetContext(), supply.NewSupply(prefixCoins)) + _, err := suite.chainA.App.BankKeeper.AddCoins(suite.chainA.GetContext(), testAddr1, prefixCoins) + suite.Require().NoError(err) + suite.chainA.CreateClient(suite.chainB) + suite.chainA.createConnection(testConnection, testConnection, testClientIDB, testClientIDA, connectionexported.OPEN) + suite.chainA.createChannel(testPort1, testChannel1, testPort2, testChannel2, channelexported.OPEN, channelexported.ORDERED, testConnection) + suite.chainA.App.IBCKeeper.ChannelKeeper.SetNextSequenceSend(suite.chainA.GetContext(), testPort1, testChannel1, 1) + }, false, true}, + {"source channel not found", testCoins, + func() {}, true, false}, + {"next seq send not found", testCoins, + func() { + suite.chainA.CreateClient(suite.chainB) + suite.chainA.createConnection(testConnection, testConnection, testClientIDB, testClientIDA, connectionexported.OPEN) + suite.chainA.createChannel(testPort1, testChannel1, testPort2, testChannel2, channelexported.OPEN, channelexported.ORDERED, testConnection) + }, true, false}, + // createOutgoingPacket tests + // - source chain + {"send coins failed", testCoins, + func() { + suite.chainA.CreateClient(suite.chainB) + suite.chainA.createConnection(testConnection, testConnection, testClientIDB, testClientIDA, connectionexported.OPEN) + suite.chainA.createChannel(testPort1, testChannel1, testPort2, testChannel2, channelexported.OPEN, channelexported.ORDERED, testConnection) + suite.chainA.App.IBCKeeper.ChannelKeeper.SetNextSequenceSend(suite.chainA.GetContext(), testPort1, testChannel1, 1) + }, true, false}, + // - receiving chain + {"send from module account failed", testCoins, + func() { + suite.chainA.CreateClient(suite.chainB) + suite.chainA.createConnection(testConnection, testConnection, testClientIDB, testClientIDA, connectionexported.OPEN) + suite.chainA.createChannel(testPort1, testChannel1, testPort2, testChannel2, channelexported.OPEN, channelexported.ORDERED, testConnection) + suite.chainA.App.IBCKeeper.ChannelKeeper.SetNextSequenceSend(suite.chainA.GetContext(), testPort1, testChannel1, 1) + }, false, false}, + {"channel capability not found", testCoins, + func() { + suite.chainA.App.BankKeeper.AddCoins(suite.chainA.GetContext(), testAddr1, testCoins) + suite.chainA.CreateClient(suite.chainB) + suite.chainA.createConnection(testConnection, testConnection, testClientIDB, testClientIDA, connectionexported.OPEN) + suite.chainA.createChannel(testPort1, testChannel1, testPort2, testChannel2, channelexported.OPEN, channelexported.ORDERED, testConnection) + suite.chainA.App.IBCKeeper.ChannelKeeper.SetNextSequenceSend(suite.chainA.GetContext(), testPort1, testChannel1, 1) + // Release channel capability + cap, _ := suite.chainA.App.ScopedTransferKeeper.GetCapability(suite.chainA.GetContext(), capName) + suite.chainA.App.ScopedTransferKeeper.ReleaseCapability(suite.chainA.GetContext(), cap) + }, true, false}, + } + + for i, tc := range testCases { + tc := tc + i := i + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + suite.SetupTest() // reset + + // create channel capability from ibc scoped keeper and claim with transfer scoped keeper + cap, err := suite.chainA.App.ScopedIBCKeeper.NewCapability(suite.chainA.GetContext(), capName) + suite.Require().Nil(err, "could not create capability") + err = suite.chainA.App.ScopedTransferKeeper.ClaimCapability(suite.chainA.GetContext(), cap, capName) + suite.Require().Nil(err, "transfer module could not claim capability") + + tc.malleate() + + err = suite.chainA.App.TransferKeeper.SendTransfer( + suite.chainA.GetContext(), testPort1, testChannel1, 100, tc.amount, testAddr1, testAddr2, + ) + + if tc.expPass { + suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg) + } else { + suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg) + } + }) + } +} + +func (suite *KeeperTestSuite) TestReceiveTransfer() { + data := types.NewFungibleTokenPacketData(prefixCoins2, testAddr1, testAddr2) + + testCases := []struct { + msg string + malleate func() + expPass bool + }{ + {"success receive from source chain", + func() {}, true}, + // onRecvPacket + // - source chain + {"no dest prefix on coin denom", + func() { + data.Amount = testCoins + }, false}, + {"mint failed", + func() { + data.Amount = prefixCoins2 + data.Amount[0].Amount = sdk.ZeroInt() + }, false}, + // - receiving chain + {"incorrect dest prefix on coin denom", + func() { + data.Amount = prefixCoins2 + }, false}, + {"success receive from external chain", + func() { + data.Amount = prefixCoins + escrow := types.GetEscrowAddress(testPort2, testChannel2) + _, err := suite.chainA.App.BankKeeper.AddCoins(suite.chainA.GetContext(), escrow, testCoins) + suite.Require().NoError(err) + }, true}, + } + + packet := channeltypes.NewPacket(data.GetBytes(), 1, testPort1, testChannel1, testPort2, testChannel2, 100) + + for i, tc := range testCases { + tc := tc + i := i + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + suite.SetupTest() // reset + tc.malleate() + + err := suite.chainA.App.TransferKeeper.ReceiveTransfer(suite.chainA.GetContext(), packet, data) + + if tc.expPass { + suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg) + } else { + suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg) + } + }) + } +} + +func (suite *KeeperTestSuite) TestTimeoutTransfer() { + data := types.NewFungibleTokenPacketData(prefixCoins, testAddr1, testAddr2) + testCoins2 := sdk.NewCoins(sdk.NewCoin("testportid/secondchannel/atom", sdk.NewInt(100))) + + testCases := []struct { + msg string + malleate func() + expPass bool + }{ + {"successful timeout from source chain", + func() { + escrow := types.GetEscrowAddress(testPort2, testChannel2) + _, err := suite.chainA.App.BankKeeper.AddCoins(suite.chainA.GetContext(), escrow, sdk.NewCoins(sdk.NewCoin("atom", sdk.NewInt(100)))) + suite.Require().NoError(err) + }, true}, + {"successful timeout from external chain", + func() { + data.Amount = testCoins2 + }, true}, + {"no source prefix on coin denom", + func() { + data.Amount = prefixCoins2 + }, false}, + {"unescrow failed", + func() { + }, false}, + {"mint failed", + func() { + data.Amount[0].Denom = prefixCoins[0].Denom + data.Amount[0].Amount = sdk.ZeroInt() + }, false}, + } + + packet := channeltypes.NewPacket(data.GetBytes(), 1, testPort1, testChannel1, testPort2, testChannel2, 100) + + for i, tc := range testCases { + tc := tc + i := i + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + suite.SetupTest() // reset + tc.malleate() + + err := suite.chainA.App.TransferKeeper.TimeoutTransfer(suite.chainA.GetContext(), packet, data) + + if tc.expPass { + suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg) + } else { + suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg) + } + }) + } +} diff --git a/x/ibc/20-transfer/module.go b/x/ibc/20-transfer/module.go new file mode 100644 index 000000000000..83f3d0260eda --- /dev/null +++ b/x/ibc/20-transfer/module.go @@ -0,0 +1,261 @@ +package transfer + +import ( + "encoding/json" + + "github.com/gorilla/mux" + "github.com/spf13/cobra" + + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/types/module" + "github.com/cosmos/cosmos-sdk/x/capability" + channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" + channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" + port "github.com/cosmos/cosmos-sdk/x/ibc/05-port" + porttypes "github.com/cosmos/cosmos-sdk/x/ibc/05-port/types" + "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/client/cli" + "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/client/rest" + "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/types" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +var ( + _ module.AppModule = AppModule{} + _ port.IBCModule = AppModule{} + _ module.AppModuleBasic = AppModuleBasic{} +) + +// AppModuleBasic is the 20-transfer appmodulebasic +type AppModuleBasic struct{} + +// Name implements AppModuleBasic interface +func (AppModuleBasic) Name() string { + return ModuleName +} + +// RegisterCodec implements AppModuleBasic interface +func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) { + RegisterCodec(cdc) +} + +// DefaultGenesis returns default genesis state as raw bytes for the ibc +// transfer module. +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { + return cdc.MustMarshalJSON(DefaultGenesis()) +} + +// ValidateGenesis performs genesis state validation for the ibc transfer module. +func (AppModuleBasic) ValidateGenesis(_ codec.JSONMarshaler, _ json.RawMessage) error { + return nil +} + +// RegisterRESTRoutes implements AppModuleBasic interface +func (AppModuleBasic) RegisterRESTRoutes(ctx context.CLIContext, rtr *mux.Router) { + rest.RegisterRoutes(ctx, rtr) +} + +// GetTxCmd implements AppModuleBasic interface +func (AppModuleBasic) GetTxCmd(cdc *codec.Codec) *cobra.Command { + return cli.GetTxCmd(cdc) +} + +// GetQueryCmd implements AppModuleBasic interface +func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command { + return cli.GetQueryCmd(cdc, QuerierRoute) +} + +// AppModule represents the AppModule for this module +type AppModule struct { + AppModuleBasic + keeper Keeper +} + +// NewAppModule creates a new 20-transfer module +func NewAppModule(k Keeper) AppModule { + return AppModule{ + keeper: k, + } +} + +// RegisterInvariants implements the AppModule interface +func (AppModule) RegisterInvariants(ir sdk.InvariantRegistry) { + // TODO +} + +// Route implements the AppModule interface +func (AppModule) Route() string { + return RouterKey +} + +// NewHandler implements the AppModule interface +func (am AppModule) NewHandler() sdk.Handler { + return NewHandler(am.keeper) +} + +// QuerierRoute implements the AppModule interface +func (AppModule) QuerierRoute() string { + return QuerierRoute +} + +// NewQuerierHandler implements the AppModule interface +func (am AppModule) NewQuerierHandler() sdk.Querier { + return nil +} + +// InitGenesis performs genesis initialization for the ibc transfer module. It returns +// no validator updates. +func (am AppModule) InitGenesis(ctx sdk.Context, _ codec.JSONMarshaler, _ json.RawMessage) []abci.ValidatorUpdate { + // check if the IBC transfer module account is set + InitGenesis(ctx, am.keeper) + return []abci.ValidatorUpdate{} +} + +func (am AppModule) ExportGenesis(ctx sdk.Context, _ codec.JSONMarshaler) json.RawMessage { + return nil +} + +// BeginBlock implements the AppModule interface +func (am AppModule) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) { + +} + +// EndBlock implements the AppModule interface +func (am AppModule) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) []abci.ValidatorUpdate { + return []abci.ValidatorUpdate{} +} + +// Implement IBCModule callbacks +func (am AppModule) OnChanOpenInit( + ctx sdk.Context, + order channelexported.Order, + connectionHops []string, + portID string, + channelID string, + chanCap *capability.Capability, + counterparty channeltypes.Counterparty, + version string, +) error { + // TODO: Enforce ordering, currently relayers use ORDERED channels + + if counterparty.PortID != types.PortID { + return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "counterparty has invalid portid. expected: %s, got %s", types.PortID, counterparty.PortID) + } + + if version != types.Version { + return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "invalid version: %s, expected %s", version, "ics20-1") + } + + // Claim channel capability passed back by IBC module + if err := am.keeper.ClaimCapability(ctx, chanCap, ibctypes.ChannelCapabilityPath(portID, channelID)); err != nil { + return sdkerrors.Wrap(channel.ErrChannelCapabilityNotFound, err.Error()) + } + + // TODO: escrow + return nil +} + +func (am AppModule) OnChanOpenTry( + ctx sdk.Context, + order channelexported.Order, + connectionHops []string, + portID, + channelID string, + chanCap *capability.Capability, + counterparty channeltypes.Counterparty, + version, + counterpartyVersion string, +) error { + // TODO: Enforce ordering, currently relayers use ORDERED channels + + if counterparty.PortID != types.PortID { + return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "counterparty has invalid portid. expected: %s, got %s", types.PortID, counterparty.PortID) + } + + if version != types.Version { + return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "invalid version: %s, expected %s", version, "ics20-1") + } + + if counterpartyVersion != types.Version { + return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "invalid counterparty version: %s, expected %s", counterpartyVersion, "ics20-1") + } + + // Claim channel capability passed back by IBC module + if err := am.keeper.ClaimCapability(ctx, chanCap, ibctypes.ChannelCapabilityPath(portID, channelID)); err != nil { + return sdkerrors.Wrap(channel.ErrChannelCapabilityNotFound, err.Error()) + } + + // TODO: escrow + return nil +} + +func (am AppModule) OnChanOpenAck( + ctx sdk.Context, + portID, + channelID string, + counterpartyVersion string, +) error { + if counterpartyVersion != types.Version { + return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "invalid counterparty version: %s, expected %s", counterpartyVersion, "ics20-1") + } + return nil +} + +func (am AppModule) OnChanOpenConfirm( + ctx sdk.Context, + portID, + channelID string, +) error { + return nil +} + +func (am AppModule) OnChanCloseInit( + ctx sdk.Context, + portID, + channelID string, +) error { + return nil +} + +func (am AppModule) OnChanCloseConfirm( + ctx sdk.Context, + portID, + channelID string, +) error { + return nil +} + +func (am AppModule) OnRecvPacket( + ctx sdk.Context, + packet channeltypes.Packet, +) (*sdk.Result, error) { + var data FungibleTokenPacketData + if err := types.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil { + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal ICS-20 transfer packet data: %s", err.Error()) + } + return handlePacketDataTransfer(ctx, am.keeper, packet, data) +} + +func (am AppModule) OnAcknowledgementPacket( + ctx sdk.Context, + packet channeltypes.Packet, + acknowledment []byte, +) (*sdk.Result, error) { + return nil, nil +} + +func (am AppModule) OnTimeoutPacket( + ctx sdk.Context, + packet channeltypes.Packet, +) (*sdk.Result, error) { + var data FungibleTokenPacketData + if err := types.ModuleCdc.UnmarshalBinaryBare(packet.GetData(), &data); err != nil { + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal ICS-20 transfer packet data: %s", err.Error()) + } + return handleTimeoutDataTransfer(ctx, am.keeper, packet, data) +} diff --git a/x/ibc/20-transfer/types/codec.go b/x/ibc/20-transfer/types/codec.go new file mode 100644 index 000000000000..80c1c767b978 --- /dev/null +++ b/x/ibc/20-transfer/types/codec.go @@ -0,0 +1,22 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" + channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" + commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" +) + +// ModuleCdc defines the IBC transfer codec. +var ModuleCdc = codec.New() + +// RegisterCodec registers the IBC transfer types +func RegisterCodec(cdc *codec.Codec) { + cdc.RegisterConcrete(MsgTransfer{}, "ibc/transfer/MsgTransfer", nil) + cdc.RegisterConcrete(FungibleTokenPacketData{}, "ibc/transfer/PacketDataTransfer", nil) +} + +func init() { + RegisterCodec(ModuleCdc) + channel.RegisterCodec(ModuleCdc) + commitmenttypes.RegisterCodec(ModuleCdc) +} diff --git a/x/ibc/20-transfer/types/errors.go b/x/ibc/20-transfer/types/errors.go new file mode 100644 index 000000000000..e46c023e4cb7 --- /dev/null +++ b/x/ibc/20-transfer/types/errors.go @@ -0,0 +1,12 @@ +package types + +import ( + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +// IBC channel sentinel errors +var ( + ErrInvalidPacketTimeout = sdkerrors.Register(ModuleName, 2, "invalid packet timeout") + ErrOnlyOneDenomAllowed = sdkerrors.Register(ModuleName, 3, "only one denom allowed") + ErrInvalidDenomForTransfer = sdkerrors.Register(ModuleName, 4, "invalid denomination for cross-chain transfer") +) diff --git a/x/ibc/20-transfer/types/events.go b/x/ibc/20-transfer/types/events.go new file mode 100644 index 000000000000..f233b49377ff --- /dev/null +++ b/x/ibc/20-transfer/types/events.go @@ -0,0 +1,17 @@ +package types + +import ( + "fmt" + + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +// IBC transfer events +const ( + AttributeKeyReceiver = "receiver" +) + +// IBC transfer events vars +var ( + AttributeValueCategory = fmt.Sprintf("%s_%s", ibctypes.ModuleName, ModuleName) +) diff --git a/x/ibc/20-transfer/types/expected_keepers.go b/x/ibc/20-transfer/types/expected_keepers.go new file mode 100644 index 000000000000..9e924ee8702d --- /dev/null +++ b/x/ibc/20-transfer/types/expected_keepers.go @@ -0,0 +1,51 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/capability" + clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" + channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" + channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + supplyexported "github.com/cosmos/cosmos-sdk/x/supply/exported" +) + +// BankKeeper defines the expected bank keeper +type BankKeeper interface { + SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error +} + +// ChannelKeeper defines the expected IBC channel keeper +type ChannelKeeper interface { + GetChannel(ctx sdk.Context, srcPort, srcChan string) (channel channel.Channel, found bool) + GetNextSequenceSend(ctx sdk.Context, portID, channelID string) (uint64, bool) + SendPacket(ctx sdk.Context, channelCap *capability.Capability, packet channelexported.PacketI) error + PacketExecuted(ctx sdk.Context, packet channelexported.PacketI, acknowledgement []byte) error + ChanCloseInit(ctx sdk.Context, portID, channelID string, chanCap *capability.Capability) error + TimeoutExecuted(ctx sdk.Context, packet channelexported.PacketI) error +} + +// ClientKeeper defines the expected IBC client keeper +type ClientKeeper interface { + GetClientConsensusState(ctx sdk.Context, clientID string) (connection clientexported.ConsensusState, found bool) +} + +// ConnectionKeeper defines the expected IBC connection keeper +type ConnectionKeeper interface { + GetConnection(ctx sdk.Context, connectionID string) (connection connection.ConnectionEnd, found bool) +} + +// PortKeeper defines the expected IBC port keeper +type PortKeeper interface { + BindPort(ctx sdk.Context, portID string) *capability.Capability +} + +// SupplyKeeper expected supply keeper +type SupplyKeeper interface { + GetModuleAddress(name string) sdk.AccAddress + GetModuleAccount(ctx sdk.Context, name string) supplyexported.ModuleAccountI + MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error + BurnCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error + SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error + SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error +} diff --git a/x/ibc/20-transfer/types/keys.go b/x/ibc/20-transfer/types/keys.go new file mode 100644 index 000000000000..28f36745d61d --- /dev/null +++ b/x/ibc/20-transfer/types/keys.go @@ -0,0 +1,50 @@ +package types + +import ( + "fmt" + + "github.com/tendermint/tendermint/crypto" + + sdk "github.com/cosmos/cosmos-sdk/types" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +const ( + // ModuleName defines the IBC transfer name + ModuleName = "transfer" + + // Version defines the current version the IBC tranfer + // module supports + Version = "ics20-1" + + // PortID that transfer module binds to + PortID = "transfer" + + // StoreKey is the store key string for IBC transfer + StoreKey = ModuleName + + // RouterKey is the message route for IBC transfer + RouterKey = ModuleName + + // QuerierRoute is the querier route for IBC transfer + QuerierRoute = ModuleName +) + +// GetEscrowAddress returns the escrow address for the specified channel +// +// CONTRACT: this assumes that there's only one bank bridge module that owns the +// port associated with the channel ID so that the address created is actually +// unique. +func GetEscrowAddress(portID, channelID string) sdk.AccAddress { + return sdk.AccAddress(crypto.AddressHash([]byte(portID + channelID))) +} + +// GetDenomPrefix returns the receiving denomination prefix +func GetDenomPrefix(portID, channelID string) string { + return fmt.Sprintf("%s/%s/", portID, channelID) +} + +// GetModuleAccountName returns the IBC transfer module account name for supply +func GetModuleAccountName() string { + return fmt.Sprintf("%s/%s", ibctypes.ModuleName, ModuleName) +} diff --git a/x/ibc/20-transfer/types/msgs.go b/x/ibc/20-transfer/types/msgs.go new file mode 100644 index 000000000000..b7ae7cb7c764 --- /dev/null +++ b/x/ibc/20-transfer/types/msgs.go @@ -0,0 +1,75 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" +) + +// MsgTransfer defines a msg to transfer fungible tokens (i.e Coins) between ICS20 enabled chains. +// See ICS Spec here: https://github.com/cosmos/ics/tree/master/spec/ics-020-fungible-token-transfer#data-structures +type MsgTransfer struct { + SourcePort string `json:"source_port" yaml:"source_port"` // the port on which the packet will be sent + SourceChannel string `json:"source_channel" yaml:"source_channel"` // the channel by which the packet will be sent + DestHeight uint64 `json:"dest_height" yaml:"dest_height"` // the current height of the destination chain + Amount sdk.Coins `json:"amount" yaml:"amount"` // the tokens to be transferred + Sender sdk.AccAddress `json:"sender" yaml:"sender"` // the sender address + Receiver sdk.AccAddress `json:"receiver" yaml:"receiver"` // the recipient address on the destination chain +} + +// NewMsgTransfer creates a new MsgTransfer instance +func NewMsgTransfer( + sourcePort, sourceChannel string, destHeight uint64, amount sdk.Coins, sender, receiver sdk.AccAddress, +) MsgTransfer { + return MsgTransfer{ + SourcePort: sourcePort, + SourceChannel: sourceChannel, + DestHeight: destHeight, + Amount: amount, + Sender: sender, + Receiver: receiver, + } +} + +// Route implements sdk.Msg +func (MsgTransfer) Route() string { + return RouterKey +} + +// Type implements sdk.Msg +func (MsgTransfer) Type() string { + return "transfer" +} + +// ValidateBasic implements sdk.Msg +func (msg MsgTransfer) ValidateBasic() error { + if err := host.DefaultPortIdentifierValidator(msg.SourcePort); err != nil { + return sdkerrors.Wrap(err, "invalid source port ID") + } + if err := host.DefaultChannelIdentifierValidator(msg.SourceChannel); err != nil { + return sdkerrors.Wrap(err, "invalid source channel ID") + } + if !msg.Amount.IsAllPositive() { + return sdkerrors.ErrInsufficientFunds + } + if !msg.Amount.IsValid() { + return sdkerrors.ErrInvalidCoins + } + if msg.Sender.Empty() { + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "missing sender address") + } + if msg.Receiver.Empty() { + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "missing recipient address") + } + return nil +} + +// GetSignBytes implements sdk.Msg +func (msg MsgTransfer) GetSignBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(msg)) +} + +// GetSigners implements sdk.Msg +func (msg MsgTransfer) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Sender} +} diff --git a/x/ibc/20-transfer/types/msgs_test.go b/x/ibc/20-transfer/types/msgs_test.go new file mode 100644 index 000000000000..1b00732d4045 --- /dev/null +++ b/x/ibc/20-transfer/types/msgs_test.go @@ -0,0 +1,110 @@ +package types + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// define constants used for testing +const ( + validPort = "testportid" + invalidPort = "invalidport1" + invalidShortPort = "p" + invalidLongPort = "invalidlongportinvalidlongport" + + validChannel = "testchannel" + invalidChannel = "invalidchannel1" + invalidShortChannel = "invalidch" + invalidLongChannel = "invalidlongchannelinvalidlongchannel" +) + +var ( + addr1 = sdk.AccAddress("testaddr1") + addr2 = sdk.AccAddress("testaddr2") + emptyAddr sdk.AccAddress + + coins, _ = sdk.ParseCoins("100atom") + invalidDenomCoins = sdk.Coins{sdk.Coin{Denom: "ato-m", Amount: sdk.NewInt(100)}} + negativeCoins = sdk.Coins{sdk.Coin{Denom: "atom", Amount: sdk.NewInt(100)}, sdk.Coin{Denom: "atoms", Amount: sdk.NewInt(-100)}} +) + +// TestMsgTransferRoute tests Route for MsgTransfer +func TestMsgTransferRoute(t *testing.T) { + msg := NewMsgTransfer(validPort, validChannel, 10, coins, addr1, addr2) + + require.Equal(t, RouterKey, msg.Route()) +} + +// TestMsgTransferType tests Type for MsgTransfer +func TestMsgTransferType(t *testing.T) { + msg := NewMsgTransfer(validPort, validChannel, 10, coins, addr1, addr2) + + require.Equal(t, "transfer", msg.Type()) +} + +// TestMsgTransferValidation tests ValidateBasic for MsgTransfer +func TestMsgTransferValidation(t *testing.T) { + testMsgs := []MsgTransfer{ + NewMsgTransfer(validPort, validChannel, 10, coins, addr1, addr2), // valid msg + NewMsgTransfer(invalidShortPort, validChannel, 10, coins, addr1, addr2), // too short port id + NewMsgTransfer(invalidLongPort, validChannel, 10, coins, addr1, addr2), // too long port id + NewMsgTransfer(invalidPort, validChannel, 10, coins, addr1, addr2), // port id contains non-alpha + NewMsgTransfer(validPort, invalidShortChannel, 10, coins, addr1, addr2), // too short channel id + NewMsgTransfer(validPort, invalidLongChannel, 10, coins, addr1, addr2), // too long channel id + NewMsgTransfer(validPort, invalidChannel, 10, coins, addr1, addr2), // channel id contains non-alpha + NewMsgTransfer(validPort, validChannel, 10, invalidDenomCoins, addr1, addr2), // invalid amount + NewMsgTransfer(validPort, validChannel, 10, negativeCoins, addr1, addr2), // amount contains negative coin + NewMsgTransfer(validPort, validChannel, 10, coins, emptyAddr, addr2), // missing sender address + NewMsgTransfer(validPort, validChannel, 10, coins, addr1, emptyAddr), // missing recipient address + NewMsgTransfer(validPort, validChannel, 10, sdk.Coins{}, addr1, addr2), // not possitive coin + } + + testCases := []struct { + msg MsgTransfer + expPass bool + errMsg string + }{ + {testMsgs[0], true, ""}, + {testMsgs[1], false, "too short port id"}, + {testMsgs[2], false, "too long port id"}, + {testMsgs[3], false, "port id contains non-alpha"}, + {testMsgs[4], false, "too short channel id"}, + {testMsgs[5], false, "too long channel id"}, + {testMsgs[6], false, "channel id contains non-alpha"}, + {testMsgs[7], false, "invalid amount"}, + {testMsgs[8], false, "amount contains negative coin"}, + {testMsgs[9], false, "missing sender address"}, + {testMsgs[10], false, "missing recipient address"}, + } + + for i, tc := range testCases { + err := tc.msg.ValidateBasic() + if tc.expPass { + require.NoError(t, err, "Msg %d failed: %v", i, err) + } else { + require.Error(t, err, "Invalid Msg %d passed: %s", i, tc.errMsg) + } + } +} + +// TestMsgTransferGetSignBytes tests GetSignBytes for MsgTransfer +func TestMsgTransferGetSignBytes(t *testing.T) { + msg := NewMsgTransfer(validPort, validChannel, 10, coins, addr1, addr2) + res := msg.GetSignBytes() + + expected := `{"type":"ibc/transfer/MsgTransfer","value":{"amount":[{"amount":"100","denom":"atom"}],"dest_height":"10","receiver":"cosmos1w3jhxarpv3j8yvs7f9y7g","sender":"cosmos1w3jhxarpv3j8yvg4ufs4x","source_channel":"testchannel","source_port":"testportid"}}` + require.Equal(t, expected, string(res)) +} + +// TestMsgTransferGetSigners tests GetSigners for MsgTransfer +func TestMsgTransferGetSigners(t *testing.T) { + msg := NewMsgTransfer(validPort, validChannel, 10, coins, addr1, addr2) + res := msg.GetSigners() + + expected := "[746573746164647231]" + require.Equal(t, expected, fmt.Sprintf("%v", res)) +} diff --git a/x/ibc/20-transfer/types/packet.go b/x/ibc/20-transfer/types/packet.go new file mode 100644 index 000000000000..9cb6d1b8122e --- /dev/null +++ b/x/ibc/20-transfer/types/packet.go @@ -0,0 +1,69 @@ +package types + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +// FungibleTokenPacketData defines a struct for the packet payload +// See FungibleTokenPacketData spec: https://github.com/cosmos/ics/tree/master/spec/ics-020-fungible-token-transfer#data-structures +type FungibleTokenPacketData struct { + Amount sdk.Coins `json:"amount" yaml:"amount"` // the tokens to be transferred + Sender sdk.AccAddress `json:"sender" yaml:"sender"` // the sender address + Receiver sdk.AccAddress `json:"receiver" yaml:"receiver"` // the recipient address on the destination chain +} + +// NewFungibleTokenPacketData contructs a new FungibleTokenPacketData instance +func NewFungibleTokenPacketData( + amount sdk.Coins, sender, receiver sdk.AccAddress) FungibleTokenPacketData { + return FungibleTokenPacketData{ + Amount: amount, + Sender: sender, + Receiver: receiver, + } +} + +// String returns a string representation of FungibleTokenPacketData +func (ftpd FungibleTokenPacketData) String() string { + return fmt.Sprintf(`FungibleTokenPacketData: + Amount: %s + Sender: %s + Receiver: %s`, + ftpd.Amount.String(), + ftpd.Sender, + ftpd.Receiver, + ) +} + +// ValidateBasic is used for validating the token transfer +func (ftpd FungibleTokenPacketData) ValidateBasic() error { + if !ftpd.Amount.IsAllPositive() { + return sdkerrors.ErrInsufficientFunds + } + if !ftpd.Amount.IsValid() { + return sdkerrors.ErrInvalidCoins + } + if ftpd.Sender.Empty() { + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "missing sender address") + } + if ftpd.Receiver.Empty() { + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "missing receiver address") + } + return nil +} + +// GetBytes is a helper for serialising +func (ftpd FungibleTokenPacketData) GetBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(ftpd)) +} + +// AckDataTransfer is a no-op packet +// See spec for onAcknowledgePacket: https://github.com/cosmos/ics/tree/master/spec/ics-020-fungible-token-transfer#packet-relay +type AckDataTransfer struct{} + +// GetBytes is a helper for serialising +func (AckDataTransfer) GetBytes() []byte { + return []byte("fungible token transfer ack") +} diff --git a/x/ibc/20-transfer/types/packet_test.go b/x/ibc/20-transfer/types/packet_test.go new file mode 100644 index 000000000000..e2e4f2cc1600 --- /dev/null +++ b/x/ibc/20-transfer/types/packet_test.go @@ -0,0 +1,39 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +// TestFungibleTokenPacketDataValidateBasic tests ValidateBasic for FungibleTokenPacketData +func TestFungibleTokenPacketDataValidateBasic(t *testing.T) { + testPacketDataTransfer := []FungibleTokenPacketData{ + NewFungibleTokenPacketData(coins, addr1, addr2), // valid msg + NewFungibleTokenPacketData(invalidDenomCoins, addr1, addr2), // invalid amount + NewFungibleTokenPacketData(negativeCoins, addr1, addr2), // amount contains negative coin + NewFungibleTokenPacketData(coins, emptyAddr, addr2), // missing sender address + NewFungibleTokenPacketData(coins, addr1, emptyAddr), // missing recipient address + } + + testCases := []struct { + packetData FungibleTokenPacketData + expPass bool + errMsg string + }{ + {testPacketDataTransfer[0], true, ""}, + {testPacketDataTransfer[1], false, "invalid amount"}, + {testPacketDataTransfer[2], false, "amount contains negative coin"}, + {testPacketDataTransfer[3], false, "missing sender address"}, + {testPacketDataTransfer[4], false, "missing recipient address"}, + } + + for i, tc := range testCases { + err := tc.packetData.ValidateBasic() + if tc.expPass { + require.NoError(t, err, "PacketDataTransfer %d failed: %v", i, err) + } else { + require.Error(t, err, "Invalid PacketDataTransfer %d passed: %s", i, tc.errMsg) + } + } +} diff --git a/x/ibc/23-commitment/exported/exported.go b/x/ibc/23-commitment/exported/exported.go new file mode 100644 index 000000000000..c6fbbce3ada1 --- /dev/null +++ b/x/ibc/23-commitment/exported/exported.go @@ -0,0 +1,71 @@ +package exported + +// ICS 023 Types Implementation +// +// This file includes types defined under +// https://github.com/cosmos/ics/tree/master/spec/ics-023-vector-commitments + +// spec:Path and spec:Value are defined as bytestring + +// Root implements spec:CommitmentRoot. +// A root is constructed from a set of key-value pairs, +// and the inclusion or non-inclusion of an arbitrary key-value pair +// can be proven with the proof. +type Root interface { + GetCommitmentType() Type + GetHash() []byte + IsEmpty() bool +} + +// Prefix implements spec:CommitmentPrefix. +// Prefix represents the common "prefix" that a set of keys shares. +type Prefix interface { + GetCommitmentType() Type + Bytes() []byte + IsEmpty() bool +} + +// Path implements spec:CommitmentPath. +// A path is the additional information provided to the verification function. +type Path interface { + GetCommitmentType() Type + String() string + IsEmpty() bool +} + +// Proof implements spec:CommitmentProof. +// Proof can prove whether the key-value pair is a part of the Root or not. +// Each proof has designated key-value pair it is able to prove. +// Proofs includes key but value is provided dynamically at the verification time. +type Proof interface { + GetCommitmentType() Type + VerifyMembership(Root, Path, []byte) error + VerifyNonMembership(Root, Path) error + IsEmpty() bool + + ValidateBasic() error +} + +// Type defines the type of the commitment +type Type byte + +// Registered commitment types +const ( + Merkle Type = iota + 1 // 1 +) + +// string representation of the commitment types +const ( + TypeMerkle string = "merkle" +) + +// String implements the Stringer interface +func (ct Type) String() string { + switch ct { + case Merkle: + return TypeMerkle + + default: + return "" + } +} diff --git a/x/ibc/23-commitment/types/codec.go b/x/ibc/23-commitment/types/codec.go new file mode 100644 index 000000000000..e7e761867fc8 --- /dev/null +++ b/x/ibc/23-commitment/types/codec.go @@ -0,0 +1,27 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" +) + +var SubModuleCdc *codec.Codec + +// RegisterCodec registers types declared in this package +func RegisterCodec(cdc *codec.Codec) { + cdc.RegisterInterface((*exported.Root)(nil), nil) + cdc.RegisterInterface((*exported.Prefix)(nil), nil) + cdc.RegisterInterface((*exported.Path)(nil), nil) + cdc.RegisterInterface((*exported.Proof)(nil), nil) + + cdc.RegisterConcrete(MerkleRoot{}, "ibc/commitment/MerkleRoot", nil) + cdc.RegisterConcrete(MerklePrefix{}, "ibc/commitment/MerklePrefix", nil) + cdc.RegisterConcrete(MerklePath{}, "ibc/commitment/MerklePath", nil) + cdc.RegisterConcrete(MerkleProof{}, "ibc/commitment/MerkleProof", nil) + + SetSubModuleCodec(cdc) +} + +func SetSubModuleCodec(cdc *codec.Codec) { + SubModuleCdc = cdc +} diff --git a/x/ibc/23-commitment/types/commitment_test.go b/x/ibc/23-commitment/types/commitment_test.go new file mode 100644 index 000000000000..932599e539cd --- /dev/null +++ b/x/ibc/23-commitment/types/commitment_test.go @@ -0,0 +1,37 @@ +package types_test + +import ( + "testing" + + "github.com/stretchr/testify/suite" + + "github.com/cosmos/cosmos-sdk/store/iavl" + "github.com/cosmos/cosmos-sdk/store/rootmulti" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + + dbm "github.com/tendermint/tm-db" +) + +type MerkleTestSuite struct { + suite.Suite + + store *rootmulti.Store + storeKey *storetypes.KVStoreKey + iavlStore *iavl.Store +} + +func (suite *MerkleTestSuite) SetupTest() { + db := dbm.NewMemDB() + suite.store = rootmulti.NewStore(db) + + suite.storeKey = storetypes.NewKVStoreKey("iavlStoreKey") + + suite.store.MountStoreWithDB(suite.storeKey, storetypes.StoreTypeIAVL, nil) + suite.store.LoadVersion(0) + + suite.iavlStore = suite.store.GetCommitStore(suite.storeKey).(*iavl.Store) +} + +func TestMerkleTestSuite(t *testing.T) { + suite.Run(t, new(MerkleTestSuite)) +} diff --git a/x/ibc/23-commitment/types/errors.go b/x/ibc/23-commitment/types/errors.go new file mode 100644 index 000000000000..3b32f24643c0 --- /dev/null +++ b/x/ibc/23-commitment/types/errors.go @@ -0,0 +1,14 @@ +package types + +import ( + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +// SubModuleName is the error codespace +const SubModuleName string = "commitment" + +// IBC connection sentinel errors +var ( + ErrInvalidProof = sdkerrors.Register(SubModuleName, 1, "invalid proof") + ErrInvalidPrefix = sdkerrors.Register(SubModuleName, 2, "invalid prefix") +) diff --git a/x/ibc/23-commitment/types/merkle.go b/x/ibc/23-commitment/types/merkle.go new file mode 100644 index 000000000000..74f6353f339a --- /dev/null +++ b/x/ibc/23-commitment/types/merkle.go @@ -0,0 +1,187 @@ +package types + +import ( + "errors" + "net/url" + + "github.com/tendermint/tendermint/crypto/merkle" + + "github.com/cosmos/cosmos-sdk/store/rootmulti" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" + host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" +) + +// ICS 023 Merkle Types Implementation +// +// This file defines Merkle commitment types that implements ICS 023. + +// Merkle proof implementation of the Proof interface +// Applied on SDK-based IBC implementation +var _ exported.Root = MerkleRoot{} + +// MerkleRoot defines a merkle root hash. +// In the Cosmos SDK, the AppHash of a block header becomes the root. +type MerkleRoot struct { + Hash []byte `json:"hash" yaml:"hash"` +} + +// NewMerkleRoot constructs a new MerkleRoot +func NewMerkleRoot(hash []byte) MerkleRoot { + return MerkleRoot{ + Hash: hash, + } +} + +// GetCommitmentType implements RootI interface +func (MerkleRoot) GetCommitmentType() exported.Type { + return exported.Merkle +} + +// GetHash implements RootI interface +func (mr MerkleRoot) GetHash() []byte { + return mr.Hash +} + +// IsEmpty returns true if the root is empty +func (mr MerkleRoot) IsEmpty() bool { + return len(mr.GetHash()) == 0 +} + +var _ exported.Prefix = MerklePrefix{} + +// MerklePrefix is merkle path prefixed to the key. +// The constructed key from the Path and the key will be append(Path.KeyPath, append(Path.KeyPrefix, key...)) +type MerklePrefix struct { + KeyPrefix []byte `json:"key_prefix" yaml:"key_prefix"` // byte slice prefixed before the key +} + +// NewMerklePrefix constructs new MerklePrefix instance +func NewMerklePrefix(keyPrefix []byte) MerklePrefix { + return MerklePrefix{ + KeyPrefix: keyPrefix, + } +} + +// GetCommitmentType implements Prefix interface +func (MerklePrefix) GetCommitmentType() exported.Type { + return exported.Merkle +} + +// Bytes returns the key prefix bytes +func (mp MerklePrefix) Bytes() []byte { + return mp.KeyPrefix +} + +// IsEmpty returns true if the prefix is empty +func (mp MerklePrefix) IsEmpty() bool { + return len(mp.Bytes()) == 0 +} + +var _ exported.Path = MerklePath{} + +// MerklePath is the path used to verify commitment proofs, which can be an arbitrary +// structured object (defined by a commitment type). +type MerklePath struct { + KeyPath merkle.KeyPath `json:"key_path" yaml:"key_path"` // byte slice prefixed before the key +} + +// NewMerklePath creates a new MerklePath instance +func NewMerklePath(keyPathStr []string) MerklePath { + merkleKeyPath := merkle.KeyPath{} + for _, keyStr := range keyPathStr { + merkleKeyPath = merkleKeyPath.AppendKey([]byte(keyStr), merkle.KeyEncodingURL) + } + + return MerklePath{ + KeyPath: merkleKeyPath, + } +} + +// GetCommitmentType implements PathI +func (MerklePath) GetCommitmentType() exported.Type { + return exported.Merkle +} + +// String implements fmt.Stringer. +func (mp MerklePath) String() string { + return mp.KeyPath.String() +} + +// Pretty returns the unescaped path of the URL string. +func (mp MerklePath) Pretty() string { + path, err := url.PathUnescape(mp.KeyPath.String()) + if err != nil { + panic(err) + } + return path +} + +// IsEmpty returns true if the path is empty +func (mp MerklePath) IsEmpty() bool { + return len(mp.KeyPath) == 0 +} + +// ApplyPrefix constructs a new commitment path from the arguments. It interprets +// the path argument in the context of the prefix argument. +// +// CONTRACT: provided path string MUST be a well formated path. See ICS24 for +// reference. +func ApplyPrefix(prefix exported.Prefix, path string) (MerklePath, error) { + err := host.DefaultPathValidator(path) + if err != nil { + return MerklePath{}, err + } + + if prefix == nil || prefix.IsEmpty() { + return MerklePath{}, errors.New("prefix can't be empty") + } + return NewMerklePath([]string{string(prefix.Bytes()), path}), nil +} + +var _ exported.Proof = MerkleProof{} + +// MerkleProof is a wrapper type that contains a merkle proof. +// It demonstrates membership or non-membership for an element or set of elements, +// verifiable in conjunction with a known commitment root. Proofs should be +// succinct. +type MerkleProof struct { + Proof *merkle.Proof `json:"proof" yaml:"proof"` +} + +// GetCommitmentType implements ProofI +func (MerkleProof) GetCommitmentType() exported.Type { + return exported.Merkle +} + +// VerifyMembership verifies the membership pf a merkle proof against the given root, path, and value. +func (proof MerkleProof) VerifyMembership(root exported.Root, path exported.Path, value []byte) error { + if proof.IsEmpty() || root == nil || root.IsEmpty() || path == nil || path.IsEmpty() || len(value) == 0 { + return errors.New("empty params or proof") + } + + runtime := rootmulti.DefaultProofRuntime() + return runtime.VerifyValue(proof.Proof, root.GetHash(), path.String(), value) +} + +// VerifyNonMembership verifies the absence of a merkle proof against the given root and path. +func (proof MerkleProof) VerifyNonMembership(root exported.Root, path exported.Path) error { + if proof.IsEmpty() || root == nil || root.IsEmpty() || path == nil || path.IsEmpty() { + return errors.New("empty params or proof") + } + + runtime := rootmulti.DefaultProofRuntime() + return runtime.VerifyAbsence(proof.Proof, root.GetHash(), path.String()) +} + +// IsEmpty returns true if the root is empty +func (proof MerkleProof) IsEmpty() bool { + return (proof == MerkleProof{}) || proof.Proof == nil +} + +// ValidateBasic checks if the proof is empty. +func (proof MerkleProof) ValidateBasic() error { + if proof.IsEmpty() { + return ErrInvalidProof + } + return nil +} diff --git a/x/ibc/23-commitment/types/merkle_test.go b/x/ibc/23-commitment/types/merkle_test.go new file mode 100644 index 000000000000..6694ef07fa7d --- /dev/null +++ b/x/ibc/23-commitment/types/merkle_test.go @@ -0,0 +1,141 @@ +package types_test + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" + + abci "github.com/tendermint/tendermint/abci/types" +) + +func (suite *MerkleTestSuite) TestVerifyMembership() { + suite.iavlStore.Set([]byte("MYKEY"), []byte("MYVALUE")) + cid := suite.store.Commit() + + res := suite.store.Query(abci.RequestQuery{ + Path: fmt.Sprintf("/%s/key", suite.storeKey.Name()), // required path to get key/value+proof + Data: []byte("MYKEY"), + Prove: true, + }) + require.NotNil(suite.T(), res.Proof) + + proof := types.MerkleProof{ + Proof: res.Proof, + } + suite.Require().NoError(proof.ValidateBasic()) + suite.Require().Error(types.MerkleProof{}.ValidateBasic()) + + cases := []struct { + name string + root []byte + pathArr []string + value []byte + shouldPass bool + }{ + {"valid proof", cid.Hash, []string{suite.storeKey.Name(), "MYKEY"}, []byte("MYVALUE"), true}, // valid proof + {"wrong value", cid.Hash, []string{suite.storeKey.Name(), "MYKEY"}, []byte("WRONGVALUE"), false}, // invalid proof with wrong value + {"nil value", cid.Hash, []string{suite.storeKey.Name(), "MYKEY"}, []byte(nil), false}, // invalid proof with nil value + {"wrong key", cid.Hash, []string{suite.storeKey.Name(), "NOTMYKEY"}, []byte("MYVALUE"), false}, // invalid proof with wrong key + {"wrong path 1", cid.Hash, []string{suite.storeKey.Name(), "MYKEY", "MYKEY"}, []byte("MYVALUE"), false}, // invalid proof with wrong path + {"wrong path 2", cid.Hash, []string{suite.storeKey.Name()}, []byte("MYVALUE"), false}, // invalid proof with wrong path + {"wrong path 3", cid.Hash, []string{"MYKEY"}, []byte("MYVALUE"), false}, // invalid proof with wrong path + {"wrong storekey", cid.Hash, []string{"otherStoreKey", "MYKEY"}, []byte("MYVALUE"), false}, // invalid proof with wrong store prefix + {"wrong root", []byte("WRONGROOT"), []string{suite.storeKey.Name(), "MYKEY"}, []byte("MYVALUE"), false}, // invalid proof with wrong root + {"nil root", []byte(nil), []string{suite.storeKey.Name(), "MYKEY"}, []byte("MYVALUE"), false}, // invalid proof with nil root + } + + for i, tc := range cases { + tc := tc + suite.Run(tc.name, func() { + root := types.NewMerkleRoot(tc.root) + path := types.NewMerklePath(tc.pathArr) + + err := proof.VerifyMembership(root, path, tc.value) + + if tc.shouldPass { + // nolint: scopelint + suite.Require().NoError(err, "test case %d should have passed", i) + } else { + // nolint: scopelint + suite.Require().Error(err, "test case %d should have failed", i) + } + }) + } + +} + +func (suite *MerkleTestSuite) TestVerifyNonMembership() { + suite.iavlStore.Set([]byte("MYKEY"), []byte("MYVALUE")) + cid := suite.store.Commit() + + // Get Proof + res := suite.store.Query(abci.RequestQuery{ + Path: fmt.Sprintf("/%s/key", suite.storeKey.Name()), // required path to get key/value+proof + Data: []byte("MYABSENTKEY"), + Prove: true, + }) + require.NotNil(suite.T(), res.Proof) + + proof := types.MerkleProof{ + Proof: res.Proof, + } + suite.Require().NoError(proof.ValidateBasic()) + + cases := []struct { + name string + root []byte + pathArr []string + shouldPass bool + }{ + {"valid proof", cid.Hash, []string{suite.storeKey.Name(), "MYABSENTKEY"}, true}, // valid proof + {"wrong key", cid.Hash, []string{suite.storeKey.Name(), "MYKEY"}, false}, // invalid proof with existent key + {"wrong path 1", cid.Hash, []string{suite.storeKey.Name(), "MYKEY", "MYABSENTKEY"}, false}, // invalid proof with wrong path + {"wrong path 2", cid.Hash, []string{suite.storeKey.Name(), "MYABSENTKEY", "MYKEY"}, false}, // invalid proof with wrong path + {"wrong path 3", cid.Hash, []string{suite.storeKey.Name()}, false}, // invalid proof with wrong path + {"wrong path 4", cid.Hash, []string{"MYABSENTKEY"}, false}, // invalid proof with wrong path + {"wrong storeKey", cid.Hash, []string{"otherStoreKey", "MYABSENTKEY"}, false}, // invalid proof with wrong store prefix + {"wrong root", []byte("WRONGROOT"), []string{suite.storeKey.Name(), "MYABSENTKEY"}, false}, // invalid proof with wrong root + {"nil root", []byte(nil), []string{suite.storeKey.Name(), "MYABSENTKEY"}, false}, // invalid proof with nil root + } + + for i, tc := range cases { + tc := tc + + suite.Run(tc.name, func() { + root := types.NewMerkleRoot(tc.root) + path := types.NewMerklePath(tc.pathArr) + + err := proof.VerifyNonMembership(root, path) + + if tc.shouldPass { + // nolint: scopelint + suite.Require().NoError(err, "test case %d should have passed", i) + } else { + // nolint: scopelint + suite.Require().Error(err, "test case %d should have failed", i) + } + }) + } + +} + +func TestApplyPrefix(t *testing.T) { + prefix := types.NewMerklePrefix([]byte("storePrefixKey")) + + pathStr := "path1/path2/path3/key" + + prefixedPath, err := types.ApplyPrefix(prefix, pathStr) + require.Nil(t, err, "valid prefix returns error") + + require.Equal(t, "/storePrefixKey/path1/path2/path3/key", prefixedPath.Pretty(), "Prefixed path incorrect") + require.Equal(t, "/storePrefixKey/path1%2Fpath2%2Fpath3%2Fkey", prefixedPath.String(), "Prefixed scaped path incorrect") + + // invalid prefix contains non-alphanumeric character + invalidPathStr := "invalid-path/doesitfail?/hopefully" + invalidPath, err := types.ApplyPrefix(prefix, invalidPathStr) + require.NotNil(t, err, "invalid prefix does not returns error") + require.Equal(t, types.MerklePath{}, invalidPath, "invalid prefix returns valid Path on ApplyPrefix") +} diff --git a/x/ibc/23-commitment/verify.go b/x/ibc/23-commitment/verify.go new file mode 100644 index 000000000000..4690fe9e1567 --- /dev/null +++ b/x/ibc/23-commitment/verify.go @@ -0,0 +1,64 @@ +package commitment + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" +) + +// CalculateRoot returns the application Hash at the curretn block height as a commitment +// root for proof verification. +func CalculateRoot(ctx sdk.Context) exported.Root { + return types.NewMerkleRoot(ctx.BlockHeader().AppHash) +} + +// BatchVerifyMembership verifies a proof that many paths have been set to +// specific values in a commitment. It calls the proof's VerifyMembership method +// with the calculated root and the provided paths. +// Returns false on the first failed membership verification. +func BatchVerifyMembership( + ctx sdk.Context, + proof exported.Proof, + prefix exported.Prefix, + items map[string][]byte, +) error { + root := CalculateRoot(ctx) + + for pathStr, value := range items { + path, err := types.ApplyPrefix(prefix, pathStr) + if err != nil { + return err + } + + if err := proof.VerifyMembership(root, path, value); err != nil { + return err + } + } + + return nil +} + +// BatchVerifyNonMembership verifies a proof that many paths have not been set +// to any value in a commitment. It calls the proof's VerifyNonMembership method +// with the calculated root and the provided paths. +// Returns false on the first failed non-membership verification. +func BatchVerifyNonMembership( + ctx sdk.Context, + proof exported.Proof, + prefix exported.Prefix, + paths []string, +) error { + root := CalculateRoot(ctx) + for _, pathStr := range paths { + path, err := types.ApplyPrefix(prefix, pathStr) + if err != nil { + return err + } + + if err := proof.VerifyNonMembership(root, path); err != nil { + return err + } + } + + return nil +} diff --git a/x/ibc/alias.go b/x/ibc/alias.go new file mode 100644 index 000000000000..7c1ad02349e2 --- /dev/null +++ b/x/ibc/alias.go @@ -0,0 +1,29 @@ +package ibc + +// nolint +// autogenerated code using github.com/rigelrozanski/multitool +// aliases generated for the following subdirectories: +// ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/keeper +// ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/types + +import ( + "github.com/cosmos/cosmos-sdk/x/ibc/keeper" + "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +const ( + ModuleName = types.ModuleName + StoreKey = types.StoreKey + QuerierRoute = types.QuerierRoute + RouterKey = types.RouterKey +) + +var ( + // functions aliases + NewKeeper = keeper.NewKeeper + NewQuerier = keeper.NewQuerier +) + +type ( + Keeper = keeper.Keeper +) diff --git a/x/ibc/ante/ante.go b/x/ibc/ante/ante.go new file mode 100644 index 000000000000..4301e95c5a10 --- /dev/null +++ b/x/ibc/ante/ante.go @@ -0,0 +1,48 @@ +package ante + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" +) + +// ProofVerificationDecorator handles messages that contains application specific packet types, +// including MsgPacket, MsgAcknowledgement, MsgTimeout. +// MsgUpdateClients are also handled here to perform atomic multimsg transaction +type ProofVerificationDecorator struct { + clientKeeper client.Keeper + channelKeeper channel.Keeper +} + +// NewProofVerificationDecorator constructs new ProofverificationDecorator +func NewProofVerificationDecorator(clientKeeper client.Keeper, channelKeeper channel.Keeper) ProofVerificationDecorator { + return ProofVerificationDecorator{ + clientKeeper: clientKeeper, + channelKeeper: channelKeeper, + } +} + +// AnteHandle executes MsgUpdateClient, MsgPacket, MsgAcknowledgement, MsgTimeout. +// The packet execution messages are then passed to the respective application handlers. +func (pvr ProofVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) { + for _, msg := range tx.GetMsgs() { + var err error + switch msg := msg.(type) { + case clientexported.MsgUpdateClient: + err = pvr.clientKeeper.UpdateClient(ctx, msg.GetClientID(), msg.GetHeader()) + case channel.MsgPacket: + _, err = pvr.channelKeeper.RecvPacket(ctx, msg.Packet, msg.Proof, msg.ProofHeight) + case channel.MsgAcknowledgement: + _, err = pvr.channelKeeper.AcknowledgePacket(ctx, msg.Packet, msg.Acknowledgement, msg.Proof, msg.ProofHeight) + case channel.MsgTimeout: + _, err = pvr.channelKeeper.TimeoutPacket(ctx, msg.Packet, msg.Proof, msg.ProofHeight, msg.NextSequenceRecv) + } + + if err != nil { + return ctx, err + } + } + + return next(ctx, tx, simulate) +} diff --git a/x/ibc/ante/ante_test.go b/x/ibc/ante/ante_test.go new file mode 100644 index 000000000000..54d74f8ec6da --- /dev/null +++ b/x/ibc/ante/ante_test.go @@ -0,0 +1,371 @@ +package ante_test + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/suite" + abci "github.com/tendermint/tendermint/abci/types" + tmtypes "github.com/tendermint/tendermint/types" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/simapp" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + connectionexported "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported" + connectiontypes "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" + channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" + "github.com/cosmos/cosmos-sdk/x/staking" + + commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" + "github.com/cosmos/cosmos-sdk/x/ibc/ante" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +// define constants used for testing +const ( + testClientIDA = "testclientida" + testClientIDB = "testclientidb" + testConnection = "testconnection" + + trustingPeriod time.Duration = time.Hour * 24 * 7 * 2 + ubdPeriod time.Duration = time.Hour * 24 * 7 * 3 +) + +// define variables used for testing +type HandlerTestSuite struct { + suite.Suite + + cdc *codec.Codec + + chainA *TestChain + chainB *TestChain +} + +func (suite *HandlerTestSuite) SetupTest() { + suite.chainA = NewTestChain(testClientIDA) + suite.chainB = NewTestChain(testClientIDB) + + suite.cdc = suite.chainA.App.Codec() + + // create client and connection during setups + suite.chainA.CreateClient(suite.chainB) + suite.chainB.CreateClient(suite.chainA) + suite.chainA.createConnection(testConnection, testConnection, testClientIDB, testClientIDA, connectionexported.OPEN) + suite.chainB.createConnection(testConnection, testConnection, testClientIDA, testClientIDB, connectionexported.OPEN) +} + +func queryProof(chain *TestChain, key string) (proof commitmenttypes.MerkleProof, height int64) { + res := chain.App.Query(abci.RequestQuery{ + Path: fmt.Sprintf("store/%s/key", ibctypes.StoreKey), + Data: []byte(key), + Prove: true, + }) + + height = res.Height + proof = commitmenttypes.MerkleProof{ + Proof: res.Proof, + } + + return +} + +func (suite *HandlerTestSuite) newTx(msg sdk.Msg) sdk.Tx { + return authtypes.StdTx{ + Msgs: []sdk.Msg{msg}, + } +} + +func (suite *HandlerTestSuite) TestHandleMsgPacketOrdered() { + handler := sdk.ChainAnteDecorators(ante.NewProofVerificationDecorator( + suite.chainA.App.IBCKeeper.ClientKeeper, + suite.chainA.App.IBCKeeper.ChannelKeeper, + )) + + packet := channel.NewPacket(newPacket(12345).GetData(), 1, portid, chanid, cpportid, cpchanid, 100) + + ctx := suite.chainA.GetContext() + cctx, _ := ctx.CacheContext() + // suite.chainA.App.IBCKeeper.ChannelKeeper.SetNextSequenceSend(ctx, packet.SourcePort, packet.SourceChannel, 1) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), packet.SourcePort, packet.SourceChannel, packet.Sequence, channeltypes.CommitPacket(packet)) + msg := channel.NewMsgPacket(packet, nil, 0, addr1) + _, err := handler(cctx, suite.newTx(msg), false) + suite.Error(err, "%+v", err) // channel does not exist + + suite.chainA.createChannel(cpportid, cpchanid, portid, chanid, channelexported.OPEN, channelexported.ORDERED, testConnection) + suite.chainB.createChannel(portid, chanid, cpportid, cpchanid, channelexported.OPEN, channelexported.ORDERED, testConnection) + ctx = suite.chainA.GetContext() + packetCommitmentPath := ibctypes.PacketCommitmentPath(packet.SourcePort, packet.SourceChannel, packet.Sequence) + proof, proofHeight := queryProof(suite.chainB, packetCommitmentPath) + msg = channel.NewMsgPacket(packet, proof, uint64(proofHeight), addr1) + _, err = handler(cctx, suite.newTx(msg), false) + suite.Error(err, "%+v", err) // invalid proof + + suite.chainA.updateClient(suite.chainB) + // // commit chainA to flush to IAVL so we can get proof + // suite.chainA.App.Commit() + // suite.chainA.App.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: suite.chainA.App.LastBlockHeight() + 1, Time: suite.chainA.Header.Time}}) + // ctx = suite.chainA.GetContext() + + proof, proofHeight = queryProof(suite.chainB, packetCommitmentPath) + msg = channel.NewMsgPacket(packet, proof, uint64(proofHeight), addr1) + + for i := 0; i < 10; i++ { + cctx, write := suite.chainA.GetContext().CacheContext() + suite.chainA.App.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(cctx, cpportid, cpchanid, uint64(i)) + _, err := handler(cctx, suite.newTx(msg), false) + if err == nil { + err = suite.chainA.App.IBCKeeper.ChannelKeeper.PacketExecuted(cctx, packet, packet.Data) + } + if i == 1 { + suite.NoError(err, "%d", i) // successfully executed + write() + } else { + suite.Error(err, "%d", i) // wrong incoming sequence + } + } +} + +func (suite *HandlerTestSuite) TestHandleMsgPacketUnordered() { + handler := sdk.ChainAnteDecorators(ante.NewProofVerificationDecorator( + suite.chainA.App.IBCKeeper.ClientKeeper, + suite.chainA.App.IBCKeeper.ChannelKeeper, + )) + + // Not testing nonexist channel, invalid proof, nextseqsend, they are already tested in TestHandleMsgPacketOrdered + + var packet channeltypes.Packet + for i := 0; i < 5; i++ { + packet = channel.NewPacket(newPacket(uint64(i)).GetData(), uint64(i), portid, chanid, cpportid, cpchanid, 100) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), packet.SourcePort, packet.SourceChannel, uint64(i), channeltypes.CommitPacket(packet)) + } + + // suite.chainA.App.IBCKeeper.ChannelKeeper.SetNextSequenceSend(suite.chainA.GetContext(), packet.SourcePort, packet.SourceChannel, uint64(10)) + + suite.chainA.createChannel(cpportid, cpchanid, portid, chanid, channelexported.OPEN, channelexported.UNORDERED, testConnection) + + suite.chainA.updateClient(suite.chainB) + + for i := 10; i >= 0; i-- { + cctx, write := suite.chainA.GetContext().CacheContext() + packet = channel.NewPacket(newPacket(uint64(i)).GetData(), uint64(i), portid, chanid, cpportid, cpchanid, 100) + packetCommitmentPath := ibctypes.PacketCommitmentPath(packet.SourcePort, packet.SourceChannel, uint64(i)) + proof, proofHeight := queryProof(suite.chainB, packetCommitmentPath) + msg := channel.NewMsgPacket(packet, proof, uint64(proofHeight), addr1) + _, err := handler(cctx, suite.newTx(msg), false) + if i < 5 { + suite.NoError(err, "%d", i) // successfully executed + write() + } else { + suite.Error(err, "%d", i) // wrong incoming sequence + } + } +} + +func TestHandlerTestSuite(t *testing.T) { + suite.Run(t, new(HandlerTestSuite)) +} + +type TestChain struct { + ClientID string + App *simapp.SimApp + Header ibctmtypes.Header + Vals *tmtypes.ValidatorSet + Signers []tmtypes.PrivValidator +} + +func NewTestChain(clientID string) *TestChain { + privVal := tmtypes.NewMockPV() + validator := tmtypes.NewValidator(privVal.GetPubKey(), 1) + valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator}) + signers := []tmtypes.PrivValidator{privVal} + now := time.Date(2020, 1, 2, 0, 0, 0, 0, time.UTC) + + header := ibctmtypes.CreateTestHeader(clientID, 1, now, valSet, signers) + + return &TestChain{ + ClientID: clientID, + App: simapp.Setup(false), + Header: header, + Vals: valSet, + Signers: signers, + } +} + +// Creates simple context for testing purposes +func (chain *TestChain) GetContext() sdk.Context { + return chain.App.BaseApp.NewContext(false, abci.Header{ChainID: chain.Header.ChainID, Height: chain.Header.Height}) +} + +// createClient will create a client for clientChain on targetChain +func (chain *TestChain) CreateClient(client *TestChain) error { + client.Header = nextHeader(client) + // Commit and create a new block on appTarget to get a fresh CommitID + client.App.Commit() + commitID := client.App.LastCommitID() + client.App.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: client.Header.Height, Time: client.Header.Time}}) + + // Set HistoricalInfo on client chain after Commit + ctxClient := client.GetContext() + validator := staking.NewValidator( + sdk.ValAddress(client.Vals.Validators[0].Address), client.Vals.Validators[0].PubKey, staking.Description{}, + ) + validator.Status = sdk.Bonded + validator.Tokens = sdk.NewInt(1000000) // get one voting power + validators := []staking.Validator{validator} + histInfo := staking.HistoricalInfo{ + Header: abci.Header{ + AppHash: commitID.Hash, + }, + Valset: validators, + } + client.App.StakingKeeper.SetHistoricalInfo(ctxClient, client.Header.Height, histInfo) + + // Create target ctx + ctxTarget := chain.GetContext() + + // create client + clientState, err := ibctmtypes.Initialize(client.ClientID, trustingPeriod, ubdPeriod, client.Header) + if err != nil { + return err + } + _, err = chain.App.IBCKeeper.ClientKeeper.CreateClient(ctxTarget, clientState, client.Header.ConsensusState()) + if err != nil { + return err + } + return nil + + // _, _, err := simapp.SignCheckDeliver( + // suite.T(), + // suite.cdc, + // suite.chainA.App.BaseApp, + // ctx.BlockHeader(), + // []sdk.Msg{clienttypes.NewMsgCreateClient(clientID, clientexported.ClientTypeTendermint, consState, accountAddress)}, + // []uint64{baseAccount.GetAccountNumber()}, + // []uint64{baseAccount.GetSequence()}, + // true, true, accountPrivKey, + // ) +} + +func (chain *TestChain) updateClient(client *TestChain) { + // Create target ctx + ctxTarget := chain.GetContext() + + // if clientState does not already exist, return without updating + _, found := chain.App.IBCKeeper.ClientKeeper.GetClientState( + ctxTarget, client.ClientID, + ) + if !found { + return + } + + // always commit when updateClient and begin a new block + client.App.Commit() + commitID := client.App.LastCommitID() + + client.Header = nextHeader(client) + client.App.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: client.Header.Height, Time: client.Header.Time}}) + + // Set HistoricalInfo on client chain after Commit + ctxClient := client.GetContext() + validator := staking.NewValidator( + sdk.ValAddress(client.Vals.Validators[0].Address), client.Vals.Validators[0].PubKey, staking.Description{}, + ) + validator.Status = sdk.Bonded + validator.Tokens = sdk.NewInt(1000000) + validators := []staking.Validator{validator} + histInfo := staking.HistoricalInfo{ + Header: abci.Header{ + AppHash: commitID.Hash, + }, + Valset: validators, + } + client.App.StakingKeeper.SetHistoricalInfo(ctxClient, client.Header.Height, histInfo) + + consensusState := ibctmtypes.ConsensusState{ + Height: uint64(client.Header.Height) - 1, + Timestamp: client.Header.Time, + Root: commitmenttypes.NewMerkleRoot(commitID.Hash), + ValidatorSet: client.Vals, + } + + chain.App.IBCKeeper.ClientKeeper.SetClientConsensusState( + ctxTarget, client.ClientID, uint64(client.Header.Height-1), consensusState, + ) + chain.App.IBCKeeper.ClientKeeper.SetClientState( + ctxTarget, ibctmtypes.NewClientState(client.ClientID, trustingPeriod, ubdPeriod, client.Header), + ) + + // _, _, err := simapp.SignCheckDeliver( + // suite.T(), + // suite.cdc, + // suite.chainA.App.BaseApp, + // ctx.BlockHeader(), + // []sdk.Msg{clienttypes.NewMsgUpdateClient(clientID, suite.header, accountAddress)}, + // []uint64{baseAccount.GetAccountNumber()}, + // []uint64{baseAccount.GetSequence()}, + // true, true, accountPrivKey, + // ) + // suite.Require().NoError(err) +} + +func (chain *TestChain) createConnection( + connID, counterpartyConnID, clientID, counterpartyClientID string, + state connectionexported.State, +) connectiontypes.ConnectionEnd { + counterparty := connectiontypes.NewCounterparty(counterpartyClientID, counterpartyConnID, chain.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix()) + connection := connectiontypes.ConnectionEnd{ + State: state, + ClientID: clientID, + Counterparty: counterparty, + Versions: connectiontypes.GetCompatibleVersions(), + } + ctx := chain.GetContext() + chain.App.IBCKeeper.ConnectionKeeper.SetConnection(ctx, connID, connection) + return connection +} + +func (chain *TestChain) createChannel( + portID, channelID, counterpartyPortID, counterpartyChannelID string, + state channelexported.State, order exported.Order, connectionID string, +) channeltypes.Channel { + counterparty := channeltypes.NewCounterparty(counterpartyPortID, counterpartyChannelID) + channel := channeltypes.NewChannel(state, order, counterparty, + []string{connectionID}, "1.0", + ) + ctx := chain.GetContext() + chain.App.IBCKeeper.ChannelKeeper.SetChannel(ctx, portID, channelID, channel) + return channel +} + +func nextHeader(chain *TestChain) ibctmtypes.Header { + return ibctmtypes.CreateTestHeader(chain.Header.ChainID, chain.Header.Height+1, + chain.Header.Time.Add(time.Minute), chain.Vals, chain.Signers) +} + +type packetT struct { + Data uint64 +} + +func (packet packetT) GetData() []byte { + return []byte(fmt.Sprintf("%d", packet.Data)) +} + +func newPacket(data uint64) packetT { + return packetT{data} +} + +// define variables used for testing +var ( + addr1 = sdk.AccAddress("testaddr1") + + portid = "testportid" + chanid = "testchannel" + cpportid = "testcpport" + cpchanid = "testcpchannel" +) diff --git a/x/ibc/client/cli/cli.go b/x/ibc/client/cli/cli.go new file mode 100644 index 000000000000..c42fbc8aa98e --- /dev/null +++ b/x/ibc/client/cli/cli.go @@ -0,0 +1,51 @@ +package cli + +import ( + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/codec" + ibcclient "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" + channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" + tmclient "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/client/cli" + "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +// GetTxCmd returns the transaction commands for this module +func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { + ibcTxCmd := &cobra.Command{ + Use: types.ModuleName, + Short: "IBC transaction subcommands", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + ibcTxCmd.AddCommand(flags.PostCommands( + tmclient.GetTxCmd(cdc, storeKey), + connection.GetTxCmd(cdc, storeKey), + channel.GetTxCmd(cdc, storeKey), + )...) + return ibcTxCmd +} + +// GetQueryCmd returns the cli query commands for this module +func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { + // Group ibc queries under a subcommand + ibcQueryCmd := &cobra.Command{ + Use: types.ModuleName, + Short: "Querying commands for the IBC module", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + ibcQueryCmd.AddCommand(flags.GetCommands( + ibcclient.GetQueryCmd(cdc, queryRoute), + connection.GetQueryCmd(cdc, queryRoute), + channel.GetQueryCmd(cdc, queryRoute), + )...) + return ibcQueryCmd +} diff --git a/x/ibc/client/rest/rest.go b/x/ibc/client/rest/rest.go new file mode 100644 index 000000000000..2e0d96e0ec6d --- /dev/null +++ b/x/ibc/client/rest/rest.go @@ -0,0 +1,17 @@ +package rest + +import ( + "github.com/gorilla/mux" + + "github.com/cosmos/cosmos-sdk/client/context" + client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" + channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" +) + +// RegisterRoutes - Central function to define routes that get registered by the main application +func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, queryRoute string) { + client.RegisterRESTRoutes(cliCtx, r, queryRoute) + connection.RegisterRESTRoutes(cliCtx, r, queryRoute) + channel.RegisterRESTRoutes(cliCtx, r, queryRoute) +} diff --git a/x/ibc/handler.go b/x/ibc/handler.go new file mode 100644 index 000000000000..d71f73e4585b --- /dev/null +++ b/x/ibc/handler.go @@ -0,0 +1,202 @@ +package ibc + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" + channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" + port "github.com/cosmos/cosmos-sdk/x/ibc/05-port" +) + +// NewHandler defines the IBC handler +func NewHandler(k Keeper) sdk.Handler { + return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { + ctx = ctx.WithEventManager(sdk.NewEventManager()) + + switch msg := msg.(type) { + // IBC client msg interface types + case clientexported.MsgCreateClient: + return client.HandleMsgCreateClient(ctx, k.ClientKeeper, msg) + + case clientexported.MsgUpdateClient: + return &sdk.Result{}, nil + + // IBC connection msgs + case connection.MsgConnectionOpenInit: + return connection.HandleMsgConnectionOpenInit(ctx, k.ConnectionKeeper, msg) + + case connection.MsgConnectionOpenTry: + return connection.HandleMsgConnectionOpenTry(ctx, k.ConnectionKeeper, msg) + + case connection.MsgConnectionOpenAck: + return connection.HandleMsgConnectionOpenAck(ctx, k.ConnectionKeeper, msg) + + case connection.MsgConnectionOpenConfirm: + return connection.HandleMsgConnectionOpenConfirm(ctx, k.ConnectionKeeper, msg) + + // IBC channel msgs + case channel.MsgChannelOpenInit: + // Lookup module by port capability + module, portCap, ok := k.PortKeeper.LookupModuleByPort(ctx, msg.PortID) + if !ok { + return nil, sdkerrors.Wrap(port.ErrInvalidPort, "could not retrieve module from portID") + } + res, cap, err := channel.HandleMsgChannelOpenInit(ctx, k.ChannelKeeper, portCap, msg) + if err != nil { + return nil, err + } + // Retrieve callbacks from router + cbs, ok := k.Router.GetRoute(module) + if !ok { + return nil, sdkerrors.Wrapf(port.ErrInvalidRoute, "route not found to module: %s", module) + } + err = cbs.OnChanOpenInit(ctx, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.PortID, msg.ChannelID, cap, msg.Channel.Counterparty, msg.Channel.Version) + if err != nil { + return nil, err + } + + return res, nil + + case channel.MsgChannelOpenTry: + // Lookup module by port capability + module, portCap, ok := k.PortKeeper.LookupModuleByPort(ctx, msg.PortID) + if !ok { + return nil, sdkerrors.Wrap(port.ErrInvalidPort, "could not retrieve module from portID") + } + res, cap, err := channel.HandleMsgChannelOpenTry(ctx, k.ChannelKeeper, portCap, msg) + if err != nil { + return nil, err + } + // Retrieve callbacks from router + cbs, ok := k.Router.GetRoute(module) + if !ok { + return nil, sdkerrors.Wrapf(port.ErrInvalidRoute, "route not found to module: %s", module) + } + err = cbs.OnChanOpenTry(ctx, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.PortID, msg.ChannelID, cap, msg.Channel.Counterparty, msg.Channel.Version, msg.CounterpartyVersion) + if err != nil { + return nil, err + } + + return res, nil + + case channel.MsgChannelOpenAck: + // Lookup module by channel capability + module, cap, ok := k.ChannelKeeper.LookupModuleByChannel(ctx, msg.PortID, msg.ChannelID) + if !ok { + return nil, sdkerrors.Wrap(channel.ErrChannelCapabilityNotFound, "could not retrieve module from channel capability") + } + // Retrieve callbacks from router + cbs, ok := k.Router.GetRoute(module) + if !ok { + return nil, sdkerrors.Wrapf(port.ErrInvalidRoute, "route not found to module: %s", module) + } + err := cbs.OnChanOpenAck(ctx, msg.PortID, msg.ChannelID, msg.CounterpartyVersion) + if err != nil { + return nil, err + } + return channel.HandleMsgChannelOpenAck(ctx, k.ChannelKeeper, cap, msg) + + case channel.MsgChannelOpenConfirm: + // Lookup module by channel capability + module, cap, ok := k.ChannelKeeper.LookupModuleByChannel(ctx, msg.PortID, msg.ChannelID) + if !ok { + return nil, sdkerrors.Wrap(channel.ErrChannelCapabilityNotFound, "could not retrieve module from channel capability") + } + // Retrieve callbacks from router + cbs, ok := k.Router.GetRoute(module) + if !ok { + return nil, sdkerrors.Wrapf(port.ErrInvalidRoute, "route not found to module: %s", module) + } + + err := cbs.OnChanOpenConfirm(ctx, msg.PortID, msg.ChannelID) + if err != nil { + return nil, err + } + return channel.HandleMsgChannelOpenConfirm(ctx, k.ChannelKeeper, cap, msg) + + case channel.MsgChannelCloseInit: + // Lookup module by channel capability + module, cap, ok := k.ChannelKeeper.LookupModuleByChannel(ctx, msg.PortID, msg.ChannelID) + if !ok { + return nil, sdkerrors.Wrap(channel.ErrChannelCapabilityNotFound, "could not retrieve module from channel capability") + } + // Retrieve callbacks from router + cbs, ok := k.Router.GetRoute(module) + if !ok { + return nil, sdkerrors.Wrapf(port.ErrInvalidRoute, "route not found to module: %s", module) + } + + err := cbs.OnChanCloseInit(ctx, msg.PortID, msg.ChannelID) + if err != nil { + return nil, err + } + return channel.HandleMsgChannelCloseInit(ctx, k.ChannelKeeper, cap, msg) + + case channel.MsgChannelCloseConfirm: + // Lookup module by channel capability + module, cap, ok := k.ChannelKeeper.LookupModuleByChannel(ctx, msg.PortID, msg.ChannelID) + if !ok { + return nil, sdkerrors.Wrap(channel.ErrChannelCapabilityNotFound, "could not retrieve module from channel capability") + } + // Retrieve callbacks from router + cbs, ok := k.Router.GetRoute(module) + if !ok { + return nil, sdkerrors.Wrapf(port.ErrInvalidRoute, "route not found to module: %s", module) + } + + err := cbs.OnChanCloseConfirm(ctx, msg.PortID, msg.ChannelID) + if err != nil { + return nil, err + } + return channel.HandleMsgChannelCloseConfirm(ctx, k.ChannelKeeper, cap, msg) + + // IBC packet msgs get routed to the appropriate module callback + case channel.MsgPacket: + // Lookup module by channel capability + module, _, ok := k.ChannelKeeper.LookupModuleByChannel(ctx, msg.Packet.DestinationPort, msg.Packet.DestinationChannel) + if !ok { + return nil, sdkerrors.Wrap(channel.ErrChannelCapabilityNotFound, "could not retrieve module from channel capability") + } + + // Retrieve callbacks from router + cbs, ok := k.Router.GetRoute(module) + if !ok { + return nil, sdkerrors.Wrapf(port.ErrInvalidRoute, "route not found to module: %s", module) + } + return cbs.OnRecvPacket(ctx, msg.Packet) + + case channel.MsgAcknowledgement: + // Lookup module by channel capability + module, _, ok := k.ChannelKeeper.LookupModuleByChannel(ctx, msg.Packet.DestinationPort, msg.Packet.DestinationChannel) + if !ok { + return nil, sdkerrors.Wrap(channel.ErrChannelCapabilityNotFound, "could not retrieve module from channel capability") + } + + // Retrieve callbacks from router + cbs, ok := k.Router.GetRoute(module) + if !ok { + return nil, sdkerrors.Wrapf(port.ErrInvalidRoute, "route not found to module: %s", module) + } + return cbs.OnAcknowledgementPacket(ctx, msg.Packet, msg.Acknowledgement) + + case channel.MsgTimeout: + // Lookup module by channel capability + module, _, ok := k.ChannelKeeper.LookupModuleByChannel(ctx, msg.Packet.DestinationPort, msg.Packet.DestinationChannel) + if !ok { + return nil, sdkerrors.Wrap(channel.ErrChannelCapabilityNotFound, "could not retrieve module from channel capability") + } + + // Retrieve callbacks from router + cbs, ok := k.Router.GetRoute(module) + if !ok { + return nil, sdkerrors.Wrapf(port.ErrInvalidRoute, "route not found to module: %s", module) + } + return cbs.OnTimeoutPacket(ctx, msg.Packet) + + default: + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized IBC message type: %T", msg) + } + } +} diff --git a/x/ibc/keeper/keeper.go b/x/ibc/keeper/keeper.go new file mode 100644 index 000000000000..7b528bbf5c88 --- /dev/null +++ b/x/ibc/keeper/keeper.go @@ -0,0 +1,46 @@ +package keeper + +import ( + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/capability" + client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" + channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" + port "github.com/cosmos/cosmos-sdk/x/ibc/05-port" +) + +// Keeper defines each ICS keeper for IBC +type Keeper struct { + ClientKeeper client.Keeper + ConnectionKeeper connection.Keeper + ChannelKeeper channel.Keeper + PortKeeper port.Keeper + Router *port.Router +} + +// NewKeeper creates a new ibc Keeper +func NewKeeper( + cdc *codec.Codec, key sdk.StoreKey, stakingKeeper client.StakingKeeper, scopedKeeper capability.ScopedKeeper, +) *Keeper { + clientKeeper := client.NewKeeper(cdc, key, stakingKeeper) + connectionKeeper := connection.NewKeeper(cdc, key, clientKeeper) + portKeeper := port.NewKeeper(scopedKeeper) + channelKeeper := channel.NewKeeper(cdc, key, clientKeeper, connectionKeeper, portKeeper, scopedKeeper) + + return &Keeper{ + ClientKeeper: clientKeeper, + ConnectionKeeper: connectionKeeper, + ChannelKeeper: channelKeeper, + PortKeeper: portKeeper, + } +} + +// Set the Router in IBC Keeper and seal it +func (k *Keeper) SetRouter(rtr *port.Router) { + if k.Router != nil && k.Router.Sealed() { + panic("cannot reset a sealed router") + } + k.Router = rtr + k.Router.Seal() +} diff --git a/x/ibc/keeper/keeper_test.go b/x/ibc/keeper/keeper_test.go new file mode 100644 index 000000000000..c5b7aa70887a --- /dev/null +++ b/x/ibc/keeper/keeper_test.go @@ -0,0 +1,37 @@ +package keeper_test + +import ( + "testing" + + "github.com/stretchr/testify/suite" + + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/simapp" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc/keeper" +) + +type KeeperTestSuite struct { + suite.Suite + + cdc *codec.Codec + ctx sdk.Context + keeper *keeper.Keeper + querier sdk.Querier +} + +func (suite *KeeperTestSuite) SetupTest() { + isCheckTx := false + app := simapp.Setup(isCheckTx) + + suite.cdc = app.Codec() + suite.ctx = app.BaseApp.NewContext(isCheckTx, abci.Header{}) + suite.keeper = app.IBCKeeper + suite.querier = keeper.NewQuerier(*app.IBCKeeper) +} + +func TestKeeperTestSuite(t *testing.T) { + suite.Run(t, new(KeeperTestSuite)) +} diff --git a/x/ibc/keeper/querier.go b/x/ibc/keeper/querier.go new file mode 100644 index 000000000000..0f9b2f0f5be5 --- /dev/null +++ b/x/ibc/keeper/querier.go @@ -0,0 +1,53 @@ +package keeper + +import ( + abci "github.com/tendermint/tendermint/abci/types" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" + channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" +) + +// NewQuerier creates a querier for the IBC module +func NewQuerier(k Keeper) sdk.Querier { + return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) { + var ( + res []byte + err error + ) + + switch path[0] { + case client.SubModuleName: + switch path[1] { + case client.QueryAllClients: + res, err = client.QuerierClients(ctx, req, k.ClientKeeper) + default: + err = sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown IBC %s query endpoint", client.SubModuleName) + } + case connection.SubModuleName: + switch path[1] { + case connection.QueryAllConnections: + res, err = connection.QuerierConnections(ctx, req, k.ConnectionKeeper) + case connection.QueryClientConnections: + res, err = connection.QuerierClientConnections(ctx, req, k.ConnectionKeeper) + default: + err = sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown IBC %s query endpoint", connection.SubModuleName) + } + case channel.SubModuleName: + switch path[1] { + case channel.QueryAllChannels: + res, err = channel.QuerierChannels(ctx, req, k.ChannelKeeper) + case channel.QueryConnectionChannels: + res, err = channel.QuerierConnectionChannels(ctx, req, k.ChannelKeeper) + default: + err = sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown IBC %s query endpoint", channel.SubModuleName) + } + default: + err = sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown IBC query endpoint") + } + + return res, err + } +} diff --git a/x/ibc/keeper/querier_test.go b/x/ibc/keeper/querier_test.go new file mode 100644 index 000000000000..83987a517cc1 --- /dev/null +++ b/x/ibc/keeper/querier_test.go @@ -0,0 +1,113 @@ +package keeper_test + +import ( + "fmt" + + "github.com/stretchr/testify/require" + + client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" + channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" + + abci "github.com/tendermint/tendermint/abci/types" +) + +// TestNewQuerier tests that the querier paths are correct. +// NOTE: the actuall testing functionality are located on each ICS querier test. +func (suite *KeeperTestSuite) TestNewQuerier() { + + query := abci.RequestQuery{ + Path: "", + Data: []byte{}, + } + + cases := []struct { + name string + path []string + expectsDefaultErr bool + errMsg string + }{ + {"client - QuerierClientState", + []string{client.SubModuleName, client.QueryClientState}, + false, + "", + }, + {"client - QuerierClients", + []string{client.SubModuleName, client.QueryAllClients}, + false, + "", + }, + { + "client - QuerierConsensusState", + []string{client.SubModuleName, client.QueryConsensusState}, + false, + "", + }, + { + "client - invalid query", + []string{client.SubModuleName, "foo"}, + true, + fmt.Sprintf("unknown IBC %s query endpoint", client.SubModuleName), + }, + { + "connection - QuerierConnections", + []string{connection.SubModuleName, connection.QueryAllConnections}, + false, + "", + }, + { + "connection - QuerierClientConnections", + []string{connection.SubModuleName, connection.QueryClientConnections}, + false, + "", + }, + { + "connection - invalid query", + []string{connection.SubModuleName, "foo"}, + true, + fmt.Sprintf("unknown IBC %s query endpoint", connection.SubModuleName), + }, + { + "channel - QuerierChannel", + []string{channel.SubModuleName, channel.QueryChannel}, + false, + "", + }, + { + "channel - QuerierChannels", + []string{channel.SubModuleName, channel.QueryAllChannels}, + false, + "", + }, + { + "channel - QuerierConnectionChannels", + []string{channel.SubModuleName, channel.QueryConnectionChannels}, + false, + "", + }, + { + "channel - invalid query", + []string{channel.SubModuleName, "foo"}, + true, + fmt.Sprintf("unknown IBC %s query endpoint", channel.SubModuleName), + }, + { + "invalid query", + []string{"foo"}, + true, + "unknown IBC query endpoint", + }, + } + + for i, tc := range cases { + i, tc := i, tc + suite.Run(tc.name, func() { + _, err := suite.querier(suite.ctx, tc.path, query) + if tc.expectsDefaultErr { + require.Contains(suite.T(), err.Error(), tc.errMsg, "test case #%d", i) + } else { + suite.Error(err, "test case #%d", i) + } + }) + } +} diff --git a/x/ibc/module.go b/x/ibc/module.go new file mode 100644 index 000000000000..a6168fba8038 --- /dev/null +++ b/x/ibc/module.go @@ -0,0 +1,140 @@ +package ibc + +import ( + "encoding/json" + + "github.com/gorilla/mux" + "github.com/spf13/cobra" + + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" + channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" + 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/client/cli" + "github.com/cosmos/cosmos-sdk/x/ibc/client/rest" + "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +// TODO: AppModuleSimulation +var ( + _ module.AppModule = AppModule{} + _ module.AppModuleBasic = AppModuleBasic{} +) + +// AppModuleBasic defines the basic application module used by the ibc module. +type AppModuleBasic struct{} + +var _ module.AppModuleBasic = AppModuleBasic{} + +// Name returns the ibc module's name. +func (AppModuleBasic) Name() string { + return types.ModuleName +} + +// RegisterCodec registers the ibc module's types for the given codec. +func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) { + client.RegisterCodec(cdc) + connection.RegisterCodec(cdc) + channel.RegisterCodec(cdc) + ibctmtypes.RegisterCodec(cdc) + commitmenttypes.RegisterCodec(cdc) +} + +// DefaultGenesis returns default genesis state as raw bytes for the ibc +// module. +func (AppModuleBasic) DefaultGenesis(_ codec.JSONMarshaler) json.RawMessage { + return nil +} + +// ValidateGenesis performs genesis state validation for the ibc module. +func (AppModuleBasic) ValidateGenesis(_ codec.JSONMarshaler, _ json.RawMessage) error { + return nil +} + +// RegisterRESTRoutes registers the REST routes for the ibc module. +func (AppModuleBasic) RegisterRESTRoutes(ctx context.CLIContext, rtr *mux.Router) { + rest.RegisterRoutes(ctx, rtr, StoreKey) +} + +// GetTxCmd returns the root tx command for the ibc module. +func (AppModuleBasic) GetTxCmd(cdc *codec.Codec) *cobra.Command { + return cli.GetTxCmd(StoreKey, cdc) +} + +// GetQueryCmd returns no root query command for the ibc module. +func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command { + return cli.GetQueryCmd(QuerierRoute, cdc) +} + +// AppModule implements an application module for the ibc module. +type AppModule struct { + AppModuleBasic + keeper *Keeper +} + +// NewAppModule creates a new AppModule object +func NewAppModule(k *Keeper) AppModule { + return AppModule{ + keeper: k, + } +} + +// Name returns the ibc module's name. +func (AppModule) Name() string { + return ModuleName +} + +// RegisterInvariants registers the ibc module invariants. +func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) { + // TODO: +} + +// Route returns the message routing key for the ibc module. +func (AppModule) Route() string { + return RouterKey +} + +// NewHandler returns an sdk.Handler for the ibc module. +func (am AppModule) NewHandler() sdk.Handler { + return NewHandler(*am.keeper) +} + +// QuerierRoute returns the ibc module's querier route name. +func (AppModule) QuerierRoute() string { + return QuerierRoute +} + +// NewQuerierHandler returns the ibc module sdk.Querier. +func (am AppModule) NewQuerierHandler() sdk.Querier { + return NewQuerier(*am.keeper) +} + +// InitGenesis performs genesis initialization for the ibc module. It returns +// no validator updates. +func (am AppModule) InitGenesis(_ sdk.Context, _ codec.JSONMarshaler, _ json.RawMessage) []abci.ValidatorUpdate { + // check if the IBC transfer module account is set + return []abci.ValidatorUpdate{} +} + +// ExportGenesis returns the exported genesis state as raw bytes for the ibc +// module. +func (am AppModule) ExportGenesis(_ sdk.Context, _ codec.JSONMarshaler) json.RawMessage { + return nil +} + +// BeginBlock returns the begin blocker for the ibc module. +func (am AppModule) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) { +} + +// EndBlock returns the end blocker for the ibc module. It returns no validator +// updates. +func (am AppModule) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) []abci.ValidatorUpdate { + return []abci.ValidatorUpdate{} +} diff --git a/x/ibc/spec/01_concepts.md b/x/ibc/spec/01_concepts.md new file mode 100644 index 000000000000..907893de27e4 --- /dev/null +++ b/x/ibc/spec/01_concepts.md @@ -0,0 +1,8 @@ + + +# Concepts + +> NOTE: if you are not familiar with the IBC terminology and concepts, please read +this [document](https://github.com/cosmos/ics/blob/master/ibc/1_IBC_TERMINOLOGY.md) as prerequisite reading. diff --git a/x/ibc/spec/02_state.md b/x/ibc/spec/02_state.md new file mode 100644 index 000000000000..b53ece883720 --- /dev/null +++ b/x/ibc/spec/02_state.md @@ -0,0 +1,21 @@ + + +# State + +The paths for the values stored in state can be found [here](https://github.com/cosmos/ics/blob/master/spec/ics-024-host-requirements/README.md#path-space). Additionally, the SDK adds +a prefix to the path to be able to aggregate the values for querying purposes. + +| Prefix | Path | Value type | +|--------|------------------------------------------------------------------------|----------------| +| "0/" | "clients/{identifier}" | ClientState | +| "0/" | "clients/{identifier}/consensusState" | ConsensusState | +| "0/" | "clients/{identifier}/type" | ClientType | +| "0/" | "connections/{identifier}" | ConnectionEnd | +| "0/" | "ports/{identifier}" | CapabilityKey | +| "0/" | "ports/{identifier}/channels/{identifier}" | ChannelEnd | +| "0/" | "ports/{identifier}/channels/{identifier}/key" | CapabilityKey | +| "0/" | "ports/{identifier}/channels/{identifier}/nextSequenceRecv" | uint64 | +| "0/" | "ports/{identifier}/channels/{identifier}/packets/{sequence}" | bytes | +| "0/" | "ports/{identifier}/channels/{identifier}/acknowledgements/{sequence}" | bytes | \ No newline at end of file diff --git a/x/ibc/spec/04_messages.md b/x/ibc/spec/04_messages.md new file mode 100644 index 000000000000..39be055e29fe --- /dev/null +++ b/x/ibc/spec/04_messages.md @@ -0,0 +1,80 @@ + + +# Messages + +In this section we describe the processing of the IBC messages and the corresponding updates to the state. + +## ICS 02 - Client + +### MsgCreateClient + +A light client is created using the `MsgCreateClient`. + +```go +type MsgCreateClient struct { + ClientID string + ClientType string + ConsensusState ConsensusState + Signer AccAddress +} +``` + +This message is expected to fail if: + +- `ClientID` is invalid (not alphanumeric or not within 10-20 characters) +- `ClientType` is not registered +- `ConsensusState` is empty +- `Signer` is empty +- A light client with the provided id and type already exist + +The message creates and stores a light client with the given ID and consensus type, +stores the validator set as the `Commiter` of the given consensus state and stores +both the consensus state and its commitment root (i.e app hash). + +### MsgUpdateClient + +A light client is updated with a new header using the `MsgUpdateClient`. + +```go +type MsgUpdateClient struct { + ClientID string + Header Header + Signer AccAddress +} +``` + +This message is expected to fail if: + +- `ClientID` is invalid (not alphanumeric or not within 10-20 characters) +- `Header` is empty +- `Signer` is empty +- A Client hasn't been created for the given ID +- the header's client type is different from the registered one +- the client is frozen due to misbehaviour and cannot be updated + +The message validates the header and updates the consensus state with the new +height, commitment root and validator sets, which are then stored. + +## ICS 03 - Connection + +## ICS 04 - Channels + +### MsgChannelOpenInit + +A channel handshake is initiated by a chain A using the `MsgChannelOpenInit` +message. + +```go +type MsgChannelOpenInit struct { + PortID string + ChannelID string + Channel Channel + Signer sdk.AccAddress +} +``` + +This message is expected to fail if: + +## ICS 20 - Fungible Token Transfer diff --git a/x/ibc/spec/05_callbacks.md b/x/ibc/spec/05_callbacks.md new file mode 100644 index 000000000000..cf77d8ec3688 --- /dev/null +++ b/x/ibc/spec/05_callbacks.md @@ -0,0 +1,5 @@ + + +# Callbacks diff --git a/x/ibc/spec/06_events.md b/x/ibc/spec/06_events.md new file mode 100644 index 000000000000..e333e8af07d4 --- /dev/null +++ b/x/ibc/spec/06_events.md @@ -0,0 +1,147 @@ + + +# Events + +The IBC module emits the following events: + +## ICS 02 - Client + +### MsgCreateClient + +| Type | Attribute Key | Attribute Value | +|---------------|---------------|-----------------| +| create_client | client_id | {clientID} | +| message | module | ibc_client | +| message | action | create_client | +| message | sender | {signer} | + +### MsgUpdateClient + +| Type | Attribute Key | Attribute Value | +|---------------|---------------|-----------------| +| update_client | client_id | {clientID} | +| message | module | ibc_client | +| message | action | update_client | +| message | sender | {signer} | + +### MsgSubmitMisbehaviour + +| Type | Attribute Key | Attribute Value | +|---------------------|---------------|---------------------| +| client_misbehaviour | client_id | {clientID} | +| message | module | evidence | +| message | action | client_misbehaviour | +| message | sender | {signer} | + +## ICS 03 - Connection + +### MsgConnectionOpenInit + +| Type | Attribute Key | Attribute Value | +|----------------------|------------------------|-------------------------| +| connection_open_init | connection_id | {connectionID} | +| connection_open_init | client_id | {clientID} | +| connection_open_init | counterparty_client_id | {counterparty.clientID} | +| message | module | ibc_connection | +| message | action | connection_open_init | +| message | sender | {signer} | + +### MsgConnectionOpenTry + +| Type | Attribute Key | Attribute Value | +|---------------------|---------------|---------------------| +| connection_open_try | connection_id | {connectionID} | +| connection_open_try | client_id | {clientID} | +| message | module | ibc_connection | +| message | action | connection_open_try | +| message | sender | {signer} | + +### MsgConnectionOpenAck + +| Type | Attribute Key | Attribute Value | +|----------------------|------------------------|-------------------------| +| connection_open_ack | connection_id | {connectionID} | +| connection_open_ack | client_id | {clientID} | +| connection_open_init | counterparty_client_id | {counterparty.clientID} | +| message | module | ibc_connection | +| message | action | connection_open_ack | +| message | sender | {signer} | + +### MsgConnectionOpenConfirm + +| Type | Attribute Key | Attribute Value | +|-------------------------|---------------|-------------------------| +| connection_open_confirm | connection_id | {connectionID} | +| message | module | ibc_connection | +| message | action | connection_open_confirm | +| message | sender | {signer} | + +## ICS 04 - Channel + +### MsgChannelOpenInit + +| Type | Attribute Key | Attribute Value | +|-------------------|-------------------------|----------------------------------| +| channel_open_init | port_id | {portID} | +| channel_open_init | channel_id | {channelID} | +| channel_open_init | counterparty_port_id | {channel.counterparty.portID} | +| channel_open_init | counterparty_channel_id | {channel.counterparty.channelID} | +| channel_open_init | connection_id | {channel.connectionHops} | +| message | module | ibc_channel | +| message | action | channel_open_init | +| message | sender | {signer} | + +### MsgChannelOpenTry + +| Type | Attribute Key | Attribute Value | +|------------------|-------------------------|----------------------------------| +| channel_open_try | port_id | {portID} | +| channel_open_try | channel_id | {channelID} | +| channel_open_try | counterparty_port_id | {channel.counterparty.portID} | +| channel_open_try | counterparty_channel_id | {channel.counterparty.channelID} | +| channel_open_try | connection_id | {channel.connectionHops} | +| message | module | ibc_channel | +| message | action | channel_open_try | +| message | sender | {signer} | + +### MsgChannelOpenAck + +| Type | Attribute Key | Attribute Value | +|------------------|---------------|------------------| +| channel_open_ack | port_id | {portID} | +| channel_open_ack | channel_id | {channelID} | +| message | module | ibc_channel | +| message | action | channel_open_ack | +| message | sender | {signer} | + +### MsgChannelOpenConfirm + +| Type | Attribute Key | Attribute Value | +|----------------------|---------------|----------------------| +| channel_open_confirm | port_id | {portID} | +| channel_open_confirm | channel_id | {channelID} | +| message | module | ibc_channel | +| message | action | channel_open_confirm | +| message | sender | {signer} | + +### MsgChannelCloseInit + +| Type | Attribute Key | Attribute Value | +|--------------------|---------------|--------------------| +| channel_close_init | port_id | {portID} | +| channel_close_init | channel_id | {channelID} | +| message | module | ibc_channel | +| message | action | channel_close_init | +| message | sender | {signer} | + +### MsgChannelCloseConfirm + +| Type | Attribute Key | Attribute Value | +|-----------------------|---------------|-----------------------| +| channel_close_confirm | port_id | {portID} | +| channel_close_confirm | channel_id | {channelID} | +| message | module | ibc_channel | +| message | action | channel_close_confirm | +| message | sender | {signer} | diff --git a/x/ibc/spec/README.md b/x/ibc/spec/README.md new file mode 100644 index 000000000000..ddaec62fab33 --- /dev/null +++ b/x/ibc/spec/README.md @@ -0,0 +1,109 @@ + + +# `ibc` + +## Abstract + +This paper defines the implementation of the IBC protocol on the Cosmos SDK, the +changes made to the specification and where to find each specific ICS spec within +the module. + +For the general specification please refer to the [Interchain Standards](https://github.com/cosmos/ics). + +## Contents + +1. **[Concepts](01_concepts.md)** +2. **[State](02_state.md)** +3. **[State Transitions](02_state_transitions.md)** +4. **[Messages](03_messages.md)** +5. **[Callbacks](06_callbacks.md)** +6. **[Events](07_events.md)** + +## Implementation Details + +As stated above, the IBC implementation on the Cosmos SDK introduces some changes +to the general specification, in order to avoid code duplication and to take +advantage of the SDK architectural components such as the `AnteHandler` and +transaction routing through `Handlers`. + +### Interchain Standards reference + +The following list is a mapping from each Interchain Standard to their implementation +in the SDK's `x/ibc` module: + +* [ICS 002 - Client Semantics](https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics): Implemented in [`x/ibc/02-client`](https://github.com/cosmos/x/ibc/02-client) +* [ICS 003 - Connection Semantics](https://github.com/cosmos/ics/blob/master/spec/ics-003-connection-semantics): Implemented in [`x/ibc/03-connection`](https://github.com/cosmos/x/ibc/03-connection) +* [ICS 004 - Channel and Packet Semantics](https://github.com/cosmos/ics/blob/master/spec/ics-004-channel-and-packet-semantics): Implemented in [`x/ibc/04-channel`](https://github.com/cosmos/x/ibc/04-channel) +* [ICS 005 - Port Allocation](https://github.com/cosmos/ics/blob/master/spec/ics-005-port-allocation): Implemented in [`x/ibc/05-port`](https://github.com/cosmos/x/ibc/05-port) +* [ICS 006 - Solo Machine Client](https://github.com/cosmos/ics/blob/master/spec/ics-006-solo-machine-client): To be implemented in [`x/ibc/06-solo`](https://github.com/cosmos/x/ibc/06-solo) +* [ICS 007 - Tendermint Client](https://github.com/cosmos/ics/blob/master/spec/ics-007-tendermint-client): Implemented in [`x/ibc/07-tendermint`](https://github.com/cosmos/x/ibc/07-tendermint) +* [ICS 009 - Loopback Client](https://github.com/cosmos/ics/blob/master/spec/ics-009-loopback-client): To be implemented in [`x/ibc/09-loopback`](https://github.com/cosmos/x/ibc/09-loopback) +* [ICS 018- Relayer Algorithms](https://github.com/cosmos/ics/tree/master/spec/ics-018-relayer-algorithms): Implemented in it's own [relayer repository](https://github.com/cosmos/relayer) +* [ICS 020 - Fungible Token Transfer](https://github.com/cosmos/ics/tree/master/spec/ics-020-fungible-token-transfer): Implemented in [`x/ibc/20-transfer`](https://github.com/cosmos/x/ibc/20-transfer) +* [ICS 023 - Vector Commitments](https://github.com/cosmos/ics/tree/master/spec/ics-023-vector-commitments): Implemented in [`x/ibc/23-commitment`](https://github.com/cosmos/x/ibc/23-commitment) +* [ICS 024 - Host Requirements](https://github.com/cosmos/ics/tree/master/spec/ics-024-host-requirements): Implemented in [`x/ibc/24-host`](https://github.com/cosmos/x/ibc/24-host) +* [ICS 025 - Handler Interface](https://github.com/cosmos/ics/tree/master/spec/ics-025-handler-interface): Handler interfaces are implemented at the top level in `x/ibc/handler.go`, +which call each ICS submodule's handlers (i.e `x/ibc/{XX-ICS}/handler.go`). +* [ICS 026 - Routing Module](https://github.com/cosmos/ics/blob/master/spec/ics-026-routing-module): Replaced by [ADR 15 - IBC Packet Receiver](../../../docs/architecture/adr-015-ibc-packet-receiver.md). + +### Architecture Decision Records (ADR) + +The following ADR provide the design and architecture decision of IBC-related components. + +* [ADR 10 - Modular AnteHandler](../../../docs/architecture/adr-010-modular-antehandler.md): Introduces a decorator pattern for the [`AnteHandler`](../../../docs/basics/gas-fees.md#antehandler), making it modular. +* [ADR 15 - IBC Packet Receiver](../../../docs/architecture/adr-015-ibc-packet-receiver.md): replaces the ICS26 routing module with [`AnteHandler`](../../../docs/basics/gas-fees.md#antehandler) logic within IBC. This is implemented using the `AnteDecorators` defined in [ADR10]((../../../docs/architecture/adr-010-modular-antehandler.md)) +* [ADR 17 - Historical Header Module](../../../docs/architecture/adr-017-historical-header-module.md): Introduces the ability to introspect past +consensus states in order to verify their membership in the counterparty clients. +* [ADR 19 - Protobuf State Encoding](../../../docs/architecture/adr-019-protobuf-state-encoding.md): Migration from Amino to Protobuf for state encoding. +* [ADR 020 - Protocol Buffer Transaction Encoding](./../../docs/architecture/adr-020-protobuf-transaction-encoding.md): Client side migration to Protobuf. +* [ADR 021 - Protocol Buffer Query Encoding](./../../docs/architecture/adr-020-protobuf-query-encoding.md): Queries migration to Protobuf. + +### SDK Modules + +* [`x/capability`](https://github.com/cosmos/tree/master/x/capability): The capability module provides object-capability keys support through scoped keepers in order to authenticate usage of ports or channels. Check [ADR 3 - Dynamic Capability Store](../../../docs/architecture/adr-003-dynamic-capability-store.md) for more details. +* [`x/evidence`](https://github.com/cosmos/tree/master/x/evidence): The evidence module provides the interfaces and client logic to handle light client misbehaviour. Check [ADR 09 - Evidence Module](../../../docs/architecture/adr-009-evidence-module.md) for more details. + +## IBC module architecture + +> **NOTE for auditors**: If you're not familiar with the overall module structure from +the SDK modules, please check this [document](../../../docs/building-modules/structure.md) as +prerequisite reading. + +For ease of auditing, every Interchain Standard has been developed in its own +package. The following tree describes the architecture of the directories within +the IBC module: + +```shell +x/ibc +├── 02-client/ +├── 03-connection/ +├── 04-channel/ +├── 05-port/ +├── 06-solo/ +├── 07-tendermint/ +├── 09-loopback/ +├── 20-transfer/ +├── 23-commitment/ +├── 24-host/ +├── ante +│   └── ante.go +├── client +│   ├── cli +│   │   └── cli.go +│   └── rest +│   └── rest.go +├── keeper +│   ├── keeper.go +│   └── querier.go +├── types +│   ├── errors.go +│   └── keys.go +├── alias.go +├── handler.go +└── module.go +``` diff --git a/x/ibc/types/errors.go b/x/ibc/types/errors.go new file mode 100644 index 000000000000..5246b3c5a206 --- /dev/null +++ b/x/ibc/types/errors.go @@ -0,0 +1,11 @@ +package types + +import ( + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +// ibc module common sentinel errors +var ( + ErrInvalidHeight = sdkerrors.Register(ModuleName, 1, "invalid height") + ErrInvalidVersion = sdkerrors.Register(ModuleName, 2, "invalid version") +) diff --git a/x/ibc/types/keys.go b/x/ibc/types/keys.go new file mode 100644 index 000000000000..edb2ed243eb3 --- /dev/null +++ b/x/ibc/types/keys.go @@ -0,0 +1,207 @@ +package types + +import ( + "fmt" + "strings" +) + +const ( + // ModuleName is the name of the IBC module + ModuleName = "ibc" + + // StoreKey is the string store representation + StoreKey string = ModuleName + + // QuerierRoute is the querier route for the IBC module + QuerierRoute string = ModuleName + + // RouterKey is the msg router key for the IBC module + RouterKey string = ModuleName +) + +// KVStore key prefixes for IBC +var ( + KeyClientPrefix = []byte("clientState") + KeyClientTypePrefix = []byte("clientType") + KeyConsensusStatePrefix = []byte("consensusState") + KeyClientConnectionsPrefix = []byte("clientConnections") + KeyConnectionPrefix = []byte("connection") +) + +// KVStore key prefixes for IBC +const ( + KeyChannelPrefix int = iota + 1 + KeyChannelCapabilityPrefix + KeyNextSeqSendPrefix + KeyNextSeqRecvPrefix + KeyPacketCommitmentPrefix + KeyPacketAckPrefix + KeyPortsPrefix +) + +// KeyPrefixBytes return the key prefix bytes from a URL string format +func KeyPrefixBytes(prefix int) []byte { + return []byte(fmt.Sprintf("%d/", prefix)) +} + +// ICS02 +// The following paths are the keys to the store as defined in https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#path-space + +// ClientStatePath takes an Identifier and returns a Path under which to store a +// particular client state +func ClientStatePath(clientID string) string { + return fmt.Sprintf("clientState/%s", clientID) +} + +// ClientTypePath takes an Identifier and returns Path under which to store the +// type of a particular client. +func ClientTypePath(clientID string) string { + return fmt.Sprintf("clientType/%s", clientID) +} + +// ConsensusStatePath takes an Identifier and returns a Path under which to +// store the consensus state of a client. +func ConsensusStatePath(clientID string, height uint64) string { + return fmt.Sprintf("consensusState/%s/%d", clientID, height) +} + +// KeyClientState returns the store key for a particular client state +func KeyClientState(clientID string) []byte { + return []byte(ClientStatePath(clientID)) +} + +// KeyClientType returns the store key for type of a particular client +func KeyClientType(clientID string) []byte { + return []byte(ClientTypePath(clientID)) +} + +// KeyConsensusState returns the store key for the consensus state of a particular +// client +func KeyConsensusState(clientID string, height uint64) []byte { + return []byte(ConsensusStatePath(clientID, height)) +} + +// ICS03 +// The following paths are the keys to the store as defined in https://github.com/cosmos/ics/tree/master/spec/ics-003-connection-semantics#store-paths + +// ClientConnectionsPath defines a reverse mapping from clients to a set of connections +func ClientConnectionsPath(clientID string) string { + return fmt.Sprintf("clientConnections/%s/", clientID) +} + +// ConnectionPath defines the path under which connection paths are stored +func ConnectionPath(connectionID string) string { + return fmt.Sprintf("connection/%s", connectionID) +} + +// KeyClientConnections returns the store key for the connectios of a given client +func KeyClientConnections(clientID string) []byte { + return []byte(ClientConnectionsPath(clientID)) +} + +// KeyConnection returns the store key for a particular connection +func KeyConnection(connectionID string) []byte { + return []byte(ConnectionPath(connectionID)) +} + +// ICS04 +// The following paths are the keys to the store as defined in https://github.com/cosmos/ics/tree/master/spec/ics-004-channel-and-packet-semantics#store-paths + +// GetChannelPortsKeysPrefix returns the prefix bytes for ICS04 and ICS05 iterators +func GetChannelPortsKeysPrefix(prefix int) []byte { + return []byte(fmt.Sprintf("%d/ports/", prefix)) +} + +// ChannelPath defines the path under which channels are stored +func ChannelPath(portID, channelID string) string { + return fmt.Sprintf("%d/", KeyChannelPrefix) + channelPath(portID, channelID) +} + +// ChannelCapabilityPath defines the path under which capability keys associated +// with a channel are stored +func ChannelCapabilityPath(portID, channelID string) string { + return fmt.Sprintf("%d/", KeyChannelCapabilityPrefix) + channelPath(portID, channelID) + "/key" +} + +// NextSequenceSendPath defines the next send sequence counter store path +func NextSequenceSendPath(portID, channelID string) string { + return fmt.Sprintf("%d/", KeyNextSeqSendPrefix) + channelPath(portID, channelID) + "/nextSequenceSend" +} + +// NextSequenceRecvPath defines the next receive sequence counter store path +func NextSequenceRecvPath(portID, channelID string) string { + return fmt.Sprintf("%d/", KeyNextSeqRecvPrefix) + channelPath(portID, channelID) + "/nextSequenceRecv" +} + +// PacketCommitmentPath defines the commitments to packet data fields store path +func PacketCommitmentPath(portID, channelID string, sequence uint64) string { + return fmt.Sprintf("%d/", KeyPacketCommitmentPrefix) + channelPath(portID, channelID) + fmt.Sprintf("/packets/%d", sequence) +} + +// PacketAcknowledgementPath defines the packet acknowledgement store path +func PacketAcknowledgementPath(portID, channelID string, sequence uint64) string { + return fmt.Sprintf("%d/", KeyPacketAckPrefix) + channelPath(portID, channelID) + fmt.Sprintf("/acknowledgements/%d", sequence) +} + +// KeyChannel returns the store key for a particular channel +func KeyChannel(portID, channelID string) []byte { + return []byte(ChannelPath(portID, channelID)) +} + +// KeyChannelCapabilityPath returns the store key for the capability key of a +// particular channel binded to a specific port +func KeyChannelCapabilityPath(portID, channelID string) []byte { + return []byte(ChannelCapabilityPath(portID, channelID)) +} + +// KeyNextSequenceSend returns the store key for the send sequence of a particular +// channel binded to a specific port +func KeyNextSequenceSend(portID, channelID string) []byte { + return []byte(NextSequenceSendPath(portID, channelID)) +} + +// KeyNextSequenceRecv returns the store key for the receive sequence of a particular +// channel binded to a specific port +func KeyNextSequenceRecv(portID, channelID string) []byte { + return []byte(NextSequenceRecvPath(portID, channelID)) +} + +// KeyPacketCommitment returns the store key of under which a packet commitment +// is stored +func KeyPacketCommitment(portID, channelID string, sequence uint64) []byte { + return []byte(PacketCommitmentPath(portID, channelID, sequence)) +} + +// KeyPacketAcknowledgement returns the store key of under which a packet +// acknowledgement is stored +func KeyPacketAcknowledgement(portID, channelID string, sequence uint64) []byte { + return []byte(PacketAcknowledgementPath(portID, channelID, sequence)) +} + +func channelPath(portID, channelID string) string { + return fmt.Sprintf("ports/%s/channels/%s", portID, channelID) +} + +func MustParseChannelPath(path string) (string, string) { + split := strings.Split(path, "/") + if len(split) != 5 { + panic("cannot parse channel path") + } + if split[1] != "ports" || split[3] != "channels" { + panic("cannot parse channel path") + } + return split[2], split[4] +} + +// ICS05 +// The following paths are the keys to the store as defined in https://github.com/cosmos/ics/tree/master/spec/ics-005-port-allocation#store-paths + +// PortPath defines the path under which ports paths are stored +func PortPath(portID string) string { + return fmt.Sprintf("%d/ports/%s", KeyPortsPrefix, portID) +} + +// KeyPort returns the store key for a particular port +func KeyPort(portID string) []byte { + return []byte(PortPath(portID)) +} diff --git a/x/ibc/types/mock.go b/x/ibc/types/mock.go new file mode 100644 index 000000000000..1cbec82adcef --- /dev/null +++ b/x/ibc/types/mock.go @@ -0,0 +1,73 @@ +package types + +import ( + "bytes" + "errors" + + commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" +) + +// Mocked types +// TODO: fix tests and replace for real proofs + +var ( + _ commitmentexported.Proof = ValidProof{nil, nil, nil} + _ commitmentexported.Proof = InvalidProof{} +) + +type ( + ValidProof struct { + root commitmentexported.Root + path commitmentexported.Path + value []byte + } + InvalidProof struct{} +) + +func (ValidProof) GetCommitmentType() commitmentexported.Type { + return commitmentexported.Merkle +} + +func (proof ValidProof) VerifyMembership( + root commitmentexported.Root, path commitmentexported.Path, value []byte, +) error { + if bytes.Equal(root.GetHash(), proof.root.GetHash()) && + path.String() == proof.path.String() && + bytes.Equal(value, proof.value) { + return nil + } + return errors.New("invalid proof") +} + +func (ValidProof) VerifyNonMembership(root commitmentexported.Root, path commitmentexported.Path) error { + return nil +} + +func (ValidProof) ValidateBasic() error { + return nil +} + +func (ValidProof) IsEmpty() bool { + return false +} + +func (InvalidProof) GetCommitmentType() commitmentexported.Type { + return commitmentexported.Merkle +} + +func (InvalidProof) VerifyMembership( + root commitmentexported.Root, path commitmentexported.Path, value []byte) error { + return errors.New("proof failed") +} + +func (InvalidProof) VerifyNonMembership(root commitmentexported.Root, path commitmentexported.Path) error { + return errors.New("proof failed") +} + +func (InvalidProof) ValidateBasic() error { + return errors.New("invalid proof") +} + +func (InvalidProof) IsEmpty() bool { + return true +} diff --git a/x/ibc/types/utils.go b/x/ibc/types/utils.go new file mode 100644 index 000000000000..7af4bf0de5ee --- /dev/null +++ b/x/ibc/types/utils.go @@ -0,0 +1,15 @@ +package types + +// For now, we enforce that only IBC and the module bound to port can own the capability +// while future implementations may allow multiple modules to bind to a port, currently we +// only allow one module to be bound to a port at any given time +func GetModuleOwner(modules []string) string { + if len(modules) != 2 { + panic("capability should only be owned by port or channel owner and ibc module, multiple owners currently not supported") + } + + if modules[0] == "ibc" { + return modules[1] + } + return modules[0] +} diff --git a/x/mint/keeper/keeper.go b/x/mint/keeper/keeper.go index 73652e41c88b..116b989a6692 100644 --- a/x/mint/keeper/keeper.go +++ b/x/mint/keeper/keeper.go @@ -32,10 +32,15 @@ func NewKeeper( panic("the mint module account has not been set") } + // set KeyTable if it has not already been set + if !paramSpace.HasKeyTable() { + paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable()) + } + return Keeper{ cdc: cdc, storeKey: key, - paramSpace: paramSpace.WithKeyTable(types.ParamKeyTable()), + paramSpace: paramSpace, sk: sk, supplyKeeper: supplyKeeper, feeCollectorName: feeCollectorName, diff --git a/x/slashing/keeper/keeper.go b/x/slashing/keeper/keeper.go index f34756afc853..e7f486ac32be 100644 --- a/x/slashing/keeper/keeper.go +++ b/x/slashing/keeper/keeper.go @@ -23,11 +23,16 @@ type Keeper struct { // NewKeeper creates a slashing keeper func NewKeeper(cdc codec.Marshaler, key sdk.StoreKey, sk types.StakingKeeper, paramspace types.ParamSubspace) Keeper { + // set KeyTable if it has not already been set + if !paramspace.HasKeyTable() { + paramspace = paramspace.WithKeyTable(types.ParamKeyTable()) + } + return Keeper{ storeKey: key, cdc: cdc, sk: sk, - paramspace: paramspace.WithKeyTable(types.ParamKeyTable()), + paramspace: paramspace, } } diff --git a/x/slashing/types/expected_keepers.go b/x/slashing/types/expected_keepers.go index 4a9dd4f7f2d6..50e71cb614e5 100644 --- a/x/slashing/types/expected_keepers.go +++ b/x/slashing/types/expected_keepers.go @@ -26,6 +26,7 @@ type BankKeeper interface { // ParamSubspace defines the expected Subspace interfacace type ParamSubspace interface { + HasKeyTable() bool WithKeyTable(table paramtypes.KeyTable) paramtypes.Subspace Get(ctx sdk.Context, key []byte, ptr interface{}) GetParamSet(ctx sdk.Context, ps paramtypes.ParamSet) diff --git a/x/staking/simulation/decoder.go b/x/staking/simulation/decoder.go index efd8cb917e42..86f1cecc9e00 100644 --- a/x/staking/simulation/decoder.go +++ b/x/staking/simulation/decoder.go @@ -51,12 +51,6 @@ func DecodeStore(cdc *codec.Codec, kvA, kvB tmkv.Pair) string { cdc.MustUnmarshalBinaryBare(kvB.Value, &redB) return fmt.Sprintf("%v\n%v", redA, redB) - case bytes.Equal(kvA.Key[:1], types.HistoricalInfoKey): - var histInfoA, histInfoB types.HistoricalInfo - cdc.MustUnmarshalBinaryBare(kvA.Value, &histInfoA) - cdc.MustUnmarshalBinaryBare(kvB.Value, &histInfoB) - return fmt.Sprintf("%v\n%v", histInfoA, histInfoB) - default: panic(fmt.Sprintf("invalid staking key prefix %X", kvA.Key[:1])) } diff --git a/x/staking/simulation/decoder_test.go b/x/staking/simulation/decoder_test.go index 813f7fc74a6f..40dd39710e84 100644 --- a/x/staking/simulation/decoder_test.go +++ b/x/staking/simulation/decoder_test.go @@ -7,7 +7,6 @@ import ( "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto/ed25519" tmkv "github.com/tendermint/tendermint/libs/kv" @@ -39,7 +38,6 @@ func TestDecodeStore(t *testing.T) { del := types.NewDelegation(delAddr1, valAddr1, sdk.OneDec()) ubd := types.NewUnbondingDelegation(delAddr1, valAddr1, 15, bondTime, sdk.OneInt()) red := types.NewRedelegation(delAddr1, valAddr1, valAddr1, 12, bondTime, sdk.OneInt(), sdk.OneDec()) - histInfo := types.NewHistoricalInfo(abci.Header{ChainID: "gaia", Height: 10, Time: bondTime}, types.Validators{val}) kvPairs := tmkv.Pairs{ tmkv.Pair{Key: types.LastTotalPowerKey, Value: cdc.MustMarshalBinaryBare(sdk.OneInt())}, @@ -48,7 +46,6 @@ func TestDecodeStore(t *testing.T) { tmkv.Pair{Key: types.GetDelegationKey(delAddr1, valAddr1), Value: cdc.MustMarshalBinaryBare(del)}, tmkv.Pair{Key: types.GetUBDKey(delAddr1, valAddr1), Value: cdc.MustMarshalBinaryBare(ubd)}, tmkv.Pair{Key: types.GetREDKey(delAddr1, valAddr1, valAddr1), Value: cdc.MustMarshalBinaryBare(red)}, - tmkv.Pair{Key: types.GetHistoricalInfoKey(10), Value: cdc.MustMarshalBinaryBare(histInfo)}, tmkv.Pair{Key: []byte{0x99}, Value: []byte{0x99}}, } @@ -62,7 +59,6 @@ func TestDecodeStore(t *testing.T) { {"Delegation", fmt.Sprintf("%v\n%v", del, del)}, {"UnbondingDelegation", fmt.Sprintf("%v\n%v", ubd, ubd)}, {"Redelegation", fmt.Sprintf("%v\n%v", red, red)}, - {"HistoricalInfo", fmt.Sprintf("%v\n%v", histInfo, histInfo)}, {"other", ""}, } for i, tt := range tests { From 192f259e77aed931142531ee86774ee91af4b31a Mon Sep 17 00:00:00 2001 From: SaReN Date: Thu, 9 Apr 2020 19:30:10 +0530 Subject: [PATCH 529/529] Merge PR #5967: Fixed cliCtx in tx cli --- x/bank/client/cli/tx.go | 4 ++++ x/crisis/client/cli/tx.go | 6 +++++- x/distribution/client/cli/tx.go | 8 ++++---- x/slashing/client/cli/tx.go | 6 +++++- x/staking/client/cli/tx.go | 28 +++++++++++++++++++++++----- 5 files changed, 41 insertions(+), 11 deletions(-) diff --git a/x/bank/client/cli/tx.go b/x/bank/client/cli/tx.go index 8a46c0aee148..597004519fe8 100644 --- a/x/bank/client/cli/tx.go +++ b/x/bank/client/cli/tx.go @@ -53,6 +53,10 @@ func NewSendTxCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) * } msg := types.NewMsgSend(cliCtx.GetFromAddress(), toAddr, coins) + if err := msg.ValidateBasic(); err != nil { + return err + } + return tx.GenerateOrBroadcastTx(cliCtx, txf, msg) }, } diff --git a/x/crisis/client/cli/tx.go b/x/crisis/client/cli/tx.go index 3ca350ee67d4..320515123a85 100644 --- a/x/crisis/client/cli/tx.go +++ b/x/crisis/client/cli/tx.go @@ -40,13 +40,17 @@ func NewMsgVerifyInvariantTxCmd(m codec.Marshaler, txg tx.Generator, ar tx.Accou Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { inBuf := bufio.NewReader(cmd.InOrStdin()) - cliCtx := context.NewCLIContextWithInputAndFrom(inBuf, args[0]).WithMarshaler(m) + cliCtx := context.NewCLIContextWithInput(inBuf).WithMarshaler(m) txf := tx.NewFactoryFromCLI(inBuf).WithTxGenerator(txg).WithAccountRetriever(ar) senderAddr := cliCtx.GetFromAddress() moduleName, route := args[0], args[1] msg := types.NewMsgVerifyInvariant(senderAddr, moduleName, route) + if err := msg.ValidateBasic(); err != nil { + return err + } + return tx.GenerateOrBroadcastTx(cliCtx, txf, msg) }, } diff --git a/x/distribution/client/cli/tx.go b/x/distribution/client/cli/tx.go index 4c2a055ac9e2..25d1e85f750b 100644 --- a/x/distribution/client/cli/tx.go +++ b/x/distribution/client/cli/tx.go @@ -107,7 +107,7 @@ $ %s tx distribution withdraw-rewards cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fx txf := tx.NewFactoryFromCLI(inBuf). WithTxGenerator(txg). WithAccountRetriever(ar) - cliCtx := context.NewCLIContextWithInputAndFrom(inBuf, args[0]).WithMarshaler(m) + cliCtx := context.NewCLIContextWithInput(inBuf).WithMarshaler(m) delAddr := cliCtx.GetFromAddress() valAddr, err := sdk.ValAddressFromBech32(args[0]) @@ -152,7 +152,7 @@ $ %s tx distribution withdraw-all-rewards --from mykey txf := tx.NewFactoryFromCLI(inBuf). WithTxGenerator(txg). WithAccountRetriever(ar) - cliCtx := context.NewCLIContextWithInputAndFrom(inBuf, args[0]).WithMarshaler(m) + cliCtx := context.NewCLIContextWithInput(inBuf).WithMarshaler(m) delAddr := cliCtx.GetFromAddress() @@ -193,7 +193,7 @@ $ %s tx distribution set-withdraw-addr cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75 txf := tx.NewFactoryFromCLI(inBuf). WithTxGenerator(txg). WithAccountRetriever(ar) - cliCtx := context.NewCLIContextWithInputAndFrom(inBuf, args[0]).WithMarshaler(m) + cliCtx := context.NewCLIContextWithInput(inBuf).WithMarshaler(m) delAddr := cliCtx.GetFromAddress() withdrawAddr, err := sdk.AccAddressFromBech32(args[0]) @@ -242,7 +242,7 @@ Where proposal.json contains: txf := tx.NewFactoryFromCLI(inBuf). WithTxGenerator(txg). WithAccountRetriever(ar) - cliCtx := context.NewCLIContextWithInputAndFrom(inBuf, args[0]).WithMarshaler(m) + cliCtx := context.NewCLIContextWithInput(inBuf).WithMarshaler(m) depositorAddr := cliCtx.GetFromAddress() amount, err := sdk.ParseCoins(args[0]) diff --git a/x/slashing/client/cli/tx.go b/x/slashing/client/cli/tx.go index e04a7e16cf29..0389cc631610 100644 --- a/x/slashing/client/cli/tx.go +++ b/x/slashing/client/cli/tx.go @@ -45,10 +45,14 @@ $ tx slashing unjail --from mykey WithTxGenerator(txg). WithAccountRetriever(ar) - cliCtx := context.NewCLIContextWithInputAndFrom(inBuf, args[0]).WithMarshaler(m) + cliCtx := context.NewCLIContextWithInput(inBuf).WithMarshaler(m) valAddr := cliCtx.GetFromAddress() msg := types.NewMsgUnjail(sdk.ValAddress(valAddr)) + if err := msg.ValidateBasic(); err != nil { + return err + } + return tx.GenerateOrBroadcastTx(cliCtx, txf, msg) }, } diff --git a/x/staking/client/cli/tx.go b/x/staking/client/cli/tx.go index c9b9211e1856..9735c5b3fa5c 100644 --- a/x/staking/client/cli/tx.go +++ b/x/staking/client/cli/tx.go @@ -66,7 +66,7 @@ func NewCreateValidatorCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRet WithTxGenerator(txg). WithAccountRetriever(ar) - cliCtx := context.NewCLIContextWithInputAndFrom(inBuf, args[0]).WithMarshaler(m) + cliCtx := context.NewCLIContextWithInput(inBuf).WithMarshaler(m) txf, msg, err := NewBuildCreateValidatorMsg(cliCtx, txf) if err != nil { @@ -101,7 +101,7 @@ func NewEditValidatorCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetri WithTxGenerator(txg). WithAccountRetriever(ar) - cliCtx := context.NewCLIContextWithInputAndFrom(inBuf, args[0]).WithMarshaler(m) + cliCtx := context.NewCLIContextWithInput(inBuf).WithMarshaler(m) valAddr := cliCtx.GetFromAddress() description := types.NewDescription( @@ -137,6 +137,9 @@ func NewEditValidatorCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetri } msg := types.NewMsgEditValidator(sdk.ValAddress(valAddr), description, newRate, newMinSelfDelegation) + if err := msg.ValidateBasic(); err != nil { + return err + } // build and sign the transaction, then broadcast to Tendermint return tx.GenerateOrBroadcastTx(cliCtx, txf, msg) @@ -165,7 +168,7 @@ $ %s tx staking delegate cosmosvaloper1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm 10 WithTxGenerator(txg). WithAccountRetriever(ar) - cliCtx := context.NewCLIContextWithInputAndFrom(inBuf, args[0]).WithMarshaler(m) + cliCtx := context.NewCLIContextWithInput(inBuf).WithMarshaler(m) amount, err := sdk.ParseCoin(args[1]) if err != nil { @@ -179,6 +182,10 @@ $ %s tx staking delegate cosmosvaloper1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm 10 } msg := types.NewMsgDelegate(delAddr, valAddr, amount) + if err := msg.ValidateBasic(); err != nil { + return err + } + return tx.GenerateOrBroadcastTx(cliCtx, txf, msg) }, } @@ -209,7 +216,7 @@ $ %s tx staking redelegate cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj WithTxGenerator(txg). WithAccountRetriever(ar) - cliCtx := context.NewCLIContextWithInputAndFrom(inBuf, args[0]).WithMarshaler(m) + cliCtx := context.NewCLIContextWithInput(inBuf).WithMarshaler(m) delAddr := cliCtx.GetFromAddress() valSrcAddr, err := sdk.ValAddressFromBech32(args[0]) if err != nil { @@ -227,6 +234,10 @@ $ %s tx staking redelegate cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj } msg := types.NewMsgBeginRedelegate(delAddr, valSrcAddr, valDstAddr, amount) + if err := msg.ValidateBasic(); err != nil { + return err + } + return tx.GenerateOrBroadcastTx(cliCtx, txf, msg) }, } @@ -253,7 +264,7 @@ $ %s tx staking unbond cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj 100s WithTxGenerator(txg). WithAccountRetriever(ar) - cliCtx := context.NewCLIContextWithInputAndFrom(inBuf, args[0]).WithMarshaler(m) + cliCtx := context.NewCLIContextWithInput(inBuf).WithMarshaler(m) delAddr := cliCtx.GetFromAddress() valAddr, err := sdk.ValAddressFromBech32(args[0]) @@ -267,6 +278,10 @@ $ %s tx staking unbond cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj 100s } msg := types.NewMsgUndelegate(delAddr, valAddr, amount) + if err := msg.ValidateBasic(); err != nil { + return err + } + return tx.GenerateOrBroadcastTx(cliCtx, txf, msg) }, } @@ -315,6 +330,9 @@ func NewBuildCreateValidatorMsg(cliCtx context.CLIContext, txf tx.Factory) (tx.F msg := types.NewMsgCreateValidator( sdk.ValAddress(valAddr), pk, amount, description, commissionRates, minSelfDelegation, ) + if err := msg.ValidateBasic(); err != nil { + return txf, nil, err + } if viper.GetBool(flags.FlagGenerateOnly) { ip := viper.GetString(FlagIP)